diff --git a/.gn b/.gn index bfc788d4..7940a2e 100644 --- a/.gn +++ b/.gn
@@ -27,6 +27,7 @@ "//chrome/common/*", "//chrome/installer/*", "//chrome/third_party/mozilla_security_manager/*", + "//chrome/tools/*", "//chrome/utility/*", "//chromecast/*", "//chrome_elf/*",
diff --git a/AUTHORS b/AUTHORS index dd1e03a..2591bf687 100644 --- a/AUTHORS +++ b/AUTHORS
@@ -481,6 +481,7 @@ Ramya Vadlamudi <ramya.v@samsung.com> Randy Posynick <randy.posynick@gmail.com> Raphael Kubo da Costa <raphael.kubo.da.costa@intel.com> +Raveendra Karu <r.karu@samsung.com> Ravi Phaneendra Kasibhatla <r.kasibhatla@samsung.com> Ravi Phaneendra Kasibhatla <ravi.kasibhatla@motorola.com> Renata Hodovan <rhodovan.u-szeged@partner.samsung.com> @@ -615,11 +616,13 @@ Wesley Wigham <t-weswig@microsoft.com> Wesley Wigham <wwigham@gmail.com> Will Hirsch <chromium@willhirsch.co.uk> +Will Shackleton <w.shackleton@gmail.com> William Xie <william.xie@intel.com> Xiang Long <xiang.long@intel.com> Xiaolei Yu <dreifachstein@gmail.com> Xinchao He <hexinchao@gmail.com> Xing Zhang <xzhang@adobe.com> +Xinghua Cao <xinghua.cao@intel.com> Xu Samuel <samuel.xu@intel.com> Xuefei Ren <xrenishere@gmail.com> Xun Sun <xun.sun@intel.com>
diff --git a/BUILD.gn b/BUILD.gn index f5db4ea..9b2bc8d 100644 --- a/BUILD.gn +++ b/BUILD.gn
@@ -196,7 +196,6 @@ "//third_party/mojo/src/mojo/edk/test:mojo_public_system_unittests", "//third_party/mojo/src/mojo/edk/test:mojo_public_utility_unittests", "//third_party/smhasher:pmurhash", - "//tools/battor_agent", "//tools/imagediff($host_toolchain)", "//tools/telemetry:bitmaptools($host_toolchain)", "//ui/display:display_unittests", @@ -224,6 +223,10 @@ } } + if (is_mac || is_win || is_linux) { + deps += [ "//tools/battor_agent" ] + } + deps += root_extra_deps if (enable_extensions) { @@ -299,6 +302,7 @@ if (!is_component_build) { deps += [ + "//components/cronet/android:cronet_package", "//components/cronet/android:cronet_sample_apk", "//components/cronet/android:cronet_sample_test_apk", "//components/cronet/android:cronet_test_apk",
diff --git a/DEPS b/DEPS index f7ba725f..7bfe494 100644 --- a/DEPS +++ b/DEPS
@@ -39,11 +39,11 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Skia # and whatever else without interference from each other. - 'skia_revision': '6df611574a3cf8abf2617af0d03a5553bb17360d', + 'skia_revision': '3405800d7a5407365143eed93e300fd5896cacee', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. - 'v8_revision': '3e445aa84cc60d4b9a8e5db94a5168ed47033814', + 'v8_revision': '7f239866c569099de1ce266a58c3c2cdd4c94495', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling swarming_client # and whatever else without interference from each other. @@ -51,11 +51,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': '457f1d929e5fd911e0ad9ea53db43010dfae0662', + 'angle_revision': 'e1743f37a9844a7b315c1703d4cf94bd3fce46ca', # 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': '6d0c448437825a1af0ad2ea28128dda474403cd7', + 'buildtools_revision': '0f8e6e4b126ee88137930a0ae4776c4741808740', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling PDFium # and whatever else without interference from each other. @@ -106,7 +106,7 @@ deps = { 'src/breakpad/src': - Var('chromium_git') + '/breakpad/breakpad/src.git' + '@' + '5b741be8cc6b746d4a77eab8a4434078affe65be', + Var('chromium_git') + '/breakpad/breakpad/src.git' + '@' + '317e714bd71c5a756e7adcca8490d5ed8966e9a1', 'src/buildtools': Var('chromium_git') + '/chromium/buildtools.git' + '@' + Var('buildtools_revision'), @@ -193,7 +193,7 @@ Var('chromium_git') + '/external/github.com/sctplab/usrsctp' + '@' + 'c60ec8b35c3fe6027d7a3faae89d1c8d7dd3ce98', 'src/third_party/libsrtp': - Var('chromium_git') + '/chromium/deps/libsrtp.git' + '@' + '8a7662a400df7bdb0dc5cb7c0bf890dfa3481295', # from svn revision 295151 + Var('chromium_git') + '/chromium/deps/libsrtp.git' + '@' + 'ebfcc9ac562411e12487036820fb1cbcd4bbe670', # from svn revision 295151 'src/third_party/yasm/source/patched-yasm': Var('chromium_git') + '/chromium/deps/yasm/patched-yasm.git' + '@' + '4671120cd8558ce62ee8672ebf3eb6f5216f909b', @@ -271,7 +271,7 @@ 'src/third_party/catapult': Var('chromium_git') + '/external/github.com/catapult-project/catapult.git' + '@' + - 'd0277b45fb76cb74b0022b759c2cf0f16c002fc3', + 'b80c94349cc85fcc8490d2d01c32c8dbd6e794bc', 'src/third_party/openh264/src': Var('chromium_git') + '/external/github.com/cisco/openh264' + '@' + 'b37cda248234162033e3e11b0335f3131cdfe488', @@ -483,7 +483,7 @@ Var('chromium_git') + '/external/github.com/kennethreitz/requests.git' + '@' + 'f172b30356d821d180fa4ecfa3e71c7274a32de4', 'src/third_party/custom_tabs_client/src': - Var('chromium_git') + '/external/github.com/GoogleChrome/custom-tabs-client.git' + '@' + '41ded9d4b5dbaf7b79e291ee8a222f5efbc52190', + Var('chromium_git') + '/external/github.com/GoogleChrome/custom-tabs-client.git' + '@' + '592e63122055d37e58cd37bd89a973eed98340ef', }, } @@ -760,12 +760,13 @@ '--overwrite', ], }, + # TODO(pmonette): Move include files out of binaries folder. { 'name': 'kasko', 'pattern': '.', 'action': ['python', 'src/build/get_syzygy_binaries.py', - '--output-dir=src/third_party/kasko', + '--output-dir=src/third_party/kasko/binaries', '--revision=56f13b37f044639b4c28cb75f327ca5e3db8758e', '--resource=kasko.zip', '--resource=kasko_symbols.zip',
diff --git a/WATCHLISTS b/WATCHLISTS index 2dee4f4..5309167 100644 --- a/WATCHLISTS +++ b/WATCHLISTS
@@ -29,6 +29,9 @@ 'filepath': 'chrome/browser/extensions/activity_log/' \ '|chrome/browser/extensions/api/activity_log_private/' }, + 'android_infobars': { + 'filepath': 'chrome/android/java/src/org/chromium/chrome/browser/infobar/' + }, 'android_infra': { 'filepath': 'build/android/' \ '|testing/android/' \ @@ -1226,6 +1229,7 @@ 'plundblad+watch@chromium.org', 'yuzo+watch@chromium.org'], 'activity_log': ['felt@chromium.org'], + 'android_infobars': ['dfalcantara+watch@chromium.org'], 'android_infra': ['yfriedman+watch@chromium.org', 'klundberg+watch@chromium.org', 'jbudorick+watch@chromium.org', @@ -1436,8 +1440,7 @@ 'piman+watch@chromium.org', 'ihf+watch@chromium.org', 'yusukes+watch@chromium.org', 'binji+watch@chromium.org', 'teravest+watch@chromium.org', 'tzik@chromium.org'], - 'permissions': ['mlamouri+watch-permissions@chromium.org', - 'kcarattini+watch@chromium.org'], + 'permissions': ['mlamouri+watch-permissions@chromium.org'], 'plugin': ['jam@chromium.org'], 'policy_definitions': ['tnagel+watch@chromium.org'], 'polymer': ['michaelpg+watch-polymer@chromium.org'], @@ -1471,7 +1474,7 @@ 'rlp+watch@chromium.org', 'rouslan+spell@chromium.org'], 'streams': ['zork+watch@chromium.org'], - 'styleguide': ['vmpstr+watch@chromium.org'], + 'styleguide': ['danakj+watch@chromium.org', 'jbroman+cpp@chromium.org', 'vmpstr+watch@chromium.org'], 'sync': ['tim+watch@chromium.org', 'maxbogue+watch@chromium.org', 'plaree+watch@chromium.org', @@ -1589,7 +1592,7 @@ 'blink_owners': [ 'abarth@chromium.org'], 'blink_platform': [ 'kinuko+watch@chromium.org' ], 'blink_platform_graphics': [ 'schenney@chromium.org', - 'danakj@chromium.org', + 'danakj+watch@chromium.org', 'pdr+graphicswatchlist@chromium.org', 'cabanier@adobe.com', 'dschulze@chromium.org',
diff --git a/android_webview/BUILD.gn b/android_webview/BUILD.gn index 95fe942..2498a1c 100644 --- a/android_webview/BUILD.gn +++ b/android_webview/BUILD.gn
@@ -9,6 +9,10 @@ import("system_webview_apk_tmpl.gni") import("webview_repack_locales.gni") +if (!defined(use_webview_internal_framework)) { + use_webview_internal_framework = false +} + group("android_webview") { if (!use_webview_internal_framework) { deps = [
diff --git a/android_webview/browser/hardware_renderer.cc b/android_webview/browser/hardware_renderer.cc index 032c877..cde6161 100644 --- a/android_webview/browser/hardware_renderer.cc +++ b/android_webview/browser/hardware_renderer.cc
@@ -172,7 +172,7 @@ // Surface and transformed using the given transform. scoped_ptr<cc::RenderPass> render_pass = cc::RenderPass::Create(); render_pass->SetAll(cc::RenderPassId(1, 1), gfx::Rect(viewport), clip, - gfx::Transform(), true); + gfx::Transform(), false); cc::SharedQuadState* quad_state = render_pass->CreateAndAppendSharedQuadState();
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientShouldOverrideUrlLoadingTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientShouldOverrideUrlLoadingTest.java index aeaa73e..0694501 100644 --- a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientShouldOverrideUrlLoadingTest.java +++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientShouldOverrideUrlLoadingTest.java
@@ -14,6 +14,7 @@ import org.chromium.android_webview.test.util.JSUtils; import org.chromium.android_webview.test.util.JavascriptEventObserver; import org.chromium.base.annotations.SuppressFBWarnings; +import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.DisabledTest; import org.chromium.base.test.util.Feature; import org.chromium.content.browser.test.util.CallbackHelper; @@ -22,6 +23,7 @@ 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.common.ContentSwitches; import org.chromium.content_public.browser.LoadUrlParams; import org.chromium.net.test.util.TestWebServer; @@ -40,6 +42,15 @@ private static final String REDIRECT_TARGET_PATH = "/redirect_target.html"; private static final String TITLE = "TITLE"; private static final String TAG = "AwContentsClientShouldOverrideUrlLoadingTest"; + private static final String TEST_EMAIL = "nobody@example.org"; + private static final String TEST_EMAIL_URI = "mailto:" + TEST_EMAIL.replace("@", "%40"); + private static final String TEST_PHONE = "+16503336000"; + private static final String TEST_PHONE_URI = "tel:" + TEST_PHONE.replace("+", "%2B"); + // Use the shortest possible address to ensure it fits into one line. + // Otherwise, click on the center of the HTML element may get into empty space. + private static final String TEST_ADDRESS = "1 st. long enough, CA 90000"; + private static final String TEST_ADDRESS_URI = "geo:0,0?q=" + + TEST_ADDRESS.replace(" ", "+").replace(",", "%2C"); private TestWebServer mWebServer; private TestAwContentsClient mContentsClient; @@ -911,7 +922,7 @@ return false; } }); - mAwContents.getSettings().setJavaScriptEnabled(true); + enableJavaScriptOnUiThread(mAwContents); final String pageTitle = "Click Title"; final String htmlWithLink = "<html><title>" + pageTitle + "</title>" + "<body><a id='link' href='" + testUrl + "'>Click this!</a></body></html>"; @@ -945,9 +956,37 @@ } } - @SmallTest - @Feature({"AndroidWebView"}) - public void testNullContentsClientClickableContent() throws Throwable { + private String setupForContentClickTest(final String content, boolean inMainFrame) + throws Exception { + final String contentId = "content"; + final String findContentJs = inMainFrame + ? "document.getElementById(\"" + contentId + "\")" + : "window.frames[0].document.getElementById(\"" + contentId + "\")"; + final String pageHtml = inMainFrame + ? "<html><body onload='document.title=" + findContentJs + ".innerText'>" + + "<span id='" + contentId + "'>" + content + "</span></body></html>" + : "<html>" + + "<body style='margin:0;' onload='document.title=" + findContentJs + ".innerText'>" + + " <iframe style='border:none;width:100%;' srcdoc=\"" + + " <body style='margin:0;'><span id='" + contentId + "'>" + + content + "</span></body>" + + "\" src='iframe.html'></iframe>" + + "</body></html>"; + final String testUrl = mWebServer.setResponse("/content_test.html", pageHtml, null); + + enableJavaScriptOnUiThread(mAwContents); + loadUrlAsync(mAwContents, testUrl); + pollOnUiThread(new Callable<Boolean>() { + @Override + public Boolean call() { + return mAwContents.getTitle().equals(content); + } + }); + return findContentJs; + } + + private void doTestNullContentsClientClickableContent(String pageContent, + String intentContent) throws Throwable { try { // The test will fire real intents through the test activity. // Need to temporarily suppress startActivity otherwise there will be a @@ -959,69 +998,51 @@ return false; } }); - final String pageTitle = "Click Title"; - final String testEmail = "nobody@example.org"; - final String testUrl = mWebServer.setResponse("/email_test.html", - "<html><head><title>" + pageTitle + "</title></head>" - + "<body><span id='email'>" + testEmail + "</span></body>", null); - // JS is required for the click simulator. - mAwContents.getSettings().setJavaScriptEnabled(true); - loadUrlAsync(mAwContents, testUrl); - pollOnUiThread(new Callable<Boolean>() { - @Override - public Boolean call() { - return mAwContents.getTitle().equals(pageTitle); - } - }); - - // Clicking on an email should create an intent. - DOMUtils.clickNode(this, mAwContents.getContentViewCore(), "email"); + final String findContentJs = setupForContentClickTest(pageContent, true); + // Clicking on the content should create an intent. + DOMUtils.clickNodeByJs(this, mAwContents.getContentViewCore(), findContentJs); pollOnUiThread(new Callable<Boolean>() { @Override public Boolean call() { return getActivity().getLastSentIntent() != null; } }); - assertEquals("mailto:" + testEmail.replace("@", "%40"), + assertEquals(intentContent, getActivity().getLastSentIntent().getData().toString()); } finally { getActivity().setIgnoreStartActivity(false); } } - private void doTestClickableContent(boolean inMainFrame) throws Throwable { + @SmallTest + @Feature({"AndroidWebView"}) + public void testNullContentsClientClickableEmail() throws Throwable { + doTestNullContentsClientClickableContent(TEST_EMAIL, TEST_EMAIL_URI); + } + + @SmallTest + @Feature({"AndroidWebView"}) + @CommandLineFlags.Add({ContentSwitches.NETWORK_COUNTRY_ISO + "=us"}) + public void testNullContentsClientClickablePhone() throws Throwable { + doTestNullContentsClientClickableContent(TEST_PHONE, TEST_PHONE_URI); + } + + @SmallTest + @Feature({"AndroidWebView"}) + public void testNullContentsClientClickableAddress() throws Throwable { + doTestNullContentsClientClickableContent(TEST_ADDRESS, TEST_ADDRESS_URI); + } + + private void doTestClickableContent(String pageContent, String intentContent, + boolean inMainFrame) throws Throwable { standardSetup(); - final String testEmail = "nobody@example.org"; - final String findEmailJs = inMainFrame - ? "document.getElementById(\"email\")" - : "window.frames[0].document.getElementById(\"email\")"; - final String pageHtml = inMainFrame - ? "<html><body onload='document.title=" + findEmailJs + ".innerText'>" - + "<span id='email'>" + testEmail + "</span></body></html>" - : "<html>" - + "<body style='margin:0;' onload='document.title=" + findEmailJs + ".innerText'>" - + " <iframe style='border:none;' srcdoc=\"" - + " <body style='margin:0;'><span id='email'>" + testEmail + "</span></body>" - + "\" src='iframe.html'></iframe>" - + "</body></html>"; - final String testUrl = mWebServer.setResponse("/email_test.html", pageHtml, null); - - // JS is required for the click simulator. - mAwContents.getSettings().setJavaScriptEnabled(true); - loadUrlAsync(mAwContents, testUrl); - pollOnUiThread(new Callable<Boolean>() { - @Override - public Boolean call() { - return mAwContents.getTitle().equals(testEmail); - } - }); - + final String findContentJs = setupForContentClickTest(pageContent, inMainFrame); int callCount = mShouldOverrideUrlLoadingHelper.getCallCount(); - DOMUtils.clickNodeByJs(this, mAwContents.getContentViewCore(), findEmailJs); + DOMUtils.clickNodeByJs(this, mAwContents.getContentViewCore(), findContentJs); mShouldOverrideUrlLoadingHelper.waitForCallback(callCount); - assertEquals("mailto:" + testEmail.replace("@", "%40"), + assertEquals(intentContent, mShouldOverrideUrlLoadingHelper.getShouldOverrideUrlLoadingUrl()); assertFalse(mShouldOverrideUrlLoadingHelper.isRedirect()); assertTrue(mShouldOverrideUrlLoadingHelper.hasUserGesture()); @@ -1030,14 +1051,40 @@ @SmallTest @Feature({"AndroidWebView"}) - public void testClickableContent() throws Throwable { - doTestClickableContent(true); + public void testClickableEmail() throws Throwable { + doTestClickableContent(TEST_EMAIL, TEST_EMAIL_URI, true); } @SmallTest @Feature({"AndroidWebView"}) - public void testClickableContentInIframe() throws Throwable { - doTestClickableContent(false); + @CommandLineFlags.Add({ContentSwitches.NETWORK_COUNTRY_ISO + "=us"}) + public void testClickablePhone() throws Throwable { + doTestClickableContent(TEST_PHONE, TEST_PHONE_URI, true); + } + + @SmallTest + @Feature({"AndroidWebView"}) + public void testClickableAddress() throws Throwable { + doTestClickableContent(TEST_ADDRESS, TEST_ADDRESS_URI, true); + } + + @SmallTest + @Feature({"AndroidWebView"}) + public void testClickableEmailInIframe() throws Throwable { + doTestClickableContent(TEST_EMAIL, TEST_EMAIL_URI, false); + } + + @SmallTest + @Feature({"AndroidWebView"}) + @CommandLineFlags.Add({ContentSwitches.NETWORK_COUNTRY_ISO + "=us"}) + public void testClickablePhoneInIframe() throws Throwable { + doTestClickableContent(TEST_PHONE, TEST_PHONE_URI, false); + } + + @SmallTest + @Feature({"AndroidWebView"}) + public void testClickableAddressInIframe() throws Throwable { + doTestClickableContent(TEST_ADDRESS, TEST_ADDRESS_URI, false); } @SmallTest
diff --git a/ash/BUILD.gn b/ash/BUILD.gn index 9dfa6f2..7b0919c2 100644 --- a/ash/BUILD.gn +++ b/ash/BUILD.gn
@@ -6,6 +6,8 @@ import("//build/config/ui.gni") import("//testing/test.gni") +assert(use_ash) + gypi_values = exec_script("//build/gypi_to_gn.py", [ rebase_path("ash.gyp") ], "scope",
diff --git a/ash/ash.gyp b/ash/ash.gyp index 960d9aa..6b695b53 100644 --- a/ash/ash.gyp +++ b/ash/ash.gyp
@@ -33,6 +33,8 @@ 'ash_constants.cc', 'ash_constants.h', 'ash_export.h', + 'ash_layout_constants.cc', + 'ash_layout_constants.h', 'ash_switches.cc', 'ash_switches.h', 'ash_touch_exploration_manager_chromeos.cc', @@ -970,6 +972,7 @@ '../ui/events/platform/events_platform.gyp:events_platform', '../ui/gfx/gfx.gyp:gfx', '../ui/gfx/gfx.gyp:gfx_geometry', + '../ui/gfx/gfx.gyp:gfx_vector_icons', '../ui/keyboard/keyboard.gyp:keyboard', '../ui/message_center/message_center.gyp:message_center', '../ui/resources/ui_resources.gyp:ui_resources',
diff --git a/ash/ash_layout_constants.cc b/ash/ash_layout_constants.cc new file mode 100644 index 0000000..de59f2c --- /dev/null +++ b/ash/ash_layout_constants.cc
@@ -0,0 +1,36 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/ash_layout_constants.h" + +#include "base/logging.h" +#include "ui/base/resource/material_design/material_design_controller.h" + +gfx::Size GetAshLayoutSize(AshLayoutSize size) { + const int kBrowserMaximizedCaptionButtonHeight[] = {27, 32, 36}; + const int kBrowserMaximizedCaptionButtonWidth[] = {35, 32, 32}; + const int kBrowserRestoredCaptionButtonHeight[] = {35, 36, 40}; + const int kBrowserRestoredCaptionButtonWidth[] = {35, 32, 32}; + const int kNonBrowserCaptionButtonHeight[] = {33, 33, 33}; + const int kNonBrowserCaptionButtonWidth[] = {32, 32, 32}; + + const int mode = ui::MaterialDesignController::GetMode(); + switch (size) { + case AshLayoutSize::BROWSER_MAXIMIZED_CAPTION_BUTTON: { + return gfx::Size(kBrowserMaximizedCaptionButtonWidth[mode], + kBrowserMaximizedCaptionButtonHeight[mode]); + } + case AshLayoutSize::BROWSER_RESTORED_CAPTION_BUTTON: { + return gfx::Size(kBrowserRestoredCaptionButtonWidth[mode], + kBrowserRestoredCaptionButtonHeight[mode]); + } + case AshLayoutSize::NON_BROWSER_CAPTION_BUTTON: { + return gfx::Size(kNonBrowserCaptionButtonWidth[mode], + kNonBrowserCaptionButtonHeight[mode]); + } + } + + NOTREACHED(); + return gfx::Size(); +}
diff --git a/ash/ash_layout_constants.h b/ash/ash_layout_constants.h new file mode 100644 index 0000000..5e0c088b --- /dev/null +++ b/ash/ash_layout_constants.h
@@ -0,0 +1,24 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_ASH_LAYOUT_CONSTANTS_H_ +#define ASH_ASH_LAYOUT_CONSTANTS_H_ + +#include "ash/ash_export.h" +#include "ui/gfx/geometry/size.h" + +enum class AshLayoutSize { + // Size of a caption button in a maximized browser window. + BROWSER_MAXIMIZED_CAPTION_BUTTON, + + // Size of a caption button in a restored browser window. + BROWSER_RESTORED_CAPTION_BUTTON, + + // Size of a caption button in a non-browser window. + NON_BROWSER_CAPTION_BUTTON, +}; + +ASH_EXPORT gfx::Size GetAshLayoutSize(AshLayoutSize size); + +#endif // ASH_ASH_LAYOUT_CONSTANTS_H_
diff --git a/ash/display/display_layout_store.cc b/ash/display/display_layout_store.cc index aacbf62..7cf3b03 100644 --- a/ash/display/display_layout_store.cc +++ b/ash/display/display_layout_store.cc
@@ -50,6 +50,11 @@ int64_t id2, const DisplayLayout& layout) { auto key = CreateDisplayIdPair(id1, id2); + + // Do not overwrite the valid data with old invalid date. + if (paired_layouts_.count(key) && !CompareDisplayIds(id1, id2)) + return; + paired_layouts_[key] = layout; }
diff --git a/ash/display/display_manager_unittest.cc b/ash/display/display_manager_unittest.cc index d23ac307..e216672 100644 --- a/ash/display/display_manager_unittest.cc +++ b/ash/display/display_manager_unittest.cc
@@ -2001,6 +2001,26 @@ info.GetRotation(gfx::Display::ROTATION_SOURCE_ACTIVE)); } +TEST_F(DisplayManagerTest, RejectInvalidLayoutData) { + DisplayLayoutStore* layout_store = display_manager()->layout_store(); + int64_t id1 = 10001; + int64_t id2 = 10002; + ASSERT_TRUE(CompareDisplayIds(id1, id2)); + DisplayLayout good(DisplayLayout(DisplayLayout::LEFT, 0)); + good.primary_id = id1; + + layout_store->RegisterLayoutForDisplayIdPair(id1, id2, good); + + DisplayLayout bad(DisplayLayout(DisplayLayout::BOTTOM, 0)); + good.primary_id = id2; + + layout_store->RegisterLayoutForDisplayIdPair(id2, id1, bad); + + EXPECT_EQ(good.ToString(), layout_store->GetRegisteredDisplayLayout( + CreateDisplayIdPair(id1, id2)) + .ToString()); +} + #endif // OS_CHROMEOS } // namespace ash
diff --git a/ash/frame/caption_buttons/frame_caption_button.cc b/ash/frame/caption_buttons/frame_caption_button.cc index 99ac5548..300e2ba2 100644 --- a/ash/frame/caption_buttons/frame_caption_button.cc +++ b/ash/frame/caption_buttons/frame_caption_button.cc
@@ -4,10 +4,12 @@ #include "ash/frame/caption_buttons/frame_caption_button.h" -#include "ui/base/resource/resource_bundle.h" #include "ui/gfx/animation/slide_animation.h" #include "ui/gfx/animation/throb_animation.h" #include "ui/gfx/canvas.h" +#include "ui/gfx/color_palette.h" +#include "ui/gfx/paint_vector_icon.h" +#include "ui/gfx/vector_icons_public.h" namespace ash { @@ -23,6 +25,13 @@ // The alpha to draw inactive icons with. const float kInactiveIconAlpha = 0.2f; +// The colors and alpha values used for the button background hovered and +// pressed states. +// TODO(tdanderson|estade): Request these colors from ThemeProvider. +const int kHoveredAlpha = 0x14; +const SkColor kHoveredPressedColor = SK_ColorBLACK; +const int kPressedAlpha = 0x24; + } // namespace // static @@ -33,10 +42,9 @@ : CustomButton(listener), icon_(icon), paint_as_active_(false), + use_light_images_(false), alpha_(255), - icon_image_id_(-1), - hovered_background_image_id_(-1), - pressed_background_image_id_(-1), + icon_image_id_(gfx::VectorIconId::VECTOR_ICON_NONE), swap_images_animation_(new gfx::SlideAnimation(this)) { swap_images_animation_->Reset(1); @@ -48,18 +56,14 @@ FrameCaptionButton::~FrameCaptionButton() { } -void FrameCaptionButton::SetImages(CaptionButtonIcon icon, - Animate animate, - int icon_image_id, - int hovered_background_image_id, - int pressed_background_image_id) { - // The early return is dependant on |animate| because callers use SetImages() +void FrameCaptionButton::SetImage(CaptionButtonIcon icon, + Animate animate, + gfx::VectorIconId icon_image_id) { + // The early return is dependent on |animate| because callers use SetImage() // with ANIMATE_NO to progress the crossfade animation to the end. if (icon == icon_ && (animate == ANIMATE_YES || !swap_images_animation_->is_animating()) && - icon_image_id == icon_image_id_ && - hovered_background_image_id == hovered_background_image_id_ && - pressed_background_image_id == pressed_background_image_id_) { + icon_image_id == icon_image_id_) { return; } @@ -68,15 +72,9 @@ icon_ = icon; icon_image_id_ = icon_image_id; - hovered_background_image_id_ = hovered_background_image_id; - pressed_background_image_id_ = pressed_background_image_id; - - ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); - icon_image_ = *rb.GetImageSkiaNamed(icon_image_id); - hovered_background_image_ = *rb.GetImageSkiaNamed( - hovered_background_image_id); - pressed_background_image_ = *rb.GetImageSkiaNamed( - pressed_background_image_id); + icon_image_ = gfx::CreateVectorIcon( + icon_image_id, 12, + use_light_images_ ? SK_ColorWHITE : gfx::kChromeIconGrey); if (animate == ANIMATE_YES) { swap_images_animation_->Reset(0); @@ -101,8 +99,7 @@ } gfx::Size FrameCaptionButton::GetPreferredSize() const { - return hovered_background_image_.isNull() ? - gfx::Size() : hovered_background_image_.size(); + return size_; } const char* FrameCaptionButton::GetClassName() const { @@ -110,17 +107,16 @@ } void FrameCaptionButton::OnPaint(gfx::Canvas* canvas) { - if (hover_animation().is_animating() || state() == STATE_HOVERED) { - int hovered_background_alpha = - hover_animation().is_animating() - ? hover_animation().CurrentValueBetween(0, 255) - : 255; - SkPaint paint; - paint.setAlpha(hovered_background_alpha); - canvas->DrawImageInt(hovered_background_image_, 0, 0, paint); - } else if (state() == STATE_PRESSED) { - canvas->DrawImageInt(pressed_background_image_, 0, 0); - } + SkAlpha bg_alpha = SK_AlphaTRANSPARENT; + if (hover_animation().is_animating()) + bg_alpha = hover_animation().CurrentValueBetween(0, kHoveredAlpha); + else if (state() == STATE_HOVERED) + bg_alpha = kHoveredAlpha; + else if (state() == STATE_PRESSED) + bg_alpha = kPressedAlpha; + + if (bg_alpha != SK_AlphaTRANSPARENT) + canvas->DrawColor(SkColorSetA(kHoveredPressedColor, bg_alpha)); int icon_alpha = swap_images_animation_->CurrentValueBetween(0, 255); int crossfade_icon_alpha = 0;
diff --git a/ash/frame/caption_buttons/frame_caption_button.h b/ash/frame/caption_buttons/frame_caption_button.h index 144f1e9..a8ed2a7 100644 --- a/ash/frame/caption_buttons/frame_caption_button.h +++ b/ash/frame/caption_buttons/frame_caption_button.h
@@ -14,6 +14,7 @@ namespace gfx { class SlideAnimation; +enum class VectorIconId; } namespace ash { @@ -32,18 +33,16 @@ FrameCaptionButton(views::ButtonListener* listener, CaptionButtonIcon icon); ~FrameCaptionButton() override; - // Sets the images to use to paint the button. If |animate| is ANIMATE_YES, - // the button crossfades to the new visuals. If the image ids match those - // currently used by the button and |animate| is ANIMATE_NO the crossfade + // Sets the image to use to paint the button. If |animate| is ANIMATE_YES, + // the button crossfades to the new visuals. If the image id matches the one + // currently used by the button and |animate| is ANIMATE_NO, the crossfade // animation is progressed to the end. - void SetImages(CaptionButtonIcon icon, - Animate animate, - int icon_image_id, - int hovered_background_image_id, - int pressed_background_image_id); + void SetImage(CaptionButtonIcon icon, + Animate animate, + gfx::VectorIconId icon_image_id); // Returns true if the button is crossfading to new visuals set in - // SetImages(). + // SetImage(). bool IsAnimatingImageSwap() const; // Sets the alpha to use for painting. Used to animate visibility changes. @@ -58,11 +57,15 @@ paint_as_active_ = paint_as_active; } + void set_use_light_images(bool light) { use_light_images_ = light; } + CaptionButtonIcon icon() const { return icon_; } - int icon_image_id() const { return icon_image_id_; } + gfx::VectorIconId icon_image_id() const { return icon_image_id_; } + + void set_size(const gfx::Size& size) { size_ = size; } protected: // views::CustomButton override: @@ -77,25 +80,27 @@ // The button's current icon. CaptionButtonIcon icon_; + // The size of the button. + gfx::Size size_; + // Whether the button should be painted as active. bool paint_as_active_; + // Whether to paint in a lighter color (for use on dark backgrounds). + bool use_light_images_; + // Current alpha to use for painting. int alpha_; - // The images and image ids used to paint the button. - int icon_image_id_; - int hovered_background_image_id_; - int pressed_background_image_id_; + // The image id and image used to paint the button's icon. + gfx::VectorIconId icon_image_id_; gfx::ImageSkia icon_image_; - gfx::ImageSkia hovered_background_image_; - gfx::ImageSkia pressed_background_image_; // The icon image to crossfade from. gfx::ImageSkia crossfade_icon_image_; // Crossfade animation started when the button's images are changed by - // SetImages(). + // SetImage(). scoped_ptr<gfx::SlideAnimation> swap_images_animation_; DISALLOW_COPY_AND_ASSIGN(FrameCaptionButton);
diff --git a/ash/frame/caption_buttons/frame_caption_button_container_view.cc b/ash/frame/caption_buttons/frame_caption_button_container_view.cc index 78c5a38..d500513b 100644 --- a/ash/frame/caption_buttons/frame_caption_button_container_view.cc +++ b/ash/frame/caption_buttons/frame_caption_button_container_view.cc
@@ -22,6 +22,7 @@ #include "ui/gfx/canvas.h" #include "ui/gfx/geometry/insets.h" #include "ui/gfx/geometry/point.h" +#include "ui/gfx/vector_icons_public.h" #include "ui/strings/grit/ui_strings.h" // Accessibility names #include "ui/views/widget/widget.h" #include "ui/views/widget/widget_delegate.h" @@ -149,25 +150,17 @@ container_view_->maximize_mode_animation_->End(); } -void FrameCaptionButtonContainerView::SetButtonImages( +void FrameCaptionButtonContainerView::SetButtonImage( CaptionButtonIcon icon, - int icon_image_id, - int hovered_background_image_id, - int pressed_background_image_id) { - button_icon_id_map_[icon] = ButtonIconIds(icon_image_id, - hovered_background_image_id, - pressed_background_image_id); + gfx::VectorIconId icon_image_id) { + button_icon_id_map_[icon] = icon_image_id; + FrameCaptionButton* buttons[] = { minimize_button_, size_button_, close_button_ }; for (size_t i = 0; i < arraysize(buttons); ++i) { - if (buttons[i]->icon() == icon) { - buttons[i]->SetImages(icon, - FrameCaptionButton::ANIMATE_NO, - icon_image_id, - hovered_background_image_id, - pressed_background_image_id); - } + if (buttons[i]->icon() == icon) + buttons[i]->SetImage(icon, FrameCaptionButton::ANIMATE_NO, icon_image_id); } } @@ -177,6 +170,12 @@ close_button_->set_paint_as_active(paint_as_active); } +void FrameCaptionButtonContainerView::SetUseLightImages(bool light) { + minimize_button_->set_use_light_images(light); + size_button_->set_use_light_images(light); + close_button_->set_use_light_images(light); +} + void FrameCaptionButtonContainerView::ResetWindowControls() { SetButtonsToNormal(ANIMATE_NO); } @@ -208,6 +207,12 @@ } } +void FrameCaptionButtonContainerView::SetButtonSize(const gfx::Size& size) { + minimize_button_->set_size(size); + size_button_->set_size(size); + close_button_->set_size(size); +} + gfx::Size FrameCaptionButtonContainerView::GetPreferredSize() const { int width = 0; for (int i = 0; i < child_count(); ++i) { @@ -299,15 +304,9 @@ FrameCaptionButton::Animate fcb_animate = (animate == ANIMATE_YES) ? FrameCaptionButton::ANIMATE_YES : FrameCaptionButton::ANIMATE_NO; - std::map<CaptionButtonIcon, ButtonIconIds>::const_iterator it = - button_icon_id_map_.find(icon); - if (it != button_icon_id_map_.end()) { - button->SetImages(icon, - fcb_animate, - it->second.icon_image_id, - it->second.hovered_background_image_id, - it->second.pressed_background_image_id); - } + auto it = button_icon_id_map_.find(icon); + if (it != button_icon_id_map_.end()) + button->SetImage(icon, fcb_animate, it->second); } bool FrameCaptionButtonContainerView::ShouldSizeButtonBeVisible() const { @@ -418,22 +417,4 @@ } } -FrameCaptionButtonContainerView::ButtonIconIds::ButtonIconIds() - : icon_image_id(-1), - hovered_background_image_id(-1), - pressed_background_image_id(-1) { -} - -FrameCaptionButtonContainerView::ButtonIconIds::ButtonIconIds( - int icon_id, - int hovered_background_id, - int pressed_background_id) - : icon_image_id(icon_id), - hovered_background_image_id(hovered_background_id), - pressed_background_image_id(pressed_background_id) { -} - -FrameCaptionButtonContainerView::ButtonIconIds::~ButtonIconIds() { -} - } // namespace ash
diff --git a/ash/frame/caption_buttons/frame_caption_button_container_view.h b/ash/frame/caption_buttons/frame_caption_button_container_view.h index 352f968..8b93aabc 100644 --- a/ash/frame/caption_buttons/frame_caption_button_container_view.h +++ b/ash/frame/caption_buttons/frame_caption_button_container_view.h
@@ -16,6 +16,7 @@ namespace gfx { class SlideAnimation; +enum class VectorIconId; } namespace views { @@ -65,18 +66,19 @@ DISALLOW_COPY_AND_ASSIGN(TestApi); }; - // Sets the resource ids of the images to paint the button for |icon|. The - // FrameCaptionButtonContainerView will keep track of the images to use for + // Sets the id of the vector image to paint the button for |icon|. The + // FrameCaptionButtonContainerView will keep track of the image to use for // |icon| even if none of the buttons currently use |icon|. - void SetButtonImages(CaptionButtonIcon icon, - int icon_image_id, - int hovered_background_image_id, - int pressed_background_image_id); + void SetButtonImage(CaptionButtonIcon icon, gfx::VectorIconId icon_image_id); // Sets whether the buttons should be painted as active. Does not schedule // a repaint. void SetPaintAsActive(bool paint_as_active); + // Sets whether the buttons should be painted in a lighter color (for use on + // dark backgrounds). + void SetUseLightImages(bool light); + // Tell the window controls to reset themselves to the normal state. void ResetWindowControls(); @@ -90,30 +92,21 @@ // to reflect the change in visibility. void UpdateSizeButtonVisibility(); + // Sets the size of the buttons in this container. + void SetButtonSize(const gfx::Size& size); + // views::View: gfx::Size GetPreferredSize() const override; void Layout() override; const char* GetClassName() const override; - // Overridden from gfx::AnimationDelegate: + // gfx::AnimationDelegate: void AnimationEnded(const gfx::Animation* animation) override; void AnimationProgressed(const gfx::Animation* animation) override; private: friend class FrameCaptionButtonContainerViewTest; - struct ButtonIconIds { - ButtonIconIds(); - ButtonIconIds(int icon_id, - int hovered_background_id, - int pressed_background_id); - ~ButtonIconIds(); - - int icon_image_id; - int hovered_background_image_id; - int pressed_background_image_id; - }; - // Sets |button|'s icon to |icon|. If |animate| is ANIMATE_YES, the button // will crossfade to the new icon. If |animate| is ANIMATE_NO and // |icon| == |button|->icon(), the crossfade animation is progressed to the @@ -149,9 +142,9 @@ FrameCaptionButton* size_button_; FrameCaptionButton* close_button_; - // Mapping of the images needed to paint a button for each of the values of + // Mapping of the image ID needed to paint a button for each of the values of // CaptionButtonIcon. - std::map<CaptionButtonIcon, ButtonIconIds> button_icon_id_map_; + std::map<CaptionButtonIcon, gfx::VectorIconId> button_icon_id_map_; // Animation that affects the position of |minimize_button_| and the // visibility of |size_button_|.
diff --git a/ash/frame/caption_buttons/frame_caption_button_container_view_unittest.cc b/ash/frame/caption_buttons/frame_caption_button_container_view_unittest.cc index 2524d8db..ff87fd4 100644 --- a/ash/frame/caption_buttons/frame_caption_button_container_view_unittest.cc +++ b/ash/frame/caption_buttons/frame_caption_button_container_view_unittest.cc
@@ -4,12 +4,14 @@ #include "ash/frame/caption_buttons/frame_caption_button_container_view.h" +#include "ash/ash_layout_constants.h" #include "ash/frame/caption_buttons/frame_caption_button.h" #include "ash/shell.h" #include "ash/test/ash_test_base.h" #include "ash/wm/maximize_mode/maximize_mode_controller.h" #include "grit/ash_resources.h" #include "ui/gfx/geometry/rect.h" +#include "ui/gfx/vector_icons_public.h" #include "ui/views/widget/widget.h" #include "ui/views/widget/widget_delegate.h" @@ -69,15 +71,14 @@ return widget; } - // Sets |container| to use arbitrary images for the buttons. Setting the - // images causes the buttons to have non-empty sizes. - void SetMockImages(FrameCaptionButtonContainerView* container) { + // Sets arbitrary images for the icons and assign the default caption button + // size to the buttons in |container|. + void InitContainer(FrameCaptionButtonContainerView* container) { + container->SetButtonSize( + GetAshLayoutSize(AshLayoutSize::NON_BROWSER_CAPTION_BUTTON)); for (int icon = 0; icon < CAPTION_BUTTON_ICON_COUNT; ++icon) { - container->SetButtonImages( - static_cast<CaptionButtonIcon>(icon), - IDR_AURA_WINDOW_CONTROL_ICON_CLOSE, - IDR_AURA_WINDOW_CONTROL_BACKGROUND_H, - IDR_AURA_WINDOW_CONTROL_BACKGROUND_P); + container->SetButtonImage(static_cast<CaptionButtonIcon>(icon), + gfx::VectorIconId::WINDOW_CONTROL_CLOSE); } } @@ -113,7 +114,7 @@ // allowed. FrameCaptionButtonContainerView container1( CreateTestWidget(MAXIMIZE_ALLOWED, MINIMIZE_ALLOWED)); - SetMockImages(&container1); + InitContainer(&container1); container1.Layout(); FrameCaptionButtonContainerView::TestApi t1(&container1); EXPECT_TRUE(t1.minimize_button()->visible()); @@ -126,7 +127,7 @@ // maximizing is disallowed. FrameCaptionButtonContainerView container2( CreateTestWidget(MAXIMIZE_DISALLOWED, MINIMIZE_ALLOWED)); - SetMockImages(&container2); + InitContainer(&container2); container2.Layout(); FrameCaptionButtonContainerView::TestApi t2(&container2); EXPECT_TRUE(t2.minimize_button()->visible()); @@ -139,7 +140,7 @@ // neither minimizing nor maximizing are allowed. FrameCaptionButtonContainerView container3( CreateTestWidget(MAXIMIZE_DISALLOWED, MINIMIZE_DISALLOWED)); - SetMockImages(&container3); + InitContainer(&container3); container3.Layout(); FrameCaptionButtonContainerView::TestApi t3(&container3); EXPECT_FALSE(t3.minimize_button()->visible()); @@ -155,7 +156,7 @@ TestUpdateSizeButtonVisibilityAnimation) { FrameCaptionButtonContainerView container( CreateTestWidget(MAXIMIZE_ALLOWED, MINIMIZE_ALLOWED)); - SetMockImages(&container); + InitContainer(&container); container.SetBoundsRect(gfx::Rect(container.GetPreferredSize())); container.Layout();
diff --git a/ash/frame/caption_buttons/frame_size_button_unittest.cc b/ash/frame/caption_buttons/frame_size_button_unittest.cc index 3c950c1..c63e49ef 100644 --- a/ash/frame/caption_buttons/frame_size_button_unittest.cc +++ b/ash/frame/caption_buttons/frame_size_button_unittest.cc
@@ -4,6 +4,7 @@ #include "ash/frame/caption_buttons/frame_size_button.h" +#include "ash/ash_layout_constants.h" #include "ash/frame/caption_buttons/frame_caption_button.h" #include "ash/frame/caption_buttons/frame_caption_button_container_view.h" #include "ash/shell.h" @@ -17,6 +18,7 @@ #include "ui/events/test/event_generator.h" #include "ui/gfx/display.h" #include "ui/gfx/screen.h" +#include "ui/gfx/vector_icons_public.h" #include "ui/views/widget/widget.h" #include "ui/views/widget/widget_delegate.h" @@ -57,14 +59,14 @@ caption_button_container_ = new FrameCaptionButtonContainerView(GetWidget()); - // Set arbitrary images for the container's buttons so that the buttons - // have non-empty sizes. + // Set arbitrary images for the button icons and assign the default + // caption button size. + caption_button_container_->SetButtonSize( + GetAshLayoutSize(AshLayoutSize::NON_BROWSER_CAPTION_BUTTON)); for (int icon = 0; icon < CAPTION_BUTTON_ICON_COUNT; ++icon) { - caption_button_container_->SetButtonImages( + caption_button_container_->SetButtonImage( static_cast<CaptionButtonIcon>(icon), - IDR_AURA_WINDOW_CONTROL_ICON_CLOSE, - IDR_AURA_WINDOW_CONTROL_BACKGROUND_H, - IDR_AURA_WINDOW_CONTROL_BACKGROUND_P); + gfx::VectorIconId::WINDOW_CONTROL_CLOSE); } AddChildView(caption_button_container_);
diff --git a/ash/frame/custom_frame_view_ash_unittest.cc b/ash/frame/custom_frame_view_ash_unittest.cc index 3d227f38..cce5f7d 100644 --- a/ash/frame/custom_frame_view_ash_unittest.cc +++ b/ash/frame/custom_frame_view_ash_unittest.cc
@@ -4,6 +4,7 @@ #include "ash/frame/custom_frame_view_ash.h" +#include "ash/ash_layout_constants.h" #include "ash/frame/caption_buttons/frame_caption_button.h" #include "ash/frame/caption_buttons/frame_caption_button_container_view.h" #include "ash/shell.h" @@ -128,14 +129,11 @@ scoped_ptr<views::Widget> widget(CreateWidget(delegate)); widget->Show(); - ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); - gfx::ImageSkia* close_button = - rb.GetImageSkiaNamed(IDR_AURA_WINDOW_CONTROL_BACKGROUND_H); - // The header should have enough room for the window controls. The // header/content separator line overlays the window controls. - EXPECT_EQ(close_button->height(), - delegate->custom_frame_view()->GetHeaderView()->height()); + EXPECT_EQ( + GetAshLayoutSize(AshLayoutSize::NON_BROWSER_CAPTION_BUTTON).height(), + delegate->custom_frame_view()->GetHeaderView()->height()); } // Verify that CustomFrameViewAsh returns the correct minimum and maximum frame
diff --git a/ash/frame/default_header_painter.cc b/ash/frame/default_header_painter.cc index 62a8465..ed39751 100644 --- a/ash/frame/default_header_painter.cc +++ b/ash/frame/default_header_painter.cc
@@ -4,6 +4,7 @@ #include "ash/frame/default_header_painter.h" +#include "ash/ash_layout_constants.h" #include "ash/frame/caption_buttons/frame_caption_button_container_view.h" #include "ash/frame/header_painter_util.h" #include "base/debug/leak_annotations.h" @@ -20,6 +21,7 @@ #include "ui/gfx/image/image.h" #include "ui/gfx/scoped_canvas.h" #include "ui/gfx/skia_util.h" +#include "ui/gfx/vector_icons_public.h" #include "ui/views/view.h" #include "ui/views/widget/native_widget_aura.h" #include "ui/views/widget/widget.h" @@ -101,6 +103,8 @@ frame_ = frame; view_ = header_view; caption_button_container_ = caption_button_container; + caption_button_container_->SetButtonSize( + GetAshLayoutSize(AshLayoutSize::NON_BROWSER_CAPTION_BUTTON)); UpdateAllButtonImages(); } @@ -155,7 +159,8 @@ } void DefaultHeaderPainter::LayoutHeader() { - UpdateSizeButtonImages(ShouldUseLightImages()); + caption_button_container_->SetUseLightImages(ShouldUseLightImages()); + UpdateSizeButtonImages(); caption_button_container_->Layout(); gfx::Size caption_button_container_size = @@ -292,52 +297,30 @@ } void DefaultHeaderPainter::UpdateAllButtonImages() { - bool use_light_images = ShouldUseLightImages(); - caption_button_container_->SetButtonImages( - CAPTION_BUTTON_ICON_MINIMIZE, - use_light_images ? IDR_AURA_WINDOW_CONTROL_ICON_MINIMIZE_WHITE - : IDR_AURA_WINDOW_CONTROL_ICON_MINIMIZE, - IDR_AURA_WINDOW_CONTROL_BACKGROUND_H, - IDR_AURA_WINDOW_CONTROL_BACKGROUND_P); + caption_button_container_->SetUseLightImages(ShouldUseLightImages()); + caption_button_container_->SetButtonImage( + CAPTION_BUTTON_ICON_MINIMIZE, gfx::VectorIconId::WINDOW_CONTROL_MINIMIZE); - UpdateSizeButtonImages(use_light_images); + UpdateSizeButtonImages(); - caption_button_container_->SetButtonImages( - CAPTION_BUTTON_ICON_CLOSE, - use_light_images ? IDR_AURA_WINDOW_CONTROL_ICON_CLOSE_WHITE - : IDR_AURA_WINDOW_CONTROL_ICON_CLOSE, - IDR_AURA_WINDOW_CONTROL_BACKGROUND_H, - IDR_AURA_WINDOW_CONTROL_BACKGROUND_P); + caption_button_container_->SetButtonImage( + CAPTION_BUTTON_ICON_CLOSE, gfx::VectorIconId::WINDOW_CONTROL_CLOSE); - caption_button_container_->SetButtonImages( + caption_button_container_->SetButtonImage( CAPTION_BUTTON_ICON_LEFT_SNAPPED, - use_light_images ? IDR_AURA_WINDOW_CONTROL_ICON_LEFT_SNAPPED_WHITE - : IDR_AURA_WINDOW_CONTROL_ICON_LEFT_SNAPPED, - IDR_AURA_WINDOW_CONTROL_BACKGROUND_H, - IDR_AURA_WINDOW_CONTROL_BACKGROUND_P); + gfx::VectorIconId::WINDOW_CONTROL_LEFT_SNAPPED); - caption_button_container_->SetButtonImages( + caption_button_container_->SetButtonImage( CAPTION_BUTTON_ICON_RIGHT_SNAPPED, - use_light_images ? IDR_AURA_WINDOW_CONTROL_ICON_RIGHT_SNAPPED_WHITE - : IDR_AURA_WINDOW_CONTROL_ICON_RIGHT_SNAPPED, - IDR_AURA_WINDOW_CONTROL_BACKGROUND_H, - IDR_AURA_WINDOW_CONTROL_BACKGROUND_P); + gfx::VectorIconId::WINDOW_CONTROL_RIGHT_SNAPPED); } -void DefaultHeaderPainter::UpdateSizeButtonImages(bool use_light_images) { - int icon_id = 0; - if (frame_->IsMaximized() || frame_->IsFullscreen()) { - icon_id = use_light_images ? IDR_AURA_WINDOW_CONTROL_ICON_RESTORE_WHITE - : IDR_AURA_WINDOW_CONTROL_ICON_RESTORE; - } else { - icon_id = use_light_images ? IDR_AURA_WINDOW_CONTROL_ICON_MAXIMIZE_WHITE - : IDR_AURA_WINDOW_CONTROL_ICON_MAXIMIZE; - } - caption_button_container_->SetButtonImages( - CAPTION_BUTTON_ICON_MAXIMIZE_RESTORE, - icon_id, - IDR_AURA_WINDOW_CONTROL_BACKGROUND_H, - IDR_AURA_WINDOW_CONTROL_BACKGROUND_P); +void DefaultHeaderPainter::UpdateSizeButtonImages() { + gfx::VectorIconId icon_id = frame_->IsMaximized() || frame_->IsFullscreen() + ? gfx::VectorIconId::WINDOW_CONTROL_RESTORE + : gfx::VectorIconId::WINDOW_CONTROL_MAXIMIZE; + caption_button_container_->SetButtonImage( + CAPTION_BUTTON_ICON_MAXIMIZE_RESTORE, icon_id); } gfx::Rect DefaultHeaderPainter::GetLocalBounds() const {
diff --git a/ash/frame/default_header_painter.h b/ash/frame/default_header_painter.h index d867f6f1..d56c265 100644 --- a/ash/frame/default_header_painter.h +++ b/ash/frame/default_header_painter.h
@@ -84,7 +84,7 @@ void UpdateAllButtonImages(); // Updates the size button's images. - void UpdateSizeButtonImages(bool use_light_images); + void UpdateSizeButtonImages(); // Returns the header bounds in the coordinates of |view_|. The header is // assumed to be positioned at the top left corner of |view_| and to have the
diff --git a/ash/host/ash_window_tree_host_ozone.cc b/ash/host/ash_window_tree_host_ozone.cc index d4b679c..c636080 100644 --- a/ash/host/ash_window_tree_host_ozone.cc +++ b/ash/host/ash_window_tree_host_ozone.cc
@@ -4,6 +4,8 @@ #include "ash/host/ash_window_tree_host.h" +#include <utility> + #include "ash/host/ash_window_tree_host_init_params.h" #include "ash/host/ash_window_tree_host_unified.h" #include "ash/host/root_window_transformer.h" @@ -85,7 +87,7 @@ void AshWindowTreeHostOzone::SetRootWindowTransformer( scoped_ptr<RootWindowTransformer> transformer) { - transformer_helper_.SetRootWindowTransformer(transformer.Pass()); + transformer_helper_.SetRootWindowTransformer(std::move(transformer)); ConfineCursorToRootWindow(); }
diff --git a/ash/resources/ash_resources.grd b/ash/resources/ash_resources.grd index c160d5e..cb56d86 100644 --- a/ash/resources/ash_resources.grd +++ b/ash/resources/ash_resources.grd
@@ -180,22 +180,6 @@ <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_VOLUME_LEVELS" file="cros/status/status_volume_dark.png" /> <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_VOLUME_MUTE" file="cros/status/status_volume_mute.png" /> - <structure type="chrome_scaled_image" name="IDR_AURA_WINDOW_CONTROL_BACKGROUND_H" file="common/window_control_background_hover.png" /> - <structure type="chrome_scaled_image" name="IDR_AURA_WINDOW_CONTROL_BACKGROUND_P" file="common/window_control_background_pressed.png" /> - <structure type="chrome_scaled_image" name="IDR_AURA_WINDOW_CONTROL_ICON_BACK" file="common/window_control_icon_back.png" /> - <structure type="chrome_scaled_image" name="IDR_AURA_WINDOW_CONTROL_ICON_CLOSE" file="common/window_control_icon_close.png" /> - <structure type="chrome_scaled_image" name="IDR_AURA_WINDOW_CONTROL_ICON_CLOSE_WHITE" file="common/window_control_icon_close_white.png" /> - <structure type="chrome_scaled_image" name="IDR_AURA_WINDOW_CONTROL_ICON_LEFT_SNAPPED" file="common/window_control_icon_left_snapped.png" /> - <structure type="chrome_scaled_image" name="IDR_AURA_WINDOW_CONTROL_ICON_LEFT_SNAPPED_WHITE" file="common/window_control_icon_left_snapped_white.png" /> - <structure type="chrome_scaled_image" name="IDR_AURA_WINDOW_CONTROL_ICON_MAXIMIZE" file="common/window_control_icon_maximize.png" /> - <structure type="chrome_scaled_image" name="IDR_AURA_WINDOW_CONTROL_ICON_MAXIMIZE_WHITE" file="common/window_control_icon_maximize_white.png" /> - <structure type="chrome_scaled_image" name="IDR_AURA_WINDOW_CONTROL_ICON_MINIMIZE" file="common/window_control_icon_minimize.png" /> - <structure type="chrome_scaled_image" name="IDR_AURA_WINDOW_CONTROL_ICON_MINIMIZE_WHITE" file="common/window_control_icon_minimize_white.png" /> - <structure type="chrome_scaled_image" name="IDR_AURA_WINDOW_CONTROL_ICON_RESTORE" file="common/window_control_icon_restore.png" /> - <structure type="chrome_scaled_image" name="IDR_AURA_WINDOW_CONTROL_ICON_RESTORE_WHITE" file="common/window_control_icon_restore_white.png" /> - <structure type="chrome_scaled_image" name="IDR_AURA_WINDOW_CONTROL_ICON_RIGHT_SNAPPED" file="common/window_control_icon_right_snapped.png" /> - <structure type="chrome_scaled_image" name="IDR_AURA_WINDOW_CONTROL_ICON_RIGHT_SNAPPED_WHITE" file="common/window_control_icon_right_snapped_white.png" /> - <structure type="chrome_scaled_image" name="IDR_AURA_WINDOW_HEADER_SHADE_INACTIVE_BOTTOM" file="common/window_header_shade_bottom_inactive.png" /> <structure type="chrome_scaled_image" name="IDR_AURA_WINDOW_HEADER_SHADE_INACTIVE_LEFT" file="common/window_header_shade_left_inactive.png" /> <structure type="chrome_scaled_image" name="IDR_AURA_WINDOW_HEADER_SHADE_INACTIVE_RIGHT" file="common/window_header_shade_right_inactive.png" />
diff --git a/ash/resources/default_100_percent/common/window_control_background_hover.png b/ash/resources/default_100_percent/common/window_control_background_hover.png deleted file mode 100644 index f32a78ea..0000000 --- a/ash/resources/default_100_percent/common/window_control_background_hover.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_100_percent/common/window_control_background_pressed.png b/ash/resources/default_100_percent/common/window_control_background_pressed.png deleted file mode 100644 index 2aee9da..0000000 --- a/ash/resources/default_100_percent/common/window_control_background_pressed.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_100_percent/common/window_control_icon_back.png b/ash/resources/default_100_percent/common/window_control_icon_back.png deleted file mode 100644 index 2e0723d..0000000 --- a/ash/resources/default_100_percent/common/window_control_icon_back.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_100_percent/common/window_control_icon_close.png b/ash/resources/default_100_percent/common/window_control_icon_close.png deleted file mode 100644 index db26524..0000000 --- a/ash/resources/default_100_percent/common/window_control_icon_close.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_100_percent/common/window_control_icon_close_white.png b/ash/resources/default_100_percent/common/window_control_icon_close_white.png deleted file mode 100644 index 1bc6a84..0000000 --- a/ash/resources/default_100_percent/common/window_control_icon_close_white.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_100_percent/common/window_control_icon_left_snapped.png b/ash/resources/default_100_percent/common/window_control_icon_left_snapped.png deleted file mode 100644 index 4374068dfb..0000000 --- a/ash/resources/default_100_percent/common/window_control_icon_left_snapped.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_100_percent/common/window_control_icon_left_snapped_white.png b/ash/resources/default_100_percent/common/window_control_icon_left_snapped_white.png deleted file mode 100644 index 58be13a..0000000 --- a/ash/resources/default_100_percent/common/window_control_icon_left_snapped_white.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_100_percent/common/window_control_icon_maximize.png b/ash/resources/default_100_percent/common/window_control_icon_maximize.png deleted file mode 100644 index ce0cf13..0000000 --- a/ash/resources/default_100_percent/common/window_control_icon_maximize.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_100_percent/common/window_control_icon_maximize_white.png b/ash/resources/default_100_percent/common/window_control_icon_maximize_white.png deleted file mode 100644 index 5dc6ccb..0000000 --- a/ash/resources/default_100_percent/common/window_control_icon_maximize_white.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_100_percent/common/window_control_icon_minimize.png b/ash/resources/default_100_percent/common/window_control_icon_minimize.png deleted file mode 100644 index 48c262c..0000000 --- a/ash/resources/default_100_percent/common/window_control_icon_minimize.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_100_percent/common/window_control_icon_minimize_white.png b/ash/resources/default_100_percent/common/window_control_icon_minimize_white.png deleted file mode 100644 index b085916..0000000 --- a/ash/resources/default_100_percent/common/window_control_icon_minimize_white.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_100_percent/common/window_control_icon_restore.png b/ash/resources/default_100_percent/common/window_control_icon_restore.png deleted file mode 100644 index 565dae9c..0000000 --- a/ash/resources/default_100_percent/common/window_control_icon_restore.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_100_percent/common/window_control_icon_restore_white.png b/ash/resources/default_100_percent/common/window_control_icon_restore_white.png deleted file mode 100644 index 5b51c15..0000000 --- a/ash/resources/default_100_percent/common/window_control_icon_restore_white.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_100_percent/common/window_control_icon_right_snapped.png b/ash/resources/default_100_percent/common/window_control_icon_right_snapped.png deleted file mode 100644 index 53551d4f..0000000 --- a/ash/resources/default_100_percent/common/window_control_icon_right_snapped.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_100_percent/common/window_control_icon_right_snapped_white.png b/ash/resources/default_100_percent/common/window_control_icon_right_snapped_white.png deleted file mode 100644 index b02d33c..0000000 --- a/ash/resources/default_100_percent/common/window_control_icon_right_snapped_white.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_200_percent/common/window_control_background_hover.png b/ash/resources/default_200_percent/common/window_control_background_hover.png deleted file mode 100644 index d37f619e9..0000000 --- a/ash/resources/default_200_percent/common/window_control_background_hover.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_200_percent/common/window_control_background_pressed.png b/ash/resources/default_200_percent/common/window_control_background_pressed.png deleted file mode 100644 index 77fcf5f..0000000 --- a/ash/resources/default_200_percent/common/window_control_background_pressed.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_200_percent/common/window_control_icon_back.png b/ash/resources/default_200_percent/common/window_control_icon_back.png deleted file mode 100644 index 34e907b..0000000 --- a/ash/resources/default_200_percent/common/window_control_icon_back.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_200_percent/common/window_control_icon_close.png b/ash/resources/default_200_percent/common/window_control_icon_close.png deleted file mode 100644 index 5c14ecd..0000000 --- a/ash/resources/default_200_percent/common/window_control_icon_close.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_200_percent/common/window_control_icon_close_white.png b/ash/resources/default_200_percent/common/window_control_icon_close_white.png deleted file mode 100644 index 27cef0f..0000000 --- a/ash/resources/default_200_percent/common/window_control_icon_close_white.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_200_percent/common/window_control_icon_left_snapped.png b/ash/resources/default_200_percent/common/window_control_icon_left_snapped.png deleted file mode 100644 index f8db919..0000000 --- a/ash/resources/default_200_percent/common/window_control_icon_left_snapped.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_200_percent/common/window_control_icon_left_snapped_white.png b/ash/resources/default_200_percent/common/window_control_icon_left_snapped_white.png deleted file mode 100644 index 6e938b8..0000000 --- a/ash/resources/default_200_percent/common/window_control_icon_left_snapped_white.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_200_percent/common/window_control_icon_maximize.png b/ash/resources/default_200_percent/common/window_control_icon_maximize.png deleted file mode 100644 index a5947a59..0000000 --- a/ash/resources/default_200_percent/common/window_control_icon_maximize.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_200_percent/common/window_control_icon_maximize_white.png b/ash/resources/default_200_percent/common/window_control_icon_maximize_white.png deleted file mode 100644 index 5e17aaef..0000000 --- a/ash/resources/default_200_percent/common/window_control_icon_maximize_white.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_200_percent/common/window_control_icon_minimize.png b/ash/resources/default_200_percent/common/window_control_icon_minimize.png deleted file mode 100644 index 837b433f..0000000 --- a/ash/resources/default_200_percent/common/window_control_icon_minimize.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_200_percent/common/window_control_icon_minimize_white.png b/ash/resources/default_200_percent/common/window_control_icon_minimize_white.png deleted file mode 100644 index cb295d0..0000000 --- a/ash/resources/default_200_percent/common/window_control_icon_minimize_white.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_200_percent/common/window_control_icon_restore.png b/ash/resources/default_200_percent/common/window_control_icon_restore.png deleted file mode 100644 index 5a327bb..0000000 --- a/ash/resources/default_200_percent/common/window_control_icon_restore.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_200_percent/common/window_control_icon_restore_white.png b/ash/resources/default_200_percent/common/window_control_icon_restore_white.png deleted file mode 100644 index a2e02ed..0000000 --- a/ash/resources/default_200_percent/common/window_control_icon_restore_white.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_200_percent/common/window_control_icon_right_snapped.png b/ash/resources/default_200_percent/common/window_control_icon_right_snapped.png deleted file mode 100644 index 8eed437a..0000000 --- a/ash/resources/default_200_percent/common/window_control_icon_right_snapped.png +++ /dev/null Binary files differ
diff --git a/ash/resources/default_200_percent/common/window_control_icon_right_snapped_white.png b/ash/resources/default_200_percent/common/window_control_icon_right_snapped_white.png deleted file mode 100644 index d8d5cfd4..0000000 --- a/ash/resources/default_200_percent/common/window_control_icon_right_snapped_white.png +++ /dev/null Binary files differ
diff --git a/ash/shell/content/client/shell_browser_main_parts.cc b/ash/shell/content/client/shell_browser_main_parts.cc index 588731c..2a9613b 100644 --- a/ash/shell/content/client/shell_browser_main_parts.cc +++ b/ash/shell/content/client/shell_browser_main_parts.cc
@@ -82,7 +82,7 @@ ShellBrowserMainParts::ShellBrowserMainParts( const content::MainFunctionParams& parameters) - : BrowserMainParts(), delegate_(NULL) {} + : BrowserMainParts(), delegate_(nullptr) {} ShellBrowserMainParts::~ShellBrowserMainParts() {} @@ -136,7 +136,6 @@ window_watcher_.reset(new ash::shell::WindowWatcher); gfx::Screen* screen = Shell::GetInstance()->GetScreen(); screen->AddObserver(window_watcher_.get()); - delegate_->SetWatcher(window_watcher_.get()); ash::shell::InitWindowTypeLauncher(); @@ -148,8 +147,7 @@ screen->RemoveObserver(window_watcher_.get()); window_watcher_.reset(); - delegate_->SetWatcher(NULL); - delegate_ = NULL; + delegate_ = nullptr; ash::Shell::DeleteInstance(); ShellContentState::DestroyInstance(); // The global message center state must be shutdown absent
diff --git a/ash/shell/shelf_delegate_impl.cc b/ash/shell/shelf_delegate_impl.cc index a61a575..b77da8bc 100644 --- a/ash/shell/shelf_delegate_impl.cc +++ b/ash/shell/shelf_delegate_impl.cc
@@ -4,18 +4,12 @@ #include "ash/shell/shelf_delegate_impl.h" -#include "ash/shell.h" -#include "ash/shell/toplevel_window.h" -#include "ash/shell/window_watcher.h" -#include "ash/wm/window_util.h" #include "base/strings/string_util.h" namespace ash { namespace shell { -ShelfDelegateImpl::ShelfDelegateImpl(WindowWatcher* watcher) - : watcher_(watcher) { -} +ShelfDelegateImpl::ShelfDelegateImpl() {} ShelfDelegateImpl::~ShelfDelegateImpl() { }
diff --git a/ash/shell/shelf_delegate_impl.h b/ash/shell/shelf_delegate_impl.h index 85d68ed..b80021ba5 100644 --- a/ash/shell/shelf_delegate_impl.h +++ b/ash/shell/shelf_delegate_impl.h
@@ -9,22 +9,14 @@ #include "base/compiler_specific.h" #include "base/macros.h" -namespace aura { -class Window; -} - namespace ash { namespace shell { -class WindowWatcher; - class ShelfDelegateImpl : public ShelfDelegate { public: - explicit ShelfDelegateImpl(WindowWatcher* watcher); + ShelfDelegateImpl(); ~ShelfDelegateImpl() override; - void set_watcher(WindowWatcher* watcher) { watcher_ = watcher; } - // ShelfDelegate overrides: void OnShelfCreated(Shelf* shelf) override; void OnShelfDestroyed(Shelf* shelf) override; @@ -36,9 +28,6 @@ void UnpinAppWithID(const std::string& app_id) override; private: - // Used to update Launcher. Owned by main. - WindowWatcher* watcher_; - DISALLOW_COPY_AND_ASSIGN(ShelfDelegateImpl); };
diff --git a/ash/shell/shell_delegate_impl.cc b/ash/shell/shell_delegate_impl.cc index 38fbe8e7..b7a1858 100644 --- a/ash/shell/shell_delegate_impl.cc +++ b/ash/shell/shell_delegate_impl.cc
@@ -137,17 +137,9 @@ } // namespace -ShellDelegateImpl::ShellDelegateImpl() - : watcher_(NULL), shelf_delegate_(NULL) {} +ShellDelegateImpl::ShellDelegateImpl() : shelf_delegate_(nullptr) {} -ShellDelegateImpl::~ShellDelegateImpl() { -} - -void ShellDelegateImpl::SetWatcher(WindowWatcher* watcher) { - watcher_ = watcher; - if (shelf_delegate_) - shelf_delegate_->set_watcher(watcher); -} +ShellDelegateImpl::~ShellDelegateImpl() {} bool ShellDelegateImpl::IsFirstRunAfterBoot() const { return false; @@ -205,7 +197,7 @@ } ShelfDelegate* ShellDelegateImpl::CreateShelfDelegate(ShelfModel* model) { - shelf_delegate_ = new ShelfDelegateImpl(watcher_); + shelf_delegate_ = new ShelfDelegateImpl(); return shelf_delegate_; }
diff --git a/ash/shell/shell_delegate_impl.h b/ash/shell/shell_delegate_impl.h index c98e1b2..dbcaa59 100644 --- a/ash/shell/shell_delegate_impl.h +++ b/ash/shell/shell_delegate_impl.h
@@ -19,15 +19,12 @@ namespace shell { class ShelfDelegateImpl; -class WindowWatcher; class ShellDelegateImpl : public ash::ShellDelegate { public: ShellDelegateImpl(); ~ShellDelegateImpl() override; - void SetWatcher(WindowWatcher* watcher); - bool IsFirstRunAfterBoot() const override; bool IsIncognitoAllowed() const override; bool IsMultiProfilesEnabled() const override; @@ -59,9 +56,6 @@ gfx::Image GetDeprecatedAcceleratorImage() const override; private: - // Used to update Launcher. Owned by main. - WindowWatcher* watcher_; - ShelfDelegateImpl* shelf_delegate_; scoped_ptr<app_list::AppListViewDelegate> app_list_view_delegate_;
diff --git a/base/BUILD.gn b/base/BUILD.gn index 6ebec967..caa5fb2 100644 --- a/base/BUILD.gn +++ b/base/BUILD.gn
@@ -109,21 +109,14 @@ # to be linked in where they wouldn't have otherwise. This does not include # test code (test support and anything in the test directory) which should use # source_set as is recommended for GN targets). -if (is_component_build) { - base_target_type = "shared_library" -} else { +component("base") { # TODO(phosek) bug 570839: If field_trial.cc is in a static library, # hacl_helper_nonsfi doesn't link properly on Linux in debug builds. The # reasons for this seem to involve obscure toolchain bugs. This should be # fixed and this target should always be a static_library in the # non-component case. - if (is_nacl_nonsfi) { - base_target_type = "source_set" - } else { - base_target_type = "static_library" - } -} -target(base_target_type, "base") { + component_never_use_source_set = !is_nacl_nonsfi + sources = [ "allocator/allocator_extension.cc", "allocator/allocator_extension.h", @@ -245,6 +238,8 @@ "debug/alias.h", "debug/asan_invalid_access.cc", "debug/asan_invalid_access.h", + "debug/close_handle_hook_win.cc", + "debug/close_handle_hook_win.h", "debug/crash_logging.cc", "debug/crash_logging.h", "debug/debugger.cc",
diff --git a/base/base.gypi b/base/base.gypi index 2148f747..0c70578 100644 --- a/base/base.gypi +++ b/base/base.gypi
@@ -146,6 +146,8 @@ 'debug/alias.h', 'debug/asan_invalid_access.cc', 'debug/asan_invalid_access.h', + 'debug/close_handle_hook_win.cc', + 'debug/close_handle_hook_win.h', 'debug/crash_logging.cc', 'debug/crash_logging.h', 'debug/debugger.cc',
diff --git a/chrome/app/close_handle_hook_win.cc b/base/debug/close_handle_hook_win.cc similarity index 90% rename from chrome/app/close_handle_hook_win.cc rename to base/debug/close_handle_hook_win.cc index 8201999..6ff6fa2 100644 --- a/chrome/app/close_handle_hook_win.cc +++ b/base/debug/close_handle_hook_win.cc
@@ -1,8 +1,8 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. +// 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/app/close_handle_hook_win.h" +#include "base/debug/close_handle_hook_win.h" #include <Windows.h> #include <psapi.h> @@ -18,8 +18,6 @@ #include "base/win/pe_image.h" #include "base/win/scoped_handle.h" #include "build/build_config.h" -#include "chrome/common/channel_info.h" -#include "components/version_info/version_info.h" namespace { @@ -61,6 +59,13 @@ options); } +} // namespace + +namespace base { +namespace debug { + +namespace { + // Provides a simple way to temporarily change the protection of a memory page. class AutoProtectMemory { public: @@ -235,22 +240,6 @@ } } -bool UseHooks() { -#if defined(ARCH_CPU_X86_64) - return false; -#elif defined(NDEBUG) - version_info::Channel channel = chrome::GetChannel(); - if (channel == version_info::Channel::CANARY || - channel == version_info::Channel::DEV) { - return true; - } - - return false; -#else // NDEBUG - return true; -#endif -} - void PatchLoadedModules(HandleHooks* hooks) { const DWORD kSize = 256; DWORD returned; @@ -270,19 +259,18 @@ } // namespace void InstallHandleHooks() { - if (UseHooks()) { - HandleHooks* hooks = g_hooks.Pointer(); + HandleHooks* hooks = g_hooks.Pointer(); - // Performing EAT interception first is safer in the presence of other - // threads attempting to call CloseHandle. - hooks->AddEATPatch(); - PatchLoadedModules(hooks); - } else { - base::win::DisableHandleVerifier(); - } + // Performing EAT interception first is safer in the presence of other + // threads attempting to call CloseHandle. + hooks->AddEATPatch(); + PatchLoadedModules(hooks); } void RemoveHandleHooks() { // We are partching all loaded modules without forcing them to stay in memory, // removing patches is not safe. } + +} // namespace debug +} // namespace base
diff --git a/base/debug/close_handle_hook_win.h b/base/debug/close_handle_hook_win.h new file mode 100644 index 0000000..a042467 --- /dev/null +++ b/base/debug/close_handle_hook_win.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 BASE_DEBUG_CLOSE_HANDLE_HOOK_WIN_H_ +#define BASE_DEBUG_CLOSE_HANDLE_HOOK_WIN_H_ + +#include "base/base_export.h" + +namespace base { +namespace debug { + +// Installs the hooks required to debug use of improper handles. +BASE_EXPORT void InstallHandleHooks(); + +// Removes the hooks installed by InstallHandleHooks(). +BASE_EXPORT void RemoveHandleHooks(); + +} // namespace debug +} // namespace base + +#endif // BASE_DEBUG_CLOSE_HANDLE_HOOK_WIN_H_
diff --git a/base/mac/scoped_nsobject_unittest.mm b/base/mac/scoped_nsobject_unittest.mm index c838217..8b0b97d 100644 --- a/base/mac/scoped_nsobject_unittest.mm +++ b/base/mac/scoped_nsobject_unittest.mm
@@ -52,6 +52,8 @@ ASSERT_EQ(2u, [p1 retainCount]); } +// Instantiating scoped_nsobject<> with T=NSAutoreleasePool should trip a +// static_assert. #if 0 TEST(ScopedNSObjectTest, FailToCreateScopedNSObjectAutoreleasePool) { base::scoped_nsobject<NSAutoreleasePool> pool;
diff --git a/base/memory/ref_counted.h b/base/memory/ref_counted.h index e569c080..a1c1269 100644 --- a/base/memory/ref_counted.h +++ b/base/memory/ref_counted.h
@@ -118,7 +118,7 @@ // ~MyFoo(); // }; // -// You should always make your destructor private, to avoid any code deleting +// You should always make your destructor non-public, to avoid any code deleting // the object accidently while there are references to it. template <class T> class RefCounted : public subtle::RefCountedBase {
diff --git a/base/memory/scoped_ptr_unittest.cc b/base/memory/scoped_ptr_unittest.cc index f091596..4f0e7842 100644 --- a/base/memory/scoped_ptr_unittest.cc +++ b/base/memory/scoped_ptr_unittest.cc
@@ -402,7 +402,7 @@ EXPECT_TRUE(scoper3.get()); } -#if !(defined(OS_ANDROID) || (defined(OS_LINUX) && !defined(OS_CHROMEOS))) +#if !defined(OS_ANDROID) && !defined(OS_LINUX) // Test uncaught Pass() does not have side effects, because Pass() // is implemented by std::move(). // TODO(danakj): Remove this test case when we remove Pass().
diff --git a/base/metrics/field_trial.cc b/base/metrics/field_trial.cc index 370ded9..b417b056 100644 --- a/base/metrics/field_trial.cc +++ b/base/metrics/field_trial.cc
@@ -17,6 +17,15 @@ namespace { +// Define a separator character to use when creating a persistent form of an +// instance. This is intended for use as a command line argument, passed to a +// second process to mimic our state (i.e., provide the same group name). +const char kPersistentStringSeparator = '/'; // Currently a slash. + +// Define a marker character to be used as a prefix to a trial name on the +// command line which forces its activation. +const char kActivationMarker = '*'; + // Created a time value based on |year|, |month| and |day_of_month| parameters. Time CreateTimeFromParams(int year, int month, int day_of_month) { DCHECK_GT(year, 1970); @@ -57,6 +66,45 @@ return std::min(result, divisor - 1); } +// Parses the --force-fieldtrials string |trials_string| into |entries|. +// Returns true if the string was parsed correctly. On failure, the |entries| +// array may end up being partially filled. +bool ParseFieldTrialsString(const std::string& trials_string, + std::vector<FieldTrial::State>* entries) { + const StringPiece trials_string_piece(trials_string); + + size_t next_item = 0; + while (next_item < trials_string.length()) { + size_t name_end = trials_string.find(kPersistentStringSeparator, next_item); + if (name_end == trials_string.npos || next_item == name_end) + return false; + size_t group_name_end = + trials_string.find(kPersistentStringSeparator, name_end + 1); + if (name_end + 1 == group_name_end) + return false; + if (group_name_end == trials_string.npos) + group_name_end = trials_string.length(); + + FieldTrial::State entry; + // Verify if the trial should be activated or not. + if (trials_string[next_item] == kActivationMarker) { + // Name cannot be only the indicator. + if (name_end - next_item == 1) + return false; + next_item++; + entry.activated = true; + } + entry.trial_name = + trials_string_piece.substr(next_item, name_end - next_item); + entry.group_name = + trials_string_piece.substr(name_end + 1, group_name_end - name_end - 1); + next_item = group_name_end + 1; + + entries->push_back(entry); + } + return true; +} + } // namespace // statics @@ -64,8 +112,6 @@ const int FieldTrial::kDefaultGroupNumber = 0; bool FieldTrial::enable_benchmarking_ = false; -const char FieldTrialList::kPersistentStringSeparator('/'); -const char FieldTrialList::kActivationMarker('*'); int FieldTrialList::kNoExpirationYear = 0; //------------------------------------------------------------------------------ @@ -74,6 +120,10 @@ FieldTrial::EntropyProvider::~EntropyProvider() { } +FieldTrial::State::State() : activated(false) {} + +FieldTrial::State::~State() {} + void FieldTrial::Disable() { DCHECK(!group_reported_); enable_field_trial_ = false; @@ -226,7 +276,7 @@ return true; } -bool FieldTrial::GetState(FieldTrialState* field_trial_state) { +bool FieldTrial::GetState(State* field_trial_state) { if (!enable_field_trial_) return false; FinalizeGroupChoice(); @@ -412,7 +462,7 @@ AutoLock auto_lock(global_->lock_); for (const auto& registered : global_->registered_) { - FieldTrial::FieldTrialState trial; + FieldTrial::State trial; if (!registered.second->GetState(&trial)) continue; DCHECK_EQ(std::string::npos, @@ -421,9 +471,9 @@ trial.group_name.find(kPersistentStringSeparator)); if (trial.activated) output->append(1, kActivationMarker); - output->append(trial.trial_name); + trial.trial_name.AppendToString(output); output->append(1, kPersistentStringSeparator); - output->append(trial.group_name); + trial.group_name.AppendToString(output); output->append(1, kPersistentStringSeparator); } } @@ -445,6 +495,24 @@ } // static +void FieldTrialList::GetActiveFieldTrialGroupsFromString( + const std::string& trials_string, + FieldTrial::ActiveGroups* active_groups) { + std::vector<FieldTrial::State> entries; + if (!ParseFieldTrialsString(trials_string, &entries)) + return; + + for (const auto& entry : entries) { + if (entry.activated) { + FieldTrial::ActiveGroup group; + group.trial_name = entry.trial_name.as_string(); + group.group_name = entry.group_name.as_string(); + active_groups->push_back(group); + } + } +} + +// static bool FieldTrialList::CreateTrialsFromString( const std::string& trials_string, FieldTrialActivationMode mode, @@ -453,40 +521,21 @@ if (trials_string.empty() || !global_) return true; - size_t next_item = 0; - while (next_item < trials_string.length()) { - size_t name_end = trials_string.find(kPersistentStringSeparator, next_item); - if (name_end == trials_string.npos || next_item == name_end) - return false; - size_t group_name_end = trials_string.find(kPersistentStringSeparator, - name_end + 1); - if (name_end + 1 == group_name_end) - return false; - if (group_name_end == trials_string.npos) - group_name_end = trials_string.length(); + std::vector<FieldTrial::State> entries; + if (!ParseFieldTrialsString(trials_string, &entries)) + return false; - // Verify if the trial should be activated or not. - std::string name; - bool force_activation = false; - if (trials_string[next_item] == kActivationMarker) { - // Name cannot be only the indicator. - if (name_end - next_item == 1) - return false; - next_item++; - force_activation = true; - } - name.append(trials_string, next_item, name_end - next_item); - std::string group_name(trials_string, name_end + 1, - group_name_end - name_end - 1); - next_item = group_name_end + 1; + for (const auto& entry : entries) { + const std::string trial_name = entry.trial_name.as_string(); + const std::string group_name = entry.group_name.as_string(); - if (ignored_trial_names.find(name) != ignored_trial_names.end()) + if (ContainsKey(ignored_trial_names, trial_name)) continue; - FieldTrial* trial = CreateFieldTrial(name, group_name); + FieldTrial* trial = CreateFieldTrial(trial_name, group_name); if (!trial) return false; - if (mode == ACTIVATE_TRIALS || force_activation) { + if (mode == ACTIVATE_TRIALS || entry.activated) { // Call |group()| to mark the trial as "used" and notify observers, if // any. This is useful to ensure that field trials created in child // processes are properly reported in crash reports.
diff --git a/base/metrics/field_trial.h b/base/metrics/field_trial.h index 6c1d93ed..7bfc1dee 100644 --- a/base/metrics/field_trial.h +++ b/base/metrics/field_trial.h
@@ -67,6 +67,7 @@ #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/observer_list_threadsafe.h" +#include "base/strings/string_piece.h" #include "base/synchronization/lock.h" #include "base/time/time.h" @@ -112,10 +113,13 @@ // A triplet representing a FieldTrial, its selected group and whether it's // active. - struct FieldTrialState { - std::string trial_name; - std::string group_name; + struct BASE_EXPORT State { + StringPiece trial_name; + StringPiece group_name; bool activated; + + State(); + ~State(); }; typedef std::vector<ActiveGroup> ActiveGroups; @@ -254,7 +258,7 @@ // been disabled. In that case, true is returned and |field_trial_state| is // filled in; otherwise, the result is false and |field_trial_state| is left // untouched. - bool GetState(FieldTrialState* field_trial_state); + bool GetState(State* field_trial_state); // Returns the group_name. A winner need not have been chosen. std::string group_name_internal() const { return group_name_; } @@ -324,15 +328,6 @@ ACTIVATE_TRIALS, }; - // Define a separator character to use when creating a persistent form of an - // instance. This is intended for use as a command line argument, passed to a - // second process to mimic our state (i.e., provide the same group name). - static const char kPersistentStringSeparator; // Currently a slash. - - // Define a marker character to be used as a prefix to a trial name on the - // command line which forces its activation. - static const char kActivationMarker; // Currently an asterisk. - // Year that is guaranteed to not be expired when instantiating a field trial // via |FactoryGetFieldTrial()|. Set to two years from the build date. static int kNoExpirationYear; @@ -452,6 +447,11 @@ static void GetActiveFieldTrialGroups( FieldTrial::ActiveGroups* active_groups); + // Returns the field trials that are marked active in |trials_string|. + static void GetActiveFieldTrialGroupsFromString( + const std::string& trials_string, + FieldTrial::ActiveGroups* active_groups); + // Use a state string (re: StatesToString()) to augment the current list of // field trials to include the supplied trials, and using a 100% probability // for each trial, force them to have the same group string. This is commonly @@ -461,9 +461,9 @@ // trials are all marked as "used" for the purposes of active trial reporting // if |mode| is ACTIVATE_TRIALS, otherwise each trial will be marked as "used" // if it is prefixed with |kActivationMarker|. Trial names in - // |ignored_trial_names| are ignored when parsing |prior_trials|. + // |ignored_trial_names| are ignored when parsing |trials_string|. static bool CreateTrialsFromString( - const std::string& prior_trials, + const std::string& trials_string, FieldTrialActivationMode mode, const std::set<std::string>& ignored_trial_names);
diff --git a/base/metrics/field_trial_unittest.cc b/base/metrics/field_trial_unittest.cc index ffb3eb2f..555d7fa 100644 --- a/base/metrics/field_trial_unittest.cc +++ b/base/metrics/field_trial_unittest.cc
@@ -316,8 +316,19 @@ } } +TEST_F(FieldTrialTest, GetActiveFieldTrialGroupsFromString) { + FieldTrial::ActiveGroups active_groups; + FieldTrialList::GetActiveFieldTrialGroupsFromString("*A/X/B/Y/*C/Z", + &active_groups); + ASSERT_EQ(2U, active_groups.size()); + EXPECT_EQ("A", active_groups[0].trial_name); + EXPECT_EQ("X", active_groups[0].group_name); + EXPECT_EQ("C", active_groups[1].trial_name); + EXPECT_EQ("Z", active_groups[1].group_name); +} + TEST_F(FieldTrialTest, AllGroups) { - FieldTrial::FieldTrialState field_trial_state; + FieldTrial::State field_trial_state; std::string one_winner("One Winner"); scoped_refptr<FieldTrial> trial = CreateFieldTrial(one_winner, 10, "Default", NULL);
diff --git a/base/move.h b/base/move.h index 66d85212..24bf9d75 100644 --- a/base/move.h +++ b/base/move.h
@@ -31,7 +31,7 @@ // for more details. // TODO(crbug.com/566182): Remove this macro and use DISALLOW_COPY_AND_ASSIGN // everywhere instead. -#if defined(OS_ANDROID) || (defined(OS_LINUX) && !defined(OS_CHROMEOS)) +#if defined(OS_ANDROID) || defined(OS_LINUX) #define DISALLOW_COPY_AND_ASSIGN_WITH_MOVE_FOR_BIND(type) \ private: \ type(const type&) = delete; \
diff --git a/base/numerics/safe_math.h b/base/numerics/safe_math.h index e824ba6..d169690 100644 --- a/base/numerics/safe_math.h +++ b/base/numerics/safe_math.h
@@ -38,9 +38,8 @@ // CheckedNumeric<int> checked_int = untrusted_input_value; // int x = checked_int.ValueOrDefault(0) | kFlagValues; // Comparison: -// CheckedNumeric<size_t> checked_size; -// CheckedNumeric<int> checked_size = untrusted_input_value; -// checked_size = checked_size + HEADER LENGTH; +// CheckedNumeric<size_t> checked_size = untrusted_input_value; +// checked_size += HEADER LENGTH; // if (checked_size.IsValid() && checked_size.ValueOrDie() < buffer_size) // Do stuff... template <typename T>
diff --git a/base/process/launch_win.cc b/base/process/launch_win.cc index 612b77e..1ffb979 100644 --- a/base/process/launch_win.cc +++ b/base/process/launch_win.cc
@@ -272,8 +272,10 @@ // If this code is run under a debugger, the launched process is // automatically associated with a job object created by the debugger. - // The CREATE_BREAKAWAY_FROM_JOB flag is used to prevent this. - flags |= CREATE_BREAKAWAY_FROM_JOB; + // The CREATE_BREAKAWAY_FROM_JOB flag is used to prevent this on Windows + // releases that do not support nested jobs. + if (win::GetVersion() < win::VERSION_WIN8) + flags |= CREATE_BREAKAWAY_FROM_JOB; } if (options.force_breakaway_from_job_)
diff --git a/base/strings/string_split.cc b/base/strings/string_split.cc index 093680d8..6c949b98 100644 --- a/base/strings/string_split.cc +++ b/base/strings/string_split.cc
@@ -130,28 +130,28 @@ return true; } -template <typename Str> +template <typename Str, typename OutputStringType> void SplitStringUsingSubstrT(BasicStringPiece<Str> input, BasicStringPiece<Str> delimiter, - std::vector<Str>* result) { + WhitespaceHandling whitespace, + SplitResult result_type, + std::vector<OutputStringType>* result) { using Piece = BasicStringPiece<Str>; using size_type = typename Piece::size_type; result->clear(); - size_type begin_index = 0; - while (true) { - size_type end_index = input.find(delimiter, begin_index); - if (end_index == Piece::npos) { - // No delimiter, use the rest of the string. - Piece term = TrimString(input.substr(begin_index), - WhitespaceForType<Str>(), TRIM_ALL); - result->push_back(term.as_string()); - return; - } - Piece term = TrimString(input.substr(begin_index, end_index - begin_index), - WhitespaceForType<Str>(), TRIM_ALL); - result->push_back(term.as_string()); - begin_index = end_index + delimiter.size(); + for (size_type begin_index = 0, end_index = 0; end_index != Piece::npos; + begin_index = end_index + delimiter.size()) { + end_index = input.find(delimiter, begin_index); + Piece term = end_index == Piece::npos + ? input.substr(begin_index) + : input.substr(begin_index, end_index - begin_index); + + if (whitespace == TRIM_WHITESPACE) + term = TrimString(term, WhitespaceForType<Str>(), TRIM_ALL); + + if (result_type == SPLIT_WANT_ALL || !term.empty()) + result->push_back(PieceToOutputType<Str, OutputStringType>(term)); } } @@ -230,13 +230,35 @@ void SplitStringUsingSubstr(StringPiece16 input, StringPiece16 delimiter, std::vector<string16>* result) { - SplitStringUsingSubstrT(input, delimiter, result); + SplitStringUsingSubstrT(input, delimiter, TRIM_WHITESPACE, SPLIT_WANT_ALL, + result); } void SplitStringUsingSubstr(StringPiece input, StringPiece delimiter, std::vector<std::string>* result) { - SplitStringUsingSubstrT(input, delimiter, result); + SplitStringUsingSubstrT(input, delimiter, TRIM_WHITESPACE, SPLIT_WANT_ALL, + result); +} + +std::vector<StringPiece16> SplitStringPieceUsingSubstr( + StringPiece16 input, + StringPiece16 delimiter, + WhitespaceHandling whitespace, + SplitResult result_type) { + std::vector<StringPiece16> result; + SplitStringUsingSubstrT(input, delimiter, whitespace, result_type, &result); + return result; +} + +std::vector<StringPiece> SplitStringPieceUsingSubstr( + StringPiece input, + StringPiece delimiter, + WhitespaceHandling whitespace, + SplitResult result_type) { + std::vector<StringPiece> result; + SplitStringUsingSubstrT(input, delimiter, whitespace, result_type, &result); + return result; } } // namespace base
diff --git a/base/strings/string_split.h b/base/strings/string_split.h index 2a0c795..ec9f2460 100644 --- a/base/strings/string_split.h +++ b/base/strings/string_split.h
@@ -101,6 +101,29 @@ StringPiece delimiter, std::vector<std::string>* result); +// Like SplitStringUsingSubstr above except it returns a vector of StringPieces +// which reference the original buffer without copying. Although you have to be +// careful to keep the original string unmodified, this provides an efficient +// way to iterate through tokens in a string. +// +// To iterate through all newline-separated tokens in an input string: +// +// for (const auto& cur : +// base::SplitStringUsingSubstr(input, "\r\n", +// base::KEEP_WHITESPACE, +// base::SPLIT_WANT_NONEMPTY)) { +// ... +BASE_EXPORT std::vector<StringPiece16> SplitStringPieceUsingSubstr( + StringPiece16 input, + StringPiece16 delimiter, + WhitespaceHandling whitespace, + SplitResult result_type); +BASE_EXPORT std::vector<StringPiece> SplitStringPieceUsingSubstr( + StringPiece input, + StringPiece delimiter, + WhitespaceHandling whitespace, + SplitResult result_type); + } // namespace base #endif // BASE_STRINGS_STRING_SPLIT_H_
diff --git a/base/strings/string_split_unittest.cc b/base/strings/string_split_unittest.cc index 0e9ca9f..657a2db 100644 --- a/base/strings/string_split_unittest.cc +++ b/base/strings/string_split_unittest.cc
@@ -268,6 +268,71 @@ results, ElementsAre("un", "deux", "trois", "quatre", "", "", "")); } +TEST(SplitStringPieceUsingSubstrTest, StringWithNoDelimiter) { + std::vector<base::StringPiece> results = + SplitStringPieceUsingSubstr("alongwordwithnodelimiter", "DELIMITER", + base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); + ASSERT_EQ(1u, results.size()); + EXPECT_THAT(results, ElementsAre("alongwordwithnodelimiter")); +} + +TEST(SplitStringPieceUsingSubstrTest, LeadingDelimitersSkipped) { + std::vector<base::StringPiece> results = SplitStringPieceUsingSubstr( + "DELIMITERDELIMITERDELIMITERoneDELIMITERtwoDELIMITERthree", "DELIMITER", + base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); + ASSERT_EQ(6u, results.size()); + EXPECT_THAT(results, ElementsAre("", "", "", "one", "two", "three")); +} + +TEST(SplitStringPieceUsingSubstrTest, ConsecutiveDelimitersSkipped) { + std::vector<base::StringPiece> results = SplitStringPieceUsingSubstr( + "unoDELIMITERDELIMITERDELIMITERdosDELIMITERtresDELIMITERDELIMITERcuatro", + "DELIMITER", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); + ASSERT_EQ(7u, results.size()); + EXPECT_THAT(results, ElementsAre("uno", "", "", "dos", "tres", "", "cuatro")); +} + +TEST(SplitStringPieceUsingSubstrTest, TrailingDelimitersSkipped) { + std::vector<base::StringPiece> results = SplitStringPieceUsingSubstr( + "unDELIMITERdeuxDELIMITERtroisDELIMITERquatreDELIMITERDELIMITERDELIMITER", + "DELIMITER", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); + ASSERT_EQ(7u, results.size()); + EXPECT_THAT(results, + ElementsAre("un", "deux", "trois", "quatre", "", "", "")); +} + +TEST(SplitStringPieceUsingSubstrTest, KeepWhitespace) { + std::vector<base::StringPiece> results = SplitStringPieceUsingSubstr( + "un DELIMITERdeux\tDELIMITERtrois\nDELIMITERquatre", "DELIMITER", + base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL); + ASSERT_EQ(4u, results.size()); + EXPECT_THAT(results, ElementsAre("un ", "deux\t", "trois\n", "quatre")); +} + +TEST(SplitStringPieceUsingSubstrTest, TrimWhitespace) { + std::vector<base::StringPiece> results = SplitStringPieceUsingSubstr( + "un DELIMITERdeux\tDELIMITERtrois\nDELIMITERquatre", "DELIMITER", + base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); + ASSERT_EQ(4u, results.size()); + EXPECT_THAT(results, ElementsAre("un", "deux", "trois", "quatre")); +} + +TEST(SplitStringPieceUsingSubstrTest, SplitWantAll) { + std::vector<base::StringPiece> results = SplitStringPieceUsingSubstr( + "unDELIMITERdeuxDELIMITERtroisDELIMITERDELIMITER", "DELIMITER", + base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); + ASSERT_EQ(5u, results.size()); + EXPECT_THAT(results, ElementsAre("un", "deux", "trois", "", "")); +} + +TEST(SplitStringPieceUsingSubstrTest, SplitWantNonEmpty) { + std::vector<base::StringPiece> results = SplitStringPieceUsingSubstr( + "unDELIMITERdeuxDELIMITERtroisDELIMITERDELIMITER", "DELIMITER", + base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); + ASSERT_EQ(3u, results.size()); + EXPECT_THAT(results, ElementsAre("un", "deux", "trois")); +} + TEST(StringSplitTest, StringSplitKeepWhitespace) { std::vector<std::string> r;
diff --git a/base/trace_event/memory_dump_manager.cc b/base/trace_event/memory_dump_manager.cc index f5c3c4f..aa81e00 100644 --- a/base/trace_event/memory_dump_manager.cc +++ b/base/trace_event/memory_dump_manager.cc
@@ -199,7 +199,7 @@ { AutoLock lock(lock_); bool already_registered = !dump_providers_.insert(mdpinfo).second; - // This actually happen in some tests which don't have a clean tear-down + // This actually happens in some tests which don't have a clean tear-down // path for RenderThreadImpl::Init(). if (already_registered) return; @@ -217,6 +217,21 @@ } void MemoryDumpManager::UnregisterDumpProvider(MemoryDumpProvider* mdp) { + UnregisterDumpProviderInternal(mdp, false /* delete_async */); +} + +void MemoryDumpManager::UnregisterAndDeleteDumpProviderSoon( + scoped_ptr<MemoryDumpProvider> mdp) { + UnregisterDumpProviderInternal(mdp.release(), true /* delete_async */); +} + +void MemoryDumpManager::UnregisterDumpProviderInternal( + MemoryDumpProvider* mdp, + bool take_mdp_ownership_and_delete_async) { + scoped_ptr<MemoryDumpProvider> owned_mdp; + if (take_mdp_ownership_and_delete_async) + owned_mdp.reset(mdp); + AutoLock lock(lock_); auto mdp_iter = dump_providers_.begin(); @@ -226,19 +241,29 @@ } if (mdp_iter == dump_providers_.end()) - return; + return; // Not registered / already unregistered. - // Unregistration of a MemoryDumpProvider while tracing is ongoing is safe - // only if the MDP has specified a thread affinity (via task_runner()) AND - // the unregistration happens on the same thread (so the MDP cannot unregister - // and OnMemoryDump() at the same time). - // Otherwise, it is not possible to guarantee that its unregistration is - // race-free. If you hit this DCHECK, your MDP has a bug. - DCHECK(!subtle::NoBarrier_Load(&memory_tracing_enabled_) || - ((*mdp_iter)->task_runner && - (*mdp_iter)->task_runner->BelongsToCurrentThread())) - << "MemoryDumpProvider \"" << (*mdp_iter)->name << "\" attempted to " - << "unregister itself in a racy way. Please file a crbug."; + if (take_mdp_ownership_and_delete_async) { + // The MDP will be deleted whenever the MDPInfo struct will, that is either: + // - At the end of this function, if no dump is in progress. + // - In the prologue of the ContinueAsyncProcessDump(). + DCHECK(!(*mdp_iter)->owned_dump_provider); + (*mdp_iter)->owned_dump_provider = std::move(owned_mdp); + } else if (subtle::NoBarrier_Load(&memory_tracing_enabled_)) { + // If you hit this DCHECK, your dump provider has a bug. + // Unregistration of a MemoryDumpProvider is safe only if: + // - The MDP has specified a thread affinity (via task_runner()) AND + // the unregistration happens on the same thread (so the MDP cannot + // unregister and be in the middle of a OnMemoryDump() at the same time. + // - The MDP has NOT specified a thread affinity and its ownership is + // transferred via UnregisterAndDeleteDumpProviderSoon(). + // In all the other cases, it is not possible to guarantee that the + // unregistration will not race with OnMemoryDump() calls. + DCHECK((*mdp_iter)->task_runner && + (*mdp_iter)->task_runner->BelongsToCurrentThread()) + << "MemoryDumpProvider \"" << (*mdp_iter)->name << "\" attempted to " + << "unregister itself in a racy way. Please file a crbug."; + } // The MDPInfo instance can still be referenced by the // |ProcessMemoryDumpAsyncState.pending_dump_providers|. For this reason @@ -365,24 +390,49 @@ if (!task_runner) task_runner = pmd_async_state->dump_thread_task_runner.get(); + bool post_task_failed = false; if (!task_runner->BelongsToCurrentThread()) { // It's time to hop onto another thread. - const bool did_post_task = task_runner->PostTask( + post_task_failed = !task_runner->PostTask( FROM_HERE, Bind(&MemoryDumpManager::ContinueAsyncProcessDump, Unretained(this), Unretained(pmd_async_state.get()))); - if (did_post_task) { + if (!post_task_failed) { // Ownership is tranferred to the next ContinueAsyncProcessDump(). ignore_result(pmd_async_state.release()); return; } - // The thread is gone. Skip the dump provider and keep going. - mdpinfo->disabled = true; } - // At this point wither we are on the right thread (|mdpinfo.task_runner|) - // to access mdp fields, or the right thread is gone (and |disabled| == true). + // At this point either: + // - The MDP has a task runner affinity and we are on the right thread. + // - The MDP has a task runner affinity but the underlying thread is gone, + // hence the above |post_task_failed| == true. + // - The MDP does NOT have a task runner affinity. A locked access is required + // to R/W |disabled| (for the UnregisterAndDeleteDumpProviderSoon() case). + bool should_dump; + const char* disabled_reason = nullptr; + { + AutoLock lock(lock_); + if (!mdpinfo->disabled) { + if (mdpinfo->consecutive_failures >= kMaxConsecutiveFailuresCount) { + mdpinfo->disabled = true; + disabled_reason = + "Dump failure, possibly related with sandboxing (crbug.com/461788)." + " Try --no-sandbox."; + } else if (post_task_failed) { + disabled_reason = "The thread it was meant to dump onto is gone."; + mdpinfo->disabled = true; + } + } + should_dump = !mdpinfo->disabled; + } - if (!mdpinfo->disabled) { + if (disabled_reason) { + LOG(ERROR) << "Disabling MemoryDumpProvider \"" << mdpinfo->name << "\". " + << disabled_reason; + } + + if (should_dump) { // Invoke the dump provider. TRACE_EVENT_WITH_FLOW1(kTraceCategory, "MemoryDumpManager::ContinueAsyncProcessDump", @@ -398,18 +448,8 @@ pmd_async_state->GetOrCreateMemoryDumpContainerForProcess(target_pid); MemoryDumpArgs args = {pmd_async_state->req_args.level_of_detail}; bool dump_successful = mdpinfo->dump_provider->OnMemoryDump(args, pmd); - - if (dump_successful) { - mdpinfo->consecutive_failures = 0; - } else { - ++mdpinfo->consecutive_failures; - if (mdpinfo->consecutive_failures >= kMaxConsecutiveFailuresCount) { - mdpinfo->disabled = true; - LOG(ERROR) << "MemoryDumpProvider \"" << mdpinfo->name << "\" failed, " - << "possibly due to sandboxing (crbug.com/461788)." - << "Disabling dumper for current process. Try --no-sandbox."; - } - } + mdpinfo->consecutive_failures = + dump_successful ? 0 : mdpinfo->consecutive_failures + 1; } // if (!mdpinfo->disabled) pmd_async_state->pending_dump_providers.pop_back();
diff --git a/base/trace_event/memory_dump_manager.h b/base/trace_event/memory_dump_manager.h index f977463..b3880af 100644 --- a/base/trace_event/memory_dump_manager.h +++ b/base/trace_event/memory_dump_manager.h
@@ -84,6 +84,15 @@ const MemoryDumpProvider::Options& options); void UnregisterDumpProvider(MemoryDumpProvider* mdp); + // Unregisters an unbound dump provider and takes care about its deletion + // asynchronously. Can be used only for for dump providers with no + // task-runner affinity. + // This method takes ownership of the dump provider and guarantees that: + // - The |mdp| will be deleted at some point in the near future. + // - Its deletion will not happen concurrently with the OnMemoryDump() call. + // Note that OnMemoryDump() calls can still happen after this method returns. + void UnregisterAndDeleteDumpProviderSoon(scoped_ptr<MemoryDumpProvider> mdp); + // Requests a memory dump. The dump might happen or not depending on the // filters and categories specified when enabling tracing. // The optional |callback| is executed asynchronously, on an arbitrary thread, @@ -142,8 +151,7 @@ // the ProcessMemoryDumpAsyncState. This is to allow removal (see below). // - When the MDP.OnMemoryDump() is invoked, the corresponding MDPInfo copy // inside ProcessMemoryDumpAsyncState is removed. - // - In nominal conditions, the MDPInfo is destroyed in the - // UnregisterDumpProvider() call. + // - In most cases, the MDPInfo is destroyed within UnregisterDumpProvider(). // - If UnregisterDumpProvider() is called while a dump is in progress, the // MDPInfo is destroyed in the epilogue of ContinueAsyncProcessDump(), when // the copy inside ProcessMemoryDumpAsyncState is erase()-d. @@ -168,6 +176,10 @@ MemoryDumpProvider* const dump_provider; + // Used to transfer ownership for UnregisterAndDeleteDumpProviderSoon(). + // nullptr in all other cases. + scoped_ptr<MemoryDumpProvider> owned_dump_provider; + // Human readable name, for debugging and testing. Not necessarily unique. const char* const name; @@ -264,6 +276,10 @@ void ContinueAsyncProcessDump( ProcessMemoryDumpAsyncState* owned_pmd_async_state); + // Helper for the public UnregisterDumpProvider* functions. + void UnregisterDumpProviderInternal(MemoryDumpProvider* mdp, + bool take_mdp_ownership_and_delete_async); + // An ordererd set of registered MemoryDumpProviderInfo(s), sorted by thread // affinity (MDPs belonging to the same thread are adjacent). MemoryDumpProviderInfo::OrderedSet dump_providers_;
diff --git a/base/trace_event/memory_dump_manager_unittest.cc b/base/trace_event/memory_dump_manager_unittest.cc index 898f003..03b3afa 100644 --- a/base/trace_event/memory_dump_manager_unittest.cc +++ b/base/trace_event/memory_dump_manager_unittest.cc
@@ -17,6 +17,7 @@ #include "base/test/test_io_thread.h" #include "base/test/trace_event_analyzer.h" #include "base/thread_task_runner_handle.h" +#include "base/threading/platform_thread.h" #include "base/threading/thread.h" #include "base/trace_event/memory_dump_provider.h" #include "base/trace_event/process_memory_dump.h" @@ -93,8 +94,17 @@ class MockMemoryDumpProvider : public MemoryDumpProvider { public: + MOCK_METHOD0(Destructor, void()); MOCK_METHOD2(OnMemoryDump, bool(const MemoryDumpArgs& args, ProcessMemoryDump* pmd)); + + MockMemoryDumpProvider() : enable_mock_destructor(false) {} + ~MockMemoryDumpProvider() override { + if (enable_mock_destructor) + Destructor(); + } + + bool enable_mock_destructor; }; class MemoryDumpManagerTest : public testing::Test { @@ -785,7 +795,7 @@ // Register also an unbound dump provider. Unbound dump providers are always // invoked after bound ones. MockMemoryDumpProvider unbound_mdp; - RegisterDumpProvider(&unbound_mdp); + RegisterDumpProvider(&unbound_mdp, nullptr, kDefaultOptions); EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory); EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1); @@ -877,5 +887,72 @@ ASSERT_EQ(events[0]->id, events[2]->id); } +// Tests the basics of the UnregisterAndDeleteDumpProviderSoon(): the +// unregistration should actually delete the providers and not leak them. +TEST_F(MemoryDumpManagerTest, UnregisterAndDeleteDumpProviderSoon) { + InitializeMemoryDumpManager(false /* is_coordinator */); + static const int kNumProviders = 3; + int dtor_count = 0; + std::vector<scoped_ptr<MemoryDumpProvider>> mdps; + for (int i = 0; i < kNumProviders; ++i) { + scoped_ptr<MockMemoryDumpProvider> mdp(new MockMemoryDumpProvider); + mdp->enable_mock_destructor = true; + EXPECT_CALL(*mdp, Destructor()) + .WillOnce(Invoke([&dtor_count]() { dtor_count++; })); + RegisterDumpProvider(mdp.get(), nullptr, kDefaultOptions); + mdps.push_back(std::move(mdp)); + } + + while (!mdps.empty()) { + mdm_->UnregisterAndDeleteDumpProviderSoon(std::move(mdps.back())); + mdps.pop_back(); + } + + ASSERT_EQ(kNumProviders, dtor_count); +} + +// This test checks against races when unregistering an unbound dump provider +// from another thread while dumping. It registers one MDP and, when +// OnMemoryDump() is called, it invokes UnregisterAndDeleteDumpProviderSoon() +// from another thread. The OnMemoryDump() and the dtor call are expected to +// happen on the same thread (the MemoryDumpManager utility thread). +TEST_F(MemoryDumpManagerTest, UnregisterAndDeleteDumpProviderSoonDuringDump) { + InitializeMemoryDumpManager(false /* is_coordinator */); + scoped_ptr<MockMemoryDumpProvider> mdp(new MockMemoryDumpProvider); + mdp->enable_mock_destructor = true; + RegisterDumpProvider(mdp.get(), nullptr, kDefaultOptions); + + base::PlatformThreadRef thread_ref; + auto self_unregister_from_another_thread = [&mdp, &thread_ref]( + const MemoryDumpArgs&, ProcessMemoryDump*) -> bool { + thread_ref = PlatformThread::CurrentRef(); + TestIOThread thread_for_unregistration(TestIOThread::kAutoStart); + thread_for_unregistration.PostTaskAndWait( + FROM_HERE, + base::Bind( + &MemoryDumpManager::UnregisterAndDeleteDumpProviderSoon, + base::Unretained(MemoryDumpManager::GetInstance()), + base::Passed(scoped_ptr<MemoryDumpProvider>(std::move(mdp))))); + thread_for_unregistration.Stop(); + return true; + }; + EXPECT_CALL(*mdp, OnMemoryDump(_, _)) + .Times(1) + .WillOnce(Invoke(self_unregister_from_another_thread)); + EXPECT_CALL(*mdp, Destructor()) + .Times(1) + .WillOnce(Invoke([&thread_ref]() { + EXPECT_EQ(thread_ref, PlatformThread::CurrentRef()); + })); + + EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory); + EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(2); + for (int i = 0; i < 2; ++i) { + RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED, + MemoryDumpLevelOfDetail::DETAILED); + } + DisableTracing(); +} + } // namespace trace_event } // namespace base
diff --git a/base/trace_event/memory_dump_provider.h b/base/trace_event/memory_dump_provider.h index 48eaaaeb..f03fcbd 100644 --- a/base/trace_event/memory_dump_provider.h +++ b/base/trace_event/memory_dump_provider.h
@@ -36,6 +36,8 @@ ProcessId target_pid; }; + virtual ~MemoryDumpProvider() {} + // Called by the MemoryDumpManager when generating memory dumps. // The |args| specify if the embedder should generate light/heavy dumps on // dump requests. The embedder should return true if the |pmd| was @@ -52,7 +54,6 @@ protected: MemoryDumpProvider() {} - virtual ~MemoryDumpProvider() {} DISALLOW_COPY_AND_ASSIGN(MemoryDumpProvider); };
diff --git a/base/win/scoped_handle.cc b/base/win/scoped_handle.cc index 39b5933..9c21603 100644 --- a/base/win/scoped_handle.cc +++ b/base/win/scoped_handle.cc
@@ -194,6 +194,9 @@ } void ActiveVerifier::OnHandleBeingClosed(HANDLE handle) { + if (!enabled_) + return; + AutoNativeLock lock(*lock_); if (closing_) return;
diff --git a/blimp/BUILD.gn b/blimp/BUILD.gn index 6712095..519c980 100644 --- a/blimp/BUILD.gn +++ b/blimp/BUILD.gn
@@ -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/config/ui.gni") import("//testing/test.gni") # Convenience meta-target for all of Blimp's production & test code. @@ -28,7 +29,7 @@ ] } - if (is_linux && !is_chromeos) { + if (is_linux && !is_chromeos && use_x11) { deps += [ "//blimp/client:blimp_shell" ] } }
diff --git a/blimp/client/BUILD.gn b/blimp/client/BUILD.gn index a16b1c1..f0b8342 100644 --- a/blimp/client/BUILD.gn +++ b/blimp/client/BUILD.gn
@@ -2,6 +2,8 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import("//build/config/ui.gni") + if (is_android) { import("//build/config/android/config.gni") import("//build/config/android/rules.gni") @@ -86,7 +88,7 @@ ] } -if (is_linux && !is_chromeos) { +if (is_linux && !is_chromeos && use_x11) { executable("blimp_shell") { sources = [ "linux/blimp_display_manager.cc",
diff --git a/blimp/client/compositor/blimp_layer_tree_settings.cc b/blimp/client/compositor/blimp_layer_tree_settings.cc index 992ccc8..029e328 100644 --- a/blimp/client/compositor/blimp_layer_tree_settings.cc +++ b/blimp/client/compositor/blimp_layer_tree_settings.cc
@@ -52,6 +52,7 @@ settings->initial_debug_state.show_screen_space_rects = false; settings->initial_debug_state.show_replica_screen_space_rects = false; settings->initial_debug_state.SetRecordRenderingStats(false); + settings->strict_layer_property_change_checking = false; #if defined(OS_ANDROID) if (base::SysInfo::IsLowEndDevice())
diff --git a/blimp/client/linux/blimp_main.cc b/blimp/client/linux/blimp_main.cc index e53283e9..6c2c9fc 100644 --- a/blimp/client/linux/blimp_main.cc +++ b/blimp/client/linux/blimp_main.cc
@@ -13,6 +13,7 @@ #include "blimp/client/blimp_startup.h" #include "blimp/client/session/blimp_client_session_linux.h" #include "blimp/client/session/navigation_feature.h" +#include "blimp/client/session/tab_control_feature.h" namespace { const char kDefaultUrl[] = "https://www.google.com"; @@ -29,12 +30,12 @@ blimp::InitializeMainMessageLoop(); blimp::BlimpClientSessionLinux session; + session.GetTabControlFeature()->CreateTab(kDummyTabId); // If there is a non-switch argument to the command line, load that url. base::CommandLine::StringVector args = base::CommandLine::ForCurrentProcess()->GetArgs(); std::string url = args.size() > 0 ? args[0] : kDefaultUrl; - session.GetNavigationFeature()->NavigateToUrlText(kDummyTabId, url); base::RunLoop().Run();
diff --git a/blimp/client/session/blimp_client_session.cc b/blimp/client/session/blimp_client_session.cc index 8465ae85..2df28d7 100644 --- a/blimp/client/session/blimp_client_session.cc +++ b/blimp/client/session/blimp_client_session.cc
@@ -4,9 +4,12 @@ #include "blimp/client/session/blimp_client_session.h" +#include "base/threading/sequenced_task_runner_handle.h" #include "blimp/client/session/navigation_feature.h" #include "blimp/client/session/render_widget_feature.h" #include "blimp/client/session/tab_control_feature.h" +#include "blimp/net/blimp_message_processor.h" +#include "blimp/net/blimp_message_thread_pipe.h" #include "blimp/net/browser_connection_handler.h" #include "blimp/net/client_connection_manager.h" #include "blimp/net/common.h" @@ -33,28 +36,44 @@ } // namespace +// This class's functions and destruction are all invoked on the IO thread by +// the BlimpClientSession. +// TODO(haibinlu): crbug/574884 class ClientNetworkComponents { public: // Can be created on any thread. ClientNetworkComponents() {} - // Must be destroyed on the IO thread. ~ClientNetworkComponents() {} - // Creates instances for |browser_connection_handler_| and - // |connection_manager_|. - // Must be called on the IO thread. + // Sets up network components and starts to connect to the engine. void Initialize(); + // Invoked by BlimpEngineSession to finish feature registration on IO thread: + // using |incoming_proxy| as the incoming message processor, and connecting + // |outgoing_pipe| to the actual message sender. + void RegisterFeature(BlimpMessage::Type type, + scoped_ptr<BlimpMessageThreadPipe> outgoing_pipe, + scoped_ptr<BlimpMessageProcessor> incoming_proxy); + private: scoped_ptr<BrowserConnectionHandler> browser_connection_handler_; scoped_ptr<ClientConnectionManager> connection_manager_; + // Container for the feature-specific MessageProcessors. + std::vector<scoped_ptr<BlimpMessageProcessor>> incoming_proxies_; + + // Containers for the MessageProcessors used to write feature-specific + // messages to the network, and the thread-pipe endpoints through which + // they are used from the UI thread. + std::vector<scoped_ptr<BlimpMessageThreadPipe>> outgoing_pipes_; + std::vector<scoped_ptr<BlimpMessageProcessor>> outgoing_message_processors_; + DISALLOW_COPY_AND_ASSIGN(ClientNetworkComponents); }; void ClientNetworkComponents::Initialize() { - browser_connection_handler_ = make_scoped_ptr(new BrowserConnectionHandler); + DCHECK(!connection_manager_); connection_manager_ = make_scoped_ptr( new ClientConnectionManager(browser_connection_handler_.get())); connection_manager_->set_client_token(kDummyClientToken); @@ -67,35 +86,88 @@ connection_manager_->Connect(); } +void ClientNetworkComponents::RegisterFeature( + BlimpMessage::Type type, + scoped_ptr<BlimpMessageThreadPipe> outgoing_pipe, + scoped_ptr<BlimpMessageProcessor> incoming_proxy) { + if (!browser_connection_handler_) { + browser_connection_handler_ = make_scoped_ptr(new BrowserConnectionHandler); + } + + // Registers |incoming_proxy| as the message processor for incoming + // messages with |type|. Sets the returned outgoing message processor as the + // actual sender of the |outgoing_pipe|. + scoped_ptr<BlimpMessageProcessor> outgoing_message_processor = + browser_connection_handler_->RegisterFeature(type, incoming_proxy.get()); + outgoing_pipe->set_target_processor(outgoing_message_processor.get()); + + incoming_proxies_.push_back(std::move(incoming_proxy)); + outgoing_pipes_.push_back(std::move(outgoing_pipe)); + outgoing_message_processors_.push_back(std::move(outgoing_message_processor)); +} + BlimpClientSession::BlimpClientSession() : io_thread_("BlimpIOThread"), tab_control_feature_(new TabControlFeature), navigation_feature_(new NavigationFeature), render_widget_feature_(new RenderWidgetFeature), - network_components_(new ClientNetworkComponents) { + net_components_(new ClientNetworkComponents) { base::Thread::Options options; options.message_loop_type = base::MessageLoop::TYPE_IO; io_thread_.StartWithOptions(options); + + // Register features' message senders and receivers. + tab_control_feature_->set_outgoing_message_processor( + RegisterFeature(BlimpMessage::TAB_CONTROL, tab_control_feature_.get())); + navigation_feature_->set_outgoing_message_processor( + RegisterFeature(BlimpMessage::NAVIGATION, navigation_feature_.get())); + render_widget_feature_->set_outgoing_input_message_processor( + RegisterFeature(BlimpMessage::INPUT, render_widget_feature_.get())); + render_widget_feature_->set_outgoing_compositor_message_processor( + RegisterFeature(BlimpMessage::COMPOSITOR, render_widget_feature_.get())); + + // We don't expect to send any RenderWidget messages, so don't save the + // outgoing BlimpMessageProcessor in the RenderWidgetFeature. + RegisterFeature(BlimpMessage::RENDER_WIDGET, render_widget_feature_.get()); + + // Initialize must only be posted after the RegisterFeature calls have + // completed. io_thread_.task_runner()->PostTask( FROM_HERE, base::Bind(&ClientNetworkComponents::Initialize, - base::Unretained(network_components_.get()))); - - // Register features. - // TODO(haibinlu): connect the features with the network layer, with support - // for thread hopping. - tab_control_feature_->set_outgoing_message_processor( - make_scoped_ptr(new NullBlimpMessageProcessor)); - navigation_feature_->set_outgoing_message_processor( - make_scoped_ptr(new NullBlimpMessageProcessor)); - render_widget_feature_->set_outgoing_input_message_processor( - make_scoped_ptr(new NullBlimpMessageProcessor)); - render_widget_feature_->set_outgoing_compositor_message_processor( - make_scoped_ptr(new NullBlimpMessageProcessor)); + base::Unretained(net_components_.get()))); } BlimpClientSession::~BlimpClientSession() { - io_thread_.task_runner()->DeleteSoon(FROM_HERE, - network_components_.release()); + io_thread_.task_runner()->DeleteSoon(FROM_HERE, net_components_.release()); +} + +scoped_ptr<BlimpMessageProcessor> BlimpClientSession::RegisterFeature( + BlimpMessage::Type type, + BlimpMessageProcessor* incoming_processor) { + // Creates an outgoing pipe and a proxy for forwarding messages + // from features on the UI thread to network components on the IO thread. + scoped_ptr<BlimpMessageThreadPipe> outgoing_pipe( + new BlimpMessageThreadPipe(io_thread_.task_runner())); + scoped_ptr<BlimpMessageProcessor> outgoing_message_proxy = + outgoing_pipe->CreateProxy(); + + // Creates an incoming pipe and a proxy for receiving messages + // from network components on the IO thread. + scoped_ptr<BlimpMessageThreadPipe> incoming_pipe( + new BlimpMessageThreadPipe(base::SequencedTaskRunnerHandle::Get())); + incoming_pipe->set_target_processor(incoming_processor); + scoped_ptr<BlimpMessageProcessor> incoming_proxy = + incoming_pipe->CreateProxy(); + + // Finishes registration on IO thread. + io_thread_.task_runner()->PostTask( + FROM_HERE, base::Bind(&ClientNetworkComponents::RegisterFeature, + base::Unretained(net_components_.get()), type, + base::Passed(std::move(outgoing_pipe)), + base::Passed(std::move(incoming_proxy)))); + + incoming_pipes_.push_back(std::move(incoming_pipe)); + return outgoing_message_proxy; } TabControlFeature* BlimpClientSession::GetTabControlFeature() const {
diff --git a/blimp/client/session/blimp_client_session.h b/blimp/client/session/blimp_client_session.h index 4c314eb..8c3ca14 100644 --- a/blimp/client/session/blimp_client_session.h +++ b/blimp/client/session/blimp_client_session.h
@@ -15,6 +15,8 @@ namespace blimp { +class BlimpMessageProcessor; +class BlimpMessageThreadPipe; class BrowserConnectionHandler; class ClientConnectionManager; class ClientNetworkComponents; @@ -38,14 +40,17 @@ NavigationFeature* GetNavigationFeature() const; RenderWidgetFeature* GetRenderWidgetFeature() const; - // Tells |connection_manager_| to start connecting to the remote host. - // Must be called on the IO thread. - void Connect(); - protected: virtual ~BlimpClientSession(); private: + // Registers a message processor which will receive all messages of the |type| + // specified. Returns a BlimpMessageProcessor object for sending messages of + // type |type|. + scoped_ptr<BlimpMessageProcessor> RegisterFeature( + BlimpMessage::Type type, + BlimpMessageProcessor* incoming_processor); + base::Thread io_thread_; scoped_ptr<TabControlFeature> tab_control_feature_; scoped_ptr<NavigationFeature> navigation_feature_; @@ -53,7 +58,12 @@ // Container struct for network components. // Must be deleted on the IO thread. - scoped_ptr<ClientNetworkComponents> network_components_; + scoped_ptr<ClientNetworkComponents> net_components_; + + // Pipes for receiving BlimpMessages from IO thread. + // Incoming messages are only routed to the UI thread since all features run + // on the UI thread. + std::vector<scoped_ptr<BlimpMessageThreadPipe>> incoming_pipes_; DISALLOW_COPY_AND_ASSIGN(BlimpClientSession); };
diff --git a/blimp/client/session/navigation_feature.cc b/blimp/client/session/navigation_feature.cc index 65318f7..2b9bf0a 100644 --- a/blimp/client/session/navigation_feature.cc +++ b/blimp/client/session/navigation_feature.cc
@@ -84,9 +84,12 @@ const NavigationMessage& navigation_message = message->navigation(); NavigationFeatureDelegate* delegate = FindDelegate(tab_id); - DCHECK(delegate); - if (!delegate) + if (!delegate) { + // TODO(haibinlu): implement NavigationFeatureDelegate for Linux client. + // crbug.com/574602 + LOG(WARNING) << "NavigationFeatureDelegate not found"; return; + } switch (navigation_message.type()) { case NavigationMessage::NAVIGATION_STATE_CHANGED: {
diff --git a/blimp/client/session/tab_control_feature.cc b/blimp/client/session/tab_control_feature.cc index 3e156347..fc64b66 100644 --- a/blimp/client/session/tab_control_feature.cc +++ b/blimp/client/session/tab_control_feature.cc
@@ -36,6 +36,22 @@ net::CompletionCallback()); } +void TabControlFeature::CreateTab(int tab_id) { + TabControlMessage* tab_control; + scoped_ptr<BlimpMessage> message = CreateBlimpMessage(&tab_control); + tab_control->set_type(TabControlMessage::CREATE_TAB); + outgoing_message_processor_->ProcessMessage(std::move(message), + net::CompletionCallback()); +} + +void TabControlFeature::CloseTab(int tab_id) { + TabControlMessage* tab_control; + scoped_ptr<BlimpMessage> message = CreateBlimpMessage(&tab_control); + tab_control->set_type(TabControlMessage::CLOSE_TAB); + outgoing_message_processor_->ProcessMessage(std::move(message), + net::CompletionCallback()); +} + void TabControlFeature::ProcessMessage( scoped_ptr<BlimpMessage> message, const net::CompletionCallback& callback) {
diff --git a/blimp/client/session/tab_control_feature.h b/blimp/client/session/tab_control_feature.h index 840b7cd9..ad62c6a0 100644 --- a/blimp/client/session/tab_control_feature.h +++ b/blimp/client/session/tab_control_feature.h
@@ -30,6 +30,9 @@ // affect the web content display area for all tabs. void SetSizeAndScale(const gfx::Size& size, float device_pixel_ratio); + void CreateTab(int tab_id); + void CloseTab(int tab_id); + private: // BlimpMessageProcessor implementation. void ProcessMessage(scoped_ptr<BlimpMessage> message,
diff --git a/blimp/engine/Dockerfile b/blimp/engine/Dockerfile index 21a4d224..5f0c79ad 100644 --- a/blimp/engine/Dockerfile +++ b/blimp/engine/Dockerfile
@@ -20,4 +20,8 @@ USER blimp_user WORKDIR "/engine" -ENTRYPOINT ["/engine/blimp_engine_app", "--disable-gpu"] +ENTRYPOINT ["/engine/blimp_engine_app", "--disable-gpu", + "--use-remote-compositing", + # Retains display items for + # serialization on the engine. + "--disable-cached-picture-raster"]
diff --git a/blimp/engine/browser/blimp_browser_main_parts.cc b/blimp/engine/browser/blimp_browser_main_parts.cc index 6265725..ad20a382 100644 --- a/blimp/engine/browser/blimp_browser_main_parts.cc +++ b/blimp/engine/browser/blimp_browser_main_parts.cc
@@ -39,22 +39,6 @@ engine_session_.reset( new BlimpEngineSession(std::move(browser_context), net_log_.get())); engine_session_->Initialize(); - - // TODO(haibinlu): Create EngineConnectionManager to accept new connections. - // TODO(haibinlu): Remove these test messages and switch to using the - // MessageDispatcher for incoming messages. - scoped_ptr<BlimpMessage> message(new BlimpMessage); - message->set_type(BlimpMessage::TAB_CONTROL); - message->mutable_tab_control()->set_type(TabControlMessage::CREATE_TAB); - engine_session_->ProcessMessage(std::move(message), - net::CompletionCallback()); - message.reset(new BlimpMessage); - message->set_type(BlimpMessage::NAVIGATION); - message->mutable_navigation()->set_type(NavigationMessage::LOAD_URL); - message->mutable_navigation()->mutable_load_url()->set_url( - "https://www.google.com/"); - engine_session_->ProcessMessage(std::move(message), - net::CompletionCallback()); } void BlimpBrowserMainParts::PostMainMessageLoopRun() {
diff --git a/blimp/engine/browser/blimp_engine_session.cc b/blimp/engine/browser/blimp_engine_session.cc index 2252471..69e9cf5 100644 --- a/blimp/engine/browser/blimp_engine_session.cc +++ b/blimp/engine/browser/blimp_engine_session.cc
@@ -13,6 +13,7 @@ #include "blimp/engine/ui/blimp_ui_context_factory.h" #include "blimp/net/blimp_connection.h" #include "blimp/net/blimp_message_multiplexer.h" +#include "blimp/net/blimp_message_thread_pipe.h" #include "blimp/net/browser_connection_handler.h" #include "blimp/net/common.h" #include "blimp/net/engine_authentication_handler.h" @@ -75,21 +76,40 @@ } // namespace -// This class's functions and destruction are all invoked on the IO thread by -// the BlimpEngineSession. +// EngineNetworkComponents is created by the BlimpEngineSession on the UI +// thread, and then used and destroyed on the IO thread. class EngineNetworkComponents { public: explicit EngineNetworkComponents(net::NetLog* net_log); ~EngineNetworkComponents(); + // Sets up network components and starts listening for incoming connection. + // This should be called after all features have been registered so that + // received messages can be properly handled. void Initialize(); + // Connects message pipes between the specified feature and the network layer, + // using |incoming_proxy| as the incoming message processor, and connecting + // |outgoing_pipe| to the actual message sender. + void RegisterFeature(BlimpMessage::Type type, + scoped_ptr<BlimpMessageThreadPipe> outgoing_pipe, + scoped_ptr<BlimpMessageProcessor> incoming_proxy); + private: net::NetLog* net_log_; scoped_ptr<BrowserConnectionHandler> connection_handler_; scoped_ptr<EngineAuthenticationHandler> authentication_handler_; scoped_ptr<EngineConnectionManager> connection_manager_; + // Container for the feature-specific MessageProcessors. + std::vector<scoped_ptr<BlimpMessageProcessor>> incoming_proxies_; + + // Containers for the MessageProcessors used to write feature-specific + // messages to the network, and the thread-pipe endpoints through which + // they are used from the UI thread. + std::vector<scoped_ptr<BlimpMessageProcessor>> outgoing_message_processors_; + std::vector<scoped_ptr<BlimpMessageThreadPipe>> outgoing_pipes_; + DISALLOW_COPY_AND_ASSIGN(EngineNetworkComponents); }; @@ -102,15 +122,15 @@ void EngineNetworkComponents::Initialize() { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); - DCHECK(!connection_handler_); + DCHECK(connection_handler_); + DCHECK(!authentication_handler_); // Creates and connects net components. // A BlimpConnection flows from // connection_manager_ --> authentication_handler_ --> connection_handler_ - connection_handler_.reset(new BrowserConnectionHandler); - authentication_handler_.reset( + authentication_handler_ = make_scoped_ptr( new EngineAuthenticationHandler(connection_handler_.get())); - connection_manager_.reset( + connection_manager_ = make_scoped_ptr( new EngineConnectionManager(authentication_handler_.get())); // Adds BlimpTransports to connection_manager_. @@ -119,6 +139,29 @@ make_scoped_ptr(new TCPEngineTransport(address, net_log_))); } +void EngineNetworkComponents::RegisterFeature( + BlimpMessage::Type type, + scoped_ptr<BlimpMessageThreadPipe> outgoing_pipe, + scoped_ptr<BlimpMessageProcessor> incoming_proxy) { + DCHECK_CURRENTLY_ON(content::BrowserThread::IO); + + if (!connection_handler_) { + connection_handler_ = make_scoped_ptr(new BrowserConnectionHandler); + } + + // Registers |incoming_proxy| as the message processor for incoming + // messages with |type|. Sets the returned outgoing message processor as the + // target of the |outgoing_pipe|. + scoped_ptr<BlimpMessageProcessor> outgoing_message_processor = + connection_handler_->RegisterFeature(type, incoming_proxy.get()); + outgoing_pipe->set_target_processor(outgoing_message_processor.get()); + + // This object manages the lifetimes of the pipe, proxy and target processor. + incoming_proxies_.push_back(std::move(incoming_proxy)); + outgoing_pipes_.push_back(std::move(outgoing_pipe)); + outgoing_message_processors_.push_back(std::move(outgoing_message_processor)); +} + BlimpEngineSession::BlimpEngineSession( scoped_ptr<BlimpBrowserContext> browser_context, net::NetLog* net_log) @@ -169,11 +212,6 @@ window_tree_host_->SetBounds(gfx::Rect(screen_->GetPrimaryDisplay().size())); - content::BrowserThread::PostTask( - content::BrowserThread::IO, FROM_HERE, - base::Bind(&EngineNetworkComponents::Initialize, - base::Unretained(net_components_.get()))); - // Register features' message senders and receivers. tab_control_message_sender_ = RegisterFeature(BlimpMessage::TAB_CONTROL, this); @@ -184,14 +222,46 @@ RegisterFeature(BlimpMessage::INPUT, &render_widget_feature_)); render_widget_feature_.set_compositor_message_sender( RegisterFeature(BlimpMessage::COMPOSITOR, &render_widget_feature_)); + + // Initialize must only be posted after the RegisterFeature calls have + // completed. + content::BrowserThread::PostTask( + content::BrowserThread::IO, FROM_HERE, + base::Bind(&EngineNetworkComponents::Initialize, + base::Unretained(net_components_.get()))); } scoped_ptr<BlimpMessageProcessor> BlimpEngineSession::RegisterFeature( BlimpMessage::Type type, BlimpMessageProcessor* incoming_processor) { - // TODO(haibinlu): implement this once thread hopping message processing is - // done. - return make_scoped_ptr(new NullBlimpMessageProcessor); + // Creates an outgoing pipe and a proxy for forwarding messages + // from features on the UI thread to network components on the IO thread. + scoped_refptr<base::SingleThreadTaskRunner> io_task_runner = + content::BrowserThread::GetMessageLoopProxyForThread( + content::BrowserThread::IO); + scoped_ptr<BlimpMessageThreadPipe> outgoing_pipe( + new BlimpMessageThreadPipe(io_task_runner)); + scoped_ptr<BlimpMessageProcessor> outgoing_proxy = + outgoing_pipe->CreateProxy(); + + // Creates an incoming pipe and a proxy for receiving messages + // from network components on the IO thread. + scoped_ptr<BlimpMessageThreadPipe> incoming_pipe(new BlimpMessageThreadPipe( + content::BrowserThread::GetMessageLoopProxyForThread( + content::BrowserThread::UI))); + incoming_pipe->set_target_processor(incoming_processor); + scoped_ptr<BlimpMessageProcessor> incoming_proxy = + incoming_pipe->CreateProxy(); + + // Finishes registration on IO thread. + io_task_runner->PostTask( + FROM_HERE, base::Bind(&EngineNetworkComponents::RegisterFeature, + base::Unretained(net_components_.get()), type, + base::Passed(std::move(outgoing_pipe)), + base::Passed(std::move(incoming_proxy)))); + + incoming_pipes_.push_back(std::move(incoming_pipe)); + return outgoing_proxy; } void BlimpEngineSession::CreateWebContents(const int target_tab_id) {
diff --git a/blimp/engine/browser/blimp_engine_session.h b/blimp/engine/browser/blimp_engine_session.h index e25d7df0..9c10f48 100644 --- a/blimp/engine/browser/blimp_engine_session.h +++ b/blimp/engine/browser/blimp_engine_session.h
@@ -52,6 +52,7 @@ class BlimpConnection; class BlimpMessage; +class BlimpMessageThreadPipe; namespace engine { @@ -80,7 +81,7 @@ BlimpBrowserContext* browser_context() { return browser_context_.get(); } // BlimpMessageProcessor implementation. - // This object handles incoming TAB_CONTROL and NAVIGATION messages. + // This object handles incoming TAB_CONTROL and NAVIGATION messages directly. void ProcessMessage(scoped_ptr<BlimpMessage> message, const net::CompletionCallback& callback) override; @@ -158,16 +159,19 @@ // Only one web_contents is supported for blimp 0.5 scoped_ptr<content::WebContents> web_contents_; + // Handles all incoming and outgoing messages related to RenderWidget, + // including INPUT, COMPOSITOR and RENDER_WIDGET messages. + EngineRenderWidgetFeature render_widget_feature_; + // Container for connection manager, authentication handler, and // browser connection handler. The components run on the I/O thread, and // this object is destroyed there. scoped_ptr<EngineNetworkComponents> net_components_; - // Handles all incoming and outgoing messages related to RenderWidget, - // including INPUT, COMPOSITOR and RENDER_WIDGET messages. - // TODO(dtrainor, haibinlu): Move this to a higher level once we start dealing - // with multiple tabs. - EngineRenderWidgetFeature render_widget_feature_; + // Pipes for receiving BlimpMessages from IO thread. + // Incoming messages are only routed to the UI thread since all features run + // there. + std::vector<scoped_ptr<BlimpMessageThreadPipe>> incoming_pipes_; scoped_ptr<BlimpMessageProcessor> tab_control_message_sender_; scoped_ptr<BlimpMessageProcessor> navigation_message_sender_;
diff --git a/blimp/engine/browser/engine_render_widget_feature.cc b/blimp/engine/browser/engine_render_widget_feature.cc index 7beaaaf..fe68ae61 100644 --- a/blimp/engine/browser/engine_render_widget_feature.cc +++ b/blimp/engine/browser/engine_render_widget_feature.cc
@@ -100,7 +100,7 @@ case BlimpMessage::INPUT: if (message->input().render_widget_id() == render_widget_id) { scoped_ptr<blink::WebInputEvent> event = - input_message_processor_.ProcessMessage(message->input()); + input_message_converter_.ProcessMessage(message->input()); if (event) delegate->OnWebInputEvent(std::move(event)); }
diff --git a/blimp/engine/browser/engine_render_widget_feature.h b/blimp/engine/browser/engine_render_widget_feature.h index 7f89516..b3504f47 100644 --- a/blimp/engine/browser/engine_render_widget_feature.h +++ b/blimp/engine/browser/engine_render_widget_feature.h
@@ -13,7 +13,7 @@ #include "base/macros.h" #include "base/memory/scoped_ptr.h" #include "blimp/net/blimp_message_processor.h" -#include "blimp/net/input_message_processor.h" +#include "blimp/net/input_message_converter.h" namespace blink { class WebInputEvent; @@ -87,16 +87,11 @@ DelegateMap delegates_; RenderWidgetIdMap render_widget_ids_; - // TODO(haibinlu): rename InputMessageProcessor. - InputMessageProcessor input_message_processor_; + InputMessageConverter input_message_converter_; - // Message processor for sending RENDER_WIDGET messages. + // Outgoing message processors for RENDER_WIDGET, COMPOSITOR and INPUT types. scoped_ptr<BlimpMessageProcessor> render_widget_message_sender_; - - // Message processor for sending COMPOSITOR messages. scoped_ptr<BlimpMessageProcessor> compositor_message_sender_; - - // Message processor for sending INPUT messages. scoped_ptr<BlimpMessageProcessor> input_message_sender_; DISALLOW_COPY_AND_ASSIGN(EngineRenderWidgetFeature);
diff --git a/blimp/net/BUILD.gn b/blimp/net/BUILD.gn index 81931f1b..30075bc0 100644 --- a/blimp/net/BUILD.gn +++ b/blimp/net/BUILD.gn
@@ -34,10 +34,10 @@ "engine_authentication_handler.h", "engine_connection_manager.cc", "engine_connection_manager.h", + "input_message_converter.cc", + "input_message_converter.h", "input_message_generator.cc", "input_message_generator.h", - "input_message_processor.cc", - "input_message_processor.h", "null_blimp_message_processor.cc", "null_blimp_message_processor.h", "stream_packet_reader.cc",
diff --git a/blimp/net/blimp_message_thread_pipe.h b/blimp/net/blimp_message_thread_pipe.h index 4f8617cb..bca86d1 100644 --- a/blimp/net/blimp_message_thread_pipe.h +++ b/blimp/net/blimp_message_thread_pipe.h
@@ -27,10 +27,9 @@ // 1. Create the pipe on the "main" thread, specifying the target thread's // task runner. // 2. Take one or more MessageProcessor proxies from it. -// 3. Post a task to the target thread to set the outgoing -// MessageProcessor. +// 3. Post a task to the target thread to set the target MessageProcessor. // 4. Start using the MessageProcessor proxy(/ies) on the main thread. -// 5. When the outgoing MessageProcessor is about to be destroyed on the +// 5. When the target MessageProcessor is about to be destroyed on the // target thread, destroy the pipe instance immediately beforehand. // Any messages that are subsequently passed to a proxy, or are already // in-flight to the pipe, will be silently dropped.
diff --git a/blimp/net/input_message_processor.cc b/blimp/net/input_message_converter.cc similarity index 96% rename from blimp/net/input_message_processor.cc rename to blimp/net/input_message_converter.cc index 626e155..7711a398 100644 --- a/blimp/net/input_message_processor.cc +++ b/blimp/net/input_message_converter.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "blimp/net/input_message_processor.h" +#include "blimp/net/input_message_converter.h" #include "base/logging.h" #include "blimp/common/proto/input.pb.h" @@ -134,11 +134,11 @@ } // namespace -InputMessageProcessor::InputMessageProcessor() {} +InputMessageConverter::InputMessageConverter() {} -InputMessageProcessor::~InputMessageProcessor() {} +InputMessageConverter::~InputMessageConverter() {} -scoped_ptr<blink::WebInputEvent> InputMessageProcessor::ProcessMessage( +scoped_ptr<blink::WebInputEvent> InputMessageConverter::ProcessMessage( const InputMessage& message) { scoped_ptr<blink::WebInputEvent> event;
diff --git a/blimp/net/input_message_processor.h b/blimp/net/input_message_converter.h similarity index 68% rename from blimp/net/input_message_processor.h rename to blimp/net/input_message_converter.h index 5a7ab1c..c0255cb4 100644 --- a/blimp/net/input_message_processor.h +++ b/blimp/net/input_message_converter.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 BLIMP_NET_INPUT_MESSAGE_PROCESSOR_H_ -#define BLIMP_NET_INPUT_MESSAGE_PROCESSOR_H_ +#ifndef BLIMP_NET_INPUT_MESSAGE_CONVERTER_H_ +#define BLIMP_NET_INPUT_MESSAGE_CONVERTER_H_ #include "base/macros.h" #include "base/memory/scoped_ptr.h" @@ -19,20 +19,20 @@ // Handles creating WebInputEvents from a stream of InputMessage protos. This // class may be stateful to optimize the size of the serialized transmission -// data. See InputMessageProcessor for the deserialize code. -class BLIMP_NET_EXPORT InputMessageProcessor { +// data. See InputMessageConverter for the deserialize code. +class BLIMP_NET_EXPORT InputMessageConverter { public: - InputMessageProcessor(); - ~InputMessageProcessor(); + InputMessageConverter(); + ~InputMessageConverter(); // Process an InputMessage and create a WebInputEvent from it. This might // make use of state from previous messages. scoped_ptr<blink::WebInputEvent> ProcessMessage(const InputMessage& message); private: - DISALLOW_COPY_AND_ASSIGN(InputMessageProcessor); + DISALLOW_COPY_AND_ASSIGN(InputMessageConverter); }; } // namespace blimp -#endif // BLIMP_NET_INPUT_MESSAGE_PROCESSOR_H_ +#endif // BLIMP_NET_INPUT_MESSAGE_CONVERTER_H_
diff --git a/blimp/net/input_message_generator.h b/blimp/net/input_message_generator.h index 0059ce4b..d4ca46a 100644 --- a/blimp/net/input_message_generator.h +++ b/blimp/net/input_message_generator.h
@@ -21,7 +21,7 @@ // Handles creating serialized InputMessage protos from a stream of // WebInputEvents. This class may be stateful to optimize the size of the -// serialized transmission data. See InputMessageProcessor for the deserialize +// serialized transmission data. See InputMessageConverter for the deserialize // code. class BLIMP_NET_EXPORT InputMessageGenerator { public:
diff --git a/blimp/net/input_message_unittest.cc b/blimp/net/input_message_unittest.cc index 9b9d3d0..eaf9ce2 100644 --- a/blimp/net/input_message_unittest.cc +++ b/blimp/net/input_message_unittest.cc
@@ -9,8 +9,8 @@ #include "blimp/common/proto/blimp_message.pb.h" #include "blimp/common/proto/input.pb.h" #include "blimp/net/blimp_message_processor.h" +#include "blimp/net/input_message_converter.h" #include "blimp/net/input_message_generator.h" -#include "blimp/net/input_message_processor.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/WebKit/public/platform/WebGestureDevice.h" #include "third_party/WebKit/public/web/WebInputEvent.h" @@ -20,7 +20,7 @@ void ValidateWebInputEventRoundTripping(const blink::WebInputEvent& event) { InputMessageGenerator generator; - InputMessageProcessor processor; + InputMessageConverter processor; scoped_ptr<BlimpMessage> proto = generator.GenerateMessage(event); EXPECT_NE(nullptr, proto.get());
diff --git a/build/all.gyp b/build/all.gyp index 37929b5..9d5eb88a 100644 --- a/build/all.gyp +++ b/build/all.gyp
@@ -574,7 +574,6 @@ '../chrome/chrome.gyp:load_library_perf_tests', '../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', '../media/midi/midi.gyp:midi_unittests', @@ -836,6 +835,7 @@ '../tools/android/android_tools.gyp:android_tools', '../tools/android/android_tools.gyp:memconsumer', '../tools/android/findbugs_plugin/findbugs_plugin.gyp:findbugs_plugin_test', + '../tools/cygprofile/cygprofile.gyp:cygprofile_unittests', '../ui/android/ui_android.gyp:ui_android_unittests', '../ui/base/ui_base_tests.gyp:ui_base_unittests', '../ui/events/events_unittests.gyp:events_unittests',
diff --git a/build/android/devil/devil_dependencies.json b/build/android/devil/devil_dependencies.json index 31db2270..d131c17 100644 --- a/build/android/devil/devil_dependencies.json +++ b/build/android/devil/devil_dependencies.json
@@ -5,7 +5,7 @@ "cloud_storage_bucket": "chromium-telemetry", "cloud_storage_base_folder": "binary_dependencies", "file_info": { - "linux_x86_64": { + "linux2_x86_64": { "cloud_storage_hash": "7448de3cb5e834afdedeaad8b40ba63ac53f3dc4", "download_path": "../bin/aapt" } @@ -15,7 +15,7 @@ "cloud_storage_bucket": "chromium-telemetry", "cloud_storage_base_folder": "binary_dependencies", "file_info": { - "linux_x86_64": { + "linux2_x86_64": { "cloud_storage_hash": "0c2043552619c8ec8bb5d986ba75703a598611fc", "download_path": "../bin/adb" } @@ -25,7 +25,7 @@ "cloud_storage_bucket": "chromium-telemetry", "cloud_storage_base_folder": "binary_dependencies", "file_info": { - "linux_x86_64": { + "linux2_x86_64": { "cloud_storage_hash": "52d150a7ccde835f38b4337392152f3013d5f303", "download_path": "../bin/lib/libc++.so" } @@ -35,7 +35,7 @@ "cloud_storage_bucket": "chromium-telemetry", "cloud_storage_base_folder": "binary_dependencies", "file_info": { - "linux_x86_64": { + "linux2_x86_64": { "cloud_storage_hash": "049f482f29bc34e2ed844e2e47b7609f8ffbeb4f", "download_path": "../bin/lib.java/chromium_commands.dex.jar" } @@ -45,7 +45,7 @@ "cloud_storage_bucket": "chromium-telemetry", "cloud_storage_base_folder": "binary_dependencies", "file_info": { - "linux_x86_64": { + "linux2_x86_64": { "cloud_storage_hash": "38765b5b358c29003e56b1d214606ea13467b6fe", "download_path": "../bin/dexdump" } @@ -69,7 +69,7 @@ "cloud_storage_bucket": "chromium-telemetry", "cloud_storage_base_folder": "binary_dependencies", "file_info": { - "linux_x86_64": { + "linux2_x86_64": { "cloud_storage_hash": "b3dda9fbdd4a3fb933b64111c11070aa809c7ed4", "download_path": "../bin/forwarder_host" } @@ -97,7 +97,7 @@ "cloud_storage_bucket": "chromium-telemetry", "cloud_storage_base_folder": "binary_dependencies", "file_info": { - "linux_x86_64": { + "linux2_x86_64": { "cloud_storage_hash": "49e36c9c4246cfebef26cbd07436c1a8343254aa", "download_path": "../bin/md5sum_host" } @@ -105,22 +105,22 @@ }, "pymock": { "file_info": { - "linux_x86_64": { + "darwin_x86_64": { "local_paths": [ "../../../tools/telemetry/third_party/mock" ] }, - "mac_x86_64": { + "linux2_x86_64": { "local_paths": [ "../../../tools/telemetry/third_party/mock" ] }, - "win_AMD64": { + "win32_AMD64": { "local_paths": [ "../../../tools/telemetry/third_party/mock" ] }, - "win_x86": { + "win32_x86": { "local_paths": [ "../../../tools/telemetry/third_party/mock" ] @@ -131,7 +131,7 @@ "cloud_storage_bucket": "chromium-telemetry", "cloud_storage_base_folder": "binary_dependencies", "file_info": { - "linux_x86_64": { + "linux2_x86_64": { "cloud_storage_hash": "3327881fa3951a503b9467425ea8e781cdffeb9f", "download_path": "../bin/split-select" }
diff --git a/build/android/devil/devil_env.py b/build/android/devil/devil_env.py index 07bb658..efec603 100644 --- a/build/android/devil/devil_env.py +++ b/build/android/devil/devil_env.py
@@ -38,11 +38,11 @@ _LEGACY_ENVIRONMENT_VARIABLES = { 'ADB_PATH': { 'dependency_name': 'adb', - 'platform': 'linux_x86_64', + 'platform': 'linux2_x86_64', }, 'ANDROID_SDK_ROOT': { 'dependency_name': 'android_sdk', - 'platform': 'linux_x86_64', + 'platform': 'linux2_x86_64', }, } @@ -139,7 +139,7 @@ def GetPlatform(arch=None, device=None): if device: return 'android_%s' % (arch or device.product_cpu_abi) - return 'linux_%s' % platform.machine() + return '%s_%s' % (sys.platform, platform.machine()) config = _Environment()
diff --git a/build/android/devil/devil_env_test.py b/build/android/devil/devil_env_test.py index 7cf4c03..c680f2d 100755 --- a/build/android/devil/devil_env_test.py +++ b/build/android/devil/devil_env_test.py
@@ -48,7 +48,7 @@ { 'adb': { 'file_info': { - 'linux_x86_64': { + 'linux2_x86_64': { 'local_paths': ['/my/fake/adb/path'], }, },
diff --git a/build/android/devil_chromium.json b/build/android/devil_chromium.json index e54beae..489add8 100644 --- a/build/android/devil_chromium.json +++ b/build/android/devil_chromium.json
@@ -3,7 +3,7 @@ "dependencies": { "aapt": { "file_info": { - "linux_x86_64": { + "linux2_x86_64": { "local_paths": [ "../../third_party/android_tools/sdk/build-tools/23.0.0/aapt" ] @@ -12,7 +12,7 @@ }, "adb": { "file_info": { - "linux_x86_64": { + "linux2_x86_64": { "local_paths": [ "../../third_party/android_tools/sdk/platform-tools/adb" ] @@ -21,7 +21,7 @@ }, "android_sdk": { "file_info": { - "linux_x86_64": { + "linux2_x86_64": { "local_paths": [ "../../third_party/android_tools/sdk" ] @@ -30,7 +30,7 @@ }, "dexdump": { "file_info": { - "linux_x86_64": { + "linux2_x86_64": { "local_paths": [ "../../third_party/android_tools/sdk/build-tools/23.0.0/dexdump" ] @@ -39,7 +39,7 @@ }, "split-select": { "file_info": { - "linux_x86_64": { + "linux2_x86_64": { "local_paths": [ "../../third_party/android_tools/sdk/build-tools/23.0.0/split-select" ] @@ -48,17 +48,17 @@ }, "pymock": { "file_info": { - "android_darwin": { + "darwin_x86_64": { "local_paths": [ "../../third_party/pymock" ] }, - "linux_x86_64": { + "linux2_x86_64": { "local_paths": [ "../../third_party/pymock" ] }, - "win32_x86_64": { + "win32_AMD64": { "local_paths": [ "../../third_party/pymock" ]
diff --git a/build/android/gyp/apk_obfuscate.py b/build/android/gyp/apk_obfuscate.py index 4a13cb1..f29f0910 100755 --- a/build/android/gyp/apk_obfuscate.py +++ b/build/android/gyp/apk_obfuscate.py
@@ -69,6 +69,8 @@ 'These will not be obfuscated.') parser.add_option('--multidex-configuration-path', help='A JSON file containing multidex build configuration.') + parser.add_option('--verbose', '-v', action='store_true', + help='Print all proguard output') (options, args) = parser.parse_args(argv) @@ -118,7 +120,7 @@ configs.append(multidex_config) proguard.configs(configs) - proguard.CheckOutput() + proguard.CheckOutput(options.verbose) def _PossibleMultidexConfig(options):
diff --git a/build/android/gyp/proguard.py b/build/android/gyp/proguard.py index 2484354..4bbb5d5 100755 --- a/build/android/gyp/proguard.py +++ b/build/android/gyp/proguard.py
@@ -31,6 +31,8 @@ parser.add_option('--classpath', action='append', help='Classpath for proguard.') parser.add_option('--stamp', help='Path to touch on success.') + parser.add_option('--verbose', '-v', action='store_true', + help='Print all proguard output') options, _ = parser.parse_args(args) @@ -63,7 +65,7 @@ input_paths = proguard.GetInputs() build_utils.CallAndWriteDepfileIfStale( - proguard.CheckOutput, + lambda: proguard.CheckOutput(options.verbose), options, input_paths=input_paths, input_strings=proguard.build(),
diff --git a/build/android/gyp/util/proguard_util.py b/build/android/gyp/util/proguard_util.py index 8ca8646..70b781d 100644 --- a/build/android/gyp/util/proguard_util.py +++ b/build/android/gyp/util/proguard_util.py
@@ -3,29 +3,33 @@ # found in the LICENSE file. import os +import re from util import build_utils -def FilterProguardOutput(output): - '''ProGuard outputs boring stuff to stdout (proguard version, jar path, etc) + +class _ProguardOutputFilter(object): + """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 '' + boring, this class suppresses the output. + """ + + IGNORE_RE = re.compile( + r'(?:Pro.*version|Note:|Reading|Preparing|.*:.*(?:MANIFEST\.MF|\.empty))') + + def __init__(self): + self._last_line_ignored = False + + def __call__(self, output): + ret = [] + for line in output.splitlines(True): + if not line.startswith(' '): + self._last_line_ignored = bool(self.IGNORE_RE.match(line)) + elif 'You should check if you need to specify' in line: + self._last_line_ignored = True + + if not self._last_line_ignored: + ret.append(line) + return ''.join(ret) class ProguardCmdBuilder(object): @@ -145,7 +149,7 @@ return inputs - def CheckOutput(self): + def CheckOutput(self, verbose=False): self.build() # Proguard will skip writing these files if they would be empty. Create # empty versions of them all now so that they are updated as the build @@ -154,8 +158,17 @@ open(self._outjar + '.seeds', 'w').close() open(self._outjar + '.usage', 'w').close() open(self._outjar + '.mapping', 'w').close() + # Warning: and Error: are sent to stderr, but messages and Note: are sent + # to stdout. + stdout_filter = None + stderr_filter = None + if not verbose: + stdout_filter = _ProguardOutputFilter() + stderr_filter = _ProguardOutputFilter() build_utils.CheckOutput(self._cmd, print_stdout=True, - stdout_filter=FilterProguardOutput) + print_stderr=True, + stdout_filter=stdout_filter, + stderr_filter=stderr_filter) this_info = { 'inputs': self._injars,
diff --git a/build/android/incremental_install/java/org/chromium/incrementalinstall/BootstrapApplication.java b/build/android/incremental_install/java/org/chromium/incrementalinstall/BootstrapApplication.java index 67c60e5..7c9bcca2 100644 --- a/build/android/incremental_install/java/org/chromium/incrementalinstall/BootstrapApplication.java +++ b/build/android/incremental_install/java/org/chromium/incrementalinstall/BootstrapApplication.java
@@ -118,7 +118,7 @@ ApplicationInfo appInfo = getPackageManager().getApplicationInfo(getPackageName(), PackageManager.GET_META_DATA); String value = appInfo.metaData.getString(key); - if (!value.contains(".")) { + if (value != null && !value.contains(".")) { value = getPackageName() + "." + value; } return value; @@ -129,11 +129,22 @@ */ private void initInstrumentation(String realInstrumentationName) throws ReflectiveOperationException { + Instrumentation oldInstrumentation = + (Instrumentation) Reflect.getField(mActivityThread, "mInstrumentation"); + if (realInstrumentationName == null) { + // This is the case when an incremental app is used as a target for an instrumentation + // test. In this case, ActivityThread can instantiate the proper class just fine since + // it exists within the test apk (as opposed to the incremental apk-under-test). + Log.i(TAG, "Running with external instrumentation"); + mRealInstrumentation = oldInstrumentation; + return; + } + // For unit tests, the instrumentation class is replaced in the manifest by a build step + // because ActivityThread tries to instantiate it before we get a chance to load the + // incremental dex files. Log.i(TAG, "Instantiating instrumentation " + realInstrumentationName); mRealInstrumentation = (Instrumentation) Reflect.newInstance( Class.forName(realInstrumentationName)); - Instrumentation oldInstrumentation = - (Instrumentation) Reflect.getField(mActivityThread, "mInstrumentation"); // Initialize the fields that are set by Instrumentation.init(). String[] initFields = {"mThread", "mMessageQueue", "mInstrContext", "mAppContext",
diff --git a/build/android/lint/suppressions.xml b/build/android/lint/suppressions.xml index 61d062d..2ab10b8 100644 --- a/build/android/lint/suppressions.xml +++ b/build/android/lint/suppressions.xml
@@ -55,7 +55,7 @@ <ignore path="chrome/android/java/res/drawable-xxxhdpi"/> <ignore path="ui/android/java/res/drawable-xxhdpi"/> <ignore path="ui/android/java/res/drawable-xxxhdpi"/> - <ignore regexp=".*: data_reduction_illustration.png, google_icon_sprite.png, reader_mode_bar_background.9.png, tabs_moved_htc.png, tabs_moved_nexus.png, tabs_moved_samsung.png$"/> + <ignore regexp=".*: data_reduction_illustration.png, google_icon_sprite.png, tabs_moved_htc.png, tabs_moved_nexus.png, tabs_moved_samsung.png$"/> </issue> <issue id="IconDipSize"> <ignore regexp=".*google_icon_sprite.png.*"/>
diff --git a/build/android/main_dex_classes.flags b/build/android/main_dex_classes.flags index a8d969a..81152dc 100644 --- a/build/android/main_dex_classes.flags +++ b/build/android/main_dex_classes.flags
@@ -5,3 +5,8 @@ -keepclasseswithmembers class * { public static ** asInterface(android.os.IBinder); } + +# Required when code coverage is enabled. +-keep class com.vladium.** { + *; +}
diff --git a/build/android/ndk.gyp b/build/android/ndk.gyp index 2838a985..b491db24 100644 --- a/build/android/ndk.gyp +++ b/build/android/ndk.gyp
@@ -15,6 +15,12 @@ 'sources': [ '<(android_ndk_root)/sources/android/cpufeatures/cpu-features.c', ], + 'variables': { + 'clang_warning_flags': [ + # cpu-features.c has few unused functions on x86 b/26403333 + '-Wno-unused-function', + ], + }, }, ], }
diff --git a/build/android/pylib/instrumentation/setup.py b/build/android/pylib/instrumentation/setup.py index ceaab042..b401371 100644 --- a/build/android/pylib/instrumentation/setup.py +++ b/build/android/pylib/instrumentation/setup.py
@@ -75,9 +75,12 @@ os.path.exists(test_options.coverage_dir)): os.makedirs(test_options.coverage_dir) - test_pkg = test_package.TestPackage(test_options.test_apk_path, - test_options.test_apk_jar_path, - test_options.test_support_apk_path) + test_pkg = test_package.TestPackage( + test_options.test_apk_path, + test_options.test_apk_jar_path, + test_options.test_support_apk_path, + additional_apks=test_options.additional_apks, + apk_under_test=test_options.apk_under_test) tests = test_pkg.GetAllMatchingTests( test_options.annotations, test_options.exclude_annotations,
diff --git a/build/android/pylib/instrumentation/test_options.py b/build/android/pylib/instrumentation/test_options.py index b5276b77..0a3d5cd 100644 --- a/build/android/pylib/instrumentation/test_options.py +++ b/build/android/pylib/instrumentation/test_options.py
@@ -25,4 +25,6 @@ 'isolate_file_path', 'set_asserts', 'delete_stale_data', - 'timeout_scale']) + 'timeout_scale', + 'apk_under_test', + 'additional_apks'])
diff --git a/build/android/pylib/instrumentation/test_package.py b/build/android/pylib/instrumentation/test_package.py index 1f56b5e..d6469b2 100644 --- a/build/android/pylib/instrumentation/test_package.py +++ b/build/android/pylib/instrumentation/test_package.py
@@ -11,13 +11,16 @@ class TestPackage(test_jar.TestJar): - def __init__(self, apk_path, jar_path, test_support_apk_path): + def __init__(self, apk_path, jar_path, test_support_apk_path, + additional_apks=None, apk_under_test=None): test_jar.TestJar.__init__(self, jar_path) if not os.path.exists(apk_path): raise Exception('%s not found, please build it' % apk_path) - self._apk_path = apk_path + self._additional_apks = additional_apks or [] self._apk_name = os.path.splitext(os.path.basename(apk_path))[0] + self._apk_path = apk_path + self._apk_under_test = apk_under_test self._package_name = apk_helper.GetPackageName(self._apk_path) self._test_support_apk_path = test_support_apk_path @@ -35,7 +38,11 @@ # Override. def Install(self, device): + if self._apk_under_test: + device.Install(self._apk_under_test) device.Install(self.GetApkPath()) if (self._test_support_apk_path and os.path.exists(self._test_support_apk_path)): device.Install(self._test_support_apk_path) + for apk in (a for a in self._additional_apks if os.path.exists(a)): + device.Install(apk)
diff --git a/build/android/test_runner.py b/build/android/test_runner.py index 192718e..4f968b5 100755 --- a/build/android/test_runner.py +++ b/build/android/test_runner.py
@@ -450,7 +450,9 @@ args.isolate_file_path, args.set_asserts, args.delete_stale_data, - args.timeout_scale) + args.timeout_scale, + args.apk_under_test, + args.additional_apks) def AddUIAutomatorTestOptions(parser):
diff --git a/build/common.gypi b/build/common.gypi index 577a95c..f63b0114 100644 --- a/build/common.gypi +++ b/build/common.gypi
@@ -1011,7 +1011,7 @@ 'use_openmax_dl_fft%': 0, }], ['OS=="win" or OS=="linux"', { - 'enable_mdns%' : 1, + 'enable_mdns%' : 1, }], # Disable various features by default on embedded. @@ -1548,9 +1548,6 @@ # Force disable libstdc++ debug mode. 'disable_glibcxx_debug%': 0, - # Set to 1 to compile with MSE support for MPEG2 TS - 'enable_mpeg2ts_stream_parser%': 0, - # Support ChromeOS touchpad gestures with ozone. 'use_evdev_gestures%': 0, @@ -1885,7 +1882,6 @@ 'use_system_fontconfig%': 1, }], ['chromecast==1', { - 'enable_mpeg2ts_stream_parser%': 1, 'use_custom_freetype%': 0, 'use_playready%': 0, 'conditions': [ @@ -2633,6 +2629,12 @@ 'clang_warning_flags': [ '-Wheader-hygiene', + # TODO(thakis): Add -Wfor-loop-analysis to -Wall in clang, remove this: + '-Wfor-loop-analysis', + + # TODO(thakis): Consider -Wloop-analysis (turns on + # -Wrange-loop-analysis too). + # Don't die on dtoa code that uses a char as an array index. # This is required solely for base/third_party/dmg_fp/dtoa.cc. '-Wno-char-subscripts', @@ -2667,9 +2669,6 @@ # TODO(thakis): Enable this, crbug.com/507717 '-Wno-shift-negative-value', - - # TODO(thakis): Consider enabling this? - '-Wno-bitfield-width', ], }, 'includes': [ 'set_clang_warning_flags.gypi', ], @@ -2774,11 +2773,6 @@ }], ['proprietary_codecs==1', { 'defines': ['USE_PROPRIETARY_CODECS'], - 'conditions': [ - ['enable_mpeg2ts_stream_parser==1', { - 'defines': ['ENABLE_MPEG2TS_STREAM_PARSER'], - }], - ], }], ['enable_viewport==1', { 'defines': ['ENABLE_VIEWPORT'],
diff --git a/build/config/BUILD.gn b/build/config/BUILD.gn index 18bd775..195293b 100644 --- a/build/config/BUILD.gn +++ b/build/config/BUILD.gn
@@ -363,15 +363,7 @@ # target that needs it. ] } else if (is_android) { - # Android uses -nostdlib so we need to add even libc here. libs = [ - # TODO(brettw) write a version of this, hopefully we can express this - # without forking out to GCC just to get the library name. The android - # toolchain directory should probably be extracted into a .gni file that - # this file and the android toolchain .gn file can share. - # # Manually link the libgcc.a that the cross compiler uses. - # '<!(<(android_toolchain)/*-gcc -print-libgcc-file-name)', - "c", "dl", "m", ]
diff --git a/build/config/BUILDCONFIG.gn b/build/config/BUILDCONFIG.gn index 54bf372..81323aa0 100644 --- a/build/config/BUILDCONFIG.gn +++ b/build/config/BUILDCONFIG.gn
@@ -549,6 +549,9 @@ if (is_component_build) { set_defaults("component") { configs = _shared_library_configs + if (is_android) { + configs -= [ "//build/config/android:hide_native_jni_exports" ] + } } } @@ -575,12 +578,25 @@ # COMPONENT SETUP # ============================================================================== -if (is_component_build) { - _component_mode = "shared_library" -} else { - _component_mode = "source_set" -} +# Defines a component, which equates to a shared_library when +# is_component_build == true and a source_set / static_library otherwise. +# +# Arguments are the same as a normal library with this addition: +# component_never_use_source_set: Whether to use static_library instead of +# source_set for non-component builds. Some targets (e.g. //base) should +# use static_library rather than source_set to avoid linking unused object +# files. template("component") { + _never_use_source_set = defined(invoker.component_never_use_source_set) && + invoker.component_never_use_source_set + assert(_never_use_source_set || true) # Mark as used. + if (is_component_build) { + _component_mode = "shared_library" + } else if (_never_use_source_set) { + _component_mode = "static_library" + } else { + _component_mode = "source_set" + } target(_component_mode, target_name) { forward_variables_from(invoker, "*")
diff --git a/build/config/android/BUILD.gn b/build/config/android/BUILD.gn index ec80f237..22a6075 100644 --- a/build/config/android/BUILD.gn +++ b/build/config/android/BUILD.gn
@@ -154,29 +154,18 @@ libs = [ "c++_static" ] } - # libgcc must come before libdl for ld.bfd (MIPS) - if (current_cpu == "mipsel") { - libs += [ - # ld linker is used for mips Android, and ld does not accept library - # absolute path prefixed by "-l"; Since libgcc does not exist in mips - # sysroot the proper library will be linked. - # TODO(gordanac): Remove once gold linker is used for mips Android. - "gcc", - ] - } else { - libs += [ - # Manually link the libgcc.a that the cross compiler uses. This is - # absolute because the linker will look inside the sysroot if it's not. - rebase_path(android_libgcc_file), - ] - } - + # Manually link the libgcc.a that the cross compiler uses. This is + # absolute because the linker will look inside the sysroot if it's not. libs += [ + rebase_path(android_libgcc_file), "c", - "dl", - "m", ] + # Clang with libc++ does not require an explicit atomic library reference. + if (!is_clang) { + libs += [ "atomic" ] + } + if (is_clang) { # Work around incompatibilities between bionic and clang headers. defines += [ @@ -190,11 +179,6 @@ if (current_cpu != "mipsel" && current_cpu != "mips64el") { ldflags += [ "-Wl,--warn-shared-textrel" ] } - - # Clang with libc++ does not require an explicit atomic library reference. - if (!is_clang) { - libs += [ "atomic" ] - } } config("executable_config") {
diff --git a/build/config/android/config.gni b/build/config/android/config.gni index 2b5bb71..14857a3 100644 --- a/build/config/android/config.gni +++ b/build/config/android/config.gni
@@ -108,9 +108,6 @@ # Adds intrumentation to each function. Writes a file with the order that # functions are called at startup. use_order_profiling = false - - # Use the internal version of the framework to build Android WebView. - use_webview_internal_framework = false } # Host stuff -----------------------------------------------------------------
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni index 0ba7996a..d547796 100644 --- a/build/config/android/rules.gni +++ b/build/config/android/rules.gni
@@ -1738,11 +1738,11 @@ native_libs = _extra_native_libs native_libs_even_when_incremental = _extra_native_libs_even_when_incremental - - # Placeholders necessary for some older devices. - # http://crbug.com/395038 - forward_variables_from(invoker, [ "native_lib_placeholders" ]) } + + # Placeholders necessary for some older devices. + # http://crbug.com/395038 + forward_variables_from(invoker, [ "native_lib_placeholders" ]) } if ((_native_libs != [] || _extra_native_libs_even_when_incremental != []) &&
diff --git a/build/config/arm.gni b/build/config/arm.gni index 9195cfc4..e6ad9b9 100644 --- a/build/config/arm.gni +++ b/build/config/arm.gni
@@ -73,4 +73,7 @@ arm_fpu = "vfpv3-d16" } } +} else if (current_cpu == "arm64") { + # arm64 supports only "hard". + arm_float_abi = "hard" }
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn index 8f827de..d52185a 100644 --- a/build/config/compiler/BUILD.gn +++ b/build/config/compiler/BUILD.gn
@@ -750,11 +750,17 @@ ] if (visual_studio_version == "2015") { - # VC++ 2015 changes 32-bit size_t truncation warnings from 4244 to 4267. - # Example: short TruncTest(size_t x) { return x; } - # Since we already disable 4244 we need to disable 4267 during migration. - # TODO(jschuh): crbug.com/167187 fix size_t to int truncations. - cflags += [ "/wd4267" ] + cflags += [ + # VC++ 2015 changes 32-bit size_t truncation warnings from 4244 to 4267. + # Example: short TruncTest(size_t x) { return x; } + # Since we disable 4244 we need to disable 4267 during migration. + # TODO(jschuh): crbug.com/167187 fix size_t to int truncations. + "/wd4267", + + # C4312 is a VS 2015 64-bit warning for integer to larger pointer. + # TODO(brucedawson): fix warnings, crbug.com/554200 + "/wd4312", + ] } # VS xtree header file needs to be patched or 4702 (unreachable code @@ -830,6 +836,12 @@ if (is_clang) { cflags += [ + # TODO(thakis): Add -Wfor-loop-analysis to -Wall in clang, remove this: + "-Wfor-loop-analysis", + + # TODO(thakis): Consider -Wloop-analysis (turns on + # -Wrange-loop-analysis too). + # This warns on using ints as initializers for floats in # initializer lists (e.g. |int a = f(); CGSize s = { a, a };|), # which happens in several places in chrome code. Not sure if @@ -869,17 +881,6 @@ cflags += [ # TODO(thakis): Enable this, crbug.com/507717 "-Wno-shift-negative-value", - - # TODO(thakis): Consider enabling this? - "-Wno-bitfield-width", - ] - } - - if (is_nacl_nonsfi) { - cflags += [ - # TODO(phosek): Enable after https://codereview.chromium.org/1419373002/ - # is rolled into Chrome. - "-Wno-sign-compare", ] } } @@ -1159,7 +1160,10 @@ if (!using_sanitizer) { cflags += [ "-fomit-frame-pointer" ] } - ldflags = common_optimize_on_ldflags + + # Don't use gc-sections since it can cause links to succeed when they + # actually shouldn't. http://crbug.com/159847 + ldflags = common_optimize_on_ldflags - [ "-Wl,--gc-sections" ] } else { cflags = [ "-O0" ] ldflags = []
diff --git a/build/config/linux/pkg-config.py b/build/config/linux/pkg-config.py index b038158..759d0a8 100644 --- a/build/config/linux/pkg-config.py +++ b/build/config/linux/pkg-config.py
@@ -26,6 +26,15 @@ # When using a sysroot, you must also specify the architecture via # "-a <arch>" where arch is either "x86" or "x64". # +# CrOS systemroots place pkgconfig files at <systemroot>/usr/share/pkgconfig +# and one of <systemroot>/usr/lib/pkgconfig or <systemroot>/usr/lib64/pkgconfig +# depending on whether the systemroot is for a 32 or 64 bit architecture. They +# specify the 'lib' or 'lib64' of the pkgconfig path by defining the +# 'system_libdir' variable in the args.gn file. pkg_config.gni communicates this +# variable to this script with the "--system_libdir <system_libdir>" flag. If no +# flag is provided, then pkgconfig files are assumed to come from +# <systemroot>/usr/lib/pkgconfig. +# # Additionally, you can specify the option --atleast-version. This will skip # the normal outputting of a dictionary and instead print true or false, # depending on the return value of pkg-config for the given package. @@ -44,8 +53,7 @@ options on the given command line.""" sysroot = options.sysroot - if not sysroot: - sysroot = "" + assert sysroot # Compute the library path name based on the architecture. arch = options.arch @@ -53,13 +61,8 @@ print "You must specify an architecture via -a if using a sysroot." sys.exit(1) - # In the gyp world this is configurable via the 'system_libdir' variable, - # which doesn't seem to have an equivelent in gn yet. - # TOOD(sbc): Make this configurable like it is under gyp. - libpath = 'lib' - # Add the sysroot path to the environment's PKG_CONFIG_PATH - config_path = sysroot + '/usr/' + libpath + '/pkgconfig' + config_path = sysroot + '/usr/' + options.system_libdir + '/pkgconfig' config_path += ':' + sysroot + '/usr/share/pkgconfig' if 'PKG_CONFIG_PATH' in os.environ: os.environ['PKG_CONFIG_PATH'] += ':' + config_path @@ -111,6 +114,8 @@ parser.add_option('-v', action='append', dest='strip_out', type='string') parser.add_option('-s', action='store', dest='sysroot', type='string') parser.add_option('-a', action='store', dest='arch', type='string') +parser.add_option('--system_libdir', action='store', dest='system_libdir', + type='string', default='lib') parser.add_option('--atleast-version', action='store', dest='atleast_version', type='string') parser.add_option('--libdir', action='store_true', dest='libdir') @@ -122,8 +127,8 @@ for regexp in options.strip_out: strip_out.append(re.compile(regexp)) -SetConfigPath(options) if options.sysroot: + SetConfigPath(options) prefix = GetPkgConfigPrefixToStrip(args) else: prefix = ''
diff --git a/build/config/linux/pkg_config.gni b/build/config/linux/pkg_config.gni index 914ca8d..58769e2 100644 --- a/build/config/linux/pkg_config.gni +++ b/build/config/linux/pkg_config.gni
@@ -31,6 +31,17 @@ # Leaving it blank defaults to searching PATH for 'pkg-config' and relying on # the sysroot mechanism to find the right .pc files. pkg_config = "" + + # CrOS systemroots place pkgconfig files at <systemroot>/usr/share/pkgconfig + # and one of <systemroot>/usr/lib/pkgconfig or <systemroot>/usr/lib64/pkgconfig + # depending on whether the systemroot is for a 32 or 64 bit architecture. + # + # When build under GYP, CrOS board builds specify the 'system_libdir' variable + # as part of the GYP_DEFINES provided by the CrOS emerge build or simple + # chrome build scheme. This variable permits controlling this for GN builds + # in similar fashion by setting the `system_libdir` variable in the build's + # args.gn file to 'lib' or 'lib64' as appropriate for the target architecture. + system_libdir = "lib" } pkg_config_script = "//build/config/linux/pkg-config.py" @@ -44,11 +55,15 @@ sysroot, "-a", current_cpu, + "--system_libdir", + system_libdir, ] } else if (pkg_config != "") { pkg_config_args = [ "-p", pkg_config, + "--system_libdir", + system_libdir, ] } else { pkg_config_args = []
diff --git a/build/gn_migration.gypi b/build/gn_migration.gypi index 190f2593..1da46bf 100644 --- a/build/gn_migration.gypi +++ b/build/gn_migration.gypi
@@ -193,6 +193,7 @@ '../cc/cc_tests.gyp:cc_perftests_apk', '../cc/cc_tests.gyp:cc_unittests_apk', #"//clank" TODO(GYP) - conditional somehow? + '../components/components.gyp:cronet_package', '../components/components.gyp:cronet_sample_apk', '../components/components.gyp:cronet_sample_test_apk', '../components/components.gyp:cronet_test_apk',
diff --git a/build/secondary/third_party/android_tools/BUILD.gn b/build/secondary/third_party/android_tools/BUILD.gn index fa2f67ab..e256258 100644 --- a/build/secondary/third_party/android_tools/BUILD.gn +++ b/build/secondary/third_party/android_tools/BUILD.gn
@@ -8,6 +8,13 @@ include_dirs = [ "ndk/sources/android/cpufeatures" ] } +config("cpu_features_warnings") { + if (is_clang) { + # cpu-features.c has few unused functions on x86 b/26403333 + cflags = [ "-Wno-unused-function" ] + } +} + # This is the GN version of # //build/android/ndk.gyp:cpu_features source_set("cpu_features") { @@ -17,7 +24,12 @@ public_configs = [ ":cpu_features_include" ] configs -= [ "//build/config/compiler:chromium_code" ] - configs += [ "//build/config/compiler:no_chromium_code" ] + configs += [ + "//build/config/compiler:no_chromium_code", + + # Must be after no_chromium_code for warning flags to be ordered correctly. + ":cpu_features_warnings", + ] } android_java_prebuilt("android_gcm_java") {
diff --git a/build/secondary/third_party/crashpad/OWNERS b/build/secondary/third_party/crashpad/OWNERS new file mode 100644 index 0000000..1e00267 --- /dev/null +++ b/build/secondary/third_party/crashpad/OWNERS
@@ -0,0 +1,3 @@ +mark@chromium.org +rsesek@chromium.org +scottmg@chromium.org
diff --git a/build/secondary/third_party/crashpad/crashpad/handler/BUILD.gn b/build/secondary/third_party/crashpad/crashpad/handler/BUILD.gn index 9ad3464..94269fa 100644 --- a/build/secondary/third_party/crashpad/crashpad/handler/BUILD.gn +++ b/build/secondary/third_party/crashpad/crashpad/handler/BUILD.gn
@@ -12,6 +12,8 @@ "mac/crash_report_exception_handler.h", "mac/exception_handler_server.cc", "mac/exception_handler_server.h", + "prune_crash_reports_thread.cc", + "prune_crash_reports_thread.h", "win/crash_report_exception_handler.cc", "win/crash_report_exception_handler.h", ]
diff --git a/build/secondary/third_party/crashpad/crashpad/util/BUILD.gn b/build/secondary/third_party/crashpad/crashpad/util/BUILD.gn index 6a4094c1..8d95f8df 100644 --- a/build/secondary/third_party/crashpad/crashpad/util/BUILD.gn +++ b/build/secondary/third_party/crashpad/crashpad/util/BUILD.gn
@@ -126,6 +126,8 @@ "thread/thread_log_messages.h", "thread/thread_posix.cc", "thread/thread_win.cc", + "thread/worker_thread.cc", + "thread/worker_thread.h", "win/address_types.h", "win/capture_context.asm", "win/capture_context.h",
diff --git a/cc/base/switches.cc b/cc/base/switches.cc index b906586..9cf6d5c 100644 --- a/cc/base/switches.cc +++ b/cc/base/switches.cc
@@ -41,6 +41,10 @@ // complete, such as --slow-down-raster-scale-factor=25. const char kSlowDownRasterScaleFactor[] = "slow-down-raster-scale-factor"; +// Check that property changes during paint do not occur. +const char kStrictLayerPropertyChangeChecking[] = + "strict-layer-property-change-checking"; + // Ensures that the draw properties computed via the property trees match those // computed by CalcDrawProperties. const char kEnablePropertyTreeVerification[] =
diff --git a/cc/blink/web_external_texture_layer_impl.cc b/cc/blink/web_external_texture_layer_impl.cc index 92414a9..7b180e8 100644 --- a/cc/blink/web_external_texture_layer_impl.cc +++ b/cc/blink/web_external_texture_layer_impl.cc
@@ -73,7 +73,7 @@ bitmap = AllocateBitmap(); if (!client_->prepareMailbox(&client_mailbox, bitmap)) { if (bitmap) - free_bitmaps_.push_back(bitmap); + free_bitmaps_.push_back(make_scoped_ptr(bitmap)); return false; } gpu::Mailbox name; @@ -106,8 +106,8 @@ WebExternalBitmapImpl* WebExternalTextureLayerImpl::AllocateBitmap() { if (!free_bitmaps_.empty()) { - WebExternalBitmapImpl* result = free_bitmaps_.back(); - free_bitmaps_.weak_erase(free_bitmaps_.end() - 1); + WebExternalBitmapImpl* result = free_bitmaps_.back().release(); + free_bitmaps_.pop_back(); return result; } return new WebExternalBitmapImpl; @@ -129,7 +129,7 @@ sizeof(sync_token)); available_mailbox.validSyncToken = sync_token.HasData(); if (bitmap) - layer->free_bitmaps_.push_back(bitmap); + layer->free_bitmaps_.push_back(make_scoped_ptr(bitmap)); layer->client_->mailboxReleased(available_mailbox, lost_resource); }
diff --git a/cc/blink/web_external_texture_layer_impl.h b/cc/blink/web_external_texture_layer_impl.h index d48af64..c85668f 100644 --- a/cc/blink/web_external_texture_layer_impl.h +++ b/cc/blink/web_external_texture_layer_impl.h
@@ -5,10 +5,11 @@ #ifndef CC_BLINK_WEB_EXTERNAL_TEXTURE_LAYER_IMPL_H_ #define CC_BLINK_WEB_EXTERNAL_TEXTURE_LAYER_IMPL_H_ +#include <vector> + #include "base/bind.h" #include "base/macros.h" #include "base/memory/scoped_ptr.h" -#include "base/memory/scoped_vector.h" #include "cc/blink/cc_blink_export.h" #include "cc/layers/texture_layer_client.h" #include "third_party/WebKit/public/platform/WebExternalTextureLayer.h" @@ -64,7 +65,7 @@ blink::WebExternalTextureLayerClient* client_; scoped_ptr<WebLayerImpl> layer_; - ScopedVector<WebExternalBitmapImpl> free_bitmaps_; + std::vector<scoped_ptr<WebExternalBitmapImpl>> free_bitmaps_; DISALLOW_COPY_AND_ASSIGN(WebExternalTextureLayerImpl); };
diff --git a/cc/layers/layer.cc b/cc/layers/layer.cc index 19b8a95..9d82b58 100644 --- a/cc/layers/layer.cc +++ b/cc/layers/layer.cc
@@ -294,7 +294,7 @@ } void Layer::InsertChild(scoped_refptr<Layer> child, size_t index) { - CHECK(IsPropertyChangeAllowed()); + DCHECK(IsPropertyChangeAllowed()); child->RemoveFromParent(); AddDrawableDescendants(child->NumDescendantsThatDrawContent() + (child->DrawsContent() ? 1 : 0)); @@ -307,7 +307,7 @@ } void Layer::RemoveFromParent() { - CHECK(IsPropertyChangeAllowed()); + DCHECK(IsPropertyChangeAllowed()); if (parent_) parent_->RemoveChildOrDependent(this); } @@ -344,7 +344,7 @@ void Layer::ReplaceChild(Layer* reference, scoped_refptr<Layer> new_layer) { DCHECK(reference); DCHECK_EQ(reference->parent(), this); - CHECK(IsPropertyChangeAllowed()); + DCHECK(IsPropertyChangeAllowed()); if (reference == new_layer.get()) return; @@ -366,7 +366,7 @@ } void Layer::SetBounds(const gfx::Size& size) { - CHECK(IsPropertyChangeAllowed()); + DCHECK(IsPropertyChangeAllowed()); if (bounds() == size) return; bounds_ = size; @@ -393,7 +393,7 @@ } void Layer::RemoveAllChildren() { - CHECK(IsPropertyChangeAllowed()); + DCHECK(IsPropertyChangeAllowed()); while (children_.size()) { Layer* layer = children_[0].get(); DCHECK_EQ(this, layer->parent()); @@ -402,7 +402,7 @@ } void Layer::SetChildren(const LayerList& children) { - CHECK(IsPropertyChangeAllowed()); + DCHECK(IsPropertyChangeAllowed()); if (children == children_) return; @@ -421,7 +421,7 @@ void Layer::RequestCopyOfOutput( scoped_ptr<CopyOutputRequest> request) { - CHECK(IsPropertyChangeAllowed()); + DCHECK(IsPropertyChangeAllowed()); bool had_no_copy_requests = copy_requests_.empty(); if (void* source = request->source()) { auto it = std::find_if(copy_requests_.begin(), copy_requests_.end(), @@ -451,7 +451,7 @@ } void Layer::SetBackgroundColor(SkColor background_color) { - CHECK(IsPropertyChangeAllowed()); + DCHECK(IsPropertyChangeAllowed()); if (background_color_ == background_color) return; background_color_ = background_color; @@ -478,7 +478,7 @@ } void Layer::SetMasksToBounds(bool masks_to_bounds) { - CHECK(IsPropertyChangeAllowed()); + DCHECK(IsPropertyChangeAllowed()); if (masks_to_bounds_ == masks_to_bounds) return; masks_to_bounds_ = masks_to_bounds; @@ -486,7 +486,7 @@ } void Layer::SetMaskLayer(Layer* mask_layer) { - CHECK(IsPropertyChangeAllowed()); + DCHECK(IsPropertyChangeAllowed()); if (mask_layer_.get() == mask_layer) return; if (mask_layer_.get()) { @@ -504,7 +504,7 @@ } void Layer::SetReplicaLayer(Layer* layer) { - CHECK(IsPropertyChangeAllowed()); + DCHECK(IsPropertyChangeAllowed()); if (replica_layer_.get() == layer) return; if (replica_layer_.get()) { @@ -521,7 +521,7 @@ } void Layer::SetFilters(const FilterOperations& filters) { - CHECK(IsPropertyChangeAllowed()); + DCHECK(IsPropertyChangeAllowed()); if (filters_ == filters) return; filters_ = filters; @@ -546,7 +546,7 @@ } void Layer::SetBackgroundFilters(const FilterOperations& filters) { - CHECK(IsPropertyChangeAllowed()); + DCHECK(IsPropertyChangeAllowed()); if (background_filters_ == filters) return; background_filters_ = filters; @@ -554,7 +554,7 @@ } void Layer::SetOpacity(float opacity) { - CHECK(IsPropertyChangeAllowed()); + DCHECK(IsPropertyChangeAllowed()); if (opacity_ == opacity) return; opacity_ = opacity; @@ -583,7 +583,7 @@ } void Layer::SetBlendMode(SkXfermode::Mode blend_mode) { - CHECK(IsPropertyChangeAllowed()); + DCHECK(IsPropertyChangeAllowed()); if (blend_mode_ == blend_mode) return; @@ -632,7 +632,7 @@ } void Layer::SetIsRootForIsolatedGroup(bool root) { - CHECK(IsPropertyChangeAllowed()); + DCHECK(IsPropertyChangeAllowed()); if (is_root_for_isolated_group_ == root) return; is_root_for_isolated_group_ = root; @@ -640,7 +640,7 @@ } void Layer::SetContentsOpaque(bool opaque) { - CHECK(IsPropertyChangeAllowed()); + DCHECK(IsPropertyChangeAllowed()); if (contents_opaque_ == opaque) return; contents_opaque_ = opaque; @@ -648,7 +648,7 @@ } void Layer::SetPosition(const gfx::PointF& position) { - CHECK(IsPropertyChangeAllowed()); + DCHECK(IsPropertyChangeAllowed()); if (position_ == position) return; position_ = position; @@ -696,7 +696,7 @@ } void Layer::SetTransform(const gfx::Transform& transform) { - CHECK(IsPropertyChangeAllowed()); + DCHECK(IsPropertyChangeAllowed()); if (transform_ == transform) return; @@ -733,7 +733,7 @@ } void Layer::SetTransformOrigin(const gfx::Point3F& transform_origin) { - CHECK(IsPropertyChangeAllowed()); + DCHECK(IsPropertyChangeAllowed()); if (transform_origin_ == transform_origin) return; transform_origin_ = transform_origin; @@ -823,7 +823,7 @@ } void Layer::SetScrollParent(Layer* parent) { - CHECK(IsPropertyChangeAllowed()); + DCHECK(IsPropertyChangeAllowed()); if (scroll_parent_ == parent) return; @@ -853,7 +853,7 @@ } void Layer::SetClipParent(Layer* ancestor) { - CHECK(IsPropertyChangeAllowed()); + DCHECK(IsPropertyChangeAllowed()); if (clip_parent_ == ancestor) return; @@ -885,7 +885,7 @@ } void Layer::SetScrollOffset(const gfx::ScrollOffset& scroll_offset) { - CHECK(IsPropertyChangeAllowed()); + DCHECK(IsPropertyChangeAllowed()); if (scroll_offset_ == scroll_offset) return; @@ -923,7 +923,7 @@ void Layer::SetScrollOffsetFromImplSide( const gfx::ScrollOffset& scroll_offset) { - CHECK(IsPropertyChangeAllowed()); + DCHECK(IsPropertyChangeAllowed()); // This function only gets called during a BeginMainFrame, so there // is no need to call SetNeedsUpdate here. DCHECK(layer_tree_host_ && layer_tree_host_->CommitRequested()); @@ -954,7 +954,7 @@ } void Layer::SetScrollClipLayerId(int clip_layer_id) { - CHECK(IsPropertyChangeAllowed()); + DCHECK(IsPropertyChangeAllowed()); if (scroll_clip_layer_id_ == clip_layer_id) return; scroll_clip_layer_id_ = clip_layer_id; @@ -962,7 +962,7 @@ } void Layer::SetUserScrollable(bool horizontal, bool vertical) { - CHECK(IsPropertyChangeAllowed()); + DCHECK(IsPropertyChangeAllowed()); if (user_scrollable_horizontal_ == horizontal && user_scrollable_vertical_ == vertical) return; @@ -972,7 +972,7 @@ } void Layer::SetShouldScrollOnMainThread(bool should_scroll_on_main_thread) { - CHECK(IsPropertyChangeAllowed()); + DCHECK(IsPropertyChangeAllowed()); if (should_scroll_on_main_thread_ == should_scroll_on_main_thread) return; should_scroll_on_main_thread_ = should_scroll_on_main_thread; @@ -980,7 +980,7 @@ } void Layer::SetHaveWheelEventHandlers(bool have_wheel_event_handlers) { - CHECK(IsPropertyChangeAllowed()); + DCHECK(IsPropertyChangeAllowed()); if (have_wheel_event_handlers_ == have_wheel_event_handlers) return; @@ -989,7 +989,7 @@ } void Layer::SetHaveScrollEventHandlers(bool have_scroll_event_handlers) { - CHECK(IsPropertyChangeAllowed()); + DCHECK(IsPropertyChangeAllowed()); if (have_scroll_event_handlers_ == have_scroll_event_handlers) return; have_scroll_event_handlers_ = have_scroll_event_handlers; @@ -997,7 +997,7 @@ } void Layer::SetNonFastScrollableRegion(const Region& region) { - CHECK(IsPropertyChangeAllowed()); + DCHECK(IsPropertyChangeAllowed()); if (non_fast_scrollable_region_ == region) return; non_fast_scrollable_region_ = region; @@ -1005,7 +1005,7 @@ } void Layer::SetTouchEventHandlerRegion(const Region& region) { - CHECK(IsPropertyChangeAllowed()); + DCHECK(IsPropertyChangeAllowed()); if (touch_event_handler_region_ == region) return; @@ -1014,7 +1014,7 @@ } void Layer::SetScrollBlocksOn(ScrollBlocksOn scroll_blocks_on) { - CHECK(IsPropertyChangeAllowed()); + DCHECK(IsPropertyChangeAllowed()); if (scroll_blocks_on_ == scroll_blocks_on) return; scroll_blocks_on_ = scroll_blocks_on; @@ -1022,7 +1022,7 @@ } void Layer::SetForceRenderSurface(bool force) { - CHECK(IsPropertyChangeAllowed()); + DCHECK(IsPropertyChangeAllowed()); if (force_render_surface_ == force) return; force_render_surface_ = force; @@ -1030,7 +1030,7 @@ } void Layer::SetDoubleSided(bool double_sided) { - CHECK(IsPropertyChangeAllowed()); + DCHECK(IsPropertyChangeAllowed()); if (double_sided_ == double_sided) return; double_sided_ = double_sided; @@ -1038,7 +1038,7 @@ } void Layer::Set3dSortingContextId(int id) { - CHECK(IsPropertyChangeAllowed()); + DCHECK(IsPropertyChangeAllowed()); if (id == sorting_context_id_) return; sorting_context_id_ = id; @@ -1046,7 +1046,7 @@ } void Layer::SetTransformTreeIndex(int index) { - CHECK(IsPropertyChangeAllowed()); + DCHECK(IsPropertyChangeAllowed()); if (transform_tree_index_ == index) return; transform_tree_index_ = index; @@ -1063,7 +1063,7 @@ } void Layer::SetClipTreeIndex(int index) { - CHECK(IsPropertyChangeAllowed()); + DCHECK(IsPropertyChangeAllowed()); if (clip_tree_index_ == index) return; clip_tree_index_ = index; @@ -1080,7 +1080,7 @@ } void Layer::SetEffectTreeIndex(int index) { - CHECK(IsPropertyChangeAllowed()); + DCHECK(IsPropertyChangeAllowed()); if (effect_tree_index_ == index) return; effect_tree_index_ = index; @@ -1104,7 +1104,7 @@ } void Layer::SetShouldFlattenTransform(bool should_flatten) { - CHECK(IsPropertyChangeAllowed()); + DCHECK(IsPropertyChangeAllowed()); if (should_flatten_transform_ == should_flatten) return; should_flatten_transform_ = should_flatten; @@ -1112,7 +1112,7 @@ } void Layer::SetIsDrawable(bool is_drawable) { - CHECK(IsPropertyChangeAllowed()); + DCHECK(IsPropertyChangeAllowed()); if (is_drawable_ == is_drawable) return; @@ -1121,7 +1121,7 @@ } void Layer::SetHideLayerAndSubtree(bool hide) { - CHECK(IsPropertyChangeAllowed()); + DCHECK(IsPropertyChangeAllowed()); if (hide_layer_and_subtree_ == hide) return; @@ -1163,7 +1163,7 @@ } void Layer::SetPositionConstraint(const LayerPositionConstraint& constraint) { - CHECK(IsPropertyChangeAllowed()); + DCHECK(IsPropertyChangeAllowed()); if (position_constraint_ == constraint) return; position_constraint_ = constraint; @@ -1974,7 +1974,7 @@ } void Layer::SetElementId(uint64_t id) { - CHECK(IsPropertyChangeAllowed()); + DCHECK(IsPropertyChangeAllowed()); if (element_id_ == id) return; TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("compositor-worker"), @@ -1984,7 +1984,7 @@ } void Layer::SetMutableProperties(uint32_t properties) { - CHECK(IsPropertyChangeAllowed()); + DCHECK(IsPropertyChangeAllowed()); if (mutable_properties_ == properties) return; TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("compositor-worker"),
diff --git a/cc/layers/layer_settings.cc b/cc/layers/layer_settings.cc index a608bdb..d2eac382 100644 --- a/cc/layers/layer_settings.cc +++ b/cc/layers/layer_settings.cc
@@ -6,7 +6,7 @@ namespace cc { -LayerSettings::LayerSettings() : use_compositor_animation_timelines(false) {} +LayerSettings::LayerSettings() : use_compositor_animation_timelines(true) {} LayerSettings::~LayerSettings() {}
diff --git a/cc/layers/layer_unittest.cc b/cc/layers/layer_unittest.cc index a9caa02..bea4393 100644 --- a/cc/layers/layer_unittest.cc +++ b/cc/layers/layer_unittest.cc
@@ -7,6 +7,8 @@ #include <stddef.h> #include "base/thread_task_runner_handle.h" +#include "cc/animation/animation_host.h" +#include "cc/animation/animation_id_provider.h" #include "cc/animation/keyframed_animation_curve.h" #include "cc/animation/mutable_properties.h" #include "cc/base/math_util.h" @@ -382,20 +384,37 @@ MOCK_METHOD0(SetNeedsFullTreeSync, void()); }; +class LayerTreeSettingsForLayerTest : public LayerTreeSettings { + public: + LayerTreeSettingsForLayerTest() { use_compositor_animation_timelines = true; } +}; + class LayerTest : public testing::Test { public: LayerTest() - : host_impl_(&task_runner_provider_, + : host_impl_(LayerTreeSettingsForLayerTest(), + &task_runner_provider_, &shared_bitmap_manager_, &task_graph_runner_), - fake_client_(FakeLayerTreeHostClient::DIRECT_3D) {} + fake_client_(FakeLayerTreeHostClient::DIRECT_3D) { + layer_settings_.use_compositor_animation_timelines = + settings().use_compositor_animation_timelines; + if (settings().use_compositor_animation_timelines) { + timeline_impl_ = + AnimationTimeline::Create(AnimationIdProvider::NextTimelineId()); + timeline_impl_->set_is_impl_only(true); + host_impl_.animation_host()->AddAnimationTimeline(timeline_impl_); + } + } + + const LayerTreeSettings& settings() { return settings_; } + scoped_refptr<AnimationTimeline> timeline_impl() { return timeline_impl_; } protected: void SetUp() override { LayerTreeHost::InitParams params; - LayerTreeSettings settings; params.client = &fake_client_; - params.settings = &settings; + params.settings = &settings_; params.task_graph_runner = &task_graph_runner_; layer_tree_host_.reset( new StrictMock<MockLayerTreeHost>(&fake_client_, ¶ms)); @@ -477,6 +496,9 @@ scoped_refptr<Layer> grand_child2_; scoped_refptr<Layer> grand_child3_; + scoped_refptr<AnimationTimeline> timeline_impl_; + + LayerTreeSettingsForLayerTest settings_; LayerSettings layer_settings_; }; @@ -1051,14 +1073,18 @@ EXPECT_SET_NEEDS_FULL_TREE_SYNC(1, layer_tree_host_->SetRootLayer(test_layer)); - scoped_ptr<AnimationRegistrar> registrar = AnimationRegistrar::Create(); - impl_layer->layer_animation_controller()->SetAnimationRegistrar( - registrar.get()); + scoped_ptr<AnimationRegistrar> registrar; + if (settings().use_compositor_animation_timelines) { + AddAnimatedTransformToLayerWithPlayer(impl_layer->id(), timeline_impl(), + 1.0, 0, 100); + } else { + registrar = AnimationRegistrar::Create(); + impl_layer->layer_animation_controller()->SetAnimationRegistrar( + registrar.get()); - AddAnimatedTransformToController(impl_layer->layer_animation_controller(), - 1.0, - 0, - 100); + AddAnimatedTransformToController(impl_layer->layer_animation_controller(), + 1.0, 0, 100); + } gfx::Transform transform; transform.Rotate(45.0); @@ -1069,13 +1095,19 @@ EXPECT_TRUE(impl_layer->LayerPropertyChanged()); impl_layer->ResetAllChangeTrackingForSubtree(); - AddAnimatedTransformToController(impl_layer->layer_animation_controller(), - 1.0, - 0, - 100); - impl_layer->layer_animation_controller() - ->GetAnimation(Animation::TRANSFORM) - ->set_is_impl_only(true); + if (settings().use_compositor_animation_timelines) { + int animation_id = AddAnimatedTransformToLayerWithPlayer( + impl_layer->id(), timeline_impl(), 1.0, 0, 100); + GetAnimationFromLayerWithExistingPlayer(impl_layer->id(), timeline_impl(), + animation_id) + ->set_is_impl_only(true); + } else { + AddAnimatedTransformToController(impl_layer->layer_animation_controller(), + 1.0, 0, 100); + impl_layer->layer_animation_controller() + ->GetAnimation(Animation::TRANSFORM) + ->set_is_impl_only(true); + } transform.Rotate(45.0); EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetTransform(transform)); @@ -1093,15 +1125,18 @@ EXPECT_SET_NEEDS_FULL_TREE_SYNC(1, layer_tree_host_->SetRootLayer(test_layer)); - scoped_ptr<AnimationRegistrar> registrar = AnimationRegistrar::Create(); - impl_layer->layer_animation_controller()->SetAnimationRegistrar( - registrar.get()); + scoped_ptr<AnimationRegistrar> registrar; + if (settings().use_compositor_animation_timelines) { + AddOpacityTransitionToLayerWithPlayer(impl_layer->id(), timeline_impl(), + 1.0, 0.3f, 0.7f, false); + } else { + registrar = AnimationRegistrar::Create(); + impl_layer->layer_animation_controller()->SetAnimationRegistrar( + registrar.get()); - AddOpacityTransitionToController(impl_layer->layer_animation_controller(), - 1.0, - 0.3f, - 0.7f, - false); + AddOpacityTransitionToController(impl_layer->layer_animation_controller(), + 1.0, 0.3f, 0.7f, false); + } EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetOpacity(0.5f)); @@ -1110,14 +1145,19 @@ EXPECT_TRUE(impl_layer->LayerPropertyChanged()); impl_layer->ResetAllChangeTrackingForSubtree(); - AddOpacityTransitionToController(impl_layer->layer_animation_controller(), - 1.0, - 0.3f, - 0.7f, - false); - impl_layer->layer_animation_controller() - ->GetAnimation(Animation::OPACITY) - ->set_is_impl_only(true); + if (settings().use_compositor_animation_timelines) { + int animation_id = AddOpacityTransitionToLayerWithPlayer( + impl_layer->id(), timeline_impl(), 1.0, 0.3f, 0.7f, false); + GetAnimationFromLayerWithExistingPlayer(impl_layer->id(), timeline_impl(), + animation_id) + ->set_is_impl_only(true); + } else { + AddOpacityTransitionToController(impl_layer->layer_animation_controller(), + 1.0, 0.3f, 0.7f, false); + impl_layer->layer_animation_controller() + ->GetAnimation(Animation::OPACITY) + ->set_is_impl_only(true); + } EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetOpacity(0.75f)); EXPECT_FALSE(impl_layer->LayerPropertyChanged()); @@ -1134,12 +1174,18 @@ EXPECT_SET_NEEDS_FULL_TREE_SYNC(1, layer_tree_host_->SetRootLayer(test_layer)); - scoped_ptr<AnimationRegistrar> registrar = AnimationRegistrar::Create(); - impl_layer->layer_animation_controller()->SetAnimationRegistrar( - registrar.get()); + scoped_ptr<AnimationRegistrar> registrar; + if (settings().use_compositor_animation_timelines) { + AddAnimatedFilterToLayerWithPlayer(impl_layer->id(), timeline_impl(), 1.0, + 1.f, 2.f); + } else { + registrar = AnimationRegistrar::Create(); + impl_layer->layer_animation_controller()->SetAnimationRegistrar( + registrar.get()); - AddAnimatedFilterToController( - impl_layer->layer_animation_controller(), 1.0, 1.f, 2.f); + AddAnimatedFilterToController(impl_layer->layer_animation_controller(), 1.0, + 1.f, 2.f); + } FilterOperations filters; filters.Append(FilterOperation::CreateBlurFilter(2.f)); @@ -1150,11 +1196,19 @@ EXPECT_TRUE(impl_layer->LayerPropertyChanged()); impl_layer->ResetAllChangeTrackingForSubtree(); - AddAnimatedFilterToController( - impl_layer->layer_animation_controller(), 1.0, 1.f, 2.f); - impl_layer->layer_animation_controller() - ->GetAnimation(Animation::FILTER) - ->set_is_impl_only(true); + if (settings().use_compositor_animation_timelines) { + int animation_id = AddAnimatedFilterToLayerWithPlayer( + impl_layer->id(), timeline_impl(), 1.0, 1.f, 2.f); + GetAnimationFromLayerWithExistingPlayer(impl_layer->id(), timeline_impl(), + animation_id) + ->set_is_impl_only(true); + } else { + AddAnimatedFilterToController(impl_layer->layer_animation_controller(), 1.0, + 1.f, 2.f); + impl_layer->layer_animation_controller() + ->GetAnimation(Animation::FILTER) + ->set_is_impl_only(true); + } filters.Append(FilterOperation::CreateSepiaFilter(0.5f)); EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetFilters(filters)); @@ -1301,6 +1355,10 @@ class LayerLayerTreeHostTest : public testing::Test { public: + LayerLayerTreeHostTest() { + layer_settings_.use_compositor_animation_timelines = true; + } + protected: LayerSettings layer_settings_; }; @@ -1488,6 +1546,10 @@ } TEST_F(LayerLayerTreeHostTest, ShouldNotAddAnimationWithoutAnimationRegistrar) { + // This tests isn't needed in new use_compositor_animation_timelines mode. + if (layer_settings_.use_compositor_animation_timelines) + return; + scoped_refptr<Layer> layer = Layer::Create(layer_settings_); // Case 1: without a LayerTreeHost and without an AnimationRegistrar, the @@ -1502,6 +1564,8 @@ LayerTreeSettings settings; settings.accelerated_animation_enabled = false; + settings.use_compositor_animation_timelines = + layer_settings_.use_compositor_animation_timelines; LayerTreeHostFactory factory; scoped_ptr<LayerTreeHost> layer_tree_host = factory.Create(settings); layer_tree_host->SetRootLayer(layer);
diff --git a/cc/layers/render_surface_impl.cc b/cc/layers/render_surface_impl.cc index d329667..600206f 100644 --- a/cc/layers/render_surface_impl.cc +++ b/cc/layers/render_surface_impl.cc
@@ -243,7 +243,7 @@ content_rect_.height() / unclipped_mask_target_size.height()); } - DCHECK(owning_layer_->draw_properties().target_space_transform.IsScale2d()); + DCHECK(owning_layer_draw_transform.IsScale2d()); gfx::Vector2dF owning_layer_to_target_scale = owning_layer_draw_transform.Scale2d();
diff --git a/cc/raster/one_copy_tile_task_worker_pool.cc b/cc/raster/one_copy_tile_task_worker_pool.cc index 9ca1ae3..ea1b947 100644 --- a/cc/raster/one_copy_tile_task_worker_pool.cc +++ b/cc/raster/one_copy_tile_task_worker_pool.cc
@@ -444,10 +444,9 @@ int rows_to_copy = std::min(chunk_size_in_rows, height - y); DCHECK_GT(rows_to_copy, 0); - gl->CopySubTextureCHROMIUM(GL_TEXTURE_2D, staging_buffer->texture_id, - resource_lock->texture_id(), 0, y, 0, y, - resource->size().width(), rows_to_copy, false, - false, false); + gl->CopySubTextureCHROMIUM( + staging_buffer->texture_id, resource_lock->texture_id(), 0, y, 0, y, + resource->size().width(), rows_to_copy, false, false, false); y += rows_to_copy; // Increment |bytes_scheduled_since_last_flush_| by the amount of memory
diff --git a/cc/resources/resource_provider.cc b/cc/resources/resource_provider.cc index c6e5c91..f1a4cf2e 100644 --- a/cc/resources/resource_provider.cc +++ b/cc/resources/resource_provider.cc
@@ -1140,6 +1140,9 @@ DCHECK(thread_checker_.CalledOnValidThread()); GLES2Interface* gl = ContextGL(); bool need_sync_token = false; + + gpu::SyncToken new_sync_token; + std::vector<GLbyte*> unverified_sync_tokens; for (ResourceIdArray::const_iterator it = resources.begin(); it != resources.end(); ++it) { @@ -1147,17 +1150,36 @@ TransferResource(gl, *it, &resource); need_sync_token |= (!resource.mailbox_holder.sync_token.HasData() && !resource.is_software); + + if (resource.mailbox_holder.sync_token.HasData() && + !resource.mailbox_holder.sync_token.verified_flush()) { + unverified_sync_tokens.push_back( + resource.mailbox_holder.sync_token.GetData()); + } + ++resources_.find(*it)->second.exported_count; list->push_back(resource); } + if (need_sync_token && output_surface_->capabilities().delegated_sync_points_required) { - gpu::SyncToken sync_token(gl->InsertSyncPointCHROMIUM()); + const uint64_t fence_sync = gl->InsertFenceSyncCHROMIUM(); + gl->OrderingBarrierCHROMIUM(); + gl->GenUnverifiedSyncTokenCHROMIUM(fence_sync, new_sync_token.GetData()); + unverified_sync_tokens.push_back(new_sync_token.GetData()); + } + + if (!unverified_sync_tokens.empty()) { + gl->VerifySyncTokensCHROMIUM(unverified_sync_tokens.data(), + unverified_sync_tokens.size()); + } + + if (new_sync_token.HasData()) { for (TransferableResourceArray::iterator it = list->begin(); it != list->end(); ++it) { if (!it->mailbox_holder.sync_token.HasData()) - it->mailbox_holder.sync_token = sync_token; + it->mailbox_holder.sync_token = new_sync_token; } } }
diff --git a/cc/resources/resource_provider_unittest.cc b/cc/resources/resource_provider_unittest.cc index 3374e85..1a0e685 100644 --- a/cc/resources/resource_provider_unittest.cc +++ b/cc/resources/resource_provider_unittest.cc
@@ -39,7 +39,6 @@ using testing::Mock; using testing::NiceMock; using testing::Return; -using testing::SetArgPointee; using testing::StrictMock; using testing::_; @@ -104,7 +103,6 @@ MOCK_METHOD2(bindTexture, void(GLenum target, GLuint texture)); MOCK_METHOD3(texParameteri, void(GLenum target, GLenum pname, GLint param)); MOCK_METHOD1(waitSyncToken, void(const GLbyte* sync_token)); - MOCK_METHOD0(insertSyncPoint, GLuint(void)); MOCK_METHOD3(produceTextureDirectCHROMIUM, void(GLuint texture, GLenum target, const GLbyte* mailbox)); MOCK_METHOD2(createAndConsumeTextureCHROMIUM, @@ -116,7 +114,21 @@ base::AutoLock lock(namespace_->lock); return namespace_->next_texture_id++; } + void RetireTextureId(GLuint) override {} + + GLuint64 insertFenceSync() override { return next_fence_sync_++; } + + void genSyncToken(GLuint64 fence_sync, GLbyte* sync_token) override { + gpu::SyncToken sync_token_data(gpu::CommandBufferNamespace::GPU_IO, 0, + 0x123, fence_sync); + sync_token_data.SetVerifyFlush(); + memcpy(sync_token, &sync_token_data, sizeof(sync_token_data)); + } + + GLuint64 GetNextFenceSync() const { return next_fence_sync_; } + + GLuint64 next_fence_sync_ = 1; }; // Shared data between multiple ResourceProviderContext. This contains mailbox @@ -127,7 +139,7 @@ return make_scoped_ptr(new ContextSharedData()); } - uint32_t InsertSyncPoint() { return next_sync_point_++; } + uint32_t InsertFenceSync() { return next_fence_sync_++; } void GenMailbox(GLbyte* mailbox) { memset(mailbox, 0, GL_MAILBOX_SIZE_CHROMIUM); @@ -165,9 +177,9 @@ } private: - ContextSharedData() : next_sync_point_(1), next_mailbox_(1) {} + ContextSharedData() : next_fence_sync_(1), next_mailbox_(1) {} - uint32_t next_sync_point_; + uint64_t next_fence_sync_; unsigned next_mailbox_; typedef base::hash_map<unsigned, scoped_refptr<TestTexture>> TextureMap; TextureMap textures_; @@ -182,19 +194,40 @@ } GLuint insertSyncPoint() override { - uint32_t sync_point = shared_data_->InsertSyncPoint(); + const uint32_t sync_point = + static_cast<uint32_t>(shared_data_->InsertFenceSync()); + gpu::SyncToken sync_token_data(sync_point); + // Commit the produceTextureCHROMIUM calls at this point, so that // they're associated with the sync point. for (const scoped_ptr<PendingProduceTexture>& pending_texture : pending_produce_textures_) { - shared_data_->ProduceTexture(pending_texture->mailbox, - gpu::SyncToken(sync_point), + shared_data_->ProduceTexture(pending_texture->mailbox, sync_token_data, pending_texture->texture); } pending_produce_textures_.clear(); return sync_point; } + GLuint64 insertFenceSync() override { + return shared_data_->InsertFenceSync(); + } + + void genSyncToken(GLuint64 fence_sync, GLbyte* sync_token) override { + gpu::SyncToken sync_token_data(gpu::CommandBufferNamespace::GPU_IO, 0, + 0x123, fence_sync); + sync_token_data.SetVerifyFlush(); + // Commit the produceTextureCHROMIUM calls at this point, so that + // they're associated with the sync point. + for (const scoped_ptr<PendingProduceTexture>& pending_texture : + pending_produce_textures_) { + shared_data_->ProduceTexture(pending_texture->mailbox, sync_token_data, + pending_texture->texture); + } + pending_produce_textures_.clear(); + memcpy(sync_token, &sync_token_data, sizeof(sync_token_data)); + } + void waitSyncToken(const GLbyte* sync_token) override { gpu::SyncToken sync_token_data; if (sync_token) @@ -280,7 +313,7 @@ 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 + // sync token, 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)); @@ -477,7 +510,8 @@ child_context_->genMailboxCHROMIUM(gpu_mailbox.name); child_context_->produceTextureDirectCHROMIUM(texture, GL_TEXTURE_2D, gpu_mailbox.name); - *sync_token = gpu::SyncToken(child_context_->insertSyncPoint()); + child_context_->genSyncToken(child_context_->insertFenceSync(), + sync_token->GetData()); EXPECT_TRUE(sync_token->HasData()); scoped_ptr<SharedBitmap> shared_bitmap; @@ -633,7 +667,10 @@ child_context_->genMailboxCHROMIUM(external_mailbox.name); child_context_->produceTextureDirectCHROMIUM( external_texture_id, GL_TEXTURE_EXTERNAL_OES, external_mailbox.name); - const gpu::SyncToken external_sync_token(child_context_->insertSyncPoint()); + gpu::SyncToken external_sync_token; + child_context_->genSyncToken(child_context_->insertFenceSync(), + external_sync_token.GetData()); + EXPECT_TRUE(external_sync_token.HasData()); ResourceId id4 = child_resource_provider_->CreateResourceFromTextureMailbox( TextureMailbox(external_mailbox, external_sync_token, GL_TEXTURE_EXTERNAL_OES), @@ -889,7 +926,10 @@ child_context_->genMailboxCHROMIUM(external_mailbox.name); child_context_->produceTextureDirectCHROMIUM( external_texture_id, GL_TEXTURE_EXTERNAL_OES, external_mailbox.name); - const gpu::SyncToken external_sync_token(child_context_->insertSyncPoint()); + gpu::SyncToken external_sync_token; + child_context_->genSyncToken(child_context_->insertFenceSync(), + external_sync_token.GetData()); + EXPECT_TRUE(external_sync_token.HasData()); ResourceId id3 = child_resource_provider_->CreateResourceFromTextureMailbox( TextureMailbox(external_mailbox, external_sync_token, GL_TEXTURE_EXTERNAL_OES), @@ -1961,7 +2001,6 @@ EXPECT_CALL(*child_context, produceTextureDirectCHROMIUM(_, GL_TEXTURE_2D, _)); - EXPECT_CALL(*child_context, insertSyncPoint()); child_resource_provider->PrepareSendToParent(resource_ids_to_transfer, &list); Mock::VerifyAndClearExpectations(child_context); @@ -2019,7 +2058,6 @@ // Transfer resources back from the parent to the child. Set no resources // as being in use. ResourceProvider::ResourceIdSet no_resources; - EXPECT_CALL(*parent_context, insertSyncPoint()); parent_resource_provider->DeclareUsedResourcesFromChild(child_id, no_resources); Mock::VerifyAndClearExpectations(parent_context); @@ -2059,7 +2097,9 @@ gpu::Mailbox mailbox; context()->genMailboxCHROMIUM(mailbox.name); context()->produceTextureDirectCHROMIUM(texture, GL_TEXTURE_2D, mailbox.name); - gpu::SyncToken sync_token(context()->insertSyncPoint()); + gpu::SyncToken sync_token; + context()->genSyncToken(context()->insertFenceSync(), sync_token.GetData()); + EXPECT_TRUE(sync_token.HasData()); // All the logic below assumes that the sync token releases are all positive. EXPECT_LT(0u, sync_token.release_count()); @@ -2101,8 +2141,9 @@ context()->produceTextureDirectCHROMIUM(other_texture, GL_TEXTURE_2D, mailbox.name); context()->deleteTexture(other_texture); - list[0].mailbox_holder.sync_token = - gpu::SyncToken(context()->insertSyncPoint()); + context()->genSyncToken(context()->insertFenceSync(), + list[0].mailbox_holder.sync_token.GetData()); + EXPECT_TRUE(list[0].mailbox_holder.sync_token.HasData()); // Receive the resource, then delete it, expect the sync points to be // consistent. @@ -2155,9 +2196,9 @@ context()->produceTextureDirectCHROMIUM(other_texture, GL_TEXTURE_2D, mailbox.name); context()->deleteTexture(other_texture); - list[0].mailbox_holder.sync_token = - gpu::SyncToken(context()->insertSyncPoint()); - EXPECT_LT(0u, list[0].mailbox_holder.sync_token.release_count()); + context()->genSyncToken(context()->insertFenceSync(), + list[0].mailbox_holder.sync_token.GetData()); + EXPECT_TRUE(list[0].mailbox_holder.sync_token.HasData()); // Delete the resource, which shouldn't do anything. resource_provider_->DeleteResource(resource); @@ -2490,7 +2531,8 @@ gpu::Mailbox mailbox; context()->genMailboxCHROMIUM(mailbox.name); context()->produceTextureDirectCHROMIUM(texture, GL_TEXTURE_2D, mailbox.name); - gpu::SyncToken sync_token(context()->insertSyncPoint()); + gpu::SyncToken sync_token; + context()->genSyncToken(context()->insertFenceSync(), sync_token.GetData()); EXPECT_TRUE(sync_token.HasData()); @@ -2810,12 +2852,13 @@ use_image_texture_targets_)); unsigned texture_id = 1; - gpu::SyncToken sync_token(30); + gpu::SyncToken sync_token(gpu::CommandBufferNamespace::GPU_IO, 0, 0x12, + 0x34); unsigned target = GL_TEXTURE_2D; + const GLuint64 current_fence_sync = context->GetNextFenceSync(); EXPECT_CALL(*context, bindTexture(_, _)).Times(0); EXPECT_CALL(*context, waitSyncToken(_)).Times(0); - EXPECT_CALL(*context, insertSyncPoint()).Times(0); EXPECT_CALL(*context, produceTextureDirectCHROMIUM(_, _, _)).Times(0); EXPECT_CALL(*context, createAndConsumeTextureCHROMIUM(_, _)).Times(0); @@ -2835,6 +2878,7 @@ ResourceId id = resource_provider->CreateResourceFromTextureMailbox( mailbox, std::move(callback)); EXPECT_NE(0u, id); + EXPECT_EQ(current_fence_sync, context->GetNextFenceSync()); Mock::VerifyAndClearExpectations(context); @@ -2848,7 +2892,6 @@ .WillOnce(Return(texture_id)); EXPECT_CALL(*context, bindTexture(target, texture_id)); - EXPECT_CALL(*context, insertSyncPoint()).Times(0); EXPECT_CALL(*context, produceTextureDirectCHROMIUM(_, _, _)).Times(0); // The sampler will reset these if |mailbox_nearest_neighbor| does not @@ -2863,11 +2906,11 @@ ResourceProvider::ScopedSamplerGL lock( resource_provider.get(), id, sampler_filter); Mock::VerifyAndClearExpectations(context); + EXPECT_EQ(current_fence_sync, context->GetNextFenceSync()); // When done with it, a sync point should be inserted, but no produce is // necessary. EXPECT_CALL(*context, bindTexture(_, _)).Times(0); - EXPECT_CALL(*context, insertSyncPoint()); EXPECT_CALL(*context, produceTextureDirectCHROMIUM(_, _, _)).Times(0); EXPECT_CALL(*context, waitSyncToken(_)).Times(0); @@ -2875,7 +2918,7 @@ } resource_provider->DeleteResource(id); - EXPECT_FALSE(release_sync_token.HasData()); + EXPECT_TRUE(release_sync_token.HasData()); EXPECT_FALSE(lost_resource); EXPECT_EQ(main_thread_task_runner, mailbox_task_runner); } @@ -2952,12 +2995,12 @@ gpu_memory_buffer_manager_.get(), NULL, 0, 1, use_gpu_memory_buffer_resources_, use_image_texture_targets_)); - gpu::SyncToken sync_token(30); + gpu::SyncToken sync_token(gpu::CommandBufferNamespace::GPU_IO, 0, 0x12, 0x34); + const GLuint64 current_fence_sync = context->GetNextFenceSync(); unsigned target = GL_TEXTURE_EXTERNAL_OES; EXPECT_CALL(*context, bindTexture(_, _)).Times(0); EXPECT_CALL(*context, waitSyncToken(_)).Times(0); - EXPECT_CALL(*context, insertSyncPoint()).Times(0); EXPECT_CALL(*context, produceTextureDirectCHROMIUM(_, _, _)).Times(0); EXPECT_CALL(*context, createAndConsumeTextureCHROMIUM(_, _)).Times(0); @@ -2971,6 +3014,7 @@ ResourceId id = resource_provider->CreateResourceFromTextureMailbox( mailbox, std::move(callback)); EXPECT_NE(0u, id); + EXPECT_EQ(current_fence_sync, context->GetNextFenceSync()); Mock::VerifyAndClearExpectations(context); @@ -2985,7 +3029,6 @@ EXPECT_CALL(*context, createAndConsumeTextureCHROMIUM(target, _)) .WillOnce(Return(texture_id)); - EXPECT_CALL(*context, insertSyncPoint()).Times(0); EXPECT_CALL(*context, produceTextureDirectCHROMIUM(_, _, _)).Times(0); ResourceProvider::ScopedReadLockGL lock(resource_provider.get(), id); @@ -2994,7 +3037,6 @@ // When done with it, a sync point should be inserted, but no produce is // necessary. EXPECT_CALL(*context, bindTexture(_, _)).Times(0); - EXPECT_CALL(*context, insertSyncPoint()); EXPECT_CALL(*context, produceTextureDirectCHROMIUM(_, _, _)).Times(0); EXPECT_CALL(*context, waitSyncToken(_)).Times(0); @@ -3022,12 +3064,12 @@ gpu_memory_buffer_manager_.get(), NULL, 0, 1, use_gpu_memory_buffer_resources_, use_image_texture_targets_)); - gpu::SyncToken sync_token(30); + gpu::SyncToken sync_token(gpu::CommandBufferNamespace::GPU_IO, 0, 0x12, 0x34); + const GLuint64 current_fence_sync = context->GetNextFenceSync(); unsigned target = GL_TEXTURE_2D; EXPECT_CALL(*context, bindTexture(_, _)).Times(0); EXPECT_CALL(*context, waitSyncToken(_)).Times(0); - EXPECT_CALL(*context, insertSyncPoint()).Times(0); EXPECT_CALL(*context, produceTextureDirectCHROMIUM(_, _, _)).Times(0); EXPECT_CALL(*context, createAndConsumeTextureCHROMIUM(_, _)).Times(0); @@ -3041,6 +3083,7 @@ ResourceId id = resource_provider->CreateResourceFromTextureMailbox( mailbox, std::move(callback)); EXPECT_NE(0u, id); + EXPECT_EQ(current_fence_sync, context->GetNextFenceSync()); Mock::VerifyAndClearExpectations(context); @@ -3077,11 +3120,11 @@ use_gpu_memory_buffer_resources_, use_image_texture_targets_)); gpu::SyncToken sync_token; + const GLuint64 current_fence_sync = context->GetNextFenceSync(); unsigned target = GL_TEXTURE_2D; EXPECT_CALL(*context, bindTexture(_, _)).Times(0); EXPECT_CALL(*context, waitSyncToken(_)).Times(0); - EXPECT_CALL(*context, insertSyncPoint()).Times(0); EXPECT_CALL(*context, produceTextureDirectCHROMIUM(_, _, _)).Times(0); EXPECT_CALL(*context, createAndConsumeTextureCHROMIUM(_, _)).Times(0); @@ -3095,6 +3138,7 @@ ResourceId id = resource_provider->CreateResourceFromTextureMailbox( mailbox, std::move(callback)); EXPECT_NE(0u, id); + EXPECT_EQ(current_fence_sync, context->GetNextFenceSync()); Mock::VerifyAndClearExpectations(context);
diff --git a/cc/test/animation_test_common.cc b/cc/test/animation_test_common.cc index 721f6c2..f61e9bb 100644 --- a/cc/test/animation_test_common.cc +++ b/cc/test/animation_test_common.cc
@@ -455,6 +455,16 @@ controller->RemoveAnimation(animation_id); } +Animation* GetAnimationFromLayerWithExistingPlayer( + int layer_id, + scoped_refptr<AnimationTimeline> timeline, + int animation_id) { + LayerAnimationController* controller = + timeline->animation_host()->GetControllerForLayerId(layer_id); + DCHECK(controller); + return controller->GetAnimationById(animation_id); +} + int AddAnimatedFilterToLayerWithPlayer( int layer_id, scoped_refptr<AnimationTimeline> timeline,
diff --git a/cc/test/animation_test_common.h b/cc/test/animation_test_common.h index c62c185..19e7a7c 100644 --- a/cc/test/animation_test_common.h +++ b/cc/test/animation_test_common.h
@@ -220,11 +220,17 @@ int layer_id, scoped_refptr<AnimationTimeline> timeline, scoped_ptr<Animation> animation); + void RemoveAnimationFromLayerWithExistingPlayer( int layer_id, scoped_refptr<AnimationTimeline> timeline, int animation_id); +Animation* GetAnimationFromLayerWithExistingPlayer( + int layer_id, + scoped_refptr<AnimationTimeline> timeline, + int animation_id); + int AddAnimatedFilterToLayerWithPlayer( int layer_id, scoped_refptr<AnimationTimeline> timeline,
diff --git a/cc/test/fake_layer_tree_host.cc b/cc/test/fake_layer_tree_host.cc index f57cad8..05ecd6a3 100644 --- a/cc/test/fake_layer_tree_host.cc +++ b/cc/test/fake_layer_tree_host.cc
@@ -32,6 +32,7 @@ TestTaskGraphRunner* task_graph_runner) { LayerTreeSettings settings; settings.verify_property_trees = true; + settings.use_compositor_animation_timelines = true; return Create(client, task_graph_runner, settings); }
diff --git a/cc/test/layer_tree_settings_for_testing.cc b/cc/test/layer_tree_settings_for_testing.cc index 855d9f5..952bb7045 100644 --- a/cc/test/layer_tree_settings_for_testing.cc +++ b/cc/test/layer_tree_settings_for_testing.cc
@@ -8,6 +8,7 @@ LayerTreeSettingsForTesting::LayerTreeSettingsForTesting() : LayerTreeSettings() { + this->use_compositor_animation_timelines = true; this->verify_property_trees = true; }
diff --git a/cc/test/test_context_provider.cc b/cc/test/test_context_provider.cc index c9de320..734ef790 100644 --- a/cc/test/test_context_provider.cc +++ b/cc/test/test_context_provider.cc
@@ -112,8 +112,7 @@ if (gr_context_) return gr_context_.get(); - skia::RefPtr<class SkGLContext> gl_context = - skia::AdoptRef(SkNullGLContext::Create(kNone_GrGLStandard)); + scoped_ptr<class SkGLContext> gl_context(SkNullGLContext::Create()); gl_context->makeCurrent(); gr_context_ = skia::AdoptRef(GrContext::Create( kOpenGL_GrBackend, reinterpret_cast<GrBackendContext>(gl_context->gl())));
diff --git a/cc/test/test_gles2_interface.cc b/cc/test/test_gles2_interface.cc index 2781712..97766fb 100644 --- a/cc/test/test_gles2_interface.cc +++ b/cc/test/test_gles2_interface.cc
@@ -327,6 +327,25 @@ return test_context_->insertSyncPoint(); } +GLuint64 TestGLES2Interface::InsertFenceSyncCHROMIUM() { + return test_context_->insertFenceSync(); +} + +void TestGLES2Interface::GenSyncTokenCHROMIUM(GLuint64 fence_sync, + GLbyte* sync_token) { + test_context_->genSyncToken(fence_sync, sync_token); +} + +void TestGLES2Interface::GenUnverifiedSyncTokenCHROMIUM(GLuint64 fence_sync, + GLbyte* sync_token) { + test_context_->genSyncToken(fence_sync, sync_token); +} + +void TestGLES2Interface::VerifySyncTokensCHROMIUM(GLbyte** sync_tokens, + GLsizei count) { + test_context_->verifySyncTokens(sync_tokens, count); +} + void TestGLES2Interface::WaitSyncTokenCHROMIUM(const GLbyte* sync_token) { test_context_->waitSyncToken(sync_token); }
diff --git a/cc/test/test_gles2_interface.h b/cc/test/test_gles2_interface.h index 0914810..fe4f16fe 100644 --- a/cc/test/test_gles2_interface.h +++ b/cc/test/test_gles2_interface.h
@@ -138,7 +138,11 @@ GLenum usage) override; GLuint InsertSyncPointCHROMIUM() override; - + GLuint64 InsertFenceSyncCHROMIUM() override; + void GenSyncTokenCHROMIUM(GLuint64 fence_sync, GLbyte* sync_token) override; + void GenUnverifiedSyncTokenCHROMIUM(GLuint64 fence_sync, + GLbyte* sync_token) override; + void VerifySyncTokensCHROMIUM(GLbyte** sync_tokens, GLsizei count) override; void WaitSyncTokenCHROMIUM(const GLbyte* sync_token) override; void BeginQueryEXT(GLenum target, GLuint id) override;
diff --git a/cc/test/test_web_graphics_context_3d.cc b/cc/test/test_web_graphics_context_3d.cc index 96b11b4a..8e4df91 100644 --- a/cc/test/test_web_graphics_context_3d.cc +++ b/cc/test/test_web_graphics_context_3d.cc
@@ -69,7 +69,7 @@ scale_factor_(-1.f), test_support_(NULL), last_update_type_(NO_UPDATE), - next_insert_sync_point_(1), + next_insert_fence_sync_(1), unpack_alignment_(4), bound_buffer_(0), weak_ptr_factory_(this) { @@ -649,8 +649,20 @@ return image_id; } -unsigned TestWebGraphicsContext3D::insertSyncPoint() { - return next_insert_sync_point_++; +GLuint TestWebGraphicsContext3D::insertSyncPoint() { + return static_cast<GLuint>(next_insert_fence_sync_++); +} + +GLuint64 TestWebGraphicsContext3D::insertFenceSync() { + return next_insert_fence_sync_++; +} + +void TestWebGraphicsContext3D::genSyncToken(GLuint64 fence_sync, + GLbyte* sync_token) { + gpu::SyncToken sync_token_data(gpu::CommandBufferNamespace::GPU_IO, 0, 0, + fence_sync); + sync_token_data.SetVerifyFlush(); + memcpy(sync_token, &sync_token_data, sizeof(sync_token_data)); } void TestWebGraphicsContext3D::waitSyncToken(const GLbyte* sync_token) { @@ -662,6 +674,16 @@ } } +void TestWebGraphicsContext3D::verifySyncTokens(GLbyte** sync_tokens, + GLsizei count) { + for (GLsizei i = 0; i < count; ++i) { + gpu::SyncToken sync_token_data; + memcpy(sync_token_data.GetData(), sync_tokens[i], sizeof(sync_token_data)); + sync_token_data.SetVerifyFlush(); + memcpy(sync_tokens[i], &sync_token_data, sizeof(sync_token_data)); + } +} + size_t TestWebGraphicsContext3D::NumTextures() const { base::AutoLock lock(namespace_->lock); return namespace_->textures.Size();
diff --git a/cc/test/test_web_graphics_context_3d.h b/cc/test/test_web_graphics_context_3d.h index 08447f7c..fba2b8d8 100644 --- a/cc/test/test_web_graphics_context_3d.h +++ b/cc/test/test_web_graphics_context_3d.h
@@ -275,8 +275,11 @@ GLuint io_surface_id, GLuint plane) {} - virtual unsigned insertSyncPoint(); + virtual GLuint insertSyncPoint(); + virtual GLuint64 insertFenceSync(); + virtual void genSyncToken(GLuint64 fence_sync, GLbyte* sync_token); virtual void waitSyncToken(const GLbyte* sync_token); + virtual void verifySyncTokens(GLbyte** sync_tokens, GLsizei count); const gpu::SyncToken& last_waited_sync_token() const { return last_waited_sync_token_; @@ -482,7 +485,7 @@ TestContextSupport* test_support_; gfx::Rect update_rect_; UpdateType last_update_type_; - unsigned next_insert_sync_point_; + GLuint64 next_insert_fence_sync_; gpu::SyncToken last_waited_sync_token_; int unpack_alignment_;
diff --git a/cc/trees/layer_tree_host_common_unittest.cc b/cc/trees/layer_tree_host_common_unittest.cc index 46bb8703..e729ec3d 100644 --- a/cc/trees/layer_tree_host_common_unittest.cc +++ b/cc/trees/layer_tree_host_common_unittest.cc
@@ -90,6 +90,7 @@ public: LayerTreeSettingsScaleContent() { layer_transforms_should_scale_layer_contents = true; + use_compositor_animation_timelines = true; } }; @@ -9478,6 +9479,9 @@ ExecuteCalculateDrawProperties(root); EXPECT_EQ(gfx::Rect(-10, -10, 30, 30), render_surface2->clip_rect()); + // A clip node is created for every render surface and for layers that have + // local clip. So, here it should be craeted for every layer. + EXPECT_EQ(root->layer_tree_impl()->property_trees()->clip_tree.size(), 5u); } TEST_F(LayerTreeHostCommonTest, MaskLayerScreenSpaceTransform) {
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc index 203670f..9d74110f 100644 --- a/cc/trees/layer_tree_host_impl.cc +++ b/cc/trees/layer_tree_host_impl.cc
@@ -3626,9 +3626,7 @@ } } -void LayerTreeHostImpl::SetMutatorsNeedCommit() { - SetNeedsCommit(); -} +void LayerTreeHostImpl::SetMutatorsNeedCommit() {} void LayerTreeHostImpl::SetMutatorsNeedRebuildPropertyTrees() {}
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc index 78be80f89..2fc38a0 100644 --- a/cc/trees/layer_tree_host_impl_unittest.cc +++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -16,6 +16,8 @@ #include "base/containers/scoped_ptr_hash_map.h" #include "base/location.h" #include "base/thread_task_runner_handle.h" +#include "cc/animation/animation_host.h" +#include "cc/animation/animation_id_provider.h" #include "cc/animation/scrollbar_animation_controller_thinning.h" #include "cc/animation/transform_operations.h" #include "cc/base/math_util.h" @@ -110,6 +112,7 @@ settings.minimum_occlusion_tracking_size = gfx::Size(); settings.renderer_settings.texture_id_allocation_chunk_size = 1; settings.gpu_rasterization_enabled = true; + settings.use_compositor_animation_timelines = true; settings.verify_property_trees = true; return settings; } @@ -207,6 +210,13 @@ BEGINFRAME_FROM_HERE, base::TimeTicks() + base::TimeDelta::FromMilliseconds(1))); host_impl_->DidFinishImplFrame(); + + if (host_impl_->settings().use_compositor_animation_timelines) { + timeline_ = + AnimationTimeline::Create(AnimationIdProvider::NextTimelineId()); + host_impl_->animation_host()->AddAnimationTimeline(timeline_); + } + return init; } @@ -406,6 +416,8 @@ void SetupMouseMoveAtWithDeviceScale(float device_scale_factor); + scoped_refptr<AnimationTimeline> timeline() { return timeline_; } + protected: virtual scoped_ptr<OutputSurface> CreateOutputSurface() { return FakeOutputSurface::Create3d(); @@ -439,6 +451,7 @@ bool skip_draw_layers_in_on_draw_; scoped_ptr<LayerTreeHostImpl::FrameData> last_on_draw_frame_; RenderPassList last_on_draw_render_passes_; + scoped_refptr<AnimationTimeline> timeline_; }; // A test fixture for new animation timelines tests. @@ -1135,7 +1148,11 @@ child->SetBounds(gfx::Size(10, 10)); child->draw_properties().visible_layer_rect = gfx::Rect(10, 10); child->SetDrawsContent(true); - AddAnimatedTransformToLayer(child, 10.0, 3, 0); + if (host_impl_->settings().use_compositor_animation_timelines) { + AddAnimatedTransformToLayerWithPlayer(child->id(), timeline(), 10.0, 3, 0); + } else { + AddAnimatedTransformToLayer(child, 10.0, 3, 0); + } EXPECT_FALSE(did_request_next_frame_); EXPECT_FALSE(did_request_redraw_); @@ -1191,7 +1208,12 @@ start.AppendTranslate(6.f, 7.f, 0.f); TransformOperations end; end.AppendTranslate(8.f, 9.f, 0.f); - AddAnimatedTransformToLayer(child, 4.0, start, end); + if (host_impl_->settings().use_compositor_animation_timelines) { + AddAnimatedTransformToLayerWithPlayer(child->id(), timeline(), 4.0, start, + end); + } else { + AddAnimatedTransformToLayer(child, 4.0, start, end); + } base::TimeTicks now = base::TimeTicks::Now(); host_impl_->WillBeginImplFrame( @@ -1248,7 +1270,11 @@ child->SetBounds(gfx::Size(10, 10)); child->draw_properties().visible_layer_rect = gfx::Rect(10, 10); child->SetDrawsContent(true); - AddAnimatedTransformToLayer(child, 10.0, 3, 0); + if (host_impl_->settings().use_compositor_animation_timelines) { + AddAnimatedTransformToLayerWithPlayer(child->id(), timeline(), 10.0, 3, 0); + } else { + AddAnimatedTransformToLayer(child, 10.0, 3, 0); + } // Set up the property trees so that UpdateDrawProperties will work in // CommitComplete below. @@ -1315,7 +1341,13 @@ start.AppendTranslate(6.f, 7.f, 0.f); TransformOperations end; end.AppendTranslate(8.f, 9.f, 0.f); - int animation_id = AddAnimatedTransformToLayer(child, 4.0, start, end); + int animation_id; + if (host_impl_->settings().use_compositor_animation_timelines) { + animation_id = AddAnimatedTransformToLayerWithPlayer( + child->id(), timeline(), 4.0, start, end); + } else { + animation_id = AddAnimatedTransformToLayer(child, 4.0, start, end); + } base::TimeTicks now = base::TimeTicks::Now(); host_impl_->WillBeginImplFrame( @@ -1346,7 +1378,12 @@ // Remove the animation. child->set_has_missing_tiles(true); - child->layer_animation_controller()->RemoveAnimation(animation_id); + if (host_impl_->settings().use_compositor_animation_timelines) { + RemoveAnimationFromLayerWithExistingPlayer(child->id(), timeline(), + animation_id); + } else { + child->layer_animation_controller()->RemoveAnimation(animation_id); + } child->draw_properties().screen_space_transform_is_animating = false; // Child layer doesn't have an animation, but was never ready since the last @@ -3200,18 +3237,17 @@ class MissingTextureAnimatingLayer : public DidDrawCheckLayer { public: - static scoped_ptr<LayerImpl> Create(LayerTreeImpl* tree_impl, - int id, - bool tile_missing, - bool had_incomplete_tile, - bool animating, - ResourceProvider* resource_provider) { - return make_scoped_ptr(new MissingTextureAnimatingLayer(tree_impl, - id, - tile_missing, - had_incomplete_tile, - animating, - resource_provider)); + static scoped_ptr<LayerImpl> Create( + LayerTreeImpl* tree_impl, + int id, + bool tile_missing, + bool had_incomplete_tile, + bool animating, + ResourceProvider* resource_provider, + scoped_refptr<AnimationTimeline> timeline) { + return make_scoped_ptr(new MissingTextureAnimatingLayer( + tree_impl, id, tile_missing, had_incomplete_tile, animating, + resource_provider, timeline)); } void AppendQuads(RenderPass* render_pass, @@ -3229,12 +3265,18 @@ bool tile_missing, bool had_incomplete_tile, bool animating, - ResourceProvider* resource_provider) + ResourceProvider* resource_provider, + scoped_refptr<AnimationTimeline> timeline) : DidDrawCheckLayer(tree_impl, id), tile_missing_(tile_missing), had_incomplete_tile_(had_incomplete_tile) { - if (animating) - AddAnimatedTransformToLayer(this, 10.0, 3, 0); + if (animating) { + if (tree_impl->settings().use_compositor_animation_timelines) { + AddAnimatedTransformToLayerWithPlayer(this->id(), timeline, 10.0, 3, 0); + } else { + AddAnimatedTransformToLayer(this, 10.0, 3, 0); + } + } } bool tile_missing_; @@ -3342,12 +3384,15 @@ host_impl_->SwapBuffers(frame); for (size_t i = 0; i < cases.size(); ++i) { + // Clean up host_impl_ state. const auto& testcase = cases[i]; std::vector<LayerImpl*> to_remove; for (const auto& child : root->children()) to_remove.push_back(child.get()); for (auto* child : to_remove) root->RemoveChild(child); + if (host_impl_->settings().use_compositor_animation_timelines) + timeline()->ClearPlayers(); std::ostringstream scope; scope << "Test case: " << i; @@ -3356,7 +3401,8 @@ root->AddChild(MissingTextureAnimatingLayer::Create( host_impl_->active_tree(), 2, testcase.layer_before.has_missing_tile, testcase.layer_before.has_incomplete_tile, - testcase.layer_before.is_animating, host_impl_->resource_provider())); + testcase.layer_before.is_animating, host_impl_->resource_provider(), + timeline())); DidDrawCheckLayer* before = static_cast<DidDrawCheckLayer*>(root->children().back().get()); if (testcase.layer_before.has_copy_request) @@ -3365,7 +3411,8 @@ root->AddChild(MissingTextureAnimatingLayer::Create( host_impl_->active_tree(), 3, testcase.layer_between.has_missing_tile, testcase.layer_between.has_incomplete_tile, - testcase.layer_between.is_animating, host_impl_->resource_provider())); + testcase.layer_between.is_animating, host_impl_->resource_provider(), + timeline())); DidDrawCheckLayer* between = static_cast<DidDrawCheckLayer*>(root->children().back().get()); if (testcase.layer_between.has_copy_request) @@ -3374,7 +3421,8 @@ root->AddChild(MissingTextureAnimatingLayer::Create( host_impl_->active_tree(), 4, testcase.layer_after.has_missing_tile, testcase.layer_after.has_incomplete_tile, - testcase.layer_after.is_animating, host_impl_->resource_provider())); + testcase.layer_after.is_animating, host_impl_->resource_provider(), + timeline())); DidDrawCheckLayer* after = static_cast<DidDrawCheckLayer*>(root->children().back().get()); if (testcase.layer_after.has_copy_request) @@ -3445,7 +3493,8 @@ root->AddChild(MissingTextureAnimatingLayer::Create( host_impl_->active_tree(), 2, testcase.layer_before.has_missing_tile, testcase.layer_before.has_incomplete_tile, - testcase.layer_before.is_animating, host_impl_->resource_provider())); + testcase.layer_before.is_animating, host_impl_->resource_provider(), + timeline())); DidDrawCheckLayer* before = static_cast<DidDrawCheckLayer*>(root->children().back().get()); if (testcase.layer_before.has_copy_request) @@ -3454,7 +3503,8 @@ root->AddChild(MissingTextureAnimatingLayer::Create( host_impl_->active_tree(), 3, testcase.layer_between.has_missing_tile, testcase.layer_between.has_incomplete_tile, - testcase.layer_between.is_animating, host_impl_->resource_provider())); + testcase.layer_between.is_animating, host_impl_->resource_provider(), + timeline())); DidDrawCheckLayer* between = static_cast<DidDrawCheckLayer*>(root->children().back().get()); if (testcase.layer_between.has_copy_request) @@ -3463,7 +3513,8 @@ root->AddChild(MissingTextureAnimatingLayer::Create( host_impl_->active_tree(), 4, testcase.layer_after.has_missing_tile, testcase.layer_after.has_incomplete_tile, - testcase.layer_after.is_animating, host_impl_->resource_provider())); + testcase.layer_after.is_animating, host_impl_->resource_provider(), + timeline())); DidDrawCheckLayer* after = static_cast<DidDrawCheckLayer*>(root->children().back().get()); if (testcase.layer_after.has_copy_request)
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc index 575a367..6974c92a 100644 --- a/cc/trees/layer_tree_host_unittest.cc +++ b/cc/trees/layer_tree_host_unittest.cc
@@ -1564,6 +1564,65 @@ MULTI_THREAD_TEST_F(LayerTreeHostTestSetVisible); +class TestOpacityChangeLayerDelegate : public ContentLayerClient { + public: + TestOpacityChangeLayerDelegate() : test_layer_(0) {} + + void SetTestLayer(Layer* test_layer) { test_layer_ = test_layer; } + + gfx::Rect PaintableRegion() override { + return gfx::Rect(test_layer_->bounds()); + } + scoped_refptr<DisplayItemList> PaintContentsToDisplayList( + PaintingControlSetting picture_control) override { + // Set layer opacity to 0. + if (test_layer_) + test_layer_->SetOpacity(0.f); + + // Return a dummy display list. + scoped_refptr<DisplayItemList> display_list = + DisplayItemList::Create(PaintableRegion(), DisplayItemListSettings()); + return display_list; + } + bool FillsBoundsCompletely() const override { return false; } + size_t GetApproximateUnsharedMemoryUsage() const override { return 0; } + + private: + Layer* test_layer_; +}; + +// Layer opacity change during paint should not prevent compositor resources +// from being updated during commit. +class LayerTreeHostTestOpacityChange : public LayerTreeHostTest { + public: + LayerTreeHostTestOpacityChange() : test_opacity_change_delegate_() {} + + void SetupTree() override { + LayerTreeHostTest::SetupTree(); + + update_check_picture_layer_ = FakePictureLayer::Create( + layer_settings(), &test_opacity_change_delegate_); + test_opacity_change_delegate_.SetTestLayer( + update_check_picture_layer_.get()); + layer_tree_host()->root_layer()->AddChild(update_check_picture_layer_); + } + + void BeginTest() override { PostSetNeedsCommitToMainThread(); } + + void CommitCompleteOnThread(LayerTreeHostImpl* impl) override { EndTest(); } + + void AfterTest() override { + // Update() should have been called once. + EXPECT_EQ(1, update_check_picture_layer_->update_count()); + } + + private: + TestOpacityChangeLayerDelegate test_opacity_change_delegate_; + scoped_refptr<FakePictureLayer> update_check_picture_layer_; +}; + +MULTI_THREAD_TEST_F(LayerTreeHostTestOpacityChange); + class LayerTreeHostTestDeviceScaleFactorScalesViewportAndLayers : public LayerTreeHostTest { public: @@ -2114,6 +2173,70 @@ SINGLE_AND_MULTI_THREAD_TEST_F( LayerTreeHostTestUninvertibleTransformDoesNotBlockActivation); +class LayerTreeHostTestChangeLayerPropertiesInPaintContents + : public LayerTreeHostTest { + public: + class SetBoundsClient : public ContentLayerClient { + public: + SetBoundsClient() : layer_(0) {} + + void set_layer(Layer* layer) { layer_ = layer; } + + gfx::Rect PaintableRegion() override { return gfx::Rect(layer_->bounds()); } + + scoped_refptr<DisplayItemList> PaintContentsToDisplayList( + PaintingControlSetting picture_control) override { + layer_->SetBounds(gfx::Size(2, 2)); + + // Return a dummy display list. + scoped_refptr<DisplayItemList> display_list = + DisplayItemList::Create(PaintableRegion(), DisplayItemListSettings()); + return display_list; + } + + bool FillsBoundsCompletely() const override { return false; } + size_t GetApproximateUnsharedMemoryUsage() const override { return 0; } + + private: + Layer* layer_; + }; + + LayerTreeHostTestChangeLayerPropertiesInPaintContents() : num_commits_(0) {} + + void SetupTree() override { + scoped_refptr<PictureLayer> root_layer = + PictureLayer::Create(layer_settings(), &client_); + root_layer->SetIsDrawable(true); + root_layer->SetBounds(gfx::Size(1, 1)); + client_.set_layer(root_layer.get()); + + layer_tree_host()->SetRootLayer(root_layer); + LayerTreeHostTest::SetupTree(); + } + + void BeginTest() override { PostSetNeedsCommitToMainThread(); } + void AfterTest() override {} + + void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override { + num_commits_++; + if (num_commits_ == 1) { + LayerImpl* root_layer = host_impl->active_tree()->root_layer(); + EXPECT_EQ(gfx::Size(1, 1), root_layer->bounds()); + } else { + LayerImpl* root_layer = host_impl->active_tree()->root_layer(); + EXPECT_EQ(gfx::Size(2, 2), root_layer->bounds()); + EndTest(); + } + } + + private: + SetBoundsClient client_; + int num_commits_; +}; + +SINGLE_AND_MULTI_THREAD_TEST_F( + LayerTreeHostTestChangeLayerPropertiesInPaintContents); + class MockIOSurfaceWebGraphicsContext3D : public TestWebGraphicsContext3D { public: MockIOSurfaceWebGraphicsContext3D() {
diff --git a/cc/trees/layer_tree_impl.cc b/cc/trees/layer_tree_impl.cc index 3519f29..86be523 100644 --- a/cc/trees/layer_tree_impl.cc +++ b/cc/trees/layer_tree_impl.cc
@@ -40,6 +40,7 @@ #include "cc/trees/property_tree_builder.h" #include "ui/gfx/geometry/box_f.h" #include "ui/gfx/geometry/point_conversions.h" +#include "ui/gfx/geometry/rect_conversions.h" #include "ui/gfx/geometry/size_conversions.h" #include "ui/gfx/geometry/vector2d_conversions.h" @@ -997,10 +998,6 @@ return layer_tree_host_impl_->CurrentBeginFrameInterval(); } -void LayerTreeImpl::SetNeedsCommit() { - layer_tree_host_impl_->SetNeedsCommit(); -} - gfx::Rect LayerTreeImpl::DeviceViewport() const { return layer_tree_host_impl_->DeviceViewport(); } @@ -1434,25 +1431,79 @@ layer->render_surface(), transform_tree); } +static bool PointIsClippedByAncestorClipNode( + const gfx::PointF& screen_space_point, + const LayerImpl* layer, + const ClipTree& clip_tree, + const TransformTree& transform_tree) { + // We need to visit all ancestor clip nodes to check this. Checking with just + // the combined clip stored at a clip node is not enough because parent + // combined clip can sometimes be smaller than current combined clip. This can + // happen when we have transforms like rotation that inflate the combined + // clip's bounds. Also, the point can be clipped by the content rect of an + // ancestor render surface. + + // We first check if the point is clipped by viewport. + const ClipNode* clip_node = clip_tree.Node(1); + gfx::Rect combined_clip_in_target_space = + gfx::ToEnclosingRect(clip_node->data.combined_clip_in_target_space); + if (!PointHitsRect(screen_space_point, gfx::Transform(), + combined_clip_in_target_space, NULL)) + return true; + + for (const ClipNode* clip_node = clip_tree.Node(layer->clip_tree_index()); + clip_node->id > 1; clip_node = clip_tree.parent(clip_node)) { + if (clip_node->data.applies_local_clip) { + const TransformNode* transform_node = + transform_tree.Node(clip_node->data.target_id); + gfx::Rect combined_clip_in_target_space = + gfx::ToEnclosingRect(clip_node->data.combined_clip_in_target_space); + + if (!PointHitsRect(screen_space_point, transform_node->data.to_screen, + combined_clip_in_target_space, NULL)) + return true; + } + const LayerImpl* clip_node_owner = + layer->layer_tree_impl()->LayerById(clip_node->owner_id); + if (clip_node_owner->render_surface() && + !PointHitsRect( + screen_space_point, + SurfaceScreenSpaceTransform(clip_node_owner, transform_tree, + true /*use_property_trees*/), + clip_node_owner->render_surface()->content_rect(), NULL)) { + return true; + } + } + return false; +} + static bool PointIsClippedBySurfaceOrClipRect( const gfx::PointF& screen_space_point, const LayerImpl* layer, const TransformTree& transform_tree, + const ClipTree& clip_tree, const bool use_property_trees) { // Walk up the layer tree and hit-test any render_surfaces and any layer // clip rects that are active. + if (use_property_trees) { + return PointIsClippedByAncestorClipNode(screen_space_point, layer, + clip_tree, transform_tree); + } + for (; layer; layer = GetNextClippingLayer(layer)) { if (layer->render_surface() && !PointHitsRect(screen_space_point, SurfaceScreenSpaceTransform(layer, transform_tree, use_property_trees), - layer->render_surface()->content_rect(), NULL)) + layer->render_surface()->content_rect(), NULL)) { return true; + } if (LayerClipsSubtree(layer) && !PointHitsRect(screen_space_point, layer->ScreenSpaceTransform(), - gfx::Rect(layer->bounds()), NULL)) + gfx::Rect(layer->bounds()), NULL)) { return true; + } } // If we have finished walking all ancestors without having already exited, @@ -1464,6 +1515,7 @@ const gfx::PointF& screen_space_point, float* distance_to_intersection, const TransformTree& transform_tree, + const ClipTree& clip_tree, const bool use_property_trees) { gfx::Rect content_rect(layer->bounds()); if (!PointHitsRect(screen_space_point, layer->ScreenSpaceTransform(), @@ -1474,7 +1526,8 @@ // up the parents to ensure that the layer was not clipped in such a way // that the hit point actually should not hit the layer. if (PointIsClippedBySurfaceOrClipRect(screen_space_point, layer, - transform_tree, use_property_trees)) + transform_tree, clip_tree, + use_property_trees)) return false; // Skip the HUD layer. @@ -1500,14 +1553,15 @@ LayerImpl* layer, const Functor& func, const TransformTree& transform_tree, + const ClipTree& clip_tree, const bool use_property_trees, FindClosestMatchingLayerDataForRecursion* data_for_recursion) { size_t children_size = layer->children().size(); for (size_t i = 0; i < children_size; ++i) { size_t index = children_size - 1 - i; FindClosestMatchingLayer(screen_space_point, layer->children()[index].get(), - func, transform_tree, use_property_trees, - data_for_recursion); + func, transform_tree, clip_tree, + use_property_trees, data_for_recursion); } if (!func(layer)) @@ -1517,10 +1571,10 @@ bool hit = false; if (layer->Is3dSorted()) hit = PointHitsLayer(layer, screen_space_point, &distance_to_intersection, - transform_tree, use_property_trees); + transform_tree, clip_tree, use_property_trees); else hit = PointHitsLayer(layer, screen_space_point, nullptr, transform_tree, - use_property_trees); + clip_tree, use_property_trees); if (!hit) return; @@ -1569,7 +1623,8 @@ settings().use_property_trees || settings().verify_property_trees; FindClosestMatchingLayer( screen_space_point, root_layer(), FindScrollingLayerFunctor(), - property_trees_.transform_tree, use_property_trees, &data_for_recursion); + property_trees_.transform_tree, property_trees_.clip_tree, + use_property_trees, &data_for_recursion); return data_for_recursion.closest_match; } @@ -1594,7 +1649,8 @@ FindClosestMatchingLayerDataForRecursion data_for_recursion; FindClosestMatchingLayer(screen_space_point, root_layer(), HitTestVisibleScrollableOrTouchableFunctor(), - property_trees_.transform_tree, use_property_trees, + property_trees_.transform_tree, + property_trees_.clip_tree, use_property_trees, &data_for_recursion); return data_for_recursion.closest_match; } @@ -1602,6 +1658,7 @@ static bool LayerHasTouchEventHandlersAt(const gfx::PointF& screen_space_point, LayerImpl* layer_impl, const TransformTree& transform_tree, + const ClipTree& clip_tree, const bool use_property_trees) { if (layer_impl->touch_event_handler_region().IsEmpty()) return false; @@ -1615,7 +1672,8 @@ // was not clipped in such a way that the hit point actually should not hit // the layer. if (PointIsClippedBySurfaceOrClipRect(screen_space_point, layer_impl, - transform_tree, use_property_trees)) + transform_tree, clip_tree, + use_property_trees)) return false; return true; @@ -1638,19 +1696,21 @@ settings().use_property_trees || settings().verify_property_trees; FindWheelEventLayerFunctor func; FindClosestMatchingLayerDataForRecursion data_for_recursion; - FindClosestMatchingLayer(screen_space_point, root_layer(), func, - property_trees_.transform_tree, use_property_trees, - &data_for_recursion); + FindClosestMatchingLayer( + screen_space_point, root_layer(), func, property_trees_.transform_tree, + property_trees_.clip_tree, use_property_trees, &data_for_recursion); return data_for_recursion.closest_match; } struct FindTouchEventLayerFunctor { bool operator()(LayerImpl* layer) const { return LayerHasTouchEventHandlersAt(screen_space_point, layer, - transform_tree, use_property_trees); + transform_tree, clip_tree, + use_property_trees); } const gfx::PointF screen_space_point; const TransformTree& transform_tree; + const ClipTree& clip_tree; const bool use_property_trees; }; @@ -1664,11 +1724,12 @@ bool use_property_trees = settings().use_property_trees || settings().verify_property_trees; FindTouchEventLayerFunctor func = { - screen_space_point, property_trees_.transform_tree, use_property_trees}; + screen_space_point, property_trees_.transform_tree, + property_trees_.clip_tree, use_property_trees}; FindClosestMatchingLayerDataForRecursion data_for_recursion; - FindClosestMatchingLayer(screen_space_point, root_layer(), func, - property_trees_.transform_tree, use_property_trees, - &data_for_recursion); + FindClosestMatchingLayer( + screen_space_point, root_layer(), func, property_trees_.transform_tree, + property_trees_.clip_tree, use_property_trees, &data_for_recursion); return data_for_recursion.closest_match; } @@ -1681,6 +1742,7 @@ LayerImpl* layer, float device_scale_factor, const TransformTree& transform_tree, + const ClipTree& clip_tree, const bool use_property_trees) { ViewportSelectionBound viewport_bound; viewport_bound.type = layer_bound.type; @@ -1726,7 +1788,7 @@ float intersect_distance = 0.f; viewport_bound.visible = PointHitsLayer(layer, visibility_point, &intersect_distance, - transform_tree, use_property_trees); + transform_tree, clip_tree, use_property_trees); return viewport_bound; } @@ -1740,7 +1802,7 @@ selection_.start, selection_.start.layer_id ? LayerById(selection_.start.layer_id) : NULL, device_scale_factor(), property_trees_.transform_tree, - use_property_trees); + property_trees_.clip_tree, use_property_trees); selection->is_editable = selection_.is_editable; selection->is_empty_text_form_control = selection_.is_empty_text_form_control; if (selection->start.type == SELECTION_BOUND_CENTER || @@ -1751,7 +1813,7 @@ selection_.end, selection_.end.layer_id ? LayerById(selection_.end.layer_id) : NULL, device_scale_factor(), property_trees_.transform_tree, - use_property_trees); + property_trees_.clip_tree, use_property_trees); } }
diff --git a/cc/trees/layer_tree_impl.h b/cc/trees/layer_tree_impl.h index 6d4ba267..d80eeca 100644 --- a/cc/trees/layer_tree_impl.h +++ b/cc/trees/layer_tree_impl.h
@@ -101,7 +101,6 @@ bool PinchGestureActive() const; BeginFrameArgs CurrentBeginFrameArgs() const; base::TimeDelta CurrentBeginFrameInterval() const; - void SetNeedsCommit(); gfx::Rect DeviceViewport() const; gfx::Size DrawViewportSize() const; const gfx::Rect ViewportRectForTilePriority() const;
diff --git a/cc/trees/layer_tree_impl_unittest.cc b/cc/trees/layer_tree_impl_unittest.cc index b6cf7f2..5298ed9 100644 --- a/cc/trees/layer_tree_impl_unittest.cc +++ b/cc/trees/layer_tree_impl_unittest.cc
@@ -380,6 +380,134 @@ ASSERT_FALSE(result_layer); } +TEST_F(LayerTreeImplTest, HitTestingClipNodeDifferentTransformAndTargetIds) { + // Tests hit testing on a layer whose clip node has different transform and + // target id. + gfx::Transform identity_matrix; + scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl().active_tree(), 1); + SetLayerPropertiesForTesting(root.get(), identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(500, 500), true, false, + true); + gfx::Transform translation; + translation.Translate(100, 100); + scoped_ptr<LayerImpl> render_surface = + LayerImpl::Create(host_impl().active_tree(), 2); + SetLayerPropertiesForTesting(render_surface.get(), translation, + gfx::Point3F(), gfx::PointF(), + gfx::Size(100, 100), true, false, true); + + gfx::Transform scale_matrix; + scale_matrix.Scale(2, 2); + scoped_ptr<LayerImpl> scale = LayerImpl::Create(host_impl().active_tree(), 3); + SetLayerPropertiesForTesting(scale.get(), scale_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(50, 50), true, false, + false); + + scoped_ptr<LayerImpl> clip = LayerImpl::Create(host_impl().active_tree(), 4); + SetLayerPropertiesForTesting(clip.get(), identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(25, 25), true, false, + false); + clip->SetMasksToBounds(true); + + scoped_ptr<LayerImpl> test = LayerImpl::Create(host_impl().active_tree(), 5); + SetLayerPropertiesForTesting(test.get(), identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(100, 100), true, false, + false); + test->SetDrawsContent(true); + + clip->AddChild(std::move(test)); + scale->AddChild(std::move(clip)); + render_surface->AddChild(std::move(scale)); + root->AddChild(std::move(render_surface)); + + host_impl().SetViewportSize(root->bounds()); + host_impl().active_tree()->SetRootLayer(std::move(root)); + host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree(); + + gfx::PointF test_point(160.f, 160.f); + LayerImpl* result_layer = + host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); + EXPECT_FALSE(result_layer); + + test_point = gfx::PointF(140.f, 140.f); + result_layer = + host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); + ASSERT_TRUE(result_layer); + EXPECT_EQ(5, result_layer->id()); + + ClipTree clip_tree = host_impl().active_tree()->property_trees()->clip_tree; + ClipNode* clip_node = clip_tree.Node(result_layer->clip_tree_index()); + EXPECT_NE(clip_node->data.transform_id, clip_node->data.target_id); +} + +TEST_F(LayerTreeImplTest, HitTestingSiblings) { + // This tests hit testing when the test point hits only one of the siblings. + gfx::Transform identity_matrix; + scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl().active_tree(), 1); + SetLayerPropertiesForTesting(root.get(), identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(100, 100), true, false, + true); + scoped_ptr<LayerImpl> child1 = + LayerImpl::Create(host_impl().active_tree(), 2); + SetLayerPropertiesForTesting(child1.get(), identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(25, 25), true, false, + false); + child1->SetMasksToBounds(true); + child1->SetDrawsContent(true); + scoped_ptr<LayerImpl> child2 = + LayerImpl::Create(host_impl().active_tree(), 3); + SetLayerPropertiesForTesting(child2.get(), identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(75, 75), true, false, + false); + child2->SetMasksToBounds(true); + child2->SetDrawsContent(true); + root->AddChild(std::move(child1)); + root->AddChild(std::move(child2)); + + host_impl().SetViewportSize(root->bounds()); + host_impl().active_tree()->SetRootLayer(std::move(root)); + host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree(); + + gfx::PointF test_point(50.f, 50.f); + LayerImpl* result_layer = + host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); + ASSERT_TRUE(result_layer); + EXPECT_EQ(3, result_layer->id()); +} + +TEST_F(LayerTreeImplTest, HitTestingPointOutsideMaxTextureSize) { + gfx::Transform identity_matrix; + int max_texture_size = + host_impl().active_tree()->resource_provider()->max_texture_size(); + gfx::Size bounds(max_texture_size + 100, max_texture_size + 100); + + scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl().active_tree(), 1); + SetLayerPropertiesForTesting(root.get(), identity_matrix, gfx::Point3F(), + gfx::PointF(), bounds, true, false, true); + + scoped_ptr<LayerImpl> surface = + LayerImpl::Create(host_impl().active_tree(), 2); + SetLayerPropertiesForTesting(surface.get(), identity_matrix, gfx::Point3F(), + gfx::PointF(), bounds, true, false, true); + surface->SetMasksToBounds(true); + surface->SetDrawsContent(true); + + root->AddChild(std::move(surface)); + host_impl().SetViewportSize(root->bounds()); + host_impl().active_tree()->SetRootLayer(std::move(root)); + host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree(); + + gfx::PointF test_point(max_texture_size - 50, max_texture_size - 50); + LayerImpl* result_layer = + host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); + EXPECT_TRUE(result_layer); + + test_point = gfx::PointF(max_texture_size + 50, max_texture_size + 50); + result_layer = + host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point); + EXPECT_FALSE(result_layer); +} + TEST_F(LayerTreeImplTest, HitTestingForSinglePerspectiveLayer) { scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl().active_tree(), 12345);
diff --git a/cc/trees/layer_tree_settings.cc b/cc/trees/layer_tree_settings.cc index 7329e10..ee0c9579 100644 --- a/cc/trees/layer_tree_settings.cc +++ b/cc/trees/layer_tree_settings.cc
@@ -88,7 +88,7 @@ skewport_target_time_in_seconds(1.0f), skewport_extrapolation_limit_in_content_pixels(2000), max_memory_for_prepaint_percentage(100), - strict_layer_property_change_checking(true), + strict_layer_property_change_checking(false), use_zero_copy(false), use_partial_raster(false), enable_elastic_overscroll(false), @@ -101,7 +101,7 @@ verify_property_trees(false), use_property_trees(true), image_decode_tasks_enabled(false), - use_compositor_animation_timelines(false), + use_compositor_animation_timelines(true), wait_for_beginframe_interval(true), max_staging_buffer_usage_in_bytes(32 * 1024 * 1024), memory_policy_(64 * 1024 * 1024,
diff --git a/cc/trees/property_tree_builder.cc b/cc/trees/property_tree_builder.cc index 3de1081..432aa6c0 100644 --- a/cc/trees/property_tree_builder.cc +++ b/cc/trees/property_tree_builder.cc
@@ -73,25 +73,6 @@ } template <typename LayerType> -static bool AppliesClip(LayerType* layer, - const DataForRecursion<LayerType>& data, - bool created_render_surface, - bool is_clipped) { - const bool render_surface_applies_clip = created_render_surface && is_clipped; - const bool render_surface_may_grow_due_to_clip_children = - created_render_surface && layer->num_unclipped_descendants() > 0; - - if (layer->masks_to_bounds() || layer->mask_layer() || - render_surface_may_grow_due_to_clip_children) - return true; - - if (!render_surface_applies_clip) - return false; - - return true; -} - -template <typename LayerType> static bool LayerClipsSubtree(LayerType* layer) { return layer->masks_to_bounds() || layer->mask_layer(); } @@ -151,17 +132,9 @@ layer_clips_subtree || parent->data.layers_are_clipped_when_surfaces_disabled; - bool applies_clip = - AppliesClip(layer, data_from_ancestor, created_render_surface, - ancestor_clips_subtree); - bool parent_applies_clip = !parent->data.resets_clip; - - // When we have an unclipped surface, all ancestor clips no longer apply. - // However, if our parent already clears ancestor clips and applies no clip of - // its own, there aren't any ancestor clips that need clearing. - bool needs_to_clear_ancestor_clips = - has_unclipped_surface && parent_applies_clip; - bool requires_node = applies_clip || needs_to_clear_ancestor_clips; + // Render surface's clip is needed during hit testing. So, we need to create + // a clip node for every render surface. + bool requires_node = layer_clips_subtree || created_render_surface; if (!requires_node) { data_for_children->clip_tree_parent = parent_id;
diff --git a/cc/trees/tree_synchronizer_unittest.cc b/cc/trees/tree_synchronizer_unittest.cc index a288da3..ede6dc0 100644 --- a/cc/trees/tree_synchronizer_unittest.cc +++ b/cc/trees/tree_synchronizer_unittest.cc
@@ -195,11 +195,24 @@ } } +class LayerTreeSettingsForTreeSynchronizerTest : public LayerTreeSettings { + public: + LayerTreeSettingsForTreeSynchronizerTest() { + use_compositor_animation_timelines = true; + } +}; + class TreeSynchronizerTest : public testing::Test { public: TreeSynchronizerTest() : client_(FakeLayerTreeHostClient::DIRECT_3D), - host_(FakeLayerTreeHost::Create(&client_, &task_graph_runner_)) {} + host_(FakeLayerTreeHost::Create( + &client_, + &task_graph_runner_, + LayerTreeSettingsForTreeSynchronizerTest())) { + layer_settings_.use_compositor_animation_timelines = + host_->settings().use_compositor_animation_timelines; + } protected: FakeLayerTreeHostClient client_; @@ -560,7 +573,12 @@ } TEST_F(TreeSynchronizerTest, SynchronizeAnimations) { - LayerTreeSettings settings; + LayerTreeSettingsForTreeSynchronizerTest settings; + // This test is meaningless in new use_compositor_animation_timelines mode. + // TODO(loyso): Delete FakeLayerAnimationController and related stuff. + if (settings.use_compositor_animation_timelines) + return; + FakeImplTaskRunnerProvider task_runner_provider; FakeRenderingStatsInstrumentation stats_instrumentation; TestSharedBitmapManager shared_bitmap_manager;
diff --git a/chrome/BUILD.gn b/chrome/BUILD.gn index d741423..11eb786 100644 --- a/chrome/BUILD.gn +++ b/chrome/BUILD.gn
@@ -125,8 +125,6 @@ "app/kasko_client.h", "app/main_dll_loader_win.cc", "app/main_dll_loader_win.h", - "app/signature_validator_win.cc", - "app/signature_validator_win.h", "common/crash_keys.cc", "common/crash_keys.h", ] @@ -155,6 +153,7 @@ "//crypto", "//sandbox", "//third_party/crashpad/crashpad/handler:handler_lib", + "//third_party/kasko", "//ui/gfx", "//win8/delegate_execute", "//win8/metro_driver", @@ -163,10 +162,6 @@ "//chrome/app/version_assembly:version_assembly_manifest", ] - libs = [ - "wintrust.lib", - "crypt32.lib", - ] if (win_console_app) { defines += [ "WIN_CONSOLE_APP" ] } else { @@ -303,8 +298,6 @@ "app/chrome_main_delegate.h", "app/chrome_main_mac.h", "app/chrome_main_mac.mm", - "app/close_handle_hook_win.cc", - "app/close_handle_hook_win.h", "app/delay_load_hook_win.cc", "app/delay_load_hook_win.h", ] @@ -402,8 +395,6 @@ "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", ] configs += [ "//build/config/compiler:wexit_time_destructors" ] @@ -684,10 +675,8 @@ "$root_gen_dir/chrome/quota_internals_resources.pak", "$root_gen_dir/chrome/settings_resources.pak", "$root_gen_dir/chrome/sync_file_system_internals_resources.pak", - "$root_gen_dir/chrome/webrtc_device_provider_resources.pak", ] deps += [ - "//chrome/browser/devtools:webrtc_device_provider_resources", "//chrome/browser/resources:component_extension_resources", "//chrome/browser/resources:options_resources", "//chrome/browser/resources:quota_internals_resources", @@ -962,8 +951,14 @@ ] } + # Some android targets still depend on --gc-sections to link. + # TODO: remove --gc-sections for Debug builds (crbug.com/159847). + config("gc_sections") { + ldflags = [ "-Wl,--gc-sections" ] + } + # GYP: //chrome/chrome_android.gypi:chrome_android_core - static_library("chrome_android_core") { + source_set("chrome_android_core") { sources = [ "app/android/chrome_android_initializer.cc", "app/android/chrome_android_initializer.h", @@ -974,6 +969,7 @@ "app/chrome_main_delegate.cc", "app/chrome_main_delegate.h", ] + public_configs = [ ":gc_sections" ] include_dirs = [ android_ndk_include_dir ]
diff --git a/chrome/VERSION b/chrome/VERSION index 8edcd37..b060897e7 100644 --- a/chrome/VERSION +++ b/chrome/VERSION
@@ -1,4 +1,4 @@ MAJOR=49 MINOR=0 -BUILD=2613 +BUILD=2616 PATCH=0
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn index a3dd2f18..049ff39 100644 --- a/chrome/android/BUILD.gn +++ b/chrome/android/BUILD.gn
@@ -133,6 +133,8 @@ "//base:base_java", "//components/safe_json/android:safe_json_java", "//components/variations/android:variations_java", + "//components/web_contents_delegate_android:web_contents_delegate_android_java", + "//components/web_restriction:web_restriction_java", "//content/public/android:content_java", "//media/base/android:media_java", "//media/midi:midi_java", @@ -340,6 +342,7 @@ "//components/precache/android:precache_java", "//components/precache/android:precache_javatests", "//components/web_contents_delegate_android:web_contents_delegate_android_java", + "//components/web_restriction:web_restriction_java", "//content/public/android:content_java", "//content/public/test/android:content_java_test_support", "//net/android:net_java",
diff --git a/chrome/android/java/AndroidManifest.xml b/chrome/android/java/AndroidManifest.xml index 0e6fb69..6983646 100644 --- a/chrome/android/java/AndroidManifest.xml +++ b/chrome/android/java/AndroidManifest.xml
@@ -431,6 +431,12 @@ android:resource="@xml/file_paths" /> </provider> + <provider android:name="org.chromium.chrome.browser.superviseduser.SupervisedUserContentProvider" + android:authorities="{{ manifest_package }}.SupervisedUserProvider" + android:permission="android.permission.INTERNET" + android:exported="true"> + </provider> + <!-- Sync adapter for browser invalidation. --> <service android:name="org.chromium.chrome.browser.invalidation.ChromeBrowserSyncAdapterService" android:exported="false">
diff --git a/chrome/android/java/DEPS b/chrome/android/java/DEPS index acf1ccfa..5c33936 100644 --- a/chrome/android/java/DEPS +++ b/chrome/android/java/DEPS
@@ -7,6 +7,7 @@ "+components/precache/android/java", "+components/service_tab_launcher", "+components/web_contents_delegate_android", + "+components/web_restriction", "+content/public/android/java", "+sync/android/java/src/org/chromium/sync", ]
diff --git a/chrome/android/java/res/drawable-hdpi/infobar_3d_blocked.png b/chrome/android/java/res/drawable-hdpi/infobar_3d_blocked.png new file mode 100644 index 0000000..99869ab --- /dev/null +++ b/chrome/android/java/res/drawable-hdpi/infobar_3d_blocked.png Binary files differ
diff --git a/chrome/android/java/res/drawable-mdpi/infobar_3d_blocked.png b/chrome/android/java/res/drawable-mdpi/infobar_3d_blocked.png new file mode 100644 index 0000000..afc66b5 --- /dev/null +++ b/chrome/android/java/res/drawable-mdpi/infobar_3d_blocked.png Binary files differ
diff --git a/chrome/android/java/res/drawable-mdpi/reader_mode_bar_background.9.png b/chrome/android/java/res/drawable-mdpi/reader_mode_bar_background.9.png deleted file mode 100644 index 60577ca8..0000000 --- a/chrome/android/java/res/drawable-mdpi/reader_mode_bar_background.9.png +++ /dev/null Binary files differ
diff --git a/chrome/android/java/res/drawable-xhdpi/infobar_3d_blocked.png b/chrome/android/java/res/drawable-xhdpi/infobar_3d_blocked.png new file mode 100644 index 0000000..dd1d962 --- /dev/null +++ b/chrome/android/java/res/drawable-xhdpi/infobar_3d_blocked.png Binary files differ
diff --git a/chrome/android/java/res/drawable-xxhdpi/infobar_3d_blocked.png b/chrome/android/java/res/drawable-xxhdpi/infobar_3d_blocked.png new file mode 100644 index 0000000..b6b658ff --- /dev/null +++ b/chrome/android/java/res/drawable-xxhdpi/infobar_3d_blocked.png Binary files differ
diff --git a/chrome/android/java/res/drawable-xxxhdpi/infobar_3d_blocked.png b/chrome/android/java/res/drawable-xxxhdpi/infobar_3d_blocked.png new file mode 100644 index 0000000..e001933b --- /dev/null +++ b/chrome/android/java/res/drawable-xxxhdpi/infobar_3d_blocked.png Binary files differ
diff --git a/chrome/android/java/res/layout/infobar_control_icon_with_description.xml b/chrome/android/java/res/layout/infobar_control_icon_with_description.xml new file mode 100644 index 0000000..4f53d83 --- /dev/null +++ b/chrome/android/java/res/layout/infobar_control_icon_with_description.xml
@@ -0,0 +1,43 @@ +<?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. --> + +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:minHeight="36dp" + android:gravity="center_vertical"> + + <ImageView + android:id="@+id/control_icon" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginEnd="@dimen/infobar_control_margin_between_items" + android:scaleType="centerInside" + android:contentDescription="@null" /> + + <org.chromium.chrome.browser.infobar.InfoBarDualControlLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="1" > + + <TextView + android:id="@+id/control_message" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textSize="@dimen/infobar_text_size" + android:textColor="@color/default_text_color" /> + + <TextView + android:id="@+id/control_secondary_message" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textSize="@dimen/infobar_text_size" + android:textColor="@color/infobar_descriptive_text_color" /> + + </org.chromium.chrome.browser.infobar.InfoBarDualControlLayout> + +</LinearLayout> \ No newline at end of file
diff --git a/chrome/android/java/res/layout/infobar_control_toggle.xml b/chrome/android/java/res/layout/infobar_control_toggle.xml index 987779b..9a65327 100644 --- a/chrome/android/java/res/layout/infobar_control_toggle.xml +++ b/chrome/android/java/res/layout/infobar_control_toggle.xml
@@ -11,19 +11,15 @@ android:gravity="center_vertical"> <ImageView - android:id="@+id/control_toggle_icon" + android:id="@+id/control_icon" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginEnd="@dimen/infobar_control_margin_between_items" android:scaleType="centerInside" android:contentDescription="@null" /> - <!-- TODO(dfalcantara): Line spacing multiplier is applied to all lines in JB & KK, even if the - TextView has only one line. This throws off vertical alignment. Find - a solution that hopefully doesn't involve subclassing the TextView. - --> <TextView - android:id="@+id/control_toggle_message" + android:id="@+id/control_message" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1"
diff --git a/chrome/android/java/res/layout/reader_mode_view.xml b/chrome/android/java/res/layout/reader_mode_view.xml deleted file mode 100644 index 5af5c7f..0000000 --- a/chrome/android/java/res/layout/reader_mode_view.xml +++ /dev/null
@@ -1,63 +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. --> - -<!-- Reader Mode view. --> -<org.chromium.chrome.browser.dom_distiller.ReaderModeButtonView - xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/reader_mode_view" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_gravity="center_vertical" - android:background="@drawable/reader_mode_bar_background" - android:paddingTop="16dp" - android:paddingBottom="16dp" - android:gravity="center_vertical|start" - android:orientation="vertical" - > - - <!-- Lint flags this as a false positive overlap. --> - <!--suppress RelativeOverlap --> - <RelativeLayout - android:layout_width="match_parent" - android:layout_height="wrap_content"> - <ImageView - android:id="@+id/main_icon" - android:src="@drawable/infobar_mobile_friendly" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginStart="16dp" - android:layout_alignParentStart="true" - android:layout_centerVertical="true" - android:contentDescription="@null" - /> - <TextView - android:id="@+id/main_text" - android:text="@string/reader_view_text" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginStart="8dp" - android:layout_marginEnd="8dp" - android:layout_toEndOf="@id/main_icon" - android:layout_toStartOf="@+id/main_close" - android:layout_centerVertical="true" - android:ellipsize="end" - android:singleLine="true" - android:fontFamily="sans-serif" - android:textColor="#333333" - android:textSize="@dimen/reader_mode_text_size" - /> - <ImageView - android:id="@+id/main_close" - android:src="@drawable/btn_close" - android:background="?attr/selectableItemBackground" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginEnd="16dp" - android:layout_alignParentEnd="true" - android:layout_centerVertical="true" - android:contentDescription="@string/close" - /> - </RelativeLayout> -</org.chromium.chrome.browser.dom_distiller.ReaderModeButtonView>
diff --git a/chrome/android/java/res/values/dimens.xml b/chrome/android/java/res/values/dimens.xml index 48e97f5..7bcdd7cac 100644 --- a/chrome/android/java/res/values/dimens.xml +++ b/chrome/android/java/res/values/dimens.xml
@@ -70,10 +70,10 @@ <dimen name="infobar_descriptive_text_size">14sp</dimen> <!-- Minimum width of an infobar. --> <dimen name="infobar_min_width">220dp</dimen> - <!-- Maximum width of an infobar. --> - <dimen name="infobar_max_width">600dp</dimen> - <!-- Margin between items in an infobar. --> - <dimen name="infobar_margin">16dp</dimen> + <!-- Padding surrounding the infobar. --> + <dimen name="infobar_padding">16dp</dimen> + <!-- Margin between stacked buttons in an infobar. --> + <dimen name="infobar_margin_between_stacked_buttons">24dp</dimen> <!-- Vertical margin applied between groups of controls. --> <dimen name="infobar_margin_above_control_groups">24dp</dimen> @@ -293,9 +293,6 @@ <dimen name="widget_column_width">80dp</dimen> <dimen name="widget_favicon_size">16dp</dimen> - <!-- Reader Mode dimensions --> - <dimen name="reader_mode_text_size">14sp</dimen> - <!-- Enhanced bookmarks dimensions --> <dimen name="enhanced_bookmark_item_corner_radius">3dp</dimen> <dimen name="enhanced_bookmark_item_icon_text_size">10dp</dimen>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/banners/SwipableOverlayView.java b/chrome/android/java/src/org/chromium/chrome/browser/banners/SwipableOverlayView.java index a15006835..346450d 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/banners/SwipableOverlayView.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/banners/SwipableOverlayView.java
@@ -5,23 +5,18 @@ package org.chromium.chrome.browser.banners; import android.animation.Animator; +import android.animation.Animator.AnimatorListener; import android.animation.AnimatorListenerAdapter; -import android.animation.AnimatorSet; import android.animation.ObjectAnimator; -import android.animation.PropertyValuesHolder; import android.content.Context; import android.graphics.Region; import android.util.AttributeSet; -import android.view.GestureDetector; -import android.view.GestureDetector.SimpleOnGestureListener; import android.view.Gravity; -import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.animation.DecelerateInterpolator; import android.view.animation.Interpolator; import android.widget.FrameLayout; -import android.widget.ScrollView; import org.chromium.chrome.browser.tab.EmptyTabObserver; import org.chromium.chrome.browser.tab.Tab; @@ -31,14 +26,14 @@ import org.chromium.ui.UiUtils; /** - * View that appears on the screen as the user scrolls on the page and can be swiped away. + * View that slides up from the bottom of the page and slides away as the user scrolls the page. * Meant to be tacked onto the {@link org.chromium.content.browser.ContentViewCore}'s view and * alerted when either the page scroll position or viewport size changes. * * GENERAL BEHAVIOR * This View is brought onto the screen by sliding upwards from the bottom of the screen. Afterward * the View slides onto and off of the screen vertically as the user scrolls upwards or - * downwards on the page. Users dismiss the View by swiping it away horizontally. + * downwards on the page. * * VERTICAL SCROLL CALCULATIONS * To determine how close the user is to the top of the page, the View must not only be informed of @@ -59,39 +54,18 @@ * from the initial value is used to determine the View's Y-translation. If a gesture is stopped, * the View will be snapped back into the center of the screen or entirely off of the screen, based * on how much of the View is visible, or where the user is currently located on the page. - * - * HORIZONTAL SCROLL CALCULATIONS - * Horizontal drags and swipes are used to dismiss the View. Translating the View far enough - * horizontally (with "enough" defined by the DISMISS_SWIPE_THRESHOLD AND DISMISS_FLING_THRESHOLD) - * triggers an animation that removes the View from the hierarchy. Failing to meet the threshold - * will result in the View being translated back to the center of the screen. - * - * Because the fling velocity handed in by Android is highly inaccurate and often indicates - * that a fling is moving in an opposite direction than expected, the scroll direction is tracked - * to determine which direction the user was dragging the View when the fling was initiated. When a - * fling is completed, the more forgiving FLING_THRESHOLD is used to determine how far a user must - * swipe to dismiss the View rather than try to use the fling velocity. */ -public abstract class SwipableOverlayView extends ScrollView { - private static final float ALPHA_THRESHOLD = 0.25f; - private static final float DISMISS_SWIPE_THRESHOLD = 0.75f; +public abstract class SwipableOverlayView extends FrameLayout { private static final float FULL_THRESHOLD = 0.5f; private static final float VERTICAL_FLING_SHOW_THRESHOLD = 0.2f; private static final float VERTICAL_FLING_HIDE_THRESHOLD = 0.9f; private static final long REATTACH_FADE_IN_MS = 250; - protected static final float ZERO_THRESHOLD = 0.001f; private static final int GESTURE_NONE = 0; private static final int GESTURE_SCROLLING = 1; private static final int GESTURE_FLINGING = 2; - private static final int DRAGGED_LEFT = -1; - private static final int DRAGGED_CANCEL = 0; - private static final int DRAGGED_RIGHT = 1; - - protected static final long MS_ANIMATION_DURATION = 250; - private static final long MS_DISMISS_FLING_THRESHOLD = MS_ANIMATION_DURATION * 2; - private static final long MS_SLOW_DISMISS = MS_ANIMATION_DURATION * 3; + private static final long ANIMATION_DURATION_MS = 250; /** Resets the state of the SwipableOverlayView, as needed. */ protected class SwipableOverlayViewTabObserver extends EmptyTabObserver { @@ -103,9 +77,6 @@ } } - // Detects when the user is dragging the View. - private final GestureDetector mGestureDetector; - // Detects when the user is dragging the ContentViewCore. private final GestureStateListener mGestureStateListener; @@ -113,7 +84,7 @@ private final View.OnLayoutChangeListener mLayoutChangeListener; // Monitors for animation completions and resets the state. - private final AnimatorListenerAdapter mAnimatorListenerAdapter; + private final AnimatorListener mAnimatorListener; // Interpolator used for the animation. private final Interpolator mInterpolator; @@ -125,16 +96,7 @@ private int mGestureState; // Animation currently being used to translate the View. - private AnimatorSet mCurrentAnimation; - - // Direction the user is horizontally dragging. - private int mDragDirection; - - // How quickly the user is horizontally dragging. - private float mDragXPerMs; - - // WHen the user first started dragging. - private long mDragStartMs; + private Animator mCurrentAnimation; // Used to determine when the layout has changed and the Viewport must be updated. private int mParentHeight; @@ -151,18 +113,12 @@ // Whether or not the View ever been fully displayed. private boolean mIsBeingDisplayedForFirstTime; - // Whether or not the View has been, or is being, dismissed. - private boolean mIsDismissed; - // The ContentViewCore to which the overlay is added. private ContentViewCore mContentViewCore; // Keeps the View from becoming visible when it normally would. private boolean mDoStayInvisible; - // Whether the View should be allowed to be swiped away. - private boolean mIsSwipable = true; - /** * Creates a SwipableOverlayView. * @param context Context for acquiring resources. @@ -170,12 +126,10 @@ */ public SwipableOverlayView(Context context, AttributeSet attrs) { super(context, attrs); - SimpleOnGestureListener gestureListener = createGestureListener(); - mGestureDetector = new GestureDetector(context, gestureListener); mGestureStateListener = createGestureStateListener(); mGestureState = GESTURE_NONE; mLayoutChangeListener = createLayoutChangeListener(); - mAnimatorListenerAdapter = createAnimatorListenerAdapter(); + mAnimatorListener = createAnimatorListener(); mInterpolator = new DecelerateInterpolator(1.0f); mTabObserver = createTabObserver(); @@ -184,11 +138,10 @@ } /** - * Indicates whether the View should be allowed to be swiped away. - * @param swipable Whether the View is reacts to horizontal gestures. + * @return TabObserver that is used to monitor a Tab. */ - protected void setIsSwipable(boolean swipable) { - mIsSwipable = swipable; + public TabObserver getTabObserver() { + return mTabObserver; } /** @@ -257,9 +210,9 @@ protected void onAttachedToWindow() { super.onAttachedToWindow(); if (!mDoStayInvisible) { - ObjectAnimator.ofFloat(this, View.ALPHA, 0.f, 1.f).setDuration(REATTACH_FADE_IN_MS) - .start(); setVisibility(VISIBLE); + setAlpha(0f); + animate().alpha(1f).setDuration(REATTACH_FADE_IN_MS); } if (!isAllowedToAutoHide()) setTranslationY(0.0f); } @@ -278,13 +231,6 @@ } /** - * @return TabObserver that is used to monitor a Tab. - */ - public TabObserver getTabObserver() { - return mTabObserver; - } - - /** * See {@link #android.view.ViewGroup.onLayout(boolean, int, int, int, int)}. */ @Override @@ -310,108 +256,13 @@ } // Update the known effective height of the View. - mTotalHeight = getMeasuredHeight(); - if (getLayoutParams() instanceof MarginLayoutParams) { - MarginLayoutParams params = (MarginLayoutParams) getLayoutParams(); - mTotalHeight += params.topMargin + params.bottomMargin; - } + MarginLayoutParams params = (MarginLayoutParams) getLayoutParams(); + mTotalHeight = getMeasuredHeight() + params.topMargin + params.bottomMargin; super.onLayout(changed, l, t, r, b); } /** - * See {@link #android.view.View.onTouchEvent(MotionEvent)}. - */ - @Override - public boolean onTouchEvent(MotionEvent event) { - if (!mIsSwipable) return false; - - if (mGestureDetector.onTouchEvent(event)) return true; - if (mCurrentAnimation != null) return true; - - int action = event.getActionMasked(); - if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) { - onFinishHorizontalGesture(); - return true; - } - return false; - } - - /** - * Creates a listener that monitors horizontal gestures performed on the View. - * @return The SimpleOnGestureListener that will monitor the View. - */ - private SimpleOnGestureListener createGestureListener() { - return new SimpleOnGestureListener() { - @Override - public boolean onDown(MotionEvent e) { - mGestureState = GESTURE_SCROLLING; - mDragDirection = DRAGGED_CANCEL; - mDragXPerMs = 0; - mDragStartMs = e.getEventTime(); - return true; - } - - @Override - public boolean onScroll(MotionEvent e1, MotionEvent e2, float distX, float distY) { - float distance = e2.getX() - e1.getX(); - setTranslationX(getTranslationX() + distance); - setAlpha(calculateAnimationAlpha()); - - // Because the Android-calculated fling velocity is highly unreliable, we track what - // direction the user is dragging the View from here. - mDragDirection = distance < 0 ? DRAGGED_LEFT : DRAGGED_RIGHT; - return true; - } - - @Override - public boolean onFling(MotionEvent e1, MotionEvent e2, float vX, float vY) { - mGestureState = GESTURE_FLINGING; - - // The direction and speed of the Android-given velocity feels completely disjoint - // from what the user actually perceives. - float androidXPerMs = Math.abs(vX) / 1000.0f; - - // Track how quickly the user has translated the view to this point. - float dragXPerMs = Math.abs(getTranslationX()) / (e2.getEventTime() - mDragStartMs); - - // Check if the velocity from the user's drag is higher; if so, use that one - // instead since that often feels more correct. - mDragXPerMs = mDragDirection * Math.max(androidXPerMs, dragXPerMs); - onFinishHorizontalGesture(); - return true; - } - - @Override - public boolean onSingleTapConfirmed(MotionEvent e) { - onViewClicked(); - return true; - } - - @Override - public void onShowPress(MotionEvent e) { - onViewPressed(e); - } - }; - } - - /** - * Called at the end of a user gesture on the banner to either return the banner to a neutral - * position in the center of the screen or dismiss it entirely. - */ - private void onFinishHorizontalGesture() { - mDragDirection = determineFinalHorizontalLocation(); - if (mDragDirection == DRAGGED_CANCEL) { - // Move the View back to the center of the screen. - createHorizontalSnapAnimation(true); - } else { - // User swiped the View away. Dismiss it. - onViewSwipedAway(); - dismiss(true); - } - } - - /** * Creates a listener than monitors the ContentViewCore for scrolls and flings. * The listener updates the location of this View to account for the user's gestures. * @return GestureStateListener to send to the ContentViewCore. @@ -516,84 +367,16 @@ * translates the View below the bottom-center of the screen so that it is * effectively invisible. */ - void createVerticalSnapAnimation(boolean visible) { + private void createVerticalSnapAnimation(boolean visible) { float translationY = visible ? 0.0f : mTotalHeight; float yDifference = Math.abs(translationY - getTranslationY()) / mTotalHeight; - long duration = (long) (MS_ANIMATION_DURATION * yDifference); - createAnimation(1.0f, 0, translationY, duration); - } + long duration = Math.max(0, (long) (ANIMATION_DURATION_MS * yDifference)); - /** - * Create an animation that snaps the View into position horizontally. - * @param visible If true, snaps the View to the bottom-center of the screen. If false, - * translates the View to the side of the screen. - */ - private void createHorizontalSnapAnimation(boolean visible) { - if (visible) { - // Move back to the center of the screen. - createAnimation(1.0f, 0.0f, getTranslationY(), MS_ANIMATION_DURATION); - } else { - if (mDragDirection == DRAGGED_CANCEL) { - // No direction was selected - mDragDirection = DRAGGED_LEFT; - } - - float finalX = mDragDirection * getWidth(); - - // Determine how long it will take for the banner to leave the screen. - long duration = MS_ANIMATION_DURATION; - switch (mGestureState) { - case GESTURE_FLINGING: - duration = (long) calculateMsRequiredToFlingOffScreen(); - break; - case GESTURE_NONE: - // Explicitly use a slow animation to help educate the user about swiping. - duration = MS_SLOW_DISMISS; - break; - default: - break; - } - - createAnimation(0.0f, finalX, getTranslationY(), duration); - } - } - - /** - * Dismisses the View, animating it moving off of the screen if needed. - * @param horizontally True if the View is being dismissed to the side of the screen. - */ - protected boolean dismiss(boolean horizontally) { - if (getParent() == null || mIsDismissed) return false; - - mIsDismissed = true; - if (horizontally) { - createHorizontalSnapAnimation(false); - } else { - createVerticalSnapAnimation(false); - } - return true; - } - - /** - * @return Whether or not the View has been dismissed. - */ - protected boolean isDismissed() { - return mIsDismissed; - } - - /** - * Calculates how transparent the View should be. - * - * The transparency value is proportional to how far the View has been swiped away from the - * center of the screen. The {@link ALPHA_THRESHOLD} determines at what point the View should - * start fading away. - * @return The alpha value to use for the View. - */ - private float calculateAnimationAlpha() { - float percentageSwiped = Math.abs(getTranslationX() / getWidth()); - float percentageAdjusted = Math.max(0.0f, percentageSwiped - ALPHA_THRESHOLD); - float alphaRange = 1.0f - ALPHA_THRESHOLD; - return 1.0f - percentageAdjusted / alphaRange; + mCurrentAnimation = ObjectAnimator.ofFloat(this, View.TRANSLATION_Y, translationY); + mCurrentAnimation.setDuration(duration); + mCurrentAnimation.addListener(mAnimatorListener); + mCurrentAnimation.setInterpolator(mInterpolator); + mCurrentAnimation.start(); } private int computeScrollDifference(int scrollOffsetY, int scrollExtentY) { @@ -601,75 +384,13 @@ } /** - * Determine where the View needs to move. If the user hasn't tried hard enough to dismiss - * the View, move it back to the center. - * @return DRAGGED_CANCEL if the View should return to a neutral center position. - * DRAGGED_LEFT if the View should be dismissed to the left. - * DRAGGED_RIGHT if the View should be dismissed to the right. - */ - private int determineFinalHorizontalLocation() { - if (mGestureState == GESTURE_FLINGING) { - // Because of the unreliability of the fling velocity, we ignore it and instead rely on - // the direction the user was last dragging the View. Moreover, we lower the - // translation threshold for dismissal, requiring the View to translate off screen - // within a reasonable time frame. - float msRequired = calculateMsRequiredToFlingOffScreen(); - if (msRequired > MS_DISMISS_FLING_THRESHOLD) return DRAGGED_CANCEL; - } else if (mGestureState == GESTURE_SCROLLING) { - // Check if the user has dragged the View far enough to be dismissed. - float dismissPercentage = DISMISS_SWIPE_THRESHOLD; - float dismissThreshold = getWidth() * dismissPercentage; - if (Math.abs(getTranslationX()) < dismissThreshold) return DRAGGED_CANCEL; - } - - return mDragDirection; - } - - /** - * Assuming a linear velocity, determine how long it would take for the View to translate off - * of the screen. - */ - private float calculateMsRequiredToFlingOffScreen() { - float remainingDifference = mDragDirection * getWidth() - getTranslationX(); - return Math.abs(remainingDifference / mDragXPerMs); - } - - /** - * Creates an animation that slides the View to the given location and visibility. - * @param alpha How opaque the View should be at the end. - * @param x X-coordinate of the final translation. - * @param y Y-coordinate of the final translation. - * @param duration How long the animation should run for. - */ - private void createAnimation(float alpha, float x, float y, long duration) { - Animator alphaAnimator = - ObjectAnimator.ofPropertyValuesHolder(this, - PropertyValuesHolder.ofFloat("alpha", getAlpha(), alpha)); - Animator translationXAnimator = - ObjectAnimator.ofPropertyValuesHolder(this, - PropertyValuesHolder.ofFloat("translationX", getTranslationX(), x)); - Animator translationYAnimator = - ObjectAnimator.ofPropertyValuesHolder(this, - PropertyValuesHolder.ofFloat("translationY", getTranslationY(), y)); - - mCurrentAnimation = new AnimatorSet(); - mCurrentAnimation.setDuration(Math.max(duration, 0)); - mCurrentAnimation.playTogether(alphaAnimator, translationXAnimator, translationYAnimator); - mCurrentAnimation.addListener(mAnimatorListenerAdapter); - mCurrentAnimation.setInterpolator(mInterpolator); - mCurrentAnimation.start(); - } - - /** * Creates an AnimatorListenerAdapter that cleans up after an animation is completed. * @return {@link AnimatorListenerAdapter} to use for animations. */ - private AnimatorListenerAdapter createAnimatorListenerAdapter() { + private AnimatorListener createAnimatorListener() { return new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { - if (mIsDismissed) removeFromParentView(); - mGestureState = GESTURE_NONE; mCurrentAnimation = null; mIsBeingDisplayedForFirstTime = false; @@ -688,25 +409,16 @@ } /** - * Cancels the current animation, if the View isn't being dismissed. + * Cancels the current animation, unless the View is coming onto the screen for the first time. * @return True if the animation was canceled or wasn't running, false otherwise. */ private boolean cancelCurrentAnimation() { - if (!mayCancelCurrentAnimation()) return false; + if (mIsBeingDisplayedForFirstTime) return false; if (mCurrentAnimation != null) mCurrentAnimation.cancel(); return true; } /** - * Determines whether or not the animation can be interrupted. Animations may not be canceled - * when the View is being dismissed or when it's coming onto screen for the first time. - * @return Whether or not the animation may be interrupted. - */ - private boolean mayCancelCurrentAnimation() { - return !mIsBeingDisplayedForFirstTime && !mIsDismissed; - } - - /** * @return Whether the SwipableOverlayView is allowed to hide itself on scroll. */ protected boolean isAllowedToAutoHide() { @@ -721,30 +433,12 @@ */ @Override public boolean gatherTransparentRegion(Region region) { - float translationX = getTranslationX(); float translationY = getTranslationY(); - setTranslationX(0); setTranslationY(0); boolean result = super.gatherTransparentRegion(region); - // Restoring TranslationX/Y invalidates this view unnecessarily. However, this function + // Restoring TranslationY invalidates this view unnecessarily. However, this function // is called as part of layout, which implies a full redraw is about to occur anyway. - setTranslationX(translationX); setTranslationY(translationY); return result; } - - /** - * Called when the View has been swiped away by the user. - */ - protected abstract void onViewSwipedAway(); - - /** - * Called when the View has been clicked. - */ - protected abstract void onViewClicked(); - - /** - * Called when the View needs to show that it's been pressed. - */ - protected abstract void onViewPressed(MotionEvent event); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/crash/MinidumpUploadService.java b/chrome/android/java/src/org/chromium/chrome/browser/crash/MinidumpUploadService.java index b36cfb9..97dd6ff1 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/crash/MinidumpUploadService.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/crash/MinidumpUploadService.java
@@ -7,30 +7,33 @@ import android.app.IntentService; import android.content.Context; import android.content.Intent; +import android.support.annotation.StringDef; import org.chromium.base.Log; +import org.chromium.base.StreamUtil; import org.chromium.base.VisibleForTesting; -import org.chromium.base.metrics.RecordUserAction; +import org.chromium.base.metrics.RecordHistogram; import org.chromium.chrome.browser.preferences.ChromePreferenceManager; +import java.io.BufferedReader; import java.io.File; +import java.io.FileReader; +import java.io.IOException; /** * Service that is responsible for uploading crash minidumps to the Google crash server. */ public class MinidumpUploadService extends IntentService { - private static final String TAG = "MinidmpUploadService"; - // Intent actions private static final String ACTION_FIND_LAST = "com.google.android.apps.chrome.crash.ACTION_FIND_LAST"; + @VisibleForTesting - static final String ACTION_FIND_ALL = - "com.google.android.apps.chrome.crash.ACTION_FIND_ALL"; + static final String ACTION_FIND_ALL = "com.google.android.apps.chrome.crash.ACTION_FIND_ALL"; + @VisibleForTesting - static final String ACTION_UPLOAD = - "com.google.android.apps.chrome.crash.ACTION_UPLOAD"; + static final String ACTION_UPLOAD = "com.google.android.apps.chrome.crash.ACTION_UPLOAD"; // Intent bundle keys @VisibleForTesting @@ -44,6 +47,23 @@ @VisibleForTesting static final int MAX_TRIES_ALLOWED = 3; + /** + * Histogram related constants. + */ + private static final String HISTOGRAM_NAME_PREFIX = "Tab.AndroidCrashUpload_"; + private static final int HISTOGRAM_MAX = 2; + private static final int FAILURE = 0; + private static final int SUCCESS = 1; + + @StringDef({BROWSER, RENDERER, GPU, OTHER}) + public @interface ProcessType {} + static final String BROWSER = "Browser"; + static final String RENDERER = "Renderer"; + static final String GPU = "GPU"; + static final String OTHER = "Other"; + + static final String[] TYPES = {BROWSER, RENDERER, GPU, OTHER}; + public MinidumpUploadService() { super(TAG); setIntentRedelivery(true); @@ -55,7 +75,6 @@ */ private void tryPopulateLogcat(Intent redirectAction) { redirectAction.putExtra(FINISHED_LOGCAT_EXTRACTION_KEY, true); - Context context = getApplicationContext(); CrashFileManager fileManager = new CrashFileManager(context.getCacheDir()); File[] dumps = fileManager.getMinidumpWithoutLogcat(); @@ -102,19 +121,25 @@ /** * Stores the successes and failures from uploading crash to UMA, - * and clears them from breakpad. */ public static void storeBreakpadUploadStatsInUma(ChromePreferenceManager pref) { - for (int success = pref.getBreakpadUploadSuccessCount(); success > 0; success--) { - RecordUserAction.record("MobileBreakpadUploadSuccess"); - } + for (String type : TYPES) { + for (int success = pref.getCrashSuccessUploadCount(type); success > 0; success--) { + RecordHistogram.recordEnumeratedHistogram( + HISTOGRAM_NAME_PREFIX + type, + SUCCESS, + HISTOGRAM_MAX); + } + for (int fail = pref.getCrashFailureUploadCount(type); fail > 0; fail--) { + RecordHistogram.recordEnumeratedHistogram( + HISTOGRAM_NAME_PREFIX + type, + FAILURE, + HISTOGRAM_MAX); + } - for (int fail = pref.getBreakpadUploadFailCount(); fail > 0; fail--) { - RecordUserAction.record("MobileBreakpadUploadFail"); + pref.setCrashSuccessUploadCount(type, 0); + pref.setCrashFailureUploadCount(type, 0); } - - pref.setBreakpadUploadSuccessCount(0); - pref.setBreakpadUploadFailCount(0); } private void handleFindAndUploadLastCrash(Intent intent) { @@ -208,7 +233,7 @@ if (uploadStatus == MinidumpUploadCallable.UPLOAD_SUCCESS) { // Only update UMA stats if an intended and successful upload. - ChromePreferenceManager.getInstance(this).incrementBreakpadUploadSuccessCount(); + incrementCrashSuccessUploadCount(getNewNameAfterSuccessfulUpload(minidumpFileName)); } else if (uploadStatus == MinidumpUploadCallable.UPLOAD_FAILURE) { // Unable to upload minidump. Incrementing try number and restarting. @@ -221,7 +246,7 @@ MinidumpUploadRetry.scheduleRetry(getApplicationContext()); } else { // Only record failure to UMA after we have maxed out the allotted tries. - ChromePreferenceManager.getInstance(this).incrementBreakpadUploadFailCount(); + incrementCrashFailureUploadCount(newName); Log.d(TAG, "Giving up on trying to upload " + minidumpFileName + "after " + tries + " number of tries."); } @@ -231,6 +256,65 @@ } } + private static String getNewNameAfterSuccessfulUpload(String fileName) { + return fileName.replace("dmp", "up"); + } + + @ProcessType + @VisibleForTesting + protected static String getCrashType(String fileName) { + // Read file and get the line containing name="ptype". + BufferedReader fileReader = null; + try { + fileReader = new BufferedReader(new FileReader(fileName)); + String line; + while ((line = fileReader.readLine()) != null) { + if (line.equals("Content-Disposition: form-data; name=\"ptype\"")) { + // Crash type is on the line after the next line. + fileReader.readLine(); + String crashType = fileReader.readLine(); + if (crashType == null) { + return OTHER; + } + + if (crashType.equals("browser")) { + return BROWSER; + } + + if (crashType.equals("renderer")) { + return RENDERER; + } + + if (crashType.equals("gpu-process")) { + return GPU; + } + + return OTHER; + } + } + } catch (IOException e) { + Log.w(TAG, "Error while reading crash file.", e.toString()); + } finally { + StreamUtil.closeQuietly(fileReader); + } + return OTHER; + } + + /** + * Increment the count of success/failure by 1 and distinguish between different types of + * crashes by looking into the file. + * @param fileName is the name of a minidump file that contains the type of crash. + */ + private void incrementCrashSuccessUploadCount(String fileName) { + ChromePreferenceManager.getInstance(this) + .incrementCrashSuccessUploadCount(getCrashType(fileName)); + } + + private void incrementCrashFailureUploadCount(String fileName) { + ChromePreferenceManager.getInstance(this) + .incrementCrashFailureUploadCount(getCrashType(fileName)); + } + /** * Factory method for creating minidump callables. * @@ -246,7 +330,7 @@ } /** - * Attempts to upload all minidump files using the given {@link android.content.Context}. + * Attempts to upload all minidump files using the given {@link android.content.Context}. * * Note that this method is asynchronous. All that is guaranteed is that * upload attempts will be enqueued.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/datausage/ExternalDataUseObserver.java b/chrome/android/java/src/org/chromium/chrome/browser/datausage/ExternalDataUseObserver.java index fc51620f..1a154774 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/datausage/ExternalDataUseObserver.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/datausage/ExternalDataUseObserver.java
@@ -6,6 +6,9 @@ import android.content.Context; +import org.chromium.base.ApplicationState; +import org.chromium.base.ApplicationStatus; +import org.chromium.base.PackageUtils; import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.JNINamespace; import org.chromium.base.annotations.NativeClassQualifiedName; @@ -13,15 +16,65 @@ /** * This class provides a base class implementation of a data use observer that is external to - * Chromium. This class should be accessed only on IO thread. + * Chromium. This class should be accessed only on UI thread. */ @JNINamespace("chrome::android") public class ExternalDataUseObserver { /** + * Listens for application state changes and whenever Chromium state changes to running, checks + * and nofifies {@link #ExternalDataUseObserverBridge} if the control app is installed. + */ + private class ControlAppManager implements ApplicationStatus.ApplicationStateListener { + // Package name of the control app. + private final String mControlAppPackageName; + + // True if the control app is installed. + private boolean mInstalled; + + ControlAppManager(String controlAppPackageName) { + mControlAppPackageName = controlAppPackageName; + mInstalled = false; + ApplicationStatus.registerApplicationStateListener(this); + checkAndNotifyPackageInstall(); + } + + @Override + public void onApplicationStateChange(int newState) { + if (!mInstalled && newState == ApplicationState.HAS_RUNNING_ACTIVITIES) { + checkAndNotifyPackageInstall(); + } + } + + /** + * Checks if the control app is installed and notifies {@link + * #ExternalDataUseObserverBridge}. + */ + private void checkAndNotifyPackageInstall() { + // Check if native object is destroyed. This may happen at the time of Chromium + // shutdown. + if (mNativeExternalDataUseObserverBridge == 0) { + return; + } + if (mControlAppPackageName != null && !mControlAppPackageName.isEmpty() + && PackageUtils.getPackageVersion( + ApplicationStatus.getApplicationContext(), mControlAppPackageName) + != -1) { + mInstalled = true; + nativeOnControlAppInstalled(mNativeExternalDataUseObserverBridge); + } + } + } + + /** * Pointer to the native ExternalDataUseObserverBridge object. */ private long mNativeExternalDataUseObserverBridge; + /** + * {@link #ControlAppManager} object that notifies when control app is installed. + */ + private ControlAppManager mControlAppManager; + @CalledByNative private static ExternalDataUseObserver create(Context context, long nativePtr) { return ((ChromeApplication) context).createExternalDataUseObserver(nativePtr); @@ -37,6 +90,15 @@ } /** + * Sets the package name of the control app. + * @param controlAppPackageName package name of the control app. + */ + @CalledByNative + protected void setControlAppPackageName(String controlAppPackageName) { + mControlAppManager = new ControlAppManager(controlAppPackageName); + } + + /** * Notification that the native object has been destroyed. */ @CalledByNative @@ -118,4 +180,7 @@ @NativeClassQualifiedName("ExternalDataUseObserverBridge") private native void nativeOnReportDataUseDone( long nativeExternalDataUseObserver, boolean success); + + @NativeClassQualifiedName("ExternalDataUseObserverBridge") + private native void nativeOnControlAppInstalled(long nativeExternalDataUseObserver); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/ReaderModeButtonView.java b/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/ReaderModeButtonView.java deleted file mode 100644 index 17cf1db..0000000 --- a/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/ReaderModeButtonView.java +++ /dev/null
@@ -1,89 +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. - -package org.chromium.chrome.browser.dom_distiller; - -import android.content.Context; -import android.util.AttributeSet; -import android.view.LayoutInflater; -import android.view.MotionEvent; -import android.view.View; - -import org.chromium.chrome.R; -import org.chromium.chrome.browser.banners.SwipableOverlayView; -import org.chromium.content.browser.ContentViewCore; - -/** - * Reader Mode "infobar"-style button at the bottom of the screen. - */ -public class ReaderModeButtonView extends SwipableOverlayView { - private ReaderModeButtonViewDelegate mReaderModeButtonViewDelegate; - - /** - * Called when the user swipes the button away or clicks it. - */ - public interface ReaderModeButtonViewDelegate { - /* Called when the user clicks on the button. */ - void onClick(); - /* Called when the user swipes-away the button. */ - void onSwipeAway(); - } - - /** - * Creates a ReaderModeButtonView and adds it to the given ContentViewCore. - * - * @param contentViewCore ContentViewCore for the ReaderModeButtonView. - * @param buttonViewDelegate A delegate for onClick/onDismiss events. - */ - public static ReaderModeButtonView create(ContentViewCore contentViewCore, - ReaderModeButtonViewDelegate buttonViewDelegate) { - if (contentViewCore == null) return null; - if (contentViewCore.getWebContents() == null) return null; - Context context = contentViewCore.getContext(); - if (context == null) return null; - - ReaderModeButtonView view = - (ReaderModeButtonView) LayoutInflater.from(context) - .inflate(R.layout.reader_mode_view, null); - view.initialize(buttonViewDelegate); - view.setContentViewCore(contentViewCore); - view.addToParentView(contentViewCore.getContainerView()); - return view; - } - - /** - * Creates a ReaderModeButtonView. - * - * @param context Context for acquiring resources. - * @param attrs Attributes from the XML layout inflation. - */ - public ReaderModeButtonView(Context context, AttributeSet attrs) { - super(context, attrs); - } - - private void initialize(ReaderModeButtonViewDelegate buttonViewDelegate) { - mReaderModeButtonViewDelegate = buttonViewDelegate; - findViewById(R.id.main_close).setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - mReaderModeButtonViewDelegate.onSwipeAway(); - } - }); - this.setClickable(true); - } - - @Override - protected void onViewClicked() { - mReaderModeButtonViewDelegate.onClick(); - } - - @Override - protected void onViewPressed(MotionEvent event) { - } - - @Override - protected void onViewSwipedAway() { - mReaderModeButtonViewDelegate.onSwipeAway(); - } -}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/ReaderModeManager.java b/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/ReaderModeManager.java index a121ec9d..ab944dc 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/ReaderModeManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/ReaderModeManager.java
@@ -17,6 +17,7 @@ import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel.PanelState; import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel.StateChangeReason; import org.chromium.chrome.browser.compositor.bottombar.readermode.ReaderModePanel; +import org.chromium.chrome.browser.device.DeviceClassManager; import org.chromium.chrome.browser.infobar.InfoBar; import org.chromium.chrome.browser.infobar.InfoBarContainer; import org.chromium.chrome.browser.infobar.InfoBarContainer.InfoBarContainerObserver; @@ -395,7 +396,8 @@ || mTabStatusMap.get(currentTabId).isDismissed() || mIsInfobarContainerShown || mIsFindToolbarShowing - || mIsFullscreenModeEntered) { + || mIsFullscreenModeEntered + || DeviceClassManager.isAccessibilityModeEnabled(mChromeActivity)) { return; } mReaderModePanel.requestPanelShow(reason); @@ -405,9 +407,9 @@ * Orientation change event handler. Simply close the panel. */ public void onOrientationChange() { - // Close to reset the panel then immediately show again. - closeReaderPanel(StateChangeReason.UNKNOWN, false); - requestReaderPanelShow(StateChangeReason.UNKNOWN); + if (mReaderModePanel != null) { + mReaderModePanel.onOrientationChanged(); + } } /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegate.java index daef539..6d635376 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegate.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegate.java
@@ -61,10 +61,11 @@ boolean needsToCloseTab); /** + * @param url The requested url. * @param tab The current tab. * @return Whether we should block the navigation and request file access before proceeding. */ - boolean shouldRequestFileAccess(Tab tab); + boolean shouldRequestFileAccess(String url, Tab tab); /** * Trigger a UI affordance that will ask the user to grant file access. After the access
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegateImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegateImpl.java index 5e0af261..8825ccb 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegateImpl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegateImpl.java
@@ -26,6 +26,7 @@ import org.chromium.base.ApplicationState; import org.chromium.base.ApplicationStatus; +import org.chromium.base.PathUtils; import org.chromium.base.ThreadUtils; import org.chromium.chrome.R; import org.chromium.chrome.browser.ChromeActivity; @@ -296,10 +297,17 @@ } @Override - public boolean shouldRequestFileAccess(Tab tab) { + public boolean shouldRequestFileAccess(String url, Tab tab) { // If the tab is null, then do not attempt to prompt for access. if (tab == null) return false; + // If the url points inside of Chromium's data directory, no permissions are necessary. + // This is required to prevent permission prompt when uses wants to access offline pages. + if (url.startsWith("file://" + PathUtils.getDataDirectory( + mActivity.getApplicationContext()))) { + return false; + } + return !tab.getWindowAndroid().hasPermission(permission.WRITE_EXTERNAL_STORAGE) && tab.getWindowAndroid().canRequestPermission(permission.WRITE_EXTERNAL_STORAGE); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandler.java index 3d83485..16388f6 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandler.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandler.java
@@ -172,7 +172,7 @@ // to Chrome. This check should happen for reloads, navigations, etc..., which is why // it occurs before the subsequent blocks. if (params.getUrl().startsWith("file:") - && mDelegate.shouldRequestFileAccess(params.getTab())) { + && mDelegate.shouldRequestFileAccess(params.getUrl(), params.getTab())) { mDelegate.startFileIntent( intent, params.getReferrerUrl(), params.getTab(), params.shouldCloseContentsOnOverrideUrlLoadingAndLaunchIntent());
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunSignInProcessor.java b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunSignInProcessor.java index a26bc42..888505c0 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunSignInProcessor.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunSignInProcessor.java
@@ -90,16 +90,12 @@ return; } - final boolean delaySync = getFirstRunFlowSignInSetupSync(activity); - final int delaySyncType = delaySync - ? SigninManager.SIGNIN_SYNC_SETUP_IN_PROGRESS - : SigninManager.SIGNIN_SYNC_IMMEDIATELY; + final boolean setUpSync = getFirstRunFlowSignInSetupSync(activity); signinManager.signInToSelectedAccount(activity, account, - SigninManager.SIGNIN_TYPE_INTERACTIVE, delaySyncType, false, - new SignInFlowObserver() { + SigninManager.SIGNIN_TYPE_INTERACTIVE, new SignInFlowObserver() { private void completeSignIn() { // Show sync settings if user pressed the "Settings" button. - if (delaySync) { + if (setUpSync) { openSyncSettings(activity); } setFirstRunFlowSignInComplete(activity, true); @@ -122,6 +118,7 @@ */ private static void openSyncSettings(Activity activity) { if (ProfileSyncService.get() == null) return; + assert !ProfileSyncService.get().hasSyncSetupCompleted(); String accountName = ChromeSigninController.get(activity).getSignedInAccountName(); if (TextUtils.isEmpty(accountName)) return; Intent intent = PreferencesLauncher.createIntentForSettingsPage(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/ForcedSigninProcessor.java b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/ForcedSigninProcessor.java index f4b90b4..b2ec65f7 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/ForcedSigninProcessor.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/ForcedSigninProcessor.java
@@ -65,7 +65,6 @@ || googleAccounts.length != 1) { return; } - signinManager.signInToSelectedAccount(null, googleAccounts[0], signinType, - SigninManager.SIGNIN_SYNC_IMMEDIATELY, false, null); + signinManager.signInToSelectedAccount(null, googleAccounts[0], signinType, null); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/AppBannerInfoBarAndroid.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/AppBannerInfoBarAndroid.java index b30d025..950cb05 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/AppBannerInfoBarAndroid.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/AppBannerInfoBarAndroid.java
@@ -74,9 +74,6 @@ Context context = getContext(); if (mAppData != null) { // Native app. - ImageView playLogo = new ImageView(layout.getContext()); - playLogo.setImageResource(R.drawable.google_play); - layout.setCustomViewInButtonRow(playLogo); layout.getPrimaryButton().setButtonColor(ApiCompatibilityUtils.getColor( getContext().getResources(), R.color.app_banner_install_button_bg)); @@ -107,6 +104,20 @@ } @Override + protected void setButtons(InfoBarLayout layout, String primaryText, String secondaryText) { + if (mAppData == null) { + // The banner for web apps uses standard buttons. + super.setButtons(layout, primaryText, secondaryText); + } else { + // The banner for native apps shows a Play logo in place of a secondary button. + assert secondaryText == null; + ImageView playLogo = new ImageView(layout.getContext()); + playLogo.setImageResource(R.drawable.google_play); + layout.setBottomViews(primaryText, playLogo, InfoBarDualControlLayout.ALIGN_APART); + } + } + + @Override public void onButtonClicked(boolean isPrimaryButton) { if (isPrimaryButton && mInstallState == INSTALL_STATE_INSTALLING) { setControlsEnabled(true);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/ConfirmInfoBar.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/ConfirmInfoBar.java index a4afa8a..0485ad8d 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/ConfirmInfoBar.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/ConfirmInfoBar.java
@@ -77,10 +77,24 @@ @Override public void createContent(InfoBarLayout layout) { - layout.setButtons(mPrimaryButtonText, mSecondaryButtonText); + setButtons(layout, mPrimaryButtonText, mSecondaryButtonText); if (mLinkText != null) layout.setMessageLinkText(mLinkText); } + /** + * If your custom infobar overrides this function, YOU'RE PROBABLY DOING SOMETHING WRONG. + * + * Adds buttons to the infobar. This should only be overridden in cases where an infobar + * requires adding something other than a button for its secondary View on the bottom row + * (almost never). + * + * @param primaryText Text to display on the primary button. + * @param secondaryText Text to display on the secondary button. May be null. + */ + protected void setButtons(InfoBarLayout layout, String primaryText, String secondaryText) { + layout.setButtons(primaryText, secondaryText); + } + private static boolean hasPermission(Context context, String permission) { return context.checkPermission(permission, Process.myPid(), Process.myUid()) != PackageManager.PERMISSION_DENIED;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/DataReductionProxyInfoBar.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/DataReductionProxyInfoBar.java index 9d534f0..8ea856d 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/DataReductionProxyInfoBar.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/DataReductionProxyInfoBar.java
@@ -36,11 +36,6 @@ } @Override - public void createContent(InfoBarLayout layout) { - layout.setButtons(sLinkText, null); - } - - @Override public void onButtonClicked(boolean isPrimaryButton) { if (!isPrimaryButton) return; onLinkClicked();
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 907c6eab..c0098ba4 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
@@ -38,13 +38,6 @@ // This points to the InfoBarAndroid class not any of its subclasses. private long mNativeInfoBarPtr; - // Used by tests to reference infobars. - private final int mId; - private static int sIdCounter = 0; - private static int generateId() { - return sIdCounter++; - } - /** * @param listener Listens to when buttons have been clicked on the InfoBar. * @param iconDrawableId ID of the resource to use for the Icon. If 0, no icon will be shown. @@ -53,7 +46,6 @@ public InfoBar(InfoBarListeners.Dismiss listener, int iconDrawableId, Bitmap iconBitmap, CharSequence message) { mListener = listener; - mId = generateId(); mIconDrawableId = iconDrawableId; mIconBitmap = iconBitmap; mMessage = message; @@ -221,11 +213,6 @@ } @VisibleForTesting - public int getId() { - return mId; - } - - @VisibleForTesting public void setDismissedListener(InfoBarListeners.Dismiss listener) { mListener = listener; }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/InfoBarContainer.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/InfoBarContainer.java index 7bd04bf..830205e 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/InfoBarContainer.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/InfoBarContainer.java
@@ -6,7 +6,6 @@ import android.content.Context; import android.view.Gravity; -import android.view.MotionEvent; import android.view.ViewGroup; import android.widget.FrameLayout; @@ -99,7 +98,6 @@ public InfoBarContainer(Context context, int tabId, ViewGroup parentView, Tab tab) { super(context, null); tab.addObserver(getTabObserver()); - setIsSwipable(false); // TODO(newt): move this workaround into the infobar views if/when they're scrollable. // Workaround for http://crbug.com/407149. See explanation in onMeasure() below. @@ -282,7 +280,7 @@ * @return all of the InfoBars held in this container. */ @VisibleForTesting - public ArrayList<InfoBar> getInfoBars() { + public ArrayList<InfoBar> getInfoBarsForTesting() { return mInfoBars; } @@ -300,21 +298,6 @@ return sIsAllowedToAutoHide; } - @Override - protected void onViewSwipedAway() { - assert false; - } - - @Override - protected void onViewClicked() { - assert false; - } - - @Override - protected void onViewPressed(MotionEvent event) { - assert false; - } - private native long nativeInit(); private native void nativeSetWebContents( long nativeInfoBarContainerAndroid, WebContents webContents);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/InfoBarControlLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/InfoBarControlLayout.java index 7bb2d2de..5c85dbee 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/InfoBarControlLayout.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/InfoBarControlLayout.java
@@ -36,6 +36,9 @@ * layout algorithm to match. * * TODO(dfalcantara): Standardize all the possible control types. + * TODO(dfalcantara): The line spacing multiplier is applied to all lines in JB & KK, even if the + * TextView has only one line. This throws off vertical alignment. Find a + * solution that hopefully doesn't involve subclassing the TextView. */ public final class InfoBarControlLayout extends ViewGroup { @@ -60,7 +63,6 @@ } } - private final int mMaxInfoBarWidth; private final int mMarginBetweenRows; private final int mMarginBetweenColumns; @@ -71,7 +73,6 @@ super(context); Resources resources = context.getResources(); - mMaxInfoBarWidth = resources.getDimensionPixelSize(R.dimen.infobar_max_width); mMarginBetweenRows = resources.getDimensionPixelSize(R.dimen.infobar_control_margin_between_rows); mMarginBetweenColumns = @@ -84,7 +85,7 @@ : "Height of this layout cannot be constrained."; int fullWidth = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.UNSPECIFIED - ? mMaxInfoBarWidth : MeasureSpec.getSize(widthMeasureSpec); + ? Integer.MAX_VALUE : MeasureSpec.getSize(widthMeasureSpec); int columnWidth = Math.max(0, (fullWidth - mMarginBetweenColumns) / 2); int atMostFullWidthSpec = MeasureSpec.makeMeasureSpec(fullWidth, MeasureSpec.AT_MOST); @@ -185,6 +186,43 @@ } /** + * Adds an icon with a descriptive message to the layout. + * + * ----------------------------------------------------- + * | ICON | PRIMARY MESSAGE SECONDARY MESSAGE | + * ----------------------------------------------------- + * If an icon is not provided, the ImageView that would normally show it is hidden. + * + * @param iconResourceId ID of the drawable to use for the icon. + * @param primaryMessage Message to display for the toggle. + * @param secondaryMessage Additional descriptive text for the toggle. May be null. + */ + public View addIcon( + int iconResourceId, CharSequence primaryMessage, CharSequence secondaryMessage) { + LinearLayout layout = (LinearLayout) LayoutInflater.from(getContext()).inflate( + R.layout.infobar_control_icon_with_description, this, false); + addView(layout, new ControlLayoutParams()); + + ImageView iconView = (ImageView) layout.findViewById(R.id.control_icon); + iconView.setImageResource(iconResourceId); + + // The primary message text is always displayed. + TextView primaryView = (TextView) layout.findViewById(R.id.control_message); + primaryView.setText(primaryMessage); + + // The secondary message text is optional. + TextView secondaryView = + (TextView) layout.findViewById(R.id.control_secondary_message); + if (secondaryMessage == null) { + layout.removeView(secondaryView); + } else { + secondaryView.setText(secondaryMessage); + } + + return layout; + } + + /** * Creates a standard toggle switch and adds it to the layout. * * ------------------------------------------------- @@ -203,14 +241,14 @@ R.layout.infobar_control_toggle, this, false); addView(switchLayout, new ControlLayoutParams()); - ImageView iconView = (ImageView) switchLayout.findViewById(R.id.control_toggle_icon); + ImageView iconView = (ImageView) switchLayout.findViewById(R.id.control_icon); if (iconResourceId == 0) { switchLayout.removeView(iconView); } else { iconView.setImageResource(iconResourceId); } - TextView messageView = (TextView) switchLayout.findViewById(R.id.control_toggle_message); + TextView messageView = (TextView) switchLayout.findViewById(R.id.control_message); messageView.setText(toggleMessage); SwitchCompat switchView =
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/InfoBarDualControlLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/InfoBarDualControlLayout.java new file mode 100644 index 0000000..0bf011d --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/InfoBarDualControlLayout.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.infobar; + +import android.content.Context; +import android.content.res.Resources; +import android.util.AttributeSet; +import android.view.View; +import android.view.ViewGroup; + +import org.chromium.base.ApiCompatibilityUtils; +import org.chromium.base.VisibleForTesting; +import org.chromium.chrome.R; + +/** + * Automatically lays out one or two Views for an infobar, placing them on the same row if possible + * and stacking them otherwise. + * + * Use cases of this Layout include placement of infobar buttons and placement of TextViews inside + * of spinner controls (http://goto.google.com/infobar-spec). + * + * Layout parameters (i.e. margins) are ignored to enforce infobar consistency. Alignment defines + * where the controls are placed (for RTL, flip everything): + * + * ALIGN_START ALIGN_APART ALIGN_END + * ----------------------------- ----------------------------- ----------------------------- + * | PRIMARY SECONDARY | | SECONDARY PRIMARY | | SECONDARY PRIMARY | + * ----------------------------- ----------------------------- ----------------------------- + * + * Controls are stacked automatically when they don't fit on the same row, with each control taking + * up the full available width and with the primary control sitting on top of the secondary. + * ----------------------------- + * | PRIMARY------------------ | + * | SECONDARY---------------- | + * ----------------------------- + * + * TODO(dfalcantara): Remove the VisibleForTesting annotations when controls that this land. + */ +@VisibleForTesting +public final class InfoBarDualControlLayout extends ViewGroup { + public static final int ALIGN_START = 0; + public static final int ALIGN_END = 1; + public static final int ALIGN_APART = 2; + + private final int mHorizontalMarginBetweenViews; + + private int mAlignment = ALIGN_START; + private int mStackedMargin; + + private boolean mIsStacked; + private View mPrimaryView; + private View mSecondaryView; + + /** + * Construct a new InfoBarDualControlLayout. + * + * See {@link ViewGroup} for parameter details. attrs may be null if constructed dynamically. + */ + @VisibleForTesting + public InfoBarDualControlLayout(Context context, AttributeSet attrs) { + super(context, attrs); + + // Cache dimensions. + Resources resources = getContext().getResources(); + mHorizontalMarginBetweenViews = + resources.getDimensionPixelSize(R.dimen.infobar_control_margin_between_items); + } + + /** + * Define how the controls will be laid out. + * + * @param alignment One of ALIGN_START, ALIGN_APART, ALIGN_END. + */ + @VisibleForTesting + void setAlignment(int alignment) { + mAlignment = alignment; + } + + /** + * Sets the margin between the controls when they're stacked. By default, there is no margin. + */ + @VisibleForTesting + void setStackedMargin(int stackedMargin) { + mStackedMargin = stackedMargin; + } + + @Override + public void onViewAdded(View child) { + super.onViewAdded(child); + + if (mPrimaryView == null) { + mPrimaryView = child; + } else if (mSecondaryView == null) { + mSecondaryView = child; + } else { + throw new IllegalStateException("Too many children added to InfoBarDualControlLayout"); + } + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + mIsStacked = false; + + // Measure the primary View, allowing it to be as wide as the Layout. + int maxWidth = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.UNSPECIFIED + ? Integer.MAX_VALUE : MeasureSpec.getSize(widthMeasureSpec); + int unspecifiedSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); + measureChild(mPrimaryView, unspecifiedSpec, unspecifiedSpec); + + int layoutWidth = mPrimaryView.getMeasuredWidth(); + int layoutHeight = mPrimaryView.getMeasuredHeight(); + + if (mSecondaryView != null) { + // Measure the secondary View, allowing it to be as wide as the layout. + measureChild(mSecondaryView, unspecifiedSpec, unspecifiedSpec); + int combinedWidth = mPrimaryView.getMeasuredWidth() + + mHorizontalMarginBetweenViews + mSecondaryView.getMeasuredWidth(); + + if (combinedWidth > maxWidth) { + // Stack the Views on top of each other. + mIsStacked = true; + + int widthSpec = MeasureSpec.makeMeasureSpec(maxWidth, MeasureSpec.EXACTLY); + mPrimaryView.measure(widthSpec, unspecifiedSpec); + mSecondaryView.measure(widthSpec, unspecifiedSpec); + + layoutWidth = maxWidth; + layoutHeight = mPrimaryView.getMeasuredHeight() + mStackedMargin + + mSecondaryView.getMeasuredHeight(); + } else { + // The Views fit side by side. Check which is taller to find the layout height. + layoutWidth = combinedWidth; + layoutHeight = Math.max(layoutHeight, mSecondaryView.getMeasuredHeight()); + } + } + + setMeasuredDimension(resolveSize(layoutWidth, widthMeasureSpec), + resolveSize(layoutHeight, heightMeasureSpec)); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + int width = right - left; + boolean isRtl = ApiCompatibilityUtils.isLayoutRtl(this); + boolean isPrimaryOnRight = (isRtl && mAlignment == ALIGN_START) + || (!isRtl && (mAlignment == ALIGN_APART || mAlignment == ALIGN_END)); + + int primaryRight = isPrimaryOnRight ? width : mPrimaryView.getMeasuredWidth(); + int primaryLeft = primaryRight - mPrimaryView.getMeasuredWidth(); + int primaryHeight = mPrimaryView.getMeasuredHeight(); + mPrimaryView.layout(primaryLeft, 0, primaryRight, primaryHeight); + + if (mIsStacked) { + // Fill out the row. onMeasure() should have already applied the correct width. + int secondaryTop = primaryHeight + mStackedMargin; + int secondaryBottom = secondaryTop + mSecondaryView.getMeasuredHeight(); + mSecondaryView.layout( + 0, secondaryTop, mSecondaryView.getMeasuredWidth(), secondaryBottom); + } else if (mSecondaryView != null) { + // Center the secondary View vertically with the primary View. + int secondaryHeight = mSecondaryView.getMeasuredHeight(); + int primaryCenter = primaryHeight / 2; + int secondaryTop = primaryCenter - (secondaryHeight / 2); + int secondaryBottom = secondaryTop + secondaryHeight; + + // Determine where to place the secondary View. + int secondaryLeft; + int secondaryRight; + if (mAlignment == ALIGN_APART) { + // Put the second View on the other side of the Layout from the primary View. + secondaryLeft = isPrimaryOnRight ? 0 : width - mSecondaryView.getMeasuredWidth(); + secondaryRight = secondaryLeft + mSecondaryView.getMeasuredWidth(); + } else if (isPrimaryOnRight) { + // Sit to the left of the primary View. + secondaryRight = primaryLeft - mHorizontalMarginBetweenViews; + secondaryLeft = secondaryRight - mSecondaryView.getMeasuredWidth(); + } else { + // Sit to the right of the primary View. + secondaryLeft = primaryRight + mHorizontalMarginBetweenViews; + secondaryRight = secondaryLeft + mSecondaryView.getMeasuredWidth(); + } + + mSecondaryView.layout( + secondaryLeft, secondaryTop, secondaryRight, secondaryBottom); + } + } +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/InfoBarLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/InfoBarLayout.java index c021c25..de30144 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/InfoBarLayout.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/InfoBarLayout.java
@@ -16,7 +16,6 @@ import android.text.TextUtils; import android.text.style.ClickableSpan; import android.util.TypedValue; -import android.view.Gravity; import android.view.View; import android.view.ViewGroup; import android.widget.Button; @@ -32,16 +31,17 @@ import java.util.List; /** - * Layout that arranges an InfoBar's views. An InfoBarLayout consists of: - * - A message describing the action that the user can take. - * - A close button on the right side. - * - (optional) An icon representing the infobar's purpose on the left side. - * - (optional) Additional "custom" views (e.g. a checkbox and text, or a pair of spinners) - * - (optional) One or two buttons with text at the bottom. + * Layout that arranges an infobar's views. + * + * An InfoBarLayout consists of: + * - A message describing why the infobar is being displayed. + * - A close button in the top right corner. + * - (optional) An icon representing the infobar's purpose in the top left corner. + * - (optional) Additional {@link InfoBarControlLayouts} for specialized controls (e.g. spinners). + * - (optional) One or two buttons with text at the bottom, or a button paired with an ImageView. * * When adding custom views, widths and heights defined in the LayoutParams will be ignored. - * However, setting a minimum width in another way, like TextView.getMinWidth(), should still be - * obeyed. + * Setting a minimum width using {@link View#setMininumWidth()} will be obeyed. * * Logic for what happens when things are clicked should be implemented by the InfoBarView. */ @@ -51,14 +51,12 @@ * Parameters used for laying out children. */ private static class LayoutParams extends ViewGroup.LayoutParams { - public int startMargin; public int endMargin; public int topMargin; public int bottomMargin; - // Where this view will be laid out. These values are assigned in onMeasure() and used in - // onLayout(). + // Where this view will be laid out. Calculated in onMeasure() and used in onLayout(). public int start; public int top; @@ -71,60 +69,13 @@ } } - private static class Group { - public View[] views; - - /** - * The gravity of each view in Group. Must be either Gravity.START, Gravity.END, or - * Gravity.FILL_HORIZONTAL. - */ - public int gravity = Gravity.START; - - /** Whether the views are vertically stacked. */ - public boolean isStacked; - - Group(View... views) { - this.views = views; - } - - static View[] filterNullViews(View... views) { - ArrayList<View> viewsList = new ArrayList<View>(); - for (View v : views) { - if (v != null) viewsList.add(v); - } - return viewsList.toArray(new View[viewsList.size()]); - } - - void setHorizontalMode(int horizontalSpacing, int startMargin, int endMargin) { - isStacked = false; - for (int i = 0; i < views.length; i++) { - LayoutParams lp = (LayoutParams) views[i].getLayoutParams(); - lp.startMargin = i == 0 ? startMargin : horizontalSpacing; - lp.topMargin = 0; - lp.endMargin = i == views.length - 1 ? endMargin : 0; - lp.bottomMargin = 0; - } - } - - void setVerticalMode(int verticalSpacing, int bottomMargin) { - isStacked = true; - for (int i = 0; i < views.length; i++) { - LayoutParams lp = (LayoutParams) views[i].getLayoutParams(); - lp.startMargin = 0; - lp.topMargin = i == 0 ? 0 : verticalSpacing; - lp.endMargin = 0; - lp.bottomMargin = i == views.length - 1 ? bottomMargin : 0; - } - } - } - private final int mSmallIconSize; private final int mSmallIconMargin; private final int mBigIconSize; private final int mBigIconMargin; private final int mMarginAboveButtonGroup; private final int mMarginAboveControlGroups; - private final int mMargin; + private final int mPadding; private final int mMinWidth; private final int mAccentColor; @@ -135,40 +86,19 @@ private TextView mMessageTextView; private ImageView mIconView; - private ButtonCompat mPrimaryButton; - private Button mSecondaryButton; - private View mCustomButton; + private InfoBarDualControlLayout mButtonRowLayout; - private Group mButtonGroup; - - private boolean mIsUsingBigIcon; private CharSequence mMessageMainText; private String mMessageLinkText; /** - * These values are used during onMeasure() to track where the next view will be placed. - * - * mWidth is the infobar width. - * [mStart, mEnd) is the range of unoccupied space on the current row. - * mTop and mBottom are the top and bottom of the current row. - * - * These values, along with a view's gravity, are used to position the next view. - * These values are updated after placing a view and after starting a new row. - */ - private int mWidth; - private int mStart; - private int mEnd; - private int mTop; - private int mBottom; - - /** - * Constructs a layout for the specified InfoBar. After calling this, be sure to set the + * Constructs a layout for the specified infobar. After calling this, be sure to set the * message, the buttons, and/or the custom content using setMessage(), setButtons(), and * setCustomContent(). * * @param context The context used to render. * @param infoBarView InfoBarView that listens to events. - * @param iconResourceId ID of the icon to use for the InfoBar. + * @param iconResourceId ID of the icon to use for the infobar. * @param iconBitmap Bitmap for the icon to use, if the resource ID wasn't passed through. * @param message The message to show in the infobar. */ @@ -179,7 +109,7 @@ mInfoBarView = infoBarView; - // Grab the dimensions. + // Cache resource values. Resources res = getResources(); mSmallIconSize = res.getDimensionPixelSize(R.dimen.infobar_small_icon_size); mSmallIconMargin = res.getDimensionPixelSize(R.dimen.infobar_small_icon_margin); @@ -189,7 +119,7 @@ res.getDimensionPixelSize(R.dimen.infobar_margin_above_button_row); mMarginAboveControlGroups = res.getDimensionPixelSize(R.dimen.infobar_margin_above_control_groups); - mMargin = res.getDimensionPixelOffset(R.dimen.infobar_margin); + mPadding = res.getDimensionPixelOffset(R.dimen.infobar_padding); mMinWidth = res.getDimensionPixelSize(R.dimen.infobar_min_width); mAccentColor = ApiCompatibilityUtils.getColor(res, R.color.infobar_accent_blue); @@ -202,10 +132,10 @@ Drawable closeButtonBackground = a.getDrawable(0); a.recycle(); mCloseButton.setBackground(closeButtonBackground); - mCloseButton.setPadding(mMargin, mMargin, mMargin, mMargin); + mCloseButton.setPadding(mPadding, mPadding, mPadding, mPadding); mCloseButton.setOnClickListener(this); mCloseButton.setContentDescription(res.getString(R.string.infobar_close)); - mCloseButton.setLayoutParams(new LayoutParams(0, -mMargin, -mMargin, -mMargin)); + mCloseButton.setLayoutParams(new LayoutParams(0, -mPadding, -mPadding, -mPadding)); // Set up the icon. if (iconResourceId != 0 || iconBitmap != null) { @@ -228,14 +158,14 @@ } /** - * Returns the {@link TextView} corresponding to the main InfoBar message. + * Returns the {@link TextView} corresponding to the main infobar message. */ TextView getMessageTextView() { return mMessageTextView; } /** - * Returns the {@link InfoBarControlLayout} containing the TextView showing the main InfoBar + * Returns the {@link InfoBarControlLayout} containing the TextView showing the main infobar * message and associated controls, which is sandwiched between its icon and close button. */ InfoBarControlLayout getMessageLayout() { @@ -254,7 +184,7 @@ } /** - * Sets the message to show for a link in the message, if an InfoBar requires a link + * Sets the message to show for a link in the message, if an infobar requires a link * (e.g. "Learn more"). */ public void setMessageLinkText(String linkText) { @@ -263,7 +193,7 @@ } /** - * Adds an {@link InfoBarControlLayout} to house additional InfoBar controls, like toggles and + * Adds an {@link InfoBarControlLayout} to house additional infobar controls, like toggles and * spinners. */ public InfoBarControlLayout addControlLayout() { @@ -275,38 +205,61 @@ /** * Adds one or two buttons to the layout. * - * @param primaryText Text for the primary button. + * @param primaryText Text for the primary button. If empty, no buttons are added at all. * @param secondaryText Text for the secondary button, or null if there isn't a second button. */ public void setButtons(String primaryText, String secondaryText) { - if (TextUtils.isEmpty(primaryText)) return; + if (TextUtils.isEmpty(primaryText)) { + assert secondaryText == null; + return; + } - mPrimaryButton = new ButtonCompat(getContext(), mAccentColor); - mPrimaryButton.setId(R.id.button_primary); - mPrimaryButton.setOnClickListener(this); - mPrimaryButton.setText(primaryText); - mPrimaryButton.setTextColor(Color.WHITE); + Button secondaryButton = null; + if (!TextUtils.isEmpty(secondaryText)) { + secondaryButton = ButtonCompat.createBorderlessButton(getContext()); + secondaryButton.setId(R.id.button_secondary); + secondaryButton.setOnClickListener(this); + secondaryButton.setText(secondaryText); + secondaryButton.setTextColor(mAccentColor); + } - if (TextUtils.isEmpty(secondaryText)) return; - - mSecondaryButton = ButtonCompat.createBorderlessButton(getContext()); - mSecondaryButton.setId(R.id.button_secondary); - mSecondaryButton.setOnClickListener(this); - mSecondaryButton.setText(secondaryText); - mSecondaryButton.setTextColor(mAccentColor); + setBottomViews(primaryText, secondaryButton, InfoBarDualControlLayout.ALIGN_END); } - /** Adds a custom view to show in the button row. */ - public void setCustomViewInButtonRow(View view) { - mCustomButton = view; + /** + * Sets up the bottom-most part of the infobar with a primary button (e.g. OK) and a secondary + * View of your choice. Subclasses should be calling {@link #setButtons(String, String)} + * instead of this function in nearly all cases (that function calls this one). + * + * @param primaryText Text to display on the primary button. If empty, the bottom layout is not + * created. + * @param secondaryView View that is aligned with the primary button. May be null. + * @param alignment One of ALIGN_START, ALIGN_APART, or ALIGN_END from + * {@link InfoBarDualControlLayout}. + */ + public void setBottomViews(String primaryText, View secondaryView, int alignment) { + assert !TextUtils.isEmpty(primaryText); + ButtonCompat primaryButton = new ButtonCompat(getContext(), mAccentColor); + primaryButton.setId(R.id.button_primary); + primaryButton.setOnClickListener(this); + primaryButton.setText(primaryText); + primaryButton.setTextColor(Color.WHITE); + primaryButton.setRaised(false); + + assert mButtonRowLayout == null; + mButtonRowLayout = new InfoBarDualControlLayout(getContext(), null); + mButtonRowLayout.setAlignment(alignment); + mButtonRowLayout.setStackedMargin(getResources().getDimensionPixelSize( + R.dimen.infobar_margin_between_stacked_buttons)); + + mButtonRowLayout.addView(primaryButton); + if (secondaryView != null) mButtonRowLayout.addView(secondaryView); } /** * Adjusts styling to account for the big icon layout. */ public void setIsUsingBigIcon() { - mIsUsingBigIcon = true; - LayoutParams lp = (LayoutParams) mIconView.getLayoutParams(); lp.width = mBigIconSize; lp.height = mBigIconSize; @@ -326,7 +279,8 @@ * Returns the primary button, or null if it doesn't exist. */ public ButtonCompat getPrimaryButton() { - return mPrimaryButton; + return mButtonRowLayout == null ? null + : (ButtonCompat) mButtonRowLayout.findViewById(R.id.button_primary); } /** @@ -341,16 +295,11 @@ * first call to onMeasure(). */ void onContentCreated() { - View[] buttons = Group.filterNullViews(mCustomButton, mSecondaryButton, mPrimaryButton); - if (buttons.length != 0) mButtonGroup = new Group(buttons); - // Add the child views in the desired focus order. if (mIconView != null) addView(mIconView); addView(mMessageLayout); for (View v : mControlLayouts) addView(v); - if (mButtonGroup != null) { - for (View v : mButtonGroup.views) addView(v); - } + if (mButtonRowLayout != null) addView(mButtonRowLayout); addView(mCloseButton); } @@ -382,221 +331,132 @@ } /** - * Measures *and* assigns positions to all of the views in the infobar. These positions are - * saved in each view's LayoutParams (lp.start and lp.top) and used during onLayout(). All of - * the interesting logic happens inside onMeasure(); onLayout() just assigns the already- - * determined positions and mirrors everything for RTL, if needed. + * Measures and determines where children should go. + * + * For current specs, see https://goto.google.com/infobar-spec + * + * All controls are padded from the infobar boundary by the same amount, but different types of + * control groups are bound by different widths and have different margins: + * -------------------------------------------------------------------------------- + * | PADDING | + * | -------------------------------------------------------------------------- | + * | | ICON | MESSAGE LAYOUT | X | | + * | |------+ +---| | + * | | | | | | + * | | ------------------------------------------------------------------| | + * | | | CONTROL LAYOUT #1 | | + * | | ------------------------------------------------------------------| | + * | | | CONTROL LAYOUT #X | | + * | |------------------------------------------------------------------------| | + * | | BOTTOM ROW LAYOUT | | + * | -------------------------------------------------------------------------| | + * | | + * -------------------------------------------------------------------------------- */ @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { assert getLayoutParams().height == LayoutParams.WRAP_CONTENT : "InfoBar heights cannot be constrained."; - // Measure all children without imposing any size constraints on them. This determines how - // big each child wants to be. + // Apply the padding that surrounds all the infobar controls. + final int layoutWidth = Math.max(MeasureSpec.getSize(widthMeasureSpec), mMinWidth); + final int paddedStart = mPadding; + final int paddedEnd = layoutWidth - mPadding; + int layoutBottom = mPadding; + + // Measure and place the icon in the top-left corner. int unspecifiedSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); - for (int i = 0; i < getChildCount(); i++) { - // No need to do a preliminary measure() on an InfoBarControlLayout, - // since InfoBarControlLayout handles all the measuring logic internally. - // TODO(dfalcantara): remove this instanceof check when refactoring this method. - if (getChildAt(i) instanceof InfoBarControlLayout) continue; - measureChild(getChildAt(i), unspecifiedSpec, unspecifiedSpec); - } - - // Avoid overlapping views, division by zero, infinite heights, and other fun problems that - // could arise with extremely narrow infobars. - mWidth = Math.max(MeasureSpec.getSize(widthMeasureSpec), mMinWidth); - mTop = mBottom = 0; - placeGroups(); - - setMeasuredDimension(mWidth, resolveSize(mBottom, heightMeasureSpec)); - } - - /** - * Assigns positions to all of the views in the infobar. The icon enforces a start margin on - * all control groups that aren't the final button group. The message and close button are - * placed on the main row, with control groups placed beneath them. - */ - private void placeGroups() { - // Enforce the general top-padding on the InfoBar controls. - mTop = mBottom = mMargin; - - // Place the icon, which forces all control groups to be inset by the size of the icon. - if (mIconView == null) { - startRowWithIconMargin(); - } else { - startRowWithoutIconMargin(); - placeChild(mIconView, Gravity.START); - } - - // Place the close button. - placeChild(mCloseButton, Gravity.END); - - // Place the main control group, which is sandwiched between the icon and the close button. - // When laid out vertically, control groups ignore where the close button's bottom is, but - // that value helps define how tall the InfoBar is. Save the bottom before overwriting it. - int closeButtonBottom = mBottom; - mTop = mBottom = mMargin; - placeChild(mMessageLayout, Gravity.FILL_HORIZONTAL); - - // Place each of the control groups. - for (InfoBarControlLayout layout : mControlLayouts) { - startRowWithIconMargin(); - mTop = mBottom + mMarginAboveControlGroups; - mBottom = mTop; - placeChild(layout, Gravity.FILL_HORIZONTAL); - } - - // Place the buttons. - if (mButtonGroup != null) { - startRowWithoutIconMargin(); - mTop = mBottom + mMarginAboveButtonGroup; - mBottom = mTop; - - updateButtonGroupLayoutProperties(); - placeButtonGroup(mButtonGroup); - - if (mCustomButton != null) { - // The custom button is start-aligned to its parent. - LayoutParams primaryButtonLP = (LayoutParams) mPrimaryButton.getLayoutParams(); - LayoutParams customButtonLP = (LayoutParams) mCustomButton.getLayoutParams(); - customButtonLP.start = mMargin; - - if (!mButtonGroup.isStacked) { - // Center the custom button vertically relative to the primary button. - customButtonLP.top = primaryButtonLP.top - + (mPrimaryButton.getMeasuredHeight() - - mCustomButton.getMeasuredHeight()) / 2; - } - } - } - - // Apply a bottom padding to the layout, then calculate its final height. - mTop = mBottom + mMargin; - mBottom = mTop; - mBottom = Math.max(mBottom, closeButtonBottom); - } - - /** - * Places a group of views on the current row, or stacks them over multiple rows if - * group.isStacked is true. mStart, mEnd, and mBottom are updated to reflect the space taken by - * the group. - */ - private void placeButtonGroup(Group group) { - if (group.gravity == Gravity.END) { - for (int i = group.views.length - 1; i >= 0; i--) { - placeChild(group.views[i], group.gravity); - if (group.isStacked && i != 0) startRowWithIconMargin(); - } - } else { // group.gravity is Gravity.START or Gravity.FILL_HORIZONTAL - for (int i = 0; i < group.views.length; i++) { - placeChild(group.views[i], group.gravity); - if (group.isStacked && i != group.views.length - 1) { - if (group == mButtonGroup) { - startRowWithoutIconMargin(); - } else { - startRowWithIconMargin(); - } - } - } - } - } - - /** - * Places a single view on the current row, and updates the view's layout parameters to remember - * its position. mStart, mEnd, and mBottom are updated to reflect the space taken by the view. - */ - private void placeChild(View child, int gravity) { - LayoutParams lp = (LayoutParams) child.getLayoutParams(); - - int availableWidth = Math.max(0, mEnd - mStart - lp.startMargin - lp.endMargin); - if (child.getMeasuredWidth() > availableWidth || gravity == Gravity.FILL_HORIZONTAL) { - measureChildWithFixedWidth(child, availableWidth); - } - - if (gravity == Gravity.START || gravity == Gravity.FILL_HORIZONTAL) { - lp.start = mStart + lp.startMargin; - mStart = lp.start + child.getMeasuredWidth() + lp.endMargin; - } else { // gravity == Gravity.END - lp.start = mEnd - lp.endMargin - child.getMeasuredWidth(); - mEnd = lp.start - lp.startMargin; - } - - lp.top = mTop + lp.topMargin; - mBottom = Math.max(mBottom, lp.top + child.getMeasuredHeight() + lp.bottomMargin); - } - - /** - * Advances the current position to the next row and adds margins on the left, right, and top - * of the new row. - */ - private void startRowWithoutIconMargin() { - mStart = mMargin; - mEnd = mWidth - mMargin; - mTop = mBottom; - } - - /** - * Advances the current position to the next row and adds margins on the left, right, and top - * of the new row, accounting for the margins imposed by the icon. - */ - private void startRowWithIconMargin() { - startRowWithoutIconMargin(); - if (mIconView != null) { - if (mIsUsingBigIcon) { - mStart += mBigIconSize + mBigIconMargin; - } else { - mStart += mSmallIconSize + mSmallIconMargin; - } + LayoutParams iconParams = getChildLayoutParams(mIconView); + measureChild(mIconView, unspecifiedSpec, unspecifiedSpec); + iconParams.start = paddedStart + iconParams.startMargin; + iconParams.top = layoutBottom + iconParams.topMargin; } + final int iconWidth = getChildWidthWithMargins(mIconView); + + // Measure and place the close button in the top-right corner of the layout. + LayoutParams closeParams = getChildLayoutParams(mCloseButton); + measureChild(mCloseButton, unspecifiedSpec, unspecifiedSpec); + closeParams.start = paddedEnd - closeParams.endMargin - mCloseButton.getMeasuredWidth(); + closeParams.top = layoutBottom + closeParams.topMargin; + + // Determine how much width is available for all the different control layouts; see the + // function JavaDoc above for details. + final int paddedWidth = paddedEnd - paddedStart; + final int controlLayoutWidth = paddedWidth - iconWidth; + final int messageWidth = controlLayoutWidth - getChildWidthWithMargins(mCloseButton); + + // The message layout is sandwiched between the icon and the close button. + LayoutParams messageParams = getChildLayoutParams(mMessageLayout); + measureChildWithFixedWidth(mMessageLayout, messageWidth); + messageParams.start = paddedStart + iconWidth; + messageParams.top = layoutBottom; + + // Control layouts are placed below the message layout and the close button. The icon is + // ignored for this particular calculation because the icon enforces a left margin on all of + // the control layouts and won't be overlapped. + layoutBottom += Math.max(getChildHeightWithMargins(mMessageLayout), + getChildHeightWithMargins(mCloseButton)); + + // The other control layouts are constrained only by the icon's width. + final int controlPaddedStart = paddedStart + iconWidth; + for (int i = 0; i < mControlLayouts.size(); i++) { + View child = mControlLayouts.get(i); + measureChildWithFixedWidth(child, controlLayoutWidth); + + layoutBottom += mMarginAboveControlGroups; + getChildLayoutParams(child).start = controlPaddedStart; + getChildLayoutParams(child).top = layoutBottom; + layoutBottom += child.getMeasuredHeight(); + } + + // The button layout takes up the full width of the infobar and sits below everything else, + // including the icon. + layoutBottom = Math.max(layoutBottom, getChildHeightWithMargins(mIconView)); + if (mButtonRowLayout != null) { + measureChildWithFixedWidth(mButtonRowLayout, paddedWidth); + + layoutBottom += mMarginAboveButtonGroup; + getChildLayoutParams(mButtonRowLayout).start = paddedStart; + getChildLayoutParams(mButtonRowLayout).top = layoutBottom; + layoutBottom += mButtonRowLayout.getMeasuredHeight(); + } + + // Apply padding to the bottom of the infobar. + layoutBottom += mPadding; + + setMeasuredDimension(resolveSize(layoutWidth, widthMeasureSpec), + resolveSize(layoutBottom, heightMeasureSpec)); + } + + private static int getChildWidthWithMargins(View view) { + if (view == null) return 0; + return view.getMeasuredWidth() + getChildLayoutParams(view).startMargin + + getChildLayoutParams(view).endMargin; + } + + private static int getChildHeightWithMargins(View view) { + if (view == null) return 0; + return view.getMeasuredHeight() + getChildLayoutParams(view).topMargin + + getChildLayoutParams(view).bottomMargin; + } + + private static LayoutParams getChildLayoutParams(View view) { + return (LayoutParams) view.getLayoutParams(); } /** - * @return The width of the group, including the items' margins. + * Measures a child for the given space, taking into account its margins. */ - private int getWidthWithMargins(Group group) { - if (group.isStacked) return getWidthWithMargins(group.views[0]); - - int width = 0; - for (View v : group.views) { - width += getWidthWithMargins(v); - } - return width; - } - - private int getWidthWithMargins(View child) { - LayoutParams lp = (LayoutParams) child.getLayoutParams(); - return child.getMeasuredWidth() + lp.startMargin + lp.endMargin; - } - private void measureChildWithFixedWidth(View child, int width) { - int widthSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY); + LayoutParams lp = getChildLayoutParams(child); + int availableWidth = width - lp.startMargin - lp.endMargin; + int widthSpec = MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.EXACTLY); int heightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); child.measure(widthSpec, heightSpec); } /** - * Updates the layout properties (margins, gravity, etc) of the button group to prepare for - * placing it on its own row. - */ - private void updateButtonGroupLayoutProperties() { - int startEndMargin = 0; - mButtonGroup.setHorizontalMode(mMargin / 2, startEndMargin, startEndMargin); - mButtonGroup.gravity = Gravity.END; - - if (mButtonGroup.views.length >= 2) { - int availableWidth = mEnd - mStart; - int extraWidth = availableWidth - getWidthWithMargins(mButtonGroup); - if (extraWidth < 0) { - // Group is too wide to fit on a single row, so stack the group items vertically. - mButtonGroup.setVerticalMode(mMargin / 2, 0); - mButtonGroup.gravity = Gravity.FILL_HORIZONTAL; - } - } - } - - /** * Listens for View clicks. * Classes that override this function MUST call this one. * @param view View that was clicked on. @@ -615,8 +475,8 @@ } /** - * Prepares text to be displayed as the InfoBar's main message, including setting up a - * clickable link if the InfoBar requires it. + * Prepares text to be displayed as the infobar's main message, including setting up a + * clickable link if the infobar requires it. */ private CharSequence prepareMainMessageString() { SpannableStringBuilder fullString = new SpannableStringBuilder();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/OWNERS b/chrome/android/java/src/org/chromium/chrome/browser/infobar/OWNERS index d61ef87b..8d3b6ae 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/OWNERS +++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/OWNERS
@@ -1,4 +1,6 @@ +set noparent dfalcantara@chromium.org miguelg@chromium.org +newt@chromium.org per-file GeneratedPasswordSavedInfoBar*=rouslan@chromium.org
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/remote/AbstractMediaRouteController.java b/chrome/android/java/src/org/chromium/chrome/browser/media/remote/AbstractMediaRouteController.java index ec71586..bb17b63 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/media/remote/AbstractMediaRouteController.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/media/remote/AbstractMediaRouteController.java
@@ -157,8 +157,8 @@ } /** Number of ms to wait for reconnection, after which we call the failure callbacks. */ - protected static final int CONNECTION_FAILURE_NOTIFICATION_DELAY_MS = 10000; - private static final int END_OF_VIDEO_THRESHOLD_MS = 500; + protected static final long CONNECTION_FAILURE_NOTIFICATION_DELAY_MS = 10000L; + private static final long END_OF_VIDEO_THRESHOLD_MS = 500L; private static final String TAG = "AbstractMediaRouteController"; private final Set<MediaStateListener> mAvailableRouteListeners; private final Context mContext; @@ -310,7 +310,7 @@ return mUiListeners; } - private final boolean isAtEndOfVideo(int positionMs, int videoLengthMs) { + private final boolean isAtEndOfVideo(long positionMs, long videoLengthMs) { return videoLengthMs - positionMs < END_OF_VIDEO_THRESHOLD_MS && videoLengthMs > 0; } @@ -380,7 +380,7 @@ protected abstract void onRouteUnselectedEvent(MediaRouter router, RouteInfo route); @Override - public void onSeek(int position) { + public void onSeek(long position) { seekTo(position); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/remote/DefaultMediaRouteController.java b/chrome/android/java/src/org/chromium/chrome/browser/media/remote/DefaultMediaRouteController.java index 2daf245..619cd776 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/media/remote/DefaultMediaRouteController.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/media/remote/DefaultMediaRouteController.java
@@ -95,9 +95,9 @@ private boolean mDebug; private String mCurrentSessionId; private String mCurrentItemId; - private int mStreamPositionTimestamp; - private int mLastKnownStreamPosition; - private int mStreamDuration; + private long mStreamPositionTimestamp; + private long mLastKnownStreamPosition; + private long mStreamDuration; private boolean mSeeking; private final String mIntentCategory; private PendingIntent mSessionStatusUpdateIntent; @@ -497,7 +497,7 @@ } @Override - public int getPosition() { + public long getPosition() { boolean paused = (getPlayerState() != PlayerState.PLAYING); if ((mStreamPositionTimestamp != 0) && !mSeeking && !paused && (mLastKnownStreamPosition < mStreamDuration)) { @@ -507,18 +507,18 @@ if (extrapolatedStreamPosition > mStreamDuration) { extrapolatedStreamPosition = mStreamDuration; } - return (int) extrapolatedStreamPosition; + return extrapolatedStreamPosition; } return mLastKnownStreamPosition; } @Override - public int getDuration() { + public long getDuration() { return mStreamDuration; } @Override - public void seekTo(int msec) { + public void seekTo(long msec) { if (msec == getPosition()) return; // Update the position now since the MRP will update it only once the video is playing // remotely. In particular, if the video is paused, the MRP doesn't send the command until @@ -529,7 +529,7 @@ intent.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK); intent.putExtra(MediaControlIntent.EXTRA_SESSION_ID, mCurrentSessionId); intent.putExtra(MediaControlIntent.EXTRA_ITEM_ID, mCurrentItemId); - intent.putExtra(MediaControlIntent.EXTRA_ITEM_CONTENT_POSITION, (long) msec); + intent.putExtra(MediaControlIntent.EXTRA_ITEM_CONTENT_POSITION, msec); sendIntentToRoute(intent, new ResultBundleHandler() { @Override public void onResult(Bundle data) { @@ -881,13 +881,13 @@ this.mCurrentItemId = itemId; - int duration = (int) itemStatus.getContentDuration(); + long duration = itemStatus.getContentDuration(); // duration can possibly be -1 if it's unknown, so cap to 0 updateDuration(Math.max(duration, 0)); // update the position using the remote player's position - mLastKnownStreamPosition = (int) itemStatus.getContentPosition(); - mStreamPositionTimestamp = (int) itemStatus.getTimestamp(); + mLastKnownStreamPosition = itemStatus.getContentPosition(); + mStreamPositionTimestamp = itemStatus.getTimestamp(); updatePosition(); if (mSeeking) { @@ -981,7 +981,7 @@ }); } - private void updateDuration(int durationMillis) { + private void updateDuration(long durationMillis) { mStreamDuration = durationMillis; for (UiListener listener : getUiListeners()) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/remote/ExpandedControllerActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/media/remote/ExpandedControllerActivity.java index 20775e2..5ebad076 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/media/remote/ExpandedControllerActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/media/remote/ExpandedControllerActivity.java
@@ -87,7 +87,7 @@ @Override public void onSeekTo(long pos) { if (mMediaRouteController == null) return; - mMediaRouteController.seekTo((int) pos); + mMediaRouteController.seekTo(pos); } @Override @@ -298,14 +298,14 @@ } @Override - public void onDurationUpdated(int durationMillis) { + public void onDurationUpdated(long durationMillis) { RemoteVideoInfo videoInfo = new RemoteVideoInfo(mVideoInfo); videoInfo.durationMillis = durationMillis; setVideoInfo(videoInfo); } @Override - public void onPositionChanged(int positionMillis) { + public void onPositionChanged(long positionMillis) { RemoteVideoInfo videoInfo = new RemoteVideoInfo(mVideoInfo); videoInfo.currentTimeMillis = positionMillis; setVideoInfo(videoInfo);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/remote/LockScreenTransportControlV16.java b/chrome/android/java/src/org/chromium/chrome/browser/media/remote/LockScreenTransportControlV16.java index f7140343..ecbbb23 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/media/remote/LockScreenTransportControlV16.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/media/remote/LockScreenTransportControlV16.java
@@ -209,14 +209,14 @@ } @Override - public void onDurationUpdated(int durationMillis) { + public void onDurationUpdated(long durationMillis) { RemoteVideoInfo videoInfo = new RemoteVideoInfo(getVideoInfo()); videoInfo.durationMillis = durationMillis; setVideoInfo(videoInfo); } @Override - public void onPositionChanged(int positionMillis) { + public void onPositionChanged(long positionMillis) { RemoteVideoInfo videoInfo = new RemoteVideoInfo(getVideoInfo()); videoInfo.currentTimeMillis = positionMillis; setVideoInfo(videoInfo);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/remote/LockScreenTransportControlV18.java b/chrome/android/java/src/org/chromium/chrome/browser/media/remote/LockScreenTransportControlV18.java index 22a8a9f..1e8a608 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/media/remote/LockScreenTransportControlV18.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/media/remote/LockScreenTransportControlV18.java
@@ -74,7 +74,7 @@ @Override public void onPlaybackPositionUpdate(long position) { - for (Listener listener : getListeners()) listener.onSeek((int) position); + for (Listener listener : getListeners()) listener.onSeek(position); } } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/remote/MediaRouteController.java b/chrome/android/java/src/org/chromium/chrome/browser/media/remote/MediaRouteController.java index 255e647..7c52ae13 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/media/remote/MediaRouteController.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/media/remote/MediaRouteController.java
@@ -56,7 +56,7 @@ void pauseLocal(); - int getLocalPosition(); + long getLocalPosition(); /** * Tells the rest of Chrome that we are starting to cast, so that user inputs control cast @@ -107,7 +107,7 @@ /** * @return the requested seek location. Only meaningful if isSeekRequested is true. */ - int getSeekLocation(); + long getSeekLocation(); } /** @@ -152,14 +152,14 @@ * Called when the duration of the currently playing video changes. * @param durationMillis the new duration in ms. */ - void onDurationUpdated(int durationMillis); + void onDurationUpdated(long durationMillis); /** * Called when the media route controller receives new information about the * current position in the video. * @param positionMillis the current position in the video in ms. */ - void onPositionChanged(int positionMillis); + void onPositionChanged(long positionMillis); /** * Called if the title of the video changes @@ -280,12 +280,12 @@ * * @return The current position of the remote playback in milliseconds. */ - int getPosition(); + long getPosition(); /** * @return The stream duration in milliseconds. */ - int getDuration(); + long getDuration(); /** * @return Whether the video is currently being played. @@ -302,7 +302,7 @@ * * @param msec The position to seek to, in milliseconds. */ - void seekTo(int msec); + void seekTo(long msec); /** * Stop the current remote playback completely and release all resources.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/remote/NotificationTransportControl.java b/chrome/android/java/src/org/chromium/chrome/browser/media/remote/NotificationTransportControl.java index 683f119f..7c38034c 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/media/remote/NotificationTransportControl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/media/remote/NotificationTransportControl.java
@@ -34,10 +34,10 @@ public class NotificationTransportControl extends TransportControl implements MediaRouteController.UiListener { /** - * Service used to transform intent requests triggered from the notification into - * {@code Listener} callbacks. Ideally this class should be protected, but public is required - * to create as a service. - */ + * Service used to transform intent requests triggered from the notification into + * {@code Listener} callbacks. Ideally this class should be protected, but public is required to + * create as a service. + */ public static class ListenerService extends Service { private static final String ACTION_PREFIX = ListenerService.class.getName() + "."; @@ -185,8 +185,7 @@ case PLAYING: showProgress = true; showPlayPause = true; - contentView.setProgressBar(R.id.progress, videoInfo.durationMillis, - videoInfo.currentTimeMillis, false); + setProgressBar(videoInfo, contentView); contentView.setImageViewResource( R.id.playpause, R.drawable.ic_vidcontrol_pause); contentView.setContentDescription( @@ -198,8 +197,7 @@ case PAUSED: showProgress = true; showPlayPause = true; - contentView.setProgressBar(R.id.progress, videoInfo.durationMillis, - videoInfo.currentTimeMillis, false); + setProgressBar(videoInfo, contentView); contentView.setImageViewResource( R.id.playpause, R.drawable.ic_vidcontrol_play); contentView.setContentDescription( @@ -234,6 +232,19 @@ } } + private void setProgressBar(RemoteVideoInfo videoInfo, RemoteViews contentView) { + long durationMillis = videoInfo.durationMillis; + long currentTimeMillis = videoInfo.currentTimeMillis; + // Handle ridiculously long videos (25 days+). + if (durationMillis > Integer.MAX_VALUE) { + long factor = durationMillis / Integer.MAX_VALUE; + durationMillis = Integer.MAX_VALUE; + currentTimeMillis = currentTimeMillis / factor; + } + contentView.setProgressBar(R.id.progress, (int) durationMillis, (int) currentTimeMillis, + false); + } + private RemoteViews createContentView() { RemoteViews contentView = new RemoteViews(getPackageName(), R.layout.remote_notification_bar); @@ -358,7 +369,6 @@ return Bitmap.createScaledBitmap(bitmap, width, height, false); } - private NotificationTransportControl(Context context) { this.mContext = context; mHandler = new Handler(context.getMainLooper()); @@ -381,7 +391,7 @@ } @Override - public void onDurationUpdated(int durationMillis) { + public void onDurationUpdated(long durationMillis) { // Set the progress update interval based on the screen height/width, since there's no point // in updating the progress bar more frequently than what the user can see. // getDisplayMetrics() is dependent on the current orientation, so we need to get the max @@ -415,7 +425,7 @@ } @Override - public void onPositionChanged(int positionMillis) { + public void onPositionChanged(long positionMillis) { RemoteVideoInfo videoInfo = new RemoteVideoInfo(getVideoInfo()); videoInfo.currentTimeMillis = positionMillis; setVideoInfo(videoInfo);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/remote/RecordCastAction.java b/chrome/android/java/src/org/chromium/chrome/browser/media/remote/RecordCastAction.java index 36c81ed..3ead86d 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/media/remote/RecordCastAction.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/media/remote/RecordCastAction.java
@@ -63,9 +63,9 @@ * @param videoLengthMs the total length of the video in milliseconds * @param timeRemainingMs the remaining time in the video in milliseconds */ - public static void castEndedTimeRemaining(int videoLengthMs, int timeRemainingMs) { + public static void castEndedTimeRemaining(long videoLengthMs, long timeRemainingMs) { if (LibraryLoader.isInitialized()) { - nativeRecordCastEndedTimeRemaining(videoLengthMs, timeRemainingMs); + nativeRecordCastEndedTimeRemaining((int) videoLengthMs, (int) timeRemainingMs); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/remote/RemoteMediaPlayerBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/media/remote/RemoteMediaPlayerBridge.java index b6d124b..4c2f074 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/media/remote/RemoteMediaPlayerBridge.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/media/remote/RemoteMediaPlayerBridge.java
@@ -44,7 +44,7 @@ private String mCookies; private boolean mPauseRequested; private boolean mSeekRequested; - private int mSeekLocation; + private long mSeekLocation; // mActive is true when the Chrome is playing, or preparing to play, this player's video // remotely. @@ -114,7 +114,7 @@ } @Override - public int getLocalPosition() { + public long getLocalPosition() { return nativeGetLocalPosition(mNativeRemoteMediaPlayerBridge); } @@ -167,7 +167,7 @@ } @Override - public int getSeekLocation() { + public long getSeekLocation() { return mSeekLocation; } }; @@ -265,14 +265,14 @@ @CalledByNative protected int getCurrentPosition() { if (mRouteController == null) return 0; - return mRouteController.getPosition(); + return (int) mRouteController.getPosition(); } @Override @CalledByNative protected int getDuration() { if (mRouteController == null) return 0; - return mRouteController.getDuration(); + return (int) mRouteController.getDuration(); } @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/remote/RemoteMediaPlayerController.java b/chrome/android/java/src/org/chromium/chrome/browser/media/remote/RemoteMediaPlayerController.java index b4adcc3..d8088eee 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/media/remote/RemoteMediaPlayerController.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/media/remote/RemoteMediaPlayerController.java
@@ -339,10 +339,10 @@ } @Override - public void onDurationUpdated(int durationMillis) {} + public void onDurationUpdated(long durationMillis) {} @Override - public void onPositionChanged(int positionMillis) {} + public void onPositionChanged(long positionMillis) {} @Override public void onTitleChanged(String title) {}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/remote/RemoteVideoInfo.java b/chrome/android/java/src/org/chromium/chrome/browser/media/remote/RemoteVideoInfo.java index 3982cf61..cfe299c 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/media/remote/RemoteVideoInfo.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/media/remote/RemoteVideoInfo.java
@@ -45,7 +45,7 @@ /** * The duration of the video */ - public int durationMillis; + public long durationMillis; /** * The current state of the video */ @@ -53,7 +53,7 @@ /** * The last known position in the video */ - public int currentTimeMillis; + public long currentTimeMillis; /** * The current error message, if any */ @@ -68,8 +68,8 @@ * @param currentTimeMillis * @param errorMessage */ - public RemoteVideoInfo(String title, int durationMillis, PlayerState state, - int currentTimeMillis, String errorMessage) { + public RemoteVideoInfo(String title, long durationMillis, PlayerState state, + long currentTimeMillis, String errorMessage) { this.title = title; this.durationMillis = durationMillis; this.state = state; @@ -105,8 +105,10 @@ @Override public int hashCode() { - int result = durationMillis; - result = 31 * result + currentTimeMillis; + int result = (int) durationMillis; + result = 31 * result + (int) (durationMillis >> 32); + result = 31 * result + (int) currentTimeMillis; + result = 31 * result + (int) (currentTimeMillis >> 32); result = 31 * result + (title == null ? 0 : title.hashCode()); result = 31 * result + (state == null ? 0 : state.hashCode()); result = 31 * result + (errorMessage == null ? 0 : errorMessage.hashCode());
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/remote/TransportControl.java b/chrome/android/java/src/org/chromium/chrome/browser/media/remote/TransportControl.java index 77b74ec..98d1e38 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/media/remote/TransportControl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/media/remote/TransportControl.java
@@ -28,7 +28,7 @@ public static interface Listener { void onPlay(); void onPause(); - void onSeek(int position); + void onSeek(long position); void onStop(); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/CustomNotificationBuilder.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/CustomNotificationBuilder.java index 0571b2e6..c394cec 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/CustomNotificationBuilder.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/CustomNotificationBuilder.java
@@ -100,6 +100,9 @@ @Override public Notification build() { + // TODO(mvanouwerkerk): Try inheriting from StandardNotificationBuilder to reduce + // duplication. + // A note about RemoteViews and updating notifications. When a notification is passed to the // {@code NotificationManager} with the same tag and id as a previous notification, an // in-place update will be performed. In that case, the actions of all new @@ -146,6 +149,16 @@ builder.setVibrate(mVibratePattern); builder.setContent(compactView); + // Some things are duplicated in the builder to ensure the notification shows correctly on + // Wear devices and custom lock screens. + builder.setContentTitle(mTitle); + builder.setContentText(mBody); + builder.setSubText(mOrigin); + builder.setLargeIcon(mLargeIcon); + for (Action action : mActions) { + builder.addAction(action); + } + Notification notification = builder.build(); notification.bigContentView = bigView; return notification;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageConnectivityListener.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageConnectivityListener.java new file mode 100644 index 0000000..0b07e946 --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageConnectivityListener.java
@@ -0,0 +1,77 @@ +// 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.offlinepages; + +import org.chromium.base.Log; +import org.chromium.chrome.browser.ChromeActivity; +import org.chromium.chrome.browser.tab.Tab; +import org.chromium.net.ConnectionType; +import org.chromium.net.NetworkChangeNotifier; + +/** + * A class to listen and respond to network connectivity events while offline pages are active. + */ +public class OfflinePageConnectivityListener + implements NetworkChangeNotifier.ConnectionTypeObserver { + private static final String TAG = "OfflinePageCL"; + private Tab mTab; + private ChromeActivity mActivity; + private boolean mSeen; + private boolean mEnabled; + + /** + * Builds an offline page connectivity listener. + * @param activity The ChromeActivity that we are listening for. + * @param tab The current tab that we are setting up a listener for. + */ + public OfflinePageConnectivityListener(ChromeActivity activity, Tab tab) { + Log.d(TAG, "OfflinePageConnectivityListener constructor, this: " + this); + this.mActivity = activity; + this.mTab = tab; + this.mSeen = false; + this.mEnabled = false; + enable(); + } + + @Override + public void onConnectionTypeChanged(int connectionType) { + Log.d(TAG, "Got connectivity event, connectionType: " + connectionType); + + boolean connected = (connectionType != ConnectionType.CONNECTION_NONE + && connectionType != ConnectionType.CONNECTION_UNKNOWN + && connectionType != ConnectionType.CONNECTION_BLUETOOTH); + + // TODO(petewil): We should consider using the connection quality monitor instead + // of the connection event here - don't offer to reload if connection quality is bad. + // Maybe the NetworkConnectivityListener is the right place to use the quality monitor. + + // Shows or hides the snackbar as needed. This also adds some hysterisis - if we keep + // connecting and disconnecting, we don't want to flash the snackbar. It will timeout at 3 + // seconds. + if (connected && mTab != null && !mSeen) { + Log.d(TAG, "Showing reload snackbar"); + OfflinePageUtils.showOfflineSnackbarIfNecessary(mActivity, mTab); + mSeen = true; + } + } + + /** + * Enable the listener when we have an offline page showing. + */ + public void enable() { + NetworkChangeNotifier.addConnectionTypeObserver(this); + mEnabled = true; + } + + /** + * Disable the listener when we are done with the offline page. + */ + public void disable() { + if (mEnabled) { + NetworkChangeNotifier.removeConnectionTypeObserver(this); + } + mEnabled = false; + } +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageTabObserver.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageTabObserver.java new file mode 100644 index 0000000..5b8f339 --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageTabObserver.java
@@ -0,0 +1,104 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.offlinepages; + +import org.chromium.base.Log; +import org.chromium.chrome.browser.ChromeActivity; +import org.chromium.chrome.browser.tab.EmptyTabObserver; +import org.chromium.chrome.browser.tab.Tab; + +import java.util.Map; +import java.util.TreeMap; + +/** + * A class that observes events for a tab which has an associated offline page. This will be + * created when needed (for instance, we want to show a snackbar when the tab is shown or we want + * to show a snackbar if the device connects). It will be removed when the user navigates away + * from the offline tab. + */ +public class OfflinePageTabObserver extends EmptyTabObserver { + private static final String TAG = "OfflinePageTO"; + private ChromeActivity mActivity; + private boolean mConnected; + private boolean mShouldSave; + private long mBookmarkId; + private boolean mWasHidden = false; + private OfflinePageConnectivityListener mListener = null; + + private static final Map<Integer, OfflinePageConnectivityListener> sConnectivityListeners = + new TreeMap<Integer, OfflinePageConnectivityListener>(); + + /** + * Builds a new OfflinePageTabObserver. + * @param activity The ChromeActivity of this instance of the browser. + * @param connected True if the phone is connected when the observer is created. + * @param shouldSave True if we should show a snackbar offering to save the page offline. + * @param bookmarkId Id of the bookmark (offline page) that is associated with this observer. + */ + public OfflinePageTabObserver( + ChromeActivity activity, boolean connected, boolean shouldSave, long bookmarkId) { + mActivity = activity; + mConnected = connected; + mShouldSave = shouldSave; + mBookmarkId = bookmarkId; + Log.d(TAG, "OfflinePageTabObserver built"); + } + + @Override + public void onShown(Tab visibleTab) { + if (mWasHidden) { + OfflinePageUtils.showOfflineSnackbar( + mActivity, visibleTab.getId(), mShouldSave, mConnected, mBookmarkId); + mWasHidden = false; + Log.d(TAG, "onShown, showing 'delayed' snackbar"); + } + } + + @Override + public void onHidden(Tab hiddenTab) { + mWasHidden = true; + // TODO(petewil): In case any snackbars are showing, dismiss them before we switch tabs. + } + + @Override + public void onDestroyed(Tab destroyedTab) { + // Unregister this tab for OS connectivity notifications. + if (mListener != null) { + mListener.disable(); + destroyedTab.removeObserver(this); + sConnectivityListeners.remove(destroyedTab.getId()); + Log.d(TAG, "onDestroyed"); + } + } + + @Override + public void onUrlUpdated(Tab reloadingTab) { + // Unregister this tab for OS connectivity notifications. + if (mListener != null) { + mListener.disable(); + reloadingTab.removeObserver(this); + sConnectivityListeners.remove(reloadingTab.getId()); + Log.d(TAG, "onUrlUpdated"); + } + } + + /** + * Attaches a connectivity listener if needed by this observer. + * @param tabId The index of the tab that this listener is listening to. + * @param listener The listener itself. + */ + public void setConnectivityListener(int tabId, OfflinePageConnectivityListener listener) { + mListener = listener; + sConnectivityListeners.put(tabId, mListener); + } + + /** + * Remembers if the page started hidden, so we know to show it if we get 'onShown' + * @param wasHidden True if the tab was hidden when the listener was set up. + */ + public void setWasHidden(boolean wasHidden) { + mWasHidden = wasHidden; + } +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtils.java index 523e226f..c5e4dd79 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtils.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtils.java
@@ -9,6 +9,7 @@ import android.net.NetworkInfo; import android.os.Environment; +import org.chromium.base.Log; import org.chromium.base.metrics.RecordUserAction; import org.chromium.chrome.R; import org.chromium.chrome.browser.ChromeActivity; @@ -16,7 +17,6 @@ import org.chromium.chrome.browser.enhancedbookmarks.EnhancedBookmarkUtils; import org.chromium.chrome.browser.snackbar.Snackbar; import org.chromium.chrome.browser.snackbar.SnackbarManager.SnackbarController; -import org.chromium.chrome.browser.tab.EmptyTabObserver; import org.chromium.chrome.browser.tab.Tab; import org.chromium.components.bookmarks.BookmarkId; import org.chromium.components.bookmarks.BookmarkType; @@ -27,6 +27,7 @@ * A class holding static util functions for offline pages. */ public class OfflinePageUtils { + private static final String TAG = "OfflinePageUtils"; /** Snackbar button types */ private static final int NO_BUTTON = 0; private static final int RELOAD_BUTTON = 1; @@ -83,11 +84,27 @@ return; } + Log.d(TAG, "showOfflineSnackbarIfNecessary called, tab " + tab); + boolean save; + final long bookmarkId = tab.getUserBookmarkId(); + Context context = activity.getBaseContext(); + final boolean connected = isConnected(context); + final boolean shouldSave = !tab.isOfflinePage(); + final OfflinePageTabObserver tabObserver = + new OfflinePageTabObserver(activity, connected, shouldSave, bookmarkId); if (tab.isOfflinePage()) { // If an offline page is being visited, prompt that an offline copy is being shown. save = false; + + // Set up the connectivity listener to watch for connectivity. + if (!connected) { + // Create a connectivityListener. + final OfflinePageConnectivityListener connectivityListener = + new OfflinePageConnectivityListener(activity, tab); + tabObserver.setConnectivityListener(tab.getId(), connectivityListener); + } } else if (tab.getUserBookmarkId() != ChromeBrowserProviderClient.INVALID_BOOKMARK_ID && !tab.hasOfflineCopy() && !tab.isShowingErrorPage() && OfflinePageBridge.canSavePage(tab.getUrl())) { @@ -99,29 +116,36 @@ return; } - if (tab.isHidden()) { - // Wait until the tab becomes visible. - final boolean finalSave = save; - tab.addObserver(new EmptyTabObserver() { - @Override - public void onShown(Tab visibleTab) { - showOfflineSnackbar(activity, visibleTab.getId(), finalSave, bookmarkId); - } - }); + // Add a listener if we are hidden or offline, we don't need one otherwise. + if (tab.isHidden() || !connected) { + // Remember if the tab was hidden when we started, so we can show the snackbar when + // the tab becomes visible. + tabObserver.setWasHidden(tab.isHidden()); + tab.addObserver(tabObserver); } else { - showOfflineSnackbar(activity, tab.getId(), save, bookmarkId); + showOfflineSnackbar(activity, tab.getId(), save, connected, bookmarkId); + Log.d(TAG, "Showing offline page snackbar"); } } /** + * Shows the "reload" snackbar for the given tab. + */ + public static void showReloadSnackbar(final ChromeActivity activity, Tab tab) { + boolean save = false; + boolean connected = true; + showOfflineSnackbar(activity, tab.getId(), save, connected, tab.getUserBookmarkId()); + } + + /** * Shows the snackbar for the current tab to provide offline specific information. * @param activity The activity owning the tab. * @param tabId The ID of current tab. * @param save Whether to offer saving the page. * @param bookmarkId Bookmark ID related to the opened page. */ - private static void showOfflineSnackbar( - final ChromeActivity activity, final int tabId, boolean save, final long bookmarkId) { + public static void showOfflineSnackbar(final ChromeActivity activity, final int tabId, + boolean save, boolean connected, final long bookmarkId) { Context context = activity.getBaseContext(); int snackbarTextId = -1; @@ -136,7 +160,7 @@ // Offer to reload the original page if there is network connection or edit if there is // none. - if (isConnected(context)) { + if (connected) { buttonType = RELOAD_BUTTON; actionTextId = R.string.reload; } else {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omaha/UpdateMenuItemHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/omaha/UpdateMenuItemHelper.java index f88610e..15cd117 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/omaha/UpdateMenuItemHelper.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/omaha/UpdateMenuItemHelper.java
@@ -100,7 +100,11 @@ * @param activity The current {@link ChromeActivity}. */ public void checkForUpdateOnBackgroundThread(final ChromeActivity activity) { - if (!getBooleanParam(ENABLE_UPDATE_MENU_ITEM)) return; + if (!getBooleanParam(ENABLE_UPDATE_MENU_ITEM) + && !getBooleanParam(ChromeSwitches.FORCE_SHOW_UPDATE_MENU_ITEM) + && !getBooleanParam(ChromeSwitches.FORCE_SHOW_UPDATE_MENU_BADGE)) { + return; + } ThreadUtils.assertOnUiThread();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/ListUrlsActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/ListUrlsActivity.java index 146b923..ecb2769 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/ListUrlsActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/ListUrlsActivity.java
@@ -59,7 +59,7 @@ mScanningImageView = (ImageView) findViewById(R.id.physical_web_logo); - mPwsClient = new PwsClient(); + mPwsClient = new PwsClientImpl(); int referer = getIntent().getIntExtra(REFERER_KEY, 0); if (savedInstanceState == null // Ensure this is a newly-created activity && referer == NOTIFICATION_REFERER) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PwsClient.java b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PwsClient.java index 50029d1..1d55fbf 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PwsClient.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PwsClient.java
@@ -5,33 +5,17 @@ package org.chromium.chrome.browser.physicalweb; import android.graphics.Bitmap; -import android.os.AsyncTask; -import org.chromium.base.Log; -import org.chromium.base.ThreadUtils; -import org.chromium.chrome.GoogleAPIKeys; -import org.chromium.chrome.browser.ChromeVersionInfo; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import java.net.MalformedURLException; -import java.util.ArrayList; import java.util.Collection; /** * This class sends requests to the Physical Web Service. */ -class PwsClient { - private static final String TAG = "PhysicalWeb"; - private static final String ENDPOINT_URL = - "https://physicalweb.googleapis.com/v1alpha1/urls:resolve"; - +interface PwsClient { /** * Callback that is run after the PWS sends a response to a resolve-scan request. */ - public interface ResolveScanCallback { + interface ResolveScanCallback { /** * Handle newly returned PwsResults. * @param pwsResults The results returned by the PWS. @@ -42,7 +26,7 @@ /** * Callback that is run after receiving the response to an icon fetch request. */ - public interface FetchIconCallback { + interface FetchIconCallback { /** * Handle newly returned favicon Bitmaps. * @param iconUrl The favicon URL. @@ -51,139 +35,17 @@ public void onIconReceived(String iconUrl, Bitmap iconBitmap); } - private String getApiKey() { - if (ChromeVersionInfo.isStableBuild()) { - return GoogleAPIKeys.GOOGLE_API_KEY; - } else { - return GoogleAPIKeys.GOOGLE_API_KEY_PHYSICAL_WEB_TEST; - } - } - - private static JSONObject createResolveScanPayload(Collection<String> urls) - throws JSONException { - // Encode the urls. - JSONArray objects = new JSONArray(); - for (String url : urls) { - JSONObject obj = new JSONObject(); - obj.put("url", url); - objects.put(obj); - } - - // Organize the data into a single object. - JSONObject jsonObject = new JSONObject(); - jsonObject.put("urls", objects); - return jsonObject; - } - - private static Collection<PwsResult> parseResolveScanResponse(JSONObject result) { - // Get the metadata array. - Collection<PwsResult> pwsResults = new ArrayList<>(); - JSONArray metadata = result.optJSONArray("results"); - if (metadata == null) { - // There are no valid results. - return pwsResults; - } - - // Loop through the metadata for each url. - for (int i = 0; i < metadata.length(); i++) { - try { - JSONObject obj = metadata.getJSONObject(i); - JSONObject pageInfo = obj.getJSONObject("pageInfo"); - String scannedUrl = obj.getString("scannedUrl"); - String resolvedUrl = obj.getString("resolvedUrl"); - String iconUrl = pageInfo.optString("icon", null); - String title = pageInfo.optString("title", ""); - String description = pageInfo.optString("description", ""); - pwsResults.add(new PwsResult(scannedUrl, resolvedUrl, iconUrl, title, description)); - } catch (JSONException e) { - Log.e(TAG, "PWS returned invalid data", e); - continue; - } - } - return pwsResults; - } - /** * Send an HTTP request to the PWS to resolve a set of URLs. * @param broadcastUrls The URLs to resolve. * @param resolveScanCallback The callback to be run when the response is received. */ - public void resolve(final Collection<String> broadcastUrls, - final ResolveScanCallback resolveScanCallback) { - // Create the response callback. - JsonObjectHttpRequest.RequestCallback requestCallback = - new JsonObjectHttpRequest.RequestCallback() { - @Override - public void onResponse(JSONObject result) { - ThreadUtils.assertOnUiThread(); - Collection<PwsResult> pwsResults = parseResolveScanResponse(result); - resolveScanCallback.onPwsResults(pwsResults); - } - - @Override - public void onError(int responseCode, Exception e) { - ThreadUtils.assertOnUiThread(); - String httpErr = ""; - if (responseCode > 0) { - httpErr = ", HTTP " + responseCode; - } - Log.e(TAG, "Error making request to PWS%s", httpErr); - resolveScanCallback.onPwsResults(new ArrayList<PwsResult>()); - } - }; - - // Create the request. - HttpRequest request = null; - try { - JSONObject payload = createResolveScanPayload(broadcastUrls); - String url = ENDPOINT_URL + "?key=" + getApiKey(); - request = new JsonObjectHttpRequest(url, payload, requestCallback); - } catch (MalformedURLException e) { - Log.e(TAG, "Error creating PWS HTTP request", e); - return; - } catch (JSONException e) { - Log.e(TAG, "Error creating PWS JSON payload", e); - return; - } - // The callback will be called on the main thread. - AsyncTask.THREAD_POOL_EXECUTOR.execute(request); - } + void resolve(Collection<String> broadcastUrls, ResolveScanCallback resolveScanCallback); /** * Send an HTTP request to fetch a favicon. * @param iconUrl The URL of the favicon. * @param fetchIconCallback The callback to be run when the icon is received. */ - public void fetchIcon(final String iconUrl, - final FetchIconCallback fetchIconCallback) { - // Create the response callback. - BitmapHttpRequest.RequestCallback requestCallback = - new BitmapHttpRequest.RequestCallback() { - @Override - public void onResponse(Bitmap iconBitmap) { - fetchIconCallback.onIconReceived(iconUrl, iconBitmap); - } - - @Override - public void onError(int responseCode, Exception e) { - ThreadUtils.assertOnUiThread(); - String httpErr = ""; - if (responseCode > 0) { - httpErr = ", HTTP " + responseCode; - } - Log.e(TAG, "Error requesting icon%s", httpErr); - } - }; - - // Create the request. - BitmapHttpRequest request = null; - try { - request = new BitmapHttpRequest(iconUrl, requestCallback); - } catch (MalformedURLException e) { - Log.e(TAG, "Error creating icon request", e); - return; - } - // The callback will be called on the main thread. - AsyncTask.THREAD_POOL_EXECUTOR.execute(request); - } + void fetchIcon(String iconUrl, FetchIconCallback fetchIconCallback); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PwsClientImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PwsClientImpl.java new file mode 100644 index 0000000..bdcf54ab --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PwsClientImpl.java
@@ -0,0 +1,170 @@ +// 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.physicalweb; + +import android.graphics.Bitmap; +import android.os.AsyncTask; + +import org.chromium.base.Log; +import org.chromium.base.ThreadUtils; +import org.chromium.chrome.GoogleAPIKeys; +import org.chromium.chrome.browser.ChromeVersionInfo; +import org.chromium.chrome.browser.physicalweb.PwsClient.FetchIconCallback; +import org.chromium.chrome.browser.physicalweb.PwsClient.ResolveScanCallback; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.net.MalformedURLException; +import java.util.ArrayList; +import java.util.Collection; + +/** + * This class sends requests to the Physical Web Service. + */ +class PwsClientImpl implements PwsClient { + private static final String TAG = "PhysicalWeb"; + private static final String ENDPOINT_URL = + "https://physicalweb.googleapis.com/v1alpha1/urls:resolve"; + + private String getApiKey() { + if (ChromeVersionInfo.isStableBuild()) { + return GoogleAPIKeys.GOOGLE_API_KEY; + } else { + return GoogleAPIKeys.GOOGLE_API_KEY_PHYSICAL_WEB_TEST; + } + } + + private static JSONObject createResolveScanPayload(Collection<String> urls) + throws JSONException { + // Encode the urls. + JSONArray objects = new JSONArray(); + for (String url : urls) { + JSONObject obj = new JSONObject(); + obj.put("url", url); + objects.put(obj); + } + + // Organize the data into a single object. + JSONObject jsonObject = new JSONObject(); + jsonObject.put("urls", objects); + return jsonObject; + } + + private static Collection<PwsResult> parseResolveScanResponse(JSONObject result) { + // Get the metadata array. + Collection<PwsResult> pwsResults = new ArrayList<>(); + JSONArray metadata = result.optJSONArray("results"); + if (metadata == null) { + // There are no valid results. + return pwsResults; + } + + // Loop through the metadata for each url. + for (int i = 0; i < metadata.length(); i++) { + try { + JSONObject obj = metadata.getJSONObject(i); + JSONObject pageInfo = obj.getJSONObject("pageInfo"); + String scannedUrl = obj.getString("scannedUrl"); + String resolvedUrl = obj.getString("resolvedUrl"); + String iconUrl = pageInfo.optString("icon", null); + String title = pageInfo.optString("title", ""); + String description = pageInfo.optString("description", ""); + pwsResults.add(new PwsResult(scannedUrl, resolvedUrl, iconUrl, title, description)); + } catch (JSONException e) { + Log.e(TAG, "PWS returned invalid data", e); + continue; + } + } + return pwsResults; + } + + /** + * Send an HTTP request to the PWS to resolve a set of URLs. + * @param broadcastUrls The URLs to resolve. + * @param resolveScanCallback The callback to be run when the response is received. + */ + @Override + public void resolve(final Collection<String> broadcastUrls, + final ResolveScanCallback resolveScanCallback) { + // Create the response callback. + JsonObjectHttpRequest.RequestCallback requestCallback = + new JsonObjectHttpRequest.RequestCallback() { + @Override + public void onResponse(JSONObject result) { + ThreadUtils.assertOnUiThread(); + Collection<PwsResult> pwsResults = parseResolveScanResponse(result); + resolveScanCallback.onPwsResults(pwsResults); + } + + @Override + public void onError(int responseCode, Exception e) { + ThreadUtils.assertOnUiThread(); + String httpErr = ""; + if (responseCode > 0) { + httpErr = ", HTTP " + responseCode; + } + Log.e(TAG, "Error making request to PWS%s", httpErr); + resolveScanCallback.onPwsResults(new ArrayList<PwsResult>()); + } + }; + + // Create the request. + HttpRequest request = null; + try { + JSONObject payload = createResolveScanPayload(broadcastUrls); + String url = ENDPOINT_URL + "?key=" + getApiKey(); + request = new JsonObjectHttpRequest(url, payload, requestCallback); + } catch (MalformedURLException e) { + Log.e(TAG, "Error creating PWS HTTP request", e); + return; + } catch (JSONException e) { + Log.e(TAG, "Error creating PWS JSON payload", e); + return; + } + // The callback will be called on the main thread. + AsyncTask.THREAD_POOL_EXECUTOR.execute(request); + } + + /** + * Send an HTTP request to fetch a favicon. + * @param iconUrl The URL of the favicon. + * @param fetchIconCallback The callback to be run when the icon is received. + */ + @Override + public void fetchIcon(final String iconUrl, + final FetchIconCallback fetchIconCallback) { + // Create the response callback. + BitmapHttpRequest.RequestCallback requestCallback = + new BitmapHttpRequest.RequestCallback() { + @Override + public void onResponse(Bitmap iconBitmap) { + fetchIconCallback.onIconReceived(iconUrl, iconBitmap); + } + + @Override + public void onError(int responseCode, Exception e) { + ThreadUtils.assertOnUiThread(); + String httpErr = ""; + if (responseCode > 0) { + httpErr = ", HTTP " + responseCode; + } + Log.e(TAG, "Error requesting icon%s", httpErr); + } + }; + + // Create the request. + BitmapHttpRequest request = null; + try { + request = new BitmapHttpRequest(iconUrl, requestCallback); + } catch (MalformedURLException e) { + Log.e(TAG, "Error creating icon request", e); + return; + } + // The callback will be called on the main thread. + AsyncTask.THREAD_POOL_EXECUTOR.execute(request); + } +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/UrlManager.java b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/UrlManager.java index 45924a7f..683234c 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/UrlManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/UrlManager.java
@@ -5,6 +5,7 @@ package org.chromium.chrome.browser.physicalweb; import android.app.Notification; +import android.app.NotificationManager; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; @@ -14,11 +15,13 @@ import android.graphics.BitmapFactory; import android.os.SystemClock; import android.support.v4.app.NotificationCompat; -import android.support.v4.app.NotificationManagerCompat; import org.chromium.base.Log; +import org.chromium.base.VisibleForTesting; import org.chromium.chrome.R; import org.chromium.chrome.browser.notifications.NotificationConstants; +import org.chromium.chrome.browser.notifications.NotificationManagerProxy; +import org.chromium.chrome.browser.notifications.NotificationManagerProxyImpl; import java.util.Arrays; import java.util.Collection; @@ -48,8 +51,8 @@ private static final int PREFS_VERSION = 2; private static UrlManager sInstance = null; private final Context mContext; - private final NotificationManagerCompat mNotificationManager; - private final PwsClient mPwsClient; + private NotificationManagerProxy mNotificationManager; + private PwsClient mPwsClient; /** * Construct the UrlManager. @@ -57,8 +60,9 @@ */ public UrlManager(Context context) { mContext = context; - mNotificationManager = NotificationManagerCompat.from(context); - mPwsClient = new PwsClient(); + mNotificationManager = new NotificationManagerProxyImpl( + (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE)); + mPwsClient = new PwsClientImpl(); initSharedPreferences(); } @@ -79,6 +83,7 @@ * This method additionally updates the Physical Web notification. * @param url The URL to add. */ + @VisibleForTesting public void addUrl(String url) { Log.d(TAG, "URL found: " + url); boolean isOnboarding = PhysicalWeb.isOnboarding(mContext); @@ -342,4 +347,15 @@ private void clearNotification() { mNotificationManager.cancel(NotificationConstants.NOTIFICATION_ID_PHYSICAL_WEB); } + + @VisibleForTesting + void overridePwsClientForTesting(PwsClient pwsClient) { + mPwsClient = pwsClient; + } + + @VisibleForTesting + void overrideNotificationManagerForTesting( + NotificationManagerProxy notificationManager) { + mNotificationManager = notificationManager; + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceManager.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceManager.java index 014ceec1..6b2f758 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceManager.java
@@ -9,8 +9,10 @@ import android.preference.PreferenceManager; import org.chromium.base.annotations.SuppressFBWarnings; +import org.chromium.chrome.browser.crash.MinidumpUploadService.ProcessType; import org.chromium.chrome.browser.signin.SigninPromoUma; +import java.util.Locale; /** * ChromePreferenceManager stores and retrieves various values in Android shared preferences. */ @@ -21,8 +23,6 @@ */ public static final String MIGRATION_ON_UPGRADE_ATTEMPTED = "migration_on_upgrade_attempted"; - private static final String BREAKPAD_UPLOAD_SUCCESS = "breakpad_upload_success"; - private static final String BREAKPAD_UPLOAD_FAIL = "breakpad_upload_fail"; private static final String PROMOS_SKIPPED_ON_FIRST_START = "promos_skipped_on_first_start"; private static final String SIGNIN_PROMO_LAST_SHOWN = "signin_promo_last_timestamp_key"; private static final String SHOW_SIGNIN_PROMO = "show_signin_promo"; @@ -39,6 +39,9 @@ "contextual_search_last_animation_time"; private static final String ENABLE_CUSTOM_TABS = "enable_custom_tabs"; + private static final String SUCCESS_UPLOAD_SUFFIX = "_crash_success_upload"; + private static final String FAILURE_UPLOAD_SUFFIX = "_crash_failure_upload"; + private static final int SIGNIN_PROMO_CYCLE_IN_DAYS = 120; private static final long MILLISECONDS_IN_DAY = 1000 * 60 * 60 * 24; @@ -66,39 +69,51 @@ } /** - * @return Number of times the upload intent service successfully uploaded - * a minidump. + * @return Number of times of successful crash upload. */ - public int getBreakpadUploadSuccessCount() { - return mSharedPreferences.getInt(BREAKPAD_UPLOAD_SUCCESS, 0); + public int getCrashSuccessUploadCount(@ProcessType String process) { + // Convention to keep all the key in preference lower case. + return mSharedPreferences.getInt(successUploadKey(process), 0); } - public void setBreakpadUploadSuccessCount(int count) { - SharedPreferences.Editor sharedPreferencesEditor = mSharedPreferences.edit(); - sharedPreferencesEditor.putInt(BREAKPAD_UPLOAD_SUCCESS, count); + public void setCrashSuccessUploadCount(@ProcessType String process, int count) { + SharedPreferences.Editor sharedPreferencesEditor; + + sharedPreferencesEditor = mSharedPreferences.edit(); + // Convention to keep all the key in preference lower case. + sharedPreferencesEditor.putInt(successUploadKey(process), count); sharedPreferencesEditor.apply(); } - public void incrementBreakpadUploadSuccessCount() { - setBreakpadUploadSuccessCount(getBreakpadUploadSuccessCount() + 1); + public void incrementCrashSuccessUploadCount(@ProcessType String process) { + setCrashSuccessUploadCount(process, getCrashSuccessUploadCount(process) + 1); + } + + private String successUploadKey(@ProcessType String process) { + return process.toLowerCase(Locale.US) + SUCCESS_UPLOAD_SUFFIX; } /** - * @return Number of times the upload intent service gave up on uploading - * minidump after a few tries. + * @return Number of times of failure crash upload after reaching the max number of tries. */ - public int getBreakpadUploadFailCount() { - return mSharedPreferences.getInt(BREAKPAD_UPLOAD_FAIL, 0); + public int getCrashFailureUploadCount(@ProcessType String process) { + return mSharedPreferences.getInt(failureUploadKey(process), 0); } - public void setBreakpadUploadFailCount(int count) { - SharedPreferences.Editor sharedPreferencesEditor = mSharedPreferences.edit(); - sharedPreferencesEditor.putInt(BREAKPAD_UPLOAD_FAIL, count); + public void setCrashFailureUploadCount(@ProcessType String process, int count) { + SharedPreferences.Editor sharedPreferencesEditor; + + sharedPreferencesEditor = mSharedPreferences.edit(); + sharedPreferencesEditor.putInt(failureUploadKey(process), count); sharedPreferencesEditor.apply(); } - public void incrementBreakpadUploadFailCount() { - setBreakpadUploadFailCount(getBreakpadUploadFailCount() + 1); + public void incrementCrashFailureUploadCount(@ProcessType String process) { + setCrashFailureUploadCount(process, getCrashFailureUploadCount(process) + 1); + } + + private String failureUploadKey(@ProcessType String process) { + return process.toLowerCase(Locale.US) + FAILURE_UPLOAD_SUFFIX; } /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/PrefServiceBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/PrefServiceBridge.java index 1d6755a..81abafa 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/PrefServiceBridge.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/PrefServiceBridge.java
@@ -10,6 +10,7 @@ import android.util.Log; import org.chromium.base.ThreadUtils; +import org.chromium.base.VisibleForTesting; import org.chromium.base.annotations.CalledByNative; import org.chromium.chrome.browser.ContentSettingsType; import org.chromium.chrome.browser.preferences.website.ContentSetting; @@ -368,6 +369,13 @@ } /** + * @return the last account id associated with sync. + */ + public String getSyncLastAccountId() { + return nativeGetSyncLastAccountId(); + } + + /** * @return the last account username associated with sync. */ public String getSyncLastAccountName() { @@ -923,6 +931,11 @@ return nativeGetClickedUpdateMenuItem(); } + @VisibleForTesting + public void setSupervisedUserId(String supervisedUserId) { + nativeSetSupervisedUserId(supervisedUserId); + } + private native boolean nativeGetAcceptCookiesEnabled(); private native boolean nativeGetAcceptCookiesManaged(); private native boolean nativeGetBlockThirdPartyCookiesEnabled(); @@ -1004,6 +1017,7 @@ private native void nativeSetResolveNavigationErrorEnabled(boolean enabled); private native void nativeSetEulaAccepted(); private native void nativeResetAcceptLanguages(String defaultLocale); + private native String nativeGetSyncLastAccountId(); private native String nativeGetSyncLastAccountName(); private native String nativeGetSupervisedUserCustodianName(); private native String nativeGetSupervisedUserCustodianEmail(); @@ -1017,4 +1031,5 @@ private native boolean nativeHasSetMetricsReporting(); private native void nativeSetClickedUpdateMenuItem(boolean clicked); private native boolean nativeGetClickedUpdateMenuItem(); + private native void nativeSetSupervisedUserId(String supervisedUserId); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountIdProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountIdProvider.java index 902c22b..423409da 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountIdProvider.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountIdProvider.java
@@ -4,7 +4,6 @@ package org.chromium.chrome.browser.signin; -import android.app.Activity; import android.content.Context; import com.google.android.gms.auth.GoogleAuthException; @@ -18,8 +17,6 @@ import java.io.IOException; -import javax.annotation.Nullable; - /** * Returns a stable id that can be used to identify a Google Account. This * id does not change if the email address associated to the account changes, @@ -55,15 +52,10 @@ * Returns whether the AccountIdProvider can be used. * Since the AccountIdProvider queries Google Play services, this basically checks whether * Google Play services is available. - * - * @param activity If an activity is provided, it will be used to show a Modal Dialog notifying - * the user to update Google Play services, else a System notification is shown. */ - public boolean canBeUsed(Context ctx, @Nullable Activity activity) { - UserRecoverableErrorHandler errorHandler = activity != null - ? new UserRecoverableErrorHandler.ModalDialog(activity) - : new UserRecoverableErrorHandler.SystemNotification(); - return ExternalAuthUtils.getInstance().canUseGooglePlayServices(ctx, errorHandler); + public boolean canBeUsed(Context ctx) { + return ExternalAuthUtils.getInstance().canUseGooglePlayServices( + ctx, new UserRecoverableErrorHandler.Silent()); } /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountTrackerService.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountTrackerService.java index 7ea1b7b9..dbc87e2 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountTrackerService.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountTrackerService.java
@@ -99,7 +99,7 @@ mSystemAccountsChanged = false; mSyncForceRefreshedForTest = false; final AccountIdProvider accountIdProvider = AccountIdProvider.getInstance(); - if (accountIdProvider.canBeUsed(mContext, null)) { + if (accountIdProvider.canBeUsed(mContext)) { mSystemAccountsSeedingStatus = SystemAccountsSeedingStatus.SEEDING_IN_PROGRESS; } else { mSystemAccountsSeedingStatus = SystemAccountsSeedingStatus.SEEDING_NOT_STARTED;
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 ff08ec7..d1ac844 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
@@ -18,9 +18,8 @@ import org.chromium.base.ObserverList; import org.chromium.base.ThreadUtils; import org.chromium.base.annotations.CalledByNative; -import org.chromium.chrome.browser.notifications.GoogleServicesNotificationController; -import org.chromium.chrome.browser.sync.ProfileSyncService; -import org.chromium.sync.AndroidSyncSettings; +import org.chromium.chrome.browser.externalauth.ExternalAuthUtils; +import org.chromium.chrome.browser.externalauth.UserRecoverableErrorHandler; import org.chromium.sync.signin.ChromeSigninController; import javax.annotation.Nullable; @@ -49,13 +48,6 @@ /** Forced signin for child accounts. */ public static final int SIGNIN_TYPE_FORCED_CHILD_ACCOUNT = 2; - // The timing of enabling the ProfileSyncService. - /** Postpone sync till the set up is fully complete. */ - public static final int SIGNIN_SYNC_SETUP_IN_PROGRESS = 0; - - /** Enable sync immediately. */ - public static final int SIGNIN_SYNC_IMMEDIATELY = 1; - private static final String TAG = "SigninManager"; private static SigninManager sSigninManager; @@ -74,8 +66,6 @@ private final ObserverList<SignInAllowedObserver> mSignInAllowedObservers = new ObserverList<SignInAllowedObserver>(); - private final SigninNotificationController mSigninNotificationController; - private Activity mSignInActivity; private Account mSignInAccount; private SignInFlowObserver mSignInFlowObserver; @@ -169,11 +159,6 @@ 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); AccountTrackerService.get(mContext).addSystemAccountsSeededListener(this); } @@ -241,13 +226,6 @@ } /** - * Return the SigninNotificationController. - */ - public SigninNotificationController getSigninNotificationController() { - return mSigninNotificationController; - } - - /** * Continue pending sign in after system accounts have been seeded into AccountTrackerService. */ @Override @@ -281,7 +259,7 @@ * @param passive If passive is true then this operation should not interact with the user. * @param observer The Observer to notify when the sign-in process is finished. */ - public void startSignIn(Activity activity, final Account account, boolean passive, + public void startSignIn(@Nullable Activity activity, final Account account, boolean passive, final SignInFlowObserver observer) { if (mSignInAccount != null) { Log.w(TAG, "Ignoring sign-in request as another sign-in request is pending."); @@ -301,7 +279,16 @@ notifySignInAllowedChanged(); if (!AccountTrackerService.get(mContext).checkAndSeedSystemAccounts()) { - mHasPendingSignin = true; + if (AccountIdProvider.getInstance().canBeUsed(mContext)) { + mHasPendingSignin = true; + } else { + UserRecoverableErrorHandler errorHandler = activity != null + ? new UserRecoverableErrorHandler.ModalDialog(activity) + : new UserRecoverableErrorHandler.SystemNotification(); + ExternalAuthUtils.getInstance().canUseGooglePlayServices(mContext, errorHandler); + Log.w(TAG, "Cancelling the sign-in process as Google Play services is unavailable"); + cancelSignIn(); + } return; } @@ -391,15 +378,6 @@ // sync tries to start without being signed in natively and crashes. ChromeSigninController.get(mContext).setSignedInAccountName(mSignInAccount.name); - // Sign-in to sync. - ProfileSyncService profileSyncService = ProfileSyncService.get(); - if (profileSyncService != null - && AndroidSyncSettings.isSyncEnabled(mContext) - && !profileSyncService.hasSyncSetupCompleted()) { - profileSyncService.setSetupInProgress(true); - profileSyncService.requestStart(); - } - if (mSignInFlowObserver != null) mSignInFlowObserver.onSigninComplete(); // All done, cleanup. @@ -443,12 +421,7 @@ boolean wipeData = getManagementDomain() != null; Log.d(TAG, "Signing out, wipe data? " + wipeData); - ProfileSyncService profileSyncService = ProfileSyncService.get(); - if (profileSyncService != null) { - profileSyncService.signOut(); - } ChromeSigninController.get(mContext).setSignedInAccountName(null); - mSigninNotificationController.onClearSignedInUser(); nativeSignOut(mNativeSigninManagerAndroid); if (wipeData) { @@ -497,13 +470,10 @@ * signin. * @param account The account to sign into. * @param signInType The type of the sign-in (one of SIGNIN_TYPE constants). - * @param signInSync When to enable the ProfileSyncService (one of SIGNIN_SYNC constants). - * @param showSignInNotification Whether the sign-in notification should be shown. * @param observer The observer to invoke when done, or null. */ public void signInToSelectedAccount(@Nullable Activity activity, final Account account, - final int signInType, final int signInSync, final boolean showSignInNotification, - @Nullable final SignInFlowObserver observer) { + final int signInType, @Nullable final SignInFlowObserver observer) { // The SigninManager handles most of the sign-in flow, and onSigninComplete handles the // Chrome-specific details. final boolean passive = signInType != SIGNIN_TYPE_INTERACTIVE; @@ -511,15 +481,6 @@ startSignIn(activity, account, passive, new SignInFlowObserver() { @Override public void onSigninComplete() { - // TODO(acleung): Maybe GoogleServicesManager should have a - // sync = true but setSetupInProgress(true) state? - ProfileSyncService profileSyncService = ProfileSyncService.get(); - if (profileSyncService != null) { - profileSyncService.setSetupInProgress( - signInSync == SIGNIN_SYNC_SETUP_IN_PROGRESS); - profileSyncService.requestStart(); - } - if (observer != null) observer.onSigninComplete(); if (signInType != SIGNIN_TYPE_INTERACTIVE) { @@ -527,14 +488,6 @@ } SigninManager.get(mContext).logInSignedInUser(); - // If Chrome was started from an external intent we should show the sync signin - // popup, since the user has not seen the welcome screen where there is easy access - // to turn off sync. - if (showSignInNotification) { - SigninManager.get(mContext) - .getSigninNotificationController() - .showSyncSignInNotification(); - } } @Override public void onSigninCancelled() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninNotificationController.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninNotificationController.java deleted file mode 100644 index 167a9a9..0000000 --- a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninNotificationController.java +++ /dev/null
@@ -1,58 +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. - -package org.chromium.chrome.browser.signin; - -import android.app.Fragment; -import android.content.Context; -import android.content.Intent; - -import org.chromium.chrome.R; -import org.chromium.chrome.browser.notifications.GoogleServicesNotificationController; -import org.chromium.chrome.browser.notifications.NotificationConstants; -import org.chromium.chrome.browser.preferences.PreferencesLauncher; - -/** - * {@link SigninNotificationController} provides functionality for displaying Android notifications - * regarding the user sign-in status. - */ -public class SigninNotificationController { - private final Context mApplicationContext; - private final GoogleServicesNotificationController mNotificationController; - private final Class<? extends Fragment> mAccountManagementFragment; - - public SigninNotificationController(Context context, - GoogleServicesNotificationController controller, - Class<? extends Fragment> accountManagementFragment) { - mApplicationContext = context.getApplicationContext(); - mNotificationController = controller; - mAccountManagementFragment = accountManagementFragment; - } - - /** - * Alerts the user through the notification bar that they have been signed in to Chrome. - * Clicking on the notification should immediately go to the sync account page. - */ - public void showSyncSignInNotification() { - // Create an Intent to go to the sync page. - Intent prefIntent = PreferencesLauncher.createIntentForSettingsPage( - mApplicationContext, mAccountManagementFragment.getCanonicalName()); - - // Create the notification. - String title = - mApplicationContext.getResources().getString(R.string.firstrun_signed_in_title); - String syncPromo = title + " " - + mApplicationContext.getResources().getString( - R.string.firstrun_signed_in_description); - mNotificationController.showNotification( - NotificationConstants.NOTIFICATION_ID_SIGNED_IN, title, syncPromo, prefIntent); - } - - /** - * Called when the user signs outs. - */ - public void onClearSignedInUser() { - mNotificationController.cancelNotification(NotificationConstants.NOTIFICATION_ID_SIGNED_IN); - } -}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninPromoScreen.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninPromoScreen.java index 39123cef..c1740ddd 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninPromoScreen.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninPromoScreen.java
@@ -116,9 +116,9 @@ dismiss(); } }; - SigninManager.get(getOwnerActivity().getApplicationContext()).signInToSelectedAccount( - getOwnerActivity(), account, SigninManager.SIGNIN_TYPE_INTERACTIVE, - SigninManager.SIGNIN_SYNC_IMMEDIATELY, false, signInCallback); + SigninManager.get(getOwnerActivity().getApplicationContext()) + .signInToSelectedAccount(getOwnerActivity(), account, + SigninManager.SIGNIN_TYPE_INTERACTIVE, signInCallback); } @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/superviseduser/SupervisedUserContentProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/superviseduser/SupervisedUserContentProvider.java new file mode 100644 index 0000000..a07b5bcc --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/superviseduser/SupervisedUserContentProvider.java
@@ -0,0 +1,178 @@ +// 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.superviseduser; + +import android.os.Bundle; +import android.util.Pair; + +import org.chromium.base.ThreadUtils; +import org.chromium.base.VisibleForTesting; +import org.chromium.base.annotations.CalledByNative; +import org.chromium.base.library_loader.LibraryProcessType; +import org.chromium.base.library_loader.ProcessInitException; +import org.chromium.components.webrestriction.WebRestrictionsContentProvider; +import org.chromium.content.browser.BrowserStartupController; + +import java.util.concurrent.CountDownLatch; + +/** + * Content provider for telling other apps (e.g. WebView apps) about the supervised user URL filter. + */ +public class SupervisedUserContentProvider extends WebRestrictionsContentProvider { + private long mNativeSupervisedUserContentProvider = 0; + + private long getSupervisedUserContentProvider() throws ProcessInitException { + if (mNativeSupervisedUserContentProvider != 0) { + return mNativeSupervisedUserContentProvider; + } + + BrowserStartupController.get(getContext(), LibraryProcessType.PROCESS_BROWSER) + .startBrowserProcessesSync(false); + + mNativeSupervisedUserContentProvider = nativeCreateSupervisedUserContentProvider(); + return mNativeSupervisedUserContentProvider; + } + + @VisibleForTesting + void setNativeSupervisedUserContentProviderForTesting(long nativeProvider) { + mNativeSupervisedUserContentProvider = nativeProvider; + } + + @VisibleForTesting + static class SupervisedUserQueryReply { + final CountDownLatch mLatch = new CountDownLatch(1); + private Pair<Boolean, String> mResult; + @VisibleForTesting + @CalledByNative("SupervisedUserQueryReply") + void onQueryComplete(boolean result, String errorMessage) { + // This must be called precisely once per query. + assert mResult == null; + mResult = new Pair<Boolean, String>(result, errorMessage); + mLatch.countDown(); + } + Pair<Boolean, String> getResult() throws InterruptedException { + mLatch.await(); + return mResult; + } + } + + @Override + protected Pair<Boolean, String> shouldProceed(final String url) { + // This will be called on multiple threads (but never the UI thread), + // see http://developer.android.com/guide/components/processes-and-threads.html#ThreadSafe. + // The reply comes back on a different thread (possibly the UI thread) some time later. + // As such it needs to correctly match the replies to the calls. It does this by creating a + // reply object for each query, and passing this through the callback structure. The reply + // object also handles waiting for the reply. + final SupervisedUserQueryReply queryReply = new SupervisedUserQueryReply(); + ThreadUtils.runOnUiThread(new Runnable() { + @Override + public void run() { + try { + nativeShouldProceed(getSupervisedUserContentProvider(), queryReply, url); + } catch (ProcessInitException e) { + queryReply.onQueryComplete(false, null); + } + } + }); + try { + // This will block until an onQueryComplete call on a different thread adds + // something to the queue. + return queryReply.getResult(); + } catch (InterruptedException e) { + return new Pair<Boolean, String>(false, null); + } + } + + @Override + protected boolean canInsert() { + // Chrome always allows insertion requests. + return true; + } + + @VisibleForTesting + static class SupervisedUserInsertReply { + final CountDownLatch mLatch = new CountDownLatch(1); + boolean mResult; + @VisibleForTesting + @CalledByNative("SupervisedUserInsertReply") + void onInsertRequestSendComplete(boolean result) { + // This must be called precisely once per query. + assert mLatch.getCount() == 1; + mResult = result; + mLatch.countDown(); + } + boolean getResult() throws InterruptedException { + mLatch.await(); + return mResult; + } + } + + @Override + protected boolean requestInsert(final String url) { + // This will be called on multiple threads (but never the UI thread), + // see http://developer.android.com/guide/components/processes-and-threads.html#ThreadSafe. + // The reply comes back on a different thread (possibly the UI thread) some time later. + // As such it needs to correctly match the replies to the calls. It does this by creating a + // reply object for each query, and passing this through the callback structure. The reply + // object also handles waiting for the reply. + final SupervisedUserInsertReply insertReply = new SupervisedUserInsertReply(); + ThreadUtils.runOnUiThread(new Runnable() { + @Override + public void run() { + try { + nativeRequestInsert(getSupervisedUserContentProvider(), insertReply, url); + } catch (ProcessInitException e) { + insertReply.onInsertRequestSendComplete(false); + } + } + }); + try { + return insertReply.getResult(); + } catch (InterruptedException e) { + return false; + } + } + + @VisibleForTesting + @Override + public Bundle call(String method, String arg, Bundle bundle) { + if (method.equals("setFilterForTesting")) setFilterForTesting(); + return null; + } + + @VisibleForTesting + void setFilterForTesting() { + ThreadUtils.runOnUiThreadBlocking(new Runnable() { + @Override + public void run() { + try { + nativeSetFilterForTesting(getSupervisedUserContentProvider()); + } catch (ProcessInitException e) { + // There is no way of returning anything sensible here, so ignore the error and + // do nothing. + } + } + }); + } + + @VisibleForTesting + @CalledByNative + void onSupervisedUserFilterUpdated() { + onFilterChanged(); + } + + @VisibleForTesting native long nativeCreateSupervisedUserContentProvider(); + + @VisibleForTesting + native void nativeShouldProceed(long nativeSupervisedUserContentProvider, + SupervisedUserQueryReply queryReply, String url); + + @VisibleForTesting + native void nativeRequestInsert(long nativeSupervisedUserContentProvider, + SupervisedUserInsertReply insertReply, String url); + + private native void nativeSetFilterForTesting(long nativeSupervisedUserContentProvider); +}
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 786f98d..40e2e60 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
@@ -18,6 +18,7 @@ import org.chromium.chrome.browser.identity.UniqueIdentificationGeneratorFactory; import org.chromium.chrome.browser.invalidation.InvalidationController; import org.chromium.chrome.browser.signin.AccountManagementFragment; +import org.chromium.chrome.browser.signin.SigninManager; import org.chromium.chrome.browser.sync.ui.PassphraseActivity; import org.chromium.sync.AndroidSyncSettings; import org.chromium.sync.ModelType; @@ -102,6 +103,16 @@ if (gmsCoreSyncListener != null) { mProfileSyncService.addSyncStateChangedListener(gmsCoreSyncListener); } + + SigninManager.get(mContext).addSignInStateObserver(new SigninManager.SignInStateObserver() { + @Override + public void onSignedIn() { + mProfileSyncService.requestStart(); + } + + @Override + public void onSignedOut() {} + }); } /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/ui/ConfirmAccountChangeFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/sync/ui/ConfirmAccountChangeFragment.java index b3ca5ea..cfe67e03 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/sync/ui/ConfirmAccountChangeFragment.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/sync/ui/ConfirmAccountChangeFragment.java
@@ -38,6 +38,7 @@ private static final String KEY_NEW_ACCOUNT_NAME = "newAccountName"; public static void confirmSyncAccount(String syncAccountName, Activity activity) { + // TODO(skym): Use last account id for equality check, crbug.com/571698. String lastSyncAccountName = PrefServiceBridge.getInstance().getSyncLastAccountName(); if (lastSyncAccountName != null && !lastSyncAccountName.isEmpty() && !lastSyncAccountName.equals(syncAccountName)) { @@ -112,8 +113,7 @@ public void onResult(Account account) { if (account == null) return; SigninManager.get(activity).signInToSelectedAccount(activity, account, - SigninManager.SIGNIN_TYPE_INTERACTIVE, - SigninManager.SIGNIN_SYNC_IMMEDIATELY, false, null); + SigninManager.SIGNIN_TYPE_INTERACTIVE, null); } }); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/ReaderModeControl.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/ReaderModeControl.java deleted file mode 100644 index 3d08ee9b..0000000 --- a/chrome/android/java/src/org/chromium/chrome/browser/widget/ReaderModeControl.java +++ /dev/null
@@ -1,96 +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. - -package org.chromium.chrome.browser.widget; - -import android.content.Context; -import android.graphics.Rect; -import android.util.AttributeSet; -import android.view.View; -import android.view.ViewParent; -import android.widget.LinearLayout; -import android.widget.TextView; - -import org.chromium.chrome.R; - -import org.chromium.ui.resources.dynamics.ViewResourceAdapter; - -/** - * Root ControlContainer for the Reader Mode panel. - * Handles user interaction with the Reader Mode control. - * See {@link ContextualSearchBarControl} for inspiration, based on ToolbarControlContainer. - */ -public class ReaderModeControl extends LinearLayout { - private ViewResourceAdapter mResourceAdapter; - private TextView mReaderViewText; - private boolean mIsDirty = false; - - /** - * Constructs a new control container. - * <p> - * This constructor is used when inflating from XML. - * - * @param context The context used to build this view. - * @param attrs The attributes used to determine how to construct this view. - */ - public ReaderModeControl(Context context, AttributeSet attrs) { - super(context, attrs); - } - - /** - * @return The {@link ViewResourceAdapter} that exposes this {@link View} as a CC resource. - */ - public ViewResourceAdapter getResourceAdapter() { - return mResourceAdapter; - } - - @Override - public void onFinishInflate() { - super.onFinishInflate(); - - mReaderViewText = (TextView) findViewById(R.id.main_text); - mResourceAdapter = new ViewResourceAdapter(findViewById(R.id.reader_mode_view)); - mIsDirty = true; - } - - @Override - public ViewParent invalidateChildInParent(int[] location, Rect dirty) { - ViewParent parent = super.invalidateChildInParent(location, dirty); - // TODO(pedrosimonetti): ViewGroup#invalidateChildInParent() is being called multiple - // times with different rectangles (for each of the individual repaints it seems). This - // means in order to invalidate it only once we need to keep track of the dirty state, - // and call ViewResourceAdapter#invalidate() only once per change of state, passing - // "null" to indicate that the whole area should be invalidated. This can be deleted - // if we stop relying on an Android View to render our Search Bar Text. - if (mIsDirty && mResourceAdapter != null) { - mIsDirty = false; - mResourceAdapter.invalidate(null); - } - return parent; - } - - /** - * Sets the reader mode text to display in the control. - */ - public void setReaderModeText() { - mReaderViewText.setText(R.string.reader_view_text); - mIsDirty = true; - } - - /** - * @param X X-coordinate in dp - * @param Y Y-coordinate in dp - * @return Whether a given coordinates are within the bounds of the "dismiss" button - */ - public boolean isInsideDismissButton(float x, float y) { - View view = findViewById(R.id.main_close); - final int left = (int) (view.getLeft() + view.getTranslationX()); - final int top = (int) (view.getTop() + view.getTranslationY()); - final int right = left + view.getWidth(); - final int bottom = top + view.getHeight(); - final int ix = (int) x; - final int iy = (int) y; - return ix >= left && ix < right && iy >= top && iy < bottom; - } -}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/findinpage/FindToolbarTablet.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/findinpage/FindToolbarTablet.java index bd42e21..4880104 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/widget/findinpage/FindToolbarTablet.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/findinpage/FindToolbarTablet.java
@@ -55,7 +55,7 @@ int endMargin = resources.getDimensionPixelOffset(R.dimen.find_in_page_popup_margin_end); int translateWidth = width + endMargin; - mAnimationEnter = ObjectAnimator.ofFloat(this, "translationX", translateWidth, 0); + mAnimationEnter = ObjectAnimator.ofFloat(this, View.TRANSLATION_X, translateWidth, 0); mAnimationEnter.setDuration(ENTER_EXIT_ANIMATION_DURATION_MS); mAnimationEnter.setInterpolator(new DecelerateInterpolator()); mAnimationEnter.addListener(new AnimatorListenerAdapter() { @@ -72,7 +72,7 @@ } }); - mAnimationLeave = ObjectAnimator.ofFloat(this, "translationX", 0, translateWidth); + mAnimationLeave = ObjectAnimator.ofFloat(this, View.TRANSLATION_X, 0, translateWidth); mAnimationLeave.setDuration(ENTER_EXIT_ANIMATION_DURATION_MS); mAnimationLeave.setInterpolator(new DecelerateInterpolator()); mAnimationLeave.addListener(new AnimatorListenerAdapter() { @@ -136,8 +136,7 @@ float translationY = makeRoom ? -(getHeight() - mYInsetPx) : 0.f; if (translationY != getTranslationY()) { - mCurrentAnimation = ObjectAnimator.ofFloat(this, "translationY", getTranslationY(), - translationY); + mCurrentAnimation = ObjectAnimator.ofFloat(this, View.TRANSLATION_Y, translationY); mCurrentAnimation.setDuration(MAKE_ROOM_ANIMATION_DURATION_MS); mAnimationLeave.setInterpolator(new DecelerateInterpolator()); mAnimationLeave.addListener(new AnimatorListenerAdapter() {
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd index edf7066..782214f 100644 --- a/chrome/android/java/strings/android_chrome_strings.grd +++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -948,12 +948,6 @@ <message name="IDS_SIGNOUT_MANAGED_ACCOUNT_MESSAGE" desc="Message to display for sign out of Chrome dialog when the account has enterprise management, and all user data will be erased"> You are signing out of an account managed by <ph name="DOMAIN_NAME">%1$s<ex>google.com</ex></ph>. This will delete the Chrome data stored on this device, but the data will remain in your Google Account. </message> - <message name="IDS_FIRSTRUN_SIGNED_IN_TITLE" desc="Message informing the user that they are now signed in."> - You’re now signed in to Chrome. - </message> - <message name="IDS_FIRSTRUN_SIGNED_IN_DESCRIPTION" desc="Message informing the user what is being synced."> - Your open bookmarks, history, passwords, and more are being synced with your Google Account. - </message> <!-- Sync strings --> <message name="IDS_SIGN_IN_SYNC" desc="Sync preference title in signed-in prefs and prefix for notification related to sync [CHAR-LIMIT=32]"> @@ -1768,10 +1762,10 @@ </message> <!-- Main menu items --> - <message name="IDS_MENU_UPDATE" desc="Menu item for updating chrome. [CHAR-LIMIT=27]"> + <message name="IDS_MENU_UPDATE" desc="Menu item for updating chrome. [CHAR-LIMIT=24]"> Update Chrome </message> - <message name="IDS_MENU_UPDATE_SUMMARY_DEFAULT" desc="Summary string for update menu item explaing why Chrome should be updated. [CHAR-LIMIT=27]"> + <message name="IDS_MENU_UPDATE_SUMMARY_DEFAULT" desc="Summary string for update menu item explaing why Chrome should be updated. [CHAR-LIMIT=30]"> Newer version is available </message> <message name="IDS_MENU_NEW_TAB" desc="Menu item for opening a new tab. [CHAR-LIMIT=27]">
diff --git a/chrome/android/javatests/DEPS b/chrome/android/javatests/DEPS index 6f2d48d..51445be 100644 --- a/chrome/android/javatests/DEPS +++ b/chrome/android/javatests/DEPS
@@ -4,6 +4,7 @@ "+components/gcm_driver/android/java/src/org/chromium/components/gcm_driver", "+components/navigation_interception", "+components/precache/android/javatests", + "+components/web_restriction", "+content/public/android/java", "+sync/android/java/src/org/chromium/sync", # We should only depend on the util package of something that lives in
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/GeolocationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/GeolocationTest.java index 32c7b70..ea5182c6 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/GeolocationTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/GeolocationTest.java
@@ -8,7 +8,6 @@ import android.test.FlakyTest; import org.chromium.base.ThreadUtils; -import org.chromium.chrome.browser.infobar.InfoBar; import org.chromium.chrome.browser.infobar.InfoBarContainer; import org.chromium.chrome.browser.tab.EmptyTabObserver; import org.chromium.chrome.browser.tab.Tab; @@ -22,8 +21,6 @@ import org.chromium.content.browser.LocationProviderFactory.LocationProvider; import org.chromium.content.browser.test.util.CallbackHelper; -import java.util.List; - /** * Test suite for Geo-Location functionality. * @@ -103,8 +100,7 @@ tab.addObserver(observer); loadUrl(url); assertTrue("InfoBar not added.", mListener.addInfoBarAnimationFinished()); - List<InfoBar> infoBars = getActivity().getActivityTab().getInfoBarContainer().getInfoBars(); - assertTrue("OK button wasn't found", InfoBarUtil.clickPrimaryButton(infoBars.get(0))); + assertTrue("OK button wasn't found", InfoBarUtil.clickPrimaryButton(getInfoBars().get(0))); sendLocation(createMockLocation(LATITUDE, LONGITUDE, ACCURACY)); loadCallback.waitForCallback(0); @@ -141,11 +137,8 @@ loadUrl(url); assertTrue("InfoBar not added.", mListener.addInfoBarAnimationFinished()); - List<InfoBar> infoBars = getActivity().getActivityTab().getInfoBarContainer().getInfoBars(); - assertTrue("OK button wasn't found", InfoBarUtil.clickPrimaryButton(infoBars.get(0))); - + assertTrue("OK button wasn't found", InfoBarUtil.clickPrimaryButton(getInfoBars().get(0))); sendLocation(createMockLocation(LATITUDE, LONGITUDE, ACCURACY)); - loadCallback0.waitForCallback(0); tab.removeObserver(observer);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/PopupTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/PopupTest.java index b91c3d0..3a50950b 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/PopupTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/PopupTest.java
@@ -36,7 +36,7 @@ } private int getNumInfobarsShowing() { - return getActivity().getActivityTab().getInfoBarContainer().getInfoBars().size(); + return getInfoBars().size(); } @Override @@ -86,7 +86,7 @@ }); assertEquals(1, selector.getTotalTabCount()); final InfoBarContainer container = selector.getCurrentTab().getInfoBarContainer(); - ArrayList<InfoBar> infobars = container.getInfoBars(); + ArrayList<InfoBar> infobars = container.getInfoBarsForTesting(); assertEquals(1, infobars.size()); // Wait until the animations are done, then click the "open popups" button.
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/banners/AppBannerManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/banners/AppBannerManagerTest.java index 5749fe9..84ce205 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/banners/AppBannerManagerTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/banners/AppBannerManagerTest.java
@@ -193,8 +193,7 @@ CriteriaHelper.pollForUIThreadCriteria(new Criteria() { @Override public boolean isSatisfied() { - InfoBarContainer container = getActivity().getActivityTab().getInfoBarContainer(); - return container.getInfoBars().size() == 0; + return getInfoBars().isEmpty(); } }); } @@ -215,8 +214,7 @@ CriteriaHelper.pollForUIThreadCriteria(new Criteria() { @Override public boolean isSatisfied() { - InfoBarContainer container = getActivity().getActivityTab().getInfoBarContainer(); - ArrayList<InfoBar> infobars = container.getInfoBars(); + List<InfoBar> infobars = getInfoBars(); if (infobars.size() != 1) return false; if (!(infobars.get(0) instanceof AppBannerInfoBarAndroid)) return false; @@ -251,7 +249,7 @@ }); // Check that the button asks if the user wants to install the app. - InfoBar infobar = container.getInfoBars().get(0); + InfoBar infobar = container.getInfoBarsForTesting().get(0); final Button button = (Button) infobar.getView().findViewById(R.id.button_primary); assertEquals(NATIVE_APP_INSTALL_TEXT, button.getText()); @@ -365,7 +363,7 @@ return listener.mDoneAnimating; } }); - ArrayList<InfoBar> infobars = container.getInfoBars(); + ArrayList<InfoBar> infobars = container.getInfoBarsForTesting(); View close = infobars.get(0).getView().findViewById(R.id.infobar_close_button); TouchCommon.singleClickView(close); waitUntilNoInfoBarsExist(); @@ -487,7 +485,7 @@ }); // Click the button to trigger the adding of the shortcut. - InfoBar infobar = container.getInfoBars().get(0); + InfoBar infobar = container.getInfoBarsForTesting().get(0); final Button button = (Button) infobar.getView().findViewById(R.id.button_primary); TouchCommon.singleClickView(button);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/crash/CrashTestCase.java b/chrome/android/javatests/src/org/chromium/chrome/browser/crash/CrashTestCase.java index 30cec59f..c8ca9ce 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/crash/CrashTestCase.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/crash/CrashTestCase.java
@@ -50,6 +50,11 @@ } protected static void setUpMinidumpFile(File file, String boundary) throws IOException { + setUpMinidumpFile(file, boundary, null); + } + + protected static void setUpMinidumpFile(File file, String boundary, String processType) + throws IOException { PrintWriter minidumpWriter = null; try { minidumpWriter = new PrintWriter(new FileWriter(file)); @@ -61,9 +66,13 @@ minidumpWriter.println("Content-Disposition: form-data; name=\"ver\""); minidumpWriter.println(); minidumpWriter.println("1"); + if (processType != null) { + minidumpWriter.println("Content-Disposition: form-data; name=\"ptype\""); + minidumpWriter.println(); + minidumpWriter.println(processType); + } minidumpWriter.println(boundary + "--"); minidumpWriter.flush(); - minidumpWriter.close(); } finally { if (minidumpWriter != null) { minidumpWriter.close();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/crash/MinidumpUploadServiceTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/crash/MinidumpUploadServiceTest.java index 2ce4ea1..fa40279 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/crash/MinidumpUploadServiceTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/crash/MinidumpUploadServiceTest.java
@@ -4,6 +4,11 @@ package org.chromium.chrome.browser.crash; +import static org.chromium.chrome.browser.crash.MinidumpUploadService.BROWSER; +import static org.chromium.chrome.browser.crash.MinidumpUploadService.GPU; +import static org.chromium.chrome.browser.crash.MinidumpUploadService.OTHER; +import static org.chromium.chrome.browser.crash.MinidumpUploadService.RENDERER; + import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -23,7 +28,6 @@ import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; - /** * Testcase for {@link MinidumpUploadService}. */ @@ -358,6 +362,42 @@ assertTrue("Should have called startService(...)", context.isFlagSet(startServiceFlag)); } + @SmallTest + @Feature({"Android-AppBase"}) + public void testGetCrashType1() throws IOException { + final File minidumpFile = new File(mCrashDir, "chromium_renderer-123.dmp"); + setUpMinidumpFile(minidumpFile, BOUNDARY, "browser"); + assertEquals(BROWSER, + MinidumpUploadService.getCrashType(minidumpFile.getAbsolutePath())); + } + + @SmallTest + @Feature({"Android-AppBase"}) + public void testGetCrashType2() throws IOException { + final File minidumpFile = new File(mCrashDir, "chromium_renderer-123.dmp"); + setUpMinidumpFile(minidumpFile, BOUNDARY, "renderer"); + assertEquals(RENDERER, + MinidumpUploadService.getCrashType(minidumpFile.getAbsolutePath())); + } + + @SmallTest + @Feature({"Android-AppBase"}) + public void testGetCrashType3() throws IOException { + final File minidumpFile = new File(mCrashDir, "chromium_renderer-123.dmp"); + setUpMinidumpFile(minidumpFile, BOUNDARY, "gpu-process"); + assertEquals(GPU, + MinidumpUploadService.getCrashType(minidumpFile.getAbsolutePath())); + } + + @SmallTest + @Feature({"Android-AppBase"}) + public void testGetCrashType4() throws IOException { + final File minidumpFile = new File(mCrashDir, "chromium_renderer-123.dmp"); + setUpMinidumpFile(minidumpFile, BOUNDARY, "weird test type"); + assertEquals(OTHER, + MinidumpUploadService.getCrashType(minidumpFile.getAbsolutePath())); + } + private class MinidumpPreparationContext extends AdvancedMockContext { /** * Field used in overridden versions of startService() so we can support retries.
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandlerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandlerTest.java index 7c415049..89f32ba 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandlerTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandlerTest.java
@@ -1216,7 +1216,7 @@ } @Override - public boolean shouldRequestFileAccess(Tab tab) { + public boolean shouldRequestFileAccess(String url, Tab tab) { return shouldRequestFileAccess; }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/InfoBarControlLayoutTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/InfoBarControlLayoutTest.java index 5e0b5a5..a7d2b286 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/InfoBarControlLayoutTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/InfoBarControlLayoutTest.java
@@ -25,8 +25,8 @@ private static final int SWITCH_ID_3 = 3; private static final int SWITCH_ID_4 = 4; private static final int SWITCH_ID_5 = 5; + private static final int INFOBAR_WIDTH = 3200; - private int mMaxInfoBarWidth; private Context mContext; @Override @@ -34,7 +34,6 @@ super.setUp(); mContext = getInstrumentation().getTargetContext(); mContext.setTheme(R.style.MainTheme); - mMaxInfoBarWidth = mContext.getResources().getDimensionPixelSize(R.dimen.infobar_max_width); } /** @@ -50,7 +49,7 @@ // Trigger the measurement algorithm. int parentWidthSpec = - MeasureSpec.makeMeasureSpec(mMaxInfoBarWidth, MeasureSpec.AT_MOST); + MeasureSpec.makeMeasureSpec(INFOBAR_WIDTH, MeasureSpec.AT_MOST); int parentHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); layout.measure(parentWidthSpec, parentHeightSpec); @@ -59,7 +58,7 @@ assertEquals(0, params.top); assertEquals(0, params.start); assertEquals(2, params.columnsRequired); - assertEquals(mMaxInfoBarWidth, smallSwitch.getMeasuredWidth()); + assertEquals(INFOBAR_WIDTH, smallSwitch.getMeasuredWidth()); } /** @@ -92,11 +91,11 @@ View switch5 = layout.addSwitch(0, "E", SWITCH_ID_4, false); // Make the second control require the full layout width. - switch2.setMinimumWidth(mMaxInfoBarWidth); + switch2.setMinimumWidth(INFOBAR_WIDTH); // Trigger the measurement algorithm. int parentWidthSpec = - MeasureSpec.makeMeasureSpec(mMaxInfoBarWidth, MeasureSpec.AT_MOST); + MeasureSpec.makeMeasureSpec(INFOBAR_WIDTH, MeasureSpec.AT_MOST); int parentHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); layout.measure(parentWidthSpec, parentHeightSpec); @@ -110,33 +109,33 @@ assertEquals(0, params1.top); assertEquals(0, params1.start); assertEquals(2, params1.columnsRequired); - assertEquals(mMaxInfoBarWidth, switch1.getMeasuredWidth()); + assertEquals(INFOBAR_WIDTH, switch1.getMeasuredWidth()); // Big control gets shunted onto the next row and takes up the whole space. assertTrue(params2.top > switch1.getMeasuredHeight()); assertEquals(0, params2.start); assertEquals(2, params2.columnsRequired); - assertEquals(mMaxInfoBarWidth, switch2.getMeasuredWidth()); + assertEquals(INFOBAR_WIDTH, switch2.getMeasuredWidth()); // Small control gets placed onto the next line and takes only half the width. int bottomOfSwitch2 = params2.top + switch2.getMeasuredHeight(); assertTrue(params3.top > bottomOfSwitch2); assertEquals(0, params3.start); assertEquals(1, params3.columnsRequired); - assertTrue(switch3.getMeasuredWidth() < mMaxInfoBarWidth); + assertTrue(switch3.getMeasuredWidth() < INFOBAR_WIDTH); // Small control gets placed next to the previous small control. assertEquals(params3.top, params4.top); assertTrue(params4.start > switch3.getMeasuredWidth()); assertEquals(1, params4.columnsRequired); - assertTrue(switch4.getMeasuredWidth() < mMaxInfoBarWidth); + assertTrue(switch4.getMeasuredWidth() < INFOBAR_WIDTH); // Last small control has no room left and gets put on its own line, taking the full width. int bottomOfSwitch4 = params4.top + switch4.getMeasuredHeight(); assertTrue(params5.top > bottomOfSwitch4); assertEquals(0, params5.start); assertEquals(2, params5.columnsRequired); - assertEquals(mMaxInfoBarWidth, switch5.getMeasuredWidth()); + assertEquals(INFOBAR_WIDTH, switch5.getMeasuredWidth()); } /** @@ -155,7 +154,7 @@ // Trigger the measurement algorithm. int parentWidthSpec = - MeasureSpec.makeMeasureSpec(mMaxInfoBarWidth, MeasureSpec.AT_MOST); + MeasureSpec.makeMeasureSpec(INFOBAR_WIDTH, MeasureSpec.AT_MOST); int parentHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); layout.measure(parentWidthSpec, parentHeightSpec); @@ -166,12 +165,12 @@ assertEquals(0, params1.top); assertEquals(0, params1.start); assertEquals(2, params1.columnsRequired); - assertEquals(mMaxInfoBarWidth, view1.getMeasuredWidth()); + assertEquals(INFOBAR_WIDTH, view1.getMeasuredWidth()); // Small control gets shunted onto the next row. assertTrue(params2.top > view1.getMeasuredHeight()); assertEquals(0, params2.start); assertEquals(2, params2.columnsRequired); - assertEquals(mMaxInfoBarWidth, view2.getMeasuredWidth()); + assertEquals(INFOBAR_WIDTH, view2.getMeasuredWidth()); } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/InfoBarDualControlLayoutTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/InfoBarDualControlLayoutTest.java new file mode 100644 index 0000000..592b7c2b --- /dev/null +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/InfoBarDualControlLayoutTest.java
@@ -0,0 +1,197 @@ +// 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 static org.chromium.chrome.browser.infobar.InfoBarDualControlLayout.ALIGN_APART; +import static org.chromium.chrome.browser.infobar.InfoBarDualControlLayout.ALIGN_END; +import static org.chromium.chrome.browser.infobar.InfoBarDualControlLayout.ALIGN_START; + +import android.content.Context; +import android.test.InstrumentationTestCase; +import android.test.MoreAsserts; +import android.test.UiThreadTest; +import android.test.suitebuilder.annotation.SmallTest; +import android.view.View; +import android.view.View.MeasureSpec; +import android.view.ViewGroup.LayoutParams; +import android.widget.Space; + +import org.chromium.chrome.R; + +/** + * Tests for InfoBarDualControlLayout. + */ +public class InfoBarDualControlLayoutTest extends InstrumentationTestCase { + private static final int PRIMARY_HEIGHT = 16; + private static final int SECONDARY_HEIGHT = 8; + private static final int STACKED_MARGIN = 4; + private static final int INFOBAR_WIDTH = 3200; + + private int mTinyControlWidth; + private Context mContext; + + @Override + public void setUp() throws Exception { + super.setUp(); + mContext = getInstrumentation().getTargetContext(); + mContext.setTheme(R.style.MainTheme); + mTinyControlWidth = INFOBAR_WIDTH / 4; + } + + @SmallTest + @UiThreadTest + public void testAlignSideBySide() { + runLayoutTest(ALIGN_START, false, false); + runLayoutTest(ALIGN_START, false, true); + runLayoutTest(ALIGN_START, true, false); + runLayoutTest(ALIGN_START, true, true); + + runLayoutTest(ALIGN_APART, false, false); + runLayoutTest(ALIGN_APART, false, true); + runLayoutTest(ALIGN_APART, true, false); + runLayoutTest(ALIGN_APART, true, true); + + runLayoutTest(ALIGN_END, false, false); + runLayoutTest(ALIGN_END, false, true); + runLayoutTest(ALIGN_END, true, false); + runLayoutTest(ALIGN_END, true, true); + } + + /** Lays out two controls that fit on the same line. */ + private void runLayoutTest(int alignment, boolean isRtl, boolean addSecondView) { + InfoBarDualControlLayout layout = new InfoBarDualControlLayout(mContext, null); + layout.setAlignment(alignment); + layout.setLayoutDirection(isRtl ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR); + layout.setLayoutParams( + new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)); + + View primary = new Space(mContext); + primary.setMinimumWidth(mTinyControlWidth); + primary.setMinimumHeight(PRIMARY_HEIGHT); + layout.addView(primary); + + View secondary = null; + if (addSecondView) { + secondary = new Space(mContext); + secondary.setMinimumWidth(mTinyControlWidth); + secondary.setMinimumHeight(SECONDARY_HEIGHT); + layout.addView(secondary); + } + + // Trigger the measurement & layout algorithms. + int parentWidthSpec = MeasureSpec.makeMeasureSpec(INFOBAR_WIDTH, MeasureSpec.EXACTLY); + int parentHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); + layout.measure(parentWidthSpec, parentHeightSpec); + layout.layout(0, 0, layout.getMeasuredWidth(), layout.getMeasuredHeight()); + + // Confirm that the primary View is in the correct place. + if ((isRtl && alignment == ALIGN_START) + || (!isRtl && (alignment == ALIGN_APART || alignment == ALIGN_END))) { + assertEquals("Primary should be on the right.", INFOBAR_WIDTH, primary.getRight()); + } else { + assertEquals("Primary should be on the left.", 0, primary.getLeft()); + } + assertEquals(mTinyControlWidth, primary.getMeasuredWidth()); + assertEquals(PRIMARY_HEIGHT, primary.getMeasuredHeight()); + MoreAsserts.assertNotEqual(primary.getLeft(), primary.getRight()); + + // Confirm that the secondary View is in the correct place. + if (secondary != null) { + assertEquals(mTinyControlWidth, secondary.getMeasuredWidth()); + assertEquals(SECONDARY_HEIGHT, secondary.getMeasuredHeight()); + MoreAsserts.assertNotEqual(secondary.getLeft(), secondary.getRight()); + if (alignment == ALIGN_START) { + if (isRtl) { + // Secondary View is immediately to the left of the parent. + assertTrue(secondary.getRight() < primary.getLeft()); + MoreAsserts.assertNotEqual(0, secondary.getLeft()); + } else { + // Secondary View is immediately to the right of the parent. + assertTrue(primary.getRight() < secondary.getLeft()); + MoreAsserts.assertNotEqual(INFOBAR_WIDTH, secondary.getRight()); + } + } else if (alignment == ALIGN_APART) { + if (isRtl) { + // Secondary View is on the far right. + assertTrue(primary.getRight() < secondary.getLeft()); + assertEquals(INFOBAR_WIDTH, secondary.getRight()); + } else { + // Secondary View is on the far left. + assertTrue(secondary.getRight() < primary.getLeft()); + assertEquals(0, secondary.getLeft()); + } + } else { + assertEquals(ALIGN_END, alignment); + if (isRtl) { + // Secondary View is immediately to the right of the parent. + assertTrue(primary.getRight() < secondary.getLeft()); + MoreAsserts.assertNotEqual(INFOBAR_WIDTH, secondary.getRight()); + } else { + // Secondary View is immediately to the left of the parent. + assertTrue(secondary.getRight() < primary.getLeft()); + MoreAsserts.assertNotEqual(0, secondary.getLeft()); + } + } + + // Confirm that the secondary View is centered with respect to the first. + int primaryCenter = (primary.getTop() + primary.getBottom()) / 2; + int secondaryCenter = (secondary.getTop() + secondary.getBottom()) / 2; + assertEquals(primaryCenter, secondaryCenter); + } + + assertEquals(layout.getMeasuredHeight(), primary.getMeasuredHeight()); + } + + @SmallTest + @UiThreadTest + public void testStacked() { + runStackedLayoutTest(ALIGN_START, false); + runStackedLayoutTest(ALIGN_START, true); + runStackedLayoutTest(ALIGN_APART, false); + runStackedLayoutTest(ALIGN_APART, true); + runStackedLayoutTest(ALIGN_END, false); + runStackedLayoutTest(ALIGN_END, true); + } + + /** Runs a test where the controls don't fit on the same line. */ + private void runStackedLayoutTest(int alignment, boolean isRtl) { + InfoBarDualControlLayout layout = new InfoBarDualControlLayout(mContext, null); + layout.setAlignment(alignment); + layout.setStackedMargin(STACKED_MARGIN); + layout.setLayoutDirection(isRtl ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR); + layout.setLayoutParams( + new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)); + + View primary = new Space(mContext); + primary.setMinimumWidth(mTinyControlWidth); + primary.setMinimumHeight(PRIMARY_HEIGHT); + layout.addView(primary); + + View secondary = new Space(mContext); + secondary.setMinimumWidth(INFOBAR_WIDTH); + secondary.setMinimumHeight(SECONDARY_HEIGHT); + layout.addView(secondary); + + // Trigger the measurement & layout algorithms. + int parentWidthSpec = + MeasureSpec.makeMeasureSpec(INFOBAR_WIDTH, MeasureSpec.AT_MOST); + int parentHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); + layout.measure(parentWidthSpec, parentHeightSpec); + layout.layout(0, 0, layout.getMeasuredWidth(), layout.getMeasuredHeight()); + + assertEquals(0, primary.getLeft()); + assertEquals(0, secondary.getLeft()); + + assertEquals(INFOBAR_WIDTH, primary.getRight()); + assertEquals(INFOBAR_WIDTH, secondary.getRight()); + + assertEquals(INFOBAR_WIDTH, primary.getMeasuredWidth()); + assertEquals(INFOBAR_WIDTH, secondary.getMeasuredWidth()); + assertEquals(INFOBAR_WIDTH, layout.getMeasuredWidth()); + + assertEquals(primary.getBottom() + STACKED_MARGIN, secondary.getTop()); + MoreAsserts.assertNotEqual(layout.getMeasuredHeight(), primary.getMeasuredHeight()); + } +}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/InfoBarTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/InfoBarTest.java index 86fc188..d51edffd 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/InfoBarTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/InfoBarTest.java
@@ -80,7 +80,7 @@ loadUrl(TestHttpServerClient.getUrl(POPUP_PAGE)); assertTrue("InfoBar not added", mListener.addInfoBarAnimationFinished()); - List<InfoBar> infoBars = getActivity().getActivityTab().getInfoBarContainer().getInfoBars(); + List<InfoBar> infoBars = getInfoBars(); assertEquals("Wrong infobar count", 1, infoBars.size()); assertTrue(InfoBarUtil.hasPrimaryButton(infoBars.get(0))); assertFalse(InfoBarUtil.hasSecondaryButton(infoBars.get(0))); @@ -105,15 +105,14 @@ assertTrue("InfoBar not added", mListener.addInfoBarAnimationFinished()); // Make sure it has OK/Cancel buttons. - List<InfoBar> infoBars = getActivity().getActivityTab().getInfoBarContainer().getInfoBars(); + List<InfoBar> infoBars = getInfoBars(); assertEquals("Wrong infobar count", 1, infoBars.size()); assertTrue(InfoBarUtil.hasPrimaryButton(infoBars.get(0))); assertTrue(InfoBarUtil.hasSecondaryButton(infoBars.get(0))); loadUrl(HELLO_WORLD_URL); assertTrue("InfoBar not removed.", mListener.removeInfoBarAnimationFinished()); - infoBars = getActivity().getActivityTab().getInfoBarContainer().getInfoBars(); - assertTrue("Wrong infobar count", infoBars.isEmpty()); + assertTrue("Wrong infobar count", getInfoBars().isEmpty()); } @@ -128,8 +127,7 @@ loadUrl(TestHttpServerClient.getUrl(GEOLOCATION_PAGE)); assertTrue("InfoBar not added.", mListener.addInfoBarAnimationFinished()); - List<InfoBar> infoBars = getActivity().getActivityTab().getInfoBarContainer().getInfoBars(); - assertEquals("Wrong infobar count", 1, infoBars.size()); + assertEquals("Wrong infobar count", 1, getInfoBars().size()); // Navigate back and ensure the InfoBar has been removed. getInstrumentation().runOnMainSync( @@ -143,9 +141,7 @@ new Criteria() { @Override public boolean isSatisfied() { - List<InfoBar> infoBars = - getActivity().getActivityTab().getInfoBarContainer().getInfoBars(); - return infoBars.isEmpty(); + return getInfoBars().isEmpty(); } }, MAX_TIMEOUT, CHECK_INTERVAL); @@ -175,7 +171,7 @@ assertTrue("InfoBar not added", mListener.addInfoBarAnimationFinished()); // Make sure it has Kill/Wait buttons. - List<InfoBar> infoBars = getActivity().getActivityTab().getInfoBarContainer().getInfoBars(); + List<InfoBar> infoBars = getInfoBars(); assertEquals("Wrong infobar count", 1, infoBars.size()); assertTrue(InfoBarUtil.hasPrimaryButton(infoBars.get(0))); assertTrue(InfoBarUtil.hasSecondaryButton(infoBars.get(0))); @@ -191,8 +187,7 @@ } }); assertTrue("InfoBar not removed.", mListener.removeInfoBarAnimationFinished()); - infoBars = getActivity().getActivityTab().getInfoBarContainer().getInfoBars(); - assertTrue("Wrong infobar count", infoBars.isEmpty()); + assertTrue("Wrong infobar count", getInfoBars().isEmpty()); } /** @@ -218,8 +213,7 @@ assertTrue("InfoBar not added", mListener.addInfoBarAnimationFinished()); // Make sure it has Kill/Wait buttons. - final List<InfoBar> infoBars = - getActivity().getActivityTab().getInfoBarContainer().getInfoBars(); + final List<InfoBar> infoBars = getInfoBars(); assertEquals("Wrong infobar count", 1, infoBars.size()); assertTrue(InfoBarUtil.hasPrimaryButton(infoBars.get(0))); assertTrue(InfoBarUtil.hasSecondaryButton(infoBars.get(0))); @@ -234,8 +228,7 @@ // The renderer should have been killed and the InfoBar removed. assertTrue("InfoBar not removed.", mListener.removeInfoBarAnimationFinished()); - assertTrue("Wrong infobar count", - getActivity().getActivityTab().getInfoBarContainer().getInfoBars().isEmpty()); + assertTrue("Wrong infobar count", getInfoBars().isEmpty()); CriteriaHelper.pollForCriteria(new Criteria() { @Override public boolean isSatisfied() { @@ -254,8 +247,7 @@ LocationSettingsTestUtil.setSystemLocationSettingEnabled(true); loadUrl(TestHttpServerClient.getUrl(GEOLOCATION_PAGE)); assertTrue("InfoBar not added", mListener.addInfoBarAnimationFinished()); - List<InfoBar> infoBars = getActivity().getActivityTab().getInfoBarContainer().getInfoBars(); - assertEquals("Wrong infobar count", 1, infoBars.size()); + assertEquals("Wrong infobar count", 1, getInfoBars().size()); // Swap out the WebContents and send the user somewhere so that the InfoBar gets removed. InfoBarTestAnimationListener removeListener = new InfoBarTestAnimationListener(); @@ -269,15 +261,13 @@ }); loadUrl(HELLO_WORLD_URL); assertTrue("InfoBar not removed.", removeListener.removeInfoBarAnimationFinished()); - infoBars = getActivity().getActivityTab().getInfoBarContainer().getInfoBars(); - assertEquals("Wrong infobar count", 0, infoBars.size()); + assertEquals("Wrong infobar count", 0, getInfoBars().size()); // Revisiting the original page should make the InfoBar reappear. InfoBarTestAnimationListener addListener = new InfoBarTestAnimationListener(); getActivity().getActivityTab().getInfoBarContainer().setAnimationListener(addListener); loadUrl(TestHttpServerClient.getUrl(GEOLOCATION_PAGE)); assertTrue("InfoBar not added", addListener.addInfoBarAnimationFinished()); - infoBars = getActivity().getActivityTab().getInfoBarContainer().getInfoBars(); - assertEquals("Wrong infobar count", 1, infoBars.size()); + assertEquals("Wrong infobar count", 1, getInfoBars().size()); } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/InfoBarTest2.java b/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/InfoBarTest2.java index 8e3a55c..d9481bc 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/InfoBarTest2.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/InfoBarTest2.java
@@ -24,7 +24,7 @@ import org.chromium.content.browser.test.util.Criteria; import org.chromium.content.browser.test.util.CriteriaHelper; -import java.util.ArrayList; +import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; @@ -97,21 +97,6 @@ getInstrumentation().waitForIdleSync(); } - protected ArrayList<Integer> getInfoBarIdsForCurrentTab() { - final ArrayList<Integer> infoBarIds = new ArrayList<Integer>(); - getInstrumentation().runOnMainSync(new Runnable() { - @Override - public void run() { - Tab tab = getActivity().getActivityTab(); - assertTrue("Failed to find tab.", tab != null); - for (InfoBar infoBar : tab.getInfoBarContainer().getInfoBars()) { - infoBarIds.add(infoBar.getId()); - } - } - }); - return infoBarIds; - } - /** * Verifies that infobars added from Java expire or not as expected. */ @@ -131,16 +116,15 @@ addInfoBarToCurrentTab(expiringInfoBar); // Verify it's really there. - ArrayList<Integer> infoBarIds = getInfoBarIdsForCurrentTab(); - assertEquals(1, infoBarIds.size()); - assertEquals(expiringInfoBar.getId(), infoBarIds.get(0).intValue()); + List<InfoBar> infoBars = getInfoBars(); + assertEquals(1, infoBars.size()); + assertSame(expiringInfoBar, infoBars.get(0)); // Now navigate, it should expire. loadUrl(TestHttpServerClient.getUrl("chrome/test/data/android/google.html")); assertTrue("InfoBar not removed.", mListener.removeInfoBarAnimationFinished()); assertTrue("InfoBar did not expire on navigation.", dismissed.mValue); - infoBarIds = getInfoBarIdsForCurrentTab(); - assertTrue(infoBarIds.isEmpty()); + assertTrue(getInfoBars().isEmpty()); // Now test a non-expiring infobar. MessageInfoBar persistentInfoBar = new MessageInfoBar("Hello!"); @@ -157,9 +141,9 @@ // Navigate, it should still be there. loadUrl(TestHttpServerClient.getUrl("chrome/test/data/android/google.html")); assertFalse("InfoBar did expire on navigation.", dismissed.mValue); - infoBarIds = getInfoBarIdsForCurrentTab(); - assertEquals(1, infoBarIds.size()); - assertEquals(persistentInfoBar.getId(), infoBarIds.get(0).intValue()); + infoBars = getInfoBars(); + assertEquals(1, infoBars.size()); + assertSame(persistentInfoBar, infoBars.get(0)); // Close the infobar. dismissInfoBar(persistentInfoBar); @@ -214,7 +198,7 @@ final InfoBar infoBar = new MessageInfoBar("Hello"); addInfoBarToCurrentTab(infoBar); removeInfoBarFromCurrentTab(infoBar); - assertTrue(getInfoBarIdsForCurrentTab().isEmpty()); + assertTrue(getInfoBars().isEmpty()); } /** @@ -227,7 +211,7 @@ final InfoBar infoBar = new MessageInfoBar("Hello"); addInfoBarToCurrentTab(infoBar); dismissInfoBar(infoBar); - assertTrue(getInfoBarIdsForCurrentTab().isEmpty()); + assertTrue(getInfoBars().isEmpty()); } /** @@ -255,9 +239,9 @@ // But no infobar removed event as the 2nd infobar was removed before it got added. assertFalse("InfoBar not removed.", mListener.removeInfoBarAnimationFinished()); - ArrayList<Integer> infoBarIds = getInfoBarIdsForCurrentTab(); - assertEquals(1, infoBarIds.size()); - assertEquals(infoBar1.getId(), infoBarIds.get(0).intValue()); + List<InfoBar> infoBars = getInfoBars(); + assertEquals(1, infoBars.size()); + assertSame(infoBar1, infoBars.get(0)); } /** @@ -285,9 +269,9 @@ // But no infobar removed event as the 2nd infobar was removed before it got added. assertFalse("InfoBar not removed.", mListener.removeInfoBarAnimationFinished()); - ArrayList<Integer> infoBarIds = getInfoBarIdsForCurrentTab(); - assertEquals(1, infoBarIds.size()); - assertEquals(infoBar1.getId(), infoBarIds.get(0).intValue()); + List<InfoBar> infoBars = getInfoBars(); + assertEquals(1, infoBars.size()); + assertSame(infoBar1, infoBars.get(0)); } /**
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/PermissionUpdateInfobarTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/PermissionUpdateInfobarTest.java index dbc5484d..feafde1 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/PermissionUpdateInfobarTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/PermissionUpdateInfobarTest.java
@@ -94,15 +94,7 @@ loadUrl(TestHttpServerClient.getUrl(GEOLOCATION_PAGE)); assertTrue("InfoBar not added", mListener.addInfoBarAnimationFinished()); - - InfoBar infoBar = ThreadUtils.runOnUiThreadBlockingNoException(new Callable<InfoBar>() { - @Override - public InfoBar call() throws Exception { - return getActivity().getActivityTab().getInfoBarContainer() - .getInfoBars().get(0); - } - }); - assertNotNull(infoBar); + assertEquals(1, getInfoBars().size()); final WebContents webContents = ThreadUtils.runOnUiThreadBlockingNoException( new Callable<WebContents>() {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/media/remote/CastNotificationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/media/remote/CastNotificationTest.java index 6d2210d..c4284fe 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/media/remote/CastNotificationTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/media/remote/CastNotificationTest.java
@@ -50,7 +50,7 @@ // The new position is sent in a separate message, so we have to wait a bit before // fetching it. Thread.sleep(STABILIZE_TIME_MS); - int position = getRemotePositionMs(); + long position = getRemotePositionMs(); // Position should not change while paused Thread.sleep(PAUSE_TEST_TIME_MS); assertEquals("Pause didn't stop playback", position, getRemotePositionMs());
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/media/remote/CastPositionTransferTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/media/remote/CastPositionTransferTest.java index ff44b17..64eeceb1 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/media/remote/CastPositionTransferTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/media/remote/CastPositionTransferTest.java
@@ -99,10 +99,10 @@ castVideoAndWaitUntilPlaying(CAST_TEST_ROUTE, tab, videoRect); tapPlayPauseButton(tab, videoRect); - int pausePosition = getRemotePositionMs(); + long pausePosition = getRemotePositionMs(); for (int time = 0; time < MAX_VIEW_TIME_MS; time += VIEW_RETRY_MS) { Thread.sleep(VIEW_RETRY_MS); - int newPosition = getRemotePositionMs(); + long newPosition = getRemotePositionMs(); if (newPosition == pausePosition) { break; } @@ -114,7 +114,7 @@ && getRemotePositionMs() != pausePosition; time += VIEW_RETRY_MS) { Thread.sleep(VIEW_RETRY_MS); } - int remotePositionMs = getRemotePositionMs(); + long remotePositionMs = getRemotePositionMs(); assertEquals("The remote player did not seek", CAST_START_TIME_MS, remotePositionMs, SEEK_EPSILON_MS);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/media/remote/CastReconnectTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/media/remote/CastReconnectTest.java index e3de4fe2..021e93f5 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/media/remote/CastReconnectTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/media/remote/CastReconnectTest.java
@@ -28,8 +28,7 @@ * from running them automatically outside the wrapper. */ public class CastReconnectTest extends CastTestBase { - - private int mVideoDurationMs; + private long mVideoDurationMs; /** * Cast and pause a video. This doesn't test anything itself, but just sets up the state for
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/media/remote/CastTestBase.java b/chrome/android/javatests/src/org/chromium/chrome/browser/media/remote/CastTestBase.java index 6f45e86..22663f6 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/media/remote/CastTestBase.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/media/remote/CastTestBase.java
@@ -66,12 +66,10 @@ } @Override - public void onDurationUpdated(int durationMillis) { - } + public void onDurationUpdated(long durationMillis) {} @Override - public void onPositionChanged(int positionMillis) { - } + public void onPositionChanged(long positionMillis) {} @Override public void onTitleChanged(String title) { @@ -362,7 +360,7 @@ }); } - protected void sleepNoThrow(int timeout) { + protected void sleepNoThrow(long timeout) { try { Thread.sleep(timeout); } catch (InterruptedException e) { @@ -463,11 +461,11 @@ return false; } - protected int getRemotePositionMs() { + protected long getRemotePositionMs() { return getMediaRouteController().getPosition(); } - protected int getRemoteDurationMs() { + protected long getRemoteDurationMs() { return getMediaRouteController().getDuration(); }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/media/remote/CastVideoControlsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/media/remote/CastVideoControlsTest.java index 3ea1a7d3..0c41d70 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/media/remote/CastVideoControlsTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/media/remote/CastVideoControlsTest.java
@@ -32,11 +32,11 @@ tapPlayPauseButton(tab, videoRect); // The new position is sent in a separate message, so we have to wait a bit before // fetching it. - int position = getRemotePositionMs(); + long position = getRemotePositionMs(); boolean paused = false; for (int time = 0; time < MAX_VIEW_TIME_MS; time += VIEW_RETRY_MS) { Thread.sleep(VIEW_RETRY_MS); - int newPosition = getRemotePositionMs(); + long newPosition = getRemotePositionMs(); if (newPosition == position) { paused = true; break;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/CustomNotificationBuilderTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/CustomNotificationBuilderTest.java index 25f5254..0c13bd1 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/CustomNotificationBuilderTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/CustomNotificationBuilderTest.java
@@ -4,6 +4,7 @@ package org.chromium.chrome.browser.notifications; +import android.annotation.SuppressLint; import android.app.Notification; import android.app.PendingIntent; import android.content.Context; @@ -28,6 +29,7 @@ /** * Instrumentation unit tests for CustomNotificationBuilder. */ +@SuppressLint("NewApi") // For the |extras| property of Notification. @SuppressWarnings("deprecation") // For the |icon| and |largeIcon| properties of Notification. public class CustomNotificationBuilderTest extends InstrumentationTestCase { @SmallTest @@ -63,9 +65,13 @@ assertEquals(R.drawable.ic_chrome, notification.icon); assertNotNull(((ImageView) compactView.findViewById(R.id.icon)).getDrawable()); assertNotNull(((ImageView) bigView.findViewById(R.id.icon)).getDrawable()); + assertNotNull(notification.largeIcon); assertEquals("title", getIdenticalText(R.id.title, compactView, bigView)); + assertEquals("title", notification.extras.getString(Notification.EXTRA_TITLE)); assertEquals("body", getIdenticalText(R.id.body, compactView, bigView)); + assertEquals("body", notification.extras.getString(Notification.EXTRA_TEXT)); assertEquals("origin", getIdenticalText(R.id.origin, compactView, bigView)); + assertEquals("origin", notification.extras.getString(Notification.EXTRA_SUB_TEXT)); assertEquals("ticker", notification.tickerText.toString()); assertEquals(Notification.DEFAULT_ALL, notification.defaults); assertEquals(1, notification.vibrate.length); @@ -73,6 +79,7 @@ assertSame(contentIntent, notification.contentIntent); assertSame(deleteIntent, notification.deleteIntent); + assertEquals(2, notification.actions.length); ArrayList<View> buttons = new ArrayList<>(); bigView.findViewsWithText(buttons, "button", View.FIND_VIEWS_WITH_TEXT); assertEquals(2, buttons.size());
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/physicalweb/MockPwsClient.java b/chrome/android/javatests/src/org/chromium/chrome/browser/physicalweb/MockPwsClient.java new file mode 100644 index 0000000..578e25b7 --- /dev/null +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/physicalweb/MockPwsClient.java
@@ -0,0 +1,71 @@ +// 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.physicalweb; + +import android.graphics.Bitmap; + +import org.chromium.chrome.browser.physicalweb.PwsClient.FetchIconCallback; +import org.chromium.chrome.browser.physicalweb.PwsClient.ResolveScanCallback; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + * This class sends requests to the Physical Web Service. + */ +class MockPwsClient implements PwsClient { + private List<Collection<String>> mResolveCalls; + private List<String> mFetchIconCalls; + private List<List<PwsResult>> mPwsResults; + private List<Bitmap> mIconBitmaps; + + public MockPwsClient() { + mResolveCalls = new ArrayList<>(); + mFetchIconCalls = new ArrayList<>(); + mPwsResults = new ArrayList<>(); + mIconBitmaps = new ArrayList<>(); + } + + public List<Collection<String>> getResolveCalls() { + return mResolveCalls; + } + + public List<String> getFetchIconCalls() { + return mFetchIconCalls; + } + + public void addPwsResults(List<PwsResult> pwsResults) { + mPwsResults.add(pwsResults); + } + + public void addIconBitmap(Bitmap iconBitmap) { + mIconBitmaps.add(iconBitmap); + } + + /** + * Send an HTTP request to the PWS to resolve a set of URLs. + * @param broadcastUrls The URLs to resolve. + * @param resolveScanCallback The callback to be run when the response is received. + */ + @Override + public void resolve(final Collection<String> broadcastUrls, + final ResolveScanCallback resolveScanCallback) { + mResolveCalls.add(broadcastUrls); + resolveScanCallback.onPwsResults(mPwsResults.remove(0)); + } + + /** + * Send an HTTP request to fetch a favicon. + * @param iconUrl The URL of the favicon. + * @param fetchIconCallback The callback to be run when the icon is received. + */ + @Override + public void fetchIcon(final String iconUrl, + final FetchIconCallback fetchIconCallback) { + mFetchIconCalls.add(iconUrl); + fetchIconCallback.onIconReceived(iconUrl, mIconBitmaps.remove(0)); + } +}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/physicalweb/UrlManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/physicalweb/UrlManagerTest.java new file mode 100644 index 0000000..f3b5a2c --- /dev/null +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/physicalweb/UrlManagerTest.java
@@ -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. + +package org.chromium.chrome.browser.physicalweb; + +import android.content.Context; +import android.content.SharedPreferences; +import android.preference.PreferenceManager; +import android.test.InstrumentationTestCase; +import android.test.suitebuilder.annotation.SmallTest; + +import org.chromium.chrome.test.util.browser.notifications.MockNotificationManagerProxy; +import org.chromium.chrome.test.util.browser.notifications.MockNotificationManagerProxy.NotificationEntry; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Set; + +/** + * Tests for the UrlManager class. + */ +public class UrlManagerTest extends InstrumentationTestCase { + static final String URL1 = "https://example.com/"; + static final String TITLE1 = "Example"; + static final String DESC1 = "Example Website"; + static final String PREF_PHYSICAL_WEB = "physical_web"; + static final int PHYSICAL_WEB_OFF = 0; + static final int PHYSICAL_WEB_ON = 1; + static final int PHYSICAL_WEB_ONBOARDING = 2; + UrlManager mUrlManager = null; + MockPwsClient mMockPwsClient = null; + MockNotificationManagerProxy mMockNotificationManagerProxy = null; + SharedPreferences mSharedPreferences = null; + + @Override + protected void setUp() throws Exception { + super.setUp(); + Context context = getInstrumentation().getTargetContext().getApplicationContext(); + mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(context); + mSharedPreferences.edit().putInt(PREF_PHYSICAL_WEB, PHYSICAL_WEB_ON).apply(); + mUrlManager = new UrlManager(context); + mMockPwsClient = new MockPwsClient(); + mUrlManager.overridePwsClientForTesting(mMockPwsClient); + mMockNotificationManagerProxy = new MockNotificationManagerProxy(); + mUrlManager.overrideNotificationManagerForTesting(mMockNotificationManagerProxy); + } + + private void setOnboarding() { + mSharedPreferences.edit().putInt(PREF_PHYSICAL_WEB, PHYSICAL_WEB_ONBOARDING).apply(); + } + + @SmallTest + public void testAddUrlWhileOnboardingMakesNotification() throws Exception { + setOnboarding(); + ArrayList<PwsResult> results = new ArrayList<>(); + results.add(new PwsResult(URL1, URL1, null, TITLE1, DESC1)); + mMockPwsClient.addPwsResults(results); + mUrlManager.addUrl(URL1); + + // Make sure that a resolution was *not* attempted. + List<Collection<String>> resolveCalls = mMockPwsClient.getResolveCalls(); + assertEquals(0, resolveCalls.size()); + + // Make sure that we have no resolved URLs. + Set<String> urls = mUrlManager.getUrls(); + assertEquals(0, urls.size()); + + // Make sure that a notification was shown. + List<NotificationEntry> notifications = mMockNotificationManagerProxy.getNotifications(); + assertEquals(1, notifications.size()); + } + + @SmallTest + public void testAddUrlNoResolutionDoesNothing() throws Exception { + mMockPwsClient.addPwsResults(new ArrayList<PwsResult>()); + mUrlManager.addUrl(URL1); + + // Make sure that a resolution was attempted. + List<Collection<String>> resolveCalls = mMockPwsClient.getResolveCalls(); + assertEquals(1, resolveCalls.size()); + + // Make sure that we have no resolved URLs. + Set<String> urls = mUrlManager.getUrls(); + assertEquals(0, urls.size()); + // Make sure that we do have unresolved URLs. + urls = mUrlManager.getUrls(true); + assertEquals(1, urls.size()); + + // Make sure that a notification was not shown. + List<NotificationEntry> notifications = mMockNotificationManagerProxy.getNotifications(); + assertEquals(0, notifications.size()); + } + + @SmallTest + public void testAddUrlWithResolutionMakesNotification() throws Exception { + ArrayList<PwsResult> results = new ArrayList<>(); + results.add(new PwsResult(URL1, URL1, null, TITLE1, DESC1)); + mMockPwsClient.addPwsResults(results); + mUrlManager.addUrl(URL1); + + // Make sure that a resolution was attempted. + List<Collection<String>> resolveCalls = mMockPwsClient.getResolveCalls(); + assertEquals(1, resolveCalls.size()); + + // Make sure that we have our resolved URLs. + Set<String> urls = mUrlManager.getUrls(); + assertEquals(1, urls.size()); + + // Make sure that a notification was shown. + List<NotificationEntry> notifications = mMockNotificationManagerProxy.getNotifications(); + assertEquals(1, notifications.size()); + } +}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/OAuth2TokenServiceIntegrationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/OAuth2TokenServiceIntegrationTest.java index 76b0e92..b7a5a6c 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/OAuth2TokenServiceIntegrationTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/OAuth2TokenServiceIntegrationTest.java
@@ -5,7 +5,6 @@ package org.chromium.chrome.browser.signin; import android.accounts.Account; -import android.app.Activity; import android.content.Context; import android.test.UiThreadTest; import android.test.suitebuilder.annotation.MediumTest; @@ -95,7 +94,7 @@ } @Override - public boolean canBeUsed(Context ctx, Activity activity) { + public boolean canBeUsed(Context ctx) { return true; } });
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/superviseduser/SupervisedUserContentProviderTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/superviseduser/SupervisedUserContentProviderTest.java new file mode 100644 index 0000000..432f48f --- /dev/null +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/superviseduser/SupervisedUserContentProviderTest.java
@@ -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. + +package org.chromium.chrome.browser.superviseduser; + +import android.accounts.Account; +import android.content.ContentProviderClient; +import android.content.ContentResolver; +import android.database.Cursor; +import android.net.Uri; +import android.os.RemoteException; +import android.test.suitebuilder.annotation.SmallTest; + +import org.chromium.base.ThreadUtils; +import org.chromium.chrome.browser.ChromeActivity; +import org.chromium.chrome.browser.childaccounts.ChildAccountService; +import org.chromium.chrome.browser.preferences.PrefServiceBridge; +import org.chromium.chrome.test.ChromeActivityTestCaseBase; +import org.chromium.chrome.test.util.browser.signin.SigninTestUtil; +import org.chromium.components.webrestriction.WebRestrictionsContentProvider; + +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; + +/** + * Instrumentation test for SupervisedUserContentProvider. + */ +public class SupervisedUserContentProviderTest extends ChromeActivityTestCaseBase<ChromeActivity> { + private static final String DEFAULT_ACCOUNT = "test@gmail.com"; + private static final String AUTHORITY_SUFFIX = ".SupervisedUserProvider"; + private ContentResolver mResolver; + private String mAuthority; + private Uri mUri; + + public SupervisedUserContentProviderTest() { + super(ChromeActivity.class); + } + + @Override + public void setUp() throws Exception { + super.setUp(); + mResolver = getInstrumentation().getContext().getContentResolver(); + assertNotNull(mResolver); + mAuthority = getInstrumentation().getTargetContext().getPackageName() + AUTHORITY_SUFFIX; + mUri = new Uri.Builder() + .scheme(ContentResolver.SCHEME_CONTENT) + .authority(mAuthority) + .path("authorized") + .build(); + SigninTestUtil.get().resetSigninState(); + } + + @Override + public void tearDown() throws Exception { + SigninTestUtil.get().resetSigninState(); + super.tearDown(); + } + + @Override + public void startMainActivity() throws InterruptedException { + SigninTestUtil.setUpAuthForTest(getInstrumentation()); + + // In principle the SupervisedUserContentProvider should work whenever Chrome is installed + // (even if it isn't running), but to test it we need to set up a dummy child, and to do + // this within a test we need to start Chrome. + startMainActivityOnBlankPage(); + } + + @SmallTest + public void testNoSupervisedUser() throws RemoteException, ExecutionException { + assertFalse(ThreadUtils.runOnUiThreadBlocking(new Callable<Boolean>() { + + @Override + public Boolean call() throws Exception { + PrefServiceBridge.getInstance().setSupervisedUserId(""); + return ChildAccountService.isChildAccount(); + } + + })); + ContentProviderClient client = mResolver.acquireContentProviderClient(mAuthority); + assertNotNull(client); + Cursor cursor = client.query(mUri, null, "url = 'http://google.com'", null, null); + assertNotNull(cursor); + assertEquals(WebRestrictionsContentProvider.PROCEED, cursor.getInt(0)); + cursor = client.query(mUri, null, "url = 'http://www.notgoogle.com'", null, null); + assertNotNull(cursor); + assertEquals(WebRestrictionsContentProvider.PROCEED, cursor.getInt(0)); + } + + @SmallTest + public void testWithSupervisedUser() throws RemoteException, ExecutionException { + final Account account = SigninTestUtil.get().addAndSignInTestAccount(); + assertNotNull(account); + assertTrue(ThreadUtils.runOnUiThreadBlocking(new Callable<Boolean>() { + + @Override + public Boolean call() throws Exception { + PrefServiceBridge.getInstance().setSupervisedUserId("ChildAccountSUID"); + return ChildAccountService.isChildAccount(); + } + + })); + ContentProviderClient client = mResolver.acquireContentProviderClient(mAuthority); + assertNotNull(client); + // setFilter for testing sets a default filter that blocks by default. + mResolver.call(mUri, "setFilterForTesting", null, null); + Cursor cursor = client.query(mUri, null, "url = 'http://www.google.com'", null, null); + assertNotNull(cursor); + assertEquals(WebRestrictionsContentProvider.BLOCKED, cursor.getInt(0)); + } +}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/translate/TranslateInfoBarTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/translate/TranslateInfoBarTest.java index b0b7aa1..7e68c435 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/translate/TranslateInfoBarTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/translate/TranslateInfoBarTest.java
@@ -59,7 +59,7 @@ public void testTranslateLanguagePanel() throws InterruptedException { loadUrl(TestHttpServerClient.getUrl(TRANSLATE_PAGE)); assertTrue("InfoBar not opened.", mListener.addInfoBarAnimationFinished()); - InfoBar infoBar = mInfoBarContainer.getInfoBars().get(0); + InfoBar infoBar = mInfoBarContainer.getInfoBarsForTesting().get(0); assertTrue(InfoBarUtil.hasPrimaryButton(infoBar)); assertTrue(InfoBarUtil.hasSecondaryButton(infoBar)); TranslateUtil.openLanguagePanel(this, infoBar); @@ -76,7 +76,7 @@ public void testTranslateNeverPanel() throws InterruptedException { loadUrl(TestHttpServerClient.getUrl(TRANSLATE_PAGE)); assertTrue("InfoBar not opened.", mListener.addInfoBarAnimationFinished()); - InfoBar infoBar = mInfoBarContainer.getInfoBars().get(0); + InfoBar infoBar = mInfoBarContainer.getInfoBarsForTesting().get(0); assertTrue(InfoBarUtil.clickCloseButton(infoBar)); assertTrue(mListener.removeInfoBarAnimationFinished()); @@ -84,7 +84,7 @@ // Reload the page so the infobar shows again loadUrl(TestHttpServerClient.getUrl(TRANSLATE_PAGE)); assertTrue("InfoBar not opened", mListener.addInfoBarAnimationFinished()); - infoBar = mInfoBarContainer.getInfoBars().get(0); + infoBar = mInfoBarContainer.getInfoBarsForTesting().get(0); assertTrue(InfoBarUtil.clickCloseButton(infoBar)); assertTrue("InfoBar not swapped", mListener.swapInfoBarAnimationFinished());
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappActivityTestBase.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappActivityTestBase.java index 39f0a40..575eae2 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappActivityTestBase.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappActivityTestBase.java
@@ -6,6 +6,7 @@ import android.content.Intent; import android.net.Uri; +import android.view.ViewGroup; import org.chromium.base.ThreadUtils; import org.chromium.chrome.browser.ShortcutHelper; @@ -194,4 +195,23 @@ } }); } + + protected ViewGroup waitUntilSplashScreenAppears() { + try { + CriteriaHelper.pollForCriteria(new Criteria() { + @Override + public boolean isSatisfied() { + return getActivity().getSplashScreenForTests() != null; + } + }); + } catch (InterruptedException e) { + fail(); + } + + ViewGroup splashScreen = getActivity().getSplashScreenForTests(); + if (splashScreen == null) { + fail("No splash screen available."); + } + return splashScreen; + } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappSplashScreenBackgroundColorTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappSplashScreenBackgroundColorTest.java index 2499491..19186d0c 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappSplashScreenBackgroundColorTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappSplashScreenBackgroundColorTest.java
@@ -32,7 +32,7 @@ public void testShowBackgroundColorAndRecordUma() throws Exception { startWebappActivity(); - ViewGroup splashScreen = getActivity().getSplashScreenForTests(); + ViewGroup splashScreen = waitUntilSplashScreenAppears(); ColorDrawable background = (ColorDrawable) splashScreen.getBackground(); assertEquals(Color.GREEN, background.getColor());
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappSplashScreenHomescreenIconTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappSplashScreenHomescreenIconTest.java index 3e638cf..62a3c85 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappSplashScreenHomescreenIconTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappSplashScreenHomescreenIconTest.java
@@ -37,7 +37,7 @@ @SmallTest @Feature({"Webapps"}) public void testShowFallbackIcon() { - ViewGroup splashScreen = getActivity().getSplashScreenForTests(); + ViewGroup splashScreen = waitUntilSplashScreenAppears(); ImageView splashImage = (ImageView) splashScreen.findViewById( R.id.webapp_splash_screen_icon); BitmapDrawable drawable = (BitmapDrawable) splashImage.getDrawable();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappSplashScreenIconTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappSplashScreenIconTest.java index 4624f86e2..b73691d 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappSplashScreenIconTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappSplashScreenIconTest.java
@@ -41,7 +41,7 @@ @SmallTest @Feature({"Webapps"}) public void testShowSplashIcon() { - ViewGroup splashScreen = getActivity().getSplashScreenForTests(); + ViewGroup splashScreen = waitUntilSplashScreenAppears(); ImageView splashImage = (ImageView) splashScreen.findViewById( R.id.webapp_splash_screen_icon); BitmapDrawable drawable = (BitmapDrawable) splashImage.getDrawable();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappSplashScreenTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappSplashScreenTest.java index aff1ce04..39c084b1 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappSplashScreenTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappSplashScreenTest.java
@@ -55,7 +55,7 @@ @Feature({"Webapps"}) public void testDefaultBackgroundColor() throws Exception { startWebappActivity(); - ViewGroup splashScreen = getActivity().getSplashScreenForTests(); + ViewGroup splashScreen = waitUntilSplashScreenAppears(); ColorDrawable background = (ColorDrawable) splashScreen.getBackground(); assertEquals(ApiCompatibilityUtils.getColor(getActivity().getResources(), @@ -230,8 +230,8 @@ WebappDataStorage.open(context, WEBAPP_ID).updateSplashScreenImage(splashBitmap); startWebappActivity(createIntent()); + ViewGroup splashScreen = waitUntilSplashScreenAppears(); assertTrue(getActivity().isSplashScreenVisibleForTests()); - ViewGroup splashScreen = getActivity().getSplashScreenForTests(); ImageView splashImage = (ImageView) splashScreen.findViewById(R.id.webapp_splash_screen_icon); @@ -257,8 +257,8 @@ WebappDataStorage.open(context, WEBAPP_ID).updateSplashScreenImage(splashBitmap); startWebappActivity(createIntent()); + ViewGroup splashScreen = waitUntilSplashScreenAppears(); assertTrue(getActivity().isSplashScreenVisibleForTests()); - ViewGroup splashScreen = getActivity().getSplashScreenForTests(); // The icon is centered within a fixed-size area on the splash screen. ImageView splashImage = @@ -286,8 +286,8 @@ Intent intent = createIntent(); intent.putExtra(ShortcutHelper.EXTRA_IS_ICON_GENERATED, true); startWebappActivity(intent); + ViewGroup splashScreen = waitUntilSplashScreenAppears(); assertTrue(getActivity().isSplashScreenVisibleForTests()); - ViewGroup splashScreen = getActivity().getSplashScreenForTests(); // There's no icon displayed. ImageView splashImage = @@ -311,8 +311,8 @@ // Don't register anything for the web app, which represents apps that were added to the // home screen before splash screen images were downloaded. startWebappActivity(createIntent()); + ViewGroup splashScreen = waitUntilSplashScreenAppears(); assertTrue(getActivity().isSplashScreenVisibleForTests()); - ViewGroup splashScreen = getActivity().getSplashScreenForTests(); // There's no icon displayed. ImageView splashImage =
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/media/remote/AbstractMediaRouteControllerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/media/remote/AbstractMediaRouteControllerTest.java index d8809d2a..2f327bf 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/media/remote/AbstractMediaRouteControllerTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/media/remote/AbstractMediaRouteControllerTest.java
@@ -100,13 +100,13 @@ mediaRouteCtrl.setPlayerStateForMediaItemState(MediaItemStatus.PLAYBACK_STATE_INVALIDATED); assertFalse(mediaRouteCtrl.isPlaying()); - doReturn(0).when(mediaRouteCtrl).getPosition(); - doReturn(5000).when(mediaRouteCtrl).getDuration(); + doReturn(0L).when(mediaRouteCtrl).getPosition(); + doReturn(5000L).when(mediaRouteCtrl).getDuration(); mediaRouteCtrl.setPlayerStateForMediaItemState(MediaItemStatus.PLAYBACK_STATE_PAUSED); assertFalse(mediaRouteCtrl.isPlaying()); - doReturn(5000).when(mediaRouteCtrl).getPosition(); - doReturn(5000).when(mediaRouteCtrl).getDuration(); + doReturn(5000L).when(mediaRouteCtrl).getPosition(); + doReturn(5000L).when(mediaRouteCtrl).getDuration(); mediaRouteCtrl.setPlayerStateForMediaItemState(MediaItemStatus.PLAYBACK_STATE_PAUSED); assertFalse(mediaRouteCtrl.isPlaying()); @@ -146,13 +146,13 @@ mediaRouteCtrl.setPlayerStateForMediaItemState(MediaItemStatus.PLAYBACK_STATE_INVALIDATED); assertFalse(mediaRouteCtrl.isBeingCast()); - doReturn(0).when(mediaRouteCtrl).getPosition(); - doReturn(5000).when(mediaRouteCtrl).getDuration(); + doReturn(0L).when(mediaRouteCtrl).getPosition(); + doReturn(5000L).when(mediaRouteCtrl).getDuration(); mediaRouteCtrl.setPlayerStateForMediaItemState(MediaItemStatus.PLAYBACK_STATE_PAUSED); assertTrue(mediaRouteCtrl.isBeingCast()); - doReturn(5000).when(mediaRouteCtrl).getPosition(); - doReturn(5000).when(mediaRouteCtrl).getDuration(); + doReturn(5000L).when(mediaRouteCtrl).getPosition(); + doReturn(5000L).when(mediaRouteCtrl).getDuration(); mediaRouteCtrl.setPlayerStateForMediaItemState(MediaItemStatus.PLAYBACK_STATE_PAUSED); assertFalse(mediaRouteCtrl.isBeingCast()); @@ -449,17 +449,17 @@ } @Override - public int getPosition() { + public long getPosition() { throw new UnsupportedOperationException(); } @Override - public int getDuration() { + public long getDuration() { throw new UnsupportedOperationException(); } @Override - public void seekTo(int msec) { + public void seekTo(long msec) { throw new UnsupportedOperationException(); }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/superviseduser/SupervisedUserContentProviderUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/superviseduser/SupervisedUserContentProviderUnitTest.java new file mode 100644 index 0000000..650b97f --- /dev/null +++ b/chrome/android/junit/src/org/chromium/chrome/browser/superviseduser/SupervisedUserContentProviderUnitTest.java
@@ -0,0 +1,132 @@ +// 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.superviseduser; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyLong; +import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import android.util.Pair; + +import org.chromium.testing.local.LocalRobolectricTestRunner; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; +import org.robolectric.annotation.Config; + +/** + * Tests of SupervisedUserContentProvider. This is tested as a simple class, not as a content + * provider. The content provider aspects are tested with WebRestrictionsContentProviderTest. + */ +@RunWith(LocalRobolectricTestRunner.class) +@Config(manifest = Config.NONE) +public class SupervisedUserContentProviderUnitTest { + + private SupervisedUserContentProvider mSupervisedUserContentProvider; + + @Before + public void setUp() { + mSupervisedUserContentProvider = Mockito.spy(new SupervisedUserContentProvider()); + mSupervisedUserContentProvider.setNativeSupervisedUserContentProviderForTesting(1234L); + } + + @Test + public void testShouldProceed() throws InterruptedException { + // Mock the native call for a permitted URL + doAnswer(new Answer<Void>() { + + @Override + public Void answer(InvocationOnMock invocation) throws Throwable { + Object args[] = invocation.getArguments(); + ((SupervisedUserContentProvider.SupervisedUserQueryReply) args[1]) + .onQueryComplete(true, null); + return null; + } + + }) + .when(mSupervisedUserContentProvider) + .nativeShouldProceed(anyLong(), + any(SupervisedUserContentProvider.SupervisedUserQueryReply.class), + anyString()); + assertThat(mSupervisedUserContentProvider.shouldProceed("url"), + is(new Pair<Boolean, String>(true, null))); + verify(mSupervisedUserContentProvider) + .nativeShouldProceed(eq(1234L), + any(SupervisedUserContentProvider.SupervisedUserQueryReply.class), + eq("url")); + // Mock the native call for a forbidden URL + doAnswer(new Answer<Void>() { + + @Override + public Void answer(InvocationOnMock invocation) throws Throwable { + Object args[] = invocation.getArguments(); + ((SupervisedUserContentProvider.SupervisedUserQueryReply) args[1]) + .onQueryComplete(false, "Hello"); + return null; + } + + }) + .when(mSupervisedUserContentProvider) + .nativeShouldProceed(anyLong(), + any(SupervisedUserContentProvider.SupervisedUserQueryReply.class), + anyString()); + assertThat(mSupervisedUserContentProvider.shouldProceed("url"), + is(new Pair<Boolean, String>(false, "Hello"))); + } + + @Test + public void testRequestInsert() throws InterruptedException { + // Mock native call. + doAnswer(new Answer<Void>() { + + @Override + public Void answer(InvocationOnMock invocation) throws Throwable { + Object args[] = invocation.getArguments(); + ((SupervisedUserContentProvider.SupervisedUserInsertReply) args[1]) + .onInsertRequestSendComplete(true); + return null; + } + + }) + .when(mSupervisedUserContentProvider) + .nativeRequestInsert(anyLong(), + any(SupervisedUserContentProvider.SupervisedUserInsertReply.class), + anyString()); + assertThat(mSupervisedUserContentProvider.requestInsert("url"), is(true)); + verify(mSupervisedUserContentProvider) + .nativeRequestInsert(eq(1234L), + any(SupervisedUserContentProvider.SupervisedUserInsertReply.class), + eq("url")); + doAnswer(new Answer<Void>() { + + @Override + public Void answer(InvocationOnMock invocation) throws Throwable { + Object args[] = invocation.getArguments(); + ((SupervisedUserContentProvider.SupervisedUserInsertReply) args[1]) + .onInsertRequestSendComplete(false); + return null; + } + + }) + .when(mSupervisedUserContentProvider) + .nativeRequestInsert(anyLong(), + any(SupervisedUserContentProvider.SupervisedUserInsertReply.class), + anyString()); + assertThat(mSupervisedUserContentProvider.requestInsert("url"), is(false)); + verify(mSupervisedUserContentProvider, times(2)) + .nativeRequestInsert(eq(1234L), + any(SupervisedUserContentProvider.SupervisedUserInsertReply.class), + eq("url")); + } +}
diff --git a/chrome/app/BUILD.gn b/chrome/app/BUILD.gn index f1ad048..7ca43b02 100644 --- a/chrome/app/BUILD.gn +++ b/chrome/app/BUILD.gn
@@ -317,8 +317,6 @@ sources = [ "chrome_main_delegate.cc", "chrome_main_delegate.h", - "close_handle_hook_win.cc", - "close_handle_hook_win.h", ] deps = [
diff --git a/chrome/app/chrome_command_ids.h b/chrome/app/chrome_command_ids.h index 9ad012c..1e27ba86 100644 --- a/chrome/app/chrome_command_ids.h +++ b/chrome/app/chrome_command_ids.h
@@ -201,11 +201,10 @@ #define IDC_SHOW_SETTINGS_CHANGE_FIRST 40033 #define IDC_SHOW_SETTINGS_CHANGE_LAST 40133 #define IDC_SHOW_AVATAR_MENU 40134 -#define IDC_EXTENSION_DISABLED_FIRST 40135 -#define IDC_EXTENSION_DISABLED_LAST 40235 +#define IDC_EXTENSION_INSTALL_ERROR_FIRST 40135 +#define IDC_EXTENSION_INSTALL_ERROR_LAST 40235 #define IDC_TOGGLE_REQUEST_TABLET_SITE 40236 #define IDC_DEV_TOOLS_TOGGLE 40237 -#define IDC_EXTERNAL_EXTENSION_ALERT 40238 #define IDC_RECENT_TABS_MENU 40239 #define IDC_RECENT_TABS_NO_DEVICE_TABS 40240 #define IDC_SHOW_SETTINGS_RESET_BUBBLE 40241
diff --git a/chrome/app/chrome_main_delegate.cc b/chrome/app/chrome_main_delegate.cc index 9cb2262..9f29057 100644 --- a/chrome/app/chrome_main_delegate.cc +++ b/chrome/app/chrome_main_delegate.cc
@@ -58,7 +58,7 @@ #include <atlbase.h> #include <malloc.h> #include <algorithm> -#include "chrome/app/close_handle_hook_win.h" +#include "base/debug/close_handle_hook_win.h" #include "chrome/common/child_process_logging.h" #include "chrome/common/v8_breakpad_support_win.h" #include "components/crash/content/app/crashpad.h" @@ -193,6 +193,22 @@ return is_sandboxed_process_func && is_sandboxed_process_func(); } +bool UseHooks() { +#if defined(ARCH_CPU_X86_64) + return false; +#elif defined(NDEBUG) + version_info::Channel channel = chrome::GetChannel(); + if (channel == version_info::Channel::CANARY || + channel == version_info::Channel::DEV) { + return true; + } + + return false; +#else // NDEBUG + return true; +#endif +} + #endif // defined(OS_WIN) #if defined(OS_LINUX) @@ -502,7 +518,11 @@ return true; } - InstallHandleHooks(); + if (UseHooks()) + base::debug::InstallHandleHooks(); + else + base::win::DisableHandleVerifier(); + #endif chrome::RegisterPathProvider(); @@ -892,7 +912,7 @@ #endif // !defined(OS_ANDROID) #if defined(OS_WIN) - RemoveHandleHooks(); + base::debug::RemoveHandleHooks(); #endif }
diff --git a/chrome/app/close_handle_hook_win.h b/chrome/app/close_handle_hook_win.h deleted file mode 100644 index ed402d2..0000000 --- a/chrome/app/close_handle_hook_win.h +++ /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. - -#ifndef CHROME_APP_CLOSE_HANDLE_HOOK_WIN_H_ -#define CHROME_APP_CLOSE_HANDLE_HOOK_WIN_H_ - -// Installs the hooks required to debug use of improper handles. -void InstallHandleHooks(); - -// Removes the hooks installed by InstallHandleHooks(). -void RemoveHandleHooks(); - -#endif // CHROME_APP_CLOSE_HANDLE_HOOK_WIN_H_
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 9829f04..55817ab 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd
@@ -6108,7 +6108,7 @@ Enable the "stale-while-revalidate" cache directive </message> <message name="IDS_FLAGS_ENABLE_STALE_WHILE_REVALIDATE_DESCRIPTION" desc="Description of the flag to enable the "stale-while-revalidate" cache directive. This message is intended for web developers who are familiar with technical terms. "Cache-Control: stale-while-revalidate" is the literal string sent by the HTTP server, and so should be untranslated where possible. If necessary for translation it can be split into the HTTP header name part "Cache-Control" and the value part "stale-while-revalidate". "directive" here is an instruction sent by an HTTP server to indicate what caching behaviour should be used. The directive is typically configured by the server administrator. "servers" here refers to HTTP server software. "resources" here means individual files served by HTTP servers and cached by the browser. "be revalidated" means "be checked with the HTTP server whether or not the browser has the latest version". "in the background" here means without making the user wait. "latency" here refers to the time the user waits for a web page to be loaded or become usable."> - Enable the experimental implementation of the "Cache-Control: stale-while-revalidate" directive. This permits servers to specify that some resources may be revalidated in the background to improve latency. + Enable the experimental implementation of the "Cache-Control: stale-while-revalidate" directive. This permits servers to specify that some resources may be revalidated in the background to improve latency. </message> </if> <message name="IDS_FLAGS_ENABLE_NAVIGATION_TRACING" desc="Name of the flag to enable navigation tracing"> @@ -6587,13 +6587,6 @@ <message name="IDS_FLAGS_ENABLE_UNIFIED_MEDIA_PIPELINE_DESCRIPTION" desc="Description for the flag to enable the unified media pipeline on Android."> Enables the unified (Android and desktop) media pipeline on Android. </message> - <message name="IDS_FLAGS_SCROLL_TOP_LEFT_INTEROP_NAME" desc="Title for the flag to enable scrollTop interoperability"> - Document scrolling element interoperability. - </message> - <message name="IDS_FLAGS_SCROLL_TOP_LEFT_INTEROP_DESCRIPTION" desc="Description for the flag to enable scrollTop interoperability."> - Control whether document.body.scrollTop/scrollLeft in JavaScript reflects the standard interoperable behavior (enabled) or legacy WebKit behavior (disabled). - When enabled, document.scrollingElement is document.documentElement, when disabled it's document.body (for strict-mode pages). - </message> <message name="IDS_FLAGS_TRY_SUPPORTED_CHANNEL_LAYOUTS_NAME" desc="Title for the flag to enable support for trying supported channel layouts."> Causes audio output streams to check if channel layouts other than the default hardware layout are available. </message> @@ -7840,13 +7833,13 @@ Page blocked </message> <message name="IDS_BLOCK_INTERSTITIAL_MESSAGE" desc="A message for the supervised user when they attempt to visit a site that is not permitted by the manager."> - Oops, looks like you need permission from <ph name="NAME">$1<ex>John Doe</ex></ph> to access this page. + Oops! You need permission from <ph name="NAME">$1<ex>John Doe</ex></ph> to access this page. </message> <message name="IDS_CHILD_BLOCK_INTERSTITIAL_MESSAGE_SINGLE_PARENT" desc="A message for the child user when they attempt to visit a site that is not permitted by their parent."> - Oops! You need to ask your parent if it's ok to visit this page. + Oops! You need to ask your parent if it's OK to visit this page. </message> <message name="IDS_CHILD_BLOCK_INTERSTITIAL_MESSAGE_MULTI_PARENT" desc="A message for the child user when they attempt to visit a site that is not permitted by their parents."> - Oops! You need to ask your parents if it's ok to visit this page. + Oops! You need to ask your parents if it's OK to visit this page. </message> <message name="IDS_BLOCK_INTERSTITIAL_MESSAGE_ACCESS_REQUESTS_DISABLED" desc="A message for the supervised user when they attempt to visit a site that is not permitted by the manager (and they can't ask for permission)."> Oops, looks like you don't have permission to access this page. @@ -7855,7 +7848,7 @@ Go back </message> <message name="IDS_BLOCK_INTERSTITIAL_REQUEST_ACCESS_BUTTON" desc="A button for requesting access to blocked sites."> - Request permission + Ask permission </message> <message name="IDS_CHILD_BLOCK_INTERSTITIAL_REQUEST_ACCESS_BUTTON" desc="A button for requesting access to blocked sites."> Ask permission @@ -7878,21 +7871,45 @@ <message name="IDS_CHILD_BLOCK_INTERSTITIAL_REQUEST_FAILED_MESSAGE_MULTI_PARENT" desc="The text that tells the child user that a request to his/her parents failed."> We could not reach your parents at the moment. Please try again. </message> - <message name="IDS_SUPERVISED_USER_BLOCK_MESSAGE_DEFAULT" desc="Message to be shown when a site was blocked due to the default fallback behavior."> - This site was blocked due to the default fallback behavior. + <message name="IDS_CHILD_BLOCK_MESSAGE_DEFAULT_SINGLE_PARENT" desc="Message to be shown when a site was blocked due to the default fallback behavior and the child has one parent."> + You're seeing this message because your parent needs to approve new sites on your first visit. </message> - <message name="IDS_SUPERVISED_USER_BLOCK_MESSAGE_ASYNC_CHECKER" desc="Message to be shown when a site was blocked due to the SafeSites online safety check."> - This site was blocked due to the SafeSites online check. + <message name="IDS_CHILD_BLOCK_MESSAGE_DEFAULT_MULTI_PARENT" desc="Message to be shown when a site was blocked due to the default fallback behavior and the child has two parents."> + You're seeing this message because your parents need to approve new sites on your first visit. </message> - <message name="IDS_SUPERVISED_USER_BLOCK_MESSAGE_BLACKLIST" desc="Message to be shown when a site was blocked due to the static blacklist."> - This site was blocked due to the SafeSites static blacklist. + <message name="IDS_SUPERVISED_USER_BLOCK_MESSAGE_DEFAULT" desc="Message to be show to a supervised user when a site was blocked due to the default fallback behaviour."> + You're seeing this message because your manager needs to approve new sites on your first visit. </message> - <message name="IDS_SUPERVISED_USER_BLOCK_MESSAGE_MANUAL" desc="Message to be shown when a site was blocked due to a manual blacklist entry."> - This site was blocked due to a manual blacklist entry. + <message name="IDS_SUPERVISED_USER_BLOCK_HEADER_DEFAULT" desc="Header for the message to be shown when a site was blocked due to the default fallback behaviour."> + Not approved + </message> + <message name="IDS_SUPERVISED_USER_BLOCK_MESSAGE_SAFE_SITES" desc="Message to be shown when a site was blocked due to the SafeSites safety check."> + You're seeing this message because Google SafeSites is enabled. + </message> + <message name="IDS_SUPERVISED_USER_BLOCK_HEADER_SAFE_SITES" desc="Header for the message to be shown when a site was blocked due to the SafeSites safety check."> + SafeSites + </message> + <message name="IDS_CHILD_BLOCK_MESSAGE_MANUAL_SINGLE_PARENT" desc="Message to be shown to a child when a site was blocked due to a manual blacklist entry and the child has one parent."> + You're seeing this message because your parent blocked this site. + </message> + <message name="IDS_CHILD_BLOCK_MESSAGE_MANUAL_MULTI_PARENT" desc="Message to be shown to a child when a site was blocked due to a manual blacklist entry and the child has two parents."> + You're seeing this message because one of your parents blocked this site. + </message> + <message name="IDS_SUPERVISED_USER_BLOCK_MESSAGE_MANUAL" desc="Message to be shown to a supervised user when a site is blocked due to a manual blacklist entry"> + You're seeing this message because your manager blocked this site. + </message> + <message name="IDS_SUPERVISED_USER_BLOCK_HEADER_MANUAL" desc="Header for the message to be shown when a site was blocked due to a manual blacklist entry."> + Blocked </message> <message name="IDS_BLOCK_INTERSTITIAL_SEND_FEEDBACK" desc="The text for a link to submit feedback about a blocked site."> Was this unexpected? Tell us about it! </message> + <message name="IDS_BLOCK_INTERSTITIAL_SHOW_DETAILS" desc="The text for the link to show details about the interstitial."> + Details + </message> + <message name="IDS_BLOCK_INTERSTITIAL_HIDE_DETAILS" desc="The text for the link to hide details about the interstitial."> + Hide details + </message> <message name="IDS_BLOCK_INTERSTITIAL_DEFAULT_FEEDBACK_TEXT" desc="The default text for feedback about a blocked site."> <ph name="REASON">$1<ex>This site was blocked due to the SafeSites filter.</ex></ph> I don't think this site should be blocked! @@ -9941,7 +9958,7 @@ Restore settings to their original defaults. </message> <message name="IDS_RESET_PROFILE_SETTINGS_EXPLANATION" desc="A label describing the consequences of the 'reset profile settings' feature"> - Your settings will be restored to their original defaults. This will reset your homepage, new tab page and search engine, disable your extensions, and unpin all tabs. It will also clear other temporary and cached data, such as cookies, content and site data. + This will reset your startup page, new tab page, search engine, and pinned tabs. It will also disable all extensions and clear temporary data like cookies. Your bookmarks, history and saved passwords will not be cleared. </message> <message name="IDS_RESET_PROFILE_SETTINGS_BUTTON" desc="The text on the button in chrome://settings that allows resetting some settings in a profile"> Reset settings
diff --git a/chrome/app/main_dll_loader_win.cc b/chrome/app/main_dll_loader_win.cc index 9bf3b6ed..3ab9f69 100644 --- a/chrome/app/main_dll_loader_win.cc +++ b/chrome/app/main_dll_loader_win.cc
@@ -124,6 +124,9 @@ #if defined(KASKO) +// For ::GetProfileType(). +#pragma comment(lib, "userenv.lib") + // Returns a string containing a list of all modifiers for the loaded profile. std::wstring GetProfileType() { std::wstring profile_type;
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp index d2f25c6..08ae2fd5 100644 --- a/chrome/app/settings_strings.grdp +++ b/chrome/app/settings_strings.grdp
@@ -139,9 +139,36 @@ <message name="IDS_SETTINGS_BLUETOOTH" desc="Name of the settings page which displays bluetooth device settings."> Bluetooth </message> + <message name="IDS_SETTINGS_BLUETOOTH_ADD_DEVICE" desc="Name of the settings page for adding bluetooth devices."> + Add a Device + </message> + <message name="IDS_SETTINGS_BLUETOOTH_PAIR_DEVICE" desc="Name of the settings page for pairing bluetooth devices."> + Pair Bluetooth Device + </message> <message name="IDS_SETTINGS_BLUETOOTH_ENABLE" desc="Label for control to enable or disable bluetooth."> Enable Bluetooth </message> + <message name="IDS_SETTINGS_BLUETOOTH_REMOVE" desc="Label for removing (unpairing) a paired bluetooth device"> + Remove from list + </message> + <message name="IDS_SETTINGS_BLUETOOTH_REQUEST_PINCODE" desc="Bluetooth pairing message typically displayed when the external Bluetooth 2.0 and older device has no display or means of input."> + Please enter the PIN for "<ph name="DEVICE_NAME">$1<ex>Nexus S</ex></ph>": + </message> + <message name="IDS_SETTINGS_BLUETOOTH_DISPLAY_PINCODE" desc="Bluetooth pairing message typically displayed when pairing a Bluetooth 2.0 and older wireless keyboard."> + Please enter this PIN code on "<ph name="DEVICE_NAME">$1<ex>Nexus S</ex></ph>": + </message> + <message name="IDS_SETTINGS_BLUETOOTH_REQUEST_PASSKEY" desc="Bluetooth pairing message typically displayed when the external Bluetooth 2.1 and later device has no display or means of input, and does not support SSP."> + Please enter the passkey for "<ph name="DEVICE_NAME">$1<ex>Nexus S</ex></ph>": + </message> + <message name="IDS_SETTINGS_BLUETOOTH_DISPLAY_PASSKEY" desc="Bluetooth pairing message typically displayed when pairing a Bluetooth 2.1 and later wireless keyboard."> + Please enter this passkey on "<ph name="DEVICE_NAME">$1<ex>Nexus S</ex></ph>": + </message> + <message name="IDS_SETTINGS_BLUETOOTH_CONFIRM_PASSKEY" desc="Bluetooth pairing message typically shown when pairing with a device that has a display."> + Please confirm this passkey is shown on "<ph name="DEVICE_NAME">$1<ex>Nexus S</ex></ph>": + </message> + <message name="IDS_SETTINGS_BLUETOOTH_START_CONNECTING"> + Connecting to "<ph name="DEVICE_NAME">$1<ex>Nexus S</ex></ph>". + </message> </if> <!-- Certificate Manager Page -->
diff --git a/chrome/app/signature_validator_win.cc b/chrome/app/signature_validator_win.cc deleted file mode 100644 index c67216b..0000000 --- a/chrome/app/signature_validator_win.cc +++ /dev/null
@@ -1,223 +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/app/signature_validator_win.h" - -#include <atlstr.h> -#include <softpub.h> -#include <windows.h> -#include <stdint.h> -#include <wintrust.h> - -#include <algorithm> - -#include "base/files/file_path.h" -#include "base/macros.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/string_util.h" -#include "base/strings/utf_string_conversions.h" -#include "base/time/time.h" -#include "base/win/scoped_handle.h" -#include "crypto/sha2.h" -#include "crypto/wincrypt_shim.h" - -namespace { - -bool ExtractPublicKeyHash(const CERT_CONTEXT* cert_context, - std::string* public_key_hash) { - public_key_hash->clear(); - - CRYPT_BIT_BLOB crypt_blob = - cert_context->pCertInfo->SubjectPublicKeyInfo.PublicKey; - - // Key blobs that are not an integral number of bytes are unsupported. - if (crypt_blob.cUnusedBits != 0) - return false; - - uint8_t hash[crypto::kSHA256Length] = {}; - - base::StringPiece key_bytes(reinterpret_cast<char*>( - crypt_blob.pbData), crypt_blob.cbData); - crypto::SHA256HashString(key_bytes, hash, crypto::kSHA256Length); - - *public_key_hash = base::ToLowerASCII(base::HexEncode(hash, arraysize(hash))); - return true; -} - -// The traits class for HCERTSTORE handles that can be closed via -// CertCloseStore() API. -class CertStoreHandleTraits { - public: - typedef HCERTSTORE Handle; - - // Closes the handle. - static bool CloseHandle(HCERTSTORE handle) { - return CertCloseStore(handle, 0) != FALSE; - } - - // Returns true if the handle value is valid. - static bool IsHandleValid(HCERTSTORE handle) { - return handle != NULL; - } - - // Returns NULL handle value. - static HANDLE NullHandle() { - return NULL; - } - - private: - DISALLOW_IMPLICIT_CONSTRUCTORS(CertStoreHandleTraits); -}; - -typedef base::win::GenericScopedHandle<CertStoreHandleTraits, - base::win::DummyVerifierTraits> ScopedCertStoreHandle; - -// Class: CertInfo -// -// CertInfo holds all sensible details of a certificate. During verification of -// a signature, one CertInfo object is made for each certificate encountered in -// the signature. -class CertInfo { - public: - explicit CertInfo(const CERT_CONTEXT* given_cert_context) - : cert_context_(NULL) { - if (given_cert_context) { - // CertDuplicateCertificateContext just increases reference count of a - // given CERT_CONTEXT. - cert_context_ = CertDuplicateCertificateContext(given_cert_context); - not_valid_before_ = cert_context_->pCertInfo->NotBefore; - not_valid_after_ = cert_context_->pCertInfo->NotAfter; - - ExtractPublicKeyHash(cert_context_, &public_key_hash_); - } - } - - ~CertInfo() { // Decrement reference count, if needed. - if (cert_context_) { - CertFreeCertificateContext(cert_context_); - cert_context_ = NULL; - } - } - - // IsValidNow() functions returns true if this certificate is valid at this - // moment, based on the validity period specified in the certificate. - bool IsValidNow() const { - // we cannot directly get current time in FILETIME format. - // so first get it in SYSTEMTIME format and convert it into FILETIME. - base::Time now = base::Time::NowFromSystemTime(); - FILETIME filetime_now = now.ToFileTime(); - // CompareFileTime() is a windows function - return ((CompareFileTime(&filetime_now, ¬_valid_before_) > 0) && - (CompareFileTime(&filetime_now, ¬_valid_after_) < 0)); - } - - std::string public_key_hash() const { - return public_key_hash_; - } - - private: - // cert_context structure, defined by Crypto API, contains all the info - // about the certificate. - const CERT_CONTEXT* cert_context_; - - // Lower-case hex SHA-256 hash of the certificate subject's public key. - std::string public_key_hash_; - - // Validity period start-date - FILETIME not_valid_before_; - - // Validity period end-date - FILETIME not_valid_after_; -}; - -} // namespace - -bool VerifyAuthenticodeSignature(const base::FilePath& signed_file) { - // Don't pop up any windows - const HWND window_mode = reinterpret_cast<HWND>(INVALID_HANDLE_VALUE); - - // Verify file & certificates using the Microsoft Authenticode Policy - // Provider. - GUID verification_type = WINTRUST_ACTION_GENERIC_VERIFY_V2; - - // Info for the file we're going to verify. - WINTRUST_FILE_INFO file_info = {}; - file_info.cbStruct = sizeof(file_info); - file_info.pcwszFilePath = signed_file.value().c_str(); - - // Info for request to WinVerifyTrust. - WINTRUST_DATA trust_data = {}; - trust_data.cbStruct = sizeof(trust_data); - trust_data.dwUIChoice = WTD_UI_NONE; // no graphics - trust_data.fdwRevocationChecks = WTD_REVOKE_NONE; // no revocation checking - trust_data.dwUnionChoice = WTD_CHOICE_FILE; // check a file - trust_data.pFile = &file_info; // check this file - trust_data.dwProvFlags = WTD_REVOCATION_CHECK_NONE; - - // From the WinVerifyTrust documentation: - // http://msdn2.microsoft.com/en-us/library/aa388208.aspx: - // "If the trust provider verifies that the subject is trusted - // for the specified action, the return value is zero. No other - // value besides zero should be considered a successful return." - LONG result = WinVerifyTrust(window_mode, &verification_type, &trust_data); - return !result; -} - -bool VerifySignerIsGoogle(const base::FilePath& signed_file, - const std::string& subject_name, - const std::vector<std::string>& expected_hashes) { - if (signed_file.empty()) - return false; - - // If successful, cert_store will be populated by a store containing all the - // certificates related to the file signature. - HCERTSTORE cert_store = NULL; - - BOOL succeeded = CryptQueryObject( - CERT_QUERY_OBJECT_FILE, - signed_file.value().c_str(), - CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED, - CERT_QUERY_FORMAT_FLAG_ALL, - 0, // Reserved: must be 0. - NULL, - NULL, - NULL, - &cert_store, - NULL, // Do not return the message. - NULL); // Do not return additional context. - - ScopedCertStoreHandle scoped_cert_store(cert_store); - - if (!succeeded || !scoped_cert_store.IsValid()) - return false; - - PCCERT_CONTEXT cert_context_ptr = NULL; - cert_context_ptr = CertFindCertificateInStore( - cert_store, - X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, - 0, - CERT_FIND_SUBJECT_STR, - base::UTF8ToWide(subject_name).c_str(), - cert_context_ptr); - - // No cert found with this subject, so stop here. - if (!cert_context_ptr) - return false; - - CertInfo cert_info(cert_context_ptr); - - CertFreeCertificateContext(cert_context_ptr); - cert_context_ptr = NULL; - - // Check the hashes to make sure subject isn't being faked, and the time - // to make sure the cert is current. - std::vector<std::string>::const_iterator it = std::find( - expected_hashes.begin(), - expected_hashes.end(), - cert_info.public_key_hash()); - if (it == expected_hashes.end() || !cert_info.IsValidNow()) - return false; - - return true; -}
diff --git a/chrome/app/signature_validator_win.h b/chrome/app/signature_validator_win.h deleted file mode 100644 index 8cc007f..0000000 --- a/chrome/app/signature_validator_win.h +++ /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. - -#ifndef CHROME_APP_SIGNATURE_VALIDATOR_WIN_H_ -#define CHROME_APP_SIGNATURE_VALIDATOR_WIN_H_ - -#include <string> -#include <vector> - -namespace base { -class FilePath; -} - -// Verifies that |signed_file| has a valid signature from a trusted software -// publisher. The signing certificate must be valid for code signing, and must -// be issued by a trusted certificate authority (e.g., VeriSign, Inc). -bool VerifyAuthenticodeSignature(const base::FilePath& signed_file); - -// Tries to verify the signer by matching the subject name of the -// certificate to |subject_name| and the hash of the public key to -// |expected_hashes|. The cert must be current. If matched, returns true -// otherwise returns false. -bool VerifySignerIsGoogle(const base::FilePath& signed_file, - const std::string& subject_name, - const std::vector<std::string>& expected_hashes); - -#endif // CHROME_APP_SIGNATURE_VALIDATOR_WIN_H_
diff --git a/chrome/app/signature_validator_win_unittest.cc b/chrome/app/signature_validator_win_unittest.cc deleted file mode 100644 index a22fdfb8..0000000 --- a/chrome/app/signature_validator_win_unittest.cc +++ /dev/null
@@ -1,133 +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 <windows.h> -#include <atlstr.h> -#include <stddef.h> -#include <stdint.h> -#include <wintrust.h> - -#include "base/base_paths.h" -#include "base/compiler_specific.h" -#include "base/files/file_path.h" -#include "base/files/file_util.h" -#include "base/logging.h" -#include "base/macros.h" -#include "base/path_service.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/string_piece.h" -#include "base/strings/string_util.h" -#include "chrome/app/signature_validator_win.h" -#include "crypto/sha2.h" -#include "crypto/wincrypt_shim.h" -#include "net/cert/test_root_certs.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace { - -const char kGoogleCertIssuer[] = "Google Inc"; -const int CERT_BUFFER_SIZE = 1024; - -const base::FilePath::CharType kCertificateRelativePath[] = - FILE_PATH_LITERAL("chrome\\app\\test_data\\certificates\\"); -const base::FilePath::CharType kDLLRelativePath[] = - FILE_PATH_LITERAL("chrome\\app\\test_data\\dlls\\"); - -class SignatureValidatorTest : public testing::Test { - protected: - SignatureValidatorTest() {} - - void SetUp() override { - test_roots_ = net::TestRootCerts::GetInstance(); - base::FilePath cert_path = - GetTestCertsDirectory().Append(L"AuthorityCert.cer"); - base::FilePath other_cert_path = - GetTestCertsDirectory().Append(L"OtherAuthorityCert.cer"); - test_roots_->AddFromFile(cert_path); - test_roots_->AddFromFile(other_cert_path); - EXPECT_FALSE(test_roots_->IsEmpty()); - - SetExpectedHash(GetTestCertsDirectory().Append(L"ValidCert.cer")); - } - - void TearDown() override { - test_roots_->Clear(); - EXPECT_TRUE(test_roots_->IsEmpty()); - } - - base::FilePath GetTestCertsDirectory() { - base::FilePath src_root; - PathService::Get(base::DIR_SOURCE_ROOT, &src_root); - return src_root.Append(kCertificateRelativePath); - } - - base::FilePath GetTestDLLsDirectory() { - base::FilePath src_root; - PathService::Get(base::DIR_SOURCE_ROOT, &src_root); - return src_root.Append(kDLLRelativePath); - } - - void SetExpectedHash(const base::FilePath& cert_path) { - char cert_buffer[CERT_BUFFER_SIZE]; - base::ReadFile(cert_path, cert_buffer, CERT_BUFFER_SIZE); - - PCCERT_CONTEXT cert = CertCreateCertificateContext(X509_ASN_ENCODING, - reinterpret_cast<byte*>(&cert_buffer), - CERT_BUFFER_SIZE); - - CRYPT_BIT_BLOB blob = cert->pCertInfo->SubjectPublicKeyInfo.PublicKey; - size_t public_key_length = blob.cbData; - uint8_t* public_key = blob.pbData; - - uint8_t hash[crypto::kSHA256Length] = {0}; - - base::StringPiece key_bytes(reinterpret_cast<char*>(public_key), - public_key_length); - crypto::SHA256HashString(key_bytes, hash, crypto::kSHA256Length); - - std::string public_key_hash = - base::ToLowerASCII(base::HexEncode(hash, arraysize(hash))); - expected_hashes_.push_back(public_key_hash); - } - - void RunTest(const wchar_t* dll_filename, bool isValid, bool isGoogle) { - base::FilePath full_dll_path = GetTestDLLsDirectory().Append(dll_filename); - ASSERT_EQ(isValid, VerifyAuthenticodeSignature(full_dll_path)); - ASSERT_EQ(isGoogle, VerifySignerIsGoogle(full_dll_path, kGoogleCertIssuer, - expected_hashes_)); - } - - private: - net::TestRootCerts* test_roots_; - std::vector<std::string> expected_hashes_; -}; - -} // namespace - -TEST_F(SignatureValidatorTest, ValidSigTest) { - RunTest(L"valid_sig.dll", true, true); -} - -TEST_F(SignatureValidatorTest, SelfSignedTest) { - RunTest(L"self_signed.dll", false, false); -} - -TEST_F(SignatureValidatorTest, NotSignedTest) { - RunTest(L"not_signed.dll", false, false); -} - -TEST_F(SignatureValidatorTest, NotGoogleTest) { - RunTest(L"not_google.dll", true, false); -} - -TEST_F(SignatureValidatorTest, CertPinningTest) { - RunTest(L"different_hash.dll", true, false); -} - -TEST_F(SignatureValidatorTest, ExpiredCertTest) { - //TODO(caitkp): Figure out how to sign a dll with an expired cert. - RunTest(L"expired.dll", false, false); -} - -
diff --git a/chrome/app/test_data/README b/chrome/app/test_data/README deleted file mode 100644 index 3153e5e..0000000 --- a/chrome/app/test_data/README +++ /dev/null
@@ -1,6 +0,0 @@ -This directory contains: --A directory of test dlls (dlls/) which contains several "dummy" dlls each -signed with varying degrees of validity (see cert_maker.bat for details) --A directory of test certs (certificates/) which are not used directly in the -tests, but are useful for analyzing test failures. --A script "cert_maker.bat" to generate these certs and sign the dlls. \ No newline at end of file
diff --git a/chrome/app/test_data/cert_maker.bat b/chrome/app/test_data/cert_maker.bat deleted file mode 100755 index 2072170..0000000 --- a/chrome/app/test_data/cert_maker.bat +++ /dev/null
@@ -1,75 +0,0 @@ -REM Copyright 2013 The Chromium Authors. All rights reserved. -REM Use of this source code is governed by a BSD-style license that can be -REM found in the LICENSE file. - -del /q certificates\* - -REM Create a Cert Authority. -makecert -r -pe -n "CN=CertAuthority" -ss CA -sr CurrentUser ^ - -a sha256 -cy authority -sky signature ^ - -sv certificates\AuthorityCert.pvk certificates\AuthorityCert.cer - -REM Create a second Cert Authority (used to test cert pinning). -makecert -r -pe -n "CN=OtherCertAuthority" -ss CA -sr CurrentUser ^ - -a sha256 -cy authority -sky signature ^ - -sv certificates\OtherAuthorityCert.pvk ^ - certificates\OtherAuthorityCert.cer - -REM Create a self-signed cert. -makecert -r -pe -n "CN=SelfSigned" -ss CA -sr CurrentUser ^ - -a sha256 -cy authority -sky signature ^ - -sv certificates\SelfSigned.pvk certificates\SelfSigned.cer - -pvk2pfx -pvk certificates\SelfSigned.pvk -spc certificates\SelfSigned.cer ^ - -pfx certificates\SelfSigned.pfx - -signtool sign /v /f certificates\SelfSigned.pfx dlls\self_signed.dll - -REM Create a signing cert from our first CA, with proper company name. -makecert -pe -n "CN=Google Inc, OU=Chrome Testers" -a sha256 -cy end ^ - -sky signature ^ - -ic certificates\AuthorityCert.cer -iv certificates\AuthorityCert.pvk ^ - -sv certificates\ValidCert.pvk certificates\ValidCert.cer - -pvk2pfx -pvk certificates\ValidCert.pvk -spc certificates\ValidCert.cer ^ - -pfx certificates\ValidCert.pfx - -signtool sign /v /f certificates\ValidCert.pfx dlls\valid_sig.dll - -REM Create a signing cert from our first CA, with wrong company name. -makecert -pe -n "CN=NotGoogle Inc, OU=Chrome Testers" -a sha256 -cy end ^ - -sky signature ^ - -ic certificates\AuthorityCert.cer -iv certificates\AuthorityCert.pvk ^ - -sv certificates\NotGoogleCert.pvk certificates\NotGoogleCert.cer - -pvk2pfx -pvk certificates\NotGoogleCert.pvk ^ - -spc certificates\NotGoogleCert.cer -pfx certificates\NotGoogleCert.pfx - -signtool sign /v /f certificates\NotGoogleCert.pfx dlls\not_google.dll - -REM Create a signing cert from the other CA. -makecert -pe -n "CN=Google Inc, OU=Other Chrome Testers" -a sha256 -cy end ^ - -sky signature ^ - -ic certificates\OtherAuthorityCert.cer ^ - -iv certificates\OtherAuthorityCert.pvk ^ - -sv certificates\DifferentHash.pvk certificates\DifferentHash.cer - -pvk2pfx -pvk certificates\DifferentHash.pvk ^ - -spc certificates\DifferentHash.cer -pfx certificates\DifferentHash.pfx - -signtool sign /v /f certificates\DifferentHash.pfx dlls\different_hash.dll - -REM Create an expired signing cert from our first CA. -makecert -pe -n "CN=Google Inc, OU=Chrome Testers" -a sha256 -cy end ^ - -sky signature ^ - -ic certificates\AuthorityCert.cer -iv certificates\AuthorityCert.pvk ^ - -e 12/31/2012 ^ - -sv certificates\ExpiredCert.pvk certificates\ExpiredCert.cer - -pvk2pfx -pvk certificates\ExpiredCert.pvk -spc certificates\ExpiredCert.cer ^ - -pfx certificates\ExpiredCert.pfx - -signtool sign /v /f certificates\ExpiredCert.pfx dlls\expired.dll - -del /q certificates\*.pvk -del /q certificates\*.pfx
diff --git a/chrome/app/test_data/certificates/AuthorityCert.cer b/chrome/app/test_data/certificates/AuthorityCert.cer deleted file mode 100644 index 0bb9b24..0000000 --- a/chrome/app/test_data/certificates/AuthorityCert.cer +++ /dev/null Binary files differ
diff --git a/chrome/app/test_data/certificates/DifferentHash.cer b/chrome/app/test_data/certificates/DifferentHash.cer deleted file mode 100644 index 3698238..0000000 --- a/chrome/app/test_data/certificates/DifferentHash.cer +++ /dev/null Binary files differ
diff --git a/chrome/app/test_data/certificates/ExpiredCert.cer b/chrome/app/test_data/certificates/ExpiredCert.cer deleted file mode 100644 index 7f35454..0000000 --- a/chrome/app/test_data/certificates/ExpiredCert.cer +++ /dev/null Binary files differ
diff --git a/chrome/app/test_data/certificates/NotGoogleCert.cer b/chrome/app/test_data/certificates/NotGoogleCert.cer deleted file mode 100644 index 8acb7a4..0000000 --- a/chrome/app/test_data/certificates/NotGoogleCert.cer +++ /dev/null Binary files differ
diff --git a/chrome/app/test_data/certificates/OtherAuthorityCert.cer b/chrome/app/test_data/certificates/OtherAuthorityCert.cer deleted file mode 100644 index 4b05d3d..0000000 --- a/chrome/app/test_data/certificates/OtherAuthorityCert.cer +++ /dev/null Binary files differ
diff --git a/chrome/app/test_data/certificates/SelfSigned.cer b/chrome/app/test_data/certificates/SelfSigned.cer deleted file mode 100644 index 0bf13e7..0000000 --- a/chrome/app/test_data/certificates/SelfSigned.cer +++ /dev/null Binary files differ
diff --git a/chrome/app/test_data/certificates/ValidCert.cer b/chrome/app/test_data/certificates/ValidCert.cer deleted file mode 100644 index 8f37082..0000000 --- a/chrome/app/test_data/certificates/ValidCert.cer +++ /dev/null Binary files differ
diff --git a/chrome/app/test_data/dlls/different_hash.dll b/chrome/app/test_data/dlls/different_hash.dll deleted file mode 100755 index e2974b7..0000000 --- a/chrome/app/test_data/dlls/different_hash.dll +++ /dev/null Binary files differ
diff --git a/chrome/app/test_data/dlls/expired.dll b/chrome/app/test_data/dlls/expired.dll deleted file mode 100755 index 72d0a1b..0000000 --- a/chrome/app/test_data/dlls/expired.dll +++ /dev/null Binary files differ
diff --git a/chrome/app/test_data/dlls/not_google.dll b/chrome/app/test_data/dlls/not_google.dll deleted file mode 100755 index f0c1ce2..0000000 --- a/chrome/app/test_data/dlls/not_google.dll +++ /dev/null Binary files differ
diff --git a/chrome/app/test_data/dlls/not_signed.dll b/chrome/app/test_data/dlls/not_signed.dll deleted file mode 100755 index 72d0a1b..0000000 --- a/chrome/app/test_data/dlls/not_signed.dll +++ /dev/null Binary files differ
diff --git a/chrome/app/test_data/dlls/self_signed.dll b/chrome/app/test_data/dlls/self_signed.dll deleted file mode 100755 index eb8b709..0000000 --- a/chrome/app/test_data/dlls/self_signed.dll +++ /dev/null Binary files differ
diff --git a/chrome/app/test_data/dlls/valid_sig.dll b/chrome/app/test_data/dlls/valid_sig.dll deleted file mode 100755 index b2d4607f..0000000 --- a/chrome/app/test_data/dlls/valid_sig.dll +++ /dev/null Binary files differ
diff --git a/chrome/app/theme/default_100_percent/common/ash/browser_window_control_background_maximized_hover.png b/chrome/app/theme/default_100_percent/common/ash/browser_window_control_background_maximized_hover.png deleted file mode 100644 index 9aaa7d64..0000000 --- a/chrome/app/theme/default_100_percent/common/ash/browser_window_control_background_maximized_hover.png +++ /dev/null Binary files differ
diff --git a/chrome/app/theme/default_100_percent/common/ash/browser_window_control_background_maximized_pressed.png b/chrome/app/theme/default_100_percent/common/ash/browser_window_control_background_maximized_pressed.png deleted file mode 100644 index b8b8e796..0000000 --- a/chrome/app/theme/default_100_percent/common/ash/browser_window_control_background_maximized_pressed.png +++ /dev/null Binary files differ
diff --git a/chrome/app/theme/default_100_percent/common/ash/browser_window_control_background_restored_hover.png b/chrome/app/theme/default_100_percent/common/ash/browser_window_control_background_restored_hover.png deleted file mode 100644 index 59407a0..0000000 --- a/chrome/app/theme/default_100_percent/common/ash/browser_window_control_background_restored_hover.png +++ /dev/null Binary files differ
diff --git a/chrome/app/theme/default_100_percent/common/ash/browser_window_control_background_restored_pressed.png b/chrome/app/theme/default_100_percent/common/ash/browser_window_control_background_restored_pressed.png deleted file mode 100644 index 8eed7ea..0000000 --- a/chrome/app/theme/default_100_percent/common/ash/browser_window_control_background_restored_pressed.png +++ /dev/null Binary files differ
diff --git a/chrome/app/theme/default_100_percent/common/error_managed_mode_blocked_page.png b/chrome/app/theme/default_100_percent/common/error_managed_mode_blocked_page.png deleted file mode 100644 index 909ce74..0000000 --- a/chrome/app/theme/default_100_percent/common/error_managed_mode_blocked_page.png +++ /dev/null Binary files differ
diff --git a/chrome/app/theme/default_200_percent/common/ash/browser_window_control_background_maximized_hover.png b/chrome/app/theme/default_200_percent/common/ash/browser_window_control_background_maximized_hover.png deleted file mode 100644 index 5750f07..0000000 --- a/chrome/app/theme/default_200_percent/common/ash/browser_window_control_background_maximized_hover.png +++ /dev/null Binary files differ
diff --git a/chrome/app/theme/default_200_percent/common/ash/browser_window_control_background_maximized_pressed.png b/chrome/app/theme/default_200_percent/common/ash/browser_window_control_background_maximized_pressed.png deleted file mode 100644 index 3d6843b..0000000 --- a/chrome/app/theme/default_200_percent/common/ash/browser_window_control_background_maximized_pressed.png +++ /dev/null Binary files differ
diff --git a/chrome/app/theme/default_200_percent/common/ash/browser_window_control_background_restored_hover.png b/chrome/app/theme/default_200_percent/common/ash/browser_window_control_background_restored_hover.png deleted file mode 100644 index 508d5cf4..0000000 --- a/chrome/app/theme/default_200_percent/common/ash/browser_window_control_background_restored_hover.png +++ /dev/null Binary files differ
diff --git a/chrome/app/theme/default_200_percent/common/ash/browser_window_control_background_restored_pressed.png b/chrome/app/theme/default_200_percent/common/ash/browser_window_control_background_restored_pressed.png deleted file mode 100644 index 0fa10f0f6..0000000 --- a/chrome/app/theme/default_200_percent/common/ash/browser_window_control_background_restored_pressed.png +++ /dev/null Binary files differ
diff --git a/chrome/app/theme/default_200_percent/common/error_managed_mode_blocked_page.png b/chrome/app/theme/default_200_percent/common/error_managed_mode_blocked_page.png deleted file mode 100644 index 1463ba4..0000000 --- a/chrome/app/theme/default_200_percent/common/error_managed_mode_blocked_page.png +++ /dev/null Binary files differ
diff --git a/chrome/app/theme/mac/apps_folder_16.png b/chrome/app/theme/mac/apps_folder_16.png index c4232778..2ee79212 100644 --- a/chrome/app/theme/mac/apps_folder_16.png +++ b/chrome/app/theme/mac/apps_folder_16.png Binary files differ
diff --git a/chrome/app/theme/mac/apps_folder_32.png b/chrome/app/theme/mac/apps_folder_32.png index 7e803377..34c70405 100644 --- a/chrome/app/theme/mac/apps_folder_32.png +++ b/chrome/app/theme/mac/apps_folder_32.png Binary files differ
diff --git a/chrome/app/theme/mac/apps_folder_overlay_128.png b/chrome/app/theme/mac/apps_folder_overlay_128.png index 77241bae..7b9593e2 100644 --- a/chrome/app/theme/mac/apps_folder_overlay_128.png +++ b/chrome/app/theme/mac/apps_folder_overlay_128.png Binary files differ
diff --git a/chrome/app/theme/mac/apps_folder_overlay_512.png b/chrome/app/theme/mac/apps_folder_overlay_512.png index a7659e2..1fd116a 100644 --- a/chrome/app/theme/mac/apps_folder_overlay_512.png +++ b/chrome/app/theme/mac/apps_folder_overlay_512.png Binary files differ
diff --git a/chrome/app/theme/theme_resources.grd b/chrome/app/theme/theme_resources.grd index d7949096..97aea9d 100644 --- a/chrome/app/theme/theme_resources.grd +++ b/chrome/app/theme/theme_resources.grd
@@ -77,10 +77,6 @@ <structure type="chrome_scaled_image" name="IDR_APP_WINDOW_MINIMIZE_P" file="common/app_window_minimize_active.png" /> </if> <if expr="use_ash"> - <structure type="chrome_scaled_image" name="IDR_ASH_BROWSER_WINDOW_CONTROL_BACKGROUND_MAXIMIZED_H" file="common/ash/browser_window_control_background_maximized_hover.png" /> - <structure type="chrome_scaled_image" name="IDR_ASH_BROWSER_WINDOW_CONTROL_BACKGROUND_MAXIMIZED_P" file="common/ash/browser_window_control_background_maximized_pressed.png" /> - <structure type="chrome_scaled_image" name="IDR_ASH_BROWSER_WINDOW_CONTROL_BACKGROUND_RESTORED_H" file="common/ash/browser_window_control_background_restored_hover.png" /> - <structure type="chrome_scaled_image" name="IDR_ASH_BROWSER_WINDOW_CONTROL_BACKGROUND_RESTORED_P" file="common/ash/browser_window_control_background_restored_pressed.png" /> <structure type="chrome_scaled_image" name="IDR_ASH_BROWSER_WINDOW_HEADER_SHADE_LEFT" file="common/ash/browser_window_header_shade_left.png" /> <structure type="chrome_scaled_image" name="IDR_ASH_BROWSER_WINDOW_HEADER_SHADE_RIGHT" file="common/ash/browser_window_header_shade_right.png" /> <structure type="chrome_scaled_image" name="IDR_ASH_BROWSER_WINDOW_HEADER_SHADE_TOP" file="common/ash/browser_window_header_shade_top.png" /> @@ -91,10 +87,6 @@ <structure type="chrome_scaled_image" name="IDR_AUTOFILL_DIALOG_MENU_BUTTON_P" file="common/autofill_dialog_menu_button_pressed.png" /> <structure type="chrome_scaled_image" name="IDR_AUTOFILL_DIALOG_MENU_BUTTON_H" file="common/autofill_dialog_menu_button_hover.png" /> <structure type="chrome_scaled_image" name="IDR_AUTOFILL_DIALOG_MENU_BUTTON_D" file="common/autofill_dialog_menu_button_disabled.png" /> - <if expr="is_macosx"> - <structure type="chrome_scaled_image" name="IDR_AUTOFILL_TOOLTIP_ICON" file="legacy/autofill_tooltip_icon.png" /> - <structure type="chrome_scaled_image" name="IDR_AUTOFILL_TOOLTIP_ICON_H" file="legacy/autofill_tooltip_icon_hover.png" /> - </if> <!-- TODO(jamescook): Update all Chrome platforms to use the new art and metrics from Ash, crbug.com/118228 --> <if expr="toolkit_views or is_macosx or is_ios">
diff --git a/chrome/app_shim/OWNERS b/chrome/app_shim/OWNERS index 7f10d7c..fff9c34f 100644 --- a/chrome/app_shim/OWNERS +++ b/chrome/app_shim/OWNERS
@@ -1,2 +1,2 @@ +dominickn@chromium.org tapted@chromium.org -jackhou@chromium.org
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 4d4d02f..161a823 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -36,6 +36,7 @@ #include "components/cloud_devices/common/cloud_devices_switches.h" #include "components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h" #include "components/dom_distiller/core/dom_distiller_switches.h" +#include "components/error_page/common/error_page_switches.h" #include "components/flags_ui/feature_entry_macros.h" #include "components/flags_ui/flags_storage.h" #include "components/flags_ui/flags_ui_switches.h" @@ -204,11 +205,14 @@ const FeatureEntry::Choice kShowSavedCopyChoices[] = { { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" }, { IDS_FLAGS_ENABLE_SHOW_SAVED_COPY_PRIMARY, - switches::kShowSavedCopy, switches::kEnableShowSavedCopyPrimary }, + error_page::switches::kShowSavedCopy, + error_page::switches::kEnableShowSavedCopyPrimary }, { IDS_FLAGS_ENABLE_SHOW_SAVED_COPY_SECONDARY, - switches::kShowSavedCopy, switches::kEnableShowSavedCopySecondary }, + error_page::switches::kShowSavedCopy, + error_page::switches::kEnableShowSavedCopySecondary }, { IDS_FLAGS_DISABLE_SHOW_SAVED_COPY, - switches::kShowSavedCopy, switches::kDisableShowSavedCopy } + error_page::switches::kShowSavedCopy, + error_page::switches::kDisableShowSavedCopy } }; const FeatureEntry::Choice kDefaultTileWidthChoices[] = { @@ -657,13 +661,12 @@ IDS_FLAGS_SHOW_AUTOFILL_TYPE_PREDICTIONS_DESCRIPTION, kOsAll, SINGLE_VALUE_TYPE(autofill::switches::kShowAutofillTypePredictions)}, - {"enable-smooth-scrolling", // FLAGS:RECORD_UMA + {"disable-smooth-scrolling", // FLAGS:RECORD_UMA IDS_FLAGS_SMOOTH_SCROLLING_NAME, IDS_FLAGS_SMOOTH_SCROLLING_DESCRIPTION, - // Can't expose the switch unless the code is compiled in. - // On by default for the Mac (different implementation in WebKit). - kOsLinux | kOsWin, - SINGLE_VALUE_TYPE(switches::kEnableSmoothScrolling)}, + // Mac has a separate implementation with its own setting to disable. + kOsLinux | kOsCrOS | kOsWin | kOsAndroid, + SINGLE_DISABLE_VALUE_TYPE(switches::kDisableSmoothScrolling)}, #if defined(USE_AURA) || defined(OS_LINUX) {"overlay-scrollbars", IDS_FLAGS_OVERLAY_SCROLLBARS_NAME, @@ -1834,16 +1837,6 @@ autofill::switches::kEnableAccessorySuggestionView, autofill::switches::kDisableAccessorySuggestionView)}, #endif // defined(OS_ANDROID) - // Temporary flag to ease the transition to standard-compliant scrollTop - // behavior. Will be removed shortly after http://crbug.com/157855 ships. - {"scroll-top-left-interop", - IDS_FLAGS_SCROLL_TOP_LEFT_INTEROP_NAME, - IDS_FLAGS_SCROLL_TOP_LEFT_INTEROP_DESCRIPTION, - kOsAll, - ENABLE_DISABLE_VALUE_TYPE_AND_VALUE(switches::kEnableBlinkFeatures, - "ScrollTopLeftInterop", - switches::kDisableBlinkFeatures, - "ScrollTopLeftInterop")}, #if defined(OS_WIN) {"try-supported-channel-layouts", IDS_FLAGS_TRY_SUPPORTED_CHANNEL_LAYOUTS_NAME,
diff --git a/chrome/browser/android/chrome_jni_registrar.cc b/chrome/browser/android/chrome_jni_registrar.cc index b84afe79..33ce239 100644 --- a/chrome/browser/android/chrome_jni_registrar.cc +++ b/chrome/browser/android/chrome_jni_registrar.cc
@@ -114,6 +114,7 @@ #include "chrome/browser/ssl/security_state_model_android.h" #include "chrome/browser/supervised_user/child_accounts/child_account_feedback_reporter_android.h" #include "chrome/browser/supervised_user/child_accounts/child_account_service_android.h" +#include "chrome/browser/supervised_user/supervised_user_content_provider_android.h" #include "chrome/browser/sync/profile_sync_service_android.h" #include "chrome/browser/ui/android/autofill/autofill_dialog_controller_android.h" #include "chrome/browser/ui/android/autofill/autofill_dialog_result.h" @@ -337,6 +338,7 @@ {"SSLClientCertificateRequest", RegisterSSLClientCertificateRequestAndroid}, {"StartupMetricUtils", RegisterStartupMetricUtils}, {"StaticTabSceneLayer", chrome::android::RegisterStaticTabSceneLayer}, + {"SupervisedUserContentProvider", SupervisedUserContentProvider::Register}, {"Sync", syncer::RegisterSyncJni}, {"TabAndroid", TabAndroid::RegisterTabAndroid}, {"TabContentManager", chrome::android::RegisterTabContentManager},
diff --git a/chrome/browser/android/data_usage/data_use_matcher.cc b/chrome/browser/android/data_usage/data_use_matcher.cc index 72703a8..8959c64 100644 --- a/chrome/browser/android/data_usage/data_use_matcher.cc +++ b/chrome/browser/android/data_usage/data_use_matcher.cc
@@ -131,6 +131,20 @@ return false; } +void DataUseMatcher::FetchMatchingRules() { + DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK(io_task_runner_); + + // Notify |external_data_use_observer_| to fetch the rules. + io_task_runner_->PostTask( + FROM_HERE, base::Bind(&ExternalDataUseObserver::FetchMatchingRules, + external_data_use_observer_)); +} + +bool DataUseMatcher::HasValidRules() const { + return !matching_rules_.empty(); +} + void DataUseMatcher::ParsePackageField(const std::string& app_package_name, std::string* new_app_package_name, base::TimeTicks* expiration) const {
diff --git a/chrome/browser/android/data_usage/data_use_matcher.h b/chrome/browser/android/data_usage/data_use_matcher.h index 5fddaa3..9d1a12c 100644 --- a/chrome/browser/android/data_usage/data_use_matcher.h +++ b/chrome/browser/android/data_usage/data_use_matcher.h
@@ -66,6 +66,13 @@ bool MatchesAppPackageName(const std::string& app_package_name, std::string* label) const WARN_UNUSED_RESULT; + // Fetches the matching rules asynchronously from + // |external_data_use_observer_|. + void FetchMatchingRules(); + + // Returns true if there is any valid matching rule. + bool HasValidRules() const; + private: friend class DataUseMatcherTest; FRIEND_TEST_ALL_PREFIXES(DataUseMatcherTest,
diff --git a/chrome/browser/android/data_usage/data_use_tab_model.cc b/chrome/browser/android/data_usage/data_use_tab_model.cc index 16784c093..b6cbc9d 100644 --- a/chrome/browser/android/data_usage/data_use_tab_model.cc +++ b/chrome/browser/android/data_usage/data_use_tab_model.cc
@@ -132,6 +132,7 @@ max_sessions_per_tab_(GetMaxSessionsPerTab()), closed_tab_expiration_duration_(GetClosedTabExpirationDuration()), open_tab_expiration_duration_(GetOpenTabExpirationDuration()), + is_control_app_installed_(false), weak_factory_(this) { // Detach from current thread since rest of DataUseTabModel lives on the UI // thread and the current thread may not be UI thread.. @@ -169,6 +170,9 @@ std::string current_label, new_label; bool is_package_match; + if (is_control_app_installed_ && !data_use_matcher_->HasValidRules()) + data_use_matcher_->FetchMatchingRules(); + GetCurrentAndNewLabelForNavigationEvent(tab_id, transition, url, package, ¤t_label, &new_label, &is_package_match); @@ -256,6 +260,11 @@ label); } +void DataUseTabModel::OnControlAppInstalled() { + is_control_app_installed_ = true; + data_use_matcher_->FetchMatchingRules(); +} + base::TimeTicks DataUseTabModel::NowTicks() const { DCHECK(thread_checker_.CalledOnValidThread()); return tick_clock_->NowTicks();
diff --git a/chrome/browser/android/data_usage/data_use_tab_model.h b/chrome/browser/android/data_usage/data_use_tab_model.h index de3314c..d5f82822 100644 --- a/chrome/browser/android/data_usage/data_use_tab_model.h +++ b/chrome/browser/android/data_usage/data_use_tab_model.h
@@ -140,6 +140,9 @@ const std::vector<std::string>& domain_path_regex, const std::vector<std::string>& label); + // Notifies the DataUseTabModel that the external control app is installed. + void OnControlAppInstalled(); + // Returns the maximum number of tracking sessions to maintain per tab. size_t max_sessions_per_tab() const { return max_sessions_per_tab_; } @@ -179,6 +182,8 @@ FRIEND_TEST_ALL_PREFIXES(DataUseTabModelTest, TabCloseEventEndsTracking); FRIEND_TEST_ALL_PREFIXES(DataUseTabModelTest, UnexpiredTabEntryRemovaltimeHistogram); + FRIEND_TEST_ALL_PREFIXES(ExternalDataUseObserverTest, + MatchingRuleFetchOnControlAppInstall); typedef base::hash_map<SessionID::id_type, TabDataUseEntry> TabEntryMap; @@ -238,6 +243,9 @@ // Stores the matching patterns. scoped_ptr<DataUseMatcher> data_use_matcher_; + // True if the external control app is installed. + bool is_control_app_installed_; + base::ThreadChecker thread_checker_; base::WeakPtrFactory<DataUseTabModel> weak_factory_;
diff --git a/chrome/browser/android/data_usage/external_data_use_observer.cc b/chrome/browser/android/data_usage/external_data_use_observer.cc index d019adc..94e9e06 100644 --- a/chrome/browser/android/data_usage/external_data_use_observer.cc +++ b/chrome/browser/android/data_usage/external_data_use_observer.cc
@@ -232,15 +232,7 @@ // |fetch_matching_rules_duration_|, fetch them again. if (now_ticks - last_matching_rules_fetch_time_ >= fetch_matching_rules_duration_) { - last_matching_rules_fetch_time_ = now_ticks; - - // It is okay to use base::Unretained here since - // |external_data_use_observer_bridge_| is owned by |this|, and is destroyed - // on UI thread when |this| is destroyed. - ui_task_runner_->PostTask( - FROM_HERE, - base::Bind(&ExternalDataUseObserverBridge::FetchMatchingRules, - base::Unretained(external_data_use_observer_bridge_))); + FetchMatchingRules(); } scoped_ptr<std::string> label(new std::string()); @@ -272,6 +264,20 @@ registered_as_data_use_observer_ = should_register; } +void ExternalDataUseObserver::FetchMatchingRules() { + DCHECK(thread_checker_.CalledOnValidThread()); + + last_matching_rules_fetch_time_ = base::TimeTicks::Now(); + + // It is okay to use base::Unretained here since + // |external_data_use_observer_bridge_| is owned by |this|, and is destroyed + // on UI thread when |this| is destroyed. + ui_task_runner_->PostTask( + FROM_HERE, + base::Bind(&ExternalDataUseObserverBridge::FetchMatchingRules, + base::Unretained(external_data_use_observer_bridge_))); +} + void ExternalDataUseObserver::DataUseLabelApplied( const data_usage::DataUse& data_use, const base::Time& start_time,
diff --git a/chrome/browser/android/data_usage/external_data_use_observer.h b/chrome/browser/android/data_usage/external_data_use_observer.h index 0e15f181..ec9c92b 100644 --- a/chrome/browser/android/data_usage/external_data_use_observer.h +++ b/chrome/browser/android/data_usage/external_data_use_observer.h
@@ -86,6 +86,9 @@ // register as a data use observer. void ShouldRegisterAsDataUseObserver(bool should_register); + // Fetches the matching rules asynchronously. + void FetchMatchingRules(); + base::WeakPtr<ExternalDataUseObserver> GetWeakPtr(); private: @@ -99,6 +102,8 @@ DataUseReportingOnApplicationStatusChange); #endif FRIEND_TEST_ALL_PREFIXES(ExternalDataUseObserverTest, HashFunction); + FRIEND_TEST_ALL_PREFIXES(ExternalDataUseObserverTest, + MatchingRuleFetchOnControlAppInstall); FRIEND_TEST_ALL_PREFIXES(ExternalDataUseObserverTest, MultipleMatchingRules); FRIEND_TEST_ALL_PREFIXES(ExternalDataUseObserverTest, PeriodicFetchMatchingRules);
diff --git a/chrome/browser/android/data_usage/external_data_use_observer_bridge.cc b/chrome/browser/android/data_usage/external_data_use_observer_bridge.cc index 28271a53..71ad96c 100644 --- a/chrome/browser/android/data_usage/external_data_use_observer_bridge.cc +++ b/chrome/browser/android/data_usage/external_data_use_observer_bridge.cc
@@ -9,15 +9,29 @@ #include "base/android/context_utils.h" #include "base/android/jni_string.h" #include "base/memory/scoped_ptr.h" +#include "base/metrics/field_trial.h" #include "base/single_thread_task_runner.h" #include "base/time/time.h" #include "chrome/browser/android/data_usage/data_use_tab_model.h" #include "chrome/browser/android/data_usage/external_data_use_observer.h" +#include "components/variations/variations_associated_data.h" #include "content/public/browser/browser_thread.h" #include "jni/ExternalDataUseObserver_jni.h" using base::android::ConvertUTF8ToJavaString; +namespace { + +// Returns the package name of the control app from the field trial. +const std::string GetControlAppPackageName() { + return variations::GetVariationParamValue( + chrome::android::ExternalDataUseObserver:: + kExternalDataUseObserverFieldTrial, + "control_app_package_name"); +} + +} // namespace + namespace chrome { namespace android { @@ -61,6 +75,9 @@ reinterpret_cast<intptr_t>(this))); DCHECK(!j_external_data_use_observer_.is_null()); + Java_ExternalDataUseObserver_setControlAppPackageName( + env, j_external_data_use_observer_.obj(), + ConvertUTF8ToJavaString(env, GetControlAppPackageName()).obj()); FetchMatchingRules(); } @@ -141,6 +158,12 @@ external_data_use_observer_, success)); } +void ExternalDataUseObserverBridge::OnControlAppInstalled(JNIEnv* env, + jobject obj) const { + DCHECK(thread_checker_.CalledOnValidThread()); + data_use_tab_model_->OnControlAppInstalled(); +} + bool RegisterExternalDataUseObserver(JNIEnv* env) { return RegisterNativesImpl(env); }
diff --git a/chrome/browser/android/data_usage/external_data_use_observer_bridge.h b/chrome/browser/android/data_usage/external_data_use_observer_bridge.h index b7e1f53..2727c407 100644 --- a/chrome/browser/android/data_usage/external_data_use_observer_bridge.h +++ b/chrome/browser/android/data_usage/external_data_use_observer_bridge.h
@@ -85,6 +85,10 @@ const base::android::JavaParamRef<jobject>& obj, bool success); + // Notifies the ExternalDataUseObserverBridge that the external control app + // is installed. + void OnControlAppInstalled(JNIEnv* env, jobject obj) const; + private: // Java listener that provides regular expressions to |this|. Data use // reports are submitted to |j_external_data_use_observer_|.
diff --git a/chrome/browser/android/data_usage/external_data_use_observer_unittest.cc b/chrome/browser/android/data_usage/external_data_use_observer_unittest.cc index 6c2405f7..f13fb58f 100644 --- a/chrome/browser/android/data_usage/external_data_use_observer_unittest.cc +++ b/chrome/browser/android/data_usage/external_data_use_observer_unittest.cc
@@ -375,6 +375,47 @@ external_data_use_observer()->fetch_matching_rules_duration_); } +// Tests the matching rule fetch behavior when the external control app is +// installed and not installed. If control app is installed and no valid rules +// are found, matching rules are fetched on every navigation. Rules are not +// fetched if control app is not installed or if more than zero valid rules +// have been fetched. +TEST_F(ExternalDataUseObserverTest, MatchingRuleFetchOnControlAppInstall) { + // Matching rules not fetched on navigation if control app is not installed. + external_data_use_observer()->last_matching_rules_fetch_time_ = + base::TimeTicks(); + EXPECT_FALSE(external_data_use_observer() + ->data_use_tab_model_->is_control_app_installed_); + external_data_use_observer()->data_use_tab_model_->OnNavigationEvent( + kDefaultTabId, DataUseTabModel::TRANSITION_LINK, GURL(kDefaultURL), + std::string()); + EXPECT_TRUE( + external_data_use_observer()->last_matching_rules_fetch_time_.is_null()); + + // Matching rules fetched on every navigation if control app is installed and + // zero rules are available. + external_data_use_observer()->data_use_tab_model_->OnControlAppInstalled(); + external_data_use_observer()->data_use_tab_model_->OnNavigationEvent( + kDefaultTabId, DataUseTabModel::TRANSITION_LINK, GURL(kDefaultURL), + std::string()); + base::RunLoop().RunUntilIdle(); + EXPECT_FALSE( + external_data_use_observer()->last_matching_rules_fetch_time_.is_null()); + + // Matching rules not fetched on navigation if control app is installed and + // more than zero rules are available. + AddDefaultMatchingRule(); + external_data_use_observer()->last_matching_rules_fetch_time_ = + base::TimeTicks(); + EXPECT_TRUE( + external_data_use_observer()->last_matching_rules_fetch_time_.is_null()); + external_data_use_observer()->data_use_tab_model_->OnNavigationEvent( + kDefaultTabId, DataUseTabModel::TRANSITION_LINK, GURL(kDefaultURL), + std::string()); + EXPECT_TRUE( + external_data_use_observer()->last_matching_rules_fetch_time_.is_null()); +} + // Tests if data use reports are sent only after the total bytes sent/received // across all buffered reports have reached the specified threshold. TEST_F(ExternalDataUseObserverTest, BufferDataUseReports) {
diff --git a/chrome/browser/android/feedback/screenshot_task.cc b/chrome/browser/android/feedback/screenshot_task.cc index 519058a..824969c0 100644 --- a/chrome/browser/android/feedback/screenshot_task.cc +++ b/chrome/browser/android/feedback/screenshot_task.cc
@@ -33,7 +33,7 @@ base::android::ScopedJavaGlobalRef<jobject>* callback, scoped_refptr<base::RefCountedBytes> png_data) { jbyteArray jbytes = nullptr; - if (!png_data.get()) { + if (png_data.get()) { size_t size = png_data->size(); jbytes = env->NewByteArray(size); env->SetByteArrayRegion(jbytes, 0, size, (jbyte*) png_data->front());
diff --git a/chrome/browser/android/preferences/pref_service_bridge.cc b/chrome/browser/android/preferences/pref_service_bridge.cc index 552afc5..3002ae9c 100644 --- a/chrome/browser/android/preferences/pref_service_bridge.cc +++ b/chrome/browser/android/preferences/pref_service_bridge.cc
@@ -6,6 +6,7 @@ #include <jni.h> #include <stddef.h> +#include <vector> #include "base/android/build_info.h" #include "base/android/jni_android.h" @@ -640,6 +641,13 @@ GetPrefService()->SetBoolean(prefs::kEnableDoNotTrack, allow); } +static ScopedJavaLocalRef<jstring> GetSyncLastAccountId( + JNIEnv* env, + const JavaParamRef<jobject>& obj) { + return ConvertUTF8ToJavaString( + env, GetPrefService()->GetString(prefs::kGoogleServicesLastAccountId)); +} + static ScopedJavaLocalRef<jstring> GetSyncLastAccountName( JNIEnv* env, const JavaParamRef<jobject>& obj) { @@ -954,3 +962,10 @@ return ConvertJavaStringToUTF8(android_permission); } + +static void SetSupervisedUserId(JNIEnv* env, + const JavaParamRef<jobject>& obj, + const JavaParamRef<jstring>& pref) { + GetPrefService()->SetString(prefs::kSupervisedUserId, + ConvertJavaStringToUTF8(env, pref)); +}
diff --git a/chrome/browser/android/resource_id.h b/chrome/browser/android/resource_id.h index e6dfd66..bd741b8 100644 --- a/chrome/browser/android/resource_id.h +++ b/chrome/browser/android/resource_id.h
@@ -18,6 +18,7 @@ LINK_RESOURCE_ID(0, 0) // InfoBar resources. +LINK_RESOURCE_ID(IDR_INFOBAR_3D_BLOCKED, R.drawable.infobar_3d_blocked) LINK_RESOURCE_ID(IDR_INFOBAR_AUTOFILL_CC, R.drawable.infobar_autofill_cc) LINK_RESOURCE_ID(IDR_INFOBAR_MEDIA_STREAM_CAMERA, R.drawable.infobar_camera) LINK_RESOURCE_ID(IDR_INFOBAR_MEDIA_STREAM_MIC, R.drawable.infobar_microphone)
diff --git a/chrome/browser/android/signin/signin_manager_android.cc b/chrome/browser/android/signin/signin_manager_android.cc index bab368d..7d3ea29 100644 --- a/chrome/browser/android/signin/signin_manager_android.cc +++ b/chrome/browser/android/signin/signin_manager_android.cc
@@ -16,7 +16,6 @@ #include "base/prefs/pref_service.h" #include "base/single_thread_task_runner.h" #include "base/thread_task_runner_handle.h" -#include "base/thread_task_runner_handle.h" #include "chrome/browser/bookmarks/bookmark_model_factory.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/browsing_data/browsing_data_helper.h" @@ -248,6 +247,7 @@ } void SigninManagerAndroid::ClearLastSignedInUser() { + profile_->GetPrefs()->ClearPref(prefs::kGoogleServicesLastAccountId); profile_->GetPrefs()->ClearPref(prefs::kGoogleServicesLastUsername); }
diff --git a/chrome/browser/apps/app_shim/OWNERS b/chrome/browser/apps/app_shim/OWNERS index 7f10d7c..fff9c34f 100644 --- a/chrome/browser/apps/app_shim/OWNERS +++ b/chrome/browser/apps/app_shim/OWNERS
@@ -1,2 +1,2 @@ +dominickn@chromium.org tapted@chromium.org -jackhou@chromium.org
diff --git a/chrome/browser/apps/app_shim/app_shim_interactive_uitest_mac.mm b/chrome/browser/apps/app_shim/app_shim_interactive_uitest_mac.mm index 1249e262..a8b0ee5 100644 --- a/chrome/browser/apps/app_shim/app_shim_interactive_uitest_mac.mm +++ b/chrome/browser/apps/app_shim/app_shim_interactive_uitest_mac.mm
@@ -8,8 +8,6 @@ #include "apps/app_lifetime_monitor_factory.h" #include "apps/switches.h" #include "base/auto_reset.h" -#include "base/callback.h" -#include "base/files/file_path_watcher.h" #include "base/mac/foundation_util.h" #include "base/mac/launch_services_util.h" #include "base/mac/mac_util.h" @@ -45,14 +43,25 @@ // General end-to-end test for app shims. class AppShimInteractiveTest : public extensions::PlatformAppBrowserTest { protected: + // Type of app to install, when invoking InstallAppWithShim(). + enum AppType { APP_TYPE_PACKAGED, APP_TYPE_HOSTED }; + AppShimInteractiveTest() : auto_reset_(&g_app_shims_allow_update_and_launch_in_tests, true) {} + // Install a test app of |type| and reliably wait for its app shim to be + // created on disk. Sets |shim_path_|. + const extensions::Extension* InstallAppWithShim(AppType type, + const char* name); + void SetUpCommandLine(base::CommandLine* command_line) override { PlatformAppBrowserTest::SetUpCommandLine(command_line); command_line->AppendSwitch(switches::kEnableNewBookmarkApps); } + protected: + base::FilePath shim_path_; + private: // Temporarily enable app shims. base::AutoReset<bool> auto_reset_; @@ -60,64 +69,6 @@ DISALLOW_COPY_AND_ASSIGN(AppShimInteractiveTest); }; -// Watches for changes to a file. This is designed to be used from the the UI -// thread. -class WindowedFilePathWatcher - : public base::RefCountedThreadSafe<WindowedFilePathWatcher> { - public: - WindowedFilePathWatcher(const base::FilePath& path) - : path_(path), observed_(false) { - content::BrowserThread::PostTask( - content::BrowserThread::FILE, - FROM_HERE, - base::Bind(&WindowedFilePathWatcher::Watch, this)); - } - - void Wait() { - if (observed_) - return; - - run_loop_.reset(new base::RunLoop); - run_loop_->Run(); - } - - protected: - friend class base::RefCountedThreadSafe<WindowedFilePathWatcher>; - virtual ~WindowedFilePathWatcher() {} - - void Watch() { - watcher_.reset(new base::FilePathWatcher); - watcher_->Watch(path_.DirName(), - false, - base::Bind(&WindowedFilePathWatcher::Observe, this)); - } - - void Observe(const base::FilePath& path, bool error) { - DCHECK(!error); - if (base::PathExists(path_)) { - watcher_.reset(); - content::BrowserThread::PostTask( - content::BrowserThread::UI, - FROM_HERE, - base::Bind(&WindowedFilePathWatcher::StopRunLoop, this)); - } - } - - void StopRunLoop() { - observed_ = true; - if (run_loop_.get()) - run_loop_->Quit(); - } - - private: - const base::FilePath path_; - scoped_ptr<base::FilePathWatcher> watcher_; - bool observed_; - scoped_ptr<base::RunLoop> run_loop_; - - DISALLOW_COPY_AND_ASSIGN(WindowedFilePathWatcher); -}; - // Watches for an app shim to connect. class WindowedAppShimLaunchObserver : public apps::AppShimHandler { public: @@ -276,20 +227,6 @@ return shortcut_creator.GetInternalShortcutPath(); } -void UpdateAppAndAwaitShimCreation(Profile* profile, - const extensions::Extension* app, - const base::FilePath& shim_path) { - // Create the internal app shim by simulating an app update. FilePathWatcher - // is used to wait for file operations on the shim to be finished before - // attempting to launch it. Since all of the file operations are done in the - // same event on the FILE thread, everything will be done by the time the - // watcher's callback is executed. - scoped_refptr<WindowedFilePathWatcher> file_watcher = - new WindowedFilePathWatcher(shim_path); - web_app::UpdateAllShortcuts(base::string16(), profile, app); - file_watcher->Wait(); -} - Browser* GetFirstHostedAppWindow() { BrowserList* browsers = BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_NATIVE); @@ -302,6 +239,36 @@ return nullptr; } +const extensions::Extension* AppShimInteractiveTest::InstallAppWithShim( + AppType type, + const char* name) { + + const extensions::Extension* app; + switch (type) { + case APP_TYPE_PACKAGED: + app = InstallPlatformApp(name); + break; + case APP_TYPE_HOSTED: + app = InstallHostedApp(); + break; + } + + // Note that usually an install triggers shim creation, but that's disabled + // (always) in tests. If it wasn't the case, the following test would fail + // (but flakily since the creation happens on the FILE thread). + shim_path_ = GetAppShimPath(profile(), app); + EXPECT_FALSE(base::PathExists(shim_path_)); + + // To create a shim in a test, instead call UpdateAllShortcuts, which has been + // blessed by g_app_shims_allow_update_and_launch_in_tests. + base::RunLoop run_loop; + web_app::UpdateAllShortcuts(base::string16(), profile(), app, + run_loop.QuitClosure()); + run_loop.Run(); + EXPECT_TRUE(base::PathExists(shim_path_)); + return app; +} + } // namespace namespace apps { @@ -323,14 +290,8 @@ #endif IN_PROC_BROWSER_TEST_F(AppShimInteractiveTest, MAYBE_HostedAppLaunch) { - const extensions::Extension* app = InstallHostedApp(); - - base::FilePath shim_path = GetAppShimPath(profile(), app); - EXPECT_FALSE(base::PathExists(shim_path)); - - UpdateAppAndAwaitShimCreation(profile(), app, shim_path); - ASSERT_TRUE(base::PathExists(shim_path)); - NSString* bundle_id = GetBundleID(shim_path); + const extensions::Extension* app = InstallAppWithShim(APP_TYPE_HOSTED, ""); + NSString* bundle_id = GetBundleID(shim_path_); // Explicitly set the launch type to open in a new window. extensions::SetLaunchType(profile(), app->id(), @@ -344,7 +305,7 @@ bundleId:bundle_id]); WindowedAppShimLaunchObserver observer(app->id()); LaunchHostedApp(app); - [ns_observer wait]; + EXPECT_TRUE([ns_observer wait]); observer.Wait(); EXPECT_TRUE(HasAppShimHost(profile(), app->id())); @@ -360,7 +321,7 @@ bundleId:bundle_id]); [base::mac::ObjCCastStrict<NSRunningApplication>( [running_shim objectAtIndex:0]) terminate]; - [ns_observer wait]; + EXPECT_TRUE([ns_observer wait]); EXPECT_FALSE(GetFirstHostedAppWindow()); EXPECT_FALSE(HasAppShimHost(profile(), app->id())); @@ -373,7 +334,7 @@ shim_cmdline.AppendSwitch(app_mode::kLaunchedForTest); ProcessSerialNumber shim_psn; ASSERT_TRUE(base::mac::OpenApplicationWithPath( - shim_path, shim_cmdline, kLSLaunchDefaults, &shim_psn)); + shim_path_, shim_cmdline, kLSLaunchDefaults, &shim_psn)); listener.WaitUntilAdded(); ASSERT_TRUE(GetFirstHostedAppWindow()); @@ -399,14 +360,9 @@ // These two cases are combined because the time to run the test is dominated // by loading the extension and creating the shim. IN_PROC_BROWSER_TEST_F(AppShimInteractiveTest, MAYBE_Launch) { - const extensions::Extension* app = InstallPlatformApp("minimal"); - - base::FilePath shim_path = GetAppShimPath(profile(), app); - EXPECT_FALSE(base::PathExists(shim_path)); - - UpdateAppAndAwaitShimCreation(profile(), app, shim_path); - ASSERT_TRUE(base::PathExists(shim_path)); - NSString* bundle_id = GetBundleID(shim_path); + const extensions::Extension* app = + InstallAppWithShim(APP_TYPE_PACKAGED, "minimal"); + NSString* bundle_id = GetBundleID(shim_path_); // Case 1: Launch the app, it should start the shim. { @@ -416,7 +372,7 @@ bundleId:bundle_id]); WindowedAppShimLaunchObserver observer(app->id()); LaunchPlatformApp(app); - [ns_observer wait]; + EXPECT_TRUE([ns_observer wait]); observer.Wait(); EXPECT_TRUE(GetFirstAppWindow()); @@ -437,7 +393,7 @@ bundleId:bundle_id]); [base::mac::ObjCCastStrict<NSRunningApplication>( [running_shim objectAtIndex:0]) terminate]; - [ns_observer wait]; + EXPECT_TRUE([ns_observer wait]); EXPECT_FALSE(GetFirstAppWindow()); EXPECT_FALSE(HasAppShimHost(profile(), app->id())); @@ -450,7 +406,7 @@ shim_cmdline.AppendSwitch(app_mode::kLaunchedForTest); ProcessSerialNumber shim_psn; ASSERT_TRUE(base::mac::OpenApplicationWithPath( - shim_path, shim_cmdline, kLSLaunchDefaults, &shim_psn)); + shim_path_, shim_cmdline, kLSLaunchDefaults, &shim_psn)); ASSERT_TRUE(launched_listener.WaitUntilSatisfied()); ASSERT_TRUE(GetFirstAppWindow()); @@ -473,14 +429,9 @@ // Test that the shim's lifetime depends on the visibility of windows. I.e. the // shim is only active when there are visible windows. IN_PROC_BROWSER_TEST_F(AppShimInteractiveTest, MAYBE_ShowWindow) { - const extensions::Extension* app = InstallPlatformApp("hidden"); - - base::FilePath shim_path = GetAppShimPath(profile(), app); - EXPECT_FALSE(base::PathExists(shim_path)); - - UpdateAppAndAwaitShimCreation(profile(), app, shim_path); - ASSERT_TRUE(base::PathExists(shim_path)); - NSString* bundle_id = GetBundleID(shim_path); + const extensions::Extension* app = + InstallAppWithShim(APP_TYPE_PACKAGED, "hidden"); + NSString* bundle_id = GetBundleID(shim_path_); // It's impractical to confirm that the shim did not launch by timing out, so // instead we watch AppLifetimeMonitor::Observer::OnAppActivated. @@ -507,7 +458,7 @@ bundleId:bundle_id]); WindowedAppShimLaunchObserver observer(app->id()); window_1->Show(extensions::AppWindow::SHOW_INACTIVE); - [ns_observer wait]; + EXPECT_TRUE([ns_observer wait]); observer.Wait(); EXPECT_EQ(1, lifetime_observer.activated_count()); EXPECT_TRUE(HasAppShimHost(profile(), app->id())); @@ -521,7 +472,7 @@ NSWorkspaceDidTerminateApplicationNotification bundleId:bundle_id]); window_1->Hide(); - [ns_observer wait]; + EXPECT_TRUE([ns_observer wait]); EXPECT_FALSE(HasAppShimHost(profile(), app->id())); } @@ -549,7 +500,7 @@ bundleId:bundle_id]); WindowedAppShimLaunchObserver observer(app->id()); window_1->Show(extensions::AppWindow::SHOW_INACTIVE); - [ns_observer wait]; + EXPECT_TRUE([ns_observer wait]); observer.Wait(); EXPECT_EQ(2, lifetime_observer.activated_count()); EXPECT_TRUE(HasAppShimHost(profile(), app->id())); @@ -585,7 +536,7 @@ NSWorkspaceDidTerminateApplicationNotification bundleId:bundle_id]); window_2->Hide(); - [ns_observer wait]; + EXPECT_TRUE([ns_observer wait]); EXPECT_EQ(1, deactivate_observer.deactivated_count()); EXPECT_FALSE(HasAppShimHost(profile(), app->id())); }
diff --git a/chrome/browser/apps/shortcut_manager.cc b/chrome/browser/apps/shortcut_manager.cc index af9c906..5032615 100644 --- a/chrome/browser/apps/shortcut_manager.cc +++ b/chrome/browser/apps/shortcut_manager.cc
@@ -119,8 +119,8 @@ // create new ones. If it is being installed, automatically create a // shortcut in the applications menu (e.g., Start Menu). if (is_update) { - web_app::UpdateAllShortcuts( - base::UTF8ToUTF16(old_name), profile_, extension); + web_app::UpdateAllShortcuts(base::UTF8ToUTF16(old_name), profile_, + extension, base::Closure()); } else { CreateShortcutsForApp(profile_, extension); }
diff --git a/chrome/browser/autocomplete/chrome_autocomplete_provider_client.cc b/chrome/browser/autocomplete/chrome_autocomplete_provider_client.cc index 6c71857..156a3e52 100644 --- a/chrome/browser/autocomplete/chrome_autocomplete_provider_client.cc +++ b/chrome/browser/autocomplete/chrome_autocomplete_provider_client.cc
@@ -24,7 +24,6 @@ #include "chrome/browser/sync/profile_sync_service_factory.h" #include "chrome/common/pref_names.h" #include "chrome/common/url_constants.h" -#include "components/bookmarks/common/bookmark_pref_names.h" #include "components/browser_sync/browser/profile_sync_service.h" #include "components/history/core/browser/history_service.h" #include "components/omnibox/browser/autocomplete_classifier.h" @@ -204,10 +203,6 @@ return profile_->GetPrefs()->GetBoolean(prefs::kSearchSuggestEnabled); } -bool ChromeAutocompleteProviderClient::BookmarkBarIsVisible() const { - return profile_->GetPrefs()->GetBoolean(bookmarks::prefs::kShowBookmarkBar); -} - bool ChromeAutocompleteProviderClient::TabSyncEnabledAndUnencrypted() const { return sync_driver::IsTabSyncEnabledAndUnencrypted( ProfileSyncServiceFactory::GetInstance()->GetForProfile(profile_),
diff --git a/chrome/browser/autocomplete/chrome_autocomplete_provider_client.h b/chrome/browser/autocomplete/chrome_autocomplete_provider_client.h index e7b85a4..1c97706 100644 --- a/chrome/browser/autocomplete/chrome_autocomplete_provider_client.h +++ b/chrome/browser/autocomplete/chrome_autocomplete_provider_client.h
@@ -40,7 +40,6 @@ std::vector<base::string16> GetBuiltinsToProvideAsUserTypes() override; bool IsOffTheRecord() const override; bool SearchSuggestEnabled() const override; - bool BookmarkBarIsVisible() const override; bool TabSyncEnabledAndUnencrypted() const override; void Classify( const base::string16& text,
diff --git a/chrome/browser/autocomplete/search_provider_unittest.cc b/chrome/browser/autocomplete/search_provider_unittest.cc index ca5a6db9..256c1366 100644 --- a/chrome/browser/autocomplete/search_provider_unittest.cc +++ b/chrome/browser/autocomplete/search_provider_unittest.cc
@@ -31,7 +31,6 @@ #include "chrome/common/pref_names.h" #include "chrome/test/base/testing_browser_process.h" #include "chrome/test/base/testing_profile.h" -#include "components/bookmarks/common/bookmark_pref_names.h" #include "components/browser_sync/browser/profile_sync_service.h" #include "components/google/core/browser/google_switches.h" #include "components/history/core/browser/history_service.h" @@ -3229,26 +3228,6 @@ } } -TEST_F(SearchProviderTest, ReflectsBookmarkBarState) { - profile_.GetPrefs()->SetBoolean(bookmarks::prefs::kShowBookmarkBar, false); - base::string16 term = term1_.substr(0, term1_.length() - 1); - QueryForInput(term, true, false); - ASSERT_FALSE(provider_->matches().empty()); - EXPECT_EQ(AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, - provider_->matches()[0].type); - ASSERT_TRUE(provider_->matches()[0].search_terms_args != NULL); - EXPECT_FALSE(provider_->matches()[0].search_terms_args->bookmark_bar_pinned); - - profile_.GetPrefs()->SetBoolean(bookmarks::prefs::kShowBookmarkBar, true); - term = term1_.substr(0, term1_.length() - 1); - QueryForInput(term, true, false); - ASSERT_FALSE(provider_->matches().empty()); - EXPECT_EQ(AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, - provider_->matches()[0].type); - ASSERT_TRUE(provider_->matches()[0].search_terms_args != NULL); - EXPECT_TRUE(provider_->matches()[0].search_terms_args->bookmark_bar_pinned); -} - TEST_F(SearchProviderTest, CanSendURL) { TemplateURLData template_url_data; template_url_data.SetShortName(ASCIIToUTF16("t"));
diff --git a/chrome/browser/banners/app_banner_data_fetcher.cc b/chrome/browser/banners/app_banner_data_fetcher.cc index 0090d10..321e8d3e 100644 --- a/chrome/browser/banners/app_banner_data_fetcher.cc +++ b/chrome/browser/banners/app_banner_data_fetcher.cc
@@ -188,6 +188,9 @@ return; } + AppBannerSettingsHelper::RecordMinutesFromFirstVisitToShow( + web_contents, validated_url_, GetAppIdentifier(), GetCurrentTime()); + // Definitely going to show the banner now. FOR_EACH_OBSERVER(Observer, observer_list_, OnDecidedWhetherToShow(this, true));
diff --git a/chrome/browser/banners/app_banner_data_fetcher_browsertest.cc b/chrome/browser/banners/app_banner_data_fetcher_browsertest.cc index b37df5f..c868268 100644 --- a/chrome/browser/banners/app_banner_data_fetcher_browsertest.cc +++ b/chrome/browser/banners/app_banner_data_fetcher_browsertest.cc
@@ -9,8 +9,10 @@ #include "base/run_loop.h" #include "base/single_thread_task_runner.h" #include "base/task_runner.h" +#include "base/test/histogram_tester.h" #include "base/thread_task_runner_handle.h" #include "chrome/browser/banners/app_banner_data_fetcher_desktop.h" +#include "chrome/browser/banners/app_banner_metrics.h" #include "chrome/browser/banners/app_banner_settings_helper.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" @@ -97,6 +99,7 @@ weak_factory_.GetWeakPtr(), 128, 128)); + base::HistogramTester histograms; base::RunLoop run_loop; quit_closure_ = run_loop.QuitClosure(); scoped_ptr<TestObserver> observer(new TestObserver(fetcher.get(), @@ -107,6 +110,10 @@ EXPECT_EQ(expected_non_web_platform, non_web_platform_); EXPECT_EQ(expected_to_show, observer->will_show()); ASSERT_FALSE(fetcher->is_active()); + + // If showing the banner, ensure that the minutes histogram is recorded. + histograms.ExpectTotalCount(banners::kMinutesHistogram, + (observer->will_show() ? 1 : 0)); } void RunBannerTest(const std::string& manifest_page,
diff --git a/chrome/browser/banners/app_banner_metrics.cc b/chrome/browser/banners/app_banner_metrics.cc index 5ab6f59a..f9bbd34 100644 --- a/chrome/browser/banners/app_banner_metrics.cc +++ b/chrome/browser/banners/app_banner_metrics.cc
@@ -4,32 +4,48 @@ #include "chrome/browser/banners/app_banner_metrics.h" +#include "base/metrics/histogram_macros.h" #include "base/metrics/sparse_histogram.h" namespace banners { +const char kDismissEventHistogram[] = "AppBanners.DismissEvent"; +const char kDisplayEventHistogram[] = "AppBanners.DisplayEvent"; +const char kInstallEventHistogram[] = "AppBanners.InstallEvent"; +const char kMinutesHistogram[] = + "AppBanners.MinutesFromFirstVisitToBannerShown"; +const char kUserResponseHistogram[] = "AppBanners.UserResponse"; + void TrackDismissEvent(int event) { DCHECK_LT(DISMISS_EVENT_MIN, event); DCHECK_LT(event, DISMISS_EVENT_MAX); - UMA_HISTOGRAM_SPARSE_SLOWLY("AppBanners.DismissEvent", event); + UMA_HISTOGRAM_SPARSE_SLOWLY(kDismissEventHistogram, event); } void TrackDisplayEvent(int event) { DCHECK_LT(DISPLAY_EVENT_MIN, event); DCHECK_LT(event, DISPLAY_EVENT_MAX); - UMA_HISTOGRAM_SPARSE_SLOWLY("AppBanners.DisplayEvent", event); + UMA_HISTOGRAM_SPARSE_SLOWLY(kDisplayEventHistogram, event); } void TrackInstallEvent(int event) { DCHECK_LT(INSTALL_EVENT_MIN, event); DCHECK_LT(event, INSTALL_EVENT_MAX); - UMA_HISTOGRAM_SPARSE_SLOWLY("AppBanners.InstallEvent", event); + UMA_HISTOGRAM_SPARSE_SLOWLY(kInstallEventHistogram, event); +} + +void TrackMinutesFromFirstVisitToBannerShown(int minutes) { + // Histogram ranges from 1 minute to the number of minutes in 21 days. + // This is one more day than the decay length of time for site engagement, + // and seven more days than the expiry of visits for the app banner + // navigation heuristic. + UMA_HISTOGRAM_CUSTOM_COUNTS(kMinutesHistogram, minutes, 1, 30240, 100); } void TrackUserResponse(int event) { DCHECK_LT(USER_RESPONSE_MIN, event); DCHECK_LT(event, USER_RESPONSE_MAX); - UMA_HISTOGRAM_SPARSE_SLOWLY("AppBanners.UserResponse", event); + UMA_HISTOGRAM_SPARSE_SLOWLY(kUserResponseHistogram, event); } } // namespace banners
diff --git a/chrome/browser/banners/app_banner_metrics.h b/chrome/browser/banners/app_banner_metrics.h index 7c781792..8b96d8c8 100644 --- a/chrome/browser/banners/app_banner_metrics.h +++ b/chrome/browser/banners/app_banner_metrics.h
@@ -57,12 +57,18 @@ USER_RESPONSE_MAX = 7, }; +extern const char kDismissEventHistogram[]; +extern const char kDisplayEventHistogram[]; +extern const char kInstallEventHistogram[]; +extern const char kMinutesHistogram[]; +extern const char kUserResponseHistogram[]; + void TrackDismissEvent(int event); void TrackDisplayEvent(int event); void TrackInstallEvent(int event); +void TrackMinutesFromFirstVisitToBannerShown(int minutes); void TrackUserResponse(int event); }; // namespace banners #endif // CHROME_BROWSER_BANNERS_APP_BANNER_METRICS_H_ -
diff --git a/chrome/browser/banners/app_banner_settings_helper.cc b/chrome/browser/banners/app_banner_settings_helper.cc index 5e456b7..824ff63 100644 --- a/chrome/browser/banners/app_banner_settings_helper.cc +++ b/chrome/browser/banners/app_banner_settings_helper.cc
@@ -10,11 +10,14 @@ #include <utility> #include "base/command_line.h" +#include "base/metrics/field_trial.h" #include "base/strings/string_number_conversions.h" +#include "base/strings/string_util.h" #include "chrome/browser/banners/app_banner_data_fetcher.h" #include "chrome/browser/banners/app_banner_metrics.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/content_settings/host_content_settings_map_factory.h" +#include "chrome/browser/engagement/site_engagement_service.h" #include "chrome/browser/profiles/profile.h" #include "chrome/common/chrome_switches.h" #include "components/content_settings/core/browser/host_content_settings_map.h" @@ -39,14 +42,17 @@ const unsigned int kNumberOfMinutesInADay = 1440; -// Number of minutes between visits that will trigger a could show banner event. -// Defaults to the number of minutes in a day. -unsigned int gMinimumMinutesBetweenVisits = kNumberOfMinutesInADay; - // Number of days that the banner being blocked will prevent it being seen again // for. const unsigned int kMinimumBannerBlockedToBannerShown = 90; +// Default scores assigned to direct and indirect navigations respectively. +const unsigned int kDefaultDirectNavigationEngagement = 1; +const unsigned int kDefaultIndirectNavigationEngagement = 1; + +// Default number of navigations required to trigger the banner. +const unsigned int kDefaultTotalEngagementToTrigger = 2; + // Dictionary keys to use for the events. const char* kBannerEventKeys[] = { "couldShowBannerEvents", @@ -65,16 +71,22 @@ const char kBannerParamsIndirectKey[] = "indirect"; const char kBannerParamsTotalKey[] = "total"; const char kBannerParamsMinutesKey[] = "minutes"; - -// Total site engagements where a banner could have been shown before -// a banner will actually be triggered. -double gTotalEngagementToTrigger = 2; +const char kBannerSiteEngagementParamsKey[] = "app_banner_triggering"; +const char kBannerSiteEngagementParamsTotalKey[] = + "app_banner_triggering_total"; // Engagement weight assigned to direct and indirect navigations. // By default, a direct navigation is a page visit via ui::PAGE_TRANSITION_TYPED // or ui::PAGE_TRANSITION_GENERATED. -double gDirectNavigationEngagement = 1; -double gIndirectNavigationEnagagement = 1; +double gDirectNavigationEngagement = kDefaultDirectNavigationEngagement; +double gIndirectNavigationEnagagement = kDefaultIndirectNavigationEngagement; + +// Number of minutes between visits that will trigger a could show banner event. +// Defaults to the number of minutes in a day. +unsigned int gMinimumMinutesBetweenVisits = kNumberOfMinutesInADay; + +// Total engagement score required before a banner will actually be triggered. +double gTotalEngagementToTrigger = kDefaultTotalEngagementToTrigger; scoped_ptr<base::DictionaryValue> GetOriginDict( HostContentSettingsMap* settings, @@ -117,10 +129,26 @@ } } +// Queries variations for the maximum site engagement score required to trigger +// the banner showing. +void UpdateSiteEngagementToTrigger() { + std::string total_param = variations::GetVariationParamValue( + SiteEngagementService::kEngagementParams, + kBannerSiteEngagementParamsTotalKey); + + if (!total_param.empty()) { + double total_engagement = -1; + + if (base::StringToDouble(total_param, &total_engagement) && + total_engagement > 0) { + AppBannerSettingsHelper::SetTotalEngagementToTrigger(total_engagement); + } + } +} + // Queries variations for updates to the default engagement values assigned // to direct and indirect navigations. void UpdateEngagementWeights() { - std::map<std::string, std::string> params; std::string direct_param = variations::GetVariationParamValue( kBannerParamsKey, kBannerParamsDirectKey); std::string indirect_param = variations::GetVariationParamValue( @@ -162,6 +190,16 @@ } } +// Returns the site engagement karma score for the given origin URL under the +// current profile. +double GetSiteEngagementScoreForOrigin( + content::WebContents* web_contents, + const GURL& origin_url) { + SiteEngagementService* service = SiteEngagementService::Get( + Profile::FromBrowserContext(web_contents->GetBrowserContext())); + return service ? service->GetScore(origin_url) : 0; +} + } // namespace void AppBannerSettingsHelper::ClearHistoryForURLs( @@ -354,6 +392,10 @@ return true; } + // Never show a banner when the package name or URL is empty. + if (package_name_or_start_url.empty()) + return false; + // Don't show if it has been added to the homescreen. base::Time added_time = GetSingleBannerEvent(web_contents, origin_url, package_name_or_start_url, @@ -384,14 +426,17 @@ return false; } - std::vector<BannerEvent> could_show_events = GetCouldShowBannerEvents( - web_contents, origin_url, package_name_or_start_url); - - // Return true if the total engagement of each applicable could show event - // meets the trigger threshold. double total_engagement = 0; - for (const auto& event : could_show_events) - total_engagement += event.engagement; + if (ShouldUseSiteEngagementScore()) { + total_engagement = + GetSiteEngagementScoreForOrigin(web_contents, origin_url); + } else { + std::vector<BannerEvent> could_show_events = GetCouldShowBannerEvents( + web_contents, origin_url, package_name_or_start_url); + + for (const auto& event : could_show_events) + total_engagement += event.engagement; + } if (total_engagement < gTotalEngagementToTrigger) { banners::TrackDisplayEvent(banners::DISPLAY_EVENT_NOT_VISITED_ENOUGH); @@ -407,8 +452,6 @@ const GURL& origin_url, const std::string& package_name_or_start_url) { std::vector<BannerEvent> result; - if (package_name_or_start_url.empty()) - return result; Profile* profile = Profile::FromBrowserContext(web_contents->GetBrowserContext()); @@ -456,9 +499,6 @@ DCHECK(event != APP_BANNER_EVENT_COULD_SHOW); DCHECK(event < APP_BANNER_EVENT_NUM_EVENTS); - if (package_name_or_start_url.empty()) - return base::Time(); - Profile* profile = Profile::FromBrowserContext(web_contents->GetBrowserContext()); HostContentSettingsMap* settings = @@ -482,6 +522,21 @@ return base::Time::FromInternalValue(internal_time); } +void AppBannerSettingsHelper::RecordMinutesFromFirstVisitToShow( + content::WebContents* web_contents, + const GURL& origin_url, + const std::string& package_name_or_start_url, + base::Time time) { + std::vector<BannerEvent> could_show_events = GetCouldShowBannerEvents( + web_contents, origin_url, package_name_or_start_url); + + int minutes = 0; + if (could_show_events.size()) + minutes = (time - could_show_events[0].time).InMinutes(); + + banners::TrackMinutesFromFirstVisitToBannerShown(minutes); +} + void AppBannerSettingsHelper::SetEngagementWeights(double direct_engagement, double indirect_engagement) { gDirectNavigationEngagement = direct_engagement; @@ -498,6 +553,13 @@ gTotalEngagementToTrigger = total_engagement; } +void AppBannerSettingsHelper::SetDefaultParameters() { + SetEngagementWeights(kDefaultDirectNavigationEngagement, + kDefaultIndirectNavigationEngagement); + SetMinimumMinutesBetweenVisits(kNumberOfMinutesInADay); + SetTotalEngagementToTrigger(kDefaultTotalEngagementToTrigger); +} + // Given a time, returns that time scoped to the nearest minute resolution // locally. For example, if the resolution is one hour, this function will // return the time to the closest (previous) hour in the local time zone. @@ -525,6 +587,32 @@ } void AppBannerSettingsHelper::UpdateFromFieldTrial() { - UpdateEngagementWeights(); - UpdateMinutesBetweenVisits(); + // If we are using the site engagement score, only extract the total + // engagement to trigger from the params variations. + if (ShouldUseSiteEngagementScore()) { + UpdateSiteEngagementToTrigger(); + } else { + UpdateEngagementWeights(); + UpdateMinutesBetweenVisits(); + } +} + +bool AppBannerSettingsHelper::ShouldUseSiteEngagementScore() { + if (base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableSiteEngagementAppBanner)) { + return true; + } + + // This experiment is controlled under the same key as the broader site + // engagement experiment rather than the banner experiment. This avoids cross + // pollution with other site engagement experiments. However, this experiment + // must only be active when there is one singular group under the banner + // experiment, otherwise the banner and site engagement banner experiments + // will conflict. + // + // Making the experiment active when a variations key is present allows us + // to have experiments which enable multiple features under site engagement. + std::string param = variations::GetVariationParamValue( + SiteEngagementService::kEngagementParams, kBannerSiteEngagementParamsKey); + return !param.empty(); }
diff --git a/chrome/browser/banners/app_banner_settings_helper.h b/chrome/browser/banners/app_banner_settings_helper.h index 3ff877c0..f1e9ab1 100644 --- a/chrome/browser/banners/app_banner_settings_helper.h +++ b/chrome/browser/banners/app_banner_settings_helper.h
@@ -117,6 +117,14 @@ const std::string& package_name_or_start_url, AppBannerEvent event); + // Record a UMA statistic measuring the minutes between the first visit to the + // site and the first showing of the banner. + static void RecordMinutesFromFirstVisitToShow( + content::WebContents* web_contents, + const GURL& origin_url, + const std::string& package_name_or_start_url, + base::Time time); + // Set the engagement weights assigned to direct and indirect navigations. static void SetEngagementWeights(double direct_engagement, double indirect_engagement); @@ -130,6 +138,10 @@ // Set the total engagement weight required to trigger a banner. static void SetTotalEngagementToTrigger(double total_engagement); + // Resets the engagement weights, minimum minutes, and total engagement to + // trigger to their default values. + static void SetDefaultParameters(); + // Bucket a given time to the given resolution in local time. static base::Time BucketTimeToResolution(base::Time time, unsigned int minutes); @@ -137,6 +149,10 @@ // Updates all values from field trial. static void UpdateFromFieldTrial(); + // Returns true if the app banner trigger condition should use the site + // engagement score instead of the navigation-based heuristic. + static bool ShouldUseSiteEngagementScore(); + private: DISALLOW_IMPLICIT_CONSTRUCTORS(AppBannerSettingsHelper); };
diff --git a/chrome/browser/banners/app_banner_settings_helper_unittest.cc b/chrome/browser/banners/app_banner_settings_helper_unittest.cc index 82550f1..1c8d10b 100644 --- a/chrome/browser/banners/app_banner_settings_helper_unittest.cc +++ b/chrome/browser/banners/app_banner_settings_helper_unittest.cc
@@ -4,8 +4,14 @@ #include <vector> +#include "base/command_line.h" +#include "chrome/browser/banners/app_banner_metrics.h" #include "chrome/browser/banners/app_banner_settings_helper.h" +#include "chrome/browser/engagement/site_engagement_service.h" +#include "chrome/browser/engagement/site_engagement_service_factory.h" +#include "chrome/common/chrome_switches.h" #include "chrome/test/base/chrome_render_view_host_test_harness.h" +#include "chrome/test/base/testing_profile.h" #include "ui/base/page_transition_types.h" namespace { @@ -38,7 +44,14 @@ time2 - time1 < base::TimeDelta::FromHours(1); } -class AppBannerSettingsHelperTest : public ChromeRenderViewHostTestHarness {}; +class AppBannerSettingsHelperTest : public ChromeRenderViewHostTestHarness { + + void SetUp() override { + ChromeRenderViewHostTestHarness::SetUp(); + AppBannerSettingsHelper::SetDefaultParameters(); + } + +}; } // namespace @@ -204,8 +217,6 @@ } TEST_F(AppBannerSettingsHelperTest, CouldShowEvents) { - AppBannerSettingsHelper::SetEngagementWeights(1, 1); - AppBannerSettingsHelper::SetMinimumMinutesBetweenVisits(1440); GURL url(kTestURL); NavigateAndCommit(url); @@ -278,7 +289,6 @@ } TEST_F(AppBannerSettingsHelperTest, CouldShowEventsDifferentResolution) { - AppBannerSettingsHelper::SetEngagementWeights(1, 1); AppBannerSettingsHelper::SetMinimumMinutesBetweenVisits(20); GURL url(kTestURL); NavigateAndCommit(url); @@ -371,8 +381,6 @@ } TEST_F(AppBannerSettingsHelperTest, SingleEvents) { - AppBannerSettingsHelper::SetEngagementWeights(1, 1); - AppBannerSettingsHelper::SetMinimumMinutesBetweenVisits(1440); GURL url(kTestURL); NavigateAndCommit(url); @@ -495,7 +503,6 @@ TEST_F(AppBannerSettingsHelperTest, IndirectEngagementWithLowerWeight) { AppBannerSettingsHelper::SetEngagementWeights(2, 0.5); - AppBannerSettingsHelper::SetMinimumMinutesBetweenVisits(1440); GURL url(kTestURL); NavigateAndCommit(url); @@ -556,8 +563,6 @@ } TEST_F(AppBannerSettingsHelperTest, ShouldShowFromEngagement) { - AppBannerSettingsHelper::SetEngagementWeights(1, 1); - AppBannerSettingsHelper::SetMinimumMinutesBetweenVisits(1440); GURL url(kTestURL); NavigateAndCommit(url); @@ -592,7 +597,6 @@ } TEST_F(AppBannerSettingsHelperTest, ShouldNotShowAfterBlocking) { - AppBannerSettingsHelper::SetEngagementWeights(1, 1); GURL url(kTestURL); NavigateAndCommit(url); @@ -631,8 +635,6 @@ } TEST_F(AppBannerSettingsHelperTest, ShouldNotShowAfterShowing) { - AppBannerSettingsHelper::SetEngagementWeights(1, 1); - AppBannerSettingsHelper::SetMinimumMinutesBetweenVisits(1440); GURL url(kTestURL); NavigateAndCommit(url); @@ -671,8 +673,6 @@ } TEST_F(AppBannerSettingsHelperTest, ShouldNotShowAfterAdding) { - AppBannerSettingsHelper::SetEngagementWeights(1, 1); - AppBannerSettingsHelper::SetMinimumMinutesBetweenVisits(1440); GURL url(kTestURL); NavigateAndCommit(url); @@ -704,7 +704,6 @@ } TEST_F(AppBannerSettingsHelperTest, OperatesOnOrigins) { - AppBannerSettingsHelper::SetEngagementWeights(1, 1); GURL url(kTestURL); NavigateAndCommit(url); @@ -731,3 +730,91 @@ EXPECT_TRUE(AppBannerSettingsHelper::ShouldShowBanner( web_contents(), url, kTestPackageName, reference_time)); } + +TEST_F(AppBannerSettingsHelperTest, ShouldShowWithHigherTotal) { + AppBannerSettingsHelper::SetTotalEngagementToTrigger(5); + GURL url(kTestURL); + NavigateAndCommit(url); + + base::Time reference_time = GetReferenceTime(); + base::Time second_day = reference_time + base::TimeDelta::FromDays(1); + base::Time third_day = reference_time + base::TimeDelta::FromDays(2); + base::Time fourth_day = reference_time + base::TimeDelta::FromDays(3); + base::Time fifth_day = reference_time + base::TimeDelta::FromDays(4); + + EXPECT_FALSE(AppBannerSettingsHelper::ShouldShowBanner( + web_contents(), url, kTestPackageName, reference_time)); + + // It should take five visits to trigger the banner. + AppBannerSettingsHelper::RecordBannerCouldShowEvent( + web_contents(), url, kTestPackageName, reference_time, + ui::PAGE_TRANSITION_LINK); + EXPECT_FALSE(AppBannerSettingsHelper::ShouldShowBanner( + web_contents(), url, kTestPackageName, reference_time)); + + AppBannerSettingsHelper::RecordBannerCouldShowEvent( + web_contents(), url, kTestPackageName, second_day, + ui::PAGE_TRANSITION_TYPED); + EXPECT_FALSE(AppBannerSettingsHelper::ShouldShowBanner( + web_contents(), url, kTestPackageName, second_day)); + + AppBannerSettingsHelper::RecordBannerCouldShowEvent( + web_contents(), url, kTestPackageName, third_day, + ui::PAGE_TRANSITION_GENERATED); + EXPECT_FALSE(AppBannerSettingsHelper::ShouldShowBanner( + web_contents(), url, kTestPackageName, third_day)); + + AppBannerSettingsHelper::RecordBannerCouldShowEvent( + web_contents(), url, kTestPackageName, fourth_day, + ui::PAGE_TRANSITION_LINK); + EXPECT_FALSE(AppBannerSettingsHelper::ShouldShowBanner( + web_contents(), url, kTestPackageName, fourth_day)); + + // Visit the site again; now it should be shown. + AppBannerSettingsHelper::RecordBannerCouldShowEvent( + web_contents(), url, kTestPackageName, fifth_day, + ui::PAGE_TRANSITION_TYPED); + EXPECT_TRUE(AppBannerSettingsHelper::ShouldShowBanner( + web_contents(), url, kTestPackageName, fifth_day)); +} + +// Test that the banner triggers correctly using site engagement. +TEST_F(AppBannerSettingsHelperTest, SiteEngagementTrigger) { + base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); + command_line->AppendSwitch(switches::kEnableSiteEngagementAppBanner); + + SiteEngagementService* service = + SiteEngagementServiceFactory::GetForProfile(profile()); + DCHECK(service); + + // Not used, but needed for method call. + base::Time reference_time = GetReferenceTime(); + GURL url(kTestURL); + + EXPECT_FALSE(AppBannerSettingsHelper::ShouldShowBanner( + web_contents(), url, kTestPackageName, reference_time)); + + service->AddPoints(url, 1); + EXPECT_FALSE(AppBannerSettingsHelper::ShouldShowBanner( + web_contents(), url, kTestPackageName, reference_time)); + + service->AddPoints(url, 1); + EXPECT_TRUE(AppBannerSettingsHelper::ShouldShowBanner( + web_contents(), url, kTestPackageName, reference_time)); + + AppBannerSettingsHelper::SetTotalEngagementToTrigger(5); + EXPECT_FALSE(AppBannerSettingsHelper::ShouldShowBanner( + web_contents(), url, kTestPackageName, reference_time)); + + service->AddPoints(url, 1.5); + EXPECT_FALSE(AppBannerSettingsHelper::ShouldShowBanner( + web_contents(), url, kTestPackageName, reference_time)); + + service->AddPoints(url, 0.5); + EXPECT_FALSE(AppBannerSettingsHelper::ShouldShowBanner( + web_contents(), url, kTestPackageName, reference_time)); + + service->AddPoints(url, 1.5); + EXPECT_TRUE(AppBannerSettingsHelper::ShouldShowBanner( + web_contents(), url, kTestPackageName, reference_time)); +}
diff --git a/chrome/browser/browsing_data/browsing_data_counter_utils.cc b/chrome/browser/browsing_data/browsing_data_counter_utils.cc new file mode 100644 index 0000000..21a328a --- /dev/null +++ b/chrome/browser/browsing_data/browsing_data_counter_utils.cc
@@ -0,0 +1,185 @@ +// 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/browsing_data/browsing_data_counter_utils.h" + +#include "base/command_line.h" +#include "base/prefs/pref_service.h" +#include "chrome/browser/browsing_data/autofill_counter.h" +#include "chrome/browser/browsing_data/cache_counter.h" +#include "chrome/browser/browsing_data/history_counter.h" +#include "chrome/browser/browsing_data/passwords_counter.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/common/pref_names.h" +#include "chrome/grit/generated_resources.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/text/bytes_formatting.h" + +bool AreCountersEnabled() { + if (base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableClearBrowsingDataCounters)) { + return true; + } + + if (base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kDisableClearBrowsingDataCounters)) { + return false; + } + + // Enabled by default on desktop. Disabled on Android until the feature + // is finished. +#if defined(OS_ANDROID) + return false; +#else + return true; +#endif +} + +// A helper function to display the size of cache in units of MB or higher. +// We need this, as 1 MB is the lowest nonzero cache size displayed by the +// counter. +base::string16 FormatBytesMBOrHigher(BrowsingDataCounter::ResultInt bytes) { + if (ui::GetByteDisplayUnits(bytes) >= ui::DataUnits::DATA_UNITS_MEBIBYTE) + return ui::FormatBytes(bytes); + + return ui::FormatBytesWithUnits( + bytes, ui::DataUnits::DATA_UNITS_MEBIBYTE, true); +} + +base::string16 GetCounterTextFromResult( + const BrowsingDataCounter::Result* result) { + base::string16 text; + std::string pref_name = result->source()->GetPrefName(); + + if (!result->Finished()) { + // The counter is still counting. + text = l10n_util::GetStringUTF16(IDS_CLEAR_BROWSING_DATA_CALCULATING); + + } else if (pref_name == prefs::kDeletePasswords) { + // Passwords counter. + BrowsingDataCounter::ResultInt passwords_count = + static_cast<const BrowsingDataCounter::FinishedResult*>( + result)->Value(); + text = l10n_util::GetPluralStringFUTF16( + IDS_DEL_PASSWORDS_COUNTER, passwords_count); + + } else if (pref_name == prefs::kDeleteCache) { + // Cache counter. + BrowsingDataCounter::ResultInt cache_size_bytes = + static_cast<const BrowsingDataCounter::FinishedResult*>( + result)->Value(); + + PrefService* prefs = result->source()->GetProfile()->GetPrefs(); + BrowsingDataRemover::TimePeriod time_period = + static_cast<BrowsingDataRemover::TimePeriod>( + prefs->GetInteger(prefs::kDeleteTimePeriod)); + + // Three cases: Nonzero result for the entire cache, nonzero result for + // a subset of cache (i.e. a finite time interval), and almost zero (< 1MB). + static const int kBytesInAMegabyte = 1024 * 1024; + if (cache_size_bytes >= kBytesInAMegabyte) { + base::string16 formatted_size = FormatBytesMBOrHigher(cache_size_bytes); + text = time_period == BrowsingDataRemover::EVERYTHING + ? formatted_size + : l10n_util::GetStringFUTF16(IDS_DEL_CACHE_COUNTER_UPPER_ESTIMATE, + formatted_size); + } else { + text = l10n_util::GetStringUTF16(IDS_DEL_CACHE_COUNTER_ALMOST_EMPTY); + } + + } else if (pref_name == prefs::kDeleteBrowsingHistory) { + // History counter. + const HistoryCounter::HistoryResult* history_result = + static_cast<const HistoryCounter::HistoryResult*>(result); + BrowsingDataCounter::ResultInt local_item_count = history_result->Value(); + bool has_synced_visits = history_result->has_synced_visits(); + + text = has_synced_visits + ? l10n_util::GetPluralStringFUTF16( + IDS_DEL_BROWSING_HISTORY_COUNTER_SYNCED, local_item_count) + : l10n_util::GetPluralStringFUTF16( + IDS_DEL_BROWSING_HISTORY_COUNTER, local_item_count); + + } else if (pref_name == prefs::kDeleteFormData) { + // Autofill counter. + const AutofillCounter::AutofillResult* autofill_result = + static_cast<const AutofillCounter::AutofillResult*>(result); + AutofillCounter::ResultInt num_suggestions = autofill_result->Value(); + AutofillCounter::ResultInt num_credit_cards = + autofill_result->num_credit_cards(); + AutofillCounter::ResultInt num_addresses = autofill_result->num_addresses(); + + std::vector<base::string16> displayed_strings; + + if (num_credit_cards) { + displayed_strings.push_back(l10n_util::GetPluralStringFUTF16( + IDS_DEL_AUTOFILL_COUNTER_CREDIT_CARDS, num_credit_cards)); + } + if (num_addresses) { + displayed_strings.push_back(l10n_util::GetPluralStringFUTF16( + IDS_DEL_AUTOFILL_COUNTER_ADDRESSES, num_addresses)); + } + if (num_suggestions) { + // We use a different wording for autocomplete suggestions based on the + // length of the entire string. + switch (displayed_strings.size()) { + case 0: + displayed_strings.push_back(l10n_util::GetPluralStringFUTF16( + IDS_DEL_AUTOFILL_COUNTER_SUGGESTIONS, num_suggestions)); + break; + case 1: + displayed_strings.push_back(l10n_util::GetPluralStringFUTF16( + IDS_DEL_AUTOFILL_COUNTER_SUGGESTIONS_LONG, num_suggestions)); + break; + case 2: + displayed_strings.push_back(l10n_util::GetPluralStringFUTF16( + IDS_DEL_AUTOFILL_COUNTER_SUGGESTIONS_SHORT, num_suggestions)); + break; + default: + NOTREACHED(); + } + } + + // Construct the resulting string from the sections in |displayed_strings|. + switch (displayed_strings.size()) { + case 0: + text = l10n_util::GetStringUTF16(IDS_DEL_AUTOFILL_COUNTER_EMPTY); + break; + case 1: + text = displayed_strings[0]; + break; + case 2: + text = l10n_util::GetStringFUTF16(IDS_DEL_AUTOFILL_COUNTER_TWO_TYPES, + displayed_strings[0], + displayed_strings[1]); + break; + case 3: + text = l10n_util::GetStringFUTF16(IDS_DEL_AUTOFILL_COUNTER_THREE_TYPES, + displayed_strings[0], + displayed_strings[1], + displayed_strings[2]); + break; + default: + NOTREACHED(); + } + } + + return text; +} + +BrowsingDataCounter* CreateCounterForPreference(std::string pref_name) { + if (!AreCountersEnabled()) + return nullptr; + + if (pref_name == prefs::kDeleteBrowsingHistory) + return new HistoryCounter(); + if (pref_name == prefs::kDeleteCache) + return new CacheCounter(); + if (pref_name == prefs::kDeletePasswords) + return new PasswordsCounter(); + if (pref_name == prefs::kDeleteFormData) + return new AutofillCounter(); + + return nullptr; +}
diff --git a/chrome/browser/browsing_data/browsing_data_counter_utils.h b/chrome/browser/browsing_data/browsing_data_counter_utils.h new file mode 100644 index 0000000..df73472a --- /dev/null +++ b/chrome/browser/browsing_data/browsing_data_counter_utils.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_BROWSER_BROWSING_DATA_BROWSING_DATA_COUNTER_UTILS_H_ +#define CHROME_BROWSER_BROWSING_DATA_BROWSING_DATA_COUNTER_UTILS_H_ + +#include "base/strings/string16.h" +#include "chrome/browser/browsing_data/browsing_data_counter.h" + +// Whether the browsing data counters experiment is enabled. +bool AreCountersEnabled(); + +// Constructs the text to be displayed by a counter from the given |result|. +base::string16 GetCounterTextFromResult( + const BrowsingDataCounter::Result* result); + +// Creates a new instance of BrowsingDataCounter that is counting the data +// related to a given deletion preference |pref_name|. +BrowsingDataCounter* CreateCounterForPreference(std::string pref_name); + +#endif // CHROME_BROWSER_BROWSING_DATA_BROWSING_DATA_COUNTER_UTILS_H_
diff --git a/chrome/browser/ui/webui/options/clear_browser_data_handler_unittest.cc b/chrome/browser/browsing_data/browsing_data_counter_utils_unittest.cc similarity index 87% rename from chrome/browser/ui/webui/options/clear_browser_data_handler_unittest.cc rename to chrome/browser/browsing_data/browsing_data_counter_utils_unittest.cc index 64792aa0..c422570 100644 --- a/chrome/browser/ui/webui/options/clear_browser_data_handler_unittest.cc +++ b/chrome/browser/browsing_data/browsing_data_counter_utils_unittest.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/ui/webui/options/clear_browser_data_handler.h" +#include "chrome/browser/browsing_data/browsing_data_counter_utils.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" @@ -10,10 +10,8 @@ #include "chrome/test/base/testing_browser_process.h" #include "testing/gtest/include/gtest/gtest.h" -namespace options { - // Tests the complex output of the Autofill counter. -TEST(ClearBrowserDataTest, AutofillCounterResult) { +TEST(BrowsingDataCounterUtilsTest, AutofillCounterResult) { AutofillCounter counter; // This test assumes that the strings are served exactly as defined, @@ -55,10 +53,7 @@ test_case.num_suggestions )); - base::string16 output = ClearBrowserDataHandler::GetCounterTextFromResult( - &result); + base::string16 output = GetCounterTextFromResult(&result); EXPECT_EQ(output, base::ASCIIToUTF16(test_case.expected_output)); } } - -} // namespace options
diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc index b264d20..6e0a187 100644 --- a/chrome/browser/chrome_browser_main.cc +++ b/chrome/browser/chrome_browser_main.cc
@@ -143,7 +143,6 @@ #include "content/public/common/content_switches.h" #include "content/public/common/main_function_params.h" #include "grit/platform_locale_settings.h" -#include "media/audio/audio_manager.h" #include "net/base/net_module.h" #include "net/cookies/cookie_monster.h" #include "net/http/http_network_layer.h" @@ -743,14 +742,6 @@ const version_info::Channel channel = chrome::GetChannel(); - // TODO(dalecurtis): Remove these checks and enable for all channels once we - // track down the root causes of crbug.com/422522 and crbug.com/478932. - if (channel == version_info::Channel::UNKNOWN || - channel == version_info::Channel::CANARY || - channel == version_info::Channel::DEV) { - media::AudioManager::EnableCrashKeyLoggingForAudioThreadHangs(); - } - // Enable profiler instrumentation depending on the channel. switch (channel) { case version_info::Channel::UNKNOWN: @@ -796,8 +787,6 @@ // On Android, first run is handled in Java code, and the C++ side of Chrome // doesn't know if this is the first run. This will cause some inaccuracy in // the UMA statistics, but this should be minor (first runs are rare). - // TODO(bshe): Figure out which first run code to use for Aura Android. See - // crbug.com/560498 is_first_run = first_run::IsChromeFirstRun(); #endif // defined(OS_ANDROID) @@ -871,13 +860,11 @@ result_code_ = PreCreateThreadsImpl(); if (result_code_ == content::RESULT_CODE_NORMAL_EXIT) { - // TODO(bshe): Use !defined(ANDROID_JAVA_UI) once - // codereview.chromium.org/1459793002 landed. -#if !defined(OS_ANDROID) || defined(USE_AURA) +#if !defined(OS_ANDROID) // These members must be initialized before exiting this function normally. DCHECK(master_prefs_.get()); DCHECK(browser_creator_.get()); -#endif // !defined(OS_ANDROID) || defined(USE_AURA) +#endif // !defined(OS_ANDROID) for (size_t i = 0; i < chrome_extra_parts_.size(); ++i) chrome_extra_parts_[i]->PreCreateThreads(); } @@ -898,8 +885,6 @@ MediaCaptureDevicesDispatcher::GetInstance(); // Android's first run is done in Java instead of native. - // TODO(bshe): Figure out which first run code to use for Aura Android. See - // crbug.com/560498 #if !defined(OS_ANDROID) process_singleton_.reset(new ChromeProcessSingleton( user_data_dir_, base::Bind(&ProcessSingletonNotificationCallback))); @@ -937,16 +922,14 @@ local_state_ = InitializeLocalState( local_state_task_runner.get(), parsed_command_line()); - // TODO(bshe): Use !defined(ANDROID_JAVA_UI) once - // codereview.chromium.org/1459793002 landed. -#if !defined(OS_ANDROID) || defined(USE_AURA) +#if !defined(OS_ANDROID) // These members must be initialized before returning from this function. master_prefs_.reset(new first_run::MasterPrefs); // Android doesn't use StartupBrowserCreator. browser_creator_.reset(new StartupBrowserCreator); // TODO(yfriedman): Refactor Android to re-use UMABrowsingActivityObserver chrome::UMABrowsingActivityObserver::Init(); -#endif // !defined(OS_ANDROID) || defined(USE_AURA) +#endif // !defined(OS_ANDROID) #if !defined(OS_CHROMEOS) // Convert active labs into switches. This needs to be done before @@ -1021,7 +1004,6 @@ base::FilePath resources_pack_path; PathService::Get(chrome::FILE_RESOURCES_PACK, &resources_pack_path); #if defined(OS_ANDROID) - // Uses Android resources even without ANDROID_JAVA_UI. ui::LoadMainAndroidPackFile("assets/resources.pak", resources_pack_path); #else ResourceBundle::GetSharedInstance().AddDataPackFromPath( @@ -1032,8 +1014,6 @@ // Android does first run in Java instead of native. // Chrome OS has its own out-of-box-experience code. - // TODO(bshe): Figure out which first run code to use for Aura Android. See - // crbug.com/560498 #if !defined(OS_ANDROID) && !defined(OS_CHROMEOS) // On first run, we need to process the predictor preferences before the // browser's profile_manager object is created, but after ResourceBundle @@ -1467,14 +1447,12 @@ if (!profile_) return content::RESULT_CODE_NORMAL_EXIT; - // TODO(bshe): Use !defined(ANDROID_JAVA_UI) once - // codereview.chromium.org/1459793002 landed. -#if !defined(OS_ANDROID) || defined(USE_AURA) +#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(); -#endif // !defined(OS_ANDROID) || defined(USE_AURA) +#endif // !defined(OS_ANDROID) #if defined(ENABLE_BACKGROUND) // Autoload any profiles which are running background apps. @@ -1516,8 +1494,6 @@ // Note that this be done _after_ the PrefService is initialized and all // preferences are registered, since some of the code that the importer // touches reads preferences. - // TODO(bshe): Figure out which first run code to use for Aura Android. See - // crbug.com/560498 if (first_run::IsChromeFirstRun()) { first_run::AutoImport(profile_, master_prefs_->homepage_defined, @@ -1652,10 +1628,9 @@ g_browser_process->local_state()); ThreadWatcherList::StartWatchingAll(parsed_command_line()); - // TODO(bshe): Aura Android may need this call. See crbug.com/565317. -#if defined(OS_ANDROID) && !defined(USE_AURA) +#if defined(OS_ANDROID) ThreadWatcherAndroid::RegisterApplicationStatusListener(); -#endif // defined(OS_ANDROID) && !defined(USE_AURA) +#endif // defined(OS_ANDROID) #if !defined(DISABLE_NACL) BrowserThread::PostTask( @@ -1682,9 +1657,7 @@ if (!parsed_command_line().HasSwitch(switches::kDisableComponentUpdate)) RegisterComponentsForUpdate(); - // TODO(bshe): Use defined(ANDROID_JAVA_UI) once - // codereview.chromium.org/1459793002 landed. -#if defined(OS_ANDROID) && !defined(USE_AURA) +#if defined(OS_ANDROID) variations::VariationsService* variations_service = browser_process_->variations_service(); if (variations_service) { @@ -1694,6 +1667,7 @@ } translate::TranslateDownloadManager::RequestLanguageList( profile_->GetPrefs()); + #else // Most general initialization is behind us, but opening a // tab and/or session restore and such is still to be done. @@ -1770,11 +1744,9 @@ content::StartPowerUsageMonitor(); #endif // !defined(OS_LINUX) || defined(OS_CHROMEOS) -#if !defined(OS_ANDROID) process_power_collector_.reset(new ProcessPowerCollector); process_power_collector_->Initialize(); #endif // !defined(OS_ANDROID) -#endif // defined(OS_ANDROID) && !defined(USE_AURA) PostBrowserStart(); @@ -1792,12 +1764,10 @@ } #endif // defined(OS_ANDROID) - // TODO(bshe): Use !defined(ANDROID_JAVA_UI) once - // codereview.chromium.org/1459793002 landed. -#if !defined(OS_ANDROID) || defined(USE_AURA) +#if !defined(OS_ANDROID) UMA_HISTOGRAM_TIMES("Startup.PreMainMessageLoopRunImplStep3Time", base::TimeTicks::Now() - start_time_step3); -#endif // !defined(OS_ANDROID) || defined(USE_AURA) +#endif // !defined(OS_ANDROID) return result_code_; }
diff --git a/chrome/browser/chrome_browser_main.h b/chrome/browser/chrome_browser_main.h index 6ba5ee3..da58d17 100644 --- a/chrome/browser/chrome_browser_main.h +++ b/chrome/browser/chrome_browser_main.h
@@ -165,10 +165,7 @@ scoped_ptr<BrowserProcessImpl> browser_process_; scoped_refptr<metrics::TrackingSynchronizer> tracking_synchronizer_; - - // TODO(bshe): Use !defined(ANDROID_JAVA_UI) once - // codereview.chromium.org/1459793002 landed. -#if !defined(OS_ANDROID) || defined(USE_AURA) +#if !defined(OS_ANDROID) // Browser creation happens on the Java side in Android. scoped_ptr<StartupBrowserCreator> browser_creator_; @@ -178,7 +175,7 @@ // Android's first run is done in Java instead of native. scoped_ptr<first_run::MasterPrefs> master_prefs_; -#endif // !defined(OS_ANDROID) || defined(USE_AURA) +#endif Profile* profile_; bool run_message_loop_; ProcessSingleton::NotifyResult notify_result_;
diff --git a/chrome/browser/chrome_browser_main_android.cc b/chrome/browser/chrome_browser_main_android.cc index 7877cff..4fd6d9d 100644 --- a/chrome/browser/chrome_browser_main_android.cc +++ b/chrome/browser/chrome_browser_main_android.cc
@@ -19,6 +19,7 @@ #include "components/crash/content/browser/crash_dump_manager_android.h" #include "components/enhanced_bookmarks/persistent_image_store.h" #include "components/signin/core/browser/signin_manager.h" +#include "content/public/browser/android/compositor.h" #include "content/public/browser/browser_thread.h" #include "content/public/common/main_function_params.h" #include "media/base/android/media_client_android.h" @@ -27,10 +28,6 @@ #include "ui/base/resource/resource_bundle_android.h" #include "ui/base/ui_base_paths.h" -#if !defined(USE_AURA) -#include "content/public/browser/android/compositor.h" -#endif - namespace { void DeleteFileTask( @@ -103,9 +100,7 @@ net::NetworkChangeNotifier::SetFactory( new net::NetworkChangeNotifierFactoryAndroid()); -#if !defined(USE_AURA) content::Compositor::Initialize(); -#endif // Chrome on Android does not use default MessageLoop. It has its own // Android specific MessageLoop.
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc index ebbc333..34b0a73 100644 --- a/chrome/browser/chrome_content_browser_client.cc +++ b/chrome/browser/chrome_content_browser_client.cc
@@ -114,6 +114,7 @@ #include "components/data_reduction_proxy/content/browser/data_reduction_proxy_message_filter.h" #include "components/dom_distiller/core/dom_distiller_switches.h" #include "components/dom_distiller/core/url_constants.h" +#include "components/error_page/common/error_page_switches.h" #include "components/google/core/browser/google_util.h" #include "components/metrics/client_info.h" #include "components/net_log/chrome_net_log.h" @@ -1427,7 +1428,7 @@ #endif static const char* const kDinosaurEasterEggSwitches[] = { - switches::kDisableDinosaurEasterEgg, + error_page::switches::kDisableDinosaurEasterEgg, }; command_line->CopySwitchesFrom(browser_command_line, kDinosaurEasterEggSwitches, @@ -1507,7 +1508,8 @@ if (prefs->HasPrefPath(prefs::kAllowDinosaurEasterEgg) && !prefs->GetBoolean(prefs::kAllowDinosaurEasterEgg)) - command_line->AppendSwitch(switches::kDisableDinosaurEasterEgg); + command_line->AppendSwitch( + error_page::switches::kDisableDinosaurEasterEgg); } if (IsAutoReloadEnabled()) @@ -1527,11 +1529,15 @@ // Command line switches override const std::string& show_saved_copy_value = - browser_command_line.GetSwitchValueASCII(switches::kShowSavedCopy); - if (show_saved_copy_value == switches::kEnableShowSavedCopyPrimary || - show_saved_copy_value == switches::kEnableShowSavedCopySecondary || - show_saved_copy_value == switches::kDisableShowSavedCopy) { - command_line->AppendSwitchASCII(switches::kShowSavedCopy, + browser_command_line.GetSwitchValueASCII( + error_page::switches::kShowSavedCopy); + if (show_saved_copy_value == + error_page::switches::kEnableShowSavedCopyPrimary || + show_saved_copy_value == + error_page::switches::kEnableShowSavedCopySecondary || + show_saved_copy_value == + error_page::switches::kDisableShowSavedCopy) { + command_line->AppendSwitchASCII(error_page::switches::kShowSavedCopy, show_saved_copy_value); } else { std::string group = @@ -1539,11 +1545,12 @@ if (group == "Primary") { command_line->AppendSwitchASCII( - switches::kShowSavedCopy, switches::kEnableShowSavedCopyPrimary); + error_page::switches::kShowSavedCopy, + error_page::switches::kEnableShowSavedCopyPrimary); } else if (group == "Secondary") { command_line->AppendSwitchASCII( - switches::kShowSavedCopy, - switches::kEnableShowSavedCopySecondary); + error_page::switches::kShowSavedCopy, + error_page::switches::kEnableShowSavedCopySecondary); } } }
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn index 8b01211..d8a1c57b 100644 --- a/chrome/browser/chromeos/BUILD.gn +++ b/chrome/browser/chromeos/BUILD.gn
@@ -8,6 +8,8 @@ import("//media/media_options.gni") import("//third_party/protobuf/proto_library.gni") +assert(is_chromeos) + gypi_values = exec_script("//build/gypi_to_gn.py", [ rebase_path("../../chrome_browser_chromeos.gypi") ], "scope",
diff --git a/chrome/browser/chromeos/events/event_rewriter.cc b/chrome/browser/chromeos/events/event_rewriter.cc index 23ab7b1..bf7d9a37 100644 --- a/chrome/browser/chromeos/events/event_rewriter.cc +++ b/chrome/browser/chromeos/events/event_rewriter.cc
@@ -680,6 +680,22 @@ const ModifierRemapping* remapped_key = NULL; // Remapping based on DomKey. switch (incoming.key) { + // On Chrome OS, F15 (XF86XK_Launch6) with NumLock (Mod2Mask) is sent + // when Diamond key is pressed. + case ui::DomKey::F15: + // When diamond key is not available, the configuration UI for Diamond + // key is not shown. Therefore, ignore the kLanguageRemapDiamondKeyTo + // syncable pref. + if (HasDiamondKey()) + remapped_key = + GetRemappedKey(prefs::kLanguageRemapDiamondKeyTo, *pref_service); + // Default behavior of F15 is Control, even if --has-chromeos-diamond-key + // is absent, according to unit test comments. + if (!remapped_key) { + DCHECK_EQ(ui::VKEY_CONTROL, kModifierRemappingCtrl->result.key_code); + remapped_key = kModifierRemappingCtrl; + } + break; case ui::DomKey::ALT_GRAPH: // The Neo2 codes modifiers such that CapsLock appears as VKEY_ALTGR, // but AltGraph (right Alt) also appears as VKEY_ALTGR in Neo2, @@ -727,27 +743,12 @@ // Remapping based on DomCode. switch (incoming.code) { - // On Chrome OS, F15 (XF86XK_Launch6) with NumLock (Mod2Mask) is sent - // when Diamond key is pressed. - case ui::DomCode::F15: - // When diamond key is not available, the configuration UI for Diamond - // key is not shown. Therefore, ignore the kLanguageRemapDiamondKeyTo - // syncable pref. - if (HasDiamondKey()) - remapped_key = - GetRemappedKey(prefs::kLanguageRemapDiamondKeyTo, *pref_service); - // Default behavior of F15 is Control, even if --has-chromeos-diamond-key - // is absent, according to unit test comments. - if (!remapped_key) { - DCHECK_EQ(ui::VKEY_CONTROL, kModifierRemappingCtrl->result.key_code); - remapped_key = kModifierRemappingCtrl; - } - break; // On Chrome OS, XF86XK_Launch7 (F16) with Mod3Mask is sent when Caps Lock // is pressed (with one exception: when // IsISOLevel5ShiftUsedByCurrentInputMethod() is true, the key generates // XK_ISO_Level3_Shift with Mod3Mask, not XF86XK_Launch7). case ui::DomCode::F16: + case ui::DomCode::CAPS_LOCK: characteristic_flag = ui::EF_CAPS_LOCK_DOWN; remapped_key = GetRemappedKey(prefs::kLanguageRemapCapsLockKeyTo, *pref_service);
diff --git a/chrome/browser/chromeos/login/screens/base_screen_delegate.h b/chrome/browser/chromeos/login/screens/base_screen_delegate.h index 62e27321..ee626ea 100644 --- a/chrome/browser/chromeos/login/screens/base_screen_delegate.h +++ b/chrome/browser/chromeos/login/screens/base_screen_delegate.h
@@ -51,9 +51,8 @@ TERMS_OF_SERVICE_ACCEPTED = 18, WRONG_HWID_WARNING_SKIPPED = 19, CONTROLLER_PAIRING_FINISHED = 20, - HOST_PAIRING_FINISHED = 21, - ENABLE_DEBUGGING_FINISHED = 22, - ENABLE_DEBUGGING_CANCELED = 23, + ENABLE_DEBUGGING_FINISHED = 21, + ENABLE_DEBUGGING_CANCELED = 22, EXIT_CODES_COUNT // not a real code, must be the last };
diff --git a/chrome/browser/chromeos/login/session/user_session_manager.cc b/chrome/browser/chromeos/login/session/user_session_manager.cc index a937370b..072015c 100644 --- a/chrome/browser/chromeos/login/session/user_session_manager.cc +++ b/chrome/browser/chromeos/login/session/user_session_manager.cc
@@ -6,7 +6,9 @@ #include <stddef.h> +#include <set> #include <string> +#include <vector> #include "base/base_paths.h" #include "base/bind.h" @@ -1398,7 +1400,7 @@ // One profile has been already loaded on browser start. user_manager::UserManager* user_manager = user_manager::UserManager::Get(); - DCHECK(user_manager->GetLoggedInUsers().size() == 1); + DCHECK_EQ(1u, user_manager->GetLoggedInUsers().size()); DCHECK(user_manager->GetActiveUser()); std::string active_user_id = user_manager->GetActiveUser()->email();
diff --git a/chrome/browser/chromeos/login/wizard_controller.cc b/chrome/browser/chromeos/login/wizard_controller.cc index 62c32e3e..e478e73 100644 --- a/chrome/browser/chromeos/login/wizard_controller.cc +++ b/chrome/browser/chromeos/login/wizard_controller.cc
@@ -766,10 +766,6 @@ ShowAutoEnrollmentCheckScreen(); } -void WizardController::OnHostPairingFinished() { - ShowAutoEnrollmentCheckScreen(); -} - void WizardController::OnAutoEnrollmentCheckCompleted() { // Check whether the device is disabled. OnDeviceDisabledChecked() will be // invoked when the result of this check is known. Until then, the current @@ -1052,9 +1048,6 @@ case CONTROLLER_PAIRING_FINISHED: OnControllerPairingFinished(); break; - case HOST_PAIRING_FINISHED: - OnHostPairingFinished(); - break; default: NOTREACHED(); }
diff --git a/chrome/browser/chromeos/login/wizard_controller.h b/chrome/browser/chromeos/login/wizard_controller.h index 3c80944..b9129fb 100644 --- a/chrome/browser/chromeos/login/wizard_controller.h +++ b/chrome/browser/chromeos/login/wizard_controller.h
@@ -206,7 +206,6 @@ void OnTermsOfServiceDeclined(); void OnTermsOfServiceAccepted(); void OnControllerPairingFinished(); - void OnHostPairingFinished(); void OnAutoEnrollmentCheckCompleted(); // Callback invoked once it has been determined whether the device is disabled
diff --git a/chrome/browser/chromeos/login/wizard_controller_browsertest.cc b/chrome/browser/chromeos/login/wizard_controller_browsertest.cc index ada3381..b3e4803 100644 --- a/chrome/browser/chromeos/login/wizard_controller_browsertest.cc +++ b/chrome/browser/chromeos/login/wizard_controller_browsertest.cc
@@ -1231,7 +1231,7 @@ // TODO(dzhioev): Add tests for controller/host pairing flow. // http://crbug.com/375191 -static_assert(BaseScreenDelegate::EXIT_CODES_COUNT == 24, +static_assert(BaseScreenDelegate::EXIT_CODES_COUNT == 23, "tests for new control flow are missing"); } // namespace chromeos
diff --git a/chrome/browser/content_settings/tab_specific_content_settings.cc b/chrome/browser/content_settings/tab_specific_content_settings.cc index 5edd14e..1ed0870 100644 --- a/chrome/browser/content_settings/tab_specific_content_settings.cc +++ b/chrome/browser/content_settings/tab_specific_content_settings.cc
@@ -520,6 +520,16 @@ content::NotificationService::NoDetails()); } +void TabSpecificContentSettings::OnDidUseKeygen(const GURL& origin_url) { + HostContentSettingsMap* map = HostContentSettingsMapFactory::GetForProfile( + Profile::FromBrowserContext(web_contents()->GetBrowserContext())); + GURL url = web_contents()->GetLastCommittedURL(); + if (map->GetContentSetting(url, url, CONTENT_SETTINGS_TYPE_KEYGEN, + std::string()) != CONTENT_SETTING_ALLOW) { + OnContentBlocked(CONTENT_SETTINGS_TYPE_KEYGEN); + } +} + #if defined(OS_ANDROID) || defined(OS_CHROMEOS) void TabSpecificContentSettings::OnProtectedMediaIdentifierPermissionSet( const GURL& requesting_origin, @@ -748,6 +758,7 @@ IPC_BEGIN_MESSAGE_MAP(TabSpecificContentSettings, message) IPC_MESSAGE_HANDLER(ChromeViewHostMsg_ContentBlocked, OnContentBlockedWithDetail) + IPC_MESSAGE_HANDLER(ChromeViewHostMsg_DidUseKeygen, OnDidUseKeygen) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() return handled;
diff --git a/chrome/browser/content_settings/tab_specific_content_settings.h b/chrome/browser/content_settings/tab_specific_content_settings.h index c91de10..99df942 100644 --- a/chrome/browser/content_settings/tab_specific_content_settings.h +++ b/chrome/browser/content_settings/tab_specific_content_settings.h
@@ -336,6 +336,7 @@ bool blocked_by_policy); void OnGeolocationPermissionSet(const GURL& requesting_frame, bool allowed); + void OnDidUseKeygen(const GURL& url); #if defined(OS_ANDROID) || defined(OS_CHROMEOS) void OnProtectedMediaIdentifierPermissionSet(const GURL& requesting_frame, bool allowed);
diff --git a/chrome/browser/devtools/BUILD.gn b/chrome/browser/devtools/BUILD.gn index 17b2789..22ffc23 100644 --- a/chrome/browser/devtools/BUILD.gn +++ b/chrome/browser/devtools/BUILD.gn
@@ -3,6 +3,7 @@ # found in the LICENSE file. if (!is_android) { + import("//build/config/features.gni") import("//tools/grit/grit_rule.gni") } @@ -69,7 +70,6 @@ if (!is_android) { deps += [ - ":webrtc_device_provider_resources", "//chrome:extra_resources", "//chrome:resources", "//chrome:strings", @@ -93,8 +93,6 @@ "device/android_device_manager.cc", "device/android_device_manager.h", "device/android_web_socket.cc", - "device/cast_device_provider.cc", - "device/cast_device_provider.h", "device/devtools_android_bridge.cc", "device/devtools_android_bridge.h", "device/port_forwarding_controller.cc", @@ -109,14 +107,6 @@ "device/usb/android_usb_socket.h", "device/usb/usb_device_provider.cc", "device/usb/usb_device_provider.h", - "device/webrtc/devtools_bridge_client.cc", - "device/webrtc/devtools_bridge_client.h", - "device/webrtc/devtools_bridge_instances_request.cc", - "device/webrtc/devtools_bridge_instances_request.h", - "device/webrtc/send_command_request.cc", - "device/webrtc/send_command_request.h", - "device/webrtc/webrtc_device_provider.cc", - "device/webrtc/webrtc_device_provider.h", "devtools_contents_resizing_strategy.cc", "devtools_contents_resizing_strategy.h", "devtools_embedder_message_dispatcher.cc", @@ -142,19 +132,11 @@ "remote_debugging_server.cc", "remote_debugging_server.h", ] - } -} - -if (!is_android) { - # GYP version: chrome/browser/devtools/webrtc_device_provider_resources.gyp:webrtc_device_provider_resources - grit("webrtc_device_provider_resources") { - source = "device/webrtc/resources.grd" - output_dir = "$root_gen_dir/chrome" - outputs = [ - "grit/webrtc_device_provider_resources.h", - "grit/webrtc_device_provider_resources_map.cc", - "grit/webrtc_device_provider_resources_map.h", - "webrtc_device_provider_resources.pak", - ] + if (enable_service_discovery) { + sources += [ + "device/cast_device_provider.cc", + "device/cast_device_provider.h", + ] + } } }
diff --git a/chrome/browser/devtools/device/cast_device_provider.cc b/chrome/browser/devtools/device/cast_device_provider.cc index 10a0c2ff..8665cce 100644 --- a/chrome/browser/devtools/device/cast_device_provider.cc +++ b/chrome/browser/devtools/device/cast_device_provider.cc
@@ -12,9 +12,12 @@ #include "base/strings/string_number_conversions.h" #include "base/strings/string_split.h" #include "base/thread_task_runner_handle.h" +#include "chrome/browser/local_discovery/service_discovery_shared_client.h" #include "net/base/host_port_pair.h" #include "net/base/ip_address_number.h" +using local_discovery::ServiceDescription; +using local_discovery::ServiceDiscoveryDeviceLister; using local_discovery::ServiceDiscoverySharedClient; namespace { @@ -23,7 +26,7 @@ const char kCastServiceType[] = "_googlecast._tcp.local"; const char kUnknownCastDevice[] = "Unknown Cast Device"; -typedef std::map<std::string, std::string> ServiceTxtRecordMap; +using ServiceTxtRecordMap = std::map<std::string, std::string>; // Parses TXT record strings into a map. TXT key-value strings are assumed to // follow the form "$key(=$value)?", where $key must contain at least one @@ -32,8 +35,11 @@ const std::vector<std::string>& record) { scoped_ptr<ServiceTxtRecordMap> record_map(new ServiceTxtRecordMap()); for (const auto& key_value_str : record) { - int index = key_value_str.find("=", 0); - if (index < 0 && key_value_str != "") { + if (key_value_str.empty()) + continue; + + size_t index = key_value_str.find("=", 0); + if (index == std::string::npos) { // Some strings may only define a key (no '=' in the key/value string). // The chosen behavior is to assume the value is the empty string. record_map->insert(std::make_pair(key_value_str, "")); @@ -53,9 +59,9 @@ AndroidDeviceManager::DeviceInfo device_info; device_info.connected = true; - const auto& search = record_map->find("md"); - if (search != record_map->end() && search->second != "") - device_info.model = search->second; + const auto it = record_map->find("md"); + if (it != record_map->end() && !it->second.empty()) + device_info.model = it->second; else device_info.model = kUnknownCastDevice; @@ -171,13 +177,13 @@ << service_description.service_name; if (service_description.service_type() != kCastServiceType) return; - net::IPAddressNumber ip_address = service_description.ip_address; + const net::IPAddressNumber& ip_address = service_description.ip_address; if (ip_address.size() != net::kIPv4AddressSize && ip_address.size() != net::kIPv6AddressSize) { // An invalid IP address is not queryable. return; } - std::string name = service_description.service_name; + const std::string& name = service_description.service_name; std::string host = net::IPAddressToString(ip_address); service_hostname_map_[name] = host; device_info_map_[host] = ServiceDescriptionToDeviceInfo(service_description); @@ -185,15 +191,12 @@ void CastDeviceProvider::OnDeviceRemoved(const std::string& service_name) { VLOG(1) << "Device removed: " << service_name; - auto it_hostname = service_hostname_map_.find(service_name); - if (it_hostname == service_hostname_map_.end()) + auto it = service_hostname_map_.find(service_name); + if (it == service_hostname_map_.end()) return; - std::string hostname = it_hostname->second; - service_hostname_map_.erase(it_hostname); - auto it_device = device_info_map_.find(hostname); - if (it_device == device_info_map_.end()) - return; - device_info_map_.erase(it_device); + const std::string& hostname = it->second; + device_info_map_.erase(hostname); + service_hostname_map_.erase(it); } void CastDeviceProvider::OnDeviceCacheFlushed() {
diff --git a/chrome/browser/devtools/device/cast_device_provider.h b/chrome/browser/devtools/device/cast_device_provider.h index 9d05c42..d0a82ac3 100644 --- a/chrome/browser/devtools/device/cast_device_provider.h +++ b/chrome/browser/devtools/device/cast_device_provider.h
@@ -12,21 +12,16 @@ #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" -#include "base/single_thread_task_runner.h" #include "chrome/browser/devtools/device/android_device_manager.h" #include "chrome/browser/devtools/device/tcp_device_provider.h" #include "chrome/browser/local_discovery/service_discovery_device_lister.h" -#include "chrome/browser/local_discovery/service_discovery_shared_client.h" #include "content/public/browser/browser_thread.h" -using local_discovery::ServiceDescription; -using local_discovery::ServiceDiscoveryDeviceLister; -using local_discovery::ServiceDiscoverySharedClient; - // Supplies Cast device information for the purposes of remote debugging Cast // applications over ADB. -class CastDeviceProvider : public AndroidDeviceManager::DeviceProvider, - public ServiceDiscoveryDeviceLister::Delegate { +class CastDeviceProvider + : public AndroidDeviceManager::DeviceProvider, + public local_discovery::ServiceDiscoveryDeviceLister::Delegate { public: CastDeviceProvider(); @@ -39,8 +34,9 @@ const SocketCallback& callback) override; // ServiceDiscoveryDeviceLister::Delegate implementation: - void OnDeviceChanged(bool added, - const ServiceDescription& service_description) override; + void OnDeviceChanged( + bool added, + const local_discovery::ServiceDescription& service_description) override; void OnDeviceRemoved(const std::string& service_name) override; void OnDeviceCacheFlushed() override;
diff --git a/chrome/browser/devtools/device/cast_device_provider_unittest.cc b/chrome/browser/devtools/device/cast_device_provider_unittest.cc index 51b3096..7e0daec 100644 --- a/chrome/browser/devtools/device/cast_device_provider_unittest.cc +++ b/chrome/browser/devtools/device/cast_device_provider_unittest.cc
@@ -8,10 +8,11 @@ #include "net/base/host_port_pair.h" #include "testing/gtest/include/gtest/gtest.h" -namespace { +using local_discovery::ServiceDescription; +using DeviceInfo = AndroidDeviceManager::DeviceInfo; +using BrowserInfo = AndroidDeviceManager::BrowserInfo; -typedef AndroidDeviceManager::DeviceInfo DeviceInfo; -typedef AndroidDeviceManager::BrowserInfo BrowserInfo; +namespace { void CompareDeviceInfo(bool* was_run, const DeviceInfo& expected, @@ -19,8 +20,8 @@ EXPECT_EQ(expected.model, actual.model); EXPECT_EQ(expected.connected, actual.connected); - BrowserInfo exp_br_info = expected.browser_info[0]; - BrowserInfo act_br_info = actual.browser_info[0]; + const BrowserInfo& exp_br_info = expected.browser_info[0]; + const BrowserInfo& act_br_info = actual.browser_info[0]; EXPECT_EQ(exp_br_info.socket_name, act_br_info.socket_name); EXPECT_EQ(exp_br_info.display_name, act_br_info.display_name); EXPECT_EQ(exp_br_info.type, act_br_info.type);
diff --git a/chrome/browser/devtools/device/devtools_android_bridge.cc b/chrome/browser/devtools/device/devtools_android_bridge.cc index eef7de4..dbe64ee 100644 --- a/chrome/browser/devtools/device/devtools_android_bridge.cc +++ b/chrome/browser/devtools/device/devtools_android_bridge.cc
@@ -29,18 +29,14 @@ #include "base/threading/thread.h" #include "base/values.h" #include "chrome/browser/devtools/device/adb/adb_device_provider.h" -#include "chrome/browser/devtools/device/cast_device_provider.h" #include "chrome/browser/devtools/device/port_forwarding_controller.h" #include "chrome/browser/devtools/device/tcp_device_provider.h" #include "chrome/browser/devtools/device/usb/usb_device_provider.h" -#include "chrome/browser/devtools/device/webrtc/webrtc_device_provider.h" #include "chrome/browser/devtools/devtools_protocol.h" #include "chrome/browser/devtools/devtools_target_impl.h" #include "chrome/browser/devtools/devtools_window.h" #include "chrome/browser/devtools/remote_debugging_server.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/signin/profile_oauth2_token_service_factory.h" -#include "chrome/browser/signin/signin_manager_factory.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/pref_names.h" #include "components/keyed_service/content/browser_context_dependency_manager.h" @@ -54,6 +50,10 @@ #include "net/base/host_port_pair.h" #include "net/base/net_errors.h" +#if defined(ENABLE_SERVICE_DISCOVERY) +#include "chrome/browser/devtools/device/cast_device_provider.h" +#endif + using content::BrowserThread; namespace { @@ -70,11 +70,6 @@ const char kWebViewSocketPrefix[] = "webview_devtools_remote"; -bool IsWebRTCDeviceProviderEnabled() { - return base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kEnableDevToolsExperiments); -} - bool BrowserIdFromString(const std::string& browser_id_str, DevToolsAndroidBridge::BrowserId* browser_id) { size_t colon_pos = browser_id_str.find(':'); @@ -276,10 +271,6 @@ : BrowserContextKeyedServiceFactory( "DevToolsAndroidBridge", BrowserContextDependencyManager::GetInstance()) { - if (IsWebRTCDeviceProviderEnabled()) { - DependsOn(ProfileOAuth2TokenServiceFactory::GetInstance()); - DependsOn(SigninManagerFactory::GetInstance()); - } } DevToolsAndroidBridge::Factory::~Factory() {} @@ -288,16 +279,7 @@ content::BrowserContext* context) const { Profile* profile = Profile::FromBrowserContext(context); - ProfileOAuth2TokenService* token_service = nullptr; - SigninManagerBase* signin_manager = nullptr; - - if (IsWebRTCDeviceProviderEnabled()) { - token_service = ProfileOAuth2TokenServiceFactory::GetForProfile(profile); - signin_manager = SigninManagerFactory::GetForProfile(profile); - } - - return new DevToolsAndroidBridge( - profile, signin_manager, token_service); + return new DevToolsAndroidBridge(profile); } // AgentHostDelegate ---------------------------------------------------------- @@ -732,12 +714,8 @@ // DevToolsAndroidBridge ------------------------------------------------------ DevToolsAndroidBridge::DevToolsAndroidBridge( - Profile* profile, - SigninManagerBase* signin_manager, - ProfileOAuth2TokenService* const token_service) + Profile* profile) : profile_(profile), - signin_manager_(signin_manager), - token_service_(token_service), device_manager_(AndroidDeviceManager::Create()), task_scheduler_(base::Bind(&DevToolsAndroidBridge::ScheduleTaskDefault)), port_forwarding_controller_(new PortForwardingController(profile, this)), @@ -949,7 +927,11 @@ if (scoped_refptr<TCPDeviceProvider> provider = CreateTCPDeviceProvider()) device_providers.push_back(provider); + +#if defined(ENABLE_SERVICE_DISCOVERY) device_providers.push_back(new CastDeviceProvider()); +#endif + device_providers.push_back(new AdbDeviceProvider()); PrefService* service = profile_->GetPrefs(); @@ -962,11 +944,6 @@ device_providers.push_back(new UsbDeviceProvider(profile_)); } - if (IsWebRTCDeviceProviderEnabled()) { - device_providers.push_back( - new WebRTCDeviceProvider(profile_, signin_manager_, token_service_)); - } - device_manager_->SetDeviceProviders(device_providers); if (NeedsDeviceListPolling()) { StopDeviceListPolling();
diff --git a/chrome/browser/devtools/device/devtools_android_bridge.h b/chrome/browser/devtools/device/devtools_android_bridge.h index b3157986..0c63afd2 100644 --- a/chrome/browser/devtools/device/devtools_android_bridge.h +++ b/chrome/browser/devtools/device/devtools_android_bridge.h
@@ -37,9 +37,6 @@ class DevToolsTargetImpl; class PortForwardingController; class Profile; -class WebRTCDeviceProvider; -class SigninManagerBase; -class ProfileOAuth2TokenService; class DevToolsAndroidBridge : public KeyedService { public: @@ -160,9 +157,7 @@ virtual ~DeviceListListener() {} }; - DevToolsAndroidBridge(Profile* profile, - SigninManagerBase* signin_manager, - ProfileOAuth2TokenService* token_service); + explicit DevToolsAndroidBridge(Profile* profile); void AddDeviceListListener(DeviceListListener* listener); void RemoveDeviceListListener(DeviceListListener* listener); @@ -274,8 +269,6 @@ } Profile* const profile_; - SigninManagerBase* const signin_manager_; - ProfileOAuth2TokenService* const token_service_; const scoped_ptr<AndroidDeviceManager> device_manager_; typedef std::map<std::string, scoped_refptr<AndroidDeviceManager::Device>>
diff --git a/chrome/browser/devtools/device/usb/android_usb_browsertest.cc b/chrome/browser/devtools/device/usb/android_usb_browsertest.cc index d7fbbf93..91307a8 100644 --- a/chrome/browser/devtools/device/usb/android_usb_browsertest.cc +++ b/chrome/browser/devtools/device/usb/android_usb_browsertest.cc
@@ -427,10 +427,6 @@ return T::kConfigured ? &config_desc_ : nullptr; } - bool Close(scoped_refptr<UsbDeviceHandle> handle) override { - return true; - } - std::set<int> claimed_interfaces_; protected:
diff --git a/chrome/browser/devtools/device/webrtc/background_worker.html b/chrome/browser/devtools/device/webrtc/background_worker.html deleted file mode 100644 index 9b630fc2..0000000 --- a/chrome/browser/devtools/device/webrtc/background_worker.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. - --> -<html> -<head> -<script src="js/webrtc_device_provider.js"></script> -</head> -</html>
diff --git a/chrome/browser/devtools/device/webrtc/devtools_bridge_client.cc b/chrome/browser/devtools/device/webrtc/devtools_bridge_client.cc deleted file mode 100644 index a1c7184..0000000 --- a/chrome/browser/devtools/device/webrtc/devtools_bridge_client.cc +++ /dev/null
@@ -1,267 +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/devtools/device/webrtc/devtools_bridge_client.h" - -#include <stddef.h> - -#include "base/callback.h" -#include "chrome/browser/chrome_notification_types.h" -#include "chrome/browser/local_discovery/gcd_api_flow.h" -#include "chrome/common/url_constants.h" -#include "components/signin/core/browser/profile_identity_provider.h" -#include "content/public/browser/notification_observer.h" -#include "content/public/browser/notification_registrar.h" -#include "content/public/browser/notification_source.h" -#include "content/public/browser/web_contents.h" -#include "content/public/browser/web_contents_observer.h" -#include "content/public/browser/web_contents_user_data.h" -#include "ui/base/page_transition_types.h" - -using content::BrowserThread; -using content::WebContents; - -namespace { - -const char kBackgroundWorkerURL[] = - "chrome://webrtc-device-provider/background_worker.html"; -const char kSerial[] = "webrtc"; -const char kPseudoDeviceName[] = "Remote browsers"; -const char kDeviceIdPrefix[] = "device-id:"; - -class BackgroundWorkerUserData - : public content::WebContentsUserData<BackgroundWorkerUserData> { - public: - DevToolsBridgeClient* client() const { return client_; } - void SetClient(DevToolsBridgeClient* client) { client_ = client; } - - private: - friend WebContentsUserData<BackgroundWorkerUserData>; - - explicit BackgroundWorkerUserData(WebContents* contents) : client_(nullptr) {} - - DevToolsBridgeClient* client_; -}; - -} // namespace - -DEFINE_WEB_CONTENTS_USER_DATA_KEY(BackgroundWorkerUserData); - -// DevToolsBridgeClient -------------------------------------------------------- - -// static -base::WeakPtr<DevToolsBridgeClient> DevToolsBridgeClient::Create( - Profile* profile, - SigninManagerBase* signin_manager, - ProfileOAuth2TokenService* token_service) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - auto instance = - new DevToolsBridgeClient(profile, signin_manager, token_service); - return instance->weak_factory_.GetWeakPtr(); -} - -DevToolsBridgeClient::DevToolsBridgeClient( - Profile* profile, - SigninManagerBase* signin_manager, - ProfileOAuth2TokenService* token_service) - : WebContentsObserver(), - profile_(profile), - identity_provider_(signin_manager, token_service, base::Closure()), - worker_is_loaded_(false), - weak_factory_(this) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - - identity_provider_.AddObserver(this); - registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED, - content::Source<Profile>(profile_)); - - if (IsAuthenticated()) - CreateBackgroundWorker(); -} - -DevToolsBridgeClient::~DevToolsBridgeClient() { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - - identity_provider_.RemoveObserver(this); -} - -void DevToolsBridgeClient::DeleteSelf() { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - delete this; -} - -void DevToolsBridgeClient::UpdateBrowserList() { - if (!IsAuthenticated() || browser_list_request_.get()) - return; - browser_list_request_ = CreateGCDApiFlow(); - browser_list_request_->Start( - make_scoped_ptr(new DevToolsBridgeInstancesRequest(this))); -} - -void DevToolsBridgeClient::StartSessionIfNeeded( - const std::string& socket_name) { - if (!background_worker_.get() || !background_worker_->GetWebUI() || - !worker_is_loaded_) { - return; - } - - const size_t kPrefixLength = sizeof(kDeviceIdPrefix) - 1; - if (socket_name.substr(0, kPrefixLength) != kDeviceIdPrefix) - return; - - std::string browser_id = socket_name.substr(kPrefixLength); - background_worker_->GetWebUI()->CallJavascriptFunction( - "WebRTCDeviceProvider.instance.startSessionIfNeeded", - base::StringValue(browser_id)); -} - -// static -DevToolsBridgeClient* DevToolsBridgeClient::FromWebContents( - WebContents* web_contents) { - auto user_data = BackgroundWorkerUserData::FromWebContents(web_contents); - return user_data ? user_data->client() : nullptr; -} - -void DevToolsBridgeClient::RegisterMessageHandlers(content::WebUI* web_ui) { - web_ui->RegisterMessageCallback( - "sendCommand", base::Bind(&DevToolsBridgeClient::HandleSendCommand, - base::Unretained(this))); -} - -bool DevToolsBridgeClient::IsAuthenticated() { - return !identity_provider_.GetActiveAccountId().empty(); -} - -void DevToolsBridgeClient::HandleSendCommand(const base::ListValue* args) { - if (args->GetSize() != 1) - return; - - const base::DictionaryValue* command_value; - if (!args->GetDictionary(0, &command_value)) - return; - - send_command_request_ = CreateGCDApiFlow(); - send_command_request_->Start( - make_scoped_ptr(new SendCommandRequest(command_value, this))); -} - -scoped_ptr<local_discovery::GCDApiFlow> -DevToolsBridgeClient::CreateGCDApiFlow() { - DCHECK(IsAuthenticated()); - return local_discovery::GCDApiFlow::Create( - profile_->GetRequestContext(), identity_provider_.GetTokenService(), - identity_provider_.GetActiveAccountId()); -} - -// static -DevToolsBridgeClient::SerialList DevToolsBridgeClient::GetDevices( - base::WeakPtr<DevToolsBridgeClient> weak_ptr) { - SerialList result; - if (auto* ptr = weak_ptr.get()) { - if (ptr->background_worker_.get()) - result.push_back(kSerial); - - ptr->UpdateBrowserList(); - } - return result; -} - -// static -DevToolsBridgeClient::DeviceInfo DevToolsBridgeClient::GetDeviceInfo( - base::WeakPtr<DevToolsBridgeClient> weak_self, - const std::string& serial) { - DeviceInfo result; - if (auto* self = weak_self.get()) { - result.connected = !!self->background_worker_.get(); - result.model = kPseudoDeviceName; - result.browser_info = self->browsers_; - } - return result; -} - -void DevToolsBridgeClient::CreateBackgroundWorker() { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - - background_worker_.reset( - WebContents::Create(WebContents::CreateParams(profile_))); - - BackgroundWorkerUserData::CreateForWebContents(background_worker_.get()); - BackgroundWorkerUserData::FromWebContents(background_worker_.get()) - ->SetClient(this); - WebContentsObserver::Observe(background_worker_.get()); - - GURL url(kBackgroundWorkerURL); - DCHECK_EQ(chrome::kChromeUIWebRTCDeviceProviderHost, url.host()); - - background_worker_->GetController().LoadURL(url, content::Referrer(), - ui::PAGE_TRANSITION_AUTO_TOPLEVEL, - std::string()); -} - -void DevToolsBridgeClient::DocumentOnLoadCompletedInMainFrame() { - worker_is_loaded_ = true; -} - -void DevToolsBridgeClient::Observe( - int type, - const content::NotificationSource& source, - const content::NotificationDetails& details) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - DCHECK_EQ(chrome::NOTIFICATION_PROFILE_DESTROYED, type); - - delete this; -} - -void DevToolsBridgeClient::OnActiveAccountLogin() { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - CreateBackgroundWorker(); -} - -void DevToolsBridgeClient::OnActiveAccountLogout() { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - background_worker_.reset(); - browser_list_request_.reset(); - send_command_request_.reset(); - BrowserInfoList().swap(browsers_); - worker_is_loaded_ = false; -} - -void DevToolsBridgeClient::OnCommandSucceeded( - const base::DictionaryValue& response) { - if (background_worker_.get() && background_worker_->GetWebUI()) { - background_worker_->GetWebUI()->CallJavascriptFunction( - "WebRTCDeviceProvider.instance.handleCommandSuccess", response); - } - send_command_request_.reset(); -} - -void DevToolsBridgeClient::OnCommandFailed() { - if (background_worker_.get() && background_worker_->GetWebUI()) { - background_worker_->GetWebUI()->CallJavascriptFunction( - "WebRTCDeviceProvider.instance.handleCommandFailure"); - } - send_command_request_.reset(); -} - -void DevToolsBridgeClient::OnDevToolsBridgeInstancesRequestSucceeded( - const DevToolsBridgeInstancesRequest::InstanceList& instances) { - BrowserInfoList browsers; - for (const auto& instance : instances) { - BrowserInfo browser; - browser.type = BrowserInfo::kTypeChrome; - browser.display_name = instance.display_name; - browser.socket_name = kDeviceIdPrefix + instance.id; - browsers.push_back(browser); - } - browsers_.swap(browsers); - - browser_list_request_.reset(); - - OnBrowserListUpdatedForTests(); -} - -void DevToolsBridgeClient::OnDevToolsBridgeInstancesRequestFailed() { - // We keep the list of remote browsers even if the request failed. - browser_list_request_.reset(); -}
diff --git a/chrome/browser/devtools/device/webrtc/devtools_bridge_client.h b/chrome/browser/devtools/device/webrtc/devtools_bridge_client.h deleted file mode 100644 index f107e2e..0000000 --- a/chrome/browser/devtools/device/webrtc/devtools_bridge_client.h +++ /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. - -#ifndef CHROME_BROWSER_DEVTOOLS_DEVICE_WEBRTC_DEVTOOLS_BRIDGE_CLIENT_H_ -#define CHROME_BROWSER_DEVTOOLS_DEVICE_WEBRTC_DEVTOOLS_BRIDGE_CLIENT_H_ - -#include "base/macros.h" -#include "chrome/browser/devtools/device/android_device_manager.h" -#include "chrome/browser/devtools/device/webrtc/devtools_bridge_instances_request.h" -#include "chrome/browser/devtools/device/webrtc/send_command_request.h" -#include "chrome/browser/local_discovery/cloud_device_list_delegate.h" -#include "components/signin/core/browser/profile_identity_provider.h" -#include "content/public/browser/notification_observer.h" -#include "content/public/browser/notification_registrar.h" -#include "content/public/browser/web_contents_observer.h" -#include "google_apis/gaia/identity_provider.h" - -class Profile; -class SigninManagerBase; -class ProfileOAuth2TokenService; - -namespace content { -class WebUI; -} // namespace content - -namespace local_discovery { -class GCDApiFlow; -} // local_discovery - -// Lives on the UI thread. -class DevToolsBridgeClient : protected content::WebContentsObserver, - private content::NotificationObserver, - private IdentityProvider::Observer, - private SendCommandRequest::Delegate, - private DevToolsBridgeInstancesRequest::Delegate { - public: - using BrowserInfo = AndroidDeviceManager::BrowserInfo; - using DeviceInfo = AndroidDeviceManager::DeviceInfo; - using SerialList = std::vector<std::string>; - using BrowserInfoList = std::vector<BrowserInfo>; - - static base::WeakPtr<DevToolsBridgeClient> Create( - Profile* profile, - SigninManagerBase* signin_manager, - ProfileOAuth2TokenService* token_service); - - void DeleteSelf(); - - static SerialList GetDevices(base::WeakPtr<DevToolsBridgeClient> weak_ptr); - static DeviceInfo GetDeviceInfo(base::WeakPtr<DevToolsBridgeClient> weak_ptr, - const std::string& serial); - void StartSessionIfNeeded(const std::string& socket_name); - - static DevToolsBridgeClient* FromWebContents( - content::WebContents* web_contents); - void RegisterMessageHandlers(content::WebUI* web_ui); - - protected: - DevToolsBridgeClient(Profile* profile, - SigninManagerBase* signin_manager, - ProfileOAuth2TokenService* token_service); - - // Implementation of content::WebContentsObserver. - void DocumentOnLoadCompletedInMainFrame() override; - - ~DevToolsBridgeClient() override; - - bool IsAuthenticated(); - - // Overridden in tests. - virtual scoped_ptr<local_discovery::GCDApiFlow> CreateGCDApiFlow(); - virtual void OnBrowserListUpdatedForTests() {} - - const BrowserInfoList& browsers() const { return browsers_; } - ProfileIdentityProvider& identity_provider() { return identity_provider_; } - - private: - void CreateBackgroundWorker(); - void UpdateBrowserList(); - - void HandleSendCommand(const base::ListValue* args); - - // Implementation of IdentityProvider::Observer. - void OnActiveAccountLogin() override; - void OnActiveAccountLogout() override; - - // Implementation of NotificationObserver. - void Observe(int type, - const content::NotificationSource& source, - const content::NotificationDetails& details) override; - - // Implementation of SendCommandRequest::Delegate. - void OnCommandSucceeded(const base::DictionaryValue& response) override; - void OnCommandFailed() override; - - // Implementation of DevToolsBridgeInstancesRequest::Delegate. - void OnDevToolsBridgeInstancesRequestSucceeded( - const DevToolsBridgeInstancesRequest::InstanceList& instances) override; - void OnDevToolsBridgeInstancesRequestFailed() override; - - Profile* const profile_; - ProfileIdentityProvider identity_provider_; - content::NotificationRegistrar registrar_; - scoped_ptr<content::WebContents> background_worker_; - scoped_ptr<local_discovery::GCDApiFlow> browser_list_request_; - scoped_ptr<local_discovery::GCDApiFlow> send_command_request_; - BrowserInfoList browsers_; - bool worker_is_loaded_; - base::WeakPtrFactory<DevToolsBridgeClient> weak_factory_; - - DISALLOW_COPY_AND_ASSIGN(DevToolsBridgeClient); -}; - -#endif // CHROME_BROWSER_DEVTOOLS_DEVICE_WEBRTC_DEVTOOLS_BRIDGE_CLIENT_H_
diff --git a/chrome/browser/devtools/device/webrtc/devtools_bridge_client_browsertest.cc b/chrome/browser/devtools/device/webrtc/devtools_bridge_client_browsertest.cc deleted file mode 100644 index 7736644f..0000000 --- a/chrome/browser/devtools/device/webrtc/devtools_bridge_client_browsertest.cc +++ /dev/null
@@ -1,185 +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/devtools/device/webrtc/devtools_bridge_client_browsertest.h" - -#include <utility> - -#include "chrome/browser/devtools/device/webrtc/devtools_bridge_client.h" -#include "chrome/browser/local_discovery/gcd_api_flow.h" -#include "chrome/browser/signin/account_tracker_service_factory.h" -#include "chrome/browser/signin/fake_signin_manager_builder.h" -#include "chrome/browser/ui/browser.h" -#include "components/signin/core/browser/account_tracker_service.h" -#include "components/signin/core/browser/fake_profile_oauth2_token_service.h" -#include "content/public/browser/web_ui_message_handler.h" - -namespace { - -const char kGaiaId[] = "stub-user@example.com"; -const char kUsername[] = "stub-user@example.com"; - -} // namespace - -class DevToolsBridgeClientBrowserTest::GCDApiFlowMock - : public local_discovery::GCDApiFlow { - public: - explicit GCDApiFlowMock(DevToolsBridgeClientBrowserTest* test) - : test_(test), id_(++test->last_flow_id_) { - test_->flows_[id_] = this; - } - - ~GCDApiFlowMock() override { test_->flows_.erase(id_); } - - // Passes request's data to the JS test. Result will be passed back - // in MessageHandler::Response. - void Start(scoped_ptr<Request> request) override { - request_ = std::move(request); - - std::string type; - std::string data; - request_->GetUploadData(&type, &data); - - ScopedVector<const base::Value> params; - params.push_back(new base::FundamentalValue(id_)); - params.push_back(new base::StringValue(request_->GetURL().spec())); - params.push_back(new base::StringValue(data)); - - test_->RunJavascriptFunction("callbacks.gcdApiRequest", params); - } - - void Respond(const base::DictionaryValue* response) { - if (request_.get()) - request_->OnGCDAPIFlowComplete(*response); - } - - private: - DevToolsBridgeClientBrowserTest* const test_; - const int id_; - scoped_ptr<Request> request_; -}; - -class DevToolsBridgeClientBrowserTest::DevToolsBridgeClientMock - : public DevToolsBridgeClient, - public base::SupportsWeakPtr<DevToolsBridgeClientMock> { - public: - explicit DevToolsBridgeClientMock(DevToolsBridgeClientBrowserTest* test) - : DevToolsBridgeClient(test->browser()->profile(), - test->fake_signin_manager_.get(), - test->fake_token_service_.get()), - test_(test) {} - - ~DevToolsBridgeClientMock() override {} - - void DocumentOnLoadCompletedInMainFrame() override { - DevToolsBridgeClient::DocumentOnLoadCompletedInMainFrame(); - - test_->RunJavascriptFunction("callbacks.workerLoaded"); - } - - void OnBrowserListUpdatedForTests() override { - int count = static_cast<int>(browsers().size()); - test_->RunJavascriptFunction("callbacks.browserListUpdated", - new base::FundamentalValue(count)); - } - - scoped_ptr<local_discovery::GCDApiFlow> CreateGCDApiFlow() override { - return make_scoped_ptr(new GCDApiFlowMock(test_)); - } - - void GoogleSigninSucceeded() { - // This username is checked on Chrome OS. - const std::string account_id = - AccountTrackerServiceFactory::GetForProfile( - test_->browser()->profile()) - ->PickAccountIdForAccount(kGaiaId, kUsername); - test_->fake_signin_manager_->SetAuthenticatedAccountInfo(kGaiaId, - kUsername); - identity_provider().GoogleSigninSucceeded(account_id, kUsername, - "password"); - } - - private: - DevToolsBridgeClientBrowserTest* const test_; -}; - -class DevToolsBridgeClientBrowserTest::MessageHandler - : public content::WebUIMessageHandler { - public: - explicit MessageHandler(DevToolsBridgeClientBrowserTest* test) - : test_(test) {} - - void RegisterMessages() override { - web_ui()->RegisterMessageCallback( - "signIn", base::Bind(&MessageHandler::SignIn, base::Unretained(this))); - web_ui()->RegisterMessageCallback( - "gcdApiResponse", - base::Bind(&MessageHandler::GCDApiResponse, base::Unretained(this))); - web_ui()->RegisterMessageCallback( - "queryDevices", - base::Bind(&MessageHandler::QueryDevices, base::Unretained(this))); - } - - void SignIn(const base::ListValue*) { - if (test_->client_mock_.get()) - test_->client_mock_->GoogleSigninSucceeded(); - const std::string account_id = - AccountTrackerServiceFactory::GetForProfile( - test_->browser()->profile())->PickAccountIdForAccount(kGaiaId, - kUsername); - test_->fake_token_service_->UpdateCredentials(account_id, "token"); - } - - void GCDApiResponse(const base::ListValue* params) { - CHECK(params->GetSize() >= 2); - int id; - const base::DictionaryValue* response; - CHECK(params->GetInteger(0, &id)); - CHECK(params->GetDictionary(1, &response)); - - auto flow = test_->flows_.find(id); - CHECK(test_->flows_.end() != flow); - flow->second->Respond(response); - } - - void QueryDevices(const base::ListValue*) { - DevToolsBridgeClient::GetDevices(test_->client_mock_); - } - - private: - DevToolsBridgeClientBrowserTest* const test_; -}; - -DevToolsBridgeClientBrowserTest::DevToolsBridgeClientBrowserTest() - : last_flow_id_(0) { -} - -DevToolsBridgeClientBrowserTest::~DevToolsBridgeClientBrowserTest() { - DCHECK(flows_.empty()); -} - -void DevToolsBridgeClientBrowserTest::SetUpOnMainThread() { - WebUIBrowserTest::SetUpOnMainThread(); - - DCHECK(browser()->profile()); - fake_signin_manager_.reset( - new FakeSigninManagerForTesting(browser()->profile())); - fake_token_service_.reset(new FakeProfileOAuth2TokenService()); - client_mock_ = (new DevToolsBridgeClientMock(this))->AsWeakPtr(); -} - -void DevToolsBridgeClientBrowserTest::TearDownOnMainThread() { - if (client_mock_.get()) - client_mock_->DeleteSelf(); - fake_token_service_.reset(); - fake_signin_manager_.reset(); - WebUIBrowserTest::TearDownOnMainThread(); -} - -content::WebUIMessageHandler* -DevToolsBridgeClientBrowserTest::GetMockMessageHandler() { - if (!handler_.get()) - handler_.reset(new MessageHandler(this)); - return handler_.get(); -}
diff --git a/chrome/browser/devtools/device/webrtc/devtools_bridge_client_browsertest.h b/chrome/browser/devtools/device/webrtc/devtools_bridge_client_browsertest.h deleted file mode 100644 index bfd5a7d..0000000 --- a/chrome/browser/devtools/device/webrtc/devtools_bridge_client_browsertest.h +++ /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. - -#ifndef CHROME_BROWSER_DEVTOOLS_DEVICE_WEBRTC_DEVTOOLS_BRIDGE_CLIENT_BROWSERTEST_H_ -#define CHROME_BROWSER_DEVTOOLS_DEVICE_WEBRTC_DEVTOOLS_BRIDGE_CLIENT_BROWSERTEST_H_ - -#include "chrome/browser/signin/fake_signin_manager_builder.h" -#include "chrome/test/base/web_ui_browser_test.h" - -class ProfileOAuth2TokenService; - -namespace content { -class WebUIMessageHandler; -} - -class DevToolsBridgeClientBrowserTest : public WebUIBrowserTest { - public: - DevToolsBridgeClientBrowserTest(); - ~DevToolsBridgeClientBrowserTest() override; - - // InProcessBrowserTest overrides. - void SetUpOnMainThread() override; - void TearDownOnMainThread() override; - content::WebUIMessageHandler* GetMockMessageHandler() override; - - private: - class DevToolsBridgeClientMock; - class GCDApiFlowMock; - class MessageHandler; - - scoped_ptr<FakeSigninManagerForTesting> fake_signin_manager_; - scoped_ptr<ProfileOAuth2TokenService> fake_token_service_; - base::WeakPtr<DevToolsBridgeClientMock> client_mock_; - scoped_ptr<MessageHandler> handler_; - std::map<int, GCDApiFlowMock*> flows_; - int last_flow_id_; -}; - -#endif // CHROME_BROWSER_DEVTOOLS_DEVICE_WEBRTC_DEVTOOLS_BRIDGE_CLIENT_BROWSERTEST_H_
diff --git a/chrome/browser/devtools/device/webrtc/devtools_bridge_client_browsertest.js b/chrome/browser/devtools/device/webrtc/devtools_bridge_client_browsertest.js deleted file mode 100644 index dbb6738..0000000 --- a/chrome/browser/devtools/device/webrtc/devtools_bridge_client_browsertest.js +++ /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. - -GEN('#include "chrome/browser/devtools/device/webrtc/' + - 'devtools_bridge_client_browsertest.h"'); - -/** - * Test fixture for DevToolsBridgeClientBrowserTest. - * @constructor - * @extends {testing.Test} - */ -function DevToolsBridgeClientBrowserTest() {} - -var DEVICES_URL = "https://www.googleapis.com/clouddevices/v1/devices"; - -DevToolsBridgeClientBrowserTest.prototype = { - __proto__: testing.Test.prototype, - - /** @override */ - typedefCppFixture: 'DevToolsBridgeClientBrowserTest', - - /** @override */ - isAsync: true, - - /** @override */ - browsePreload: DUMMY_URL, - - setUp: function() { - this.callbacksMock = mock(DevToolsBridgeClientBrowserTest.NativeCallbacks); - window.callbacks = this.callbacksMock.proxy(); - }, - - /** - * Simulates user sign in. DevToolsBridgeClient creates - * background_worker only in this case. - */ - signIn: function() { - chrome.send('signIn', []); - return new Promise(function(resolve) { - this.callbacksMock.expects(once()).workerLoaded().will( - callFunction(resolve)); - }.bind(this)); - }, - - /** - * Creates GCD device definition which could be recognized as a - * DevToolsBridge. - * - * @param {string} id GCD instance id. - * @param {string} displayName Display name. - */ - createInstanceDef: function(id, displayName) { - return { - 'kind': 'clouddevices#device', - 'deviceKind': 'vendor', - 'id': id, - 'displayName': displayName, - 'commandDefs': { - 'base': { - '_iceExchange': {'kind': 'clouddevices#commandDef'}, - '_renegotiate': {'kind': 'clouddevices#commandDef'}, - '_startSession': {'kind': 'clouddevices#commandDef'}, - } - }, - }; - } -}; - -/** - * Callbacks from native DevToolsBridgeClientBrowserTest. - * @constructor - */ -DevToolsBridgeClientBrowserTest.NativeCallbacks = function() {} - -DevToolsBridgeClientBrowserTest.NativeCallbacks.prototype = { - workerLoaded: function() {}, - gcdApiRequest: function(id, body) {}, - browserListUpdated: function(count) {}, -}; - -TEST_F('DevToolsBridgeClientBrowserTest', 'testSetUpOnMainThread', function() { - testDone(); -}); - -TEST_F('DevToolsBridgeClientBrowserTest', 'testSignIn', function() { - this.signIn().then(testDone); -}); - -TEST_F('DevToolsBridgeClientBrowserTest', 'testQueryBrowsers', function() { - this.signIn().then(function() { - chrome.send('queryDevices'); - }); - var savedArgs = new SaveMockArguments(); - this.callbacksMock.expects(once()).gcdApiRequest( - savedArgs.match(ANYTHING), DEVICES_URL, '').will( - callFunctionWithSavedArgs(savedArgs, function(id) { - var response = { - 'kind': 'clouddevices#devicesListResponse', - 'devices': [ - this.createInstanceDef( - 'ab911465-83c7-e335-ea64-cb656868cbe0', 'Test 1'), - this.createInstanceDef( - 'ab911465-83c7-e335-ea64-cb656868cbe1', 'Test 2'), - this.createInstanceDef( - 'ab911465-83c7-e335-ea64-cb656868cbe2', 'Test 3'), - ], - }; - chrome.send('gcdApiResponse', [id, response]); - }.bind(this))); - - var browsersCount = 3; - - this.callbacksMock.expects(once()).browserListUpdated(browsersCount).will( - callFunction(testDone)); -});
diff --git a/chrome/browser/devtools/device/webrtc/devtools_bridge_instances_request.cc b/chrome/browser/devtools/device/webrtc/devtools_bridge_instances_request.cc deleted file mode 100644 index 1ddf6e6..0000000 --- a/chrome/browser/devtools/device/webrtc/devtools_bridge_instances_request.cc +++ /dev/null
@@ -1,86 +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/devtools/device/webrtc/devtools_bridge_instances_request.h" - -#include "base/values.h" -#include "components/cloud_devices/common/cloud_devices_urls.h" -#include "net/base/url_util.h" - -namespace { - -std::string GetKind(const base::DictionaryValue& value) { - std::string result; - value.GetString("kind", &result); - return result; -} - -bool HasCommand(const base::DictionaryValue& commands_defs_value, - const std::string& command_name) { - const base::DictionaryValue* command_value; - return commands_defs_value.GetDictionary(command_name, &command_value) && - GetKind(*command_value) == "clouddevices#commandDef"; -} - -} // namespace - -DevToolsBridgeInstancesRequest::Instance::~Instance() { -} - -DevToolsBridgeInstancesRequest::DevToolsBridgeInstancesRequest( - Delegate* delegate) - : delegate_(delegate) { - DCHECK(delegate_); -} - -DevToolsBridgeInstancesRequest::~DevToolsBridgeInstancesRequest() { -} - -void DevToolsBridgeInstancesRequest::OnGCDAPIFlowError( - local_discovery::GCDApiFlow::Status status) { - delegate_->OnDevToolsBridgeInstancesRequestFailed(); -} - -void DevToolsBridgeInstancesRequest::OnGCDAPIFlowComplete( - const base::DictionaryValue& value) { - const base::ListValue* device_list_value = NULL; - if (GetKind(value) == "clouddevices#devicesListResponse" && - value.GetList("devices", &device_list_value)) { - for (const auto& device_value : *device_list_value) { - const base::DictionaryValue* dictionary; - if (device_value->GetAsDictionary(&dictionary)) - TryAddInstance(*dictionary); - } - } - - delegate_->OnDevToolsBridgeInstancesRequestSucceeded(result_); -} - -GURL DevToolsBridgeInstancesRequest::GetURL() { - return cloud_devices::GetCloudDevicesRelativeURL("devices"); -} - -void DevToolsBridgeInstancesRequest::TryAddInstance( - const base::DictionaryValue& device_value) { - if (GetKind(device_value) != "clouddevices#device") - return; - - const base::DictionaryValue* commands_defs_value; - if (!device_value.GetDictionary("commandDefs", &commands_defs_value)) - return; - - if (!HasCommand(*commands_defs_value, "base._startSession") || - !HasCommand(*commands_defs_value, "base._iceExchange") || - !HasCommand(*commands_defs_value, "base._renegotiate")) { - return; - } - - Instance instance; - if (!device_value.GetString("id", &instance.id)) - return; - if (!device_value.GetString("displayName", &instance.display_name)) - return; - - result_.push_back(instance); -}
diff --git a/chrome/browser/devtools/device/webrtc/devtools_bridge_instances_request.h b/chrome/browser/devtools/device/webrtc/devtools_bridge_instances_request.h deleted file mode 100644 index 3763b7e1..0000000 --- a/chrome/browser/devtools/device/webrtc/devtools_bridge_instances_request.h +++ /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. - -#ifndef CHROME_BROWSER_DEVTOOLS_DEVICE_WEBRTC_DEVTOOLS_BRIDGE_INSTANCES_REQUEST_H_ -#define CHROME_BROWSER_DEVTOOLS_DEVICE_WEBRTC_DEVTOOLS_BRIDGE_INSTANCES_REQUEST_H_ - -#include "base/macros.h" -#include "chrome/browser/devtools/device/android_device_manager.h" -#include "chrome/browser/local_discovery/gcd_api_flow.h" - -class DevToolsBridgeInstancesRequest - : public local_discovery::GCDApiFlowRequest { - public: - struct Instance { - std::string id; - std::string display_name; - - ~Instance(); - }; - - using InstanceList = std::vector<Instance>; - - class Delegate { - public: - virtual void OnDevToolsBridgeInstancesRequestSucceeded( - const InstanceList& result) = 0; - virtual void OnDevToolsBridgeInstancesRequestFailed() = 0; - - protected: - ~Delegate() {} - }; - - explicit DevToolsBridgeInstancesRequest(Delegate* delegate); - ~DevToolsBridgeInstancesRequest() override; - - // Implementation of GCDApiFlowRequest. - void OnGCDAPIFlowError(local_discovery::GCDApiFlow::Status status) override; - void OnGCDAPIFlowComplete(const base::DictionaryValue& value) override; - GURL GetURL() override; - - private: - void TryAddInstance(const base::DictionaryValue& device_value); - - Delegate* const delegate_; - InstanceList result_; - - DISALLOW_COPY_AND_ASSIGN(DevToolsBridgeInstancesRequest); -}; - -#endif // CHROME_BROWSER_DEVTOOLS_DEVICE_WEBRTC_DEVTOOLS_BRIDGE_INSTANCES_REQUEST_H_
diff --git a/chrome/browser/devtools/device/webrtc/devtools_bridge_instances_request_unittest.cc b/chrome/browser/devtools/device/webrtc/devtools_bridge_instances_request_unittest.cc deleted file mode 100644 index 3b9710f..0000000 --- a/chrome/browser/devtools/device/webrtc/devtools_bridge_instances_request_unittest.cc +++ /dev/null
@@ -1,61 +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/devtools/device/webrtc/devtools_bridge_instances_request.h" - -#include "base/files/file_util.h" -#include "base/json/json_reader.h" -#include "base/logging.h" -#include "base/memory/scoped_ptr.h" -#include "base/path_service.h" -#include "base/values.h" -#include "chrome/common/chrome_paths.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace { - -class MockDelegate : public DevToolsBridgeInstancesRequest::Delegate { - public: - DevToolsBridgeInstancesRequest::InstanceList instances; - - void OnDevToolsBridgeInstancesRequestSucceeded( - const DevToolsBridgeInstancesRequest::InstanceList& result) override { - instances = result; - } - - void OnDevToolsBridgeInstancesRequestFailed() override {} -}; - -base::FilePath GetTestFilePath(const std::string& file_name) { - base::FilePath path; - if (!PathService::Get(chrome::DIR_TEST_DATA, &path)) - return base::FilePath(); - return path.AppendASCII("devtools") - .AppendASCII("webrtc_device_provider") - .AppendASCII(file_name); -} - -} // namespace - -TEST(DevToolsBridgeInstancesRequestTest, ParseResponse) { - std::string input; - ASSERT_TRUE(base::ReadFileToString( - GetTestFilePath("devtools_bridge_instances_response.json"), &input)); - base::JSONReader reader; - scoped_ptr<base::Value> root(reader.ReadToValue(input)); - ASSERT_TRUE(root.get()) << reader.GetErrorMessage(); - EXPECT_TRUE(root->IsType(base::Value::TYPE_DICTIONARY)); - - const base::DictionaryValue* dictionary = NULL; - ASSERT_TRUE(root->GetAsDictionary(&dictionary)); - - MockDelegate delegate; - - delegate.instances.resize(10); - - DevToolsBridgeInstancesRequest(&delegate).OnGCDAPIFlowComplete(*dictionary); - - ASSERT_TRUE(delegate.instances.size() == 1); - ASSERT_EQ("ab911465-83c7-e335-ea64-cb656868cbe0", delegate.instances[0].id); -}
diff --git a/chrome/browser/devtools/device/webrtc/js/webrtc_device_provider.js b/chrome/browser/devtools/device/webrtc/js/webrtc_device_provider.js deleted file mode 100644 index a9e67fe..0000000 --- a/chrome/browser/devtools/device/webrtc/js/webrtc_device_provider.js +++ /dev/null
@@ -1,28 +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. - -/** - * @constructor - */ -function WebRTCDeviceProvider() { -} - -WebRTCDeviceProvider.prototype.handleCommandFailure = function() { - // TODO(serya): Remove debugging code and implement. - console.error('Command failed'); -}; - -WebRTCDeviceProvider.prototype.handleCommandSuccess = function(result) { - // TODO(serya): Remove debugging code and implement. - console.log('Command succeded', result); -}; - -WebRTCDeviceProvider.prototype.startSessionIfNeeded = function(deviceId) { - // TODO(serya): Remove debugging code and implement. - this.lastDeviceId = deviceId; -}; - -addEventListener('DOMContentLoaded', function() { - window.WebRTCDeviceProvider.instance = new WebRTCDeviceProvider(); -}, false);
diff --git a/chrome/browser/devtools/device/webrtc/resources.grd b/chrome/browser/devtools/device/webrtc/resources.grd deleted file mode 100644 index 01524333..0000000 --- a/chrome/browser/devtools/device/webrtc/resources.grd +++ /dev/null
@@ -1,17 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<grit latest_public_release="0" current_release="1"> - <outputs> - <output filename="grit/webrtc_device_provider_resources.h" type="rc_header"> - <emit emit_type='prepend'></emit> - </output> - <output filename="grit/webrtc_device_provider_resources_map.cc" type="resource_file_map_source" /> - <output filename="grit/webrtc_device_provider_resources_map.h" type="resource_map_header" /> - <output filename="webrtc_device_provider_resources.pak" type="data_package" /> - </outputs> - <release seq="1"> - <includes> - <include name="IDR_BACKGROUND_WORKER_HTML" file="background_worker.html" flattenhtml="false" allowexternalscript="true" type="BINDATA" /> - <include name="IDR_WEBRTC_DEVICE_PROVIDER_JS" file="js/webrtc_device_provider.js" type="BINDATA" /> - </includes> - </release> -</grit>
diff --git a/chrome/browser/devtools/device/webrtc/send_command_request.cc b/chrome/browser/devtools/device/webrtc/send_command_request.cc deleted file mode 100644 index 7bfe5f4..0000000 --- a/chrome/browser/devtools/device/webrtc/send_command_request.cc +++ /dev/null
@@ -1,53 +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/devtools/device/webrtc/send_command_request.h" - -#include "base/json/json_writer.h" -#include "base/values.h" -#include "components/cloud_devices/common/cloud_devices_urls.h" -#include "net/base/url_util.h" - -using local_discovery::GCDApiFlow; -using local_discovery::GCDApiFlowRequest; - -namespace { - -const char kContentTypeJSON[] = "application/json"; -const char kCommandTimeoutMs[] = "20000"; - -} // namespace - -SendCommandRequest::SendCommandRequest(const base::DictionaryValue* request, - Delegate* delegate) - : delegate_(delegate) { - base::JSONWriter::Write(*request, &upload_data_); - DCHECK(delegate_); -} - -net::URLFetcher::RequestType SendCommandRequest::GetRequestType() { - return net::URLFetcher::POST; -} - -void SendCommandRequest::GetUploadData(std::string* upload_type, - std::string* upload_data) { - *upload_type = kContentTypeJSON; - *upload_data = upload_data_; -} - -void SendCommandRequest::OnGCDAPIFlowError(GCDApiFlow::Status status) { - delegate_->OnCommandFailed(); -} - -void SendCommandRequest::OnGCDAPIFlowComplete( - const base::DictionaryValue& value) { - delegate_->OnCommandSucceeded(value); -} - -GURL SendCommandRequest::GetURL() { - GURL url = cloud_devices::GetCloudDevicesRelativeURL("commands"); - url = net::AppendQueryParameter(url, "expireInMs", kCommandTimeoutMs); - url = net::AppendQueryParameter(url, "responseAwaitMs", kCommandTimeoutMs); - return url; -}
diff --git a/chrome/browser/devtools/device/webrtc/send_command_request.h b/chrome/browser/devtools/device/webrtc/send_command_request.h deleted file mode 100644 index 045dd7c..0000000 --- a/chrome/browser/devtools/device/webrtc/send_command_request.h +++ /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. - -#ifndef CHROME_BROWSER_DEVTOOLS_DEVICE_WEBRTC_SEND_COMMAND_REQUEST_H_ -#define CHROME_BROWSER_DEVTOOLS_DEVICE_WEBRTC_SEND_COMMAND_REQUEST_H_ - -#include "base/macros.h" -#include "chrome/browser/local_discovery/gcd_api_flow.h" - -class SendCommandRequest : public local_discovery::GCDApiFlowRequest { - public: - class Delegate { - public: - // It's safe to destroy SendCommandRequest in these methods. - virtual void OnCommandSucceeded(const base::DictionaryValue& value) = 0; - virtual void OnCommandFailed() = 0; - - protected: - ~Delegate() {} - }; - - SendCommandRequest(const base::DictionaryValue* request, Delegate* delegate); - - // Implementation of GCDApiFlowRequest. - net::URLFetcher::RequestType GetRequestType() override; - void GetUploadData(std::string* upload_type, - std::string* upload_data) override; - void OnGCDAPIFlowError(local_discovery::GCDApiFlow::Status status) override; - void OnGCDAPIFlowComplete(const base::DictionaryValue& value) override; - GURL GetURL() override; - - private: - std::string upload_data_; - Delegate* const delegate_; - - DISALLOW_COPY_AND_ASSIGN(SendCommandRequest); -}; - -#endif // CHROME_BROWSER_DEVTOOLS_DEVICE_WEBRTC_SEND_COMMAND_REQUEST_H_
diff --git a/chrome/browser/devtools/device/webrtc/webrtc_device_provider.cc b/chrome/browser/devtools/device/webrtc/webrtc_device_provider.cc deleted file mode 100644 index ec49e2e0..0000000 --- a/chrome/browser/devtools/device/webrtc/webrtc_device_provider.cc +++ /dev/null
@@ -1,94 +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/devtools/device/webrtc/webrtc_device_provider.h" - -#include <stddef.h> - -#include "base/location.h" -#include "base/single_thread_task_runner.h" -#include "base/thread_task_runner_handle.h" -#include "chrome/browser/devtools/device/webrtc/devtools_bridge_client.h" -#include "chrome/common/url_constants.h" -#include "content/public/browser/web_ui.h" -#include "content/public/browser/web_ui_data_source.h" -#include "grit/webrtc_device_provider_resources_map.h" -#include "net/base/net_errors.h" -#include "net/socket/stream_socket.h" - -using content::BrowserThread; -using content::WebUIDataSource; - -// WebRTCDeviceProvider::WebUI ------------------------------------------------- - -WebRTCDeviceProvider::WebUI::WebUI(content::WebUI* web_ui) - : content::WebUIController(web_ui) { - Profile* profile = Profile::FromWebUI(web_ui); - - WebUIDataSource* source = WebUIDataSource::Create( - chrome::kChromeUIWebRTCDeviceProviderHost); - - for (size_t i = 0; i < kWebrtcDeviceProviderResourcesSize; i++) { - source->AddResourcePath(kWebrtcDeviceProviderResources[i].name, - kWebrtcDeviceProviderResources[i].value); - } - - auto client = - DevToolsBridgeClient::FromWebContents(web_ui->GetWebContents()); - if (client) - client->RegisterMessageHandlers(web_ui); - - WebUIDataSource::Add(profile, source); -} - -WebRTCDeviceProvider::WebUI::~WebUI() { -} - -// WebRTCDeviceProvider -------------------------------------------------------- - -WebRTCDeviceProvider::WebRTCDeviceProvider( - Profile* profile, - SigninManagerBase* signin_manager, - ProfileOAuth2TokenService* token_service) - : client_(DevToolsBridgeClient::Create( - profile, signin_manager, token_service)) { -} - -WebRTCDeviceProvider::~WebRTCDeviceProvider() { - BrowserThread::PostTask( - BrowserThread::UI, - FROM_HERE, - base::Bind(&DevToolsBridgeClient::DeleteSelf, client_)); -} - -void WebRTCDeviceProvider::QueryDevices(const SerialsCallback& callback) { - BrowserThread::PostTaskAndReplyWithResult( - BrowserThread::UI, - FROM_HERE, - base::Bind(&DevToolsBridgeClient::GetDevices, client_), - callback); -} - -void WebRTCDeviceProvider::QueryDeviceInfo(const std::string& serial, - const DeviceInfoCallback& callback) { - BrowserThread::PostTaskAndReplyWithResult( - BrowserThread::UI, - FROM_HERE, - base::Bind(&DevToolsBridgeClient::GetDeviceInfo, client_, serial), - callback); -} - -void WebRTCDeviceProvider::OpenSocket(const std::string& serial, - const std::string& socket_name, - const SocketCallback& callback) { - BrowserThread::PostTask( - BrowserThread::UI, - FROM_HERE, - base::Bind(&DevToolsBridgeClient::StartSessionIfNeeded, - client_, socket_name)); - // TODO(serya): Implement - scoped_ptr<net::StreamSocket> socket; - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::Bind(callback, net::ERR_FAILED, base::Passed(&socket))); -}
diff --git a/chrome/browser/devtools/device/webrtc/webrtc_device_provider.h b/chrome/browser/devtools/device/webrtc/webrtc_device_provider.h deleted file mode 100644 index 0663fe9..0000000 --- a/chrome/browser/devtools/device/webrtc/webrtc_device_provider.h +++ /dev/null
@@ -1,59 +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_DEVTOOLS_DEVICE_WEBRTC_WEBRTC_DEVICE_PROVIDER_H_ -#define CHROME_BROWSER_DEVTOOLS_DEVICE_WEBRTC_WEBRTC_DEVICE_PROVIDER_H_ - -#include "base/macros.h" -#include "chrome/browser/devtools/device/android_device_manager.h" -#include "content/public/browser/web_ui_controller.h" - -namespace content { -class WebUI; -} - -class DevToolsBridgeClient; -class OAuth2TokenService; -class Profile; -class ProfileOAuth2TokenService; -class SigninManagerBase; - -// Provides access to remote DevTools targets over WebRTC data channel and GCD. -class WebRTCDeviceProvider final : public AndroidDeviceManager::DeviceProvider { - public: - /** - * Provides resources for provider's background worker. Background worker - * is a windowless page that implements most of functionality of the - * provider. It sandboxes WebRTC connections with remote devices and other - * provider implementation details. - */ - class WebUI : public content::WebUIController { - public: - explicit WebUI(content::WebUI* web_ui); - ~WebUI() override; - }; - - WebRTCDeviceProvider(Profile* profile, - SigninManagerBase* signin_manager, - ProfileOAuth2TokenService* token_service); - - // AndroidDeviceManager::DeviceProvider implementation. - void QueryDevices(const SerialsCallback& callback) override; - - void QueryDeviceInfo(const std::string& serial, - const DeviceInfoCallback& callback) override; - - void OpenSocket(const std::string& serial, - const std::string& socket_name, - const SocketCallback& callback) override; - - private: - ~WebRTCDeviceProvider() override; - - const base::WeakPtr<DevToolsBridgeClient> client_; - - DISALLOW_COPY_AND_ASSIGN(WebRTCDeviceProvider); -}; - -#endif // CHROME_BROWSER_DEVTOOLS_DEVICE_WEBRTC_WEBRTC_DEVICE_PROVIDER_H_
diff --git a/chrome/browser/devtools/device/webrtc/webrtc_device_provider_browsertest.cc b/chrome/browser/devtools/device/webrtc/webrtc_device_provider_browsertest.cc deleted file mode 100644 index 3b461ff..0000000 --- a/chrome/browser/devtools/device/webrtc/webrtc_device_provider_browsertest.cc +++ /dev/null
@@ -1,52 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/bind.h" -#include "chrome/browser/devtools/device/webrtc/webrtc_device_provider.h" -#include "chrome/browser/signin/profile_oauth2_token_service_factory.h" -#include "chrome/browser/signin/signin_manager_factory.h" -#include "chrome/browser/ui/browser.h" -#include "chrome/test/base/in_process_browser_test.h" -#include "components/signin/core/browser/signin_manager.h" -#include "content/public/browser/browser_thread.h" -#include "content/public/test/test_utils.h" - -using content::BrowserThread; -using content::MessageLoopRunner; - -class WebRtcDeviceProviderTest : public InProcessBrowserTest { - protected: - scoped_refptr<WebRTCDeviceProvider> CreateProvider(); - static void Unreference( - scoped_refptr<WebRTCDeviceProvider> provider); - - scoped_refptr<WebRTCDeviceProvider> provider_; -}; - -scoped_refptr<WebRTCDeviceProvider> -WebRtcDeviceProviderTest::CreateProvider() { - return new WebRTCDeviceProvider( - browser()->profile(), - SigninManagerFactory::GetForProfile(browser()->profile()), - ProfileOAuth2TokenServiceFactory::GetForProfile(browser()->profile())); -} - -// static -void WebRtcDeviceProviderTest::Unreference( - scoped_refptr<WebRTCDeviceProvider> provider) { -} - -IN_PROC_BROWSER_TEST_F(WebRtcDeviceProviderTest, TestDeleteSelf) { - scoped_refptr<MessageLoopRunner> runner = new MessageLoopRunner; - BrowserThread::PostTaskAndReply( - BrowserThread::IO, - FROM_HERE, - base::Bind(&Unreference, CreateProvider()), - runner->QuitClosure()); - runner->Run(); -} - -IN_PROC_BROWSER_TEST_F(WebRtcDeviceProviderTest, OutliveProfile) { - provider_ = CreateProvider(); -}
diff --git a/chrome/browser/devtools/webrtc_device_provider_resources.gyp b/chrome/browser/devtools/webrtc_device_provider_resources.gyp deleted file mode 100644 index 35d645f..0000000 --- a/chrome/browser/devtools/webrtc_device_provider_resources.gyp +++ /dev/null
@@ -1,26 +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. - -{ - 'targets': [ - { - # GN version: //chrome/browser/devtools:webrtc_device_provider_resources - 'target_name': 'webrtc_device_provider_resources', - 'type': 'none', - 'variables': { - 'grit_out_dir': '<(SHARED_INTERMEDIATE_DIR)/chrome', - }, - 'actions': [ - { - 'action_name': 'generate_webrtc_device_provider_resources', - 'variables': { - 'grit_grd_file': 'device/webrtc/resources.grd', - }, - 'includes': [ '../../../build/grit_action.gypi' ], - }, - ], - 'includes': [ '../../../build/grit_target.gypi' ], - }, - ] -}
diff --git a/chrome/browser/download/download_query.cc b/chrome/browser/download/download_query.cc index f42e93d0..a1819f3 100644 --- a/chrome/browser/download/download_query.cc +++ b/chrome/browser/download/download_query.cc
@@ -242,8 +242,7 @@ return true; } -DownloadQuery::DownloadQuery() - : limit_(std::numeric_limits<uint32_t>::max()), skip_(0U) {} +DownloadQuery::DownloadQuery() : limit_(std::numeric_limits<uint32_t>::max()) {} DownloadQuery::~DownloadQuery() {} // AddFilter() pushes a new FilterCallback to filters_. Most FilterCallbacks are @@ -435,21 +434,13 @@ } void DownloadQuery::FinishSearch(DownloadQuery::DownloadVector* results) const { - if (skip_ >= results->size()) { - results->clear(); - return; + if (!sorters_.empty()) { + std::partial_sort(results->begin(), + results->begin() + std::min(limit_, results->size()), + results->end(), + DownloadComparator(sorters_)); } - if (!sorters_.empty()) { - std::partial_sort( - results->begin(), - results->begin() + std::min(limit_ + skip_, results->size()), - results->end(), - DownloadComparator(sorters_)); - } - - results->erase(results->begin(), results->begin() + skip_); - if (results->size() > limit_) results->resize(limit_); }
diff --git a/chrome/browser/download/download_query.h b/chrome/browser/download/download_query.h index e81edc5..980e531 100644 --- a/chrome/browser/download/download_query.h +++ b/chrome/browser/download/download_query.h
@@ -39,7 +39,6 @@ // query.AddSorter(SORT_BYTES_RECEIVED, ASCENDING); // query.AddSorter(SORT_URL, DESCENDING); // query.Limit(20); -// query.Skip(5); // DownloadVector all_items, results; // query.Search(all_items.begin(), all_items.end(), &results); class DownloadQuery { @@ -128,11 +127,6 @@ // Limit the size of search results to |limit|. void Limit(size_t limit) { limit_ = limit; } - // Ignore |skip| items. Note: which items are skipped are not guaranteed to - // always be the same. If you rely on this, you should probably be using - // AddSorter() in conjunction with this method. - void Skip(size_t skip) { skip_ = skip; } - // Filters DownloadItem*s from |iter| to |last| into |results|, sorts // |results|, and limits the size of |results|. |results| must be non-NULL. template <typename InputIterator> @@ -160,7 +154,6 @@ FilterCallbackVector filters_; SorterVector sorters_; size_t limit_; - size_t skip_; DISALLOW_COPY_AND_ASSIGN(DownloadQuery); };
diff --git a/chrome/browser/download/download_query_unittest.cc b/chrome/browser/download/download_query_unittest.cc index 8ffc90a8..37fba0c 100644 --- a/chrome/browser/download/download_query_unittest.cc +++ b/chrome/browser/download/download_query_unittest.cc
@@ -182,35 +182,6 @@ ExpectStandardFilterResults(); } -TEST_F(DownloadQueryTest, DownloadQueryTest_Skip) { - CreateMocks(2); - query()->Skip(1); - Search(); - EXPECT_EQ(1U, results()->size()); -} - -TEST_F(DownloadQueryTest, DownloadQueryTest_SkipMoreThanExist) { - query()->Skip(20); - Search(); - EXPECT_EQ(0U, results()->size()); -} - -TEST_F(DownloadQueryTest, DownloadQueryTest_LimitSkipAndSort) { - const size_t kNumMocks = 10U; - CreateMocks(kNumMocks); - for (size_t i = 0; i < kNumMocks; ++i) { - EXPECT_CALL(mock(i), GetStartTime()).WillRepeatedly(Return( - base::Time::FromTimeT(kSomeKnownTime + 1000 * i))); - } - query()->AddSorter(DownloadQuery::SORT_START_TIME, DownloadQuery::ASCENDING); - query()->Limit(2); - query()->Skip(5); - Search(); - EXPECT_EQ(2U, results()->size()); - EXPECT_EQ(5U, results()->at(0)->GetId()); - EXPECT_EQ(6U, results()->at(1)->GetId()); -} - TEST_F(DownloadQueryTest, DownloadQueryTest_FilterGenericQueryFilename) { CreateMocks(2); EXPECT_CALL(mock(0), GetBrowserContext()).WillRepeatedly(Return(
diff --git a/chrome/browser/engagement/site_engagement_helper_unittest.cc b/chrome/browser/engagement/site_engagement_helper_unittest.cc index 41be8aa4..1e74be28f 100644 --- a/chrome/browser/engagement/site_engagement_helper_unittest.cc +++ b/chrome/browser/engagement/site_engagement_helper_unittest.cc
@@ -21,14 +21,16 @@ class SiteEngagementHelperTest : public BrowserWithTestWindowTest { public: - // Create a SiteEngagementHelper. Called here as friend class methods cannot - // be called in tests. - scoped_ptr<SiteEngagementHelper> CreateHelper( - content::WebContents* web_contents) { - scoped_ptr<SiteEngagementHelper> helper( - new SiteEngagementHelper(web_contents)); - DCHECK(helper.get()); + void SetUp() override { + BrowserWithTestWindowTest::SetUp(); + base::CommandLine::ForCurrentProcess()->AppendSwitch( + switches::kEnableSiteEngagementService); + } + SiteEngagementHelper* GetHelper(content::WebContents* web_contents) { + SiteEngagementHelper* helper = + SiteEngagementHelper::FromWebContents(web_contents); + DCHECK(helper); return helper; } @@ -97,41 +99,41 @@ content::WebContents* web_contents = browser()->tab_strip_model()->GetActiveWebContents(); - scoped_ptr<SiteEngagementHelper> helper(CreateHelper(web_contents)); + SiteEngagementHelper* helper = GetHelper(web_contents); SiteEngagementService* service = SiteEngagementServiceFactory::GetForProfile(browser()->profile()); DCHECK(service); // Check that navigation triggers engagement. NavigateWithDisposition(url1, CURRENT_TAB); - TrackingStarted(helper.get()); + TrackingStarted(helper); EXPECT_DOUBLE_EQ(0.5, service->GetScore(url1)); EXPECT_EQ(0, service->GetScore(url2)); // Simulate a user input trigger and ensure it is treated correctly. - HandleUserInputAndRestartTracking(helper.get(), type); + HandleUserInputAndRestartTracking(helper, type); EXPECT_DOUBLE_EQ(0.55, service->GetScore(url1)); EXPECT_EQ(0, service->GetScore(url2)); // Simulate three inputs , and ensure they are treated correctly. - HandleUserInputAndRestartTracking(helper.get(), type); - HandleUserInputAndRestartTracking(helper.get(), type); - HandleUserInputAndRestartTracking(helper.get(), type); + HandleUserInputAndRestartTracking(helper, type); + HandleUserInputAndRestartTracking(helper, type); + HandleUserInputAndRestartTracking(helper, type); EXPECT_DOUBLE_EQ(0.7, service->GetScore(url1)); EXPECT_EQ(0, service->GetScore(url2)); // Simulate inputs for a different link. NavigateWithDisposition(url2, CURRENT_TAB); - TrackingStarted(helper.get()); + TrackingStarted(helper); EXPECT_DOUBLE_EQ(0.7, service->GetScore(url1)); EXPECT_DOUBLE_EQ(0.5, service->GetScore(url2)); EXPECT_DOUBLE_EQ(1.2, service->GetTotalEngagementPoints()); - HandleUserInputAndRestartTracking(helper.get(), type); + HandleUserInputAndRestartTracking(helper, type); EXPECT_DOUBLE_EQ(0.7, service->GetScore(url1)); EXPECT_DOUBLE_EQ(0.55, service->GetScore(url2)); EXPECT_DOUBLE_EQ(1.25, service->GetTotalEngagementPoints()); @@ -161,48 +163,48 @@ content::WebContents* web_contents = browser()->tab_strip_model()->GetActiveWebContents(); - scoped_ptr<SiteEngagementHelper> helper(CreateHelper(web_contents)); + SiteEngagementHelper* helper = GetHelper(web_contents); SiteEngagementService* service = SiteEngagementServiceFactory::GetForProfile(browser()->profile()); DCHECK(service); NavigateWithDisposition(url1, CURRENT_TAB); - TrackingStarted(helper.get()); + TrackingStarted(helper); EXPECT_DOUBLE_EQ(0.5, service->GetScore(url1)); EXPECT_EQ(0, service->GetScore(url2)); // Simulate a foreground media input and ensure it is treated correctly. - HandleMediaPlaying(helper.get(), false); + HandleMediaPlaying(helper, false); EXPECT_DOUBLE_EQ(0.52, service->GetScore(url1)); EXPECT_EQ(0, service->GetScore(url2)); // Simulate continual media playing, and ensure it is treated correctly. - HandleMediaPlaying(helper.get(), false); - HandleMediaPlaying(helper.get(), false); - HandleMediaPlaying(helper.get(), false); + HandleMediaPlaying(helper, false); + HandleMediaPlaying(helper, false); + HandleMediaPlaying(helper, false); EXPECT_DOUBLE_EQ(0.58, service->GetScore(url1)); EXPECT_EQ(0, service->GetScore(url2)); // Simulate backgrounding the media. - HandleMediaPlaying(helper.get(), true); - HandleMediaPlaying(helper.get(), true); + HandleMediaPlaying(helper, true); + HandleMediaPlaying(helper, true); EXPECT_DOUBLE_EQ(0.60, service->GetScore(url1)); EXPECT_EQ(0, service->GetScore(url2)); // Simulate inputs for a different link. NavigateWithDisposition(url2, CURRENT_TAB); - TrackingStarted(helper.get()); + TrackingStarted(helper); EXPECT_DOUBLE_EQ(0.6, service->GetScore(url1)); EXPECT_DOUBLE_EQ(0.5, service->GetScore(url2)); EXPECT_DOUBLE_EQ(1.1, service->GetTotalEngagementPoints()); - HandleMediaPlaying(helper.get(), false); - HandleMediaPlaying(helper.get(), false); + HandleMediaPlaying(helper, false); + HandleMediaPlaying(helper, false); EXPECT_DOUBLE_EQ(0.6, service->GetScore(url1)); EXPECT_DOUBLE_EQ(0.54, service->GetScore(url2)); EXPECT_DOUBLE_EQ(1.14, service->GetTotalEngagementPoints()); @@ -216,14 +218,14 @@ browser()->tab_strip_model()->GetActiveWebContents(); base::MockTimer* media_tracker_timer = new base::MockTimer(true, false); - scoped_ptr<SiteEngagementHelper> helper(CreateHelper(web_contents)); - SetMediaTrackerPauseTimer(helper.get(), make_scoped_ptr(media_tracker_timer)); + SiteEngagementHelper* helper = GetHelper(web_contents); + SetMediaTrackerPauseTimer(helper, make_scoped_ptr(media_tracker_timer)); SiteEngagementService* service = SiteEngagementServiceFactory::GetForProfile(browser()->profile()); DCHECK(service); NavigateWithDisposition(url1, CURRENT_TAB); - MediaStartedPlaying(helper.get()); + MediaStartedPlaying(helper); EXPECT_DOUBLE_EQ(0.50, service->GetScore(url1)); EXPECT_EQ(0, service->GetScore(url2)); @@ -240,7 +242,7 @@ EXPECT_EQ(0, service->GetScore(url2)); EXPECT_TRUE(media_tracker_timer->IsRunning()); - MediaStoppedPlaying(helper.get()); + MediaStoppedPlaying(helper); media_tracker_timer->Fire(); EXPECT_DOUBLE_EQ(0.53, service->GetScore(url1)); EXPECT_EQ(0, service->GetScore(url2)); @@ -252,7 +254,7 @@ EXPECT_EQ(0, service->GetScore(url2)); EXPECT_TRUE(media_tracker_timer->IsRunning()); - MediaStartedPlaying(helper.get()); + MediaStartedPlaying(helper); media_tracker_timer->Fire(); EXPECT_DOUBLE_EQ(0.55, service->GetScore(url1)); EXPECT_EQ(0, service->GetScore(url2)); @@ -263,7 +265,7 @@ EXPECT_EQ(0.5, service->GetScore(url2)); EXPECT_FALSE(media_tracker_timer->IsRunning()); - MediaStartedPlaying(helper.get()); + MediaStartedPlaying(helper); media_tracker_timer->Fire(); EXPECT_DOUBLE_EQ(0.55, service->GetScore(url1)); EXPECT_EQ(0.52, service->GetScore(url2)); @@ -275,7 +277,7 @@ EXPECT_EQ(0.53, service->GetScore(url2)); EXPECT_TRUE(media_tracker_timer->IsRunning()); - MediaStoppedPlaying(helper.get()); + MediaStoppedPlaying(helper); web_contents->WasShown(); media_tracker_timer->Fire(); EXPECT_DOUBLE_EQ(0.55, service->GetScore(url1)); @@ -290,7 +292,7 @@ content::WebContents* web_contents = browser()->tab_strip_model()->GetActiveWebContents(); - scoped_ptr<SiteEngagementHelper> helper(CreateHelper(web_contents)); + SiteEngagementHelper* helper = GetHelper(web_contents); SiteEngagementService* service = SiteEngagementServiceFactory::GetForProfile(browser()->profile()); DCHECK(service); @@ -302,7 +304,7 @@ 0); NavigateWithDisposition(url1, CURRENT_TAB); - TrackingStarted(helper.get()); + TrackingStarted(helper); EXPECT_DOUBLE_EQ(0.5, service->GetScore(url1)); EXPECT_EQ(0, service->GetScore(url2)); @@ -311,16 +313,13 @@ histograms.ExpectBucketCount(SiteEngagementMetrics::kEngagementTypeHistogram, SiteEngagementMetrics::ENGAGEMENT_NAVIGATION, 1); - HandleUserInputAndRestartTracking(helper.get(), - blink::WebInputEvent::RawKeyDown); - HandleUserInputAndRestartTracking(helper.get(), + HandleUserInputAndRestartTracking(helper, blink::WebInputEvent::RawKeyDown); + HandleUserInputAndRestartTracking(helper, blink::WebInputEvent::GestureTapDown); - HandleUserInputAndRestartTracking(helper.get(), + HandleUserInputAndRestartTracking(helper, blink::WebInputEvent::GestureTapDown); - HandleUserInputAndRestartTracking(helper.get(), - blink::WebInputEvent::RawKeyDown); - HandleUserInputAndRestartTracking(helper.get(), - blink::WebInputEvent::MouseDown); + HandleUserInputAndRestartTracking(helper, blink::WebInputEvent::RawKeyDown); + HandleUserInputAndRestartTracking(helper, blink::WebInputEvent::MouseDown); EXPECT_DOUBLE_EQ(0.75, service->GetScore(url1)); EXPECT_EQ(0, service->GetScore(url2)); @@ -336,14 +335,12 @@ SiteEngagementMetrics::ENGAGEMENT_TOUCH_GESTURE, 2); - HandleUserInputAndRestartTracking(helper.get(), - blink::WebInputEvent::MouseWheel); - HandleUserInputAndRestartTracking(helper.get(), - blink::WebInputEvent::MouseDown); - HandleMediaPlaying(helper.get(), true); - HandleUserInputAndRestartTracking(helper.get(), + HandleUserInputAndRestartTracking(helper, blink::WebInputEvent::MouseWheel); + HandleUserInputAndRestartTracking(helper, blink::WebInputEvent::MouseDown); + HandleMediaPlaying(helper, true); + HandleUserInputAndRestartTracking(helper, blink::WebInputEvent::GestureTapDown); - HandleMediaPlaying(helper.get(), false); + HandleMediaPlaying(helper, false); EXPECT_DOUBLE_EQ(0.93, service->GetScore(url1)); EXPECT_EQ(0, service->GetScore(url2)); @@ -364,16 +361,15 @@ 1); NavigateWithDisposition(url2, CURRENT_TAB); - TrackingStarted(helper.get()); + TrackingStarted(helper); EXPECT_DOUBLE_EQ(0.93, service->GetScore(url1)); EXPECT_DOUBLE_EQ(0.5, service->GetScore(url2)); EXPECT_DOUBLE_EQ(1.43, service->GetTotalEngagementPoints()); - HandleUserInputAndRestartTracking(helper.get(), + HandleUserInputAndRestartTracking(helper, blink::WebInputEvent::GestureTapDown); - HandleUserInputAndRestartTracking(helper.get(), - blink::WebInputEvent::RawKeyDown); + HandleUserInputAndRestartTracking(helper, blink::WebInputEvent::RawKeyDown); EXPECT_DOUBLE_EQ(0.93, service->GetScore(url1)); EXPECT_DOUBLE_EQ(0.6, service->GetScore(url2)); @@ -398,9 +394,9 @@ base::MockTimer* input_tracker_timer = new base::MockTimer(true, false); base::MockTimer* media_tracker_timer = new base::MockTimer(true, false); - scoped_ptr<SiteEngagementHelper> helper(CreateHelper(web_contents)); - SetInputTrackerPauseTimer(helper.get(), make_scoped_ptr(input_tracker_timer)); - SetMediaTrackerPauseTimer(helper.get(), make_scoped_ptr(media_tracker_timer)); + SiteEngagementHelper* helper = GetHelper(web_contents); + SetInputTrackerPauseTimer(helper, make_scoped_ptr(input_tracker_timer)); + SetMediaTrackerPauseTimer(helper, make_scoped_ptr(media_tracker_timer)); SiteEngagementService* service = SiteEngagementServiceFactory::GetForProfile(browser()->profile()); @@ -413,11 +409,11 @@ // Input timer should be running for navigation delay, but media timer is // inactive. EXPECT_TRUE(input_tracker_timer->IsRunning()); - EXPECT_FALSE(IsTrackingInput(helper.get())); + EXPECT_FALSE(IsTrackingInput(helper)); EXPECT_FALSE(media_tracker_timer->IsRunning()); // Media timer starts once media is detected as playing. - MediaStartedPlaying(helper.get()); + MediaStartedPlaying(helper); EXPECT_TRUE(media_tracker_timer->IsRunning()); input_tracker_timer->Fire(); @@ -428,12 +424,12 @@ // Input timer should start running again after input, but the media timer // keeps running. EXPECT_FALSE(input_tracker_timer->IsRunning()); - EXPECT_TRUE(IsTrackingInput(helper.get())); + EXPECT_TRUE(IsTrackingInput(helper)); EXPECT_TRUE(media_tracker_timer->IsRunning()); - HandleUserInput(helper.get(), blink::WebInputEvent::RawKeyDown); + HandleUserInput(helper, blink::WebInputEvent::RawKeyDown); EXPECT_TRUE(input_tracker_timer->IsRunning()); - EXPECT_FALSE(IsTrackingInput(helper.get())); + EXPECT_FALSE(IsTrackingInput(helper)); EXPECT_TRUE(media_tracker_timer->IsRunning()); EXPECT_DOUBLE_EQ(0.57, service->GetScore(url1)); @@ -441,13 +437,13 @@ input_tracker_timer->Fire(); EXPECT_FALSE(input_tracker_timer->IsRunning()); - EXPECT_TRUE(IsTrackingInput(helper.get())); + EXPECT_TRUE(IsTrackingInput(helper)); EXPECT_TRUE(media_tracker_timer->IsRunning()); // Timer should start running again after input. - HandleUserInput(helper.get(), blink::WebInputEvent::GestureTapDown); + HandleUserInput(helper, blink::WebInputEvent::GestureTapDown); EXPECT_TRUE(input_tracker_timer->IsRunning()); - EXPECT_FALSE(IsTrackingInput(helper.get())); + EXPECT_FALSE(IsTrackingInput(helper)); EXPECT_TRUE(media_tracker_timer->IsRunning()); EXPECT_DOUBLE_EQ(0.62, service->GetScore(url1)); @@ -455,7 +451,7 @@ input_tracker_timer->Fire(); EXPECT_FALSE(input_tracker_timer->IsRunning()); - EXPECT_TRUE(IsTrackingInput(helper.get())); + EXPECT_TRUE(IsTrackingInput(helper)); media_tracker_timer->Fire(); EXPECT_TRUE(media_tracker_timer->IsRunning()); @@ -465,7 +461,7 @@ // Timer should be running for navigation delay. Media is disabled again. NavigateWithDisposition(url2, CURRENT_TAB); EXPECT_TRUE(input_tracker_timer->IsRunning()); - EXPECT_FALSE(IsTrackingInput(helper.get())); + EXPECT_FALSE(IsTrackingInput(helper)); EXPECT_FALSE(media_tracker_timer->IsRunning()); EXPECT_DOUBLE_EQ(0.64, service->GetScore(url1)); @@ -474,15 +470,15 @@ input_tracker_timer->Fire(); EXPECT_FALSE(input_tracker_timer->IsRunning()); - EXPECT_TRUE(IsTrackingInput(helper.get())); + EXPECT_TRUE(IsTrackingInput(helper)); EXPECT_FALSE(media_tracker_timer->IsRunning()); - HandleUserInput(helper.get(), blink::WebInputEvent::MouseDown); + HandleUserInput(helper, blink::WebInputEvent::MouseDown); EXPECT_TRUE(input_tracker_timer->IsRunning()); - EXPECT_FALSE(IsTrackingInput(helper.get())); + EXPECT_FALSE(IsTrackingInput(helper)); EXPECT_FALSE(media_tracker_timer->IsRunning()); - MediaStartedPlaying(helper.get()); + MediaStartedPlaying(helper); EXPECT_TRUE(media_tracker_timer->IsRunning()); EXPECT_DOUBLE_EQ(0.64, service->GetScore(url1)); @@ -508,9 +504,9 @@ base::MockTimer* input_tracker_timer = new base::MockTimer(true, false); base::MockTimer* media_tracker_timer = new base::MockTimer(true, false); - scoped_ptr<SiteEngagementHelper> helper(CreateHelper(web_contents)); - SetInputTrackerPauseTimer(helper.get(), make_scoped_ptr(input_tracker_timer)); - SetMediaTrackerPauseTimer(helper.get(), make_scoped_ptr(media_tracker_timer)); + SiteEngagementHelper* helper = GetHelper(web_contents); + SetInputTrackerPauseTimer(helper, make_scoped_ptr(input_tracker_timer)); + SetMediaTrackerPauseTimer(helper, make_scoped_ptr(media_tracker_timer)); NavigateWithDisposition(url1, CURRENT_TAB); input_tracker_timer->Fire(); @@ -519,37 +515,37 @@ web_contents->WasHidden(); EXPECT_FALSE(input_tracker_timer->IsRunning()); EXPECT_FALSE(media_tracker_timer->IsRunning()); - EXPECT_FALSE(IsTrackingInput(helper.get())); + EXPECT_FALSE(IsTrackingInput(helper)); // Showing the tab should start tracking again after another delay. Media // tracking remains inactive. web_contents->WasShown(); EXPECT_TRUE(input_tracker_timer->IsRunning()); EXPECT_FALSE(media_tracker_timer->IsRunning()); - EXPECT_FALSE(IsTrackingInput(helper.get())); + EXPECT_FALSE(IsTrackingInput(helper)); // Start media tracking. - MediaStartedPlaying(helper.get()); + MediaStartedPlaying(helper); EXPECT_TRUE(media_tracker_timer->IsRunning()); // Hiding the tab should stop input tracking, but not media tracking. web_contents->WasHidden(); EXPECT_FALSE(input_tracker_timer->IsRunning()); EXPECT_TRUE(media_tracker_timer->IsRunning()); - EXPECT_FALSE(IsTrackingInput(helper.get())); + EXPECT_FALSE(IsTrackingInput(helper)); // Showing the tab should start tracking again after another delay. Media // tracking continues. web_contents->WasShown(); EXPECT_TRUE(input_tracker_timer->IsRunning()); EXPECT_TRUE(media_tracker_timer->IsRunning()); - EXPECT_FALSE(IsTrackingInput(helper.get())); + EXPECT_FALSE(IsTrackingInput(helper)); input_tracker_timer->Fire(); media_tracker_timer->Fire(); EXPECT_FALSE(input_tracker_timer->IsRunning()); EXPECT_TRUE(media_tracker_timer->IsRunning()); - EXPECT_TRUE(IsTrackingInput(helper.get())); + EXPECT_TRUE(IsTrackingInput(helper)); } // Ensure tracking behavior is correct for multiple navigations in a single tab. @@ -561,26 +557,26 @@ browser()->tab_strip_model()->GetActiveWebContents(); base::MockTimer* input_tracker_timer = new base::MockTimer(true, false); - scoped_ptr<SiteEngagementHelper> helper(CreateHelper(web_contents)); - SetInputTrackerPauseTimer(helper.get(), make_scoped_ptr(input_tracker_timer)); + SiteEngagementHelper* helper = GetHelper(web_contents); + SetInputTrackerPauseTimer(helper, make_scoped_ptr(input_tracker_timer)); // Navigation should start the initial delay timer. NavigateWithDisposition(url1, CURRENT_TAB); EXPECT_TRUE(input_tracker_timer->IsRunning()); - EXPECT_FALSE(IsTrackingInput(helper.get())); + EXPECT_FALSE(IsTrackingInput(helper)); // Navigating before the timer fires should simply reset the timer. NavigateWithDisposition(url2, CURRENT_TAB); EXPECT_TRUE(input_tracker_timer->IsRunning()); - EXPECT_FALSE(IsTrackingInput(helper.get())); + EXPECT_FALSE(IsTrackingInput(helper)); // When the timer fires, callbacks are added. input_tracker_timer->Fire(); EXPECT_FALSE(input_tracker_timer->IsRunning()); - EXPECT_TRUE(IsTrackingInput(helper.get())); + EXPECT_TRUE(IsTrackingInput(helper)); // Navigation should start the initial delay timer again. NavigateWithDisposition(url1, CURRENT_TAB); EXPECT_TRUE(input_tracker_timer->IsRunning()); - EXPECT_FALSE(IsTrackingInput(helper.get())); + EXPECT_FALSE(IsTrackingInput(helper)); }
diff --git a/chrome/browser/engagement/site_engagement_service.cc b/chrome/browser/engagement/site_engagement_service.cc index 3cd7f11..1c9a7832 100644 --- a/chrome/browser/engagement/site_engagement_service.cc +++ b/chrome/browser/engagement/site_engagement_service.cc
@@ -17,6 +17,7 @@ #include "base/time/clock.h" #include "base/time/default_clock.h" #include "base/values.h" +#include "chrome/browser/banners/app_banner_settings_helper.h" #include "chrome/browser/content_settings/host_content_settings_map_factory.h" #include "chrome/browser/engagement/site_engagement_eviction_policy.h" #include "chrome/browser/engagement/site_engagement_helper.h" @@ -281,7 +282,8 @@ // return true immediately. if (base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kEnableSiteEngagementService) || - SiteEngagementEvictionPolicy::IsEnabled()) { + SiteEngagementEvictionPolicy::IsEnabled() || + AppBannerSettingsHelper::ShouldUseSiteEngagementScore()) { return true; }
diff --git a/chrome/browser/engagement/site_engagement_service.h b/chrome/browser/engagement/site_engagement_service.h index 17577bc..7f735d0 100644 --- a/chrome/browser/engagement/site_engagement_service.h +++ b/chrome/browser/engagement/site_engagement_service.h
@@ -194,6 +194,7 @@ FRIEND_TEST_ALL_PREFIXES(SiteEngagementServiceTest, GetTotalUserInputPoints); FRIEND_TEST_ALL_PREFIXES(SiteEngagementServiceTest, CleanupOriginsOnHistoryDeletion); + FRIEND_TEST_ALL_PREFIXES(AppBannerSettingsHelperTest, SiteEngagementTrigger); // Only used in tests. SiteEngagementService(Profile* profile, scoped_ptr<base::Clock> clock);
diff --git a/chrome/browser/engagement/site_engagement_service_factory.cc b/chrome/browser/engagement/site_engagement_service_factory.cc index 3dc054f2..7838836 100644 --- a/chrome/browser/engagement/site_engagement_service_factory.cc +++ b/chrome/browser/engagement/site_engagement_service_factory.cc
@@ -6,6 +6,7 @@ #include "chrome/browser/content_settings/host_content_settings_map_factory.h" #include "chrome/browser/engagement/site_engagement_service.h" +#include "chrome/browser/history/history_service_factory.h" #include "chrome/browser/profiles/profile.h" #include "components/keyed_service/content/browser_context_dependency_manager.h" @@ -25,6 +26,7 @@ : BrowserContextKeyedServiceFactory( "SiteEngagementService", BrowserContextDependencyManager::GetInstance()) { + DependsOn(HistoryServiceFactory::GetInstance()); DependsOn(HostContentSettingsMapFactory::GetInstance()); } @@ -32,7 +34,7 @@ } bool SiteEngagementServiceFactory::ServiceIsNULLWhileTesting() const { - return true; + return false; } KeyedService* SiteEngagementServiceFactory::BuildServiceInstanceFor(
diff --git a/chrome/browser/errorpage_browsertest.cc b/chrome/browser/errorpage_browsertest.cc index 26db469..f814e7d 100644 --- a/chrome/browser/errorpage_browsertest.cc +++ b/chrome/browser/errorpage_browsertest.cc
@@ -32,6 +32,7 @@ #include "chrome/common/pref_names.h" #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/ui_test_utils.h" +#include "components/error_page/common/error_page_switches.h" #include "components/google/core/browser/google_util.h" #include "components/strings/grit/components_strings.h" #include "content/public/browser/browser_thread.h" @@ -336,8 +337,9 @@ // Navigates the active tab to a mock url created for the file at |file_path|. // Needed for StaleCacheStatus and StaleCacheStatusFailedCorrections tests. void SetUpCommandLine(base::CommandLine* command_line) override { - command_line->AppendSwitchASCII(switches::kShowSavedCopy, - switches::kEnableShowSavedCopyPrimary); + command_line->AppendSwitchASCII( + error_page::switches::kShowSavedCopy, + error_page::switches::kEnableShowSavedCopyPrimary); } // Navigates the active tab to a mock url created for the file at |path|.
diff --git a/chrome/browser/extensions/BUILD.gn b/chrome/browser/extensions/BUILD.gn index 95f44e0e..e6d00d9 100644 --- a/chrome/browser/extensions/BUILD.gn +++ b/chrome/browser/extensions/BUILD.gn
@@ -111,11 +111,11 @@ } } - if (!is_android) { - sources += - rebase_path(gypi_values.chrome_browser_extensions_non_android_sources, - ".", - "//chrome") + if (enable_service_discovery) { + sources += rebase_path( + gypi_values.chrome_browser_extensions_service_discovery_sources, + ".", + "//chrome") } if (use_ash) {
diff --git a/chrome/browser/extensions/api/desktop_capture/desktop_capture_base.cc b/chrome/browser/extensions/api/desktop_capture/desktop_capture_base.cc index 04c3685..fccf615 100644 --- a/chrome/browser/extensions/api/desktop_capture/desktop_capture_base.cc +++ b/chrome/browser/extensions/api/desktop_capture/desktop_capture_base.cc
@@ -132,12 +132,7 @@ // DesktopMediaPicker is implemented only for Windows, OSX and // Aura Linux builds. - // TODO(bshe): Use ANDROID_JAVA_UI flag here after it landed. -#if (defined(TOOLKIT_VIEWS) && !defined(OS_ANDROID)) || defined(OS_MACOSX) - // TODO(bshe): This is called if chrome.desktopCapture.chooseDesktopMedia - // or chrome.webrtcDesktopCapturePrivate.chooseDesktopMedia are called by - // extensions. Simply return error message on Android platform for now. - // Revisit this when necessary. See crbug.com/557424. +#if defined(TOOLKIT_VIEWS) || defined(OS_MACOSX) picker_ = DesktopMediaPicker::Create(); #else error_ = "Desktop Capture API is not yet implemented for this platform.";
diff --git a/chrome/browser/extensions/api/extension_action/browser_action_unittest.cc b/chrome/browser/extensions/api/extension_action/browser_action_unittest.cc index 8060e9e..b69bbf30 100644 --- a/chrome/browser/extensions/api/extension_action/browser_action_unittest.cc +++ b/chrome/browser/extensions/api/extension_action/browser_action_unittest.cc
@@ -35,36 +35,5 @@ EXPECT_EQ("icon38.png", icons.Get(38, ExtensionIconSet::MATCH_EXACTLY)); } -TEST_F(BrowserActionUnitTest, MissingIconInWebstoreCrx) { - InitializeEmptyExtensionService(); - base::FilePath path = - data_dir().AppendASCII("api_test/browser_action/missing_icon"); - ASSERT_TRUE(base::PathExists(path)); - - const Extension* extension = PackAndInstallCRX(path, INSTALL_NEW); - - ASSERT_EQ(1U, extension->install_warnings().size()); - EXPECT_EQ("Could not load extension icon 'icon19.png'.", - extension->install_warnings().front().message); - const ActionInfo* browser_action_info = - ActionInfo::GetBrowserActionInfo(extension); - ASSERT_TRUE(browser_action_info); - - const ExtensionIconSet& icons = browser_action_info->default_icon; - - EXPECT_EQ(2u, icons.map().size()); - EXPECT_EQ("icon24.png", icons.Get(24, ExtensionIconSet::MATCH_EXACTLY)); - EXPECT_EQ("icon38.png", icons.Get(38, ExtensionIconSet::MATCH_EXACTLY)); -} - -TEST_F(BrowserActionUnitTest, MissingIconInCommandLine) { - InitializeEmptyExtensionService(); - base::FilePath path = - data_dir().AppendASCII("api_test/browser_action/missing_icon"); - ASSERT_TRUE(base::PathExists(path)); - - PackAndInstallCRXWithLocation(path, Manifest::COMMAND_LINE, INSTALL_FAILED); -} - } // namespace } // namespace extensions
diff --git a/chrome/browser/extensions/api/messaging/extension_message_port.cc b/chrome/browser/extensions/api/messaging/extension_message_port.cc index 1e4f87f..a22568f9 100644 --- a/chrome/browser/extensions/api/messaging/extension_message_port.cc +++ b/chrome/browser/extensions/api/messaging/extension_message_port.cc
@@ -4,31 +4,121 @@ #include "chrome/browser/extensions/api/messaging/extension_message_port.h" +#include "base/scoped_observer.h" #include "chrome/browser/profiles/profile.h" +#include "content/public/browser/navigation_details.h" +#include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_process_host.h" +#include "content/public/browser/web_contents.h" +#include "content/public/browser/web_contents_observer.h" #include "extensions/browser/extension_host.h" #include "extensions/browser/process_manager.h" +#include "extensions/browser/process_manager_observer.h" #include "extensions/common/extension_messages.h" #include "extensions/common/manifest_handlers/background_info.h" namespace extensions { -ExtensionMessagePort::ExtensionMessagePort(content::RenderProcessHost* process, - int routing_id, - const std::string& extension_id) - : process_(process), - routing_id_(routing_id), - extension_id_(extension_id), - background_host_ptr_(NULL) { +const char kReceivingEndDoesntExistError[] = + "Could not establish connection. Receiving end does not exist."; + +// Helper class to detect when frames are destroyed. +class ExtensionMessagePort::FrameTracker : public content::WebContentsObserver, + public ProcessManagerObserver { + public: + explicit FrameTracker(ExtensionMessagePort* port) + : pm_observer_(this), port_(port) {} + ~FrameTracker() override {} + + void TrackExtensionProcessFrames() { + pm_observer_.Add(ProcessManager::Get(port_->browser_context_)); + } + + void TrackTabFrames(content::WebContents* tab) { + Observe(tab); + } + + private: + // content::WebContentsObserver overrides: + void RenderFrameDeleted(content::RenderFrameHost* render_frame_host) + override { + port_->UnregisterFrame(render_frame_host); + } + + void DidNavigateAnyFrame(content::RenderFrameHost* render_frame_host, + const content::LoadCommittedDetails& details, + const content::FrameNavigateParams&) override { + if (!details.is_in_page) + port_->UnregisterFrame(render_frame_host); + } + + // extensions::ProcessManagerObserver overrides: + void OnExtensionFrameUnregistered( + const std::string& extension_id, + content::RenderFrameHost* render_frame_host) override { + if (extension_id == port_->extension_id_) + port_->UnregisterFrame(render_frame_host); + } + + ScopedObserver<ProcessManager, ProcessManagerObserver> pm_observer_; + ExtensionMessagePort* port_; // Owns this FrameTracker. + + DISALLOW_COPY_AND_ASSIGN(FrameTracker); +}; + +ExtensionMessagePort::ExtensionMessagePort( + base::WeakPtr<MessageService> message_service, + int port_id, + const std::string& extension_id, + content::RenderProcessHost* extension_process) + : weak_message_service_(message_service), + port_id_(port_id), + extension_id_(extension_id), + browser_context_(extension_process->GetBrowserContext()), + extension_process_(extension_process), + frames_(ProcessManager::Get(browser_context_)-> + GetRenderFrameHostsForExtension(extension_id)), + did_create_port_(false), + background_host_ptr_(nullptr), + frame_tracker_(new FrameTracker(this)) { + frame_tracker_->TrackExtensionProcessFrames(); +} + +ExtensionMessagePort::ExtensionMessagePort( + base::WeakPtr<MessageService> message_service, + int port_id, + const std::string& extension_id, + content::RenderFrameHost* rfh, + bool include_child_frames) + : weak_message_service_(message_service), + port_id_(port_id), + extension_id_(extension_id), + browser_context_(rfh->GetProcess()->GetBrowserContext()), + extension_process_(nullptr), + did_create_port_(false), + background_host_ptr_(nullptr), + frame_tracker_(new FrameTracker(this)) { + content::WebContents* tab = content::WebContents::FromRenderFrameHost(rfh); + DCHECK(tab); + frame_tracker_->TrackTabFrames(tab); + if (include_child_frames) { + tab->ForEachFrame(base::Bind(&ExtensionMessagePort::RegisterFrame, + base::Unretained(this))); + } else { + RegisterFrame(rfh); + } +} + +ExtensionMessagePort::~ExtensionMessagePort() {} + +bool ExtensionMessagePort::IsValidPort() { + return !frames_.empty(); } void ExtensionMessagePort::DispatchOnConnect( - int dest_port_id, const std::string& channel_name, scoped_ptr<base::DictionaryValue> source_tab, int source_frame_id, - int target_tab_id, - int target_frame_id, int guest_process_id, int guest_render_frame_routing_id, const std::string& source_extension_id, @@ -44,32 +134,26 @@ info.target_id = target_extension_id; info.source_id = source_extension_id; info.source_url = source_url; - info.target_tab_id = target_tab_id; - info.target_frame_id = target_frame_id; info.guest_process_id = guest_process_id; info.guest_render_frame_routing_id = guest_render_frame_routing_id; - process_->Send(new ExtensionMsg_DispatchOnConnect( - routing_id_, dest_port_id, channel_name, source, info, tls_channel_id)); + SendToPort(make_scoped_ptr(new ExtensionMsg_DispatchOnConnect( + MSG_ROUTING_NONE, port_id_, channel_name, source, info, tls_channel_id))); } void ExtensionMessagePort::DispatchOnDisconnect( - int source_port_id, const std::string& error_message) { - process_->Send(new ExtensionMsg_DispatchOnDisconnect( - routing_id_, source_port_id, error_message)); + SendToPort(make_scoped_ptr(new ExtensionMsg_DispatchOnDisconnect( + MSG_ROUTING_NONE, port_id_, error_message))); } -void ExtensionMessagePort::DispatchOnMessage(const Message& message, - int target_port_id) { - process_->Send(new ExtensionMsg_DeliverMessage( - routing_id_, target_port_id, message)); +void ExtensionMessagePort::DispatchOnMessage(const Message& message) { + SendToPort(make_scoped_ptr(new ExtensionMsg_DeliverMessage( + MSG_ROUTING_NONE, port_id_, message))); } void ExtensionMessagePort::IncrementLazyKeepaliveCount() { - Profile* profile = - Profile::FromBrowserContext(process_->GetBrowserContext()); - extensions::ProcessManager* pm = ProcessManager::Get(profile); + ProcessManager* pm = ProcessManager::Get(browser_context_); ExtensionHost* host = pm->GetBackgroundHostForExtension(extension_id_); if (host && BackgroundInfo::HasLazyBackgroundPage(host->extension())) pm->IncrementLazyKeepaliveCount(host->extension()); @@ -80,16 +164,66 @@ } void ExtensionMessagePort::DecrementLazyKeepaliveCount() { - Profile* profile = - Profile::FromBrowserContext(process_->GetBrowserContext()); - extensions::ProcessManager* pm = ProcessManager::Get(profile); + ProcessManager* pm = ProcessManager::Get(browser_context_); ExtensionHost* host = pm->GetBackgroundHostForExtension(extension_id_); if (host && host == background_host_ptr_) pm->DecrementLazyKeepaliveCount(host->extension()); } -content::RenderProcessHost* ExtensionMessagePort::GetRenderProcessHost() { - return process_; +void ExtensionMessagePort::OpenPort(int process_id, int routing_id) { + DCHECK(routing_id != MSG_ROUTING_NONE || extension_process_); + + did_create_port_ = true; +} + +void ExtensionMessagePort::ClosePort(int process_id, int routing_id) { + if (routing_id == MSG_ROUTING_NONE) { + // The only non-frame-specific message is the response to an unhandled + // onConnect event in the extension process. + DCHECK(extension_process_); + frames_.clear(); + CloseChannel(); + return; + } + + content::RenderFrameHost* rfh = + content::RenderFrameHost::FromID(process_id, routing_id); + if (rfh) + UnregisterFrame(rfh); +} + +void ExtensionMessagePort::CloseChannel() { + std::string error_message = did_create_port_ ? std::string() : + kReceivingEndDoesntExistError; + if (weak_message_service_) + weak_message_service_->CloseChannel(port_id_, error_message); +} + +void ExtensionMessagePort::RegisterFrame(content::RenderFrameHost* rfh) { + frames_.insert(rfh); +} + +void ExtensionMessagePort::UnregisterFrame(content::RenderFrameHost* rfh) { + if (frames_.erase(rfh) != 0 && frames_.empty()) + CloseChannel(); +} + +void ExtensionMessagePort::SendToPort(scoped_ptr<IPC::Message> msg) { + DCHECK_GT(frames_.size(), 0UL); + if (extension_process_) { + // All extension frames reside in the same process, so we can just send a + // single IPC message to the extension process as an optimization. + // The frame tracking is then only used to make sure that the port gets + // closed when all frames have closed / reloaded. + msg->set_routing_id(MSG_ROUTING_CONTROL); + extension_process_->Send(msg.release()); + return; + } + for (content::RenderFrameHost* rfh : frames_) { + IPC::Message* msg_copy = new IPC::Message(*msg.get()); + msg_copy->set_routing_id(rfh->GetRoutingID()); + rfh->Send(msg_copy); + } } } // namespace extensions
diff --git a/chrome/browser/extensions/api/messaging/extension_message_port.h b/chrome/browser/extensions/api/messaging/extension_message_port.h index 79b8003..f950f64 100644 --- a/chrome/browser/extensions/api/messaging/extension_message_port.h +++ b/chrome/browser/extensions/api/messaging/extension_message_port.h
@@ -5,46 +5,101 @@ #ifndef CHROME_BROWSER_EXTENSIONS_API_MESSAGING_EXTENSION_MESSAGE_PORT_H_ #define CHROME_BROWSER_EXTENSIONS_API_MESSAGING_EXTENSION_MESSAGE_PORT_H_ +#include "base/macros.h" #include "chrome/browser/extensions/api/messaging/message_service.h" class GURL; namespace content { +class BrowserContext; +class RenderFrameHost; class RenderProcessHost; } // namespace content +namespace IPC { +class Message; +} // namespace IPC + namespace extensions { // A port that manages communication with an extension. +// The port's lifetime will end when either all receivers close the port, or +// when the opener / receiver explicitly closes the channel. class ExtensionMessagePort : public MessageService::MessagePort { public: - ExtensionMessagePort(content::RenderProcessHost* process, - int routing_id, - const std::string& extension_id); - void DispatchOnConnect(int dest_port_id, - const std::string& channel_name, + // Create a port that is tied to frame(s) in a single tab. + ExtensionMessagePort(base::WeakPtr<MessageService> message_service, + int port_id, + const std::string& extension_id, + content::RenderFrameHost* rfh, + bool include_child_frames); + // Create a port that is tied to all frames of an extension, possibly spanning + // multiple tabs, including the invisible background page, popups, etc. + ExtensionMessagePort(base::WeakPtr<MessageService> message_service, + int port_id, + const std::string& extension_id, + content::RenderProcessHost* extension_process); + ~ExtensionMessagePort() override; + + bool IsValidPort() override; + + // MessageService::MessagePort: + void DispatchOnConnect(const std::string& channel_name, scoped_ptr<base::DictionaryValue> source_tab, int source_frame_id, - int target_tab_id, - int target_frame_id, int guest_process_id, int guest_render_frame_routing_id, const std::string& source_extension_id, const std::string& target_extension_id, const GURL& source_url, const std::string& tls_channel_id) override; - void DispatchOnDisconnect(int source_port_id, - const std::string& error_message) override; - void DispatchOnMessage(const Message& message, int target_port_id) override; + void DispatchOnDisconnect(const std::string& error_message) override; + void DispatchOnMessage(const Message& message) override; void IncrementLazyKeepaliveCount() override; void DecrementLazyKeepaliveCount() override; - content::RenderProcessHost* GetRenderProcessHost() override; + void OpenPort(int process_id, int routing_id) override; + void ClosePort(int process_id, int routing_id) override; private: - content::RenderProcessHost* process_; - int routing_id_; + class FrameTracker; + + // Registers a frame as a receiver / sender. + void RegisterFrame(content::RenderFrameHost* rfh); + + // Unregisters a frame as a receiver / sender. When there are no registered + // frames any more, the port closes via CloseChannel(). + void UnregisterFrame(content::RenderFrameHost* rfh); + + // Immediately close the port and its associated channel. + void CloseChannel(); + + // Send a IPC message to the renderer for all registered frames. + void SendToPort(scoped_ptr<IPC::Message> msg); + + base::WeakPtr<MessageService> weak_message_service_; + + int port_id_; std::string extension_id_; - void* background_host_ptr_; // used in IncrementLazyKeepaliveCount + content::BrowserContext* browser_context_; + // Only for receivers in an extension process. + content::RenderProcessHost* extension_process_; + + // When the port is used as a sender, this set contains only one element. + // If used as a receiver, it may contain any number of frames. + // This set is populated before the first message is sent to the destination, + // and shrinks over time when the port is rejected by the recipient frame, or + // when the frame is removed or unloaded. + std::set<content::RenderFrameHost*> frames_; + + // Whether the renderer acknowledged creation of the port. This is used to + // distinguish abnormal port closure (e.g. no receivers) from explicit port + // closure (e.g. by the port.disconnect() JavaScript method in the renderer). + bool did_create_port_; + + ExtensionHost* background_host_ptr_; // used in IncrementLazyKeepaliveCount + scoped_ptr<FrameTracker> frame_tracker_; + + DISALLOW_COPY_AND_ASSIGN(ExtensionMessagePort); }; } // namespace extensions
diff --git a/chrome/browser/extensions/api/messaging/message_service.cc b/chrome/browser/extensions/api/messaging/message_service.cc index 743ba0c..e936b7d 100644 --- a/chrome/browser/extensions/api/messaging/message_service.cc +++ b/chrome/browser/extensions/api/messaging/message_service.cc
@@ -18,7 +18,6 @@ #include "base/prefs/pref_service.h" #include "base/stl_util.h" #include "build/build_config.h" -#include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/extensions/api/messaging/extension_message_port.h" #include "chrome/browser/extensions/api/messaging/incognito_connectability.h" #include "chrome/browser/extensions/api/messaging/native_message_port.h" @@ -30,7 +29,6 @@ #include "chrome/browser/tab_contents/tab_util.h" #include "components/guest_view/common/guest_view_constants.h" #include "content/public/browser/browser_thread.h" -#include "content/public/browser/notification_service.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_process_host.h" #include "content/public/browser/render_view_host.h" @@ -40,6 +38,7 @@ #include "content/public/browser/web_contents.h" #include "content/public/common/child_process_host.h" #include "extensions/browser/event_router.h" +#include "extensions/browser/extension_api_frame_id_map.h" #include "extensions/browser/extension_host.h" #include "extensions/browser/extension_registry.h" #include "extensions/browser/extension_system.h" @@ -134,10 +133,9 @@ struct MessageService::OpenChannelParams { int source_process_id; + int source_routing_id; scoped_ptr<base::DictionaryValue> source_tab; int source_frame_id; - int target_tab_id; - int target_frame_id; scoped_ptr<MessagePort> receiver; int receiver_port_id; std::string source_extension_id; @@ -150,10 +148,9 @@ // Takes ownership of receiver. OpenChannelParams(int source_process_id, + int source_routing_id, scoped_ptr<base::DictionaryValue> source_tab, int source_frame_id, - int target_tab_id, - int target_frame_id, MessagePort* receiver, int receiver_port_id, const std::string& source_extension_id, @@ -163,9 +160,8 @@ bool include_tls_channel_id, bool include_guest_process_info) : source_process_id(source_process_id), + source_routing_id(source_routing_id), source_frame_id(source_frame_id), - target_tab_id(target_tab_id), - target_frame_id(target_frame_id), receiver(receiver), receiver_port_id(receiver_port_id), source_extension_id(source_extension_id), @@ -197,11 +193,6 @@ } // namespace -content::RenderProcessHost* - MessageService::MessagePort::GetRenderProcessHost() { - return NULL; -} - // static void MessageService::AllocatePortIdPair(int* port1, int* port2) { DCHECK_CURRENTLY_ON(BrowserThread::IO); @@ -229,11 +220,6 @@ LazyBackgroundTaskQueue::Get(context)), weak_factory_(this) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - - registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED, - content::NotificationService::AllBrowserContextsAndSources()); - registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED, - content::NotificationService::AllBrowserContextsAndSources()); } MessageService::~MessageService() { @@ -266,11 +252,11 @@ bool include_tls_channel_id) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - content::RenderProcessHost* source = - content::RenderProcessHost::FromID(source_process_id); + content::RenderFrameHost* source = + content::RenderFrameHost::FromID(source_process_id, source_routing_id); if (!source) return; - BrowserContext* context = source->GetBrowserContext(); + BrowserContext* context = source->GetProcess()->GetBrowserContext(); ExtensionRegistry* registry = ExtensionRegistry::Get(context); const Extension* target_extension = @@ -341,9 +327,8 @@ content::RenderFrameHost* rfh = content::RenderFrameHost::FromID(source_process_id, source_routing_id); - // Main frame's frameId is 0. if (rfh) - source_frame_id = !rfh->GetParent() ? 0 : source_routing_id; + source_frame_id = ExtensionApiFrameIdMap::GetFrameId(rfh); } else { // Check to see if it was a WebView making the request. // Sending messages from WebViews to extensions breaks webview isolation, @@ -352,20 +337,13 @@ if (is_web_view && extensions::Manifest::IsComponentLocation( target_extension->location())) { include_guest_process_info = true; - auto* rfh = content::RenderFrameHost::FromID(source_process_id, - source_routing_id); - // Include |source_frame_id| so that we can retrieve the guest's frame - // routing id in OpenChannelImpl. - if (rfh) - source_frame_id = source_routing_id; } } scoped_ptr<OpenChannelParams> params(new OpenChannelParams( - source_process_id, std::move(source_tab), source_frame_id, -1, - -1, // no target_tab_id/target_frame_id for connections to extensions - nullptr, receiver_port_id, source_extension_id, target_extension_id, - source_url, channel_name, include_tls_channel_id, + source_process_id, source_routing_id, std::move(source_tab), + source_frame_id, nullptr, receiver_port_id, source_extension_id, + target_extension_id, source_url, channel_name, include_tls_channel_id, include_guest_process_info)); pending_incognito_channels_[GET_CHANNEL_ID(params->receiver_port_id)] = @@ -423,13 +401,14 @@ const std::string& native_app_name) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - content::RenderProcessHost* source = - content::RenderProcessHost::FromID(source_process_id); + content::RenderFrameHost* source = + content::RenderFrameHost::FromID(source_process_id, source_routing_id); if (!source) return; #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX) - Profile* profile = Profile::FromBrowserContext(source->GetBrowserContext()); + Profile* profile = + Profile::FromBrowserContext(source->GetProcess()->GetBrowserContext()); ExtensionService* extension_service = ExtensionSystem::Get(profile)->extension_service(); bool has_permission = false; @@ -457,14 +436,13 @@ } scoped_ptr<MessageChannel> channel(new MessageChannel()); - channel->opener.reset(new ExtensionMessagePort(source, MSG_ROUTING_CONTROL, - source_extension_id)); + channel->opener.reset( + new ExtensionMessagePort(weak_factory_.GetWeakPtr(), + GET_OPPOSITE_PORT_ID(receiver_port_id), + source_extension_id, source, false)); // Get handle of the native view and pass it to the native messaging host. - content::RenderFrameHost* render_frame_host = - content::RenderFrameHost::FromID(source_process_id, source_routing_id); - gfx::NativeView native_view = - render_frame_host ? render_frame_host->GetNativeView() : nullptr; + gfx::NativeView native_view = source ? source->GetNativeView() : nullptr; std::string error = kReceivingEndDoesntExistError; scoped_ptr<NativeMessageHost> native_host = NativeMessageHost::Create( @@ -496,18 +474,21 @@ } void MessageService::OpenChannelToTab(int source_process_id, + int source_routing_id, int receiver_port_id, int tab_id, int frame_id, const std::string& extension_id, const std::string& channel_name) { DCHECK_CURRENTLY_ON(BrowserThread::UI); + DCHECK_GE(frame_id, -1); - content::RenderProcessHost* source = - content::RenderProcessHost::FromID(source_process_id); + content::RenderFrameHost* source = + content::RenderFrameHost::FromID(source_process_id, source_routing_id); if (!source) return; - Profile* profile = Profile::FromBrowserContext(source->GetBrowserContext()); + Profile* profile = + Profile::FromBrowserContext(source->GetProcess()->GetBrowserContext()); WebContents* contents = NULL; scoped_ptr<MessagePort> receiver; @@ -520,30 +501,21 @@ return; } - int receiver_routing_id; - if (frame_id > 0) { - // Positive frame ID is child frame. - int receiver_process_id = contents->GetRenderProcessHost()->GetID(); - if (!content::RenderFrameHost::FromID(receiver_process_id, frame_id)) { - // Frame does not exist. - DispatchOnDisconnect( - source, receiver_port_id, kReceivingEndDoesntExistError); - return; - } - receiver_routing_id = frame_id; - } else if (frame_id == 0) { - // Frame ID 0 is main frame. - receiver_routing_id = contents->GetMainFrame()->GetRoutingID(); - } else { - DCHECK_EQ(-1, frame_id); - // If the frame ID is not set (i.e. -1), then the channel has to be opened - // in every frame. - // TODO(robwu): Update logic so that frames that are not hosted in the main - // frame's process can also receive the port. - receiver_routing_id = MSG_ROUTING_CONTROL; + // Frame ID -1 is every frame in the tab. + bool include_child_frames = frame_id == -1; + content::RenderFrameHost* receiver_rfh = + include_child_frames + ? contents->GetMainFrame() + : ExtensionApiFrameIdMap::GetRenderFrameHostById(contents, frame_id); + if (!receiver_rfh) { + DispatchOnDisconnect( + source, receiver_port_id, kReceivingEndDoesntExistError); + return; } - receiver.reset(new ExtensionMessagePort(contents->GetRenderProcessHost(), - receiver_routing_id, extension_id)); + receiver.reset( + new ExtensionMessagePort(weak_factory_.GetWeakPtr(), + receiver_port_id, extension_id, receiver_rfh, + include_child_frames)); const Extension* extension = nullptr; if (!extension_id.empty()) { @@ -556,11 +528,11 @@ scoped_ptr<OpenChannelParams> params(new OpenChannelParams( source_process_id, + source_routing_id, scoped_ptr<base::DictionaryValue>(), // Source tab doesn't make sense // for opening to tabs. -1, // If there is no tab, then there is no frame either. - tab_id, frame_id, receiver.release(), receiver_port_id, extension_id, - extension_id, + receiver.release(), receiver_port_id, extension_id, extension_id, GURL(), // Source URL doesn't make sense for opening to tabs. channel_name, false, // Connections to tabs don't get TLS channel IDs. @@ -576,46 +548,48 @@ DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK_EQ(target_extension != nullptr, !params->target_extension_id.empty()); - content::RenderProcessHost* source = - content::RenderProcessHost::FromID(params->source_process_id); + content::RenderFrameHost* source = + content::RenderFrameHost::FromID(params->source_process_id, + params->source_routing_id); if (!source) return; // Closed while in flight. - if (!params->receiver || !params->receiver->GetRenderProcessHost()) { + if (!params->receiver || !params->receiver->IsValidPort()) { DispatchOnDisconnect(source, params->receiver_port_id, kReceivingEndDoesntExistError); return; } MessageChannel* channel(new MessageChannel); - channel->opener.reset(new ExtensionMessagePort(source, MSG_ROUTING_CONTROL, - params->source_extension_id)); + channel->opener.reset( + new ExtensionMessagePort(weak_factory_.GetWeakPtr(), + GET_OPPOSITE_PORT_ID(params->receiver_port_id), + params->source_extension_id, source, false)); channel->receiver.reset(params->receiver.release()); AddChannel(channel, params->receiver_port_id); + // TODO(robwu): Could |guest_process_id| and |guest_render_frame_routing_id| + // be removed? In the past extension message routing was process-based, but + // now that extensions are routed from a specific RFH, the special casing for + // guest views seems no longer necessary, because the ExtensionMessagePort can + // simply obtain the source process & frame ID directly from the RFH. int guest_process_id = content::ChildProcessHost::kInvalidUniqueID; int guest_render_frame_routing_id = MSG_ROUTING_NONE; if (params->include_guest_process_info) { guest_process_id = params->source_process_id; - guest_render_frame_routing_id = params->source_frame_id; - auto* guest_rfh = content::RenderFrameHost::FromID( - guest_process_id, guest_render_frame_routing_id); - // Reset the |source_frame_id| parameter. - params->source_frame_id = -1; + guest_render_frame_routing_id = params->source_routing_id; - DCHECK(guest_rfh == nullptr || - WebViewGuest::FromWebContents( - WebContents::FromRenderFrameHost(guest_rfh)) != nullptr); + DCHECK(WebViewGuest::FromWebContents( + WebContents::FromRenderFrameHost(source))); } // Send the connect event to the receiver. Give it the opener's port ID (the // opener has the opposite port ID). channel->receiver->DispatchOnConnect( - params->receiver_port_id, params->channel_name, - std::move(params->source_tab), params->source_frame_id, - params->target_tab_id, params->target_frame_id, guest_process_id, - guest_render_frame_routing_id, params->source_extension_id, - params->target_extension_id, params->source_url, params->tls_channel_id); + params->channel_name, std::move(params->source_tab), + params->source_frame_id, guest_process_id, guest_render_frame_routing_id, + params->source_extension_id, params->target_extension_id, + params->source_url, params->tls_channel_id); // Report the event to the event router, if the target is an extension. // @@ -662,10 +636,36 @@ pending_lazy_background_page_channels_.erase(channel_id); } +void MessageService::OpenPort(int port_id, int process_id, int routing_id) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + DCHECK(!IS_OPENER_PORT_ID(port_id)); + + int channel_id = GET_CHANNEL_ID(port_id); + MessageChannelMap::iterator it = channels_.find(channel_id); + if (it == channels_.end()) + return; + + it->second->receiver->OpenPort(process_id, routing_id); +} + +void MessageService::ClosePort( + int port_id, int process_id, int routing_id, bool force_close) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + ClosePortImpl(port_id, process_id, routing_id, force_close, std::string()); +} + void MessageService::CloseChannel(int port_id, const std::string& error_message) { DCHECK_CURRENTLY_ON(BrowserThread::UI); + ClosePortImpl(port_id, content::ChildProcessHost::kInvalidUniqueID, + MSG_ROUTING_NONE, true, error_message); +} +void MessageService::ClosePortImpl(int port_id, + int process_id, + int routing_id, + bool force_close, + const std::string& error_message) { // Note: The channel might be gone already, if the other side closed first. int channel_id = GET_CHANNEL_ID(port_id); MessageChannelMap::iterator it = channels_.find(channel_id); @@ -675,12 +675,23 @@ if (pending != pending_lazy_background_page_channels_.end()) { lazy_background_task_queue_->AddPendingTask( pending->second.first, pending->second.second, - base::Bind(&MessageService::PendingLazyBackgroundPageCloseChannel, - weak_factory_.GetWeakPtr(), port_id, error_message)); + base::Bind(&MessageService::PendingLazyBackgroundPageClosePort, + weak_factory_.GetWeakPtr(), port_id, process_id, + routing_id, force_close, error_message)); } return; } - CloseChannelImpl(it, port_id, error_message, true); + + // The difference between closing a channel and port is that closing a port + // does not necessarily have to destroy the channel if there are multiple + // receivers, whereas closing a channel always forces all ports to be closed. + if (force_close) { + CloseChannelImpl(it, port_id, error_message, true); + } else if (IS_OPENER_PORT_ID(port_id)) { + it->second->opener->ClosePort(process_id, routing_id); + } else { + it->second->receiver->ClosePort(process_id, routing_id); + } } void MessageService::CloseChannelImpl( @@ -696,8 +707,7 @@ if (notify_other_port) { MessagePort* port = IS_OPENER_PORT_ID(closing_port_id) ? channel->receiver.get() : channel->opener.get(); - port->DispatchOnDisconnect(GET_OPPOSITE_PORT_ID(closing_port_id), - error_message); + port->DispatchOnDisconnect(error_message); } // Balance the IncrementLazyKeepaliveCount() in OpenChannelImpl. @@ -723,53 +733,6 @@ DispatchMessage(source_port_id, iter->second, message); } -void MessageService::Observe(int type, - const content::NotificationSource& source, - const content::NotificationDetails& details) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - - switch (type) { - case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED: - case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: { - content::RenderProcessHost* renderer = - content::Source<content::RenderProcessHost>(source).ptr(); - OnProcessClosed(renderer); - break; - } - default: - NOTREACHED(); - return; - } -} - -void MessageService::OnProcessClosed(content::RenderProcessHost* process) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - - // Close any channels that share this renderer. We notify the opposite - // port that its pair has closed. - for (MessageChannelMap::iterator it = channels_.begin(); - it != channels_.end(); ) { - MessageChannelMap::iterator current = it++; - - content::RenderProcessHost* opener_process = - current->second->opener->GetRenderProcessHost(); - content::RenderProcessHost* receiver_process = - current->second->receiver->GetRenderProcessHost(); - - // Only notify the other side if it has a different porocess host. - bool notify_other_port = opener_process && receiver_process && - opener_process != receiver_process; - - if (opener_process == process) { - CloseChannelImpl(current, GET_CHANNEL_OPENER_ID(current->first), - std::string(), notify_other_port); - } else if (receiver_process == process) { - CloseChannelImpl(current, GET_CHANNEL_RECEIVERS_ID(current->first), - std::string(), notify_other_port); - } - } -} - void MessageService::EnqueuePendingMessage(int source_port_id, int channel_id, const Message& message) { @@ -827,7 +790,7 @@ MessagePort* port = IS_OPENER_PORT_ID(dest_port_id) ? channel->opener.get() : channel->receiver.get(); - port->DispatchOnMessage(message, dest_port_id); + port->DispatchOnMessage(message); } bool MessageService::MaybeAddPendingLazyBackgroundPageOpenChannelTask( @@ -882,8 +845,9 @@ pending_incognito_channels_.erase(pending_for_incognito); // Re-lookup the source process since it may no longer be valid. - content::RenderProcessHost* source = - content::RenderProcessHost::FromID(params->source_process_id); + content::RenderFrameHost* source = + content::RenderFrameHost::FromID(params->source_process_id, + params->source_routing_id); if (!source) { return; } @@ -894,14 +858,20 @@ return; } - BrowserContext* context = source->GetBrowserContext(); + BrowserContext* context = source->GetProcess()->GetBrowserContext(); // Note: we use the source's profile here. If the source is an incognito // process, we will use the incognito EPM to find the right extension process, // which depends on whether the extension uses spanning or split mode. - params->receiver.reset(new ExtensionMessagePort( - GetExtensionProcess(context, params->target_extension_id), - MSG_ROUTING_CONTROL, params->target_extension_id)); + if (content::RenderProcessHost* extension_process = + GetExtensionProcess(context, params->target_extension_id)) { + params->receiver.reset( + new ExtensionMessagePort( + weak_factory_.GetWeakPtr(), params->receiver_port_id, + params->target_extension_id, extension_process)); + } else { + params->receiver.reset(); + } // If the target requests the TLS channel id, begin the lookup for it. // The target might also be a lazy background page, checked next, but the @@ -957,13 +927,14 @@ pending_tls_channel_id_channels_.erase(pending_for_tls_channel_id); // Re-lookup the source process since it may no longer be valid. - content::RenderProcessHost* source = - content::RenderProcessHost::FromID(params->source_process_id); + content::RenderFrameHost* source = + content::RenderFrameHost::FromID(params->source_process_id, + params->source_routing_id); if (!source) { return; } - BrowserContext* context = source->GetBrowserContext(); + BrowserContext* context = source->GetProcess()->GetBrowserContext(); ExtensionRegistry* registry = ExtensionRegistry::Get(context); const Extension* target_extension = registry->enabled_extensions().GetByID(params->target_extension_id); @@ -990,20 +961,22 @@ if (!host) return; // TODO(mpcomplete): notify source of disconnect? - params->receiver.reset(new ExtensionMessagePort(host->render_process_host(), - MSG_ROUTING_CONTROL, - params->target_extension_id)); + params->receiver.reset( + new ExtensionMessagePort( + weak_factory_.GetWeakPtr(), params->receiver_port_id, + params->target_extension_id, host->render_process_host())); OpenChannelImpl(host->browser_context(), std::move(params), host->extension(), true /* did_enqueue */); } -void MessageService::DispatchOnDisconnect(content::RenderProcessHost* source, +void MessageService::DispatchOnDisconnect(content::RenderFrameHost* source, int port_id, const std::string& error_message) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - ExtensionMessagePort port(source, MSG_ROUTING_CONTROL, ""); - port.DispatchOnDisconnect(GET_OPPOSITE_PORT_ID(port_id), error_message); + ExtensionMessagePort port(weak_factory_.GetWeakPtr(), + GET_OPPOSITE_PORT_ID(port_id), "", source, false); + port.DispatchOnDisconnect(error_message); } void MessageService::DispatchPendingMessages(const PendingMessagesQueue& queue,
diff --git a/chrome/browser/extensions/api/messaging/message_service.h b/chrome/browser/extensions/api/messaging/message_service.h index d170b97c..08a3f96 100644 --- a/chrome/browser/extensions/api/messaging/message_service.h +++ b/chrome/browser/extensions/api/messaging/message_service.h
@@ -16,8 +16,6 @@ #include "base/memory/weak_ptr.h" #include "base/values.h" #include "chrome/browser/extensions/api/messaging/message_property_provider.h" -#include "content/public/browser/notification_observer.h" -#include "content/public/browser/notification_registrar.h" #include "extensions/browser/api/messaging/native_message_host.h" #include "extensions/browser/browser_context_keyed_api_factory.h" #include "extensions/common/api/messaging/message.h" @@ -27,8 +25,6 @@ namespace content { class BrowserContext; -class RenderProcessHost; -class WebContents; } namespace extensions { @@ -54,11 +50,8 @@ // // Terminology: // channel: connection between two ports -// port: an IPC::Message::Process interface and an optional routing_id (in the -// case that the port is a tab). The Process is usually either a -// RenderProcessHost or a RenderViewHost. -class MessageService : public BrowserContextKeyedAPI, - public content::NotificationObserver { +// port: One sender or receiver tied to one or more RenderFrameHost instances. +class MessageService : public BrowserContextKeyedAPI { public: // A messaging channel. Note that the opening port can be the same as the // receiver, if an extension background page wants to talk to its tab (for @@ -69,13 +62,15 @@ class MessagePort { public: virtual ~MessagePort() {} + + // Called right before a port is connected to a channel. If false, the port + // is not used and the channel is closed. + virtual bool IsValidPort() = 0; + // Notify the port that the channel has been opened. - virtual void DispatchOnConnect(int dest_port_id, - const std::string& channel_name, + virtual void DispatchOnConnect(const std::string& channel_name, scoped_ptr<base::DictionaryValue> source_tab, int source_frame_id, - int target_tab_id, - int target_frame_id, int guest_process_id, int guest_render_frame_routing_id, const std::string& source_extension_id, @@ -85,21 +80,22 @@ // Notify the port that the channel has been closed. If |error_message| is // non-empty, it indicates an error occurred while opening the connection. - virtual void DispatchOnDisconnect(int source_port_id, - const std::string& error_message) {} + virtual void DispatchOnDisconnect(const std::string& error_message) {} // Dispatch a message to this end of the communication. - virtual void DispatchOnMessage(const Message& message, - int target_port_id) = 0; + virtual void DispatchOnMessage(const Message& message) = 0; - // MessagPorts that target extensions will need to adjust their keepalive + // Mark the port as opened by the specific frame. + virtual void OpenPort(int process_id, int routing_id) {} + + // Close the port for the given frame. + virtual void ClosePort(int process_id, int routing_id) {} + + // MessagePorts that target extensions will need to adjust their keepalive // counts for their lazy background page. virtual void IncrementLazyKeepaliveCount() {} virtual void DecrementLazyKeepaliveCount() {} - // Get the RenderProcessHost (if any) associated with the port. - virtual content::RenderProcessHost* GetRenderProcessHost(); - protected: MessagePort() {} @@ -145,6 +141,7 @@ // are restricted to that tab, so if there are multiple tabs in that process, // only the targeted tab will receive messages. void OpenChannelToTab(int source_process_id, + int source_routing_id, int receiver_port_id, int tab_id, int frame_id, @@ -158,6 +155,14 @@ const std::string& source_extension_id, const std::string& native_app_name); + // Mark the given port as opened by the frame identified by + // (process_id, routing_id). + void OpenPort(int port_id, int process_id, int routing_id); + + // Closes the given port in the given frame. If this was the last frame or if + // |force_close| is true, then the other side is closed as well. + void ClosePort(int port_id, int process_id, int routing_id, bool force_close); + // Closes the message channel associated with the given port, and notifies // the other side. void CloseChannel(int port_id, const std::string& error_message); @@ -200,6 +205,12 @@ const Extension* target_extension, bool did_enqueue); + void ClosePortImpl(int port_id, + int process_id, + int routing_id, + bool force_close, + const std::string& error_message); + void CloseChannelImpl(MessageChannelMap::iterator channel_iter, int port_id, const std::string& error_message, @@ -209,14 +220,6 @@ // channels with the same id. void AddChannel(MessageChannel* channel, int receiver_port_id); - // content::NotificationObserver interface. - void Observe(int type, - const content::NotificationSource& source, - const content::NotificationDetails& details) override; - - // A process that might be in our list of channels has closed. - void OnProcessClosed(content::RenderProcessHost* process); - // If the channel is being opened from an incognito tab the user must allow // the connection. void OnOpenChannelAllowed(scoped_ptr<OpenChannelParams> params, bool allowed); @@ -252,11 +255,15 @@ scoped_ptr<OpenChannelParams> params, int source_process_id, extensions::ExtensionHost* host); - void PendingLazyBackgroundPageCloseChannel(int port_id, - const std::string& error_message, - extensions::ExtensionHost* host) { + void PendingLazyBackgroundPageClosePort(int port_id, + int process_id, + int routing_id, + bool force_close, + const std::string& error_message, + extensions::ExtensionHost* host) { if (host) - CloseChannel(port_id, error_message); + ClosePortImpl(port_id, process_id, routing_id, force_close, + error_message); } void PendingLazyBackgroundPagePostMessage(int port_id, const Message& message, @@ -267,7 +274,7 @@ // Immediate dispatches a disconnect to |source| for |port_id|. Sets source's // runtime.lastMessage to |error_message|, if any. - void DispatchOnDisconnect(content::RenderProcessHost* source, + void DispatchOnDisconnect(content::RenderFrameHost* source, int port_id, const std::string& error_message); @@ -282,7 +289,6 @@ static const bool kServiceIsCreatedWithBrowserContext = false; static const bool kServiceIsNULLWhileTesting = true; - content::NotificationRegistrar registrar_; MessageChannelMap channels_; // A set of channel IDs waiting for TLS channel IDs to complete opening, and // any pending messages queued to be sent on those channels. This and the
diff --git a/chrome/browser/extensions/api/messaging/native_message_port.cc b/chrome/browser/extensions/api/messaging/native_message_port.cc index 51e8478c..dc97cf8 100644 --- a/chrome/browser/extensions/api/messaging/native_message_port.cc +++ b/chrome/browser/extensions/api/messaging/native_message_port.cc
@@ -102,9 +102,16 @@ host_task_runner_->DeleteSoon(FROM_HERE, core_.release()); } -void NativeMessagePort::DispatchOnMessage( - const Message& message, - int target_port_id) { +bool NativeMessagePort::IsValidPort() { + // The native message port is immediately connected after construction, so it + // is not possible to invalidate the port between construction and connection. + // The return value doesn't matter since native messaging follows a code path + // where IsValidPort() is never called. + NOTREACHED(); + return true; +} + +void NativeMessagePort::DispatchOnMessage(const Message& message) { DCHECK(thread_checker_.CalledOnValidThread()); core_->OnMessageFromChrome(message.data); }
diff --git a/chrome/browser/extensions/api/messaging/native_message_port.h b/chrome/browser/extensions/api/messaging/native_message_port.h index 438b3176..a19485f 100644 --- a/chrome/browser/extensions/api/messaging/native_message_port.h +++ b/chrome/browser/extensions/api/messaging/native_message_port.h
@@ -21,7 +21,8 @@ ~NativeMessagePort() override; // MessageService::MessagePort implementation. - void DispatchOnMessage(const Message& message, int target_port_id) override; + bool IsValidPort() override; + void DispatchOnMessage(const Message& message) override; private: class Core;
diff --git a/chrome/browser/extensions/api/web_navigation/web_navigation_api.cc b/chrome/browser/extensions/api/web_navigation/web_navigation_api.cc index 13bf2afa..635636e 100644 --- a/chrome/browser/extensions/api/web_navigation/web_navigation_api.cc +++ b/chrome/browser/extensions/api/web_navigation/web_navigation_api.cc
@@ -26,6 +26,7 @@ #include "content/public/browser/web_contents.h" #include "content/public/common/url_constants.h" #include "extensions/browser/event_router.h" +#include "extensions/browser/extension_api_frame_id_map.h" #include "extensions/browser/view_type_utils.h" #include "net/base/net_errors.h" @@ -492,7 +493,6 @@ EXTENSION_FUNCTION_VALIDATE(params.get()); int tab_id = params->details.tab_id; int frame_id = params->details.frame_id; - int process_id = params->details.process_id; SetResult(base::Value::CreateNullValue()); @@ -516,8 +516,8 @@ observer->frame_navigation_state(); content::RenderFrameHost* render_frame_host = - frame_id == 0 ? web_contents->GetMainFrame() - : content::RenderFrameHost::FromID(process_id, frame_id); + ExtensionApiFrameIdMap::Get()->GetRenderFrameHostById(web_contents, + frame_id); if (!frame_navigation_state.IsValidFrame(render_frame_host)) return true;
diff --git a/chrome/browser/extensions/api/web_navigation/web_navigation_api_helpers.cc b/chrome/browser/extensions/api/web_navigation/web_navigation_api_helpers.cc index a8b027a..14612ed 100644 --- a/chrome/browser/extensions/api/web_navigation/web_navigation_api_helpers.cc +++ b/chrome/browser/extensions/api/web_navigation/web_navigation_api_helpers.cc
@@ -21,6 +21,7 @@ #include "content/public/browser/render_view_host.h" #include "content/public/browser/web_contents.h" #include "extensions/browser/event_router.h" +#include "extensions/browser/extension_api_frame_id_map.h" #include "extensions/common/event_filtering_info.h" #include "net/base/net_errors.h" #include "ui/base/page_transition_types.h" @@ -62,15 +63,10 @@ } // namespace int GetFrameId(content::RenderFrameHost* frame_host) { - if (!frame_host) - return -1; - return !frame_host->GetParent() ? 0 : frame_host->GetRoutingID(); + return ExtensionApiFrameIdMap::GetFrameId(frame_host); } // Constructs and dispatches an onBeforeNavigate event. -// TODO(dcheng): Is the parent process ID needed here? http://crbug.com/393640 -// Collisions are probably possible... but maybe this won't ever happen because -// of the SiteInstance grouping policies. void DispatchOnBeforeNavigate(content::WebContents* web_contents, content::RenderFrameHost* frame_host, const GURL& validated_url) {
diff --git a/chrome/browser/extensions/api/web_navigation/web_navigation_apitest.cc b/chrome/browser/extensions/api/web_navigation/web_navigation_apitest.cc index e2c2379..46d1020d 100644 --- a/chrome/browser/extensions/api/web_navigation/web_navigation_apitest.cc +++ b/chrome/browser/extensions/api/web_navigation/web_navigation_apitest.cc
@@ -44,6 +44,7 @@ #include "content/public/common/resource_type.h" #include "content/public/common/url_constants.h" #include "content/public/test/browser_test_utils.h" +#include "content/public/test/test_utils.h" #include "extensions/browser/extension_system.h" #include "extensions/common/switches.h" #include "extensions/test/result_catcher.h" @@ -739,6 +740,12 @@ << message_; } +IN_PROC_BROWSER_TEST_F(WebNavigationApiTest, CrossProcessIframe) { + content::IsolateAllSitesForTesting(base::CommandLine::ForCurrentProcess()); + ASSERT_TRUE(StartEmbeddedTestServer()); + ASSERT_TRUE(RunExtensionTest("webnavigation/crossProcessIframe")) << message_; +} + // TODO(jam): http://crbug.com/350550 #if !(defined(OS_CHROMEOS) && defined(ADDRESS_SANITIZER)) IN_PROC_BROWSER_TEST_F(WebNavigationApiTest, Crash) {
diff --git a/chrome/browser/extensions/browser_context_keyed_service_factories.cc b/chrome/browser/extensions/browser_context_keyed_service_factories.cc index 19f04056..96cf3ee 100644 --- a/chrome/browser/extensions/browser_context_keyed_service_factories.cc +++ b/chrome/browser/extensions/browser_context_keyed_service_factories.cc
@@ -21,11 +21,13 @@ #include "chrome/browser/extensions/api/extension_action/extension_action_api.h" #include "chrome/browser/extensions/api/feedback_private/feedback_private_api.h" #include "chrome/browser/extensions/api/font_settings/font_settings_api.h" +#include "chrome/browser/extensions/api/gcd_private/gcd_private_api.h" #include "chrome/browser/extensions/api/history/history_api.h" #include "chrome/browser/extensions/api/hotword_private/hotword_private_api.h" #include "chrome/browser/extensions/api/identity/identity_api.h" #include "chrome/browser/extensions/api/language_settings_private/language_settings_private_delegate_factory.h" #include "chrome/browser/extensions/api/location/location_manager.h" +#include "chrome/browser/extensions/api/mdns/mdns_api.h" #include "chrome/browser/extensions/api/omnibox/omnibox_api.h" #include "chrome/browser/extensions/api/passwords_private/passwords_private_event_router_factory.h" #include "chrome/browser/extensions/api/preference/chrome_direct_setting_api.h" @@ -57,11 +59,6 @@ #include "chrome/browser/speech/extension_api/tts_extension_api.h" #include "chrome/browser/ui/toolbar/toolbar_actions_model_factory.h" -#if !defined(OS_ANDROID) -#include "chrome/browser/extensions/api/gcd_private/gcd_private_api.h" -#include "chrome/browser/extensions/api/mdns/mdns_api.h" -#endif - #if defined(OS_CHROMEOS) #include "chrome/browser/chromeos/extensions/file_manager/event_router_factory.h" #include "chrome/browser/chromeos/extensions/input_method_api.h" @@ -98,9 +95,7 @@ extensions::ExtensionWebUIOverrideRegistrar::GetFactoryInstance(); extensions::FeedbackPrivateAPI::GetFactoryInstance(); extensions::FontSettingsAPI::GetFactoryInstance(); -#if !defined(OS_ANDROID) extensions::GcdPrivateAPI::GetFactoryInstance(); -#endif extensions::HistoryAPI::GetFactoryInstance(); extensions::HotwordPrivateEventService::GetFactoryInstance(); extensions::IdentityAPI::GetFactoryInstance(); @@ -115,9 +110,7 @@ #if defined(OS_CHROMEOS) extensions::LogPrivateAPI::GetFactoryInstance(); #endif -#if !defined(OS_ANDROID) extensions::MDnsAPI::GetFactoryInstance(); -#endif #if defined(OS_CHROMEOS) extensions::MediaPlayerAPI::GetFactoryInstance(); #endif
diff --git a/chrome/browser/extensions/extension_action_manager_unittest.cc b/chrome/browser/extensions/extension_action_manager_unittest.cc index 617c41c..f809bbcf 100644 --- a/chrome/browser/extensions/extension_action_manager_unittest.cc +++ b/chrome/browser/extensions/extension_action_manager_unittest.cc
@@ -84,7 +84,6 @@ .Set("icons", std::move(extension_icons)) .Set(action_type, std::move(action)) .Set("name", std::string("Test Extension").append(id)))) - .SetLocation(Manifest::UNPACKED) .SetID(id) .Build(); registry_->AddEnabled(extension);
diff --git a/chrome/browser/extensions/extension_disabled_ui.cc b/chrome/browser/extensions/extension_disabled_ui.cc index 0e096b5..80fdb73 100644 --- a/chrome/browser/extensions/extension_disabled_ui.cc +++ b/chrome/browser/extensions/extension_disabled_ui.cc
@@ -20,6 +20,7 @@ #include "base/strings/utf_string_conversions.h" #include "base/thread_task_runner_handle.h" #include "chrome/app/chrome_command_ids.h" +#include "chrome/browser/extensions/extension_install_error_menu_item_id_provider.h" #include "chrome/browser/extensions/extension_install_prompt.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/extension_uninstall_dialog.h" @@ -62,32 +63,6 @@ static const int kIconSize = extension_misc::EXTENSION_ICON_SMALL; -static base::LazyInstance< - std::bitset<IDC_EXTENSION_DISABLED_LAST - - IDC_EXTENSION_DISABLED_FIRST + 1> > - menu_command_ids = LAZY_INSTANCE_INITIALIZER; - -// Get an available menu ID. -int GetMenuCommandID() { - int id; - for (id = IDC_EXTENSION_DISABLED_FIRST; - id <= IDC_EXTENSION_DISABLED_LAST; ++id) { - if (!menu_command_ids.Get()[id - IDC_EXTENSION_DISABLED_FIRST]) { - menu_command_ids.Get().set(id - IDC_EXTENSION_DISABLED_FIRST); - return id; - } - } - // This should not happen. - DCHECK(id <= IDC_EXTENSION_DISABLED_LAST) << - "No available menu command IDs for ExtensionDisabledGlobalError"; - return IDC_EXTENSION_DISABLED_LAST; -} - -// Make a menu ID available when it is no longer used. -void ReleaseMenuCommandID(int id) { - menu_command_ids.Get().reset(id - IDC_EXTENSION_DISABLED_FIRST); -} - } // namespace // ExtensionDisabledDialogDelegate -------------------------------------------- @@ -214,8 +189,8 @@ scoped_ptr<extensions::ExtensionUninstallDialog> uninstall_dialog_; - // Menu command ID assigned for this extension's error. - int menu_command_id_; + // Helper to get menu command ID assigned for this extension's error. + extensions::ExtensionInstallErrorMenuItemIdProvider id_provider_; content::NotificationRegistrar registrar_; @@ -234,7 +209,6 @@ is_remote_install_(is_remote_install), icon_(icon), user_response_(IGNORED), - menu_command_id_(GetMenuCommandID()), registry_observer_(this) { if (icon_.IsEmpty()) { icon_ = gfx::Image( @@ -253,7 +227,6 @@ } ExtensionDisabledGlobalError::~ExtensionDisabledGlobalError() { - ReleaseMenuCommandID(menu_command_id_); if (is_remote_install_) { UMA_HISTOGRAM_ENUMERATION("Extensions.DisabledUIUserResponseRemoteInstall", user_response_, @@ -274,7 +247,7 @@ } int ExtensionDisabledGlobalError::MenuItemCommandID() { - return menu_command_id_; + return id_provider_.menu_command_id(); } base::string16 ExtensionDisabledGlobalError::MenuItemLabel() {
diff --git a/chrome/browser/extensions/extension_disabled_ui_browsertest.cc b/chrome/browser/extensions/extension_disabled_ui_browsertest.cc index 677922fa..47a791c 100644 --- a/chrome/browser/extensions/extension_disabled_ui_browsertest.cc +++ b/chrome/browser/extensions/extension_disabled_ui_browsertest.cc
@@ -76,7 +76,7 @@ // Caution: currently only supports one error at a time. GlobalError* GetExtensionDisabledGlobalError() { return GlobalErrorServiceFactory::GetForProfile(profile())-> - GetGlobalErrorByMenuItemCommandID(IDC_EXTENSION_DISABLED_FIRST); + GetGlobalErrorByMenuItemCommandID(IDC_EXTENSION_INSTALL_ERROR_FIRST); } // Install the initial version, which should happen just fine.
diff --git a/chrome/browser/extensions/extension_install_error_menu_item_id_provider.cc b/chrome/browser/extensions/extension_install_error_menu_item_id_provider.cc new file mode 100644 index 0000000..97b1182 --- /dev/null +++ b/chrome/browser/extensions/extension_install_error_menu_item_id_provider.cc
@@ -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. + +#include "chrome/browser/extensions/extension_install_error_menu_item_id_provider.h" + +#include <bitset> + +#include "base/lazy_instance.h" +#include "chrome/app/chrome_command_ids.h" + +namespace extensions { + +namespace { + +base::LazyInstance<std::bitset< + IDC_EXTENSION_INSTALL_ERROR_LAST - IDC_EXTENSION_INSTALL_ERROR_FIRST + 1>> + menu_command_ids = LAZY_INSTANCE_INITIALIZER; + +// Get an available menu ID. +int GetMenuCommandID() { + int id; + for (id = IDC_EXTENSION_INSTALL_ERROR_FIRST; + id <= IDC_EXTENSION_INSTALL_ERROR_LAST; ++id) { + if (!menu_command_ids.Get()[id - IDC_EXTENSION_INSTALL_ERROR_FIRST]) { + menu_command_ids.Get().set(id - IDC_EXTENSION_INSTALL_ERROR_FIRST); + return id; + } + } + // This should not happen. + DCHECK_LE(id, IDC_EXTENSION_INSTALL_ERROR_LAST) + << "No available menu command IDs for ExtensionDisabledGlobalError"; + return IDC_EXTENSION_INSTALL_ERROR_LAST; +} + +// Make a menu ID available when it is no longer used. +void ReleaseMenuCommandID(int id) { + menu_command_ids.Get().reset(id - IDC_EXTENSION_INSTALL_ERROR_FIRST); +} + +} // namespace + +ExtensionInstallErrorMenuItemIdProvider:: + ExtensionInstallErrorMenuItemIdProvider() + : menu_command_id_(GetMenuCommandID()) {} + +ExtensionInstallErrorMenuItemIdProvider:: + ~ExtensionInstallErrorMenuItemIdProvider() { + ReleaseMenuCommandID(menu_command_id_); +} + +} // namespace extensions
diff --git a/chrome/browser/extensions/extension_install_error_menu_item_id_provider.h b/chrome/browser/extensions/extension_install_error_menu_item_id_provider.h new file mode 100644 index 0000000..79c6b1b --- /dev/null +++ b/chrome/browser/extensions/extension_install_error_menu_item_id_provider.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 CHROME_BROWSER_EXTENSIONS_EXTENSION_INSTALL_ERROR_MENU_ITEM_ID_PROVIDER_H_ +#define CHROME_BROWSER_EXTENSIONS_EXTENSION_INSTALL_ERROR_MENU_ITEM_ID_PROVIDER_H_ + +#include "base/macros.h" + +namespace extensions { + +// Helper class to generate not-in-use and unique menu item id for GlobalErrors +// that require items in hotdog menu. +// +// The generated ids lie within the interval: +// [IDC_EXTENSION_INSTALL_ERROR_FIRST, IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST]. +class ExtensionInstallErrorMenuItemIdProvider { + public: + ExtensionInstallErrorMenuItemIdProvider(); + ~ExtensionInstallErrorMenuItemIdProvider(); + + int menu_command_id() { return menu_command_id_; } + + private: + int menu_command_id_; + + DISALLOW_COPY_AND_ASSIGN(ExtensionInstallErrorMenuItemIdProvider); +}; + +} // namespace extensions + +#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_INSTALL_ERROR_MENU_ITEM_ID_PROVIDER_H_
diff --git a/chrome/browser/extensions/extension_messages_apitest.cc b/chrome/browser/extensions/extension_messages_apitest.cc index eb2c6ba..e6e80c42 100644 --- a/chrome/browser/extensions/extension_messages_apitest.cc +++ b/chrome/browser/extensions/extension_messages_apitest.cc
@@ -39,6 +39,8 @@ #include "extensions/common/api/runtime.h" #include "extensions/common/extension_builder.h" #include "extensions/common/value_builder.h" +#include "extensions/test/extension_test_message_listener.h" +#include "extensions/test/result_catcher.h" #include "net/cert/asn1_util.h" #include "net/cert/jwk_serializer.h" #include "net/dns/mock_host_resolver.h" @@ -118,6 +120,22 @@ ASSERT_TRUE(RunExtensionTest("messaging/connect")) << message_; } +IN_PROC_BROWSER_TEST_F(ExtensionApiTest, MessagingCrash) { + ASSERT_TRUE(StartEmbeddedTestServer()); + ExtensionTestMessageListener ready_to_crash("ready_to_crash", true); + ASSERT_TRUE(LoadExtension( + test_data_dir_.AppendASCII("messaging/connect_crash"))); + ui_test_utils::NavigateToURL( + browser(), embedded_test_server()->GetURL("/extensions/test_file.html")); + content::WebContents* tab = + browser()->tab_strip_model()->GetActiveWebContents(); + EXPECT_TRUE(ready_to_crash.WaitUntilSatisfied()); + + ResultCatcher catcher; + CrashTab(tab); + EXPECT_TRUE(catcher.GetNextResult()); +} + // Tests that message passing from one extension to another works. IN_PROC_BROWSER_TEST_F(ExtensionApiTest, MessagingExternal) { ASSERT_TRUE(LoadExtension(
diff --git a/chrome/browser/extensions/extension_service_test_with_install.cc b/chrome/browser/extensions/extension_service_test_with_install.cc index 8f93b2c..f2cedef 100644 --- a/chrome/browser/extensions/extension_service_test_with_install.cc +++ b/chrome/browser/extensions/extension_service_test_with_install.cc
@@ -126,20 +126,6 @@ Extension::NO_FLAGS); } -const Extension* ExtensionServiceTestWithInstall::PackAndInstallCRXWithLocation( - const base::FilePath& dir_path, - Manifest::Location location, - InstallState install_state) { - // TODO(devlin): reuse another function instead of reimplementing here. - base::FilePath crx_path; - base::ScopedTempDir temp_dir; - EXPECT_TRUE(temp_dir.CreateUniqueTempDir()); - crx_path = temp_dir.path().AppendASCII("temp.crx"); - - PackCRX(dir_path, base::FilePath(), crx_path); - return InstallCRXWithLocation(crx_path, location, install_state); -} - // Attempts to install an extension. Use INSTALL_FAILED if the installation // is expected to fail. // If |install_state| is INSTALL_UPDATED, and |expected_old_name| is
diff --git a/chrome/browser/extensions/extension_service_test_with_install.h b/chrome/browser/extensions/extension_service_test_with_install.h index bb9e6dc..0be2d9a 100644 --- a/chrome/browser/extensions/extension_service_test_with_install.h +++ b/chrome/browser/extensions/extension_service_test_with_install.h
@@ -58,9 +58,6 @@ InstallState install_state); const Extension* PackAndInstallCRX(const base::FilePath& dir_path, InstallState install_state); - const Extension* PackAndInstallCRXWithLocation(const base::FilePath& dir_path, - Manifest::Location location, - InstallState install_state); const Extension* InstallCRX(const base::FilePath& path, InstallState install_state,
diff --git a/chrome/browser/extensions/extension_service_unittest.cc b/chrome/browser/extensions/extension_service_unittest.cc index 084ca228..511226ed 100644 --- a/chrome/browser/extensions/extension_service_unittest.cc +++ b/chrome/browser/extensions/extension_service_unittest.cc
@@ -163,6 +163,7 @@ using extensions::ExtensionRegistry; using extensions::ExtensionResource; using extensions::ExtensionSystem; +using extensions::ExternalInstallError; using extensions::FakeSafeBrowsingDatabaseManager; using extensions::FeatureSwitch; using extensions::Manifest; @@ -182,6 +183,7 @@ const char all_zero[] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; const char good2048[] = "nmgjhmhbleinmjpbdhgajfjkbijcmgbh"; const char good_crx[] = "ldnnhddmnhbkjipkidpdiheffobcpfmf"; +const char minimal_platform_app_crx[] = "jjeoclcdfjddkdjokiejckgcildcflpp"; const char hosted_app[] = "kbmnembihfiondgfjekmnmcbddelicoi"; const char page_action[] = "obcimlgaoabeegjmmpldobjndiealpln"; const char theme_crx[] = "iamefpfkojoapidjnbafmgkgncegbkad"; @@ -205,6 +207,21 @@ return --(*count) == 0; } +bool HasExternalInstallErrors(ExtensionService* service) { + return !service->external_install_manager()->GetErrorsForTesting().empty(); +} + +bool HasExternalInstallBubble(ExtensionService* service) { + std::vector<ExternalInstallError*> errors = + service->external_install_manager()->GetErrorsForTesting(); + auto found = std::find_if( + errors.begin(), errors.end(), + [](const ExternalInstallError* error) { + return error->alert_type() == ExternalInstallError::BUBBLE_ALERT; + }); + return found != errors.end(); +} + } // namespace class MockExtensionProvider : public extensions::ExternalProviderInterface { @@ -633,7 +650,17 @@ return ExtensionSystem::Get(browser_context())->management_policy(); } - protected: + ExternalInstallError* GetError(const std::string& extension_id) { + std::vector<ExternalInstallError*> errors = + service_->external_install_manager()->GetErrorsForTesting(); + auto found = std::find_if( + errors.begin(), errors.end(), + [&extension_id](const ExternalInstallError* error) { + return error->extension_id() == extension_id; + }); + return found == errors.end() ? nullptr : *found; + } + typedef extensions::ExtensionManagementPrefUpdater< syncable_prefs::TestingPrefServiceSyncable> ManagementPrefUpdater; }; @@ -5845,8 +5872,7 @@ service()->external_install_manager()->UpdateExternalExtensionAlert(); // Should return false, meaning there aren't any extensions that the user // needs to know about. - EXPECT_FALSE( - service()->external_install_manager()->HasExternalInstallError()); + EXPECT_FALSE(HasExternalInstallErrors(service())); // This is a normal extension, installed normally. // This should NOT trigger an alert. @@ -5856,8 +5882,7 @@ service()->CheckForExternalUpdates(); base::RunLoop().RunUntilIdle(); - EXPECT_FALSE( - service()->external_install_manager()->HasExternalInstallError()); + EXPECT_FALSE(HasExternalInstallErrors(service())); // A hosted app, installed externally. // This should NOT trigger an alert. @@ -5869,8 +5894,7 @@ content::NotificationService::AllSources()); service()->CheckForExternalUpdates(); observer.Wait(); - EXPECT_FALSE( - service()->external_install_manager()->HasExternalInstallError()); + EXPECT_FALSE(HasExternalInstallErrors(service())); // Another normal extension, but installed externally. // This SHOULD trigger an alert. @@ -5882,7 +5906,7 @@ content::NotificationService::AllSources()); service()->CheckForExternalUpdates(); observer2.Wait(); - EXPECT_TRUE(service()->external_install_manager()->HasExternalInstallError()); + EXPECT_TRUE(HasExternalInstallErrors(service())); } // Test that external extensions are initially disabled, and that enabling @@ -5904,7 +5928,7 @@ content::NotificationService::AllSources()); service()->CheckForExternalUpdates(); observer.Wait(); - EXPECT_TRUE(service()->external_install_manager()->HasExternalInstallError()); + EXPECT_TRUE(HasExternalInstallErrors(service())); EXPECT_FALSE(service()->IsExtensionEnabled(page_action)); const Extension* extension = @@ -5913,8 +5937,7 @@ EXPECT_EQ(page_action, extension->id()); service()->EnableExtension(page_action); - EXPECT_FALSE( - service()->external_install_manager()->HasExternalInstallError()); + EXPECT_FALSE(HasExternalInstallErrors(service())); EXPECT_TRUE(service()->IsExtensionEnabled(page_action)); } @@ -5949,29 +5972,94 @@ base::Bind(&WaitForCountNotificationsCallback, &count)); service()->CheckForExternalUpdates(); observer.Wait(); - EXPECT_TRUE(service()->external_install_manager()->HasExternalInstallError()); + EXPECT_TRUE(HasExternalInstallErrors(service())); EXPECT_FALSE(service()->IsExtensionEnabled(page_action)); EXPECT_FALSE(service()->IsExtensionEnabled(good_crx)); EXPECT_FALSE(service()->IsExtensionEnabled(theme_crx)); service()->EnableExtension(page_action); - EXPECT_TRUE(service()->external_install_manager()->HasExternalInstallError()); - EXPECT_FALSE(service() - ->external_install_manager() - ->HasExternalInstallBubbleForTesting()); + EXPECT_FALSE(GetError(page_action)); + EXPECT_TRUE(GetError(good_crx)); + EXPECT_TRUE(GetError(theme_crx)); + EXPECT_TRUE(HasExternalInstallErrors(service())); + EXPECT_FALSE(HasExternalInstallBubble(service())); service()->EnableExtension(theme_crx); - EXPECT_TRUE(service()->external_install_manager()->HasExternalInstallError()); - EXPECT_FALSE(service() - ->external_install_manager() - ->HasExternalInstallBubbleForTesting()); + EXPECT_FALSE(GetError(page_action)); + EXPECT_FALSE(GetError(theme_crx)); + EXPECT_TRUE(GetError(good_crx)); + EXPECT_TRUE(HasExternalInstallErrors(service())); + EXPECT_FALSE(HasExternalInstallBubble(service())); service()->EnableExtension(good_crx); - EXPECT_FALSE( - service()->external_install_manager()->HasExternalInstallError()); - EXPECT_FALSE(service() - ->external_install_manager() - ->HasExternalInstallBubbleForTesting()); + EXPECT_FALSE(GetError(page_action)); + EXPECT_FALSE(GetError(good_crx)); + EXPECT_FALSE(GetError(theme_crx)); + EXPECT_FALSE(HasExternalInstallErrors(service())); + EXPECT_FALSE(HasExternalInstallBubble(service())); +} + +TEST_F(ExtensionServiceTest, MultipleExternalInstallErrors) { + FeatureSwitch::ScopedOverride prompt( + FeatureSwitch::prompt_for_external_extensions(), true); + InitializeEmptyExtensionService(); + service()->set_extensions_enabled(true); + + MockExtensionProvider* reg_provider = + new MockExtensionProvider(service(), Manifest::EXTERNAL_REGISTRY); + AddMockExternalProvider(reg_provider); + + std::string extension_info[][3] = { + // {id, path, version} + {good_crx, "1.0.0.0", "good.crx"}, + {page_action, "1.0.0.0", "page_action.crx"}, + {minimal_platform_app_crx, "0.1", "minimal_platform_app.crx"}}; + + for (size_t i = 0; i < arraysize(extension_info); ++i) { + reg_provider->UpdateOrAddExtension( + extension_info[i][0], extension_info[i][1], + data_dir().AppendASCII(extension_info[i][2])); + content::WindowedNotificationObserver observer( + extensions::NOTIFICATION_CRX_INSTALLER_DONE, + content::NotificationService::AllSources()); + service()->CheckForExternalUpdates(); + observer.Wait(); + const size_t expected_error_count = i + 1u; + EXPECT_EQ( + expected_error_count, + service()->external_install_manager()->GetErrorsForTesting().size()); + EXPECT_FALSE(service()->IsExtensionEnabled(extension_info[i][0])); + } + + std::string extension_ids[] = { + extension_info[0][0], extension_info[1][0], extension_info[2][0] + }; + + // Each extension should end up in error. + ASSERT_TRUE(GetError(extension_ids[0])); + EXPECT_TRUE(GetError(extension_ids[1])); + EXPECT_TRUE(GetError(extension_ids[2])); + + // Accept the first extension, this will remove the error associated with + // this extension. Also verify the other errors still exist. + GetError(extension_ids[0])->InstallUIProceed(); + EXPECT_FALSE(GetError(extension_ids[0])); + ASSERT_TRUE(GetError(extension_ids[1])); + EXPECT_TRUE(GetError(extension_ids[2])); + + // Abort the second extension. + GetError(extension_ids[1])->InstallUIAbort(true); + EXPECT_FALSE(GetError(extension_ids[0])); + EXPECT_FALSE(GetError(extension_ids[1])); + ASSERT_TRUE(GetError(extension_ids[2])); + + // Finally, re-enable the third extension, all errors should be removed. + service()->EnableExtension(extension_ids[2]); + EXPECT_FALSE(GetError(extension_ids[0])); + EXPECT_FALSE(GetError(extension_ids[1])); + EXPECT_FALSE(GetError(extension_ids[2])); + + EXPECT_FALSE(HasExternalInstallErrors(service_)); } // Test that there is a bubble for external extensions that update @@ -6001,10 +6089,10 @@ content::NotificationService::AllSources()); service()->CheckForExternalUpdates(); observer.Wait(); - EXPECT_TRUE(service()->external_install_manager()->HasExternalInstallError()); - EXPECT_TRUE(service() - ->external_install_manager() - ->HasExternalInstallBubbleForTesting()); + EXPECT_TRUE(HasExternalInstallErrors(service())); + ASSERT_TRUE(GetError(updates_from_webstore)); + EXPECT_EQ(ExternalInstallError::BUBBLE_ALERT, + GetError(updates_from_webstore)->alert_type()); EXPECT_FALSE(service()->IsExtensionEnabled(updates_from_webstore)); } @@ -6030,10 +6118,10 @@ content::NotificationService::AllSources()); service()->CheckForExternalUpdates(); observer.Wait(); - EXPECT_TRUE(service()->external_install_manager()->HasExternalInstallError()); - EXPECT_FALSE(service() - ->external_install_manager() - ->HasExternalInstallBubbleForTesting()); + EXPECT_TRUE(HasExternalInstallErrors(service())); + ASSERT_TRUE(GetError(updates_from_webstore)); + EXPECT_NE(ExternalInstallError::BUBBLE_ALERT, + GetError(updates_from_webstore)->alert_type()); EXPECT_FALSE(service()->IsExtensionEnabled(updates_from_webstore)); } @@ -6062,7 +6150,7 @@ content::NotificationService::AllSources()); service_->CheckForExternalUpdates(); observer.Wait(); - EXPECT_TRUE(service_->external_install_manager()->HasExternalInstallError()); + EXPECT_TRUE(HasExternalInstallErrors(service_)); // We check both enabled and disabled, since these are "eventually exclusive" // sets. @@ -6070,13 +6158,14 @@ EXPECT_FALSE(registry()->enabled_extensions().GetByID(updates_from_webstore)); // Click the negative response. - service_->external_install_manager()->error_for_testing()->InstallUIAbort( - true); + service_->external_install_manager() + ->GetErrorsForTesting()[0] + ->InstallUIAbort(true); // The Extension should be uninstalled. EXPECT_FALSE(registry()->GetExtensionById(updates_from_webstore, ExtensionRegistry::EVERYTHING)); // The error should be removed. - EXPECT_FALSE(service_->external_install_manager()->HasExternalInstallError()); + EXPECT_FALSE(HasExternalInstallErrors(service_)); } // Test that clicking to keep the extension on an external install warning @@ -6104,7 +6193,7 @@ content::NotificationService::AllSources()); service_->CheckForExternalUpdates(); observer.Wait(); - EXPECT_TRUE(service_->external_install_manager()->HasExternalInstallError()); + EXPECT_TRUE(HasExternalInstallErrors(service_)); // We check both enabled and disabled, since these are "eventually exclusive" // sets. @@ -6112,7 +6201,9 @@ EXPECT_FALSE(registry()->enabled_extensions().GetByID(updates_from_webstore)); // Accept the extension. - service_->external_install_manager()->error_for_testing()->InstallUIProceed(); + service_->external_install_manager() + ->GetErrorsForTesting()[0] + ->InstallUIProceed(); // It should be enabled again. EXPECT_TRUE(registry()->enabled_extensions().GetByID(updates_from_webstore)); @@ -6120,7 +6211,7 @@ registry()->disabled_extensions().GetByID(updates_from_webstore)); // The error should be removed. - EXPECT_FALSE(service_->external_install_manager()->HasExternalInstallError()); + EXPECT_FALSE(HasExternalInstallErrors(service_)); } TEST_F(ExtensionServiceTest, InstallBlacklistedExtension) {
diff --git a/chrome/browser/extensions/external_install_error.cc b/chrome/browser/extensions/external_install_error.cc index 3b52ef7..e704895 100644 --- a/chrome/browser/extensions/external_install_error.cc +++ b/chrome/browser/extensions/external_install_error.cc
@@ -11,6 +11,7 @@ #include "base/macros.h" #include "base/strings/utf_string_conversions.h" #include "chrome/app/chrome_command_ids.h" +#include "chrome/browser/extensions/extension_install_error_menu_item_id_provider.h" #include "chrome/browser/extensions/extension_install_prompt_show_params.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/external_install_manager.h" @@ -73,6 +74,9 @@ // The owning ExternalInstallError. ExternalInstallError* error_; + // Provides menu item id for GlobalError. + ExtensionInstallErrorMenuItemIdProvider id_provider_; + DISALLOW_COPY_AND_ASSIGN(ExternalInstallMenuAlert); }; @@ -103,6 +107,7 @@ // The owning ExternalInstallError. ExternalInstallError* error_; + ExtensionInstallErrorMenuItemIdProvider id_provider_; // The Prompt with all information, which we then use to populate the bubble. // Owned by |error|. @@ -130,7 +135,7 @@ } int ExternalInstallMenuAlert::MenuItemCommandID() { - return IDC_EXTERNAL_EXTENSION_ALERT; + return id_provider_.menu_command_id(); } base::string16 ExternalInstallMenuAlert::MenuItemLabel() { @@ -181,7 +186,7 @@ } int ExternalInstallBubbleAlert::MenuItemCommandID() { - return IDC_EXTERNAL_EXTENSION_ALERT; + return id_provider_.menu_command_id(); } base::string16 ExternalInstallBubbleAlert::MenuItemLabel() { @@ -308,7 +313,7 @@ // remove the error... } else { // ... Otherwise we have to do it explicitly. - manager_->RemoveExternalInstallError(); + manager_->RemoveExternalInstallError(extension_id_); } } @@ -324,7 +329,7 @@ // remove the error... } else { // ... Otherwise we have to do it explicitly. - manager_->RemoveExternalInstallError(); + manager_->RemoveExternalInstallError(extension_id_); } }
diff --git a/chrome/browser/extensions/external_install_manager.cc b/chrome/browser/extensions/external_install_manager.cc index 27557d5..385e81bc 100644 --- a/chrome/browser/extensions/external_install_manager.cc +++ b/chrome/browser/extensions/external_install_manager.cc
@@ -8,6 +8,7 @@ #include "base/logging.h" #include "base/metrics/histogram.h" +#include "chrome/app/chrome_command_ids.h" #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/extensions/external_install_error.h" #include "chrome/browser/profiles/profile.h" @@ -75,71 +76,60 @@ void ExternalInstallManager::AddExternalInstallError(const Extension* extension, bool is_new_profile) { - if (HasExternalInstallError()) - return; // Only have one external install error at a time. + // Error already exists. + if (ContainsKey(errors_, extension->id())) + return; ExternalInstallError::AlertType alert_type = (ManifestURL::UpdatesFromGallery(extension) && !is_new_profile) ? ExternalInstallError::BUBBLE_ALERT : ExternalInstallError::MENU_ALERT; - error_.reset(new ExternalInstallError( + scoped_ptr<ExternalInstallError> error(new ExternalInstallError( browser_context_, extension->id(), alert_type, this)); + errors_.insert(std::make_pair(extension->id(), std::move(error))); } -void ExternalInstallManager::RemoveExternalInstallError() { - error_.reset(); +void ExternalInstallManager::RemoveExternalInstallError( + const std::string& extension_id) { + errors_.erase(extension_id); UpdateExternalExtensionAlert(); } -bool ExternalInstallManager::HasExternalInstallError() const { - return error_.get() != NULL; -} - void ExternalInstallManager::UpdateExternalExtensionAlert() { - // If the feature is not enabled, or there is already an error displayed, do - // nothing. - if (!FeatureSwitch::prompt_for_external_extensions()->IsEnabled() || - HasExternalInstallError()) { + // If the feature is not enabled do nothing. + if (!FeatureSwitch::prompt_for_external_extensions()->IsEnabled()) return; - } // Look for any extensions that were disabled because of being unacknowledged // external extensions. - const Extension* extension = NULL; const ExtensionSet& disabled_extensions = ExtensionRegistry::Get(browser_context_)->disabled_extensions(); - for (ExtensionSet::const_iterator iter = disabled_extensions.begin(); - iter != disabled_extensions.end(); - ++iter) { - if (IsUnacknowledgedExternalExtension(iter->get())) { - extension = iter->get(); - break; + for (const scoped_refptr<const Extension>& extension : disabled_extensions) { + if (ContainsKey(errors_, extension->id())) + continue; + + if (!IsUnacknowledgedExternalExtension(extension.get())) + continue; + + // Warn the user about the suspicious extension. + if (extension_prefs_->IncrementAcknowledgePromptCount(extension->id()) > + kMaxExtensionAcknowledgePromptCount) { + // Stop prompting for this extension and record metrics. + extension_prefs_->AcknowledgeExternalExtension(extension->id()); + LogExternalExtensionEvent(extension.get(), EXTERNAL_EXTENSION_IGNORED); + continue; } + + if (is_first_run_) + extension_prefs_->SetExternalInstallFirstRun(extension->id()); + + // |first_run| is true if the extension was installed during a first run + // (even if it's post-first run now). + AddExternalInstallError( + extension.get(), + extension_prefs_->IsExternalInstallFirstRun(extension->id())); } - - if (!extension) - return; // No unacknowledged external extensions. - - // Otherwise, warn the user about the suspicious extension. - if (extension_prefs_->IncrementAcknowledgePromptCount(extension->id()) > - kMaxExtensionAcknowledgePromptCount) { - // Stop prompting for this extension and record metrics. - extension_prefs_->AcknowledgeExternalExtension(extension->id()); - LogExternalExtensionEvent(extension, EXTERNAL_EXTENSION_IGNORED); - - // Check if there's another extension that needs prompting. - UpdateExternalExtensionAlert(); - return; - } - - if (is_first_run_) - extension_prefs_->SetExternalInstallFirstRun(extension->id()); - - // |first_run| is true if the extension was installed during a first run - // (even if it's post-first run now). - AddExternalInstallError( - extension, extension_prefs_->IsExternalInstallFirstRun(extension->id())); } void ExternalInstallManager::AcknowledgeExternalExtension( @@ -148,9 +138,12 @@ UpdateExternalExtensionAlert(); } -bool ExternalInstallManager::HasExternalInstallBubbleForTesting() const { - return error_.get() && - error_->alert_type() == ExternalInstallError::BUBBLE_ALERT; +std::vector<ExternalInstallError*> +ExternalInstallManager::GetErrorsForTesting() { + std::vector<ExternalInstallError*> errors; + for (auto const& error : errors_) + errors.push_back(error.second.get()); + return errors; } void ExternalInstallManager::OnExtensionLoaded( @@ -165,8 +158,7 @@ LogExternalExtensionEvent(extension, EXTERNAL_EXTENSION_REENABLED); // If we had an error for this extension, remove it. - if (error_.get() && extension->id() == error_->extension_id()) - RemoveExternalInstallError(); + RemoveExternalInstallError(extension->id()); } void ExternalInstallManager::OnExtensionInstalled( @@ -217,11 +209,10 @@ // It's a shame we have to use the notification system (instead of the // registry observer) for this, but the ExtensionUnloaded notification is // not sent out if the extension is disabled (which it is here). - if (error_.get() && - content::Details<const Extension>(details).ptr()->id() == - error_->extension_id()) { - RemoveExternalInstallError(); - } + const std::string& extension_id = + content::Details<const Extension>(details).ptr()->id(); + if (ContainsKey(errors_, extension_id)) + RemoveExternalInstallError(extension_id); } } // namespace extensions
diff --git a/chrome/browser/extensions/external_install_manager.h b/chrome/browser/extensions/external_install_manager.h index cd351af..5312283 100644 --- a/chrome/browser/extensions/external_install_manager.h +++ b/chrome/browser/extensions/external_install_manager.h
@@ -5,6 +5,8 @@ #ifndef CHROME_BROWSER_EXTENSIONS_EXTERNAL_INSTALL_MANAGER_H_ #define CHROME_BROWSER_EXTENSIONS_EXTERNAL_INSTALL_MANAGER_H_ +#include <map> + #include "base/macros.h" #include "base/memory/scoped_ptr.h" #include "base/scoped_observer.h" @@ -31,11 +33,8 @@ bool is_first_run); ~ExternalInstallManager() override; - // Removes the global error, if one existed. - void RemoveExternalInstallError(); - - // Returns true if there is a global error for an external install. - bool HasExternalInstallError() const; + // Removes the error associated with a given extension. + void RemoveExternalInstallError(const std::string& extension_id); // Checks if there are any new external extensions to notify the user about. void UpdateExternalExtensionAlert(); @@ -44,15 +43,8 @@ // acknowledged. void AcknowledgeExternalExtension(const std::string& extension_id); - // Returns true if there is a global error with a bubble view for an external - // install. Used for testing. - bool HasExternalInstallBubbleForTesting() const; - - // Returns the current install error, if one exists. - const ExternalInstallError* error() { return error_.get(); } - - // Returns a mutable copy of the error for testing purposes. - ExternalInstallError* error_for_testing() { return error_.get(); } + // Returns a mutable copy of the list of global errors for testing purposes. + std::vector<ExternalInstallError*> GetErrorsForTesting(); private: // ExtensionRegistryObserver implementation. @@ -88,8 +80,8 @@ // The associated ExtensionPrefs. ExtensionPrefs* extension_prefs_; - // The current ExternalInstallError, if one exists. - scoped_ptr<ExternalInstallError> error_; + // The collection of ExternalInstallErrors. + std::map<std::string, scoped_ptr<ExternalInstallError>> errors_; content::NotificationRegistrar registrar_;
diff --git a/chrome/browser/extensions/updater/chrome_extension_downloader_factory.cc b/chrome/browser/extensions/updater/chrome_extension_downloader_factory.cc index 244aed9..667a1901 100644 --- a/chrome/browser/extensions/updater/chrome_extension_downloader_factory.cc +++ b/chrome/browser/extensions/updater/chrome_extension_downloader_factory.cc
@@ -7,6 +7,8 @@ #include <string> #include <utility> + +#include "base/command_line.h" #include "chrome/browser/google/google_brand.h" #include "chrome/browser/metrics/chrome_metrics_service_accessor.h" #include "chrome/browser/profiles/profile.h" @@ -23,6 +25,10 @@ using extensions::ExtensionDownloaderDelegate; using update_client::UpdateQueryParams; +namespace { +const char kTestRequestParam[] = "extension-updater-test-request"; +} // namespace + scoped_ptr<ExtensionDownloader> ChromeExtensionDownloaderFactory::CreateForRequestContext( net::URLRequestContextGetter* request_context, @@ -35,8 +41,14 @@ if (!brand.empty() && !google_brand::IsOrganic(brand)) downloader->set_brand_code(brand); #endif // defined(GOOGLE_CHROME_BUILD) - downloader->set_manifest_query_params( - UpdateQueryParams::Get(UpdateQueryParams::CRX)); + std::string manifest_query_params = + UpdateQueryParams::Get(UpdateQueryParams::CRX); + base::CommandLine* command_line = + base::CommandLine::ForCurrentProcess(); + if (command_line->HasSwitch(kTestRequestParam)) { + manifest_query_params += "&testrequest=1"; + } + downloader->set_manifest_query_params(manifest_query_params); downloader->set_ping_enabled_domain("google.com"); downloader->set_enable_extra_update_metrics( ChromeMetricsServiceAccessor::IsMetricsAndCrashReportingEnabled());
diff --git a/chrome/browser/local_discovery/cloud_device_list.cc b/chrome/browser/local_discovery/cloud_device_list.cc deleted file mode 100644 index 95c2a7f9..0000000 --- a/chrome/browser/local_discovery/cloud_device_list.cc +++ /dev/null
@@ -1,82 +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/local_discovery/cloud_device_list.h" - -#include <utility> - -#include "base/strings/stringprintf.h" -#include "chrome/browser/local_discovery/gcd_constants.h" -#include "components/cloud_devices/common/cloud_devices_urls.h" - -namespace local_discovery { - -namespace { -const char kKindDevicesList[] = "clouddevices#devicesListResponse"; -} - -CloudDeviceList::CloudDeviceList(CloudDeviceListDelegate* delegate) - : delegate_(delegate) { -} - -CloudDeviceList::~CloudDeviceList() { -} - -void CloudDeviceList::OnGCDAPIFlowError(GCDApiFlow::Status status) { - delegate_->OnDeviceListUnavailable(); -} - -void CloudDeviceList::OnGCDAPIFlowComplete(const base::DictionaryValue& value) { - std::string kind; - value.GetString(kGCDKeyKind, &kind); - - const base::ListValue* devices = NULL; - if (kind != kKindDevicesList || !value.GetList("devices", &devices)) { - delegate_->OnDeviceListUnavailable(); - return; - } - - std::vector<CloudDeviceListDelegate::Device> result; - for (base::ListValue::const_iterator i = devices->begin(); - i != devices->end(); i++) { - base::DictionaryValue* device; - CloudDeviceListDelegate::Device details; - - if (!(*i)->GetAsDictionary(&device)) - continue; - - if (!FillDeviceDetails(*device, &details)) - continue; - - result.push_back(details); - } - - delegate_->OnDeviceListReady(result); -} - -GURL CloudDeviceList::GetURL() { - return cloud_devices::GetCloudDevicesRelativeURL("devices"); -} - -bool CloudDeviceList::FillDeviceDetails( - const base::DictionaryValue& device_value, - CloudDeviceListDelegate::Device* details) { - if (!device_value.GetString("id", &details->id)) - return false; - - if (!device_value.GetString("displayName", &details->display_name) && - !device_value.GetString("systemName", &details->display_name)) { - return false; - } - - if (!device_value.GetString("deviceKind", &details->type)) - return false; - - // Non-essential. - device_value.GetString("description", &details->description); - - return true; -} - -} // namespace local_discovery
diff --git a/chrome/browser/local_discovery/cloud_device_list.h b/chrome/browser/local_discovery/cloud_device_list.h deleted file mode 100644 index 1f75efd..0000000 --- a/chrome/browser/local_discovery/cloud_device_list.h +++ /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. - -#ifndef CHROME_BROWSER_LOCAL_DISCOVERY_CLOUD_DEVICE_LIST_H_ -#define CHROME_BROWSER_LOCAL_DISCOVERY_CLOUD_DEVICE_LIST_H_ - -#include <string> -#include <vector> - -#include "base/values.h" -#include "chrome/browser/local_discovery/cloud_device_list_delegate.h" -#include "chrome/browser/local_discovery/gcd_api_flow.h" - -namespace local_discovery { - -class CloudDeviceList : public GCDApiFlowRequest { - public: - typedef std::vector<CloudDeviceListDelegate::Device> DeviceList; - typedef DeviceList::const_iterator iterator; - - explicit CloudDeviceList(CloudDeviceListDelegate* delegate); - ~CloudDeviceList() override; - - void OnGCDAPIFlowError(GCDApiFlow::Status status) override; - - void OnGCDAPIFlowComplete(const base::DictionaryValue& value) override; - - GURL GetURL() override; - - private: - bool FillDeviceDetails(const base::DictionaryValue& value, - CloudDeviceListDelegate::Device* device); - - CloudDeviceListDelegate* delegate_; -}; - -} // namespace local_discovery - -#endif // CHROME_BROWSER_LOCAL_DISCOVERY_CLOUD_DEVICE_LIST_H_
diff --git a/chrome/browser/local_discovery/cloud_device_list_delegate.cc b/chrome/browser/local_discovery/cloud_device_list_delegate.cc deleted file mode 100644 index 353dbd0..0000000 --- a/chrome/browser/local_discovery/cloud_device_list_delegate.cc +++ /dev/null
@@ -1,24 +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/local_discovery/cloud_device_list_delegate.h" - -namespace local_discovery { - -const char CloudDeviceListDelegate::kDeviceTypePrinter[] = "printer"; - -CloudDeviceListDelegate::CloudDeviceListDelegate() { -} - -CloudDeviceListDelegate::~CloudDeviceListDelegate() { -} - -CloudDeviceListDelegate::Device::Device() { -} - -CloudDeviceListDelegate::Device::~Device() { -} - -} // namespace local_discovery -
diff --git a/chrome/browser/local_discovery/cloud_device_list_delegate.h b/chrome/browser/local_discovery/cloud_device_list_delegate.h deleted file mode 100644 index 71d07af6..0000000 --- a/chrome/browser/local_discovery/cloud_device_list_delegate.h +++ /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. - -#ifndef CHROME_BROWSER_LOCAL_DISCOVERY_CLOUD_DEVICE_LIST_DELEGATE_H_ -#define CHROME_BROWSER_LOCAL_DISCOVERY_CLOUD_DEVICE_LIST_DELEGATE_H_ - -#include <string> -#include <vector> - -namespace local_discovery { - -class CloudDeviceListDelegate { - public: - static const char kDeviceTypePrinter[]; - struct Device { - Device(); - ~Device(); - - std::string id; - std::string type; - std::string display_name; - std::string description; - }; - - typedef std::vector<Device> DeviceList; - - CloudDeviceListDelegate(); - virtual ~CloudDeviceListDelegate(); - - virtual void OnDeviceListReady(const DeviceList& devices) = 0; - virtual void OnDeviceListUnavailable() = 0; -}; - -} // namespace local_discovery - -#endif // CHROME_BROWSER_LOCAL_DISCOVERY_CLOUD_DEVICE_LIST_DELEGATE_H_
diff --git a/chrome/browser/local_discovery/cloud_device_list_unittest.cc b/chrome/browser/local_discovery/cloud_device_list_unittest.cc deleted file mode 100644 index 9351743..0000000 --- a/chrome/browser/local_discovery/cloud_device_list_unittest.cc +++ /dev/null
@@ -1,96 +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/local_discovery/cloud_device_list.h" - -#include <stddef.h> - -#include <set> - -#include "base/json/json_reader.h" -#include "chrome/browser/local_discovery/cloud_device_list_delegate.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -using testing::Mock; -using testing::SaveArg; -using testing::StrictMock; -using testing::_; - -namespace local_discovery { - -namespace { - -const char kSampleSuccessResponseOAuth[] = - "{" - "\"kind\": \"clouddevices#devicesListResponse\"," - "\"devices\": [{" - " \"kind\": \"clouddevices#device\"," - " \"id\": \"someID\"," - " \"deviceKind\": \"someType\"," - " \"creationTimeMs\": \"123\"," - " \"systemName\": \"someDisplayName\"," - " \"owner\": \"user@domain.com\"," - " \"description\": \"someDescription\"," - " \"state\": {" - " \"base\": {" - " \"connectionStatus\": \"offline\"" - " }" - " }," - " \"channel\": {" - " \"supportedType\": \"xmpp\"" - " }," - " \"personalizedInfo\": {" - " \"maxRole\": \"owner\"" - " }}]}"; - -class MockDelegate : public CloudDeviceListDelegate { - public: - MOCK_METHOD1(OnDeviceListReady, void(const DeviceList&)); - MOCK_METHOD0(OnDeviceListUnavailable, void()); -}; - -TEST(CloudDeviceListTest, Params) { - CloudDeviceList device_list(NULL); - EXPECT_EQ(GURL("https://www.googleapis.com/clouddevices/v1/devices"), - device_list.GetURL()); - EXPECT_EQ("https://www.googleapis.com/auth/clouddevices", - device_list.GetOAuthScope()); - EXPECT_EQ(net::URLFetcher::GET, device_list.GetRequestType()); - EXPECT_TRUE(device_list.GetExtraRequestHeaders().empty()); -} - -TEST(CloudDeviceListTest, Parsing) { - StrictMock<MockDelegate> delegate; - CloudDeviceList device_list(&delegate); - CloudDeviceListDelegate::DeviceList devices; - EXPECT_CALL(delegate, OnDeviceListReady(_)).WillOnce(SaveArg<0>(&devices)); - - scoped_ptr<base::Value> value = - base::JSONReader::Read(kSampleSuccessResponseOAuth); - const base::DictionaryValue* dictionary = NULL; - ASSERT_TRUE(value->GetAsDictionary(&dictionary)); - device_list.OnGCDAPIFlowComplete(*dictionary); - - Mock::VerifyAndClear(&delegate); - - std::set<std::string> ids_found; - std::set<std::string> ids_expected; - ids_expected.insert("someID"); - - for (size_t i = 0; i != devices.size(); ++i) { - ids_found.insert(devices[i].id); - } - - ASSERT_EQ(ids_expected, ids_found); - - EXPECT_EQ("someID", devices[0].id); - EXPECT_EQ("someDisplayName", devices[0].display_name); - EXPECT_EQ("someDescription", devices[0].description); - EXPECT_EQ("someType", devices[0].type); -} - -} // namespace - -} // namespace local_discovery
diff --git a/chrome/browser/local_discovery/cloud_print_printer_list.h b/chrome/browser/local_discovery/cloud_print_printer_list.h deleted file mode 100644 index f4858eeb..0000000 --- a/chrome/browser/local_discovery/cloud_print_printer_list.h +++ /dev/null
@@ -1,37 +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_LOCAL_DISCOVERY_CLOUD_PRINT_PRINTER_LIST_H_ -#define CHROME_BROWSER_LOCAL_DISCOVERY_CLOUD_PRINT_PRINTER_LIST_H_ - -#include <string> -#include <vector> - -#include "base/values.h" -#include "chrome/browser/local_discovery/cloud_device_list_delegate.h" -#include "chrome/browser/local_discovery/gcd_api_flow.h" - -namespace local_discovery { - -class CloudPrintPrinterList : public CloudPrintApiFlowRequest { - public: - explicit CloudPrintPrinterList(CloudDeviceListDelegate* delegate); - ~CloudPrintPrinterList() override; - - void OnGCDAPIFlowError(GCDApiFlow::Status status) override; - - void OnGCDAPIFlowComplete(const base::DictionaryValue& value) override; - - GURL GetURL() override; - - private: - bool FillPrinterDetails(const base::DictionaryValue& printer_value, - CloudDeviceListDelegate::Device* printer_details); - - CloudDeviceListDelegate* delegate_; -}; - -} // namespace local_discovery - -#endif // CHROME_BROWSER_LOCAL_DISCOVERY_CLOUD_PRINT_PRINTER_LIST_H_
diff --git a/chrome/browser/local_discovery/gcd_constants.h b/chrome/browser/local_discovery/gcd_constants.h deleted file mode 100644 index b251126..0000000 --- a/chrome/browser/local_discovery/gcd_constants.h +++ /dev/null
@@ -1,16 +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_LOCAL_DISCOVERY_GCD_CONSTANTS_H_ -#define CHROME_BROWSER_LOCAL_DISCOVERY_GCD_CONSTANTS_H_ - -namespace local_discovery { - -extern const char kGCDKeyKind[]; -extern const char kGCDKeyDeviceId[]; -extern const char kGCDTypePrinter[]; - -} // namespace local_discovery - -#endif // CHROME_BROWSER_LOCAL_DISCOVERY_GCD_CONSTANTS_H_
diff --git a/chrome/browser/local_discovery/privet_device_lister_impl.h b/chrome/browser/local_discovery/privet_device_lister_impl.h deleted file mode 100644 index 2a41009..0000000 --- a/chrome/browser/local_discovery/privet_device_lister_impl.h +++ /dev/null
@@ -1,47 +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_LOCAL_DISCOVERY_PRIVET_DEVICE_LISTER_IMPL_H_ -#define CHROME_BROWSER_LOCAL_DISCOVERY_PRIVET_DEVICE_LISTER_IMPL_H_ - -#include <string> - -#include "chrome/browser/local_discovery/privet_device_lister.h" -#include "chrome/browser/local_discovery/service_discovery_device_lister.h" - -namespace local_discovery { - -class ServiceDiscoveryClient; - -class PrivetDeviceListerImpl : public PrivetDeviceLister, - public ServiceDiscoveryDeviceLister::Delegate { - public: - PrivetDeviceListerImpl( - ServiceDiscoveryClient* service_discovery_client, - PrivetDeviceLister::Delegate* delegate, - const std::string& subtype); - - PrivetDeviceListerImpl( - ServiceDiscoveryClient* service_discovery_client, - PrivetDeviceLister::Delegate* delegate); - - ~PrivetDeviceListerImpl() override; - - void Start() override; - void DiscoverNewDevices(bool force_update) override; - - protected: - void OnDeviceChanged(bool added, - const ServiceDescription& service_description) override; - void OnDeviceRemoved(const std::string& service_name) override; - void OnDeviceCacheFlushed() override; - - private: - PrivetDeviceLister::Delegate* delegate_; - ServiceDiscoveryDeviceLister device_lister_; -}; - -} // namespace local_discovery - -#endif // CHROME_BROWSER_LOCAL_DISCOVERY_PRIVET_DEVICE_LISTER_IMPL_H_
diff --git a/chrome/browser/local_discovery/service_discovery_client_utility.cc b/chrome/browser/local_discovery/service_discovery_client_utility.cc deleted file mode 100644 index 4b9242a..0000000 --- a/chrome/browser/local_discovery/service_discovery_client_utility.cc +++ /dev/null
@@ -1,109 +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/local_discovery/service_discovery_client_utility.h" - -#include "base/location.h" -#include "base/metrics/histogram.h" -#include "base/single_thread_task_runner.h" -#include "base/thread_task_runner_handle.h" -#include "chrome/browser/local_discovery/service_discovery_host_client.h" -#include "content/public/browser/browser_thread.h" - -namespace local_discovery { - -using content::BrowserThread; - -namespace { -const int kMaxRestartAttempts = 10; -const int kRestartDelayOnNetworkChangeSeconds = 3; -const int kReportSuccessAfterSeconds = 10; -} - -scoped_ptr<ServiceWatcher> ServiceDiscoveryClientUtility::CreateServiceWatcher( - const std::string& service_type, - const ServiceWatcher::UpdatedCallback& callback) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - return host_client_->CreateServiceWatcher(service_type, callback); -} - -scoped_ptr<ServiceResolver> -ServiceDiscoveryClientUtility::CreateServiceResolver( - const std::string& service_name, - const ServiceResolver::ResolveCompleteCallback& callback) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - return host_client_->CreateServiceResolver(service_name, callback); -} - -scoped_ptr<LocalDomainResolver> -ServiceDiscoveryClientUtility::CreateLocalDomainResolver( - const std::string& domain, - net::AddressFamily address_family, - const LocalDomainResolver::IPAddressCallback& callback) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - return host_client_->CreateLocalDomainResolver(domain, address_family, - callback); -} - -ServiceDiscoveryClientUtility::ServiceDiscoveryClientUtility() - : restart_attempts_(kMaxRestartAttempts), - weak_ptr_factory_(this) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - net::NetworkChangeNotifier::AddNetworkChangeObserver(this); - StartNewClient(); -} - -ServiceDiscoveryClientUtility::~ServiceDiscoveryClientUtility() { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this); - host_client_->Shutdown(); -} - -void ServiceDiscoveryClientUtility::OnNetworkChanged( - net::NetworkChangeNotifier::ConnectionType type) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - // Only network changes resets kMaxRestartAttempts. - restart_attempts_ = kMaxRestartAttempts; - ScheduleStartNewClient(); -} - -void ServiceDiscoveryClientUtility::ScheduleStartNewClient() { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - host_client_->Shutdown(); - weak_ptr_factory_.InvalidateWeakPtrs(); - base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( - FROM_HERE, base::Bind(&ServiceDiscoveryClientUtility::StartNewClient, - weak_ptr_factory_.GetWeakPtr()), - base::TimeDelta::FromSeconds(kRestartDelayOnNetworkChangeSeconds)); -} - -void ServiceDiscoveryClientUtility::StartNewClient() { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - scoped_refptr<ServiceDiscoveryHostClient> old_client = host_client_; - if ((restart_attempts_--) > 0) { - host_client_ = new ServiceDiscoveryHostClient(); - host_client_->Start( - base::Bind(&ServiceDiscoveryClientUtility::ScheduleStartNewClient, - weak_ptr_factory_.GetWeakPtr())); - - base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( - FROM_HERE, base::Bind(&ServiceDiscoveryClientUtility::ReportSuccess, - weak_ptr_factory_.GetWeakPtr()), - base::TimeDelta::FromSeconds(kReportSuccessAfterSeconds)); - } else { - restart_attempts_ = -1; - ReportSuccess(); - } - // Run when host_client_ is created. Callbacks created by InvalidateWatchers - // may create new watchers. - if (old_client.get()) - old_client->InvalidateWatchers(); -} - -void ServiceDiscoveryClientUtility::ReportSuccess() { - UMA_HISTOGRAM_COUNTS_100("LocalDiscovery.ClientRestartAttempts", - kMaxRestartAttempts - restart_attempts_); -} - -} // namespace local_discovery
diff --git a/chrome/browser/local_discovery/service_discovery_client_utility.h b/chrome/browser/local_discovery/service_discovery_client_utility.h deleted file mode 100644 index 3df9dfe..0000000 --- a/chrome/browser/local_discovery/service_discovery_client_utility.h +++ /dev/null
@@ -1,61 +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_LOCAL_DISCOVERY_SERVICE_DISCOVERY_CLIENT_UTILITY_H_ -#define CHROME_BROWSER_LOCAL_DISCOVERY_SERVICE_DISCOVERY_CLIENT_UTILITY_H_ - -#include <string> - -#include "base/cancelable_callback.h" -#include "base/macros.h" -#include "chrome/browser/local_discovery/service_discovery_shared_client.h" -#include "chrome/common/local_discovery/service_discovery_client.h" -#include "net/base/network_change_notifier.h" - -namespace local_discovery { - -class ServiceDiscoveryHostClient; - -// Wrapper for ServiceDiscoveryHostClient to hide restarting of utility process -// from mdns users. -class ServiceDiscoveryClientUtility - : public ServiceDiscoverySharedClient, - public net::NetworkChangeNotifier::NetworkChangeObserver { - public: - ServiceDiscoveryClientUtility(); - - // ServiceDiscoveryClient implementation. - scoped_ptr<ServiceWatcher> CreateServiceWatcher( - const std::string& service_type, - const ServiceWatcher::UpdatedCallback& callback) override; - scoped_ptr<ServiceResolver> CreateServiceResolver( - const std::string& service_name, - const ServiceResolver::ResolveCompleteCallback& callback) override; - scoped_ptr<LocalDomainResolver> CreateLocalDomainResolver( - const std::string& domain, - net::AddressFamily address_family, - const LocalDomainResolver::IPAddressCallback& callback) override; - - // net::NetworkChangeNotifier::NetworkChangeObserver implementation. - void OnNetworkChanged( - net::NetworkChangeNotifier::ConnectionType type) override; - - private: - friend class base::RefCounted<ServiceDiscoveryClientUtility>; - - ~ServiceDiscoveryClientUtility() override; - void ScheduleStartNewClient(); - void StartNewClient(); - void ReportSuccess(); - - scoped_refptr<ServiceDiscoveryHostClient> host_client_; - int restart_attempts_; - base::WeakPtrFactory<ServiceDiscoveryClientUtility> weak_ptr_factory_; - - DISALLOW_COPY_AND_ASSIGN(ServiceDiscoveryClientUtility); -}; - -} // namespace local_discovery - -#endif // CHROME_BROWSER_LOCAL_DISCOVERY_SERVICE_DISCOVERY_CLIENT_UTILITY_H_
diff --git a/chrome/browser/local_discovery/service_discovery_host_client.cc b/chrome/browser/local_discovery/service_discovery_host_client.cc deleted file mode 100644 index 2d5603ad..0000000 --- a/chrome/browser/local_discovery/service_discovery_host_client.cc +++ /dev/null
@@ -1,461 +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/local_discovery/service_discovery_host_client.h" - -#include <stddef.h> - -#include "base/location.h" -#include "base/single_thread_task_runner.h" -#include "base/thread_task_runner_handle.h" -#include "build/build_config.h" -#include "chrome/common/local_discovery/local_discovery_messages.h" -#include "chrome/grit/generated_resources.h" -#include "content/public/browser/browser_thread.h" -#include "content/public/browser/utility_process_host.h" -#include "net/base/net_util.h" -#include "net/dns/mdns_client.h" -#include "net/socket/socket_descriptor.h" -#include "ui/base/l10n/l10n_util.h" - -#if defined(OS_POSIX) -#include <netinet/in.h> -#include "base/file_descriptor_posix.h" -#endif // OS_POSIX - -namespace local_discovery { - -using content::BrowserThread; -using content::UtilityProcessHost; - -namespace { - -#if defined(OS_POSIX) -SocketInfoList GetSocketsOnFileThread() { - net::InterfaceIndexFamilyList interfaces(net::GetMDnsInterfacesToBind()); - SocketInfoList sockets; - for (size_t i = 0; i < interfaces.size(); ++i) { - DCHECK(interfaces[i].second == net::ADDRESS_FAMILY_IPV4 || - interfaces[i].second == net::ADDRESS_FAMILY_IPV6); - base::FileDescriptor socket_descriptor( - net::CreatePlatformSocket( - net::ConvertAddressFamily(interfaces[i].second), SOCK_DGRAM, - IPPROTO_UDP), - true); - LOG_IF(ERROR, socket_descriptor.fd == net::kInvalidSocket) - << "Can't create socket, family=" << interfaces[i].second; - if (socket_descriptor.fd != net::kInvalidSocket) { - LocalDiscoveryMsg_SocketInfo socket; - socket.descriptor = socket_descriptor; - socket.interface_index = interfaces[i].first; - socket.address_family = interfaces[i].second; - sockets.push_back(socket); - } - } - - return sockets; -} -#endif // OS_POSIX - -} // namespace - -class ServiceDiscoveryHostClient::ServiceWatcherProxy : public ServiceWatcher { - public: - ServiceWatcherProxy(ServiceDiscoveryHostClient* host, - const std::string& service_type, - const ServiceWatcher::UpdatedCallback& callback) - : host_(host), - service_type_(service_type), - id_(host_->RegisterWatcherCallback(callback)), - started_(false) { - } - - ~ServiceWatcherProxy() override { - DVLOG(1) << "~ServiceWatcherProxy with id " << id_; - host_->UnregisterWatcherCallback(id_); - if (started_) - host_->Send(new LocalDiscoveryMsg_DestroyWatcher(id_)); - } - - void Start() override { - DVLOG(1) << "ServiceWatcher::Start with id " << id_; - DCHECK(!started_); - host_->Send(new LocalDiscoveryMsg_StartWatcher(id_, service_type_)); - started_ = true; - } - - void DiscoverNewServices(bool force_update) override { - DVLOG(1) << "ServiceWatcher::DiscoverNewServices with id " << id_; - DCHECK(started_); - host_->Send(new LocalDiscoveryMsg_DiscoverServices(id_, force_update)); - } - - void SetActivelyRefreshServices(bool actively_refresh_services) override { - DVLOG(1) << "ServiceWatcher::SetActivelyRefreshServices with id " << id_; - DCHECK(started_); - host_->Send(new LocalDiscoveryMsg_SetActivelyRefreshServices( - id_, actively_refresh_services)); - } - - std::string GetServiceType() const override { return service_type_; } - - private: - scoped_refptr<ServiceDiscoveryHostClient> host_; - const std::string service_type_; - const uint64_t id_; - bool started_; -}; - -class ServiceDiscoveryHostClient::ServiceResolverProxy - : public ServiceResolver { - public: - ServiceResolverProxy(ServiceDiscoveryHostClient* host, - const std::string& service_name, - const ServiceResolver::ResolveCompleteCallback& callback) - : host_(host), - service_name_(service_name), - id_(host->RegisterResolverCallback(callback)), - started_(false) { - } - - ~ServiceResolverProxy() override { - DVLOG(1) << "~ServiceResolverProxy with id " << id_; - host_->UnregisterResolverCallback(id_); - if (started_) - host_->Send(new LocalDiscoveryMsg_DestroyResolver(id_)); - } - - void StartResolving() override { - DVLOG(1) << "ServiceResolverProxy::StartResolving with id " << id_; - DCHECK(!started_); - host_->Send(new LocalDiscoveryMsg_ResolveService(id_, service_name_)); - started_ = true; - } - - std::string GetName() const override { return service_name_; } - - private: - scoped_refptr<ServiceDiscoveryHostClient> host_; - const std::string service_name_; - const uint64_t id_; - bool started_; -}; - -class ServiceDiscoveryHostClient::LocalDomainResolverProxy - : public LocalDomainResolver { - public: - LocalDomainResolverProxy(ServiceDiscoveryHostClient* host, - const std::string& domain, - net::AddressFamily address_family, - const LocalDomainResolver::IPAddressCallback& callback) - : host_(host), - domain_(domain), - address_family_(address_family), - id_(host->RegisterLocalDomainResolverCallback(callback)), - started_(false) { - } - - ~LocalDomainResolverProxy() override { - DVLOG(1) << "~LocalDomainResolverProxy with id " << id_; - host_->UnregisterLocalDomainResolverCallback(id_); - if (started_) - host_->Send(new LocalDiscoveryMsg_DestroyLocalDomainResolver(id_)); - } - - void Start() override { - DVLOG(1) << "LocalDomainResolverProxy::Start with id " << id_; - DCHECK(!started_); - host_->Send(new LocalDiscoveryMsg_ResolveLocalDomain(id_, domain_, - address_family_)); - started_ = true; - } - - private: - scoped_refptr<ServiceDiscoveryHostClient> host_; - std::string domain_; - net::AddressFamily address_family_; - const uint64_t id_; - bool started_; -}; - -ServiceDiscoveryHostClient::ServiceDiscoveryHostClient() : current_id_(0) { - callback_runner_ = base::MessageLoop::current()->task_runner(); - io_runner_ = BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO); -} - -ServiceDiscoveryHostClient::~ServiceDiscoveryHostClient() { - DCHECK(service_watcher_callbacks_.empty()); - DCHECK(service_resolver_callbacks_.empty()); - DCHECK(domain_resolver_callbacks_.empty()); -} - -scoped_ptr<ServiceWatcher> ServiceDiscoveryHostClient::CreateServiceWatcher( - const std::string& service_type, - const ServiceWatcher::UpdatedCallback& callback) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - return scoped_ptr<ServiceWatcher>( - new ServiceWatcherProxy(this, service_type, callback)); -} - -scoped_ptr<ServiceResolver> ServiceDiscoveryHostClient::CreateServiceResolver( - const std::string& service_name, - const ServiceResolver::ResolveCompleteCallback& callback) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - return scoped_ptr<ServiceResolver>( - new ServiceResolverProxy(this, service_name, callback)); -} - -scoped_ptr<LocalDomainResolver> -ServiceDiscoveryHostClient::CreateLocalDomainResolver( - const std::string& domain, - net::AddressFamily address_family, - const LocalDomainResolver::IPAddressCallback& callback) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - return scoped_ptr<LocalDomainResolver>(new LocalDomainResolverProxy( - this, domain, address_family, callback)); -} - -uint64_t ServiceDiscoveryHostClient::RegisterWatcherCallback( - const ServiceWatcher::UpdatedCallback& callback) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - DCHECK(!ContainsKey(service_watcher_callbacks_, current_id_ + 1)); - service_watcher_callbacks_[++current_id_] = callback; - return current_id_; -} - -uint64_t ServiceDiscoveryHostClient::RegisterResolverCallback( - const ServiceResolver::ResolveCompleteCallback& callback) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - DCHECK(!ContainsKey(service_resolver_callbacks_, current_id_ + 1)); - service_resolver_callbacks_[++current_id_] = callback; - return current_id_; -} - -uint64_t ServiceDiscoveryHostClient::RegisterLocalDomainResolverCallback( - const LocalDomainResolver::IPAddressCallback& callback) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - DCHECK(!ContainsKey(domain_resolver_callbacks_, current_id_ + 1)); - domain_resolver_callbacks_[++current_id_] = callback; - return current_id_; -} - -void ServiceDiscoveryHostClient::UnregisterWatcherCallback(uint64_t id) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - service_watcher_callbacks_.erase(id); -} - -void ServiceDiscoveryHostClient::UnregisterResolverCallback(uint64_t id) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - service_resolver_callbacks_.erase(id); -} - -void ServiceDiscoveryHostClient::UnregisterLocalDomainResolverCallback( - uint64_t id) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - domain_resolver_callbacks_.erase(id); -} - -void ServiceDiscoveryHostClient::Start( - const base::Closure& error_callback) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - DCHECK(!utility_host_); - DCHECK(error_callback_.is_null()); - error_callback_ = error_callback; - io_runner_->PostTask( - FROM_HERE, - base::Bind(&ServiceDiscoveryHostClient::StartOnIOThread, this)); -} - -void ServiceDiscoveryHostClient::Shutdown() { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - io_runner_->PostTask( - FROM_HERE, - base::Bind(&ServiceDiscoveryHostClient::ShutdownOnIOThread, this)); -} - -#if defined(OS_POSIX) - -void ServiceDiscoveryHostClient::StartOnIOThread() { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - DCHECK(!utility_host_); - BrowserThread::PostTaskAndReplyWithResult( - BrowserThread::FILE, - FROM_HERE, - base::Bind(&GetSocketsOnFileThread), - base::Bind(&ServiceDiscoveryHostClient::OnSocketsReady, this)); -} - -void ServiceDiscoveryHostClient::OnSocketsReady(const SocketInfoList& sockets) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - DCHECK(!utility_host_); - utility_host_ = - UtilityProcessHost::Create( - this, base::ThreadTaskRunnerHandle::Get().get())->AsWeakPtr(); - utility_host_->SetName(l10n_util::GetStringUTF16( - IDS_UTILITY_PROCESS_SERVICE_DISCOVERY_HANDLER_NAME)); - utility_host_->EnableMDns(); - utility_host_->StartBatchMode(); - if (sockets.empty()) { - ShutdownOnIOThread(); - return; - } - utility_host_->Send(new LocalDiscoveryMsg_SetSockets(sockets)); - // Send messages for requests made during network enumeration. - for (size_t i = 0; i < delayed_messages_.size(); ++i) - utility_host_->Send(delayed_messages_[i]); - delayed_messages_.weak_clear(); -} - -#else // OS_POSIX - -void ServiceDiscoveryHostClient::StartOnIOThread() { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - DCHECK(!utility_host_); - utility_host_ = - UtilityProcessHost::Create( - this, base::ThreadTaskRunnerHandle::Get().get())->AsWeakPtr(); - utility_host_->SetName(l10n_util::GetStringUTF16( - IDS_UTILITY_PROCESS_SERVICE_DISCOVERY_HANDLER_NAME)); - utility_host_->EnableMDns(); - utility_host_->StartBatchMode(); - // Windows does not enumerate networks here. - DCHECK(delayed_messages_.empty()); -} - -#endif // OS_POSIX - -void ServiceDiscoveryHostClient::ShutdownOnIOThread() { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - if (utility_host_) { - utility_host_->Send(new LocalDiscoveryMsg_ShutdownLocalDiscovery); - utility_host_->EndBatchMode(); - utility_host_.reset(); - } - error_callback_ = base::Closure(); -} - -void ServiceDiscoveryHostClient::Send(IPC::Message* msg) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - io_runner_->PostTask( - FROM_HERE, - base::Bind(&ServiceDiscoveryHostClient::SendOnIOThread, this, msg)); -} - -void ServiceDiscoveryHostClient::SendOnIOThread(IPC::Message* msg) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - if (utility_host_) { - utility_host_->Send(msg); - } else { - delayed_messages_.push_back(msg); - } -} - -void ServiceDiscoveryHostClient::OnProcessCrashed(int exit_code) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - DCHECK(!utility_host_); - OnError(); -} - -bool ServiceDiscoveryHostClient::OnMessageReceived( - const IPC::Message& message) { - bool handled = true; - IPC_BEGIN_MESSAGE_MAP(ServiceDiscoveryHostClient, message) - IPC_MESSAGE_HANDLER(LocalDiscoveryHostMsg_Error, OnError) - IPC_MESSAGE_HANDLER(LocalDiscoveryHostMsg_WatcherCallback, - OnWatcherCallback) - IPC_MESSAGE_HANDLER(LocalDiscoveryHostMsg_ResolverCallback, - OnResolverCallback) - IPC_MESSAGE_HANDLER(LocalDiscoveryHostMsg_LocalDomainResolverCallback, - OnLocalDomainResolverCallback) - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP() - return handled; -} - -void ServiceDiscoveryHostClient::InvalidateWatchers() { - WatcherCallbacks service_watcher_callbacks; - service_watcher_callbacks_.swap(service_watcher_callbacks); - service_resolver_callbacks_.clear(); - domain_resolver_callbacks_.clear(); - - for (WatcherCallbacks::iterator i = service_watcher_callbacks.begin(); - i != service_watcher_callbacks.end(); i++) { - if (!i->second.is_null()) { - i->second.Run(ServiceWatcher::UPDATE_INVALIDATED, ""); - } - } -} - -void ServiceDiscoveryHostClient::OnError() { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - if (!error_callback_.is_null()) - callback_runner_->PostTask(FROM_HERE, error_callback_); -} - -void ServiceDiscoveryHostClient::OnWatcherCallback( - uint64_t id, - ServiceWatcher::UpdateType update, - const std::string& service_name) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - callback_runner_->PostTask( - FROM_HERE, - base::Bind(&ServiceDiscoveryHostClient::RunWatcherCallback, this, id, - update, service_name)); -} - -void ServiceDiscoveryHostClient::OnResolverCallback( - uint64_t id, - ServiceResolver::RequestStatus status, - const ServiceDescription& description) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - callback_runner_->PostTask( - FROM_HERE, - base::Bind(&ServiceDiscoveryHostClient::RunResolverCallback, this, id, - status, description)); -} - -void ServiceDiscoveryHostClient::OnLocalDomainResolverCallback( - uint64_t id, - bool success, - const net::IPAddressNumber& ip_address_ipv4, - const net::IPAddressNumber& ip_address_ipv6) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - callback_runner_->PostTask( - FROM_HERE, - base::Bind(&ServiceDiscoveryHostClient::RunLocalDomainResolverCallback, - this, id, success, ip_address_ipv4, ip_address_ipv6)); -} - -void ServiceDiscoveryHostClient::RunWatcherCallback( - uint64_t id, - ServiceWatcher::UpdateType update, - const std::string& service_name) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - WatcherCallbacks::iterator it = service_watcher_callbacks_.find(id); - if (it != service_watcher_callbacks_.end() && !it->second.is_null()) - it->second.Run(update, service_name); -} - -void ServiceDiscoveryHostClient::RunResolverCallback( - uint64_t id, - ServiceResolver::RequestStatus status, - const ServiceDescription& description) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - ResolverCallbacks::iterator it = service_resolver_callbacks_.find(id); - if (it != service_resolver_callbacks_.end() && !it->second.is_null()) - it->second.Run(status, description); -} - -void ServiceDiscoveryHostClient::RunLocalDomainResolverCallback( - uint64_t id, - bool success, - const net::IPAddressNumber& ip_address_ipv4, - const net::IPAddressNumber& ip_address_ipv6) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - DomainResolverCallbacks::iterator it = domain_resolver_callbacks_.find(id); - if (it != domain_resolver_callbacks_.end() && !it->second.is_null()) - it->second.Run(success, ip_address_ipv4, ip_address_ipv6); -} - -} // namespace local_discovery
diff --git a/chrome/browser/local_discovery/service_discovery_host_client.h b/chrome/browser/local_discovery/service_discovery_host_client.h deleted file mode 100644 index 7849f31..0000000 --- a/chrome/browser/local_discovery/service_discovery_host_client.h +++ /dev/null
@@ -1,150 +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_LOCAL_DISCOVERY_SERVICE_DISCOVERY_HOST_CLIENT_H_ -#define CHROME_BROWSER_LOCAL_DISCOVERY_SERVICE_DISCOVERY_HOST_CLIENT_H_ - -#include <stdint.h> - -#include <map> -#include <string> -#include <vector> - -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/memory/scoped_vector.h" -#include "base/memory/weak_ptr.h" -#include "build/build_config.h" -#include "chrome/common/local_discovery/service_discovery_client.h" -#include "content/public/browser/utility_process_host_client.h" - -struct LocalDiscoveryMsg_SocketInfo; - -namespace base { -class TaskRunner; -} - -namespace content { -class UtilityProcessHost; -} - -namespace local_discovery { - -#if defined(OS_POSIX) -typedef std::vector<LocalDiscoveryMsg_SocketInfo> SocketInfoList; -#endif // OS_POSIX - -// Implementation of ServiceDiscoveryClient that delegates all functionality to -// utility process. -class ServiceDiscoveryHostClient - : public ServiceDiscoveryClient, - public content::UtilityProcessHostClient { - public: - ServiceDiscoveryHostClient(); - - // Starts utility process with ServiceDiscoveryClient. - void Start(const base::Closure& error_callback); - - // Shutdowns utility process. - void Shutdown(); - - // ServiceDiscoveryClient implementation. - scoped_ptr<ServiceWatcher> CreateServiceWatcher( - const std::string& service_type, - const ServiceWatcher::UpdatedCallback& callback) override; - scoped_ptr<ServiceResolver> CreateServiceResolver( - const std::string& service_name, - const ServiceResolver::ResolveCompleteCallback& callback) override; - scoped_ptr<LocalDomainResolver> CreateLocalDomainResolver( - const std::string& domain, - net::AddressFamily address_family, - const LocalDomainResolver::IPAddressCallback& callback) override; - - // UtilityProcessHostClient implementation. - void OnProcessCrashed(int exit_code) override; - bool OnMessageReceived(const IPC::Message& message) override; - - protected: - ~ServiceDiscoveryHostClient() override; - - private: - class ServiceWatcherProxy; - class ServiceResolverProxy; - class LocalDomainResolverProxy; - friend class ServiceDiscoveryClientUtility; - - typedef std::map<uint64_t, ServiceWatcher::UpdatedCallback> WatcherCallbacks; - typedef std::map<uint64_t, ServiceResolver::ResolveCompleteCallback> - ResolverCallbacks; - typedef std::map<uint64_t, LocalDomainResolver::IPAddressCallback> - DomainResolverCallbacks; - - void StartOnIOThread(); - void ShutdownOnIOThread(); - -#if defined(OS_POSIX) - void OnSocketsReady(const SocketInfoList& interfaces); -#endif // OS_POSIX - - void InvalidateWatchers(); - - void Send(IPC::Message* msg); - void SendOnIOThread(IPC::Message* msg); - - uint64_t RegisterWatcherCallback( - const ServiceWatcher::UpdatedCallback& callback); - uint64_t RegisterResolverCallback( - const ServiceResolver::ResolveCompleteCallback& callback); - uint64_t RegisterLocalDomainResolverCallback( - const LocalDomainResolver::IPAddressCallback& callback); - - void UnregisterWatcherCallback(uint64_t id); - void UnregisterResolverCallback(uint64_t id); - void UnregisterLocalDomainResolverCallback(uint64_t id); - - // IPC Message handlers. - void OnError(); - void OnWatcherCallback(uint64_t id, - ServiceWatcher::UpdateType update, - const std::string& service_name); - void OnResolverCallback(uint64_t id, - ServiceResolver::RequestStatus status, - const ServiceDescription& description); - void OnLocalDomainResolverCallback(uint64_t id, - bool success, - const net::IPAddressNumber& address_ipv4, - const net::IPAddressNumber& address_ipv6); - - // Runs watcher callback on owning thread. - void RunWatcherCallback(uint64_t id, - ServiceWatcher::UpdateType update, - const std::string& service_name); - // Runs resolver callback on owning thread. - void RunResolverCallback(uint64_t id, - ServiceResolver::RequestStatus status, - const ServiceDescription& description); - // Runs local domain resolver callback on owning thread. - void RunLocalDomainResolverCallback(uint64_t id, - bool success, - const net::IPAddressNumber& address_ipv4, - const net::IPAddressNumber& address_ipv6); - - base::WeakPtr<content::UtilityProcessHost> utility_host_; - - // Incrementing counter to assign ID to watchers and resolvers. - uint64_t current_id_; - base::Closure error_callback_; - WatcherCallbacks service_watcher_callbacks_; - ResolverCallbacks service_resolver_callbacks_; - DomainResolverCallbacks domain_resolver_callbacks_; - scoped_refptr<base::TaskRunner> callback_runner_; - scoped_refptr<base::TaskRunner> io_runner_; - ScopedVector<IPC::Message> delayed_messages_; - - DISALLOW_COPY_AND_ASSIGN(ServiceDiscoveryHostClient); -}; - -} // namespace local_discovery - -#endif // CHROME_BROWSER_LOCAL_DISCOVERY_SERVICE_DISCOVERY_HOST_CLIENT_H_
diff --git a/chrome/browser/local_discovery/service_discovery_shared_client.cc b/chrome/browser/local_discovery/service_discovery_shared_client.cc index 4d8c9eb..1a397e4 100644 --- a/chrome/browser/local_discovery/service_discovery_shared_client.cc +++ b/chrome/browser/local_discovery/service_discovery_shared_client.cc
@@ -21,7 +21,6 @@ #if defined(ENABLE_MDNS) #include "chrome/browser/local_discovery/service_discovery_client_mdns.h" -#include "chrome/browser/local_discovery/service_discovery_client_utility.h" #endif // ENABLE_MDNS namespace { @@ -97,39 +96,6 @@ #endif // OS_MACOSX } -// static -void ServiceDiscoverySharedClient::GetInstanceWithoutAlert( - const GetInstanceCallback& callback) { -#if !defined(OS_WIN) - - scoped_refptr<ServiceDiscoverySharedClient> result = GetInstance(); - return callback.Run(result); - -#else // OS_WIN - DCHECK_CURRENTLY_ON(BrowserThread::UI); - // TODO(vitalybuka): Switch to |ServiceDiscoveryClientMdns| after we find what - // to do with firewall for user-level installs. crbug.com/366408 - scoped_refptr<ServiceDiscoverySharedClient> result = - g_service_discovery_client; - if (result.get()) - return callback.Run(result); - - if (!g_is_firewall_state_reported) { - BrowserThread::PostTaskAndReply( - BrowserThread::FILE, - FROM_HERE, - base::Bind(&ReportFirewallStats), - base::Bind(&ServiceDiscoverySharedClient::GetInstanceWithoutAlert, - callback)); - return; - } - - result = - g_is_firewall_ready ? GetInstance() : new ServiceDiscoveryClientUtility(); - callback.Run(result); -#endif // OS_WIN -} - #else scoped_refptr<ServiceDiscoverySharedClient>
diff --git a/chrome/browser/local_discovery/service_discovery_shared_client.h b/chrome/browser/local_discovery/service_discovery_shared_client.h index 9ffe5ce..dc98e7d2 100644 --- a/chrome/browser/local_discovery/service_discovery_shared_client.h +++ b/chrome/browser/local_discovery/service_discovery_shared_client.h
@@ -21,7 +21,6 @@ typedef base::Callback<void( const scoped_refptr<ServiceDiscoverySharedClient>&)> GetInstanceCallback; - static void GetInstanceWithoutAlert(const GetInstanceCallback& callback); protected: ServiceDiscoverySharedClient();
diff --git a/chrome/browser/media/android/remote/remote_media_player_manager.cc b/chrome/browser/media/android/remote/remote_media_player_manager.cc index 301abde..6b7efa91 100644 --- a/chrome/browser/media/android/remote/remote_media_player_manager.cc +++ b/chrome/browser/media/android/remote/remote_media_player_manager.cc
@@ -20,7 +20,12 @@ weak_ptr_factory_(this) { } -RemoteMediaPlayerManager::~RemoteMediaPlayerManager() {} +RemoteMediaPlayerManager::~RemoteMediaPlayerManager() { + for (MediaPlayerAndroid* player : alternative_players_) + player->DeleteOnCorrectThread(); + + alternative_players_.weak_clear(); +} void RemoteMediaPlayerManager::OnStart(int player_id) { RemoteMediaPlayerBridge* remote_player = GetRemotePlayer(player_id);
diff --git a/chrome/browser/media/router/media_router_mojo_impl_unittest.cc b/chrome/browser/media/router/media_router_mojo_impl_unittest.cc index f78fa77..3631d83 100644 --- a/chrome/browser/media/router/media_router_mojo_impl_unittest.cc +++ b/chrome/browser/media/router/media_router_mojo_impl_unittest.cc
@@ -37,6 +37,7 @@ using testing::_; using testing::Eq; using testing::Invoke; +using testing::InvokeWithoutArgs; using testing::IsEmpty; using testing::Mock; using testing::Not; @@ -200,7 +201,11 @@ // MediaRouterMojoImpl will start observing local displayable routes as a // result of having one created. - EXPECT_CALL(mock_media_route_provider_, StartObservingMediaRoutes()); + base::RunLoop run_loop; + EXPECT_CALL(mock_media_route_provider_, StartObservingMediaRoutes()) + .WillOnce(InvokeWithoutArgs([&run_loop]() { + run_loop.Quit(); + })); RouteResponseCallbackHandler handler; EXPECT_CALL(handler, Invoke(Pointee(Equals(expected_route)), Not(""), "")); @@ -209,7 +214,7 @@ &RouteResponseCallbackHandler::Invoke, base::Unretained(&handler))); router()->CreateRoute(kSource, kSinkId, GURL(kOrigin), nullptr, route_response_callbacks); - ProcessEventLoop(); + run_loop.Run(); } TEST_F(MediaRouterMojoImplTest, CreateRouteFails) { @@ -225,13 +230,17 @@ })); RouteResponseCallbackHandler handler; - EXPECT_CALL(handler, Invoke(nullptr, "", kError)); + base::RunLoop run_loop; + EXPECT_CALL(handler, Invoke(nullptr, "", kError)) + .WillOnce(InvokeWithoutArgs([&run_loop]() { + run_loop.Quit(); + })); std::vector<MediaRouteResponseCallback> route_response_callbacks; route_response_callbacks.push_back(base::Bind( &RouteResponseCallbackHandler::Invoke, base::Unretained(&handler))); router()->CreateRoute(kSource, kSinkId, GURL(kOrigin), nullptr, route_response_callbacks); - ProcessEventLoop(); + run_loop.Run(); } TEST_F(MediaRouterMojoImplTest, JoinRoute) { @@ -260,7 +269,11 @@ // MediaRouterMojoImpl will start observing local displayable routes as a // result of having one created. - EXPECT_CALL(mock_media_route_provider_, StartObservingMediaRoutes()); + base::RunLoop run_loop; + EXPECT_CALL(mock_media_route_provider_, StartObservingMediaRoutes()) + .WillOnce(InvokeWithoutArgs([&run_loop]() { + run_loop.Quit(); + })); RouteResponseCallbackHandler handler; EXPECT_CALL(handler, Invoke(Pointee(Equals(expected_route)), Not(""), "")); @@ -269,7 +282,7 @@ &RouteResponseCallbackHandler::Invoke, base::Unretained(&handler))); router()->JoinRoute(kSource, kPresentationId, GURL(kOrigin), nullptr, route_response_callbacks); - ProcessEventLoop(); + run_loop.Run(); } TEST_F(MediaRouterMojoImplTest, JoinRouteFails) { @@ -284,26 +297,38 @@ })); RouteResponseCallbackHandler handler; - EXPECT_CALL(handler, Invoke(nullptr, "", kError)); + base::RunLoop run_loop; + EXPECT_CALL(handler, Invoke(nullptr, "", kError)) + .WillOnce(InvokeWithoutArgs([&run_loop]() { + run_loop.Quit(); + })); std::vector<MediaRouteResponseCallback> route_response_callbacks; route_response_callbacks.push_back(base::Bind( &RouteResponseCallbackHandler::Invoke, base::Unretained(&handler))); router()->JoinRoute(kSource, kPresentationId, GURL(kOrigin), nullptr, route_response_callbacks); - ProcessEventLoop(); + run_loop.Run(); } TEST_F(MediaRouterMojoImplTest, DetachRoute) { - EXPECT_CALL(mock_media_route_provider_, DetachRoute(mojo::String(kRouteId))); + base::RunLoop run_loop; + EXPECT_CALL(mock_media_route_provider_, DetachRoute(mojo::String(kRouteId))) + .WillOnce(InvokeWithoutArgs([&run_loop]() { + run_loop.Quit(); + })); router()->DetachRoute(kRouteId); - ProcessEventLoop(); + run_loop.Run(); } TEST_F(MediaRouterMojoImplTest, TerminateRoute) { + base::RunLoop run_loop; EXPECT_CALL(mock_media_route_provider_, - TerminateRoute(mojo::String(kRouteId))); + TerminateRoute(mojo::String(kRouteId))) + .WillOnce(InvokeWithoutArgs([&run_loop]() { + run_loop.Quit(); + })); router()->TerminateRoute(kRouteId); - ProcessEventLoop(); + run_loop.Run(); } TEST_F(MediaRouterMojoImplTest, HandleIssue) { @@ -319,10 +344,14 @@ EXPECT_CALL(issue_observer1, OnIssueUpdated(Pointee(EqualsIssue(expected_issue1)))) .WillOnce(SaveArg<0>(&issue)); + base::RunLoop run_loop; EXPECT_CALL(issue_observer2, - OnIssueUpdated(Pointee(EqualsIssue(expected_issue1)))); + OnIssueUpdated(Pointee(EqualsIssue(expected_issue1)))) + .WillOnce(InvokeWithoutArgs([&run_loop]() { + run_loop.Quit(); + })); media_router_proxy_->OnIssue(std::move(mojo_issue1)); - ProcessEventLoop(); + run_loop.Run(); EXPECT_TRUE(Mock::VerifyAndClearExpectations(&issue_observer1)); EXPECT_TRUE(Mock::VerifyAndClearExpectations(&issue_observer2)); @@ -347,10 +376,14 @@ router()->ClearIssue(issue->id()); EXPECT_TRUE(Mock::VerifyAndClearExpectations(&issue_observer2)); + base::RunLoop run_loop2; EXPECT_CALL(issue_observer2, - OnIssueUpdated(Pointee(EqualsIssue(expected_issue2)))); + OnIssueUpdated(Pointee(EqualsIssue(expected_issue2)))) + .WillOnce(InvokeWithoutArgs([&run_loop2]() { + run_loop2.Quit(); + })); media_router_proxy_->OnIssue(std::move(mojo_issue2)); - ProcessEventLoop(); + run_loop2.Run(); issue_observer1.UnregisterObserver(); issue_observer2.UnregisterObserver(); @@ -395,21 +428,29 @@ mojo_sinks[1]->icon_type = media_router::interfaces::MediaSink::IconType::ICON_TYPE_CAST; + base::RunLoop run_loop; EXPECT_CALL(sinks_observer, OnSinksReceived(SequenceEquals(expected_sinks))); EXPECT_CALL(extra_sinks_observer, - OnSinksReceived(SequenceEquals(expected_sinks))); + OnSinksReceived(SequenceEquals(expected_sinks))) + .WillOnce(InvokeWithoutArgs([&run_loop]() { + run_loop.Quit(); + })); media_router_proxy_->OnSinksReceived(media_source.id(), std::move(mojo_sinks)); - ProcessEventLoop(); + run_loop.Run(); + base::RunLoop run_loop2; EXPECT_CALL(mock_media_route_provider_, StopObservingMediaSinks(mojo::String(kSource))); EXPECT_CALL(mock_media_route_provider_, - StopObservingMediaSinks(mojo::String(kSource2))); + StopObservingMediaSinks(mojo::String(kSource2))) + .WillOnce(InvokeWithoutArgs([&run_loop2]() { + run_loop2.Quit(); + })); router()->UnregisterMediaSinksObserver(&sinks_observer); router()->UnregisterMediaSinksObserver(&extra_sinks_observer); router()->UnregisterMediaSinksObserver(&unrelated_sinks_observer); - ProcessEventLoop(); + run_loop2.Run(); } TEST_F(MediaRouterMojoImplTest, @@ -570,12 +611,16 @@ cb.Run(true); })); + base::RunLoop run_loop; SendMessageCallbackHandler handler; - EXPECT_CALL(handler, Invoke(true)); + EXPECT_CALL(handler, Invoke(true)) + .WillOnce(InvokeWithoutArgs([&run_loop]() { + run_loop.Quit(); + })); router()->SendRouteMessage(kRouteId, kMessage, base::Bind(&SendMessageCallbackHandler::Invoke, base::Unretained(&handler))); - ProcessEventLoop(); + run_loop.Run(); } TEST_F(MediaRouterMojoImplTest, SendRouteBinaryMessage) { @@ -593,13 +638,17 @@ cb.Run(true); })); + base::RunLoop run_loop; SendMessageCallbackHandler handler; - EXPECT_CALL(handler, Invoke(true)); + EXPECT_CALL(handler, Invoke(true)) + .WillOnce(InvokeWithoutArgs([&run_loop]() { + run_loop.Quit(); + })); router()->SendRouteBinaryMessage( kRouteId, std::move(expected_binary_data), base::Bind(&SendMessageCallbackHandler::Invoke, base::Unretained(&handler))); - ProcessEventLoop(); + run_loop.Run(); } TEST_F(MediaRouterMojoImplTest, PresentationSessionMessagesSingleObserver) { @@ -623,11 +672,15 @@ message->data.reset(new std::vector<uint8_t>(1, 1)); expected_messages.push_back(std::move(message)); + base::RunLoop run_loop; MediaRoute::Id expected_route_id("foo"); interfaces::MediaRouteProvider::ListenForRouteMessagesCallback mojo_callback; EXPECT_CALL(mock_media_route_provider_, ListenForRouteMessages(Eq(expected_route_id), _)) - .WillOnce(SaveArg<1>(&mojo_callback)); + .WillOnce(DoAll(SaveArg<1>(&mojo_callback), + InvokeWithoutArgs([&run_loop]() { + run_loop.Quit(); + }))); // |pass_ownership| param is "true" here because there is only one observer. ListenForMessagesCallbackHandler handler(std::move(expected_messages), true); @@ -640,8 +693,9 @@ base::Bind(&ListenForMessagesCallbackHandler::Invoke, base::Unretained(&handler)), expected_route_id, router())); - ProcessEventLoop(); + run_loop.Run(); + base::RunLoop run_loop2; // Simulate messages by invoking the saved mojo callback. // We expect one more ListenForRouteMessages call since |observer| was // still registered when the first set of messages arrived. @@ -649,9 +703,13 @@ interfaces::MediaRouteProvider::ListenForRouteMessagesCallback mojo_callback_2; EXPECT_CALL(mock_media_route_provider_, ListenForRouteMessages(_, _)) - .WillOnce(SaveArg<1>(&mojo_callback_2)); - ProcessEventLoop(); + .WillOnce(DoAll(SaveArg<1>(&mojo_callback_2), + InvokeWithoutArgs([&run_loop2]() { + run_loop2.Quit(); + }))); + run_loop2.Run(); + base::RunLoop run_loop3; // Stop listening for messages. In particular, MediaRouterMojoImpl will not // call ListenForRouteMessages again when it sees there are no more observers. mojo::Array<interfaces::RouteMessagePtr> mojo_messages_2(1); @@ -660,8 +718,11 @@ mojo_messages_2[0]->message = "foo"; observer.reset(); mojo_callback_2.Run(std::move(mojo_messages_2), false); - EXPECT_CALL(mock_media_route_provider_, StopListeningForRouteMessages(_)); - ProcessEventLoop(); + EXPECT_CALL(mock_media_route_provider_, StopListeningForRouteMessages(_)) + .WillOnce(InvokeWithoutArgs([&run_loop3]() { + run_loop3.Quit(); + })); + run_loop3.Run(); } TEST_F(MediaRouterMojoImplTest, PresentationSessionMessagesMultipleObservers) { @@ -685,11 +746,15 @@ message->data.reset(new std::vector<uint8_t>(1, 1)); expected_messages.push_back(std::move(message)); + base::RunLoop run_loop; MediaRoute::Id expected_route_id("foo"); interfaces::MediaRouteProvider::ListenForRouteMessagesCallback mojo_callback; EXPECT_CALL(mock_media_route_provider_, ListenForRouteMessages(Eq(expected_route_id), _)) - .WillOnce(SaveArg<1>(&mojo_callback)); + .WillOnce(DoAll(SaveArg<1>(&mojo_callback), + InvokeWithoutArgs([&run_loop]() { + run_loop.Quit(); + }))); // |pass_ownership| param is "false" here because there are more than one // observers. @@ -708,8 +773,9 @@ base::Bind(&ListenForMessagesCallbackHandler::Invoke, base::Unretained(&handler)), expected_route_id, router())); - ProcessEventLoop(); + run_loop.Run(); + base::RunLoop run_loop2; // Simulate messages by invoking the saved mojo callback. // We expect one more ListenForRouteMessages call since |observer| was // still registered when the first set of messages arrived. @@ -717,9 +783,13 @@ interfaces::MediaRouteProvider::ListenForRouteMessagesCallback mojo_callback_2; EXPECT_CALL(mock_media_route_provider_, ListenForRouteMessages(_, _)) - .WillOnce(SaveArg<1>(&mojo_callback_2)); - ProcessEventLoop(); + .WillOnce(DoAll(SaveArg<1>(&mojo_callback_2), + InvokeWithoutArgs([&run_loop2]() { + run_loop2.Quit(); + }))); + run_loop2.Run(); + base::RunLoop run_loop3; // Stop listening for messages. In particular, MediaRouterMojoImpl will not // call ListenForRouteMessages again when it sees there are no more observers. mojo::Array<interfaces::RouteMessagePtr> mojo_messages_2(1); @@ -729,16 +799,23 @@ observer1.reset(); observer2.reset(); mojo_callback_2.Run(std::move(mojo_messages_2), false); - EXPECT_CALL(mock_media_route_provider_, StopListeningForRouteMessages(_)); - ProcessEventLoop(); + EXPECT_CALL(mock_media_route_provider_, StopListeningForRouteMessages(_)) + .WillOnce(InvokeWithoutArgs([&run_loop3]() { + run_loop3.Quit(); + })); + run_loop3.Run(); } TEST_F(MediaRouterMojoImplTest, PresentationSessionMessagesError) { MediaRoute::Id expected_route_id("foo"); interfaces::MediaRouteProvider::ListenForRouteMessagesCallback mojo_callback; + base::RunLoop run_loop; EXPECT_CALL(mock_media_route_provider_, ListenForRouteMessages(Eq(expected_route_id), _)) - .WillOnce(SaveArg<1>(&mojo_callback)); + .WillOnce(DoAll(SaveArg<1>(&mojo_callback), + InvokeWithoutArgs([&run_loop]() { + run_loop.Quit(); + }))); ListenForMessagesCallbackHandler handler( ScopedVector<content::PresentationSessionMessage>(), true); @@ -750,7 +827,7 @@ base::Bind(&ListenForMessagesCallbackHandler::Invoke, base::Unretained(&handler)), expected_route_id, router())); - ProcessEventLoop(); + run_loop.Run(); mojo_callback.Run(mojo::Array<interfaces::RouteMessagePtr>(0), true); ProcessEventLoop(); @@ -772,23 +849,29 @@ base::Bind(&MockPresentationConnectionStateChangedCallback::Run, base::Unretained(&callback))); + base::RunLoop run_loop; EXPECT_CALL(callback, Run(content::PRESENTATION_CONNECTION_STATE_CLOSED)) - .Times(1); + .WillOnce(InvokeWithoutArgs([&run_loop]() { + run_loop.Quit(); + })); media_router_proxy_->OnPresentationConnectionStateChanged( route_id, PresentationConnectionState::PRESENTATION_CONNECTION_STATE_CLOSED); - ProcessEventLoop(); + run_loop.Run(); EXPECT_TRUE(Mock::VerifyAndClearExpectations(&callback)); + base::RunLoop run_loop2; // Right now we don't keep track of previous state so the callback will be // invoked with the same state again. EXPECT_CALL(callback, Run(content::PRESENTATION_CONNECTION_STATE_CLOSED)) - .Times(1); + .WillOnce(InvokeWithoutArgs([&run_loop2]() { + run_loop2.Quit(); + })); media_router_proxy_->OnPresentationConnectionStateChanged( route_id, PresentationConnectionState::PRESENTATION_CONNECTION_STATE_CLOSED); - ProcessEventLoop(); + run_loop2.Run(); // Callback has been removed, so we don't expect it to be called anymore. subscription.reset(); @@ -846,15 +929,19 @@ } TEST_F(MediaRouterMojoImplTest, QueuedWhileAsleep) { + base::RunLoop run_loop; EXPECT_CALL(mock_event_page_tracker_, IsEventPageSuspended(extension_id())) .Times(2) .WillRepeatedly(Return(true)); EXPECT_CALL(mock_event_page_tracker_, WakeEventPage(extension_id(), _)) .Times(2) - .WillRepeatedly(Return(true)); + .WillOnce(Return(true)) + .WillOnce(DoAll(InvokeWithoutArgs([&run_loop]() { + run_loop.Quit(); + }), Return(true))); router()->DetachRoute(kRouteId); router()->DetachRoute(kRouteId2); - ProcessEventLoop(); + run_loop.Run(); EXPECT_CALL(mock_event_page_tracker_, IsEventPageSuspended(extension_id())) .Times(1) .WillRepeatedly(Return(false)); @@ -954,35 +1041,56 @@ BindMediaRouteProvider(); + base::RunLoop run_loop, run_loop2; // |mojo_media_router| signals its readiness to the MR by registering // itself via RegisterMediaRouteProvider(). // Now that the |media_router| and |mojo_media_router| are fully initialized, // the queued DetachRoute() call should be executed. - EXPECT_CALL(provide_handler_, Invoke(testing::Not(""))); + EXPECT_CALL(provide_handler_, Invoke(testing::Not(""))) + .WillOnce(InvokeWithoutArgs([&run_loop]() { + run_loop.Quit(); + })); EXPECT_CALL(*process_manager_, IsEventPageSuspended(kExtensionId)) .WillOnce(Return(false)); - EXPECT_CALL(mock_media_route_provider_, DetachRoute(mojo::String(kRouteId))); + EXPECT_CALL(mock_media_route_provider_, DetachRoute(mojo::String(kRouteId))) + .WillOnce(InvokeWithoutArgs([&run_loop2]() { + run_loop2.Quit(); + })); RegisterMediaRouteProvider(); - ProcessEventLoop(); + run_loop.Run(); + run_loop2.Run(); + base::RunLoop run_loop3; // Extension is suspended and re-awoken. ResetMediaRouteProvider(); EXPECT_CALL(*process_manager_, IsEventPageSuspended(kExtensionId)) .WillOnce(Return(true)); EXPECT_CALL(*process_manager_, WakeEventPage(kExtensionId, _)) - .WillOnce(testing::DoAll(media::RunCallback<1>(true), Return(true))); + .WillOnce(testing::DoAll(media::RunCallback<1>(true), + InvokeWithoutArgs([&run_loop3]() { + run_loop3.Quit(); + }), + Return(true))); media_router_->DetachRoute(kRouteId2); - ProcessEventLoop(); + run_loop3.Run(); + base::RunLoop run_loop4, run_loop5; // RegisterMediaRouteProvider() is called. // The queued DetachRoute(kRouteId2) call should be executed. - EXPECT_CALL(provide_handler_, Invoke(testing::Not(""))); + EXPECT_CALL(provide_handler_, Invoke(testing::Not(""))) + .WillOnce(InvokeWithoutArgs([&run_loop4]() { + run_loop4.Quit(); + })); EXPECT_CALL(*process_manager_, IsEventPageSuspended(kExtensionId)) .WillOnce(Return(false)); - EXPECT_CALL(mock_media_route_provider_, DetachRoute(mojo::String(kRouteId2))); + EXPECT_CALL(mock_media_route_provider_, DetachRoute(mojo::String(kRouteId2))) + .WillOnce(InvokeWithoutArgs([&run_loop5]() { + run_loop5.Quit(); + })); BindMediaRouteProvider(); RegisterMediaRouteProvider(); - ProcessEventLoop(); + run_loop4.Run(); + run_loop5.Run(); ExpectWakeReasonBucketCount(MediaRouteProviderWakeReason::DETACH_ROUTE, 1); } @@ -1066,16 +1174,25 @@ // The request queue size should not exceed |kMaxPendingRequests|. EXPECT_EQ(kMaxPendingRequests, media_router_->pending_requests_.size()); + base::RunLoop run_loop, run_loop2; + size_t count = 0; // The oldest request should have been dropped, so we don't expect to see // DetachRoute(kRouteId) here. BindMediaRouteProvider(); - EXPECT_CALL(provide_handler_, Invoke(testing::Not(""))); - EXPECT_CALL(*process_manager_, IsEventPageSuspended(kExtensionId)) - .WillOnce(Return(false)); + EXPECT_CALL(provide_handler_, Invoke(testing::Not(""))) + .WillOnce(InvokeWithoutArgs([&run_loop]() { + run_loop.Quit(); + })); + EXPECT_CALL(*process_manager_, IsEventPageSuspended(kExtensionId)); EXPECT_CALL(mock_media_route_provider_, DetachRoute(mojo::String(kRouteId2))) - .Times(kMaxPendingRequests); + .Times(kMaxPendingRequests) + .WillRepeatedly(InvokeWithoutArgs([&run_loop2, &count]() { + if (++count == MediaRouterMojoImpl::kMaxPendingRequests) + run_loop2.Quit(); + })); RegisterMediaRouteProvider(); - ProcessEventLoop(); + run_loop.Run(); + run_loop2.Run(); } } // namespace media_router
diff --git a/chrome/browser/net/predictor.cc b/chrome/browser/net/predictor.cc index 799fa1ae..ee5278c 100644 --- a/chrome/browser/net/predictor.cc +++ b/chrome/browser/net/predictor.cc
@@ -188,7 +188,6 @@ // --------------------- Start UI methods. ------------------------------------ void Predictor::InitNetworkPredictor(PrefService* user_prefs, - PrefService* local_state, IOThread* io_thread, net::URLRequestContextGetter* getter, ProfileIOData* profile_io_data) { @@ -198,7 +197,7 @@ url_request_context_getter_ = getter; // Gather the list of hostnames to prefetch on startup. - UrlList urls = GetPredictedUrlListAtStartup(user_prefs, local_state); + UrlList urls = GetPredictedUrlListAtStartup(user_prefs); base::ListValue* referral_list = static_cast<base::ListValue*>(user_prefs->GetList( @@ -314,9 +313,7 @@ PredictFrameSubresources(url.GetWithEmptyPath(), first_party_for_cookies); } -UrlList Predictor::GetPredictedUrlListAtStartup( - PrefService* user_prefs, - PrefService* local_state) { +UrlList Predictor::GetPredictedUrlListAtStartup(PrefService* user_prefs) { DCHECK_CURRENTLY_ON(BrowserThread::UI); UrlList urls; // Recall list of URLs we learned about during last session. @@ -1299,7 +1296,6 @@ void SimplePredictor::InitNetworkPredictor( PrefService* user_prefs, - PrefService* local_state, IOThread* io_thread, net::URLRequestContextGetter* getter, ProfileIOData* profile_io_data) {
diff --git a/chrome/browser/net/predictor.h b/chrome/browser/net/predictor.h index 5f26701..53ea632 100644 --- a/chrome/browser/net/predictor.h +++ b/chrome/browser/net/predictor.h
@@ -19,16 +19,15 @@ #ifndef CHROME_BROWSER_NET_PREDICTOR_H_ #define CHROME_BROWSER_NET_PREDICTOR_H_ +#include <stddef.h> +#include <stdint.h> + #include <map> #include <queue> #include <set> #include <string> #include <vector> -#include <stddef.h> - -#include <stdint.h> - #include "base/gtest_prod_util.h" #include "base/macros.h" #include "base/memory/scoped_ptr.h" @@ -137,7 +136,6 @@ // ------------- Start UI thread methods. virtual void InitNetworkPredictor(PrefService* user_prefs, - PrefService* local_state, IOThread* io_thread, net::URLRequestContextGetter* getter, ProfileIOData* profile_io_data); @@ -151,8 +149,7 @@ void PreconnectUrlAndSubresources(const GURL& url, const GURL& first_party_for_cookies); - static UrlList GetPredictedUrlListAtStartup(PrefService* user_prefs, - PrefService* local_state); + static UrlList GetPredictedUrlListAtStartup(PrefService* user_prefs); static void set_max_queueing_delay(int max_queueing_delay_ms); @@ -610,7 +607,6 @@ : Predictor(preconnect_enabled, predictor_enabled) {} ~SimplePredictor() override {} void InitNetworkPredictor(PrefService* user_prefs, - PrefService* local_state, IOThread* io_thread, net::URLRequestContextGetter* getter, ProfileIOData* profile_io_data) override;
diff --git a/chrome/browser/page_load_metrics/observers/aborts_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/aborts_page_load_metrics_observer.cc index fb1b528..cb5f020 100644 --- a/chrome/browser/page_load_metrics/observers/aborts_page_load_metrics_observer.cc +++ b/chrome/browser/page_load_metrics/observers/aborts_page_load_metrics_observer.cc
@@ -8,6 +8,79 @@ using page_load_metrics::UserAbortType; +namespace { + +void RecordAbortBeforeCommit(UserAbortType abort_type, + const base::TimeDelta& time_to_abort) { + switch (abort_type) { + case UserAbortType::ABORT_RELOAD: + PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortReloadBeforeCommit, + time_to_abort); + return; + case UserAbortType::ABORT_FORWARD_BACK: + PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortForwardBackBeforeCommit, + time_to_abort); + return; + case UserAbortType::ABORT_NEW_NAVIGATION: + PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortNewNavigationBeforeCommit, + time_to_abort); + return; + case UserAbortType::ABORT_STOP: + PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortStopBeforeCommit, + time_to_abort); + return; + case UserAbortType::ABORT_CLOSE: + PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortCloseBeforeCommit, + time_to_abort); + return; + case UserAbortType::ABORT_OTHER: + PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortOtherBeforeCommit, + time_to_abort); + return; + case UserAbortType::ABORT_NONE: + case UserAbortType::ABORT_LAST_ENTRY: + NOTREACHED(); + return; + } + NOTREACHED(); +} + +void RecordAbortAfterCommitBeforePaint(UserAbortType abort_type, + const base::TimeDelta& time_to_abort) { + switch (abort_type) { + case UserAbortType::ABORT_RELOAD: + PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortReloadBeforePaint, + time_to_abort); + return; + case UserAbortType::ABORT_FORWARD_BACK: + PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortForwardBackBeforePaint, + time_to_abort); + return; + case UserAbortType::ABORT_NEW_NAVIGATION: + PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortNewNavigationBeforePaint, + time_to_abort); + return; + case UserAbortType::ABORT_STOP: + PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortStopBeforePaint, + time_to_abort); + return; + case UserAbortType::ABORT_CLOSE: + PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortCloseBeforePaint, + time_to_abort); + return; + case UserAbortType::ABORT_OTHER: + DLOG(FATAL) << "Received UserAbortType::ABORT_OTHER for committed load."; + return; + case UserAbortType::ABORT_NONE: + case UserAbortType::ABORT_LAST_ENTRY: + NOTREACHED(); + return; + } + NOTREACHED(); +} + +} // namespace + namespace internal { const char kHistogramAbortForwardBackBeforeCommit[] = @@ -47,85 +120,24 @@ const base::TimeDelta& time_to_abort = extra_info.time_to_abort; DCHECK(!time_to_abort.is_zero()); - // Loads are not considered aborts if they painted before the abort event. - if (!timing.first_paint.is_zero() && timing.first_paint < time_to_abort) - return; - // Don't log abort times if the page was backgrounded before the abort event. if (!EventOccurredInForeground(time_to_abort, extra_info)) return; - // If |timing.IsEmpty()|, then this load was not tracked by the renderer. It - // is impossible to know whether the abort signals came before the page - // painted. - if (!extra_info.time_to_commit.is_zero() && !timing.IsEmpty()) { - switch (abort_type) { - case UserAbortType::ABORT_RELOAD: - PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortReloadBeforePaint, - time_to_abort); - return; - case UserAbortType::ABORT_FORWARD_BACK: - PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortForwardBackBeforePaint, - time_to_abort); - return; - case UserAbortType::ABORT_NEW_NAVIGATION: - PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortNewNavigationBeforePaint, - time_to_abort); - return; - case UserAbortType::ABORT_STOP: - PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortStopBeforePaint, - time_to_abort); - return; - case UserAbortType::ABORT_CLOSE: - PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortCloseBeforePaint, - time_to_abort); - return; - case UserAbortType::ABORT_OTHER: - DLOG(FATAL) - << "Received UserAbortType::ABORT_OTHER for committed load."; - return; - case UserAbortType::ABORT_NONE: - case UserAbortType::ABORT_LAST_ENTRY: - NOTREACHED(); - return; - } - NOTREACHED(); - } - if (!extra_info.time_to_commit.is_zero()) { - // This load was not tracked by the renderer. + if (extra_info.time_to_commit.is_zero()) { + RecordAbortBeforeCommit(abort_type, time_to_abort); return; } - // Handle provisional aborts. - DCHECK(timing.IsEmpty()); - switch (abort_type) { - case UserAbortType::ABORT_RELOAD: - PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortReloadBeforeCommit, - time_to_abort); - return; - case UserAbortType::ABORT_FORWARD_BACK: - PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortForwardBackBeforeCommit, - time_to_abort); - return; - case UserAbortType::ABORT_NEW_NAVIGATION: - PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortNewNavigationBeforeCommit, - time_to_abort); - return; - case UserAbortType::ABORT_STOP: - PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortStopBeforeCommit, - time_to_abort); - return; - case UserAbortType::ABORT_CLOSE: - PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortCloseBeforeCommit, - time_to_abort); - return; - case UserAbortType::ABORT_OTHER: - PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortOtherBeforeCommit, - time_to_abort); - return; - case UserAbortType::ABORT_NONE: - case UserAbortType::ABORT_LAST_ENTRY: - NOTREACHED(); - return; + + // If we have a committed load but |timing.IsEmpty()|, then this load was not + // tracked by the renderer. In this case, it is not possible to know whether + // the abort signals came before the page painted. Additionally, for + // consistency with PageLoad.Timing2 metrics, we ignore non-render-tracked + // loads when tracking aborts after commit. + if (timing.IsEmpty()) + return; + + if (timing.first_paint.is_zero() || timing.first_paint >= time_to_abort) { + RecordAbortAfterCommitBeforePaint(abort_type, time_to_abort); } - NOTREACHED(); }
diff --git a/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.cc new file mode 100644 index 0000000..d9ef53c5 --- /dev/null +++ b/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.cc
@@ -0,0 +1,244 @@ +// 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/page_load_metrics/observers/core_page_load_metrics_observer.h" + +#include <stddef.h> +#include <stdint.h> +#include <utility> + +#include "chrome/browser/browser_process.h" +#include "components/page_load_metrics/browser/page_load_metrics_util.h" +#include "components/rappor/rappor_service.h" +#include "components/rappor/rappor_utils.h" + +namespace { + +// The number of buckets in the bitfield histogram. These buckets are described +// in rappor.xml in PageLoad.CoarseTiming.NavigationToFirstContentfulPaint. +// The bucket flag is defined by 1 << bucket_index, and is the bitfield +// representing which timing bucket the page load falls into, i.e. 000010 +// would be the bucket flag showing that the page took between 2 and 4 seconds +// to load. +const size_t kNumRapporHistogramBuckets = 6; + +uint64_t RapporHistogramBucketIndex(const base::TimeDelta& time) { + int64_t seconds = time.InSeconds(); + if (seconds < 2) + return 0; + if (seconds < 4) + return 1; + if (seconds < 8) + return 2; + if (seconds < 16) + return 3; + if (seconds < 32) + return 4; + return 5; +} + +} // namespace + +namespace internal { + +const char kHistogramCommit[] = "PageLoad.Timing2.NavigationToCommit"; +const char kHistogramFirstLayout[] = "PageLoad.Timing2.NavigationToFirstLayout"; +const char kHistogramFirstTextPaint[] = + "PageLoad.Timing2.NavigationToFirstTextPaint"; +const char kHistogramDomContentLoaded[] = + "PageLoad.Timing2.NavigationToDOMContentLoadedEventFired"; +const char kHistogramLoad[] = "PageLoad.Timing2.NavigationToLoadEventFired"; +const char kHistogramFirstPaint[] = "PageLoad.Timing2.NavigationToFirstPaint"; +const char kHistogramFirstImagePaint[] = + "PageLoad.Timing2.NavigationToFirstImagePaint"; +const char kHistogramFirstContentfulPaint[] = + "PageLoad.Timing2.NavigationToFirstContentfulPaint"; +const char kBackgroundHistogramCommit[] = + "PageLoad.Timing2.NavigationToCommit.Background"; +const char kBackgroundHistogramFirstLayout[] = + "PageLoad.Timing2.NavigationToFirstLayout.Background"; +const char kBackgroundHistogramFirstTextPaint[] = + "PageLoad.Timing2.NavigationToFirstTextPaint.Background"; +const char kBackgroundHistogramDomContentLoaded[] = + "PageLoad.Timing2.NavigationToDOMContentLoadedEventFired.Background"; +const char kBackgroundHistogramLoad[] = + "PageLoad.Timing2.NavigationToLoadEventFired.Background"; +const char kBackgroundHistogramFirstPaint[] = + "PageLoad.Timing2.NavigationToFirstPaint.Background"; +const char kBackgroundHistogramFirstImagePaint[] = + "PageLoad.Timing2.NavigationToFirstImagePaint.Background."; +const char kBackgroundHistogramFirstContentfulPaint[] = + "PageLoad.Timing2.NavigationToFirstContentfulPaint.Background"; + +const char kHistogramFirstContentfulPaintHigh[] = + "PageLoad.Timing2.NavigationToFirstContentfulPaint.HighResolutionClock"; +const char kHistogramFirstContentfulPaintLow[] = + "PageLoad.Timing2.NavigationToFirstContentfulPaint.LowResolutionClock"; + +const char kHistogramFirstBackground[] = + "PageLoad.Timing2.NavigationToFirstBackground"; +const char kHistogramFirstForeground[] = + "PageLoad.Timing2.NavigationToFirstForeground"; + +const char kHistogramBackgroundBeforePaint[] = + "PageLoad.Timing2.NavigationToFirstBackground.AfterCommit.BeforePaint"; +const char kHistogramBackgroundBeforeCommit[] = + "PageLoad.Timing2.NavigationToFirstBackground.BeforeCommit"; + +const char kRapporMetricsNameCoarseTiming[] = + "PageLoad.CoarseTiming.NavigationToFirstContentfulPaint"; + +} // namespace internal + +CorePageLoadMetricsObserver::CorePageLoadMetricsObserver() {} + +CorePageLoadMetricsObserver::~CorePageLoadMetricsObserver() {} + +void CorePageLoadMetricsObserver::OnComplete( + const page_load_metrics::PageLoadTiming& timing, + const page_load_metrics::PageLoadExtraInfo& info) { + RecordTimingHistograms(timing, info); + RecordRappor(timing, info); +} + +void CorePageLoadMetricsObserver::RecordTimingHistograms( + const page_load_metrics::PageLoadTiming& timing, + const page_load_metrics::PageLoadExtraInfo& info) { + if (!info.first_background_time.is_zero() && + !EventOccurredInForeground(timing.first_paint, info)) { + if (!info.time_to_commit.is_zero()) { + PAGE_LOAD_HISTOGRAM(internal::kHistogramBackgroundBeforePaint, + info.first_background_time); + } else { + PAGE_LOAD_HISTOGRAM(internal::kHistogramBackgroundBeforeCommit, + info.first_background_time); + } + } + + // The rest of the histograms require the load to have commit and be relevant. + // If |timing.IsEmpty()|, then this load was not tracked by the renderer. + if (info.time_to_commit.is_zero() || timing.IsEmpty()) + return; + + if (EventOccurredInForeground(info.time_to_commit, info)) { + PAGE_LOAD_HISTOGRAM(internal::kHistogramCommit, info.time_to_commit); + } else { + PAGE_LOAD_HISTOGRAM(internal::kBackgroundHistogramCommit, + info.time_to_commit); + } + if (!timing.dom_content_loaded_event_start.is_zero()) { + if (EventOccurredInForeground(timing.dom_content_loaded_event_start, + info)) { + PAGE_LOAD_HISTOGRAM(internal::kHistogramDomContentLoaded, + timing.dom_content_loaded_event_start); + } else { + PAGE_LOAD_HISTOGRAM(internal::kBackgroundHistogramDomContentLoaded, + timing.dom_content_loaded_event_start); + } + } + if (!timing.load_event_start.is_zero()) { + if (EventOccurredInForeground(timing.load_event_start, info)) { + PAGE_LOAD_HISTOGRAM(internal::kHistogramLoad, timing.load_event_start); + } else { + PAGE_LOAD_HISTOGRAM(internal::kBackgroundHistogramLoad, + timing.load_event_start); + } + } + if (!timing.first_layout.is_zero()) { + if (EventOccurredInForeground(timing.first_layout, info)) { + PAGE_LOAD_HISTOGRAM(internal::kHistogramFirstLayout, timing.first_layout); + } else { + PAGE_LOAD_HISTOGRAM(internal::kBackgroundHistogramFirstLayout, + timing.first_layout); + } + } + if (!timing.first_paint.is_zero()) { + if (EventOccurredInForeground(timing.first_paint, info)) { + PAGE_LOAD_HISTOGRAM(internal::kHistogramFirstPaint, timing.first_paint); + } else { + PAGE_LOAD_HISTOGRAM(internal::kBackgroundHistogramFirstPaint, + timing.first_paint); + } + } + if (!timing.first_text_paint.is_zero()) { + if (EventOccurredInForeground(timing.first_text_paint, info)) { + PAGE_LOAD_HISTOGRAM(internal::kHistogramFirstTextPaint, + timing.first_text_paint); + } else { + PAGE_LOAD_HISTOGRAM(internal::kBackgroundHistogramFirstTextPaint, + timing.first_text_paint); + } + } + if (!timing.first_image_paint.is_zero()) { + if (EventOccurredInForeground(timing.first_image_paint, info)) { + PAGE_LOAD_HISTOGRAM(internal::kHistogramFirstImagePaint, + timing.first_image_paint); + } else { + PAGE_LOAD_HISTOGRAM(internal::kBackgroundHistogramFirstImagePaint, + timing.first_image_paint); + } + } + base::TimeDelta first_contentful_paint = GetFirstContentfulPaint(timing); + if (!first_contentful_paint.is_zero()) { + if (EventOccurredInForeground(first_contentful_paint, info)) { + PAGE_LOAD_HISTOGRAM(internal::kHistogramFirstContentfulPaint, + first_contentful_paint); + // Bucket these histograms into high/low resolution clock systems. This + // might point us to directions that will de-noise some UMA. + if (base::TimeTicks::IsHighResolution()) { + PAGE_LOAD_HISTOGRAM(internal::kHistogramFirstContentfulPaintHigh, + first_contentful_paint); + } else { + PAGE_LOAD_HISTOGRAM(internal::kHistogramFirstContentfulPaintLow, + first_contentful_paint); + } + } else { + PAGE_LOAD_HISTOGRAM(internal::kBackgroundHistogramFirstContentfulPaint, + first_contentful_paint); + } + } + + // Log time to first foreground / time to first background. Log counts that we + // started a relevant page load in the foreground / background. + if (!info.first_background_time.is_zero()) + PAGE_LOAD_HISTOGRAM(internal::kHistogramFirstBackground, + info.first_background_time); + else if (!info.first_foreground_time.is_zero()) + PAGE_LOAD_HISTOGRAM(internal::kHistogramFirstForeground, + info.first_foreground_time); +} + +void CorePageLoadMetricsObserver::RecordRappor( + const page_load_metrics::PageLoadTiming& timing, + const page_load_metrics::PageLoadExtraInfo& info) { + // During the browser process shutdown path, calling + // BrowserProcess::rappor_service() can reinitialize multiple destroyed + // objects. This alters shutdown ordering, so we avoid it by testing + // IsShuttingDown() first. + if (g_browser_process->IsShuttingDown()) + return; + rappor::RapporService* rappor_service = g_browser_process->rappor_service(); + if (!rappor_service) + return; + if (info.time_to_commit.is_zero()) + return; + DCHECK(!info.committed_url.is_empty()); + base::TimeDelta first_contentful_paint = GetFirstContentfulPaint(timing); + // Log the eTLD+1 of sites that show poor loading performance. + if (!EventOccurredInForeground(first_contentful_paint, info)) { + return; + } + scoped_ptr<rappor::Sample> sample = + rappor_service->CreateSample(rappor::UMA_RAPPOR_TYPE); + sample->SetStringField( + "Domain", rappor::GetDomainAndRegistrySampleFromGURL(info.committed_url)); + uint64_t bucket_index = RapporHistogramBucketIndex(first_contentful_paint); + sample->SetFlagsField("Bucket", uint64_t(1) << bucket_index, + kNumRapporHistogramBuckets); + // The IsSlow flag is just a one bit boolean if the first contentful paint + // was > 10s. + sample->SetFlagsField("IsSlow", first_contentful_paint.InSecondsF() >= 10, 1); + rappor_service->RecordSampleObj(internal::kRapporMetricsNameCoarseTiming, + std::move(sample)); +}
diff --git a/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.h b/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.h new file mode 100644 index 0000000..cc7329ab --- /dev/null +++ b/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.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_PAGE_LOAD_METRICS_OBSERVERS_CORE_PAGE_LOAD_METRICS_OBSERVER_H_ +#define CHROME_BROWSER_PAGE_LOAD_METRICS_OBSERVERS_CORE_PAGE_LOAD_METRICS_OBSERVER_H_ + +#include "components/page_load_metrics/browser/page_load_metrics_observer.h" + +namespace internal { + +// NOTE: Some of these histograms are separated into a separate histogram +// specified by the ".Background" suffix. For these events, we put them into the +// background histogram if the web contents was ever in the background from +// navigation start to the event in question. +extern const char kHistogramCommit[]; +extern const char kHistogramFirstLayout[]; +extern const char kHistogramFirstTextPaint[]; +extern const char kHistogramDomContentLoaded[]; +extern const char kHistogramLoad[]; +extern const char kHistogramFirstPaint[]; +extern const char kHistogramFirstImagePaint[]; +extern const char kHistogramFirstContentfulPaint[]; +extern const char kBackgroundHistogramCommit[]; +extern const char kBackgroundHistogramFirstLayout[]; +extern const char kBackgroundHistogramFirstTextPaint[]; +extern const char kBackgroundHistogramDomContentLoaded[]; +extern const char kBackgroundHistogramLoad[]; +extern const char kBackgroundHistogramFirstPaint[]; +extern const char kBackgroundHistogramFirstImagePaint[]; +extern const char kBackgroundHistogramFirstContentfulPaint[]; + +extern const char kHistogramFirstContentfulPaintHigh[]; +extern const char kHistogramFirstContentfulPaintLow[]; + +extern const char kHistogramFirstBackground[]; +extern const char kHistogramFirstForeground[]; + +extern const char kHistogramBackgroundBeforePaint[]; +extern const char kHistogramBackgroundBeforeCommit[]; + +extern const char kRapporMetricsNameCoarseTiming[]; + +} // namespace internal + +// Observer responsible for recording 'core' page load metrics. Core metrics are +// maintained by loading-dev team, typically the metrics under +// PageLoad.Timing2.*. +class CorePageLoadMetricsObserver + : public page_load_metrics::PageLoadMetricsObserver { + public: + CorePageLoadMetricsObserver(); + ~CorePageLoadMetricsObserver() override; + + // page_load_metrics::PageLoadMetricsObserver: + void OnComplete(const page_load_metrics::PageLoadTiming& timing, + const page_load_metrics::PageLoadExtraInfo& info) override; + + private: + void RecordTimingHistograms(const page_load_metrics::PageLoadTiming& timing, + const page_load_metrics::PageLoadExtraInfo& info); + void RecordRappor(const page_load_metrics::PageLoadTiming& timing, + const page_load_metrics::PageLoadExtraInfo& info); + + DISALLOW_COPY_AND_ASSIGN(CorePageLoadMetricsObserver); +}; + +#endif // CHROME_BROWSER_PAGE_LOAD_METRICS_OBSERVERS_CORE_PAGE_LOAD_METRICS_OBSERVER_H_
diff --git a/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer_unittest.cc new file mode 100644 index 0000000..757e0bf --- /dev/null +++ b/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer_unittest.cc
@@ -0,0 +1,334 @@ +// 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/page_load_metrics/observers/core_page_load_metrics_observer.h" +#include "chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.h" +#include "chrome/test/base/testing_browser_process.h" +#include "components/rappor/rappor_utils.h" +#include "components/rappor/test_rappor_service.h" + +namespace { + +const char kDefaultTestUrl[] = "https://google.com"; +const char kDefaultTestUrlAnchor[] = "https://google.com#samepage"; +const char kDefaultTestUrl2[] = "https://whatever.com"; + +} // namespace + +class CorePageLoadMetricsObserverTest + : public page_load_metrics::PageLoadMetricsObserverTestHarness { + protected: + void RegisterObservers(page_load_metrics::PageLoadTracker* tracker) override { + tracker->AddObserver(make_scoped_ptr(new CorePageLoadMetricsObserver())); + } + + void AssertNoHistogramsLogged() { + histogram_tester().ExpectTotalCount(internal::kHistogramDomContentLoaded, + 0); + histogram_tester().ExpectTotalCount(internal::kHistogramLoad, 0); + histogram_tester().ExpectTotalCount(internal::kHistogramFirstLayout, 0); + histogram_tester().ExpectTotalCount(internal::kHistogramFirstTextPaint, 0); + } + + void SetUp() override { + page_load_metrics::PageLoadMetricsObserverTestHarness::SetUp(); + TestingBrowserProcess::GetGlobal()->SetRapporService(&rappor_tester_); + } + + rappor::TestRapporService rappor_tester_; +}; + +TEST_F(CorePageLoadMetricsObserverTest, NoMetrics) { + AssertNoHistogramsLogged(); +} + +TEST_F(CorePageLoadMetricsObserverTest, SamePageNoTriggerUntilTrueNavCommit) { + base::TimeDelta first_layout = base::TimeDelta::FromMilliseconds(1); + + page_load_metrics::PageLoadTiming timing; + timing.navigation_start = base::Time::FromDoubleT(1); + timing.first_layout = first_layout; + + NavigateAndCommit(GURL(kDefaultTestUrl)); + SimulateTimingUpdate(timing); + + NavigateAndCommit(GURL(kDefaultTestUrlAnchor)); + // A same page navigation shouldn't trigger logging UMA for the original. + AssertNoHistogramsLogged(); + + // But we should keep the timing info and log it when we get another + // navigation. + NavigateAndCommit(GURL(kDefaultTestUrl2)); + histogram_tester().ExpectTotalCount(internal::kHistogramCommit, 1); + histogram_tester().ExpectTotalCount(internal::kHistogramDomContentLoaded, 0); + histogram_tester().ExpectTotalCount(internal::kHistogramLoad, 0); + histogram_tester().ExpectTotalCount(internal::kHistogramFirstLayout, 1); + histogram_tester().ExpectBucketCount(internal::kHistogramFirstLayout, + first_layout.InMilliseconds(), 1); + histogram_tester().ExpectTotalCount(internal::kHistogramFirstTextPaint, 0); +} + +TEST_F(CorePageLoadMetricsObserverTest, SingleMetricAfterCommit) { + base::TimeDelta first_layout = base::TimeDelta::FromMilliseconds(1); + + page_load_metrics::PageLoadTiming timing; + timing.navigation_start = base::Time::FromDoubleT(1); + timing.first_layout = first_layout; + + NavigateAndCommit(GURL(kDefaultTestUrl)); + SimulateTimingUpdate(timing); + + AssertNoHistogramsLogged(); + + // Navigate again to force histogram recording. + NavigateAndCommit(GURL(kDefaultTestUrl2)); + + histogram_tester().ExpectTotalCount(internal::kHistogramCommit, 1); + histogram_tester().ExpectTotalCount(internal::kHistogramDomContentLoaded, 0); + histogram_tester().ExpectTotalCount(internal::kHistogramLoad, 0); + histogram_tester().ExpectTotalCount(internal::kHistogramFirstLayout, 1); + histogram_tester().ExpectBucketCount(internal::kHistogramFirstLayout, + first_layout.InMilliseconds(), 1); + histogram_tester().ExpectTotalCount(internal::kHistogramFirstTextPaint, 0); +} + +TEST_F(CorePageLoadMetricsObserverTest, MultipleMetricsAfterCommits) { + base::TimeDelta first_layout_1 = base::TimeDelta::FromMilliseconds(1); + base::TimeDelta first_layout_2 = base::TimeDelta::FromMilliseconds(20); + base::TimeDelta response = base::TimeDelta::FromMilliseconds(10); + base::TimeDelta first_text_paint = base::TimeDelta::FromMilliseconds(30); + base::TimeDelta dom_content = base::TimeDelta::FromMilliseconds(40); + base::TimeDelta load = base::TimeDelta::FromMilliseconds(100); + + page_load_metrics::PageLoadTiming timing; + timing.navigation_start = base::Time::FromDoubleT(1); + timing.first_layout = first_layout_1; + timing.response_start = response; + timing.first_text_paint = first_text_paint; + timing.dom_content_loaded_event_start = dom_content; + timing.load_event_start = load; + + NavigateAndCommit(GURL(kDefaultTestUrl)); + SimulateTimingUpdate(timing); + + NavigateAndCommit(GURL(kDefaultTestUrl2)); + + page_load_metrics::PageLoadTiming timing2; + timing2.navigation_start = base::Time::FromDoubleT(200); + timing2.first_layout = first_layout_2; + + SimulateTimingUpdate(timing2); + + NavigateAndCommit(GURL(kDefaultTestUrl)); + + histogram_tester().ExpectTotalCount(internal::kHistogramCommit, 2); + histogram_tester().ExpectBucketCount(internal::kHistogramFirstLayout, + first_layout_1.InMilliseconds(), 1); + histogram_tester().ExpectTotalCount(internal::kHistogramFirstLayout, 2); + histogram_tester().ExpectBucketCount(internal::kHistogramFirstLayout, + first_layout_1.InMilliseconds(), 1); + histogram_tester().ExpectBucketCount(internal::kHistogramFirstLayout, + first_layout_2.InMilliseconds(), 1); + + histogram_tester().ExpectTotalCount(internal::kHistogramFirstTextPaint, 1); + histogram_tester().ExpectBucketCount(internal::kHistogramFirstTextPaint, + first_text_paint.InMilliseconds(), 1); + + histogram_tester().ExpectTotalCount(internal::kHistogramDomContentLoaded, 1); + histogram_tester().ExpectBucketCount(internal::kHistogramDomContentLoaded, + dom_content.InMilliseconds(), 1); + + histogram_tester().ExpectTotalCount(internal::kHistogramLoad, 1); + histogram_tester().ExpectBucketCount(internal::kHistogramLoad, + load.InMilliseconds(), 1); +} + +TEST_F(CorePageLoadMetricsObserverTest, BackgroundDifferentHistogram) { + base::TimeDelta first_layout = base::TimeDelta::FromSeconds(2); + + page_load_metrics::PageLoadTiming timing; + timing.navigation_start = base::Time::FromDoubleT(1); + timing.first_layout = first_layout; + + // Simulate "Open link in new tab." + web_contents()->WasHidden(); + NavigateAndCommit(GURL(kDefaultTestUrl)); + SimulateTimingUpdate(timing); + + // Simulate switching to the tab and making another navigation. + web_contents()->WasShown(); + AssertNoHistogramsLogged(); + + // Navigate again to force histogram recording. + NavigateAndCommit(GURL(kDefaultTestUrl2)); + + histogram_tester().ExpectTotalCount(internal::kBackgroundHistogramCommit, 1); + histogram_tester().ExpectTotalCount( + internal::kBackgroundHistogramDomContentLoaded, 0); + histogram_tester().ExpectTotalCount(internal::kBackgroundHistogramLoad, 0); + histogram_tester().ExpectTotalCount(internal::kBackgroundHistogramFirstLayout, + 1); + histogram_tester().ExpectBucketCount( + internal::kBackgroundHistogramFirstLayout, first_layout.InMilliseconds(), + 1); + histogram_tester().ExpectTotalCount( + internal::kBackgroundHistogramFirstTextPaint, 0); + + histogram_tester().ExpectTotalCount(internal::kHistogramCommit, 0); + histogram_tester().ExpectTotalCount(internal::kHistogramDomContentLoaded, 0); + histogram_tester().ExpectTotalCount(internal::kHistogramLoad, 0); + histogram_tester().ExpectTotalCount(internal::kHistogramFirstLayout, 0); + histogram_tester().ExpectTotalCount(internal::kHistogramFirstTextPaint, 0); +} + +TEST_F(CorePageLoadMetricsObserverTest, OnlyBackgroundLaterEvents) { + page_load_metrics::PageLoadTiming timing; + timing.navigation_start = base::Time::FromDoubleT(1); + // Set these events at 1 microsecond so they are definitely occur before we + // background the tab later in the test. + timing.response_start = base::TimeDelta::FromMicroseconds(1); + timing.dom_content_loaded_event_start = base::TimeDelta::FromMicroseconds(1); + + NavigateAndCommit(GURL(kDefaultTestUrl)); + SimulateTimingUpdate(timing); + + // Background the tab, then forground it. + web_contents()->WasHidden(); + web_contents()->WasShown(); + timing.first_layout = base::TimeDelta::FromSeconds(3); + timing.first_text_paint = base::TimeDelta::FromSeconds(4); + SimulateTimingUpdate(timing); + + // Navigate again to force histogram recording. + NavigateAndCommit(GURL(kDefaultTestUrl2)); + + histogram_tester().ExpectTotalCount(internal::kBackgroundHistogramCommit, 0); + histogram_tester().ExpectTotalCount( + internal::kBackgroundHistogramDomContentLoaded, 0); + histogram_tester().ExpectTotalCount(internal::kBackgroundHistogramLoad, 0); + histogram_tester().ExpectTotalCount(internal::kBackgroundHistogramFirstLayout, + 1); + histogram_tester().ExpectBucketCount( + internal::kBackgroundHistogramFirstLayout, + timing.first_layout.InMilliseconds(), 1); + histogram_tester().ExpectTotalCount( + internal::kBackgroundHistogramFirstTextPaint, 1); + histogram_tester().ExpectBucketCount( + internal::kBackgroundHistogramFirstTextPaint, + timing.first_text_paint.InMilliseconds(), 1); + + histogram_tester().ExpectTotalCount(internal::kHistogramCommit, 1); + histogram_tester().ExpectTotalCount(internal::kHistogramDomContentLoaded, 1); + histogram_tester().ExpectBucketCount( + internal::kHistogramDomContentLoaded, + timing.dom_content_loaded_event_start.InMilliseconds(), 1); + histogram_tester().ExpectTotalCount(internal::kHistogramLoad, 0); + histogram_tester().ExpectTotalCount(internal::kHistogramFirstLayout, 0); + histogram_tester().ExpectTotalCount(internal::kHistogramFirstTextPaint, 0); +} + +TEST_F(CorePageLoadMetricsObserverTest, DontBackgroundQuickerLoad) { + // Set this event at 1 microsecond so it occurs before we foreground later in + // the test. + base::TimeDelta first_layout = base::TimeDelta::FromMicroseconds(1); + + page_load_metrics::PageLoadTiming timing; + timing.navigation_start = base::Time::FromDoubleT(1); + timing.first_layout = first_layout; + + web_contents()->WasHidden(); + + // Open in new tab + StartNavigation(GURL(kDefaultTestUrl)); + + // Switch to the tab + web_contents()->WasShown(); + + // Start another provisional load + StartNavigation(GURL(kDefaultTestUrl2)); + content::RenderFrameHostTester* rfh_tester = + content::RenderFrameHostTester::For(main_rfh()); + rfh_tester->SimulateNavigationCommit(GURL(kDefaultTestUrl2)); + SimulateTimingUpdate(timing); + rfh_tester->SimulateNavigationStop(); + + // Navigate again to see if the timing updated for the foregrounded load. + NavigateAndCommit(GURL(kDefaultTestUrl)); + + histogram_tester().ExpectTotalCount(internal::kHistogramCommit, 1); + histogram_tester().ExpectTotalCount(internal::kHistogramDomContentLoaded, 0); + histogram_tester().ExpectTotalCount(internal::kHistogramLoad, 0); + histogram_tester().ExpectTotalCount(internal::kHistogramFirstLayout, 1); + histogram_tester().ExpectBucketCount(internal::kHistogramFirstLayout, + first_layout.InMilliseconds(), 1); + histogram_tester().ExpectTotalCount(internal::kHistogramFirstTextPaint, 0); +} + +TEST_F(CorePageLoadMetricsObserverTest, BackgroundBeforePaint) { + page_load_metrics::PageLoadTiming timing; + timing.navigation_start = base::Time::FromDoubleT(1); + timing.first_paint = base::TimeDelta::FromSeconds(10); + NavigateAndCommit(GURL(kDefaultTestUrl)); + // Background the tab and go for a coffee or something. + web_contents()->WasHidden(); + SimulateTimingUpdate(timing); + // Come back and start browsing again. + web_contents()->WasShown(); + // Simulate the user performaning another navigation. + NavigateAndCommit(GURL("https://www.example.com")); + histogram_tester().ExpectTotalCount(internal::kHistogramBackgroundBeforePaint, + 1); +} + +TEST_F(CorePageLoadMetricsObserverTest, NoRappor) { + rappor::TestSample::Shadow* sample_obj = + rappor_tester_.GetRecordedSampleForMetric( + internal::kRapporMetricsNameCoarseTiming); + EXPECT_EQ(sample_obj, nullptr); +} + +TEST_F(CorePageLoadMetricsObserverTest, RapporLongPageLoad) { + page_load_metrics::PageLoadTiming timing; + timing.navigation_start = base::Time::FromDoubleT(1); + timing.first_image_paint = base::TimeDelta::FromSeconds(40); + NavigateAndCommit(GURL(kDefaultTestUrl)); + SimulateTimingUpdate(timing); + + // Navigate again to force logging RAPPOR. + NavigateAndCommit(GURL(kDefaultTestUrl2)); + rappor::TestSample::Shadow* sample_obj = + rappor_tester_.GetRecordedSampleForMetric( + internal::kRapporMetricsNameCoarseTiming); + const auto& string_it = sample_obj->string_fields.find("Domain"); + EXPECT_NE(string_it, sample_obj->string_fields.end()); + EXPECT_EQ(rappor::GetDomainAndRegistrySampleFromGURL(GURL(kDefaultTestUrl)), + string_it->second); + + const auto& flag_it = sample_obj->flag_fields.find("IsSlow"); + EXPECT_NE(flag_it, sample_obj->flag_fields.end()); + EXPECT_EQ(1u, flag_it->second); +} + +TEST_F(CorePageLoadMetricsObserverTest, RapporQuickPageLoad) { + page_load_metrics::PageLoadTiming timing; + timing.navigation_start = base::Time::FromDoubleT(1); + timing.first_text_paint = base::TimeDelta::FromSeconds(1); + + NavigateAndCommit(GURL(kDefaultTestUrl)); + SimulateTimingUpdate(timing); + + // Navigate again to force logging RAPPOR. + NavigateAndCommit(GURL(kDefaultTestUrl2)); + rappor::TestSample::Shadow* sample_obj = + rappor_tester_.GetRecordedSampleForMetric( + internal::kRapporMetricsNameCoarseTiming); + const auto& string_it = sample_obj->string_fields.find("Domain"); + EXPECT_NE(string_it, sample_obj->string_fields.end()); + EXPECT_EQ(rappor::GetDomainAndRegistrySampleFromGURL(GURL(kDefaultTestUrl)), + string_it->second); + + const auto& flag_it = sample_obj->flag_fields.find("IsSlow"); + EXPECT_NE(flag_it, sample_obj->flag_fields.end()); + EXPECT_EQ(0u, flag_it->second); +}
diff --git a/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.cc b/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.cc index 24b5589..44ff512 100644 --- a/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.cc +++ b/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.cc
@@ -19,8 +19,6 @@ PageLoadMetricsObserverTestHarness* test) : test_(test) {} - rappor::RapporService* GetRapporService() override { return nullptr; } - bool IsPrerendering(content::WebContents* web_contents) override { return false; }
diff --git a/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.h b/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.h index c2abae4..56e0832 100644 --- a/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.h +++ b/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.h
@@ -11,10 +11,6 @@ #include "components/page_load_metrics/browser/metrics_web_contents_observer.h" #include "content/public/test/web_contents_tester.h" -namespace rappor { -class RapporService; -} // namespace rappor - namespace page_load_metrics { // This class can be used to drive tests of PageLoadMetricsObservers. To hook up
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc b/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc index 74d9f81..1d6d56c 100644 --- a/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc +++ b/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc
@@ -4,17 +4,15 @@ #include "base/macros.h" #include "base/test/histogram_tester.h" +#include "chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.h" #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/ui_test_utils.h" -#include "components/page_load_metrics/browser/metrics_web_contents_observer.h" #include "net/test/embedded_test_server/embedded_test_server.h" -namespace page_load_metrics { - class MetricsWebContentsObserverBrowserTest : public InProcessBrowserTest { public: - MetricsWebContentsObserverBrowserTest(){}; - ~MetricsWebContentsObserverBrowserTest() override{}; + MetricsWebContentsObserverBrowserTest() {} + ~MetricsWebContentsObserverBrowserTest() override {} protected: base::HistogramTester histogram_tester_; @@ -25,9 +23,9 @@ IN_PROC_BROWSER_TEST_F(MetricsWebContentsObserverBrowserTest, NoNavigation) { ASSERT_TRUE(embedded_test_server()->Start()); - histogram_tester_.ExpectTotalCount(kHistogramDomContentLoaded, 0); - histogram_tester_.ExpectTotalCount(kHistogramLoad, 0); - histogram_tester_.ExpectTotalCount(kHistogramFirstLayout, 0); + histogram_tester_.ExpectTotalCount(internal::kHistogramDomContentLoaded, 0); + histogram_tester_.ExpectTotalCount(internal::kHistogramLoad, 0); + histogram_tester_.ExpectTotalCount(internal::kHistogramFirstLayout, 0); } IN_PROC_BROWSER_TEST_F(MetricsWebContentsObserverBrowserTest, NewPage) { @@ -38,9 +36,9 @@ ui_test_utils::NavigateToURL(browser(), embedded_test_server()->GetURL("/title2.html")); - histogram_tester_.ExpectTotalCount(kHistogramDomContentLoaded, 1); - histogram_tester_.ExpectTotalCount(kHistogramLoad, 1); - histogram_tester_.ExpectTotalCount(kHistogramFirstLayout, 1); + histogram_tester_.ExpectTotalCount(internal::kHistogramDomContentLoaded, 1); + histogram_tester_.ExpectTotalCount(internal::kHistogramLoad, 1); + histogram_tester_.ExpectTotalCount(internal::kHistogramFirstLayout, 1); } IN_PROC_BROWSER_TEST_F(MetricsWebContentsObserverBrowserTest, AnchorLink) { @@ -53,9 +51,7 @@ ui_test_utils::NavigateToURL(browser(), embedded_test_server()->GetURL("/title2.html")); - histogram_tester_.ExpectTotalCount(kHistogramDomContentLoaded, 1); - histogram_tester_.ExpectTotalCount(kHistogramLoad, 1); - histogram_tester_.ExpectTotalCount(kHistogramFirstLayout, 1); + histogram_tester_.ExpectTotalCount(internal::kHistogramDomContentLoaded, 1); + histogram_tester_.ExpectTotalCount(internal::kHistogramLoad, 1); + histogram_tester_.ExpectTotalCount(internal::kHistogramFirstLayout, 1); } - -} // namespace page_load_metrics
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_initialize.cc b/chrome/browser/page_load_metrics/page_load_metrics_initialize.cc index a66737d..d922118 100644 --- a/chrome/browser/page_load_metrics/page_load_metrics_initialize.cc +++ b/chrome/browser/page_load_metrics/page_load_metrics_initialize.cc
@@ -4,8 +4,8 @@ #include "chrome/browser/page_load_metrics/page_load_metrics_initialize.h" -#include "chrome/browser/browser_process.h" #include "chrome/browser/page_load_metrics/observers/aborts_page_load_metrics_observer.h" +#include "chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.h" #include "chrome/browser/page_load_metrics/observers/from_gws_page_load_metrics_observer.h" #include "chrome/browser/page_load_metrics/observers/google_captcha_observer.h" #include "chrome/browser/page_load_metrics/observers/stale_while_revalidate_metrics_observer.h" @@ -19,8 +19,7 @@ void InitializePageLoadMetricsForWebContents( content::WebContents* web_contents) { page_load_metrics::MetricsWebContentsObserver::CreateForWebContents( - web_contents, - make_scoped_ptr(new PageLoadMetricsEmbedder())); + web_contents, make_scoped_ptr(new PageLoadMetricsEmbedder())); } PageLoadMetricsEmbedder::~PageLoadMetricsEmbedder() {} @@ -28,22 +27,14 @@ void PageLoadMetricsEmbedder::RegisterObservers( page_load_metrics::PageLoadTracker* tracker) { // These classes are owned by the metrics. + tracker->AddObserver(make_scoped_ptr(new AbortsPageLoadMetricsObserver())); + tracker->AddObserver(make_scoped_ptr(new CorePageLoadMetricsObserver())); tracker->AddObserver(make_scoped_ptr(new FromGWSPageLoadMetricsObserver())); tracker->AddObserver( make_scoped_ptr(new google_captcha_observer::GoogleCaptchaObserver())); // TODO(ricea): Remove this in April 2016 or before. crbug.com/348877 tracker->AddObserver( make_scoped_ptr(new chrome::StaleWhileRevalidateMetricsObserver())); - tracker->AddObserver(make_scoped_ptr(new AbortsPageLoadMetricsObserver())); -} - -rappor::RapporService* -PageLoadMetricsEmbedder::GetRapporService() { - // During the browser process shutdown path, calling this getter can - // reinitialize multiple destroyed objects. This alters shutdown ordering. - if (g_browser_process->IsShuttingDown()) - return nullptr; - return g_browser_process->rappor_service(); } bool PageLoadMetricsEmbedder::IsPrerendering(
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_initialize.h b/chrome/browser/page_load_metrics/page_load_metrics_initialize.h index e3aaa79..4ffca06 100644 --- a/chrome/browser/page_load_metrics/page_load_metrics_initialize.h +++ b/chrome/browser/page_load_metrics/page_load_metrics_initialize.h
@@ -11,10 +11,6 @@ class WebContents; } -namespace rappor { -class RapporService; -} - namespace chrome { void InitializePageLoadMetricsForWebContents( @@ -25,7 +21,6 @@ public: // PageLoadMetricsEmbedderInterface: ~PageLoadMetricsEmbedder() override; - rappor::RapporService* GetRapporService() override; bool IsPrerendering(content::WebContents* web_contents) override; void RegisterObservers(page_load_metrics::PageLoadTracker* tracker) override; };
diff --git a/chrome/browser/plugins/plugin_power_saver_browsertest.cc b/chrome/browser/plugins/plugin_power_saver_browsertest.cc index 23a6509..234c0a9 100644 --- a/chrome/browser/plugins/plugin_power_saver_browsertest.cc +++ b/chrome/browser/plugins/plugin_power_saver_browsertest.cc
@@ -37,7 +37,6 @@ #include "ui/gfx/geometry/point.h" #include "ui/gfx/screen.h" #include "ui/gfx/switches.h" -#include "ui/gl/gl_switches.h" namespace { @@ -284,13 +283,9 @@ // Allows us to use the same reference image on HiDPI/Retina displays. command_line->AppendSwitchASCII(switches::kForceDeviceScaleFactor, "1"); -#if defined(OS_CHROMEOS) - // ChromeOS builds running on Linux use OSMesa by default. This is flaky - // with pixel tests, so force these environments to use hardware GPU. - command_line->AppendSwitch(switches::kUseGpuInTests); -#else - // Software rendering is faster and more reliable for these tests. - // Unfortunately ChromeOS does not support software rendering. +#if !defined(OS_CHROMEOS) + // These pixel tests are flaky on MSan bots with hardware rendering. + // However, ChromeOS does not support software compositing. command_line->AppendSwitch(switches::kDisableGpu); #endif }
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc index 80d4ae2..8847e775 100644 --- a/chrome/browser/prefs/browser_prefs.cc +++ b/chrome/browser/prefs/browser_prefs.cc
@@ -65,7 +65,7 @@ #include "chrome/browser/ui/webui/flags_ui.h" #include "chrome/browser/ui/webui/instant_ui.h" #include "chrome/browser/ui/webui/ntp/new_tab_ui.h" -#include "chrome/browser/ui/webui/plugins_ui.h" +#include "chrome/browser/ui/webui/plugins/plugins_ui.h" #include "chrome/browser/ui/webui/print_preview/sticky_settings.h" #include "chrome/common/features.h" #include "chrome/common/pref_names.h" @@ -306,14 +306,9 @@ BackgroundModeManager::RegisterPrefs(registry); #endif - // TODO(bshe): Use !defined(ANDROID_JAVA_UI) once - // codereview.chromium.org/1459793002 landed. -#if !defined(OS_ANDROID) || defined(USE_AURA) - RegisterBrowserPrefs(registry); -#endif - #if !defined(OS_ANDROID) ChromeTracingDelegate::RegisterPrefs(registry); + RegisterBrowserPrefs(registry); StartupBrowserCreator::RegisterLocalStatePrefs(registry); // The native GCM is used on Android instead. gcm::GCMChannelStatusSyncer::RegisterPrefs(registry); @@ -494,9 +489,7 @@ signin::RegisterProfilePrefs(registry); #endif - // TODO(bshe): Revisit this once it is more clear on what should we do with - // default apps on Aura Android. See crbug.com/564738 -#if (!defined(OS_ANDROID) || defined(USE_AURA)) && !defined(OS_CHROMEOS) +#if !defined(OS_ANDROID) && !defined(OS_CHROMEOS) default_apps::RegisterProfilePrefs(registry); #endif
diff --git a/chrome/browser/prefs/chrome_pref_service_factory.cc b/chrome/browser/prefs/chrome_pref_service_factory.cc index 7c73093..98c5fb13 100644 --- a/chrome/browser/prefs/chrome_pref_service_factory.cc +++ b/chrome/browser/prefs/chrome_pref_service_factory.cc
@@ -235,6 +235,12 @@ PrefHashFilter::TRACKING_STRATEGY_ATOMIC, PrefHashFilter::VALUE_PERSONAL }, + { + 24, prefs::kGoogleServicesLastAccountId, + PrefHashFilter::ENFORCE_ON_LOAD, + PrefHashFilter::TRACKING_STRATEGY_ATOMIC, + PrefHashFilter::VALUE_PERSONAL + }, // See note at top, new items added here also need to be added to // histograms.xml's TrackedPreference enum. };
diff --git a/chrome/browser/prefs/incognito_mode_prefs.cc b/chrome/browser/prefs/incognito_mode_prefs.cc index 929263a..3e2c0627 100644 --- a/chrome/browser/prefs/incognito_mode_prefs.cc +++ b/chrome/browser/prefs/incognito_mode_prefs.cc
@@ -213,11 +213,6 @@ bool IncognitoModePrefs::ArePlatformParentalControlsEnabled() { #if defined(OS_WIN) return PlatformParentalControlsValue::GetInstance()->is_enabled(); -#elif defined(OS_ANDROID) && defined(USE_AURA) - // TODO(bshe): Support parental controls for Aura Android. See - // crbug.com/564742 - NOTIMPLEMENTED(); - return false; #elif BUILDFLAG(ANDROID_JAVA_UI) return chrome::android::ChromeApplication::AreParentalControlsEnabled(); #else
diff --git a/chrome/browser/local_discovery/cloud_print_printer_list.cc b/chrome/browser/printing/cloud_print/cloud_print_printer_list.cc similarity index 72% rename from chrome/browser/local_discovery/cloud_print_printer_list.cc rename to chrome/browser/printing/cloud_print/cloud_print_printer_list.cc index a8de56a3..94683e4 100644 --- a/chrome/browser/local_discovery/cloud_print_printer_list.cc +++ b/chrome/browser/printing/cloud_print/cloud_print_printer_list.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/local_discovery/cloud_print_printer_list.h" +#include "chrome/browser/printing/cloud_print/cloud_print_printer_list.h" #include <utility> @@ -10,20 +10,27 @@ #include "chrome/common/cloud_print/cloud_print_constants.h" #include "components/cloud_devices/common/cloud_devices_urls.h" -namespace local_discovery { +namespace cloud_print { -CloudPrintPrinterList::CloudPrintPrinterList(CloudDeviceListDelegate* delegate) - : delegate_(delegate) { -} +CloudPrintPrinterList::Device::Device() {} + +CloudPrintPrinterList::Device::~Device() {} + +CloudPrintPrinterList::Delegate::Delegate() {} + +CloudPrintPrinterList::Delegate::~Delegate() {} + +CloudPrintPrinterList::CloudPrintPrinterList(Delegate* delegate) + : delegate_(delegate) {} CloudPrintPrinterList::~CloudPrintPrinterList() { } -void CloudPrintPrinterList::OnGCDAPIFlowError(GCDApiFlow::Status status) { +void CloudPrintPrinterList::OnGCDApiFlowError(GCDApiFlow::Status status) { delegate_->OnDeviceListUnavailable(); } -void CloudPrintPrinterList::OnGCDAPIFlowComplete( +void CloudPrintPrinterList::OnGCDApiFlowComplete( const base::DictionaryValue& value) { const base::ListValue* printers; @@ -32,12 +39,12 @@ return; } - std::vector<CloudDeviceListDelegate::Device> devices; + DeviceList devices; for (base::ListValue::const_iterator i = printers->begin(); i != printers->end(); i++) { base::DictionaryValue* printer; - CloudDeviceListDelegate::Device printer_details; + Device printer_details; if (!(*i)->GetAsDictionary(&printer)) continue; @@ -57,7 +64,7 @@ bool CloudPrintPrinterList::FillPrinterDetails( const base::DictionaryValue& printer_value, - CloudDeviceListDelegate::Device* printer_details) { + Device* printer_details) { if (!printer_value.GetString(cloud_print::kIdValue, &printer_details->id)) return false; @@ -70,9 +77,7 @@ printer_value.GetString(cloud_print::kPrinterDescValue, &printer_details->description); - printer_details->type = CloudDeviceListDelegate::kDeviceTypePrinter; - return true; } -} // namespace local_discovery +} // namespace cloud_print
diff --git a/chrome/browser/printing/cloud_print/cloud_print_printer_list.h b/chrome/browser/printing/cloud_print/cloud_print_printer_list.h new file mode 100644 index 0000000..abfadf5 --- /dev/null +++ b/chrome/browser/printing/cloud_print/cloud_print_printer_list.h
@@ -0,0 +1,55 @@ +// 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_PRINTING_CLOUD_PRINT_CLOUD_PRINT_PRINTER_LIST_H_ +#define CHROME_BROWSER_PRINTING_CLOUD_PRINT_CLOUD_PRINT_PRINTER_LIST_H_ + +#include <string> +#include <vector> + +#include "base/values.h" +#include "chrome/browser/printing/cloud_print/gcd_api_flow.h" + +namespace cloud_print { + +class CloudPrintPrinterList : public CloudPrintApiFlowRequest { + public: + struct Device { + Device(); + ~Device(); + + std::string id; + std::string display_name; + std::string description; + }; + typedef std::vector<Device> DeviceList; + + class Delegate { + public: + Delegate(); + virtual ~Delegate(); + + virtual void OnDeviceListReady(const DeviceList& devices) = 0; + virtual void OnDeviceListUnavailable() = 0; + }; + + explicit CloudPrintPrinterList(Delegate* delegate); + ~CloudPrintPrinterList() override; + + void OnGCDApiFlowError(GCDApiFlow::Status status) override; + + void OnGCDApiFlowComplete(const base::DictionaryValue& value) override; + + GURL GetURL() override; + + private: + bool FillPrinterDetails(const base::DictionaryValue& printer_value, + Device* printer_details); + + Delegate* delegate_; +}; + +} // namespace cloud_print + +#endif // CHROME_BROWSER_PRINTING_CLOUD_PRINT_CLOUD_PRINT_PRINTER_LIST_H_
diff --git a/chrome/browser/local_discovery/cloud_print_printer_list_unittest.cc b/chrome/browser/printing/cloud_print/cloud_print_printer_list_unittest.cc similarity index 81% rename from chrome/browser/local_discovery/cloud_print_printer_list_unittest.cc rename to chrome/browser/printing/cloud_print/cloud_print_printer_list_unittest.cc index 7a46b11..8431f19d 100644 --- a/chrome/browser/local_discovery/cloud_print_printer_list_unittest.cc +++ b/chrome/browser/printing/cloud_print/cloud_print_printer_list_unittest.cc
@@ -2,14 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/local_discovery/cloud_print_printer_list.h" +#include "chrome/browser/printing/cloud_print/cloud_print_printer_list.h" #include <stddef.h> #include <set> #include "base/json/json_reader.h" -#include "chrome/browser/local_discovery/cloud_device_list_delegate.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -18,7 +17,7 @@ using testing::StrictMock; using testing::_; -namespace local_discovery { +namespace cloud_print { namespace { @@ -31,9 +30,10 @@ " ]" "}"; -class MockDelegate : public CloudDeviceListDelegate { +class MockDelegate : public CloudPrintPrinterList::Delegate { public: - MOCK_METHOD1(OnDeviceListReady, void(const DeviceList&)); + MOCK_METHOD1(OnDeviceListReady, + void(const CloudPrintPrinterList::DeviceList&)); MOCK_METHOD0(OnDeviceListUnavailable, void()); }; @@ -50,14 +50,14 @@ TEST(CloudPrintPrinterListTest, Parsing) { StrictMock<MockDelegate> delegate; CloudPrintPrinterList device_list(&delegate); - CloudDeviceListDelegate::DeviceList devices; + CloudPrintPrinterList::DeviceList devices; EXPECT_CALL(delegate, OnDeviceListReady(_)).WillOnce(SaveArg<0>(&devices)); scoped_ptr<base::Value> value = base::JSONReader::Read(kSampleSuccessResponseOAuth); const base::DictionaryValue* dictionary = NULL; ASSERT_TRUE(value->GetAsDictionary(&dictionary)); - device_list.OnGCDAPIFlowComplete(*dictionary); + device_list.OnGCDApiFlowComplete(*dictionary); Mock::VerifyAndClear(&delegate); @@ -74,9 +74,8 @@ EXPECT_EQ("someID", devices[0].id); EXPECT_EQ("someDisplayName", devices[0].display_name); EXPECT_EQ("someDescription", devices[0].description); - EXPECT_EQ("printer", devices[0].type); } } // namespace -} // namespace local_discovery +} // namespace cloud_print
diff --git a/chrome/browser/local_discovery/device_description.cc b/chrome/browser/printing/cloud_print/device_description.cc similarity index 85% rename from chrome/browser/local_discovery/device_description.cc rename to chrome/browser/printing/cloud_print/device_description.cc index f3bd497..6726aea7 100644 --- a/chrome/browser/local_discovery/device_description.cc +++ b/chrome/browser/printing/cloud_print/device_description.cc
@@ -2,16 +2,16 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/local_discovery/device_description.h" +#include "chrome/browser/printing/cloud_print/device_description.h" #include <vector> #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" -#include "chrome/browser/local_discovery/privet_constants.h" +#include "chrome/browser/printing/cloud_print/privet_constants.h" #include "chrome/common/local_discovery/service_discovery_client.h" -namespace local_discovery { +namespace cloud_print { namespace { @@ -33,7 +33,7 @@ } DeviceDescription::DeviceDescription( - const ServiceDescription& service_description) { + const local_discovery::ServiceDescription& service_description) { address = service_description.address; const std::vector<std::string>& metadata = service_description.metadata; @@ -55,4 +55,4 @@ DeviceDescription::~DeviceDescription() { } -} // namespace local_discovery +} // namespace cloud_print
diff --git a/chrome/browser/local_discovery/device_description.h b/chrome/browser/printing/cloud_print/device_description.h similarity index 63% rename from chrome/browser/local_discovery/device_description.h rename to chrome/browser/printing/cloud_print/device_description.h index 34bc8372..87aa7a1 100644 --- a/chrome/browser/local_discovery/device_description.h +++ b/chrome/browser/printing/cloud_print/device_description.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 CHROME_BROWSER_LOCAL_DISCOVERY_DEVICE_DESCRIPTION_H_ -#define CHROME_BROWSER_LOCAL_DISCOVERY_DEVICE_DESCRIPTION_H_ +#ifndef CHROME_BROWSER_PRINTING_CLOUD_PRINT_DEVICE_DESCRIPTION_H_ +#define CHROME_BROWSER_PRINTING_CLOUD_PRINT_DEVICE_DESCRIPTION_H_ #include <string> @@ -11,12 +11,15 @@ #include "net/base/host_port_pair.h" namespace local_discovery { - struct ServiceDescription; +} + +namespace cloud_print { struct DeviceDescription { DeviceDescription(); - explicit DeviceDescription(const ServiceDescription& service_description); + explicit DeviceDescription( + const local_discovery::ServiceDescription& service_description); ~DeviceDescription(); bool IsValid() const; @@ -34,6 +37,6 @@ net::HostPortPair address; }; -} // namespace local_discovery +} // namespace cloud_print -#endif // CHROME_BROWSER_LOCAL_DISCOVERY_DEVICE_DESCRIPTION_H_ +#endif // CHROME_BROWSER_PRINTING_CLOUD_PRINT_DEVICE_DESCRIPTION_H_
diff --git a/chrome/browser/local_discovery/gcd_api_flow.cc b/chrome/browser/printing/cloud_print/gcd_api_flow.cc similarity index 87% rename from chrome/browser/local_discovery/gcd_api_flow.cc rename to chrome/browser/printing/cloud_print/gcd_api_flow.cc index ce1d0c9..e75c59d7 100644 --- a/chrome/browser/local_discovery/gcd_api_flow.cc +++ b/chrome/browser/printing/cloud_print/gcd_api_flow.cc
@@ -2,14 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/local_discovery/gcd_api_flow.h" +#include "chrome/browser/printing/cloud_print/gcd_api_flow.h" -#include "chrome/browser/local_discovery/gcd_api_flow_impl.h" -#include "chrome/browser/local_discovery/gcd_constants.h" +#include "chrome/browser/printing/cloud_print/gcd_api_flow_impl.h" +#include "chrome/browser/printing/cloud_print/gcd_constants.h" #include "chrome/common/cloud_print/cloud_print_constants.h" #include "components/cloud_devices/common/cloud_devices_urls.h" -namespace local_discovery { +namespace cloud_print { GCDApiFlow::Request::Request() { } @@ -69,4 +69,4 @@ return std::vector<std::string>(1, cloud_print::kChromeCloudPrintProxyHeader); } -} // namespace local_discovery +} // namespace cloud_print
diff --git a/chrome/browser/local_discovery/gcd_api_flow.h b/chrome/browser/printing/cloud_print/gcd_api_flow.h similarity index 86% rename from chrome/browser/local_discovery/gcd_api_flow.h rename to chrome/browser/printing/cloud_print/gcd_api_flow.h index b70109b..d57f722 100644 --- a/chrome/browser/local_discovery/gcd_api_flow.h +++ b/chrome/browser/printing/cloud_print/gcd_api_flow.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 CHROME_BROWSER_LOCAL_DISCOVERY_GCD_API_FLOW_H_ -#define CHROME_BROWSER_LOCAL_DISCOVERY_GCD_API_FLOW_H_ +#ifndef CHROME_BROWSER_PRINTING_CLOUD_PRINT_GCD_API_FLOW_H_ +#define CHROME_BROWSER_PRINTING_CLOUD_PRINT_GCD_API_FLOW_H_ #include <string> @@ -12,7 +12,7 @@ #include "net/url_request/url_fetcher.h" #include "net/url_request/url_request_context_getter.h" -namespace local_discovery { +namespace cloud_print { // API flow for communicating with cloud print and cloud devices. class GCDApiFlow { @@ -34,9 +34,9 @@ Request(); virtual ~Request(); - virtual void OnGCDAPIFlowError(Status status) = 0; + virtual void OnGCDApiFlowError(Status status) = 0; - virtual void OnGCDAPIFlowComplete(const base::DictionaryValue& value) = 0; + virtual void OnGCDApiFlowComplete(const base::DictionaryValue& value) = 0; virtual GURL GetURL() = 0; @@ -94,6 +94,6 @@ DISALLOW_COPY_AND_ASSIGN(CloudPrintApiFlowRequest); }; -} // namespace local_discovery +} // namespace cloud_print -#endif // CHROME_BROWSER_LOCAL_DISCOVERY_GCD_API_FLOW_H_ +#endif // CHROME_BROWSER_PRINTING_CLOUD_PRINT_GCD_API_FLOW_H_
diff --git a/chrome/browser/local_discovery/gcd_api_flow_impl.cc b/chrome/browser/printing/cloud_print/gcd_api_flow_impl.cc similarity index 88% rename from chrome/browser/local_discovery/gcd_api_flow_impl.cc rename to chrome/browser/printing/cloud_print/gcd_api_flow_impl.cc index ddad2013..a8043645 100644 --- a/chrome/browser/local_discovery/gcd_api_flow_impl.cc +++ b/chrome/browser/printing/cloud_print/gcd_api_flow_impl.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/local_discovery/gcd_api_flow_impl.h" +#include "chrome/browser/printing/cloud_print/gcd_api_flow_impl.h" #include <stddef.h> #include <utility> @@ -11,7 +11,7 @@ #include "base/strings/string_number_conversions.h" #include "base/strings/stringprintf.h" #include "base/values.h" -#include "chrome/browser/local_discovery/gcd_constants.h" +#include "chrome/browser/printing/cloud_print/gcd_constants.h" #include "chrome/common/cloud_print/cloud_print_constants.h" #include "components/cloud_devices/common/cloud_devices_urls.h" #include "google_apis/gaia/google_service_auth_error.h" @@ -20,7 +20,7 @@ #include "net/http/http_status_code.h" #include "net/url_request/url_request_status.h" -namespace local_discovery { +namespace cloud_print { GCDApiFlowImpl::GCDApiFlowImpl(net::URLRequestContextGetter* request_context, OAuth2TokenService* token_service, @@ -60,7 +60,7 @@ void GCDApiFlowImpl::OnGetTokenFailure( const OAuth2TokenService::Request* request, const GoogleServiceAuthError& error) { - request_->OnGCDAPIFlowError(ERROR_TOKEN); + request_->OnGCDApiFlowError(ERROR_TOKEN); } void GCDApiFlowImpl::CreateRequest(const GURL& url) { @@ -91,12 +91,12 @@ if (source->GetStatus().status() != net::URLRequestStatus::SUCCESS || !source->GetResponseAsString(&response_str)) { - request_->OnGCDAPIFlowError(ERROR_NETWORK); + request_->OnGCDApiFlowError(ERROR_NETWORK); return; } if (source->GetResponseCode() != net::HTTP_OK) { - request_->OnGCDAPIFlowError(ERROR_HTTP_CODE); + request_->OnGCDApiFlowError(ERROR_HTTP_CODE); return; } @@ -105,11 +105,11 @@ const base::DictionaryValue* dictionary_value = NULL; if (!value || !value->GetAsDictionary(&dictionary_value)) { - request_->OnGCDAPIFlowError(ERROR_MALFORMED_RESPONSE); + request_->OnGCDApiFlowError(ERROR_MALFORMED_RESPONSE); return; } - request_->OnGCDAPIFlowComplete(*dictionary_value); + request_->OnGCDApiFlowComplete(*dictionary_value); } -} // namespace local_discovery +} // namespace cloud_print
diff --git a/chrome/browser/local_discovery/gcd_api_flow_impl.h b/chrome/browser/printing/cloud_print/gcd_api_flow_impl.h similarity index 84% rename from chrome/browser/local_discovery/gcd_api_flow_impl.h rename to chrome/browser/printing/cloud_print/gcd_api_flow_impl.h index 8b72a24..ba4cc09 100644 --- a/chrome/browser/local_discovery/gcd_api_flow_impl.h +++ b/chrome/browser/printing/cloud_print/gcd_api_flow_impl.h
@@ -2,15 +2,15 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_LOCAL_DISCOVERY_GCD_API_FLOW_IMPL_H_ -#define CHROME_BROWSER_LOCAL_DISCOVERY_GCD_API_FLOW_IMPL_H_ +#ifndef CHROME_BROWSER_PRINTING_CLOUD_PRINT_GCD_API_FLOW_IMPL_H_ +#define CHROME_BROWSER_PRINTING_CLOUD_PRINT_GCD_API_FLOW_IMPL_H_ #include "base/macros.h" -#include "chrome/browser/local_discovery/gcd_api_flow.h" +#include "chrome/browser/printing/cloud_print/gcd_api_flow.h" #include "net/url_request/url_fetcher.h" #include "net/url_request/url_fetcher_delegate.h" -namespace local_discovery { +namespace cloud_print { namespace { const char kCloudPrintOAuthHeaderFormat[] = "Authorization: Bearer %s"; @@ -52,6 +52,6 @@ DISALLOW_COPY_AND_ASSIGN(GCDApiFlowImpl); }; -} // namespace local_discovery +} // namespace cloud_print -#endif // CHROME_BROWSER_LOCAL_DISCOVERY_GCD_API_FLOW_IMPL_H_ +#endif // CHROME_BROWSER_PRINTING_CLOUD_PRINT_GCD_API_FLOW_IMPL_H_
diff --git a/chrome/browser/local_discovery/gcd_api_flow_unittest.cc b/chrome/browser/printing/cloud_print/gcd_api_flow_unittest.cc similarity index 88% rename from chrome/browser/local_discovery/gcd_api_flow_unittest.cc rename to chrome/browser/printing/cloud_print/gcd_api_flow_unittest.cc index 4d11280..ac64fdcd 100644 --- a/chrome/browser/local_discovery/gcd_api_flow_unittest.cc +++ b/chrome/browser/printing/cloud_print/gcd_api_flow_unittest.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/local_discovery/gcd_api_flow.h" +#include "chrome/browser/printing/cloud_print/gcd_api_flow.h" #include <utility> @@ -10,7 +10,7 @@ #include "base/message_loop/message_loop.h" #include "base/thread_task_runner_handle.h" #include "base/values.h" -#include "chrome/browser/local_discovery/gcd_api_flow_impl.h" +#include "chrome/browser/printing/cloud_print/gcd_api_flow_impl.h" #include "content/public/test/test_browser_thread.h" #include "google_apis/gaia/fake_oauth2_token_service.h" #include "google_apis/gaia/google_service_auth_error.h" @@ -25,7 +25,7 @@ using testing::_; using testing::Return; -namespace local_discovery { +namespace cloud_print { namespace { @@ -37,8 +37,8 @@ class MockDelegate : public CloudPrintApiFlowRequest { public: - MOCK_METHOD1(OnGCDAPIFlowError, void(GCDApiFlow::Status)); - MOCK_METHOD1(OnGCDAPIFlowComplete, void(const base::DictionaryValue&)); + MOCK_METHOD1(OnGCDApiFlowError, void(GCDApiFlow::Status)); + MOCK_METHOD1(OnGCDApiFlowComplete, void(const base::DictionaryValue&)); MOCK_METHOD0(GetURL, GURL()); }; @@ -100,13 +100,13 @@ net::URLRequestStatus(net::URLRequestStatus::SUCCESS, net::OK)); fetcher->set_response_code(200); - EXPECT_CALL(*mock_delegate_, OnGCDAPIFlowComplete(_)); + EXPECT_CALL(*mock_delegate_, OnGCDApiFlowComplete(_)); fetcher->delegate()->OnURLFetchComplete(fetcher); } TEST_F(GCDApiFlowTest, BadToken) { - EXPECT_CALL(*mock_delegate_, OnGCDAPIFlowError(GCDApiFlow::ERROR_TOKEN)); + EXPECT_CALL(*mock_delegate_, OnGCDApiFlowError(GCDApiFlow::ERROR_TOKEN)); gcd_flow_->OnGetTokenFailure( NULL, GoogleServiceAuthError(GoogleServiceAuthError::USER_NOT_SIGNED_UP)); } @@ -124,11 +124,11 @@ fetcher->set_response_code(200); EXPECT_CALL(*mock_delegate_, - OnGCDAPIFlowError(GCDApiFlow::ERROR_MALFORMED_RESPONSE)); + OnGCDApiFlowError(GCDApiFlow::ERROR_MALFORMED_RESPONSE)); fetcher->delegate()->OnURLFetchComplete(fetcher); } } // namespace -} // namespace local_discovery +} // namespace cloud_print
diff --git a/chrome/browser/local_discovery/gcd_constants.cc b/chrome/browser/printing/cloud_print/gcd_constants.cc similarity index 70% rename from chrome/browser/local_discovery/gcd_constants.cc rename to chrome/browser/printing/cloud_print/gcd_constants.cc index 2ec7be9..7ed8371 100644 --- a/chrome/browser/local_discovery/gcd_constants.cc +++ b/chrome/browser/printing/cloud_print/gcd_constants.cc
@@ -2,12 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/local_discovery/gcd_constants.h" +#include "chrome/browser/printing/cloud_print/gcd_constants.h" -namespace local_discovery { +namespace cloud_print { const char kGCDKeyKind[] = "kind"; const char kGCDKeyDeviceId[] = "deviceId"; const char kGCDTypePrinter[] = "printer"; -} // namespace local_discovery +} // namespace cloud_print
diff --git a/chrome/browser/printing/cloud_print/gcd_constants.h b/chrome/browser/printing/cloud_print/gcd_constants.h new file mode 100644 index 0000000..9fc2b97c --- /dev/null +++ b/chrome/browser/printing/cloud_print/gcd_constants.h
@@ -0,0 +1,16 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_PRINTING_CLOUD_PRINT_GCD_CONSTANTS_H_ +#define CHROME_BROWSER_PRINTING_CLOUD_PRINT_GCD_CONSTANTS_H_ + +namespace cloud_print { + +extern const char kGCDKeyKind[]; +extern const char kGCDKeyDeviceId[]; +extern const char kGCDTypePrinter[]; + +} // namespace cloud_print + +#endif // CHROME_BROWSER_PRINTING_CLOUD_PRINT_GCD_CONSTANTS_H_
diff --git a/chrome/browser/local_discovery/privet_confirm_api_flow.cc b/chrome/browser/printing/cloud_print/privet_confirm_api_flow.cc similarity index 75% rename from chrome/browser/local_discovery/privet_confirm_api_flow.cc rename to chrome/browser/printing/cloud_print/privet_confirm_api_flow.cc index adc4e95..4abd9f0 100644 --- a/chrome/browser/local_discovery/privet_confirm_api_flow.cc +++ b/chrome/browser/printing/cloud_print/privet_confirm_api_flow.cc
@@ -2,18 +2,18 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/local_discovery/privet_confirm_api_flow.h" +#include "chrome/browser/printing/cloud_print/privet_confirm_api_flow.h" #include "base/strings/stringprintf.h" #include "base/values.h" -#include "chrome/browser/local_discovery/gcd_api_flow.h" -#include "chrome/browser/local_discovery/gcd_constants.h" -#include "chrome/browser/local_discovery/privet_constants.h" +#include "chrome/browser/printing/cloud_print/gcd_api_flow.h" +#include "chrome/browser/printing/cloud_print/gcd_constants.h" +#include "chrome/browser/printing/cloud_print/privet_constants.h" #include "chrome/common/cloud_print/cloud_print_constants.h" #include "components/cloud_devices/common/cloud_devices_urls.h" #include "net/base/url_util.h" -namespace local_discovery { +namespace cloud_print { namespace { @@ -33,11 +33,11 @@ PrivetConfirmApiCallFlow::~PrivetConfirmApiCallFlow() { } -void PrivetConfirmApiCallFlow::OnGCDAPIFlowError(GCDApiFlow::Status status) { +void PrivetConfirmApiCallFlow::OnGCDApiFlowError(GCDApiFlow::Status status) { callback_.Run(status); } -void PrivetConfirmApiCallFlow::OnGCDAPIFlowComplete( +void PrivetConfirmApiCallFlow::OnGCDApiFlowComplete( const base::DictionaryValue& value) { bool success = false; @@ -61,4 +61,4 @@ return GetConfirmFlowUrl(token_); } -} // namespace local_discovery +} // namespace cloud_print
diff --git a/chrome/browser/local_discovery/privet_confirm_api_flow.h b/chrome/browser/printing/cloud_print/privet_confirm_api_flow.h similarity index 65% rename from chrome/browser/local_discovery/privet_confirm_api_flow.h rename to chrome/browser/printing/cloud_print/privet_confirm_api_flow.h index 5107247..dc52e45 100644 --- a/chrome/browser/local_discovery/privet_confirm_api_flow.h +++ b/chrome/browser/printing/cloud_print/privet_confirm_api_flow.h
@@ -2,16 +2,16 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_LOCAL_DISCOVERY_PRIVET_CONFIRM_API_FLOW_H_ -#define CHROME_BROWSER_LOCAL_DISCOVERY_PRIVET_CONFIRM_API_FLOW_H_ +#ifndef CHROME_BROWSER_PRINTING_CLOUD_PRINT_PRIVET_CONFIRM_API_FLOW_H_ +#define CHROME_BROWSER_PRINTING_CLOUD_PRINT_PRIVET_CONFIRM_API_FLOW_H_ #include <string> #include "base/values.h" -#include "chrome/browser/local_discovery/gcd_api_flow.h" +#include "chrome/browser/printing/cloud_print/gcd_api_flow.h" #include "net/url_request/url_request_context_getter.h" -namespace local_discovery { +namespace cloud_print { // API call flow for server-side communication with CloudPrint for registration. class PrivetConfirmApiCallFlow : public CloudPrintApiFlowRequest { @@ -24,8 +24,8 @@ ~PrivetConfirmApiCallFlow() override; - void OnGCDAPIFlowError(GCDApiFlow::Status status) override; - void OnGCDAPIFlowComplete(const base::DictionaryValue& value) override; + void OnGCDApiFlowError(GCDApiFlow::Status status) override; + void OnGCDApiFlowComplete(const base::DictionaryValue& value) override; net::URLFetcher::RequestType GetRequestType() override; GURL GetURL() override; @@ -35,6 +35,6 @@ std::string token_; }; -} // namespace local_discovery +} // namespace cloud_print -#endif // CHROME_BROWSER_LOCAL_DISCOVERY_PRIVET_CONFIRM_API_FLOW_H_ +#endif // CHROME_BROWSER_PRINTING_CLOUD_PRINT_PRIVET_CONFIRM_API_FLOW_H_
diff --git a/chrome/browser/local_discovery/privet_confirm_api_flow_unittest.cc b/chrome/browser/printing/cloud_print/privet_confirm_api_flow_unittest.cc similarity index 88% rename from chrome/browser/local_discovery/privet_confirm_api_flow_unittest.cc rename to chrome/browser/printing/cloud_print/privet_confirm_api_flow_unittest.cc index 40f766ce1..4877c2c 100644 --- a/chrome/browser/local_discovery/privet_confirm_api_flow_unittest.cc +++ b/chrome/browser/printing/cloud_print/privet_confirm_api_flow_unittest.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/local_discovery/privet_confirm_api_flow.h" +#include "chrome/browser/printing/cloud_print/privet_confirm_api_flow.h" #include <set> @@ -13,7 +13,7 @@ using testing::StrictMock; using testing::_; -namespace local_discovery { +namespace cloud_print { namespace { @@ -51,15 +51,15 @@ base::JSONReader::Read(kSampleConfirmResponse); const base::DictionaryValue* dictionary = NULL; ASSERT_TRUE(value->GetAsDictionary(&dictionary)); - confirmation.OnGCDAPIFlowComplete(*dictionary); + confirmation.OnGCDApiFlowComplete(*dictionary); EXPECT_CALL(delegate, Callback(GCDApiFlow::ERROR_FROM_SERVER)).Times(1); value = base::JSONReader::Read(kFailedConfirmResponse); ASSERT_TRUE(value->GetAsDictionary(&dictionary)); - confirmation.OnGCDAPIFlowComplete(*dictionary); + confirmation.OnGCDApiFlowComplete(*dictionary); } } // namespace -} // namespace local_discovery +} // namespace cloud_print
diff --git a/chrome/browser/local_discovery/privet_constants.cc b/chrome/browser/printing/cloud_print/privet_constants.cc similarity index 95% rename from chrome/browser/local_discovery/privet_constants.cc rename to chrome/browser/printing/cloud_print/privet_constants.cc index a148901..d757912 100644 --- a/chrome/browser/local_discovery/privet_constants.cc +++ b/chrome/browser/printing/cloud_print/privet_constants.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 "chrome/browser/local_discovery/privet_constants.h" +#include "chrome/browser/printing/cloud_print/privet_constants.h" -namespace local_discovery { +namespace cloud_print { const char kPrivetKeyError[] = "error"; const char kPrivetInfoKeyToken[] = "x-privet-token"; @@ -61,4 +61,4 @@ const char kPrivetConnectionStatusConnecting[] = "connecting"; const char kPrivetConnectionStatusNotConfigured[] = "not-configured"; -} // namespace local_discovery +} // namespace cloud_print
diff --git a/chrome/browser/local_discovery/privet_constants.h b/chrome/browser/printing/cloud_print/privet_constants.h similarity index 90% rename from chrome/browser/local_discovery/privet_constants.h rename to chrome/browser/printing/cloud_print/privet_constants.h index 29c730f..306db99 100644 --- a/chrome/browser/local_discovery/privet_constants.h +++ b/chrome/browser/printing/cloud_print/privet_constants.h
@@ -2,10 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_LOCAL_DISCOVERY_PRIVET_CONSTANTS_H_ -#define CHROME_BROWSER_LOCAL_DISCOVERY_PRIVET_CONSTANTS_H_ +#ifndef CHROME_BROWSER_PRINTING_CLOUD_PRINT_PRIVET_CONSTANTS_H_ +#define CHROME_BROWSER_PRINTING_CLOUD_PRINT_PRIVET_CONSTANTS_H_ -namespace local_discovery { +namespace cloud_print { extern const char kPrivetKeyError[]; extern const char kPrivetInfoKeyToken[]; @@ -72,6 +72,6 @@ const int kAccountIndexUseOAuth2 = -1; -} // namespace local_discovery +} // namespace cloud_print -#endif // CHROME_BROWSER_LOCAL_DISCOVERY_PRIVET_CONSTANTS_H_ +#endif // CHROME_BROWSER_PRINTING_CLOUD_PRINT_PRIVET_CONSTANTS_H_
diff --git a/chrome/browser/local_discovery/privet_device_lister.cc b/chrome/browser/printing/cloud_print/privet_device_lister.cc similarity index 67% rename from chrome/browser/local_discovery/privet_device_lister.cc rename to chrome/browser/printing/cloud_print/privet_device_lister.cc index 3571337..9118eb6 100644 --- a/chrome/browser/local_discovery/privet_device_lister.cc +++ b/chrome/browser/printing/cloud_print/privet_device_lister.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 "chrome/browser/local_discovery/privet_device_lister.h" +#include "chrome/browser/printing/cloud_print/privet_device_lister.h" -namespace local_discovery { +namespace cloud_print { PrivetDeviceLister::PrivetDeviceLister() { } @@ -12,4 +12,4 @@ PrivetDeviceLister::~PrivetDeviceLister() { } -} // namespace local_discovery +} // namespace cloud_print
diff --git a/chrome/browser/local_discovery/privet_device_lister.h b/chrome/browser/printing/cloud_print/privet_device_lister.h similarity index 70% rename from chrome/browser/local_discovery/privet_device_lister.h rename to chrome/browser/printing/cloud_print/privet_device_lister.h index ad1bbd6..cbf28a6 100644 --- a/chrome/browser/local_discovery/privet_device_lister.h +++ b/chrome/browser/printing/cloud_print/privet_device_lister.h
@@ -2,16 +2,16 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_LOCAL_DISCOVERY_PRIVET_DEVICE_LISTER_H_ -#define CHROME_BROWSER_LOCAL_DISCOVERY_PRIVET_DEVICE_LISTER_H_ +#ifndef CHROME_BROWSER_PRINTING_CLOUD_PRINT_PRIVET_DEVICE_LISTER_H_ +#define CHROME_BROWSER_PRINTING_CLOUD_PRINT_PRIVET_DEVICE_LISTER_H_ #include <string> #include "base/callback.h" #include "base/time/time.h" -#include "chrome/browser/local_discovery/device_description.h" +#include "chrome/browser/printing/cloud_print/device_description.h" -namespace local_discovery { +namespace cloud_print { class PrivetDeviceLister { public: @@ -33,6 +33,6 @@ virtual void DiscoverNewDevices(bool force_update) = 0; }; -} // namespace local_discovery +} // namespace cloud_print -#endif // CHROME_BROWSER_LOCAL_DISCOVERY_PRIVET_DEVICE_LISTER_H_ +#endif // CHROME_BROWSER_PRINTING_CLOUD_PRINT_PRIVET_DEVICE_LISTER_H_
diff --git a/chrome/browser/local_discovery/privet_device_lister_impl.cc b/chrome/browser/printing/cloud_print/privet_device_lister_impl.cc similarity index 78% rename from chrome/browser/local_discovery/privet_device_lister_impl.cc rename to chrome/browser/printing/cloud_print/privet_device_lister_impl.cc index 0c3ee1a..f48bbb5 100644 --- a/chrome/browser/local_discovery/privet_device_lister_impl.cc +++ b/chrome/browser/printing/cloud_print/privet_device_lister_impl.cc
@@ -2,26 +2,26 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/local_discovery/privet_device_lister_impl.h" +#include "chrome/browser/printing/cloud_print/privet_device_lister_impl.h" #include <utility> #include <vector> #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" -#include "chrome/browser/local_discovery/privet_constants.h" +#include "chrome/browser/printing/cloud_print/privet_constants.h" -namespace local_discovery { +namespace cloud_print { PrivetDeviceListerImpl::PrivetDeviceListerImpl( - ServiceDiscoveryClient* service_discovery_client, + local_discovery::ServiceDiscoveryClient* service_discovery_client, PrivetDeviceLister::Delegate* delegate) : delegate_(delegate), device_lister_(this, service_discovery_client, kPrivetDefaultDeviceType) { } PrivetDeviceListerImpl::PrivetDeviceListerImpl( - ServiceDiscoveryClient* service_discovery_client, + local_discovery::ServiceDiscoveryClient* service_discovery_client, PrivetDeviceLister::Delegate* delegate, const std::string& subtype) : delegate_(delegate), @@ -43,7 +43,8 @@ } void PrivetDeviceListerImpl::OnDeviceChanged( - bool added, const ServiceDescription& service_description) { + bool added, + const local_discovery::ServiceDescription& service_description) { if (!delegate_) return; @@ -61,4 +62,4 @@ delegate_->DeviceCacheFlushed(); } -} // namespace local_discovery +} // namespace cloud_print
diff --git a/chrome/browser/printing/cloud_print/privet_device_lister_impl.h b/chrome/browser/printing/cloud_print/privet_device_lister_impl.h new file mode 100644 index 0000000..fa711ca --- /dev/null +++ b/chrome/browser/printing/cloud_print/privet_device_lister_impl.h
@@ -0,0 +1,51 @@ +// 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_PRINTING_CLOUD_PRINT_PRIVET_DEVICE_LISTER_IMPL_H_ +#define CHROME_BROWSER_PRINTING_CLOUD_PRINT_PRIVET_DEVICE_LISTER_IMPL_H_ + +#include <string> + +#include "chrome/browser/local_discovery/service_discovery_device_lister.h" +#include "chrome/browser/printing/cloud_print/privet_device_lister.h" + +namespace local_discovery { +class ServiceDiscoveryClient; +} + +namespace cloud_print { + +class PrivetDeviceListerImpl + : public PrivetDeviceLister, + public local_discovery::ServiceDiscoveryDeviceLister::Delegate { + public: + PrivetDeviceListerImpl( + local_discovery::ServiceDiscoveryClient* service_discovery_client, + PrivetDeviceLister::Delegate* delegate, + const std::string& subtype); + + PrivetDeviceListerImpl( + local_discovery::ServiceDiscoveryClient* service_discovery_client, + PrivetDeviceLister::Delegate* delegate); + + ~PrivetDeviceListerImpl() override; + + void Start() override; + void DiscoverNewDevices(bool force_update) override; + + protected: + void OnDeviceChanged( + bool added, + const local_discovery::ServiceDescription& service_description) override; + void OnDeviceRemoved(const std::string& service_name) override; + void OnDeviceCacheFlushed() override; + + private: + PrivetDeviceLister::Delegate* delegate_; + local_discovery::ServiceDiscoveryDeviceLister device_lister_; +}; + +} // namespace cloud_print + +#endif // CHROME_BROWSER_PRINTING_CLOUD_PRINT_PRIVET_DEVICE_LISTER_IMPL_H_
diff --git a/chrome/browser/local_discovery/privet_device_lister_unittest.cc b/chrome/browser/printing/cloud_print/privet_device_lister_unittest.cc similarity index 96% rename from chrome/browser/local_discovery/privet_device_lister_unittest.cc rename to chrome/browser/printing/cloud_print/privet_device_lister_unittest.cc index a165b718..0675ab3 100644 --- a/chrome/browser/local_discovery/privet_device_lister_unittest.cc +++ b/chrome/browser/printing/cloud_print/privet_device_lister_unittest.cc
@@ -3,14 +3,19 @@ // found in the LICENSE file. #include "base/bind.h" -#include "chrome/browser/local_discovery/privet_device_lister_impl.h" +#include "chrome/browser/printing/cloud_print/privet_device_lister_impl.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" -using testing::SaveArg; +using local_discovery::LocalDomainResolver; +using local_discovery::ServiceDescription; +using local_discovery::ServiceDiscoveryClient; +using local_discovery::ServiceResolver; +using local_discovery::ServiceWatcher; using testing::_; +using testing::SaveArg; -namespace local_discovery { +namespace cloud_print { namespace { @@ -309,4 +314,4 @@ } // namespace -} // namespace local_discovery +} // namespace cloud_print
diff --git a/chrome/browser/local_discovery/privet_http.cc b/chrome/browser/printing/cloud_print/privet_http.cc similarity index 72% rename from chrome/browser/local_discovery/privet_http.cc rename to chrome/browser/printing/cloud_print/privet_http.cc index 6b68f0d..d6897e84 100644 --- a/chrome/browser/local_discovery/privet_http.cc +++ b/chrome/browser/printing/cloud_print/privet_http.cc
@@ -2,13 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/local_discovery/privet_http.h" +#include "chrome/browser/printing/cloud_print/privet_http.h" #include <utility> -#include "chrome/browser/local_discovery/privet_http_impl.h" +#include "chrome/browser/printing/cloud_print/privet_http_impl.h" -namespace local_discovery { +namespace cloud_print { // static scoped_ptr<PrivetV1HTTPClient> PrivetV1HTTPClient::CreateDefault( @@ -19,4 +19,4 @@ new PrivetV1HTTPClientImpl(std::move(info_client))); } -} // namespace local_discovery +} // namespace cloud_print
diff --git a/chrome/browser/local_discovery/privet_http.h b/chrome/browser/printing/cloud_print/privet_http.h similarity index 94% rename from chrome/browser/local_discovery/privet_http.h rename to chrome/browser/printing/cloud_print/privet_http.h index a151543b..97952a2 100644 --- a/chrome/browser/local_discovery/privet_http.h +++ b/chrome/browser/printing/cloud_print/privet_http.h
@@ -2,13 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_LOCAL_DISCOVERY_PRIVET_HTTP_H_ -#define CHROME_BROWSER_LOCAL_DISCOVERY_PRIVET_HTTP_H_ +#ifndef CHROME_BROWSER_PRINTING_CLOUD_PRINT_PRIVET_HTTP_H_ +#define CHROME_BROWSER_PRINTING_CLOUD_PRINT_PRIVET_HTTP_H_ #include <string> #include "base/callback.h" -#include "chrome/browser/local_discovery/privet_url_fetcher.h" +#include "chrome/browser/printing/cloud_print/privet_url_fetcher.h" #include "net/base/host_port_pair.h" namespace base { @@ -21,11 +21,11 @@ namespace printing { class PdfRenderSettings; +class PWGRasterConverter; } -namespace local_discovery { +namespace cloud_print { -class PWGRasterConverter; class PrivetHTTPClient; // Represents a simple request that returns pure JSON. @@ -176,7 +176,7 @@ // For testing, inject an alternative PWG raster converter. virtual void SetPWGRasterConverterForTesting( - scoped_ptr<PWGRasterConverter> pwg_raster_converter) = 0; + scoped_ptr<printing::PWGRasterConverter> pwg_raster_converter) = 0; virtual PrivetHTTPClient* GetHTTPClient() = 0; }; @@ -210,5 +210,6 @@ PrivetLocalPrintOperation::Delegate* delegate) = 0; }; -} // namespace local_discovery -#endif // CHROME_BROWSER_LOCAL_DISCOVERY_PRIVET_HTTP_H_ +} // namespace cloud_print + +#endif // CHROME_BROWSER_PRINTING_CLOUD_PRINT_PRIVET_HTTP_H_
diff --git a/chrome/browser/local_discovery/privet_http_asynchronous_factory.cc b/chrome/browser/printing/cloud_print/privet_http_asynchronous_factory.cc similarity index 66% rename from chrome/browser/local_discovery/privet_http_asynchronous_factory.cc rename to chrome/browser/printing/cloud_print/privet_http_asynchronous_factory.cc index 3434344..e60b7ec 100644 --- a/chrome/browser/local_discovery/privet_http_asynchronous_factory.cc +++ b/chrome/browser/printing/cloud_print/privet_http_asynchronous_factory.cc
@@ -2,11 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/local_discovery/privet_http_asynchronous_factory.h" +#include "chrome/browser/printing/cloud_print/privet_http_asynchronous_factory.h" -#include "chrome/browser/local_discovery/privet_http_asynchronous_factory_impl.h" +#include "chrome/browser/printing/cloud_print/privet_http_asynchronous_factory_impl.h" -namespace local_discovery { +namespace cloud_print { // static scoped_ptr<PrivetHTTPAsynchronousFactory> @@ -16,4 +16,4 @@ new PrivetHTTPAsynchronousFactoryImpl(request_context)); } -} // namespace local_discovery +} // namespace cloud_print
diff --git a/chrome/browser/local_discovery/privet_http_asynchronous_factory.h b/chrome/browser/printing/cloud_print/privet_http_asynchronous_factory.h similarity index 78% rename from chrome/browser/local_discovery/privet_http_asynchronous_factory.h rename to chrome/browser/printing/cloud_print/privet_http_asynchronous_factory.h index cea62bf8..17a1bb7 100644 --- a/chrome/browser/local_discovery/privet_http_asynchronous_factory.h +++ b/chrome/browser/printing/cloud_print/privet_http_asynchronous_factory.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 CHROME_BROWSER_LOCAL_DISCOVERY_PRIVET_HTTP_ASYNCHRONOUS_FACTORY_H_ -#define CHROME_BROWSER_LOCAL_DISCOVERY_PRIVET_HTTP_ASYNCHRONOUS_FACTORY_H_ +#ifndef CHROME_BROWSER_PRINTING_CLOUD_PRINT_PRIVET_HTTP_ASYNCHRONOUS_FACTORY_H_ +#define CHROME_BROWSER_PRINTING_CLOUD_PRINT_PRIVET_HTTP_ASYNCHRONOUS_FACTORY_H_ #include <string> @@ -15,7 +15,7 @@ class URLRequestContextGetter; } -namespace local_discovery { +namespace cloud_print { class PrivetHTTPClient; @@ -46,6 +46,6 @@ const std::string& service_name) = 0; }; -} // namespace local_discovery +} // namespace cloud_print -#endif // CHROME_BROWSER_LOCAL_DISCOVERY_PRIVET_HTTP_ASYNCHRONOUS_FACTORY_H_ +#endif // CHROME_BROWSER_PRINTING_CLOUD_PRINT_PRIVET_HTTP_ASYNCHRONOUS_FACTORY_H_
diff --git a/chrome/browser/local_discovery/privet_http_asynchronous_factory_impl.cc b/chrome/browser/printing/cloud_print/privet_http_asynchronous_factory_impl.cc similarity index 88% rename from chrome/browser/local_discovery/privet_http_asynchronous_factory_impl.cc rename to chrome/browser/printing/cloud_print/privet_http_asynchronous_factory_impl.cc index 684b606..c18a11bc 100644 --- a/chrome/browser/local_discovery/privet_http_asynchronous_factory_impl.cc +++ b/chrome/browser/printing/cloud_print/privet_http_asynchronous_factory_impl.cc
@@ -2,12 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/local_discovery/privet_http_asynchronous_factory_impl.h" +#include "chrome/browser/printing/cloud_print/privet_http_asynchronous_factory_impl.h" #include "chrome/browser/local_discovery/endpoint_resolver.h" -#include "chrome/browser/local_discovery/privet_http_impl.h" +#include "chrome/browser/printing/cloud_print/privet_http_impl.h" -namespace local_discovery { +namespace cloud_print { PrivetHTTPAsynchronousFactoryImpl::PrivetHTTPAsynchronousFactoryImpl( net::URLRequestContextGetter* request_context) @@ -29,7 +29,7 @@ net::URLRequestContextGetter* request_context) : name_(service_name), request_context_(request_context), - endpoint_resolver_(new EndpointResolver()) {} + endpoint_resolver_(new local_discovery::EndpointResolver()) {} PrivetHTTPAsynchronousFactoryImpl::ResolutionImpl::~ResolutionImpl() { } @@ -65,4 +65,4 @@ new PrivetHTTPClientImpl(name_, new_address, request_context_.get()))); } -} // namespace local_discovery +} // namespace cloud_print
diff --git a/chrome/browser/local_discovery/privet_http_asynchronous_factory_impl.h b/chrome/browser/printing/cloud_print/privet_http_asynchronous_factory_impl.h similarity index 73% rename from chrome/browser/local_discovery/privet_http_asynchronous_factory_impl.h rename to chrome/browser/printing/cloud_print/privet_http_asynchronous_factory_impl.h index 8681a27f..ac2e8044 100644 --- a/chrome/browser/local_discovery/privet_http_asynchronous_factory_impl.h +++ b/chrome/browser/printing/cloud_print/privet_http_asynchronous_factory_impl.h
@@ -2,16 +2,18 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_LOCAL_DISCOVERY_PRIVET_HTTP_ASYNCHRONOUS_FACTORY_IMPL_H_ -#define CHROME_BROWSER_LOCAL_DISCOVERY_PRIVET_HTTP_ASYNCHRONOUS_FACTORY_IMPL_H_ +#ifndef CHROME_BROWSER_PRINTING_CLOUD_PRINT_PRIVET_HTTP_ASYNCHRONOUS_FACTORY_IMPL_H_ +#define CHROME_BROWSER_PRINTING_CLOUD_PRINT_PRIVET_HTTP_ASYNCHRONOUS_FACTORY_IMPL_H_ #include "base/macros.h" -#include "chrome/browser/local_discovery/privet_http.h" -#include "chrome/browser/local_discovery/privet_http_asynchronous_factory.h" +#include "chrome/browser/printing/cloud_print/privet_http.h" +#include "chrome/browser/printing/cloud_print/privet_http_asynchronous_factory.h" namespace local_discovery { - class EndpointResolver; +} + +namespace cloud_print { class PrivetHTTPAsynchronousFactoryImpl : public PrivetHTTPAsynchronousFactory { public: @@ -41,7 +43,7 @@ const net::IPEndPoint& endpoint); std::string name_; scoped_refptr<net::URLRequestContextGetter> request_context_; - scoped_ptr<EndpointResolver> endpoint_resolver_; + scoped_ptr<local_discovery::EndpointResolver> endpoint_resolver_; DISALLOW_COPY_AND_ASSIGN(ResolutionImpl); }; @@ -51,6 +53,6 @@ DISALLOW_COPY_AND_ASSIGN(PrivetHTTPAsynchronousFactoryImpl); }; -} // namespace local_discovery +} // namespace cloud_print -#endif // CHROME_BROWSER_LOCAL_DISCOVERY_PRIVET_HTTP_ASYNCHRONOUS_FACTORY_IMPL_H_ +#endif // CHROME_BROWSER_PRINTING_CLOUD_PRINT_PRIVET_HTTP_ASYNCHRONOUS_FACTORY_IMPL_H_
diff --git a/chrome/browser/local_discovery/privet_http_impl.cc b/chrome/browser/printing/cloud_print/privet_http_impl.cc similarity index 98% rename from chrome/browser/local_discovery/privet_http_impl.cc rename to chrome/browser/printing/cloud_print/privet_http_impl.cc index 1a72537..e70b18c1 100644 --- a/chrome/browser/local_discovery/privet_http_impl.cc +++ b/chrome/browser/printing/cloud_print/privet_http_impl.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/local_discovery/privet_http_impl.h" +#include "chrome/browser/printing/cloud_print/privet_http_impl.h" #include <stddef.h> #include <algorithm> @@ -17,7 +17,7 @@ #include "base/strings/utf_string_conversions.h" #include "base/thread_task_runner_handle.h" #include "chrome/browser/extensions/api/gcd_private/privet_v3_context_getter.h" -#include "chrome/browser/local_discovery/privet_constants.h" +#include "chrome/browser/printing/cloud_print/privet_constants.h" #include "chrome/common/chrome_content_client.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/cloud_print/cloud_print_constants.h" @@ -25,14 +25,14 @@ #include "url/gurl.h" #if defined(ENABLE_PRINT_PREVIEW) -#include "chrome/browser/local_discovery/pwg_raster_converter.h" +#include "chrome/browser/printing/pwg_raster_converter.h" #include "components/cloud_devices/common/printer_description.h" #include "printing/pdf_render_settings.h" #include "printing/pwg_raster_settings.h" #include "ui/gfx/text_elider.h" #endif // ENABLE_PRINT_PREVIEW -namespace local_discovery { +namespace cloud_print { namespace { @@ -545,6 +545,7 @@ } void PrivetLocalPrintOperationImpl::StartConvertToPWG() { + using printing::PWGRasterConverter; if (!pwg_raster_converter_) pwg_raster_converter_ = PWGRasterConverter::CreateDefault(); @@ -689,7 +690,7 @@ } void PrivetLocalPrintOperationImpl::SetPWGRasterConverterForTesting( - scoped_ptr<PWGRasterConverter> pwg_raster_converter) { + scoped_ptr<printing::PWGRasterConverter> pwg_raster_converter) { pwg_raster_converter_ = std::move(pwg_raster_converter); } #endif // ENABLE_PRINT_PREVIEW @@ -801,4 +802,4 @@ #endif // ENABLE_PRINT_PREVIEW } -} // namespace local_discovery +} // namespace cloud_print
diff --git a/chrome/browser/local_discovery/privet_http_impl.h b/chrome/browser/printing/cloud_print/privet_http_impl.h similarity index 95% rename from chrome/browser/local_discovery/privet_http_impl.h rename to chrome/browser/printing/cloud_print/privet_http_impl.h index 9a8eec9..149f33cb 100644 --- a/chrome/browser/local_discovery/privet_http_impl.h +++ b/chrome/browser/printing/cloud_print/privet_http_impl.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 CHROME_BROWSER_LOCAL_DISCOVERY_PRIVET_HTTP_IMPL_H_ -#define CHROME_BROWSER_LOCAL_DISCOVERY_PRIVET_HTTP_IMPL_H_ +#ifndef CHROME_BROWSER_PRINTING_CLOUD_PRINT_PRIVET_HTTP_IMPL_H_ +#define CHROME_BROWSER_PRINTING_CLOUD_PRINT_PRIVET_HTTP_IMPL_H_ #include <string> #include <vector> @@ -13,11 +13,11 @@ #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" -#include "chrome/browser/local_discovery/privet_http.h" +#include "chrome/browser/printing/cloud_print/privet_http.h" #include "components/cloud_devices/common/cloud_device_description.h" #include "ui/gfx/geometry/size.h" -namespace local_discovery { +namespace cloud_print { class PrivetHTTPClient; @@ -173,7 +173,7 @@ void SetPageSize(const gfx::Size& page_size) override; void SetPWGRasterConverterForTesting( - scoped_ptr<PWGRasterConverter> pwg_raster_converter) override; + scoped_ptr<printing::PWGRasterConverter> pwg_raster_converter) override; PrivetHTTPClient* GetHTTPClient() override; @@ -230,7 +230,7 @@ scoped_ptr<PrivetURLFetcher> url_fetcher_; scoped_ptr<PrivetJSONOperation> info_operation_; - scoped_ptr<PWGRasterConverter> pwg_raster_converter_; + scoped_ptr<printing::PWGRasterConverter> pwg_raster_converter_; base::WeakPtrFactory<PrivetLocalPrintOperationImpl> weak_factory_; }; @@ -294,5 +294,6 @@ DISALLOW_COPY_AND_ASSIGN(PrivetV1HTTPClientImpl); }; -} // namespace local_discovery -#endif // CHROME_BROWSER_LOCAL_DISCOVERY_PRIVET_HTTP_IMPL_H_ +} // namespace cloud_print + +#endif // CHROME_BROWSER_PRINTING_CLOUD_PRINT_PRIVET_HTTP_IMPL_H_
diff --git a/chrome/browser/local_discovery/privet_http_unittest.cc b/chrome/browser/printing/cloud_print/privet_http_unittest.cc similarity index 98% rename from chrome/browser/local_discovery/privet_http_unittest.cc rename to chrome/browser/printing/cloud_print/privet_http_unittest.cc index 84d0a70..711d34c 100644 --- a/chrome/browser/local_discovery/privet_http_unittest.cc +++ b/chrome/browser/printing/cloud_print/privet_http_unittest.cc
@@ -2,14 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/local_discovery/privet_http.h" +#include "chrome/browser/printing/cloud_print/privet_http.h" #include <utility> #include "base/json/json_reader.h" #include "base/json/json_writer.h" #include "base/run_loop.h" -#include "chrome/browser/local_discovery/privet_http_impl.h" +#include "chrome/browser/printing/cloud_print/privet_http_impl.h" #include "content/public/browser/browser_thread.h" #include "content/public/test/test_browser_thread_bundle.h" #include "net/test/embedded_test_server/embedded_test_server.h" @@ -19,11 +19,11 @@ #include "testing/gtest/include/gtest/gtest.h" #if defined(ENABLE_PRINT_PREVIEW) -#include "chrome/browser/local_discovery/pwg_raster_converter.h" +#include "chrome/browser/printing/pwg_raster_converter.h" #include "printing/pwg_raster_settings.h" #endif // ENABLE_PRINT_PREVIEW -namespace local_discovery { +namespace cloud_print { namespace { @@ -733,7 +733,7 @@ // converts strings to file paths based on them by appending "test.pdf", since // it's easier to test that way. Instead of using a mock, we simply check if the // request is uploading a file that is based on this pattern. -class FakePWGRasterConverter : public PWGRasterConverter { +class FakePWGRasterConverter : public printing::PWGRasterConverter { public: void Start(base::RefCountedMemory* data, const printing::PdfRenderSettings& conversion_settings, @@ -1118,4 +1118,4 @@ } // namespace -} // namespace local_discovery +} // namespace cloud_print
diff --git a/chrome/browser/local_discovery/privet_local_printer_lister.cc b/chrome/browser/printing/cloud_print/privet_local_printer_lister.cc similarity index 90% rename from chrome/browser/local_discovery/privet_local_printer_lister.cc rename to chrome/browser/printing/cloud_print/privet_local_printer_lister.cc index 5a5cd11dd..9a568bf 100644 --- a/chrome/browser/local_discovery/privet_local_printer_lister.cc +++ b/chrome/browser/printing/cloud_print/privet_local_printer_lister.cc
@@ -2,17 +2,17 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/local_discovery/privet_local_printer_lister.h" +#include "chrome/browser/printing/cloud_print/privet_local_printer_lister.h" #include <stddef.h> #include <string> #include <utility> -#include "chrome/browser/local_discovery/privet_constants.h" -#include "chrome/browser/local_discovery/privet_device_lister_impl.h" -#include "chrome/browser/local_discovery/privet_http_asynchronous_factory.h" +#include "chrome/browser/printing/cloud_print/privet_constants.h" +#include "chrome/browser/printing/cloud_print/privet_device_lister_impl.h" +#include "chrome/browser/printing/cloud_print/privet_http_asynchronous_factory.h" -namespace local_discovery { +namespace cloud_print { struct PrivetLocalPrinterLister::DeviceContext { DeviceContext() : has_local_printing(false) { @@ -27,7 +27,7 @@ }; PrivetLocalPrinterLister::PrivetLocalPrinterLister( - ServiceDiscoveryClient* service_discovery_client, + local_discovery::ServiceDiscoveryClient* service_discovery_client, net::URLRequestContextGetter* request_context, Delegate* delegate) : delegate_(delegate) { privet_lister_.reset( @@ -135,4 +135,4 @@ return &i->second->description; } -} // namespace local_discovery +} // namespace cloud_print
diff --git a/chrome/browser/local_discovery/privet_local_printer_lister.h b/chrome/browser/printing/cloud_print/privet_local_printer_lister.h similarity index 75% rename from chrome/browser/local_discovery/privet_local_printer_lister.h rename to chrome/browser/printing/cloud_print/privet_local_printer_lister.h index cdb99e90..c4910379 100644 --- a/chrome/browser/local_discovery/privet_local_printer_lister.h +++ b/chrome/browser/printing/cloud_print/privet_local_printer_lister.h
@@ -2,20 +2,20 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_LOCAL_DISCOVERY_PRIVET_LOCAL_PRINTER_LISTER_H_ -#define CHROME_BROWSER_LOCAL_DISCOVERY_PRIVET_LOCAL_PRINTER_LISTER_H_ +#ifndef CHROME_BROWSER_PRINTING_CLOUD_PRINT_PRIVET_LOCAL_PRINTER_LISTER_H_ +#define CHROME_BROWSER_PRINTING_CLOUD_PRINT_PRIVET_LOCAL_PRINTER_LISTER_H_ #include <map> #include <string> #include "base/memory/linked_ptr.h" -#include "chrome/browser/local_discovery/privet_device_lister.h" -#include "chrome/browser/local_discovery/privet_http.h" -#include "chrome/browser/local_discovery/privet_http_asynchronous_factory.h" +#include "chrome/browser/printing/cloud_print/privet_device_lister.h" +#include "chrome/browser/printing/cloud_print/privet_http.h" +#include "chrome/browser/printing/cloud_print/privet_http_asynchronous_factory.h" #include "chrome/common/local_discovery/service_discovery_client.h" #include "net/url_request/url_request_context.h" -namespace local_discovery { +namespace cloud_print { // This is an adapter to PrivetDeviceLister that finds printers and checks if // they support Privet local printing. @@ -32,9 +32,10 @@ virtual void LocalPrinterCacheFlushed() = 0; }; - PrivetLocalPrinterLister(ServiceDiscoveryClient* service_discovery_client, - net::URLRequestContextGetter* request_context, - Delegate* delegate); + PrivetLocalPrinterLister( + local_discovery::ServiceDiscoveryClient* service_discovery_client, + net::URLRequestContextGetter* request_context, + Delegate* delegate); virtual ~PrivetLocalPrinterLister(); void Start(); @@ -70,6 +71,6 @@ scoped_ptr<PrivetDeviceLister> privet_lister_; }; -} // namespace local_discovery +} // namespace cloud_print -#endif // CHROME_BROWSER_LOCAL_DISCOVERY_PRIVET_LOCAL_PRINTER_LISTER_H_ +#endif // CHROME_BROWSER_PRINTING_CLOUD_PRINT_PRIVET_LOCAL_PRINTER_LISTER_H_
diff --git a/chrome/browser/local_discovery/privet_local_printer_lister_unittest.cc b/chrome/browser/printing/cloud_print/privet_local_printer_lister_unittest.cc similarity index 97% rename from chrome/browser/local_discovery/privet_local_printer_lister_unittest.cc rename to chrome/browser/printing/cloud_print/privet_local_printer_lister_unittest.cc index 700335f..58e5c3c1 100644 --- a/chrome/browser/local_discovery/privet_local_printer_lister_unittest.cc +++ b/chrome/browser/printing/cloud_print/privet_local_printer_lister_unittest.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/local_discovery/privet_local_printer_lister.h" +#include "chrome/browser/printing/cloud_print/privet_local_printer_lister.h" #include <stddef.h> #include <stdint.h> @@ -16,11 +16,13 @@ #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +using local_discovery::TestServiceDiscoveryClient; + using testing::StrictMock; using testing::AtLeast; using testing::_; -namespace local_discovery { +namespace cloud_print { namespace { @@ -172,7 +174,7 @@ EXPECT_TRUE(SuccessfulResponseToURL( GURL(kPrivetInfoURL), std::string(kInfoIsLocalPrinter))); -}; +} TEST_F(PrivetLocalPrinterListerTest, NonPrinterAddedTest) { ExpectAnyPacket(); @@ -186,8 +188,8 @@ EXPECT_TRUE(SuccessfulResponseToURL( GURL(kPrivetInfoURL), std::string(kInfoIsNotLocalPrinter))); -}; +} } // namespace -} // namespace local_discovery +} // namespace cloud_print
diff --git a/chrome/browser/local_discovery/privet_notifications.cc b/chrome/browser/printing/cloud_print/privet_notifications.cc similarity index 95% rename from chrome/browser/local_discovery/privet_notifications.cc rename to chrome/browser/printing/cloud_print/privet_notifications.cc index 4913576..81c8120e 100644 --- a/chrome/browser/local_discovery/privet_notifications.cc +++ b/chrome/browser/printing/cloud_print/privet_notifications.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/local_discovery/privet_notifications.h" +#include "chrome/browser/printing/cloud_print/privet_notifications.h" #include <utility> @@ -16,11 +16,11 @@ #include "base/strings/utf_string_conversions.h" #include "base/thread_task_runner_handle.h" #include "chrome/browser/browser_process.h" -#include "chrome/browser/local_discovery/privet_device_lister_impl.h" -#include "chrome/browser/local_discovery/privet_http_asynchronous_factory.h" #include "chrome/browser/local_discovery/service_discovery_shared_client.h" #include "chrome/browser/notifications/notification.h" #include "chrome/browser/notifications/notification_ui_manager.h" +#include "chrome/browser/printing/cloud_print/privet_device_lister_impl.h" +#include "chrome/browser/printing/cloud_print/privet_http_asynchronous_factory.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/signin/signin_manager_factory.h" #include "chrome/browser/ui/browser.h" @@ -44,10 +44,10 @@ #include "ui/message_center/notifier_settings.h" #if defined(ENABLE_MDNS) -#include "chrome/browser/local_discovery/privet_traffic_detector.h" +#include "chrome/browser/printing/cloud_print/privet_traffic_detector.h" #endif -namespace local_discovery { +namespace cloud_print { namespace { @@ -270,7 +270,8 @@ bool updated = g_browser_process->notification_ui_manager()->Update( notification, profile_object); - if (!updated && added && !LocalDiscoveryUIHandler::GetHasVisible()) { + if (!updated && added && + !local_discovery::LocalDiscoveryUIHandler::GetHasVisible()) { ReportPrivetUmaEvent(PRIVET_NOTIFICATION_SHOWN); g_browser_process->notification_ui_manager()->Add(notification, profile_object); @@ -336,7 +337,8 @@ #if defined(ENABLE_MDNS) traffic_detector_ = NULL; #endif // ENABLE_MDNS - service_discovery_client_ = ServiceDiscoverySharedClient::GetInstance(); + service_discovery_client_ = + local_discovery::ServiceDiscoverySharedClient::GetInstance(); device_lister_.reset( new PrivetDeviceListerImpl(service_discovery_client_.get(), this)); device_lister_->Start(); @@ -390,4 +392,4 @@ false); } -} // namespace local_discovery +} // namespace cloud_print
diff --git a/chrome/browser/local_discovery/privet_notifications.h b/chrome/browser/printing/cloud_print/privet_notifications.h similarity index 89% rename from chrome/browser/local_discovery/privet_notifications.h rename to chrome/browser/printing/cloud_print/privet_notifications.h index 3faf92e..7e8e6503 100644 --- a/chrome/browser/local_discovery/privet_notifications.h +++ b/chrome/browser/printing/cloud_print/privet_notifications.h
@@ -2,27 +2,30 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_LOCAL_DISCOVERY_PRIVET_NOTIFICATIONS_H_ -#define CHROME_BROWSER_LOCAL_DISCOVERY_PRIVET_NOTIFICATIONS_H_ +#ifndef CHROME_BROWSER_PRINTING_CLOUD_PRINT_PRIVET_NOTIFICATIONS_H_ +#define CHROME_BROWSER_PRINTING_CLOUD_PRINT_PRIVET_NOTIFICATIONS_H_ #include <map> #include <string> #include "base/prefs/pref_member.h" -#include "chrome/browser/local_discovery/privet_device_lister.h" -#include "chrome/browser/local_discovery/privet_http.h" #include "chrome/browser/notifications/notification_delegate.h" +#include "chrome/browser/printing/cloud_print/privet_device_lister.h" +#include "chrome/browser/printing/cloud_print/privet_http.h" #include "components/keyed_service/core/keyed_service.h" class NotificationUIManager; namespace content { class BrowserContext; -} // namespace content +} namespace local_discovery { - class ServiceDiscoverySharedClient; +} + +namespace cloud_print { + class PrivetDeviceLister; class PrivetHTTPAsynchronousFactory; class PrivetHTTPResolution; @@ -119,7 +122,8 @@ content::BrowserContext* profile_; scoped_ptr<PrivetDeviceLister> device_lister_; - scoped_refptr<ServiceDiscoverySharedClient> service_discovery_client_; + scoped_refptr<local_discovery::ServiceDiscoverySharedClient> + service_discovery_client_; scoped_ptr<PrivetNotificationsListener> privet_notifications_listener_; BooleanPrefMember enable_privet_notification_member_; @@ -145,6 +149,6 @@ content::BrowserContext* profile_; }; -} // namespace local_discovery +} // namespace cloud_print -#endif // CHROME_BROWSER_LOCAL_DISCOVERY_PRIVET_NOTIFICATIONS_H_ +#endif // CHROME_BROWSER_PRINTING_CLOUD_PRINT_PRIVET_NOTIFICATIONS_H_
diff --git a/chrome/browser/local_discovery/privet_notifications_factory.cc b/chrome/browser/printing/cloud_print/privet_notifications_factory.cc similarity index 84% rename from chrome/browser/local_discovery/privet_notifications_factory.cc rename to chrome/browser/printing/cloud_print/privet_notifications_factory.cc index cb8432e..c051b56 100644 --- a/chrome/browser/local_discovery/privet_notifications_factory.cc +++ b/chrome/browser/printing/cloud_print/privet_notifications_factory.cc
@@ -2,13 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/local_discovery/privet_notifications_factory.h" +#include "chrome/browser/printing/cloud_print/privet_notifications_factory.h" #include "chrome/browser/browser_process.h" -#include "chrome/browser/local_discovery/privet_notifications.h" +#include "chrome/browser/printing/cloud_print/privet_notifications.h" #include "components/keyed_service/content/browser_context_dependency_manager.h" -namespace local_discovery { +namespace cloud_print { PrivetNotificationServiceFactory* PrivetNotificationServiceFactory::GetInstance() { @@ -38,4 +38,4 @@ return true; } -} // namespace local_discovery +} // namespace cloud_print
diff --git a/chrome/browser/local_discovery/privet_notifications_factory.h b/chrome/browser/printing/cloud_print/privet_notifications_factory.h similarity index 76% rename from chrome/browser/local_discovery/privet_notifications_factory.h rename to chrome/browser/printing/cloud_print/privet_notifications_factory.h index 3248db9..c22d5f3 100644 --- a/chrome/browser/local_discovery/privet_notifications_factory.h +++ b/chrome/browser/printing/cloud_print/privet_notifications_factory.h
@@ -2,13 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_LOCAL_DISCOVERY_PRIVET_NOTIFICATIONS_FACTORY_H_ -#define CHROME_BROWSER_LOCAL_DISCOVERY_PRIVET_NOTIFICATIONS_FACTORY_H_ +#ifndef CHROME_BROWSER_PRINTING_CLOUD_PRINT_PRIVET_NOTIFICATIONS_FACTORY_H_ +#define CHROME_BROWSER_PRINTING_CLOUD_PRINT_PRIVET_NOTIFICATIONS_FACTORY_H_ #include "base/memory/singleton.h" #include "components/keyed_service/content/browser_context_keyed_service_factory.h" -namespace local_discovery { +namespace cloud_print { class PrivetNotificationServiceFactory : public BrowserContextKeyedServiceFactory { @@ -29,6 +29,6 @@ bool ServiceIsNULLWhileTesting() const override; }; -} // namespace local_discovery +} // namespace cloud_print -#endif // CHROME_BROWSER_LOCAL_DISCOVERY_PRIVET_NOTIFICATIONS_FACTORY_H_ +#endif // CHROME_BROWSER_PRINTING_CLOUD_PRINT_PRIVET_NOTIFICATIONS_FACTORY_H_
diff --git a/chrome/browser/local_discovery/privet_notifications_unittest.cc b/chrome/browser/printing/cloud_print/privet_notifications_unittest.cc similarity index 95% rename from chrome/browser/local_discovery/privet_notifications_unittest.cc rename to chrome/browser/printing/cloud_print/privet_notifications_unittest.cc index b4c43700..422416c 100644 --- a/chrome/browser/local_discovery/privet_notifications_unittest.cc +++ b/chrome/browser/printing/cloud_print/privet_notifications_unittest.cc
@@ -3,9 +3,9 @@ // found in the LICENSE file. #include "base/thread_task_runner_handle.h" -#include "chrome/browser/local_discovery/privet_http_asynchronous_factory.h" -#include "chrome/browser/local_discovery/privet_http_impl.h" -#include "chrome/browser/local_discovery/privet_notifications.h" +#include "chrome/browser/printing/cloud_print/privet_http_asynchronous_factory.h" +#include "chrome/browser/printing/cloud_print/privet_http_impl.h" +#include "chrome/browser/printing/cloud_print/privet_notifications.h" #include "net/url_request/test_url_fetcher_factory.h" #include "net/url_request/url_request_test_util.h" #include "testing/gmock/include/gmock/gmock.h" @@ -16,7 +16,7 @@ using ::testing::_; using ::testing::SaveArg; -namespace local_discovery { +namespace cloud_print { namespace { @@ -214,4 +214,4 @@ } // namespace -} // namespace local_discovery +} // namespace cloud_print
diff --git a/chrome/browser/local_discovery/privet_traffic_detector.cc b/chrome/browser/printing/cloud_print/privet_traffic_detector.cc similarity index 97% rename from chrome/browser/local_discovery/privet_traffic_detector.cc rename to chrome/browser/printing/cloud_print/privet_traffic_detector.cc index 687b6f1..ec2c4445e 100644 --- a/chrome/browser/local_discovery/privet_traffic_detector.cc +++ b/chrome/browser/printing/cloud_print/privet_traffic_detector.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/local_discovery/privet_traffic_detector.h" +#include "chrome/browser/printing/cloud_print/privet_traffic_detector.h" #include <stddef.h> @@ -58,7 +58,7 @@ } // namespace -namespace local_discovery { +namespace cloud_print { PrivetTrafficDetector::PrivetTrafficDetector( net::AddressFamily address_family, @@ -200,4 +200,4 @@ return net::OK; } -} // namespace local_discovery +} // namespace cloud_print
diff --git a/chrome/browser/local_discovery/privet_traffic_detector.h b/chrome/browser/printing/cloud_print/privet_traffic_detector.h similarity index 88% rename from chrome/browser/local_discovery/privet_traffic_detector.h rename to chrome/browser/printing/cloud_print/privet_traffic_detector.h index 0ff0d13e..4577cbb 100644 --- a/chrome/browser/local_discovery/privet_traffic_detector.h +++ b/chrome/browser/printing/cloud_print/privet_traffic_detector.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 CHROME_BROWSER_LOCAL_DISCOVERY_PRIVET_TRAFFIC_DETECTOR_H_ -#define CHROME_BROWSER_LOCAL_DISCOVERY_PRIVET_TRAFFIC_DETECTOR_H_ +#ifndef CHROME_BROWSER_PRINTING_CLOUD_PRINT_PRIVET_TRAFFIC_DETECTOR_H_ +#define CHROME_BROWSER_PRINTING_CLOUD_PRINT_PRIVET_TRAFFIC_DETECTOR_H_ #include "base/callback.h" #include "base/cancelable_callback.h" @@ -18,7 +18,7 @@ class IOBufferWithSize; } -namespace local_discovery { +namespace cloud_print { // Detects mDns traffic that looks like "Privet" protocol. // Can produce false positives results, but main task of the class is to avoid @@ -67,6 +67,6 @@ DISALLOW_COPY_AND_ASSIGN(PrivetTrafficDetector); }; -} // namespace local_discovery +} // namespace cloud_print -#endif // CHROME_BROWSER_LOCAL_DISCOVERY_PRIVET_TRAFFIC_DETECTOR_H_ +#endif // CHROME_BROWSER_PRINTING_CLOUD_PRINT_PRIVET_TRAFFIC_DETECTOR_H_
diff --git a/chrome/browser/local_discovery/privet_url_fetcher.cc b/chrome/browser/printing/cloud_print/privet_url_fetcher.cc similarity index 98% rename from chrome/browser/local_discovery/privet_url_fetcher.cc rename to chrome/browser/printing/cloud_print/privet_url_fetcher.cc index f8cf391..3b370b5 100644 --- a/chrome/browser/local_discovery/privet_url_fetcher.cc +++ b/chrome/browser/printing/cloud_print/privet_url_fetcher.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/local_discovery/privet_url_fetcher.h" +#include "chrome/browser/printing/cloud_print/privet_url_fetcher.h" #include <stdint.h> @@ -19,14 +19,14 @@ #include "base/strings/stringprintf.h" #include "base/thread_task_runner_handle.h" #include "chrome/browser/browser_process.h" -#include "chrome/browser/local_discovery/privet_constants.h" +#include "chrome/browser/printing/cloud_print/privet_constants.h" #include "content/public/browser/browser_thread.h" #include "net/base/load_flags.h" #include "net/http/http_status_code.h" #include "net/url_request/url_request_context.h" #include "net/url_request/url_request_status.h" -namespace local_discovery { +namespace cloud_print { namespace { @@ -386,4 +386,4 @@ (error == kPrivetErrorPrinterBusy); } -} // namespace local_discovery +} // namespace cloud_print
diff --git a/chrome/browser/local_discovery/privet_url_fetcher.h b/chrome/browser/printing/cloud_print/privet_url_fetcher.h similarity index 94% rename from chrome/browser/local_discovery/privet_url_fetcher.h rename to chrome/browser/printing/cloud_print/privet_url_fetcher.h index f37722b8..9b797f4e 100644 --- a/chrome/browser/local_discovery/privet_url_fetcher.h +++ b/chrome/browser/printing/cloud_print/privet_url_fetcher.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 CHROME_BROWSER_LOCAL_DISCOVERY_PRIVET_URL_FETCHER_H_ -#define CHROME_BROWSER_LOCAL_DISCOVERY_PRIVET_URL_FETCHER_H_ +#ifndef CHROME_BROWSER_PRINTING_CLOUD_PRINT_PRIVET_URL_FETCHER_H_ +#define CHROME_BROWSER_PRINTING_CLOUD_PRINT_PRIVET_URL_FETCHER_H_ #include <string> @@ -20,7 +20,7 @@ class FilePath; } -namespace local_discovery { +namespace cloud_print { // Privet-specific URLFetcher adapter. Currently supports only the subset // of HTTP features required by Privet for GCP 1.5 @@ -142,6 +142,6 @@ DISALLOW_COPY_AND_ASSIGN(PrivetURLFetcher); }; -} // namespace local_discovery +} // namespace cloud_print -#endif // CHROME_BROWSER_LOCAL_DISCOVERY_PRIVET_URL_FETCHER_H_ +#endif // CHROME_BROWSER_PRINTING_CLOUD_PRINT_PRIVET_URL_FETCHER_H_
diff --git a/chrome/browser/local_discovery/privet_url_fetcher_unittest.cc b/chrome/browser/printing/cloud_print/privet_url_fetcher_unittest.cc similarity index 98% rename from chrome/browser/local_discovery/privet_url_fetcher_unittest.cc rename to chrome/browser/printing/cloud_print/privet_url_fetcher_unittest.cc index 3219f46c..75c38ac59 100644 --- a/chrome/browser/local_discovery/privet_url_fetcher_unittest.cc +++ b/chrome/browser/printing/cloud_print/privet_url_fetcher_unittest.cc
@@ -5,7 +5,7 @@ #include "base/location.h" #include "base/single_thread_task_runner.h" #include "base/thread_task_runner_handle.h" -#include "chrome/browser/local_discovery/privet_url_fetcher.h" +#include "chrome/browser/printing/cloud_print/privet_url_fetcher.h" #include "net/url_request/test_url_fetcher_factory.h" #include "net/url_request/url_request_test_util.h" #include "testing/gmock/include/gmock/gmock.h" @@ -13,7 +13,7 @@ using testing::StrictMock; -namespace local_discovery { +namespace cloud_print { namespace { @@ -299,4 +299,4 @@ } // namespace -} // namespace local_discovery +} // namespace cloud_print
diff --git a/chrome/browser/local_discovery/pwg_raster_converter.cc b/chrome/browser/printing/pwg_raster_converter.cc similarity index 96% rename from chrome/browser/local_discovery/pwg_raster_converter.cc rename to chrome/browser/printing/pwg_raster_converter.cc index 4c5b7a7a..44e47ad 100644 --- a/chrome/browser/local_discovery/pwg_raster_converter.cc +++ b/chrome/browser/printing/pwg_raster_converter.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/local_discovery/pwg_raster_converter.h" +#include "chrome/browser/printing/pwg_raster_converter.h" #include <algorithm> #include <utility> @@ -32,7 +32,7 @@ #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" -namespace local_discovery { +namespace printing { namespace { @@ -114,9 +114,9 @@ // simultaneously by several threads. class PwgUtilityProcessHostClient : public content::UtilityProcessHostClient { public: - explicit PwgUtilityProcessHostClient( - const printing::PdfRenderSettings& settings, - const printing::PwgRasterSettings& bitmap_settings); + PwgUtilityProcessHostClient( + const PdfRenderSettings& settings, + const PwgRasterSettings& bitmap_settings); void Convert(base::RefCountedMemory* data, const PWGRasterConverter::ResultCallback& callback); @@ -141,8 +141,8 @@ void OnFilesReadyOnUIThread(); scoped_ptr<FileHandlers, BrowserThread::DeleteOnFileThread> files_; - printing::PdfRenderSettings settings_; - printing::PwgRasterSettings bitmap_settings_; + PdfRenderSettings settings_; + PwgRasterSettings bitmap_settings_; PWGRasterConverter::ResultCallback callback_; base::WeakPtr<content::UtilityProcessHost> utility_process_host_; @@ -363,4 +363,4 @@ return result; } -} // namespace local_discovery +} // namespace printing
diff --git a/chrome/browser/local_discovery/pwg_raster_converter.h b/chrome/browser/printing/pwg_raster_converter.h similarity index 75% rename from chrome/browser/local_discovery/pwg_raster_converter.h rename to chrome/browser/printing/pwg_raster_converter.h index 90412bea..a101afcd 100644 --- a/chrome/browser/local_discovery/pwg_raster_converter.h +++ b/chrome/browser/printing/pwg_raster_converter.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 CHROME_BROWSER_LOCAL_DISCOVERY_PWG_RASTER_CONVERTER_H_ -#define CHROME_BROWSER_LOCAL_DISCOVERY_PWG_RASTER_CONVERTER_H_ +#ifndef CHROME_BROWSER_PRINTING_PWG_RASTER_CONVERTER_H_ +#define CHROME_BROWSER_PRINTING_PWG_RASTER_CONVERTER_H_ #include "base/callback.h" #include "base/memory/ref_counted_memory.h" @@ -21,11 +21,9 @@ } namespace printing { + class PdfRenderSettings; struct PwgRasterSettings; -} - -namespace local_discovery { class PWGRasterConverter { public: @@ -43,22 +41,22 @@ // Generates conversion settings to be used with converter from printer // capabilities and page size. // TODO(vitalybuka): Extract page size from pdf document data. - static printing::PdfRenderSettings GetConversionSettings( + static PdfRenderSettings GetConversionSettings( const cloud_devices::CloudDeviceDescription& printer_capabilities, const gfx::Size& page_size); // Generates pwg bitmap settings to be used with the converter from // device capabilites and printing ticket. - static printing::PwgRasterSettings GetBitmapSettings( + static PwgRasterSettings GetBitmapSettings( const cloud_devices::CloudDeviceDescription& printer_capabilities, const cloud_devices::CloudDeviceDescription& ticket); virtual void Start(base::RefCountedMemory* data, - const printing::PdfRenderSettings& conversion_settings, - const printing::PwgRasterSettings& bitmap_settings, + const PdfRenderSettings& conversion_settings, + const PwgRasterSettings& bitmap_settings, const ResultCallback& callback) = 0; }; -} // namespace local_discovery +} // namespace printing -#endif // CHROME_BROWSER_LOCAL_DISCOVERY_PWG_RASTER_CONVERTER_H_ +#endif // CHROME_BROWSER_PRINTING_PWG_RASTER_CONVERTER_H_
diff --git a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc index ab7e8b9..38177c7 100644 --- a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc +++ b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
@@ -141,7 +141,7 @@ #endif #if defined(ENABLE_SERVICE_DISCOVERY) -#include "chrome/browser/local_discovery/privet_notifications_factory.h" +#include "chrome/browser/printing/cloud_print/privet_notifications_factory.h" #endif namespace chrome { @@ -246,7 +246,7 @@ invalidation::ProfileInvalidationProviderFactory::GetInstance(); InstantServiceFactory::GetInstance(); #if defined(ENABLE_SERVICE_DISCOVERY) - local_discovery::PrivetNotificationServiceFactory::GetInstance(); + cloud_print::PrivetNotificationServiceFactory::GetInstance(); #endif #if defined(ENABLE_SUPERVISED_USERS) #if defined(OS_CHROMEOS)
diff --git a/chrome/browser/profiles/profile_impl.cc b/chrome/browser/profiles/profile_impl.cc index c077e60..56b8cb4 100644 --- a/chrome/browser/profiles/profile_impl.cc +++ b/chrome/browser/profiles/profile_impl.cc
@@ -88,7 +88,6 @@ #include "components/keyed_service/content/browser_context_dependency_manager.h" #include "components/metrics/metrics_service.h" #include "components/omnibox/browser/autocomplete_classifier.h" -#include "components/omnibox/browser/shortcuts_backend.h" #include "components/pref_registry/pref_registry_syncable.h" #include "components/proxy_config/pref_proxy_config_tracker.h" #include "components/signin/core/browser/signin_manager.h" @@ -919,7 +918,6 @@ content::URLRequestInterceptorScopedVector request_interceptors) { return io_data_.CreateMainRequestContextGetter( protocol_handlers, std::move(request_interceptors), - g_browser_process->local_state(), g_browser_process->io_thread()) .get(); }
diff --git a/chrome/browser/profiles/profile_impl.h b/chrome/browser/profiles/profile_impl.h index 33e581e..008fae1 100644 --- a/chrome/browser/profiles/profile_impl.h +++ b/chrome/browser/profiles/profile_impl.h
@@ -26,7 +26,6 @@ class NetPrefObserver; class PrefService; -class ShortcutsBackend; class TrackedPreferenceValidationDelegate; #if defined(OS_CHROMEOS) @@ -183,11 +182,6 @@ void EnsureSessionServiceCreated(); #endif - - void EnsureRequestContextCreated() { - GetRequestContext(); - } - // Updates the ProfileInfoCache with data from this profile. void UpdateProfileSupervisedUserIdCache(); void UpdateProfileNameCache(); @@ -242,7 +236,6 @@ #endif scoped_ptr<NetPrefObserver> net_pref_observer_; scoped_ptr<ssl_config::SSLConfigServiceManager> ssl_config_service_manager_; - scoped_refptr<ShortcutsBackend> shortcuts_backend_; // Exit type the last time the profile was opened. This is set only once from // prefs.
diff --git a/chrome/browser/profiles/profile_impl_io_data.cc b/chrome/browser/profiles/profile_impl_io_data.cc index 9667bdb..0cfe7e86 100644 --- a/chrome/browser/profiles/profile_impl_io_data.cc +++ b/chrome/browser/profiles/profile_impl_io_data.cc
@@ -5,6 +5,7 @@ #include "chrome/browser/profiles/profile_impl_io_data.h" #include <set> +#include <string> #include <utility> #include "base/bind.h" @@ -223,7 +224,6 @@ ProfileImplIOData::Handle::CreateMainRequestContextGetter( content::ProtocolHandlerMap* protocol_handlers, content::URLRequestInterceptorScopedVector request_interceptors, - PrefService* local_state, IOThread* io_thread) const { DCHECK_CURRENTLY_ON(BrowserThread::UI); LazyInitialize(); @@ -233,7 +233,6 @@ io_data_->predictor_ ->InitNetworkPredictor(profile_->GetPrefs(), - local_state, io_thread, main_request_context_getter_.get(), io_data_);
diff --git a/chrome/browser/profiles/profile_impl_io_data.h b/chrome/browser/profiles/profile_impl_io_data.h index b924856..4647499 100644 --- a/chrome/browser/profiles/profile_impl_io_data.h +++ b/chrome/browser/profiles/profile_impl_io_data.h
@@ -76,7 +76,6 @@ scoped_refptr<ChromeURLRequestContextGetter> CreateMainRequestContextGetter( content::ProtocolHandlerMap* protocol_handlers, content::URLRequestInterceptorScopedVector request_interceptors, - PrefService* local_state, IOThread* io_thread) const; scoped_refptr<ChromeURLRequestContextGetter> CreateIsolatedAppRequestContextGetter(
diff --git a/chrome/browser/profiles/profile_manager.cc b/chrome/browser/profiles/profile_manager.cc index aaa2a34e..0c9b9ef 100644 --- a/chrome/browser/profiles/profile_manager.cc +++ b/chrome/browser/profiles/profile_manager.cc
@@ -7,6 +7,7 @@ #include <stdint.h> #include <set> +#include <string> #include "base/bind.h" #include "base/command_line.h" @@ -41,6 +42,7 @@ #include "chrome/browser/profiles/profile_destroyer.h" #include "chrome/browser/profiles/profile_info_cache.h" #include "chrome/browser/profiles/profile_metrics.h" +#include "chrome/browser/profiles/profile_statistics.h" #include "chrome/browser/profiles/profiles_state.h" #include "chrome/browser/signin/account_fetcher_service_factory.h" #include "chrome/browser/signin/account_reconcilor_factory.h" @@ -1058,6 +1060,15 @@ chrome::NOTIFICATION_PROFILE_ADDED, content::Source<Profile>(profile), content::NotificationService::NoDetails()); + + // Record statistics to ProfileInfoCache if statistics were not recorded + // during shutdown, i.e. the last shutdown was a system shutdown or a crash. + if (!profile->IsGuestSession() && !profile->IsSystemProfile() && + !profile->IsNewProfile() && !go_off_the_record && + profile->GetLastSessionExitType() != Profile::EXIT_NORMAL) { + profiles::GatherProfileStatistics( + profile, profiles::ProfileStatisticsCallback(), nullptr); + } } void ProfileManager::DoFinalInitForServices(Profile* profile, @@ -1458,19 +1469,26 @@ void ProfileManager::BrowserListObserver::OnBrowserRemoved( Browser* browser) { Profile* profile = browser->profile(); + Profile* original_profile = profile->GetOriginalProfile(); + // Do nothing if the closed window is not the last window of the same profile. for (chrome::BrowserIterator it; !it.done(); it.Next()) { - if (it->profile()->GetOriginalProfile() == profile->GetOriginalProfile()) - // Not the last window for this profile. + if (it->profile()->GetOriginalProfile() == original_profile) return; } - // If the last browser of a profile that is scheduled for deletion is closed - // do that now. base::FilePath path = profile->GetPath(); - if (profile->GetPrefs()->GetBoolean(prefs::kForceEphemeralProfiles) && - !IsProfileMarkedForDeletion(path)) { + if (IsProfileMarkedForDeletion(path)) { + // Do nothing if the profile is already being deleted. + } else if (profile->GetPrefs()->GetBoolean(prefs::kForceEphemeralProfiles)) { + // Delete if the profile is an ephemeral profile. g_browser_process->profile_manager()->ScheduleProfileForDeletion( path, ProfileManager::CreateCallback()); + } else if (!profile->IsSystemProfile()) { + // Gather statistics and store into ProfileInfoCache. For incognito profile + // we gather the statistics of its parent profile instead, because a window + // of the parent profile was open. + profiles::GatherProfileStatistics( + original_profile, profiles::ProfileStatisticsCallback(), nullptr); } }
diff --git a/chrome/browser/profiles/profile_statistics.cc b/chrome/browser/profiles/profile_statistics.cc index df42397c..923cc38b 100644 --- a/chrome/browser/profiles/profile_statistics.cc +++ b/chrome/browser/profiles/profile_statistics.cc
@@ -4,6 +4,8 @@ #include "chrome/browser/profiles/profile_statistics.h" +#include <set> + #include "base/bind.h" #include "base/macros.h" #include "base/memory/ref_counted.h" @@ -19,13 +21,12 @@ #include "chrome/browser/profiles/profile_info_cache.h" #include "chrome/browser/profiles/profile_manager.h" #include "components/bookmarks/browser/bookmark_model.h" +#include "components/bookmarks/browser/bookmark_model_observer.h" #include "components/history/core/browser/history_service.h" #include "components/password_manager/core/browser/password_store.h" #include "components/password_manager/core/browser/password_store_consumer.h" #include "content/public/browser/browser_thread.h" -using content::BrowserThread; - namespace { struct ProfileStatValue { @@ -46,18 +47,19 @@ class ProfileStatisticsAggregator : public base::RefCountedThreadSafe<ProfileStatisticsAggregator> { - // This class collects statistical information about the profile and returns + // This class is used internally by GetProfileStatistics and + // StoreProfileStatisticsToCache. + // + // The class collects statistical information about the profile and returns // the information via a callback function. Currently bookmarks, history, // logins and preferences are counted. // // The class is RefCounted because this is needed for CancelableTaskTracker // to function properly. Once all tasks are run (or cancelled) the instance is // automatically destructed. - // - // The class is used internally by GetProfileStatistics function. public: - explicit ProfileStatisticsAggregator(Profile* profile, + ProfileStatisticsAggregator(Profile* profile, const profiles::ProfileStatisticsCallback& callback, base::CancelableTaskTracker* tracker); @@ -79,21 +81,57 @@ void StatisticsCallbackHistory(history::HistoryCountResult result); // Bookmark counting. - ProfileStatValue CountBookmarks() const; + void WaitOrCountBookmarks(); + void CountBookmarks(bookmarks::BookmarkModel* bookmark_model); - // Preference counting. - ProfileStatValue CountPrefs() const; + class BookmarkModelHelper + : public bookmarks::BookmarkModelObserver { + public: + explicit BookmarkModelHelper(ProfileStatisticsAggregator* parent) + : parent_(parent) {} - Profile* profile_; - profiles::ProfileCategoryStats profile_category_stats_; + void BookmarkModelLoaded(bookmarks::BookmarkModel* model, + bool ids_reassigned) + override { + // Remove observer before release, otherwise it may become a dangling + // reference. + model->RemoveObserver(this); + parent_->CountBookmarks(model); + parent_->Release(); + } - // Callback function to be called when results arrive. Will be called - // multiple times (once for each statistics). - const profiles::ProfileStatisticsCallback callback_; + void BookmarkNodeMoved(bookmarks::BookmarkModel* model, + const bookmarks::BookmarkNode* old_parent, + int old_index, + const bookmarks::BookmarkNode* new_parent, + int new_index) override {} - base::CancelableTaskTracker* tracker_; + void BookmarkNodeAdded(bookmarks::BookmarkModel* model, + const bookmarks::BookmarkNode* parent, + int index) override {} - // Password counting. + void BookmarkNodeRemoved(bookmarks::BookmarkModel* model, + const bookmarks::BookmarkNode* parent, + int old_index, const bookmarks::BookmarkNode* node, + const std::set<GURL>& no_longer_bookmarked) override {} + + void BookmarkNodeChanged(bookmarks::BookmarkModel* model, + const bookmarks::BookmarkNode* node) override {} + + void BookmarkNodeFaviconChanged(bookmarks::BookmarkModel* model, + const bookmarks::BookmarkNode* node) override {} + + void BookmarkNodeChildrenReordered(bookmarks::BookmarkModel* model, + const bookmarks::BookmarkNode* node) override {} + + void BookmarkAllUserNodesRemoved(bookmarks::BookmarkModel* model, + const std::set<GURL>& removed_urls) override {} + + private: + ProfileStatisticsAggregator* parent_ = nullptr; + }; + + // Password counting class PasswordStoreConsumerHelper : public password_manager::PasswordStoreConsumer { public: @@ -111,6 +149,24 @@ DISALLOW_COPY_AND_ASSIGN(PasswordStoreConsumerHelper); }; + + // Preference counting. + ProfileStatValue CountPrefs() const; + + Profile* profile_; + profiles::ProfileCategoryStats profile_category_stats_; + + // Callback function to be called when results arrive. Will be called + // multiple times (once for each statistics). + const profiles::ProfileStatisticsCallback callback_; + + base::CancelableTaskTracker* tracker_; + scoped_ptr<base::CancelableTaskTracker> default_tracker_; + + // Bookmark counting + scoped_ptr<BookmarkModelHelper> bookmark_model_helper_; + + // Password counting. PasswordStoreConsumerHelper password_store_consumer_helper_; DISALLOW_COPY_AND_ASSIGN(ProfileStatisticsAggregator); @@ -124,17 +180,22 @@ callback_(callback), tracker_(tracker), password_store_consumer_helper_(this) { + if (!tracker_) { + default_tracker_.reset(new base::CancelableTaskTracker); + tracker_ = default_tracker_.get(); + } Init(); } void ProfileStatisticsAggregator::Init() { + DCHECK(profile_); + // Initiate bookmark counting (async). Post to UI thread. - tracker_->PostTaskAndReplyWithResult( - BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI).get(), - FROM_HERE, - base::Bind(&ProfileStatisticsAggregator::CountBookmarks, this), - base::Bind(&ProfileStatisticsAggregator::StatisticsCallback, - this, profiles::kProfileStatisticsBookmarks)); + tracker_->PostTask( + content::BrowserThread::GetMessageLoopProxyForThread( + content::BrowserThread::UI).get(), + FROM_HERE, + base::Bind(&ProfileStatisticsAggregator::WaitOrCountBookmarks, this)); // Initiate history counting (async). history::HistoryService* history_service = @@ -164,11 +225,12 @@ // Initiate preference counting (async). Post to UI thread. tracker_->PostTaskAndReplyWithResult( - BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI).get(), - FROM_HERE, - base::Bind(&ProfileStatisticsAggregator::CountPrefs, this), - base::Bind(&ProfileStatisticsAggregator::StatisticsCallback, - this, profiles::kProfileStatisticsSettings)); + content::BrowserThread::GetMessageLoopProxyForThread( + content::BrowserThread::UI).get(), + FROM_HERE, + base::Bind(&ProfileStatisticsAggregator::CountPrefs, this), + base::Bind(&ProfileStatisticsAggregator::StatisticsCallback, + this, profiles::kProfileStatisticsSettings)); } void ProfileStatisticsAggregator::StatisticsCallback( @@ -178,7 +240,13 @@ datum.count = result.count; datum.success = result.success; profile_category_stats_.push_back(datum); - callback_.Run(profile_category_stats_); + if (!callback_.is_null()) + callback_.Run(profile_category_stats_); + + if (result.success) { + profiles::SetProfileStatisticsInCache(profile_->GetPath(), datum.category, + result.count); + } } void ProfileStatisticsAggregator::StatisticsCallbackSuccess( @@ -206,21 +274,30 @@ result_converted); } -ProfileStatValue ProfileStatisticsAggregator::CountBookmarks() const { +void ProfileStatisticsAggregator::CountBookmarks( + bookmarks::BookmarkModel* bookmark_model) { + int count = CountBookmarksFromNode(bookmark_model->bookmark_bar_node()) + + CountBookmarksFromNode(bookmark_model->other_node()) + + CountBookmarksFromNode(bookmark_model->mobile_node()); + + StatisticsCallbackSuccess(profiles::kProfileStatisticsBookmarks, count); +} + +void ProfileStatisticsAggregator::WaitOrCountBookmarks() { bookmarks::BookmarkModel* bookmark_model = BookmarkModelFactory::GetForProfileIfExists(profile_); - ProfileStatValue result; if (bookmark_model) { - result.count = CountBookmarksFromNode(bookmark_model->bookmark_bar_node()) + - CountBookmarksFromNode(bookmark_model->other_node()) + - CountBookmarksFromNode(bookmark_model->mobile_node()); - result.success = true; + if (bookmark_model->loaded()) { + CountBookmarks(bookmark_model); + } else { + AddRef(); + bookmark_model_helper_.reset(new BookmarkModelHelper(this)); + bookmark_model->AddObserver(bookmark_model_helper_.get()); + } } else { - result.count = 0; - result.success = false; + StatisticsCallbackFailure(profiles::kProfileStatisticsBookmarks); } - return result; } ProfileStatValue ProfileStatisticsAggregator::CountPrefs() const { @@ -262,9 +339,15 @@ const char kProfileStatisticsBookmarks[] = "Bookmarks"; const char kProfileStatisticsSettings[] = "Settings"; -void GetProfileStatistics(Profile* profile, - const ProfileStatisticsCallback& callback, - base::CancelableTaskTracker* tracker) { +void GatherProfileStatistics(Profile* profile, + const ProfileStatisticsCallback& callback, + base::CancelableTaskTracker* tracker) { + DCHECK(profile); + if (profile->IsOffTheRecord() || profile->IsSystemProfile()) { + NOTREACHED(); + return; + } + scoped_refptr<ProfileStatisticsAggregator> aggregator = new ProfileStatisticsAggregator(profile, callback, tracker); } @@ -309,8 +392,12 @@ if (!g_browser_process || !g_browser_process->local_state()) return; - ProfileInfoCache& profile_info_cache = - g_browser_process->profile_manager()->GetProfileInfoCache(); + // profile_manager() may return a null pointer. + ProfileManager* profile_manager = g_browser_process->profile_manager(); + if (!profile_manager) + return; + + ProfileInfoCache& profile_info_cache = profile_manager->GetProfileInfoCache(); ProfileAttributesEntry* entry = nullptr; if (!profile_info_cache.GetProfileAttributesWithPath(profile_path, &entry)) return;
diff --git a/chrome/browser/profiles/profile_statistics.h b/chrome/browser/profiles/profile_statistics.h index 61bba0d..c24393a 100644 --- a/chrome/browser/profiles/profile_statistics.h +++ b/chrome/browser/profiles/profile_statistics.h
@@ -39,13 +39,16 @@ // Profile Statistics ---------------------------------------------------------- -// This function collects statistical information about |profile| and returns -// the information via |callback|. Currently bookmarks, history, logins and -// preferences are counted. The callback function will probably be called more -// than once so binding parameters with bind::Passed() is prohibited. -void GetProfileStatistics(Profile* profile, - const ProfileStatisticsCallback& callback, - base::CancelableTaskTracker* tracker); +// This function collects statistical information about |profile|, also returns +// the information via |callback| if |callback| is not null. The statistical +// information is also copied to ProfileInfoCache. Currently bookmarks, history, +// logins and preferences are counted. The callback function will probably be +// called more than once, so binding parameters with bind::Passed() is +// prohibited. Most of the async tasks involved in this function can be +// cancelled if |tracker| is not null. +void GatherProfileStatistics(Profile* profile, + const ProfileStatisticsCallback& callback, + base::CancelableTaskTracker* tracker); // ProfileInfoCache ------------------------------------------------------------
diff --git a/chrome/browser/renderer_host/chrome_extension_message_filter.cc b/chrome/browser/renderer_host/chrome_extension_message_filter.cc index 921b225..59412fc 100644 --- a/chrome/browser/renderer_host/chrome_extension_message_filter.cc +++ b/chrome/browser/renderer_host/chrome_extension_message_filter.cc
@@ -86,10 +86,11 @@ IPC_MESSAGE_HANDLER(ExtensionHostMsg_OpenChannelToTab, OnOpenChannelToTab) IPC_MESSAGE_HANDLER(ExtensionHostMsg_OpenChannelToNativeApp, OnOpenChannelToNativeApp) + IPC_MESSAGE_HANDLER(ExtensionHostMsg_OpenMessagePort, OnOpenMessagePort) + IPC_MESSAGE_HANDLER(ExtensionHostMsg_CloseMessagePort, OnCloseMessagePort) IPC_MESSAGE_HANDLER(ExtensionHostMsg_PostMessage, OnPostMessage) IPC_MESSAGE_HANDLER_DELAY_REPLY(ExtensionHostMsg_GetMessageBundle, OnGetExtMessageBundle) - IPC_MESSAGE_HANDLER(ExtensionHostMsg_CloseChannel, OnExtensionCloseChannel) IPC_MESSAGE_HANDLER(ExtensionHostMsg_AddAPIActionToActivityLog, OnAddAPIActionToExtensionActivityLog); IPC_MESSAGE_HANDLER(ExtensionHostMsg_AddDOMActionToActivityLog, @@ -105,8 +106,9 @@ void ChromeExtensionMessageFilter::OverrideThreadForMessage( const IPC::Message& message, BrowserThread::ID* thread) { switch (message.type()) { + case ExtensionHostMsg_OpenMessagePort::ID: + case ExtensionHostMsg_CloseMessagePort::ID: case ExtensionHostMsg_PostMessage::ID: - case ExtensionHostMsg_CloseChannel::ID: case ExtensionHostMsg_AddAPIActionToActivityLog::ID: case ExtensionHostMsg_AddDOMActionToActivityLog::ID: case ExtensionHostMsg_AddEventToActivityLog::ID: @@ -194,6 +196,7 @@ } void ChromeExtensionMessageFilter::OnOpenChannelToTab( + int routing_id, const ExtensionMsg_TabTargetConnectionInfo& info, const std::string& extension_id, const std::string& channel_name, @@ -204,12 +207,13 @@ BrowserThread::PostTask( BrowserThread::UI, FROM_HERE, base::Bind(&ChromeExtensionMessageFilter::OpenChannelToTabOnUIThread, - this, render_process_id_, port2_id, info, extension_id, - channel_name)); + this, render_process_id_, routing_id, port2_id, info, + extension_id, channel_name)); } void ChromeExtensionMessageFilter::OpenChannelToTabOnUIThread( int source_process_id, + int source_routing_id, int receiver_port_id, const ExtensionMsg_TabTargetConnectionInfo& info, const std::string& extension_id, @@ -218,6 +222,7 @@ if (profile_) { extensions::MessageService::Get(profile_) ->OpenChannelToTab(source_process_id, + source_routing_id, receiver_port_id, info.tab_id, info.frame_id, @@ -226,6 +231,25 @@ } } +void ChromeExtensionMessageFilter::OnOpenMessagePort(int routing_id, + int port_id) { + if (!profile_) + return; + + extensions::MessageService::Get(profile_)->OpenPort( + port_id, render_process_id_, routing_id); +} + +void ChromeExtensionMessageFilter::OnCloseMessagePort(int routing_id, + int port_id, + bool force_close) { + if (!profile_) + return; + + extensions::MessageService::Get(profile_)->ClosePort( + port_id, render_process_id_, routing_id, force_close); +} + void ChromeExtensionMessageFilter::OnPostMessage( int port_id, const extensions::Message& message) { @@ -261,21 +285,6 @@ Send(reply_msg); } -void ChromeExtensionMessageFilter::OnExtensionCloseChannel( - int port_id, - const std::string& error_message) { - if (!profile_) - return; - - if (!content::RenderProcessHost::FromID(render_process_id_)) - return; // To guard against crash in browser_tests shutdown. - - extensions::MessageService* message_service = - extensions::MessageService::Get(profile_); - if (message_service) - message_service->CloseChannel(port_id, error_message); -} - void ChromeExtensionMessageFilter::OnAddAPIActionToExtensionActivityLog( const std::string& extension_id, const ExtensionHostMsg_APIActionOrEvent_Params& params) {
diff --git a/chrome/browser/renderer_host/chrome_extension_message_filter.h b/chrome/browser/renderer_host/chrome_extension_message_filter.h index 04762a9..50b958e 100644 --- a/chrome/browser/renderer_host/chrome_extension_message_filter.h +++ b/chrome/browser/renderer_host/chrome_extension_message_filter.h
@@ -72,23 +72,26 @@ int receiver_port_id, const std::string& source_extension_id, const std::string& native_app_name); - void OnOpenChannelToTab(const ExtensionMsg_TabTargetConnectionInfo& info, + void OnOpenChannelToTab(int routing_id, + const ExtensionMsg_TabTargetConnectionInfo& info, const std::string& extension_id, const std::string& channel_name, int* port_id); void OpenChannelToTabOnUIThread( int source_process_id, + int source_routing_id, int receiver_port_id, const ExtensionMsg_TabTargetConnectionInfo& info, const std::string& extension_id, const std::string& channel_name); + void OnOpenMessagePort(int routing_id, int port_id); + void OnCloseMessagePort(int routing_id, int port_id, bool force_close); void OnPostMessage(int port_id, const extensions::Message& message); void OnGetExtMessageBundle(const std::string& extension_id, IPC::Message* reply_msg); void OnGetExtMessageBundleOnBlockingPool( const std::string& extension_id, IPC::Message* reply_msg); - void OnExtensionCloseChannel(int port_id, const std::string& error_message); void OnAddAPIActionToExtensionActivityLog( const std::string& extension_id, const ExtensionHostMsg_APIActionOrEvent_Params& params);
diff --git a/chrome/browser/resources/media_router/elements/media_router_container/media_router_container.js b/chrome/browser/resources/media_router/elements/media_router_container/media_router_container.js index c9858792..9de6201 100644 --- a/chrome/browser/resources/media_router/elements/media_router_container/media_router_container.js +++ b/chrome/browser/resources/media_router/elements/media_router_container/media_router_container.js
@@ -153,6 +153,15 @@ }, /** + * Whether the user's mouse is positioned over the dialog. + * @private {boolean} + */ + mouseIsPositionedOverDialog_: { + type: Boolean, + value: false, + }, + + /** * The list of current routes. * @type {!Array<!media_router.Route>} */ @@ -247,16 +256,6 @@ }, /** - * List of active timer IDs. Used to retrieve active timer IDs when - * clearing timers. - * @private {!Array<number>} - */ - timerIdList_: { - type: Array, - value: [], - }, - - /** * Whether the user has explicitly selected a cast mode. * @private {boolean} */ @@ -268,7 +267,8 @@ listeners: { 'arrow-drop-click': 'toggleCastModeHidden_', - 'tap': 'onTap_', + 'mouseleave': 'onMouseLeave_', + 'mouseenter': 'onMouseEnter_', }, ready: function() { @@ -452,7 +452,8 @@ * @private */ computeIssueBannerShown_: function(view, issue) { - return !!issue && view != media_router.MediaRouterView.CAST_MODE_LIST; + return !!issue && (view == media_router.MediaRouterView.SINK_LIST || + view == media_router.MediaRouterView.ISSUE); }, /** @@ -723,6 +724,29 @@ this.startTapTimer_(); }, + /** + * Called when a mouseleave event is triggered. + * + * @private + */ + onMouseLeave_: function() { + this.mouseIsPositionedOverDialog_ = false; + }, + + /** + * Called when a mouseenter event is triggered. + * + * @private + */ + onMouseEnter_: function() { + this.mouseIsPositionedOverDialog_ = true; + }, + + /** + * Handles timeout of previous create route attempt. Clearing + * |currentLaunchingSinkId_| hides the spinner indicating there is a route + * creation in progress and show the device icon instead. + */ onNotifyRouteCreationTimeout: function() { this.currentLaunchingSinkId_ = ''; }, @@ -739,24 +763,6 @@ }, /** - * Called when a tap event is triggered. Clears any active timers. onTap_ - * is called before a new timer is started for taps that trigger a new active - * timer. - * - * @private - */ - onTap_: function(e) { - if (this.timerIdList_.length == 0) - return; - - this.timerIdList_.forEach(function(id) { - clearTimeout(id); - }, this); - - this.timerIdList_ = []; - }, - - /** * Called when |routeList| is updated. Rebuilds |routeMap_| and * |sinkToRouteMap_|. * @@ -908,17 +914,16 @@ }, /** - * Starts a timer which fires a close-dialog event if the timer has not been - * cleared within three seconds. + * Starts a timer which fires a close-dialog event if the user's mouse is + * not positioned over the dialog after three seconds. * * @private */ startTapTimer_: function() { var id = setTimeout(function() { - this.fire('close-dialog'); + if (!this.mouseIsPositionedOverDialog_) + this.fire('close-dialog'); }.bind(this), 3000 /* 3 seconds */); - - this.timerIdList_.push(id); }, /**
diff --git a/chrome/browser/resources/media_router/media_router_data.js b/chrome/browser/resources/media_router/media_router_data.js index 794b171ef..1f70797 100644 --- a/chrome/browser/resources/media_router/media_router_data.js +++ b/chrome/browser/resources/media_router/media_router_data.js
@@ -38,7 +38,7 @@ /** * This corresponds to the C++ MediaSink IconType. - * @enum {mumber} + * @enum {number} */ var SinkIconType = { CAST: 0,
diff --git a/chrome/browser/resources/options/autofill_edit_address_overlay.js b/chrome/browser/resources/options/autofill_edit_address_overlay.js index 85675d5..43049212 100644 --- a/chrome/browser/resources/options/autofill_edit_address_overlay.js +++ b/chrome/browser/resources/options/autofill_edit_address_overlay.js
@@ -66,8 +66,8 @@ this.guid_ = ''; this.populateCountryList_(); - this.rebuildInputFields_( - loadTimeData.getValue('autofillDefaultCountryComponents')); + this.rebuildInputFields_(/** @type {Array<Array<Object>>} */( + loadTimeData.getValue('autofillDefaultCountryComponents'))); this.languageCode_ = loadTimeData.getString('autofillDefaultCountryLanguageCode'); this.connectInputEvents_();
diff --git a/chrome/browser/resources/options/browser_options.js b/chrome/browser/resources/options/browser_options.js index c9fa7ba..bb646e6 100644 --- a/chrome/browser/resources/options/browser_options.js +++ b/chrome/browser/resources/options/browser_options.js
@@ -79,24 +79,21 @@ /** * Keeps track of whether the user is signed in or not. - * @type {boolean} - * @private + * @private {boolean} */ signedIn_: false, /** * Indicates whether signing out is allowed or whether a complete profile * wipe is required to remove the current enterprise account. - * @type {boolean} - * @private + * @private {boolean} */ signoutAllowed_: true, /** * Keeps track of whether |onShowHomeButtonChanged_| has been called. See * |onShowHomeButtonChanged_|. - * @type {boolean} - * @private + * @private {boolean} */ onShowHomeButtonChangedCalled_: false, @@ -104,8 +101,7 @@ * Track if page initialization is complete. All C++ UI handlers have the * chance to manipulate page content within their InitializePage methods. * This flag is set to true after all initializers have been called. - * @type {boolean} - * @private + * @private {boolean} */ initializationComplete_: false, @@ -192,7 +188,8 @@ } // Sync (Sign in) section. - this.updateSyncState_(loadTimeData.getValue('syncData')); + this.updateSyncState_(/** @type {options.SyncStatus} */( + loadTimeData.getValue('syncData'))); $('start-stop-sync').onclick = function(event) { if (self.signedIn_) { @@ -351,7 +348,8 @@ profilesList.autoExpands = true; // The profiles info data in |loadTimeData| might be stale. - this.setProfilesInfo_(loadTimeData.getValue('profilesInfo')); + this.setProfilesInfo_(/** @type {!Array<!options.Profile>} */( + loadTimeData.getValue('profilesInfo'))); chrome.send('requestProfilesInfo'); profilesList.addEventListener('change', @@ -1514,7 +1512,7 @@ /** * Adds all |profiles| to the list. - * @param {Array<!options.Profile>} profiles An array of profile info + * @param {!Array<!options.Profile>} profiles An array of profile info * objects. * @private */ @@ -2296,7 +2294,7 @@ } button.hidden = false; - var strId; + /** @type {string} */ var strId; switch (status) { case ConsumerManagementOverlay.Status.STATUS_UNENROLLED: strId = 'consumerManagementEnrollButton';
diff --git a/chrome/browser/resources/options/chromeos/bluetooth_pair_device_overlay.js b/chrome/browser/resources/options/chromeos/bluetooth_pair_device_overlay.js index 65f07c60..11cc7ae 100644 --- a/chrome/browser/resources/options/chromeos/bluetooth_pair_device_overlay.js +++ b/chrome/browser/resources/options/chromeos/bluetooth_pair_device_overlay.js
@@ -271,7 +271,9 @@ this.clearElement_(instructionsEl); this.dismissible_ = opt_notDismissible !== true; var message = loadTimeData.getString(this.event_.pairing); - message = message.replace('%1', this.event_.device.name); + assert(typeof this.event_.device.name == 'string'); + message = message.replace( + '%1', /** @type {string} */(this.event_.device.name)); instructionsEl.textContent = message; // Update visibility of dialog elements.
diff --git a/chrome/browser/resources/options/language_add_language_overlay.js b/chrome/browser/resources/options/language_add_language_overlay.js index 9197ecdb..9ea8904 100644 --- a/chrome/browser/resources/options/language_add_language_overlay.js +++ b/chrome/browser/resources/options/language_add_language_overlay.js
@@ -5,6 +5,16 @@ /////////////////////////////////////////////////////////////////////////////// // AddLanguageOverlay class: +/** + * @typedef {{ + * code: string, + * displayName: string, + * textDirection: string, + * nativeDisplayName: string + * }} + */ +options.LanguageData; + cr.define('options', function() { /** @const */ var Page = cr.ui.pageManager.Page; /** @const */ var PageManager = cr.ui.pageManager.PageManager; @@ -37,12 +47,13 @@ // Create the language list with which users can add a language. var addLanguageList = $('add-language-overlay-language-list'); + /** - * @type {Array<{code: string, displayName: string, - * textDirection: string, nativeDisplayName: string}>} + * @type {!Array<!options.LanguageData>} * @see chrome/browser/ui/webui/options/language_options_handler.cc */ - var languageListData = loadTimeData.getValue('languageList'); + var languageListData = /** @type {!Array<!options.LanguageData>} */( + loadTimeData.getValue('languageList')); for (var i = 0; i < languageListData.length; i++) { var language = languageListData[i]; var displayText = language.displayName;
diff --git a/chrome/browser/resources/options/language_options.js b/chrome/browser/resources/options/language_options.js index 0975c93..e9b6cb7 100644 --- a/chrome/browser/resources/options/language_options.js +++ b/chrome/browser/resources/options/language_options.js
@@ -200,8 +200,8 @@ this.handleSpellCheckDictionariesPrefChange_.bind(this)); Preferences.getInstance().addEventListener(ENABLE_TRANSLATE, this.handleEnableTranslatePrefChange_.bind(this)); - this.translateSupportedLanguages_ = - loadTimeData.getValue('translateSupportedLanguages'); + this.translateSupportedLanguages_ = /** @type {Array} */( + loadTimeData.getValue('translateSupportedLanguages')); // Set up add button. var onclick = function(e) { @@ -283,10 +283,12 @@ // change the visibility in handleLanguageOptionsListChange_() based // on the selected language. Note that we only have less than 100 // input methods, so creating DOM nodes at once here should be ok. - this.appendInputMethodElement_(loadTimeData.getValue('inputMethodList')); - this.appendComponentExtensionIme_( - loadTimeData.getValue('componentExtensionImeList')); - this.appendInputMethodElement_(loadTimeData.getValue('extensionImeList')); + this.appendInputMethodElement_(/** @type {!Array} */( + loadTimeData.getValue('inputMethodList'))); + this.appendComponentExtensionIme_(/** @type {!Array} */( + loadTimeData.getValue('componentExtensionImeList'))); + this.appendInputMethodElement_(/** @type {!Array} */( + loadTimeData.getValue('extensionImeList'))); // Listen to pref change once the input method list is initialized. Preferences.getInstance().addEventListener(
diff --git a/chrome/browser/resources/options/options_settings_app.js b/chrome/browser/resources/options/options_settings_app.js index 9704dff..72d2928 100644 --- a/chrome/browser/resources/options/options_settings_app.js +++ b/chrome/browser/resources/options/options_settings_app.js
@@ -47,5 +47,6 @@ $('profiles-list').canDeleteItems = false; }); - loadTimeData.overrideValues(loadTimeData.getValue('settingsApp')); + loadTimeData.overrideValues(/** @type {!Object} */( + loadTimeData.getValue('settingsApp'))); }());
diff --git a/chrome/browser/resources/options/supervised_user_import.js b/chrome/browser/resources/options/supervised_user_import.js index b9030b7..d3591c7 100644 --- a/chrome/browser/resources/options/supervised_user_import.js +++ b/chrome/browser/resources/options/supervised_user_import.js
@@ -41,7 +41,8 @@ var avatarGrid = $('select-avatar-grid'); options.ProfilesIconGrid.decorate(avatarGrid); var avatarIcons = loadTimeData.getValue('avatarIcons'); - avatarGrid.dataModel = new ArrayDataModel(avatarIcons); + avatarGrid.dataModel = new ArrayDataModel( + /** @type {!Array} */(avatarIcons)); supervisedUserList.addEventListener('change', function(event) { var supervisedUser = supervisedUserList.selectedItem;
diff --git a/chrome/browser/resources/pdf/pdf.js b/chrome/browser/resources/pdf/pdf.js index 3403bba..3c5bf9e 100644 --- a/chrome/browser/resources/pdf/pdf.js +++ b/chrome/browser/resources/pdf/pdf.js
@@ -262,8 +262,7 @@ new ViewportScroller(this.viewport_, this.plugin_, window); // Request translated strings. - if (!this.isPrintPreview_) - chrome.resourcesPrivate.getStrings('pdf', this.handleStrings_.bind(this)); + chrome.resourcesPrivate.getStrings('pdf', this.handleStrings_.bind(this)); } PDFViewer.prototype = {
diff --git a/chrome/browser/resources/settings/bluetooth_page/bluetooth_add_device_dialog.html b/chrome/browser/resources/settings/bluetooth_page/bluetooth_add_device_dialog.html new file mode 100644 index 0000000..c6f747c0 --- /dev/null +++ b/chrome/browser/resources/settings/bluetooth_page/bluetooth_add_device_dialog.html
@@ -0,0 +1,49 @@ +<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/classes/iron-flex-layout.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/iron-selector/iron-selector.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/paper-spinner/paper-spinner.html"> + +<dom-module id="settings-bluetooth-add-device-dialog"> + <link rel="import" type="css" href="chrome://md-settings/settings_shared.css"> + <link rel="import" type="css" href="bluetooth_page.css"> + <link rel="import" type="css" href="bluetooth_dialog.css"> + <template> + <div id="dialogOuterDiv" class="layout vertical flex"> + <div id="dialogHeaderDiv" class="settings-box layout horizontal"> + <span id="dialogTitle" class="flex" + i18n-content="bluetoothAddDevicePageTitle"> + </span> + <paper-icon-button icon="close" on-tap="onCancelTap_" id="close"> + </paper-icon-button> + </div> + <div class="settings-box flex"> + <div id="dialogDeviceList" class="settings-box layout vertical" + on-device-event="onDeviceEvent_"> + <span class="no-devices" hidden$="[[haveDevices_(deviceList)]]" + i18n-content="bluetoothNoDevices"> + </span> + <iron-selector class="flex"> + <template is="dom-repeat" items="[[deviceList]]" + filter="deviceNotPaired_" observe="paired"> + <bluetooth-device-list-item device="[[item]]"> + </bluetooth-device-list-item> + </template> + </iron-selector> + </div> + </div> + <div id="dialogFooterDiv" class="layout horizontal center"> + <div id="scanning" class="layout horizontal center flex" + hidden$="[[!adapterState.discovering]]"> + <paper-spinner active="[[adapterState.discovering]]"> + </paper-spinner> + <span i18n-content="bluetoothScanning"></span> + </div> + <paper-button id="cancel" class="end-justified" + i18n-content="bluetoothCancel" on-tap="onCancelTap_"> + </paper-button> + </div> + </div> + </template> + <script src="bluetooth_add_device_dialog.js"></script> +</dom-module>
diff --git a/chrome/browser/resources/settings/bluetooth_page/bluetooth_add_device_dialog.js b/chrome/browser/resources/settings/bluetooth_page/bluetooth_add_device_dialog.js new file mode 100644 index 0000000..189711f --- /dev/null +++ b/chrome/browser/resources/settings/bluetooth_page/bluetooth_add_device_dialog.js
@@ -0,0 +1,71 @@ +// 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 + * 'settings-bluetooth-add-device-dialog' is the settings subpage for adding + * bluetooth devices. + * + * @group Chrome Settings Elements + * @element settings-bluetooth-add-device-dialog + */ +Polymer({ + is: 'settings-bluetooth-add-device-dialog', + + properties: { + /** + * The cached bluetooth adapter state. + * @type {!chrome.bluetooth.AdapterState|undefined} + */ + adapterState: { + type: Object, + observer: 'adapterStateChanged_', + }, + + /** + * The ordered list of bluetooth devices. + * @type {!Array<!chrome.bluetooth.Device>} + */ + deviceList: { + type: Array, + value: function() { return []; }, + }, + }, + + /** @private */ + adapterStateChanged_: function() { + if (!this.adapterState.powered) + this.fire('close-dialog'); + }, + + /** + * @param {!chrome.bluetooth.Device} device + * @return {boolean} + * @private + */ + deviceNotPaired_: function(device) { + return !device.paired; + }, + + /** + * @param {!Array<!chrome.bluetooth.Device>} deviceList + * @return {boolean} True if deviceList contains any unpaired devices. + * @private + */ + haveDevices_: function(deviceList) { + return this.deviceList.findIndex(function(d) { return !d.paired; }) != -1; + }, + + /** + * @param {!{detail: {action: string, device: !chrome.bluetooth.Device}}} e + * @private + */ + onDeviceEvent_: function(e) { + this.fire('device-event', e.detail); + /** @type {Event} */(e).stopPropagation(); + }, + + /** @private */ + onCancelTap_: function() { this.fire('close-dialog'); }, +});
diff --git a/chrome/browser/resources/settings/bluetooth_page/bluetooth_device_list_item.css b/chrome/browser/resources/settings/bluetooth_page/bluetooth_device_list_item.css new file mode 100644 index 0000000..de43201 --- /dev/null +++ b/chrome/browser/resources/settings/bluetooth_page/bluetooth_device_list_item.css
@@ -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. */ + +#outer { + padding: 5px 5px 5px 15px; +} + +#outer:hover:not([dropdown]) { + background-color: #f0f0f0; +} + +iron-icon { + -webkit-padding-start: 10px; + color: green; +} + +paper-item:hover { + background-color: #f0f0f0; +} + +span.name { + padding: 10px 0; +} + +span.name[connected] { + font-weight: bold; +} + +.dropdown-content { + background: white; + box-shadow: 0 2px 6px grey; +}
diff --git a/chrome/browser/resources/settings/bluetooth_page/bluetooth_device_list_item.html b/chrome/browser/resources/settings/bluetooth_page/bluetooth_device_list_item.html new file mode 100644 index 0000000..a868a55 --- /dev/null +++ b/chrome/browser/resources/settings/bluetooth_page/bluetooth_device_list_item.html
@@ -0,0 +1,37 @@ +<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/iron-dropdown/iron-dropdown.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/classes/iron-flex-layout.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/iron-icons/iron-icons.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/paper-item/paper-item.html"> + +<dom-module id="bluetooth-device-list-item"> + <link rel="import" type="css" href="bluetooth_device_list_item.css"> + <template> + <div id="outer" class="layout horizontal center" + dropdown$="[[dropdownOpened]]" on-tap="itemTapped_"> + <span class="name" connected$="[[device.connected]]"> + [[getDeviceName_(device)]] + </span> + <iron-icon icon="check" hidden$="[[!device.connected]]"></iron-icon> + <span class="flex"></span> + <span hidden$="[[!device.connecting]]" + i18n-content="bluetoothConnecting"></span> + <div hidden$="[[!device.paired]]" on-tap="doNothing_"> + <paper-icon-button icon="more-vert" toggles active="{{dropdownOpened}}"> + </paper-icon-button> + <iron-dropdown opened="{{dropdownOpened}}" on-tap="menuSelected_"> + <div class="dropdown-content"> + <paper-item id="connect" i18n-content="bluetoothConnect" + hidden$="[[device.connected]]"></paper-item> + <paper-item id="disconnect" i18n-content="bluetoothDisconnect" + hidden$="[[!device.connected]]"></paper-item> + <paper-item id="remove" i18n-content="bluetoothRemove"></paper-item> + </div> + </iron-dropdown> + </div> + </div> + </template> + <script src="bluetooth_device_list_item.js"></script> +</dom-module>
diff --git a/chrome/browser/resources/settings/bluetooth_page/bluetooth_device_list_item.js b/chrome/browser/resources/settings/bluetooth_page/bluetooth_device_list_item.js new file mode 100644 index 0000000..dd2378b --- /dev/null +++ b/chrome/browser/resources/settings/bluetooth_page/bluetooth_device_list_item.js
@@ -0,0 +1,71 @@ +// 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 Polymer element for displaying a bluetooth device in a list. + */ + +Polymer({ + is: 'bluetooth-device-list-item', + + properties: { + /** + * The bluetooth device. + * @type {!chrome.bluetooth.Device} + */ + device: { + type: Object, + }, + }, + + /** + * @param {Event} e + * @private + */ + itemTapped_: function(e) { + this.fire('device-event', { + action: 'connect', + device: this.device, + }); + }, + + /** + * @param {Event} e + * @private + */ + menuSelected_: function(e) { + e.currentTarget.opened = false; + this.fire('device-event', { + action: e.target.id, + device: this.device, + }); + }, + + /** + * @param {Event} e + * @private + */ + doNothing_: function(e) { + // Avoid triggering itemTapped_. + e.stopPropagation(); + }, + + /** + * @param {!chrome.bluetooth.Device} device + * @return {string} The text to display for |device| in the device list. + * @private + */ + getDeviceName_: function(device) { + return device.name || device.address; + }, + + /** + * @param {!chrome.bluetooth.Device} device + * @return {boolean} + * @private + */ + isDisconnected_: function(device) { + return !device.connected && !device.connecting; + }, +});
diff --git a/chrome/browser/resources/settings/bluetooth_page/bluetooth_dialog.css b/chrome/browser/resources/settings/bluetooth_page/bluetooth_dialog.css new file mode 100644 index 0000000..6764633 --- /dev/null +++ b/chrome/browser/resources/settings/bluetooth_page/bluetooth_dialog.css
@@ -0,0 +1,91 @@ +/* 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. */ + +#dialogOuterDiv { + margin-bottom: 16px; +} + +#dialogHeaderDiv { + height: 40px; + margin: 0 5px 10px; +} + +#dialogFooterDiv { + height: 40px; + margin: 0 20px; +} + +#dialogMessage { + margin-bottom: 10px; +} + +#dialogTitle { + font-size: 125%; + margin: 0 10px; +} + +#dialogDeviceList { + height: 210px; + margin-bottom: 20px; + margin-left: 4px; + overflow-y: auto; +} + +#pairing { + margin-bottom: 10px; +} + +#pairing paper-input { + text-align: center; +} + +#pinDiv { + margin-top: 10px; +} + +iron-selector { + width: 100%; +} + +paper-spinner { + height: 20px; + margin: 0 10px; + width: 20px; +} + +/* .display indicates a displayed pin code or passkey. */ +span.display { + border: 1px solid #ccc; + border-radius: 4px; + box-shadow: 0 0 0 1px #222; + color: #222; + font-size: 16px; + height: 38px; + line-height: 38px; + margin: 0 5px; + padding: 0 15px; + text-align: center; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); +} + +span.display.next { + background: rgb(77, 144, 254); + border: 2px solid rgb(77, 144, 254); + box-shadow: none; + color: #fff; +} + +span.display.untyped { + border: 1px solid #d4d4d4; + box-shadow: 0 0 0 1px #888; + color: #666; +} + +/* .confirm indicates a confirmation passkey. */ +span.confirm { + color: #999; + font-size: 20px; + font-weight: 600; /* semibold */ + margin: 0 20px; +}
diff --git a/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.css b/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.css index ba920d0..2eb7bd8 100644 --- a/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.css +++ b/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.css
@@ -2,27 +2,31 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ +#addDevice { + color: blue; +} + +#deviceList { + -webkit-margin-start: 15px; + max-height: 300px; + overflow-y: auto; +} + +cr-expand-button { + -webkit-margin-end: 10px; +} + iron-icon { -webkit-margin-end: 10px; } -#deviceList { - border: lightgrey solid 1px; - margin: 10px 0; - max-height: 400px; - padding: 10px; +settings-bluetooth-add-device-dialog, +settings-bluetooth-pair-device-dialog { + height: 400px; + padding: 0; + width: 500px; } -div.iron-selected, -div.device:hover { - background-color: lightgrey; -} - -div.device:not(:hover) .hover-only { - visibility: hidden; -} - -span.name[connected], -span.name[connecting] { - font-weight: bold; +span.no-devices { + margin: 10px 20px; }
diff --git a/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.html b/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.html index 54278c0..042ca96 100644 --- a/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.html +++ b/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.html
@@ -1,7 +1,7 @@ <link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/classes/iron-flex-layout.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-icons/device-icons.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/iron-selector/iron-selector.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/iron-list/iron-list.html"> <link rel="import" href="chrome://resources/polymer/v1_0/neon-animation/neon-animatable.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button.html"> @@ -9,6 +9,9 @@ <link rel="import" href="chrome://resources/cr_elements/cr_collapse/cr_collapse.html"> <link rel="import" href="chrome://resources/html/i18n_behavior.html"> <link rel="import" href="chrome://md-settings/settings_page/settings_animated_pages.html"> +<link rel="import" href="bluetooth_device_list_item.html"> +<link rel="import" href="bluetooth_add_device_dialog.html"> +<link rel="import" href="bluetooth_pair_device_dialog.html"> <dom-module id="settings-bluetooth-page"> <link rel="import" type="css" href="chrome://md-settings/settings_shared.css"> @@ -17,51 +20,67 @@ <settings-animated-pages id="pages" current-route="{{currentRoute}}" section="bluetooth"> <neon-animatable id="main"> - <div class="layout vertical"> + <div class="settings-box"> <div class="layout horizontal center"> <iron-icon icon="device:bluetooth"></iron-icon> <span class="flex" i18n-content="bluetoothEnable"></span> + <cr-expand-button id="expandListButton" + hidden$="[[!bluetoothEnabled]]" + expanded="{{deviceListExpanded}}"> + </cr-expand-button> <paper-toggle-button id="enableBluetooth" checked="{{bluetoothEnabled}}" on-change="onBluetoothEnabledChange_"> </paper-toggle-button> </div> - <cr-collapse opened="[[bluetoothEnabled]]"> - <div id="deviceList" class="layout vertical flex"> - <span hidden$="[[haveDevices_(deviceList.splices)]]" + <cr-collapse opened="[[deviceListExpanded]]"> + <div id="deviceList" class="layout vertical" + on-device-event="onDeviceEvent_"> + <span class="no-devices" + hidden$="[[haveDevices_(deviceList.splices)]]" i18n-content="bluetoothNoDevices"> </span> - <iron-selector selected="{{selectedDevice}}"> - <template is="dom-repeat" items="[[deviceList]]"> - <div class="device layout horizontal center" - hidden$="[[!showDeviceInList_(item)]]"> - <span class="name flex" - connected$=[[item.connected]] - connecting$=[[item.connecting]]> - [[getDeviceText_(item)]] - </span> - <paper-icon-button class="hover-only" - icon="clear" address$=[[item.address]] - on-tap="onRemoveTap_"> - </paper-icon-button> - </div> - </template> - </iron-selector> + <template is="dom-repeat" items="[[deviceList]]" + filter="deviceIsPairedOrConnecting_"> + <bluetooth-device-list-item device="[[item]]"> + </bluetooth-device-list-item> + </template> + </div> + <div class="settings-box" hidden$="[[!bluetoothEnabled]]"> + <paper-button id="addDevice" i18n-content="bluetoothAddDevice" + on-tap="onAddDeviceTap_"> + </paper-button> </div> </cr-collapse> - <div class="layout horizontal end-justified" - hidden$="[[!bluetoothEnabled]]"> - <paper-button id="connect" i18n-content="bluetoothConnect" - disabled="[[!haveSelectedDevice_(selectedDevice)]]" - on-tap="onConnectTap_"> - </paper-button> - <paper-button id="addDevice" i18n-content="bluetoothAddDevice" - on-tap="onAddDeviceTap_"> - </paper-button> - </div> </div> </neon-animatable> </settings-animated-pages> + + <paper-dialog modal id="deviceDialog" class="layout vertical" + on-iron-overlay-opened="onDialogOpened_" + on-iron-overlay-closed="onDialogClosed_"> + <template is="dom-if" if="[[dialogIsVisible_(dialog, 'addDevice')]]" + restamp> + <settings-bluetooth-add-device-dialog + class="layout vertical flex" + adapter-state="[[adapterState]]" + device-list="[[deviceList]]" + on-device-event="onDeviceEvent_" + on-close-dialog="onCloseDialog_"> + </settings-bluetooth-add-device-dialog> + </template> + <template is="dom-if" if="[[dialogIsVisible_(dialog, 'pairDevice')]]" + restamp> + <settings-bluetooth-pair-device-dialog + class="layout vertical flex" + pairing-device="[[pairingDevice]]" + pairing-event="[[pairingEvent]]" + on-response="onResponse_" + on-close-dialog="onCloseDialog_"> + </settings-bluetooth-pair-device-dialog> + </template> + </paper-dialog> + </template> <script src="bluetooth_page.js"></script> </dom-module>
diff --git a/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.js b/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.js index 9a11f17..c8babf42 100644 --- a/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.js +++ b/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.js
@@ -47,16 +47,54 @@ }, /** Whether bluetooth is enabled. */ - bluetoothEnabled: {type: Boolean, value: false}, + bluetoothEnabled: { + type: Boolean, + value: false, + observer: 'bluetoothEnabledChanged_', + }, + + /** Whether the device list is expanded. */ + deviceListExpanded: { + type: Boolean, + value: false, + }, + + /** + * The cached bluetooth adapter state. + * @type {!chrome.bluetooth.AdapterState|undefined} + */ + adapterState: Object, /** * The ordered list of bluetooth devices. * @type {!Array<!chrome.bluetooth.Device>} */ - deviceList: {type: Array, value: function() { return []; }}, + deviceList: { + type: Array, + value: function() { return []; }, + }, - /** The index of the selected device or -1 if none. */ - selectedDevice: {type: Number, value: -1}, + /** + * Set to the name of the dialog to show. This page uses a single + * paper-dialog to host one of two dialog elements, 'addDevice' or + * 'pairDevice'. This allows a seamless transition between adding and + * pairing dialogs. Note: This property should be set before opening the + * dialog, and setting the property will not itself cause the dialog to + * open. + */ + dialog: String, + + /** + * Current Pairing device. + * @type {?chrome.bluetooth.Device|undefined} + */ + pairingDevice: Object, + + /** + * Current Pairing event. + * @type {?chrome.bluetoothPrivate.PairingEvent|undefined} + */ + pairingEvent: Object, /** * Interface for bluetooth calls. May be overriden by tests. @@ -98,6 +136,13 @@ */ bluetoothDeviceRemovedListener_: undefined, + /** + * Listener for chrome.bluetoothPrivate.onPairing events. + * @type {function(!chrome.bluetoothPrivate.PairingEvent)|undefined} + * @private + */ + bluetoothPrivateOnPairingListener_: undefined, + /** @override */ ready: function() { if (bluetoothPage.bluetoothApiForTest) @@ -148,6 +193,12 @@ } }, + bluetoothEnabledChanged_: function() { + // When bluetooth is enabled, auto-expand the device list. + if (this.bluetoothEnabled) + this.deviceListExpanded = true; + }, + /** * If bluetooth is enabled, request the complete list of devices and update * |deviceList|. @@ -184,6 +235,7 @@ * @private */ onBluetoothAdapterStateChanged_: function(state) { + this.adapterState = state; this.bluetoothEnabled = state.powered; this.updateDeviceList_(); }, @@ -194,12 +246,16 @@ * @private */ onBluetoothDeviceUpdated_: function(device) { - if (!device) - return; var address = device.address; + if (this.dialog && this.pairingDevice && + this.pairingDevice.address == address) { + this.pairingDevice = device; + } var index = this.getDeviceIndex_(address); if (index >= 0) { - this.set('deviceList.' + index, device); + // Use splice to update the item in order to update the dom-repeat lists. + // See https://github.com/Polymer/polymer/issues/3254. + this.splice('deviceList', index, 1, device); return; } this.push('deviceList', device); @@ -218,6 +274,110 @@ this.splice('deviceList', index, 1); }, + /** @private */ + startDiscovery_: function() { + if (!this.adapterState || this.adapterState.discovering) + return; + + if (!this.bluetoothPrivateOnPairingListener_) { + this.bluetoothPrivateOnPairingListener_ = + this.onBluetoothPrivateOnPairing_.bind(this); + this.bluetoothPrivate.onPairing.addListener( + this.bluetoothPrivateOnPairingListener_); + } + + this.bluetooth.startDiscovery(function() { + if (chrome.runtime.lastError) { + if (chrome.runtime.lastError.message == 'Failed to stop discovery') { + // May happen if also started elsewhere; ignore. + return; + } + console.error('startDsicovery Error: ' + + chrome.runtime.lastError.message); + } + }); + }, + + /** @private */ + stopDiscovery_: function() { + if (!this.get('adapterState.discovering')) + return; + + if (this.bluetoothPrivateOnPairingListener_) { + this.bluetoothPrivate.onPairing.removeListener( + this.bluetoothPrivateOnPairingListener_); + this.bluetoothPrivateOnPairingListener_ = undefined; + } + + this.bluetooth.stopDiscovery(function() { + if (chrome.runtime.lastError) { + console.error('Error stopping bluetooth discovery: ' + + chrome.runtime.lastError.message); + } + }); + }, + + /** + * Process bluetoothPrivate.onPairing events. + * @param {!chrome.bluetoothPrivate.PairingEvent} e + * @private + */ + onBluetoothPrivateOnPairing_: function(e) { + if (!this.dialog || !this.pairingDevice || + e.device.address != this.pairingDevice.address) { + return; + } + if (e.pairing == chrome.bluetoothPrivate.PairingEventType.KEYS_ENTERED && + e.passkey === undefined && this.pairingEvent) { + // 'keysEntered' event might not include the updated passkey so preserve + // the current one. + e.passkey = this.pairingEvent.passkey; + } + this.pairingEvent = e; + }, + + /** @private */ + onAddDeviceTap_: function() { this.openDialog_('addDevice'); }, + + /** + * @param {!{detail: {action: string, device: !chrome.bluetooth.Device}}} e + * @private + */ + onDeviceEvent_: function(e) { + var action = e.detail.action; + var device = e.detail.device; + if (action == 'connect') + this.connectDevice_(device); + else if (action == 'disconnect') + this.disconnectDevice_(device); + else if (action == 'remove') + this.forgetDevice_(device); + else + console.error('Unexected action: ' + action); + }, + + /** + * Handle a response sent from the pairing dialog and pass it to the + * bluetoothPrivate API. + * @param {Event} e + * @private + */ + onResponse_: function(e) { + var options = + /** @type {!chrome.bluetoothPrivate.SetPairingResponseOptions} */ ( + e.detail); + this.bluetoothPrivate.setPairingResponse(options, function() { + if (chrome.runtime.lastError) { + // TODO(stevenjb): Show error. + console.error( + 'Error setting pairing response: ' + options.device.name + + ': Response: ' + options.response + ': Error: ' + + chrome.runtime.lastError.message); + } + this.closeDialog_(); + }.bind(this)); + }, + /** * @param {string} address * @return {number} The index of the device associated with |address| or -1. @@ -237,82 +397,127 @@ * @return {string} The text to display for |device| in the device list. * @private */ - getDeviceText_: function(device) { - if (device.connecting) - return this.i18n('bluetoothConnecting', device.name); + getDeviceName_: function(device) { return device.name || device.address; }, /** * @param {!chrome.bluetooth.Device} device - * @return {boolean} True if |device| should be shown in the device list. + * @return {boolean} * @private */ - showDeviceInList_: function(device) { - return !!device.paired || !!device.connected || !!device.connecting; + deviceIsPairedOrConnecting_: function(device) { + return !!device.paired || !!device.connecting; }, /** - * @param {Object} deviceListChanges - * @return {boolean} True if deviceList is not empty. + * @param {Object} deviceListChanges Changes to the deviceList Array. + * @return {boolean} True if deviceList contains any paired devices. * @private */ haveDevices_: function(deviceListChanges) { - return !!this.deviceList.length; + return this.deviceList.findIndex(function(d) { return d.paired; }) != -1; }, /** - * @param {number} selectedDevice - * @return {boolean} True if a device is selected. + * @param {!chrome.bluetooth.Device} device * @private */ - haveSelectedDevice_: function(selectedDevice) { return selectedDevice >= 0; }, + connectDevice_: function(device) { + // If the device is not paired, show the pairing dialog. + if (!device.paired) { + // Set the pairing device and clear any pairing event. + this.pairingDevice = device; + this.pairingEvent = null; - /** @private */ - onConnectTap_: function() { - if (this.selectedDevice < 0) - return; - var device = this.deviceList[this.selectedDevice]; - if (!device) - return; + this.openDialog_('pairDevice'); + } + this.bluetoothPrivate.connect(device.address, function(result) { if (chrome.runtime.lastError) { console.error( - 'Error connecting to: ' + device.address + + 'Error connecting: ' + device.address + + chrome.runtime.lastError.message); + // TODO(stevenjb): Show error message insead. + this.closeDialog_(); + } + }.bind(this)); + }, + + /** + * @param {!chrome.bluetooth.Device} device + * @private + */ + disconnectDevice_: function(device) { + this.bluetoothPrivate.disconnectAll(device.address, function() { + if (chrome.runtime.lastError) { + console.error( + 'Error disconnecting: ' + device.address + chrome.runtime.lastError.message); } }); }, /** - * @param {!Event} event + * @param {!chrome.bluetooth.Device} device * @private */ - onRemoveTap_: function(event) { - var address = event.target.address; - var index = this.getDeviceIndex_(address); - if (index < 0) + forgetDevice_: function(device) { + this.bluetoothPrivate.forgetDevice(device.address, function() { + if (chrome.runtime.lastError) { + console.error( + 'Error forgetting: ' + device.name + ': ' + + chrome.runtime.lastError.message); + } + this.updateDeviceList_(); + }.bind(this)); + }, + + /** + * @param {string} dialog + * @param {string} dialogToShow The name of the dialog. + * @return {boolean} + * @private + */ + dialogIsVisible_(dialog, dialogToShow) { + return dialogToShow == dialog; + }, + + /** + * @param {string} dialogId + * @private + */ + openDialog_: function(dialogId) { + if (this.dialog) { + // Dialog already opened, just update the contents. + this.dialog = dialogId; return; - var device = this.deviceList[index]; - if (device.connected) { - this.bluetoothPrivate.disconnectAll(address, function() { - if (chrome.runtime.lastError) { - console.error( - 'Error disconnecting devce: ' + device.name + ': ' + - chrome.runtime.lastError.message); - } - }); - } else { - this.bluetoothPrivate.forgetDevice(address, function() { - if (chrome.runtime.lastError) { - console.error( - 'Error forgetting devce: ' + device.name + ': ' + - chrome.runtime.lastError.message); - } - }); } + this.dialog = dialogId; + // Call flush so that the dialog gets sized correctly before it is opened. + Polymer.dom.flush(); + var dialog = this.$$('#deviceDialog'); + dialog.open(); + dialog.focus(); }, /** @private */ - onAddDeviceTap_: function() {} + closeDialog_: function() { + if (!this.dialog) + return; + var dialog = this.$$('#deviceDialog'); + dialog.close(); + this.dialog = ''; + this.pairingDevice = null; + this.pairingEvent = null; + }, + + /** @private */ + onCloseDialog_: function(event) { this.closeDialog_(); }, + + /** @private */ + onDialogOpened_: function() { this.startDiscovery_(); }, + + /** @private */ + onDialogClosed_: function() { this.stopDiscovery_(); }, });
diff --git a/chrome/browser/resources/settings/bluetooth_page/bluetooth_pair_device_dialog.html b/chrome/browser/resources/settings/bluetooth_page/bluetooth_pair_device_dialog.html new file mode 100644 index 0000000..05ed236 --- /dev/null +++ b/chrome/browser/resources/settings/bluetooth_page/bluetooth_pair_device_dialog.html
@@ -0,0 +1,68 @@ +<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/classes/iron-flex-layout.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/paper-input/paper-input.html"> + +<dom-module id="settings-bluetooth-pair-device-dialog"> + <link rel="import" type="css" href="chrome://md-settings/settings_shared.css"> + <link rel="import" type="css" href="bluetooth_page.css"> + <link rel="import" type="css" href="bluetooth_dialog.css"> + <template> + <div id="dialogOuterDiv" class="layout vertical flex"> + <div id="dialogHeaderDiv" class="settings-box layout horizontal center"> + <span id="dialogTitle" class="flex" + i18n-content="bluetoothPairDevicePageTitle"> + </span> + <paper-icon-button icon="close" on-tap="onCancelTap_" id="close"> + </paper-icon-button> + </div> + <div id="pairing" + class="settings-blox layout vertical center center-justified flex"> + <div id="dialogMessage"> + [[getMessage_(pairingDevice, pairingEvent)]] + </div> + <div hidden$="[[!showEnterPincode_(pairingEvent)]]"> + <paper-input id="pincode" minlength="1" maxlength="16" type="text"> + </div> + <div hidden$="[[!showEnterPasskey_(pairingEvent)]]"> + <paper-input id="passkey" minlength="6" maxlength="6" type="text"> + </div> + <div id="pinDiv" class="layout horizontal center center-justified" + hidden="[[!showDisplayPassOrPin_(pairingEvent)]]"> + <template is="dom-repeat" items="[[digits]]"> + <span class$="[[getPinClass_(pairingEvent, index)]]"> + [[getPinDigit_(pairingEvent, index)]] + </span> + </template> + <span class$="[[getPinClass_(pairingEvent, -1)]]" + hidden="[[showAcceptReject_(pairingEvent)]]"> + [[i18n('bluetoothEnterKey')]] + </span> + </div> + </div> + <div id="dialogFooterDiv" class="layout horizontal center end-justified"> + <paper-button i18n-content="bluetoothAccept" + hidden$="[[!showAcceptReject_(pairingEvent)]]" + on-tap="onAcceptTap_"> + </paper-button> + <paper-button i18n-content="bluetoothReject" + hidden$="[[!showAcceptReject_(pairingEvent)]]" + on-tap="onRejectTap_"> + </paper-button> + <paper-button i18n-content="bluetoothConnect" + hidden$="[[!showConnect_(pairingEvent)]]" + on-tap="onConnectTap_"> + </paper-button> + <paper-button i18n-content="bluetoothDismiss" + hidden$="[[!showDismiss_(pairingDevice, pairingEvent)]]" + on-tap="onDismissTap_"> + </paper-button> + <paper-button i18n-content="bluetoothCancel" on-tap="onCancelTap_" + hidden$="[[showDismiss_(pairingDevice, pairingEvent)]]" + </paper-button> + </div> + </div> + </template> + <script src="bluetooth_pair_device_dialog.js"></script> +</dom-module>
diff --git a/chrome/browser/resources/settings/bluetooth_page/bluetooth_pair_device_dialog.js b/chrome/browser/resources/settings/bluetooth_page/bluetooth_pair_device_dialog.js new file mode 100644 index 0000000..9ee5e6a8 --- /dev/null +++ b/chrome/browser/resources/settings/bluetooth_page/bluetooth_pair_device_dialog.js
@@ -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. + +/** + * @fileoverview + * 'settings-bluetooth-pair-device-dialog' is the settings dialog for pairing + * a bluetooth device. + * + * @group Chrome Settings Elements + * @element settings-bluetooth-pair-device-dialog + */ + +(function() { + +var PairingEventType = chrome.bluetoothPrivate.PairingEventType; + +Polymer({ + is: 'settings-bluetooth-pair-device-dialog', + + behaviors: [I18nBehavior], + + properties: { + /** + * Current Pairing device. + * @type {?chrome.bluetooth.Device|undefined} + */ + pairingDevice: Object, + + /** + * Current Pairing event. + * @type {?chrome.bluetoothPrivate.PairingEvent|undefined} + */ + pairingEvent: Object, + + /** + * @const + * @type {!Array<number>} + */ + digits: { + type: Array, + readonly: true, + value: [0, 1, 2, 3, 4, 5], + }, + }, + + observers: [ + 'pairingChanged_(pairingDevice, pairingEvent)', + ], + + /** + * @param {?chrome.bluetooth.Device} pairingDevice + * @param {?chrome.bluetoothPrivate.PairingEvent} pairingEvent + * @private + */ + pairingChanged_: function(pairingDevice, pairingEvent) { + // Auto-close the dialog when pairing completes. + if (pairingDevice && pairingDevice.connected) { + this.fire('close-dialog', ''); + return; + } + }, + + /** + * @param {?chrome.bluetooth.Device} device + * @param {?chrome.bluetoothPrivate.PairingEvent} pairingEvent + * @return {string} + * @private + */ + getMessage_: function(device, pairingEvent) { + if (!device) + return ''; + var message; + if (!pairingEvent) + message = 'bluetoothStartConnecting'; + else + message = this.getEventDesc_(pairingEvent.pairing); + return this.i18n(message, device.name); + }, + + /** + * @param {?chrome.bluetoothPrivate.PairingEvent} pairingEvent + * @return {boolean} + * @private + */ + showEnterPincode_: function(pairingEvent) { + return !!pairingEvent && + pairingEvent.pairing == PairingEventType.REQUEST_PINCODE; + }, + + /** + * @param {?chrome.bluetoothPrivate.PairingEvent} pairingEvent + * @return {boolean} + * @private + */ + showEnterPasskey_: function(pairingEvent) { + return !!pairingEvent && + pairingEvent.pairing == PairingEventType.REQUEST_PASSKEY; + }, + + /** + * @param {?chrome.bluetoothPrivate.PairingEvent} pairingEvent + * @return {boolean} + * @private + */ + showDisplayPassOrPin_: function(pairingEvent) { + if (!pairingEvent) + return false; + var pairing = pairingEvent.pairing; + return ( + pairing == PairingEventType.DISPLAY_PINCODE || + pairing == PairingEventType.DISPLAY_PASSKEY || + pairing == PairingEventType.CONFIRM_PASSKEY || + pairing == PairingEventType.KEYS_ENTERED); + }, + + /** + * @param {?chrome.bluetoothPrivate.PairingEvent} pairingEvent + * @return {boolean} + * @private + */ + showAcceptReject_: function(pairingEvent) { + return !!pairingEvent && + pairingEvent.pairing == PairingEventType.CONFIRM_PASSKEY; + }, + + /** + * @param {?chrome.bluetoothPrivate.PairingEvent} pairingEvent + * @return {boolean} + * @private + */ + showConnect_: function(pairingEvent) { + if (!pairingEvent) + return false; + var pairing = pairingEvent.pairing; + if (pairing == PairingEventType.REQUEST_PINCODE) { + var pincode = /** @type {{invalid: boolean}} */(this.$.pincode); + return !pincode.invalid; + } else if (pairing == PairingEventType.REQUEST_PASSKEY) { + var passkey = /** @type {{invalid: boolean}} */(this.$.passkey); + return !passkey.invalid; + } + return false; + }, + + /** + * @param {?chrome.bluetooth.Device} device + * @param {?chrome.bluetoothPrivate.PairingEvent} pairingEvent + * @return {boolean} + * @private + */ + showDismiss_: function(device, pairingEvent) { + return (!!device && device.paired) || + (!!pairingEvent && pairingEvent.pairing == PairingEventType.COMPLETE); + }, + + /** @private */ + onAcceptTap_: function() { + this.sendResponse_(chrome.bluetoothPrivate.PairingResponse.CONFIRM); + }, + + /** @private */ + onConnectTap_: function() { + this.sendResponse_(chrome.bluetoothPrivate.PairingResponse.CONFIRM); + }, + + /** @private */ + onRejectTap_: function() { + this.sendResponse_(chrome.bluetoothPrivate.PairingResponse.REJECT); + }, + + /** @private */ + onCancelTap_: function() { + this.sendResponse_(chrome.bluetoothPrivate.PairingResponse.CANCEL); + }, + + /** @private */ + onDismissTap_: function() { this.fire('close-dialog', ''); }, + + /** @private */ + sendResponse_: function(response) { + if (!this.pairingDevice) + return; + var options = + /** @type {!chrome.bluetoothPrivate.SetPairingResponseOptions} */ { + device: this.pairingDevice, + response: response + }; + if (response == chrome.bluetoothPrivate.PairingResponse.CONFIRM) { + var pairing = this.pairingEvent.pairing; + if (pairing == PairingEventType.REQUEST_PINCODE) + options.pincode = this.$.pincode.value; + else if (pairing == PairingEventType.REQUEST_PASSKEY) + options.passkey = parseInt(this.$.passkey.value, 10); + } + this.fire('response', options); + }, + + /** + * @param {!PairingEventType} eventType + * @return {string} + * @private + */ + getEventDesc_: function(eventType) { + assert(eventType); + if (eventType == PairingEventType.COMPLETE || + eventType == PairingEventType.KEYS_ENTERED || + eventType == PairingEventType.REQUEST_AUTHORIZATION) { + return 'bluetoothStartConnecting'; + } + return 'bluetooth_' + /** @type {string} */(eventType); + }, + + /** + * @param {?chrome.bluetoothPrivate.PairingEvent} pairingEvent + * @param {number} index + * @return {string} + * @private + */ + getPinDigit_: function(pairingEvent, index) { + if (!pairingEvent) + return ''; + var digit = '0'; + var pairing = pairingEvent.pairing; + if (pairing == PairingEventType.DISPLAY_PINCODE && pairingEvent.pincode && + index < pairingEvent.pincode.length) { + digit = pairingEvent.pincode[index]; + } else if (pairingEvent.passkey && + (pairing == PairingEventType.DISPLAY_PASSKEY || + pairing == PairingEventType.KEYS_ENTERED || + pairing == PairingEventType.CONFIRM_PASSKEY)) { + var passkeyString = String(pairingEvent.passkey); + if (index < passkeyString.length) + digit = passkeyString[index]; + } + return digit; + }, + + /** + * @param {?chrome.bluetoothPrivate.PairingEvent} pairingEvent + * @param {number} index + * @return {string} + * @private + */ + getPinClass_: function(pairingEvent, index) { + if (!pairingEvent) + return ''; + if (pairingEvent.pairing == PairingEventType.CONFIRM_PASSKEY) + return 'confirm'; + var cssClass = 'display'; + if (pairingEvent.pairing == PairingEventType.DISPLAY_PASSKEY) { + if (index == 0) + cssClass += ' next'; + else + cssClass += ' untyped'; + } else if ( + pairingEvent.pairing == PairingEventType.KEYS_ENTERED && + pairingEvent.enteredKey) { + var enteredKey = pairingEvent.enteredKey; // 1-7 + var lastKey = this.digits.length; // 6 + if ((index == -1 && enteredKey > lastKey) || (index + 1 == enteredKey)) + cssClass += ' next'; + else if (index > enteredKey) + cssClass += ' untyped'; + } + return cssClass; + }, +}); +})();
diff --git a/chrome/browser/resources/settings/bluetooth_page/compiled_resources.gyp b/chrome/browser/resources/settings/bluetooth_page/compiled_resources.gyp index 6e1c519..1703205 100644 --- a/chrome/browser/resources/settings/bluetooth_page/compiled_resources.gyp +++ b/chrome/browser/resources/settings/bluetooth_page/compiled_resources.gyp
@@ -21,5 +21,52 @@ }, 'includes': ['../../../../../third_party/closure_compiler/compile_js.gypi'], }, + { + 'target_name': 'bluetooth_device_list_item', + 'variables': { + 'depends': [ + '../../../../../ui/webui/resources/js/compiled_resources.gyp:assert', + ], + 'externs': [ + '../../../../../third_party/closure_compiler/externs/bluetooth.js', + '../../../../../third_party/closure_compiler/externs/bluetooth_private.js' + ], + }, + 'includes': ['../../../../../third_party/closure_compiler/compile_js.gypi'], + }, + { + 'target_name': 'bluetooth_add_device_dialog', + 'variables': { + 'depends': [ + '../../../../../third_party/closure_compiler/externs/bluetooth_interface.js', + '../../../../../third_party/closure_compiler/externs/bluetooth_private_interface.js', + '../../../../../ui/webui/resources/js/compiled_resources.gyp:assert', + '../../../../../ui/webui/resources/js/compiled_resources.gyp:load_time_data', + '../../../../../ui/webui/resources/js/i18n_behavior.js', + ], + 'externs': [ + '../../../../../third_party/closure_compiler/externs/bluetooth.js', + '../../../../../third_party/closure_compiler/externs/bluetooth_private.js' + ], + }, + 'includes': ['../../../../../third_party/closure_compiler/compile_js.gypi'], + }, + { + 'target_name': 'bluetooth_pair_device_dialog', + 'variables': { + 'depends': [ + '../../../../../third_party/closure_compiler/externs/bluetooth_interface.js', + '../../../../../third_party/closure_compiler/externs/bluetooth_private_interface.js', + '../../../../../ui/webui/resources/js/compiled_resources.gyp:assert', + '../../../../../ui/webui/resources/js/compiled_resources.gyp:load_time_data', + '../../../../../ui/webui/resources/js/i18n_behavior.js', + ], + 'externs': [ + '../../../../../third_party/closure_compiler/externs/bluetooth.js', + '../../../../../third_party/closure_compiler/externs/bluetooth_private.js' + ], + }, + 'includes': ['../../../../../third_party/closure_compiler/compile_js.gypi'], + }, ], }
diff --git a/chrome/browser/resources/settings/settings_page/settings_router.js b/chrome/browser/resources/settings/settings_page/settings_router.js index 51a5ec5..6331392 100644 --- a/chrome/browser/resources/settings/settings_page/settings_router.js +++ b/chrome/browser/resources/settings/settings_page/settings_router.js
@@ -95,6 +95,22 @@ subpage: [], subpageTitles: [], }, +<if expr="chromeos"> + { + url: '/networkDetail', + page: 'basic', + section: 'internet', + subpage: ['network-detail'], + subpageTitles: ['internetDetailPageTitle'], + }, + { + url: '/knownNetworks', + page: 'basic', + section: 'internet', + subpage: ['known-networks'], + subpageTitles: ['internetKnownNetworksPageTitle'], + }, +</if> { url: '/fonts', page: 'basic', @@ -168,20 +184,23 @@ subpage: ['clear-browsing-data'], subpageTitles: ['clearBrowsingData'], }, +<if expr="chromeos"> { - url: '/networkDetail', - page: 'basic', - section: 'internet', - subpage: ['network-detail'], - subpageTitles: ['internetDetailPageTitle'], + url: '/bluetoothAddDevice', + page: 'advanced', + section: 'bluetooth', + subpage: ['bluetooth-add-device'], + subpageTitles: ['bluetoothAddDevicePageTitle'], }, { - url: '/knownNetworks', - page: 'basic', - section: 'internet', - subpage: ['known-networks'], - subpageTitles: ['internetKnownNetworksPageTitle'], + url: '/bluetoothAddDevice/bluetoothPairDevice', + page: 'advanced', + section: 'bluetooth', + subpage: ['bluetooth-add-device', 'bluetooth-pair-device'], + subpageTitles: ['bluetoothAddDevicePageTitle', + 'bluetoothPairDevicePageTitle'], }, +</if> { url: '/languages', page: 'advanced',
diff --git a/chrome/browser/resources/settings/settings_resources.grd b/chrome/browser/resources/settings/settings_resources.grd index 4133b58d..db7cde6 100644 --- a/chrome/browser/resources/settings/settings_resources.grd +++ b/chrome/browser/resources/settings/settings_resources.grd
@@ -538,6 +538,18 @@ file="settings.js" type="chrome_html" /> <if expr="chromeos"> + <structure name="IDR_SETTINGS_BLUETOOTH_DEVICE_LIST_ITEM_CSS" + file="bluetooth_page/bluetooth_device_list_item.css" + type="chrome_html" /> + <structure name="IDR_SETTINGS_BLUETOOTH_DEVICE_LIST_ITEM_HTML" + file="bluetooth_page/bluetooth_device_list_item.html" + type="chrome_html" /> + <structure name="IDR_SETTINGS_BLUETOOTH_DEVICE_LIST_ITEM_JS" + file="bluetooth_page/bluetooth_device_list_item.js" + type="chrome_html" /> + <structure name="IDR_SETTINGS_BLUETOOTH_DIALOG_CSS" + file="bluetooth_page/bluetooth_dialog.css" + type="chrome_html" /> <structure name="IDR_SETTINGS_BLUETOOTH_PAGE_CSS" file="bluetooth_page/bluetooth_page.css" type="chrome_html" /> @@ -547,6 +559,18 @@ <structure name="IDR_SETTINGS_BLUETOOTH_PAGE_JS" file="bluetooth_page/bluetooth_page.js" type="chrome_html" /> + <structure name="IDR_SETTINGS_BLUETOOTH_ADD_DEVICE_DIALOG_HTML" + file="bluetooth_page/bluetooth_add_device_dialog.html" + type="chrome_html" /> + <structure name="IDR_SETTINGS_BLUETOOTH_ADD_DEVICE_DIALOG_JS" + file="bluetooth_page/bluetooth_add_device_dialog.js" + type="chrome_html" /> + <structure name="IDR_SETTINGS_BLUETOOTH_PAIR_DEVICE_DIALOG_HTML" + file="bluetooth_page/bluetooth_pair_device_dialog.html" + type="chrome_html" /> + <structure name="IDR_SETTINGS_BLUETOOTH_PAIR_DEVICE_DIALOG_JS" + file="bluetooth_page/bluetooth_pair_device_dialog.js" + type="chrome_html" /> <structure name="IDR_SETTINGS_DATE_TIME_PAGE_CSS" file="date_time_page/date_time_page.css" type="chrome_html" />
diff --git a/chrome/browser/resources/settings/site_settings/site_details_permission.html b/chrome/browser/resources/settings/site_settings/site_details_permission.html index a1fe1ab..0c65a99 100644 --- a/chrome/browser/resources/settings/site_settings/site_details_permission.html +++ b/chrome/browser/resources/settings/site_settings/site_details_permission.html
@@ -28,8 +28,8 @@ <paper-dropdown-menu> <paper-menu id="permission" class="dropdown-content" on-iron-select="onPermissionMenuIronSelect_"> - <paper-item>[[i18n_.allowAction]]</paper-item> - <paper-item>[[i18n_.blockAction]]</paper-item> + <paper-item id="allow">[[i18n_.allowAction]]</paper-item> + <paper-item id="block">[[i18n_.blockAction]]</paper-item> </paper-menu> </paper-dropdown-menu> </div>
diff --git a/chrome/browser/resources/settings/site_settings/site_details_permission.js b/chrome/browser/resources/settings/site_settings/site_details_permission.js index f688c378..a5596900 100644 --- a/chrome/browser/resources/settings/site_settings/site_details_permission.js +++ b/chrome/browser/resources/settings/site_settings/site_details_permission.js
@@ -33,10 +33,7 @@ /** * The origin, which this permission affects. */ - origin: { - type: String, - observer: 'initialize_', - }, + origin: String, i18n_: { readOnly: true, @@ -50,7 +47,17 @@ }, }, + observers: [ + 'initialize_(' + + 'prefs.profile.content_settings.exceptions.*, category, origin)', + ], + initialize_: function() { + this.$.details.hidden = true; + if (this.get('prefs.' + + this.computeCategoryExceptionsPrefName(this.category)) === undefined) + return; + var pref = this.getPref( this.computeCategoryExceptionsPrefName(this.category)); var originPref = pref.value[this.origin + ',*'];
diff --git a/chrome/browser/resources/supervised_user_block_interstitial.css b/chrome/browser/resources/supervised_user_block_interstitial.css index 20bba42..0c666f0 100644 --- a/chrome/browser/resources/supervised_user_block_interstitial.css +++ b/chrome/browser/resources/supervised_user_block_interstitial.css
@@ -2,70 +2,35 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ body { - background-color: rgb(230, 230, 230); + background-color: rgb(247, 247, 247); font-size: 10pt; - margin: 50px 40px 20px 40px; - text-align: center; + margin: 150px 60px 0 30px; } #main-frame-blocked { margin: auto; - max-width: 540px; + max-width: 600px; min-width: 200px; } -#box { - background-color: rgb(251, 251, 251); - border: 1px solid rgb(170, 170, 170); - border-bottom: 1px solid rgb(136, 136, 136); - border-radius: 3px; - box-shadow: 0 2px 2px rgb(170, 170, 170); - color: black; -} - h1 { - color: rgb(102, 102, 102); - font-size: 1.3em; + font-size: 1.8em; font-weight: normal; margin: 5px 0 25px 0; } -a { - color: rgb(17, 85, 204); - text-decoration: none; -} - -#error-img { - /* Can't access chrome:// urls from an untrusted renderer process, so embed - * the resource manually. */ - -webkit-user-select: none; - content: -webkit-image-set( - url(../../app/theme/default_100_percent/common/error_managed_mode_blocked_page.png) 1x, - url(../../app/theme/default_200_percent/common/error_managed_mode_blocked_page.png) 2x); - margin-bottom: 15px; - margin-top: 10px; -} - -#avatar-container { - position: relative; -} - .avatar-img { -webkit-user-select: none; border: 3px solid rgb(251, 251, 251); border-radius: 50%; + content: -webkit-image-set( + url(../../app/theme/default_100_percent/cros/logo_avatar_circle_blue_color.png) 1x, + url(../../app/theme/default_200_percent/cros/logo_avatar_circle_blue_color.png) 2x); margin-bottom: 5px; - margin-top: 10px; - position: relative; -} - -#content-top { - margin: 20px 25px; -} - -#block-reason-message { - font-size: 80%; + margin-right: 15px; margin-top: 5px; + max-width: 45px; + position: relative; } #feedback-link { @@ -73,43 +38,104 @@ margin-top: 10px; } -button { - -webkit-user-select: none; - background-image: linear-gradient(rgb(246, 246, 246) 5%, - rgb(239, 239, 239) 50%, - rgb(221, 221, 221)); - border: 1px solid rgb(209, 209, 211); - border-bottom: 1px solid rgb(193, 193, 195); - border-radius: 2px; - box-shadow: inset 0 1px 0 rgb(255, 255, 255); - color: rgb(102, 102, 102); +#request-access-button { + background-color: rgb(66, 133, 244); + color: rgb(255, 255, 255); + cursor: pointer; + font-size: 12px; font-weight: bold; - margin: 5px 3px; - padding: 8px 13px; - text-shadow: 0 1px 0 rgba(255, 255, 255, 0.8); + min-width: 88px; + padding: 10px 15px; + transition: box-shadow 200ms cubic-bezier(0.4, 0, 0.2, 1); + transition-delay: 200ms; } -@media (min-width: 376px) { - #back-button { - width: 100px; - } +#request-access-button:hover { + background-color: rgb(30, 136, 229); } -@media (max-width: 375px) { +#request-access-button:active { + background-color: rgb(25,118,210); + box-shadow: 0 8px 17px 0 rgba(0, 0, 0, 0.2); + transition-delay: 0s; +} + +#details-button-container { + color: rgb(97,97,97); + cursor: pointer; + display: inline; + font-size: 12px; + text-decoration: underline; +} + +#button-container { + align-items: baseline; + display: flex; + justify-content: space-between; + margin-top: 60px; +} + +#details { + color: rgb(97,97,97); + font-size: 14px; +} + +#details-header { + font-weight: bold; +} + +.custodian-information { + align-items: center; + display: flex; + font-size: 12px; +} + +.custodian-name { + color: rgb(97,97,97); + padding: 1px 0; +} + +.custodian-email { + color: rgb(183, 183, 183); + padding: 1px 0; +} + +@media (max-width: 600px) { #button-container { display: flex; flex-flow: column; + justify-content: flex-start; + order: 2; + text-transform: uppercase; } - #back-button { + #details-button-container { + font-weight: bold; + margin: auto; order: 2; } #request-access-button { + margin-bottom: 30px; + order: 1; + text-align: center + } + + .button { + width: 100%; + } + + #details { + margin: auto; order: 1; } - button { - width: 100%; + .hidden-on-mobile { + display: none; + } + + #main-frame-blocked { + display: flex; + flex-flow: column; } }
diff --git a/chrome/browser/resources/supervised_user_block_interstitial.html b/chrome/browser/resources/supervised_user_block_interstitial.html index 169662d..45946ee 100644 --- a/chrome/browser/resources/supervised_user_block_interstitial.html +++ b/chrome/browser/resources/supervised_user_block_interstitial.html
@@ -13,34 +13,52 @@ <body> <div id="main-frame-blocked"> - <div id="box"> - <div id="content-top"> - <img id="error-img"> - <div id="avatar-container"> - <img id="avatar-img" class="avatar-img" hidden> - <img id="second-avatar-img" class="avatar-img" hidden> + <div id="information-container"> + <h1> + <div id="block-page-message" i18n-content="blockPageMessage"></div> + <div id="request-failed-message" i18n-content="requestFailedMessage" + hidden></div> + <div id="request-sent-message" i18n-content="requestSentMessage" hidden> </div> - <h1> - <div id="block-page-message" i18n-content="blockPageMessage"></div> - <div id="request-failed-message" i18n-content="requestFailedMessage" - hidden></div> - <div id="request-sent-message" i18n-content="requestSentMessage" hidden> + </h1> + <div id="custodians-information" hidden> + <div id="custodian-information" class="custodian-information"> + <img id="custodian-avatar-img" class="avatar-img"> + <div id="custodian-contact"> + <div id="custodian-name" class="custodian-name"></div> + <div id="custodian-email" class="custodian-email"></div> </div> - <div id="block-reason-message" i18n-content="blockReasonMessage"></div> - </h1> - <div id="button-container"> - <button id="back-button" class="custom-appearance" - i18n-content="backButton"> - </button> - <button id="request-access-button" class="custom-appearance" - i18n-content="requestAccessButton"> - </button> </div> - <h1> - <a id="feedback-link" is="action-link" i18n-content="feedbackLink"></a> - </h1> + <div id="second-custodian-information" class="custodian-information" hidden> + <img id="second-custodian-avatar-img" class="avatar-img" hidden> + <div id="second-custodian-contact"> + <div id="second-custodian-name" class="custodian-name"></div> + <div id="second-custodian-email" class="custodian-email"></div> + </div> + </div> </div> </div> + <div id="button-container"> + <div id="details-button-container"> + <a id="show-details-link" i18n-content="showDetailsLink" + hidden class="button"> + </a> + <a id="hide-details-link" i18n-content="hideDetailsLink" + hidden class="button"></a> + <a id="back-button" i18n-content="backButton" + hidden class="button"></a> + </div> + <div id="request-access-button" class="button" + i18n-content="requestAccessButton"> + </div> + </div> + <h1> + <a id="feedback-link" is="action-link" i18n-content="feedbackLink"></a> + </h1> + <div id="details" hidden> + <p id="details-header" i18n-content="blockReasonHeader"></p> + <p id="details-message" i18n-content="blockReasonMessage"></p> + </div> </div> </body> </html>
diff --git a/chrome/browser/resources/supervised_user_block_interstitial.js b/chrome/browser/resources/supervised_user_block_interstitial.js index 55b652c..e41ab19 100644 --- a/chrome/browser/resources/supervised_user_block_interstitial.js +++ b/chrome/browser/resources/supervised_user_block_interstitial.js
@@ -22,25 +22,50 @@ } var avatarURL1x = loadTimeData.getString('avatarURL1x'); var avatarURL2x = loadTimeData.getString('avatarURL2x'); - if (avatarURL1x) { - $('avatar-img').style.content = makeImageSet(avatarURL1x, avatarURL2x); - $('avatar-img').hidden = false; - $('error-img').hidden = true; + var custodianName = loadTimeData.getString('custodianName'); + if (custodianName) { + $('custodians-information').hidden = false; + if (avatarURL1x) { + $('custodian-avatar-img').style.content = + makeImageSet(avatarURL1x, avatarURL2x); + } + $('custodian-name').innerHTML = custodianName; + $('custodian-email').innerHTML = loadTimeData.getString('custodianEmail'); var secondAvatarURL1x = loadTimeData.getString('secondAvatarURL1x'); var secondAvatarURL2x = loadTimeData.getString('secondAvatarURL2x'); - if (secondAvatarURL1x) { - $('second-avatar-img').style.content = - makeImageSet(secondAvatarURL1x, secondAvatarURL2x); - $('second-avatar-img').hidden = false; - // The avatar images should overlap a bit. - $('avatar-img').style.left = '6px'; - $('avatar-img').style.zIndex = '1'; - $('second-avatar-img').style.left = '-6px'; + var secondCustodianName = loadTimeData.getString('secondCustodianName'); + if (secondCustodianName) { + $('second-custodian-information').hidden = false; + $('second-custodian-avatar-img').hidden = false; + if (secondAvatarURL1x) { + $('second-custodian-avatar-img').style.content = + makeImageSet(secondAvatarURL1x, secondAvatarURL2x); + } + $('second-custodian-name').innerHTML = secondCustodianName; + $('second-custodian-email').innerHTML = loadTimeData.getString( + 'secondCustodianEmail'); } } + var showDetailsLink = loadTimeData.getString('showDetailsLink'); + $('show-details-link').hidden = !showDetailsLink; + $('back-button').hidden = showDetailsLink; $('back-button').onclick = function(event) { sendCommand('back'); }; + $('show-details-link').onclick = function(event) { + $('details').hidden = false; + $('show-details-link').hidden = true; + $('hide-details-link').hidden = false; + $('information-container').classList.add('hidden-on-mobile'); + $('request-access-button').classList.add('hidden-on-mobile'); + }; + $('hide-details-link').onclick = function(event) { + $('details').hidden = true; + $('show-details-link').hidden = false; + $('hide-details-link').hidden = true; + $('information-container').classList.remove('hidden-on-mobile'); + $('request-access-button').classList.remove('hidden-on-mobile'); + }; if (loadTimeData.getBoolean('showFeedbackLink')) { $('feedback-link').onclick = function(event) { sendCommand('feedback'); @@ -55,14 +80,15 @@ * @param {boolean} isSuccessful Whether the request was successful or not. */ function setRequestStatus(isSuccessful) { - $('error-img').hidden = true; $('block-page-message').hidden = true; if (isSuccessful) { $('request-failed-message').hidden = true; $('request-sent-message').hidden = false; - if ($('avatar-img').hidden) { - $('request-sent-message').style.marginTop = '40px'; - } + $('show-details-link').hidden = true; + $('hide-details-link').hidden = true; + $('details').hidden = true; + $('back-button').hidden = false; + $('request-access-button').hidden = true; } else { $('request-failed-message').hidden = false; $('request-access-button').hidden = false;
diff --git a/chrome/browser/safe_browsing/protocol_manager.cc b/chrome/browser/safe_browsing/protocol_manager.cc index beeaf02..189d4c0 100644 --- a/chrome/browser/safe_browsing/protocol_manager.cc +++ b/chrome/browser/safe_browsing/protocol_manager.cc
@@ -6,6 +6,7 @@ #include <utility> +#include "base/base64.h" #include "base/environment.h" #include "base/logging.h" #include "base/macros.h" @@ -92,6 +93,9 @@ const char kUmaHashResponseMetricName[] = "SB2.GetHashResponseOrErrorCode"; +// The V4 URL prefix where browser fetches hashes from the V4 server. +const char kSbV4UrlPrefix[] = "https://safebrowsing.googleapis.com/v4"; + // The default SBProtocolManagerFactory. class SBProtocolManagerFactoryImpl : public SBProtocolManagerFactory { public: @@ -196,6 +200,10 @@ STLDeleteContainerPairFirstPointers(hash_requests_.begin(), hash_requests_.end()); hash_requests_.clear(); + + STLDeleteContainerPairFirstPointers(v4_hash_requests_.begin(), + v4_hash_requests_.end()); + v4_hash_requests_.clear(); } // We can only have one update or chunk request outstanding, but there may be @@ -231,6 +239,58 @@ fetcher->Start(); } +std::string SafeBrowsingProtocolManager::GetV4HashRequest( + const std::vector<SBPrefix>& prefixes, + ThreatType threat_type) { + // Build the request. Client info and client states are not added to the + // request protocol buffer. Client info is passed as params in the url. + FindFullHashesRequest req; + ThreatInfo* info = req.mutable_threat_info(); + info->add_threat_types(threat_type); + info->add_platform_types(CHROME_PLATFORM); + info->add_threat_entry_types(URL_EXPRESSION); + for (const SBPrefix& prefix : prefixes) { + std::string hash(reinterpret_cast<const char*>(&prefix), sizeof(SBPrefix)); + info->add_threat_entries()->set_hash(hash); + } + + // Serialize and Base64 encode. + std::string req_data, req_base64; + req.SerializeToString(&req_data); + base::Base64Encode(req_data, &req_base64); + + return req_base64; +} + +void SafeBrowsingProtocolManager::GetV4FullHashes( + const std::vector<SBPrefix>& prefixes, + ThreatType threat_type, + FullHashCallback callback) { + DCHECK(CalledOnValidThread()); + // TODO(kcarattini): Implement backoff behavior. + + std::string req_base64 = GetV4HashRequest(prefixes, threat_type); + GURL gethash_url = GetV4HashUrl(req_base64); + + net::URLFetcher* fetcher = + net::URLFetcher::Create(url_fetcher_id_++, gethash_url, + net::URLFetcher::GET, this) + .release(); + // TODO(kcarattini): Implement a new response processor. + v4_hash_requests_[fetcher] = FullHashDetails(callback, + false /* is_download */); + + fetcher->SetLoadFlags(net::LOAD_DISABLE_CACHE); + fetcher->SetRequestContext(request_context_getter_.get()); + fetcher->Start(); +} + +void SafeBrowsingProtocolManager::GetFullHashesWithApis( + const std::vector<SBPrefix>& prefixes, + FullHashCallback callback) { + GetV4FullHashes(prefixes, API_ABUSE, callback); +} + void SafeBrowsingProtocolManager::GetNextUpdate() { DCHECK(CalledOnValidThread()); if (request_.get() || request_type_ != NO_REQUEST) @@ -761,6 +821,15 @@ return GURL(url); } +// The API hash call uses the pver4 Safe Browsing server. +GURL SafeBrowsingProtocolManager::GetV4HashUrl( + const std::string& request_base64) const { + std::string url = SafeBrowsingProtocolManagerHelper::ComposePver4Url( + kSbV4UrlPrefix, "encodedFullHashes", + request_base64, client_name_, version_); + return GURL(url); +} + GURL SafeBrowsingProtocolManager::NextChunkUrl(const std::string& url) const { DCHECK(CalledOnValidThread()); std::string next_url;
diff --git a/chrome/browser/safe_browsing/protocol_manager.h b/chrome/browser/safe_browsing/protocol_manager.h index 88835666..70e6bcb 100644 --- a/chrome/browser/safe_browsing/protocol_manager.h +++ b/chrome/browser/safe_browsing/protocol_manager.h
@@ -31,6 +31,7 @@ #include "chrome/browser/safe_browsing/protocol_manager_helper.h" #include "chrome/browser/safe_browsing/protocol_parser.h" #include "chrome/browser/safe_browsing/safe_browsing_util.h" +#include "components/safe_browsing_db/safebrowsing.pb.h" #include "net/url_request/url_fetcher_delegate.h" #include "net/url_request/url_request_status.h" #include "url/gurl.h" @@ -86,6 +87,19 @@ bool is_download, bool is_extended_reporting); + // Retrieve the full hash for a set of prefixes, and invoke the callback + // argument when the results are retrieved. The callback may be invoked + // synchronously. Uses the V4 Safe Browsing protocol. + virtual void GetV4FullHashes(const std::vector<SBPrefix>& prefixes, + ThreatType threat_type, + FullHashCallback callback); + + // Retrieve the full hash and API metadata for a set of prefixes, and invoke + // the callback argument when the results are retrieved. The callback may be + // invoked synchronously. Uses the V4 Safe Browsing protocol. + virtual void GetFullHashesWithApis(const std::vector<SBPrefix>& prefixes, + FullHashCallback callback); + // Forces the start of next update after |interval| time. void ForceScheduleNextUpdate(base::TimeDelta interval); @@ -188,6 +202,10 @@ FRIEND_TEST_ALL_PREFIXES(SafeBrowsingProtocolManagerTest, TestChunkStrings); FRIEND_TEST_ALL_PREFIXES(SafeBrowsingProtocolManagerTest, TestGetHashUrl); FRIEND_TEST_ALL_PREFIXES(SafeBrowsingProtocolManagerTest, + TestGetV4HashUrl); + FRIEND_TEST_ALL_PREFIXES(SafeBrowsingProtocolManagerTest, + TestGetV4HashRequest); + FRIEND_TEST_ALL_PREFIXES(SafeBrowsingProtocolManagerTest, TestGetHashBackOffTimes); FRIEND_TEST_ALL_PREFIXES(SafeBrowsingProtocolManagerTest, TestNextChunkUrl); FRIEND_TEST_ALL_PREFIXES(SafeBrowsingProtocolManagerTest, TestUpdateUrl); @@ -223,6 +241,16 @@ GURL GetHashUrl(bool is_extended_reporting) const; // Generates URL for reporting safe browsing hits for UMA users. + // Generates GetHashWithApis Pver4 request URL for retrieving full hashes. + // |request_base64| is the serialized FindFullHashesRequest protocol buffer + // encoded in base 64. + GURL GetV4HashUrl(const std::string& request_base64) const; + + // Fills a FindFullHashesRequest protocol buffer for an API_ABUSE request. + // Returns the serialized and base 64 encoded request as a string. + std::string GetV4HashRequest(const std::vector<SBPrefix>& prefixes, + ThreatType threat_type); + // Composes a ChunkUrl based on input string. GURL NextChunkUrl(const std::string& input) const; @@ -336,6 +364,7 @@ std::deque<ChunkUrl> chunk_request_urls_; HashRequests hash_requests_; + HashRequests v4_hash_requests_; // True if the service has been given an add/sub chunk but it hasn't been // added to the database yet.
diff --git a/chrome/browser/safe_browsing/protocol_manager_unittest.cc b/chrome/browser/safe_browsing/protocol_manager_unittest.cc index 60bd467..d250e95 100644 --- a/chrome/browser/safe_browsing/protocol_manager_unittest.cc +++ b/chrome/browser/safe_browsing/protocol_manager_unittest.cc
@@ -5,6 +5,7 @@ #include <vector> +#include "base/base64.h" #include "base/memory/scoped_ptr.h" #include "base/strings/stringprintf.h" #include "base/test/test_simple_task_runner.h" @@ -13,6 +14,7 @@ #include "chrome/browser/safe_browsing/chunk.pb.h" #include "chrome/browser/safe_browsing/protocol_manager.h" #include "chrome/browser/safe_browsing/safe_browsing_util.h" +#include "components/safe_browsing_db/safebrowsing.pb.h" #include "google_apis/google_api_keys.h" #include "net/base/escape.h" #include "net/base/load_flags.h" @@ -269,6 +271,57 @@ pm->GetHashUrl(true).spec()); } +TEST_F(SafeBrowsingProtocolManagerTest, TestGetV4HashUrl) { + scoped_ptr<SafeBrowsingProtocolManager> pm(CreateProtocolManager(NULL)); + + EXPECT_EQ( + "https://safebrowsing.googleapis.com/v4/encodedFullHashes/request_base64?" + "alt=proto&client_id=unittest&client_version=1.0" + key_param_, + pm->GetV4HashUrl("request_base64").spec()); + + // Additional query has no effect. + pm->set_additional_query(kAdditionalQuery); + EXPECT_EQ( + "https://safebrowsing.googleapis.com/v4/encodedFullHashes/request_base64?" + "alt=proto&client_id=unittest&client_version=1.0" + key_param_, + pm->GetV4HashUrl("request_base64").spec()); +} + +TEST_F(SafeBrowsingProtocolManagerTest, TestGetV4HashRequest) { + scoped_ptr<SafeBrowsingProtocolManager> pm(CreateProtocolManager(NULL)); + + FindFullHashesRequest req; + ThreatInfo* info = req.mutable_threat_info(); + info->add_threat_types(API_ABUSE); + info->add_platform_types(CHROME_PLATFORM); + info->add_threat_entry_types(URL_EXPRESSION); + + SBPrefix one = 1u; + SBPrefix two = 2u; + SBPrefix three = 3u; + std::string hash(reinterpret_cast<const char*>(&one), sizeof(SBPrefix)); + info->add_threat_entries()->set_hash(hash); + hash.clear(); + hash.append(reinterpret_cast<const char*>(&two), sizeof(SBPrefix)); + info->add_threat_entries()->set_hash(hash); + hash.clear(); + hash.append(reinterpret_cast<const char*>(&three), sizeof(SBPrefix)); + info->add_threat_entries()->set_hash(hash); + + // Serialize and Base64 encode. + std::string req_data, req_base64; + req.SerializeToString(&req_data); + base::Base64Encode(req_data, &req_base64); + + std::vector<SBPrefix> prefixes; + prefixes.push_back(one); + prefixes.push_back(two); + prefixes.push_back(three); + EXPECT_EQ( + req_base64, + pm->GetV4HashRequest(prefixes, API_ABUSE)); +} + TEST_F(SafeBrowsingProtocolManagerTest, TestUpdateUrl) { scoped_ptr<SafeBrowsingProtocolManager> pm(CreateProtocolManager(NULL));
diff --git a/chrome/browser/search/instant_service.cc b/chrome/browser/search/instant_service.cc index 9a89038..a89f381a 100644 --- a/chrome/browser/search/instant_service.cc +++ b/chrome/browser/search/instant_service.cc
@@ -73,7 +73,6 @@ InstantService::InstantService(Profile* profile) : profile_(profile), template_url_service_(TemplateURLServiceFactory::GetForProfile(profile_)), - omnibox_start_margin_(search::kDisableStartMargin), suggestions_service_(NULL), weak_ptr_factory_(this) { // The initialization below depends on a typical set of browser threads. Skip @@ -297,12 +296,6 @@ search::GetSearchURLs(profile_), search::GetNewTabPageURL(profile_))); } -void InstantService::OnOmniboxStartMarginChanged(int start_margin) { - omnibox_start_margin_ = start_margin; - FOR_EACH_OBSERVER(InstantServiceObserver, observers_, - OmniboxStartMarginChanged(omnibox_start_margin_)); -} - void InstantService::OnRendererProcessTerminated(int process_id) { process_ids_.erase(process_id);
diff --git a/chrome/browser/search/instant_service.h b/chrome/browser/search/instant_service.h index 96abba7..e711898 100644 --- a/chrome/browser/search/instant_service.h +++ b/chrome/browser/search/instant_service.h
@@ -87,16 +87,10 @@ // Sends the current set of search URLs to a renderer process. void SendSearchURLsToRenderer(content::RenderProcessHost* rph); - // Invoked to notify the Instant page that the omnibox start margin has - // changed. - void OnOmniboxStartMarginChanged(int start_margin); - InstantSearchPrerenderer* instant_search_prerenderer() { return instant_prerenderer_.get(); } - int omnibox_start_margin() const { return omnibox_start_margin_; } - private: friend class InstantExtendedTest; friend class InstantServiceTest; @@ -169,10 +163,6 @@ // Theme-related data for NTP overlay to adopt themes. scoped_ptr<ThemeBackgroundInfo> theme_info_; - // The start-edge margin of the omnibox, used by the Instant page to align - // text or assets properly with the omnibox. - int omnibox_start_margin_; - base::ObserverList<InstantServiceObserver> observers_; content::NotificationRegistrar registrar_;
diff --git a/chrome/browser/search/instant_service_observer.cc b/chrome/browser/search/instant_service_observer.cc index 2dd5a50..31fedf0 100644 --- a/chrome/browser/search/instant_service_observer.cc +++ b/chrome/browser/search/instant_service_observer.cc
@@ -14,7 +14,3 @@ void InstantServiceObserver::DefaultSearchProviderChanged( bool google_base_url_domain_changed) { } - -void InstantServiceObserver::OmniboxStartMarginChanged( - int omnibox_start_margin) { -}
diff --git a/chrome/browser/search/instant_service_observer.h b/chrome/browser/search/instant_service_observer.h index d38337d..0ed36b5 100644 --- a/chrome/browser/search/instant_service_observer.h +++ b/chrome/browser/search/instant_service_observer.h
@@ -26,9 +26,6 @@ virtual void DefaultSearchProviderChanged( bool google_base_url_domain_changed); - // Indicates that the omnibox start margin has changed. - virtual void OmniboxStartMarginChanged(int omnibox_start_margin); - protected: virtual ~InstantServiceObserver() {} };
diff --git a/chrome/browser/search/instant_service_unittest.cc b/chrome/browser/search/instant_service_unittest.cc index 4b5f0f7..dcfe926b 100644 --- a/chrome/browser/search/instant_service_unittest.cc +++ b/chrome/browser/search/instant_service_unittest.cc
@@ -30,7 +30,6 @@ class MockInstantServiceObserver : public InstantServiceObserver { public: MOCK_METHOD1(DefaultSearchProviderChanged, void(bool)); - MOCK_METHOD1(OmniboxStartMarginChanged, void(int)); }; class InstantServiceTest : public InstantUnitTestBase { @@ -51,10 +50,6 @@ return instant_service_->instant_search_prerenderer(); } - void UpdateOmniboxStartMargin(int start_margin) { - instant_service_->OnOmniboxStartMarginChanged(start_margin); - } - scoped_ptr<MockInstantServiceObserver> instant_service_observer_; }; @@ -159,13 +154,6 @@ EXPECT_NE(old_prerenderer, GetInstantSearchPrerenderer()); } -TEST_F(InstantServiceTest, OmniboxStartMarginChanged) { - int new_start_margin = 92; - EXPECT_CALL(*instant_service_observer_.get(), - OmniboxStartMarginChanged(new_start_margin)).Times(1); - UpdateOmniboxStartMargin(new_start_margin); -} - TEST_F(InstantServiceTest, GetSuggestionFromServiceSide) { auto profile = suggestions::SuggestionsProfile(); profile.add_suggestions();
diff --git a/chrome/browser/search/instant_unittest_base.cc b/chrome/browser/search/instant_unittest_base.cc index fc9dfb6..b6d87b8b 100644 --- a/chrome/browser/search/instant_unittest_base.cc +++ b/chrome/browser/search/instant_unittest_base.cc
@@ -54,9 +54,8 @@ data.SetShortName(base::UTF8ToUTF16(base_url)); data.SetKeyword(base::UTF8ToUTF16(base_url)); data.SetURL(base_url + "url?bar={searchTerms}"); - data.instant_url = base_url + - "instant?{google:omniboxStartMarginParameter}{google:forceInstantResults}" - "foo=foo#foo=foo&strk"; + data.instant_url = + base_url + "instant?{google:forceInstantResults}foo=foo#foo=foo&strk"; data.new_tab_url = base_url + "newtab"; data.alternate_urls.push_back(base_url + "alt#quux={searchTerms}"); data.search_terms_replacement_key = "strk";
diff --git a/chrome/browser/search_engines/ui_thread_search_terms_data.cc b/chrome/browser/search_engines/ui_thread_search_terms_data.cc index c9e66be..7c3366f 100644 --- a/chrome/browser/search_engines/ui_thread_search_terms_data.cc +++ b/chrome/browser/search_engines/ui_thread_search_terms_data.cc
@@ -16,8 +16,6 @@ #include "chrome/browser/search/instant_service.h" #include "chrome/browser/search/instant_service_factory.h" #include "chrome/browser/search/search.h" -#include "chrome/browser/themes/theme_service.h" -#include "chrome/browser/themes/theme_service_factory.h" #include "chrome/common/channel_info.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/pref_names.h" @@ -127,11 +125,6 @@ return "chrome-ext-ansg"; } -bool UIThreadSearchTermsData::IsShowingSearchTermsOnSearchResultsPages() const { - return search::IsInstantExtendedAPIEnabled() && - search::IsQueryExtractionEnabled(); -} - std::string UIThreadSearchTermsData::InstantExtendedEnabledParam( bool for_search) const { return search::InstantExtendedEnabledParam(for_search); @@ -142,33 +135,6 @@ return search::ForceInstantResultsParam(for_prerender); } -int UIThreadSearchTermsData::OmniboxStartMargin() const { - InstantService* instant_service = - InstantServiceFactory::GetForProfile(profile_); - // Android and iOS have no InstantService. - return instant_service ? instant_service->omnibox_start_margin() - : search::kDisableStartMargin; -} - -std::string UIThreadSearchTermsData::NTPIsThemedParam() const { - DCHECK(!BrowserThread::IsThreadInitialized(BrowserThread::UI) || - BrowserThread::CurrentlyOn(BrowserThread::UI)); -#if defined(ENABLE_THEMES) - if (!search::IsInstantExtendedAPIEnabled()) - return std::string(); - - // TODO(dhollowa): Determine fraction of custom themes that don't affect the - // NTP background and/or color. - ThemeService* theme_service = ThemeServiceFactory::GetForProfile(profile_); - // NTP is considered themed if the theme is not default and not native (GTK+). - if (theme_service && !theme_service->UsingDefaultTheme() && - !theme_service->UsingSystemTheme()) - return "es_th=1&"; -#endif // defined(ENABLE_THEMES) - - return std::string(); -} - // It's acutally OK to call this method on any thread, but it's currently placed // in UIThreadSearchTermsData since SearchTermsData cannot depend on src/chrome // as it is shared with iOS.
diff --git a/chrome/browser/search_engines/ui_thread_search_terms_data.h b/chrome/browser/search_engines/ui_thread_search_terms_data.h index 0b85ffdc..1f61378 100644 --- a/chrome/browser/search_engines/ui_thread_search_terms_data.h +++ b/chrome/browser/search_engines/ui_thread_search_terms_data.h
@@ -27,11 +27,8 @@ std::string GetSearchClient() const override; std::string GetSuggestClient() const override; std::string GetSuggestRequestIdentifier() const override; - bool IsShowingSearchTermsOnSearchResultsPages() const override; std::string InstantExtendedEnabledParam(bool for_search) const override; std::string ForceInstantResultsParam(bool for_prerender) const override; - int OmniboxStartMargin() const override; - std::string NTPIsThemedParam() const override; std::string GoogleImageSearchSource() const override; std::string GetAcceptLanguages() const override;
diff --git a/chrome/browser/signin/signin_promo.cc b/chrome/browser/signin/signin_promo.cc index 1a78b18..b3a8bef 100644 --- a/chrome/browser/signin/signin_promo.cc +++ b/chrome/browser/signin/signin_promo.cc
@@ -205,13 +205,12 @@ bool is_constrained) { CHECK_LT(static_cast<int>(access_point), static_cast<int>(signin_metrics::AccessPoint::ACCESS_POINT_MAX)); - CHECK_NE( - static_cast<int>(access_point), - static_cast<int>(signin_metrics::AccessPoint::ACCESS_POINT_UNSPECIFIED)); + CHECK_NE(static_cast<int>(access_point), + static_cast<int>(signin_metrics::AccessPoint::ACCESS_POINT_UNKNOWN)); CHECK_LT(static_cast<int>(reason), static_cast<int>(signin_metrics::Reason::REASON_MAX)); CHECK_NE(static_cast<int>(reason), - static_cast<int>(signin_metrics::Reason::REASON_UNSPECIFIED)); + static_cast<int>(signin_metrics::Reason::REASON_UNKNOWN_REASON)); std::string url(chrome::kChromeUIChromeSigninURL); base::StringAppendF(&url, "?%s=%d", kSignInPromoQueryKeyAccessPoint, @@ -294,29 +293,35 @@ std::string value; if (!net::GetValueForKeyInQuery(url, kSignInPromoQueryKeyAccessPoint, &value)) { - return signin_metrics::AccessPoint::ACCESS_POINT_UNSPECIFIED; + return signin_metrics::AccessPoint::ACCESS_POINT_UNKNOWN; } - int access_point = 0; - CHECK(base::StringToInt(value, &access_point)); - CHECK_GE( - access_point, - static_cast<int>(signin_metrics::AccessPoint::ACCESS_POINT_START_PAGE)); - CHECK_LT(access_point, - static_cast<int>(signin_metrics::AccessPoint::ACCESS_POINT_MAX)); + int access_point = -1; + base::StringToInt(value, &access_point); + if (access_point < + static_cast<int>( + signin_metrics::AccessPoint::ACCESS_POINT_START_PAGE) || + access_point >= + static_cast<int>(signin_metrics::AccessPoint::ACCESS_POINT_MAX)) { + return signin_metrics::AccessPoint::ACCESS_POINT_UNKNOWN; + } + return static_cast<signin_metrics::AccessPoint>(access_point); } signin_metrics::Reason GetSigninReasonForPromoURL(const GURL& url) { std::string value; if (!net::GetValueForKeyInQuery(url, kSignInPromoQueryKeyReason, &value)) - return signin_metrics::Reason::REASON_UNSPECIFIED; + return signin_metrics::Reason::REASON_UNKNOWN_REASON; - int reason = 0; - CHECK(base::StringToInt(value, &reason)); - CHECK_GE(reason, static_cast<int>( - signin_metrics::Reason::REASON_SIGNIN_PRIMARY_ACCOUNT)); - CHECK_LT(reason, static_cast<int>(signin_metrics::Reason::REASON_MAX)); + int reason = -1; + base::StringToInt(value, &reason); + if (reason < static_cast<int>( + signin_metrics::Reason::REASON_SIGNIN_PRIMARY_ACCOUNT) || + reason >= static_cast<int>(signin_metrics::Reason::REASON_MAX)) { + return signin_metrics::Reason::REASON_UNKNOWN_REASON; + } + return static_cast<signin_metrics::Reason>(reason); }
diff --git a/chrome/browser/supervised_user/supervised_user_content_provider_android.cc b/chrome/browser/supervised_user/supervised_user_content_provider_android.cc new file mode 100644 index 0000000..d5881a2 --- /dev/null +++ b/chrome/browser/supervised_user/supervised_user_content_provider_android.cc
@@ -0,0 +1,141 @@ +// 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/supervised_user/supervised_user_content_provider_android.h" + +#include "base/android/jni_android.h" +#include "base/android/jni_string.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/profiles/profile_manager.h" +#include "chrome/browser/supervised_user/supervised_user_interstitial.h" +#include "chrome/browser/supervised_user/supervised_user_service.h" +#include "chrome/browser/supervised_user/supervised_user_service_factory.h" +#include "jni/SupervisedUserContentProvider_jni.h" + +using base::android::JavaRef; +using base::android::JavaParamRef; +using base::android::ScopedJavaGlobalRef; +using base::android::AttachCurrentThread; + +namespace { + +class UrlFilterObserver : public SupervisedUserURLFilter::Observer { + public: + UrlFilterObserver(JNIEnv* env, + const ScopedJavaGlobalRef<jobject>& java_content_provider) + : java_content_provider_(java_content_provider) {} + + virtual ~UrlFilterObserver() {} + + private: + void OnSiteListUpdated() override { + Java_SupervisedUserContentProvider_onSupervisedUserFilterUpdated( + AttachCurrentThread(), java_content_provider_.obj()); + } + ScopedJavaGlobalRef<jobject> java_content_provider_; +}; + +} // namespace + +static jlong CreateSupervisedUserContentProvider( + JNIEnv* env, + const JavaParamRef<jobject>& caller) { + return reinterpret_cast<intptr_t>( + new SupervisedUserContentProvider(env, caller)); +} + +SupervisedUserContentProvider::SupervisedUserContentProvider( + JNIEnv* env, + const JavaParamRef<jobject>& caller) + : profile_(ProfileManager::GetLastUsedProfile()), + java_content_provider_(env, caller), + weak_factory_(this) { + if (profile_->IsSupervised()) { + SupervisedUserService* supervised_user_service = + SupervisedUserServiceFactory::GetForProfile(profile_); + SupervisedUserURLFilter* url_filter = + supervised_user_service->GetURLFilterForUIThread(); + url_filter->AddObserver(new UrlFilterObserver(env, java_content_provider_)); + } +} + +SupervisedUserContentProvider::~SupervisedUserContentProvider() {} + +void SupervisedUserContentProvider::ShouldProceed( + JNIEnv* env, + const JavaParamRef<jobject>& caller, + const JavaParamRef<jobject>& query_result_jobj, + const JavaParamRef<jstring>& url) { + if (!profile_->IsSupervised()) { + // User isn't supervised + Java_SupervisedUserQueryReply_onQueryComplete(env, query_result_jobj.obj(), + true, nullptr); + return; + } + SupervisedUserService* supervised_user_service = + SupervisedUserServiceFactory::GetForProfile(profile_); + SupervisedUserURLFilter* url_filter = + supervised_user_service->GetURLFilterForUIThread(); + url_filter->GetFilteringBehaviorForURLWithAsyncChecks( + GURL(base::android::ConvertJavaStringToUTF16(env, url)), + base::Bind(&SupervisedUserContentProvider::OnQueryComplete, + weak_factory_.GetWeakPtr(), + ScopedJavaGlobalRef<jobject>(env, query_result_jobj.obj()))); +} + +void SupervisedUserContentProvider::RequestInsert( + JNIEnv* env, + const JavaParamRef<jobject>& caller, + const JavaParamRef<jobject>& insert_result_jobj, + const JavaParamRef<jstring>& url) { + if (!profile_->IsSupervised()) + return; + SupervisedUserService* supervised_user_service = + SupervisedUserServiceFactory::GetForProfile(profile_); + supervised_user_service->AddURLAccessRequest( + GURL(base::android::ConvertJavaStringToUTF16(env, url)), + base::Bind(&SupervisedUserContentProvider::OnInsertRequestSendComplete, + weak_factory_.GetWeakPtr(), + ScopedJavaGlobalRef<jobject>(env, insert_result_jobj.obj()))); +} + +void SupervisedUserContentProvider::OnQueryComplete( + ScopedJavaGlobalRef<jobject> query_reply_jobj, + SupervisedUserURLFilter::FilteringBehavior behavior, + SupervisedUserURLFilter::FilteringBehaviorReason reason, + bool /* uncertain */) { + if (behavior != SupervisedUserURLFilter::BLOCK) { + Java_SupervisedUserQueryReply_onQueryComplete( + AttachCurrentThread(), query_reply_jobj.obj(), true, nullptr); + } else { + JNIEnv* env = AttachCurrentThread(); + Java_SupervisedUserQueryReply_onQueryComplete( + env, query_reply_jobj.obj(), false, + base::android::ConvertUTF8ToJavaString( + env, SupervisedUserInterstitial::GetHTMLContents(profile_, reason)) + .obj()); + } +} + +void SupervisedUserContentProvider::SetFilterForTesting(JNIEnv* env, + jobject caller) { + if (!profile_->IsSupervised()) + return; + SupervisedUserService* supervised_user_service = + SupervisedUserServiceFactory::GetForProfile(profile_); + SupervisedUserURLFilter* url_filter = + supervised_user_service->GetURLFilterForUIThread(); + url_filter->SetDefaultFilteringBehavior(SupervisedUserURLFilter::BLOCK); +} + +void SupervisedUserContentProvider::OnInsertRequestSendComplete( + ScopedJavaGlobalRef<jobject> insert_reply_jobj, + bool sent_ok) { + Java_SupervisedUserInsertReply_onInsertRequestSendComplete( + AttachCurrentThread(), insert_reply_jobj.obj(), sent_ok); +} + +bool SupervisedUserContentProvider::Register(JNIEnv* env) { + return RegisterNativesImpl(env); +}
diff --git a/chrome/browser/supervised_user/supervised_user_content_provider_android.h b/chrome/browser/supervised_user/supervised_user_content_provider_android.h new file mode 100644 index 0000000..d1b6431a --- /dev/null +++ b/chrome/browser/supervised_user/supervised_user_content_provider_android.h
@@ -0,0 +1,55 @@ +// 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_SUPERVISED_USER_SUPERVISED_USER_CONTENT_PROVIDER_ANDROID_H_ +#define CHROME_BROWSER_SUPERVISED_USER_SUPERVISED_USER_CONTENT_PROVIDER_ANDROID_H_ + +#include <jni.h> +#include "base/android/scoped_java_ref.h" +#include "base/macros.h" +#include "base/memory/weak_ptr.h" +#include "chrome/browser/supervised_user/supervised_user_url_filter.h" + +class SupervisedUserService; + +class SupervisedUserContentProvider { + public: + SupervisedUserContentProvider( + JNIEnv* env, + const base::android::JavaParamRef<jobject>& caller); + virtual ~SupervisedUserContentProvider(); + + void ShouldProceed( + JNIEnv* env, + const base::android::JavaParamRef<jobject>& caller, + const base::android::JavaParamRef<jobject>& query_result_jobj, + const base::android::JavaParamRef<jstring>& url); + void RequestInsert( + JNIEnv* env, + const base::android::JavaParamRef<jobject>& caller, + const base::android::JavaParamRef<jobject>& insert_result_jobj, + const base::android::JavaParamRef<jstring>& url); + + void SetFilterForTesting(JNIEnv* env, jobject caller); + + static bool Register(JNIEnv* env); + + private: + void OnQueryComplete( + base::android::ScopedJavaGlobalRef<jobject> query_reply_jobj, + SupervisedUserURLFilter::FilteringBehavior behavior, + SupervisedUserURLFilter::FilteringBehaviorReason reason, + bool /* uncertain */); + void OnInsertRequestSendComplete( + base::android::ScopedJavaGlobalRef<jobject> insert_reply_jobj, + bool sent_ok); + Profile* profile_; + base::android::ScopedJavaGlobalRef<jobject> java_content_provider_; + + base::WeakPtrFactory<SupervisedUserContentProvider> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(SupervisedUserContentProvider); +}; + +#endif // CHROME_BROWSER_SUPERVISED_USER_SUPERVISED_USER_CONTENT_PROVIDER_ANDROID_H_
diff --git a/chrome/browser/supervised_user/supervised_user_interstitial.cc b/chrome/browser/supervised_user/supervised_user_interstitial.cc index 1f7b606..21735f7 100644 --- a/chrome/browser/supervised_user/supervised_user_interstitial.cc +++ b/chrome/browser/supervised_user/supervised_user_interstitial.cc
@@ -198,37 +198,48 @@ return true; } -std::string SupervisedUserInterstitial::GetHTMLContents() { +// static +std::string SupervisedUserInterstitial::GetHTMLContents( + Profile* profile, + SupervisedUserURLFilter::FilteringBehaviorReason reason) { base::DictionaryValue strings; strings.SetString("blockPageTitle", l10n_util::GetStringUTF16(IDS_BLOCK_INTERSTITIAL_TITLE)); SupervisedUserService* supervised_user_service = - SupervisedUserServiceFactory::GetForProfile(profile_); + SupervisedUserServiceFactory::GetForProfile(profile); bool allow_access_requests = supervised_user_service->AccessRequestsEnabled(); strings.SetBoolean("allowAccessRequests", allow_access_requests); - std::string profile_image_url = profile_->GetPrefs()->GetString( + std::string profile_image_url = profile->GetPrefs()->GetString( prefs::kSupervisedUserCustodianProfileImageURL); strings.SetString("avatarURL1x", BuildAvatarImageUrl(profile_image_url, kAvatarSize1x)); strings.SetString("avatarURL2x", BuildAvatarImageUrl(profile_image_url, kAvatarSize2x)); - std::string profile_image_url2 = profile_->GetPrefs()->GetString( + std::string profile_image_url2 = profile->GetPrefs()->GetString( prefs::kSupervisedUserSecondCustodianProfileImageURL); strings.SetString("secondAvatarURL1x", BuildAvatarImageUrl(profile_image_url2, kAvatarSize1x)); strings.SetString("secondAvatarURL2x", BuildAvatarImageUrl(profile_image_url2, kAvatarSize2x)); - bool is_child_account = profile_->IsChild(); + bool is_child_account = profile->IsChild(); base::string16 custodian = base::UTF8ToUTF16(supervised_user_service->GetCustodianName()); base::string16 second_custodian = base::UTF8ToUTF16(supervised_user_service->GetSecondCustodianName()); + base::string16 custodian_email = + base::UTF8ToUTF16(supervised_user_service->GetCustodianEmailAddress()); + base::string16 second_custodian_email = base::UTF8ToUTF16( + supervised_user_service->GetSecondCustodianEmailAddress()); + strings.SetString("custodianName", custodian); + strings.SetString("custodianEmail", custodian_email); + strings.SetString("secondCustodianName", second_custodian); + strings.SetString("secondCustodianEmail", second_custodian_email); base::string16 block_message; if (allow_access_requests) { @@ -246,15 +257,15 @@ IDS_BLOCK_INTERSTITIAL_MESSAGE_ACCESS_REQUESTS_DISABLED); } strings.SetString("blockPageMessage", block_message); - strings.SetString("blockReasonMessage", is_child_account - ? l10n_util::GetStringUTF16( - SupervisedUserURLFilter::GetBlockMessageID(reason_)) - : base::string16()); - + strings.SetString("blockReasonMessage", l10n_util::GetStringUTF16( + SupervisedUserURLFilter::GetBlockMessageID( + reason, is_child_account, second_custodian.empty()))); + strings.SetString("blockReasonHeader", l10n_util::GetStringUTF16( + SupervisedUserURLFilter::GetBlockHeaderID(reason))); bool show_feedback = false; #if defined(GOOGLE_CHROME_BUILD) - show_feedback = is_child_account && - SupervisedUserURLFilter::ReasonIsAutomatic(reason_); + show_feedback = + is_child_account && SupervisedUserURLFilter::ReasonIsAutomatic(reason); #endif strings.SetBoolean("showFeedbackLink", show_feedback); strings.SetString("feedbackLink", @@ -262,9 +273,12 @@ strings.SetString("backButton", l10n_util::GetStringUTF16(IDS_BACK_BUTTON)); strings.SetString("requestAccessButton", l10n_util::GetStringUTF16( - is_child_account - ? IDS_CHILD_BLOCK_INTERSTITIAL_REQUEST_ACCESS_BUTTON - : IDS_BLOCK_INTERSTITIAL_REQUEST_ACCESS_BUTTON)); + IDS_BLOCK_INTERSTITIAL_REQUEST_ACCESS_BUTTON)); + + strings.SetString("showDetailsLink", l10n_util::GetStringUTF16( + IDS_BLOCK_INTERSTITIAL_SHOW_DETAILS)); + strings.SetString("hideDetailsLink", l10n_util::GetStringUTF16( + IDS_BLOCK_INTERSTITIAL_HIDE_DETAILS)); base::string16 request_sent_message; base::string16 request_failed_message; @@ -301,6 +315,10 @@ return webui::GetI18nTemplateHtml(html, &strings); } +std::string SupervisedUserInterstitial::GetHTMLContents() { + return GetHTMLContents(profile_, reason_); +} + void SupervisedUserInterstitial::CommandReceived(const std::string& command) { // For use in histograms. enum Commands { @@ -339,16 +357,22 @@ return; } + SupervisedUserService* supervised_user_service = + SupervisedUserServiceFactory::GetForProfile(profile_); + base::string16 second_custodian = + base::UTF8ToUTF16(supervised_user_service->GetSecondCustodianName()); + if (command == "\"feedback\"") { base::string16 reason = l10n_util::GetStringUTF16( - SupervisedUserURLFilter::GetBlockMessageID(reason_)); + SupervisedUserURLFilter::GetBlockMessageID( + reason_, true, second_custodian.empty())); std::string message = l10n_util::GetStringFUTF8( IDS_BLOCK_INTERSTITIAL_DEFAULT_FEEDBACK_TEXT, reason); #if BUILDFLAG(ANDROID_JAVA_UI) ReportChildAccountFeedback(web_contents_, message, url_); #else chrome::ShowFeedbackPage(chrome::FindBrowserWithWebContents(web_contents_), - message, std::string()); + message, std::string()); #endif return; }
diff --git a/chrome/browser/supervised_user/supervised_user_interstitial.h b/chrome/browser/supervised_user/supervised_user_interstitial.h index 5504b1d..f90bf1e 100644 --- a/chrome/browser/supervised_user/supervised_user_interstitial.h +++ b/chrome/browser/supervised_user/supervised_user_interstitial.h
@@ -36,6 +36,10 @@ SupervisedUserURLFilter::FilteringBehaviorReason reason, const base::Callback<void(bool)>& callback); + static std::string GetHTMLContents( + Profile* profile, + SupervisedUserURLFilter::FilteringBehaviorReason reason); + private: SupervisedUserInterstitial( content::WebContents* web_contents,
diff --git a/chrome/browser/supervised_user/supervised_user_url_filter.cc b/chrome/browser/supervised_user/supervised_user_url_filter.cc index 254bce9..acb9565 100644 --- a/chrome/browser/supervised_user/supervised_user_url_filter.cc +++ b/chrome/browser/supervised_user/supervised_user_url_filter.cc
@@ -193,16 +193,39 @@ } // static -int SupervisedUserURLFilter::GetBlockMessageID(FilteringBehaviorReason reason) { +int SupervisedUserURLFilter::GetBlockMessageID( + FilteringBehaviorReason reason, bool is_child_account, bool single_parent) { switch (reason) { case DEFAULT: - return IDS_SUPERVISED_USER_BLOCK_MESSAGE_DEFAULT; - case ASYNC_CHECKER: - return IDS_SUPERVISED_USER_BLOCK_MESSAGE_ASYNC_CHECKER; + return is_child_account ? + (single_parent ? + IDS_CHILD_BLOCK_MESSAGE_DEFAULT_SINGLE_PARENT : + IDS_CHILD_BLOCK_MESSAGE_DEFAULT_MULTI_PARENT) : + IDS_SUPERVISED_USER_BLOCK_MESSAGE_DEFAULT; case BLACKLIST: - return IDS_SUPERVISED_USER_BLOCK_MESSAGE_BLACKLIST; + case ASYNC_CHECKER: + return IDS_SUPERVISED_USER_BLOCK_MESSAGE_SAFE_SITES; case MANUAL: - return IDS_SUPERVISED_USER_BLOCK_MESSAGE_MANUAL; + return is_child_account ? + (single_parent ? + IDS_CHILD_BLOCK_MESSAGE_MANUAL_SINGLE_PARENT : + IDS_CHILD_BLOCK_MESSAGE_MANUAL_MULTI_PARENT) : + IDS_SUPERVISED_USER_BLOCK_MESSAGE_MANUAL; + } + NOTREACHED(); + return 0; +} + +// static +int SupervisedUserURLFilter::GetBlockHeaderID(FilteringBehaviorReason reason) { + switch (reason) { + case DEFAULT: + return IDS_SUPERVISED_USER_BLOCK_HEADER_DEFAULT; + case BLACKLIST: + case ASYNC_CHECKER: + return IDS_SUPERVISED_USER_BLOCK_HEADER_SAFE_SITES; + case MANUAL: + return IDS_SUPERVISED_USER_BLOCK_HEADER_MANUAL; } NOTREACHED(); return 0;
diff --git a/chrome/browser/supervised_user/supervised_user_url_filter.h b/chrome/browser/supervised_user/supervised_user_url_filter.h index 09b59558..50239f5 100644 --- a/chrome/browser/supervised_user/supervised_user_url_filter.h +++ b/chrome/browser/supervised_user/supervised_user_url_filter.h
@@ -77,7 +77,12 @@ static FilteringBehavior BehaviorFromInt(int behavior_value); - static int GetBlockMessageID(FilteringBehaviorReason reason); + static int GetBlockMessageID( + FilteringBehaviorReason reason, + bool is_child_account, + bool single_parent); + + static int GetBlockHeaderID(FilteringBehaviorReason reason); static bool ReasonIsAutomatic(FilteringBehaviorReason reason);
diff --git a/chrome/browser/sync/test/integration/sync_exponential_backoff_test.cc b/chrome/browser/sync/test/integration/sync_exponential_backoff_test.cc index 51a07cc..1910811 100644 --- a/chrome/browser/sync/test/integration/sync_exponential_backoff_test.cc +++ b/chrome/browser/sync/test/integration/sync_exponential_backoff_test.cc
@@ -11,6 +11,7 @@ #include "chrome/browser/sync/test/integration/sync_integration_test_util.h" #include "chrome/browser/sync/test/integration/sync_test.h" #include "components/browser_sync/browser/profile_sync_service.h" +#include "net/base/network_change_notifier.h" namespace { @@ -81,11 +82,24 @@ exponential_backoff_checker.Wait(); ASSERT_FALSE(exponential_backoff_checker.TimedOut()); + // Trigger network change notification and remember time when it happened. + // Ensure that scheduler runs canary job immediately. GetFakeServer()->EnableNetwork(); + net::NetworkChangeNotifier::NotifyObserversOfConnectionTypeChangeForTests( + net::NetworkChangeNotifier::CONNECTION_ETHERNET); + + base::Time network_notification_time = base::Time::Now(); // Verify that sync was able to recover. ASSERT_TRUE(AwaitCommitActivityCompletion(GetSyncService((0)))); ASSERT_TRUE(ModelMatchesVerifier(0)); + + // Verify that recovery time is short. Without canary job recovery time would + // be more than 5 seconds. + base::TimeDelta recovery_time = + GetSyncService(0)->GetLastSessionSnapshot().sync_start_time() - + network_notification_time; + ASSERT_LE(recovery_time, base::TimeDelta::FromSeconds(2)); } IN_PROC_BROWSER_TEST_F(SyncExponentialBackoffTest, TransientErrorTest) {
diff --git a/chrome/browser/task_management/providers/arc/arc_process_task.cc b/chrome/browser/task_management/providers/arc/arc_process_task.cc index c24e17b4..7ef3926b 100644 --- a/chrome/browser/task_management/providers/arc/arc_process_task.cc +++ b/chrome/browser/task_management/providers/arc/arc_process_task.cc
@@ -7,6 +7,7 @@ #include "base/i18n/rtl.h" #include "base/strings/utf_string_conversions.h" #include "chrome/grit/generated_resources.h" +#include "components/arc/arc_bridge_service.h" #include "ui/base/l10n/l10n_util.h" namespace task_management { @@ -44,4 +45,19 @@ return 0; } +void ArcProcessTask::Kill() { + arc::ProcessInstance* arc_process_instance = + arc::ArcBridgeService::Get()->process_instance(); + if (!arc_process_instance) { + LOG(ERROR) << "ARC process instance is not ready."; + return; + } + if (arc::ArcBridgeService::Get()->process_version() < 1) { + LOG(ERROR) << "ARC KillProcess IPC is unavailable."; + return; + } + arc_process_instance->KillProcess( + nspid_, "Killed manually from Task Manager"); +} + } // namespace task_management
diff --git a/chrome/browser/task_management/providers/arc/arc_process_task.h b/chrome/browser/task_management/providers/arc/arc_process_task.h index 1e03568..3a873597 100644 --- a/chrome/browser/task_management/providers/arc/arc_process_task.h +++ b/chrome/browser/task_management/providers/arc/arc_process_task.h
@@ -24,6 +24,7 @@ // task_management::Task: Type GetType() const override; int GetChildProcessUniqueID() const override; + void Kill() override; base::ProcessId nspid() const { return nspid_; } const std::string& process_name() const { return process_name_; }
diff --git a/chrome/browser/task_management/providers/browser_process_task.cc b/chrome/browser/task_management/providers/browser_process_task.cc index 854e850..2e98a539 100644 --- a/chrome/browser/task_management/providers/browser_process_task.cc +++ b/chrome/browser/task_management/providers/browser_process_task.cc
@@ -55,6 +55,10 @@ BrowserProcessTask::~BrowserProcessTask() { } +void BrowserProcessTask::Kill() { + // Never kill the browser process. +} + void BrowserProcessTask::Refresh(const base::TimeDelta& update_interval, int64_t refresh_flags) { Task::Refresh(update_interval, refresh_flags);
diff --git a/chrome/browser/task_management/providers/browser_process_task.h b/chrome/browser/task_management/providers/browser_process_task.h index fad5783..45ccad6de 100644 --- a/chrome/browser/task_management/providers/browser_process_task.h +++ b/chrome/browser/task_management/providers/browser_process_task.h
@@ -19,6 +19,7 @@ ~BrowserProcessTask() override; // task_management::Task: + void Kill() override; void Refresh(const base::TimeDelta& update_interval, int64_t refresh_flags) override; Type GetType() const override;
diff --git a/chrome/browser/task_management/providers/task.cc b/chrome/browser/task_management/providers/task.cc index 1912721..46d3ad8 100644 --- a/chrome/browser/task_management/providers/task.cc +++ b/chrome/browser/task_management/providers/task.cc
@@ -6,11 +6,13 @@ #include <stddef.h> +#include "base/process/process.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_info_cache.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/task_management/task_manager_observer.h" +#include "content/public/common/result_codes.h" namespace task_management { @@ -55,6 +57,12 @@ void Task::Activate() { } +void Task::Kill() { + DCHECK_NE(process_id(), base::GetCurrentProcId()); + base::Process process = base::Process::Open(process_id()); + process.Terminate(content::RESULT_CODE_KILLED, false); +} + void Task::Refresh(const base::TimeDelta& update_interval, int64_t refresh_flags) { if ((refresh_flags & REFRESH_TYPE_NETWORK_USAGE) == 0)
diff --git a/chrome/browser/task_management/providers/task.h b/chrome/browser/task_management/providers/task.h index 86dc3c6..c1f09be 100644 --- a/chrome/browser/task_management/providers/task.h +++ b/chrome/browser/task_management/providers/task.h
@@ -58,6 +58,9 @@ // (if possible). virtual void Activate(); + // Kills this task. + virtual void Kill(); + // Will be called to let the task refresh itself between refresh cycles. // |update_interval| is the time since the last task manager refresh. // the |refresh_flags| indicate which resources should be calculated on each
diff --git a/chrome/browser/task_management/sampling/task_manager_impl.cc b/chrome/browser/task_management/sampling/task_manager_impl.cc index 9f6e87b..7fee4a5 100644 --- a/chrome/browser/task_management/sampling/task_manager_impl.cc +++ b/chrome/browser/task_management/sampling/task_manager_impl.cc
@@ -72,6 +72,10 @@ GetTaskByTaskId(task_id)->Activate(); } +void TaskManagerImpl::KillTask(TaskId task_id) { + GetTaskByTaskId(task_id)->Kill(); +} + double TaskManagerImpl::GetCpuUsage(TaskId task_id) const { return GetTaskGroupByTaskId(task_id)->cpu_usage(); }
diff --git a/chrome/browser/task_management/sampling/task_manager_impl.h b/chrome/browser/task_management/sampling/task_manager_impl.h index eef0410..562b8dc 100644 --- a/chrome/browser/task_management/sampling/task_manager_impl.h +++ b/chrome/browser/task_management/sampling/task_manager_impl.h
@@ -35,6 +35,7 @@ // task_management::TaskManagerInterface: void ActivateTask(TaskId task_id) override; + void KillTask(TaskId task_id) override; double GetCpuUsage(TaskId task_id) const override; int64_t GetPhysicalMemoryUsage(TaskId task_id) const override; int64_t GetPrivateMemoryUsage(TaskId task_id) const override;
diff --git a/chrome/browser/task_management/task_manager_interface.h b/chrome/browser/task_management/task_manager_interface.h index 30379d66..d8dd95c 100644 --- a/chrome/browser/task_management/task_manager_interface.h +++ b/chrome/browser/task_management/task_manager_interface.h
@@ -47,6 +47,9 @@ // possible. virtual void ActivateTask(TaskId task_id) = 0; + // Kills the task with |task_id|. + virtual void KillTask(TaskId task_id) = 0; + // returns the CPU usage in percent for the process on which the task with // |task_id| is running during the current refresh cycle. virtual double GetCpuUsage(TaskId task_id) const = 0;
diff --git a/chrome/browser/task_management/test_task_manager.cc b/chrome/browser/task_management/test_task_manager.cc index c76c5b13..c49c5f1 100644 --- a/chrome/browser/task_management/test_task_manager.cc +++ b/chrome/browser/task_management/test_task_manager.cc
@@ -20,6 +20,9 @@ void TestTaskManager::ActivateTask(TaskId task_id) { } +void TestTaskManager::KillTask(TaskId task_id) { +} + double TestTaskManager::GetCpuUsage(TaskId task_id) const { return 0.0; }
diff --git a/chrome/browser/task_management/test_task_manager.h b/chrome/browser/task_management/test_task_manager.h index 156df2e..b666bb0 100644 --- a/chrome/browser/task_management/test_task_manager.h +++ b/chrome/browser/task_management/test_task_manager.h
@@ -23,6 +23,7 @@ // task_management::TaskManagerInterface: void ActivateTask(TaskId task_id) override; + void KillTask(TaskId task_id) override; double GetCpuUsage(TaskId task_id) const override; int64_t GetPhysicalMemoryUsage(TaskId task_id) const override; int64_t GetPrivateMemoryUsage(TaskId task_id) const override;
diff --git a/chrome/browser/themes/theme_properties.cc b/chrome/browser/themes/theme_properties.cc index ee099c51..c963ae6 100644 --- a/chrome/browser/themes/theme_properties.cc +++ b/chrome/browser/themes/theme_properties.cc
@@ -52,6 +52,8 @@ #endif // OS_MACOSX const SkColor kDefaultDetachedBookmarkBarBackground[] = { SK_ColorWHITE, SkColorSetRGB(0xF1, 0xF1, 0xF1)}; +const SkColor kDefaultDetachedBookmarkBarBackgroundIncognito[] = { + SK_ColorWHITE, SkColorSetRGB(0x32, 0x32, 0x32)}; const SkColor kDefaultColorTabText = SK_ColorBLACK; @@ -63,6 +65,8 @@ #endif // OS_MACOSX const SkColor kDefaultColorBookmarkText = SK_ColorBLACK; +const SkColor kDefaultColorBookmarkTextIncognito[] = {SK_ColorBLACK, + SK_ColorWHITE}; #if defined(OS_WIN) const SkColor kDefaultColorNTPBackground = @@ -97,8 +101,10 @@ // Defaults for properties which are not stored in the browser theme pack. const SkColor kDefaultColorControlBackground = SK_ColorWHITE; -const SkColor kDefaultColorToolbarSeparator[] = { +const SkColor kDefaultDetachedBookmarkBarSeparator[] = { SkColorSetRGB(170, 170, 171), SkColorSetRGB(182, 180, 182)}; +const SkColor kDefaultDetachedBookmarkBarSeparatorIncognito[] = { + SkColorSetRGB(170, 170, 171), SkColorSetRGB(0x28, 0x28, 0x28)}; #if defined(OS_MACOSX) const SkColor kDefaultColorToolbarButtonStroke = SkColorSetARGB(75, 81, 81, 81); @@ -284,7 +290,8 @@ return kDefaultColorBackgroundTabText[mode]; #endif // OS_MACOSX case COLOR_BOOKMARK_TEXT: - return kDefaultColorBookmarkText; + return otr ? kDefaultColorBookmarkTextIncognito[mode] + : kDefaultColorBookmarkText; case COLOR_NTP_BACKGROUND: return kDefaultColorNTPBackground; case COLOR_NTP_TEXT: @@ -311,9 +318,11 @@ return kDefaultColorControlBackground; case COLOR_TOOLBAR_SEPARATOR: case COLOR_DETACHED_BOOKMARK_BAR_SEPARATOR: - return kDefaultColorToolbarSeparator[mode]; + return otr ? kDefaultDetachedBookmarkBarSeparatorIncognito[mode] + : kDefaultDetachedBookmarkBarSeparator[mode]; case COLOR_DETACHED_BOOKMARK_BAR_BACKGROUND: - return kDefaultDetachedBookmarkBarBackground[mode]; + return otr ? kDefaultDetachedBookmarkBarBackgroundIncognito[mode] + : kDefaultDetachedBookmarkBarBackground[mode]; #if defined(OS_MACOSX) case COLOR_TOOLBAR_BUTTON_STROKE: return kDefaultColorToolbarButtonStroke;
diff --git a/chrome/browser/translate/chrome_translate_client.cc b/chrome/browser/translate/chrome_translate_client.cc index 196ff58c..3539ee0 100644 --- a/chrome/browser/translate/chrome_translate_client.cc +++ b/chrome/browser/translate/chrome_translate_client.cc
@@ -11,6 +11,7 @@ #include "base/prefs/pref_service.h" #include "base/strings/string_split.h" #include "build/build_config.h" +#include "chrome/browser/browser_process.h" #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/infobars/infobar_service.h" #include "chrome/browser/profiles/profile.h" @@ -35,6 +36,7 @@ #include "components/translate/core/browser/translate_manager.h" #include "components/translate/core/browser/translate_prefs.h" #include "components/translate/core/common/language_detection_details.h" +#include "components/variations/service/variations_service.h" #include "content/public/browser/notification_service.h" #include "content/public/browser/render_view_host.h" #include "content/public/browser/web_contents.h" @@ -99,8 +101,21 @@ #else const char* preferred_languages_prefs = NULL; #endif - return scoped_ptr<translate::TranslatePrefs>(new translate::TranslatePrefs( - prefs, prefs::kAcceptLanguages, preferred_languages_prefs)); + scoped_ptr<translate::TranslatePrefs> translate_prefs( + new translate::TranslatePrefs(prefs, prefs::kAcceptLanguages, + preferred_languages_prefs)); + + // We need to obtain the country here, since it comes from VariationsService. + // components/ does not have access to that. + DCHECK(g_browser_process); + variations::VariationsService* variations_service = + g_browser_process->variations_service(); + if (variations_service) { + translate_prefs->SetCountry( + variations_service->GetStoredPermanentCountry()); + } + + return translate_prefs; } // static
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index 13be4f6..b623e2e6 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -260,12 +260,6 @@ ".", "//chrome") } - if (is_android) { - sources += - rebase_path(gypi_values.chrome_browser_ui_views_android_sources, - ".", - "//chrome") - } } else { # !toolkit_views if (!is_ios) {
diff --git a/chrome/browser/ui/app_list/arc/arc_app_item.cc b/chrome/browser/ui/app_list/arc/arc_app_item.cc index 1fa0b9e..37164851 100644 --- a/chrome/browser/ui/app_list/arc/arc_app_item.cc +++ b/chrome/browser/ui/app_list/arc/arc_app_item.cc
@@ -5,6 +5,7 @@ #include "chrome/browser/ui/app_list/arc/arc_app_item.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/app_list/app_list_controller_delegate.h" #include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h" #include "components/arc/arc_bridge_service.h" #include "content/public/browser/browser_thread.h" @@ -72,6 +73,10 @@ } app_instance->LaunchApp(app_info->package, app_info->activity); + + // Manually close app_list view because focus is not changed on ARC app start, + // and current view remains active. + GetController()->DismissView(); } void ArcAppItem::SetReady(bool ready) {
diff --git a/chrome/browser/ui/ash/cast_config_delegate_media_router.cc b/chrome/browser/ui/ash/cast_config_delegate_media_router.cc index 31c8c11..980feda 100644 --- a/chrome/browser/ui/ash/cast_config_delegate_media_router.cc +++ b/chrome/browser/ui/ash/cast_config_delegate_media_router.cc
@@ -29,6 +29,15 @@ return router; } +// The media router will sometimes append " (Tab)" to the tab title. This +// function will remove that data from the inout param |string|. +std::string StripEndingTab(const std::string& str) { + static const char ending[] = " (Tab)"; + if (base::EndsWith(str, ending, base::CompareCase::SENSITIVE)) + return str.substr(0, str.size() - strlen(ending)); + return str; +} + } // namespace // This class caches the values that the observers give us so we can query them @@ -43,6 +52,10 @@ explicit CastDeviceCache(ash::CastConfigDelegate* cast_config_delegate); ~CastDeviceCache() override; + // This may call cast_config_delegate->RequestDeviceRefresh() before + // returning. + void Init(); + const MediaSinks& sinks() const { return sinks_; } const MediaRoutes& routes() const { return routes_; } @@ -67,11 +80,14 @@ MediaSinksObserver(GetMediaRouter(), media_router::MediaSourceForDesktop()), cast_config_delegate_(cast_config_delegate) { - CHECK(MediaSinksObserver::Init()); } CastDeviceCache::~CastDeviceCache() {} +void CastDeviceCache::Init() { + CHECK(MediaSinksObserver::Init()); +} + void CastDeviceCache::OnSinksReceived(const MediaSinks& sinks) { sinks_ = sinks; cast_config_delegate_->RequestDeviceRefresh(); @@ -104,8 +120,10 @@ CastDeviceCache* CastConfigDelegateMediaRouter::devices() { // The CastDeviceCache instance is lazily allocated because the MediaRouter // component is not ready when the constructor is invoked. - if (!devices_ && GetMediaRouter() != nullptr) + if (!devices_ && GetMediaRouter() != nullptr) { devices_.reset(new CastDeviceCache(this)); + devices_->Init(); + } return devices_.get(); } @@ -121,9 +139,56 @@ } void CastConfigDelegateMediaRouter::RequestDeviceRefresh() { - // TODO(jdufault): Temporarily disable mediarouter integration. See - // crbug.com/571111. - return; + // The media router component isn't ready yet. + if (!devices()) + return; + + // Build the old-style ReceiverAndActivity set out of the MediaRouter + // source/sink/route setup. We first map the existing sinks, and then we + // update those sinks with activity information. + + ReceiversAndActivities items; + + for (const media_router::MediaSink& sink : devices()->sinks()) { + ReceiverAndActivity ra; + ra.receiver.id = sink.id(); + ra.receiver.name = base::UTF8ToUTF16(sink.name()); + items.push_back(ra); + } + + for (const media_router::MediaRoute& route : devices()->routes()) { + if (!route.for_display()) + continue; + + for (ReceiverAndActivity& item : items) { + if (item.receiver.id == route.media_sink_id()) { + item.activity.id = route.media_route_id(); + item.activity.title = + base::UTF8ToUTF16(StripEndingTab(route.description())); + item.activity.is_local_source = route.is_local(); + + if (route.is_local()) { + // TODO(jdufault): Once the extension backend is removed, we can + // remove tab_id and specify the Desktop/Tab capture directly. + // crbug.com/551132. + // TODO(jdufault): We currently don't actually display DIAL casts to + // the user even though we have all the information necessary. We'll + // do this once the extension backend is gone because supporting both + // introduces extra complexity. crbug.com/551132. + + // Default to a tab/app capture. This will display the media router + // description. This means we will properly support DIAL casts. + item.activity.tab_id = 0; + if (media_router::IsDesktopMirroringMediaSource(route.media_source())) + item.activity.tab_id = Activity::TabId::DESKTOP; + } + + break; + } + } + } + + callback_list_.Notify(items); } void CastConfigDelegateMediaRouter::CastToReceiver(
diff --git a/chrome/browser/ui/ash/system_tray_tray_cast_browsertest_media_router_chromeos.cc b/chrome/browser/ui/ash/system_tray_tray_cast_browsertest_media_router_chromeos.cc index 0994de5..0f236f444 100644 --- a/chrome/browser/ui/ash/system_tray_tray_cast_browsertest_media_router_chromeos.cc +++ b/chrome/browser/ui/ash/system_tray_tray_cast_browsertest_media_router_chromeos.cc
@@ -105,7 +105,7 @@ // Verifies that we only show the tray view if there are available cast // targets/sinks. IN_PROC_BROWSER_TEST_F(SystemTrayTrayCastMediaRouterChromeOSTest, - DISABLED_VerifyCorrectVisiblityWithSinks) { + VerifyCorrectVisiblityWithSinks) { ash::TrayCast* tray = GetTrayCast(); ash::TrayCastTestAPI test_api(tray); EXPECT_TRUE(test_api.IsTrayInitialized()); @@ -145,7 +145,7 @@ // we display the correct cast session if there are multiple active casting // sessions. IN_PROC_BROWSER_TEST_F(SystemTrayTrayCastMediaRouterChromeOSTest, - DISABLED_VerifyCastingShowsCastView) { + VerifyCastingShowsCastView) { ash::TrayCast* tray = GetTrayCast(); ash::TrayCastTestAPI test_api(tray); EXPECT_TRUE(test_api.IsTrayInitialized());
diff --git a/chrome/browser/ui/autofill/autofill_popup_controller.h b/chrome/browser/ui/autofill/autofill_popup_controller.h index 0845688f..8f22698 100644 --- a/chrome/browser/ui/autofill/autofill_popup_controller.h +++ b/chrome/browser/ui/autofill/autofill_popup_controller.h
@@ -41,9 +41,6 @@ // rather than an Autofill suggestion. virtual bool IsWarning(size_t index) const = 0; - // Updates the bounds of the popup and initiates a redraw. - virtual void SetPopupBounds(const gfx::Rect& bounds) = 0; - // Returns the bounds of the item at |index| in the popup, relative to // the top left of the popup. virtual gfx::Rect GetRowBounds(size_t index) = 0;
diff --git a/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc b/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc index 3d09213..3902ab9 100644 --- a/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc +++ b/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc
@@ -42,7 +42,7 @@ // The vertical height of a separator in pixels. const size_t kSeparatorHeight = 1; -#if !defined(OS_ANDROID) || defined(USE_AURA) +#if !defined(OS_ANDROID) // Size difference between name and label in pixels. const int kLabelFontSizeDelta = -2; @@ -64,7 +64,7 @@ { "jcbCC", IDR_AUTOFILL_CC_GENERIC }, { "masterCardCC", IDR_AUTOFILL_CC_MASTERCARD }, { "visaCC", IDR_AUTOFILL_CC_VISA }, -#if defined(OS_ANDROID) && !defined(USE_AURA) +#if defined(OS_ANDROID) { "scanCreditCardIcon", IDR_AUTOFILL_CC_SCAN_NEW }, { "settings", IDR_AUTOFILL_SETTINGS }, #endif @@ -115,7 +115,7 @@ controller_common_->SetKeyPressCallback( base::Bind(&AutofillPopupControllerImpl::HandleKeyPressEvent, base::Unretained(this))); -#if !defined(OS_ANDROID) || defined(USE_AURA) +#if !defined(OS_ANDROID) label_font_list_ = value_font_list_.DeriveWithSizeDelta(kLabelFontSizeDelta); title_font_list_ = value_font_list_.DeriveWithStyle(gfx::Font::BOLD); #if defined(OS_MACOSX) @@ -135,7 +135,7 @@ DCHECK_EQ(suggestions_.size(), elided_values_.size()); DCHECK_EQ(suggestions_.size(), elided_labels_.size()); -#if !defined(OS_ANDROID) || defined(USE_AURA) +#if !defined(OS_ANDROID) // Android displays the long text with ellipsis using the view attributes. UpdatePopupBounds(); @@ -312,7 +312,7 @@ } void AutofillPopupControllerImpl::UpdateBoundsAndRedrawPopup() { -#if !defined(OS_ANDROID) || defined(USE_AURA) +#if !defined(OS_ANDROID) // TODO(csharp): Since UpdatePopupBounds can change the position of the popup, // the popup could end up jumping from above the element to below it. // It is unclear if it is better to keep the popup where it was, or if it @@ -361,10 +361,10 @@ } } -#if defined(OS_ANDROID) && !defined(USE_AURA) +#if defined(OS_ANDROID) if (result == IDR_AUTOFILL_CC_SCAN_NEW && IsKeyboardAccessoryEnabled()) result = IDR_AUTOFILL_CC_SCAN_NEW_KEYBOARD_ACCESSORY; -#endif +#endif // OS_ANDROID return result; } @@ -386,11 +386,6 @@ GetRowHeightFromId(suggestions_[index].frontend_id)); } -void AutofillPopupControllerImpl::SetPopupBounds(const gfx::Rect& bounds) { - popup_bounds_ = bounds; - UpdateBoundsAndRedrawPopup(); -} - const gfx::Rect& AutofillPopupControllerImpl::popup_bounds() const { return popup_bounds_; } @@ -462,7 +457,7 @@ return true; } -#if !defined(OS_ANDROID) || defined(USE_AURA) +#if !defined(OS_ANDROID) const gfx::FontList& AutofillPopupControllerImpl::GetValueFontListForRow( size_t index) const { if (suggestions_[index].frontend_id == POPUP_ITEM_ID_WARNING_MESSAGE) @@ -605,7 +600,7 @@ view_->InvalidateRow(row); } -#if !defined(OS_ANDROID) || defined(USE_AURA) +#if !defined(OS_ANDROID) int AutofillPopupControllerImpl::GetDesiredPopupWidth() const { int popup_width = controller_common_->RoundedElementBounds().width(); for (size_t i = 0; i < GetLineCount(); ++i) { @@ -659,7 +654,7 @@ popup_bounds_ = controller_common_->GetPopupBounds(popup_width, popup_height); } -#endif +#endif // !defined(OS_ANDROID) WeakPtr<AutofillPopupControllerImpl> AutofillPopupControllerImpl::GetWeakPtr() { return weak_ptr_factory_.GetWeakPtr();
diff --git a/chrome/browser/ui/autofill/autofill_popup_controller_impl.h b/chrome/browser/ui/autofill/autofill_popup_controller_impl.h index ef6b4f1..2f67f45 100644 --- a/chrome/browser/ui/autofill/autofill_popup_controller_impl.h +++ b/chrome/browser/ui/autofill/autofill_popup_controller_impl.h
@@ -79,7 +79,6 @@ int GetIconResourceID(const base::string16& resource_name) const override; bool IsWarning(size_t index) const override; gfx::Rect GetRowBounds(size_t index) override; - void SetPopupBounds(const gfx::Rect& bounds) override; const gfx::Rect& popup_bounds() const override; gfx::NativeView container_view() override; const gfx::RectF& element_bounds() const override; @@ -93,7 +92,7 @@ base::string16* title, base::string16* body) override; bool RemoveSuggestion(int list_index) override; -#if !defined(OS_ANDROID) || defined(USE_AURA) +#if !defined(OS_ANDROID) const gfx::FontList& GetValueFontListForRow(size_t index) const override; const gfx::FontList& GetLabelFontList() const override; #endif @@ -136,7 +135,7 @@ virtual void InvalidateRow(size_t row); // Protected so tests can access. -#if !defined(OS_ANDROID) || defined(USE_AURA) +#if !defined(OS_ANDROID) // Calculates the desired width of the popup based on its contents. int GetDesiredPopupWidth() const; @@ -160,7 +159,7 @@ // when the popup is reused it doesn't leak values between uses. void ClearState(); -#if !defined(OS_ANDROID) || defined(USE_AURA) +#if !defined(OS_ANDROID) // Calculates and sets the bounds of the popup, including placing it properly // to prevent it from going off the screen. void UpdatePopupBounds(); @@ -183,7 +182,7 @@ std::vector<base::string16> elided_values_; std::vector<base::string16> elided_labels_; -#if !defined(OS_ANDROID) || defined(USE_AURA) +#if !defined(OS_ANDROID) // The fonts for the popup text. gfx::FontList value_font_list_; gfx::FontList label_font_list_;
diff --git a/chrome/browser/ui/autofill/autofill_popup_controller_unittest.cc b/chrome/browser/ui/autofill/autofill_popup_controller_unittest.cc index c54b2f1..4fa3e217 100644 --- a/chrome/browser/ui/autofill/autofill_popup_controller_unittest.cc +++ b/chrome/browser/ui/autofill/autofill_popup_controller_unittest.cc
@@ -95,7 +95,6 @@ } // Making protected functions public for testing - using AutofillPopupControllerImpl::SetPopupBounds; using AutofillPopupControllerImpl::GetLineCount; using AutofillPopupControllerImpl::GetSuggestionAt; using AutofillPopupControllerImpl::GetElidedValueAt; @@ -185,18 +184,6 @@ testing::NiceMock<TestAutofillPopupController>* autofill_popup_controller_; }; -TEST_F(AutofillPopupControllerUnitTest, SetBounds) { - // Ensure the popup size can be set and causes a redraw. - gfx::Rect popup_bounds(10, 10, 100, 100); - - EXPECT_CALL(*autofill_popup_controller_, - UpdateBoundsAndRedrawPopup()); - - popup_controller()->SetPopupBounds(popup_bounds); - - EXPECT_EQ(popup_bounds, popup_controller()->popup_bounds()); -} - TEST_F(AutofillPopupControllerUnitTest, ChangeSelectedLine) { // Set up the popup. std::vector<Suggestion> suggestions;
diff --git a/chrome/browser/ui/bluetooth/bluetooth_chooser_bubble_delegate.cc b/chrome/browser/ui/bluetooth/bluetooth_chooser_bubble_delegate.cc index c0f23d3..8ca66407 100644 --- a/chrome/browser/ui/bluetooth/bluetooth_chooser_bubble_delegate.cc +++ b/chrome/browser/ui/bluetooth/bluetooth_chooser_bubble_delegate.cc
@@ -16,20 +16,22 @@ bluetooth_chooser_->set_bluetooth_chooser_bubble_delegate(nullptr); } -const std::vector<base::string16>& BluetoothChooserBubbleDelegate::GetOptions() - const { - return device_names_; +size_t BluetoothChooserBubbleDelegate::NumOptions() const { + return device_names_and_ids_.size(); } -// TODO(juncai): Change the index type to be size_t in base class to avoid -// extra type casting. -void BluetoothChooserBubbleDelegate::Select(int index) { - size_t idx = static_cast<size_t>(index); - size_t num_options = device_ids_.size(); - DCHECK_LT(idx, num_options); +const base::string16& BluetoothChooserBubbleDelegate::GetOption( + size_t index) const { + DCHECK_LT(index, device_names_and_ids_.size()); + return device_names_and_ids_[index].first; +} + +void BluetoothChooserBubbleDelegate::Select(size_t index) { + DCHECK_LT(index, device_names_and_ids_.size()); if (bluetooth_chooser_) { bluetooth_chooser_->CallEventHandler( - content::BluetoothChooser::Event::SELECTED, device_ids_[idx]); + content::BluetoothChooser::Event::SELECTED, + device_names_and_ids_[index].second); } if (bubble_controller_) @@ -56,25 +58,21 @@ void BluetoothChooserBubbleDelegate::AddDevice( const std::string& device_id, const base::string16& device_name) { - DCHECK(!ContainsValue(device_ids_, device_id)); - device_names_.push_back(device_name); - device_ids_.push_back(device_id); - // TODO(juncai): Change OnOptionAdded's index type to be size_t to avoid - // extra type casting here. + device_names_and_ids_.push_back(std::make_pair(device_name, device_id)); if (observer()) - observer()->OnOptionAdded(static_cast<int>(device_names_.size()) - 1); + observer()->OnOptionAdded(device_names_and_ids_.size() - 1); } void BluetoothChooserBubbleDelegate::RemoveDevice( const std::string& device_id) { - auto iter = std::find(device_ids_.begin(), device_ids_.end(), device_id); - if (iter != device_ids_.end()) { - size_t index = iter - device_ids_.begin(); - device_ids_.erase(iter); - device_names_.erase(device_names_.begin() + index); - // TODO(juncai): Change OnOptionRemoved's index type to be size_t to avoid - // extra type casting here. - if (observer()) - observer()->OnOptionRemoved(index); + for (auto it = device_names_and_ids_.begin(); + it != device_names_and_ids_.end(); ++it) { + if (it->second == device_id) { + size_t index = it - device_names_and_ids_.begin(); + device_names_and_ids_.erase(it); + if (observer()) + observer()->OnOptionRemoved(index); + return; + } } }
diff --git a/chrome/browser/ui/bluetooth/bluetooth_chooser_bubble_delegate.h b/chrome/browser/ui/bluetooth/bluetooth_chooser_bubble_delegate.h index e4d2d4a..a1555d7 100644 --- a/chrome/browser/ui/bluetooth/bluetooth_chooser_bubble_delegate.h +++ b/chrome/browser/ui/bluetooth/bluetooth_chooser_bubble_delegate.h
@@ -24,8 +24,9 @@ ~BluetoothChooserBubbleDelegate() override; // ChooserBubbleDelegate: - const std::vector<base::string16>& GetOptions() const override; - void Select(int index) override; + size_t NumOptions() const override; + const base::string16& GetOption(size_t index) const override; + void Select(size_t index) override; void Cancel() override; void Close() override; @@ -45,17 +46,8 @@ } private: - // TODO(juncai): use std::vector<std::pair<base::string16, std::string>> - // here since the lengths can't get out of sync and each pair of items - // is tightly associated. - // Also need to change ChooserBubbleDelegate::GetOptions to be: - // size_t NumOptions() - // const base::string16& GetOption(size_t index) - // - // |device_names_| and |device_ids_| have the same length. - // device_names_[i] is the name for the device with id device_ids_[i]. - std::vector<base::string16> device_names_; - std::vector<std::string> device_ids_; + // Each pair is a (device name, device id). + std::vector<std::pair<base::string16, std::string>> device_names_and_ids_; BluetoothChooserDesktop* bluetooth_chooser_; BubbleReference bubble_controller_;
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc index 1f41d7c9..8dd3a53 100644 --- a/chrome/browser/ui/browser.cc +++ b/chrome/browser/ui/browser.cc
@@ -1620,14 +1620,17 @@ } } -void Browser::ContentsMouseEvent( - WebContents* source, const gfx::Point& location, bool motion) { - if (!GetStatusBubble()) +void Browser::ContentsMouseEvent(WebContents* source, + const gfx::Point& location, + bool motion, + bool exited) { + // Mouse motion events update the status bubble, if it exists. + if (!GetStatusBubble() || (!motion && !exited)) return; if (source == tab_strip_model_->GetActiveWebContents()) { - GetStatusBubble()->MouseMoved(location, !motion); - if (!motion) + GetStatusBubble()->MouseMoved(location, exited); + if (exited) GetStatusBubble()->SetURL(GURL(), std::string()); } }
diff --git a/chrome/browser/ui/browser.h b/chrome/browser/ui/browser.h index e3f6b8832..13ec6b46 100644 --- a/chrome/browser/ui/browser.h +++ b/chrome/browser/ui/browser.h
@@ -575,7 +575,8 @@ void UpdateTargetURL(content::WebContents* source, const GURL& url) override; void ContentsMouseEvent(content::WebContents* source, const gfx::Point& location, - bool motion) override; + bool motion, + bool exited) override; void ContentsZoomChange(bool zoom_in) override; bool TakeFocus(content::WebContents* source, bool reverse) override; gfx::Rect GetRootWindowResizerRect() const override;
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_main_container.mm b/chrome/browser/ui/cocoa/autofill/autofill_main_container.mm index b406df2..e4e9727 100644 --- a/chrome/browser/ui/cocoa/autofill/autofill_main_container.mm +++ b/chrome/browser/ui/cocoa/autofill/autofill_main_container.mm
@@ -17,7 +17,7 @@ #import "chrome/browser/ui/cocoa/autofill/autofill_tooltip_controller.h" #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_button.h" #import "chrome/browser/ui/cocoa/key_equivalent_constants.h" -#include "grit/theme_resources.h" +#include "grit/components_scaled_resources.h" #include "skia/ext/skia_utils_mac.h" #import "third_party/google_toolbox_for_mac/src/AppKit/GTMUILocalizerAndLayoutTweaker.h" #import "ui/base/cocoa/controls/blue_label_button.h"
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_notification_controller.mm b/chrome/browser/ui/cocoa/autofill/autofill_notification_controller.mm index 3bb12638..e7b7f954 100644 --- a/chrome/browser/ui/cocoa/autofill/autofill_notification_controller.mm +++ b/chrome/browser/ui/cocoa/autofill/autofill_notification_controller.mm
@@ -15,7 +15,7 @@ #include "chrome/browser/ui/chrome_style.h" #include "chrome/browser/ui/cocoa/autofill/autofill_dialog_constants.h" #import "chrome/browser/ui/cocoa/autofill/autofill_tooltip_controller.h" -#include "grit/theme_resources.h" +#include "grit/components_scaled_resources.h" #include "skia/ext/skia_utils_mac.h" #import "ui/base/cocoa/controls/hyperlink_text_view.h"
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_section_container.mm b/chrome/browser/ui/cocoa/autofill/autofill_section_container.mm index cbd3bdf8..432582ef 100644 --- a/chrome/browser/ui/cocoa/autofill/autofill_section_container.mm +++ b/chrome/browser/ui/cocoa/autofill/autofill_section_container.mm
@@ -24,6 +24,7 @@ #import "chrome/browser/ui/cocoa/menu_button.h" #include "components/autofill/core/browser/autofill_type.h" #include "content/public/browser/native_web_keyboard_event.h" +#include "grit/components_scaled_resources.h" #include "grit/theme_resources.h" #import "ui/base/cocoa/menu_controller.h" #include "ui/base/l10n/l10n_util_mac.h"
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 2d2a68f..2a9d770 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
@@ -22,9 +22,9 @@ #include "chrome/browser/ui/cocoa/themed_window.h" #include "components/autofill/core/browser/ui/card_unmask_prompt_controller.h" #include "content/public/browser/web_contents.h" +#include "grit/components_scaled_resources.h" #include "grit/components_strings.h" #include "grit/generated_resources.h" -#include "grit/theme_resources.h" #include "skia/ext/skia_utils_mac.h" #import "ui/base/cocoa/controls/hyperlink_button_cell.h" #include "ui/base/cocoa/window_size_constants.h"
diff --git a/chrome/browser/ui/cocoa/extensions/browser_action_button.mm b/chrome/browser/ui/cocoa/extensions/browser_action_button.mm index edb52129..accc139 100644 --- a/chrome/browser/ui/cocoa/extensions/browser_action_button.mm +++ b/chrome/browser/ui/cocoa/extensions/browser_action_button.mm
@@ -429,6 +429,8 @@ // Also reset the context menu, since it has a dependency on the backing // controller (which owns its model). contextMenuController_.reset(); + // Remove any lingering observations. + [[NSNotificationCenter defaultCenter] removeObserver:self]; } - (BOOL)isAnimating {
diff --git a/chrome/browser/ui/cocoa/full_size_content_window.mm b/chrome/browser/ui/cocoa/full_size_content_window.mm index 555c523..8c5b300 100644 --- a/chrome/browser/ui/cocoa/full_size_content_window.mm +++ b/chrome/browser/ui/cocoa/full_size_content_window.mm
@@ -4,8 +4,12 @@ #import "chrome/browser/ui/cocoa/full_size_content_window.h" +#include <crt_externs.h> + +#include "base/auto_reset.h" #include "base/logging.h" #include "base/mac/foundation_util.h" +#include "base/mac/scoped_objc_class_swizzler.h" @interface FullSizeContentWindow () @@ -44,10 +48,62 @@ @end +static bool g_disable_callstacksymbols = false; +static IMP g_original_callstacksymbols_implementation; + +@interface FullSizeContentWindowSwizzlingSupport : NSObject +@end + +@implementation FullSizeContentWindowSwizzlingSupport + +// This method replaces [NSThread callStackSymbols] via swizzling - see +load +// below. ++ (NSArray*)callStackSymbols { + return g_disable_callstacksymbols ? + @[@"+callStackSymbols disabled for performance reasons"] : + g_original_callstacksymbols_implementation( + self, @selector(callStackSymbols)); +} + +@end + @implementation FullSizeContentWindow #pragma mark - Lifecycle +// In initWithContentRect:styleMask:backing:defer:, the call to +// [NSView addSubview:positioned:relativeTo:] causes NSWindow to complain that +// an unknown view is being added to it, and to generate a stack trace. +// Not only does this stack trace pollute the console, it can also take hundreds +// of milliseconds to generate (because of symbolication). By swizzling +// [NSThread callStackSymbols] we can prevent the stack trace output. +// See crbug.com/520373 . ++ (void)load { + // Swizzling should only happen in the browser process. + const char* const* const argv = *_NSGetArgv(); + const int argc = *_NSGetArgc(); + const char kType[] = "--type="; + for (int i = 1; i < argc; ++i) { + const char* arg = argv[i]; + if (strncmp(arg, kType, strlen(kType)) == 0) { + return; + } + } + + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + Class targetClass = [NSThread class]; + Class swizzleClass = [FullSizeContentWindowSwizzlingSupport class]; + SEL targetSelector = @selector(callStackSymbols); + + CR_DEFINE_STATIC_LOCAL(base::mac::ScopedObjCClassSwizzler, + callStackSymbolsSuppressor, (targetClass, + swizzleClass, targetSelector)); + g_original_callstacksymbols_implementation = + callStackSymbolsSuppressor.GetOriginalImplementation(); + }); +} + - (instancetype)init { NOTREACHED(); return nil; @@ -87,6 +143,13 @@ // it is positioned below the buttons. NSView* superview = [chromeWindowView_ superview]; [chromeWindowView_ removeFromSuperview]; + + // Prevent the AppKit from generating a backtrace to include in it's + // complaint about our upcoming call to addSubview:positioned:relativeTo:. + // See +load for more info. + base::AutoReset<bool> disable_symbolication(&g_disable_callstacksymbols, + true); + [superview addSubview:chromeWindowView_ positioned:NSWindowBelow relativeTo:nil];
diff --git a/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.mm b/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.mm index de44911f..d4a10a9 100644 --- a/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.mm +++ b/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.mm
@@ -22,9 +22,6 @@ #include "chrome/browser/extensions/location_bar_controller.h" #include "chrome/browser/extensions/tab_helper.h" #include "chrome/browser/profiles/profile.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/template_url_service_factory.h" #include "chrome/browser/translate/chrome_translate_client.h" #include "chrome/browser/translate/translate_service.h" @@ -558,13 +555,6 @@ location_icon_decoration_->SetImage(image); ev_bubble_decoration_->SetImage(image); Layout(); - - InstantService* instant_service = - InstantServiceFactory::GetForProfile(profile()); - if (instant_service) { - gfx::Rect bounds(NSRectToCGRect([field_ frame])); - instant_service->OnOmniboxStartMarginChanged(bounds.x()); - } } void LocationBarViewMac::OnSetFocus() {
diff --git a/chrome/browser/ui/cocoa/website_settings/chooser_bubble_ui_cocoa.h b/chrome/browser/ui/cocoa/website_settings/chooser_bubble_ui_cocoa.h index 8be15bd..f742754 100644 --- a/chrome/browser/ui/cocoa/website_settings/chooser_bubble_ui_cocoa.h +++ b/chrome/browser/ui/cocoa/website_settings/chooser_bubble_ui_cocoa.h
@@ -32,8 +32,8 @@ // ChooserBubbleDelegate::Observer: void OnOptionsInitialized() override; - void OnOptionAdded(int index) override; - void OnOptionRemoved(int index) override; + void OnOptionAdded(size_t index) override; + void OnOptionRemoved(size_t index) override; // Called when |chooser_bubble_ui_controller_| is closing. void OnBubbleClosing();
diff --git a/chrome/browser/ui/cocoa/website_settings/chooser_bubble_ui_cocoa.mm b/chrome/browser/ui/cocoa/website_settings/chooser_bubble_ui_cocoa.mm index 2e8b819b..45e2349c 100644 --- a/chrome/browser/ui/cocoa/website_settings/chooser_bubble_ui_cocoa.mm +++ b/chrome/browser/ui/cocoa/website_settings/chooser_bubble_ui_cocoa.mm
@@ -294,31 +294,26 @@ } - (NSInteger)numberOfRowsInTableView:(NSTableView*)tableView { - const std::vector<base::string16>& device_names = - chooserBubbleDelegate_->GetOptions(); - if (device_names.empty()) { - return 1; - } else { - return static_cast<NSInteger>(device_names.size()); - } + // When there are no devices, the table contains a message saying there are + // no devices, so the number of rows is always at least 1. + return std::max(static_cast<NSInteger>(chooserBubbleDelegate_->NumOptions()), + static_cast<NSInteger>(1)); } - (id)tableView:(NSTableView*)tableView objectValueForTableColumn:(NSTableColumn*)tableColumn row:(NSInteger)rowIndex { - const std::vector<base::string16>& device_names = - chooserBubbleDelegate_->GetOptions(); - if (device_names.empty()) { - DCHECK(rowIndex == 0); + NSInteger num_options = + static_cast<NSInteger>(chooserBubbleDelegate_->NumOptions()); + if (num_options == 0) { + DCHECK_EQ(0, rowIndex); return l10n_util::GetNSString(IDS_CHOOSER_BUBBLE_NO_DEVICES_FOUND_PROMPT); - } else { - if (rowIndex >= 0 && - rowIndex < static_cast<NSInteger>(device_names.size())) { - return base::SysUTF16ToNSString(device_names[rowIndex]); - } else { - return @""; - } } + + DCHECK_GE(rowIndex, 0); + DCHECK_LT(rowIndex, num_options); + return base::SysUTF16ToNSString( + chooserBubbleDelegate_->GetOption(static_cast<size_t>(rowIndex))); } - (BOOL)tableView:(NSTableView*)aTableView @@ -346,9 +341,7 @@ } - (void)updateTableView { - const std::vector<base::string16>& device_names = - chooserBubbleDelegate_->GetOptions(); - [tableView_ setEnabled:!device_names.empty()]; + [tableView_ setEnabled:chooserBubbleDelegate_->NumOptions() > 0]; [tableView_ reloadData]; } @@ -503,12 +496,12 @@ [chooser_bubble_ui_controller_ onOptionsInitialized]; } -void ChooserBubbleUiCocoa::OnOptionAdded(int index) { - [chooser_bubble_ui_controller_ onOptionAdded:index]; +void ChooserBubbleUiCocoa::OnOptionAdded(size_t index) { + [chooser_bubble_ui_controller_ onOptionAdded:static_cast<NSInteger>(index)]; } -void ChooserBubbleUiCocoa::OnOptionRemoved(int index) { - [chooser_bubble_ui_controller_ onOptionRemoved:index]; +void ChooserBubbleUiCocoa::OnOptionRemoved(size_t index) { + [chooser_bubble_ui_controller_ onOptionRemoved:static_cast<NSInteger>(index)]; } void ChooserBubbleUiCocoa::OnBubbleClosing() {
diff --git a/chrome/browser/ui/cocoa/website_settings/website_settings_bubble_controller.mm b/chrome/browser/ui/cocoa/website_settings/website_settings_bubble_controller.mm index 48eafd9ce..6ff61af 100644 --- a/chrome/browser/ui/cocoa/website_settings/website_settings_bubble_controller.mm +++ b/chrome/browser/ui/cocoa/website_settings/website_settings_bubble_controller.mm
@@ -69,9 +69,6 @@ // Square size of the images on the Connections tab. const CGFloat kConnectionImageSize = 30; -// Square size of the image that is shown for internal pages. -const CGFloat kInternalPageImageSize = 16; - // Square size of the permission images. const CGFloat kPermissionImageSize = 19; @@ -396,27 +393,33 @@ NSPoint controlOrigin = NSMakePoint( kInternalPageFramePadding, kInternalPageFramePadding + info_bubble::kBubbleArrowHeight); - NSSize imageSize = NSMakeSize(kInternalPageImageSize, - kInternalPageImageSize); - NSImageView* imageView = [self addImageWithSize:imageSize + NSImage* productLogoImage = + rb.GetNativeImageNamed(IDR_PRODUCT_LOGO_16).ToNSImage(); + NSImageView* imageView = [self addImageWithSize:[productLogoImage size] toView:contentView_ atPoint:controlOrigin]; - [imageView setImage:rb.GetNativeImageNamed(IDR_PRODUCT_LOGO_16).ToNSImage()]; + [imageView setImage:productLogoImage]; - controlOrigin.x += NSWidth([imageView frame]) + kInternalPageImageSpacing; + NSRect imageFrame = [imageView frame]; + controlOrigin.x += NSWidth(imageFrame) + kInternalPageImageSpacing; base::string16 text = l10n_util::GetStringUTF16(IDS_PAGE_INFO_INTERNAL_PAGE); NSTextField* textField = [self addText:text withSize:[NSFont smallSystemFontSize] bold:NO toView:contentView_ atPoint:controlOrigin]; - // Center the text vertically with the image. + // Center the image vertically with the text. Previously this code centered + // the text vertically while holding the image in place. That produced correct + // results when the image, at 26x26, was taller than (or just slightly + // shorter) than the text, but produced incorrect results once the icon + // shrank to 16x16. The icon should now always be shorter than the text. + // See crbug.com/572044 . NSRect textFrame = [textField frame]; - textFrame.origin.y += (imageSize.height - NSHeight(textFrame)) / 2; - [textField setFrame:textFrame]; + imageFrame.origin.y += (NSHeight(textFrame) - NSHeight(imageFrame)) / 2; + [imageView setFrame:imageFrame]; // Adjust the contentView to fit everything. - CGFloat maxY = std::max(NSMaxY([imageView frame]), NSMaxY(textFrame)); + CGFloat maxY = std::max(NSMaxY(imageFrame), NSMaxY(textFrame)); [contentView_ setFrame:NSMakeRect( 0, 0, [self defaultWindowWidth], maxY + kInternalPageFramePadding)];
diff --git a/chrome/browser/ui/exclusive_access/exclusive_access_bubble.h b/chrome/browser/ui/exclusive_access/exclusive_access_bubble.h index 5def540..f5bc4db 100644 --- a/chrome/browser/ui/exclusive_access/exclusive_access_bubble.h +++ b/chrome/browser/ui/exclusive_access/exclusive_access_bubble.h
@@ -54,9 +54,9 @@ // Space between top of screen and popup, in simplified UI. static const int kSimplifiedPopupTopPx; - // Returns the current desirable rect for the popup window. If - // |ignore_animation_state| is true this returns the rect assuming the popup - // is fully onscreen. + // Returns the current desirable rect for the popup window in screen + // coordinates. If |ignore_animation_state| is true this returns the rect + // assuming the popup is fully onscreen. virtual gfx::Rect GetPopupRect(bool ignore_animation_state) const = 0; virtual gfx::Point GetCursorScreenPoint() = 0; virtual bool WindowContainsPoint(gfx::Point pos) = 0;
diff --git a/chrome/browser/ui/panels/panel_manager.cc b/chrome/browser/ui/panels/panel_manager.cc index 459b5de..06c1762 100644 --- a/chrome/browser/ui/panels/panel_manager.cc +++ b/chrome/browser/ui/panels/panel_manager.cc
@@ -136,14 +136,6 @@ return true; } -#if defined(OS_CHROMEOS) - // Without --enable-panels, only support IME extensions on Chrome OS. - for (const char* id : extension_misc::kIMEExtensionIds) { - if (extension_id == id) - return true; - } -#endif - return false; }
diff --git a/chrome/browser/ui/search/instant_extended_interactive_uitest.cc b/chrome/browser/ui/search/instant_extended_interactive_uitest.cc index 6d44c183..94ed97a 100644 --- a/chrome/browser/ui/search/instant_extended_interactive_uitest.cc +++ b/chrome/browser/ui/search/instant_extended_interactive_uitest.cc
@@ -434,34 +434,6 @@ ASSERT_THAT(active_tab->GetURL().spec(), HasSubstr("q=puppies")); } -#if defined(OS_LINUX) && defined(ADDRESS_SANITIZER) -// Flaky crashes at shutdown on Linux Asan; http://crbug.com/517886. -#define MAYBE_OmniboxMarginSetForSearchURLs \ - DISABLED_OmniboxMarginSetForSearchURLs -#else -#define MAYBE_OmniboxMarginSetForSearchURLs OmniboxMarginSetForSearchURLs -#endif -IN_PROC_BROWSER_TEST_F(InstantExtendedTest, - MAYBE_OmniboxMarginSetForSearchURLs) { - ASSERT_NO_FATAL_FAILURE(SetupInstant(browser())); - FocusOmnibox(); - - // Create an observer to wait for the instant tab to support Instant. - content::WindowedNotificationObserver observer( - chrome::NOTIFICATION_INSTANT_TAB_SUPPORT_DETERMINED, - content::NotificationService::AllSources()); - - SetOmniboxText("flowers"); - browser()->window()->GetLocationBar()->AcceptInput(); - observer.Wait(); - - const std::string& url = - browser()->tab_strip_model()->GetActiveWebContents()->GetURL().spec(); - // Make sure we actually used search_url, not instant_url. - ASSERT_THAT(url, HasSubstr("&is_search")); - EXPECT_THAT(url, HasSubstr("&es_sm=")); -} - // Test to verify that switching tabs should not dispatch onmostvisitedchanged // events. IN_PROC_BROWSER_TEST_F(InstantExtendedTest, NoMostVisitedChangedOnTabSwitch) {
diff --git a/chrome/browser/ui/search/instant_test_utils.cc b/chrome/browser/ui/search/instant_test_utils.cc index d0f652c..e8cf7971 100644 --- a/chrome/browser/ui/search/instant_test_utils.cc +++ b/chrome/browser/ui/search/instant_test_utils.cc
@@ -55,8 +55,7 @@ // Necessary to use exact URL for both the main URL and the alternate URL for // search term extraction to work in InstantExtended. data.SetShortName(base::ASCIIToUTF16("name")); - data.SetURL(instant_url_.spec() + - "q={searchTerms}&is_search&{google:omniboxStartMarginParameter}"); + data.SetURL(instant_url_.spec() + "q={searchTerms}&is_search"); data.instant_url = instant_url_.spec(); data.new_tab_url = ntp_url_.spec(); if (init_suggestions_url_)
diff --git a/chrome/browser/ui/search/search_ipc_router.cc b/chrome/browser/ui/search/search_ipc_router.cc index fce368fb..ebbdeff 100644 --- a/chrome/browser/ui/search/search_ipc_router.cc +++ b/chrome/browser/ui/search/search_ipc_router.cc
@@ -101,13 +101,6 @@ suggestion)); } -void SearchIPCRouter::SetOmniboxStartMargin(int start_margin) { - if (!policy_->ShouldSendSetOmniboxStartMargin()) - return; - - Send(new ChromeViewMsg_SearchBoxMarginChange(routing_id(), start_margin)); -} - void SearchIPCRouter::SetInputInProgress(bool input_in_progress) { if (!policy_->ShouldSendSetInputInProgress(is_active_tab_)) return;
diff --git a/chrome/browser/ui/search/search_ipc_router.h b/chrome/browser/ui/search/search_ipc_router.h index bc7636a9..9564050 100644 --- a/chrome/browser/ui/search/search_ipc_router.h +++ b/chrome/browser/ui/search/search_ipc_router.h
@@ -110,7 +110,6 @@ virtual bool ShouldSendSetPromoInformation() = 0; virtual bool ShouldSendSetDisplayInstantResults() = 0; virtual bool ShouldSendSetSuggestionToPrefetch() = 0; - virtual bool ShouldSendSetOmniboxStartMargin() = 0; virtual bool ShouldSendSetInputInProgress(bool is_active_tab) = 0; virtual bool ShouldSendOmniboxFocusChanged() = 0; virtual bool ShouldSendMostVisitedItems() = 0; @@ -146,10 +145,6 @@ // Tells the page the suggestion to be prefetched if any. void SetSuggestionToPrefetch(const InstantSuggestion& suggestion); - // Tells the page the left margin of the omnibox. This is used by the page to - // align text or assets properly with the omnibox. - void SetOmniboxStartMargin(int start_margin); - // Tells the page that user input started or stopped. void SetInputInProgress(bool input_in_progress);
diff --git a/chrome/browser/ui/search/search_ipc_router_policy_impl.cc b/chrome/browser/ui/search/search_ipc_router_policy_impl.cc index 382038a0..8af1228 100644 --- a/chrome/browser/ui/search/search_ipc_router_policy_impl.cc +++ b/chrome/browser/ui/search/search_ipc_router_policy_impl.cc
@@ -71,10 +71,6 @@ return !is_incognito_; } -bool SearchIPCRouterPolicyImpl::ShouldSendSetOmniboxStartMargin() { - return true; -} - bool SearchIPCRouterPolicyImpl::ShouldSendSetInputInProgress( bool is_active_tab) { return is_active_tab && !is_incognito_;
diff --git a/chrome/browser/ui/search/search_ipc_router_policy_impl.h b/chrome/browser/ui/search/search_ipc_router_policy_impl.h index 4c260594..2322186 100644 --- a/chrome/browser/ui/search/search_ipc_router_policy_impl.h +++ b/chrome/browser/ui/search/search_ipc_router_policy_impl.h
@@ -34,7 +34,6 @@ bool ShouldSendSetPromoInformation() override; bool ShouldSendSetDisplayInstantResults() override; bool ShouldSendSetSuggestionToPrefetch() override; - bool ShouldSendSetOmniboxStartMargin() override; bool ShouldSendSetInputInProgress(bool is_active_tab) override; bool ShouldSendOmniboxFocusChanged() override; bool ShouldSendMostVisitedItems() override;
diff --git a/chrome/browser/ui/search/search_ipc_router_policy_unittest.cc b/chrome/browser/ui/search/search_ipc_router_policy_unittest.cc index ad221b5..f3e15bc 100644 --- a/chrome/browser/ui/search/search_ipc_router_policy_unittest.cc +++ b/chrome/browser/ui/search/search_ipc_router_policy_unittest.cc
@@ -172,11 +172,6 @@ EXPECT_TRUE(GetSearchIPCRouterPolicy()->ShouldSendSetSuggestionToPrefetch()); } -TEST_F(SearchIPCRouterPolicyTest, SendSetOmniboxStartMargin) { - NavigateAndCommitActiveTab(GURL("chrome-search://foo/bar")); - EXPECT_TRUE(GetSearchIPCRouterPolicy()->ShouldSendSetOmniboxStartMargin()); -} - TEST_F(SearchIPCRouterPolicyTest, DoNotSendSetMessagesForIncognitoPage) { NavigateAndCommitActiveTab(GURL(chrome::kChromeSearchLocalNtpUrl)); @@ -197,9 +192,7 @@ NavigateAndCommitActiveTab(GURL("chrome-search://foo/bar")); SetIncognitoProfile(); - SearchIPCRouter::Policy* router_policy = GetSearchIPCRouterPolicy(); - EXPECT_TRUE(router_policy->ShouldSubmitQuery()); - EXPECT_TRUE(router_policy->ShouldSendSetOmniboxStartMargin()); + EXPECT_TRUE(GetSearchIPCRouterPolicy()->ShouldSubmitQuery()); } TEST_F(SearchIPCRouterPolicyTest, SendMostVisitedItems) {
diff --git a/chrome/browser/ui/search/search_ipc_router_unittest.cc b/chrome/browser/ui/search/search_ipc_router_unittest.cc index 05f7ffd..70d6a83c 100644 --- a/chrome/browser/ui/search/search_ipc_router_unittest.cc +++ b/chrome/browser/ui/search/search_ipc_router_unittest.cc
@@ -80,7 +80,6 @@ MOCK_METHOD0(ShouldSendSetPromoInformation, bool()); MOCK_METHOD0(ShouldSendSetDisplayInstantResults, bool()); MOCK_METHOD0(ShouldSendSetSuggestionToPrefetch, bool()); - MOCK_METHOD0(ShouldSendSetOmniboxStartMargin, bool()); MOCK_METHOD1(ShouldSendSetInputInProgress, bool(bool)); MOCK_METHOD0(ShouldSendOmniboxFocusChanged, bool()); MOCK_METHOD0(ShouldSendMostVisitedItems, bool()); @@ -109,8 +108,7 @@ TemplateURLData data; data.SetShortName(base::ASCIIToUTF16("foo.com")); data.SetURL("http://foo.com/url?bar={searchTerms}"); - data.instant_url = "http://foo.com/instant?" - "{google:omniboxStartMarginParameter}foo=foo#foo=foo&espv"; + data.instant_url = "http://foo.com/instant?foo=foo#foo=foo&espv"; data.new_tab_url = "https://foo.com/newtab?espv"; data.alternate_urls.push_back("http://foo.com/alt#quux={searchTerms}"); data.search_terms_replacement_key = "espv"; @@ -700,30 +698,6 @@ ChromeViewMsg_SearchBoxSetSuggestionToPrefetch::ID)); } -TEST_F(SearchIPCRouterTest, SendSetOmniboxStartMargin) { - NavigateAndCommitActiveTab(GURL("chrome-search://foo/bar")); - SetupMockDelegateAndPolicy(); - MockSearchIPCRouterPolicy* policy = GetSearchIPCRouterPolicy(); - EXPECT_CALL(*policy, ShouldSendSetOmniboxStartMargin()).Times(1) - .WillOnce(testing::Return(true)); - - process()->sink().ClearMessages(); - GetSearchIPCRouter().SetOmniboxStartMargin(92); - EXPECT_TRUE(MessageWasSent(ChromeViewMsg_SearchBoxMarginChange::ID)); -} - -TEST_F(SearchIPCRouterTest, DoNotSendSetOmniboxStartMargin) { - NavigateAndCommitActiveTab(GURL("chrome-search://foo/bar")); - SetupMockDelegateAndPolicy(); - MockSearchIPCRouterPolicy* policy = GetSearchIPCRouterPolicy(); - EXPECT_CALL(*policy, ShouldSendSetOmniboxStartMargin()).Times(1) - .WillOnce(testing::Return(false)); - - process()->sink().ClearMessages(); - GetSearchIPCRouter().SetOmniboxStartMargin(92); - EXPECT_FALSE(MessageWasSent(ChromeViewMsg_SearchBoxMarginChange::ID)); -} - TEST_F(SearchIPCRouterTest, SendOmniboxFocusChange) { NavigateAndCommitActiveTab(GURL(chrome::kChromeSearchLocalNtpUrl)); SetupMockDelegateAndPolicy();
diff --git a/chrome/browser/ui/search/search_tab_helper.cc b/chrome/browser/ui/search/search_tab_helper.cc index 1226775..65a7f91 100644 --- a/chrome/browser/ui/search/search_tab_helper.cc +++ b/chrome/browser/ui/search/search_tab_helper.cc
@@ -340,12 +340,8 @@ return; if (search::ShouldAssignURLToInstantRenderer(web_contents_->GetURL(), - profile())) { - InstantService* instant_service = - InstantServiceFactory::GetForProfile(profile()); - ipc_router_.SetOmniboxStartMargin(instant_service->omnibox_start_margin()); + profile())) ipc_router_.SetDisplayInstantResults(); - } UpdateMode(true, false); @@ -410,10 +406,6 @@ } } -void SearchTabHelper::OmniboxStartMarginChanged(int omnibox_start_margin) { - ipc_router_.SetOmniboxStartMargin(omnibox_start_margin); -} - void SearchTabHelper::FocusOmnibox(OmniboxFocusState state) { // TODO(kmadhusu): Move platform specific code from here and get rid of #ifdef. #if !defined(OS_ANDROID)
diff --git a/chrome/browser/ui/search/search_tab_helper.h b/chrome/browser/ui/search/search_tab_helper.h index a58b2c69..b265d7a 100644 --- a/chrome/browser/ui/search/search_tab_helper.h +++ b/chrome/browser/ui/search/search_tab_helper.h
@@ -179,7 +179,6 @@ void ThemeInfoChanged(const ThemeBackgroundInfo& theme_info) override; void MostVisitedItemsChanged( const std::vector<InstantMostVisitedItem>& items) override; - void OmniboxStartMarginChanged(int omnibox_start_margin) override; // Sets the mode of the model based on the current URL of web_contents(). // Only updates the origin part of the mode if |update_origin| is true,
diff --git a/chrome/browser/ui/task_manager/task_manager_table_model.cc b/chrome/browser/ui/task_manager/task_manager_table_model.cc index 739a646..8146eb5 100644 --- a/chrome/browser/ui/task_manager/task_manager_table_model.cc +++ b/chrome/browser/ui/task_manager/task_manager_table_model.cc
@@ -606,13 +606,7 @@ } void TaskManagerTableModel::KillTask(int row_index) { - base::ProcessId proc_id = observed_task_manager()->GetProcessId( - tasks_[row_index]); - - DCHECK_NE(proc_id, base::GetCurrentProcId()); - - base::Process process = base::Process::Open(proc_id); - process.Terminate(content::RESULT_CODE_KILLED, false); + observed_task_manager()->KillTask(tasks_[row_index]); } void TaskManagerTableModel::UpdateRefreshTypes(int column_id, bool visibility) {
diff --git a/chrome/browser/ui/toolbar/test_toolbar_model.cc b/chrome/browser/ui/toolbar/test_toolbar_model.cc index c00d396..729a5bf 100644 --- a/chrome/browser/ui/toolbar/test_toolbar_model.cc +++ b/chrome/browser/ui/toolbar/test_toolbar_model.cc
@@ -11,7 +11,7 @@ : ChromeToolbarModel(), perform_search_term_replacement_(false), security_level_(SecurityStateModel::NONE), - icon_(IDR_LOCATION_BAR_HTTP), + icon_(gfx::VectorIconId::VECTOR_ICON_NONE), should_display_url_(true) {} TestToolbarModel::~TestToolbarModel() {} @@ -43,11 +43,12 @@ } int TestToolbarModel::GetIcon() const { - return icon_; + // This placeholder implementation should be removed when MD is default. + return IDR_LOCATION_BAR_HTTP; } gfx::VectorIconId TestToolbarModel::GetVectorIcon() const { - return gfx::VectorIconId::VECTOR_ICON_NONE; + return icon_; } base::string16 TestToolbarModel::GetEVCertName() const {
diff --git a/chrome/browser/ui/toolbar/test_toolbar_model.h b/chrome/browser/ui/toolbar/test_toolbar_model.h index e563403b..c1fbc3a 100644 --- a/chrome/browser/ui/toolbar/test_toolbar_model.h +++ b/chrome/browser/ui/toolbar/test_toolbar_model.h
@@ -12,6 +12,10 @@ #include "base/strings/string16.h" #include "chrome/browser/ui/toolbar/chrome_toolbar_model.h" +namespace gfx { +enum class VectorIconId; +} + // A ToolbarModel that is backed by instance variables, which are initialized // with some basic values that can be changed with the provided setters. This // should be used only for testing. @@ -40,7 +44,7 @@ void set_security_level(SecurityStateModel::SecurityLevel security_level) { security_level_ = security_level; } - void set_icon(int icon) { icon_ = icon; } + void set_icon(gfx::VectorIconId icon) { icon_ = icon; } void set_ev_cert_name(const base::string16& ev_cert_name) { ev_cert_name_ = ev_cert_name; } @@ -53,7 +57,7 @@ GURL url_; bool perform_search_term_replacement_; SecurityStateModel::SecurityLevel security_level_; - int icon_; + gfx::VectorIconId icon_; base::string16 ev_cert_name_; bool should_display_url_;
diff --git a/chrome/browser/ui/views/desktop_media_picker_views.cc b/chrome/browser/ui/views/desktop_media_picker_views.cc index 1c89f35..6b13e2c5 100644 --- a/chrome/browser/ui/views/desktop_media_picker_views.cc +++ b/chrome/browser/ui/views/desktop_media_picker_views.cc
@@ -58,11 +58,6 @@ gfx::AcceleratedWidget accelerated_widget) { #if defined(OS_WIN) return reinterpret_cast<DesktopMediaID::Id>(accelerated_widget); -#elif defined(OS_ANDROID) - // TODO(bshe): We may need to revisit this for Android platform. See - // crbug.com/557424. - NOTIMPLEMENTED(); - return reinterpret_cast<DesktopMediaID::Id>(accelerated_widget); #else return static_cast<DesktopMediaID::Id>(accelerated_widget); #endif
diff --git a/chrome/browser/ui/views/exclusive_access_bubble_views.cc b/chrome/browser/ui/views/exclusive_access_bubble_views.cc index 78721f3c..5028490 100644 --- a/chrome/browser/ui/views/exclusive_access_bubble_views.cc +++ b/chrome/browser/ui/views/exclusive_access_bubble_views.cc
@@ -422,6 +422,7 @@ popup_->Init(params); popup_->SetContentsView(view_); gfx::Size size = GetPopupRect(true).size(); + // Bounds are in screen coordinates. popup_->SetBounds(GetPopupRect(false)); // We set layout manager to nullptr to prevent the widget from sizing its // contents to the same size as itself. This prevents the widget contents from @@ -574,17 +575,11 @@ gfx::Rect ExclusiveAccessBubbleViews::GetPopupRect( bool ignore_animation_state) const { 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( - bubble_view_context_->GetBubbleAssociatedWidget()->GetNativeView()); - gfx::Rect screen_bounds = - screen->GetDisplayNearestWindow( - bubble_view_context_->GetBubbleAssociatedWidget() - ->GetNativeView()).bounds(); - int x = screen_bounds.x() + (screen_bounds.width() - size.width()) / 2; + gfx::Rect widget_bounds = bubble_view_context_->GetBubbleAssociatedWidget() + ->GetClientAreaBoundsInScreen(); + int x = widget_bounds.x() + (widget_bounds.width() - size.width()) / 2; - int top_container_bottom = screen_bounds.y(); + int top_container_bottom = widget_bounds.y(); if (bubble_view_context_->IsImmersiveModeEnabled()) { // Skip querying the top container height in non-immersive fullscreen // because:
diff --git a/chrome/browser/ui/views/exclusive_access_bubble_views.h b/chrome/browser/ui/views/exclusive_access_bubble_views.h index 8feb2f5..ce614a8 100644 --- a/chrome/browser/ui/views/exclusive_access_bubble_views.h +++ b/chrome/browser/ui/views/exclusive_access_bubble_views.h
@@ -65,7 +65,7 @@ // Returns the root view containing |browser_view_|. views::View* GetBrowserRootView() const; - // FullScreenExitBubble overrides: + // ExclusiveAccessBubble overrides: void AnimationProgressed(const gfx::Animation* animation) override; void AnimationEnded(const gfx::Animation* animation) override; gfx::Rect GetPopupRect(bool ignore_animation_state) const override;
diff --git a/chrome/browser/ui/views/frame/browser_header_painter_ash.cc b/chrome/browser/ui/views/frame/browser_header_painter_ash.cc index d840736c..336821c 100644 --- a/chrome/browser/ui/views/frame/browser_header_painter_ash.cc +++ b/chrome/browser/ui/views/frame/browser_header_painter_ash.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/ui/views/frame/browser_header_painter_ash.h" +#include "ash/ash_layout_constants.h" #include "ash/frame/caption_buttons/frame_caption_button_container_view.h" #include "ash/frame/header_painter_util.h" #include "base/logging.h" // DCHECK @@ -24,6 +25,7 @@ #include "ui/gfx/geometry/rect.h" #include "ui/gfx/image/image_skia.h" #include "ui/gfx/skia_util.h" +#include "ui/gfx/vector_icons_public.h" #include "ui/views/view.h" #include "ui/views/widget/widget.h" #include "ui/views/widget/widget_delegate.h" @@ -238,7 +240,7 @@ // on having laid out the window controls. painted_height_ = -1; - UpdateCaptionButtonImages(); + UpdateCaptionButtons(); caption_button_container_->Layout(); gfx::Size caption_button_container_size = @@ -399,52 +401,31 @@ IDR_THEME_FRAME_INCOGNITO_INACTIVE : IDR_THEME_FRAME_INACTIVE); } -void BrowserHeaderPainterAsh::UpdateCaptionButtonImages() { - int hover_background_id = 0; - int pressed_background_id = 0; - if (frame_->IsMaximized() || frame_->IsFullscreen()) { - hover_background_id = - IDR_ASH_BROWSER_WINDOW_CONTROL_BACKGROUND_MAXIMIZED_H; - pressed_background_id = - IDR_ASH_BROWSER_WINDOW_CONTROL_BACKGROUND_MAXIMIZED_P; - } else { - hover_background_id = - IDR_ASH_BROWSER_WINDOW_CONTROL_BACKGROUND_RESTORED_H; - pressed_background_id = - IDR_ASH_BROWSER_WINDOW_CONTROL_BACKGROUND_RESTORED_P; - } - caption_button_container_->SetButtonImages( +void BrowserHeaderPainterAsh::UpdateCaptionButtons() { + caption_button_container_->SetButtonImage( ash::CAPTION_BUTTON_ICON_MINIMIZE, - IDR_AURA_WINDOW_CONTROL_ICON_MINIMIZE, - hover_background_id, - pressed_background_id); - - int size_icon_id = 0; - if (frame_->IsMaximized() || frame_->IsFullscreen()) - size_icon_id = IDR_AURA_WINDOW_CONTROL_ICON_RESTORE; - else - size_icon_id = IDR_AURA_WINDOW_CONTROL_ICON_MAXIMIZE; - caption_button_container_->SetButtonImages( - ash::CAPTION_BUTTON_ICON_MAXIMIZE_RESTORE, - size_icon_id, - hover_background_id, - pressed_background_id); - - caption_button_container_->SetButtonImages( - ash::CAPTION_BUTTON_ICON_CLOSE, - IDR_AURA_WINDOW_CONTROL_ICON_CLOSE, - hover_background_id, - pressed_background_id); - caption_button_container_->SetButtonImages( + gfx::VectorIconId::WINDOW_CONTROL_MINIMIZE); + caption_button_container_->SetButtonImage( + ash::CAPTION_BUTTON_ICON_CLOSE, gfx::VectorIconId::WINDOW_CONTROL_CLOSE); + caption_button_container_->SetButtonImage( ash::CAPTION_BUTTON_ICON_LEFT_SNAPPED, - IDR_AURA_WINDOW_CONTROL_ICON_LEFT_SNAPPED, - hover_background_id, - pressed_background_id); - caption_button_container_->SetButtonImages( + gfx::VectorIconId::WINDOW_CONTROL_LEFT_SNAPPED); + caption_button_container_->SetButtonImage( ash::CAPTION_BUTTON_ICON_RIGHT_SNAPPED, - IDR_AURA_WINDOW_CONTROL_ICON_RIGHT_SNAPPED, - hover_background_id, - pressed_background_id); + gfx::VectorIconId::WINDOW_CONTROL_RIGHT_SNAPPED); + + gfx::VectorIconId size_icon_id = gfx::VectorIconId::WINDOW_CONTROL_MAXIMIZE; + gfx::Size button_size( + GetAshLayoutSize(AshLayoutSize::BROWSER_RESTORED_CAPTION_BUTTON)); + if (frame_->IsMaximized() || frame_->IsFullscreen()) { + size_icon_id = gfx::VectorIconId::WINDOW_CONTROL_RESTORE; + button_size = + GetAshLayoutSize(AshLayoutSize::BROWSER_MAXIMIZED_CAPTION_BUTTON); + } + caption_button_container_->SetButtonImage( + ash::CAPTION_BUTTON_ICON_MAXIMIZE_RESTORE, + size_icon_id); + caption_button_container_->SetButtonSize(button_size); } gfx::Rect BrowserHeaderPainterAsh::GetPaintedBounds() const {
diff --git a/chrome/browser/ui/views/frame/browser_header_painter_ash.h b/chrome/browser/ui/views/frame/browser_header_painter_ash.h index 821510b..8d27f54d 100644 --- a/chrome/browser/ui/views/frame/browser_header_painter_ash.h +++ b/chrome/browser/ui/views/frame/browser_header_painter_ash.h
@@ -81,8 +81,9 @@ // browser windows and for hosted app windows which show the toolbar. gfx::ImageSkia GetFrameImageForNonTabbedBrowser(Mode mode) const; - // Updates the images used for the minimize, restore and close buttons. - void UpdateCaptionButtonImages(); + // Updates the size and icons used for the minimize, restore, and close + // buttons. + void UpdateCaptionButtons(); // Returns bounds of the region in |view_| which is painted with the header // images. The region is assumed to start at the top left corner of |view_|
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc index 5349b06..ffefd3c 100644 --- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc +++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc
@@ -177,6 +177,14 @@ return 0; if (browser_view()->IsTabStripVisible()) { + // TODO(tdanderson): Remove this temporary hack to prevent the buttons in + // the header from overlapping the tabstrip/toolbar + // separator in material design. + if (ui::MaterialDesignController::IsModeMaterial()) { + return header_painter_->GetHeaderHeight() - + browser_view()->GetTabStripHeight(); + } + return ((frame()->IsMaximized() || frame()->IsFullscreen()) && !restored) ? kTabstripTopSpacingShort : kTabstripTopSpacingTall; }
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_factory_android.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_factory_android.cc deleted file mode 100644 index 851aad6..0000000 --- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_factory_android.cc +++ /dev/null
@@ -1,18 +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 "chrome/browser/ui/views/frame/browser_non_client_frame_view.h" - -#include "chrome/browser/ui/views/frame/browser_view.h" -#include "chrome/browser/ui/views/frame/opaque_browser_frame_view.h" - -namespace chrome { - -BrowserNonClientFrameView* CreateBrowserNonClientFrameView( - BrowserFrame* frame, - BrowserView* browser_view) { - return new OpaqueBrowserFrameView(frame, browser_view); -} - -} // namespace chrome
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc index b132da3..fcbd890 100644 --- a/chrome/browser/ui/views/frame/browser_view.cc +++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -237,9 +237,13 @@ PaintHorizontalBorder(canvas, view, true, separator_color); } + // For the bottom separator, increase the luminance. Either double it or halve + // the distance to 1.0, whichever is less of a difference. + color_utils::HSL hsl; + color_utils::SkColorToHSL(separator_color, &hsl); + hsl.l = std::min((hsl.l + 1) / 2, hsl.l * 2); BrowserView::Paint1pxHorizontalLine( - canvas, - SkColorSetA(separator_color, SkColorGetA(separator_color) / 2), + canvas, color_utils::HSLToSkColor(hsl, SK_AlphaOPAQUE), view->GetLocalBounds(), true); }
diff --git a/chrome/browser/ui/views/frame/immersive_mode_controller_factory_android.cc b/chrome/browser/ui/views/frame/immersive_mode_controller_factory_android.cc deleted file mode 100644 index 0276b96..0000000 --- a/chrome/browser/ui/views/frame/immersive_mode_controller_factory_android.cc +++ /dev/null
@@ -1,16 +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 "chrome/browser/ui/host_desktop.h" -#include "chrome/browser/ui/views/frame/immersive_mode_controller_stub.h" - -namespace chrome { - -ImmersiveModeController* CreateImmersiveModeController( - chrome::HostDesktopType host_desktop_type) { - // TODO(bshe): Implement for Android. See crbug.com/559179. - return new ImmersiveModeControllerStub(); -} - -} // namespace chrome
diff --git a/chrome/browser/ui/views/frame/web_app_left_header_view_ash.cc b/chrome/browser/ui/views/frame/web_app_left_header_view_ash.cc index 4b145e7..2fb92c3 100644 --- a/chrome/browser/ui/views/frame/web_app_left_header_view_ash.cc +++ b/chrome/browser/ui/views/frame/web_app_left_header_view_ash.cc
@@ -13,6 +13,7 @@ #include "components/toolbar/toolbar_model.h" #include "content/public/browser/navigation_entry.h" #include "grit/ash_resources.h" +#include "ui/gfx/vector_icons_public.h" #include "ui/views/layout/box_layout.h" // static @@ -25,10 +26,9 @@ back_button_ = new ash::FrameCaptionButton(this, ash::CAPTION_BUTTON_ICON_BACK); - back_button_->SetImages( - ash::CAPTION_BUTTON_ICON_BACK, ash::FrameCaptionButton::ANIMATE_NO, - IDR_AURA_WINDOW_CONTROL_ICON_BACK, IDR_AURA_WINDOW_CONTROL_BACKGROUND_H, - IDR_AURA_WINDOW_CONTROL_BACKGROUND_P); + back_button_->SetImage(ash::CAPTION_BUTTON_ICON_BACK, + ash::FrameCaptionButton::ANIMATE_NO, + gfx::VectorIconId::WINDOW_CONTROL_BACK); AddChildView(back_button_); location_icon_ = @@ -42,11 +42,9 @@ } void WebAppLeftHeaderView::Update() { - int icon_resource = browser_view_->browser()->toolbar_model()->GetIcon(); - location_icon_->SetImages(ash::CAPTION_BUTTON_ICON_LOCATION, - ash::FrameCaptionButton::ANIMATE_NO, icon_resource, - IDR_AURA_WINDOW_CONTROL_BACKGROUND_H, - IDR_AURA_WINDOW_CONTROL_BACKGROUND_P); + location_icon_->SetImage( + ash::CAPTION_BUTTON_ICON_LOCATION, ash::FrameCaptionButton::ANIMATE_NO, + browser_view_->browser()->toolbar_model()->GetVectorIcon()); back_button_->SetState( chrome::IsCommandEnabled(browser_view_->browser(), IDC_BACK)
diff --git a/chrome/browser/ui/views/frame/web_app_left_header_view_ash_unittest.cc b/chrome/browser/ui/views/frame/web_app_left_header_view_ash_unittest.cc index 50f1178..1c20979 100644 --- a/chrome/browser/ui/views/frame/web_app_left_header_view_ash_unittest.cc +++ b/chrome/browser/ui/views/frame/web_app_left_header_view_ash_unittest.cc
@@ -19,6 +19,7 @@ #include "grit/components_scaled_resources.h" #include "grit/theme_resources.h" #include "ui/aura/window.h" +#include "ui/gfx/vector_icons_public.h" #include "ui/views/controls/button/button.h" #include "url/gurl.h" @@ -43,7 +44,7 @@ test_toolbar_model_ = new TestToolbarModel(); scoped_ptr<ToolbarModel> toolbar_model(test_toolbar_model_); browser()->swap_toolbar_models(&toolbar_model); - test_toolbar_model_->set_icon(IDR_LOCATION_BAR_HTTP); + test_toolbar_model_->set_icon(gfx::VectorIconId::LOCATION_BAR_HTTP); AddTab(browser(), GURL("about:blank")); NavigateAndCommitActiveTab(GURL("http://www.google.com")); @@ -123,11 +124,13 @@ ASSERT_TRUE(view); // The location icon should be non-secure one. - EXPECT_EQ(IDR_LOCATION_BAR_HTTP, view->location_icon_->icon_image_id()); + EXPECT_EQ(gfx::VectorIconId::LOCATION_BAR_HTTP, + view->location_icon_->icon_image_id()); - test_toolbar_model_->set_icon(IDR_OMNIBOX_HTTPS_VALID); + test_toolbar_model_->set_icon(gfx::VectorIconId::LOCATION_BAR_HTTPS_VALID); NavigateAndCommitActiveTab(GURL("https://secure.google.com")); // The location icon should now be the secure one. - EXPECT_EQ(IDR_OMNIBOX_HTTPS_VALID, view->location_icon_->icon_image_id()); + EXPECT_EQ(gfx::VectorIconId::LOCATION_BAR_HTTPS_VALID, + view->location_icon_->icon_image_id()); }
diff --git a/chrome/browser/ui/views/location_bar/location_bar_view.cc b/chrome/browser/ui/views/location_bar/location_bar_view.cc index 0e78556..a5195bd 100644 --- a/chrome/browser/ui/views/location_bar/location_bar_view.cc +++ b/chrome/browser/ui/views/location_bar/location_bar_view.cc
@@ -22,16 +22,12 @@ #include "chrome/browser/extensions/location_bar_controller.h" #include "chrome/browser/extensions/tab_helper.h" #include "chrome/browser/profiles/profile.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/template_url_service_factory.h" #include "chrome/browser/translate/chrome_translate_client.h" #include "chrome/browser/translate/translate_service.h" #include "chrome/browser/ui/autofill/save_card_bubble_controller_impl.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_finder.h" -#include "chrome/browser/ui/browser_instant_controller.h" #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/content_settings/content_setting_bubble_model.h" #include "chrome/browser/ui/layout_constants.h" @@ -1247,11 +1243,6 @@ } void LocationBarView::OnBoundsChanged(const gfx::Rect& previous_bounds) { - InstantService* instant_service = - InstantServiceFactory::GetForProfile(profile()); - if (instant_service) - instant_service->OnOmniboxStartMarginChanged(bounds().x()); - OmniboxPopupView* popup = omnibox_view_->model()->popup_model()->view(); if (popup->IsOpen()) popup->UpdatePopupAppearance();
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller.cc b/chrome/browser/ui/views/tabs/tab_drag_controller.cc index 10e9520..8542c62 100644 --- a/chrome/browser/ui/views/tabs/tab_drag_controller.cc +++ b/chrome/browser/ui/views/tabs/tab_drag_controller.cc
@@ -1800,10 +1800,12 @@ const gfx::Point& screen_point, bool exclude_dragged_view) { std::set<gfx::NativeWindow> exclude; - gfx::NativeWindow dragged_window = - attached_tabstrip_->GetWidget()->GetNativeWindow(); - if (exclude_dragged_view && dragged_window) - exclude.insert(dragged_window); + if (exclude_dragged_view) { + gfx::NativeWindow dragged_window = + attached_tabstrip_->GetWidget()->GetNativeWindow(); + if (dragged_window) + exclude.insert(dragged_window); + } #if defined(OS_LINUX) && !defined(OS_CHROMEOS) // Exclude windows which are pending deletion via Browser::TabStripEmpty(). // These windows can be returned in the Linux Aura port because the browser @@ -1818,6 +1820,8 @@ exclude.insert((*it)->window()->GetNativeWindow()); } #endif - return GetLocalProcessWindowAtPoint(host_desktop_type_, screen_point, exclude, - dragged_window); + return GetLocalProcessWindowAtPoint(host_desktop_type_, + screen_point, + exclude); + }
diff --git a/chrome/browser/ui/views/tabs/window_finder.h b/chrome/browser/ui/views/tabs/window_finder.h index cdb61c1b..91de6c1 100644 --- a/chrome/browser/ui/views/tabs/window_finder.h +++ b/chrome/browser/ui/views/tabs/window_finder.h
@@ -9,19 +9,18 @@ #include "chrome/browser/ui/host_desktop.h" +namespace aura { +class Window; +} + namespace gfx { class Point; } // Returns the Window at the specified point, ignoring the windows in |ignore|. -// On Android, |source| is required to access root window. All other platforms -// do not use the parameter. -// TODO(bshe): Remove |source| once we have a way to get root window from -// |screen_point| on Android. See crbug.com/549735 gfx::NativeWindow GetLocalProcessWindowAtPoint( chrome::HostDesktopType host_desktop_type, const gfx::Point& screen_point, - const std::set<gfx::NativeWindow>& ignore, - gfx::NativeWindow source); + const std::set<gfx::NativeWindow>& ignore); #endif // CHROME_BROWSER_UI_VIEWS_TABS_WINDOW_FINDER_H_
diff --git a/chrome/browser/ui/views/tabs/window_finder_android.cc b/chrome/browser/ui/views/tabs/window_finder_android.cc deleted file mode 100644 index 21c4449..0000000 --- a/chrome/browser/ui/views/tabs/window_finder_android.cc +++ /dev/null
@@ -1,21 +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 "chrome/browser/ui/views/tabs/window_finder.h" - -#include "chrome/browser/ui/host_desktop.h" -#include "chrome/browser/ui/views/tabs/window_finder_impl.h" -#include "ui/aura/window.h" - -gfx::NativeWindow GetLocalProcessWindowAtPoint( - chrome::HostDesktopType host_desktop_type, - const gfx::Point& screen_point, - const std::set<gfx::NativeWindow>& ignore, - gfx::NativeWindow source) { - gfx::NativeWindow root_window = source ? source->GetRootWindow() : nullptr; - if (!root_window) - return nullptr; - return GetLocalProcessWindowAtPointImpl(screen_point, ignore, std::set<int>(), - root_window); -}
diff --git a/chrome/browser/ui/views/tabs/window_finder_ash.cc b/chrome/browser/ui/views/tabs/window_finder_ash.cc index e6de710..1628a82 100644 --- a/chrome/browser/ui/views/tabs/window_finder_ash.cc +++ b/chrome/browser/ui/views/tabs/window_finder_ash.cc
@@ -6,15 +6,55 @@ #include "ash/shell_window_ids.h" #include "ash/wm/coordinate_conversion.h" -#include "chrome/browser/ui/views/tabs/window_finder_impl.h" +#include "ui/aura/client/screen_position_client.h" +#include "ui/aura/window.h" +#include "ui/aura/window_event_dispatcher.h" +#include "ui/wm/core/window_util.h" + +namespace { + +gfx::NativeWindow GetLocalProcessWindowAtPointImpl( + const gfx::Point& screen_point, + const std::set<gfx::NativeWindow>& ignore, + gfx::NativeWindow window) { + if (ignore.find(window) != ignore.end()) + return NULL; + + if (!window->IsVisible()) + return NULL; + + if (window->id() == ash::kShellWindowId_PhantomWindow || + window->id() == ash::kShellWindowId_OverlayContainer || + window->id() == ash::kShellWindowId_MouseCursorContainer) + return NULL; + + if (window->layer()->type() == ui::LAYER_TEXTURED) { + // Returns the window that has visible layer and can hit the + // |screen_point|, because we want to detach the tab as soon as + // the dragging mouse moved over to the window that can hide the + // moving tab. + aura::client::ScreenPositionClient* client = + aura::client::GetScreenPositionClient(window->GetRootWindow()); + gfx::Point local_point = screen_point; + client->ConvertPointFromScreen(window, &local_point); + return window->GetEventHandlerForPoint(local_point) ? window : nullptr; + } + + for (aura::Window::Windows::const_reverse_iterator i = + window->children().rbegin(); i != window->children().rend(); ++i) { + gfx::NativeWindow result = + GetLocalProcessWindowAtPointImpl(screen_point, ignore, *i); + if (result) + return result; + } + return NULL; +} + +} // namespace gfx::NativeWindow GetLocalProcessWindowAtPointAsh( const gfx::Point& screen_point, const std::set<gfx::NativeWindow>& ignore) { - gfx::NativeWindow window = ::ash::wm::GetRootWindowAt(screen_point); - std::set<int> ignore_ash_ids = {ash::kShellWindowId_PhantomWindow, - ash::kShellWindowId_OverlayContainer, - ash::kShellWindowId_MouseCursorContainer}; - return GetLocalProcessWindowAtPointImpl(screen_point, ignore, ignore_ash_ids, - window); + return GetLocalProcessWindowAtPointImpl( + screen_point, ignore, ::ash::wm::GetRootWindowAt(screen_point)); }
diff --git a/chrome/browser/ui/views/tabs/window_finder_chromeos.cc b/chrome/browser/ui/views/tabs/window_finder_chromeos.cc index 5cb43f9..175615c 100644 --- a/chrome/browser/ui/views/tabs/window_finder_chromeos.cc +++ b/chrome/browser/ui/views/tabs/window_finder_chromeos.cc
@@ -14,7 +14,6 @@ gfx::NativeWindow GetLocalProcessWindowAtPoint( chrome::HostDesktopType host_desktop_type, const gfx::Point& screen_point, - const std::set<gfx::NativeWindow>& ignore, - gfx::NativeWindow source) { + const std::set<gfx::NativeWindow>& ignore) { return GetLocalProcessWindowAtPointAsh(screen_point, ignore); }
diff --git a/chrome/browser/ui/views/tabs/window_finder_impl.cc b/chrome/browser/ui/views/tabs/window_finder_impl.cc deleted file mode 100644 index 06c1356d..0000000 --- a/chrome/browser/ui/views/tabs/window_finder_impl.cc +++ /dev/null
@@ -1,48 +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 "chrome/browser/ui/views/tabs/window_finder_impl.h" - -#include "ui/aura/client/screen_position_client.h" -#include "ui/aura/window.h" -#include "ui/aura/window_event_dispatcher.h" -#include "ui/compositor/layer.h" -#include "ui/wm/core/window_util.h" - -gfx::NativeWindow GetLocalProcessWindowAtPointImpl( - const gfx::Point& screen_point, - const std::set<gfx::NativeWindow>& ignore, - const std::set<int>& ignore_ids, - gfx::NativeWindow window) { - if (ignore.find(window) != ignore.end()) - return nullptr; - - if (!window->IsVisible()) - return nullptr; - - if (ignore_ids.find(window->id()) != ignore_ids.end()) - return nullptr; - - if (window->layer()->type() == ui::LAYER_TEXTURED) { - // Returns the window that has visible layer and can hit the - // |screen_point|, because we want to detach the tab as soon as - // the dragging mouse moved over to the window that can hide the - // moving tab. - aura::client::ScreenPositionClient* client = - aura::client::GetScreenPositionClient(window->GetRootWindow()); - gfx::Point local_point = screen_point; - client->ConvertPointFromScreen(window, &local_point); - return window->GetEventHandlerForPoint(local_point) ? window : nullptr; - } - - for (aura::Window::Windows::const_reverse_iterator i = - window->children().rbegin(); - i != window->children().rend(); ++i) { - gfx::NativeWindow result = - GetLocalProcessWindowAtPointImpl(screen_point, ignore, ignore_ids, *i); - if (result) - return result; - } - return nullptr; -}
diff --git a/chrome/browser/ui/views/tabs/window_finder_impl.h b/chrome/browser/ui/views/tabs/window_finder_impl.h deleted file mode 100644 index 17e16cab..0000000 --- a/chrome/browser/ui/views/tabs/window_finder_impl.h +++ /dev/null
@@ -1,22 +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 CHROME_BROWSER_UI_VIEWS_TABS_WINDOW_FINDER_IMPL_H_ -#define CHROME_BROWSER_UI_VIEWS_TABS_WINDOW_FINDER_IMPL_H_ - -#include <set> - -#include "ui/gfx/native_widget_types.h" - -namespace gfx { -class Point; -} - -gfx::NativeWindow GetLocalProcessWindowAtPointImpl( - const gfx::Point& screen_point, - const std::set<gfx::NativeWindow>& ignore, - const std::set<int>& ignore_ids, - gfx::NativeWindow window); - -#endif // CHROME_BROWSER_UI_VIEWS_TABS_WINDOW_FINDER_IMPL_H_
diff --git a/chrome/browser/ui/views/tabs/window_finder_mac.mm b/chrome/browser/ui/views/tabs/window_finder_mac.mm index dfe6e536..b2307da 100644 --- a/chrome/browser/ui/views/tabs/window_finder_mac.mm +++ b/chrome/browser/ui/views/tabs/window_finder_mac.mm
@@ -7,8 +7,7 @@ gfx::NativeWindow GetLocalProcessWindowAtPoint( chrome::HostDesktopType host_desktop_type, const gfx::Point& screen_point, - const std::set<gfx::NativeWindow>& ignore, - gfx::NativeWindow source) { + const std::set<gfx::NativeWindow>& ignore) { NOTIMPLEMENTED(); return NULL; }
diff --git a/chrome/browser/ui/views/tabs/window_finder_win.cc b/chrome/browser/ui/views/tabs/window_finder_win.cc index cb1b3211..c32dba6 100644 --- a/chrome/browser/ui/views/tabs/window_finder_win.cc +++ b/chrome/browser/ui/views/tabs/window_finder_win.cc
@@ -242,8 +242,7 @@ gfx::NativeWindow GetLocalProcessWindowAtPoint( chrome::HostDesktopType host_desktop_type, const gfx::Point& screen_point, - const std::set<gfx::NativeWindow>& ignore, - gfx::NativeWindow source) { + const std::set<gfx::NativeWindow>& ignore) { #if defined(USE_ASH) if (host_desktop_type == chrome::HOST_DESKTOP_TYPE_ASH) return GetLocalProcessWindowAtPointAsh(screen_point, ignore);
diff --git a/chrome/browser/ui/views/tabs/window_finder_x11.cc b/chrome/browser/ui/views/tabs/window_finder_x11.cc index 68df7182..18c9c02 100644 --- a/chrome/browser/ui/views/tabs/window_finder_x11.cc +++ b/chrome/browser/ui/views/tabs/window_finder_x11.cc
@@ -30,8 +30,7 @@ gfx::NativeWindow GetLocalProcessWindowAtPoint( chrome::HostDesktopType host_desktop_type, const gfx::Point& screen_point, - const std::set<gfx::NativeWindow>& ignore, - gfx::NativeWindow source) { + const std::set<gfx::NativeWindow>& ignore) { #if defined(USE_ASH) if (host_desktop_type == chrome::HOST_DESKTOP_TYPE_ASH) return GetLocalProcessWindowAtPointAsh(screen_point, ignore);
diff --git a/chrome/browser/ui/views/theme_image_mapper.cc b/chrome/browser/ui/views/theme_image_mapper.cc index 4185c90..832d6a1 100644 --- a/chrome/browser/ui/views/theme_image_mapper.cc +++ b/chrome/browser/ui/views/theme_image_mapper.cc
@@ -12,7 +12,7 @@ // On platforms where there is both Ash and a desktop browser, provide DESKTOP // resources for the latter. int MapThemeImage(HostDesktopType desktop_type, int resource) { -#if !defined(OS_CHROMEOS) && !defined(OS_MACOSX) && !defined(OS_ANDROID) +#if !defined(OS_CHROMEOS) && !defined(OS_MACOSX) if (desktop_type != HOST_DESKTOP_TYPE_NATIVE) return resource;
diff --git a/chrome/browser/ui/views/toolbar/toolbar_button.cc b/chrome/browser/ui/views/toolbar/toolbar_button.cc index 020e34ce..06c08fe 100644 --- a/chrome/browser/ui/views/toolbar/toolbar_button.cc +++ b/chrome/browser/ui/views/toolbar/toolbar_button.cc
@@ -192,10 +192,6 @@ layer()->Add(ink_drop_layer); layer()->StackAtBottom(ink_drop_layer); - - // Invalidates the contents of the parent's layer which may contain - // a stale close/reload icon that should not remain visible. - parent()->SchedulePaint(); } void ToolbarButton::RemoveInkDropLayer(ui::Layer* ink_drop_layer) {
diff --git a/chrome/browser/ui/views/website_settings/chooser_bubble_ui_view.cc b/chrome/browser/ui/views/website_settings/chooser_bubble_ui_view.cc index 5d4d566b..7a853b6 100644 --- a/chrome/browser/ui/views/website_settings/chooser_bubble_ui_view.cc +++ b/chrome/browser/ui/views/website_settings/chooser_bubble_ui_view.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/ui/views/website_settings/chooser_bubble_ui_view.h" +#include <algorithm> #include <string> #include "base/macros.h" @@ -115,84 +116,20 @@ class ChooserTableModel : public ui::TableModel, public ChooserBubbleDelegate::Observer { public: - explicit ChooserTableModel(ChooserBubbleDelegate* chooser_bubble_delegate) - : observer_(nullptr), chooser_bubble_delegate_(chooser_bubble_delegate) { - chooser_bubble_delegate_->set_observer(this); - } + explicit ChooserTableModel(ChooserBubbleDelegate* chooser_bubble_delegate); // ui::TableModel: - int RowCount() override { - const std::vector<base::string16>& device_names = - chooser_bubble_delegate_->GetOptions(); - if (device_names.empty()) { - // Here it returns 1 when there is no device. In this case, the - // table view still needs to display a text message saying no - // devices found, so the number of rows is 1. - return 1; - } else { - return static_cast<int>(device_names.size()); - } - } + int RowCount() override; + base::string16 GetText(int row, int column_id) override; + void SetObserver(ui::TableModelObserver* observer) override; - // ui::TableModel: - base::string16 GetText(int row, int column_id) override { - const std::vector<base::string16>& device_names = - chooser_bubble_delegate_->GetOptions(); - if (device_names.empty()) { - DCHECK(row == 0); - return l10n_util::GetStringUTF16( - IDS_CHOOSER_BUBBLE_NO_DEVICES_FOUND_PROMPT); - } else if (row >= 0 && row < static_cast<int>(device_names.size())) { - return device_names[row]; - } else { - NOTREACHED(); - return base::string16(); - } - } + // ChooserBubbleDelegate::Observer: + void OnOptionsInitialized() override; + void OnOptionAdded(size_t index) override; + void OnOptionRemoved(size_t index) override; - // ui::TableModel: - void SetObserver(ui::TableModelObserver* observer) override { - observer_ = observer; - } - - // ChooserOptions::Observer: - void OnOptionsInitialized() override { - if (observer_) { - observer_->OnModelChanged(); - Update(); - } - } - - // ChooserOptions::Observer: - void OnOptionAdded(int index) override { - if (observer_) { - observer_->OnItemsAdded(index, 1); - Update(); - } - } - - // ChooserOptions::Observer: - void OnOptionRemoved(int index) override { - if (observer_) { - observer_->OnItemsRemoved(index, 1); - Update(); - } - } - - void Update() { - views::TableView* table_view = static_cast<views::TableView*>(observer_); - - if (chooser_bubble_delegate_->GetOptions().empty()) { - observer_->OnModelChanged(); - table_view->SetEnabled(false); - } else { - table_view->SetEnabled(true); - } - } - - void SetConnectButton(views::LabelButton* connect_button) { - connect_button_ = connect_button; - } + void Update(); + void SetConnectButton(views::LabelButton* connect_button); private: ui::TableModelObserver* observer_; @@ -232,7 +169,7 @@ views::GridLayout::FILL, views::GridLayout::FILL, kChooserPermissionBubbleWidth, kChooserPermissionBubbleHeight); - if (chooser_bubble_delegate_->GetOptions().empty()) { + if (chooser_bubble_delegate_->NumOptions() == 0) { table_view_->SetEnabled(false); } @@ -344,6 +281,71 @@ SetAnchorView(anchor_view); } +ChooserTableModel::ChooserTableModel( + ChooserBubbleDelegate* chooser_bubble_delegate) + : observer_(nullptr), chooser_bubble_delegate_(chooser_bubble_delegate) { + chooser_bubble_delegate_->set_observer(this); +} + +int ChooserTableModel::RowCount() { + // When there are no devices, the table contains a message saying there + // are no devices, so the number of rows is always at least 1. + return std::max(static_cast<int>(chooser_bubble_delegate_->NumOptions()), 1); +} + +base::string16 ChooserTableModel::GetText(int row, int column_id) { + int num_options = static_cast<int>(chooser_bubble_delegate_->NumOptions()); + if (num_options == 0) { + DCHECK_EQ(0, row); + return l10n_util::GetStringUTF16( + IDS_CHOOSER_BUBBLE_NO_DEVICES_FOUND_PROMPT); + } + + DCHECK_GE(row, 0); + DCHECK_LT(row, num_options); + return chooser_bubble_delegate_->GetOption(static_cast<size_t>(row)); +} + +void ChooserTableModel::SetObserver(ui::TableModelObserver* observer) { + observer_ = observer; +} + +void ChooserTableModel::OnOptionsInitialized() { + if (observer_) { + observer_->OnModelChanged(); + Update(); + } +} + +void ChooserTableModel::OnOptionAdded(size_t index) { + if (observer_) { + observer_->OnItemsAdded(static_cast<int>(index), 1); + Update(); + } +} + +void ChooserTableModel::OnOptionRemoved(size_t index) { + if (observer_) { + observer_->OnItemsRemoved(static_cast<int>(index), 1); + Update(); + } +} + +void ChooserTableModel::Update() { + views::TableView* table_view = static_cast<views::TableView*>(observer_); + + if (chooser_bubble_delegate_->NumOptions() == 0) { + observer_->OnModelChanged(); + table_view->SetEnabled(false); + } else { + table_view->SetEnabled(true); + } +} + +void ChooserTableModel::SetConnectButton(views::LabelButton* connect_button) { + connect_button_ = connect_button; +} + ////////////////////////////////////////////////////////////////////////////// // ChooserBubbleUiView
diff --git a/chrome/browser/ui/website_settings/chooser_bubble_delegate.h b/chrome/browser/ui/website_settings/chooser_bubble_delegate.h index 6166e56..4e4f3bd 100644 --- a/chrome/browser/ui/website_settings/chooser_bubble_delegate.h +++ b/chrome/browser/ui/website_settings/chooser_bubble_delegate.h
@@ -35,16 +35,18 @@ // Called after the options list is initialized for the first time. // OnOptionsInitialized should only be called once. virtual void OnOptionsInitialized() = 0; - // Called after GetOptions()[index] has been added to the options and the + + // Called after GetOption(index) has been added to the options and the // newly added option is the last element in the options list. Calling - // GetOptions()[index] from inside a call to OnOptionAdded will see the + // GetOption(index) from inside a call to OnOptionAdded will see the // added string since the options have already been updated. - virtual void OnOptionAdded(int index) = 0; - // Called when GetOptions()[index] is no longer present, and all later - // options have been moved earlier by 1 slot. Calling GetOptions()[index] + virtual void OnOptionAdded(size_t index) = 0; + + // Called when GetOption(index) is no longer present, and all later + // options have been moved earlier by 1 slot. Calling GetOption(index) // from inside a call to OnOptionRemoved will NOT see the removed string // since the options have already been updated. - virtual void OnOptionRemoved(int index) = 0; + virtual void OnOptionRemoved(size_t index) = 0; protected: virtual ~Observer() {} @@ -54,16 +56,22 @@ std::string GetName() const override; scoped_ptr<BubbleUi> BuildBubbleUi() override; - // The set of options users can pick from. For example, it can be - // USB/Bluetooth devices names which are listed in the chooser bubble - // so that users can grant permission. - virtual const std::vector<base::string16>& GetOptions() const = 0; + // The number of options users can pick from. For example, it can be + // the number of USB/Bluetooth device names which are listed in the + // chooser bubble so that users can grant permission. + virtual size_t NumOptions() const = 0; + + // The |index|th option string which is listed in the chooser bubble. + virtual const base::string16& GetOption(size_t index) const = 0; // These three functions are called just before this object is destroyed: + // Called when the user selects the |index|th element from the dialog. - virtual void Select(int index) = 0; + virtual void Select(size_t index) = 0; + // Called when the user presses the 'Cancel' button in the dialog. virtual void Cancel() = 0; + // Called when the user clicks outside the dialog or the dialog otherwise // closes without the user taking an explicit action. virtual void Close() = 0;
diff --git a/chrome/browser/ui/webui/bookmarks_ui_browsertest.cc b/chrome/browser/ui/webui/bookmarks_ui_browsertest.cc index 410e7fcb..c2440d84 100644 --- a/chrome/browser/ui/webui/bookmarks_ui_browsertest.cc +++ b/chrome/browser/ui/webui/bookmarks_ui_browsertest.cc
@@ -21,7 +21,11 @@ void SetUpOnMainThread() override { InProcessBrowserTest::SetUpOnMainThread(); - EnableAccessibilityChecksForTestCase(true); + + // Re-enable accessibility checks when audit failures are resolved. + // AX_TEXT_01: http://crbug.com/559201 + // AX_ARIA_08: http://crbug.com/559202 + // EnableAccessibilityChecksForTestCase(true); } void OpenBookmarksManager() {
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 2689679..b197c127 100644 --- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc +++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
@@ -47,7 +47,7 @@ #include "chrome/browser/ui/webui/omnibox/omnibox_ui.h" #include "chrome/browser/ui/webui/options/options_ui.h" #include "chrome/browser/ui/webui/password_manager_internals/password_manager_internals_ui.h" -#include "chrome/browser/ui/webui/plugins_ui.h" +#include "chrome/browser/ui/webui/plugins/plugins_ui.h" #include "chrome/browser/ui/webui/predictors/predictors_ui.h" #include "chrome/browser/ui/webui/profiler_ui.h" #include "chrome/browser/ui/webui/settings/md_settings_ui.h" @@ -115,7 +115,6 @@ #if defined(OS_ANDROID) || defined(OS_IOS) #include "chrome/browser/ui/webui/net_export_ui.h" #else -#include "chrome/browser/devtools/device/webrtc/webrtc_device_provider.h" #include "chrome/browser/signin/easy_unlock_service.h" #include "chrome/browser/signin/easy_unlock_service_factory.h" #include "chrome/browser/ui/webui/copresence_ui.h" @@ -504,8 +503,6 @@ return &NewWebUI<InlineLoginUI>; if (url.SchemeIs(content::kChromeDevToolsScheme)) return &NewWebUI<DevToolsUI>; - if (url.host() == chrome::kChromeUIWebRTCDeviceProviderHost) - return &NewWebUI<WebRTCDeviceProvider::WebUI>; // chrome://inspect isn't supported on Android nor iOS. Page debugging is // handled by a remote devtools on the host machine, and other elements, i.e.
diff --git a/chrome/browser/ui/webui/downloads_ui_browsertest.js b/chrome/browser/ui/webui/downloads_ui_browsertest.js index 89fc311..8ffba04 100644 --- a/chrome/browser/ui/webui/downloads_ui_browsertest.js +++ b/chrome/browser/ui/webui/downloads_ui_browsertest.js
@@ -120,6 +120,8 @@ setUp: function() { // Doesn't create any fake downloads. assertEquals(0, downloads.Manager.size()); + + this.updateAccessibilityAuditConfig(); }, };
diff --git a/chrome/browser/ui/webui/downloads_ui_browsertest_base.js b/chrome/browser/ui/webui/downloads_ui_browsertest_base.js index 4af9e7e..24ec279 100644 --- a/chrome/browser/ui/webui/downloads_ui_browsertest_base.js +++ b/chrome/browser/ui/webui/downloads_ui_browsertest_base.js
@@ -47,6 +47,8 @@ * @override */ setUp: function() { + testing.Test.prototype.setUp.call(this); + this.createdDownloads = []; // The entries will begin at 1:00 AM on Sept 2, 2008, and will be spaced @@ -58,6 +60,26 @@ } downloads.Manager.updateAll(this.createdDownloads); expectEquals(downloads.Manager.size(), TOTAL_RESULT_COUNT); + + this.updateAccessibilityAuditConfig(); + }, + + /** + * Disables failing accessibility audits. This should be removed when all + * audit issues have been resolved. + */ + updateAccessibilityAuditConfig: function() { + // Enable when failure is resolved. + // AX_TEXT_01: http://crbug.com/559217 + this.accessibilityAuditConfig.ignoreSelectors( + 'controlsWithoutLabel', + '#term'); + + // Enable when failure is resolved. + // AX_FOCUS_03: http://crbug.com/559219 + this.accessibilityAuditConfig.ignoreSelectors( + 'tabIndexGreaterThanZero', + '#term'); }, /**
diff --git a/chrome/browser/ui/webui/extensions/extension_settings_browsertest.js b/chrome/browser/ui/webui/extensions/extension_settings_browsertest.js index d7847ef..1aca91b 100644 --- a/chrome/browser/ui/webui/extensions/extension_settings_browsertest.js +++ b/chrome/browser/ui/webui/extensions/extension_settings_browsertest.js
@@ -51,7 +51,14 @@ /** @override */ setUp: function() { + testing.Test.prototype.setUp.call(this); testing.Test.disableAnimationsAndTransitions(); + + // Enable when failure is resolved. + // AX_ARIA_08: http://crbug.com/560903 + this.accessibilityAuditConfig.ignoreSelectors( + 'requiredOwnedAriaRoleMissing', + '#kiosk-app-list'); }, /**
diff --git a/chrome/browser/ui/webui/local_discovery/local_discovery_ui_handler.cc b/chrome/browser/ui/webui/local_discovery/local_discovery_ui_handler.cc index e623163..ecade406 100644 --- a/chrome/browser/ui/webui/local_discovery/local_discovery_ui_handler.cc +++ b/chrome/browser/ui/webui/local_discovery/local_discovery_ui_handler.cc
@@ -14,14 +14,13 @@ #include "base/strings/utf_string_conversions.h" #include "base/values.h" #include "build/build_config.h" -#include "chrome/browser/local_discovery/cloud_device_list.h" -#include "chrome/browser/local_discovery/privet_confirm_api_flow.h" -#include "chrome/browser/local_discovery/privet_constants.h" -#include "chrome/browser/local_discovery/privet_device_lister_impl.h" -#include "chrome/browser/local_discovery/privet_http_asynchronous_factory.h" #include "chrome/browser/local_discovery/service_discovery_shared_client.h" #include "chrome/browser/printing/cloud_print/cloud_print_proxy_service.h" #include "chrome/browser/printing/cloud_print/cloud_print_proxy_service_factory.h" +#include "chrome/browser/printing/cloud_print/privet_confirm_api_flow.h" +#include "chrome/browser/printing/cloud_print/privet_constants.h" +#include "chrome/browser/printing/cloud_print/privet_device_lister_impl.h" +#include "chrome/browser/printing/cloud_print/privet_http_asynchronous_factory.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/signin/profile_oauth2_token_service_factory.h" #include "chrome/browser/signin/signin_manager_factory.h" @@ -41,6 +40,11 @@ #define CLOUD_PRINT_CONNECTOR_UI_AVAILABLE #endif +using cloud_print::CloudPrintPrinterList; +using cloud_print::DeviceDescription; +using cloud_print::GCDApiFlow; +using cloud_print::PrivetRegisterOperation; + namespace local_discovery { namespace { @@ -59,30 +63,29 @@ const int kCloudDevicesPrivetVersion = 3; scoped_ptr<base::DictionaryValue> CreateDeviceInfo( - const CloudDeviceListDelegate::Device& description) { + const CloudPrintPrinterList::Device& description) { scoped_ptr<base::DictionaryValue> return_value(new base::DictionaryValue); return_value->SetString(kDictionaryKeyID, description.id); return_value->SetString(kDictionaryKeyDisplayName, description.display_name); return_value->SetString(kDictionaryKeyDescription, description.description); - return_value->SetString(kDictionaryKeyType, description.type); + return_value->SetString(kDictionaryKeyType, "printer"); return return_value; } -void ReadDevicesList( - const std::vector<CloudDeviceListDelegate::Device>& devices, - const std::set<std::string>& local_ids, - base::ListValue* devices_list) { - for (CloudDeviceList::iterator i = devices.begin(); i != devices.end(); i++) { - if (local_ids.count(i->id) > 0) { - devices_list->Append(CreateDeviceInfo(*i).release()); +void ReadDevicesList(const CloudPrintPrinterList::DeviceList& devices, + const std::set<std::string>& local_ids, + base::ListValue* devices_list) { + for (const auto& i : devices) { + if (local_ids.count(i.id) > 0) { + devices_list->Append(CreateDeviceInfo(i).release()); } } - for (CloudDeviceList::iterator i = devices.begin(); i != devices.end(); i++) { - if (local_ids.count(i->id) == 0) { - devices_list->Append(CreateDeviceInfo(*i).release()); + for (const auto& i : devices) { + if (local_ids.count(i.id) == 0) { + devices_list->Append(CreateDeviceInfo(i).release()); } } } @@ -171,9 +174,11 @@ if (!privet_lister_) { service_discovery_client_ = ServiceDiscoverySharedClient::GetInstance(); privet_lister_.reset( - new PrivetDeviceListerImpl(service_discovery_client_.get(), this)); - privet_http_factory_ = PrivetHTTPAsynchronousFactory::CreateInstance( - profile->GetRequestContext()); + new cloud_print::PrivetDeviceListerImpl(service_discovery_client_.get(), + this)); + privet_http_factory_ = + cloud_print::PrivetHTTPAsynchronousFactory::CreateInstance( + profile->GetRequestContext()); SigninManagerBase* signin_manager = SigninManagerFactory::GetInstance()->GetForProfile(profile); @@ -268,9 +273,9 @@ } void LocalDiscoveryUIHandler::StartRegisterHTTP( - scoped_ptr<PrivetHTTPClient> http_client) { + scoped_ptr<cloud_print::PrivetHTTPClient> http_client) { current_http_client_ = - PrivetV1HTTPClient::CreateDefault(std::move(http_client)); + cloud_print::PrivetV1HTTPClient::CreateDefault(std::move(http_client)); std::string user = GetSyncAccount(); @@ -285,7 +290,7 @@ } void LocalDiscoveryUIHandler::OnPrivetRegisterClaimToken( - PrivetRegisterOperation* operation, + cloud_print::PrivetRegisterOperation* operation, const std::string& token, const GURL& url) { web_ui()->CallJavascriptFunction( @@ -301,10 +306,11 @@ return; } confirm_api_call_flow_->Start( - make_scoped_ptr<GCDApiFlow::Request>(new PrivetConfirmApiCallFlow( - token, - base::Bind(&LocalDiscoveryUIHandler::OnConfirmDone, - base::Unretained(this))))); + make_scoped_ptr<GCDApiFlow::Request>( + new cloud_print::PrivetConfirmApiCallFlow( + token, + base::Bind(&LocalDiscoveryUIHandler::OnConfirmDone, + base::Unretained(this))))); } void LocalDiscoveryUIHandler::OnPrivetRegisterError( @@ -316,12 +322,12 @@ std::string error; if (reason == PrivetRegisterOperation::FAILURE_JSON_ERROR && - json->GetString(kPrivetKeyError, &error)) { - if (error == kPrivetErrorTimeout) { + json->GetString(cloud_print::kPrivetKeyError, &error)) { + if (error == cloud_print::kPrivetErrorTimeout) { web_ui()->CallJavascriptFunction( "local_discovery.onRegistrationTimeout"); return; - } else if (error == kPrivetErrorCancel) { + } else if (error == cloud_print::kPrivetErrorCancel) { web_ui()->CallJavascriptFunction( "local_discovery.onRegistrationCanceledPrinter"); return; @@ -396,7 +402,7 @@ } void LocalDiscoveryUIHandler::OnDeviceListReady( - const std::vector<Device>& devices) { + const CloudPrintPrinterList::DeviceList& devices) { cloud_devices_.insert(cloud_devices_.end(), devices.begin(), devices.end()); ++succeded_list_count_; CheckListingDone();
diff --git a/chrome/browser/ui/webui/local_discovery/local_discovery_ui_handler.h b/chrome/browser/ui/webui/local_discovery/local_discovery_ui_handler.h index 2873c45..40d05904 100644 --- a/chrome/browser/ui/webui/local_discovery/local_discovery_ui_handler.h +++ b/chrome/browser/ui/webui/local_discovery/local_discovery_ui_handler.h
@@ -11,9 +11,9 @@ #include "base/macros.h" #include "build/build_config.h" -#include "chrome/browser/local_discovery/cloud_print_printer_list.h" -#include "chrome/browser/local_discovery/privet_device_lister.h" -#include "chrome/browser/local_discovery/privet_http.h" +#include "chrome/browser/printing/cloud_print/cloud_print_printer_list.h" +#include "chrome/browser/printing/cloud_print/privet_device_lister.h" +#include "chrome/browser/printing/cloud_print/privet_http.h" #include "components/signin/core/browser/signin_manager.h" #include "content/public/browser/web_ui_message_handler.h" @@ -21,23 +21,27 @@ #define CLOUD_PRINT_CONNECTOR_UI_AVAILABLE #endif -// TODO(noamsml): Factor out full registration flow into single class -namespace local_discovery { - +namespace cloud_print { class PrivetConfirmApiCallFlow; class PrivetHTTPAsynchronousFactory; class PrivetHTTPResolution; class PrivetV1HTTPClient; +} + +// TODO(noamsml): Factor out full registration flow into single class +namespace local_discovery { + class ServiceDiscoverySharedClient; // UI Handler for chrome://devices/ // It listens to local discovery notifications and passes those notifications // into the Javascript to update the page. -class LocalDiscoveryUIHandler : public content::WebUIMessageHandler, - public PrivetRegisterOperation::Delegate, - public PrivetDeviceLister::Delegate, - public CloudDeviceListDelegate, - public SigninManagerBase::Observer { +class LocalDiscoveryUIHandler + : public content::WebUIMessageHandler, + public cloud_print::PrivetRegisterOperation::Delegate, + public cloud_print::PrivetDeviceLister::Delegate, + public cloud_print::CloudPrintPrinterList::Delegate, + public SigninManagerBase::Observer { public: LocalDiscoveryUIHandler(); ~LocalDiscoveryUIHandler() override; @@ -47,26 +51,30 @@ // WebUIMessageHandler implementation. void RegisterMessages() override; // PrivetRegisterOperation::Delegate implementation. - void OnPrivetRegisterClaimToken(PrivetRegisterOperation* operation, - const std::string& token, - const GURL& url) override; - void OnPrivetRegisterError(PrivetRegisterOperation* operation, - const std::string& action, - PrivetRegisterOperation::FailureReason reason, - int printer_http_code, - const base::DictionaryValue* json) override; - void OnPrivetRegisterDone(PrivetRegisterOperation* operation, + void OnPrivetRegisterClaimToken( + cloud_print::PrivetRegisterOperation* operation, + const std::string& token, + const GURL& url) override; + void OnPrivetRegisterError( + cloud_print::PrivetRegisterOperation* operation, + const std::string& action, + cloud_print::PrivetRegisterOperation::FailureReason reason, + int printer_http_code, + const base::DictionaryValue* json) override; + void OnPrivetRegisterDone(cloud_print::PrivetRegisterOperation* operation, const std::string& device_id) override; // PrivetDeviceLister::Delegate implementation. - void DeviceChanged(bool added, - const std::string& name, - const DeviceDescription& description) override; + void DeviceChanged( + bool added, + const std::string& name, + const cloud_print::DeviceDescription& description) override; void DeviceRemoved(const std::string& name) override; void DeviceCacheFlushed() override; - // CloudDeviceListDelegate implementation. - void OnDeviceListReady(const std::vector<Device>& devices) override; + // CloudPrintPrinterList::Delegate implementation. + void OnDeviceListReady( + const cloud_print::CloudPrintPrinterList::DeviceList& devices) override; void OnDeviceListUnavailable() override; // SigninManagerBase::Observer implementation. @@ -77,7 +85,8 @@ const std::string& username) override; private: - typedef std::map<std::string, DeviceDescription> DeviceDescriptionMap; + typedef std::map<std::string, + cloud_print::DeviceDescription> DeviceDescriptionMap; typedef base::Callback<void(bool result)> ResultCallback; // Message handlers: @@ -104,11 +113,11 @@ void HandleShowSyncUI(const base::ListValue* args); // For when the IP address of the printer has been resolved for registration. - void StartRegisterHTTP(scoped_ptr<PrivetHTTPClient> http_client); + void StartRegisterHTTP(scoped_ptr<cloud_print::PrivetHTTPClient> http_client); // For when the confirm operation on the cloudprint server has finished // executing. - void OnConfirmDone(GCDApiFlow::Status status); + void OnConfirmDone(cloud_print::GCDApiFlow::Status status); // Signal to the web interface an error has ocurred while registering. void SendRegisterError(); @@ -125,7 +134,7 @@ // Reset and cancel the current registration. void ResetCurrentRegistration(); - scoped_ptr<GCDApiFlow> CreateApiFlow(); + scoped_ptr<cloud_print::GCDApiFlow> CreateApiFlow(); void OnSetupError(); // Announcement hasn't been sent for a certain time after registration @@ -156,29 +165,29 @@ scoped_refptr<ServiceDiscoverySharedClient> service_discovery_client_; // A factory for creating the privet HTTP Client. - scoped_ptr<PrivetHTTPAsynchronousFactory> privet_http_factory_; + scoped_ptr<cloud_print::PrivetHTTPAsynchronousFactory> privet_http_factory_; // An object representing the resolution process for the privet_http_factory. - scoped_ptr<PrivetHTTPResolution> privet_resolution_; + scoped_ptr<cloud_print::PrivetHTTPResolution> privet_resolution_; // The current HTTP client (used for the current operation). - scoped_ptr<PrivetV1HTTPClient> current_http_client_; + scoped_ptr<cloud_print::PrivetV1HTTPClient> current_http_client_; // The current register operation. Only one allowed at any time. - scoped_ptr<PrivetRegisterOperation> current_register_operation_; + scoped_ptr<cloud_print::PrivetRegisterOperation> current_register_operation_; // The current confirm call used during the registration flow. - scoped_ptr<GCDApiFlow> confirm_api_call_flow_; + scoped_ptr<cloud_print::GCDApiFlow> confirm_api_call_flow_; // The device lister used to list devices on the local network. - scoped_ptr<PrivetDeviceLister> privet_lister_; + scoped_ptr<cloud_print::PrivetDeviceLister> privet_lister_; // Whether or not the page is marked as visible. bool is_visible_; // List of printers from cloud print. - scoped_ptr<GCDApiFlow> cloud_print_printer_list_; - std::vector<Device> cloud_devices_; + scoped_ptr<cloud_print::GCDApiFlow> cloud_print_printer_list_; + std::vector<cloud_print::CloudPrintPrinterList::Device> cloud_devices_; int failed_list_count_; int succeded_list_count_;
diff --git a/chrome/browser/ui/webui/options/browser_options_browsertest.js b/chrome/browser/ui/webui/options/browser_options_browsertest.js index 004535c..4415c04 100644 --- a/chrome/browser/ui/webui/options/browser_options_browsertest.js +++ b/chrome/browser/ui/webui/options/browser_options_browsertest.js
@@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +GEN_INCLUDE(['options_browsertest_base.js']); + /** * TestFixture for browser options WebUI testing. * @extends {testing.Test} @@ -73,10 +75,27 @@ function BrowserOptionsFrameWebUITest() {} BrowserOptionsFrameWebUITest.prototype = { - __proto__: testing.Test.prototype, + __proto__: OptionsBrowsertestBase.prototype, /** @override */ browsePreload: 'chrome://settings-frame/', + + /** @override */ + setUp: function() { + OptionsBrowsertestBase.prototype.setUp.call(this); + + // Enable when failure is resolved. + // AX_TEXT_04: http://crbug.com/570721 + this.accessibilityAuditConfig.ignoreSelectors( + 'linkWithUnclearPurpose', + '#sync-overview > A'); + + // Enable when failure is resolved. + // AX_ARIA_10: http://crbug.com/570723 + this.accessibilityAuditConfig.ignoreSelectors( + 'unsupportedAriaAttribute', + '#profiles-list'); + }, }; TEST_F('BrowserOptionsFrameWebUITest', 'testAdvancedSettingsHiddenByDefault', @@ -92,7 +111,7 @@ function AdvancedSettingsWebUITest() {} AdvancedSettingsWebUITest.prototype = { - __proto__: testing.Test.prototype, + __proto__: OptionsBrowsertestBase.prototype, /** @override */ browsePreload: 'chrome://settings-frame/autofill',
diff --git a/chrome/browser/ui/webui/options/browser_options_handler.cc b/chrome/browser/ui/webui/options/browser_options_handler.cc index b081f9c5..3d948bc 100644 --- a/chrome/browser/ui/webui/options/browser_options_handler.cc +++ b/chrome/browser/ui/webui/options/browser_options_handler.cc
@@ -142,7 +142,7 @@ #endif // defined(OS_WIN) #if defined(ENABLE_SERVICE_DISCOVERY) -#include "chrome/browser/local_discovery/privet_notifications.h" +#include "chrome/browser/printing/cloud_print/privet_notifications.h" #endif #if defined(USE_ASH) @@ -645,7 +645,7 @@ #if defined(ENABLE_SERVICE_DISCOVERY) values->SetBoolean("cloudPrintHideNotificationsCheckbox", - !local_discovery::PrivetNotificationService::IsEnabled()); + !cloud_print::PrivetNotificationService::IsEnabled()); #endif values->SetBoolean("cloudPrintShowMDnsOptions",
diff --git a/chrome/browser/ui/webui/options/certificate_manager_browsertest.js b/chrome/browser/ui/webui/options/certificate_manager_browsertest.js index 8a553a7..cb9e3d81 100644 --- a/chrome/browser/ui/webui/options/certificate_manager_browsertest.js +++ b/chrome/browser/ui/webui/options/certificate_manager_browsertest.js
@@ -6,6 +6,8 @@ // isn't implemented if OpenSSL is used. GEN('#if defined(USE_NSS_CERTS)'); +GEN_INCLUDE(['options_browsertest_base.js']); + /** * URL of the Certificates dialog in the Settings page. * @const @@ -32,7 +34,7 @@ function CertificateManagerWebUIBaseTest() {} CertificateManagerWebUIBaseTest.prototype = { - __proto__: testing.Test.prototype, + __proto__: OptionsBrowsertestBase.prototype, /** @override */ preLoad: function() { @@ -53,6 +55,44 @@ 'viewCertificate', ]); }, + + /** @override */ + setUp: function() { + OptionsBrowsertestBase.prototype.setUp.call(this); + + var ariaRoleNotScopedSelectors = [ + '#tree-item-autogen-id-0', + '#tree-item-autogen-id-1', + '#tree-item-autogen-id-2', + '#tree-item-autogen-id-3', + '#tree-item-autogen-id-4', + ]; + + // Enable when failure is resolved. + // AX_ARIA_09: http://crbug.com/570567 + this.accessibilityAuditConfig.ignoreSelectors( + 'ariaRoleNotScoped', + ariaRoleNotScopedSelectors); + + // Enable when failure is resolved. + // AX_ARIA_10: http://crbug.com/570566 + this.accessibilityAuditConfig.ignoreSelectors( + 'unsupportedAriaAttribute', + '#caCertsTab-tree'); + + var focusableElementNotVisibleAndNotAriaHiddenSelectors = [ + '#personalCertsTab-tree', + '#personalCertsTab-import', + '#personalCertsTab-import-and-bind', + '#certificate-confirm', + ]; + + // Enable when failure is resolved. + // AX_FOCUS_01: http://crbug.com/570568 + this.accessibilityAuditConfig.ignoreSelectors( + 'focusableElementNotVisibleAndNotAriaHidden', + focusableElementNotVisibleAndNotAriaHiddenSelectors); + }, }; /**
diff --git a/chrome/browser/ui/webui/options/chromeos/bluetooth_options_browsertest.js b/chrome/browser/ui/webui/options/chromeos/bluetooth_options_browsertest.js index 607484c2..bccb3a7 100644 --- a/chrome/browser/ui/webui/options/chromeos/bluetooth_options_browsertest.js +++ b/chrome/browser/ui/webui/options/chromeos/bluetooth_options_browsertest.js
@@ -4,10 +4,12 @@ GEN('#if defined(OS_CHROMEOS)'); +GEN_INCLUDE(['../options_browsertest_base.js']); + function BluetoothWebUITestAsync() {} BluetoothWebUITestAsync.prototype = { - __proto__: testing.Test.prototype, + __proto__: OptionsBrowsertestBase.prototype, /** @override */ isAsync: true, @@ -50,6 +52,22 @@ paired: false }, + /** @override */ + setUp: function() { + OptionsBrowsertestBase.prototype.setUp.call(this); + + var unsupportedAriaAttributeSelectors = [ + '#bluetooth-paired-devices-list', + '#bluetooth-unpaired-devices-list', + ]; + + // Enable when failure is resolved. + // AX_ARIA_10: http://crbug.com/570564 + this.accessibilityAuditConfig.ignoreSelectors( + 'unsupportedAriaAttribute', + unsupportedAriaAttributeSelectors); + }, + /** * Retrieves the list item associated with a Bluetooth device. * @param {!Element} listElement Element containing a list of devices. @@ -86,7 +104,6 @@ element.value = text; cr.dispatchSimpleEvent(element, 'input'); }, - }; TEST_F('BluetoothWebUITestAsync', 'testEnableBluetooth', function() {
diff --git a/chrome/browser/ui/webui/options/chromeos/power_overlay_browsertest.js b/chrome/browser/ui/webui/options/chromeos/power_overlay_browsertest.js index ce1b01a6..d49131c 100644 --- a/chrome/browser/ui/webui/options/chromeos/power_overlay_browsertest.js +++ b/chrome/browser/ui/webui/options/chromeos/power_overlay_browsertest.js
@@ -2,10 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +GEN_INCLUDE(['../options_browsertest_base.js']); + function PowerOverlayWebUITest() {} PowerOverlayWebUITest.prototype = { - __proto__: testing.Test.prototype, + __proto__: OptionsBrowsertestBase.prototype, browsePreload: 'chrome://settings-frame/',
diff --git a/chrome/browser/ui/webui/options/clear_browser_data_handler.cc b/chrome/browser/ui/webui/options/clear_browser_data_handler.cc index eafdd443..847d0b5 100644 --- a/chrome/browser/ui/webui/options/clear_browser_data_handler.cc +++ b/chrome/browser/ui/webui/options/clear_browser_data_handler.cc
@@ -9,7 +9,6 @@ #include "base/bind.h" #include "base/bind_helpers.h" -#include "base/command_line.h" #include "base/macros.h" #include "base/metrics/histogram_macros.h" #include "base/metrics/sparse_histogram.h" @@ -21,6 +20,7 @@ #include "chrome/browser/browser_process.h" #include "chrome/browser/browsing_data/autofill_counter.h" #include "chrome/browser/browsing_data/browsing_data_counter.h" +#include "chrome/browser/browsing_data/browsing_data_counter_utils.h" #include "chrome/browser/browsing_data/browsing_data_helper.h" #include "chrome/browser/browsing_data/browsing_data_remover.h" #include "chrome/browser/browsing_data/cache_counter.h" @@ -30,7 +30,6 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/browser/sync/profile_sync_service_factory.h" #include "chrome/browser/ui/accelerator_utils.h" -#include "chrome/common/chrome_switches.h" #include "chrome/common/pref_names.h" #include "chrome/grit/generated_resources.h" #include "chrome/grit/locale_settings.h" @@ -39,7 +38,6 @@ #include "content/public/browser/web_ui.h" #include "ui/base/accelerators/accelerator.h" #include "ui/base/l10n/l10n_util.h" -#include "ui/base/text/bytes_formatting.h" #include "ui/events/keycodes/keyboard_codes.h" namespace { @@ -47,32 +45,6 @@ const char kClearBrowsingDataLearnMoreUrl[] = "https://support.google.com/chrome/?p=settings_clear_browsing_data"; -bool AreCountersEnabled() { - if (base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kEnableClearBrowsingDataCounters)) { - return true; - } - - if (base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kDisableClearBrowsingDataCounters)) { - return false; - } - - // Enabled by default. - return true; -} - -// A helper function to display the size of cache in units of MB or higher. -// We need this, as 1 MB is the lowest nonzero cache size displayed by the -// counter. -base::string16 FormatBytesMBOrHigher(BrowsingDataCounter::ResultInt bytes) { - if (ui::GetByteDisplayUnits(bytes) >= ui::DataUnits::DATA_UNITS_MEBIBYTE) - return ui::FormatBytes(bytes); - - return ui::FormatBytesWithUnits( - bytes, ui::DataUnits::DATA_UNITS_MEBIBYTE, true); -} - } // namespace namespace options { @@ -151,128 +123,6 @@ base::StringValue(text)); } -// static -base::string16 ClearBrowserDataHandler::GetCounterTextFromResult( - const BrowsingDataCounter::Result* result) { - base::string16 text; - std::string pref_name = result->source()->GetPrefName(); - - if (!result->Finished()) { - // The counter is still counting. - text = l10n_util::GetStringUTF16(IDS_CLEAR_BROWSING_DATA_CALCULATING); - - } else if (pref_name == prefs::kDeletePasswords) { - // Passwords counter. - BrowsingDataCounter::ResultInt passwords_count = - static_cast<const BrowsingDataCounter::FinishedResult*>( - result)->Value(); - text = l10n_util::GetPluralStringFUTF16( - IDS_DEL_PASSWORDS_COUNTER, passwords_count); - - } else if (pref_name == prefs::kDeleteCache) { - // Cache counter. - BrowsingDataCounter::ResultInt cache_size_bytes = - static_cast<const BrowsingDataCounter::FinishedResult*>( - result)->Value(); - - PrefService* prefs = result->source()->GetProfile()->GetPrefs(); - BrowsingDataRemover::TimePeriod time_period = - static_cast<BrowsingDataRemover::TimePeriod>( - prefs->GetInteger(prefs::kDeleteTimePeriod)); - - // Three cases: Nonzero result for the entire cache, nonzero result for - // a subset of cache (i.e. a finite time interval), and almost zero (< 1MB). - static const int kBytesInAMegabyte = 1024 * 1024; - if (cache_size_bytes >= kBytesInAMegabyte) { - base::string16 formatted_size = FormatBytesMBOrHigher(cache_size_bytes); - text = time_period == BrowsingDataRemover::EVERYTHING - ? formatted_size - : l10n_util::GetStringFUTF16(IDS_DEL_CACHE_COUNTER_UPPER_ESTIMATE, - formatted_size); - } else { - text = l10n_util::GetStringUTF16(IDS_DEL_CACHE_COUNTER_ALMOST_EMPTY); - } - - } else if (pref_name == prefs::kDeleteBrowsingHistory) { - // History counter. - const HistoryCounter::HistoryResult* history_result = - static_cast<const HistoryCounter::HistoryResult*>(result); - BrowsingDataCounter::ResultInt local_item_count = history_result->Value(); - bool has_synced_visits = history_result->has_synced_visits(); - - text = has_synced_visits - ? l10n_util::GetPluralStringFUTF16( - IDS_DEL_BROWSING_HISTORY_COUNTER_SYNCED, local_item_count) - : l10n_util::GetPluralStringFUTF16( - IDS_DEL_BROWSING_HISTORY_COUNTER, local_item_count); - - } else if (pref_name == prefs::kDeleteFormData) { - // Autofill counter. - const AutofillCounter::AutofillResult* autofill_result = - static_cast<const AutofillCounter::AutofillResult*>(result); - AutofillCounter::ResultInt num_suggestions = autofill_result->Value(); - AutofillCounter::ResultInt num_credit_cards = - autofill_result->num_credit_cards(); - AutofillCounter::ResultInt num_addresses = autofill_result->num_addresses(); - - std::vector<base::string16> displayed_strings; - - if (num_credit_cards) { - displayed_strings.push_back(l10n_util::GetPluralStringFUTF16( - IDS_DEL_AUTOFILL_COUNTER_CREDIT_CARDS, num_credit_cards)); - } - if (num_addresses) { - displayed_strings.push_back(l10n_util::GetPluralStringFUTF16( - IDS_DEL_AUTOFILL_COUNTER_ADDRESSES, num_addresses)); - } - if (num_suggestions) { - // We use a different wording for autocomplete suggestions based on the - // length of the entire string. - switch (displayed_strings.size()) { - case 0: - displayed_strings.push_back(l10n_util::GetPluralStringFUTF16( - IDS_DEL_AUTOFILL_COUNTER_SUGGESTIONS, num_suggestions)); - break; - case 1: - displayed_strings.push_back(l10n_util::GetPluralStringFUTF16( - IDS_DEL_AUTOFILL_COUNTER_SUGGESTIONS_LONG, num_suggestions)); - break; - case 2: - displayed_strings.push_back(l10n_util::GetPluralStringFUTF16( - IDS_DEL_AUTOFILL_COUNTER_SUGGESTIONS_SHORT, num_suggestions)); - break; - default: - NOTREACHED(); - } - } - - // Construct the resulting string from the sections in |displayed_strings|. - switch (displayed_strings.size()) { - case 0: - text = l10n_util::GetStringUTF16(IDS_DEL_AUTOFILL_COUNTER_EMPTY); - break; - case 1: - text = displayed_strings[0]; - break; - case 2: - text = l10n_util::GetStringFUTF16(IDS_DEL_AUTOFILL_COUNTER_TWO_TYPES, - displayed_strings[0], - displayed_strings[1]); - break; - case 3: - text = l10n_util::GetStringFUTF16(IDS_DEL_AUTOFILL_COUNTER_THREE_TYPES, - displayed_strings[0], - displayed_strings[1], - displayed_strings[2]); - break; - default: - NOTREACHED(); - } - } - - return text; -} - void ClearBrowserDataHandler::OnPageOpened(const base::ListValue* value) { for (BrowsingDataCounter* counter : counters_) { DCHECK(AreCountersEnabled());
diff --git a/chrome/browser/ui/webui/options/clear_browser_data_handler.h b/chrome/browser/ui/webui/options/clear_browser_data_handler.h index 6a09ab6..8621543 100644 --- a/chrome/browser/ui/webui/options/clear_browser_data_handler.h +++ b/chrome/browser/ui/webui/options/clear_browser_data_handler.h
@@ -33,10 +33,6 @@ void UpdateInfoBannerVisibility(); - // Constructs the text to be displayed by a counter from the given |result|. - static base::string16 GetCounterTextFromResult( - const BrowsingDataCounter::Result* result); - private: // Javascript callback for when the CBD dialog is opened. The caller does // not provide any parameters, so |value| is unused.
diff --git a/chrome/browser/ui/webui/options/content_settings_exception_area_browsertest.js b/chrome/browser/ui/webui/options/content_settings_exception_area_browsertest.js index f9fc3df..4112ed6 100644 --- a/chrome/browser/ui/webui/options/content_settings_exception_area_browsertest.js +++ b/chrome/browser/ui/webui/options/content_settings_exception_area_browsertest.js
@@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +GEN_INCLUDE(['options_browsertest_base.js']); + /** * TestFixture for content settings exception area WebUI testing. * @extends {testing.Test} @@ -37,13 +39,30 @@ function ContentSettingsExceptionsAreaAsyncWebUITest() {} ContentSettingsExceptionsAreaAsyncWebUITest.prototype = { - __proto__: testing.Test.prototype, + __proto__: OptionsBrowsertestBase.prototype, /** @override */ browsePreload: 'chrome://settings-frame/contentExceptions', /** @override */ isAsync: true, + + /** @override */ + setUp: function() { + OptionsBrowsertestBase.prototype.setUp.call(this); + + // Enable when failure is resolved. + // AX_TEXT_01: http://crbug.com/570562 + this.accessibilityAuditConfig.ignoreSelectors( + 'controlsWithoutLabel', + '#content-settings-exceptions-area > .content-area > *'); + + // Enable when failure is resolved. + // AX_TEXT_04: http://crbug.com/570563 + this.accessibilityAuditConfig.ignoreSelectors( + 'linkWithUnclearPurpose', + '#content-settings-exceptions-area > .action-area > *'); + }, }; // Adds and removes a location content setting exception.
diff --git a/chrome/browser/ui/webui/options/content_settings_handler.cc b/chrome/browser/ui/webui/options/content_settings_handler.cc index 935897c..325974c8 100644 --- a/chrome/browser/ui/webui/options/content_settings_handler.cc +++ b/chrome/browser/ui/webui/options/content_settings_handler.cc
@@ -777,12 +777,6 @@ } else { if (ContainsKey(GetExceptionsInfoMap(), details.type())) UpdateExceptionsViewFromModel(details.type()); - for (const ChooserTypeNameEntry& chooser_type : kChooserTypeGroupNames) { - if (chooser_type.type == details.type()) { - UpdateChooserExceptionsViewFromModel(chooser_type); - break; - } - } } } @@ -1512,6 +1506,7 @@ ChooserContextBase* chooser_context = chooser_type->get_context(profile); chooser_context->RevokeObjectPermission(requesting_origin, embedding_origin, *object); + UpdateChooserExceptionsViewFromModel(*chooser_type); // TODO(reillyg): Create metrics for revocations. crbug.com/556845 }
diff --git a/chrome/browser/ui/webui/options/cookies_view_browsertest.js b/chrome/browser/ui/webui/options/cookies_view_browsertest.js index 7fea55b..c17894d 100644 --- a/chrome/browser/ui/webui/options/cookies_view_browsertest.js +++ b/chrome/browser/ui/webui/options/cookies_view_browsertest.js
@@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +GEN_INCLUDE(['options_browsertest_base.js']); + /** * TestFixture for cookies view WebUI testing. * @extends {testing.Test} @@ -10,12 +12,23 @@ function CookiesViewWebUITest() {} CookiesViewWebUITest.prototype = { - __proto__: testing.Test.prototype, + __proto__: OptionsBrowsertestBase.prototype, /** * Browse to the cookies view. */ browsePreload: 'chrome://settings-frame/cookies', + + /** @override */ + setUp: function() { + OptionsBrowsertestBase.prototype.setUp.call(this); + + // Enable when failure is resolved. + // AX_TEXT_01: http://crbug.com/570560 + this.accessibilityAuditConfig.ignoreSelectors( + 'controlsWithoutLabel', + '#cookies-view-page > .content-area.cookies-list-content-area > *'); + }, }; // Test opening the cookies view has correct location.
diff --git a/chrome/browser/ui/webui/options/edit_dictionary_browsertest.js b/chrome/browser/ui/webui/options/edit_dictionary_browsertest.js index 1705505..272cf16 100644 --- a/chrome/browser/ui/webui/options/edit_dictionary_browsertest.js +++ b/chrome/browser/ui/webui/options/edit_dictionary_browsertest.js
@@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +GEN_INCLUDE(['options_browsertest_base.js']); + /** * TestFixture for EditDictionaryOverlay WebUI testing. * @extends {testing.Test} @@ -10,7 +12,7 @@ function EditDictionaryWebUITest() {} EditDictionaryWebUITest.prototype = { - __proto__: testing.Test.prototype, + __proto__: OptionsBrowsertestBase.prototype, /** * Browse to the edit dictionary page & call our preLoad(). @@ -33,6 +35,28 @@ this.mockHandler.stubs().addDictionaryWord(ANYTHING); this.mockHandler.stubs().removeDictionaryWord(ANYTHING); }, + + /** @override */ + setUp: function() { + OptionsBrowsertestBase.prototype.setUp.call(this); + + // Enable when failure is resolved. + // AX_TEXT_01: http://crbug.com/570556 + this.accessibilityAuditConfig.ignoreSelectors( + 'controlsWithoutLabel', + '#language-dictionary-overlay-word-list > .deletable-item > *'); + + var unsupportedAriaAttributeSelectors = [ + '#language-dictionary-overlay-word-list', + '#language-options-list', + ]; + + // Enable when failure is resolved. + // AX_ARIA_10: http://crbug.com/570559 + this.accessibilityAuditConfig.ignoreSelectors( + 'unsupportedAriaAttribute', + unsupportedAriaAttributeSelectors); + }, }; // Verify that users can add and remove words in the dictionary.
diff --git a/chrome/browser/ui/webui/options/font_settings_browsertest.js b/chrome/browser/ui/webui/options/font_settings_browsertest.js index d59db3d..6e419a2 100644 --- a/chrome/browser/ui/webui/options/font_settings_browsertest.js +++ b/chrome/browser/ui/webui/options/font_settings_browsertest.js
@@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +GEN_INCLUDE(['options_browsertest_base.js']); + /** * TestFixture for font settings WebUI testing. * @extends {testing.Test} @@ -10,7 +12,7 @@ function FontSettingsWebUITest() {} FontSettingsWebUITest.prototype = { - __proto__: testing.Test.prototype, + __proto__: OptionsBrowsertestBase.prototype, /** * Browse to the font settings page. @@ -20,7 +22,23 @@ /** @override */ preLoad: function() { this.makeAndRegisterMockHandler(['openAdvancedFontSettingsOptions']); - } + }, + + /** @override */ + setUp: function() { + OptionsBrowsertestBase.prototype.setUp.call(this); + + var controlsWithoutLabelSelectors = [ + '#standard-font-size', + '#minimum-font-size', + ]; + + // Enable when failure is resolved. + // AX_TEXT_01: http://crbug.com/570555 + this.accessibilityAuditConfig.ignoreSelectors( + 'controlsWithoutLabel', + controlsWithoutLabelSelectors); + }, }; // Test opening font settings has correct location.
diff --git a/chrome/browser/ui/webui/options/language_options_browsertest.js b/chrome/browser/ui/webui/options/language_options_browsertest.js index fc5ffba..bfd3acb6 100644 --- a/chrome/browser/ui/webui/options/language_options_browsertest.js +++ b/chrome/browser/ui/webui/options/language_options_browsertest.js
@@ -16,6 +16,23 @@ /** @override */ browsePreload: 'chrome://settings-frame/languages', + + /** @override */ + setUp: function() { + OptionsBrowsertestBase.prototype.setUp.call(this); + + // Enable when failure is resolved. + // AX_ARIA_10: http://crbug.com/559266 + this.accessibilityAuditConfig.ignoreSelectors( + 'unsupportedAriaAttribute', + '#language-options-list'); + + // Enable when failure is resolved. + // AX_TEXT_04: http://crbug.com/559271 + this.accessibilityAuditConfig.ignoreSelectors( + 'linkWithUnclearPurpose', + '#languagePage > .content-area > .language-options-header > A'); + } }; // Test opening language options has correct location.
diff --git a/chrome/browser/ui/webui/options/language_options_dictionary_download_browsertest.js b/chrome/browser/ui/webui/options/language_options_dictionary_download_browsertest.js index 5a134ec..bab5224 100644 --- a/chrome/browser/ui/webui/options/language_options_dictionary_download_browsertest.js +++ b/chrome/browser/ui/webui/options/language_options_dictionary_download_browsertest.js
@@ -4,6 +4,7 @@ GEN('#include "chrome/browser/ui/webui/options/' + 'single_language_options_browsertest.h"'); +GEN_INCLUDE(['options_browsertest_base.js']); /** * TestFixture for testing messages of dictionary download progress in language @@ -14,7 +15,7 @@ function LanguagesOptionsDictionaryDownloadWebUITest() {} LanguagesOptionsDictionaryDownloadWebUITest.prototype = { - __proto__: testing.Test.prototype, + __proto__: OptionsBrowsertestBase.prototype, /** * Browse to languages options. @@ -34,6 +35,23 @@ options.LanguageOptions.onDictionaryDownloadBegin('en-US'); })); }, + + /** @override */ + setUp: function() { + OptionsBrowsertestBase.prototype.setUp.call(this); + + // Enable when failure is resolved. + // AX_ARIA_10: http://crbug.com/570554 + this.accessibilityAuditConfig.ignoreSelectors( + 'unsupportedAriaAttribute', + '#language-options-list'); + + // Enable when failure is resolved. + // AX_TEXT_04: http://crbug.com/570553 + this.accessibilityAuditConfig.ignoreSelectors( + 'linkWithUnclearPurpose', + '#languagePage > .content-area > .language-options-header > A'); + }, }; // Verify that dictionary download success shows 'This language is used for
diff --git a/chrome/browser/ui/webui/options/multilanguage_options_webui_browsertest.js b/chrome/browser/ui/webui/options/multilanguage_options_webui_browsertest.js index 56419fa4..c691a6f 100644 --- a/chrome/browser/ui/webui/options/multilanguage_options_webui_browsertest.js +++ b/chrome/browser/ui/webui/options/multilanguage_options_webui_browsertest.js
@@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +GEN_INCLUDE(['options_browsertest_base.js']); GEN('#include "chrome/browser/ui/webui/options/' + 'multilanguage_options_browsertest.h"'); @@ -13,7 +14,7 @@ function MultilanguageOptionsWebUIBrowserTest() {} MultilanguageOptionsWebUIBrowserTest.prototype = { - __proto__: testing.Test.prototype, + __proto__: OptionsBrowsertestBase.prototype, /** @override */ browsePreload: 'chrome://settings-frame/languages', @@ -32,7 +33,7 @@ /** @override */ setUp: function() { - testing.Test.prototype.setUp.call(this); + OptionsBrowsertestBase.prototype.setUp.call(this); assertTrue(loadTimeData.getBoolean('enableMultilingualSpellChecker')); assertFalse(cr.isMac); @@ -40,6 +41,29 @@ expectFalse($('edit-custom-dictionary-button').hidden); this.expectEnableSpellcheckCheckboxHidden(); this.expectCurrentlySelected('fr'); + + var requiredOwnedAriaRoleMissingSelectors = [ + '#default-search-engine-list', + '#other-search-engine-list', + ]; + + // Enable when failure is resolved. + // AX_ARIA_08: http://crbug.com/559320 + this.accessibilityAuditConfig.ignoreSelectors( + 'requiredOwnedAriaRoleMissing', + requiredOwnedAriaRoleMissingSelectors); + + // Enable when failure is resolved. + // AX_ARIA_10: http://crbug.com/559266 + this.accessibilityAuditConfig.ignoreSelectors( + 'unsupportedAriaAttribute', + '#language-options-list'); + + // Enable when failure is resolved. + // AX_TEXT_04: http://crbug.com/559271 + this.accessibilityAuditConfig.ignoreSelectors( + 'linkWithUnclearPurpose', + '#languagePage > .content-area > .language-options-header > A'); }, /** @override */ @@ -140,7 +164,7 @@ /** @override */ setUp: function() { - testing.Test.prototype.setUp.call(this); + OptionsBrowsertestBase.prototype.setUp.call(this); assertTrue(loadTimeData.getBoolean('enableMultilingualSpellChecker')); assertFalse(cr.isMac); @@ -149,6 +173,24 @@ this.expectEnableSpellcheckCheckboxHidden(); this.expectCurrentlySelected(''); this.expectRegisteredDictionariesPref(''); + + // Enable when failure is resolved. + // AX_ARIA_10: http://crbug.com/559266 + this.accessibilityAuditConfig.ignoreSelectors( + 'unsupportedAriaAttribute', + '#language-options-list'); + + // Enable when failure is resolved. + // AX_TEXT_04: http://crbug.com/559271 + this.accessibilityAuditConfig.ignoreSelectors( + 'linkWithUnclearPurpose', + '#languagePage > .content-area > .language-options-header > A'); + + // Enable when failure is resolved. + // AX_FOCUS_01: http://crbug.com/570046 + this.accessibilityAuditConfig.ignoreSelectors( + 'focusableElementNotVisibleAndNotAriaHidden', + '#offer-to-translate-in-this-language'); }, };
diff --git a/chrome/browser/ui/webui/options/options_browsertest.js b/chrome/browser/ui/webui/options/options_browsertest.js index 895928a..4de8c19 100644 --- a/chrome/browser/ui/webui/options/options_browsertest.js +++ b/chrome/browser/ui/webui/options/options_browsertest.js
@@ -79,6 +79,31 @@ this.mockHandler.stubs().observePrefs(ANYTHING); this.mockHandler.stubs().coreOptionsUserMetricsAction(ANYTHING); }, + + /** @override */ + setUp: function() { + OptionsBrowsertestBase.prototype.setUp.call(this); + + // Enable when failure is resolved. + // AX_ARIA_10: http://crbug.com/559329 + this.accessibilityAuditConfig.ignoreSelectors( + 'unsupportedAriaAttribute', + '#profiles-list'); + + var linkWithUnclearPurposeSelectors = [ + '#sync-overview > A', + '#privacy-explanation > A', + '#languages-section > .settings-row > A', + '#cloudprint-options-mdns > .settings-row > A', + '#do-not-track-confirm-overlay > .action-area > .hbox.stretch > A', + ]; + + // Enable when failure is resolved. + // AX_TEXT_04: http://crbug.com/559318 + this.accessibilityAuditConfig.ignoreSelectors( + 'linkWithUnclearPurpose', + linkWithUnclearPurposeSelectors); + }, }; /** @@ -378,6 +403,44 @@ /** @override */ typedefCppFixture: 'OptionsBrowserTest', + /** @override */ + setUp: function() { + OptionsWebUITest.prototype.setUp.call(this); + + // Enable when failure is resolved. + // AX_ARIA_10: http://crbug.com/559329 + this.accessibilityAuditConfig.ignoreSelectors( + 'unsupportedAriaAttribute', + '#profiles-list'); + + var controlsWithoutLabelSelectors = [ + '#cookies-view-page > .content-area.cookies-list-content-area > *', + '#other-search-engine-list > .deletable-item > DIV > *', + ]; + + // Enable when failure is resolved. + // AX_TEXT_01: http://crbug.com/559330 + this.accessibilityAuditConfig.ignoreSelectors( + 'controlsWithoutLabel', + controlsWithoutLabelSelectors); + + var linkWithUnclearPurposeSelectors = [ + '#sync-overview > A', + '#privacy-explanation > A', + '#languages-section > .settings-row > A', + '#cloudprint-options-mdns > .settings-row > A', + // Selectors below only affect ChromeOS tests. + '#privacy-section > DIV > DIV:nth-of-type(9) > A', + '#accessibility-learn-more', + ]; + + // Enable when failure is resolved. + // AX_TEXT_04: http://crbug.com/559326 + this.accessibilityAuditConfig.ignoreSelectors( + 'linkWithUnclearPurpose', + linkWithUnclearPurposeSelectors); + }, + testGenPreamble: function() { // Start with no supervised users managed by this profile. GEN(' ClearPref("' + SUPERVISED_USERS_PREF + '");');
diff --git a/chrome/browser/ui/webui/options/options_browsertest_base.js b/chrome/browser/ui/webui/options/options_browsertest_base.js index 1483ba32..bca7c49 100644 --- a/chrome/browser/ui/webui/options/options_browsertest_base.js +++ b/chrome/browser/ui/webui/options/options_browsertest_base.js
@@ -16,4 +16,60 @@ /** @override */ accessibilityIssuesAreErrors: true, + + /** @override */ + setUp: function() { + testing.Test.prototype.setUp.call(this); + + var requiredOwnedAriaRoleMissingSelectors = [ + '#address-list', + '#creditcard-list', + '#home-page-overlay > .autocomplete-suggestions', + '#language-options-list', + '#manage-profile-icon-grid', + '#create-profile-icon-grid', + '#saved-passwords-list', + '#password-exceptions-list', + '#extension-keyword-list', + '#startup-overlay > .autocomplete-suggestions', + '#content-settings-exceptions-area > .content-area > *', + '#cookies-list', + '#handlers-list', + '#ignored-handlers-list', + '#supervised-user-list', + '#select-avatar-grid', + '#language-dictionary-overlay-word-list', + // Selectors below only affect ChromeOS tests. + '#bluetooth-unpaired-devices-list', + '#ignored-host-list', + '#remembered-network-list', + '#bluetooth-paired-devices-list', + ]; + + // Enable when failure is resolved. + // AX_ARIA_08: http://crbug.com/559265 + this.accessibilityAuditConfig.ignoreSelectors( + 'requiredOwnedAriaRoleMissing', + requiredOwnedAriaRoleMissingSelectors); + + var tabIndexGreaterThanZeroSelectors = [ + '#user-image-grid', + '#discard-photo', + '#take-photo', + '#flip-photo', + '#change-picture-overlay-confirm', + ]; + + // Enable when failure is resolved. + // AX_FOCUS_03: http://crbug.com/560910 + this.accessibilityAuditConfig.ignoreSelectors( + 'tabIndexGreaterThanZero', + tabIndexGreaterThanZeroSelectors); + + // Enable when audit has improved performance. + // AX_HTML_02: + // https://github.com/GoogleChrome/accessibility-developer-tools/issues/263 + this.accessibilityAuditConfig.auditRulesToIgnore.push( + 'duplicateId'); + }, };
diff --git a/chrome/browser/ui/webui/options/profile_settings_reset_browsertest.js b/chrome/browser/ui/webui/options/profile_settings_reset_browsertest.js index ac4d7fa..2bd7a05 100644 --- a/chrome/browser/ui/webui/options/profile_settings_reset_browsertest.js +++ b/chrome/browser/ui/webui/options/profile_settings_reset_browsertest.js
@@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +GEN_INCLUDE(['options_browsertest_base.js']); + /** * TestFixture for profile settings reset WebUI testing. * @extends {testing.Test} @@ -10,12 +12,23 @@ function ProfileSettingsResetWebUITest() {} ProfileSettingsResetWebUITest.prototype = { - __proto__: testing.Test.prototype, + __proto__: OptionsBrowsertestBase.prototype, /** * Browse to the reset profile settings page. */ browsePreload: 'chrome://settings-frame/resetProfileSettings', + + /** @override */ + setUp: function() { + OptionsBrowsertestBase.prototype.setUp.call(this); + + // Enable when failure is resolved. + // AX_TEXT_04: http://crbug.com/570551 + this.accessibilityAuditConfig.ignoreSelectors( + 'linkWithUnclearPurpose', + '#reset-profile-settings-overlay > .action-area > .hbox.stretch > A'); + }, }; // Test opening the profile settings reset has correct location.
diff --git a/chrome/browser/ui/webui/options/settings_format_browsertest.js b/chrome/browser/ui/webui/options/settings_format_browsertest.js index f2f2fa6..27561f88 100644 --- a/chrome/browser/ui/webui/options/settings_format_browsertest.js +++ b/chrome/browser/ui/webui/options/settings_format_browsertest.js
@@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +GEN_INCLUDE(['options_browsertest_base.js']); + /** * TestFixture for testing the formatting of settings pages. * @extends {testing.Test} @@ -34,7 +36,7 @@ }; SettingsFormatWebUITest.prototype = { - __proto__: testing.Test.prototype, + __proto__: OptionsBrowsertestBase.prototype, /** * Navigate to browser settings. @@ -50,8 +52,23 @@ */ errors: null, + /** @override */ setUp: function() { + OptionsBrowsertestBase.prototype.setUp.call(this); + this.errors = []; + + // Enable when failure is resolved. + // AX_TEXT_04: http://crbug.com/570727 + this.accessibilityAuditConfig.ignoreSelectors( + 'linkWithUnclearPurpose', + '#sync-overview > A'); + + // Enable when failure is resolved. + // AX_ARIA_10: http://crbug.com/570725 + this.accessibilityAuditConfig.ignoreSelectors( + 'unsupportedAriaAttribute', + '#profiles-list'); }, tearDown: function() {
diff --git a/chrome/browser/ui/webui/plugins/plugins_handler.cc b/chrome/browser/ui/webui/plugins/plugins_handler.cc new file mode 100644 index 0000000..29ae46e --- /dev/null +++ b/chrome/browser/ui/webui/plugins/plugins_handler.cc
@@ -0,0 +1,374 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/webui/plugins/plugins_handler.h" + +#include <vector> + +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/files/file_path.h" +#include "base/memory/scoped_ptr.h" +#include "base/path_service.h" +#include "base/prefs/pref_service.h" +#include "base/prefs/scoped_user_pref_update.h" +#include "base/strings/utf_string_conversions.h" +#include "chrome/browser/chrome_notification_types.h" +#include "chrome/browser/content_settings/host_content_settings_map_factory.h" +#include "chrome/browser/plugins/plugin_finder.h" +#include "chrome/browser/plugins/plugin_metadata.h" +#include "chrome/browser/plugins/plugin_prefs.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/common/chrome_content_client.h" +#include "chrome/common/chrome_paths.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 "content/public/browser/notification_observer.h" +#include "content/public/browser/plugin_service.h" +#include "content/public/browser/web_ui.h" +#include "content/public/common/content_constants.h" +#include "ui/base/l10n/l10n_util.h" + +using content::WebPluginInfo; +// Holds grouped plugins. The key is the group identifier and +// the value is the list of plugins belonging to the group. +using PluginGroups = base::hash_map<std::string, + std::vector<const content::WebPluginInfo*>>; + +namespace { + +// Callback function to process result of EnablePlugin method. +void AssertPluginEnabled(bool did_enable) { + DCHECK(did_enable); +} + +base::string16 PluginTypeToString(int type) { + // The type is stored as an |int|, but doing the switch on the right + // enumeration type gives us better build-time error checking (if someone adds + // a new type). + switch (static_cast<WebPluginInfo::PluginType>(type)) { + case WebPluginInfo::PLUGIN_TYPE_NPAPI: + return l10n_util::GetStringUTF16(IDS_PLUGINS_NPAPI); + case WebPluginInfo::PLUGIN_TYPE_PEPPER_IN_PROCESS: + return l10n_util::GetStringUTF16(IDS_PLUGINS_PPAPI_IN_PROCESS); + case WebPluginInfo::PLUGIN_TYPE_PEPPER_OUT_OF_PROCESS: + return l10n_util::GetStringUTF16(IDS_PLUGINS_PPAPI_OUT_OF_PROCESS); + case WebPluginInfo::PLUGIN_TYPE_BROWSER_PLUGIN: + return l10n_util::GetStringUTF16(IDS_PLUGINS_BROWSER_PLUGIN); + } + NOTREACHED(); + return base::string16(); +} + +base::string16 GetPluginDescription(const WebPluginInfo& plugin) { + // If this plugin is Pepper Flash, and the plugin path is the same as the + // path for the Pepper Flash System plugin, then mark this plugin + // description as the system plugin to help the user disambiguate the + // two plugins. + base::string16 desc = plugin.desc; + if (plugin.is_pepper_plugin() && + plugin.name == base::ASCIIToUTF16(content::kFlashPluginName)) { + base::FilePath system_flash_path; + PathService::Get(chrome::FILE_PEPPER_FLASH_SYSTEM_PLUGIN, + &system_flash_path); + if (base::FilePath::CompareEqualIgnoreCase(plugin.path.value(), + system_flash_path.value())) { +#if defined(GOOGLE_CHROME_BUILD) + // Existing documentation for debugging Flash describe this plugin as + // "Debug" so preserve this nomenclature here. + desc += base::ASCIIToUTF16(" Debug"); +#else + // On Chromium, we can name it what it really is; the system plugin. + desc += base::ASCIIToUTF16(" System"); +#endif + } + } + return desc; +} + +scoped_ptr<base::ListValue> GetPluginMimeTypes(const WebPluginInfo& plugin) { + scoped_ptr<base::ListValue> mime_types(new base::ListValue()); + for (const auto& plugin_mime_type: plugin.mime_types) { + base::DictionaryValue* mime_type = new base::DictionaryValue(); + mime_type->SetString("mimeType", plugin_mime_type.mime_type); + mime_type->SetString("description", plugin_mime_type.description); + + base::ListValue* file_extensions = new base::ListValue(); + for (const auto& mime_file_extension : plugin_mime_type.file_extensions) { + file_extensions->Append(new base::StringValue(mime_file_extension)); + } + mime_type->Set("fileExtensions", file_extensions); + mime_types->Append(mime_type); + } + return mime_types; +} + +} // namespace + + +PluginsHandler::PluginsHandler() : weak_ptr_factory_(this) { +} + +PluginsHandler::~PluginsHandler() { +} + +void PluginsHandler::RegisterMessages() { + Profile* profile = Profile::FromWebUI(web_ui()); + + PrefService* prefs = profile->GetPrefs(); + show_details_.Init(prefs::kPluginsShowDetails, prefs); + + registrar_.Add(this, + chrome::NOTIFICATION_PLUGIN_ENABLE_STATUS_CHANGED, + content::Source<Profile>(profile)); + + web_ui()->RegisterMessageCallback("requestPluginsData", + base::Bind(&PluginsHandler::HandleRequestPluginsData, + base::Unretained(this))); + web_ui()->RegisterMessageCallback("enablePlugin", + base::Bind(&PluginsHandler::HandleEnablePluginMessage, + base::Unretained(this))); + web_ui()->RegisterMessageCallback("setPluginAlwaysAllowed", + base::Bind(&PluginsHandler::HandleSetPluginAlwaysAllowed, + base::Unretained(this))); + web_ui()->RegisterMessageCallback("saveShowDetailsToPrefs", + base::Bind(&PluginsHandler::HandleSaveShowDetailsToPrefs, + base::Unretained(this))); + web_ui()->RegisterMessageCallback("getShowDetails", + base::Bind(&PluginsHandler::HandleGetShowDetails, + base::Unretained(this))); +} + +void PluginsHandler::HandleRequestPluginsData(const base::ListValue* args) { + LoadPlugins(); +} + +void PluginsHandler::HandleEnablePluginMessage(const base::ListValue* args) { + Profile* profile = Profile::FromWebUI(web_ui()); + + // Be robust in accepting badness since plugins display HTML (hence + // JavaScript). + if (args->GetSize() != 3) { + NOTREACHED(); + return; + } + + std::string enable_str; + std::string is_group_str; + if (!args->GetString(1, &enable_str) || !args->GetString(2, &is_group_str)) { + NOTREACHED(); + return; + } + bool enable = enable_str == "true"; + + PluginPrefs* plugin_prefs = PluginPrefs::GetForProfile(profile).get(); + if (is_group_str == "true") { + base::string16 group_name; + if (!args->GetString(0, &group_name)) { + NOTREACHED(); + return; + } + + plugin_prefs->EnablePluginGroup(enable, group_name); + if (enable) { + // See http://crbug.com/50105 for background. + base::string16 adobereader = base::ASCIIToUTF16( + PluginMetadata::kAdobeReaderGroupName); + base::string16 internalpdf = + base::ASCIIToUTF16(ChromeContentClient::kPDFPluginName); + if (group_name == adobereader) + plugin_prefs->EnablePluginGroup(false, internalpdf); + else if (group_name == internalpdf) + plugin_prefs->EnablePluginGroup(false, adobereader); + } + } else { + base::FilePath::StringType file_path; + if (!args->GetString(0, &file_path)) { + NOTREACHED(); + return; + } + + plugin_prefs->EnablePlugin(enable, base::FilePath(file_path), + base::Bind(&AssertPluginEnabled)); + } +} + +void PluginsHandler::HandleSaveShowDetailsToPrefs( + const base::ListValue* args) { + std::string details_mode; + if (!args->GetString(0, &details_mode)) { + NOTREACHED(); + return; + } + show_details_.SetValue(details_mode == "true"); +} + +void PluginsHandler::HandleGetShowDetails(const base::ListValue* args) { + base::FundamentalValue show_details(show_details_.GetValue()); + web_ui()->CallJavascriptFunction("loadShowDetailsFromPrefs", show_details); +} + +void PluginsHandler::HandleSetPluginAlwaysAllowed( + const base::ListValue* args) { + // Be robust in the input parameters, but crash in a Debug build. + if (args->GetSize() != 2) { + NOTREACHED(); + return; + } + + std::string plugin; + bool allowed = false; + if (!args->GetString(0, &plugin) || !args->GetBoolean(1, &allowed)) { + NOTREACHED(); + return; + } + Profile* profile = Profile::FromWebUI(web_ui()); + HostContentSettingsMapFactory::GetForProfile(profile)->SetContentSetting( + ContentSettingsPattern::Wildcard(), + ContentSettingsPattern::Wildcard(), + CONTENT_SETTINGS_TYPE_PLUGINS, + plugin, + allowed ? CONTENT_SETTING_ALLOW : CONTENT_SETTING_DEFAULT); + + // Keep track of the whitelist separately, so that we can distinguish plugins + // whitelisted by the user from automatically whitelisted ones. + DictionaryPrefUpdate update(profile->GetPrefs(), + prefs::kContentSettingsPluginWhitelist); + update->SetBoolean(plugin, allowed); +} + +void PluginsHandler::Observe(int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) { + DCHECK_EQ(chrome::NOTIFICATION_PLUGIN_ENABLE_STATUS_CHANGED, type); + LoadPlugins(); +} + +void PluginsHandler::LoadPlugins() { + if (weak_ptr_factory_.HasWeakPtrs()) + return; + + content::PluginService::GetInstance()->GetPlugins( + base::Bind(&PluginsHandler::PluginsLoaded, + weak_ptr_factory_.GetWeakPtr())); +} + +void PluginsHandler::PluginsLoaded( + const std::vector<WebPluginInfo>& plugins) { + Profile* profile = Profile::FromWebUI(web_ui()); + PluginPrefs* plugin_prefs = PluginPrefs::GetForProfile(profile).get(); + + ContentSettingsPattern wildcard = ContentSettingsPattern::Wildcard(); + + PluginFinder* plugin_finder = PluginFinder::GetInstance(); + // Group plugins by identifier. This is done to be able to display + // the plugins in UI in a grouped fashion. + PluginGroups groups; + for (size_t i = 0; i < plugins.size(); ++i) { + scoped_ptr<PluginMetadata> plugin( + plugin_finder->GetPluginMetadata(plugins[i])); + groups[plugin->identifier()].push_back(&plugins[i]); + } + + // Construct DictionaryValues to return to UI. + base::ListValue* plugin_groups_data = new base::ListValue(); + for (PluginGroups::const_iterator it = groups.begin(); + it != groups.end(); ++it) { + const std::vector<const WebPluginInfo*>& group_plugins = it->second; + base::ListValue* plugin_files = new base::ListValue(); + scoped_ptr<PluginMetadata> plugin_metadata( + plugin_finder->GetPluginMetadata(*group_plugins[0])); + base::string16 group_name = plugin_metadata->name(); + std::string group_identifier = plugin_metadata->identifier(); + bool group_enabled = false; + bool all_plugins_enabled_by_policy = true; + bool all_plugins_disabled_by_policy = true; + bool all_plugins_managed_by_policy = true; + const WebPluginInfo* active_plugin = NULL; + for (size_t j = 0; j < group_plugins.size(); ++j) { + const WebPluginInfo& group_plugin = *group_plugins[j]; + + base::DictionaryValue* plugin_file = new base::DictionaryValue(); + plugin_file->SetString("name", group_plugin.name); + plugin_file->SetString("description", GetPluginDescription(group_plugin)); + plugin_file->SetString("path", group_plugin.path.value()); + plugin_file->SetString("version", group_plugin.version); + plugin_file->SetString("type", PluginTypeToString(group_plugin.type)); + plugin_file->Set("mimeTypes", GetPluginMimeTypes(group_plugin)); + + bool plugin_enabled = plugin_prefs->IsPluginEnabled(group_plugin); + + if (!active_plugin || (plugin_enabled && !group_enabled)) + active_plugin = &group_plugin; + group_enabled = plugin_enabled || group_enabled; + + std::string enabled_mode; + PluginPrefs::PolicyStatus plugin_status = + plugin_prefs->PolicyStatusForPlugin(group_plugin.name); + PluginPrefs::PolicyStatus group_status = + plugin_prefs->PolicyStatusForPlugin(group_name); + if (plugin_status == PluginPrefs::POLICY_ENABLED || + group_status == PluginPrefs::POLICY_ENABLED) { + enabled_mode = "enabledByPolicy"; + all_plugins_disabled_by_policy = false; + } else { + all_plugins_enabled_by_policy = false; + if (plugin_status == PluginPrefs::POLICY_DISABLED || + group_status == PluginPrefs::POLICY_DISABLED) { + enabled_mode = "disabledByPolicy"; + } else { + all_plugins_disabled_by_policy = false; + all_plugins_managed_by_policy = false; + enabled_mode = plugin_enabled ? "enabledByUser" : "disabledByUser"; + } + } + plugin_file->SetString("enabledMode", enabled_mode); + + plugin_files->Append(plugin_file); + } + base::DictionaryValue* group_data = new base::DictionaryValue(); + + group_data->Set("plugin_files", plugin_files); + group_data->SetString("name", group_name); + group_data->SetString("id", group_identifier); + group_data->SetString("description", active_plugin->desc); + group_data->SetString("version", active_plugin->version); + +#if defined(ENABLE_PLUGIN_INSTALLATION) + bool out_of_date = plugin_metadata->GetSecurityStatus(*active_plugin) == + PluginMetadata::SECURITY_STATUS_OUT_OF_DATE; + group_data->SetBoolean("critical", out_of_date); + group_data->SetString("update_url", plugin_metadata->plugin_url().spec()); +#endif + + std::string enabled_mode; + if (all_plugins_enabled_by_policy) { + enabled_mode = "enabledByPolicy"; + } else if (all_plugins_disabled_by_policy) { + enabled_mode = "disabledByPolicy"; + } else if (all_plugins_managed_by_policy) { + enabled_mode = "managedByPolicy"; + } else if (group_enabled) { + enabled_mode = "enabledByUser"; + } else { + enabled_mode = "disabledByUser"; + } + group_data->SetString("enabledMode", enabled_mode); + + bool always_allowed = false; + if (group_enabled) { + const base::DictionaryValue* whitelist = + profile->GetPrefs()->GetDictionary( + prefs::kContentSettingsPluginWhitelist); + whitelist->GetBoolean(group_identifier, &always_allowed); + } + group_data->SetBoolean("alwaysAllowed", always_allowed); + + plugin_groups_data->Append(group_data); + } + base::DictionaryValue results; + results.Set("plugins", plugin_groups_data); + web_ui()->CallJavascriptFunction("returnPluginsData", results); +}
diff --git a/chrome/browser/ui/webui/plugins/plugins_handler.h b/chrome/browser/ui/webui/plugins/plugins_handler.h new file mode 100644 index 0000000..f9d109b --- /dev/null +++ b/chrome/browser/ui/webui/plugins/plugins_handler.h
@@ -0,0 +1,63 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_WEBUI_PLUGINS_PLUGINS_HANDLER_H_ +#define CHROME_BROWSER_UI_WEBUI_PLUGINS_PLUGINS_HANDLER_H_ + +#include "base/memory/weak_ptr.h" +#include "base/prefs/pref_member.h" +#include "base/values.h" +#include "content/public/browser/notification_observer.h" +#include "content/public/browser/notification_registrar.h" +#include "content/public/browser/notification_source.h" +#include "content/public/browser/web_ui_message_handler.h" +#include "content/public/common/webplugininfo.h" + +class PluginsHandler : public content::WebUIMessageHandler, + public content::NotificationObserver { + public: + PluginsHandler(); + ~PluginsHandler() override; + + // content::WebUIMessageHandler implementation. + void RegisterMessages() override; + + // content::NotificationObserver implementation. + void Observe(int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) override; + + private: + // Callback for the "requestPluginsData" message. + void HandleRequestPluginsData(const base::ListValue* args); + + // Callback for the "enablePlugin" message. + void HandleEnablePluginMessage(const base::ListValue* args); + + // Callback for the "saveShowDetailsToPrefs" message. + void HandleSaveShowDetailsToPrefs(const base::ListValue* args); + + // Calback for the "getShowDetails" message. + void HandleGetShowDetails(const base::ListValue* args); + + // Callback for the "setPluginAlwaysAllowed" message. + void HandleSetPluginAlwaysAllowed(const base::ListValue* args); + + void LoadPlugins(); + + // Called on the UI thread when the plugin information is ready. + void PluginsLoaded(const std::vector<content::WebPluginInfo>& plugins); + + content::NotificationRegistrar registrar_; + + // This pref guards the value whether about:plugins is in the details mode or + // not. + BooleanPrefMember show_details_; + + base::WeakPtrFactory<PluginsHandler> weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(PluginsHandler); +}; + +#endif // CHROME_BROWSER_UI_WEBUI_PLUGINS_PLUGINS_HANDLER_H_
diff --git a/chrome/browser/ui/webui/plugins/plugins_ui.cc b/chrome/browser/ui/webui/plugins/plugins_ui.cc new file mode 100644 index 0000000..7e1326d --- /dev/null +++ b/chrome/browser/ui/webui/plugins/plugins_ui.cc
@@ -0,0 +1,100 @@ +// 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/plugins/plugins_ui.h" + +#include <stddef.h> + +#include <algorithm> + +#include "base/macros.h" +#include "base/memory/ref_counted_memory.h" +#include "build/build_config.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/webui/plugins/plugins_handler.h" +#include "chrome/common/pref_names.h" +#include "chrome/common/url_constants.h" +#include "chrome/grit/browser_resources.h" +#include "chrome/grit/generated_resources.h" +#include "chrome/grit/theme_resources.h" +#include "components/pref_registry/pref_registry_syncable.h" +#include "content/public/browser/web_ui.h" +#include "content/public/browser/web_ui_data_source.h" +#include "ui/base/resource/resource_bundle.h" + +#if defined(OS_CHROMEOS) +#include "chrome/browser/ui/webui/chromeos/ui_account_tweaks.h" +#endif + +namespace { + +content::WebUIDataSource* CreatePluginsUIHTMLSource(Profile* profile) { + content::WebUIDataSource* source = + content::WebUIDataSource::Create(chrome::kChromeUIPluginsHost); + + source->AddLocalizedString("pluginsTitle", IDS_PLUGINS_TITLE); + source->AddLocalizedString("pluginsDetailsModeLink", + IDS_PLUGINS_DETAILS_MODE_LINK); + source->AddLocalizedString("pluginsNoneInstalled", + IDS_PLUGINS_NONE_INSTALLED); + source->AddLocalizedString("pluginDisabled", IDS_PLUGINS_DISABLED_PLUGIN); + source->AddLocalizedString("pluginDisabledByPolicy", + IDS_PLUGINS_DISABLED_BY_POLICY_PLUGIN); + source->AddLocalizedString("pluginEnabledByPolicy", + IDS_PLUGINS_ENABLED_BY_POLICY_PLUGIN); + source->AddLocalizedString("pluginGroupManagedByPolicy", + IDS_PLUGINS_GROUP_MANAGED_BY_POLICY); + source->AddLocalizedString("pluginDownload", IDS_PLUGINS_DOWNLOAD); + source->AddLocalizedString("pluginName", IDS_PLUGINS_NAME); + source->AddLocalizedString("pluginVersion", IDS_PLUGINS_VERSION); + source->AddLocalizedString("pluginDescription", IDS_PLUGINS_DESCRIPTION); + source->AddLocalizedString("pluginPath", IDS_PLUGINS_PATH); + source->AddLocalizedString("pluginType", IDS_PLUGINS_TYPE); + source->AddLocalizedString("pluginMimeTypes", IDS_PLUGINS_MIME_TYPES); + source->AddLocalizedString("pluginMimeTypesMimeType", + IDS_PLUGINS_MIME_TYPES_MIME_TYPE); + source->AddLocalizedString("pluginMimeTypesDescription", + IDS_PLUGINS_MIME_TYPES_DESCRIPTION); + source->AddLocalizedString("pluginMimeTypesFileExtensions", + IDS_PLUGINS_MIME_TYPES_FILE_EXTENSIONS); + source->AddLocalizedString("disable", IDS_PLUGINS_DISABLE); + source->AddLocalizedString("enable", IDS_PLUGINS_ENABLE); + source->AddLocalizedString("alwaysAllowed", IDS_PLUGINS_ALWAYS_ALLOWED); + source->AddLocalizedString("noPlugins", IDS_PLUGINS_NO_PLUGINS); + + source->SetJsonPath("strings.js"); + source->AddResourcePath("plugins.js", IDR_PLUGINS_JS); + source->SetDefaultResource(IDR_PLUGINS_HTML); +#if defined(OS_CHROMEOS) + chromeos::AddAccountUITweaksLocalizedValues(source, profile); +#endif + return source; +} + +} // namespace + + +PluginsUI::PluginsUI(content::WebUI* web_ui) : WebUIController(web_ui) { + web_ui->AddMessageHandler(new PluginsHandler()); + + // Set up the chrome://plugins/ source. + Profile* profile = Profile::FromWebUI(web_ui); + content::WebUIDataSource::Add(profile, CreatePluginsUIHTMLSource(profile)); +} + +// static +base::RefCountedMemory* PluginsUI::GetFaviconResourceBytes( + ui::ScaleFactor scale_factor) { + return ResourceBundle::GetSharedInstance(). + LoadDataResourceBytesForScale(IDR_PLUGINS_FAVICON, scale_factor); +} + +// static +void PluginsUI::RegisterProfilePrefs( + user_prefs::PrefRegistrySyncable* registry) { + registry->RegisterBooleanPref(prefs::kPluginsShowDetails, false); + registry->RegisterDictionaryPref( + prefs::kContentSettingsPluginWhitelist, + user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); +}
diff --git a/chrome/browser/ui/webui/plugins_ui.h b/chrome/browser/ui/webui/plugins/plugins_ui.h similarity index 81% rename from chrome/browser/ui/webui/plugins_ui.h rename to chrome/browser/ui/webui/plugins/plugins_ui.h index 0d462f5..d187d6d 100644 --- a/chrome/browser/ui/webui/plugins_ui.h +++ b/chrome/browser/ui/webui/plugins/plugins_ui.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 CHROME_BROWSER_UI_WEBUI_PLUGINS_UI_H_ -#define CHROME_BROWSER_UI_WEBUI_PLUGINS_UI_H_ +#ifndef CHROME_BROWSER_UI_WEBUI_PLUGINS_PLUGINS_UI_H_ +#define CHROME_BROWSER_UI_WEBUI_PLUGINS_PLUGINS_UI_H_ #include "base/macros.h" #include "content/public/browser/web_ui_controller.h" @@ -29,4 +29,4 @@ DISALLOW_COPY_AND_ASSIGN(PluginsUI); }; -#endif // CHROME_BROWSER_UI_WEBUI_PLUGINS_UI_H_ +#endif // CHROME_BROWSER_UI_WEBUI_PLUGINS_PLUGINS_UI_H_
diff --git a/chrome/browser/ui/webui/plugins_ui.cc b/chrome/browser/ui/webui/plugins_ui.cc deleted file mode 100644 index 678c0e6..0000000 --- a/chrome/browser/ui/webui/plugins_ui.cc +++ /dev/null
@@ -1,535 +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/plugins_ui.h" - -#include <stddef.h> - -#include <algorithm> -#include <string> -#include <vector> - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/files/file_path.h" -#include "base/macros.h" -#include "base/memory/ref_counted_memory.h" -#include "base/memory/scoped_ptr.h" -#include "base/memory/singleton.h" -#include "base/memory/weak_ptr.h" -#include "base/message_loop/message_loop.h" -#include "base/path_service.h" -#include "base/prefs/pref_member.h" -#include "base/prefs/pref_service.h" -#include "base/prefs/scoped_user_pref_update.h" -#include "base/strings/utf_string_conversions.h" -#include "base/values.h" -#include "build/build_config.h" -#include "chrome/browser/chrome_notification_types.h" -#include "chrome/browser/content_settings/host_content_settings_map_factory.h" -#include "chrome/browser/plugins/plugin_finder.h" -#include "chrome/browser/plugins/plugin_metadata.h" -#include "chrome/browser/plugins/plugin_prefs.h" -#include "chrome/browser/profiles/profile.h" -#include "chrome/browser/ui/browser.h" -#include "chrome/browser/ui/browser_window.h" -#include "chrome/common/chrome_content_client.h" -#include "chrome/common/chrome_paths.h" -#include "chrome/common/pref_names.h" -#include "chrome/common/url_constants.h" -#include "chrome/grit/generated_resources.h" -#include "components/content_settings/core/browser/host_content_settings_map.h" -#include "components/pref_registry/pref_registry_syncable.h" -#include "content/public/browser/notification_source.h" -#include "content/public/browser/plugin_service.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 "content/public/browser/web_ui_message_handler.h" -#include "content/public/common/content_constants.h" -#include "grit/browser_resources.h" -#include "grit/theme_resources.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/base/resource/resource_bundle.h" - -#if defined(OS_CHROMEOS) -#include "chrome/browser/ui/webui/chromeos/ui_account_tweaks.h" -#endif - -using content::PluginService; -using content::WebContents; -using content::WebPluginInfo; -using content::WebUIMessageHandler; - -namespace { - -// Callback function to process result of EnablePlugin method. -void AssertPluginEnabled(bool did_enable) { - DCHECK(did_enable); -} - -content::WebUIDataSource* CreatePluginsUIHTMLSource(Profile* profile) { - content::WebUIDataSource* source = - content::WebUIDataSource::Create(chrome::kChromeUIPluginsHost); - - source->AddLocalizedString("pluginsTitle", IDS_PLUGINS_TITLE); - source->AddLocalizedString("pluginsDetailsModeLink", - IDS_PLUGINS_DETAILS_MODE_LINK); - source->AddLocalizedString("pluginsNoneInstalled", - IDS_PLUGINS_NONE_INSTALLED); - source->AddLocalizedString("pluginDisabled", IDS_PLUGINS_DISABLED_PLUGIN); - source->AddLocalizedString("pluginDisabledByPolicy", - IDS_PLUGINS_DISABLED_BY_POLICY_PLUGIN); - source->AddLocalizedString("pluginEnabledByPolicy", - IDS_PLUGINS_ENABLED_BY_POLICY_PLUGIN); - source->AddLocalizedString("pluginGroupManagedByPolicy", - IDS_PLUGINS_GROUP_MANAGED_BY_POLICY); - source->AddLocalizedString("pluginDownload", IDS_PLUGINS_DOWNLOAD); - source->AddLocalizedString("pluginName", IDS_PLUGINS_NAME); - source->AddLocalizedString("pluginVersion", IDS_PLUGINS_VERSION); - source->AddLocalizedString("pluginDescription", IDS_PLUGINS_DESCRIPTION); - source->AddLocalizedString("pluginPath", IDS_PLUGINS_PATH); - source->AddLocalizedString("pluginType", IDS_PLUGINS_TYPE); - source->AddLocalizedString("pluginMimeTypes", IDS_PLUGINS_MIME_TYPES); - source->AddLocalizedString("pluginMimeTypesMimeType", - IDS_PLUGINS_MIME_TYPES_MIME_TYPE); - source->AddLocalizedString("pluginMimeTypesDescription", - IDS_PLUGINS_MIME_TYPES_DESCRIPTION); - source->AddLocalizedString("pluginMimeTypesFileExtensions", - IDS_PLUGINS_MIME_TYPES_FILE_EXTENSIONS); - source->AddLocalizedString("disable", IDS_PLUGINS_DISABLE); - source->AddLocalizedString("enable", IDS_PLUGINS_ENABLE); - source->AddLocalizedString("alwaysAllowed", IDS_PLUGINS_ALWAYS_ALLOWED); - source->AddLocalizedString("noPlugins", IDS_PLUGINS_NO_PLUGINS); - - source->SetJsonPath("strings.js"); - source->AddResourcePath("plugins.js", IDR_PLUGINS_JS); - source->SetDefaultResource(IDR_PLUGINS_HTML); -#if defined(OS_CHROMEOS) - chromeos::AddAccountUITweaksLocalizedValues(source, profile); -#endif - return source; -} - -base::string16 PluginTypeToString(int type) { - // The type is stored as an |int|, but doing the switch on the right - // enumeration type gives us better build-time error checking (if someone adds - // a new type). - switch (static_cast<WebPluginInfo::PluginType>(type)) { - case WebPluginInfo::PLUGIN_TYPE_NPAPI: - return l10n_util::GetStringUTF16(IDS_PLUGINS_NPAPI); - case WebPluginInfo::PLUGIN_TYPE_PEPPER_IN_PROCESS: - return l10n_util::GetStringUTF16(IDS_PLUGINS_PPAPI_IN_PROCESS); - case WebPluginInfo::PLUGIN_TYPE_PEPPER_OUT_OF_PROCESS: - return l10n_util::GetStringUTF16(IDS_PLUGINS_PPAPI_OUT_OF_PROCESS); - case WebPluginInfo::PLUGIN_TYPE_BROWSER_PLUGIN: - return l10n_util::GetStringUTF16(IDS_PLUGINS_BROWSER_PLUGIN); - } - NOTREACHED(); - return base::string16(); -} - -//////////////////////////////////////////////////////////////////////////////// -// -// PluginsDOMHandler -// -//////////////////////////////////////////////////////////////////////////////// - -// The handler for Javascript messages for the chrome://plugins/ page. -// TODO(viettrungluu): Make plugin list updates notify, and then observe -// changes; maybe replumb plugin list through plugin service? -// <http://crbug.com/39101> -class PluginsDOMHandler : public WebUIMessageHandler, - public content::NotificationObserver { - public: - PluginsDOMHandler(); - ~PluginsDOMHandler() override {} - - // WebUIMessageHandler implementation. - void RegisterMessages() override; - - // Callback for the "requestPluginsData" message. - void HandleRequestPluginsData(const base::ListValue* args); - - // Callback for the "enablePlugin" message. - void HandleEnablePluginMessage(const base::ListValue* args); - - // Callback for the "saveShowDetailsToPrefs" message. - void HandleSaveShowDetailsToPrefs(const base::ListValue* args); - - // Calback for the "getShowDetails" message. - void HandleGetShowDetails(const base::ListValue* args); - - // Callback for the "setPluginAlwaysAllowed" message. - void HandleSetPluginAlwaysAllowed(const base::ListValue* args); - - // content::NotificationObserver method overrides - void Observe(int type, - const content::NotificationSource& source, - const content::NotificationDetails& details) override; - - private: - void LoadPlugins(); - - // Called on the UI thread when the plugin information is ready. - void PluginsLoaded(const std::vector<WebPluginInfo>& plugins); - - content::NotificationRegistrar registrar_; - - // Holds grouped plugins. The key is the group identifier and - // the value is the list of plugins belonging to the group. - typedef base::hash_map<std::string, std::vector<const WebPluginInfo*> > - PluginGroups; - - // This pref guards the value whether about:plugins is in the details mode or - // not. - BooleanPrefMember show_details_; - - base::WeakPtrFactory<PluginsDOMHandler> weak_ptr_factory_; - - DISALLOW_COPY_AND_ASSIGN(PluginsDOMHandler); -}; - -PluginsDOMHandler::PluginsDOMHandler() - : weak_ptr_factory_(this) { -} - -void PluginsDOMHandler::RegisterMessages() { - Profile* profile = Profile::FromWebUI(web_ui()); - - PrefService* prefs = profile->GetPrefs(); - show_details_.Init(prefs::kPluginsShowDetails, prefs); - - registrar_.Add(this, - chrome::NOTIFICATION_PLUGIN_ENABLE_STATUS_CHANGED, - content::Source<Profile>(profile)); - - web_ui()->RegisterMessageCallback("requestPluginsData", - base::Bind(&PluginsDOMHandler::HandleRequestPluginsData, - base::Unretained(this))); - web_ui()->RegisterMessageCallback("enablePlugin", - base::Bind(&PluginsDOMHandler::HandleEnablePluginMessage, - base::Unretained(this))); - web_ui()->RegisterMessageCallback("setPluginAlwaysAllowed", - base::Bind(&PluginsDOMHandler::HandleSetPluginAlwaysAllowed, - base::Unretained(this))); - web_ui()->RegisterMessageCallback("saveShowDetailsToPrefs", - base::Bind(&PluginsDOMHandler::HandleSaveShowDetailsToPrefs, - base::Unretained(this))); - web_ui()->RegisterMessageCallback("getShowDetails", - base::Bind(&PluginsDOMHandler::HandleGetShowDetails, - base::Unretained(this))); -} - -void PluginsDOMHandler::HandleRequestPluginsData(const base::ListValue* args) { - LoadPlugins(); -} - -void PluginsDOMHandler::HandleEnablePluginMessage(const base::ListValue* args) { - Profile* profile = Profile::FromWebUI(web_ui()); - - // Be robust in accepting badness since plugins display HTML (hence - // JavaScript). - if (args->GetSize() != 3) { - NOTREACHED(); - return; - } - - std::string enable_str; - std::string is_group_str; - if (!args->GetString(1, &enable_str) || !args->GetString(2, &is_group_str)) { - NOTREACHED(); - return; - } - bool enable = enable_str == "true"; - - PluginPrefs* plugin_prefs = PluginPrefs::GetForProfile(profile).get(); - if (is_group_str == "true") { - base::string16 group_name; - if (!args->GetString(0, &group_name)) { - NOTREACHED(); - return; - } - - plugin_prefs->EnablePluginGroup(enable, group_name); - if (enable) { - // See http://crbug.com/50105 for background. - base::string16 adobereader = base::ASCIIToUTF16( - PluginMetadata::kAdobeReaderGroupName); - base::string16 internalpdf = - base::ASCIIToUTF16(ChromeContentClient::kPDFPluginName); - if (group_name == adobereader) - plugin_prefs->EnablePluginGroup(false, internalpdf); - else if (group_name == internalpdf) - plugin_prefs->EnablePluginGroup(false, adobereader); - } - } else { - base::FilePath::StringType file_path; - if (!args->GetString(0, &file_path)) { - NOTREACHED(); - return; - } - - plugin_prefs->EnablePlugin(enable, base::FilePath(file_path), - base::Bind(&AssertPluginEnabled)); - } -} - -void PluginsDOMHandler::HandleSaveShowDetailsToPrefs( - const base::ListValue* args) { - std::string details_mode; - if (!args->GetString(0, &details_mode)) { - NOTREACHED(); - return; - } - show_details_.SetValue(details_mode == "true"); -} - -void PluginsDOMHandler::HandleGetShowDetails(const base::ListValue* args) { - base::FundamentalValue show_details(show_details_.GetValue()); - web_ui()->CallJavascriptFunction("loadShowDetailsFromPrefs", show_details); -} - -void PluginsDOMHandler::HandleSetPluginAlwaysAllowed( - const base::ListValue* args) { - // Be robust in the input parameters, but crash in a Debug build. - if (args->GetSize() != 2) { - NOTREACHED(); - return; - } - - std::string plugin; - bool allowed = false; - if (!args->GetString(0, &plugin) || !args->GetBoolean(1, &allowed)) { - NOTREACHED(); - return; - } - Profile* profile = Profile::FromWebUI(web_ui()); - HostContentSettingsMapFactory::GetForProfile(profile)->SetContentSetting( - ContentSettingsPattern::Wildcard(), - ContentSettingsPattern::Wildcard(), - CONTENT_SETTINGS_TYPE_PLUGINS, - plugin, - allowed ? CONTENT_SETTING_ALLOW : CONTENT_SETTING_DEFAULT); - - // Keep track of the whitelist separately, so that we can distinguish plugins - // whitelisted by the user from automatically whitelisted ones. - DictionaryPrefUpdate update(profile->GetPrefs(), - prefs::kContentSettingsPluginWhitelist); - update->SetBoolean(plugin, allowed); -} - -void PluginsDOMHandler::Observe(int type, - const content::NotificationSource& source, - const content::NotificationDetails& details) { - DCHECK_EQ(chrome::NOTIFICATION_PLUGIN_ENABLE_STATUS_CHANGED, type); - LoadPlugins(); -} - -void PluginsDOMHandler::LoadPlugins() { - if (weak_ptr_factory_.HasWeakPtrs()) - return; - - PluginService::GetInstance()->GetPlugins( - base::Bind(&PluginsDOMHandler::PluginsLoaded, - weak_ptr_factory_.GetWeakPtr())); -} - -void PluginsDOMHandler::PluginsLoaded( - const std::vector<WebPluginInfo>& plugins) { - Profile* profile = Profile::FromWebUI(web_ui()); - PluginPrefs* plugin_prefs = PluginPrefs::GetForProfile(profile).get(); - - ContentSettingsPattern wildcard = ContentSettingsPattern::Wildcard(); - - PluginFinder* plugin_finder = PluginFinder::GetInstance(); - // Group plugins by identifier. This is done to be able to display - // the plugins in UI in a grouped fashion. - PluginGroups groups; - for (size_t i = 0; i < plugins.size(); ++i) { - scoped_ptr<PluginMetadata> plugin( - plugin_finder->GetPluginMetadata(plugins[i])); - groups[plugin->identifier()].push_back(&plugins[i]); - } - - // Construct DictionaryValues to return to UI. - base::ListValue* plugin_groups_data = new base::ListValue(); - for (PluginGroups::const_iterator it = groups.begin(); - it != groups.end(); ++it) { - const std::vector<const WebPluginInfo*>& group_plugins = it->second; - base::ListValue* plugin_files = new base::ListValue(); - scoped_ptr<PluginMetadata> plugin_metadata( - plugin_finder->GetPluginMetadata(*group_plugins[0])); - base::string16 group_name = plugin_metadata->name(); - std::string group_identifier = plugin_metadata->identifier(); - bool group_enabled = false; - bool all_plugins_enabled_by_policy = true; - bool all_plugins_disabled_by_policy = true; - bool all_plugins_managed_by_policy = true; - const WebPluginInfo* active_plugin = NULL; - for (size_t j = 0; j < group_plugins.size(); ++j) { - const WebPluginInfo& group_plugin = *group_plugins[j]; - - base::DictionaryValue* plugin_file = new base::DictionaryValue(); - plugin_file->SetString("name", group_plugin.name); - - // If this plugin is Pepper Flash, and the plugin path is the same as the - // path for the Pepper Flash System plugin, then mark this plugin - // description as the system plugin to help the user disambiguate the - // two plugins. - base::string16 desc = group_plugin.desc; - if (group_plugin.is_pepper_plugin() && - group_plugin.name == base::ASCIIToUTF16(content::kFlashPluginName)) { - base::FilePath system_flash_path; - PathService::Get(chrome::FILE_PEPPER_FLASH_SYSTEM_PLUGIN, - &system_flash_path); - if (base::FilePath::CompareEqualIgnoreCase(group_plugin.path.value(), - system_flash_path.value())) { -#if defined(GOOGLE_CHROME_BUILD) - // Existing documentation for debugging Flash describe this plugin as - // "Debug" so preserve this nomenclature here. - desc += base::ASCIIToUTF16(" Debug"); -#else - // On Chromium, we can name it what it really is; the system plugin. - desc += base::ASCIIToUTF16(" System"); -#endif - } - } - plugin_file->SetString("description", desc); - - plugin_file->SetString("path", group_plugin.path.value()); - plugin_file->SetString("version", group_plugin.version); - plugin_file->SetString("type", PluginTypeToString(group_plugin.type)); - - base::ListValue* mime_types = new base::ListValue(); - const std::vector<content::WebPluginMimeType>& plugin_mime_types = - group_plugin.mime_types; - for (size_t k = 0; k < plugin_mime_types.size(); ++k) { - base::DictionaryValue* mime_type = new base::DictionaryValue(); - mime_type->SetString("mimeType", plugin_mime_types[k].mime_type); - mime_type->SetString("description", plugin_mime_types[k].description); - - base::ListValue* file_extensions = new base::ListValue(); - const std::vector<std::string>& mime_file_extensions = - plugin_mime_types[k].file_extensions; - for (size_t l = 0; l < mime_file_extensions.size(); ++l) { - file_extensions->Append( - new base::StringValue(mime_file_extensions[l])); - } - mime_type->Set("fileExtensions", file_extensions); - - mime_types->Append(mime_type); - } - plugin_file->Set("mimeTypes", mime_types); - - bool plugin_enabled = plugin_prefs->IsPluginEnabled(group_plugin); - - if (!active_plugin || (plugin_enabled && !group_enabled)) - active_plugin = &group_plugin; - group_enabled = plugin_enabled || group_enabled; - - std::string enabled_mode; - PluginPrefs::PolicyStatus plugin_status = - plugin_prefs->PolicyStatusForPlugin(group_plugin.name); - PluginPrefs::PolicyStatus group_status = - plugin_prefs->PolicyStatusForPlugin(group_name); - if (plugin_status == PluginPrefs::POLICY_ENABLED || - group_status == PluginPrefs::POLICY_ENABLED) { - enabled_mode = "enabledByPolicy"; - all_plugins_disabled_by_policy = false; - } else { - all_plugins_enabled_by_policy = false; - if (plugin_status == PluginPrefs::POLICY_DISABLED || - group_status == PluginPrefs::POLICY_DISABLED) { - enabled_mode = "disabledByPolicy"; - } else { - all_plugins_disabled_by_policy = false; - all_plugins_managed_by_policy = false; - if (plugin_enabled) { - enabled_mode = "enabledByUser"; - } else { - enabled_mode = "disabledByUser"; - } - } - } - plugin_file->SetString("enabledMode", enabled_mode); - - plugin_files->Append(plugin_file); - } - base::DictionaryValue* group_data = new base::DictionaryValue(); - - group_data->Set("plugin_files", plugin_files); - group_data->SetString("name", group_name); - group_data->SetString("id", group_identifier); - group_data->SetString("description", active_plugin->desc); - group_data->SetString("version", active_plugin->version); - -#if defined(ENABLE_PLUGIN_INSTALLATION) - bool out_of_date = plugin_metadata->GetSecurityStatus(*active_plugin) == - PluginMetadata::SECURITY_STATUS_OUT_OF_DATE; - group_data->SetBoolean("critical", out_of_date); - group_data->SetString("update_url", plugin_metadata->plugin_url().spec()); -#endif - - std::string enabled_mode; - if (all_plugins_enabled_by_policy) { - enabled_mode = "enabledByPolicy"; - } else if (all_plugins_disabled_by_policy) { - enabled_mode = "disabledByPolicy"; - } else if (all_plugins_managed_by_policy) { - enabled_mode = "managedByPolicy"; - } else if (group_enabled) { - enabled_mode = "enabledByUser"; - } else { - enabled_mode = "disabledByUser"; - } - group_data->SetString("enabledMode", enabled_mode); - - bool always_allowed = false; - if (group_enabled) { - const base::DictionaryValue* whitelist = - profile->GetPrefs()->GetDictionary( - prefs::kContentSettingsPluginWhitelist); - whitelist->GetBoolean(group_identifier, &always_allowed); - } - group_data->SetBoolean("alwaysAllowed", always_allowed); - - plugin_groups_data->Append(group_data); - } - base::DictionaryValue results; - results.Set("plugins", plugin_groups_data); - web_ui()->CallJavascriptFunction("returnPluginsData", results); -} - -} // namespace - -/////////////////////////////////////////////////////////////////////////////// -// -// PluginsUI -// -/////////////////////////////////////////////////////////////////////////////// - -PluginsUI::PluginsUI(content::WebUI* web_ui) : WebUIController(web_ui) { - web_ui->AddMessageHandler(new PluginsDOMHandler()); - - // Set up the chrome://plugins/ source. - Profile* profile = Profile::FromWebUI(web_ui); - content::WebUIDataSource::Add(profile, CreatePluginsUIHTMLSource(profile)); -} - -// static -base::RefCountedMemory* PluginsUI::GetFaviconResourceBytes( - ui::ScaleFactor scale_factor) { - return ResourceBundle::GetSharedInstance(). - LoadDataResourceBytesForScale(IDR_PLUGINS_FAVICON, scale_factor); -} - -// static -void PluginsUI::RegisterProfilePrefs( - user_prefs::PrefRegistrySyncable* registry) { - registry->RegisterBooleanPref(prefs::kPluginsShowDetails, false); - registry->RegisterDictionaryPref( - prefs::kContentSettingsPluginWhitelist, - user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); -}
diff --git a/chrome/browser/ui/webui/print_preview/extension_printer_handler.cc b/chrome/browser/ui/webui/print_preview/extension_printer_handler.cc index d2af813..11b571e 100644 --- a/chrome/browser/ui/webui/print_preview/extension_printer_handler.cc +++ b/chrome/browser/ui/webui/print_preview/extension_printer_handler.cc
@@ -17,7 +17,7 @@ #include "base/memory/ref_counted_memory.h" #include "base/strings/string_split.h" #include "base/task_runner_util.h" -#include "chrome/browser/local_discovery/pwg_raster_converter.h" +#include "chrome/browser/printing/pwg_raster_converter.h" #include "components/cloud_devices/common/cloud_device_description.h" #include "components/cloud_devices/common/printer_description.h" #include "device/core/device_client.h" @@ -43,7 +43,7 @@ using extensions::ExtensionRegistry; using extensions::ListBuilder; using extensions::UsbPrinterManifestData; -using local_discovery::PWGRasterConverter; +using printing::PWGRasterConverter; namespace { @@ -254,8 +254,8 @@ weak_ptr_factory_.GetWeakPtr(), callback)); } -void ExtensionPrinterHandler::SetPwgRasterConverterForTesting( - scoped_ptr<local_discovery::PWGRasterConverter> pwg_raster_converter) { +void ExtensionPrinterHandler::SetPWGRasterConverterForTesting( + scoped_ptr<PWGRasterConverter> pwg_raster_converter) { pwg_raster_converter_ = std::move(pwg_raster_converter); }
diff --git a/chrome/browser/ui/webui/print_preview/extension_printer_handler.h b/chrome/browser/ui/webui/print_preview/extension_printer_handler.h index 76e707b1..1868542 100644 --- a/chrome/browser/ui/webui/print_preview/extension_printer_handler.h +++ b/chrome/browser/ui/webui/print_preview/extension_printer_handler.h
@@ -38,7 +38,7 @@ class Size; } -namespace local_discovery { +namespace printing { class PWGRasterConverter; } @@ -77,8 +77,8 @@ private: friend class ExtensionPrinterHandlerTest; - void SetPwgRasterConverterForTesting( - scoped_ptr<local_discovery::PWGRasterConverter> pwg_raster_converter); + void SetPWGRasterConverterForTesting( + scoped_ptr<printing::PWGRasterConverter> pwg_raster_converter); // Converts |data| to PWG raster format (from PDF) for a printer described // by |printer_description|. @@ -119,7 +119,7 @@ content::BrowserContext* browser_context_; - scoped_ptr<local_discovery::PWGRasterConverter> pwg_raster_converter_; + scoped_ptr<printing::PWGRasterConverter> pwg_raster_converter_; int pending_enumeration_count_ = 0; scoped_refptr<base::TaskRunner> slow_task_runner_;
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 de4cff4a..d99bae8 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
@@ -21,7 +21,7 @@ #include "base/test/values_test_util.h" #include "base/values.h" #include "chrome/browser/extensions/test_extension_environment.h" -#include "chrome/browser/local_discovery/pwg_raster_converter.h" +#include "chrome/browser/printing/pwg_raster_converter.h" #include "chrome/browser/ui/webui/print_preview/extension_printer_handler.h" #include "chrome/test/base/testing_profile.h" #include "components/version_info/version_info.h" @@ -47,7 +47,7 @@ using extensions::PrinterProviderAPI; using extensions::PrinterProviderPrintJob; using extensions::TestExtensionEnvironment; -using local_discovery::PWGRasterConverter; +using printing::PWGRasterConverter; namespace { @@ -268,7 +268,7 @@ return std::string(memory->front_as<char>(), memory->size()); } -// Fake PWGRasterconverter used in the tests. +// Fake PWGRasterConverter used in the tests. class FakePWGRasterConverter : public PWGRasterConverter { public: FakePWGRasterConverter() : fail_conversion_(false), initialized_(false) {} @@ -479,7 +479,7 @@ env_.profile(), base::MessageLoop::current()->task_runner())); pwg_raster_converter_ = new FakePWGRasterConverter(); - extension_printer_handler_->SetPwgRasterConverterForTesting( + extension_printer_handler_->SetPWGRasterConverterForTesting( scoped_ptr<PWGRasterConverter>(pwg_raster_converter_)); device_client_.set_usb_service(&usb_service_); }
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_handler.cc b/chrome/browser/ui/webui/print_preview/print_preview_handler.cc index 5af74615..ed1affcc 100644 --- a/chrome/browser/ui/webui/print_preview/print_preview_handler.cc +++ b/chrome/browser/ui/webui/print_preview/print_preview_handler.cc
@@ -94,7 +94,7 @@ #endif #if defined(ENABLE_SERVICE_DISCOVERY) -#include "chrome/browser/local_discovery/privet_constants.h" +#include "chrome/browser/printing/cloud_print/privet_constants.h" #endif using content::BrowserThread; @@ -1549,7 +1549,7 @@ DCHECK(!service_discovery_client_.get() || service_discovery_client_.get() == client.get()); service_discovery_client_ = client; - printer_lister_.reset(new local_discovery::PrivetLocalPrinterLister( + printer_lister_.reset(new cloud_print::PrivetLocalPrinterLister( service_discovery_client_.get(), profile->GetRequestContext(), this)); printer_lister_->Start(); } @@ -1558,7 +1558,7 @@ bool added, const std::string& name, bool has_local_printing, - const local_discovery::DeviceDescription& description) { + const cloud_print::DeviceDescription& description) { base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); if (has_local_printing || command_line->HasSwitch(switches::kEnablePrintPreviewRegisterPromos)) { @@ -1575,7 +1575,7 @@ } void PrintPreviewHandler::PrivetCapabilitiesUpdateClient( - scoped_ptr<local_discovery::PrivetHTTPClient> http_client) { + scoped_ptr<cloud_print::PrivetHTTPClient> http_client) { if (!PrivetUpdateClient(std::move(http_client))) return; @@ -1587,7 +1587,7 @@ } bool PrintPreviewHandler::PrivetUpdateClient( - scoped_ptr<local_discovery::PrivetHTTPClient> http_client) { + scoped_ptr<cloud_print::PrivetHTTPClient> http_client) { if (!http_client) { SendPrivetCapabilitiesError(privet_http_resolution_->GetName()); privet_http_resolution_.reset(); @@ -1596,7 +1596,7 @@ privet_local_print_operation_.reset(); privet_capabilities_operation_.reset(); - privet_http_client_ = local_discovery::PrivetV1HTTPClient::CreateDefault( + privet_http_client_ = cloud_print::PrivetV1HTTPClient::CreateDefault( std::move(http_client)); privet_http_resolution_.reset(); @@ -1608,7 +1608,7 @@ std::string print_ticket, std::string capabilities, gfx::Size page_size, - scoped_ptr<local_discovery::PrivetHTTPClient> http_client) { + scoped_ptr<cloud_print::PrivetHTTPClient> http_client) { if (!PrivetUpdateClient(std::move(http_client))) return; @@ -1654,14 +1654,14 @@ const base::DictionaryValue* capabilities) { std::string name = privet_capabilities_operation_->GetHTTPClient()->GetName(); - if (!capabilities || capabilities->HasKey(local_discovery::kPrivetKeyError) || + if (!capabilities || capabilities->HasKey(cloud_print::kPrivetKeyError) || !printer_lister_) { SendPrivetCapabilitiesError(name); return; } base::DictionaryValue printer_info; - const local_discovery::DeviceDescription* description = + const cloud_print::DeviceDescription* description = printer_lister_->GetDeviceDescription(name); if (!description) { @@ -1702,9 +1702,9 @@ bool PrintPreviewHandler::CreatePrivetHTTP( const std::string& name, - const local_discovery::PrivetHTTPAsynchronousFactory::ResultCallback& + const cloud_print::PrivetHTTPAsynchronousFactory::ResultCallback& callback) { - const local_discovery::DeviceDescription* device_description = + const cloud_print::DeviceDescription* device_description = printer_lister_ ? printer_lister_->GetDeviceDescription(name) : NULL; if (!device_description) { @@ -1713,7 +1713,7 @@ } privet_http_factory_ = - local_discovery::PrivetHTTPAsynchronousFactory::CreateInstance( + cloud_print::PrivetHTTPAsynchronousFactory::CreateInstance( Profile::FromWebUI(web_ui())->GetRequestContext()); privet_http_resolution_ = privet_http_factory_->CreatePrivetHTTP(name); privet_http_resolution_->Start(device_description->address, callback); @@ -1722,12 +1722,12 @@ } void PrintPreviewHandler::OnPrivetPrintingDone( - const local_discovery::PrivetLocalPrintOperation* print_operation) { + const cloud_print::PrivetLocalPrintOperation* print_operation) { ClosePreviewDialog(); } void PrintPreviewHandler::OnPrivetPrintingError( - const local_discovery::PrivetLocalPrintOperation* print_operation, + const cloud_print::PrivetLocalPrintOperation* print_operation, int http_code) { base::FundamentalValue http_code_value(http_code); web_ui()->CallJavascriptFunction("onPrivetPrintFailed", http_code_value); @@ -1735,7 +1735,7 @@ void PrintPreviewHandler::FillPrinterDescription( const std::string& name, - const local_discovery::DeviceDescription& description, + const cloud_print::DeviceDescription& description, bool has_local_printing, base::DictionaryValue* printer_value) { base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_handler.h b/chrome/browser/ui/webui/print_preview/print_preview_handler.h index 5d19a46..5188e0c 100644 --- a/chrome/browser/ui/webui/print_preview/print_preview_handler.h +++ b/chrome/browser/ui/webui/print_preview/print_preview_handler.h
@@ -20,8 +20,8 @@ #include "ui/shell_dialogs/select_file_dialog.h" #if defined(ENABLE_SERVICE_DISCOVERY) -#include "chrome/browser/local_discovery/privet_local_printer_lister.h" #include "chrome/browser/local_discovery/service_discovery_shared_client.h" +#include "chrome/browser/printing/cloud_print/privet_local_printer_lister.h" #endif // ENABLE_SERVICE_DISCOVERY class PrinterHandler; @@ -45,8 +45,8 @@ class PrintPreviewHandler : public content::WebUIMessageHandler, #if defined(ENABLE_SERVICE_DISCOVERY) - public local_discovery::PrivetLocalPrinterLister::Delegate, - public local_discovery::PrivetLocalPrintOperation::Delegate, + public cloud_print::PrivetLocalPrinterLister::Delegate, + public cloud_print::PrivetLocalPrintOperation::Delegate, #endif public ui::SelectFileDialog::Listener, public printing::PrintViewManagerObserver, @@ -92,15 +92,15 @@ bool added, const std::string& name, bool has_local_printing, - const local_discovery::DeviceDescription& description) override; + const cloud_print::DeviceDescription& description) override; void LocalPrinterRemoved(const std::string& name) override; void LocalPrinterCacheFlushed() override; // PrivetLocalPrintOperation::Delegate implementation. - void OnPrivetPrintingDone(const local_discovery::PrivetLocalPrintOperation* - print_operation) override; + void OnPrivetPrintingDone( + const cloud_print::PrivetLocalPrintOperation* print_operation) override; void OnPrivetPrintingError( - const local_discovery::PrivetLocalPrintOperation* print_operation, + const cloud_print::PrivetLocalPrintOperation* print_operation, int http_code) override; #endif // ENABLE_SERVICE_DISCOVERY int regenerate_preview_request_count() const { @@ -278,14 +278,14 @@ local_discovery::ServiceDiscoverySharedClient>& client); void OnPrivetCapabilities(const base::DictionaryValue* capabilities); void PrivetCapabilitiesUpdateClient( - scoped_ptr<local_discovery::PrivetHTTPClient> http_client); + scoped_ptr<cloud_print::PrivetHTTPClient> http_client); void PrivetLocalPrintUpdateClient( std::string print_ticket, std::string capabilities, gfx::Size page_size, - scoped_ptr<local_discovery::PrivetHTTPClient> http_client); + scoped_ptr<cloud_print::PrivetHTTPClient> http_client); bool PrivetUpdateClient( - scoped_ptr<local_discovery::PrivetHTTPClient> http_client); + scoped_ptr<cloud_print::PrivetHTTPClient> http_client); void StartPrivetLocalPrint(const std::string& print_ticket, const std::string& capabilities, const gfx::Size& page_size); @@ -296,11 +296,11 @@ const gfx::Size& page_size); bool CreatePrivetHTTP( const std::string& name, - const local_discovery::PrivetHTTPAsynchronousFactory::ResultCallback& + const cloud_print::PrivetHTTPAsynchronousFactory::ResultCallback& callback); void FillPrinterDescription( const std::string& name, - const local_discovery::DeviceDescription& description, + const cloud_print::DeviceDescription& description, bool has_local_printing, base::DictionaryValue* printer_value); #endif @@ -372,15 +372,15 @@ #if defined(ENABLE_SERVICE_DISCOVERY) scoped_refptr<local_discovery::ServiceDiscoverySharedClient> service_discovery_client_; - scoped_ptr<local_discovery::PrivetLocalPrinterLister> printer_lister_; + scoped_ptr<cloud_print::PrivetLocalPrinterLister> printer_lister_; - scoped_ptr<local_discovery::PrivetHTTPAsynchronousFactory> + scoped_ptr<cloud_print::PrivetHTTPAsynchronousFactory> privet_http_factory_; - scoped_ptr<local_discovery::PrivetHTTPResolution> privet_http_resolution_; - scoped_ptr<local_discovery::PrivetV1HTTPClient> privet_http_client_; - scoped_ptr<local_discovery::PrivetJSONOperation> + scoped_ptr<cloud_print::PrivetHTTPResolution> privet_http_resolution_; + scoped_ptr<cloud_print::PrivetV1HTTPClient> privet_http_client_; + scoped_ptr<cloud_print::PrivetJSONOperation> privet_capabilities_operation_; - scoped_ptr<local_discovery::PrivetLocalPrintOperation> + scoped_ptr<cloud_print::PrivetLocalPrintOperation> privet_local_print_operation_; #endif
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_ui.cc b/chrome/browser/ui/webui/print_preview/print_preview_ui.cc index 8ef6e074..67daffd 100644 --- a/chrome/browser/ui/webui/print_preview/print_preview_ui.cc +++ b/chrome/browser/ui/webui/print_preview/print_preview_ui.cc
@@ -126,7 +126,8 @@ const content::WebUIDataSource::GotDataCallback& callback) { // ChromeWebUIDataSource handles most requests except for the print preview // data. - if (!base::EndsWith(path, "/print.pdf", base::CompareCase::SENSITIVE)) + std::string file_path = path.substr(0, path.find_first_of('?')); + if (!base::EndsWith(file_path, "/print.pdf", base::CompareCase::SENSITIVE)) return false; // Print Preview data.
diff --git a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc index df44b1d3..b2ddb46c 100644 --- a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc +++ b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
@@ -127,6 +127,10 @@ html_source->AddLocalizedString( "bluetoothPageTitle", IDS_SETTINGS_BLUETOOTH); html_source->AddLocalizedString( + "bluetoothAddDevicePageTitle", IDS_SETTINGS_BLUETOOTH_ADD_DEVICE); + html_source->AddLocalizedString( + "bluetoothPairDevicePageTitle", IDS_SETTINGS_BLUETOOTH_PAIR_DEVICE); + html_source->AddLocalizedString( "bluetoothEnable", IDS_SETTINGS_BLUETOOTH_ENABLE); html_source->AddLocalizedString( "bluetoothConnect", IDS_OPTIONS_SETTINGS_BLUETOOTH_CONNECT); @@ -135,7 +139,46 @@ html_source->AddLocalizedString( "bluetoothNoDevices", IDS_OPTIONS_SETTINGS_BLUETOOTH_NO_DEVICES); html_source->AddLocalizedString( + "bluetoothConnect", IDS_OPTIONS_SETTINGS_BLUETOOTH_CONNECT); + html_source->AddLocalizedString( + "bluetoothDisconnect", IDS_OPTIONS_SETTINGS_BLUETOOTH_DISCONNECT); + html_source->AddLocalizedString( "bluetoothConnecting", IDS_OPTIONS_SETTINGS_BLUETOOTH_CONNECTING); + html_source->AddLocalizedString( + "bluetoothRemove", IDS_SETTINGS_BLUETOOTH_REMOVE); + html_source->AddLocalizedString( + "bluetoothCancel", IDS_OPTIONS_SETTINGS_BLUETOOTH_CANCEL); + html_source->AddLocalizedString( + "bluetoothScanning", IDS_OPTIONS_SETTINGS_BLUETOOTH_SCANNING); + html_source->AddLocalizedString( + "bluetoothAccept", IDS_OPTIONS_SETTINGS_BLUETOOTH_ACCEPT_PASSKEY); + html_source->AddLocalizedString( + "bluetoothReject", IDS_OPTIONS_SETTINGS_BLUETOOTH_REJECT_PASSKEY); + html_source->AddLocalizedString( + "bluetoothConnect", IDS_OPTIONS_SETTINGS_BLUETOOTH_CONNECT); + html_source->AddLocalizedString( + "bluetoothCancel", IDS_OPTIONS_SETTINGS_BLUETOOTH_CANCEL); + html_source->AddLocalizedString( + "bluetoothDismiss", IDS_OPTIONS_SETTINGS_BLUETOOTH_DISMISS_ERROR); + + // Device connecting and pairing. + html_source->AddLocalizedString("bluetoothStartConnecting", + IDS_SETTINGS_BLUETOOTH_START_CONNECTING); + html_source->AddLocalizedString("bluetoothEnterKey", + IDS_OPTIONS_SETTINGS_BLUETOOTH_ENTER_KEY); + // These ids are generated in JS using 'bluetooth_' + a value from + // bluetoothPrivate.PairingEventType (see bluetooth_private.idl). + // 'keysEntered', and 'requestAuthorization' have no associated message. + html_source->AddLocalizedString("bluetooth_requestPincode", + IDS_SETTINGS_BLUETOOTH_REQUEST_PINCODE); + html_source->AddLocalizedString("bluetooth_displayPincode", + IDS_SETTINGS_BLUETOOTH_DISPLAY_PINCODE); + html_source->AddLocalizedString("bluetooth_requestPasskey", + IDS_SETTINGS_BLUETOOTH_REQUEST_PASSKEY); + html_source->AddLocalizedString("bluetooth_displayPasskey", + IDS_SETTINGS_BLUETOOTH_DISPLAY_PASSKEY); + html_source->AddLocalizedString("bluetooth_confirmPasskey", + IDS_SETTINGS_BLUETOOTH_CONFIRM_PASSKEY); } #endif
diff --git a/chrome/browser/ui/webui/settings/reset_settings_handler.cc b/chrome/browser/ui/webui/settings/reset_settings_handler.cc index 238a0066..50f42b4 100644 --- a/chrome/browser/ui/webui/settings/reset_settings_handler.cc +++ b/chrome/browser/ui/webui/settings/reset_settings_handler.cc
@@ -49,7 +49,8 @@ namespace settings { ResetSettingsHandler::ResetSettingsHandler( - Profile* profile, bool allow_powerwash) : profile_(profile) { + Profile* profile, bool allow_powerwash) + : profile_(profile), weak_ptr_factory_(this) { #if defined(OS_CHROMEOS) allow_powerwash_ = allow_powerwash; #endif // defined(OS_CHROMEOS) @@ -119,7 +120,7 @@ // Reset once the prefs are fetched. config_fetcher_->SetCallback( base::Bind(&ResetSettingsHandler::ResetProfile, - Unretained(this), + base::Unretained(this), send_settings)); } else { ResetProfile(send_settings); @@ -153,7 +154,8 @@ if (!GetResetter()->IsActive()) { setting_snapshot_.reset(new ResettableSettingsSnapshot(profile_)); setting_snapshot_->RequestShortcuts(base::Bind( - &ResetSettingsHandler::UpdateFeedbackUI, AsWeakPtr())); + &ResetSettingsHandler::UpdateFeedbackUI, + weak_ptr_factory_.GetWeakPtr())); UpdateFeedbackUI(); } @@ -161,7 +163,7 @@ return; config_fetcher_.reset(new BrandcodeConfigFetcher( base::Bind(&ResetSettingsHandler::OnSettingsFetched, - Unretained(this)), + base::Unretained(this)), GURL("https://tools.google.com/service/update2"), brandcode_)); } @@ -202,7 +204,8 @@ GetResetter()->Reset( ProfileResetter::ALL, std::move(default_settings), - base::Bind(&ResetSettingsHandler::OnResetProfileSettingsDone, AsWeakPtr(), + base::Bind(&ResetSettingsHandler::OnResetProfileSettingsDone, + weak_ptr_factory_.GetWeakPtr(), send_settings)); content::RecordAction(base::UserMetricsAction("ResetProfile")); UMA_HISTOGRAM_BOOLEAN("ProfileReset.SendFeedback", send_settings);
diff --git a/chrome/browser/ui/webui/settings/reset_settings_handler.h b/chrome/browser/ui/webui/settings/reset_settings_handler.h index a6e39e1a..aa27c8f 100644 --- a/chrome/browser/ui/webui/settings/reset_settings_handler.h +++ b/chrome/browser/ui/webui/settings/reset_settings_handler.h
@@ -33,9 +33,7 @@ // Handler for // 1) 'Reset Profile Settings' dialog // 2) 'Powerwash' dialog (ChromeOS only) -class ResetSettingsHandler - : public SettingsPageUIHandler, - public base::SupportsWeakPtr<ResetSettingsHandler> { +class ResetSettingsHandler : public SettingsPageUIHandler { public: ~ResetSettingsHandler() override; @@ -101,6 +99,8 @@ // Contains Chrome brand code; empty for organic Chrome. std::string brandcode_; + base::WeakPtrFactory<ResetSettingsHandler> weak_ptr_factory_; + DISALLOW_COPY_AND_ASSIGN(ResetSettingsHandler); };
diff --git a/chrome/browser/ui/webui/signin/inline_login_handler.cc b/chrome/browser/ui/webui/signin/inline_login_handler.cc index 8655905..899607f 100644 --- a/chrome/browser/ui/webui/signin/inline_login_handler.cc +++ b/chrome/browser/ui/webui/signin/inline_login_handler.cc
@@ -131,9 +131,9 @@ content::RecordAction( base::UserMetricsAction("Signin_Signin_FromRecentTabs")); break; - case signin_metrics::AccessPoint::ACCESS_POINT_UNSPECIFIED: + case signin_metrics::AccessPoint::ACCESS_POINT_UNKNOWN: content::RecordAction( - base::UserMetricsAction("Signin_Signin_FromUnspecifiedAccessPoint")); + base::UserMetricsAction("Signin_Signin_FromUnknownAccessPoint")); break; case signin_metrics::AccessPoint::ACCESS_POINT_MAX: NOTREACHED();
diff --git a/chrome/browser/ui/webui/signin/inline_login_handler_impl.cc b/chrome/browser/ui/webui/signin/inline_login_handler_impl.cc index 0a9c4b1..aaea0eb6 100644 --- a/chrome/browser/ui/webui/signin/inline_login_handler_impl.cc +++ b/chrome/browser/ui/webui/signin/inline_login_handler_impl.cc
@@ -372,6 +372,7 @@ const std::string& refresh_token, OneClickSigninSyncStarter::ConfirmationRequired confirmation_required, OneClickSigninSyncStarter::StartSyncMode start_mode) { + // TODO(skym): Use last account id for equality check, crbug.com/571698. std::string last_email = profile_->GetPrefs()->GetString(prefs::kGoogleServicesLastUsername);
diff --git a/chrome/browser/ui/webui/signin/user_manager_screen_handler.cc b/chrome/browser/ui/webui/signin/user_manager_screen_handler.cc index 441afca..fb0c0ae 100644 --- a/chrome/browser/ui/webui/signin/user_manager_screen_handler.cc +++ b/chrome/browser/ui/webui/signin/user_manager_screen_handler.cc
@@ -5,6 +5,7 @@ #include "chrome/browser/ui/webui/signin/user_manager_screen_handler.h" #include <stddef.h> +#include <utility> #include "base/bind.h" #include "base/location.h" @@ -25,6 +26,7 @@ #include "chrome/browser/profiles/profile_info_cache_observer.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/profiles/profile_metrics.h" +#include "chrome/browser/profiles/profile_statistics.h" #include "chrome/browser/profiles/profile_window.h" #include "chrome/browser/profiles/profiles_state.h" #include "chrome/browser/signin/local_auth.h" @@ -75,6 +77,7 @@ const char kKeyAvatarUrl[] = "userImage"; const char kKeyNeedsSignin[] = "needsSignin"; const char kKeyHasLocalCreds[] = "hasLocalCreds"; +const char kKeyStatistics[] = "statistics"; const char kKeyIsProfileLoaded[] = "isProfileLoaded"; // JS API callback names. @@ -585,7 +588,32 @@ if (!profile) return; - profiles::GetProfileStatistics( + if (!chrome::FindAnyBrowser(profile, true, desktop_type_)) { + // If no windows are open for that profile, the statistics in + // ProfileInfoCache are up to date. The statistics in ProfileInfoCache are + // returned because the copy in user_pod_row.js may be outdated. However, if + // some statistics are missing in ProfileInfoCache (i.e. |item.success| is + // false), then the actual statistics are queried instead. + base::DictionaryValue return_value; + profiles::ProfileCategoryStats stats = + profiles::GetProfileStatisticsFromCache(profile_path); + bool stats_success = true; + for (const auto& item : stats) { + scoped_ptr<base::DictionaryValue> stat(new base::DictionaryValue); + stat->SetIntegerWithoutPathExpansion("count", item.count); + stat->SetBooleanWithoutPathExpansion("success", item.success); + return_value.SetWithoutPathExpansion(item.category, std::move(stat)); + stats_success &= item.success; + } + if (stats_success) { + web_ui()->CallJavascriptFunction("updateRemoveWarningDialog", + base::StringValue(profile_path.value()), + return_value); + return; + } + } + + profiles::GatherProfileStatistics( profile, base::Bind( &UserManagerScreenHandler::RemoveUserDialogLoadStatsCallback, @@ -597,16 +625,16 @@ base::FilePath profile_path, profiles::ProfileCategoryStats result) { // Copy result into return_value. - base::StringValue return_profile_path(profile_path.value()); base::DictionaryValue return_value; for (const auto& item : result) { - base::DictionaryValue* stat = new base::DictionaryValue(); + scoped_ptr<base::DictionaryValue> stat(new base::DictionaryValue); stat->SetIntegerWithoutPathExpansion("count", item.count); stat->SetBooleanWithoutPathExpansion("success", item.success); - return_value.SetWithoutPathExpansion(item.category, stat); + return_value.SetWithoutPathExpansion(item.category, std::move(stat)); } web_ui()->CallJavascriptFunction("updateRemoveWarningDialog", - return_profile_path, return_value); + base::StringValue(profile_path.value()), + return_value); } void UserManagerScreenHandler::HandleGetRemoveWarningDialogMessage( @@ -879,6 +907,18 @@ profile_value->SetString( kKeyAvatarUrl, GetAvatarImageAtIndex(i, info_cache)); + profiles::ProfileCategoryStats stats = + profiles::GetProfileStatisticsFromCache(profile_path); + scoped_ptr<base::DictionaryValue> stats_dict(new base::DictionaryValue); + for (const auto& item : stats) { + scoped_ptr<base::DictionaryValue> stat(new base::DictionaryValue); + stat->SetIntegerWithoutPathExpansion("count", item.count); + stat->SetBooleanWithoutPathExpansion("success", item.success); + stats_dict->SetWithoutPathExpansion(item.category, std::move(stat)); + } + profile_value->SetWithoutPathExpansion(kKeyStatistics, + std::move(stats_dict)); + // GetProfileByPath returns a pointer if the profile is fully loaded, NULL // otherwise. Profile* profile =
diff --git a/chrome/browser/usb/usb_chooser_bubble_delegate.cc b/chrome/browser/usb/usb_chooser_bubble_delegate.cc index 0bf4eda..f8f817c 100644 --- a/chrome/browser/usb/usb_chooser_bubble_delegate.cc +++ b/chrome/browser/usb/usb_chooser_bubble_delegate.cc
@@ -77,34 +77,32 @@ callback_.Run(nullptr); } -const std::vector<base::string16>& UsbChooserBubbleDelegate::GetOptions() - const { - return devices_names_; +size_t UsbChooserBubbleDelegate::NumOptions() const { + return devices_.size(); } -void UsbChooserBubbleDelegate::Select(int index) { - size_t idx = static_cast<size_t>(index); - size_t num_options = devices_.size(); - DCHECK_LT(idx, num_options); - if (idx < num_options) { - content::WebContents* web_contents = - content::WebContents::FromRenderFrameHost(render_frame_host_); - GURL embedding_origin = - web_contents->GetMainFrame()->GetLastCommittedURL().GetOrigin(); - Profile* profile = - Profile::FromBrowserContext(web_contents->GetBrowserContext()); - UsbChooserContext* chooser_context = - UsbChooserContextFactory::GetForProfile(profile); - chooser_context->GrantDevicePermission( - render_frame_host_->GetLastCommittedURL().GetOrigin(), embedding_origin, - devices_[idx]->guid()); +const base::string16& UsbChooserBubbleDelegate::GetOption(size_t index) const { + DCHECK_LT(index, devices_.size()); + return devices_[index].second; +} - device::usb::DeviceInfoPtr device_info_ptr = - device::usb::DeviceInfo::From(*devices_[idx]); - callback_.Run(std::move(device_info_ptr)); - } else { - callback_.Run(nullptr); - } +void UsbChooserBubbleDelegate::Select(size_t index) { + DCHECK_LT(index, devices_.size()); + content::WebContents* web_contents = + content::WebContents::FromRenderFrameHost(render_frame_host_); + GURL embedding_origin = + web_contents->GetMainFrame()->GetLastCommittedURL().GetOrigin(); + Profile* profile = + Profile::FromBrowserContext(web_contents->GetBrowserContext()); + UsbChooserContext* chooser_context = + UsbChooserContextFactory::GetForProfile(profile); + chooser_context->GrantDevicePermission( + render_frame_host_->GetLastCommittedURL().GetOrigin(), embedding_origin, + devices_[index].first->guid()); + + device::usb::DeviceInfoPtr device_info_ptr = + device::usb::DeviceInfo::From(*devices_[index].first); + callback_.Run(std::move(device_info_ptr)); callback_.reset(); // Reset |callback_| so that it is only run once. if (bubble_controller_) @@ -120,27 +118,26 @@ void UsbChooserBubbleDelegate::OnDeviceAdded( scoped_refptr<device::UsbDevice> device) { - DCHECK(!ContainsValue(devices_, device)); if (device::UsbDeviceFilter::MatchesAny(device, filters_) && FindOriginInDescriptorSet( device->webusb_allowed_origins(), render_frame_host_->GetLastCommittedURL().GetOrigin())) { - devices_.push_back(device); - devices_names_.push_back(device->product_string()); + devices_.push_back(std::make_pair(device, device->product_string())); if (observer()) - observer()->OnOptionAdded(static_cast<int>(devices_names_.size()) - 1); + observer()->OnOptionAdded(devices_.size() - 1); } } void UsbChooserBubbleDelegate::OnDeviceRemoved( scoped_refptr<device::UsbDevice> device) { - auto iter = std::find(devices_.begin(), devices_.end(), device); - if (iter != devices_.end()) { - int index = iter - devices_.begin(); - devices_.erase(iter); - devices_names_.erase(devices_names_.begin() + index); - if (observer()) - observer()->OnOptionRemoved(index); + for (auto it = devices_.begin(); it != devices_.end(); ++it) { + if (it->first == device) { + size_t index = it - devices_.begin(); + devices_.erase(it); + if (observer()) + observer()->OnOptionRemoved(index); + return; + } } } @@ -153,8 +150,7 @@ FindOriginInDescriptorSet( device->webusb_allowed_origins(), render_frame_host_->GetLastCommittedURL().GetOrigin())) { - devices_.push_back(device); - devices_names_.push_back(device->product_string()); + devices_.push_back(std::make_pair(device, device->product_string())); } } if (observer())
diff --git a/chrome/browser/usb/usb_chooser_bubble_delegate.h b/chrome/browser/usb/usb_chooser_bubble_delegate.h index 6d471341..af4526b1 100644 --- a/chrome/browser/usb/usb_chooser_bubble_delegate.h +++ b/chrome/browser/usb/usb_chooser_bubble_delegate.h
@@ -5,6 +5,8 @@ #ifndef CHROME_BROWSER_USB_USB_CHOOSER_BUBBLE_DELEGATE_H_ #define CHROME_BROWSER_USB_USB_CHOOSER_BUBBLE_DELEGATE_H_ +#include <utility> + #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" @@ -38,8 +40,9 @@ ~UsbChooserBubbleDelegate() override; // ChooserBubbleDelegate: - const std::vector<base::string16>& GetOptions() const override; - void Select(int index) override; + size_t NumOptions() const override; + const base::string16& GetOption(size_t index) const override; + void Select(size_t index) override; void Cancel() override; void Close() override; @@ -58,8 +61,9 @@ ScopedObserver<device::UsbService, device::UsbService::Observer> usb_service_observer_; std::vector<device::UsbDeviceFilter> filters_; - std::vector<scoped_refptr<device::UsbDevice>> devices_; - std::vector<base::string16> devices_names_; + // Each pair is a (device, device name). + std::vector<std::pair<scoped_refptr<device::UsbDevice>, base::string16>> + devices_; BubbleReference bubble_controller_; base::WeakPtrFactory<UsbChooserBubbleDelegate> weak_factory_;
diff --git a/chrome/browser/usb/usb_chooser_context.cc b/chrome/browser/usb/usb_chooser_context.cc index fc940c9a..702c98a 100644 --- a/chrome/browser/usb/usb_chooser_context.cc +++ b/chrome/browser/usb/usb_chooser_context.cc
@@ -100,9 +100,9 @@ base::DictionaryValue object; object.SetString(kDeviceNameKey, device->product_string()); object.SetString(kGuidKey, device->guid()); - objects.push_back(make_scoped_ptr( - new ChooserContextBase::Object(requesting_origin, embedding_origin, - &object, "", is_off_the_record_))); + objects.push_back(make_scoped_ptr(new ChooserContextBase::Object( + requesting_origin, embedding_origin, &object, "preference", + is_off_the_record_))); } }
diff --git a/chrome/browser/web_applications/OWNERS b/chrome/browser/web_applications/OWNERS index ce77cd1..f75720b4 100644 --- a/chrome/browser/web_applications/OWNERS +++ b/chrome/browser/web_applications/OWNERS
@@ -3,6 +3,3 @@ # Windows calamity@chromium.org - -# Mac -jackhou@chromium.org
diff --git a/chrome/browser/web_applications/web_app.cc b/chrome/browser/web_applications/web_app.cc index 2836f53..1aec9ac 100644 --- a/chrome/browser/web_applications/web_app.cc +++ b/chrome/browser/web_applications/web_app.cc
@@ -87,14 +87,19 @@ void UpdateAllShortcutsForShortcutInfo( const base::string16& old_app_title, + const base::Closure& callback, scoped_ptr<web_app::ShortcutInfo> shortcut_info, const extensions::FileHandlersInfo& file_handlers_info) { base::FilePath shortcut_data_dir = GetShortcutDataDir(*shortcut_info); - BrowserThread::PostTask( - BrowserThread::FILE, FROM_HERE, - base::Bind(&web_app::internals::UpdatePlatformShortcuts, - shortcut_data_dir, old_app_title, base::Passed(&shortcut_info), - file_handlers_info)); + base::Closure task = base::Bind( + &web_app::internals::UpdatePlatformShortcuts, shortcut_data_dir, + old_app_title, base::Passed(&shortcut_info), file_handlers_info); + if (callback.is_null()) { + BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, task); + } else { + BrowserThread::PostTaskAndReply(BrowserThread::FILE, FROM_HERE, task, + callback); + } } void OnImageLoaded(scoped_ptr<web_app::ShortcutInfo> shortcut_info, @@ -450,12 +455,12 @@ void UpdateAllShortcuts(const base::string16& old_app_title, Profile* profile, - const extensions::Extension* app) { + const extensions::Extension* app, + const base::Closure& callback) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - GetInfoForApp(app, - profile, - base::Bind(&UpdateAllShortcutsForShortcutInfo, old_app_title)); + GetInfoForApp(app, profile, base::Bind(&UpdateAllShortcutsForShortcutInfo, + old_app_title, callback)); } bool IsValidUrl(const GURL& url) {
diff --git a/chrome/browser/web_applications/web_app.h b/chrome/browser/web_applications/web_app.h index 0781349..6a4ccb0 100644 --- a/chrome/browser/web_applications/web_app.h +++ b/chrome/browser/web_applications/web_app.h
@@ -202,12 +202,15 @@ // extension. void DeleteAllShortcuts(Profile* profile, const extensions::Extension* app); -// Updates shortcuts for web application based on given shortcut data. This -// refreshes existing shortcuts and their icons, but does not create new ones. +// Updates shortcuts for |app|, but does not create new ones if shortcuts are +// not present in user-facing locations. Some platforms may still (re)create +// hidden shortcuts to interact correctly with the system shelf. // |old_app_title| contains the title of the app prior to this update. +// |callback| is invoked once the FILE thread tasks have completed. void UpdateAllShortcuts(const base::string16& old_app_title, Profile* profile, - const extensions::Extension* app); + const extensions::Extension* app, + const base::Closure& callback); // Updates shortcuts for all apps in this profile. This is expected to be called // on the UI thread.
diff --git a/chrome/browser/web_applications/web_app_mac.mm b/chrome/browser/web_applications/web_app_mac.mm index a5d4674..2caee90 100644 --- a/chrome/browser/web_applications/web_app_mac.mm +++ b/chrome/browser/web_applications/web_app_mac.mm
@@ -18,6 +18,7 @@ #include "base/mac/scoped_cftyperef.h" #include "base/mac/scoped_nsobject.h" #include "base/macros.h" +#include "base/memory/ref_counted.h" #include "base/metrics/sparse_histogram.h" #include "base/path_service.h" #include "base/process/process_handle.h" @@ -63,6 +64,34 @@ // Launch Services Key to run as an agent app, which doesn't launch in the dock. NSString* const kLSUIElement = @"LSUIElement"; +// Class that invokes a provided |callback| when destroyed, and supplies a means +// to keep the instance alive via posted tasks. The provided |callback| will +// always be invoked on the UI thread. +class Latch : public base::RefCountedThreadSafe< + Latch, + content::BrowserThread::DeleteOnUIThread> { + public: + explicit Latch(const base::Closure& callback) : callback_(callback) {} + + // Wraps a reference to |this| in a Closure and returns it. Running the + // Closure does nothing. The Closure just serves to keep a reference alive + // until |this| is ready to be destroyed; invoking the |callback|. + base::Closure NoOpClosure() { return base::Bind(&Latch::NoOp, this); } + + private: + friend class base::RefCountedThreadSafe<Latch>; + friend class base::DeleteHelper<Latch>; + friend struct content::BrowserThread::DeleteOnThread< + content::BrowserThread::UI>; + + ~Latch() { callback_.Run(); } + void NoOp() {} + + base::Closure callback_; + + DISALLOW_COPY_AND_ASSIGN(Latch); +}; + class ScopedCarbonHandle { public: ScopedCarbonHandle(size_t initial_size) : handle_(NewHandle(initial_size)) { @@ -807,22 +836,31 @@ std::vector<base::FilePath> paths; paths.push_back(app_data_dir_); - // Try to update the copy under /Applications. If that does not exist, check + // Try to update the copy under ~/Applications. If that does not exist, check // if a matching bundle can be found elsewhere. base::FilePath app_path = GetApplicationsShortcutPath(); - if (app_path.empty() || !base::PathExists(app_path)) - app_path = GetAppBundleById(GetBundleIdentifier()); - if (app_path.empty()) { - if (info_->from_bookmark) { - // The bookmark app shortcut has been deleted by the user. Restore it, as - // the Mac UI for bookmark apps creates the expectation that the app will - // be added to Applications. - app_path = GetApplicationsDirname(); - paths.push_back(app_path); + // Never look in ~/Applications or search the system for a bundle ID in a test + // since that relies on global system state and potentially cruft that may be + // leftover from prior/crashed test runs. + // TODO(tapted): Remove this check when tests that arrive here via setting + // |g_app_shims_allow_update_and_launch_in_tests| can properly mock out all + // the calls below. + if (!g_app_shims_allow_update_and_launch_in_tests) { + if (app_path.empty() || !base::PathExists(app_path)) + app_path = GetAppBundleById(GetBundleIdentifier()); + + if (app_path.empty()) { + if (info_->from_bookmark) { + // The bookmark app shortcut has been deleted by the user. Restore it, + // as the Mac UI for bookmark apps creates the expectation that the app + // will be added to Applications. + app_path = GetApplicationsDirname(); + paths.push_back(app_path); + } + } else { + paths.push_back(app_path.DirName()); } - } else { - paths.push_back(app_path.DirName()); } size_t success_count = CreateShortcutsIn(paths); @@ -1138,18 +1176,19 @@ if (!registry) return; + scoped_refptr<Latch> latch = new Latch(callback); + // Update all apps. - scoped_ptr<extensions::ExtensionSet> everything = + scoped_ptr<extensions::ExtensionSet> candidates = registry->GenerateInstalledExtensionsSet(); - for (extensions::ExtensionSet::const_iterator it = everything->begin(); - it != everything->end(); ++it) { + for (auto& extension_refptr : *candidates) { + const extensions::Extension* extension = extension_refptr.get(); if (web_app::ShouldCreateShortcutFor(SHORTCUT_CREATION_AUTOMATED, profile, - it->get())) { - web_app::UpdateAllShortcuts(base::string16(), profile, it->get()); + extension)) { + web_app::UpdateAllShortcuts(base::string16(), profile, extension, + latch->NoOpClosure()); } } - - callback.Run(); } void RevealAppShimInFinderForApp(Profile* profile,
diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp index 971ee9f..d8c21a9b 100644 --- a/chrome/chrome.gyp +++ b/chrome/chrome.gyp
@@ -567,6 +567,7 @@ '../components/components.gyp:signin_core_browser_java', '../components/components.gyp:variations_java', '../components/components.gyp:web_contents_delegate_android_java', + '../components/components.gyp:web_restriction_java', '../components/components_strings.gyp:components_strings', '../content/content.gyp:content_java', '../media/media.gyp:media_java',
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 28d3d88..c4027513 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi
@@ -77,6 +77,8 @@ 'browser/browsing_data/browsing_data_cookie_helper.h', 'browser/browsing_data/browsing_data_counter.cc', 'browser/browsing_data/browsing_data_counter.h', + 'browser/browsing_data/browsing_data_counter_utils.cc', + 'browser/browsing_data/browsing_data_counter_utils.h', 'browser/browsing_data/browsing_data_database_helper.cc', 'browser/browsing_data/browsing_data_database_helper.h', 'browser/browsing_data/browsing_data_file_system_helper.cc', @@ -398,6 +400,8 @@ 'browser/ntp_snippets/ntp_snippets_service_factory.h', 'browser/page_load_metrics/observers/aborts_page_load_metrics_observer.cc', 'browser/page_load_metrics/observers/aborts_page_load_metrics_observer.h', + 'browser/page_load_metrics/observers/core_page_load_metrics_observer.cc', + 'browser/page_load_metrics/observers/core_page_load_metrics_observer.h', 'browser/page_load_metrics/observers/from_gws_page_load_metrics_observer.cc', 'browser/page_load_metrics/observers/from_gws_page_load_metrics_observer.h', 'browser/page_load_metrics/observers/google_captcha_observer.cc', @@ -1897,6 +1901,7 @@ 'android/java/src/org/chromium/chrome/browser/signin/SigninManager.java', 'android/java/src/org/chromium/chrome/browser/snackbar/smartlockautosignin/AutoSigninSnackbarController.java', 'android/java/src/org/chromium/chrome/browser/spellchecker/SpellCheckerSessionBridge.java', + 'android/java/src/org/chromium/chrome/browser/superviseduser/SupervisedUserContentProvider.java', 'android/java/src/org/chromium/chrome/browser/sync/ProfileSyncService.java', 'android/java/src/org/chromium/chrome/browser/tab/Tab.java', 'android/java/src/org/chromium/chrome/browser/tab/TabWebContentsDelegateAndroid.java', @@ -1928,14 +1933,10 @@ 'android/java/src/org/chromium/chrome/browser/webapps/WebappRegistry.java', ], 'chrome_browser_mdns_sources': [ - 'browser/local_discovery/privet_traffic_detector.cc', - 'browser/local_discovery/privet_traffic_detector.h', 'browser/local_discovery/service_discovery_client_mdns.cc', 'browser/local_discovery/service_discovery_client_mdns.h', - 'browser/local_discovery/service_discovery_client_utility.cc', - 'browser/local_discovery/service_discovery_client_utility.h', - 'browser/local_discovery/service_discovery_host_client.cc', - 'browser/local_discovery/service_discovery_host_client.h', + 'browser/printing/cloud_print/privet_traffic_detector.cc', + 'browser/printing/cloud_print/privet_traffic_detector.h', ], 'chrome_browser_metrics_sources': [ 'browser/metrics/chrome_browser_main_extra_parts_metrics.cc', @@ -2388,8 +2389,6 @@ ], # Used on top of the "basic" sources when enable_print_preview==1. 'chrome_browser_printing_full_sources': [ - 'browser/local_discovery/pwg_raster_converter.cc', - 'browser/local_discovery/pwg_raster_converter.h', 'browser/printing/background_printing_manager.cc', 'browser/printing/background_printing_manager.h', 'browser/printing/cloud_print/cloud_print_proxy_service.cc', @@ -2417,6 +2416,8 @@ 'browser/printing/printer_manager_dialog_linux.cc', 'browser/printing/printer_manager_dialog_mac.mm', 'browser/printing/printer_manager_dialog_win.cc', + 'browser/printing/pwg_raster_converter.cc', + 'browser/printing/pwg_raster_converter.h', 'browser/service_process/service_process_control.cc', 'browser/service_process/service_process_control.h', 'browser/service_process/service_process_control_mac.mm', @@ -2655,46 +2656,8 @@ 'browser/search_engines/template_url_service_android.h', ], 'chrome_browser_service_discovery_sources': [ - 'browser/local_discovery/cloud_device_list.cc', - 'browser/local_discovery/cloud_device_list.h', - 'browser/local_discovery/cloud_device_list_delegate.cc', - 'browser/local_discovery/cloud_device_list_delegate.h', - 'browser/local_discovery/cloud_print_printer_list.cc', - 'browser/local_discovery/cloud_print_printer_list.h', - 'browser/local_discovery/device_description.cc', - 'browser/local_discovery/device_description.h', 'browser/local_discovery/endpoint_resolver.cc', 'browser/local_discovery/endpoint_resolver.h', - 'browser/local_discovery/gcd_api_flow.cc', - 'browser/local_discovery/gcd_api_flow.h', - 'browser/local_discovery/gcd_api_flow_impl.cc', - 'browser/local_discovery/gcd_api_flow_impl.h', - 'browser/local_discovery/gcd_constants.cc', - 'browser/local_discovery/gcd_constants.h', - 'browser/local_discovery/privet_confirm_api_flow.cc', - 'browser/local_discovery/privet_confirm_api_flow.h', - 'browser/local_discovery/privet_constants.cc', - 'browser/local_discovery/privet_constants.h', - 'browser/local_discovery/privet_device_lister.cc', - 'browser/local_discovery/privet_device_lister.h', - 'browser/local_discovery/privet_device_lister_impl.cc', - 'browser/local_discovery/privet_device_lister_impl.h', - 'browser/local_discovery/privet_http.cc', - 'browser/local_discovery/privet_http.h', - 'browser/local_discovery/privet_http_asynchronous_factory.cc', - 'browser/local_discovery/privet_http_asynchronous_factory.h', - 'browser/local_discovery/privet_http_asynchronous_factory_impl.cc', - 'browser/local_discovery/privet_http_asynchronous_factory_impl.h', - 'browser/local_discovery/privet_http_impl.cc', - 'browser/local_discovery/privet_http_impl.h', - 'browser/local_discovery/privet_local_printer_lister.cc', - 'browser/local_discovery/privet_local_printer_lister.h', - 'browser/local_discovery/privet_notifications.cc', - 'browser/local_discovery/privet_notifications.h', - 'browser/local_discovery/privet_notifications_factory.cc', - 'browser/local_discovery/privet_notifications_factory.h', - 'browser/local_discovery/privet_url_fetcher.cc', - 'browser/local_discovery/privet_url_fetcher.h', 'browser/local_discovery/service_discovery_client_mac.h', 'browser/local_discovery/service_discovery_client_mac.mm', 'browser/local_discovery/service_discovery_client_mac_factory.h', @@ -2703,6 +2666,40 @@ 'browser/local_discovery/service_discovery_device_lister.h', 'browser/local_discovery/service_discovery_shared_client.cc', 'browser/local_discovery/service_discovery_shared_client.h', + 'browser/printing/cloud_print/cloud_print_printer_list.cc', + 'browser/printing/cloud_print/cloud_print_printer_list.h', + 'browser/printing/cloud_print/device_description.cc', + 'browser/printing/cloud_print/device_description.h', + 'browser/printing/cloud_print/gcd_api_flow.cc', + 'browser/printing/cloud_print/gcd_api_flow.h', + 'browser/printing/cloud_print/gcd_api_flow_impl.cc', + 'browser/printing/cloud_print/gcd_api_flow_impl.h', + 'browser/printing/cloud_print/gcd_constants.cc', + 'browser/printing/cloud_print/gcd_constants.h', + 'browser/printing/cloud_print/privet_confirm_api_flow.cc', + 'browser/printing/cloud_print/privet_confirm_api_flow.h', + 'browser/printing/cloud_print/privet_constants.cc', + 'browser/printing/cloud_print/privet_constants.h', + 'browser/printing/cloud_print/privet_device_lister.cc', + 'browser/printing/cloud_print/privet_device_lister.h', + 'browser/printing/cloud_print/privet_device_lister_impl.cc', + 'browser/printing/cloud_print/privet_device_lister_impl.h', + 'browser/printing/cloud_print/privet_http.cc', + 'browser/printing/cloud_print/privet_http.h', + 'browser/printing/cloud_print/privet_http_asynchronous_factory.cc', + 'browser/printing/cloud_print/privet_http_asynchronous_factory.h', + 'browser/printing/cloud_print/privet_http_asynchronous_factory_impl.cc', + 'browser/printing/cloud_print/privet_http_asynchronous_factory_impl.h', + 'browser/printing/cloud_print/privet_http_impl.cc', + 'browser/printing/cloud_print/privet_http_impl.h', + 'browser/printing/cloud_print/privet_local_printer_lister.cc', + 'browser/printing/cloud_print/privet_local_printer_lister.h', + 'browser/printing/cloud_print/privet_notifications.cc', + 'browser/printing/cloud_print/privet_notifications.h', + 'browser/printing/cloud_print/privet_notifications_factory.cc', + 'browser/printing/cloud_print/privet_notifications_factory.h', + 'browser/printing/cloud_print/privet_url_fetcher.cc', + 'browser/printing/cloud_print/privet_url_fetcher.h', ], 'chrome_browser_services_sources': [ 'browser/services/gcm/gcm_profile_service_factory.cc', @@ -2862,6 +2859,8 @@ 'browser/supervised_user/supervised_user_bookmarks_handler.h', 'browser/supervised_user/supervised_user_constants.cc', 'browser/supervised_user/supervised_user_constants.h', + 'browser/supervised_user/supervised_user_content_provider_android.cc', + 'browser/supervised_user/supervised_user_content_provider_android.h', 'browser/supervised_user/supervised_user_interstitial.cc', 'browser/supervised_user/supervised_user_interstitial.h', 'browser/supervised_user/supervised_user_navigation_observer.cc',
diff --git a/chrome/chrome_browser_extensions.gypi b/chrome/chrome_browser_extensions.gypi index 7a790eb..a9bbd5b 100644 --- a/chrome/chrome_browser_extensions.gypi +++ b/chrome/chrome_browser_extensions.gypi
@@ -70,15 +70,13 @@ 'browser/extensions/api/messaging/native_process_launcher_posix.cc', 'browser/extensions/api/messaging/native_process_launcher_win.cc', ], - 'chrome_browser_extensions_non_android_sources': [ + 'chrome_browser_extensions_service_discovery_sources': [ 'browser/extensions/api/gcd_private/gcd_private_api.cc', 'browser/extensions/api/gcd_private/gcd_private_api.h', 'browser/extensions/api/gcd_private/privet_v3_context_getter.cc', 'browser/extensions/api/gcd_private/privet_v3_context_getter.h', 'browser/extensions/api/gcd_private/privet_v3_session.cc', 'browser/extensions/api/gcd_private/privet_v3_session.h', - 'browser/extensions/api/launcher_page/launcher_page_api.cc', - 'browser/extensions/api/launcher_page/launcher_page_api.h', 'browser/extensions/api/mdns/dns_sd_delegate.cc', 'browser/extensions/api/mdns/dns_sd_delegate.h', 'browser/extensions/api/mdns/dns_sd_device_lister.cc', @@ -362,6 +360,8 @@ 'browser/extensions/api/language_settings_private/language_settings_private_delegate.h', 'browser/extensions/api/language_settings_private/language_settings_private_delegate_factory.cc', 'browser/extensions/api/language_settings_private/language_settings_private_delegate_factory.h', + 'browser/extensions/api/launcher_page/launcher_page_api.cc', + 'browser/extensions/api/launcher_page/launcher_page_api.h', 'browser/extensions/api/location/location_api.cc', 'browser/extensions/api/location/location_api.h', 'browser/extensions/api/location/location_manager.cc', @@ -686,6 +686,8 @@ 'browser/extensions/extension_icon_manager.h', 'browser/extensions/extension_install_checker.cc', 'browser/extensions/extension_install_checker.h', + 'browser/extensions/extension_install_error_menu_item_id_provider.h', + 'browser/extensions/extension_install_error_menu_item_id_provider.cc', 'browser/extensions/extension_install_prompt.cc', 'browser/extensions/extension_install_prompt.h', 'browser/extensions/extension_install_prompt_show_params.cc', @@ -1038,9 +1040,9 @@ '<@(chrome_browser_extensions_non_chromeos_sources)', ], }], - ['OS!="android"', { + ['enable_service_discovery==1', { 'sources': [ - '<@(chrome_browser_extensions_non_android_sources)', + '<@(chrome_browser_extensions_service_discovery_sources)', ], }], ['use_ash==1', {
diff --git a/chrome/chrome_browser_ui.gypi b/chrome/chrome_browser_ui.gypi index 1bb44e1..bb04718 100644 --- a/chrome/chrome_browser_ui.gypi +++ b/chrome/chrome_browser_ui.gypi
@@ -651,14 +651,6 @@ 'browser/ui/views/frame/web_app_left_header_view_ash.cc', 'browser/ui/views/frame/web_app_left_header_view_ash.h', 'browser/ui/views/tabs/window_finder_ash.cc', - 'browser/ui/views/tabs/window_finder_impl.cc', - 'browser/ui/views/tabs/window_finder_impl.h', - ], - # Used when Android + Views. - 'chrome_browser_ui_views_android_sources': [ - 'browser/ui/views/tabs/window_finder_android.cc', - 'browser/ui/views/tabs/window_finder_impl.cc', - 'browser/ui/views/tabs/window_finder_impl.h', ], # Used when ash is disabled. 'chrome_browser_ui_non_ash_sources': [ @@ -2248,7 +2240,6 @@ 'browser/ui/views/frame/browser_frame_mac.mm', 'browser/ui/views/frame/browser_non_client_frame_view.cc', 'browser/ui/views/frame/browser_non_client_frame_view.h', - 'browser/ui/views/frame/browser_non_client_frame_view_factory_android.cc', 'browser/ui/views/frame/browser_non_client_frame_view_factory_mac.mm', 'browser/ui/views/frame/browser_non_client_frame_view_factory_views.cc', 'browser/ui/views/frame/browser_non_client_frame_view_mac.h', @@ -2271,7 +2262,6 @@ 'browser/ui/views/frame/contents_web_view.h', 'browser/ui/views/frame/immersive_mode_controller.cc', 'browser/ui/views/frame/immersive_mode_controller.h', - 'browser/ui/views/frame/immersive_mode_controller_factory_android.cc', 'browser/ui/views/frame/immersive_mode_controller_factory_mac.cc', 'browser/ui/views/frame/immersive_mode_controller_factory_views.cc', 'browser/ui/views/frame/immersive_mode_controller_stub.cc', @@ -2774,8 +2764,10 @@ 'browser/ui/hung_plugin_tab_helper.h', 'browser/ui/webui/flash_ui.cc', 'browser/ui/webui/flash_ui.h', - 'browser/ui/webui/plugins_ui.cc', - 'browser/ui/webui/plugins_ui.h', + 'browser/ui/webui/plugins/plugins_handler.cc', + 'browser/ui/webui/plugins/plugins_handler.h', + 'browser/ui/webui/plugins/plugins_ui.cc', + 'browser/ui/webui/plugins/plugins_ui.h', ], 'chrome_browser_ui_policy_sources': [ 'browser/ui/webui/policy_material_design_ui.cc', @@ -3040,9 +3032,6 @@ }], ], }], - ['OS=="android"', { - 'sources': [ '<@(chrome_browser_ui_views_android_sources)' ], - }], ['enable_extensions==1', { 'dependencies': [ '<(DEPTH)/extensions/components/extensions_components.gyp:native_app_window',
diff --git a/chrome/chrome_common.gypi b/chrome/chrome_common.gypi index 989a6ae..cbf6331e 100644 --- a/chrome/chrome_common.gypi +++ b/chrome/chrome_common.gypi
@@ -516,11 +516,6 @@ '<(DEPTH)/components/components.gyp:dom_distiller_core', # Needed by chrome_content_client.cc. ], }], - ['enable_mdns == 1', { - 'sources': [ - 'common/local_discovery/local_discovery_messages.h', - ] - }], ['OS=="mac"', { 'dependencies': [ '../third_party/google_toolbox_for_mac/google_toolbox_for_mac.gyp:google_toolbox_for_mac',
diff --git a/chrome/chrome_debugger.gypi b/chrome/chrome_debugger.gypi index fd98495..42c10680 100644 --- a/chrome/chrome_debugger.gypi +++ b/chrome/chrome_debugger.gypi
@@ -13,7 +13,6 @@ '../base/base.gyp:base', '../content/content.gyp:content_browser', '../net/net.gyp:net', - 'browser/devtools/webrtc_device_provider_resources.gyp:webrtc_device_provider_resources', 'browser/devtools/devtools_protocol_constants.gyp:devtools_protocol_constants', 'chrome_features.gyp:chrome_common_features', ], @@ -62,14 +61,10 @@ 'common/extensions/api/api.gyp:chrome_api', ], 'sources': [ - '<(SHARED_INTERMEDIATE_DIR)/chrome/grit/webrtc_device_provider_resources_map.cc', - '<(SHARED_INTERMEDIATE_DIR)/chrome/grit/webrtc_device_provider_resources_map.h', 'browser/devtools/chrome_devtools_discovery_provider.cc', 'browser/devtools/chrome_devtools_discovery_provider.h', 'browser/devtools/device/adb/adb_client_socket.cc', 'browser/devtools/device/adb/adb_client_socket.h', - 'browser/devtools/device/cast_device_provider.cc', - 'browser/devtools/device/cast_device_provider.h', 'browser/devtools/device/adb/adb_device_provider.cc', 'browser/devtools/device/adb/adb_device_provider.h', 'browser/devtools/device/android_device_info_query.cc', @@ -90,14 +85,6 @@ 'browser/devtools/device/usb/android_usb_socket.h', 'browser/devtools/device/usb/usb_device_provider.cc', 'browser/devtools/device/usb/usb_device_provider.h', - 'browser/devtools/device/webrtc/devtools_bridge_client.cc', - 'browser/devtools/device/webrtc/devtools_bridge_client.h', - 'browser/devtools/device/webrtc/devtools_bridge_instances_request.cc', - 'browser/devtools/device/webrtc/devtools_bridge_instances_request.h', - 'browser/devtools/device/webrtc/send_command_request.cc', - 'browser/devtools/device/webrtc/send_command_request.h', - 'browser/devtools/device/webrtc/webrtc_device_provider.cc', - 'browser/devtools/device/webrtc/webrtc_device_provider.h', 'browser/devtools/devtools_contents_resizing_strategy.cc', 'browser/devtools/devtools_contents_resizing_strategy.h', 'browser/devtools/devtools_embedder_message_dispatcher.cc', @@ -123,6 +110,15 @@ 'browser/devtools/remote_debugging_server.cc', 'browser/devtools/remote_debugging_server.h', ], + 'conditions': [ + ['enable_service_discovery==1', { + 'sources': [ + 'browser/devtools/device/cast_device_provider.cc', + 'browser/devtools/device/cast_device_provider.h', + ], + }], + ], + }], # OS!="android" ['debug_devtools==1', { 'defines': [
diff --git a/chrome/chrome_dll.gypi b/chrome/chrome_dll.gypi index c873e52..b6e7634b 100644 --- a/chrome/chrome_dll.gypi +++ b/chrome/chrome_dll.gypi
@@ -116,8 +116,6 @@ 'app/chrome_main_delegate.h', 'app/chrome_main_mac.h', 'app/chrome_main_mac.mm', - 'app/close_handle_hook_win.cc', - 'app/close_handle_hook_win.h', 'app/delay_load_hook_win.cc', 'app/delay_load_hook_win.h', ], @@ -364,8 +362,6 @@ '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', ], 'conditions': [ ['OS=="win" and win_use_allocator_shim==1', {
diff --git a/chrome/chrome_exe.gypi b/chrome/chrome_exe.gypi index 07f2a78..4cec0e7a 100644 --- a/chrome/chrome_exe.gypi +++ b/chrome/chrome_exe.gypi
@@ -75,8 +75,6 @@ 'app/kasko_client.h', 'app/main_dll_loader_win.cc', 'app/main_dll_loader_win.h', - 'app/signature_validator_win.cc', - 'app/signature_validator_win.h', ], 'mac_bundle_resources': [ 'app/app-Info.plist', @@ -459,10 +457,6 @@ 'ole32.dll', 'oleaut32.dll', ], - 'AdditionalDependencies': [ - 'wintrust.lib', - 'crypt32.lib' - ], 'conditions': [ ['win_console_app==0', { # Set /SUBSYSTEM:WINDOWS for chrome.exe itself, unless a
diff --git a/chrome/chrome_features.gypi b/chrome/chrome_features.gypi index 1042f41..b78a4dae 100644 --- a/chrome/chrome_features.gypi +++ b/chrome/chrome_features.gypi
@@ -1,7 +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. - + # This is the GYP equivalent of //chrome/common/features.gni. # Please keep in sync! @@ -38,6 +38,6 @@ 'chrome_grit_defines': [ '-D', 'enable_google_now=<(enable_google_now)', '-D', 'use_vulcanize=<(use_vulcanize)', - ] + ], }, }
diff --git a/chrome/chrome_grit_action.gypi b/chrome/chrome_grit_action.gypi new file mode 100644 index 0000000..9169aa0 --- /dev/null +++ b/chrome/chrome_grit_action.gypi
@@ -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. + +{ + 'variables': { + # Wrapper around build/grit_action.gypi that applies Chrome-specific grit + # settings. Actions that include this gypi file at their local scopes can + # define variables with the same names as the ones below and they will be + # merged. + 'grit_additional_defines': [ '<@(chrome_grit_defines)' ], + }, + 'includes': [ '../build/grit_action.gypi', 'chrome_features.gypi' ], +}
diff --git a/chrome/chrome_repack_resources.gypi b/chrome/chrome_repack_resources.gypi index 4668372..94cad45 100644 --- a/chrome/chrome_repack_resources.gypi +++ b/chrome/chrome_repack_resources.gypi
@@ -53,7 +53,6 @@ '<(grit_out_dir)/quota_internals_resources.pak', '<(grit_out_dir)/settings_resources.pak', '<(grit_out_dir)/sync_file_system_internals_resources.pak', - '<(grit_out_dir)/webrtc_device_provider_resources.pak', ], }], ['enable_extensions==1', {
diff --git a/chrome/chrome_resources.gyp b/chrome/chrome_resources.gyp index 3036b08..d78b04f 100644 --- a/chrome/chrome_resources.gyp +++ b/chrome/chrome_resources.gyp
@@ -2,14 +2,14 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. { - 'includes': [ - 'chrome_features.gypi', - ], 'variables': { - # Apply Chrome-specific grit settings to all grit actions in this file. + # Apply Chrome-specific grit settings to all of this file. + # The advantage is that one entry here applies to the entire file. + # The caveat is these variables cannot be merged with other variable + # dictionaries in more inner scopes. If the variable should be merged, + # consider putting them in a gypi file and including it at the right scope + # instead. e.g. with chrome_grit_action.gypi. 'grit_out_dir': '<(SHARED_INTERMEDIATE_DIR)/chrome', - 'grit_additional_defines': [ '<@(chrome_grit_defines)' ], - 'additional_modules_list_file': '<(SHARED_INTERMEDIATE_DIR)/chrome/browser/internal/additional_modules_list.txt', }, 'targets': [ @@ -27,7 +27,7 @@ 'variables': { 'grit_grd_file': 'browser/resources/memory_internals_resources.grd', }, - 'includes': [ '../build/grit_action.gypi' ], + 'includes': [ 'chrome_grit_action.gypi' ], }, { # GN version: //chrome/browser/resources:net_internals_resources @@ -35,7 +35,7 @@ 'variables': { 'grit_grd_file': 'browser/resources/net_internals_resources.grd', }, - 'includes': [ '../build/grit_action.gypi' ], + 'includes': [ 'chrome_grit_action.gypi' ], }, { # GN version: //chrome/browser/resources:invalidations_resources @@ -43,7 +43,7 @@ 'variables': { 'grit_grd_file': 'browser/resources/invalidations_resources.grd', }, - 'includes': ['../build/grit_action.gypi' ], + 'includes': ['chrome_grit_action.gypi' ], }, { # GN version: //chrome/browser/resources:password_manager_internals_resources @@ -51,7 +51,7 @@ 'variables': { 'grit_grd_file': 'browser/resources/password_manager_internals_resources.grd', }, - 'includes': [ '../build/grit_action.gypi' ], + 'includes': [ 'chrome_grit_action.gypi' ], }, { # GN version: //chrome/browser/resources:policy_resources @@ -59,7 +59,7 @@ 'variables': { 'grit_grd_file': 'browser/resources/md_policy/policy_resources.grd', }, - 'includes': [ '../build/grit_action.gypi' ], + 'includes': [ 'chrome_grit_action.gypi' ], }, { # GN version: //chrome/browser/resources:signin_internals_resources @@ -67,7 +67,7 @@ 'variables': { 'grit_grd_file': 'browser/resources/signin_internals_resources.grd', }, - 'includes': ['../build/grit_action.gypi' ], + 'includes': ['chrome_grit_action.gypi' ], }, { # GN version: //chrome/browser/resources:translate_internals_resources @@ -75,7 +75,7 @@ 'variables': { 'grit_grd_file': 'browser/resources/translate_internals_resources.grd', }, - 'includes': [ '../build/grit_action.gypi' ], + 'includes': [ 'chrome_grit_action.gypi' ], }, ], 'includes': [ '../build/grit_target.gypi' ], @@ -85,7 +85,6 @@ '../components/components_resources.gyp:components_resources', '../content/browser/devtools/devtools_resources.gyp:devtools_resources', '../content/browser/tracing/tracing_resources.gyp:tracing_resources', - 'browser/devtools/webrtc_device_provider_resources.gyp:webrtc_device_provider_resources', ], 'actions': [ { @@ -94,7 +93,7 @@ 'variables': { 'grit_grd_file': 'browser/resources/component_extension_resources.grd', }, - 'includes': [ '../build/grit_action.gypi' ], + 'includes': [ 'chrome_grit_action.gypi' ], }, { # GN version: //chrome/browser/resources:options_resources @@ -102,7 +101,7 @@ 'variables': { 'grit_grd_file': 'browser/resources/options_resources.grd', }, - 'includes': [ '../build/grit_action.gypi' ], + 'includes': [ 'chrome_grit_action.gypi' ], }, { # GN version: //chrome/browser/resources:settings_resources @@ -110,7 +109,7 @@ 'variables': { 'grit_grd_file': 'browser/resources/settings/settings_resources.grd', }, - 'includes': [ '../build/grit_action.gypi' ], + 'includes': [ 'chrome_grit_action.gypi' ], }, ], 'copies': [ @@ -136,7 +135,7 @@ 'variables': { 'grit_grd_file': 'browser/resources/quota_internals_resources.grd', }, - 'includes': [ '../build/grit_action.gypi' ], + 'includes': [ 'chrome_grit_action.gypi' ], }, { # GN version: //chrome/browser/resources:sync_file_system_internals_resources @@ -144,7 +143,7 @@ 'variables': { 'grit_grd_file': 'browser/resources/sync_file_system_internals_resources.grd', }, - 'includes': [ '../build/grit_action.gypi' ], + 'includes': [ 'chrome_grit_action.gypi' ], }, ], }], @@ -203,16 +202,11 @@ 'variables': { 'grit_grd_file': 'browser/browser_resources.grd', 'grit_additional_defines': [ - # TODO(dbeam): 'chrome_grit_defines' should just be appended to - # this list of 'grit_additional_defines' via the top of this file, - # but they're not for some reason. Maybe because they're in - # different scopes? - '<@(chrome_grit_defines)', '-E', 'additional_modules_list_file=<(additional_modules_list_file)', '-E', 'root_gen_dir=<(SHARED_INTERMEDIATE_DIR)', ], }, - 'includes': [ '../build/grit_action.gypi' ], + 'includes': [ 'chrome_grit_action.gypi' ], }, { # GN version: //chrome/common:resources @@ -220,7 +214,7 @@ 'variables': { 'grit_grd_file': 'common/common_resources.grd', }, - 'includes': [ '../build/grit_action.gypi' ], + 'includes': [ 'chrome_grit_action.gypi' ], }, { # GN version: //chrome/renderer:resources @@ -228,7 +222,7 @@ 'variables': { 'grit_grd_file': 'renderer/resources/renderer_resources.grd', }, - 'includes': [ '../build/grit_action.gypi' ], + 'includes': [ 'chrome_grit_action.gypi' ], }, ], 'conditions': [ @@ -240,7 +234,7 @@ 'variables': { 'grit_grd_file': 'common/extensions_api_resources.grd', }, - 'includes': [ '../build/grit_action.gypi' ], + 'includes': [ 'chrome_grit_action.gypi' ], } ], }], @@ -263,7 +257,7 @@ 'variables': { 'grit_grd_file': 'app/resources/locale_settings.grd', }, - 'includes': [ '../build/grit_action.gypi' ], + 'includes': [ 'chrome_grit_action.gypi' ], }, { # GN version: //chrome/app:chromium_strings @@ -271,7 +265,7 @@ 'variables': { 'grit_grd_file': 'app/chromium_strings.grd', }, - 'includes': [ '../build/grit_action.gypi' ], + 'includes': [ 'chrome_grit_action.gypi' ], }, { # GN version: //chrome/app:generated_resources @@ -279,7 +273,7 @@ 'variables': { 'grit_grd_file': 'app/generated_resources.grd', }, - 'includes': [ '../build/grit_action.gypi' ], + 'includes': [ 'chrome_grit_action.gypi' ], }, { # GN version: //chrome/app:google_chrome_strings @@ -287,7 +281,7 @@ 'variables': { 'grit_grd_file': 'app/google_chrome_strings.grd', }, - 'includes': [ '../build/grit_action.gypi' ], + 'includes': [ 'chrome_grit_action.gypi' ], }, { # GN version: //chrome/app:settings_strings @@ -295,7 +289,7 @@ 'variables': { 'grit_grd_file': 'app/settings_strings.grd', }, - 'includes': [ '../build/grit_action.gypi' ], + 'includes': [ 'chrome_grit_action.gypi' ], }, { # GN version: //chrome/app:settings_chromium_strings @@ -303,7 +297,7 @@ 'variables': { 'grit_grd_file': 'app/settings_chromium_strings.grd', }, - 'includes': [ '../build/grit_action.gypi' ], + 'includes': [ 'chrome_grit_action.gypi' ], }, { # GN version: //chrome/app:settings_google_chrome_strings @@ -311,7 +305,7 @@ 'variables': { 'grit_grd_file': 'app/settings_google_chrome_strings.grd', }, - 'includes': [ '../build/grit_action.gypi' ], + 'includes': [ 'chrome_grit_action.gypi' ], }, ], }, @@ -414,7 +408,7 @@ 'variables': { 'grit_grd_file': '<(platform_locale_settings_grd)', }, - 'includes': [ '../build/grit_action.gypi' ], + 'includes': [ 'chrome_grit_action.gypi' ], }, ], 'includes': [ '../build/grit_target.gypi' ], @@ -433,7 +427,7 @@ 'variables': { 'grit_grd_file': 'app/theme/theme_resources.grd', }, - 'includes': [ '../build/grit_action.gypi' ], + 'includes': [ 'chrome_grit_action.gypi' ], }, ], 'includes': [ '../build/grit_target.gypi' ], @@ -651,7 +645,7 @@ 'variables': { 'grit_grd_file': 'app/theme/chrome_unscaled_resources.grd', }, - 'includes': [ '../build/grit_action.gypi' ], + 'includes': [ 'chrome_grit_action.gypi' ], }, ], 'includes': [ '../build/grit_target.gypi' ], @@ -666,7 +660,7 @@ 'variables': { 'grit_grd_file': 'browser/resources/options_test_resources.grd', }, - 'includes': [ '../build/grit_action.gypi' ], + 'includes': [ 'chrome_grit_action.gypi' ], }, ], 'includes': [ '../build/grit_target.gypi' ], @@ -681,7 +675,7 @@ 'variables': { 'grit_grd_file': 'test/data/webui_test_resources.grd', }, - 'includes': [ '../build/grit_action.gypi' ], + 'includes': [ 'chrome_grit_action.gypi' ], }, ], 'includes': [ '../build/grit_target.gypi' ],
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index a11a90e..1851588 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi
@@ -97,9 +97,6 @@ 'browser/devtools/device/adb/mock_adb_server.h', 'browser/devtools/device/port_forwarding_browsertest.cc', 'browser/devtools/device/usb/android_usb_browsertest.cc', - 'browser/devtools/device/webrtc/devtools_bridge_client_browsertest.cc', - 'browser/devtools/device/webrtc/devtools_bridge_client_browsertest.h', - 'browser/devtools/device/webrtc/webrtc_device_provider_browsertest.cc', 'browser/devtools/devtools_sanity_browsertest.cc', 'browser/devtools/devtools_window_testing.cc', 'browser/devtools/devtools_window_testing.h', @@ -173,7 +170,6 @@ 'browser/extensions/api/management/management_api_browsertest.cc', 'browser/extensions/api/management/management_apitest.cc', 'browser/extensions/api/management/management_browsertest.cc', - 'browser/extensions/api/mdns/mdns_apitest.cc', 'browser/extensions/api/media_galleries/media_galleries_apitest.cc', 'browser/extensions/api/media_galleries/media_galleries_watch_apitest.cc', 'browser/extensions/api/messaging/native_messaging_apitest.cc', @@ -904,6 +900,9 @@ 'browser/ui/app_list/search/webstore/webstore_provider_browsertest.cc', 'browser/ui/app_list/speech_recognizer_browsertest.cc', ], + 'chrome_browser_tests_service_discovery_sources': [ + 'browser/extensions/api/mdns/mdns_apitest.cc', + ], 'chrome_browser_tests_media_router_sources': [ 'browser/ui/webui/media_router/media_router_dialog_controller_impl_browsertest.cc', 'test/data/webui/media_router/media_router_elements_browsertest.js', @@ -922,7 +921,6 @@ # and are handled by a rule, but in the GN build they're in a separate # action so need to be separated out. 'chrome_browser_tests_webui_js_sources': [ - 'browser/devtools/device/webrtc/devtools_bridge_client_browsertest.js', 'browser/ui/webui/app_list/start_page_browsertest.js', 'browser/ui/webui/chromeos/bluetooth_pairing_ui_browsertest.js', 'browser/ui/webui/chromeos/certificate_manager_dialog_browsertest.js', @@ -2570,6 +2568,9 @@ }, { 'sources!': [ 'browser/ui/webui/app_list/start_page_browsertest.js' ], }], + ['enable_service_discovery==1', { + 'sources': [ '<@(chrome_browser_tests_service_discovery_sources)' ], + }], ['enable_supervised_users==1', { 'sources': [ '<@(chrome_browser_tests_supervised_user_sources)' ], }, {
diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi index 2909438..19f47ce 100644 --- a/chrome/chrome_tests_unit.gypi +++ b/chrome/chrome_tests_unit.gypi
@@ -50,6 +50,7 @@ 'browser/browsing_data/browsing_data_cache_storage_helper_unittest.cc', 'browser/browsing_data/browsing_data_channel_id_helper_unittest.cc', 'browser/browsing_data/browsing_data_cookie_helper_unittest.cc', + 'browser/browsing_data/browsing_data_counter_utils_unittest.cc', 'browser/browsing_data/browsing_data_database_helper_unittest.cc', 'browser/browsing_data/browsing_data_file_system_helper_unittest.cc', 'browser/browsing_data/browsing_data_helper_unittest.cc', @@ -84,8 +85,6 @@ 'browser/custom_handlers/protocol_handler_registry_unittest.cc', 'browser/data_usage/tab_id_annotator_unittest.cc', 'browser/data_usage/tab_id_provider_unittest.cc', - 'browser/devtools/device/cast_device_provider_unittest.cc', - 'browser/devtools/device/webrtc/devtools_bridge_instances_request_unittest.cc', 'browser/devtools/devtools_network_controller_unittest.cc', 'browser/download/all_download_item_notifier_unittest.cc', 'browser/download/chrome_download_manager_delegate_unittest.cc', @@ -158,6 +157,7 @@ 'browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.cc', 'browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.h', 'browser/page_load_metrics/observers/aborts_page_load_metrics_observer_unittest.cc', + 'browser/page_load_metrics/observers/core_page_load_metrics_observer_unittest.cc', 'browser/page_load_metrics/observers/from_gws_page_load_metrics_observer_unittest.cc', 'browser/page_load_metrics/observers/google_captcha_observer_unittest.cc', 'browser/password_manager/chrome_password_manager_client_unittest.cc', @@ -278,7 +278,6 @@ 'browser/update_client/chrome_update_query_params_delegate_unittest.cc', 'common/chrome_content_client_unittest.cc', 'common/chrome_paths_unittest.cc', - 'common/cloud_print/cloud_print_helpers_unittest.cc', 'common/component_flash_hint_file_linux_unittest.cc', 'common/crash_keys_unittest.cc', 'common/ini_parser_unittest.cc', @@ -310,7 +309,6 @@ 'test/base/v8_unit_test.h', 'test/logging/win/mof_data_parser_unittest.cc', 'utility/chrome_content_utility_client_unittest.cc', - 'utility/cloud_print/pwg_encoder_unittest.cc', # Duplicate these tests here because PathService has more items in # unit_tests than in base_unittests. @@ -438,8 +436,6 @@ 'browser/extensions/api/file_handlers/api_file_handler_util_unittest.cc', 'browser/extensions/api/file_handlers/mime_util_unittest.cc', 'browser/extensions/api/file_system/file_system_api_unittest.cc', - 'browser/extensions/api/gcd_private/privet_v3_context_getter_unittest.cc', - 'browser/extensions/api/gcd_private/privet_v3_session_unittest.cc', 'browser/extensions/api/identity/extension_token_key_unittest.cc', 'browser/extensions/api/identity/gaia_web_auth_flow_unittest.cc', 'browser/extensions/api/identity/identity_mint_queue_unittest.cc', @@ -451,8 +447,6 @@ 'browser/extensions/api/image_writer_private/write_from_file_operation_unittest.cc', 'browser/extensions/api/image_writer_private/write_from_url_operation_unittest.cc', 'browser/extensions/api/management/management_api_unittest.cc', - 'browser/extensions/api/mdns/dns_sd_registry_unittest.cc', - 'browser/extensions/api/mdns/mdns_api_unittest.cc', 'browser/extensions/api/omnibox/omnibox_unittest.cc', 'browser/extensions/api/permissions/permissions_api_helpers_unittest.cc', 'browser/extensions/api/preference/preference_api_prefs_unittest.cc', @@ -674,6 +668,12 @@ 'utility/image_writer/image_writer_unittest.cc', 'utility/media_galleries/image_metadata_extractor_unittest.cc', ], + 'chrome_unit_tests_extensions_service_discovery_sources': [ + 'browser/extensions/api/gcd_private/privet_v3_context_getter_unittest.cc', + 'browser/extensions/api/gcd_private/privet_v3_session_unittest.cc', + 'browser/extensions/api/mdns/dns_sd_registry_unittest.cc', + 'browser/extensions/api/mdns/mdns_api_unittest.cc', + ], 'chrome_unit_tests_extensions_non_chromeos_sources': [ 'browser/extensions/api/messaging/native_message_process_host_unittest.cc', 'browser/extensions/api/messaging/native_messaging_host_manifest_unittest.cc', @@ -715,20 +715,20 @@ 'browser/task_manager/task_manager_util_unittest.cc', ], 'chrome_unit_tests_mdns_sources': [ - 'browser/local_discovery/privet_device_lister_unittest.cc', - 'browser/local_discovery/privet_local_printer_lister_unittest.cc', - 'browser/local_discovery/privet_notifications_unittest.cc', 'common/local_discovery/local_domain_resolver_unittest.cc', 'common/local_discovery/service_discovery_client_unittest.cc', + 'browser/printing/cloud_print/privet_device_lister_unittest.cc', + 'browser/printing/cloud_print/privet_local_printer_lister_unittest.cc', ], 'chrome_unit_tests_service_discovery_sources': [ - 'browser/local_discovery/cloud_device_list_unittest.cc', - 'browser/local_discovery/cloud_print_printer_list_unittest.cc', - 'browser/local_discovery/gcd_api_flow_unittest.cc', - 'browser/local_discovery/privet_confirm_api_flow_unittest.cc', - 'browser/local_discovery/privet_http_unittest.cc', - 'browser/local_discovery/privet_url_fetcher_unittest.cc', + 'browser/devtools/device/cast_device_provider_unittest.cc', 'browser/local_discovery/service_discovery_client_mac_unittest.mm', + 'browser/printing/cloud_print/cloud_print_printer_list_unittest.cc', + 'browser/printing/cloud_print/gcd_api_flow_unittest.cc', + 'browser/printing/cloud_print/privet_confirm_api_flow_unittest.cc', + 'browser/printing/cloud_print/privet_http_unittest.cc', + 'browser/printing/cloud_print/privet_notifications_unittest.cc', + 'browser/printing/cloud_print/privet_url_fetcher_unittest.cc', ], 'chrome_unit_tests_configuration_policy_sources': [ 'browser/policy/cloud/cloud_policy_invalidator_unittest.cc', @@ -871,6 +871,7 @@ 'browser/printing/print_preview_test.h', 'browser/ui/webui/print_preview/extension_printer_handler_unittest.cc', 'browser/ui/webui/print_preview/print_preview_ui_unittest.cc', + 'common/cloud_print/cloud_print_helpers_unittest.cc', 'common/service_process_util_unittest.cc', 'service/cloud_print/cloud_print_service_helpers_unittest.cc', 'service/cloud_print/cloud_print_token_store_unittest.cc', @@ -880,6 +881,7 @@ 'service/cloud_print/printer_job_queue_handler_unittest.cc', 'service/service_ipc_server_unittest.cc', 'service/service_process_prefs_unittest.cc', + 'utility/cloud_print/pwg_encoder_unittest.cc', ], 'chrome_unit_tests_captive_portal_sources': [ 'browser/captive_portal/captive_portal_service_unittest.cc', @@ -1586,7 +1588,6 @@ 'browser/ui/webui/md_downloads/downloads_list_tracker_unittest.cc', 'browser/ui/webui/ntp/ntp_user_data_logger_unittest.cc', 'browser/ui/webui/options/autofill_options_handler_unittest.cc', - 'browser/ui/webui/options/clear_browser_data_handler_unittest.cc', 'browser/ui/webui/options/language_options_handler_unittest.cc', 'browser/ui/webui/options/pepper_flash_content_settings_utils_unittest.cc', 'browser/ui/webui/options/sync_setup_handler_unittest.cc', @@ -1726,8 +1727,6 @@ 'sources': [ 'app/chrome_main_delegate.cc', 'app/chrome_main_delegate.h', - 'app/close_handle_hook_win.cc', - 'app/close_handle_hook_win.h', 'browser/browsing_data/mock_browsing_data_appcache_helper.cc', 'browser/browsing_data/mock_browsing_data_appcache_helper.h', 'browser/browsing_data/mock_browsing_data_cache_storage_helper.cc', @@ -2400,7 +2399,10 @@ ['configuration_policy==1', { 'sources': [ '<@(chrome_unit_tests_extensions_policy_sources)' ], }], - ['chromeos == 0', { + ['enable_service_discovery==1', { + 'sources': [ '<@(chrome_unit_tests_extensions_service_discovery_sources)' ], + }], + ['chromeos==0', { 'sources': [ '<@(chrome_unit_tests_extensions_non_chromeos_sources)', ], @@ -2738,8 +2740,6 @@ }], ['OS=="android" or OS=="ios"', { 'sources!': [ - 'browser/devtools/device/cast_device_provider_unittest.cc', - 'browser/devtools/device/webrtc/devtools_bridge_instances_request_unittest.cc', 'browser/ui/bookmarks/bookmark_ui_utils_desktop_unittest.cc', 'browser/ui/sync/sync_promo_ui_unittest.cc', ], @@ -2907,9 +2907,6 @@ 'app/delay_load_hook_win.cc', 'app/delay_load_hook_win.h', 'app/resources/resources_unittest.cc', - 'app/signature_validator_win.cc', - 'app/signature_validator_win.h', - 'app/signature_validator_win_unittest.cc', 'common/crash_keys.cc', 'common/crash_keys.h', ], @@ -2938,11 +2935,6 @@ ], }], ], - 'msvs_settings': { - 'VCLinkerTool': { - 'AdditionalDependencies': [ 'wintrust.lib' ], - }, - }, }], ], },
diff --git a/chrome/chrome_utility.gypi b/chrome/chrome_utility.gypi index d6e9be0..8ed5511f 100644 --- a/chrome/chrome_utility.gypi +++ b/chrome/chrome_utility.gypi
@@ -15,8 +15,6 @@ 'utility/cloud_print/pwg_encoder.h', 'utility/font_cache_handler_win.cc', 'utility/font_cache_handler_win.h', - 'utility/local_discovery/service_discovery_message_handler.cc', - 'utility/local_discovery/service_discovery_message_handler.h', 'utility/printing_handler.cc', 'utility/printing_handler.h', 'utility/safe_json_parser_handler.cc', @@ -215,12 +213,6 @@ 'utility/printing_handler.h', ] }], - ['enable_mdns==0', { - 'sources!': [ - 'utility/local_discovery/service_discovery_message_handler.cc', - 'utility/local_discovery/service_discovery_message_handler.h', - ] - }], ['safe_browsing==1', { 'sources': [ '<@(chrome_utility_safe_browsing_sources)' ], 'conditions': [
diff --git a/chrome/chrome_watcher/BUILD.gn b/chrome/chrome_watcher/BUILD.gn index 42fd8b7..e7b793a8 100644 --- a/chrome/chrome_watcher/BUILD.gn +++ b/chrome/chrome_watcher/BUILD.gn
@@ -37,6 +37,7 @@ "//build/config/sanitizers:deps", "//chrome/installer/util:with_no_strings", "//components/browser_watcher", + "//third_party/kasko", ] ldflags = [ "/DEF:" + rebase_path("chrome_watcher.def", root_build_dir) ] configs -= [ "//build/config/win:console" ]
diff --git a/chrome/common/BUILD.gn b/chrome/common/BUILD.gn index edd9bc0..df5e371 100644 --- a/chrome/common/BUILD.gn +++ b/chrome/common/BUILD.gn
@@ -247,10 +247,6 @@ ] } - if (enable_mdns) { - sources += [ "local_discovery/local_discovery_messages.h" ] - } - if (is_mac) { sources -= [ "channel_info_posix.cc" ] public_deps += [
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc index 88c8045..0ecd648 100644 --- a/chrome/common/chrome_switches.cc +++ b/chrome/common/chrome_switches.cc
@@ -249,9 +249,6 @@ const char kDisableDeviceDiscoveryNotifications[] = "disable-device-discovery-notifications"; -// Disables the dinosaur easter egg on the offline interstitial. -const char kDisableDinosaurEasterEgg[] = "disable-dinosaur-easter-egg"; - // Disables Domain Reliability Monitoring. const char kDisableDomainReliability[] = "disable-domain-reliability"; @@ -520,6 +517,12 @@ const char kDisableSimplifiedFullscreenUI[] = "disable-simplified-fullscreen-ui"; +// Enable the Site Engagement App Banner which triggers app install banners +// using the site engagement service rather than a navigation-based heuristic. +// Implicitly enables the site engagement service. +const char kEnableSiteEngagementAppBanner[] = + "enable-site-engagement-app-banner"; + // Enable the Site Engagement Eviction Policy which evicts temporary storage // using the site engagement service. Implicitly enables the site engagement // service. @@ -944,22 +947,12 @@ // If true the app list will be shown. const char kShowAppList[] = "show-app-list"; -// Command line flag offering a "Show saved copy" option to the user if offline. -// The various modes are disabled, primary, or secondary. Primary/secondary -// refers to button placement (for experiment). -const char kShowSavedCopy[] = "show-saved-copy"; - // Causes SSL key material to be logged to the specified file for debugging // purposes. See // https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS/Key_Log_Format // for the format. const char kSSLKeyLogFile[] = "ssl-key-log-file"; -// Values for the kShowSavedCopy flag. -const char kEnableShowSavedCopyPrimary[] = "primary"; -const char kEnableShowSavedCopySecondary[] = "secondary"; -const char kDisableShowSavedCopy[] = "disable"; - // Does not show an infobar when an extension attaches to a page using // chrome.debugger page. Required to attach to extension background pages. const char kSilentDebuggerExtensionAPI[] = "silent-debugger-extension-api";
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h index 1767ffff..ff02de7 100644 --- a/chrome/common/chrome_switches.h +++ b/chrome/common/chrome_switches.h
@@ -72,7 +72,6 @@ extern const char kDisableComponentUpdate[]; extern const char kDisableDefaultApps[]; extern const char kDisableDeviceDiscoveryNotifications[]; -extern const char kDisableDinosaurEasterEgg[]; extern const char kDisableDomainReliability[]; extern const char kDisableDownloadNotification[]; extern const char kDisableExtensionsFileAccessCheck[]; @@ -150,6 +149,7 @@ extern const char kDisableSettingsWindow[]; extern const char kEnableSimplifiedFullscreenUI[]; extern const char kDisableSimplifiedFullscreenUI[]; +extern const char kEnableSiteEngagementAppBanner[]; extern const char kEnableSiteEngagementEvictionPolicy[]; extern const char kEnableSiteEngagementService[]; extern const char kEnableSupervisedUserManagedBookmarksFolder[]; @@ -255,11 +255,7 @@ extern const char kSilentDebuggerExtensionAPI[]; extern const char kSilentLaunch[]; extern const char kShowAppList[]; -extern const char kShowSavedCopy[]; extern const char kSSLKeyLogFile[]; -extern const char kEnableShowSavedCopyPrimary[]; -extern const char kEnableShowSavedCopySecondary[]; -extern const char kDisableShowSavedCopy[]; extern const char kSimulateElevatedRecovery[]; extern const char kSimulateUpgrade[]; extern const char kSimulateCriticalUpdate[];
diff --git a/chrome/common/common_message_generator.h b/chrome/common/common_message_generator.h index d6734af..e7a3f68 100644 --- a/chrome/common/common_message_generator.h +++ b/chrome/common/common_message_generator.h
@@ -18,10 +18,6 @@ #include "chrome/common/extensions/chrome_utility_extensions_messages.h" #endif -#if defined(ENABLE_MDNS) -#include "chrome/common/local_discovery/local_discovery_messages.h" -#endif - #if defined(ENABLE_PRINT_PREVIEW) #include "chrome/common/service_messages.h" #endif
diff --git a/chrome/common/extensions/api/_permission_features.json b/chrome/common/extensions/api/_permission_features.json index f258ccf..c4d96ed 100644 --- a/chrome/common/extensions/api/_permission_features.json +++ b/chrome/common/extensions/api/_permission_features.json
@@ -728,7 +728,8 @@ "9193D3A51E2FE33B496CDA53EA330423166E7F02", // http://crbug.com/397691 "F9119B8B18C7C82B51E7BC6FF816B694F2EC3E89", // http://crbug.com/397691 "C17CD9E6868D7B9C67926E0EC612EA25C768418F", // http://crbug.com/457908 - "EF2AB692559EA97C3BBDEA018A8C45F92457BD4E" // http://crbug.com/457908 + "EF2AB692559EA97C3BBDEA018A8C45F92457BD4E", // http://crbug.com/457908 + "1BFB3A47AA4A1E1C4714D919217602685CDD0FA7" // http://crbug.com/574600 ] }, {
diff --git a/chrome/common/extensions/api/extension_action/action_info.cc b/chrome/common/extensions/api/extension_action/action_info.cc index 8e68d32..9185d132 100644 --- a/chrome/common/extensions/api/extension_action/action_info.cc +++ b/chrome/common/extensions/api/extension_action/action_info.cc
@@ -52,7 +52,7 @@ } // static -scoped_ptr<ActionInfo> ActionInfo::Load(Extension* extension, +scoped_ptr<ActionInfo> ActionInfo::Load(const Extension* extension, const base::DictionaryValue* dict, base::string16* error) { scoped_ptr<ActionInfo> result(new ActionInfo()); @@ -92,7 +92,7 @@ std::string default_icon; if (dict->GetDictionary(keys::kPageActionDefaultIcon, &icons_value)) { if (!manifest_handler_helpers::LoadIconsFromDictionary( - extension, icons_value, &result->default_icon, error)) { + icons_value, &result->default_icon, error)) { return scoped_ptr<ActionInfo>(); } } else if (dict->GetString(keys::kPageActionDefaultIcon, &default_icon) &&
diff --git a/chrome/common/extensions/api/extension_action/action_info.h b/chrome/common/extensions/api/extension_action/action_info.h index 3ad0a25..09e497c 100644 --- a/chrome/common/extensions/api/extension_action/action_info.h +++ b/chrome/common/extensions/api/extension_action/action_info.h
@@ -32,7 +32,7 @@ }; // Loads an ActionInfo from the given DictionaryValue. - static scoped_ptr<ActionInfo> Load(Extension* extension, + static scoped_ptr<ActionInfo> Load(const Extension* extension, const base::DictionaryValue* dict, base::string16* error);
diff --git a/chrome/common/extensions/api/extension_action/browser_action_manifest_unittest.cc b/chrome/common/extensions/api/extension_action/browser_action_manifest_unittest.cc index 7a0a64c..fdab935 100644 --- a/chrome/common/extensions/api/extension_action/browser_action_manifest_unittest.cc +++ b/chrome/common/extensions/api/extension_action/browser_action_manifest_unittest.cc
@@ -86,8 +86,6 @@ .Set("19", "icon19.png") .Set("24", "icon24.png") .Set("38", "icon38.png"))))))) - // Don't check for existence of icons during parsing. - .SetLocation(Manifest::UNPACKED) .Build(); ASSERT_TRUE(extension.get());
diff --git a/chrome/common/extensions/api/schemas.gni b/chrome/common/extensions/api/schemas.gni index a996cbe6..b95d4ee 100644 --- a/chrome/common/extensions/api/schemas.gni +++ b/chrome/common/extensions/api/schemas.gni
@@ -17,12 +17,12 @@ if (is_chromeos) { sources += gypi_values.chromeos_schema_files } +if (enable_service_discovery) { + sources += gypi_values.service_discovery_schema_files +} if (enable_webrtc) { sources += gypi_values.webrtc_schema_files } -if (!is_android) { - sources += gypi_values.non_android_schema_files -} uncompiled_sources = gypi_values.main_non_compiled_schema_files
diff --git a/chrome/common/extensions/api/schemas.gypi b/chrome/common/extensions/api/schemas.gypi index 51a5797..29add64c 100644 --- a/chrome/common/extensions/api/schemas.gypi +++ b/chrome/common/extensions/api/schemas.gypi
@@ -55,6 +55,7 @@ 'inline_install_private.idl', 'instance_id.json', 'language_settings_private.idl', + 'launcher_page.idl', 'location.idl', 'manifest_types.json', 'media_galleries.idl', @@ -133,10 +134,8 @@ 'media_player_private.json', ], - # Non Android schemas. - 'non_android_schema_files': [ + 'service_discovery_schema_files': [ 'gcd_private.idl', - 'launcher_page.idl', 'mdns.idl', ], @@ -177,16 +176,16 @@ 'input_ime.json', ], }], + ['enable_service_discovery==1', { + 'schema_files': [ + '<@(service_discovery_schema_files)', + ], + }], ['enable_webrtc==1', { 'schema_files': [ '<@(webrtc_schema_files)', ], }], - ['OS!="android"', { - 'schema_files': [ - '<@(non_android_schema_files)', - ], - }], ], 'cc_dir': 'chrome/common/extensions/api', 'root_namespace': 'extensions::api::%(namespace)s',
diff --git a/chrome/common/extensions/api/web_navigation.json b/chrome/common/extensions/api/web_navigation.json index fb79b82..fa32a6d4 100644 --- a/chrome/common/extensions/api/web_navigation.json +++ b/chrome/common/extensions/api/web_navigation.json
@@ -31,7 +31,12 @@ "description": "Information about the frame to retrieve information about.", "properties": { "tabId": { "type": "integer", "minimum": 0, "description": "The ID of the tab in which the frame is." }, - "processId": {"type": "integer", "description": "The ID of the process runs the renderer for this tab."}, + "processId": { + "type": "integer", + "optional": true, + "deprecated": "Frames are now uniquely identified by their tab ID and frame ID; the process ID is no longer needed and therefore ignored.", + "description": "The ID of the process that runs the renderer for this tab." + }, "frameId": { "type": "integer", "minimum": 0, "description": "The ID of the frame in the given tab." } } }, @@ -90,7 +95,7 @@ }, "processId": { "type": "integer", - "description": "The ID of the process runs the renderer for this tab." + "description": "The ID of the process that runs the renderer for this frame." }, "frameId": { "type": "integer", @@ -132,7 +137,7 @@ "properties": { "tabId": {"type": "integer", "description": "The ID of the tab in which the navigation is about to occur."}, "url": {"type": "string"}, - "processId": {"type": "integer", "description": "The ID of the process runs the renderer for this tab."}, + "processId": {"type": "integer", "description": "The ID of the process that runs the renderer for this frame."}, "frameId": {"type": "integer", "description": "0 indicates the navigation happens in the tab content window; a positive value indicates navigation in a subframe. Frame IDs are unique for a given tab and process."}, "parentFrameId": {"type": "integer", "description": "ID of frame that wraps the frame. Set to -1 of no parent frame exists."}, "timeStamp": {"type": "number", "description": "The time when the browser was about to start the navigation, in milliseconds since the epoch."} @@ -159,7 +164,7 @@ "properties": { "tabId": {"type": "integer", "description": "The ID of the tab in which the navigation occurs."}, "url": {"type": "string"}, - "processId": {"type": "integer", "description": "The ID of the process runs the renderer for this tab."}, + "processId": {"type": "integer", "description": "The ID of the process that runs the renderer for this frame."}, "frameId": {"type": "integer", "description": "0 indicates the navigation happens in the tab content window; a positive value indicates navigation in a subframe. Frame IDs are unique within a tab."}, "transitionType": {"$ref": "TransitionType", "description": "Cause of the navigation."}, "transitionQualifiers": {"type": "array", "description": "A list of transition qualifiers.", "items": {"$ref": "TransitionQualifier"}}, @@ -187,7 +192,7 @@ "properties": { "tabId": {"type": "integer", "description": "The ID of the tab in which the navigation occurs."}, "url": {"type": "string"}, - "processId": {"type": "integer", "description": "The ID of the process runs the renderer for this tab."}, + "processId": {"type": "integer", "description": "The ID of the process that runs the renderer for this frame."}, "frameId": {"type": "integer", "description": "0 indicates the navigation happens in the tab content window; a positive value indicates navigation in a subframe. Frame IDs are unique within a tab."}, "timeStamp": {"type": "number", "description": "The time when the page's DOM was fully constructed, in milliseconds since the epoch."} } @@ -213,7 +218,7 @@ "properties": { "tabId": {"type": "integer", "description": "The ID of the tab in which the navigation occurs."}, "url": {"type": "string"}, - "processId": {"type": "integer", "description": "The ID of the process runs the renderer for this tab."}, + "processId": {"type": "integer", "description": "The ID of the process that runs the renderer for this frame."}, "frameId": {"type": "integer", "description": "0 indicates the navigation happens in the tab content window; a positive value indicates navigation in a subframe. Frame IDs are unique within a tab."}, "timeStamp": {"type": "number", "description": "The time when the document finished loading, in milliseconds since the epoch."} } @@ -239,7 +244,7 @@ "properties": { "tabId": {"type": "integer", "description": "The ID of the tab in which the navigation occurs."}, "url": {"type": "string"}, - "processId": {"type": "integer", "description": "The ID of the process runs the renderer for this tab."}, + "processId": {"type": "integer", "description": "The ID of the process that runs the renderer for this frame."}, "frameId": {"type": "integer", "description": "0 indicates the navigation happens in the tab content window; a positive value indicates navigation in a subframe. Frame IDs are unique within a tab."}, "error": {"type": "string", "description": "The error description."}, "timeStamp": {"type": "number", "description": "The time when the error occurred, in milliseconds since the epoch."} @@ -265,7 +270,7 @@ "name": "details", "properties": { "sourceTabId": {"type": "integer", "description": "The ID of the tab in which the navigation is triggered."}, - "sourceProcessId": {"type": "integer", "description": "The ID of the process runs the renderer for the source tab."}, + "sourceProcessId": {"type": "integer", "description": "The ID of the process that runs the renderer for the source frame."}, "sourceFrameId": {"type": "integer", "description": "The ID of the frame with sourceTabId in which the navigation is triggered. 0 indicates the main frame."}, "url": {"type": "string", "description": "The URL to be opened in the new window."}, "tabId": {"type": "integer", "description": "The ID of the tab in which the url is opened"}, @@ -293,7 +298,7 @@ "properties": { "tabId": {"type": "integer", "description": "The ID of the tab in which the navigation occurs."}, "url": {"type": "string"}, - "processId": {"type": "integer", "description": "The ID of the process runs the renderer for this tab."}, + "processId": {"type": "integer", "description": "The ID of the process that runs the renderer for this frame."}, "frameId": {"type": "integer", "description": "0 indicates the navigation happens in the tab content window; a positive value indicates navigation in a subframe. Frame IDs are unique within a tab."}, "transitionType": {"$ref": "TransitionType", "description": "Cause of the navigation."}, "transitionQualifiers": {"type": "array", "description": "A list of transition qualifiers.", "items": {"$ref": "TransitionQualifier"}}, @@ -337,7 +342,7 @@ "properties": { "tabId": {"type": "integer", "description": "The ID of the tab in which the navigation occurs."}, "url": {"type": "string"}, - "processId": {"type": "integer", "description": "The ID of the process runs the renderer for this tab."}, + "processId": {"type": "integer", "description": "The ID of the process that runs the renderer for this frame."}, "frameId": {"type": "integer", "description": "0 indicates the navigation happens in the tab content window; a positive value indicates navigation in a subframe. Frame IDs are unique within a tab."}, "transitionType": {"$ref": "TransitionType", "description": "Cause of the navigation."}, "transitionQualifiers": {"type": "array", "description": "A list of transition qualifiers.", "items": {"$ref": "TransitionQualifier"}},
diff --git a/chrome/common/extensions/docs/templates/intros/webNavigation.html b/chrome/common/extensions/docs/templates/intros/webNavigation.html index 36e3136..6dc666e 100644 --- a/chrome/common/extensions/docs/templates/intros/webNavigation.html +++ b/chrome/common/extensions/docs/templates/intros/webNavigation.html
@@ -103,21 +103,23 @@ unexpected results. </p> -<h2 id="frame_ids">A note about frame and process IDs</h2> +<h2 id="frame_ids">A note about frame IDs</h2> <p> Frames within a tab can be identified by a frame ID. The frame ID of the main frame is always 0, the ID of child frames is a positive number. Once a document is constructed in a frame, its frame ID remains constant during the lifetime of -the document. +the document. As of Chrome 49, this ID is also constant for the lifetime of the +frame (across multiple navigations). </p> <p> Due to the multi-process nature of Chrome, a tab might use different processes to render the source and destination of a web page. Therefore, if a navigation takes place in a new process, you might receive events both from the new and the old page until the new navigation is committed (i.e. the -<code>onCommitted</code> event is send for the new main frame). Because frame -IDs are only unique for a given process, the webNavigation events include a -process ID, so you can still determine which frame a navigation came from. +<code>onCommitted</code> event is send for the new main frame). In other words, +it is possible to have more than one pending sequence of webNavigation events +with the same <code>frameId</code>. The sequences can be distinguished by the +<code>processId</code> key. </p> <p> Also note that during a provisional load the process might be switched several
diff --git a/chrome/common/extensions/manifest_tests/extension_manifests_icons_unittest.cc b/chrome/common/extensions/manifest_tests/extension_manifests_icons_unittest.cc index 0a7a41fe..e73ba823 100644 --- a/chrome/common/extensions/manifest_tests/extension_manifests_icons_unittest.cc +++ b/chrome/common/extensions/manifest_tests/extension_manifests_icons_unittest.cc
@@ -15,22 +15,9 @@ class IconsManifestTest : public ChromeManifestTest { }; -// Icons that don't exist on disk should be ignored (for most manifest -// locations). -TEST_F(IconsManifestTest, IgnoreNonExistentIcons) { - scoped_refptr<extensions::Extension> extension( - LoadAndExpectSuccess("normalize_icon_paths.json", Manifest::INTERNAL)); - const ExtensionIconSet& icons = IconsInfo::GetIcons(extension.get()); - - EXPECT_EQ("", icons.Get(extension_misc::EXTENSION_ICON_BITTY, - ExtensionIconSet::MATCH_EXACTLY)); - EXPECT_EQ("", icons.Get(extension_misc::EXTENSION_ICON_MEDIUM, - ExtensionIconSet::MATCH_EXACTLY)); -} - TEST_F(IconsManifestTest, NormalizeIconPaths) { scoped_refptr<extensions::Extension> extension( - LoadAndExpectSuccess("normalize_icon_paths.json", Manifest::UNPACKED)); + LoadAndExpectSuccess("normalize_icon_paths.json")); const ExtensionIconSet& icons = IconsInfo::GetIcons(extension.get()); EXPECT_EQ("16.png", icons.Get(extension_misc::EXTENSION_ICON_BITTY, @@ -41,7 +28,7 @@ TEST_F(IconsManifestTest, IconSizes) { scoped_refptr<extensions::Extension> extension( - LoadAndExpectSuccess("init_icon_size.json", Manifest::UNPACKED)); + LoadAndExpectSuccess("init_icon_size.json")); const ExtensionIconSet& icons = IconsInfo::GetIcons(extension.get()); EXPECT_EQ("16.png", icons.Get(extension_misc::EXTENSION_ICON_BITTY,
diff --git a/chrome/common/local_discovery/local_discovery_messages.h b/chrome/common/local_discovery/local_discovery_messages.h deleted file mode 100644 index 8d94156b..0000000 --- a/chrome/common/local_discovery/local_discovery_messages.h +++ /dev/null
@@ -1,139 +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. - -// Defines local discovery messages between the browser and utility process. - -// Multiple-included file, no traditional include guard. - -#include <stdint.h> - -#include <vector> - -#include "build/build_config.h" -#include "chrome/common/local_discovery/service_discovery_client.h" -#include "ipc/ipc_message_macros.h" - -#ifndef CHROME_COMMON_LOCAL_DISCOVERY_LOCAL_DISCOVERY_MESSAGES_H_ -#define CHROME_COMMON_LOCAL_DISCOVERY_LOCAL_DISCOVERY_MESSAGES_H_ - -#if defined(OS_POSIX) -#include "base/file_descriptor_posix.h" -#endif - -#if defined(OS_POSIX) -struct LocalDiscoveryMsg_SocketInfo { - LocalDiscoveryMsg_SocketInfo() - : address_family(net::ADDRESS_FAMILY_UNSPECIFIED), - interface_index(0) { - } - - base::FileDescriptor descriptor; - net::AddressFamily address_family; - uint32_t interface_index; -}; -#endif // OS_POSIX - -#endif // CHROME_COMMON_LOCAL_DISCOVERY_LOCAL_DISCOVERY_MESSAGES_H_ - -#define IPC_MESSAGE_START LocalDiscoveryMsgStart - -IPC_ENUM_TRAITS_MAX_VALUE(local_discovery::ServiceWatcher::UpdateType, - local_discovery::ServiceWatcher::UPDATE_TYPE_LAST) - -IPC_ENUM_TRAITS_MAX_VALUE( - local_discovery::ServiceResolver::RequestStatus, - local_discovery::ServiceResolver::REQUEST_STATUS_LAST) - -IPC_ENUM_TRAITS_MAX_VALUE(net::AddressFamily, net::ADDRESS_FAMILY_LAST) - -IPC_STRUCT_TRAITS_BEGIN(local_discovery::ServiceDescription) - IPC_STRUCT_TRAITS_MEMBER(service_name) - IPC_STRUCT_TRAITS_MEMBER(address) - IPC_STRUCT_TRAITS_MEMBER(metadata) - IPC_STRUCT_TRAITS_MEMBER(ip_address) - IPC_STRUCT_TRAITS_MEMBER(last_seen) -IPC_STRUCT_TRAITS_END() - -#if defined(OS_POSIX) -IPC_STRUCT_TRAITS_BEGIN(LocalDiscoveryMsg_SocketInfo) - IPC_STRUCT_TRAITS_MEMBER(descriptor) - IPC_STRUCT_TRAITS_MEMBER(address_family) - IPC_STRUCT_TRAITS_MEMBER(interface_index) -IPC_STRUCT_TRAITS_END() -#endif // OS_POSIX -//------------------------------------------------------------------------------ -// Utility process messages: -// These are messages from the browser to the utility process. - -#if defined(OS_POSIX) -IPC_MESSAGE_CONTROL1(LocalDiscoveryMsg_SetSockets, - std::vector<LocalDiscoveryMsg_SocketInfo> /* sockets */) -#endif // OS_POSIX - -// Creates watcher and starts listening in utility process. -IPC_MESSAGE_CONTROL2(LocalDiscoveryMsg_StartWatcher, - uint64_t /* id */, - std::string /* service_type */) - -// Discovers new services. -IPC_MESSAGE_CONTROL2(LocalDiscoveryMsg_DiscoverServices, - uint64_t /* id */, - bool /* force_update */) - -// Discovers new services. -IPC_MESSAGE_CONTROL2(LocalDiscoveryMsg_SetActivelyRefreshServices, - uint64_t /* id */, - bool /* actively_refresh_services */) - -// Destroys watcher in utility process. -IPC_MESSAGE_CONTROL1(LocalDiscoveryMsg_DestroyWatcher, uint64_t /* id */) - -// Creates service resolver and starts resolving service in utility process. -IPC_MESSAGE_CONTROL2(LocalDiscoveryMsg_ResolveService, - uint64_t /* id */, - std::string /* service_name */) - -// Destroys service resolver in utility process. -IPC_MESSAGE_CONTROL1(LocalDiscoveryMsg_DestroyResolver, uint64_t /* id */) - -// Creates a local domain resolver and starts resolving in utility process. -IPC_MESSAGE_CONTROL3(LocalDiscoveryMsg_ResolveLocalDomain, - uint64_t /* id */, - std::string /* domain */, - net::AddressFamily /* address_family */) - -// Destroys local domain resolver in utility process. -IPC_MESSAGE_CONTROL1(LocalDiscoveryMsg_DestroyLocalDomainResolver, - uint64_t /* id */) - -// Stops local discovery in utility process. http://crbug.com/268466. -IPC_MESSAGE_CONTROL0(LocalDiscoveryMsg_ShutdownLocalDiscovery) - - -//------------------------------------------------------------------------------ -// Utility process host messages: -// These are messages from the utility process to the browser. - -// Notifies browser process if process failed. -IPC_MESSAGE_CONTROL0(LocalDiscoveryHostMsg_Error) - -// Notifies browser process about new services. -IPC_MESSAGE_CONTROL3(LocalDiscoveryHostMsg_WatcherCallback, - uint64_t /* id */, - local_discovery::ServiceWatcher::UpdateType /* update */, - std::string /* service_name */) - -// Notifies browser process about service resolution results. -IPC_MESSAGE_CONTROL3( - LocalDiscoveryHostMsg_ResolverCallback, - uint64_t /* id */, - local_discovery::ServiceResolver::RequestStatus /* status */, - local_discovery::ServiceDescription /* description */) - -// Notifies browser process about local domain resolution results. -IPC_MESSAGE_CONTROL4(LocalDiscoveryHostMsg_LocalDomainResolverCallback, - uint64_t /* id */, - bool /* success */, - net::IPAddressNumber /* ip_address_ipv4 */, - net::IPAddressNumber /* ip_address_ipv6 */)
diff --git a/chrome/common/localized_error.cc b/chrome/common/localized_error.cc index 5e8b4ea..1c06ae59 100644 --- a/chrome/common/localized_error.cc +++ b/chrome/common/localized_error.cc
@@ -17,10 +17,10 @@ #include "base/strings/utf_string_conversions.h" #include "base/values.h" #include "build/build_config.h" -#include "chrome/common/chrome_switches.h" #include "chrome/grit/chromium_strings.h" #include "chrome/grit/google_chrome_strings.h" #include "components/error_page/common/error_page_params.h" +#include "components/error_page/common/error_page_switches.h" #include "components/error_page/common/net_error_info.h" #include "components/strings/grit/components_chromium_strings.h" #include "components/strings/grit/components_google_chrome_strings.h" @@ -619,7 +619,8 @@ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); // Check if easter egg should be disabled. - if (command_line->HasSwitch(switches::kDisableDinosaurEasterEgg)) { + if (command_line->HasSwitch( + error_page::switches::kDisableDinosaurEasterEgg)) { // The presence of this string disables the easter egg. Acts as a flag. error_strings->SetString("disabledEasterEgg", l10n_util::GetStringUTF16(IDS_ERRORPAGE_FUN_DISABLED)); @@ -743,11 +744,13 @@ return; const std::string& show_saved_copy_value = - command_line->GetSwitchValueASCII(switches::kShowSavedCopy); - bool show_saved_copy_primary = (show_saved_copy_value == - switches::kEnableShowSavedCopyPrimary); - bool show_saved_copy_secondary = (show_saved_copy_value == - switches::kEnableShowSavedCopySecondary); + command_line->GetSwitchValueASCII(error_page::switches::kShowSavedCopy); + bool show_saved_copy_primary = + (show_saved_copy_value == + error_page::switches::kEnableShowSavedCopyPrimary); + bool show_saved_copy_secondary = + (show_saved_copy_value == + error_page::switches::kEnableShowSavedCopySecondary); bool show_saved_copy_visible = (stale_copy_in_cache && !is_post && (show_saved_copy_primary || show_saved_copy_secondary));
diff --git a/chrome/common/render_messages.h b/chrome/common/render_messages.h index 0e32f14..ddc7796 100644 --- a/chrome/common/render_messages.h +++ b/chrome/common/render_messages.h
@@ -226,8 +226,6 @@ OmniboxFocusState /* new_focus_state */, OmniboxFocusChangeReason /* reason */) -IPC_MESSAGE_ROUTED1(ChromeViewMsg_SearchBoxMarginChange, int /* start */) - IPC_MESSAGE_ROUTED1(ChromeViewMsg_SearchBoxMostVisitedItemsChanged, std::vector<InstantMostVisitedItem> /* items */)
diff --git a/chrome/common/url_constants.cc b/chrome/common/url_constants.cc index 7c72273..3f81c2ed 100644 --- a/chrome/common/url_constants.cc +++ b/chrome/common/url_constants.cc
@@ -252,8 +252,6 @@ const char kChromeUIUberHost[] = "chrome"; const char kChromeUIUserActionsHost[] = "user-actions"; const char kChromeUIVersionHost[] = "version"; -const char kChromeUIWebRTCDeviceProviderHost[] = - "webrtc-device-provider"; const char kChromeUIWorkersHost[] = "workers"; const char kChromeUIThemePath[] = "theme";
diff --git a/chrome/common/url_constants.h b/chrome/common/url_constants.h index 805a75a..fc35006 100644 --- a/chrome/common/url_constants.h +++ b/chrome/common/url_constants.h
@@ -239,7 +239,6 @@ extern const char kChromeUIUberHost[]; extern const char kChromeUIUserActionsHost[]; extern const char kChromeUIVersionHost[]; -extern const char kChromeUIWebRTCDeviceProviderHost[]; extern const char kChromeUIWorkersHost[]; extern const char kChromeUIThemePath[];
diff --git a/chrome/renderer/autofill/form_autofill_browsertest.cc b/chrome/renderer/autofill/form_autofill_browsertest.cc index f2669cf..3dfdd69 100644 --- a/chrome/renderer/autofill/form_autofill_browsertest.cc +++ b/chrome/renderer/autofill/form_autofill_browsertest.cc
@@ -302,6 +302,12 @@ WebInputElement::defaultMaxLength() : 0; expected.name = ASCIIToUTF16(field_cases[i].name); expected.value = ASCIIToUTF16(field_cases[i].initial_value); + if (expected.form_control_type == "text" || + expected.form_control_type == "month") { + expected.label = ASCIIToUTF16(field_cases[i].initial_value); + } else { + expected.label.clear(); + } expected.autocomplete_attribute = field_cases[i].autocomplete_attribute; EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields[i]); // Fill the form_data for the field. @@ -529,21 +535,25 @@ expected.name = ASCIIToUTF16("firstname"); expected.value = ASCIIToUTF16("John"); + expected.label = ASCIIToUTF16("John"); EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields[0]); EXPECT_FORM_FIELD_DATA_EQUALS(expected, field); expected.name = ASCIIToUTF16("lastname"); expected.value = ASCIIToUTF16("Smith"); + expected.label = ASCIIToUTF16("Smith"); EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields[1]); expected.name = ASCIIToUTF16("email"); expected.value = ASCIIToUTF16("john@example.com"); + expected.label = ASCIIToUTF16("john@example.com"); expected.autocomplete_attribute = "off"; EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields[2]); expected.autocomplete_attribute.clear(); expected.name = ASCIIToUTF16("phone"); expected.value = ASCIIToUTF16("1.800.555.1234"); + expected.label = ASCIIToUTF16("1.800.555.1234"); EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields[3]); } @@ -579,18 +589,21 @@ expected.name = ASCIIToUTF16("firstname"); expected.value = ASCIIToUTF16("John"); + expected.label = ASCIIToUTF16("John"); expected.form_control_type = "text"; expected.max_length = WebInputElement::defaultMaxLength(); EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields[0]); expected.name = ASCIIToUTF16("lastname"); expected.value = ASCIIToUTF16("Smith"); + expected.label = ASCIIToUTF16("Smith"); expected.form_control_type = "text"; expected.max_length = WebInputElement::defaultMaxLength(); EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields[1]); expected.name = ASCIIToUTF16("email"); expected.value = ASCIIToUTF16("john@example.com"); + expected.label = ASCIIToUTF16("john@example.com"); expected.autocomplete_attribute = "off"; expected.form_control_type = "text"; expected.max_length = WebInputElement::defaultMaxLength(); @@ -599,6 +612,7 @@ expected.name = ASCIIToUTF16("street-address"); expected.value = ASCIIToUTF16("123 Fantasy Ln.\nApt. 42"); + expected.label.clear(); expected.form_control_type = "textarea"; expected.max_length = 0; EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields[3]); @@ -1077,27 +1091,32 @@ expected.name = ASCIIToUTF16("noAC"); expected.value = ASCIIToUTF16("one"); + expected.label = ASCIIToUTF16("one"); expected.autocomplete_attribute = "off"; EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields[2]); expected.autocomplete_attribute.clear(); expected.name = ASCIIToUTF16("notenabled"); expected.value = ASCIIToUTF16("no clear"); + expected.label.clear(); EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields[3]); expected.form_control_type = "month"; expected.max_length = 0; expected.name = ASCIIToUTF16("month"); expected.value.clear(); + expected.label.clear(); EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields[4]); expected.name = ASCIIToUTF16("month-disabled"); expected.value = ASCIIToUTF16("2012-11"); + expected.label = ASCIIToUTF16("2012-11"); EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields[5]); expected.form_control_type = "textarea"; expected.name = ASCIIToUTF16("textarea"); expected.value.clear(); + expected.label.clear(); EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields[6]); expected.name = ASCIIToUTF16("textarea-disabled"); @@ -2179,14 +2198,17 @@ expected.name = ASCIIToUTF16("firstname"); expected.value = ASCIIToUTF16("John"); + expected.label = ASCIIToUTF16("John"); EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields[0]); expected.name = ASCIIToUTF16("lastname"); expected.value = ASCIIToUTF16("Smith"); + expected.label = ASCIIToUTF16("Smith"); EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields[1]); expected.name = ASCIIToUTF16("email"); expected.value = ASCIIToUTF16("john@example.com"); + expected.label = ASCIIToUTF16("john@example.com"); EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields[2]); // Second form. @@ -2201,14 +2223,17 @@ expected.name = ASCIIToUTF16("firstname"); expected.value = ASCIIToUTF16("Jack"); + expected.label = ASCIIToUTF16("Jack"); EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields2[0]); expected.name = ASCIIToUTF16("lastname"); expected.value = ASCIIToUTF16("Adams"); + expected.label = ASCIIToUTF16("Adams"); EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields2[1]); expected.name = ASCIIToUTF16("email"); expected.value = ASCIIToUTF16("jack@example.com"); + expected.label = ASCIIToUTF16("jack@example.com"); EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields2[2]); } @@ -2253,18 +2278,22 @@ expected.name = ASCIIToUTF16("firstname"); expected.value = ASCIIToUTF16("John"); + expected.label = ASCIIToUTF16("John"); EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields[0]); expected.name = ASCIIToUTF16("lastname"); expected.value = ASCIIToUTF16("Smith"); + expected.label = ASCIIToUTF16("Smith"); EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields[1]); expected.name = ASCIIToUTF16("email"); expected.value = ASCIIToUTF16("john@example.com"); + expected.label = ASCIIToUTF16("john@example.com"); EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields[2]); expected.name = ASCIIToUTF16("telephone"); expected.value = ASCIIToUTF16("12345"); + expected.label.clear(); EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields[3]); forms.clear(); @@ -2302,14 +2331,17 @@ expected.name = ASCIIToUTF16("second_firstname"); expected.value = ASCIIToUTF16("Bob"); + expected.label.clear(); EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields2[0]); expected.name = ASCIIToUTF16("second_lastname"); expected.value = ASCIIToUTF16("Hope"); + expected.label.clear(); EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields2[1]); expected.name = ASCIIToUTF16("second_email"); expected.value = ASCIIToUTF16("bobhope@example.com"); + expected.label.clear(); EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields2[2]); } @@ -3351,11 +3383,11 @@ names.push_back(ASCIIToUTF16("dayphone1")); values.push_back(base::string16()); - labels.push_back(ASCIIToUTF16("-")); + labels.push_back(ASCIIToUTF16("")); names.push_back(ASCIIToUTF16("dayphone2")); values.push_back(base::string16()); - labels.push_back(ASCIIToUTF16("-")); + labels.push_back(ASCIIToUTF16("")); names.push_back(ASCIIToUTF16("dayphone3")); values.push_back(base::string16()); @@ -3638,11 +3670,11 @@ expected.name = ASCIIToUTF16("dayphone1"); EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields[0]); - expected.label = ASCIIToUTF16("-"); + expected.label = ASCIIToUTF16(""); expected.name = ASCIIToUTF16("dayphone2"); EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields[1]); - expected.label = ASCIIToUTF16("-"); + expected.label = ASCIIToUTF16(""); expected.name = ASCIIToUTF16("dayphone3"); EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields[2]); @@ -3696,12 +3728,12 @@ expected.max_length = 3; EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields[0]); - expected.label = ASCIIToUTF16("-"); + expected.label = ASCIIToUTF16(""); expected.name = ASCIIToUTF16("dayphone2"); expected.max_length = 3; EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields[1]); - expected.label = ASCIIToUTF16("-"); + expected.label = ASCIIToUTF16(""); expected.name = ASCIIToUTF16("dayphone3"); expected.max_length = 4; EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields[2]); @@ -4012,18 +4044,21 @@ expected.name = ASCIIToUTF16("firstname"); expected.value = ASCIIToUTF16("John"); + expected.label = ASCIIToUTF16("John"); expected.form_control_type = "text"; expected.max_length = WebInputElement::defaultMaxLength(); EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields[0]); expected.name = ASCIIToUTF16("lastname"); expected.value = ASCIIToUTF16("Smith"); + expected.label = ASCIIToUTF16("Smith"); expected.form_control_type = "text"; expected.max_length = WebInputElement::defaultMaxLength(); EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields[1]); expected.name = ASCIIToUTF16("country"); expected.value = ASCIIToUTF16("Albania"); + expected.label.clear(); expected.form_control_type = "select-one"; expected.max_length = 0; EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields[2]); @@ -4043,18 +4078,21 @@ expected.name = ASCIIToUTF16("firstname"); expected.value = ASCIIToUTF16("John"); + expected.label = ASCIIToUTF16("John"); expected.form_control_type = "text"; expected.max_length = WebInputElement::defaultMaxLength(); EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields[0]); expected.name = ASCIIToUTF16("lastname"); expected.value = ASCIIToUTF16("Smith"); + expected.label = ASCIIToUTF16("Smith"); expected.form_control_type = "text"; expected.max_length = WebInputElement::defaultMaxLength(); EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields[1]); expected.name = ASCIIToUTF16("country"); expected.value = ASCIIToUTF16("AL"); + expected.label.clear(); expected.form_control_type = "select-one"; expected.max_length = 0; EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields[2]);
diff --git a/chrome/renderer/chrome_content_renderer_client.cc b/chrome/renderer/chrome_content_renderer_client.cc index adf4fd1..d331933 100644 --- a/chrome/renderer/chrome_content_renderer_client.cc +++ b/chrome/renderer/chrome_content_renderer_client.cc
@@ -933,6 +933,8 @@ base::EndsWith(app_url_host, "plus.google.com", base::CompareCase::INSENSITIVE_ASCII) || base::EndsWith(app_url_host, "plus.sandbox.google.com", + base::CompareCase::INSENSITIVE_ASCII) || + base::EndsWith(app_url_host, "hangouts.google.com", base::CompareCase::INSENSITIVE_ASCII)) && // The manifest must be loaded from the host's FileSystem. (manifest_fs_host == app_url_host);
diff --git a/chrome/renderer/chrome_render_process_observer.cc b/chrome/renderer/chrome_render_process_observer.cc index 37452b12..d8f7fb7d 100644 --- a/chrome/renderer/chrome_render_process_observer.cc +++ b/chrome/renderer/chrome_render_process_observer.cc
@@ -6,9 +6,11 @@ #include <stddef.h> #include <limits> +#include <set> #include <utility> #include <vector> +#include "base/base_switches.h" #include "base/bind.h" #include "base/command_line.h" #include "base/files/file_util.h" @@ -126,7 +128,8 @@ public: ResourceUsageReporterImpl(base::WeakPtr<ChromeRenderProcessObserver> observer, mojo::InterfaceRequest<ResourceUsageReporter> req) - : binding_(this, std::move(req)), + : workers_to_go_(0), + binding_(this, std::move(req)), observer_(observer), weak_factory_(this) {} ~ResourceUsageReporterImpl() override {} @@ -216,6 +219,8 @@ base::WeakPtr<ChromeRenderProcessObserver> observer_; base::WeakPtrFactory<ResourceUsageReporterImpl> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(ResourceUsageReporterImpl); }; void CreateResourceUsageReporter( @@ -264,13 +269,37 @@ chrome_common_media::LocalizedStringProvider); #endif - // Setup initial set of crash dump data for Field Trials in this renderer. - variations::SetVariationListCrashKeys(); - // Listen for field trial activations to report them to the browser. - base::FieldTrialList::AddObserver(this); + InitFieldTrialObserving(command_line); } -ChromeRenderProcessObserver::~ChromeRenderProcessObserver() { +ChromeRenderProcessObserver::~ChromeRenderProcessObserver() {} + +void ChromeRenderProcessObserver::InitFieldTrialObserving( + const base::CommandLine& command_line) { + // Set up initial set of crash dump data for field trials in this renderer. + variations::SetVariationListCrashKeys(); + + // Listen for field trial activations to report them to the browser. + base::FieldTrialList::AddObserver(this); + + // Some field trials may have been activated before this point. Notify the + // browser of these activations now. To detect these, take the set difference + // of currently active trials with the initially active trials. + base::FieldTrial::ActiveGroups initially_active_trials; + base::FieldTrialList::GetActiveFieldTrialGroupsFromString( + command_line.GetSwitchValueASCII(switches::kForceFieldTrials), + &initially_active_trials); + std::set<std::string> initially_active_trials_set; + for (const auto& entry : initially_active_trials) { + initially_active_trials_set.insert(std::move(entry.trial_name)); + } + + base::FieldTrial::ActiveGroups current_active_trials; + base::FieldTrialList::GetActiveFieldTrialGroups(¤t_active_trials); + for (const auto& trial : current_active_trials) { + if (!ContainsKey(initially_active_trials_set, trial.trial_name)) + OnFieldTrialGroupFinalized(trial.trial_name, trial.group_name); + } } bool ChromeRenderProcessObserver::OnControlMessageReceived(
diff --git a/chrome/renderer/chrome_render_process_observer.h b/chrome/renderer/chrome_render_process_observer.h index af0c0f9ec..7950ee7f 100644 --- a/chrome/renderer/chrome_render_process_observer.h +++ b/chrome/renderer/chrome_render_process_observer.h
@@ -19,6 +19,10 @@ class GURL; struct ContentSettings; +namespace base { +class CommandLine; +} + namespace content { class ResourceDispatcherDelegate; } @@ -42,12 +46,16 @@ const RendererContentSettingRules* content_setting_rules() const; private: - // RenderProcessObserver implementation. + // Initializes field trial state change observation and notifies the browser + // of any field trials that might have already been activated. + void InitFieldTrialObserving(const base::CommandLine& command_line); + + // content::RenderProcessObserver: bool OnControlMessageReceived(const IPC::Message& message) override; void WebKitInitialized() override; void OnRenderProcessShutdown() override; - // Observer implementation. + // base::FieldTrialList::Observer: void OnFieldTrialGroupFinalized(const std::string& trial_name, const std::string& group_name) override;
diff --git a/chrome/renderer/content_settings_observer.cc b/chrome/renderer/content_settings_observer.cc index 1e00b6c..2a2ba4e 100644 --- a/chrome/renderer/content_settings_observer.cc +++ b/chrome/renderer/content_settings_observer.cc
@@ -593,6 +593,13 @@ return true; } +void ContentSettingsObserver::didUseKeygen() { + WebFrame* frame = render_frame()->GetWebFrame(); + Send(new ChromeViewHostMsg_DidUseKeygen( + routing_id(), + GURL(frame->securityOrigin().toString()))); +} + void ContentSettingsObserver::didNotAllowPlugins() { DidBlockContentType(CONTENT_SETTINGS_TYPE_PLUGINS); }
diff --git a/chrome/renderer/content_settings_observer.h b/chrome/renderer/content_settings_observer.h index eaa939cd..b876a6c6 100644 --- a/chrome/renderer/content_settings_observer.h +++ b/chrome/renderer/content_settings_observer.h
@@ -78,6 +78,7 @@ bool allowMutationEvents(bool default_value) override; void didNotAllowPlugins() override; void didNotAllowScript() override; + void didUseKeygen() override; bool allowDisplayingInsecureContent(bool allowed_per_settings, const blink::WebSecurityOrigin& context, const blink::WebURL& url) override; @@ -151,7 +152,7 @@ typedef std::pair<GURL, bool> StoragePermissionsKey; std::map<StoragePermissionsKey, bool> cached_storage_permissions_; - // Caches the result of |AllowScript|. + // Caches the result of AllowScript. std::map<blink::WebFrame*, bool> cached_script_permissions_; std::set<std::string> temporarily_allowed_plugins_;
diff --git a/chrome/renderer/extensions/tabs_custom_bindings.cc b/chrome/renderer/extensions/tabs_custom_bindings.cc index b9d5d24aa3..2459f96 100644 --- a/chrome/renderer/extensions/tabs_custom_bindings.cc +++ b/chrome/renderer/extensions/tabs_custom_bindings.cc
@@ -49,7 +49,8 @@ std::string channel_name = *v8::String::Utf8Value(args[3]); int port_id = -1; render_frame->Send(new ExtensionHostMsg_OpenChannelToTab( - info, extension_id, channel_name, &port_id)); + render_frame->GetRoutingID(), info, extension_id, channel_name, + &port_id)); args.GetReturnValue().Set(static_cast<int32_t>(port_id)); }
diff --git a/chrome/renderer/resources/extensions/searchbox_api.js b/chrome/renderer/resources/extensions/searchbox_api.js index d99fa26..5120ff6 100644 --- a/chrome/renderer/resources/extensions/searchbox_api.js +++ b/chrome/renderer/resources/extensions/searchbox_api.js
@@ -19,7 +19,6 @@ native function GetQuery(); native function GetSearchRequestParams(); native function GetRightToLeft(); - native function GetStartMargin(); native function GetSuggestionToPrefetch(); native function IsFocused(); native function IsKeyCaptureEnabled(); @@ -34,7 +33,6 @@ this.__defineGetter__('isFocused', IsFocused); this.__defineGetter__('isKeyCaptureEnabled', IsKeyCaptureEnabled); this.__defineGetter__('rtl', GetRightToLeft); - this.__defineGetter__('startMargin', GetStartMargin); this.__defineGetter__('suggestion', GetSuggestionToPrefetch); this.__defineGetter__('value', GetQuery); Object.defineProperty(this, 'requestParams', @@ -78,7 +76,6 @@ this.onfocuschange = null; this.onkeycapturechange = null; - this.onmarginchange = null; this.onsubmit = null; this.onsuggestionchange = null;
diff --git a/chrome/renderer/searchbox/searchbox.cc b/chrome/renderer/searchbox/searchbox.cc index ed0e62a1..b629e63c 100644 --- a/chrome/renderer/searchbox/searchbox.cc +++ b/chrome/renderer/searchbox/searchbox.cc
@@ -241,8 +241,7 @@ is_key_capture_enabled_(false), display_instant_results_(false), most_visited_items_cache_(kMaxInstantMostVisitedItemCacheSize), - query_(), - start_margin_(0) { + query_() { } SearchBox::~SearchBox() { @@ -379,7 +378,6 @@ IPC_MESSAGE_HANDLER(ChromeViewMsg_HistorySyncCheckResult, OnHistorySyncCheckResult) IPC_MESSAGE_HANDLER(ChromeViewMsg_SearchBoxFocusChanged, OnFocusChanged) - IPC_MESSAGE_HANDLER(ChromeViewMsg_SearchBoxMarginChange, OnMarginChange) IPC_MESSAGE_HANDLER(ChromeViewMsg_SearchBoxMostVisitedItemsChanged, OnMostVisitedChanged) IPC_MESSAGE_HANDLER(ChromeViewMsg_SearchBoxPromoInformation, @@ -460,14 +458,6 @@ } } -void SearchBox::OnMarginChange(int margin) { - start_margin_ = margin; - if (render_view()->GetWebView() && render_view()->GetWebView()->mainFrame()) { - extensions_v8::SearchBoxExtension::DispatchMarginChange( - render_view()->GetWebView()->mainFrame()); - } -} - void SearchBox::OnMostVisitedChanged( const std::vector<InstantMostVisitedItem>& items) { std::vector<InstantMostVisitedItemIDPair> last_known_items; @@ -551,7 +541,6 @@ query_.clear(); embedded_search_request_params_ = EmbeddedSearchRequestParams(); suggestion_ = InstantSuggestion(); - start_margin_ = 0; is_focused_ = false; is_key_capture_enabled_ = false; theme_info_ = ThemeBackgroundInfo();
diff --git a/chrome/renderer/searchbox/searchbox.h b/chrome/renderer/searchbox/searchbox.h index 562c3e4..fa41434 100644 --- a/chrome/renderer/searchbox/searchbox.h +++ b/chrome/renderer/searchbox/searchbox.h
@@ -140,7 +140,6 @@ bool is_key_capture_enabled() const { return is_key_capture_enabled_; } bool display_instant_results() const { return display_instant_results_; } const base::string16& query() const { return query_; } - int start_margin() const { return start_margin_; } const InstantSuggestion& suggestion() const { return suggestion_; } private: @@ -154,7 +153,6 @@ void OnFocusChanged(OmniboxFocusState new_focus_state, OmniboxFocusChangeReason reason); void OnHistorySyncCheckResult(bool sync_history); - void OnMarginChange(int margin); void OnMostVisitedChanged( const std::vector<InstantMostVisitedItem>& items); void OnPromoInformationReceived(bool is_app_launcher_enabled); @@ -184,7 +182,6 @@ ThemeBackgroundInfo theme_info_; base::string16 query_; EmbeddedSearchRequestParams embedded_search_request_params_; - int start_margin_; InstantSuggestion suggestion_; DISALLOW_COPY_AND_ASSIGN(SearchBox);
diff --git a/chrome/renderer/searchbox/searchbox_extension.cc b/chrome/renderer/searchbox/searchbox_extension.cc index 2b20a41..5dc7ae5 100644 --- a/chrome/renderer/searchbox/searchbox_extension.cc +++ b/chrome/renderer/searchbox/searchbox_extension.cc
@@ -353,17 +353,6 @@ " true;" "}"; -static const char kDispatchMarginChangeEventScript[] = - "if (window.chrome &&" - " window.chrome.embeddedSearch &&" - " window.chrome.embeddedSearch.searchBox &&" - " window.chrome.embeddedSearch.searchBox.onmarginchange &&" - " typeof window.chrome.embeddedSearch.searchBox.onmarginchange ==" - " 'function') {" - " window.chrome.embeddedSearch.searchBox.onmarginchange();" - " true;" - "}"; - static const char kDispatchMostVisitedChangedScript[] = "if (window.chrome &&" " window.chrome.embeddedSearch &&" @@ -466,9 +455,6 @@ static void GetSearchRequestParams( const v8::FunctionCallbackInfo<v8::Value>& args); - // Gets the start-edge margin to use with extended Instant. - static void GetStartMargin(const v8::FunctionCallbackInfo<v8::Value>& args); - // Gets the current top suggestion to prefetch search results. static void GetSuggestionToPrefetch( const v8::FunctionCallbackInfo<v8::Value>& args); @@ -591,11 +577,6 @@ } // static -void SearchBoxExtension::DispatchMarginChange(blink::WebFrame* frame) { - Dispatch(frame, kDispatchMarginChangeEventScript); -} - -// static void SearchBoxExtension::DispatchMostVisitedChanged( blink::WebFrame* frame) { Dispatch(frame, kDispatchMostVisitedChangedScript); @@ -649,8 +630,6 @@ return v8::FunctionTemplate::New(isolate, GetRightToLeft); if (name->Equals(v8::String::NewFromUtf8(isolate, "GetSearchRequestParams"))) return v8::FunctionTemplate::New(isolate, GetSearchRequestParams); - if (name->Equals(v8::String::NewFromUtf8(isolate, "GetStartMargin"))) - return v8::FunctionTemplate::New(isolate, GetStartMargin); if (name->Equals(v8::String::NewFromUtf8(isolate, "GetSuggestionToPrefetch"))) return v8::FunctionTemplate::New(isolate, GetSuggestionToPrefetch); if (name->Equals(v8::String::NewFromUtf8(isolate, "GetThemeBackgroundInfo"))) @@ -894,15 +873,6 @@ } // static -void SearchBoxExtensionWrapper::GetStartMargin( - const v8::FunctionCallbackInfo<v8::Value>& args) { - content::RenderView* render_view = GetRenderView(); - if (!render_view) return; - args.GetReturnValue().Set(static_cast<int32_t>( - SearchBox::Get(render_view)->start_margin())); -} - -// static void SearchBoxExtensionWrapper::GetSuggestionToPrefetch( const v8::FunctionCallbackInfo<v8::Value>& args) { content::RenderView* render_view = GetRenderView();
diff --git a/chrome/renderer/searchbox/searchbox_extension.h b/chrome/renderer/searchbox/searchbox_extension.h index c63e1d76..1ce9a95 100644 --- a/chrome/renderer/searchbox/searchbox_extension.h +++ b/chrome/renderer/searchbox/searchbox_extension.h
@@ -40,7 +40,6 @@ static void DispatchInputCancel(blink::WebFrame* frame); static void DispatchInputStart(blink::WebFrame* frame); static void DispatchKeyCaptureChange(blink::WebFrame* frame); - static void DispatchMarginChange(blink::WebFrame* frame); static void DispatchMostVisitedChanged(blink::WebFrame* frame); static void DispatchSubmit(blink::WebFrame* frame); static void DispatchSuggestionChange(blink::WebFrame* frame);
diff --git a/chrome/renderer/spellchecker/spellcheck_worditerator_unittest.cc b/chrome/renderer/spellchecker/spellcheck_worditerator_unittest.cc index 4cf35ce3..70ed965a5 100644 --- a/chrome/renderer/spellchecker/spellcheck_worditerator_unittest.cc +++ b/chrome/renderer/spellchecker/spellcheck_worditerator_unittest.cc
@@ -17,6 +17,7 @@ #include "testing/gtest/include/gtest/gtest.h" using base::i18n::BreakIterator; +using WordIteratorStatus = SpellcheckWordIterator::WordIteratorStatus; namespace { @@ -32,6 +33,16 @@ return attribute.GetRuleSet(true); } +WordIteratorStatus GetNextNonSkippableWord(SpellcheckWordIterator* iterator, + base::string16* word_string, + int* word_start, + int* word_length) { + WordIteratorStatus status = SpellcheckWordIterator::IS_SKIPPABLE; + while (status == SpellcheckWordIterator::IS_SKIPPABLE) + status = iterator->GetNextWord(word_string, word_start, word_length); + return status; +} + } // namespace // Tests whether or not our SpellcheckWordIterator can extract words used by the @@ -144,13 +155,13 @@ base::string16(1, ' '), base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); base::string16 actual_word; - int actual_start, actual_end; + int actual_start, actual_len; size_t index = 0; for (SpellcheckWordIterator::WordIteratorStatus status = - iterator.GetNextWord(&actual_word, &actual_start, &actual_end); + iterator.GetNextWord(&actual_word, &actual_start, &actual_len); status != SpellcheckWordIterator::IS_END_OF_TEXT; status = - iterator.GetNextWord(&actual_word, &actual_start, &actual_end)) { + iterator.GetNextWord(&actual_word, &actual_start, &actual_len)) { if (status == SpellcheckWordIterator::WordIteratorStatus::IS_SKIPPABLE) continue; @@ -180,18 +191,13 @@ // iterator.GetNextWord() calls get stuck in an infinite loop. Therefore, this // test succeeds if this call returns without timeouts. base::string16 actual_word; - int actual_start, actual_end; - SpellcheckWordIterator::WordIteratorStatus status; - for (status = iterator.GetNextWord(&actual_word, &actual_start, &actual_end); - status == SpellcheckWordIterator::IS_SKIPPABLE; - status = - iterator.GetNextWord(&actual_word, &actual_start, &actual_end)) { - continue; - } + int actual_start, actual_len; + WordIteratorStatus status = GetNextNonSkippableWord( + &iterator, &actual_word, &actual_start, &actual_len); EXPECT_EQ(SpellcheckWordIterator::WordIteratorStatus::IS_END_OF_TEXT, status); EXPECT_EQ(0, actual_start); - EXPECT_EQ(0, actual_end); + EXPECT_EQ(0, actual_len); } // Vertify our SpellcheckWordIterator can treat ASCII numbers as word characters @@ -249,15 +255,9 @@ EXPECT_TRUE(iterator.SetText(input_word.c_str(), input_word.length())); base::string16 actual_word; - int actual_start, actual_end; - SpellcheckWordIterator::WordIteratorStatus status; - for (status = - iterator.GetNextWord(&actual_word, &actual_start, &actual_end); - status == SpellcheckWordIterator::IS_SKIPPABLE; - status = - iterator.GetNextWord(&actual_word, &actual_start, &actual_end)) { - continue; - } + int actual_start, actual_len; + WordIteratorStatus status = GetNextNonSkippableWord( + &iterator, &actual_word, &actual_start, &actual_len); EXPECT_EQ(SpellcheckWordIterator::WordIteratorStatus::IS_WORD, status); if (kTestCases[i].left_to_right) @@ -267,59 +267,48 @@ } } -// Vertify SpellcheckWordIterator treats typographical apostrophe as a part of +// Verify SpellcheckWordIterator treats typographical apostrophe as a part of // the word. TEST(SpellcheckWordIteratorTest, TypographicalApostropheIsPartOfWord) { static const struct { const char* language; - const wchar_t* word; + const wchar_t* input; + const wchar_t* expected; } kTestCases[] = { - // Typewriter apostrophe: - { - "en-AU", L"you're" - }, { - "en-CA", L"you're" - }, { - "en-GB", L"you're" - }, { - "en-US", L"you're" - }, - // Typographical apostrophe: - { - "en-AU", L"you\x2019re" - }, { - "en-CA", L"you\x2019re" - }, { - "en-GB", L"you\x2019re" - }, { - "en-US", L"you\x2019re" - }, + // Typewriter apostrophe: + {"en-AU", L"you're", L"you're"}, + {"en-CA", L"you're", L"you're"}, + {"en-GB", L"you're", L"you're"}, + {"en-US", L"you're", L"you're"}, + {"en-US", L"!!!!you're", L"you're"}, + // Typographical apostrophe: + {"en-AU", L"you\x2019re", L"you\x2019re"}, + {"en-CA", L"you\x2019re", L"you\x2019re"}, + {"en-GB", L"you\x2019re", L"you\x2019re"}, + {"en-US", L"you\x2019re", L"you\x2019re"}, + {"en-US", L"....you\x2019re", L"you\x2019re"}, }; for (size_t i = 0; i < arraysize(kTestCases); ++i) { SpellcheckCharAttribute attributes; attributes.SetDefaultLanguage(kTestCases[i].language); - base::string16 input_word(base::WideToUTF16(kTestCases[i].word)); + base::string16 input_word(base::WideToUTF16(kTestCases[i].input)); + base::string16 expected_word(base::WideToUTF16(kTestCases[i].expected)); SpellcheckWordIterator iterator; EXPECT_TRUE(iterator.Initialize(&attributes, true)); EXPECT_TRUE(iterator.SetText(input_word.c_str(), input_word.length())); base::string16 actual_word; - int actual_start, actual_end; - SpellcheckWordIterator::WordIteratorStatus status; - for (status = - iterator.GetNextWord(&actual_word, &actual_start, &actual_end); - status == SpellcheckWordIterator::IS_SKIPPABLE; - iterator.GetNextWord(&actual_word, &actual_start, &actual_end)) { - continue; - } + int actual_start, actual_len; + WordIteratorStatus status = GetNextNonSkippableWord( + &iterator, &actual_word, &actual_start, &actual_len); EXPECT_EQ(SpellcheckWordIterator::WordIteratorStatus::IS_WORD, status); - EXPECT_EQ(input_word, actual_word); - EXPECT_EQ(0, actual_start); - EXPECT_EQ(input_word.length(), - static_cast<base::string16::size_type>(actual_end)); + EXPECT_EQ(expected_word, actual_word); + EXPECT_LE(0, actual_start); + EXPECT_EQ(expected_word.length(), + static_cast<base::string16::size_type>(actual_len)); } }
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 1e5fa35c..e8d2a0f 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -675,16 +675,10 @@ group("telemetry_perf_unittests") { deps = [ - "//tools/perf/chrome_telemetry_build:telemetry_chrome_test", + "//tools/perf:perf", ] data = [ - "//tools/perf/", - - # Field trial config - "//tools/variations/", - "//testing/variations/", - # For isolate contract. "//testing/scripts/common.py", "//testing/xvfb.py", @@ -1234,6 +1228,12 @@ ".", "//chrome") } + if (enable_service_discovery) { + sources += rebase_path( + chrome_tests_gypi_values.chrome_browser_tests_service_discovery_sources, + ".", + "//chrome") + } if (enable_supervised_users) { sources += rebase_path( chrome_tests_gypi_values.chrome_browser_tests_supervised_user_sources, @@ -1719,6 +1719,12 @@ ".", "//chrome") } + if (enable_service_discovery) { + sources += rebase_path( + chrome_tests_unit_gypi_values.chrome_unit_tests_extensions_service_discovery_sources, + ".", + "//chrome") + } if (!is_chromeos) { sources += rebase_path( chrome_tests_unit_gypi_values.chrome_unit_tests_extensions_non_chromeos_sources, @@ -2034,8 +2040,6 @@ } if (is_android || is_ios) { sources -= [ - "../browser/devtools/device/cast_device_provider_unittest.cc", - "../browser/devtools/device/webrtc/devtools_bridge_instances_request_unittest.cc", "../browser/ui/bookmarks/bookmark_ui_utils_desktop_unittest.cc", "../browser/ui/sync/sync_promo_ui_unittest.cc", ]
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeActivityTestCaseBase.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeActivityTestCaseBase.java index 770bda1..139aad819 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeActivityTestCaseBase.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeActivityTestCaseBase.java
@@ -764,16 +764,15 @@ * Returns the infobars being displayed by the current tab, or null if they don't exist. */ protected List<InfoBar> getInfoBars() { - Tab currentTab = getActivity().getActivityTab(); - if (currentTab == null) { - return null; - } - - if (currentTab.getInfoBarContainer() != null) { - return currentTab.getInfoBarContainer().getInfoBars(); - } else { - return null; - } + return ThreadUtils.runOnUiThreadBlockingNoException(new Callable<List<InfoBar>>() { + @Override + public List<InfoBar> call() throws Exception { + Tab currentTab = getActivity().getActivityTab(); + assertNotNull(currentTab); + assertNotNull(currentTab.getInfoBarContainer()); + return currentTab.getInfoBarContainer().getInfoBarsForTesting(); + } + }); } /**
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/signin/SigninTestUtil.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/signin/SigninTestUtil.java index e408a9e..41ff1ad 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/signin/SigninTestUtil.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/signin/SigninTestUtil.java
@@ -5,7 +5,6 @@ package org.chromium.chrome.test.util.browser.signin; import android.accounts.Account; -import android.app.Activity; import android.app.Instrumentation; import android.content.Context; import android.preference.PreferenceManager; @@ -115,7 +114,7 @@ } @Override - public boolean canBeUsed(Context ctx, Activity activity) { + public boolean canBeUsed(Context ctx) { return true; } });
diff --git a/chrome/test/base/testing_browser_process.cc b/chrome/test/base/testing_browser_process.cc index c799f31f..69a89d928 100644 --- a/chrome/test/base/testing_browser_process.cc +++ b/chrome/test/base/testing_browser_process.cc
@@ -73,6 +73,7 @@ local_state_(nullptr), io_thread_(nullptr), system_request_context_(nullptr), + rappor_service_(nullptr), platform_part_(new TestingBrowserProcessPlatformPart()) { #if defined(ENABLE_EXTENSIONS) extensions_browser_client_.reset( @@ -112,7 +113,7 @@ } rappor::RapporService* TestingBrowserProcess::rappor_service() { - return nullptr; + return rappor_service_; } IOThread* TestingBrowserProcess::io_thread() { @@ -453,6 +454,11 @@ #endif } +void TestingBrowserProcess::SetRapporService( + rappor::RapporService* rappor_service) { + rappor_service_ = rappor_service; +} + /////////////////////////////////////////////////////////////////////////////// TestingBrowserProcessInitializer::TestingBrowserProcessInitializer() {
diff --git a/chrome/test/base/testing_browser_process.h b/chrome/test/base/testing_browser_process.h index e63c13a..0a185e8 100644 --- a/chrome/test/base/testing_browser_process.h +++ b/chrome/test/base/testing_browser_process.h
@@ -139,6 +139,7 @@ void SetSystemRequestContext(net::URLRequestContextGetter* context_getter); void SetNotificationUIManager( scoped_ptr<NotificationUIManager> notification_ui_manager); + void SetRapporService(rappor::RapporService* rappor_service); void ShutdownBrowserPolicyConnector(); private: @@ -180,6 +181,7 @@ PrefService* local_state_; IOThread* io_thread_; net::URLRequestContextGetter* system_request_context_; + rappor::RapporService* rappor_service_; scoped_ptr<BrowserProcessPlatformPart> platform_part_;
diff --git a/chrome/test/chromedriver/archive.py b/chrome/test/chromedriver/archive.py index 17aaf2c..eabac1b2 100644 --- a/chrome/test/chromedriver/archive.py +++ b/chrome/test/chromedriver/archive.py
@@ -10,9 +10,9 @@ import util -CHROME_45_REVISION = '338390' CHROME_46_REVISION = '344997' CHROME_47_REVISION = '352825' +CHROME_48_REVISION = '359663' _SITE = 'http://commondatastorage.googleapis.com'
diff --git a/chrome/test/chromedriver/chrome/version.cc b/chrome/test/chromedriver/chrome/version.cc index 591d74e4..edcb058d 100644 --- a/chrome/test/chromedriver/chrome/version.cc +++ b/chrome/test/chromedriver/chrome/version.cc
@@ -9,7 +9,7 @@ namespace { // This variable must be able to be found and parsed by the upload script. -const int kMinimumSupportedChromeVersion[] = {45, 0, 2454, 0}; +const int kMinimumSupportedChromeVersion[] = {46, 0, 2490, 0}; } // namespace
diff --git a/chrome/test/chromedriver/test/run_all_tests.py b/chrome/test/chromedriver/test/run_all_tests.py index 1907c8a4..ef4cd24 100755 --- a/chrome/test/chromedriver/test/run_all_tests.py +++ b/chrome/test/chromedriver/test/run_all_tests.py
@@ -191,9 +191,9 @@ latest_snapshot_revision = archive.GetLatestSnapshotVersion() versions = [ ['HEAD', latest_snapshot_revision], + ['48', archive.CHROME_48_REVISION], ['47', archive.CHROME_47_REVISION], ['46', archive.CHROME_46_REVISION], - ['45', archive.CHROME_45_REVISION], ] code = 0 for version in versions:
diff --git a/chrome/test/data/autofill/heuristics/output/01_misc_phones.out b/chrome/test/data/autofill/heuristics/output/01_misc_phones.out index ff6c3be6..23e2e1c 100644 --- a/chrome/test/data/autofill/heuristics/output/01_misc_phones.out +++ b/chrome/test/data/autofill/heuristics/output/01_misc_phones.out
@@ -8,20 +8,20 @@ PHONE_HOME_CITY_CODE | areacode1 | Area Code: | | firstname_1-default PHONE_HOME_NUMBER | phone1 | Phone: | | firstname_1-default PHONE_HOME_CITY_CODE | hphone1 | Phone: | | firstname_1-default -PHONE_HOME_NUMBER | hphone2 | - | | firstname_1-default -PHONE_HOME_NUMBER | hphone3 | - | | firstname_1-default +PHONE_HOME_NUMBER | hphone2 | | | firstname_1-default +PHONE_HOME_NUMBER | hphone3 | | | firstname_1-default UNKNOWN_TYPE | hphone4 | ext.: | | firstname_1-default PHONE_HOME_CITY_CODE | hphone1a | Phone: ( | | firstname_1-default -PHONE_HOME_NUMBER | hphone2a | ) | | firstname_1-default -PHONE_HOME_NUMBER | hphone3a | - | | firstname_1-default +PHONE_HOME_NUMBER | hphone2a | | | firstname_1-default +PHONE_HOME_NUMBER | hphone3a | | | firstname_1-default UNKNOWN_TYPE | hphone4a | ext.: | | firstname_1-default PHONE_HOME_COUNTRY_CODE | hphone1b | Phone: | | firstname_1-default PHONE_HOME_CITY_CODE | hphone1b | | | firstname_1-default -PHONE_HOME_NUMBER | hphone2b | - | | firstname_1-default -PHONE_HOME_NUMBER | hphone3b | - | | firstname_1-default +PHONE_HOME_NUMBER | hphone2b | | | firstname_1-default +PHONE_HOME_NUMBER | hphone3b | | | firstname_1-default UNKNOWN_TYPE | hphone4b | ext.: | | firstname_1-default PHONE_HOME_COUNTRY_CODE | hphone1c | Phone: | | firstname_1-default -PHONE_HOME_CITY_CODE | hphone1c | ( | | firstname_1-default -PHONE_HOME_NUMBER | hphone2c | ) | | firstname_1-default -PHONE_HOME_NUMBER | hphone3c | - | | firstname_1-default +PHONE_HOME_CITY_CODE | hphone1c | | | firstname_1-default +PHONE_HOME_NUMBER | hphone2c | | | firstname_1-default +PHONE_HOME_NUMBER | hphone3c | | | firstname_1-default UNKNOWN_TYPE | hphone4c | ext.: | | firstname_1-default
diff --git a/chrome/test/data/autofill/heuristics/output/02_checkout_advanceautoparts.com.out b/chrome/test/data/autofill/heuristics/output/02_checkout_advanceautoparts.com.out index 90f00068..7fae45a 100644 --- a/chrome/test/data/autofill/heuristics/output/02_checkout_advanceautoparts.com.out +++ b/chrome/test/data/autofill/heuristics/output/02_checkout_advanceautoparts.com.out
@@ -6,8 +6,8 @@ ADDRESS_HOME_CITY | billCity | *City: | | billingShippingSame_1-default ADDRESS_HOME_STATE | billState | *State: | AL | billingShippingSame_1-default ADDRESS_HOME_ZIP | billZipCode | *Zip Code: | | billingShippingSame_1-default -PHONE_HOME_CITY_CODE | billDayPhonePart1 | ( | | billingShippingSame_1-default -PHONE_HOME_NUMBER | billDayPhonePart2 | ) | | billingShippingSame_1-default +PHONE_HOME_CITY_CODE | billDayPhonePart1 | *Day Phone: | | billingShippingSame_1-default +PHONE_HOME_NUMBER | billDayPhonePart2 | *Day Phone: | | billingShippingSame_1-default PHONE_HOME_NUMBER | billDayPhonePart3 | *Day Phone: | | billingShippingSame_1-default EMAIL_ADDRESS | billEmail | *Email Address: | | billingShippingSame_1-default UNKNOWN_TYPE | sendMeEmail | Yes, please send me emails about news, special offers, exclusives and promotions from Advance Auto Parts. See our | checked | billingShippingSame_1-default @@ -20,9 +20,9 @@ ADDRESS_HOME_CITY | shipCity | *City: | | shipFirstName_1-default ADDRESS_HOME_STATE | shipState | *State: | AL | shipFirstName_1-default ADDRESS_HOME_ZIP | shipZipCode | *Zip Code: | | shipFirstName_1-default -PHONE_HOME_CITY_CODE | shipDayPhonePart1 | ( | | shipFirstName_1-default -PHONE_HOME_NUMBER | shipDayPhonePart2 | ) | | shipFirstName_1-default +PHONE_HOME_CITY_CODE | shipDayPhonePart1 | *Day Phone: | | shipFirstName_1-default +PHONE_HOME_NUMBER | shipDayPhonePart2 | *Day Phone: | | shipFirstName_1-default PHONE_HOME_NUMBER | shipDayPhonePart3 | *Day Phone: | | shipFirstName_1-default -PHONE_HOME_CITY_CODE | shipNightPhonePart1 | ( | | shipFirstName_1-default -PHONE_HOME_NUMBER | shipNightPhonePart2 | ) | | shipFirstName_1-default +PHONE_HOME_CITY_CODE | shipNightPhonePart1 | Night Phone: | | shipFirstName_1-default +PHONE_HOME_NUMBER | shipNightPhonePart2 | Night Phone: | | shipFirstName_1-default PHONE_HOME_NUMBER | shipNightPhonePart3 | Night Phone: | | shipFirstName_1-default
diff --git a/chrome/test/data/autofill/heuristics/output/02_checkout_ae.com.out b/chrome/test/data/autofill/heuristics/output/02_checkout_ae.com.out index f1dbbe5..32055e8 100644 --- a/chrome/test/data/autofill/heuristics/output/02_checkout_ae.com.out +++ b/chrome/test/data/autofill/heuristics/output/02_checkout_ae.com.out
@@ -1,5 +1,5 @@ NAME_FIRST | firstName | Search wish lists by name | First Name | firstName_1-default -NAME_LAST | lastName | | Last Name | firstName_1-default +NAME_LAST | lastName | Last Name | Last Name | firstName_1-default EMAIL_ADDRESS | email | Or search wish lists by email | Email | firstName_1-default ADDRESS_HOME_COUNTRY | countryType | Country Type | usa | countryType_1-default ADDRESS_HOME_COUNTRY | country | Country, APO/FPO | US | countryType_1-default
diff --git a/chrome/test/data/autofill/heuristics/output/02_checkout_cafepress.com.out b/chrome/test/data/autofill/heuristics/output/02_checkout_cafepress.com.out index 4e480e6..29f68c8 100644 --- a/chrome/test/data/autofill/heuristics/output/02_checkout_cafepress.com.out +++ b/chrome/test/data/autofill/heuristics/output/02_checkout_cafepress.com.out
@@ -10,7 +10,7 @@ PHONE_HOME_WHOLE_NUMBER | BillPhone | Phone Number* | | BillName_1-default EMAIL_ADDRESS | BillEmail | Email Address* | | BillName_1-default UNKNOWN_TYPE | cbStoreSpecial | | on | BillName_1-default -UNKNOWN_TYPE | ShipDestination | | billaddress | BillName_1-default +UNKNOWN_TYPE | ShipDestination | billaddress | billaddress | BillName_1-default UNKNOWN_TYPE | ShipDestination | Ship to my billing address | shipaddress | BillName_1-default NAME_FULL | ShipName | Recipient Name* | | ShipName_1-default ADDRESS_HOME_COUNTRY | ShipCountry | Country* | UNITED STATES | ShipName_1-default @@ -25,12 +25,12 @@ UNKNOWN_TYPE | countdown | You have | 300 | ShipName_1-default UNKNOWN_TYPE | ApplyGiftWrap | (+$0.00) | on | ShipName_1-default UNKNOWN_TYPE | txtCoupon | Apply Promo Code | | ShipName_1-default -UNKNOWN_TYPE | PaymentMethod | | PayByCafeCash | ShipName_1-default -UNKNOWN_TYPE | PaymentMethod | | PayByGC | ShipName_1-default -UNKNOWN_TYPE | PaymentMethod | | PayByCCGC | ShipName_1-default -UNKNOWN_TYPE | PaymentMethod | | PayByCC | ShipName_1-default +UNKNOWN_TYPE | PaymentMethod | PayByCafeCash | PayByCafeCash | ShipName_1-default +UNKNOWN_TYPE | PaymentMethod | PayByGC | PayByGC | ShipName_1-default +UNKNOWN_TYPE | PaymentMethod | PayByCCGC | PayByCCGC | ShipName_1-default +UNKNOWN_TYPE | PaymentMethod | PayByCC | PayByCC | ShipName_1-default CREDIT_CARD_NUMBER | txtCCAccount | Credit Card No.* | | ShipName_1-cc CREDIT_CARD_EXP_MONTH | ccExp$MonthDrop | Expiration Date* | 06 (June) | ShipName_1-cc CREDIT_CARD_EXP_4_DIGIT_YEAR | ccExp$YearDrop | Expiration Date* | 2011 | ShipName_1-cc UNKNOWN_TYPE | PaymentMethod | Expiration Date* | PayByCheck | ShipName_1-default -UNKNOWN_TYPE | PaymentMethod | | PayByPayPal | ShipName_1-default +UNKNOWN_TYPE | PaymentMethod | PayByPayPal | PayByPayPal | ShipName_1-default
diff --git a/chrome/test/data/autofill/heuristics/output/03_checkout_hsn.com.out b/chrome/test/data/autofill/heuristics/output/03_checkout_hsn.com.out index caa43c6..2bcfab9 100644 --- a/chrome/test/data/autofill/heuristics/output/03_checkout_hsn.com.out +++ b/chrome/test/data/autofill/heuristics/output/03_checkout_hsn.com.out
@@ -7,13 +7,13 @@ ADDRESS_HOME_STATE | Body$BillingAddress$_state | State | | Body$BillingIsShippingCheckboxB_1-default ADDRESS_HOME_ZIP | Body$BillingAddress$_zipcode | Zip Code | | Body$BillingIsShippingCheckboxB_1-default PHONE_HOME_WHOLE_NUMBER | Body$BillingAddress$_PrimaryPhone | Primary Phone | | Body$BillingIsShippingCheckboxB_1-default -UNKNOWN_TYPE | Body$BillingAddress$rdoPrimary | | H | Body$BillingIsShippingCheckboxB_1-default -UNKNOWN_TYPE | Body$BillingAddress$rdoPrimary | | M | Body$BillingIsShippingCheckboxB_1-default -UNKNOWN_TYPE | Body$BillingAddress$rdoPrimary | | W | Body$BillingIsShippingCheckboxB_1-default +UNKNOWN_TYPE | Body$BillingAddress$rdoPrimary | H | H | Body$BillingIsShippingCheckboxB_1-default +UNKNOWN_TYPE | Body$BillingAddress$rdoPrimary | M | M | Body$BillingIsShippingCheckboxB_1-default +UNKNOWN_TYPE | Body$BillingAddress$rdoPrimary | W | W | Body$BillingIsShippingCheckboxB_1-default PHONE_HOME_WHOLE_NUMBER | Body$BillingAddress$_Alt1Phone | Alternate Phone2(optional) | | Body$BillingIsShippingCheckboxB_1-default -UNKNOWN_TYPE | Body$BillingAddress$rdoAlt1 | | H | Body$BillingIsShippingCheckboxB_1-default -UNKNOWN_TYPE | Body$BillingAddress$rdoAlt1 | | M | Body$BillingIsShippingCheckboxB_1-default -UNKNOWN_TYPE | Body$BillingAddress$rdoAlt1 | | W | Body$BillingIsShippingCheckboxB_1-default +UNKNOWN_TYPE | Body$BillingAddress$rdoAlt1 | H | H | Body$BillingIsShippingCheckboxB_1-default +UNKNOWN_TYPE | Body$BillingAddress$rdoAlt1 | M | M | Body$BillingIsShippingCheckboxB_1-default +UNKNOWN_TYPE | Body$BillingAddress$rdoAlt1 | W | W | Body$BillingIsShippingCheckboxB_1-default UNKNOWN_TYPE | Body$MobileAlerts | Send me special promotion mobile alerts | on | Body$BillingIsShippingCheckboxB_1-default EMAIL_ADDRESS | Body$NewEmailAddress2 | Email Address | | Body$BillingIsShippingCheckboxB_1-default UNKNOWN_TYPE | Body$WeeklyNewsletterSignup12 | Email me weekly HSN newsletters and special offers | on | Body$BillingIsShippingCheckboxB_1-default
diff --git a/chrome/test/data/autofill/heuristics/output/04_checkout_jr.com.out b/chrome/test/data/autofill/heuristics/output/04_checkout_jr.com.out index d0f8f9a..bea2013 100644 --- a/chrome/test/data/autofill/heuristics/output/04_checkout_jr.com.out +++ b/chrome/test/data/autofill/heuristics/output/04_checkout_jr.com.out
@@ -1,25 +1,25 @@ -NAME_FIRST | billingAddress.firstName | * | | billingAddress.firstName_1-default -NAME_LAST | billingAddress.lastName | * | | billingAddress.firstName_1-default -ADDRESS_HOME_LINE1 | billingAddress.address1 | * | | billingAddress.firstName_1-default +NAME_FIRST | billingAddress.firstName | | | billingAddress.firstName_1-default +NAME_LAST | billingAddress.lastName | | | billingAddress.firstName_1-default +ADDRESS_HOME_LINE1 | billingAddress.address1 | | | billingAddress.firstName_1-default ADDRESS_HOME_LINE2 | billingAddress.address2 | Street address or P.O. box | | billingAddress.firstName_1-default -ADDRESS_HOME_CITY | billingAddress.city | * | | billingAddress.firstName_1-default -ADDRESS_HOME_STATE | billingAddress.stateCode | * | XX | billingAddress.firstName_1-default -ADDRESS_HOME_ZIP | billingAddress.postalCode | * | | billingAddress.firstName_1-default -ADDRESS_HOME_COUNTRY | billingAddress.country | * | US | billingAddress.firstName_1-default -PHONE_HOME_WHOLE_NUMBER | billingAddress.phoneNumber | * | | billingAddress.firstName_1-default -EMAIL_ADDRESS | customer.emailAddress | * | | billingAddress.firstName_1-default +ADDRESS_HOME_CITY | billingAddress.city | | | billingAddress.firstName_1-default +ADDRESS_HOME_STATE | billingAddress.stateCode | | XX | billingAddress.firstName_1-default +ADDRESS_HOME_ZIP | billingAddress.postalCode | | | billingAddress.firstName_1-default +ADDRESS_HOME_COUNTRY | billingAddress.country | | US | billingAddress.firstName_1-default +PHONE_HOME_WHOLE_NUMBER | billingAddress.phoneNumber | | | billingAddress.firstName_1-default +EMAIL_ADDRESS | customer.emailAddress | | | billingAddress.firstName_1-default UNKNOWN_TYPE | customer.optIn | Yes, send me J&R's promotional email newsletter. | on | billingAddress.firstName_1-default UNKNOWN_TYPE | storePickup | Pickup In-Store (Park Row, New York NY) | on | billingAddress.firstName_1-default UNKNOWN_TYPE | shipToBillingAddress | Ship to my billing address | on | billingAddress.firstName_1-default -NAME_FIRST | shippingAddress.firstName | * | | shippingAddress.firstName_1-default -NAME_LAST | shippingAddress.lastName | * | | shippingAddress.firstName_1-default -ADDRESS_HOME_LINE1 | shippingAddress.address1 | * | | shippingAddress.firstName_1-default +NAME_FIRST | shippingAddress.firstName | | | shippingAddress.firstName_1-default +NAME_LAST | shippingAddress.lastName | | | shippingAddress.firstName_1-default +ADDRESS_HOME_LINE1 | shippingAddress.address1 | | | shippingAddress.firstName_1-default ADDRESS_HOME_LINE2 | shippingAddress.address2 | Street address or P.O. box | | shippingAddress.firstName_1-default -ADDRESS_HOME_CITY | shippingAddress.city | * | | shippingAddress.firstName_1-default -ADDRESS_HOME_STATE | shippingAddress.stateCode | * | XX | shippingAddress.firstName_1-default -ADDRESS_HOME_ZIP | shippingAddress.postalCode | * | | shippingAddress.firstName_1-default -ADDRESS_HOME_COUNTRY | shippingAddress.country | * | US | shippingAddress.firstName_1-default -PHONE_HOME_WHOLE_NUMBER | shippingAddress.phoneNumber | * | | shippingAddress.firstName_1-default +ADDRESS_HOME_CITY | shippingAddress.city | | | shippingAddress.firstName_1-default +ADDRESS_HOME_STATE | shippingAddress.stateCode | | XX | shippingAddress.firstName_1-default +ADDRESS_HOME_ZIP | shippingAddress.postalCode | | | shippingAddress.firstName_1-default +ADDRESS_HOME_COUNTRY | shippingAddress.country | | US | shippingAddress.firstName_1-default +PHONE_HOME_WHOLE_NUMBER | shippingAddress.phoneNumber | | | shippingAddress.firstName_1-default UNKNOWN_TYPE | customOrderHeader.internationalBilling | International Billing | | shippingAddress.firstName_1-default UNKNOWN_TYPE | customOrderHeader.salespersonNumber | Salesperson Number | | shippingAddress.firstName_1-default UNKNOWN_TYPE | customOrderHeader.giftFromName | Gift From | | shippingAddress.firstName_1-default
diff --git a/chrome/test/data/autofill/heuristics/output/04_checkout_lowes.com.out b/chrome/test/data/autofill/heuristics/output/04_checkout_lowes.com.out index 70cb59b..e7ee5e7 100644 --- a/chrome/test/data/autofill/heuristics/output/04_checkout_lowes.com.out +++ b/chrome/test/data/autofill/heuristics/output/04_checkout_lowes.com.out
@@ -1,4 +1,4 @@ -ADDRESS_HOME_COUNTRY | country | | USA | country_1-default +ADDRESS_HOME_COUNTRY | country | USA | USA | country_1-default ADDRESS_HOME_LINE1 | addressField2 | Address Name: | | country_1-default NAME_FIRST | firstName | First Name: | | country_1-default NAME_LAST | lastName | Last Name: | | country_1-default @@ -15,4 +15,4 @@ PHONE_HOME_NUMBER | billphone2 | Contact Phone: | | taxGeoCode_1-default PHONE_HOME_NUMBER | billphone3 | Contact Phone: | | taxGeoCode_1-default EMAIL_ADDRESS | selfAddress | Please enter the phone number and e-mail address associated with this billing address.E-mail Address: Contact Phone: | 0 | selfAddress_1-default -UNKNOWN_TYPE | save-address | | on | selfAddress_1-default +UNKNOWN_TYPE | save-address | on | on | selfAddress_1-default
diff --git a/chrome/test/data/autofill/heuristics/output/05_checkout_macys.com.out b/chrome/test/data/autofill/heuristics/output/05_checkout_macys.com.out index c4f70574..6b1bb3b 100644 --- a/chrome/test/data/autofill/heuristics/output/05_checkout_macys.com.out +++ b/chrome/test/data/autofill/heuristics/output/05_checkout_macys.com.out
@@ -7,5 +7,5 @@ ADDRESS_HOME_STATE | currentShipment.shipmentAddress.state | State: | NOSELECTION | selectedShippingAddress_1-default ADDRESS_HOME_ZIP | currentShipment.shipmentAddress.zipCode | ZipCode: | | selectedShippingAddress_1-default PHONE_HOME_CITY_CODE | currentShipment.shipmentAddress.dayPhone.areaCode | Phone: | | selectedShippingAddress_1-default -PHONE_HOME_NUMBER | currentShipment.shipmentAddress.dayPhone.exchangeNbr | - | | selectedShippingAddress_1-default -PHONE_HOME_NUMBER | currentShipment.shipmentAddress.dayPhone.subscriberNbr | - | | selectedShippingAddress_1-default +PHONE_HOME_NUMBER | currentShipment.shipmentAddress.dayPhone.exchangeNbr | * Phone: | | selectedShippingAddress_1-default +PHONE_HOME_WHOLE_NUMBER | currentShipment.shipmentAddress.dayPhone.subscriberNbr | * Phone: | | selectedShippingAddress_1-default
diff --git a/chrome/test/data/autofill/heuristics/output/05_checkout_overstock.com.out b/chrome/test/data/autofill/heuristics/output/05_checkout_overstock.com.out index f43cff3..ac977b8 100644 --- a/chrome/test/data/autofill/heuristics/output/05_checkout_overstock.com.out +++ b/chrome/test/data/autofill/heuristics/output/05_checkout_overstock.com.out
@@ -18,12 +18,12 @@ ADDRESS_HOME_STATE | state | State | CA | ShippingFirstName_1-default ADDRESS_HOME_ZIP | zip | Zip | 95014 | ShippingFirstName_1-default UNKNOWN_TYPE | product6496917 | Black-plated Tungsten Carbide Comfort Fit Band (8 mm) Options: 10 1 | GROUND6496917 | ShippingFirstName_1-default -UNKNOWN_TYPE | CC | | CreditCardValue | ShippingFirstName_1-default +UNKNOWN_TYPE | CC | CreditCardValue | CreditCardValue | ShippingFirstName_1-default CREDIT_CARD_NUMBER | CC_number | Credit Card #: | | ShippingFirstName_1-cc CREDIT_CARD_EXP_MONTH | exp_month | Expiration Date: | 0 | ShippingFirstName_1-cc CREDIT_CARD_EXP_4_DIGIT_YEAR | exp_year | Expiration Date: | | ShippingFirstName_1-cc -UNKNOWN_TYPE | CC | | PayPal | ShippingFirstName_1-default -UNKNOWN_TYPE | CC | | bml | ShippingFirstName_1-default +UNKNOWN_TYPE | CC | PayPal | PayPal | ShippingFirstName_1-default +UNKNOWN_TYPE | CC | bml | bml | ShippingFirstName_1-default UNKNOWN_TYPE | UsePromoCode | Use Promo Code | on | ShippingFirstName_1-default UNKNOWN_TYPE | PromoCode | See Terms | | ShippingFirstName_1-default UNKNOWN_TYPE | UseGiftCards | Use Gift Card | on | ShippingFirstName_1-default
diff --git a/chrome/test/data/autofill/heuristics/output/06_checkout_urbanoutfitters.com.out b/chrome/test/data/autofill/heuristics/output/06_checkout_urbanoutfitters.com.out index 50a3489..aefdadda 100644 --- a/chrome/test/data/autofill/heuristics/output/06_checkout_urbanoutfitters.com.out +++ b/chrome/test/data/autofill/heuristics/output/06_checkout_urbanoutfitters.com.out
@@ -1,33 +1,33 @@ UNKNOWN_TYPE | shipto | Select a Saved Shipping Address | | shipto_1-default -NAME_FIRST | shippingFirstName | | First Name | shipto_1-default -NAME_LAST | shippingLastName | | Last Name | shipto_1-default -ADDRESS_HOME_LINE1 | shippingAddress | | Street Address | shipto_1-default +NAME_FIRST | shippingFirstName | First Name | First Name | shipto_1-default +NAME_LAST | shippingLastName | Last Name | Last Name | shipto_1-default +ADDRESS_HOME_LINE1 | shippingAddress | Street Address | Street Address | shipto_1-default UNKNOWN_TYPE | shippingPobox | This address is a P.O. Box | true | shipto_1-default -ADDRESS_HOME_LINE2 | shippingAddress2 | | Apt / Flr / Bldg (optional) | shipto_1-default -ADDRESS_HOME_CITY | shippingCity | | City | shipto_1-default +ADDRESS_HOME_LINE2 | shippingAddress2 | Apt / Flr / Bldg (optional) | Apt / Flr / Bldg (optional) | shipto_1-default +ADDRESS_HOME_CITY | shippingCity | City | City | shipto_1-default ADDRESS_HOME_STATE | shippingStates | | | shipto_1-default -ADDRESS_HOME_ZIP | shippingPostalCode | | Postal Code | shipto_1-default +ADDRESS_HOME_ZIP | shippingPostalCode | Postal Code | Postal Code | shipto_1-default ADDRESS_HOME_COUNTRY | shippingCountries | | | shipto_1-default -PHONE_HOME_WHOLE_NUMBER | shippingPhone | | Phone | shipto_1-default -PHONE_HOME_WHOLE_NUMBER | altShippingPhone | | Alternate Phone (optional) | shipto_1-default +PHONE_HOME_WHOLE_NUMBER | shippingPhone | Phone | Phone | shipto_1-default +PHONE_HOME_WHOLE_NUMBER | altShippingPhone | Alternate Phone (optional) | Alternate Phone (optional) | shipto_1-default UNKNOWN_TYPE | billingIsShipping | My billing address is the same as my shipping address | true | shipto_1-default UNKNOWN_TYPE | defaultShipping | Make this my default shipping address | true | shipto_1-default -NAME_FIRST | billingFirstName | | First Name | billingFirstName_1-default -NAME_LAST | billingLastName | | Last Name | billingFirstName_1-default -ADDRESS_HOME_LINE1 | billingAddress | | Street Address | billingFirstName_1-default +NAME_FIRST | billingFirstName | First Name | First Name | billingFirstName_1-default +NAME_LAST | billingLastName | Last Name | Last Name | billingFirstName_1-default +ADDRESS_HOME_LINE1 | billingAddress | Street Address | Street Address | billingFirstName_1-default UNKNOWN_TYPE | billingPobox | This address is a P.O. Box | true | billingFirstName_1-default -ADDRESS_HOME_LINE2 | billingAddress2 | | Apt / Flr / Bldg (optional) | billingFirstName_1-default -ADDRESS_HOME_CITY | billingCity | | City | billingFirstName_1-default +ADDRESS_HOME_LINE2 | billingAddress2 | Apt / Flr / Bldg (optional) | Apt / Flr / Bldg (optional) | billingFirstName_1-default +ADDRESS_HOME_CITY | billingCity | City | City | billingFirstName_1-default ADDRESS_HOME_STATE | billingStates | | | billingFirstName_1-default -ADDRESS_HOME_ZIP | billingPostalCode | | Postal Code | billingFirstName_1-default +ADDRESS_HOME_ZIP | billingPostalCode | Postal Code | Postal Code | billingFirstName_1-default ADDRESS_HOME_COUNTRY | billingCountries | | | billingFirstName_1-default -PHONE_HOME_WHOLE_NUMBER | billingPhone | | Phone | billingFirstName_1-default -PHONE_HOME_WHOLE_NUMBER | altBillingPhone | | Alternate Phone (optional) | billingFirstName_1-default +PHONE_HOME_WHOLE_NUMBER | billingPhone | Phone | Phone | billingFirstName_1-default +PHONE_HOME_WHOLE_NUMBER | altBillingPhone | Alternate Phone (optional) | Alternate Phone (optional) | billingFirstName_1-default UNKNOWN_TYPE | defaultBilling | Make this my default billing address | true | billingFirstName_1-default UNKNOWN_TYPE | savedCreditCard | | | billingFirstName_1-default CREDIT_CARD_TYPE | payment_cardtype | | | billingFirstName_1-cc -CREDIT_CARD_NUMBER | payment_acctnum | | Card Number (no spaces or dashes) | billingFirstName_1-cc +CREDIT_CARD_NUMBER | payment_acctnum | Card Number (no spaces or dashes) | Card Number (no spaces or dashes) | billingFirstName_1-cc CREDIT_CARD_EXP_MONTH | expmonth | | | billingFirstName_1-cc CREDIT_CARD_EXP_4_DIGIT_YEAR | expyear | | | billingFirstName_1-cc -CREDIT_CARD_VERIFICATION_CODE | payment_cidnew | | CID / Security Code | billingFirstName_1-cc +CREDIT_CARD_VERIFICATION_CODE | payment_cidnew | CID / Security Code | CID / Security Code | billingFirstName_1-cc UNKNOWN_TYPE | makeDefaultCreditCard | Make this my default credit card | true | billingFirstName_1-default
diff --git a/chrome/test/data/autofill/heuristics/output/09_register_ebay.com.out b/chrome/test/data/autofill/heuristics/output/09_register_ebay.com.out index e9df41a..4d639fd4 100644 --- a/chrome/test/data/autofill/heuristics/output/09_register_ebay.com.out +++ b/chrome/test/data/autofill/heuristics/output/09_register_ebay.com.out
@@ -7,8 +7,8 @@ ADDRESS_HOME_ZIP | zip | ZIP / Postal code | | firstname_1-default ADDRESS_HOME_COUNTRY | countryId | Country or region | 1 | firstname_1-default PHONE_HOME_CITY_CODE | dayphone1 | Primary telephone number | | firstname_1-default -PHONE_HOME_NUMBER | dayphone2 | - | | firstname_1-default -PHONE_HOME_NUMBER | dayphone3 | - | | firstname_1-default +PHONE_HOME_NUMBER | dayphone2 | Primary telephone number | | firstname_1-default +PHONE_HOME_NUMBER | dayphone3 | Primary telephone number | | firstname_1-default UNKNOWN_TYPE | dayphone4 | ext.: | | firstname_1-default EMAIL_ADDRESS | email | Email address | | firstname_1-default EMAIL_ADDRESS | retype_email | Re-enter email address | | firstname_1-default
diff --git a/chrome/test/data/autofill/heuristics/output/11_register_macys.com.out b/chrome/test/data/autofill/heuristics/output/11_register_macys.com.out index a67d6be..142ad425 100644 --- a/chrome/test/data/autofill/heuristics/output/11_register_macys.com.out +++ b/chrome/test/data/autofill/heuristics/output/11_register_macys.com.out
@@ -14,8 +14,8 @@ UNKNOWN_TYPE | NewsLetter | We'll let you know about exclusive sales and events,both online and in-store. | NewsLetter | FirstName_1-default UNKNOWN_TYPE | MobileMarketing | Yes, please text me about exclusive sales and events, both online and in-store. We'll send your first text message within 48 hours. | MobileMarketing | FirstName_1-default PHONE_HOME_CITY_CODE | MobilePhoneAreaCode | | | FirstName_1-default -PHONE_HOME_NUMBER | MobilePhoneExchangeNbr | - | | FirstName_1-default -PHONE_HOME_NUMBER | MobilePhoneSubscriberNbr | - | | FirstName_1-default +PHONE_HOME_NUMBER | MobilePhoneExchangeNbr | | | FirstName_1-default +PHONE_HOME_WHOLE_NUMBER | MobilePhoneSubscriberNbr | | | FirstName_1-default UNKNOWN_TYPE | addacard | Yes, I'd like to add my Macy's Card to my profile. | on | FirstName_1-default UNKNOWN_TYPE | MaskedAccountNumber | Macy's Account Number: | | FirstName_1-default UNKNOWN_TYPE | SSN4 | Last 4 digits of SSN: | | FirstName_1-default
diff --git a/chrome/test/data/autofill/heuristics/output/11_register_newegg.com.out b/chrome/test/data/autofill/heuristics/output/11_register_newegg.com.out index e072d2e..f2a35232 100644 --- a/chrome/test/data/autofill/heuristics/output/11_register_newegg.com.out +++ b/chrome/test/data/autofill/heuristics/output/11_register_newegg.com.out
@@ -31,8 +31,8 @@ ADDRESS_HOME_STATE | SState | State* | AK | LoginName_1-default ADDRESS_HOME_ZIP | SZip | Zip Code* | | LoginName_1-default PHONE_HOME_CITY_CODE | ShippingPhone_tel1 | Shipping Phone* | | LoginName_1-default -PHONE_HOME_NUMBER | ShippingPhone_tel2 | ) | | LoginName_1-default -PHONE_HOME_NUMBER | ShippingPhone_tel3 | - | | LoginName_1-default +PHONE_HOME_NUMBER | ShippingPhone_tel2 | | | LoginName_1-default +PHONE_HOME_NUMBER | ShippingPhone_tel3 | | | LoginName_1-default UNKNOWN_TYPE | ShippingPhone_ext1 | Ext | | LoginName_1-default UNKNOWN_TYPE | custtype | Is this purchase for personal or business use? | 200 | LoginName_1-default UNKNOWN_TYPE | Age | Age | | LoginName_1-default
diff --git a/chrome/test/data/autofill/heuristics/output/12_register_officedepot.com.out b/chrome/test/data/autofill/heuristics/output/12_register_officedepot.com.out index f94b063..4c34df8 100644 --- a/chrome/test/data/autofill/heuristics/output/12_register_officedepot.com.out +++ b/chrome/test/data/autofill/heuristics/output/12_register_officedepot.com.out
@@ -8,12 +8,12 @@ ADDRESS_HOME_STATE | addrsForm[0].state | *State | {blank} | addrsForm[0].firstName_1-default ADDRESS_HOME_ZIP | addrsForm[0].postalCode1 | *Zip Code | | addrsForm[0].firstName_1-default PHONE_HOME_CITY_CODE | addrsForm[0].phoneNumber1 | *Phone Number: | | addrsForm[0].firstName_1-default -PHONE_HOME_NUMBER | addrsForm[0].phoneNumber2 | - | | addrsForm[0].firstName_1-default -PHONE_HOME_NUMBER | addrsForm[0].phoneNumber3 | - | | addrsForm[0].firstName_1-default +PHONE_HOME_NUMBER | addrsForm[0].phoneNumber2 | *Phone Number: | | addrsForm[0].firstName_1-default +PHONE_HOME_NUMBER | addrsForm[0].phoneNumber3 | *Phone Number: | | addrsForm[0].firstName_1-default UNKNOWN_TYPE | addrsForm[0].phoneNumber4 | ext. | | addrsForm[0].firstName_1-default UNKNOWN_TYPE | addrsForm[0].faxNumber1 | Fax: | | addrsForm[0].firstName_1-default -UNKNOWN_TYPE | addrsForm[0].faxNumber2 | - | | addrsForm[0].firstName_1-default -UNKNOWN_TYPE | addrsForm[0].faxNumber3 | - | | addrsForm[0].firstName_1-default +UNKNOWN_TYPE | addrsForm[0].faxNumber2 | Fax: | | addrsForm[0].firstName_1-default +UNKNOWN_TYPE | addrsForm[0].faxNumber3 | Fax: | | addrsForm[0].firstName_1-default EMAIL_ADDRESS | addrsForm[0].email | *Email Address: | | addrsForm[0].firstName_1-default CREDIT_CARD_TYPE | paymentFormInfo.creditCardType | Credit Card Type: | | addrsForm[0].firstName_1-cc CREDIT_CARD_NUMBER | paymentFormInfo.creditCardNumber | Credit Card Number: | | addrsForm[0].firstName_1-cc @@ -31,8 +31,8 @@ ADDRESS_HOME_STATE | addrsForm[2].state | *State | {blank} | addrsForm[2].firstName_1-default ADDRESS_HOME_ZIP | addrsForm[2].postalCode1 | *Zip Code | | addrsForm[2].firstName_1-default PHONE_HOME_CITY_CODE | addrsForm[2].phoneNumber1 | *Phone Number: | | addrsForm[2].firstName_1-default -PHONE_HOME_NUMBER | addrsForm[2].phoneNumber2 | - | | addrsForm[2].firstName_1-default -PHONE_HOME_NUMBER | addrsForm[2].phoneNumber3 | - | | addrsForm[2].firstName_1-default +PHONE_HOME_NUMBER | addrsForm[2].phoneNumber2 | *Phone Number: | | addrsForm[2].firstName_1-default +PHONE_HOME_NUMBER | addrsForm[2].phoneNumber3 | *Phone Number: | | addrsForm[2].firstName_1-default UNKNOWN_TYPE | addrsForm[2].phoneNumber4 | ext. | | addrsForm[2].firstName_1-default EMAIL_ADDRESS | addrsForm[2].email | *Email Address: | | addrsForm[2].firstName_1-default UNKNOWN_TYPE | loginForm.loginName | *Login Name: | | addrsForm[2].firstName_1-default
diff --git a/chrome/test/data/autofill/heuristics/output/12_register_rediff.com.out b/chrome/test/data/autofill/heuristics/output/12_register_rediff.com.out index 20c1ed7c..de6431d 100644 --- a/chrome/test/data/autofill/heuristics/output/12_register_rediff.com.out +++ b/chrome/test/data/autofill/heuristics/output/12_register_rediff.com.out
@@ -1,18 +1,18 @@ -NAME_FULL | name | : | | name_1-default -UNKNOWN_TYPE | login | : | | name_1-default -UNKNOWN_TYPE | passwd | : | | name_1-default -UNKNOWN_TYPE | confirm_passwd | : | | name_1-default -EMAIL_ADDRESS | altemail | : | | name_1-default +NAME_FULL | name | Create a Rediffmail account | | name_1-default +NAME_FULL | login | Full Name:Enter your first name & last nameEg. Sameer Bhagwat | | name_1-default +UNKNOWN_TYPE | passwd | Choose a Rediffmail ID:@rediffmail.com | | name_1-default +UNKNOWN_TYPE | confirm_passwd | Password:6-12 characters allowed | | name_1-default +EMAIL_ADDRESS | altemail | | | name_1-default UNKNOWN_TYPE | chk_altemail | | on | name_1-default -UNKNOWN_TYPE | hintq | : | | name_1-default -UNKNOWN_TYPE | hinta | : | | name_1-default -UNKNOWN_TYPE | mothername | : | | name_1-default -UNKNOWN_TYPE | DOB_Day | : | | name_1-default -UNKNOWN_TYPE | DOB_Month | : | | name_1-default -UNKNOWN_TYPE | DOB_Year | : | | name_1-default +UNKNOWN_TYPE | hintq | | | name_1-default +UNKNOWN_TYPE | hinta | Select a Security Question: | | name_1-default +UNKNOWN_TYPE | mothername | Enter an Answer: | | name_1-default +UNKNOWN_TYPE | DOB_Day | Select a Security QuestionEnter an Answer | | name_1-default +UNKNOWN_TYPE | DOB_Month | Select a Security QuestionEnter an Answer | | name_1-default +UNKNOWN_TYPE | DOB_Year | Select a Security QuestionEnter an Answer | | name_1-default UNKNOWN_TYPE | gender | Male | m | name_1-default UNKNOWN_TYPE | gender | Female | f | name_1-default -ADDRESS_HOME_COUNTRY | country | : | 99 | name_1-default -ADDRESS_HOME_CITY | city | : | | name_1-default +ADDRESS_HOME_COUNTRY | country | Gender: | 99 | name_1-default +ADDRESS_HOME_CITY | city | | | name_1-default UNKNOWN_TYPE | othercity | City : | | name_1-default -UNKNOWN_TYPE | 75cd7feb6ce926e1efbb8b96c0fb71c0 | : | | name_1-default +ADDRESS_HOME_CITY | 75cd7feb6ce926e1efbb8b96c0fb71c0 | City : | | name_1-default
diff --git a/chrome/test/data/autofill/heuristics/output/15_crbug_52198.out b/chrome/test/data/autofill/heuristics/output/15_crbug_52198.out index c61e5ec73..337d250 100644 --- a/chrome/test/data/autofill/heuristics/output/15_crbug_52198.out +++ b/chrome/test/data/autofill/heuristics/output/15_crbug_52198.out
@@ -11,8 +11,8 @@ ADDRESS_HOME_STATE | stateOrProvinceOfBirth | State or Province of Birth: (only if born in the US or Canada) | | firstName_1-default ADDRESS_HOME_COUNTRY | countryOfBirth | Country of Birth: | | firstName_1-default UNKNOWN_TYPE | studentSSNa | U.S. Social Security Number: (Why do we ask for your SSN?) | | firstName_1-default -UNKNOWN_TYPE | studentSSNb | - | | firstName_1-default -UNKNOWN_TYPE | studentSSNc | - | | firstName_1-default +UNKNOWN_TYPE | studentSSNb | | | firstName_1-default +UNKNOWN_TYPE | studentSSNc | | | firstName_1-default UNKNOWN_TYPE | idCardNumber | UT Austin ID Card Number: | | firstName_1-default EMAIL_ADDRESS | emailAddress | E-mail Address: | | firstName_1-default EMAIL_ADDRESS | emailAddressVerify | Verify Your E-mail Address: | | firstName_1-default
diff --git a/chrome/test/data/autofill/heuristics/output/16_crbug_98269.out b/chrome/test/data/autofill/heuristics/output/16_crbug_98269.out index af6cb1c..0a4bcd8 100644 --- a/chrome/test/data/autofill/heuristics/output/16_crbug_98269.out +++ b/chrome/test/data/autofill/heuristics/output/16_crbug_98269.out
@@ -1,4 +1,4 @@ -UNKNOWN_TYPE | PaymentMethod | | BL | PaymentMethod_1-default +UNKNOWN_TYPE | PaymentMethod | BL | BL | PaymentMethod_1-default PHONE_HOME_CITY_CODE | txtHomePhone1 | * Home Phone: | | PaymentMethod_1-default PHONE_HOME_NUMBER | txtHomePhone2 | * Home Phone: | | PaymentMethod_1-default PHONE_HOME_NUMBER | txtHomePhone3 | * Home Phone: | | PaymentMethod_1-default @@ -8,8 +8,8 @@ UNKNOWN_TYPE | selBirthDate | * Date of Birth: | Date | PaymentMethod_1-default UNKNOWN_TYPE | selBirthYear | * Date of Birth: | Year | PaymentMethod_1-default UNKNOWN_TYPE | chkTAC | I agree to have the | on | PaymentMethod_1-default -UNKNOWN_TYPE | PaymentMethod | | CK | PaymentMethod_1-default -UNKNOWN_TYPE | PaymentMethod | | AddNew | PaymentMethod_1-default +UNKNOWN_TYPE | PaymentMethod | CK | CK | PaymentMethod_1-default +UNKNOWN_TYPE | PaymentMethod | AddNew | AddNew | PaymentMethod_1-default CREDIT_CARD_TYPE | cardType | Type: | VI | PaymentMethod_1-cc CREDIT_CARD_NUMBER | CreditCardNumber | Number: | | PaymentMethod_1-cc CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR | CreditCardExpYYMM | Expiration: | 092011 | PaymentMethod_1-cc
diff --git a/chrome/test/data/autofill/heuristics/output/20_register_epson.com.mx.out b/chrome/test/data/autofill/heuristics/output/20_register_epson.com.mx.out index 8d33cc7..5d56a1b5 100644 --- a/chrome/test/data/autofill/heuristics/output/20_register_epson.com.mx.out +++ b/chrome/test/data/autofill/heuristics/output/20_register_epson.com.mx.out
@@ -1,5 +1,5 @@ UNKNOWN_TYPE | doAction | | | doAction_1-default -ADDRESS_HOME_COUNTRY | idPaiseReg | | MX | doAction_1-default +ADDRESS_HOME_COUNTRY | idPaiseReg | MX | MX | doAction_1-default UNKNOWN_TYPE | fechaCompra | *dd/mm/yyyy | | doAction_1-default UNKNOWN_TYPE | serialNumber | Serial * | | doAction_1-default UNKNOWN_TYPE | idProducto | Serial * | | doAction_1-default
diff --git a/chrome/test/data/autofill/heuristics/output/21_checkout_m_macys.com.out b/chrome/test/data/autofill/heuristics/output/21_checkout_m_macys.com.out index 309407e..bb9d4a73 100644 --- a/chrome/test/data/autofill/heuristics/output/21_checkout_m_macys.com.out +++ b/chrome/test/data/autofill/heuristics/output/21_checkout_m_macys.com.out
@@ -13,8 +13,8 @@ ADDRESS_HOME_ZIP | creditCard.billingContact.address.postalCode | Zip code: | | creditCard.cardType.code_1-default EMAIL_ADDRESS | user.email | email address: | | creditCard.cardType.code_1-default PHONE_HOME_CITY_CODE | user.phone.areaCode | phone: | | creditCard.cardType.code_1-default -PHONE_HOME_NUMBER | user.phone.exchangeNumber | – | | creditCard.cardType.code_1-default -PHONE_HOME_WHOLE_NUMBER | user.phone.subscriberNumber | – | | creditCard.cardType.code_1-default +PHONE_HOME_NUMBER | user.phone.exchangeNumber | phone:Please enter your phone number | | creditCard.cardType.code_1-default +PHONE_HOME_WHOLE_NUMBER | user.phone.subscriberNumber | phone:Please enter your phone number | | creditCard.cardType.code_1-default UNKNOWN_TYPE | user.profile.createAccount | Yes! Create an account for me at macys.com | true | creditCard.cardType.code_1-default EMAIL_ADDRESS | user.profile.email | email address: | | user.profile.email_1-default EMAIL_ADDRESS | user.profile.confirmEmail | Confirm email address: | | user.profile.email_1-default
diff --git a/chrome/test/data/autofill/heuristics/output/21_checkout_peapod.com.out b/chrome/test/data/autofill/heuristics/output/21_checkout_peapod.com.out index 8ceafcb..e12dcb85 100644 --- a/chrome/test/data/autofill/heuristics/output/21_checkout_peapod.com.out +++ b/chrome/test/data/autofill/heuristics/output/21_checkout_peapod.com.out
@@ -1,18 +1,18 @@ UNKNOWN_TYPE | | My billing address and delivery address are the same. | on | _1-default UNKNOWN_TYPE | billTitle | Title: | Ms. | _1-default -NAME_FIRST | billFirstName | | Shorty | _1-default +NAME_FIRST | billFirstName | Shorty | Shorty | _1-default NAME_LAST | billLastName | Last Name: | Nge | _1-default ADDRESS_HOME_LINE1 | billAddressLine1 | Street Address: | 340 Main | _1-default ADDRESS_HOME_LINE2 | billAddressLine2 | Address Line 2: | Apt 2 | _1-default ADDRESS_HOME_CITY | billCity | City: | Agawam | _1-default -ADDRESS_HOME_STATE | billState | | MA | _1-default +ADDRESS_HOME_STATE | billState | MA | MA | _1-default ADDRESS_HOME_ZIP | billZip | Zip Code: | 01001 | _1-default PHONE_HOME_CITY_CODE | HomeArea | Contact Phone: | 310 | _1-default -PHONE_HOME_NUMBER | HomePrefix | - | 555 | _1-default -PHONE_HOME_NUMBER | HomeSuffix | - | 1212 | _1-default +PHONE_HOME_NUMBER | HomePrefix | Contact Phone: | 555 | _1-default +PHONE_HOME_NUMBER | HomeSuffix | Contact Phone: | 1212 | _1-default CREDIT_CARD_TYPE | /peapod/handler/iditarod/CheckoutRegistrationHandler.creditCardType | Card Type: | | _1-cc CREDIT_CARD_NUMBER | cardNum | | | _1-cc CREDIT_CARD_VERIFICATION_CODE | cid | | | _1-cc CREDIT_CARD_EXP_MONTH | /peapod/handler/iditarod/CheckoutRegistrationHandler.expirationMonth | Expiration Date: | 0 | _1-cc CREDIT_CARD_EXP_4_DIGIT_YEAR | /peapod/handler/iditarod/CheckoutRegistrationHandler.expirationYear | / | 0 | _1-cc -CREDIT_CARD_NAME | cardName | | Shorty Nge | _1-cc +CREDIT_CARD_NAME | cardName | Shorty Nge | Shorty Nge | _1-cc
diff --git a/chrome/test/data/autofill/heuristics/output/23_checkout_m_amazon.com.out b/chrome/test/data/autofill/heuristics/output/23_checkout_m_amazon.com.out new file mode 100644 index 0000000..805a18e --- /dev/null +++ b/chrome/test/data/autofill/heuristics/output/23_checkout_m_amazon.com.out
@@ -0,0 +1,15 @@ +NAME_FULL | enterAddressFullName | Full name | | enterAddressFullName_1-default +ADDRESS_HOME_LINE1 | enterAddressAddressLine1 | Address line 1 | | enterAddressFullName_1-default +ADDRESS_HOME_LINE2 | enterAddressAddressLine2 | Address line 2 | | enterAddressFullName_1-default +ADDRESS_HOME_CITY | enterAddressCity | City | | enterAddressFullName_1-default +ADDRESS_HOME_STATE | enterAddressStateOrRegion | State/Province/Region | | enterAddressFullName_1-default +ADDRESS_HOME_ZIP | enterAddressPostalCode | ZIP | | enterAddressFullName_1-default +UNKNOWN_TYPE | enterAddressTaxId | | | enterAddressFullName_1-default +PHONE_HOME_WHOLE_NUMBER | enterAddressPhoneNumber | Phone number | | enterAddressFullName_1-default +ADDRESS_HOME_COUNTRY | enterAddressCountryCode | | US | enterAddressFullName_1-default +UNKNOWN_TYPE | AddressType | Optional Delivery Preferences | OTH | enterAddressFullName_1-default +UNKNOWN_TYPE | GateCode | Security Access Code | | enterAddressFullName_1-default +CREDIT_CARD_NAME | name | Name on card | | name_1-cc +CREDIT_CARD_NUMBER | addCreditCardNumber | Card number | | name_1-cc +CREDIT_CARD_EXP_MONTH | month | Expiration date | 1 | name_1-cc +CREDIT_CARD_EXP_4_DIGIT_YEAR | year | Expiration date | 2014 | name_1-cc
diff --git a/chrome/test/data/autofill/heuristics/output/bug_465576.out b/chrome/test/data/autofill/heuristics/output/bug_465576.out index 0577aad..6cb528a 100644 --- a/chrome/test/data/autofill/heuristics/output/bug_465576.out +++ b/chrome/test/data/autofill/heuristics/output/bug_465576.out
@@ -1,4 +1,4 @@ -CREDIT_CARD_TYPE | cardTypeSelect | : | Visa | cardTypeSelect_1-cc +CREDIT_CARD_TYPE | cardTypeSelect | | Visa | cardTypeSelect_1-cc CREDIT_CARD_NUMBER | creditCardNumber | Card Number * | | cardTypeSelect_1-cc CREDIT_CARD_EXP_MONTH | expirationMonth | Expiry Date * | | cardTypeSelect_1-cc CREDIT_CARD_EXP_4_DIGIT_YEAR | expirationYear | Expiry Date * | | cardTypeSelect_1-cc
diff --git a/chrome/test/data/autofill/heuristics/output/bug_465587.out b/chrome/test/data/autofill/heuristics/output/bug_465587.out index 7bc8116c..504c0fa7 100644 --- a/chrome/test/data/autofill/heuristics/output/bug_465587.out +++ b/chrome/test/data/autofill/heuristics/output/bug_465587.out
@@ -7,7 +7,7 @@ CREDIT_CARD_EXP_MONTH | /bodybuilding/commerce/order/purchase/CardPaymentInfoFormHandler.billingInfo.creditCard.expirationMonth | Expiration Date | 01 | /bodybuilding/commerce/order/purchase/CardPaymentInfoFormHandler.billingInfo.paymentType_1-cc CREDIT_CARD_EXP_4_DIGIT_YEAR | /bodybuilding/commerce/order/purchase/CardPaymentInfoFormHandler.billingInfo.creditCard.expirationYear | Expiration Date | 2015 | /bodybuilding/commerce/order/purchase/CardPaymentInfoFormHandler.billingInfo.paymentType_1-cc CREDIT_CARD_VERIFICATION_CODE | secureid | CVC/CVV | | /bodybuilding/commerce/order/purchase/CardPaymentInfoFormHandler.billingInfo.paymentType_1-cc -UNKNOWN_TYPE | /bodybuilding/commerce/order/purchase/CardPaymentInfoFormHandler.billingInfo.billingSameAsShipping | | true | /bodybuilding/commerce/order/purchase/CardPaymentInfoFormHandler.billingInfo.paymentType_1-default +UNKNOWN_TYPE | /bodybuilding/commerce/order/purchase/CardPaymentInfoFormHandler.billingInfo.billingSameAsShipping | true | true | /bodybuilding/commerce/order/purchase/CardPaymentInfoFormHandler.billingInfo.paymentType_1-default NAME_FIRST | /bodybuilding/commerce/order/purchase/CardPaymentInfoFormHandler.billingInfo.creditCard.billingAddress.firstName | First Name | | /bodybuilding/commerce/order/purchase/CardPaymentInfoFormHandler.billingInfo.paymentType_1-default NAME_LAST | /bodybuilding/commerce/order/purchase/CardPaymentInfoFormHandler.billingInfo.creditCard.billingAddress.lastName | Last Name | | /bodybuilding/commerce/order/purchase/CardPaymentInfoFormHandler.billingInfo.paymentType_1-default UNKNOWN_TYPE | /bodybuilding/commerce/order/purchase/CardPaymentInfoFormHandler.billingInfo.militaryAddressInd | APO FPO DPO | APO | /bodybuilding/commerce/order/purchase/CardPaymentInfoFormHandler.billingInfo.paymentType_1-default
diff --git a/chrome/test/data/chromeos/oobe_webui_browsertest.js b/chrome/test/data/chromeos/oobe_webui_browsertest.js index e2c4ce57..c14bff61 100644 --- a/chrome/test/data/chromeos/oobe_webui_browsertest.js +++ b/chrome/test/data/chromeos/oobe_webui_browsertest.js
@@ -57,6 +57,62 @@ this.accessibilityAuditConfig.ignoreSelectors( 'focusableElementNotVisibleAndNotAriaHidden', '#iconButton'); + + // Enable when failure is resolved. + // AX_ARIA_02: http://crbug.com/560932 + this.accessibilityAuditConfig.ignoreSelectors( + 'nonExistentAriaRelatedElement', + '#cancelConfirmDlg'); + + var requiredOwnedAriaRoleMissingSelectors = [ + '#networks-list-dropdown-container', + '#offline-networks-list-dropdown-container', + '#supervised-user-creation-image-grid', + 'body > .decorated', + ]; + + // Enable when failure is resolved. + // AX_ARIA_08: http://crbug.com/560924 + this.accessibilityAuditConfig.ignoreSelectors( + 'requiredOwnedAriaRoleMissing', + requiredOwnedAriaRoleMissingSelectors); + + var badAriaAttributeSelectors = [ + '#forgotPasswordDlg', + '#cancelConfirmDlg', + ]; + + // Enable when failure is resolved. + // AX_ARIA_11: http://crbug.com/560935 + this.accessibilityAuditConfig.ignoreSelectors( + 'badAriaAttribute', + badAriaAttributeSelectors); + + var tabIndexGreaterThanZeroSelectors = [ + '#user-image-grid', + '#discard-photo', + '#take-photo', + '#flip-photo', + ]; + + // Enable when failure is resolved. + // AX_FOCUS_03: http://crbug.com/560928 + this.accessibilityAuditConfig.ignoreSelectors( + 'tabIndexGreaterThanZero', + tabIndexGreaterThanZeroSelectors); + + var controlsWithoutLabelSelectors = [ + '#supervised-user-creation-managers-pane', + '#supervised-user-creation-name', + '#supervised-user-creation-password', + '#supervised-user-creation-password-confirm', + ]; + + // Enable when failure is resolved. + // AX_TEXT_01: http://crbug.com/560939 + this.accessibilityAuditConfig.ignoreSelectors( + 'controlsWithoutLabel', + controlsWithoutLabelSelectors); }, };
diff --git a/chrome/test/data/diagnostics/user/Default/Preferences b/chrome/test/data/diagnostics/user/Default/Preferences index 0718051c..a941f16 100644 --- a/chrome/test/data/diagnostics/user/Default/Preferences +++ b/chrome/test/data/diagnostics/user/Default/Preferences
@@ -22,7 +22,7 @@ "encodings": "UTF-8", "icon_url": "http://www.google.com/favicon.ico", "id": "2", - "instant_url": "{google:baseURL}webhp?sourceid=chrome-instant&{google:RLZ}{google:forceInstantResults}{google:instantExtendedEnabledParameter}{google:ntpIsThemedParameter}{google:omniboxStartMarginParameter}ie={inputEncoding}", + "instant_url": "{google:baseURL}webhp?sourceid=chrome-instant&{google:RLZ}{google:forceInstantResults}{google:instantExtendedEnabledParameter}ie={inputEncoding}", "keyword": "google.com", "name": "Google", "prepopulate_id": "1",
diff --git a/chrome/test/data/extensions/api_test/browser_action/missing_icon/icon24.png b/chrome/test/data/extensions/api_test/browser_action/missing_icon/icon24.png deleted file mode 100644 index 84c4be34..0000000 --- a/chrome/test/data/extensions/api_test/browser_action/missing_icon/icon24.png +++ /dev/null Binary files differ
diff --git a/chrome/test/data/extensions/api_test/browser_action/missing_icon/icon38.png b/chrome/test/data/extensions/api_test/browser_action/missing_icon/icon38.png deleted file mode 100644 index 84c4be34..0000000 --- a/chrome/test/data/extensions/api_test/browser_action/missing_icon/icon38.png +++ /dev/null Binary files differ
diff --git a/chrome/test/data/extensions/api_test/browser_action/missing_icon/manifest.json b/chrome/test/data/extensions/api_test/browser_action/missing_icon/manifest.json deleted file mode 100644 index 7f6df457..0000000 --- a/chrome/test/data/extensions/api_test/browser_action/missing_icon/manifest.json +++ /dev/null
@@ -1,12 +0,0 @@ -{ - "name": "A test extension that tests multiple browser action icons", - "version": "1.0", - "manifest_version": 2, - "browser_action": { - "default_icon": { - "19": "icon19.png", - "24": "icon24.png", - "38": "icon38.png" - } - } -}
diff --git a/chrome/test/data/extensions/api_test/messaging/connect/frame.js b/chrome/test/data/extensions/api_test/messaging/connect/frame.js index b7a3c4f..a6f9df1c3 100644 --- a/chrome/test/data/extensions/api_test/messaging/connect/frame.js +++ b/chrome/test/data/extensions/api_test/messaging/connect/frame.js
@@ -9,9 +9,16 @@ // This number is used in test.js to identify messages from this frame. var test_id = location.search.slice(-1); port.postMessage('from_' + test_id); + } else if (msg.testConnectChildFrameAndNavigate) { + location.search = '?testConnectChildFrameAndNavigateDone'; } }); }); // continuation of testSendMessageFromFrame() -chrome.runtime.sendMessage({frameUrl: location.href}); +if (location.search.lastIndexOf('?testSendMessageFromFrame', 0) === 0) { + chrome.runtime.sendMessage({frameUrl: location.href}); +} else if (location.search === '?testConnectChildFrameAndNavigateSetup') { + // continuation of connectChildFrameAndNavigate() 1/2 + chrome.runtime.sendMessage('testConnectChildFrameAndNavigateSetupDone'); +}
diff --git a/chrome/test/data/extensions/api_test/messaging/connect/manifest.json b/chrome/test/data/extensions/api_test/messaging/connect/manifest.json index abb898b..e9af6db 100644 --- a/chrome/test/data/extensions/api_test/messaging/connect/manifest.json +++ b/chrome/test/data/extensions/api_test/messaging/connect/manifest.json
@@ -15,7 +15,10 @@ }, { "all_frames": true, - "matches": ["http://*/*?testSendMessageFromFrame*"], + "matches": [ + "http://*/*?testSendMessageFromFrame*", + "http://*/*?testConnectChildFrameAndNavigate*" + ], "js": ["frame.js"] } ]
diff --git a/chrome/test/data/extensions/api_test/messaging/connect/page.js b/chrome/test/data/extensions/api_test/messaging/connect/page.js index b8a88a3..bf122e7 100644 --- a/chrome/test/data/extensions/api_test/messaging/connect/page.js +++ b/chrome/test/data/extensions/api_test/messaging/connect/page.js
@@ -19,7 +19,7 @@ }; // For complex connect tests. -chrome.runtime.onConnect.addListener(function(port) { +chrome.runtime.onConnect.addListener(function onConnect(port) { console.log('connected'); port.onMessage.addListener(function(msg) { console.log('got ' + msg); @@ -35,6 +35,10 @@ port.postMessage('from_main'); } else if (msg.testDisconnect) { port.disconnect(); + } else if (msg.testConnectChildFrameAndNavigateSetup) { + chrome.runtime.onConnect.removeListener(onConnect); + chrome.test.assertFalse(chrome.runtime.onConnect.hasListeners()); + testConnectChildFrameAndNavigateSetup(); } else if (msg.testDisconnectOnClose) { window.location = "about:blank"; } else if (msg.testPortName) { @@ -81,6 +85,17 @@ } } +function testConnectChildFrameAndNavigateSetup() { + var frames = document.querySelectorAll('iframe'); + for (var i = 0; i < frames.length; ++i) { + frames[i].remove(); + } + var f = document.createElement('iframe'); + f.src = '?testConnectChildFrameAndNavigateSetup'; + document.body.appendChild(f); + // Test will continue in frame.js +} + // Tests sendMessage to an invalid extension. function testSendMessageFromTabError() { // try sending a request to a bad extension id
diff --git a/chrome/test/data/extensions/api_test/messaging/connect/test.js b/chrome/test/data/extensions/api_test/messaging/connect/test.js index 50dbb8c..356f3d69 100644 --- a/chrome/test/data/extensions/api_test/messaging/connect/test.js +++ b/chrome/test/data/extensions/api_test/messaging/connect/test.js
@@ -260,6 +260,21 @@ } }, + // Tests that reloading a child frame disconnects the port if it was the + // only recipient of the port (i.e. no onConnect in main frame). + function connectChildFrameAndNavigate() { + listenOnce(chrome.runtime.onMessage, function(msg) { + chrome.test.assertEq('testConnectChildFrameAndNavigateSetupDone', msg); + // Now we have set up a frame and ensured that there is no onConnect + // handler in the main frame. Run the actual test: + var port = chrome.tabs.connect(testTab.id); + listenOnce(port.onDisconnect, function() {}); + port.postMessage({testConnectChildFrameAndNavigate: true}); + }); + chrome.tabs.connect(testTab.id) + .postMessage({testConnectChildFrameAndNavigateSetup: true}); + }, + // Tests that we get the disconnect event when the tab context closes. function disconnectOnClose() { var port = chrome.tabs.connect(testTab.id); @@ -300,7 +315,6 @@ 'Could not establish connection. Receiving end does not exist.', function() { stopFailing(); - chrome.test.succeed(); } )); }, @@ -330,14 +344,12 @@ // chrome.test.assertEq(location.href, sender.url); // setTimeout(function() { // stopFailing(); - // chrome.test.succeed(); // }, 0); // } // ); // // chrome.runtime.sendMessage('ping'); // }, - ]); }); @@ -347,10 +359,12 @@ }); var messages = []; var isDone = false; - listenForever(port.onMessage, function(message) { - if (isDone) // Should not get any messages after completing the test. + port.onMessage.addListener(function(message) { + if (isDone) { // Should not get any messages after completing the test. chrome.test.fail( 'Unexpected message from port to frame ' + frameId + ': ' + message); + return; + } messages.push(message); isDone = messages.length == expectedMessages.length; @@ -359,7 +373,7 @@ chrome.test.succeed(); } }); - listenOnce(port.onDisconnect, function() { + port.onDisconnect.addListener(function() { if (!isDone) // The event should never be triggered when we expect messages. chrome.test.fail('Unexpected disconnect from port to frame ' + frameId); });
diff --git a/chrome/test/data/extensions/api_test/messaging/connect_crash/manifest.json b/chrome/test/data/extensions/api_test/messaging/connect_crash/manifest.json new file mode 100644 index 0000000..7660f3e --- /dev/null +++ b/chrome/test/data/extensions/api_test/messaging/connect_crash/manifest.json
@@ -0,0 +1,13 @@ +{ + "name": "connect_crash", + "version": "1.0", + "manifest_version": 2, + "description": "Tests that the port is disconnect if the tab crashes.", + "background": { + "scripts": ["test.js"] + }, + "content_scripts": [{ + "matches": ["*://*/*"], + "js": ["page.js"] + }] +}
diff --git a/chrome/test/data/extensions/api_test/messaging/connect_crash/page.js b/chrome/test/data/extensions/api_test/messaging/connect_crash/page.js new file mode 100644 index 0000000..b3fc833 --- /dev/null +++ b/chrome/test/data/extensions/api_test/messaging/connect_crash/page.js
@@ -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. + +var port = chrome.runtime.connect(); +port.onDisconnect.addListener(function() { + chrome.test.fail('onDisconnect should not be triggered because the ' + + 'background page exists and the tab should have been crashed'); +}); + +var ref; +chrome.runtime.onMessage.addListener(function(msg, sender, sendResponse) { + chrome.test.assertEq('Rob says hi', msg); + port.postMessage('is_ready_to_crash'); + // Keep the callback around to avoid test flakiness due to GC. + ref = sendResponse; + + // TODO(robwu): Remove the following line once crbug.com/439780 is fixed. + // (the response callback is not automatically invoked when the tab crashes). + sendResponse(); + + // Keep the port open - do not send a response. + return true; +});
diff --git a/chrome/test/data/extensions/api_test/messaging/connect_crash/test.js b/chrome/test/data/extensions/api_test/messaging/connect_crash/test.js new file mode 100644 index 0000000..dbb865d1 --- /dev/null +++ b/chrome/test/data/extensions/api_test/messaging/connect_crash/test.js
@@ -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. + +chrome.runtime.onConnect.addListener(function(port) { + var is_ready_to_crash = false; + var succeed1 = chrome.test.callbackAdded(); + var succeed2 = chrome.test.callbackAdded(); + + port.onMessage.addListener(function(msg) { + chrome.test.assertEq('is_ready_to_crash', msg); + is_ready_to_crash = true; + chrome.test.sendMessage('ready_to_crash'); + // Now the browser test should kill the tab, and the port should be closed. + }); + port.onDisconnect.addListener(function() { + chrome.test.log('port.onDisconnect was triggered.'); + chrome.test.assertTrue(is_ready_to_crash); + succeed1(); + }); + + chrome.tabs.sendMessage(port.sender.tab.id, 'Rob says hi', function() { + chrome.test.log('tab.sendMessage\'s response callback was invoked'); + chrome.test.assertNoLastError(); + succeed2(); + }); +});
diff --git a/chrome/test/data/extensions/api_test/webnavigation/crossProcessIframe/frame.html b/chrome/test/data/extensions/api_test/webnavigation/crossProcessIframe/frame.html new file mode 100644 index 0000000..8c58ffd8 --- /dev/null +++ b/chrome/test/data/extensions/api_test/webnavigation/crossProcessIframe/frame.html
@@ -0,0 +1,3 @@ +<body> +<script src="frame.js"></script> +</body>
diff --git a/chrome/test/data/extensions/api_test/webnavigation/crossProcessIframe/frame.js b/chrome/test/data/extensions/api_test/webnavigation/crossProcessIframe/frame.js new file mode 100644 index 0000000..46e3f80a --- /dev/null +++ b/chrome/test/data/extensions/api_test/webnavigation/crossProcessIframe/frame.js
@@ -0,0 +1,18 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +onload = function() { + setTimeout(function() { + if (location.hostname === 'a.com') { + // Notify the parent frame, so they can navigate us. + parent.postMessage('a.com: go to b.com', location.ancestorOrigins[0]); + } else if (location.hostname === 'b.com') { + // Trigger a navigation to a site in another process. + location.hostname = 'c.com'; + } else { + console.assert(location.hostname === 'c.com'); + // Done. + } + }, 0); +};
diff --git a/chrome/test/data/extensions/api_test/webnavigation/crossProcessIframe/framework.js b/chrome/test/data/extensions/api_test/webnavigation/crossProcessIframe/framework.js new file mode 100644 index 0000000..b380ccb0 --- /dev/null +++ b/chrome/test/data/extensions/api_test/webnavigation/crossProcessIframe/framework.js
@@ -0,0 +1,263 @@ +// 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 deepEq = chrome.test.checkDeepEq; +var expectedEventData; +var expectedEventOrder; +var capturedEventData; +var nextFrameId; +var frameIds; +var nextTabId; +var tabIds; +var nextProcessId; +var processIds; +var initialized = false; + +var debug = false; + +function deepCopy(obj) { + if (obj === null) + return null; + if (typeof(obj) != 'object') + return obj; + if (Array.isArray(obj)) { + var tmp_array = new Array; + for (var i = 0; i < obj.length; i++) { + tmp_array.push(deepCopy(obj[i])); + } + return tmp_array; + } + + var tmp_object = {} + for (var p in obj) { + tmp_object[p] = deepCopy(obj[p]); + } + return tmp_object; +} + +// data: array of expected events, each one is a dictionary: +// { label: "<unique identifier>", +// event: "<webnavigation event type>", +// details: { <expected details of the event> } +// } +// order: an array of sequences, e.g. [ ["a", "b", "c"], ["d", "e"] ] means that +// event with label "a" needs to occur before event with label "b". The +// relative order of "a" and "d" does not matter. +function expect(data, order) { + expectedEventData = data; + capturedEventData = []; + expectedEventOrder = order; + nextFrameId = 1; + frameIds = {}; + nextTabId = 0; + tabIds = {}; + nextProcessId = 0; + processIds = {} + initListeners(); +} + +function checkExpectations() { + if (capturedEventData.length < expectedEventData.length) { + return; + } + if (capturedEventData.length > expectedEventData.length) { + chrome.test.fail("Recorded too many events. " + + JSON.stringify(capturedEventData)); + } + // We have ensured that capturedEventData contains exactly the same elements + // as expectedEventData. Now we need to verify the ordering. + // Step 1: build positions such that + // position[<event-label>]=<position of this event in capturedEventData> + var curPos = 0; + var positions = {}; + capturedEventData.forEach(function (event) { + chrome.test.assertTrue(event.hasOwnProperty("label")); + positions[event.label] = curPos; + curPos++; + }); + // Step 2: check that elements arrived in correct order + expectedEventOrder.forEach(function (order) { + var previousLabel = undefined; + order.forEach(function (label) { + if (previousLabel === undefined) { + previousLabel = label; + return; + } + chrome.test.assertTrue(positions[previousLabel] < positions[label], + "Event " + previousLabel + " is supposed to arrive before " + + label + "."); + previousLabel = label; + }); + }); + chrome.test.succeed(); +} + +function captureEvent(name, details) { + if ('url' in details) { + // Skip about:blank navigations + if (details.url == 'about:blank') { + return; + } + // Strip query parameter as it is hard to predict. + details.url = details.url.replace(new RegExp('\\?[^#]*'), ''); + } + // normalize details. + if ('timeStamp' in details) { + details.timeStamp = 0; + } + if (('frameId' in details) && (details.frameId != 0)) { + if (frameIds[details.frameId] === undefined) { + frameIds[details.frameId] = nextFrameId++; + } + details.frameId = frameIds[details.frameId]; + } + if (('parentFrameId' in details) && (details.parentFrameId > 0)) { + if (frameIds[details.parentFrameId] === undefined) { + frameIds[details.parentFrameId] = nextFrameId++; + } + details.parentFrameId = frameIds[details.parentFrameId]; + } + if (('sourceFrameId' in details) && (details.sourceFrameId != 0)) { + if (frameIds[details.sourceFrameId] === undefined) { + frameIds[details.sourceFrameId] = nextFrameId++; + } + details.sourceFrameId = frameIds[details.sourceFrameId]; + } + if ('tabId' in details) { + if (tabIds[details.tabId] === undefined) { + tabIds[details.tabId] = nextTabId++; + } + details.tabId = tabIds[details.tabId]; + } + if ('sourceTabId' in details) { + if (tabIds[details.sourceTabId] === undefined) { + tabIds[details.sourceTabId] = nextTabId++; + } + details.sourceTabId = tabIds[details.sourceTabId]; + } + if ('replacedTabId' in details) { + if (tabIds[details.replacedTabId] === undefined) { + tabIds[details.replacedTabId] = nextTabId++; + } + details.replacedTabId = tabIds[details.replacedTabId]; + } + if ('processId' in details) { + if (processIds[details.processId] === undefined) { + processIds[details.processId] = nextProcessId++; + } + details.processId = processIds[details.processId]; + } + if ('sourceProcessId' in details) { + if (processIds[details.sourceProcessId] === undefined) { + processIds[details.sourceProcessId] = nextProcessId++; + } + details.sourceProcessId = processIds[details.sourceProcessId]; + } + + if (debug) + console.log("Received event '" + name + "':" + JSON.stringify(details)); + + // find |details| in expectedEventData + var found = false; + var label = undefined; + expectedEventData.forEach(function (exp) { + if (exp.event == name) { + var exp_details; + var alt_details; + if ('transitionQualifiers' in exp.details) { + var idx = exp.details['transitionQualifiers'].indexOf( + 'maybe_client_redirect'); + if (idx >= 0) { + exp_details = deepCopy(exp.details); + exp_details['transitionQualifiers'].splice(idx, 1); + alt_details = deepCopy(exp_details); + alt_details['transitionQualifiers'].push('client_redirect'); + } else { + exp_details = exp.details; + alt_details = exp.details; + } + } else { + exp_details = exp.details; + alt_details = exp.details; + } + if (deepEq(exp_details, details) || deepEq(alt_details, details)) { + if (!found) { + found = true; + label = exp.label; + exp.event = undefined; + } + } + } + }); + if (!found) { + chrome.test.fail("Received unexpected event '" + name + "':" + + JSON.stringify(details)); + } + capturedEventData.push({label: label, event: name, details: details}); + checkExpectations(); +} + +function initListeners() { + if (initialized) + return; + initialized = true; + chrome.webNavigation.onBeforeNavigate.addListener( + function(details) { + captureEvent("onBeforeNavigate", details); + }); + chrome.webNavigation.onCommitted.addListener( + function(details) { + captureEvent("onCommitted", details); + }); + chrome.webNavigation.onDOMContentLoaded.addListener( + function(details) { + captureEvent("onDOMContentLoaded", details); + }); + chrome.webNavigation.onCompleted.addListener( + function(details) { + captureEvent("onCompleted", details); + }); + chrome.webNavigation.onCreatedNavigationTarget.addListener( + function(details) { + captureEvent("onCreatedNavigationTarget", details); + }); + chrome.webNavigation.onReferenceFragmentUpdated.addListener( + function(details) { + captureEvent("onReferenceFragmentUpdated", details); + }); + chrome.webNavigation.onErrorOccurred.addListener( + function(details) { + captureEvent("onErrorOccurred", details); + }); + chrome.webNavigation.onTabReplaced.addListener( + function(details) { + captureEvent("onTabReplaced", details); + }); + chrome.webNavigation.onHistoryStateUpdated.addListener( + function(details) { + captureEvent("onHistoryStateUpdated", details); + }); +} + +// Returns the usual order of navigation events. +function navigationOrder(prefix) { + return [ prefix + "onBeforeNavigate", + prefix + "onCommitted", + prefix + "onDOMContentLoaded", + prefix + "onCompleted" ]; +} + +// Returns the constraints expressing that a frame is an iframe of another +// frame. +function isIFrameOf(iframe, main_frame) { + return [ main_frame + "onCommitted", + iframe + "onBeforeNavigate", + iframe + "onCompleted", + main_frame + "onCompleted" ]; +} + +// Returns the constraint expressing that a frame was loaded by another. +function isLoadedBy(target, source) { + return [ source + "onDOMContentLoaded", target + "onBeforeNavigate"]; +}
diff --git a/chrome/test/data/extensions/api_test/webnavigation/crossProcessIframe/main.html b/chrome/test/data/extensions/api_test/webnavigation/crossProcessIframe/main.html new file mode 100644 index 0000000..140fab71 --- /dev/null +++ b/chrome/test/data/extensions/api_test/webnavigation/crossProcessIframe/main.html
@@ -0,0 +1 @@ +<script src=main.js></script>
diff --git a/chrome/test/data/extensions/api_test/webnavigation/crossProcessIframe/main.js b/chrome/test/data/extensions/api_test/webnavigation/crossProcessIframe/main.js new file mode 100644 index 0000000..4f5be77 --- /dev/null +++ b/chrome/test/data/extensions/api_test/webnavigation/crossProcessIframe/main.js
@@ -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. + +onload = function() { + var port = location.search.slice(1); + setTimeout(function() { + var f = document.createElement('iframe'); + window.onmessage = function(event) { + chrome.test.assertEq(f.contentWindow, event.source); + chrome.test.assertEq('http://a.com:' + port, event.origin); + chrome.test.assertEq('a.com: go to b.com', event.data); + f.src = f.src.replace('a.com', 'b.com'); + }; + f.src = 'http://a.com:' + port + + '/extensions/api_test/webnavigation/crossProcessIframe/frame.html'; + document.body.appendChild(f); + }, 0); +};
diff --git a/chrome/test/data/extensions/api_test/webnavigation/crossProcessIframe/manifest.json b/chrome/test/data/extensions/api_test/webnavigation/crossProcessIframe/manifest.json new file mode 100644 index 0000000..81a3ff1 --- /dev/null +++ b/chrome/test/data/extensions/api_test/webnavigation/crossProcessIframe/manifest.json
@@ -0,0 +1,10 @@ +{ + "name": "webNavigation", + "version": "1.0", + "manifest_version": 2, + "description": "Tests the webNavigation API events - crossProcessIframe.", + "background": { + "page": "test_crossProcessIframe.html" + }, + "permissions": ["webNavigation", "tabs"] +}
diff --git a/chrome/test/data/extensions/api_test/webnavigation/crossProcessIframe/test_crossProcessIframe.html b/chrome/test/data/extensions/api_test/webnavigation/crossProcessIframe/test_crossProcessIframe.html new file mode 100644 index 0000000..f2d0a82d --- /dev/null +++ b/chrome/test/data/extensions/api_test/webnavigation/crossProcessIframe/test_crossProcessIframe.html
@@ -0,0 +1,2 @@ +<script src="test_crossProcessIframe.js"></script> +<script src="framework.js"></script>
diff --git a/chrome/test/data/extensions/api_test/webnavigation/crossProcessIframe/test_crossProcessIframe.js b/chrome/test/data/extensions/api_test/webnavigation/crossProcessIframe/test_crossProcessIframe.js new file mode 100644 index 0000000..8912831 --- /dev/null +++ b/chrome/test/data/extensions/api_test/webnavigation/crossProcessIframe/test_crossProcessIframe.js
@@ -0,0 +1,216 @@ +// 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. + +onload = function() { + debug = true; + var getURL = chrome.extension.getURL; + var URL_MAIN = getURL('main.html'); + var URL_FRAME1 = 'http://a.com:PORT/extensions/api_test/webnavigation/' + + 'crossProcessIframe/frame.html'; + var URL_FRAME2 = 'http://b.com:PORT/extensions/api_test/webnavigation/' + + 'crossProcessIframe/frame.html'; + var URL_FRAME3 = 'http://c.com:PORT/extensions/api_test/webnavigation/' + + 'crossProcessIframe/frame.html'; + chrome.tabs.create({'url': 'about:blank'}, function(tab) { + var tabId = tab.id; + chrome.test.getConfig(function(config) { + var fixPort = function(url) { + return url.replace(/PORT/g, config.testServer.port); + }; + URL_FRAME1 = fixPort(URL_FRAME1); + URL_FRAME2 = fixPort(URL_FRAME2); + URL_FRAME3 = fixPort(URL_FRAME3); + + chrome.test.runTests([ + // Navigates from an extension page to a HTTP page which causes a + // process switch. The extension page embeds a same-process iframe which + // embeds another frame that navigates three times (cross-process): + // c. Loaded by the parent frame. + // d. Navigated by the parent frame. + // e. Navigated by the child frame. + // Tests whether the frameId stays constant across navigations. + function crossProcessIframe() { + expect([ + { label: 'main-onBeforeNavigate', + event: 'onBeforeNavigate', + details: { frameId: 0, + parentFrameId: -1, + processId: 0, + tabId: 0, + timeStamp: 0, + url: URL_MAIN }}, + { label: 'main-onCommitted', + event: 'onCommitted', + details: { frameId: 0, + processId: 0, + tabId: 0, + timeStamp: 0, + transitionQualifiers: [], + transitionType: 'link', + url: URL_MAIN }}, + { label: 'main-onDOMContentLoaded', + event: 'onDOMContentLoaded', + details: { frameId: 0, + processId: 0, + tabId: 0, + timeStamp: 0, + url: URL_MAIN }}, + { label: 'main-onCompleted', + event: 'onCompleted', + details: { frameId: 0, + processId: 0, + tabId: 0, + timeStamp: 0, + url: URL_MAIN }}, + // pre-a.com is the navigation before the process swap. + { label: 'pre-a.com-onBeforeNavigate', + event: 'onBeforeNavigate', + details: { frameId: 1, + parentFrameId: 0, + processId: 0, + tabId: 0, + timeStamp: 0, + url: URL_FRAME1 }}, + { label: 'pre-a.com-onErrorOccurred', + event: 'onErrorOccurred', + details: { error: 'net::ERR_ABORTED', + frameId: 1, + processId: 0, + tabId: 0, + timeStamp: 0, + url: URL_FRAME1 }}, + { label: 'a.com-onBeforeNavigate', + event: 'onBeforeNavigate', + details: { frameId: 1, + parentFrameId: 0, + processId: 1, + tabId: 0, + timeStamp: 0, + url: URL_FRAME1 }}, + { label: 'a.com-onCommitted', + event: 'onCommitted', + details: { frameId: 1, + processId: 1, + tabId: 0, + timeStamp: 0, + transitionQualifiers: [], + transitionType: 'auto_subframe', + url: URL_FRAME1 }}, + { label: 'a.com-onDOMContentLoaded', + event: 'onDOMContentLoaded', + details: { frameId: 1, + processId: 1, + tabId: 0, + timeStamp: 0, + url: URL_FRAME1 }}, + { label: 'a.com-onCompleted', + event: 'onCompleted', + details: { frameId: 1, + processId: 1, + tabId: 0, + timeStamp: 0, + url: URL_FRAME1 }}, + // There is no onBeforeNavigate and onErrorOccurred (like the other + // navigations in this test) because this navigation is triggered by + // a frame in a different process, so the navigation directly goes + // through the browser. This difference will be resolved once + // PlzNavigate goes live. + { label: 'b.com-onBeforeNavigate', + event: 'onBeforeNavigate', + details: { frameId: 1, + parentFrameId: 0, + processId: 2, + tabId: 0, + timeStamp: 0, + url: URL_FRAME2 }}, + { label: 'b.com-onCommitted', + event: 'onCommitted', + details: { frameId: 1, + processId: 2, + tabId: 0, + timeStamp: 0, + transitionQualifiers: [], + transitionType: 'manual_subframe', + url: URL_FRAME2 }}, + { label: 'b.com-onDOMContentLoaded', + event: 'onDOMContentLoaded', + details: { frameId: 1, + processId: 2, + tabId: 0, + timeStamp: 0, + url: URL_FRAME2 }}, + { label: 'b.com-onCompleted', + event: 'onCompleted', + details: { frameId: 1, + processId: 2, + tabId: 0, + timeStamp: 0, + url: URL_FRAME2 }}, + // pre-c.com is the navigation before the process swap. + { label: 'pre-c.com-onBeforeNavigate', + event: 'onBeforeNavigate', + details: { frameId: 1, + parentFrameId: 0, + processId: 2, + tabId: 0, + timeStamp: 0, + url: URL_FRAME3 }}, + { label: 'pre-c.com-onErrorOccurred', + event: 'onErrorOccurred', + details: { error: 'net::ERR_ABORTED', + frameId: 1, + processId: 2, + tabId: 0, + timeStamp: 0, + url: URL_FRAME3 }}, + { label: 'c.com-onBeforeNavigate', + event: 'onBeforeNavigate', + details: { frameId: 1, + parentFrameId: 0, + processId: 3, + tabId: 0, + timeStamp: 0, + url: URL_FRAME3 }}, + { label: 'c.com-onCommitted', + event: 'onCommitted', + details: { frameId: 1, + processId: 3, + tabId: 0, + timeStamp: 0, + transitionQualifiers: [], + transitionType: 'manual_subframe', + url: URL_FRAME3 }}, + { label: 'c.com-onDOMContentLoaded', + event: 'onDOMContentLoaded', + details: { frameId: 1, + processId: 3, + tabId: 0, + timeStamp: 0, + url: URL_FRAME3 }}, + { label: 'c.com-onCompleted', + event: 'onCompleted', + details: { frameId: 1, + processId: 3, + tabId: 0, + timeStamp: 0, + url: URL_FRAME3 }}], + [ + navigationOrder('main-'), + navigationOrder('a.com-'), + navigationOrder('b.com-'), + navigationOrder('c.com-'), + ['pre-a.com-onBeforeNavigate', 'a.com-onBeforeNavigate', + 'pre-a.com-onErrorOccurred'], + ['pre-c.com-onBeforeNavigate', 'c.com-onBeforeNavigate', + 'pre-c.com-onErrorOccurred']]); + + chrome.tabs.update(tabId, { + url: URL_MAIN + '?' + config.testServer.port + }); + }, + + ]); + }); + }); +};
diff --git a/chrome/test/data/extensions/api_test/webrequest/framework.js b/chrome/test/data/extensions/api_test/webrequest/framework.js index 7faa458..c9b7c15 100644 --- a/chrome/test/data/extensions/api_test/webrequest/framework.js +++ b/chrome/test/data/extensions/api_test/webrequest/framework.js
@@ -191,11 +191,6 @@ } function captureEvent(name, details, callback) { - // frameId should be -1 or positive, but is sometimes -2 (MSG_ROUTING_NONE). - // TODO(robwu): This will be resolved once crbug.com/432875 is resolved. - if (details.frameId === -2) - details.frameId = -1; - // Ignore system-level requests like safebrowsing updates and favicon fetches // since they are unpredictable. if (details.type == "other" ||
diff --git a/chrome/test/data/webui/history_browsertest.js b/chrome/test/data/webui/history_browsertest.js index d8792ea..d49ee8b 100644 --- a/chrome/test/data/webui/history_browsertest.js +++ b/chrome/test/data/webui/history_browsertest.js
@@ -775,6 +775,17 @@ // Add a visit on the next day. GEN(' AddPageToHistory(36, "http://google.com", "Google");'); }, + + /** @override */ + setUp: function() { + BaseHistoryWebUITest.prototype.setUp.call(this); + + // Enable when failure is resolved. + // AX_TEXT_04: http://crbug.com/560914 + this.accessibilityAuditConfig.ignoreSelectors( + 'linkWithUnclearPurpose', + '#notification-bar > A'); + }, }; /**
diff --git a/chrome/test/data/webui/media_router/media_router_container_tests.js b/chrome/test/data/webui/media_router/media_router_container_tests.js index 7fc1da1f..1ea8ef1 100644 --- a/chrome/test/data/webui/media_router/media_router_container_tests.js +++ b/chrome/test/data/webui/media_router/media_router_container_tests.js
@@ -473,7 +473,6 @@ setTimeout(function() { checkElementsVisibleWithId(['container-header', 'device-missing', - 'issue-banner', 'route-details']); done(); });
diff --git a/chrome/test/data/webui/net_internals/net_internals_test.js b/chrome/test/data/webui/net_internals/net_internals_test.js index 56bc93f6..b381ec82 100644 --- a/chrome/test/data/webui/net_internals/net_internals_test.js +++ b/chrome/test/data/webui/net_internals/net_internals_test.js
@@ -56,6 +56,8 @@ isAsync: true, setUp: function() { + testing.Test.prototype.setUp.call(this); + // Enforce accessibility auditing, but suppress some false positives. this.accessibilityIssuesAreErrors = true; // False positive because a unicode character is used to draw a square. @@ -79,6 +81,25 @@ this.accessibilityAuditConfig.auditRulesToIgnore.push( 'focusableElementNotVisibleAndNotAriaHidden'); + var controlsWithoutLabelSelectors = [ + '#export-view-user-comments', + '#hsts-view-add-input', + '#hsts-view-delete-input', + '#hsts-view-query-input', + ]; + + // Enable when failure is resolved. + // AX_TEXT_01: http://crbug.com/559203 + this.accessibilityAuditConfig.ignoreSelectors( + 'controlsWithoutLabel', + controlsWithoutLabelSelectors); + + // Enable when warning is resolved. + // AX_HTML_01: http://crbug.com/559204 + this.accessibilityAuditConfig.ignoreSelectors( + 'humanLangMissing', + 'html'); + // Wrap g_browser.receive around a test function so that assert and expect // functions can be called from observers. g_browser.receive =
diff --git a/chrome/test/data/webui/print_preview.js b/chrome/test/data/webui/print_preview.js index 2ef9260..7d84ef9 100644 --- a/chrome/test/data/webui/print_preview.js +++ b/chrome/test/data/webui/print_preview.js
@@ -166,6 +166,7 @@ * @override */ setUp: function() { + testing.Test.prototype.setUp.call(this); Mock4JS.clearMocksToVerify(); this.initialSettings_ = new print_preview.NativeInitialSettings( @@ -189,6 +190,12 @@ this.nativeLayer_ = printPreview.nativeLayer_; testing.Test.disableAnimationsAndTransitions(); + + // Enable when failure is resolved. + // AX_TEXT_03: http://crbug.com/559209 + this.accessibilityAuditConfig.ignoreSelectors( + 'multipleLabelableElementsPerLabel', + '#page-settings > .right-column > *'); } };
diff --git a/chrome/test/data/webui/settings/bluetooth_page_browsertest_chromeos.js b/chrome/test/data/webui/settings/bluetooth_page_browsertest_chromeos.js index cc01d7f5..9d31c55 100644 --- a/chrome/test/data/webui/settings/bluetooth_page_browsertest_chromeos.js +++ b/chrome/test/data/webui/settings/bluetooth_page_browsertest_chromeos.js
@@ -72,11 +72,14 @@ address: '10:00:00:00:00:01', name: 'FakePairedDevice1', paired: true, + connected: true, }, { address: '10:00:00:00:00:02', name: 'FakePairedDevice2', paired: true, + connected: false, + connecting: true, }, { address: '00:00:00:00:00:01', @@ -133,13 +136,13 @@ self.bluetoothApi_.setDevicesForTest(fakeDevices_); Polymer.dom.flush(); expectTrue(noDevices.hidden); - // Confirm that there are three devices in the list. - var devices = deviceList.querySelectorAll('iron-selector div'); - assertEquals(3, devices.length); - // Only paired devices should be visible. - expectFalse(devices[0].hidden); - expectFalse(devices[1].hidden); - expectTrue(devices[2].hidden); + // Confirm that there are two paired devices in the list. + var devices = deviceList.querySelectorAll('bluetooth-device-list-item'); + assertEquals(2, devices.length); + // Check the state of each device. + assertTrue(devices[0].device.connected); + assertFalse(devices[1].device.connected); + assertTrue(devices[1].device.connecting); }); });
diff --git a/chrome/test/data/webui/settings/cr_settings_browsertest.js b/chrome/test/data/webui/settings/cr_settings_browsertest.js index 193de6a..6790547a 100644 --- a/chrome/test/data/webui/settings/cr_settings_browsertest.js +++ b/chrome/test/data/webui/settings/cr_settings_browsertest.js
@@ -36,6 +36,8 @@ 'prefs_test_cases.js', 'prefs_tests.js', 'reset_page_test.js', + 'site_details_tests.js', + 'site_details_permission_tests.js', 'site_list_tests.js', 'site_settings_category_tests.js', ]), @@ -58,6 +60,8 @@ settings_dropdown_menu.registerTests(); settings_prefUtil.registerTests(); settings_prefs.registerTests(); + site_details.registerTests(); + site_details_permission.registerTests(); site_list.registerTests(); site_settings_category.registerTests();
diff --git a/chrome/test/data/webui/settings/site_details_permission_tests.js b/chrome/test/data/webui/settings/site_details_permission_tests.js new file mode 100644 index 0000000..cee9f87 --- /dev/null +++ b/chrome/test/data/webui/settings/site_details_permission_tests.js
@@ -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. + +/** @fileoverview Suite of tests for site-details. */ +cr.define('site_details_permission', function() { + function registerTests() { + suite('SiteDetailsPermission', function() { + /** + * A site list element created before each test. + * @type {SiteDetailsPermission} + */ + var testElement; + + /** + * An example pref with only camera allowed. + */ + var prefs = { + profile: { + content_settings: { + exceptions: { + media_stream_camera: { + value: { + 'https:\/\/foo-allow.com:443,https:\/\/foo-allow.com:443': { + setting: 1, + } + }, + }, + }, + }, + }, + }; + + /** + * An example empty pref. + */ + var prefsEmpty = { + profile: { + content_settings: { + exceptions: {}, + }, + }, + }; + + // Import necessary html before running suite. + suiteSetup(function() { + return PolymerTest.importHtml( + 'chrome://md-settings/site_settings/site_details_permission.html' + ); + }); + + // Initialize a site-details-permission before each test. + setup(function() { + PolymerTest.clearBody(); + testElement = document.createElement('site-details-permission'); + document.body.appendChild(testElement); + }); + + // Tests that the given value is converted to the expected value, for a + // given prefType. + var isAllowed = function(permission, prefs, origin) { + var pref = + testElement.prefs.profile.content_settings.exceptions[permission]; + var permissionPref = pref.value[origin + ',' + origin]; + return permissionPref.setting == settings.PermissionValues.ALLOW; + }; + + test('empty state', function() { + testElement.prefs = prefsEmpty; + testElement.category = settings.ContentSettingsTypes.CAMERA; + testElement.origin = "http://www.google.com"; + + assertEquals(0, testElement.offsetHeight, + 'No prefs, widget should not be visible, height'); + }); + + test('camera category', function() { + testElement.prefs = prefs; + testElement.category = settings.ContentSettingsTypes.CAMERA; + var origin = "https://foo-allow.com:443"; + testElement.origin = origin; + + assertNotEquals(0, testElement.offsetHeight, + 'Prefs loaded, widget should be visible, height'); + + var header = testElement.$.details.querySelector('.permission-header'); + assertEquals('Camera', header.innerText.trim(), + 'Widget should be labelled correctly'); + + // Flip the permission and validate that prefs stay in sync. + assertTrue(isAllowed('media_stream_camera', prefs, origin)); + MockInteractions.tap(testElement.$.block); + assertFalse(isAllowed('media_stream_camera', prefs, origin)); + MockInteractions.tap(testElement.$.allow); + assertTrue(isAllowed('media_stream_camera', prefs, origin)); + + // When the pref gets deleted, the widget should disappear. + testElement.prefs = prefsEmpty; + assertEquals(0, testElement.offsetHeight, + 'Widget should not be visible, height'); + }); + }); + } + return { + registerTests: registerTests, + }; +});
diff --git a/chrome/test/data/webui/settings/site_details_tests.js b/chrome/test/data/webui/settings/site_details_tests.js new file mode 100644 index 0000000..bb81b2e0 --- /dev/null +++ b/chrome/test/data/webui/settings/site_details_tests.js
@@ -0,0 +1,150 @@ +// 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 Suite of tests for site-details. */ +cr.define('site_details', function() { + function registerTests() { + suite('SiteDetails', function() { + /** + * A site list element created before each test. + * @type {SiteDetails} + */ + var testElement; + + /** + * An example pref with 1 allowed in each category. + */ + var prefs = { + profile: { + content_settings: { + exceptions: { + media_stream_camera: { + value: { + 'https:\/\/foo-allow.com:443,https:\/\/foo-allow.com:443': { + setting: 1, + }, + }, + }, + cookies: { + value: { + 'https:\/\/foo-allow.com:443,https:\/\/foo-allow.com:443': { + setting: 1, + }, + }, + }, + fullscreen: { + value: { + 'https:\/\/foo-allow.com:443,https:\/\/foo-allow.com:443': { + setting: 1, + }, + }, + }, + geolocation: { + value: { + 'https:\/\/foo-allow.com:443,https:\/\/foo-allow.com:443': { + setting: 1, + }, + }, + }, + javascript: { + value: { + 'https:\/\/foo-allow.com:443,https:\/\/foo-allow.com:443': { + setting: 1, + }, + }, + }, + media_stream_mic: { + value: { + 'https:\/\/foo-allow.com:443,https:\/\/foo-allow.com:443': { + setting: 1, + }, + }, + }, + notifications: { + value: { + 'https:\/\/foo-allow.com:443,https:\/\/foo-allow.com:443': { + setting: 1, + }, + }, + }, + popups: { + value: { + 'https:\/\/foo-allow.com:443,https:\/\/foo-allow.com:443': { + setting: 1, + }, + }, + }, + }, + }, + }, + }; + + /** + * An example empty pref. + */ + var prefsEmpty = { + profile: { + content_settings: { + exceptions: {}, + }, + }, + }; + + // Import necessary html before running suite. + suiteSetup(function() { + return PolymerTest.importHtml( + 'chrome://md-settings/site_settings/site_details.html' + ); + }); + + // Initialize a site-details before each test. + setup(function() { + PolymerTest.clearBody(); + testElement = document.createElement('site-details'); + document.body.appendChild(testElement); + }); + + test('empty state', function() { + testElement.prefs = prefsEmpty; + testElement.origin = "http://www.google.com"; + + // Once actual storage numbers are shown (instead of hard-coded), these + // two will become hidden by default. + assertFalse(testElement.$.usage.hidden); + assertFalse(testElement.$.storage.hidden); + + // TODO(finnur): Check for the Permission heading hiding when no + // permissions are showing. + + var msg = 'No category should be showing, height'; + assertEquals(0, testElement.$.camera.offsetHeight, msg); + assertEquals(0, testElement.$.cookies.offsetHeight, msg); + assertEquals(0, testElement.$.fullscreen.offsetHeight, msg); + assertEquals(0, testElement.$.geolocation.offsetHeight, msg); + assertEquals(0, testElement.$.javascript.offsetHeight, msg); + assertEquals(0, testElement.$.mic.offsetHeight, msg); + assertEquals(0, testElement.$.notification.offsetHeight, msg); + assertEquals(0, testElement.$.popups.offsetHeight, msg); + }); + + test('all categories visible', function() { + testElement.prefs = prefs; + testElement.origin = "https://foo-allow.com:443"; + + var msg = 'All categories should be showing'; + assertNotEquals(0, testElement.$.camera.offsetHeight, msg); + assertNotEquals(0, testElement.$.cookies.offsetHeight, msg); + assertNotEquals(0, testElement.$.fullscreen.offsetHeight, msg); + assertNotEquals(0, testElement.$.geolocation.offsetHeight, msg); + assertNotEquals(0, testElement.$.javascript.offsetHeight, msg); + assertNotEquals(0, testElement.$.mic.offsetHeight, msg); + assertNotEquals(0, testElement.$.notification.offsetHeight, msg); + assertNotEquals(0, testElement.$.popups.offsetHeight, msg); + }); + }); + } + return { + registerTests: registerTests, + }; +});
diff --git a/chrome/test/data/webui/settings/site_list_tests.js b/chrome/test/data/webui/settings/site_list_tests.js index 585e497..bb2b47d 100644 --- a/chrome/test/data/webui/settings/site_list_tests.js +++ b/chrome/test/data/webui/settings/site_list_tests.js
@@ -16,22 +16,22 @@ * An example pref with 2 blocked location items and 2 allowed. */ var prefs = { - 'profile': { - 'content_settings': { - 'exceptions': { - 'geolocation': { - 'value': { + profile: { + content_settings: { + exceptions: { + geolocation: { + value: { 'https:\/\/foo-allow.com:443,https:\/\/foo-allow.com:443': { - 'setting': 1, + setting: 1, }, 'https:\/\/bar-allow.com:443,https:\/\/bar-allow.com:443': { - 'setting': 1, + setting: 1, }, 'https:\/\/foo-block.com:443,https:\/\/foo-block.com:443': { - 'setting': 2, + setting: 2, }, 'https:\/\/bar-block.com:443,https:\/\/bar-block.com:443': { - 'setting': 2, + setting: 2, } }, }, @@ -44,10 +44,10 @@ * An example empty pref. */ var prefsEmpty = { - 'profile': { - 'content_settings': { - 'exceptions': { - 'geolocation': {} + profile: { + content_settings: { + exceptions: { + geolocation: {} }, }, },
diff --git a/chrome/test/data/webui/settings/site_settings_category_tests.js b/chrome/test/data/webui/settings/site_settings_category_tests.js index 26a3c7b..5c06d57 100644 --- a/chrome/test/data/webui/settings/site_settings_category_tests.js +++ b/chrome/test/data/webui/settings/site_settings_category_tests.js
@@ -16,10 +16,10 @@ * An example pref where the location category is disabled. */ var prefsLocationDisabled = { - 'profile': { - 'default_content_setting_values': { - 'geolocation': { - 'value': 2, + profile: { + default_content_setting_values: { + geolocation: { + value: 2, } }, }, @@ -29,10 +29,10 @@ * An example pref where the location category is enabled. */ var prefsLocationEnabled = { - 'profile': { - 'default_content_setting_values': { - 'geolocation': { - 'value': 3, + profile: { + default_content_setting_values: { + geolocation: { + value: 3, } } },
diff --git a/chrome/test/data/webui/test_api.js b/chrome/test/data/webui/test_api.js index b04dbb3..62aea22e 100644 --- a/chrome/test/data/webui/test_api.js +++ b/chrome/test/data/webui/test_api.js
@@ -168,15 +168,10 @@ /** * Returns the configuration for the accessibility audit, creating it * on-demand. - * @return {axs.AuditConfiguration} + * @return {!axs.AuditConfiguration} */ get accessibilityAuditConfig() { - // The axs namespace is not available in chromevox tests. - // Further, 'window' is not available in unit tests, but since the - // accessibility audit library pulls in the closure library, - // 'goog.global' has to be present if axs is, so we use that here. - if (!this.accessibilityAuditConfig_ && - goog && goog.global && goog.global.axs) { + if (!this.accessibilityAuditConfig_) { this.accessibilityAuditConfig_ = new axs.AuditConfiguration(); this.accessibilityAuditConfig_.showUnsupportedRulesWarning = false; @@ -196,6 +191,10 @@ // TODO(aboxhall): re-enable when crbug.com/267035 is fixed. // Until then it's just noise. "lowContrastElements", + + // TODO(apacible): re-enable when following issue is fixed. + // github.com/GoogleChrome/accessibility-developer-tools/issues/251 + "tableHasAppropriateHeaders", ]; } return this.accessibilityAuditConfig_; @@ -307,17 +306,14 @@ * @type {Function} */ setUp: function() { - var auditConfig = this.accessibilityAuditConfig; - if (auditConfig) { - // These should be ignored in many of the web UI tests. - // user-image-stream and supervised-user-creation-image-stream are - // streaming video elements used for capturing a user image so they - // won't have captions and should be ignored everywhere. - auditConfig.ignoreSelectors('videoWithoutCaptions', - '.user-image-stream'); - auditConfig.ignoreSelectors( - 'videoWithoutCaptions', '.supervised-user-creation-image-stream'); - } + // These should be ignored in many of the web UI tests. + // user-image-stream and supervised-user-creation-image-stream are + // streaming video elements used for capturing a user image so they + // won't have captions and should be ignored everywhere. + this.accessibilityAuditConfig.ignoreSelectors('videoWithoutCaptions', + '.user-image-stream'); + this.accessibilityAuditConfig.ignoreSelectors( + 'videoWithoutCaptions', '.supervised-user-creation-image-stream'); }, /**
diff --git a/chrome/test/media_router/media_router_integration_ui_browsertest.cc b/chrome/test/media_router/media_router_integration_ui_browsertest.cc index 4e059b6..b363fd6b 100644 --- a/chrome/test/media_router/media_router_integration_ui_browsertest.cc +++ b/chrome/test/media_router/media_router_integration_ui_browsertest.cc
@@ -34,10 +34,14 @@ ChooseSink(web_contents, kTestSinkName); WaitUntilRouteCreated(); - // Simulate a click on the dialog to prevent it from automatically closing - // after the route has been created. Then, check that the dialog remains - // open. - ClickDialog(); + // Simulate keeping the mouse on the dialog to prevent it from automatically + // closing after the route has been created. Then, check that the dialog + // remains open. + std::string mouse_enter_script = base::StringPrintf( + "domAutomationController.send(" + "window.document.getElementById('media-router-container').dispatchEvent(" + "new Event('mouseenter')))"); + ASSERT_TRUE(content::ExecuteScript(dialog_contents, mouse_enter_script)); CheckDialogRemainsOpen(web_contents); // Verify the route details page. @@ -62,8 +66,13 @@ // Close route. CloseRouteOnUI(); - // Do not simulate a click on the dialog. Confirm that the dialog closes + // Simulate moving the mouse off the dialog. Confirm that the dialog closes // automatically after the route is closed. + std::string mouse_leave_script = base::StringPrintf( + "domAutomationController.send(" + "window.document.getElementById('media-router-container').dispatchEvent(" + "new Event('mouseleave')))"); + ASSERT_TRUE(content::ExecuteScript(dialog_contents, mouse_leave_script)); WaitUntilDialogClosed(web_contents); }
diff --git a/chrome/tools/build/win/syzygy/BUILD.gn b/chrome/tools/build/win/syzygy/BUILD.gn index 116318b9..c73f949 100644 --- a/chrome/tools/build/win/syzygy/BUILD.gn +++ b/chrome/tools/build/win/syzygy/BUILD.gn
@@ -98,6 +98,8 @@ script = "//chrome/tools/build/win/syzygy/instrument.py" filter = "syzyasan-instrumentation-filter.txt" + + dll_name = invoker.dll_name input_dll = "$root_out_dir/$dll_name.dll" input_pdb = "$root_out_dir/$dll_name.dll.pdb"
diff --git a/chrome/tools/convert_dict/BUILD.gn b/chrome/tools/convert_dict/BUILD.gn index e55a144..c4b42ce8 100644 --- a/chrome/tools/convert_dict/BUILD.gn +++ b/chrome/tools/convert_dict/BUILD.gn
@@ -17,6 +17,7 @@ configs += [ "//build/config/compiler:wexit_time_destructors" ] deps = [ "//base", + "//base:i18n", ] }
diff --git a/chrome/tools/service_discovery_sniffer/BUILD.gn b/chrome/tools/service_discovery_sniffer/BUILD.gn index 8fc3195f..161afbb 100644 --- a/chrome/tools/service_discovery_sniffer/BUILD.gn +++ b/chrome/tools/service_discovery_sniffer/BUILD.gn
@@ -16,6 +16,7 @@ "//base/allocator", "//base/test:test_support", "//build/config/sanitizers:deps", + "//chrome/common", "//chrome/utility", "//net", ]
diff --git a/chrome/unit_tests.isolate b/chrome/unit_tests.isolate index 4e7d8e93..b76c4e1 100644 --- a/chrome/unit_tests.isolate +++ b/chrome/unit_tests.isolate
@@ -34,14 +34,9 @@ ], }, }], - ['OS=="android" or OS=="linux" or OS=="win" or OS=="mac"', { + ['OS=="android" or OS=="linux" or OS=="mac" or OS=="win"', { 'variables': { 'files': [ - '<(PRODUCT_DIR)/test_data/chrome/browser/resources/google_now/', - '<(PRODUCT_DIR)/test_data/chrome/browser/resources/print_preview/', - '<(PRODUCT_DIR)/test_data/chrome/renderer/resources/extensions/', - '<(PRODUCT_DIR)/test_data/chrome/test/data/unit/', - '<(PRODUCT_DIR)/test_data/ui/webui/', '../base/test/data/', '../components/test/data/', '../extensions/test/data/', @@ -83,7 +78,12 @@ '../third_party/pywebsocket/', '../third_party/tlslite/', '<(PRODUCT_DIR)/pyproto/google/', + '<(PRODUCT_DIR)/test_data/chrome/browser/resources/google_now/', '<(PRODUCT_DIR)/test_data/chrome/browser/resources/md_downloads/', + '<(PRODUCT_DIR)/test_data/chrome/browser/resources/print_preview/', + '<(PRODUCT_DIR)/test_data/chrome/renderer/resources/extensions/', + '<(PRODUCT_DIR)/test_data/chrome/test/data/unit/', + '<(PRODUCT_DIR)/test_data/ui/webui/', ], }, }],
diff --git a/chrome/utility/BUILD.gn b/chrome/utility/BUILD.gn index edef316..22435b7 100644 --- a/chrome/utility/BUILD.gn +++ b/chrome/utility/BUILD.gn
@@ -118,13 +118,6 @@ ] } - if (!enable_mdns) { - sources -= [ - "local_discovery/service_discovery_message_handler.cc", - "local_discovery/service_discovery_message_handler.h", - ] - } - if (safe_browsing_mode == 1) { sources += rebase_path(gypi_values.chrome_utility_safe_browsing_sources, ".", "..")
diff --git a/chrome/utility/chrome_content_utility_client.cc b/chrome/utility/chrome_content_utility_client.cc index c594732..b3cc696 100644 --- a/chrome/utility/chrome_content_utility_client.cc +++ b/chrome/utility/chrome_content_utility_client.cc
@@ -56,10 +56,6 @@ #include "chrome/utility/printing_handler.h" #endif -#if defined(ENABLE_MDNS) -#include "chrome/utility/local_discovery/service_discovery_message_handler.h" -#endif - #if defined(OS_MACOSX) && defined(FULL_SAFE_BROWSING) #include "chrome/utility/safe_browsing/mac/dmg_analyzer.h" #endif @@ -133,13 +129,6 @@ handlers_.push_back(new printing::PrintingHandler()); #endif -#if defined(ENABLE_MDNS) - if (base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kUtilityProcessEnableMDns)) { - handlers_.push_back(new local_discovery::ServiceDiscoveryMessageHandler()); - } -#endif - #if defined(OS_WIN) handlers_.push_back(new ShellHandler()); handlers_.push_back(new FontCacheHandler()); @@ -225,13 +214,6 @@ #if defined(ENABLE_EXTENSIONS) extensions::ExtensionsHandler::PreSandboxStartup(); #endif - -#if defined(ENABLE_MDNS) - if (base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kUtilityProcessEnableMDns)) { - local_discovery::ServiceDiscoveryMessageHandler::PreSandboxStartup(); - } -#endif // ENABLE_MDNS } // static
diff --git a/chrome/utility/local_discovery/OWNERS b/chrome/utility/local_discovery/OWNERS deleted file mode 100644 index a0508fc..0000000 --- a/chrome/utility/local_discovery/OWNERS +++ /dev/null
@@ -1,3 +0,0 @@ -gene@chromium.org -noamsml@chromium.org -vitalybuka@chromium.org
diff --git a/chrome/utility/local_discovery/service_discovery_message_handler.cc b/chrome/utility/local_discovery/service_discovery_message_handler.cc deleted file mode 100644 index 9a9aac7..0000000 --- a/chrome/utility/local_discovery/service_discovery_message_handler.cc +++ /dev/null
@@ -1,489 +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/utility/local_discovery/service_discovery_message_handler.h" - -#include <stddef.h> - -#include <algorithm> -#include <vector> - -#include "base/lazy_instance.h" -#include "base/location.h" -#include "base/macros.h" -#include "base/memory/scoped_ptr.h" -#include "base/single_thread_task_runner.h" -#include "build/build_config.h" -#include "chrome/common/local_discovery/local_discovery_messages.h" -#include "chrome/common/local_discovery/service_discovery_client_impl.h" -#include "content/public/utility/utility_thread.h" -#include "net/base/net_util.h" -#include "net/socket/socket_descriptor.h" -#include "net/udp/datagram_server_socket.h" - -namespace local_discovery { - -namespace { - -void ClosePlatformSocket(net::SocketDescriptor socket); - -// Sets socket factory used by |net::CreatePlatformSocket|. Implemetation -// keeps single socket that will be returned to the first call to -// |net::CreatePlatformSocket| during object lifetime. -class ScopedSocketFactory : public net::PlatformSocketFactory { - public: - explicit ScopedSocketFactory(net::SocketDescriptor socket) : socket_(socket) { - net::PlatformSocketFactory::SetInstance(this); - } - - ~ScopedSocketFactory() override { - net::PlatformSocketFactory::SetInstance(NULL); - ClosePlatformSocket(socket_); - socket_ = net::kInvalidSocket; - } - - net::SocketDescriptor CreateSocket(int family, - int type, - int protocol) override { - DCHECK_EQ(type, SOCK_DGRAM); - DCHECK(family == AF_INET || family == AF_INET6); - net::SocketDescriptor result = net::kInvalidSocket; - std::swap(result, socket_); - return result; - } - - private: - net::SocketDescriptor socket_; - DISALLOW_COPY_AND_ASSIGN(ScopedSocketFactory); -}; - -struct SocketInfo { - SocketInfo(net::SocketDescriptor socket, - net::AddressFamily address_family, - uint32_t interface_index) - : socket(socket), - address_family(address_family), - interface_index(interface_index) {} - net::SocketDescriptor socket; - net::AddressFamily address_family; - uint32_t interface_index; -}; - -// Returns list of sockets preallocated before. -class PreCreatedMDnsSocketFactory : public net::MDnsSocketFactory { - public: - PreCreatedMDnsSocketFactory() {} - ~PreCreatedMDnsSocketFactory() override { - // Not empty if process exits too fast, before starting mDns code. If - // happened, destructors may crash accessing destroyed global objects. - // TODO This sounds memory leak, check and do better if possible - for (scoped_ptr<net::DatagramServerSocket>& it : sockets_) - base::IgnoreResult(it.release()); - sockets_.clear(); - } - - // net::MDnsSocketFactory implementation: - void CreateSockets( - std::vector<scoped_ptr<net::DatagramServerSocket>>* sockets) override { - sockets->swap(sockets_); - Reset(); - } - - void AddSocket(const SocketInfo& socket_info) { - // Takes ownership of socket_info.socket; - ScopedSocketFactory platform_factory(socket_info.socket); - scoped_ptr<net::DatagramServerSocket> socket( - net::CreateAndBindMDnsSocket(socket_info.address_family, - socket_info.interface_index)); - if (socket) { - socket->DetachFromThread(); - sockets_.push_back(std::move(socket)); - } - } - - void Reset() { - sockets_.clear(); - } - - private: - std::vector<scoped_ptr<net::DatagramServerSocket>> sockets_; - - DISALLOW_COPY_AND_ASSIGN(PreCreatedMDnsSocketFactory); -}; - -base::LazyInstance<PreCreatedMDnsSocketFactory> - g_local_discovery_socket_factory = LAZY_INSTANCE_INITIALIZER; - -#if defined(OS_WIN) - -void ClosePlatformSocket(net::SocketDescriptor socket) { - ::closesocket(socket); -} - -void StaticInitializeSocketFactory() { - net::InterfaceIndexFamilyList interfaces(net::GetMDnsInterfacesToBind()); - for (size_t i = 0; i < interfaces.size(); ++i) { - DCHECK(interfaces[i].second == net::ADDRESS_FAMILY_IPV4 || - interfaces[i].second == net::ADDRESS_FAMILY_IPV6); - net::SocketDescriptor descriptor = - net::CreatePlatformSocket( - net::ConvertAddressFamily(interfaces[i].second), SOCK_DGRAM, - IPPROTO_UDP); - g_local_discovery_socket_factory.Get().AddSocket( - SocketInfo(descriptor, interfaces[i].second, interfaces[i].first)); - } -} - -#else // OS_WIN - -void ClosePlatformSocket(net::SocketDescriptor socket) { - ::close(socket); -} - -void StaticInitializeSocketFactory() { -} - -#endif // OS_WIN - -void SendHostMessageOnUtilityThread(IPC::Message* msg) { - content::UtilityThread::Get()->Send(msg); -} - -std::string WatcherUpdateToString(ServiceWatcher::UpdateType update) { - switch (update) { - case ServiceWatcher::UPDATE_ADDED: - return "UPDATE_ADDED"; - case ServiceWatcher::UPDATE_CHANGED: - return "UPDATE_CHANGED"; - case ServiceWatcher::UPDATE_REMOVED: - return "UPDATE_REMOVED"; - case ServiceWatcher::UPDATE_INVALIDATED: - return "UPDATE_INVALIDATED"; - } - return "Unknown Update"; -} - -std::string ResolverStatusToString(ServiceResolver::RequestStatus status) { - switch (status) { - case ServiceResolver::STATUS_SUCCESS: - return "STATUS_SUCESS"; - case ServiceResolver::STATUS_REQUEST_TIMEOUT: - return "STATUS_REQUEST_TIMEOUT"; - case ServiceResolver::STATUS_KNOWN_NONEXISTENT: - return "STATUS_KNOWN_NONEXISTENT"; - } - return "Unknown Status"; -} - -} // namespace - -ServiceDiscoveryMessageHandler::ServiceDiscoveryMessageHandler() { -} - -ServiceDiscoveryMessageHandler::~ServiceDiscoveryMessageHandler() { - DCHECK(!discovery_thread_); -} - -void ServiceDiscoveryMessageHandler::PreSandboxStartup() { - StaticInitializeSocketFactory(); -} - -void ServiceDiscoveryMessageHandler::InitializeMdns() { - if (service_discovery_client_ || mdns_client_) - return; - - mdns_client_ = net::MDnsClient::CreateDefault(); - bool result = - mdns_client_->StartListening(g_local_discovery_socket_factory.Pointer()); - // Close unused sockets. - g_local_discovery_socket_factory.Get().Reset(); - if (!result) { - VLOG(1) << "Failed to start MDnsClient"; - Send(new LocalDiscoveryHostMsg_Error()); - return; - } - - service_discovery_client_.reset( - new local_discovery::ServiceDiscoveryClientImpl(mdns_client_.get())); -} - -bool ServiceDiscoveryMessageHandler::InitializeThread() { - if (discovery_task_runner_.get()) - return true; - if (discovery_thread_) - return false; - utility_task_runner_ = base::MessageLoop::current()->task_runner(); - discovery_thread_.reset(new base::Thread("ServiceDiscoveryThread")); - base::Thread::Options thread_options(base::MessageLoop::TYPE_IO, 0); - if (discovery_thread_->StartWithOptions(thread_options)) { - discovery_task_runner_ = discovery_thread_->task_runner(); - discovery_task_runner_->PostTask(FROM_HERE, - base::Bind(&ServiceDiscoveryMessageHandler::InitializeMdns, - base::Unretained(this))); - } - return discovery_task_runner_.get() != NULL; -} - -bool ServiceDiscoveryMessageHandler::OnMessageReceived( - const IPC::Message& message) { - bool handled = true; - IPC_BEGIN_MESSAGE_MAP(ServiceDiscoveryMessageHandler, message) -#if defined(OS_POSIX) - IPC_MESSAGE_HANDLER(LocalDiscoveryMsg_SetSockets, OnSetSockets) -#endif // OS_POSIX - IPC_MESSAGE_HANDLER(LocalDiscoveryMsg_StartWatcher, OnStartWatcher) - IPC_MESSAGE_HANDLER(LocalDiscoveryMsg_DiscoverServices, OnDiscoverServices) - IPC_MESSAGE_HANDLER(LocalDiscoveryMsg_SetActivelyRefreshServices, - OnSetActivelyRefreshServices) - IPC_MESSAGE_HANDLER(LocalDiscoveryMsg_DestroyWatcher, OnDestroyWatcher) - IPC_MESSAGE_HANDLER(LocalDiscoveryMsg_ResolveService, OnResolveService) - IPC_MESSAGE_HANDLER(LocalDiscoveryMsg_DestroyResolver, OnDestroyResolver) - IPC_MESSAGE_HANDLER(LocalDiscoveryMsg_ResolveLocalDomain, - OnResolveLocalDomain) - IPC_MESSAGE_HANDLER(LocalDiscoveryMsg_DestroyLocalDomainResolver, - OnDestroyLocalDomainResolver) - IPC_MESSAGE_HANDLER(LocalDiscoveryMsg_ShutdownLocalDiscovery, - ShutdownLocalDiscovery) - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP() - return handled; -} - -void ServiceDiscoveryMessageHandler::PostTask( - const tracked_objects::Location& from_here, - const base::Closure& task) { - if (!InitializeThread()) - return; - discovery_task_runner_->PostTask(from_here, task); -} - -#if defined(OS_POSIX) -void ServiceDiscoveryMessageHandler::OnSetSockets( - const std::vector<LocalDiscoveryMsg_SocketInfo>& sockets) { - for (size_t i = 0; i < sockets.size(); ++i) { - g_local_discovery_socket_factory.Get().AddSocket( - SocketInfo(sockets[i].descriptor.fd, sockets[i].address_family, - sockets[i].interface_index)); - } -} -#endif // OS_POSIX - -void ServiceDiscoveryMessageHandler::OnStartWatcher( - uint64_t id, - const std::string& service_type) { - PostTask(FROM_HERE, - base::Bind(&ServiceDiscoveryMessageHandler::StartWatcher, - base::Unretained(this), id, service_type)); -} - -void ServiceDiscoveryMessageHandler::OnDiscoverServices(uint64_t id, - bool force_update) { - PostTask(FROM_HERE, - base::Bind(&ServiceDiscoveryMessageHandler::DiscoverServices, - base::Unretained(this), id, force_update)); -} - -void ServiceDiscoveryMessageHandler::OnSetActivelyRefreshServices( - uint64_t id, - bool actively_refresh_services) { - PostTask(FROM_HERE, - base::Bind( - &ServiceDiscoveryMessageHandler::SetActivelyRefreshServices, - base::Unretained(this), id, actively_refresh_services)); -} - -void ServiceDiscoveryMessageHandler::OnDestroyWatcher(uint64_t id) { - PostTask(FROM_HERE, - base::Bind(&ServiceDiscoveryMessageHandler::DestroyWatcher, - base::Unretained(this), id)); -} - -void ServiceDiscoveryMessageHandler::OnResolveService( - uint64_t id, - const std::string& service_name) { - PostTask(FROM_HERE, - base::Bind(&ServiceDiscoveryMessageHandler::ResolveService, - base::Unretained(this), id, service_name)); -} - -void ServiceDiscoveryMessageHandler::OnDestroyResolver(uint64_t id) { - PostTask(FROM_HERE, - base::Bind(&ServiceDiscoveryMessageHandler::DestroyResolver, - base::Unretained(this), id)); -} - -void ServiceDiscoveryMessageHandler::OnResolveLocalDomain( - uint64_t id, - const std::string& domain, - net::AddressFamily address_family) { - PostTask(FROM_HERE, - base::Bind(&ServiceDiscoveryMessageHandler::ResolveLocalDomain, - base::Unretained(this), id, domain, address_family)); -} - -void ServiceDiscoveryMessageHandler::OnDestroyLocalDomainResolver(uint64_t id) { - PostTask(FROM_HERE, - base::Bind( - &ServiceDiscoveryMessageHandler::DestroyLocalDomainResolver, - base::Unretained(this), id)); -} - -void ServiceDiscoveryMessageHandler::StartWatcher( - uint64_t id, - const std::string& service_type) { - VLOG(1) << "StartWatcher, id=" << id << ", type=" << service_type; - if (!service_discovery_client_) - return; - DCHECK(!ContainsKey(service_watchers_, id)); - scoped_ptr<ServiceWatcher> watcher( - service_discovery_client_->CreateServiceWatcher( - service_type, - base::Bind(&ServiceDiscoveryMessageHandler::OnServiceUpdated, - base::Unretained(this), id))); - watcher->Start(); - service_watchers_[id].reset(watcher.release()); -} - -void ServiceDiscoveryMessageHandler::DiscoverServices(uint64_t id, - bool force_update) { - VLOG(1) << "DiscoverServices, id=" << id; - if (!service_discovery_client_) - return; - DCHECK(ContainsKey(service_watchers_, id)); - service_watchers_[id]->DiscoverNewServices(force_update); -} - -void ServiceDiscoveryMessageHandler::SetActivelyRefreshServices( - uint64_t id, - bool actively_refresh_services) { - VLOG(1) << "ActivelyRefreshServices, id=" << id; - if (!service_discovery_client_) - return; - DCHECK(ContainsKey(service_watchers_, id)); - service_watchers_[id]->SetActivelyRefreshServices(actively_refresh_services); -} - -void ServiceDiscoveryMessageHandler::DestroyWatcher(uint64_t id) { - VLOG(1) << "DestoryWatcher, id=" << id; - if (!service_discovery_client_) - return; - service_watchers_.erase(id); -} - -void ServiceDiscoveryMessageHandler::ResolveService( - uint64_t id, - const std::string& service_name) { - VLOG(1) << "ResolveService, id=" << id << ", name=" << service_name; - if (!service_discovery_client_) - return; - DCHECK(!ContainsKey(service_resolvers_, id)); - scoped_ptr<ServiceResolver> resolver( - service_discovery_client_->CreateServiceResolver( - service_name, - base::Bind(&ServiceDiscoveryMessageHandler::OnServiceResolved, - base::Unretained(this), id))); - resolver->StartResolving(); - service_resolvers_[id].reset(resolver.release()); -} - -void ServiceDiscoveryMessageHandler::DestroyResolver(uint64_t id) { - VLOG(1) << "DestroyResolver, id=" << id; - if (!service_discovery_client_) - return; - service_resolvers_.erase(id); -} - -void ServiceDiscoveryMessageHandler::ResolveLocalDomain( - uint64_t id, - const std::string& domain, - net::AddressFamily address_family) { - VLOG(1) << "ResolveLocalDomain, id=" << id << ", domain=" << domain; - if (!service_discovery_client_) - return; - DCHECK(!ContainsKey(local_domain_resolvers_, id)); - scoped_ptr<LocalDomainResolver> resolver( - service_discovery_client_->CreateLocalDomainResolver( - domain, address_family, - base::Bind(&ServiceDiscoveryMessageHandler::OnLocalDomainResolved, - base::Unretained(this), id))); - resolver->Start(); - local_domain_resolvers_[id].reset(resolver.release()); -} - -void ServiceDiscoveryMessageHandler::DestroyLocalDomainResolver(uint64_t id) { - VLOG(1) << "DestroyLocalDomainResolver, id=" << id; - if (!service_discovery_client_) - return; - local_domain_resolvers_.erase(id); -} - -void ServiceDiscoveryMessageHandler::ShutdownLocalDiscovery() { - if (!discovery_task_runner_.get()) - return; - - discovery_task_runner_->PostTask( - FROM_HERE, - base::Bind(&ServiceDiscoveryMessageHandler::ShutdownOnIOThread, - base::Unretained(this))); - - // This will wait for message loop to drain, so ShutdownOnIOThread will - // definitely be called. - discovery_thread_.reset(); -} - -void ServiceDiscoveryMessageHandler::ShutdownOnIOThread() { - VLOG(1) << "ShutdownLocalDiscovery"; - service_watchers_.clear(); - service_resolvers_.clear(); - local_domain_resolvers_.clear(); - service_discovery_client_.reset(); - mdns_client_.reset(); -} - -void ServiceDiscoveryMessageHandler::OnServiceUpdated( - uint64_t id, - ServiceWatcher::UpdateType update, - const std::string& name) { - VLOG(1) << "OnServiceUpdated, id=" << id - << ", status=" << WatcherUpdateToString(update) << ", name=" << name; - DCHECK(service_discovery_client_); - - Send(new LocalDiscoveryHostMsg_WatcherCallback(id, update, name)); -} - -void ServiceDiscoveryMessageHandler::OnServiceResolved( - uint64_t id, - ServiceResolver::RequestStatus status, - const ServiceDescription& description) { - VLOG(1) << "OnServiceResolved, id=" << id - << ", status=" << ResolverStatusToString(status) - << ", name=" << description.service_name; - - DCHECK(service_discovery_client_); - Send(new LocalDiscoveryHostMsg_ResolverCallback(id, status, description)); -} - -void ServiceDiscoveryMessageHandler::OnLocalDomainResolved( - uint64_t id, - bool success, - const net::IPAddressNumber& address_ipv4, - const net::IPAddressNumber& address_ipv6) { - VLOG(1) << "OnLocalDomainResolved, id=" << id - << ", IPv4=" << (address_ipv4.empty() ? "" : - net::IPAddressToString(address_ipv4)) - << ", IPv6=" << (address_ipv6.empty() ? "" : - net::IPAddressToString(address_ipv6)); - - DCHECK(service_discovery_client_); - Send(new LocalDiscoveryHostMsg_LocalDomainResolverCallback( - id, success, address_ipv4, address_ipv6)); -} - -void ServiceDiscoveryMessageHandler::Send(IPC::Message* msg) { - utility_task_runner_->PostTask(FROM_HERE, - base::Bind(&SendHostMessageOnUtilityThread, - msg)); -} - -} // namespace local_discovery
diff --git a/chrome/utility/local_discovery/service_discovery_message_handler.h b/chrome/utility/local_discovery/service_discovery_message_handler.h deleted file mode 100644 index ce0435d..0000000 --- a/chrome/utility/local_discovery/service_discovery_message_handler.h +++ /dev/null
@@ -1,123 +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_UTILITY_LOCAL_DISCOVERY_SERVICE_DISCOVERY_MESSAGE_HANDLER_H_ -#define CHROME_UTILITY_LOCAL_DISCOVERY_SERVICE_DISCOVERY_MESSAGE_HANDLER_H_ - -#include <stdint.h> - -#include <map> -#include <string> - -#include "base/memory/linked_ptr.h" -#include "build/build_config.h" -#include "chrome/common/local_discovery/service_discovery_client.h" -#include "chrome/utility/utility_message_handler.h" - -struct LocalDiscoveryMsg_SocketInfo; - -namespace net { -class MDnsClient; -} - -namespace base { -struct FileDescriptor; -class TaskRunner; -class Thread; -} - -namespace tracked_objects { -class Location; -} - -namespace local_discovery { - -class ServiceDiscoveryClient; - -// Handles messages related to local discovery inside utility process. -class ServiceDiscoveryMessageHandler : public UtilityMessageHandler { - public: - ServiceDiscoveryMessageHandler(); - ~ServiceDiscoveryMessageHandler() override; - - // UtilityMessageHandler implementation. - bool OnMessageReceived(const IPC::Message& message) override; - - static void PreSandboxStartup(); - - private: - typedef std::map<uint64_t, linked_ptr<ServiceWatcher>> ServiceWatchers; - typedef std::map<uint64_t, linked_ptr<ServiceResolver>> ServiceResolvers; - typedef std::map<uint64_t, linked_ptr<LocalDomainResolver>> - LocalDomainResolvers; - - // Lazy initializes ServiceDiscoveryClient. - bool InitializeThread(); - void PostTask(const tracked_objects::Location& from_here, - const base::Closure& task); - - // IPC message handlers. -#if defined(OS_POSIX) - void OnSetSockets(const std::vector<LocalDiscoveryMsg_SocketInfo>& sockets); -#endif // OS_POSIX - void OnStartWatcher(uint64_t id, const std::string& service_type); - void OnDiscoverServices(uint64_t id, bool force_update); - void OnSetActivelyRefreshServices(uint64_t id, - bool actively_refresh_services); - void OnDestroyWatcher(uint64_t id); - void OnResolveService(uint64_t id, const std::string& service_name); - void OnDestroyResolver(uint64_t id); - void OnResolveLocalDomain(uint64_t id, - const std::string& domain, - net::AddressFamily address_family); - void OnDestroyLocalDomainResolver(uint64_t id); - - void InitializeMdns(); - void StartWatcher(uint64_t id, const std::string& service_type); - void DiscoverServices(uint64_t id, bool force_update); - void SetActivelyRefreshServices(uint64_t id, bool actively_refresh_services); - void DestroyWatcher(uint64_t id); - void ResolveService(uint64_t id, const std::string& service_name); - void DestroyResolver(uint64_t id); - void ResolveLocalDomain(uint64_t id, - const std::string& domain, - net::AddressFamily address_family); - void DestroyLocalDomainResolver(uint64_t id); - - void ShutdownLocalDiscovery(); - void ShutdownOnIOThread(); - - // Is called by ServiceWatcher as callback. - void OnServiceUpdated(uint64_t id, - ServiceWatcher::UpdateType update, - const std::string& name); - - // Is called by ServiceResolver as callback. - void OnServiceResolved(uint64_t id, - ServiceResolver::RequestStatus status, - const ServiceDescription& description); - - // Is called by LocalDomainResolver as callback. - void OnLocalDomainResolved(uint64_t id, - bool success, - const net::IPAddressNumber& address_ipv4, - const net::IPAddressNumber& address_ipv6); - - void Send(IPC::Message* msg); - - ServiceWatchers service_watchers_; - ServiceResolvers service_resolvers_; - LocalDomainResolvers local_domain_resolvers_; - - scoped_ptr<net::MDnsClient> mdns_client_; - scoped_ptr<ServiceDiscoveryClient> service_discovery_client_; - - scoped_refptr<base::TaskRunner> utility_task_runner_; - scoped_refptr<base::TaskRunner> discovery_task_runner_; - scoped_ptr<base::Thread> discovery_thread_; -}; - -} // namespace local_discovery - -#endif // CHROME_UTILITY_LOCAL_DISCOVERY_SERVICE_DISCOVERY_MESSAGE_HANDLER_H_
diff --git a/chromecast/BUILD.gn b/chromecast/BUILD.gn index 4a939804..275480f 100644 --- a/chromecast/BUILD.gn +++ b/chromecast/BUILD.gn
@@ -7,6 +7,7 @@ import("//build/config/ui.gni") import("//chromecast/build/tests/cast_test.gni") import("//chromecast/chromecast.gni") +import("//media/media_options.gni") import("//tools/grit/repack.gni") import("//ui/ozone/ozone.gni") @@ -112,6 +113,13 @@ # --enable-local-file-accesses => to load sample media files # --test-launcher-jobs=1 => so internal code can bind to port filters += [ "cast_shell_browser_test --no-sandbox --enable-local-file-accesses --enable-cma-media-pipeline --ozone-platform=cast --test-launcher-jobs=1" ] + + # TODO(slan): Reenable this test for Desktop x86 when CQ supports it. + # (b/26429268) + if (use_alsa && !is_cast_desktop_build) { + tests += + [ "//chromecast/media/cma/backend/alsa:alsa_cma_backend_unittests" ] + } } if (!disable_display) {
diff --git a/chromecast/base/BUILD.gn b/chromecast/base/BUILD.gn index 81c20ff..355c0da7 100644 --- a/chromecast/base/BUILD.gn +++ b/chromecast/base/BUILD.gn
@@ -14,6 +14,8 @@ "android/system_time_change_notifier_android.cc", "android/system_time_change_notifier_android.h", "bind_to_task_runner.h", + "cast_constants.cc", + "cast_constants.h", "cast_paths.cc", "cast_paths.h", "cast_resource.cc",
diff --git a/chromecast/base/cast_constants.cc b/chromecast/base/cast_constants.cc new file mode 100644 index 0000000..9caf71f --- /dev/null +++ b/chromecast/base/cast_constants.cc
@@ -0,0 +1,11 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chromecast/base/cast_constants.h" + +namespace chromecast { + +const char kChromeResourceScheme[] = "chrome-resource"; + +} // namespace chromecast
diff --git a/chromecast/base/cast_constants.h b/chromecast/base/cast_constants.h new file mode 100644 index 0000000..d65777fa --- /dev/null +++ b/chromecast/base/cast_constants.h
@@ -0,0 +1,14 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROMECAST_BASE_CAST_CONSTANTS_H_ +#define CHROMECAST_BASE_CAST_CONSTANTS_H_ + +namespace chromecast { + +extern const char kChromeResourceScheme[]; + +} // namespace chromecast + +#endif // CHROMECAST_BASE_CAST_CONSTANTS_H_
diff --git a/chromecast/base/chromecast_switches.cc b/chromecast/base/chromecast_switches.cc index 94186c8..25438ac 100644 --- a/chromecast/base/chromecast_switches.cc +++ b/chromecast/base/chromecast_switches.cc
@@ -32,4 +32,23 @@ // started. const char kPreviousApp[] = "previous-app"; +// Size of the ALSA output buffer in frames. This directly sets the latency of +// the output device. Latency can be calculated by multiplying the sample rate +// by the output buffer size. +const char kAlsaOutputBufferSize[] = "alsa-output-buffer-size"; + +// Size of the ALSA output period in frames. The period of an ALSA output device +// determines how many frames elapse between hardware interrupts. +const char kAlsaOutputPeriodSize[] = "alsa-output-period-size"; + +// How many frames need to be in the output buffer before output starts. +const char kAlsaOutputStartThreshold[] = "alsa-output-start-threshold"; + +// Minimum number of available frames for scheduling a transfer. +const char kAlsaOutputAvailMin[] = "alsa-output-avail-min"; + +// Time in ms to wait before closing the PCM handle when no more mixer inputs +// remain. +const char kAlsaCheckCloseTimeout[] = "alsa-check-close-timeout"; + } // namespace switches
diff --git a/chromecast/base/chromecast_switches.h b/chromecast/base/chromecast_switches.h index f811db2..1ac84d87 100644 --- a/chromecast/base/chromecast_switches.h +++ b/chromecast/base/chromecast_switches.h
@@ -29,6 +29,13 @@ extern const char kLastLaunchedApp[]; extern const char kPreviousApp[]; +// ALSA-based CMA switches. (Only valid for audio products.) +extern const char kAlsaOutputBufferSize[]; +extern const char kAlsaOutputPeriodSize[]; +extern const char kAlsaOutputStartThreshold[]; +extern const char kAlsaOutputAvailMin[]; +extern const char kAlsaCheckCloseTimeout[]; + } // namespace switches #endif // CHROMECAST_BASE_CHROMECAST_SWITCHES_H_
diff --git a/chromecast/browser/cast_browser_main_parts.cc b/chromecast/browser/cast_browser_main_parts.cc index a7037237f..9f31a1e 100644 --- a/chromecast/browser/cast_browser_main_parts.cc +++ b/chromecast/browser/cast_browser_main_parts.cc
@@ -19,6 +19,7 @@ #include "base/thread_task_runner_handle.h" #include "build/build_config.h" #include "cc/base/switches.h" +#include "chromecast/base/cast_constants.h" #include "chromecast/base/cast_paths.h" #include "chromecast/base/cast_sys_info_util.h" #include "chromecast/base/chromecast_switches.h" @@ -41,6 +42,7 @@ #include "chromecast/public/cast_sys_info.h" #include "chromecast/service/cast_service.h" #include "content/public/browser/browser_thread.h" +#include "content/public/browser/child_process_security_policy.h" #include "content/public/browser/gpu_data_manager.h" #include "content/public/common/content_switches.h" #include "gpu/command_buffer/service/gpu_switches.h" @@ -325,6 +327,9 @@ gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE, cast_browser_process_->cast_screen()); #endif + + content::ChildProcessSecurityPolicy::GetInstance()->RegisterWebSafeScheme( + kChromeResourceScheme); return 0; }
diff --git a/chromecast/browser/cast_content_browser_client.cc b/chromecast/browser/cast_content_browser_client.cc index 3021c9c1..654a64a 100644 --- a/chromecast/browser/cast_content_browser_client.cc +++ b/chromecast/browser/cast_content_browser_client.cc
@@ -16,6 +16,7 @@ #include "base/path_service.h" #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" +#include "chromecast/base/cast_constants.h" #include "chromecast/base/cast_paths.h" #include "chromecast/base/chromecast_switches.h" #include "chromecast/browser/cast_browser_context.h" @@ -171,11 +172,12 @@ return false; static const char* const kProtocolList[] = { - url::kBlobScheme, - url::kFileSystemScheme, - content::kChromeUIScheme, - content::kChromeDevToolsScheme, - url::kDataScheme, + content::kChromeUIScheme, + content::kChromeDevToolsScheme, + kChromeResourceScheme, + url::kBlobScheme, + url::kDataScheme, + url::kFileSystemScheme, }; const std::string& scheme = url.scheme(); @@ -410,6 +412,11 @@ #endif // defined(OS_ANDROID) +void CastContentBrowserClient::GetAdditionalWebUISchemes( + std::vector<std::string>* additional_schemes) { + additional_schemes->push_back(kChromeResourceScheme); +} + #if defined(OS_ANDROID) && defined(VIDEO_HOLE) content::ExternalVideoSurfaceContainer* CastContentBrowserClient::OverrideCreateExternalVideoSurfaceContainer(
diff --git a/chromecast/browser/cast_content_browser_client.h b/chromecast/browser/cast_content_browser_client.h index ff3805c..9ab3af7 100644 --- a/chromecast/browser/cast_content_browser_client.h +++ b/chromecast/browser/cast_content_browser_client.h
@@ -152,6 +152,8 @@ int child_process_id, content::FileDescriptorInfo* mappings) override; #endif // defined(OS_ANDROID) + void GetAdditionalWebUISchemes( + std::vector<std::string>* additional_schemes) override; #if defined(OS_ANDROID) && defined(VIDEO_HOLE) content::ExternalVideoSurfaceContainer* OverrideCreateExternalVideoSurfaceContainer(
diff --git a/chromecast/chromecast.gyp b/chromecast/chromecast.gyp index 3a6080e..4d78212 100644 --- a/chromecast/chromecast.gyp +++ b/chromecast/chromecast.gyp
@@ -88,6 +88,8 @@ 'base/android/system_time_change_notifier_android.cc', 'base/android/system_time_change_notifier_android.h', 'base/bind_to_task_runner.h', + 'base/cast_constants.cc', + 'base/cast_constants.h', 'base/cast_paths.cc', 'base/cast_paths.h', 'base/cast_resource.h',
diff --git a/chromecast/chromecast_tests.gypi b/chromecast/chromecast_tests.gypi index 71a28c0..7fbbde9 100644 --- a/chromecast/chromecast_tests.gypi +++ b/chromecast/chromecast_tests.gypi
@@ -4,7 +4,8 @@ { 'variables': { - 'chromium_code': 1 + 'chromium_code': 1, + 'use_alsa%': 0, }, 'targets': [ { @@ -186,6 +187,15 @@ 'cast_shell_browser_test --no-sandbox --enable-local-file-accesses --enable-cma-media-pipeline --ozone-platform=cast --test-launcher-jobs=1', ], }, + 'conditions': [ + # TODO(slan): Reenable this test for Desktop x86 when CQ supports it. + # (b/26429268) + ['use_alsa==1 and is_cast_desktop_build==0', { + 'dependencies': [ + 'media/media.gyp:alsa_cma_backend_unittests', + ], + }], + ], }], ['disable_display==1', { 'variables': {
diff --git a/chromecast/common/BUILD.gn b/chromecast/common/BUILD.gn index d16b2c8..14d6618 100644 --- a/chromecast/common/BUILD.gn +++ b/chromecast/common/BUILD.gn
@@ -20,9 +20,11 @@ deps = [ "//base", + "//chromecast/base", "//chromecast/base:cast_version", "//content/public/common", "//ui/base", "//ui/gfx", + "//url:url", ] }
diff --git a/chromecast/common/cast_content_client.cc b/chromecast/common/cast_content_client.cc index b442fdd..2332ba66 100644 --- a/chromecast/common/cast_content_client.cc +++ b/chromecast/common/cast_content_client.cc
@@ -9,10 +9,12 @@ #include "base/strings/stringprintf.h" #include "base/sys_info.h" #include "build/build_config.h" +#include "chromecast/base/cast_constants.h" #include "chromecast/base/version.h" #include "content/public/common/user_agent.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/resource/resource_bundle.h" +#include "url/url_util.h" namespace chromecast { namespace shell { @@ -50,6 +52,10 @@ } #endif +const url::SchemeWithType kChromeResourceSchemeWithType = { + kChromeResourceScheme, url::SCHEME_WITHOUT_PORT +}; + } // namespace std::string GetUserAgent() { @@ -73,6 +79,12 @@ CastContentClient::~CastContentClient() { } +void CastContentClient::AddAdditionalSchemes( + std::vector<url::SchemeWithType>* standard_schemes, + std::vector<std::string>* savable_schemes) { + standard_schemes->push_back(kChromeResourceSchemeWithType); +} + std::string CastContentClient::GetUserAgent() const { return chromecast::shell::GetUserAgent(); }
diff --git a/chromecast/common/cast_content_client.h b/chromecast/common/cast_content_client.h index 8289f41b..f77a610614 100644 --- a/chromecast/common/cast_content_client.h +++ b/chromecast/common/cast_content_client.h
@@ -17,6 +17,8 @@ ~CastContentClient() override; // content::ContentClient implementation: + void AddAdditionalSchemes(std::vector<url::SchemeWithType>* standard_schemes, + std::vector<std::string>* saveable_shemes) override; std::string GetUserAgent() const override; base::string16 GetLocalizedString(int message_id) const override; base::StringPiece GetDataResource(
diff --git a/chromecast/media/cma/backend/alsa/BUILD.gn b/chromecast/media/cma/backend/alsa/BUILD.gn new file mode 100644 index 0000000..c12367d --- /dev/null +++ b/chromecast/media/cma/backend/alsa/BUILD.gn
@@ -0,0 +1,109 @@ +# 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/buildflag_header.gni") +import("//media/media_options.gni") +import("//testing/test.gni") + +declare_args() { + # Set true to use raw timestamps. This should only be enabled when the ALSA + # library supports it. + use_alsa_monotonic_raw_tstamps = false +} + +# Alsa must be used for these targets to build. +assert(use_alsa) + +# GYP target: chromecast/media/media.gyp:libcast_media_1.0_audio +shared_library("libcast_media_1.0_audio") { + sources = [ + "//chromecast/media/base/media_caps.cc", + "//chromecast/media/base/media_caps.h", + "cast_media_shlib.cc", + "media_codec_support_cast_audio.cc", + ] + deps = [ + ":alsa_cma_backend", + "//base", + "//chromecast/base", + "//chromecast/public", + "//media", + ] +} + +# GYP target: chromecast/media/media.gyp:alsa_cma_backend +source_set("alsa_cma_backend") { + sources = [ + "alsa_wrapper.cc", + "alsa_wrapper.h", + "audio_decoder_alsa.cc", + "audio_decoder_alsa.h", + "media_pipeline_backend_alsa.cc", + "media_pipeline_backend_alsa.h", + "stream_mixer_alsa.cc", + "stream_mixer_alsa.h", + "stream_mixer_alsa_input.cc", + "stream_mixer_alsa_input.h", + "stream_mixer_alsa_input_impl.cc", + "stream_mixer_alsa_input_impl.h", + ] + + deps = [ + ":alsa_features", + "//base", + "//chromecast/base", + "//chromecast/media/cma/backend", + "//chromecast/media/cma/base", + "//chromecast/media/cma/decoder", + "//chromecast/public/media", + "//media", + "//media:shared_memory_support", + ] +} + +# GYP target: chromecast/media/media.gyp:chromecast_alsa_features +buildflag_header("alsa_features") { + header = "alsa_features.h" + + flags = [ "ALSA_MONOTONIC_RAW_TSTAMPS=$use_alsa_monotonic_raw_tstamps" ] +} + +# GYP target: chromecast/media/media.gyp:alsa_cma_backend_unittests +test("alsa_cma_backend_unittests") { + sources = [ + "stream_mixer_alsa_unittest.cc", + ] + + deps = [ + ":test_support", + "//base", + "//base/test:run_all_unittests", + "//chromecast/media/base", + "//chromecast/media/base:libcast_media_1.0_default_core", + "//media", + "//media:shared_memory_support", + "//testing/gmock", + "//testing/gtest", + ] +} + +# GYP target: n/a +source_set("test_support") { + testonly = true + + sources = [ + "mock_alsa_wrapper.cc", + "mock_alsa_wrapper.h", + ] + + public_deps = [ + ":alsa_cma_backend", + ] + + deps = [ + "//base", + "//media", + "//testing/gmock", + ] +}
diff --git a/chromecast/media/cma/backend/alsa/alsa_fsm.dot b/chromecast/media/cma/backend/alsa/alsa_fsm.dot new file mode 100644 index 0000000..8c5d7ac --- /dev/null +++ b/chromecast/media/cma/backend/alsa/alsa_fsm.dot
@@ -0,0 +1,91 @@ +digraph { +// This specifies a diagram using the DOT language. It can be interactively +// viewed with xdot or can generate an image using +// `dot -Tpng alsa_fsm.dot > alsa_fsm.png` + +// This was build out of the state transition information from +// linux/sound/core/pcm_native.c and linux/sound/core/pcm_lib.c. Since it is +// intended to help with writing software which uses ALSA's PCM interface, it +// includes every possible transition, even if they are unlikely, rather than +// trying to model a more typical software path. + +// snd_pcm_hw_free is called as a result of snd_pcm_close +// snd_pcm_hwsync is called before querying any hardware state such as in +// snd_pcm_avail. + +// From the perspective of the state machine, snd_pcm_capture_rewind and +// snd_pcm_playback rewind are the same function so they are not +// distinguished in this diagram. This also holds for the forward +// functions. + +// For all states the a SND_PCM_STATE_ prefix has been omitted to clarify +// the state machine. + +// For all transitions the snd_pcm_ prefix has been omitted to clarify +// the state machine. + +rankdir=BT; + +// Bulk processing +ANY [label = "any state"]; +ANY -> SUSPENDED [label = suspend]; +SUSPENDED -> ANY [label = resume]; + +// snd_pcm_dev_disconnect is the only kernel-only ALSA function included in +// this diagram because it is the only way to transition into the +// SNDRV_PCM_STATE_DISCONNECTED state and that state should be accounted for +// when designing code which directly interacts with ALSA and might use USB +// audio devices which may be disconnected in use. +ANY -> DISCONNECTED [label = dev_disconnect]; +ANY -> ANY [label = "info/hw_refine/unlink/sync_ptr/tstamp"]; + +NOT_OPEN [label = "any state but OPEN"] +NOT_OPEN -> NOT_OPEN [label = "sw_params/channel_info/link"]; + +// State-specific transitions. +unitialized [label="", shape=none]; +unitialized -> OPEN [label = open]; + +OPEN -> OPEN [label = hw_params]; +OPEN -> SETUP [label = hw_params]; + +SETUP -> OPEN [label = hw_free]; +SETUP -> SETUP [label = "hw_params/drain/drop"]; +SETUP -> PREPARED [label = prepare]; + +PREPARED -> OPEN [label = "hw_free/reset"]; +PREPARED -> SETUP [label = "hw_params/drop"]; +PREPARED -> PREPARED [label = "prepare/rewind/forward/hwsync/delay"]; +PREPARED -> RUNNING [label = "start/writei"]; +PREPARED -> DRAINING [label = drain]; + +RUNNING -> OPEN [label = reset]; +RUNNING -> SETUP [label = "drain/drop"]; +RUNNING -> RUNNING [label = "rewind/forward/hwsync/delay/writei"]; +RUNNING -> XRUN [label = "xrun/hwsync/writei"]; +RUNNING -> DRAINING [label = drain]; +RUNNING -> PAUSED [label = pause]; + +// snd_pcm_xrun is called if an xrun is detected by +// snd_pcm_hw_avail_update. It puts the kernel-based ALSA code into the +// SNDRV_PCM_STATE_XRUN state. +XRUN -> SETUP[label = "drain/drop"]; +XRUN -> PREPARED [label = prepare]; +XRUN -> XRUN [label = xrun]; + +DRAINING -> SETUP [label = "sw_params/status/drain/drop/delay"]; +DRAINING -> PREPARED [label = prepare]; +DRAINING -> DRAINING [label = "drain/rewind/forward"]; + +PAUSED -> OPEN [label = reset]; +PAUSED -> SETUP [label = "drain/drop"]; +PAUSED -> PREPARED [label = prepare]; +PAUSED -> RUNNING [label = pause]; +PAUSED -> DRAINING [label = drain]; +PAUSED -> PAUSED [label = "forward/writei"]; + +SUSPENDED -> OPEN [label = reset]; +SUSPENDED -> PREPARED [label = prepare]; +SUSPENDED -> SUSPENDED [label = "hwsync/delay"]; + +}
diff --git a/chromecast/media/cma/backend/alsa/alsa_wrapper.cc b/chromecast/media/cma/backend/alsa/alsa_wrapper.cc new file mode 100644 index 0000000..5898b286 --- /dev/null +++ b/chromecast/media/cma/backend/alsa/alsa_wrapper.cc
@@ -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. + +#include "chromecast/media/cma/backend/alsa/alsa_wrapper.h" + +#include "chromecast/media/cma/backend/alsa/alsa_features.h" + +namespace chromecast { +namespace media { + +#if BUILDFLAG(ALSA_MONOTONIC_RAW_TSTAMPS) +const int kAlsaTstampTypeMonotonicRaw = + static_cast<int>(SND_PCM_TSTAMP_TYPE_MONOTONIC_RAW); +#else +const int kAlsaTstampTypeMonotonicRaw = 0; +#endif // BUILDFLAG(ALSA_MONOTONIC_RAW_TSTAMPS) + +AlsaWrapper::AlsaWrapper() { +} + +AlsaWrapper::~AlsaWrapper() { +} + +int AlsaWrapper::PcmPause(snd_pcm_t* handle, int enable) { + return snd_pcm_pause(handle, enable); +} + +int AlsaWrapper::PcmStatusMalloc(snd_pcm_status_t** ptr) { + return snd_pcm_status_malloc(ptr); +} + +void AlsaWrapper::PcmStatusFree(snd_pcm_status_t* obj) { + snd_pcm_status_free(obj); +} + +int AlsaWrapper::PcmStatus(snd_pcm_t* handle, snd_pcm_status_t* status) { + return snd_pcm_status(handle, status); +} + +snd_pcm_sframes_t AlsaWrapper::PcmStatusGetDelay(const snd_pcm_status_t* obj) { + return snd_pcm_status_get_delay(obj); +} + +ssize_t AlsaWrapper::PcmFormatSize(snd_pcm_format_t format, size_t samples) { + return snd_pcm_format_size(format, samples); +} + +void AlsaWrapper::PcmStatusGetHtstamp(const snd_pcm_status_t* obj, + snd_htimestamp_t* ptr) { + snd_pcm_status_get_htstamp(obj, ptr); +} + +int AlsaWrapper::PcmHwParamsMalloc(snd_pcm_hw_params_t** ptr) { + return snd_pcm_hw_params_malloc(ptr); +} + +void AlsaWrapper::PcmHwParamsFree(snd_pcm_hw_params_t* obj) { + snd_pcm_hw_params_free(obj); +} + +int AlsaWrapper::PcmHwParamsCurrent(snd_pcm_t* handle, + snd_pcm_hw_params_t* params) { + return snd_pcm_hw_params_current(handle, params); +} + +int AlsaWrapper::PcmHwParamsCanPause(const snd_pcm_hw_params_t* params) { + return snd_pcm_hw_params_can_pause(params); +} + +int AlsaWrapper::PcmHwParamsSetRateResample(snd_pcm_t* handle, + snd_pcm_hw_params_t* params, + bool val) { + return snd_pcm_hw_params_set_rate_resample(handle, params, val); +} + +int AlsaWrapper::PcmHwParamsSetAccess(snd_pcm_t* handle, + snd_pcm_hw_params_t* params, + snd_pcm_access_t access) { + return snd_pcm_hw_params_set_access(handle, params, access); +} + +int AlsaWrapper::PcmHwParamsSetFormat(snd_pcm_t* handle, + snd_pcm_hw_params_t* params, + snd_pcm_format_t format) { + return snd_pcm_hw_params_set_format(handle, params, format); +} + +int AlsaWrapper::PcmHwParamsSetChannels(snd_pcm_t* handle, + snd_pcm_hw_params_t* params, + unsigned int num_channels) { + return snd_pcm_hw_params_set_channels(handle, params, num_channels); +} + +int AlsaWrapper::PcmHwParamsSetRateNear(snd_pcm_t* handle, + snd_pcm_hw_params_t* params, + unsigned int* rate, + int* dir) { + return snd_pcm_hw_params_set_rate_near(handle, params, rate, dir); +} + +int AlsaWrapper::PcmHwParamsSetBufferSizeNear(snd_pcm_t* handle, + snd_pcm_hw_params_t* params, + snd_pcm_uframes_t* val) { + return snd_pcm_hw_params_set_buffer_size_near(handle, params, val); +} + +int AlsaWrapper::PcmHwParamsSetPeriodSizeNear(snd_pcm_t* handle, + snd_pcm_hw_params_t* params, + snd_pcm_uframes_t* val, + int* dir) { + return snd_pcm_hw_params_set_period_size_near(handle, params, val, dir); +} + +int AlsaWrapper::PcmHwParamsTestFormat(snd_pcm_t* handle, + snd_pcm_hw_params_t* params, + snd_pcm_format_t format) { + return snd_pcm_hw_params_test_format(handle, params, format); +} + +int AlsaWrapper::PcmHwParamsTestRate(snd_pcm_t* handle, + snd_pcm_hw_params_t* params, + unsigned int rate, + int dir) { + return snd_pcm_hw_params_test_rate(handle, params, rate, dir); +} + +int AlsaWrapper::PcmHwParamsAny(snd_pcm_t* handle, + snd_pcm_hw_params_t* params) { + return snd_pcm_hw_params_any(handle, params); +} + +int AlsaWrapper::PcmHwParams(snd_pcm_t* handle, snd_pcm_hw_params_t* params) { + return snd_pcm_hw_params(handle, params); +} + +int AlsaWrapper::PcmSwParamsMalloc(snd_pcm_sw_params_t** params) { + return snd_pcm_sw_params_malloc(params); +} + +void AlsaWrapper::PcmSwParamsFree(snd_pcm_sw_params_t* params) { + snd_pcm_sw_params_free(params); +} + +int AlsaWrapper::PcmSwParamsCurrent(snd_pcm_t* handle, + snd_pcm_sw_params_t* params) { + return snd_pcm_sw_params_current(handle, params); +} + +int AlsaWrapper::PcmSwParamsSetStartThreshold(snd_pcm_t* handle, + snd_pcm_sw_params_t* params, + snd_pcm_uframes_t val) { + return snd_pcm_sw_params_set_start_threshold(handle, params, val); +} + +int AlsaWrapper::PcmSwParamsSetAvailMin(snd_pcm_t* handle, + snd_pcm_sw_params_t* params, + snd_pcm_uframes_t val) { + return snd_pcm_sw_params_set_avail_min(handle, params, val); +} + +int AlsaWrapper::PcmSwParamsSetTstampMode(snd_pcm_t* handle, + snd_pcm_sw_params_t* obj, + snd_pcm_tstamp_t val) { + return snd_pcm_sw_params_set_tstamp_mode(handle, obj, val); +} + +int AlsaWrapper::PcmSwParamsSetTstampType(snd_pcm_t* handle, + snd_pcm_sw_params_t* obj, + int val) { +#if BUILDFLAG(ALSA_MONOTONIC_RAW_TSTAMPS) + return snd_pcm_sw_params_set_tstamp_type( + handle, obj, static_cast<snd_pcm_tstamp_type_t>(val)); +#else + return 0; +#endif // BUILDFLAG(ALSA_MONOTONIC_RAW_TSTAMPS) +} + +int AlsaWrapper::PcmSwParams(snd_pcm_t* handle, snd_pcm_sw_params_t* params) { + return snd_pcm_sw_params(handle, params); +} + +} // namespace media +} // namespace chromecast
diff --git a/chromecast/media/cma/backend/alsa/alsa_wrapper.h b/chromecast/media/cma/backend/alsa/alsa_wrapper.h new file mode 100644 index 0000000..1e33a9b --- /dev/null +++ b/chromecast/media/cma/backend/alsa/alsa_wrapper.h
@@ -0,0 +1,94 @@ +// 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_CMA_BACKEND_ALSA_ALSA_WRAPPER_H_ +#define CHROMECAST_MEDIA_CMA_BACKEND_ALSA_ALSA_WRAPPER_H_ + +#include "base/macros.h" +#include "media/audio/alsa/alsa_wrapper.h" + +namespace chromecast { +namespace media { + +extern const int kAlsaTstampTypeMonotonicRaw; + +// Extends the Chromium AlsaWrapper, adding additional functions that we use. +class AlsaWrapper : public ::media::AlsaWrapper { + public: + AlsaWrapper(); + ~AlsaWrapper() override; + + virtual int PcmPause(snd_pcm_t* handle, int enable); + + virtual int PcmStatusMalloc(snd_pcm_status_t** ptr); + virtual void PcmStatusFree(snd_pcm_status_t* obj); + virtual int PcmStatus(snd_pcm_t* handle, snd_pcm_status_t* status); + virtual snd_pcm_sframes_t PcmStatusGetDelay(const snd_pcm_status_t* obj); + virtual void PcmStatusGetHtstamp(const snd_pcm_status_t* obj, + snd_htimestamp_t* ptr); + virtual ssize_t PcmFormatSize(snd_pcm_format_t format, size_t samples); + virtual int PcmHwParamsMalloc(snd_pcm_hw_params_t** ptr); + virtual void PcmHwParamsFree(snd_pcm_hw_params_t* obj); + virtual int PcmHwParamsCurrent(snd_pcm_t* handle, + snd_pcm_hw_params_t* params); + virtual int PcmHwParamsCanPause(const snd_pcm_hw_params_t* params); + virtual int PcmHwParamsAny(snd_pcm_t* handle, snd_pcm_hw_params_t* params); + virtual int PcmHwParamsSetRateResample(snd_pcm_t* handle, + snd_pcm_hw_params_t* params, + bool val); + virtual int PcmHwParamsSetAccess(snd_pcm_t* handle, + snd_pcm_hw_params_t* params, + snd_pcm_access_t access); + virtual int PcmHwParamsSetFormat(snd_pcm_t* handle, + snd_pcm_hw_params_t* params, + snd_pcm_format_t format); + virtual int PcmHwParamsSetChannels(snd_pcm_t* handle, + snd_pcm_hw_params_t* params, + unsigned int num_channels); + virtual int PcmHwParamsSetRateNear(snd_pcm_t* handle, + snd_pcm_hw_params_t* params, + unsigned int* rate, + int* dir); + virtual int PcmHwParamsSetBufferSizeNear(snd_pcm_t* handle, + snd_pcm_hw_params_t* params, + snd_pcm_uframes_t* val); + virtual int PcmHwParamsSetPeriodSizeNear(snd_pcm_t* handle, + snd_pcm_hw_params_t* params, + snd_pcm_uframes_t* val, + int* dir); + virtual int PcmHwParamsTestFormat(snd_pcm_t* handle, + snd_pcm_hw_params_t* params, + snd_pcm_format_t format); + virtual int PcmHwParamsTestRate(snd_pcm_t* handle, + snd_pcm_hw_params_t* params, + unsigned int rate, + int dir); + virtual int PcmHwParams(snd_pcm_t* handle, snd_pcm_hw_params_t* params); + + virtual int PcmSwParamsMalloc(snd_pcm_sw_params_t** params); + virtual void PcmSwParamsFree(snd_pcm_sw_params_t* params); + virtual int PcmSwParamsCurrent(snd_pcm_t* handle, + snd_pcm_sw_params_t* params); + virtual int PcmSwParamsSetStartThreshold(snd_pcm_t* handle, + snd_pcm_sw_params_t* params, + snd_pcm_uframes_t val); + virtual int PcmSwParamsSetAvailMin(snd_pcm_t* handle, + snd_pcm_sw_params_t* params, + snd_pcm_uframes_t val); + virtual int PcmSwParamsSetTstampMode(snd_pcm_t* handle, + snd_pcm_sw_params_t* obj, + snd_pcm_tstamp_t val); + virtual int PcmSwParamsSetTstampType(snd_pcm_t* handle, + snd_pcm_sw_params_t* obj, + int val); + virtual int PcmSwParams(snd_pcm_t* handle, snd_pcm_sw_params_t* obj); + + private: + DISALLOW_COPY_AND_ASSIGN(AlsaWrapper); +}; + +} // namespace media +} // namespace chromecast + +#endif // CHROMECAST_MEDIA_CMA_BACKEND_ALSA_ALSA_WRAPPER_H_
diff --git a/chromecast/media/cma/backend/alsa/audio_decoder_alsa.cc b/chromecast/media/cma/backend/alsa/audio_decoder_alsa.cc new file mode 100644 index 0000000..9c3aa4f --- /dev/null +++ b/chromecast/media/cma/backend/alsa/audio_decoder_alsa.cc
@@ -0,0 +1,299 @@ +// 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/cma/backend/alsa/audio_decoder_alsa.h" + +#include <time.h> + +#include <algorithm> +#include <limits> + +#include "base/callback_helpers.h" +#include "base/logging.h" +#include "base/macros.h" +#include "base/trace_event/trace_event.h" +#include "chromecast/base/task_runner_impl.h" +#include "chromecast/media/cma/backend/alsa/media_pipeline_backend_alsa.h" +#include "chromecast/media/cma/base/decoder_buffer_base.h" +#include "chromecast/public/media/cast_decoder_buffer.h" + +#define TRACE_FUNCTION_ENTRY0() TRACE_EVENT0("cma", __FUNCTION__) + +#define TRACE_FUNCTION_ENTRY1(arg1) \ + TRACE_EVENT1("cma", __FUNCTION__, #arg1, arg1) + +#define TRACE_FUNCTION_ENTRY2(arg1, arg2) \ + TRACE_EVENT2("cma", __FUNCTION__, #arg1, arg1, #arg2, arg2) + +namespace chromecast { +namespace media { + +namespace { + +const CastAudioDecoder::OutputFormat kDecoderSampleFormat = + CastAudioDecoder::kOutputPlanarFloat; + +const int kInvalidSampleRate = -1; +const int64_t kInvalidDelayTimestamp = std::numeric_limits<int64_t>::min(); + +AudioDecoderAlsa::RenderingDelay kInvalidRenderingDelay() { + AudioDecoderAlsa::RenderingDelay delay; + delay.timestamp_microseconds = kInvalidDelayTimestamp; + delay.delay_microseconds = 0; + return delay; +} + +} // namespace + +AudioDecoderAlsa::AudioDecoderAlsa(MediaPipelineBackendAlsa* backend) + : backend_(backend), + task_runner_(backend->GetTaskRunner()), + delegate_(nullptr), + is_eos_(false), + error_(false), + volume_multiplier_(1.0f), + weak_factory_(this) { + TRACE_FUNCTION_ENTRY0(); + DCHECK(backend_); + DCHECK(task_runner_.get()); + DCHECK(task_runner_->BelongsToCurrentThread()); +} + +AudioDecoderAlsa::~AudioDecoderAlsa() { + TRACE_FUNCTION_ENTRY0(); + DCHECK(task_runner_->BelongsToCurrentThread()); +} + +void AudioDecoderAlsa::SetDelegate( + MediaPipelineBackend::Decoder::Delegate* delegate) { + DCHECK(delegate); + delegate_ = delegate; +} + +bool AudioDecoderAlsa::Initialize() { + TRACE_FUNCTION_ENTRY0(); + DCHECK(delegate_); + stats_ = Statistics(); + is_eos_ = false; + + struct timespec now; + if (clock_gettime(CLOCK_MONOTONIC, &now) == 0) { + last_known_delay_.timestamp_microseconds = + static_cast<int64_t>(now.tv_sec) * 1000000 + now.tv_nsec / 1000; + } else { + LOG(ERROR) << "Failed to get current timestamp"; + last_known_delay_.timestamp_microseconds = kInvalidDelayTimestamp; + return false; + } + last_known_delay_.delay_microseconds = 0; + return true; +} + +bool AudioDecoderAlsa::Start(int64_t start_pts) { + TRACE_FUNCTION_ENTRY0(); + current_pts_ = start_pts; + DCHECK_NE(config_.samples_per_second, kInvalidSampleRate); + mixer_input_.reset(new StreamMixerAlsaInput( + this, config_.samples_per_second, backend_->Primary())); + mixer_input_->SetVolumeMultiplier(volume_multiplier_); + // Create decoder_ if necessary. This can happen if Stop() was called, and + // SetConfig() was not called since then. + if (!decoder_) + CreateDecoder(); + return true; +} + +bool AudioDecoderAlsa::Stop() { + TRACE_FUNCTION_ENTRY0(); + decoder_.reset(); + mixer_input_.reset(); + return Initialize(); +} + +bool AudioDecoderAlsa::Pause() { + TRACE_FUNCTION_ENTRY0(); + DCHECK(mixer_input_); + mixer_input_->SetPaused(true); + return true; +} + +bool AudioDecoderAlsa::Resume() { + TRACE_FUNCTION_ENTRY0(); + DCHECK(mixer_input_); + mixer_input_->SetPaused(false); + return true; +} + +AudioDecoderAlsa::BufferStatus AudioDecoderAlsa::PushBuffer( + CastDecoderBuffer* buffer) { + TRACE_FUNCTION_ENTRY0(); + DCHECK(task_runner_->BelongsToCurrentThread()); + DCHECK(buffer); + DCHECK(!is_eos_); + DCHECK(!error_); + + uint64_t input_bytes = buffer->end_of_stream() ? 0 : buffer->data_size(); + scoped_refptr<DecoderBufferBase> buffer_base( + static_cast<DecoderBufferBase*>(buffer)); + if (!buffer->end_of_stream()) + last_buffer_pts_ = buffer->timestamp(); + + // If the buffer is already decoded, do not attempt to decode. Call + // OnBufferDecoded asynchronously on the main thread. + if (BypassDecoder()) { + DCHECK(!decoder_); + task_runner_->PostTask( + FROM_HERE, + base::Bind(&AudioDecoderAlsa::OnBufferDecoded, + weak_factory_.GetWeakPtr(), input_bytes, + CastAudioDecoder::Status::kDecodeOk, buffer_base)); + return MediaPipelineBackendAlsa::kBufferPending; + } + + DCHECK(decoder_); + // Decode the buffer. + decoder_->Decode(buffer_base, + base::Bind(&AudioDecoderAlsa::OnBufferDecoded, + weak_factory_.GetWeakPtr(), + input_bytes)); + return MediaPipelineBackendAlsa::kBufferPending; +} + +void AudioDecoderAlsa::UpdateStatistics(Statistics delta) { + DCHECK(task_runner_->BelongsToCurrentThread()); + stats_.decoded_bytes += delta.decoded_bytes; +} + +void AudioDecoderAlsa::GetStatistics(Statistics* stats) { + TRACE_FUNCTION_ENTRY0(); + DCHECK(stats); + DCHECK(task_runner_->BelongsToCurrentThread()); + *stats = stats_; +} + +bool AudioDecoderAlsa::SetConfig(const AudioConfig& config) { + TRACE_FUNCTION_ENTRY0(); + DCHECK(task_runner_->BelongsToCurrentThread()); + if (!IsValidConfig(config)) { + LOG(ERROR) << "Invalid audio config passed to SetConfig"; + return false; + } + + if (mixer_input_ && config.samples_per_second != config_.samples_per_second) { + // Destroy the old input first to ensure that the mixer output sample rate + // is updated. + mixer_input_.reset(); + mixer_input_.reset(new StreamMixerAlsaInput( + this, config.samples_per_second, backend_->Primary())); + mixer_input_->SetVolumeMultiplier(volume_multiplier_); + } + + config_ = config; + decoder_.reset(); + CreateDecoder(); + return true; +} + +void AudioDecoderAlsa::CreateDecoder() { + DCHECK(!decoder_); + DCHECK(IsValidConfig(config_)); + + // No need to create a decoder if the samples are already decoded. + if (BypassDecoder()) { + LOG(INFO) << "Data is not coded. Decoder will not be used."; + return; + } + + // Create a decoder. + decoder_ = CastAudioDecoder::Create( + task_runner_, + config_, + kDecoderSampleFormat, + base::Bind(&AudioDecoderAlsa::OnDecoderInitialized, + weak_factory_.GetWeakPtr())); +} + +bool AudioDecoderAlsa::SetVolume(float multiplier) { + TRACE_FUNCTION_ENTRY1(multiplier); + DCHECK(task_runner_->BelongsToCurrentThread()); + volume_multiplier_ = multiplier; + if (mixer_input_) + mixer_input_->SetVolumeMultiplier(volume_multiplier_); + return true; +} + +AudioDecoderAlsa::RenderingDelay AudioDecoderAlsa::GetRenderingDelay() { + TRACE_FUNCTION_ENTRY0(); + return last_known_delay_; +} + +void AudioDecoderAlsa::OnDecoderInitialized(bool success) { + TRACE_FUNCTION_ENTRY0(); + DCHECK(task_runner_->BelongsToCurrentThread()); + LOG(INFO) << "Decoder initialization returned with success = " << success; + if (!success) + delegate_->OnDecoderError(); +} + +void AudioDecoderAlsa::OnBufferDecoded( + uint64_t input_bytes, + CastAudioDecoder::Status status, + const scoped_refptr<DecoderBufferBase>& decoded) { + TRACE_FUNCTION_ENTRY0(); + DCHECK(task_runner_->BelongsToCurrentThread()); + DCHECK(!is_eos_); + + Statistics delta = Statistics(); + + if (status == CastAudioDecoder::Status::kDecodeError) { + LOG(ERROR) << "Decode error"; + task_runner_->PostTask(FROM_HERE, + base::Bind(&AudioDecoderAlsa::OnWritePcmCompletion, + weak_factory_.GetWeakPtr(), + MediaPipelineBackendAlsa::kBufferFailed, + kInvalidRenderingDelay())); + UpdateStatistics(delta); + return; + } + + delta.decoded_bytes = input_bytes; + UpdateStatistics(delta); + + if (decoded->end_of_stream()) + is_eos_ = true; + + DCHECK(mixer_input_); + mixer_input_->WritePcm(decoded); +} + +bool AudioDecoderAlsa::BypassDecoder() const { + DCHECK(task_runner_->BelongsToCurrentThread()); + // The mixer input requires planar float PCM data. + return (config_.codec == kCodecPCM && + config_.sample_format == kSampleFormatPlanarF32); +} + +void AudioDecoderAlsa::OnWritePcmCompletion(BufferStatus status, + const RenderingDelay& delay) { + TRACE_FUNCTION_ENTRY0(); + DCHECK(task_runner_->BelongsToCurrentThread()); + if (status == MediaPipelineBackendAlsa::kBufferSuccess) + current_pts_ = last_buffer_pts_; + if (delay.timestamp_microseconds != kInvalidDelayTimestamp) + last_known_delay_ = delay; + delegate_->OnPushBufferComplete(status); + if (is_eos_) + delegate_->OnEndOfStream(); +} + +void AudioDecoderAlsa::OnMixerError() { + TRACE_FUNCTION_ENTRY0(); + DCHECK(task_runner_->BelongsToCurrentThread()); + LOG(ERROR) << "Mixer error occured."; + error_ = true; + delegate_->OnDecoderError(); +} + +} // namespace media +} // namespace chromecast
diff --git a/chromecast/media/cma/backend/alsa/audio_decoder_alsa.h b/chromecast/media/cma/backend/alsa/audio_decoder_alsa.h new file mode 100644 index 0000000..231eed08 --- /dev/null +++ b/chromecast/media/cma/backend/alsa/audio_decoder_alsa.h
@@ -0,0 +1,94 @@ +// 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_CMA_BACKEND_ALSA_AUDIO_DECODER_ALSA_H_ +#define CHROMECAST_MEDIA_CMA_BACKEND_ALSA_AUDIO_DECODER_ALSA_H_ + +#include "base/bind.h" +#include "base/location.h" +#include "chromecast/media/cma/backend/alsa/stream_mixer_alsa_input.h" +#include "chromecast/media/cma/decoder/cast_audio_decoder.h" +#include "chromecast/public/media/decoder_config.h" +#include "chromecast/public/media/media_pipeline_backend.h" +#include "chromecast/public/media/media_pipeline_device_params.h" + +namespace base { +class SingleThreadTaskRunner; +class Thread; +} // namespace base + +namespace chromecast { +namespace media { +class DecoderBufferBase; +class MediaPipelineBackendAlsa; + +class AudioDecoderAlsa : public MediaPipelineBackend::AudioDecoder, + public StreamMixerAlsaInput::Delegate { + public: + using BufferStatus = MediaPipelineBackend::BufferStatus; + + explicit AudioDecoderAlsa(MediaPipelineBackendAlsa* backend); + ~AudioDecoderAlsa() override; + + bool Initialize(); + bool Start(int64_t start_pts); + bool Stop(); + bool Pause(); + bool Resume(); + + int64_t current_pts() const { return current_pts_; } + + // MediaPipelineBackend::AudioDecoder implementation: + void SetDelegate( + MediaPipelineBackend::Decoder::Delegate* delegate) override; + BufferStatus PushBuffer(CastDecoderBuffer* buffer) override; + void GetStatistics(Statistics* statistics) override; + bool SetConfig(const AudioConfig& config) override; + bool SetVolume(float multiplier) override; + RenderingDelay GetRenderingDelay() override; + + private: + // StreamMixerAlsaInput::Delegate implementation: + void OnWritePcmCompletion(BufferStatus status, + const RenderingDelay& delay) override; + void OnMixerError() override; + + void CleanUpPcm(); + void CreateDecoder(); + void OnDecoderInitialized(bool success); + void OnBufferDecoded(uint64_t input_bytes, + CastAudioDecoder::Status status, + const scoped_refptr<DecoderBufferBase>& decoded); + void RunEos(); + bool BypassDecoder() const; + bool ShouldStartClock() const; + void UpdateStatistics(Statistics delta); + + MediaPipelineBackendAlsa* const backend_; + const scoped_refptr<base::SingleThreadTaskRunner> task_runner_; + MediaPipelineBackend::Decoder::Delegate* delegate_; + + Statistics stats_; + bool is_eos_; + bool error_; + + AudioConfig config_; + scoped_ptr<CastAudioDecoder> decoder_; + + int64_t current_pts_; + int64_t last_buffer_pts_; + + scoped_ptr<StreamMixerAlsaInput> mixer_input_; + RenderingDelay last_known_delay_; + float volume_multiplier_; + + base::WeakPtrFactory<AudioDecoderAlsa> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(AudioDecoderAlsa); +}; + +} // namespace media +} // namespace chromecast + +#endif // CHROMECAST_MEDIA_CMA_BACKEND_ALSA_AUDIO_DECODER_ALSA_H_
diff --git a/chromecast/media/cma/backend/alsa/cast_media_shlib.cc b/chromecast/media/cma/backend/alsa/cast_media_shlib.cc new file mode 100644 index 0000000..0ac44a7 --- /dev/null +++ b/chromecast/media/cma/backend/alsa/cast_media_shlib.cc
@@ -0,0 +1,151 @@ +// 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 <fcntl.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <unistd.h> + +#include "base/at_exit.h" +#include "base/command_line.h" +#include "base/files/scoped_file.h" +#include "base/logging.h" +#include "base/single_thread_task_runner.h" +#include "base/thread_task_runner_handle.h" +#include "chromecast/base/task_runner_impl.h" +#include "chromecast/media/cma/backend/alsa/media_pipeline_backend_alsa.h" +#include "chromecast/public/cast_media_shlib.h" +#include "chromecast/public/graphics_types.h" +#include "chromecast/public/media_codec_support_shlib.h" +#include "chromecast/public/video_plane.h" +#include "media/base/media.h" + +namespace chromecast { +namespace media { +namespace { + +const char kPepperoniAlsaDevName[] = "/dev/snd/hwC0D0"; + +// 1 MHz reference allows easy translation between frequency and PPM. +const double kOneMhzReference = 1e6; +const double kMaxAdjustmentHz = 500; +const double kGranularityHz = 1.0; + +enum { + SNDRV_BERLIN_GET_CLOCK_PPM = 0x1003, + SNDRV_BERLIN_SET_CLOCK_PPM, +}; + +class DefaultVideoPlane : public VideoPlane { + public: + ~DefaultVideoPlane() override {} + + void SetGeometry(const RectF& display_rect, + Transform transform) override {} +}; + +DefaultVideoPlane* g_video_plane = nullptr; + +base::AtExitManager g_at_exit_manager; + +scoped_ptr<base::ThreadTaskRunnerHandle> g_thread_task_runner_handle; + +} // namespace + +void CastMediaShlib::Initialize(const std::vector<std::string>& argv) { + base::CommandLine::Init(0, nullptr); + base::CommandLine::ForCurrentProcess()->InitFromArgv(argv); + + g_video_plane = new DefaultVideoPlane(); + + ::media::InitializeMediaLibrary(); +} + +void CastMediaShlib::Finalize() { + base::CommandLine::Reset(); + + delete g_video_plane; + g_video_plane = nullptr; + + g_thread_task_runner_handle.reset(); +} + +VideoPlane* CastMediaShlib::GetVideoPlane() { + return g_video_plane; +} + +MediaPipelineBackend* CastMediaShlib::CreateMediaPipelineBackend( + const MediaPipelineDeviceParams& params) { + // Set up the static reference in base::ThreadTaskRunnerHandle::Get + // for the media thread in this shared library. We can extract the + // SingleThreadTaskRunner passed in from cast_shell for this. + if (!base::ThreadTaskRunnerHandle::IsSet()) { + DCHECK(!g_thread_task_runner_handle); + const scoped_refptr<base::SingleThreadTaskRunner> task_runner = + static_cast<TaskRunnerImpl*>(params.task_runner)->runner(); + DCHECK(task_runner->BelongsToCurrentThread()); + g_thread_task_runner_handle.reset( + new base::ThreadTaskRunnerHandle(task_runner)); + } + + // TODO(cleichner): Implement MediaSyncType in MediaPipelineDeviceAlsa + return new MediaPipelineBackendAlsa(params); +} + +double CastMediaShlib::GetMediaClockRate() { + base::ScopedFD alsa_device( + TEMP_FAILURE_RETRY(open(kPepperoniAlsaDevName, O_RDONLY))); + DCHECK(alsa_device.is_valid()) << "Failed to open ALSA device"; + double ppm; + int ret = ioctl(alsa_device.get(), SNDRV_BERLIN_GET_CLOCK_PPM, &ppm); + DCHECK(ret != -1) << "ioctl(SNDRV_BERLIN_GET_CLOCK_PPM) failed: " + << strerror(errno); + return kOneMhzReference + ppm; +} + +double CastMediaShlib::MediaClockRatePrecision() { + return kGranularityHz; +} + +void CastMediaShlib::MediaClockRateRange(double* minimum_rate, + double* maximum_rate) { + DCHECK(minimum_rate); + DCHECK(maximum_rate); + + *minimum_rate = kOneMhzReference - kMaxAdjustmentHz; + *maximum_rate = kOneMhzReference + kMaxAdjustmentHz; +} + +bool CastMediaShlib::SetMediaClockRate(double new_rate) { + new_rate -= kOneMhzReference; + base::ScopedFD alsa_device( + TEMP_FAILURE_RETRY(open(kPepperoniAlsaDevName, O_WRONLY))); + DCHECK(alsa_device.is_valid()) << "Failed to open ALSA device"; + + int ret = ioctl(alsa_device.get(), SNDRV_BERLIN_SET_CLOCK_PPM, &new_rate); + if (ret) { + LOG(ERROR) << "ioctl(SNDRV_BERLIN_SET_CLOCK_PPM) failed: " + << strerror(errno); + return false; + } + return true; +} + +bool CastMediaShlib::SupportsMediaClockRateChange() { + // Simply test the 'Get PPM' IOCTL to determine support. + base::ScopedFD alsa_device( + TEMP_FAILURE_RETRY(open(kPepperoniAlsaDevName, O_RDONLY))); + if (!alsa_device.is_valid()) + return false; + + double ppm; + int ret = ioctl(alsa_device.get(), SNDRV_BERLIN_GET_CLOCK_PPM, &ppm); + if (ret == -1) + return false; + + return true; +} + +} // namespace media +} // namespace chromecast
diff --git a/chromecast/media/cma/backend/alsa/media_codec_support_cast_audio.cc b/chromecast/media/cma/backend/alsa/media_codec_support_cast_audio.cc new file mode 100644 index 0000000..e52bdda --- /dev/null +++ b/chromecast/media/cma/backend/alsa/media_codec_support_cast_audio.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 "base/strings/string_util.h" +#include "chromecast/public/media_codec_support_shlib.h" + +namespace chromecast { +namespace media { + +MediaCodecSupportShlib::CodecSupport MediaCodecSupportShlib::IsSupported( + const std::string& codec) { + // Allow audio codecs. + if (codec == "1" /*PCM*/ || codec == "vorbis" || codec == "opus" || + codec == "mp3" || codec == "mp4a.66" || codec == "mp4a.67" || + codec == "mp4a.68" || codec == "mp4a.69" || codec == "mp4a.6B" || + codec == "mp4a.40.2" || codec == "mp4a.40.02" || codec == "mp4a.40.29" || + codec == "mp4a.40.5" || codec == "mp4a.40.05" || codec == "mp4a.40" || + codec == "flac") + return kSupported; + + // Some video codecs are allowed because mixed audio/video content should + // be able to play. The audio stream will play back and the video frames will + // be dropped by the ALSA-based CMA backend. + // + // TODO(cleichner): Remove this when there is a better solution for detecting + // audio-only device from JS and sending audio-only streams. + if (base::StartsWith(codec, "avc1.", base::CompareCase::SENSITIVE) || + base::StartsWith(codec, "vp8", base::CompareCase::SENSITIVE) || + base::StartsWith(codec, "vp9", base::CompareCase::SENSITIVE)) + return kDefault; + + return kNotSupported; +} + +} // namespace media +} // namespace chromecast
diff --git a/chromecast/media/cma/backend/alsa/media_pipeline_backend_alsa.cc b/chromecast/media/cma/backend/alsa/media_pipeline_backend_alsa.cc new file mode 100644 index 0000000..b528e74 --- /dev/null +++ b/chromecast/media/cma/backend/alsa/media_pipeline_backend_alsa.cc
@@ -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. + +#include "chromecast/media/cma/backend/alsa/media_pipeline_backend_alsa.h" + +#include <limits> + +#include "chromecast/base/task_runner_impl.h" +#include "chromecast/media/cma/backend/alsa/audio_decoder_alsa.h" +#include "chromecast/media/cma/backend/video_decoder_default.h" + +namespace chromecast { +namespace media { + +MediaPipelineBackendAlsa::MediaPipelineBackendAlsa( + const MediaPipelineDeviceParams& params) + : state_(kStateUninitialized), params_(params) { +} + +MediaPipelineBackendAlsa::~MediaPipelineBackendAlsa() { +} + +MediaPipelineBackendAlsa::AudioDecoder* +MediaPipelineBackendAlsa::CreateAudioDecoder() { + DCHECK_EQ(kStateUninitialized, state_); + if (audio_decoder_) + return nullptr; + audio_decoder_.reset(new AudioDecoderAlsa(this)); + return audio_decoder_.get(); +} + +MediaPipelineBackendAlsa::VideoDecoder* +MediaPipelineBackendAlsa::CreateVideoDecoder() { + DCHECK_EQ(kStateUninitialized, state_); + if (video_decoder_) + return nullptr; + video_decoder_.reset(new VideoDecoderDefault()); + return video_decoder_.get(); +} + +bool MediaPipelineBackendAlsa::Initialize() { + DCHECK_EQ(kStateUninitialized, state_); + if (audio_decoder_ && !audio_decoder_->Initialize()) + return false; + state_ = kStateInitialized; + return true; +} + +bool MediaPipelineBackendAlsa::Start(int64_t start_pts) { + DCHECK_EQ(kStateInitialized, state_); + if (audio_decoder_ && !audio_decoder_->Start(start_pts)) + return false; + state_ = kStatePlaying; + return true; +} + +bool MediaPipelineBackendAlsa::Stop() { + DCHECK(state_ == kStatePlaying || state_ == kStatePaused) << "Invalid state " + << state_; + if (audio_decoder_ && !audio_decoder_->Stop()) + return false; + state_ = kStateInitialized; + return true; +} + +bool MediaPipelineBackendAlsa::Pause() { + DCHECK_EQ(kStatePlaying, state_); + if (audio_decoder_ && !audio_decoder_->Pause()) + return false; + state_ = kStatePaused; + return true; +} + +bool MediaPipelineBackendAlsa::Resume() { + DCHECK_EQ(kStatePaused, state_); + if (audio_decoder_ && !audio_decoder_->Resume()) + return false; + state_ = kStatePlaying; + return true; +} + +bool MediaPipelineBackendAlsa::SetPlaybackRate(float rate) { + // TODO(kmackay) Implement this for rates other than 1.0. + if (rate != 1.0) + NOTIMPLEMENTED() << " unhandled rate: " << rate; + return true; +} + +int64_t MediaPipelineBackendAlsa::GetCurrentPts() { + if (audio_decoder_) + return audio_decoder_->current_pts(); + return std::numeric_limits<int64_t>::min(); +} + +bool MediaPipelineBackendAlsa::Primary() const { + return (params_.audio_type != + MediaPipelineDeviceParams::kAudioStreamSoundEffects); +} + +const scoped_refptr<base::SingleThreadTaskRunner>& +MediaPipelineBackendAlsa::GetTaskRunner() const { + return static_cast<TaskRunnerImpl*>(params_.task_runner)->runner(); +} + +} // namespace media +} // namespace chromecast
diff --git a/chromecast/media/cma/backend/alsa/media_pipeline_backend_alsa.h b/chromecast/media/cma/backend/alsa/media_pipeline_backend_alsa.h new file mode 100644 index 0000000..a492d0b --- /dev/null +++ b/chromecast/media/cma/backend/alsa/media_pipeline_backend_alsa.h
@@ -0,0 +1,65 @@ +// 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_CMA_BACKEND_ALSA_MEDIA_PIPELINE_BACKEND_ALSA_H_ +#define CHROMECAST_MEDIA_CMA_BACKEND_ALSA_MEDIA_PIPELINE_BACKEND_ALSA_H_ + +#include "base/macros.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "base/time/time.h" +#include "chromecast/public/media/media_pipeline_backend.h" +#include "chromecast/public/media/media_pipeline_device_params.h" + +namespace base { +class SingleThreadTaskRunner; +} // namespace base + +namespace chromecast { +namespace media { +class AudioDecoderAlsa; +class VideoDecoderDefault; + +class MediaPipelineBackendAlsa : public MediaPipelineBackend { + public: + using RenderingDelay = AudioDecoder::RenderingDelay; + + explicit MediaPipelineBackendAlsa(const MediaPipelineDeviceParams& params); + ~MediaPipelineBackendAlsa() override; + + // MediaPipelineBackend implementation: + AudioDecoder* CreateAudioDecoder() override; + VideoDecoder* CreateVideoDecoder() override; + bool Initialize() override; + bool Start(int64_t start_pts) override; + bool Stop() override; + bool Pause() override; + bool Resume() override; + bool SetPlaybackRate(float rate) override; + int64_t GetCurrentPts() override; + + bool Primary() const; + const scoped_refptr<base::SingleThreadTaskRunner>& GetTaskRunner() const; + + private: + // State variable for DCHECKing caller correctness. + enum State { + kStateUninitialized, + kStateInitialized, + kStatePlaying, + kStatePaused, + }; + State state_; + + const MediaPipelineDeviceParams params_; + scoped_ptr<VideoDecoderDefault> video_decoder_; + scoped_ptr<AudioDecoderAlsa> audio_decoder_; + + DISALLOW_COPY_AND_ASSIGN(MediaPipelineBackendAlsa); +}; + +} // namespace media +} // namespace chromecast + +#endif // CHROMECAST_MEDIA_CMA_BACKEND_ALSA_MEDIA_PIPELINE_BACKEND_ALSA_H_
diff --git a/chromecast/media/cma/backend/alsa/mock_alsa_wrapper.cc b/chromecast/media/cma/backend/alsa/mock_alsa_wrapper.cc new file mode 100644 index 0000000..34d7a023 --- /dev/null +++ b/chromecast/media/cma/backend/alsa/mock_alsa_wrapper.cc
@@ -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. + +#include "chromecast/media/cma/backend/alsa/mock_alsa_wrapper.h" + +#include "base/logging.h" + +// Define dummy structs here to avoid linking in the ALSA lib. +struct _snd_pcm_hw_params {}; +struct _snd_pcm {}; + +namespace chromecast { +namespace media { + +// This class keeps basic state to ensure that ALSA is being used correctly. +// Calls from MockAlsaWrapper are delegated to an instance of this class in +// cases where internal ALSA state change occurs, or where a valid value needs +// to be returned to the caller. +class MockAlsaWrapper::FakeAlsaWrapper : public AlsaWrapper { + public: + FakeAlsaWrapper() + : state_(SND_PCM_STATE_RUNNING), + fake_handle_(nullptr), + fake_pcm_hw_params_(nullptr) {} + + ~FakeAlsaWrapper() override { + delete fake_handle_; + delete fake_pcm_hw_params_; + } + + // AlsaWrapper implementation: + int PcmPause(snd_pcm_t* handle, int pause) override { + CHECK_NE(pause, (state_ == SND_PCM_STATE_PAUSED)); + if (pause) + state_ = SND_PCM_STATE_PAUSED; + else + state_ = SND_PCM_STATE_RUNNING; + return 0; + } + + snd_pcm_state_t PcmState(snd_pcm_t* handle) override { return state_; } + + int PcmOpen(snd_pcm_t** handle, + const char* name, + snd_pcm_stream_t stream, + int mode) override { + fake_handle_ = new snd_pcm_t(); + CHECK(fake_handle_); + *handle = fake_handle_; + return 0; + } + + snd_pcm_sframes_t PcmWritei(snd_pcm_t* handle, + const void* buffer, + snd_pcm_uframes_t size) override { + CHECK_EQ(fake_handle_, handle); + CHECK(buffer); + const uint8_t* ptr = reinterpret_cast<const uint8_t*>(buffer); + int len = size * 2 * 4; + data_.assign(ptr, ptr + len); + return size; + } + + int PcmHwParamsMalloc(snd_pcm_hw_params_t** ptr) override { + fake_pcm_hw_params_ = new snd_pcm_hw_params_t(); + CHECK(fake_pcm_hw_params_); + *ptr = fake_pcm_hw_params_; + return 0; + } + + ssize_t PcmFormatSize(snd_pcm_format_t format, size_t samples) override { + return 4 * samples; + }; + + snd_pcm_state_t state() { return state_; } + std::vector<uint8_t>& data() { return data_; } + + private: + snd_pcm_state_t state_; + snd_pcm_t* fake_handle_; + snd_pcm_hw_params_t* fake_pcm_hw_params_; + std::vector<uint8_t> data_; + + DISALLOW_COPY_AND_ASSIGN(FakeAlsaWrapper); +}; + +using ::testing::_; +using ::testing::Invoke; + +MockAlsaWrapper::MockAlsaWrapper() : fake_(new FakeAlsaWrapper()) { + // Delgate calls that need to be faked. + ON_CALL(*this, PcmOpen(_, _, _, _)) + .WillByDefault(testing::Invoke(fake_.get(), &FakeAlsaWrapper::PcmOpen)); + ON_CALL(*this, PcmWritei(_, _, _)) + .WillByDefault(testing::Invoke(fake_.get(), &FakeAlsaWrapper::PcmWritei)); + ON_CALL(*this, PcmState(_)) + .WillByDefault(testing::Invoke(fake_.get(), &FakeAlsaWrapper::PcmState)); + ON_CALL(*this, PcmFormatSize(_, _)).WillByDefault( + testing::Invoke(fake_.get(), &FakeAlsaWrapper::PcmFormatSize)); + ON_CALL(*this, PcmPause(_, _)) + .WillByDefault(testing::Invoke(fake_.get(), &FakeAlsaWrapper::PcmPause)); + ON_CALL(*this, PcmHwParamsCanPause(_)).WillByDefault(testing::Return(true)); + ON_CALL(*this, PcmHwParamsMalloc(_)).WillByDefault( + testing::Invoke(fake_.get(), &FakeAlsaWrapper::PcmHwParamsMalloc)); +} + +MockAlsaWrapper::~MockAlsaWrapper() { +} + +snd_pcm_state_t MockAlsaWrapper::state() { + return fake_->state(); +} + +const std::vector<uint8_t>& MockAlsaWrapper::data() { + return fake_->data(); +} + +} // namespace media +} // namespace chromecast
diff --git a/chromecast/media/cma/backend/alsa/mock_alsa_wrapper.h b/chromecast/media/cma/backend/alsa/mock_alsa_wrapper.h new file mode 100644 index 0000000..3aed1e02 --- /dev/null +++ b/chromecast/media/cma/backend/alsa/mock_alsa_wrapper.h
@@ -0,0 +1,159 @@ +// 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_CMA_BACKEND_ALSA_MOCK_ALSA_WRAPPER_H_ +#define CHROMECAST_MEDIA_CMA_BACKEND_ALSA_MOCK_ALSA_WRAPPER_H_ + +#include <vector> + +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" +#include "chromecast/media/cma/backend/alsa/alsa_wrapper.h" +#include "media/audio/alsa/alsa_wrapper.h" +#include "testing/gmock/include/gmock/gmock.h" + +namespace chromecast { +namespace media { + +class MockAlsaWrapper : public AlsaWrapper { + public: + MockAlsaWrapper(); + ~MockAlsaWrapper() override; + + MOCK_METHOD3(DeviceNameHint, int(int card, const char* iface, void*** hints)); + MOCK_METHOD2(DeviceNameGetHint, char*(const void* hint, const char* id)); + MOCK_METHOD1(DeviceNameFreeHint, int(void** hints)); + + MOCK_METHOD4(PcmOpen, + int(snd_pcm_t** handle, + const char* name, + snd_pcm_stream_t stream, + int mode)); + MOCK_METHOD1(PcmClose, int(snd_pcm_t* handle)); + MOCK_METHOD1(PcmPrepare, int(snd_pcm_t* handle)); + MOCK_METHOD1(PcmDrain, int(snd_pcm_t* handle)); + MOCK_METHOD1(PcmDrop, int(snd_pcm_t* handle)); + MOCK_METHOD2(PcmDelay, int(snd_pcm_t* handle, snd_pcm_sframes_t* delay)); + MOCK_METHOD3(PcmWritei, + snd_pcm_sframes_t(snd_pcm_t* handle, + const void* buffer, + snd_pcm_uframes_t size)); + MOCK_METHOD3(PcmReadi, + snd_pcm_sframes_t(snd_pcm_t* handle, + void* buffer, + snd_pcm_uframes_t size)); + MOCK_METHOD3(PcmRecover, int(snd_pcm_t* handle, int err, int silent)); + MOCK_METHOD7(PcmSetParams, + int(snd_pcm_t* handle, + snd_pcm_format_t format, + snd_pcm_access_t access, + unsigned int channels, + unsigned int rate, + int soft_resample, + unsigned int latency)); + MOCK_METHOD3(PcmGetParams, + int(snd_pcm_t* handle, + snd_pcm_uframes_t* buffer_size, + snd_pcm_uframes_t* period_size)); + MOCK_METHOD1(PcmName, const char*(snd_pcm_t* handle)); + MOCK_METHOD1(PcmAvailUpdate, snd_pcm_sframes_t(snd_pcm_t* handle)); + MOCK_METHOD1(PcmState, snd_pcm_state_t(snd_pcm_t* handle)); + MOCK_METHOD1(PcmStart, int(snd_pcm_t* handle)); + MOCK_METHOD2(PcmFormatSize, ssize_t(snd_pcm_format_t format, size_t samples)); + MOCK_METHOD1(StrError, const char*(int errnum)); + + MOCK_METHOD2(PcmPause, int(snd_pcm_t* handle, int enable)); + + MOCK_METHOD1(PcmStatusMalloc, int(snd_pcm_status_t** ptr)); + MOCK_METHOD1(PcmStatusFree, void(snd_pcm_status_t* obj)); + MOCK_METHOD2(PcmStatus, int(snd_pcm_t* handle, snd_pcm_status_t* status)); + MOCK_METHOD1(PcmStatusGetDelay, + snd_pcm_sframes_t(const snd_pcm_status_t* obj)); + MOCK_METHOD2(PcmStatusGetHtstamp, + void(const snd_pcm_status_t* obj, snd_htimestamp_t* ptr)); + + MOCK_METHOD1(PcmHwParamsMalloc, int(snd_pcm_hw_params_t** ptr)); + MOCK_METHOD1(PcmHwParamsFree, void(snd_pcm_hw_params_t* obj)); + MOCK_METHOD2(PcmHwParamsCurrent, + int(snd_pcm_t* handle, snd_pcm_hw_params_t* params)); + MOCK_METHOD1(PcmHwParamsCanPause, int(const snd_pcm_hw_params_t* params)); + MOCK_METHOD2(PcmHwParamsAny, + int(snd_pcm_t* handle, snd_pcm_hw_params_t* params)); + MOCK_METHOD3(PcmHwParamsSetRateResample, + int(snd_pcm_t* handle, snd_pcm_hw_params_t* params, bool val)); + MOCK_METHOD3(PcmHwParamsSetAccess, + int(snd_pcm_t* handle, + snd_pcm_hw_params_t* params, + snd_pcm_access_t access)); + MOCK_METHOD3(PcmHwParamsSetFormat, + int(snd_pcm_t* handle, + snd_pcm_hw_params_t* params, + snd_pcm_format_t format)); + MOCK_METHOD3(PcmHwParamsSetChannels, + int(snd_pcm_t* handle, + snd_pcm_hw_params_t* params, + unsigned int num_channels)); + MOCK_METHOD4(PcmHwParamsSetRateNear, + int(snd_pcm_t* handle, + snd_pcm_hw_params_t* params, + unsigned int* rate, + int* dir)); + MOCK_METHOD3(PcmHwParamsSetBufferSizeNear, + int(snd_pcm_t* handle, + snd_pcm_hw_params_t* params, + snd_pcm_uframes_t* val)); + MOCK_METHOD4(PcmHwParamsSetPeriodSizeNear, + int(snd_pcm_t* handle, + snd_pcm_hw_params_t* params, + snd_pcm_uframes_t* val, + int* dir)); + MOCK_METHOD3(PcmHwParamsTestFormat, + int(snd_pcm_t* handle, + snd_pcm_hw_params_t* params, + snd_pcm_format_t format)); + MOCK_METHOD4(PcmHwParamsTestRateNear, + int(snd_pcm_t* handle, + snd_pcm_hw_params_t* params, + unsigned int rate, + int dir)); + MOCK_METHOD2(PcmHwParams, + int(snd_pcm_t* handle, snd_pcm_hw_params_t* params)); + + MOCK_METHOD1(PcmSwParamsMalloc, int(snd_pcm_sw_params_t** params)); + MOCK_METHOD1(PcmSwParamsFree, void(snd_pcm_sw_params_t* params)); + MOCK_METHOD2(PcmSwParamsCurrent, + int(snd_pcm_t* handle, snd_pcm_sw_params_t* params)); + MOCK_METHOD3(PcmSwParamsSetStartThreshold, + int(snd_pcm_t* handle, + snd_pcm_sw_params_t* params, + snd_pcm_uframes_t val)); + MOCK_METHOD3(PcmSwParamsSetAvailMin, + int(snd_pcm_t* handle, + snd_pcm_sw_params_t* params, + snd_pcm_uframes_t val)); + MOCK_METHOD3(PcmSwParamsSetTstampMode, + int(snd_pcm_t* handle, + snd_pcm_sw_params_t* obj, + snd_pcm_tstamp_t val)); + MOCK_METHOD3(PcmSwParamsSetTstampType, + int(snd_pcm_t* handle, snd_pcm_sw_params_t* obj, int val)); + MOCK_METHOD2(PcmSwParams, int(snd_pcm_t* handle, snd_pcm_sw_params_t* obj)); + + // Getters for test control. + snd_pcm_state_t state(); + const std::vector<uint8_t>& data(); + + private: + class FakeAlsaWrapper; + + // Certain calls will be delegated to this class. + scoped_ptr<FakeAlsaWrapper> fake_; + + DISALLOW_COPY_AND_ASSIGN(MockAlsaWrapper); +}; + +} // namespace media +} // namespace chromecast + +#endif // CHROMECAST_MEDIA_CMA_BACKEND_ALSA_MOCK_ALSA_WRAPPER_H_
diff --git a/chromecast/media/cma/backend/alsa/stream_mixer_alsa.cc b/chromecast/media/cma/backend/alsa/stream_mixer_alsa.cc new file mode 100644 index 0000000..7bdf91cf --- /dev/null +++ b/chromecast/media/cma/backend/alsa/stream_mixer_alsa.cc
@@ -0,0 +1,752 @@ +// 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/cma/backend/alsa/stream_mixer_alsa.h" + +#include <algorithm> +#include <cmath> +#include <limits> +#include <utility> + +#include "base/bind_helpers.h" +#include "base/command_line.h" +#include "base/lazy_instance.h" +#include "base/memory/weak_ptr.h" +#include "base/single_thread_task_runner.h" +#include "base/strings/string_number_conversions.h" +#include "base/thread_task_runner_handle.h" +#include "chromecast/base/chromecast_switches.h" +#include "chromecast/media/cma/backend/alsa/alsa_wrapper.h" +#include "chromecast/media/cma/backend/alsa/stream_mixer_alsa_input_impl.h" +#include "media/base/audio_bus.h" +#include "media/base/media_switches.h" +#include "media/base/vector_math.h" + +#define RETURN_REPORT_ERROR(snd_func, ...) \ + do { \ + int err = alsa_->snd_func(__VA_ARGS__); \ + if (err < 0) { \ + LOG(ERROR) << #snd_func " error: " << alsa_->StrError(err); \ + SignalError(); \ + return; \ + } \ + } while (0) + +#define RETURN_ERROR_CODE(snd_func, ...) \ + do { \ + int err = alsa_->snd_func(__VA_ARGS__); \ + if (err < 0) { \ + LOG(ERROR) << #snd_func " error: " << alsa_->StrError(err); \ + return err; \ + } \ + } while (0) + +#define CHECK_PCM_INITIALIZED() \ + if (!pcm_ || !pcm_hw_params_) { \ + LOG(WARNING) << __FUNCTION__ << "() called after failed initialization"; \ + return; \ + } + +#define RUN_ON_MIXER_THREAD(callback, ...) \ + if (!mixer_task_runner_->BelongsToCurrentThread()) { \ + POST_TASK_TO_MIXER_THREAD(callback, ##__VA_ARGS__); \ + return; \ + } + +#define POST_TASK_TO_MIXER_THREAD(task, ...) \ + mixer_task_runner_->PostTask( \ + FROM_HERE, base::Bind(task, base::Unretained(this), ##__VA_ARGS__)); + +namespace chromecast { +namespace media { + +namespace { + +const char kOutputDeviceDefaultName[] = "default"; +const int kNumOutputChannels = 2; + +const int kDefaultOutputBufferSizeFrames = 4096; +const bool kPcmRecoverIsSilent = false; +// The number of frames of silence to write (to prevent underrun) when no inputs +// are present. +const int kPreventUnderrunChunkSize = 512; +const int kDefaultCheckCloseTimeoutMs = 2000; + +// A list of supported sample rates. +// TODO(jyw): move this up into chromecast/public for 1) documentation and +// 2) to help when implementing IsSampleRateSupported() +// clang-format off +const int kSupportedSampleRates[] = + { 8000, 11025, 12000, + 16000, 22050, 24000, + 32000, 44100, 48000, + 64000, 88200, 96000}; +// clang-format on + +// Arbitrary sample rate in Hz to mix all audio to when a new primary input has +// a sample rate that is not directly supported, and a better fallback sample +// rate cannot be determined. 48000 is the highest supported non-hi-res sample +// rate. 96000 is the highest supported hi-res sample rate. +const unsigned int kFallbackSampleRate = 48000; +const unsigned int kFallbackSampleRateHiRes = 96000; + +// The snd_pcm_(hw|sw)_params_set_*_near families of functions will report what +// direction they adjusted the requested parameter in, but since we read the +// output param and then log the information, this module doesn't need to get +// the direction explicitly. +static int* kAlsaDirDontCare = nullptr; + +// These sample formats will be tried in order. 32 bit samples is ideal, but +// some devices do not support 32 bit samples. +const snd_pcm_format_t kPreferredSampleFormats[] = {SND_PCM_FORMAT_S32, + SND_PCM_FORMAT_S16}; + +int64_t TimespecToMicroseconds(struct timespec time) { + return static_cast<int64_t>(time.tv_sec) * + base::Time::kMicrosecondsPerSecond + + time.tv_nsec / 1000; +} + +bool GetSwitchValueAsNonNegativeInt(const std::string& switch_name, + int default_value, + int* value) { + DCHECK(value); + DCHECK_GE(default_value, 0) << "--" << switch_name + << " must have a non-negative default value"; + *value = default_value; + if (!base::CommandLine::InitializedForCurrentProcess()) { + LOG(WARNING) << "No CommandLine for current process."; + return false; + } + const base::CommandLine* command_line = + base::CommandLine::ForCurrentProcess(); + if (!command_line->HasSwitch(switch_name)) + return false; + + int arg_value; + if (!base::StringToInt(command_line->GetSwitchValueASCII(switch_name), + &arg_value)) { + LOG(DFATAL) << "--" << switch_name << " only accepts integers as arguments"; + return false; + } + if (arg_value < 0) { + LOG(DFATAL) << "--" << switch_name << " must have a non-negative value"; + return false; + } + *value = arg_value; + return true; +} + +class StreamMixerAlsaInstance : public StreamMixerAlsa { + public: + StreamMixerAlsaInstance() {} + ~StreamMixerAlsaInstance() override {} + + private: + DISALLOW_COPY_AND_ASSIGN(StreamMixerAlsaInstance); +}; + +base::LazyInstance<StreamMixerAlsaInstance> g_mixer_instance = + LAZY_INSTANCE_INITIALIZER; + +} // namespace + +// static +bool StreamMixerAlsa::single_threaded_for_test_ = false; + +// static +StreamMixerAlsa* StreamMixerAlsa::Get() { + return g_mixer_instance.Pointer(); +} + +// static +void StreamMixerAlsa::MakeSingleThreadedForTest() { + single_threaded_for_test_ = true; + StreamMixerAlsa::Get()->ResetTaskRunnerForTest(); +} + +StreamMixerAlsa::StreamMixerAlsa() + : mixer_thread_(new base::Thread("ALSA CMA mixer thread")), + mixer_task_runner_(nullptr), + requested_output_samples_per_second_(0), + output_samples_per_second_(0), + pcm_(nullptr), + pcm_hw_params_(nullptr), + pcm_status_(nullptr), + pcm_format_(SND_PCM_FORMAT_UNKNOWN), + alsa_buffer_size_(0), + alsa_period_explicitly_set(false), + alsa_period_size_(0), + alsa_start_threshold_(0), + alsa_avail_min_(0), + state_(kStateUninitialized), + retry_write_frames_timer_(new base::Timer(false, false)), + check_close_timeout_(kDefaultCheckCloseTimeoutMs), + check_close_timer_(new base::Timer(false, false)) { + if (single_threaded_for_test_) { + mixer_task_runner_ = base::ThreadTaskRunnerHandle::Get(); + } else { + // TODO(kmackay) Start thread with higher priority? + mixer_thread_->Start(); + mixer_task_runner_ = mixer_thread_->task_runner(); + } + + alsa_device_name_ = kOutputDeviceDefaultName; + if (base::CommandLine::InitializedForCurrentProcess() && + base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kAlsaOutputDevice)) { + alsa_device_name_ = + base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( + switches::kAlsaOutputDevice); + } + + DefineAlsaParameters(); +} + +void StreamMixerAlsa::ResetTaskRunnerForTest() { + mixer_task_runner_ = base::ThreadTaskRunnerHandle::Get(); +} + +void StreamMixerAlsa::DefineAlsaParameters() { + // Get the ALSA output configuration from the command line. + int buffer_size; + GetSwitchValueAsNonNegativeInt(switches::kAlsaOutputBufferSize, + kDefaultOutputBufferSizeFrames, &buffer_size); + alsa_buffer_size_ = buffer_size; + + int period_size; + if (GetSwitchValueAsNonNegativeInt(switches::kAlsaOutputPeriodSize, + alsa_buffer_size_ / 16, &period_size)) { + if (period_size >= buffer_size) { + LOG(DFATAL) << "ALSA period size must be smaller than the buffer size"; + period_size = buffer_size / 2; + } else { + alsa_period_explicitly_set = true; + } + } + alsa_period_size_ = period_size; + + int start_threshold; + GetSwitchValueAsNonNegativeInt(switches::kAlsaOutputStartThreshold, + (buffer_size / period_size) * period_size, + &start_threshold); + if (start_threshold > buffer_size) { + LOG(DFATAL) << "ALSA start threshold must be no larger than " + << "the buffer size"; + start_threshold = (buffer_size / period_size) * period_size; + } + alsa_start_threshold_ = start_threshold; + + // By default, allow the transfer when at least period_size samples can be + // processed. + int avail_min; + GetSwitchValueAsNonNegativeInt(switches::kAlsaOutputAvailMin, period_size, + &avail_min); + if (avail_min > buffer_size) { + LOG(DFATAL) << "ALSA avail min must be no larger than the buffer size"; + avail_min = alsa_period_size_; + } + alsa_avail_min_ = avail_min; + + GetSwitchValueAsNonNegativeInt(switches::kAlsaCheckCloseTimeout, + kDefaultCheckCloseTimeoutMs, + &check_close_timeout_); +} + +int StreamMixerAlsa::SetAlsaPlaybackParams() { + int err = 0; + // Set hardware parameters. + DCHECK(!pcm_hw_params_); + RETURN_ERROR_CODE(PcmHwParamsMalloc, &pcm_hw_params_); + RETURN_ERROR_CODE(PcmHwParamsAny, pcm_, pcm_hw_params_); + RETURN_ERROR_CODE(PcmHwParamsSetAccess, pcm_, pcm_hw_params_, + SND_PCM_ACCESS_RW_INTERLEAVED); + if (pcm_format_ == SND_PCM_FORMAT_UNKNOWN) { + for (const auto& pcm_format : kPreferredSampleFormats) { + err = alsa_->PcmHwParamsTestFormat(pcm_, pcm_hw_params_, pcm_format); + if (err < 0) { + LOG(WARNING) << "PcmHwParamsTestFormat: " << alsa_->StrError(err); + } else { + pcm_format_ = pcm_format; + break; + } + } + if (pcm_format_ == SND_PCM_FORMAT_UNKNOWN) { + LOG(ERROR) << "Could not find a valid PCM format. Running " + << "/bin/alsa_api_test may be instructive."; + return err; + } + } + + RETURN_ERROR_CODE(PcmHwParamsSetFormat, pcm_, pcm_hw_params_, pcm_format_); + RETURN_ERROR_CODE(PcmHwParamsSetChannels, pcm_, pcm_hw_params_, + kNumOutputChannels); + + // Set output rate, allow resampling with a warning if the device doesn't + // support the rate natively. + RETURN_ERROR_CODE(PcmHwParamsSetRateResample, + pcm_, + pcm_hw_params_, + false /* Don't allow resampling. */); + unsigned int requested_rate = + static_cast<unsigned int>(requested_output_samples_per_second_); + unsigned int unsigned_output_samples_per_second = requested_rate; + + // Try the requested sample rate. If the ALSA driver doesn't know how to deal + // with it, try the nearest supported sample rate instead. Lastly, try some + // common sample rates as a fallback. Note that PcmHwParamsSetRateNear + // doesn't always choose a rate that's actually near the given input sample + // rate when the input sample rate is not supported. + const int* kSupportedSampleRatesEnd = + kSupportedSampleRates + arraysize(kSupportedSampleRates); + auto nearest_sample_rate = + std::min_element(kSupportedSampleRates, kSupportedSampleRatesEnd, + [this](int r1, int r2) -> bool { + return abs(requested_output_samples_per_second_ - r1) < + abs(requested_output_samples_per_second_ - r2); + }); + const unsigned int preferred_sample_rates[] = { + requested_rate, + static_cast<unsigned int>(*nearest_sample_rate), + kFallbackSampleRateHiRes, + kFallbackSampleRate}; + for (const auto& sample_rate : preferred_sample_rates) { + err = alsa_->PcmHwParamsTestRate(pcm_, pcm_hw_params_, sample_rate, + 0 /* try exact rate */); + if (err == 0) { + unsigned_output_samples_per_second = sample_rate; + break; + } + } + LOG_IF(ERROR, err != 0) << "Even the fallback sample rate isn't supported! " + << "Have you tried /bin/alsa_api_test on-device?"; + RETURN_ERROR_CODE(PcmHwParamsSetRateNear, + pcm_, + pcm_hw_params_, + &unsigned_output_samples_per_second, + kAlsaDirDontCare); + if (requested_rate != unsigned_output_samples_per_second) { + LOG(ERROR) << "Requested sample rate (" << requested_rate + << " Hz) does not match the actual sample rate (" + << unsigned_output_samples_per_second + << " Hz). This may lead to lower audio quality."; + } + output_samples_per_second_ = + static_cast<int>(unsigned_output_samples_per_second); + + snd_pcm_uframes_t requested_buffer_size = alsa_buffer_size_; + RETURN_ERROR_CODE(PcmHwParamsSetBufferSizeNear, pcm_, pcm_hw_params_, + &alsa_buffer_size_); + if (requested_buffer_size != alsa_buffer_size_) { + LOG(ERROR) << "Requested buffer size (" << requested_buffer_size + << " frames) does not match the actual buffer size (" + << alsa_buffer_size_ + << " frames). This may lead to an increase in " + "either audio latency or audio underruns."; + + // Always try to use the value for period_size that was passed in on the + // command line, if any. + if (!alsa_period_explicitly_set) { + alsa_period_size_ = alsa_buffer_size_ / 16; + } else if (alsa_period_size_ >= alsa_buffer_size_) { + snd_pcm_uframes_t new_period_size = alsa_buffer_size_ / 2; + LOG(DFATAL) << "Configured period size (" << alsa_period_size_ + << ") is >= actual buffer size (" << alsa_buffer_size_ + << "); reducing to " << new_period_size; + alsa_period_size_ = new_period_size; + } + // Scale the start threshold and avail_min based on the new buffer size. + float original_buffer_size = static_cast<float>(requested_buffer_size); + float avail_min_ratio = original_buffer_size / alsa_avail_min_; + alsa_avail_min_ = alsa_buffer_size_ / avail_min_ratio; + float start_threshold_ratio = original_buffer_size / alsa_start_threshold_; + alsa_start_threshold_ = alsa_buffer_size_ / start_threshold_ratio; + } + + snd_pcm_uframes_t requested_period_size = alsa_period_size_; + RETURN_ERROR_CODE(PcmHwParamsSetPeriodSizeNear, pcm_, pcm_hw_params_, + &alsa_period_size_, kAlsaDirDontCare); + if (requested_period_size != alsa_period_size_) { + LOG(ERROR) << "Requested period size (" << requested_period_size + << " frames) does not match the actual period size (" + << alsa_period_size_ + << " frames). This may lead to an increase in " + "CPU usage or an increase in audio latency."; + } + RETURN_ERROR_CODE(PcmHwParams, pcm_, pcm_hw_params_); + + // Set software parameters. + snd_pcm_sw_params_t* swparams; + RETURN_ERROR_CODE(PcmSwParamsMalloc, &swparams); + RETURN_ERROR_CODE(PcmSwParamsCurrent, pcm_, swparams); + RETURN_ERROR_CODE(PcmSwParamsSetStartThreshold, pcm_, swparams, + alsa_start_threshold_); + if (alsa_start_threshold_ > alsa_buffer_size_) { + LOG(ERROR) << "Requested start threshold (" << alsa_start_threshold_ + << " frames) is larger than the buffer size (" + << alsa_buffer_size_ + << " frames). Audio playback will not start."; + } + RETURN_ERROR_CODE(PcmSwParamsSetAvailMin, pcm_, swparams, alsa_avail_min_); + RETURN_ERROR_CODE(PcmSwParamsSetTstampMode, pcm_, swparams, + SND_PCM_TSTAMP_ENABLE); + RETURN_ERROR_CODE(PcmSwParamsSetTstampType, pcm_, swparams, + kAlsaTstampTypeMonotonicRaw); + err = alsa_->PcmSwParams(pcm_, swparams); + alsa_->PcmSwParamsFree(swparams); + return err; +} + +StreamMixerAlsa::~StreamMixerAlsa() { + FinalizeOnMixerThread(); + mixer_thread_->Stop(); + mixer_task_runner_ = nullptr; +} + +void StreamMixerAlsa::FinalizeOnMixerThread() { + RUN_ON_MIXER_THREAD(&StreamMixerAlsa::FinalizeOnMixerThread); + retry_write_frames_timer_.reset(); + check_close_timer_.reset(); + + Stop(); + ClosePcm(); + + inputs_.clear(); + ignored_inputs_.clear(); +} + +void StreamMixerAlsa::Start() { + DCHECK(mixer_task_runner_->BelongsToCurrentThread()); + if (!pcm_) { + RETURN_REPORT_ERROR( + PcmOpen, &pcm_, alsa_device_name_.c_str(), SND_PCM_STREAM_PLAYBACK, 0); + LOG(INFO) << "snd_pcm_open: handle=" << pcm_; + } + + // Some OEM-developed Cast for Audio devices don't accurately report their + // support for different output formats, so this tries 32-bit output and then + // 16-bit output if that fails. + // + // TODO(cleichner): Replace this with more specific device introspection. + // b/24747205 + int err = SetAlsaPlaybackParams(); + if (err < 0) { + LOG(ERROR) << "32-bit playback is not supported on this device, falling " + "back to 16-bit playback. This can degrade audio quality."; + pcm_format_ = SND_PCM_FORMAT_S16; + // Free pcm_hw_params_, which is re-allocated in SetAlsaPlaybackParams(). + // See b/25572466. + alsa_->PcmHwParamsFree(pcm_hw_params_); + pcm_hw_params_ = nullptr; + int err = SetAlsaPlaybackParams(); + if (err < 0) { + LOG(ERROR) << "Error setting ALSA playback parameters: " + << alsa_->StrError(err); + SignalError(); + return; + } + } + RETURN_REPORT_ERROR(PcmPrepare, pcm_); + RETURN_REPORT_ERROR(PcmStatusMalloc, &pcm_status_); + + struct timespec now = {0, 0}; + clock_gettime(CLOCK_MONOTONIC_RAW, &now); + rendering_delay_.timestamp_microseconds = TimespecToMicroseconds(now); + rendering_delay_.delay_microseconds = 0; + + state_ = kStateNormalPlayback; +} + +void StreamMixerAlsa::Stop() { + alsa_->PcmStatusFree(pcm_status_); + pcm_status_ = nullptr; + alsa_->PcmHwParamsFree(pcm_hw_params_); + pcm_hw_params_ = nullptr; + state_ = kStateUninitialized; + + if (!pcm_) + return; + + // If |pcm_| is RUNNING, drain all pending data. + if (alsa_->PcmState(pcm_) == SND_PCM_STATE_RUNNING) { + int err = alsa_->PcmDrain(pcm_); + if (err < 0) + LOG(ERROR) << "snd_pcm_drain error: " << alsa_->StrError(err); + } else { + int err = alsa_->PcmDrop(pcm_); + if (err < 0) + LOG(ERROR) << "snd_pcm_drop error: " << alsa_->StrError(err); + } +} + +void StreamMixerAlsa::ClosePcm() { + if (!pcm_) + return; + LOG(INFO) << "snd_pcm_close: handle=" << pcm_; + int err = alsa_->PcmClose(pcm_); + if (err < 0) { + LOG(ERROR) << "snd_pcm_close error, leaking handle: " + << alsa_->StrError(err); + } + pcm_ = nullptr; +} + +void StreamMixerAlsa::SignalError() { + state_ = kStateError; + for (InputQueue* input : inputs_) + input->SignalError(); +} + +void StreamMixerAlsa::SetAlsaWrapperForTest( + scoped_ptr<AlsaWrapper> alsa_wrapper) { + if (alsa_) { + Stop(); + ClosePcm(); + } + alsa_ = std::move(alsa_wrapper); +} + +void StreamMixerAlsa::WriteFramesForTest() { + RUN_ON_MIXER_THREAD(&StreamMixerAlsa::WriteFramesForTest); + WriteFrames(); +} + +void StreamMixerAlsa::ClearInputsForTest() { + RUN_ON_MIXER_THREAD(&StreamMixerAlsa::ClearInputsForTest); + inputs_.clear(); +} + +void StreamMixerAlsa::AddInput(scoped_ptr<InputQueue> input) { + RUN_ON_MIXER_THREAD(&StreamMixerAlsa::AddInput, + base::Passed(std::move(input))); + if (!alsa_) + alsa_.reset(new AlsaWrapper()); + + DCHECK(input); + // If the new input is a primary one, we may need to change the output + // sample rate to match its input sample rate. + if (input->primary()) + CheckChangeOutputRate(input->input_samples_per_second()); + + InputQueue* input_ptr = input.get(); + inputs_.push_back(std::move(input)); + check_close_timer_->Stop(); + if (state_ == kStateUninitialized) { + requested_output_samples_per_second_ = + input_ptr->input_samples_per_second(); + Start(); + input_ptr->Initialize(rendering_delay_); + } else if (state_ == kStateNormalPlayback) { + input_ptr->Initialize(rendering_delay_); + } else { + input_ptr->SignalError(); + } +} + +void StreamMixerAlsa::CheckChangeOutputRate(int input_samples_per_second) { + DCHECK(mixer_task_runner_->BelongsToCurrentThread()); + if (!pcm_ || + input_samples_per_second == requested_output_samples_per_second_ || + input_samples_per_second == output_samples_per_second_) + return; + for (InputQueue* input : inputs_) { + if (input->primary() && !input->IsDeleting()) + return; + } + + // Move all current inputs to the ignored list + for (InputQueue* input : inputs_) { + LOG(INFO) << "Mixer input " << input + << " now being ignored due to output sample rate change from " + << output_samples_per_second_ << " to " + << input_samples_per_second; + ignored_inputs_.push_back(input); + input->SignalError(); + } + inputs_.weak_clear(); + + requested_output_samples_per_second_ = input_samples_per_second; + // Reset the ALSA params so that the new output sample rate takes effect. + Stop(); + Start(); +} + +void StreamMixerAlsa::RemoveInput(InputQueue* input) { + RUN_ON_MIXER_THREAD(&StreamMixerAlsa::RemoveInput, input); + DCHECK(input); + DCHECK(!input->IsDeleting()); + input->PrepareToDelete( + base::Bind(&StreamMixerAlsa::DeleteInputQueue, base::Unretained(this))); +} + +void StreamMixerAlsa::DeleteInputQueue(InputQueue* input) { + // Always post a task, in case an input calls this while we are iterating + // through the |inputs_| list. + POST_TASK_TO_MIXER_THREAD(&StreamMixerAlsa::DeleteInputQueueInternal, input); +} + +void StreamMixerAlsa::DeleteInputQueueInternal(InputQueue* input) { + DCHECK(input); + DCHECK(mixer_task_runner_->BelongsToCurrentThread()); + auto it = std::find(inputs_.begin(), inputs_.end(), input); + if (it == inputs_.end()) { + it = std::find(ignored_inputs_.begin(), ignored_inputs_.end(), input); + DCHECK(it != ignored_inputs_.end()); + ignored_inputs_.erase(it); + } else { + inputs_.erase(it); + } + + if (inputs_.empty()) { + check_close_timer_->Start( + FROM_HERE, + base::TimeDelta::FromMilliseconds(check_close_timeout_), + base::Bind(&StreamMixerAlsa::CheckClose, base::Unretained(this))); + } +} + +void StreamMixerAlsa::CheckClose() { + DCHECK(mixer_task_runner_->BelongsToCurrentThread()); + DCHECK(inputs_.empty()); + retry_write_frames_timer_->Stop(); + Stop(); + ClosePcm(); +} + +void StreamMixerAlsa::OnFramesQueued() { + if (retry_write_frames_timer_->IsRunning()) + return; + retry_write_frames_timer_->Start( + FROM_HERE, + base::TimeDelta(), + base::Bind(&StreamMixerAlsa::WriteFrames, base::Unretained(this))); +} + +void StreamMixerAlsa::WriteFrames() { + retry_write_frames_timer_->Stop(); + if (TryWriteFrames()) { + retry_write_frames_timer_->Start( + FROM_HERE, + base::TimeDelta(), + base::Bind(&StreamMixerAlsa::WriteFrames, base::Unretained(this))); + } +} + +bool StreamMixerAlsa::TryWriteFrames() { + DCHECK(mixer_task_runner_->BelongsToCurrentThread()); + if (state_ != kStateNormalPlayback) + return false; + int chunk_size = std::numeric_limits<int>::max(); + std::vector<InputQueue*> active_inputs; + for (InputQueue* input : inputs_) { + int read_size = input->MaxReadSize(); + if (read_size > 0) { + active_inputs.push_back(input); + chunk_size = std::min(chunk_size, read_size); + } else if (input->primary()) { + // A primary input cannot provide any data, so wait until later. + return false; + } + } + + if (active_inputs.empty()) { + // No inputs have any data to provide. + if (!inputs_.empty()) + return false; // If there are some inputs, don't fill with silence. + + // If we have no inputs, fill with silence to avoid underrun. + chunk_size = kPreventUnderrunChunkSize; + if (!mixed_ || mixed_->frames() < chunk_size) + mixed_ = ::media::AudioBus::Create(kNumOutputChannels, chunk_size); + mixed_->Zero(); + WriteMixedPcm(*mixed_, chunk_size); + return true; + } + + // If |mixed_| has not been allocated, or it is too small, allocate a buffer. + if (!mixed_ || mixed_->frames() < chunk_size) + mixed_ = ::media::AudioBus::Create(kNumOutputChannels, chunk_size); + // If |temp_| has not been allocated, or is too small, allocate a buffer. + if (!temp_ || temp_->frames() < chunk_size) + temp_ = ::media::AudioBus::Create(kNumOutputChannels, chunk_size); + + mixed_->ZeroFramesPartial(0, chunk_size); + + // Loop through active inputs, polling them for data, and mixing them. + for (InputQueue* input : active_inputs) { + input->GetResampledData(temp_.get(), chunk_size); + for (int c = 0; c < kNumOutputChannels; ++c) { + float volume_scalar = input->volume_multiplier(); + DCHECK(volume_scalar >= 0.0 && volume_scalar <= 1.0) << volume_scalar; + ::media::vector_math::FMAC( + temp_->channel(c), volume_scalar, chunk_size, mixed_->channel(c)); + } + } + + WriteMixedPcm(*mixed_, chunk_size); + return true; +} + +ssize_t StreamMixerAlsa::BytesPerOutputFormatSample() { + return alsa_->PcmFormatSize(pcm_format_, 1); +} + +void StreamMixerAlsa::WriteMixedPcm(const ::media::AudioBus& mixed, + int frames) { + DCHECK(mixer_task_runner_->BelongsToCurrentThread()); + CHECK_PCM_INITIALIZED(); + + if (interleaved_.size() < static_cast<size_t>(frames * kNumOutputChannels) * + BytesPerOutputFormatSample()) { + interleaved_.resize(frames * kNumOutputChannels * + BytesPerOutputFormatSample()); + } + mixed.ToInterleaved(frames, BytesPerOutputFormatSample(), &interleaved_[0]); + + // If the PCM has been drained it will be in SND_PCM_STATE_SETUP and need + // to be prepared in order for playback to work. + if (alsa_->PcmState(pcm_) == SND_PCM_STATE_SETUP) + RETURN_REPORT_ERROR(PcmPrepare, pcm_); + + int frames_left = frames; + uint8_t* data = &interleaved_[0]; + while (frames_left) { + int frames_or_error; + while ((frames_or_error = alsa_->PcmWritei(pcm_, data, frames_left)) < 0) { + RETURN_REPORT_ERROR( + PcmRecover, pcm_, frames_or_error, kPcmRecoverIsSilent); + } + frames_left -= frames_or_error; + DCHECK_GE(frames_left, 0); + data += frames_or_error * kNumOutputChannels * BytesPerOutputFormatSample(); + } + UpdateRenderingDelay(frames); + for (InputQueue* input : inputs_) + input->AfterWriteFrames(rendering_delay_); +} + +void StreamMixerAlsa::UpdateRenderingDelay(int newly_pushed_frames) { + DCHECK(mixer_task_runner_->BelongsToCurrentThread()); + CHECK_PCM_INITIALIZED(); + + if (alsa_->PcmStatus(pcm_, pcm_status_) != 0) { + // Estimate updated delay based on the number of frames we just pushed. + rendering_delay_.delay_microseconds += + static_cast<int64_t>(newly_pushed_frames) * + base::Time::kMicrosecondsPerSecond / output_samples_per_second_; + return; + } + + snd_htimestamp_t status_timestamp; + alsa_->PcmStatusGetHtstamp(pcm_status_, &status_timestamp); + rendering_delay_.timestamp_microseconds = + TimespecToMicroseconds(status_timestamp); + snd_pcm_sframes_t delay_frames = alsa_->PcmStatusGetDelay(pcm_status_); + rendering_delay_.delay_microseconds = static_cast<int64_t>(delay_frames) * + base::Time::kMicrosecondsPerSecond / + output_samples_per_second_; +} + +} // namespace media +} // namespace chromecast
diff --git a/chromecast/media/cma/backend/alsa/stream_mixer_alsa.h b/chromecast/media/cma/backend/alsa/stream_mixer_alsa.h new file mode 100644 index 0000000..0e8ba35d --- /dev/null +++ b/chromecast/media/cma/backend/alsa/stream_mixer_alsa.h
@@ -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. + +#ifndef CHROMECAST_MEDIA_CMA_BACKEND_ALSA_STREAM_MIXER_ALSA_H_ +#define CHROMECAST_MEDIA_CMA_BACKEND_ALSA_STREAM_MIXER_ALSA_H_ + +#include <alsa/asoundlib.h> +#include <stdint.h> + +#include <string> +#include <vector> + +#include "base/macros.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/scoped_vector.h" +#include "base/threading/thread.h" +#include "base/timer/timer.h" +#include "chromecast/media/cma/backend/alsa/media_pipeline_backend_alsa.h" + +namespace media { +class AudioBus; +} // namespace media + +namespace chromecast { +namespace media { +class AlsaWrapper; +class StreamMixerAlsaInputImpl; + +// Mixer implementation. The mixer has one or more input queues; these can be +// added/removed at any time. When an input source pushes frames to an input +// queue, the queue should call StreamMixerAlsa::WriteFrames(); this causes +// the mixer to attempt to mix and write out as many frames as possible. To do +// this, the mixer determines how many frames can be read from all inputs (ie, +// it gets the maximum number of frames that can be read from each input, and +// uses the minimum value). Assuming that all primary inputs have some data +// available, the calculated number of frames are pulled from each input (maybe +// resampled, if the input's incoming sample rate is not equal to the mixer's +// output sample rate) and written to the ALSA stack. +// +// The rendering delay is recalculated after every successful write to the ALSA +// stack. This delay is passed up to the input sources whenever some new data +// is sucessfully added to the input queue (which happens whenever the amount +// of data in the queue drops below the maximum limit, if data is pending). Note +// that the rendering delay is not accurate while the mixer is gathering frames +// to write, so the rendering delay and the queue size for each input must be +// updated atomically after each write is complete (ie, in AfterWriteFrames()). +class StreamMixerAlsa { + public: + // This mixer will pull data from InputQueues which are added to it, mix the + // data from the streams, and write the mixed data as a single stream to ALSA. + // These methods will be called on the mixer thread only. + class InputQueue { + public: + using OnReadyToDeleteCb = base::Callback<void(InputQueue*)>; + + virtual ~InputQueue() {} + + // Returns the sample rate of this stream *before* data is resampled to + // match the sample rate expected by the mixer. The returned value must be + // positive. + virtual int input_samples_per_second() const = 0; + + // This number will be used to scale the stream before it is mixed. The + // result must be in the range (0.0, 1.0]. + virtual float volume_multiplier() const = 0; + + // Returns true if the stream is primary. Primary streams will be given + // precedence for sample rates and will dictate when data is polled. + virtual bool primary() const = 0; + + // Returns true if PrepareToDelete() has been called. + virtual bool IsDeleting() const = 0; + + // Initializes the InputQueue after the mixer is set up. At this point the + // input can correctly determine the mixer's output sample rate. + virtual void Initialize(const MediaPipelineBackendAlsa::RenderingDelay& + mixer_rendering_delay) = 0; + + // Returns the maximum number of frames that can be read from this input + // stream without filling with zeros. This should return 0 if the queue is + // empty and EOS has not been queued. + virtual int MaxReadSize() = 0; + + // Pulls data from the input stream. The input stream should populate |dest| + // with |frames| frames of data to be mixed. The mixer expects data to be + // at a sample rate of |output_samples_per_second()|, so each input stream + // should resample as necessary before returning. |frames| is guaranteed to + // be no larger than the value returned by the most recent call to + // MaxReadSize(), and |dest->frames()| shall be >= |frames|. + virtual void GetResampledData(::media::AudioBus* dest, int frames) = 0; + + // This is called for every InputQueue when the mixer writes data to ALSA + // for any of its input streams. + virtual void AfterWriteFrames( + const MediaPipelineBackendAlsa::RenderingDelay& + mixer_rendering_delay) = 0; + + // This will be called when a fatal error occurs in the mixer. + virtual void SignalError() = 0; + + // Notifies the input that it is being removed by the upper layers, and + // should do whatever is necessary to become ready to delete from the mixer. + // Once the input is ready to be removed, it should call the supplied + // |delete_cb|; this should only happen once per input. + virtual void PrepareToDelete(const OnReadyToDeleteCb& delete_cb) = 0; + }; + + enum State { + kStateUninitialized, + kStateNormalPlayback, + kStateError, + }; + + static StreamMixerAlsa* Get(); + static void MakeSingleThreadedForTest(); + + int output_samples_per_second() const { return output_samples_per_second_; } + bool empty() const { return inputs_.empty(); } + State state() const { return state_; } + + const scoped_refptr<base::SingleThreadTaskRunner>& task_runner() const { + return mixer_task_runner_; + } + + // Adds an input to the mixer. The input will live at least until + // RemoveInput(input) is called. Can be called on any thread. + void AddInput(scoped_ptr<InputQueue> input); + // Instructs the mixer to remove an input. The input should not be referenced + // after this is called. Can be called on any thread. + void RemoveInput(InputQueue* input); + + // Attempts to write some frames of audio to ALSA. Must only be called on the + // mixer thread. + void OnFramesQueued(); + + void SetAlsaWrapperForTest(scoped_ptr<AlsaWrapper> alsa_wrapper); + void WriteFramesForTest(); // Can be called on any thread. + void ClearInputsForTest(); // Removes all inputs. + + protected: + StreamMixerAlsa(); + virtual ~StreamMixerAlsa(); + + private: + void ResetTaskRunnerForTest(); + void FinalizeOnMixerThread(); + + // Reads the buffer size, period size, start threshold, and avail min value + // from the provided command line flags or uses default values if no flags are + // provided. + void DefineAlsaParameters(); + + // Takes the provided ALSA config and sets all ALSA output hardware/software + // playback parameters. It will try to select sane fallback parameters based + // on what the output hardware supports and will log warnings if it does so. + // If any ALSA function returns an unexpected error code, the error code will + // be returned by this function. Otherwise, it will return 0. + int SetAlsaPlaybackParams(); + void Start(); + void Stop(); + void ClosePcm(); + void SignalError(); + void CheckChangeOutputRate(int input_samples_per_second); + + // Deletes an input queue that has finished preparing to delete itself. + // May be called on any thread. + void DeleteInputQueue(InputQueue* input); + // Runs on mixer thread to complete input queue deletion. + void DeleteInputQueueInternal(InputQueue* input); + // Called after a timeout period to close the PCM handle if no inputs are + // present. + void CheckClose(); + + void WriteFrames(); + bool TryWriteFrames(); + void WriteMixedPcm(const ::media::AudioBus& mixed, int frames); + void UpdateRenderingDelay(int newly_pushed_frames); + ssize_t BytesPerOutputFormatSample(); + + static bool single_threaded_for_test_; + + scoped_ptr<AlsaWrapper> alsa_; + scoped_ptr<base::Thread> mixer_thread_; + scoped_refptr<base::SingleThreadTaskRunner> mixer_task_runner_; + + int requested_output_samples_per_second_; + int output_samples_per_second_; + snd_pcm_t* pcm_; + snd_pcm_hw_params_t* pcm_hw_params_; + snd_pcm_status_t* pcm_status_; + snd_pcm_format_t pcm_format_; + + // User-configurable ALSA parameters. This caches the results, so the code + // only has to interact with the command line parameters once. + std::string alsa_device_name_; + snd_pcm_uframes_t alsa_buffer_size_; + bool alsa_period_explicitly_set; + snd_pcm_uframes_t alsa_period_size_; + snd_pcm_uframes_t alsa_start_threshold_; + snd_pcm_uframes_t alsa_avail_min_; + + State state_; + + ScopedVector<InputQueue> inputs_; + ScopedVector<InputQueue> ignored_inputs_; + MediaPipelineBackendAlsa::RenderingDelay rendering_delay_; + // Buffer to write final interleaved data before sending to snd_pcm_writei(). + std::vector<uint8_t> interleaved_; + + // Buffers that hold audio data while it is mixed, before it is passed to the + // ALSA layer. These are kept as members of this class to minimize copies and + // allocations. + scoped_ptr<::media::AudioBus> temp_; + scoped_ptr<::media::AudioBus> mixed_; + + scoped_ptr<base::Timer> retry_write_frames_timer_; + + int check_close_timeout_; + scoped_ptr<base::Timer> check_close_timer_; + + DISALLOW_COPY_AND_ASSIGN(StreamMixerAlsa); +}; + +} // namespace media +} // namespace chromecast + +#endif // CHROMECAST_MEDIA_CMA_BACKEND_ALSA_STREAM_MIXER_ALSA_H_
diff --git a/chromecast/media/cma/backend/alsa/stream_mixer_alsa_input.cc b/chromecast/media/cma/backend/alsa/stream_mixer_alsa_input.cc new file mode 100644 index 0000000..5cd967e --- /dev/null +++ b/chromecast/media/cma/backend/alsa/stream_mixer_alsa_input.cc
@@ -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. + +#include "chromecast/media/cma/backend/alsa/stream_mixer_alsa_input.h" + +#include <utility> + +#include "chromecast/media/cma/backend/alsa/stream_mixer_alsa.h" +#include "chromecast/media/cma/backend/alsa/stream_mixer_alsa_input_impl.h" + +namespace chromecast { +namespace media { + +StreamMixerAlsaInput::StreamMixerAlsaInput(Delegate* delegate, + int samples_per_second, + bool primary) { + scoped_ptr<StreamMixerAlsaInputImpl> impl(new StreamMixerAlsaInputImpl( + delegate, samples_per_second, primary, StreamMixerAlsa::Get())); + impl_ = impl.get(); // Store a pointer to the impl, but the mixer owns it. + StreamMixerAlsa::Get()->AddInput(std::move(impl)); +} + +StreamMixerAlsaInput::~StreamMixerAlsaInput() { + DCHECK(thread_checker_.CalledOnValidThread()); + impl_->PreventDelegateCalls(); + StreamMixerAlsa::Get()->RemoveInput(impl_); +} + +void StreamMixerAlsaInput::WritePcm( + const scoped_refptr<DecoderBufferBase>& data) { + DCHECK(thread_checker_.CalledOnValidThread()); + impl_->WritePcm(data); +} + +void StreamMixerAlsaInput::SetPaused(bool paused) { + DCHECK(thread_checker_.CalledOnValidThread()); + impl_->SetPaused(paused); +} + +void StreamMixerAlsaInput::SetVolumeMultiplier(float multiplier) { + DCHECK(thread_checker_.CalledOnValidThread()); + impl_->SetVolumeMultiplier(multiplier); +} + +} // namespace media +} // namespace chromecast
diff --git a/chromecast/media/cma/backend/alsa/stream_mixer_alsa_input.h b/chromecast/media/cma/backend/alsa/stream_mixer_alsa_input.h new file mode 100644 index 0000000..a656fd02 --- /dev/null +++ b/chromecast/media/cma/backend/alsa/stream_mixer_alsa_input.h
@@ -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. + +#ifndef CHROMECAST_MEDIA_CMA_BACKEND_ALSA_STREAM_MIXER_ALSA_INPUT_H_ +#define CHROMECAST_MEDIA_CMA_BACKEND_ALSA_STREAM_MIXER_ALSA_INPUT_H_ + +#include "base/macros.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "base/threading/thread_checker.h" +#include "chromecast/media/cma/backend/alsa/media_pipeline_backend_alsa.h" + +namespace chromecast { +namespace media { + +class DecoderBufferBase; +class StreamMixerAlsaInputImpl; + +// Input handle to the mixer. All methods (including constructor and destructor) +// must be called on the same thread. +class StreamMixerAlsaInput { + public: + class Delegate { + public: + // Called when the last data passed to WritePcm() has been successfully + // added to the queue. + virtual void OnWritePcmCompletion( + MediaPipelineBackendAlsa::BufferStatus status, + const MediaPipelineBackendAlsa::RenderingDelay& delay) = 0; + // Called when a mixer error occurs. No further data should be written. + virtual void OnMixerError() = 0; + + protected: + virtual ~Delegate() {} + }; + + // Adds a new input to the mixer, creating the mixer if it does not already + // exist. + StreamMixerAlsaInput(Delegate* delegate, + int samples_per_second, + bool primary); + // Removes this input from the mixer, destroying the mixer if there are no + // remaining inputs. + ~StreamMixerAlsaInput(); + + // Writes some PCM data to be mixed. |data| must be in planar float format. + // Once the data has been written, the delegate's OnWritePcmCompletion() + // method will be called on the same thread that the StreamMixerAlsaInput was + // created on. Note that no further calls to WritePcm() should be made until + // OnWritePcmCompletion() has been called. + void WritePcm(const scoped_refptr<DecoderBufferBase>& data); + + // Pauses/unpauses this input. If the mixer has other unpaused inputs, it + // will continue to play sound while this input is paused. + void SetPaused(bool paused); + + // Sets the volume multiplier for this input. If |multiplier| is outside the + // range [0.0, 1.0], it is clamped to that range. + void SetVolumeMultiplier(float multiplier); + + private: + StreamMixerAlsaInputImpl* impl_; + base::ThreadChecker thread_checker_; + + DISALLOW_COPY_AND_ASSIGN(StreamMixerAlsaInput); +}; + +} // namespace media +} // namespace chromecast + +#endif // CHROMECAST_MEDIA_CMA_BACKEND_ALSA_STREAM_MIXER_ALSA_INPUT_H_
diff --git a/chromecast/media/cma/backend/alsa/stream_mixer_alsa_input_impl.cc b/chromecast/media/cma/backend/alsa/stream_mixer_alsa_input_impl.cc new file mode 100644 index 0000000..19f3a523e --- /dev/null +++ b/chromecast/media/cma/backend/alsa/stream_mixer_alsa_input_impl.cc
@@ -0,0 +1,485 @@ +// 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/cma/backend/alsa/stream_mixer_alsa_input_impl.h" + +#include <algorithm> + +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/callback_helpers.h" +#include "base/location.h" +#include "base/logging.h" +#include "base/single_thread_task_runner.h" +#include "base/thread_task_runner_handle.h" +#include "chromecast/media/cma/backend/alsa/stream_mixer_alsa.h" +#include "chromecast/media/cma/base/decoder_buffer_base.h" +#include "media/base/audio_bus.h" +#include "media/base/multi_channel_resampler.h" + +#define RUN_ON_MIXER_THREAD(callback, ...) \ + if (!mixer_task_runner_->BelongsToCurrentThread()) { \ + POST_TASK_TO_MIXER_THREAD(&StreamMixerAlsaInputImpl::callback, \ + ##__VA_ARGS__); \ + return; \ + } + +#define POST_TASK_TO_MIXER_THREAD(task, ...) \ + mixer_task_runner_->PostTask( \ + FROM_HERE, base::Bind(task, base::Unretained(this), ##__VA_ARGS__)); + +#define RUN_ON_CALLER_THREAD(callback, ...) \ + if (!caller_task_runner_->BelongsToCurrentThread()) { \ + POST_TASK_TO_CALLER_THREAD(&StreamMixerAlsaInputImpl::callback, \ + ##__VA_ARGS__); \ + return; \ + } + +#define POST_TASK_TO_CALLER_THREAD(task, ...) \ + caller_task_runner_->PostTask(FROM_HERE, \ + base::Bind(task, weak_this_, ##__VA_ARGS__)); + +namespace chromecast { +namespace media { + +namespace { + +const int kNumOutputChannels = 2; +const int64_t kMaxInputQueueUs = 90000; +const int64_t kFadeMs = 15; +// Number of samples to report as readable when paused. When paused, the mixer +// will still pull this many frames each time it tries to write frames, but we +// fill the frames with silence. +const int kPausedReadSamples = 512; +const int kDefaultReadSize = ::media::SincResampler::kDefaultRequestSize; + +} // namespace + +StreamMixerAlsaInputImpl::StreamMixerAlsaInputImpl( + StreamMixerAlsaInput::Delegate* delegate, + int input_samples_per_second, + bool primary, + StreamMixerAlsa* mixer) + : delegate_(delegate), + input_samples_per_second_(input_samples_per_second), + primary_(primary), + mixer_(mixer), + mixer_task_runner_(mixer_->task_runner()), + caller_task_runner_(base::ThreadTaskRunnerHandle::Get()), + state_(kStateUninitialized), + volume_multiplier_(1.0f), + queued_frames_(0), + queued_frames_including_resampler_(0), + current_buffer_offset_(0), + max_queued_frames_(kMaxInputQueueUs * input_samples_per_second / + base::Time::kMicrosecondsPerSecond), + fade_frames_remaining_(0), + fade_out_frames_total_(0), + weak_factory_(this) { + DCHECK(delegate_); + DCHECK(mixer_); + weak_this_ = weak_factory_.GetWeakPtr(); +} + +StreamMixerAlsaInputImpl::~StreamMixerAlsaInputImpl() { + DCHECK(mixer_task_runner_->BelongsToCurrentThread()); +} + +int StreamMixerAlsaInputImpl::input_samples_per_second() const { + return input_samples_per_second_; +} + +float StreamMixerAlsaInputImpl::volume_multiplier() const { + return volume_multiplier_; +} + +bool StreamMixerAlsaInputImpl::primary() const { + return primary_; +} + +bool StreamMixerAlsaInputImpl::IsDeleting() const { + DCHECK(mixer_task_runner_->BelongsToCurrentThread()); + return (state_ == kStateFinalFade || state_ == kStateDeleted); +} + +void StreamMixerAlsaInputImpl::Initialize( + const MediaPipelineBackendAlsa::RenderingDelay& mixer_rendering_delay) { + DCHECK(mixer_task_runner_->BelongsToCurrentThread()); + DCHECK(!IsDeleting()); + if (mixer_->output_samples_per_second() != input_samples_per_second_) { + double resample_ratio = static_cast<double>(input_samples_per_second_) / + mixer_->output_samples_per_second(); + resampler_.reset(new ::media::MultiChannelResampler( + kNumOutputChannels, + resample_ratio, + kDefaultReadSize, + base::Bind(&StreamMixerAlsaInputImpl::ReadCB, base::Unretained(this)))); + resampler_->PrimeWithSilence(); + } + mixer_rendering_delay_ = mixer_rendering_delay; + fade_out_frames_total_ = NormalFadeFrames(); + fade_frames_remaining_ = NormalFadeFrames(); +} + +void StreamMixerAlsaInputImpl::PreventDelegateCalls() { + DCHECK(caller_task_runner_->BelongsToCurrentThread()); + weak_factory_.InvalidateWeakPtrs(); + + base::AutoLock lock(queue_lock_); + pending_data_ = nullptr; +} + +void StreamMixerAlsaInputImpl::PrepareToDelete( + const OnReadyToDeleteCb& delete_cb) { + DCHECK(mixer_task_runner_->BelongsToCurrentThread()); + DCHECK(!delete_cb.is_null()); + DCHECK(!IsDeleting()); + delete_cb_ = delete_cb; + if (state_ != kStateNormalPlayback && state_ != kStateFadingOut && + state_ != kStateGotEos) { + DeleteThis(); + return; + } + + { + base::AutoLock lock(queue_lock_); + if (state_ == kStateGotEos) { + fade_out_frames_total_ = queued_frames_including_resampler_; + fade_frames_remaining_ = queued_frames_including_resampler_; + } else if (state_ == kStateNormalPlayback) { + fade_out_frames_total_ = + std::min(queued_frames_including_resampler_, NormalFadeFrames()); + fade_frames_remaining_ = fade_out_frames_total_; + } + } + + state_ = kStateFinalFade; + if (fade_frames_remaining_ == 0) { + DeleteThis(); + } else { + // Tell the mixer that some more data might be available (since when fading + // out, we can drain the queue completely). + mixer_->OnFramesQueued(); + } +} + +void StreamMixerAlsaInputImpl::DeleteThis() { + DCHECK(mixer_task_runner_->BelongsToCurrentThread()); + state_ = kStateDeleted; + if (!delete_cb_.is_null()) + base::ResetAndReturn(&delete_cb_).Run(this); +} + +void StreamMixerAlsaInputImpl::WritePcm( + const scoped_refptr<DecoderBufferBase>& data) { + MediaPipelineBackendAlsa::RenderingDelay delay; + { + base::AutoLock lock(queue_lock_); + if (queued_frames_ >= max_queued_frames_) { + DCHECK(!pending_data_); + pending_data_ = data; + return; + } + delay = QueueData(data); + } + // Alert the |mixer_| on the mixer thread. + DidQueueData(data->end_of_stream()); + PostPcmCallback(delay); +} + +// Must only be called when queue_lock_ is locked. +MediaPipelineBackendAlsa::RenderingDelay StreamMixerAlsaInputImpl::QueueData( + const scoped_refptr<DecoderBufferBase>& data) { + queue_lock_.AssertAcquired(); + if (!data->end_of_stream()) { + int frames = data->data_size() / (kNumOutputChannels * sizeof(float)); + queue_.push_back(data); + queued_frames_ += frames; + queued_frames_including_resampler_ += frames; + } + + MediaPipelineBackendAlsa::RenderingDelay delay = mixer_rendering_delay_; + delay.delay_microseconds += + static_cast<int64_t>(queued_frames_including_resampler_) * + base::Time::kMicrosecondsPerSecond / input_samples_per_second_; + return delay; +} + +void StreamMixerAlsaInputImpl::PostPcmCallback( + const MediaPipelineBackendAlsa::RenderingDelay& delay) { + RUN_ON_CALLER_THREAD(PostPcmCallback, delay); + delegate_->OnWritePcmCompletion(MediaPipelineBackendAlsa::kBufferSuccess, + delay); +} + +void StreamMixerAlsaInputImpl::DidQueueData(bool end_of_stream) { + RUN_ON_MIXER_THREAD(DidQueueData, end_of_stream); + DCHECK(!IsDeleting()); + if (end_of_stream) { + state_ = kStateGotEos; + } else if (state_ == kStateUninitialized) { + state_ = kStateNormalPlayback; + } + mixer_->OnFramesQueued(); +} + +void StreamMixerAlsaInputImpl::AfterWriteFrames( + const MediaPipelineBackendAlsa::RenderingDelay& mixer_rendering_delay) { + DCHECK(mixer_task_runner_->BelongsToCurrentThread()); + int resampler_queued_frames = (resampler_ ? resampler_->BufferedFrames() : 0); + + bool queued_more_data = false; + MediaPipelineBackendAlsa::RenderingDelay total_delay; + { + base::AutoLock lock(queue_lock_); + mixer_rendering_delay_ = mixer_rendering_delay; + queued_frames_ = 0; + for (const auto& data : queue_) + queued_frames_ += + data->data_size() / (kNumOutputChannels * sizeof(float)); + queued_frames_ -= current_buffer_offset_; + DCHECK_GE(queued_frames_, 0); + queued_frames_including_resampler_ = + queued_frames_ + resampler_queued_frames; + + if (pending_data_ && queued_frames_ < max_queued_frames_) { + scoped_refptr<DecoderBufferBase> data = pending_data_; + pending_data_ = nullptr; + total_delay = QueueData(data); + queued_more_data = true; + if (data->end_of_stream()) + state_ = kStateGotEos; + } + } + + if (queued_more_data) + PostPcmCallback(total_delay); +} + +int StreamMixerAlsaInputImpl::MaxReadSize() { + DCHECK(mixer_task_runner_->BelongsToCurrentThread()); + if (state_ == kStatePaused || state_ == kStateDeleted) + return kPausedReadSamples; + if (state_ == kStateFinalFade) + return fade_frames_remaining_; + + int queued_frames; + { + base::AutoLock lock(queue_lock_); + if (state_ == kStateGotEos) + return std::max(queued_frames_including_resampler_, kDefaultReadSize); + queued_frames = queued_frames_; + } + + int available_frames = 0; + if (resampler_) { + int num_chunks = queued_frames / kDefaultReadSize; + available_frames = resampler_->ChunkSize() * num_chunks; + } else { + available_frames = queued_frames; + } + + if (state_ == kStateFadingOut) + return std::min(available_frames, fade_frames_remaining_); + return std::max(0, available_frames - NormalFadeFrames()); +} + +void StreamMixerAlsaInputImpl::GetResampledData(::media::AudioBus* dest, + int frames) { + DCHECK(mixer_task_runner_->BelongsToCurrentThread()); + DCHECK(dest); + DCHECK_EQ(kNumOutputChannels, dest->channels()); + DCHECK_GE(dest->frames(), frames); + + if (state_ == kStatePaused || state_ == kStateDeleted) { + dest->ZeroFramesPartial(0, frames); + return; + } + + if (resampler_) { + resampler_->Resample(frames, dest); + } else { + FillFrames(0, dest, frames); + } + + if (state_ == kStateFadingOut || state_ == kStateFinalFade) { + FadeOut(dest, frames); + } else if (fade_frames_remaining_) { + FadeIn(dest, frames); + } +} + +// This is the signature expected by the resampler. |output| should be filled +// completely by FillFrames. +void StreamMixerAlsaInputImpl::ReadCB(int frame_delay, + ::media::AudioBus* output) { + DCHECK(mixer_task_runner_->BelongsToCurrentThread()); + DCHECK(output); + FillFrames(frame_delay, output, output->frames()); +} + +void StreamMixerAlsaInputImpl::FillFrames(int frame_delay, + ::media::AudioBus* output, + int frames) { + DCHECK(mixer_task_runner_->BelongsToCurrentThread()); + DCHECK(output); + DCHECK_GE(output->frames(), frames); + int frames_left = frames; + int frames_filled = 0; + while (frames_left) { + scoped_refptr<DecoderBufferBase> buffer; + int buffer_frames; + int frames_to_copy; + int buffer_offset = current_buffer_offset_; + + { + base::AutoLock lock(queue_lock_); + if (!queue_.empty()) { + buffer = queue_.front(); + buffer_frames = + buffer->data_size() / (kNumOutputChannels * sizeof(float)); + frames_to_copy = + std::min(frames_left, buffer_frames - current_buffer_offset_); + // Note that queued_frames_ is not updated until AfterWriteFrames(). + // This is done so that the rendering delay is always correct from the + // perspective of the calling thread. + current_buffer_offset_ += frames_to_copy; + if (current_buffer_offset_ == buffer_frames) { + queue_.pop_front(); + current_buffer_offset_ = 0; + } + } + } + + if (buffer) { + const float* buffer_samples = + reinterpret_cast<const float*>(buffer->data()); + for (int i = 0; i < kNumOutputChannels; ++i) { + const float* buffer_channel = buffer_samples + (buffer_frames * i); + memcpy(output->channel(i) + frames_filled, + buffer_channel + buffer_offset, + frames_to_copy * sizeof(float)); + } + frames_left -= frames_to_copy; + frames_filled += frames_to_copy; + } else { + // No data left in queue; fill remaining frames with zeros. + LOG(WARNING) << "Filling " << frames_left << " frames with 0"; + output->ZeroFramesPartial(frames_filled, frames_left); + frames_filled += frames_left; + frames_left = 0; + break; + } + } + + DCHECK_EQ(0, frames_left); + DCHECK_EQ(frames, frames_filled); +} + +int StreamMixerAlsaInputImpl::NormalFadeFrames() { + DCHECK(mixer_task_runner_->BelongsToCurrentThread()); + int frames = (mixer_->output_samples_per_second() * kFadeMs / + base::Time::kMillisecondsPerSecond) - 1; + return std::max(frames, 0); +} + +void StreamMixerAlsaInputImpl::FadeIn(::media::AudioBus* dest, int frames) { + DCHECK(mixer_task_runner_->BelongsToCurrentThread()); + LOG(INFO) << "Fading in, " << fade_frames_remaining_ << " frames remaining"; + float fade_in_frames = mixer_->output_samples_per_second() * kFadeMs / + base::Time::kMillisecondsPerSecond; + for (int f = 0; f < frames && fade_frames_remaining_; ++f) { + float fade_multiplier = 1.0 - fade_frames_remaining_ / fade_in_frames; + for (int c = 0; c < kNumOutputChannels; ++c) + dest->channel(c)[f] *= fade_multiplier; + --fade_frames_remaining_; + } +} + +void StreamMixerAlsaInputImpl::FadeOut(::media::AudioBus* dest, int frames) { + DCHECK(mixer_task_runner_->BelongsToCurrentThread()); + LOG(INFO) << "Fading out, " << fade_frames_remaining_ << " frames remaining"; + int f = 0; + for (; f < frames && fade_frames_remaining_; ++f) { + float fade_multiplier = + fade_frames_remaining_ / static_cast<float>(fade_out_frames_total_); + for (int c = 0; c < kNumOutputChannels; ++c) + dest->channel(c)[f] *= fade_multiplier; + --fade_frames_remaining_; + } + // Zero remaining frames + for (; f < frames; ++f) { + for (int c = 0; c < kNumOutputChannels; ++c) + dest->channel(c)[f] = 0.0f; + } + + if (fade_frames_remaining_ == 0) { + if (state_ == kStateFinalFade) { + DeleteThis(); + } else { + state_ = kStatePaused; + } + } +} + +void StreamMixerAlsaInputImpl::SignalError() { + DCHECK(mixer_task_runner_->BelongsToCurrentThread()); + if (state_ == kStateFinalFade) { + DeleteThis(); + return; + } + state_ = kStateError; + PostError(); +} + +void StreamMixerAlsaInputImpl::PostError() { + RUN_ON_CALLER_THREAD(PostError); + delegate_->OnMixerError(); +} + +void StreamMixerAlsaInputImpl::SetPaused(bool paused) { + RUN_ON_MIXER_THREAD(SetPaused, paused); + DCHECK(!IsDeleting()); + if (paused) { + if (state_ == kStateUninitialized) { + state_ = kStatePaused; + } else if (state_ == kStateNormalPlayback) { + fade_frames_remaining_ = NormalFadeFrames() - fade_frames_remaining_; + state_ = (fade_frames_remaining_ ? kStateFadingOut : kStatePaused); + } else { + return; + } + LOG(INFO) << "Pausing"; + } else { + if (state_ == kStateFadingOut) { + fade_frames_remaining_ = NormalFadeFrames() - fade_frames_remaining_; + } else if (state_ == kStatePaused) { + fade_frames_remaining_ = NormalFadeFrames(); + } else { + return; + } + LOG(INFO) << "Unpausing"; + state_ = kStateNormalPlayback; + } + DCHECK_GE(fade_frames_remaining_, 0); + + if (state_ == kStateFadingOut) { + // Tell the mixer that some more data might be available (since when fading + // out, we can drain the queue completely). + mixer_->OnFramesQueued(); + } +} + +void StreamMixerAlsaInputImpl::SetVolumeMultiplier(float multiplier) { + RUN_ON_MIXER_THREAD(SetVolumeMultiplier, multiplier); + DCHECK(!IsDeleting()); + if (multiplier > 1.0f) + multiplier = 1.0f; + if (multiplier < 0.0f) + multiplier = 0.0f; + volume_multiplier_ = multiplier; +} + +} // namespace media +} // namespace chromecast
diff --git a/chromecast/media/cma/backend/alsa/stream_mixer_alsa_input_impl.h b/chromecast/media/cma/backend/alsa/stream_mixer_alsa_input_impl.h new file mode 100644 index 0000000..e5a76bc --- /dev/null +++ b/chromecast/media/cma/backend/alsa/stream_mixer_alsa_input_impl.h
@@ -0,0 +1,177 @@ +// 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_CMA_BACKEND_ALSA_STREAM_MIXER_ALSA_INPUT_IMPL_H_ +#define CHROMECAST_MEDIA_CMA_BACKEND_ALSA_STREAM_MIXER_ALSA_INPUT_IMPL_H_ + +#include <deque> + +#include "base/macros.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/weak_ptr.h" +#include "base/synchronization/lock.h" +#include "chromecast/media/cma/backend/alsa/media_pipeline_backend_alsa.h" +#include "chromecast/media/cma/backend/alsa/stream_mixer_alsa.h" +#include "chromecast/media/cma/backend/alsa/stream_mixer_alsa_input.h" + +namespace base { +class SingleThreadTaskRunner; +} // namespace base + +namespace media { +class AudioBus; +class MultiChannelResampler; +} // namespace media + +namespace chromecast { +namespace media { + +// Input queue implementation for StreamMixerAlsa. Each input source pushes +// frames to an instance of StreamMixerAlsaInputImpl; this then signals the +// mixer to pull as much data as possible from all input queues, and mix it and +// write it out to the ALSA stack. The delegate's OnWritePcmCompletion() method +// is called (on the caller thread) whenever data has been successfully added to +// the queue (this may not happen immediately if the queue's maximum size limit +// has been exceeded). +// +// If an input is being resampled, it is conservative about how much data it can +// provide to be written. This is because the resampler buffers some data +// internally, and consumes data from the queue in large chunks. A resampled +// input ignores the data buffered inside the resampler, as well as any data +// that does not fit within a multiple of the resampler chunk size, for the +// purpose of calculating how much data it can provide. Note that this only +// holds true if the input is not in end-of-stream mode. +// +// When an input is paused, it rapidly fades out (to avoid any pops or clicks), +// and then begins feeding silence to the mixer. The "paused" state is +// transparent to the mixer (when paused, this class provides silence when the +// mixer asks for data). On unpause, the sound is rapidly faded in and then +// resumes normal playback. Similarly, the sound is rapidly faded in at the +// start of playback, and faded out when the input is being removed. This +// prevents sound distortions on track skip or seeking. +// +// The rendering delay is recalculated after every successful write to the ALSA +// stack. This delay is passed up to the input sources whenever some new data +// is sucessfully added to the input queue (which happens whenever the amount +// of data in the queue drops below the maximum limit, if data is pending). Note +// that the rendering delay is not accurate while the mixer is gathering frames +// to write, so pending data is not added to an input queue until after a write +// has completed (in AfterWriteFrames()). +// +// This class is constructed on the caller thread, and the StreamMixerAlsaInput +// methods (WritePcm(), SetPaused(), SetVolumeMultiplier(), and +// PreventDelegateCalls()) must be called on the caller thread. These methods +// must not be called after the input is being removed (ie, after +// mixer->RemoveInput() has been called for this input impl). All other methods +// (including the destructor) must be called on the mixer thread. +// +// When an input is removed, the mixer tells the impl that it is about to be +// removed (it is not deleted yet) by calling PrepareToRemove(). The impl then +// fades out any remaining audio data. Once that is done (or if it is not +// possible/necessary) then the impl calls the |delete_cb| to tell the mixer to +// actually delete it. +class StreamMixerAlsaInputImpl : public StreamMixerAlsa::InputQueue { + public: + enum State { + kStateUninitialized, // No data has been queued yet. + kStateNormalPlayback, // Normal playback. + kStateFadingOut, // Fading out to a paused state. + kStatePaused, // Currently paused. + kStateGotEos, // Got the end-of-stream buffer (normal playback). + kStateFinalFade, // Fading out to a deleted state. + kStateDeleted, // Told the mixer to delete this. + kStateError, // A mixer error occurred, this is unusable now. + }; + + StreamMixerAlsaInputImpl(StreamMixerAlsaInput::Delegate* delegate, + int input_samples_per_second, + bool primary, + StreamMixerAlsa* mixer); + + ~StreamMixerAlsaInputImpl() override; + + // Queues some PCM data to be mixed. |data| must be in planar float format. + void WritePcm(const scoped_refptr<DecoderBufferBase>& data); + + // Sets the pause state of this stream. + void SetPaused(bool paused); + + // Sets the volume multiplier for this stream. If |multiplier| < 0, sets the + // volume multiplier to 0. If |multiplier| > 1, sets the volume multiplier + // to 1. + void SetVolumeMultiplier(float multiplier); + + // Prevents any further calls to the delegate (ie, called when the delegate + // is being destroyed). + void PreventDelegateCalls(); + + State state() const { return state_; } + + private: + // StreamMixerAlsa::InputQueue implementation: + int input_samples_per_second() const override; + float volume_multiplier() const override; + bool primary() const override; + bool IsDeleting() const override; + void Initialize(const MediaPipelineBackendAlsa::RenderingDelay& + mixer_rendering_delay) override; + int MaxReadSize() override; + void GetResampledData(::media::AudioBus* dest, int frames) override; + void AfterWriteFrames(const MediaPipelineBackendAlsa::RenderingDelay& + mixer_rendering_delay) override; + void SignalError() override; + void PrepareToDelete(const OnReadyToDeleteCb& delete_cb) override; + + // Tells the mixer to delete |this|. Makes sure not to call |delete_cb_| more + // than once for |this|. + void DeleteThis(); + MediaPipelineBackendAlsa::RenderingDelay QueueData( + const scoped_refptr<DecoderBufferBase>& data); + void PostPcmCallback(const MediaPipelineBackendAlsa::RenderingDelay& delay); + void DidQueueData(bool end_of_stream); + void ReadCB(int frame_delay, ::media::AudioBus* output); + void FillFrames(int frame_delay, ::media::AudioBus* output, int frames); + int NormalFadeFrames(); + void FadeIn(::media::AudioBus* dest, int frames); + void FadeOut(::media::AudioBus* dest, int frames); + void PostError(); + + StreamMixerAlsaInput::Delegate* const delegate_; + const int input_samples_per_second_; + const bool primary_; + StreamMixerAlsa* const mixer_; + const scoped_refptr<base::SingleThreadTaskRunner> mixer_task_runner_; + const scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner_; + + State state_; + float volume_multiplier_; + + base::Lock queue_lock_; // Lock for the following queue-related members. + scoped_refptr<DecoderBufferBase> pending_data_; + std::deque<scoped_refptr<DecoderBufferBase>> queue_; + int queued_frames_; + int queued_frames_including_resampler_; + MediaPipelineBackendAlsa::RenderingDelay mixer_rendering_delay_; + // End of members that queue_lock_ controls access for. + + int current_buffer_offset_; + int max_queued_frames_; + int fade_frames_remaining_; + int fade_out_frames_total_; + + OnReadyToDeleteCb delete_cb_; + + scoped_ptr<::media::MultiChannelResampler> resampler_; + + base::WeakPtr<StreamMixerAlsaInputImpl> weak_this_; + base::WeakPtrFactory<StreamMixerAlsaInputImpl> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(StreamMixerAlsaInputImpl); +}; + +} // namespace media +} // namespace chromecast + +#endif // CHROMECAST_MEDIA_CMA_BACKEND_ALSA_STREAM_MIXER_ALSA_INPUT_IMPL_H_
diff --git a/chromecast/media/cma/backend/alsa/stream_mixer_alsa_unittest.cc b/chromecast/media/cma/backend/alsa/stream_mixer_alsa_unittest.cc new file mode 100644 index 0000000..2b7b35834 --- /dev/null +++ b/chromecast/media/cma/backend/alsa/stream_mixer_alsa_unittest.cc
@@ -0,0 +1,586 @@ +// 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/cma/backend/alsa/stream_mixer_alsa.h" + +#include <algorithm> +#include <cmath> +#include <limits> +#include <utility> + +#include "base/memory/scoped_vector.h" +#include "base/message_loop/message_loop.h" +#include "base/run_loop.h" +#include "base/thread_task_runner_handle.h" +#include "chromecast/media/cma/backend/alsa/mock_alsa_wrapper.h" +#include "media/base/audio_bus.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using testing::_; + +namespace chromecast { +namespace media { + +namespace { + +// Testing constants that are common to multiple test cases. +const int kNumChannels = 2; +const int kBytesPerSample = 4; +const int kTestMaxReadSize = 4096; +const int kTestSamplesPerSecond = 12345; + +// This array holds |NUM_DATA_SETS| sets of arbitrary interleaved float data. +// Each set holds |NUM_SAMPLES| / kNumChannels frames of data. +#define NUM_DATA_SETS 2u +#define NUM_SAMPLES 64u + +float kTestData[NUM_DATA_SETS][NUM_SAMPLES] = { + { + 0.034619, -0.62082, + -0.633705, 0.530298, + 0.89957, 0.864411, + 0.302309, 0.262931, + 0.780742, 0.0109042, + -0.602219, 0.255149, + -0.454606, 0.857073, + 0.798388, 0.167035, + 0.458046, 0.588998, + 0.206043, 0.569494, + 0.147803, 0.170857, + 0.648797, -0.475908, + -0.95678, -0.0743951, + 0.524809, -0.924101, + 0.65518, -0.322856, + -0.721563, 0.573805, + 0.451849, -0.814982, + -0.364712, 0.573464, + 0.537977, -0.381851, + 0.53816, -0.516168, + -0.0700984, 0.481362, + 0.98778, 0.852158, + -0.8815, -0.381422, + -0.230589, 0.466485, + -0.67107, 0.322319, + 0.892472, -0.320276, + -0.424015, 0.789646, + 0.462945, 0.826759, + 0.423481, 0.229418, + -0.354715, -0.961272, + 0.632236, -0.735754, + 0.872045, -0.709881, + }, { + 0.908805, 0.331583, + 0.514689, 0.803509, + -0.459579, 0.106887, + 0.48557, 0.879381, + 0.688156, 0.692105, + -0.158415, -0.851542, + 0.660676, -0.33735, + -0.49228, 0.655911, + -0.014641, 0.66197, + -0.573276, 0.254189, + 0.666018, 0.98153, + -0.967202, -0.525433, + -0.838106, -0.484799, + 0.889906, -0.548501, + -0.889936, -0.432651, + 0.590209, 0.0801954, + -0.953734, -0.994462, + 0.341957, 0.565746, + 0.605983, -0.152254, + -0.232025, -0.54384, + -0.274306, 0.275652, + 0.276137, -0.367112, + -0.000647, 0.68271, + 0.179821, 0.646818, + 0.435898, -0.669994, + 0.624382, -0.752883, + -0.396175, 0.776021, + 0.600866, -0.2293, + 0.306964, -0.252563, + -0.055882, 0.480061, + -0.408798, -0.405238, + 0.61592, -0.16056, + } +}; + +// Return a scoped pointer filled with the data laid out at |index| above. +scoped_ptr<::media::AudioBus> GetTestData(size_t index) { + CHECK_LT(index, NUM_DATA_SETS); + int frames = NUM_SAMPLES / kNumChannels; + auto data = + ::media::AudioBus::WrapMemory(kNumChannels, frames, kTestData[index]); + return data; +} + +class MockInputQueue : public StreamMixerAlsa::InputQueue { + public: + explicit MockInputQueue(int samples_per_second) + : paused_(true), + samples_per_second_(samples_per_second), + max_read_size_(kTestMaxReadSize), + multiplier_(1.0), + primary_(true), + deleting_(false) { + ON_CALL(*this, GetResampledData(_, _)).WillByDefault( + testing::Invoke(this, &MockInputQueue::DoGetResampledData)); + ON_CALL(*this, PrepareToDelete(_)).WillByDefault( + testing::Invoke(this, &MockInputQueue::DoPrepareToDelete)); + } + ~MockInputQueue() override {} + + bool paused() const { return paused_; } + + // StreamMixerAlsa::InputQueue implementation: + int input_samples_per_second() const override { return samples_per_second_; } + float volume_multiplier() const override { return multiplier_; } + bool primary() const override { return primary_; } + bool IsDeleting() const override { return deleting_; } + MOCK_METHOD1(Initialize, + void(const MediaPipelineBackendAlsa::RenderingDelay& + mixer_rendering_delay)); + int MaxReadSize() override { return max_read_size_; } + MOCK_METHOD2(GetResampledData, void(::media::AudioBus* dest, int frames)); + MOCK_METHOD1(AfterWriteFrames, + void(const MediaPipelineBackendAlsa::RenderingDelay& + mixer_rendering_delay)); + MOCK_METHOD0(SignalError, void()); + MOCK_METHOD1(PrepareToDelete, void(const OnReadyToDeleteCb& delete_cb)); + + // Setters and getters for test control. + void SetPaused(bool paused) { paused_ = paused; } + void SetMaxReadSize(int max_read_size) { max_read_size_ = max_read_size; } + void SetData(scoped_ptr<::media::AudioBus> data) { + CHECK(!data_); + data_ = std::move(data); + max_read_size_ = data_->frames(); + } + void SetVolumeMultiplier(float multiplier) { + CHECK(multiplier >= 0.0 && multiplier <= 1.0); + multiplier_ = multiplier; + } + void SetPrimary(bool primary) { primary_ = primary; } + const ::media::AudioBus& data() { + CHECK(data_); + return *data_; + } + float multiplier() const { return multiplier_; } + + private: + void DoGetResampledData(::media::AudioBus* dest, int frames) { + CHECK(dest); + CHECK_GE(dest->frames(), frames); + if (data_) + data_->CopyPartialFramesTo(0, frames, 0, dest); + } + + void DoPrepareToDelete(const OnReadyToDeleteCb& delete_cb) { + deleting_ = true; + delete_cb.Run(this); + } + + bool paused_; + int samples_per_second_; + int max_read_size_; + float multiplier_; + bool primary_; + bool deleting_; + scoped_ptr<::media::AudioBus> data_; + + DISALLOW_COPY_AND_ASSIGN(MockInputQueue); +}; + +// Given |inputs|, returns mixed audio data according to the mixing method used +// by the mixer. +scoped_ptr<::media::AudioBus> GetMixedAudioData( + const std::vector<testing::StrictMock<MockInputQueue>*>& inputs) { + int read_size = std::numeric_limits<int>::max(); + for (const auto input : inputs) { + CHECK(input); + read_size = std::min(input->MaxReadSize(), read_size); + } + + // Verify all inputs are the right size. + for (const auto input : inputs) { + CHECK_EQ(kNumChannels, input->data().channels()); + CHECK_LE(read_size, input->data().frames()); + } + + // Currently, the mixing algorithm is simply to sum the scaled, clipped input + // streams. Go sample-by-sample and mix the data. + auto mixed = ::media::AudioBus::Create(kNumChannels, read_size); + for (int c = 0; c < mixed->channels(); ++c) { + for (int f = 0; f < read_size; ++f) { + float* result = mixed->channel(c) + f; + + // Sum the sample from each input stream, scaling each stream. + *result = 0.0; + for (const auto input : inputs) + *result += *(input->data().channel(c) + f) * input->multiplier(); + + // Clamp the mixed sample between 1.0 and -1.0. + *result = std::min(1.0f, std::max(-1.0f, *result)); + } + } + return mixed; +} + +// Like the method above, but accepts a single input. This returns an AudioBus +// with this input after it is scaled and clipped. +scoped_ptr<::media::AudioBus> GetMixedAudioData( + testing::StrictMock<MockInputQueue>* input) { + return GetMixedAudioData( + std::vector<testing::StrictMock<MockInputQueue>*>(1, input)); +} + +// Asserts that |expected| matches |actual| exactly. +void CompareAudioData(const ::media::AudioBus& expected, + const ::media::AudioBus& actual) { + ASSERT_EQ(expected.channels(), actual.channels()); + ASSERT_EQ(expected.frames(), actual.frames()); + for (int c = 0; c < expected.channels(); ++c) { + const float* expected_data = expected.channel(c); + const float* actual_data = actual.channel(c); + for (int f = 0; f < expected.frames(); ++f) + ASSERT_FLOAT_EQ(*expected_data++, *actual_data++) << c << " " << f; + } +} + +} // namespace + +class StreamMixerAlsaTest : public testing::Test { + protected: + StreamMixerAlsaTest() + : message_loop_(new base::MessageLoop()), + mock_alsa_(new testing::NiceMock<MockAlsaWrapper>()) { + StreamMixerAlsa::MakeSingleThreadedForTest(); + StreamMixerAlsa::Get()->SetAlsaWrapperForTest(make_scoped_ptr(mock_alsa_)); + } + + ~StreamMixerAlsaTest() override { + StreamMixerAlsa::Get()->ClearInputsForTest(); + } + + MockAlsaWrapper* mock_alsa() { return mock_alsa_; } + + private: + const scoped_ptr<base::MessageLoop> message_loop_; + testing::NiceMock<MockAlsaWrapper>* mock_alsa_; + + DISALLOW_COPY_AND_ASSIGN(StreamMixerAlsaTest); +}; + +TEST_F(StreamMixerAlsaTest, AddSingleInput) { + auto input = new testing::StrictMock<MockInputQueue>(kTestSamplesPerSecond); + StreamMixerAlsa* mixer = StreamMixerAlsa::Get(); + + EXPECT_CALL(*input, Initialize(_)).Times(1); + mixer->AddInput(make_scoped_ptr(input)); + EXPECT_EQ(StreamMixerAlsa::kStateNormalPlayback, mixer->state()); +} + +TEST_F(StreamMixerAlsaTest, AddMultipleInputs) { + auto input1 = new testing::StrictMock<MockInputQueue>(kTestSamplesPerSecond); + auto input2 = + new testing::StrictMock<MockInputQueue>(kTestSamplesPerSecond * 2); + StreamMixerAlsa* mixer = StreamMixerAlsa::Get(); + + EXPECT_CALL(*input1, Initialize(_)).Times(1); + EXPECT_CALL(*input2, Initialize(_)).Times(1); + mixer->AddInput(make_scoped_ptr(input1)); + mixer->AddInput(make_scoped_ptr(input2)); + + // The mixer should be ready to play, and should sample to the initial + // sample rate. + EXPECT_EQ(kTestSamplesPerSecond, mixer->output_samples_per_second()); + EXPECT_EQ(StreamMixerAlsa::kStateNormalPlayback, mixer->state()); +} + +TEST_F(StreamMixerAlsaTest, RemoveInput) { + std::vector<testing::StrictMock<MockInputQueue>*> inputs; + const int kNumInputs = 3; + for (int i = 0; i < kNumInputs; ++i) { + inputs.push_back(new testing::StrictMock<MockInputQueue>( + kTestSamplesPerSecond * (i + 1))); + } + + StreamMixerAlsa* mixer = StreamMixerAlsa::Get(); + for (size_t i = 0; i < inputs.size(); ++i) { + EXPECT_CALL(*inputs[i], Initialize(_)).Times(1); + mixer->AddInput(make_scoped_ptr(inputs[i])); + } + + EXPECT_EQ(StreamMixerAlsa::kStateNormalPlayback, mixer->state()); + + for (size_t i = 0; i < inputs.size(); ++i) { + EXPECT_CALL(*inputs[i], PrepareToDelete(_)).Times(1); + mixer->RemoveInput(inputs[i]); + } + + // Need to wait for the removal task (it is always posted). + base::RunLoop().RunUntilIdle(); + + EXPECT_TRUE(mixer->empty()); + EXPECT_EQ(StreamMixerAlsa::kStateNormalPlayback, mixer->state()); +} + +TEST_F(StreamMixerAlsaTest, WriteFrames) { + std::vector<testing::StrictMock<MockInputQueue>*> inputs; + const int kNumInputs = 3; + for (int i = 0; i < kNumInputs; ++i) { + inputs.push_back( + new testing::StrictMock<MockInputQueue>(kTestSamplesPerSecond)); + inputs.back()->SetPaused(false); + } + + StreamMixerAlsa* mixer = StreamMixerAlsa::Get(); + for (size_t i = 0; i < inputs.size(); ++i) { + EXPECT_CALL(*inputs[i], Initialize(_)).Times(1); + mixer->AddInput(make_scoped_ptr(inputs[i])); + } + + ASSERT_EQ(StreamMixerAlsa::kStateNormalPlayback, mixer->state()); + + // The mixer should pull data from all streams, using the smallest + // MaxReadSize provided by any of the channels. + // TODO(slan): Check that the proper number of frames is pulled. + ASSERT_EQ(3u, inputs.size()); + inputs[0]->SetMaxReadSize(1024); + inputs[1]->SetMaxReadSize(512); + inputs[2]->SetMaxReadSize(2048); + for (const auto input : inputs) { + EXPECT_CALL(*input, GetResampledData(_, 512)).Times(1); + EXPECT_CALL(*input, AfterWriteFrames(_)).Times(1); + } + + // TODO(slan): Verify that the data is mixed properly with math. + EXPECT_CALL(*mock_alsa(), PcmWritei(_, _, 512)).Times(1); + mixer->WriteFramesForTest(); + + // Make two of these streams non-primary, and exhaust a non-primary stream. + // All non-empty streams shall be polled for data and the mixer shall write + // to ALSA. + inputs[1]->SetPrimary(false); + inputs[1]->SetMaxReadSize(0); + inputs[2]->SetPrimary(false); + for (const auto input : inputs) { + if (input != inputs[1]) + EXPECT_CALL(*input, GetResampledData(_, 1024)).Times(1); + EXPECT_CALL(*input, AfterWriteFrames(_)).Times(1); + } + // Note that the new smallest stream shall dictate the length of the write. + EXPECT_CALL(*mock_alsa(), PcmWritei(_, _, 1024)).Times(1); + mixer->WriteFramesForTest(); + + // Exhaust a primary stream. No streams shall be polled for data, and no + // data shall be written to ALSA. + inputs[0]->SetMaxReadSize(0); + EXPECT_CALL(*mock_alsa(), PcmWritei(_, _, _)).Times(0); + mixer->WriteFramesForTest(); +} + +TEST_F(StreamMixerAlsaTest, OneStreamMixesProperly) { + auto input = new testing::StrictMock<MockInputQueue>(kTestSamplesPerSecond); + input->SetPaused(false); + + StreamMixerAlsa* mixer = StreamMixerAlsa::Get(); + EXPECT_CALL(*input, Initialize(_)).Times(1); + mixer->AddInput(make_scoped_ptr(input)); + EXPECT_EQ(StreamMixerAlsa::kStateNormalPlayback, mixer->state()); + + // Populate the stream with data. + const int kNumFrames = 32; + input->SetData(GetTestData(0)); + + // Write the stream to ALSA. + EXPECT_CALL(*input, GetResampledData(_, kNumFrames)); + EXPECT_CALL(*input, AfterWriteFrames(_)); + mixer->WriteFramesForTest(); + + // Get the actual stream rendered to ALSA, and compare it against the + // expected stream. The stream should match exactly. + auto actual = ::media::AudioBus::Create(kNumChannels, kNumFrames); + ASSERT_GT(mock_alsa()->data().size(), 0u); + actual->FromInterleaved( + &(mock_alsa()->data()[0]), kNumFrames, kBytesPerSample); + auto expected = GetMixedAudioData(input); + CompareAudioData(*expected, *actual); +} + +TEST_F(StreamMixerAlsaTest, OneStreamIsScaledDownProperly) { + auto input = new testing::StrictMock<MockInputQueue>(kTestSamplesPerSecond); + input->SetPaused(false); + + StreamMixerAlsa* mixer = StreamMixerAlsa::Get(); + EXPECT_CALL(*input, Initialize(_)).Times(1); + mixer->AddInput(make_scoped_ptr(input)); + EXPECT_EQ(StreamMixerAlsa::kStateNormalPlayback, mixer->state()); + + // Populate the stream with data. + const int kNumFrames = 32; + ASSERT_EQ((int)sizeof(kTestData[0]), + kNumChannels * kNumFrames * kBytesPerSample); + auto data = + ::media::AudioBus::WrapMemory(kNumChannels, kNumFrames, kTestData[0]); + input->SetData(std::move(data)); + + // Set a volume multiplier on the stream. + input->SetVolumeMultiplier(0.75); + + // Write the stream to ALSA. + EXPECT_CALL(*input, GetResampledData(_, kNumFrames)); + EXPECT_CALL(*input, AfterWriteFrames(_)); + mixer->WriteFramesForTest(); + + // Check that the retrieved stream is scaled correctly. + auto actual = ::media::AudioBus::Create(kNumChannels, kNumFrames); + actual->FromInterleaved( + &(mock_alsa()->data()[0]), kNumFrames, kBytesPerSample); + auto expected = GetMixedAudioData(input); + CompareAudioData(*expected, *actual); +} + +TEST_F(StreamMixerAlsaTest, TwoUnscaledStreamsMixProperly) { + // Create a group of input streams. + std::vector<testing::StrictMock<MockInputQueue>*> inputs; + const int kNumInputs = 2; + for (int i = 0; i < kNumInputs; ++i) { + inputs.push_back( + new testing::StrictMock<MockInputQueue>(kTestSamplesPerSecond)); + inputs.back()->SetPaused(false); + } + + StreamMixerAlsa* mixer = StreamMixerAlsa::Get(); + for (size_t i = 0; i < inputs.size(); ++i) { + EXPECT_CALL(*inputs[i], Initialize(_)).Times(1); + mixer->AddInput(make_scoped_ptr(inputs[i])); + } + + // Poll the inputs for data. + const int kNumFrames = 32; + for (size_t i = 0; i < inputs.size(); ++i) { + inputs[i]->SetData(GetTestData(i)); + EXPECT_CALL(*inputs[i], GetResampledData(_, kNumFrames)); + EXPECT_CALL(*inputs[i], AfterWriteFrames(_)); + } + + EXPECT_CALL(*mock_alsa(), PcmWritei(_, _, kNumFrames)).Times(1); + mixer->WriteFramesForTest(); + + // Mix the inputs manually. + auto expected = GetMixedAudioData(inputs); + + // Get the actual stream rendered to ALSA, and compare it against the + // expected stream. The stream should match exactly. + auto actual = ::media::AudioBus::Create(kNumChannels, kNumFrames); + actual->FromInterleaved( + &(mock_alsa()->data()[0]), kNumFrames, kBytesPerSample); + CompareAudioData(*expected, *actual); +} + +TEST_F(StreamMixerAlsaTest, TwoUnscaledStreamsMixProperlyWithEdgeCases) { + // Create a group of input streams. + std::vector<testing::StrictMock<MockInputQueue>*> inputs; + const int kNumInputs = 2; + for (int i = 0; i < kNumInputs; ++i) { + inputs.push_back( + new testing::StrictMock<MockInputQueue>(kTestSamplesPerSecond)); + inputs.back()->SetPaused(false); + } + + StreamMixerAlsa* mixer = StreamMixerAlsa::Get(); + for (size_t i = 0; i < inputs.size(); ++i) { + EXPECT_CALL(*inputs[i], Initialize(_)).Times(1); + mixer->AddInput(make_scoped_ptr(inputs[i])); + } + + // Create edge case data for the inputs. By mixing these two short streams, + // every combination of {-1.0, 0.0, 1.0} is tested. Note that this test case + // is intended to be a hand-checkable gut check. + const int kNumFrames = 3; + + float kEdgeData[2][8] = { + { + -1.0, -1.0, + -1.0, 0.0, + 0.0, 1.0, + 0.0, 0.0, + }, { + -1.0, 0.0, + 1.0, 0.0, + 1.0, 1.0, + 0.0, 0.0, + } + }; + + // Hand-calculate the results. Index 0 is clamped to -1.0 from -2.0. Index + // 5 is clamped from 2.0 to 1.0. + float kResult[8] = { + -1.0, -1.0, + 0.0, 0.0, + 1.0, 1.0, + 0.0, 0.0, + }; + + for (size_t i = 0; i < inputs.size(); ++i) { + auto test_data = + ::media::AudioBus::WrapMemory(kNumChannels, kNumFrames, kEdgeData[i]); + inputs[i]->SetData(std::move(test_data)); + EXPECT_CALL(*inputs[i], GetResampledData(_, kNumFrames)); + EXPECT_CALL(*inputs[i], AfterWriteFrames(_)); + } + + EXPECT_CALL(*mock_alsa(), PcmWritei(_, _, kNumFrames)).Times(1); + mixer->WriteFramesForTest(); + + // Use the hand-calculated results above. + auto expected = + ::media::AudioBus::WrapMemory(kNumChannels, kNumFrames, kResult); + + // Get the actual stream rendered to ALSA, and compare it against the + // expected stream. The stream should match exactly. + auto actual = ::media::AudioBus::Create(kNumChannels, kNumFrames); + actual->FromInterleaved( + &(mock_alsa()->data()[0]), kNumFrames, kBytesPerSample); + CompareAudioData(*expected, *actual); +} + +TEST_F(StreamMixerAlsaTest, WriteBuffersOfVaryingLength) { + auto input = new testing::StrictMock<MockInputQueue>(kTestSamplesPerSecond); + input->SetPaused(false); + + StreamMixerAlsa* mixer = StreamMixerAlsa::Get(); + EXPECT_CALL(*input, Initialize(_)).Times(1); + mixer->AddInput(make_scoped_ptr(input)); + EXPECT_EQ(StreamMixerAlsa::kStateNormalPlayback, mixer->state()); + + // The input stream will provide buffers of several different lengths. + input->SetMaxReadSize(7); + EXPECT_CALL(*input, GetResampledData(_, 7)); + EXPECT_CALL(*input, AfterWriteFrames(_)); + EXPECT_CALL(*mock_alsa(), PcmWritei(_, _, 7)).Times(1); + mixer->WriteFramesForTest(); + + input->SetMaxReadSize(100); + EXPECT_CALL(*input, GetResampledData(_, 100)); + EXPECT_CALL(*input, AfterWriteFrames(_)); + EXPECT_CALL(*mock_alsa(), PcmWritei(_, _, 100)).Times(1); + mixer->WriteFramesForTest(); + + input->SetMaxReadSize(32); + EXPECT_CALL(*input, GetResampledData(_, 32)); + EXPECT_CALL(*input, AfterWriteFrames(_)); + EXPECT_CALL(*mock_alsa(), PcmWritei(_, _, 32)).Times(1); + mixer->WriteFramesForTest(); + + input->SetMaxReadSize(1024); + EXPECT_CALL(*input, GetResampledData(_, 1024)); + EXPECT_CALL(*input, AfterWriteFrames(_)); + EXPECT_CALL(*mock_alsa(), PcmWritei(_, _, 1024)).Times(1); + mixer->WriteFramesForTest(); +} + +} // namespace media +} // namespace chromecast
diff --git a/chromecast/media/media.gyp b/chromecast/media/media.gyp index 1f2b5be..b18f916 100644 --- a/chromecast/media/media.gyp +++ b/chromecast/media/media.gyp
@@ -6,6 +6,10 @@ 'variables': { 'chromium_code': 1, 'chromecast_branding%': 'public', + 'use_alsa%': 0, + + # Set true if the ALSA library being used supports raw timestamps + 'use_alsa_monotonic_raw_tstamps%': 0, }, 'target_defaults': { 'include_dirs': [ @@ -337,5 +341,83 @@ 'base/cast_media_default.cc', ], }, - ], # end of targets + { # Alsa implementation of CMA backend. + 'target_name': 'alsa_cma_backend', + 'type': '<(component)', + 'dependencies': [ + 'chromecast_alsa_features', + 'cma_base', + 'cma_decoder', + 'default_cma_backend', + '<(DEPTH)/base/base.gyp:base', + '<(DEPTH)/chromecast/chromecast.gyp:cast_base', + '<(DEPTH)/chromecast/chromecast.gyp:cast_public_api', + '<(DEPTH)/media/media.gyp:media', + ], + 'sources': [ + 'cma/backend/alsa/alsa_wrapper.cc', + 'cma/backend/alsa/alsa_wrapper.h', + 'cma/backend/alsa/audio_decoder_alsa.cc', + 'cma/backend/alsa/audio_decoder_alsa.h', + 'cma/backend/alsa/media_pipeline_backend_alsa.cc', + 'cma/backend/alsa/media_pipeline_backend_alsa.h', + 'cma/backend/alsa/stream_mixer_alsa.cc', + 'cma/backend/alsa/stream_mixer_alsa.h', + 'cma/backend/alsa/stream_mixer_alsa_input.cc', + 'cma/backend/alsa/stream_mixer_alsa_input.h', + 'cma/backend/alsa/stream_mixer_alsa_input_impl.cc', + 'cma/backend/alsa/stream_mixer_alsa_input_impl.h', + ], + }, # end of target 'alsa_cma_backend' + { + # GN target: //chromecast/media/cma/backend/alsa:alsa_features + 'target_name': 'chromecast_alsa_features', + 'includes': [ '../../build/buildflag_header.gypi' ], + 'variables': { + 'buildflag_header_path': 'chromecast/media/cma/backend/alsa/alsa_features.h', + 'buildflag_flags': [ + 'ALSA_MONOTONIC_RAW_TSTAMPS=<(use_alsa_monotonic_raw_tstamps)', + ] + } + }, # end of target 'alsa_features' + { # Alsa implementation of libcast_media_1.0. + 'target_name': 'libcast_media_1.0_audio', + 'type': 'loadable_module', + 'dependencies': [ + 'alsa_cma_backend', + '<(DEPTH)/base/base.gyp:base', + '<(DEPTH)/chromecast/chromecast.gyp:cast_base', + '<(DEPTH)/chromecast/chromecast.gyp:cast_public_api', + '<(DEPTH)/chromecast/media/media.gyp:default_cma_backend', + ], + 'sources': [ + 'cma/backend/alsa/cast_media_shlib.cc', + 'cma/backend/alsa/media_codec_support_cast_audio.cc', + # NOTE: can't depend on media_base because that pulls in libcast_media. + '<(DEPTH)/chromecast/media/base/media_caps.cc', + '<(DEPTH)/chromecast/media/base/media_caps.h', + ], + }, # end of target 'libcast_media_1.0_audio' + ], # end of targets + 'conditions': [ + ['use_alsa==1', { + 'targets': [ + { + 'target_name': 'alsa_cma_backend_unittests', + 'type': '<(gtest_target_type)', + 'dependencies': [ + 'alsa_cma_backend', + '<(DEPTH)/base/base.gyp:run_all_unittests', + '<(DEPTH)/testing/gmock.gyp:gmock', + '<(DEPTH)/testing/gtest.gyp:gtest', + ], + 'sources': [ + 'cma/backend/alsa/mock_alsa_wrapper.cc', + 'cma/backend/alsa/mock_alsa_wrapper.h', + 'cma/backend/alsa/stream_mixer_alsa_unittest.cc', + ], + }, # end of target 'alsa_cma_backend_unittests' + ], # end of targets + }], + ], # end of conditions }
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM index 38a5dad..15034736 100644 --- a/chromeos/CHROMEOS_LKGM +++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@ -7795.0.0 \ No newline at end of file +7804.0.0 \ No newline at end of file
diff --git a/chromeos/binder/command_broker.cc b/chromeos/binder/command_broker.cc index 0a5393f..52158e2 100644 --- a/chromeos/binder/command_broker.cc +++ b/chromeos/binder/command_broker.cc
@@ -8,6 +8,7 @@ #include <stddef.h> #include <stdint.h> +#include "base/bind.h" #include "base/logging.h" #include "chromeos/binder/driver.h" #include "chromeos/binder/transaction_data.h" @@ -38,7 +39,8 @@ } // namespace -CommandBroker::CommandBroker(Driver* driver) : command_stream_(driver, this) {} +CommandBroker::CommandBroker(Driver* driver) + : command_stream_(driver, this), weak_ptr_factory_(this) {} CommandBroker::~CommandBroker() { DCHECK(thread_checker_.CalledOnValidThread()); @@ -73,17 +75,36 @@ << response_type; return false; } - *reply = response_data.Pass(); + *reply = std::move(response_data); } return true; } +void CommandBroker::AddReference(int32_t handle) { + // Increment weak reference count. + command_stream_.AppendOutgoingCommand(BC_INCREFS, &handle, sizeof(handle)); + // Increment strong reference count. + command_stream_.AppendOutgoingCommand(BC_ACQUIRE, &handle, sizeof(handle)); +} + +void CommandBroker::ReleaseReference(int32_t handle) { + // Decrement strong reference count. + command_stream_.AppendOutgoingCommand(BC_RELEASE, &handle, sizeof(handle)); + // Decrement weak reference count. + command_stream_.AppendOutgoingCommand(BC_DECREFS, &handle, sizeof(handle)); +} + +base::Closure CommandBroker::GetReleaseReferenceClosure(int32_t handle) { + return base::Bind(&CommandBroker::ReleaseReference, + weak_ptr_factory_.GetWeakPtr(), handle); +} + void CommandBroker::OnReply(scoped_ptr<TransactionData> data) { DCHECK(thread_checker_.CalledOnValidThread()); DCHECK_EQ(response_type_, RESPONSE_TYPE_NONE); DCHECK(!response_data_); response_type_ = RESPONSE_TYPE_TRANSACTION_REPLY; - response_data_ = data.Pass(); + response_data_ = std::move(data); } void CommandBroker::OnDeadReply() { @@ -124,7 +145,7 @@ } ResponseType response_type = response_type_; response_type_ = RESPONSE_TYPE_NONE; - *data = response_data_.Pass(); + *data = std::move(response_data_); return response_type; }
diff --git a/chromeos/binder/command_broker.h b/chromeos/binder/command_broker.h index 4f3ae2d1..2e754481 100644 --- a/chromeos/binder/command_broker.h +++ b/chromeos/binder/command_broker.h
@@ -9,8 +9,10 @@ #include <utility> +#include "base/callback.h" #include "base/macros.h" #include "base/memory/scoped_ptr.h" +#include "base/memory/weak_ptr.h" #include "base/threading/thread_checker.h" #include "chromeos/binder/command_stream.h" #include "chromeos/chromeos_export.h" @@ -37,6 +39,17 @@ const TransactionData& request, scoped_ptr<TransactionData>* reply); + // Increments the ref-count of a remote object specified by |handle|. + void AddReference(int32_t handle); + + // Decrements the ref-count of a remote object specified by |handle|. + void ReleaseReference(int32_t handle); + + // Returns a closure which decrements the ref-count of a remote object. + // It's safe to run the returned closure even after the destruction of this + // object. + base::Closure GetReleaseReferenceClosure(int32_t handle); + // CommandStream::IncomingCommandHandler override: void OnReply(scoped_ptr<TransactionData> data) override; void OnDeadReply() override; @@ -61,6 +74,8 @@ ResponseType response_type_ = RESPONSE_TYPE_NONE; scoped_ptr<TransactionData> response_data_; + base::WeakPtrFactory<CommandBroker> weak_ptr_factory_; + DISALLOW_COPY_AND_ASSIGN(CommandBroker); };
diff --git a/chromeos/binder/command_stream.cc b/chromeos/binder/command_stream.cc index e80c346a..ad0e8233 100644 --- a/chromeos/binder/command_stream.cc +++ b/chromeos/binder/command_stream.cc
@@ -123,7 +123,7 @@ LOG(ERROR) << "Failed to read transaction data."; return false; } - incoming_command_handler_->OnReply(data.Pass()); + incoming_command_handler_->OnReply(std::move(data)); break; } case BR_ACQUIRE_RESULT:
diff --git a/chromeos/binder/local_object.cc b/chromeos/binder/local_object.cc new file mode 100644 index 0000000..ec9bd37 --- /dev/null +++ b/chromeos/binder/local_object.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 "chromeos/binder/local_object.h" + +#include <utility> + +#include "chromeos/binder/transaction_data.h" + +namespace binder { + +LocalObject::LocalObject(scoped_ptr<TransactionHandler> handler) + : handler_(std::move(handler)) {} + +LocalObject::~LocalObject() {} + +Object::Type LocalObject::GetType() const { + return TYPE_LOCAL; +} + +bool LocalObject::Transact(CommandBroker* command_broker, + const TransactionData& data, + scoped_ptr<TransactionData>* reply) { + *reply = handler_->OnTransact(command_broker, data); + return true; +} + +} // namespace binder
diff --git a/chromeos/binder/local_object.h b/chromeos/binder/local_object.h new file mode 100644 index 0000000..d833f5c --- /dev/null +++ b/chromeos/binder/local_object.h
@@ -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. + +#ifndef CHROMEOS_BINDER_LOCAL_OBJECT_H_ +#define CHROMEOS_BINDER_LOCAL_OBJECT_H_ + +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" +#include "chromeos/binder/object.h" +#include "chromeos/chromeos_export.h" + +namespace binder { + +// Object living in the current process. +class CHROMEOS_EXPORT LocalObject : public Object { + public: + // Inherit this interface to implement transaction. + class TransactionHandler { + public: + virtual ~TransactionHandler() {} + + // Called when LocalObject::Transact() is called. + virtual scoped_ptr<TransactionData> OnTransact( + CommandBroker* command_broker, + const TransactionData& data) = 0; + }; + + explicit LocalObject(scoped_ptr<TransactionHandler> handler); + + // Object override: + Type GetType() const override; + bool Transact(CommandBroker* command_broker, + const TransactionData& data, + scoped_ptr<TransactionData>* reply) override; + + protected: + ~LocalObject() override; + + private: + scoped_ptr<TransactionHandler> handler_; + + DISALLOW_COPY_AND_ASSIGN(LocalObject); +}; + +} // namespace binder + +#endif // CHROMEOS_BINDER_LOCAL_OBJECT_H_
diff --git a/chromeos/binder/object.h b/chromeos/binder/object.h new file mode 100644 index 0000000..21b99f0 --- /dev/null +++ b/chromeos/binder/object.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 CHROMEOS_BINDER_OBJECT_H_ +#define CHROMEOS_BINDER_OBJECT_H_ + +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" + +namespace binder { + +class CommandBroker; +class TransactionData; + +// An object to perform a transaction. +class Object : public base::RefCountedThreadSafe<Object> { + public: + // Type of an object. + enum Type { + TYPE_LOCAL, // This object lives in this process. + TYPE_REMOTE, // This object lives in a remote process. + }; + + // Returns the type of this object. + virtual Type GetType() const = 0; + + // Performs a transaction. + virtual bool Transact(CommandBroker* command_broker, + const TransactionData& data, + scoped_ptr<TransactionData>* reply) = 0; + + protected: + friend class base::RefCountedThreadSafe<Object>; + virtual ~Object() {} +}; + +} // namespace binder + +#endif // CHROMEOS_BINDER_OBJECT_H_
diff --git a/chromeos/binder/remote_object.cc b/chromeos/binder/remote_object.cc new file mode 100644 index 0000000..c00ba3f --- /dev/null +++ b/chromeos/binder/remote_object.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 "chromeos/binder/remote_object.h" + +#include "base/location.h" +#include "base/thread_task_runner_handle.h" +#include "chromeos/binder/command_broker.h" + +namespace binder { + +RemoteObject::RemoteObject(CommandBroker* command_broker, int32_t handle) + : release_closure_(command_broker->GetReleaseReferenceClosure(handle)), + release_task_runner_(base::ThreadTaskRunnerHandle::Get()), + handle_(handle) { + command_broker->AddReference(handle_); +} + +RemoteObject::~RemoteObject() { + if (release_task_runner_->BelongsToCurrentThread()) { + release_closure_.Run(); + } else { + release_task_runner_->PostTask(FROM_HERE, release_closure_); + } +} + +Object::Type RemoteObject::GetType() const { + return TYPE_REMOTE; +} + +bool RemoteObject::Transact(CommandBroker* command_broker, + const TransactionData& data, + scoped_ptr<TransactionData>* reply) { + return command_broker->Transact(handle_, data, reply); +} + +} // namespace binder
diff --git a/chromeos/binder/remote_object.h b/chromeos/binder/remote_object.h new file mode 100644 index 0000000..656ac8d --- /dev/null +++ b/chromeos/binder/remote_object.h
@@ -0,0 +1,49 @@ +// 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 CHROMEOS_BINDER_REMOTE_OBJECT_H_ +#define CHROMEOS_BINDER_REMOTE_OBJECT_H_ + +#include "base/callback.h" +#include "base/macros.h" +#include "base/memory/ref_counted.h" +#include "chromeos/binder/object.h" +#include "chromeos/chromeos_export.h" + +namespace base { +class SingleThreadTaskRunner; +} + +namespace binder { + +class CommandBroker; + +// Object living in a remote process. +class CHROMEOS_EXPORT RemoteObject : public Object { + public: + RemoteObject(CommandBroker* command_broker, int32_t handle); + + // Returns the handle of this object. + int32_t GetHandle() const { return handle_; } + + // Object override: + Type GetType() const override; + bool Transact(CommandBroker* command_broker, + const TransactionData& data, + scoped_ptr<TransactionData>* reply) override; + + protected: + ~RemoteObject() override; + + private: + base::Closure release_closure_; + scoped_refptr<base::SingleThreadTaskRunner> release_task_runner_; + int32_t handle_; + + DISALLOW_COPY_AND_ASSIGN(RemoteObject); +}; + +} // namespace binder + +#endif // CHROMEOS_BINDER_REMOTE_OBJECT_H_
diff --git a/chromeos/binder/transaction_data.h b/chromeos/binder/transaction_data.h index d43fc69..900ca08 100644 --- a/chromeos/binder/transaction_data.h +++ b/chromeos/binder/transaction_data.h
@@ -5,6 +5,8 @@ #ifndef CHROMEOS_BINDER_TRANSACTION_DATA_H_ #define CHROMEOS_BINDER_TRANSACTION_DATA_H_ +#include <sys/types.h> + #include "chromeos/binder/status.h" namespace binder {
diff --git a/chromeos/binder/transaction_data_from_driver.h b/chromeos/binder/transaction_data_from_driver.h index cf7837c..c2a248f 100644 --- a/chromeos/binder/transaction_data_from_driver.h +++ b/chromeos/binder/transaction_data_from_driver.h
@@ -5,10 +5,11 @@ #ifndef CHROMEOS_BINDER_TRANSACTION_DATA_FROM_DRIVER_H_ #define CHROMEOS_BINDER_TRANSACTION_DATA_FROM_DRIVER_H_ -#include <linux/android/binder.h> #include <stddef.h> #include <stdint.h> -#include <unistd.h> +#include <sys/types.h> + +#include <linux/android/binder.h> #include "base/callback.h" #include "base/macros.h"
diff --git a/chromeos/binder/transaction_data_reader.cc b/chromeos/binder/transaction_data_reader.cc index 450591165..ba97826 100644 --- a/chromeos/binder/transaction_data_reader.cc +++ b/chromeos/binder/transaction_data_reader.cc
@@ -7,6 +7,11 @@ #include <stddef.h> #include <stdint.h> +#include <linux/android/binder.h> + +#include "chromeos/binder/local_object.h" +#include "chromeos/binder/object.h" +#include "chromeos/binder/remote_object.h" #include "chromeos/binder/transaction_data.h" namespace binder { @@ -32,6 +37,7 @@ } bool TransactionDataReader::ReadData(void* buf, size_t n) { + DCHECK(buf); return reader_.Read(buf, n) && reader_.Skip(AddPadding(n) - n); } @@ -59,4 +65,20 @@ return ReadData(value, sizeof(*value)); } +scoped_refptr<Object> TransactionDataReader::ReadObject( + CommandBroker* command_broker) { + DCHECK(command_broker); + flat_binder_object obj = {}; + if (!ReadData(&obj, sizeof(obj))) { + return scoped_refptr<Object>(); + } + switch (obj.type) { + case BINDER_TYPE_HANDLE: + return make_scoped_refptr(new RemoteObject(command_broker, obj.handle)); + case BINDER_TYPE_BINDER: + return make_scoped_refptr(reinterpret_cast<LocalObject*>(obj.cookie)); + } + return scoped_refptr<Object>(); +} + } // namespace binder
diff --git a/chromeos/binder/transaction_data_reader.h b/chromeos/binder/transaction_data_reader.h index 26cb916d..6265cb4b 100644 --- a/chromeos/binder/transaction_data_reader.h +++ b/chromeos/binder/transaction_data_reader.h
@@ -9,11 +9,14 @@ #include <stdint.h> #include "base/macros.h" +#include "base/memory/ref_counted.h" #include "chromeos/binder/buffer_reader.h" #include "chromeos/chromeos_export.h" namespace binder { +class CommandBroker; +class Object; class TransactionData; // Reads contents of a TransactionData. @@ -28,25 +31,30 @@ bool HasMoreData() const; // Reads the specified number of bytes with appropriate padding. + // Returns true on success. bool ReadData(void* buf, size_t n); - // Reads an int32_t value. + // Reads an int32_t value. Returns true on success. bool ReadInt32(int32_t* value); - // Reads an uint32_t value. + // Reads an uint32_t value. Returns true on success. bool ReadUint32(uint32_t* value); - // Reads an int64_t value. + // Reads an int64_t value. Returns true on success. bool ReadInt64(int64_t* value); - // Reads an uint64_t value. + // Reads an uint64_t value. Returns true on success. bool ReadUint64(uint64_t* value); - // Reads a float value. + // Reads a float value. Returns true on success. bool ReadFloat(float* value); - // Reads a double value. + // Reads a double value. Returns true on success. bool ReadDouble(double* value); + + // Reads an object. Returns null on failure. + // |command_broker| will be used for object ref-count operations. + scoped_refptr<Object> ReadObject(CommandBroker* command_broker); // TODO(hashimoto): Support more types (i.e. strings, FDs, objects). private:
diff --git a/chromeos/binder/transaction_data_reader_unittest.cc b/chromeos/binder/transaction_data_reader_unittest.cc index 8bed9ea..3dc3e0da 100644 --- a/chromeos/binder/transaction_data_reader_unittest.cc +++ b/chromeos/binder/transaction_data_reader_unittest.cc
@@ -4,9 +4,17 @@ #include <stddef.h> #include <stdint.h> +#include <sys/types.h> + +#include <linux/android/binder.h> #include <vector> +#include "base/message_loop/message_loop.h" +#include "chromeos/binder/command_broker.h" +#include "chromeos/binder/driver.h" +#include "chromeos/binder/local_object.h" +#include "chromeos/binder/remote_object.h" #include "chromeos/binder/transaction_data_reader.h" #include "chromeos/binder/writable_transaction_data.h" #include "testing/gtest/include/gtest/gtest.h" @@ -84,4 +92,40 @@ EXPECT_FALSE(reader.HasMoreData()); } +TEST(TransactionDataReaderTest, ReadObject) { + base::MessageLoopForIO message_loop; + + Driver driver; + ASSERT_TRUE(driver.Initialize()); + CommandBroker command_broker(&driver); + + scoped_refptr<LocalObject> local( + new LocalObject(scoped_ptr<LocalObject::TransactionHandler>())); + + const int32_t kDummyHandle = 42; + scoped_refptr<RemoteObject> remote( + new RemoteObject(&command_broker, kDummyHandle)); + + // Write a local object & a remote object. + WritableTransactionData data; + data.WriteObject(local); + data.WriteObject(remote); + + // Read the local object. + TransactionDataReader reader(data); + scoped_refptr<Object> result = reader.ReadObject(&command_broker); + ASSERT_TRUE(result); + ASSERT_EQ(Object::TYPE_LOCAL, result->GetType()); + EXPECT_EQ(local.get(), static_cast<LocalObject*>(result.get())); + + // Read the remote object. + result = reader.ReadObject(&command_broker); + ASSERT_TRUE(result); + ASSERT_EQ(Object::TYPE_REMOTE, result->GetType()); + EXPECT_EQ(kDummyHandle, + static_cast<RemoteObject*>(result.get())->GetHandle()); + + EXPECT_FALSE(reader.HasMoreData()); +} + } // namespace binder
diff --git a/chromeos/binder/util.cc b/chromeos/binder/util.cc index cd9802d..49736b5 100644 --- a/chromeos/binder/util.cc +++ b/chromeos/binder/util.cc
@@ -4,8 +4,9 @@ #include "chromeos/binder/util.h" +#include <sys/types.h> + #include <linux/android/binder.h> -#include <stdint.h> #include "base/logging.h"
diff --git a/chromeos/binder/util.h b/chromeos/binder/util.h index 461d4e0..d4e4e17 100644 --- a/chromeos/binder/util.h +++ b/chromeos/binder/util.h
@@ -5,6 +5,8 @@ #ifndef CHROMEOS_BINDER_UTIL_H_ #define CHROMEOS_BINDER_UTIL_H_ +#include <stdint.h> + #include "chromeos/chromeos_export.h" namespace binder {
diff --git a/chromeos/binder/writable_transaction_data.cc b/chromeos/binder/writable_transaction_data.cc index 1afbdc0b5..9149125 100644 --- a/chromeos/binder/writable_transaction_data.cc +++ b/chromeos/binder/writable_transaction_data.cc
@@ -4,6 +4,12 @@ #include "chromeos/binder/writable_transaction_data.h" +#include <linux/android/binder.h> + +#include "chromeos/binder/local_object.h" +#include "chromeos/binder/object.h" +#include "chromeos/binder/remote_object.h" + namespace binder { WritableTransactionData::WritableTransactionData() {} @@ -92,4 +98,31 @@ WriteData(&value, sizeof(value)); } +void WritableTransactionData::WriteObject(scoped_refptr<Object> object) { + objects_.push_back(object); // Hold reference. + + flat_binder_object flat = {}; + flat.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS; + + switch (object->GetType()) { + case Object::TYPE_LOCAL: { + auto* local = static_cast<LocalObject*>(object.get()); + flat.type = BINDER_TYPE_BINDER; + flat.cookie = reinterpret_cast<uintptr_t>(local); + // flat.binder is unused, but the driver requires it to be a non-zero + // unique value. + flat.binder = reinterpret_cast<uintptr_t>(local); + break; + } + case Object::TYPE_REMOTE: { + auto* remote = static_cast<RemoteObject*>(object.get()); + flat.type = BINDER_TYPE_HANDLE; + flat.handle = remote->GetHandle(); + break; + } + } + object_offsets_.push_back(data_.size()); + WriteData(&flat, sizeof(flat)); +} + } // namespace binder
diff --git a/chromeos/binder/writable_transaction_data.h b/chromeos/binder/writable_transaction_data.h index 9001ad3..bb889653 100644 --- a/chromeos/binder/writable_transaction_data.h +++ b/chromeos/binder/writable_transaction_data.h
@@ -11,11 +11,14 @@ #include <vector> #include "base/macros.h" +#include "base/memory/ref_counted.h" #include "chromeos/binder/transaction_data.h" #include "chromeos/chromeos_export.h" namespace binder { +class Object; + // Use this class to construct TransactionData (as parameters and replies) to // transact with remote objects. // GetSenderPID() and GetSenderEUID() return 0. @@ -66,6 +69,9 @@ // Appends a double value. void WriteDouble(double value); + + // Appends an object. + void WriteObject(scoped_refptr<Object> object); // TODO(hashimoto): Support more types (i.e. strings, FDs, objects). private: @@ -73,6 +79,7 @@ bool is_one_way_ = false; std::vector<char> data_; std::vector<uintptr_t> object_offsets_; + std::vector<scoped_refptr<Object>> objects_; DISALLOW_COPY_AND_ASSIGN(WritableTransactionData); };
diff --git a/chromeos/binder/writable_transaction_data_unittest.cc b/chromeos/binder/writable_transaction_data_unittest.cc index 07d1d31..d73eb67 100644 --- a/chromeos/binder/writable_transaction_data_unittest.cc +++ b/chromeos/binder/writable_transaction_data_unittest.cc
@@ -4,8 +4,16 @@ #include <stddef.h> #include <stdint.h> +#include <sys/types.h> +#include <linux/android/binder.h> + +#include "base/message_loop/message_loop.h" #include "chromeos/binder/buffer_reader.h" +#include "chromeos/binder/command_broker.h" +#include "chromeos/binder/driver.h" +#include "chromeos/binder/local_object.h" +#include "chromeos/binder/remote_object.h" #include "chromeos/binder/writable_transaction_data.h" #include "testing/gtest/include/gtest/gtest.h" @@ -105,4 +113,43 @@ EXPECT_FALSE(reader.HasMoreData()); } +TEST(BinderWritableTransactionDataTest, WriteObject) { + base::MessageLoopForIO message_loop; + + Driver driver; + ASSERT_TRUE(driver.Initialize()); + CommandBroker command_broker(&driver); + + scoped_refptr<LocalObject> local( + new LocalObject(scoped_ptr<LocalObject::TransactionHandler>())); + + const int32_t kDummyHandle = 42; + scoped_refptr<RemoteObject> remote( + new RemoteObject(&command_broker, kDummyHandle)); + + // Write a local object & a remote object. + WritableTransactionData data; + data.WriteObject(local); + data.WriteObject(remote); + + // Check object offsets. + ASSERT_EQ(2u, data.GetNumObjectOffsets()); + EXPECT_EQ(0u, data.GetObjectOffsets()[0]); + EXPECT_EQ(sizeof(flat_binder_object), data.GetObjectOffsets()[1]); + + // Check the written local object. + BufferReader reader(reinterpret_cast<const char*>(data.GetData()), + data.GetDataSize()); + flat_binder_object result = {}; + EXPECT_TRUE(reader.Read(&result, sizeof(result))); + EXPECT_EQ(BINDER_TYPE_BINDER, result.type); + EXPECT_EQ(reinterpret_cast<uintptr_t>(local.get()), result.cookie); + EXPECT_EQ(reinterpret_cast<uintptr_t>(local.get()), result.binder); + + // Check the written remote object. + EXPECT_TRUE(reader.Read(&result, sizeof(result))); + EXPECT_EQ(BINDER_TYPE_HANDLE, result.type); + EXPECT_EQ(kDummyHandle, result.handle); +} + } // namespace binder
diff --git a/chromeos/chromeos.gyp b/chromeos/chromeos.gyp index 169be47..1388bd76 100644 --- a/chromeos/chromeos.gyp +++ b/chromeos/chromeos.gyp
@@ -396,6 +396,11 @@ 'binder/constants.h', 'binder/driver.cc', 'binder/driver.h', + 'binder/local_object.cc', + 'binder/local_object.h', + 'binder/object.h', + 'binder/remote_object.cc', + 'binder/remote_object.h', 'binder/status.h', 'binder/transaction_data.h', 'binder/transaction_data_from_driver.cc',
diff --git a/components/arc/arc_bridge_bootstrap.cc b/components/arc/arc_bridge_bootstrap.cc index 317bf3a..204bf7c0 100644 --- a/components/arc/arc_bridge_bootstrap.cc +++ b/components/arc/arc_bridge_bootstrap.cc
@@ -30,7 +30,7 @@ namespace { const base::FilePath::CharType kArcBridgeSocketPath[] = - FILE_PATH_LITERAL("/home/chronos/ArcBridge/bridge.sock"); + FILE_PATH_LITERAL("/var/run/chrome/arc_bridge.sock"); void OnChannelCreated(mojo::embedder::ChannelInfo* channel) {} @@ -57,6 +57,11 @@ // STOPPING // StopInstance() -> // STOPPED + // + // When the instance crashes while it was ready, it will be stopped: + // READY -> STOPPING -> STOPPED + // and then restarted: + // STOPPED -> SOCKET_CREATING -> ... -> READY). enum class State { // ARC is not currently running. STOPPED,
diff --git a/components/arc/arc_bridge_service.cc b/components/arc/arc_bridge_service.cc index 3c5f3914..2d10d8a4 100644 --- a/components/arc/arc_bridge_service.cc +++ b/components/arc/arc_bridge_service.cc
@@ -22,7 +22,7 @@ } // namespace ArcBridgeService::ArcBridgeService() - : available_(false), state_(State::STOPPED) { + : available_(false), state_(State::STOPPED), weak_factory_(this) { DCHECK(!g_arc_bridge_service); g_arc_bridge_service = this; } @@ -58,40 +58,149 @@ void ArcBridgeService::OnAppInstanceReady(AppInstancePtr app_ptr) { DCHECK(CalledOnValidThread()); - app_ptr_ = std::move(app_ptr); + temporary_app_ptr_ = std::move(app_ptr); + temporary_app_ptr_.QueryVersion(base::Bind( + &ArcBridgeService::OnAppVersionReady, weak_factory_.GetWeakPtr())); +} + +void ArcBridgeService::OnAppVersionReady(int32_t version) { + DCHECK(CalledOnValidThread()); + app_ptr_ = std::move(temporary_app_ptr_); FOR_EACH_OBSERVER(Observer, observer_list(), OnAppInstanceReady()); + app_ptr_.set_connection_error_handler(base::Bind( + &ArcBridgeService::CloseAppChannel, weak_factory_.GetWeakPtr())); +} + +void ArcBridgeService::CloseAppChannel() { + DCHECK(CalledOnValidThread()); + if (!app_ptr_) + return; + + app_ptr_.reset(); + FOR_EACH_OBSERVER(Observer, observer_list(), OnAppInstanceClosed()); } void ArcBridgeService::OnInputInstanceReady(InputInstancePtr input_ptr) { DCHECK(CalledOnValidThread()); - input_ptr_ = std::move(input_ptr); + temporary_input_ptr_ = std::move(input_ptr); + temporary_input_ptr_.QueryVersion(base::Bind( + &ArcBridgeService::OnInputVersionReady, weak_factory_.GetWeakPtr())); +} + +void ArcBridgeService::OnInputVersionReady(int32_t version) { + DCHECK(CalledOnValidThread()); + input_ptr_ = std::move(temporary_input_ptr_); FOR_EACH_OBSERVER(Observer, observer_list(), OnInputInstanceReady()); + input_ptr_.set_connection_error_handler(base::Bind( + &ArcBridgeService::CloseInputChannel, weak_factory_.GetWeakPtr())); +} + +void ArcBridgeService::CloseInputChannel() { + DCHECK(CalledOnValidThread()); + if (!input_ptr_) + return; + + input_ptr_.reset(); + FOR_EACH_OBSERVER(Observer, observer_list(), OnInputInstanceClosed()); } void ArcBridgeService::OnNotificationsInstanceReady( NotificationsInstancePtr notifications_ptr) { DCHECK(CalledOnValidThread()); - notifications_ptr_ = std::move(notifications_ptr); + temporary_notifications_ptr_ = std::move(notifications_ptr); + temporary_notifications_ptr_.QueryVersion( + base::Bind(&ArcBridgeService::OnNotificationsVersionReady, + weak_factory_.GetWeakPtr())); +} + +void ArcBridgeService::OnNotificationsVersionReady(int32_t version) { + DCHECK(CalledOnValidThread()); + notifications_ptr_ = std::move(temporary_notifications_ptr_); FOR_EACH_OBSERVER(Observer, observer_list(), OnNotificationsInstanceReady()); + notifications_ptr_.set_connection_error_handler( + base::Bind(&ArcBridgeService::CloseNotificationsChannel, + weak_factory_.GetWeakPtr())); +} + +void ArcBridgeService::CloseNotificationsChannel() { + DCHECK(CalledOnValidThread()); + if (!notifications_ptr_) + return; + + notifications_ptr_.reset(); + FOR_EACH_OBSERVER(Observer, observer_list(), OnNotificationsInstanceClosed()); } void ArcBridgeService::OnPowerInstanceReady(PowerInstancePtr power_ptr) { DCHECK(CalledOnValidThread()); - power_ptr_ = std::move(power_ptr); + temporary_power_ptr_ = std::move(power_ptr); + temporary_power_ptr_.QueryVersion(base::Bind( + &ArcBridgeService::OnPowerVersionReady, weak_factory_.GetWeakPtr())); +} + +void ArcBridgeService::OnPowerVersionReady(int32_t version) { + DCHECK(CalledOnValidThread()); + power_ptr_ = std::move(temporary_power_ptr_); FOR_EACH_OBSERVER(Observer, observer_list(), OnPowerInstanceReady()); + power_ptr_.set_connection_error_handler(base::Bind( + &ArcBridgeService::ClosePowerChannel, weak_factory_.GetWeakPtr())); +} + +void ArcBridgeService::ClosePowerChannel() { + DCHECK(CalledOnValidThread()); + if (!power_ptr_) + return; + + power_ptr_.reset(); + FOR_EACH_OBSERVER(Observer, observer_list(), OnPowerInstanceClosed()); } void ArcBridgeService::OnProcessInstanceReady(ProcessInstancePtr process_ptr) { DCHECK(CalledOnValidThread()); - process_ptr_ = std::move(process_ptr); + temporary_process_ptr_ = std::move(process_ptr); + temporary_process_ptr_.QueryVersion(base::Bind( + &ArcBridgeService::OnProcessVersionReady, weak_factory_.GetWeakPtr())); +} + +void ArcBridgeService::OnProcessVersionReady(int32_t version) { + DCHECK(CalledOnValidThread()); + process_ptr_ = std::move(temporary_process_ptr_); FOR_EACH_OBSERVER(Observer, observer_list(), OnProcessInstanceReady()); + process_ptr_.set_connection_error_handler(base::Bind( + &ArcBridgeService::CloseProcessChannel, weak_factory_.GetWeakPtr())); +} + +void ArcBridgeService::CloseProcessChannel() { + DCHECK(CalledOnValidThread()); + if (!process_ptr_) + return; + + process_ptr_.reset(); + FOR_EACH_OBSERVER(Observer, observer_list(), OnProcessInstanceClosed()); } void ArcBridgeService::OnSettingsInstanceReady( SettingsInstancePtr settings_ptr) { DCHECK(CalledOnValidThread()); - settings_ptr_ = std::move(settings_ptr); + temporary_settings_ptr_ = std::move(settings_ptr); + temporary_settings_ptr_.QueryVersion(base::Bind( + &ArcBridgeService::OnSettingsVersionReady, weak_factory_.GetWeakPtr())); +} + +void ArcBridgeService::OnSettingsVersionReady(int32_t version) { + settings_ptr_ = std::move(temporary_settings_ptr_); FOR_EACH_OBSERVER(Observer, observer_list(), OnSettingsInstanceReady()); + settings_ptr_.set_connection_error_handler(base::Bind( + &ArcBridgeService::CloseSettingsChannel, weak_factory_.GetWeakPtr())); +} + +void ArcBridgeService::CloseSettingsChannel() { + DCHECK(CalledOnValidThread()); + if (!settings_ptr_) + return; + + settings_ptr_.reset(); + FOR_EACH_OBSERVER(Observer, observer_list(), OnSettingsInstanceClosed()); } void ArcBridgeService::SetState(State state) { @@ -113,4 +222,15 @@ return thread_checker_.CalledOnValidThread(); } +void ArcBridgeService::CloseAllChannels() { + // Call all the error handlers of all the channels to both close the channel + // and notify any observers that the channel is closed. + CloseAppChannel(); + CloseInputChannel(); + CloseNotificationsChannel(); + ClosePowerChannel(); + CloseProcessChannel(); + CloseSettingsChannel(); +} + } // namespace arc
diff --git a/components/arc/arc_bridge_service.h b/components/arc/arc_bridge_service.h index 6e8c885b..1f54b7e 100644 --- a/components/arc/arc_bridge_service.h +++ b/components/arc/arc_bridge_service.h
@@ -73,23 +73,29 @@ // Called whenever ARC's availability has changed for this system. virtual void OnAvailableChanged(bool available) {} - // Called whenever the ARC app list is ready. + // Called whenever the ARC app interface state changes. virtual void OnAppInstanceReady() {} + virtual void OnAppInstanceClosed() {} - // Called whenever the ARC input is ready. + // Called whenever the ARC input interface state changes. virtual void OnInputInstanceReady() {} + virtual void OnInputInstanceClosed() {} - // Called whenever the ARC notification is ready. + // Called whenever the ARC notification interface state changes. virtual void OnNotificationsInstanceReady() {} + virtual void OnNotificationsInstanceClosed() {} - // Called whenever the ARC power is ready. + // Called whenever the ARC power interface state changes. virtual void OnPowerInstanceReady() {} + virtual void OnPowerInstanceClosed() {} - // Called whenever the ARC process is ready. + // Called whenever the ARC process interface state changes. virtual void OnProcessInstanceReady() {} + virtual void OnProcessInstanceClosed() {} - // Called whenever the ARC settings is ready. + // Called whenever the ARC settings interface state changes. virtual void OnSettingsInstanceReady() {} + virtual void OnSettingsInstanceClosed() {} protected: virtual ~Observer() {} @@ -137,6 +143,13 @@ ProcessInstance* process_instance() { return process_ptr_.get(); } SettingsInstance* settings_instance() { return settings_ptr_.get(); } + int32_t app_version() const { return app_ptr_.version(); } + int32_t input_version() const { return input_ptr_.version(); } + int32_t notifications_version() const { return notifications_ptr_.version(); } + int32_t power_version() const { return power_ptr_.version(); } + int32_t process_version() const { return process_ptr_.version(); } + int32_t settings_version() const { return settings_ptr_.version(); } + // ArcHost: void OnAppInstanceReady(AppInstancePtr app_ptr) override; void OnInputInstanceReady(InputInstancePtr input_ptr) override; @@ -165,11 +178,31 @@ bool CalledOnValidThread(); + // Closes all Mojo channels. + void CloseAllChannels(); + private: friend class ArcBridgeTest; FRIEND_TEST_ALL_PREFIXES(ArcBridgeTest, Basic); FRIEND_TEST_ALL_PREFIXES(ArcBridgeTest, Prerequisites); FRIEND_TEST_ALL_PREFIXES(ArcBridgeTest, ShutdownMidStartup); + FRIEND_TEST_ALL_PREFIXES(ArcBridgeTest, Restart); + + // Called when one of the individual channels is closed. + void CloseAppChannel(); + void CloseInputChannel(); + void CloseNotificationsChannel(); + void ClosePowerChannel(); + void CloseProcessChannel(); + void CloseSettingsChannel(); + + // Callbacks for QueryVersion. + void OnAppVersionReady(int32_t version); + void OnInputVersionReady(int32_t version); + void OnNotificationsVersionReady(int32_t version); + void OnPowerVersionReady(int32_t version); + void OnProcessVersionReady(int32_t version); + void OnSettingsVersionReady(int32_t version); // Mojo interfaces. AppInstancePtr app_ptr_; @@ -179,6 +212,19 @@ ProcessInstancePtr process_ptr_; SettingsInstancePtr settings_ptr_; + // Temporary Mojo interfaces. After a Mojo interface pointer has been + // received from the other endpoint, we still need to asynchronously query + // its version. While that is going on, we should still return nullptr on + // the xxx_instance() functions. + // To keep the xxx_instance() functions being trivial, store the instance + // pointer in a temporary variable to avoid losing its reference. + AppInstancePtr temporary_app_ptr_; + InputInstancePtr temporary_input_ptr_; + NotificationsInstancePtr temporary_notifications_ptr_; + PowerInstancePtr temporary_power_ptr_; + ProcessInstancePtr temporary_process_ptr_; + SettingsInstancePtr temporary_settings_ptr_; + base::ObserverList<Observer> observer_list_; base::ThreadChecker thread_checker_; @@ -189,6 +235,9 @@ // The current state of the bridge. ArcBridgeService::State state_; + // WeakPtrFactory to use callbacks. + base::WeakPtrFactory<ArcBridgeService> weak_factory_; + DISALLOW_COPY_AND_ASSIGN(ArcBridgeService); };
diff --git a/components/arc/arc_bridge_service_impl.cc b/components/arc/arc_bridge_service_impl.cc index 2572579..4bc20c0 100644 --- a/components/arc/arc_bridge_service_impl.cc +++ b/components/arc/arc_bridge_service_impl.cc
@@ -75,6 +75,9 @@ } SetState(State::STOPPING); + instance_ptr_.reset(); + if (binding_.is_bound()) + binding_.Close(); bootstrap_->Stop(); } @@ -95,6 +98,8 @@ } instance_ptr_ = std::move(instance); + instance_ptr_.set_connection_error_handler(base::Bind( + &ArcBridgeServiceImpl::OnChannelClosed, weak_factory_.GetWeakPtr())); ArcBridgeHostPtr host; binding_.Bind(GetProxy(&host)); @@ -106,6 +111,24 @@ void ArcBridgeServiceImpl::OnStopped() { DCHECK(CalledOnValidThread()); SetState(State::STOPPED); + if (reconnect_) { + // There was a previous invocation and it crashed for some reason. Try + // starting the container again. + reconnect_ = false; + PrerequisitesChanged(); + } +} + +void ArcBridgeServiceImpl::OnChannelClosed() { + DCHECK(CalledOnValidThread()); + if (state() == State::STOPPED || state() == State::STOPPING) { + // This will happen when the instance is shut down. Ignore that case. + return; + } + VLOG(1) << "Mojo connection lost"; + CloseAllChannels(); + reconnect_ = true; + StopInstance(); } } // namespace arc
diff --git a/components/arc/arc_bridge_service_impl.h b/components/arc/arc_bridge_service_impl.h index d0de3e3a6..ea90b087 100644 --- a/components/arc/arc_bridge_service_impl.h +++ b/components/arc/arc_bridge_service_impl.h
@@ -37,9 +37,7 @@ private: friend class ArcBridgeTest; - FRIEND_TEST_ALL_PREFIXES(ArcBridgeTest, Basic); - FRIEND_TEST_ALL_PREFIXES(ArcBridgeTest, Prerequisites); - FRIEND_TEST_ALL_PREFIXES(ArcBridgeTest, ShutdownMidStartup); + FRIEND_TEST_ALL_PREFIXES(ArcBridgeTest, Restart); // If all pre-requisites are true (ARC is available, it has been enabled, and // the session has started), and ARC is stopped, start ARC. If ARC is running @@ -56,6 +54,10 @@ // DBus callbacks. void OnArcAvailable(bool available); + // Called when the bridge channel is closed. This typically only happens when + // the ARC instance crashes. This is not called during shutdown. + void OnChannelClosed(); + scoped_ptr<ArcBridgeBootstrap> bootstrap_; // Mojo endpoints. @@ -65,6 +67,10 @@ // If the user's session has started. bool session_started_; + // If the instance had already been started but the connection to it was + // lost. This should make the instance restart. + bool reconnect_ = false; + // WeakPtrFactory to use callbacks. base::WeakPtrFactory<ArcBridgeServiceImpl> weak_factory_;
diff --git a/components/arc/arc_bridge_service_unittest.cc b/components/arc/arc_bridge_service_unittest.cc index f9e6334..74100b7 100644 --- a/components/arc/arc_bridge_service_unittest.cc +++ b/components/arc/arc_bridge_service_unittest.cc
@@ -36,6 +36,7 @@ void Stop() override { DCHECK(delegate_); + instance_->Unbind(); delegate_->OnStopped(); } @@ -73,7 +74,7 @@ ArcBridgeService::State state() const { return state_; } protected: - scoped_ptr<ArcBridgeService> service_; + scoped_ptr<ArcBridgeServiceImpl> service_; scoped_ptr<FakeArcBridgeInstance> instance_; private: @@ -108,45 +109,18 @@ DISALLOW_COPY_AND_ASSIGN(ArcBridgeTest); }; -// Shuts down the instance reports booted. -class ScopedShutdownWhenReady : public ArcBridgeService::Observer { - public: - explicit ScopedShutdownWhenReady(ArcBridgeService* service) - : service_(service) { - service_->AddObserver(this); - } - - ~ScopedShutdownWhenReady() override { service_->RemoveObserver(this); } - - void OnStateChanged(ArcBridgeService::State state) override { - if (state == ArcBridgeService::State::READY) { - service_->Shutdown(); - } - } - - private: - ArcBridgeService* service_; - - DISALLOW_COPY_AND_ASSIGN(ScopedShutdownWhenReady); -}; - // Exercises the basic functionality of the ARC Bridge Service. A message from // within the instance should cause the observer to be notified. TEST_F(ArcBridgeTest, Basic) { ASSERT_FALSE(ready()); ASSERT_EQ(ArcBridgeService::State::STOPPED, state()); - ScopedShutdownWhenReady shutdown(service_.get()); - service_->SetAvailable(true); service_->HandleStartup(); + instance_->WaitForInitCall(); + ASSERT_EQ(ArcBridgeService::State::READY, state()); - ASSERT_EQ(ArcBridgeService::State::STOPPED, state()); - - base::RunLoop run_loop; - run_loop.Run(); - - EXPECT_TRUE(ready()); + service_->Shutdown(); ASSERT_EQ(ArcBridgeService::State::STOPPED, state()); } @@ -168,16 +142,31 @@ service_->SetAvailable(true); service_->HandleStartup(); - + // WaitForInitCall() omitted. ASSERT_EQ(ArcBridgeService::State::READY, state()); + service_->Shutdown(); - // Some machines can reach the STOPPED state immediately. - ASSERT_TRUE(state() == ArcBridgeService::State::STOPPING || - state() == ArcBridgeService::State::STOPPED); + ASSERT_EQ(ArcBridgeService::State::STOPPED, state()); +} - base::RunLoop run_loop; - run_loop.Run(); +// If the channel is disconnected, it should be re-established. +TEST_F(ArcBridgeTest, Restart) { + ASSERT_FALSE(ready()); + ASSERT_EQ(0, instance_->init_calls()); + service_->SetAvailable(true); + service_->HandleStartup(); + instance_->WaitForInitCall(); + ASSERT_EQ(ArcBridgeService::State::READY, state()); + ASSERT_EQ(1, instance_->init_calls()); + + // Simulate a connection loss. + service_->OnChannelClosed(); + instance_->WaitForInitCall(); + ASSERT_EQ(ArcBridgeService::State::READY, state()); + ASSERT_EQ(2, instance_->init_calls()); + + service_->Shutdown(); ASSERT_EQ(ArcBridgeService::State::STOPPED, state()); }
diff --git a/components/arc/common/notifications.mojom b/components/arc/common/notifications.mojom index 5a7b78fb..6ee8f23 100644 --- a/components/arc/common/notifications.mojom +++ b/components/arc/common/notifications.mojom
@@ -15,6 +15,7 @@ BUTTON3_CLICKED = 4, BUTTON4_CLICKED = 5, BUTTON5_CLICKED = 6, + MAX = BUTTON5_CLICKED }; // These values must be matched with the NOTIFICATION_TYPE_* constants in @@ -23,6 +24,7 @@ BASIC = 0, IMAGE = 1, PROGRESS = 2, + MAX = PROGRESS }; struct ArcNotificationData {
diff --git a/components/arc/common/process.mojom b/components/arc/common/process.mojom index c6268f9be..9148173 100644 --- a/components/arc/common/process.mojom +++ b/components/arc/common/process.mojom
@@ -87,4 +87,8 @@ interface ProcessInstance { // Requests ARC instance to return the current process list. RequestProcessList() => (array<RunningAppProcessInfo> processes); + + // Requests ARC instance to kill a process. + [MinVersion=1] + KillProcess(uint32 pid, string reason); };
diff --git a/components/arc/input/arc_input_bridge_impl.cc b/components/arc/input/arc_input_bridge_impl.cc index fe38b5b..e24aeb8 100644 --- a/components/arc/input/arc_input_bridge_impl.cc +++ b/components/arc/input/arc_input_bridge_impl.cc
@@ -27,6 +27,20 @@ namespace { +// ARC runs as 32-bit in all platforms, so we need to make sure to send a +// struct input_event that is the same size it expects. +struct timeval32 { + int32_t tv_sec; + int32_t tv_usec; +}; + +struct input_event32 { + struct timeval32 time; + uint16_t type; + uint16_t code; + int32_t value; +}; + // input_event values for keyboard events. const int kKeyReleased = 0; const int kKeyPressed = 1; @@ -256,7 +270,7 @@ int value) { DCHECK(fd.is_valid()); - struct input_event event; + struct input_event32 event; event.time.tv_sec = time_stamp.InSeconds(); base::TimeDelta remainder = time_stamp - base::TimeDelta::FromSeconds(event.time.tv_sec); @@ -267,8 +281,8 @@ // Write event to file descriptor size_t num_written = write(fd.get(), reinterpret_cast<void*>(&event), - sizeof(struct input_event)); - DCHECK_EQ(num_written, sizeof(struct input_event)); + sizeof(struct input_event32)); + DCHECK_EQ(num_written, sizeof(struct input_event32)); } void ArcInputBridgeImpl::SendSynReport(const base::ScopedFD& fd,
diff --git a/components/arc/test/fake_app_instance.cc b/components/arc/test/fake_app_instance.cc index 15a49c7..2ea1ff0 100644 --- a/components/arc/test/fake_app_instance.cc +++ b/components/arc/test/fake_app_instance.cc
@@ -12,6 +12,7 @@ #include "base/files/file_path.h" #include "base/files/file_util.h" #include "base/path_service.h" +#include "base/run_loop.h" #include "mojo/common/common_type_converters.h" namespace mojo { @@ -109,8 +110,18 @@ } void FakeAppInstance::WaitForOnAppInstanceReady() { - WaitForIncomingMethodCall(); // Wait for Init(). - WaitForIncomingMethodCall(); // Wait for RefreshAppList(). + // Several messages are sent back and forth when OnAppInstanceReady() is + // called. Normally, it would be preferred to use a single + // WaitForIncomingMethodCall() to wait for each method individually, but + // QueryVersion() does require processing on the I/O thread, so + // RunUntilIdle() is required to correctly dispatch it. On slower machines + // (and when running under Valgrind), the two thread hops needed to send and + // dispatch each Mojo message might not be picked up by a single + // RunUntilIdle(), so keep pumping the message loop until all expected + // messages are. + while (refresh_app_list_count_ != 1) { + base::RunLoop().RunUntilIdle(); + } } } // namespace arc
diff --git a/components/arc/test/fake_arc_bridge_instance.cc b/components/arc/test/fake_arc_bridge_instance.cc index 4ee47cfd..cfa0737 100644 --- a/components/arc/test/fake_arc_bridge_instance.cc +++ b/components/arc/test/fake_arc_bridge_instance.cc
@@ -13,6 +13,13 @@ void FakeArcBridgeInstance::Init(ArcBridgeHostPtr host) { host_ptr_ = std::move(host); + init_calls_++; +} + +void FakeArcBridgeInstance::Unbind() { + host_ptr_.reset(); + if (binding_.is_bound()) + binding_.Close(); } void FakeArcBridgeInstance::Bind( @@ -20,4 +27,8 @@ binding_.Bind(std::move(interface_request)); } +void FakeArcBridgeInstance::WaitForInitCall() { + binding_.WaitForIncomingMethodCall(); +} + } // namespace arc
diff --git a/components/arc/test/fake_arc_bridge_instance.h b/components/arc/test/fake_arc_bridge_instance.h index 88ac24d7..a121560 100644 --- a/components/arc/test/fake_arc_bridge_instance.h +++ b/components/arc/test/fake_arc_bridge_instance.h
@@ -21,13 +21,23 @@ // the host that the boot sequence has finished. void Bind(mojo::InterfaceRequest<ArcBridgeInstance> interface_request); + // Resets the binding. Useful to simulate a restart. + void Unbind(); + // ArcBridgeInstance: void Init(ArcBridgeHostPtr host) override; + // Ensures the call to Init() has been dispatched. + void WaitForInitCall(); + + // The number of times Init() has been called. + int init_calls() const { return init_calls_; } + private: // Mojo endpoints. mojo::Binding<ArcBridgeInstance> binding_; ArcBridgeHostPtr host_ptr_; + int init_calls_ = 0; DISALLOW_COPY_AND_ASSIGN(FakeArcBridgeInstance); };
diff --git a/components/autofill/content/renderer/form_autofill_util.cc b/components/autofill/content/renderer/form_autofill_util.cc index ef079c6..1655f1abc 100644 --- a/components/autofill/content/renderer/form_autofill_util.cc +++ b/components/autofill/content/renderer/form_autofill_util.cc
@@ -363,9 +363,22 @@ return base::string16(); } +// Helper for |InferLabelForElement()| that infers a label, from +// the value attribute when it is present and user has not typed in (if +// element's value attribute is same as the element's value). +base::string16 InferLabelFromValueAttr(const WebFormControlElement& element) { + CR_DEFINE_STATIC_LOCAL(WebString, kValue, ("value")); + if (element.hasAttribute(kValue) && element.getAttribute(kValue) == + element.value()) { + return element.getAttribute(kValue); + } + + return base::string16(); +} + // Helper for |InferLabelForElement()| that infers a label, if possible, from // enclosing list item, -// e.g. <li>Some Text<input ...><input ...><input ...></tr> +// e.g. <li>Some Text<input ...><input ...><input ...></li> base::string16 InferLabelFromListItem(const WebFormControlElement& element) { WebNode parent = element.parentNode(); CR_DEFINE_STATIC_LOCAL(WebString, kListItem, ("li")); @@ -381,6 +394,24 @@ } // Helper for |InferLabelForElement()| that infers a label, if possible, from +// enclosing label, +// e.g. <label>Some Text<input ...><input ...><input ...></label> +base::string16 InferLabelFromEnclosingLabel( + const WebFormControlElement& element) { + WebNode parent = element.parentNode(); + CR_DEFINE_STATIC_LOCAL(WebString, kLabel, ("label")); + while (!parent.isNull() && parent.isElementNode() && + !parent.to<WebElement>().hasHTMLTagName(kLabel)) { + parent = parent.parentNode(); + } + + if (!parent.isNull() && HasTagName(parent, kLabel)) + return FindChildText(parent); + + return base::string16(); +} + +// Helper for |InferLabelForElement()| that infers a label, if possible, from // surrounding table structure, // e.g. <tr><td>Some Text</td><td><input ...></td></tr> // or <tr><th>Some Text</th><td><input ...></td></tr> @@ -633,23 +664,35 @@ return tag_names; } +bool IsLabelValid(base::StringPiece16 inferred_label, + const std::vector<base::char16>& stop_words) { + // If |inferred_label| has any character other than those in |stop_words|. + auto first_non_stop_word = std::find_if(inferred_label.begin(), + inferred_label.end(), [&stop_words](base::char16 c) { + return !ContainsValue(stop_words, c); + }); + return first_non_stop_word != inferred_label.end(); +} + // Infers corresponding label for |element| from surrounding context in the DOM, // e.g. the contents of the preceding <p> tag or text element. -base::string16 InferLabelForElement(const WebFormControlElement& element) { +base::string16 InferLabelForElement(const WebFormControlElement& element, + const std::vector<base::char16>& stop_words) { base::string16 inferred_label; + if (IsCheckableElement(toWebInputElement(&element))) { inferred_label = InferLabelFromNext(element); - if (!inferred_label.empty()) + if (IsLabelValid(inferred_label, stop_words)) return inferred_label; } inferred_label = InferLabelFromPrevious(element); - if (!inferred_label.empty()) + if (IsLabelValid(inferred_label, stop_words)) return inferred_label; // If we didn't find a label, check for placeholder text. inferred_label = InferLabelFromPlaceholder(element); - if (!inferred_label.empty()) + if (IsLabelValid(inferred_label, stop_words)) return inferred_label; // For all other searches that involve traversing up the tree, the search @@ -661,11 +704,13 @@ continue; seen_tag_names.insert(tag_name); - if (tag_name == "DIV") { + if (tag_name == "LABEL") { + inferred_label = InferLabelFromEnclosingLabel(element); + } else if (tag_name == "DIV") { inferred_label = InferLabelFromDivTable(element); } else if (tag_name == "TD") { inferred_label = InferLabelFromTableColumn(element); - if (inferred_label.empty()) + if (!IsLabelValid(inferred_label, stop_words)) inferred_label = InferLabelFromTableRow(element); } else if (tag_name == "DD") { inferred_label = InferLabelFromDefinitionList(element); @@ -675,11 +720,16 @@ break; } - if (!inferred_label.empty()) - break; + if (IsLabelValid(inferred_label, stop_words)) + return inferred_label; } - return inferred_label; + // If we didn't find a label, check the value attr used as the placeholder. + inferred_label = InferLabelFromValueAttr(element); + if (IsLabelValid(inferred_label, stop_words)) + return inferred_label; + else + return base::string16(); } // Fills |option_strings| with the values of the <option> elements present in @@ -1033,6 +1083,18 @@ } } + // List of characters a label can't be entirely made of (this list can grow). + // Since the term |stop_words| is a known text processing concept we use here + // it to refer to such characters. They are not to be confused with words. + std::vector<base::char16> stop_words; + stop_words.push_back(static_cast<base::char16>(' ')); + stop_words.push_back(static_cast<base::char16>('*')); + stop_words.push_back(static_cast<base::char16>(':')); + stop_words.push_back(static_cast<base::char16>('-')); + stop_words.push_back(static_cast<base::char16>(L'\u2013')); + stop_words.push_back(static_cast<base::char16>('(')); + stop_words.push_back(static_cast<base::char16>(')')); + // Loop through the form control elements, extracting the label text from // the DOM. We use the |fields_extracted| vector to make sure we assign the // extracted label to the correct field, as it's possible |form_fields| will @@ -1045,8 +1107,10 @@ continue; const WebFormControlElement& control_element = control_elements[i]; - if (form_fields[field_idx]->label.empty()) - form_fields[field_idx]->label = InferLabelForElement(control_element); + if (form_fields[field_idx]->label.empty()) { + form_fields[field_idx]->label = InferLabelForElement(control_element, + stop_words); + } TruncateString(&form_fields[field_idx]->label, kMaxDataLength); if (field && *form_control_element == control_element)
diff --git a/components/autofill/core/browser/autofill_test_utils.cc b/components/autofill/core/browser/autofill_test_utils.cc index 1d16c24..85bfba0d 100644 --- a/components/autofill/core/browser/autofill_test_utils.cc +++ b/components/autofill/core/browser/autofill_test_utils.cc
@@ -4,6 +4,8 @@ #include "components/autofill/core/browser/autofill_test_utils.h" +#include <string> + #include "base/guid.h" #include "base/prefs/pref_service.h" #include "base/prefs/pref_service_factory.h" @@ -40,15 +42,17 @@ new user_prefs::PrefRegistrySyncable()); AutofillManager::RegisterProfilePrefs(registry.get()); - // PDM depends on these prefs, which is normally registered in + // PDM depends on these prefs, which are normally registered in // SigninManagerFactory. registry->RegisterStringPref(::prefs::kGoogleServicesAccountId, std::string()); - registry->RegisterStringPref(::prefs::kGoogleServicesUsername, + registry->RegisterStringPref(::prefs::kGoogleServicesLastAccountId, + std::string()); + registry->RegisterStringPref(::prefs::kGoogleServicesLastUsername, std::string()); registry->RegisterStringPref(::prefs::kGoogleServicesUserAccountId, std::string()); - registry->RegisterStringPref(::prefs::kGoogleServicesLastUsername, + registry->RegisterStringPref(::prefs::kGoogleServicesUsername, std::string()); // PDM depends on these prefs, which are normally registered in
diff --git a/components/bitmap_uploader/bitmap_uploader.cc b/components/bitmap_uploader/bitmap_uploader.cc index 5f7f0c5..baa5103b 100644 --- a/components/bitmap_uploader/bitmap_uploader.cc +++ b/components/bitmap_uploader/bitmap_uploader.cc
@@ -149,8 +149,9 @@ mailbox_holder->sync_token = mus::mojom::SyncToken::From<gpu::SyncToken>(sync_token); resource->mailbox_holder = std::move(mailbox_holder); - resource->is_repeated = false; + resource->read_lock_fences_enabled = false; resource->is_software = false; + resource->is_overlay_candidate = false; mus::mojom::QuadPtr quad = mus::mojom::Quad::New(); quad->material = mus::mojom::MATERIAL_TEXTURE_CONTENT;
diff --git a/components/components.gyp b/components/components.gyp index a4b3169..c83d0aa 100644 --- a/components/components.gyp +++ b/components/components.gyp
@@ -101,6 +101,7 @@ 'version_info.gypi', 'version_ui.gypi', 'web_resource.gypi', + 'web_restriction.gypi', 'webdata.gypi', 'webdata_services.gypi', ],
diff --git a/components/components_tests.gyp b/components/components_tests.gyp index ea2fb5f..82deb50b 100644 --- a/components/components_tests.gyp +++ b/components/components_tests.gyp
@@ -1629,6 +1629,7 @@ 'components.gyp:invalidation_java', 'components.gyp:policy_java', 'components.gyp:policy_java_test_support', + 'components.gyp:web_restriction_java', '../base/base.gyp:base_java', '../base/base.gyp:base_java_test_support', '../testing/android/junit/junit_test.gyp:junit_test_support', @@ -1637,7 +1638,8 @@ 'main_class': 'org.chromium.testing.local.JunitTestMain', 'src_paths': [ 'invalidation/impl/android/junit/', - 'policy/android/junit/' + 'policy/android/junit/', + 'web_restriction/junit/' ], }, 'includes': [ '../build/host_jar.gypi' ],
diff --git a/components/content_settings/content/common/content_settings_messages.h b/components/content_settings/content/common/content_settings_messages.h index 5e6e3b06..3b7225c 100644 --- a/components/content_settings/content/common/content_settings_messages.h +++ b/components/content_settings/content/common/content_settings_messages.h
@@ -73,6 +73,11 @@ bool /* if true local storage, otherwise session */, bool /* allowed */) +// Sent by the renderer process when a keygen element is rendered onto the +// current page. +IPC_MESSAGE_ROUTED1(ChromeViewHostMsg_DidUseKeygen, + GURL /* origin_url */) + // Sent by the renderer process to check whether access to FileSystem is // granted by content settings. IPC_MESSAGE_CONTROL4(ChromeViewHostMsg_RequestFileSystemAccessAsync,
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 fd9cbbf..18c1c26d 100644 --- a/components/content_settings/core/browser/host_content_settings_map.cc +++ b/components/content_settings/core/browser/host_content_settings_map.cc
@@ -335,7 +335,8 @@ primary_pattern = ContentSettingsPattern::FromURLNoWildcard(primary_url); secondary_pattern = ContentSettingsPattern::FromURLNoWildcard(secondary_url); - } else if (type == CONTENT_SETTINGS_TYPE_IMAGES || + } else if (type == CONTENT_SETTINGS_TYPE_COOKIES || + type == CONTENT_SETTINGS_TYPE_IMAGES || type == CONTENT_SETTINGS_TYPE_JAVASCRIPT || type == CONTENT_SETTINGS_TYPE_PLUGINS || type == CONTENT_SETTINGS_TYPE_POPUPS || @@ -346,7 +347,8 @@ secondary_pattern = ContentSettingsPattern::Wildcard(); } else if (type == CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC || type == CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA || - type == CONTENT_SETTINGS_TYPE_NOTIFICATIONS) { + type == CONTENT_SETTINGS_TYPE_NOTIFICATIONS || + type == CONTENT_SETTINGS_TYPE_PPAPI_BROKER) { primary_pattern = ContentSettingsPattern::FromURLNoWildcard(primary_url); secondary_pattern = ContentSettingsPattern::Wildcard(); } else { @@ -360,8 +362,8 @@ // the existing rule is more specific, than change the existing rule instead // of creating a new rule that would be hidden behind the existing rule. content_settings::SettingInfo info; - scoped_ptr<base::Value> v = - GetWebsiteSetting(primary_url, secondary_url, type, std::string(), &info); + scoped_ptr<base::Value> v = GetWebsiteSettingInternal( + primary_url, secondary_url, type, std::string(), &info); DCHECK_EQ(content_settings::SETTING_SOURCE_USER, info.source); ContentSettingsPattern narrow_primary = primary_pattern;
diff --git a/components/crash/content/app/BUILD.gn b/components/crash/content/app/BUILD.gn index b4fbe74c..474b2f2 100644 --- a/components/crash/content/app/BUILD.gn +++ b/components/crash/content/app/BUILD.gn
@@ -44,6 +44,7 @@ ] deps = [ "//base", + "//third_party/kasko", ] deps += [ ":lib" ]
diff --git a/components/crash/content/app/crashpad_win.cc b/components/crash/content/app/crashpad_win.cc index 2da371cc..1c241ca 100644 --- a/components/crash/content/app/crashpad_win.cc +++ b/components/crash/content/app/crashpad_win.cc
@@ -77,6 +77,9 @@ arguments.push_back("--type=crashpad-handler"); } + // TODO(scottmg): See https://crashpad.chromium.org/bug/23. + arguments.push_back("--no-rate-limit"); + result = g_crashpad_client.Get().StartHandler( exe_file, database_path, url, process_annotations, arguments, false);
diff --git a/components/cronet/android/BUILD.gn b/components/cronet/android/BUILD.gn index 7d1d603c..dab63ff 100644 --- a/components/cronet/android/BUILD.gn +++ b/components/cronet/android/BUILD.gn
@@ -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/config/android/config.gni") import("//build/config/android/rules.gni") import("//build/util/version.gni") import("//chrome/version.gni") @@ -498,3 +499,187 @@ "//testing/gtest", ] } + +_package_dir = "$root_out_dir/cronet" +_extract_cronet_jars_dir = "$target_gen_dir/cronet_jar_extract" + +action("extract_cronet_jars") { + # extract_from_jars.py deletes the target directory before extracting. + script = "//components/cronet/tools/extract_from_jars.py" + depfile = "$target_gen_dir/$target_name.d" + + sources = [ + "$root_out_dir/lib.java/base/base_java.jar", + "$root_out_dir/lib.java/components/cronet/android/cronet_java.jar", + "$root_out_dir/lib.java/net/android/net_java.jar", + "$root_out_dir/lib.java/url/url_java.jar", + ] + outputs = [ + depfile, + ] + + _rebased_sources = rebase_path(sources, root_build_dir) + + args = [ + "--classes-dir", + rebase_path(_extract_cronet_jars_dir, root_build_dir), + "--jars=${_rebased_sources}", + "--depfile", + rebase_path(depfile, root_build_dir), + ] + + deps = [ + ":cronet_java", + "//base:base_java", + "//net/android:net_java", + "//url:url_java", + ] +} + +action("repackage_extracted_jars") { + _output_jar = "$_package_dir/cronet.jar" + + script = "//build/android/gyp/jar.py" + outputs = [ + _output_jar, + ] + + args = [ + "--classes-dir", + rebase_path(_extract_cronet_jars_dir, root_build_dir), + "--jar-path", + rebase_path(_output_jar, root_build_dir), + ] + + deps = [ + ":extract_cronet_jars", + ] +} + +template("jar_src") { + action(target_name) { + _rebased_src_dirs = rebase_path(invoker.src_dirs, root_build_dir) + + script = "//components/cronet/tools/jar_src.py" + depfile = "$target_gen_dir/$target_name.d" + outputs = [ + depfile, + invoker.jar_path, + ] + args = [ + "--src-dir=${_rebased_src_dirs}", + "--jar-path", + rebase_path(invoker.jar_path, root_build_dir), + "--depfile", + rebase_path(depfile, root_build_dir), + ] + } +} + +jar_src("jar_cronet_api_source") { + src_dirs = [ "api/src" ] + jar_path = "$_package_dir/cronet_api-src.jar" +} + +jar_src("jar_cronet_sample_source") { + src_dirs = [ "sample" ] + jar_path = "$_package_dir/cronet-sample-src.jar" +} + +jar_src("jar_cronet_other_source") { + src_dirs = [ + "//base/android/java/src", + "//components/cronet/android/java/src", + "//net/android/java/src", + "//url/android/java/src", + ] + jar_path = "$_package_dir/cronet-src.jar" +} + +action("generate_licenses") { + _license_path = "$_package_dir/LICENSE" + + script = "//components/cronet/tools/cronet_licenses.py" + outputs = [ + _license_path, + ] + args = [ + "license", + rebase_path(_license_path, root_build_dir), + ] +} + +action("generate_javadoc") { + script = "//components/cronet/tools/generate_javadoc.py" + depfile = "$target_gen_dir/$target_name.d" + outputs = [ + depfile, + ] + + args = [ + "--output-dir", + rebase_path(_package_dir, root_build_dir), + "--input-dir", + rebase_path("//components/cronet", root_build_dir), + "--overview-file", + rebase_path("$_package_dir/README.md.html", root_build_dir), + "--readme-file", + rebase_path("//components/cronet/README.md", root_build_dir), + "--depfile", + rebase_path(depfile, root_build_dir), + ] +} + +copy("cronet_package_copy") { + sources = [ + "$root_out_dir/lib.java/components/cronet/android/cronet_api.jar", + "//AUTHORS", + "//chrome/VERSION", + "//components/cronet/android/proguard.cfg", + ] + outputs = [ + "$_package_dir/{{source_file_part}}", + ] + + deps = [ + ":cronet_api", + ] +} + +copy("cronet_package_copy_native_lib") { + sources = [ + "$root_out_dir/libcronet.so", + ] + outputs = [ + "$_package_dir/libs/${android_app_abi}/libcronet.so", + ] + deps = [ + ":cronet", + ] +} + +copy("cronet_package_copy_native_lib_unstripped") { + sources = [ + "$root_out_dir/lib.unstripped/libcronet.so", + ] + outputs = [ + "$_package_dir/symbols/${android_app_abi}/libcronet.so", + ] + deps = [ + ":cronet", + ] +} + +group("cronet_package") { + deps = [ + ":cronet_package_copy", + ":cronet_package_copy_native_lib", + ":cronet_package_copy_native_lib_unstripped", + ":generate_javadoc", + ":generate_licenses", + ":jar_cronet_api_source", + ":jar_cronet_other_source", + ":jar_cronet_sample_source", + ":repackage_extracted_jars", + ] +}
diff --git a/components/cronet/android/cronet_data_reduction_proxy.cc b/components/cronet/android/cronet_data_reduction_proxy.cc index 195ab8e..0b6bf02 100644 --- a/components/cronet/android/cronet_data_reduction_proxy.cc +++ b/components/cronet/android/cronet_data_reduction_proxy.cc
@@ -4,6 +4,8 @@ #include "components/cronet/android/cronet_data_reduction_proxy.h" +#include <utility> + #include "base/command_line.h" #include "base/logging.h" #include "base/prefs/pref_registry_simple.h" @@ -38,9 +40,9 @@ pref_service_factory.set_user_prefs( make_scoped_refptr(new CronetInMemoryPrefStore())); scoped_ptr<PrefService> pref_service = - pref_service_factory.Create(pref_registry.get()).Pass(); + pref_service_factory.Create(pref_registry.get()); pref_registry = nullptr; - return pref_service.Pass(); + return pref_service; } // TODO(bengr): Apply test configurations directly, instead of via the @@ -100,8 +102,8 @@ scoped_ptr<net::NetworkDelegate> CronetDataReductionProxy::CreateNetworkDelegate( scoped_ptr<net::NetworkDelegate> wrapped_network_delegate) { - return io_data_->CreateNetworkDelegate(wrapped_network_delegate.Pass(), - false /* No bypass UMA */ ); + return io_data_->CreateNetworkDelegate(std::move(wrapped_network_delegate), + false /* No bypass UMA */); } scoped_ptr<net::URLRequestInterceptor> @@ -125,7 +127,7 @@ data_reduction_proxy_service->GetWeakPtr()); settings_->InitDataReductionProxySettings( kDataReductionProxyEnabled, prefs_.get(), io_data_.get(), - data_reduction_proxy_service.Pass()); + std::move(data_reduction_proxy_service)); settings_->SetDataReductionProxyEnabled(enable); settings_->MaybeActivateDataReductionProxy(true); }
diff --git a/components/cronet/android/cronet_url_request_context_adapter.cc b/components/cronet/android/cronet_url_request_context_adapter.cc index 231d64f..efc0446 100644 --- a/components/cronet/android/cronet_url_request_context_adapter.cc +++ b/components/cronet/android/cronet_url_request_context_adapter.cc
@@ -278,8 +278,8 @@ config->data_reduction_fallback_proxy, config->data_reduction_secure_proxy_check_url, config->user_agent, GetNetworkTaskRunner(), net_log_.get())); - network_delegate = - data_reduction_proxy_->CreateNetworkDelegate(network_delegate.Pass()); + network_delegate = data_reduction_proxy_->CreateNetworkDelegate( + std::move(network_delegate)); std::vector<scoped_ptr<net::URLRequestInterceptor>> interceptors; interceptors.push_back(data_reduction_proxy_->CreateInterceptor()); context_builder.SetInterceptors(std::move(interceptors));
diff --git a/components/cronet/tools/extract_from_jars.py b/components/cronet/tools/extract_from_jars.py index d72d46c..73931cd 100755 --- a/components/cronet/tools/extract_from_jars.py +++ b/components/cronet/tools/extract_from_jars.py
@@ -31,6 +31,7 @@ def main(): parser = optparse.OptionParser() + build_utils.AddDepfileOption(parser) parser.add_option('--classes-dir', help='Directory to extract .class files.') parser.add_option('--jars', help='Paths to jars to extract.') parser.add_option('--stamp', help='Path to touch on success.') @@ -39,6 +40,10 @@ ExtractJars(options) + if options.depfile: + build_utils.WriteDepfile(options.depfile, + build_utils.GetPythonDependencies()) + if options.stamp: build_utils.Touch(options.stamp)
diff --git a/components/cronet/tools/generate_javadoc.py b/components/cronet/tools/generate_javadoc.py index 495f1b278..f21ceb3 100755 --- a/components/cronet/tools/generate_javadoc.py +++ b/components/cronet/tools/generate_javadoc.py
@@ -48,6 +48,7 @@ def main(): parser = optparse.OptionParser() + build_utils.AddDepfileOption(parser) parser.add_option('--output-dir', help='Directory to put javadoc') parser.add_option('--input-dir', help='Root of cronet source') parser.add_option('--overview-file', help='Path of the overview page') @@ -60,6 +61,12 @@ GenerateJavadoc(options) + if options.depfile: + input_paths = [] + for root, _, filenames in os.walk(options.input_dir): + input_paths.extend(os.path.join(root, f) for f in filenames) + build_utils.WriteDepfile(options.depfile, + input_paths + build_utils.GetPythonDependencies()) + if __name__ == '__main__': sys.exit(main()) -
diff --git a/components/cronet/tools/jar_src.py b/components/cronet/tools/jar_src.py index 0cda4a89..2b941d5 100755 --- a/components/cronet/tools/jar_src.py +++ b/components/cronet/tools/jar_src.py
@@ -32,6 +32,7 @@ def main(): parser = optparse.OptionParser() + build_utils.AddDepfileOption(parser) parser.add_option('--src-dir', action="append", help='Directory containing .java files.') parser.add_option('--jar-path', help='Jar output path.') @@ -39,13 +40,24 @@ options, _ = parser.parse_args() + src_dirs = [] for src_dir in options.src_dir: + src_dirs.extend(build_utils.ParseGypList(src_dir)) + + for src_dir in src_dirs: JarSources(src_dir, options.jar_path) + if options.depfile: + input_paths = [] + for src_dir in src_dirs: + for root, _, filenames in os.walk(src_dir): + input_paths.extend(os.path.join(root, f) for f in filenames) + build_utils.WriteDepfile(options.depfile, + input_paths + build_utils.GetPythonDependencies()) + if options.stamp: build_utils.Touch(options.stamp) - if __name__ == '__main__': sys.exit(main())
diff --git a/components/dom_distiller/core/css/distilledpage.css b/components/dom_distiller/core/css/distilledpage.css index 4c01939f..2a80875 100644 --- a/components/dom_distiller/core/css/distilledpage.css +++ b/components/dom_distiller/core/css/distilledpage.css
@@ -285,6 +285,7 @@ .light, .dark, .sepia { color: #000 !important; background-color: #fff !important; + font-family: sans-serif !important; } /* If the transition duration is unchanged, the above color changes
diff --git a/components/error_page.gypi b/components/error_page.gypi index ab54dbf..6e19996e 100644 --- a/components/error_page.gypi +++ b/components/error_page.gypi
@@ -19,6 +19,8 @@ 'sources': [ 'error_page/common/error_page_params.cc', 'error_page/common/error_page_params.h', + 'error_page/common/error_page_switches.cc', + 'error_page/common/error_page_switches.h', 'error_page/common/net_error_info.cc', 'error_page/common/net_error_info.h', 'error_page/common/offline_page_types.h',
diff --git a/components/error_page/common/BUILD.gn b/components/error_page/common/BUILD.gn index b5ed80e..0f34a3a 100644 --- a/components/error_page/common/BUILD.gn +++ b/components/error_page/common/BUILD.gn
@@ -6,6 +6,8 @@ sources = [ "error_page_params.cc", "error_page_params.h", + "error_page_switches.cc", + "error_page_switches.h", "net_error_info.cc", "net_error_info.h", "offline_page_types.h",
diff --git a/components/error_page/common/error_page_switches.cc b/components/error_page/common/error_page_switches.cc new file mode 100644 index 0000000..7d8ef37 --- /dev/null +++ b/components/error_page/common/error_page_switches.cc
@@ -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. + +#include "components/error_page/common/error_page_switches.h" + +namespace error_page { +namespace switches { + +// Disables the dinosaur easter egg on the offline interstitial. +const char kDisableDinosaurEasterEgg[] = "disable-dinosaur-easter-egg"; + +// Values for the kShowSavedCopy flag. +const char kDisableShowSavedCopy[] = "disable"; +const char kEnableShowSavedCopyPrimary[] = "primary"; +const char kEnableShowSavedCopySecondary[] = "secondary"; + +// Command line flag offering a "Show saved copy" option to the user if offline. +// The various modes are disabled, primary, or secondary. Primary/secondary +// refers to button placement (for experiment). +const char kShowSavedCopy[] = "show-saved-copy"; + +} // namespace switches +} // namespace error_page
diff --git a/components/error_page/common/error_page_switches.h b/components/error_page/common/error_page_switches.h new file mode 100644 index 0000000..d154656 --- /dev/null +++ b/components/error_page/common/error_page_switches.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. + +// Defines all the command-line switches used by //components/error_page. + +#ifndef COMPONENTS_ERROR_PAGE_COMMON_ERROR_PAGE_SWITCHES_H_ +#define COMPONENTS_ERROR_PAGE_COMMON_ERROR_PAGE_SWITCHES_H_ + +namespace error_page { +namespace switches { + +extern const char kDisableDinosaurEasterEgg[]; +extern const char kDisableShowSavedCopy[]; +extern const char kEnableShowSavedCopyPrimary[]; +extern const char kEnableShowSavedCopySecondary[]; +extern const char kShowSavedCopy[]; + +} // namespace switches +} // namespace error_page + +#endif // COMPONENTS_ERROR_PAGE_COMMON_ERROR_PAGE_SWITCHES_H_
diff --git a/components/error_page/renderer/net_error_helper_core.cc b/components/error_page/renderer/net_error_helper_core.cc index 56381ff8..847ff0d2 100644 --- a/components/error_page/renderer/net_error_helper_core.cc +++ b/components/error_page/renderer/net_error_helper_core.cc
@@ -283,7 +283,7 @@ void LogCorrectionTypeShown(int type_id) { UMA_HISTOGRAM_ENUMERATION( - "Net.ErrorpageCounts.NavigationCorrectionLinksShown", type_id, + "Net.ErrorPageCounts.NavigationCorrectionLinksShown", type_id, kWebSearchQueryUMAId + 1); } @@ -390,7 +390,7 @@ // Web search suggestion isn't in |kCorrectionResourceTable| array. if (type_id == "webSearchQuery") { UMA_HISTOGRAM_ENUMERATION( - "Net.ErrorpageCounts.NavigationCorrectionLinksUsed", + "Net.ErrorPageCounts.NavigationCorrectionLinksUsed", kWebSearchQueryUMAId, kWebSearchQueryUMAId + 1); return; } @@ -402,7 +402,7 @@ if (kCorrectionResourceTable[correction_index].correction_type == type_id) { UMA_HISTOGRAM_ENUMERATION( - "Net.ErrorpageCounts.NavigationCorrectionLinksUsed", + "Net.ErrorPageCounts.NavigationCorrectionLinksUsed", static_cast<int>(correction_index), kWebSearchQueryUMAId + 1); break; }
diff --git a/components/exo/display.cc b/components/exo/display.cc index 51a353ac..a63a627 100644 --- a/components/exo/display.cc +++ b/components/exo/display.cc
@@ -4,6 +4,8 @@ #include "components/exo/display.h" +#include <utility> + #include "base/trace_event/trace_event.h" #include "base/trace_event/trace_event_argument.h" #include "components/exo/shared_memory.h" @@ -54,7 +56,7 @@ gfx::GpuMemoryBufferHandle handle; handle.type = gfx::OZONE_NATIVE_PIXMAP; - handle.native_pixmap_handle.fd = base::FileDescriptor(fd.Pass()); + handle.native_pixmap_handle.fd = base::FileDescriptor(std::move(fd)); handle.native_pixmap_handle.stride = stride; scoped_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer = @@ -68,7 +70,7 @@ } return make_scoped_ptr( - new Buffer(gpu_memory_buffer.Pass(), GL_TEXTURE_EXTERNAL_OES)); + new Buffer(std::move(gpu_memory_buffer), GL_TEXTURE_EXTERNAL_OES)); } #endif
diff --git a/components/exo/shell_surface.cc b/components/exo/shell_surface.cc index 54c3699..6f8cb84 100644 --- a/components/exo/shell_surface.cc +++ b/components/exo/shell_surface.cc
@@ -49,19 +49,34 @@ DISALLOW_COPY_AND_ASSIGN(CustomFrameView); }; -views::Widget::InitParams CreateWidgetInitParams( - views::WidgetDelegate* delegate) { - views::Widget::InitParams params; - params.type = views::Widget::InitParams::TYPE_WINDOW; - params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; - params.delegate = delegate; - params.shadow_type = views::Widget::InitParams::SHADOW_TYPE_NONE; - params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; - params.show_state = ui::SHOW_STATE_NORMAL; - params.parent = ash::Shell::GetContainer( - ash::Shell::GetPrimaryRootWindow(), ash::kShellWindowId_DefaultContainer); - return params; -} +class ShellSurfaceWidget : public views::Widget { + public: + explicit ShellSurfaceWidget(ShellSurface* shell_surface) + : shell_surface_(shell_surface) {} + + static views::Widget::InitParams CreateInitParams( + views::WidgetDelegate* delegate) { + views::Widget::InitParams params; + params.type = views::Widget::InitParams::TYPE_WINDOW; + params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + params.delegate = delegate; + params.shadow_type = views::Widget::InitParams::SHADOW_TYPE_NONE; + params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; + params.show_state = ui::SHOW_STATE_NORMAL; + params.parent = + ash::Shell::GetContainer(ash::Shell::GetPrimaryRootWindow(), + ash::kShellWindowId_DefaultContainer); + return params; + } + + // Overridden from views::Widget + void Close() override { shell_surface_->Close(); } + + private: + ShellSurface* const shell_surface_; + + DISALLOW_COPY_AND_ASSIGN(ShellSurfaceWidget); +}; } // namespace @@ -94,9 +109,9 @@ return; } - views::Widget::InitParams params = CreateWidgetInitParams(this); + views::Widget::InitParams params = ShellSurfaceWidget::CreateInitParams(this); params.bounds = gfx::Rect(gfx::Size(1, 1)); - widget_.reset(new views::Widget); + widget_.reset(new ShellSurfaceWidget(this)); widget_->Init(params); widget_->GetNativeWindow()->set_owned_by_parent(false); widget_->GetNativeWindow()->SetName("ExoShellSurface"); @@ -116,9 +131,9 @@ return; } - views::Widget::InitParams params = CreateWidgetInitParams(this); + views::Widget::InitParams params = ShellSurfaceWidget::CreateInitParams(this); params.show_state = ui::SHOW_STATE_MAXIMIZED; - widget_.reset(new views::Widget); + widget_.reset(new ShellSurfaceWidget(this)); widget_->Init(params); widget_->GetNativeWindow()->set_owned_by_parent(false); widget_->GetNativeWindow()->SetName("ExoShellSurface"); @@ -134,9 +149,9 @@ return; } - views::Widget::InitParams params = CreateWidgetInitParams(this); + views::Widget::InitParams params = ShellSurfaceWidget::CreateInitParams(this); params.show_state = ui::SHOW_STATE_FULLSCREEN; - widget_.reset(new views::Widget); + widget_.reset(new ShellSurfaceWidget(this)); widget_->Init(params); widget_->GetNativeWindow()->set_owned_by_parent(false); widget_->GetNativeWindow()->SetName("ExoShellSurface"); @@ -181,6 +196,11 @@ } } +void ShellSurface::Close() { + if (!close_callback_.is_null()) + close_callback_.Run(); +} + void ShellSurface::SetGeometry(const gfx::Rect& geometry) { TRACE_EVENT1("exo", "ShellSurface::SetGeometry", "geometry", geometry.ToString());
diff --git a/components/exo/shell_surface.h b/components/exo/shell_surface.h index 541dd11d..2d2b1d0 100644 --- a/components/exo/shell_surface.h +++ b/components/exo/shell_surface.h
@@ -34,6 +34,12 @@ explicit ShellSurface(Surface* surface); ~ShellSurface() override; + // Set the callback to run when the user wants the shell surface to be closed. + // The receiver can chose to not close the window on this signal. + void set_close_callback(const base::Closure& close_callback) { + close_callback_ = close_callback; + } + // Show surface as a toplevel window. void SetToplevel(); @@ -58,6 +64,10 @@ // Start an interactive move of surface. void Move(); + // Signal a request to close the window. It is up to the implementation to + // actually decide to do so though. + void Close(); + // Set geometry for surface. The geometry represents the "visible bounds" // for the surface from the user's perspective. void SetGeometry(const gfx::Rect& geometry); @@ -89,6 +99,7 @@ base::string16 title_; std::string application_id_; gfx::Rect geometry_; + base::Closure close_callback_; DISALLOW_COPY_AND_ASSIGN(ShellSurface); };
diff --git a/components/exo/shell_surface_unittest.cc b/components/exo/shell_surface_unittest.cc index c8b6d46..ff95d2e3 100644 --- a/components/exo/shell_surface_unittest.cc +++ b/components/exo/shell_surface_unittest.cc
@@ -137,5 +137,25 @@ surface->bounds().ToString()); } +void Close(int* close_call_count) { + (*close_call_count)++; +} + +TEST_F(ShellSurfaceTest, CloseCallback) { + scoped_ptr<Surface> surface(new Surface); + scoped_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get())); + + int close_call_count = 0; + shell_surface->set_close_callback( + base::Bind(&Close, base::Unretained(&close_call_count))); + + shell_surface->SetToplevel(); + surface->Commit(); + + EXPECT_EQ(0, close_call_count); + shell_surface->GetWidget()->Close(); + EXPECT_EQ(1, close_call_count); +} + } // namespace } // namespace exo
diff --git a/components/exo/surface.cc b/components/exo/surface.cc index 7501f580..a5e0fbf 100644 --- a/components/exo/surface.cc +++ b/components/exo/surface.cc
@@ -22,6 +22,7 @@ #include "ui/compositor/layer.h" #include "ui/gfx/buffer_format_util.h" #include "ui/gfx/gpu_memory_buffer.h" +#include "ui/gfx/transform_util.h" DECLARE_WINDOW_PROPERTY_TYPE(exo::Surface*); @@ -93,6 +94,7 @@ Surface::Surface() : aura::Window(new EmptyWindowDelegate), has_pending_contents_(false), + pending_buffer_scale_(1.0f), needs_commit_surface_hierarchy_(false), update_contents_after_successful_compositing_(false), compositor_(nullptr), @@ -152,6 +154,12 @@ pending_opaque_region_ = region; } +void Surface::SetBufferScale(float scale) { + TRACE_EVENT1("exo", "Surface::SetBufferScale", "scale", scale); + + pending_buffer_scale_ = scale; +} + void Surface::AddSubSurface(Surface* sub_surface) { TRACE_EVENT1("exo", "Surface::AddSubSurface", "sub_surface", sub_surface->AsTracedValue()); @@ -274,10 +282,15 @@ std::move(texture_mailbox_release_callback), texture_mailbox.size_in_pixels()); layer()->SetTextureFlipped(false); - layer()->SetBounds(gfx::Rect(layer()->bounds().origin(), - texture_mailbox.size_in_pixels())); + gfx::Size contents_size(gfx::ScaleToFlooredSize( + texture_mailbox.size_in_pixels(), 1.0f / pending_buffer_scale_)); + layer()->SetBounds(gfx::Rect(layer()->bounds().origin(), contents_size)); layer()->SetFillsBoundsOpaquely(pending_opaque_region_.contains( - gfx::RectToSkIRect(gfx::Rect(texture_mailbox.size_in_pixels())))); + gfx::RectToSkIRect(gfx::Rect(contents_size)))); + layer()->SetTransform(gfx::GetScaleTransform( + gfx::Rect(texture_mailbox.size_in_pixels()).CenterPoint(), + static_cast<float>(contents_size.width()) / + texture_mailbox.size_in_pixels().width())); } else { // Show solid color content if no buffer is attached or we failed // to produce a texture mailbox for the currently attached buffer. @@ -334,7 +347,9 @@ } gfx::Size Surface::GetPreferredSize() const { - return pending_buffer_ ? pending_buffer_->GetSize() : layer()->size(); + return pending_buffer_ ? gfx::ScaleToFlooredSize(pending_buffer_->GetSize(), + 1.0f / pending_buffer_scale_) + : layer()->size(); } bool Surface::IsSynchronized() const {
diff --git a/components/exo/surface.h b/components/exo/surface.h index 99336c56..9868a55 100644 --- a/components/exo/surface.h +++ b/components/exo/surface.h
@@ -55,6 +55,12 @@ // This sets the region of the surface that contains opaque content. void SetOpaqueRegion(const SkRegion& region); + // This sets the scaling factor used to interpret the contents of the buffer + // attached to the surface. Note that if the scale is larger than 1, then you + // have to attach a buffer that is larger (by a factor of scale in each + // dimension) than the desired surface size. + void SetBufferScale(float scale); + // Functions that control sub-surface state. All sub-surface state is // double-buffered and will be applied when Commit() is called. void AddSubSurface(Surface* sub_surface); @@ -139,6 +145,9 @@ // The opaque region to take effect when Commit() is called. SkRegion pending_opaque_region_; + // The buffer scaling factor to take effect when Commit() is called. + float pending_buffer_scale_; + // The stack of sub-surfaces to take effect when Commit() is called. // Bottom-most sub-surface at the front of the list and top-most sub-surface // at the back.
diff --git a/components/exo/surface_unittest.cc b/components/exo/surface_unittest.cc index 96d43fc..3ba3a7d5 100644 --- a/components/exo/surface_unittest.cc +++ b/components/exo/surface_unittest.cc
@@ -91,6 +91,27 @@ surface->SetOpaqueRegion(SkRegion(SkIRect::MakeEmpty())); } +TEST_F(SurfaceTest, SetBufferScale) { + gfx::Size buffer_size(512, 512); + scoped_ptr<Buffer> buffer( + new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size).Pass(), + GL_TEXTURE_2D)); + scoped_ptr<Surface> surface(new Surface); + + // Attach the buffer to the surface. This will update the pending bounds of + // the surface to the buffer size. + surface->Attach(buffer.get()); + EXPECT_EQ(buffer_size.ToString(), surface->GetPreferredSize().ToString()); + + // This will update the pending bounds of the surface and take the buffer + // scale into account. + const float kBufferScale = 2.0f; + surface->SetBufferScale(kBufferScale); + EXPECT_EQ( + gfx::ScaleToFlooredSize(buffer_size, 1.0f / kBufferScale).ToString(), + surface->GetPreferredSize().ToString()); +} + TEST_F(SurfaceTest, Commit) { scoped_ptr<Surface> surface(new Surface);
diff --git a/components/exo/wayland/BUILD.gn b/components/exo/wayland/BUILD.gn index 4b184088..d0ac6b5 100644 --- a/components/exo/wayland/BUILD.gn +++ b/components/exo/wayland/BUILD.gn
@@ -22,6 +22,7 @@ defines = [ "EXO_IMPLEMENTATION" ] deps = [ + "//ash", "//base", "//components/exo", "//skia",
diff --git a/components/exo/wayland/server.cc b/components/exo/wayland/server.cc index f0f2a3c..6d93087 100644 --- a/components/exo/wayland/server.cc +++ b/components/exo/wayland/server.cc
@@ -13,6 +13,9 @@ #include <algorithm> #include <utility> +#include "ash/display/display_info.h" +#include "ash/display/display_manager.h" +#include "ash/shell.h" #include "base/bind.h" #include "base/cancelable_callback.h" #include "base/macros.h" @@ -178,7 +181,15 @@ void surface_set_buffer_scale(wl_client* client, wl_resource* resource, int32_t scale) { - NOTIMPLEMENTED(); + if (scale < 1) { + wl_resource_post_error(resource, WL_SURFACE_ERROR_INVALID_SCALE, + "buffer scale must be at least one " + "('%d' specified)", + scale); + return; + } + + GetUserDataAs<Surface>(resource)->SetBufferScale(scale); } const struct wl_surface_interface surface_implementation = { @@ -488,7 +499,7 @@ buffer->set_release_callback( base::Bind(&wl_buffer_send_release, base::Unretained(buffer_resource))); - SetImplementation(buffer_resource, &buffer_implementation, buffer.Pass()); + SetImplementation(buffer_resource, &buffer_implementation, std::move(buffer)); } const struct wl_drm_interface drm_implementation = { @@ -725,6 +736,55 @@ } //////////////////////////////////////////////////////////////////////////////// +// wl_output_interface: + +const uint32_t output_version = 2; + +void bind_output(wl_client* client, void* data, uint32_t version, uint32_t id) { + wl_resource* resource = wl_resource_create( + client, &wl_output_interface, std::min(version, output_version), id); + if (!resource) { + wl_client_post_no_memory(client); + return; + } + + // TODO(reveman): Watch for display changes and report them. + // TODO(reveman): Multi-display support. + ash::DisplayManager* display_manager = + ash::Shell::GetInstance()->display_manager(); + const gfx::Display& primary = display_manager->GetPrimaryDisplayCandidate(); + + const ash::DisplayInfo& info = display_manager->GetDisplayInfo(primary.id()); + const float kInchInMm = 25.4f; + const char* kUnknownMake = "unknown"; + const char* kUnknownModel = "unknown"; + gfx::Rect bounds = info.bounds_in_native(); + // TODO(reveman): Send the actual active device rotation. + wl_output_send_geometry( + resource, bounds.x(), bounds.y(), + static_cast<int>(kInchInMm * bounds.width() / info.device_dpi()), + static_cast<int>(kInchInMm * bounds.height() / info.device_dpi()), + WL_OUTPUT_SUBPIXEL_UNKNOWN, kUnknownMake, kUnknownModel, + WL_OUTPUT_TRANSFORM_NORMAL); + + // TODO(reveman): Send correct device scale factor when surface API respects + // scale. + if (version >= WL_OUTPUT_SCALE_SINCE_VERSION) + wl_output_send_scale(resource, 1); + + // TODO(reveman): Send real list of modes after adding multi-display support. + ash::DisplayMode mode = + display_manager->GetActiveModeForDisplayId(primary.id()); + wl_output_send_mode(resource, + WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED, + mode.size.width(), mode.size.height(), + static_cast<int>(mode.refresh_rate * 1000)); + + if (version >= WL_OUTPUT_DONE_SINCE_VERSION) + wl_output_send_done(resource); +} + +//////////////////////////////////////////////////////////////////////////////// // xdg_surface_interface: void xdg_surface_destroy(wl_client* client, wl_resource* resource) { @@ -871,6 +931,9 @@ // An XdgSurface is a toplevel shell surface. shell_surface->SetToplevel(); + shell_surface->set_close_callback(base::Bind( + &xdg_surface_send_close, base::Unretained(xdg_surface_resource))); + SetImplementation(xdg_surface_resource, &xdg_surface_implementation, std::move(shell_surface)); } @@ -1412,6 +1475,8 @@ bind_subcompositor); wl_global_create(wl_display_.get(), &wl_shell_interface, 1, display_, bind_shell); + wl_global_create(wl_display_.get(), &wl_output_interface, 2, display_, + bind_output); wl_global_create(wl_display_.get(), &xdg_shell_interface, 1, display_, bind_xdg_shell); wl_global_create(wl_display_.get(), &wl_data_device_manager_interface, 1,
diff --git a/components/guest_view/browser/guest_view_base.cc b/components/guest_view/browser/guest_view_base.cc index ff69424..c2c27c7 100644 --- a/components/guest_view/browser/guest_view_base.cc +++ b/components/guest_view/browser/guest_view_base.cc
@@ -608,12 +608,13 @@ void GuestViewBase::ContentsMouseEvent(WebContents* source, const gfx::Point& location, - bool motion) { + bool motion, + bool exited) { if (!attached() || !embedder_web_contents()->GetDelegate()) return; embedder_web_contents()->GetDelegate()->ContentsMouseEvent( - embedder_web_contents(), location, motion); + embedder_web_contents(), location, motion, exited); } void GuestViewBase::ContentsZoomChange(bool zoom_in) {
diff --git a/components/guest_view/browser/guest_view_base.h b/components/guest_view/browser/guest_view_base.h index 3dfa4c6..9d5b340d 100644 --- a/components/guest_view/browser/guest_view_base.h +++ b/components/guest_view/browser/guest_view_base.h
@@ -352,7 +352,8 @@ void ActivateContents(content::WebContents* contents) final; void ContentsMouseEvent(content::WebContents* source, const gfx::Point& location, - bool motion) final; + bool motion, + bool exited) final; void ContentsZoomChange(bool zoom_in) final; void LoadingStateChanged(content::WebContents* source, bool to_different_document) final;
diff --git a/components/html_viewer/html_document.cc b/components/html_viewer/html_document.cc index b515444..3da8c5d 100644 --- a/components/html_viewer/html_document.cc +++ b/components/html_viewer/html_document.cc
@@ -63,7 +63,7 @@ private: // WindowTreeDelegate: void OnEmbed(mus::Window* root) override { delegate_->OnEmbed(root); } - void OnUnembed() override { delegate_->OnUnembed(); } + void OnUnembed(mus::Window* root) override { delegate_->OnUnembed(root); } void OnConnectionLost(mus::WindowTreeConnection* connection) override { delegate_->OnConnectionLost(connection); }
diff --git a/components/mus/gles2/command_buffer_type_conversions.cc b/components/mus/gles2/command_buffer_type_conversions.cc index 56353acf..47deb56 100644 --- a/components/mus/gles2/command_buffer_type_conversions.cc +++ b/components/mus/gles2/command_buffer_type_conversions.cc
@@ -133,6 +133,7 @@ result->blend_equation_advanced = input.blend_equation_advanced; result->blend_equation_advanced_coherent = input.blend_equation_advanced_coherent; + result->flips_vertically = input.flips_vertically; return result; } @@ -176,6 +177,7 @@ result.blend_equation_advanced = input->blend_equation_advanced; result.blend_equation_advanced_coherent = input->blend_equation_advanced_coherent; + result.flips_vertically = input->flips_vertically; return result; }
diff --git a/components/mus/mus_app.cc b/components/mus/mus_app.cc index d319aa6..ebc9f39 100644 --- a/components/mus/mus_app.cc +++ b/components/mus/mus_app.cc
@@ -98,11 +98,11 @@ MandolineUIServicesApp::CreateClientConnectionForEmbedAtWindow( ws::ConnectionManager* connection_manager, mojo::InterfaceRequest<mojom::WindowTree> tree_request, - const ws::WindowId& root_id, + ws::ServerWindow* root, uint32_t policy_bitmask, mojom::WindowTreeClientPtr client) { scoped_ptr<ws::WindowTreeImpl> service( - new ws::WindowTreeImpl(connection_manager, root_id, policy_bitmask)); + new ws::WindowTreeImpl(connection_manager, root, policy_bitmask)); return new ws::DefaultClientConnection(std::move(service), connection_manager, std::move(tree_request), std::move(client));
diff --git a/components/mus/mus_app.h b/components/mus/mus_app.h index 5be9031..058d418 100644 --- a/components/mus/mus_app.h +++ b/components/mus/mus_app.h
@@ -63,7 +63,7 @@ ws::ClientConnection* CreateClientConnectionForEmbedAtWindow( ws::ConnectionManager* connection_manager, mojo::InterfaceRequest<mojom::WindowTree> tree_request, - const ws::WindowId& root_id, + ws::ServerWindow* root, uint32_t policy_bitmask, mojom::WindowTreeClientPtr client) override;
diff --git a/components/mus/public/cpp/lib/scoped_window_ptr.cc b/components/mus/public/cpp/lib/scoped_window_ptr.cc index cf734cb..1c7e1f4 100644 --- a/components/mus/public/cpp/lib/scoped_window_ptr.cc +++ b/components/mus/public/cpp/lib/scoped_window_ptr.cc
@@ -22,7 +22,7 @@ // static void ScopedWindowPtr::DeleteWindowOrWindowManager(Window* window) { - if (window->connection()->GetRoot() == window) + if (window->connection()->GetRoots().count(window) > 0) delete window->connection(); else window->Destroy();
diff --git a/components/mus/public/cpp/lib/window.cc b/components/mus/public/cpp/lib/window.cc index 9d7feeb..bbbcc47d 100644 --- a/components/mus/public/cpp/lib/window.cc +++ b/components/mus/public/cpp/lib/window.cc
@@ -152,7 +152,8 @@ } bool IsConnectionRoot(Window* window) { - return window->connection() && window->connection()->GetRoot() == window; + return window->connection() && + window->connection()->GetRoots().count(window) > 0; } bool OwnsWindowOrIsRoot(Window* window) {
diff --git a/components/mus/public/cpp/lib/window_tree_client_impl.cc b/components/mus/public/cpp/lib/window_tree_client_impl.cc index aa72171e..a07a43b 100644 --- a/components/mus/public/cpp/lib/window_tree_client_impl.cc +++ b/components/mus/public/cpp/lib/window_tree_client_impl.cc
@@ -113,11 +113,11 @@ next_change_id_(1), delegate_(delegate), window_manager_delegate_(window_manager_delegate), - root_(nullptr), focused_window_(nullptr), binding_(this), tree_(nullptr), is_embed_root_(false), + delete_on_no_roots_(true), in_destructor_(false) { // Allow for a null request in tests. if (request.is_pending()) @@ -149,7 +149,7 @@ } void WindowTreeClientImpl::WaitForEmbed() { - DCHECK(!root_); + DCHECK(roots_.empty()); // OnEmbed() is the first function called. binding_.WaitForIncomingMethodCall(); // TODO(sky): deal with pipe being closed before we get OnEmbed(). @@ -347,12 +347,9 @@ for (auto change_id : in_flight_change_ids_to_remove) in_flight_map_.erase(change_id); - if (window == root_) { - root_ = nullptr; - - // When the root is gone we can't do anything useful. - if (!in_destructor_) - delete this; + if (roots_.erase(window) > 0 && roots_.empty() && delete_on_no_roots_ && + !in_destructor_) { + delete this; } } @@ -396,12 +393,13 @@ is_embed_root_ = (access_policy & mojom::WindowTree::ACCESS_POLICY_EMBED_ROOT) != 0; - DCHECK(!root_); - root_ = AddWindowToConnection(this, nullptr, root_data); + DCHECK(roots_.empty()); + Window* root = AddWindowToConnection(this, nullptr, root_data); + roots_.insert(root); focused_window_ = GetWindowById(focused_window_id); - delegate_->OnEmbed(root_); + delegate_->OnEmbed(root); if (focused_window_) { FOR_EACH_OBSERVER(WindowTreeConnectionObserver, observers_, @@ -412,8 +410,12 @@ //////////////////////////////////////////////////////////////////////////////// // WindowTreeClientImpl, WindowTreeConnection implementation: -Window* WindowTreeClientImpl::GetRoot() { - return root_; +void WindowTreeClientImpl::SetDeleteOnNoRoots(bool value) { + delete_on_no_roots_ = value; +} + +const std::set<Window*>& WindowTreeClientImpl::GetRoots() { + return roots_; } Window* WindowTreeClientImpl::GetWindowById(Id id) { @@ -491,10 +493,13 @@ } } -void WindowTreeClientImpl::OnUnembed() { - delegate_->OnUnembed(); - // This will send out the various notifications. - delete this; +void WindowTreeClientImpl::OnUnembed(Id window_id) { + Window* window = GetWindowById(window_id); + if (!window) + return; + + delegate_->OnUnembed(window); + WindowPrivate(window).LocalDestroy(); } void WindowTreeClientImpl::OnWindowBoundsChanged(Id window_id, @@ -559,11 +564,14 @@ } void WindowTreeClientImpl::OnWindowViewportMetricsChanged( + mojo::Array<uint32_t> window_ids, mojom::ViewportMetricsPtr old_metrics, mojom::ViewportMetricsPtr new_metrics) { - Window* window = GetRoot(); - if (window) - SetViewportMetricsOnDecendants(window, *old_metrics, *new_metrics); + for (size_t i = 0; i < window_ids.size(); ++i) { + Window* window = GetWindowById(window_ids[i]); + if (window) + SetViewportMetricsOnDecendants(window, *old_metrics, *new_metrics); + } } void WindowTreeClientImpl::OnWindowHierarchyChanged( @@ -709,7 +717,7 @@ void WindowTreeClientImpl::RequestClose(uint32_t window_id) { Window* window = GetWindowById(window_id); - if (!window || window != root_) + if (!window || !IsRoot(window)) return; FOR_EACH_OBSERVER(WindowObserver, *WindowPrivate(window).observers(),
diff --git a/components/mus/public/cpp/lib/window_tree_client_impl.h b/components/mus/public/cpp/lib/window_tree_client_impl.h index ed96ef9..b595548 100644 --- a/components/mus/public/cpp/lib/window_tree_client_impl.h +++ b/components/mus/public/cpp/lib/window_tree_client_impl.h
@@ -8,6 +8,7 @@ #include <stdint.h> #include <map> +#include <set> #include "base/macros.h" #include "base/observer_list.h" @@ -104,6 +105,8 @@ // WindowTreeConnection::GetWindowById. void AddWindow(Window* window); + bool IsRoot(Window* window) const { return roots_.count(window) > 0; } + bool is_embed_root() const { return is_embed_root_; } // Called after the window's observers have been notified of destruction (as @@ -137,7 +140,8 @@ uint32_t access_policy); // Overridden from WindowTreeConnection: - Window* GetRoot() override; + void SetDeleteOnNoRoots(bool value) override; + const std::set<Window*>& GetRoots() override; Window* GetWindowById(Id id) override; Window* GetFocusedWindow() override; Window* NewWindow(const Window::SharedProperties* properties) override; @@ -153,7 +157,7 @@ Id focused_window_id, uint32_t access_policy) override; void OnEmbeddedAppDisconnected(Id window_id) override; - void OnUnembed() override; + void OnUnembed(Id window_id) override; void OnWindowBoundsChanged(Id window_id, mojo::RectPtr old_bounds, mojo::RectPtr new_bounds) override; @@ -166,6 +170,7 @@ void OnTransientWindowRemoved(uint32_t window_id, uint32_t transient_window_id) override; void OnWindowViewportMetricsChanged( + mojo::Array<uint32_t> window_ids, mojom::ViewportMetricsPtr old_metrics, mojom::ViewportMetricsPtr new_metrics) override; void OnWindowHierarchyChanged( @@ -218,7 +223,7 @@ WindowManagerDelegate* window_manager_delegate_; - Window* root_; + std::set<Window*> roots_; IdToWindowMap windows_; @@ -232,6 +237,8 @@ bool is_embed_root_; + bool delete_on_no_roots_; + bool in_destructor_; base::ObserverList<WindowTreeConnectionObserver> observers_;
diff --git a/components/mus/public/cpp/lib/window_tree_delegate.cc b/components/mus/public/cpp/lib/window_tree_delegate.cc index c9377ba..14192bd 100644 --- a/components/mus/public/cpp/lib/window_tree_delegate.cc +++ b/components/mus/public/cpp/lib/window_tree_delegate.cc
@@ -6,6 +6,6 @@ namespace mus { -void WindowTreeDelegate::OnUnembed() {} +void WindowTreeDelegate::OnUnembed(Window* root) {} } // namespace mus
diff --git a/components/mus/public/cpp/scoped_window_ptr.h b/components/mus/public/cpp/scoped_window_ptr.h index 3fffd353..b94e0f94 100644 --- a/components/mus/public/cpp/scoped_window_ptr.h +++ b/components/mus/public/cpp/scoped_window_ptr.h
@@ -17,8 +17,11 @@ explicit ScopedWindowPtr(Window* window); ~ScopedWindowPtr() override; - // Destroys |window|. If |window| is the root of the WindowManager than the + // Destroys |window|. If |window| is a root of the WindowManager than the // WindowManager is destroyed (which in turn destroys |window|). + // + // NOTE: this function (and class) are only useful for clients that only + // ever have a single root. static void DeleteWindowOrWindowManager(Window* window); Window* window() { return window_; }
diff --git a/components/mus/public/cpp/tests/window_tree_client_impl_unittest.cc b/components/mus/public/cpp/tests/window_tree_client_impl_unittest.cc index 608916e..d9c8dbca 100644 --- a/components/mus/public/cpp/tests/window_tree_client_impl_unittest.cc +++ b/components/mus/public/cpp/tests/window_tree_client_impl_unittest.cc
@@ -95,6 +95,12 @@ TestWindowTree* window_tree() { return &window_tree_; } + Window* GetFirstRoot() { + return window_tree_connection()->GetRoots().empty() + ? nullptr + : *window_tree_connection()->GetRoots().begin(); + } + private: TestWindowTree window_tree_; TestWindowTreeDelegate window_tree_delegate_; @@ -150,7 +156,7 @@ // Verifies bounds are reverted if the server replied that the change failed. TEST_F(WindowTreeClientImplTest, SetBoundsFailed) { WindowTreeSetup setup; - Window* root = setup.window_tree_connection()->GetRoot(); + Window* root = setup.GetFirstRoot(); ASSERT_TRUE(root); const gfx::Rect original_bounds(root->bounds()); const gfx::Rect new_bounds(gfx::Rect(0, 0, 100, 100)); @@ -166,7 +172,7 @@ // server replies with a new bounds and the original bounds change fails. TEST_F(WindowTreeClientImplTest, SetBoundsFailedWithPendingChange) { WindowTreeSetup setup; - Window* root = setup.window_tree_connection()->GetRoot(); + Window* root = setup.GetFirstRoot(); ASSERT_TRUE(root); const gfx::Rect original_bounds(root->bounds()); const gfx::Rect new_bounds(gfx::Rect(0, 0, 100, 100)); @@ -199,7 +205,7 @@ TEST_F(WindowTreeClientImplTest, TwoInFlightBoundsChangesBothCanceled) { WindowTreeSetup setup; - Window* root = setup.window_tree_connection()->GetRoot(); + Window* root = setup.GetFirstRoot(); ASSERT_TRUE(root); const gfx::Rect original_bounds(root->bounds()); const gfx::Rect bounds1(gfx::Rect(0, 0, 100, 100)); @@ -229,7 +235,7 @@ // failed. TEST_F(WindowTreeClientImplTest, SetPropertyFailed) { WindowTreeSetup setup; - Window* root = setup.window_tree_connection()->GetRoot(); + Window* root = setup.GetFirstRoot(); ASSERT_TRUE(root); ASSERT_FALSE(root->HasSharedProperty("foo")); const int32_t new_value = 11; @@ -246,7 +252,7 @@ // server replies with a new property and the original property change fails. TEST_F(WindowTreeClientImplTest, SetPropertyFailedWithPendingChange) { WindowTreeSetup setup; - Window* root = setup.window_tree_connection()->GetRoot(); + Window* root = setup.GetFirstRoot(); ASSERT_TRUE(root); const int32_t value1 = 11; root->SetSharedProperty("foo", value1); @@ -280,7 +286,7 @@ // Verifies visible is reverted if the server replied that the change failed. TEST_F(WindowTreeClientImplTest, SetVisibleFailed) { WindowTreeSetup setup; - Window* root = setup.window_tree_connection()->GetRoot(); + Window* root = setup.GetFirstRoot(); ASSERT_TRUE(root); const bool original_visible = root->visible(); const bool new_visible = !original_visible; @@ -296,7 +302,7 @@ // server replies with a new visible and the original visible change fails. TEST_F(WindowTreeClientImplTest, SetVisibleFailedWithPendingChange) { WindowTreeSetup setup; - Window* root = setup.window_tree_connection()->GetRoot(); + Window* root = setup.GetFirstRoot(); ASSERT_TRUE(root); const bool original_visible = root->visible(); const bool new_visible = !original_visible; @@ -327,7 +333,7 @@ TEST_F(WindowTreeClientImplTest, InputEventBasic) { WindowTreeSetup setup; - Window* root = setup.window_tree_connection()->GetRoot(); + Window* root = setup.GetFirstRoot(); ASSERT_TRUE(root); TestInputEventHandler event_handler; @@ -357,7 +363,7 @@ // Verifies focus is reverted if the server replied that the change failed. TEST_F(WindowTreeClientImplTest, SetFocusFailed) { WindowTreeSetup setup; - Window* root = setup.window_tree_connection()->GetRoot(); + Window* root = setup.GetFirstRoot(); ASSERT_TRUE(root); root->SetVisible(true); Window* child = setup.window_tree_connection()->NewWindow(); @@ -378,7 +384,7 @@ // replies with a new focus and the original focus change fails. TEST_F(WindowTreeClientImplTest, SetFocusFailedWithPendingChange) { WindowTreeSetup setup; - Window* root = setup.window_tree_connection()->GetRoot(); + Window* root = setup.GetFirstRoot(); ASSERT_TRUE(root); root->SetVisible(true); Window* child1 = setup.window_tree_connection()->NewWindow(); @@ -415,7 +421,7 @@ TEST_F(WindowTreeClientImplTest, FocusOnRemovedWindowWithInFlightFocusChange) { WindowTreeSetup setup; - Window* root = setup.window_tree_connection()->GetRoot(); + Window* root = setup.GetFirstRoot(); ASSERT_TRUE(root); root->SetVisible(true); Window* child1 = setup.window_tree_connection()->NewWindow(); @@ -471,7 +477,7 @@ TEST_F(WindowTreeClientImplTest, ToggleVisibilityFromWindowDestroyed) { WindowTreeSetup setup; - Window* root = setup.window_tree_connection()->GetRoot(); + Window* root = setup.GetFirstRoot(); ASSERT_TRUE(root); Window* child1 = setup.window_tree_connection()->NewWindow(); root->AddChild(child1);
diff --git a/components/mus/public/cpp/window.h b/components/mus/public/cpp/window.h index 796a71a1..53df7dba 100644 --- a/components/mus/public/cpp/window.h +++ b/components/mus/public/cpp/window.h
@@ -44,8 +44,7 @@ struct WindowProperty; // Windows are owned by the WindowTreeConnection. See WindowTreeDelegate for -// details -// on ownership. +// details on ownership. // // TODO(beng): Right now, you'll have to implement a WindowObserver to track // destruction and NULL any pointers you have. @@ -58,9 +57,9 @@ using SharedProperties = std::map<std::string, std::vector<uint8_t>>; // Destroys this window and all its children. Destruction is allowed for - // windows that were created by this connection, or the root window. For - // windows from other connections (except the root), Destroy() does nothing. - // If the destruction is allowed observers are notified and the Window is + // windows that were created by this connection, or the roots. For windows + // from other connections (except the roots), Destroy() does nothing. If the + // destruction is allowed observers are notified and the Window is // immediately deleted. void Destroy();
diff --git a/components/mus/public/cpp/window_tree_connection.h b/components/mus/public/cpp/window_tree_connection.h index 471843f1..322bd04 100644 --- a/components/mus/public/cpp/window_tree_connection.h +++ b/components/mus/public/cpp/window_tree_connection.h
@@ -49,8 +49,12 @@ CreateType create_type, WindowManagerDelegate* window_manager_delegate); + // Sets whether this is deleted when there are no roots. The default is to + // delete when there are no roots. + virtual void SetDeleteOnNoRoots(bool value) = 0; + // Returns the root of this connection. - virtual Window* GetRoot() = 0; + virtual const std::set<Window*>& GetRoots() = 0; // Returns a Window known to this connection. virtual Window* GetWindowById(Id id) = 0;
diff --git a/components/mus/public/cpp/window_tree_delegate.h b/components/mus/public/cpp/window_tree_delegate.h index 3e2f397..d75af40 100644 --- a/components/mus/public/cpp/window_tree_delegate.h +++ b/components/mus/public/cpp/window_tree_delegate.h
@@ -18,11 +18,11 @@ // Interface implemented by an application using the window manager. // -// Each call to OnEmbed() results in a new WindowTreeConnection and new root -// Window. // WindowTreeConnection is deleted by any of the following: -// . If the root of the connection is destroyed. This happens if the owner -// of the root Embed()s another app in root, or root is explicitly deleted. +// . If all the roots of the connection are destroyed and the connection is +// configured to delete when there are no roots (the default). This happens +// if the owner of the roots Embed()s another app in all the roots, or all +// the roots are explicitly deleted. // . The connection to the window manager is lost. // . Explicitly by way of calling delete. // @@ -35,10 +35,12 @@ // |root|. virtual void OnEmbed(Window* root) = 0; - // Sent when another app is embedded in the same Window as this connection. - // Subsequently the root Window and this object are destroyed (observers are - // notified appropriately). - virtual void OnUnembed(); + // Sent when another app is embedded in |root| (one of the roots of the + // connection). Afer this call |root| is deleted. If |root| is the only root + // and the connection is configured to delete when there are no roots (the + // default), then after |root| is destroyed the connection is destroyed as + // well. + virtual void OnUnembed(Window* root); // Called from the destructor of WindowTreeConnection after all the Windows // have been destroyed. |connection| is no longer valid after this call.
diff --git a/components/mus/public/interfaces/compositor_frame.mojom b/components/mus/public/interfaces/compositor_frame.mojom index 88d6f2f..38ab06f6 100644 --- a/components/mus/public/interfaces/compositor_frame.mojom +++ b/components/mus/public/interfaces/compositor_frame.mojom
@@ -71,8 +71,9 @@ uint32 filter; mojo.Size size; MailboxHolder mailbox_holder; - bool is_repeated; + bool read_lock_fences_enabled; bool is_software; + bool is_overlay_candidate; }; // See cc/output/compositor_frame_metadata.h.
diff --git a/components/mus/public/interfaces/gpu_capabilities.mojom b/components/mus/public/interfaces/gpu_capabilities.mojom index 5518583..d56b337a 100644 --- a/components/mus/public/interfaces/gpu_capabilities.mojom +++ b/components/mus/public/interfaces/gpu_capabilities.mojom
@@ -51,4 +51,5 @@ bool future_sync_points; bool blend_equation_advanced; bool blend_equation_advanced_coherent; + bool flips_vertically; };
diff --git a/components/mus/public/interfaces/window_tree.mojom b/components/mus/public/interfaces/window_tree.mojom index 644f9c4..6851107 100644 --- a/components/mus/public/interfaces/window_tree.mojom +++ b/components/mus/public/interfaces/window_tree.mojom
@@ -257,7 +257,7 @@ // Sent when another connection is embedded in the Window this connection was // previously embedded in. See Embed() for more information. - OnUnembed(); + OnUnembed(uint32 window); // Invoked when a window's bounds have changed. OnWindowBoundsChanged(uint32 window, @@ -274,9 +274,14 @@ OnTransientWindowRemoved(uint32 window_id, uint32 transient_window_id); - // Invoked when the viewport metrics for the window have changed. - // Clients are expected to propagate this to the window tree. - OnWindowViewportMetricsChanged(ViewportMetrics old_metrics, + // Invoked when the viewport metrics for the specified windows have changed. + // This is only sent for the roots, not for every window, it is expected + // clients propagate this to the tree. + // TODO(sky): rather than passing viewportmetrics like this, perhaps each + // window should know the display it is on, and the viewportmetrics of the + // display may change. + OnWindowViewportMetricsChanged(array<uint32> window_ids, + ViewportMetrics old_metrics, ViewportMetrics new_metrics); // Invoked when a change is done to the hierarchy. A value of 0 is used to
diff --git a/components/mus/surfaces/direct_output_surface.cc b/components/mus/surfaces/direct_output_surface.cc index 477c66e2..3ee0de5a 100644 --- a/components/mus/surfaces/direct_output_surface.cc +++ b/components/mus/surfaces/direct_output_surface.cc
@@ -21,6 +21,17 @@ DirectOutputSurface::~DirectOutputSurface() {} +bool DirectOutputSurface::BindToClient(cc::OutputSurfaceClient* client) { + if (!cc::OutputSurface::BindToClient(client)) + return false; + + if (capabilities_.uses_default_gl_framebuffer) { + capabilities_.flipped_output_surface = + context_provider()->ContextCapabilities().gpu.flips_vertically; + } + return true; +} + void DirectOutputSurface::SwapBuffers(cc::CompositorFrame* frame) { DCHECK(context_provider_); DCHECK(frame->gl_frame_data);
diff --git a/components/mus/surfaces/direct_output_surface.h b/components/mus/surfaces/direct_output_surface.h index f4be72712..b32d0cdd85 100644 --- a/components/mus/surfaces/direct_output_surface.h +++ b/components/mus/surfaces/direct_output_surface.h
@@ -18,6 +18,7 @@ ~DirectOutputSurface() override; // cc::OutputSurface implementation + bool BindToClient(cc::OutputSurfaceClient* client) override; void SwapBuffers(cc::CompositorFrame* frame) override; private:
diff --git a/components/mus/surfaces/surfaces_context_provider.cc b/components/mus/surfaces/surfaces_context_provider.cc index cf00579..000b248 100644 --- a/components/mus/surfaces/surfaces_context_provider.cc +++ b/components/mus/surfaces/surfaces_context_provider.cc
@@ -49,9 +49,9 @@ return false; gles2_helper_->SetAutomaticFlushes(false); transfer_buffer_.reset(new gpu::TransferBuffer(gles2_helper_.get())); - gpu::Capabilities capabilities = command_buffer_local_->GetCapabilities(); + capabilities_.gpu = command_buffer_local_->GetCapabilities(); bool bind_generates_resource = - !!capabilities.bind_generates_resource_chromium; + !!capabilities_.gpu.bind_generates_resource_chromium; // TODO(piman): Some contexts (such as compositor) want this to be true, so // this needs to be a public parameter. bool lose_context_when_out_of_memory = false;
diff --git a/components/mus/ws/access_policy_delegate.h b/components/mus/ws/access_policy_delegate.h index a24db84..39c32c7 100644 --- a/components/mus/ws/access_policy_delegate.h +++ b/components/mus/ws/access_policy_delegate.h
@@ -19,8 +19,8 @@ // Delegate used by the AccessPolicy implementations to get state. class AccessPolicyDelegate { public: - // Returns true if |id| is the root of the connection. - virtual bool IsRootForAccessPolicy(const WindowId& id) const = 0; + // Returns true if the connection has |window| as one of its roots. + virtual bool HasRootForAccessPolicy(const ServerWindow* window) const = 0; // Returns true if |window| has been exposed to the client. virtual bool IsWindowKnownForAccessPolicy(
diff --git a/components/mus/ws/connection_manager.cc b/components/mus/ws/connection_manager.cc index 9f14860..6733076 100644 --- a/components/mus/ws/connection_manager.cc +++ b/components/mus/ws/connection_manager.cc
@@ -79,14 +79,12 @@ } void ConnectionManager::OnConnectionError(ClientConnection* connection) { - // This will be null if the root has been destroyed. - const WindowId* window_id = connection->service()->root(); - ServerWindow* window = - window_id ? GetWindow(*connection->service()->root()) : nullptr; - // If the WindowTree root is a viewport root, then we'll wait until - // the root connection goes away to cleanup. - if (window && (GetRootWindow(window) == window)) - return; + for (auto* root : connection->service()->roots()) { + // If the WindowTree root is a viewport root, then we'll wait until + // the root connection goes away to cleanup. + if (GetRootWindow(root) == root) + return; + } scoped_ptr<ClientConnection> connection_owner(connection); @@ -96,10 +94,15 @@ for (auto& pair : connection_map_) pair.second->service()->OnWillDestroyWindowTreeImpl(connection->service()); - // Notify the host. - WindowTreeHostImpl* host = GetWindowTreeHostByWindow(window); - if (host) - host->OnWindowTreeConnectionError(connection->service()); + // Notify the hosts, taking care to only notify each host once. + std::set<WindowTreeHostImpl*> hosts_notified; + for (auto* root : connection->service()->roots()) { + WindowTreeHostImpl* host = GetWindowTreeHostByWindow(root); + if (host && hosts_notified.count(host) == 0) { + host->OnWindowTreeConnectionError(connection->service()); + hosts_notified.insert(host); + } + } // Remove any requests from the client that resulted in a call to the window // manager and we haven't gotten a response back yet. @@ -141,13 +144,13 @@ } WindowTreeImpl* ConnectionManager::EmbedAtWindow( - const WindowId& window_id, + ServerWindow* root, uint32_t policy_bitmask, mojom::WindowTreeClientPtr client) { mojom::WindowTreePtr service_ptr; ClientConnection* client_connection = delegate_->CreateClientConnectionForEmbedAtWindow( - this, GetProxy(&service_ptr), window_id, policy_bitmask, + this, GetProxy(&service_ptr), root, policy_bitmask, std::move(client)); AddConnection(client_connection); client_connection->service()->Init(client_connection->client(), @@ -214,9 +217,11 @@ } const WindowTreeImpl* ConnectionManager::GetConnectionWithRoot( - const WindowId& id) const { + const ServerWindow* window) const { + if (!window) + return nullptr; for (auto& pair : connection_map_) { - if (pair.second->service()->IsRoot(id)) + if (pair.second->service()->HasRoot(window)) return pair.second->service(); } return nullptr; @@ -240,20 +245,6 @@ return nullptr; } -WindowTreeImpl* ConnectionManager::GetEmbedRoot(WindowTreeImpl* service) { - while (service) { - const WindowId* root_id = service->root(); - if (!root_id || root_id->connection_id == service->id()) - return nullptr; - - WindowTreeImpl* parent_service = GetConnection(root_id->connection_id); - service = parent_service; - if (service && service->is_embed_root()) - return service; - } - return nullptr; -} - WindowTreeHostImpl* ConnectionManager::GetActiveWindowTreeHost() { return host_connection_map_.begin()->first; } @@ -269,18 +260,14 @@ void ConnectionManager::WindowManagerChangeCompleted( uint32_t window_manager_change_id, bool success) { - // There are valid reasons as to why we wouldn't know about the id. The - // most likely is the client disconnected before the response from the window - // manager came back. - auto iter = in_flight_wm_change_map_.find(window_manager_change_id); - if (iter == in_flight_wm_change_map_.end()) + InFlightWindowManagerChange change; + if (!GetAndClearInFlightWindowManagerChange(window_manager_change_id, + &change)) { return; - - const InFlightWindowManagerChange change = iter->second; - in_flight_wm_change_map_.erase(iter); + } WindowTreeImpl* connection = GetConnection(change.connection_id); - connection->client()->OnChangeCompleted(change.client_change_id, success); + connection->OnChangeCompleted(change.client_change_id, success); } void ConnectionManager::ProcessWindowBoundsChanged( @@ -340,7 +327,7 @@ } } -void ConnectionManager::ProcessWindowDeleted(const WindowId& window) { +void ConnectionManager::ProcessWindowDeleted(const ServerWindow* window) { for (auto& pair : connection_map_) { pair.second->service()->ProcessWindowDeleted(window, IsOperationSource(pair.first)); @@ -362,14 +349,30 @@ } void ConnectionManager::ProcessViewportMetricsChanged( + WindowTreeHostImpl* host, const mojom::ViewportMetrics& old_metrics, const mojom::ViewportMetrics& new_metrics) { for (auto& pair : connection_map_) { pair.second->service()->ProcessViewportMetricsChanged( - old_metrics, new_metrics, IsOperationSource(pair.first)); + host, old_metrics, new_metrics, IsOperationSource(pair.first)); } } +bool ConnectionManager::GetAndClearInFlightWindowManagerChange( + uint32_t window_manager_change_id, + InFlightWindowManagerChange* change) { + // There are valid reasons as to why we wouldn't know about the id. The + // most likely is the client disconnected before the response from the window + // manager came back. + auto iter = in_flight_wm_change_map_.find(window_manager_change_id); + if (iter == in_flight_wm_change_map_.end()) + return false; + + *change = iter->second; + in_flight_wm_change_map_.erase(iter); + return true; +} + void ConnectionManager::PrepareForOperation(Operation* op) { // Should only ever have one change in flight. CHECK(!current_operation_); @@ -420,7 +423,7 @@ void ConnectionManager::OnWindowDestroyed(ServerWindow* window) { if (!in_destructor_) - ProcessWindowDeleted(window->id()); + ProcessWindowDeleted(window); } void ConnectionManager::OnWillChangeWindowHierarchy(ServerWindow* window,
diff --git a/components/mus/ws/connection_manager.h b/components/mus/ws/connection_manager.h index 21e91ed..2f319b8 100644 --- a/components/mus/ws/connection_manager.h +++ b/components/mus/ws/connection_manager.h
@@ -70,7 +70,7 @@ // See description of WindowTree::Embed() for details. This assumes // |transport_window_id| is valid. - WindowTreeImpl* EmbedAtWindow(const WindowId& window_id, + WindowTreeImpl* EmbedAtWindow(ServerWindow* root, uint32_t policy_bitmask, mojom::WindowTreeClientPtr client); @@ -108,19 +108,17 @@ const ServerWindow* window); // Returns the WindowTreeImpl that has |id| as a root. - WindowTreeImpl* GetConnectionWithRoot(const WindowId& id) { + WindowTreeImpl* GetConnectionWithRoot(const ServerWindow* window) { return const_cast<WindowTreeImpl*>( - const_cast<const ConnectionManager*>(this)->GetConnectionWithRoot(id)); + const_cast<const ConnectionManager*>(this) + ->GetConnectionWithRoot(window)); } - const WindowTreeImpl* GetConnectionWithRoot(const WindowId& id) const; + const WindowTreeImpl* GetConnectionWithRoot(const ServerWindow* window) const; WindowTreeHostImpl* GetWindowTreeHostByWindow(const ServerWindow* window); const WindowTreeHostImpl* GetWindowTreeHostByWindow( const ServerWindow* window) const; - // Returns the first ancestor of |service| that is marked as an embed root. - WindowTreeImpl* GetEmbedRoot(WindowTreeImpl* service); - WindowTreeHostImpl* GetActiveWindowTreeHost(); bool has_tree_host_connections() const { @@ -150,7 +148,8 @@ const ServerWindow* window, const gfx::Insets& new_client_area, const std::vector<gfx::Rect>& new_additional_client_areas); - void ProcessViewportMetricsChanged(const mojom::ViewportMetrics& old_metrics, + void ProcessViewportMetricsChanged(WindowTreeHostImpl* host, + const mojom::ViewportMetrics& old_metrics, const mojom::ViewportMetrics& new_metrics); void ProcessWillChangeWindowHierarchy(const ServerWindow* window, const ServerWindow* new_parent, @@ -161,7 +160,7 @@ void ProcessWindowReorder(const ServerWindow* window, const ServerWindow* relative_window, const mojom::OrderDirection direction); - void ProcessWindowDeleted(const WindowId& window); + void ProcessWindowDeleted(const ServerWindow* window); void ProcessWillChangeWindowPredefinedCursor(ServerWindow* window, int32_t cursor_id); @@ -183,6 +182,10 @@ using InFlightWindowManagerChangeMap = std::map<uint32_t, InFlightWindowManagerChange>; + bool GetAndClearInFlightWindowManagerChange( + uint32_t window_manager_change_id, + InFlightWindowManagerChange* change); + // Invoked when a connection is about to execute a window server operation. // Subsequently followed by FinishOperation() once the change is done. //
diff --git a/components/mus/ws/connection_manager_delegate.h b/components/mus/ws/connection_manager_delegate.h index 56acda4..7e3d529 100644 --- a/components/mus/ws/connection_manager_delegate.h +++ b/components/mus/ws/connection_manager_delegate.h
@@ -19,7 +19,7 @@ class ClientConnection; class ConnectionManager; -struct WindowId; +class ServerWindow; class ConnectionManagerDelegate { public: @@ -32,7 +32,7 @@ virtual ClientConnection* CreateClientConnectionForEmbedAtWindow( ConnectionManager* connection_manager, mojo::InterfaceRequest<mojom::WindowTree> tree_request, - const WindowId& root_id, + ServerWindow* root, uint32_t policy_bitmask, mojom::WindowTreeClientPtr client) = 0;
diff --git a/components/mus/ws/default_access_policy.cc b/components/mus/ws/default_access_policy.cc index 9deb3da..fb012f82 100644 --- a/components/mus/ws/default_access_policy.cc +++ b/components/mus/ws/default_access_policy.cc
@@ -22,14 +22,14 @@ if (!WasCreatedByThisConnection(window)) return false; // Can only unparent windows we created. - return delegate_->IsRootForAccessPolicy(window->parent()->id()) || + return delegate_->HasRootForAccessPolicy(window->parent()) || WasCreatedByThisConnection(window->parent()); } bool DefaultAccessPolicy::CanAddWindow(const ServerWindow* parent, const ServerWindow* child) const { return WasCreatedByThisConnection(child) && - (delegate_->IsRootForAccessPolicy(parent->id()) || + (delegate_->HasRootForAccessPolicy(parent) || (WasCreatedByThisConnection(parent) && !delegate_->IsWindowRootOfAnotherConnectionForAccessPolicy(parent))); } @@ -38,7 +38,7 @@ const ServerWindow* parent, const ServerWindow* child) const { return WasCreatedByThisConnection(child) && - (delegate_->IsRootForAccessPolicy(parent->id()) || + (delegate_->HasRootForAccessPolicy(parent) || WasCreatedByThisConnection(parent)); } @@ -47,7 +47,7 @@ if (!WasCreatedByThisConnection(window)) return false; // Can only unparent windows we created. - return delegate_->IsRootForAccessPolicy(window->transient_parent()->id()) || + return delegate_->HasRootForAccessPolicy(window->transient_parent()) || WasCreatedByThisConnection(window->transient_parent()); } @@ -65,7 +65,7 @@ bool DefaultAccessPolicy::CanGetWindowTree(const ServerWindow* window) const { return WasCreatedByThisConnection(window) || - delegate_->IsRootForAccessPolicy(window->id()) || + delegate_->HasRootForAccessPolicy(window) || IsDescendantOfEmbedRoot(window); } @@ -73,7 +73,7 @@ const ServerWindow* window) const { return (WasCreatedByThisConnection(window) && !delegate_->IsWindowRootOfAnotherConnectionForAccessPolicy(window)) || - delegate_->IsRootForAccessPolicy(window->id()) || + delegate_->HasRootForAccessPolicy(window) || delegate_->IsDescendantOfEmbedRoot(window); } @@ -84,13 +84,13 @@ return WasCreatedByThisConnection(window) || (delegate_->IsWindowKnownForAccessPolicy(window) && IsDescendantOfEmbedRoot(window) && - !delegate_->IsRootForAccessPolicy(window->id())); + !delegate_->HasRootForAccessPolicy(window)); } bool DefaultAccessPolicy::CanChangeWindowVisibility( const ServerWindow* window) const { return WasCreatedByThisConnection(window) || - delegate_->IsRootForAccessPolicy(window->id()); + delegate_->HasRootForAccessPolicy(window); } bool DefaultAccessPolicy::CanSetWindowSurface( @@ -105,7 +105,7 @@ if (delegate_->IsWindowRootOfAnotherConnectionForAccessPolicy(window)) return false; return WasCreatedByThisConnection(window) || - delegate_->IsRootForAccessPolicy(window->id()); + delegate_->HasRootForAccessPolicy(window); } bool DefaultAccessPolicy::CanSetWindowBounds(const ServerWindow* window) const { @@ -120,23 +120,23 @@ bool DefaultAccessPolicy::CanSetWindowTextInputState( const ServerWindow* window) const { return WasCreatedByThisConnection(window) || - delegate_->IsRootForAccessPolicy(window->id()); + delegate_->HasRootForAccessPolicy(window); } bool DefaultAccessPolicy::CanSetFocus(const ServerWindow* window) const { return WasCreatedByThisConnection(window) || - delegate_->IsRootForAccessPolicy(window->id()); + delegate_->HasRootForAccessPolicy(window); } bool DefaultAccessPolicy::CanSetClientArea(const ServerWindow* window) const { return WasCreatedByThisConnection(window) || - delegate_->IsRootForAccessPolicy(window->id()); + delegate_->HasRootForAccessPolicy(window); } bool DefaultAccessPolicy::CanSetCursorProperties( const ServerWindow* window) const { return WasCreatedByThisConnection(window) || - delegate_->IsRootForAccessPolicy(window->id()); + delegate_->HasRootForAccessPolicy(window); } bool DefaultAccessPolicy::ShouldNotifyOnHierarchyChange( @@ -150,13 +150,13 @@ } if (*new_parent && !WasCreatedByThisConnection(*new_parent) && - !delegate_->IsRootForAccessPolicy((*new_parent)->id()) && + !delegate_->HasRootForAccessPolicy((*new_parent)) && !delegate_->IsDescendantOfEmbedRoot(*new_parent)) { *new_parent = nullptr; } if (*old_parent && !WasCreatedByThisConnection(*old_parent) && - !delegate_->IsRootForAccessPolicy((*old_parent)->id()) && + !delegate_->HasRootForAccessPolicy((*old_parent)) && !delegate_->IsDescendantOfEmbedRoot(*new_parent)) { *old_parent = nullptr; } @@ -166,7 +166,7 @@ const ServerWindow* DefaultAccessPolicy::GetWindowForFocusChange( const ServerWindow* focused) { if (WasCreatedByThisConnection(focused) || - delegate_->IsRootForAccessPolicy(focused->id())) + delegate_->HasRootForAccessPolicy(focused)) return focused; return nullptr; }
diff --git a/components/mus/ws/test_change_tracker.cc b/components/mus/ws/test_change_tracker.cc index 0b090e5a..3eb2317e 100644 --- a/components/mus/ws/test_change_tracker.cc +++ b/components/mus/ws/test_change_tracker.cc
@@ -44,7 +44,8 @@ WindowIdToString(change.window_id).c_str()); case CHANGE_TYPE_UNEMBED: - return "OnUnembed"; + return base::StringPrintf("OnUnembed window=%s", + WindowIdToString(change.window_id).c_str()); case CHANGE_TYPE_NODE_ADD_TRANSIENT_WINDOW: return base::StringPrintf("AddTransientWindow parent = %s child = %s", @@ -106,10 +107,6 @@ change.property_key.c_str(), change.property_value.c_str()); - case CHANGE_TYPE_DELEGATE_EMBED: - return base::StringPrintf("DelegateEmbed url=%s", - change.embed_url.data()); - case CHANGE_TYPE_FOCUSED: return base::StringPrintf("Focused id=%s", WindowIdToString(change.window_id).c_str()); @@ -118,6 +115,10 @@ return base::StringPrintf("CursorChanged id=%s cursor_id=%d", WindowIdToString(change.window_id).c_str(), change.cursor_id); + case CHANGE_TYPE_ON_CHANGE_COMPLETED: + return base::StringPrintf("ChangeCompleted id=%d sucess=%s", + change.change_id, + change.bool_value ? "true" : "false"); } return std::string(); } @@ -182,7 +183,8 @@ window_id3(0), event_action(0), direction(mojom::ORDER_DIRECTION_ABOVE), - bool_value(false) {} + bool_value(false), + change_id(0u) {} Change::~Change() {} @@ -223,9 +225,10 @@ AddChange(change); } -void TestChangeTracker::OnUnembed() { +void TestChangeTracker::OnUnembed(Id window_id) { Change change; change.type = CHANGE_TYPE_UNEMBED; + change.window_id = window_id; AddChange(change); } @@ -344,10 +347,11 @@ AddChange(change); } -void TestChangeTracker::DelegateEmbed(const String& url) { +void TestChangeTracker::OnChangeCompleted(uint32_t change_id, bool success) { Change change; - change.type = CHANGE_TYPE_DELEGATE_EMBED; - change.embed_url = url; + change.type = CHANGE_TYPE_ON_CHANGE_COMPLETED; + change.change_id = change_id; + change.bool_value = success; AddChange(change); }
diff --git a/components/mus/ws/test_change_tracker.h b/components/mus/ws/test_change_tracker.h index b25ae45..da506e3 100644 --- a/components/mus/ws/test_change_tracker.h +++ b/components/mus/ws/test_change_tracker.h
@@ -36,9 +36,9 @@ CHANGE_TYPE_NODE_DELETED, CHANGE_TYPE_INPUT_EVENT, CHANGE_TYPE_PROPERTY_CHANGED, - CHANGE_TYPE_DELEGATE_EMBED, CHANGE_TYPE_FOCUSED, - CHANGE_TYPE_CURSOR_CHANGED + CHANGE_TYPE_CURSOR_CHANGED, + CHANGE_TYPE_ON_CHANGE_COMPLETED, }; // TODO(sky): consider nuking and converting directly to WindowData. @@ -80,6 +80,7 @@ std::string property_key; std::string property_value; int32_t cursor_id; + uint32_t change_id; }; // Converts Changes to string descriptions. @@ -127,7 +128,7 @@ // WindowTreeClient function. void OnEmbed(ConnectionSpecificId connection_id, mojom::WindowDataPtr root); void OnEmbeddedAppDisconnected(Id window_id); - void OnUnembed(); + void OnUnembed(Id window_id); void OnTransientWindowAdded(Id window_id, Id transient_window_id); void OnTransientWindowRemoved(Id window_id, Id transient_window_id); void OnWindowBoundsChanged(Id window_id, @@ -151,7 +152,7 @@ mojo::Array<uint8_t> data); void OnWindowFocused(Id window_id); void OnWindowPredefinedCursorChanged(Id window_id, mojom::Cursor cursor_id); - void DelegateEmbed(const mojo::String& url); + void OnChangeCompleted(uint32_t change_id, bool success); private: void AddChange(const Change& change);
diff --git a/components/mus/ws/window_manager_access_policy.cc b/components/mus/ws/window_manager_access_policy.cc index f53bfbbf..65ac9c1 100644 --- a/components/mus/ws/window_manager_access_policy.cc +++ b/components/mus/ws/window_manager_access_policy.cc
@@ -66,7 +66,7 @@ bool WindowManagerAccessPolicy::CanEmbed(const ServerWindow* window, uint32_t policy_bitmask) const { - return !delegate_->IsRootForAccessPolicy(window->id()); + return !delegate_->HasRootForAccessPolicy(window); } bool WindowManagerAccessPolicy::CanChangeWindowVisibility( @@ -85,7 +85,7 @@ if (delegate_->IsWindowRootOfAnotherConnectionForAccessPolicy(window)) return false; return window->id().connection_id == connection_id_ || - (delegate_->IsRootForAccessPolicy(window->id())); + (delegate_->HasRootForAccessPolicy(window)); } bool WindowManagerAccessPolicy::CanSetWindowBounds( @@ -110,13 +110,13 @@ bool WindowManagerAccessPolicy::CanSetClientArea( const ServerWindow* window) const { return window->id().connection_id == connection_id_ || - delegate_->IsRootForAccessPolicy(window->id()); + delegate_->HasRootForAccessPolicy(window); } bool WindowManagerAccessPolicy::CanSetCursorProperties( const ServerWindow* window) const { return window->id().connection_id == connection_id_ || - delegate_->IsRootForAccessPolicy(window->id()); + delegate_->HasRootForAccessPolicy(window); } bool WindowManagerAccessPolicy::ShouldNotifyOnHierarchyChange(
diff --git a/components/mus/ws/window_manager_client_apptest.cc b/components/mus/ws/window_manager_client_apptest.cc index 205fd92e..2d58027 100644 --- a/components/mus/ws/window_manager_client_apptest.cc +++ b/components/mus/ws/window_manager_client_apptest.cc
@@ -23,7 +23,6 @@ #include "ui/mojo/geometry/geometry_util.h" namespace mus { - namespace ws { namespace { @@ -204,6 +203,11 @@ ConnectionSpecificId connection_id; }; +Window* GetFirstRoot(WindowTreeConnection* connection) { + return connection->GetRoots().empty() ? nullptr + : *connection->GetRoots().begin(); +} + // These tests model synchronization of two peer connections to the window // manager // service, that are given access to some root window. @@ -212,6 +216,8 @@ public: WindowServerTest() {} + Window* GetFirstWMRoot() { return GetFirstRoot(window_manager()); } + Window* NewVisibleWindow(Window* parent, WindowTreeConnection* connection) { Window* window = connection->NewWindow(); window->SetVisible(true); @@ -305,18 +311,18 @@ TEST_F(WindowServerTest, RootWindow) { ASSERT_NE(nullptr, window_manager()); - EXPECT_NE(nullptr, window_manager()->GetRoot()); + EXPECT_EQ(1u, window_manager()->GetRoots().size()); } TEST_F(WindowServerTest, Embed) { Window* window = window_manager()->NewWindow(); ASSERT_NE(nullptr, window); window->SetVisible(true); - window_manager()->GetRoot()->AddChild(window); + GetFirstWMRoot()->AddChild(window); WindowTreeConnection* embedded = Embed(window).connection; ASSERT_NE(nullptr, embedded); - Window* window_in_embedded = embedded->GetRoot(); + Window* window_in_embedded = GetFirstRoot(embedded); ASSERT_NE(nullptr, window_in_embedded); EXPECT_EQ(window->id(), window_in_embedded->id()); EXPECT_EQ(nullptr, window_in_embedded->parent()); @@ -329,7 +335,7 @@ Window* window = window_manager()->NewWindow(); ASSERT_NE(nullptr, window); window->SetVisible(true); - window_manager()->GetRoot()->AddChild(window); + GetFirstWMRoot()->AddChild(window); Window* nested = window_manager()->NewWindow(); ASSERT_NE(nullptr, nested); nested->SetVisible(true); @@ -337,7 +343,7 @@ WindowTreeConnection* embedded = Embed(window).connection; ASSERT_NE(nullptr, embedded); - Window* window_in_embedded = embedded->GetRoot(); + Window* window_in_embedded = GetFirstRoot(embedded); EXPECT_EQ(window->id(), window_in_embedded->id()); EXPECT_EQ(nullptr, window_in_embedded->parent()); EXPECT_TRUE(window_in_embedded->children().empty()); @@ -360,7 +366,7 @@ TEST_F(WindowServerTest, SetBounds) { Window* window = window_manager()->NewWindow(); window->SetVisible(true); - window_manager()->GetRoot()->AddChild(window); + GetFirstWMRoot()->AddChild(window); WindowTreeConnection* embedded = Embed(window).connection; ASSERT_NE(nullptr, embedded); @@ -377,7 +383,7 @@ TEST_F(WindowServerTest, SetBoundsSecurity) { Window* window = window_manager()->NewWindow(); window->SetVisible(true); - window_manager()->GetRoot()->AddChild(window); + GetFirstWMRoot()->AddChild(window); WindowTreeConnection* embedded = Embed(window).connection; ASSERT_NE(nullptr, embedded); @@ -399,7 +405,7 @@ TEST_F(WindowServerTest, DestroySecurity) { Window* window = window_manager()->NewWindow(); window->SetVisible(true); - window_manager()->GetRoot()->AddChild(window); + GetFirstWMRoot()->AddChild(window); WindowTreeConnection* embedded = Embed(window).connection; ASSERT_NE(nullptr, embedded); @@ -420,10 +426,10 @@ TEST_F(WindowServerTest, MultiRoots) { Window* window1 = window_manager()->NewWindow(); window1->SetVisible(true); - window_manager()->GetRoot()->AddChild(window1); + GetFirstWMRoot()->AddChild(window1); Window* window2 = window_manager()->NewWindow(); window2->SetVisible(true); - window_manager()->GetRoot()->AddChild(window2); + GetFirstWMRoot()->AddChild(window2); WindowTreeConnection* embedded1 = Embed(window1).connection; ASSERT_NE(nullptr, embedded1); WindowTreeConnection* embedded2 = Embed(window2).connection; @@ -434,20 +440,20 @@ TEST_F(WindowServerTest, Reorder) { Window* window1 = window_manager()->NewWindow(); window1->SetVisible(true); - window_manager()->GetRoot()->AddChild(window1); + GetFirstWMRoot()->AddChild(window1); WindowTreeConnection* embedded = Embed(window1).connection; ASSERT_NE(nullptr, embedded); Window* window11 = embedded->NewWindow(); window11->SetVisible(true); - embedded->GetRoot()->AddChild(window11); + GetFirstRoot(embedded)->AddChild(window11); Window* window12 = embedded->NewWindow(); window12->SetVisible(true); - embedded->GetRoot()->AddChild(window12); + GetFirstRoot(embedded)->AddChild(window12); ASSERT_TRUE(WaitForTreeSizeToMatch(window1, 3u)); - Window* root_in_embedded = embedded->GetRoot(); + Window* root_in_embedded = GetFirstRoot(embedded); { window11->MoveToFront(); @@ -516,13 +522,13 @@ TEST_F(WindowServerTest, Visible) { Window* window1 = window_manager()->NewWindow(); window1->SetVisible(true); - window_manager()->GetRoot()->AddChild(window1); + GetFirstWMRoot()->AddChild(window1); // Embed another app and verify initial state. WindowTreeConnection* embedded = Embed(window1).connection; ASSERT_NE(nullptr, embedded); - ASSERT_NE(nullptr, embedded->GetRoot()); - Window* embedded_root = embedded->GetRoot(); + ASSERT_NE(nullptr, GetFirstRoot(embedded)); + Window* embedded_root = GetFirstRoot(embedded); EXPECT_TRUE(embedded_root->visible()); EXPECT_TRUE(embedded_root->IsDrawn()); @@ -580,13 +586,13 @@ TEST_F(WindowServerTest, Drawn) { Window* window1 = window_manager()->NewWindow(); window1->SetVisible(true); - window_manager()->GetRoot()->AddChild(window1); + GetFirstWMRoot()->AddChild(window1); // Embed another app and verify initial state. WindowTreeConnection* embedded = Embed(window1).connection; ASSERT_NE(nullptr, embedded); - ASSERT_NE(nullptr, embedded->GetRoot()); - Window* embedded_root = embedded->GetRoot(); + ASSERT_NE(nullptr, GetFirstRoot(embedded)); + Window* embedded_root = GetFirstRoot(embedded); EXPECT_TRUE(embedded_root->visible()); EXPECT_TRUE(embedded_root->IsDrawn()); @@ -594,7 +600,7 @@ // change to |embedded|. { DrawnChangeObserver observer(embedded_root); - window_manager()->GetRoot()->SetVisible(false); + GetFirstWMRoot()->SetVisible(false); ASSERT_TRUE(DoRunLoopWithTimeout()); } @@ -686,17 +692,17 @@ TEST_F(WindowServerTest, Focus) { Window* window1 = window_manager()->NewWindow(); window1->SetVisible(true); - window_manager()->GetRoot()->AddChild(window1); + GetFirstWMRoot()->AddChild(window1); WindowTreeConnection* embedded = Embed(window1).connection; ASSERT_NE(nullptr, embedded); Window* window11 = embedded->NewWindow(); window11->SetVisible(true); - embedded->GetRoot()->AddChild(window11); + GetFirstRoot(embedded)->AddChild(window11); { // Focus the embed root in |embedded|. - Window* embedded_root = embedded->GetRoot(); + Window* embedded_root = GetFirstRoot(embedded); FocusChangeObserver observer(embedded_root); observer.set_quit_on_change(false); embedded_root->SetFocus(); @@ -709,7 +715,7 @@ ASSERT_TRUE(WaitForWindowToHaveFocus(window1)); } - // Focus a child of embedded->GetRoot(). + // Focus a child of GetFirstRoot(embedded). { FocusChangeObserver observer(window11); observer.set_quit_on_change(false); @@ -718,7 +724,7 @@ ASSERT_NE(nullptr, observer.last_gained_focus()); ASSERT_NE(nullptr, observer.last_lost_focus()); EXPECT_EQ(window11->id(), observer.last_gained_focus()->id()); - EXPECT_EQ(embedded->GetRoot()->id(), observer.last_lost_focus()->id()); + EXPECT_EQ(GetFirstRoot(embedded)->id(), observer.last_lost_focus()->id()); } { @@ -726,17 +732,16 @@ // observer sees the right values. FocusChangeObserver observer(window11); observer.set_quit_on_change(false); - embedded->GetRoot()->SetFocus(); + GetFirstRoot(embedded)->SetFocus(); ASSERT_NE(nullptr, observer.last_gained_focus()); ASSERT_NE(nullptr, observer.last_lost_focus()); EXPECT_EQ(window11->id(), observer.last_lost_focus()->id()); - EXPECT_EQ(embedded->GetRoot()->id(), observer.last_gained_focus()->id()); + EXPECT_EQ(GetFirstRoot(embedded)->id(), observer.last_gained_focus()->id()); } } TEST_F(WindowServerTest, Activation) { - Window* parent = - NewVisibleWindow(window_manager()->GetRoot(), window_manager()); + Window* parent = NewVisibleWindow(GetFirstWMRoot(), window_manager()); Window* child1 = NewVisibleWindow(parent, window_manager()); Window* child2 = NewVisibleWindow(parent, window_manager()); Window* child3 = NewVisibleWindow(parent, window_manager()); @@ -748,8 +753,8 @@ WindowTreeConnection* embedded2 = Embed(child2).connection; ASSERT_NE(nullptr, embedded2); - Window* child11 = NewVisibleWindow(embedded1->GetRoot(), embedded1); - Window* child21 = NewVisibleWindow(embedded2->GetRoot(), embedded2); + Window* child11 = NewVisibleWindow(GetFirstRoot(embedded1), embedded1); + Window* child21 = NewVisibleWindow(GetFirstRoot(embedded2), embedded2); WaitForTreeSizeToMatch(parent, 6); @@ -794,7 +799,7 @@ } TEST_F(WindowServerTest, ActivationNext) { - Window* parent = window_manager()->GetRoot(); + Window* parent = GetFirstWMRoot(); Window* child1 = NewVisibleWindow(parent, window_manager()); Window* child2 = NewVisibleWindow(parent, window_manager()); Window* child3 = NewVisibleWindow(parent, window_manager()); @@ -806,9 +811,9 @@ WindowTreeConnection* embedded3 = Embed(child3).connection; ASSERT_NE(nullptr, embedded3); - Window* child11 = NewVisibleWindow(embedded1->GetRoot(), embedded1); - Window* child21 = NewVisibleWindow(embedded2->GetRoot(), embedded2); - Window* child31 = NewVisibleWindow(embedded3->GetRoot(), embedded3); + Window* child11 = NewVisibleWindow(GetFirstRoot(embedded1), embedded1); + Window* child21 = NewVisibleWindow(GetFirstRoot(embedded2), embedded2); + Window* child31 = NewVisibleWindow(GetFirstRoot(embedded3), embedded3); WaitForTreeSizeToMatch(parent, 7); Window* expecteds[] = { child1, child2, child3, child1, nullptr }; @@ -864,11 +869,12 @@ Window* window = window_manager()->NewWindow(); ASSERT_NE(nullptr, window); window->SetVisible(true); - window_manager()->GetRoot()->AddChild(window); + GetFirstWMRoot()->AddChild(window); WindowTreeConnection* connection = Embed(window).connection; ASSERT_TRUE(connection); bool got_destroy = false; - DestroyedChangedObserver observer(this, connection->GetRoot(), &got_destroy); + DestroyedChangedObserver observer(this, GetFirstRoot(connection), + &got_destroy); delete connection; EXPECT_TRUE(window_tree_connection_destroyed()); EXPECT_TRUE(got_destroy); @@ -880,7 +886,7 @@ Window* window = window_manager()->NewWindow(); ASSERT_NE(nullptr, window); window->SetVisible(true); - window_manager()->GetRoot()->AddChild(window); + GetFirstWMRoot()->AddChild(window); WindowTreeConnection* connection = Embed(window).connection; EXPECT_NE(connection, window_manager()); Window* embedded_window = connection->NewWindow(); @@ -918,7 +924,7 @@ TEST_F(WindowServerTest, EmbedRemovesChildren) { Window* window1 = window_manager()->NewWindow(); Window* window2 = window_manager()->NewWindow(); - window_manager()->GetRoot()->AddChild(window1); + GetFirstWMRoot()->AddChild(window1); window1->AddChild(window2); WindowRemovedFromParentObserver observer(window2); @@ -941,7 +947,7 @@ WindowTreeConnection* connection, bool* got_destroy) : test_(test), got_destroy_(got_destroy) { - connection->GetRoot()->AddObserver(this); + GetFirstRoot(connection)->AddObserver(this); } ~DestroyObserver() override {} @@ -971,7 +977,7 @@ // OnWindowManagerDestroyed()). TEST_F(WindowServerTest, WindowServerDestroyedAfterRootObserver) { Window* embed_window = window_manager()->NewWindow(); - window_manager()->GetRoot()->AddChild(embed_window); + GetFirstWMRoot()->AddChild(embed_window); WindowTreeConnection* embedded_connection = Embed(embed_window).connection; @@ -988,17 +994,17 @@ // connection. TEST_F(WindowServerTest, EmbedRootSeesHierarchyChanged) { Window* embed_window = window_manager()->NewWindow(); - window_manager()->GetRoot()->AddChild(embed_window); + GetFirstWMRoot()->AddChild(embed_window); WindowTreeConnection* vm2 = Embed(embed_window, mus::mojom::WindowTree::ACCESS_POLICY_EMBED_ROOT) .connection; Window* vm2_v1 = vm2->NewWindow(); - vm2->GetRoot()->AddChild(vm2_v1); + GetFirstRoot(vm2)->AddChild(vm2_v1); WindowTreeConnection* vm3 = Embed(vm2_v1).connection; Window* vm3_v1 = vm3->NewWindow(); - vm3->GetRoot()->AddChild(vm3_v1); + GetFirstRoot(vm3)->AddChild(vm3_v1); // As |vm2| is an embed root it should get notified about |vm3_v1|. ASSERT_TRUE(WaitForTreeSizeToMatch(vm2_v1, 2)); @@ -1006,7 +1012,7 @@ TEST_F(WindowServerTest, EmbedFromEmbedRoot) { Window* embed_window = window_manager()->NewWindow(); - window_manager()->GetRoot()->AddChild(embed_window); + GetFirstWMRoot()->AddChild(embed_window); // Give the connection embedded at |embed_window| embed root powers. const EmbedResult result1 = @@ -1014,13 +1020,13 @@ WindowTreeConnection* vm2 = result1.connection; EXPECT_EQ(result1.connection_id, vm2->GetConnectionId()); Window* vm2_v1 = vm2->NewWindow(); - vm2->GetRoot()->AddChild(vm2_v1); + GetFirstRoot(vm2)->AddChild(vm2_v1); const EmbedResult result2 = Embed(vm2_v1); WindowTreeConnection* vm3 = result2.connection; EXPECT_EQ(result2.connection_id, vm3->GetConnectionId()); Window* vm3_v1 = vm3->NewWindow(); - vm3->GetRoot()->AddChild(vm3_v1); + GetFirstRoot(vm3)->AddChild(vm3_v1); // Embed from v3, the callback should not get the connection id as vm3 is not // an embed root. @@ -1042,24 +1048,23 @@ TEST_F(WindowServerTest, ClientAreaChanged) { Window* embed_window = window_manager()->NewWindow(); - window_manager()->GetRoot()->AddChild(embed_window); + GetFirstWMRoot()->AddChild(embed_window); WindowTreeConnection* embedded_connection = Embed(embed_window).connection; // Verify change from embedded makes it to parent. - embedded_connection->GetRoot()->SetClientArea(gfx::Insets(1, 2, 3, 4)); + GetFirstRoot(embedded_connection)->SetClientArea(gfx::Insets(1, 2, 3, 4)); ASSERT_TRUE(WaitForClientAreaToChange(embed_window)); EXPECT_TRUE(gfx::Insets(1, 2, 3, 4) == embed_window->client_area()); // Changing bounds shouldn't effect client area. embed_window->SetBounds(gfx::Rect(21, 22, 23, 24)); - WaitForBoundsToChange(embedded_connection->GetRoot()); + WaitForBoundsToChange(GetFirstRoot(embedded_connection)); EXPECT_TRUE(gfx::Rect(21, 22, 23, 24) == - embedded_connection->GetRoot()->bounds()); + GetFirstRoot(embedded_connection)->bounds()); EXPECT_TRUE(gfx::Insets(1, 2, 3, 4) == - embedded_connection->GetRoot()->client_area()); + GetFirstRoot(embedded_connection)->client_area()); } } // namespace ws - } // namespace mus
diff --git a/components/mus/ws/window_tree_apptest.cc b/components/mus/ws/window_tree_apptest.cc index a70805353..ec1ead7 100644 --- a/components/mus/ws/window_tree_apptest.cc +++ b/components/mus/ws/window_tree_apptest.cc
@@ -283,7 +283,7 @@ void OnEmbeddedAppDisconnected(Id window_id) override { tracker()->OnEmbeddedAppDisconnected(window_id); } - void OnUnembed() override { tracker()->OnUnembed(); } + void OnUnembed(Id window_id) override { tracker()->OnUnembed(window_id); } void OnWindowBoundsChanged(Id window_id, RectPtr old_bounds, RectPtr new_bounds) override { @@ -307,7 +307,8 @@ uint32_t transient_window_id) override { tracker()->OnTransientWindowRemoved(window_id, transient_window_id); } - void OnWindowViewportMetricsChanged(ViewportMetricsPtr old_metrics, + void OnWindowViewportMetricsChanged(mojo::Array<uint32_t> window_ids, + ViewportMetricsPtr old_metrics, ViewportMetricsPtr new_metrics) override { // Don't track the metrics as they are available at an indeterministic time // on Android. @@ -1251,7 +1252,8 @@ // Connection2 should have been told of the unembed and delete. { ws_client2_->WaitForChangeCount(2); - EXPECT_EQ("OnUnembed", ChangesToDescription1(*changes2())[0]); + EXPECT_EQ("OnUnembed window=" + IdToString(window_1_1), + ChangesToDescription1(*changes2())[0]); EXPECT_EQ("WindowDeleted window=" + IdToString(window_1_1), ChangesToDescription1(*changes2())[1]); } @@ -1301,7 +1303,8 @@ // And 3 should get an unembed and delete. ws_client3_->WaitForChangeCount(2); - EXPECT_EQ("OnUnembed", ChangesToDescription1(*changes3())[0]); + EXPECT_EQ("OnUnembed window=" + IdToString(window_1_1), + ChangesToDescription1(*changes3())[0]); EXPECT_EQ("WindowDeleted window=" + IdToString(window_1_1), ChangesToDescription1(*changes3())[1]); }
diff --git a/components/mus/ws/window_tree_host_connection.cc b/components/mus/ws/window_tree_host_connection.cc index 6f78af3d..31691034 100644 --- a/components/mus/ws/window_tree_host_connection.cc +++ b/components/mus/ws/window_tree_host_connection.cc
@@ -38,7 +38,7 @@ delete this; } -WindowTreeImpl* WindowTreeHostConnection::GetWindowTree() { +const WindowTreeImpl* WindowTreeHostConnection::GetWindowTree() const { return tree_; } @@ -62,7 +62,7 @@ void WindowTreeHostConnectionImpl::OnDisplayInitialized() { connection_manager()->AddHost(this); set_window_tree(connection_manager()->EmbedAtWindow( - window_tree_host()->root_window()->id(), + window_tree_host()->root_window(), mojom::WindowTree::ACCESS_POLICY_EMBED_ROOT, std::move(client_))); }
diff --git a/components/mus/ws/window_tree_host_connection.h b/components/mus/ws/window_tree_host_connection.h index 24d0f00..452a5f068 100644 --- a/components/mus/ws/window_tree_host_connection.h +++ b/components/mus/ws/window_tree_host_connection.h
@@ -49,7 +49,7 @@ // WindowTreeHostDelegate: void OnDisplayInitialized() override; void OnDisplayClosed() override; - WindowTreeImpl* GetWindowTree() override; + const WindowTreeImpl* GetWindowTree() const override; private: scoped_ptr<WindowTreeHostImpl> host_;
diff --git a/components/mus/ws/window_tree_host_delegate.h b/components/mus/ws/window_tree_host_delegate.h index a13faa14..84eec7a 100644 --- a/components/mus/ws/window_tree_host_delegate.h +++ b/components/mus/ws/window_tree_host_delegate.h
@@ -26,7 +26,11 @@ virtual void OnDisplayClosed() = 0; // Returns the WindowTreeImpl associated with the delegate. - virtual WindowTreeImpl* GetWindowTree() = 0; + virtual const WindowTreeImpl* GetWindowTree() const = 0; + WindowTreeImpl* GetWindowTree() { + return const_cast<WindowTreeImpl*>( + const_cast<const WindowTreeHostDelegate*>(this)->GetWindowTree()); + } protected: virtual ~WindowTreeHostDelegate() {}
diff --git a/components/mus/ws/window_tree_host_impl.cc b/components/mus/ws/window_tree_host_impl.cc index 7478ab3e..1bca0c58 100644 --- a/components/mus/ws/window_tree_host_impl.cc +++ b/components/mus/ws/window_tree_host_impl.cc
@@ -88,6 +88,10 @@ delegate_->OnDisplayInitialized(); } +const WindowTreeImpl* WindowTreeHostImpl::GetWindowTree() const { + return delegate_ ? delegate_->GetWindowTree() : nullptr; +} + WindowTreeImpl* WindowTreeHostImpl::GetWindowTree() { return delegate_ ? delegate_->GetWindowTree() : nullptr; } @@ -196,16 +200,16 @@ event_dispatcher_.RemoveAccelerator(id); } -void WindowTreeHostImpl::AddActivationParent(uint32_t window_id) { - ServerWindow* window = - connection_manager_->GetWindow(WindowIdFromTransportId(window_id)); +void WindowTreeHostImpl::AddActivationParent(Id transport_window_id) { + ServerWindow* window = connection_manager_->GetWindow( + MapWindowIdFromClient(transport_window_id)); if (window) activation_parents_.insert(window->id()); } -void WindowTreeHostImpl::RemoveActivationParent(uint32_t window_id) { - ServerWindow* window = - connection_manager_->GetWindow(WindowIdFromTransportId(window_id)); +void WindowTreeHostImpl::RemoveActivationParent(Id transport_window_id) { + ServerWindow* window = connection_manager_->GetWindow( + MapWindowIdFromClient(transport_window_id)); if (window) activation_parents_.erase(window->id()); } @@ -228,6 +232,13 @@ window->set_extended_hit_test_region(hit_area.To<gfx::Insets>()); } +WindowId WindowTreeHostImpl::MapWindowIdFromClient( + Id transport_window_id) const { + const WindowTreeImpl* connection = GetWindowTree(); + return connection ? connection->MapWindowIdFromClient(transport_window_id) + : WindowIdFromTransportId(transport_window_id); +} + void WindowTreeHostImpl::OnClientClosed() { // |display_manager_.reset()| destroys the display-manager first, and then // sets |display_manager_| to nullptr. However, destroying |display_manager_| @@ -312,7 +323,8 @@ } else { root_->SetBounds(gfx::Rect(new_metrics.size_in_pixels.To<gfx::Size>())); } - connection_manager_->ProcessViewportMetricsChanged(old_metrics, new_metrics); + connection_manager_->ProcessViewportMetricsChanged(this, old_metrics, + new_metrics); } void WindowTreeHostImpl::OnTopLevelSurfaceChanged(cc::SurfaceId surface_id) { @@ -364,7 +376,7 @@ new_focused_window); } embedded_connection_old = - connection_manager_->GetConnectionWithRoot(old_focused_window->id()); + connection_manager_->GetConnectionWithRoot(old_focused_window); if (embedded_connection_old) { DCHECK_NE(owning_connection_old, embedded_connection_old); embedded_connection_old->ProcessFocusChanged(old_focused_window, @@ -383,7 +395,7 @@ new_focused_window); } embedded_connection_new = - connection_manager_->GetConnectionWithRoot(new_focused_window->id()); + connection_manager_->GetConnectionWithRoot(new_focused_window); if (embedded_connection_new && embedded_connection_new != owning_connection_old && embedded_connection_new != embedded_connection_old) { @@ -438,7 +450,7 @@ WindowTreeImpl* connection = in_nonclient_area ? connection_manager_->GetConnection(target->id().connection_id) - : connection_manager_->GetConnectionWithRoot(target->id()); + : connection_manager_->GetConnectionWithRoot(target); if (!connection) { DCHECK(!in_nonclient_area); connection = connection_manager_->GetConnection(target->id().connection_id);
diff --git a/components/mus/ws/window_tree_host_impl.h b/components/mus/ws/window_tree_host_impl.h index 84e9ed4..9b0f02d 100644 --- a/components/mus/ws/window_tree_host_impl.h +++ b/components/mus/ws/window_tree_host_impl.h
@@ -56,6 +56,7 @@ // Initializes state that depends on the existence of a WindowTreeHostImpl. void Init(WindowTreeHostDelegate* delegate); + const WindowTreeImpl* GetWindowTree() const; WindowTreeImpl* GetWindowTree(); mojom::WindowTreeHostClient* client() const { return client_.get(); } @@ -115,8 +116,8 @@ mojom::EventMatcherPtr event_matcher, const AddAcceleratorCallback& callback) override; void RemoveAccelerator(uint32_t id) override; - void AddActivationParent(uint32_t window_id) override; - void RemoveActivationParent(uint32_t window_id) override; + void AddActivationParent(Id transport_window_id) override; + void RemoveActivationParent(Id transport_window_id) override; void ActivateNextWindow() override; void SetUnderlaySurfaceOffsetAndExtendedHitArea( Id window_id, @@ -129,6 +130,8 @@ private: friend class WindowTreeTest; + WindowId MapWindowIdFromClient(Id transport_window_id) const; + void OnClientClosed(); void OnEventAckTimeout(); void DispatchNextEventFromQueue();
diff --git a/components/mus/ws/window_tree_impl.cc b/components/mus/ws/window_tree_impl.cc index 34665c29..2d6611f 100644 --- a/components/mus/ws/window_tree_impl.cc +++ b/components/mus/ws/window_tree_impl.cc
@@ -32,7 +32,6 @@ using mojo::String; namespace mus { - namespace ws { class TargetedEvent : public ServerWindowObserver { @@ -64,18 +63,18 @@ }; WindowTreeImpl::WindowTreeImpl(ConnectionManager* connection_manager, - const WindowId& root_id, + ServerWindow* root, uint32_t policy_bitmask) : connection_manager_(connection_manager), id_(connection_manager_->GetAndAdvanceNextConnectionId()), client_(nullptr), event_ack_id_(0), + event_source_host_(nullptr), is_embed_root_(false), window_manager_internal_(nullptr) { - ServerWindow* window = GetWindow(root_id); - CHECK(window); - root_.reset(new WindowId(root_id)); - if (window->GetRoot() == window) { + CHECK(root); + roots_.insert(root); + if (root->GetRoot() == root) { access_policy_.reset(new WindowManagerAccessPolicy(id_, this)); is_embed_root_ = true; } else { @@ -94,17 +93,15 @@ DCHECK(!client_); client_ = client; std::vector<const ServerWindow*> to_send; - if (root_.get()) - GetUnknownWindowsFrom(GetWindow(*root_), &to_send); + CHECK_EQ(1u, roots_.size()); + GetUnknownWindowsFrom(*roots_.begin(), &to_send); - // TODO(beng): verify that host can actually be nullptr here. - WindowTreeHostImpl* host = GetHost(); + WindowTreeHostImpl* host = GetHost(*roots_.begin()); const ServerWindow* focused_window = host ? host->GetFocusedWindow() : nullptr; if (focused_window) focused_window = access_policy_->GetWindowForFocusChange(focused_window); - const Id focused_window_transport_id(WindowIdToTransportId( - focused_window ? focused_window->id() : WindowId())); + const Id focused_window_transport_id(MapWindowIdToClient(focused_window)); client->OnEmbed(id_, WindowToWindowData(to_send.front()), std::move(tree), focused_window_transport_id, @@ -120,25 +117,27 @@ return connection_manager_->GetWindow(id); } -bool WindowTreeImpl::IsRoot(const WindowId& id) const { - return root_.get() && *root_ == id; +bool WindowTreeImpl::HasRoot(const ServerWindow* window) const { + return roots_.count(window) > 0; } -WindowTreeHostImpl* WindowTreeImpl::GetHost() const { - return root_.get() - ? connection_manager_->GetWindowTreeHostByWindow(GetWindow(*root_)) - : nullptr; +const WindowTreeHostImpl* WindowTreeImpl::GetHost( + const ServerWindow* window) const { + return window ? connection_manager_->GetWindowTreeHostByWindow(window) + : nullptr; } void WindowTreeImpl::OnWillDestroyWindowTreeImpl(WindowTreeImpl* connection) { - const ServerWindow* connection_root = - connection->root_ ? connection->GetWindow(*connection->root_) : nullptr; - if (connection_root && - ((connection_root->id().connection_id == id_ && - window_map_.count(connection_root->id().window_id) > 0) || - (is_embed_root_ && IsWindowKnown(connection_root)))) { - client()->OnEmbeddedAppDisconnected( - WindowIdToTransportId(*connection->root_)); + // Notify our client if |connection| was embedded in any of our views. + for (const auto* connection_root : connection->roots_) { + const bool owns_connection_root = + connection_root->id().connection_id == id_; + const bool knows_about_connection_root = + window_map_.count(connection_root->id().window_id) > 0; + if ((owns_connection_root && knows_about_connection_root) || + (is_embed_root_ && IsWindowKnown(connection_root))) { + client_->OnEmbeddedAppDisconnected(MapWindowIdToClient(connection_root)); + } } } @@ -152,9 +151,7 @@ bool WindowTreeImpl::NewWindow( const WindowId& window_id, const std::map<std::string, std::vector<uint8_t>>& properties) { - if (window_id.connection_id != id_) - return false; - if (window_map_.find(window_id.window_id) != window_map_.end()) + if (!IsValidIdForNewWindow(window_id)) return false; window_map_[window_id.window_id] = connection_manager_->CreateServerWindow(window_id, properties); @@ -164,8 +161,8 @@ bool WindowTreeImpl::AddWindow(const WindowId& parent_id, const WindowId& child_id) { - ServerWindow* parent = GetWindow(parent_id); - ServerWindow* child = GetWindow(child_id); + ServerWindow* parent = GetWindow(MapWindowIdFromClient(parent_id)); + ServerWindow* child = GetWindow(MapWindowIdFromClient(child_id)); if (parent && child && child->parent() != parent && !child->Contains(parent) && access_policy_->CanAddWindow(parent, child)) { Operation op(this, connection_manager_, OperationType::ADD_WINDOW); @@ -177,8 +174,9 @@ bool WindowTreeImpl::AddTransientWindow(const WindowId& window_id, const WindowId& transient_window_id) { - ServerWindow* window = GetWindow(window_id); - ServerWindow* transient_window = GetWindow(transient_window_id); + ServerWindow* window = GetWindow(MapWindowIdFromClient(window_id)); + ServerWindow* transient_window = + GetWindow(MapWindowIdFromClient(transient_window_id)); if (window && transient_window && !transient_window->Contains(window) && access_policy_->CanAddTransientWindow(window, transient_window)) { Operation op(this, connection_manager_, @@ -200,7 +198,7 @@ bool WindowTreeImpl::SetWindowVisibility(const WindowId& window_id, bool visible) { - ServerWindow* window = GetWindow(window_id); + ServerWindow* window = GetWindow(MapWindowIdFromClient(window_id)); if (!window || window->visible() == visible || !access_policy_->CanChangeWindowVisibility(window)) { return false; @@ -215,11 +213,11 @@ uint32_t policy_bitmask, ConnectionSpecificId* connection_id) { *connection_id = kInvalidConnectionId; - if (!client.get() || !CanEmbed(window_id, policy_bitmask)) + if (!client || !CanEmbed(window_id, policy_bitmask)) return false; PrepareForEmbed(window_id); WindowTreeImpl* new_connection = connection_manager_->EmbedAtWindow( - window_id, policy_bitmask, std::move(client)); + GetWindow(window_id), policy_bitmask, std::move(client)); if (is_embed_root_) *connection_id = new_connection->id(); return true; @@ -248,15 +246,31 @@ DispatchInputEventImpl(target, std::move(event)); } +WindowId WindowTreeImpl::MapWindowIdFromClient(const WindowId& id) const { + return id; +} + +Id WindowTreeImpl::MapWindowIdToClient(const ServerWindow* window) const { + return MapWindowIdToClient(window ? window->id() : WindowId()); +} + +Id WindowTreeImpl::MapWindowIdToClient(const WindowId& id) const { + return WindowIdToTransportId(id); +} + +void WindowTreeImpl::OnChangeCompleted(uint32_t change_id, bool success) { + client_->OnChangeCompleted(change_id, success); +} + void WindowTreeImpl::ProcessWindowBoundsChanged(const ServerWindow* window, const gfx::Rect& old_bounds, const gfx::Rect& new_bounds, bool originated_change) { if (originated_change || !IsWindowKnown(window)) return; - client()->OnWindowBoundsChanged(WindowIdToTransportId(window->id()), - Rect::From(old_bounds), - Rect::From(new_bounds)); + client_->OnWindowBoundsChanged(MapWindowIdToClient(window), + Rect::From(old_bounds), + Rect::From(new_bounds)); } void WindowTreeImpl::ProcessClientAreaChanged( @@ -266,17 +280,26 @@ bool originated_change) { if (originated_change || !IsWindowKnown(window)) return; - client()->OnClientAreaChanged( - WindowIdToTransportId(window->id()), mojo::Insets::From(new_client_area), + client_->OnClientAreaChanged( + MapWindowIdToClient(window), mojo::Insets::From(new_client_area), mojo::Array<mojo::RectPtr>::From(new_additional_client_areas)); } void WindowTreeImpl::ProcessViewportMetricsChanged( + WindowTreeHostImpl* host, const mojom::ViewportMetrics& old_metrics, const mojom::ViewportMetrics& new_metrics, bool originated_change) { - client()->OnWindowViewportMetricsChanged(old_metrics.Clone(), - new_metrics.Clone()); + mojo::Array<Id> window_ids; + for (const ServerWindow* root : roots_) { + if (GetHost(root) == host) + window_ids.push_back(MapWindowIdToClient(root->id())); + } + if (window_ids.size() == 0u) + return; + + client_->OnWindowViewportMetricsChanged( + std::move(window_ids), old_metrics.Clone(), new_metrics.Clone()); } void WindowTreeImpl::ProcessWillChangeWindowHierarchy( @@ -308,8 +331,8 @@ if (new_data) data = Array<uint8_t>::From(*new_data); - client()->OnWindowSharedPropertyChanged(WindowIdToTransportId(window->id()), - String(name), std::move(data)); + client_->OnWindowSharedPropertyChanged(MapWindowIdToClient(window), + String(name), std::move(data)); } void WindowTreeImpl::ProcessWindowHierarchyChanged( @@ -340,9 +363,9 @@ GetUnknownWindowsFrom(window, &to_send); const WindowId new_parent_id(new_parent ? new_parent->id() : WindowId()); const WindowId old_parent_id(old_parent ? old_parent->id() : WindowId()); - client()->OnWindowHierarchyChanged( - WindowIdToTransportId(window->id()), WindowIdToTransportId(new_parent_id), - WindowIdToTransportId(old_parent_id), WindowsToWindowDatas(to_send)); + client_->OnWindowHierarchyChanged( + MapWindowIdToClient(window), MapWindowIdToClient(new_parent_id), + MapWindowIdToClient(old_parent_id), WindowsToWindowDatas(to_send)); connection_manager_->OnConnectionMessagedClient(id_); } @@ -355,27 +378,29 @@ connection_manager_->DidConnectionMessageClient(id_)) return; - client()->OnWindowReordered(WindowIdToTransportId(window->id()), - WindowIdToTransportId(relative_window->id()), - direction); + client_->OnWindowReordered(MapWindowIdToClient(window), + MapWindowIdToClient(relative_window), direction); connection_manager_->OnConnectionMessagedClient(id_); } -void WindowTreeImpl::ProcessWindowDeleted(const WindowId& window, +void WindowTreeImpl::ProcessWindowDeleted(const ServerWindow* window, bool originated_change) { - if (window.connection_id == id_) - window_map_.erase(window.window_id); + if (window->id().connection_id == id_) + window_map_.erase(window->id().window_id); - const bool in_known = known_windows_.erase(WindowIdToTransportId(window)) > 0; + const Id transport_id = MapWindowIdToClient(window); - if (IsRoot(window)) - root_.reset(); + const bool in_known = + known_windows_.erase(WindowIdToTransportId(window->id())) > 0; + + if (HasRoot(window)) + RemoveRoot(window, RemoveRootReason::DELETED); if (originated_change) return; if (in_known) { - client()->OnWindowDeleted(WindowIdToTransportId(window)); + client_->OnWindowDeleted(transport_id); connection_manager_->OnConnectionMessagedClient(id_); } } @@ -387,8 +412,8 @@ return; if (IsWindowKnown(window)) { - client()->OnWindowVisibilityChanged(WindowIdToTransportId(window->id()), - !window->visible()); + client_->OnWindowVisibilityChanged(MapWindowIdToClient(window), + !window->visible()); return; } @@ -409,8 +434,8 @@ bool originated_change) { if (originated_change) return; - client()->OnWindowPredefinedCursorChanged(WindowIdToTransportId(window->id()), - mojom::Cursor(cursor_id)); + client_->OnWindowPredefinedCursorChanged(MapWindowIdToClient(window), + mojom::Cursor(cursor_id)); } void WindowTreeImpl::ProcessFocusChanged( @@ -420,8 +445,8 @@ new_focused_window ? access_policy_->GetWindowForFocusChange(new_focused_window) : nullptr; - client()->OnWindowFocused(window ? WindowIdToTransportId(window->id()) - : WindowIdToTransportId(WindowId())); + client_->OnWindowFocused(window ? MapWindowIdToClient(window) + : MapWindowIdToClient(WindowId())); } void WindowTreeImpl::ProcessTransientWindowAdded( @@ -430,9 +455,8 @@ bool originated_change) { if (originated_change) return; - client()->OnTransientWindowAdded( - WindowIdToTransportId(window->id()), - WindowIdToTransportId(transient_window->id())); + client_->OnTransientWindowAdded(MapWindowIdToClient(window), + MapWindowIdToClient(transient_window)); } void WindowTreeImpl::ProcessTransientWindowRemoved( @@ -441,9 +465,21 @@ bool originated_change) { if (originated_change) return; - client()->OnTransientWindowRemoved( - WindowIdToTransportId(window->id()), - WindowIdToTransportId(transient_window->id())); + client_->OnTransientWindowRemoved(MapWindowIdToClient(window), + MapWindowIdToClient(transient_window)); +} + +WindowTreeHostImpl* WindowTreeImpl::GetHostForWindowManager() { + // The WindowTreeImpl for the wm has one and only one root. + CHECK_EQ(1u, roots_.size()); + + // Indicates this connection is for the wm. + DCHECK(window_manager_internal_); + + WindowTreeHostImpl* host = GetHost(*roots_.begin()); + CHECK(host); + DCHECK_EQ(this, host->GetWindowTree()); + return host; } bool WindowTreeImpl::ShouldRouteToWindowManager( @@ -451,15 +487,16 @@ // If the client created this window, then do not route it through the WM. if (window->id().connection_id == id_) return false; + // If the client did not create the window, then it must be the root of the // client. If not, that means the client should not know about this window, // and so do not route the request to the WM. - if (!root_ || *root_ != window->id()) + if (roots_.count(window) == 0) return false; // The WindowManager is attached to the root of the WindowTreeHost, if there // isn't a WindowManager attached no need to route to it. - WindowTreeHostImpl* host = GetHost(); + const WindowTreeHostImpl* host = GetHost(window); if (!host || !host->GetWindowTree() || !host->GetWindowTree()->window_manager_internal_) { return false; @@ -474,6 +511,10 @@ return known_windows_.count(WindowIdToTransportId(window->id())) > 0; } +bool WindowTreeImpl::IsValidIdForNewWindow(const WindowId& id) const { + return id.connection_id == id_ && window_map_.count(id.window_id) == 0; +} + bool WindowTreeImpl::CanReorderWindow(const ServerWindow* window, const ServerWindow* relative_window, mojom::OrderDirection direction) const { @@ -537,22 +578,26 @@ RemoveFromKnown(children[i], local_windows); } -void WindowTreeImpl::RemoveRoot() { - CHECK(root_.get()); - const WindowId root_id(*root_); - root_.reset(); +void WindowTreeImpl::RemoveRoot(const ServerWindow* window, + RemoveRootReason reason) { + DCHECK(roots_.count(window) > 0); + roots_.erase(window); + const Id transport_id = MapWindowIdToClient(window); + // No need to do anything if we created the window. - if (root_id.connection_id == id_) + if (window->id().connection_id == id_) return; - client()->OnUnembed(); - client()->OnWindowDeleted(WindowIdToTransportId(root_id)); - connection_manager_->OnConnectionMessagedClient(id_); + if (reason == RemoveRootReason::EMBED) { + client_->OnUnembed(transport_id); + client_->OnWindowDeleted(transport_id); + connection_manager_->OnConnectionMessagedClient(id_); + } // This connection no longer knows about the window. Unparent any windows that // were parented to windows in the root. std::vector<ServerWindow*> local_windows; - RemoveFromKnown(GetWindow(root_id), &local_windows); + RemoveFromKnown(window, &local_windows); for (size_t i = 0; i < local_windows.size(); ++i) local_windows[i]->parent()->Remove(local_windows[i]); } @@ -574,9 +619,8 @@ if (parent && !IsWindowKnown(parent)) parent = NULL; mojom::WindowDataPtr window_data(mojom::WindowData::New()); - window_data->parent_id = - WindowIdToTransportId(parent ? parent->id() : WindowId()); - window_data->window_id = WindowIdToTransportId(window->id()); + window_data->parent_id = MapWindowIdToClient(parent); + window_data->window_id = MapWindowIdToClient(window); window_data->bounds = Rect::From(window->bounds()); window_data->properties = mojo::Map<String, Array<uint8_t>>::From(window->properties()); @@ -609,14 +653,14 @@ bool new_drawn_value) { // Even though we don't know about window, it may be an ancestor of our root, // in which case the change may effect our roots drawn state. - if (!root_.get()) + if (roots_.empty()) return; - const ServerWindow* root = GetWindow(*root_); - DCHECK(root); - if (window->Contains(root) && (new_drawn_value != root->IsDrawn())) { - client()->OnWindowDrawnStateChanged(WindowIdToTransportId(root->id()), - new_drawn_value); + for (auto* root : roots_) { + if (window->Contains(root) && (new_drawn_value != root->IsDrawn())) { + client_->OnWindowDrawnStateChanged(MapWindowIdToClient(root), + new_drawn_value); + } } } @@ -652,14 +696,14 @@ // Only allow a node to be the root for one connection. WindowTreeImpl* existing_owner = - connection_manager_->GetConnectionWithRoot(window_id); + connection_manager_->GetConnectionWithRoot(window); Operation op(this, connection_manager_, OperationType::EMBED); RemoveChildrenAsPartOfEmbed(window_id); if (existing_owner) { // Never message the originating connection. connection_manager_->OnConnectionMessagedClient(id_); - existing_owner->RemoveRoot(); + existing_owner->RemoveRoot(window, RemoveRootReason::EMBED); } } @@ -680,8 +724,11 @@ // the event pointer. event_ack_id_ = 0x1000000 | (reinterpret_cast<uintptr_t>(event.get()) & 0xffffff); - client()->OnWindowInputEvent( - event_ack_id_, WindowIdToTransportId(target->id()), std::move(event)); + event_source_host_ = GetHost(target); + // Should only get events from windows attached to a host. + DCHECK(event_source_host_); + client_->OnWindowInputEvent(event_ack_id_, MapWindowIdToClient(target), + std::move(event)); } void WindowTreeImpl::NewWindow( @@ -695,12 +742,11 @@ } client_->OnChangeCompleted( change_id, - NewWindow(WindowIdFromTransportId(transport_window_id), properties)); + NewWindow(MapWindowIdFromClient(transport_window_id), properties)); } void WindowTreeImpl::DeleteWindow(uint32_t change_id, Id transport_window_id) { - ServerWindow* window = - GetWindow(WindowIdFromTransportId(transport_window_id)); + ServerWindow* window = GetWindow(MapWindowIdFromClient(transport_window_id)); bool success = false; bool should_close = window && (access_policy_->CanDeleteWindow(window) || ShouldRouteToWindowManager(window)); @@ -714,13 +760,13 @@ void WindowTreeImpl::AddWindow(uint32_t change_id, Id parent_id, Id child_id) { client_->OnChangeCompleted(change_id, - AddWindow(WindowIdFromTransportId(parent_id), - WindowIdFromTransportId(child_id))); + AddWindow(MapWindowIdFromClient(parent_id), + MapWindowIdFromClient(child_id))); } void WindowTreeImpl::RemoveWindowFromParent(uint32_t change_id, Id window_id) { bool success = false; - ServerWindow* window = GetWindow(WindowIdFromTransportId(window_id)); + ServerWindow* window = GetWindow(MapWindowIdFromClient(window_id)); if (window && window->parent() && access_policy_->CanRemoveWindowFromParent(window)) { success = true; @@ -735,15 +781,15 @@ Id window, Id transient_window) { client_->OnChangeCompleted( - change_id, AddTransientWindow(WindowIdFromTransportId(window), - WindowIdFromTransportId(transient_window))); + change_id, AddTransientWindow(MapWindowIdFromClient(window), + MapWindowIdFromClient(transient_window))); } void WindowTreeImpl::RemoveTransientWindowFromParent(uint32_t change_id, Id transient_window_id) { bool success = false; ServerWindow* transient_window = - GetWindow(WindowIdFromTransportId(transient_window_id)); + GetWindow(MapWindowIdFromClient(transient_window_id)); if (transient_window->transient_parent() && access_policy_->CanRemoveTransientWindowFromParent(transient_window)) { success = true; @@ -760,9 +806,9 @@ Id relative_window_id, mojom::OrderDirection direction) { bool success = false; - ServerWindow* window = GetWindow(WindowIdFromTransportId(window_id)); + ServerWindow* window = GetWindow(MapWindowIdFromClient(window_id)); ServerWindow* relative_window = - GetWindow(WindowIdFromTransportId(relative_window_id)); + GetWindow(MapWindowIdFromClient(relative_window_id)); if (CanReorderWindow(window, relative_window, direction)) { success = true; Operation op(this, connection_manager_, OperationType::REORDER_WINDOW); @@ -777,19 +823,21 @@ Id window_id, const Callback<void(Array<mojom::WindowDataPtr>)>& callback) { std::vector<const ServerWindow*> windows( - GetWindowTree(WindowIdFromTransportId(window_id))); + GetWindowTree(MapWindowIdFromClient(window_id))); callback.Run(WindowsToWindowDatas(windows)); } void WindowTreeImpl::SetWindowBounds(uint32_t change_id, Id window_id, mojo::RectPtr bounds) { - ServerWindow* window = GetWindow(WindowIdFromTransportId(window_id)); + ServerWindow* window = GetWindow(MapWindowIdFromClient(window_id)); if (window && ShouldRouteToWindowManager(window)) { const uint32_t wm_change_id = connection_manager_->GenerateWindowManagerChangeId(this, change_id); - GetHost()->GetWindowTree()->window_manager_internal_->WmSetBounds( - wm_change_id, window_id, std::move(bounds)); + // |window_id| may be a client id, use the id from the window to ensure + // the windowmanager doesn't get an id it doesn't know about. + GetHost(window)->GetWindowTree()->window_manager_internal_->WmSetBounds( + wm_change_id, WindowIdToTransportId(window->id()), std::move(bounds)); return; } @@ -806,20 +854,21 @@ Id transport_window_id, bool visible) { client_->OnChangeCompleted( - change_id, SetWindowVisibility( - WindowIdFromTransportId(transport_window_id), visible)); + change_id, + SetWindowVisibility(MapWindowIdFromClient(transport_window_id), visible)); } void WindowTreeImpl::SetWindowProperty(uint32_t change_id, - uint32_t window_id, + Id transport_window_id, const mojo::String& name, mojo::Array<uint8_t> value) { - ServerWindow* window = GetWindow(WindowIdFromTransportId(window_id)); + ServerWindow* window = GetWindow(MapWindowIdFromClient(transport_window_id)); if (window && ShouldRouteToWindowManager(window)) { const uint32_t wm_change_id = connection_manager_->GenerateWindowManagerChangeId(this, change_id); - GetHost()->GetWindowTree()->window_manager_internal_->WmSetProperty( - wm_change_id, window_id, name, std::move(value)); + GetHost(window)->GetWindowTree()->window_manager_internal_->WmSetProperty( + wm_change_id, WindowIdToTransportId(window->id()), name, + std::move(value)); return; } const bool success = window && access_policy_->CanSetWindowProperties(window); @@ -836,11 +885,11 @@ } void WindowTreeImpl::AttachSurface( - Id window_id, + Id transport_window_id, mojom::SurfaceType type, mojo::InterfaceRequest<mojom::Surface> surface, mojom::SurfaceClientPtr client) { - ServerWindow* window = GetWindow(WindowIdFromTransportId(window_id)); + ServerWindow* window = GetWindow(MapWindowIdFromClient(transport_window_id)); const bool success = window && access_policy_->CanSetWindowSurface(window, type); if (!success) @@ -848,9 +897,9 @@ window->CreateSurface(type, std::move(surface), std::move(client)); } -void WindowTreeImpl::SetWindowTextInputState(Id window_id, +void WindowTreeImpl::SetWindowTextInputState(Id transport_window_id, mojo::TextInputStatePtr state) { - ServerWindow* window = GetWindow(WindowIdFromTransportId(window_id)); + ServerWindow* window = GetWindow(MapWindowIdFromClient(transport_window_id)); bool success = window && access_policy_->CanSetWindowTextInputState(window); if (success) window->SetTextInputState(state.To<ui::TextInputState>()); @@ -859,14 +908,13 @@ void WindowTreeImpl::SetImeVisibility(Id transport_window_id, bool visible, mojo::TextInputStatePtr state) { - ServerWindow* window = - GetWindow(WindowIdFromTransportId(transport_window_id)); + ServerWindow* window = GetWindow(MapWindowIdFromClient(transport_window_id)); bool success = window && access_policy_->CanSetWindowTextInputState(window); if (success) { if (!state.is_null()) window->SetTextInputState(state.To<ui::TextInputState>()); - WindowTreeHostImpl* host = GetHost(); + WindowTreeHostImpl* host = GetHost(window); if (host) host->SetImeVisibility(window, visible); } @@ -878,7 +926,11 @@ NOTIMPLEMENTED() << "Wrong event acked."; } event_ack_id_ = 0; - GetHost()->OnEventAck(this); + + WindowTreeHostImpl* event_source_host = event_source_host_; + event_source_host_ = nullptr; + if (event_source_host) + event_source_host->OnEventAck(this); if (!event_queue_.empty()) { DCHECK(!event_ack_id_); @@ -890,7 +942,7 @@ event_queue_.pop(); target = targeted_event->target(); event = targeted_event->event(); - } while (!event_queue_.empty() && !target); + } while (!event_queue_.empty() && !GetHost(target)); if (target) DispatchInputEventImpl(target, std::move(event)); } @@ -900,8 +952,7 @@ Id transport_window_id, mojo::InsetsPtr insets, mojo::Array<mojo::RectPtr> transport_additional_client_areas) { - ServerWindow* window = - GetWindow(WindowIdFromTransportId(transport_window_id)); + ServerWindow* window = GetWindow(MapWindowIdFromClient(transport_window_id)); if (!window || !access_policy_->CanSetClientArea(window)) return; @@ -915,16 +966,18 @@ uint32_t policy_bitmask, const EmbedCallback& callback) { ConnectionSpecificId connection_id = kInvalidConnectionId; - const bool result = Embed(WindowIdFromTransportId(transport_window_id), + const bool result = Embed(MapWindowIdFromClient(transport_window_id), std::move(client), policy_bitmask, &connection_id); callback.Run(result, connection_id); } -void WindowTreeImpl::SetFocus(uint32_t change_id, Id window_id) { - ServerWindow* window = GetWindow(WindowIdFromTransportId(window_id)); +void WindowTreeImpl::SetFocus(uint32_t change_id, Id transport_window_id) { + ServerWindow* window = GetWindow(MapWindowIdFromClient(transport_window_id)); // TODO(beng): consider shifting non-policy drawn check logic to VTH's // FocusController. - WindowTreeHostImpl* host = GetHost(); + // TODO(sky): this doesn't work to clear focus. That is because if window is + // null, then |host| is null and we fail. + WindowTreeHostImpl* host = GetHost(window); const bool success = window && window->IsDrawn() && access_policy_->CanSetFocus(window) && host; if (success) { @@ -934,16 +987,18 @@ client_->OnChangeCompleted(change_id, success); } -void WindowTreeImpl::SetCanFocus(Id window_id, bool can_focus) { - ServerWindow* window = GetWindow(WindowIdFromTransportId(window_id)); +void WindowTreeImpl::SetCanFocus(Id transport_window_id, bool can_focus) { + ServerWindow* window = GetWindow(MapWindowIdFromClient(transport_window_id)); + // TODO(sky): there should be an else case (if shouldn't route to wm and + // policy allows, then set_can_focus). if (window && ShouldRouteToWindowManager(window)) window->set_can_focus(can_focus); } void WindowTreeImpl::SetPredefinedCursor(uint32_t change_id, - Id window_id, + Id transport_window_id, mus::mojom::Cursor cursor_id) { - ServerWindow* window = GetWindow(WindowIdFromTransportId(window_id)); + ServerWindow* window = GetWindow(MapWindowIdFromClient(transport_window_id)); // Only the owner of the window can change the bounds. bool success = window && access_policy_->CanSetCursorProperties(window); @@ -970,24 +1025,27 @@ } void WindowTreeImpl::WmResponse(uint32_t change_id, bool response) { - if (GetHost() && GetHost()->GetWindowTree() == this) + // TODO(sky): think about what else case means. + if (GetHostForWindowManager()) connection_manager_->WindowManagerChangeCompleted(change_id, response); } void WindowTreeImpl::WmRequestClose(Id transport_window_id) { // Only the WindowManager should be using this. - if (!GetHost() || GetHost()->GetWindowTree() != this) + WindowTreeHostImpl* host = GetHostForWindowManager(); + if (!host) return; - const WindowId window_id(WindowIdFromTransportId(transport_window_id)); + ServerWindow* window = GetWindow(MapWindowIdFromClient(transport_window_id)); WindowTreeImpl* connection = - connection_manager_->GetConnectionWithRoot(window_id); - if (connection && connection != GetHost()->GetWindowTree()) - connection->client_->RequestClose(transport_window_id); + connection_manager_->GetConnectionWithRoot(window); + if (connection && connection != host->GetWindowTree()) + connection->client_->RequestClose(MapWindowIdToClient(window)); + // TODO(sky): think about what else case means. } -bool WindowTreeImpl::IsRootForAccessPolicy(const WindowId& id) const { - return IsRoot(id); +bool WindowTreeImpl::HasRootForAccessPolicy(const ServerWindow* window) const { + return HasRoot(window); } bool WindowTreeImpl::IsWindowKnownForAccessPolicy( @@ -998,14 +1056,20 @@ bool WindowTreeImpl::IsWindowRootOfAnotherConnectionForAccessPolicy( const ServerWindow* window) const { WindowTreeImpl* connection = - connection_manager_->GetConnectionWithRoot(window->id()); + connection_manager_->GetConnectionWithRoot(window); return connection && connection != this; } bool WindowTreeImpl::IsDescendantOfEmbedRoot(const ServerWindow* window) { - return is_embed_root_ && root_ && GetWindow(*root_)->Contains(window); + if (!is_embed_root_) + return false; + + for (const auto* root : roots_) { + if (root->Contains(window)) + return true; + } + return false; } } // namespace ws - } // namespace mus
diff --git a/components/mus/ws/window_tree_impl.h b/components/mus/ws/window_tree_impl.h index e883bb3..676cced0 100644 --- a/components/mus/ws/window_tree_impl.h +++ b/components/mus/ws/window_tree_impl.h
@@ -27,7 +27,6 @@ } namespace mus { - namespace ws { class AccessPolicy; @@ -45,7 +44,7 @@ public mojom::WindowManagerInternalClient { public: WindowTreeImpl(ConnectionManager* connection_manager, - const WindowId& root_id, + ServerWindow* root, uint32_t policy_bitmask); ~WindowTreeImpl() override; @@ -62,16 +61,18 @@ } const ServerWindow* GetWindow(const WindowId& id) const; - // Returns true if this connection's root is |id|. - bool IsRoot(const WindowId& id) const; + // Returns true if |window| is one of this connections roots. + bool HasRoot(const ServerWindow* window) const; - // Returns the id of the root node. This is null if the root has been - // destroyed but the connection is still valid. - const WindowId* root() const { return root_.get(); } + std::set<const ServerWindow*> roots() { return roots_; } bool is_embed_root() const { return is_embed_root_; } - WindowTreeHostImpl* GetHost() const; + const WindowTreeHostImpl* GetHost(const ServerWindow* window) const; + WindowTreeHostImpl* GetHost(const ServerWindow* window) { + return const_cast<WindowTreeHostImpl*>( + const_cast<const WindowTreeImpl*>(this)->GetHost(window)); + } // Invoked when a connection is about to be destroyed. void OnWillDestroyWindowTreeImpl(WindowTreeImpl* connection); @@ -92,6 +93,20 @@ ConnectionSpecificId* connection_id); void DispatchInputEvent(ServerWindow* target, mojom::EventPtr event); + // Maps the window id from the client to the server. Normally the ids are the + // same, but there may be a different id at the embed point. + WindowId MapWindowIdFromClient(Id transport_window_id) const { + return MapWindowIdFromClient(WindowIdFromTransportId(transport_window_id)); + } + WindowId MapWindowIdFromClient(const WindowId& id) const; + + // Maps the window id to the client. + Id MapWindowIdToClient(const ServerWindow* window) const; + Id MapWindowIdToClient(const WindowId& id) const; + + // Calls through to the client. + void OnChangeCompleted(uint32_t change_id, bool success); + // The following methods are invoked after the corresponding change has been // processed. They do the appropriate bookkeeping and update the client as // necessary. @@ -104,7 +119,8 @@ const gfx::Insets& new_client_area, const std::vector<gfx::Rect>& new_additional_client_areas, bool originated_change); - void ProcessViewportMetricsChanged(const mojom::ViewportMetrics& old_metrics, + void ProcessViewportMetricsChanged(WindowTreeHostImpl* host, + const mojom::ViewportMetrics& old_metrics, const mojom::ViewportMetrics& new_metrics, bool originated_change); void ProcessWillChangeWindowHierarchy(const ServerWindow* window, @@ -123,7 +139,7 @@ const ServerWindow* relative_window, mojom::OrderDirection direction, bool originated_change); - void ProcessWindowDeleted(const WindowId& window, bool originated_change); + void ProcessWindowDeleted(const ServerWindow* window, bool originated_change); void ProcessWillChangeWindowVisibility(const ServerWindow* window, bool originated_change); void ProcessCursorChanged(const ServerWindow* window, @@ -142,10 +158,24 @@ using WindowIdSet = base::hash_set<Id>; using WindowMap = std::map<ConnectionSpecificId, ServerWindow*>; + enum class RemoveRootReason { + // The window is being removed. + DELETED, + + // Another connection is being embedded in the window. + EMBED, + }; + + // Used when this connection is associated with the window manager. + WindowTreeHostImpl* GetHostForWindowManager(); + bool ShouldRouteToWindowManager(const ServerWindow* window) const; bool IsWindowKnown(const ServerWindow* window) const; + // Returns true if |id| is a valid WindowId for a new window. + bool IsValidIdForNewWindow(const WindowId& id) const; + // These functions return true if the corresponding mojom function is allowed // for this connection. bool CanReorderWindow(const ServerWindow* window, @@ -168,7 +198,7 @@ std::vector<ServerWindow*>* local_windows); // Resets the root of this connection. - void RemoveRoot(); + void RemoveRoot(const ServerWindow* window, RemoveRootReason reason); // Converts Window(s) to WindowData(s) for transport. This assumes all the // windows are valid for the client. The parent of windows the client is not @@ -229,10 +259,10 @@ Id window_id, bool visible) override; void SetWindowProperty(uint32_t change_id, - Id window_id, + Id transport_window_id, const mojo::String& name, mojo::Array<uint8_t> value) override; - void AttachSurface(Id window_id, + void AttachSurface(Id transport_window_id, mojom::SurfaceType type, mojo::InterfaceRequest<mojom::Surface> surface, mojom::SurfaceClientPtr client) override; @@ -240,12 +270,12 @@ mojom::WindowTreeClientPtr client, uint32_t policy_bitmask, const EmbedCallback& callback) override; - void SetFocus(uint32_t change_id, Id window_id) override; - void SetCanFocus(Id window_id, bool can_focus) override; + void SetFocus(uint32_t change_id, Id transport_window_id) override; + void SetCanFocus(Id transport_window_id, bool can_focus) override; void SetPredefinedCursor(uint32_t change_id, - Id window_id, + Id transport_window_id, mus::mojom::Cursor cursor_id) override; - void SetWindowTextInputState(Id window_id, + void SetWindowTextInputState(Id transport_window_id, mojo::TextInputStatePtr state) override; void SetImeVisibility(Id transport_window_id, bool visible, @@ -264,7 +294,7 @@ void WmRequestClose(Id transport_window_id) override; // AccessPolicyDelegate: - bool IsRootForAccessPolicy(const WindowId& id) const override; + bool HasRootForAccessPolicy(const ServerWindow* window) const override; bool IsWindowKnownForAccessPolicy(const ServerWindow* window) const override; bool IsWindowRootOfAnotherConnectionForAccessPolicy( const ServerWindow* window) const override; @@ -285,12 +315,18 @@ // The set of windows that has been communicated to the client. WindowIdSet known_windows_; - // The root of this connection. This is a scoped_ptr to reinforce the - // connection may have no root. A connection has no root if either the root - // is destroyed or Embed() is invoked on the root. - scoped_ptr<WindowId> root_; + // The roots, or embed points, of this connection. A WindowTreeImpl may have + // any number of roots, including 0. + std::set<const ServerWindow*> roots_; uint32_t event_ack_id_; + + // WindowTreeHostImpl the current event came from. + // TODO(sky): in the case of multiple roots we may outlive + // |event_source_host_|. Make sure we null out event_source_host_ if the + // WindowTreeHostImpl is destroyed before us. + WindowTreeHostImpl* event_source_host_; + bool is_embed_root_; std::queue<scoped_ptr<TargetedEvent>> event_queue_; @@ -303,7 +339,6 @@ }; } // namespace ws - } // namespace mus #endif // COMPONENTS_MUS_WS_WINDOW_TREE_IMPL_H_
diff --git a/components/mus/ws/window_tree_unittest.cc b/components/mus/ws/window_tree_unittest.cc index 722f1974..a1f835ca 100644 --- a/components/mus/ws/window_tree_unittest.cc +++ b/components/mus/ws/window_tree_unittest.cc
@@ -43,7 +43,6 @@ using mus::mojom::WindowDataPtr; namespace mus { - namespace ws { namespace { @@ -75,7 +74,7 @@ void OnEmbeddedAppDisconnected(uint32_t window) override { tracker_.OnEmbeddedAppDisconnected(window); } - void OnUnembed() override { tracker_.OnUnembed(); } + void OnUnembed(Id window_id) override { tracker_.OnUnembed(window_id); } void OnWindowBoundsChanged(uint32_t window, mojo::RectPtr old_bounds, mojo::RectPtr new_bounds) override { @@ -91,6 +90,7 @@ void OnTransientWindowRemoved(uint32_t window_id, uint32_t transient_window_id) override {} void OnWindowViewportMetricsChanged( + mojo::Array<uint32_t> window_ids, mojom::ViewportMetricsPtr old_metrics, mojom::ViewportMetricsPtr new_metrics) override { tracker_.OnWindowViewportMetricsChanged(std::move(old_metrics), @@ -192,12 +192,12 @@ ClientConnection* CreateClientConnectionForEmbedAtWindow( ConnectionManager* connection_manager, mojo::InterfaceRequest<mus::mojom::WindowTree> service_request, - const WindowId& root_id, + ServerWindow* root, uint32_t policy_bitmask, mus::mojom::WindowTreeClientPtr client) override { // Used by ConnectionManager::AddRoot. scoped_ptr<WindowTreeImpl> service( - new WindowTreeImpl(connection_manager, root_id, policy_bitmask)); + new WindowTreeImpl(connection_manager, root, policy_bitmask)); last_connection_ = new TestClientConnection(std::move(service)); return last_connection_; } @@ -221,7 +221,7 @@ void OnDisplayInitialized() override { connection_manager()->AddHost(this); set_window_tree(connection_manager()->EmbedAtWindow( - window_tree_host()->root_window()->id(), + window_tree_host()->root_window(), mus::mojom::WindowTree::ACCESS_POLICY_EMBED_ROOT, mus::mojom::WindowTreeClientPtr())); } @@ -312,6 +312,11 @@ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON); } +const ServerWindow* FirstRoot(WindowTreeImpl* connection) { + return connection->roots().size() == 1u ? *(connection->roots().begin()) + : nullptr; +} + } // namespace // ----------------------------------------------------------------------------- @@ -339,6 +344,10 @@ ConnectionManager* connection_manager() { return connection_manager_.get(); } + ServerWindow* GetWindowById(const WindowId& id) { + return connection_manager_->GetWindow(id); + } + TestWindowTreeClient* wm_client() { return wm_client_; } int32_t cursor_id() { return cursor_id_; } @@ -359,8 +368,8 @@ AckPreviousEvent(); } - // Embeds a child window to the root window. Shared setup between several of - // the unit tests. + // Creates a new window from wm_connection() and embeds a new connection in + // it. void SetupEventTargeting(TestWindowTreeClient** out_client, WindowTreeImpl** window_tree_connection, ServerWindow** window); @@ -405,8 +414,9 @@ EXPECT_TRUE( wm_connection()->NewWindow(embed_window_id, ServerWindow::Properties())); EXPECT_TRUE(wm_connection()->SetWindowVisibility(embed_window_id, true)); - EXPECT_TRUE( - wm_connection()->AddWindow(*(wm_connection()->root()), embed_window_id)); + ASSERT_TRUE(FirstRoot(wm_connection())); + EXPECT_TRUE(wm_connection()->AddWindow(FirstRoot(wm_connection())->id(), + embed_window_id)); host_connection()->window_tree_host()->root_window()->SetBounds( gfx::Rect(0, 0, 100, 100)); mojom::WindowTreeClientPtr client; @@ -417,8 +427,8 @@ wm_connection()->Embed(embed_window_id, std::move(client), mojom::WindowTree::ACCESS_POLICY_DEFAULT, &connection_id); - WindowTreeImpl* connection1 = - connection_manager()->GetConnectionWithRoot(embed_window_id); + WindowTreeImpl* connection1 = connection_manager()->GetConnectionWithRoot( + GetWindowById(embed_window_id)); ASSERT_TRUE(connection1 != nullptr); ASSERT_NE(connection1, wm_connection()); @@ -429,8 +439,8 @@ const WindowId child1(connection1->id(), 1); EXPECT_TRUE(connection1->NewWindow(child1, ServerWindow::Properties())); EXPECT_TRUE(connection1->AddWindow(embed_window_id, child1)); - connection1->GetHost()->AddActivationParent( - WindowIdToTransportId(embed_window_id)); + connection1->GetHost(GetWindowById(embed_window_id)) + ->AddActivationParent(WindowIdToTransportId(embed_window_id)); ServerWindow* v1 = connection1->GetWindow(child1); v1->SetVisible(true); @@ -452,8 +462,9 @@ EXPECT_TRUE( wm_connection()->NewWindow(embed_window_id, ServerWindow::Properties())); EXPECT_TRUE(wm_connection()->SetWindowVisibility(embed_window_id, true)); - EXPECT_TRUE( - wm_connection()->AddWindow(*(wm_connection()->root()), embed_window_id)); + ASSERT_TRUE(FirstRoot(wm_connection())); + EXPECT_TRUE(wm_connection()->AddWindow(FirstRoot(wm_connection())->id(), + embed_window_id)); host_connection()->window_tree_host()->root_window()->SetBounds( gfx::Rect(0, 0, 100, 100)); mojom::WindowTreeClientPtr client; @@ -464,8 +475,8 @@ wm_connection()->Embed(embed_window_id, std::move(client), mojom::WindowTree::ACCESS_POLICY_DEFAULT, &connection_id); - WindowTreeImpl* connection1 = - connection_manager()->GetConnectionWithRoot(embed_window_id); + WindowTreeImpl* connection1 = connection_manager()->GetConnectionWithRoot( + GetWindowById(embed_window_id)); ASSERT_TRUE(connection1 != nullptr); ASSERT_NE(connection1, wm_connection()); @@ -488,18 +499,19 @@ // Focus should not go to |child1| yet, since the parent still doesn't allow // active children. DispatchEventAndAckImmediately(CreatePointerDownEvent(21, 22)); - EXPECT_EQ(nullptr, connection1->GetHost()->GetFocusedWindow()); + WindowTreeHostImpl* host1 = + connection1->GetHost(GetWindowById(embed_window_id)); + EXPECT_EQ(nullptr, host1->GetFocusedWindow()); DispatchEventAndAckImmediately(CreatePointerUpEvent(21, 22)); connection1_client->tracker()->changes()->clear(); wm_client()->tracker()->changes()->clear(); - connection1->GetHost()->AddActivationParent( - WindowIdToTransportId(embed_window_id)); + host1->AddActivationParent(WindowIdToTransportId(embed_window_id)); // Focus should go to child1. This result in notifying both the window // manager and client connection being notified. DispatchEventAndAckImmediately(CreatePointerDownEvent(21, 22)); - EXPECT_EQ(v1, connection1->GetHost()->GetFocusedWindow()); + EXPECT_EQ(v1, host1->GetFocusedWindow()); ASSERT_GE(wm_client()->tracker()->changes()->size(), 1u); EXPECT_EQ("Focused id=2,1", ChangesToDescription1(*wm_client()->tracker()->changes())[0]); @@ -671,8 +683,9 @@ EXPECT_TRUE( window_tree_connection->NewWindow(child2, ServerWindow::Properties())); EXPECT_TRUE(window_tree_connection->AddWindow(embed_window_id, child2)); - window_tree_connection->GetHost()->AddActivationParent( - WindowIdToTransportId(embed_window_id)); + window_tree_connection->GetHost( + GetWindowById(WindowId(wm_connection()->id(), 1))) + ->AddActivationParent(WindowIdToTransportId(embed_window_id)); ServerWindow* window2 = window_tree_connection->GetWindow(child2); window2->SetVisible(true); window2->SetBounds(gfx::Rect(20, 20, 20, 20)); @@ -696,8 +709,9 @@ EXPECT_TRUE( wm_connection()->NewWindow(embed_window_id, ServerWindow::Properties())); EXPECT_TRUE(wm_connection()->SetWindowVisibility(embed_window_id, true)); - EXPECT_TRUE( - wm_connection()->AddWindow(*(wm_connection()->root()), embed_window_id)); + ASSERT_TRUE(FirstRoot(wm_connection())); + EXPECT_TRUE(wm_connection()->AddWindow(FirstRoot(wm_connection())->id(), + embed_window_id)); host_connection()->window_tree_host()->root_window()->SetBounds( gfx::Rect(0, 0, 100, 100)); @@ -720,5 +734,4 @@ } } // namespace ws - } // namespace mus
diff --git a/components/nacl/broker/BUILD.gn b/components/nacl/broker/BUILD.gn new file mode 100644 index 0000000..23d8ba18 --- /dev/null +++ b/components/nacl/broker/BUILD.gn
@@ -0,0 +1,156 @@ +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//build/config/features.gni") + +# This file builds nacl64.exe, which is a 64-bit x86 Windows executable +# used only in the 32-bit x86 Windows build. The :broker code runs both +# in nacl64.exe and in the 32-bit chrome executable, to launch +# nacl64.exe and communicate with it. + +assert(enable_nacl) +assert(is_win) +assert(target_cpu == "x86") + +source_set("broker") { + sources = [ + "nacl_broker_listener.cc", + "nacl_broker_listener.h", + ] + + deps = [ + "//base", + "//components/nacl/common:debug_exception_handler", + "//components/nacl/common:minimal", + "//components/nacl/common:switches", + "//content/public/common:static_switches", + "//ipc", + "//sandbox", + ] + + if (current_cpu == target_cpu) { + deps += [ "//content/public/common" ] + } else { + deps += [ ":content_dummy" ] + } +} + +# This exists just to make 'gn check' happy with :broker. It can't depend +# on //content/public/common or anything like that, because that would +# bring in lots more stuff that should not be in the nacl64.exe build. +source_set("content_dummy") { + check_includes = false + sources = [ + "//content/public/common/sandbox_init.h", + "//content/public/common/sandboxed_process_launcher_delegate.h", + ] +} + +if (current_cpu == "x86") { + # Tests, packaging rules, etc. will expect to find nacl64.exe in the root + # of the output directory. It gets built in a non-default toolchain and + # so will be delivered in the toolchain output subdirectory. So this + # just copies it to the expected place. Having this target also makes + # it simpler for things to depend on nacl64, since they don't have to + # use a toolchain qualifier. + copy("nacl64") { + # NOTE: This must match what //build/config/BUILDCONFIG.gn uses + # as default toolchain for the corresponding x64 build. + if (is_clang) { + x64_toolchain = "//build/toolchain/win:clang_x64" + } else { + x64_toolchain = "//build/toolchain/win:x64" + } + nacl64_label = ":nacl64($x64_toolchain)" + nacl64_out_dir = get_label_info(nacl64_label, "root_out_dir") + sources = [ + "$nacl64_out_dir/nacl64.exe", + ] + outputs = [ + "$root_out_dir/{{source_file_part}}", + ] + deps = [ + nacl64_label, + ] + } +} else if (current_cpu == "x64") { + # In the x64 toolchain context, build nacl64.exe for real. + executable("nacl64") { + configs += [ "//build/config/win:windowed" ] + + # //build/config/compiler:optimize{,_max} adds this for official builds + # only, as it only reduces binary size and is not necessary for + # correctness. But for nacl64.exe, it makes more than a six-fold + # difference in the binary size, so always use it. + ldflags = [ "/OPT:REF" ] + + sources = [ + "//chrome/nacl/nacl_exe_win_64.cc", + ] + + deps = [ + ":broker", + ":nacl64_content", + ":nacl64_crash_reporter_client", + "//base", + "//breakpad:breakpad_handler", + "//chrome:nacl64_exe_version", + "//components/crash/content/app:app_breakpad_mac_win_to_be_deleted", + "//components/nacl/loader:nacl_helper_win_64", + "//content/public/common:static_switches", + "//ppapi/proxy:ipc", + "//sandbox", + ] + } + + # This is a tiny subset of //content built specially for nacl64.exe. + # There are no subcomponents of //content small enough to get just + # what nacl64.exe needs without bringing in other stuff that causes + # problems for the build. + source_set("nacl64_content") { + sources = [ + "//content/app/sandbox_helper_win.cc", + "//content/common/sandbox_init_win.cc", + "//content/common/sandbox_win.cc", + "//content/public/common/sandboxed_process_launcher_delegate.cc", + ] + + defines = [ + "COMPILE_CONTENT_STATICALLY", + "NACL_WIN64", + ] + + # This defangs 'gn check', which does not like this cherry-picking. + # All the source files here are part of other proper components + # under //content, where their #include discipline will be checked. + check_includes = false + + deps = [ + "//base", + "//content/public/common:static_switches", + "//sandbox", + ] + } + + source_set("nacl64_crash_reporter_client") { + sources = [ + "//chrome/app/chrome_crash_reporter_client.cc", + "//chrome/common/crash_keys.cc", + ] + + defines = [ "NACL_WIN64" ] + + check_includes = false + + deps = [ + "//chrome/common:constants", + "//chrome/installer/util:with_no_strings", + "//components/browser_watcher:browser_watcher_client", + "//components/flags_ui:switches", + "//components/policy", + "//content/public/common:static_switches", + "//ipc", + ] + } +}
diff --git a/components/nacl/common/BUILD.gn b/components/nacl/common/BUILD.gn index 5af9cbe..f1822b3 100644 --- a/components/nacl/common/BUILD.gn +++ b/components/nacl/common/BUILD.gn
@@ -5,18 +5,15 @@ import("//build/config/features.gni") if (enable_nacl) { - source_set("common") { + # This is separate so it can be used by ../broker:nacl64. + source_set("minimal") { sources = [ "nacl_cmd_line.cc", "nacl_cmd_line.h", "nacl_constants.cc", "nacl_constants.h", - "nacl_host_messages.cc", - "nacl_host_messages.h", "nacl_messages.cc", "nacl_messages.h", - "nacl_nonsfi_util.cc", - "nacl_nonsfi_util.h", "nacl_process_type.h", "nacl_renderer_messages.cc", "nacl_renderer_messages.h", @@ -25,11 +22,45 @@ "nacl_types.h", "nacl_types_param_traits.cc", "nacl_types_param_traits.h", + ] + + public_deps = [ + ":switches", + ] + + deps = [ + ":minimal_content_dummy", + "//base", + "//base:base_static", + "//ipc", + ] + } + + # This exists just to make 'gn check' happy with :minimal. It can't + # depend on //content/public/common or anything like that, because that + # would bring in lots more than counts as "minimal" (stuff that should + # not be in the nacl64.exe build). + source_set("minimal_content_dummy") { + check_includes = false + sources = [ + "//content/public/common/content_switches.h", + "//content/public/common/process_type.h", + "//content/public/common/sandbox_type.h", + ] + } + + source_set("common") { + sources = [ + "nacl_host_messages.cc", + "nacl_host_messages.h", + "nacl_nonsfi_util.cc", + "nacl_nonsfi_util.h", "pnacl_types.cc", "pnacl_types.h", ] public_deps = [ + ":minimal", ":switches", ]
diff --git a/components/nacl/loader/BUILD.gn b/components/nacl/loader/BUILD.gn index db7a71dd..e9d9d9c8 100644 --- a/components/nacl/loader/BUILD.gn +++ b/components/nacl/loader/BUILD.gn
@@ -8,7 +8,8 @@ assert(enable_nacl) -source_set("loader") { +# This is separate so it can be used by ../broker:nacl64. +source_set("minimal") { sources = [ "nacl_ipc_adapter.cc", "nacl_ipc_adapter.h", @@ -27,17 +28,40 @@ ] deps = [ + ":minimal_content_dummy", "//base", - "//base:base_static", - "//components/nacl/common", - "//content/public/common", + "//components/nacl/common:minimal", "//crypto", "//ipc", "//native_client/src/trusted/service_runtime:sel_main_chrome", "//ppapi/c", "//ppapi/proxy:ipc", - "//ppapi/shared_impl", "//sandbox", + ] +} + +# This exists just to make 'gn check' happy with :minimal and +# :nacl_helper_win_64 (below). They can't depend on //content/public/common +# or anything like that, because that would bring in lots more than counts +# as "minimal" (stuff that should not be in the nacl64.exe build). +source_set("minimal_content_dummy") { + check_includes = false + sources = [ + "//content/public/common/child_process_sandbox_support_linux.h", + "//content/public/common/content_switches.h", + "//content/public/common/main_function_params.h", + "//content/public/common/sandbox_init.h", + ] +} + +source_set("loader") { + public_deps = [ + ":minimal", + ] + deps = [ + "//components/nacl/common", + "//content/public/common", + "//ppapi/shared_impl", "//third_party/mojo/src/mojo/edk/system", ] @@ -163,6 +187,25 @@ } } +if (is_win && target_cpu == "x86" && current_cpu == "x64") { + source_set("nacl_helper_win_64") { + sources = [ + "nacl_helper_win_64.cc", + "nacl_helper_win_64.h", + ] + + deps = [ + ":minimal", + ":minimal_content_dummy", + "//base", + "//components/nacl/broker", + "//components/nacl/common:switches", + "//content/public/common:static_switches", + "//sandbox", + ] + } +} + if (is_nacl_nonsfi) { executable("nacl_helper_nonsfi_nexe") { output_name = "nacl_helper_nonsfi"
diff --git a/components/nacl/renderer/plugin/pnacl_translate_thread.cc b/components/nacl/renderer/plugin/pnacl_translate_thread.cc index 85a5b88..e671916c2 100644 --- a/components/nacl/renderer/plugin/pnacl_translate_thread.cc +++ b/components/nacl/renderer/plugin/pnacl_translate_thread.cc
@@ -32,48 +32,32 @@ return ss.str(); } -void GetLlcCommandLine(std::vector<char>* split_args, +void GetLlcCommandLine(std::vector<std::string>* args, size_t obj_files_size, int32_t opt_level, bool is_debug, const std::string& architecture_attributes) { - typedef std::vector<std::string> Args; - Args args; - // TODO(dschuff): This CL override is ugly. Change llc to default to // using the number of modules specified in the first param, and // ignore multiple uses of -split-module - args.push_back(MakeCommandLineArg("-split-module=", obj_files_size)); - args.push_back(MakeCommandLineArg("-O", opt_level)); + args->push_back(MakeCommandLineArg("-split-module=", obj_files_size)); + args->push_back(MakeCommandLineArg("-O", opt_level)); if (is_debug) - args.push_back("-bitcode-format=llvm"); + args->push_back("-bitcode-format=llvm"); if (!architecture_attributes.empty()) - args.push_back("-mattr=" + architecture_attributes); - - for (const std::string& arg : args) { - std::copy(arg.begin(), arg.end(), std::back_inserter(*split_args)); - split_args->push_back('\x00'); - } + args->push_back("-mattr=" + architecture_attributes); } -void GetSubzeroCommandLine(std::vector<char>* split_args, +void GetSubzeroCommandLine(std::vector<std::string>* args, int32_t opt_level, bool is_debug, const std::string& architecture_attributes) { - typedef std::vector<std::string> Args; - Args args; - - args.push_back(MakeCommandLineArg("-O", opt_level)); + args->push_back(MakeCommandLineArg("-O", opt_level)); DCHECK(!is_debug); // TODO(stichnot): enable this once the mattr flag formatting is // compatible: https://code.google.com/p/nativeclient/issues/detail?id=4132 // if (!architecture_attributes.empty()) - // args.push_back("-mattr=" + architecture_attributes); - - for (const std::string& arg : args) { - std::copy(arg.begin(), arg.end(), std::back_inserter(*split_args)); - split_args->push_back('\x00'); - } + // args->push_back("-mattr=" + architecture_attributes); } } // namespace @@ -270,18 +254,24 @@ int64_t do_compile_start_time = NaClGetTimeOfDayMicroseconds(); bool init_success; - std::vector<char> split_args; + std::vector<std::string> args; if (pnacl_options_->use_subzero) { - GetSubzeroCommandLine(&split_args, pnacl_options_->opt_level, + GetSubzeroCommandLine(&args, pnacl_options_->opt_level, PP_ToBool(pnacl_options_->is_debug), architecture_attributes_); } else { - GetLlcCommandLine(&split_args, obj_files_->size(), + GetLlcCommandLine(&args, obj_files_->size(), pnacl_options_->opt_level, PP_ToBool(pnacl_options_->is_debug), architecture_attributes_); } + std::vector<char> split_args; + for (const std::string& arg : args) { + std::copy(arg.begin(), arg.end(), std::back_inserter(split_args)); + split_args.push_back('\x00'); + } + init_success = compiler_subprocess_->InvokeSrpcMethod( "StreamInitWithSplit", "ihhhhhhhhhhhhhhhhC", ¶ms, num_threads_, compile_out_files[0]->desc(), compile_out_files[1]->desc(),
diff --git a/components/omnibox/browser/autocomplete_provider_client.h b/components/omnibox/browser/autocomplete_provider_client.h index acaa7ac..301d60bc 100644 --- a/components/omnibox/browser/autocomplete_provider_client.h +++ b/components/omnibox/browser/autocomplete_provider_client.h
@@ -85,9 +85,6 @@ virtual bool IsOffTheRecord() const = 0; virtual bool SearchSuggestEnabled() const = 0; - // Returns whether the bookmark bar is visible on all tabs. - virtual bool BookmarkBarIsVisible() const = 0; - virtual bool TabSyncEnabledAndUnencrypted() const = 0; // Given some string |text| that the user wants to use for navigation,
diff --git a/components/omnibox/browser/base_search_provider.cc b/components/omnibox/browser/base_search_provider.cc index c6833f68..0c1feb15a 100644 --- a/components/omnibox/browser/base_search_provider.cc +++ b/components/omnibox/browser/base_search_provider.cc
@@ -265,7 +265,6 @@ new TemplateURLRef::SearchTermsArgs(suggestion.suggestion())); match.search_terms_args->original_query = input.text(); match.search_terms_args->accepted_suggestion = accepted_suggestion; - match.search_terms_args->enable_omnibox_start_margin = true; match.search_terms_args->suggest_query_params = suggestion.suggest_query_params(); match.search_terms_args->append_extra_query_params = @@ -372,8 +371,6 @@ accepted_suggestion, ShouldAppendExtraParams(result)); if (!match.destination_url.is_valid()) return; - match.search_terms_args->bookmark_bar_pinned = - client_->BookmarkBarIsVisible(); match.RecordAdditionalInfo(kRelevanceFromServerKey, result.relevance_from_server() ? kTrue : kFalse); match.RecordAdditionalInfo(kShouldPrefetchKey,
diff --git a/components/omnibox/browser/history_url_provider.cc b/components/omnibox/browser/history_url_provider.cc index 978cb865..a7a4b01 100644 --- a/components/omnibox/browser/history_url_provider.cc +++ b/components/omnibox/browser/history_url_provider.cc
@@ -277,10 +277,8 @@ std::string GetApplicationLocale() const override; base::string16 GetRlzParameterValue(bool from_app_list) const override; std::string GetSearchClient() const override; - bool IsShowingSearchTermsOnSearchResultsPages() const override; std::string InstantExtendedEnabledParam(bool for_search) const override; std::string ForceInstantResultsParam(bool for_prerender) const override; - std::string NTPIsThemedParam() const override; std::string GoogleImageSearchSource() const override; private: @@ -288,12 +286,10 @@ std::string application_locale_; base::string16 rlz_parameter_value_; std::string search_client_; - bool is_showing_search_terms_on_search_results_pages_; std::string instant_extended_enabled_param_; std::string instant_extended_enabled_param_for_search_; std::string force_instant_results_param_; std::string force_instant_results_param_for_prerender_; - std::string ntp_is_themed_param_; std::string google_image_search_source_; DISALLOW_COPY_AND_ASSIGN(SearchTermsDataSnapshot); @@ -305,8 +301,6 @@ application_locale_(search_terms_data.GetApplicationLocale()), rlz_parameter_value_(search_terms_data.GetRlzParameterValue(false)), search_client_(search_terms_data.GetSearchClient()), - is_showing_search_terms_on_search_results_pages_( - search_terms_data.IsShowingSearchTermsOnSearchResultsPages()), instant_extended_enabled_param_( search_terms_data.InstantExtendedEnabledParam(false)), instant_extended_enabled_param_for_search_( @@ -315,7 +309,6 @@ search_terms_data.ForceInstantResultsParam(false)), force_instant_results_param_for_prerender_( search_terms_data.ForceInstantResultsParam(true)), - ntp_is_themed_param_(search_terms_data.NTPIsThemedParam()), google_image_search_source_(search_terms_data.GoogleImageSearchSource()) { } @@ -339,10 +332,6 @@ return search_client_; } -bool SearchTermsDataSnapshot::IsShowingSearchTermsOnSearchResultsPages() const { - return is_showing_search_terms_on_search_results_pages_; -} - std::string SearchTermsDataSnapshot::InstantExtendedEnabledParam( bool for_search) const { return for_search ? instant_extended_enabled_param_ : @@ -355,10 +344,6 @@ force_instant_results_param_for_prerender_; } -std::string SearchTermsDataSnapshot::NTPIsThemedParam() const { - return ntp_is_themed_param_; -} - std::string SearchTermsDataSnapshot::GoogleImageSearchSource() const { return google_image_search_source_; }
diff --git a/components/omnibox/browser/in_memory_url_index_types.h b/components/omnibox/browser/in_memory_url_index_types.h index 218760a..73e8af2 100644 --- a/components/omnibox/browser/in_memory_url_index_types.h +++ b/components/omnibox/browser/in_memory_url_index_types.h
@@ -11,7 +11,6 @@ #include <set> #include <vector> -#include "base/containers/hash_tables.h" #include "base/strings/string16.h" #include "components/history/core/browser/history_types.h" #include "url/gurl.h" @@ -163,7 +162,7 @@ }; // A map from history_id to the history's URL and title. -typedef base::hash_map<HistoryID, HistoryInfoMapValue> HistoryInfoMap; +typedef std::map<HistoryID, HistoryInfoMapValue> HistoryInfoMap; // A map from history_id to URL and page title word start metrics. struct RowWordStarts {
diff --git a/components/omnibox/browser/mock_autocomplete_provider_client.h b/components/omnibox/browser/mock_autocomplete_provider_client.h index af390d3..1810dd1 100644 --- a/components/omnibox/browser/mock_autocomplete_provider_client.h +++ b/components/omnibox/browser/mock_autocomplete_provider_client.h
@@ -64,7 +64,6 @@ MOCK_METHOD0(GetBuiltinsToProvideAsUserTypes, std::vector<base::string16>()); MOCK_CONST_METHOD0(IsOffTheRecord, bool()); MOCK_CONST_METHOD0(SearchSuggestEnabled, bool()); - MOCK_CONST_METHOD0(BookmarkBarIsVisible, bool()); MOCK_CONST_METHOD0(TabSyncEnabledAndUnencrypted, bool()); MOCK_METHOD6( Classify,
diff --git a/components/page_load_metrics/browser/metrics_web_contents_observer.cc b/components/page_load_metrics/browser/metrics_web_contents_observer.cc index ab15c52..d2decce 100644 --- a/components/page_load_metrics/browser/metrics_web_contents_observer.cc +++ b/components/page_load_metrics/browser/metrics_web_contents_observer.cc
@@ -4,8 +4,6 @@ #include "components/page_load_metrics/browser/metrics_web_contents_observer.h" -#include <stddef.h> -#include <stdint.h> #include <utility> #include "base/location.h" @@ -15,8 +13,6 @@ #include "components/page_load_metrics/browser/page_load_metrics_util.h" #include "components/page_load_metrics/common/page_load_metrics_messages.h" #include "components/page_load_metrics/common/page_load_timing.h" -#include "components/rappor/rappor_service.h" -#include "components/rappor/rappor_utils.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/navigation_details.h" #include "content/public/browser/navigation_handle.h" @@ -38,10 +34,9 @@ // The url we see from the renderer side is not always the same as what // we see from the browser side (e.g. chrome://newtab). We want to be // sure here that we aren't logging UMA for internal pages. -bool IsRelevantNavigation( - content::NavigationHandle* navigation_handle, - const GURL& browser_url, - const std::string& mime_type) { +bool IsRelevantNavigation(content::NavigationHandle* navigation_handle, + const GURL& browser_url, + const std::string& mime_type) { DCHECK(navigation_handle->HasCommitted()); return navigation_handle->IsInMainFrame() && !navigation_handle->IsSamePage() && @@ -83,7 +78,7 @@ } void RecordInternalError(InternalErrorLoadEvent event) { - UMA_HISTOGRAM_ENUMERATION(kErrorEvents, event, ERR_LAST_ENTRY); + UMA_HISTOGRAM_ENUMERATION(internal::kErrorEvents, event, ERR_LAST_ENTRY); } UserAbortType AbortTypeForPageTransition(ui::PageTransition transition) { @@ -97,31 +92,17 @@ return ABORT_OTHER; } -// The number of buckets in the bitfield histogram. These buckets are described -// in rappor.xml in PageLoad.CoarseTiming.NavigationToFirstContentfulPaint. -// The bucket flag is defined by 1 << bucket_index, and is the bitfield -// representing which timing bucket the page load falls into, i.e. 000010 -// would be the bucket flag showing that the page took between 2 and 4 seconds -// to load. -const size_t kNumRapporHistogramBuckets = 6; - -uint64_t RapporHistogramBucketIndex(const base::TimeDelta& time) { - int64_t seconds = time.InSeconds(); - if (seconds < 2) - return 0; - if (seconds < 4) - return 1; - if (seconds < 8) - return 2; - if (seconds < 16) - return 3; - if (seconds < 32) - return 4; - return 5; -} - } // namespace +namespace internal { + +const char kProvisionalEvents[] = "PageLoad.Events.Provisional"; +const char kBackgroundProvisionalEvents[] = + "PageLoad.Events.Provisional.Background"; +const char kErrorEvents[] = "PageLoad.Events.InternalError"; + +} // namespace internal + PageLoadTracker::PageLoadTracker( bool in_foreground, PageLoadMetricsEmbedderInterface* embedder_interface, @@ -138,9 +119,11 @@ } PageLoadTracker::~PageLoadTracker() { - PageLoadExtraInfo info = GetPageLoadMetricsInfo(); - RecordRappor(info); - RecordTimingHistograms(info); + const PageLoadExtraInfo info = GetPageLoadMetricsInfo(); + if (!info.time_to_commit.is_zero() && renderer_tracked() && + timing_.IsEmpty()) { + RecordInternalError(ERR_NO_IPCS_RECEIVED); + } for (const auto& observer : observers_) { observer->OnComplete(timing_, info); } @@ -163,7 +146,7 @@ // TODO(bmcquade): To improve accuracy, consider adding commit time to // NavigationHandle. Taking a timestamp here should be close enough for now. commit_time_ = base::TimeTicks::Now(); - url_ = navigation_handle->GetURL(); + committed_url_ = navigation_handle->GetURL(); for (const auto& observer : observers_) { observer->OnCommit(navigation_handle); } @@ -218,18 +201,15 @@ } else { DCHECK(abort_time_.is_null()); } - if (!commit_time_.is_null()) { + if (!committed_url_.is_empty()) { DCHECK_GT(commit_time_, navigation_start_); time_to_commit = commit_time_ - navigation_start_; + } else { + DCHECK(commit_time_.is_null()); } return PageLoadExtraInfo(first_background_time, first_foreground_time, - started_in_foreground_, time_to_commit, abort_type_, - time_to_abort); -} - -const GURL& PageLoadTracker::committed_url() { - DCHECK(!commit_time_.is_null()); - return url_; + started_in_foreground_, committed_url_, + time_to_commit, abort_type_, time_to_abort); } void PageLoadTracker::NotifyAbort(UserAbortType abort_type, @@ -275,149 +255,16 @@ abort_time_ = timestamp; } -void PageLoadTracker::RecordTimingHistograms(const PageLoadExtraInfo& info) { - if (!info.first_background_time.is_zero() && - !EventOccurredInForeground(timing_.first_paint, info)) { - if (!info.time_to_commit.is_zero()) { - PAGE_LOAD_HISTOGRAM(kHistogramBackgroundBeforePaint, - info.first_background_time); - } else { - PAGE_LOAD_HISTOGRAM(kHistogramBackgroundBeforeCommit, - info.first_background_time); - } - } - - // The rest of the histograms require the load to have commit and be relevant. - if (info.time_to_commit.is_zero() || !renderer_tracked()) - return; - - if (EventOccurredInForeground(info.time_to_commit, info)) { - PAGE_LOAD_HISTOGRAM(kHistogramCommit, info.time_to_commit); - } else { - PAGE_LOAD_HISTOGRAM(kBackgroundHistogramCommit, info.time_to_commit); - } - - // The rest of the timing histograms require us to have received IPCs from the - // renderer. Record UMA for how often this occurs (usually for quickly aborted - // loads). For now, don't update observers if this is the case. - if (timing_.IsEmpty()) { - RecordInternalError(ERR_NO_IPCS_RECEIVED); - return; - } - - if (!timing_.dom_content_loaded_event_start.is_zero()) { - if (EventOccurredInForeground(timing_.dom_content_loaded_event_start, - info)) { - PAGE_LOAD_HISTOGRAM(kHistogramDomContentLoaded, - timing_.dom_content_loaded_event_start); - } else { - PAGE_LOAD_HISTOGRAM(kBackgroundHistogramDomContentLoaded, - timing_.dom_content_loaded_event_start); - } - } - if (!timing_.load_event_start.is_zero()) { - if (EventOccurredInForeground(timing_.load_event_start, info)) { - PAGE_LOAD_HISTOGRAM(kHistogramLoad, timing_.load_event_start); - } else { - PAGE_LOAD_HISTOGRAM(kBackgroundHistogramLoad, timing_.load_event_start); - } - } - if (!timing_.first_layout.is_zero()) { - if (EventOccurredInForeground(timing_.first_layout, info)) { - PAGE_LOAD_HISTOGRAM(kHistogramFirstLayout, timing_.first_layout); - } else { - PAGE_LOAD_HISTOGRAM(kBackgroundHistogramFirstLayout, - timing_.first_layout); - } - } - if (!timing_.first_paint.is_zero()) { - if (EventOccurredInForeground(timing_.first_paint, info)) { - PAGE_LOAD_HISTOGRAM(kHistogramFirstPaint, timing_.first_paint); - } else { - PAGE_LOAD_HISTOGRAM(kBackgroundHistogramFirstPaint, timing_.first_paint); - } - } - if (!timing_.first_text_paint.is_zero()) { - if (EventOccurredInForeground(timing_.first_text_paint, info)) { - PAGE_LOAD_HISTOGRAM(kHistogramFirstTextPaint, timing_.first_text_paint); - } else { - PAGE_LOAD_HISTOGRAM(kBackgroundHistogramFirstTextPaint, - timing_.first_text_paint); - } - } - if (!timing_.first_image_paint.is_zero()) { - if (EventOccurredInForeground(timing_.first_image_paint, info)) { - PAGE_LOAD_HISTOGRAM(kHistogramFirstImagePaint, timing_.first_image_paint); - } else { - PAGE_LOAD_HISTOGRAM(kBackgroundHistogramFirstImagePaint, - timing_.first_image_paint); - } - } - base::TimeDelta first_contentful_paint = GetFirstContentfulPaint(timing_); - if (!first_contentful_paint.is_zero()) { - if (EventOccurredInForeground(first_contentful_paint, info)) { - PAGE_LOAD_HISTOGRAM(kHistogramFirstContentfulPaint, - first_contentful_paint); - // Bucket these histograms into high/low resolution clock systems. This - // might point us to directions that will de-noise some UMA. - if (base::TimeTicks::IsHighResolution()) { - PAGE_LOAD_HISTOGRAM(kHistogramFirstContentfulPaintHigh, - first_contentful_paint); - } else { - PAGE_LOAD_HISTOGRAM(kHistogramFirstContentfulPaintLow, - first_contentful_paint); - } - } else { - PAGE_LOAD_HISTOGRAM(kBackgroundHistogramFirstContentfulPaint, - first_contentful_paint); - } - } - - // Log time to first foreground / time to first background. Log counts that we - // started a relevant page load in the foreground / background. - if (!info.first_background_time.is_zero()) - PAGE_LOAD_HISTOGRAM(kHistogramFirstBackground, info.first_background_time); - else if (!info.first_foreground_time.is_zero()) - PAGE_LOAD_HISTOGRAM(kHistogramFirstForeground, info.first_foreground_time); -} - void PageLoadTracker::RecordProvisionalEvent(ProvisionalLoadEvent event) { if (HasBackgrounded()) { - UMA_HISTOGRAM_ENUMERATION(kBackgroundProvisionalEvents, event, + UMA_HISTOGRAM_ENUMERATION(internal::kBackgroundProvisionalEvents, event, PROVISIONAL_LOAD_LAST_ENTRY); } else { - UMA_HISTOGRAM_ENUMERATION(kProvisionalEvents, event, + UMA_HISTOGRAM_ENUMERATION(internal::kProvisionalEvents, event, PROVISIONAL_LOAD_LAST_ENTRY); } } -void PageLoadTracker::RecordRappor(const PageLoadExtraInfo& info) { - if (info.time_to_commit.is_zero()) - return; - DCHECK(!committed_url().is_empty()); - rappor::RapporService* rappor_service = - embedder_interface_->GetRapporService(); - if (!rappor_service) - return; - base::TimeDelta first_contentful_paint = GetFirstContentfulPaint(timing_); - // Log the eTLD+1 of sites that show poor loading performance. - if (EventOccurredInForeground(first_contentful_paint, info)) { - scoped_ptr<rappor::Sample> sample = - rappor_service->CreateSample(rappor::UMA_RAPPOR_TYPE); - sample->SetStringField( - "Domain", rappor::GetDomainAndRegistrySampleFromGURL(committed_url())); - uint64_t bucket_index = RapporHistogramBucketIndex(first_contentful_paint); - sample->SetFlagsField("Bucket", uint64_t(1) << bucket_index, - kNumRapporHistogramBuckets); - // The IsSlow flag is just a one bit boolean if the first contentful paint - // was > 10s. - sample->SetFlagsField("IsSlow", first_contentful_paint.InSecondsF() >= 10, - 1); - rappor_service->RecordSampleObj(kRapporMetricsNameCoarseTiming, - std::move(sample)); - } -} - // static MetricsWebContentsObserver::MetricsWebContentsObserver( content::WebContents* web_contents, @@ -496,10 +343,19 @@ // TODO(csharrison): Track changes to NavigationHandle for signals when this // is the case (HTTP response headers). if (!navigation_handle->HasCommitted()) { - net::Error error = navigation_handle->GetNetErrorCode(); - ProvisionalLoadEvent event = error == net::OK ? PROVISIONAL_LOAD_STOPPED - : error == net::ERR_ABORTED ? PROVISIONAL_LOAD_ERR_ABORTED - : PROVISIONAL_LOAD_ERR_FAILED_NON_ABORT; + const ProvisionalLoadEvent event = [](net::Error error) { + switch (error) { + case net::OK: + // When a finished navigation that didn't commit has a net error code + // of OK, it indicates that the provisional load was stopped by the + // user. + return PROVISIONAL_LOAD_STOPPED; + case net::ERR_ABORTED: + return PROVISIONAL_LOAD_ERR_ABORTED; + default: + return PROVISIONAL_LOAD_ERR_FAILED_NON_ABORT; + } + }(navigation_handle->GetNetErrorCode()); finished_nav->RecordProvisionalEvent(event); if (event != PROVISIONAL_LOAD_ERR_FAILED_NON_ABORT) { finished_nav->NotifyAbort(ABORT_OTHER, base::TimeTicks::Now());
diff --git a/components/page_load_metrics/browser/metrics_web_contents_observer.h b/components/page_load_metrics/browser/metrics_web_contents_observer.h index 403bae9..a1e0cb3 100644 --- a/components/page_load_metrics/browser/metrics_web_contents_observer.h +++ b/components/page_load_metrics/browser/metrics_web_contents_observer.h
@@ -16,8 +16,6 @@ #include "content/public/browser/web_contents_user_data.h" #include "net/base/net_errors.h" -class PageLoadMetricsObserverTest; - namespace content { class NavigationHandle; class RenderFrameHost; @@ -27,72 +25,17 @@ class Message; } // namespace IPC -namespace rappor { -class RapporService; -} - namespace page_load_metrics { class PageLoadTracker; -// These constants are for keeping the tests in sync. -const char kHistogramCommit[] = "PageLoad.Timing2.NavigationToCommit"; -const char kHistogramFirstLayout[] = "PageLoad.Timing2.NavigationToFirstLayout"; -const char kHistogramFirstTextPaint[] = - "PageLoad.Timing2.NavigationToFirstTextPaint"; -const char kHistogramDomContentLoaded[] = - "PageLoad.Timing2.NavigationToDOMContentLoadedEventFired"; -const char kHistogramLoad[] = "PageLoad.Timing2.NavigationToLoadEventFired"; -const char kHistogramFirstPaint[] = "PageLoad.Timing2.NavigationToFirstPaint"; -const char kHistogramFirstImagePaint[] = - "PageLoad.Timing2.NavigationToFirstImagePaint"; -const char kHistogramFirstContentfulPaint[] = - "PageLoad.Timing2.NavigationToFirstContentfulPaint"; -const char kBackgroundHistogramCommit[] = - "PageLoad.Timing2.NavigationToCommit.Background"; -const char kBackgroundHistogramFirstLayout[] = - "PageLoad.Timing2.NavigationToFirstLayout.Background"; -const char kBackgroundHistogramFirstTextPaint[] = - "PageLoad.Timing2.NavigationToFirstTextPaint.Background"; -const char kBackgroundHistogramDomContentLoaded[] = - "PageLoad.Timing2.NavigationToDOMContentLoadedEventFired.Background"; -const char kBackgroundHistogramLoad[] = - "PageLoad.Timing2.NavigationToLoadEventFired.Background"; -const char kBackgroundHistogramFirstPaint[] = - "PageLoad.Timing2.NavigationToFirstPaint.Background"; -const char kBackgroundHistogramFirstImagePaint[] = - "PageLoad.Timing2.NavigationToFirstImagePaint.Background."; -const char kBackgroundHistogramFirstContentfulPaint[] = - "PageLoad.Timing2.NavigationToFirstContentfulPaint.Background"; +namespace internal { -const char kHistogramFirstContentfulPaintHigh[] = - "PageLoad.Timing2.NavigationToFirstContentfulPaint.HighResolutionClock"; -const char kHistogramFirstContentfulPaintLow[] = - "PageLoad.Timing2.NavigationToFirstContentfulPaint.LowResolutionClock"; +extern const char kProvisionalEvents[]; +extern const char kBackgroundProvisionalEvents[]; +extern const char kErrorEvents[]; -const char kHistogramFirstBackground[] = - "PageLoad.Timing2.NavigationToFirstBackground"; -const char kHistogramFirstForeground[] = - "PageLoad.Timing2.NavigationToFirstForeground"; - -const char kHistogramBackgroundBeforePaint[] = - "PageLoad.Timing2.NavigationToFirstBackground.AfterCommit.BeforePaint"; -const char kHistogramBackgroundBeforeCommit[] = - "PageLoad.Timing2.NavigationToFirstBackground.BeforeCommit"; - -const char kProvisionalEvents[] = "PageLoad.Events.Provisional"; -const char kBackgroundProvisionalEvents[] = - "PageLoad.Events.Provisional.Background"; - -const char kErrorEvents[] = "PageLoad.Events.InternalError"; - -const char kRapporMetricsNameCoarseTiming[] = - "PageLoad.CoarseTiming.NavigationToFirstContentfulPaint"; - -// NOTE: Some of these histograms are separated into a separate histogram -// specified by the ".Background" suffix. For these events, we put them into the -// background histogram if the web contents was ever in the background from -// navigation start to the event in question. +} // namespace internal // ProvisionalLoadEvents count all main frame navigations before they commit. // The events in this enum are all disjoint, and summing them yields the total @@ -171,14 +114,12 @@ class PageLoadMetricsEmbedderInterface { public: virtual ~PageLoadMetricsEmbedderInterface() {} - virtual rappor::RapporService* GetRapporService() = 0; virtual bool IsPrerendering(content::WebContents* web_contents) = 0; virtual void RegisterObservers(PageLoadTracker* metrics) = 0; }; // This class tracks a given page load, starting from navigation start / -// provisional load, until a new navigation commits or the navigation fails. It -// also records RAPPOR/UMA about the page load. +// provisional load, until a new navigation commits or the navigation fails. // MetricsWebContentsObserver manages a set of provisional PageLoadTrackers, as // well as a committed PageLoadTracker. class PageLoadTracker { @@ -219,7 +160,6 @@ const GURL& committed_url(); void RecordTimingHistograms(const PageLoadExtraInfo& info); - void RecordRappor(const PageLoadExtraInfo& info); void UpdateAbortInternal(UserAbortType abort_type, const base::TimeTicks& timestamp); @@ -229,8 +169,9 @@ // The navigation start in TimeTicks, not the wall time reported by Blink. const base::TimeTicks navigation_start_; - // Time this navigation was committed, or zero if this navigation hasn't - // committed yet. + // URL and time this page load was committed. If this page load hasn't + // committed, |committed_url_| will be empty, and |commit_time_| will be zero. + GURL committed_url_; base::TimeTicks commit_time_; // Will be ABORT_NONE if we have not aborted this load yet. Otherwise will @@ -246,7 +187,6 @@ bool started_in_foreground_; PageLoadTiming timing_; - GURL url_; // Interface to chrome features. Must outlive the class. PageLoadMetricsEmbedderInterface* const embedder_interface_; @@ -263,8 +203,6 @@ public content::WebContentsUserData<MetricsWebContentsObserver> { public: // Note that the returned metrics is owned by the web contents. - // The caller must guarantee that the RapporService (if non-null) will - // outlive the WebContents. static MetricsWebContentsObserver* CreateForWebContents( content::WebContents* web_contents, scoped_ptr<PageLoadMetricsEmbedderInterface> embedder_interface);
diff --git a/components/page_load_metrics/browser/metrics_web_contents_observer_unittest.cc b/components/page_load_metrics/browser/metrics_web_contents_observer_unittest.cc index 668282a..16bffa7 100644 --- a/components/page_load_metrics/browser/metrics_web_contents_observer_unittest.cc +++ b/components/page_load_metrics/browser/metrics_web_contents_observer_unittest.cc
@@ -4,14 +4,15 @@ #include "components/page_load_metrics/browser/metrics_web_contents_observer.h" +#include <vector> + #include "base/macros.h" #include "base/memory/scoped_ptr.h" #include "base/process/kill.h" #include "base/test/histogram_tester.h" #include "base/time/time.h" +#include "components/page_load_metrics/browser/page_load_metrics_observer.h" #include "components/page_load_metrics/common/page_load_metrics_messages.h" -#include "components/rappor/rappor_utils.h" -#include "components/rappor/test_rappor_service.h" #include "content/public/browser/navigation_handle.h" #include "content/public/browser/render_frame_host.h" #include "content/public/test/test_renderer_host.h" @@ -26,28 +27,49 @@ const char kDefaultTestUrlAnchor[] = "https://google.com#samepage"; const char kDefaultTestUrl2[] = "https://whatever.com"; -} // namespace +// Simple PageLoadMetricsObserver that copies observed PageLoadTimings into the +// provided std::vector, so they can be analyzed by unit tests. +class TestPageLoadMetricsObserver : public PageLoadMetricsObserver { + public: + explicit TestPageLoadMetricsObserver( + std::vector<PageLoadTiming>* observed_timings) + : observed_timings_(observed_timings) {} + + void OnComplete(const PageLoadTiming& timing, + const PageLoadExtraInfo&) override { + observed_timings_->push_back(timing); + } + + private: + std::vector<PageLoadTiming>* const observed_timings_; +}; class TestPageLoadMetricsEmbedderInterface : public PageLoadMetricsEmbedderInterface { public: TestPageLoadMetricsEmbedderInterface() : is_prerendering_(false) {} - rappor::TestRapporService* GetRapporService() override { - return &rappor_tester_; - } + bool IsPrerendering(content::WebContents* web_contents) override { return is_prerendering_; } - void RegisterObservers(PageLoadTracker* tracker) override {} void set_is_prerendering(bool is_prerendering) { is_prerendering_ = is_prerendering; } + void RegisterObservers(PageLoadTracker* tracker) override { + tracker->AddObserver( + make_scoped_ptr(new TestPageLoadMetricsObserver(&observed_timings_))); + } + const std::vector<PageLoadTiming>& observed_timings() const { + return observed_timings_; + } private: + std::vector<PageLoadTiming> observed_timings_; bool is_prerendering_; - rappor::TestRapporService rappor_tester_; }; +} // namespace + class MetricsWebContentsObserverTest : public content::RenderViewHostTestHarness { public: @@ -68,37 +90,42 @@ observer_->WasShown(); } - void AssertNoHistogramsLogged() { - histogram_tester_.ExpectTotalCount(kHistogramDomContentLoaded, 0); - histogram_tester_.ExpectTotalCount(kHistogramLoad, 0); - histogram_tester_.ExpectTotalCount(kHistogramFirstLayout, 0); - histogram_tester_.ExpectTotalCount(kHistogramFirstTextPaint, 0); - } - void CheckProvisionalEvent(ProvisionalLoadEvent event, int count, bool background) { if (background) { - histogram_tester_.ExpectBucketCount(kBackgroundProvisionalEvents, event, - count); + histogram_tester_.ExpectBucketCount( + internal::kBackgroundProvisionalEvents, event, count); num_provisional_events_bg_ += count; } else { - histogram_tester_.ExpectBucketCount(kProvisionalEvents, event, count); + histogram_tester_.ExpectBucketCount(internal::kProvisionalEvents, event, + count); num_provisional_events_ += count; } } void CheckErrorEvent(InternalErrorLoadEvent error, int count) { - histogram_tester_.ExpectBucketCount(kErrorEvents, error, count); + histogram_tester_.ExpectBucketCount(internal::kErrorEvents, error, count); num_errors_ += count; } void CheckTotalEvents() { - histogram_tester_.ExpectTotalCount(kProvisionalEvents, + histogram_tester_.ExpectTotalCount(internal::kProvisionalEvents, num_provisional_events_); - histogram_tester_.ExpectTotalCount(kBackgroundProvisionalEvents, + histogram_tester_.ExpectTotalCount(internal::kBackgroundProvisionalEvents, num_provisional_events_bg_); - histogram_tester_.ExpectTotalCount(kErrorEvents, num_errors_); + histogram_tester_.ExpectTotalCount(internal::kErrorEvents, num_errors_); + } + + void AssertNoNonEmptyTimingReported() { + ASSERT_FALSE(embedder_interface_->observed_timings().empty()); + for (const auto& timing : embedder_interface_->observed_timings()) { + ASSERT_TRUE(timing.IsEmpty()); + } + } + + void AssertNoTimingReported() { + ASSERT_TRUE(embedder_interface_->observed_timings().empty()); } protected: @@ -114,10 +141,6 @@ DISALLOW_COPY_AND_ASSIGN(MetricsWebContentsObserverTest); }; -TEST_F(MetricsWebContentsObserverTest, NoMetrics) { - AssertNoHistogramsLogged(); -} - TEST_F(MetricsWebContentsObserverTest, NotInMainFrame) { base::TimeDelta first_layout = base::TimeDelta::FromMilliseconds(1); @@ -145,7 +168,7 @@ // Navigate again to see if the timing updated for a subframe message. web_contents_tester->NavigateAndCommit(GURL(kDefaultTestUrl)); - AssertNoHistogramsLogged(); + AssertNoNonEmptyTimingReported(); } TEST_F(MetricsWebContentsObserverTest, SamePageNoTrigger) { @@ -164,163 +187,7 @@ web_contents()->GetMainFrame()); web_contents_tester->NavigateAndCommit(GURL(kDefaultTestUrlAnchor)); // A same page navigation shouldn't trigger logging UMA for the original. - AssertNoHistogramsLogged(); -} - -TEST_F(MetricsWebContentsObserverTest, SamePageNoTriggerUntilTrueNavCommit) { - base::TimeDelta first_layout = base::TimeDelta::FromMilliseconds(1); - - PageLoadTiming timing; - timing.navigation_start = base::Time::FromDoubleT(1); - timing.first_layout = first_layout; - - content::WebContentsTester* web_contents_tester = - content::WebContentsTester::For(web_contents()); - web_contents_tester->NavigateAndCommit(GURL(kDefaultTestUrl)); - - observer_->OnMessageReceived( - PageLoadMetricsMsg_TimingUpdated(observer_->routing_id(), timing), - web_contents()->GetMainFrame()); - web_contents_tester->NavigateAndCommit(GURL(kDefaultTestUrlAnchor)); - // A same page navigation shouldn't trigger logging UMA for the original. - AssertNoHistogramsLogged(); - - // But we should keep the timing info and log it when we get another - // navigation. - web_contents_tester->NavigateAndCommit(GURL(kDefaultTestUrl2)); - histogram_tester_.ExpectTotalCount(kHistogramCommit, 1); - histogram_tester_.ExpectTotalCount(kHistogramDomContentLoaded, 0); - histogram_tester_.ExpectTotalCount(kHistogramLoad, 0); - histogram_tester_.ExpectTotalCount(kHistogramFirstLayout, 1); - histogram_tester_.ExpectBucketCount(kHistogramFirstLayout, - first_layout.InMilliseconds(), 1); - histogram_tester_.ExpectTotalCount(kHistogramFirstTextPaint, 0); -} - -TEST_F(MetricsWebContentsObserverTest, SingleMetricAfterCommit) { - base::TimeDelta first_layout = base::TimeDelta::FromMilliseconds(1); - - PageLoadTiming timing; - timing.navigation_start = base::Time::FromDoubleT(1); - timing.first_layout = first_layout; - - content::WebContentsTester* web_contents_tester = - content::WebContentsTester::For(web_contents()); - web_contents_tester->NavigateAndCommit(GURL(kDefaultTestUrl)); - - observer_->OnMessageReceived( - PageLoadMetricsMsg_TimingUpdated(observer_->routing_id(), timing), - web_contents()->GetMainFrame()); - - AssertNoHistogramsLogged(); - - // Navigate again to force histogram recording. - web_contents_tester->NavigateAndCommit(GURL(kDefaultTestUrl2)); - - histogram_tester_.ExpectTotalCount(kHistogramCommit, 1); - histogram_tester_.ExpectTotalCount(kHistogramDomContentLoaded, 0); - histogram_tester_.ExpectTotalCount(kHistogramLoad, 0); - histogram_tester_.ExpectTotalCount(kHistogramFirstLayout, 1); - histogram_tester_.ExpectBucketCount(kHistogramFirstLayout, - first_layout.InMilliseconds(), 1); - histogram_tester_.ExpectTotalCount(kHistogramFirstTextPaint, 0); -} - -TEST_F(MetricsWebContentsObserverTest, MultipleMetricsAfterCommits) { - base::TimeDelta first_layout_1 = base::TimeDelta::FromMilliseconds(1); - base::TimeDelta first_layout_2 = base::TimeDelta::FromMilliseconds(20); - base::TimeDelta response = base::TimeDelta::FromMilliseconds(10); - base::TimeDelta first_text_paint = base::TimeDelta::FromMilliseconds(30); - base::TimeDelta dom_content = base::TimeDelta::FromMilliseconds(40); - base::TimeDelta load = base::TimeDelta::FromMilliseconds(100); - - PageLoadTiming timing; - timing.navigation_start = base::Time::FromDoubleT(1); - timing.first_layout = first_layout_1; - timing.response_start = response; - timing.first_text_paint = first_text_paint; - timing.dom_content_loaded_event_start = dom_content; - timing.load_event_start = load; - - content::WebContentsTester* web_contents_tester = - content::WebContentsTester::For(web_contents()); - web_contents_tester->NavigateAndCommit(GURL(kDefaultTestUrl)); - - observer_->OnMessageReceived( - PageLoadMetricsMsg_TimingUpdated(observer_->routing_id(), timing), - web_contents()->GetMainFrame()); - - web_contents_tester->NavigateAndCommit(GURL(kDefaultTestUrl2)); - - PageLoadTiming timing2; - timing2.navigation_start = base::Time::FromDoubleT(200); - timing2.first_layout = first_layout_2; - - observer_->OnMessageReceived( - PageLoadMetricsMsg_TimingUpdated(observer_->routing_id(), timing2), - web_contents()->GetMainFrame()); - - web_contents_tester->NavigateAndCommit(GURL(kDefaultTestUrl)); - - histogram_tester_.ExpectTotalCount(kHistogramCommit, 2); - histogram_tester_.ExpectBucketCount(kHistogramFirstLayout, - first_layout_1.InMilliseconds(), 1); - histogram_tester_.ExpectTotalCount(kHistogramFirstLayout, 2); - histogram_tester_.ExpectBucketCount(kHistogramFirstLayout, - first_layout_1.InMilliseconds(), 1); - histogram_tester_.ExpectBucketCount(kHistogramFirstLayout, - first_layout_2.InMilliseconds(), 1); - - histogram_tester_.ExpectTotalCount(kHistogramFirstTextPaint, 1); - histogram_tester_.ExpectBucketCount(kHistogramFirstTextPaint, - first_text_paint.InMilliseconds(), 1); - - histogram_tester_.ExpectTotalCount(kHistogramDomContentLoaded, 1); - histogram_tester_.ExpectBucketCount(kHistogramDomContentLoaded, - dom_content.InMilliseconds(), 1); - - histogram_tester_.ExpectTotalCount(kHistogramLoad, 1); - histogram_tester_.ExpectBucketCount(kHistogramLoad, load.InMilliseconds(), 1); -} - -TEST_F(MetricsWebContentsObserverTest, BackgroundDifferentHistogram) { - base::TimeDelta first_layout = base::TimeDelta::FromSeconds(2); - - PageLoadTiming timing; - timing.navigation_start = base::Time::FromDoubleT(1); - timing.first_layout = first_layout; - - content::WebContentsTester* web_contents_tester = - content::WebContentsTester::For(web_contents()); - - // Simulate "Open link in new tab." - observer_->WasHidden(); - web_contents_tester->NavigateAndCommit(GURL(kDefaultTestUrl)); - - observer_->OnMessageReceived( - PageLoadMetricsMsg_TimingUpdated(observer_->routing_id(), timing), - web_contents()->GetMainFrame()); - - // Simulate switching to the tab and making another navigation. - observer_->WasShown(); - AssertNoHistogramsLogged(); - - // Navigate again to force histogram recording. - web_contents_tester->NavigateAndCommit(GURL(kDefaultTestUrl2)); - - histogram_tester_.ExpectTotalCount(kBackgroundHistogramCommit, 1); - histogram_tester_.ExpectTotalCount(kBackgroundHistogramDomContentLoaded, 0); - histogram_tester_.ExpectTotalCount(kBackgroundHistogramLoad, 0); - histogram_tester_.ExpectTotalCount(kBackgroundHistogramFirstLayout, 1); - histogram_tester_.ExpectBucketCount(kBackgroundHistogramFirstLayout, - first_layout.InMilliseconds(), 1); - histogram_tester_.ExpectTotalCount(kBackgroundHistogramFirstTextPaint, 0); - - histogram_tester_.ExpectTotalCount(kHistogramCommit, 0); - histogram_tester_.ExpectTotalCount(kHistogramDomContentLoaded, 0); - histogram_tester_.ExpectTotalCount(kHistogramLoad, 0); - histogram_tester_.ExpectTotalCount(kHistogramFirstLayout, 0); - histogram_tester_.ExpectTotalCount(kHistogramFirstTextPaint, 0); + AssertNoNonEmptyTimingReported(); } TEST_F(MetricsWebContentsObserverTest, DontLogPrerender) { @@ -337,99 +204,7 @@ web_contents()->GetMainFrame()); web_contents_tester->NavigateAndCommit(GURL(kDefaultTestUrl2)); - AssertNoHistogramsLogged(); -} - -TEST_F(MetricsWebContentsObserverTest, OnlyBackgroundLaterEvents) { - PageLoadTiming timing; - timing.navigation_start = base::Time::FromDoubleT(1); - // Set these events at 1 microsecond so they are definitely occur before we - // background the tab later in the test. - timing.response_start = base::TimeDelta::FromMicroseconds(1); - timing.dom_content_loaded_event_start = base::TimeDelta::FromMicroseconds(1); - - content::WebContentsTester* web_contents_tester = - content::WebContentsTester::For(web_contents()); - - web_contents_tester->NavigateAndCommit(GURL(kDefaultTestUrl)); - observer_->OnMessageReceived( - PageLoadMetricsMsg_TimingUpdated(observer_->routing_id(), timing), - web_contents()->GetMainFrame()); - - // Background the tab, then forground it. - observer_->WasHidden(); - observer_->WasShown(); - timing.first_layout = base::TimeDelta::FromSeconds(3); - timing.first_text_paint = base::TimeDelta::FromSeconds(4); - observer_->OnMessageReceived( - PageLoadMetricsMsg_TimingUpdated(observer_->routing_id(), timing), - web_contents()->GetMainFrame()); - - // Navigate again to force histogram recording. - web_contents_tester->NavigateAndCommit(GURL(kDefaultTestUrl2)); - - histogram_tester_.ExpectTotalCount(kBackgroundHistogramCommit, 0); - histogram_tester_.ExpectTotalCount(kBackgroundHistogramDomContentLoaded, 0); - histogram_tester_.ExpectTotalCount(kBackgroundHistogramLoad, 0); - histogram_tester_.ExpectTotalCount(kBackgroundHistogramFirstLayout, 1); - histogram_tester_.ExpectBucketCount(kBackgroundHistogramFirstLayout, - timing.first_layout.InMilliseconds(), 1); - histogram_tester_.ExpectTotalCount(kBackgroundHistogramFirstTextPaint, 1); - histogram_tester_.ExpectBucketCount(kBackgroundHistogramFirstTextPaint, - timing.first_text_paint.InMilliseconds(), - 1); - - histogram_tester_.ExpectTotalCount(kHistogramCommit, 1); - histogram_tester_.ExpectTotalCount(kHistogramDomContentLoaded, 1); - histogram_tester_.ExpectBucketCount( - kHistogramDomContentLoaded, - timing.dom_content_loaded_event_start.InMilliseconds(), 1); - histogram_tester_.ExpectTotalCount(kHistogramLoad, 0); - histogram_tester_.ExpectTotalCount(kHistogramFirstLayout, 0); - histogram_tester_.ExpectTotalCount(kHistogramFirstTextPaint, 0); -} - -TEST_F(MetricsWebContentsObserverTest, DontBackgroundQuickerLoad) { - // Set this event at 1 microsecond so it occurs before we foreground later in - // the test. - base::TimeDelta first_layout = base::TimeDelta::FromMicroseconds(1); - - PageLoadTiming timing; - timing.navigation_start = base::Time::FromDoubleT(1); - timing.first_layout = first_layout; - - observer_->WasHidden(); - - // Open in new tab - content::WebContentsTester* web_contents_tester = - content::WebContentsTester::For(web_contents()); - - web_contents_tester->StartNavigation(GURL(kDefaultTestUrl)); - - content::RenderFrameHostTester* rfh_tester = - content::RenderFrameHostTester::For(main_rfh()); - - // Switch to the tab - observer_->WasShown(); - - // Start another provisional load - web_contents_tester->StartNavigation(GURL(kDefaultTestUrl2)); - rfh_tester->SimulateNavigationCommit(GURL(kDefaultTestUrl2)); - observer_->OnMessageReceived( - PageLoadMetricsMsg_TimingUpdated(observer_->routing_id(), timing), - main_rfh()); - rfh_tester->SimulateNavigationStop(); - - // Navigate again to see if the timing updated for the foregrounded load. - web_contents_tester->NavigateAndCommit(GURL(kDefaultTestUrl)); - - histogram_tester_.ExpectTotalCount(kHistogramCommit, 1); - histogram_tester_.ExpectTotalCount(kHistogramDomContentLoaded, 0); - histogram_tester_.ExpectTotalCount(kHistogramLoad, 0); - histogram_tester_.ExpectTotalCount(kHistogramFirstLayout, 1); - histogram_tester_.ExpectBucketCount(kHistogramFirstLayout, - first_layout.InMilliseconds(), 1); - histogram_tester_.ExpectTotalCount(kHistogramFirstTextPaint, 0); + AssertNoTimingReported(); } TEST_F(MetricsWebContentsObserverTest, FailProvisionalLoad) { @@ -463,25 +238,6 @@ CheckTotalEvents(); } -TEST_F(MetricsWebContentsObserverTest, BackgroundBeforePaint) { - page_load_metrics::PageLoadTiming timing; - timing.navigation_start = base::Time::FromDoubleT(1); - timing.first_paint = base::TimeDelta::FromSeconds(10); - content::WebContentsTester* web_contents_tester = - content::WebContentsTester::For(web_contents()); - web_contents_tester->NavigateAndCommit(GURL("https://www.google.com")); - // Background the tab and go for a coffee or something. - observer_->WasHidden(); - observer_->OnMessageReceived( - PageLoadMetricsMsg_TimingUpdated(observer_->routing_id(), timing), - main_rfh()); - // Come back and start browsing again. - observer_->WasShown(); - // Simulate the user performaning another navigation. - web_contents_tester->NavigateAndCommit(GURL("https://www.example.com")); - histogram_tester_.ExpectTotalCount(kHistogramBackgroundBeforePaint, 1); -} - TEST_F(MetricsWebContentsObserverTest, AbortProvisionalLoadInBackground) { content::WebContentsTester* web_contents_tester = content::WebContentsTester::For(web_contents()); @@ -588,70 +344,7 @@ main_rfh()); // Navigate again to force histogram logging. web_contents_tester->NavigateAndCommit(GURL(kDefaultTestUrl2)); - AssertNoHistogramsLogged(); -} - -TEST_F(MetricsWebContentsObserverTest, NoRappor) { - rappor::TestSample::Shadow* sample_obj = - embedder_interface_->GetRapporService()->GetRecordedSampleForMetric( - kRapporMetricsNameCoarseTiming); - EXPECT_EQ(sample_obj, nullptr); -} - -TEST_F(MetricsWebContentsObserverTest, RapporLongPageLoad) { - PageLoadTiming timing; - timing.navigation_start = base::Time::FromDoubleT(1); - timing.first_image_paint = base::TimeDelta::FromSeconds(40); - - content::WebContentsTester* web_contents_tester = - content::WebContentsTester::For(web_contents()); - web_contents_tester->NavigateAndCommit(GURL(kDefaultTestUrl)); - - observer_->OnMessageReceived( - PageLoadMetricsMsg_TimingUpdated(observer_->routing_id(), timing), - main_rfh()); - - // Navigate again to force logging RAPPOR. - web_contents_tester->NavigateAndCommit(GURL(kDefaultTestUrl2)); - rappor::TestSample::Shadow* sample_obj = - embedder_interface_->GetRapporService()->GetRecordedSampleForMetric( - kRapporMetricsNameCoarseTiming); - const auto& string_it = sample_obj->string_fields.find("Domain"); - EXPECT_NE(string_it, sample_obj->string_fields.end()); - EXPECT_EQ(rappor::GetDomainAndRegistrySampleFromGURL(GURL(kDefaultTestUrl)), - string_it->second); - - const auto& flag_it = sample_obj->flag_fields.find("IsSlow"); - EXPECT_NE(flag_it, sample_obj->flag_fields.end()); - EXPECT_EQ(1u, flag_it->second); -} - -TEST_F(MetricsWebContentsObserverTest, RapporQuickPageLoad) { - PageLoadTiming timing; - timing.navigation_start = base::Time::FromDoubleT(1); - timing.first_text_paint = base::TimeDelta::FromSeconds(1); - - content::WebContentsTester* web_contents_tester = - content::WebContentsTester::For(web_contents()); - web_contents_tester->NavigateAndCommit(GURL(kDefaultTestUrl)); - - observer_->OnMessageReceived( - PageLoadMetricsMsg_TimingUpdated(observer_->routing_id(), timing), - main_rfh()); - - // Navigate again to force logging RAPPOR. - web_contents_tester->NavigateAndCommit(GURL(kDefaultTestUrl2)); - rappor::TestSample::Shadow* sample_obj = - embedder_interface_->GetRapporService()->GetRecordedSampleForMetric( - kRapporMetricsNameCoarseTiming); - const auto& string_it = sample_obj->string_fields.find("Domain"); - EXPECT_NE(string_it, sample_obj->string_fields.end()); - EXPECT_EQ(rappor::GetDomainAndRegistrySampleFromGURL(GURL(kDefaultTestUrl)), - string_it->second); - - const auto& flag_it = sample_obj->flag_fields.find("IsSlow"); - EXPECT_NE(flag_it, sample_obj->flag_fields.end()); - EXPECT_EQ(0u, flag_it->second); + AssertNoTimingReported(); } } // namespace page_load_metrics
diff --git a/components/page_load_metrics/browser/page_load_metrics_observer.cc b/components/page_load_metrics/browser/page_load_metrics_observer.cc index 6c5015c..b41c347 100644 --- a/components/page_load_metrics/browser/page_load_metrics_observer.cc +++ b/components/page_load_metrics/browser/page_load_metrics_observer.cc
@@ -10,15 +10,16 @@ const base::TimeDelta& first_background_time, const base::TimeDelta& first_foreground_time, bool started_in_foreground, + const GURL& committed_url, const base::TimeDelta& time_to_commit, UserAbortType abort_type, const base::TimeDelta& time_to_abort) : first_background_time(first_background_time), first_foreground_time(first_foreground_time), started_in_foreground(started_in_foreground), + committed_url(committed_url), time_to_commit(time_to_commit), abort_type(abort_type), - time_to_abort(time_to_abort) { -} + time_to_abort(time_to_abort) {} } // namespace page_load_metrics
diff --git a/components/page_load_metrics/browser/page_load_metrics_observer.h b/components/page_load_metrics/browser/page_load_metrics_observer.h index d8c50a55..7e01f37 100644 --- a/components/page_load_metrics/browser/page_load_metrics_observer.h +++ b/components/page_load_metrics/browser/page_load_metrics_observer.h
@@ -8,6 +8,7 @@ #include "base/macros.h" #include "components/page_load_metrics/common/page_load_timing.h" #include "content/public/browser/navigation_handle.h" +#include "url/gurl.h" namespace page_load_metrics { @@ -49,6 +50,7 @@ PageLoadExtraInfo(const base::TimeDelta& first_background_time, const base::TimeDelta& first_foreground_time, bool started_in_foreground, + const GURL& committed_url, const base::TimeDelta& time_to_commit, UserAbortType abort_type, const base::TimeDelta& time_to_abort); @@ -66,6 +68,10 @@ // True if the page load started in the foreground. const bool started_in_foreground; + // Committed URL. If the page load did not commit, |committed_url| will be + // empty. + const GURL committed_url; + // Time from navigation start until commit. If the page load did not commit, // |time_to_commit| will be zero. const base::TimeDelta time_to_commit;
diff --git a/components/resources/autofill_scaled_resources.grdp b/components/resources/autofill_scaled_resources.grdp index 83b682c3..bc1d884c 100644 --- a/components/resources/autofill_scaled_resources.grdp +++ b/components/resources/autofill_scaled_resources.grdp
@@ -6,7 +6,7 @@ <structure type="chrome_scaled_image" name="IDR_AUTOFILL_CC_MASTERCARD" file="autofill/mastercard.png" /> <structure type="chrome_scaled_image" name="IDR_AUTOFILL_CC_VISA" file="autofill/visa.png" /> - <if expr="is_android and not use_aura"> + <if expr="is_android"> <!-- These are not used on desktop, only Android, so use a placeholder file. TODO(rouslan): Remove non-keyboard-accessory icon when keyboard accessory becomes default on Android. --> @@ -18,4 +18,8 @@ <structure type="chrome_scaled_image" name="IDR_CREDIT_CARD_CVC_HINT" file="autofill/credit_card_cvc_hint.png" /> <structure type="chrome_scaled_image" name="IDR_CREDIT_CARD_CVC_HINT_AMEX" file="autofill/credit_card_cvc_hint_amex.png" /> <structure type="chrome_scaled_image" name="IDR_INFOBAR_AUTOFILL_CC" file="autofill/infobar_autofill_cc.png" /> + <if expr="is_macosx or is_ios"> + <structure type="chrome_scaled_image" name="IDR_AUTOFILL_TOOLTIP_ICON" file="autofill/autofill_tooltip_icon.png" /> + <structure type="chrome_scaled_image" name="IDR_AUTOFILL_TOOLTIP_ICON_H" file="autofill/autofill_tooltip_icon_hover.png" /> + </if> </grit-part>
diff --git a/chrome/app/theme/default_100_percent/legacy/autofill_tooltip_icon.png b/components/resources/default_100_percent/autofill/autofill_tooltip_icon.png similarity index 100% rename from chrome/app/theme/default_100_percent/legacy/autofill_tooltip_icon.png rename to components/resources/default_100_percent/autofill/autofill_tooltip_icon.png Binary files differ
diff --git a/chrome/app/theme/default_100_percent/legacy/autofill_tooltip_icon_hover.png b/components/resources/default_100_percent/autofill/autofill_tooltip_icon_hover.png similarity index 100% rename from chrome/app/theme/default_100_percent/legacy/autofill_tooltip_icon_hover.png rename to components/resources/default_100_percent/autofill/autofill_tooltip_icon_hover.png Binary files differ
diff --git a/chrome/app/theme/default_200_percent/legacy/autofill_tooltip_icon.png b/components/resources/default_200_percent/autofill/autofill_tooltip_icon.png similarity index 100% rename from chrome/app/theme/default_200_percent/legacy/autofill_tooltip_icon.png rename to components/resources/default_200_percent/autofill/autofill_tooltip_icon.png Binary files differ
diff --git a/chrome/app/theme/default_200_percent/legacy/autofill_tooltip_icon_hover.png b/components/resources/default_200_percent/autofill/autofill_tooltip_icon_hover.png similarity index 100% rename from chrome/app/theme/default_200_percent/legacy/autofill_tooltip_icon_hover.png rename to components/resources/default_200_percent/autofill/autofill_tooltip_icon_hover.png Binary files differ
diff --git a/components/safe_browsing_db.gypi b/components/safe_browsing_db.gypi index 60b5127..4c3b7e5 100644 --- a/components/safe_browsing_db.gypi +++ b/components/safe_browsing_db.gypi
@@ -11,6 +11,7 @@ 'dependencies': [ '../base/base.gyp:base', '../crypto/crypto.gyp:crypto', + ':safebrowsing_proto', ], 'sources': [ # Note: sources list duplicated in GN build.
diff --git a/components/safe_browsing_db/BUILD.gn b/components/safe_browsing_db/BUILD.gn index 12fd9a5..8203128 100644 --- a/components/safe_browsing_db/BUILD.gn +++ b/components/safe_browsing_db/BUILD.gn
@@ -13,6 +13,7 @@ group("safe_browsing_db") { deps = [ ":prefix_set", + ":proto", ":util", ] }
diff --git a/components/safe_browsing_db/safebrowsing.proto b/components/safe_browsing_db/safebrowsing.proto index 89b9f6d..6fe0f53c 100644 --- a/components/safe_browsing_db/safebrowsing.proto +++ b/components/safe_browsing_db/safebrowsing.proto
@@ -251,7 +251,7 @@ THREAT_TYPE_UNSPECIFIED = 0; // Malware threat type. - MALWARE = 1; + MALWARE_THREAT = 1; // Social engineering threat type. SOCIAL_ENGINEERING_PUBLIC = 2; @@ -275,10 +275,10 @@ PLATFORM_TYPE_UNSPECIFIED = 0; // Threat posed to Windows. - WINDOWS = 1; + WINDOWS_PLATFORM = 1; // Threat posed to Linux. - LINUX = 2; + LINUX_PLATFORM = 2; // Threat posed to Android. // This cannot be ANDROID because that symbol is defined for android builds @@ -286,10 +286,10 @@ ANDROID_PLATFORM = 3; // Threat posed to OSX. - OSX = 4; + OSX_PLATFORM = 4; // Threat posed to iOS. - IOS = 5; + IOS_PLATFORM = 5; // Threat posed to at least one of the defined platforms. ANY_PLATFORM = 6; @@ -298,7 +298,7 @@ ALL_PLATFORMS = 7; // Threat posed to Chrome. - CHROME = 8; + CHROME_PLATFORM = 8; } // The client metadata associated with Safe Browsing API requests.
diff --git a/components/scheduler/base/task_queue_impl.cc b/components/scheduler/base/task_queue_impl.cc index 8ec8ce2..b449e2d 100644 --- a/components/scheduler/base/task_queue_impl.cc +++ b/components/scheduler/base/task_queue_impl.cc
@@ -379,6 +379,8 @@ } void TaskQueueImpl::PumpQueueLocked(bool may_post_dowork) { + TRACE_EVENT1(disabled_by_default_tracing_category_, + "TaskQueueImpl::PumpQueueLocked", "queue", name_); TaskQueueManager* task_queue_manager = any_thread().task_queue_manager; if (!task_queue_manager) return;
diff --git a/components/scheduler/base/time_domain.cc b/components/scheduler/base/time_domain.cc index e23883e..a0173ea 100644 --- a/components/scheduler/base/time_domain.cc +++ b/components/scheduler/base/time_domain.cc
@@ -177,6 +177,17 @@ } } +void TimeDomain::ClearExpiredWakeups() { + LazyNow lazy_now(CreateLazyNow()); + while (!delayed_wakeup_multimap_.empty()) { + DelayedWakeupMultimap::iterator next_wakeup = + delayed_wakeup_multimap_.begin(); + if (next_wakeup->first > lazy_now.Now()) + break; + delayed_wakeup_multimap_.erase(next_wakeup); + } +} + bool TimeDomain::NextScheduledRunTime(base::TimeTicks* out_time) const { if (delayed_wakeup_multimap_.empty()) return false;
diff --git a/components/scheduler/base/time_domain.h b/components/scheduler/base/time_domain.h index e8691f3..e14eb03 100644 --- a/components/scheduler/base/time_domain.h +++ b/components/scheduler/base/time_domain.h
@@ -115,6 +115,12 @@ bool should_trigger_wakeup, const internal::TaskQueueImpl::Task* previous_task); + protected: + // Clears expired entries from |delayed_wakeup_multimap_|. Caution needs to be + // taken to ensure TaskQueueImpl::UpdateDelayedWorkQueue or + // TaskQueueImpl::Pump is called on the affected queues. + void ClearExpiredWakeups(); + private: void MoveNewlyUpdatableQueuesIntoUpdatableQueueSet();
diff --git a/components/scheduler/base/time_domain_unittest.cc b/components/scheduler/base/time_domain_unittest.cc index b863dd16..efcd3fc8 100644 --- a/components/scheduler/base/time_domain_unittest.cc +++ b/components/scheduler/base/time_domain_unittest.cc
@@ -15,6 +15,7 @@ #include "testing/gmock/include/gmock/gmock.h" using testing::_; +using testing::AnyNumber; using testing::Mock; namespace scheduler { @@ -27,6 +28,7 @@ ~MockTimeDomain() override {} + using TimeDomain::ClearExpiredWakeups; using TimeDomain::NextScheduledRunTime; using TimeDomain::NextScheduledTaskQueue; using TimeDomain::ScheduleDelayedWork; @@ -183,6 +185,32 @@ EXPECT_EQ(1UL, dummy_queue->delayed_work_queue()->Size()); } +TEST_F(TimeDomainTest, ClearExpiredWakeups) { + LazyNow lazy_now = time_domain_->CreateLazyNow(); + base::TimeDelta delay1 = base::TimeDelta::FromMilliseconds(10); + base::TimeDelta delay2 = base::TimeDelta::FromMilliseconds(20); + base::TimeTicks run_time1 = time_domain_->Now() + delay1; + base::TimeTicks run_time2 = time_domain_->Now() + delay2; + + EXPECT_CALL(*time_domain_.get(), RequestWakeup(_, _)).Times(AnyNumber()); + time_domain_->ScheduleDelayedWork(task_queue_.get(), run_time1, &lazy_now); + time_domain_->ScheduleDelayedWork(task_queue_.get(), run_time2, &lazy_now); + + base::TimeTicks next_run_time; + ASSERT_TRUE(time_domain_->NextScheduledRunTime(&next_run_time)); + EXPECT_EQ(run_time1, next_run_time); + + time_domain_->SetNow(run_time1); + time_domain_->ClearExpiredWakeups(); + + ASSERT_TRUE(time_domain_->NextScheduledRunTime(&next_run_time)); + EXPECT_EQ(run_time2, next_run_time); + + time_domain_->SetNow(run_time2); + time_domain_->ClearExpiredWakeups(); + ASSERT_FALSE(time_domain_->NextScheduledRunTime(&next_run_time)); +} + namespace { class MockObserver : public TimeDomain::Observer { public:
diff --git a/components/scheduler/base/virtual_time_domain.h b/components/scheduler/base/virtual_time_domain.h index 0242a62..6091b31 100644 --- a/components/scheduler/base/virtual_time_domain.h +++ b/components/scheduler/base/virtual_time_domain.h
@@ -28,6 +28,8 @@ // call TaskQueueManager::MaybeScheduleImmediateWork if needed. void AdvanceTo(base::TimeTicks now); + using TimeDomain::ClearExpiredWakeups; + protected: void OnRegisterWithTaskQueueManager( TaskQueueManager* task_queue_manager) override;
diff --git a/components/scheduler/child/webthread_impl_for_worker_scheduler.cc b/components/scheduler/child/webthread_impl_for_worker_scheduler.cc index 4c8335e..afdcb6d 100644 --- a/components/scheduler/child/webthread_impl_for_worker_scheduler.cc +++ b/components/scheduler/child/webthread_impl_for_worker_scheduler.cc
@@ -26,7 +26,8 @@ const char* name, base::Thread::Options options) : thread_(new base::Thread(name ? name : std::string())) { - thread_->StartWithOptions(options); + bool started = thread_->StartWithOptions(options); + CHECK(started); thread_task_runner_ = thread_->task_runner(); base::WaitableEvent completion(false, false);
diff --git a/components/scheduler/renderer/throttling_helper.cc b/components/scheduler/renderer/throttling_helper.cc index c7525720..673074cd 100644 --- a/components/scheduler/renderer/throttling_helper.cc +++ b/components/scheduler/renderer/throttling_helper.cc
@@ -36,12 +36,14 @@ } void ThrottlingHelper::Throttle(TaskQueue* task_queue) { + DCHECK_NE(task_queue, task_runner_.get()); throttled_queues_.insert(task_queue); task_queue->SetTimeDomain(time_domain_.get()); task_queue->SetPumpPolicy(TaskQueue::PumpPolicy::MANUAL); - MaybeSchedulePumpThrottledTasksLocked(FROM_HERE); + if (!task_queue->IsEmpty()) + MaybeSchedulePumpThrottledTasksLocked(FROM_HERE); } void ThrottlingHelper::Unthrottle(TaskQueue* task_queue) { @@ -73,16 +75,23 @@ pending_pump_throttled_tasks_ = false; time_domain_->AdvanceTo(tick_clock_->NowTicks()); - bool work_to_do = false; for (TaskQueue* task_queue : throttled_queues_) { if (task_queue->IsEmpty()) continue; - work_to_do = true; task_queue->PumpQueue(false); } + // Make sure NextScheduledRunTime gives us an up-to date result. + time_domain_->ClearExpiredWakeups(); - if (work_to_do) + base::TimeTicks next_scheduled_delayed_task; + // Maybe schedule a call to ThrottlingHelper::PumpThrottledTasks if there is + // a pending delayed task. NOTE posting a non-delayed task in the future will + // result in ThrottlingHelper::OnTimeDomainHasImmediateWork being called. + // + // TODO(alexclarke): Consider taking next_scheduled_delayed_task into account + // inside MaybeSchedulePumpThrottledTasksLocked. + if (time_domain_->NextScheduledRunTime(&next_scheduled_delayed_task)) MaybeSchedulePumpThrottledTasksLocked(FROM_HERE); }
diff --git a/components/scheduler/renderer/throttling_helper.h b/components/scheduler/renderer/throttling_helper.h index dd4d0fd..537571c 100644 --- a/components/scheduler/renderer/throttling_helper.h +++ b/components/scheduler/renderer/throttling_helper.h
@@ -36,6 +36,8 @@ static base::TimeDelta DelayToNextRunTimeInSeconds(base::TimeTicks now); + const scoped_refptr<TaskQueue>& task_runner() const { return task_runner_; } + private: void PumpThrottledTasks(); void MaybeSchedulePumpThrottledTasksLocked( @@ -44,7 +46,7 @@ std::set<TaskQueue*> throttled_queues_; base::Closure pump_throttled_tasks_closure_; base::Closure forward_immediate_work_closure_; - scoped_refptr<base::SingleThreadTaskRunner> task_runner_; + scoped_refptr<TaskQueue> task_runner_; RendererSchedulerImpl* renderer_scheduler_; // NOT OWNED base::TickClock* tick_clock_; // NOT OWNED const char* tracing_category_; // NOT OWNED
diff --git a/components/scheduler/renderer/throttling_helper_unittest.cc b/components/scheduler/renderer/throttling_helper_unittest.cc index cc2df55..f2bddbe 100644 --- a/components/scheduler/renderer/throttling_helper_unittest.cc +++ b/components/scheduler/renderer/throttling_helper_unittest.cc
@@ -170,6 +170,13 @@ start_time + base::TimeDelta::FromMilliseconds(8300.0))); } +TEST_F(ThrottlingHelperTest, + ThrotlingAnEmptyQueueDoesNotPostPumpThrottledTasksLocked) { + throttling_helper_->Throttle(timer_queue_.get()); + + EXPECT_TRUE(throttling_helper_->task_runner()->IsEmpty()); +} + TEST_F(ThrottlingHelperTest, WakeUpForNonDelayedTask) { std::vector<base::TimeTicks> run_times; @@ -224,9 +231,7 @@ mock_task_runner_->RunTasksWhile( base::Bind(&MessageLoopTaskCounter, &task_count)); - // NOTE PumpThrottledTasks will always run at least twice because we can only - // detect if the queues have become empty before pumping. - EXPECT_EQ(2u, task_count); + EXPECT_EQ(1u, task_count); } } // namespace scheduler
diff --git a/components/search/search.cc b/components/search/search.cc index 807e476..cbc955235 100644 --- a/components/search/search.cc +++ b/components/search/search.cc
@@ -71,9 +71,6 @@ } // namespace -// Negative start-margin values prevent the "es_sm" parameter from being used. -const int kDisableStartMargin = -1; - bool IsInstantExtendedAPIEnabled() { #if defined(OS_IOS) return false;
diff --git a/components/search/search.h b/components/search/search.h index 3907f85c..d97b240 100644 --- a/components/search/search.h +++ b/components/search/search.h
@@ -19,10 +19,6 @@ namespace search { -// Use this value for "start margin" to prevent the "es_sm" parameter from -// being used. -extern const int kDisableStartMargin; - // Returns whether the Instant Extended API is enabled. bool IsInstantExtendedAPIEnabled();
diff --git a/components/search_engines/prepopulated_engines.json b/components/search_engines/prepopulated_engines.json index 8c4717d..f18125e 100644 --- a/components/search_engines/prepopulated_engines.json +++ b/components/search_engines/prepopulated_engines.json
@@ -30,7 +30,7 @@ // Increment this if you change the data in ways that mean users with // existing data should get a new version. - "kCurrentDataVersion": 87 + "kCurrentDataVersion": 88 }, // The following engines are included in country lists and are added to the @@ -110,11 +110,11 @@ "name": "Google", "keyword": "google.com", "favicon_url": "http://www.google.com/favicon.ico", - "search_url": "{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}", + "search_url": "{google:baseURL}search?q={searchTerms}&{google:RLZ}{google:originalQueryForSuggestion}{google:assistedQueryStats}{google:searchFieldtrialParameter}{google:searchClient}{google:sourceId}{google:instantExtendedEnabledParameter}{google:contextualSearchVersion}ie={inputEncoding}", "suggest_url": "{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}", - "instant_url": "{google:baseURL}webhp?sourceid=chrome-instant&{google:RLZ}{google:forceInstantResults}{google:instantExtendedEnabledParameter}{google:ntpIsThemedParameter}{google:omniboxStartMarginParameter}ie={inputEncoding}", + "instant_url": "{google:baseURL}webhp?sourceid=chrome-instant&{google:RLZ}{google:forceInstantResults}{google:instantExtendedEnabledParameter}ie={inputEncoding}", "image_url": "{google:baseURL}searchbyimage/upload", - "new_tab_url": "{google:baseURL}_/chrome/newtab?{google:RLZ}{google:instantExtendedEnabledParameter}{google:ntpIsThemedParameter}ie={inputEncoding}", + "new_tab_url": "{google:baseURL}_/chrome/newtab?{google:RLZ}{google:instantExtendedEnabledParameter}ie={inputEncoding}", "contextual_search_url": "{google:baseURL}_/contextualsearch?{google:contextualSearchVersion}{google:contextualSearchContextData}", "image_url_post_params": "encoded_image={google:imageThumbnail},image_url={google:imageURL},sbisrc={google:imageSearchSource},original_width={google:imageOriginalWidth},original_height={google:imageOriginalHeight}", "alternate_urls": [
diff --git a/components/search_engines/search_terms_data.cc b/components/search_engines/search_terms_data.cc index be897db..f7300e4 100644 --- a/components/search_engines/search_terms_data.cc +++ b/components/search_engines/search_terms_data.cc
@@ -54,10 +54,6 @@ return std::string(); } -bool SearchTermsData::IsShowingSearchTermsOnSearchResultsPages() const { - return false; -} - std::string SearchTermsData::InstantExtendedEnabledParam( bool for_search) const { return std::string(); @@ -68,14 +64,6 @@ return std::string(); } -int SearchTermsData::OmniboxStartMargin() const { - return 0; -} - -std::string SearchTermsData::NTPIsThemedParam() const { - return std::string(); -} - std::string SearchTermsData::IOSWebViewTypeParam() const { return std::string(); }
diff --git a/components/search_engines/search_terms_data.h b/components/search_engines/search_terms_data.h index 2cd5951..0ac61591 100644 --- a/components/search_engines/search_terms_data.h +++ b/components/search_engines/search_terms_data.h
@@ -49,10 +49,6 @@ // This implementation returns the empty string. virtual std::string GetSuggestRequestIdentifier() const; - // Returns true if search terms are shown in the omnibox on search results - // pages. - virtual bool IsShowingSearchTermsOnSearchResultsPages() const; - // Returns a string indicating whether InstantExtended is enabled. virtual std::string InstantExtendedEnabledParam(bool for_search) const; @@ -60,16 +56,6 @@ // incrementally. virtual std::string ForceInstantResultsParam(bool for_prerender) const; - // Returns the start-edge margin of the omnibox in pixels. - virtual int OmniboxStartMargin() const; - - // Returns a string indicating whether a non-default theme is active, - // suitable for adding as a query string param to the homepage. This only - // applies if Instant Extended is enabled. Returns an empty string otherwise. - // Determining this requires accessing the Profile, so this can only ever be - // non-empty for UIThreadSearchTermsData. - virtual std::string NTPIsThemedParam() const; - // Returns a string indicating which webview is currently in use on iOS, // suitable for adding as a query string param to search requests. Returns an // empty string if no parameter should be passed along with search requests.
diff --git a/components/search_engines/template_url.cc b/components/search_engines/template_url.cc index b5baebe..a75779b 100644 --- a/components/search_engines/template_url.cc +++ b/components/search_engines/template_url.cc
@@ -148,9 +148,7 @@ input_type(metrics::OmniboxInputType::INVALID), accepted_suggestion(NO_SUGGESTIONS_AVAILABLE), cursor_position(base::string16::npos), - enable_omnibox_start_margin(false), page_classification(metrics::OmniboxEventProto::INVALID_SPEC), - bookmark_bar_pinned(false), append_extra_query_params(false), force_instant_results(false), from_app_list(false), @@ -571,8 +569,6 @@ replacements->push_back(Replacement(GOOGLE_BASE_URL, start)); } else if (parameter == "google:baseSuggestURL") { replacements->push_back(Replacement(GOOGLE_BASE_SUGGEST_URL, start)); - } else if (parameter == "google:bookmarkBarPinned") { - replacements->push_back(Replacement(GOOGLE_BOOKMARK_BAR_PINNED, start)); } else if (parameter == "google:currentPageUrl") { replacements->push_back(Replacement(GOOGLE_CURRENT_PAGE_URL, start)); } else if (parameter == "google:cursorPosition") { @@ -602,10 +598,6 @@ start)); } else if (parameter == "google:instantExtendedEnabledKey") { url->insert(start, google_util::kInstantExtendedAPIParam); - } else if (parameter == "google:ntpIsThemedParameter") { - replacements->push_back(Replacement(GOOGLE_NTP_IS_THEMED, start)); - } else if (parameter == "google:omniboxStartMarginParameter") { - replacements->push_back(Replacement(GOOGLE_OMNIBOX_START_MARGIN, start)); } else if (parameter == "google:contextualSearchVersion") { replacements->push_back( Replacement(GOOGLE_CONTEXTUAL_SEARCH_VERSION, start)); @@ -904,17 +896,6 @@ &url); break; - case GOOGLE_BOOKMARK_BAR_PINNED: - if (search_terms_data.IsShowingSearchTermsOnSearchResultsPages()) { - // Log whether the bookmark bar is pinned when the user is seeing - // InstantExtended on the SRP. - DCHECK(!i->is_post_param); - HandleReplacement( - "bmbp", search_terms_args.bookmark_bar_pinned ? "1" : "0", *i, - &url); - } - break; - case GOOGLE_CURRENT_PAGE_URL: DCHECK(!i->is_post_param); if (!search_terms_args.current_page_url.empty()) { @@ -959,23 +940,6 @@ &url); break; - case GOOGLE_NTP_IS_THEMED: - DCHECK(!i->is_post_param); - HandleReplacement( - std::string(), search_terms_data.NTPIsThemedParam(), *i, &url); - break; - - case GOOGLE_OMNIBOX_START_MARGIN: - DCHECK(!i->is_post_param); - if (search_terms_args.enable_omnibox_start_margin) { - int omnibox_start_margin = search_terms_data.OmniboxStartMargin(); - if (omnibox_start_margin >= 0) { - HandleReplacement("es_sm", base::IntToString(omnibox_start_margin), - *i, &url); - } - } - break; - case GOOGLE_CONTEXTUAL_SEARCH_VERSION: if (search_terms_args.contextual_search_params.version >= 0) { HandleReplacement(
diff --git a/components/search_engines/template_url.h b/components/search_engines/template_url.h index c07f428..dd11b39 100644 --- a/components/search_engines/template_url.h +++ b/components/search_engines/template_url.h
@@ -147,10 +147,6 @@ // the request was issued. Set to base::string16::npos if not used. size_t cursor_position; - // True to enable the start-edge margin of the omnibox, used in extended - // Instant to align the preview contents with the omnibox. - bool enable_omnibox_start_margin; - // The URL of the current webpage to be used for experimental zero-prefix // suggestions. std::string current_page_url; @@ -158,9 +154,6 @@ // Which omnibox the user used to type the prefix. metrics::OmniboxEventProto::PageClassification page_classification; - // True for searches issued with the bookmark bar pref set to shown. - bool bookmark_bar_pinned; - // Optional session token. std::string session_token; @@ -311,7 +304,6 @@ FRIEND_TEST_ALL_PREFIXES(TemplateURLTest, ParseURLTwoParameters); FRIEND_TEST_ALL_PREFIXES(TemplateURLTest, ParseURLNestedParameter); FRIEND_TEST_ALL_PREFIXES(TemplateURLTest, URLRefTestImageURLWithPOST); - FRIEND_TEST_ALL_PREFIXES(TemplateURLTest, ReflectsBookmarkBarPinned); // Enumeration of the known types. enum ReplacementType { @@ -319,7 +311,6 @@ GOOGLE_ASSISTED_QUERY_STATS, GOOGLE_BASE_URL, GOOGLE_BASE_SUGGEST_URL, - GOOGLE_BOOKMARK_BAR_PINNED, GOOGLE_CURRENT_PAGE_URL, GOOGLE_CURSOR_POSITION, GOOGLE_FORCE_INSTANT_RESULTS, @@ -331,7 +322,6 @@ GOOGLE_INPUT_TYPE, GOOGLE_INSTANT_EXTENDED_ENABLED, GOOGLE_NTP_IS_THEMED, - GOOGLE_OMNIBOX_START_MARGIN, GOOGLE_CONTEXTUAL_SEARCH_VERSION, GOOGLE_CONTEXTUAL_SEARCH_CONTEXT_DATA, GOOGLE_ORIGINAL_QUERY_FOR_SUGGESTION, @@ -714,7 +704,6 @@ private: friend class TemplateURLService; - FRIEND_TEST_ALL_PREFIXES(TemplateURLTest, ReflectsBookmarkBarPinned); void CopyFrom(const TemplateURL& other);
diff --git a/components/search_engines/template_url_unittest.cc b/components/search_engines/template_url_unittest.cc index 8a0227b0..a5f3399 100644 --- a/components/search_engines/template_url_unittest.cc +++ b/components/search_engines/template_url_unittest.cc
@@ -645,42 +645,6 @@ } } -TEST_F(TemplateURLTest, OmniboxStartmargin) { - struct TestData { - const bool enable_omnibox_start_margin; - const int omnibox_start_margin; - const std::string expected_result; - } test_data[] = { - { false, - 0, - "http://bar/foo?q=foobar" }, - { true, - 0, - "http://bar/foo?es_sm=0&q=foobar" }, - { true, - 42, - "http://bar/foo?es_sm=42&q=foobar" }, - }; - TemplateURLData data; - data.SetURL("http://bar/foo?{google:omniboxStartMarginParameter}" - "q={searchTerms}"); - data.input_encodings.push_back("UTF-8"); - TemplateURL url(data); - EXPECT_TRUE(url.url_ref().IsValid(search_terms_data_)); - ASSERT_TRUE(url.url_ref().SupportsReplacement(search_terms_data_)); - for (size_t i = 0; i < arraysize(test_data); ++i) { - TemplateURLRef::SearchTermsArgs search_terms_args(ASCIIToUTF16("foobar")); - search_terms_args.enable_omnibox_start_margin = - test_data[i].enable_omnibox_start_margin; - search_terms_data_.set_omnibox_start_margin( - test_data[i].omnibox_start_margin); - GURL result(url.url_ref().ReplaceSearchTerms(search_terms_args, - search_terms_data_)); - ASSERT_TRUE(result.is_valid()); - EXPECT_EQ(test_data[i].expected_result, result.spec()); - } -} - TEST_F(TemplateURLTest, Suggestions) { struct TestData { const int accepted_suggestion; @@ -1605,35 +1569,6 @@ } } -TEST_F(TemplateURLTest, ReflectsBookmarkBarPinned) { - TemplateURLData data; - data.input_encodings.push_back("UTF-8"); - data.SetURL("{google:baseURL}?{google:bookmarkBarPinned}q={searchTerms}"); - TemplateURL url(data); - EXPECT_TRUE(url.url_ref().IsValid(search_terms_data_)); - ASSERT_TRUE(url.url_ref().SupportsReplacement(search_terms_data_)); - TemplateURLRef::SearchTermsArgs search_terms_args(ASCIIToUTF16("foo")); - - // Do not add the param when InstantExtended is suppressed on SRPs. - search_terms_data_.set_is_showing_search_terms_on_search_results_pages(false); - std::string result = url.url_ref().ReplaceSearchTerms(search_terms_args, - search_terms_data_); - EXPECT_EQ("http://www.google.com/?q=foo", result); - - // Add the param when InstantExtended is not suppressed on SRPs. - search_terms_data_.set_is_showing_search_terms_on_search_results_pages(true); - search_terms_args.bookmark_bar_pinned = false; - result = url.url_ref().ReplaceSearchTerms(search_terms_args, - search_terms_data_); - EXPECT_EQ("http://www.google.com/?bmbp=0&q=foo", result); - - search_terms_data_.set_is_showing_search_terms_on_search_results_pages(true); - search_terms_args.bookmark_bar_pinned = true; - result = url.url_ref().ReplaceSearchTerms(search_terms_args, - search_terms_data_); - EXPECT_EQ("http://www.google.com/?bmbp=1&q=foo", result); -} - TEST_F(TemplateURLTest, SearchboxVersionIncludedForAnswers) { TemplateURLData data; search_terms_data_.set_google_base_url("http://bar/");
diff --git a/components/search_engines/testing_search_terms_data.cc b/components/search_engines/testing_search_terms_data.cc index b4e9824..9fed5cf 100644 --- a/components/search_engines/testing_search_terms_data.cc +++ b/components/search_engines/testing_search_terms_data.cc
@@ -8,8 +8,7 @@ TestingSearchTermsData::TestingSearchTermsData( const std::string& google_base_url) - : google_base_url_(google_base_url), - is_showing_search_terms_on_search_results_pages_(false) { + : google_base_url_(google_base_url) { } TestingSearchTermsData::~TestingSearchTermsData() {} @@ -31,11 +30,3 @@ std::string TestingSearchTermsData::GoogleImageSearchSource() const { return "google_image_search_source"; } - -bool TestingSearchTermsData::IsShowingSearchTermsOnSearchResultsPages() const { - return is_showing_search_terms_on_search_results_pages_; -} - -int TestingSearchTermsData::OmniboxStartMargin() const { - return omnibox_start_margin_; -}
diff --git a/components/search_engines/testing_search_terms_data.h b/components/search_engines/testing_search_terms_data.h index b03c71b..083d0253 100644 --- a/components/search_engines/testing_search_terms_data.h +++ b/components/search_engines/testing_search_terms_data.h
@@ -17,8 +17,6 @@ base::string16 GetRlzParameterValue(bool from_app_list) const override; std::string GetSearchClient() const override; std::string GoogleImageSearchSource() const override; - bool IsShowingSearchTermsOnSearchResultsPages() const override; - int OmniboxStartMargin() const override; void set_google_base_url(const std::string& google_base_url) { google_base_url_ = google_base_url; @@ -26,18 +24,10 @@ void set_search_client(const std::string& search_client) { search_client_ = search_client; } - void set_is_showing_search_terms_on_search_results_pages(bool value) { - is_showing_search_terms_on_search_results_pages_ = value; - } - void set_omnibox_start_margin(int omnibox_start_margin) { - omnibox_start_margin_ = omnibox_start_margin; - } private: std::string google_base_url_; std::string search_client_; - bool is_showing_search_terms_on_search_results_pages_; - int omnibox_start_margin_; DISALLOW_COPY_AND_ASSIGN(TestingSearchTermsData); };
diff --git a/components/signin/core/browser/signin_manager_base.cc b/components/signin/core/browser/signin_manager_base.cc index a84f5ef..cd3d9cd5 100644 --- a/components/signin/core/browser/signin_manager_base.cc +++ b/components/signin/core/browser/signin_manager_base.cc
@@ -43,6 +43,8 @@ user_prefs::PrefRegistrySyncable* registry) { registry->RegisterStringPref(prefs::kGoogleServicesHostedDomain, std::string()); + registry->RegisterStringPref(prefs::kGoogleServicesLastAccountId, + std::string()); registry->RegisterStringPref(prefs::kGoogleServicesLastUsername, std::string()); registry->RegisterInt64Pref( @@ -208,8 +210,10 @@ } // Go ahead and update the last signed in account info here as well. Once a - // user is signed in the two preferences should match. Doing it here as - // opposed to on signin allows us to catch the upgrade scenario. + // user is signed in the corresponding preferences should match. Doing it here + // as opposed to on signin allows us to catch the upgrade scenario. + client_->GetPrefs()->SetString(prefs::kGoogleServicesLastAccountId, + account_id); client_->GetPrefs()->SetString(prefs::kGoogleServicesLastUsername, info.email); }
diff --git a/components/signin/core/browser/signin_metrics.h b/components/signin/core/browser/signin_metrics.h index ff22f84..9ffe2ee 100644 --- a/components/signin/core/browser/signin_metrics.h +++ b/components/signin/core/browser/signin_metrics.h
@@ -134,9 +134,8 @@ ACCESS_POINT_CONTENT_AREA, ACCESS_POINT_SIGNIN_PROMO, ACCESS_POINT_RECENT_TABS, - ACCESS_POINT_UNSPECIFIED, // This should never have been used to get signin - // URL. - ACCESS_POINT_MAX // This must be last. + ACCESS_POINT_UNKNOWN, // This should never have been used to get signin URL. + ACCESS_POINT_MAX, // This must be last. }; // Enum values which enumerates all reasons to start sign in process. @@ -145,8 +144,8 @@ REASON_ADD_SECONDARY_ACCOUNT, REASON_REAUTHENTICATION, REASON_UNLOCK, - REASON_UNSPECIFIED, // This should never have been used to get signin URL. - REASON_MAX // This must be last. + REASON_UNKNOWN_REASON, // This should never have been used to get signin URL. + REASON_MAX, // This must be last. }; // Enum values used for use with the "Signin.Reauth" histogram.
diff --git a/components/signin/core/common/signin_pref_names.cc b/components/signin/core/common/signin_pref_names.cc index 38496dc..dcf3b59 100644 --- a/components/signin/core/common/signin_pref_names.cc +++ b/components/signin/core/common/signin_pref_names.cc
@@ -18,12 +18,20 @@ // The profile's hosted domain; empty if unset; // AccountTrackerService::kNoHostedDomainFound if there is none. +// Typically contains an obfuscated gaiaid and will match the value of +// kGoogleServicesUserAccountId. Some platforms and legacy clients may have +// an email stored in this preference instead. This is transitional and will +// eventually be fixed, allowing the removal of kGoogleServicesUserAccountId. const char kGoogleServicesAccountId[] = "google.services.account_id"; // The profile's hosted domain; empty if unset; Profile::kNoHostedDomainFound // if there is none. const char kGoogleServicesHostedDomain[] = "google.services.hosted_domain"; +// Similar to kGoogleServicesLastUsername, this is the corresponding version of +// kGoogleServicesAccountId that is not cleared on signout. +const char kGoogleServicesLastAccountId[] = "google.services.last_account_id"; + // String the identifies the last user that logged into sync and other // google services. As opposed to kGoogleServicesUsername, this value is not // cleared on signout, but while the user is signed in the two values will
diff --git a/components/signin/core/common/signin_pref_names.h b/components/signin/core/common/signin_pref_names.h index 412a3d6..226830ea 100644 --- a/components/signin/core/common/signin_pref_names.h +++ b/components/signin/core/common/signin_pref_names.h
@@ -11,6 +11,7 @@ extern const char kAutologinEnabled[]; extern const char kGoogleServicesAccountId[]; extern const char kGoogleServicesHostedDomain[]; +extern const char kGoogleServicesLastAccountId[]; extern const char kGoogleServicesLastUsername[]; extern const char kGoogleServicesRefreshTokenAnnotateScheduledTime[]; extern const char kGoogleServicesSigninScopedDeviceId[];
diff --git a/components/startup_metric_utils/browser/startup_metric_utils.cc b/components/startup_metric_utils/browser/startup_metric_utils.cc index 914c960..6594376 100644 --- a/components/startup_metric_utils/browser/startup_metric_utils.cc +++ b/components/startup_metric_utils/browser/startup_metric_utils.cc
@@ -135,6 +135,30 @@ g_startup_temperature); \ } +// Returns the system uptime on process launch. +base::TimeDelta GetSystemUptimeOnProcessLaunch() { + // Process launch time is not available on Android. + if (g_process_creation_ticks.Get().is_null()) + return base::TimeDelta(); + + // base::SysInfo::Uptime returns the time elapsed between system boot and now. + // Substract the time elapsed between process launch and now to get the time + // elapsed between system boot and process launch. + return base::SysInfo::Uptime() - + (base::TimeTicks::Now() - g_process_creation_ticks.Get()); +} + +void RecordSystemUptimeHistogram() { + const base::TimeDelta system_uptime_on_process_launch = + GetSystemUptimeOnProcessLaunch(); + if (system_uptime_on_process_launch.is_zero()) + return; + + UMA_HISTOGRAM_WITH_STARTUP_TEMPERATURE(UMA_HISTOGRAM_LONG_TIMES_100, + "Startup.SystemUptime", + GetSystemUptimeOnProcessLaunch()); +} + // On Windows, records the number of hard-faults that have occurred in the // current chrome.exe process since it was started. This is a nop on other // platforms. @@ -395,6 +419,7 @@ bool is_first_run) { AddStartupEventsForTelemetry(); RecordHardFaultHistogram(is_first_run); + RecordSystemUptimeHistogram(); RecordMainEntryTimeHistogram(); const base::TimeTicks& process_creation_ticks =
diff --git a/components/translate.gypi b/components/translate.gypi index be9317b..a9a3cc8 100644 --- a/components/translate.gypi +++ b/components/translate.gypi
@@ -42,6 +42,8 @@ 'translate/core/browser/translate_error_details.h', 'translate/core/browser/translate_event_details.cc', 'translate/core/browser/translate_event_details.h', + 'translate/core/browser/translate_experiment.cc', + 'translate/core/browser/translate_experiment.h', 'translate/core/browser/translate_language_list.cc', 'translate/core/browser/translate_language_list.h', 'translate/core/browser/translate_manager.cc',
diff --git a/components/translate/core/browser/BUILD.gn b/components/translate/core/browser/BUILD.gn index 2fafccc..d6593fd 100644 --- a/components/translate/core/browser/BUILD.gn +++ b/components/translate/core/browser/BUILD.gn
@@ -20,6 +20,8 @@ "translate_error_details.h", "translate_event_details.cc", "translate_event_details.h", + "translate_experiment.cc", + "translate_experiment.h", "translate_language_list.cc", "translate_language_list.h", "translate_manager.cc",
diff --git a/components/translate/core/browser/translate_experiment.cc b/components/translate/core/browser/translate_experiment.cc new file mode 100644 index 0000000..f37fb0cf --- /dev/null +++ b/components/translate/core/browser/translate_experiment.cc
@@ -0,0 +1,73 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/translate/core/browser/translate_experiment.h" + +#include "base/command_line.h" +#include "base/logging.h" +#include "base/metrics/field_trial.h" +#include "base/strings/string_util.h" +#include "components/translate/core/browser/translate_download_manager.h" + +using base::CommandLine; + +namespace translate { + +namespace { + +const char kTranslateExperimentTrial[] = "TranslateUiLangTrial"; +const char kDisableTranslateExperiment[] = "disable-translate-experiment"; +const char kEnableTranslateExperiment[] = "enable-translate-experiment"; +const char kForceTranslateLanguage[] = "force-translate-language"; + +} // namespace + +// static +void TranslateExperiment::OverrideUiLanguage(const std::string& country, + std::string* ui_lang) { + DCHECK(ui_lang); + if (!InExperiment()) + return; + + // Forced target language takes precedence. + if (CommandLine::ForCurrentProcess()->HasSwitch(kForceTranslateLanguage)) { + *ui_lang = CommandLine::ForCurrentProcess()->GetSwitchValueASCII( + kForceTranslateLanguage); + return; + } + + // Otherwise, base the target language on the current country. + if (country == "my") + *ui_lang = "ms"; + else if (country == "id") + *ui_lang = "id"; +} + +// static +bool TranslateExperiment::ShouldOverrideBlocking(const std::string& ui_language, + const std::string& language) { + return InExperiment() && (language == ui_language); +} + +// static +bool TranslateExperiment::InExperiment() { + // Note: It's important to query the field trial state first, to ensure that + // UMA reports the correct group. + const std::string group_name = + base::FieldTrialList::FindFullName(kTranslateExperimentTrial); + if (CommandLine::ForCurrentProcess()->HasSwitch(kDisableTranslateExperiment)) + return false; + // TODO(groby): Figure out if we can get rid of the enable branch completely. + // Or, if we allow enable, we have to gate this on country. I'd rather not, + // since this complicates the experiment. + if (CommandLine::ForCurrentProcess()->HasSwitch(kEnableTranslateExperiment)) + return true; + if (CommandLine::ForCurrentProcess()->HasSwitch(kForceTranslateLanguage)) + return true; + // Use StartsWith() for more flexibility (e.g. multiple Enabled groups). + return base::StartsWith(group_name, "Enabled", + base::CompareCase::INSENSITIVE_ASCII); +} + +} // namespace translate
diff --git a/components/translate/core/browser/translate_experiment.h b/components/translate/core/browser/translate_experiment.h new file mode 100644 index 0000000..964eff8 --- /dev/null +++ b/components/translate/core/browser/translate_experiment.h
@@ -0,0 +1,34 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_TRANSLATE_CORE_BROWSER_TRANSLATE_EXPERIMENT_H_ +#define COMPONENTS_TRANSLATE_CORE_BROWSER_TRANSLATE_EXPERIMENT_H_ + +#include <string> + +namespace translate { + +class TranslateExperiment { + public: + // Replaces the UI language for experiment purposes, if the experiment is + // enabled. I.e. if the user participates in the experiment, and their UI + // language differs from the predominantly spoken language in the area, this + // changes |ui_lang| to the predominantly spoken language. + static void OverrideUiLanguage(const std::string& country, + std::string* ui_lang); + + // Check if a user-defined block needs to be overridden for |language|, i.e. + // if the user is in the experiment and |language| matches |ui_language|. + // This is necessary because the current Translate systems treats the UI + // language as auto-blocked. + static bool ShouldOverrideBlocking(const std::string& ui_language, + const std::string& language); + + private: + static bool InExperiment(); +}; + +} // namespace translate + +#endif // COMPONENTS_TRANSLATE_CORE_BROWSER_TRANSLATE_EXPERIMENT_H_
diff --git a/components/translate/core/browser/translate_manager.cc b/components/translate/core/browser/translate_manager.cc index 0768223..371a10f 100644 --- a/components/translate/core/browser/translate_manager.cc +++ b/components/translate/core/browser/translate_manager.cc
@@ -20,6 +20,7 @@ #include "components/translate/core/browser/translate_download_manager.h" #include "components/translate/core/browser/translate_driver.h" #include "components/translate/core/browser/translate_error_details.h" +#include "components/translate/core/browser/translate_experiment.h" #include "components/translate/core/browser/translate_language_list.h" #include "components/translate/core/browser/translate_prefs.h" #include "components/translate/core/browser/translate_script.h" @@ -360,6 +361,8 @@ TranslateDownloadManager::GetInstance()->application_locale()); translate::ToTranslateLanguageSynonym(&ui_lang); + TranslateExperiment::OverrideUiLanguage(prefs->GetCountry(), &ui_lang); + if (TranslateDownloadManager::IsSupportedLanguage(ui_lang)) return ui_lang;
diff --git a/components/translate/core/browser/translate_prefs.cc b/components/translate/core/browser/translate_prefs.cc index b265f96..5b3938da 100644 --- a/components/translate/core/browser/translate_prefs.cc +++ b/components/translate/core/browser/translate_prefs.cc
@@ -14,6 +14,7 @@ #include "components/pref_registry/pref_registry_syncable.h" #include "components/translate/core/browser/translate_accept_languages.h" #include "components/translate/core/browser/translate_download_manager.h" +#include "components/translate/core/browser/translate_experiment.h" #include "components/translate/core/common/translate_util.h" namespace translate { @@ -160,6 +161,14 @@ #endif } +void TranslatePrefs::SetCountry(const std::string& country) { + country_ = country; +} + +std::string TranslatePrefs::GetCountry() const { + return country_; +} + void TranslatePrefs::ResetToDefaults() { ClearBlockedLanguages(); ClearBlacklistedSites(); @@ -397,6 +406,13 @@ TranslateAcceptLanguages::CanBeAcceptLanguage(language); bool is_accept_language = accept_languages->IsAcceptLanguage(language); + // For the translate language experiment, blocklists can be overridden. + const std::string& app_locale = + TranslateDownloadManager::GetInstance()->application_locale(); + std::string ui_lang = TranslateDownloadManager::GetLanguageCode(app_locale); + if (TranslateExperiment::ShouldOverrideBlocking(ui_lang, language)) + return true; + // Don't translate any user black-listed languages. Checking // |is_accept_language| is necessary because if the user eliminates the // language from the preference, it is natural to forget whether or not
diff --git a/components/translate/core/browser/translate_prefs.h b/components/translate/core/browser/translate_prefs.h index 10b39ca..fa32241a 100644 --- a/components/translate/core/browser/translate_prefs.h +++ b/components/translate/core/browser/translate_prefs.h
@@ -81,6 +81,11 @@ const char* accept_languages_pref, const char* preferred_languages_pref); + // Sets the country that the application is run in. Determined by the + // VariationsService, can be left empty. Used by TranslateExperiment. + void SetCountry(const std::string& country); + std::string GetCountry() const; + // Resets the blocked languages list, the sites blacklist, the languages // whitelist, and the accepted/denied counts. void ResetToDefaults(); @@ -190,6 +195,8 @@ PrefService* prefs_; // Weak. + std::string country_; // The country the app runs in. + DISALLOW_COPY_AND_ASSIGN(TranslatePrefs); };
diff --git a/components/url_formatter/BUILD.gn b/components/url_formatter/BUILD.gn index 1756f02..0bd6e01 100644 --- a/components/url_formatter/BUILD.gn +++ b/components/url_formatter/BUILD.gn
@@ -2,8 +2,6 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -import("//build/config/ui.gni") - source_set("url_formatter") { sources = [ "elide_url.cc", @@ -24,7 +22,7 @@ "//url", ] - if (!is_android || use_aura) { + if (!is_android) { deps += [ "//ui/gfx" ] } } @@ -42,10 +40,11 @@ "//base", "//net", "//testing/gtest", + "//ui/gfx", "//url", ] - if (!is_android || use_aura) { - deps += [ "//ui/gfx" ] + if (is_android) { + deps -= [ "//ui/gfx" ] } }
diff --git a/components/url_formatter/elide_url.cc b/components/url_formatter/elide_url.cc index 7f5538aa..45984304 100644 --- a/components/url_formatter/elide_url.cc +++ b/components/url_formatter/elide_url.cc
@@ -16,14 +16,14 @@ #include "url/gurl.h" #include "url/url_constants.h" -#if !defined(OS_ANDROID) || defined(USE_AURA) +#if !defined(OS_ANDROID) #include "ui/gfx/text_elider.h" // nogncheck #include "ui/gfx/text_utils.h" // nogncheck -#endif // !defined(OS_ANDROID) || defined(USE_AURA) +#endif namespace { -#if !defined(OS_ANDROID) || defined(USE_AURA) +#if !defined(OS_ANDROID) const base::char16 kDot = '.'; // Build a path from the first |num_components| elements in |path_elements|. @@ -105,7 +105,7 @@ } } -#endif // !defined(OS_ANDROID) || defined(USE_AURA) +#endif // !defined(OS_ANDROID) base::string16 FormatUrlForSecurityDisplayInternal(const GURL& url, const std::string& languages, @@ -157,7 +157,7 @@ namespace url_formatter { -#if !defined(OS_ANDROID) || defined(USE_AURA) +#if !defined(OS_ANDROID) // TODO(pkasting): http://crbug.com/77883 This whole function gets // kerning/ligatures/etc. issues potentially wrong by assuming that the width of @@ -356,7 +356,7 @@ gfx::ELIDE_HEAD); } -#endif // !defined(OS_ANDROID) || defined(USE_AURA) +#endif // !defined(OS_ANDROID) base::string16 FormatUrlForSecurityDisplay(const GURL& url, const std::string& languages) {
diff --git a/components/url_formatter/elide_url.h b/components/url_formatter/elide_url.h index ca9274a..5a05cef 100644 --- a/components/url_formatter/elide_url.h +++ b/components/url_formatter/elide_url.h
@@ -22,7 +22,7 @@ // ElideUrl and Elide host require // gfx::GetStringWidthF which is not implemented in Android -#if !defined(OS_ANDROID) || defined(USE_AURA) +#if !defined(OS_ANDROID) // This function takes a GURL object and elides it. It returns a string // which composed of parts from subdomain, domain, path, filename and query. // A "..." is added automatically at the end if the elided string is bigger @@ -50,7 +50,7 @@ base::string16 ElideHost(const GURL& host_url, const gfx::FontList& font_list, float available_pixel_width); -#endif // !defined(OS_ANDROID) || defined(USE_AURA) +#endif // !defined(OS_ANDROID) // This is a convenience function for formatting a URL in a concise and // human-friendly way, to help users make security-related decisions (or in
diff --git a/components/url_formatter/url_formatter.gyp b/components/url_formatter/url_formatter.gyp index 304c545..9375e96 100644 --- a/components/url_formatter/url_formatter.gyp +++ b/components/url_formatter/url_formatter.gyp
@@ -28,7 +28,7 @@ 'msvs_disabled_warnings': [4267, ], 'conditions': [ - ['OS!="android" or use_aura==1', { + ['OS != "android"', { 'dependencies': [ '../../ui/gfx/gfx.gyp:gfx', ]
diff --git a/components/web_restriction.gypi b/components/web_restriction.gypi new file mode 100644 index 0000000..01aa9bde --- /dev/null +++ b/components/web_restriction.gypi
@@ -0,0 +1,23 @@ +# 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. + +{ + 'conditions': [ + ['OS == "android"', { + 'targets': [ + { + # GN: //components/web_restriction:web_restriction_java + 'target_name': 'web_restriction_java', + 'type': 'none', + 'variables': { + 'java_in_dir': 'web_restriction/java', + }, + 'dependencies': [ + '../base/base.gyp:base', + ], + 'includes': [ '../build/java.gypi' ], + }, + ], + }]] +}
diff --git a/components/web_restriction/BUILD.gn b/components/web_restriction/BUILD.gn new file mode 100644 index 0000000..b6974db --- /dev/null +++ b/components/web_restriction/BUILD.gn
@@ -0,0 +1,20 @@ +# 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/android/rules.gni") + +# GYP: components.gyp:web_restriction_java +android_library("web_restriction_java") { + java_files = [ "java/src/org/chromium/components/webrestriction/WebRestrictionsContentProvider.java" ] +} + +# GYP: //components/components_test.gyp:components_junit_tests +junit_binary("components_web_restrictions_junit_tests") { + java_files = [ "junit/src/org/chromium/components/webrestriction/WebRestrictionsContentProviderTest.java" ] + deps = [ + ":web_restriction_java", + "//base:base_java", + "//third_party/junit:hamcrest", + ] +}
diff --git a/components/web_restriction/OWNERS b/components/web_restriction/OWNERS new file mode 100644 index 0000000..b9540e11 --- /dev/null +++ b/components/web_restriction/OWNERS
@@ -0,0 +1,2 @@ +aberent@chromium.org +bauerb@chromium.org \ No newline at end of file
diff --git a/components/web_restriction/java/src/org/chromium/components/webrestriction/WebRestrictionsContentProvider.java b/components/web_restriction/java/src/org/chromium/components/webrestriction/WebRestrictionsContentProvider.java new file mode 100644 index 0000000..e549de6a --- /dev/null +++ b/components/web_restriction/java/src/org/chromium/components/webrestriction/WebRestrictionsContentProvider.java
@@ -0,0 +1,178 @@ +// 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.components.webrestriction; + +import android.content.ContentProvider; +import android.content.ContentValues; +import android.content.Context; +import android.content.UriMatcher; +import android.content.pm.ProviderInfo; +import android.database.AbstractCursor; +import android.database.Cursor; +import android.net.Uri; +import android.util.Pair; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Abstract content provider for providing web restrictions, i.e. for providing a filter for URLs so + * that they can be blocked or permitted, and a means of requesting permission for new URLs. It + * provides two (virtual) tables; an 'authorized' table listing the the status of every URL, and a + * 'requested' table containing the requests for access to new URLs. The 'authorized' table is read + * only and the 'requested' table is write only. + */ +public abstract class WebRestrictionsContentProvider extends ContentProvider { + public static final int BLOCKED = 0; + public static final int PROCEED = 1; + private static final int WEB_RESTRICTIONS = 1; + private static final int AUTHORIZED = 2; + private static final int REQUESTED = 3; + + private final Pattern mSelectionPattern; + private UriMatcher mContentUriMatcher; + private Uri mContentUri; + + protected WebRestrictionsContentProvider() { + // Pattern to extract the URL from the selection. + // Matches patterns of the form "url = '<url>'" with arbitrary spacing around the "=" etc. + mSelectionPattern = Pattern.compile("\\s*url\\s*=\\s*'([^']*)'"); + } + + @Override + public boolean onCreate() { + return true; + } + + @Override + public void attachInfo(Context context, ProviderInfo info) { + super.attachInfo(context, info); + mContentUri = new Uri.Builder().scheme("content").authority(info.authority).build(); + mContentUriMatcher = new UriMatcher(WEB_RESTRICTIONS); + mContentUriMatcher.addURI(info.authority, "authorized", AUTHORIZED); + mContentUriMatcher.addURI(info.authority, "requested", REQUESTED); + } + + @Override + public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, + String sortOrder) { + // Check that this is the a query on the 'authorized' table + // TODO(aberent): Provide useful queries on the 'requested' table. + if (mContentUriMatcher.match(uri) != AUTHORIZED) return null; + // If the selection is of the right form get the url we are querying. + Matcher matcher = mSelectionPattern.matcher(selection); + if (!matcher.find()) return null; + final String url = matcher.group(1); + final Pair<Boolean, String> result = shouldProceed(url); + + return new AbstractCursor() { + + @Override + public int getCount() { + return 1; + } + + @Override + public String[] getColumnNames() { + return new String[] {"Should Proceed", "Error message"}; + } + + @Override + public String getString(int column) { + if (column == 1) return result.second; + return null; + } + + @Override + public short getShort(int column) { + return 0; + } + + @Override + public int getInt(int column) { + if (column == 0) return result.first ? PROCEED : BLOCKED; + return 0; + } + + @Override + public long getLong(int column) { + return 0; + } + + @Override + public float getFloat(int column) { + return 0; + } + + @Override + public double getDouble(int column) { + return 0; + } + + @Override + public boolean isNull(int column) { + return false; + } + }; + } + + @Override + public String getType(Uri uri) { + // Abused to return whether we can insert + if (mContentUriMatcher.match(uri) != REQUESTED) return null; + return canInsert() ? "text/plain" : null; + } + + @Override + public Uri insert(Uri uri, ContentValues values) { + if (mContentUriMatcher.match(uri) != REQUESTED) return null; + String url = values.getAsString("url"); + if (requestInsert(url)) { + // TODO(aberent): If we ever make the 'requested' table readable then we might want to + // change this to a more conventional content URI (with a row number). + return uri.buildUpon().appendPath(url).build(); + } else { + return null; + } + } + + @Override + public int delete(Uri uri, String selection, String[] selectionArgs) { + return 0; + } + + @Override + public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { + return 0; + } + + /** + * @param url the URL that is wanted. + * @return a pair containing the Result and the HTML Error Message. result is true if safe to + * proceed, false otherwise. error message is only meaningful if result is false, a null + * error message means use application default. + */ + protected abstract Pair<Boolean, String> shouldProceed(final String url); + + /** + * @return whether the content provider allows insertions. + */ + protected abstract boolean canInsert(); + + /** + * Start a request that a URL should be permitted + * + * @param url the URL that is wanted. + */ + protected abstract boolean requestInsert(final String url); + + /** + * Call to tell observers that the filter has changed. + */ + protected void onFilterChanged() { + getContext().getContentResolver().notifyChange( + mContentUri.buildUpon().appendPath("authorized").build(), null); + } +}
diff --git a/components/web_restriction/junit/src/org/chromium/components/webrestriction/WebRestrictionsContentProviderTest.java b/components/web_restriction/junit/src/org/chromium/components/webrestriction/WebRestrictionsContentProviderTest.java new file mode 100644 index 0000000..0da6bd8 --- /dev/null +++ b/components/web_restriction/junit/src/org/chromium/components/webrestriction/WebRestrictionsContentProviderTest.java
@@ -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. + +package org.chromium.components.webrestriction; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.junit.Assert.assertThat; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.ContentResolver; +import android.content.ContentValues; +import android.content.pm.ProviderInfo; +import android.database.Cursor; +import android.net.Uri; +import android.util.Pair; + +import org.chromium.testing.local.LocalRobolectricTestRunner; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.robolectric.Robolectric; +import org.robolectric.annotation.Config; +import org.robolectric.shadows.ShadowContentResolver; + +/** + * Tests of WebRestrictionsContentProvider. + */ +@RunWith(LocalRobolectricTestRunner.class) +@Config(manifest = Config.NONE) +public class WebRestrictionsContentProviderTest { + private static final String AUTHORITY = "org.chromium.browser.DummyProvider"; + + private WebRestrictionsContentProvider mContentProvider; + private ContentResolver mContentResolver; + private Uri mUri; + + @Before + public void setUp() { + // The test needs a concrete version of the test class, but mocks the additional members as + // necessary. + mContentProvider = Mockito.spy(new WebRestrictionsContentProvider() { + @Override + protected Pair<Boolean, String> shouldProceed(String url) { + return null; + } + + @Override + protected boolean canInsert() { + return false; + } + + @Override + protected boolean requestInsert(String url) { + return false; + } + }); + mContentProvider.onCreate(); + ShadowContentResolver.registerProvider(AUTHORITY, mContentProvider); + ProviderInfo info = new ProviderInfo(); + info.authority = AUTHORITY; + mContentProvider.attachInfo(null, info); + mContentResolver = Robolectric.application.getContentResolver(); + mUri = new Uri.Builder() + .scheme(ContentResolver.SCHEME_CONTENT) + .authority(AUTHORITY) + .build(); + } + + @Test + public void testQuery() { + when(mContentProvider.shouldProceed(anyString())) + .thenReturn(new Pair<Boolean, String>(false, "Error Message")); + Cursor cursor = mContentResolver.query(mUri.buildUpon().appendPath("authorized").build(), + null, "url = 'dummy'", null, null); + verify(mContentProvider).shouldProceed("dummy"); + assertThat(cursor, is(not(nullValue()))); + assertThat(cursor.getInt(0), is(WebRestrictionsContentProvider.BLOCKED)); + assertThat(cursor.getString(1), is("Error Message")); + when(mContentProvider.shouldProceed(anyString())) + .thenReturn(new Pair<Boolean, String>(true, null)); + cursor = mContentResolver.query(mUri.buildUpon().appendPath("authorized").build(), null, + "url = 'dummy'", null, null); + assertThat(cursor, is(not(nullValue()))); + assertThat(cursor.getInt(0), is(WebRestrictionsContentProvider.PROCEED)); + } + + @Test + public void testInsert() { + ContentValues values = new ContentValues(); + values.put("url", "dummy2"); + when(mContentProvider.requestInsert(anyString())).thenReturn(false); + assertThat( + mContentResolver.insert(mUri.buildUpon().appendPath("requested").build(), values), + is(nullValue())); + verify(mContentProvider).requestInsert("dummy2"); + values.put("url", "dummy3"); + when(mContentProvider.requestInsert(anyString())).thenReturn(true); + assertThat( + mContentResolver.insert(mUri.buildUpon().appendPath("requested").build(), values), + is(not(nullValue()))); + verify(mContentProvider).requestInsert("dummy3"); + } + + @Test + public void testGetType() { + assertThat(mContentResolver.getType(mUri.buildUpon().appendPath("junk").build()), + is(nullValue())); + when(mContentProvider.canInsert()).thenReturn(false); + assertThat(mContentResolver.getType(mUri.buildUpon().appendPath("requested").build()), + is(nullValue())); + when(mContentProvider.canInsert()).thenReturn(true); + assertThat(mContentResolver.getType(mUri.buildUpon().appendPath("requested").build()), + is(not(nullValue()))); + } +}
diff --git a/components/web_view/frame_apptest.cc b/components/web_view/frame_apptest.cc index 0c7ce4f..ce9f9cd 100644 --- a/components/web_view/frame_apptest.cc +++ b/components/web_view/frame_apptest.cc
@@ -392,7 +392,7 @@ mus::mojom::WindowTreeClientPtr window_tree_client = frame_connection->GetWindowTreeClient(); mus::Window* frame_root_view = window_manager()->NewWindow(); - window_manager()->GetRoot()->AddChild(frame_root_view); + (*window_manager()->GetRoots().begin())->AddChild(frame_root_view); frame_tree_.reset(new FrameTree( 0u, frame_root_view, std::move(window_tree_client), frame_tree_delegate_.get(), frame_client, std::move(frame_connection),
diff --git a/components/web_view/web_view_apptest.cc b/components/web_view/web_view_apptest.cc index d8d7858..eebd2d90 100644 --- a/components/web_view/web_view_apptest.cc +++ b/components/web_view/web_view_apptest.cc
@@ -115,8 +115,9 @@ } void TearDown() override { + ASSERT_EQ(1u, window_manager()->GetRoots().size()); mus::ScopedWindowPtr::DeleteWindowOrWindowManager( - window_manager()->GetRoot()); + *window_manager()->GetRoots().begin()); WindowServerTestBase::TearDown(); }
diff --git a/components/webusb/BUILD.gn b/components/webusb/BUILD.gn index f62a2ea1..de279d6a 100644 --- a/components/webusb/BUILD.gn +++ b/components/webusb/BUILD.gn
@@ -9,12 +9,14 @@ "webusb_detector.h", ] - deps = [ + public_deps = [ "//base", "//components/webusb/public/interfaces", - "//device/core", "//device/usb", ] + deps = [ + "//device/core", + ] } source_set("unit_tests") {
diff --git a/content/BUILD.gn b/content/BUILD.gn index 56be979..cb50de5 100644 --- a/content/BUILD.gn +++ b/content/BUILD.gn
@@ -56,7 +56,7 @@ } if (is_component_build) { - shared_library("content") { + component("content") { public_deps = content_shared_components + [ "//content/public/app:both_sources" ] deps = [
diff --git a/content/app/BUILD.gn b/content/app/BUILD.gn index e8575cc..923e608 100644 --- a/content/app/BUILD.gn +++ b/content/app/BUILD.gn
@@ -29,7 +29,7 @@ # This is needed by app/content_main_runner.cc # TODO(brettw) this shouldn't be here, only final executables should be - # picking the allocator. + # picking the allocator. http://crbug.com/571731 "//base/allocator", "//content:export", "//content:sandbox_helper_win",
diff --git a/content/app/DEPS b/content/app/DEPS index f4792db..7745238 100644 --- a/content/app/DEPS +++ b/content/app/DEPS
@@ -3,6 +3,7 @@ "+content", "+device/battery", "+device/bluetooth", + "+device/usb", "+device/vibration", # For loading V8's initial snapshot from external files. "+gin/public/isolate_holder.h",
diff --git a/content/app/android/library_loader_hooks.cc b/content/app/android/library_loader_hooks.cc index 487d973..21e51b3 100644 --- a/content/app/android/library_loader_hooks.cc +++ b/content/app/android/library_loader_hooks.cc
@@ -26,6 +26,7 @@ #include "content/public/common/content_switches.h" #include "content/public/common/result_codes.h" #include "device/bluetooth/android/bluetooth_jni_registrar.h" +#include "device/usb/android/usb_jni_registrar.h" #include "media/base/android/media_jni_registrar.h" #include "media/midi/midi_jni_registrar.h" #include "net/android/net_jni_registrar.h" @@ -75,6 +76,9 @@ if (!device::android::RegisterBluetoothJni(env)) return false; + if (!device::android::RegisterUsbJni(env)) + return false; + if (!media::RegisterJni(env)) return false;
diff --git a/content/app/content_main_runner.cc b/content/app/content_main_runner.cc index a686b02..3b5f88ad 100644 --- a/content/app/content_main_runner.cc +++ b/content/app/content_main_runner.cc
@@ -90,9 +90,7 @@ #if !defined(OS_IOS) #include "base/power_monitor/power_monitor_device_source.h" #include "content/app/mac/mac_init.h" -#include "content/browser/browser_io_surface_manager_mac.h" #include "content/browser/mach_broker_mac.h" -#include "content/child/child_io_surface_manager_mac.h" #include "content/common/sandbox_init_mac.h" #endif // !OS_IOS #endif // OS_WIN @@ -652,19 +650,6 @@ (!delegate_ || delegate_->ShouldSendMachPort(process_type))) { MachBroker::ChildSendTaskPortToParent(); } - - if (!command_line.HasSwitch(switches::kSingleProcess) && - !process_type.empty() && (process_type == switches::kRendererProcess || - process_type == switches::kGpuProcess)) { - base::mac::ScopedMachSendRight service_port = - BrowserIOSurfaceManager::LookupServicePort(getppid()); - if (service_port.is_valid()) { - ChildIOSurfaceManager::GetInstance()->set_service_port( - service_port.release()); - gfx::IOSurfaceManager::SetInstance( - ChildIOSurfaceManager::GetInstance()); - } - } #elif defined(OS_WIN) base::win::SetupCRT(command_line); #endif
diff --git a/content/browser/DEPS b/content/browser/DEPS index be561672..93be705 100644 --- a/content/browser/DEPS +++ b/content/browser/DEPS
@@ -13,6 +13,7 @@ "+device/battery", # For battery status service. "+device/vibration", # For Vibration API "+gin/v8_initializer.h", + "+media/media_features.h", "+media/audio", # For audio input for speech input feature. "+media/base", # For Android JNI registration. "+media/filters", # For reporting GPU decoding UMA.
diff --git a/content/browser/bad_message.h b/content/browser/bad_message.h index 356eb0e2..219cc12 100644 --- a/content/browser/bad_message.h +++ b/content/browser/bad_message.h
@@ -30,7 +30,7 @@ RVH_CAN_ACCESS_FILES_OF_PAGE_STATE = 6, RVH_FILE_CHOOSER_PATH = 7, RWH_SYNTHETIC_GESTURE = 8, - RWH_FOCUS = 9, + RWH_FOCUS = 9, // obsolete; no longer used RWH_BLUR = 10, RWH_SHARED_BITMAP = 11, RWH_BAD_ACK_MESSAGE = 12, @@ -124,6 +124,8 @@ BDH_EMPTY_OR_INVALID_FILTERS = 100, WC_CONTENT_WITH_CERT_ERRORS_BAD_SECURITY_INFO = 101, RFMF_RENDERER_FAKED_ITS_OWN_DEATH = 102, + DWNLD_INVALID_SAVABLE_RESOURCE_LINKS_RESPONSE = 103, + DWNLD_INVALID_SERIALIZE_AS_MHTML_RESPONSE = 104, // Please add new elements here. The naming convention is abbreviated class // name (e.g. RenderFrameHost becomes RFH) plus a unique description of the
diff --git a/content/browser/bootstrap_sandbox_manager_mac.cc b/content/browser/bootstrap_sandbox_manager_mac.cc index 48d2549..61d1b1e 100644 --- a/content/browser/bootstrap_sandbox_manager_mac.cc +++ b/content/browser/bootstrap_sandbox_manager_mac.cc
@@ -6,7 +6,6 @@ #include "base/logging.h" #include "base/mac/mac_util.h" -#include "content/browser/browser_io_surface_manager_mac.h" #include "content/browser/mach_broker_mac.h" #include "content/common/sandbox_init_mac.h" #include "content/public/browser/browser_thread.h" @@ -79,11 +78,6 @@ policy.rules["com.apple.windowserver.active"] = sandbox::Rule(sandbox::POLICY_ALLOW); - // Allow renderers to contact the IOSurfaceManager in the browser to share - // accelerated surfaces. - policy.rules[BrowserIOSurfaceManager::GetMachPortName()] = - sandbox::Rule(sandbox::POLICY_ALLOW); - // Allow access to launchservicesd on 10.10+ otherwise the renderer will crash // attempting to get its ASN. http://crbug.com/533537 if (base::mac::IsOSYosemiteOrLater()) {
diff --git a/content/browser/browser_io_surface_manager_mac.cc b/content/browser/browser_io_surface_manager_mac.cc deleted file mode 100644 index d859ee7..0000000 --- a/content/browser/browser_io_surface_manager_mac.cc +++ /dev/null
@@ -1,331 +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 "content/browser/browser_io_surface_manager_mac.h" - -#include <servers/bootstrap.h> - -#include <string> - -#include "base/logging.h" -#include "base/mac/foundation_util.h" -#include "base/mac/mach_logging.h" -#include "base/strings/stringprintf.h" -#include "content/browser/gpu/browser_gpu_channel_host_factory.h" - -namespace content { -namespace { - -// Returns the Mach port name to use when sending or receiving messages. |pid| -// is the process ID of the service. -std::string GetMachPortNameByPid(pid_t pid) { - return base::StringPrintf("%s.iosurfacemgr.%d", base::mac::BaseBundleID(), - pid); -} - -// Amount of time to wait before giving up when sending a reply message. -const int kSendReplyTimeoutMs = 100; - -} // namespace - -// static -BrowserIOSurfaceManager* BrowserIOSurfaceManager::GetInstance() { - return base::Singleton< - BrowserIOSurfaceManager, - base::LeakySingletonTraits<BrowserIOSurfaceManager>>::get(); -} - -// static -base::mac::ScopedMachSendRight BrowserIOSurfaceManager::LookupServicePort( - pid_t pid) { - // Look up the named IOSurfaceManager port that's been registered with - // the bootstrap server. - mach_port_t port; - kern_return_t kr = - bootstrap_look_up(bootstrap_port, - GetMachPortNameByPid(pid).c_str(), - &port); - if (kr != KERN_SUCCESS) { - BOOTSTRAP_LOG(ERROR, kr) << "bootstrap_look_up"; - return base::mac::ScopedMachSendRight(); - } - - return base::mac::ScopedMachSendRight(port); -} - -// static -std::string BrowserIOSurfaceManager::GetMachPortName() { - return GetMachPortNameByPid(getpid()); -} - -bool BrowserIOSurfaceManager::RegisterIOSurface(gfx::IOSurfaceId io_surface_id, - int client_id, - IOSurfaceRef io_surface) { - base::AutoLock lock(lock_); - - IOSurfaceMapKey key(io_surface_id, client_id); - DCHECK(io_surfaces_.find(key) == io_surfaces_.end()); - io_surfaces_.insert( - std::make_pair(key, base::ScopedCFTypeRef<IOSurfaceRef>(io_surface))); - return true; -} - -void BrowserIOSurfaceManager::UnregisterIOSurface( - gfx::IOSurfaceId io_surface_id, - int client_id) { - base::AutoLock lock(lock_); - - IOSurfaceMapKey key(io_surface_id, client_id); - DCHECK(io_surfaces_.find(key) != io_surfaces_.end()); - io_surfaces_.erase(key); -} - -IOSurfaceRef BrowserIOSurfaceManager::AcquireIOSurface( - gfx::IOSurfaceId io_surface_id) { - base::AutoLock lock(lock_); - - IOSurfaceMapKey key( - io_surface_id, - BrowserGpuChannelHostFactory::instance()->GetGpuChannelId()); - auto it = io_surfaces_.find(key); - if (it == io_surfaces_.end()) { - LOG(ERROR) << "Invalid Id for IOSurface " << io_surface_id.id; - return nullptr; - } - - IOSurfaceRef io_surface = it->second; - CFRetain(io_surface); - return io_surface; -} - -void BrowserIOSurfaceManager::EnsureRunning() { - base::AutoLock lock(lock_); - - if (initialized_) - return; - - // Do not attempt to reinitialize in the event of failure. - initialized_ = true; - - if (!Initialize()) { - LOG(ERROR) << "Failed to initialize the BrowserIOSurfaceManager"; - } -} - -IOSurfaceManagerToken BrowserIOSurfaceManager::GenerateGpuProcessToken() { - base::AutoLock lock(lock_); - - DCHECK(gpu_process_token_.IsZero()); - gpu_process_token_ = IOSurfaceManagerToken::Generate(); - DCHECK(gpu_process_token_.Verify()); - return gpu_process_token_; -} - -void BrowserIOSurfaceManager::InvalidateGpuProcessToken() { - base::AutoLock lock(lock_); - - DCHECK(!gpu_process_token_.IsZero()); - gpu_process_token_.SetZero(); - io_surfaces_.clear(); -} - -IOSurfaceManagerToken BrowserIOSurfaceManager::GenerateChildProcessToken( - int child_process_id) { - base::AutoLock lock(lock_); - - IOSurfaceManagerToken token = IOSurfaceManagerToken::Generate(); - DCHECK(token.Verify()); - child_process_ids_[token] = child_process_id; - return token; -} - -void BrowserIOSurfaceManager::InvalidateChildProcessToken( - const IOSurfaceManagerToken& token) { - base::AutoLock lock(lock_); - - DCHECK(child_process_ids_.find(token) != child_process_ids_.end()); - child_process_ids_.erase(token); -} - -BrowserIOSurfaceManager::BrowserIOSurfaceManager() : initialized_(false) { -} - -BrowserIOSurfaceManager::~BrowserIOSurfaceManager() { -} - -bool BrowserIOSurfaceManager::Initialize() { - lock_.AssertAcquired(); - DCHECK(!server_port_.is_valid()); - - // Check in with launchd and publish the service name. - mach_port_t port; - kern_return_t kr = bootstrap_check_in( - bootstrap_port, GetMachPortName().c_str(), &port); - if (kr != KERN_SUCCESS) { - BOOTSTRAP_LOG(ERROR, kr) << "bootstrap_check_in"; - return false; - } - server_port_.reset(port); - - // Start the dispatch source. - std::string queue_name = - base::StringPrintf("%s.IOSurfaceManager", base::mac::BaseBundleID()); - dispatch_source_.reset( - new base::DispatchSourceMach(queue_name.c_str(), server_port_.get(), ^{ - HandleRequest(); - })); - dispatch_source_->Resume(); - - return true; -} - -void BrowserIOSurfaceManager::HandleRequest() { - struct { - union { - mach_msg_header_t header; - IOSurfaceManagerHostMsg_RegisterIOSurface register_io_surface; - IOSurfaceManagerHostMsg_UnregisterIOSurface unregister_io_surface; - IOSurfaceManagerHostMsg_AcquireIOSurface acquire_io_surface; - } msg; - mach_msg_trailer_t trailer; - } request = {{{0}}}; - request.msg.header.msgh_size = sizeof(request); - request.msg.header.msgh_local_port = server_port_.get(); - - kern_return_t kr = - mach_msg(&request.msg.header, MACH_RCV_MSG, 0, sizeof(request), - server_port_.get(), MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); - if (kr != KERN_SUCCESS) { - MACH_LOG(ERROR, kr) << "mach_msg"; - return; - } - - union { - mach_msg_header_t header; - IOSurfaceManagerMsg_RegisterIOSurfaceReply register_io_surface; - IOSurfaceManagerMsg_AcquireIOSurfaceReply acquire_io_surface; - } reply = {{0}}; - - switch (request.msg.header.msgh_id) { - case IOSurfaceManagerHostMsg_RegisterIOSurface::ID: - HandleRegisterIOSurfaceRequest(request.msg.register_io_surface, - &reply.register_io_surface); - break; - case IOSurfaceManagerHostMsg_UnregisterIOSurface::ID: - HandleUnregisterIOSurfaceRequest(request.msg.unregister_io_surface); - // Unregister requests are asynchronous and do not require a reply as - // there is no guarantee for how quickly an IO surface is removed from - // the IOSurfaceManager instance after it has been deleted by a child - // process. - return; - case IOSurfaceManagerHostMsg_AcquireIOSurface::ID: - HandleAcquireIOSurfaceRequest(request.msg.acquire_io_surface, - &reply.acquire_io_surface); - break; - default: - LOG(ERROR) << "Unknown message received!"; - return; - } - - kr = mach_msg(&reply.header, MACH_SEND_MSG | MACH_SEND_TIMEOUT, - reply.header.msgh_size, 0, MACH_PORT_NULL, kSendReplyTimeoutMs, - MACH_PORT_NULL); - if (kr != KERN_SUCCESS) { - MACH_LOG(ERROR, kr) << "mach_msg"; - } -} - -void BrowserIOSurfaceManager::HandleRegisterIOSurfaceRequest( - const IOSurfaceManagerHostMsg_RegisterIOSurface& request, - IOSurfaceManagerMsg_RegisterIOSurfaceReply* reply) { - base::AutoLock lock(lock_); - - reply->header.msgh_bits = MACH_MSGH_BITS_REMOTE(request.header.msgh_bits); - reply->header.msgh_remote_port = request.header.msgh_remote_port; - reply->header.msgh_size = sizeof(*reply); - reply->body.msgh_descriptor_count = 0; - reply->result = false; - - IOSurfaceManagerToken token; - static_assert(sizeof(request.token_name) == sizeof(token.name), - "Mach message token size doesn't match expectation."); - token.SetName(request.token_name); - if (token.IsZero() || token != gpu_process_token_) { - LOG(ERROR) << "Illegal message from non-GPU process!"; - return; - } - - base::mac::ScopedMachSendRight io_surface_port(request.io_surface_port.name); - base::ScopedCFTypeRef<IOSurfaceRef> io_surface( - IOSurfaceLookupFromMachPort(io_surface_port.get())); - if (!io_surface) { - LOG(ERROR) << "Failed to open registered IOSurface port!"; - return; - } - IOSurfaceMapKey key(gfx::IOSurfaceId(request.io_surface_id), - request.client_id); - io_surfaces_.insert(std::make_pair(key, io_surface)); - reply->result = true; -} - -bool BrowserIOSurfaceManager::HandleUnregisterIOSurfaceRequest( - const IOSurfaceManagerHostMsg_UnregisterIOSurface& request) { - base::AutoLock lock(lock_); - - IOSurfaceManagerToken token; - static_assert(sizeof(request.token_name) == sizeof(token.name), - "Mach message token size doesn't match expectation."); - token.SetName(request.token_name); - if (token.IsZero() || token != gpu_process_token_) { - LOG(ERROR) << "Illegal message from non-GPU process!"; - return false; - } - - IOSurfaceMapKey key(gfx::IOSurfaceId(request.io_surface_id), - request.client_id); - io_surfaces_.erase(key); - return true; -} - -void BrowserIOSurfaceManager::HandleAcquireIOSurfaceRequest( - const IOSurfaceManagerHostMsg_AcquireIOSurface& request, - IOSurfaceManagerMsg_AcquireIOSurfaceReply* reply) { - base::AutoLock lock(lock_); - - reply->header.msgh_bits = - MACH_MSGH_BITS_REMOTE(request.header.msgh_bits) | MACH_MSGH_BITS_COMPLEX; - reply->header.msgh_remote_port = request.header.msgh_remote_port; - reply->header.msgh_size = sizeof(*reply); - reply->body.msgh_descriptor_count = 0; - reply->result = false; - reply->io_surface_port.name = MACH_PORT_NULL; - reply->io_surface_port.disposition = 0; - reply->io_surface_port.type = 0; - - IOSurfaceManagerToken token; - static_assert(sizeof(request.token_name) == sizeof(token.name), - "Mach message token size doesn't match expectation."); - token.SetName(request.token_name); - auto child_process_id_it = child_process_ids_.find(token); - if (child_process_id_it == child_process_ids_.end()) { - LOG(ERROR) << "Illegal message from non-child process!"; - return; - } - - reply->result = true; - IOSurfaceMapKey key(gfx::IOSurfaceId(request.io_surface_id), - child_process_id_it->second); - auto it = io_surfaces_.find(key); - if (it == io_surfaces_.end()) { - LOG(ERROR) << "Invalid Id for IOSurface " << request.io_surface_id; - return; - } - - reply->body.msgh_descriptor_count = 1; - reply->io_surface_port.name = IOSurfaceCreateMachPort(it->second); - reply->io_surface_port.disposition = MACH_MSG_TYPE_MOVE_SEND; - reply->io_surface_port.type = MACH_MSG_PORT_DESCRIPTOR; -} - -} // namespace content
diff --git a/content/browser/browser_io_surface_manager_mac.h b/content/browser/browser_io_surface_manager_mac.h deleted file mode 100644 index 021d6fd0..0000000 --- a/content/browser/browser_io_surface_manager_mac.h +++ /dev/null
@@ -1,130 +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 CONTENT_BROWSER_BROWSER_IO_SURFACE_MANAGER_MAC_H_ -#define CONTENT_BROWSER_BROWSER_IO_SURFACE_MANAGER_MAC_H_ - -#include <IOSurface/IOSurface.h> -#include <mach/mach.h> - -#include <map> -#include <utility> - -#include "base/containers/scoped_ptr_hash_map.h" -#include "base/mac/dispatch_source_mach.h" -#include "base/mac/scoped_cftyperef.h" -#include "base/mac/scoped_mach_port.h" -#include "base/macros.h" -#include "base/memory/scoped_ptr.h" -#include "base/memory/singleton.h" -#include "base/synchronization/lock.h" -#include "content/common/content_export.h" -#include "content/common/mac/io_surface_manager_messages.h" -#include "content/common/mac/io_surface_manager_token.h" -#include "ui/gfx/mac/io_surface_manager.h" - -namespace content { - -// TODO(ericrk): Use gfx::GenericSharedMemoryId as the |io_surface_id| in -// this file. Allows for more type-safe usage of GpuMemoryBufferIds as the -// type of the |io_surface_id|, as it is a typedef of -// gfx::GenericSharedMemoryId. - -// Implementation of IOSurfaceManager that provides a mechanism for child -// processes to register and acquire IOSurfaces through a Mach service. -class CONTENT_EXPORT BrowserIOSurfaceManager : public gfx::IOSurfaceManager { - public: - // Returns the global BrowserIOSurfaceManager. - static BrowserIOSurfaceManager* GetInstance(); - - // Look up the IOSurfaceManager service port that's been registered with - // the bootstrap server. |pid| is the process ID of the service. - static base::mac::ScopedMachSendRight LookupServicePort(pid_t pid); - - // Returns the name of the service registered with the bootstrap server. - static std::string GetMachPortName(); - - // Overridden from IOSurfaceManager: - bool RegisterIOSurface(gfx::IOSurfaceId io_surface_id, - int client_id, - IOSurfaceRef io_surface) override; - void UnregisterIOSurface(gfx::IOSurfaceId io_surface_id, - int client_id) override; - IOSurfaceRef AcquireIOSurface(gfx::IOSurfaceId io_surface_id) override; - - // Performs any necessary setup that cannot happen in the constructor. - void EnsureRunning(); - - // Generate a unique unguessable token that the GPU process can use to - // register/unregister IOSurface for use by clients. - IOSurfaceManagerToken GenerateGpuProcessToken(); - - // Invalidate the previously generated GPU process token. - void InvalidateGpuProcessToken(); - - // Generate a unique unguessable token that the child process associated - // |child_process_id| can use to acquire IOSurface references. - IOSurfaceManagerToken GenerateChildProcessToken(int child_process_id); - - // Invalidate a previously generated child process token. - void InvalidateChildProcessToken(const IOSurfaceManagerToken& token); - - private: - friend class BrowserIOSurfaceManagerTest; - friend struct base::DefaultSingletonTraits<BrowserIOSurfaceManager>; - - BrowserIOSurfaceManager(); - ~BrowserIOSurfaceManager() override; - - // Performs any initialization work. - bool Initialize(); - - // Message handler that is invoked on |dispatch_source_| when an - // incoming message needs to be received. - void HandleRequest(); - - // Message handlers that are invoked from HandleRequest. - void HandleRegisterIOSurfaceRequest( - const IOSurfaceManagerHostMsg_RegisterIOSurface& request, - IOSurfaceManagerMsg_RegisterIOSurfaceReply* reply); - bool HandleUnregisterIOSurfaceRequest( - const IOSurfaceManagerHostMsg_UnregisterIOSurface& request); - void HandleAcquireIOSurfaceRequest( - const IOSurfaceManagerHostMsg_AcquireIOSurface& request, - IOSurfaceManagerMsg_AcquireIOSurfaceReply* reply); - - // Whether or not the class has been initialized. - bool initialized_; - - // The Mach port on which the server listens. - base::mac::ScopedMachReceiveRight server_port_; - - // The dispatch source and queue on which Mach messages will be received. - scoped_ptr<base::DispatchSourceMach> dispatch_source_; - - // Stores the IOSurfaces for all GPU clients. The key contains the IOSurface - // id and the Child process unique id of the owner. - using IOSurfaceMapKey = std::pair<gfx::IOSurfaceId, int>; - using IOSurfaceMap = - std::map<IOSurfaceMapKey, base::ScopedCFTypeRef<IOSurfaceRef>>; - IOSurfaceMap io_surfaces_; - - // Stores the Child process unique id (RenderProcessHost ID) for every - // token. - using ChildProcessIdMap = std::map<IOSurfaceManagerToken, int>; - ChildProcessIdMap child_process_ids_; - - // Stores the GPU process token. - IOSurfaceManagerToken gpu_process_token_; - - // Mutex that guards |initialized_|, |io_surfaces_|, |child_process_ids_| - // and |gpu_process_token_|. - base::Lock lock_; - - DISALLOW_COPY_AND_ASSIGN(BrowserIOSurfaceManager); -}; - -} // namespace content - -#endif // CONTENT_BROWSER_BROWSER_IO_SURFACE_MANAGER_MAC_H_
diff --git a/content/browser/browser_io_surface_manager_mac_unittest.cc b/content/browser/browser_io_surface_manager_mac_unittest.cc deleted file mode 100644 index 38de070..0000000 --- a/content/browser/browser_io_surface_manager_mac_unittest.cc +++ /dev/null
@@ -1,331 +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 "content/browser/browser_io_surface_manager_mac.h" - -#include "testing/gtest/include/gtest/gtest.h" -#include "ui/gfx/mac/io_surface_manager.h" - -namespace content { - -class BrowserIOSurfaceManagerTest : public testing::Test { - public: - void EnsureRunning() { io_surface_manager_.EnsureRunning(); } - - IOSurfaceManagerToken GenerateGpuProcessToken() { - return io_surface_manager_.GenerateGpuProcessToken(); - } - - void InvalidateGpuProcessToken() { - io_surface_manager_.InvalidateGpuProcessToken(); - } - - IOSurfaceManagerToken GenerateChildProcessToken(int child_process_id) { - return io_surface_manager_.GenerateChildProcessToken(child_process_id); - } - - void InvalidateChildProcessToken(const IOSurfaceManagerToken& token) { - io_surface_manager_.InvalidateChildProcessToken(token); - } - - bool HandleRegisterIOSurfaceRequest( - const IOSurfaceManagerHostMsg_RegisterIOSurface& request, - IOSurfaceManagerMsg_RegisterIOSurfaceReply* reply) { - io_surface_manager_.HandleRegisterIOSurfaceRequest(request, reply); - return reply->result; - } - - bool HandleUnregisterIOSurfaceRequest( - const IOSurfaceManagerHostMsg_UnregisterIOSurface& request) { - return io_surface_manager_.HandleUnregisterIOSurfaceRequest(request); - } - - bool HandleAcquireIOSurfaceRequest( - const IOSurfaceManagerHostMsg_AcquireIOSurface& request, - IOSurfaceManagerMsg_AcquireIOSurfaceReply* reply) { - io_surface_manager_.HandleAcquireIOSurfaceRequest(request, reply); - return reply->result; - } - - // Helper function used to register an IOSurface for testing. - void RegisterIOSurface(const IOSurfaceManagerToken& gpu_process_token, - int io_surface_id, - int client_id, - mach_port_t io_surface_port) { - IOSurfaceManagerHostMsg_RegisterIOSurface request = {{0}}; - IOSurfaceManagerMsg_RegisterIOSurfaceReply reply = {{0}}; - request.io_surface_id = io_surface_id; - request.client_id = client_id; - request.io_surface_port.name = GetIOSurfaceMachPort(); - memcpy(request.token_name, gpu_process_token.name, - sizeof(gpu_process_token.name)); - ASSERT_TRUE(HandleRegisterIOSurfaceRequest(request, &reply)); - ASSERT_TRUE(reply.result); - } - - mach_port_t GetIOSurfaceMachPort() { - if (!io_surface_) { - io_surface_.reset(gfx::IOSurfaceManager::CreateIOSurface( - gfx::Size(32, 32), gfx::BufferFormat::BGRA_8888)); - io_surface_port_.reset(IOSurfaceCreateMachPort(io_surface_)); - } - return io_surface_port_.get(); - } - - private: - BrowserIOSurfaceManager io_surface_manager_; - base::ScopedCFTypeRef<IOSurfaceRef> io_surface_; - base::mac::ScopedMachSendRight io_surface_port_; -}; - -TEST_F(BrowserIOSurfaceManagerTest, EnsureRunning) { - EnsureRunning(); - base::mac::ScopedMachSendRight service_port = - BrowserIOSurfaceManager::LookupServicePort(getpid()); - EXPECT_TRUE(service_port.is_valid()); -} - -TEST_F(BrowserIOSurfaceManagerTest, RegisterIOSurfaceSucceeds) { - const int kIOSurfaceId = 1; - const int kClientId = 1; - - base::ScopedCFTypeRef<IOSurfaceRef> io_surface( - gfx::IOSurfaceManager::CreateIOSurface(gfx::Size(32, 32), - gfx::BufferFormat::BGRA_8888)); - base::mac::ScopedMachSendRight io_surface_port( - IOSurfaceCreateMachPort(io_surface)); - - IOSurfaceManagerToken gpu_process_token = GenerateGpuProcessToken(); - - IOSurfaceManagerHostMsg_RegisterIOSurface request = {{0}}; - IOSurfaceManagerMsg_RegisterIOSurfaceReply reply = {{0}}; - - request.io_surface_id = kIOSurfaceId; - request.client_id = kClientId; - request.io_surface_port.name = GetIOSurfaceMachPort(); - memcpy(request.token_name, gpu_process_token.name, - sizeof(gpu_process_token.name)); - EXPECT_TRUE(HandleRegisterIOSurfaceRequest(request, &reply)); - EXPECT_TRUE(reply.result); -} - -TEST_F(BrowserIOSurfaceManagerTest, RegisterIOSurfaceFailsWithInvalidToken) { - const int kIOSurfaceId = 1; - const int kClientId = 1; - - IOSurfaceManagerHostMsg_RegisterIOSurface request = {{0}}; - IOSurfaceManagerMsg_RegisterIOSurfaceReply reply = {{0}}; - request.io_surface_id = kIOSurfaceId; - request.client_id = kClientId; - // Fails as request doesn't contain a valid token. - EXPECT_FALSE(HandleRegisterIOSurfaceRequest(request, &reply)); -} - -TEST_F(BrowserIOSurfaceManagerTest, - RegisterIOSurfaceFailsWithChildProcessToken) { - const int kIOSurfaceId = 1; - const int kClientId = 1; - - IOSurfaceManagerToken child_process_token = - GenerateChildProcessToken(kClientId); - - IOSurfaceManagerHostMsg_RegisterIOSurface request = {{0}}; - IOSurfaceManagerMsg_RegisterIOSurfaceReply reply = {{0}}; - request.io_surface_id = kIOSurfaceId; - request.client_id = kClientId; - memcpy(request.token_name, child_process_token.name, - sizeof(child_process_token.name)); - // Fails as child process is not allowed to register IOSurfaces. - EXPECT_FALSE(HandleRegisterIOSurfaceRequest(request, &reply)); -} - -TEST_F(BrowserIOSurfaceManagerTest, RegisterIOSurfaceFailsWithInvalidPort) { - const int kIOSurfaceId = 1; - const int kClientId = 1; - const mach_port_t kIOInvalidSurfacePortId = 100u; - - base::ScopedCFTypeRef<IOSurfaceRef> io_surface( - gfx::IOSurfaceManager::CreateIOSurface(gfx::Size(32, 32), - gfx::BufferFormat::BGRA_8888)); - base::mac::ScopedMachSendRight io_surface_port( - IOSurfaceCreateMachPort(io_surface)); - - IOSurfaceManagerToken gpu_process_token = GenerateGpuProcessToken(); - - IOSurfaceManagerHostMsg_RegisterIOSurface request = {{0}}; - IOSurfaceManagerMsg_RegisterIOSurfaceReply reply = {{0}}; - - request.io_surface_id = kIOSurfaceId; - request.client_id = kClientId; - request.io_surface_port.name = kIOInvalidSurfacePortId; - memcpy(request.token_name, gpu_process_token.name, - sizeof(gpu_process_token.name)); - EXPECT_FALSE(HandleRegisterIOSurfaceRequest(request, &reply)); - EXPECT_FALSE(reply.result); -} - -TEST_F(BrowserIOSurfaceManagerTest, UnregisterIOSurfaceSucceeds) { - const int kIOSurfaceId = 1; - const int kClientId = 1; - - IOSurfaceManagerToken gpu_process_token = GenerateGpuProcessToken(); - - RegisterIOSurface(gpu_process_token, kIOSurfaceId, kClientId, 0); - - IOSurfaceManagerHostMsg_UnregisterIOSurface request = {{0}}; - request.io_surface_id = kIOSurfaceId; - request.client_id = kClientId; - memcpy(request.token_name, gpu_process_token.name, - sizeof(gpu_process_token.name)); - EXPECT_TRUE(HandleUnregisterIOSurfaceRequest(request)); -} - -TEST_F(BrowserIOSurfaceManagerTest, UnregisterIOSurfaceFailsWithInvalidToken) { - const int kIOSurfaceId = 1; - const int kClientId = 1; - - IOSurfaceManagerToken gpu_process_token = GenerateGpuProcessToken(); - - RegisterIOSurface(gpu_process_token, kIOSurfaceId, kClientId, 0); - - IOSurfaceManagerHostMsg_UnregisterIOSurface request = {{0}}; - request.io_surface_id = kIOSurfaceId; - request.client_id = kClientId; - // Fails as request doesn't contain valid GPU token. - EXPECT_FALSE(HandleUnregisterIOSurfaceRequest(request)); -} - -TEST_F(BrowserIOSurfaceManagerTest, - UnregisterIOSurfaceFailsWithChildProcessToken) { - const int kIOSurfaceId = 1; - const int kClientId = 1; - - IOSurfaceManagerToken gpu_process_token = GenerateGpuProcessToken(); - IOSurfaceManagerToken child_process_token = - GenerateChildProcessToken(kClientId); - - RegisterIOSurface(gpu_process_token, kIOSurfaceId, kClientId, 0); - - IOSurfaceManagerHostMsg_UnregisterIOSurface request = {{0}}; - request.io_surface_id = kIOSurfaceId; - request.client_id = kClientId; - memcpy(request.token_name, child_process_token.name, - sizeof(child_process_token.name)); - // Fails as child process is not allowed to unregister IOSurfaces. - EXPECT_FALSE(HandleUnregisterIOSurfaceRequest(request)); -} - -TEST_F(BrowserIOSurfaceManagerTest, AcquireIOSurfaceSucceeds) { - const int kIOSurfaceId = 10; - const int kClientId = 1; - const mach_port_t io_surface_port = GetIOSurfaceMachPort(); - - IOSurfaceManagerToken gpu_process_token = GenerateGpuProcessToken(); - IOSurfaceManagerToken child_process_token = - GenerateChildProcessToken(kClientId); - - RegisterIOSurface(gpu_process_token, kIOSurfaceId, kClientId, - io_surface_port); - - IOSurfaceManagerHostMsg_AcquireIOSurface request = {{0}}; - IOSurfaceManagerMsg_AcquireIOSurfaceReply reply = {{0}}; - request.io_surface_id = kIOSurfaceId; - memcpy(request.token_name, child_process_token.name, - sizeof(child_process_token.name)); - EXPECT_TRUE(HandleAcquireIOSurfaceRequest(request, &reply)); -} - -TEST_F(BrowserIOSurfaceManagerTest, AcquireIOSurfaceFailsWithInvalidToken) { - const int kIOSurfaceId = 10; - const int kClientId = 1; - const mach_port_t io_surface_port = GetIOSurfaceMachPort(); - - IOSurfaceManagerToken gpu_process_token = GenerateGpuProcessToken(); - - RegisterIOSurface(gpu_process_token, kIOSurfaceId, kClientId, - io_surface_port); - - IOSurfaceManagerHostMsg_AcquireIOSurface request = {{0}}; - IOSurfaceManagerMsg_AcquireIOSurfaceReply reply = {{0}}; - request.io_surface_id = kIOSurfaceId; - // Fails as request doesn't contain valid token. - EXPECT_FALSE(HandleAcquireIOSurfaceRequest(request, &reply)); -} - -TEST_F(BrowserIOSurfaceManagerTest, - AcquireIOSurfaceFailsWithWrongChildProcessToken) { - const int kIOSurfaceId = 10; - const int kClientId1 = 1; - const int kClientId2 = 2; - const mach_port_t io_surface_port = GetIOSurfaceMachPort(); - - IOSurfaceManagerToken gpu_process_token = GenerateGpuProcessToken(); - IOSurfaceManagerToken child_process_token2 = - GenerateChildProcessToken(kClientId2); - - RegisterIOSurface(gpu_process_token, kIOSurfaceId, kClientId1, - io_surface_port); - - IOSurfaceManagerHostMsg_AcquireIOSurface request = {{0}}; - IOSurfaceManagerMsg_AcquireIOSurfaceReply reply = {{0}}; - request.io_surface_id = kIOSurfaceId; - memcpy(request.token_name, child_process_token2.name, - sizeof(child_process_token2.name)); - EXPECT_TRUE(HandleAcquireIOSurfaceRequest(request, &reply)); - // Fails as child process 2 is not allowed to acquire this IOSurface. - EXPECT_EQ(static_cast<mach_port_t>(MACH_PORT_NULL), - reply.io_surface_port.name); -} - -TEST_F(BrowserIOSurfaceManagerTest, - AcquireIOSurfaceFailsAfterInvalidatingChildProcessToken) { - const int kIOSurfaceId = 10; - const int kClientId = 1; - const mach_port_t io_surface_port = GetIOSurfaceMachPort(); - - IOSurfaceManagerToken gpu_process_token = GenerateGpuProcessToken(); - IOSurfaceManagerToken child_process_token = - GenerateChildProcessToken(kClientId); - - RegisterIOSurface(gpu_process_token, kIOSurfaceId, kClientId, - io_surface_port); - - InvalidateChildProcessToken(child_process_token); - - IOSurfaceManagerHostMsg_AcquireIOSurface request = {{0}}; - IOSurfaceManagerMsg_AcquireIOSurfaceReply reply = {{0}}; - request.io_surface_id = kIOSurfaceId; - memcpy(request.token_name, child_process_token.name, - sizeof(child_process_token.name)); - // Fails as token is no longer valid. - EXPECT_FALSE(HandleAcquireIOSurfaceRequest(request, &reply)); -} - -TEST_F(BrowserIOSurfaceManagerTest, - AcquireIOSurfaceAfterInvalidatingGpuProcessToken) { - const int kIOSurfaceId = 10; - const int kClientId = 1; - const mach_port_t io_surface_port = GetIOSurfaceMachPort(); - - IOSurfaceManagerToken gpu_process_token = GenerateGpuProcessToken(); - IOSurfaceManagerToken child_process_token = - GenerateChildProcessToken(kClientId); - - RegisterIOSurface(gpu_process_token, kIOSurfaceId, kClientId, - io_surface_port); - - InvalidateGpuProcessToken(); - - IOSurfaceManagerHostMsg_AcquireIOSurface request = {{0}}; - IOSurfaceManagerMsg_AcquireIOSurfaceReply reply = {{0}}; - request.io_surface_id = kIOSurfaceId; - memcpy(request.token_name, child_process_token.name, - sizeof(child_process_token.name)); - EXPECT_TRUE(HandleAcquireIOSurfaceRequest(request, &reply)); - // Should return invalid port. - EXPECT_EQ(static_cast<mach_port_t>(MACH_PORT_NULL), - reply.io_surface_port.name); -} - -} // namespace content
diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc index 5daf100..732f0e2 100644 --- a/content/browser/browser_main_loop.cc +++ b/content/browser/browser_main_loop.cc
@@ -111,10 +111,8 @@ #if defined(OS_MACOSX) && !defined(OS_IOS) #include "base/memory/memory_pressure_monitor_mac.h" #include "content/browser/bootstrap_sandbox_manager_mac.h" -#include "content/browser/browser_io_surface_manager_mac.h" #include "content/browser/cocoa/system_hotkey_helper_mac.h" #include "content/browser/compositor/browser_compositor_view_mac.h" -#include "content/browser/in_process_io_surface_manager_mac.h" #include "content/browser/theme_helper_mac.h" #include "ui/accelerated_widget_mac/window_resize_helper_mac.h" #endif @@ -662,17 +660,6 @@ #endif #if defined(OS_MACOSX) && !defined(OS_IOS) - { - TRACE_EVENT0("startup", "BrowserMainLoop::Subsystem:IOSurfaceManager"); - if (parsed_command_line_.HasSwitch(switches::kSingleProcess)) { - gfx::IOSurfaceManager::SetInstance( - InProcessIOSurfaceManager::GetInstance()); - } else { - gfx::IOSurfaceManager::SetInstance( - BrowserIOSurfaceManager::GetInstance()); - } - } - if (BootstrapSandboxManager::ShouldEnable()) { TRACE_EVENT0("startup", "BrowserMainLoop::Subsystem:BootstrapSandbox");
diff --git a/content/browser/cache_storage/cache_storage_cache.cc b/content/browser/cache_storage/cache_storage_cache.cc index a99154f..2fc7411 100644 --- a/content/browser/cache_storage/cache_storage_cache.cc +++ b/content/browser/cache_storage/cache_storage_cache.cc
@@ -815,11 +815,12 @@ scoped_ptr<disk_cache::Entry*> entry_ptr, scoped_ptr<PutContext> put_context, int rv) { + put_context->cache_entry.reset(*entry_ptr); + if (rv != net::OK) { put_context->callback.Run(CACHE_STORAGE_ERROR_EXISTS); return; } - put_context->cache_entry.reset(*entry_ptr); CacheMetadata metadata; CacheRequest* request_metadata = metadata.mutable_request();
diff --git a/content/browser/child_process_launcher.cc b/content/browser/child_process_launcher.cc index b0052d5a..40d78e0 100644 --- a/content/browser/child_process_launcher.cc +++ b/content/browser/child_process_launcher.cc
@@ -30,7 +30,6 @@ #include "content/public/common/sandbox_init.h" #elif defined(OS_MACOSX) #include "content/browser/bootstrap_sandbox_manager_mac.h" -#include "content/browser/browser_io_surface_manager_mac.h" #include "content/browser/mach_broker_mac.h" #include "sandbox/mac/bootstrap_sandbox.h" #include "sandbox/mac/pre_exec_delegate.h" @@ -243,9 +242,6 @@ // check-in from the new process. broker->EnsureRunning(); - // Make sure the IOSurfaceManager service is running. - BrowserIOSurfaceManager::GetInstance()->EnsureRunning(); - const SandboxType sandbox_type = delegate->GetSandboxType(); scoped_ptr<sandbox::PreExecDelegate> pre_exec_delegate; if (BootstrapSandboxManager::ShouldEnable()) {
diff --git a/content/browser/compositor/gpu_browser_compositor_output_surface.cc b/content/browser/compositor/gpu_browser_compositor_output_surface.cc index 3dde15a..adf0764c 100644 --- a/content/browser/compositor/gpu_browser_compositor_output_surface.cc +++ b/content/browser/compositor/gpu_browser_compositor_output_surface.cc
@@ -61,6 +61,10 @@ swap_buffers_completion_callback_.callback()); GetCommandBufferProxy()->SetUpdateVSyncParametersCallback( update_vsync_parameters_callback_.callback()); + if (capabilities_.uses_default_gl_framebuffer) { + capabilities_.flipped_output_surface = + context_provider()->ContextCapabilities().gpu.flips_vertically; + } return true; }
diff --git a/content/browser/download/mhtml_generation_manager.cc b/content/browser/download/mhtml_generation_manager.cc index accd940f..792e019 100644 --- a/content/browser/download/mhtml_generation_manager.cc +++ b/content/browser/download/mhtml_generation_manager.cc
@@ -17,6 +17,7 @@ #include "base/stl_util.h" #include "base/strings/string_number_conversions.h" #include "base/strings/stringprintf.h" +#include "content/browser/bad_message.h" #include "content/browser/frame_host/frame_tree_node.h" #include "content/browser/frame_host/render_frame_host_impl.h" #include "content/common/frame_messages.h" @@ -25,7 +26,6 @@ #include "content/public/browser/render_process_host.h" #include "content/public/browser/render_process_host_observer.h" #include "content/public/browser/web_contents.h" -#include "url/gurl.h" namespace content { @@ -36,6 +36,7 @@ Job(int job_id, WebContents* web_contents, GenerateMHTMLCallback callback); ~Job() override; + int id() const { return job_id_; } void set_browser_file(base::File file) { browser_file_ = std::move(file); } GenerateMHTMLCallback callback() const { return callback_; } @@ -250,7 +251,8 @@ // Sanitize renderer input / reject unexpected messages. int sender_id = sender->frame_tree_node()->frame_tree_node_id(); if (sender_id != frame_tree_node_id_of_busy_frame_) { - NOTREACHED(); + ReceivedBadMessage(sender->GetProcess(), + bad_message::DWNLD_INVALID_SERIALIZE_AS_MHTML_RESPONSE); return false; // Report failure. } frame_tree_node_id_of_busy_frame_ = FrameTreeNode::kFrameTreeNodeInvalidId; @@ -329,23 +331,26 @@ const std::set<std::string>& digests_of_uris_of_serialized_resources) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - if (!mhtml_generation_in_renderer_succeeded) { - JobFinished(job_id, JobStatus::FAILURE); + Job* job = FindJob(job_id); + if (!job) { + ReceivedBadMessage(sender->GetProcess(), + bad_message::DWNLD_INVALID_SERIALIZE_AS_MHTML_RESPONSE); return; } - Job* job = FindJob(job_id); - if (!job) + if (!mhtml_generation_in_renderer_succeeded) { + JobFinished(job, JobStatus::FAILURE); return; + } if (!job->OnSerializeAsMHTMLResponse( sender, digests_of_uris_of_serialized_resources)) { - JobFinished(job_id, JobStatus::FAILURE); + JobFinished(job, JobStatus::FAILURE); return; } if (job->IsDone()) - JobFinished(job_id, JobStatus::SUCCESS); + JobFinished(job, JobStatus::SUCCESS); } // static @@ -372,34 +377,30 @@ base::File browser_file) { DCHECK_CURRENTLY_ON(BrowserThread::UI); + Job* job = FindJob(job_id); + DCHECK(job); + if (!browser_file.IsValid()) { LOG(ERROR) << "Failed to create file"; - JobFinished(job_id, JobStatus::FAILURE); + JobFinished(job, JobStatus::FAILURE); return; } - Job* job = FindJob(job_id); - if (!job) - return; - job->set_browser_file(std::move(browser_file)); if (!job->SendToNextRenderFrame()) { - JobFinished(job_id, JobStatus::FAILURE); + JobFinished(job, JobStatus::FAILURE); } } -void MHTMLGenerationManager::JobFinished(int job_id, JobStatus job_status) { +void MHTMLGenerationManager::JobFinished(Job* job, JobStatus job_status) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - - Job* job = FindJob(job_id); - if (!job) - return; + DCHECK(job); job->CloseFile( base::Bind(&MHTMLGenerationManager::OnFileClosed, base::Unretained(this), // Safe b/c |this| is a singleton. - job_id, job_status)); + job->id(), job_status)); } void MHTMLGenerationManager::OnFileClosed(int job_id, @@ -408,8 +409,7 @@ DCHECK_CURRENTLY_ON(BrowserThread::UI); Job* job = FindJob(job_id); - if (!job) - return; + DCHECK(job); job->callback().Run(job_status == JobStatus::SUCCESS ? file_size : -1); id_to_job_.erase(job_id); @@ -439,15 +439,8 @@ void MHTMLGenerationManager::RenderProcessExited(Job* job) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - - for (IDToJobMap::iterator it = id_to_job_.begin(); it != id_to_job_.end(); - ++it) { - if (it->second == job) { - JobFinished(it->first, JobStatus::FAILURE); - return; - } - } - NOTREACHED(); + DCHECK(job); + JobFinished(job, JobStatus::FAILURE); } } // namespace content
diff --git a/content/browser/download/mhtml_generation_manager.h b/content/browser/download/mhtml_generation_manager.h index b418e54..24e729a8 100644 --- a/content/browser/download/mhtml_generation_manager.h +++ b/content/browser/download/mhtml_generation_manager.h
@@ -16,7 +16,6 @@ #include "base/memory/singleton.h" #include "base/process/process.h" #include "ipc/ipc_platform_file.h" -#include "url/gurl.h" namespace base { class FilePath; @@ -68,7 +67,7 @@ void OnFileAvailable(int job_id, base::File browser_file); // Called on the UI thread when a job has been finished. - void JobFinished(int job_id, JobStatus job_status); + void JobFinished(Job* job, JobStatus job_status); // Called on the UI thread after the file got finalized and we have its size. void OnFileClosed(int job_id, JobStatus job_status, int64_t file_size);
diff --git a/content/browser/download/save_package.cc b/content/browser/download/save_package.cc index eae1e0d..c3f1c49a 100644 --- a/content/browser/download/save_package.cc +++ b/content/browser/download/save_package.cc
@@ -22,6 +22,7 @@ #include "base/threading/thread.h" #include "build/build_config.h" #include "components/url_formatter/url_formatter.h" +#include "content/browser/bad_message.h" #include "content/browser/download/download_item_impl.h" #include "content/browser/download/download_manager_impl.h" #include "content/browser/download/download_stats.h" @@ -1035,10 +1036,9 @@ int frame_tree_node_id = sender->frame_tree_node()->frame_tree_node_id(); auto it = frame_tree_node_id_to_save_item_.find(frame_tree_node_id); if (it == frame_tree_node_id_to_save_item_.end()) { - // Sanitization of renderer IPC - we will have no save item only if - // the renderer misbehaves and sends OnSerializedHtmlFragment IPC without - // being asked to. - NOTREACHED(); + // This is parimarily sanitization of IPC (renderer shouldn't send + // OnSerializedHtmlFragment IPC without being asked to), but it might also + // occur in the wild (if old renderer response reaches a new SavePackage). return; } SaveItem* save_item = it->second; @@ -1133,10 +1133,15 @@ sender->frame_tree_node()->frame_tree()->FindByRoutingID( sender->GetProcess()->GetID(), subframe.routing_id); - if (!subframe_tree_node || - subframe_tree_node->parent() != sender->frame_tree_node()) { + if (!subframe_tree_node) { + // crbug.com/541354 - Raciness when saving a dynamically changing page. + continue; + } + if (subframe_tree_node->parent() != sender->frame_tree_node()) { // Only reachable if the renderer has a bug or has been compromised. - NOTREACHED(); + ReceivedBadMessage( + sender->GetProcess(), + bad_message::DWNLD_INVALID_SAVABLE_RESOURCE_LINKS_RESPONSE); continue; }
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc index 1834494..e693c96e 100644 --- a/content/browser/frame_host/render_frame_host_impl.cc +++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -318,6 +318,10 @@ return parent_node->current_frame_host(); } +int RenderFrameHostImpl::GetFrameTreeNodeId() { + return frame_tree_node_->frame_tree_node_id(); +} + const std::string& RenderFrameHostImpl::GetFrameName() { return frame_tree_node_->frame_name(); }
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h index 07f78db..b457a07 100644 --- a/content/browser/frame_host/render_frame_host_impl.h +++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -140,6 +140,7 @@ SiteInstanceImpl* GetSiteInstance() override; RenderProcessHost* GetProcess() override; RenderFrameHost* GetParent() override; + int GetFrameTreeNodeId() override; const std::string& GetFrameName() override; bool IsCrossProcessSubframe() override; GURL GetLastCommittedURL() override;
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 d633aca..1397568 100644 --- a/content/browser/frame_host/render_frame_host_manager_unittest.cc +++ b/content/browser/frame_host/render_frame_host_manager_unittest.cc
@@ -609,9 +609,9 @@ // Send an update favicon message and make sure it works. { PluginFaviconMessageObserver observer(contents()); - EXPECT_TRUE(ntp_rfh->GetRenderViewHost()->OnMessageReceived( - ViewHostMsg_UpdateFaviconURL( - ntp_rfh->GetRenderViewHost()->GetRoutingID(), icons))); + EXPECT_TRUE(ntp_rfh->GetRenderViewHost()->GetWidget()->OnMessageReceived( + ViewHostMsg_UpdateFaviconURL( + ntp_rfh->GetRenderViewHost()->GetRoutingID(), icons))); EXPECT_TRUE(observer.favicon_received()); } // Create one more frame in the same SiteInstance where ntp_rfh @@ -628,10 +628,9 @@ // The new RVH should be able to update its favicon. { PluginFaviconMessageObserver observer(contents()); - EXPECT_TRUE( - dest_rfh->GetRenderViewHost()->OnMessageReceived( - ViewHostMsg_UpdateFaviconURL( - dest_rfh->GetRenderViewHost()->GetRoutingID(), icons))); + EXPECT_TRUE(dest_rfh->GetRenderViewHost()->GetWidget()->OnMessageReceived( + ViewHostMsg_UpdateFaviconURL( + dest_rfh->GetRenderViewHost()->GetRoutingID(), icons))); EXPECT_TRUE(observer.favicon_received()); } @@ -640,9 +639,8 @@ { PluginFaviconMessageObserver observer(contents()); EXPECT_TRUE( - ntp_rvh->OnMessageReceived( - ViewHostMsg_UpdateFaviconURL( - dest_rfh->GetRenderViewHost()->GetRoutingID(), icons))); + ntp_rvh->GetWidget()->OnMessageReceived(ViewHostMsg_UpdateFaviconURL( + dest_rfh->GetRenderViewHost()->GetRoutingID(), icons))); EXPECT_FALSE(observer.favicon_received()); } @@ -707,9 +705,9 @@ // Send an update favicon message and make sure it works. { PluginFaviconMessageObserver observer(contents()); - EXPECT_TRUE(rfh1->GetRenderViewHost()->OnMessageReceived( - ViewHostMsg_UpdateFaviconURL( - rfh1->GetRenderViewHost()->GetRoutingID(), icons))); + EXPECT_TRUE(rfh1->GetRenderViewHost()->GetWidget()->OnMessageReceived( + ViewHostMsg_UpdateFaviconURL(rfh1->GetRenderViewHost()->GetRoutingID(), + icons))); EXPECT_TRUE(observer.favicon_received()); } @@ -731,7 +729,7 @@ // The new RVH should be able to update its favicons. { PluginFaviconMessageObserver observer(contents()); - EXPECT_TRUE(rfh2->GetRenderViewHost()->OnMessageReceived( + EXPECT_TRUE(rfh2->GetRenderViewHost()->GetWidget()->OnMessageReceived( ViewHostMsg_UpdateFaviconURL(rfh2->GetRenderViewHost()->GetRoutingID(), icons))); EXPECT_TRUE(observer.favicon_received()); @@ -741,7 +739,7 @@ // be ignored. { PluginFaviconMessageObserver observer(contents()); - EXPECT_TRUE(rfh1->GetRenderViewHost()->OnMessageReceived( + EXPECT_TRUE(rfh1->GetRenderViewHost()->GetWidget()->OnMessageReceived( ViewHostMsg_UpdateFaviconURL(rfh1->GetRenderViewHost()->GetRoutingID(), icons))); EXPECT_FALSE(observer.favicon_received()); @@ -818,7 +816,8 @@ ViewHostMsg_SwapCompositorFrame msg( rvh()->GetRoutingID(), 0, frame, std::vector<IPC::Message>()); - EXPECT_TRUE(swapped_out_rfh->render_view_host()->OnMessageReceived(msg)); + EXPECT_TRUE( + swapped_out_rfh->render_view_host()->GetWidget()->OnMessageReceived(msg)); EXPECT_TRUE(swapped_out_rwhv->did_swap_compositor_frame()); }
diff --git a/content/browser/gpu/gpu_process_host.cc b/content/browser/gpu/gpu_process_host.cc index 05e8005..913d7e1 100644 --- a/content/browser/gpu/gpu_process_host.cc +++ b/content/browser/gpu/gpu_process_host.cc
@@ -72,11 +72,6 @@ #include "ui/gfx/x/x11_switches.h" #endif -#if defined(OS_MACOSX) && !defined(OS_IOS) -#include "content/browser/browser_io_surface_manager_mac.h" -#include "content/common/child_process_messages.h" -#endif - #if defined(OS_MACOSX) #include "content/browser/renderer_host/render_widget_resize_helper_mac.h" #endif @@ -451,13 +446,6 @@ queued_messages_.pop(); } -#if defined(OS_MACOSX) && !defined(OS_IOS) - if (!io_surface_manager_token_.IsZero()) { - BrowserIOSurfaceManager::GetInstance()->InvalidateGpuProcessToken(); - io_surface_manager_token_.SetZero(); - } -#endif - // This is only called on the IO thread so no race against the constructor // for another GpuProcessHost. if (g_gpu_process_hosts[kind_] == this) @@ -568,14 +556,6 @@ if (!Send(new GpuMsg_Initialize())) return false; -#if defined(OS_MACOSX) && !defined(OS_IOS) - io_surface_manager_token_ = - BrowserIOSurfaceManager::GetInstance()->GenerateGpuProcessToken(); - // Note: A valid IOSurface manager token needs to be sent to the Gpu process - // before any GpuMemoryBuffer allocation requests can be sent. - Send(new ChildProcessMsg_SetIOSurfaceManagerToken(io_surface_manager_token_)); -#endif - return true; } @@ -937,13 +917,6 @@ if (g_gpu_process_hosts[kind_] == this) g_gpu_process_hosts[kind_] = NULL; -#if defined(OS_MACOSX) && !defined(OS_IOS) - if (!io_surface_manager_token_.IsZero()) { - BrowserIOSurfaceManager::GetInstance()->InvalidateGpuProcessToken(); - io_surface_manager_token_.SetZero(); - } -#endif - process_->ForceShutdown(); }
diff --git a/content/browser/gpu/gpu_process_host.h b/content/browser/gpu/gpu_process_host.h index 74d9927..60001e63 100644 --- a/content/browser/gpu/gpu_process_host.h +++ b/content/browser/gpu/gpu_process_host.h
@@ -34,10 +34,6 @@ #include "ui/gfx/native_widget_types.h" #include "url/gurl.h" -#if defined(OS_MACOSX) && !defined(OS_IOS) -#include "content/common/mac/io_surface_manager_token.h" -#endif - struct GPUCreateCommandBufferConfig; namespace IPC { @@ -295,12 +291,6 @@ std::string shader_prefix_key_; -#if defined(OS_MACOSX) && !defined(OS_IOS) - // Unique unguessable token that the GPU process is using to register - // IOSurfaces. - IOSurfaceManagerToken io_surface_manager_token_; -#endif - // Browser-side Mojo endpoint which sets up a Mojo channel with the child // process and contains the browser's ServiceRegistry. scoped_ptr<MojoApplicationHost> mojo_application_host_;
diff --git a/content/browser/gpu/gpu_process_host_ui_shim.cc b/content/browser/gpu/gpu_process_host_ui_shim.cc index 4b84d6d..083c99d 100644 --- a/content/browser/gpu/gpu_process_host_ui_shim.cc +++ b/content/browser/gpu/gpu_process_host_ui_shim.cc
@@ -26,7 +26,6 @@ #include "content/public/browser/browser_thread.h" #if defined(OS_MACOSX) -#include "content/browser/browser_io_surface_manager_mac.h" #include "ui/accelerated_widget_mac/accelerated_widget_mac.h" #endif @@ -246,24 +245,12 @@ content::GpuSurfaceTracker::Get()->AcquireNativeWidget( params.surface_id); base::ScopedCFTypeRef<IOSurfaceRef> io_surface; - CAContextID ca_context_id = 0; + CAContextID ca_context_id = params.ca_context_id; - switch (ui::GetSurfaceHandleType(params.surface_handle)) { - case ui::kSurfaceHandleTypeIOSurface: { - IOSurfaceID io_surface_id = - ui::IOSurfaceIDFromSurfaceHandle(params.surface_handle); - io_surface.reset( - BrowserIOSurfaceManager::GetInstance()->AcquireIOSurface( - gfx::GenericSharedMemoryId(io_surface_id))); - break; - } - case ui::kSurfaceHandleTypeCAContext: { - ca_context_id = ui::CAContextIDFromSurfaceHandle(params.surface_handle); - break; - } - default: - DLOG(ERROR) << "Unrecognized accelerated frame type."; - return; + DCHECK((params.ca_context_id == 0) ^ + (params.io_surface.get() == MACH_PORT_NULL)); + if (params.io_surface.get()) { + io_surface.reset(IOSurfaceLookupFromMachPort(params.io_surface)); } ui::AcceleratedWidgetMacGotFrame(native_widget, ca_context_id, io_surface,
diff --git a/content/browser/in_process_io_surface_manager_mac.cc b/content/browser/in_process_io_surface_manager_mac.cc deleted file mode 100644 index 70f18a74..0000000 --- a/content/browser/in_process_io_surface_manager_mac.cc +++ /dev/null
@@ -1,54 +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 "content/browser/in_process_io_surface_manager_mac.h" - -#include "base/logging.h" - -namespace content { - -// static -InProcessIOSurfaceManager* InProcessIOSurfaceManager::GetInstance() { - return base::Singleton< - InProcessIOSurfaceManager, - base::LeakySingletonTraits<InProcessIOSurfaceManager>>::get(); -} - -bool InProcessIOSurfaceManager::RegisterIOSurface( - gfx::IOSurfaceId io_surface_id, - int client_id, - IOSurfaceRef io_surface) { - base::AutoLock lock(lock_); - - DCHECK(io_surfaces_.find(io_surface_id) == io_surfaces_.end()); - io_surfaces_.add(io_surface_id, - make_scoped_ptr(new base::mac::ScopedMachSendRight( - IOSurfaceCreateMachPort(io_surface)))); - return true; -} - -void InProcessIOSurfaceManager::UnregisterIOSurface( - gfx::IOSurfaceId io_surface_id, - int client_id) { - base::AutoLock lock(lock_); - - DCHECK(io_surfaces_.find(io_surface_id) != io_surfaces_.end()); - io_surfaces_.erase(io_surface_id); -} - -IOSurfaceRef InProcessIOSurfaceManager::AcquireIOSurface( - gfx::IOSurfaceId io_surface_id) { - base::AutoLock lock(lock_); - - DCHECK(io_surfaces_.find(io_surface_id) != io_surfaces_.end()); - return IOSurfaceLookupFromMachPort(io_surfaces_.get(io_surface_id)->get()); -} - -InProcessIOSurfaceManager::InProcessIOSurfaceManager() { -} - -InProcessIOSurfaceManager::~InProcessIOSurfaceManager() { -} - -} // namespace content
diff --git a/content/browser/in_process_io_surface_manager_mac.h b/content/browser/in_process_io_surface_manager_mac.h deleted file mode 100644 index 6016e65..0000000 --- a/content/browser/in_process_io_surface_manager_mac.h +++ /dev/null
@@ -1,48 +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 CONTENT_BROWSER_IN_PROCESS_IO_SURFACE_MANAGER_MAC_H_ -#define CONTENT_BROWSER_IN_PROCESS_IO_SURFACE_MANAGER_MAC_H_ - -#include "base/containers/scoped_ptr_hash_map.h" -#include "base/mac/scoped_mach_port.h" -#include "base/macros.h" -#include "base/memory/scoped_ptr.h" -#include "base/memory/singleton.h" -#include "base/synchronization/lock.h" -#include "content/common/content_export.h" -#include "ui/gfx/mac/io_surface_manager.h" - -namespace content { - -class CONTENT_EXPORT InProcessIOSurfaceManager : public gfx::IOSurfaceManager { - public: - static InProcessIOSurfaceManager* GetInstance(); - - // Overridden from IOSurfaceManager: - bool RegisterIOSurface(gfx::IOSurfaceId io_surface_id, - int client_id, - IOSurfaceRef io_surface) override; - void UnregisterIOSurface(gfx::IOSurfaceId io_surface_id, - int client_id) override; - IOSurfaceRef AcquireIOSurface(gfx::IOSurfaceId io_surface_id) override; - - private: - friend struct base::DefaultSingletonTraits<InProcessIOSurfaceManager>; - - InProcessIOSurfaceManager(); - ~InProcessIOSurfaceManager() override; - - using IOSurfaceMap = - base::ScopedPtrHashMap<gfx::IOSurfaceId, - scoped_ptr<base::mac::ScopedMachSendRight>>; - IOSurfaceMap io_surfaces_; - base::Lock lock_; - - DISALLOW_COPY_AND_ASSIGN(InProcessIOSurfaceManager); -}; - -} // namespace content - -#endif // CONTENT_BROWSER_IN_PROCESS_IO_SURFACE_MANAGER_MAC_H_
diff --git a/content/browser/loader/resource_dispatcher_host_impl.cc b/content/browser/loader/resource_dispatcher_host_impl.cc index 67eaf08a..92f06c3 100644 --- a/content/browser/loader/resource_dispatcher_host_impl.cc +++ b/content/browser/loader/resource_dispatcher_host_impl.cc
@@ -1182,8 +1182,7 @@ // ResourceRequestInfo rather than caching it locally. This lets us update // the info object when a transfer occurs. info->UpdateForTransfer(child_id, route_id, request_data.origin_pid, - request_id, request_data.parent_render_frame_id, - filter_->GetWeakPtr()); + request_id, filter_->GetWeakPtr()); // Update maps that used the old IDs, if necessary. Some transfers in tests // do not actually use a different ID, so not all maps need to be updated. @@ -1414,7 +1413,6 @@ request_data.render_frame_id, request_data.is_main_frame, request_data.parent_is_main_frame, - request_data.parent_render_frame_id, request_data.resource_type, request_data.transition_type, request_data.should_replace_current_entry, @@ -1712,7 +1710,6 @@ render_frame_route_id, false, // is_main_frame false, // parent_is_main_frame - -1, // parent_render_frame_id RESOURCE_TYPE_SUB_RESOURCE, ui::PAGE_TRANSITION_LINK, false, // should_replace_current_entry @@ -2152,7 +2149,6 @@ request_id_, -1, // request_data.render_frame_id, info.is_main_frame, info.parent_is_main_frame, - -1, // request_data.parent_render_frame_id, resource_type, info.common_params.transition, // should_replace_current_entry. This was only maintained at layer for // request transfers and isn't needed for browser-side navigations.
diff --git a/content/browser/loader/resource_dispatcher_host_unittest.cc b/content/browser/loader/resource_dispatcher_host_unittest.cc index f5a97aa..7fbe399 100644 --- a/content/browser/loader/resource_dispatcher_host_unittest.cc +++ b/content/browser/loader/resource_dispatcher_host_unittest.cc
@@ -153,7 +153,6 @@ request.should_reset_appcache = false; request.is_main_frame = true; request.parent_is_main_frame = false; - request.parent_render_frame_id = -1; request.transition_type = ui::PAGE_TRANSITION_LINK; request.allow_download = true; return request;
diff --git a/content/browser/loader/resource_request_info_impl.cc b/content/browser/loader/resource_request_info_impl.cc index a269baf..0f61829 100644 --- a/content/browser/loader/resource_request_info_impl.cc +++ b/content/browser/loader/resource_request_info_impl.cc
@@ -71,7 +71,6 @@ render_frame_id, // render_frame_id is_main_frame, // is_main_frame parent_is_main_frame, // parent_is_main_frame - 0, // parent_render_frame_id resource_type, // resource_type ui::PAGE_TRANSITION_LINK, // transition_type false, // should_replace_current_entry @@ -132,7 +131,6 @@ int render_frame_id, bool is_main_frame, bool parent_is_main_frame, - int parent_render_frame_id, ResourceType resource_type, ui::PageTransition transition_type, bool should_replace_current_entry, @@ -162,7 +160,6 @@ render_frame_id_(render_frame_id), is_main_frame_(is_main_frame), parent_is_main_frame_(parent_is_main_frame), - parent_render_frame_id_(parent_render_frame_id), should_replace_current_entry_(should_replace_current_entry), is_download_(is_download), is_stream_(is_stream), @@ -240,10 +237,6 @@ return parent_is_main_frame_; } -int ResourceRequestInfoImpl::GetParentRenderFrameID() const { - return parent_render_frame_id_; -} - ResourceType ResourceRequestInfoImpl::GetResourceType() const { return resource_type_; } @@ -330,13 +323,11 @@ int route_id, int origin_pid, int request_id, - int parent_render_frame_id, base::WeakPtr<ResourceMessageFilter> filter) { child_id_ = child_id; route_id_ = route_id; origin_pid_ = origin_pid; request_id_ = request_id; - parent_render_frame_id_ = parent_render_frame_id; filter_ = filter; }
diff --git a/content/browser/loader/resource_request_info_impl.h b/content/browser/loader/resource_request_info_impl.h index bb6c948..3fbce96b 100644 --- a/content/browser/loader/resource_request_info_impl.h +++ b/content/browser/loader/resource_request_info_impl.h
@@ -49,7 +49,6 @@ int render_frame_id, bool is_main_frame, bool parent_is_main_frame, - int parent_render_frame_id, ResourceType resource_type, ui::PageTransition transition_type, bool should_replace_current_entry, @@ -79,7 +78,6 @@ int GetRenderFrameID() const override; bool IsMainFrame() const override; bool ParentIsMainFrame() const override; - int GetParentRenderFrameID() const override; ResourceType GetResourceType() const override; int GetProcessType() const override; blink::WebReferrerPolicy GetReferrerPolicy() const override; @@ -118,7 +116,6 @@ int route_id, int origin_pid, int request_id, - int parent_render_frame_id, base::WeakPtr<ResourceMessageFilter> filter); // CrossSiteResourceHandler for this request. May be null. @@ -204,7 +201,6 @@ int render_frame_id_; bool is_main_frame_; bool parent_is_main_frame_; - int parent_render_frame_id_; bool should_replace_current_entry_; bool is_download_; bool is_stream_;
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 3e3ff06..6d092577f 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
@@ -172,8 +172,8 @@ // CaptureTestSourceController. class CaptureTestView : public TestRenderWidgetHostView { public: - explicit CaptureTestView(RenderWidgetHostImpl* rwh, - CaptureTestSourceController* controller) + CaptureTestView(RenderWidgetHostImpl* rwh, + CaptureTestSourceController* controller) : TestRenderWidgetHostView(rwh), controller_(controller), fake_bounds_(100, 100, 100 + kTestWidth, 100 + kTestHeight) {} @@ -240,40 +240,19 @@ DISALLOW_IMPLICIT_CONSTRUCTORS(CaptureTestView); }; -#if defined(COMPILER_MSVC) -// MSVC warns on diamond inheritance. See comment for same warning on -// RenderViewHostImpl. -#pragma warning(push) -#pragma warning(disable: 4250) -#endif - // A stub implementation which returns solid-color bitmaps in calls to // CopyFromBackingStore(). The behavior is controlled by a // CaptureTestSourceController. -class CaptureTestRenderViewHost : public TestRenderViewHost { +class CaptureTestRenderWidgetHost : public RenderWidgetHostImpl { public: - CaptureTestRenderViewHost(SiteInstance* instance, - RenderViewHostDelegate* delegate, - RenderWidgetHostDelegate* widget_delegate, - int32_t routing_id, - int32_t main_frame_routing_id, - bool swapped_out, - CaptureTestSourceController* controller) - : TestRenderViewHost(instance, - delegate, - widget_delegate, - routing_id, - main_frame_routing_id, - swapped_out), - controller_(controller) { - // Override the default view installed by TestRenderViewHost; we need - // our special subclass which has mocked-out tab capture support. - RenderWidgetHostView* old_view = GetWidget()->GetView(); - GetWidget()->SetView(new CaptureTestView(GetWidget(), controller)); - delete old_view; - } + CaptureTestRenderWidgetHost(RenderWidgetHostDelegate* delegate, + RenderProcessHost* process, + int32_t routing_id, + CaptureTestSourceController* controller) + : RenderWidgetHostImpl(delegate, process, routing_id, false /* hidden */), + controller_(controller) {} - // TestRenderViewHost overrides. + // RenderWidgetHostImpl overrides. void CopyFromBackingStore(const gfx::Rect& src_rect, const gfx::Size& accelerated_dst_size, const ReadbackRequestCallback& callback, @@ -294,13 +273,40 @@ private: CaptureTestSourceController* controller_; - DISALLOW_IMPLICIT_CONSTRUCTORS(CaptureTestRenderViewHost); + DISALLOW_IMPLICIT_CONSTRUCTORS(CaptureTestRenderWidgetHost); }; -#if defined(COMPILER_MSVC) -// Re-enable warning 4250 -#pragma warning(pop) -#endif +class CaptureTestRenderViewHost : public TestRenderViewHost { + public: + CaptureTestRenderViewHost(SiteInstance* instance, + RenderViewHostDelegate* delegate, + RenderWidgetHostDelegate* widget_delegate, + int32_t routing_id, + int32_t main_frame_routing_id, + bool swapped_out, + CaptureTestSourceController* controller) + : TestRenderViewHost(instance, + make_scoped_ptr(new CaptureTestRenderWidgetHost( + widget_delegate, + instance->GetProcess(), + routing_id, + controller)), + delegate, + main_frame_routing_id, + swapped_out), + controller_(controller) { + // Override the default view installed by TestRenderViewHost; we need + // our special subclass which has mocked-out tab capture support. + RenderWidgetHostView* old_view = GetWidget()->GetView(); + GetWidget()->SetView(new CaptureTestView(GetWidget(), controller)); + delete old_view; + } + + private: + CaptureTestSourceController* controller_; + + DISALLOW_IMPLICIT_CONSTRUCTORS(CaptureTestRenderViewHost); +}; class CaptureTestRenderViewHostFactory : public RenderViewHostFactory { public:
diff --git a/content/browser/media/media_canplaytype_browsertest.cc b/content/browser/media/media_canplaytype_browsertest.cc index 0c41e31..58c4b6dc 100644 --- a/content/browser/media/media_canplaytype_browsertest.cc +++ b/content/browser/media/media_canplaytype_browsertest.cc
@@ -10,6 +10,7 @@ #include "content/public/test/browser_test_utils.h" #include "content/public/test/content_browser_test_utils.h" #include "content/shell/browser/shell.h" +#include "media/media_features.h" #if defined(OS_ANDROID) #include "base/android/build_info.h" @@ -47,7 +48,7 @@ const char* kHevcSupported = kNot; #endif -#if defined(ENABLE_MPEG2TS_STREAM_PARSER) +#if BUILDFLAG(ENABLE_MSE_MPEG2TS_STREAM_PARSER) const char* kMp2tsMaybe = kPropMaybe; const char* kMp2tsProbably = kPropProbably; #else
diff --git a/content/browser/media/media_source_browsertest.cc b/content/browser/media/media_source_browsertest.cc index 39ea59a..90d11ba5 100644 --- a/content/browser/media/media_source_browsertest.cc +++ b/content/browser/media/media_source_browsertest.cc
@@ -6,6 +6,7 @@ #include "build/build_config.h" #include "content/browser/media/media_browsertest.h" #include "content/public/common/content_switches.h" +#include "media/media_features.h" #if defined(OS_ANDROID) #include "base/android/build_info.h" #endif @@ -21,9 +22,11 @@ const char kWebMVideoOnly[] = "video/webm; codecs=\"vp8\""; const char kWebMAudioVideo[] = "video/webm; codecs=\"vorbis, vp8\""; -#if defined(USE_PROPRIETARY_CODECS) && defined(ENABLE_MPEG2TS_STREAM_PARSER) +#if defined(USE_PROPRIETARY_CODECS) +#if BUILDFLAG(ENABLE_MSE_MPEG2TS_STREAM_PARSER) const char kMp2tAudioVideo[] = "video/mp2t; codecs=\"mp4a.40.2, avc1.42E01E\""; #endif +#endif namespace content { @@ -127,9 +130,11 @@ } #endif -#if defined(USE_PROPRIETARY_CODECS) && defined(ENABLE_MPEG2TS_STREAM_PARSER) +#if defined(USE_PROPRIETARY_CODECS) +#if BUILDFLAG(ENABLE_MSE_MPEG2TS_STREAM_PARSER) IN_PROC_BROWSER_TEST_F(MediaSourceTest, Playback_AudioVideo_Mp2t) { TestSimplePlayback("bear-1280x720.ts", kMp2tAudioVideo, kEnded); } #endif +#endif } // namespace content
diff --git a/content/browser/media/webrtc_media_recorder_browsertest.cc b/content/browser/media/webrtc_media_recorder_browsertest.cc index 3765a884..6774312 100644 --- a/content/browser/media/webrtc_media_recorder_browsertest.cc +++ b/content/browser/media/webrtc_media_recorder_browsertest.cc
@@ -103,8 +103,12 @@ IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcMediaRecorderTest, MediaRecorderIllegalPauseThrowsDOMError) { - MakeTypicalCall("testIllegalPauseThrowsDOMError();", - kMediaRecorderHtmlFile); + MakeTypicalCall("testIllegalPauseThrowsDOMError();", kMediaRecorderHtmlFile); +} + +IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcMediaRecorderTest, + MediaRecorderTwoChannelAudioRecording) { + MakeTypicalCall("testTwoChannelAudio();", kMediaRecorderHtmlFile); } IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcMediaRecorderTest,
diff --git a/content/browser/mojo/mojo_shell_client_host.cc b/content/browser/mojo/mojo_shell_client_host.cc index 6725e6fe..b11b6363 100644 --- a/content/browser/mojo/mojo_shell_client_host.cc +++ b/content/browser/mojo/mojo_shell_client_host.cc
@@ -14,6 +14,7 @@ #include "content/common/mojo/mojo_messages.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/render_process_host.h" +#include "content/public/browser/render_process_host_observer.h" #include "content/public/common/mojo_shell_connection.h" #include "ipc/ipc_sender.h" #include "mojo/application/public/cpp/application_impl.h" @@ -89,6 +90,34 @@ mojo::ScopedHandle(mojo::Handle(client_pipe))); } +class PIDSender : public RenderProcessHostObserver { + public: + PIDSender( + RenderProcessHost* host, + mojo::shell::mojom::PIDReceiverPtr pid_receiver) + : host_(host), + pid_receiver_(std::move(pid_receiver)) { + pid_receiver_.set_connection_error_handler([this]() { delete this; }); + DCHECK(!host_->IsReady()); + host_->AddObserver(this); + } + ~PIDSender() override { + host_->RemoveObserver(this); + } + + private: + // Overridden from RenderProcessHostObserver: + void RenderProcessReady(RenderProcessHost* host) override { + pid_receiver_->SetPID(base::GetProcId(host->GetHandle())); + delete this; + } + + RenderProcessHost* host_; + mojo::shell::mojom::PIDReceiverPtr pid_receiver_; + + DISALLOW_COPY_AND_ASSIGN(PIDSender); +}; + } // namespace void RegisterChildWithExternalShell(int child_process_id, @@ -120,10 +149,16 @@ std::string url = base::StringPrintf("exe:chrome_renderer%d", child_process_id); + mojo::shell::mojom::PIDReceiverPtr pid_receiver; + mojo::InterfaceRequest<mojo::shell::mojom::PIDReceiver> request = + GetProxy(&pid_receiver); + new PIDSender(render_process_host, std::move(pid_receiver)); + application_manager->CreateInstanceForHandle( mojo::ScopedHandle(mojo::Handle(handle.release().value())), url, - CreateCapabilityFilterForRenderer()); + CreateCapabilityFilterForRenderer(), + std::move(request)); // Send the other end to the child via Chrome IPC. base::PlatformFile client_file = PlatformFileFromScopedPlatformHandle(
diff --git a/content/browser/renderer_host/compositor_impl_android.cc b/content/browser/renderer_host/compositor_impl_android.cc index 26d265c..74f1e70 100644 --- a/content/browser/renderer_host/compositor_impl_android.cc +++ b/content/browser/renderer_host/compositor_impl_android.cc
@@ -71,7 +71,6 @@ namespace { -const unsigned int kMaxUiSwapBuffers = 1U; const unsigned int kMaxDisplaySwapBuffers = 1U; // Used to override capabilities_.adjust_deadline_for_parent to false @@ -144,8 +143,7 @@ OutputSurface::OnSwapBuffersComplete(); } - void OnUpdateVSyncParameters(base::TimeTicks timebase, - base::TimeDelta interval) override { + void OnVSync(base::TimeTicks timebase, base::TimeDelta interval) override { CommitVSyncParameters(timebase, interval); } @@ -157,6 +155,36 @@ scoped_ptr<cc::OverlayCandidateValidator> overlay_candidate_validator_; }; +class ExternalBeginFrameSource : public cc::BeginFrameSourceBase, + public CompositorImpl::VSyncObserver { + public: + ExternalBeginFrameSource(CompositorImpl* compositor) + : compositor_(compositor) { + compositor_->AddObserver(this); + } + + ~ExternalBeginFrameSource() override { + compositor_->RemoveObserver(this); + } + + // cc::BeginFrameSourceBase implementation: + void OnNeedsBeginFramesChange( + bool needs_begin_frames) override { + compositor_->OnNeedsBeginFramesChange(needs_begin_frames); + } + + // CompositorImpl::VSyncObserver implementation: + void OnVSync(base::TimeTicks frame_time, + base::TimeDelta vsync_period) override { + CallOnBeginFrame(cc::BeginFrameArgs::Create( + BEGINFRAME_FROM_HERE, frame_time, base::TimeTicks::Now(), vsync_period, + cc::BeginFrameArgs::NORMAL)); + } + + private: + CompositorImpl* compositor_; +}; + static bool g_initialized = false; bool g_use_surface_manager = false; @@ -239,15 +267,11 @@ surface_id_(0), client_(client), root_window_(root_window), - did_post_swapbuffers_(false), - ignore_schedule_composite_(false), - needs_composite_(false), needs_animate_(false), - will_composite_immediately_(false), - composite_on_vsync_trigger_(DO_NOT_COMPOSITE), pending_swapbuffers_(0U), num_successive_context_creation_failures_(0), output_surface_request_pending_(false), + needs_begin_frames_(false), weak_factory_(this) { DCHECK(client); DCHECK(root_window); @@ -262,111 +286,6 @@ SetSurface(NULL); } -void CompositorImpl::PostComposite(CompositingTrigger trigger) { - DCHECK(host_->visible()); - DCHECK(needs_composite_); - DCHECK(trigger == COMPOSITE_IMMEDIATELY || trigger == COMPOSITE_EVENTUALLY); - - if (will_composite_immediately_ || - (trigger == COMPOSITE_EVENTUALLY && WillComposite())) { - // We will already composite soon enough. - DCHECK(WillComposite()); - return; - } - - if (DidCompositeThisFrame()) { - DCHECK(!WillCompositeThisFrame()); - if (composite_on_vsync_trigger_ != COMPOSITE_IMMEDIATELY) { - composite_on_vsync_trigger_ = trigger; - root_window_->RequestVSyncUpdate(); - } - DCHECK(WillComposite()); - return; - } - - base::TimeDelta delay; - if (trigger == COMPOSITE_IMMEDIATELY) { - will_composite_immediately_ = true; - composite_on_vsync_trigger_ = DO_NOT_COMPOSITE; - } else { - DCHECK(!WillComposite()); - const base::TimeDelta estimated_composite_time = vsync_period_ / 4; - const base::TimeTicks now = base::TimeTicks::Now(); - - if (!last_vsync_.is_null() && (now - last_vsync_) < vsync_period_) { - base::TimeTicks next_composite = - last_vsync_ + vsync_period_ - estimated_composite_time; - if (next_composite < now) { - // It's too late, we will reschedule composite as needed on the next - // vsync. - composite_on_vsync_trigger_ = COMPOSITE_EVENTUALLY; - root_window_->RequestVSyncUpdate(); - DCHECK(WillComposite()); - return; - } - - delay = next_composite - now; - } - } - TRACE_EVENT2("cc,benchmark", "CompositorImpl::PostComposite", - "trigger", trigger, - "delay", delay.InMillisecondsF()); - - DCHECK(composite_on_vsync_trigger_ == DO_NOT_COMPOSITE); - if (current_composite_task_) - current_composite_task_->Cancel(); - - // Unretained because we cancel the task on shutdown. - current_composite_task_.reset(new base::CancelableClosure( - base::Bind(&CompositorImpl::Composite, base::Unretained(this), trigger))); - base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( - FROM_HERE, current_composite_task_->callback(), delay); -} - -void CompositorImpl::Composite(CompositingTrigger trigger) { - if (trigger == COMPOSITE_IMMEDIATELY) - will_composite_immediately_ = false; - - DCHECK(host_->visible()); - DCHECK(trigger == COMPOSITE_IMMEDIATELY || trigger == COMPOSITE_EVENTUALLY); - DCHECK(needs_composite_); - DCHECK(!DidCompositeThisFrame()); - - DCHECK_LE(pending_swapbuffers_, kMaxUiSwapBuffers); - // Swap Ack accounting is unreliable if the OutputSurface was lost. - // In that case still attempt to composite, which will cause creation of a - // new OutputSurface and reset pending_swapbuffers_. - if (pending_swapbuffers_ == kMaxUiSwapBuffers && - !host_->output_surface_lost()) { - TRACE_EVENT0("compositor", "CompositorImpl_SwapLimit"); - return; - } - - // Reset state before Layout+Composite since that might create more - // requests to Composite that we need to respect. - needs_composite_ = false; - - // Only allow compositing once per vsync. - current_composite_task_->Cancel(); - DCHECK(DidCompositeThisFrame() && !WillComposite()); - - const base::TimeTicks frame_time = base::TimeTicks::Now(); - if (needs_animate_) { - base::AutoReset<bool> auto_reset_ignore_schedule( - &ignore_schedule_composite_, true); - needs_animate_ = false; - root_window_->Animate(frame_time); - } - - did_post_swapbuffers_ = false; - host_->Composite(frame_time); - if (did_post_swapbuffers_) - pending_swapbuffers_++; - - // Need to track vsync to avoid compositing more than once per frame. - root_window_->RequestVSyncUpdate(); -} - ui::UIResourceProvider& CompositorImpl::GetUIResourceProvider() { return *this; } @@ -427,27 +346,20 @@ void CompositorImpl::CreateLayerTreeHost() { DCHECK(!host_); - DCHECK(!WillCompositeThisFrame()); - - // Just in case, since we immediately hide the LTH in this function, - // and we do not want to end up with a pending Composite task when the - // host is hidden. - base::AutoReset<bool> auto_reset_ignore_schedule(&ignore_schedule_composite_, - true); cc::LayerTreeSettings settings; settings.renderer_settings.refresh_rate = 60.0; settings.renderer_settings.allow_antialiasing = false; settings.renderer_settings.highp_threshold_min = 2048; settings.use_zero_copy = true; + settings.use_external_begin_frame_source = true; base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); settings.initial_debug_state.SetRecordRenderingStats( command_line->HasSwitch(cc::switches::kEnableGpuBenchmarking)); if (command_line->HasSwitch(cc::switches::kDisableCompositorPropertyTrees)) settings.use_property_trees = false; - // TODO(enne): Update this this compositor to use the scheduler. - settings.single_thread_proxy_scheduler = false; + settings.single_thread_proxy_scheduler = true; settings.use_compositor_animation_timelines = !command_line->HasSwitch( switches::kDisableAndroidCompositorAnimationTimelines); @@ -459,6 +371,7 @@ params.task_graph_runner = g_task_graph_runner.Pointer(); params.main_task_runner = base::ThreadTaskRunnerHandle::Get(); params.settings = &settings; + params.external_begin_frame_source.reset(new ExternalBeginFrameSource(this)); host_ = cc::LayerTreeHost::CreateSingleThreaded(this, ¶ms); DCHECK(!host_->visible()); host_->SetRootLayer(root_layer_); @@ -476,39 +389,16 @@ TRACE_EVENT1("cc", "CompositorImpl::SetVisible", "visible", visible); if (!visible) { DCHECK(host_->visible()); - // Look for any layers that were attached to the root for readback - // and are waiting for Composite() to happen. - bool readback_pending = false; - for (size_t i = 0; i < root_layer_->children().size(); ++i) { - if (root_layer_->children()[i]->HasCopyRequest()) { - readback_pending = true; - break; - } - } - if (readback_pending) { - base::AutoReset<bool> auto_reset_ignore_schedule( - &ignore_schedule_composite_, true); - host_->Composite(base::TimeTicks::Now()); - } - if (WillComposite()) - CancelComposite(); host_->SetVisible(false); if (!host_->output_surface_lost()) host_->ReleaseOutputSurface(); pending_swapbuffers_ = 0; - needs_composite_ = false; - composite_on_vsync_trigger_ = DO_NOT_COMPOSITE; establish_gpu_channel_timeout_.Stop(); display_client_.reset(); - if (current_composite_task_) { - current_composite_task_->Cancel(); - current_composite_task_.reset(); - } } else { host_->SetVisible(true); if (output_surface_request_pending_) RequestNewOutputSurface(); - SetNeedsComposite(); } } @@ -539,10 +429,7 @@ void CompositorImpl::SetNeedsComposite() { if (!host_->visible()) return; - DCHECK(!needs_composite_ || WillComposite()); - - needs_composite_ = true; - PostComposite(COMPOSITE_IMMEDIATELY); + host_->SetNeedsAnimate(); } static scoped_ptr<WebGraphicsContext3DCommandBufferImpl> @@ -576,9 +463,11 @@ } void CompositorImpl::UpdateLayerTreeHost() { - base::AutoReset<bool> auto_reset_ignore_schedule(&ignore_schedule_composite_, - true); client_->UpdateLayerTreeHost(); + if (needs_animate_) { + needs_animate_ = false; + root_window_->Animate(base::TimeTicks::Now()); + } } void CompositorImpl::OnGpuChannelEstablished() { @@ -709,44 +598,15 @@ return gpu_capabilities_.texture_format_etc1_npot; } -void CompositorImpl::ScheduleComposite() { - if (ignore_schedule_composite_ || !host_->visible()) - return; - - DCHECK(!needs_composite_ || WillComposite()); - needs_composite_ = true; - // We currently expect layer tree invalidations at most once per frame - // during normal operation and therefore try to composite immediately - // to minimize latency. - PostComposite(COMPOSITE_IMMEDIATELY); -} - -void CompositorImpl::ScheduleAnimation() { - needs_animate_ = true; - - if (!host_->visible()) - return; - - if (needs_composite_) { - DCHECK(WillComposite()); - return; - } - - TRACE_EVENT0("cc", "CompositorImpl::ScheduleAnimation"); - needs_composite_ = true; - PostComposite(COMPOSITE_EVENTUALLY); -} - void CompositorImpl::DidPostSwapBuffers() { TRACE_EVENT0("compositor", "CompositorImpl::DidPostSwapBuffers"); - did_post_swapbuffers_ = true; + pending_swapbuffers_++; } void CompositorImpl::DidCompleteSwapBuffers() { TRACE_EVENT0("compositor", "CompositorImpl::DidCompleteSwapBuffers"); DCHECK_GT(pending_swapbuffers_, 0U); - if (pending_swapbuffers_-- == kMaxUiSwapBuffers && needs_composite_) - PostComposite(COMPOSITE_IMMEDIATELY); + pending_swapbuffers_--; client_->OnSwapBuffersCompleted(pending_swapbuffers_); } @@ -755,7 +615,8 @@ // This really gets called only once from // SingleThreadProxy::DidLoseOutputSurfaceOnImplThread() when the // context was lost. - ScheduleComposite(); + if (host_->visible()) + host_->SetNeedsCommit(); client_->OnSwapBuffersCompleted(0); } @@ -774,28 +635,19 @@ void CompositorImpl::OnVSync(base::TimeTicks frame_time, base::TimeDelta vsync_period) { - vsync_period_ = vsync_period; - last_vsync_ = frame_time; - - if (WillCompositeThisFrame()) { - // We somehow missed the last vsync interval, so reschedule for deadline. - // We cannot schedule immediately, or will get us out-of-phase with new - // renderer frames. - CancelComposite(); - composite_on_vsync_trigger_ = COMPOSITE_EVENTUALLY; - } else { - current_composite_task_.reset(); - } - - DCHECK(!DidCompositeThisFrame() && !WillCompositeThisFrame()); - if (composite_on_vsync_trigger_ != DO_NOT_COMPOSITE) { - CompositingTrigger trigger = composite_on_vsync_trigger_; - composite_on_vsync_trigger_ = DO_NOT_COMPOSITE; - PostComposite(trigger); - } - FOR_EACH_OBSERVER(VSyncObserver, observer_list_, - OnUpdateVSyncParameters(frame_time, vsync_period)); + OnVSync(frame_time, vsync_period)); + if (needs_begin_frames_) + root_window_->RequestVSyncUpdate(); +} + +void CompositorImpl::OnNeedsBeginFramesChange(bool needs_begin_frames) { + if (needs_begin_frames_ == needs_begin_frames) + return; + + needs_begin_frames_ = needs_begin_frames; + if (needs_begin_frames_) + root_window_->RequestVSyncUpdate(); } void CompositorImpl::SetNeedsAnimate() {
diff --git a/content/browser/renderer_host/compositor_impl_android.h b/content/browser/renderer_host/compositor_impl_android.h index 0072979eb..9b1a60eb 100644 --- a/content/browser/renderer_host/compositor_impl_android.h +++ b/content/browser/renderer_host/compositor_impl_android.h
@@ -50,8 +50,8 @@ public: class VSyncObserver { public: - virtual void OnUpdateVSyncParameters(base::TimeTicks timebase, - base::TimeDelta interval) = 0; + virtual void OnVSync(base::TimeTicks timebase, + base::TimeDelta interval) = 0; }; CompositorImpl(CompositorClient* client, gfx::NativeWindow root_window); @@ -66,6 +66,7 @@ void AddObserver(VSyncObserver* observer); void RemoveObserver(VSyncObserver* observer); + void OnNeedsBeginFramesChange(bool needs_begin_frames); // ui::ResourceProvider implementation. cc::UIResourceId CreateUIResource(cc::UIResourceClient* client) override; @@ -108,8 +109,6 @@ override {} // LayerTreeHostSingleThreadClient implementation. - void ScheduleComposite() override; - void ScheduleAnimation() override; void DidPostSwapBuffers() override; void DidAbortSwapBuffers() override; @@ -120,38 +119,8 @@ void OnVSync(base::TimeTicks frame_time, base::TimeDelta vsync_period) override; void SetNeedsAnimate() override; - void SetVisible(bool visible); - - enum CompositingTrigger { - DO_NOT_COMPOSITE, - COMPOSITE_IMMEDIATELY, - COMPOSITE_EVENTUALLY, - }; - void PostComposite(CompositingTrigger trigger); - void Composite(CompositingTrigger trigger); void CreateOutputSurface(); - - bool WillCompositeThisFrame() const { - return current_composite_task_ && - !current_composite_task_->callback().is_null(); - } - bool DidCompositeThisFrame() const { - return current_composite_task_ && - current_composite_task_->callback().is_null(); - } - bool WillComposite() const { - return WillCompositeThisFrame() || - composite_on_vsync_trigger_ != DO_NOT_COMPOSITE; - } - void CancelComposite() { - DCHECK(WillComposite()); - if (WillCompositeThisFrame()) - current_composite_task_->Cancel(); - current_composite_task_.reset(); - composite_on_vsync_trigger_ = DO_NOT_COMPOSITE; - will_composite_immediately_ = false; - } void CreateLayerTreeHost(); void OnGpuChannelEstablished(); @@ -162,6 +131,8 @@ scoped_refptr<cc::Layer> root_layer_; scoped_refptr<cc::Layer> subroot_layer_; + // Destruction order matters here: + base::ObserverList<VSyncObserver, true> observer_list_; scoped_ptr<cc::LayerTreeHost> host_; ui::ResourceManagerImpl resource_manager_; @@ -179,39 +150,15 @@ gfx::NativeWindow root_window_; - // Used locally to track whether a call to LTH::Composite() did result in - // a posted SwapBuffers(). - bool did_post_swapbuffers_; - - // Used locally to inhibit ScheduleComposite() during - // UpdateLayerTreeHost(). - bool ignore_schedule_composite_; - - // Whether we need to composite in general because of any invalidation or - // explicit request. - bool needs_composite_; - // Whether we need to update animations on the next composite. bool needs_animate_; - // Whether we posted a task and are about to composite. - bool will_composite_immediately_; - - // How we should schedule Composite during the next vsync. - CompositingTrigger composite_on_vsync_trigger_; - - // The Composite operation scheduled for the current vsync interval. - scoped_ptr<base::CancelableClosure> current_composite_task_; - // The number of SwapBuffer calls that have not returned and ACK'd from // the GPU thread. unsigned int pending_swapbuffers_; size_t num_successive_context_creation_failures_; - base::TimeDelta vsync_period_; - base::TimeTicks last_vsync_; - base::OneShotTimer establish_gpu_channel_timeout_; // Whether there is an OutputSurface request pending from the current @@ -221,9 +168,7 @@ bool output_surface_request_pending_; gpu::Capabilities gpu_capabilities_; - - base::ObserverList<VSyncObserver, true> observer_list_; - + bool needs_begin_frames_; base::WeakPtrFactory<CompositorImpl> weak_factory_; DISALLOW_COPY_AND_ASSIGN(CompositorImpl);
diff --git a/content/browser/renderer_host/render_message_filter.cc b/content/browser/renderer_host/render_message_filter.cc index d422083..44114fd 100644 --- a/content/browser/renderer_host/render_message_filter.cc +++ b/content/browser/renderer_host/render_message_filter.cc
@@ -79,7 +79,6 @@ #if defined(OS_ANDROID) #include "content/browser/media/android/media_throttler.h" -#include "media/base/android/webaudio_media_codec_bridge.h" #endif #if defined(OS_MACOSX) @@ -101,13 +100,6 @@ LAZY_INSTANCE_INITIALIZER; #endif -#if defined(OS_ANDROID) -void CloseWebAudioFileDescriptor(int fd) { - if (close(fd)) - VLOG(1) << "Couldn't close output webaudio fd: " << strerror(errno); -} -#endif - } // namespace RenderMessageFilter::RenderMessageFilter( @@ -202,9 +194,6 @@ OnGetMonitorColorProfile) #endif IPC_MESSAGE_HANDLER(ViewHostMsg_MediaLogEvents, OnMediaLogEvents) -#if defined(OS_ANDROID) - IPC_MESSAGE_HANDLER(ViewHostMsg_RunWebAudioMediaCodec, OnWebAudioMediaCodec) -#endif IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() @@ -610,32 +599,6 @@ media_internals_->OnMediaEvents(render_process_id_, events); } -#if defined(OS_ANDROID) -void RenderMessageFilter::OnWebAudioMediaCodec( - base::SharedMemoryHandle encoded_data_handle, - base::FileDescriptor pcm_output, - uint32_t data_size) { - if (!MediaThrottler::GetInstance()->RequestDecoderResources()) { - base::WorkerPool::PostTask( - FROM_HERE, - base::Bind(&CloseWebAudioFileDescriptor, pcm_output.fd), - true); - VLOG(1) << "Cannot decode audio data due to throttling"; - } else { - // Let a WorkerPool handle this request since the WebAudio - // MediaCodec bridge is slow and can block while sending the data to - // the renderer. - base::WorkerPool::PostTask( - FROM_HERE, - base::Bind(&media::WebAudioMediaCodecBridge::RunWebAudioMediaCodec, - encoded_data_handle, pcm_output, data_size, - base::Bind(&MediaThrottler::OnDecodeRequestFinished, - base::Unretained(MediaThrottler::GetInstance()))), - true); - } -} -#endif - void RenderMessageFilter::OnAllocateGpuMemoryBuffer(gfx::GpuMemoryBufferId id, uint32_t width, uint32_t height,
diff --git a/content/browser/renderer_host/render_message_filter.h b/content/browser/renderer_host/render_message_filter.h index b87ad3f0..f8307a9 100644 --- a/content/browser/renderer_host/render_message_filter.h +++ b/content/browser/renderer_host/render_message_filter.h
@@ -205,12 +205,6 @@ bool CheckBenchmarkingEnabled() const; bool CheckPreparsedJsCachingEnabled() const; -#if defined(OS_ANDROID) - void OnWebAudioMediaCodec(base::SharedMemoryHandle encoded_data_handle, - base::FileDescriptor pcm_output, - uint32_t data_size); -#endif - void OnAllocateGpuMemoryBuffer(gfx::GpuMemoryBufferId id, uint32_t width, uint32_t height,
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc index cf90419..d97e777 100644 --- a/content/browser/renderer_host/render_process_host_impl.cc +++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -197,7 +197,6 @@ #if defined(OS_MACOSX) && !defined(OS_IOS) #include "content/browser/bootstrap_sandbox_manager_mac.h" -#include "content/browser/browser_io_surface_manager_mac.h" #include "content/browser/mach_broker_mac.h" #endif @@ -1372,6 +1371,7 @@ switches::kDisableRTCSmoothnessAlgorithm, switches::kDisableSeccompFilterSandbox, switches::kDisableSharedWorkers, + switches::kDisableSmoothScrolling, switches::kDisableSpeechAPI, switches::kDisableThreadedCompositing, switches::kDisableThreadedScrolling, @@ -1460,6 +1460,7 @@ switches::kUseMobileUserAgent, switches::kUseNewMediaCache, switches::kUseNormalPriorityForTileTaskWorkerThreads, + switches::kUseRemoteCompositing, switches::kV, switches::kVideoThreads, switches::kVideoUnderflowThresholdMs, @@ -1481,6 +1482,7 @@ cc::switches::kShowScreenSpaceRects, cc::switches::kShowSurfaceDamageRects, cc::switches::kSlowDownRasterScaleFactor, + cc::switches::kStrictLayerPropertyChangeChecking, cc::switches::kTopControlsHideThreshold, cc::switches::kTopControlsShowThreshold, @@ -1887,14 +1889,6 @@ // Remove ourself from the list of renderer processes so that we can't be // reused in between now and when the Delete task runs. UnregisterHost(GetID()); - -#if defined(OS_MACOSX) && !defined(OS_IOS) - if (!io_surface_manager_token_.IsZero()) { - BrowserIOSurfaceManager::GetInstance()->InvalidateChildProcessToken( - io_surface_manager_token_); - io_surface_manager_token_.SetZero(); - } -#endif } } @@ -2501,13 +2495,6 @@ UpdateProcessPriority(); } -#if defined(OS_MACOSX) && !defined(OS_IOS) - io_surface_manager_token_ = - BrowserIOSurfaceManager::GetInstance()->GenerateChildProcessToken( - GetID()); - Send(new ChildProcessMsg_SetIOSurfaceManagerToken(io_surface_manager_token_)); -#endif - // NOTE: This needs to be before sending queued messages because // ExtensionService uses this notification to initialize the renderer process // with state that must be there before any JavaScript executes.
diff --git a/content/browser/renderer_host/render_process_host_impl.h b/content/browser/renderer_host/render_process_host_impl.h index c9cc5ac7..7915495 100644 --- a/content/browser/renderer_host/render_process_host_impl.h +++ b/content/browser/renderer_host/render_process_host_impl.h
@@ -30,10 +30,6 @@ #include "ui/gfx/gpu_memory_buffer.h" #include "ui/gl/gpu_switching_observer.h" -#if defined(OS_MACOSX) && !defined(OS_IOS) -#include "content/common/mac/io_surface_manager_token.h" -#endif - namespace base { class CommandLine; class MessageLoop; @@ -498,12 +494,6 @@ // Whether or not the CHROMIUM_subscribe_uniform WebGL extension is enabled bool subscribe_uniform_enabled_; -#if defined(OS_MACOSX) && !defined(OS_IOS) - // Unique unguessable token that the child process is using to acquire - // IOSurface references. - IOSurfaceManagerToken io_surface_manager_token_; -#endif - bool channel_connected_; bool sent_render_process_ready_;
diff --git a/content/browser/renderer_host/render_view_host_factory.cc b/content/browser/renderer_host/render_view_host_factory.cc index 7fa252aa..13b2c08 100644 --- a/content/browser/renderer_host/render_view_host_factory.cc +++ b/content/browser/renderer_host/render_view_host_factory.cc
@@ -5,12 +5,14 @@ #include "content/browser/renderer_host/render_view_host_factory.h" #include "base/logging.h" +#include "base/memory/scoped_ptr.h" #include "content/browser/renderer_host/render_view_host_impl.h" +#include "content/browser/renderer_host/render_widget_host_impl.h" namespace content { // static -RenderViewHostFactory* RenderViewHostFactory::factory_ = NULL; +RenderViewHostFactory* RenderViewHostFactory::factory_ = nullptr; // static RenderViewHost* RenderViewHostFactory::Create( @@ -41,9 +43,12 @@ routing_id, main_frame_routing_id, swapped_out); } - return new RenderViewHostImpl(instance, delegate, widget_delegate, routing_id, - main_frame_routing_id, swapped_out, hidden, - true /* has_initialized_audio_host */); + return new RenderViewHostImpl( + instance, + make_scoped_ptr(new RenderWidgetHostImpl( + widget_delegate, instance->GetProcess(), routing_id, hidden)), + delegate, main_frame_routing_id, swapped_out, + true /* has_initialized_audio_host */); } // static @@ -55,7 +60,7 @@ // static void RenderViewHostFactory::UnregisterFactory() { DCHECK(factory_) << "No factory to unregister."; - factory_ = NULL; + factory_ = nullptr; } } // namespace content
diff --git a/content/browser/renderer_host/render_view_host_impl.cc b/content/browser/renderer_host/render_view_host_impl.cc index 76596b6..77ce24b 100644 --- a/content/browser/renderer_host/render_view_host_impl.cc +++ b/content/browser/renderer_host/render_view_host_impl.cc
@@ -205,19 +205,13 @@ return rvh; } -RenderViewHostImpl::RenderViewHostImpl( - SiteInstance* instance, - RenderViewHostDelegate* delegate, - RenderWidgetHostDelegate* widget_delegate, - int32_t routing_id, - int32_t main_frame_routing_id, - bool swapped_out, - bool hidden, - bool has_initialized_audio_host) - : RenderWidgetHostImpl(widget_delegate, - instance->GetProcess(), - routing_id, - hidden), +RenderViewHostImpl::RenderViewHostImpl(SiteInstance* instance, + scoped_ptr<RenderWidgetHostImpl> widget, + RenderViewHostDelegate* delegate, + int32_t main_frame_routing_id, + bool swapped_out, + bool has_initialized_audio_host) + : render_widget_host_(std::move(widget)), frames_ref_count_(0), delegate_(delegate), instance_(static_cast<SiteInstanceImpl*>(instance)), @@ -486,16 +480,8 @@ prefs.slimming_paint_v2_enabled = command_line.HasSwitch(switches::kEnableSlimmingPaintV2); -#if defined(OS_MACOSX) || defined(OS_CHROMEOS) - bool default_enable_scroll_animator = true; -#else - bool default_enable_scroll_animator = false; -#endif - prefs.enable_scroll_animator = default_enable_scroll_animator; - if (command_line.HasSwitch(switches::kEnableSmoothScrolling)) - prefs.enable_scroll_animator = true; - if (command_line.HasSwitch(switches::kDisableSmoothScrolling)) - prefs.enable_scroll_animator = false; + prefs.enable_scroll_animator = !command_line.HasSwitch( + switches::kDisableSmoothScrolling); // Certain GPU features might have been blacklisted. GpuDataManagerImpl::GetInstance()->UpdateRendererWebPrefs(&prefs); @@ -610,7 +596,7 @@ if (!GetWidget()->renderer_initialized()) return; - RenderWidgetHostImpl::RendererExited(status, exit_code); + GetWidget()->RendererExited(status, exit_code); delegate_->RenderViewTerminated(this, status, exit_code); } @@ -747,20 +733,19 @@ } bool RenderViewHostImpl::Send(IPC::Message* msg) { - return RenderWidgetHostImpl::Send(msg); + return GetWidget()->Send(msg); } RenderWidgetHostImpl* RenderViewHostImpl::GetWidget() const { - return const_cast<RenderWidgetHostImpl*>( - static_cast<const RenderWidgetHostImpl*>(this)); + return render_widget_host_.get(); } RenderProcessHost* RenderViewHostImpl::GetProcess() const { - return RenderWidgetHostImpl::GetProcess(); + return GetWidget()->GetProcess(); } int RenderViewHostImpl::GetRoutingID() const { - return RenderWidgetHostImpl::GetRoutingID(); + return GetWidget()->GetRoutingID(); } RenderFrameHost* RenderViewHostImpl::GetMainFrame() { @@ -899,10 +884,8 @@ // RenderViewHostImpl, IPC message handlers: bool RenderViewHostImpl::OnMessageReceived(const IPC::Message& msg) { - if (!BrowserMessageFilter::CheckCanDispatchOnUI( - msg, static_cast<RenderWidgetHostImpl*>(this))) { + if (!BrowserMessageFilter::CheckCanDispatchOnUI(msg, GetWidget())) return true; - } // Filter out most IPC messages if this renderer is swapped out. // We still want to handle certain ACKs to keep our state consistent. @@ -948,10 +931,9 @@ IPC_MESSAGE_HANDLER(ViewHostMsg_ClosePage_ACK, OnClosePageACK) IPC_MESSAGE_HANDLER(ViewHostMsg_DidZoomURL, OnDidZoomURL) IPC_MESSAGE_HANDLER(ViewHostMsg_RunFileChooser, OnRunFileChooser) + IPC_MESSAGE_HANDLER(ViewHostMsg_Focus, OnFocus) IPC_MESSAGE_HANDLER(ViewHostMsg_FocusedNodeTouched, OnFocusedNodeTouched) - // Have the super handle all other messages. - IPC_MESSAGE_UNHANDLED( - handled = RenderWidgetHostImpl::OnMessageReceived(msg)) + IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() return handled;
diff --git a/content/browser/renderer_host/render_view_host_impl.h b/content/browser/renderer_host/render_view_host_impl.h index 396747b7..9d9455d 100644 --- a/content/browser/renderer_host/render_view_host_impl.h +++ b/content/browser/renderer_host/render_view_host_impl.h
@@ -47,18 +47,6 @@ struct FileChooserParams; struct FrameReplicationState; -#if defined(COMPILER_MSVC) -// RenderViewHostImpl is the bottom of a diamond-shaped hierarchy, -// with RenderWidgetHost at the root. VS warns when methods from the -// root are overridden in only one of the base classes and not both -// (in this case, RenderWidgetHostImpl provides implementations of -// many of the methods). This is a silly warning when dealing with -// pure virtual methods that only have a single implementation in the -// hierarchy above this class, and is safe to ignore in this case. -#pragma warning(push) -#pragma warning(disable: 4250) -#endif - // This implements the RenderViewHost interface that is exposed to // embedders of content, and adds things only visible to content. // @@ -81,7 +69,6 @@ // For context, please see https://crbug.com/467770 and // http://www.chromium.org/developers/design-documents/site-isolation. class CONTENT_EXPORT RenderViewHostImpl : public RenderViewHost, - RenderWidgetHostImpl, public RenderWidgetHostOwnerDelegate, public RenderProcessHostObserver { public: @@ -91,23 +78,11 @@ // Convenience function, just like RenderViewHost::From. static RenderViewHostImpl* From(RenderWidgetHost* rwh); - // |routing_id| must be a valid route id. |swapped_out| indicates - // whether the view should initially be swapped out (e.g., for an opener - // frame being rendered by another process). |hidden| indicates whether the - // view is initially hidden or visible. - // - // The |session_storage_namespace| parameter allows multiple render views and - // WebContentses to share the same session storage (part of the WebStorage - // spec) space. This is useful when restoring contentses, but most callers - // should pass in NULL which will cause a new SessionStorageNamespace to be - // created. RenderViewHostImpl(SiteInstance* instance, + scoped_ptr<RenderWidgetHostImpl> widget, RenderViewHostDelegate* delegate, - RenderWidgetHostDelegate* widget_delegate, - int32_t routing_id, int32_t main_frame_routing_id, bool swapped_out, - bool hidden, bool has_initialized_audio_host); ~RenderViewHostImpl() override; @@ -266,9 +241,6 @@ sudden_termination_allowed_ = enabled; } - // RenderWidgetHost public overrides. - bool OnMessageReceived(const IPC::Message& msg) override; - // Creates a new RenderView with the given route id. void CreateNewWindow(int32_t route_id, int32_t main_frame_route_id, @@ -309,10 +281,8 @@ // to keep them consistent). protected: - // RenderWidgetHost protected overrides. - void OnFocus() override; - // RenderWidgetHostOwnerDelegate overrides. + bool OnMessageReceived(const IPC::Message& msg) override; void RenderWidgetDidInit() override; void RenderWidgetWillSetIsLoading(bool is_loading) override; void RenderWidgetGotFocus() override; @@ -352,6 +322,7 @@ void OnDidZoomURL(double zoom_level, const GURL& url); void OnRunFileChooser(const FileChooserParams& params); void OnFocusedNodeTouched(bool editable); + void OnFocus(); private: // TODO(nasko): Temporarily friend RenderFrameHostImpl, so we don't duplicate @@ -389,6 +360,9 @@ // files without the user's consent. void GrantFileAccessFromPageState(const PageState& validated_state); + // The RenderWidgetHost. + scoped_ptr<RenderWidgetHostImpl> render_widget_host_; + // The number of RenderFrameHosts which have a reference to this RVH. int frames_ref_count_; @@ -461,10 +435,6 @@ DISALLOW_COPY_AND_ASSIGN(RenderViewHostImpl); }; -#if defined(COMPILER_MSVC) -#pragma warning(pop) -#endif - } // namespace content #endif // CONTENT_BROWSER_RENDERER_HOST_RENDER_VIEW_HOST_IMPL_H_
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc index cf4ed0f..87b8550 100644 --- a/content/browser/renderer_host/render_widget_host_impl.cc +++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -437,6 +437,9 @@ } bool RenderWidgetHostImpl::OnMessageReceived(const IPC::Message &msg) { + if (owner_delegate_ && owner_delegate_->OnMessageReceived(msg)) + return true; + bool handled = true; IPC_BEGIN_MESSAGE_MAP(RenderWidgetHostImpl, msg) IPC_MESSAGE_HANDLER(FrameHostMsg_RenderProcessGone, OnRenderProcessGone) @@ -452,7 +455,6 @@ IPC_MESSAGE_HANDLER_GENERIC(ViewHostMsg_SwapCompositorFrame, OnSwapCompositorFrame(msg)) IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateRect, OnUpdateRect) - IPC_MESSAGE_HANDLER(ViewHostMsg_Focus, OnFocus) IPC_MESSAGE_HANDLER(ViewHostMsg_SetCursor, OnSetCursor) IPC_MESSAGE_HANDLER(ViewHostMsg_TextInputStateChanged, OnTextInputStateChanged) @@ -1719,11 +1721,6 @@ weak_factory_.GetWeakPtr())); } -void RenderWidgetHostImpl::OnFocus() { - // Only RenderViewHost can deal with that message. - bad_message::ReceivedBadMessage(GetProcess(), bad_message::RWH_FOCUS); -} - void RenderWidgetHostImpl::OnSetCursor(const WebCursor& cursor) { SetCursor(cursor); }
diff --git a/content/browser/renderer_host/render_widget_host_impl.h b/content/browser/renderer_host/render_widget_host_impl.h index 48c2a90..e364fdd 100644 --- a/content/browser/renderer_host/render_widget_host_impl.h +++ b/content/browser/renderer_host/render_widget_host_impl.h
@@ -369,7 +369,7 @@ void SetEditCommandsForNextKeyEvent( const std::vector<EditCommand>& commands); - // Executes the edit command on the RenderView. + // Executes the edit command. void ExecuteEditCommand(const std::string& command, const std::string& value); @@ -489,6 +489,11 @@ // request to create a new RenderWidget. void SetInitialRenderSizeParams(const ViewMsg_Resize_Params& resize_params); + // Called when we receive a notification indicating that the renderer process + // is gone. This will reset our state so that our state will be consistent if + // a new renderer is created. + void RendererExited(base::TerminationStatus status, int exit_code); + // Expose increment/decrement of the in-flight event count, so // RenderViewHostImpl can account for in-flight beforeunload/unload events. int increment_in_flight_event_count() { return ++in_flight_event_count_; } @@ -500,11 +505,6 @@ bool renderer_initialized() const { return renderer_initialized_; } protected: - // Called when we receive a notification indicating that the renderer - // process has gone. This will reset our state so that our state will be - // consistent if a new renderer is created. - void RendererExited(base::TerminationStatus status, int exit_code); - // Retrieves an id the renderer can use to refer to its view. // This is used for various IPC messages, including plugins. gfx::NativeViewId GetNativeViewId() const; @@ -521,7 +521,7 @@ bool IsMouseLocked() const; - // The View associated with the RenderViewHost. The lifetime of this object + // The View associated with the RenderWidgetHost. The lifetime of this object // is associated with the lifetime of the Render process. If the Renderer // crashes, its View is destroyed and this pointer becomes NULL, even though // render_view_host_ lives on to load another URL (creating a new View while @@ -561,7 +561,6 @@ bool OnSwapCompositorFrame(const IPC::Message& message); void OnUpdateRect(const ViewHostMsg_UpdateRect_Params& params); void OnQueueSyntheticGesture(const SyntheticGesturePacket& gesture_packet); - virtual void OnFocus(); void OnSetCursor(const WebCursor& cursor); void OnTextInputStateChanged( const ViewHostMsg_TextInputState_Params& params);
diff --git a/content/browser/renderer_host/render_widget_host_input_event_router.cc b/content/browser/renderer_host/render_widget_host_input_event_router.cc index 5c097111..eef72ac2 100644 --- a/content/browser/renderer_host/render_widget_host_input_event_router.cc +++ b/content/browser/renderer_host/render_widget_host_input_event_router.cc
@@ -11,7 +11,7 @@ namespace content { RenderWidgetHostInputEventRouter::RenderWidgetHostInputEventRouter() - : current_touch_target_(nullptr), active_touches_(0) {} + : active_touches_(0) {} RenderWidgetHostInputEventRouter::~RenderWidgetHostInputEventRouter() { owner_map_.clear(); @@ -41,7 +41,12 @@ // parent frame has not sent a new compositor frame since that happened. if (iter == owner_map_.end()) return root_view; - return iter->second.get(); + RenderWidgetHostViewBase* target = iter->second.get(); + // If we find the weak pointer is now null, it means the map entry is stale + // and should be removed to free space. + if (!target) + owner_map_.erase(iter); + return target; } void RenderWidgetHostInputEventRouter::RouteMouseEvent( @@ -87,8 +92,14 @@ gfx::Point transformed_point; gfx::Point original_point(event->touches[0].position.x, event->touches[0].position.y); - current_touch_target_ = + RenderWidgetHostViewBase* target = FindEventTarget(root_view, original_point, &transformed_point); + if (!target) + return; + + // Store the weak-ptr to the target, since it could disappear in the + // middle of a touch sequence. + current_touch_target_ = target->GetWeakPtr(); } ++active_touches_; if (current_touch_target_) @@ -106,7 +117,7 @@ current_touch_target_->ProcessTouchEvent(*event, latency); --active_touches_; if (!active_touches_) - current_touch_target_ = nullptr; + current_touch_target_ = WeakTarget(); break; default: NOTREACHED();
diff --git a/content/browser/renderer_host/render_widget_host_input_event_router.h b/content/browser/renderer_host/render_widget_host_input_event_router.h index 0c01a6c..03902f5 100644 --- a/content/browser/renderer_host/render_widget_host_input_event_router.h +++ b/content/browser/renderer_host/render_widget_host_input_event_router.h
@@ -57,6 +57,7 @@ } private: + using WeakTarget = base::WeakPtr<RenderWidgetHostViewBase>; using SurfaceIdNamespaceOwnerMap = base::hash_map<uint32_t, base::WeakPtr<RenderWidgetHostViewBase>>; @@ -65,7 +66,7 @@ gfx::Point* transformed_point); SurfaceIdNamespaceOwnerMap owner_map_; - RenderWidgetHostViewBase* current_touch_target_; + WeakTarget current_touch_target_; int active_touches_; DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostInputEventRouter);
diff --git a/content/browser/renderer_host/render_widget_host_owner_delegate.h b/content/browser/renderer_host/render_widget_host_owner_delegate.h index 68638f3..c2b0c45 100644 --- a/content/browser/renderer_host/render_widget_host_owner_delegate.h +++ b/content/browser/renderer_host/render_widget_host_owner_delegate.h
@@ -7,6 +7,10 @@ #include "content/common/content_export.h" +namespace IPC { +class Message; +} + namespace blink { class WebMouseEvent; } @@ -24,6 +28,10 @@ // and http://crbug.com/478281. class CONTENT_EXPORT RenderWidgetHostOwnerDelegate { public: + // The RenderWidgetHost received an IPC message. Return true if this delegate + // handles it. + virtual bool OnMessageReceived(const IPC::Message& msg) = 0; + // The RenderWidgetHost has been initialized. virtual void RenderWidgetDidInit() = 0;
diff --git a/content/browser/renderer_host/render_widget_host_view_android.cc b/content/browser/renderer_host/render_widget_host_view_android.cc index a736706b..1b8ca445 100644 --- a/content/browser/renderer_host/render_widget_host_view_android.cc +++ b/content/browser/renderer_host/render_widget_host_view_android.cc
@@ -1616,6 +1616,10 @@ } break; + case blink::WebInputEvent::GestureScrollBegin: + selection_controller_->OnScrollBeginEvent(); + break; + default: break; }
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.cc b/content/browser/renderer_host/render_widget_host_view_aura.cc index 6968dfc..634bd66c 100644 --- a/content/browser/renderer_host/render_widget_host_view_aura.cc +++ b/content/browser/renderer_host/render_widget_host_view_aura.cc
@@ -2929,6 +2929,7 @@ } break; case ui::ET_GESTURE_SCROLL_BEGIN: + selection_controller_->OnScrollBeginEvent(); selection_controller_client_->OnScrollStarted(); break; case ui::ET_GESTURE_SCROLL_END:
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 e4a9f42b..8a8f916 100644 --- a/content/browser/renderer_host/render_widget_host_view_mac.mm +++ b/content/browser/renderer_host/render_widget_host_view_mac.mm
@@ -69,7 +69,6 @@ #include "third_party/WebKit/public/platform/WebScreenInfo.h" #include "third_party/WebKit/public/web/WebInputEvent.h" #import "third_party/mozilla/ComplexTextInputPanel.h" -#include "ui/accelerated_widget_mac/surface_handle_types.h" #include "ui/base/cocoa/animation_utils.h" #import "ui/base/cocoa/fullscreen_window_manager.h" #import "ui/base/cocoa/underlay_opengl_hosting_window.h"
diff --git a/content/browser/service_worker/embedded_worker_instance.cc b/content/browser/service_worker/embedded_worker_instance.cc index c40adea..211c11fe 100644 --- a/content/browser/service_worker/embedded_worker_instance.cc +++ b/content/browser/service_worker/embedded_worker_instance.cc
@@ -21,6 +21,7 @@ #include "content/common/service_worker/service_worker_types.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/render_process_host.h" +#include "content/public/common/child_process_host.h" #include "ipc/ipc_message.h" #include "url/gurl.h" @@ -136,7 +137,7 @@ EmbeddedWorkerInstance::~EmbeddedWorkerInstance() { DCHECK(status_ == STOPPING || status_ == STOPPED) << status_; devtools_proxy_.reset(); - if (context_ && process_id_ != -1) + if (context_ && process_id_ != ChildProcessHost::kInvalidUniqueID) context_->process_manager()->ReleaseWorkerProcess(embedded_worker_id_); if (registry_->GetWorker(embedded_worker_id_)) registry_->RemoveWorker(process_id_, embedded_worker_id_); @@ -236,12 +237,11 @@ embedded_worker_id_(embedded_worker_id), status_(STOPPED), starting_phase_(NOT_STARTING), - process_id_(-1), + process_id_(ChildProcessHost::kInvalidUniqueID), thread_id_(kInvalidEmbeddedWorkerThreadId), devtools_attached_(false), network_accessed_for_script_(false), - weak_factory_(this) { -} + weak_factory_(this) {} // static void EmbeddedWorkerInstance::RunProcessAllocated( @@ -275,7 +275,7 @@ int process_id, bool is_new_process, ServiceWorkerStatusCode status) { - DCHECK_EQ(process_id_, -1); + DCHECK_EQ(process_id_, ChildProcessHost::kInvalidUniqueID); TRACE_EVENT_ASYNC_END1("ServiceWorker", "EmbeddedWorkerInstance::ProcessAllocate", params.get(), @@ -508,11 +508,11 @@ void EmbeddedWorkerInstance::ReleaseProcess() { devtools_proxy_.reset(); - if (context_ && process_id_ != -1) + if (context_ && process_id_ != ChildProcessHost::kInvalidUniqueID) context_->process_manager()->ReleaseWorkerProcess(embedded_worker_id_); status_ = STOPPED; - process_id_ = -1; - thread_id_ = -1; + process_id_ = ChildProcessHost::kInvalidUniqueID; + thread_id_ = kInvalidEmbeddedWorkerThreadId; service_registry_.reset(); start_callback_.Reset(); }
diff --git a/content/browser/service_worker/embedded_worker_instance.h b/content/browser/service_worker/embedded_worker_instance.h index ad1272f8..0b292d1 100644 --- a/content/browser/service_worker/embedded_worker_instance.h +++ b/content/browser/service_worker/embedded_worker_instance.h
@@ -262,7 +262,7 @@ Status status_; StartingPhase starting_phase_; - // Current running information. -1 indicates the worker is not running. + // Current running information. int process_id_; int thread_id_; scoped_ptr<ServiceRegistryImpl> service_registry_;
diff --git a/content/browser/service_worker/embedded_worker_instance_unittest.cc b/content/browser/service_worker/embedded_worker_instance_unittest.cc index b19f8846..9aebb0d2 100644 --- a/content/browser/service_worker/embedded_worker_instance_unittest.cc +++ b/content/browser/service_worker/embedded_worker_instance_unittest.cc
@@ -15,6 +15,7 @@ #include "content/browser/service_worker/service_worker_context_core.h" #include "content/browser/service_worker/service_worker_context_wrapper.h" #include "content/common/service_worker/embedded_worker_messages.h" +#include "content/public/common/child_process_host.h" #include "content/public/test/test_browser_thread_bundle.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -269,8 +270,9 @@ base::RunLoop run_loop; worker->SendStartWorker( std::move(params), - base::Bind(&SaveStatusAndCall, &status, run_loop.QuitClosure()), true, -1, - false); + base::Bind(&SaveStatusAndCall, &status, run_loop.QuitClosure()), + true /* is_new_process */, MSG_ROUTING_NONE, + false /* wait_for_debugger */); run_loop.Run(); EXPECT_EQ(SERVICE_WORKER_ERROR_ABORT, status); // Don't expect SendStartWorker() to dispatch an OnStopped/Detached() message @@ -284,8 +286,9 @@ EmbeddedWorkerInstance* worker_ptr = worker.get(); worker_ptr->SendStartWorker( std::move(params), - base::Bind(&DestroyWorker, base::Passed(&worker), &status), true, -1, - false); + base::Bind(&DestroyWorker, base::Passed(&worker), &status), + true /* is_new_process */, MSG_ROUTING_NONE, + false /* wait_for_debugger */); // No crash. EXPECT_EQ(SERVICE_WORKER_ERROR_ABORT, status); } @@ -298,7 +301,7 @@ worker->AddListener(this); // Pretend we stop during starting before we got a process allocated. worker->status_ = EmbeddedWorkerInstance::STARTING; - worker->process_id_ = -1; + worker->process_id_ = ChildProcessHost::kInvalidUniqueID; worker->Stop(); EXPECT_EQ(EmbeddedWorkerInstance::STOPPED, worker->status()); EXPECT_TRUE(detached_);
diff --git a/content/browser/service_worker/embedded_worker_registry.h b/content/browser/service_worker/embedded_worker_registry.h index 308e1de..c9cea03 100644 --- a/content/browser/service_worker/embedded_worker_registry.h +++ b/content/browser/service_worker/embedded_worker_registry.h
@@ -127,7 +127,8 @@ ServiceWorkerStatusCode Send(int process_id, IPC::Message* message); // RemoveWorker is called when EmbeddedWorkerInstance is destructed. - // |process_id| could be invalid (i.e. -1) if it's not running. + // |process_id| could be invalid (i.e. ChildProcessHost::kInvalidUniqueID) + // if it's not running. void RemoveWorker(int process_id, int embedded_worker_id); EmbeddedWorkerInstance* GetWorkerForMessage(int process_id,
diff --git a/content/browser/service_worker/service_worker_browsertest.cc b/content/browser/service_worker/service_worker_browsertest.cc index 6ef3306d..205f067 100644 --- a/content/browser/service_worker/service_worker_browsertest.cc +++ b/content/browser/service_worker/service_worker_browsertest.cc
@@ -305,11 +305,6 @@ protected: using self = ServiceWorkerBrowserTest; - void SetUpCommandLine(base::CommandLine* command_line) override { - command_line->AppendSwitch( - switches::kEnableExperimentalWebPlatformFeatures); - } - void SetUpOnMainThread() override { ASSERT_TRUE(embedded_test_server()->Start()); StoragePartition* partition = BrowserContext::GetDefaultStoragePartition( @@ -1249,7 +1244,6 @@ version_->RemoveListener(this); } void SetUpCommandLine(base::CommandLine* command_line) override { - ServiceWorkerBrowserTest::SetUpCommandLine(command_line); command_line->AppendSwitchASCII(switches::kV8CacheOptions, "code"); } void SetUpRegistrationAndListenerOnIOThread(const std::string& worker_url) {
diff --git a/content/browser/service_worker/service_worker_client_navigation_utils.cc b/content/browser/service_worker/service_worker_client_navigation_utils.cc deleted file mode 100644 index 5147bd1..0000000 --- a/content/browser/service_worker/service_worker_client_navigation_utils.cc +++ /dev/null
@@ -1,234 +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 "content/browser/service_worker/service_worker_client_navigation_utils.h" - -#include "base/macros.h" -#include "content/browser/frame_host/frame_tree_node.h" -#include "content/browser/frame_host/render_frame_host_impl.h" -#include "content/browser/service_worker/service_worker_context_core.h" -#include "content/browser/service_worker/service_worker_context_wrapper.h" -#include "content/browser/storage_partition_impl.h" -#include "content/common/service_worker/service_worker_client_info.h" -#include "content/public/browser/browser_thread.h" -#include "content/public/browser/content_browser_client.h" -#include "content/public/browser/page_navigator.h" -#include "content/public/browser/web_contents.h" -#include "content/public/browser/web_contents_observer.h" -#include "content/public/common/child_process_host.h" -#include "url/gurl.h" - -namespace content { -namespace service_worker_client_navigation_utils { - -namespace { - -using OpenURLCallback = base::Callback<void(int, int)>; - -// The OpenURLObserver class is a WebContentsObserver that will wait for a -// WebContents to be initialized, run the |callback| passed to its constructor -// then self destroy. -// The callback will receive the process and frame ids. If something went wrong -// those will be (kInvalidUniqueID, MSG_ROUTING_NONE). -// The callback will be called in the IO thread. -class OpenURLObserver : public WebContentsObserver { - public: - OpenURLObserver(WebContents* web_contents, - int frame_tree_node_id, - const OpenURLCallback& callback) - : WebContentsObserver(web_contents), - frame_tree_node_id_(frame_tree_node_id), - callback_(callback) {} - - void DidCommitProvisionalLoadForFrame( - RenderFrameHost* render_frame_host, - const GURL& validated_url, - ui::PageTransition transition_type) override { - DCHECK(web_contents()); - - RenderFrameHostImpl* rfhi = - static_cast<RenderFrameHostImpl*>(render_frame_host); - if (rfhi->frame_tree_node()->frame_tree_node_id() != frame_tree_node_id_) - return; - - RunCallback(render_frame_host->GetProcess()->GetID(), - render_frame_host->GetRoutingID()); - } - - void RenderProcessGone(base::TerminationStatus status) override { - RunCallback(ChildProcessHost::kInvalidUniqueID, MSG_ROUTING_NONE); - } - - void WebContentsDestroyed() override { - RunCallback(ChildProcessHost::kInvalidUniqueID, MSG_ROUTING_NONE); - } - - private: - void RunCallback(int render_process_id, int render_frame_id) { - // After running the callback, |this| will stop observing, thus - // web_contents() should return nullptr and |RunCallback| should no longer - // be called. Then, |this| will self destroy. - DCHECK(web_contents()); - - BrowserThread::PostTask( - BrowserThread::IO, FROM_HERE, - base::Bind(callback_, render_process_id, render_frame_id)); - Observe(nullptr); - base::MessageLoop::current()->DeleteSoon(FROM_HERE, this); - } - - int frame_tree_node_id_; - const OpenURLCallback callback_; - - DISALLOW_COPY_AND_ASSIGN(OpenURLObserver); -}; - -// This is only called for main frame navigations in OpenWindowOnUI(). -void DidOpenURL(const OpenURLCallback& callback, WebContents* web_contents) { - DCHECK(web_contents); - - RenderFrameHostImpl* rfhi = - static_cast<RenderFrameHostImpl*>(web_contents->GetMainFrame()); - new OpenURLObserver(web_contents, - rfhi->frame_tree_node()->frame_tree_node_id(), callback); -} - -void OpenWindowOnUI( - const GURL& url, - const GURL& script_url, - int worker_process_id, - const scoped_refptr<ServiceWorkerContextWrapper>& context_wrapper, - const OpenURLCallback& callback) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - - BrowserContext* browser_context = - context_wrapper->storage_partition() - ? context_wrapper->storage_partition()->browser_context() - : nullptr; - // We are shutting down. - if (!browser_context) - return; - - RenderProcessHost* render_process_host = - RenderProcessHost::FromID(worker_process_id); - if (render_process_host->IsForGuestsOnly()) { - BrowserThread::PostTask( - BrowserThread::IO, FROM_HERE, - base::Bind(callback, ChildProcessHost::kInvalidUniqueID, - MSG_ROUTING_NONE)); - return; - } - - OpenURLParams params( - url, Referrer::SanitizeForRequest( - url, Referrer(script_url, blink::WebReferrerPolicyDefault)), - NEW_FOREGROUND_TAB, ui::PAGE_TRANSITION_AUTO_TOPLEVEL, - true /* is_renderer_initiated */); - - GetContentClient()->browser()->OpenURL(browser_context, params, - base::Bind(&DidOpenURL, callback)); -} - -void NavigateClientOnUI(const GURL& url, - const GURL& script_url, - int process_id, - int frame_id, - const OpenURLCallback& callback) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - - RenderFrameHostImpl* rfhi = RenderFrameHostImpl::FromID(process_id, frame_id); - WebContents* web_contents = WebContents::FromRenderFrameHost(rfhi); - - if (!rfhi || !web_contents) { - BrowserThread::PostTask( - BrowserThread::IO, FROM_HERE, - base::Bind(callback, ChildProcessHost::kInvalidUniqueID, - MSG_ROUTING_NONE)); - return; - } - - ui::PageTransition transition = rfhi->GetParent() - ? ui::PAGE_TRANSITION_AUTO_SUBFRAME - : ui::PAGE_TRANSITION_AUTO_TOPLEVEL; - int frame_tree_node_id = rfhi->frame_tree_node()->frame_tree_node_id(); - - OpenURLParams params( - url, Referrer::SanitizeForRequest( - url, Referrer(script_url, blink::WebReferrerPolicyDefault)), - frame_tree_node_id, CURRENT_TAB, transition, - true /* is_renderer_initiated */); - web_contents->OpenURL(params); - new OpenURLObserver(web_contents, frame_tree_node_id, callback); -} - -void DidNavigate(const base::WeakPtr<ServiceWorkerContextCore>& context, - const GURL& origin, - const NavigationCallback& callback, - int render_process_id, - int render_frame_id) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - - if (!context) { - callback.Run(SERVICE_WORKER_ERROR_ABORT, std::string(), - ServiceWorkerClientInfo()); - return; - } - - if (render_process_id == ChildProcessHost::kInvalidUniqueID && - render_frame_id == MSG_ROUTING_NONE) { - callback.Run(SERVICE_WORKER_ERROR_FAILED, std::string(), - ServiceWorkerClientInfo()); - return; - } - - for (scoped_ptr<ServiceWorkerContextCore::ProviderHostIterator> it = - context->GetClientProviderHostIterator(origin); - !it->IsAtEnd(); it->Advance()) { - ServiceWorkerProviderHost* provider_host = it->GetProviderHost(); - if (provider_host->process_id() != render_process_id || - provider_host->frame_id() != render_frame_id) { - continue; - } - provider_host->GetWindowClientInfo( - base::Bind(callback, SERVICE_WORKER_OK, provider_host->client_uuid())); - return; - } - - // If here, it means that no provider_host was found, in which case, the - // renderer should still be informed that the window was opened. - callback.Run(SERVICE_WORKER_OK, std::string(), ServiceWorkerClientInfo()); -} - -} // namespace - -void OpenWindow(const GURL& url, - const GURL& script_url, - int worker_process_id, - const base::WeakPtr<ServiceWorkerContextCore>& context, - const NavigationCallback& callback) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, - base::Bind( - &OpenWindowOnUI, url, script_url, worker_process_id, - make_scoped_refptr(context->wrapper()), - base::Bind(&DidNavigate, context, script_url.GetOrigin(), callback))); -} - -void NavigateClient(const GURL& url, - const GURL& script_url, - int process_id, - int frame_id, - const base::WeakPtr<ServiceWorkerContextCore>& context, - const NavigationCallback& callback) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, - base::Bind( - &NavigateClientOnUI, url, script_url, process_id, frame_id, - base::Bind(&DidNavigate, context, script_url.GetOrigin(), callback))); -} - -} // namespace service_worker_client_navigation_utils -} // namespace content
diff --git a/content/browser/service_worker/service_worker_client_utils.cc b/content/browser/service_worker/service_worker_client_utils.cc new file mode 100644 index 0000000..26ef4d3 --- /dev/null +++ b/content/browser/service_worker/service_worker_client_utils.cc
@@ -0,0 +1,397 @@ +// 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/service_worker/service_worker_client_utils.h" + +#include <algorithm> + +#include "base/macros.h" +#include "content/browser/frame_host/frame_tree_node.h" +#include "content/browser/frame_host/render_frame_host_impl.h" +#include "content/browser/service_worker/service_worker_context_core.h" +#include "content/browser/service_worker/service_worker_context_wrapper.h" +#include "content/browser/service_worker/service_worker_version.h" +#include "content/browser/storage_partition_impl.h" +#include "content/common/service_worker/service_worker_client_info.h" +#include "content/common/service_worker/service_worker_types.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/content_browser_client.h" +#include "content/public/browser/page_navigator.h" +#include "content/public/browser/web_contents.h" +#include "content/public/browser/web_contents_observer.h" +#include "content/public/common/child_process_host.h" +#include "url/gurl.h" + +namespace content { +namespace service_worker_client_utils { + +namespace { + +using OpenURLCallback = base::Callback<void(int, int)>; +using GetWindowClientsCallback = + base::Callback<void(scoped_ptr<ServiceWorkerClients>)>; + +// The OpenURLObserver class is a WebContentsObserver that will wait for a +// WebContents to be initialized, run the |callback| passed to its constructor +// then self destroy. +// The callback will receive the process and frame ids. If something went wrong +// those will be (kInvalidUniqueID, MSG_ROUTING_NONE). +// The callback will be called in the IO thread. +class OpenURLObserver : public WebContentsObserver { + public: + OpenURLObserver(WebContents* web_contents, + int frame_tree_node_id, + const OpenURLCallback& callback) + : WebContentsObserver(web_contents), + frame_tree_node_id_(frame_tree_node_id), + callback_(callback) {} + + void DidCommitProvisionalLoadForFrame( + RenderFrameHost* render_frame_host, + const GURL& validated_url, + ui::PageTransition transition_type) override { + DCHECK(web_contents()); + + RenderFrameHostImpl* rfhi = + static_cast<RenderFrameHostImpl*>(render_frame_host); + if (rfhi->frame_tree_node()->frame_tree_node_id() != frame_tree_node_id_) + return; + + RunCallback(render_frame_host->GetProcess()->GetID(), + render_frame_host->GetRoutingID()); + } + + void RenderProcessGone(base::TerminationStatus status) override { + RunCallback(ChildProcessHost::kInvalidUniqueID, MSG_ROUTING_NONE); + } + + void WebContentsDestroyed() override { + RunCallback(ChildProcessHost::kInvalidUniqueID, MSG_ROUTING_NONE); + } + + private: + void RunCallback(int render_process_id, int render_frame_id) { + // After running the callback, |this| will stop observing, thus + // web_contents() should return nullptr and |RunCallback| should no longer + // be called. Then, |this| will self destroy. + DCHECK(web_contents()); + + BrowserThread::PostTask( + BrowserThread::IO, FROM_HERE, + base::Bind(callback_, render_process_id, render_frame_id)); + Observe(nullptr); + base::MessageLoop::current()->DeleteSoon(FROM_HERE, this); + } + + int frame_tree_node_id_; + const OpenURLCallback callback_; + + DISALLOW_COPY_AND_ASSIGN(OpenURLObserver); +}; + +// This is only called for main frame navigations in OpenWindowOnUI(). +void DidOpenURL(const OpenURLCallback& callback, WebContents* web_contents) { + DCHECK(web_contents); + + RenderFrameHostImpl* rfhi = + static_cast<RenderFrameHostImpl*>(web_contents->GetMainFrame()); + new OpenURLObserver(web_contents, + rfhi->frame_tree_node()->frame_tree_node_id(), callback); +} + +void OpenWindowOnUI( + const GURL& url, + const GURL& script_url, + int worker_process_id, + const scoped_refptr<ServiceWorkerContextWrapper>& context_wrapper, + const OpenURLCallback& callback) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + + BrowserContext* browser_context = + context_wrapper->storage_partition() + ? context_wrapper->storage_partition()->browser_context() + : nullptr; + // We are shutting down. + if (!browser_context) + return; + + RenderProcessHost* render_process_host = + RenderProcessHost::FromID(worker_process_id); + if (render_process_host->IsForGuestsOnly()) { + BrowserThread::PostTask( + BrowserThread::IO, FROM_HERE, + base::Bind(callback, ChildProcessHost::kInvalidUniqueID, + MSG_ROUTING_NONE)); + return; + } + + OpenURLParams params( + url, Referrer::SanitizeForRequest( + url, Referrer(script_url, blink::WebReferrerPolicyDefault)), + NEW_FOREGROUND_TAB, ui::PAGE_TRANSITION_AUTO_TOPLEVEL, + true /* is_renderer_initiated */); + + GetContentClient()->browser()->OpenURL(browser_context, params, + base::Bind(&DidOpenURL, callback)); +} + +void NavigateClientOnUI(const GURL& url, + const GURL& script_url, + int process_id, + int frame_id, + const OpenURLCallback& callback) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + + RenderFrameHostImpl* rfhi = RenderFrameHostImpl::FromID(process_id, frame_id); + WebContents* web_contents = WebContents::FromRenderFrameHost(rfhi); + + if (!rfhi || !web_contents) { + BrowserThread::PostTask( + BrowserThread::IO, FROM_HERE, + base::Bind(callback, ChildProcessHost::kInvalidUniqueID, + MSG_ROUTING_NONE)); + return; + } + + ui::PageTransition transition = rfhi->GetParent() + ? ui::PAGE_TRANSITION_AUTO_SUBFRAME + : ui::PAGE_TRANSITION_AUTO_TOPLEVEL; + int frame_tree_node_id = rfhi->frame_tree_node()->frame_tree_node_id(); + + OpenURLParams params( + url, Referrer::SanitizeForRequest( + url, Referrer(script_url, blink::WebReferrerPolicyDefault)), + frame_tree_node_id, CURRENT_TAB, transition, + true /* is_renderer_initiated */); + web_contents->OpenURL(params); + new OpenURLObserver(web_contents, frame_tree_node_id, callback); +} + +void DidNavigate(const base::WeakPtr<ServiceWorkerContextCore>& context, + const GURL& origin, + const NavigationCallback& callback, + int render_process_id, + int render_frame_id) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + + if (!context) { + callback.Run(SERVICE_WORKER_ERROR_ABORT, std::string(), + ServiceWorkerClientInfo()); + return; + } + + if (render_process_id == ChildProcessHost::kInvalidUniqueID && + render_frame_id == MSG_ROUTING_NONE) { + callback.Run(SERVICE_WORKER_ERROR_FAILED, std::string(), + ServiceWorkerClientInfo()); + return; + } + + for (scoped_ptr<ServiceWorkerContextCore::ProviderHostIterator> it = + context->GetClientProviderHostIterator(origin); + !it->IsAtEnd(); it->Advance()) { + ServiceWorkerProviderHost* provider_host = it->GetProviderHost(); + if (provider_host->process_id() != render_process_id || + provider_host->frame_id() != render_frame_id) { + continue; + } + provider_host->GetWindowClientInfo( + base::Bind(callback, SERVICE_WORKER_OK, provider_host->client_uuid())); + return; + } + + // If here, it means that no provider_host was found, in which case, the + // renderer should still be informed that the window was opened. + callback.Run(SERVICE_WORKER_OK, std::string(), ServiceWorkerClientInfo()); +} + +void AddWindowClient( + ServiceWorkerProviderHost* host, + std::vector<base::Tuple<int, int, std::string>>* client_info) { + if (host->client_type() != blink::WebServiceWorkerClientTypeWindow) + return; + client_info->push_back(base::MakeTuple(host->process_id(), host->frame_id(), + host->client_uuid())); +} + +void AddNonWindowClient(ServiceWorkerProviderHost* host, + const ServiceWorkerClientQueryOptions& options, + ServiceWorkerClients* clients) { + blink::WebServiceWorkerClientType host_client_type = host->client_type(); + if (host_client_type == blink::WebServiceWorkerClientTypeWindow) + return; + if (options.client_type != blink::WebServiceWorkerClientTypeAll && + options.client_type != host_client_type) + return; + + ServiceWorkerClientInfo client_info(blink::WebPageVisibilityStateHidden, + false, // is_focused + host->document_url(), + REQUEST_CONTEXT_FRAME_TYPE_NONE, + base::TimeTicks(), host_client_type); + client_info.client_uuid = host->client_uuid(); + clients->push_back(client_info); +} + +void OnGetWindowClientsOnUI( + // The tuple contains process_id, frame_id, client_uuid. + const std::vector<base::Tuple<int, int, std::string>>& clients_info, + const GURL& script_url, + const GetWindowClientsCallback& callback) { + scoped_ptr<ServiceWorkerClients> clients(new ServiceWorkerClients); + + for (const auto& it : clients_info) { + ServiceWorkerClientInfo info = + ServiceWorkerProviderHost::GetWindowClientInfoOnUI(base::get<0>(it), + base::get<1>(it)); + + // If the request to the provider_host returned an empty + // ServiceWorkerClientInfo, that means that it wasn't possible to associate + // it with a valid RenderFrameHost. It might be because the frame was killed + // or navigated in between. + if (info.IsEmpty()) + continue; + + // We can get info for a frame that was navigating end ended up with a + // different URL than expected. In such case, we should make sure to not + // expose cross-origin WindowClient. + if (info.url.GetOrigin() != script_url.GetOrigin()) + continue; + + info.client_uuid = base::get<2>(it); + clients->push_back(info); + } + + BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, + base::Bind(callback, base::Passed(&clients))); +} + +struct ServiceWorkerClientInfoSortMRU { + bool operator()(const ServiceWorkerClientInfo& a, + const ServiceWorkerClientInfo& b) const { + return a.last_focus_time > b.last_focus_time; + } +}; + +void DidGetClients(const ClientsCallback& callback, + ServiceWorkerClients* clients) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + + // Sort clients so that the most recently active tab is in the front. + std::sort(clients->begin(), clients->end(), ServiceWorkerClientInfoSortMRU()); + + callback.Run(clients); +} + +void GetNonWindowClients(const base::WeakPtr<ServiceWorkerVersion>& controller, + const ServiceWorkerClientQueryOptions& options, + ServiceWorkerClients* clients) { + if (!options.include_uncontrolled) { + for (auto& controllee : controller->controllee_map()) + AddNonWindowClient(controllee.second, options, clients); + } else if (controller->context()) { + GURL origin = controller->script_url().GetOrigin(); + for (auto it = controller->context()->GetClientProviderHostIterator(origin); + !it->IsAtEnd(); it->Advance()) { + AddNonWindowClient(it->GetProviderHost(), options, clients); + } + } +} + +void DidGetWindowClients(const base::WeakPtr<ServiceWorkerVersion>& controller, + const ServiceWorkerClientQueryOptions& options, + const ClientsCallback& callback, + scoped_ptr<ServiceWorkerClients> clients) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + if (options.client_type == blink::WebServiceWorkerClientTypeAll) + GetNonWindowClients(controller, options, clients.get()); + DidGetClients(callback, clients.get()); +} + +void GetWindowClients(const base::WeakPtr<ServiceWorkerVersion>& controller, + const ServiceWorkerClientQueryOptions& options, + const ClientsCallback& callback) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + DCHECK(options.client_type == blink::WebServiceWorkerClientTypeWindow || + options.client_type == blink::WebServiceWorkerClientTypeAll); + + std::vector<base::Tuple<int, int, std::string>> clients_info; + if (!options.include_uncontrolled) { + for (auto& controllee : controller->controllee_map()) + AddWindowClient(controllee.second, &clients_info); + } else if (controller->context()) { + GURL origin = controller->script_url().GetOrigin(); + for (auto it = controller->context()->GetClientProviderHostIterator(origin); + !it->IsAtEnd(); it->Advance()) { + AddWindowClient(it->GetProviderHost(), &clients_info); + } + } + + if (clients_info.empty()) { + DidGetWindowClients(controller, options, callback, + make_scoped_ptr(new ServiceWorkerClients)); + return; + } + + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + base::Bind( + &OnGetWindowClientsOnUI, clients_info, controller->script_url(), + base::Bind(&DidGetWindowClients, controller, options, callback))); +} + +} // namespace + +void OpenWindow(const GURL& url, + const GURL& script_url, + int worker_process_id, + const base::WeakPtr<ServiceWorkerContextCore>& context, + const NavigationCallback& callback) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + base::Bind( + &OpenWindowOnUI, url, script_url, worker_process_id, + make_scoped_refptr(context->wrapper()), + base::Bind(&DidNavigate, context, script_url.GetOrigin(), callback))); +} + +void NavigateClient(const GURL& url, + const GURL& script_url, + int process_id, + int frame_id, + const base::WeakPtr<ServiceWorkerContextCore>& context, + const NavigationCallback& callback) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + base::Bind( + &NavigateClientOnUI, url, script_url, process_id, frame_id, + base::Bind(&DidNavigate, context, script_url.GetOrigin(), callback))); +} + +void GetClients(const base::WeakPtr<ServiceWorkerVersion>& controller, + const ServiceWorkerClientQueryOptions& options, + const ClientsCallback& callback) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + + ServiceWorkerClients clients; + if (!controller->HasControllee() && !options.include_uncontrolled) { + DidGetClients(callback, &clients); + return; + } + + // For Window clients we want to query the info on the UI thread first. + if (options.client_type == blink::WebServiceWorkerClientTypeWindow || + options.client_type == blink::WebServiceWorkerClientTypeAll) { + GetWindowClients(controller, options, callback); + return; + } + + GetNonWindowClients(controller, options, &clients); + DidGetClients(callback, &clients); +} + +} // namespace service_worker_client_utils +} // namespace content
diff --git a/content/browser/service_worker/service_worker_client_navigation_utils.h b/content/browser/service_worker/service_worker_client_utils.h similarity index 64% rename from content/browser/service_worker/service_worker_client_navigation_utils.h rename to content/browser/service_worker/service_worker_client_utils.h index 26aee55..258268e 100644 --- a/content/browser/service_worker/service_worker_client_navigation_utils.h +++ b/content/browser/service_worker/service_worker_client_utils.h
@@ -2,10 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_CLIENT_NAVIGATION_UTILS_H_ -#define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_CLIENT_NAVIGATION_UTILS_H_ +#ifndef CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_CLIENT_UTILS_H_ +#define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_CLIENT_UTILS_H_ #include <string> +#include <vector> #include "base/callback.h" #include "base/memory/weak_ptr.h" @@ -16,14 +17,18 @@ namespace content { class ServiceWorkerContextCore; +class ServiceWorkerVersion; struct ServiceWorkerClientInfo; +struct ServiceWorkerClientQueryOptions; -namespace service_worker_client_navigation_utils { +namespace service_worker_client_utils { using NavigationCallback = base::Callback<void(ServiceWorkerStatusCode status, const std::string& client_uuid, const ServiceWorkerClientInfo& client_info)>; +using ServiceWorkerClients = std::vector<ServiceWorkerClientInfo>; +using ClientsCallback = base::Callback<void(ServiceWorkerClients* clients)>; // Opens a new window and navigates it to |url|. |callback| is called with the // window's client information on completion. @@ -42,8 +47,14 @@ const base::WeakPtr<ServiceWorkerContextCore>& context, const NavigationCallback& callback); -} // namespace service_worker_client_navigation_utils +// Collects clients matched with |options|. |callback| is called with the client +// information sorted in MRU order (most recently focused order) on completion. +void GetClients(const base::WeakPtr<ServiceWorkerVersion>& controller, + const ServiceWorkerClientQueryOptions& options, + const ClientsCallback& callback); + +} // namespace service_worker_client_utils } // namespace content -#endif // CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_CLIENT_NAVIGATION_UTILS_H_ +#endif // CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_CLIENT_UTILS_H_
diff --git a/content/browser/service_worker/service_worker_controllee_request_handler.cc b/content/browser/service_worker/service_worker_controllee_request_handler.cc index 85de5313..a656fd869 100644 --- a/content/browser/service_worker/service_worker_controllee_request_handler.cc +++ b/content/browser/service_worker/service_worker_controllee_request_handler.cc
@@ -4,6 +4,8 @@ #include "content/browser/service_worker/service_worker_controllee_request_handler.h" +#include <string> + #include "base/memory/scoped_ptr.h" #include "base/trace_event/trace_event.h" #include "content/browser/service_worker/service_worker_context_core.h" @@ -244,6 +246,12 @@ return; } + // A registration exists, so associate it. Note that the controller is only + // set if there's an active version. If there's no active version, we should + // still associate so the provider host can use .ready. + provider_host_->AssociateRegistration(registration.get(), + false /* notify_controllerchange */); + if (!active_version.get() || active_version->status() != ServiceWorkerVersion::ACTIVATED) { job_->FallbackToNetwork(); @@ -259,8 +267,6 @@ ServiceWorkerMetrics::CountControlledPageLoad(stripped_url_); - provider_host_->AssociateRegistration(registration.get(), - false /* notify_controllerchange */); job_->ForwardToServiceWorker(); TRACE_EVENT_ASYNC_END2( "ServiceWorker",
diff --git a/content/browser/service_worker/service_worker_controllee_request_handler_unittest.cc b/content/browser/service_worker/service_worker_controllee_request_handler_unittest.cc index b2d87945..bf79f74 100644 --- a/content/browser/service_worker/service_worker_controllee_request_handler_unittest.cc +++ b/content/browser/service_worker/service_worker_controllee_request_handler_unittest.cc
@@ -5,7 +5,9 @@ #include "content/browser/service_worker/service_worker_controllee_request_handler.h" #include <utility> +#include <vector> +#include "base/callback_helpers.h" #include "base/files/scoped_temp_dir.h" #include "base/logging.h" #include "base/run_loop.h" @@ -15,7 +17,6 @@ #include "content/browser/service_worker/service_worker_context_core.h" #include "content/browser/service_worker/service_worker_provider_host.h" #include "content/browser/service_worker/service_worker_registration.h" -#include "content/browser/service_worker/service_worker_registration.h" #include "content/browser/service_worker/service_worker_url_request_job.h" #include "content/common/resource_request_body.h" #include "content/common/service_worker/service_worker_utils.h" @@ -35,8 +36,6 @@ int kMockProviderId = 1; -void EmptyCallback() {} - } class ServiceWorkerControlleeRequestHandlerTest : public testing::Test { @@ -67,7 +66,7 @@ provider_host_ = host->AsWeakPtr(); context()->AddProviderHost(std::move(host)); - context()->storage()->LazyInitialize(base::Bind(&EmptyCallback)); + context()->storage()->LazyInitialize(base::Bind(&base::DoNothing)); base::RunLoop().RunUntilIdle(); } @@ -192,6 +191,39 @@ EXPECT_TRUE(version_->update_timer_.IsRunning()); } +// Test that an installing registration is associated with a provider host. +TEST_F(ServiceWorkerControlleeRequestHandlerTest, InstallingRegistration) { + // Create an installing registration. + version_->SetStatus(ServiceWorkerVersion::INSTALLING); + registration_->SetInstallingVersion(version_); + context()->storage()->NotifyInstallingRegistration(registration_.get()); + + // Conduct a main resource load. + const GURL kDocUrl("http://host/scope/doc"); + scoped_ptr<net::URLRequest> request = url_request_context_.CreateRequest( + kDocUrl, net::DEFAULT_PRIORITY, &url_request_delegate_); + scoped_ptr<ServiceWorkerControlleeRequestHandler> handler( + new ServiceWorkerControlleeRequestHandler( + context()->AsWeakPtr(), provider_host_, + base::WeakPtr<storage::BlobStorageContext>(), + FETCH_REQUEST_MODE_NO_CORS, FETCH_CREDENTIALS_MODE_OMIT, + FetchRedirectMode::FOLLOW_MODE, RESOURCE_TYPE_MAIN_FRAME, + REQUEST_CONTEXT_TYPE_HYPERLINK, REQUEST_CONTEXT_FRAME_TYPE_TOP_LEVEL, + scoped_refptr<ResourceRequestBody>())); + scoped_ptr<net::URLRequestJob> job( + handler->MaybeCreateJob(request.get(), nullptr, &mock_resource_context_)); + base::RunLoop().RunUntilIdle(); + + // The handler should have fallen back to network and destroyed the job. The + // registration should be associated with the provider host, although it is + // not controlled since there is no active version. + EXPECT_FALSE(job); + EXPECT_EQ(registration_.get(), provider_host_->associated_registration()); + EXPECT_EQ(version_.get(), provider_host_->installing_version()); + EXPECT_FALSE(version_->HasControllee()); + EXPECT_FALSE(provider_host_->controlling_version()); +} + // Test to not regress crbug/414118. TEST_F(ServiceWorkerControlleeRequestHandlerTest, DeletedProviderHost) { // Store a registration so the call to FindRegistrationForDocument will read
diff --git a/content/browser/service_worker/service_worker_database.cc b/content/browser/service_worker/service_worker_database.cc index cf6e941..6a602ae 100644 --- a/content/browser/service_worker/service_worker_database.cc +++ b/content/browser/service_worker/service_worker_database.cc
@@ -272,26 +272,6 @@ return ServiceWorkerDatabase::STATUS_OK; } -ServiceWorkerDatabase::Status ParseDatabaseVersion( - const std::string& serialized, - int64_t* out) { - DCHECK(out); - const int kFirstValidVersion = 1; - int64_t version; - if (!base::StringToInt64(serialized, &version) || - version < kFirstValidVersion) { - return ServiceWorkerDatabase::STATUS_ERROR_CORRUPTED; - } - if (kCurrentSchemaVersion < version) { - DLOG(ERROR) << "ServiceWorkerDatabase has newer schema version" - << " than the current latest version: " - << version << " vs " << kCurrentSchemaVersion; - return ServiceWorkerDatabase::STATUS_ERROR_CORRUPTED; - } - *out = version; - return ServiceWorkerDatabase::STATUS_OK; -} - ServiceWorkerDatabase::Status ParseRegistrationData( const std::string& serialized, ServiceWorkerDatabase::RegistrationData* out) { @@ -1197,25 +1177,27 @@ status = ReadDatabaseVersion(&db_version); if (status != STATUS_OK) return status; - DCHECK_LE(0, db_version); - if (db_version > 0 && db_version < kCurrentSchemaVersion) { - switch (db_version) { - case 1: - status = UpgradeDatabaseSchemaFromV1ToV2(); - if (status != STATUS_OK) - return status; - db_version = 2; - // Intentionally fall-through to other version upgrade cases. - } - // Either the database got upgraded to the current schema version, or some - // upgrade step failed which would have caused this method to abort. - DCHECK_EQ(db_version, kCurrentSchemaVersion); + switch (db_version) { + case 0: + // This database is new. It will be initialized when something is written. + DCHECK_EQ(UNINITIALIZED, state_); + return STATUS_OK; + case 1: + // This database has an obsolete schema version. ServiceWorkerStorage + // should recreate it. + status = STATUS_ERROR_FAILED; + Disable(FROM_HERE, status); + return status; + case 2: + DCHECK_EQ(db_version, kCurrentSchemaVersion); + state_ = INITIALIZED; + return STATUS_OK; + default: + // Other cases should be handled in ReadDatabaseVersion. + NOTREACHED(); + return STATUS_ERROR_CORRUPTED; } - - if (db_version > 0) - state_ = INITIALIZED; - return STATUS_OK; } bool ServiceWorkerDatabase::IsNewOrNonexistentDatabase( @@ -1227,52 +1209,6 @@ return false; } -ServiceWorkerDatabase::Status -ServiceWorkerDatabase::UpgradeDatabaseSchemaFromV1ToV2() { - Status status = STATUS_OK; - leveldb::WriteBatch batch; - - // Version 2 introduced REGID_TO_ORIGIN, add for all existing registrations. - scoped_ptr<leveldb::Iterator> itr(db_->NewIterator(leveldb::ReadOptions())); - for (itr->Seek(kRegKeyPrefix); itr->Valid(); itr->Next()) { - status = LevelDBStatusToStatus(itr->status()); - if (status != STATUS_OK) { - HandleReadResult(FROM_HERE, status); - return status; - } - - std::string key; - if (!RemovePrefix(itr->key().ToString(), kRegKeyPrefix, &key)) - break; - - std::vector<std::string> parts = - base::SplitString(key, std::string(1, kKeySeparator), - base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL); - if (parts.size() != 2) { - status = STATUS_ERROR_CORRUPTED; - HandleReadResult(FROM_HERE, status); - return status; - } - - int64_t registration_id; - status = ParseId(parts[1], ®istration_id); - if (status != STATUS_OK) { - HandleReadResult(FROM_HERE, status); - return status; - } - - batch.Put(CreateRegistrationIdToOriginKey(registration_id), parts[0]); - } - - // Update schema version manually instead of relying on WriteBatch to make - // sure each upgrade step only updates it to the actually correct version. - batch.Put(kDatabaseVersionKey, base::Int64ToString(2)); - status = LevelDBStatusToStatus( - db_->Write(leveldb::WriteOptions(), &batch)); - HandleWriteResult(FROM_HERE, status); - return status; -} - ServiceWorkerDatabase::Status ServiceWorkerDatabase::ReadNextAvailableId( const char* id_key, int64_t* next_avail_id) { @@ -1521,7 +1457,15 @@ return status; } - status = ParseDatabaseVersion(value, db_version); + const int kFirstValidVersion = 1; + if (!base::StringToInt64(value, db_version) || + *db_version < kFirstValidVersion || kCurrentSchemaVersion < *db_version) { + status = STATUS_ERROR_CORRUPTED; + HandleReadResult(FROM_HERE, status); + return status; + } + + status = STATUS_OK; HandleReadResult(FROM_HERE, status); return status; }
diff --git a/content/browser/service_worker/service_worker_database.h b/content/browser/service_worker/service_worker_database.h index e43bcd2..2372abf 100644 --- a/content/browser/service_worker/service_worker_database.h +++ b/content/browser/service_worker/service_worker_database.h
@@ -248,10 +248,6 @@ // the database is new or nonexistent, that is, it has never been used. bool IsNewOrNonexistentDatabase(Status status); - // Upgrades the database schema from version 1 to version 2. Called by - // LazyOpen() when the stored schema is older than version 2. - Status UpgradeDatabaseSchemaFromV1ToV2(); - // Reads the next available id for |id_key|. Returns OK if it's successfully // read. Fills |next_avail_id| with an initial value and returns OK if it's // not found in the database. Otherwise, returns an error. @@ -351,14 +347,18 @@ FRIEND_TEST_ALL_PREFIXES(ServiceWorkerDatabaseTest, OpenDatabase); FRIEND_TEST_ALL_PREFIXES(ServiceWorkerDatabaseTest, OpenDatabase_InMemory); - FRIEND_TEST_ALL_PREFIXES(ServiceWorkerDatabaseTest, DatabaseVersion); + FRIEND_TEST_ALL_PREFIXES(ServiceWorkerDatabaseTest, + DatabaseVersion_ValidSchemaVersion); + FRIEND_TEST_ALL_PREFIXES(ServiceWorkerDatabaseTest, + DatabaseVersion_ObsoleteSchemaVersion); + FRIEND_TEST_ALL_PREFIXES(ServiceWorkerDatabaseTest, + DatabaseVersion_CorruptedSchemaVersion); FRIEND_TEST_ALL_PREFIXES(ServiceWorkerDatabaseTest, GetNextAvailableIds); FRIEND_TEST_ALL_PREFIXES(ServiceWorkerDatabaseTest, Registration_UninitializedDatabase); FRIEND_TEST_ALL_PREFIXES(ServiceWorkerDatabaseTest, UserData_UninitializedDatabase); FRIEND_TEST_ALL_PREFIXES(ServiceWorkerDatabaseTest, DestroyDatabase); - FRIEND_TEST_ALL_PREFIXES(ServiceWorkerDatabaseTest, UpgradeSchemaToVersion2); DISALLOW_COPY_AND_ASSIGN(ServiceWorkerDatabase); };
diff --git a/content/browser/service_worker/service_worker_database_unittest.cc b/content/browser/service_worker/service_worker_database_unittest.cc index 15521208..818a5fa 100644 --- a/content/browser/service_worker/service_worker_database_unittest.cc +++ b/content/browser/service_worker/service_worker_database_unittest.cc
@@ -115,7 +115,7 @@ database->LazyOpen(false)); } -TEST(ServiceWorkerDatabaseTest, DatabaseVersion) { +TEST(ServiceWorkerDatabaseTest, DatabaseVersion_ValidSchemaVersion) { GURL origin("http://example.com"); scoped_ptr<ServiceWorkerDatabase> database(CreateDatabaseInMemory()); EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, database->LazyOpen(true)); @@ -144,62 +144,83 @@ EXPECT_LT(0, db_version); } -TEST(ServiceWorkerDatabaseTest, UpgradeSchemaToVersion2) { +TEST(ServiceWorkerDatabaseTest, DatabaseVersion_ObsoleteSchemaVersion) { base::ScopedTempDir database_dir; ASSERT_TRUE(database_dir.CreateUniqueTempDir()); scoped_ptr<ServiceWorkerDatabase> database( CreateDatabase(database_dir.path())); + EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, database->LazyOpen(true)); + // First writing triggers database initialization and bumps the schema + // version. GURL origin("http://example.com"); - - // Add a registration to the database. std::vector<ServiceWorkerDatabase::ResourceRecord> resources; + resources.push_back(CreateResource(1, URL(origin, "/resource"), 10)); ServiceWorkerDatabase::RegistrationData deleted_version; std::vector<int64_t> newly_purgeable_resources; ServiceWorkerDatabase::RegistrationData data; - data.registration_id = 100; - data.scope = URL(origin, "/foo"); - data.script = URL(origin, "/script1.js"); - data.version_id = 200; - data.resources_total_size_bytes = 300; - resources.push_back(CreateResource(1, data.script, 300)); + data.resources_total_size_bytes = 10; ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, database->WriteRegistration(data, resources, &deleted_version, &newly_purgeable_resources)); - - // Sanity check on current version. int64_t db_version = -1; + ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, + database->ReadDatabaseVersion(&db_version)); + ASSERT_LT(0, db_version); + + // Emulate an obsolete schema version. + int64_t old_db_version = 1; + leveldb::WriteBatch batch; + batch.Put("INITDATA_DB_VERSION", base::Int64ToString(old_db_version)); + ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, database->WriteBatch(&batch)); + db_version = -1; EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, database->ReadDatabaseVersion(&db_version)); - EXPECT_LE(2, db_version); + ASSERT_EQ(old_db_version, db_version); - // Now delete the data that will be created in an upgrade to schema version 2, - // and reset the schema version to 1. - leveldb::WriteBatch batch; - batch.Delete("REGID_TO_ORIGIN:" + base::Int64ToString(data.registration_id)); - batch.Put("INITDATA_DB_VERSION", base::Int64ToString(1)); - ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, database->WriteBatch(&batch)); - - // Make sure correct data got deleted. - GURL origin_out; - EXPECT_EQ( - ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND, - database->ReadRegistrationOrigin(data.registration_id, &origin_out)); - - // Close and reopen the database to verify the schema got updated. + // Opening the database whose schema version is obsolete should fail. database.reset(CreateDatabase(database_dir.path())); + EXPECT_EQ(ServiceWorkerDatabase::STATUS_ERROR_FAILED, + database->LazyOpen(true)); +} + +TEST(ServiceWorkerDatabaseTest, DatabaseVersion_CorruptedSchemaVersion) { + base::ScopedTempDir database_dir; + ASSERT_TRUE(database_dir.CreateUniqueTempDir()); + scoped_ptr<ServiceWorkerDatabase> database( + CreateDatabase(database_dir.path())); EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, database->LazyOpen(true)); - // Verify version number. - EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, + // First writing triggers database initialization and bumps the schema + // version. + GURL origin("http://example.com"); + std::vector<ServiceWorkerDatabase::ResourceRecord> resources; + resources.push_back(CreateResource(1, URL(origin, "/resource"), 10)); + ServiceWorkerDatabase::RegistrationData deleted_version; + std::vector<int64_t> newly_purgeable_resources; + ServiceWorkerDatabase::RegistrationData data; + data.resources_total_size_bytes = 10; + ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, + database->WriteRegistration(data, resources, &deleted_version, + &newly_purgeable_resources)); + int64_t db_version = -1; + ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, database->ReadDatabaseVersion(&db_version)); - EXPECT_LE(2, db_version); + ASSERT_LT(0, db_version); - // And check that looking up origin for registration works. - EXPECT_EQ( - ServiceWorkerDatabase::STATUS_OK, - database->ReadRegistrationOrigin(data.registration_id, &origin_out)); - EXPECT_EQ(origin, origin_out); + // Emulate a corrupted schema version. + int64_t corrupted_db_version = -10; + leveldb::WriteBatch batch; + batch.Put("INITDATA_DB_VERSION", base::Int64ToString(corrupted_db_version)); + ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, database->WriteBatch(&batch)); + db_version = -1; + EXPECT_EQ(ServiceWorkerDatabase::STATUS_ERROR_CORRUPTED, + database->ReadDatabaseVersion(&db_version)); + + // Opening the database whose schema version is corrupted should fail. + database.reset(CreateDatabase(database_dir.path())); + EXPECT_EQ(ServiceWorkerDatabase::STATUS_ERROR_CORRUPTED, + database->LazyOpen(true)); } TEST(ServiceWorkerDatabaseTest, GetNextAvailableIds) {
diff --git a/content/browser/service_worker/service_worker_info.cc b/content/browser/service_worker/service_worker_info.cc index 7d40512a..836e979 100644 --- a/content/browser/service_worker/service_worker_info.cc +++ b/content/browser/service_worker/service_worker_info.cc
@@ -5,13 +5,15 @@ #include "content/browser/service_worker/service_worker_info.h" #include "content/common/service_worker/service_worker_types.h" +#include "content/public/common/child_process_host.h" #include "ipc/ipc_message.h" namespace content { ServiceWorkerVersionInfo::ClientInfo::ClientInfo() - : ClientInfo(-1, MSG_ROUTING_NONE, SERVICE_WORKER_PROVIDER_UNKNOWN) { -} + : ClientInfo(ChildProcessHost::kInvalidUniqueID, + MSG_ROUTING_NONE, + SERVICE_WORKER_PROVIDER_UNKNOWN) {} ServiceWorkerVersionInfo::ClientInfo::ClientInfo(int process_id, int route_id, @@ -27,10 +29,9 @@ status(ServiceWorkerVersion::NEW), registration_id(kInvalidServiceWorkerRegistrationId), version_id(kInvalidServiceWorkerVersionId), - process_id(-1), - thread_id(-1), - devtools_agent_route_id(MSG_ROUTING_NONE) { -} + process_id(ChildProcessHost::kInvalidUniqueID), + thread_id(kInvalidEmbeddedWorkerThreadId), + devtools_agent_route_id(MSG_ROUTING_NONE) {} ServiceWorkerVersionInfo::ServiceWorkerVersionInfo( ServiceWorkerVersion::RunningStatus running_status,
diff --git a/content/browser/service_worker/service_worker_process_manager.cc b/content/browser/service_worker/service_worker_process_manager.cc index cb1f5891..2300811c 100644 --- a/content/browser/service_worker/service_worker_process_manager.cc +++ b/content/browser/service_worker/service_worker_process_manager.cc
@@ -13,6 +13,7 @@ #include "content/browser/service_worker/service_worker_context_wrapper.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/site_instance.h" +#include "content/public/common/child_process_host.h" #include "url/gurl.h" namespace content { @@ -45,7 +46,7 @@ ServiceWorkerProcessManager::ServiceWorkerProcessManager( BrowserContext* browser_context) : browser_context_(browser_context), - process_id_for_test_(-1), + process_id_for_test_(ChildProcessHost::kInvalidUniqueID), weak_this_factory_(this) { DCHECK_CURRENTLY_ON(BrowserThread::UI); weak_this_ = weak_this_factory_.GetWeakPtr(); @@ -147,7 +148,7 @@ return; } - if (process_id_for_test_ != -1) { + if (process_id_for_test_ != ChildProcessHost::kInvalidUniqueID) { // Let tests specify the returned process ID. Note: We may need to be able // to specify the error code too. BrowserThread::PostTask( @@ -159,7 +160,8 @@ if (IsShutdown()) { BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, - base::Bind(callback, SERVICE_WORKER_ERROR_ABORT, -1, + base::Bind(callback, SERVICE_WORKER_ERROR_ABORT, + ChildProcessHost::kInvalidUniqueID, false /* is_new_process */)); return; } @@ -170,7 +172,7 @@ << embedded_worker_id << " already has a process allocated"; int process_id = FindAvailableProcess(pattern); - if (process_id != -1) { + if (process_id != ChildProcessHost::kInvalidUniqueID) { RenderProcessHost::FromID(process_id)->IncrementWorkerRefCount(); instance_info_.insert( std::make_pair(embedded_worker_id, ProcessInfo(process_id))); @@ -192,7 +194,8 @@ LOG(ERROR) << "Couldn't start a new process!"; BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, - base::Bind(callback, SERVICE_WORKER_ERROR_PROCESS_NOT_FOUND, -1, + base::Bind(callback, SERVICE_WORKER_ERROR_PROCESS_NOT_FOUND, + ChildProcessHost::kInvalidUniqueID, false /* is_new_process */)); return; } @@ -217,7 +220,7 @@ return; } - if (process_id_for_test_ != -1) { + if (process_id_for_test_ != ChildProcessHost::kInvalidUniqueID) { // Unittests don't increment or decrement the worker refcount of a // RenderProcessHost. return; @@ -293,7 +296,7 @@ if (backgrounded_candidate) return backgrounded_candidate->GetID(); - return -1; + return ChildProcessHost::kInvalidUniqueID; } } // namespace content
diff --git a/content/browser/service_worker/service_worker_process_manager.h b/content/browser/service_worker/service_worker_process_manager.h index e39ea80f..443aafb 100644 --- a/content/browser/service_worker/service_worker_process_manager.h +++ b/content/browser/service_worker/service_worker_process_manager.h
@@ -113,8 +113,8 @@ // Returns a process vector sorted by the reference count for the |pattern|. std::vector<int> SortProcessesForPattern(const GURL& pattern) const; - // Returns the id of an available process for this pattern, or -1 if there is - // none. + // Returns the id of an available process for this pattern, or + // ChildProcessHost::kInvalidUniqueID if there is none. int FindAvailableProcess(const GURL& pattern); // These fields are only accessed on the UI thread.
diff --git a/content/browser/service_worker/service_worker_process_manager_unittest.cc b/content/browser/service_worker/service_worker_process_manager_unittest.cc index 622412a..384f996 100644 --- a/content/browser/service_worker/service_worker_process_manager_unittest.cc +++ b/content/browser/service_worker/service_worker_process_manager_unittest.cc
@@ -6,6 +6,7 @@ #include "base/macros.h" #include "base/run_loop.h" #include "content/browser/service_worker/service_worker_process_manager.h" +#include "content/public/common/child_process_host.h" #include "content/public/test/mock_render_process_host.h" #include "content/public/test/test_browser_context.h" #include "content/public/test/test_browser_thread_bundle.h" @@ -240,7 +241,7 @@ // Allocating a process in shutdown should abort. EXPECT_EQ(SERVICE_WORKER_ERROR_ABORT, status); - EXPECT_EQ(-1, process_id); + EXPECT_EQ(ChildProcessHost::kInvalidUniqueID, process_id); EXPECT_FALSE(is_new_process); EXPECT_TRUE(process_manager_->instance_info_.empty()); }
diff --git a/content/browser/service_worker/service_worker_version.cc b/content/browser/service_worker/service_worker_version.cc index 10f9de5..bf4f1f61 100644 --- a/content/browser/service_worker/service_worker_version.cc +++ b/content/browser/service_worker/service_worker_version.cc
@@ -6,7 +6,6 @@ #include <stddef.h> -#include <algorithm> #include <map> #include <string> @@ -28,7 +27,7 @@ #include "content/browser/message_port_service.h" #include "content/browser/service_worker/embedded_worker_instance.h" #include "content/browser/service_worker/embedded_worker_registry.h" -#include "content/browser/service_worker/service_worker_client_navigation_utils.h" +#include "content/browser/service_worker/service_worker_client_utils.h" #include "content/browser/service_worker/service_worker_context_core.h" #include "content/browser/service_worker/service_worker_context_wrapper.h" #include "content/browser/service_worker/service_worker_metrics.h" @@ -52,9 +51,6 @@ namespace content { using StatusCallback = ServiceWorkerVersion::StatusCallback; -using ServiceWorkerClients = std::vector<ServiceWorkerClientInfo>; -using GetClientsCallback = - base::Callback<void(scoped_ptr<ServiceWorkerClients>)>; namespace { @@ -199,67 +195,6 @@ return base::TimeTicks().Now() - time; } -void OnGetWindowClientsFromUI( - // The tuple contains process_id, frame_id, client_uuid. - const std::vector<base::Tuple<int, int, std::string>>& clients_info, - const GURL& script_url, - const GetClientsCallback& callback) { - scoped_ptr<ServiceWorkerClients> clients(new ServiceWorkerClients); - - for (const auto& it : clients_info) { - ServiceWorkerClientInfo info = - ServiceWorkerProviderHost::GetWindowClientInfoOnUI(base::get<0>(it), - base::get<1>(it)); - - // If the request to the provider_host returned an empty - // ServiceWorkerClientInfo, that means that it wasn't possible to associate - // it with a valid RenderFrameHost. It might be because the frame was killed - // or navigated in between. - if (info.IsEmpty()) - continue; - - // We can get info for a frame that was navigating end ended up with a - // different URL than expected. In such case, we should make sure to not - // expose cross-origin WindowClient. - if (info.url.GetOrigin() != script_url.GetOrigin()) - continue; - - info.client_uuid = base::get<2>(it); - clients->push_back(info); - } - - BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, - base::Bind(callback, base::Passed(&clients))); -} - -void AddWindowClient( - ServiceWorkerProviderHost* host, - std::vector<base::Tuple<int, int, std::string>>* client_info) { - if (host->client_type() != blink::WebServiceWorkerClientTypeWindow) - return; - client_info->push_back(base::MakeTuple(host->process_id(), host->frame_id(), - host->client_uuid())); -} - -void AddNonWindowClient(ServiceWorkerProviderHost* host, - const ServiceWorkerClientQueryOptions& options, - ServiceWorkerClients* clients) { - blink::WebServiceWorkerClientType host_client_type = host->client_type(); - if (host_client_type == blink::WebServiceWorkerClientTypeWindow) - return; - if (options.client_type != blink::WebServiceWorkerClientTypeAll && - options.client_type != host_client_type) - return; - - ServiceWorkerClientInfo client_info(blink::WebPageVisibilityStateHidden, - false, // is_focused - host->document_url(), - REQUEST_CONTEXT_FRAME_TYPE_NONE, - base::TimeTicks(), host_client_type); - client_info.client_uuid = host->client_uuid(); - clients->push_back(client_info); -} - bool IsInstalled(ServiceWorkerVersion::Status status) { switch (status) { case ServiceWorkerVersion::NEW: @@ -275,13 +210,6 @@ return false; } -struct ServiceWorkerClientInfoSortMRU { - bool operator()(const ServiceWorkerClientInfo& a, - const ServiceWorkerClientInfo& b) const { - return a.last_focus_time > b.last_focus_time; - } -}; - } // namespace const int ServiceWorkerVersion::kTimeoutTimerDelaySeconds = 30; @@ -1185,22 +1113,10 @@ "ServiceWorker", "ServiceWorkerVersion::OnGetClients", request_id, "client_type", options.client_type, "include_uncontrolled", options.include_uncontrolled); - - ServiceWorkerClients clients; - if (controllee_map_.empty() && !options.include_uncontrolled) { - OnGetClientsFinished(request_id, &clients); - return; - } - - // For Window clients we want to query the info on the UI thread first. - if (options.client_type == blink::WebServiceWorkerClientTypeWindow || - options.client_type == blink::WebServiceWorkerClientTypeAll) { - GetWindowClients(request_id, options); - return; - } - - GetNonWindowClients(request_id, options, &clients); - OnGetClientsFinished(request_id, &clients); + service_worker_client_utils::GetClients( + weak_factory_.GetWeakPtr(), options, + base::Bind(&ServiceWorkerVersion::OnGetClientsFinished, + weak_factory_.GetWeakPtr(), request_id)); } void ServiceWorkerVersion::OnGetClientsFinished(int request_id, @@ -1214,8 +1130,6 @@ if (running_status() != STARTING && running_status() != RUNNING) return; - // Sort clients so that the most recently active tab is in the front. - std::sort(clients->begin(), clients->end(), ServiceWorkerClientInfoSortMRU()); embedded_worker_->SendMessage( ServiceWorkerMsg_DidGetClients(request_id, *clients)); } @@ -1431,7 +1345,7 @@ return; } - service_worker_client_navigation_utils::OpenWindow( + service_worker_client_utils::OpenWindow( url, script_url_, embedded_worker_->process_id(), context_, base::Bind(&ServiceWorkerVersion::OnOpenWindowFinished, weak_factory_.GetWeakPtr(), request_id)); @@ -1602,7 +1516,7 @@ return; } - service_worker_client_navigation_utils::NavigateClient( + service_worker_client_utils::NavigateClient( url, script_url_, provider_host->process_id(), provider_host->frame_id(), context_, base::Bind(&ServiceWorkerVersion::OnNavigateClientFinished, weak_factory_.GetWeakPtr(), request_id)); @@ -1769,64 +1683,6 @@ } } -void ServiceWorkerVersion::GetWindowClients( - int request_id, - const ServiceWorkerClientQueryOptions& options) { - DCHECK(options.client_type == blink::WebServiceWorkerClientTypeWindow || - options.client_type == blink::WebServiceWorkerClientTypeAll); - - std::vector<base::Tuple<int, int, std::string>> clients_info; - if (!options.include_uncontrolled) { - for (auto& controllee : controllee_map_) - AddWindowClient(controllee.second, &clients_info); - } else if (context_) { - for (auto it = - context_->GetClientProviderHostIterator(script_url_.GetOrigin()); - !it->IsAtEnd(); it->Advance()) { - AddWindowClient(it->GetProviderHost(), &clients_info); - } - } - - if (clients_info.empty()) { - DidGetWindowClients(request_id, options, - make_scoped_ptr(new ServiceWorkerClients)); - return; - } - - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, - base::Bind(&OnGetWindowClientsFromUI, clients_info, script_url_, - base::Bind(&ServiceWorkerVersion::DidGetWindowClients, - weak_factory_.GetWeakPtr(), request_id, options))); -} - -void ServiceWorkerVersion::DidGetWindowClients( - int request_id, - const ServiceWorkerClientQueryOptions& options, - scoped_ptr<ServiceWorkerClients> clients) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - if (options.client_type == blink::WebServiceWorkerClientTypeAll) - GetNonWindowClients(request_id, options, clients.get()); - OnGetClientsFinished(request_id, clients.get()); -} - -void ServiceWorkerVersion::GetNonWindowClients( - int request_id, - const ServiceWorkerClientQueryOptions& options, - ServiceWorkerClients* clients) { - if (!options.include_uncontrolled) { - for (auto& controllee : controllee_map_) { - AddNonWindowClient(controllee.second, options, clients); - } - } else if (context_) { - for (auto it = - context_->GetClientProviderHostIterator(script_url_.GetOrigin()); - !it->IsAtEnd(); it->Advance()) { - AddNonWindowClient(it->GetProviderHost(), options, clients); - } - } -} - void ServiceWorkerVersion::StartTimeoutTimer() { DCHECK(!timeout_timer_.IsRunning());
diff --git a/content/browser/service_worker/service_worker_version.h b/content/browser/service_worker/service_worker_version.h index 3575f815..5856ed6 100644 --- a/content/browser/service_worker/service_worker_version.h +++ b/content/browser/service_worker/service_worker_version.h
@@ -286,6 +286,11 @@ // Returns if it has controllee. bool HasControllee() const { return !controllee_map_.empty(); } + std::map<std::string, ServiceWorkerProviderHost*> controllee_map() { + return controllee_map_; + } + + base::WeakPtr<ServiceWorkerContextCore> context() const { return context_; } // Adds and removes |request_job| as a dependent job not to stop the // ServiceWorker while |request_job| is reading the stream of the fetch event @@ -521,14 +526,6 @@ void DidSkipWaiting(int request_id); - void GetWindowClients(int request_id, - const ServiceWorkerClientQueryOptions& options); - void DidGetWindowClients(int request_id, - const ServiceWorkerClientQueryOptions& options, - scoped_ptr<ServiceWorkerClients> clients); - void GetNonWindowClients(int request_id, - const ServiceWorkerClientQueryOptions& options, - ServiceWorkerClients* clients); void OnGetClientsFinished(int request_id, ServiceWorkerClients* clients); // The timeout timer periodically calls OnTimeoutTimer, which stops the worker
diff --git a/content/browser/service_worker/service_worker_version_unittest.cc b/content/browser/service_worker/service_worker_version_unittest.cc index 649d563..82f55b6 100644 --- a/content/browser/service_worker/service_worker_version_unittest.cc +++ b/content/browser/service_worker/service_worker_version_unittest.cc
@@ -83,16 +83,26 @@ callback_.Run(SERVICE_WORKER_EVENT_STATUS_ABORTED); } + void set_notify_sync_called(const base::Closure& closure) { + notify_sync_called_ = closure; + } + private: // BackgroundSyncServiceClient overrides void Sync(int64_t handle_id, content::BackgroundSyncEventLastChance last_chance, const SyncCallback& callback) override { EXPECT_TRUE(callback_.is_null()); + + if (!notify_sync_called_.is_null()) { + notify_sync_called_.Run(); + notify_sync_called_.Reset(); + } callback_ = callback; } SyncCallback callback_; + base::Closure notify_sync_called_; mojo::StrongBinding<BackgroundSyncServiceClient> binding_; DISALLOW_COPY_AND_ASSIGN(MockBackgroundSyncServiceClient); @@ -822,14 +832,17 @@ EXPECT_EQ(SERVICE_WORKER_ERROR_TIMEOUT, status); } -// crbug.com/571271 tracks flakiness in MixedRequestTimeouts. -TEST_F(ServiceWorkerWaitForeverInFetchTest, DISABLED_MixedRequestTimeouts) { +TEST_F(ServiceWorkerWaitForeverInFetchTest, MixedRequestTimeouts) { ServiceWorkerStatusCode sync_status = SERVICE_WORKER_ERROR_NETWORK; // dummy value ServiceWorkerStatusCode fetch_status = SERVICE_WORKER_ERROR_NETWORK; // dummy value version_->SetStatus(ServiceWorkerVersion::ACTIVATED); + base::RunLoop run_loop; + mock_background_sync_dispatcher_->set_notify_sync_called( + run_loop.QuitClosure()); + // Create a fetch request that should expire sometime later. version_->DispatchFetchEvent(ServiceWorkerFetchRequest(), base::Bind(&base::DoNothing), @@ -853,6 +866,7 @@ EXPECT_EQ(ServiceWorkerVersion::RUNNING, version_->running_status()); // Gracefully handle the sync event finishing after the timeout. + run_loop.Run(); // Wait until Sync() is called on the mojo client. mock_background_sync_dispatcher_->RunCallback(); base::RunLoop().RunUntilIdle();
diff --git a/content/browser/utility_process_host_impl.cc b/content/browser/utility_process_host_impl.cc index 3b7891f..db67d60 100644 --- a/content/browser/utility_process_host_impl.cc +++ b/content/browser/utility_process_host_impl.cc
@@ -130,7 +130,6 @@ : client_(client), client_task_runner_(client_task_runner), is_batch_mode_(false), - is_mdns_enabled_(false), no_sandbox_(false), run_elevated_(false), #if defined(OS_LINUX) @@ -177,10 +176,6 @@ exposed_dir_ = dir; } -void UtilityProcessHostImpl::EnableMDns() { - is_mdns_enabled_ = true; -} - void UtilityProcessHostImpl::DisableSandbox() { no_sandbox_ = true; } @@ -318,9 +313,6 @@ exposed_dir_); } - if (is_mdns_enabled_) - cmd_line->AppendSwitch(switches::kUtilityProcessEnableMDns); - #if defined(OS_WIN) // Let the utility process know if it is intended to be elevated. if (run_elevated_)
diff --git a/content/browser/utility_process_host_impl.h b/content/browser/utility_process_host_impl.h index ea8572f..94aafa7c 100644 --- a/content/browser/utility_process_host_impl.h +++ b/content/browser/utility_process_host_impl.h
@@ -49,7 +49,6 @@ bool StartBatchMode() override; void EndBatchMode() override; void SetExposedDir(const base::FilePath& dir) override; - void EnableMDns() override; void DisableSandbox() override; #if defined(OS_WIN) void ElevatePrivileges() override; @@ -84,10 +83,6 @@ base::FilePath exposed_dir_; - // Whether the utility process needs to perform presandbox initialization - // for mDNS. - bool is_mdns_enabled_; - // Whether to pass switches::kNoSandbox to the child. bool no_sandbox_;
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc index 88f58a7..150396ef 100644 --- a/content/browser/web_contents/web_contents_impl.cc +++ b/content/browser/web_contents/web_contents_impl.cc
@@ -6,6 +6,7 @@ #include <stddef.h> +#include <cmath> #include <utility> #include "base/command_line.h" @@ -396,6 +397,7 @@ closed_by_user_gesture_(false), minimum_zoom_percent_(static_cast<int>(kMinimumZoomFactor * 100)), maximum_zoom_percent_(static_cast<int>(kMaximumZoomFactor * 100)), + zoom_scroll_remainder_(0), render_view_message_source_(NULL), render_frame_message_source_(NULL), fullscreen_widget_routing_id_(MSG_ROUTING_NONE), @@ -771,6 +773,12 @@ return focused_node->current_frame_host(); } +RenderFrameHostImpl* WebContentsImpl::FindFrameByFrameTreeNodeId( + int frame_tree_node_id) { + FrameTreeNode* frame = frame_tree_.FindByID(frame_tree_node_id); + return frame ? frame->current_frame_host() : nullptr; +} + void WebContentsImpl::ForEachFrame( const base::Callback<void(RenderFrameHost*)>& on_frame) { frame_tree_.ForEach(base::Bind(&ForEachFrameInternal, on_frame)); @@ -1587,7 +1595,14 @@ if (delegate_ && event.wheelTicksY && (event.modifiers & blink::WebInputEvent::ControlKey) && !event.canScroll) { - delegate_->ContentsZoomChange(event.wheelTicksY > 0); + // Count only integer cumulative scrolls as zoom events; this handles + // smooth scroll and regular scroll device behavior. + zoom_scroll_remainder_ += event.wheelTicksY; + int whole_zoom_scroll_remainder_ = std::lround(zoom_scroll_remainder_); + zoom_scroll_remainder_ -= whole_zoom_scroll_remainder_; + if (whole_zoom_scroll_remainder_ != 0) { + delegate_->ContentsZoomChange(whole_zoom_scroll_remainder_ > 0); + } return true; } #endif
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h index ceb900e..a247d03 100644 --- a/content/browser/web_contents/web_contents_impl.h +++ b/content/browser/web_contents/web_contents_impl.h
@@ -240,6 +240,8 @@ RenderProcessHost* GetRenderProcessHost() const override; RenderFrameHostImpl* GetMainFrame() override; RenderFrameHostImpl* GetFocusedFrame() override; + RenderFrameHostImpl* FindFrameByFrameTreeNodeId( + int frame_tree_node_id) override; void ForEachFrame( const base::Callback<void(RenderFrameHost*)>& on_frame) override; void SendToAllFrames(IPC::Message* message) override; @@ -1180,6 +1182,9 @@ int minimum_zoom_percent_; int maximum_zoom_percent_; + // Used to correctly handle integer zooming through a smooth scroll device. + float zoom_scroll_remainder_; + // The intrinsic size of the page. gfx::Size preferred_size_;
diff --git a/content/browser/web_contents/web_contents_view_aura.cc b/content/browser/web_contents/web_contents_view_aura.cc index 41ef84f..a899bf3 100644 --- a/content/browser/web_contents/web_contents_view_aura.cc +++ b/content/browser/web_contents/web_contents_view_aura.cc
@@ -1192,20 +1192,14 @@ if (!web_contents_->GetDelegate()) return; - switch (event->type()) { - case ui::ET_MOUSE_PRESSED: + ui::EventType type = event->type(); + if (type == ui::ET_MOUSE_PRESSED) web_contents_->GetDelegate()->ActivateContents(web_contents_); - break; - case ui::ET_MOUSE_MOVED: - case ui::ET_MOUSE_EXITED: - web_contents_->GetDelegate()->ContentsMouseEvent( - web_contents_, - gfx::Screen::GetScreenFor(GetNativeView())->GetCursorScreenPoint(), - event->type() == ui::ET_MOUSE_MOVED); - break; - default: - break; - } + + web_contents_->GetDelegate()->ContentsMouseEvent( + web_contents_, + gfx::Screen::GetScreenFor(GetNativeView())->GetCursorScreenPoint(), + type == ui::ET_MOUSE_MOVED, type == ui::ET_MOUSE_EXITED); } ////////////////////////////////////////////////////////////////////////////////
diff --git a/content/browser/web_contents/web_contents_view_mac.mm b/content/browser/web_contents/web_contents_view_mac.mm index 33d5ae30..9556dde5 100644 --- a/content/browser/web_contents/web_contents_view_mac.mm +++ b/content/browser/web_contents/web_contents_view_mac.mm
@@ -465,12 +465,9 @@ WebContentsImpl* webContents = [self webContents]; if (webContents && webContents->GetDelegate()) { NSPoint location = [NSEvent mouseLocation]; - if ([theEvent type] == NSMouseMoved) - webContents->GetDelegate()->ContentsMouseEvent( - webContents, gfx::Point(location.x, location.y), true); - if ([theEvent type] == NSMouseExited) - webContents->GetDelegate()->ContentsMouseEvent( - webContents, gfx::Point(location.x, location.y), false); + webContents->GetDelegate()->ContentsMouseEvent( + webContents, gfx::Point(location.x, location.y), + [theEvent type] == NSMouseMoved, [theEvent type] == NSMouseExited); } }
diff --git a/content/browser/webui/web_ui_data_source_impl.cc b/content/browser/webui/web_ui_data_source_impl.cc index 9c93731..9a02600 100644 --- a/content/browser/webui/web_ui_data_source_impl.cc +++ b/content/browser/webui/web_ui_data_source_impl.cc
@@ -74,11 +74,6 @@ bool ShouldDenyXFrameOptions() const override { return parent_->deny_xframe_options_; } - void WillServiceRequest(const net::URLRequest* request, - std::string* path) const override { - // We want to remove any query strings from the path. - *path = path->substr(0, path->find_first_of('?')); - } private: WebUIDataSourceImpl* parent_; @@ -191,19 +186,22 @@ } std::string WebUIDataSourceImpl::GetMimeType(const std::string& path) const { - if (base::EndsWith(path, ".css", base::CompareCase::INSENSITIVE_ASCII)) + // Remove the query string for to determine the mime type. + std::string file_path = path.substr(0, path.find_first_of('?')); + + if (base::EndsWith(file_path, ".css", base::CompareCase::INSENSITIVE_ASCII)) return "text/css"; - if (base::EndsWith(path, ".js", base::CompareCase::INSENSITIVE_ASCII)) + if (base::EndsWith(file_path, ".js", base::CompareCase::INSENSITIVE_ASCII)) return "application/javascript"; - if (base::EndsWith(path, ".json", base::CompareCase::INSENSITIVE_ASCII)) + if (base::EndsWith(file_path, ".json", base::CompareCase::INSENSITIVE_ASCII)) return "application/json"; - if (base::EndsWith(path, ".pdf", base::CompareCase::INSENSITIVE_ASCII)) + if (base::EndsWith(file_path, ".pdf", base::CompareCase::INSENSITIVE_ASCII)) return "application/pdf"; - if (base::EndsWith(path, ".svg", base::CompareCase::INSENSITIVE_ASCII)) + if (base::EndsWith(file_path, ".svg", base::CompareCase::INSENSITIVE_ASCII)) return "image/svg+xml"; return "text/html"; @@ -226,7 +224,9 @@ int resource_id = default_resource_; std::map<std::string, int>::iterator result; - result = path_to_idr_map_.find(path); + // Remove the query string for named resource lookups. + std::string file_path = path.substr(0, path.find_first_of('?')); + result = path_to_idr_map_.find(file_path); if (result != path_to_idr_map_.end()) resource_id = result->second; DCHECK_NE(resource_id, -1);
diff --git a/content/browser/webui/web_ui_data_source_unittest.cc b/content/browser/webui/web_ui_data_source_unittest.cc index e43c866..5e49ec09 100644 --- a/content/browser/webui/web_ui_data_source_unittest.cc +++ b/content/browser/webui/web_ui_data_source_unittest.cc
@@ -20,7 +20,7 @@ const char kDummyString[] = "foo"; const char kDummyDefaultResource[] = "<html>foo</html>"; -const char kDummytResource[] = "<html>blah</html>"; +const char kDummyResource[] = "<html>blah</html>"; class TestClient : public TestContentClient { public: @@ -41,8 +41,8 @@ bytes = new base::RefCountedStaticMemory( kDummyDefaultResource, arraysize(kDummyDefaultResource)); } else if (resource_id == kDummyResourceId) { - bytes = new base::RefCountedStaticMemory( - kDummytResource, arraysize(kDummytResource)); + bytes = new base::RefCountedStaticMemory(kDummyResource, + arraysize(kDummyResource)); } return bytes; } @@ -68,7 +68,15 @@ return source_->GetMimeType(path); } + bool HandleRequest(const std::string& path, + const WebUIDataSourceImpl::GotDataCallback&) { + request_path_ = path; + return true; + } + + protected: scoped_refptr<base::RefCountedMemory> result_data_; + std::string request_path_; private: void SetUp() override { @@ -110,7 +118,7 @@ TEST_F(WebUIDataSourceTest, DefaultResource) { source()->SetDefaultResource(kDummyDefaultResourceId); - StartDataRequest("foobar" ); + StartDataRequest("foobar"); std::string result(result_data_->front_as<char>(), result_data_->size()); EXPECT_NE(result.find(kDummyDefaultResource), std::string::npos); StartDataRequest("strings.js"); @@ -123,12 +131,32 @@ source()->AddResourcePath("foobar", kDummyResourceId); StartDataRequest("foobar"); std::string result(result_data_->front_as<char>(), result_data_->size()); - EXPECT_NE(result.find(kDummytResource), std::string::npos); + EXPECT_NE(result.find(kDummyResource), std::string::npos); StartDataRequest("strings.js"); result = std::string(result_data_->front_as<char>(), result_data_->size()); EXPECT_NE(result.find(kDummyDefaultResource), std::string::npos); } +TEST_F(WebUIDataSourceTest, NamedResourceWithQueryString) { + source()->SetDefaultResource(kDummyDefaultResourceId); + source()->AddResourcePath("foobar", kDummyResourceId); + StartDataRequest("foobar?query?string"); + std::string result(result_data_->front_as<char>(), result_data_->size()); + EXPECT_NE(result.find(kDummyResource), std::string::npos); +} + +TEST_F(WebUIDataSourceTest, RequestFilterQueryString) { + request_path_ = std::string(); + source()->SetRequestFilter( + base::Bind(&WebUIDataSourceTest::HandleRequest, base::Unretained(this))); + source()->SetDefaultResource(kDummyDefaultResourceId); + source()->AddResourcePath("foobar", kDummyResourceId); + StartDataRequest("foobar?query?string"); + // Check that the query string is passed to the request filter (and not + // trimmed). + EXPECT_EQ("foobar?query?string", request_path_); +} + TEST_F(WebUIDataSourceTest, MimeType) { const char* css = "text/css"; const char* html = "text/html"; @@ -144,16 +172,12 @@ EXPECT_EQ(GetMimeType("foocss"), html); EXPECT_EQ(GetMimeType("foo.css"), css); EXPECT_EQ(GetMimeType(".css.foo"), html); -} -TEST_F(WebUIDataSourceTest, QueryStringRemoval) { - std::string path = "path.js?query_string"; - source()->source()->WillServiceRequest(nullptr, &path); - EXPECT_EQ("path.js", path); - - path = "path.js?query_string?query_string2"; - source()->source()->WillServiceRequest(nullptr, &path); - EXPECT_EQ("path.js", path); + // With query strings. + EXPECT_EQ(GetMimeType("foo?abc?abc"), html); + EXPECT_EQ(GetMimeType("foo.html?abc?abc"), html); + EXPECT_EQ(GetMimeType("foo.css?abc?abc"), css); + EXPECT_EQ(GetMimeType("foo.js?abc?abc"), js); } } // namespace content
diff --git a/content/browser/zygote_host/zygote_host_impl_linux.cc b/content/browser/zygote_host/zygote_host_impl_linux.cc index 9c68a3fd..f439e06 100644 --- a/content/browser/zygote_host/zygote_host_impl_linux.cc +++ b/content/browser/zygote_host/zygote_host_impl_linux.cc
@@ -161,8 +161,7 @@ // or namespace sandbox. This is needed beacuse the processes are // non-dumpable, so /proc/pid/oom_score_adj can only be written by root. use_suid_sandbox_for_adj_oom_score_ = - !sandbox_binary_.empty() && - (using_namespace_sandbox || using_suid_sandbox); + !sandbox_binary_.empty() && using_suid_sandbox; // Start up the sandbox host process and get the file descriptor for the // renderers to talk to it.
diff --git a/content/child/child_io_surface_manager_mac.cc b/content/child/child_io_surface_manager_mac.cc deleted file mode 100644 index e766c1c..0000000 --- a/content/child/child_io_surface_manager_mac.cc +++ /dev/null
@@ -1,150 +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 "content/child/child_io_surface_manager_mac.h" - -#include "base/mac/mach_logging.h" -#include "content/common/mac/io_surface_manager_messages.h" - -namespace content { - -// static -ChildIOSurfaceManager* ChildIOSurfaceManager::GetInstance() { - return base::Singleton< - ChildIOSurfaceManager, - base::LeakySingletonTraits<ChildIOSurfaceManager>>::get(); -} - -bool ChildIOSurfaceManager::RegisterIOSurface(gfx::IOSurfaceId io_surface_id, - int client_id, - IOSurfaceRef io_surface) { - DCHECK(service_port_.is_valid()); - CHECK(!token_.IsZero()); - - mach_port_t reply_port; - kern_return_t kr = mach_port_allocate(mach_task_self(), - MACH_PORT_RIGHT_RECEIVE, &reply_port); - if (kr != KERN_SUCCESS) { - MACH_LOG(ERROR, kr) << "mach_port_allocate"; - return false; - } - base::mac::ScopedMachReceiveRight scoped_receive_right(reply_port); - - // Deallocate the right after sending a copy to the parent. - base::mac::ScopedMachSendRight scoped_io_surface_right( - IOSurfaceCreateMachPort(io_surface)); - - union { - IOSurfaceManagerHostMsg_RegisterIOSurface request; - struct { - IOSurfaceManagerMsg_RegisterIOSurfaceReply msg; - mach_msg_trailer_t trailer; - } reply; - } data = {{{0}}}; - data.request.header.msgh_bits = - MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND_ONCE) | - MACH_MSGH_BITS_COMPLEX; - data.request.header.msgh_remote_port = service_port_.get(); - data.request.header.msgh_local_port = reply_port; - data.request.header.msgh_size = sizeof(data.request); - data.request.header.msgh_id = IOSurfaceManagerHostMsg_RegisterIOSurface::ID; - data.request.body.msgh_descriptor_count = 1; - data.request.io_surface_port.name = scoped_io_surface_right.get(); - data.request.io_surface_port.disposition = MACH_MSG_TYPE_COPY_SEND; - data.request.io_surface_port.type = MACH_MSG_PORT_DESCRIPTOR; - data.request.io_surface_id = io_surface_id.id; - data.request.client_id = client_id; - memcpy(data.request.token_name, token_.name, sizeof(token_.name)); - - kr = mach_msg(&data.request.header, MACH_SEND_MSG | MACH_RCV_MSG, - sizeof(data.request), sizeof(data.reply), reply_port, - MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); - if (kr != KERN_SUCCESS) { - MACH_LOG(ERROR, kr) << "mach_msg"; - return false; - } - - return data.reply.msg.result; -} - -void ChildIOSurfaceManager::UnregisterIOSurface(gfx::IOSurfaceId io_surface_id, - int client_id) { - DCHECK(service_port_.is_valid()); - CHECK(!token_.IsZero()); - - IOSurfaceManagerHostMsg_UnregisterIOSurface request = {{0}}; - request.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0); - request.header.msgh_remote_port = service_port_.get(); - request.header.msgh_local_port = MACH_PORT_NULL; - request.header.msgh_size = sizeof(request); - request.header.msgh_id = IOSurfaceManagerHostMsg_UnregisterIOSurface::ID; - request.io_surface_id = io_surface_id.id; - request.client_id = client_id; - memcpy(request.token_name, token_.name, sizeof(token_.name)); - - kern_return_t kr = - mach_msg(&request.header, MACH_SEND_MSG, sizeof(request), 0, - MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); - if (kr != KERN_SUCCESS) { - MACH_LOG(ERROR, kr) << "mach_msg"; - } -} - -IOSurfaceRef ChildIOSurfaceManager::AcquireIOSurface( - gfx::IOSurfaceId io_surface_id) { - DCHECK(service_port_.is_valid()); - CHECK(!token_.IsZero()); - - mach_port_t reply_port; - kern_return_t kr = mach_port_allocate(mach_task_self(), - MACH_PORT_RIGHT_RECEIVE, &reply_port); - CHECK_EQ(KERN_SUCCESS, kr); - base::mac::ScopedMachReceiveRight scoped_receive_right(reply_port); - - union { - IOSurfaceManagerHostMsg_AcquireIOSurface request; - struct { - IOSurfaceManagerMsg_AcquireIOSurfaceReply msg; - mach_msg_trailer_t trailer; - } reply; - } data = {{{0}}}; - data.request.header.msgh_bits = - MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND_ONCE); - data.request.header.msgh_remote_port = service_port_.get(); - data.request.header.msgh_local_port = reply_port; - data.request.header.msgh_size = sizeof(data.request); - data.request.header.msgh_id = IOSurfaceManagerHostMsg_AcquireIOSurface::ID; - data.request.io_surface_id = io_surface_id.id; - memcpy(data.request.token_name, token_.name, sizeof(token_.name)); - - kr = mach_msg(&data.request.header, MACH_SEND_MSG | MACH_RCV_MSG, - sizeof(data.request), sizeof(data.reply), reply_port, - MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); - if (kr != KERN_SUCCESS) { - MACH_LOG(ERROR, kr) << "mach_msg"; - return nullptr; - } - if (!data.reply.msg.result) { - DLOG(ERROR) << "Browser refused AcquireIOSurface request"; - return nullptr; - } - - // Deallocate the right after creating an IOSurface reference. - base::mac::ScopedMachSendRight scoped_io_surface_right( - data.reply.msg.io_surface_port.name); - - // If a port was successfully received, it should be valid, and opening it - // should not fail. - CHECK(scoped_io_surface_right.is_valid()); - IOSurfaceRef io_surface = IOSurfaceLookupFromMachPort( - scoped_io_surface_right.get()); - CHECK(io_surface); - return io_surface; -} - -ChildIOSurfaceManager::ChildIOSurfaceManager() {} - -ChildIOSurfaceManager::~ChildIOSurfaceManager() {} - -} // namespace content
diff --git a/content/child/child_io_surface_manager_mac.h b/content/child/child_io_surface_manager_mac.h deleted file mode 100644 index 6c849fb2..0000000 --- a/content/child/child_io_surface_manager_mac.h +++ /dev/null
@@ -1,63 +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 CONTENT_CHILD_CHILD_IO_SURFACE_MANAGER_MAC_H_ -#define CONTENT_CHILD_CHILD_IO_SURFACE_MANAGER_MAC_H_ - -#include "base/mac/scoped_mach_port.h" -#include "base/macros.h" -#include "base/memory/singleton.h" -#include "content/common/content_export.h" -#include "content/common/mac/io_surface_manager_token.h" -#include "ui/gfx/mac/io_surface_manager.h" - -namespace content { - -// Implementation of IOSurfaceManager that registers and acquires IOSurfaces -// through a Mach service. -class CONTENT_EXPORT ChildIOSurfaceManager : public gfx::IOSurfaceManager { - public: - // Returns the global ChildIOSurfaceManager. - static ChildIOSurfaceManager* GetInstance(); - - // Overridden from IOSurfaceManager: - bool RegisterIOSurface(gfx::IOSurfaceId io_surface_id, - int client_id, - IOSurfaceRef io_surface) override; - void UnregisterIOSurface(gfx::IOSurfaceId io_surface_id, - int client_id) override; - IOSurfaceRef AcquireIOSurface(gfx::IOSurfaceId io_surface_id) override; - - // Set the service Mach port. Ownership of |service_port| is passed to the - // manager. - // Note: This can be called on any thread but must happen before the - // thread-safe IOSurfaceManager interface is used. It is the responsibility - // of users of this class to ensure there are no races. - void set_service_port(mach_port_t service_port) { - service_port_.reset(service_port); - } - - // Set the token used when communicating with the Mach service. - // Note: This can be called on any thread but must happen before the - // thread-safe IOSurfaceManager interface is used. It is the responsibility - // of users of this class to ensure there are no races. - void set_token(const IOSurfaceManagerToken& token) { - token_ = token; - } - - private: - friend struct base::DefaultSingletonTraits<ChildIOSurfaceManager>; - - ChildIOSurfaceManager(); - ~ChildIOSurfaceManager() override; - - base::mac::ScopedMachSendRight service_port_; - IOSurfaceManagerToken token_; - - DISALLOW_COPY_AND_ASSIGN(ChildIOSurfaceManager); -}; - -} // namespace content - -#endif // CONTENT_CHILD_CHILD_IO_SURFACE_MANAGER_MAC_H_
diff --git a/content/child/child_thread_impl.cc b/content/child/child_thread_impl.cc index 3c6d869..d9b02b2 100644 --- a/content/child/child_thread_impl.cc +++ b/content/child/child_thread_impl.cc
@@ -70,10 +70,6 @@ #include "third_party/tcmalloc/chromium/src/gperftools/heap-profiler.h" #endif -#if defined(OS_MACOSX) -#include "content/child/child_io_surface_manager_mac.h" -#endif - #if defined(USE_OZONE) #include "ui/ozone/public/client_native_pixmap_factory.h" #endif @@ -179,29 +175,6 @@ #endif // OS(POSIX) -#if defined(OS_MACOSX) -class IOSurfaceManagerFilter : public IPC::MessageFilter { - public: - // Overridden from IPC::MessageFilter: - bool OnMessageReceived(const IPC::Message& message) override { - bool handled = true; - IPC_BEGIN_MESSAGE_MAP(IOSurfaceManagerFilter, message) - IPC_MESSAGE_HANDLER(ChildProcessMsg_SetIOSurfaceManagerToken, - OnSetIOSurfaceManagerToken) - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP() - return handled; - } - - protected: - ~IOSurfaceManagerFilter() override {} - - void OnSetIOSurfaceManagerToken(const IOSurfaceManagerToken& token) { - ChildIOSurfaceManager::GetInstance()->set_token(token); - } -}; -#endif - #if defined(USE_OZONE) class ClientNativePixmapFactoryFilter : public IPC::MessageFilter { public: @@ -481,10 +454,6 @@ channel_->AddFilter(new SuicideOnChannelErrorFilter()); #endif -#if defined(OS_MACOSX) - channel_->AddFilter(new IOSurfaceManagerFilter()); -#endif - #if defined(USE_OZONE) channel_->AddFilter(new ClientNativePixmapFactoryFilter()); #endif
diff --git a/content/child/ftp_directory_listing_response_delegate.cc b/content/child/ftp_directory_listing_response_delegate.cc index 26d43c86..5bf21a7 100644 --- a/content/child/ftp_directory_listing_response_delegate.cc +++ b/content/child/ftp_directory_listing_response_delegate.cc
@@ -17,9 +17,9 @@ #include "base/strings/utf_string_conversions.h" #include "base/time/time.h" #include "content/child/weburlresponse_extradata_impl.h" +#include "net/base/directory_listing.h" #include "net/base/escape.h" #include "net/base/net_errors.h" -#include "net/base/net_util.h" #include "net/ftp/ftp_directory_listing_parser.h" #include "third_party/WebKit/public/platform/WebURL.h" #include "third_party/WebKit/public/platform/WebURLLoaderClient.h"
diff --git a/content/child/resource_dispatcher.cc b/content/child/resource_dispatcher.cc index 1e641510..bcb99b9 100644 --- a/content/child/resource_dispatcher.cc +++ b/content/child/resource_dispatcher.cc
@@ -129,12 +129,12 @@ ResourceDispatcher::PendingRequestInfo* ResourceDispatcher::GetPendingRequestInfo(int request_id) { - PendingRequestList::iterator it = pending_requests_.find(request_id); + PendingRequestMap::iterator it = pending_requests_.find(request_id); if (it == pending_requests_.end()) { // This might happen for kill()ed requests on the webkit end. return NULL; } - return &(it->second); + return it->second.get(); } void ResourceDispatcher::OnUploadProgress(int request_id, @@ -338,7 +338,7 @@ request_info->pending_redirect_message.reset( new ResourceHostMsg_FollowRedirect(request_id)); if (!request_info->is_deferred) { - FollowPendingRedirect(request_id, *request_info); + FollowPendingRedirect(request_id, request_info); } } else { Cancel(request_id); @@ -347,8 +347,8 @@ void ResourceDispatcher::FollowPendingRedirect( int request_id, - PendingRequestInfo& request_info) { - IPC::Message* msg = request_info.pending_redirect_message.release(); + PendingRequestInfo* request_info) { + IPC::Message* msg = request_info->pending_redirect_message.release(); if (msg) message_sender_->Send(msg); } @@ -421,15 +421,15 @@ } bool ResourceDispatcher::RemovePendingRequest(int request_id) { - PendingRequestList::iterator it = pending_requests_.find(request_id); + PendingRequestMap::iterator it = pending_requests_.find(request_id); if (it == pending_requests_.end()) return false; - PendingRequestInfo& request_info = it->second; + PendingRequestInfo* request_info = it->second.get(); - bool release_downloaded_file = request_info.download_to_file; + bool release_downloaded_file = request_info->download_to_file; - ReleaseResourcesInMessageQueue(&request_info.deferred_message_queue); + ReleaseResourcesInMessageQueue(&request_info->deferred_message_queue); pending_requests_.erase(it); if (release_downloaded_file) { @@ -444,7 +444,7 @@ } void ResourceDispatcher::Cancel(int request_id) { - PendingRequestList::iterator it = pending_requests_.find(request_id); + PendingRequestMap::iterator it = pending_requests_.find(request_id); if (it == pending_requests_.end()) { DVLOG(1) << "unknown request"; return; @@ -455,7 +455,7 @@ // TODO(csharrison): Remove this code when crbug.com/557430 is resolved. // ~250,000 ERR_ABORTED coming into canary with |request_time| < 100ms. Sample // by .01% to get something reasonable. - PendingRequestInfo& info = it->second; + const PendingRequestInfo& info = *it->second; int64_t request_time = (base::TimeTicks::Now() - info.request_start).InMilliseconds(); if (info.resource_type == ResourceType::RESOURCE_TYPE_MAIN_FRAME && @@ -479,16 +479,16 @@ } void ResourceDispatcher::SetDefersLoading(int request_id, bool value) { - PendingRequestList::iterator it = pending_requests_.find(request_id); + PendingRequestMap::iterator it = pending_requests_.find(request_id); if (it == pending_requests_.end()) { DLOG(ERROR) << "unknown request"; return; } - PendingRequestInfo& request_info = it->second; + PendingRequestInfo* request_info = it->second.get(); if (value) { - request_info.is_deferred = value; - } else if (request_info.is_deferred) { - request_info.is_deferred = false; + request_info->is_deferred = value; + } else if (request_info->is_deferred) { + request_info->is_deferred = false; FollowPendingRedirect(request_id, request_info); @@ -522,16 +522,6 @@ return false; } -ResourceDispatcher::PendingRequestInfo::PendingRequestInfo() - : peer(NULL), - threaded_data_provider(NULL), - resource_type(RESOURCE_TYPE_SUB_RESOURCE), - is_deferred(false), - download_to_file(false), - buffer_size(0), - data_offset(-1) { -} - ResourceDispatcher::PendingRequestInfo::PendingRequestInfo( RequestPeer* peer, ResourceType resource_type, @@ -540,16 +530,13 @@ const GURL& request_url, bool download_to_file) : peer(peer), - threaded_data_provider(NULL), resource_type(resource_type), origin_pid(origin_pid), - is_deferred(false), url(request_url), frame_origin(frame_origin), response_url(request_url), download_to_file(download_to_file), - request_start(base::TimeTicks::Now()), - data_offset(-1) { + request_start(base::TimeTicks::Now()) { } ResourceDispatcher::PendingRequestInfo::~PendingRequestInfo() { @@ -573,16 +560,16 @@ } void ResourceDispatcher::FlushDeferredMessages(int request_id) { - PendingRequestList::iterator it = pending_requests_.find(request_id); + PendingRequestMap::iterator it = pending_requests_.find(request_id); if (it == pending_requests_.end()) // The request could have become invalid. return; - PendingRequestInfo& request_info = it->second; - if (request_info.is_deferred) + PendingRequestInfo* request_info = it->second.get(); + if (request_info->is_deferred) return; // Because message handlers could result in request_info being destroyed, // we need to work with a stack reference to the deferred queue. MessageQueue q; - q.swap(request_info.deferred_message_queue); + q.swap(request_info->deferred_message_queue); while (!q.empty()) { IPC::Message* m = q.front(); q.pop_front(); @@ -592,11 +579,11 @@ // we should honor the same and stop dispatching further messages. // We need to find the request again in the list as it may have completed // by now and the request_info instance above may be invalid. - PendingRequestList::iterator index = pending_requests_.find(request_id); + PendingRequestMap::iterator index = pending_requests_.find(request_id); if (index != pending_requests_.end()) { - PendingRequestInfo& pending_request = index->second; - if (pending_request.is_deferred) { - pending_request.deferred_message_queue.swap(q); + PendingRequestInfo* pending_request = index->second.get(); + if (pending_request->is_deferred) { + pending_request->deferred_message_queue.swap(q); return; } } @@ -643,12 +630,12 @@ // Compute a unique request_id for this renderer process. int request_id = MakeRequestID(); pending_requests_[request_id] = - PendingRequestInfo(peer, + make_scoped_ptr(new PendingRequestInfo(peer, request->resource_type, request->origin_pid, frame_origin, request->url, - request_info.download_to_file); + request_info.download_to_file)); if (resource_scheduling_filter_.get() && request_info.loading_web_task_runner) {
diff --git a/content/child/resource_dispatcher.h b/content/child/resource_dispatcher.h index 5b1d867..8f1946e 100644 --- a/content/child/resource_dispatcher.h +++ b/content/child/resource_dispatcher.h
@@ -10,6 +10,7 @@ #include <stdint.h> #include <deque> +#include <map> #include <string> #include "base/containers/hash_tables.h" @@ -141,8 +142,6 @@ typedef std::deque<IPC::Message*> MessageQueue; struct PendingRequestInfo { - PendingRequestInfo(); - PendingRequestInfo(RequestPeer* peer, ResourceType resource_type, int origin_pid, @@ -153,14 +152,14 @@ ~PendingRequestInfo(); RequestPeer* peer; - ThreadedDataProvider* threaded_data_provider; + ThreadedDataProvider* threaded_data_provider = nullptr; ResourceType resource_type; // The PID of the original process which issued this request. This gets // non-zero only for a request proxied by another renderer, particularly // requests from plugins. int origin_pid; MessageQueue deferred_message_queue; - bool is_deferred; + bool is_deferred = false; // Original requested url. GURL url; // The security origin of the frame that initiates this request. @@ -168,26 +167,26 @@ // The url of the latest response even in case of redirection. GURL response_url; bool download_to_file; - linked_ptr<IPC::Message> pending_redirect_message; + scoped_ptr<IPC::Message> pending_redirect_message; base::TimeTicks request_start; base::TimeTicks response_start; base::TimeTicks completion_time; linked_ptr<base::SharedMemory> buffer; scoped_refptr<SharedMemoryReceivedDataFactory> received_data_factory; - linked_ptr<SiteIsolationResponseMetaData> site_isolation_metadata; + scoped_ptr<SiteIsolationResponseMetaData> site_isolation_metadata; int buffer_size; // Debugging for https://code.google.com/p/chromium/issues/detail?id=527588. - int data_offset; + int data_offset = -1; }; - typedef base::hash_map<int, PendingRequestInfo> PendingRequestList; + using PendingRequestMap = std::map<int, scoped_ptr<PendingRequestInfo>>; // Helper to lookup the info based on the request_id. // May return NULL if the request as been canceled from the client side. PendingRequestInfo* GetPendingRequestInfo(int request_id); // Follows redirect, if any, for the given request. - void FollowPendingRedirect(int request_id, PendingRequestInfo& request_info); + void FollowPendingRedirect(int request_id, PendingRequestInfo* request_info); // Message response handlers, called by the message handler for this process. void OnUploadProgress(int request_id, int64_t position, int64_t size); @@ -252,7 +251,7 @@ IPC::Sender* message_sender_; // All pending requests issued to the host - PendingRequestList pending_requests_; + PendingRequestMap pending_requests_; ResourceDispatcherDelegate* delegate_;
diff --git a/content/child/resource_dispatcher_unittest.cc b/content/child/resource_dispatcher_unittest.cc index 86391a3..aafa029c 100644 --- a/content/child/resource_dispatcher_unittest.cc +++ b/content/child/resource_dispatcher_unittest.cc
@@ -725,8 +725,7 @@ // FIXME } -class TimeConversionTest : public ResourceDispatcherTest, - public RequestPeer { +class TimeConversionTest : public ResourceDispatcherTest { public: bool Send(IPC::Message* msg) override { delete msg; @@ -742,38 +741,6 @@ ResourceMsg_ReceivedResponse(0, response_head)); } - // RequestPeer methods. - void OnUploadProgress(uint64_t position, uint64_t size) override {} - - bool OnReceivedRedirect(const net::RedirectInfo& redirect_info, - const ResourceResponseInfo& info) override { - return true; - } - - void OnReceivedResponse(const ResourceResponseInfo& info) override { - response_info_ = info; - } - - void OnDownloadedData(int len, int encoded_data_length) override {} - - void OnReceivedData(scoped_ptr<ReceivedData> data) override {} - - void OnCompletedRequest(int error_code, - bool was_ignored_by_handler, - bool stale_copy_in_cache, - const std::string& security_info, - const base::TimeTicks& completion_time, - int64_t total_transfer_size) override {} - - void OnReceivedCompletedResponse(const ResourceResponseInfo& info, - scoped_ptr<ReceivedData> data, - int error_code, - bool was_ignored_by_handler, - bool stale_copy_in_cache, - const std::string& security_info, - const base::TimeTicks& completion_time, - int64_t total_transfer_size) override {} - const ResourceResponseInfo& response_info() const { return response_info_; } private:
diff --git a/content/child/site_isolation_stats_gatherer.cc b/content/child/site_isolation_stats_gatherer.cc index 63bd8c6..f38ea385 100644 --- a/content/child/site_isolation_stats_gatherer.cc +++ b/content/child/site_isolation_stats_gatherer.cc
@@ -53,7 +53,7 @@ void HistogramCountBlockedResponse( const std::string& bucket_prefix, - const linked_ptr<SiteIsolationResponseMetaData>& resp_data, + const scoped_ptr<SiteIsolationResponseMetaData>& resp_data, bool nosniff_block) { std::string block_label(nosniff_block ? ".NoSniffBlocked" : ".Blocked"); IncrementHistogramCount(bucket_prefix + block_label); @@ -96,7 +96,7 @@ g_stats_gathering_enabled = enabled; } -linked_ptr<SiteIsolationResponseMetaData> +scoped_ptr<SiteIsolationResponseMetaData> SiteIsolationStatsGatherer::OnReceivedResponse( const GURL& frame_origin, const GURL& response_url, @@ -104,7 +104,7 @@ int origin_pid, const ResourceResponseInfo& info) { if (!g_stats_gathering_enabled) - return linked_ptr<SiteIsolationResponseMetaData>(); + return nullptr; // if |origin_pid| is non-zero, it means that this response is for a plugin // spawned from this renderer process. We exclude responses for plugins for @@ -112,26 +112,26 @@ // the browser process so that we don't apply cross-site document blocking to // them. if (origin_pid) - return linked_ptr<SiteIsolationResponseMetaData>(); + return nullptr; UMA_HISTOGRAM_COUNTS("SiteIsolation.AllResponses", 1); // See if this is for navigation. If it is, don't block it, under the // assumption that we will put it in an appropriate process. if (IsResourceTypeFrame(resource_type)) - return linked_ptr<SiteIsolationResponseMetaData>(); + return nullptr; if (!CrossSiteDocumentClassifier::IsBlockableScheme(response_url)) - return linked_ptr<SiteIsolationResponseMetaData>(); + return nullptr; if (CrossSiteDocumentClassifier::IsSameSite(frame_origin, response_url)) - return linked_ptr<SiteIsolationResponseMetaData>(); + return nullptr; CrossSiteDocumentMimeType canonical_mime_type = CrossSiteDocumentClassifier::GetCanonicalMimeType(info.mime_type); if (canonical_mime_type == CROSS_SITE_DOCUMENT_MIME_TYPE_OTHERS) - return linked_ptr<SiteIsolationResponseMetaData>(); + return nullptr; // Every CORS request should have the Access-Control-Allow-Origin header even // if it is preceded by a pre-flight request. Therefore, if this is a CORS @@ -144,13 +144,13 @@ &access_control_origin); if (CrossSiteDocumentClassifier::IsValidCorsHeaderSet( frame_origin, response_url, access_control_origin)) - return linked_ptr<SiteIsolationResponseMetaData>(); + return nullptr; // Real XSD data collection starts from here. std::string no_sniff; info.headers->EnumerateHeader(NULL, "x-content-type-options", &no_sniff); - linked_ptr<SiteIsolationResponseMetaData> resp_data( + scoped_ptr<SiteIsolationResponseMetaData> resp_data( new SiteIsolationResponseMetaData); resp_data->frame_origin = frame_origin.spec(); resp_data->response_url = response_url; @@ -163,7 +163,7 @@ } bool SiteIsolationStatsGatherer::OnReceivedFirstChunk( - const linked_ptr<SiteIsolationResponseMetaData>& resp_data, + const scoped_ptr<SiteIsolationResponseMetaData>& resp_data, const char* raw_data, int raw_length) { if (!g_stats_gathering_enabled)
diff --git a/content/child/site_isolation_stats_gatherer.h b/content/child/site_isolation_stats_gatherer.h index 7e792797..4530a16 100644 --- a/content/child/site_isolation_stats_gatherer.h +++ b/content/child/site_isolation_stats_gatherer.h
@@ -9,7 +9,7 @@ #include "base/gtest_prod_util.h" #include "base/macros.h" -#include "base/memory/linked_ptr.h" +#include "base/memory/scoped_ptr.h" #include "base/strings/string_piece.h" #include "content/common/content_export.h" #include "content/common/cross_site_document_classifier.h" @@ -69,7 +69,7 @@ // Returns any bookkeeping data about the HTTP header information for the // request identified by |request_id|. Any data returned should then be // passed to OnReceivedFirstChunk() with the first data chunk. - static linked_ptr<SiteIsolationResponseMetaData> OnReceivedResponse( + static scoped_ptr<SiteIsolationResponseMetaData> OnReceivedResponse( const GURL& frame_origin, const GURL& response_url, ResourceType resource_type, @@ -81,7 +81,7 @@ // kinds of UMA data stats. This function is called only if the length of // received data is non-zero. static bool OnReceivedFirstChunk( - const linked_ptr<SiteIsolationResponseMetaData>& resp_data, + const scoped_ptr<SiteIsolationResponseMetaData>& resp_data, const char* payload, int length);
diff --git a/content/child/web_url_loader_impl.cc b/content/child/web_url_loader_impl.cc index 9eedbf7c..5da4d60a 100644 --- a/content/child/web_url_loader_impl.cc +++ b/content/child/web_url_loader_impl.cc
@@ -768,9 +768,9 @@ } WebURLLoaderImpl::Context::~Context() { - if (request_id_ >= 0) { - resource_dispatcher_->RemovePendingRequest(request_id_); - } + // We must be already cancelled at this point. + // TODO(kinuko): Replace this with DCHECK once we make sure this is safe. + CHECK_LT(request_id_, 0); } void WebURLLoaderImpl::Context::CancelBodyStreaming() {
diff --git a/content/common/child_process_messages.h b/content/common/child_process_messages.h index 7516ec8..b4ee49f 100644 --- a/content/common/child_process_messages.h +++ b/content/common/child_process_messages.h
@@ -23,10 +23,6 @@ #include "ui/gfx/gpu_memory_buffer.h" #include "ui/gfx/ipc/gfx_param_traits.h" -#if defined(OS_MACOSX) -#include "content/common/mac/io_surface_manager_token.h" -#endif - IPC_ENUM_TRAITS_MAX_VALUE(tracked_objects::ThreadData::Status, tracked_objects::ThreadData::STATUS_LAST) @@ -77,6 +73,8 @@ IPC_STRUCT_TRAITS_MEMBER(stride) #if defined(USE_OZONE) IPC_STRUCT_TRAITS_MEMBER(native_pixmap_handle) +#elif defined(OS_MACOSX) + IPC_STRUCT_TRAITS_MEMBER(mach_port) #endif IPC_STRUCT_TRAITS_END() @@ -124,13 +122,6 @@ IPC_MESSAGE_CONTROL1(ChildProcessMsg_SetProcessBackgrounded, bool /* background */) -#if defined(OS_MACOSX) -// Sent to child processes to tell them what token to use when registering -// and/or acquiring IOSurfaces. -IPC_MESSAGE_CONTROL1(ChildProcessMsg_SetIOSurfaceManagerToken, - content::IOSurfaceManagerToken /* token */) -#endif - // Sends a pipe used by the child process to broker passing of Mojo handles. IPC_MESSAGE_CONTROL1(ChildProcessMsg_SetMojoParentPipeHandle, IPC::PlatformFileForTransit /* handle */)
diff --git a/content/common/cursors/webcursor_aura.cc b/content/common/cursors/webcursor_aura.cc index 3486870..8595ee9 100644 --- a/content/common/cursors/webcursor_aura.cc +++ b/content/common/cursors/webcursor_aura.cc
@@ -120,7 +120,8 @@ void WebCursor::CreateScaledBitmapAndHotspotFromCustomData( SkBitmap* bitmap, gfx::Point* hotspot) { - DCHECK(custom_data_.size() > 0); + if (custom_data_.size() <= 0) + return; *hotspot = hotspot_; bitmap->allocN32Pixels(custom_size_.width(), custom_size_.height()); memcpy(bitmap->getAddr32(0, 0), custom_data_.data(), custom_data_.size());
diff --git a/content/common/experiments/api_key.cc b/content/common/experiments/api_key.cc new file mode 100644 index 0000000..09b607f5 --- /dev/null +++ b/content/common/experiments/api_key.cc
@@ -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. + +#include "content/common/experiments/api_key.h" + +#include <vector> + +#include "base/base64.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/string_split.h" +#include "base/strings/string_util.h" +#include "base/strings/utf_string_conversions.h" +#include "base/time/time.h" +#include "url/origin.h" + +namespace content { + +namespace { + +const char* kApiKeyFieldSeparator = "|"; +} + +ApiKey::~ApiKey() {} + +scoped_ptr<ApiKey> ApiKey::Parse(const std::string& key_text) { + if (key_text.empty()) { + return nullptr; + } + + // API Key should resemble: + // signature|origin|api_name|expiry_timestamp + std::vector<std::string> parts = + SplitString(key_text, kApiKeyFieldSeparator, base::KEEP_WHITESPACE, + base::SPLIT_WANT_ALL); + if (parts.size() != 4) { + return nullptr; + } + + const std::string& signature = parts[0]; + const std::string& origin_string = parts[1]; + const std::string& api_name = parts[2]; + const std::string& expiry_string = parts[3]; + + uint64_t expiry_timestamp; + if (!base::StringToUint64(expiry_string, &expiry_timestamp)) { + return nullptr; + } + + // Ensure that the origin is a valid (non-unique) origin URL + GURL origin_url(origin_string); + if (url::Origin(origin_url).unique()) { + return nullptr; + } + + // signed data is (origin + "|" + api_name + "|" + expiry). + std::string data = key_text.substr(signature.length() + 1); + + return make_scoped_ptr( + new ApiKey(signature, data, origin_url, api_name, expiry_timestamp)); +} + +ApiKey::ApiKey(const std::string& signature, + const std::string& data, + const GURL& origin, + const std::string& api_name, + uint64_t expiry_timestamp) + : signature_(signature), + data_(data), + origin_(origin), + api_name_(api_name), + expiry_timestamp_(expiry_timestamp) {} + +bool ApiKey::IsAppropriate(const std::string& origin, + const std::string& api_name) const { + return ValidateOrigin(origin) && ValidateApiName(api_name); +} + +bool ApiKey::IsValid(const base::Time& now) const { + // TODO(iclelland): Validate signature on key data here as well. + // https://crbug.com/543215 + return ValidateDate(now); +} + +bool ApiKey::ValidateOrigin(const std::string& origin) const { + return GURL(origin) == origin_; +} + +bool ApiKey::ValidateApiName(const std::string& api_name) const { + return base::EqualsCaseInsensitiveASCII(api_name, api_name_); +} + +bool ApiKey::ValidateDate(const base::Time& now) const { + base::Time expiry_time = base::Time::FromDoubleT((double)expiry_timestamp_); + return expiry_time > now; +} + +} // namespace content
diff --git a/content/common/experiments/api_key.h b/content/common/experiments/api_key.h new file mode 100644 index 0000000..6b06ea2 --- /dev/null +++ b/content/common/experiments/api_key.h
@@ -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. + +#ifndef CONTENT_COMMON_EXPERIMENTS_API_KEY_H_ +#define CONTENT_COMMON_EXPERIMENTS_API_KEY_H_ + +#include <string> + +#include "base/memory/scoped_ptr.h" +#include "base/time/time.h" +#include "content/common/content_export.h" +#include "url/gurl.h" + +namespace content { + +// The Experimental Framework (EF) provides limited access to experimental APIs, +// on a per-origin basis. This class defines the API key data structure, used +// to securely provide access to an experimental API. +// +// Experimental APIs are defined by string names, provided by the implementers. +// The EF code does not maintain an enum or constant list for experiment names. +// Instead, the EF validates the name provided by the API implementation against +// any provided API keys. +// +// More documentation on the key format can be found at +// https://docs.google.com/document/d/1v5fi0EUV_QHckVHVF2K4P72iNywnrJtNhNZ6i2NPt0M + +class CONTENT_EXPORT ApiKey { + public: + ~ApiKey(); + + // Returns a key object if the string represents a well-formed key, or + // nullptr otherwise. (This does not mean that the key is valid, just that it + // can be parsed.) + static scoped_ptr<ApiKey> Parse(const std::string& key_text); + + // Returns true if this API is appropriate for use by the given origin, for + // the given API name. This does not check whether the signature is valid, or + // whether the key itself has expired. + bool IsAppropriate(const std::string& origin, + const std::string& apiName) const; + + // Returns true if this API key has a valid signature, and has not expired. + bool IsValid(const base::Time& now) const; + + std::string signature() { return signature_; } + std::string data() { return data_; } + GURL origin() { return origin_; } + std::string api_name() { return api_name_; } + uint64_t expiry_timestamp() { return expiry_timestamp_; } + + protected: + friend class ApiKeyTest; + + bool ValidateOrigin(const std::string& origin) const; + bool ValidateApiName(const std::string& api_name) const; + bool ValidateDate(const base::Time& now) const; + + private: + ApiKey(const std::string& signature, + const std::string& data, + const GURL& origin, + const std::string& api_name, + uint64_t expiry_timestamp); + + // The base64-encoded-signature portion of the key. For the key to be valid, + // this must be a valid signature for the data portion of the key, as verified + // by the public key in api_key.cc. + std::string signature_; + + // The portion of the key string which is signed, and whose signature is + // contained in the signature_ member. + std::string data_; + + // The origin for which this key is valid. Must be a secure origin. + GURL origin_; + + // The name of the API experiment which this key enables. + std::string api_name_; + + // The time until which this key should be considered valid, in UTC, as + // seconds since the Unix epoch. + uint64_t expiry_timestamp_; +}; + +} // namespace content + +#endif // CONTENT_COMMON_EXPERIMENTS_API_KEY_H_
diff --git a/content/common/experiments/api_key_unittest.cc b/content/common/experiments/api_key_unittest.cc new file mode 100644 index 0000000..697456d --- /dev/null +++ b/content/common/experiments/api_key_unittest.cc
@@ -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. + +#include "content/common/experiments/api_key.h" + +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" +#include "base/strings/string_util.h" +#include "base/test/simple_test_clock.h" +#include "base/time/time.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace content { + +namespace { + +const char* kSampleAPIKey = + "Signature|https://valid.example.com|Frobulate|1458766277"; + +const char* kExpectedAPIKeySignature = "Signature"; +const char* kExpectedAPIKeyData = + "https://valid.example.com|Frobulate|1458766277"; +const char* kExpectedAPIName = "Frobulate"; +const char* kExpectedOrigin = "https://valid.example.com"; +const uint64_t kExpectedExpiry = 1458766277; + +// The key should not be valid for this origin, or for this API. +const char* kInvalidOrigin = "https://invalid.example.com"; +const char* kInsecureOrigin = "http://valid.example.com"; +const char* kInvalidAPIName = "Grokalyze"; + +// The key should be valid if the current time is kValidTimestamp or earlier. +double kValidTimestamp = 1458766276.0; + +// The key should be invalid if the current time is kInvalidTimestamp or later. +double kInvalidTimestamp = 1458766278.0; + +// Various ill-formed API keys. These should all fail to parse. +const char* kInvalidAPIKeys[] = { + // Invalid - only one part + "abcde", + // Not enough parts + "https://valid.example.com|APIName|1458766277", + // Delimiter in API Name + "Signature|https://valid.example.com|API|Name|1458766277", + // Extra string field + "Signature|https://valid.example.com|APIName|1458766277|SomethingElse", + // Extra numeric field + "Signature|https://valid.example.com|APIName|1458766277|1458766277", + // Non-numeric expiry timestamp + "Signature|https://valid.example.com|APIName|abcdefghij", + "Signature|https://valid.example.com|APIName|1458766277x", + // Negative expiry timestamp + "Signature|https://valid.example.com|APIName|-1458766277", + // Origin not a proper origin URL + "Signature|abcdef|APIName|1458766277", + "Signature|data:text/plain,abcdef|APIName|1458766277", + "Signature|javascript:alert(1)|APIName|1458766277"}; +const size_t kNumInvalidAPIKeys = arraysize(kInvalidAPIKeys); + +} // namespace + +class ApiKeyTest : public testing::Test { + protected: + bool ValidateOrigin(ApiKey* api_key, const char* origin) { + return api_key->ValidateOrigin(origin); + } + + bool ValidateApiName(ApiKey* api_key, const char* api_name) { + return api_key->ValidateApiName(api_name); + } + + bool ValidateDate(ApiKey* api_key, const base::Time& now) { + return api_key->ValidateDate(now); + } +}; + +TEST_F(ApiKeyTest, ParseEmptyString) { + scoped_ptr<ApiKey> empty_key = ApiKey::Parse(""); + EXPECT_FALSE(empty_key); +} + +TEST_F(ApiKeyTest, ParseInvalidStrings) { + for (size_t i = 0; i < kNumInvalidAPIKeys; ++i) { + scoped_ptr<ApiKey> empty_key = ApiKey::Parse(kInvalidAPIKeys[i]); + EXPECT_FALSE(empty_key) << "Invalid API Key should not parse: " + << kInvalidAPIKeys[i]; + } +} + +TEST_F(ApiKeyTest, ParseValidKeyString) { + scoped_ptr<ApiKey> key = ApiKey::Parse(kSampleAPIKey); + ASSERT_TRUE(key); + EXPECT_EQ(kExpectedAPIName, key->api_name()); + EXPECT_EQ(kExpectedAPIKeySignature, key->signature()); + EXPECT_EQ(kExpectedAPIKeyData, key->data()); + EXPECT_EQ(GURL(kExpectedOrigin), key->origin()); + EXPECT_EQ(kExpectedExpiry, key->expiry_timestamp()); +} + +TEST_F(ApiKeyTest, ValidateValidKey) { + scoped_ptr<ApiKey> key = ApiKey::Parse(kSampleAPIKey); + ASSERT_TRUE(key); + EXPECT_TRUE(ValidateOrigin(key.get(), kExpectedOrigin)); + EXPECT_FALSE(ValidateOrigin(key.get(), kInvalidOrigin)); + EXPECT_FALSE(ValidateOrigin(key.get(), kInsecureOrigin)); + EXPECT_TRUE(ValidateApiName(key.get(), kExpectedAPIName)); + EXPECT_FALSE(ValidateApiName(key.get(), kInvalidAPIName)); + EXPECT_TRUE( + ValidateDate(key.get(), base::Time::FromDoubleT(kValidTimestamp))); + EXPECT_FALSE( + ValidateDate(key.get(), base::Time::FromDoubleT(kInvalidTimestamp))); +} + +TEST_F(ApiKeyTest, KeyIsAppropriateForOriginAndAPI) { + scoped_ptr<ApiKey> key = ApiKey::Parse(kSampleAPIKey); + ASSERT_TRUE(key); + EXPECT_TRUE(key->IsAppropriate(kExpectedOrigin, kExpectedAPIName)); + EXPECT_TRUE(key->IsAppropriate(kExpectedOrigin, + base::ToUpperASCII(kExpectedAPIName))); + EXPECT_TRUE(key->IsAppropriate(kExpectedOrigin, + base::ToLowerASCII(kExpectedAPIName))); + EXPECT_FALSE(key->IsAppropriate(kInvalidOrigin, kExpectedAPIName)); + EXPECT_FALSE(key->IsAppropriate(kInsecureOrigin, kExpectedAPIName)); + EXPECT_FALSE(key->IsAppropriate(kExpectedOrigin, kInvalidAPIName)); +} + +} // namespace content
diff --git a/content/common/gpu/client/gpu_memory_buffer_impl_io_surface.cc b/content/common/gpu/client/gpu_memory_buffer_impl_io_surface.cc index 9794bbfa..2df9994 100644 --- a/content/common/gpu/client/gpu_memory_buffer_impl_io_surface.cc +++ b/content/common/gpu/client/gpu_memory_buffer_impl_io_surface.cc
@@ -7,7 +7,7 @@ #include "base/logging.h" #include "content/common/gpu/gpu_memory_buffer_factory_io_surface.h" #include "ui/gfx/buffer_format_util.h" -#include "ui/gfx/mac/io_surface_manager.h" +#include "ui/gfx/mac/io_surface.h" namespace content { namespace { @@ -25,8 +25,7 @@ return 0; } -void FreeIOSurfaceForTesting(gfx::GpuMemoryBufferId id) { - gfx::IOSurfaceManager::GetInstance()->UnregisterIOSurface(id, 0); +void NoOp() { } } // namespace @@ -54,7 +53,7 @@ gfx::BufferUsage usage, const DestructionCallback& callback) { base::ScopedCFTypeRef<IOSurfaceRef> io_surface( - gfx::IOSurfaceManager::GetInstance()->AcquireIOSurface(handle.id)); + IOSurfaceLookupFromMachPort(handle.mach_port.get())); if (!io_surface) return nullptr; @@ -78,15 +77,13 @@ gfx::BufferUsage usage, gfx::GpuMemoryBufferHandle* handle) { base::ScopedCFTypeRef<IOSurfaceRef> io_surface( - gfx::IOSurfaceManager::CreateIOSurface(size, format)); + gfx::CreateIOSurface(size, format)); DCHECK(io_surface); gfx::GpuMemoryBufferId kBufferId(1); - bool rv = gfx::IOSurfaceManager::GetInstance()->RegisterIOSurface( - kBufferId, 0, io_surface); - DCHECK(rv); handle->type = gfx::IO_SURFACE_BUFFER; handle->id = kBufferId; - return base::Bind(&FreeIOSurfaceForTesting, kBufferId); + handle->mach_port.reset(IOSurfaceCreateMachPort(io_surface)); + return base::Bind(&NoOp); } bool GpuMemoryBufferImplIOSurface::Map() {
diff --git a/content/common/gpu/gpu_memory_buffer_factory_io_surface.cc b/content/common/gpu/gpu_memory_buffer_factory_io_surface.cc index f8a74d6..49fab37 100644 --- a/content/common/gpu/gpu_memory_buffer_factory_io_surface.cc +++ b/content/common/gpu/gpu_memory_buffer_factory_io_surface.cc
@@ -9,7 +9,7 @@ #include "base/logging.h" #include "content/common/gpu/client/gpu_memory_buffer_impl.h" #include "ui/gfx/buffer_format_util.h" -#include "ui/gfx/mac/io_surface_manager.h" +#include "ui/gfx/mac/io_surface.h" #include "ui/gl/gl_image_io_surface.h" namespace content { @@ -49,15 +49,10 @@ int client_id, gfx::PluginWindowHandle surface_handle) { base::ScopedCFTypeRef<IOSurfaceRef> io_surface( - gfx::IOSurfaceManager::CreateIOSurface(size, format)); + gfx::CreateIOSurface(size, format)); if (!io_surface) return gfx::GpuMemoryBufferHandle(); - if (!gfx::IOSurfaceManager::GetInstance()->RegisterIOSurface(id, client_id, - io_surface)) { - return gfx::GpuMemoryBufferHandle(); - } - { base::AutoLock lock(io_surfaces_lock_); @@ -69,6 +64,7 @@ gfx::GpuMemoryBufferHandle handle; handle.type = gfx::IO_SURFACE_BUFFER; handle.id = id; + handle.mach_port.reset(IOSurfaceCreateMachPort(io_surface)); return handle; } @@ -93,8 +89,6 @@ DCHECK(io_surfaces_.find(key) != io_surfaces_.end()); io_surfaces_.erase(key); } - - gfx::IOSurfaceManager::GetInstance()->UnregisterIOSurface(id, client_id); } gpu::ImageFactory* GpuMemoryBufferFactoryIOSurface::AsImageFactory() {
diff --git a/content/common/gpu/gpu_memory_buffer_factory_io_surface.h b/content/common/gpu/gpu_memory_buffer_factory_io_surface.h index 753e160..d2fd00d 100644 --- a/content/common/gpu/gpu_memory_buffer_factory_io_surface.h +++ b/content/common/gpu/gpu_memory_buffer_factory_io_surface.h
@@ -19,7 +19,7 @@ #include "gpu/command_buffer/service/image_factory.h" #include "ui/gfx/geometry/size.h" #include "ui/gfx/gpu_memory_buffer.h" -#include "ui/gfx/mac/io_surface_manager.h" +#include "ui/gfx/mac/io_surface.h" namespace gl { class GLImage; @@ -67,6 +67,8 @@ typedef std::pair<gfx::IOSurfaceId, int> IOSurfaceMapKey; typedef base::hash_map<IOSurfaceMapKey, base::ScopedCFTypeRef<IOSurfaceRef>> IOSurfaceMap; + // TOOD(reveman): Remove |io_surfaces_| and allow IOSurface backed GMBs to be + // used with any GPU process by passing a mach_port to CreateImageCHROMIUM. IOSurfaceMap io_surfaces_; base::Lock io_surfaces_lock_;
diff --git a/content/common/gpu/gpu_messages.h b/content/common/gpu/gpu_messages.h index 2f84f97ffc..961c33f 100644 --- a/content/common/gpu/gpu_messages.h +++ b/content/common/gpu/gpu_messages.h
@@ -46,6 +46,9 @@ #if defined(OS_ANDROID) #include "content/common/android/surface_texture_peer.h" +#elif defined(OS_MACOSX) +#include "ui/base/cocoa/remote_layer_api.h" +#include "ui/gfx/mac/io_surface.h" #endif #undef IPC_MESSAGE_EXPORT @@ -120,7 +123,9 @@ #if defined(OS_MACOSX) IPC_STRUCT_BEGIN(GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params) IPC_STRUCT_MEMBER(int32_t, surface_id) - IPC_STRUCT_MEMBER(uint64_t, surface_handle) + // Only one of ca_context_id or io_surface may be non-0. + IPC_STRUCT_MEMBER(CAContextID, ca_context_id) + IPC_STRUCT_MEMBER(gfx::ScopedRefCountedIOSurfaceMachPort, io_surface) IPC_STRUCT_MEMBER(int32_t, route_id) IPC_STRUCT_MEMBER(gfx::Size, size) IPC_STRUCT_MEMBER(float, scale_factor)
diff --git a/content/common/gpu/image_transport_surface_overlay_mac.mm b/content/common/gpu/image_transport_surface_overlay_mac.mm index 5a950680..594a6d1 100644 --- a/content/common/gpu/image_transport_surface_overlay_mac.mm +++ b/content/common/gpu/image_transport_surface_overlay_mac.mm
@@ -24,7 +24,6 @@ #include "base/mac/scoped_cftyperef.h" #include "content/common/gpu/gpu_messages.h" #include "ui/accelerated_widget_mac/io_surface_context.h" -#include "ui/accelerated_widget_mac/surface_handle_types.h" #include "ui/base/cocoa/animation_utils.h" #include "ui/base/cocoa/remote_layer_api.h" #include "ui/base/ui_base_switches.h" @@ -465,11 +464,10 @@ // Send acknowledgement to the browser. GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params params; if (use_remote_layer_api_) { - params.surface_handle = - ui::SurfaceHandleFromCAContextID([ca_context_ contextId]); + params.ca_context_id = [ca_context_ contextId]; } else { - params.surface_handle = - ui::SurfaceHandleFromIOSurfaceID(current_root_plane_->io_surface_id); + params.io_surface.reset( + IOSurfaceCreateMachPort(current_root_plane_->io_surface)); } params.size = swap->pixel_size; params.scale_factor = swap->scale_factor;
diff --git a/content/common/gpu/media/android_copying_backing_strategy.cc b/content/common/gpu/media/android_copying_backing_strategy.cc index 325b9de1..9ca413e 100644 --- a/content/common/gpu/media/android_copying_backing_strategy.cc +++ b/content/common/gpu/media/android_copying_backing_strategy.cc
@@ -121,7 +121,7 @@ // instead of using default matrix crbug.com/226218. copier_->DoCopyTextureWithTransform( state_provider_->GetGlDecoder().get(), GL_TEXTURE_EXTERNAL_OES, - surface_texture_id_, picture_buffer_texture_id, + surface_texture_id_, GL_TEXTURE_2D, picture_buffer_texture_id, state_provider_->GetSize().width(), state_provider_->GetSize().height(), false, false, false, kIdentityMatrix); }
diff --git a/content/common/gpu/media/v4l2_video_encode_accelerator.cc b/content/common/gpu/media/v4l2_video_encode_accelerator.cc index f667b18..98f4e48 100644 --- a/content/common/gpu/media/v4l2_video_encode_accelerator.cc +++ b/content/common/gpu/media/v4l2_video_encode_accelerator.cc
@@ -9,6 +9,7 @@ #include <sys/eventfd.h> #include <sys/ioctl.h> #include <sys/mman.h> +#include <utility> #include "base/callback.h" #include "base/command_line.h" @@ -53,7 +54,7 @@ BitstreamBufferRef(int32_t id, scoped_ptr<base::SharedMemory> shm, size_t size) - : id(id), shm(shm.Pass()), size(size) {} + : id(id), shm(std::move(shm)), size(size) {} const int32_t id; const scoped_ptr<base::SharedMemory> shm; const size_t size; @@ -238,7 +239,7 @@ } scoped_ptr<BitstreamBufferRef> buffer_ref( - new BitstreamBufferRef(buffer.id(), shm.Pass(), buffer.size())); + new BitstreamBufferRef(buffer.id(), std::move(shm), buffer.size())); encoder_thread_.message_loop()->PostTask( FROM_HERE, base::Bind(&V4L2VideoEncodeAccelerator::UseOutputBitstreamBufferTask,
diff --git a/content/common/gpu/stream_texture_android.cc b/content/common/gpu/stream_texture_android.cc index 16f7b94..17d841d 100644 --- a/content/common/gpu/stream_texture_android.cc +++ b/content/common/gpu/stream_texture_android.cc
@@ -7,6 +7,7 @@ #include <string.h> #include "base/bind.h" +#include "base/strings/stringize_macros.h" #include "content/common/android/surface_texture_peer.h" #include "content/common/gpu/gpu_channel.h" #include "content/common/gpu/gpu_messages.h" @@ -16,6 +17,8 @@ #include "gpu/command_buffer/service/texture_manager.h" #include "ui/gfx/geometry/size.h" #include "ui/gl/gl_context.h" +#include "ui/gl/gl_helper.h" +#include "ui/gl/scoped_binders.h" #include "ui/gl/scoped_make_current.h" namespace content { @@ -66,6 +69,12 @@ route_id_(route_id), has_listener_(false), texture_id_(texture_id), + framebuffer_(0), + vertex_shader_(0), + fragment_shader_(0), + program_(0), + vertex_buffer_(0), + u_xform_location_(-1), weak_factory_(this) { owner_stub->AddDestructionObserver(this); memset(current_matrix_, 0, sizeof(current_matrix_)); @@ -84,6 +93,23 @@ void StreamTexture::OnWillDestroyStub() { owner_stub_->RemoveDestructionObserver(this); owner_stub_->channel()->RemoveRoute(route_id_); + + if (framebuffer_) { + scoped_ptr<ui::ScopedMakeCurrent> scoped_make_current(MakeStubCurrent()); + + glDeleteProgram(program_); + glDeleteShader(vertex_shader_); + glDeleteShader(fragment_shader_); + glDeleteBuffersARB(1, &vertex_buffer_); + glDeleteFramebuffersEXT(1, &framebuffer_); + program_ = 0; + vertex_shader_ = 0; + fragment_shader_ = 0; + vertex_buffer_ = 0; + framebuffer_ = 0; + u_xform_location_ = -1; + } + owner_stub_ = NULL; // If the owner goes away, there is no need to keep the SurfaceTexture around. @@ -95,7 +121,75 @@ NOTREACHED(); } +scoped_ptr<ui::ScopedMakeCurrent> StreamTexture::MakeStubCurrent() { + scoped_ptr<ui::ScopedMakeCurrent> scoped_make_current; + bool needs_make_current = + !owner_stub_->decoder()->GetGLContext()->IsCurrent(NULL); + // On Android we should not have to perform a real context switch here when + // using virtual contexts. + DCHECK(!needs_make_current || + !owner_stub_->decoder() + ->GetContextGroup() + ->feature_info() + ->workarounds() + .use_virtualized_gl_contexts); + if (needs_make_current) { + scoped_make_current.reset(new ui::ScopedMakeCurrent( + owner_stub_->decoder()->GetGLContext(), owner_stub_->surface())); + } + return scoped_make_current; +} + +void StreamTexture::UpdateTexImage() { + DCHECK(surface_texture_.get()); + DCHECK(owner_stub_); + + if (!has_pending_frame_) return; + + scoped_ptr<ui::ScopedMakeCurrent> scoped_make_current(MakeStubCurrent()); + + surface_texture_->UpdateTexImage(); + + has_valid_frame_ = true; + has_pending_frame_ = false; + + float mtx[16]; + surface_texture_->GetTransformMatrix(mtx); + + if (memcmp(current_matrix_, mtx, sizeof(mtx)) != 0) { + memcpy(current_matrix_, mtx, sizeof(mtx)); + + if (has_listener_) { + GpuStreamTextureMsg_MatrixChanged_Params params; + memcpy(¶ms.m00, mtx, sizeof(mtx)); + owner_stub_->channel()->Send( + new GpuStreamTextureMsg_MatrixChanged(route_id_, params)); + } + } + + if (scoped_make_current.get()) { + // UpdateTexImage() implies glBindTexture(). + // The cmd decoder takes care of restoring the binding for this GLImage as + // far as the current context is concerned, but if we temporarily change + // it, we have to keep the state intact in *that* context also. + const gpu::gles2::ContextState* state = + owner_stub_->decoder()->GetContextState(); + const gpu::gles2::TextureUnit& active_unit = + state->texture_units[state->active_texture_unit]; + glBindTexture(GL_TEXTURE_EXTERNAL_OES, + active_unit.bound_texture_external_oes.get() + ? active_unit.bound_texture_external_oes->service_id() + : 0); + } +} + bool StreamTexture::CopyTexImage(unsigned target) { + if (target == GL_TEXTURE_2D) { + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size_.width(), size_.height(), 0, + GL_RGBA, GL_UNSIGNED_BYTE, nullptr); + return CopyTexSubImage(GL_TEXTURE_2D, gfx::Point(), gfx::Rect(size_)); + } + if (target != GL_TEXTURE_EXTERNAL_OES) return false; @@ -111,39 +205,7 @@ if (static_cast<unsigned>(texture_id) != texture_id_) return false; - if (has_pending_frame_) { - scoped_ptr<ui::ScopedMakeCurrent> scoped_make_current; - bool needs_make_current = - !owner_stub_->decoder()->GetGLContext()->IsCurrent(NULL); - // On Android we should not have to perform a real context switch here when - // using virtual contexts. - DCHECK(!needs_make_current || !owner_stub_->decoder() - ->GetContextGroup() - ->feature_info() - ->workarounds() - .use_virtualized_gl_contexts); - if (needs_make_current) { - scoped_make_current.reset(new ui::ScopedMakeCurrent( - owner_stub_->decoder()->GetGLContext(), owner_stub_->surface())); - } - surface_texture_->UpdateTexImage(); - has_valid_frame_ = true; - has_pending_frame_ = false; - if (scoped_make_current.get()) { - // UpdateTexImage() implies glBindTexture(). - // The cmd decoder takes care of restoring the binding for this GLImage as - // far as the current context is concerned, but if we temporarily change - // it, we have to keep the state intact in *that* context also. - const gpu::gles2::ContextState* state = - owner_stub_->decoder()->GetContextState(); - const gpu::gles2::TextureUnit& active_unit = - state->texture_units[state->active_texture_unit]; - glBindTexture(GL_TEXTURE_EXTERNAL_OES, - active_unit.bound_texture_external_oes.get() - ? active_unit.bound_texture_external_oes->service_id() - : 0); - } - } + UpdateTexImage(); TextureManager* texture_manager = owner_stub_->decoder()->GetContextGroup()->texture_manager(); @@ -157,21 +219,6 @@ gpu::gles2::Texture::UNBOUND); } - if (has_listener_ && has_valid_frame_) { - float mtx[16]; - surface_texture_->GetTransformMatrix(mtx); - - // Only query the matrix once we have bound a valid frame. - if (memcmp(current_matrix_, mtx, sizeof(mtx)) != 0) { - memcpy(current_matrix_, mtx, sizeof(mtx)); - - GpuStreamTextureMsg_MatrixChanged_Params params; - memcpy(¶ms.m00, mtx, sizeof(mtx)); - owner_stub_->channel()->Send( - new GpuStreamTextureMsg_MatrixChanged(route_id_, params)); - } - } - return true; } @@ -231,7 +278,94 @@ bool StreamTexture::CopyTexSubImage(unsigned target, const gfx::Point& offset, const gfx::Rect& rect) { - return false; + if (target != GL_TEXTURE_2D) + return false; + + if (!owner_stub_ || !surface_texture_.get()) + return true; + + if (!offset.IsOrigin()) { + LOG(ERROR) << "Non-origin offset is not supported"; + return false; + } + + if (rect != gfx::Rect(size_)) { + LOG(ERROR) << "Sub-rectangle is not supported"; + return false; + } + + GLint target_texture = 0; + glGetIntegerv(GL_TEXTURE_BINDING_2D, &target_texture); + DCHECK(target_texture); + + UpdateTexImage(); + + if (!framebuffer_) { + glGenFramebuffersEXT(1, &framebuffer_); + + // This vertex shader introduces a y flip before applying the stream + // texture matrix. This is required because the stream texture matrix + // Android provides is intended to be used in a y-up coordinate system, + // whereas Chromium expects y-down. + + // clang-format off + const char kVertexShader[] = STRINGIZE( + attribute vec2 a_position; + varying vec2 v_texCoord; + uniform mat4 u_xform; + void main() { + gl_Position = vec4(a_position.x, a_position.y, 0.0, 1.0); + vec2 uv_untransformed = a_position * vec2(0.5, -0.5) + vec2(0.5, 0.5); + v_texCoord = (u_xform * vec4(uv_untransformed, 0.0, 1.0)).xy; + } + ); + const char kFragmentShader[] = + "#extension GL_OES_EGL_image_external : require\n" STRINGIZE( + precision mediump float; + uniform samplerExternalOES a_texture; + varying vec2 v_texCoord; + void main() { + gl_FragColor = texture2D(a_texture, v_texCoord); + } + ); + // clang-format on + + vertex_buffer_ = gfx::GLHelper::SetupQuadVertexBuffer(); + vertex_shader_ = gfx::GLHelper::LoadShader(GL_VERTEX_SHADER, kVertexShader); + fragment_shader_ = + gfx::GLHelper::LoadShader(GL_FRAGMENT_SHADER, kFragmentShader); + program_ = gfx::GLHelper::SetupProgram(vertex_shader_, fragment_shader_); + gfx::ScopedUseProgram use_program(program_); + int sampler_location = glGetUniformLocation(program_, "a_texture"); + DCHECK_NE(-1, sampler_location); + glUniform1i(sampler_location, 0); + u_xform_location_ = glGetUniformLocation(program_, "u_xform"); + DCHECK_NE(-1, u_xform_location_); + } + + gfx::ScopedActiveTexture active_texture(GL_TEXTURE0); + // UpdateTexImage() call below will bind the surface texture to + // TEXTURE_EXTERNAL_OES. This scoped texture binder will restore the current + // binding before this function returns. + gfx::ScopedTextureBinder texture_binder(GL_TEXTURE_EXTERNAL_OES, texture_id_); + + { + gfx::ScopedFrameBufferBinder framebuffer_binder(framebuffer_); + gfx::ScopedViewport viewport(0, 0, size_.width(), size_.height()); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, target_texture, 0); + DCHECK_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE), + glCheckFramebufferStatusEXT(GL_FRAMEBUFFER)); + gfx::ScopedUseProgram use_program(program_); + + glUniformMatrix4fv(u_xform_location_, 1, false, current_matrix_); + gfx::GLHelper::DrawQuad(vertex_buffer_); + + // Detach the output texture from the fbo. + glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, 0, 0); + } + return true; } bool StreamTexture::ScheduleOverlayPlane(gfx::AcceleratedWidget widget,
diff --git a/content/common/gpu/stream_texture_android.h b/content/common/gpu/stream_texture_android.h index a5afb8eac..e19fc1b 100644 --- a/content/common/gpu/stream_texture_android.h +++ b/content/common/gpu/stream_texture_android.h
@@ -14,6 +14,10 @@ #include "ui/gl/android/surface_texture.h" #include "ui/gl/gl_image.h" +namespace ui { +class ScopedMakeCurrent; +} + namespace gfx { class Size; } @@ -56,6 +60,10 @@ // GpuCommandBufferStub::DestructionObserver implementation. void OnWillDestroyStub() override; + scoped_ptr<ui::ScopedMakeCurrent> MakeStubCurrent(); + + void UpdateTexImage(); + // Called when a new frame is available for the SurfaceTexture. void OnFrameAvailable(); @@ -86,6 +94,13 @@ bool has_listener_; uint32_t texture_id_; + unsigned framebuffer_; + unsigned vertex_shader_; + unsigned fragment_shader_; + unsigned program_; + unsigned vertex_buffer_; + int u_xform_location_; + base::WeakPtrFactory<StreamTexture> weak_factory_; DISALLOW_COPY_AND_ASSIGN(StreamTexture); };
diff --git a/content/common/mac/io_surface_manager_messages.h b/content/common/mac/io_surface_manager_messages.h deleted file mode 100644 index d72d2b32..0000000 --- a/content/common/mac/io_surface_manager_messages.h +++ /dev/null
@@ -1,67 +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 CONTENT_COMMON_MAC_IO_SURFACE_MANAGER_MESSAGES_H_ -#define CONTENT_COMMON_MAC_IO_SURFACE_MANAGER_MESSAGES_H_ - -#include <mach/message.h> - -#include "content/common/mac/io_surface_manager_token.h" - -// Mach messages used for child processes. - -// Message IDs. -// Note: we currently use __LINE__ to give unique IDs to messages. -// They're unique since all messages are defined in this file. -#define MACH_MESSAGE_ID() __LINE__ - -namespace content { - -// Messages sent from the child process to the browser. - -struct IOSurfaceManagerHostMsg_RegisterIOSurface { - enum { ID = MACH_MESSAGE_ID() }; - mach_msg_header_t header; - mach_msg_body_t body; - mach_msg_port_descriptor_t io_surface_port; - IOSurfaceManagerToken::Name token_name; - int io_surface_id; - int client_id; -}; - -struct IOSurfaceManagerHostMsg_UnregisterIOSurface { - enum { ID = MACH_MESSAGE_ID() }; - mach_msg_header_t header; - mach_msg_body_t body; - IOSurfaceManagerToken::Name token_name; - int io_surface_id; - int client_id; -}; - -struct IOSurfaceManagerHostMsg_AcquireIOSurface { - enum { ID = MACH_MESSAGE_ID() }; - mach_msg_header_t header; - mach_msg_body_t body; - IOSurfaceManagerToken::Name token_name; - int io_surface_id; -}; - -// Messages sent from the browser to the child process. - -struct IOSurfaceManagerMsg_RegisterIOSurfaceReply { - mach_msg_header_t header; - mach_msg_body_t body; - boolean_t result; -}; - -struct IOSurfaceManagerMsg_AcquireIOSurfaceReply { - mach_msg_header_t header; - mach_msg_body_t body; - mach_msg_port_descriptor_t io_surface_port; - boolean_t result; -}; - -} // namespace content - -#endif // CONTENT_COMMON_MAC_IO_SURFACE_MANAGER_MESSAGES_H_
diff --git a/content/common/mac/io_surface_manager_token.h b/content/common/mac/io_surface_manager_token.h deleted file mode 100644 index cdaebf65..0000000 --- a/content/common/mac/io_surface_manager_token.h +++ /dev/null
@@ -1,16 +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 CONTENT_COMMON_MAC_IO_SURFACE_MANAGER_TOKEN_H_ -#define CONTENT_COMMON_MAC_IO_SURFACE_MANAGER_TOKEN_H_ - -#include "gpu/command_buffer/common/mailbox.h" - -namespace content { - -using IOSurfaceManagerToken = gpu::Mailbox; - -} // namespace content - -#endif // CONTENT_COMMON_MAC_IO_SURFACE_MANAGER_TOKEN_H_
diff --git a/content/common/sandbox_win.cc b/content/common/sandbox_win.cc index 9833544..937ab23e1 100644 --- a/content/common/sandbox_win.cc +++ b/content/common/sandbox_win.cc
@@ -40,7 +40,10 @@ #include "sandbox/win/src/sandbox_nt_util.h" #include "sandbox/win/src/sandbox_policy_base.h" #include "sandbox/win/src/win_utils.h" -#include "ui/gfx/win/direct_write.h" + +#if !defined(NACL_WIN64) +#include "ui/gfx/win/direct_write.h" // nogncheck: unused #ifdef NACL_WIN64 +#endif // !defined(NACL_WIN64) static sandbox::BrokerServices* g_broker_services = NULL; static sandbox::TargetServices* g_target_services = NULL;
diff --git a/content/common/view_messages.h b/content/common/view_messages.h index 1d0cb0c..5b5e578 100644 --- a/content/common/view_messages.h +++ b/content/common/view_messages.h
@@ -1389,12 +1389,6 @@ GURL /* content_url */, bool /* is_main_frame */) -// This message runs the MediaCodec for decoding audio for webaudio. -IPC_MESSAGE_CONTROL3(ViewHostMsg_RunWebAudioMediaCodec, - base::SharedMemoryHandle /* encoded_data_handle */, - base::FileDescriptor /* pcm_output */, - uint32_t /* data_size*/) - // Reply to the ViewMsg_ExtractSmartClipData message. IPC_MESSAGE_ROUTED3(ViewHostMsg_SmartClipDataExtracted, base::string16 /* text */,
diff --git a/content/content_browser.gypi b/content/content_browser.gypi index 737efe8..30492a6 100644 --- a/content/content_browser.gypi +++ b/content/content_browser.gypi
@@ -445,8 +445,6 @@ 'browser/browser_child_process_host_impl.cc', 'browser/browser_child_process_host_impl.h', 'browser/browser_context.cc', - 'browser/browser_io_surface_manager_mac.cc', - 'browser/browser_io_surface_manager_mac.h', 'browser/browser_ipc_logging.cc', 'browser/browser_main.cc', 'browser/browser_main.h', @@ -851,8 +849,6 @@ 'browser/host_zoom_level_context.h', 'browser/host_zoom_map_impl.cc', 'browser/host_zoom_map_impl.h', - 'browser/in_process_io_surface_manager_mac.cc', - 'browser/in_process_io_surface_manager_mac.h', 'browser/indexed_db/indexed_db.h', 'browser/indexed_db/indexed_db_active_blob_registry.cc', 'browser/indexed_db/indexed_db_active_blob_registry.h', @@ -1340,8 +1336,8 @@ 'browser/service_worker/foreign_fetch_request_handler.h', 'browser/service_worker/service_worker_cache_writer.cc', 'browser/service_worker/service_worker_cache_writer.h', - 'browser/service_worker/service_worker_client_navigation_utils.cc', - 'browser/service_worker/service_worker_client_navigation_utils.h', + 'browser/service_worker/service_worker_client_utils.cc', + 'browser/service_worker/service_worker_client_utils.h', 'browser/service_worker/service_worker_context_core.cc', 'browser/service_worker/service_worker_context_core.h', 'browser/service_worker/service_worker_context_observer.h', @@ -1875,6 +1871,7 @@ '../components/mime_util/mime_util.gyp:mime_util', '../components/scheduler/scheduler.gyp:scheduler_common', '../device/bluetooth/bluetooth.gyp:device_bluetooth', + '../device/usb/usb.gyp:device_usb', '../gin/gin.gyp:gin', '../net/net.gyp:http_server', '../storage/storage_browser.gyp:storage',
diff --git a/content/content_child.gypi b/content/content_child.gypi index 824fddf..bf17bcf9 100644 --- a/content/content_child.gypi +++ b/content/content_child.gypi
@@ -64,8 +64,6 @@ 'child/child_gpu_memory_buffer_manager.h', 'child/child_histogram_message_filter.cc', 'child/child_histogram_message_filter.h', - 'child/child_io_surface_manager_mac.cc', - 'child/child_io_surface_manager_mac.h', 'child/child_message_filter.cc', 'child/child_message_filter.h', 'child/child_process.cc',
diff --git a/content/content_common.gypi b/content/content_common.gypi index d5d97a8f..5509c88 100644 --- a/content/content_common.gypi +++ b/content/content_common.gypi
@@ -253,6 +253,8 @@ 'common/dwrite_font_platform_win.cc', 'common/dwrite_font_proxy_messages.h', 'common/edit_command.h', + 'common/experiments/api_key.cc', + 'common/experiments/api_key.h', 'common/file_utilities_messages.h', 'common/fileapi/file_system_messages.h', 'common/fileapi/webblob_messages.h', @@ -420,8 +422,6 @@ 'common/mac/font_descriptor.mm', 'common/mac/font_loader.h', 'common/mac/font_loader.mm', - 'common/mac/io_surface_manager_messages.h', - 'common/mac/io_surface_manager_token.h', 'common/manifest_manager_messages.h', 'common/media/aec_dump_messages.h', 'common/media/audio_messages.h',
diff --git a/content/content_renderer.gypi b/content/content_renderer.gypi index ba139df..c0f6449 100644 --- a/content/content_renderer.gypi +++ b/content/content_renderer.gypi
@@ -261,8 +261,6 @@ 'renderer/manifest/manifest_uma_util.h', 'renderer/media/aec_dump_message_filter.cc', 'renderer/media/aec_dump_message_filter.h', - 'renderer/media/android/audio_decoder_android.cc', - 'renderer/media/android/audio_decoder_android.h', 'renderer/media/android/media_info_loader.cc', 'renderer/media/android/media_info_loader.h', 'renderer/media/android/media_source_delegate.cc', @@ -811,9 +809,6 @@ ], }], ['OS=="android"', { - 'sources!': [ - 'renderer/media/audio_decoder.cc', - ], 'sources': [ 'renderer/external_popup_menu.cc', 'renderer/external_popup_menu.h',
diff --git a/content/content_tests.gypi b/content/content_tests.gypi index a9a647bd..440056b 100644 --- a/content/content_tests.gypi +++ b/content/content_tests.gypi
@@ -367,7 +367,6 @@ 'browser/blob_storage/blob_async_builder_host_unittest.cc', 'browser/blob_storage/blob_async_transport_strategy_unittest.cc', 'browser/blob_storage/blob_storage_registry_unittest.cc', - 'browser/browser_io_surface_manager_mac_unittest.cc', 'browser/browser_thread_unittest.cc', 'browser/browser_url_handler_impl_unittest.cc', 'browser/byte_stream_unittest.cc', @@ -658,6 +657,7 @@ 'common/discardable_shared_memory_heap_unittest.cc', 'common/dom_storage/dom_storage_map_unittest.cc', 'common/dwrite_font_platform_win_unittest.cc', + 'common/experiments/api_key_unittest.cc', 'common/fileapi/file_system_util_unittest.cc', 'common/font_warmup_win_unittest.cc', 'common/gpu/client/gpu_memory_buffer_impl_shared_memory_unittest.cc', @@ -765,6 +765,7 @@ 'browser/renderer_host/p2p/socket_host_unittest.cc', 'renderer/media/audio_repetition_detector_unittest.cc', 'renderer/media/audio_track_recorder_unittest.cc', + 'renderer/media/canvas_capture_handler_unittest.cc', 'renderer/media/html_video_element_capturer_source_unittest.cc', 'renderer/media/media_recorder_handler_unittest.cc', 'renderer/media/media_stream_audio_processor_unittest.cc', @@ -1283,6 +1284,13 @@ '../third_party/libvpx_new/libvpx.gyp:libvpx_new', ], }], + ['chromecast == 1', { + 'sources!': [ + 'renderer/media/audio_track_recorder_unittest.cc', + 'renderer/media/media_recorder_handler_unittest.cc', + 'renderer/media/video_track_recorder_unittest.cc', + ], + }], # Avoid windows due to non-availability of cursor resources in test. ['OS != "linux"', { 'sources!': [ @@ -1501,6 +1509,7 @@ ], 'dependencies': [ '<(DEPTH)/content/app/strings/content_strings.gyp:content_strings', + '<(DEPTH)/media/media.gyp:media_features', '<(DEPTH)/net/net.gyp:net_resources', '<(DEPTH)/third_party/WebKit/public/blink_resources.gyp:blink_resources', '<(DEPTH)/third_party/iaccessible2/iaccessible2.gyp:iaccessible2',
diff --git a/content/public/android/BUILD.gn b/content/public/android/BUILD.gn index bea70b9e..e726c463 100644 --- a/content/public/android/BUILD.gn +++ b/content/public/android/BUILD.gn
@@ -35,6 +35,7 @@ "//device/battery:mojo_bindings_java", "//device/battery/android:battery_monitor_android", "//device/bluetooth:java", + "//device/usb:java", "//device/vibration:mojo_bindings_java", "//device/vibration/android:vibration_manager_android", "//media/base/android:media_java",
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java b/content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java index de645173..f9800d37 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java +++ b/content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java
@@ -883,6 +883,36 @@ } @SmallTest + @Feature({"TextInput", "Main"}) + public void testNavigateTextWithDpadKeyCodes() throws Throwable { + focusElementAndWaitForStateUpdate("textarea"); + + commitText("hello", 1); + waitAndVerifyStatesAndCalls(0, "hello", 5, 5, -1, -1); + + dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_LEFT)); + dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_LEFT)); + + // Ideally getTextBeforeCursor immediately after dispatchKeyEvent should return a correct + // value, but we have a stop-gap solution in render_widget_input_handler and it make take + // some round trip time until we get the correct value. + // TODO(changwan): Change the test not to wait when we fix it. + waitUntilGetCharacterBeforeCursorBecomes("l"); + } + + private void waitUntilGetCharacterBeforeCursorBecomes(final String expectedText) + throws InterruptedException { + CriteriaHelper.pollForUIThreadCriteria(new Criteria() { + @Override + public boolean isSatisfied() { + String actualText = (String) mConnection.getTextBeforeCursor(1, 0); + updateFailureReason("actualText: " + actualText); + return expectedText.equals(actualText); + } + }); + } + + @SmallTest @Feature({"TextInput"}) public void testPastePopupShowAndHide() throws Throwable { commitText("hello", 1);
diff --git a/content/public/browser/render_frame_host.h b/content/public/browser/render_frame_host.h index a5c04244..4a45df2 100644 --- a/content/public/browser/render_frame_host.h +++ b/content/public/browser/render_frame_host.h
@@ -37,6 +37,16 @@ // Returns nullptr if the IDs do not correspond to a live RenderFrameHost. static RenderFrameHost* FromID(int render_process_id, int render_frame_id); + // Returns the current RenderFrameHost associated with the frame identified by + // the given FrameTreeNode ID, in any WebContents. The frame may change its + // current RenderFrameHost over time, so the returned RenderFrameHost can be + // different from the RenderFrameHost that returned the ID via + // GetFrameTreeNodeId(). See GetFrameTreeNodeId for more details. + // Use WebContents::FindFrameByFrameTreeNodeId to find a RenderFrameHost in + // a specific WebContents. + // Returns nullptr if the frame does not exist. + static RenderFrameHost* FromFrameTreeNodeId(int frame_tree_node_id); + #if defined(OS_ANDROID) // Globally allows for injecting JavaScript into the main world. This feature // is present only to support Android WebView and must not be used in other @@ -68,6 +78,17 @@ // current RenderFrameHost. virtual RenderFrameHost* GetParent() = 0; + // Returns the FrameTreeNode ID for this frame. This ID is browser-global and + // uniquely identifies a frame that hosts content. The identifier is fixed at + // the creation of the frame and stays constant for the lifetime of the frame. + // When the frame is removed, the ID is not used again. + // + // A RenderFrameHost is tied to a process. Due to cross-process navigations, + // the RenderFrameHost may have a shorter lifetime than a frame. Consequently, + // the same FrameTreeNode ID may refer to a different RenderFrameHost after a + // navigation. + virtual int GetFrameTreeNodeId() = 0; + // Returns the assigned name of the frame, the name of the iframe tag // declaring it. For example, <iframe name="framename">[...]</iframe>. It is // quite possible for a frame to have no name, in which case GetFrameName will
diff --git a/content/public/browser/resource_request_info.h b/content/public/browser/resource_request_info.h index e65bce0..d5ee296 100644 --- a/content/public/browser/resource_request_info.h +++ b/content/public/browser/resource_request_info.h
@@ -94,13 +94,9 @@ // True if GetRenderFrameID() represents a main frame in the RenderView. virtual bool IsMainFrame() const = 0; - // True if GetParentRenderFrameID() represents a main frame in the RenderView. + // True if the frame's parent represents a main frame in the RenderView. virtual bool ParentIsMainFrame() const = 0; - // Routing ID of parent frame of frame that sent this resource request. - // -1 if unknown / invalid. - virtual int GetParentRenderFrameID() const = 0; - // Returns the associated resource type. virtual ResourceType GetResourceType() const = 0;
diff --git a/content/public/browser/utility_process_host.h b/content/public/browser/utility_process_host.h index 3e5252f..1a903136 100644 --- a/content/public/browser/utility_process_host.h +++ b/content/public/browser/utility_process_host.h
@@ -61,9 +61,6 @@ // the operation. virtual void SetExposedDir(const base::FilePath& dir) = 0; - // Perform presandbox initialization for mDNS. - virtual void EnableMDns() = 0; - // Make the process run without a sandbox. virtual void DisableSandbox() = 0;
diff --git a/content/public/browser/web_contents.h b/content/public/browser/web_contents.h index 6f68c962..bc13dc9 100644 --- a/content/public/browser/web_contents.h +++ b/content/public/browser/web_contents.h
@@ -214,6 +214,12 @@ // Returns the focused frame for the currently active view. virtual RenderFrameHost* GetFocusedFrame() = 0; + // Returns the current RenderFrameHost for a given FrameTreeNode ID if it is + // part of this tab. See RenderFrameHost::GetFrameTreeNodeId for documentation + // on this ID. + virtual RenderFrameHost* FindFrameByFrameTreeNodeId( + int frame_tree_node_id) = 0; + // Calls |on_frame| for each frame in the currently active view. // Note: The RenderFrameHost parameter is not guaranteed to have a live // RenderFrame counterpart in the renderer process. Callbacks should check
diff --git a/content/public/browser/web_contents_delegate.cc b/content/public/browser/web_contents_delegate.cc index e247f5b..0a1d3f13 100644 --- a/content/public/browser/web_contents_delegate.cc +++ b/content/public/browser/web_contents_delegate.cc
@@ -23,33 +23,7 @@ WebContents* WebContentsDelegate::OpenURLFromTab(WebContents* source, const OpenURLParams& params) { - // This default implementation only handles CURRENT_TAB. - if (params.disposition != CURRENT_TAB) - return nullptr; - - NavigationController::LoadURLParams load_url_params(params.url); - load_url_params.source_site_instance = params.source_site_instance; - load_url_params.transition_type = params.transition; - load_url_params.frame_tree_node_id = params.frame_tree_node_id; - load_url_params.referrer = params.referrer; - load_url_params.redirect_chain = params.redirect_chain; - load_url_params.extra_headers = params.extra_headers; - load_url_params.is_renderer_initiated = params.is_renderer_initiated; - load_url_params.transferred_global_request_id = - params.transferred_global_request_id; - load_url_params.should_replace_current_entry = - params.should_replace_current_entry; - - // Only allows the browser-initiated navigation to use POST. - if (params.uses_post && !params.is_renderer_initiated) { - load_url_params.load_type = - NavigationController::LOAD_TYPE_BROWSER_INITIATED_HTTP_POST; - load_url_params.browser_initiated_post_data = - params.browser_initiated_post_data; - } - - source->GetController().LoadURLWithParams(load_url_params); - return source; + return nullptr; } bool WebContentsDelegate::ShouldTransferNavigation() {
diff --git a/content/public/browser/web_contents_delegate.h b/content/public/browser/web_contents_delegate.h index 6379fe4..ed46e43 100644 --- a/content/public/browser/web_contents_delegate.h +++ b/content/public/browser/web_contents_delegate.h
@@ -152,11 +152,13 @@ const GURL& url) {} // Notification that there was a mouse event, along with the absolute - // coordinates of the mouse pointer and whether it was a normal motion event - // (otherwise, the pointer left the contents area). + // coordinates of the mouse pointer and the type of event. If |motion| is + // true, this is a normal motion event. If |exited| is true, the pointer left + // the contents area. virtual void ContentsMouseEvent(WebContents* source, const gfx::Point& location, - bool motion) {} + bool motion, + bool exited) {} // Request the delegate to change the zoom level of the current tab. virtual void ContentsZoomChange(bool zoom_in) {}
diff --git a/content/public/common/common_param_traits.cc b/content/public/common/common_param_traits.cc index 2764719..f953fa3 100644 --- a/content/public/common/common_param_traits.cc +++ b/content/public/common/common_param_traits.cc
@@ -10,6 +10,7 @@ #include "content/public/common/page_state.h" #include "content/public/common/referrer.h" #include "net/base/host_port_pair.h" +#include "net/base/ip_address.h" #include "net/base/ip_endpoint.h" namespace IPC { @@ -139,6 +140,29 @@ LogParam("IPEndPoint:" + p.ToString(), l); } +void ParamTraits<net::IPAddress>::Write(Message* m, const param_type& p) { + WriteParam(m, p.bytes()); +} + +bool ParamTraits<net::IPAddress>::Read(const Message* m, + base::PickleIterator* iter, + param_type* p) { + std::vector<uint8_t> bytes; + if (!ReadParam(m, iter, &bytes)) + return false; + if (bytes.size() && + bytes.size() != net::IPAddress::kIPv4AddressSize && + bytes.size() != net::IPAddress::kIPv6AddressSize) { + return false; + } + *p = net::IPAddress(bytes); + return true; +} + +void ParamTraits<net::IPAddress>::Log(const param_type& p, std::string* l) { + LogParam("IPAddress:" + (p.empty() ? "(empty)" : p.ToString()), l); +} + void ParamTraits<content::PageState>::Write( Message* m, const param_type& p) { WriteParam(m, p.ToEncodedData());
diff --git a/content/public/common/common_param_traits.h b/content/public/common/common_param_traits.h index bd349c8..e3f5142 100644 --- a/content/public/common/common_param_traits.h +++ b/content/public/common/common_param_traits.h
@@ -38,6 +38,7 @@ namespace net { class HostPortPair; +class IPAddress; class IPEndPoint; } @@ -76,6 +77,14 @@ }; template <> +struct CONTENT_EXPORT ParamTraits<net::IPAddress> { + typedef net::IPAddress param_type; + static void Write(Message* m, const param_type& p); + static bool Read(const Message* m, base::PickleIterator* iter, param_type* p); + static void Log(const param_type& p, std::string* l); +}; + +template <> struct CONTENT_EXPORT ParamTraits<content::PageState> { typedef content::PageState param_type; static void Write(Message* m, const param_type& p);
diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc index 0f97ee2..b7d4010e 100644 --- a/content/public/common/content_switches.cc +++ b/content/public/common/content_switches.cc
@@ -822,6 +822,9 @@ const char kUseNormalPriorityForTileTaskWorkerThreads[] = "use-normal-priority-for-tile-task-worker-threads"; +// Use remote compositor for the renderer. +const char kUseRemoteCompositing[] = "use-remote-compositing"; + // Use the new surfaces system to handle compositor delegation. const char kUseSurfaces[] = "use-surfaces"; @@ -839,9 +842,6 @@ // specifies the directory that can be accessed. const char kUtilityProcessAllowedDir[] = "utility-allowed-dir"; -// Allows MDns to access network in sandboxed process. -const char kUtilityProcessEnableMDns[] = "utility-enable-mdns"; - const char kUtilityProcessRunningElevated[] = "utility-run-elevated"; // In debug builds, asserts that the stream of input events is valid.
diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h index 3c9954f..45297bb 100644 --- a/content/public/common/content_switches.h +++ b/content/public/common/content_switches.h
@@ -231,12 +231,12 @@ CONTENT_EXPORT extern const char kVideoImageTextureTarget[]; CONTENT_EXPORT extern const char kUseMobileUserAgent[]; CONTENT_EXPORT extern const char kUseNormalPriorityForTileTaskWorkerThreads[]; +CONTENT_EXPORT extern const char kUseRemoteCompositing[]; extern const char kUseSurfaces[]; CONTENT_EXPORT extern const char kDisableSurfaces[]; extern const char kUtilityCmdPrefix[]; CONTENT_EXPORT extern const char kUtilityProcess[]; extern const char kUtilityProcessAllowedDir[]; -CONTENT_EXPORT extern const char kUtilityProcessEnableMDns[]; CONTENT_EXPORT extern const char kUtilityProcessRunningElevated[]; CONTENT_EXPORT extern const char kV8CacheOptions[]; CONTENT_EXPORT extern const char kV8NativesPassedByFD[];
diff --git a/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/Criteria.java b/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/Criteria.java index 871441c..55c5f27b 100644 --- a/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/Criteria.java +++ b/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/Criteria.java
@@ -37,7 +37,7 @@ * @return The failure message that will be logged if the criteria is not satisfied within * the specified time range. */ - public final String getFailureReason() { + public String getFailureReason() { return mFailureReason; }
diff --git a/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/CriteriaHelper.java b/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/CriteriaHelper.java index 2b08359..4039835 100644 --- a/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/CriteriaHelper.java +++ b/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/CriteriaHelper.java
@@ -102,6 +102,11 @@ public boolean isSatisfied() { return ThreadUtils.runOnUiThreadBlockingNoException(callable); } + + @Override + public String getFailureReason() { + return criteria.getFailureReason(); + } }, maxTimeoutMs, checkIntervalMs); }
diff --git a/content/public/test/test_renderer_host.cc b/content/public/test/test_renderer_host.cc index 9fe0e953..2535299 100644 --- a/content/public/test/test_renderer_host.cc +++ b/content/public/test/test_renderer_host.cc
@@ -65,7 +65,8 @@ // static bool RenderViewHostTester::TestOnMessageReceived(RenderViewHost* rvh, const IPC::Message& msg) { - return static_cast<RenderViewHostImpl*>(rvh)->OnMessageReceived(msg); + return static_cast<RenderViewHostImpl*>(rvh)->GetWidget()->OnMessageReceived( + msg); } // static
diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn index 3e262d7e..613681d 100644 --- a/content/renderer/BUILD.gn +++ b/content/renderer/BUILD.gn
@@ -24,12 +24,15 @@ defines = [] deps = [ + "//base:i18n", + # TODO(GYP) bug 376846 remove this. This should be inherited from //net but # those don't cross component boundaries. "//base/allocator", "//cc", "//cc/blink", "//cc/proto", + "//cc/surfaces", "//components/scheduler:scheduler", "//components/startup_metric_utils/common", "//components/url_formatter", @@ -41,14 +44,18 @@ "//content/public/common:mojo_bindings", "//crypto:platform", "//device/battery:mojo_bindings", + "//device/bluetooth", + "//device/devices_app/public/cpp", "//device/devices_app/usb/public/interfaces", "//device/vibration:mojo_bindings", "//gin", "//gpu", + "//gpu/blink", "//gpu/command_buffer/client:gles2_interface", "//jingle:jingle_glue", "//media", "//media/blink", + "//media/midi", "//mojo/application/public/interfaces", "//mojo/common:url_type_converters", "//mojo/converters/geometry", @@ -68,6 +75,7 @@ "//third_party/widevine/cdm:version_h", "//ui/accessibility", "//ui/base", + "//ui/base/ime", "//ui/events:dom_keycode_converter", "//ui/events:events_base", "//ui/events/blink", @@ -93,7 +101,6 @@ } if (is_android) { - sources -= [ "media/audio_decoder.cc" ] sources += [ "external_popup_menu.cc", "external_popup_menu.h",
diff --git a/content/renderer/gpu/render_widget_compositor.cc b/content/renderer/gpu/render_widget_compositor.cc index dcb923e..4048e3b 100644 --- a/content/renderer/gpu/render_widget_compositor.cc +++ b/content/renderer/gpu/render_widget_compositor.cc
@@ -375,6 +375,9 @@ &settings.initial_debug_state.slow_down_raster_scale_factor); } + settings.strict_layer_property_change_checking = + cmd->HasSwitch(cc::switches::kStrictLayerPropertyChangeChecking); + #if defined(OS_ANDROID) DCHECK(!SynchronousCompositorFactory::GetInstance() || !cmd->HasSwitch(switches::kIPCSyncCompositing)); @@ -479,6 +482,11 @@ cc::TaskGraphRunner* task_graph_runner = compositor_deps_->GetTaskGraphRunner(); + bool use_remote_compositing = cmd->HasSwitch(switches::kUseRemoteCompositing); + + if (use_remote_compositing) + settings.use_external_begin_frame_source = false; + scoped_ptr<cc::BeginFrameSource> external_begin_frame_source; if (settings.use_external_begin_frame_source) { external_begin_frame_source = @@ -493,7 +501,13 @@ params.task_graph_runner = task_graph_runner; params.main_task_runner = main_thread_compositor_task_runner; params.external_begin_frame_source = std::move(external_begin_frame_source); - if (compositor_thread_task_runner.get()) { + if (use_remote_compositing) { + DCHECK(!compositor_thread_task_runner.get()); + + // TODO(khushalsagar): Replace this with LayerTreeHost::CreateRemote + // See crbug/550687. + layer_tree_host_ = cc::LayerTreeHost::CreateSingleThreaded(this, ¶ms); + } else if (compositor_thread_task_runner.get()) { layer_tree_host_ = cc::LayerTreeHost::CreateThreaded( compositor_thread_task_runner, ¶ms); } else {
diff --git a/content/renderer/input/input_handler_wrapper.cc b/content/renderer/input/input_handler_wrapper.cc index 5995d99b..2300e67 100644 --- a/content/renderer/input/input_handler_wrapper.cc +++ b/content/renderer/input/input_handler_wrapper.cc
@@ -27,8 +27,8 @@ render_view_impl_(render_view_impl) { DCHECK(input_handler); input_handler_proxy_.set_smooth_scroll_enabled( - base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kEnableSmoothScrolling)); + !base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kDisableSmoothScrolling)); } InputHandlerWrapper::~InputHandlerWrapper() {
diff --git a/content/renderer/input/render_widget_input_handler.cc b/content/renderer/input/render_widget_input_handler.cc index 5e358f65..828541c 100644 --- a/content/renderer/input/render_widget_input_handler.cc +++ b/content/renderer/input/render_widget_input_handler.cc
@@ -206,11 +206,30 @@ &event_overscroll); #if defined(OS_ANDROID) - const bool is_keyboard_event = - WebInputEvent::isKeyboardEventType(input_event.type); + bool from_ime = false; - // For non-keyboard events, we want the change source to be FROM_NON_IME. - ImeEventGuard guard(widget_, false, is_keyboard_event); + // For most keyboard events, we want the change source to be FROM_IME because + // we don't need to update IME states in AdapterInputConnection. + if (WebInputEvent::isKeyboardEventType(input_event.type)) { + const WebKeyboardEvent& key_event = + *static_cast<const WebKeyboardEvent*>(&input_event); + // TODO(changwan): this if-condition is a stop-gap solution to update IME + // states in AdapterInputConnection when using DPAD navigation. This is not + // a correct solution because InputConnection#getTextBeforeCursor() + // immediately after InputConnection#sendKeyEvent() will not return the + // correct value. The correct solution is either redesign the architecture + // or emulate the DPAD behavior in AdapterInputConnection, either is + // non-trivial. + if (key_event.nativeKeyCode != AKEYCODE_TAB && + key_event.nativeKeyCode != AKEYCODE_DPAD_CENTER && + key_event.nativeKeyCode != AKEYCODE_DPAD_LEFT && + key_event.nativeKeyCode != AKEYCODE_DPAD_RIGHT && + key_event.nativeKeyCode != AKEYCODE_DPAD_UP && + key_event.nativeKeyCode != AKEYCODE_DPAD_DOWN) + from_ime = true; + } + + ImeEventGuard guard(widget_, false, from_ime); #endif base::TimeTicks start_time;
diff --git a/content/renderer/media/android/audio_decoder_android.cc b/content/renderer/media/android/audio_decoder_android.cc deleted file mode 100644 index 2601fea4..0000000 --- a/content/renderer/media/android/audio_decoder_android.cc +++ /dev/null
@@ -1,596 +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 "content/renderer/media/android/audio_decoder_android.h" - -#include <errno.h> -#include <fcntl.h> -#include <limits.h> -#include <stdint.h> -#include <sys/mman.h> -#include <unistd.h> -#include <vector> - -#include "base/file_descriptor_posix.h" -#include "base/logging.h" -#include "base/macros.h" -#include "base/memory/shared_memory.h" -#include "base/posix/eintr_wrapper.h" -#include "base/process/process_handle.h" -#include "content/common/view_messages.h" -#include "media/base/android/webaudio_media_codec_info.h" -#include "media/base/audio_bus.h" -#include "media/base/limits.h" -#include "third_party/WebKit/public/platform/WebAudioBus.h" - -namespace content { - -class AudioDecoderIO { - public: - AudioDecoderIO(const char* data, size_t data_size); - ~AudioDecoderIO(); - bool ShareEncodedToProcess(base::SharedMemoryHandle* handle); - - // Returns true if AudioDecoderIO was successfully created. - bool IsValid() const; - - int read_fd() const { return read_fd_; } - int write_fd() const { return write_fd_; } - - private: - // Shared memory that will hold the encoded audio data. This is - // used by MediaCodec for decoding. - base::SharedMemory encoded_shared_memory_; - - // A pipe used to communicate with MediaCodec. MediaCodec owns - // write_fd_ and writes to it. - int read_fd_; - int write_fd_; - - DISALLOW_COPY_AND_ASSIGN(AudioDecoderIO); -}; - -AudioDecoderIO::AudioDecoderIO(const char* data, size_t data_size) - : read_fd_(-1), - write_fd_(-1) { - - if (!data || !data_size || data_size > 0x80000000) - return; - - // Create the shared memory and copy our data to it so that - // MediaCodec can access it. - encoded_shared_memory_.CreateAndMapAnonymous(data_size); - - if (!encoded_shared_memory_.memory()) - return; - - memcpy(encoded_shared_memory_.memory(), data, data_size); - - // Create a pipe for reading/writing the decoded PCM data - int pipefd[2]; - - if (pipe(pipefd)) - return; - - read_fd_ = pipefd[0]; - write_fd_ = pipefd[1]; -} - -AudioDecoderIO::~AudioDecoderIO() { - // Close the read end of the pipe. The write end should have been - // closed by MediaCodec. - if (read_fd_ >= 0 && close(read_fd_)) { - DVLOG(1) << "Cannot close read fd " << read_fd_ - << ": " << strerror(errno); - } -} - -bool AudioDecoderIO::IsValid() const { - return read_fd_ >= 0 && write_fd_ >= 0 && - encoded_shared_memory_.memory(); -} - -bool AudioDecoderIO::ShareEncodedToProcess(base::SharedMemoryHandle* handle) { - return encoded_shared_memory_.ShareToProcess(base::GetCurrentProcessHandle(), - handle); -} - -static float ConvertSampleToFloat(int16_t sample) { - const float kMaxScale = 1.0f / std::numeric_limits<int16_t>::max(); - const float kMinScale = -1.0f / std::numeric_limits<int16_t>::min(); - - return sample * (sample < 0 ? kMinScale : kMaxScale); -} - -// A basic WAVE file decoder. See -// https://ccrma.stanford.edu/courses/422/projects/WaveFormat/ for a -// basic guide to the WAVE file format. -class WAVEDecoder { - public: - WAVEDecoder(const uint8_t* data, size_t data_size); - ~WAVEDecoder(); - - // Try to decode the data as a WAVE file. If the data is a supported - // WAVE file, |destination_bus| is filled with the decoded data and - // DecodeWAVEFile returns true. Otherwise, DecodeWAVEFile returns - // false. - bool DecodeWAVEFile(blink::WebAudioBus* destination_bus); - - private: - // Minimum number of bytes in a WAVE file to hold all of the data we - // need to interpret it as a WAVE file. - static const unsigned kMinimumWAVLength = 44; - - // Number of bytes in the chunk ID field. - static const unsigned kChunkIDLength = 4; - - // Number of bytes in the chunk size field. - static const unsigned kChunkSizeLength = 4; - - // Number of bytes in the format field of the "RIFF" chunk. - static const unsigned kFormatFieldLength = 4; - - // Number of bytes in a valid "fmt" chunk. - static const unsigned kFMTChunkLength = 16; - - // Supported audio format in a WAVE file. - // TODO(rtoy): Consider supporting other formats here, if necessary. - static const int16_t kAudioFormatPCM = 1; - - // Maximum number (inclusive) of bytes per sample supported by this - // decoder. - static const unsigned kMaximumBytesPerSample = 3; - - // Read an unsigned integer of |length| bytes from |buffer|. The - // integer is interpreted as being in little-endian order. - uint32_t ReadUnsignedInteger(const uint8_t* buffer, size_t length); - - // Read a PCM sample from the WAVE data at |pcm_data|. - int16_t ReadPCMSample(const uint8_t* pcm_data); - - // Read a WAVE chunk header including the chunk ID and chunk size. - // Returns false if the header could not be read. - bool ReadChunkHeader(); - - // Read and parse the "fmt" chunk. Returns false if the fmt chunk - // could not be read or contained unsupported formats. - bool ReadFMTChunk(); - - // Read data chunk and save it to |destination_bus|. Returns false - // if the data chunk could not be read correctly. - bool CopyDataChunkToBus(blink::WebAudioBus* destination_bus); - - // The WAVE chunk ID that identifies the chunk. - uint8_t chunk_id_[kChunkIDLength]; - - // The number of bytes in the data portion of the chunk. - size_t chunk_size_; - - // The total number of bytes in the encoded data. - size_t data_size_; - - // The current position within the WAVE file. - const uint8_t* buffer_; - - // Points one byte past the end of the in-memory WAVE file. Used for - // detecting if we've reached the end of the file. - const uint8_t* buffer_end_; - - size_t bytes_per_sample_; - - uint16_t number_of_channels_; - - // Sample rate of the WAVE data, in Hz. - uint32_t sample_rate_; - - DISALLOW_COPY_AND_ASSIGN(WAVEDecoder); -}; - -WAVEDecoder::WAVEDecoder(const uint8_t* encoded_data, size_t data_size) - : data_size_(data_size), - buffer_(encoded_data), - buffer_end_(encoded_data + 1), - bytes_per_sample_(0), - number_of_channels_(0), - sample_rate_(0) { - if (buffer_ + data_size > buffer_) - buffer_end_ = buffer_ + data_size; -} - -WAVEDecoder::~WAVEDecoder() {} - -uint32_t WAVEDecoder::ReadUnsignedInteger(const uint8_t* buffer, - size_t length) { - unsigned value = 0; - - if (length == 0 || length > sizeof(value)) { - DCHECK(false) << "ReadUnsignedInteger: Invalid length: " << length; - return 0; - } - - // All integer fields in a WAVE file are little-endian. - for (size_t k = length; k > 0; --k) - value = (value << 8) + buffer[k - 1]; - - return value; -} - -int16_t WAVEDecoder::ReadPCMSample(const uint8_t* pcm_data) { - uint32_t unsigned_sample = ReadUnsignedInteger(pcm_data, bytes_per_sample_); - int16_t sample; - - // Convert the unsigned data into a 16-bit PCM sample. - switch (bytes_per_sample_) { - case 1: - sample = (unsigned_sample - 128) << 8; - break; - case 2: - sample = static_cast<int16_t>(unsigned_sample); - break; - case 3: - // Android currently converts 24-bit WAVE data into 16-bit - // samples by taking the high-order 16 bits without rounding. - // We do the same here for consistency. - sample = static_cast<int16_t>(unsigned_sample >> 8); - break; - default: - sample = 0; - break; - } - return sample; -} - -bool WAVEDecoder::ReadChunkHeader() { - if (buffer_ + kChunkIDLength + kChunkSizeLength >= buffer_end_) - return false; - - memcpy(chunk_id_, buffer_, kChunkIDLength); - - chunk_size_ = ReadUnsignedInteger(buffer_ + kChunkIDLength, kChunkSizeLength); - - // Adjust for padding - if (chunk_size_ % 2) - ++chunk_size_; - - // Check for completely bogus chunk size. - if (chunk_size_ > data_size_) - return false; - - return true; -} - -bool WAVEDecoder::ReadFMTChunk() { - // The fmt chunk has basic info about the format of the audio - // data. Only a basic PCM format is supported. - if (chunk_size_ < kFMTChunkLength) { - DVLOG(1) << "FMT chunk too short: " << chunk_size_; - return 0; - } - - uint16_t audio_format = ReadUnsignedInteger(buffer_, 2); - - if (audio_format != kAudioFormatPCM) { - DVLOG(1) << "Audio format not supported: " << audio_format; - return false; - } - - number_of_channels_ = ReadUnsignedInteger(buffer_ + 2, 2); - sample_rate_ = ReadUnsignedInteger(buffer_ + 4, 4); - unsigned bits_per_sample = ReadUnsignedInteger(buffer_ + 14, 2); - - // Sanity checks. - - if (!number_of_channels_ || - number_of_channels_ > media::limits::kMaxChannels) { - DVLOG(1) << "Unsupported number of channels: " << number_of_channels_; - return false; - } - - if (sample_rate_ < media::limits::kMinSampleRate || - sample_rate_ > media::limits::kMaxSampleRate) { - DVLOG(1) << "Unsupported sample rate: " << sample_rate_; - return false; - } - - // We only support 8, 16, and 24 bits per sample. - if (bits_per_sample == 8 || bits_per_sample == 16 || bits_per_sample == 24) { - bytes_per_sample_ = bits_per_sample / 8; - return true; - } - - DVLOG(1) << "Unsupported bits per sample: " << bits_per_sample; - return false; -} - -bool WAVEDecoder::CopyDataChunkToBus(blink::WebAudioBus* destination_bus) { - // The data chunk contains the audio data itself. - if (!bytes_per_sample_ || bytes_per_sample_ > kMaximumBytesPerSample) { - DVLOG(1) << "WARNING: data chunk without preceeding fmt chunk," - << " or invalid bytes per sample."; - return false; - } - - DVLOG(0) << "Decoding WAVE file: " << number_of_channels_ << " channels, " - << sample_rate_ << " kHz, " - << chunk_size_ / bytes_per_sample_ / number_of_channels_ - << " frames, " << 8 * bytes_per_sample_ << " bits/sample"; - - // Create the destination bus of the appropriate size and then decode - // the data into the bus. - size_t number_of_frames = - chunk_size_ / bytes_per_sample_ / number_of_channels_; - - destination_bus->initialize( - number_of_channels_, number_of_frames, sample_rate_); - - for (size_t m = 0; m < number_of_frames; ++m) { - for (uint16_t k = 0; k < number_of_channels_; ++k) { - int16_t sample = ReadPCMSample(buffer_); - - buffer_ += bytes_per_sample_; - destination_bus->channelData(k)[m] = ConvertSampleToFloat(sample); - } - } - - return true; -} - -bool WAVEDecoder::DecodeWAVEFile(blink::WebAudioBus* destination_bus) { - // Parse and decode WAVE file. If we can't parse it, return false. - - if (buffer_ + kMinimumWAVLength > buffer_end_) { - DVLOG(1) << "Buffer too small to contain full WAVE header: "; - return false; - } - - // Do we have a RIFF file? - ReadChunkHeader(); - if (memcmp(chunk_id_, "RIFF", kChunkIDLength) != 0) { - DVLOG(1) << "RIFF missing"; - return false; - } - buffer_ += kChunkIDLength + kChunkSizeLength; - - // Check the format field of the RIFF chunk - memcpy(chunk_id_, buffer_, kFormatFieldLength); - if (memcmp(chunk_id_, "WAVE", kFormatFieldLength) != 0) { - DVLOG(1) << "Invalid WAVE file: missing WAVE header"; - return false; - } - // Advance past the format field - buffer_ += kFormatFieldLength; - - // We have a WAVE file. Start parsing the chunks. - - while (buffer_ < buffer_end_) { - if (!ReadChunkHeader()) { - DVLOG(1) << "Couldn't read chunk header"; - return false; - } - - // Consume the chunk ID and chunk size - buffer_ += kChunkIDLength + kChunkSizeLength; - - // Make sure we can read all chunk_size bytes. - if (buffer_ + chunk_size_ > buffer_end_) { - DVLOG(1) << "Insufficient bytes to read chunk of size " << chunk_size_; - return false; - } - - if (memcmp(chunk_id_, "fmt ", kChunkIDLength) == 0) { - if (!ReadFMTChunk()) - return false; - } else if (memcmp(chunk_id_, "data", kChunkIDLength) == 0) { - // Return after reading the data chunk, whether we succeeded or - // not. - return CopyDataChunkToBus(destination_bus); - } else { - // Ignore these chunks that we don't know about. - DVLOG(0) << "Ignoring WAVE chunk `" << chunk_id_ << "' size " - << chunk_size_; - } - - // Advance to next chunk. - buffer_ += chunk_size_; - } - - // If we get here, that means we didn't find a data chunk, so we - // couldn't handle this WAVE file. - - return false; -} - -// The number of frames is known so preallocate the destination -// bus and copy the pcm data to the destination bus as it's being -// received. -static void CopyPcmDataToBus(int input_fd, - blink::WebAudioBus* destination_bus, - size_t number_of_frames, - unsigned number_of_channels, - double file_sample_rate) { - destination_bus->initialize(number_of_channels, - number_of_frames, - file_sample_rate); - - int16_t pipe_data[PIPE_BUF / sizeof(int16_t)]; - size_t decoded_frames = 0; - size_t current_sample_in_frame = 0; - ssize_t nread; - - while ((nread = HANDLE_EINTR(read(input_fd, pipe_data, sizeof(pipe_data)))) > - 0) { - size_t samples_in_pipe = nread / sizeof(int16_t); - - // The pipe may not contain a whole number of frames. This is - // especially true if the number of channels is greater than - // 2. Thus, keep track of which sample in a frame is being - // processed, so we handle the boundary at the end of the pipe - // correctly. - for (size_t m = 0; m < samples_in_pipe; ++m) { - if (decoded_frames >= number_of_frames) - break; - - destination_bus->channelData(current_sample_in_frame)[decoded_frames] = - ConvertSampleToFloat(pipe_data[m]); - ++current_sample_in_frame; - - if (current_sample_in_frame >= number_of_channels) { - current_sample_in_frame = 0; - ++decoded_frames; - } - } - } - - // number_of_frames is only an estimate. Resize the buffer with the - // actual number of received frames. - if (decoded_frames < number_of_frames) - destination_bus->resizeSmaller(decoded_frames); -} - -// The number of frames is unknown, so keep reading and buffering -// until there's no more data and then copy the data to the -// destination bus. -static void BufferAndCopyPcmDataToBus(int input_fd, - blink::WebAudioBus* destination_bus, - unsigned number_of_channels, - double file_sample_rate) { - int16_t pipe_data[PIPE_BUF / sizeof(int16_t)]; - std::vector<int16_t> decoded_samples; - ssize_t nread; - - while ((nread = HANDLE_EINTR(read(input_fd, pipe_data, sizeof(pipe_data)))) > - 0) { - size_t samples_in_pipe = nread / sizeof(int16_t); - if (decoded_samples.size() + samples_in_pipe > decoded_samples.capacity()) { - decoded_samples.reserve(std::max(samples_in_pipe, - 2 * decoded_samples.capacity())); - } - std::copy(pipe_data, - pipe_data + samples_in_pipe, - back_inserter(decoded_samples)); - } - - DVLOG(1) << "Total samples read = " << decoded_samples.size(); - - // Convert the samples and save them in the audio bus. - size_t number_of_samples = decoded_samples.size(); - size_t number_of_frames = decoded_samples.size() / number_of_channels; - size_t decoded_frames = 0; - - destination_bus->initialize(number_of_channels, - number_of_frames, - file_sample_rate); - - for (size_t m = 0; m < number_of_samples; m += number_of_channels) { - if (decoded_frames >= number_of_frames) - break; - - for (size_t k = 0; k < number_of_channels; ++k) { - int16_t sample = decoded_samples[m + k]; - destination_bus->channelData(k)[decoded_frames] = - ConvertSampleToFloat(sample); - } - ++decoded_frames; - } - - // number_of_frames is only an estimate. Resize the buffer with the - // actual number of received frames. - if (decoded_frames < number_of_frames) - destination_bus->resizeSmaller(decoded_frames); -} - -static bool TryWAVEFileDecoder(blink::WebAudioBus* destination_bus, - const uint8_t* encoded_data, - size_t data_size) { - WAVEDecoder decoder(encoded_data, data_size); - - return decoder.DecodeWAVEFile(destination_bus); -} - -// To decode audio data, we want to use the Android MediaCodec class. -// But this can't run in a sandboxed process so we need initiate the -// request to MediaCodec in the browser. To do this, we create a -// shared memory buffer that holds the audio data. We send a message -// to the browser to start the decoder using this buffer and one end -// of a pipe. The MediaCodec class will decode the data from the -// shared memory and write the PCM samples back to us over a pipe. -bool DecodeAudioFileData(blink::WebAudioBus* destination_bus, const char* data, - size_t data_size, - scoped_refptr<ThreadSafeSender> sender) { - // Try to decode the data as a WAVE file first. If it can't be - // decoded, use MediaCodec. See crbug.com/259048. - if (TryWAVEFileDecoder( - destination_bus, reinterpret_cast<const uint8_t*>(data), data_size)) { - return true; - } - - AudioDecoderIO audio_decoder(data, data_size); - - if (!audio_decoder.IsValid()) - return false; - - base::SharedMemoryHandle encoded_data_handle; - audio_decoder.ShareEncodedToProcess(&encoded_data_handle); - base::FileDescriptor fd(audio_decoder.write_fd(), true); - - DVLOG(1) << "DecodeAudioFileData: Starting MediaCodec"; - - // Start MediaCodec processing in the browser which will read from - // encoded_data_handle for our shared memory and write the decoded - // PCM samples (16-bit integer) to our pipe. - - sender->Send(new ViewHostMsg_RunWebAudioMediaCodec( - encoded_data_handle, fd, data_size)); - - // First, read the number of channels, the sample rate, and the - // number of frames and a flag indicating if the file is an - // ogg/vorbis file. This must be coordinated with - // WebAudioMediaCodecBridge! - // - // If we know the number of samples, we can create the destination - // bus directly and do the conversion directly to the bus instead of - // buffering up everything before saving the data to the bus. - - int input_fd = audio_decoder.read_fd(); - struct media::WebAudioMediaCodecInfo info; - - DVLOG(1) << "Reading audio file info from fd " << input_fd; - ssize_t nread = HANDLE_EINTR(read(input_fd, &info, sizeof(info))); - DVLOG(1) << "read: " << nread << " bytes:\n" - << " 0: number of channels = " << info.channel_count << "\n" - << " 1: sample rate = " << info.sample_rate << "\n" - << " 2: number of frames = " << info.number_of_frames << "\n"; - - if (nread != sizeof(info)) - return false; - - unsigned number_of_channels = info.channel_count; - double file_sample_rate = static_cast<double>(info.sample_rate); - size_t number_of_frames = info.number_of_frames; - - // Sanity checks - if (!number_of_channels || - number_of_channels > media::limits::kMaxChannels || - file_sample_rate < media::limits::kMinSampleRate || - file_sample_rate > media::limits::kMaxSampleRate) { - return false; - } - - if (number_of_frames > 0) { - CopyPcmDataToBus(input_fd, - destination_bus, - number_of_frames, - number_of_channels, - file_sample_rate); - } else { - BufferAndCopyPcmDataToBus(input_fd, - destination_bus, - number_of_channels, - file_sample_rate); - } - - return true; -} - -} // namespace content
diff --git a/content/renderer/media/android/audio_decoder_android.h b/content/renderer/media/android/audio_decoder_android.h deleted file mode 100644 index 3f4c45b..0000000 --- a/content/renderer/media/android/audio_decoder_android.h +++ /dev/null
@@ -1,25 +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 CONTENT_RENDERER_MEDIA_ANDROID_AUDIO_DECODER_ANDROID_H_ -#define CONTENT_RENDERER_MEDIA_ANDROID_AUDIO_DECODER_ANDROID_H_ - -#include <stddef.h> - -#include "content/child/thread_safe_sender.h" - -namespace blink { -class WebAudioBus; -} - -namespace content { - -bool DecodeAudioFileData(blink::WebAudioBus* destination_bus, - const char* data, - size_t data_size, - scoped_refptr<ThreadSafeSender> sender); - -} // namespace content - -#endif // CONTENT_RENDERER_MEDIA_ANDROID_AUDIO_DECODER_ANDROID_H_
diff --git a/content/renderer/media/android/webmediaplayer_android.cc b/content/renderer/media/android/webmediaplayer_android.cc index 4a1f4f74..629f9852 100644 --- a/content/renderer/media/android/webmediaplayer_android.cc +++ b/content/renderer/media/android/webmediaplayer_android.cc
@@ -713,9 +713,9 @@ // value down to get the expected result. // flip_y==true means to reverse the video orientation while // flip_y==false means to keep the intrinsic orientation. - web_graphics_context->copyTextureCHROMIUM( - GL_TEXTURE_2D, src_texture, texture, internal_format, type, - flip_y, premultiply_alpha, false); + web_graphics_context->copyTextureCHROMIUM(src_texture, texture, + internal_format, type, flip_y, + premultiply_alpha, false); web_graphics_context->deleteTexture(src_texture); web_graphics_context->flush(); @@ -976,7 +976,6 @@ void WebMediaPlayerAndroid::OnConnectedToRemoteDevice( const std::string& remote_playback_message) { DCHECK(main_thread_checker_.CalledOnValidThread()); - DCHECK(!media_source_delegate_); DrawRemotePlaybackText(remote_playback_message); is_remote_ = true; SetNeedsEstablishPeer(false); @@ -985,7 +984,6 @@ void WebMediaPlayerAndroid::OnDisconnectedFromRemoteDevice() { DCHECK(main_thread_checker_.CalledOnValidThread()); - DCHECK(!media_source_delegate_); SetNeedsEstablishPeer(true); if (!paused()) EstablishSurfaceTexturePeer();
diff --git a/content/renderer/media/canvas_capture_handler.cc b/content/renderer/media/canvas_capture_handler.cc index 1ba28798..9da03dd 100644 --- a/content/renderer/media/canvas_capture_handler.cc +++ b/content/renderer/media/canvas_capture_handler.cc
@@ -94,12 +94,14 @@ DISALLOW_COPY_AND_ASSIGN(CanvasCaptureHandlerDelegate); }; -CanvasCaptureHandler::CanvasCaptureHandler(const blink::WebSize& size, - double frame_rate, - blink::WebMediaStreamTrack* track) +CanvasCaptureHandler::CanvasCaptureHandler( + const blink::WebSize& size, + double frame_rate, + const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner, + blink::WebMediaStreamTrack* track) : ask_for_new_frame_(false), size_(size), - io_task_runner_(content::RenderThread::Get()->GetIOMessageLoopProxy()), + io_task_runner_(io_task_runner), weak_ptr_factory_(this) { scoped_ptr<media::VideoCapturerSource> video_source( new CanvasCaptureHandler::VideoCapturerSource( @@ -113,7 +115,7 @@ io_task_runner_->DeleteSoon(FROM_HERE, delegate_.release()); } -void CanvasCaptureHandler::sendNewFrame(const blink::WebSkImage& image) { +void CanvasCaptureHandler::sendNewFrame(const SkImage* image) { DCHECK(thread_checker_.CalledOnValidThread()); CreateNewFrame(image); } @@ -148,26 +150,28 @@ io_task_runner_->DeleteSoon(FROM_HERE, delegate_.release()); } -void CanvasCaptureHandler::CreateNewFrame(const blink::WebSkImage& image) { +void CanvasCaptureHandler::CreateNewFrame(const SkImage* image) { DCHECK(thread_checker_.CalledOnValidThread()); - DCHECK(!image.isNull()); - const gfx::Size size(image.width(), image.height()); + DCHECK(image); + const gfx::Size size(image->width(), image->height()); if (size != last_size) { temp_data_.resize( media::VideoFrame::AllocationSize(media::PIXEL_FORMAT_ARGB, size)); - row_bytes_ = media::VideoFrame::RowBytes( - 0, media::PIXEL_FORMAT_ARGB, capture_format_.frame_size.width()); + row_bytes_ = + media::VideoFrame::RowBytes(0, media::PIXEL_FORMAT_ARGB, size.width()); image_info_ = SkImageInfo::Make(size.width(), size.height(), kBGRA_8888_SkColorType, kPremul_SkAlphaType); last_size = size; } - image.readPixels(image_info_, &temp_data_[0], row_bytes_, 0, 0); + image->readPixels(image_info_, &temp_data_[0], row_bytes_, 0, 0); scoped_refptr<media::VideoFrame> video_frame = frame_pool_.CreateFrame(media::PIXEL_FORMAT_I420, size, gfx::Rect(size), size, base::TimeTicks::Now() - base::TimeTicks()); + DCHECK(video_frame); + libyuv::ARGBToI420(temp_data_.data(), row_bytes_, video_frame->data(media::VideoFrame::kYPlane), video_frame->stride(media::VideoFrame::kYPlane), @@ -176,7 +180,6 @@ video_frame->data(media::VideoFrame::kVPlane), video_frame->stride(media::VideoFrame::kVPlane), size.width(), size.height()); - io_task_runner_->PostTask( FROM_HERE, base::Bind(&CanvasCaptureHandler::CanvasCaptureHandlerDelegate::
diff --git a/content/renderer/media/canvas_capture_handler.h b/content/renderer/media/canvas_capture_handler.h index adec2624..f080fd1 100644 --- a/content/renderer/media/canvas_capture_handler.h +++ b/content/renderer/media/canvas_capture_handler.h
@@ -18,34 +18,35 @@ #include "third_party/WebKit/public/platform/WebCanvasCaptureHandler.h" #include "third_party/WebKit/public/platform/WebMediaStreamTrack.h" #include "third_party/WebKit/public/platform/WebSize.h" -#include "third_party/WebKit/public/platform/WebSkImage.h" #include "third_party/skia/include/core/SkImage.h" namespace content { -// CanvasCaptureHandler acts as the link between blink side HTMLCanvasElement +// CanvasCaptureHandler acts as the link between Blink side HTMLCanvasElement // and Chrome side VideoCapturerSource. It is responsible for handling -// WebSkImage instances sent from the blink side, convert them to +// SkImage instances sent from the Blink side, convert them to // media::VideoFrame and plug them to the MediaStreamTrack. // CanvasCaptureHandler instance is owned by a blink::CanvasDrawListener which // is owned by a CanvasCaptureMediaStreamTrack. // All methods are called on the same thread as construction and destruction, // i.e. the Main Render thread. Note that a CanvasCaptureHandlerDelegate is -// used to send back frames on the IO thread. +// used to send back frames to |io_task_runner_|, i.e. IO thread. class CONTENT_EXPORT CanvasCaptureHandler final : public NON_EXPORTED_BASE(blink::WebCanvasCaptureHandler) { public: // A VideoCapturerSource instance is created, which is responsible for handing // stop&start callbacks back to CanvasCaptureHandler. That VideoCapturerSource // is then plugged into a MediaStreamTrack passed as |track|, and it is owned - // by the blink side MediaStreamSource. - CanvasCaptureHandler(const blink::WebSize& size, - double frame_rate, - blink::WebMediaStreamTrack* track); + // by the Blink side MediaStreamSource. + CanvasCaptureHandler( + const blink::WebSize& size, + double frame_rate, + const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner, + blink::WebMediaStreamTrack* track); ~CanvasCaptureHandler() override; // blink::WebCanvasCaptureHandler Implementation. - void sendNewFrame(const blink::WebSkImage& image) override; + void sendNewFrame(const SkImage* image) override; bool needsNewFrame() const override; // Functions called by media::VideoCapturerSource implementation. @@ -58,17 +59,17 @@ blink::WebSize GetSourceSize() const { return size_; } private: - void CreateNewFrame(const blink::WebSkImage& image); + void CreateNewFrame(const SkImage* image); void AddVideoCapturerSourceToVideoTrack( scoped_ptr<media::VideoCapturerSource> source, blink::WebMediaStreamTrack* web_track); - // Implementation VideoCapturerSource that is owned by blink and delegates + // Implementation VideoCapturerSource that is owned by Blink and delegates // the Start/Stop calls to CanvasCaptureHandler. class VideoCapturerSource; // Object that does all the work of running |new_frame_callback_|. - // Destroyed on |io_task_runner_| after the class is destroyed. + // Destroyed on |frame_callback_task_runner_| after the class is destroyed. class CanvasCaptureHandlerDelegate; media::VideoCaptureFormat capture_format_;
diff --git a/content/renderer/media/canvas_capture_handler_unittest.cc b/content/renderer/media/canvas_capture_handler_unittest.cc new file mode 100644 index 0000000..4bbe54da --- /dev/null +++ b/content/renderer/media/canvas_capture_handler_unittest.cc
@@ -0,0 +1,201 @@ +// 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/message_loop/message_loop.h" +#include "base/run_loop.h" +#include "base/thread_task_runner_handle.h" +#include "content/child/child_process.h" +#include "content/renderer/media/canvas_capture_handler.h" +#include "content/renderer/media/media_stream_video_capturer_source.h" +#include "media/base/limits.h" +#include "skia/ext/refptr.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/WebKit/public/platform/WebMediaStreamSource.h" +#include "third_party/WebKit/public/platform/WebMediaStreamTrack.h" +#include "third_party/WebKit/public/platform/WebSize.h" +#include "third_party/WebKit/public/web/WebHeap.h" + +using ::testing::_; +using ::testing::InSequence; +using ::testing::Mock; +using ::testing::SaveArg; +using ::testing::Test; + +namespace content { + +static const int kTestCanvasCaptureWidth = 320; +static const int kTestCanvasCaptureHeight = 240; +static const double kTestCanvasCaptureFramesPerSecond = 55.5; + +static const int kTestCanvasCaptureFrameWidth = 2; +static const int kTestCanvasCaptureFrameHeight = 2; +static const int kTestCanvasCaptureFrameErrorTolerance = 2; + +ACTION_P(RunClosure, closure) { + closure.Run(); +} + +class CanvasCaptureHandlerTest : public Test { + public: + CanvasCaptureHandlerTest() {} + + void SetUp() override { + canvas_capture_handler_.reset(new CanvasCaptureHandler( + blink::WebSize(kTestCanvasCaptureWidth, kTestCanvasCaptureHeight), + kTestCanvasCaptureFramesPerSecond, message_loop_.task_runner(), + &track_)); + } + + void TearDown() override { + track_.reset(); + blink::WebHeap::collectAllGarbageForTesting(); + canvas_capture_handler_.reset(); + + // Let the message loop run to finish destroying the capturer. + base::RunLoop().RunUntilIdle(); + } + + // Necessary callbacks and MOCK_METHODS for VideoCapturerSource. + MOCK_METHOD2(DoOnDeliverFrame, + void(const scoped_refptr<media::VideoFrame>&, base::TimeTicks)); + void OnDeliverFrame(const scoped_refptr<media::VideoFrame>& video_frame, + base::TimeTicks estimated_capture_time) { + DoOnDeliverFrame(video_frame, estimated_capture_time); + } + + MOCK_METHOD1(DoOnVideoCaptureDeviceFormats, + void(const media::VideoCaptureFormats&)); + void OnVideoCaptureDeviceFormats(const media::VideoCaptureFormats& formats) { + DoOnVideoCaptureDeviceFormats(formats); + } + + MOCK_METHOD1(DoOnRunning, void(bool)); + void OnRunning(bool state) { DoOnRunning(state); } + + // Verify returned frames. + static skia::RefPtr<SkImage> GenerateTestImage() { + SkBitmap testBitmap; + testBitmap.allocN32Pixels(kTestCanvasCaptureFrameWidth, + kTestCanvasCaptureFrameHeight); + testBitmap.eraseColor(SK_ColorBLUE); + return skia::AdoptRef(SkImage::NewFromBitmap(testBitmap)); + } + + void OnVerifyDeliveredFrame( + const scoped_refptr<media::VideoFrame>& video_frame, + base::TimeTicks estimated_capture_time) { + EXPECT_EQ(media::PIXEL_FORMAT_I420, video_frame->format()); + const gfx::Size& size = video_frame->coded_size(); + EXPECT_EQ(kTestCanvasCaptureFrameWidth, size.width()); + EXPECT_EQ(kTestCanvasCaptureFrameHeight, size.height()); + const uint8_t* y_plane = video_frame->data(0); + EXPECT_NEAR(41, y_plane[0], kTestCanvasCaptureFrameErrorTolerance); + const uint8_t* u_plane = video_frame->data(1); + EXPECT_NEAR(239, u_plane[0], kTestCanvasCaptureFrameErrorTolerance); + const uint8_t* v_plane = video_frame->data(2); + EXPECT_NEAR(110, v_plane[0], kTestCanvasCaptureFrameErrorTolerance); + } + + blink::WebMediaStreamTrack track_; + // The Class under test. Needs to be scoped_ptr to force its destruction. + scoped_ptr<CanvasCaptureHandler> canvas_capture_handler_; + + protected: + media::VideoCapturerSource* GetVideoCapturerSource( + MediaStreamVideoCapturerSource* ms_source) { + return ms_source->source_.get(); + } + + // A ChildProcess and a MessageLoopForUI are both needed to fool the Tracks + // and Sources into believing they are on the right threads. + base::MessageLoopForUI message_loop_; + ChildProcess child_process_; + + private: + DISALLOW_COPY_AND_ASSIGN(CanvasCaptureHandlerTest); +}; + +// Checks that the initialization-destruction sequence works fine. +TEST_F(CanvasCaptureHandlerTest, ConstructAndDestruct) { + EXPECT_TRUE(canvas_capture_handler_->needsNewFrame()); + base::RunLoop().RunUntilIdle(); +} + +// Checks that VideoCapturerSource call sequence works fine. +TEST_F(CanvasCaptureHandlerTest, GetFormatsStartAndStop) { + InSequence s; + const blink::WebMediaStreamSource& web_media_stream_source = track_.source(); + EXPECT_FALSE(web_media_stream_source.isNull()); + MediaStreamVideoCapturerSource* const ms_source = + static_cast<MediaStreamVideoCapturerSource*>( + web_media_stream_source.extraData()); + EXPECT_TRUE(ms_source != nullptr); + media::VideoCapturerSource* source = GetVideoCapturerSource(ms_source); + EXPECT_TRUE(source != nullptr); + + media::VideoCaptureFormats formats; + EXPECT_CALL(*this, DoOnVideoCaptureDeviceFormats(_)) + .Times(1) + .WillOnce(SaveArg<0>(&formats)); + source->GetCurrentSupportedFormats( + media::limits::kMaxCanvas /* max_requesteed_width */, + media::limits::kMaxCanvas /* max_requesteed_height */, + media::limits::kMaxFramesPerSecond /* max_requested_frame_rate */, + base::Bind(&CanvasCaptureHandlerTest::OnVideoCaptureDeviceFormats, + base::Unretained(this))); + ASSERT_EQ(1u, formats.size()); + EXPECT_EQ(kTestCanvasCaptureWidth, formats[0].frame_size.width()); + EXPECT_EQ(kTestCanvasCaptureHeight, formats[0].frame_size.height()); + media::VideoCaptureParams params; + params.requested_format = formats[0]; + + base::RunLoop run_loop; + base::Closure quit_closure = run_loop.QuitClosure(); + EXPECT_CALL(*this, DoOnRunning(true)).Times(1); + EXPECT_CALL(*this, DoOnDeliverFrame(_, _)) + .Times(1) + .WillOnce(RunClosure(quit_closure)); + source->StartCapture( + params, base::Bind(&CanvasCaptureHandlerTest::OnDeliverFrame, + base::Unretained(this)), + base::Bind(&CanvasCaptureHandlerTest::OnRunning, base::Unretained(this))); + canvas_capture_handler_->sendNewFrame(GenerateTestImage().get()); + run_loop.Run(); + + source->StopCapture(); +} + +// Verifies that SkImage is processed and produces VideoFrame as expected. +TEST_F(CanvasCaptureHandlerTest, VerifyFrame) { + InSequence s; + media::VideoCapturerSource* const source = + GetVideoCapturerSource(static_cast<MediaStreamVideoCapturerSource*>( + track_.source().extraData())); + EXPECT_TRUE(source != nullptr); + + base::RunLoop run_loop; + EXPECT_CALL(*this, DoOnRunning(true)).Times(1); + media::VideoCaptureParams params; + source->StartCapture( + params, base::Bind(&CanvasCaptureHandlerTest::OnVerifyDeliveredFrame, + base::Unretained(this)), + base::Bind(&CanvasCaptureHandlerTest::OnRunning, base::Unretained(this))); + canvas_capture_handler_->sendNewFrame(GenerateTestImage().get()); + run_loop.RunUntilIdle(); +} + +// Checks that needsNewFrame() works as expected. +TEST_F(CanvasCaptureHandlerTest, CheckNeedsNewFrame) { + InSequence s; + media::VideoCapturerSource* source = + GetVideoCapturerSource(static_cast<MediaStreamVideoCapturerSource*>( + track_.source().extraData())); + EXPECT_TRUE(source != nullptr); + EXPECT_TRUE(canvas_capture_handler_->needsNewFrame()); + source->StopCapture(); + EXPECT_FALSE(canvas_capture_handler_->needsNewFrame()); +} + +} // namespace content
diff --git a/content/renderer/media/cdm/pepper_cdm_wrapper_impl.cc b/content/renderer/media/cdm/pepper_cdm_wrapper_impl.cc index 1dfc24d..8928f84 100644 --- a/content/renderer/media/cdm/pepper_cdm_wrapper_impl.cc +++ b/content/renderer/media/cdm/pepper_cdm_wrapper_impl.cc
@@ -45,8 +45,10 @@ return scoped_ptr<PepperCdmWrapper>(); GURL url(plugin_instance->container()->element().document().url()); - CHECK_EQ(security_origin.GetOrigin(), url.GetOrigin()) - << "Pepper instance has a different origin than the EME call."; + if (security_origin.GetOrigin() != url.GetOrigin()) { + NOTREACHED() << "Pepper instance has a different origin than the EME call."; + return scoped_ptr<PepperCdmWrapper>(); + } if (!plugin_instance->GetContentDecryptorDelegate()) return scoped_ptr<PepperCdmWrapper>();
diff --git a/content/renderer/media/media_stream_video_capturer_source.h b/content/renderer/media/media_stream_video_capturer_source.h index a2f48916..9dc7b1f 100644 --- a/content/renderer/media/media_stream_video_capturer_source.h +++ b/content/renderer/media/media_stream_video_capturer_source.h
@@ -32,6 +32,7 @@ ~MediaStreamVideoCapturerSource() override; private: + friend class CanvasCaptureHandlerTest; friend class MediaStreamVideoCapturerSourceTest; // Implements MediaStreamVideoSource.
diff --git a/content/renderer/media/rtc_video_encoder.cc b/content/renderer/media/rtc_video_encoder.cc index f586a897..c9406f1 100644 --- a/content/renderer/media/rtc_video_encoder.cc +++ b/content/renderer/media/rtc_video_encoder.cc
@@ -176,6 +176,10 @@ // Checks if the bitrate would overflow when passing from kbps to bps. bool IsBitrateTooHigh(uint32_t bitrate); + // Checks if the frame size is different than hardware accelerator + // requirements. + bool RequiresSizeChange(const scoped_refptr<media::VideoFrame>& frame) const; + base::ThreadChecker thread_checker_; // Weak pointer to the parent RTCVideoEncoder, for posting back VEA::Client @@ -504,10 +508,16 @@ } const int index = input_buffers_free_.back(); + bool requires_copy = false; scoped_refptr<media::VideoFrame> frame; if (next_frame->native_handle()) { frame = static_cast<media::VideoFrame*>(next_frame->native_handle()); + requires_copy = RequiresSizeChange(frame); } else { + requires_copy = true; + } + + if (requires_copy) { base::SharedMemory* input_buffer = input_buffers_[index]; frame = media::VideoFrame::WrapExternalSharedMemory( media::PIXEL_FORMAT_I420, input_frame_coded_size_, @@ -583,6 +593,12 @@ return true; } +bool RTCVideoEncoder::Impl::RequiresSizeChange( + const scoped_refptr<media::VideoFrame>& frame) const { + return (frame->coded_size() != input_frame_coded_size_ || + frame->visible_rect() != gfx::Rect(input_visible_size_)); +} + RTCVideoEncoder::RTCVideoEncoder( webrtc::VideoCodecType type, media::GpuVideoAcceleratorFactories* gpu_factories)
diff --git a/content/renderer/media/webrtc/peer_connection_dependency_factory.cc b/content/renderer/media/webrtc/peer_connection_dependency_factory.cc index cfd82f5..270cf16 100644 --- a/content/renderer/media/webrtc/peer_connection_dependency_factory.cc +++ b/content/renderer/media/webrtc/peer_connection_dependency_factory.cc
@@ -353,12 +353,13 @@ factory_options.disable_encryption = cmd_line->HasSwitch(switches::kDisableWebRtcEncryption); + // DTLS 1.2 is the default now but could be changed to 1.0 by the experiment. + factory_options.ssl_max_version = rtc::SSL_PROTOCOL_DTLS_12; std::string group_name = base::FieldTrialList::FindFullName("WebRTC-PeerConnectionDTLS1.2"); - if (StartsWith(group_name, "Enabled", base::CompareCase::SENSITIVE) || - cmd_line->HasSwitch(switches::kEnableWebRtcDtls12)) { - factory_options.ssl_max_version = rtc::SSL_PROTOCOL_DTLS_12; - } + if (StartsWith(group_name, "Control", base::CompareCase::SENSITIVE)) + factory_options.ssl_max_version = rtc::SSL_PROTOCOL_DTLS_10; + pc_factory_->SetOptions(factory_options); event->Signal();
diff --git a/content/renderer/media/webrtc_audio_renderer.cc b/content/renderer/media/webrtc_audio_renderer.cc index f0ce3f0..640d8dc4 100644 --- a/content/renderer/media/webrtc_audio_renderer.cc +++ b/content/renderer/media/webrtc_audio_renderer.cc
@@ -594,8 +594,8 @@ // to match the native audio layer. int sample_rate = sink_->GetOutputParameters().sample_rate(); DVLOG(1) << "Audio output hardware sample rate: " << sample_rate; - if (sample_rate == 192000) { - DVLOG(1) << "Resampling from 48000 to 192000 is required"; + if (sample_rate >= 192000) { + DVLOG(1) << "Resampling from 48000 to " << sample_rate << " is required"; sample_rate = 48000; } media::AudioSampleRate asr;
diff --git a/content/renderer/pepper/OWNERS b/content/renderer/pepper/OWNERS index dadb8e91..3d24b44 100644 --- a/content/renderer/pepper/OWNERS +++ b/content/renderer/pepper/OWNERS
@@ -1,5 +1,6 @@ bbudge@chromium.org raymes@chromium.org +per-file plugin_power_saver*=tommycli@chromium.org per-file usb_key_code_*=garykac@chromium.org per-file usb_key_code_*=wez@chromium.org
diff --git a/content/renderer/pepper/plugin_power_saver_helper.cc b/content/renderer/pepper/plugin_power_saver_helper.cc index cd1f27cc..10f0954 100644 --- a/content/renderer/pepper/plugin_power_saver_helper.cc +++ b/content/renderer/pepper/plugin_power_saver_helper.cc
@@ -7,6 +7,7 @@ #include <string> #include "base/command_line.h" +#include "base/message_loop/message_loop.h" #include "base/metrics/histogram.h" #include "base/strings/string_number_conversions.h" #include "content/common/frame_messages.h" @@ -70,7 +71,10 @@ auto it = peripheral_plugins_.begin(); while (it != peripheral_plugins_.end()) { if (origin_whitelist.count(it->content_origin)) { - it->unthrottle_callback.Run(); + // Because the unthrottle callback may register another peripheral plugin + // and invalidate our iterator, we cannot run it synchronously. + base::MessageLoop::current()->PostTask(FROM_HERE, + it->unthrottle_callback); it = peripheral_plugins_.erase(it); } else { ++it;
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc index 73796d2..a5c3d3a 100644 --- a/content/renderer/render_thread_impl.cc +++ b/content/renderer/render_thread_impl.cc
@@ -128,7 +128,6 @@ #include "content/renderer/shared_worker/embedded_shared_worker_stub.h" #include "gin/public/debug.h" #include "gpu/GLES2/gl2extchromium.h" -#include "gpu/command_buffer/common/gles2_cmd_utils.h" #include "ipc/ipc_channel_handle.h" #include "ipc/ipc_platform_file.h" #include "ipc/mojo/ipc_channel_mojo.h" @@ -1219,7 +1218,8 @@ base::Unretained(this))); SetResourceDispatchTaskQueue(renderer_scheduler_->LoadingTaskRunner()); - if (!command_line.HasSwitch(switches::kDisableThreadedCompositing)) + if (!command_line.HasSwitch(switches::kDisableThreadedCompositing) && + !command_line.HasSwitch(switches::kUseRemoteCompositing)) InitializeCompositorThread(); if (!input_event_filter_.get()) {
diff --git a/content/renderer/renderer_blink_platform_impl.cc b/content/renderer/renderer_blink_platform_impl.cc index 391a2a4..2bffb25 100644 --- a/content/renderer/renderer_blink_platform_impl.cc +++ b/content/renderer/renderer_blink_platform_impl.cc
@@ -98,7 +98,6 @@ #if defined(OS_ANDROID) #include "content/renderer/android/synchronous_compositor_factory.h" -#include "content/renderer/media/android/audio_decoder_android.h" #include "gpu/blink/webgraphicscontext3d_in_process_command_buffer_impl.h" #endif @@ -753,17 +752,6 @@ return new RendererWebAudioDeviceImpl(params, callback, session_id); } -#if defined(OS_ANDROID) -bool RendererBlinkPlatformImpl::loadAudioResource( - blink::WebAudioBus* destination_bus, - const char* audio_file_data, - size_t data_size) { - return DecodeAudioFileData(destination_bus, - audio_file_data, - data_size, - thread_safe_sender_); -} -#else bool RendererBlinkPlatformImpl::loadAudioResource( blink::WebAudioBus* destination_bus, const char* audio_file_data, @@ -771,7 +759,6 @@ return DecodeAudioFileData( destination_bus, audio_file_data, data_size); } -#endif // defined(OS_ANDROID) //------------------------------------------------------------------------------ @@ -946,7 +933,8 @@ double frame_rate, WebMediaStreamTrack* track) { #if defined(ENABLE_WEBRTC) - return new CanvasCaptureHandler(size, frame_rate, track); + return new CanvasCaptureHandler( + size, frame_rate, RenderThread::Get()->GetIOMessageLoopProxy(), track); #else return nullptr; #endif // defined(ENABLE_WEBRTC)
diff --git a/content/shell/browser/shell.cc b/content/shell/browser/shell.cc index 81c9cad0..409f0d41 100644 --- a/content/shell/browser/shell.cc +++ b/content/shell/browser/shell.cc
@@ -270,6 +270,37 @@ return web_contents_->GetNativeView(); } +WebContents* Shell::OpenURLFromTab(WebContents* source, + const OpenURLParams& params) { + // This implementation only handles CURRENT_TAB. + if (params.disposition != CURRENT_TAB) + return nullptr; + + NavigationController::LoadURLParams load_url_params(params.url); + load_url_params.source_site_instance = params.source_site_instance; + load_url_params.transition_type = params.transition; + load_url_params.frame_tree_node_id = params.frame_tree_node_id; + load_url_params.referrer = params.referrer; + load_url_params.redirect_chain = params.redirect_chain; + load_url_params.extra_headers = params.extra_headers; + load_url_params.is_renderer_initiated = params.is_renderer_initiated; + load_url_params.transferred_global_request_id = + params.transferred_global_request_id; + load_url_params.should_replace_current_entry = + params.should_replace_current_entry; + + // Only allows the browser-initiated navigation to use POST. + if (params.uses_post && !params.is_renderer_initiated) { + load_url_params.load_type = + NavigationController::LOAD_TYPE_BROWSER_INITIATED_HTTP_POST; + load_url_params.browser_initiated_post_data = + params.browser_initiated_post_data; + } + + source->GetController().LoadURLWithParams(load_url_params); + return source; +} + void Shell::LoadingStateChanged(WebContents* source, bool to_different_document) { UpdateNavigationControls(to_different_document);
diff --git a/content/shell/browser/shell.h b/content/shell/browser/shell.h index 4383625..2581c409 100644 --- a/content/shell/browser/shell.h +++ b/content/shell/browser/shell.h
@@ -107,6 +107,8 @@ #endif // WebContentsDelegate + WebContents* OpenURLFromTab(WebContents* source, + const OpenURLParams& params) override; void AddNewContents(WebContents* source, WebContents* new_contents, WindowOpenDisposition disposition,
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn index ad9596b..c9d3a05 100644 --- a/content/test/BUILD.gn +++ b/content/test/BUILD.gn
@@ -76,6 +76,12 @@ ".", "//content") + if (is_android) { + sources -= [ + "mock_google_streaming_server.cc", + "mock_google_streaming_server.h", + ] + } public_deps += [ "//third_party/WebKit/public:blink" ] deps += [ ":content_test_mojo_bindings", @@ -90,6 +96,7 @@ "//content/public/renderer", "//content/public/utility", "//content/shell:pak", + "//ipc:test_support", "//ipc/mojo", "//media", "//mojo/application/public/cpp:cpp_for_chromium", @@ -376,6 +383,7 @@ "//gin", "//gpu", "//ipc:test_support", + "//media:media_features", "//media:shared_memory_support", "//media:test_support", "//media/audio:test_support",
diff --git a/content/test/content_test_suite.cc b/content/test/content_test_suite.cc index 97d66ff2..2cb9731 100644 --- a/content/test/content_test_suite.cc +++ b/content/test/content_test_suite.cc
@@ -23,7 +23,6 @@ #include "base/mac/scoped_nsautorelease_pool.h" #if !defined(OS_IOS) #include "base/test/mock_chrome_application_mac.h" -#include "content/browser/in_process_io_surface_manager_mac.h" #endif #endif @@ -111,9 +110,6 @@ SurfaceTextureManager::SetInstance( InProcessSurfaceTextureManager::GetInstance()); #endif -#if defined(OS_MACOSX) && !defined(OS_IOS) - gfx::IOSurfaceManager::SetInstance(InProcessIOSurfaceManager::GetInstance()); -#endif #if defined(USE_OZONE) if (!is_child_process) { client_native_pixmap_factory_ = ui::ClientNativePixmapFactory::Create();
diff --git a/content/test/data/media/mediarecorder_test.html b/content/test/data/media/mediarecorder_test.html index 7f8c75c..cacd5ae 100644 --- a/content/test/data/media/mediarecorder_test.html +++ b/content/test/data/media/mediarecorder_test.html
@@ -16,6 +16,12 @@ const DEFAULT_CONSTRAINTS= {audio:true, video:true}; const DEFAULT_RECORDER_MIME_TYPE = ''; const DEFAULT_TIME_SLICE = 100; +const FREQUENCY = 880; +// Note that not all audio sampling rates are supported by the underlying +// Opus audio codec: the valid rates are 8kHz, 12kHz, 16kHz, 24kHz, 48kHz. +// See crbug/569089 for details. +const SAMPLING_RATE = 48000; +const NUM_SAMPLES = 2 * SAMPLING_RATE; // Function assert_throws inspired from Blink's // LayoutTests/resources/testharness.js @@ -23,7 +29,7 @@ function assertThrows(func, description) { try { func.call(this); - failTest('Error:' + func + description + " did not throw!"); + failTest('Error:' + func + description + ' did not throw!'); } catch (e) { console.log(e); reportTestSuccess(); @@ -32,8 +38,8 @@ function createAndStartMediaRecorder(stream, mimeType, slice) { return new Promise(function(resolve, reject) { - document.getElementById("video").src = URL.createObjectURL(stream); - var recorder = new MediaRecorder(stream, {"mimeType" : mimeType}); + document.getElementById('video').src = URL.createObjectURL(stream); + var recorder = new MediaRecorder(stream, {'mimeType' : mimeType}); console.log('Recorder object created.'); if (slice != undefined) { recorder.start(slice); @@ -47,8 +53,7 @@ function createMediaRecorder(stream, mimeType) { return new Promise(function(resolve, reject) { - document.getElementById("video").src = URL.createObjectURL(stream); - var recorder = new MediaRecorder(stream, {"mimeType" : mimeType}); + var recorder = new MediaRecorder(stream, {'mimeType' : mimeType}); console.log('Recorder object created.'); resolve(recorder); }); @@ -117,7 +122,7 @@ }); } -// Tests that when MediaRecorder's start() functioo is called, some data is +// Tests that when MediaRecorder's start() function is called, some data is // made available by media recorder via dataavailable events, containing non // empty blob data. function testStartAndDataAvailable() { @@ -364,7 +369,7 @@ }) .then(function() { theRecorder.ondataavailable = function(event) { - failTest("Received unexpected data after pause!"); + failTest('Received unexpected data after pause!'); }; }) .then(function() { @@ -431,6 +436,40 @@ }); } +// Tests that MediaRecorder can record a 2 Channel audio stream. +function testTwoChannelAudio() { + var audioSize = 0; + var context = new OfflineAudioContext(2, NUM_SAMPLES, SAMPLING_RATE); + var oscillator = context.createOscillator(); + oscillator.type = "sine"; + oscillator.frequency.value = FREQUENCY; + var dest = context.createMediaStreamDestination(); + dest.channelCount = 2; + oscillator.connect(dest); + createMediaRecorder(dest.stream, DEFAULT_RECORDER_MIME_TYPE) + .then(function(recorder) { + recorder.ondataavailable = function(event) { + audioSize += event.data.size; + }; + recorder.start(); + oscillator.start(); + context.startRendering(); + }) + .then(function() { + return waitFor('Make sure the recording has data', + function() { + return audioSize > 0; + }); + }) + .catch(function(err) { + return failTest(err.toString()); + }) + .then(function() { + console.log('audioSize', audioSize); + reportTestSuccess(); + }); +} + </script> </body> </html>
diff --git a/content/test/gpu/gpu_tests/memory_test.py b/content/test/gpu/gpu_tests/memory_test.py index c06c7225..c88ef09 100644 --- a/content/test/gpu/gpu_tests/memory_test.py +++ b/content/test/gpu/gpu_tests/memory_test.py
@@ -7,8 +7,7 @@ from telemetry.page import page_test from telemetry.timeline import model -from telemetry.timeline import tracing_category_filter -from telemetry.timeline import tracing_options +from telemetry.timeline import tracing_config MEMORY_LIMIT_MB = 192 SINGLE_TAB_LIMIT_MB = 192 @@ -86,13 +85,11 @@ def WillNavigateToPage(self, page, tab): # FIXME: Remove webkit.console when blink.console lands in chromium and the # ref builds are updated. crbug.com/386847 - custom_categories = ['webkit.console', 'blink.console', 'gpu'] - category_filter = tracing_category_filter.TracingCategoryFilter() - for c in custom_categories: - category_filter.AddIncludedCategory(c) - options = tracing_options.TracingOptions() - options.enable_chrome_trace = True - tab.browser.platform.tracing_controller.Start(options, category_filter, 60) + config = tracing_config.TracingConfig() + for c in ['webkit.console', 'blink.console', 'gpu']: + config.tracing_category_filter.AddIncludedCategory(c) + config.tracing_options.enable_chrome_trace = True + tab.browser.platform.tracing_controller.Start(config, 60) def _FormatException(self, low_or_high, mb_used): return 'Memory allocation too %s (was %d MB, should be %d MB +/- %d MB)' % (
diff --git a/content/test/gpu/gpu_tests/trace_test.py b/content/test/gpu/gpu_tests/trace_test.py index 35b1192..b5389bd0 100644 --- a/content/test/gpu/gpu_tests/trace_test.py +++ b/content/test/gpu/gpu_tests/trace_test.py
@@ -7,8 +7,7 @@ from telemetry.page import page_test from telemetry.timeline import model as model_module -from telemetry.timeline import tracing_category_filter -from telemetry.timeline import tracing_options +from telemetry.timeline import tracing_config TOPLEVEL_GL_CATEGORY = 'gpu_toplevel' TOPLEVEL_SERVICE_CATEGORY = 'disabled-by-default-gpu.service' @@ -23,6 +22,16 @@ domAutomationController.setAutomationId = function(id) {} domAutomationController.send = function(msg) { + // Issue a read pixel to synchronize the gpu process to ensure + // the asynchronous category enabling is finished. + var canvas = document.createElement("canvas") + canvas.width = 1; + canvas.height = 1; + var gl = canvas.getContext("webgl"); + gl.clear(gl.COLOR_BUFFER_BIT); + var id = new Uint8Array(4); + gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, id); + domAutomationController._finished = true; } @@ -52,11 +61,11 @@ options.AppendExtraBrowserArgs('--enable-logging') def WillNavigateToPage(self, page, tab): - cat_string = ','.join(TOPLEVEL_CATEGORIES) - cat_filter = tracing_category_filter.TracingCategoryFilter(cat_string) - options = tracing_options.TracingOptions() - options.enable_chrome_trace = True - tab.browser.platform.tracing_controller.Start(options, cat_filter, 60) + config = tracing_config.TracingConfig() + for cat in TOPLEVEL_CATEGORIES: + config.tracing_category_filter.AddDisabledByDefault(cat) + config.tracing_options.enable_chrome_trace = True + tab.browser.platform.tracing_controller.Start(config, 60) def _FormatException(self, category): return 'Trace markers for GPU category was not found: %s' % category
diff --git a/content/test/gpu/gpu_tests/trace_test_expectations.py b/content/test/gpu/gpu_tests/trace_test_expectations.py index a1f9d01..764dbce5 100644 --- a/content/test/gpu/gpu_tests/trace_test_expectations.py +++ b/content/test/gpu/gpu_tests/trace_test_expectations.py
@@ -11,7 +11,7 @@ # Sample Usage: # self.Fail('TraceTest.Canvas2DRedBox', # ['mac', 'amd', ('nvidia', 0x1234)], bug=123) - self.Skip('*', bug=512622) + pass class DeviceTraceTestExpectations(GpuTestExpectations): def SetExpectations(self):
diff --git a/content/test/test_blink_web_unit_test_support.cc b/content/test/test_blink_web_unit_test_support.cc index 39e17001..876bca0f 100644 --- a/content/test/test_blink_web_unit_test_support.cc +++ b/content/test/test_blink_web_unit_test_support.cc
@@ -335,17 +335,6 @@ url_loader_factory_->set_delegate(delegate); } -blink::WebString TestBlinkWebUnitTestSupport::webKitRootDir() { - base::FilePath path; - PathService::Get(base::DIR_SOURCE_ROOT, &path); - path = path.Append(FILE_PATH_LITERAL("third_party/WebKit")); - path = base::MakeAbsoluteFilePath(path); - CHECK(!path.empty()); - std::string path_ascii = path.MaybeAsASCII(); - CHECK(!path_ascii.empty()); - return blink::WebString::fromUTF8(path_ascii.c_str()); -} - blink::WebLayerTreeView* TestBlinkWebUnitTestSupport::createLayerTreeViewForTesting() { scoped_ptr<WebLayerTreeViewImplForTesting> view(
diff --git a/content/test/test_blink_web_unit_test_support.h b/content/test/test_blink_web_unit_test_support.h index a655d0c..e4de999 100644 --- a/content/test/test_blink_web_unit_test_support.h +++ b/content/test/test_blink_web_unit_test_support.h
@@ -84,7 +84,6 @@ void unregisterAllMockedURLs() override; void serveAsynchronousMockedRequests() override; void setLoaderDelegate(blink::WebURLLoaderTestDelegate* delegate) override; - blink::WebString webKitRootDir() override; blink::WebLayerTreeView* createLayerTreeViewForTesting() override; blink::WebData readFromFile(const blink::WebString& path) override; blink::WebThread* currentThread() override;
diff --git a/content/test/test_render_view_host.cc b/content/test/test_render_view_host.cc index 5617240..bb5999e 100644 --- a/content/test/test_render_view_host.cc +++ b/content/test/test_render_view_host.cc
@@ -212,27 +212,23 @@ } #endif -TestRenderViewHost::TestRenderViewHost( - SiteInstance* instance, - RenderViewHostDelegate* delegate, - RenderWidgetHostDelegate* widget_delegate, - int32_t routing_id, - int32_t main_frame_routing_id, - bool swapped_out) +TestRenderViewHost::TestRenderViewHost(SiteInstance* instance, + scoped_ptr<RenderWidgetHostImpl> widget, + RenderViewHostDelegate* delegate, + int32_t main_frame_routing_id, + bool swapped_out) : RenderViewHostImpl(instance, + std::move(widget), delegate, - widget_delegate, - routing_id, main_frame_routing_id, swapped_out, - false /* hidden */, false /* has_initialized_audio_host */), delete_counter_(NULL), opener_frame_route_id_(MSG_ROUTING_NONE) { // TestRenderWidgetHostView installs itself into this->view_ in its // constructor, and deletes itself when TestRenderWidgetHostView::Destroy() is // called. - new TestRenderWidgetHostView(this); + new TestRenderWidgetHostView(GetWidget()); } TestRenderViewHost::~TestRenderViewHost() { @@ -259,7 +255,7 @@ const FrameReplicationState& replicated_frame_state, bool window_was_created_with_opener) { DCHECK(!IsRenderViewLive()); - set_renderer_initialized(true); + GetWidget()->set_renderer_initialized(true); DCHECK(IsRenderViewLive()); opener_frame_route_id_ = opener_frame_route_id; RenderFrameHost* main_frame = GetMainFrame(); @@ -274,11 +270,11 @@ } void TestRenderViewHost::SimulateWasHidden() { - WasHidden(); + GetWidget()->WasHidden(); } void TestRenderViewHost::SimulateWasShown() { - WasShown(ui::LatencyInfo()); + GetWidget()->WasShown(ui::LatencyInfo()); } WebPreferences TestRenderViewHost::TestComputeWebkitPrefs() {
diff --git a/content/test/test_render_view_host.h b/content/test/test_render_view_host.h index bcc101e..0cb0913 100644 --- a/content/test/test_render_view_host.h +++ b/content/test/test_render_view_host.h
@@ -203,9 +203,8 @@ public RenderViewHostTester { public: TestRenderViewHost(SiteInstance* instance, + scoped_ptr<RenderWidgetHostImpl> widget, RenderViewHostDelegate* delegate, - RenderWidgetHostDelegate* widget_delegate, - int32_t routing_id, int32_t main_frame_routing_id, bool swapped_out); ~TestRenderViewHost() override;
diff --git a/content/test/test_render_view_host_factory.cc b/content/test/test_render_view_host_factory.cc index 4350960..5f4fb4dd 100644 --- a/content/test/test_render_view_host_factory.cc +++ b/content/test/test_render_view_host_factory.cc
@@ -4,6 +4,7 @@ #include "content/test/test_render_view_host_factory.h" +#include "content/browser/renderer_host/render_widget_host_impl.h" #include "content/browser/site_instance_impl.h" #include "content/public/browser/render_process_host_factory.h" #include "content/test/test_render_view_host.h" @@ -33,8 +34,11 @@ int32_t routing_id, int32_t main_frame_routing_id, bool swapped_out) { - return new TestRenderViewHost(instance, delegate, widget_delegate, routing_id, - main_frame_routing_id, swapped_out); + return new TestRenderViewHost(instance, + make_scoped_ptr(new RenderWidgetHostImpl( + widget_delegate, instance->GetProcess(), + routing_id, false /* hidden */)), + delegate, main_frame_routing_id, swapped_out); } } // namespace content
diff --git a/courgette/label_manager.cc b/courgette/label_manager.cc index f19975d..06f3558 100644 --- a/courgette/label_manager.cc +++ b/courgette/label_manager.cc
@@ -10,6 +10,7 @@ #include <algorithm> #include "base/logging.h" +#include "base/numerics/safe_conversions.h" #include "base/numerics/safe_math.h" #include "courgette/consecutive_range_visitor.h" @@ -17,6 +18,89 @@ LabelManager::RvaVisitor::~RvaVisitor() {} +LabelManager::SimpleIndexAssigner::SimpleIndexAssigner(LabelVector* labels) + : labels_(labels) { + // Find the maximum assigned index. Not bounded by |labels_| size. + int max_index = -1; + for (const Label& label : *labels_) { + if (label.index_ != Label::kNoIndex) + max_index = std::max(max_index, label.index_); + } + + // Initialize |num_index_| and |available_|. + CHECK_GE(max_index + 1, 0); + num_index_ = std::max(base::checked_cast<int>(labels_->size()), + max_index + 1); + available_.resize(num_index_, true); + size_t used = 0; + for (const Label& label : *labels_) { + if (label.index_ != Label::kNoIndex) { + available_.at(label.index_) = false; + ++used; + } + } + VLOG(1) << used << " of " << labels_->size() << " labels pre-assigned."; +} + +LabelManager::SimpleIndexAssigner::~SimpleIndexAssigner() {} + +void LabelManager::SimpleIndexAssigner::DoForwardFill() { + size_t count = 0; + // Inside the loop, if |prev_index| == |kNoIndex| then we try to assign 0. + // This allows 0 (if unused) to be assigned in middle of |labels_|. + int prev_index = Label::kNoIndex; + for (auto p = labels_->begin(); p != labels_->end(); ++p) { + if (p->index_ == Label::kNoIndex) { + int index = (prev_index == Label::kNoIndex) ? 0 : prev_index + 1; + if (index < num_index_ && available_.at(index)) { + p->index_ = index; + available_.at(index) = false; + ++count; + } + } + prev_index = p->index_; + } + VLOG(1) << " fill forward " << count; +} + +void LabelManager::SimpleIndexAssigner::DoBackwardFill() { + size_t count = 0; + // This is asymmetric from DoForwardFill(), to preserve old behavior. + // Inside the loop, if |prev_index| == |kNoIndex| then we skip assignment. + // But we initilaize |prev_index| = |num_index_|, so if the last element in + // |labels_| has no index, then can use |num_index_| - 1 (if unused). We don't + // try this assignment elsewhere. + int prev_index = num_index_; + for (auto p = labels_->rbegin(); p != labels_->rend(); ++p) { + if (p->index_ == Label::kNoIndex && prev_index != Label::kNoIndex) { + int index = prev_index - 1; + if (index >= 0 && available_.at(index)) { + p->index_ = index; + available_.at(index) = false; + ++count; + } + } + prev_index = p->index_; + } + VLOG(1) << " fill backward " << count; +} + +void LabelManager::SimpleIndexAssigner::DoInFill() { + size_t count = 0; + int index = 0; + for (Label& label : *labels_) { + if (label.index_ == Label::kNoIndex) { + while (!available_.at(index)) + ++index; + label.index_ = index; + available_.at(index) = false; + ++index; + ++count; + } + } + VLOG(1) << " infill " << count; +} + LabelManager::LabelManager() {} LabelManager::~LabelManager() {} @@ -74,4 +158,26 @@ return it == labels_.end() || it->rva_ != rva ? nullptr : &(*it); } +void LabelManager::UnassignIndexes() { + for (Label& label : labels_) + label.index_ = Label::kNoIndex; +} + +void LabelManager::DefaultAssignIndexes() { + int cur_index = 0; + for (Label& label : labels_) { + CHECK_EQ(Label::kNoIndex, label.index_); + label.index_ = cur_index++; + } +} + +void LabelManager::AssignRemainingIndexes() { + // This adds some memory overhead, about 1 bit per Label (more if indexes >= + // |labels_.size()| get used). + SimpleIndexAssigner assigner(&labels_); + assigner.DoForwardFill(); + assigner.DoBackwardFill(); + assigner.DoInFill(); +} + } // namespace courgette
diff --git a/courgette/label_manager.h b/courgette/label_manager.h index d155561..1b88024 100644 --- a/courgette/label_manager.h +++ b/courgette/label_manager.h
@@ -15,6 +15,8 @@ namespace courgette { +using LabelVector = std::vector<Label>; + // A container to store and manage Label instances. A key consideration is peak // memory usage reduction. To this end we preallocate Label instances in bulk, // and carefully control transient memory usage when initializing Labels. @@ -37,6 +39,58 @@ virtual void Next() = 0; }; + // A helper class to heuristically complete index assignment for a list of + // Labels that have partially assigned indexes. + // Goal: An address table compresses best when each index is associated with + // an address that is slightly larger than the previous index. + // For example, suppose we have RVAs + // [0x0000, 0x0070, 0x00E0, 0x0150]. + // Consider candidate (RVA, index) assignments A and B: + // A: [(0x0000, 0), (0x0070, 1), (0x00E0, 2), (0x0150, 3)], + // B: [(0x0000, 2), (0x0070, 1), (0x00E0, 0), (0x0150, 3)]. + // To form the address table, we first sort by indexes: + // A: [(0x0000, 0), (0x0070, 1), (0x00E0, 2), (0x0150, 3)], + // B: [(0x00E0, 0), (0x0070, 1), (0x0000, 2), (0x0150, 3)]. + // Then we extract the RVAs for storage: + // A: [0x0000, 0x0070, 0x00E0, 0x0150], + // B: [0x00E0, 0x0070, 0x0000, 0x0150]. + // Clearly A compresses better than B under (signed) delta encoding. + // In Courgette-gen, an assignment algorithm (subclass of AdjustmentMethod) + // creates partial and arbitrary index assignments (to attempt to match one + // file against another). So the sorted case (like A) won't happen in general. + // Our helper class fills in the missing assignments by creating runs of + // consecutive indexes, so once RVAs are sorted by these indexes we'd reduce + // distances between successive RVAs. + class SimpleIndexAssigner { + public: + SimpleIndexAssigner(LabelVector* labels); + ~SimpleIndexAssigner(); + + // Scans forward to assign successive indexes to Labels, using existing + // indexes as start-anchors. + void DoForwardFill(); + + // Scans backward to assign successive indexes to Labels, using existing + // indexes as end-anchors. + void DoBackwardFill(); + + // Assigns all unsigned indexes using what's available, disregarding current + // Label assignment. + void DoInFill(); + + private: + // List of Labels to process. Owned by caller. + LabelVector* labels_; + + // A bound on indexes. + int num_index_ = 0; + + // Tracker for index usage to ensure uniqueness of indexes. + std::vector<bool> available_; + + DISALLOW_COPY_AND_ASSIGN(SimpleIndexAssigner); + }; + LabelManager(); virtual ~LabelManager(); @@ -52,11 +106,18 @@ // the stored Label instance if found, or null otherwise. Label* Find(RVA rva); - // TODO(huangs): Move AssignRemainingIndexes() here. + // Resets all indexes to an unassigend state. + void UnassignIndexes(); + + // Assigns indexes to successive integers from 0, ordered by RVA. + void DefaultAssignIndexes(); + + // Assigns indexes to any Label elements that don't have one yet. + void AssignRemainingIndexes(); protected: // The main list of Label instances, sorted by the |rva_| member. - std::vector<Label> labels_; + LabelVector labels_; private: DISALLOW_COPY_AND_ASSIGN(LabelManager);
diff --git a/courgette/label_manager_unittest.cc b/courgette/label_manager_unittest.cc index acc6240..cc112a85 100644 --- a/courgette/label_manager_unittest.cc +++ b/courgette/label_manager_unittest.cc
@@ -9,9 +9,13 @@ #include <iterator> #include <map> +#include <set> +#include <string> #include <utility> #include <vector> +#include "base/logging.h" +#include "base/macros.h" #include "testing/gtest/include/gtest/gtest.h" namespace courgette { @@ -41,12 +45,17 @@ // Test version of LabelManager: Expose data to test implementation. class TestLabelManager : public LabelManager { public: - size_t LabelCount() const { return labels_.size(); }; + TestLabelManager() {} + + // Using move semantics to optimize injection of test LabelVector. + explicit TestLabelManager(LabelVector&& labels) { labels_ = labels; } + + const LabelVector& Labels() const { return labels_; } }; void CheckLabelManagerContent(TestLabelManager* label_manager, const std::map<RVA, int32_t>& expected) { - EXPECT_EQ(expected.size(), label_manager->LabelCount()); + EXPECT_EQ(expected.size(), label_manager->Labels().size()); for (const auto& rva_and_count : expected) { Label* label = label_manager->Find(rva_and_count.first); EXPECT_TRUE(label != nullptr); @@ -55,6 +64,65 @@ } } +// Instantiates a LabelVector with |n| elements. The |rva_| fields are assigned +// 0, ..., |n| - 1. The other fields are uninitialized. +LabelVector CreateLabelVectorBasic(size_t n) { + LabelVector labels; + labels.reserve(n); + for (size_t i = 0; i < n; ++i) + labels.push_back(Label(i)); + return labels; +} + +// Instantiates a list of Labels, one per character |ch| in |encoded_index|. +// - |rva_| is assigned 0, 1, 2, ... +// - |count_| is assigned 1. +// - |index_| depends on |ch|: '.' => kNoIndex, 'A' => 0, ..., 'Z' => 25. +// Each letter (except '.') can appear at most once in |encoded_index|. +// For example, |encoded_index| = "A.E" initializes 3 Labels: +// [{rva_: 0, count_: 1, index_: 0}, +// {rva_: 1, count_: 1, index_: kNoIndex}, +// {rva_: 2, count_: 1, index_: 4}]. +LabelVector CreateLabelVectorWithIndexes(const std::string& encoded_index) { + LabelVector labels; + size_t n = encoded_index.size(); + labels.reserve(n); + std::set<char> used_ch; + for (size_t i = 0; i < n; ++i) { + Label label(i); + label.count_ = 1; + char ch = encoded_index[i]; + if (ch != '.') { + // Sanity check for test case. + if (ch < 'A' || ch > 'Z' || used_ch.find(ch) != used_ch.end()) + NOTREACHED() << "Malformed test case: " << encoded_index; + used_ch.insert(ch); + label.index_ = ch - 'A'; + } else { + label.index_ = Label::kNoIndex; + } + labels.push_back(label); + } + return labels; +} + +// Returns a string encoding for |index_| assignments for |label_| elements, +// with kNoIndex => '.', 0 => 'A', ..., '25' => 'Z'. Fails if any |index_| +// does not fit the above. +std::string EncodeLabelIndexes(const LabelVector& labels) { + std::string encoded; + encoded.reserve(labels.size()); + for (const Label& label : labels) { + if (label.index_ == Label::kNoIndex) + encoded += '.'; + else if (label.index_ >= 0 && label.index_ <= 'Z' - 'A') + encoded += static_cast<char>(label.index_ + 'A'); + else + NOTREACHED(); + } + return encoded; +} + } // namespace TEST(LabelManagerTest, Basic) { @@ -62,12 +130,12 @@ 0x04000010, 0x04000030, 0x04000020, - 0x04000010, // Redundant + 0x04000010, // Redundant. 0xFEEDF00D, - 0x04000030, // Redundant - 0xFEEDF00D, // Redundant + 0x04000030, // Redundant. + 0xFEEDF00D, // Redundant. 0x00000110, - 0x04000010, // Redundant + 0x04000010, // Redundant. 0xABCD1234 }; std::vector<RVA> test_targets(std::begin(kTestTargetsRaw), @@ -111,7 +179,7 @@ TestRvaVisitor visitor(test_targets.begin(), test_targets.end()); TestLabelManager label_manager; label_manager.Read(&visitor); - EXPECT_EQ(1U, label_manager.LabelCount()); // Deduped to 1 Label. + EXPECT_EQ(1U, label_manager.Labels().size()); // Deduped to 1 Label. Label* label = label_manager.Find(kRva); EXPECT_NE(nullptr, label); @@ -130,9 +198,167 @@ TestRvaVisitor visitor(empty_test_targets.begin(), empty_test_targets.end()); TestLabelManager label_manager; label_manager.Read(&visitor); - EXPECT_EQ(0U, label_manager.LabelCount()); + EXPECT_EQ(0U, label_manager.Labels().size()); for (RVA rva = 0U; rva < 16U; ++rva) EXPECT_EQ(nullptr, label_manager.Find(rva)); } +TEST(LabelManagerTest, EmptyAssign) { + TestLabelManager label_manager_empty; + label_manager_empty.DefaultAssignIndexes(); + label_manager_empty.UnassignIndexes(); + label_manager_empty.AssignRemainingIndexes(); +} + +TEST(LabelManagerTest, TrivialAssign) { + for (size_t size = 0; size < 20; ++size) { + TestLabelManager label_manager(CreateLabelVectorBasic(size)); + // Sanity check. + for (size_t i = 0; i < size; ++i) + EXPECT_EQ(Label::kNoIndex, label_manager.Labels()[i].index_); + + // Default assign. + label_manager.DefaultAssignIndexes(); + for (size_t i = 0; i < size; ++i) + EXPECT_EQ(static_cast<int>(i), label_manager.Labels()[i].index_); + + // Heuristic assign, but since everything's assigned, so no change. + label_manager.AssignRemainingIndexes(); + for (size_t i = 0; i < size; ++i) + EXPECT_EQ(static_cast<int>(i), label_manager.Labels()[i].index_); + + // Unassign. + label_manager.UnassignIndexes(); + for (size_t i = 0; i < size; ++i) + EXPECT_EQ(Label::kNoIndex, label_manager.Labels()[i].index_); + } +} + +// Tests SimpleIndexAssigner fill strategies independently. +TEST(LabelManagerTest, SimpleIndexAssigner) { + using SimpleIndexAssigner = LabelManager::SimpleIndexAssigner; + // See CreateLabelVectorWithIndexes() explanation on how we encode LabelVector + // |index_| values as a string. + const struct TestCase { + const char* input; + const char* expect_forward; + const char* expect_backward; + const char* expect_in; + } kTestCases[] = { + {"", "", "", ""}, + {".", "A", "A", "A"}, + {"....", "ABCD", "ABCD", "ABCD"}, + {"A...", "ABCD", "ABCD", "ABCD"}, + {".A..", ".ABC", ".ACD", "BACD"}, + {"...A", "...A", "...A", "BCDA"}, + {"C...", "CD.A", "C..D", "CABD"}, + {".C..", "ACD.", "BC.D", "ACBD"}, + {"...C", "AB.C", ".ABC", "ABDC"}, + {"D...", "D.AB", "D...", "DABC"}, + {".D..", "AD..", "CD..", "ADBC"}, + {"...D", "ABCD", "ABCD", "ABCD"}, + {"Z...", "Z.AB", "Z...", "ZABC"}, + {".Z..", "AZ..", "YZ..", "AZBC"}, + {"...Z", "ABCZ", "WXYZ", "ABCZ"}, + {"..AZ..", "..AZ..", "..AZ..", "BCAZDE"}, + {"..ZA..", "..ZABC", "XYZA..", "BCZADE"}, + {"A....Z", "ABCDEZ", "AVWXYZ", "ABCDEZ"}, + {"Z....A", "Z....A", "Z....A", "ZBCDEA"}, + {"..CD..", "ABCDEF", "ABCDEF", "ABCDEF"}, + {"..DC..", "ABDC..", "..DCEF", "ABDCEF"}, + {"..MN..", "ABMN..", "KLMN..", "ABMNCD"}, + {"..NM..", "ABNM..", "..NM..", "ABNMCD"}, + {".B.D.F.", "ABCDEFG", "ABCDEFG", "ABCDEFG"}, + {".D.G.J.", "ADEGHJ.", "CDFGIJ.", "ADBGCJE"}, + {".D.Z.J.", "ADEZ.JK", "CDYZIJ.", "ADBZCJE"}, + {".B..E..", "ABCDEFG", "ABCDEFG", "ABCDEFG"}, + {".B..D..", "ABC.DEF", "AB.CDFG", "ABCEDFG"}, + }; + const int kNumFuns = 3; + // TestCase member variable pointers to enable iteration. + const char* TestCase::*expect_ptr[kNumFuns] = { + &TestCase::expect_forward, + &TestCase::expect_backward, + &TestCase::expect_in + }; + // SimpleIndexAssigner member function pointers to enable iteration. + void (SimpleIndexAssigner::*fun_ptrs[kNumFuns])() = { + &SimpleIndexAssigner::DoForwardFill, + &SimpleIndexAssigner::DoBackwardFill, + &SimpleIndexAssigner::DoInFill + }; + for (const auto& test_case : kTestCases) { + // Loop over {forward fill, backward fill, infill}. + for (int i = 0; i < kNumFuns; ++i) { + std::string expect = test_case.*(expect_ptr[i]); + LabelVector labels = CreateLabelVectorWithIndexes(test_case.input); + SimpleIndexAssigner assigner(&labels); + (assigner.*(fun_ptrs[i]))(); + std::string result = EncodeLabelIndexes(labels); + EXPECT_EQ(expect, result); + } + } +} + +// Tests integrated AssignRemainingIndexes(). +TEST(LabelManagerTest, AssignRemainingIndexes) { + const struct { + const char* input; + const char* expect; + } kTestCases[] = { + // Trivial. + {"", ""}, + {"M", "M"}, + {"ABCDEFG", "ABCDEFG"}, + {"THEQUICKBROWNFXJMPSVLAZYDG", "THEQUICKBROWNFXJMPSVLAZYDG"}, + // Forward fill only. + {".", "A"}, + {".......", "ABCDEFG"}, + {"....E..", "ABCDEFG"}, // "E" is at right place. + {".D.B.H.F.", "ADEBCHIFG"}, + {"ZN....", "ZNOPQR"}, // "Z" exists, so 'OPQR" are defined. + {"H.D...A..", "HIDEFGABC"}, + {"...K.DE..H..Z", "ABCKLDEFGHIJZ"}, // "Z" exists, so "L" defined. + // Infill only. + {"E.", "EA"}, + {"...A", "BCDA"}, + {"Z...A", "ZBCDA"}, + {"AN...", "ANBCD"}, + {"...AZ", "BCDAZ"}, + {"....AC", "BDEFAC"}, + {"ED...C...B....A", "EDFGHCIJKBLMNOA"}, + // Forward fill and infill. + {"E..", "EBA"}, // Forward: "A"; in: "B". + {"Z....", "ZDABC"}, // Forward: "ABC"; in: "D". + {".E.....", "AEFGBCD"}, // Forward: "A", "FG"; in: "BCD". + {"....C..", "ABFGCDE"}, // Forward: "AB", "DE"; in: "FG". + {"...Z...", "ABCZDEF"}, // Forward: "ABC"; in: "DEF". + {"...A...", "EFGABCD"}, // Forward: "BCD"; in: "EFG". + // Backward fill only. + {".CA", "BCA"}, + {"...ZA", "WXYZA"}, + {"BA...Z", "BAWXYZ"}, + {"ANM..Z....L...T", "ANMXYZHIJKLQRST"}, + {"....G..Z...LAH", "CDEFGXYZIJKLAH"}, + // Forward fill and backward fill. + {"..ZA..", "XYZABC"}, // Forward: "BC"; backward: "XY". + {".....ZD", "ABCXYZD"}, // Forward: "ABC"; backward: "XY". + {"DA.....", "DABCEFG"}, // Forward: "BC"; backward: "EFG". + // Backward fill and infill. + {"G....DA", "GEFBCDA"}, // Backward: "BC"; in: "EF". + {"..ZBA..", "XYZBACD"}, // Backward: "XY"; in: "CD". + // All. + {".....ZED.", "ABCXYZEDF"}, // Forward: "ABC"; backward: "XY"; in: "F". + {".....GD.", "ABCHFGDE"}, // Forward: "ABC", "E"; backward: "F"; in: "H". + {"..FE..GD..", "ABFECHGDIJ"}, // Forward: "AB"; backward: "IJ"; in: "CH". + }; + for (const auto& test_case : kTestCases) { + TestLabelManager label_manager( + CreateLabelVectorWithIndexes(test_case.input)); + label_manager.AssignRemainingIndexes(); + std::string result = EncodeLabelIndexes(label_manager.Labels()); + EXPECT_EQ(test_case.expect, result); + } +} + } // namespace courgette
diff --git a/dbus/BUILD.gn b/dbus/BUILD.gn index ee154a85..dbeee0c 100644 --- a/dbus/BUILD.gn +++ b/dbus/BUILD.gn
@@ -90,7 +90,6 @@ "object_manager_unittest.cc", "object_proxy_unittest.cc", "property_unittest.cc", - "run_all_unittests.cc", "signal_sender_verification_unittest.cc", "string_util_unittest.cc", "test_service.cc", @@ -103,6 +102,7 @@ ":dbus", ":test_proto", ":test_support", + "//base/test:run_all_unittests", "//base/test:test_support", "//testing/gmock", "//testing/gtest",
diff --git a/dbus/dbus.gyp b/dbus/dbus.gyp index daac2e2..264383ee 100644 --- a/dbus/dbus.gyp +++ b/dbus/dbus.gyp
@@ -89,6 +89,7 @@ 'target_name': 'dbus_unittests', 'type': 'executable', 'dependencies': [ + '../base/base.gyp:run_all_unittests', '../base/base.gyp:test_support_base', '../build/linux/system.gyp:dbus', '../testing/gmock.gyp:gmock', @@ -107,7 +108,6 @@ 'object_manager_unittest.cc', 'object_proxy_unittest.cc', 'property_unittest.cc', - 'run_all_unittests.cc', 'signal_sender_verification_unittest.cc', 'string_util_unittest.cc', 'test_service.cc',
diff --git a/dbus/end_to_end_async_unittest.cc b/dbus/end_to_end_async_unittest.cc index 121c660..8f628649d 100644 --- a/dbus/end_to_end_async_unittest.cc +++ b/dbus/end_to_end_async_unittest.cc
@@ -63,7 +63,7 @@ bus_options.dbus_task_runner = dbus_thread_->task_runner(); bus_ = new Bus(bus_options); object_proxy_ = bus_->GetObjectProxy( - "org.chromium.TestService", + test_service_->service_name(), ObjectPath("/org/chromium/TestObject")); ASSERT_TRUE(bus_->HasDBusThread()); @@ -97,7 +97,7 @@ run_loop_->Run(); // Create a second object proxy for the root object. - root_object_proxy_ = bus_->GetObjectProxy("org.chromium.TestService", + root_object_proxy_ = bus_->GetObjectProxy(test_service_->service_name(), ObjectPath("/")); ASSERT_TRUE(bus_->HasDBusThread()); @@ -147,7 +147,7 @@ // Create new object proxy. object_proxy_ = bus_->GetObjectProxy( - "org.chromium.TestService", + test_service_->service_name(), ObjectPath("/org/chromium/TestObject")); } @@ -435,7 +435,7 @@ // Remove the object proxy before receiving the result. // This results in cancelling the pending method call. - bus_->RemoveObjectProxy("org.chromium.TestService", + bus_->RemoveObjectProxy(test_service_->service_name(), ObjectPath("/org/chromium/TestObject"), base::Bind(&base::DoNothing)); @@ -517,7 +517,7 @@ const ObjectPath invalid_object_path("/org/chromium/TestObject/"); // Replace object proxy with new one. - object_proxy_ = bus_->GetObjectProxy("org.chromium.TestService", + object_proxy_ = bus_->GetObjectProxy(test_service_->service_name(), invalid_object_path); MethodCall method_call("org.chromium.TestInterface", "Echo");
diff --git a/dbus/end_to_end_sync_unittest.cc b/dbus/end_to_end_sync_unittest.cc index 1167d96..47dc9b1 100644 --- a/dbus/end_to_end_sync_unittest.cc +++ b/dbus/end_to_end_sync_unittest.cc
@@ -35,7 +35,7 @@ client_bus_options.connection_type = Bus::PRIVATE; client_bus_ = new Bus(client_bus_options); object_proxy_ = client_bus_->GetObjectProxy( - "org.chromium.TestService", + test_service_->service_name(), ObjectPath("/org/chromium/TestObject")); ASSERT_FALSE(client_bus_->HasDBusThread()); } @@ -112,7 +112,7 @@ const ObjectPath invalid_object_path("/org/chromium/TestObject/"); // Replace object proxy with new one. - object_proxy_ = client_bus_->GetObjectProxy("org.chromium.TestService", + object_proxy_ = client_bus_->GetObjectProxy(test_service_->service_name(), invalid_object_path); MethodCall method_call("org.chromium.TestInterface", "Echo");
diff --git a/dbus/object_manager_unittest.cc b/dbus/object_manager_unittest.cc index fa83034..443210c 100644 --- a/dbus/object_manager_unittest.cc +++ b/dbus/object_manager_unittest.cc
@@ -87,7 +87,7 @@ ASSERT_TRUE(bus_->HasDBusThread()); object_manager_ = bus_->GetObjectManager( - "org.chromium.TestService", + test_service_->service_name(), ObjectPath("/org/chromium/TestService")); object_manager_->RegisterInterface("org.chromium.TestInterface", this); @@ -189,7 +189,7 @@ void PerformAction(const std::string& action, const ObjectPath& object_path) { ObjectProxy* object_proxy = bus_->GetObjectProxy( - "org.chromium.TestService", + test_service_->service_name(), ObjectPath("/org/chromium/TestObject")); MethodCall method_call("org.chromium.TestInterface", "PerformAction"); @@ -288,7 +288,7 @@ TEST_F(ObjectManagerTest, SameObject) { ObjectManager* object_manager = bus_->GetObjectManager( - "org.chromium.TestService", + test_service_->service_name(), ObjectPath("/org/chromium/TestService")); EXPECT_EQ(object_manager_, object_manager); } @@ -302,7 +302,7 @@ TEST_F(ObjectManagerTest, DifferentObjectForPath) { ObjectManager* object_manager = bus_->GetObjectManager( - "org.chromium.TestService", + test_service_->service_name(), ObjectPath("/org/chromium/DifferentService")); EXPECT_NE(object_manager_, object_manager); } @@ -387,7 +387,7 @@ object_manager_->UnregisterInterface("org.chromium.TestInterface"); run_loop_.reset(new base::RunLoop); EXPECT_TRUE(bus_->RemoveObjectManager( - "org.chromium.TestService", + test_service_->service_name(), ObjectPath("/org/chromium/TestService"), run_loop_->QuitClosure())); run_loop_->Run(); @@ -396,7 +396,7 @@ ObjectPath("/org/chromium/TestService")); object_manager_ = bus_->GetObjectManager( - "org.chromium.TestService", + test_service_->service_name(), ObjectPath("/org/chromium/TestService")); object_manager_->RegisterInterface("org.chromium.TestInterface", this);
diff --git a/dbus/object_proxy_unittest.cc b/dbus/object_proxy_unittest.cc index 22130b6..05c1294 100644 --- a/dbus/object_proxy_unittest.cc +++ b/dbus/object_proxy_unittest.cc
@@ -20,16 +20,12 @@ bus_options.bus_type = Bus::SESSION; bus_options.connection_type = Bus::PRIVATE; bus_ = new Bus(bus_options); - - object_proxy_ = bus_->GetObjectProxy( - "org.chromium.TestService", ObjectPath("/org/chromium/TestObject")); } void TearDown() override { bus_->ShutdownAndBlock(); } base::MessageLoopForIO message_loop_; scoped_refptr<Bus> bus_; - ObjectProxy* object_proxy_; }; // Used as a WaitForServiceToBeAvailableCallback. @@ -43,14 +39,17 @@ TEST_F(ObjectProxyTest, WaitForServiceToBeAvailable) { scoped_ptr<base::RunLoop> run_loop; + TestService::Options options; + TestService test_service(options); + // Callback is not yet called because the service is not available. - object_proxy_->WaitForServiceToBeAvailable( + ObjectProxy* object_proxy = bus_->GetObjectProxy( + test_service.service_name(), ObjectPath("/org/chromium/TestObject")); + object_proxy->WaitForServiceToBeAvailable( base::Bind(&OnServiceIsAvailable, &run_loop)); base::RunLoop().RunUntilIdle(); // Start the service. - TestService::Options options; - TestService test_service(options); ASSERT_TRUE(test_service.StartService()); ASSERT_TRUE(test_service.WaitUntilServiceIsStarted()); ASSERT_TRUE(test_service.has_ownership()); @@ -61,7 +60,7 @@ // Callback is called because the service is already available. run_loop.reset(new base::RunLoop); - object_proxy_->WaitForServiceToBeAvailable( + object_proxy->WaitForServiceToBeAvailable( base::Bind(&OnServiceIsAvailable, &run_loop)); run_loop->Run();
diff --git a/dbus/property_unittest.cc b/dbus/property_unittest.cc index b6bbb18..f1592849 100644 --- a/dbus/property_unittest.cc +++ b/dbus/property_unittest.cc
@@ -77,7 +77,7 @@ bus_options.dbus_task_runner = dbus_thread_->task_runner(); bus_ = new Bus(bus_options); object_proxy_ = bus_->GetObjectProxy( - "org.chromium.TestService", + test_service_->service_name(), ObjectPath("/org/chromium/TestObject")); ASSERT_TRUE(bus_->HasDBusThread());
diff --git a/dbus/run_all_unittests.cc b/dbus/run_all_unittests.cc deleted file mode 100644 index a758d54..0000000 --- a/dbus/run_all_unittests.cc +++ /dev/null
@@ -1,14 +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 "base/bind.h" -#include "base/test/launcher/unit_test_launcher.h" -#include "base/test/test_suite.h" - -int main(int argc, char** argv) { - base::TestSuite test_suite(argc, argv); - return base::LaunchUnitTestsSerially( - argc, argv, - base::Bind(&base::TestSuite::Run, base::Unretained(&test_suite))); -}
diff --git a/dbus/signal_sender_verification_unittest.cc b/dbus/signal_sender_verification_unittest.cc index 0cedda7..785948a 100644 --- a/dbus/signal_sender_verification_unittest.cc +++ b/dbus/signal_sender_verification_unittest.cc
@@ -40,6 +40,11 @@ thread_options.message_loop_type = base::MessageLoop::TYPE_IO; ASSERT_TRUE(dbus_thread_->StartWithOptions(thread_options)); + // Create the test service, using the D-Bus thread. + TestService::Options options; + options.dbus_task_runner = dbus_thread_->task_runner(); + test_service_.reset(new TestService(options)); + // Create the client, using the D-Bus thread. Bus::Options bus_options; bus_options.bus_type = Bus::SESSION; @@ -47,7 +52,7 @@ bus_options.dbus_task_runner = dbus_thread_->task_runner(); bus_ = new Bus(bus_options); object_proxy_ = bus_->GetObjectProxy( - "org.chromium.TestService", + test_service_->service_name(), ObjectPath("/org/chromium/TestObject")); ASSERT_TRUE(bus_->HasDBusThread()); @@ -69,10 +74,7 @@ run_loop_.reset(new base::RunLoop); run_loop_->Run(); - // Start the test service, using the D-Bus thread. - TestService::Options options; - options.dbus_task_runner = dbus_thread_->task_runner(); - test_service_.reset(new TestService(options)); + // Start the test service. ASSERT_TRUE(test_service_->StartService()); ASSERT_TRUE(test_service_->WaitUntilServiceIsStarted()); ASSERT_TRUE(test_service_->HasDBusThread()); @@ -80,6 +82,7 @@ // Same setup for the second TestService. This service should not have the // ownership of the name at this point. + options.service_name = test_service_->service_name(); test_service2_.reset(new TestService(options)); ASSERT_TRUE(test_service2_->StartService()); ASSERT_TRUE(test_service2_->WaitUntilServiceIsStarted()); @@ -280,6 +283,7 @@ TestService::Options options; options.dbus_task_runner = dbus_thread_->task_runner(); options.request_ownership_options = Bus::REQUIRE_PRIMARY_ALLOW_REPLACEMENT; + options.service_name = test_service_->service_name(); TestService stealable_test_service(options); ASSERT_TRUE(stealable_test_service.StartService()); ASSERT_TRUE(stealable_test_service.WaitUntilServiceIsStarted()); @@ -331,7 +335,7 @@ const char kMessage[] = "hello, world"; ObjectProxy* object_proxy2 = bus_->GetObjectProxy( - "org.chromium.TestService", + test_service_->service_name(), ObjectPath("/org/chromium/DifferentObject")); bool second_name_owner_changed_called = false;
diff --git a/dbus/test_service.cc b/dbus/test_service.cc index a4e152a..7b36082 100644 --- a/dbus/test_service.cc +++ b/dbus/test_service.cc
@@ -10,6 +10,7 @@ #include <vector> #include "base/bind.h" +#include "base/guid.h" #include "base/test/test_timeouts.h" #include "base/threading/platform_thread.h" #include "dbus/bus.h" @@ -41,6 +42,7 @@ TestService::TestService(const Options& options) : base::Thread("TestService"), + service_name_(options.service_name), request_ownership_options_(options.request_ownership_options), dbus_task_runner_(options.dbus_task_runner), on_name_obtained_(false, false), @@ -49,6 +51,9 @@ has_ownership_(false), exported_object_(NULL), exported_object_manager_(NULL) { + if (service_name_.empty()) { + service_name_ = "org.chromium.TestService-" + base::GenerateGUID(); + } } TestService::~TestService() { @@ -113,7 +118,7 @@ MessageWriter writer(&signal); writer.AppendString(message); - bus_->RequestOwnership("org.chromium.TestService", + bus_->RequestOwnership(service_name_, request_ownership_options_, base::Bind(&TestService::OnOwnership, base::Unretained(this), @@ -134,7 +139,7 @@ void TestService::RequestOwnershipInternal( base::Callback<void(bool)> callback) { - bus_->RequestOwnership("org.chromium.TestService", + bus_->RequestOwnership(service_name_, request_ownership_options_, base::Bind(&TestService::OnOwnership, base::Unretained(this), @@ -161,7 +166,7 @@ void TestService::ReleaseOwnershipInternal( base::Closure callback) { - bus_->ReleaseOwnership("org.chromium.TestService"); + bus_->ReleaseOwnership(service_name_); has_ownership_ = false; bus_->GetOriginTaskRunner()->PostTask( @@ -188,7 +193,7 @@ if (num_exported_methods_ == kNumMethodsToExport) { // As documented in exported_object.h, the service name should be // requested after all methods are exposed. - bus_->RequestOwnership("org.chromium.TestService", + bus_->RequestOwnership(service_name_, request_ownership_options_, base::Bind(&TestService::OnOwnership, base::Unretained(this),
diff --git a/dbus/test_service.h b/dbus/test_service.h index de4aa72..e2ed480 100644 --- a/dbus/test_service.h +++ b/dbus/test_service.h
@@ -40,6 +40,9 @@ // Flags governing parameters of service ownership request. Bus::ServiceOwnershipOptions request_ownership_options; + + // Name of this service (randomly generated name will be used if empty). + std::string service_name; }; // The number of methods we'll export. @@ -78,6 +81,9 @@ // |callback| will be called when the ownership has been released. void ReleaseOwnership(base::Closure callback); + // Returns the name of this service. + const std::string& service_name() const { return service_name_; } + // Returns whether this instance has the name ownership or not. bool has_ownership() const { return has_ownership_; } @@ -199,6 +205,9 @@ dbus::ExportedObject::ResponseSender response_sender, bool success); + // Name of this service. + std::string service_name_; + // Options to use when requesting service ownership. Bus::ServiceOwnershipOptions request_ownership_options_;
diff --git a/device/bluetooth/test/mock_bluetooth_central_manager_mac.h b/device/bluetooth/test/mock_bluetooth_central_manager_mac.h index 876bd477..6e60614 100644 --- a/device/bluetooth/test/mock_bluetooth_central_manager_mac.h +++ b/device/bluetooth/test/mock_bluetooth_central_manager_mac.h
@@ -26,13 +26,6 @@ @property(nonatomic, assign) id<CBCentralManagerDelegate> delegate; @property(nonatomic, assign) CBCentralManagerState state; -// Designated initializer -- (instancetype)init; - -- (instancetype)initWithDelegate:(id<CBCentralManagerDelegate>)delegate - queue:(dispatch_queue_t)queue - options:(NSDictionary*)options; - - (void)scanForPeripheralsWithServices:(NSArray*)serviceUUIDs options:(NSDictionary*)options;
diff --git a/device/bluetooth/test/mock_bluetooth_central_manager_mac.mm b/device/bluetooth/test/mock_bluetooth_central_manager_mac.mm index ca6164c..96e7ce9 100644 --- a/device/bluetooth/test/mock_bluetooth_central_manager_mac.mm +++ b/device/bluetooth/test/mock_bluetooth_central_manager_mac.mm
@@ -11,18 +11,6 @@ @synthesize delegate = _delegate; @synthesize state = _state; -- (instancetype)init { - _scanForPeripheralsCallCount = 0; - _stopScanCallCount = 0; - return self; -} - -- (instancetype)initWithDelegate:(id<CBCentralManagerDelegate>)delegate - queue:(dispatch_queue_t)queue - options:(NSDictionary*)options { - return [self init]; -} - - (void)scanForPeripheralsWithServices:(NSArray*)serviceUUIDs options:(NSDictionary*)options { _scanForPeripheralsCallCount++;
diff --git a/device/serial/BUILD.gn b/device/serial/BUILD.gn index 474317e..ae6e00a 100644 --- a/device/serial/BUILD.gn +++ b/device/serial/BUILD.gn
@@ -5,6 +5,9 @@ import("//build/config/features.gni") import("//mojo/public/tools/bindings/mojom.gni") +# Library works only on desktop platforms. +assert(is_win || is_linux || is_mac) + # GYP version: device/serial/serial.gyp:device_serial static_library("serial") { output_name = "device_serial"
diff --git a/device/test/run_all_unittests.cc b/device/test/run_all_unittests.cc index b70df54..76a4996 100644 --- a/device/test/run_all_unittests.cc +++ b/device/test/run_all_unittests.cc
@@ -11,11 +11,13 @@ #if defined(OS_ANDROID) #include "base/android/jni_android.h" #include "device/bluetooth/android/bluetooth_jni_registrar.h" +#include "device/usb/android/usb_jni_registrar.h" #endif int main(int argc, char** argv) { #if defined(OS_ANDROID) device::android::RegisterBluetoothJni(base::android::AttachCurrentThread()); + device::android::RegisterUsbJni(base::android::AttachCurrentThread()); #endif base::TestSuite test_suite(argc, argv);
diff --git a/device/usb/BUILD.gn b/device/usb/BUILD.gn index 99e12ca..6adc36f 100644 --- a/device/usb/BUILD.gn +++ b/device/usb/BUILD.gn
@@ -6,23 +6,39 @@ assert(!is_ios) +if (is_android) { + import("//build/config/android/rules.gni") # For generate_jni(). +} + source_ids = "//third_party/usb_ids/usb.ids" generated_ids = "$target_gen_dir/usb_ids_gen.cc" source_set("usb") { sources = [ + "android/usb_jni_registrar.cc", + "android/usb_jni_registrar.h", + "usb_configuration_android.cc", + "usb_configuration_android.h", "usb_descriptors.cc", "usb_descriptors.h", "usb_device.cc", "usb_device.h", + "usb_device_android.cc", + "usb_device_android.h", "usb_device_filter.cc", "usb_device_filter.h", "usb_device_handle.cc", "usb_device_handle.h", + "usb_endpoint_android.cc", + "usb_endpoint_android.h", "usb_ids.cc", "usb_ids.h", + "usb_interface_android.cc", + "usb_interface_android.h", "usb_service.cc", "usb_service.h", + "usb_service_android.cc", + "usb_service_android.h", "webusb_descriptors.cc", "webusb_descriptors.h", generated_ids, @@ -42,10 +58,7 @@ } if (is_android) { - sources += [ - "usb_service_android.cc", - "usb_service_android.h", - ] + deps += [ ":jni_headers" ] } else { sources += [ "usb_context.cc", @@ -111,3 +124,32 @@ # Only the device_usb target can depend on us. visibility = [ ":usb" ] } + +if (is_android) { + java_sources_needing_jni = [ + "android/java/src/org/chromium/device/usb/ChromeUsbConfiguration.java", + "android/java/src/org/chromium/device/usb/ChromeUsbDevice.java", + "android/java/src/org/chromium/device/usb/ChromeUsbEndpoint.java", + "android/java/src/org/chromium/device/usb/ChromeUsbInterface.java", + "android/java/src/org/chromium/device/usb/ChromeUsbService.java", + ] + + generate_jni("jni_headers") { + sources = java_sources_needing_jni + jni_package = "device" + } + + java_cpp_enum("usb_descriptors_javagen") { + sources = [ + "usb_descriptors.h", + ] + } + + android_library("java") { + java_files = java_sources_needing_jni + deps = [ + "//base:base_java", + ] + srcjar_deps = [ ":usb_descriptors_javagen" ] + } +}
diff --git a/device/usb/DEPS b/device/usb/DEPS index 25ff287..b1c259f 100644 --- a/device/usb/DEPS +++ b/device/usb/DEPS
@@ -1,6 +1,7 @@ include_rules = [ "+chromeos", "+dbus", + "+jni", "-net", "+net/base",
diff --git a/device/usb/android/java/src/org/chromium/device/usb/ChromeUsbConfiguration.java b/device/usb/android/java/src/org/chromium/device/usb/ChromeUsbConfiguration.java new file mode 100644 index 0000000..90371e5 --- /dev/null +++ b/device/usb/android/java/src/org/chromium/device/usb/ChromeUsbConfiguration.java
@@ -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. + +package org.chromium.device.usb; + +import android.annotation.TargetApi; +import android.hardware.usb.UsbConfiguration; +import android.hardware.usb.UsbInterface; +import android.os.Build; + +import org.chromium.base.Log; +import org.chromium.base.annotations.CalledByNative; +import org.chromium.base.annotations.JNINamespace; + +/** + * Exposes android.hardware.usb.UsbConfiguration as necessary for C++ + * device::UsbConfigurationAndroid. + * + * Lifetime is controlled by device::UsbConfigurationAndroid. + */ +@JNINamespace("device") +@TargetApi(Build.VERSION_CODES.LOLLIPOP) +final class ChromeUsbConfiguration { + private static final String TAG = "Usb"; + + final UsbConfiguration mConfiguration; + + private ChromeUsbConfiguration(UsbConfiguration configuration) { + mConfiguration = configuration; + Log.v(TAG, "ChromeUsbConfiguration created."); + } + + @CalledByNative + private static ChromeUsbConfiguration create(UsbConfiguration configuration) { + return new ChromeUsbConfiguration(configuration); + } + + @CalledByNative + private int getConfigurationValue() { + return mConfiguration.getId(); + } + + @CalledByNative + private boolean isSelfPowered() { + return mConfiguration.isSelfPowered(); + } + + @CalledByNative + private boolean isRemoteWakeup() { + return mConfiguration.isRemoteWakeup(); + } + + @CalledByNative + private int getMaxPower() { + return mConfiguration.getMaxPower(); + } + + @CalledByNative + private UsbInterface[] getInterfaces() { + int count = mConfiguration.getInterfaceCount(); + UsbInterface[] interfaces = new UsbInterface[count]; + for (int i = 0; i < count; ++i) { + interfaces[i] = mConfiguration.getInterface(i); + } + return interfaces; + } +}
diff --git a/device/usb/android/java/src/org/chromium/device/usb/ChromeUsbDevice.java b/device/usb/android/java/src/org/chromium/device/usb/ChromeUsbDevice.java new file mode 100644 index 0000000..92e4e148 --- /dev/null +++ b/device/usb/android/java/src/org/chromium/device/usb/ChromeUsbDevice.java
@@ -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. + +package org.chromium.device.usb; + +import android.annotation.TargetApi; +import android.hardware.usb.UsbConfiguration; +import android.hardware.usb.UsbDevice; +import android.hardware.usb.UsbInterface; +import android.os.Build; + +import org.chromium.base.Log; +import org.chromium.base.annotations.CalledByNative; +import org.chromium.base.annotations.JNINamespace; + +/** + * Exposes android.hardware.usb.UsbDevice as necessary for C++ + * device::UsbDeviceAndroid. + * + * Lifetime is controlled by device::UsbDeviceAndroid. + */ +@JNINamespace("device") +final class ChromeUsbDevice { + private static final String TAG = "Usb"; + + final UsbDevice mDevice; + + private ChromeUsbDevice(UsbDevice device) { + mDevice = device; + Log.v(TAG, "ChromeUsbDevice created."); + } + + @CalledByNative + private static ChromeUsbDevice create(UsbDevice device) { + return new ChromeUsbDevice(device); + } + + @CalledByNative + private int getVendorId() { + return mDevice.getVendorId(); + } + + @CalledByNative + private int getProductId() { + return mDevice.getProductId(); + } + + @CalledByNative + private String getManufacturerName() { + return mDevice.getManufacturerName(); + } + + @CalledByNative + private String getProductName() { + return mDevice.getProductName(); + } + + @CalledByNative + private String getSerialNumber() { + return mDevice.getSerialNumber(); + } + + @TargetApi(Build.VERSION_CODES.LOLLIPOP) + @CalledByNative + private UsbConfiguration[] getConfigurations() { + int count = mDevice.getConfigurationCount(); + UsbConfiguration[] configurations = new UsbConfiguration[count]; + for (int i = 0; i < count; ++i) { + configurations[i] = mDevice.getConfiguration(i); + } + return configurations; + } + + @CalledByNative + private UsbInterface[] getInterfaces() { + int count = mDevice.getInterfaceCount(); + UsbInterface[] interfaces = new UsbInterface[count]; + for (int i = 0; i < count; ++i) { + interfaces[i] = mDevice.getInterface(i); + } + return interfaces; + } +}
diff --git a/device/usb/android/java/src/org/chromium/device/usb/ChromeUsbEndpoint.java b/device/usb/android/java/src/org/chromium/device/usb/ChromeUsbEndpoint.java new file mode 100644 index 0000000..135dc51 --- /dev/null +++ b/device/usb/android/java/src/org/chromium/device/usb/ChromeUsbEndpoint.java
@@ -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. + +package org.chromium.device.usb; + +import android.hardware.usb.UsbConstants; +import android.hardware.usb.UsbEndpoint; + +import org.chromium.base.Log; +import org.chromium.base.annotations.CalledByNative; +import org.chromium.base.annotations.JNINamespace; + +/** + * Exposes android.hardware.usb.UsbEndpoint as necessary for C++ + * device::UsbEndpointAndroid. + * + * Lifetime is controlled by device::UsbEndpointAndroid. + */ +@JNINamespace("device") +final class ChromeUsbEndpoint { + private static final String TAG = "Usb"; + + final UsbEndpoint mEndpoint; + + private ChromeUsbEndpoint(UsbEndpoint endpoint) { + mEndpoint = endpoint; + Log.v(TAG, "ChromeUsbEndpoint created."); + } + + @CalledByNative + private static ChromeUsbEndpoint create(UsbEndpoint endpoint) { + return new ChromeUsbEndpoint(endpoint); + } + + @CalledByNative + private int getAddress() { + return mEndpoint.getAddress(); + } + + @CalledByNative + private int getDirection() { + switch (mEndpoint.getDirection()) { + case UsbConstants.USB_DIR_IN: + return UsbEndpointDirection.USB_DIRECTION_INBOUND; + case UsbConstants.USB_DIR_OUT: + return UsbEndpointDirection.USB_DIRECTION_OUTBOUND; + default: + throw new AssertionError(); + } + } + + @CalledByNative + private int getMaxPacketSize() { + return mEndpoint.getMaxPacketSize(); + } + + @CalledByNative + private int getAttributes() { + return mEndpoint.getAttributes(); + } + + @CalledByNative + private int getType() { + switch (mEndpoint.getType()) { + case UsbConstants.USB_ENDPOINT_XFER_CONTROL: + return UsbTransferType.USB_TRANSFER_CONTROL; + case UsbConstants.USB_ENDPOINT_XFER_ISOC: + return UsbTransferType.USB_TRANSFER_ISOCHRONOUS; + case UsbConstants.USB_ENDPOINT_XFER_BULK: + return UsbTransferType.USB_TRANSFER_BULK; + case UsbConstants.USB_ENDPOINT_XFER_INT: + return UsbTransferType.USB_TRANSFER_INTERRUPT; + default: + throw new AssertionError(); + } + } + + @CalledByNative + private int getInterval() { + return mEndpoint.getInterval(); + } +}
diff --git a/device/usb/android/java/src/org/chromium/device/usb/ChromeUsbInterface.java b/device/usb/android/java/src/org/chromium/device/usb/ChromeUsbInterface.java new file mode 100644 index 0000000..cd4f492 --- /dev/null +++ b/device/usb/android/java/src/org/chromium/device/usb/ChromeUsbInterface.java
@@ -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. + +package org.chromium.device.usb; + +import android.hardware.usb.UsbEndpoint; +import android.hardware.usb.UsbInterface; + +import org.chromium.base.Log; +import org.chromium.base.annotations.CalledByNative; +import org.chromium.base.annotations.JNINamespace; + +/** + * Exposes android.hardware.usb.UsbInterface as necessary for C++ + * device::UsbInterfaceAndroid. + * + * Lifetime is controlled by device::UsbInterfaceAndroid. + */ +@JNINamespace("device") +final class ChromeUsbInterface { + private static final String TAG = "Usb"; + + final UsbInterface mInterface; + + private ChromeUsbInterface(UsbInterface iface) { + mInterface = iface; + Log.v(TAG, "ChromeUsbInterface created."); + } + + @CalledByNative + private static ChromeUsbInterface create(UsbInterface iface) { + return new ChromeUsbInterface(iface); + } + + @CalledByNative + private int getInterfaceNumber() { + return mInterface.getId(); + } + + @CalledByNative + private int getAlternateSetting() { + return mInterface.getAlternateSetting(); + } + + @CalledByNative + private int getInterfaceClass() { + return mInterface.getInterfaceClass(); + } + + @CalledByNative + private int getInterfaceSubclass() { + return mInterface.getInterfaceSubclass(); + } + + @CalledByNative + private int getInterfaceProtocol() { + return mInterface.getInterfaceProtocol(); + } + + @CalledByNative + private UsbEndpoint[] getEndpoints() { + int count = mInterface.getEndpointCount(); + UsbEndpoint[] endpoints = new UsbEndpoint[count]; + for (int i = 0; i < count; ++i) { + endpoints[i] = mInterface.getEndpoint(i); + } + return endpoints; + } +}
diff --git a/device/usb/android/java/src/org/chromium/device/usb/ChromeUsbService.java b/device/usb/android/java/src/org/chromium/device/usb/ChromeUsbService.java new file mode 100644 index 0000000..834ddb1 --- /dev/null +++ b/device/usb/android/java/src/org/chromium/device/usb/ChromeUsbService.java
@@ -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. + +package org.chromium.device.usb; + +import android.content.Context; +import android.hardware.usb.UsbDevice; +import android.hardware.usb.UsbManager; + +import org.chromium.base.Log; +import org.chromium.base.annotations.CalledByNative; +import org.chromium.base.annotations.JNINamespace; + +import java.util.HashMap; + +/** + * Exposes android.hardware.usb.UsbManager as necessary for C++ + * device::UsbServiceAndroid. + * + * Lifetime is controlled by device::UsbServiceAndroid. + */ +@JNINamespace("device") +final class ChromeUsbService { + private static final String TAG = "Usb"; + + Context mContext; + + private ChromeUsbService(Context context) { + mContext = context; + Log.v(TAG, "ChromeUsbService created."); + } + + @CalledByNative + private static ChromeUsbService create(Context context) { + return new ChromeUsbService(context); + } + + @CalledByNative + private Object[] getDevices() { + UsbManager manager = (UsbManager) mContext.getSystemService(Context.USB_SERVICE); + HashMap<String, UsbDevice> deviceList = manager.getDeviceList(); + return deviceList.values().toArray(); + } +}
diff --git a/device/usb/android/usb_jni_registrar.cc b/device/usb/android/usb_jni_registrar.cc new file mode 100644 index 0000000..1e53c5b --- /dev/null +++ b/device/usb/android/usb_jni_registrar.cc
@@ -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. + +#include "device/usb/android/usb_jni_registrar.h" + +#include "base/android/jni_android.h" +#include "base/android/jni_registrar.h" +#include "device/usb/usb_configuration_android.h" +#include "device/usb/usb_device_android.h" +#include "device/usb/usb_endpoint_android.h" +#include "device/usb/usb_interface_android.h" +#include "device/usb/usb_service_android.h" + +namespace device { +namespace android { +namespace { + +const base::android::RegistrationMethod kRegisteredMethods[] = { + {"UsbConfigurationAndroid", device::UsbConfigurationAndroid::RegisterJNI}, + {"UsbDeviceAndroid", device::UsbDeviceAndroid::RegisterJNI}, + {"UsbEndpointAndroid", device::UsbEndpointAndroid::RegisterJNI}, + {"UsbInterfaceAndroid", device::UsbInterfaceAndroid::RegisterJNI}, + {"UsbServiceAndroid", device::UsbServiceAndroid::RegisterJNI}, +}; + +} // namespace + +bool RegisterUsbJni(JNIEnv* env) { + return RegisterNativeMethods(env, kRegisteredMethods, + arraysize(kRegisteredMethods)); +} + +} // namespace android +} // namespace device
diff --git a/device/usb/android/usb_jni_registrar.h b/device/usb/android/usb_jni_registrar.h new file mode 100644 index 0000000..a691583 --- /dev/null +++ b/device/usb/android/usb_jni_registrar.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 DEVICE_USB_ANDROID_USB_JNI_REGISTRAR_H_ +#define DEVICE_USB_ANDROID_USB_JNI_REGISTRAR_H_ + +#include <jni.h> + +namespace device { +namespace android { + +// Registers C++ methods in device/usb classes with JNI. +// See https://www.chromium.org/developers/design-documents/android-jni +// +// Must be called before classes in the USB module are used. +bool RegisterUsbJni(JNIEnv* env); + +} // namespace android +} // namespace device + +#endif // DEVICE_USB_ANDROID_USB_JNI_REGISTRAR_H_
diff --git a/device/usb/mock_usb_device.h b/device/usb/mock_usb_device.h index c25a915b..91bb0bb 100644 --- a/device/usb/mock_usb_device.h +++ b/device/usb/mock_usb_device.h
@@ -5,12 +5,12 @@ #ifndef DEVICE_USB_MOCK_USB_DEVICE_H_ #define DEVICE_USB_MOCK_USB_DEVICE_H_ -#include "device/usb/usb_device.h" - #include <stdint.h> #include <string> +#include <vector> +#include "device/usb/usb_device.h" #include "device/usb/usb_device_handle.h" #include "testing/gmock/include/gmock/gmock.h" @@ -41,7 +41,6 @@ const std::vector<UsbConfigDescriptor>& configurations); MOCK_METHOD1(Open, void(const OpenCallback&)); - MOCK_METHOD1(Close, bool(scoped_refptr<UsbDeviceHandle>)); MOCK_METHOD0(GetActiveConfiguration, const device::UsbConfigDescriptor*()); private:
diff --git a/device/usb/usb.gyp b/device/usb/usb.gyp index 453ba1aa..a68b187b 100644 --- a/device/usb/usb.gyp +++ b/device/usb/usb.gyp
@@ -20,6 +20,10 @@ '../..', ], 'sources': [ + 'android/usb_jni_registrar.cc', + 'android/usb_jni_registrar.h', + 'usb_configuration_android.cc', + 'usb_configuration_android.h', 'usb_context.cc', 'usb_context.h', 'usb_descriptors.cc', @@ -28,18 +32,26 @@ 'usb_device_impl.h', 'usb_device.cc', 'usb_device.h', + 'usb_device_android.cc', + 'usb_device_android.h', 'usb_device_filter.cc', 'usb_device_filter.h', 'usb_device_handle_impl.cc', 'usb_device_handle_impl.h', 'usb_device_handle.cc', 'usb_device_handle.h', + 'usb_endpoint_android.cc', + 'usb_endpoint_android.h', 'usb_error.cc', 'usb_error.h', 'usb_ids.cc', 'usb_ids.h', + 'usb_interface_android.cc', + 'usb_interface_android.h', 'usb_service.cc', 'usb_service.h', + 'usb_service_android.cc', + 'usb_service_android.h', 'usb_service_impl.cc', 'usb_service_impl.h', 'webusb_descriptors.cc', @@ -75,13 +87,14 @@ ], }], ['OS=="android"', { + 'dependencies': [ + 'device_usb_java', + 'device_usb_jni_headers', + ], 'dependencies!': [ '../../third_party/libusb/libusb.gyp:libusb', ], - 'sources': [ - 'usb_service_android.cc', - 'usb_service_android.h', - ], + # These sources are libusb-specific. 'sources!': [ 'usb_context.cc', 'usb_context.h', @@ -122,4 +135,45 @@ ], }, ], + 'conditions': [ + ['OS == "android"', { + 'targets': [ + { + 'target_name': 'device_usb_jni_headers', + 'type': 'none', + 'sources': [ + 'android/java/src/org/chromium/device/usb/ChromeUsbConfiguration.java', + 'android/java/src/org/chromium/device/usb/ChromeUsbDevice.java', + 'android/java/src/org/chromium/device/usb/ChromeUsbEndpoint.java', + 'android/java/src/org/chromium/device/usb/ChromeUsbInterface.java', + 'android/java/src/org/chromium/device/usb/ChromeUsbService.java', + ], + 'variables': { + 'jni_gen_package': 'device_usb', + }, + 'includes': [ '../../build/jni_generator.gypi' ], + }, + { + 'target_name': 'device_usb_java', + 'type': 'none', + 'dependencies': [ + 'usb_descriptors_javagen', + '../../base/base.gyp:base', + ], + 'variables': { + 'java_in_dir': '../../device/usb/android/java', + }, + 'includes': [ '../../build/java.gypi' ], + }, + { + 'target_name': 'usb_descriptors_javagen', + 'type': 'none', + 'variables': { + 'source_file': 'usb_descriptors.h', + }, + 'includes': [ '../../build/android/java_cpp_enum.gypi' ], + }, + ], + }], + ], }
diff --git a/device/usb/usb_configuration_android.cc b/device/usb/usb_configuration_android.cc new file mode 100644 index 0000000..4a9c712 --- /dev/null +++ b/device/usb/usb_configuration_android.cc
@@ -0,0 +1,49 @@ +// 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/usb/usb_configuration_android.h" + +#include "device/usb/usb_interface_android.h" +#include "jni/ChromeUsbConfiguration_jni.h" + +using base::android::ScopedJavaLocalRef; + +namespace device { + +// static +bool UsbConfigurationAndroid::RegisterJNI(JNIEnv* env) { + return RegisterNativesImpl(env); // Generated in ChromeUsbConfiguration_jni.h +} + +// static +UsbConfigDescriptor UsbConfigurationAndroid::Convert( + JNIEnv* env, + const base::android::JavaRef<jobject>& usb_configuration) { + ScopedJavaLocalRef<jobject> wrapper = + Java_ChromeUsbConfiguration_create(env, usb_configuration.obj()); + + UsbConfigDescriptor config; + config.configuration_value = + Java_ChromeUsbConfiguration_getConfigurationValue(env, wrapper.obj()); + config.self_powered = + Java_ChromeUsbConfiguration_isSelfPowered(env, wrapper.obj()); + config.remote_wakeup = + Java_ChromeUsbConfiguration_isRemoteWakeup(env, wrapper.obj()); + config.maximum_power = + Java_ChromeUsbConfiguration_getMaxPower(env, wrapper.obj()); + + ScopedJavaLocalRef<jobjectArray> interfaces = + Java_ChromeUsbConfiguration_getInterfaces(env, wrapper.obj()); + jsize count = env->GetArrayLength(interfaces.obj()); + config.interfaces.reserve(count); + for (jsize i = 0; i < count; ++i) { + ScopedJavaLocalRef<jobject> interface( + env, env->GetObjectArrayElement(interfaces.obj(), i)); + config.interfaces.push_back(UsbInterfaceAndroid::Convert(env, interface)); + } + + return config; +} + +} // namespace device
diff --git a/device/usb/usb_configuration_android.h b/device/usb/usb_configuration_android.h new file mode 100644 index 0000000..610ac07 --- /dev/null +++ b/device/usb/usb_configuration_android.h
@@ -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. + +#ifndef DEVICE_USB_USB_CONFIGURATION_ANDROID_H_ +#define DEVICE_USB_USB_CONFIGURATION_ANDROID_H_ + +#include "base/android/scoped_java_ref.h" +#include "device/usb/usb_descriptors.h" + +namespace device { + +class UsbConfigurationAndroid { + public: + // Register C++ methods exposed to Java using JNI. + static bool RegisterJNI(JNIEnv* env); + + static UsbConfigDescriptor Convert( + JNIEnv* env, + const base::android::JavaRef<jobject>& usb_configuration); +}; + +} // namespace device + +#endif // DEVICE_USB_USB_CONFIGURATION_ANDROID_H_
diff --git a/device/usb/usb_descriptors.h b/device/usb/usb_descriptors.h index 93b6f62..adaa0ab 100644 --- a/device/usb/usb_descriptors.h +++ b/device/usb/usb_descriptors.h
@@ -12,6 +12,8 @@ namespace device { +// A Java counterpart will be generated for this enum. +// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.device.usb enum UsbTransferType { USB_TRANSFER_CONTROL = 0, USB_TRANSFER_ISOCHRONOUS, @@ -19,6 +21,8 @@ USB_TRANSFER_INTERRUPT, }; +// A Java counterpart will be generated for this enum. +// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.device.usb enum UsbEndpointDirection { USB_DIRECTION_INBOUND = 0, USB_DIRECTION_OUTBOUND,
diff --git a/device/usb/usb_device.h b/device/usb/usb_device.h index 9822a38..92d0e29 100644 --- a/device/usb/usb_device.h +++ b/device/usb/usb_device.h
@@ -7,6 +7,7 @@ #include <stdint.h> +#include <string> #include <vector> #include "base/callback.h" @@ -59,10 +60,6 @@ // Creates a UsbDeviceHandle for further manipulation. virtual void Open(const OpenCallback& callback) = 0; - // Explicitly closes a device handle. This method will be automatically called - // by the destructor of a UsbDeviceHandle as well. - virtual bool Close(scoped_refptr<UsbDeviceHandle> handle) = 0; - // Gets the UsbConfigDescriptor for the active device configuration or nullptr // if the device is unconfigured. virtual const UsbConfigDescriptor* GetActiveConfiguration() = 0;
diff --git a/device/usb/usb_device_android.cc b/device/usb/usb_device_android.cc new file mode 100644 index 0000000..ee9e93b --- /dev/null +++ b/device/usb/usb_device_android.cc
@@ -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. + +#include "device/usb/usb_device_android.h" + +#include "base/android/build_info.h" +#include "base/android/jni_string.h" +#include "base/bind.h" +#include "base/location.h" +#include "base/thread_task_runner_handle.h" +#include "device/usb/usb_configuration_android.h" +#include "device/usb/usb_device_handle.h" +#include "device/usb/usb_interface_android.h" +#include "jni/ChromeUsbDevice_jni.h" + +using base::android::AttachCurrentThread; +using base::android::ConvertJavaStringToUTF16; +using base::android::JavaRef; +using base::android::ScopedJavaLocalRef; + +namespace device { + +// static +bool UsbDeviceAndroid::RegisterJNI(JNIEnv* env) { + return RegisterNativesImpl(env); // Generated in ChromeUsbDevice_jni.h +} + +// static +scoped_refptr<UsbDeviceAndroid> UsbDeviceAndroid::Create( + JNIEnv* env, + const JavaRef<jobject>& usb_device) { + ScopedJavaLocalRef<jobject> wrapper = + Java_ChromeUsbDevice_create(env, usb_device.obj()); + uint16_t vendor_id = Java_ChromeUsbDevice_getVendorId(env, wrapper.obj()); + uint16_t product_id = Java_ChromeUsbDevice_getProductId(env, wrapper.obj()); + ScopedJavaLocalRef<jstring> manufacturer_string = + Java_ChromeUsbDevice_getManufacturerName(env, wrapper.obj()); + ScopedJavaLocalRef<jstring> product_string = + Java_ChromeUsbDevice_getProductName(env, wrapper.obj()); + ScopedJavaLocalRef<jstring> serial_number = + Java_ChromeUsbDevice_getSerialNumber(env, wrapper.obj()); + return make_scoped_refptr(new UsbDeviceAndroid( + env, vendor_id, product_id, + ConvertJavaStringToUTF16(env, manufacturer_string), + ConvertJavaStringToUTF16(env, product_string), + ConvertJavaStringToUTF16(env, serial_number), wrapper)); +} + +void UsbDeviceAndroid::Open(const OpenCallback& callback) { + base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, + base::Bind(callback, nullptr)); +} + +const UsbConfigDescriptor* UsbDeviceAndroid::GetActiveConfiguration() { + return nullptr; +} + +UsbDeviceAndroid::UsbDeviceAndroid(JNIEnv* env, + uint16_t vendor_id, + uint16_t product_id, + const base::string16& manufacturer_string, + const base::string16& product_string, + const base::string16& serial_number, + const JavaRef<jobject>& wrapper) + : UsbDevice(vendor_id, + product_id, + manufacturer_string, + product_string, + serial_number) { + j_object_.Reset(wrapper); + + if (base::android::BuildInfo::GetInstance()->sdk_int() >= 21) { + ScopedJavaLocalRef<jobjectArray> configurations = + Java_ChromeUsbDevice_getConfigurations(env, j_object_.obj()); + jsize count = env->GetArrayLength(configurations.obj()); + configurations_.reserve(count); + for (jsize i = 0; i < count; ++i) { + ScopedJavaLocalRef<jobject> config( + env, env->GetObjectArrayElement(configurations.obj(), i)); + configurations_.push_back(UsbConfigurationAndroid::Convert(env, config)); + } + } else { + // Pre-lollipop only the first configuration was supported. Build a basic + // configuration out of the available interfaces. + UsbConfigDescriptor config; + config.configuration_value = 1; // Reasonable guess. + config.self_powered = false; // Arbitrary default. + config.remote_wakeup = false; // Arbitrary default. + config.maximum_power = 0; // Arbitrary default. + + ScopedJavaLocalRef<jobjectArray> interfaces = + Java_ChromeUsbDevice_getInterfaces(env, wrapper.obj()); + jsize count = env->GetArrayLength(interfaces.obj()); + config.interfaces.reserve(count); + for (jsize i = 0; i < count; ++i) { + ScopedJavaLocalRef<jobject> interface( + env, env->GetObjectArrayElement(interfaces.obj(), i)); + config.interfaces.push_back(UsbInterfaceAndroid::Convert(env, interface)); + } + configurations_.push_back(config); + } +} + +UsbDeviceAndroid::~UsbDeviceAndroid() {} + +} // namespace device
diff --git a/device/usb/usb_device_android.h b/device/usb/usb_device_android.h new file mode 100644 index 0000000..ad468913 --- /dev/null +++ b/device/usb/usb_device_android.h
@@ -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. + +#ifndef DEVICE_USB_USB_DEVICE_ANDROID_H_ +#define DEVICE_USB_USB_DEVICE_ANDROID_H_ + +#include "base/android/scoped_java_ref.h" +#include "device/usb/usb_device.h" + +namespace device { + +class UsbDeviceAndroid : public UsbDevice { + public: + // Register C++ methods exposed to Java using JNI. + static bool RegisterJNI(JNIEnv* env); + + static scoped_refptr<UsbDeviceAndroid> Create( + JNIEnv* env, + const base::android::JavaRef<jobject>& usb_device); + + // UsbDevice: + void Open(const OpenCallback& callback) override; + const UsbConfigDescriptor* GetActiveConfiguration() override; + + private: + UsbDeviceAndroid(JNIEnv* env, + uint16_t vendor_id, + uint16_t product_id, + const base::string16& manufacturer_string, + const base::string16& product_string, + const base::string16& serial_number, + const base::android::JavaRef<jobject>& wrapper); + ~UsbDeviceAndroid() override; + + // Java object org.chromium.device.usb.ChromeUsbDevice. + base::android::ScopedJavaGlobalRef<jobject> j_object_; +}; + +} // namespace device + +#endif // DEVICE_USB_USB_DEVICE_ANDROID_H_
diff --git a/device/usb/usb_device_impl.cc b/device/usb/usb_device_impl.cc index 874ccad..271b631 100644 --- a/device/usb/usb_device_impl.cc +++ b/device/usb/usb_device_impl.cc
@@ -204,7 +204,7 @@ #endif // defined(OS_CHROMEOS) } -bool UsbDeviceImpl::Close(scoped_refptr<UsbDeviceHandle> handle) { +void UsbDeviceImpl::Close(scoped_refptr<UsbDeviceHandle> handle) { DCHECK(thread_checker_.CalledOnValidThread()); for (HandlesVector::iterator it = handles_.begin(); it != handles_.end(); @@ -212,10 +212,9 @@ if (it->get() == handle.get()) { (*it)->InternalClose(); handles_.erase(it); - return true; + return; } } - return false; } const UsbConfigDescriptor* UsbDeviceImpl::GetActiveConfiguration() {
diff --git a/device/usb/usb_device_impl.h b/device/usb/usb_device_impl.h index 337c0e86..a64e3d1b 100644 --- a/device/usb/usb_device_impl.h +++ b/device/usb/usb_device_impl.h
@@ -6,6 +6,8 @@ #define DEVICE_USB_USB_DEVICE_IMPL_H_ #include <stdint.h> + +#include <string> #include <utility> #include <vector> @@ -45,7 +47,6 @@ void CheckUsbAccess(const ResultCallback& callback) override; #endif // OS_CHROMEOS void Open(const OpenCallback& callback) override; - bool Close(scoped_refptr<UsbDeviceHandle> handle) override; const UsbConfigDescriptor* GetActiveConfiguration() override; // These functions are used during enumeration only. The values must not @@ -87,6 +88,7 @@ void ReadAllConfigurations(); // Called by UsbDeviceHandleImpl. + void Close(scoped_refptr<UsbDeviceHandle> handle); void RefreshActiveConfiguration(); private:
diff --git a/device/usb/usb_endpoint_android.cc b/device/usb/usb_endpoint_android.cc new file mode 100644 index 0000000..3280b04 --- /dev/null +++ b/device/usb/usb_endpoint_android.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 "device/usb/usb_endpoint_android.h" + +#include "jni/ChromeUsbEndpoint_jni.h" + +namespace device { + +// static +bool UsbEndpointAndroid::RegisterJNI(JNIEnv* env) { + return RegisterNativesImpl(env); // Generated in ChromeUsbEndpoint_jni.h +} + +// static +UsbEndpointDescriptor UsbEndpointAndroid::Convert( + JNIEnv* env, + const base::android::JavaRef<jobject>& usb_endpoint) { + base::android::ScopedJavaLocalRef<jobject> wrapper = + Java_ChromeUsbEndpoint_create(env, usb_endpoint.obj()); + + UsbEndpointDescriptor endpoint; + endpoint.address = Java_ChromeUsbEndpoint_getAddress(env, wrapper.obj()); + endpoint.direction = static_cast<UsbEndpointDirection>( + Java_ChromeUsbEndpoint_getDirection(env, wrapper.obj())); + endpoint.maximum_packet_size = + Java_ChromeUsbEndpoint_getMaxPacketSize(env, wrapper.obj()); + jint attributes = Java_ChromeUsbEndpoint_getAttributes(env, wrapper.obj()); + endpoint.synchronization_type = + static_cast<UsbSynchronizationType>((attributes >> 2) & 3); + endpoint.usage_type = static_cast<UsbUsageType>((attributes >> 4) & 3); + endpoint.transfer_type = static_cast<UsbTransferType>( + Java_ChromeUsbEndpoint_getType(env, wrapper.obj())); + endpoint.polling_interval = + Java_ChromeUsbEndpoint_getInterval(env, wrapper.obj()); + + return endpoint; +} + +} // namespace device
diff --git a/device/usb/usb_endpoint_android.h b/device/usb/usb_endpoint_android.h new file mode 100644 index 0000000..3fc835c --- /dev/null +++ b/device/usb/usb_endpoint_android.h
@@ -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. + +#ifndef DEVICE_USB_USB_ENDPOINT_ANDROID_H_ +#define DEVICE_USB_USB_ENDPOINT_ANDROID_H_ + +#include "base/android/scoped_java_ref.h" +#include "device/usb/usb_descriptors.h" + +namespace device { + +class UsbEndpointAndroid { + public: + // Register C++ methods exposed to Java using JNI. + static bool RegisterJNI(JNIEnv* env); + + static UsbEndpointDescriptor Convert( + JNIEnv* env, + const base::android::JavaRef<jobject>& usb_endpoint); +}; + +} // namespace device + +#endif // DEVICE_USB_USB_ENDPOINT_ANDROID_H_
diff --git a/device/usb/usb_interface_android.cc b/device/usb/usb_interface_android.cc new file mode 100644 index 0000000..60403ae --- /dev/null +++ b/device/usb/usb_interface_android.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 "device/usb/usb_interface_android.h" + +#include "device/usb/usb_endpoint_android.h" +#include "jni/ChromeUsbInterface_jni.h" + +using base::android::ScopedJavaLocalRef; + +namespace device { + +// static +bool UsbInterfaceAndroid::RegisterJNI(JNIEnv* env) { + return RegisterNativesImpl(env); // Generated in ChromeUsbInterface_jni.h +} + +// static +UsbInterfaceDescriptor UsbInterfaceAndroid::Convert( + JNIEnv* env, + const base::android::JavaRef<jobject>& usb_interface) { + ScopedJavaLocalRef<jobject> wrapper = + Java_ChromeUsbInterface_create(env, usb_interface.obj()); + + UsbInterfaceDescriptor interface; + interface.interface_number = + Java_ChromeUsbInterface_getInterfaceNumber(env, wrapper.obj()); + interface.alternate_setting = + Java_ChromeUsbInterface_getAlternateSetting(env, wrapper.obj()); + interface.interface_class = + Java_ChromeUsbInterface_getInterfaceClass(env, wrapper.obj()); + interface.interface_subclass = + Java_ChromeUsbInterface_getInterfaceSubclass(env, wrapper.obj()); + interface.interface_protocol = + Java_ChromeUsbInterface_getInterfaceProtocol(env, wrapper.obj()); + + ScopedJavaLocalRef<jobjectArray> endpoints = + Java_ChromeUsbInterface_getEndpoints(env, wrapper.obj()); + jsize count = env->GetArrayLength(endpoints.obj()); + interface.endpoints.reserve(count); + for (jsize i = 0; i < count; ++i) { + ScopedJavaLocalRef<jobject> endpoint( + env, env->GetObjectArrayElement(endpoints.obj(), i)); + interface.endpoints.push_back(UsbEndpointAndroid::Convert(env, endpoint)); + } + + return interface; +} + +} // namespace device
diff --git a/device/usb/usb_interface_android.h b/device/usb/usb_interface_android.h new file mode 100644 index 0000000..ec04b61e --- /dev/null +++ b/device/usb/usb_interface_android.h
@@ -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. + +#ifndef DEVICE_USB_USB_INTERFACE_ANDROID_H_ +#define DEVICE_USB_USB_INTERFACE_ANDROID_H_ + +#include "base/android/scoped_java_ref.h" +#include "device/usb/usb_descriptors.h" + +namespace device { + +class UsbInterfaceAndroid { + public: + // Register C++ methods exposed to Java using JNI. + static bool RegisterJNI(JNIEnv* env); + + static UsbInterfaceDescriptor Convert( + JNIEnv* env, + const base::android::JavaRef<jobject>& usb_interface); +}; + +} // namespace device + +#endif // DEVICE_USB_USB_INTERFACE_ANDROID_H_
diff --git a/device/usb/usb_service_android.cc b/device/usb/usb_service_android.cc index 45ce499..3bdf3bc6 100644 --- a/device/usb/usb_service_android.cc +++ b/device/usb/usb_service_android.cc
@@ -4,14 +4,30 @@ #include "device/usb/usb_service_android.h" +#include <string> +#include <vector> + +#include "base/android/context_utils.h" #include "base/bind.h" #include "base/location.h" #include "base/thread_task_runner_handle.h" -#include "device/usb/usb_device.h" +#include "device/usb/usb_device_android.h" +#include "jni/ChromeUsbService_jni.h" + +using base::android::AttachCurrentThread; +using base::android::ScopedJavaLocalRef; namespace device { -UsbServiceAndroid::UsbServiceAndroid() {} +// static +bool UsbServiceAndroid::RegisterJNI(JNIEnv* env) { + return RegisterNativesImpl(env); // Generated in ChromeUsbService_jni.h +} + +UsbServiceAndroid::UsbServiceAndroid() { + j_object_.Reset(Java_ChromeUsbService_create( + AttachCurrentThread(), base::android::GetApplicationContext())); +} UsbServiceAndroid::~UsbServiceAndroid() {} @@ -20,9 +36,20 @@ } void UsbServiceAndroid::GetDevices(const GetDevicesCallback& callback) { - std::vector<scoped_refptr<UsbDevice>> empty; + JNIEnv* env = AttachCurrentThread(); + ScopedJavaLocalRef<jobjectArray> devices = + Java_ChromeUsbService_getDevices(env, j_object_.obj()); + jsize length = env->GetArrayLength(devices.obj()); + + std::vector<scoped_refptr<UsbDevice>> results; + for (jsize i = 0; i < length; ++i) { + ScopedJavaLocalRef<jobject> raw_device( + env, env->GetObjectArrayElement(devices.obj(), i)); + results.push_back(UsbDeviceAndroid::Create(env, raw_device)); + } + base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, - base::Bind(callback, empty)); + base::Bind(callback, results)); } } // namespace device
diff --git a/device/usb/usb_service_android.h b/device/usb/usb_service_android.h index d1ffd9df..9cab4385 100644 --- a/device/usb/usb_service_android.h +++ b/device/usb/usb_service_android.h
@@ -5,6 +5,9 @@ #ifndef DEVICE_USB_USB_SERVICE_ANDROID_H_ #define DEVICE_USB_USB_SERVICE_ANDROID_H_ +#include <string> + +#include "base/android/scoped_java_ref.h" #include "device/usb/usb_service.h" namespace device { @@ -13,11 +16,19 @@ // does not return any devices. class UsbServiceAndroid : public UsbService { public: + // Register C++ methods exposed to Java using JNI. + static bool RegisterJNI(JNIEnv* env); + UsbServiceAndroid(); ~UsbServiceAndroid() override; + // UsbService: scoped_refptr<UsbDevice> GetDevice(const std::string& guid) override; void GetDevices(const GetDevicesCallback& callback) override; + + private: + // Java object org.chromium.device.usb.ChromeUsbService. + base::android::ScopedJavaGlobalRef<jobject> j_object_; }; } // namespace device
diff --git a/extensions/browser/api/app_current_window_internal/OWNERS b/extensions/browser/api/app_current_window_internal/OWNERS index 2a397b7d..5caf038 100644 --- a/extensions/browser/api/app_current_window_internal/OWNERS +++ b/extensions/browser/api/app_current_window_internal/OWNERS
@@ -1,3 +1,3 @@ benwells@chromium.org -jackhou@chromium.org - +calamity@chromium.org +tapted@chromium.org
diff --git a/extensions/browser/api/app_window/OWNERS b/extensions/browser/api/app_window/OWNERS index 1ecba6c9b..5caf038 100644 --- a/extensions/browser/api/app_window/OWNERS +++ b/extensions/browser/api/app_window/OWNERS
@@ -1,2 +1,3 @@ benwells@chromium.org -jackhou@chromium.org +calamity@chromium.org +tapted@chromium.org
diff --git a/extensions/browser/api/web_request/web_request_api.cc b/extensions/browser/api/web_request/web_request_api.cc index 871e3e0f..b3855a3 100644 --- a/extensions/browser/api/web_request/web_request_api.cc +++ b/extensions/browser/api/web_request/web_request_api.cc
@@ -40,6 +40,7 @@ #include "extensions/browser/api/web_request/web_request_event_router_delegate.h" #include "extensions/browser/api/web_request/web_request_time_tracker.h" #include "extensions/browser/event_router.h" +#include "extensions/browser/extension_api_frame_id_map.h" #include "extensions/browser/extension_prefs.h" #include "extensions/browser/extension_registry.h" #include "extensions/browser/extension_system.h" @@ -131,10 +132,6 @@ return "Not reached"; } -int GetFrameId(bool is_main_frame, int frame_id) { - return is_main_frame ? 0 : frame_id; -} - bool IsWebRequestEvent(const std::string& event_name) { std::string web_request_event_name(event_name); if (base::StartsWith(web_request_event_name, @@ -205,9 +202,7 @@ void ExtractRequestInfoDetails(const net::URLRequest* request, bool* is_main_frame, - int* frame_id, - bool* parent_is_main_frame, - int* parent_frame_id, + int* render_frame_id, int* render_process_host_id, int* routing_id, ResourceType* resource_type) { @@ -215,10 +210,8 @@ if (!info) return; - *frame_id = info->GetRenderFrameID(); + *render_frame_id = info->GetRenderFrameID(); *is_main_frame = info->IsMainFrame(); - *parent_frame_id = info->GetParentRenderFrameID(); - *parent_is_main_frame = info->ParentIsMainFrame(); *render_process_host_id = info->GetChildID(); *routing_id = info->GetRouteID(); @@ -229,6 +222,21 @@ *resource_type = content::RESOURCE_TYPE_LAST_TYPE; } +// Extracts a pair of IDs to identify the RenderFrameHost. These IDs are used to +// get the frame ID and parent frame ID from ExtensionApiFrameIdMap, and then +// stored in |dict| by DispatchEventToListeners or SendOnMessageEventOnUI. +void ExtractRenderFrameInfo(base::DictionaryValue* dict, + int* render_process_id, + int* render_frame_id) { + if (!dict->GetInteger(keys::kFrameIdKey, render_frame_id) || + !dict->GetInteger(keys::kProcessIdKey, render_process_id)) { + *render_process_id = -1; + *render_frame_id = -1; + } + // kFrameIdKey will be overwritten later, so it's not removed here. + dict->Remove(keys::kProcessIdKey, nullptr); +} + // Extracts the body from |request| and writes the data into |out|. void ExtractRequestInfoBody(const net::URLRequest* request, base::DictionaryValue* out) { @@ -361,6 +369,16 @@ return; scoped_ptr<base::ListValue> event_args(new base::ListValue); + int render_process_host_id = -1; + int render_frame_id = -1; + ExtractRenderFrameInfo(event_argument.get(), &render_process_host_id, + &render_frame_id); + content::RenderFrameHost* rfh = + content::RenderFrameHost::FromID(render_process_host_id, render_frame_id); + event_argument->SetInteger(keys::kFrameIdKey, + ExtensionApiFrameIdMap::GetFrameId(rfh)); + event_argument->SetInteger(keys::kParentFrameIdKey, + ExtensionApiFrameIdMap::GetParentFrameId(rfh)); event_args->Append(event_argument.release()); EventRouter* event_router = EventRouter::Get(browser_context); @@ -527,8 +545,8 @@ // is also used to find and remove an event listener when an extension is // unloaded. At this point, the event listener cannot be mapped back to // the original process, so 0 is used instead of the actual process ID. - DCHECK(embedder_process_id == 0 || that.embedder_process_id == 0); - return false; + if (embedder_process_id == 0 || that.embedder_process_id == 0) + return false; } if (embedder_process_id != that.embedder_process_id) @@ -744,28 +762,24 @@ const net::URLRequest* request, base::DictionaryValue* out) { bool is_main_frame = false; - int frame_id = -1; - bool parent_is_main_frame = false; - int parent_frame_id = -1; - int frame_id_for_extension = -1; - int parent_frame_id_for_extension = -1; + int render_frame_id = -1; int render_process_host_id = -1; int routing_id = -1; ResourceType resource_type = content::RESOURCE_TYPE_LAST_TYPE; - ExtractRequestInfoDetails(request, &is_main_frame, &frame_id, - &parent_is_main_frame, &parent_frame_id, + ExtractRequestInfoDetails(request, &is_main_frame, &render_frame_id, &render_process_host_id, &routing_id, &resource_type); - frame_id_for_extension = GetFrameId(is_main_frame, frame_id); - parent_frame_id_for_extension = GetFrameId(parent_is_main_frame, - parent_frame_id); out->SetString(keys::kRequestIdKey, base::Uint64ToString(request->identifier())); out->SetString(keys::kUrlKey, request->url().spec()); out->SetString(keys::kMethodKey, request->method()); - out->SetInteger(keys::kFrameIdKey, frame_id_for_extension); - out->SetInteger(keys::kParentFrameIdKey, parent_frame_id_for_extension); + // Note: This (frameId, processId) pair is removed by ExtractRenderFrameInfo, + // and finally restored in DispatchEventToListeners or SendOnMessageEventOnUI. + // TODO(robwu): This is ugly. Create a proper data structure to separate these + // two IDs from the dictionary, so that kFrameIdKey has only one meaning. + out->SetInteger(keys::kFrameIdKey, render_frame_id); + out->SetInteger(keys::kProcessIdKey, render_process_host_id); out->SetString(keys::kTypeKey, helpers::ResourceTypeToString(resource_type)); out->SetDouble(keys::kTimeStampKey, base::Time::Now().ToDoubleT() * 1000); if (web_request_event_router_delegate_) { @@ -1244,21 +1258,12 @@ // TODO(mpcomplete): Consider consolidating common (extension_id,json_args) // pairs into a single message sent to a list of sub_event_names. int num_handlers_blocking = 0; - for (const EventListener* listener : listeners) { - // Filter out the optional keys that this listener didn't request. - scoped_ptr<base::ListValue> args_filtered(args.DeepCopy()); - base::DictionaryValue* dict = NULL; - CHECK(args_filtered->GetDictionary(0, &dict) && dict); - if (!(listener->extra_info_spec & ExtraInfoSpec::REQUEST_HEADERS)) - dict->Remove(keys::kRequestHeadersKey, NULL); - if (!(listener->extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS)) - dict->Remove(keys::kResponseHeadersKey, NULL); - EventRouter::DispatchEventToSender( - listener->ipc_sender.get(), browser_context, listener->extension_id, - listener->histogram_value, listener->sub_event_name, - std::move(args_filtered), EventRouter::USER_GESTURE_UNKNOWN, - EventFilteringInfo()); + scoped_ptr<std::vector<EventListener>> listeners_to_dispatch( + new std::vector<EventListener>()); + listeners_to_dispatch->reserve(listeners.size()); + for (const EventListener* listener : listeners) { + listeners_to_dispatch->push_back(*listener); if (listener->extra_info_spec & (ExtraInfoSpec::BLOCKING | ExtraInfoSpec::ASYNC_BLOCKING)) { listener->blocked_requests.insert(request->identifier()); @@ -1276,6 +1281,22 @@ } } + // TODO(robwu): Avoid unnecessary copy, by changing |args| to be a + // scoped_ptr<base::DictionaryValue> and transferring the ownership. + const base::DictionaryValue* dict = nullptr; + CHECK(args.GetDictionary(0, &dict) && dict); + base::DictionaryValue* args_copy = dict->DeepCopy(); + + int render_process_host_id = -1; + int render_frame_id = -1; + ExtractRenderFrameInfo(args_copy, &render_process_host_id, &render_frame_id); + + ExtensionApiFrameIdMap::Get()->GetFrameIdOnIO( + render_process_host_id, render_frame_id, + base::Bind(&ExtensionWebRequestEventRouter::DispatchEventToListeners, + AsWeakPtr(), browser_context, + base::Passed(&listeners_to_dispatch), base::Owned(args_copy))); + if (num_handlers_blocking > 0) { BlockedRequest& blocked_request = blocked_requests_[request->identifier()]; blocked_request.request = request; @@ -1288,6 +1309,59 @@ return false; } +void ExtensionWebRequestEventRouter::DispatchEventToListeners( + void* browser_context, + scoped_ptr<std::vector<EventListener>> listeners, + base::DictionaryValue* dict, + int extension_api_frame_id, + int extension_api_parent_frame_id) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + DCHECK(listeners.get()); + DCHECK_GT(listeners->size(), 0UL); + DCHECK(dict); + + dict->SetInteger(keys::kFrameIdKey, extension_api_frame_id); + dict->SetInteger(keys::kParentFrameIdKey, extension_api_parent_frame_id); + + std::string event_name = + EventRouter::GetBaseEventName((*listeners)[0].sub_event_name); + DCHECK(IsWebRequestEvent(event_name)); + + const std::set<EventListener>& event_listeners = + listeners_[browser_context][event_name]; + void* cross_browser_context = GetCrossBrowserContext(browser_context); + const std::set<EventListener>* cross_event_listeners = + cross_browser_context ? &listeners_[cross_browser_context][event_name] + : nullptr; + + for (const EventListener& target : *listeners) { + std::set<EventListener>::const_iterator listener = + event_listeners.find(target); + // Ignore listener if it was removed between the thread hops. + if (listener == event_listeners.end()) { + if (!cross_event_listeners) + continue; + listener = cross_event_listeners->find(target); + if (listener == cross_event_listeners->end()) + continue; + } + + // Filter out the optional keys that this listener didn't request. + scoped_ptr<base::ListValue> args_filtered(new base::ListValue); + args_filtered->Append(dict->DeepCopy()); + if (!(listener->extra_info_spec & ExtraInfoSpec::REQUEST_HEADERS)) + dict->Remove(keys::kRequestHeadersKey, nullptr); + if (!(listener->extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS)) + dict->Remove(keys::kResponseHeadersKey, nullptr); + + EventRouter::DispatchEventToSender( + listener->ipc_sender.get(), browser_context, listener->extension_id, + listener->histogram_value, listener->sub_event_name, + std::move(args_filtered), EventRouter::USER_GESTURE_UNKNOWN, + EventFilteringInfo()); + } +} + void ExtensionWebRequestEventRouter::OnEventHandled( void* browser_context, const std::string& extension_id, @@ -1441,17 +1515,14 @@ bool ExtensionWebRequestEventRouter::IsPageLoad( const net::URLRequest* request) const { bool is_main_frame = false; - int frame_id = -1; - bool parent_is_main_frame = false; - int parent_frame_id = -1; + int render_frame_id = -1; int render_process_host_id = -1; int routing_id = -1; ResourceType resource_type = content::RESOURCE_TYPE_LAST_TYPE; - ExtractRequestInfoDetails(request, &is_main_frame, &frame_id, - &parent_is_main_frame, &parent_frame_id, - &render_process_host_id, - &routing_id, &resource_type); + ExtractRequestInfoDetails(request, &is_main_frame, &render_frame_id, + &render_process_host_id, &routing_id, + &resource_type); return resource_type == content::RESOURCE_TYPE_MAIN_FRAME; } @@ -1591,18 +1662,15 @@ *extra_info_spec = 0; bool is_main_frame = false; - int frame_id = -1; - bool parent_is_main_frame = false; - int parent_frame_id = -1; + int render_frame_id = -1; int render_process_host_id = -1; int routing_id = -1; ResourceType resource_type = content::RESOURCE_TYPE_LAST_TYPE; const GURL& url = request->url(); - ExtractRequestInfoDetails(request, &is_main_frame, &frame_id, - &parent_is_main_frame, &parent_frame_id, - &render_process_host_id, - &routing_id, &resource_type); + ExtractRequestInfoDetails(request, &is_main_frame, &render_frame_id, + &render_process_host_id, &routing_id, + &resource_type); bool is_request_from_extension = IsRequestFromExtension(request, extension_info_map);
diff --git a/extensions/browser/api/web_request/web_request_api.h b/extensions/browser/api/web_request/web_request_api.h index 4b214ca49..191005d 100644 --- a/extensions/browser/api/web_request/web_request_api.h +++ b/extensions/browser/api/web_request/web_request_api.h
@@ -342,6 +342,13 @@ const std::vector<const EventListener*>& listeners, const base::ListValue& args); + void DispatchEventToListeners( + void* browser_context, + scoped_ptr<std::vector<EventListener>> listeners, + base::DictionaryValue* dict, + int extension_api_frame_id, + int extension_api_parent_frame_id); + // Returns a list of event listeners that care about the given event, based // on their filter parameters. |extra_info_spec| will contain the combined // set of extra_info_spec flags that every matching listener asked for.
diff --git a/extensions/browser/api/web_request/web_request_api_constants.cc b/extensions/browser/api/web_request/web_request_api_constants.cc index 4bc0c0e..fd10ca1 100644 --- a/extensions/browser/api/web_request/web_request_api_constants.cc +++ b/extensions/browser/api/web_request/web_request_api_constants.cc
@@ -10,6 +10,7 @@ const char kErrorKey[] = "error"; const char kFrameIdKey[] = "frameId"; const char kParentFrameIdKey[] = "parentFrameId"; +const char kProcessIdKey[] = "processId"; const char kFromCache[] = "fromCache"; const char kHostKey[] = "host"; const char kIpKey[] = "ip";
diff --git a/extensions/browser/api/web_request/web_request_api_constants.h b/extensions/browser/api/web_request/web_request_api_constants.h index 57bf535..ce51d06 100644 --- a/extensions/browser/api/web_request/web_request_api_constants.h +++ b/extensions/browser/api/web_request/web_request_api_constants.h
@@ -14,6 +14,7 @@ extern const char kErrorKey[]; extern const char kFrameIdKey[]; extern const char kParentFrameIdKey[]; +extern const char kProcessIdKey[]; extern const char kFromCache[]; extern const char kHostKey[]; extern const char kIpKey[];
diff --git a/extensions/browser/extension_api_frame_id_map.cc b/extensions/browser/extension_api_frame_id_map.cc new file mode 100644 index 0000000..72949be --- /dev/null +++ b/extensions/browser/extension_api_frame_id_map.cc
@@ -0,0 +1,245 @@ +// 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/browser/extension_api_frame_id_map.h" + +#include <tuple> + +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/render_frame_host.h" +#include "content/public/browser/render_process_host.h" +#include "content/public/browser/web_contents.h" +#include "content/public/common/child_process_host.h" + +namespace extensions { + +namespace { + +// The map is accessed on the IO and UI thread, so construct it once and never +// delete it. +base::LazyInstance<ExtensionApiFrameIdMap>::Leaky g_map_instance = + LAZY_INSTANCE_INITIALIZER; + +} // namespace + +const int ExtensionApiFrameIdMap::kInvalidFrameId = -1; + +ExtensionApiFrameIdMap::CachedFrameIdPair::CachedFrameIdPair() + : frame_id(kInvalidFrameId), parent_frame_id(kInvalidFrameId) {} + +ExtensionApiFrameIdMap::CachedFrameIdPair::CachedFrameIdPair( + int frame_id, + int parent_frame_id) + : frame_id(frame_id), parent_frame_id(parent_frame_id) {} + +ExtensionApiFrameIdMap::RenderFrameIdKey::RenderFrameIdKey() + : render_process_id(content::ChildProcessHost::kInvalidUniqueID), + frame_routing_id(MSG_ROUTING_NONE) {} + +ExtensionApiFrameIdMap::RenderFrameIdKey::RenderFrameIdKey( + int render_process_id, + int frame_routing_id) + : render_process_id(render_process_id), + frame_routing_id(frame_routing_id) {} + +ExtensionApiFrameIdMap::FrameIdCallbacks::FrameIdCallbacks() + : is_iterating(false) {} + +ExtensionApiFrameIdMap::FrameIdCallbacks::~FrameIdCallbacks() {} + +bool ExtensionApiFrameIdMap::RenderFrameIdKey::operator<( + const RenderFrameIdKey& other) const { + return std::tie(render_process_id, frame_routing_id) < + std::tie(other.render_process_id, other.frame_routing_id); +} + +bool ExtensionApiFrameIdMap::RenderFrameIdKey::operator==( + const RenderFrameIdKey& other) const { + return render_process_id == other.render_process_id && + frame_routing_id == other.frame_routing_id; +} + +ExtensionApiFrameIdMap::ExtensionApiFrameIdMap() {} + +ExtensionApiFrameIdMap::~ExtensionApiFrameIdMap() {} + +ExtensionApiFrameIdMap* ExtensionApiFrameIdMap::Get() { + return g_map_instance.Pointer(); +} + +int ExtensionApiFrameIdMap::GetFrameId(content::RenderFrameHost* rfh) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + + if (!rfh) + return kInvalidFrameId; + if (rfh->GetParent()) + return rfh->GetFrameTreeNodeId(); + return 0; // Main frame. +} + +int ExtensionApiFrameIdMap::GetParentFrameId(content::RenderFrameHost* rfh) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + + return rfh ? GetFrameId(rfh->GetParent()) : kInvalidFrameId; +} + +content::RenderFrameHost* ExtensionApiFrameIdMap::GetRenderFrameHostById( + content::WebContents* web_contents, + int frame_id) { + // Although it is technically possible to map |frame_id| to a RenderFrameHost + // without WebContents, we choose to not do that because in the extension API + // frameIds are only guaranteed to be meaningful in combination with a tabId. + if (!web_contents) + return nullptr; + + if (frame_id == kInvalidFrameId) + return nullptr; + + if (frame_id == 0) + return web_contents->GetMainFrame(); + + DCHECK_GE(frame_id, 1); + return web_contents->FindFrameByFrameTreeNodeId(frame_id); +} + +ExtensionApiFrameIdMap::CachedFrameIdPair ExtensionApiFrameIdMap::KeyToValue( + const RenderFrameIdKey& key) const { + content::RenderFrameHost* rfh = content::RenderFrameHost::FromID( + key.render_process_id, key.frame_routing_id); + return CachedFrameIdPair(GetFrameId(rfh), GetParentFrameId(rfh)); +} + +ExtensionApiFrameIdMap::CachedFrameIdPair +ExtensionApiFrameIdMap::LookupFrameIdOnUI(const RenderFrameIdKey& key) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + + FrameIdMap::const_iterator frame_id_iter = frame_id_map_.find(key); + if (frame_id_iter != frame_id_map_.end()) + return frame_id_iter->second; + + CachedFrameIdPair cached_frame_id_pair = KeyToValue(key); + // Don't save invalid values in the map. + if (cached_frame_id_pair.frame_id == kInvalidFrameId) + return cached_frame_id_pair; + + auto kvpair = FrameIdMap::value_type(key, cached_frame_id_pair); + base::AutoLock lock(frame_id_map_lock_); + return frame_id_map_.insert(kvpair).first->second; +} + +void ExtensionApiFrameIdMap::ReceivedFrameIdOnIO( + const RenderFrameIdKey& key, + const CachedFrameIdPair& cached_frame_id_pair) { + DCHECK_CURRENTLY_ON(content::BrowserThread::IO); + + FrameIdCallbacksMap::iterator map_iter = callbacks_map_.find(key); + if (map_iter == callbacks_map_.end()) { + // Can happen if ReceivedFrameIdOnIO was called after the frame ID was + // resolved (e.g. via GetFrameIdOnIO), but before PostTaskAndReply replied. + return; + } + + FrameIdCallbacks& callbacks = map_iter->second; + + if (callbacks.is_iterating) + return; + callbacks.is_iterating = true; + + // Note: Extra items can be appended to |callbacks| during this loop if a + // callback calls GetFrameIdOnIO(). + for (std::list<FrameIdCallback>::iterator it = callbacks.callbacks.begin(); + it != callbacks.callbacks.end(); ++it) { + it->Run(cached_frame_id_pair.frame_id, + cached_frame_id_pair.parent_frame_id); + } + callbacks_map_.erase(key); +} + +void ExtensionApiFrameIdMap::GetFrameIdOnIO(int render_process_id, + int frame_routing_id, + const FrameIdCallback& callback) { + DCHECK_CURRENTLY_ON(content::BrowserThread::IO); + + if (frame_routing_id <= -1) { + // frame_routing_id == -2 = MSG_ROUTING_NONE -> not a RenderFrameHost. + // frame_routing_id == -1 -> should be MSG_ROUTING_NONE, but there are + // callers that use "-1" for unknown frames. + // TODO(robwu): Enable assertion when all callers have been fixed. + // DCHECK_EQ(MSG_ROUTING_NONE, -1); + callback.Run(kInvalidFrameId, kInvalidFrameId); + return; + } + // A valid routing ID is only meaningful with a valid process ID. + DCHECK_GE(render_process_id, 0); + + const RenderFrameIdKey key(render_process_id, frame_routing_id); + CachedFrameIdPair cached_frame_id_pair; + bool did_find_cached_frame_id_pair = false; + + { + base::AutoLock lock(frame_id_map_lock_); + FrameIdMap::const_iterator frame_id_iter = frame_id_map_.find(key); + if (frame_id_iter != frame_id_map_.end()) { + // This is very likely to happen because CacheFrameId() is called as soon + // as the frame is created. + cached_frame_id_pair = frame_id_iter->second; + did_find_cached_frame_id_pair = true; + } + } + + FrameIdCallbacksMap::iterator map_iter = callbacks_map_.find(key); + + if (did_find_cached_frame_id_pair) { + // Value already cached, thread hopping is not needed. + if (map_iter == callbacks_map_.end()) { + // If the frame ID was cached, then it is likely that there are no pending + // callbacks. So do not unnecessarily copy the callback, but run it. + callback.Run(cached_frame_id_pair.frame_id, + cached_frame_id_pair.parent_frame_id); + } else { + map_iter->second.callbacks.push_back(callback); + ReceivedFrameIdOnIO(key, cached_frame_id_pair); + } + return; + } + + // The key was seen for the first time (or the frame has been removed). + // Hop to the UI thread to look up the extension API frame ID. + callbacks_map_[key].callbacks.push_back(callback); + content::BrowserThread::PostTaskAndReplyWithResult( + content::BrowserThread::UI, FROM_HERE, + base::Bind(&ExtensionApiFrameIdMap::LookupFrameIdOnUI, + base::Unretained(this), key), + base::Bind(&ExtensionApiFrameIdMap::ReceivedFrameIdOnIO, + base::Unretained(this), key)); +} + +void ExtensionApiFrameIdMap::CacheFrameId(content::RenderFrameHost* rfh) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + + const RenderFrameIdKey key(rfh->GetProcess()->GetID(), rfh->GetRoutingID()); + CacheFrameId(key); + DCHECK(frame_id_map_.find(key) != frame_id_map_.end()); +} + +void ExtensionApiFrameIdMap::CacheFrameId(const RenderFrameIdKey& key) { + LookupFrameIdOnUI(key); +} + +void ExtensionApiFrameIdMap::RemoveFrameId(content::RenderFrameHost* rfh) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + DCHECK(rfh); + + const RenderFrameIdKey key(rfh->GetProcess()->GetID(), rfh->GetRoutingID()); + RemoveFrameId(key); +} + +void ExtensionApiFrameIdMap::RemoveFrameId(const RenderFrameIdKey& key) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + + base::AutoLock lock(frame_id_map_lock_); + frame_id_map_.erase(key); +} + +} // namespace extensions
diff --git a/extensions/browser/extension_api_frame_id_map.h b/extensions/browser/extension_api_frame_id_map.h new file mode 100644 index 0000000..c3af8b3d --- /dev/null +++ b/extensions/browser/extension_api_frame_id_map.h
@@ -0,0 +1,168 @@ +// 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_BROWSER_EXTENSION_API_FRAME_ID_MAP_H_ +#define EXTENSIONS_BROWSER_EXTENSION_API_FRAME_ID_MAP_H_ + +#include <list> +#include <map> + +#include "base/callback.h" +#include "base/lazy_instance.h" +#include "base/macros.h" +#include "base/synchronization/lock.h" + +namespace content { +class RenderFrameHost; +class WebContents; +} // namespace content + +namespace extensions { + +// Extension frame IDs are exposed through the chrome.* APIs and have the +// following characteristics: +// - The top-level frame has ID 0. +// - Any child frame has a positive ID. +// - A non-existant frame has ID -1. +// - They are only guaranteed to be unique within a tab. +// - The ID does not change during the frame's lifetime and is not re-used after +// the frame is removed. The frame may change its current RenderFrameHost over +// time, so multiple RenderFrameHosts may map to the same extension frame ID. + +// This class provides a mapping from a (render_process_id, frame_routing_id) +// pair that maps a RenderFrameHost to an extension frame ID. +// Unless stated otherwise, the methods can only be called on the UI thread. +// +// The non-static methods of this class use an internal cache. This cache is +// used to minimize IO->UI->IO round-trips of GetFrameIdOnIO. If the cost of +// attaching FrameTreeNode IDs to requests is negligible (crbug.com/524228), +// then we can remove all key caching and remove the cache from this class. +// TODO(robwu): Keep an eye on crbug.com/524228 and act upon the outcome. +class ExtensionApiFrameIdMap { + public: + using FrameIdCallback = + base::Callback<void(int extension_api_frame_id, + int extension_api_parent_frame_id)>; + + // An invalid extension API frame ID. + static const int kInvalidFrameId; + + static ExtensionApiFrameIdMap* Get(); + + // Get the extension API frame ID for |rfh|. + static int GetFrameId(content::RenderFrameHost* rfh); + + // Get the extension API frame ID for the parent of |rfh|. + static int GetParentFrameId(content::RenderFrameHost* rfh); + + // Find the current RenderFrameHost for a given WebContents and extension + // frame ID. + // Returns nullptr if not found. + static content::RenderFrameHost* GetRenderFrameHostById( + content::WebContents* web_contents, + int frame_id); + + // Runs |callback| with the result that is equivalent to calling GetFrameId() + // on the UI thread. Thread hopping is minimized if possible. Callbacks for + // the same |render_process_id| and |frame_routing_id| are guaranteed to be + // run in order. The order of other callbacks is undefined. + void GetFrameIdOnIO(int render_process_id, + int frame_routing_id, + const FrameIdCallback& callback); + + // Looks up the frame ID and stores it in the map. This method should be + // called as early as possible, e.g. in a + // WebContentsObserver::RenderFrameCreated notification. + void CacheFrameId(content::RenderFrameHost* rfh); + + // Removes the frame ID mapping for a given frame. This method can be called + // at any time, but it is typically called when a frame is destroyed. + // If this method is not called, the cached mapping for the frame is retained + // forever. + void RemoveFrameId(content::RenderFrameHost* rfh); + + protected: + friend struct base::DefaultLazyInstanceTraits<ExtensionApiFrameIdMap>; + + // A set of identifiers that uniquely identifies a RenderFrame. + struct RenderFrameIdKey { + RenderFrameIdKey(); + RenderFrameIdKey(int render_process_id, int frame_routing_id); + + // The process ID of the renderer that contains the RenderFrame. + int render_process_id; + + // The routing ID of the RenderFrame. + int frame_routing_id; + + bool operator<(const RenderFrameIdKey& other) const; + bool operator==(const RenderFrameIdKey& other) const; + }; + + // The cached pair of frame IDs of the frame. Every RenderFrameIdKey + // maps to a CachedFrameIdPair. + struct CachedFrameIdPair { + CachedFrameIdPair(); + CachedFrameIdPair(int frame_id, int parent_frame_id); + + // The extension API frame ID of the frame. + int frame_id; + + // The extension API frame ID of the parent of the frame. + int parent_frame_id; + }; + + struct FrameIdCallbacks { + FrameIdCallbacks(); + ~FrameIdCallbacks(); + + // This is a std::list so that iterators are not invalidated when the list + // is modified during an iteration. + std::list<FrameIdCallback> callbacks; + + // To avoid re-entrant processing of callbacks. + bool is_iterating; + }; + + using FrameIdMap = std::map<RenderFrameIdKey, CachedFrameIdPair>; + using FrameIdCallbacksMap = std::map<RenderFrameIdKey, FrameIdCallbacks>; + + ExtensionApiFrameIdMap(); + ~ExtensionApiFrameIdMap(); + + // Determines the value to be stored in |frame_id_map_| for a given key. This + // method is only called when |key| is not in |frame_id_map_|. + // virtual for testing. + virtual CachedFrameIdPair KeyToValue(const RenderFrameIdKey& key) const; + + CachedFrameIdPair LookupFrameIdOnUI(const RenderFrameIdKey& key); + + // Called as soon as the frame ID is found for the given |key|, and runs all + // queued callbacks with |cached_frame_id_pair|. + void ReceivedFrameIdOnIO(const RenderFrameIdKey& key, + const CachedFrameIdPair& cached_frame_id_pair); + + // Implementation of CacheFrameId(RenderFrameHost), separated for testing. + void CacheFrameId(const RenderFrameIdKey& key); + + // Implementation of RemoveFrameId(RenderFrameHost), separated for testing. + void RemoveFrameId(const RenderFrameIdKey& key); + + // Queued callbacks for use on the IO thread. + FrameIdCallbacksMap callbacks_map_; + + // This map is only modified on the UI thread and is used to minimize the + // number of thread hops on the IO thread. + FrameIdMap frame_id_map_; + + // This lock protects |frame_id_map_| from being concurrently written on the + // UI thread and read on the IO thread. + base::Lock frame_id_map_lock_; + + DISALLOW_COPY_AND_ASSIGN(ExtensionApiFrameIdMap); +}; + +} // namespace extensions + +#endif // EXTENSIONS_BROWSER_EXTENSION_API_FRAME_ID_MAP_H_
diff --git a/extensions/browser/extension_api_frame_id_map_unittest.cc b/extensions/browser/extension_api_frame_id_map_unittest.cc new file mode 100644 index 0000000..119c54d6 --- /dev/null +++ b/extensions/browser/extension_api_frame_id_map_unittest.cc
@@ -0,0 +1,222 @@ +// 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/bind.h" +#include "base/run_loop.h" +#include "content/public/test/test_browser_thread_bundle.h" +#include "extensions/browser/extension_api_frame_id_map.h" +#include "ipc/ipc_message.h" +#include "testing/gtest/include/gtest/gtest.h" + +using FrameIdCallback = extensions::ExtensionApiFrameIdMap::FrameIdCallback; + +namespace extensions { + +namespace { + +int ToTestFrameId(int render_process_id, int frame_routing_id) { + if (render_process_id < 0 && frame_routing_id < 0) + return ExtensionApiFrameIdMap::kInvalidFrameId; + // Return a deterministic value (yet different from the input) for testing. + // To make debugging easier: Ending with 0 = frame ID. + return render_process_id * 1000 + frame_routing_id * 10; +} + +int ToTestParentFrameId(int render_process_id, int frame_routing_id) { + if (render_process_id < 0 && frame_routing_id < 0) + return ExtensionApiFrameIdMap::kInvalidFrameId; + // Return a deterministic value (yet different from the input) for testing. + // To make debugging easier: Ending with 7 = parent frame ID. + return render_process_id * 1000 + frame_routing_id * 10 + 7; +} + +class TestExtensionApiFrameIdMap : public ExtensionApiFrameIdMap { + public: + int GetInternalSize() { return frame_id_map_.size(); } + int GetInternalCallbackCount() { + int count = 0; + for (auto& it : callbacks_map_) + count += it.second.callbacks.size(); + return count; + } + + // These indirections are used because we cannot mock RenderFrameHost with + // fixed IDs in unit tests. + // TODO(robwu): Use content/public/test/test_renderer_host.h to mock + // RenderFrameHosts and update the tests to test against these mocks. + // After doing that, there is no need for CacheFrameId/RemoveFrameId methods + // that take a RenderFrameIdKey, so the methods can be merged. + void SetInternalFrameId(int render_process_id, int frame_routing_id) { + CacheFrameId(RenderFrameIdKey(render_process_id, frame_routing_id)); + } + void RemoveInternalFrameId(int render_process_id, int frame_routing_id) { + RemoveFrameId(RenderFrameIdKey(render_process_id, frame_routing_id)); + } + + private: + // ExtensionApiFrameIdMap: + CachedFrameIdPair KeyToValue(const RenderFrameIdKey& key) const override { + return CachedFrameIdPair( + ToTestFrameId(key.render_process_id, key.frame_routing_id), + ToTestParentFrameId(key.render_process_id, key.frame_routing_id)); + } +}; + +class ExtensionApiFrameIdMapTest : public testing::Test { + public: + ExtensionApiFrameIdMapTest() + : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP) {} + + FrameIdCallback CreateCallback(int render_process_id, + int frame_routing_id, + const std::string& callback_name_for_testing) { + return base::Bind(&ExtensionApiFrameIdMapTest::OnCalledCallback, + base::Unretained(this), render_process_id, + frame_routing_id, callback_name_for_testing); + } + + void OnCalledCallback(int render_process_id, + int frame_routing_id, + const std::string& callback_name_for_testing, + int extension_api_frame_id, + int extension_api_parent_frame_id) { + results_.push_back(callback_name_for_testing); + + // If this fails, then the mapping is completely wrong. + EXPECT_EQ(ToTestFrameId(render_process_id, frame_routing_id), + extension_api_frame_id); + EXPECT_EQ(ToTestParentFrameId(render_process_id, frame_routing_id), + extension_api_parent_frame_id); + } + + const std::vector<std::string>& results() { return results_; } + void ClearResults() { results_.clear(); } + + private: + content::TestBrowserThreadBundle thread_bundle_; + // Used to verify the order of callbacks. + std::vector<std::string> results_; + + DISALLOW_COPY_AND_ASSIGN(ExtensionApiFrameIdMapTest); +}; + +} // namespace + +TEST_F(ExtensionApiFrameIdMapTest, GetFrameIdOnIO) { + TestExtensionApiFrameIdMap map; + EXPECT_EQ(0, map.GetInternalSize()); + + // Two identical calls, should be processed at the next message loop. + map.GetFrameIdOnIO(1, 2, CreateCallback(1, 2, "first")); + EXPECT_EQ(1, map.GetInternalCallbackCount()); + EXPECT_EQ(0, map.GetInternalSize()); + + map.GetFrameIdOnIO(1, 2, CreateCallback(1, 2, "first again")); + EXPECT_EQ(2, map.GetInternalCallbackCount()); + EXPECT_EQ(0, map.GetInternalSize()); + + // First get the frame ID on IO (queued on message loop), then set it on UI. + // No callbacks should be invoked because the IO thread cannot know that the + // frame ID was set on the UI thread. + map.GetFrameIdOnIO(2, 1, CreateCallback(2, 1, "something else")); + EXPECT_EQ(3, map.GetInternalCallbackCount()); + EXPECT_EQ(0, map.GetInternalSize()); + + map.SetInternalFrameId(2, 1); + EXPECT_EQ(1, map.GetInternalSize()); + EXPECT_EQ(0U, results().size()); + + // Run some self-contained test. They should not affect the above callbacks. + { + // Callbacks for invalid IDs should immediately be run because it doesn't + // require a thread hop to determine their invalidity. + map.GetFrameIdOnIO(-1, MSG_ROUTING_NONE, + CreateCallback(-1, MSG_ROUTING_NONE, "invalid IDs")); + EXPECT_EQ(3, map.GetInternalCallbackCount()); // No change. + EXPECT_EQ(1, map.GetInternalSize()); // No change. + ASSERT_EQ(1U, results().size()); // +1 + EXPECT_EQ("invalid IDs", results()[0]); + ClearResults(); + } + + { + // First set the frame ID on UI, then get it on IO. Callback should + // immediately be invoked. + map.SetInternalFrameId(3, 1); + EXPECT_EQ(2, map.GetInternalSize()); + + map.GetFrameIdOnIO(3, 1, CreateCallback(3, 1, "the only result")); + EXPECT_EQ(3, map.GetInternalCallbackCount()); // No change. + EXPECT_EQ(2, map.GetInternalSize()); // +1 + ASSERT_EQ(1U, results().size()); // +1 + EXPECT_EQ("the only result", results()[0]); + ClearResults(); + } + + { + // Request the frame ID on IO, set the frame ID (in reality, set on the UI), + // and request another frame ID. The last query should cause both callbacks + // to run because the frame ID is known at the time of the call. + map.GetFrameIdOnIO(7, 2, CreateCallback(7, 2, "queued")); + EXPECT_EQ(4, map.GetInternalCallbackCount()); // +1 + + map.SetInternalFrameId(7, 2); + EXPECT_EQ(3, map.GetInternalSize()); // +1 + + map.GetFrameIdOnIO(7, 2, CreateCallback(7, 2, "not queued")); + EXPECT_EQ(3, map.GetInternalCallbackCount()); // -1 (first callback ran). + EXPECT_EQ(3, map.GetInternalSize()); // No change. + ASSERT_EQ(2U, results().size()); // +2 (both callbacks ran). + EXPECT_EQ("queued", results()[0]); + EXPECT_EQ("not queued", results()[1]); + ClearResults(); + } + + // A call identical to the very first call. + map.GetFrameIdOnIO(1, 2, CreateCallback(1, 2, "same as first")); + EXPECT_EQ(4, map.GetInternalCallbackCount()); + EXPECT_EQ(3, map.GetInternalSize()); + + // Trigger the queued callbacks. + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(0, map.GetInternalCallbackCount()); // -4 (no queued callbacks). + + EXPECT_EQ(4, map.GetInternalSize()); // +1 (1 new cached frame ID). + ASSERT_EQ(4U, results().size()); // +4 (callbacks ran). + + // PostTasks are processed in order, so the very first callbacks should be + // processed. As soon as the first callback is available, all of its callbacks + // should be run (no deferrals!). + EXPECT_EQ("first", results()[0]); + EXPECT_EQ("first again", results()[1]); + EXPECT_EQ("same as first", results()[2]); + // This was queued after "first again", but has a different frame ID, so it + // is received after "same as first". + EXPECT_EQ("something else", results()[3]); + ClearResults(); + + // Request the frame ID for input that was already looked up. Should complete + // synchronously. + map.GetFrameIdOnIO(1, 2, CreateCallback(1, 2, "first and cached")); + EXPECT_EQ(0, map.GetInternalCallbackCount()); // No change. + EXPECT_EQ(4, map.GetInternalSize()); // No change. + ASSERT_EQ(1U, results().size()); // +1 (synchronous callback). + EXPECT_EQ("first and cached", results()[0]); + ClearResults(); + + // Trigger frame removal and look up frame ID. The frame ID should no longer + // be available. and GetFrameIdOnIO() should require a thread hop. + map.RemoveInternalFrameId(1, 2); + EXPECT_EQ(3, map.GetInternalSize()); // -1 + map.GetFrameIdOnIO(1, 2, CreateCallback(1, 2, "first was removed")); + EXPECT_EQ(1, map.GetInternalCallbackCount()); // +1 + ASSERT_EQ(0U, results().size()); // No change (queued callback). + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(0, map.GetInternalCallbackCount()); // -1 (callback not in queue). + EXPECT_EQ(4, map.GetInternalSize()); // +1 (cached frame ID). + ASSERT_EQ(1U, results().size()); // +1 (callback ran). + EXPECT_EQ("first was removed", results()[0]); +} + +} // namespace extensions
diff --git a/extensions/browser/extension_web_contents_observer.cc b/extensions/browser/extension_web_contents_observer.cc index 757c1af..ac482df 100644 --- a/extensions/browser/extension_web_contents_observer.cc +++ b/extensions/browser/extension_web_contents_observer.cc
@@ -12,6 +12,7 @@ #include "content/public/browser/site_instance.h" #include "content/public/browser/web_contents.h" #include "content/public/common/url_constants.h" +#include "extensions/browser/extension_api_frame_id_map.h" #include "extensions/browser/extension_prefs.h" #include "extensions/browser/extension_registry.h" #include "extensions/browser/extensions_browser_client.h" @@ -110,12 +111,18 @@ void ExtensionWebContentsObserver::RenderFrameCreated( content::RenderFrameHost* render_frame_host) { InitializeRenderFrame(render_frame_host); + + // Optimization: Look up the extension API frame ID to force the mapping to be + // cached. This minimizes the number of IO->UI->IO thread hops when the ID is + // looked up again on the IO thread for the webRequest API. + ExtensionApiFrameIdMap::Get()->CacheFrameId(render_frame_host); } void ExtensionWebContentsObserver::RenderFrameDeleted( content::RenderFrameHost* render_frame_host) { ProcessManager::Get(browser_context_) ->UnregisterRenderFrameHost(render_frame_host); + ExtensionApiFrameIdMap::Get()->RemoveFrameId(render_frame_host); } void ExtensionWebContentsObserver::DidCommitProvisionalLoadForFrame(
diff --git a/extensions/common/constants.cc b/extensions/common/constants.cc index a481dcd..cfd00c1 100644 --- a/extensions/common/constants.cc +++ b/extensions/common/constants.cc
@@ -81,7 +81,4 @@ // Keep in sync with _api_features.json and _manifest_features.json. }; -const char* const kIMEExtensionIds[2] = {"gjaehgfemfahhmlgpdfknkhdnemmolop", - "jkghodnilhceideoidjikpgommlajknk"}; - } // namespace extension_misc
diff --git a/extensions/common/constants.h b/extensions/common/constants.h index 6ecbe2b..d2bbb43 100644 --- a/extensions/common/constants.h +++ b/extensions/common/constants.h
@@ -210,9 +210,6 @@ // Extension ids used by Hangouts. extern const char* const kHangoutsExtensionIds[6]; -// Extension ids used by IME. -extern const char* const kIMEExtensionIds[2]; - } // namespace extension_misc #endif // EXTENSIONS_COMMON_CONSTANTS_H_
diff --git a/extensions/common/extension_messages.h b/extensions/common/extension_messages.h index ce8f2517..6ff3cf1 100644 --- a/extensions/common/extension_messages.h +++ b/extensions/common/extension_messages.h
@@ -182,14 +182,6 @@ // The URL of the frame that initiated the request. IPC_STRUCT_MEMBER(GURL, source_url) - // The ID of the tab that is the target of the request, or -1 if there is no - // target tab. - IPC_STRUCT_MEMBER(int, target_tab_id) - - // The ID of the frame that is the target of the request, or -1 if there is - // no target frame (implying the message is for all frames). - IPC_STRUCT_MEMBER(int, target_frame_id) - // The process ID of the webview that initiated the request. IPC_STRUCT_MEMBER(int, guest_process_id) @@ -642,38 +634,46 @@ // sending messages. If an error occurred, the opener will be notified // asynchronously. IPC_SYNC_MESSAGE_CONTROL4_1(ExtensionHostMsg_OpenChannelToExtension, - int /* routing_id */, + int /* frame_routing_id */, ExtensionMsg_ExternalConnectionInfo, std::string /* channel_name */, bool /* include_tls_channel_id */, int /* port_id */) IPC_SYNC_MESSAGE_CONTROL3_1(ExtensionHostMsg_OpenChannelToNativeApp, - int /* routing_id */, + int /* frame_routing_id */, std::string /* source_extension_id */, std::string /* native_app_name */, int /* port_id */) // Get a port handle to the given tab. The handle can be used for sending // messages to the extension. -IPC_SYNC_MESSAGE_CONTROL3_1(ExtensionHostMsg_OpenChannelToTab, +IPC_SYNC_MESSAGE_CONTROL4_1(ExtensionHostMsg_OpenChannelToTab, + int /* frame_routing_id */, ExtensionMsg_TabTargetConnectionInfo, std::string /* extension_id */, std::string /* channel_name */, int /* port_id */) +// Sent in response to ExtensionMsg_DispatchOnConnect when the port is accepted. +// The handle is the value returned by ExtensionHostMsg_OpenChannelTo*. +IPC_MESSAGE_CONTROL2(ExtensionHostMsg_OpenMessagePort, + int /* frame_routing_id */, + int /* port_id */); + +// Sent in response to ExtensionMsg_DispatchOnConnect and whenever the port is +// closed. The handle is the value returned by ExtensionHostMsg_OpenChannelTo*. +IPC_MESSAGE_CONTROL3(ExtensionHostMsg_CloseMessagePort, + int /* frame_routing_id */, + int /* port_id */, + bool /* force_close */); + // Send a message to an extension process. The handle is the value returned -// by ViewHostMsg_OpenChannelTo*. +// by ExtensionHostMsg_OpenChannelTo*. IPC_MESSAGE_ROUTED2(ExtensionHostMsg_PostMessage, int /* port_id */, extensions::Message) -// Send a message to an extension process. The handle is the value returned -// by ViewHostMsg_OpenChannelTo*. -IPC_MESSAGE_CONTROL2(ExtensionHostMsg_CloseChannel, - int /* port_id */, - std::string /* error_message */) - // Used to get the extension message bundle. IPC_SYNC_MESSAGE_CONTROL1_1(ExtensionHostMsg_GetMessageBundle, std::string /* extension id */,
diff --git a/extensions/common/file_util.cc b/extensions/common/file_util.cc index 3ddf6d0..ae12f2c 100644 --- a/extensions/common/file_util.cc +++ b/extensions/common/file_util.cc
@@ -56,6 +56,12 @@ }; SafeInstallationFlag g_use_safe_installation = DEFAULT; +// Returns true if the given file path exists and is not zero-length. +bool ValidateFilePath(const base::FilePath& path) { + int64_t size = 0; + return base::PathExists(path) && base::GetFileSize(path, &size) && size != 0; +} + // Returns true if the extension installation should flush all files and the // directory. bool UseSafeInstallation() { @@ -263,11 +269,6 @@ return base::DictionaryValue::From(std::move(root)); } -bool ValidateFilePath(const base::FilePath& path) { - int64_t size = 0; - return base::PathExists(path) && base::GetFileSize(path, &size) && size != 0; -} - bool ValidateExtension(const Extension* extension, std::string* error, std::vector<InstallWarning>* warnings) {
diff --git a/extensions/common/file_util.h b/extensions/common/file_util.h index 609b27ce..3fda56ad 100644 --- a/extensions/common/file_util.h +++ b/extensions/common/file_util.h
@@ -72,9 +72,6 @@ const base::FilePath::CharType* manifest_filename, std::string* error); -// Returns true if the given file path exists and is not zero-length. -bool ValidateFilePath(const base::FilePath& path); - // Returns true if the given extension object is valid and consistent. // May also append a series of warning messages to |warnings|, but they // should not prevent the extension from running.
diff --git a/extensions/common/file_util_unittest.cc b/extensions/common/file_util_unittest.cc index afbcf3c..c058400 100644 --- a/extensions/common/file_util_unittest.cc +++ b/extensions/common/file_util_unittest.cc
@@ -430,13 +430,7 @@ std::string error; scoped_refptr<Extension> extension(file_util::LoadExtension( ext_dir, Manifest::INTERNAL, Extension::NO_FLAGS, &error)); - EXPECT_TRUE(extension); - ASSERT_EQ(2U, extension->install_warnings().size()); - - EXPECT_EQ("Could not load extension icon 'missing-icon.png'.", - extension->install_warnings()[0].message); - EXPECT_EQ("Could not load extension icon 'icon.png'.", - extension->install_warnings()[1].message); + ASSERT_FALSE(extension); } // Try to install an unpacked extension with a zero-length icon file.
diff --git a/extensions/common/manifest_handler_helpers.cc b/extensions/common/manifest_handler_helpers.cc index 36af224d..bfc9e33 100644 --- a/extensions/common/manifest_handler_helpers.cc +++ b/extensions/common/manifest_handler_helpers.cc
@@ -13,10 +13,7 @@ #include "extensions/common/error_utils.h" #include "extensions/common/extension.h" #include "extensions/common/extension_icon_set.h" -#include "extensions/common/file_util.h" #include "extensions/common/manifest_constants.h" -#include "grit/extensions_strings.h" -#include "ui/base/l10n/l10n_util.h" namespace extensions { @@ -35,8 +32,7 @@ return true; } -bool LoadIconsFromDictionary(Extension* extension, - const base::DictionaryValue* icons_value, +bool LoadIconsFromDictionary(const base::DictionaryValue* icons_value, ExtensionIconSet* icons, base::string16* error) { DCHECK(icons); @@ -53,23 +49,7 @@ return false; } - // For backwards compatibility, only warn (don't error out) if an icon is - // missing. Component extensions can skip this check as their icons are not - // located on disk. Unpacked extensions skip this check and fail later - // during validation if the file isn't present. See crbug.com/570249 - // TODO(estade|devlin): remove this workaround and let install fail in the - // validate step a few releases after M49. See http://crbug.com/571193 - if (Manifest::IsComponentLocation(extension->location()) || - Manifest::IsUnpackedLocation(extension->location()) || - file_util::ValidateFilePath( - extension->GetResource(icon_path).GetFilePath())) { - icons->Add(size, icon_path); - } else { - extension->AddInstallWarning(InstallWarning( - l10n_util::GetStringFUTF8(IDS_EXTENSION_LOAD_ICON_FAILED, - base::UTF8ToUTF16(icon_path)), - std::string())); - } + icons->Add(size, icon_path); } return true; }
diff --git a/extensions/common/manifest_handler_helpers.h b/extensions/common/manifest_handler_helpers.h index e1f901a..b0249c30 100644 --- a/extensions/common/manifest_handler_helpers.h +++ b/extensions/common/manifest_handler_helpers.h
@@ -6,11 +6,9 @@ #define EXTENSIONS_COMMON_MANIFEST_HANDLER_HELPERS_H_ #include <string> -#include <vector> #include "base/memory/scoped_ptr.h" #include "base/strings/string16.h" -#include "extensions/common/install_warning.h" class ExtensionIconSet; @@ -19,9 +17,6 @@ } namespace extensions { - -class Extension; - namespace manifest_handler_helpers { // Strips leading slashes from the file path. Returns true iff the final path is @@ -30,10 +25,8 @@ // Loads icon paths defined in dictionary |icons_value| into ExtensionIconSet // |icons|. |icons_value| is a dictionary value {icon size -> icon path}. -// Returns success. If load fails, |error| will be set. Non-failure warnings may -// be added to |extension|. -bool LoadIconsFromDictionary(Extension* extension, - const base::DictionaryValue* icons_value, +// Returns success. If load fails, |error| will be set. +bool LoadIconsFromDictionary(const base::DictionaryValue* icons_value, ExtensionIconSet* icons, base::string16* error);
diff --git a/extensions/common/manifest_handlers/icons_handler.cc b/extensions/common/manifest_handlers/icons_handler.cc index 52597e5..20ad025b 100644 --- a/extensions/common/manifest_handlers/icons_handler.cc +++ b/extensions/common/manifest_handlers/icons_handler.cc
@@ -64,7 +64,7 @@ } if (!manifest_handler_helpers::LoadIconsFromDictionary( - extension, icons_dict, &icons_info->icons, error)) { + icons_dict, &icons_info->icons, error)) { return false; }
diff --git a/extensions/components/native_app_window/OWNERS b/extensions/components/native_app_window/OWNERS index 1ecba6c9b..aac10b5b 100644 --- a/extensions/components/native_app_window/OWNERS +++ b/extensions/components/native_app_window/OWNERS
@@ -1,2 +1,2 @@ benwells@chromium.org -jackhou@chromium.org +tapted@chromium.org
diff --git a/extensions/extensions.gypi b/extensions/extensions.gypi index e18e6822..b49e007 100644 --- a/extensions/extensions.gypi +++ b/extensions/extensions.gypi
@@ -565,6 +565,8 @@ 'browser/event_router.h', 'browser/event_router_factory.cc', 'browser/event_router_factory.h', + 'browser/extension_api_frame_id_map.cc', + 'browser/extension_api_frame_id_map.h', 'browser/extension_dialog_auto_confirm.cc', 'browser/extension_dialog_auto_confirm.h', 'browser/extension_error.cc',
diff --git a/extensions/extensions_tests.gypi b/extensions/extensions_tests.gypi index e164a8c..2c7209af 100644 --- a/extensions/extensions_tests.gypi +++ b/extensions/extensions_tests.gypi
@@ -77,6 +77,7 @@ 'browser/error_map_unittest.cc', 'browser/event_listener_map_unittest.cc', 'browser/event_router_unittest.cc', + 'browser/extension_api_frame_id_map_unittest.cc', 'browser/extension_icon_image_unittest.cc', 'browser/extension_pref_value_map_unittest.cc', 'browser/extension_registry_unittest.cc',
diff --git a/extensions/renderer/messaging_bindings.cc b/extensions/renderer/messaging_bindings.cc index a0a855f..722bc72 100644 --- a/extensions/renderer/messaging_bindings.cc +++ b/extensions/renderer/messaging_bindings.cc
@@ -130,8 +130,6 @@ base::LazyInstance<PortTracker> g_port_tracker = LAZY_INSTANCE_INITIALIZER; const char kPortClosedError[] = "Attempting to use a disconnected port object"; -const char kReceivingEndDoesntExistError[] = - "Could not establish connection. Receiving end does not exist."; class ExtensionImpl : public ObjectBackedNativeHandler { public: @@ -175,8 +173,8 @@ // Sends a message along the given channel. void PostMessage(const v8::FunctionCallbackInfo<v8::Value>& args) { - content::RenderFrame* renderframe = context()->GetRenderFrame(); - if (!renderframe) + content::RenderFrame* render_frame = context()->GetRenderFrame(); + if (!render_frame) return; // Arguments are (int32_t port_id, string message). @@ -190,8 +188,8 @@ return; } - renderframe->Send(new ExtensionHostMsg_PostMessage( - renderframe->GetRoutingID(), port_id, + render_frame->Send(new ExtensionHostMsg_PostMessage( + render_frame->GetRoutingID(), port_id, Message(*v8::String::Utf8Value(args[1]), blink::WebUserGestureIndicator::isProcessingUserGesture()))); } @@ -209,9 +207,10 @@ // Send via the RenderThread because the RenderFrame might be closing. bool notify_browser = args[1].As<v8::Boolean>()->Value(); - if (notify_browser) { - content::RenderThread::Get()->Send( - new ExtensionHostMsg_CloseChannel(port_id, std::string())); + content::RenderFrame* render_frame = context()->GetRenderFrame(); + if (notify_browser && render_frame) { + render_frame->Send(new ExtensionHostMsg_CloseMessagePort( + render_frame->GetRoutingID(), port_id, true)); } ClearPortDataAndNotifyDispatcher(port_id); @@ -231,6 +230,8 @@ // The frame a port lived in has been destroyed. When there are no more // frames with a reference to a given port, we will disconnect it and notify // the other end of the channel. + // TODO(robwu): Port lifetime management has moved to the browser, this is no + // longer needed. See .destroy_() inmessaging.js for more details. void PortRelease(const v8::FunctionCallbackInfo<v8::Value>& args) { // Arguments are (int32_t port_id). CHECK(args.Length() == 1 && args[0]->IsInt32()); @@ -240,12 +241,11 @@ // Releases the reference to |port_id| for this context, and clears all port // data if there are no more references. void ReleasePort(int port_id) { + content::RenderFrame* render_frame = context()->GetRenderFrame(); if (g_port_tracker.Get().RemoveReference(context(), port_id) && - !g_port_tracker.Get().HasPort(port_id)) { - // Send via the RenderThread because the RenderFrame might be closing. - content::RenderThread::Get()->Send( - new ExtensionHostMsg_CloseChannel(port_id, std::string())); - ClearPortDataAndNotifyDispatcher(port_id); + !g_port_tracker.Get().HasPort(port_id) && render_frame) { + render_frame->Send(new ExtensionHostMsg_CloseMessagePort( + render_frame->GetRoutingID(), port_id, false)); } } @@ -286,23 +286,6 @@ const std::string& tls_channel_id, bool* port_created, ScriptContext* script_context) { - // Only dispatch the events if this is the requested target frame (0 = main - // frame; positive = child frame). - content::RenderFrame* renderframe = script_context->GetRenderFrame(); - if (info.target_frame_id == 0 && renderframe->GetWebFrame()->parent() != NULL) - return; - if (info.target_frame_id > 0 && - renderframe->GetRoutingID() != info.target_frame_id) - return; - - // Bandaid fix for crbug.com/520303. - // TODO(rdevlin.cronin): Fix this properly by routing messages to the correct - // RenderFrame from the browser (same with |target_frame_id| in fact). - if (info.target_tab_id != -1 && - info.target_tab_id != ExtensionFrameHelper::Get(renderframe)->tab_id()) { - return; - } - v8::Isolate* isolate = script_context->isolate(); v8::HandleScope handle_scope(isolate); @@ -472,11 +455,15 @@ base::Bind(&DispatchOnConnectToScriptContext, target_port_id, channel_name, &source, info, tls_channel_id, &port_created)); - // If we didn't create a port, notify the other end of the channel (treat it - // as a disconnect). - if (!port_created) { - content::RenderThread::Get()->Send(new ExtensionHostMsg_CloseChannel( - target_port_id, kReceivingEndDoesntExistError)); + int routing_id = restrict_to_render_frame + ? restrict_to_render_frame->GetRoutingID() + : MSG_ROUTING_NONE; + if (port_created) { + content::RenderThread::Get()->Send( + new ExtensionHostMsg_OpenMessagePort(routing_id, target_port_id)); + } else { + content::RenderThread::Get()->Send(new ExtensionHostMsg_CloseMessagePort( + routing_id, target_port_id, false)); } }
diff --git a/extensions/renderer/resources/messaging.js b/extensions/renderer/resources/messaging.js index 5a7ec1e4..a15497d 100644 --- a/extensions/renderer/resources/messaging.js +++ b/extensions/renderer/resources/messaging.js
@@ -76,6 +76,16 @@ this.onDestroy_(); privates(this.onDisconnect).impl.destroy_(); privates(this.onMessage).impl.destroy_(); + // TODO(robwu): Remove port lifetime management because it is completely + // handled in the browser. The renderer's only roles are + // 1) rejecting ports so that the browser knows that the renderer is not + // interested in the port (this is merely an optimization) + // 2) acknowledging port creations, so that the browser knows that the port + // was successfully created (from the perspective of the extension), but + // then closed for some non-fatal reason. + // 3) notifying the browser of explicit port closure via .disconnect(). + // In other cases (navigations), the browser automatically cleans up the + // port. messagingNatives.PortRelease(this.portId_); delete ports[this.portId_]; };
diff --git a/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_compressed_copy_texture.txt b/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_compressed_copy_texture.txt index d4f823e..9c080d8 100644 --- a/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_compressed_copy_texture.txt +++ b/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_compressed_copy_texture.txt
@@ -71,48 +71,6 @@ INVALID_VALUE is generated if level 0 of the source texture is not defined. - The command - - void glCompressedCopySubTextureCHROMIUM (GLenum target, - GLenum source_id, - GLenum dest_id, - GLint xoffset, GLint yoffset, - GLint x, GLint y, - GLsizei width, GLsizei height) - - Copies the sub contents of texture referred to by <source_id> to <dest_id> - texture without redefining <dest_id> texture. - - <target> uses the same parameters as TexImage2D. - - <xoffset> and <yoffset> specify a texel offset in the x and y direction - respectively within the destination texture. - - <x> and <y> specify a texel offset in the x and y direction respectively - within the source texture. - - <width> specifies the width of the texture subimage. - - <height> specifies the width of the texture subimage. - - INVALID_OPERATION is generated if internal format of source texture is not - one of the following: GL_ATC_RGB_AMD, GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD, - GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, - GL_ETC1_RGB8_OES - - INVALID_VALUE is generated if <target> is not GL_TEXTURE_2D. - - INVALID_OPERATION is generated if the destination texture has not been - defined. - - INVALID_VALUE is generated if level 0 of the source texture or - the destination texture is not defined. - - INVALID_VALUE is generated if <xoffset> < 0 , or <yoffset> < 0. - - INVALID_VALUE is generated if (<xoffset> + <width>) > dest_width, - or (<yoffset> + <height>) > dest_height. - Errors None. @@ -129,3 +87,4 @@ 15/6/2015 Documented the extension. 5/8/2015 Added glCompressedCopySubTextureCHROMIUM. + 1/6/2016 Remove glCompressedCopySubTextureCHROMIUM.
diff --git a/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_copy_texture.txt b/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_copy_texture.txt index 101c0f6..71a84b8b 100644 --- a/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_copy_texture.txt +++ b/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_copy_texture.txt
@@ -33,16 +33,14 @@ The command - void glCopyTextureCHROMIUM (GLenum target, GLenum source_id, + void glCopyTextureCHROMIUM (GLenum source_id, GLenum dest_id, GLint internal_format, GLenum dest_type, GLboolean unpack_flip_y, GLboolean unpack_premultiply_alpha, GLboolean unpack_unmultiply_alpha) - Copies the contents of texture referred to by <source_id> to <dest_id> - texture. If <source_id> texture is not defined or has different dimension - to <dest_id> texture, define <source_id> texture same to <dest_id> texture. + Copies the contents of <source_id> texture to <dest_id> texture. Texture level 0 is copied from the source image to level 0 of the destination texture. @@ -70,8 +68,6 @@ The format type of the destination texture is converted to that specified by <dest_type>. - <target> uses the same parameters as TexImage2D. - If <flip_y> is true, vertically flip texture image data. If <unpack_premultiply_alpha> and <unpack_unmultiply_alpha> are true, @@ -84,13 +80,11 @@ INVALID_OPERATION is generated if the internal format of <source_id> is not one of formats from the table above. - INVALID_VALUE is generated if <target> is not GL_TEXTURE_2D. - INVALID_VALUE is generated if <source_id> or <dest_id> are not valid texture objects. INVALID_VALUE is generated if textures corresponding to <dest_id> have not - been bound as GL_TEXTURE_2D object. + been bound as GL_TEXTURE_2D or GL_TEXTURE_RECTANGLE_ARB objects. INVALID_VALUE is generated if textures corresponding to <source_id> have not been bound as GL_TEXTURE_2D, GL_TEXTURE_RECTANGLE_ARB or @@ -100,7 +94,7 @@ The command - void glCopySubTextureCHROMIUM (GLenum target, GLenum source_id, + void glCopySubTextureCHROMIUM (GLenum source_id, GLenum dest_id, GLint xoffset, GLint yoffset, GLint x, GLint y, @@ -112,7 +106,7 @@ Copies the sub contents of texture referred to by <source_id> to <dest_id> texture without redefining <dest_id> texture. - See CopyTextureCHROMIUM for the interpretation of the <target>, <flip_y>, + See CopyTextureCHROMIUM for the interpretation of the <flip_y>, <premultiply_alpha>, and <unmultiply_alpha> arguments. <xoffset> and <yoffset> specify a texel offset in the x and y direction @@ -125,14 +119,18 @@ <height> specifies the width of the texture subimage. + INVALID_VALUE is generated if either <source_id> texture or <dest_id> + texture is not defined. + INVALID_OPERATION is generated if source internal_format and destination internal_format are not one of the valid formats described above. - INVALID_VALUE is generated if <target> is not GL_TEXTURE_2D. - INVALID_OPERATION is generated if the destination texture has not been defined. + INVALID_VALUE is generated if <dest_id> texture is not bound as + GL_TEXTURE_2D or GL_TEXTURE_RECTANGLE_ARB. + INVALID_VALUE is generated if level 0 of the source texture or the destination texture is not defined. @@ -170,3 +168,5 @@ 16/7/2014 Add GL_TEXTURE_RECTANGLE_ARB as valid source_id target 19/6/2015 Add arguments unpack_flip_y, unpack_premultiply_alpha, and unpack_unmultiply_alpha to both commands. + 4/1/2016 Removed the argument target. + 4/1/2016 Added GL_TEXTURE_RECTANGLE_ARB as valid dest_id target
diff --git a/gpu/GLES2/gl2chromium_autogen.h b/gpu/GLES2/gl2chromium_autogen.h index 7429cab..2e757eb 100644 --- a/gpu/GLES2/gl2chromium_autogen.h +++ b/gpu/GLES2/gl2chromium_autogen.h
@@ -297,8 +297,6 @@ #define glCopySubTextureCHROMIUM GLES2_GET_FUN(CopySubTextureCHROMIUM) #define glCompressedCopyTextureCHROMIUM \ GLES2_GET_FUN(CompressedCopyTextureCHROMIUM) -#define glCompressedCopySubTextureCHROMIUM \ - GLES2_GET_FUN(CompressedCopySubTextureCHROMIUM) #define glDrawArraysInstancedANGLE GLES2_GET_FUN(DrawArraysInstancedANGLE) #define glDrawElementsInstancedANGLE GLES2_GET_FUN(DrawElementsInstancedANGLE) #define glVertexAttribDivisorANGLE GLES2_GET_FUN(VertexAttribDivisorANGLE)
diff --git a/gpu/GLES2/gl2extchromium.h b/gpu/GLES2/gl2extchromium.h index 2d8a4499..bed8164 100644 --- a/gpu/GLES2/gl2extchromium.h +++ b/gpu/GLES2/gl2extchromium.h
@@ -367,7 +367,6 @@ #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glCopyTextureCHROMIUM( - GLenum target, GLenum source_id, GLenum dest_id, GLint internalformat, @@ -377,7 +376,6 @@ GLboolean unpack_unmultiply_alpha); GL_APICALL void GL_APIENTRY glCopySubTextureCHROMIUM( - GLenum target, GLenum source_id, GLenum dest_id, GLint xoffset, @@ -391,7 +389,6 @@ GLboolean unpack_unmultiply_alpha); #endif typedef void(GL_APIENTRYP PFNGLCOPYTEXTURECHROMIUMPROC)( - GLenum target, GLenum source_id, GLenum dest_id, GLint internalformat, @@ -401,7 +398,6 @@ GLboolean unpack_unmultiply_alpha); typedef void(GL_APIENTRYP PFNGLCOPYSUBTEXTURECHROMIUMPROC)( - GLenum target, GLenum source_id, GLenum dest_id, GLint xoffset, @@ -421,31 +417,9 @@ #ifdef GL_GLEXT_PROTOTYPES GL_APICALL void GL_APIENTRY glCompressedCopyTextureCHROMIUM( GLenum target, GLenum source_id, GLenum dest_id); - -GL_APICALL void GL_APIENTRY glCompressedCopySubTextureCHROMIUM( - GLenum target, - GLenum source_id, - GLenum dest_id, - GLint xoffset, - GLint yoffset, - GLint x, - GLint y, - GLsizei width, - GLsizei height); #endif typedef void(GL_APIENTRYP PFNGLCOMPRESSEDCOPYTEXTURECHROMIUMPROC)( GLenum target, GLenum source_id, GLenum dest_id); - -typedef void(GL_APIENTRYP PFNGLCOMPRESSEDCOPYSUBTEXTURECHROMIUMPROC)( - GLenum target, - GLenum source_id, - GLenum dest_id, - GLint xoffset, - GLint yoffset, - GLint x, - GLint y, - GLsizei width, - GLsizei height); #endif /* GL_CHROMIUM_compressed_copy_texture */ /* GL_CHROMIUM_lose_context */
diff --git a/gpu/blink/webgraphicscontext3d_impl.cc b/gpu/blink/webgraphicscontext3d_impl.cc index eec0300..5883701 100644 --- a/gpu/blink/webgraphicscontext3d_impl.cc +++ b/gpu/blink/webgraphicscontext3d_impl.cc
@@ -875,9 +875,8 @@ WGC3Denum, WGC3Duint64*) -DELEGATE_TO_GL_8(copyTextureCHROMIUM, +DELEGATE_TO_GL_7(copyTextureCHROMIUM, CopyTextureCHROMIUM, - WGC3Denum, WebGLId, WebGLId, WGC3Denum, @@ -886,9 +885,8 @@ WGC3Dboolean, WGC3Dboolean); -DELEGATE_TO_GL_12(copySubTextureCHROMIUM, +DELEGATE_TO_GL_11(copySubTextureCHROMIUM, CopySubTextureCHROMIUM, - WGC3Denum, WebGLId, WebGLId, WGC3Dint,
diff --git a/gpu/blink/webgraphicscontext3d_impl.h b/gpu/blink/webgraphicscontext3d_impl.h index b3c1dea..b468ca0 100644 --- a/gpu/blink/webgraphicscontext3d_impl.h +++ b/gpu/blink/webgraphicscontext3d_impl.h
@@ -545,7 +545,6 @@ blink::WGC3Duint64* params) override; void copyTextureCHROMIUM( - blink::WGC3Denum target, blink::WebGLId source_id, blink::WebGLId dest_id, blink::WGC3Denum internal_format, @@ -555,7 +554,6 @@ blink::WGC3Dboolean unpack_unmultiply_alpha) override; void copySubTextureCHROMIUM( - blink::WGC3Denum target, blink::WebGLId source_id, blink::WebGLId dest_id, blink::WGC3Dint xoffset,
diff --git a/gpu/command_buffer/build_gles2_cmd_buffer.py b/gpu/command_buffer/build_gles2_cmd_buffer.py index 104de37..6809b65 100755 --- a/gpu/command_buffer/build_gles2_cmd_buffer.py +++ b/gpu/command_buffer/build_gles2_cmd_buffer.py
@@ -436,56 +436,64 @@ 'type': 'GLint', 'enum': 'GL_PACK_ROW_LENGTH', 'default': '0', - 'es3': True + 'es3': True, + 'manual': True, }, { 'name': 'pack_skip_pixels', 'type': 'GLint', 'enum': 'GL_PACK_SKIP_PIXELS', 'default': '0', - 'es3': True + 'es3': True, + 'manual': True, }, { 'name': 'pack_skip_rows', 'type': 'GLint', 'enum': 'GL_PACK_SKIP_ROWS', 'default': '0', - 'es3': True + 'es3': True, + 'manual': True, }, { 'name': 'unpack_row_length', 'type': 'GLint', 'enum': 'GL_UNPACK_ROW_LENGTH', 'default': '0', - 'es3': True + 'es3': True, + 'manual': True, }, { 'name': 'unpack_image_height', 'type': 'GLint', 'enum': 'GL_UNPACK_IMAGE_HEIGHT', 'default': '0', - 'es3': True + 'es3': True, + 'manual': True, }, { 'name': 'unpack_skip_pixels', 'type': 'GLint', 'enum': 'GL_UNPACK_SKIP_PIXELS', 'default': '0', - 'es3': True + 'es3': True, + 'manual': True, }, { 'name': 'unpack_skip_rows', 'type': 'GLint', 'enum': 'GL_UNPACK_SKIP_ROWS', 'default': '0', - 'es3': True + 'es3': True, + 'manual': True, }, { 'name': 'unpack_skip_images', 'type': 'GLint', 'enum': 'GL_UNPACK_SKIP_IMAGES', 'default': '0', - 'es3': True + 'es3': True, + 'manual': True, } ], }, @@ -3967,12 +3975,6 @@ 'extension': 'CHROMIUM_copy_compressed_texture', 'chromium': True, }, - 'CompressedCopySubTextureCHROMIUM': { - 'decoder_func': 'DoCompressedCopySubTextureCHROMIUM', - 'unit_test': False, - 'extension': 'CHROMIUM_copy_compressed_texture', - 'chromium': True, - }, 'TexStorage2DEXT': { 'unit_test': False, 'extension': 'EXT_texture_storage', @@ -10453,6 +10455,9 @@ for item in state['states']: item_name = CachedStateName(item) + if 'manual' in item: + assert item['manual'] + continue if 'es3' in item: assert item['es3'] f.write(" if (feature_info_->IsES3Capable()) {\n"); @@ -10513,6 +10518,7 @@ f.write(" } else {") WriteStates(False) f.write(" }") + f.write(" InitStateManual(prev_state);") f.write("}\n") f.write("""bool ContextState::GetEnabled(GLenum cap) const { @@ -10711,6 +10717,9 @@ f.write(" .RetiresOnSaturation();\n") elif state['type'] == 'NamedParameter': for item in state['states']: + if 'manual' in item: + assert item['manual'] + continue if 'extension_flag' in item: f.write(" if (group_->feature_info()->feature_flags().%s) {\n" % item['extension_flag']) @@ -10753,6 +10762,7 @@ f.write(" .RetiresOnSaturation();\n") if 'extension_flag' in state: f.write(" }\n") + f.write(" SetupInitStateManualExpectations(es3_capable);\n") f.write("}\n") self.generated_cpp_filenames.append(filename)
diff --git a/gpu/command_buffer/client/gles2_c_lib_autogen.h b/gpu/command_buffer/client/gles2_c_lib_autogen.h index c866225..3c348b1 100644 --- a/gpu/command_buffer/client/gles2_c_lib_autogen.h +++ b/gpu/command_buffer/client/gles2_c_lib_autogen.h
@@ -1334,8 +1334,7 @@ gles2::GetGLContext()->TexImageIOSurface2DCHROMIUM(target, width, height, ioSurfaceId, plane); } -void GL_APIENTRY GLES2CopyTextureCHROMIUM(GLenum target, - GLenum source_id, +void GL_APIENTRY GLES2CopyTextureCHROMIUM(GLenum source_id, GLenum dest_id, GLint internalformat, GLenum dest_type, @@ -1343,12 +1342,11 @@ GLboolean unpack_premultiply_alpha, GLboolean unpack_unmultiply_alpha) { gles2::GetGLContext()->CopyTextureCHROMIUM( - target, source_id, dest_id, internalformat, dest_type, unpack_flip_y, + source_id, dest_id, internalformat, dest_type, unpack_flip_y, unpack_premultiply_alpha, unpack_unmultiply_alpha); } void GL_APIENTRY -GLES2CopySubTextureCHROMIUM(GLenum target, - GLenum source_id, +GLES2CopySubTextureCHROMIUM(GLenum source_id, GLenum dest_id, GLint xoffset, GLint yoffset, @@ -1360,8 +1358,8 @@ GLboolean unpack_premultiply_alpha, GLboolean unpack_unmultiply_alpha) { gles2::GetGLContext()->CopySubTextureCHROMIUM( - target, source_id, dest_id, xoffset, yoffset, x, y, width, height, - unpack_flip_y, unpack_premultiply_alpha, unpack_unmultiply_alpha); + source_id, dest_id, xoffset, yoffset, x, y, width, height, unpack_flip_y, + unpack_premultiply_alpha, unpack_unmultiply_alpha); } void GL_APIENTRY GLES2CompressedCopyTextureCHROMIUM(GLenum target, GLenum source_id, @@ -1369,18 +1367,6 @@ gles2::GetGLContext()->CompressedCopyTextureCHROMIUM(target, source_id, dest_id); } -void GL_APIENTRY GLES2CompressedCopySubTextureCHROMIUM(GLenum target, - GLenum source_id, - GLenum dest_id, - GLint xoffset, - GLint yoffset, - GLint x, - GLint y, - GLsizei width, - GLsizei height) { - gles2::GetGLContext()->CompressedCopySubTextureCHROMIUM( - target, source_id, dest_id, xoffset, yoffset, x, y, width, height); -} void GL_APIENTRY GLES2DrawArraysInstancedANGLE(GLenum mode, GLint first, GLsizei count, @@ -2758,11 +2744,6 @@ reinterpret_cast<GLES2FunctionPointer>(glCompressedCopyTextureCHROMIUM), }, { - "glCompressedCopySubTextureCHROMIUM", - reinterpret_cast<GLES2FunctionPointer>( - glCompressedCopySubTextureCHROMIUM), - }, - { "glDrawArraysInstancedANGLE", reinterpret_cast<GLES2FunctionPointer>(glDrawArraysInstancedANGLE), },
diff --git a/gpu/command_buffer/client/gles2_cmd_helper_autogen.h b/gpu/command_buffer/client/gles2_cmd_helper_autogen.h index 3d7daa58..b8a40327 100644 --- a/gpu/command_buffer/client/gles2_cmd_helper_autogen.h +++ b/gpu/command_buffer/client/gles2_cmd_helper_autogen.h
@@ -2491,8 +2491,7 @@ } } -void CopyTextureCHROMIUM(GLenum target, - GLenum source_id, +void CopyTextureCHROMIUM(GLenum source_id, GLenum dest_id, GLint internalformat, GLenum dest_type, @@ -2502,13 +2501,12 @@ gles2::cmds::CopyTextureCHROMIUM* c = GetCmdSpace<gles2::cmds::CopyTextureCHROMIUM>(); if (c) { - c->Init(target, source_id, dest_id, internalformat, dest_type, - unpack_flip_y, unpack_premultiply_alpha, unpack_unmultiply_alpha); + c->Init(source_id, dest_id, internalformat, dest_type, unpack_flip_y, + unpack_premultiply_alpha, unpack_unmultiply_alpha); } } -void CopySubTextureCHROMIUM(GLenum target, - GLenum source_id, +void CopySubTextureCHROMIUM(GLenum source_id, GLenum dest_id, GLint xoffset, GLint yoffset, @@ -2522,7 +2520,7 @@ gles2::cmds::CopySubTextureCHROMIUM* c = GetCmdSpace<gles2::cmds::CopySubTextureCHROMIUM>(); if (c) { - c->Init(target, source_id, dest_id, xoffset, yoffset, x, y, width, height, + c->Init(source_id, dest_id, xoffset, yoffset, x, y, width, height, unpack_flip_y, unpack_premultiply_alpha, unpack_unmultiply_alpha); } } @@ -2537,22 +2535,6 @@ } } -void CompressedCopySubTextureCHROMIUM(GLenum target, - GLenum source_id, - GLenum dest_id, - GLint xoffset, - GLint yoffset, - GLint x, - GLint y, - GLsizei width, - GLsizei height) { - gles2::cmds::CompressedCopySubTextureCHROMIUM* c = - GetCmdSpace<gles2::cmds::CompressedCopySubTextureCHROMIUM>(); - if (c) { - c->Init(target, source_id, dest_id, xoffset, yoffset, x, y, width, height); - } -} - void DrawArraysInstancedANGLE(GLenum mode, GLint first, GLsizei count,
diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc index 96d08e1..556eea7 100644 --- a/gpu/command_buffer/client/gles2_implementation.cc +++ b/gpu/command_buffer/client/gles2_implementation.cc
@@ -5589,7 +5589,7 @@ void GLES2Implementation::VerifySyncTokensCHROMIUM(GLbyte **sync_tokens, GLsizei count) { - bool sync_tokens_verified = false; + bool requires_synchronization = false; for (GLsizei i = 0; i < count; ++i) { if (sync_tokens[i]) { SyncToken sync_token; @@ -5601,18 +5601,26 @@ "Cannot verify sync token using this context."); return; } - if (!sync_tokens_verified) { - // Insert a fence sync here and ensure it is received immediately. - // This will require a flush but simplifies things a bit because - // unverified sync tokens only need an ordering barrier. - const uint64_t release = gpu_control_->GenerateFenceSyncRelease(); - FlushHelper(); - const bool verified = gpu_control_->IsFenceSyncFlushReceived(release); - DCHECK(verified); + requires_synchronization = true; + } + } + } - sync_tokens_verified = true; - } + // This step must be done after all unverified tokens have finished processing + // CanWaitUnverifiedSyncToken(), command buffers use that to do any necessary + // flushes. + if (requires_synchronization) { + // Make sure we have no pending ordering barriers by flushing now. + FlushHelper(); + // Ensure all the fence syncs are visible on GPU service. + gpu_control_->EnsureWorkVisible(); + + // We can automatically mark everything as verified now. + for (GLsizei i = 0; i < count; ++i) { + SyncToken sync_token; + memcpy(&sync_token, sync_tokens[i], sizeof(sync_token)); + if (!sync_token.verified_flush()) { sync_token.SetVerifyFlush(); memcpy(sync_tokens[i], &sync_token, sizeof(sync_token)); }
diff --git a/gpu/command_buffer/client/gles2_implementation_autogen.h b/gpu/command_buffer/client/gles2_implementation_autogen.h index b2fa97c..0ac39f92 100644 --- a/gpu/command_buffer/client/gles2_implementation_autogen.h +++ b/gpu/command_buffer/client/gles2_implementation_autogen.h
@@ -927,8 +927,7 @@ GLuint ioSurfaceId, GLuint plane) override; -void CopyTextureCHROMIUM(GLenum target, - GLenum source_id, +void CopyTextureCHROMIUM(GLenum source_id, GLenum dest_id, GLint internalformat, GLenum dest_type, @@ -936,8 +935,7 @@ GLboolean unpack_premultiply_alpha, GLboolean unpack_unmultiply_alpha) override; -void CopySubTextureCHROMIUM(GLenum target, - GLenum source_id, +void CopySubTextureCHROMIUM(GLenum source_id, GLenum dest_id, GLint xoffset, GLint yoffset, @@ -953,16 +951,6 @@ GLenum source_id, GLenum dest_id) override; -void CompressedCopySubTextureCHROMIUM(GLenum target, - GLenum source_id, - GLenum dest_id, - GLint xoffset, - GLint yoffset, - GLint x, - GLint y, - GLsizei width, - GLsizei height) override; - void DrawArraysInstancedANGLE(GLenum mode, GLint first, GLsizei count,
diff --git a/gpu/command_buffer/client/gles2_implementation_impl_autogen.h b/gpu/command_buffer/client/gles2_implementation_impl_autogen.h index 0d091536..2727a878 100644 --- a/gpu/command_buffer/client/gles2_implementation_impl_autogen.h +++ b/gpu/command_buffer/client/gles2_implementation_impl_autogen.h
@@ -3171,7 +3171,6 @@ } void GLES2Implementation::CopyTextureCHROMIUM( - GLenum target, GLenum source_id, GLenum dest_id, GLint internalformat, @@ -3182,21 +3181,19 @@ GPU_CLIENT_SINGLE_THREAD_CHECK(); GPU_CLIENT_LOG( "[" << GetLogPrefix() << "] glCopyTextureCHROMIUM(" - << GLES2Util::GetStringEnum(target) << ", " << GLES2Util::GetStringEnum(source_id) << ", " << GLES2Util::GetStringEnum(dest_id) << ", " << internalformat << ", " << GLES2Util::GetStringPixelType(dest_type) << ", " << GLES2Util::GetStringBool(unpack_flip_y) << ", " << GLES2Util::GetStringBool(unpack_premultiply_alpha) << ", " << GLES2Util::GetStringBool(unpack_unmultiply_alpha) << ")"); - helper_->CopyTextureCHROMIUM( - target, source_id, dest_id, internalformat, dest_type, unpack_flip_y, - unpack_premultiply_alpha, unpack_unmultiply_alpha); + helper_->CopyTextureCHROMIUM(source_id, dest_id, internalformat, dest_type, + unpack_flip_y, unpack_premultiply_alpha, + unpack_unmultiply_alpha); CheckGLError(); } void GLES2Implementation::CopySubTextureCHROMIUM( - GLenum target, GLenum source_id, GLenum dest_id, GLint xoffset, @@ -3211,7 +3208,6 @@ GPU_CLIENT_SINGLE_THREAD_CHECK(); GPU_CLIENT_LOG( "[" << GetLogPrefix() << "] glCopySubTextureCHROMIUM(" - << GLES2Util::GetStringEnum(target) << ", " << GLES2Util::GetStringEnum(source_id) << ", " << GLES2Util::GetStringEnum(dest_id) << ", " << xoffset << ", " << yoffset << ", " << x << ", " << y << ", " << width << ", " @@ -3227,8 +3223,8 @@ return; } helper_->CopySubTextureCHROMIUM( - target, source_id, dest_id, xoffset, yoffset, x, y, width, height, - unpack_flip_y, unpack_premultiply_alpha, unpack_unmultiply_alpha); + source_id, dest_id, xoffset, yoffset, x, y, width, height, unpack_flip_y, + unpack_premultiply_alpha, unpack_unmultiply_alpha); CheckGLError(); } @@ -3244,38 +3240,6 @@ CheckGLError(); } -void GLES2Implementation::CompressedCopySubTextureCHROMIUM(GLenum target, - GLenum source_id, - GLenum dest_id, - GLint xoffset, - GLint yoffset, - GLint x, - GLint y, - GLsizei width, - GLsizei height) { - GPU_CLIENT_SINGLE_THREAD_CHECK(); - GPU_CLIENT_LOG("[" << GetLogPrefix() - << "] glCompressedCopySubTextureCHROMIUM(" - << GLES2Util::GetStringEnum(target) << ", " - << GLES2Util::GetStringEnum(source_id) << ", " - << GLES2Util::GetStringEnum(dest_id) << ", " << xoffset - << ", " << yoffset << ", " << x << ", " << y << ", " - << width << ", " << height << ")"); - if (width < 0) { - SetGLError(GL_INVALID_VALUE, "glCompressedCopySubTextureCHROMIUM", - "width < 0"); - return; - } - if (height < 0) { - SetGLError(GL_INVALID_VALUE, "glCompressedCopySubTextureCHROMIUM", - "height < 0"); - return; - } - helper_->CompressedCopySubTextureCHROMIUM(target, source_id, dest_id, xoffset, - yoffset, x, y, width, height); - CheckGLError(); -} - void GLES2Implementation::GenValuebuffersCHROMIUM(GLsizei n, GLuint* buffers) { GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGenValuebuffersCHROMIUM(" << n << ", " << static_cast<const void*>(buffers) << ")");
diff --git a/gpu/command_buffer/client/gles2_implementation_unittest.cc b/gpu/command_buffer/client/gles2_implementation_unittest.cc index 732107b..e408610c 100644 --- a/gpu/command_buffer/client/gles2_implementation_unittest.cc +++ b/gpu/command_buffer/client/gles2_implementation_unittest.cc
@@ -35,6 +35,7 @@ using testing::InSequence; using testing::Invoke; using testing::Mock; +using testing::Pointee; using testing::Sequence; using testing::StrictMock; using testing::Truly; @@ -3881,14 +3882,10 @@ EXPECT_FALSE(sync_token.verified_flush()); ClearCommands(); - const GLuint64 kVerifyFenceSync = 234u; EXPECT_CALL(*gpu_control_, CanWaitUnverifiedSyncToken(_)) .WillOnce(testing::Return(true)); - EXPECT_CALL(*gpu_control_, GenerateFenceSyncRelease()) - .WillOnce(testing::Return(kVerifyFenceSync)); - EXPECT_CALL(*gpu_control_, IsFenceSyncFlushReceived(kVerifyFenceSync)) - .WillOnce(testing::Return(true)); - gl_->VerifySyncTokensCHROMIUM(sync_token_datas, 1); + EXPECT_CALL(*gpu_control_, EnsureWorkVisible()); + gl_->VerifySyncTokensCHROMIUM(sync_token_datas, arraysize(sync_token_datas)); EXPECT_TRUE(NoCommandsWritten()); EXPECT_EQ(GL_NO_ERROR, CheckError()); @@ -3898,6 +3895,67 @@ EXPECT_TRUE(sync_token.verified_flush()); } +TEST_F(GLES2ImplementationTest, VerifySyncTokensCHROMIUM_Sequence) { + // To verify sync tokens, the sync tokens must all be verified after + // CanWaitUnverifiedSyncTokens() are called. This test ensures the right + // sequence. + ExpectedMemoryInfo result = + GetExpectedResultMemory(sizeof(cmds::GetError::Result)); + EXPECT_CALL(*command_buffer(), OnFlush()) + .WillRepeatedly(SetMemory(result.ptr, GLuint(GL_NO_ERROR))) + .RetiresOnSaturation(); + + const CommandBufferNamespace kNamespaceId = CommandBufferNamespace::GPU_IO; + const GLuint64 kCommandBufferId = 234u; + const GLuint64 kFenceSync1 = 123u; + const GLuint64 kFenceSync2 = 234u; + gpu::SyncToken sync_token1; + gpu::SyncToken sync_token2; + GLbyte* sync_token_datas[] = { sync_token1.GetData(), sync_token2.GetData() }; + + EXPECT_CALL(*gpu_control_, GetNamespaceID()) + .WillRepeatedly(Return(kNamespaceId)); + EXPECT_CALL(*gpu_control_, GetCommandBufferID()) + .WillRepeatedly(Return(kCommandBufferId)); + EXPECT_CALL(*gpu_control_, GetExtraCommandBufferData()) + .WillRepeatedly(Return(0)); + + // Generate sync token 1. + EXPECT_CALL(*gpu_control_, IsFenceSyncRelease(kFenceSync1)) + .WillOnce(Return(true)); + EXPECT_CALL(*gpu_control_, IsFenceSyncFlushed(kFenceSync1)) + .WillOnce(Return(true)); + gl_->GenUnverifiedSyncTokenCHROMIUM(kFenceSync1, sync_token1.GetData()); + ASSERT_TRUE(sync_token1.HasData()); + ASSERT_FALSE(sync_token1.verified_flush()); + + // Generate sync token 2. + EXPECT_CALL(*gpu_control_, IsFenceSyncRelease(kFenceSync2)) + .WillOnce(Return(true)); + EXPECT_CALL(*gpu_control_, IsFenceSyncFlushed(kFenceSync2)) + .WillOnce(Return(true)); + gl_->GenUnverifiedSyncTokenCHROMIUM(kFenceSync2, sync_token2.GetData()); + ASSERT_TRUE(sync_token2.HasData()); + ASSERT_FALSE(sync_token2.verified_flush()); + + // Ensure proper sequence of checking and validating. + Sequence sequence; + EXPECT_CALL(*gpu_control_, CanWaitUnverifiedSyncToken(Pointee(sync_token1))) + .InSequence(sequence) + .WillOnce(Return(true)); + EXPECT_CALL(*gpu_control_, CanWaitUnverifiedSyncToken(Pointee(sync_token2))) + .InSequence(sequence) + .WillOnce(Return(true)); + EXPECT_CALL(*gpu_control_, EnsureWorkVisible()) + .InSequence(sequence); + gl_->VerifySyncTokensCHROMIUM(sync_token_datas, arraysize(sync_token_datas)); + EXPECT_TRUE(NoCommandsWritten()); + EXPECT_EQ(GL_NO_ERROR, CheckError()); + + EXPECT_TRUE(sync_token1.verified_flush()); + EXPECT_TRUE(sync_token2.verified_flush()); +} + TEST_F(GLES2ImplementationTest, WaitSyncTokenCHROMIUM) { const CommandBufferNamespace kNamespaceId = CommandBufferNamespace::GPU_IO; const GLuint64 kCommandBufferId = 234u;
diff --git a/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h b/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h index 604425c..6f3a011 100644 --- a/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h +++ b/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h
@@ -2814,10 +2814,9 @@ cmds::CopyTextureCHROMIUM cmd; }; Cmds expected; - expected.cmd.Init(1, 2, 3, GL_ALPHA, GL_UNSIGNED_BYTE, true, true, true); + expected.cmd.Init(1, 2, GL_ALPHA, GL_UNSIGNED_BYTE, true, true, true); - gl_->CopyTextureCHROMIUM(1, 2, 3, GL_ALPHA, GL_UNSIGNED_BYTE, true, true, - true); + gl_->CopyTextureCHROMIUM(1, 2, GL_ALPHA, GL_UNSIGNED_BYTE, true, true, true); EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))); } @@ -2826,9 +2825,9 @@ cmds::CopySubTextureCHROMIUM cmd; }; Cmds expected; - expected.cmd.Init(1, 2, 3, 4, 5, 6, 7, 8, 9, true, true, true); + expected.cmd.Init(1, 2, 3, 4, 5, 6, 7, 8, true, true, true); - gl_->CopySubTextureCHROMIUM(1, 2, 3, 4, 5, 6, 7, 8, 9, true, true, true); + gl_->CopySubTextureCHROMIUM(1, 2, 3, 4, 5, 6, 7, 8, true, true, true); EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))); } @@ -2843,17 +2842,6 @@ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))); } -TEST_F(GLES2ImplementationTest, CompressedCopySubTextureCHROMIUM) { - struct Cmds { - cmds::CompressedCopySubTextureCHROMIUM cmd; - }; - Cmds expected; - expected.cmd.Init(1, 2, 3, 4, 5, 6, 7, 8, 9); - - gl_->CompressedCopySubTextureCHROMIUM(1, 2, 3, 4, 5, 6, 7, 8, 9); - EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))); -} - TEST_F(GLES2ImplementationTest, DrawArraysInstancedANGLE) { struct Cmds { cmds::DrawArraysInstancedANGLE cmd;
diff --git a/gpu/command_buffer/client/gles2_interface_autogen.h b/gpu/command_buffer/client/gles2_interface_autogen.h index 568f180b..1940d30 100644 --- a/gpu/command_buffer/client/gles2_interface_autogen.h +++ b/gpu/command_buffer/client/gles2_interface_autogen.h
@@ -688,16 +688,14 @@ GLsizei height, GLuint ioSurfaceId, GLuint plane) = 0; -virtual void CopyTextureCHROMIUM(GLenum target, - GLenum source_id, +virtual void CopyTextureCHROMIUM(GLenum source_id, GLenum dest_id, GLint internalformat, GLenum dest_type, GLboolean unpack_flip_y, GLboolean unpack_premultiply_alpha, GLboolean unpack_unmultiply_alpha) = 0; -virtual void CopySubTextureCHROMIUM(GLenum target, - GLenum source_id, +virtual void CopySubTextureCHROMIUM(GLenum source_id, GLenum dest_id, GLint xoffset, GLint yoffset, @@ -711,15 +709,6 @@ virtual void CompressedCopyTextureCHROMIUM(GLenum target, GLenum source_id, GLenum dest_id) = 0; -virtual void CompressedCopySubTextureCHROMIUM(GLenum target, - GLenum source_id, - GLenum dest_id, - GLint xoffset, - GLint yoffset, - GLint x, - GLint y, - GLsizei width, - GLsizei height) = 0; virtual void DrawArraysInstancedANGLE(GLenum mode, GLint first, GLsizei count,
diff --git a/gpu/command_buffer/client/gles2_interface_stub_autogen.h b/gpu/command_buffer/client/gles2_interface_stub_autogen.h index 59c264c..be25847 100644 --- a/gpu/command_buffer/client/gles2_interface_stub_autogen.h +++ b/gpu/command_buffer/client/gles2_interface_stub_autogen.h
@@ -667,16 +667,14 @@ GLsizei height, GLuint ioSurfaceId, GLuint plane) override; -void CopyTextureCHROMIUM(GLenum target, - GLenum source_id, +void CopyTextureCHROMIUM(GLenum source_id, GLenum dest_id, GLint internalformat, GLenum dest_type, GLboolean unpack_flip_y, GLboolean unpack_premultiply_alpha, GLboolean unpack_unmultiply_alpha) override; -void CopySubTextureCHROMIUM(GLenum target, - GLenum source_id, +void CopySubTextureCHROMIUM(GLenum source_id, GLenum dest_id, GLint xoffset, GLint yoffset, @@ -690,15 +688,6 @@ void CompressedCopyTextureCHROMIUM(GLenum target, GLenum source_id, GLenum dest_id) override; -void CompressedCopySubTextureCHROMIUM(GLenum target, - GLenum source_id, - GLenum dest_id, - GLint xoffset, - GLint yoffset, - GLint x, - GLint y, - GLsizei width, - GLsizei height) override; void DrawArraysInstancedANGLE(GLenum mode, GLint first, GLsizei count,
diff --git a/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h b/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h index 9033928..d645e63a 100644 --- a/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h +++ b/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h
@@ -912,7 +912,6 @@ GLuint /* ioSurfaceId */, GLuint /* plane */) {} void GLES2InterfaceStub::CopyTextureCHROMIUM( - GLenum /* target */, GLenum /* source_id */, GLenum /* dest_id */, GLint /* internalformat */, @@ -921,7 +920,6 @@ GLboolean /* unpack_premultiply_alpha */, GLboolean /* unpack_unmultiply_alpha */) {} void GLES2InterfaceStub::CopySubTextureCHROMIUM( - GLenum /* target */, GLenum /* source_id */, GLenum /* dest_id */, GLint /* xoffset */, @@ -936,16 +934,6 @@ void GLES2InterfaceStub::CompressedCopyTextureCHROMIUM(GLenum /* target */, GLenum /* source_id */, GLenum /* dest_id */) {} -void GLES2InterfaceStub::CompressedCopySubTextureCHROMIUM( - GLenum /* target */, - GLenum /* source_id */, - GLenum /* dest_id */, - GLint /* xoffset */, - GLint /* yoffset */, - GLint /* x */, - GLint /* y */, - GLsizei /* width */, - GLsizei /* height */) {} void GLES2InterfaceStub::DrawArraysInstancedANGLE(GLenum /* mode */, GLint /* first */, GLsizei /* count */,
diff --git a/gpu/command_buffer/client/gles2_trace_implementation_autogen.h b/gpu/command_buffer/client/gles2_trace_implementation_autogen.h index 129bc2a..2b86e41 100644 --- a/gpu/command_buffer/client/gles2_trace_implementation_autogen.h +++ b/gpu/command_buffer/client/gles2_trace_implementation_autogen.h
@@ -667,16 +667,14 @@ GLsizei height, GLuint ioSurfaceId, GLuint plane) override; -void CopyTextureCHROMIUM(GLenum target, - GLenum source_id, +void CopyTextureCHROMIUM(GLenum source_id, GLenum dest_id, GLint internalformat, GLenum dest_type, GLboolean unpack_flip_y, GLboolean unpack_premultiply_alpha, GLboolean unpack_unmultiply_alpha) override; -void CopySubTextureCHROMIUM(GLenum target, - GLenum source_id, +void CopySubTextureCHROMIUM(GLenum source_id, GLenum dest_id, GLint xoffset, GLint yoffset, @@ -690,15 +688,6 @@ void CompressedCopyTextureCHROMIUM(GLenum target, GLenum source_id, GLenum dest_id) override; -void CompressedCopySubTextureCHROMIUM(GLenum target, - GLenum source_id, - GLenum dest_id, - GLint xoffset, - GLint yoffset, - GLint x, - GLint y, - GLsizei width, - GLsizei height) override; void DrawArraysInstancedANGLE(GLenum mode, GLint first, GLsizei count,
diff --git a/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h b/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h index 32d9cf5..cf40552 100644 --- a/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h +++ b/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h
@@ -1940,7 +1940,6 @@ } void GLES2TraceImplementation::CopyTextureCHROMIUM( - GLenum target, GLenum source_id, GLenum dest_id, GLint internalformat, @@ -1949,13 +1948,12 @@ GLboolean unpack_premultiply_alpha, GLboolean unpack_unmultiply_alpha) { TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::CopyTextureCHROMIUM"); - gl_->CopyTextureCHROMIUM(target, source_id, dest_id, internalformat, - dest_type, unpack_flip_y, unpack_premultiply_alpha, + gl_->CopyTextureCHROMIUM(source_id, dest_id, internalformat, dest_type, + unpack_flip_y, unpack_premultiply_alpha, unpack_unmultiply_alpha); } void GLES2TraceImplementation::CopySubTextureCHROMIUM( - GLenum target, GLenum source_id, GLenum dest_id, GLint xoffset, @@ -1968,9 +1966,9 @@ GLboolean unpack_premultiply_alpha, GLboolean unpack_unmultiply_alpha) { TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::CopySubTextureCHROMIUM"); - gl_->CopySubTextureCHROMIUM( - target, source_id, dest_id, xoffset, yoffset, x, y, width, height, - unpack_flip_y, unpack_premultiply_alpha, unpack_unmultiply_alpha); + gl_->CopySubTextureCHROMIUM(source_id, dest_id, xoffset, yoffset, x, y, width, + height, unpack_flip_y, unpack_premultiply_alpha, + unpack_unmultiply_alpha); } void GLES2TraceImplementation::CompressedCopyTextureCHROMIUM(GLenum target, @@ -1981,22 +1979,6 @@ gl_->CompressedCopyTextureCHROMIUM(target, source_id, dest_id); } -void GLES2TraceImplementation::CompressedCopySubTextureCHROMIUM( - GLenum target, - GLenum source_id, - GLenum dest_id, - GLint xoffset, - GLint yoffset, - GLint x, - GLint y, - GLsizei width, - GLsizei height) { - TRACE_EVENT_BINARY_EFFICIENT0("gpu", - "GLES2Trace::CompressedCopySubTextureCHROMIUM"); - gl_->CompressedCopySubTextureCHROMIUM(target, source_id, dest_id, xoffset, - yoffset, x, y, width, height); -} - void GLES2TraceImplementation::DrawArraysInstancedANGLE(GLenum mode, GLint first, GLsizei count,
diff --git a/gpu/command_buffer/cmd_buffer_functions.txt b/gpu/command_buffer/cmd_buffer_functions.txt index dce7a56..2ca188c 100644 --- a/gpu/command_buffer/cmd_buffer_functions.txt +++ b/gpu/command_buffer/cmd_buffer_functions.txt
@@ -278,10 +278,9 @@ GL_APICALL void GL_APIENTRY glGetTranslatedShaderSourceANGLE (GLidShader shader, GLsizeiNotNegative bufsize, GLsizeiOptional* length, char* source); GL_APICALL void GL_APIENTRY glPostSubBufferCHROMIUM (GLint x, GLint y, GLint width, GLint height); GL_APICALL void GL_APIENTRY glTexImageIOSurface2DCHROMIUM (GLenumTextureBindTarget target, GLsizei width, GLsizei height, GLuint ioSurfaceId, GLuint plane); -GL_APICALL void GL_APIENTRY glCopyTextureCHROMIUM (GLenum target, GLenum source_id, GLenum dest_id, GLintTextureInternalFormat internalformat, GLenumPixelType dest_type, GLboolean unpack_flip_y, GLboolean unpack_premultiply_alpha, GLboolean unpack_unmultiply_alpha); -GL_APICALL void GL_APIENTRY glCopySubTextureCHROMIUM (GLenum target, GLenum source_id, GLenum dest_id, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, GLboolean unpack_flip_y, GLboolean unpack_premultiply_alpha, GLboolean unpack_unmultiply_alpha); +GL_APICALL void GL_APIENTRY glCopyTextureCHROMIUM (GLenum source_id, GLenum dest_id, GLintTextureInternalFormat internalformat, GLenumPixelType dest_type, GLboolean unpack_flip_y, GLboolean unpack_premultiply_alpha, GLboolean unpack_unmultiply_alpha); +GL_APICALL void GL_APIENTRY glCopySubTextureCHROMIUM (GLenum source_id, GLenum dest_id, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, GLboolean unpack_flip_y, GLboolean unpack_premultiply_alpha, GLboolean unpack_unmultiply_alpha); GL_APICALL void GL_APIENTRY glCompressedCopyTextureCHROMIUM (GLenum target, GLenum source_id, GLenum dest_id); -GL_APICALL void GL_APIENTRY glCompressedCopySubTextureCHROMIUM (GLenum target, GLenum source_id, GLenum dest_id, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); GL_APICALL void GL_APIENTRY glDrawArraysInstancedANGLE (GLenumDrawMode mode, GLint first, GLsizei count, GLsizei primcount); GL_APICALL void GL_APIENTRY glDrawElementsInstancedANGLE (GLenumDrawMode mode, GLsizei count, GLenumIndexType type, const void* indices, GLsizei primcount); GL_APICALL void GL_APIENTRY glVertexAttribDivisorANGLE (GLuint index, GLuint divisor);
diff --git a/gpu/command_buffer/common/capabilities.cc b/gpu/command_buffer/common/capabilities.cc index d1b2def..e5a975a 100644 --- a/gpu/command_buffer/common/capabilities.cc +++ b/gpu/command_buffer/common/capabilities.cc
@@ -80,6 +80,7 @@ occlusion_query_boolean(false), timer_queries(false), surfaceless(false), + flips_vertically(false), major_version(2), minor_version(0) {}
diff --git a/gpu/command_buffer/common/capabilities.h b/gpu/command_buffer/common/capabilities.h index 339d6ae..be49645d 100644 --- a/gpu/command_buffer/common/capabilities.h +++ b/gpu/command_buffer/common/capabilities.h
@@ -139,6 +139,7 @@ bool occlusion_query_boolean; bool timer_queries; bool surfaceless; + bool flips_vertically; int major_version; int minor_version;
diff --git a/gpu/command_buffer/common/gles2_cmd_format_autogen.h b/gpu/command_buffer/common/gles2_cmd_format_autogen.h index d6c853d5d..23a50113 100644 --- a/gpu/command_buffer/common/gles2_cmd_format_autogen.h +++ b/gpu/command_buffer/common/gles2_cmd_format_autogen.h
@@ -12332,8 +12332,7 @@ void SetHeader() { header.SetCmd<ValueType>(); } - void Init(GLenum _target, - GLenum _source_id, + void Init(GLenum _source_id, GLenum _dest_id, GLint _internalformat, GLenum _dest_type, @@ -12341,7 +12340,6 @@ GLboolean _unpack_premultiply_alpha, GLboolean _unpack_unmultiply_alpha) { SetHeader(); - target = _target; source_id = _source_id; dest_id = _dest_id; internalformat = _internalformat; @@ -12352,7 +12350,6 @@ } void* Set(void* cmd, - GLenum _target, GLenum _source_id, GLenum _dest_id, GLint _internalformat, @@ -12361,13 +12358,12 @@ GLboolean _unpack_premultiply_alpha, GLboolean _unpack_unmultiply_alpha) { static_cast<ValueType*>(cmd)->Init( - _target, _source_id, _dest_id, _internalformat, _dest_type, - _unpack_flip_y, _unpack_premultiply_alpha, _unpack_unmultiply_alpha); + _source_id, _dest_id, _internalformat, _dest_type, _unpack_flip_y, + _unpack_premultiply_alpha, _unpack_unmultiply_alpha); return NextCmdAddress<ValueType>(cmd); } gpu::CommandHeader header; - uint32_t target; uint32_t source_id; uint32_t dest_id; int32_t internalformat; @@ -12377,28 +12373,26 @@ uint32_t unpack_unmultiply_alpha; }; -static_assert(sizeof(CopyTextureCHROMIUM) == 36, - "size of CopyTextureCHROMIUM should be 36"); +static_assert(sizeof(CopyTextureCHROMIUM) == 32, + "size of CopyTextureCHROMIUM should be 32"); static_assert(offsetof(CopyTextureCHROMIUM, header) == 0, "offset of CopyTextureCHROMIUM header should be 0"); -static_assert(offsetof(CopyTextureCHROMIUM, target) == 4, - "offset of CopyTextureCHROMIUM target should be 4"); -static_assert(offsetof(CopyTextureCHROMIUM, source_id) == 8, - "offset of CopyTextureCHROMIUM source_id should be 8"); -static_assert(offsetof(CopyTextureCHROMIUM, dest_id) == 12, - "offset of CopyTextureCHROMIUM dest_id should be 12"); -static_assert(offsetof(CopyTextureCHROMIUM, internalformat) == 16, - "offset of CopyTextureCHROMIUM internalformat should be 16"); -static_assert(offsetof(CopyTextureCHROMIUM, dest_type) == 20, - "offset of CopyTextureCHROMIUM dest_type should be 20"); -static_assert(offsetof(CopyTextureCHROMIUM, unpack_flip_y) == 24, - "offset of CopyTextureCHROMIUM unpack_flip_y should be 24"); +static_assert(offsetof(CopyTextureCHROMIUM, source_id) == 4, + "offset of CopyTextureCHROMIUM source_id should be 4"); +static_assert(offsetof(CopyTextureCHROMIUM, dest_id) == 8, + "offset of CopyTextureCHROMIUM dest_id should be 8"); +static_assert(offsetof(CopyTextureCHROMIUM, internalformat) == 12, + "offset of CopyTextureCHROMIUM internalformat should be 12"); +static_assert(offsetof(CopyTextureCHROMIUM, dest_type) == 16, + "offset of CopyTextureCHROMIUM dest_type should be 16"); +static_assert(offsetof(CopyTextureCHROMIUM, unpack_flip_y) == 20, + "offset of CopyTextureCHROMIUM unpack_flip_y should be 20"); static_assert( - offsetof(CopyTextureCHROMIUM, unpack_premultiply_alpha) == 28, - "offset of CopyTextureCHROMIUM unpack_premultiply_alpha should be 28"); + offsetof(CopyTextureCHROMIUM, unpack_premultiply_alpha) == 24, + "offset of CopyTextureCHROMIUM unpack_premultiply_alpha should be 24"); static_assert( - offsetof(CopyTextureCHROMIUM, unpack_unmultiply_alpha) == 32, - "offset of CopyTextureCHROMIUM unpack_unmultiply_alpha should be 32"); + offsetof(CopyTextureCHROMIUM, unpack_unmultiply_alpha) == 28, + "offset of CopyTextureCHROMIUM unpack_unmultiply_alpha should be 28"); struct CopySubTextureCHROMIUM { typedef CopySubTextureCHROMIUM ValueType; @@ -12412,8 +12406,7 @@ void SetHeader() { header.SetCmd<ValueType>(); } - void Init(GLenum _target, - GLenum _source_id, + void Init(GLenum _source_id, GLenum _dest_id, GLint _xoffset, GLint _yoffset, @@ -12425,7 +12418,6 @@ GLboolean _unpack_premultiply_alpha, GLboolean _unpack_unmultiply_alpha) { SetHeader(); - target = _target; source_id = _source_id; dest_id = _dest_id; xoffset = _xoffset; @@ -12440,7 +12432,6 @@ } void* Set(void* cmd, - GLenum _target, GLenum _source_id, GLenum _dest_id, GLint _xoffset, @@ -12452,15 +12443,13 @@ GLboolean _unpack_flip_y, GLboolean _unpack_premultiply_alpha, GLboolean _unpack_unmultiply_alpha) { - static_cast<ValueType*>(cmd) - ->Init(_target, _source_id, _dest_id, _xoffset, _yoffset, _x, _y, - _width, _height, _unpack_flip_y, _unpack_premultiply_alpha, - _unpack_unmultiply_alpha); + static_cast<ValueType*>(cmd)->Init( + _source_id, _dest_id, _xoffset, _yoffset, _x, _y, _width, _height, + _unpack_flip_y, _unpack_premultiply_alpha, _unpack_unmultiply_alpha); return NextCmdAddress<ValueType>(cmd); } gpu::CommandHeader header; - uint32_t target; uint32_t source_id; uint32_t dest_id; int32_t xoffset; @@ -12474,36 +12463,34 @@ uint32_t unpack_unmultiply_alpha; }; -static_assert(sizeof(CopySubTextureCHROMIUM) == 52, - "size of CopySubTextureCHROMIUM should be 52"); +static_assert(sizeof(CopySubTextureCHROMIUM) == 48, + "size of CopySubTextureCHROMIUM should be 48"); static_assert(offsetof(CopySubTextureCHROMIUM, header) == 0, "offset of CopySubTextureCHROMIUM header should be 0"); -static_assert(offsetof(CopySubTextureCHROMIUM, target) == 4, - "offset of CopySubTextureCHROMIUM target should be 4"); -static_assert(offsetof(CopySubTextureCHROMIUM, source_id) == 8, - "offset of CopySubTextureCHROMIUM source_id should be 8"); -static_assert(offsetof(CopySubTextureCHROMIUM, dest_id) == 12, - "offset of CopySubTextureCHROMIUM dest_id should be 12"); -static_assert(offsetof(CopySubTextureCHROMIUM, xoffset) == 16, - "offset of CopySubTextureCHROMIUM xoffset should be 16"); -static_assert(offsetof(CopySubTextureCHROMIUM, yoffset) == 20, - "offset of CopySubTextureCHROMIUM yoffset should be 20"); -static_assert(offsetof(CopySubTextureCHROMIUM, x) == 24, - "offset of CopySubTextureCHROMIUM x should be 24"); -static_assert(offsetof(CopySubTextureCHROMIUM, y) == 28, - "offset of CopySubTextureCHROMIUM y should be 28"); -static_assert(offsetof(CopySubTextureCHROMIUM, width) == 32, - "offset of CopySubTextureCHROMIUM width should be 32"); -static_assert(offsetof(CopySubTextureCHROMIUM, height) == 36, - "offset of CopySubTextureCHROMIUM height should be 36"); -static_assert(offsetof(CopySubTextureCHROMIUM, unpack_flip_y) == 40, - "offset of CopySubTextureCHROMIUM unpack_flip_y should be 40"); +static_assert(offsetof(CopySubTextureCHROMIUM, source_id) == 4, + "offset of CopySubTextureCHROMIUM source_id should be 4"); +static_assert(offsetof(CopySubTextureCHROMIUM, dest_id) == 8, + "offset of CopySubTextureCHROMIUM dest_id should be 8"); +static_assert(offsetof(CopySubTextureCHROMIUM, xoffset) == 12, + "offset of CopySubTextureCHROMIUM xoffset should be 12"); +static_assert(offsetof(CopySubTextureCHROMIUM, yoffset) == 16, + "offset of CopySubTextureCHROMIUM yoffset should be 16"); +static_assert(offsetof(CopySubTextureCHROMIUM, x) == 20, + "offset of CopySubTextureCHROMIUM x should be 20"); +static_assert(offsetof(CopySubTextureCHROMIUM, y) == 24, + "offset of CopySubTextureCHROMIUM y should be 24"); +static_assert(offsetof(CopySubTextureCHROMIUM, width) == 28, + "offset of CopySubTextureCHROMIUM width should be 28"); +static_assert(offsetof(CopySubTextureCHROMIUM, height) == 32, + "offset of CopySubTextureCHROMIUM height should be 32"); +static_assert(offsetof(CopySubTextureCHROMIUM, unpack_flip_y) == 36, + "offset of CopySubTextureCHROMIUM unpack_flip_y should be 36"); static_assert( - offsetof(CopySubTextureCHROMIUM, unpack_premultiply_alpha) == 44, - "offset of CopySubTextureCHROMIUM unpack_premultiply_alpha should be 44"); + offsetof(CopySubTextureCHROMIUM, unpack_premultiply_alpha) == 40, + "offset of CopySubTextureCHROMIUM unpack_premultiply_alpha should be 40"); static_assert( - offsetof(CopySubTextureCHROMIUM, unpack_unmultiply_alpha) == 48, - "offset of CopySubTextureCHROMIUM unpack_unmultiply_alpha should be 48"); + offsetof(CopySubTextureCHROMIUM, unpack_unmultiply_alpha) == 44, + "offset of CopySubTextureCHROMIUM unpack_unmultiply_alpha should be 44"); struct CompressedCopyTextureCHROMIUM { typedef CompressedCopyTextureCHROMIUM ValueType; @@ -12546,93 +12533,6 @@ static_assert(offsetof(CompressedCopyTextureCHROMIUM, dest_id) == 12, "offset of CompressedCopyTextureCHROMIUM dest_id should be 12"); -struct CompressedCopySubTextureCHROMIUM { - typedef CompressedCopySubTextureCHROMIUM ValueType; - static const CommandId kCmdId = kCompressedCopySubTextureCHROMIUM; - static const cmd::ArgFlags kArgFlags = cmd::kFixed; - static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3); - - static uint32_t ComputeSize() { - return static_cast<uint32_t>(sizeof(ValueType)); // NOLINT - } - - void SetHeader() { header.SetCmd<ValueType>(); } - - void Init(GLenum _target, - GLenum _source_id, - GLenum _dest_id, - GLint _xoffset, - GLint _yoffset, - GLint _x, - GLint _y, - GLsizei _width, - GLsizei _height) { - SetHeader(); - target = _target; - source_id = _source_id; - dest_id = _dest_id; - xoffset = _xoffset; - yoffset = _yoffset; - x = _x; - y = _y; - width = _width; - height = _height; - } - - void* Set(void* cmd, - GLenum _target, - GLenum _source_id, - GLenum _dest_id, - GLint _xoffset, - GLint _yoffset, - GLint _x, - GLint _y, - GLsizei _width, - GLsizei _height) { - static_cast<ValueType*>(cmd)->Init(_target, _source_id, _dest_id, _xoffset, - _yoffset, _x, _y, _width, _height); - return NextCmdAddress<ValueType>(cmd); - } - - gpu::CommandHeader header; - uint32_t target; - uint32_t source_id; - uint32_t dest_id; - int32_t xoffset; - int32_t yoffset; - int32_t x; - int32_t y; - int32_t width; - int32_t height; -}; - -static_assert(sizeof(CompressedCopySubTextureCHROMIUM) == 40, - "size of CompressedCopySubTextureCHROMIUM should be 40"); -static_assert(offsetof(CompressedCopySubTextureCHROMIUM, header) == 0, - "offset of CompressedCopySubTextureCHROMIUM header should be 0"); -static_assert(offsetof(CompressedCopySubTextureCHROMIUM, target) == 4, - "offset of CompressedCopySubTextureCHROMIUM target should be 4"); -static_assert( - offsetof(CompressedCopySubTextureCHROMIUM, source_id) == 8, - "offset of CompressedCopySubTextureCHROMIUM source_id should be 8"); -static_assert( - offsetof(CompressedCopySubTextureCHROMIUM, dest_id) == 12, - "offset of CompressedCopySubTextureCHROMIUM dest_id should be 12"); -static_assert( - offsetof(CompressedCopySubTextureCHROMIUM, xoffset) == 16, - "offset of CompressedCopySubTextureCHROMIUM xoffset should be 16"); -static_assert( - offsetof(CompressedCopySubTextureCHROMIUM, yoffset) == 20, - "offset of CompressedCopySubTextureCHROMIUM yoffset should be 20"); -static_assert(offsetof(CompressedCopySubTextureCHROMIUM, x) == 24, - "offset of CompressedCopySubTextureCHROMIUM x should be 24"); -static_assert(offsetof(CompressedCopySubTextureCHROMIUM, y) == 28, - "offset of CompressedCopySubTextureCHROMIUM y should be 28"); -static_assert(offsetof(CompressedCopySubTextureCHROMIUM, width) == 32, - "offset of CompressedCopySubTextureCHROMIUM width should be 32"); -static_assert(offsetof(CompressedCopySubTextureCHROMIUM, height) == 36, - "offset of CompressedCopySubTextureCHROMIUM height should be 36"); - struct DrawArraysInstancedANGLE { typedef DrawArraysInstancedANGLE ValueType; static const CommandId kCmdId = kDrawArraysInstancedANGLE;
diff --git a/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h b/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h index 8b9c540..727fc7d 100644 --- a/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h +++ b/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h
@@ -4143,20 +4143,19 @@ cmds::CopyTextureCHROMIUM& cmd = *GetBufferAs<cmds::CopyTextureCHROMIUM>(); void* next_cmd = cmd.Set(&cmd, static_cast<GLenum>(11), static_cast<GLenum>(12), - static_cast<GLenum>(13), static_cast<GLint>(14), - static_cast<GLenum>(15), static_cast<GLboolean>(16), - static_cast<GLboolean>(17), static_cast<GLboolean>(18)); + static_cast<GLint>(13), static_cast<GLenum>(14), + static_cast<GLboolean>(15), static_cast<GLboolean>(16), + static_cast<GLboolean>(17)); EXPECT_EQ(static_cast<uint32_t>(cmds::CopyTextureCHROMIUM::kCmdId), cmd.header.command); EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u); - EXPECT_EQ(static_cast<GLenum>(11), cmd.target); - EXPECT_EQ(static_cast<GLenum>(12), cmd.source_id); - EXPECT_EQ(static_cast<GLenum>(13), cmd.dest_id); - EXPECT_EQ(static_cast<GLint>(14), cmd.internalformat); - EXPECT_EQ(static_cast<GLenum>(15), cmd.dest_type); - EXPECT_EQ(static_cast<GLboolean>(16), cmd.unpack_flip_y); - EXPECT_EQ(static_cast<GLboolean>(17), cmd.unpack_premultiply_alpha); - EXPECT_EQ(static_cast<GLboolean>(18), cmd.unpack_unmultiply_alpha); + EXPECT_EQ(static_cast<GLenum>(11), cmd.source_id); + EXPECT_EQ(static_cast<GLenum>(12), cmd.dest_id); + EXPECT_EQ(static_cast<GLint>(13), cmd.internalformat); + EXPECT_EQ(static_cast<GLenum>(14), cmd.dest_type); + EXPECT_EQ(static_cast<GLboolean>(15), cmd.unpack_flip_y); + EXPECT_EQ(static_cast<GLboolean>(16), cmd.unpack_premultiply_alpha); + EXPECT_EQ(static_cast<GLboolean>(17), cmd.unpack_unmultiply_alpha); CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd)); } @@ -4165,25 +4164,24 @@ *GetBufferAs<cmds::CopySubTextureCHROMIUM>(); void* next_cmd = cmd.Set( &cmd, static_cast<GLenum>(11), static_cast<GLenum>(12), - static_cast<GLenum>(13), static_cast<GLint>(14), static_cast<GLint>(15), - static_cast<GLint>(16), static_cast<GLint>(17), static_cast<GLsizei>(18), - static_cast<GLsizei>(19), static_cast<GLboolean>(20), - static_cast<GLboolean>(21), static_cast<GLboolean>(22)); + static_cast<GLint>(13), static_cast<GLint>(14), static_cast<GLint>(15), + static_cast<GLint>(16), static_cast<GLsizei>(17), + static_cast<GLsizei>(18), static_cast<GLboolean>(19), + static_cast<GLboolean>(20), static_cast<GLboolean>(21)); EXPECT_EQ(static_cast<uint32_t>(cmds::CopySubTextureCHROMIUM::kCmdId), cmd.header.command); EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u); - EXPECT_EQ(static_cast<GLenum>(11), cmd.target); - EXPECT_EQ(static_cast<GLenum>(12), cmd.source_id); - EXPECT_EQ(static_cast<GLenum>(13), cmd.dest_id); - EXPECT_EQ(static_cast<GLint>(14), cmd.xoffset); - EXPECT_EQ(static_cast<GLint>(15), cmd.yoffset); - EXPECT_EQ(static_cast<GLint>(16), cmd.x); - EXPECT_EQ(static_cast<GLint>(17), cmd.y); - EXPECT_EQ(static_cast<GLsizei>(18), cmd.width); - EXPECT_EQ(static_cast<GLsizei>(19), cmd.height); - EXPECT_EQ(static_cast<GLboolean>(20), cmd.unpack_flip_y); - EXPECT_EQ(static_cast<GLboolean>(21), cmd.unpack_premultiply_alpha); - EXPECT_EQ(static_cast<GLboolean>(22), cmd.unpack_unmultiply_alpha); + EXPECT_EQ(static_cast<GLenum>(11), cmd.source_id); + EXPECT_EQ(static_cast<GLenum>(12), cmd.dest_id); + EXPECT_EQ(static_cast<GLint>(13), cmd.xoffset); + EXPECT_EQ(static_cast<GLint>(14), cmd.yoffset); + EXPECT_EQ(static_cast<GLint>(15), cmd.x); + EXPECT_EQ(static_cast<GLint>(16), cmd.y); + EXPECT_EQ(static_cast<GLsizei>(17), cmd.width); + EXPECT_EQ(static_cast<GLsizei>(18), cmd.height); + EXPECT_EQ(static_cast<GLboolean>(19), cmd.unpack_flip_y); + EXPECT_EQ(static_cast<GLboolean>(20), cmd.unpack_premultiply_alpha); + EXPECT_EQ(static_cast<GLboolean>(21), cmd.unpack_unmultiply_alpha); CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd)); } @@ -4201,30 +4199,6 @@ CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd)); } -TEST_F(GLES2FormatTest, CompressedCopySubTextureCHROMIUM) { - cmds::CompressedCopySubTextureCHROMIUM& cmd = - *GetBufferAs<cmds::CompressedCopySubTextureCHROMIUM>(); - void* next_cmd = cmd.Set(&cmd, static_cast<GLenum>(11), - static_cast<GLenum>(12), static_cast<GLenum>(13), - static_cast<GLint>(14), static_cast<GLint>(15), - static_cast<GLint>(16), static_cast<GLint>(17), - static_cast<GLsizei>(18), static_cast<GLsizei>(19)); - EXPECT_EQ( - static_cast<uint32_t>(cmds::CompressedCopySubTextureCHROMIUM::kCmdId), - cmd.header.command); - EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u); - EXPECT_EQ(static_cast<GLenum>(11), cmd.target); - EXPECT_EQ(static_cast<GLenum>(12), cmd.source_id); - EXPECT_EQ(static_cast<GLenum>(13), cmd.dest_id); - EXPECT_EQ(static_cast<GLint>(14), cmd.xoffset); - EXPECT_EQ(static_cast<GLint>(15), cmd.yoffset); - EXPECT_EQ(static_cast<GLint>(16), cmd.x); - EXPECT_EQ(static_cast<GLint>(17), cmd.y); - EXPECT_EQ(static_cast<GLsizei>(18), cmd.width); - EXPECT_EQ(static_cast<GLsizei>(19), cmd.height); - CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd)); -} - TEST_F(GLES2FormatTest, DrawArraysInstancedANGLE) { cmds::DrawArraysInstancedANGLE& cmd = *GetBufferAs<cmds::DrawArraysInstancedANGLE>();
diff --git a/gpu/command_buffer/common/gles2_cmd_ids_autogen.h b/gpu/command_buffer/common/gles2_cmd_ids_autogen.h index 1d8cfd6..9091f41 100644 --- a/gpu/command_buffer/common/gles2_cmd_ids_autogen.h +++ b/gpu/command_buffer/common/gles2_cmd_ids_autogen.h
@@ -271,72 +271,71 @@ OP(CopyTextureCHROMIUM) /* 512 */ \ OP(CopySubTextureCHROMIUM) /* 513 */ \ OP(CompressedCopyTextureCHROMIUM) /* 514 */ \ - OP(CompressedCopySubTextureCHROMIUM) /* 515 */ \ - OP(DrawArraysInstancedANGLE) /* 516 */ \ - OP(DrawElementsInstancedANGLE) /* 517 */ \ - OP(VertexAttribDivisorANGLE) /* 518 */ \ - OP(GenMailboxCHROMIUM) /* 519 */ \ - OP(ProduceTextureCHROMIUMImmediate) /* 520 */ \ - OP(ProduceTextureDirectCHROMIUMImmediate) /* 521 */ \ - OP(ConsumeTextureCHROMIUMImmediate) /* 522 */ \ - OP(CreateAndConsumeTextureCHROMIUMImmediate) /* 523 */ \ - OP(BindUniformLocationCHROMIUMBucket) /* 524 */ \ - OP(GenValuebuffersCHROMIUMImmediate) /* 525 */ \ - OP(DeleteValuebuffersCHROMIUMImmediate) /* 526 */ \ - OP(IsValuebufferCHROMIUM) /* 527 */ \ - OP(BindValuebufferCHROMIUM) /* 528 */ \ - OP(SubscribeValueCHROMIUM) /* 529 */ \ - OP(PopulateSubscribedValuesCHROMIUM) /* 530 */ \ - OP(UniformValuebufferCHROMIUM) /* 531 */ \ - OP(BindTexImage2DCHROMIUM) /* 532 */ \ - OP(ReleaseTexImage2DCHROMIUM) /* 533 */ \ - OP(TraceBeginCHROMIUM) /* 534 */ \ - OP(TraceEndCHROMIUM) /* 535 */ \ - OP(DiscardFramebufferEXTImmediate) /* 536 */ \ - OP(LoseContextCHROMIUM) /* 537 */ \ - OP(InsertSyncPointCHROMIUM) /* 538 */ \ - OP(WaitSyncPointCHROMIUM) /* 539 */ \ - OP(InsertFenceSyncCHROMIUM) /* 540 */ \ - OP(GenSyncTokenCHROMIUMImmediate) /* 541 */ \ - OP(GenUnverifiedSyncTokenCHROMIUMImmediate) /* 542 */ \ - OP(VerifySyncTokensCHROMIUMImmediate) /* 543 */ \ - OP(WaitSyncTokenCHROMIUM) /* 544 */ \ - OP(DrawBuffersEXTImmediate) /* 545 */ \ - OP(DiscardBackbufferCHROMIUM) /* 546 */ \ - OP(ScheduleOverlayPlaneCHROMIUM) /* 547 */ \ - OP(ScheduleCALayerCHROMIUM) /* 548 */ \ - OP(CommitOverlayPlanesCHROMIUM) /* 549 */ \ - OP(SwapInterval) /* 550 */ \ - OP(FlushDriverCachesCHROMIUM) /* 551 */ \ - OP(MatrixLoadfCHROMIUMImmediate) /* 552 */ \ - OP(MatrixLoadIdentityCHROMIUM) /* 553 */ \ - OP(GenPathsCHROMIUM) /* 554 */ \ - OP(DeletePathsCHROMIUM) /* 555 */ \ - OP(IsPathCHROMIUM) /* 556 */ \ - OP(PathCommandsCHROMIUM) /* 557 */ \ - OP(PathParameterfCHROMIUM) /* 558 */ \ - OP(PathParameteriCHROMIUM) /* 559 */ \ - OP(PathStencilFuncCHROMIUM) /* 560 */ \ - OP(StencilFillPathCHROMIUM) /* 561 */ \ - OP(StencilStrokePathCHROMIUM) /* 562 */ \ - OP(CoverFillPathCHROMIUM) /* 563 */ \ - OP(CoverStrokePathCHROMIUM) /* 564 */ \ - OP(StencilThenCoverFillPathCHROMIUM) /* 565 */ \ - OP(StencilThenCoverStrokePathCHROMIUM) /* 566 */ \ - OP(StencilFillPathInstancedCHROMIUM) /* 567 */ \ - OP(StencilStrokePathInstancedCHROMIUM) /* 568 */ \ - OP(CoverFillPathInstancedCHROMIUM) /* 569 */ \ - OP(CoverStrokePathInstancedCHROMIUM) /* 570 */ \ - OP(StencilThenCoverFillPathInstancedCHROMIUM) /* 571 */ \ - OP(StencilThenCoverStrokePathInstancedCHROMIUM) /* 572 */ \ - OP(BindFragmentInputLocationCHROMIUMBucket) /* 573 */ \ - OP(ProgramPathFragmentInputGenCHROMIUM) /* 574 */ \ - OP(CoverageModulationCHROMIUM) /* 575 */ \ - OP(BlendBarrierKHR) /* 576 */ \ - OP(ApplyScreenSpaceAntialiasingCHROMIUM) /* 577 */ \ - OP(BindFragDataLocationIndexedEXTBucket) /* 578 */ \ - OP(BindFragDataLocationEXTBucket) /* 579 */ \ - OP(GetFragDataIndexEXT) /* 580 */ + OP(DrawArraysInstancedANGLE) /* 515 */ \ + OP(DrawElementsInstancedANGLE) /* 516 */ \ + OP(VertexAttribDivisorANGLE) /* 517 */ \ + OP(GenMailboxCHROMIUM) /* 518 */ \ + OP(ProduceTextureCHROMIUMImmediate) /* 519 */ \ + OP(ProduceTextureDirectCHROMIUMImmediate) /* 520 */ \ + OP(ConsumeTextureCHROMIUMImmediate) /* 521 */ \ + OP(CreateAndConsumeTextureCHROMIUMImmediate) /* 522 */ \ + OP(BindUniformLocationCHROMIUMBucket) /* 523 */ \ + OP(GenValuebuffersCHROMIUMImmediate) /* 524 */ \ + OP(DeleteValuebuffersCHROMIUMImmediate) /* 525 */ \ + OP(IsValuebufferCHROMIUM) /* 526 */ \ + OP(BindValuebufferCHROMIUM) /* 527 */ \ + OP(SubscribeValueCHROMIUM) /* 528 */ \ + OP(PopulateSubscribedValuesCHROMIUM) /* 529 */ \ + OP(UniformValuebufferCHROMIUM) /* 530 */ \ + OP(BindTexImage2DCHROMIUM) /* 531 */ \ + OP(ReleaseTexImage2DCHROMIUM) /* 532 */ \ + OP(TraceBeginCHROMIUM) /* 533 */ \ + OP(TraceEndCHROMIUM) /* 534 */ \ + OP(DiscardFramebufferEXTImmediate) /* 535 */ \ + OP(LoseContextCHROMIUM) /* 536 */ \ + OP(InsertSyncPointCHROMIUM) /* 537 */ \ + OP(WaitSyncPointCHROMIUM) /* 538 */ \ + OP(InsertFenceSyncCHROMIUM) /* 539 */ \ + OP(GenSyncTokenCHROMIUMImmediate) /* 540 */ \ + OP(GenUnverifiedSyncTokenCHROMIUMImmediate) /* 541 */ \ + OP(VerifySyncTokensCHROMIUMImmediate) /* 542 */ \ + OP(WaitSyncTokenCHROMIUM) /* 543 */ \ + OP(DrawBuffersEXTImmediate) /* 544 */ \ + OP(DiscardBackbufferCHROMIUM) /* 545 */ \ + OP(ScheduleOverlayPlaneCHROMIUM) /* 546 */ \ + OP(ScheduleCALayerCHROMIUM) /* 547 */ \ + OP(CommitOverlayPlanesCHROMIUM) /* 548 */ \ + OP(SwapInterval) /* 549 */ \ + OP(FlushDriverCachesCHROMIUM) /* 550 */ \ + OP(MatrixLoadfCHROMIUMImmediate) /* 551 */ \ + OP(MatrixLoadIdentityCHROMIUM) /* 552 */ \ + OP(GenPathsCHROMIUM) /* 553 */ \ + OP(DeletePathsCHROMIUM) /* 554 */ \ + OP(IsPathCHROMIUM) /* 555 */ \ + OP(PathCommandsCHROMIUM) /* 556 */ \ + OP(PathParameterfCHROMIUM) /* 557 */ \ + OP(PathParameteriCHROMIUM) /* 558 */ \ + OP(PathStencilFuncCHROMIUM) /* 559 */ \ + OP(StencilFillPathCHROMIUM) /* 560 */ \ + OP(StencilStrokePathCHROMIUM) /* 561 */ \ + OP(CoverFillPathCHROMIUM) /* 562 */ \ + OP(CoverStrokePathCHROMIUM) /* 563 */ \ + OP(StencilThenCoverFillPathCHROMIUM) /* 564 */ \ + OP(StencilThenCoverStrokePathCHROMIUM) /* 565 */ \ + OP(StencilFillPathInstancedCHROMIUM) /* 566 */ \ + OP(StencilStrokePathInstancedCHROMIUM) /* 567 */ \ + OP(CoverFillPathInstancedCHROMIUM) /* 568 */ \ + OP(CoverStrokePathInstancedCHROMIUM) /* 569 */ \ + OP(StencilThenCoverFillPathInstancedCHROMIUM) /* 570 */ \ + OP(StencilThenCoverStrokePathInstancedCHROMIUM) /* 571 */ \ + OP(BindFragmentInputLocationCHROMIUMBucket) /* 572 */ \ + OP(ProgramPathFragmentInputGenCHROMIUM) /* 573 */ \ + OP(CoverageModulationCHROMIUM) /* 574 */ \ + OP(BlendBarrierKHR) /* 575 */ \ + OP(ApplyScreenSpaceAntialiasingCHROMIUM) /* 576 */ \ + OP(BindFragDataLocationIndexedEXTBucket) /* 577 */ \ + OP(BindFragDataLocationEXTBucket) /* 578 */ \ + OP(GetFragDataIndexEXT) /* 579 */ enum CommandId { kStartPoint = cmd::kLastCommonId, // All GLES2 commands start after this.
diff --git a/gpu/command_buffer/service/context_state.cc b/gpu/command_buffer/service/context_state.cc index 2149556b..1a3a8c0 100644 --- a/gpu/command_buffer/service/context_state.cc +++ b/gpu/command_buffer/service/context_state.cc
@@ -625,6 +625,14 @@ return params; } +void ContextState::InitStateManual(const ContextState*) const { + // Here we always reset the states whether it's different from previous ones. + // We have very limited states here; also, once we switch to MANGLE, MANGLE + // will opmitize this. + UpdatePackParameters(); + UpdateUnpackParameters(); +} + // Include the auto-generated part of this file. We split this because it means // we can easily edit the non-auto generated parts right here in this file // instead of having to edit some template or the code generator.
diff --git a/gpu/command_buffer/service/context_state.h b/gpu/command_buffer/service/context_state.h index 7a44edc5..5a58916 100644 --- a/gpu/command_buffer/service/context_state.h +++ b/gpu/command_buffer/service/context_state.h
@@ -304,6 +304,8 @@ // parameters user values; otherwise, set them to 0. void UpdateUnpackParameters() const; + void InitStateManual(const ContextState* prev_state) const; + FeatureInfo* feature_info_; scoped_ptr<ErrorState> error_state_; };
diff --git a/gpu/command_buffer/service/context_state_impl_autogen.h b/gpu/command_buffer/service/context_state_impl_autogen.h index aca4764..c7d7eb1d 100644 --- a/gpu/command_buffer/service/context_state_impl_autogen.h +++ b/gpu/command_buffer/service/context_state_impl_autogen.h
@@ -326,46 +326,6 @@ if (prev_state->unpack_alignment != unpack_alignment) { glPixelStorei(GL_UNPACK_ALIGNMENT, unpack_alignment); } - if (feature_info_->IsES3Capable()) { - if (prev_state->pack_row_length != pack_row_length) { - glPixelStorei(GL_PACK_ROW_LENGTH, pack_row_length); - } - } - if (feature_info_->IsES3Capable()) { - if (prev_state->pack_skip_pixels != pack_skip_pixels) { - glPixelStorei(GL_PACK_SKIP_PIXELS, pack_skip_pixels); - } - } - if (feature_info_->IsES3Capable()) { - if (prev_state->pack_skip_rows != pack_skip_rows) { - glPixelStorei(GL_PACK_SKIP_ROWS, pack_skip_rows); - } - } - if (feature_info_->IsES3Capable()) { - if (prev_state->unpack_row_length != unpack_row_length) { - glPixelStorei(GL_UNPACK_ROW_LENGTH, unpack_row_length); - } - } - if (feature_info_->IsES3Capable()) { - if (prev_state->unpack_image_height != unpack_image_height) { - glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, unpack_image_height); - } - } - if (feature_info_->IsES3Capable()) { - if (prev_state->unpack_skip_pixels != unpack_skip_pixels) { - glPixelStorei(GL_UNPACK_SKIP_PIXELS, unpack_skip_pixels); - } - } - if (feature_info_->IsES3Capable()) { - if (prev_state->unpack_skip_rows != unpack_skip_rows) { - glPixelStorei(GL_UNPACK_SKIP_ROWS, unpack_skip_rows); - } - } - if (feature_info_->IsES3Capable()) { - if (prev_state->unpack_skip_images != unpack_skip_images) { - glPixelStorei(GL_UNPACK_SKIP_IMAGES, unpack_skip_images); - } - } if ((polygon_offset_factor != prev_state->polygon_offset_factor) || (polygon_offset_units != prev_state->polygon_offset_units)) glPolygonOffset(polygon_offset_factor, polygon_offset_units); @@ -446,30 +406,6 @@ stencil_path_mask); glPixelStorei(GL_PACK_ALIGNMENT, pack_alignment); glPixelStorei(GL_UNPACK_ALIGNMENT, unpack_alignment); - if (feature_info_->IsES3Capable()) { - glPixelStorei(GL_PACK_ROW_LENGTH, pack_row_length); - } - if (feature_info_->IsES3Capable()) { - glPixelStorei(GL_PACK_SKIP_PIXELS, pack_skip_pixels); - } - if (feature_info_->IsES3Capable()) { - glPixelStorei(GL_PACK_SKIP_ROWS, pack_skip_rows); - } - if (feature_info_->IsES3Capable()) { - glPixelStorei(GL_UNPACK_ROW_LENGTH, unpack_row_length); - } - if (feature_info_->IsES3Capable()) { - glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, unpack_image_height); - } - if (feature_info_->IsES3Capable()) { - glPixelStorei(GL_UNPACK_SKIP_PIXELS, unpack_skip_pixels); - } - if (feature_info_->IsES3Capable()) { - glPixelStorei(GL_UNPACK_SKIP_ROWS, unpack_skip_rows); - } - if (feature_info_->IsES3Capable()) { - glPixelStorei(GL_UNPACK_SKIP_IMAGES, unpack_skip_images); - } glPolygonOffset(polygon_offset_factor, polygon_offset_units); glSampleCoverage(sample_coverage_value, sample_coverage_invert); glScissor(scissor_x, scissor_y, scissor_width, scissor_height); @@ -485,6 +421,7 @@ stencil_back_z_pass_op); glViewport(viewport_x, viewport_y, viewport_width, viewport_height); } + InitStateManual(prev_state); } bool ContextState::GetEnabled(GLenum cap) const { switch (cap) {
diff --git a/gpu/command_buffer/service/feature_info.cc b/gpu/command_buffer/service/feature_info.cc index 86a566d..1b51948 100644 --- a/gpu/command_buffer/service/feature_info.cc +++ b/gpu/command_buffer/service/feature_info.cc
@@ -316,6 +316,14 @@ AddExtensionString("GL_CHROMIUM_trace_marker"); AddExtensionString("GL_EXT_debug_marker"); + // Pre es3, there are no PBOS and all unpack state is handled in client side. + // With es3, unpack state is needed in server side. We always mark these + // enums as valid and pass them to drivers only when a valid PBO is bound. + AddExtensionString("GL_EXT_unpack_subimage"); + validators_.pixel_store.AddValue(GL_UNPACK_ROW_LENGTH); + validators_.pixel_store.AddValue(GL_UNPACK_SKIP_ROWS); + validators_.pixel_store.AddValue(GL_UNPACK_SKIP_PIXELS); + if (feature_flags_.enable_subscribe_uniform) { AddExtensionString("GL_CHROMIUM_subscribe_uniform"); }
diff --git a/gpu/command_buffer/service/feature_info_unittest.cc b/gpu/command_buffer/service/feature_info_unittest.cc index 7e6c0807..9edd93f 100644 --- a/gpu/command_buffer/service/feature_info_unittest.cc +++ b/gpu/command_buffer/service/feature_info_unittest.cc
@@ -206,6 +206,7 @@ EXPECT_THAT(info_->extensions(), HasSubstr("GL_ANGLE_translated_shader_source")); EXPECT_THAT(info_->extensions(), HasSubstr("GL_CHROMIUM_trace_marker")); + EXPECT_THAT(info_->extensions(), HasSubstr("GL_EXT_unpack_subimage")); // Check a couple of random extensions that should not be there. EXPECT_THAT(info_->extensions(), Not(HasSubstr("GL_OES_texture_npot"))); @@ -309,6 +310,9 @@ EXPECT_FALSE(info_->validators()->frame_buffer_parameter.IsValid( GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT)); EXPECT_FALSE(info_->feature_flags().chromium_image_ycbcr_422); + EXPECT_TRUE(info_->validators()->pixel_store.IsValid(GL_UNPACK_ROW_LENGTH)); + EXPECT_TRUE(info_->validators()->pixel_store.IsValid(GL_UNPACK_SKIP_ROWS)); + EXPECT_TRUE(info_->validators()->pixel_store.IsValid(GL_UNPACK_SKIP_PIXELS)); } TEST_P(FeatureInfoTest, InitializeWithANGLE) {
diff --git a/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc b/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc index f5a9001e..d84cbde 100644 --- a/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc +++ b/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc
@@ -19,12 +19,6 @@ 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; -enum VertexShaderId { - VERTEX_SHADER_COPY_TEXTURE, - VERTEX_SHADER_COPY_TEXTURE_FLIP_Y, - NUM_VERTEX_SHADERS, -}; - enum FragmentShaderId { FRAGMENT_SHADER_COPY_TEXTURE_2D, FRAGMENT_SHADER_COPY_TEXTURE_RECTANGLE_ARB, @@ -38,19 +32,6 @@ NUM_FRAGMENT_SHADERS, }; -// Returns the correct vertex shader id to evaluate the copy operation for -// the CHROMIUM_flipy setting. -VertexShaderId GetVertexShaderId(bool flip_y) { - // bit 0: flip y - static VertexShaderId shader_ids[] = { - VERTEX_SHADER_COPY_TEXTURE, - VERTEX_SHADER_COPY_TEXTURE_FLIP_Y, - }; - - unsigned index = flip_y ? 1 : 0; - return shader_ids[index]; -} - // Returns the correct fragment shader id to evaluate the copy operation for // the premultiply alpha pixel store settings and target. FragmentShaderId GetFragmentShaderId(bool premultiply_alpha, @@ -116,7 +97,7 @@ #define TexCoordPrecision\n\ #endif\n"; -std::string GetVertexShaderSource(bool flip_y) { +std::string GetVertexShaderSource() { std::string source; // Preamble for core and compatibility mode. @@ -135,23 +116,19 @@ // Preamble for texture precision. source += std::string(kShaderPrecisionPreamble); - // Preamble to differentiate based on |flip_y|. - if (flip_y) { - source += std::string("#define SIGN -\n"); - } else { - source += std::string("#define SIGN\n"); - } - // Main shader source. source += std::string("\ - uniform vec2 u_vertex_translate;\n\ - uniform vec2 u_half_size;\n\ + uniform vec2 u_vertex_dest_mult;\n\ + uniform vec2 u_vertex_dest_add;\n\ + uniform vec2 u_vertex_source_mult;\n\ + uniform vec2 u_vertex_source_add;\n\ ATTRIBUTE vec4 a_position;\n\ VARYING TexCoordPrecision vec2 v_uv;\n\ void main(void) {\n\ - gl_Position = a_position + vec4(u_vertex_translate, 0.0, 0.0);\n\ - v_uv = a_position.xy * vec2(u_half_size.s, SIGN u_half_size.t) +\n\ - vec2(u_half_size.s, u_half_size.t);\n\ + gl_Position = a_position;\n\ + gl_Position.xy = a_position.xy * u_vertex_dest_mult + \ + u_vertex_dest_add;\n\ + v_uv = a_position.xy * u_vertex_source_mult + u_vertex_source_add;\n\ }\n"); return source; @@ -285,20 +262,21 @@ void DoCopyTexImage2D(const gpu::gles2::GLES2Decoder* decoder, GLenum source_target, GLuint source_id, + GLenum dest_target, GLuint dest_id, GLenum dest_internal_format, GLsizei width, GLsizei height, GLuint framebuffer) { - DCHECK(source_target == GL_TEXTURE_2D || - source_target == GL_TEXTURE_RECTANGLE_ARB); + DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), source_target); + DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), dest_target); if (BindFramebufferTexture2D(source_target, source_id, framebuffer)) { - glBindTexture(GL_TEXTURE_2D, dest_id); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glCopyTexImage2D(GL_TEXTURE_2D, 0 /* level */, dest_internal_format, + glBindTexture(dest_target, dest_id); + glTexParameterf(dest_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(dest_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(dest_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(dest_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glCopyTexImage2D(dest_target, 0 /* level */, dest_internal_format, 0 /* x */, 0 /* y */, width, height, 0 /* border */); } @@ -312,6 +290,7 @@ void DoCopyTexSubImage2D(const gpu::gles2::GLES2Decoder* decoder, GLenum source_target, GLuint source_id, + GLenum dest_target, GLuint dest_id, GLint xoffset, GLint yoffset, @@ -322,13 +301,14 @@ GLuint framebuffer) { DCHECK(source_target == GL_TEXTURE_2D || source_target == GL_TEXTURE_RECTANGLE_ARB); + DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), dest_target); if (BindFramebufferTexture2D(source_target, source_id, framebuffer)) { - glBindTexture(GL_TEXTURE_2D, dest_id); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glCopyTexSubImage2D(GL_TEXTURE_2D, 0 /* level */, xoffset, yoffset, + glBindTexture(dest_target, dest_id); + glTexParameterf(dest_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(dest_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(dest_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(dest_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glCopyTexSubImage2D(dest_target, 0 /* level */, xoffset, yoffset, source_x, source_y, source_width, source_height); } @@ -345,7 +325,7 @@ CopyTextureCHROMIUMResourceManager::CopyTextureCHROMIUMResourceManager() : initialized_(false), - vertex_shaders_(NUM_VERTEX_SHADERS, 0u), + vertex_shader_(0u), fragment_shaders_(NUM_FRAGMENT_SHADERS, 0u), buffer_id_(0u), framebuffer_(0u) {} @@ -389,7 +369,7 @@ glDeleteFramebuffersEXT(1, &framebuffer_); framebuffer_ = 0; - std::for_each(vertex_shaders_.begin(), vertex_shaders_.end(), DeleteShader); + DeleteShader(vertex_shader_); std::for_each( fragment_shaders_.begin(), fragment_shaders_.end(), DeleteShader); @@ -408,6 +388,7 @@ GLenum source_target, GLuint source_id, GLenum source_internal_format, + GLenum dest_target, GLuint dest_id, GLenum dest_internal_format, GLsizei width, @@ -426,11 +407,13 @@ (source_internal_format == GL_RGBA && dest_internal_format == GL_RGB); // GL_TEXTURE_RECTANGLE_ARB on FBO is supported by OpenGL, not GLES2, // so restrict this to GL_TEXTURE_2D. - if (source_target == GL_TEXTURE_2D && !flip_y && !premultiply_alpha_change && + if (source_target == GL_TEXTURE_2D && dest_target == GL_TEXTURE_2D && + !flip_y && !premultiply_alpha_change && source_format_contain_superset_of_dest_format) { DoCopyTexImage2D(decoder, source_target, source_id, + dest_target, dest_id, dest_internal_format, width, @@ -440,8 +423,8 @@ } // Use kIdentityMatrix if no transform passed in. - DoCopyTextureWithTransform(decoder, source_target, source_id, dest_id, width, - height, flip_y, premultiply_alpha, + DoCopyTextureWithTransform(decoder, source_target, source_id, dest_target, + dest_id, width, height, flip_y, premultiply_alpha, unpremultiply_alpha, kIdentityMatrix); } @@ -450,6 +433,7 @@ GLenum source_target, GLuint source_id, GLenum source_internal_format, + GLenum dest_target, GLuint dest_id, GLenum dest_internal_format, GLint xoffset, @@ -476,23 +460,25 @@ (source_internal_format == GL_RGBA && dest_internal_format == GL_RGB); // GL_TEXTURE_RECTANGLE_ARB on FBO is supported by OpenGL, not GLES2, // so restrict this to GL_TEXTURE_2D. - if (source_target == GL_TEXTURE_2D && !flip_y && !premultiply_alpha_change && + if (source_target == GL_TEXTURE_2D && dest_target == GL_TEXTURE_2D && + !flip_y && !premultiply_alpha_change && source_format_contain_superset_of_dest_format) { - DoCopyTexSubImage2D(decoder, source_target, source_id, dest_id, xoffset, - yoffset, x, y, width, height, framebuffer_); + DoCopyTexSubImage2D(decoder, source_target, source_id, dest_target, dest_id, + xoffset, yoffset, x, y, width, height, framebuffer_); return; } - DoCopyTextureInternal(decoder, source_target, source_id, dest_id, xoffset, - yoffset, x, y, width, height, dest_width, dest_height, - source_width, source_height, flip_y, premultiply_alpha, - unpremultiply_alpha, kIdentityMatrix); + DoCopyTextureInternal(decoder, source_target, source_id, dest_target, dest_id, + xoffset, yoffset, x, y, width, height, dest_width, dest_height, + source_width, source_height, flip_y, premultiply_alpha, + unpremultiply_alpha, kIdentityMatrix); } void CopyTextureCHROMIUMResourceManager::DoCopyTextureWithTransform( const gles2::GLES2Decoder* decoder, GLenum source_target, GLuint source_id, + GLenum dest_target, GLuint dest_id, GLsizei width, GLsizei height, @@ -502,16 +488,17 @@ const GLfloat transform_matrix[16]) { GLsizei dest_width = width; GLsizei dest_height = height; - DoCopyTextureInternal(decoder, source_target, source_id, dest_id, 0, 0, 0, 0, - width, height, dest_width, dest_height, width, height, - flip_y, premultiply_alpha, unpremultiply_alpha, - transform_matrix); + DoCopyTextureInternal(decoder, source_target, source_id, dest_target, dest_id, + 0, 0, 0, 0, width, height, dest_width, dest_height, + width, height, flip_y, premultiply_alpha, + unpremultiply_alpha, transform_matrix); } void CopyTextureCHROMIUMResourceManager::DoCopyTextureInternal( const gles2::GLES2Decoder* decoder, GLenum source_target, GLuint source_id, + GLenum dest_target, GLuint dest_id, GLint xoffset, GLint yoffset, @@ -530,33 +517,37 @@ DCHECK(source_target == GL_TEXTURE_2D || source_target == GL_TEXTURE_RECTANGLE_ARB || source_target == GL_TEXTURE_EXTERNAL_OES); + DCHECK(dest_target == GL_TEXTURE_2D || + dest_target == GL_TEXTURE_RECTANGLE_ARB); DCHECK_GE(xoffset, 0); DCHECK_LE(xoffset + width, dest_width); DCHECK_GE(yoffset, 0); DCHECK_LE(yoffset + height, dest_height); + if (dest_width == 0 || dest_height == 0 || source_width == 0 || + source_height == 0) { + return; + } + if (!initialized_) { DLOG(ERROR) << "CopyTextureCHROMIUM: Uninitialized manager."; return; } - VertexShaderId vertex_shader_id = GetVertexShaderId(flip_y); - DCHECK_LT(static_cast<size_t>(vertex_shader_id), vertex_shaders_.size()); FragmentShaderId fragment_shader_id = GetFragmentShaderId( premultiply_alpha, unpremultiply_alpha, source_target); DCHECK_LT(static_cast<size_t>(fragment_shader_id), fragment_shaders_.size()); - ProgramMapKey key(vertex_shader_id, fragment_shader_id); + ProgramMapKey key(fragment_shader_id); ProgramInfo* info = &programs_[key]; // Create program if necessary. if (!info->program) { info->program = glCreateProgram(); - GLuint* vertex_shader = &vertex_shaders_[vertex_shader_id]; - if (!*vertex_shader) { - *vertex_shader = glCreateShader(GL_VERTEX_SHADER); - std::string source = GetVertexShaderSource(flip_y); - CompileShader(*vertex_shader, source.c_str()); + if (!vertex_shader_) { + vertex_shader_ = glCreateShader(GL_VERTEX_SHADER); + std::string source = GetVertexShaderSource(); + CompileShader(vertex_shader_, source.c_str()); } - glAttachShader(info->program, *vertex_shader); + glAttachShader(info->program, vertex_shader_); GLuint* fragment_shader = &fragment_shaders_[fragment_shader_id]; if (!*fragment_shader) { *fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); @@ -573,11 +564,17 @@ if (!linked) DLOG(ERROR) << "CopyTextureCHROMIUM: program link failure."; #endif - info->vertex_translate_handle = glGetUniformLocation(info->program, - "u_vertex_translate"); + info->vertex_dest_mult_handle = + glGetUniformLocation(info->program, "u_vertex_dest_mult"); + info->vertex_dest_add_handle = + glGetUniformLocation(info->program, "u_vertex_dest_add"); + info->vertex_source_mult_handle = + glGetUniformLocation(info->program, "u_vertex_source_mult"); + info->vertex_source_add_handle = + glGetUniformLocation(info->program, "u_vertex_source_add"); + info->tex_coord_transform_handle = glGetUniformLocation(info->program, "u_tex_coord_transform"); - info->half_size_handle = glGetUniformLocation(info->program, "u_half_size"); info->sampler_handle = glGetUniformLocation(info->program, "u_sampler"); } glUseProgram(info->program); @@ -585,27 +582,75 @@ glUniformMatrix4fv(info->tex_coord_transform_handle, 1, GL_FALSE, transform_matrix); - GLint x_translate = xoffset - x; - GLint y_translate = yoffset - y; - if (!x_translate && !y_translate) { - glUniform2f(info->vertex_translate_handle, 0.0f, 0.0f); - } else { - // transform offsets from ([0, dest_width], [0, dest_height]) coord. - // to ([-1, 1], [-1, 1]) coord. - GLfloat x_translate_on_vertex = ((2.f * x_translate) / dest_width); - GLfloat y_translate_on_vertex = ((2.f * y_translate) / dest_height); + // Note: For simplicity, the calculations in this comment block use a single + // dimension. All calculations trivially extend to the x-y plane. + // The target subrange in the destination texture has coordinates + // [xoffset, xoffset + width]. The full destination texture has range + // [0, dest_width]. + // + // We want to find A and B such that: + // A * X + B = Y + // C * Y + D = Z + // + // where X = [-1, 1], Z = [xoffset, xoffset + width] + // and C, D satisfy the relationship C * [-1, 1] + D = [0, dest_width]. + // + // Math shows: + // C = D = dest_width / 2 + // Y = [(xoffset * 2 / dest_width) - 1, + // (xoffset + width) * 2 / dest_width) - 1] + // A = width / dest_width + // B = (xoffset * 2 + width - dest_width) / dest_width + glUniform2f(info->vertex_dest_mult_handle, width * 1.f / dest_width, + height * 1.f / dest_height); + glUniform2f(info->vertex_dest_add_handle, + (xoffset * 2.f + width - dest_width) / dest_width, + (yoffset * 2.f + height - dest_height) / dest_height); - // Pass translation to the shader program. - glUniform2f(info->vertex_translate_handle, x_translate_on_vertex, - y_translate_on_vertex); - } - if (source_target == GL_TEXTURE_RECTANGLE_ARB) - glUniform2f(info->half_size_handle, source_width / 2.0f, - source_height / 2.0f); - else - glUniform2f(info->half_size_handle, 0.5f, 0.5f); + // Note: For simplicity, the calculations in this comment block use a single + // dimension. All calculations trivially extend to the x-y plane. + // The target subrange in the source texture has coordinates [x, x + width]. + // The full source texture has range [0, source_width]. We need to transform + // the subrange into texture space ([0, M]), assuming that [0, source_width] + // gets mapped to [0, M]. If source_target == GL_TEXTURE_RECTANGLE_ARB, M = + // source_width. Otherwise, M = 1. + // + // We want to find A and B such that: + // A * X + B = Y + // C * Y + D = Z + // + // where X = [-1, 1], Z = [x, x + width] + // and C, D satisfy the relationship C * [0, M] + D = [0, source_width]. + // + // Math shows: + // D = 0 + // C = source_width / M + // Y = [x * M / source_width, (x + width) * M / source_width] + // B = (x + w/2) * M / source_width + // A = (w/2) * M / source_width + // + // When flip_y is true, we run the same calcluation, but with Z = [x + width, + // x]. (I'm intentionally keeping the x-plane notation, although the + // calculation only gets applied to the y-plane). + // + // Math shows: + // D = 0 + // C = source_width / M + // Y = [(x + width) * M / source_width, x * M / source_width] + // B = (x + w/2) * M / source_width + // A = (-w/2) * M / source_width + // + // So everything is the same but the sign of A is flipped. + GLfloat m_x = source_target == GL_TEXTURE_RECTANGLE_ARB ? source_width : 1; + GLfloat m_y = source_target == GL_TEXTURE_RECTANGLE_ARB ? source_height : 1; + GLfloat sign_a = flip_y ? -1 : 1; + glUniform2f(info->vertex_source_mult_handle, width / 2.f * m_x / source_width, + height / 2.f * m_y / source_height * sign_a); + glUniform2f(info->vertex_source_add_handle, + (x + width / 2.f) * m_x / source_width, + (y + height / 2.f) * m_y / source_height); - if (BindFramebufferTexture2D(GL_TEXTURE_2D, dest_id, framebuffer_)) { + if (BindFramebufferTexture2D(dest_target, dest_id, framebuffer_)) { #ifndef NDEBUG // glValidateProgram of MACOSX validates FBO unlike other platforms, so // glValidateProgram must be called after FBO binding. crbug.com/463439
diff --git a/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.h b/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.h index bbd215e..59014c38 100644 --- a/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.h +++ b/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.h
@@ -35,6 +35,7 @@ GLenum source_target, GLuint source_id, GLenum source_internal_format, + GLenum dest_target, GLuint dest_id, GLenum dest_internal_format, GLsizei width, @@ -47,6 +48,7 @@ GLenum source_target, GLuint source_id, GLenum source_internal_format, + GLenum dest_target, GLuint dest_id, GLenum dest_internal_format, GLint xoffset, @@ -70,6 +72,7 @@ void DoCopyTextureWithTransform(const gles2::GLES2Decoder* decoder, GLenum source_target, GLuint source_id, + GLenum dest_target, GLuint dest_id, GLsizei width, GLsizei height, @@ -85,21 +88,33 @@ struct ProgramInfo { ProgramInfo() : program(0u), - vertex_translate_handle(0u), + vertex_dest_mult_handle(0u), + vertex_dest_add_handle(0u), + vertex_source_mult_handle(0u), + vertex_source_add_handle(0u), tex_coord_transform_handle(0u), - half_size_handle(0u), sampler_handle(0u) {} GLuint program; - GLuint vertex_translate_handle; + + // Transformations that map from the original quad coordinates [-1, 1] into + // the destination texture's quad coordinates. + GLuint vertex_dest_mult_handle; + GLuint vertex_dest_add_handle; + + // Transformations that map from the original quad coordinates [-1, 1] into + // the source texture's texture coordinates. + GLuint vertex_source_mult_handle; + GLuint vertex_source_add_handle; + GLuint tex_coord_transform_handle; - GLuint half_size_handle; GLuint sampler_handle; }; void DoCopyTextureInternal(const gles2::GLES2Decoder* decoder, GLenum source_target, GLuint source_id, + GLenum dest_target, GLuint dest_id, GLint xoffset, GLint yoffset, @@ -118,9 +133,9 @@ bool initialized_; typedef std::vector<GLuint> ShaderVector; - ShaderVector vertex_shaders_; + GLuint vertex_shader_; ShaderVector fragment_shaders_; - typedef std::pair<int, int> ProgramMapKey; + typedef int ProgramMapKey; typedef base::hash_map<ProgramMapKey, ProgramInfo> ProgramMap; ProgramMap programs_; GLuint buffer_id_;
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc index 4bf77ab..a5f42aff 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -940,8 +940,7 @@ GLuint io_surface_id, GLuint plane); - void DoCopyTextureCHROMIUM(GLenum target, - GLuint source_id, + void DoCopyTextureCHROMIUM(GLuint source_id, GLuint dest_id, GLenum internal_format, GLenum dest_type, @@ -949,8 +948,7 @@ GLboolean unpack_premultiply_alpha, GLboolean unpack_unmultiply_alpha); - void DoCopySubTextureCHROMIUM(GLenum target, - GLuint source_id, + void DoCopySubTextureCHROMIUM(GLuint source_id, GLuint dest_id, GLint xoffset, GLint yoffset, @@ -966,16 +964,6 @@ GLuint source_id, GLuint dest_id); - void DoCompressedCopySubTextureCHROMIUM(GLenum target, - GLuint source_id, - GLuint dest_id, - GLint xoffset, - GLint yoffset, - GLint x, - GLint y, - GLsizei width, - GLsizei height); - // Wrapper for TexStorage2DEXT. void DoTexStorage2DEXT( GLenum target, @@ -1810,11 +1798,13 @@ GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, Texture* texture); - bool ValidateCopyTextureCHROMIUM(const char* function_name, - GLenum target, - TextureRef* source_texture_ref, - TextureRef* dest_texture_ref, - GLenum dest_internal_format); + bool ValidateCopyTextureCHROMIUMTextures(const char* function_name, + TextureRef* source_texture_ref, + TextureRef* dest_texture_ref); + bool ValidateCopyTextureCHROMIUMInternalFormats( + const char* function_name, + TextureRef* source_texture_ref, + GLenum dest_internal_format); bool ValidateCompressedCopyTextureCHROMIUM(const char* function_name, GLenum target, TextureRef* source_texture_ref, @@ -3146,6 +3136,8 @@ caps.commit_overlay_planes = supports_commit_overlay_planes_; caps.image = true; caps.surfaceless = surfaceless_; + bool is_offscreen = !!offscreen_target_frame_buffer_.get(); + caps.flips_vertically = !is_offscreen && surface_->FlipsVertically(); caps.blend_equation_advanced = feature_info_->feature_flags().blend_equation_advanced; @@ -13068,23 +13060,15 @@ #endif } -bool GLES2DecoderImpl::ValidateCopyTextureCHROMIUM( +bool GLES2DecoderImpl::ValidateCopyTextureCHROMIUMTextures( const char* function_name, - GLenum target, TextureRef* source_texture_ref, - TextureRef* dest_texture_ref, - GLenum dest_internal_format) { + TextureRef* dest_texture_ref) { if (!source_texture_ref || !dest_texture_ref) { LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, function_name, "unknown texture id"); return false; } - if (GL_TEXTURE_2D != target) { - LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, function_name, - "invalid texture target"); - return false; - } - Texture* source_texture = source_texture_ref->texture(); Texture* dest_texture = dest_texture_ref->texture(); if (source_texture == dest_texture) { @@ -13093,17 +13077,36 @@ return false; } - if (dest_texture->target() != GL_TEXTURE_2D || - (source_texture->target() != GL_TEXTURE_2D && - source_texture->target() != GL_TEXTURE_RECTANGLE_ARB && - source_texture->target() != GL_TEXTURE_EXTERNAL_OES)) { + switch (dest_texture->target()) { + case GL_TEXTURE_2D: + case GL_TEXTURE_RECTANGLE_ARB: + break; + default: LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, function_name, - "invalid texture target binding"); + "invalid dest texture target binding"); return false; } + switch (source_texture->target()) { + case GL_TEXTURE_2D: + case GL_TEXTURE_RECTANGLE_ARB: + case GL_TEXTURE_EXTERNAL_OES: + break; + default: + LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, function_name, + "invalid source texture target binding"); + return false; + } + return true; +} + +bool GLES2DecoderImpl::ValidateCopyTextureCHROMIUMInternalFormats( + const char* function_name, + TextureRef* source_texture_ref, + GLenum dest_internal_format) { GLenum source_type = 0; GLenum source_internal_format = 0; + Texture* source_texture = source_texture_ref->texture(); source_texture->GetLevelType(source_texture->target(), 0, &source_type, &source_internal_format); @@ -13183,7 +13186,6 @@ } void GLES2DecoderImpl::DoCopyTextureCHROMIUM( - GLenum target, GLuint source_id, GLuint dest_id, GLenum internal_format, @@ -13196,18 +13198,24 @@ TextureRef* source_texture_ref = GetTexture(source_id); TextureRef* dest_texture_ref = GetTexture(dest_id); - if (!source_texture_ref || !dest_texture_ref) { - LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glCopySubTextureCHROMIUM", - "unknown texture ids"); + if (!ValidateCopyTextureCHROMIUMTextures( + "glCopyTextureCHROMIUM", source_texture_ref, dest_texture_ref)) { + return; + } + + if (!ValidateCopyTextureCHROMIUMInternalFormats( + "glCopyTextureCHROMIUM", source_texture_ref, internal_format)) { return; } Texture* source_texture = source_texture_ref->texture(); Texture* dest_texture = dest_texture_ref->texture(); + GLenum source_target = source_texture->target(); + GLenum dest_target = dest_texture->target(); int source_width = 0; int source_height = 0; gl::GLImage* image = - source_texture->GetLevelImage(source_texture->target(), 0); + source_texture->GetLevelImage(source_target, 0); if (image) { gfx::Size size = image->GetSize(); source_width = size.width(); @@ -13219,7 +13227,7 @@ return; } } else { - if (!source_texture->GetLevelSize(source_texture->target(), 0, + if (!source_texture->GetLevelSize(source_target, 0, &source_width, &source_height, nullptr)) { LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glCopyTextureChromium", @@ -13228,7 +13236,7 @@ } // Check that this type of texture is allowed. - if (!texture_manager()->ValidForTarget(source_texture->target(), 0, + if (!texture_manager()->ValidForTarget(source_target, 0, source_width, source_height, 1)) { LOCAL_SET_GL_ERROR( GL_INVALID_VALUE, "glCopyTextureCHROMIUM", "Bad dimensions"); @@ -13238,8 +13246,8 @@ GLenum source_type = 0; GLenum source_internal_format = 0; - source_texture->GetLevelType( - source_texture->target(), 0, &source_type, &source_internal_format); + source_texture->GetLevelType(source_target, 0, &source_type, + &source_internal_format); if (dest_texture->IsImmutable()) { LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glCopyTextureCHROMIUM", @@ -13247,15 +13255,9 @@ return; } - if (!ValidateCopyTextureCHROMIUM("glCopyTextureCHROMIUM", target, - source_texture_ref, dest_texture_ref, - internal_format)) { - return; - } - // Clear the source texture if necessary. if (!texture_manager()->ClearTextureLevel(this, source_texture_ref, - source_texture->target(), 0)) { + source_target, 0)) { LOCAL_SET_GL_ERROR(GL_OUT_OF_MEMORY, "glCopyTextureCHROMIUM", "dimensions too big"); return; @@ -13277,10 +13279,10 @@ int dest_width = 0; int dest_height = 0; bool dest_level_defined = dest_texture->GetLevelSize( - GL_TEXTURE_2D, 0, &dest_width, &dest_height, nullptr); + dest_target, 0, &dest_width, &dest_height, nullptr); if (dest_level_defined) { - dest_texture->GetLevelType(GL_TEXTURE_2D, 0, &dest_type_previous, + dest_texture->GetLevelType(dest_target, 0, &dest_type_previous, &dest_internal_format); } @@ -13291,21 +13293,21 @@ dest_type_previous != dest_type) { // Ensure that the glTexImage2D succeeds. LOCAL_COPY_REAL_GL_ERRORS_TO_WRAPPER("glCopyTextureCHROMIUM"); - glBindTexture(GL_TEXTURE_2D, dest_texture->service_id()); - glTexImage2D(GL_TEXTURE_2D, 0, internal_format, source_width, source_height, + glBindTexture(dest_target, dest_texture->service_id()); + glTexImage2D(dest_target, 0, internal_format, source_width, source_height, 0, internal_format, dest_type, NULL); GLenum error = LOCAL_PEEK_GL_ERROR("glCopyTextureCHROMIUM"); if (error != GL_NO_ERROR) { - RestoreCurrentTextureBindings(&state_, GL_TEXTURE_2D); + RestoreCurrentTextureBindings(&state_, dest_target); return; } texture_manager()->SetLevelInfo( - dest_texture_ref, GL_TEXTURE_2D, 0, internal_format, source_width, + dest_texture_ref, dest_target, 0, internal_format, source_width, source_height, 1, 0, internal_format, dest_type, gfx::Rect(source_width, source_height)); } else { - texture_manager()->SetLevelCleared(dest_texture_ref, GL_TEXTURE_2D, 0, + texture_manager()->SetLevelCleared(dest_texture_ref, dest_target, 0, true); } @@ -13313,30 +13315,30 @@ bool unpack_premultiply_alpha_change = (unpack_premultiply_alpha ^ unpack_unmultiply_alpha) != 0; if (image && !unpack_flip_y && !unpack_premultiply_alpha_change) { - glBindTexture(GL_TEXTURE_2D, dest_texture->service_id()); - if (image->CopyTexImage(GL_TEXTURE_2D)) + glBindTexture(dest_target, dest_texture->service_id()); + if (image->CopyTexImage(dest_target)) return; } - DoCopyTexImageIfNeeded(source_texture, source_texture->target()); + DoCopyTexImageIfNeeded(source_texture, source_target); // GL_TEXTURE_EXTERNAL_OES texture requires apply a transform matrix // before presenting. - if (source_texture->target() == GL_TEXTURE_EXTERNAL_OES) { + if (source_target == GL_TEXTURE_EXTERNAL_OES) { // TODO(hkuang): get the StreamTexture transform matrix in GPU process // instead of using kIdentityMatrix crbug.com/226218. copy_texture_CHROMIUM_->DoCopyTextureWithTransform( - this, source_texture->target(), source_texture->service_id(), - dest_texture->service_id(), source_width, source_height, + this, source_target, source_texture->service_id(), + dest_target, dest_texture->service_id(), source_width, source_height, unpack_flip_y == GL_TRUE, unpack_premultiply_alpha == GL_TRUE, unpack_unmultiply_alpha == GL_TRUE, kIdentityMatrix); } else { copy_texture_CHROMIUM_->DoCopyTexture( - this, source_texture->target(), source_texture->service_id(), - source_internal_format, dest_texture->service_id(), internal_format, - source_width, source_height, + this, source_target, source_texture->service_id(), + source_internal_format, dest_target, dest_texture->service_id(), + internal_format, source_width, source_height, unpack_flip_y == GL_TRUE, unpack_premultiply_alpha == GL_TRUE, unpack_unmultiply_alpha == GL_TRUE); @@ -13344,7 +13346,6 @@ } void GLES2DecoderImpl::DoCopySubTextureCHROMIUM( - GLenum target, GLuint source_id, GLuint dest_id, GLint xoffset, @@ -13361,18 +13362,19 @@ TextureRef* source_texture_ref = GetTexture(source_id); TextureRef* dest_texture_ref = GetTexture(dest_id); - if (!source_texture_ref || !dest_texture_ref) { - LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glCopySubTextureCHROMIUM", - "unknown texture ids"); + if (!ValidateCopyTextureCHROMIUMTextures( + "glCopySubTextureCHROMIUM", source_texture_ref, dest_texture_ref)) { return; } Texture* source_texture = source_texture_ref->texture(); Texture* dest_texture = dest_texture_ref->texture(); + GLenum source_target = source_texture->target(); + GLenum dest_target = dest_texture->target(); int source_width = 0; int source_height = 0; gl::GLImage* image = - source_texture->GetLevelImage(source_texture->target(), 0); + source_texture->GetLevelImage(source_target, 0); if (image) { gfx::Size size = image->GetSize(); source_width = size.width(); @@ -13383,7 +13385,7 @@ return; } } else { - if (!source_texture->GetLevelSize(source_texture->target(), 0, + if (!source_texture->GetLevelSize(source_target, 0, &source_width, &source_height, nullptr)) { LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glCopySubTextureCHROMIUM", "source texture has no level 0"); @@ -13391,7 +13393,7 @@ } // Check that this type of texture is allowed. - if (!texture_manager()->ValidForTarget(source_texture->target(), 0, + if (!texture_manager()->ValidForTarget(source_target, 0, source_width, source_height, 1)) { LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glCopySubTextureCHROMIUM", "source texture bad dimensions"); @@ -13401,9 +13403,9 @@ GLenum source_type = 0; GLenum source_internal_format = 0; - source_texture->GetLevelType(source_texture->target(), 0, &source_type, + source_texture->GetLevelType(source_target, 0, &source_type, &source_internal_format); - if (!source_texture->ValidForTexture(source_texture->target(), 0, x, y, 0, + if (!source_texture->ValidForTexture(source_target, 0, x, y, 0, width, height, 1)) { LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glCopySubTextureCHROMIUM", "source texture bad dimensions."); @@ -13413,28 +13415,28 @@ GLenum dest_type = 0; GLenum dest_internal_format = 0; bool dest_level_defined = dest_texture->GetLevelType( - dest_texture->target(), 0, &dest_type, &dest_internal_format); + dest_target, 0, &dest_type, &dest_internal_format); if (!dest_level_defined) { LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glCopySubTextureCHROMIUM", "destination texture is not defined"); return; } - if (!dest_texture->ValidForTexture(dest_texture->target(), 0, xoffset, + if (!dest_texture->ValidForTexture(dest_target, 0, xoffset, yoffset, 0, width, height, 1)) { LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glCopySubTextureCHROMIUM", "destination texture bad dimensions."); return; } - if (!ValidateCopyTextureCHROMIUM("glCopySubTextureCHROMIUM", target, - source_texture_ref, dest_texture_ref, - dest_internal_format)) { + if (!ValidateCopyTextureCHROMIUMInternalFormats("glCopySubTextureCHROMIUM", + source_texture_ref, + dest_internal_format)) { return; } // Clear the source texture if necessary. if (!texture_manager()->ClearTextureLevel(this, source_texture_ref, - source_texture->target(), 0)) { + source_target, 0)) { LOCAL_SET_GL_ERROR(GL_OUT_OF_MEMORY, "glCopySubTextureCHROMIUM", "source texture dimensions too big"); return; @@ -13454,29 +13456,30 @@ int dest_width = 0; int dest_height = 0; bool ok = dest_texture->GetLevelSize( - GL_TEXTURE_2D, 0, &dest_width, &dest_height, nullptr); + dest_target, 0, &dest_width, &dest_height, nullptr); DCHECK(ok); if (xoffset != 0 || yoffset != 0 || width != dest_width || height != dest_height) { gfx::Rect cleared_rect; if (TextureManager::CombineAdjacentRects( - dest_texture->GetLevelClearedRect(target, 0), + dest_texture->GetLevelClearedRect(dest_target, 0), gfx::Rect(xoffset, yoffset, width, height), &cleared_rect)) { - DCHECK_GE(cleared_rect.size().GetArea(), - dest_texture->GetLevelClearedRect(target, 0).size().GetArea()); - texture_manager()->SetLevelClearedRect(dest_texture_ref, target, 0, + DCHECK_GE( + cleared_rect.size().GetArea(), + dest_texture->GetLevelClearedRect(dest_target, 0).size().GetArea()); + texture_manager()->SetLevelClearedRect(dest_texture_ref, dest_target, 0, cleared_rect); } else { // Otherwise clear part of texture level that is not already cleared. - if (!texture_manager()->ClearTextureLevel(this, dest_texture_ref, target, - 0)) { + if (!texture_manager()->ClearTextureLevel(this, dest_texture_ref, + dest_target, 0)) { LOCAL_SET_GL_ERROR(GL_OUT_OF_MEMORY, "glCopySubTextureCHROMIUM", "destination texture dimensions too big"); return; } } } else { - texture_manager()->SetLevelCleared(dest_texture_ref, GL_TEXTURE_2D, 0, + texture_manager()->SetLevelCleared(dest_texture_ref, dest_target, 0, true); } @@ -13485,20 +13488,20 @@ (unpack_premultiply_alpha ^ unpack_unmultiply_alpha) != 0; if (image && !unpack_flip_y && !unpack_premultiply_alpha_change) { ScopedTextureBinder binder( - &state_, dest_texture->service_id(), GL_TEXTURE_2D); - if (image->CopyTexSubImage(GL_TEXTURE_2D, gfx::Point(xoffset, yoffset), + &state_, dest_texture->service_id(), dest_target); + if (image->CopyTexSubImage(dest_target, gfx::Point(xoffset, yoffset), gfx::Rect(x, y, width, height))) { return; } } - DoCopyTexImageIfNeeded(source_texture, source_texture->target()); + DoCopyTexImageIfNeeded(source_texture, source_target); // TODO(hkuang): get the StreamTexture transform matrix in GPU process. // crbug.com/226218. copy_texture_CHROMIUM_->DoCopySubTexture( - this, source_texture->target(), source_texture->service_id(), - source_internal_format, dest_texture->service_id(), dest_internal_format, + this, source_target, source_texture->service_id(), source_internal_format, + dest_target, dest_texture->service_id(), dest_internal_format, xoffset, yoffset, x, y, width, height, dest_width, dest_height, source_width, source_height, unpack_flip_y == GL_TRUE, @@ -13568,8 +13571,7 @@ } if (!ValidateCompressedCopyTextureCHROMIUM( - "glCompressedCopyTextureCHROMIUM", - target, + "glCompressedCopyTextureCHROMIUM", target, source_texture_ref, dest_texture_ref)) { return; } @@ -13673,235 +13675,17 @@ // instead of using kIdentityMatrix crbug.com/226218. copy_texture_CHROMIUM_->DoCopyTextureWithTransform( this, source_texture->target(), source_texture->service_id(), - dest_texture->service_id(), source_width, source_height, - false, false, false, kIdentityMatrix); + dest_texture->target(), dest_texture->service_id(), source_width, + source_height, false, false, false, kIdentityMatrix); } else { copy_texture_CHROMIUM_->DoCopyTexture( this, source_texture->target(), source_texture->service_id(), - source_internal_format, dest_texture->service_id(), GL_RGBA, - source_width, source_height, false, false, false); + source_internal_format, dest_texture->target(), + dest_texture->service_id(), GL_RGBA, source_width, source_height, false, + false, false); } } -void GLES2DecoderImpl::DoCompressedCopySubTextureCHROMIUM(GLenum target, - GLuint source_id, - GLuint dest_id, - GLint xoffset, - GLint yoffset, - GLint x, - GLint y, - GLsizei width, - GLsizei height) { - TRACE_EVENT0("gpu", "GLES2DecoderImpl::DoCompressedCopySubTextureCHROMIUM"); - - TextureRef* source_texture_ref = GetTexture(source_id); - TextureRef* dest_texture_ref = GetTexture(dest_id); - - if (!source_texture_ref || !dest_texture_ref) { - LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glCompressedCopySubTextureCHROMIUM", - "unknown texture ids"); - return; - } - - Texture* source_texture = source_texture_ref->texture(); - Texture* dest_texture = dest_texture_ref->texture(); - int source_width = 0; - int source_height = 0; - gl::GLImage* image = - source_texture->GetLevelImage(source_texture->target(), 0); - if (image) { - gfx::Size size = image->GetSize(); - source_width = size.width(); - source_height = size.height(); - if (source_width <= 0 || source_height <= 0) { - LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glCompressedCopySubTextureCHROMIUM", - "invalid image size"); - return; - } - } else { - if (!source_texture->GetLevelSize(source_texture->target(), 0, - &source_width, &source_height, nullptr)) { - LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glCompressedCopySubTextureCHROMIUM", - "source texture has no level 0"); - return; - } - - // Check that this type of texture is allowed. - if (!texture_manager()->ValidForTarget(source_texture->target(), 0, - source_width, source_height, 1)) { - LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glCompressedCopySubTextureCHROMIUM", - "source texture bad dimensions"); - return; - } - } - - GLenum source_type = 0; - GLenum source_internal_format = 0; - source_texture->GetLevelType(source_texture->target(), 0, &source_type, - &source_internal_format); - if (!source_texture->ValidForTexture(source_texture->target(), 0, x, y, 0, - width, height, 1)) { - LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glCompressedCopySubTextureCHROMIUM", - "source texture bad dimensions."); - return; - } - - GLenum dest_type = 0; - GLenum dest_internal_format = 0; - bool dest_level_defined = dest_texture->GetLevelType( - dest_texture->target(), 0, &dest_type, &dest_internal_format); - if (!dest_level_defined) { - LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, - "glCompressedCopySubTextureCHROMIUM", - "destination texture is not defined"); - return; - } - if (!dest_texture->ValidForTexture(dest_texture->target(), 0, xoffset, - yoffset, 0, width, height, 1)) { - LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glCompressedCopySubTextureCHROMIUM", - "destination texture bad dimensions."); - return; - } - - if (!ValidateCompressedCopyTextureCHROMIUM( - "glCompressedCopySubTextureCHROMIUM", target, source_texture_ref, - dest_texture_ref)) { - return; - } - - if (!ValidateCompressedTexSubDimensions("glCompressedCopySubTextureCHROMIUM", - source_texture->target(), 0, x, y, 0, - width, height, 1, - source_internal_format, - source_texture) || - !ValidateCompressedTexSubDimensions("glCompressedCopySubTextureCHROMIUM", - dest_texture->target(), 0, - xoffset, yoffset, 0, width, height, 1, - dest_internal_format, - dest_texture)) { - return; - } - - // Defer initializing the CopyTextureCHROMIUMResourceManager until it is - // needed because it takes 10s of milliseconds to initialize. - if (!copy_texture_CHROMIUM_.get()) { - LOCAL_COPY_REAL_GL_ERRORS_TO_WRAPPER("glCompressedCopySubTextureCHROMIUM"); - copy_texture_CHROMIUM_.reset(new CopyTextureCHROMIUMResourceManager()); - copy_texture_CHROMIUM_->Initialize(this); - RestoreCurrentFramebufferBindings(); - if (LOCAL_PEEK_GL_ERROR("glCompressedCopySubTextureCHROMIUM") != - GL_NO_ERROR) { - return; - } - } - - // Clear the source texture if necessary. - if (!texture_manager()->ClearTextureLevel(this, source_texture_ref, - source_texture->target(), 0)) { - LOCAL_SET_GL_ERROR(GL_OUT_OF_MEMORY, "glCompressedCopySubTextureCHROMIUM", - "source texture dimensions too big"); - return; - } - - int dest_width = 0; - int dest_height = 0; - bool ok = dest_texture->GetLevelSize( - GL_TEXTURE_2D, 0, &dest_width, &dest_height, nullptr); - DCHECK(ok); - if (xoffset != 0 || yoffset != 0 || width != dest_width || - height != dest_height) { - gfx::Rect cleared_rect; - if (TextureManager::CombineAdjacentRects( - dest_texture->GetLevelClearedRect(target, 0), - gfx::Rect(xoffset, yoffset, width, height), &cleared_rect)) { - DCHECK_GE(cleared_rect.size().GetArea(), - dest_texture->GetLevelClearedRect(target, 0).size().GetArea()); - texture_manager()->SetLevelClearedRect(dest_texture_ref, target, 0, - cleared_rect); - } else { - // Otherwise clear part of texture level that is not already cleared. - if (!texture_manager()->ClearTextureLevel(this, dest_texture_ref, target, - 0)) { - LOCAL_SET_GL_ERROR(GL_OUT_OF_MEMORY, - "glCompressedCopySubTextureCHROMIUM", - "destination texture dimensions too big"); - return; - } - } - } else { - texture_manager()->SetLevelCleared(dest_texture_ref, GL_TEXTURE_2D, 0, - true); - } - - ScopedTextureBinder binder( - &state_, dest_texture->service_id(), GL_TEXTURE_2D); - - // Try using GLImage::CopyTexSubImage when possible. - if (image && - image->CopyTexSubImage(GL_TEXTURE_2D, gfx::Point(xoffset, yoffset), - gfx::Rect(x, y, width, height))) { - return; - } - - TRACE_EVENT0( - "gpu", - "GLES2DecoderImpl::DoCompressedCopySubTextureCHROMIUM, fallback"); - - DoCopyTexImageIfNeeded(source_texture, source_texture->target()); - - // As a fallback, copy into a non-compressed GL_RGBA texture. - if (dest_internal_format != GL_RGBA) { - // To preserve the contents of the original destination texture we must - // first copy the original destination texture to a temporary storage, then - // copy it back to the original destination texture. - GLuint tmp_service_id; - glGenTextures(1, &tmp_service_id); - DCHECK_NE(0u, tmp_service_id); - - glBindTexture(GL_TEXTURE_2D, tmp_service_id); - - LOCAL_COPY_REAL_GL_ERRORS_TO_WRAPPER("glCompressedCopyTextureCHROMIUM"); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, dest_width, dest_height, 0, GL_RGBA, - GL_UNSIGNED_BYTE, NULL); - GLenum error = LOCAL_PEEK_GL_ERROR("glCompressedCopySubTextureCHROMIUM"); - if (error != GL_NO_ERROR) - return; - - copy_texture_CHROMIUM_->DoCopyTexture( - this, dest_texture->target(), dest_texture->service_id(), - dest_internal_format, tmp_service_id, GL_RGBA, - dest_width, dest_height, false, false, false); - - // Redefine destination texture to use RGBA. - glBindTexture(GL_TEXTURE_2D, dest_texture->service_id()); - LOCAL_COPY_REAL_GL_ERRORS_TO_WRAPPER("glCompressedCopyTextureCHROMIUM"); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, dest_width, dest_height, 0, GL_RGBA, - GL_UNSIGNED_BYTE, NULL); - error = LOCAL_PEEK_GL_ERROR("glCompressedCopySubTextureCHROMIUM"); - if (error != GL_NO_ERROR) - return; - - texture_manager()->SetLevelInfo( - dest_texture_ref, GL_TEXTURE_2D, 0, GL_RGBA, dest_width, dest_height, - 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect(dest_width, dest_height)); - - copy_texture_CHROMIUM_->DoCopyTexture( - this, GL_TEXTURE_2D, tmp_service_id, GL_RGBA, - dest_texture->service_id(), GL_RGBA, - dest_width, dest_height, false, false, false); - - glDeleteTextures(1, &tmp_service_id); - } - - // TODO(hkuang): get the StreamTexture transform matrix in GPU process. - // crbug.com/226218. - copy_texture_CHROMIUM_->DoCopySubTexture( - this, source_texture->target(), source_texture->service_id(), - source_internal_format, dest_texture->service_id(), GL_RGBA, - xoffset, yoffset, x, y, width, height, dest_width, dest_height, - source_width, source_height, false, false, false); -} - void GLES2DecoderImpl::DoTexStorage2DEXT( GLenum target, GLint levels,
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h index badfbcd..b751b2a 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
@@ -4405,7 +4405,6 @@ const gles2::cmds::CopyTextureCHROMIUM& c = *static_cast<const gles2::cmds::CopyTextureCHROMIUM*>(cmd_data); (void)c; - GLenum target = static_cast<GLenum>(c.target); GLenum source_id = static_cast<GLenum>(c.source_id); GLenum dest_id = static_cast<GLenum>(c.dest_id); GLint internalformat = static_cast<GLint>(c.internalformat); @@ -4425,7 +4424,7 @@ "dest_type"); return error::kNoError; } - DoCopyTextureCHROMIUM(target, source_id, dest_id, internalformat, dest_type, + DoCopyTextureCHROMIUM(source_id, dest_id, internalformat, dest_type, unpack_flip_y, unpack_premultiply_alpha, unpack_unmultiply_alpha); return error::kNoError; @@ -4437,7 +4436,6 @@ const gles2::cmds::CopySubTextureCHROMIUM& c = *static_cast<const gles2::cmds::CopySubTextureCHROMIUM*>(cmd_data); (void)c; - GLenum target = static_cast<GLenum>(c.target); GLenum source_id = static_cast<GLenum>(c.source_id); GLenum dest_id = static_cast<GLenum>(c.dest_id); GLint xoffset = static_cast<GLint>(c.xoffset); @@ -4461,9 +4459,9 @@ "height < 0"); return error::kNoError; } - DoCopySubTextureCHROMIUM(target, source_id, dest_id, xoffset, yoffset, x, y, - width, height, unpack_flip_y, - unpack_premultiply_alpha, unpack_unmultiply_alpha); + DoCopySubTextureCHROMIUM(source_id, dest_id, xoffset, yoffset, x, y, width, + height, unpack_flip_y, unpack_premultiply_alpha, + unpack_unmultiply_alpha); return error::kNoError; } @@ -4480,37 +4478,6 @@ return error::kNoError; } -error::Error GLES2DecoderImpl::HandleCompressedCopySubTextureCHROMIUM( - uint32_t immediate_data_size, - const void* cmd_data) { - const gles2::cmds::CompressedCopySubTextureCHROMIUM& c = - *static_cast<const gles2::cmds::CompressedCopySubTextureCHROMIUM*>( - cmd_data); - (void)c; - GLenum target = static_cast<GLenum>(c.target); - GLenum source_id = static_cast<GLenum>(c.source_id); - GLenum dest_id = static_cast<GLenum>(c.dest_id); - GLint xoffset = static_cast<GLint>(c.xoffset); - GLint yoffset = static_cast<GLint>(c.yoffset); - GLint x = static_cast<GLint>(c.x); - GLint y = static_cast<GLint>(c.y); - GLsizei width = static_cast<GLsizei>(c.width); - GLsizei height = static_cast<GLsizei>(c.height); - if (width < 0) { - LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glCompressedCopySubTextureCHROMIUM", - "width < 0"); - return error::kNoError; - } - if (height < 0) { - LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glCompressedCopySubTextureCHROMIUM", - "height < 0"); - return error::kNoError; - } - DoCompressedCopySubTextureCHROMIUM(target, source_id, dest_id, xoffset, - yoffset, x, y, width, height); - return error::kNoError; -} - error::Error GLES2DecoderImpl::HandleProduceTextureCHROMIUMImmediate( uint32_t immediate_data_size, const void* cmd_data) {
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_0_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_0_autogen.h index dfb66bb..0c5de16 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_0_autogen.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_0_autogen.h
@@ -95,46 +95,6 @@ EXPECT_CALL(*gl_, PixelStorei(GL_UNPACK_ALIGNMENT, 4)) .Times(1) .RetiresOnSaturation(); - if (es3_capable) { - EXPECT_CALL(*gl_, PixelStorei(GL_PACK_ROW_LENGTH, 0)) - .Times(1) - .RetiresOnSaturation(); - } - if (es3_capable) { - EXPECT_CALL(*gl_, PixelStorei(GL_PACK_SKIP_PIXELS, 0)) - .Times(1) - .RetiresOnSaturation(); - } - if (es3_capable) { - EXPECT_CALL(*gl_, PixelStorei(GL_PACK_SKIP_ROWS, 0)) - .Times(1) - .RetiresOnSaturation(); - } - if (es3_capable) { - EXPECT_CALL(*gl_, PixelStorei(GL_UNPACK_ROW_LENGTH, 0)) - .Times(1) - .RetiresOnSaturation(); - } - if (es3_capable) { - EXPECT_CALL(*gl_, PixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0)) - .Times(1) - .RetiresOnSaturation(); - } - if (es3_capable) { - EXPECT_CALL(*gl_, PixelStorei(GL_UNPACK_SKIP_PIXELS, 0)) - .Times(1) - .RetiresOnSaturation(); - } - if (es3_capable) { - EXPECT_CALL(*gl_, PixelStorei(GL_UNPACK_SKIP_ROWS, 0)) - .Times(1) - .RetiresOnSaturation(); - } - if (es3_capable) { - EXPECT_CALL(*gl_, PixelStorei(GL_UNPACK_SKIP_IMAGES, 0)) - .Times(1) - .RetiresOnSaturation(); - } EXPECT_CALL(*gl_, PolygonOffset(0.0f, 0.0f)).Times(1).RetiresOnSaturation(); EXPECT_CALL(*gl_, SampleCoverage(1.0f, false)).Times(1).RetiresOnSaturation(); EXPECT_CALL(*gl_, @@ -163,5 +123,6 @@ Viewport(kViewportX, kViewportY, kViewportWidth, kViewportHeight)) .Times(1) .RetiresOnSaturation(); + SetupInitStateManualExpectations(es3_capable); } #endif // GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_0_AUTOGEN_H_
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h index 5cda2e1..e8b9eb6 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h
@@ -394,4 +394,12 @@ kInvalidSharedMemoryOffset); EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd)); } + +TEST_P(GLES2DecoderTest3, SwapIntervalValidArgs) { + SpecializedSetup<cmds::SwapInterval, 0>(true); + cmds::SwapInterval cmd; + cmd.Init(1); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); +} #endif // GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_3_AUTOGEN_H_
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_4_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_4_autogen.h index 166ced9..9abba52 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_4_autogen.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_4_autogen.h
@@ -12,11 +12,4 @@ #ifndef GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_4_AUTOGEN_H_ #define GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_4_AUTOGEN_H_ -TEST_P(GLES2DecoderTest4, SwapIntervalValidArgs) { - SpecializedSetup<cmds::SwapInterval, 0>(true); - cmds::SwapInterval cmd; - cmd.Init(1); - EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); - EXPECT_EQ(GL_NO_ERROR, GetGLError()); -} #endif // GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_4_AUTOGEN_H_
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc index b567357..4c4e9f0 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
@@ -1924,6 +1924,35 @@ &GLES2DecoderTestBase::MockGLStates::OnVertexAttribNullPointer)); } +void GLES2DecoderTestBase::SetupInitStateManualExpectations(bool es3_capable) { + if (es3_capable) { + EXPECT_CALL(*gl_, PixelStorei(GL_PACK_ROW_LENGTH, 0)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, PixelStorei(GL_PACK_SKIP_PIXELS, 0)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, PixelStorei(GL_PACK_SKIP_ROWS, 0)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, PixelStorei(GL_UNPACK_ROW_LENGTH, 0)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, PixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, PixelStorei(GL_UNPACK_SKIP_PIXELS, 0)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, PixelStorei(GL_UNPACK_SKIP_ROWS, 0)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, PixelStorei(GL_UNPACK_SKIP_IMAGES, 0)) + .Times(1) + .RetiresOnSaturation(); + } +} + GLES2DecoderWithShaderTestBase::MockCommandBufferEngine:: MockCommandBufferEngine() {
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h index 764fe6c0..ff8c0ab5 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h
@@ -737,6 +737,8 @@ void AddExpectationsForVertexAttribManager(); void SetupMockGLBehaviors(); + void SetupInitStateManualExpectations(bool es3_capable); + scoped_ptr< ::testing::StrictMock<MockCommandBufferEngine> > engine_; scoped_refptr<ContextGroup> group_; MockGLStates gl_states_;
diff --git a/gpu/command_buffer/tests/gl_compressed_copy_texture_CHROMIUM_unittest.cc b/gpu/command_buffer/tests/gl_compressed_copy_texture_CHROMIUM_unittest.cc index b444bb9..333da3c7 100644 --- a/gpu/command_buffer/tests/gl_compressed_copy_texture_CHROMIUM_unittest.cc +++ b/gpu/command_buffer/tests/gl_compressed_copy_texture_CHROMIUM_unittest.cc
@@ -22,12 +22,6 @@ namespace { -enum CopyType { TexImage, TexSubImage }; -const CopyType kCopyTypes[] = { - TexImage, - TexSubImage, -}; - const uint8_t kCompressedImageColor[4] = {255u, 0u, 0u, 255u}; // Single compressed ATC block of source pixels all set to: @@ -46,14 +40,6 @@ const uint8_t kCompressedImageDXT1[8] = {0x00, 0xf8, 0x00, 0xf8, 0xaa, 0xaa, 0xaa, 0xaa}; -// Four compressed DXT1 blocks solidly colored in red, green, blue and black: -// [R][G] -// [B][b] -const uint8_t kCompressedImageDXT1RGB[32] = { - 0x0, 0xf8, 0x0, 0xf8, 0xaa, 0xaa, 0xaa, 0xaa, 0xe0, 0x7, 0xe0, - 0x7, 0xaa, 0xaa, 0xaa, 0xaa, 0x1f, 0x0, 0x1f, 0x0, 0xaa, 0xaa, - 0xaa, 0xaa, 0x0, 0x0, 0x0, 0x0, 0xaa, 0xaa, 0xaa, 0xaa}; - // Single compressed DXT5 block of source pixels all set to: // kCompressedImageColor. const uint8_t kCompressedImageDXT5[16] = {0xff, 0xff, 0x0, 0x0, 0x0, 0x0, @@ -65,16 +51,6 @@ const uint8_t kCompressedImageETC1[8] = {0x0, 0x0, 0xf8, 0x2, 0xff, 0xff, 0x0, 0x0}; -// Single block of zeroes, used for texture pre-allocation. -const uint8_t kInvalidCompressedImage[8] = {0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0}; - -// Four blocks of zeroes, used for texture pre-allocation. -const uint8_t kInvalidCompressedImageLarge[32] = { - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; - void glEnableDisable(GLint param, GLboolean value) { if (value) glEnable(param); @@ -86,8 +62,7 @@ // A collection of tests that exercise the GL_CHROMIUM_copy_texture extension. class GLCompressedCopyTextureCHROMIUMTest - : public testing::Test, - public ::testing::WithParamInterface<CopyType> { + : public testing::Test { protected: void SetUp() override { gl_.Initialize(GLManager::Options()); @@ -125,20 +100,14 @@ GLuint framebuffer_id_; }; -INSTANTIATE_TEST_CASE_P(CopyType, - GLCompressedCopyTextureCHROMIUMTest, - ::testing::ValuesIn(kCopyTypes)); - // Test to ensure that the basic functionality of the extension works. -TEST_P(GLCompressedCopyTextureCHROMIUMTest, Basic) { +TEST_F(GLCompressedCopyTextureCHROMIUMTest, Basic) { if (!GLTestHelper::HasExtension("GL_EXT_texture_compression_dxt1")) { LOG(INFO) << "GL_EXT_texture_compression_dxt1 not supported. Skipping test..."; return; } - CopyType copy_type = GetParam(); - glBindTexture(GL_TEXTURE_2D, textures_[0]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); @@ -154,17 +123,7 @@ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - if (copy_type == TexImage) { - glCompressedCopyTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1]); - } else { - glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, - 4, 4, 0, - sizeof(kInvalidCompressedImage), - kInvalidCompressedImage); - - glCompressedCopySubTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], - textures_[1], 0, 0, 0, 0, 4, 4); - } + glCompressedCopyTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1]); EXPECT_TRUE(glGetError() == GL_NO_ERROR); // Load shader program. @@ -193,9 +152,7 @@ EXPECT_TRUE(GL_NO_ERROR == glGetError()); } -TEST_P(GLCompressedCopyTextureCHROMIUMTest, InternalFormat) { - CopyType copy_type = GetParam(); - +TEST_F(GLCompressedCopyTextureCHROMIUMTest, InternalFormat) { struct Image { const GLint format; const uint8_t* data; @@ -206,9 +163,8 @@ }; std::vector<scoped_ptr<Image>> supported_formats; - if ((GLTestHelper::HasExtension("GL_AMD_compressed_ATC_texture") || - GLTestHelper::HasExtension("GL_ATI_texture_compression_atitc")) && - copy_type != TexSubImage) { + if (GLTestHelper::HasExtension("GL_AMD_compressed_ATC_texture") || + GLTestHelper::HasExtension("GL_ATI_texture_compression_atitc")) { supported_formats.push_back(make_scoped_ptr(new Image( GL_ATC_RGB_AMD, kCompressedImageATC, @@ -231,8 +187,7 @@ kCompressedImageDXT5, sizeof(kCompressedImageDXT5)))); } - if (GLTestHelper::HasExtension("GL_OES_compressed_ETC1_RGB8_texture") && - copy_type != TexSubImage) { + if (GLTestHelper::HasExtension("GL_OES_compressed_ETC1_RGB8_texture")) { supported_formats.push_back(make_scoped_ptr(new Image( GL_ETC1_RGB8_OES, kCompressedImageETC1, @@ -254,30 +209,18 @@ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - if (copy_type == TexImage) { - glCompressedCopyTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], - textures_[1]); - } else { - glCompressedTexImage2D(GL_TEXTURE_2D, 0, image->format, 4, 4, 0, - sizeof(kInvalidCompressedImage), - kInvalidCompressedImage); - - glCompressedCopySubTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], - textures_[1], 0, 0, 0, 0, 4, 4); - } + glCompressedCopyTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1]); EXPECT_TRUE(GL_NO_ERROR == glGetError()); } } -TEST_P(GLCompressedCopyTextureCHROMIUMTest, InternalFormatNotSupported) { +TEST_F(GLCompressedCopyTextureCHROMIUMTest, InternalFormatNotSupported) { if (!GLTestHelper::HasExtension("GL_EXT_texture_compression_dxt1")) { LOG(INFO) << "GL_EXT_texture_compression_dxt1 not supported. Skipping test..."; return; } - CopyType copy_type = GetParam(); - const uint8_t kUncompressedPixels[1 * 4] = {255u, 0u, 0u, 255u}; glBindTexture(GL_TEXTURE_2D, textures_[0]); @@ -296,27 +239,17 @@ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // Check that the GL_RGBA format reports an error. - if (copy_type == TexImage) { - glCompressedCopyTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1]); - } else { - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, - kUncompressedPixels); - - glCompressedCopySubTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], - textures_[1], 0, 0, 0, 0, 1, 1); - } + glCompressedCopyTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1]); EXPECT_TRUE(GL_INVALID_OPERATION == glGetError()); } -TEST_P(GLCompressedCopyTextureCHROMIUMTest, InvalidTextureIds) { +TEST_F(GLCompressedCopyTextureCHROMIUMTest, InvalidTextureIds) { if (!GLTestHelper::HasExtension("GL_EXT_texture_compression_dxt1")) { LOG(INFO) << "GL_EXT_texture_compression_dxt1 not supported. Skipping test..."; return; } - CopyType copy_type = GetParam(); - glBindTexture(GL_TEXTURE_2D, textures_[0]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); @@ -332,52 +265,29 @@ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - if (copy_type == TexImage) { - glCompressedCopyTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], 99993); - EXPECT_TRUE(glGetError() == GL_INVALID_VALUE); - glCompressedCopyTextureCHROMIUM(GL_TEXTURE_2D, 99994, textures_[1]); - EXPECT_TRUE(glGetError() == GL_INVALID_VALUE); + glCompressedCopyTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], 99993); + EXPECT_TRUE(glGetError() == GL_INVALID_VALUE); - glCompressedCopyTextureCHROMIUM(GL_TEXTURE_2D, 99995, 99996); - EXPECT_TRUE(glGetError() == GL_INVALID_VALUE); + glCompressedCopyTextureCHROMIUM(GL_TEXTURE_2D, 99994, textures_[1]); + EXPECT_TRUE(glGetError() == GL_INVALID_VALUE); - glCompressedCopyTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1]); - EXPECT_TRUE(glGetError() == GL_NO_ERROR); - } else { - glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 4, - 4, 0, sizeof(kInvalidCompressedImage), - kInvalidCompressedImage); + glCompressedCopyTextureCHROMIUM(GL_TEXTURE_2D, 99995, 99996); + EXPECT_TRUE(glGetError() == GL_INVALID_VALUE); - glCompressedCopySubTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], 99993, 0, 0, - 0, 0, 4, 4); - EXPECT_TRUE(glGetError() == GL_INVALID_VALUE); - - glCompressedCopySubTextureCHROMIUM(GL_TEXTURE_2D, 99994, textures_[1], 0, 0, - 0, 0, 4, 4); - EXPECT_TRUE(glGetError() == GL_INVALID_VALUE); - - glCompressedCopySubTextureCHROMIUM(GL_TEXTURE_2D, 99995, 99996, 0, 0, 0, 0, - 4, 4); - EXPECT_TRUE(glGetError() == GL_INVALID_VALUE); - - glCompressedCopySubTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], - textures_[1], 0, 0, 0, 0, 4, 4); - EXPECT_TRUE(glGetError() == GL_NO_ERROR); - } + glCompressedCopyTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1]); + EXPECT_TRUE(glGetError() == GL_NO_ERROR); } // Validate that some basic GL state is not touched upon execution of // the extension. -TEST_P(GLCompressedCopyTextureCHROMIUMTest, BasicStatePreservation) { +TEST_F(GLCompressedCopyTextureCHROMIUMTest, BasicStatePreservation) { if (!GLTestHelper::HasExtension("GL_EXT_texture_compression_dxt1")) { LOG(INFO) << "GL_EXT_texture_compression_dxt1 not supported. Skipping test..."; return; } - CopyType copy_type = GetParam(); - glBindTexture(GL_TEXTURE_2D, textures_[0]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); @@ -394,13 +304,6 @@ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - if (copy_type == TexSubImage) { - glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, - 4, 4, 0, - sizeof(kInvalidCompressedImage), - kInvalidCompressedImage); - } - GLboolean reference_settings[2] = { GL_TRUE, GL_FALSE }; for (int x = 0; x < 2; ++x) { GLboolean setting = reference_settings[x]; @@ -413,14 +316,7 @@ glDepthMask(setting); glActiveTexture(GL_TEXTURE1 + x); - - if (copy_type == TexImage) { - glCompressedCopyTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], - textures_[1]); - } else { - glCompressedCopySubTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], - textures_[1], 0, 0, 0, 0, 4, 4); - } + glCompressedCopyTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1]); EXPECT_TRUE(glGetError() == GL_NO_ERROR); EXPECT_EQ(setting, glIsEnabled(GL_DEPTH_TEST)); @@ -450,15 +346,13 @@ // Verify that invocation of the extension does not modify the bound // texture state. -TEST_P(GLCompressedCopyTextureCHROMIUMTest, TextureStatePreserved) { +TEST_F(GLCompressedCopyTextureCHROMIUMTest, TextureStatePreserved) { if (!GLTestHelper::HasExtension("GL_EXT_texture_compression_dxt1")) { LOG(INFO) << "GL_EXT_texture_compression_dxt1 not supported. Skipping test..."; return; } - CopyType copy_type = GetParam(); - glBindTexture(GL_TEXTURE_2D, textures_[0]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); @@ -475,13 +369,6 @@ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - if (copy_type == TexSubImage) { - glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, - 4, 4, 0, - sizeof(kInvalidCompressedImage), - kInvalidCompressedImage); - } - GLuint texture_ids[2]; glGenTextures(2, texture_ids); @@ -491,12 +378,7 @@ glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, texture_ids[1]); - if (copy_type == TexImage) { - glCompressedCopyTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1]); - } else { - glCompressedCopySubTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], - textures_[1], 0, 0, 0, 0, 4, 4); - } + glCompressedCopyTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1]); EXPECT_TRUE(GL_NO_ERROR == glGetError()); GLint active_texture = 0; @@ -519,253 +401,4 @@ EXPECT_TRUE(GL_NO_ERROR == glGetError()); } -TEST_F(GLCompressedCopyTextureCHROMIUMTest, CopySubTextureDimension) { - if (!GLTestHelper::HasExtension("GL_EXT_texture_compression_dxt1")) { - LOG(INFO) << - "GL_EXT_texture_compression_dxt1 not supported. Skipping test..."; - return; - } - - glBindTexture(GL_TEXTURE_2D, textures_[0]); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, - 8, 8, 0, - sizeof(kCompressedImageDXT1RGB), - kCompressedImageDXT1RGB); - EXPECT_TRUE(glGetError() == GL_NO_ERROR); - - glBindTexture(GL_TEXTURE_2D, textures_[1]); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, - 8, 8, 0, - sizeof(kInvalidCompressedImageLarge), - kInvalidCompressedImageLarge); - - glCompressedCopySubTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], - textures_[1], 4, 4, 0, 0, 4, 4); - EXPECT_TRUE(GL_NO_ERROR == glGetError()); - - // Reset the destination texture as it might have been converted to RGBA. - glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, - 8, 8, 0, - sizeof(kInvalidCompressedImageLarge), - kInvalidCompressedImageLarge); - - // xoffset < 0 - glCompressedCopySubTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1], - -4, 4, 0, 0, 4, 4); - EXPECT_TRUE(glGetError() == GL_INVALID_VALUE); - - // x < 0 - glCompressedCopySubTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1], - 4, 4, -4, 0, 4, 4); - EXPECT_TRUE(glGetError() == GL_INVALID_VALUE); - - // xoffset + width > dest_width - glCompressedCopySubTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1], - 8, 8, 0, 0, 4, 4); - EXPECT_TRUE(glGetError() == GL_INVALID_VALUE); - - // x + width > source_width - glCompressedCopySubTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1], - 0, 0, 8, 8, 4, 4); - EXPECT_TRUE(glGetError() == GL_INVALID_VALUE); - - // xoffset not within block-boundary - glCompressedCopySubTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1], - 3, 0, 0, 0, 4, 4); - EXPECT_TRUE(glGetError() == GL_INVALID_OPERATION); - - // x not within block-boundary - glCompressedCopySubTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1], - 0, 0, 3, 0, 4, 4); - EXPECT_TRUE(glGetError() == GL_INVALID_OPERATION); -} - -TEST_F(GLCompressedCopyTextureCHROMIUMTest, CopySubTextureOffset) { - if (!GLTestHelper::HasExtension("GL_EXT_texture_compression_dxt1")) { - LOG(INFO) << - "GL_EXT_texture_compression_dxt1 not supported. Skipping test..."; - return; - } - - glBindTexture(GL_TEXTURE_2D, textures_[0]); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, - 8, 8, 0, - sizeof(kCompressedImageDXT1RGB), - kCompressedImageDXT1RGB); - EXPECT_TRUE(glGetError() == GL_NO_ERROR); - - glBindTexture(GL_TEXTURE_2D, textures_[1]); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, - 8, 8, 0, - sizeof(kInvalidCompressedImageLarge), - kInvalidCompressedImageLarge); - - // Load shader program. - GLuint program = LoadProgram(); - ASSERT_NE(program, 0u); - GLint position_loc = glGetAttribLocation(program, "a_position"); - GLint texture_loc = glGetUniformLocation(program, "u_texture"); - ASSERT_NE(position_loc, -1); - ASSERT_NE(texture_loc, -1); - glUseProgram(program); - - // Load geometry. - GLuint vbo = GLTestHelper::SetupUnitQuad(position_loc); - ASSERT_NE(vbo, 0u); - - // Load texture. - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, textures_[1]); - glUniform1i(texture_loc, 0); - - const uint8_t kBlack[1 * 4] = {0u, 0u, 0u, 255u}; - const uint8_t kRed[1 * 4] = {255u, 0u, 0u, 255u}; - const uint8_t kGreen[1 * 4] = {0u, 255u, 0u, 255u}; - const uint8_t kBlue[1 * 4] = {0u, 0u, 255u, 255u}; - - // Copy each block one by one in a clockwise fashion. Note that we reset the - // destination texture after each copy operation. That's because on some - // platforms we might fallback into replacing the compressed destination - // texture with an uncompressed one. - - // Move blue block up. - glCompressedCopySubTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], - textures_[1], 0, 0, 0, 4, 4, 4); - EXPECT_TRUE(glGetError() == GL_NO_ERROR); - - glDrawArrays(GL_TRIANGLES, 0, 6); - glFlush(); - GLTestHelper::CheckPixels(0, 0, 2, 2, 0, kBlue); - - glBindTexture(GL_TEXTURE_2D, textures_[1]); - glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, - 8, 8, 0, - sizeof(kInvalidCompressedImageLarge), - kInvalidCompressedImageLarge); - - // Move red block right. - glCompressedCopySubTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], - textures_[1], 4, 0, 0, 0, 4, 4); - EXPECT_TRUE(glGetError() == GL_NO_ERROR); - - glDrawArrays(GL_TRIANGLES, 0, 6); - glFlush(); - GLTestHelper::CheckPixels(2, 0, 2, 2, 0, kRed); - - glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, - 8, 8, 0, - sizeof(kInvalidCompressedImageLarge), - kInvalidCompressedImageLarge); - - // Move green block down. - glCompressedCopySubTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], - textures_[1], 4, 4, 4, 0, 4, 4); - EXPECT_TRUE(glGetError() == GL_NO_ERROR); - - glDrawArrays(GL_TRIANGLES, 0, 6); - glFlush(); - GLTestHelper::CheckPixels(2, 2, 2, 2, 0, kGreen); - - glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, - 8, 8, 0, - sizeof(kInvalidCompressedImageLarge), - kInvalidCompressedImageLarge); - - // Move black block left. - glCompressedCopySubTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], - textures_[1], 0, 4, 4, 4, 4, 4); - EXPECT_TRUE(glGetError() == GL_NO_ERROR); - - glDrawArrays(GL_TRIANGLES, 0, 6); - glFlush(); - GLTestHelper::CheckPixels(0, 2, 2, 2, 0, kBlack); - - EXPECT_TRUE(GL_NO_ERROR == glGetError()); -} - -TEST_F(GLCompressedCopyTextureCHROMIUMTest, CopySubTexturePreservation) { - if (!GLTestHelper::HasExtension("GL_EXT_texture_compression_dxt1")) { - LOG(INFO) << - "GL_EXT_texture_compression_dxt1 not supported. Skipping test..."; - return; - } - - glBindTexture(GL_TEXTURE_2D, textures_[0]); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, - 4, 4, 0, - sizeof(kCompressedImageDXT1), - kCompressedImageDXT1); - EXPECT_TRUE(glGetError() == GL_NO_ERROR); - - glBindTexture(GL_TEXTURE_2D, textures_[1]); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, - 8, 8, 0, - sizeof(kCompressedImageDXT1RGB), - kCompressedImageDXT1RGB); - - // Copy entire first texture into the second, replacing the green block: - // [R][R] - // [B][b] - glCompressedCopySubTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], - textures_[1], 4, 0, 0, 0, 4, 4); - EXPECT_TRUE(glGetError() == GL_NO_ERROR); - - // Load shader program. - GLuint program = LoadProgram(); - ASSERT_NE(program, 0u); - GLint position_loc = glGetAttribLocation(program, "a_position"); - GLint texture_loc = glGetUniformLocation(program, "u_texture"); - ASSERT_NE(position_loc, -1); - ASSERT_NE(texture_loc, -1); - glUseProgram(program); - - // Load geometry. - GLuint vbo = GLTestHelper::SetupUnitQuad(position_loc); - ASSERT_NE(vbo, 0u); - - // Load texture. - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, textures_[1]); - glUniform1i(texture_loc, 0); - - // Draw. - glDrawArrays(GL_TRIANGLES, 0, 6); - glFlush(); - - const uint8_t kBlack[1 * 4] = {0u, 0u, 0u, 255u}; - const uint8_t kRed[1 * 4] = {255u, 0u, 0u, 255u}; - const uint8_t kBlue[1 * 4] = {0u, 0u, 255u, 255u}; - - // Note that while destination texture is 8 x 8 pixels the viewport is only - // 4 x 4. - GLTestHelper::CheckPixels(0, 0, 4, 2, 0, kRed); - GLTestHelper::CheckPixels(0, 2, 2, 2, 0, kBlue); - GLTestHelper::CheckPixels(2, 2, 2, 2, 0, kBlack); - EXPECT_TRUE(GL_NO_ERROR == glGetError()); -} - } // namespace gpu
diff --git a/gpu/command_buffer/tests/gl_copy_texture_CHROMIUM_unittest.cc b/gpu/command_buffer/tests/gl_copy_texture_CHROMIUM_unittest.cc index 7cdfb0cf..c47474a5 100644 --- a/gpu/command_buffer/tests/gl_copy_texture_CHROMIUM_unittest.cc +++ b/gpu/command_buffer/tests/gl_copy_texture_CHROMIUM_unittest.cc
@@ -32,31 +32,47 @@ : public testing::Test, public ::testing::WithParamInterface<CopyType> { protected: - void SetUp() override { - gl_.Initialize(GLManager::Options()); + void CreateAndBindDestinationTextureAndFBO(GLenum target) { glGenTextures(2, textures_); - glBindTexture(GL_TEXTURE_2D, textures_[1]); + glBindTexture(target, textures_[1]); // Some drivers (NVidia/SGX) require texture settings to be a certain way or // they won't report FRAMEBUFFER_COMPLETE. - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glGenFramebuffers(1, &framebuffer_id_); glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_id_); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target, textures_[1], 0); } + void SetUp() override { + gl_.Initialize(GLManager::Options()); + + CreateAndBindDestinationTextureAndFBO(GL_TEXTURE_2D); + } + void TearDown() override { glDeleteTextures(2, textures_); glDeleteFramebuffers(1, &framebuffer_id_); gl_.Destroy(); } + void CreateBackingForTexture(GLenum target, GLsizei width, GLsizei height) { + if (target == GL_TEXTURE_RECTANGLE_ARB) { + GLuint image_id = glCreateGpuMemoryBufferImageCHROMIUM( + width, height, GL_RGBA, GL_READ_WRITE_CHROMIUM); + glBindTexImage2DCHROMIUM(target, image_id); + } else { + glTexImage2D(target, 0, GL_RGBA, width, height, 0, GL_RGBA, + GL_UNSIGNED_BYTE, nullptr); + } + } + GLManager gl_; GLuint textures_[2]; GLuint framebuffer_id_; @@ -76,14 +92,14 @@ pixels); if (copy_type == TexImage) { - glCopyTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1], GL_RGBA, + glCopyTextureCHROMIUM(textures_[0], textures_[1], GL_RGBA, GL_UNSIGNED_BYTE, false, false, false); } else { glBindTexture(GL_TEXTURE_2D, textures_[1]); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); - glCopySubTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1], 0, 0, 0, + glCopySubTextureCHROMIUM(textures_[0], textures_[1], 0, 0, 0, 0, 1, 1, false, false, false); } EXPECT_TRUE(glGetError() == GL_NO_ERROR); @@ -123,11 +139,11 @@ EXPECT_TRUE(glGetError() == GL_NO_ERROR); if (copy_type == TexImage) { - glCopyTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1], GL_RGBA, + glCopyTextureCHROMIUM(textures_[0], textures_[1], GL_RGBA, GL_UNSIGNED_BYTE, false, false, false); EXPECT_TRUE(glGetError() == GL_INVALID_OPERATION); } else { - glCopySubTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1], 0, 0, 0, + glCopySubTextureCHROMIUM(textures_[0], textures_[1], 0, 0, 0, 0, 1, 1, false, false, false); EXPECT_TRUE(glGetError() == GL_NO_ERROR); @@ -150,7 +166,7 @@ CopyType copy_type = GetParam(); GLint src_formats[] = {GL_ALPHA, GL_RGB, GL_RGBA, GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_BGRA_EXT}; - GLint dest_formats[] = {GL_RGB, GL_RGBA}; + GLint dest_formats[] = {GL_RGB, GL_RGBA, GL_BGRA_EXT}; for (size_t src_index = 0; src_index < arraysize(src_formats); src_index++) { for (size_t dest_index = 0; dest_index < arraysize(dest_formats); @@ -161,7 +177,7 @@ EXPECT_TRUE(GL_NO_ERROR == glGetError()); if (copy_type == TexImage) { - glCopyTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1], + glCopyTextureCHROMIUM(textures_[0], textures_[1], dest_formats[dest_index], GL_UNSIGNED_BYTE, false, false, false); } else { @@ -170,7 +186,7 @@ dest_formats[dest_index], GL_UNSIGNED_BYTE, nullptr); EXPECT_TRUE(GL_NO_ERROR == glGetError()); - glCopySubTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1], 0, + glCopySubTextureCHROMIUM(textures_[0], textures_[1], 0, 0, 0, 0, 1, 1, false, false, false); } @@ -193,7 +209,7 @@ for (size_t dest_index = 0; dest_index < arraysize(unsupported_dest_formats); dest_index++) { if (copy_type == TexImage) { - glCopyTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1], + glCopyTextureCHROMIUM(textures_[0], textures_[1], unsupported_dest_formats[dest_index], GL_UNSIGNED_BYTE, false, false, false); } else { @@ -201,7 +217,7 @@ glTexImage2D(GL_TEXTURE_2D, 0, unsupported_dest_formats[dest_index], 1, 1, 0, unsupported_dest_formats[dest_index], GL_UNSIGNED_BYTE, nullptr); - glCopySubTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1], 0, 0, + glCopySubTextureCHROMIUM(textures_[0], textures_[1], 0, 0, 0, 0, 1, 1, false, false, false); } EXPECT_TRUE(GL_INVALID_OPERATION == glGetError()) @@ -242,7 +258,7 @@ // If the dest texture has different properties, glCopyTextureCHROMIUM() // redefines them. - glCopyTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1], GL_RGBA, + glCopyTextureCHROMIUM(textures_[0], textures_[1], GL_RGBA, GL_UNSIGNED_BYTE, false, false, false); EXPECT_TRUE(GL_NO_ERROR == glGetError()); @@ -310,10 +326,10 @@ glActiveTexture(GL_TEXTURE1 + x); if (copy_type == TexImage) { - glCopyTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1], GL_RGBA, + glCopyTextureCHROMIUM(textures_[0], textures_[1], GL_RGBA, GL_UNSIGNED_BYTE, false, false, false); } else { - glCopySubTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1], 0, 0, + glCopySubTextureCHROMIUM(textures_[0], textures_[1], 0, 0, 0, 0, 1, 1, false, false, false); } EXPECT_TRUE(GL_NO_ERROR == glGetError()); @@ -369,10 +385,10 @@ glBindTexture(GL_TEXTURE_2D, texture_ids[1]); if (copy_type == TexImage) { - glCopyTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1], GL_RGBA, + glCopyTextureCHROMIUM(textures_[0], textures_[1], GL_RGBA, GL_UNSIGNED_BYTE, false, false, false); } else { - glCopySubTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1], 0, 0, 0, + glCopySubTextureCHROMIUM(textures_[0], textures_[1], 0, 0, 0, 0, 1, 1, false, false, false); } EXPECT_TRUE(GL_NO_ERROR == glGetError()); @@ -441,10 +457,10 @@ GLTestHelper::CheckPixels(0, 0, 1, 1, 0, expected_color); if (copy_type == TexImage) { - glCopyTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1], GL_RGBA, + glCopyTextureCHROMIUM(textures_[0], textures_[1], GL_RGBA, GL_UNSIGNED_BYTE, false, false, false); } else { - glCopySubTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1], 0, 0, 0, + glCopySubTextureCHROMIUM(textures_[0], textures_[1], 0, 0, 0, 0, 1, 1, false, false, false); } EXPECT_TRUE(GL_NO_ERROR == glGetError()); @@ -554,13 +570,13 @@ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); if (copy_type == TexImage) { - glCopyTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1], GL_RGBA, + glCopyTextureCHROMIUM(textures_[0], textures_[1], GL_RGBA, GL_UNSIGNED_BYTE, false, false, false); } else { glBindTexture(GL_TEXTURE_2D, textures_[1]); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); - glCopySubTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1], 0, 0, 0, + glCopySubTextureCHROMIUM(textures_[0], textures_[1], 0, 0, 0, 0, 1, 1, false, false, false); } @@ -586,13 +602,13 @@ GL_UNSIGNED_BYTE, nullptr); if (copy_type == TexImage) { - glCopyTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1], GL_RGBA, + glCopyTextureCHROMIUM(textures_[0], textures_[1], GL_RGBA, GL_UNSIGNED_BYTE, false, false, false); } else { glBindTexture(GL_TEXTURE_2D, textures_[1]); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kWidth, kHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); - glCopySubTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1], 0, 0, 0, + glCopySubTextureCHROMIUM(textures_[0], textures_[1], 0, 0, 0, 0, kWidth, kHeight, false, false, false); } EXPECT_TRUE(GL_NO_ERROR == glGetError()); @@ -620,27 +636,27 @@ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 3, 3, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); - glCopySubTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1], 1, 1, 0, + glCopySubTextureCHROMIUM(textures_[0], textures_[1], 1, 1, 0, 0, 1, 1, false, false, false); EXPECT_TRUE(GL_NO_ERROR == glGetError()); // xoffset < 0 - glCopySubTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1], -1, 1, 0, + glCopySubTextureCHROMIUM(textures_[0], textures_[1], -1, 1, 0, 0, 1, 1, false, false, false); EXPECT_TRUE(glGetError() == GL_INVALID_VALUE); // x < 0 - glCopySubTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1], 1, 1, -1, + glCopySubTextureCHROMIUM(textures_[0], textures_[1], 1, 1, -1, 0, 1, 1, false, false, false); EXPECT_TRUE(glGetError() == GL_INVALID_VALUE); // xoffset + width > dest_width - glCopySubTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1], 2, 2, 0, + glCopySubTextureCHROMIUM(textures_[0], textures_[1], 2, 2, 0, 0, 2, 2, false, false, false); EXPECT_TRUE(glGetError() == GL_INVALID_VALUE); // x + width > source_width - glCopySubTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1], 0, 0, 1, + glCopySubTextureCHROMIUM(textures_[0], textures_[1], 0, 0, 1, 1, 2, 2, false, false, false); EXPECT_TRUE(glGetError() == GL_INVALID_VALUE); } @@ -654,19 +670,19 @@ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 3, 3, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); - glCopyTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], 99993, GL_RGBA, + glCopyTextureCHROMIUM(textures_[0], 99993, GL_RGBA, GL_UNSIGNED_BYTE, false, false, false); EXPECT_TRUE(GL_INVALID_VALUE == glGetError()); - glCopyTextureCHROMIUM(GL_TEXTURE_2D, 99994, textures_[1], GL_RGBA, + glCopyTextureCHROMIUM(99994, textures_[1], GL_RGBA, GL_UNSIGNED_BYTE, false, false, false); EXPECT_TRUE(GL_INVALID_VALUE == glGetError()); - glCopyTextureCHROMIUM(GL_TEXTURE_2D, 99995, 99996, GL_RGBA, GL_UNSIGNED_BYTE, + glCopyTextureCHROMIUM(99995, 99996, GL_RGBA, GL_UNSIGNED_BYTE, false, false, false); EXPECT_TRUE(GL_INVALID_VALUE == glGetError()); - glCopyTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1], GL_RGBA, + glCopyTextureCHROMIUM(textures_[0], textures_[1], GL_RGBA, GL_UNSIGNED_BYTE, false, false, false); EXPECT_TRUE(GL_NO_ERROR == glGetError()); } @@ -680,19 +696,19 @@ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 3, 3, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); - glCopySubTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], 99993, 1, 1, 0, 0, 1, 1, + glCopySubTextureCHROMIUM(textures_[0], 99993, 1, 1, 0, 0, 1, 1, false, false, false); EXPECT_TRUE(GL_INVALID_VALUE == glGetError()); - glCopySubTextureCHROMIUM(GL_TEXTURE_2D, 99994, textures_[1], 1, 1, 0, 0, 1, 1, + glCopySubTextureCHROMIUM(99994, textures_[1], 1, 1, 0, 0, 1, 1, false, false, false); EXPECT_TRUE(GL_INVALID_VALUE == glGetError()); - glCopySubTextureCHROMIUM(GL_TEXTURE_2D, 99995, 99996, 1, 1, 0, 0, 1, 1, false, + glCopySubTextureCHROMIUM(99995, 99996, 1, 1, 0, 0, 1, 1, false, false, false); EXPECT_TRUE(GL_INVALID_VALUE == glGetError()); - glCopySubTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1], 1, 1, 0, + glCopySubTextureCHROMIUM(textures_[0], textures_[1], 1, 1, 0, 0, 1, 1, false, false, false); EXPECT_TRUE(GL_NO_ERROR == glGetError()); } @@ -710,13 +726,13 @@ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, transparent_pixels); - glCopySubTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1], 1, 1, 0, + glCopySubTextureCHROMIUM(textures_[0], textures_[1], 1, 1, 0, 0, 1, 1, false, false, false); EXPECT_TRUE(glGetError() == GL_NO_ERROR); - glCopySubTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1], 1, 0, 1, + glCopySubTextureCHROMIUM(textures_[0], textures_[1], 1, 0, 1, 0, 1, 1, false, false, false); EXPECT_TRUE(glGetError() == GL_NO_ERROR); - glCopySubTextureCHROMIUM(GL_TEXTURE_2D, textures_[0], textures_[1], 0, 1, 0, + glCopySubTextureCHROMIUM(textures_[0], textures_[1], 0, 1, 0, 1, 1, 1, false, false, false); EXPECT_TRUE(glGetError() == GL_NO_ERROR); @@ -741,4 +757,98 @@ EXPECT_TRUE(GL_NO_ERROR == glGetError()); } +TEST_F(GLCopyTextureCHROMIUMTest, CopyTextureBetweenTexture2DAndRectangleArb) { + if (!GLTestHelper::HasExtension("GL_ARB_texture_rectangle")) { + LOG(INFO) << + "GL_ARB_texture_rectangle not supported. Skipping test..."; + return; + } + + GLenum src_targets[] = {GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_2D}; + GLenum dest_targets[] = {GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_2D}; + GLsizei src_width = 30; + GLsizei src_height = 14; + GLsizei dest_width = 15; + GLsizei dest_height = 13; + GLsizei copy_region_x = 1; + GLsizei copy_region_y = 1; + GLsizei copy_region_width = 5; + GLsizei copy_region_height = 3; + uint8_t red[1 * 4] = {255u, 0u, 0u, 255u}; + uint8_t blue[1 * 4] = {0u, 0u, 255u, 255u}; + uint8_t green[1 * 4] = {0u, 255u, 0, 255u}; + uint8_t white[1 * 4] = {255u, 255u, 255u, 255u}; + uint8_t grey[1 * 4] = {199u, 199u, 199u, 255u}; + + for (size_t src_index = 0; src_index < arraysize(src_targets); src_index++) { + GLenum src_target = src_targets[src_index]; + for (size_t dest_index = 0; dest_index < arraysize(dest_targets); + dest_index++) { + GLenum dest_target = dest_targets[dest_index]; + + // SetUp() sets up textures with the wrong parameters for this test, and + // TearDown() expects to successfully delete textures/framebuffers, so + // this is the right place for the delete/create calls. + glDeleteTextures(2, textures_); + glDeleteFramebuffers(1, &framebuffer_id_); + CreateAndBindDestinationTextureAndFBO(dest_target); + + // Allocate source and destination textures. + glBindTexture(src_target, textures_[0]); + CreateBackingForTexture(src_target, src_width, src_height); + + glBindTexture(dest_target, textures_[1]); + CreateBackingForTexture(dest_target, dest_width, dest_height); + + // The bottom left is red, bottom right is blue, top left is green, top + // right is white. + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, src_target, + textures_[0], 0); + glBindTexture(src_target, textures_[0]); + for (GLint x = 0; x < src_width; ++x) { + for (GLint y = 0; y < src_height; ++y) { + uint8_t* data; + if (x < src_width / 2) { + data = y < src_height / 2 ? red : green; + } else { + data = y < src_height / 2 ? blue : white; + } + glTexSubImage2D(src_target, 0, x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, + data); + } + } + + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, dest_target, + textures_[1], 0); + glBindTexture(dest_target, textures_[1]); + + // Copy the subtexture x=[13,18) y=[6,9) to the destination. + glClearColor(grey[0] / 255.f, grey[1] / 255.f, grey[2] / 255.f, 1.0); + glClear(GL_COLOR_BUFFER_BIT); + glCopySubTextureCHROMIUM(textures_[0], textures_[1], copy_region_x, + copy_region_y, 13, 6, copy_region_width, + copy_region_height, false, false, false); + EXPECT_TRUE(GL_NO_ERROR == glGetError()); + + for (GLint x = 0; x < dest_width; ++x) { + for (GLint y = 0; y < dest_height; ++y) { + if (x < copy_region_x || x >= copy_region_x + copy_region_width || + y < copy_region_y || y >= copy_region_y + copy_region_height) { + GLTestHelper::CheckPixels(x, y, 1, 1, 0, grey); + continue; + } + + uint8_t* expected_color; + if (x < copy_region_x + 2) { + expected_color = y < copy_region_y + 1 ? red : green; + } else { + expected_color = y < copy_region_y + 1 ? blue : white; + } + GLTestHelper::CheckPixels(x, y, 1, 1, 0, expected_color); + } + } + } + } +} + } // namespace gpu
diff --git a/gpu/gles2_conform_support/BUILD.gn b/gpu/gles2_conform_support/BUILD.gn index 87f0362..4d1e26c2 100644 --- a/gpu/gles2_conform_support/BUILD.gn +++ b/gpu/gles2_conform_support/BUILD.gn
@@ -7,6 +7,32 @@ internal_gles2_conform_tests = false } +config("gles2_conform_test_warnings") { + if (is_clang) { + cflags = [ + "-Wno-array-bounds", + "-Wno-implicit-function-declaration", + "-Wno-logical-op-parentheses", + + # Many struct initializers in the GTF_ES code are missing braces. + "-Wno-missing-braces", + "-Wno-parentheses-equality", + "-Wno-pointer-sign", + "-Wno-return-type", + "-Wno-sign-compare", + "-Wno-sizeof-pointer-memaccess", + + # A few variables are unitialized if GLVersion != 2.0. + "-Wno-sometimes-uninitialized", + "-Wno-tautological-compare", + + # GTFVecBase.h contains static no-inline functions in a header :-/ + "-Wno-unused-function", + "-Wno-unused-variable", + ] + } +} + import("//build/config/allocator.gni") import("//testing/test.gni") @@ -57,6 +83,13 @@ rebase_path("$target_gen_dir/gles2_conform_test_embedded_data"), ] } + action("generate_gles2_conform_tests") { + script = "generate_gles2_conform_tests.py" + outputs = [ + "$target_gen_dir/gles2_conform_test_autogen.cc", + ] + args = [ rebase_path("$target_gen_dir") ] + } gles2_conform_gypi = exec_script("//build/gypi_to_gn.py", [ @@ -70,34 +103,38 @@ testonly = true # Include a dummy c++ file to force linking of libstdc++. - sources = [ "dummy.cc" ] + gles2_conform_gypi.gtf_es_sources + sources = [ + "dummy.cc", + ] + sources += gles2_conform_gypi.gtf_es_sources + sources += gles2_conform_gypi.gl2_extension_test_sources + sources += gles2_conform_gypi.gl2_fixed_test_sources + sources += gles2_conform_gypi.gl2_test_sources defines = [ "GTF_API=GTF_GLES20", "HKEMBEDDEDFILESYSTEM", ] + include_dirs = [ + rebase_path("$target_gen_dir/gles2_conform_test_embedded_data"), + "//third_party/gles2_conform/GTF_ES/glsl/GTF/Source", + ] deps = [ ":generate_gles2_conform_embedded_data", "//build/config/sanitizers:deps", "//gpu/command_buffer/client:gles2_c_lib_nocheck", "//gpu/gles2_conform_support/egl", "//gpu/gles2_conform_support/native:windowless", + "//third_party/expat:expat", ] - configs += [ "//build/config/compiler:no_incompatible_pointer_warnings" ] + configs += [ + "//build/config/compiler:no_incompatible_pointer_warnings", + + # Must be done this way for warning flags to be ordered correctly. + ":gles2_conform_test_warnings", + ] if (is_linux) { if (!is_chromeos) { deps += [ "//build/config/linux/gtk2" ] - - if (is_clang) { - cflags = [ - "-Wno-array-bounds", - "-Wno-implicit-function-declaration", - "-Wno-parentheses-equality", - "-Wno-pointer-sign", - "-Wno-return-type", - "-Wno-sizeof-pointer-memaccess", - "-Wno-tautological-compare", - ] - } } } if (is_win) { @@ -122,31 +159,6 @@ "_STDINT", "_STDINT_H", ] - if (is_clang) { - cflags = [ - "-Wno-pointer-sign", - "-Wno-array-bounds", - "-Wno-sizeof-pointer-memaccess", - "-Wno-implicit-function-declaration", - "-Wno-logical-op-parentheses", - "-Wno-tautological-compare", - "-Wno-parentheses-equality", - "-Wno-return-type", - ] - #"xcode_settings": { - #"LD": "clang++", - #"WARNING_CFLAGS": [ - #"-Wno-pointer-sign", - #"-Wno-array-bounds", - #"-Wno-sizeof-pointer-memaccess", - #"-Wno-implicit-function-declaration", - #"-Wno-logical-op-parentheses", - #"-Wno-tautological-compare", - #"-Wno-parentheses-equality", - #"-Wno-return-type", - #], - #}, - } } #'run_as': { @@ -178,6 +190,7 @@ ] deps = [ "//base", + "//base/test:test_support", "//gpu/config", "//testing/gtest", ] @@ -187,7 +200,12 @@ ] if (internal_gles2_conform_tests) { - deps += [ ":gles2_conform_test_windowless" ] + deps += [ + ":generate_gles2_conform_tests", + ":gles2_conform_test_windowless", + ] + sources += [ "$target_gen_dir/gles2_conform_test_autogen.cc" ] + # TODO: Make these tests pull in the correct data dependencies once they # are exported in GN. Maybe from //third_party/gles2_conform/GTF_ES/ }
diff --git a/gpu/gles2_conform_support/egl/egl.cc b/gpu/gles2_conform_support/egl/egl.cc index 3a39728..b439b1eb 100644 --- a/gpu/gles2_conform_support/egl/egl.cc +++ b/gpu/gles2_conform_support/egl/egl.cc
@@ -126,7 +126,7 @@ for (size_t i = 0; i < args.size(); ++i) { argv[i] = args[i].c_str(); } - base::CommandLine::Init(args.size(), argv.get()); + base::CommandLine::Init(static_cast<int>(args.size()), argv.get()); base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); if (!command_line->HasSwitch(switches::kDisableGpuDriverBugWorkarounds)) { gpu::ApplyGpuDriverBugWorkarounds(command_line);
diff --git a/gpu/gles2_conform_support/gles2_conform_test.cc b/gpu/gles2_conform_support/gles2_conform_test.cc index 054d3781..6c80b306 100644 --- a/gpu/gles2_conform_support/gles2_conform_test.cc +++ b/gpu/gles2_conform_support/gles2_conform_test.cc
@@ -9,7 +9,6 @@ #include <string> -#include "base/at_exit.h" #include "base/base_paths.h" #include "base/command_line.h" #include "base/files/file_path.h" @@ -21,10 +20,20 @@ #include "base/path_service.h" #include "base/process/launch.h" #include "base/strings/string_util.h" +#include "base/test/launcher/unit_test_launcher.h" +#include "base/test/test_suite.h" #include "gpu/config/gpu_test_config.h" #include "gpu/config/gpu_test_expectations_parser.h" #include "testing/gtest/include/gtest/gtest.h" +namespace { + +int RunHelper(base::TestSuite* test_suite) { + return test_suite->Run(); +} + +} // namespace + bool RunGLES2ConformTest(const char* path) { // Load test expectations, and return early if a test is marked as FAIL. base::FilePath src_path; @@ -116,14 +125,15 @@ } int main(int argc, char** argv) { - base::AtExitManager exit_manager; base::CommandLine::Init(argc, argv); #if defined(OS_MACOSX) base::mac::ScopedNSAutoreleasePool pool; #endif ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); + base::TestSuite test_suite(argc, argv); + int rt = base::LaunchUnitTestsSerially( + argc, + argv, + base::Bind(&RunHelper, base::Unretained(&test_suite))); + return rt; } - - -
diff --git a/gpu/gles2_conform_support/gles2_conform_test.gyp b/gpu/gles2_conform_support/gles2_conform_test.gyp index 15650cf..9ddbce4 100644 --- a/gpu/gles2_conform_support/gles2_conform_test.gyp +++ b/gpu/gles2_conform_support/gles2_conform_test.gyp
@@ -27,9 +27,10 @@ 'targets': [ { 'target_name': 'gles2_conform_test', - 'type': 'executable', + 'type': '<(gtest_target_type)', 'dependencies': [ '<(DEPTH)/base/base.gyp:base', + '<(DEPTH)/base/base.gyp:test_support_base', '<(DEPTH)/gpu/gpu.gyp:gpu', '<(DEPTH)/testing/gtest.gyp:gtest', ],
diff --git a/gpu/gles2_conform_support/native/BUILD.gn b/gpu/gles2_conform_support/native/BUILD.gn index 0d1c0ee..f64048c 100644 --- a/gpu/gles2_conform_support/native/BUILD.gn +++ b/gpu/gles2_conform_support/native/BUILD.gn
@@ -7,7 +7,6 @@ output_name = "egl_main_native" sources = [ "egl_native.cc", - "egl_native_win.cc", "main.cc", ] defines = [ @@ -27,6 +26,9 @@ "egl_native_x11.cc", ] } + if (is_win) { + sources += [ "egl_native_win.cc" ] + } } # GYP version: gpu/gles2_conform_support/gles2_conform_support.gyp:egl_main_windowless @@ -34,7 +36,6 @@ output_name = "egl_main_windowless" sources = [ "egl_native.cc", - "egl_native_win.cc", "egl_native_windowless.cc", "main.cc", ] @@ -49,10 +50,4 @@ "//gpu/gles2_conform_support/egl", "//ui/gl", ] - if (is_linux) { - sources += [ - "egl_native_aura.cc", - "egl_native_x11.cc", - ] - } }
diff --git a/gpu/ipc/gpu_command_buffer_traits_multi.h b/gpu/ipc/gpu_command_buffer_traits_multi.h index d885177..75ac8d2 100644 --- a/gpu/ipc/gpu_command_buffer_traits_multi.h +++ b/gpu/ipc/gpu_command_buffer_traits_multi.h
@@ -107,6 +107,7 @@ IPC_STRUCT_TRAITS_MEMBER(occlusion_query_boolean) IPC_STRUCT_TRAITS_MEMBER(timer_queries) IPC_STRUCT_TRAITS_MEMBER(surfaceless) + IPC_STRUCT_TRAITS_MEMBER(flips_vertically) IPC_STRUCT_TRAITS_MEMBER(major_version) IPC_STRUCT_TRAITS_MEMBER(minor_version)
diff --git a/ios/chrome/app/strings/ios_strings.grd b/ios/chrome/app/strings/ios_strings.grd index 0d1c6404..56a8e8f 100644 --- a/ios/chrome/app/strings/ios_strings.grd +++ b/ios/chrome/app/strings/ios_strings.grd
@@ -286,6 +286,16 @@ Security error </message> + <message name="IDS_IOS_INTERSTITIAL_HEADING_SPOOFING_ATTEMPT_ERROR" desc="Header error message to tell user that the requested URI might be misleading [Length: 20em]"> + Warning: Something's Not Right Here! + </message> + <message name="IDS_IOS_INTERSTITIAL_SUMMARY_SPOOFING_ATTEMPT_ERROR" desc="Summary error message to tell user that the requested URI might be misleading [Length: unlimited]"> + Chrome is unable to verify that the URL for this site is correct. + </message> + <message name="IDS_IOS_INTERSTITIAL_DETAILS_SPOOFING_ATTEMPT_ERROR" desc="Details error message to tell user that the requested URI might be misleading [Length: unlimited]"> + The site you are trying to access is acting strangely, and Chrome is unable to verify that its URL is correct. For security reasons, you should not proceed, and perhaps try again tomorrow or go somewhere else. + </message> + </messages> </release> </grit>
diff --git a/ios/chrome/browser/BUILD.gn b/ios/chrome/browser/BUILD.gn index 2ffc147a..e8a8c207 100644 --- a/ios/chrome/browser/BUILD.gn +++ b/ios/chrome/browser/BUILD.gn
@@ -345,6 +345,8 @@ "snapshots/snapshot_overlay.mm", "snapshots/snapshots_util.h", "snapshots/snapshots_util.mm", + "ssl/ios_ssl_blocking_page.cc", + "ssl/ios_ssl_blocking_page.h", "suggestions/image_fetcher_impl.h", "suggestions/image_fetcher_impl.mm", "suggestions/suggestions_service_factory.h", @@ -415,14 +417,13 @@ "ui/keyboard/UIKeyCommand+Chrome.mm", "ui/keyboard/hardware_keyboard_watcher.h", "ui/keyboard/hardware_keyboard_watcher.mm", - "ui/legacy_size_class_support_util.h", - "ui/legacy_size_class_support_util.mm", "ui/native_content_controller.h", "ui/native_content_controller.mm", "ui/omnibox/web_omnibox_edit_controller.cc", "ui/omnibox/web_omnibox_edit_controller.h", "ui/orientation_limiting_navigation_controller.h", "ui/orientation_limiting_navigation_controller.mm", + "ui/prerender_final_status.h", "ui/reversed_animation.h", "ui/reversed_animation.mm", "ui/rtl_geometry.h",
diff --git a/ios/chrome/browser/application_context_impl.cc b/ios/chrome/browser/application_context_impl.cc index 1d56841..eee2f06 100644 --- a/ios/chrome/browser/application_context_impl.cc +++ b/ios/chrome/browser/application_context_impl.cc
@@ -133,12 +133,7 @@ metrics_services_manager_.reset(); // Need to clear browser states before the IO thread. - if (chrome_browser_state_manager_) { - // TODO(crbug.com/560854): the ShutDown() method can be folded into the - // destructor once ApplicationContextImpl owns ChromeBrowserStateManager. - chrome_browser_state_manager_->ShutDown(); - chrome_browser_state_manager_.reset(); - } + chrome_browser_state_manager_.reset(); // PromoResourceService must be destroyed after the keyed services and before // the IO thread.
diff --git a/ios/chrome/browser/autocomplete/autocomplete_provider_client_impl.cc b/ios/chrome/browser/autocomplete/autocomplete_provider_client_impl.cc index dd70a6229..b3f933ee 100644 --- a/ios/chrome/browser/autocomplete/autocomplete_provider_client_impl.cc +++ b/ios/chrome/browser/autocomplete/autocomplete_provider_client_impl.cc
@@ -6,7 +6,6 @@ #include "base/prefs/pref_service.h" #include "base/strings/utf_string_conversions.h" -#include "components/bookmarks/common/bookmark_pref_names.h" #include "components/browser_sync/browser/profile_sync_service.h" #include "components/history/core/browser/history_service.h" #include "components/keyed_service/core/service_access_type.h" @@ -132,11 +131,6 @@ return browser_state_->GetPrefs()->GetBoolean(prefs::kSearchSuggestEnabled); } -bool AutocompleteProviderClientImpl::BookmarkBarIsVisible() const { - return browser_state_->GetPrefs()->GetBoolean( - bookmarks::prefs::kShowBookmarkBar); -} - bool AutocompleteProviderClientImpl::TabSyncEnabledAndUnencrypted() const { return sync_driver::IsTabSyncEnabledAndUnencrypted( IOSChromeProfileSyncServiceFactory::GetForBrowserState(browser_state_),
diff --git a/ios/chrome/browser/autocomplete/autocomplete_provider_client_impl.h b/ios/chrome/browser/autocomplete/autocomplete_provider_client_impl.h index df8c60e1f..901494b 100644 --- a/ios/chrome/browser/autocomplete/autocomplete_provider_client_impl.h +++ b/ios/chrome/browser/autocomplete/autocomplete_provider_client_impl.h
@@ -45,7 +45,6 @@ std::vector<base::string16> GetBuiltinsToProvideAsUserTypes() override; bool IsOffTheRecord() const override; bool SearchSuggestEnabled() const override; - bool BookmarkBarIsVisible() const override; bool TabSyncEnabledAndUnencrypted() const override; void Classify( const base::string16& text,
diff --git a/ios/chrome/browser/chrome_switches.cc b/ios/chrome/browser/chrome_switches.cc index ced6978..dc15ee3 100644 --- a/ios/chrome/browser/chrome_switches.cc +++ b/ios/chrome/browser/chrome_switches.cc
@@ -128,9 +128,6 @@ // measurements. const char kDisableBackgroundNetworking[] = "disable-background-networking"; -// Disables the dinosaur easter egg on the offline interstitial. -const char kDisableDinosaurEasterEgg[] = "disable-dinosaur-easter-egg"; - // Enables grouping websites by domain and filtering them by period. const char kHistoryEnableGroupByDomain[] = "enable-grouped-history"; @@ -144,14 +141,4 @@ // This is used for testing only. const char kSbDisableAutoUpdate[] = "safebrowsing-disable-auto-update"; -// Command line flag offering a "Show saved copy" option to the user if offline. -// The various modes are disabled, primary, or secondary. Primary/secondary -// refers to button placement (for experiment). -const char kShowSavedCopy[] = "show-saved-copy"; - -// Values for the kShowSavedCopy flag. -const char kEnableShowSavedCopyPrimary[] = "primary"; -const char kEnableShowSavedCopySecondary[] = "secondary"; -const char kDisableShowSavedCopy[] = "disable"; - } // namespace switches
diff --git a/ios/chrome/browser/chrome_switches.h b/ios/chrome/browser/chrome_switches.h index 7d8ced06..08da4c0 100644 --- a/ios/chrome/browser/chrome_switches.h +++ b/ios/chrome/browser/chrome_switches.h
@@ -50,16 +50,11 @@ // and iOS. Once the corresponding code has been componentized or is no longer // used by iOS, remove the duplicate definition. extern const char kDisableBackgroundNetworking[]; -extern const char kDisableDinosaurEasterEgg[]; extern const char kHistoryEnableGroupByDomain[]; extern const char kMarkNonSecureAs[]; extern const char kMarkNonSecureAsNeutral[]; extern const char kMarkNonSecureAsNonSecure[]; extern const char kSbDisableAutoUpdate[]; -extern const char kShowSavedCopy[]; -extern const char kEnableShowSavedCopyPrimary[]; -extern const char kEnableShowSavedCopySecondary[]; -extern const char kDisableShowSavedCopy[]; } // namespace switches
diff --git a/ios/chrome/browser/experimental_flags.mm b/ios/chrome/browser/experimental_flags.mm index 56890a0..aeb717d 100644 --- a/ios/chrome/browser/experimental_flags.mm +++ b/ios/chrome/browser/experimental_flags.mm
@@ -159,8 +159,10 @@ return false; // Check if the finch experiment is turned on. - return base::StartsWith(group_name, "Enabled", - base::CompareCase::INSENSITIVE_ASCII); + return !base::StartsWith(group_name, "Disabled", + base::CompareCase::INSENSITIVE_ASCII) && + !base::StartsWith(group_name, "Control", + base::CompareCase::INSENSITIVE_ASCII); } bool IsTargetedToWKWebViewExperimentControlGroup() {
diff --git a/ios/chrome/browser/interstitials/ios_security_interstitial_page.h b/ios/chrome/browser/interstitials/ios_security_interstitial_page.h index 763cc284..128f833 100644 --- a/ios/chrome/browser/interstitials/ios_security_interstitial_page.h +++ b/ios/chrome/browser/interstitials/ios_security_interstitial_page.h
@@ -58,15 +58,6 @@ // the ChromeBrowserState associated with |web_state_|. bool IsPrefEnabled(const char* pref_name) const; - // TODO(felt): Remove these. They are temporary methods, used to pass along - // calls to the |controller_| for subclasses that don't yet have their own - // ChromeControllerClients. crbug.com/488673 - void SetReportingPreference(bool report); - void OpenExtendedReportingPrivacyPolicy(); - security_interstitials::MetricsHelper* GetMetricsHelper(); - void SetMetricsHelper( - scoped_ptr<security_interstitials::MetricsHelper> metrics_helper); - web::WebState* web_state() const { return web_state_; } const GURL& request_url() const { return request_url_; } web::WebInterstitial* web_interstitial() const { return web_interstitial_; } @@ -82,9 +73,6 @@ // IOSSecurityInterstitialPage instance. web::WebInterstitial* web_interstitial_; - // For subclasses that don't have their own IOSChromeControllerClient yet. - scoped_ptr<IOSChromeControllerClient> controller_; - DISALLOW_COPY_AND_ASSIGN(IOSSecurityInterstitialPage); };
diff --git a/ios/chrome/browser/interstitials/ios_security_interstitial_page.mm b/ios/chrome/browser/interstitials/ios_security_interstitial_page.mm index 823027c..bde510c 100644 --- a/ios/chrome/browser/interstitials/ios_security_interstitial_page.mm +++ b/ios/chrome/browser/interstitials/ios_security_interstitial_page.mm
@@ -24,8 +24,7 @@ const GURL& request_url) : web_state_(web_state), request_url_(request_url), - web_interstitial_(nullptr), - controller_(new IOSChromeControllerClient(web_state)) { + web_interstitial_(nullptr) { // Creating web_interstitial_ without showing it leaks memory, so don't // create it here. } @@ -38,8 +37,6 @@ web_state_, ShouldCreateNewNavigation(), request_url_, scoped_ptr<web::HtmlWebInterstitialDelegate>(this)); web_interstitial_->Show(); - - controller_->SetWebInterstitial(web_interstitial_); AfterShow(); } @@ -69,21 +66,3 @@ ios::ChromeBrowserState::FromBrowserState(web_state_->GetBrowserState()); return browser_state->GetPrefs()->GetBoolean(pref_name); } - -void IOSSecurityInterstitialPage::SetReportingPreference(bool report) { - controller_->SetReportingPreference(report); -} - -void IOSSecurityInterstitialPage::OpenExtendedReportingPrivacyPolicy() { - controller_->OpenExtendedReportingPrivacyPolicy(); -} - -security_interstitials::MetricsHelper* -IOSSecurityInterstitialPage::GetMetricsHelper() { - return controller_->metrics_helper(); -} - -void IOSSecurityInterstitialPage::SetMetricsHelper( - scoped_ptr<security_interstitials::MetricsHelper> metrics_helper) { - controller_->set_metrics_helper(std::move(metrics_helper)); -}
diff --git a/ios/chrome/browser/pref_names.cc b/ios/chrome/browser/pref_names.cc index efa345a3..de4b0aa 100644 --- a/ios/chrome/browser/pref_names.cc +++ b/ios/chrome/browser/pref_names.cc
@@ -167,8 +167,4 @@ const char kSafeBrowsingProceedAnywayDisabled[] = "safebrowsing.proceed_anyway_disabled"; -// Boolean that is true when the SSL interstitial should allow users to -// proceed anyway. Otherwise, proceeding is not possible. -const char kSSLErrorOverrideAllowed[] = "ssl.error_override_allowed"; - } // namespace prefs
diff --git a/ios/chrome/browser/pref_names.h b/ios/chrome/browser/pref_names.h index d01f0098..c3a8151 100644 --- a/ios/chrome/browser/pref_names.h +++ b/ios/chrome/browser/pref_names.h
@@ -58,7 +58,6 @@ extern const char kSafeBrowsingExtendedReportingEnabled[]; extern const char kSafeBrowsingExtendedReportingOptInAllowed[]; extern const char kSafeBrowsingProceedAnywayDisabled[]; -extern const char kSSLErrorOverrideAllowed[]; } // namespace prefs
diff --git a/ios/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc b/ios/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc index ad87807..c34f9ebd 100644 --- a/ios/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc +++ b/ios/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc
@@ -26,6 +26,7 @@ #include "components/security_interstitials/core/controller_client.h" #include "ios/chrome/browser/application_context.h" #include "ios/chrome/browser/chrome_url_constants.h" +#include "ios/chrome/browser/interstitials/ios_chrome_controller_client.h" #include "ios/chrome/browser/interstitials/ios_chrome_metrics_helper.h" #include "ios/chrome/browser/pref_names.h" #include "ios/chrome/browser/safe_browsing/ui_manager.h" @@ -117,7 +118,8 @@ ui_manager_(ui_manager), is_main_frame_load_blocked_(IsMainPageLoadBlocked(unsafe_resources)), unsafe_resources_(unsafe_resources), - proceeded_(false) { + proceeded_(false), + controller_(new IOSChromeControllerClient(web_state)) { bool malware = false; bool harmful = false; bool phishing = false; @@ -150,14 +152,14 @@ reporting_info.extra_suffix = GetExtraMetricsSuffix(); reporting_info.rappor_prefix = GetRapporPrefix(); reporting_info.rappor_report_type = rappor::SAFEBROWSING_RAPPOR_TYPE; - SetMetricsHelper(make_scoped_ptr( + controller_->set_metrics_helper(make_scoped_ptr( new IOSChromeMetricsHelper(web_state, request_url(), reporting_info))); - GetMetricsHelper()->RecordUserDecision( + controller_->metrics_helper()->RecordUserDecision( security_interstitials::MetricsHelper::SHOW); - GetMetricsHelper()->RecordUserInteraction( + controller_->metrics_helper()->RecordUserInteraction( security_interstitials::MetricsHelper::TOTAL_VISITS); if (IsPrefEnabled(prefs::kSafeBrowsingProceedAnywayDisabled)) { - GetMetricsHelper()->RecordUserDecision( + controller_->metrics_helper()->RecordUserDecision( security_interstitials::MetricsHelper::PROCEEDING_DISABLED); } @@ -185,17 +187,17 @@ switch (command) { case security_interstitials::CMD_DO_REPORT: { // User enabled SB Extended Reporting via the checkbox. - SetReportingPreference(true); + controller_->SetReportingPreference(true); break; } case security_interstitials::CMD_DONT_REPORT: { // User disabled SB Extended Reporting via the checkbox. - SetReportingPreference(false); + controller_->SetReportingPreference(false); break; } case security_interstitials::CMD_OPEN_HELP_CENTER: { // User pressed "Learn more". - GetMetricsHelper()->RecordUserInteraction( + controller_->metrics_helper()->RecordUserInteraction( security_interstitials::MetricsHelper::SHOW_LEARN_MORE); GURL learn_more_url(interstitial_reason_ == SB_REASON_PHISHING ? kLearnMorePhishingUrlV2 @@ -209,13 +211,13 @@ } case security_interstitials::CMD_OPEN_REPORTING_PRIVACY: { // User pressed on the SB Extended Reporting "privacy policy" link. - OpenExtendedReportingPrivacyPolicy(); + controller_->OpenExtendedReportingPrivacyPolicy(); break; } case security_interstitials::CMD_PROCEED: { // User pressed on the button to proceed. if (!IsPrefEnabled(prefs::kSafeBrowsingProceedAnywayDisabled)) { - GetMetricsHelper()->RecordUserDecision( + controller_->metrics_helper()->RecordUserDecision( security_interstitials::MetricsHelper::PROCEED); web_interstitial()->Proceed(); // |this| has been deleted after Proceed() returns. @@ -250,7 +252,7 @@ // User wants to see why this page is blocked. const UnsafeResource& unsafe_resource = unsafe_resources_[0]; std::string bad_url_spec = unsafe_resource.url.spec(); - GetMetricsHelper()->RecordUserInteraction( + controller_->metrics_helper()->RecordUserInteraction( security_interstitials::MetricsHelper::SHOW_DIAGNOSTIC); std::string diagnostic = base::StringPrintf( kSbDiagnosticUrl, @@ -269,13 +271,13 @@ } case security_interstitials::CMD_SHOW_MORE_SECTION: { // User has opened up the hidden text. - GetMetricsHelper()->RecordUserInteraction( + controller_->metrics_helper()->RecordUserInteraction( security_interstitials::MetricsHelper::SHOW_ADVANCED); break; } case security_interstitials::CMD_REPORT_PHISHING_ERROR: { // User wants to report a phishing error. - GetMetricsHelper()->RecordUserInteraction( + controller_->metrics_helper()->RecordUserInteraction( security_interstitials::MetricsHelper::REPORT_PHISHING_ERROR); GURL phishing_error_url(kReportPhishingErrorUrl); phishing_error_url = google_util::AppendGoogleLocaleParam( @@ -322,7 +324,7 @@ return; if (!IsPrefEnabled(prefs::kSafeBrowsingProceedAnywayDisabled)) { - GetMetricsHelper()->RecordUserDecision( + controller_->metrics_helper()->RecordUserDecision( security_interstitials::MetricsHelper::DONT_PROCEED); } @@ -509,6 +511,10 @@ } } +void SafeBrowsingBlockingPage::AfterShow() { + controller_->SetWebInterstitial(web_interstitial()); +} + void SafeBrowsingBlockingPage::PopulateMalwareLoadTimeData( base::DictionaryValue* load_time_data) const { load_time_data->SetBoolean("phishing", false);
diff --git a/ios/chrome/browser/safe_browsing/safe_browsing_blocking_page.h b/ios/chrome/browser/safe_browsing/safe_browsing_blocking_page.h index cfc2828..c99f4eb3 100644 --- a/ios/chrome/browser/safe_browsing/safe_browsing_blocking_page.h +++ b/ios/chrome/browser/safe_browsing/safe_browsing_blocking_page.h
@@ -92,7 +92,7 @@ bool ShouldCreateNewNavigation() const override; void PopulateInterstitialStrings( base::DictionaryValue* load_time_data) const override; - void AfterShow() override {} + void AfterShow() override; // A list of SafeBrowsingUIManager::UnsafeResource for a tab that the user // should be warned about. They are queued when displaying more than one @@ -148,6 +148,8 @@ std::string GetRapporPrefix() const; std::string GetSamplingEventName() const; + scoped_ptr<IOSChromeControllerClient> controller_; + DISALLOW_COPY_AND_ASSIGN(SafeBrowsingBlockingPage); };
diff --git a/ios/chrome/browser/search_engines/ui_thread_search_terms_data.cc b/ios/chrome/browser/search_engines/ui_thread_search_terms_data.cc index d6e92f6..ab06488 100644 --- a/ios/chrome/browser/search_engines/ui_thread_search_terms_data.cc +++ b/ios/chrome/browser/search_engines/ui_thread_search_terms_data.cc
@@ -91,12 +91,6 @@ return "chrome-ext-ansg"; } -bool UIThreadSearchTermsData::IsShowingSearchTermsOnSearchResultsPages() const { - DCHECK(thread_checker_.CalledOnValidThread()); - return search::IsInstantExtendedAPIEnabled() && - search::IsQueryExtractionEnabled(); -} - std::string UIThreadSearchTermsData::InstantExtendedEnabledParam( bool for_search) const { DCHECK(thread_checker_.CalledOnValidThread()); @@ -109,18 +103,6 @@ return search::ForceInstantResultsParam(for_prerender); } -int UIThreadSearchTermsData::OmniboxStartMargin() const { - DCHECK(thread_checker_.CalledOnValidThread()); - // iOS has not InstantService. - return search::kDisableStartMargin; -} - -std::string UIThreadSearchTermsData::NTPIsThemedParam() const { - DCHECK(thread_checker_.CalledOnValidThread()); - // iOS does not supports themed NTP. - return std::string(); -} - std::string UIThreadSearchTermsData::IOSWebViewTypeParam() const { DCHECK(thread_checker_.CalledOnValidThread()); std::string param = experimental_flags::GetWKWebViewSearchParams();
diff --git a/ios/chrome/browser/search_engines/ui_thread_search_terms_data.h b/ios/chrome/browser/search_engines/ui_thread_search_terms_data.h index 0c8a2c2..b522a5e 100644 --- a/ios/chrome/browser/search_engines/ui_thread_search_terms_data.h +++ b/ios/chrome/browser/search_engines/ui_thread_search_terms_data.h
@@ -26,11 +26,8 @@ std::string GetSearchClient() const override; std::string GetSuggestClient() const override; std::string GetSuggestRequestIdentifier() const override; - bool IsShowingSearchTermsOnSearchResultsPages() const override; std::string InstantExtendedEnabledParam(bool for_search) const override; std::string ForceInstantResultsParam(bool for_prerender) const override; - int OmniboxStartMargin() const override; - std::string NTPIsThemedParam() const override; std::string IOSWebViewTypeParam() const override; std::string GoogleImageSearchSource() const override;
diff --git a/ios/chrome/browser/signin/browser_state_data_remover.mm b/ios/chrome/browser/signin/browser_state_data_remover.mm index 4e7dccb..4390c25 100644 --- a/ios/chrome/browser/signin/browser_state_data_remover.mm +++ b/ios/chrome/browser/signin/browser_state_data_remover.mm
@@ -76,8 +76,10 @@ return; } - if (forget_last_username_) + if (forget_last_username_) { + browser_state_->GetPrefs()->ClearPref(prefs::kGoogleServicesLastAccountId); browser_state_->GetPrefs()->ClearPref(prefs::kGoogleServicesLastUsername); + } if (callback_) callback_.get()();
diff --git a/ios/chrome/browser/ssl/OWNERS b/ios/chrome/browser/ssl/OWNERS new file mode 100644 index 0000000..9a5eb5e1c --- /dev/null +++ b/ios/chrome/browser/ssl/OWNERS
@@ -0,0 +1,2 @@ +estark@chromium.org +felt@chromium.org
diff --git a/ios/chrome/browser/ssl/ios_ssl_blocking_page.cc b/ios/chrome/browser/ssl/ios_ssl_blocking_page.cc new file mode 100644 index 0000000..304af8d7 --- /dev/null +++ b/ios/chrome/browser/ssl/ios_ssl_blocking_page.cc
@@ -0,0 +1,207 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ios/chrome/browser/ssl/ios_ssl_blocking_page.h" + +#include <utility> + +#include "base/metrics/histogram.h" +#include "base/prefs/pref_service.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/utf_string_conversions.h" +#include "components/security_interstitials/core/metrics_helper.h" +#include "components/security_interstitials/core/ssl_error_ui.h" +#include "ios/chrome/browser/interstitials/ios_chrome_controller_client.h" +#include "ios/chrome/browser/interstitials/ios_chrome_metrics_helper.h" +#include "ios/chrome/browser/pref_names.h" +#include "ios/chrome/grit/ios_strings.h" +#include "ios/public/provider/chrome/browser/browser_constants.h" +#include "ios/public/provider/chrome/browser/browser_state/chrome_browser_state.h" +#include "ios/web/public/web_state/web_state.h" +#include "net/base/net_errors.h" +#include "ui/base/l10n/l10n_util.h" +#include "url/gurl.h" + +using security_interstitials::SSLErrorUI; + +namespace { +// Events for UMA. Do not reorder or change! +enum SSLExpirationAndDecision { + EXPIRED_AND_PROCEED, + EXPIRED_AND_DO_NOT_PROCEED, + NOT_EXPIRED_AND_PROCEED, + NOT_EXPIRED_AND_DO_NOT_PROCEED, + END_OF_SSL_EXPIRATION_AND_DECISION, +}; + +// Rappor prefix, which is used for both overridable and non-overridable +// interstitials so we don't leak the "overridable" bit. +const char kSSLRapporPrefix[] = "ssl2"; + +void RecordSSLExpirationPageEventState(bool expired_but_previously_allowed, + bool proceed, + bool overridable) { + SSLExpirationAndDecision event; + if (expired_but_previously_allowed && proceed) + event = EXPIRED_AND_PROCEED; + else if (expired_but_previously_allowed && !proceed) + event = EXPIRED_AND_DO_NOT_PROCEED; + else if (!expired_but_previously_allowed && proceed) + event = NOT_EXPIRED_AND_PROCEED; + else + event = NOT_EXPIRED_AND_DO_NOT_PROCEED; + + if (overridable) { + UMA_HISTOGRAM_ENUMERATION( + "interstitial.ssl.expiration_and_decision.overridable", event, + END_OF_SSL_EXPIRATION_AND_DECISION); + } else { + UMA_HISTOGRAM_ENUMERATION( + "interstitial.ssl.expiration_and_decision.nonoverridable", event, + END_OF_SSL_EXPIRATION_AND_DECISION); + } +} +} // namespace + +// Note that we always create a navigation entry with SSL errors. +// No error happening loading a sub-resource triggers an interstitial so far. +IOSSSLBlockingPage::IOSSSLBlockingPage( + web::WebState* web_state, + int cert_error, + const net::SSLInfo& ssl_info, + const GURL& request_url, + int options_mask, + const base::Time& time_triggered, + const base::Callback<void(bool)>& callback) + : IOSSecurityInterstitialPage(web_state, request_url), + callback_(callback), + ssl_info_(ssl_info), + overridable_(IsOverridable(options_mask)), + expired_but_previously_allowed_( + (options_mask & SSLErrorUI::EXPIRED_BUT_PREVIOUSLY_ALLOWED) != 0), + controller_(new IOSChromeControllerClient(web_state)) { + // Get the language and override prefs for the SSLErrorUI. + std::string languages; + ios::ChromeBrowserState* browser_state = + ios::ChromeBrowserState::FromBrowserState(web_state->GetBrowserState()); + if (browser_state) { + languages = browser_state->GetPrefs()->GetString(prefs::kAcceptLanguages); + } + if (overridable_) + options_mask |= SSLErrorUI::SOFT_OVERRIDE_ENABLED; + else + options_mask &= ~SSLErrorUI::SOFT_OVERRIDE_ENABLED; + + // Set up the metrics helper for the SSLErrorUI. + security_interstitials::MetricsHelper::ReportDetails reporting_info; + reporting_info.metric_prefix = + overridable_ ? "ssl_overridable" : "ssl_nonoverridable"; + reporting_info.rappor_prefix = kSSLRapporPrefix; + reporting_info.rappor_report_type = rappor::UMA_RAPPOR_TYPE; + IOSChromeMetricsHelper* ios_chrome_metrics_helper = + new IOSChromeMetricsHelper(web_state, request_url, reporting_info); + controller_->set_metrics_helper(make_scoped_ptr(ios_chrome_metrics_helper)); + + ssl_error_ui_.reset(new SSLErrorUI(request_url, cert_error, ssl_info, + options_mask, time_triggered, languages, + controller_.get())); + + // Creating an interstitial without showing (e.g. from chrome://interstitials) + // it leaks memory, so don't create it here. +} + +bool IOSSSLBlockingPage::ShouldCreateNewNavigation() const { + return true; +} + +IOSSSLBlockingPage::~IOSSSLBlockingPage() { + if (!callback_.is_null()) { + // The page is closed without the user having chosen what to do, default to + // deny. + RecordSSLExpirationPageEventState(expired_but_previously_allowed_, false, + overridable_); + NotifyDenyCertificate(); + } +} + +void IOSSSLBlockingPage::AfterShow() { + controller_->SetWebInterstitial(web_interstitial()); +} + +void IOSSSLBlockingPage::PopulateInterstitialStrings( + base::DictionaryValue* load_time_data) const { + ssl_error_ui_->PopulateStringsForHTML(load_time_data); + // Spoofing attempts have a custom message on iOS. + // This code will no longer be necessary once UIWebView is gone. + if (ssl_info_.cert->subject().GetDisplayName() == ios::kSpoofingAttemptFlag) { + load_time_data->SetString( + "errorCode", base::string16(base::ASCIIToUTF16("Unverified URL"))); + load_time_data->SetString( + "tabTitle", l10n_util::GetStringUTF16( + IDS_IOS_INTERSTITIAL_HEADING_SPOOFING_ATTEMPT_ERROR)); + load_time_data->SetString( + "heading", l10n_util::GetStringUTF16( + IDS_IOS_INTERSTITIAL_HEADING_SPOOFING_ATTEMPT_ERROR)); + load_time_data->SetString( + "primaryParagraph", + l10n_util::GetStringUTF16( + IDS_IOS_INTERSTITIAL_SUMMARY_SPOOFING_ATTEMPT_ERROR)); + load_time_data->SetString( + "explanationParagraph", + l10n_util::GetStringUTF16( + IDS_IOS_INTERSTITIAL_DETAILS_SPOOFING_ATTEMPT_ERROR)); + load_time_data->SetString("finalParagraph", base::string16()); + } +} + +// This handles the commands sent from the interstitial JavaScript. +void IOSSSLBlockingPage::CommandReceived(const std::string& command) { + if (command == "\"pageLoadComplete\"") { + // content::WaitForRenderFrameReady sends this message when the page + // load completes. Ignore it. + return; + } + + int cmd = 0; + bool retval = base::StringToInt(command, &cmd); + DCHECK(retval); + ssl_error_ui_->HandleCommand( + static_cast<security_interstitials::SecurityInterstitialCommands>(cmd)); +} + +void IOSSSLBlockingPage::OnProceed() { + RecordSSLExpirationPageEventState(expired_but_previously_allowed_, true, + overridable_); + + // Accepting the certificate resumes the loading of the page. + DCHECK(!callback_.is_null()); + callback_.Run(true); + callback_.Reset(); +} + +void IOSSSLBlockingPage::OnDontProceed() { + RecordSSLExpirationPageEventState(expired_but_previously_allowed_, false, + overridable_); + + NotifyDenyCertificate(); +} + +void IOSSSLBlockingPage::NotifyDenyCertificate() { + // It's possible that callback_ may not exist if the user clicks "Proceed" + // followed by pressing the back button before the interstitial is hidden. + // In that case the certificate will still be treated as allowed. + if (callback_.is_null()) + return; + + callback_.Run(false); + callback_.Reset(); +} + +// static +bool IOSSSLBlockingPage::IsOverridable(int options_mask) { + const bool is_overridable = + (options_mask & SSLErrorUI::SOFT_OVERRIDE_ENABLED) && + !(options_mask & SSLErrorUI::STRICT_ENFORCEMENT); + return is_overridable; +}
diff --git a/ios/chrome/browser/ssl/ios_ssl_blocking_page.h b/ios/chrome/browser/ssl/ios_ssl_blocking_page.h new file mode 100644 index 0000000..be5b9463 --- /dev/null +++ b/ios/chrome/browser/ssl/ios_ssl_blocking_page.h
@@ -0,0 +1,80 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_CHROME_BROWSER_SSL_IOS_SSL_BLOCKING_PAGE_H_ +#define IOS_CHROME_BROWSER_SSL_IOS_SSL_BLOCKING_PAGE_H_ + +#include <string> +#include <vector> + +#include "base/callback.h" +#include "base/macros.h" +#include "base/time/time.h" +#include "components/certificate_reporting/error_report.h" +#include "ios/chrome/browser/interstitials/ios_security_interstitial_page.h" +#include "net/ssl/ssl_info.h" + +class IOSChromeControllerClient; +class GURL; + +namespace ios { +class ChromeBrowserState; +} + +namespace security_interstitials { +class SSLErrorUI; +} + +// This class is responsible for showing/hiding the interstitial page that is +// shown when a certificate error happens. +// It deletes itself when the interstitial page is closed. +class IOSSSLBlockingPage : public IOSSecurityInterstitialPage { + public: + ~IOSSSLBlockingPage() override; + + // Creates an SSL blocking page. If the blocking page isn't shown, the caller + // is responsible for cleaning up the blocking page, otherwise the + // interstitial takes ownership when shown. |options_mask| must be a bitwise + // mask of SSLErrorUI::SSLErrorOptionsMask values. + IOSSSLBlockingPage(web::WebState* web_state, + int cert_error, + const net::SSLInfo& ssl_info, + const GURL& request_url, + int options_mask, + const base::Time& time_triggered, + const base::Callback<void(bool)>& callback); + + protected: + // InterstitialPageDelegate implementation. + void CommandReceived(const std::string& command) override; + void OnProceed() override; + void OnDontProceed() override; + + // SecurityInterstitialPage implementation: + bool ShouldCreateNewNavigation() const override; + void PopulateInterstitialStrings( + base::DictionaryValue* load_time_data) const override; + void AfterShow() override; + + private: + void NotifyDenyCertificate(); + + // Returns true if |options_mask| refers to a soft-overridable SSL error. + static bool IsOverridable(int options_mask); + + base::Callback<void(bool)> callback_; + const net::SSLInfo ssl_info_; + const bool overridable_; // The UI allows the user to override the error. + + // The user previously allowed a bad certificate, but the decision has now + // expired. + const bool expired_but_previously_allowed_; + + scoped_ptr<IOSChromeControllerClient> controller_; + scoped_ptr<security_interstitials::SSLErrorUI> ssl_error_ui_; + + DISALLOW_COPY_AND_ASSIGN(IOSSSLBlockingPage); +}; + +#endif // IOS_CHROME_BROWSER_SSL_IOS_SSL_BLOCKING_PAGE_H_
diff --git a/ios/chrome/browser/ui/UIView+SizeClassSupport.h b/ios/chrome/browser/ui/UIView+SizeClassSupport.h index c5ee09c..18b52428 100644 --- a/ios/chrome/browser/ui/UIView+SizeClassSupport.h +++ b/ios/chrome/browser/ui/UIView+SizeClassSupport.h
@@ -11,13 +11,16 @@ typedef NS_ENUM(NSInteger, SizeClassIdiom) { COMPACT = 0, REGULAR, - SIZE_CLASS_COUNT + UNSPECIFIED, + SIZE_CLASS_COUNT = UNSPECIFIED, }; // UIView category that exposes SizeClassIdiom getters. @interface UIView (SizeClassSupport) -// Convenience getters for the view's width and height SizeClassIdioms. +// Convenience getters for the view's width and height SizeClassIdioms. If the +// view's size class is unspecified, these functions return the size class idiom +// of the application's key window. @property(nonatomic, readonly) SizeClassIdiom cr_widthSizeClass; @property(nonatomic, readonly) SizeClassIdiom cr_heightSizeClass;
diff --git a/ios/chrome/browser/ui/UIView+SizeClassSupport.mm b/ios/chrome/browser/ui/UIView+SizeClassSupport.mm index 8855c7f..79ba910 100644 --- a/ios/chrome/browser/ui/UIView+SizeClassSupport.mm +++ b/ios/chrome/browser/ui/UIView+SizeClassSupport.mm
@@ -4,13 +4,40 @@ #import "ios/chrome/browser/ui/UIView+SizeClassSupport.h" +#import "base/logging.h" #import "base/ios/ios_util.h" -#import "ios/chrome/browser/ui/legacy_size_class_support_util.h" +#import "ios/chrome/browser/ui/ui_util.h" namespace { +// Returns the SizeClassIdiom corresponding with |size_class|. SizeClassIdiom GetSizeClassIdiom(UIUserInterfaceSizeClass size_class) { - return size_class == UIUserInterfaceSizeClassCompact ? COMPACT : REGULAR; + switch (size_class) { + case UIUserInterfaceSizeClassCompact: + return COMPACT; + case UIUserInterfaceSizeClassRegular: + return REGULAR; + case UIUserInterfaceSizeClassUnspecified: + return UNSPECIFIED; + } +} + +// Returns YES if |size_class| is not UIUserInterfaceSizeClassUnspecified. +bool IsSizeClassSpecified(UIUserInterfaceSizeClass size_class) { + return size_class != UIUserInterfaceSizeClassUnspecified; +} + +// The height of an iPhone 6 in portrait. A UIWindow's size class idiom is +// REGULAR if the frame's size is greater than this value in that dimension. +const CGFloat kIPhone6PortraitHeight = 667.0f; + +// Returns the SizeClassIdiom for a UIWindow with a side of |side_length| points +// in a given dimension. This fallback approach is used when: +// - |-traitCollection| is not implemented (i.e. pre-iOS8), or +// - both the target and the UIApplication's |-keyWindow| have an unspecified +// size class. +SizeClassIdiom SizeClassForSideLength(CGFloat side_length) { + return side_length > kIPhone6PortraitHeight ? REGULAR : COMPACT; } } // namespace @@ -18,15 +45,30 @@ @implementation UIView (SizeClassSupport) - (SizeClassIdiom)cr_widthSizeClass { - if (base::ios::IsRunningOnIOS8OrLater()) - return GetSizeClassIdiom(self.traitCollection.horizontalSizeClass); - return CurrentWidthSizeClass(); + UIWindow* keyWindow = [UIApplication sharedApplication].keyWindow; + if ([self respondsToSelector:@selector(traitCollection)]) { + UIUserInterfaceSizeClass sizeClass = + self.traitCollection.horizontalSizeClass; + if (!IsSizeClassSpecified(sizeClass)) + sizeClass = keyWindow.traitCollection.horizontalSizeClass; + if (IsSizeClassSpecified(sizeClass)) + return GetSizeClassIdiom(sizeClass); + LOG(WARNING) << "Encountered UIWindow with unspecified width size class."; + } + return SizeClassForSideLength(CGRectGetWidth(keyWindow.frame)); } - (SizeClassIdiom)cr_heightSizeClass { - if (base::ios::IsRunningOnIOS8OrLater()) - return GetSizeClassIdiom(self.traitCollection.verticalSizeClass); - return CurrentHeightSizeClass(); + UIWindow* keyWindow = [UIApplication sharedApplication].keyWindow; + if ([self respondsToSelector:@selector(traitCollection)]) { + UIUserInterfaceSizeClass sizeClass = self.traitCollection.verticalSizeClass; + if (!IsSizeClassSpecified(sizeClass)) + sizeClass = keyWindow.traitCollection.verticalSizeClass; + if (IsSizeClassSpecified(sizeClass)) + return GetSizeClassIdiom(sizeClass); + LOG(WARNING) << "Encountered UIWindow with unspecified height size class."; + } + return SizeClassForSideLength(CGRectGetHeight(keyWindow.frame)); } @end
diff --git a/ios/chrome/browser/ui/commands/ios_command_ids.h b/ios/chrome/browser/ui/commands/ios_command_ids.h index aa07da18..496de1d 100644 --- a/ios/chrome/browser/ui/commands/ios_command_ids.h +++ b/ios/chrome/browser/ui/commands/ios_command_ids.h
@@ -12,9 +12,23 @@ // If you change a given command's number, any NIB files that refer to it will // also need to be updated. -// Do not use IDs below 40900 while the iOS build still depends on //chrome, to -// avoid conflicts. -// TODO(droger): Remove this comment once iOS no longer depends on //chrome. +#define IDC_BACK 33000 +#define IDC_FORWARD 33001 +#define IDC_RELOAD 33002 +#define IDC_STOP 33006 +#define IDC_NEW_TAB 34014 +#define IDC_CLOSE_TAB 34015 +#define IDC_FULLSCREEN 34030 +#define IDC_BOOKMARK_PAGE 35000 +#define IDC_VIEW_SOURCE 35002 +#define IDC_PRINT 35003 +#define IDC_FIND 37000 +#define IDC_FIND_NEXT 37001 +#define IDC_FIND_PREVIOUS 37002 +#define IDC_SHOW_HISTORY 40010 +#define IDC_SHOW_BOOKMARK_MANAGER 40011 +#define IDC_OPTIONS 40015 +#define IDC_HELP_PAGE_VIA_MENU 40020 #define IDC_SHOW_TOOLS_MENU 40900 #define IDC_TOGGLE_TAB_SWITCHER 40901 #define IDC_VOICE_SEARCH 40902 @@ -59,8 +73,5 @@ #define IDC_SHOW_SAVE_PASSWORDS_SETTINGS 40945 #define IDC_READER_MODE 40947 #define IDC_RATE_THIS_APP 40948 -// Do not use IDs above 40999 while the iOS build still depends on //chrome, to -// avoid conflicts. -// TODO(droger): Remove this comment once iOS no longer depends on //chrome. #endif // IOS_CHROME_BROWSER_UI_COMMANDS_IOS_COMMAND_IDS_H_
diff --git a/ios/chrome/browser/ui/legacy_size_class_support_util.h b/ios/chrome/browser/ui/legacy_size_class_support_util.h deleted file mode 100644 index a5eac623..0000000 --- a/ios/chrome/browser/ui/legacy_size_class_support_util.h +++ /dev/null
@@ -1,16 +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 IOS_CHROME_BROWSER_UI_LEGACY_SIZE_CLASS_SUPPORT_UTIL_H_ -#define IOS_CHROME_BROWSER_UI_LEGACY_SIZE_CLASS_SUPPORT_UTIL_H_ - -#import "ios/chrome/browser/ui/UIView+SizeClassSupport.h" - -// Temporary functions for supporting size classes on pre-iOS8 devices. The -// return values are based on the bounds of the main UIScreen. -// TODO(crbug.com/519568): Remove once Chrome for iOS drops support for iOS7. -SizeClassIdiom CurrentWidthSizeClass(); -SizeClassIdiom CurrentHeightSizeClass(); - -#endif // IOS_CHROME_BROWSER_UI_LEGACY_SIZE_CLASS_SUPPORT_UTIL_H_
diff --git a/ios/chrome/browser/ui/legacy_size_class_support_util.mm b/ios/chrome/browser/ui/legacy_size_class_support_util.mm deleted file mode 100644 index 3ba6e6e..0000000 --- a/ios/chrome/browser/ui/legacy_size_class_support_util.mm +++ /dev/null
@@ -1,40 +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. - -#import "ios/chrome/browser/ui/legacy_size_class_support_util.h" - -#include "base/logging.h" -#import "base/ios/ios_util.h" -#import "ios/chrome/browser/ui/ui_util.h" - -namespace { -// The height of an iPhone 6 in portrait. An iPhone whose side length is -// greater than this value is considered to be of a REGULAR size class in that -// dimension. -const CGFloat kIPhone6PortraitHeight = 667.0f; - -// Returns the SizeClassIdiom for a screen with a side of |side_length| points -// in a given dimension. -SizeClassIdiom SizeClassForSideLength(CGFloat side_length) { - // These functions are only for use in pre-iOS8. This simplifies the logic - // for iPad size classes, as it eliminates the need to consider multitasking. - DCHECK(!base::ios::IsRunningOnIOS8OrLater()); - // iPads always have a REGULAR width size class. - if (IsIPadIdiom()) - return REGULAR; - // A side whose length is greater than |kIPhone6PortraitHeight| is REGULAR. - if (side_length > kIPhone6PortraitHeight) - return REGULAR; - // All other iPhone widths are COMPACT. - return COMPACT; -} -} - -SizeClassIdiom CurrentWidthSizeClass() { - return SizeClassForSideLength(CurrentScreenWidth()); -} - -SizeClassIdiom CurrentHeightSizeClass() { - return SizeClassForSideLength(CurrentScreenHeight()); -}
diff --git a/ios/chrome/browser/ui/prerender_final_status.h b/ios/chrome/browser/ui/prerender_final_status.h new file mode 100644 index 0000000..a7d30abd --- /dev/null +++ b/ios/chrome/browser/ui/prerender_final_status.h
@@ -0,0 +1,17 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_CHROME_BROWSER_UI_PRERENDER_FINAL_STATUS_H_ +#define IOS_CHROME_BROWSER_UI_PRERENDER_FINAL_STATUS_H_ + +// PrerenderFinalStatus values are used in the "Prerender.FinalStatus" histogram +// and new values needs to be kept in sync with histogram.xml. +enum PrerenderFinalStatus { + PRERENDER_FINAL_STATUS_USED = 0, + PRERENDER_FINAL_STATUS_MEMORY_LIMIT_EXCEEDED = 12, + PRERENDER_FINAL_STATUS_CANCELLED = 32, + PRERENDER_FINAL_STATUS_MAX = 52, +}; + +#endif // IOS_CHROME_BROWSER_UI_PRERENDER_FINAL_STATUS_H_
diff --git a/ios/chrome/ios_chrome.gyp b/ios/chrome/ios_chrome.gyp index fd886f5..082c75bc 100644 --- a/ios/chrome/ios_chrome.gyp +++ b/ios/chrome/ios_chrome.gyp
@@ -497,6 +497,8 @@ 'browser/snapshots/snapshot_overlay.mm', 'browser/snapshots/snapshots_util.h', 'browser/snapshots/snapshots_util.mm', + 'browser/ssl/ios_ssl_blocking_page.cc', + 'browser/ssl/ios_ssl_blocking_page.h', 'browser/suggestions/image_fetcher_impl.h', 'browser/suggestions/image_fetcher_impl.mm', 'browser/suggestions/suggestions_service_factory.h', @@ -567,14 +569,13 @@ 'browser/ui/keyboard/UIKeyCommand+Chrome.mm', 'browser/ui/keyboard/hardware_keyboard_watcher.h', 'browser/ui/keyboard/hardware_keyboard_watcher.mm', - 'browser/ui/legacy_size_class_support_util.h', - 'browser/ui/legacy_size_class_support_util.mm', 'browser/ui/native_content_controller.h', 'browser/ui/native_content_controller.mm', 'browser/ui/omnibox/web_omnibox_edit_controller.cc', 'browser/ui/omnibox/web_omnibox_edit_controller.h', 'browser/ui/orientation_limiting_navigation_controller.h', 'browser/ui/orientation_limiting_navigation_controller.mm', + 'browser/ui/prerender_final_status.h', 'browser/ui/reversed_animation.h', 'browser/ui/reversed_animation.mm', 'browser/ui/rtl_geometry.h',
diff --git a/ios/provider/ios_provider_chrome.gyp b/ios/provider/ios_provider_chrome.gyp index 15d9dad..dc2bb81 100644 --- a/ios/provider/ios_provider_chrome.gyp +++ b/ios/provider/ios_provider_chrome.gyp
@@ -28,6 +28,7 @@ '../public/provider/chrome/browser/signin/signin_error_provider.mm', '../public/provider/chrome/browser/signin/signin_resources_provider.h', '../public/provider/chrome/browser/signin/signin_resources_provider.mm', + '../public/provider/chrome/browser/string_provider.cc', '../public/provider/chrome/browser/string_provider.h', '../public/provider/chrome/browser/ui/infobar_view_delegate.h', '../public/provider/chrome/browser/ui/infobar_view_protocol.h', @@ -37,6 +38,10 @@ 'dependencies': [ '../../base/base.gyp:base', '../../components/components.gyp:autofill_core_browser', + '../../components/components.gyp:favicon_base', + '../../components/components.gyp:metrics', + '../../components/components.gyp:sync_sessions', + '../../net/net.gyp:net', '../web/ios_web.gyp:ios_web', 'ios_provider_web.gyp:ios_provider_web', ],
diff --git a/ios/public/provider/chrome/DEPS b/ios/public/provider/chrome/DEPS deleted file mode 100644 index 2635c94..0000000 --- a/ios/public/provider/chrome/DEPS +++ /dev/null
@@ -1,5 +0,0 @@ -include_rules = [ - "+components/autofill/core/browser", - "+components/favicon_base", - "+ios/web/public", -]
diff --git a/ios/public/provider/chrome/browser/BUILD.gn b/ios/public/provider/chrome/browser/BUILD.gn index c633a52f..aad28a85 100644 --- a/ios/public/provider/chrome/browser/BUILD.gn +++ b/ios/public/provider/chrome/browser/BUILD.gn
@@ -17,6 +17,7 @@ "signin/chrome_identity_service.mm", "signin/signin_error_provider.h", "signin/signin_error_provider.mm", + "string_provider.cc", "string_provider.h", "ui/infobar_view_delegate.h", "ui/infobar_view_protocol.h",
diff --git a/ios/public/provider/chrome/browser/DEPS b/ios/public/provider/chrome/browser/DEPS index 6487945..6b2f540 100644 --- a/ios/public/provider/chrome/browser/DEPS +++ b/ios/public/provider/chrome/browser/DEPS
@@ -1,4 +1,8 @@ include_rules = [ + "+components/autofill/core/browser", + "+components/favicon_base", "+components/metrics", "+components/sync_sessions", + "+ios/web/public", + "+net", ]
diff --git a/ios/public/provider/chrome/browser/browser_state/chrome_browser_state.h b/ios/public/provider/chrome/browser/browser_state/chrome_browser_state.h index 08dac81..15d7580d 100644 --- a/ios/public/provider/chrome/browser/browser_state/chrome_browser_state.h +++ b/ios/public/provider/chrome/browser/browser_state/chrome_browser_state.h
@@ -5,14 +5,19 @@ #ifndef IOS_PUBLIC_PROVIDER_CHROME_BROWSER_BROWSER_STATE_CHROME_BROWSER_STATE_H_ #define IOS_PUBLIC_PROVIDER_CHROME_BROWSER_BROWSER_STATE_CHROME_BROWSER_STATE_H_ +#include <map> #include <string> #include "base/callback_forward.h" #include "base/compiler_specific.h" #include "base/macros.h" +#include "base/memory/linked_ptr.h" #include "base/memory/ref_counted.h" +#include "base/memory/scoped_vector.h" #include "ios/web/public/browser_state.h" +#include "net/url_request/url_request_job_factory.h" +class ChromeBrowserStateIOData; class PrefProxyConfigTracker; class PrefService; @@ -23,6 +28,7 @@ namespace net { class SSLConfigService; +class URLRequestInterceptor; } namespace syncable_prefs { @@ -78,6 +84,15 @@ // Retrieves a pointer to the PrefService that manages the preferences. virtual PrefService* GetPrefs() = 0; + // Retrieves a pointer to the PrefService that manages the preferences + // for OffTheRecord browser states. + virtual PrefService* GetOffTheRecordPrefs() = 0; + + // Allows access to ChromeBrowserStateIOData without going through + // ResourceContext that is not compiled on iOS. This method must be called on + // UI thread, but the returned object must only be accessed on the IO thread. + virtual ChromeBrowserStateIOData* GetIOData() = 0; + // Retrieves a pointer to the PrefService that manages the preferences as // a syncable_prefs::PrefServiceSyncable. virtual syncable_prefs::PrefServiceSyncable* GetSyncablePrefs() = 0; @@ -101,6 +116,19 @@ // Returns the SSLConfigService for this browser state. virtual net::SSLConfigService* GetSSLConfigService() = 0; + // Creates the main net::URLRequestContextGetter that will be returned by + // GetRequestContext(). Should only be called once. + virtual net::URLRequestContextGetter* CreateRequestContext( + std::map<std::string, + linked_ptr<net::URLRequestJobFactory::ProtocolHandler>>* + protocol_handlers, + ScopedVector<net::URLRequestInterceptor> request_interceptors) = 0; + + // Creates a isolated net::URLRequestContextGetter. Should only be called once + // per partition_path per browser state object. + virtual net::URLRequestContextGetter* CreateIsolatedRequestContext( + const base::FilePath& partition_path) = 0; + protected: ChromeBrowserState() {}
diff --git a/ios/public/provider/chrome/browser/browser_state/chrome_browser_state_manager.h b/ios/public/provider/chrome/browser/browser_state/chrome_browser_state_manager.h index 1a992cce..b17c41ae 100644 --- a/ios/public/provider/chrome/browser/browser_state/chrome_browser_state_manager.h +++ b/ios/public/provider/chrome/browser/browser_state/chrome_browser_state_manager.h
@@ -26,10 +26,6 @@ public: virtual ~ChromeBrowserStateManager() {} - // Temporary method to help migrating from ProfileManager to - // ChromeBrowserStateManager. - virtual void ShutDown() {} - // Returns the ChromeBrowserState that was last used, creating one if // necessary. virtual ChromeBrowserState* GetLastUsedBrowserState() = 0;
diff --git a/ios/public/provider/chrome/browser/string_provider.cc b/ios/public/provider/chrome/browser/string_provider.cc new file mode 100644 index 0000000..29e9d151 --- /dev/null +++ b/ios/public/provider/chrome/browser/string_provider.cc
@@ -0,0 +1,45 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ios/public/provider/chrome/browser/string_provider.h" + +namespace ios { + +StringProvider::StringProvider() {} + +StringProvider::~StringProvider() {} + +std::string StringProvider::GetOmniboxCopyUrlString() { + return std::string(); +} + +int StringProvider::GetUnsafePortTitleID() { + return 0; +} + +int StringProvider::GetUnsafePortHeadlineID() { + return 0; +} + +int StringProvider::GetUnsafePortMessageID() { + return 0; +} + +int StringProvider::GetUnsafePortDetailsID() { + return 0; +} + +base::string16 StringProvider::GetDoneString() { + return base::string16(); +} + +base::string16 StringProvider::GetOKString() { + return base::string16(); +} + +base::string16 StringProvider::GetProductName() { + return base::string16(); +} + +} // namespace ios
diff --git a/ios/public/provider/chrome/browser/string_provider.h b/ios/public/provider/chrome/browser/string_provider.h index 3f10b04..f89659c 100644 --- a/ios/public/provider/chrome/browser/string_provider.h +++ b/ios/public/provider/chrome/browser/string_provider.h
@@ -23,32 +23,25 @@ // is no longer necessary. class StringProvider { public: - StringProvider() {} - virtual ~StringProvider() {} + StringProvider(); + virtual ~StringProvider(); // Returns the string to display in the omnibox context menu for the user to // copy the URL for the current search query into the pasteboard. virtual std::string GetOmniboxCopyUrlString() = 0; - // Return the strings used to display spoofing attempt errors. - virtual base::string16 GetSpoofingInterstitialTitle() = 0; - virtual base::string16 GetSpoofingInterstitialHeadline() = 0; - virtual base::string16 GetSpoofingInterstitialMessage() = 0; - virtual base::string16 GetSpoofingInterstitialDetails() = 0; - virtual base::string16 GetSpoofingInterstitialFailure() = 0; - // Return the resource IDs used to display unsafe port errors. - virtual int GetUnsafePortTitleID() = 0; - virtual int GetUnsafePortHeadlineID() = 0; - virtual int GetUnsafePortMessageID() = 0; - virtual int GetUnsafePortDetailsID() = 0; + virtual int GetUnsafePortTitleID(); + virtual int GetUnsafePortHeadlineID(); + virtual int GetUnsafePortMessageID(); + virtual int GetUnsafePortDetailsID(); // Returns a generic "Done" string. - virtual base::string16 GetDoneString() = 0; + virtual base::string16 GetDoneString(); // Returns a generic "OK" string. - virtual base::string16 GetOKString() = 0; + virtual base::string16 GetOKString(); // Returns the product name (e.g. "Google Chrome"). - virtual base::string16 GetProductName() = 0; + virtual base::string16 GetProductName(); }; } // namespace ios
diff --git a/ios/public/test/fake_string_provider.cc b/ios/public/test/fake_string_provider.cc index 0313177e..87269f6a 100644 --- a/ios/public/test/fake_string_provider.cc +++ b/ios/public/test/fake_string_provider.cc
@@ -6,62 +6,12 @@ namespace ios { -FakeStringProvider::FakeStringProvider() { -} +FakeStringProvider::FakeStringProvider() {} -FakeStringProvider::~FakeStringProvider() { -} +FakeStringProvider::~FakeStringProvider() {} std::string FakeStringProvider::GetOmniboxCopyUrlString() { return "Copy URL"; } -base::string16 FakeStringProvider::GetSpoofingInterstitialTitle() { - return base::string16(); -} - -base::string16 FakeStringProvider::GetSpoofingInterstitialHeadline() { - return base::string16(); -} - -base::string16 FakeStringProvider::GetSpoofingInterstitialMessage() { - return base::string16(); -} - -base::string16 FakeStringProvider::GetSpoofingInterstitialDetails() { - return base::string16(); -} - -base::string16 FakeStringProvider::GetSpoofingInterstitialFailure() { - return base::string16(); -} - -int FakeStringProvider::GetUnsafePortTitleID() { - return 0; -} - -int FakeStringProvider::GetUnsafePortHeadlineID() { - return 0; -} - -int FakeStringProvider::GetUnsafePortMessageID() { - return 0; -} - -int FakeStringProvider::GetUnsafePortDetailsID() { - return 0; -} - -base::string16 FakeStringProvider::GetDoneString() { - return base::string16(); -} - -base::string16 FakeStringProvider::GetOKString() { - return base::string16(); -} - -base::string16 FakeStringProvider::GetProductName() { - return base::string16(); -} - } // namespace ios
diff --git a/ios/public/test/fake_string_provider.h b/ios/public/test/fake_string_provider.h index 0ae7baac..77b9b87a 100644 --- a/ios/public/test/fake_string_provider.h +++ b/ios/public/test/fake_string_provider.h
@@ -18,18 +18,6 @@ // StringProvider implementation std::string GetOmniboxCopyUrlString() override; - base::string16 GetSpoofingInterstitialTitle() override; - base::string16 GetSpoofingInterstitialHeadline() override; - base::string16 GetSpoofingInterstitialMessage() override; - base::string16 GetSpoofingInterstitialDetails() override; - base::string16 GetSpoofingInterstitialFailure() override; - int GetUnsafePortTitleID() override; - int GetUnsafePortHeadlineID() override; - int GetUnsafePortMessageID() override; - int GetUnsafePortDetailsID() override; - base::string16 GetDoneString() override; - base::string16 GetOKString() override; - base::string16 GetProductName() override; }; } // namespace ios
diff --git a/ios/web/public/web_state/crw_web_view_scroll_view_proxy.h b/ios/web/public/web_state/crw_web_view_scroll_view_proxy.h index e95b24d..7b49f89c3 100644 --- a/ios/web/public/web_state/crw_web_view_scroll_view_proxy.h +++ b/ios/web/public/web_state/crw_web_view_scroll_view_proxy.h
@@ -25,6 +25,7 @@ @property(nonatomic, assign) CGPoint contentOffset; @property(nonatomic, assign) UIEdgeInsets contentInset; @property(nonatomic, readonly) BOOL isZooming; +@property(nonatomic, readonly) CGFloat zoomScale; @property(nonatomic, assign) UIEdgeInsets scrollIndicatorInsets; @property(nonatomic, assign) CGSize contentSize; @property(nonatomic, readonly) CGRect frame;
diff --git a/ios/web/web_state/crw_web_view_scroll_view_proxy.mm b/ios/web/web_state/crw_web_view_scroll_view_proxy.mm index dcd2971f..306a9ca 100644 --- a/ios/web/web_state/crw_web_view_scroll_view_proxy.mm +++ b/ios/web/web_state/crw_web_view_scroll_view_proxy.mm
@@ -99,6 +99,10 @@ return [_scrollView isZooming]; } +- (CGFloat)zoomScale { + return [_scrollView zoomScale]; +} + - (void)setContentOffset:(CGPoint)contentOffset { [_scrollView setContentOffset:contentOffset]; }
diff --git a/ios/web/web_state/ui/crw_ui_web_view_web_controller.mm b/ios/web/web_state/ui/crw_ui_web_view_web_controller.mm index 03549b24..c9e836d 100644 --- a/ios/web/web_state/ui/crw_ui_web_view_web_controller.mm +++ b/ios/web/web_state/ui/crw_ui_web_view_web_controller.mm
@@ -186,6 +186,9 @@ - (void)generateMissingLoadRequestWithURL:(const GURL&)currentURL referrer:(const web::Referrer&)referrer; +// Registers the current user agent with the web view. +- (void)registerUserAgent; + // Returns a child scripting CRWWebController with the given window name. - (id<CRWWebControllerScripting>)scriptingInterfaceForWindowNamed: (NSString*)name; @@ -432,6 +435,14 @@ } } +- (void)restoreStateAfterURLRejection { + // Re-register the user agent, because UIWebView will sometimes try to read + // the agent again from a saved search result page in which no other page has + // yet been loaded. See crbug.com/260370. + [self registerUserAgent]; + [super restoreStateAfterURLRejection]; +} + #pragma mark - #pragma mark Testing-Only Methods @@ -532,12 +543,6 @@ return url; } -- (void)registerUserAgent { - web::BuildAndRegisterUserAgentForUIWebView( - self.webStateImpl->GetRequestGroupID(), - [self useDesktopUserAgent]); -} - - (BOOL)isCurrentNavigationItemPOST { DCHECK([self currentSessionEntry]); NSData* currentPOSTData = @@ -633,6 +638,11 @@ - (void)loadRequestForCurrentNavigationItem { DCHECK(self.webView && !self.nativeController); + + // Re-register the user agent, because UIWebView sometimes loses it. + // See crbug.com/228397. + [self registerUserAgent]; + NSMutableURLRequest* request = [self requestForCurrentNavigationItem]; ProceduralBlock GETBlock = ^{ @@ -1401,6 +1411,11 @@ [self registerLoadRequest:currentURL referrer:referrer transition:transition]; } +- (void)registerUserAgent { + web::BuildAndRegisterUserAgentForUIWebView( + self.webStateImpl->GetRequestGroupID(), [self useDesktopUserAgent]); +} + - (id<CRWWebControllerScripting>)scriptingInterfaceForWindowNamed: (NSString*)name { if (![self.delegate respondsToSelector:
diff --git a/ios/web/web_state/ui/crw_web_controller+protected.h b/ios/web/web_state/ui/crw_web_controller+protected.h index 02a7638..7261210e4 100644 --- a/ios/web/web_state/ui/crw_web_controller+protected.h +++ b/ios/web/web_state/ui/crw_web_controller+protected.h
@@ -108,9 +108,6 @@ // based on the confidence in the verification. - (GURL)webURLWithTrustLevel:(web::URLVerificationTrustLevel*)trustLevel; -// Registers the current user agent with the web view. -- (void)registerUserAgent; - // Returns YES if the current navigation item corresponds to a web page // loaded by a POST request. - (BOOL)isCurrentNavigationItemPOST;
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm index 59aaca3..8351079 100644 --- a/ios/web/web_state/ui/crw_web_controller.mm +++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -1325,10 +1325,6 @@ - (void)loadCurrentURLInWebView { [self willLoadCurrentURLInWebView]; - // Re-register the user agent, because UIWebView sometimes loses it. - // See crbug.com/228397. - [self registerUserAgent]; - // Clear the set of URLs opened in external applications. _openedApplicationURL.reset([[NSMutableSet alloc] init]); @@ -1591,9 +1587,9 @@ if (!_overlayPreviewMode) _usePlaceholderOverlay = NO; } else if (_requireReloadOnDisplay && self.webView) { + _requireReloadOnDisplay = NO; [self addPlaceholderOverlay]; [self loadCurrentURL]; - _requireReloadOnDisplay = NO; } } @@ -2483,13 +2479,10 @@ pushURL = URLEscapedForHistory(pushURL); if (!pushURL.is_valid()) return YES; - const NavigationManagerImpl& navigationManager = - _webStateImpl->GetNavigationManagerImpl(); web::NavigationItem* navItem = [self currentNavItem]; - // PushState happened before first navigation entry or called right after - // window.open when the url is empty. - if (!navItem || - (navigationManager.GetItemCount() <= 1 && navItem->GetURL().is_empty())) + // PushState happened before first navigation entry or called when the + // navigation entry does not contain a valid URL. + if (!navItem || !navItem->GetURL().is_valid()) return YES; if (!web::history_state_util::IsHistoryStateChangeValid(navItem->GetURL(), pushURL)) { @@ -2836,11 +2829,6 @@ - (void)restoreStateAfterURLRejection { [[self sessionController] discardNonCommittedEntries]; - // Re-register the user agent, because UIWebView will sometimes try to read - // the agent again from a saved search result page in which no other page has - // yet been loaded. See crbug.com/260370. - [self registerUserAgent]; - // Reset |_lastRegisteredRequestURL| so that it reflects the URL from before // the load was rejected. This value may be out of sync because // |_lastRegisteredRequestURL| may have already been updated before the load
diff --git a/ios/web/web_state/ui/crw_wk_web_view_web_controller.mm b/ios/web/web_state/ui/crw_wk_web_view_web_controller.mm index 040f6139..7e2f7b8 100644 --- a/ios/web/web_state/ui/crw_wk_web_view_web_controller.mm +++ b/ios/web/web_state/ui/crw_wk_web_view_web_controller.mm
@@ -533,12 +533,6 @@ return _documentURL; } -// TODO(stuartmorgan): Remove this method and use the API for WKWebView, -// making the reset-on-each-load behavior specific to the UIWebView subclass. -- (void)registerUserAgent { - web::BuildAndRegisterUserAgentForUIWebView(nil, [self useDesktopUserAgent]); -} - - (BOOL)isCurrentNavigationItemPOST { // |_pendingNavigationInfo| will be nil if the decidePolicy* delegate methods // were not called. @@ -1616,8 +1610,9 @@ [self addActivityIndicatorTask]; } else { [self clearActivityIndicatorTasks]; - if ([self currentBackForwardListItemHolder]->navigation_type() == - WKNavigationTypeBackForward) { + if ([self currentNavItem] && + [self currentBackForwardListItemHolder]->navigation_type() == + WKNavigationTypeBackForward) { // A fast back/forward may not call |webView:didFinishNavigation:|, so // finishing the navigation should be signalled explicitly. [self didFinishNavigation];
diff --git a/ios/web/web_state/web_view_internal_creation_util.mm b/ios/web/web_state/web_view_internal_creation_util.mm index a9a69ce..cbf01d64 100644 --- a/ios/web/web_state/web_view_internal_creation_util.mm +++ b/ios/web/web_state/web_view_internal_creation_util.mm
@@ -9,6 +9,7 @@ #include "base/logging.h" #include "base/mac/scoped_nsobject.h" +#include "base/strings/sys_string_conversions.h" #import "ios/web/alloc_with_zone_interceptor.h" #include "ios/web/public/active_state_manager.h" #include "ios/web/public/browser_state.h" @@ -164,8 +165,11 @@ WKWebViewConfiguration* configuration, BrowserState* browser_state, BOOL use_desktop_user_agent) { - web::BuildAndRegisterUserAgentForUIWebView(nil, use_desktop_user_agent); - return CreateWKWebView(frame, configuration, browser_state); + WKWebView* web_view = CreateWKWebView(frame, configuration, browser_state); + DCHECK(web::GetWebClient()); + web_view.customUserAgent = base::SysUTF8ToNSString( + web::GetWebClient()->GetUserAgent(use_desktop_user_agent)); + return web_view; } WKWebView* CreateWKWebView(CGRect frame,
diff --git a/ipc/attachment_broker_mac_unittest.cc b/ipc/attachment_broker_mac_unittest.cc index be4f3c515..bf994b7 100644 --- a/ipc/attachment_broker_mac_unittest.cc +++ b/ipc/attachment_broker_mac_unittest.cc
@@ -76,8 +76,10 @@ IPC::internal::MachPortAttachmentMac* received_mach_port_attachment = static_cast<IPC::internal::MachPortAttachmentMac*>(attachment.get()); - return base::mac::ScopedMachSendRight( + base::mac::ScopedMachSendRight send_right( received_mach_port_attachment->get_mach_port()); + received_mach_port_attachment->reset_mach_port_ownership(); + return send_right; } // Makes a Mach port backed SharedMemory region and fills it with |contents|.
diff --git a/ipc/ipc_message_start.h b/ipc/ipc_message_start.h index 8ec7f3c..8197ac629 100644 --- a/ipc/ipc_message_start.h +++ b/ipc/ipc_message_start.h
@@ -79,7 +79,6 @@ WebSocketMsgStart, NaClHostMsgStart, WebRTCIdentityMsgStart, - LocalDiscoveryMsgStart, PowerMonitorMsgStart, EncryptedMediaMsgStart, CacheStorageMsgStart,
diff --git a/ipc/mach_port_attachment_mac.cc b/ipc/mach_port_attachment_mac.cc index 7a1d40b..65baa34 100644 --- a/ipc/mach_port_attachment_mac.cc +++ b/ipc/mach_port_attachment_mac.cc
@@ -24,13 +24,7 @@ MachPortAttachmentMac::MachPortAttachmentMac(const WireFormat& wire_format) : BrokerableAttachment(wire_format.attachment_id), mach_port_(static_cast<mach_port_t>(wire_format.mach_port)), - owns_mach_port_(false) {} - -MachPortAttachmentMac::MachPortAttachmentMac( - const BrokerableAttachment::AttachmentId& id) - : BrokerableAttachment(id), - mach_port_(MACH_PORT_NULL), - owns_mach_port_(false) {} + owns_mach_port_(true) {} MachPortAttachmentMac::~MachPortAttachmentMac() { if (mach_port_ != MACH_PORT_NULL && owns_mach_port_) {
diff --git a/ipc/mach_port_attachment_mac.h b/ipc/mach_port_attachment_mac.h index 7b2465c9..244014e 100644 --- a/ipc/mach_port_attachment_mac.h +++ b/ipc/mach_port_attachment_mac.h
@@ -51,10 +51,10 @@ // IPC message. explicit MachPortAttachmentMac(mach_port_t mach_port); - // These constructors do not take ownership of |mach_port|, and should only be - // called by the receiver of a Chrome IPC message. + // This constructor takes ownership of |wire_format.mach_port|, but does not + // modify its ref count. Should only be called by the receiver of a Chrome IPC + // message. explicit MachPortAttachmentMac(const WireFormat& wire_format); - explicit MachPortAttachmentMac(const BrokerableAttachment::AttachmentId& id); BrokerableType GetBrokerableType() const override; @@ -71,11 +71,10 @@ const mach_port_t mach_port_; // In the sender process, the attachment owns the Mach port of a newly created - // message. The attachment broker will eventually take ownership, and set - // this member to |false|. - // In the destination process, the attachment never owns the Mach port. The - // client code that receives the Chrome IPC message is always expected to take - // ownership. + // message. The attachment broker will eventually take ownership of + // |mach_port_|. + // In the destination process, the attachment owns |mach_port_| until + // ParamTraits<MachPortMac>::Read() is called, which takes ownership. bool owns_mach_port_; DISALLOW_COPY_AND_ASSIGN(MachPortAttachmentMac); };
diff --git a/ipc/mach_port_mac.cc b/ipc/mach_port_mac.cc index 96f4acae..51a5bd7 100644 --- a/ipc/mach_port_mac.cc +++ b/ipc/mach_port_mac.cc
@@ -37,6 +37,7 @@ IPC::internal::MachPortAttachmentMac* mach_port_attachment = static_cast<IPC::internal::MachPortAttachmentMac*>(brokerable_attachment); r->set_mach_port(mach_port_attachment->get_mach_port()); + mach_port_attachment->reset_mach_port_ownership(); return true; }
diff --git a/mash/BUILD.gn b/mash/BUILD.gn index 461ff4c..5b29b266 100644 --- a/mash/BUILD.gn +++ b/mash/BUILD.gn
@@ -11,6 +11,10 @@ deps = [ ":tests", "//mash/example", + "//mash/quick_launch", + "//mash/shell", + "//mash/task_viewer", + "//mash/wm", ] }
diff --git a/mash/example/BUILD.gn b/mash/example/BUILD.gn index fb226c21..a61ace5 100644 --- a/mash/example/BUILD.gn +++ b/mash/example/BUILD.gn
@@ -8,7 +8,6 @@ testonly = true deps = [ - "//mash/example/main", "//mash/example/views_examples", "//mash/example/window_type_launcher", "//mash/wm",
diff --git a/mash/example/main/BUILD.gn b/mash/example/main/BUILD.gn deleted file mode 100644 index bef2aef..0000000 --- a/mash/example/main/BUILD.gn +++ /dev/null
@@ -1,33 +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. - -import("//build/config/ui.gni") -import("//mojo/public/mojo_application.gni") -import("//mojo/public/tools/bindings/mojom.gni") -import("//tools/grit/repack.gni") - -mojo_native_application("main") { - output_name = "example_main" - testonly = true - - sources = [ - "main.cc", - "main_application_delegate.cc", - "main_application_delegate.h", - ] - - deps = [ - "//base", - "//mojo/application/public/cpp", - "//mojo/application/public/cpp:sources", - "//mojo/public/cpp/bindings", - ] - - data_deps = [ - "//mash/shell", - "//mash/task_viewer", - "//mash/example/views_examples", - "//mash/example/window_type_launcher", - ] -}
diff --git a/mash/example/main/main.cc b/mash/example/main/main.cc deleted file mode 100644 index 00d5743..0000000 --- a/mash/example/main/main.cc +++ /dev/null
@@ -1,12 +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 "mash/example/main/main_application_delegate.h" -#include "mojo/application/public/cpp/application_runner.h" -#include "mojo/public/c/system/main.h" - -MojoResult MojoMain(MojoHandle shell_handle) { - mojo::ApplicationRunner runner(new MainApplicationDelegate); - return runner.Run(shell_handle); -}
diff --git a/mash/example/main/main_application_delegate.cc b/mash/example/main/main_application_delegate.cc deleted file mode 100644 index d130adc..0000000 --- a/mash/example/main/main_application_delegate.cc +++ /dev/null
@@ -1,25 +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 "mash/example/main/main_application_delegate.h" - -#include "mojo/application/public/cpp/application_connection.h" -#include "mojo/application/public/cpp/application_impl.h" - -MainApplicationDelegate::MainApplicationDelegate() {} - -MainApplicationDelegate::~MainApplicationDelegate() {} - -void MainApplicationDelegate::Initialize(mojo::ApplicationImpl* app) { - connections_.push_back(app->ConnectToApplication("mojo:mash_shell")); - connections_.push_back(app->ConnectToApplication("mojo:views_examples")); - connections_.push_back( - app->ConnectToApplication("exe:window_type_launcher_exe")); - connections_.push_back(app->ConnectToApplication("mojo:task_viewer")); -} - -bool MainApplicationDelegate::ConfigureIncomingConnection( - mojo::ApplicationConnection* connection) { - return false; -}
diff --git a/mash/example/main/main_application_delegate.h b/mash/example/main/main_application_delegate.h deleted file mode 100644 index 9542d1c..0000000 --- a/mash/example/main/main_application_delegate.h +++ /dev/null
@@ -1,33 +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 MASH_EXAMPLE_MAIN_MAIN_APPLICATION_DELEGATE_H_ -#define MASH_EXAMPLE_MAIN_MAIN_APPLICATION_DELEGATE_H_ - -#include "base/macros.h" -#include "base/memory/scoped_vector.h" -#include "mojo/application/public/cpp/application_delegate.h" -#include "mojo/application/public/cpp/interface_factory_impl.h" - -namespace mojo { -class ApplicationConnection; -} - -class MainApplicationDelegate : public mojo::ApplicationDelegate { - public: - MainApplicationDelegate(); - ~MainApplicationDelegate() override; - - private: - // ApplicationDelegate: - void Initialize(mojo::ApplicationImpl* app) override; - bool ConfigureIncomingConnection( - mojo::ApplicationConnection* connection) override; - - ScopedVector<mojo::ApplicationConnection> connections_; - - DISALLOW_COPY_AND_ASSIGN(MainApplicationDelegate); -}; - -#endif // MASH_EXAMPLE_MAIN_MAIN_APPLICATION_DELEGATE_H_
diff --git a/mash/quick_launch/BUILD.gn b/mash/quick_launch/BUILD.gn new file mode 100644 index 0000000..17db5af6 --- /dev/null +++ b/mash/quick_launch/BUILD.gn
@@ -0,0 +1,32 @@ +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//build/config/ui.gni") +import("//mojo/public/mojo_application.gni") +import("//mojo/public/tools/bindings/mojom.gni") +import("//tools/grit/repack.gni") + +mojo_native_application("quick_launch") { + sources = [ + "quick_launch.cc", + ] + + deps = [ + "//base", + "//mojo/application/public/cpp", + "//mojo/application/public/cpp:sources", + "//mojo/application/public/interfaces", + "//mojo/public/cpp/bindings", + "//mojo/services/tracing/public/cpp", + "//ui/views", + "//ui/views/mus:for_mojo_application", + "//url", + ] + + resources = [ "$root_out_dir/views_mus_resources.pak" ] + + data_deps = [ + "//components/mus", + ] +}
diff --git a/mash/quick_launch/quick_launch.cc b/mash/quick_launch/quick_launch.cc new file mode 100644 index 0000000..8d2b0e84 --- /dev/null +++ b/mash/quick_launch/quick_launch.cc
@@ -0,0 +1,118 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/macros.h" +#include "base/strings/string_util.h" +#include "base/strings/utf_string_conversions.h" +#include "mojo/application/public/cpp/application_delegate.h" +#include "mojo/application/public/cpp/application_impl.h" +#include "mojo/application/public/cpp/application_runner.h" +#include "mojo/public/c/system/main.h" +#include "mojo/services/tracing/public/cpp/tracing_impl.h" +#include "ui/views/background.h" +#include "ui/views/controls/textfield/textfield.h" +#include "ui/views/controls/textfield/textfield_controller.h" +#include "ui/views/mus/aura_init.h" +#include "ui/views/mus/window_manager_connection.h" +#include "ui/views/widget/widget_delegate.h" +#include "url/gurl.h" + +namespace views { +class AuraInit; +} + +namespace mash { +namespace quick_launch { + +class QuickLaunchUI : public views::WidgetDelegateView, + public views::TextfieldController { + public: + QuickLaunchUI(mojo::ApplicationImpl* app) + : app_(app), + prompt_(new views::Textfield) { + set_background(views::Background::CreateStandardPanelBackground()); + prompt_->set_controller(this); + AddChildView(prompt_); + } + ~QuickLaunchUI() override {} + + private: + // Overridden from views::WidgetDelegate: + views::View* GetContentsView() override { return this; } + base::string16 GetWindowTitle() const override { + // TODO(beng): use resources. + return base::ASCIIToUTF16("QuickLaunch"); + } + + // Overridden from views::View: + void Layout() override { + gfx::Rect bounds = GetLocalBounds(); + bounds.Inset(5, 5); + prompt_->SetBoundsRect(bounds); + } + gfx::Size GetPreferredSize() const override { + gfx::Size ps = prompt_->GetPreferredSize(); + ps.Enlarge(500, 10); + return ps; + } + + // Overridden from views::TextFieldController: + bool HandleKeyEvent(views::Textfield* sender, + const ui::KeyEvent& key_event) override { + if (key_event.key_code() == ui::VKEY_RETURN) { + std::string url = Canonicalize(prompt_->text()); + connections_.push_back(app_->ConnectToApplication(url)); + prompt_->SetText(base::string16()); + } + return false; + } + + std::string Canonicalize(const base::string16& input) const { + base::string16 working; + base::TrimWhitespace(input, base::TRIM_ALL, &working); + GURL url(working); + if (url.scheme() != "mojo" && url.scheme() != "exe") + working = base::ASCIIToUTF16("mojo:") + working; + return base::UTF16ToUTF8(working); + } + + mojo::ApplicationImpl* app_; + views::Textfield* prompt_; + std::vector<scoped_ptr<mojo::ApplicationConnection>> connections_; + + DISALLOW_COPY_AND_ASSIGN(QuickLaunchUI); +}; + +class QuickLaunchApplicationDelegate : public mojo::ApplicationDelegate { + public: + QuickLaunchApplicationDelegate() {} + ~QuickLaunchApplicationDelegate() override {} + + private: + // mojo::ApplicationDelegate: + void Initialize(mojo::ApplicationImpl* app) override { + tracing_.Initialize(app); + + aura_init_.reset(new views::AuraInit(app, "views_mus_resources.pak")); + views::WindowManagerConnection::Create(app); + + views::Widget* window = views::Widget::CreateWindowWithBounds( + new QuickLaunchUI(app), gfx::Rect(10, 640, 0, 0)); + window->Show(); + } + + mojo::TracingImpl tracing_; + scoped_ptr<views::AuraInit> aura_init_; + + DISALLOW_COPY_AND_ASSIGN(QuickLaunchApplicationDelegate); +}; + +} // namespace quick_launch +} // namespace mash + +MojoResult MojoMain(MojoHandle shell_handle) { + mojo::ApplicationRunner runner( + new mash::quick_launch::QuickLaunchApplicationDelegate); + return runner.Run(shell_handle); +}
diff --git a/mash/shell/shell_application_delegate.cc b/mash/shell/shell_application_delegate.cc index a958446..b370835 100644 --- a/mash/shell/shell_application_delegate.cc +++ b/mash/shell/shell_application_delegate.cc
@@ -20,6 +20,7 @@ StartBrowserDriver(); StartWindowManager(); StartSystemUI(); + StartQuickLaunch(); } bool ShellApplicationDelegate::ConfigureIncomingConnection( @@ -47,6 +48,13 @@ base::Unretained(this))); } +void ShellApplicationDelegate::StartQuickLaunch() { + StartRestartableService( + "mojo:quick_launch", + base::Bind(&ShellApplicationDelegate::StartQuickLaunch, + base::Unretained(this))); +} + void ShellApplicationDelegate::StartRestartableService( const std::string& url, const base::Closure& restart_callback) {
diff --git a/mash/shell/shell_application_delegate.h b/mash/shell/shell_application_delegate.h index 3bec26c..e93afd7 100644 --- a/mash/shell/shell_application_delegate.h +++ b/mash/shell/shell_application_delegate.h
@@ -33,6 +33,7 @@ void StartWindowManager(); void StartSystemUI(); void StartBrowserDriver(); + void StartQuickLaunch(); // Starts the application at |url|, running |restart_callback| if the // connection to the application is closed.
diff --git a/mash/task_viewer/task_viewer_application_delegate.cc b/mash/task_viewer/task_viewer_application_delegate.cc index 244a9bc7..ca19cc6 100644 --- a/mash/task_viewer/task_viewer_application_delegate.cc +++ b/mash/task_viewer/task_viewer_application_delegate.cc
@@ -59,15 +59,18 @@ kill_button_->SetStyle(views::Button::STYLE_BUTTON); AddChildView(kill_button_); } - ~TaskViewer() override {} + ~TaskViewer() override { + table_view_->SetModel(nullptr); + } private: - struct ProcessInfo { + struct ApplicationInfo { + int id; std::string url; uint32_t pid; - ProcessInfo(const std::string url, base::ProcessId pid) - : url(url), pid(pid) {} + ApplicationInfo(int id, const std::string url, base::ProcessId pid) + : id(id), url(url), pid(pid) {} }; // Overridden from views::WidgetDelegate: @@ -93,16 +96,16 @@ // Overridden from ui::TableModel: int RowCount() override { - return static_cast<int>(processes_.size()); + return static_cast<int>(applications_.size()); } base::string16 GetText(int row, int column_id) override { switch(column_id) { case 0: - DCHECK(row < static_cast<int>(processes_.size())); - return base::UTF8ToUTF16(processes_[row]->url); + DCHECK(row < static_cast<int>(applications_.size())); + return base::UTF8ToUTF16(applications_[row]->url); case 1: - DCHECK(row < static_cast<int>(processes_.size())); - return base::IntToString16(processes_[row]->pid); + DCHECK(row < static_cast<int>(applications_.size())); + return base::IntToString16(applications_[row]->pid); default: NOTREACHED(); break; @@ -118,8 +121,8 @@ DCHECK_EQ(sender, kill_button_); DCHECK_EQ(table_view_->SelectedRowCount(), 1); int row = table_view_->FirstSelectedRow(); - DCHECK(row < static_cast<int>(processes_.size())); - base::Process process = base::Process::Open(processes_[row]->pid); + DCHECK(row < static_cast<int>(applications_.size())); + base::Process process = base::Process::Open(applications_[row]->pid); process.Terminate(9, true); } @@ -127,43 +130,46 @@ void SetRunningApplications( mojo::Array<ApplicationInfoPtr> applications) override { // This callback should only be called with an empty model. - DCHECK(processes_.empty()); + DCHECK(applications_.empty()); for (size_t i = 0; i < applications.size(); ++i) { - processes_.push_back( - make_scoped_ptr(new ProcessInfo(applications[i]->url, - applications[i]->pid))); + applications_.push_back( + make_scoped_ptr(new ApplicationInfo(applications[i]->id, + applications[i]->url, + applications[i]->pid))); } } - void ApplicationStarted(ApplicationInfoPtr application) override { - DCHECK(!ContainsURL(application->url)); - // TODO(beng): eventually nothing should be returning invalid process ids. - if (application->pid != base::kNullProcessId) - DCHECK(!ContainsPid(application->pid)); - processes_.push_back( - make_scoped_ptr(new ProcessInfo(application->url, application->pid))); - observer_->OnItemsAdded(static_cast<int>(processes_.size()), 1); + void ApplicationInstanceCreated(ApplicationInfoPtr application) override { + DCHECK(!ContainsId(application->id)); + applications_.push_back(make_scoped_ptr( + new ApplicationInfo(application->id, application->url, + application->pid))); + observer_->OnItemsAdded(static_cast<int>(applications_.size()), 1); } - void ApplicationEnded(uint32_t pid) override { - for (auto it = processes_.begin(); it != processes_.end(); ++it) { - if ((*it)->pid == pid) { - observer_->OnItemsRemoved(static_cast<int>(it - processes_.begin()), 1); - processes_.erase(it); + void ApplicationInstanceDestroyed(int32_t id) override { + for (auto it = applications_.begin(); it != applications_.end(); ++it) { + if ((*it)->id == id) { + observer_->OnItemsRemoved( + static_cast<int>(it - applications_.begin()), 1); + applications_.erase(it); return; } } NOTREACHED(); } - - bool ContainsURL(const std::string& url) const { - for (auto& it : processes_) { - if (it->url == url) - return true; + void ApplicationPIDAvailable(int id, uint32_t pid) override { + for (auto it = applications_.begin(); it != applications_.end(); ++it) { + if ((*it)->id == id) { + (*it)->pid = pid; + observer_->OnItemsChanged( + static_cast<int>(it - applications_.begin()), 1); + return; + } } - return false; } - bool ContainsPid(uint32_t pid) const { - for (auto& it : processes_) { - if (it->pid == pid) + + bool ContainsId(int id) const { + for (auto& it : applications_) { + if (it->id == id) return true; } return false; @@ -199,7 +205,7 @@ views::LabelButton* kill_button_; ui::TableModelObserver* observer_; - std::vector<scoped_ptr<ProcessInfo>> processes_; + std::vector<scoped_ptr<ApplicationInfo>> applications_; DISALLOW_COPY_AND_ASSIGN(TaskViewer); };
diff --git a/mash/wm/window_manager_apptest.cc b/mash/wm/window_manager_apptest.cc index ddb9566..8f9b0f0 100644 --- a/mash/wm/window_manager_apptest.cc +++ b/mash/wm/window_manager_apptest.cc
@@ -40,7 +40,7 @@ mus::WindowTreeConnection* connection = mus::WindowTreeConnection::Create( this, std::move(window_tree_client_request), mus::WindowTreeConnection::CreateType::WAIT_FOR_EMBED); - return connection->GetRoot(); + return *connection->GetRoots().begin(); } private:
diff --git a/media/BUILD.gn b/media/BUILD.gn index b0bf9d6..7d03d4d 100644 --- a/media/BUILD.gn +++ b/media/BUILD.gn
@@ -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/buildflag_header.gni") import("//build/config/android/config.gni") import("//build/config/arm.gni") import("//build/config/features.gni") @@ -10,6 +11,13 @@ import("//media/media_options.gni") import("//testing/test.gni") +buildflag_header("media_features") { + header = "media_features.h" + + flags = + [ "ENABLE_MSE_MPEG2TS_STREAM_PARSER=$enable_mse_mpeg2ts_stream_parser" ] +} + # Common configuration for targets in the media directory. # NOT for exporting. config("media_config") { @@ -479,32 +487,6 @@ "cdm/cenc_utils.h", "filters/h264_to_annex_b_bitstream_converter.cc", "filters/h264_to_annex_b_bitstream_converter.h", - "formats/mp2t/es_adapter_video.cc", - "formats/mp2t/es_adapter_video.h", - "formats/mp2t/es_parser.cc", - "formats/mp2t/es_parser.h", - "formats/mp2t/es_parser_adts.cc", - "formats/mp2t/es_parser_adts.h", - "formats/mp2t/es_parser_h264.cc", - "formats/mp2t/es_parser_h264.h", - "formats/mp2t/es_parser_mpeg1audio.cc", - "formats/mp2t/es_parser_mpeg1audio.h", - "formats/mp2t/mp2t_common.h", - "formats/mp2t/mp2t_stream_parser.cc", - "formats/mp2t/mp2t_stream_parser.h", - "formats/mp2t/timestamp_unroller.cc", - "formats/mp2t/timestamp_unroller.h", - "formats/mp2t/ts_packet.cc", - "formats/mp2t/ts_packet.h", - "formats/mp2t/ts_section.h", - "formats/mp2t/ts_section_pat.cc", - "formats/mp2t/ts_section_pat.h", - "formats/mp2t/ts_section_pes.cc", - "formats/mp2t/ts_section_pes.h", - "formats/mp2t/ts_section_pmt.cc", - "formats/mp2t/ts_section_pmt.h", - "formats/mp2t/ts_section_psi.cc", - "formats/mp2t/ts_section_psi.h", "formats/mp4/aac.cc", "formats/mp4/aac.h", "formats/mp4/avc.cc", @@ -534,6 +516,36 @@ "formats/mpeg/mpeg_audio_stream_parser_base.cc", "formats/mpeg/mpeg_audio_stream_parser_base.h", ] + if (enable_mse_mpeg2ts_stream_parser) { + sources += [ + "formats/mp2t/es_adapter_video.cc", + "formats/mp2t/es_adapter_video.h", + "formats/mp2t/es_parser.cc", + "formats/mp2t/es_parser.h", + "formats/mp2t/es_parser_adts.cc", + "formats/mp2t/es_parser_adts.h", + "formats/mp2t/es_parser_h264.cc", + "formats/mp2t/es_parser_h264.h", + "formats/mp2t/es_parser_mpeg1audio.cc", + "formats/mp2t/es_parser_mpeg1audio.h", + "formats/mp2t/mp2t_common.h", + "formats/mp2t/mp2t_stream_parser.cc", + "formats/mp2t/mp2t_stream_parser.h", + "formats/mp2t/timestamp_unroller.cc", + "formats/mp2t/timestamp_unroller.h", + "formats/mp2t/ts_packet.cc", + "formats/mp2t/ts_packet.h", + "formats/mp2t/ts_section.h", + "formats/mp2t/ts_section_pat.cc", + "formats/mp2t/ts_section_pat.h", + "formats/mp2t/ts_section_pes.cc", + "formats/mp2t/ts_section_pes.h", + "formats/mp2t/ts_section_pmt.cc", + "formats/mp2t/ts_section_pmt.h", + "formats/mp2t/ts_section_psi.cc", + "formats/mp2t/ts_section_psi.h", + ] + } } if (use_low_memory_buffer) { @@ -549,13 +561,14 @@ } public_deps = [ + ":media_features", + ":shared_memory_support", "//media/audio", "//media/base", "//third_party/opus", ] deps += [ - ":shared_memory_support", "//base", "//base:i18n", "//base/third_party/dynamic_annotations", @@ -745,14 +758,6 @@ "filters/h264_to_annex_b_bitstream_converter_unittest.cc", "formats/common/stream_parser_test_base.cc", "formats/common/stream_parser_test_base.h", - "formats/mp2t/es_adapter_video_unittest.cc", - "formats/mp2t/es_parser_adts_unittest.cc", - "formats/mp2t/es_parser_h264_unittest.cc", - "formats/mp2t/es_parser_mpeg1audio_unittest.cc", - "formats/mp2t/es_parser_test_base.cc", - "formats/mp2t/es_parser_test_base.h", - "formats/mp2t/mp2t_stream_parser_unittest.cc", - "formats/mp2t/timestamp_unroller_unittest.cc", "formats/mp4/aac_unittest.cc", "formats/mp4/avc_unittest.cc", "formats/mp4/box_reader_unittest.cc", @@ -763,6 +768,18 @@ "formats/mpeg/adts_stream_parser_unittest.cc", "formats/mpeg/mpeg1_audio_stream_parser_unittest.cc", ] + if (enable_mse_mpeg2ts_stream_parser) { + sources += [ + "formats/mp2t/es_adapter_video_unittest.cc", + "formats/mp2t/es_parser_adts_unittest.cc", + "formats/mp2t/es_parser_h264_unittest.cc", + "formats/mp2t/es_parser_mpeg1audio_unittest.cc", + "formats/mp2t/es_parser_test_base.cc", + "formats/mp2t/es_parser_test_base.h", + "formats/mp2t/mp2t_stream_parser_unittest.cc", + "formats/mp2t/timestamp_unroller_unittest.cc", + ] + } if (media_use_ffmpeg) { sources += [ "filters/ffmpeg_aac_bitstream_converter_unittest.cc",
diff --git a/media/audio/alsa/alsa_wrapper.cc b/media/audio/alsa/alsa_wrapper.cc index 16fe9ea..5719ebe 100644 --- a/media/audio/alsa/alsa_wrapper.cc +++ b/media/audio/alsa/alsa_wrapper.cc
@@ -172,4 +172,91 @@ return snd_mixer_selem_get_capture_volume_range(elem, min, max); } +void* AlsaWrapper::MixerElemGetCallbackPrivate(const snd_mixer_elem_t* obj) { + return snd_mixer_elem_get_callback_private(obj); +} + +void AlsaWrapper::MixerElemSetCallback(snd_mixer_elem_t* obj, + snd_mixer_elem_callback_t val) { + snd_mixer_elem_set_callback(obj, val); +} + +void AlsaWrapper::MixerElemSetCallbackPrivate(snd_mixer_elem_t* obj, + void* val) { + snd_mixer_elem_set_callback_private(obj, val); +} + +snd_mixer_elem_t* AlsaWrapper::MixerFindSelem(snd_mixer_t* mixer, + const snd_mixer_selem_id_t* id) { + return snd_mixer_find_selem(mixer, id); +} + +int AlsaWrapper::MixerHandleEvents(snd_mixer_t* mixer) { + return snd_mixer_handle_events(mixer); +} + +int AlsaWrapper::MixerPollDescriptors(snd_mixer_t* mixer, + struct pollfd* pfds, + unsigned int space) { + return snd_mixer_poll_descriptors(mixer, pfds, space); +} + +int AlsaWrapper::MixerPollDescriptorsCount(snd_mixer_t* mixer) { + return snd_mixer_poll_descriptors_count(mixer); +} + +int AlsaWrapper::MixerSelemGetPlaybackSwitch( + snd_mixer_elem_t* elem, + snd_mixer_selem_channel_id_t channel, + int* value) { + return snd_mixer_selem_get_playback_switch(elem, channel, value); +} + +int AlsaWrapper::MixerSelemGetPlaybackVolume( + snd_mixer_elem_t* elem, + snd_mixer_selem_channel_id_t channel, + long* value) { + return snd_mixer_selem_get_playback_volume(elem, channel, value); +} + +int AlsaWrapper::MixerSelemGetPlaybackVolumeRange(snd_mixer_elem_t* elem, + long* min, + long* max) { + return snd_mixer_selem_get_playback_volume_range(elem, min, max); +} + +int AlsaWrapper::MixerSelemHasPlaybackSwitch(snd_mixer_elem_t* elem) { + return snd_mixer_selem_has_playback_switch(elem); +} + +void AlsaWrapper::MixerSelemIdSetIndex(snd_mixer_selem_id_t* obj, + unsigned int val) { + snd_mixer_selem_id_set_index(obj, val); +} + +void AlsaWrapper::MixerSelemIdSetName(snd_mixer_selem_id_t* obj, + const char* val) { + snd_mixer_selem_id_set_name(obj, val); +} + +int AlsaWrapper::MixerSelemSetPlaybackSwitch( + snd_mixer_elem_t* elem, + snd_mixer_selem_channel_id_t channel, + int value) { + return snd_mixer_selem_set_playback_switch(elem, channel, value); +} + +int AlsaWrapper::MixerSelemSetPlaybackVolumeAll(snd_mixer_elem_t* elem, + long value) { + return snd_mixer_selem_set_playback_volume_all(elem, value); +} + +int AlsaWrapper::MixerSelemIdMalloc(snd_mixer_selem_id_t** ptr) { + return snd_mixer_selem_id_malloc(ptr); +} + +void AlsaWrapper::MixerSelemIdFree(snd_mixer_selem_id_t* obj) { + snd_mixer_selem_id_free(obj); +} + } // namespace media
diff --git a/media/audio/alsa/alsa_wrapper.h b/media/audio/alsa/alsa_wrapper.h index 9539bf1..bd70f537 100644 --- a/media/audio/alsa/alsa_wrapper.h +++ b/media/audio/alsa/alsa_wrapper.h
@@ -71,14 +71,49 @@ virtual int MixerSelemHasCaptureVolume(snd_mixer_elem_t* elem); virtual int MixerSelemGetCaptureVolumeRange(snd_mixer_elem_t* elem, long* min, long* max); + virtual void* MixerElemGetCallbackPrivate(const snd_mixer_elem_t* obj); + virtual void MixerElemSetCallback(snd_mixer_elem_t* obj, + snd_mixer_elem_callback_t val); + virtual void MixerElemSetCallbackPrivate(snd_mixer_elem_t* obj, void* val); + virtual snd_mixer_elem_t* MixerFindSelem(snd_mixer_t* mixer, + const snd_mixer_selem_id_t* id); + virtual int MixerHandleEvents(snd_mixer_t* mixer); + virtual int MixerPollDescriptors(snd_mixer_t* mixer, + struct pollfd* pfds, + unsigned int space); + virtual int MixerPollDescriptorsCount(snd_mixer_t* mixer); + virtual int MixerSelemGetPlaybackSwitch(snd_mixer_elem_t* elem, + snd_mixer_selem_channel_id_t channel, + int* value); + virtual int MixerSelemGetPlaybackVolume(snd_mixer_elem_t* elem, + snd_mixer_selem_channel_id_t channel, + long* value); + virtual int MixerSelemGetPlaybackVolumeRange(snd_mixer_elem_t* elem, + long* min, + long* max); + virtual int MixerSelemHasPlaybackSwitch(snd_mixer_elem_t* elem); + virtual void MixerSelemIdSetIndex(snd_mixer_selem_id_t* obj, + unsigned int val); + virtual void MixerSelemIdSetName(snd_mixer_selem_id_t* obj, const char* val); + virtual int MixerSelemSetPlaybackSwitch(snd_mixer_elem_t* elem, + snd_mixer_selem_channel_id_t channel, + int value); + virtual int MixerSelemSetPlaybackVolumeAll(snd_mixer_elem_t* elem, + long value); + virtual int MixerSelemIdMalloc(snd_mixer_selem_id_t** ptr); + virtual void MixerSelemIdFree(snd_mixer_selem_id_t* obj); virtual const char* StrError(int errnum); private: - int ConfigureHwParams(snd_pcm_t* handle, snd_pcm_hw_params_t* hw_params, - snd_pcm_format_t format, snd_pcm_access_t access, - unsigned int channels, unsigned int rate, - int soft_resample, unsigned int latency); + int ConfigureHwParams(snd_pcm_t* handle, + snd_pcm_hw_params_t* hw_params, + snd_pcm_format_t format, + snd_pcm_access_t access, + unsigned int channels, + unsigned int rate, + int soft_resample, + unsigned int latency); DISALLOW_COPY_AND_ASSIGN(AlsaWrapper); };
diff --git a/media/audio/audio_manager.h b/media/audio/audio_manager.h index 0a61dfe..d3eea4a 100644 --- a/media/audio/audio_manager.h +++ b/media/audio/audio_manager.h
@@ -62,6 +62,10 @@ static AudioManager* CreateForTesting(); // Enables non-crash dumps when audio thread hangs are detected. + // TODO(dalecurtis): There are no callers to this function at present. A list + // of bad drivers has been given to Microsoft. This should be re-enabled in + // the future if Microsoft is able to triage third party drivers. + // See http://crbug.com/422522 static void EnableCrashKeyLoggingForAudioThreadHangs(); #if defined(OS_LINUX)
diff --git a/media/audio/sample_rates.cc b/media/audio/sample_rates.cc index 3757f831..9853ef3 100644 --- a/media/audio/sample_rates.cc +++ b/media/audio/sample_rates.cc
@@ -17,6 +17,9 @@ case 16000: *asr = k16000Hz; return true; + case 24000: + *asr = k24000Hz; + return true; case 32000: *asr = k32000Hz; return true; @@ -44,8 +47,8 @@ case 192000: *asr = k192000Hz; return true; - case 24000: - *asr = k24000Hz; + case 384000: + *asr = k384000Hz; return true; } return false;
diff --git a/media/audio/sample_rates.h b/media/audio/sample_rates.h index d2834e7..fdc37c2 100644 --- a/media/audio/sample_rates.h +++ b/media/audio/sample_rates.h
@@ -24,8 +24,9 @@ k176400Hz = 9, k192000Hz = 10, k24000Hz = 11, + k384000Hz = 12, // Must always equal the largest value ever reported: - kAudioSampleRateMax = k24000Hz, + kAudioSampleRateMax = k384000Hz, }; // Helper method to convert integral values to their respective enum values,
diff --git a/media/base/android/BUILD.gn b/media/base/android/BUILD.gn index 75c6717c..54d8074 100644 --- a/media/base/android/BUILD.gn +++ b/media/base/android/BUILD.gn
@@ -64,9 +64,6 @@ "sdk_media_codec_bridge.h", "video_decoder_job.cc", "video_decoder_job.h", - "webaudio_media_codec_bridge.cc", - "webaudio_media_codec_bridge.h", - "webaudio_media_codec_info.h", ] configs += [ "//media:media_config", @@ -114,7 +111,6 @@ "java/src/org/chromium/media/MediaDrmBridge.java", "java/src/org/chromium/media/MediaPlayerBridge.java", "java/src/org/chromium/media/MediaPlayerListener.java", - "java/src/org/chromium/media/WebAudioMediaCodecBridge.java", ] jni_package = "media" }
diff --git a/media/base/android/java/src/org/chromium/media/WebAudioMediaCodecBridge.java b/media/base/android/java/src/org/chromium/media/WebAudioMediaCodecBridge.java deleted file mode 100644 index abc394c..0000000 --- a/media/base/android/java/src/org/chromium/media/WebAudioMediaCodecBridge.java +++ /dev/null
@@ -1,293 +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.media; - -import android.content.Context; -import android.media.MediaCodec; -import android.media.MediaCodec.BufferInfo; -import android.media.MediaExtractor; -import android.media.MediaFormat; -import android.os.ParcelFileDescriptor; - -import org.chromium.base.Log; -import org.chromium.base.annotations.CalledByNative; -import org.chromium.base.annotations.JNINamespace; - -import java.io.File; -import java.nio.ByteBuffer; - -@JNINamespace("media") -class WebAudioMediaCodecBridge { - private static final String TAG = "cr.media"; - // TODO(rtoy): What is the correct timeout value for reading - // from a file in memory? - static final long TIMEOUT_MICROSECONDS = 500; - @CalledByNative - private static String createTempFile(Context ctx) throws java.io.IOException { - File outputDirectory = ctx.getCacheDir(); - File outputFile = File.createTempFile("webaudio", ".dat", outputDirectory); - return outputFile.getAbsolutePath(); - } - - @SuppressWarnings("deprecation") - @CalledByNative - private static boolean decodeAudioFile(Context ctx, long nativeMediaCodecBridge, - int inputFD, long dataSize) { - - if (dataSize < 0 || dataSize > 0x7fffffff) return false; - - MediaExtractor extractor = new MediaExtractor(); - - ParcelFileDescriptor encodedFD; - encodedFD = ParcelFileDescriptor.adoptFd(inputFD); - try { - extractor.setDataSource(encodedFD.getFileDescriptor(), 0, dataSize); - } catch (Exception e) { - e.printStackTrace(); - encodedFD.detachFd(); - return false; - } - - if (extractor.getTrackCount() <= 0) { - encodedFD.detachFd(); - return false; - } - - MediaFormat format = extractor.getTrackFormat(0); - - // If we are unable to get the input channel count, the sample - // rate or the mime type for any reason, just give up. - // Without these, we don't know what to do. - - int inputChannelCount; - try { - // Number of channels specified in the file - inputChannelCount = format.getInteger(MediaFormat.KEY_CHANNEL_COUNT); - } catch (Exception e) { - // Give up. - Log.w(TAG, "Unable to determine number of channels"); - encodedFD.detachFd(); - return false; - } - - // Number of channels the decoder will provide. (Not - // necessarily the same as inputChannelCount. See - // crbug.com/266006.) - int outputChannelCount = inputChannelCount; - - int sampleRate; - try { - sampleRate = format.getInteger(MediaFormat.KEY_SAMPLE_RATE); - } catch (Exception e) { - // Give up. - Log.w(TAG, "Unable to determine sample rate"); - encodedFD.detachFd(); - return false; - } - - String mime; - try { - mime = format.getString(MediaFormat.KEY_MIME); - } catch (Exception e) { - // Give up. - Log.w(TAG, "Unable to determine type of encoding used by the file"); - encodedFD.detachFd(); - return false; - } - - long durationMicroseconds = 0; - if (format.containsKey(MediaFormat.KEY_DURATION)) { - try { - durationMicroseconds = format.getLong(MediaFormat.KEY_DURATION); - } catch (Exception e) { - Log.d(TAG, "Cannot get duration"); - } - } - - // If the duration is too long, set to 0 to force the caller - // not to preallocate space. See crbug.com/326856. - // FIXME: What should be the limit? We're arbitrarily using - // about 2148 sec (35.8 min). - if (durationMicroseconds > 0x7fffffff) { - durationMicroseconds = 0; - } - - Log.d(TAG, "Initial: Tracks: %d Format: %s", extractor.getTrackCount(), format); - - // Create decoder - MediaCodec codec; - try { - codec = MediaCodec.createDecoderByType(mime); - } catch (Exception e) { - Log.w(TAG, "Failed to create MediaCodec for mime type: %s", mime); - encodedFD.detachFd(); - return false; - } - - try { - codec.configure(format, null /* surface */, null /* crypto */, 0 /* flags */); - } catch (Exception e) { - Log.w(TAG, "Unable to configure codec for format " + format, e); - encodedFD.detachFd(); - return false; - } - try { - codec.start(); - } catch (Exception e) { - Log.w(TAG, "Unable to start()", e); - encodedFD.detachFd(); - return false; - } - - ByteBuffer[] codecInputBuffers; - try { - codecInputBuffers = codec.getInputBuffers(); - } catch (Exception e) { - Log.w(TAG, "getInputBuffers() failed", e); - encodedFD.detachFd(); - return false; - } - ByteBuffer[] codecOutputBuffers; - try { - codecOutputBuffers = codec.getOutputBuffers(); - } catch (Exception e) { - Log.w(TAG, "getOutputBuffers() failed", e); - encodedFD.detachFd(); - return false; - } - - // A track must be selected and will be used to read samples. - extractor.selectTrack(0); - - boolean sawInputEOS = false; - boolean sawOutputEOS = false; - boolean destinationInitialized = false; - boolean decodedSuccessfully = true; - - // Keep processing until the output is done. - while (!sawOutputEOS) { - if (!sawInputEOS) { - // Input side - int inputBufIndex; - try { - inputBufIndex = codec.dequeueInputBuffer(TIMEOUT_MICROSECONDS); - } catch (Exception e) { - Log.w(TAG, "dequeueInputBuffer(%d) failed.", TIMEOUT_MICROSECONDS, e); - decodedSuccessfully = false; - break; - } - - if (inputBufIndex >= 0) { - ByteBuffer dstBuf = codecInputBuffers[inputBufIndex]; - int sampleSize; - - try { - sampleSize = extractor.readSampleData(dstBuf, 0); - } catch (Exception e) { - Log.w(TAG, "readSampleData failed."); - decodedSuccessfully = false; - break; - } - - long presentationTimeMicroSec = 0; - - if (sampleSize < 0) { - sawInputEOS = true; - sampleSize = 0; - } else { - presentationTimeMicroSec = extractor.getSampleTime(); - } - - try { - codec.queueInputBuffer(inputBufIndex, - 0, /* offset */ - sampleSize, - presentationTimeMicroSec, - sawInputEOS ? MediaCodec.BUFFER_FLAG_END_OF_STREAM : 0); - } catch (Exception e) { - Log.w(TAG, "queueInputBuffer(%d, 0, %d, %d, %d) failed.", - inputBufIndex, sampleSize, presentationTimeMicroSec, - (sawInputEOS ? MediaCodec.BUFFER_FLAG_END_OF_STREAM : 0), e); - decodedSuccessfully = false; - break; - } - - if (!sawInputEOS) { - extractor.advance(); - } - } - } - - // Output side - MediaCodec.BufferInfo info = new BufferInfo(); - final int outputBufIndex; - - try { - outputBufIndex = codec.dequeueOutputBuffer(info, TIMEOUT_MICROSECONDS); - } catch (Exception e) { - Log.w(TAG, "dequeueOutputBuffer(%s, %d) failed", info, TIMEOUT_MICROSECONDS); - e.printStackTrace(); - decodedSuccessfully = false; - break; - } - - if (outputBufIndex >= 0) { - ByteBuffer buf = codecOutputBuffers[outputBufIndex]; - - if (!destinationInitialized) { - // Initialize the destination as late as possible to - // catch any changes in format. But be sure to - // initialize it BEFORE we send any decoded audio, - // and only initialize once. - Log.d(TAG, "Final: Rate: %d Channels: %d Mime: %s Duration: %d microsec", - sampleRate, inputChannelCount, mime, durationMicroseconds); - - nativeInitializeDestination(nativeMediaCodecBridge, - inputChannelCount, - sampleRate, - durationMicroseconds); - destinationInitialized = true; - } - - if (destinationInitialized && info.size > 0) { - nativeOnChunkDecoded(nativeMediaCodecBridge, buf, info.size, - inputChannelCount, outputChannelCount); - } - - buf.clear(); - codec.releaseOutputBuffer(outputBufIndex, false /* render */); - - if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) { - sawOutputEOS = true; - } - } else if (outputBufIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) { - codecOutputBuffers = codec.getOutputBuffers(); - } else if (outputBufIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { - MediaFormat newFormat = codec.getOutputFormat(); - outputChannelCount = newFormat.getInteger(MediaFormat.KEY_CHANNEL_COUNT); - sampleRate = newFormat.getInteger(MediaFormat.KEY_SAMPLE_RATE); - Log.d(TAG, "output format changed to " + newFormat); - } - } - - encodedFD.detachFd(); - - codec.stop(); - codec.release(); - codec = null; - - return decodedSuccessfully; - } - - private static native void nativeOnChunkDecoded( - long nativeWebAudioMediaCodecBridge, ByteBuffer buf, int size, - int inputChannelCount, int outputChannelCount); - - private static native void nativeInitializeDestination( - long nativeWebAudioMediaCodecBridge, - int inputChannelCount, - int sampleRate, - long durationMicroseconds); -}
diff --git a/media/base/android/media_jni_registrar.cc b/media/base/android/media_jni_registrar.cc index 375748e8..e230784 100644 --- a/media/base/android/media_jni_registrar.cc +++ b/media/base/android/media_jni_registrar.cc
@@ -15,7 +15,6 @@ #include "media/base/android/media_player_bridge.h" #include "media/base/android/media_player_listener.h" #include "media/base/android/sdk_media_codec_bridge.h" -#include "media/base/android/webaudio_media_codec_bridge.h" #include "media/capture/video/android/video_capture_device_android.h" #include "media/capture/video/android/video_capture_device_factory_android.h" @@ -33,8 +32,6 @@ VideoCaptureDeviceAndroid::RegisterVideoCaptureDevice}, {"VideoCaptureDeviceFactory", VideoCaptureDeviceFactoryAndroid::RegisterVideoCaptureDeviceFactory}, - {"WebAudioMediaCodecBridge", - WebAudioMediaCodecBridge::RegisterWebAudioMediaCodecBridge}, }; bool RegisterJni(JNIEnv* env) {
diff --git a/media/base/android/webaudio_media_codec_bridge.cc b/media/base/android/webaudio_media_codec_bridge.cc deleted file mode 100644 index c38ba75..0000000 --- a/media/base/android/webaudio_media_codec_bridge.cc +++ /dev/null
@@ -1,202 +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 "media/base/android/webaudio_media_codec_bridge.h" - -#include <errno.h> -#include <fcntl.h> -#include <stddef.h> -#include <string.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <unistd.h> -#include <vector> - -#include "base/android/context_utils.h" -#include "base/android/jni_android.h" -#include "base/android/jni_array.h" -#include "base/android/jni_string.h" -#include "base/files/scoped_file.h" -#include "base/logging.h" -#include "base/posix/eintr_wrapper.h" -#include "jni/WebAudioMediaCodecBridge_jni.h" -#include "media/base/android/webaudio_media_codec_info.h" - -using base::android::AttachCurrentThread; - -namespace media { - -void WebAudioMediaCodecBridge::RunWebAudioMediaCodec( - base::SharedMemoryHandle encoded_audio_handle, - base::FileDescriptor pcm_output, - uint32_t data_size, - base::Closure on_decode_finished_cb) { - WebAudioMediaCodecBridge bridge( - encoded_audio_handle, pcm_output, data_size); - - bridge.DecodeInMemoryAudioFile(); - on_decode_finished_cb.Run(); -} - -WebAudioMediaCodecBridge::WebAudioMediaCodecBridge( - base::SharedMemoryHandle encoded_audio_handle, - base::FileDescriptor pcm_output, - uint32_t data_size) - : encoded_audio_handle_(encoded_audio_handle), - pcm_output_(pcm_output.fd), - data_size_(data_size) { - DVLOG(1) << "WebAudioMediaCodecBridge start **********************" - << " output fd = " << pcm_output.fd; -} - -WebAudioMediaCodecBridge::~WebAudioMediaCodecBridge() { - if (close(pcm_output_)) { - DVLOG(1) << "Couldn't close output fd " << pcm_output_ - << ": " << strerror(errno); - } -} - -int WebAudioMediaCodecBridge::SaveEncodedAudioToFile( - JNIEnv* env, - jobject context) { - // Create a temporary file where we can save the encoded audio data. - std::string temporaryFile = - base::android::ConvertJavaStringToUTF8( - env, - Java_WebAudioMediaCodecBridge_createTempFile(env, context).obj()); - - // Open the file and unlink it, so that it will be actually removed - // when we close the file. - base::ScopedFD fd(open(temporaryFile.c_str(), O_RDWR)); - if (unlink(temporaryFile.c_str())) { - VLOG(0) << "Couldn't unlink temp file " << temporaryFile - << ": " << strerror(errno); - } - - if (!fd.is_valid()) { - return -1; - } - - // Create a local mapping of the shared memory containing the - // encoded audio data, and save the contents to the temporary file. - base::SharedMemory encoded_data(encoded_audio_handle_, true); - - if (!encoded_data.Map(data_size_)) { - VLOG(0) << "Unable to map shared memory!"; - return -1; - } - - if (static_cast<uint32_t>(write(fd.get(), encoded_data.memory(), data_size_)) - != data_size_) { - VLOG(0) << "Failed to write all audio data to temp file!"; - return -1; - } - - lseek(fd.get(), 0, SEEK_SET); - - return fd.release(); -} - -bool WebAudioMediaCodecBridge::DecodeInMemoryAudioFile() { - JNIEnv* env = AttachCurrentThread(); - CHECK(env); - - jobject context = base::android::GetApplicationContext(); - - int sourceFd = SaveEncodedAudioToFile(env, context); - - if (sourceFd < 0) - return false; - - jboolean decoded = Java_WebAudioMediaCodecBridge_decodeAudioFile( - env, - context, - reinterpret_cast<intptr_t>(this), - sourceFd, - data_size_); - - close(sourceFd); - - DVLOG(1) << "decoded = " << (decoded ? "true" : "false"); - - return decoded; -} - -void WebAudioMediaCodecBridge::InitializeDestination( - JNIEnv* env, - const JavaParamRef<jobject>& /*java object*/, - jint channel_count, - jint sample_rate, - jlong duration_microsec) { - // Send information about this audio file: number of channels, - // sample rate (Hz), and the number of frames. - struct WebAudioMediaCodecInfo info = { - static_cast<unsigned long>(channel_count), - static_cast<unsigned long>(sample_rate), - // The number of frames is the duration of the file - // (in microseconds) times the sample rate. - static_cast<unsigned long>( - 0.5 + (duration_microsec * 0.000001 * - sample_rate)) - }; - - DVLOG(1) << "InitializeDestination:" - << " channel count = " << channel_count - << " rate = " << sample_rate - << " duration = " << duration_microsec << " microsec"; - - HANDLE_EINTR(write(pcm_output_, &info, sizeof(info))); -} - -void WebAudioMediaCodecBridge::OnChunkDecoded( - JNIEnv* env, - const JavaParamRef<jobject>& /*java object*/, - const JavaParamRef<jobject>& buf, - jint buf_size, - jint input_channel_count, - jint output_channel_count) { - if (buf_size <= 0 || !buf) - return; - - int8_t* buffer = - static_cast<int8_t*>(env->GetDirectBufferAddress(buf)); - size_t count = static_cast<size_t>(buf_size); - std::vector<int16_t> decoded_data; - - if (input_channel_count == 1 && output_channel_count == 2) { - // See crbug.com/266006. The file has one channel, but the - // decoder decided to return two channels. To be consistent with - // the number of channels in the file, only send one channel (the - // first). - int16_t* data = static_cast<int16_t*>(env->GetDirectBufferAddress(buf)); - int frame_count = buf_size / sizeof(*data) / 2; - - decoded_data.resize(frame_count); - for (int k = 0; k < frame_count; ++k) { - decoded_data[k] = *data; - data += 2; - } - buffer = reinterpret_cast<int8_t*>(decoded_data.data()); - DCHECK(buffer); - count = frame_count * sizeof(*data); - } - - // Write out the data to the pipe in small chunks if necessary. - while (count > 0) { - int bytes_to_write = (count >= PIPE_BUF) ? PIPE_BUF : count; - ssize_t bytes_written = HANDLE_EINTR(write(pcm_output_, - buffer, - bytes_to_write)); - if (bytes_written == -1) - break; - count -= bytes_written; - buffer += bytes_written; - } -} - -bool WebAudioMediaCodecBridge::RegisterWebAudioMediaCodecBridge(JNIEnv* env) { - return RegisterNativesImpl(env); -} - -} // namespace
diff --git a/media/base/android/webaudio_media_codec_bridge.h b/media/base/android/webaudio_media_codec_bridge.h deleted file mode 100644 index cd40843..0000000 --- a/media/base/android/webaudio_media_codec_bridge.h +++ /dev/null
@@ -1,87 +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. - -#ifndef MEDIA_BASE_ANDROID_WEBAUDIO_MEDIA_CODEC_BRIDGE_H_ -#define MEDIA_BASE_ANDROID_WEBAUDIO_MEDIA_CODEC_BRIDGE_H_ - -#include <jni.h> -#include <stdint.h> - -#include "base/android/scoped_java_ref.h" -#include "base/callback.h" -#include "base/file_descriptor_posix.h" -#include "base/macros.h" -#include "base/memory/shared_memory.h" -#include "media/base/media_export.h" - -namespace media { - -// This class serves as a bridge for native code to call Java -// functions in the Android MediaCodec class. See -// http://developer.android.com/reference/android/media/MediaCodec.html. -class MEDIA_EXPORT WebAudioMediaCodecBridge { - public: - // Create the bridge with the given file descriptors. We read from - // |encoded_audio_handle| to get the encoded audio data. Audio file - // information and decoded PCM samples are written to |pcm_output|. - // We also take ownership of |pcm_output|. - WebAudioMediaCodecBridge(base::SharedMemoryHandle encoded_audio_handle, - base::FileDescriptor pcm_output, - uint32_t data_size); - ~WebAudioMediaCodecBridge(); - - // Inform JNI about this bridge. Returns true if registration - // succeeded. - static bool RegisterWebAudioMediaCodecBridge(JNIEnv* env); - - // Start MediaCodec to process the encoded data in - // |encoded_audio_handle|. The PCM samples are sent to |pcm_output|. - static void RunWebAudioMediaCodec( - base::SharedMemoryHandle encoded_audio_handle, - base::FileDescriptor pcm_output, - uint32_t data_size, - base::Closure on_decode_finished_cb); - - void OnChunkDecoded( - JNIEnv* env, - const base::android::JavaParamRef<jobject>& /*java object*/, - const base::android::JavaParamRef<jobject>& buf, - jint buf_size, - jint input_channel_count, - jint output_channel_count); - - void InitializeDestination( - JNIEnv* env, - const base::android::JavaParamRef<jobject>& /*java object*/, - jint channel_count, - jint sample_rate, - jlong duration_us); - - private: - // Handles MediaCodec processing of the encoded data in - // |encoded_audio_handle_| and sends the pcm data to |pcm_output_|. - // Returns true if decoding was successful. - bool DecodeInMemoryAudioFile(); - - // Save encoded audio data to a temporary file and return the file - // descriptor to that file. -1 is returned if the audio data could - // not be saved for any reason. - int SaveEncodedAudioToFile(JNIEnv*, jobject); - - // The encoded audio data is read from this file descriptor for the - // shared memory that holds the encoded data. - base::SharedMemoryHandle encoded_audio_handle_; - - // The audio file information and decoded pcm data are written to - // this file descriptor. We take ownership of this descriptor. - int pcm_output_; - - // The length of the encoded data. - uint32_t data_size_; - - DISALLOW_COPY_AND_ASSIGN(WebAudioMediaCodecBridge); -}; - -} // namespace media -#endif // MEDIA_BASE_ANDROID_WEBAUDIO_MEDIA_CODEC_BRIDGE_H_
diff --git a/media/base/android/webaudio_media_codec_info.h b/media/base/android/webaudio_media_codec_info.h deleted file mode 100644 index 423af91..0000000 --- a/media/base/android/webaudio_media_codec_info.h +++ /dev/null
@@ -1,20 +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_BASE_ANDROID_WEBAUDIO_MEDIA_CODEC_INFO_H_ -#define MEDIA_BASE_ANDROID_WEBAUDIO_MEDIA_CODEC_INFO_H_ - -namespace media { - -// This structure holds the information about the audio file -// determined by MediaCodec that is needed by the audio decoder to -// create the necessary destination bus. -struct WebAudioMediaCodecInfo { - unsigned long channel_count; - unsigned long sample_rate; - unsigned long number_of_frames; -}; - -} // namespace media -#endif // MEDIA_BASE_ANDROID_WEBAUDIO_MEDIA_CODEC_INFO_H_
diff --git a/media/base/limits.h b/media/base/limits.h index 34f5066..d6a50d4 100644 --- a/media/base/limits.h +++ b/media/base/limits.h
@@ -26,10 +26,11 @@ // A few notes on sample rates of common formats: // - AAC files are limited to 96 kHz. // - MP3 files are limited to 48 kHz. - // - Vorbis used to be limited to 96 KHz, but no longer has that + // - Vorbis used to be limited to 96 kHz, but no longer has that // restriction. - // - Most PC audio hardware is limited to 192 KHz. - kMaxSampleRate = 192000, + // - Most PC audio hardware is limited to 192 kHz, some specialized DAC + // devices will use 384 kHz though. + kMaxSampleRate = 384000, kMinSampleRate = 3000, kMaxChannels = 32, kMaxBytesPerSample = 4,
diff --git a/media/base/mime_util.cc b/media/base/mime_util.cc index 5055c542..ba52704 100644 --- a/media/base/mime_util.cc +++ b/media/base/mime_util.cc
@@ -15,6 +15,7 @@ #include "base/strings/string_util.h" #include "build/build_config.h" #include "media/base/mime_util.h" +#include "media/media_features.h" #if defined(OS_ANDROID) #include "base/android/build_info.h" @@ -255,7 +256,7 @@ {"audio/x-m4a", PROPRIETARY, kMP4AudioCodecsExpression}, {"video/mp4", PROPRIETARY, kMP4VideoCodecsExpression}, {"video/x-m4v", PROPRIETARY, kMP4VideoCodecsExpression}, -#if defined(ENABLE_MPEG2TS_STREAM_PARSER) +#if BUILDFLAG(ENABLE_MSE_MPEG2TS_STREAM_PARSER) {"video/mp2t", PROPRIETARY, kMP4VideoCodecsExpression}, #endif #if defined(OS_ANDROID) @@ -308,7 +309,7 @@ // avc1/avc3.XXXXXX may be ambiguous; handled by ParseH264CodecID(). }; -#if defined(ENABLE_MPEG2TS_STREAM_PARSER) +#if BUILDFLAG(ENABLE_MSE_MPEG2TS_STREAM_PARSER) static const char kHexString[] = "0123456789ABCDEF"; static char IntToHex(int i) { DCHECK_GE(i, 0) << i << " not a hex value"; @@ -479,7 +480,7 @@ return IsCodecSupported(default_codec) ? IsSupported : IsNotSupported; } -#if defined(ENABLE_MPEG2TS_STREAM_PARSER) +#if BUILDFLAG(ENABLE_MSE_MPEG2TS_STREAM_PARSER) if (mime_type_lower_case == "video/mp2t") { std::vector<std::string> codecs_to_check; for (const auto& codec_id : codecs) {
diff --git a/media/base/mime_util_unittest.cc b/media/base/mime_util_unittest.cc index 84280329..34a2ea3 100644 --- a/media/base/mime_util_unittest.cc +++ b/media/base/mime_util_unittest.cc
@@ -8,6 +8,7 @@ #include "base/strings/string_split.h" #include "build/build_config.h" #include "media/base/mime_util.h" +#include "media/media_features.h" #include "testing/gtest/include/gtest/gtest.h" namespace media { @@ -51,7 +52,7 @@ EXPECT_TRUE(IsSupportedMediaMimeType("audio/mpeg")); EXPECT_TRUE(IsSupportedMediaMimeType("audio/aac")); -#if defined(ENABLE_MPEG2TS_STREAM_PARSER) +#if BUILDFLAG(ENABLE_MSE_MPEG2TS_STREAM_PARSER) EXPECT_TRUE(IsSupportedMediaMimeType("video/mp2t")); #else EXPECT_FALSE(IsSupportedMediaMimeType("video/mp2t"));
diff --git a/media/capture/content/feedback_signal_accumulator.h b/media/capture/content/feedback_signal_accumulator.h index c6046de..3905d58a 100644 --- a/media/capture/content/feedback_signal_accumulator.h +++ b/media/capture/content/feedback_signal_accumulator.h
@@ -31,6 +31,9 @@ // Update(1.0, t=1s) will result in an accumulated average value of 0.5. explicit FeedbackSignalAccumulator(base::TimeDelta half_life); + // TODO(xjz): Change time type used by Reset() and Update() methods to + // TimeDelta instead of TimeTicks. https://crbug.com/573280. + // Erase all memory of historical values, re-starting with the given // |starting_value|. void Reset(double starting_value, base::TimeTicks timestamp);
diff --git a/media/cast/cast_config.cc b/media/cast/cast_config.cc index 400480790..f3b1612b 100644 --- a/media/cast/cast_config.cc +++ b/media/cast/cast_config.cc
@@ -13,6 +13,8 @@ kDefaultMaxQp = 63, kDefaultMinQp = 4, + kDefaultMaxCpuSaverQp = 25, + // Number of video buffers in default configuration (applies only to certain // external codecs). kDefaultNumberOfVideoBuffers = 1, @@ -50,6 +52,7 @@ start_bitrate(kDefaultMaxVideoKbps * 1000), max_qp(kDefaultMaxQp), min_qp(kDefaultMinQp), + max_cpu_saver_qp(kDefaultMaxCpuSaverQp), max_frame_rate(kDefaultMaxFrameRate), max_number_of_video_buffers_used(kDefaultNumberOfVideoBuffers), codec(CODEC_VIDEO_VP8),
diff --git a/media/cast/cast_config.h b/media/cast/cast_config.h index 9e5931b..e6a0a62 100644 --- a/media/cast/cast_config.h +++ b/media/cast/cast_config.h
@@ -128,6 +128,16 @@ int start_bitrate; int max_qp; int min_qp; + + // The maximum |min_quantizer| set to the encoder when CPU is constrained. + // This is a trade-off between higher resolution with lower encoding quality + // and lower resolution with higher encoding quality. The set value indicates + // the maximum quantizer that the encoder might produce better quality video + // at this resolution than lowering resolution with similar CPU usage and + // smaller quantizer. The set value has to be between |min_qp| and |max_qp|. + // Suggested value range: [4, 30]. + int max_cpu_saver_qp; + int max_frame_rate; // TODO(miu): Should be double, not int. // This field is used differently by various encoders. It defaults to 1.
diff --git a/media/cast/net/pacing/paced_sender.cc b/media/cast/net/pacing/paced_sender.cc index c751736..1084901 100644 --- a/media/cast/net/pacing/paced_sender.cc +++ b/media/cast/net/pacing/paced_sender.cc
@@ -31,11 +31,11 @@ DedupInfo::DedupInfo() : last_byte_acked_for_audio(0) {} // static -PacketKey PacedPacketSender::MakePacketKey(PacketKey::PacketType packet_type, - uint32_t frame_id, +PacketKey PacedPacketSender::MakePacketKey(base::TimeTicks capture_time, uint32_t ssrc, + uint32_t frame_id, uint16_t packet_id) { - PacketKey key{packet_type, frame_id, ssrc, packet_id}; + PacketKey key{capture_time, ssrc, frame_id, packet_id}; return key; } @@ -172,7 +172,7 @@ bool PacedSender::SendRtcpPacket(uint32_t ssrc, PacketRef packet) { if (state_ == State_TransportBlocked) { PacketKey key = - PacedPacketSender::MakePacketKey(PacketKey::RTCP, 0, ssrc, 0); + PacedPacketSender::MakePacketKey(base::TimeTicks(), ssrc, 0, 0); priority_packet_list_[key] = make_pair(PacketType_RTCP, packet); } else { // We pass the RTCP packets straight through.
diff --git a/media/cast/net/pacing/paced_sender.h b/media/cast/net/pacing/paced_sender.h index bf1116e..714fe9d 100644 --- a/media/cast/net/pacing/paced_sender.h +++ b/media/cast/net/pacing/paced_sender.h
@@ -37,16 +37,14 @@ // are sent out. // 3. The PacketKey is unique for each RTP (frame) packet. struct PacketKey { - enum PacketType { RTCP = 0, RTP = 1 }; - - PacketType packet_type; - uint32_t frame_id; + base::TimeTicks capture_time; uint32_t ssrc; + uint32_t frame_id; uint16_t packet_id; bool operator<(const PacketKey& key) const { - return std::tie(packet_type, frame_id, ssrc, packet_id) < - std::tie(key.packet_type, key.frame_id, key.ssrc, key.packet_id); + return std::tie(capture_time, ssrc, frame_id, packet_id) < + std::tie(key.capture_time, key.ssrc, key.frame_id, key.packet_id); } }; @@ -83,9 +81,9 @@ virtual ~PacedPacketSender() {} - static PacketKey MakePacketKey(PacketKey::PacketType, - uint32_t frame_id, + static PacketKey MakePacketKey(base::TimeTicks capture_time, uint32_t ssrc, + uint32_t frame_id, uint16_t packet_id); };
diff --git a/media/cast/net/pacing/paced_sender_unittest.cc b/media/cast/net/pacing/paced_sender_unittest.cc index 6985057..fec5c5f8 100644 --- a/media/cast/net/pacing/paced_sender_unittest.cc +++ b/media/cast/net/pacing/paced_sender_unittest.cc
@@ -62,7 +62,7 @@ class PacedSenderTest : public ::testing::Test { protected: - PacedSenderTest() : frame_id_(0) { + PacedSenderTest() { testing_clock_.Advance( base::TimeDelta::FromMilliseconds(kStartMillisecond)); task_runner_ = new test::FakeSingleThreadTaskRunner(&testing_clock_); @@ -82,11 +82,15 @@ bool audio) { DCHECK_GE(packet_size, 12u); SendPacketVector packets; + base::TimeTicks frame_tick = testing_clock_.NowTicks(); + // Advance the clock so that we don't get the same |frame_tick| + // next time this function is called. + testing_clock_.Advance(base::TimeDelta::FromMilliseconds(1)); for (int i = 0; i < num_of_packets_in_frame; ++i) { PacketKey key = PacedPacketSender::MakePacketKey( - PacketKey::RTP, frame_id_, + frame_tick, audio ? kAudioSsrc : kVideoSsrc, // ssrc - i); + 0, i); PacketRef packet(new base::RefCountedData<Packet>); packet->data.resize(packet_size, kValue); @@ -104,9 +108,6 @@ CHECK(success); packets.push_back(std::make_pair(key, packet)); } - // Increase |frame_id_| so that we don't get the same key next time this - // function is called. - ++frame_id_; return packets; } @@ -118,7 +119,6 @@ task_runner_->RunTasks(); if (mock_transport_.expected_packet_size_.empty()) return true; - i++; } return mock_transport_.expected_packet_size_.empty(); @@ -129,7 +129,6 @@ TestPacketSender mock_transport_; scoped_refptr<test::FakeSingleThreadTaskRunner> task_runner_; scoped_ptr<PacedSender> paced_sender_; - uint32_t frame_id_; DISALLOW_COPY_AND_ASSIGN(PacedSenderTest); };
diff --git a/media/cast/net/rtp/packet_storage_unittest.cc b/media/cast/net/rtp/packet_storage_unittest.cc index 380a450..0484cc20 100644 --- a/media/cast/net/rtp/packet_storage_unittest.cc +++ b/media/cast/net/rtp/packet_storage_unittest.cc
@@ -25,6 +25,7 @@ static void StoreFrames(size_t number_of_frames, uint32_t first_frame_id, PacketStorage* storage) { + const base::TimeTicks zero; const int kSsrc = 1; for (size_t i = 0; i < number_of_frames; ++i) { SendPacketVector packets; @@ -32,10 +33,10 @@ const size_t kNumberOfPackets = i + 1; for (size_t j = 0; j < kNumberOfPackets; ++j) { Packet test_packet(1, 0); - packets.push_back(std::make_pair( - PacedPacketSender::MakePacketKey(PacketKey::RTP, i, kSsrc, - base::checked_cast<uint16_t>(j)), - new base::RefCountedData<Packet>(test_packet))); + packets.push_back( + std::make_pair(PacedPacketSender::MakePacketKey( + zero, kSsrc, i, base::checked_cast<uint16_t>(j)), + new base::RefCountedData<Packet>(test_packet))); } storage->StoreFrame(first_frame_id, packets); ++first_frame_id;
diff --git a/media/cast/net/rtp/rtp_packetizer.cc b/media/cast/net/rtp/rtp_packetizer.cc index 247eae8..2650098 100644 --- a/media/cast/net/rtp/rtp_packetizer.cc +++ b/media/cast/net/rtp/rtp_packetizer.cc
@@ -105,7 +105,7 @@ data_iter += payload_length; const PacketKey key = PacedPacketSender::MakePacketKey( - PacketKey::RTP, frame.frame_id, config_.ssrc, packet_id); + frame.reference_time, config_.ssrc, frame.frame_id, packet_id); packets.push_back(make_pair(key, packet)); // Update stats.
diff --git a/media/cast/sender/congestion_control.cc b/media/cast/sender/congestion_control.cc index 4168116..c007165 100644 --- a/media/cast/sender/congestion_control.cc +++ b/media/cast/sender/congestion_control.cc
@@ -44,8 +44,7 @@ base::TimeTicks when) final; void AckFrame(uint32_t frame_id, base::TimeTicks when) final; int GetBitrate(base::TimeTicks playout_time, - base::TimeDelta playout_delay, - int soft_max_bitrate) final; + base::TimeDelta playout_delay) final; private: struct FrameStats { @@ -104,8 +103,7 @@ base::TimeTicks when) final {} void AckFrame(uint32_t frame_id, base::TimeTicks when) final {} int GetBitrate(base::TimeTicks playout_time, - base::TimeDelta playout_delay, - int soft_max_bitrate) final { + base::TimeDelta playout_delay) final { return bitrate_; } @@ -343,8 +341,7 @@ } int AdaptiveCongestionControl::GetBitrate(base::TimeTicks playout_time, - base::TimeDelta playout_delay, - int soft_max_bitrate) { + base::TimeDelta playout_delay) { double safe_bitrate = CalculateSafeBitrate(); // Estimate when we might start sending the next frame. base::TimeDelta time_to_catch_up = @@ -363,7 +360,6 @@ << " SBR:" << (safe_bitrate / 1E6); TRACE_COUNTER_ID1("cast.stream", "Empty Buffer Fraction", this, empty_buffer_fraction); - bits_per_second = std::min(bits_per_second, soft_max_bitrate); bits_per_second = std::max(bits_per_second, min_bitrate_configured_); bits_per_second = std::min(bits_per_second, max_bitrate_configured_);
diff --git a/media/cast/sender/congestion_control.h b/media/cast/sender/congestion_control.h index 1311aa5..805879d 100644 --- a/media/cast/sender/congestion_control.h +++ b/media/cast/sender/congestion_control.h
@@ -37,8 +37,7 @@ // is a soft upper-bound applied to the computed target bitrate before the // hard upper- and lower-bounds are applied. virtual int GetBitrate(base::TimeTicks playout_time, - base::TimeDelta playout_delay, - int soft_max_bitrate) = 0; + base::TimeDelta playout_delay) = 0; }; CongestionControl* NewAdaptiveCongestionControl(
diff --git a/media/cast/sender/congestion_control_unittest.cc b/media/cast/sender/congestion_control_unittest.cc index 36c9e5f..3a09dfe 100644 --- a/media/cast/sender/congestion_control_unittest.cc +++ b/media/cast/sender/congestion_control_unittest.cc
@@ -82,29 +82,23 @@ // Empty the buffer. task_runner_->Sleep(base::TimeDelta::FromMilliseconds(100)); - // Use a soft maximum bitrate limit so large it will not bound the results of - // the underlying computations. - const int soft_max_bitrate = std::numeric_limits<int>::max(); - uint32_t safe_bitrate = frame_size * 1000 / kFrameDelayMs; uint32_t bitrate = congestion_control_->GetBitrate( testing_clock_.NowTicks() + base::TimeDelta::FromMilliseconds(300), - base::TimeDelta::FromMilliseconds(300), soft_max_bitrate); + base::TimeDelta::FromMilliseconds(300)); EXPECT_NEAR( safe_bitrate / kTargetEmptyBufferFraction, bitrate, safe_bitrate * 0.05); bitrate = congestion_control_->GetBitrate( testing_clock_.NowTicks() + base::TimeDelta::FromMilliseconds(200), - base::TimeDelta::FromMilliseconds(300), - soft_max_bitrate); + base::TimeDelta::FromMilliseconds(300)); EXPECT_NEAR(safe_bitrate / kTargetEmptyBufferFraction * 2 / 3, bitrate, safe_bitrate * 0.05); bitrate = congestion_control_->GetBitrate( testing_clock_.NowTicks() + base::TimeDelta::FromMilliseconds(100), - base::TimeDelta::FromMilliseconds(300), - soft_max_bitrate); + base::TimeDelta::FromMilliseconds(300)); EXPECT_NEAR(safe_bitrate / kTargetEmptyBufferFraction * 1 / 3, bitrate, safe_bitrate * 0.05); @@ -116,8 +110,7 @@ // Results should show that we have ~200ms to send. bitrate = congestion_control_->GetBitrate( testing_clock_.NowTicks() + base::TimeDelta::FromMilliseconds(300), - base::TimeDelta::FromMilliseconds(300), - soft_max_bitrate); + base::TimeDelta::FromMilliseconds(300)); EXPECT_NEAR(safe_bitrate / kTargetEmptyBufferFraction * 2 / 3, bitrate, safe_bitrate * 0.05); @@ -129,8 +122,7 @@ // Results should show that we have ~100ms to send. bitrate = congestion_control_->GetBitrate( testing_clock_.NowTicks() + base::TimeDelta::FromMilliseconds(300), - base::TimeDelta::FromMilliseconds(300), - soft_max_bitrate); + base::TimeDelta::FromMilliseconds(300)); EXPECT_NEAR(safe_bitrate / kTargetEmptyBufferFraction * 1 / 3, bitrate, safe_bitrate * 0.05);
diff --git a/media/cast/sender/video_sender.cc b/media/cast/sender/video_sender.cc index 2862c40..1c39ecb 100644 --- a/media/cast/sender/video_sender.cc +++ b/media/cast/sender/video_sender.cc
@@ -242,8 +242,7 @@ } const int bitrate = congestion_control_->GetBitrate( - reference_time + target_playout_delay_, target_playout_delay_, - GetMaximumTargetBitrateForFrame(*video_frame)); + reference_time + target_playout_delay_, target_playout_delay_); if (bitrate != last_bitrate_) { video_encoder_->SetBitRate(bitrate); last_bitrate_ = bitrate; @@ -298,57 +297,6 @@ } } -// static -int VideoSender::GetMaximumTargetBitrateForFrame( - const media::VideoFrame& frame) { - enum { - // Constants used to linearly translate between lines of resolution and a - // maximum target bitrate. These values are based on observed quality - // trade-offs over a wide range of content. The math will use these values - // to compute a bitrate of 2 Mbps for 360 lines of resolution and 4 Mbps for - // 720 lines. - BITRATE_FOR_HIGH_RESOLUTION = 4000000, - BITRATE_FOR_STANDARD_RESOLUTION = 2000000, - HIGH_RESOLUTION_LINES = 720, - STANDARD_RESOLUTION_LINES = 360, - - // The smallest maximum target bitrate, regardless of what the math says. - MAX_BITRATE_LOWER_BOUND = 1000000, - - // Constants used to boost the result for high frame rate content. - HIGH_FRAME_RATE_THRESHOLD_USEC = 25000, // 40 FPS - HIGH_FRAME_RATE_BOOST_NUMERATOR = 3, - HIGH_FRAME_RATE_BOOST_DENOMINATOR = 2, - }; - - // Determine the approximate height of a 16:9 frame having the same area - // (number of pixels) as |frame|. - const gfx::Size& resolution = frame.visible_rect().size(); - const int lines_of_resolution = - ((resolution.width() * 9) == (resolution.height() * 16)) ? - resolution.height() : - static_cast<int>(sqrt(resolution.GetArea() * 9.0 / 16.0)); - - // Linearly translate from |lines_of_resolution| to a maximum target bitrate. - int64_t result = lines_of_resolution - STANDARD_RESOLUTION_LINES; - result *= BITRATE_FOR_HIGH_RESOLUTION - BITRATE_FOR_STANDARD_RESOLUTION; - result /= HIGH_RESOLUTION_LINES - STANDARD_RESOLUTION_LINES; - result += BITRATE_FOR_STANDARD_RESOLUTION; - - // Boost the result for high frame rate content. - base::TimeDelta frame_duration; - if (frame.metadata()->GetTimeDelta(media::VideoFrameMetadata::FRAME_DURATION, - &frame_duration) && - frame_duration > base::TimeDelta() && - frame_duration.InMicroseconds() <= HIGH_FRAME_RATE_THRESHOLD_USEC) { - result *= HIGH_FRAME_RATE_BOOST_NUMERATOR; - result /= HIGH_FRAME_RATE_BOOST_DENOMINATOR; - } - - // Return a lower-bounded result. - return std::max<int>(result, MAX_BITRATE_LOWER_BOUND); -} - void VideoSender::OnEncodedVideoFrame( const scoped_refptr<media::VideoFrame>& video_frame, int encoder_bitrate,
diff --git a/media/cast/sender/video_sender.h b/media/cast/sender/video_sender.h index 7c18e57..025aaa0 100644 --- a/media/cast/sender/video_sender.h +++ b/media/cast/sender/video_sender.h
@@ -66,13 +66,6 @@ int GetNumberOfFramesInEncoder() const final; base::TimeDelta GetInFlightMediaDuration() const final; - // Return the maximum target bitrate that should be used for the given video - // |frame|. This will be provided to CongestionControl as a soft maximum - // limit, and should be interpreted as "the point above which the extra - // encoder CPU time + network bandwidth usage isn't warranted for the amount - // of further quality improvement to be gained." - static int GetMaximumTargetBitrateForFrame(const media::VideoFrame& frame); - private: // Called by the |video_encoder_| with the next EncodedFrame to send. void OnEncodedVideoFrame(const scoped_refptr<media::VideoFrame>& video_frame,
diff --git a/media/cast/sender/video_sender_unittest.cc b/media/cast/sender/video_sender_unittest.cc index e48b5971..9c5d9c4 100644 --- a/media/cast/sender/video_sender_unittest.cc +++ b/media/cast/sender/video_sender_unittest.cc
@@ -119,25 +119,8 @@ transport_sender, base::Bind(&IgnorePlayoutDelayChanges)) {} using VideoSender::OnReceivedCastFeedback; - using VideoSender::GetMaximumTargetBitrateForFrame; }; -// Creates a VideoFrame NOT backed by actual memory storage. The frame's -// metadata (i.e., size and frame duration) are all that are needed to test the -// GetMaximumTargetBitrateForFrame() logic. -scoped_refptr<VideoFrame> CreateFakeFrame(const gfx::Size& resolution, - bool high_frame_rate_in_metadata) { - const scoped_refptr<VideoFrame> frame = VideoFrame::WrapExternalData( - PIXEL_FORMAT_I420, resolution, gfx::Rect(resolution), resolution, - static_cast<uint8_t*>(nullptr) + 1, resolution.GetArea() * 3 / 2, - base::TimeDelta()); - const double frame_rate = high_frame_rate_in_metadata ? 60.0 : 30.0; - frame->metadata()->SetTimeDelta( - VideoFrameMetadata::FRAME_DURATION, - base::TimeDelta::FromSecondsD(1.0 / frame_rate)); - return frame; -} - } // namespace class VideoSenderTest : public ::testing::Test { @@ -615,51 +598,5 @@ } } -// Tests that VideoSender::GetMaximumTargetBitrateForFrame() returns the correct -// result for a number of frame resolution combinations. -TEST(VideoSenderMathTest, ComputesCorrectMaximumTargetBitratesForFrames) { - const struct { - int width; - int height; - bool high_frame_rate; - int expected_bitrate; - } kTestCases[] = { - // Standard 16:9 resolutions, non-HFR. - { 16, 9, false, 1000000 }, - { 320, 180, false, 1000000 }, - { 640, 360, false, 2000000 }, - { 800, 450, false, 2500000 }, - { 1280, 720, false, 4000000 }, - { 1920, 1080, false, 6000000 }, - { 3840, 2160, false, 12000000 }, - - // Standard 16:9 resolutions, HFR. - { 16, 9, true, 1000000 }, - { 320, 180, true, 1500000 }, - { 640, 360, true, 3000000 }, - { 800, 450, true, 3750000 }, - { 1280, 720, true, 6000000 }, - { 1920, 1080, true, 9000000 }, - { 3840, 2160, true, 18000000 }, - - // 4:3 and oddball resolutions. - { 640, 480, false, 2305555 }, - { 1024, 768, false, 3694444 }, - { 10, 5000, false, 1000000 }, - { 1234, 567, false, 3483333 }, - { 16384, 16384, true, 102399999 }, - }; - - for (size_t i = 0; i < arraysize(kTestCases); ++i) { - const gfx::Size resolution(kTestCases[i].width, kTestCases[i].height); - SCOPED_TRACE(::testing::Message() << "resolution=" << resolution.ToString() - << ", hfr=" << kTestCases[i].high_frame_rate); - const scoped_refptr<VideoFrame> frame = - CreateFakeFrame(resolution, kTestCases[i].high_frame_rate); - EXPECT_EQ(kTestCases[i].expected_bitrate, - PeerVideoSender::GetMaximumTargetBitrateForFrame(*frame)); - } -} - } // namespace cast } // namespace media
diff --git a/media/cast/sender/vp8_encoder.cc b/media/cast/sender/vp8_encoder.cc index f2d6117f..a9a4547 100644 --- a/media/cast/sender/vp8_encoder.cc +++ b/media/cast/sender/vp8_encoder.cc
@@ -25,6 +25,37 @@ // pause in the video stream. const int kRestartFramePeriods = 3; +// The following constants are used to automactically tune the encoder +// parameters: |cpu_used| and |min_quantizer|. + +// The |half-life| of the encoding speed accumulator. +// The smaller, the shorter of the time averaging window. +const int kEncodingSpeedAccHalfLife = 120000; // 0.12 second. + +// The target deadline utilization signal. This is a trade-off between quality +// and less CPU usage. The range of this value is [0, 1]. With the higher this +// value, the better quality and higher CPU usage. The typical range for cast +// streaming is [0.6, 0.7]. +const double kTargetDeadlineUtilization = 0.7; + +// This is the equivalent change on encoding speed for the change on each +// quantizer step. +const double kEquivalentEncodingSpeedStepPerQpStep = 1 / 20.0; + +// Highest/lowest allowed encoding speed set to the encoder. The valid range +// is [4, 16]. Experiments show that with speed higher than 12, the saving of +// the encoding time is not worth the dropping of the quality. And with speed +// lower than 6, the increasing of quality is not worth the increasing of +// encoding time. +const int kHighestEncodingSpeed = 12; +const int kLowestEncodingSpeed = 6; + +bool HasSufficientFeedback(const FeedbackSignalAccumulator& accumulator) { + const base::TimeDelta amount_of_history = + accumulator.update_time() - accumulator.reset_time(); + return amount_of_history.InMicroseconds() >= 250000; // 0.25 second. +} + } // namespace Vp8Encoder::Vp8Encoder(const VideoSenderConfig& video_config) @@ -32,8 +63,13 @@ key_frame_requested_(true), bitrate_kbit_(cast_config_.start_bitrate / 1000), last_encoded_frame_id_(kFirstFrameId - 1), - has_seen_zero_length_encoded_frame_(false) { + has_seen_zero_length_encoded_frame_(false), + encoding_speed_acc_( + base::TimeDelta::FromMicroseconds(kEncodingSpeedAccHalfLife)), + encoding_speed_(kHighestEncodingSpeed) { config_.g_timebase.den = 0; // Not initialized. + DCHECK_LE(cast_config_.min_qp, cast_config_.max_cpu_saver_qp); + DCHECK_LE(cast_config_.max_cpu_saver_qp, cast_config_.max_qp); thread_checker_.DetachFromThread(); } @@ -63,6 +99,7 @@ << frame_size.ToString(); config_.g_w = frame_size.width(); config_.g_h = frame_size.height(); + config_.rc_min_quantizer = cast_config_.min_qp; 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 " @@ -125,12 +162,17 @@ CHECK_EQ(vpx_codec_control(&encoder_, VP8E_SET_STATIC_THRESHOLD, 1), VPX_CODEC_OK); - // Improve quality by enabling sets of codec features that utilize more CPU. - // The default is zero, with increasingly more CPU to be used as the value is - // more negative. - // TODO(miu): Document why this value was chosen and expected behaviors. - // Should this be dynamic w.r.t. hardware performance? - CHECK_EQ(vpx_codec_control(&encoder_, VP8E_SET_CPUUSED, -6), VPX_CODEC_OK); + // This cpu_used setting is a trade-off between cpu usage and encoded video + // quality. The default is zero, with increasingly less CPU to be used as the + // value is more negative or more positive. The encoder does some automatic + // adjust on encoding speed for positive values, however at least at this + // stage the experiments show that this automatic behaviour is not reliable on + // windows machines. We choose to set negative values instead to directly set + // the encoding speed to the encoder. Starting with the highest encoding speed + // to avoid large cpu usage from the beginning. + encoding_speed_ = kHighestEncodingSpeed; + CHECK_EQ(vpx_codec_control(&encoder_, VP8E_SET_CPUUSED, -encoding_speed_), + VPX_CODEC_OK); } void Vp8Encoder::Encode(const scoped_refptr<media::VideoFrame>& video_frame, @@ -289,6 +331,56 @@ if (encoded_frame->dependency == EncodedFrame::KEY) { key_frame_requested_ = false; } + + // This is not a true system clock value, but a "hack" needed in order to use + // FeedbackSignalAccumulator. + const base::TimeTicks current_time = base::TimeTicks() + + base::TimeDelta::FromMilliseconds(10) + + video_frame->timestamp(); + + if (encoded_frame->dependency == EncodedFrame::KEY) { + encoding_speed_acc_.Reset(kHighestEncodingSpeed, current_time); + } else { + // Equivalent encoding speed considering both cpu_used setting and + // quantizer. + double actual_encoding_speed = + encoding_speed_ + + kEquivalentEncodingSpeedStepPerQpStep * + std::max(0, quantizer - cast_config_.min_qp); + double adjusted_encoding_speed = actual_encoding_speed * + encoded_frame->deadline_utilization / + kTargetDeadlineUtilization; + encoding_speed_acc_.Update(adjusted_encoding_speed, current_time); + } + + if (HasSufficientFeedback(encoding_speed_acc_)) { + // Predict |encoding_speed_| and |min_quantizer| for next frame. + // When CPU is constrained, increase encoding speed and increase + // |min_quantizer| if needed. + double next_encoding_speed = encoding_speed_acc_.current(); + int next_min_qp; + if (next_encoding_speed > kHighestEncodingSpeed) { + double remainder = next_encoding_speed - kHighestEncodingSpeed; + next_encoding_speed = kHighestEncodingSpeed; + next_min_qp = + static_cast<int>(remainder / kEquivalentEncodingSpeedStepPerQpStep + + cast_config_.min_qp + 0.5); + next_min_qp = std::min(next_min_qp, cast_config_.max_cpu_saver_qp); + } else { + next_encoding_speed = + std::max<double>(kLowestEncodingSpeed, next_encoding_speed) + 0.5; + next_min_qp = cast_config_.min_qp; + } + if (encoding_speed_ != static_cast<int>(next_encoding_speed)) { + encoding_speed_ = static_cast<int>(next_encoding_speed); + CHECK_EQ(vpx_codec_control(&encoder_, VP8E_SET_CPUUSED, -encoding_speed_), + VPX_CODEC_OK); + } + if (config_.rc_min_quantizer != static_cast<unsigned int>(next_min_qp)) { + config_.rc_min_quantizer = static_cast<unsigned int>(next_min_qp); + CHECK_EQ(vpx_codec_enc_config_set(&encoder_, &config_), VPX_CODEC_OK); + } + } } void Vp8Encoder::UpdateRates(uint32_t new_bitrate) {
diff --git a/media/cast/sender/vp8_encoder.h b/media/cast/sender/vp8_encoder.h index d8270b2..ef80a69 100644 --- a/media/cast/sender/vp8_encoder.h +++ b/media/cast/sender/vp8_encoder.h
@@ -10,6 +10,7 @@ #include "base/macros.h" #include "base/memory/scoped_ptr.h" #include "base/threading/thread_checker.h" +#include "media/capture/content/feedback_signal_accumulator.h" #include "media/cast/cast_config.h" #include "media/cast/sender/software_video_encoder.h" #include "third_party/libvpx_new/source/libvpx/vpx/vpx_encoder.h" @@ -78,6 +79,12 @@ // TODO(miu): Remove after discovering cause. http://crbug.com/519022 bool has_seen_zero_length_encoded_frame_; + // The accumulator (time averaging) of the encoding speed. + FeedbackSignalAccumulator encoding_speed_acc_; + + // The higher the speed, the less CPU usage, and the lower quality. + int encoding_speed_; + DISALLOW_COPY_AND_ASSIGN(Vp8Encoder); };
diff --git a/media/cast/sender/vp8_quantizer_parser_unittest.cc b/media/cast/sender/vp8_quantizer_parser_unittest.cc index bb033ec6..260dd79b 100644 --- a/media/cast/sender/vp8_quantizer_parser_unittest.cc +++ b/media/cast/sender/vp8_quantizer_parser_unittest.cc
@@ -33,6 +33,7 @@ config.max_frame_rate = kFrameRate; config.min_qp = kQp; config.max_qp = kQp; + config.max_cpu_saver_qp = kQp; return config; } } // unnamed namespace @@ -59,6 +60,7 @@ DCHECK((qp > 3) && (qp < 64)); video_config_.min_qp = qp; video_config_.max_qp = qp; + video_config_.max_cpu_saver_qp = qp; RecreateVp8Encoder(); }
diff --git a/media/cdm/cenc_utils_unittest.cc b/media/cdm/cenc_utils_unittest.cc index beab6ed..c124cbd2 100644 --- a/media/cdm/cenc_utils_unittest.cc +++ b/media/cdm/cenc_utils_unittest.cc
@@ -159,9 +159,9 @@ // and simply appends the data to the end of it. It updates the box size // and sets the data size. DCHECK(data.size() < 100); - pssh_box[3] += data.size(); + pssh_box[3] += static_cast<uint8_t>(data.size()); pssh_box.pop_back(); - pssh_box.push_back(data.size()); + pssh_box.push_back(static_cast<uint8_t>(data.size())); pssh_box.insert(pssh_box.end(), data.begin(), data.end()); } @@ -284,7 +284,7 @@ // Add 20 additional bytes to |box|. size_t original_size = box.size(); for (size_t i = 0; i < 20; ++i) - box.push_back(i); + box.push_back(static_cast<uint8_t>(i)); // Tries every size greater than |original_size|. for (size_t i = original_size + 1; i < box.size(); ++i) {
diff --git a/media/filters/chunk_demuxer_unittest.cc b/media/filters/chunk_demuxer_unittest.cc index 2e4983d..94698d4 100644 --- a/media/filters/chunk_demuxer_unittest.cc +++ b/media/filters/chunk_demuxer_unittest.cc
@@ -25,6 +25,7 @@ #include "media/base/timestamp_constants.h" #include "media/formats/webm/cluster_builder.h" #include "media/formats/webm/webm_constants.h" +#include "media/media_features.h" #include "testing/gtest/include/gtest/gtest.h" using ::testing::AnyNumber; @@ -362,6 +363,7 @@ return demuxer_->AddId(source_id, type, codecs); } +#if BUILDFLAG(ENABLE_MSE_MPEG2TS_STREAM_PARSER) ChunkDemuxer::Status AddIdForMp2tSource(const std::string& source_id) { std::vector<std::string> codecs; std::string type = "video/mp2t"; @@ -369,6 +371,7 @@ codecs.push_back("avc1.640028"); return demuxer_->AddId(source_id, type, codecs); } +#endif void AppendData(const uint8_t* data, size_t length) { AppendData(kSourceId, data, length); @@ -3047,7 +3050,7 @@ } #if defined(USE_PROPRIETARY_CODECS) -#if defined(ENABLE_MPEG2TS_STREAM_PARSER) +#if BUILDFLAG(ENABLE_MSE_MPEG2TS_STREAM_PARSER) TEST_F(ChunkDemuxerTest, EmitBuffersDuringAbort) { EXPECT_CALL(*this, DemuxerOpened()); demuxer_->Initialize(
diff --git a/media/filters/stream_parser_factory.cc b/media/filters/stream_parser_factory.cc index cfc881f..db626c5f 100644 --- a/media/filters/stream_parser_factory.cc +++ b/media/filters/stream_parser_factory.cc
@@ -18,13 +18,14 @@ #include "media/formats/mpeg/adts_stream_parser.h" #include "media/formats/mpeg/mpeg1_audio_stream_parser.h" #include "media/formats/webm/webm_stream_parser.h" +#include "media/media_features.h" #if defined(OS_ANDROID) #include "base/android/build_info.h" #endif #if defined(USE_PROPRIETARY_CODECS) -#if defined(ENABLE_MPEG2TS_STREAM_PARSER) +#if BUILDFLAG(ENABLE_MSE_MPEG2TS_STREAM_PARSER) #include "media/formats/mp2t/mp2t_stream_parser.h" #endif #include "media/formats/mp4/es_descriptor.h" @@ -235,7 +236,7 @@ return new ADTSStreamParser(); } -#if defined(ENABLE_MPEG2TS_STREAM_PARSER) +#if BUILDFLAG(ENABLE_MSE_MPEG2TS_STREAM_PARSER) static const CodecInfo* kVideoMP2TCodecs[] = { &kH264AVC1CodecInfo, &kH264AVC3CodecInfo, @@ -263,17 +264,16 @@ #endif #endif - static const SupportedTypeInfo kSupportedTypeInfo[] = { - { "video/webm", &BuildWebMParser, kVideoWebMCodecs }, - { "audio/webm", &BuildWebMParser, kAudioWebMCodecs }, + {"video/webm", &BuildWebMParser, kVideoWebMCodecs}, + {"audio/webm", &BuildWebMParser, kAudioWebMCodecs}, #if defined(USE_PROPRIETARY_CODECS) - { "audio/aac", &BuildADTSParser, kAudioADTSCodecs }, - { "audio/mpeg", &BuildMP3Parser, kAudioMP3Codecs }, - { "video/mp4", &BuildMP4Parser, kVideoMP4Codecs }, - { "audio/mp4", &BuildMP4Parser, kAudioMP4Codecs }, -#if defined(ENABLE_MPEG2TS_STREAM_PARSER) - { "video/mp2t", &BuildMP2TParser, kVideoMP2TCodecs }, + {"audio/aac", &BuildADTSParser, kAudioADTSCodecs}, + {"audio/mpeg", &BuildMP3Parser, kAudioMP3Codecs}, + {"video/mp4", &BuildMP4Parser, kVideoMP4Codecs}, + {"audio/mp4", &BuildMP4Parser, kAudioMP4Codecs}, +#if BUILDFLAG(ENABLE_MSE_MPEG2TS_STREAM_PARSER) + {"video/mp2t", &BuildMP2TParser, kVideoMP2TCodecs}, #endif #endif };
diff --git a/media/media.gyp b/media/media.gyp index 3cbb74f..89e1ade 100644 --- a/media/media.gyp +++ b/media/media.gyp
@@ -33,6 +33,11 @@ }, { 'use_low_memory_buffer%': 0, }], + ['chromecast == 1', { + 'enable_mse_mpeg2ts_stream_parser%': 1, + }, { + 'enable_mse_mpeg2ts_stream_parser%': 0, + }], ['chromecast==1', { # Enable HEVC/H265 demuxing. Actual decoding must be provided by the # platform. @@ -48,10 +53,22 @@ ], 'targets': [ { + # GN version: //media:media_features + 'target_name': 'media_features', + 'includes': [ '../build/buildflag_header.gypi' ], + 'variables': { + 'buildflag_header_path': 'media/media_features.h', + 'buildflag_flags': [ + "ENABLE_MSE_MPEG2TS_STREAM_PARSER=<(enable_mse_mpeg2ts_stream_parser)", + ], + }, + }, + { # GN version: //media 'target_name': 'media', 'type': '<(component)', 'dependencies': [ + 'media_features', '../base/base.gyp:base', '../base/base.gyp:base_i18n', '../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations', @@ -1039,32 +1056,6 @@ 'filters/ffmpeg_h264_to_annex_b_bitstream_converter.h', 'filters/h264_to_annex_b_bitstream_converter.cc', 'filters/h264_to_annex_b_bitstream_converter.h', - 'formats/mp2t/es_adapter_video.cc', - 'formats/mp2t/es_adapter_video.h', - 'formats/mp2t/es_parser.cc', - 'formats/mp2t/es_parser.h', - 'formats/mp2t/es_parser_adts.cc', - 'formats/mp2t/es_parser_adts.h', - 'formats/mp2t/es_parser_h264.cc', - 'formats/mp2t/es_parser_h264.h', - 'formats/mp2t/es_parser_mpeg1audio.cc', - 'formats/mp2t/es_parser_mpeg1audio.h', - 'formats/mp2t/mp2t_common.h', - 'formats/mp2t/mp2t_stream_parser.cc', - 'formats/mp2t/mp2t_stream_parser.h', - 'formats/mp2t/timestamp_unroller.cc', - 'formats/mp2t/timestamp_unroller.h', - 'formats/mp2t/ts_packet.cc', - 'formats/mp2t/ts_packet.h', - 'formats/mp2t/ts_section.h', - 'formats/mp2t/ts_section_pat.cc', - 'formats/mp2t/ts_section_pat.h', - 'formats/mp2t/ts_section_pes.cc', - 'formats/mp2t/ts_section_pes.h', - 'formats/mp2t/ts_section_pmt.cc', - 'formats/mp2t/ts_section_pmt.h', - 'formats/mp2t/ts_section_psi.cc', - 'formats/mp2t/ts_section_psi.h', 'formats/mp4/aac.cc', 'formats/mp4/aac.h', 'formats/mp4/avc.cc', @@ -1095,6 +1086,36 @@ 'formats/mpeg/mpeg_audio_stream_parser_base.h', ], }], + ['proprietary_codecs==1 and enable_mse_mpeg2ts_stream_parser==1', { + 'sources': [ + 'formats/mp2t/es_adapter_video.cc', + 'formats/mp2t/es_adapter_video.h', + 'formats/mp2t/es_parser.cc', + 'formats/mp2t/es_parser.h', + 'formats/mp2t/es_parser_adts.cc', + 'formats/mp2t/es_parser_adts.h', + 'formats/mp2t/es_parser_h264.cc', + 'formats/mp2t/es_parser_h264.h', + 'formats/mp2t/es_parser_mpeg1audio.cc', + 'formats/mp2t/es_parser_mpeg1audio.h', + 'formats/mp2t/mp2t_common.h', + 'formats/mp2t/mp2t_stream_parser.cc', + 'formats/mp2t/mp2t_stream_parser.h', + 'formats/mp2t/timestamp_unroller.cc', + 'formats/mp2t/timestamp_unroller.h', + 'formats/mp2t/ts_packet.cc', + 'formats/mp2t/ts_packet.h', + 'formats/mp2t/ts_section.h', + 'formats/mp2t/ts_section_pat.cc', + 'formats/mp2t/ts_section_pat.h', + 'formats/mp2t/ts_section_pes.cc', + 'formats/mp2t/ts_section_pes.h', + 'formats/mp2t/ts_section_pmt.cc', + 'formats/mp2t/ts_section_pmt.h', + 'formats/mp2t/ts_section_psi.cc', + 'formats/mp2t/ts_section_psi.h', + ], + }], ['proprietary_codecs==1 and enable_hevc_demuxing==1', { 'defines': [ 'ENABLE_HEVC_DEMUXING' @@ -1413,14 +1434,6 @@ 'filters/h264_to_annex_b_bitstream_converter_unittest.cc', 'formats/common/stream_parser_test_base.cc', 'formats/common/stream_parser_test_base.h', - 'formats/mp2t/es_adapter_video_unittest.cc', - 'formats/mp2t/es_parser_adts_unittest.cc', - 'formats/mp2t/es_parser_h264_unittest.cc', - 'formats/mp2t/es_parser_mpeg1audio_unittest.cc', - 'formats/mp2t/es_parser_test_base.cc', - 'formats/mp2t/es_parser_test_base.h', - 'formats/mp2t/mp2t_stream_parser_unittest.cc', - 'formats/mp2t/timestamp_unroller_unittest.cc', 'formats/mp4/aac_unittest.cc', 'formats/mp4/avc_unittest.cc', 'formats/mp4/box_reader_unittest.cc', @@ -1432,6 +1445,18 @@ 'formats/mpeg/mpeg1_audio_stream_parser_unittest.cc', ], }], + ['proprietary_codecs==1 and enable_mse_mpeg2ts_stream_parser==1', { + 'sources': [ + 'formats/mp2t/es_adapter_video_unittest.cc', + 'formats/mp2t/es_parser_adts_unittest.cc', + 'formats/mp2t/es_parser_h264_unittest.cc', + 'formats/mp2t/es_parser_mpeg1audio_unittest.cc', + 'formats/mp2t/es_parser_test_base.cc', + 'formats/mp2t/es_parser_test_base.h', + 'formats/mp2t/mp2t_stream_parser_unittest.cc', + 'formats/mp2t/timestamp_unroller_unittest.cc', + ], + }], ['OS=="mac"', { 'sources': [ 'capture/video/mac/video_capture_device_factory_mac_unittest.mm', @@ -1823,7 +1848,6 @@ 'base/android/java/src/org/chromium/media/MediaDrmBridge.java', 'base/android/java/src/org/chromium/media/MediaPlayerBridge.java', 'base/android/java/src/org/chromium/media/MediaPlayerListener.java', - 'base/android/java/src/org/chromium/media/WebAudioMediaCodecBridge.java', ], 'variables': { 'jni_gen_package': 'media', @@ -1901,9 +1925,6 @@ 'base/android/sdk_media_codec_bridge.h', 'base/android/video_decoder_job.cc', 'base/android/video_decoder_job.h', - 'base/android/webaudio_media_codec_bridge.cc', - 'base/android/webaudio_media_codec_bridge.h', - 'base/android/webaudio_media_codec_info.h', ], 'conditions': [ # Only 64 bit builds are using android-21 NDK library, check common.gypi
diff --git a/media/media_options.gni b/media/media_options.gni index 62401b1..fa01d0f 100644 --- a/media/media_options.gni +++ b/media/media_options.gni
@@ -48,10 +48,7 @@ # Use low-memory buffers on non-Android builds of Chromecast. use_low_memory_buffer = is_chromecast && !is_android - # Enables the MPEG2-TS stream parser for use with Media Source. Disabled by - # default (except on Chromecast) since it's not available on the normal Web - # Platform and costs money. - enable_mpeg2ts_stream_parser = is_chromecast + enable_mse_mpeg2ts_stream_parser = is_chromecast # Enable HEVC/H265 demuxing. Actual decoding must be provided by the # platform. Enable by default for Chromecast.
diff --git a/media/renderers/skcanvas_video_renderer.cc b/media/renderers/skcanvas_video_renderer.cc index d5b9fa9..0740f47 100644 --- a/media/renderers/skcanvas_video_renderer.cc +++ b/media/renderers/skcanvas_video_renderer.cc
@@ -115,8 +115,8 @@ gl->GenTextures(1, &texture_copy); DCHECK(texture_copy); gl->BindTexture(GL_TEXTURE_2D, texture_copy); - gl->CopyTextureCHROMIUM(GL_TEXTURE_2D, source_textures[i], texture_copy, - GL_RGB, GL_UNSIGNED_BYTE, false, true, false); + gl->CopyTextureCHROMIUM(source_textures[i], texture_copy, GL_RGB, + GL_UNSIGNED_BYTE, false, true, false); gl->DeleteTextures(1, &source_textures[i]); source_textures[i] = texture_copy; @@ -582,9 +582,8 @@ // value down to get the expected result. // "flip_y == true" means to reverse the video orientation while // "flip_y == false" means to keep the intrinsic orientation. - gl->CopyTextureCHROMIUM(GL_TEXTURE_2D, source_texture, texture, - internal_format, type, flip_y, premultiply_alpha, - false); + gl->CopyTextureCHROMIUM(source_texture, texture, internal_format, type, + flip_y, premultiply_alpha, false); gl->DeleteTextures(1, &source_texture); gl->Flush();
diff --git a/mojo/application/public/interfaces/application_manager.mojom b/mojo/application/public/interfaces/application_manager.mojom index 458cd91..84d7e584 100644 --- a/mojo/application/public/interfaces/application_manager.mojom +++ b/mojo/application/public/interfaces/application_manager.mojom
@@ -7,6 +7,7 @@ import "mojo/application/public/interfaces/shell.mojom"; struct ApplicationInfo { + int32 id; string url; string qualifier; uint32 pid; @@ -20,9 +21,28 @@ // applications that the listener observes changes against. SetRunningApplications(array<ApplicationInfo> applications); - // Tells the listener about applications starting or ending. - ApplicationStarted(ApplicationInfo application); - ApplicationEnded(uint32 pid); + // Called when the application manager has started tracking an application. + // This happens when the application manager first handles a request to launch + // the application, and before any process or content handler is created for + // it. + ApplicationInstanceCreated(ApplicationInfo application); + + // Called when the application manager has stopped tracking an application. + // (i.e. when it has ended/quit). + ApplicationInstanceDestroyed(int32 id); + + // Called when a pid is available for the application. This could be because a + // process was created by the runner for it, or because an existing content + // handler process was assigned. + ApplicationPIDAvailable(int32 id, uint32 pid); +}; + +// Implemented by an object in the application manager associated with a +// specific instance. Tells it the PID for a process launched by the client. +// This interface is only available to callers of ApplicationManager:: +// CreateInstanceForHandle(). +interface PIDReceiver { + SetPID(uint32 pid); }; interface ApplicationManager { @@ -33,7 +53,8 @@ // request there. CreateInstanceForHandle(handle channel, string url, - mojo.CapabilityFilter filter); + mojo.CapabilityFilter filter, + PIDReceiver& pid_receiver); // Called by a child process every time it launches a process. This is needed // so that the ChildBroker class in the grandchild process can talk to the one
diff --git a/mojo/converters/surfaces/surfaces_type_converters.cc b/mojo/converters/surfaces/surfaces_type_converters.cc index 7f6cb16..ab77a5a 100644 --- a/mojo/converters/surfaces/surfaces_type_converters.cc +++ b/mojo/converters/surfaces/surfaces_type_converters.cc
@@ -591,7 +591,9 @@ transferable->filter = input.filter; transferable->size = Size::From(input.size); transferable->mailbox_holder = MailboxHolder::From(input.mailbox_holder); + transferable->read_lock_fences_enabled = input.read_lock_fences_enabled; transferable->is_software = input.is_software; + transferable->is_overlay_candidate = input.is_overlay_candidate; return transferable; } @@ -605,7 +607,9 @@ transferable.filter = input->filter; transferable.size = input->size.To<gfx::Size>(); transferable.mailbox_holder = input->mailbox_holder.To<gpu::MailboxHolder>(); + transferable.read_lock_fences_enabled = input->read_lock_fences_enabled; transferable.is_software = input->is_software; + transferable.is_overlay_candidate = input->is_overlay_candidate; return transferable; }
diff --git a/mojo/gpu/mojo_gles2_impl_autogen.cc b/mojo/gpu/mojo_gles2_impl_autogen.cc index 7821ba8..aca5f3f 100644 --- a/mojo/gpu/mojo_gles2_impl_autogen.cc +++ b/mojo/gpu/mojo_gles2_impl_autogen.cc
@@ -1489,8 +1489,7 @@ MojoGLES2MakeCurrent(context_); glTexImageIOSurface2DCHROMIUM(target, width, height, ioSurfaceId, plane); } -void MojoGLES2Impl::CopyTextureCHROMIUM(GLenum target, - GLenum source_id, +void MojoGLES2Impl::CopyTextureCHROMIUM(GLenum source_id, GLenum dest_id, GLint internalformat, GLenum dest_type, @@ -1498,12 +1497,11 @@ GLboolean unpack_premultiply_alpha, GLboolean unpack_unmultiply_alpha) { MojoGLES2MakeCurrent(context_); - glCopyTextureCHROMIUM(target, source_id, dest_id, internalformat, dest_type, + glCopyTextureCHROMIUM(source_id, dest_id, internalformat, dest_type, unpack_flip_y, unpack_premultiply_alpha, unpack_unmultiply_alpha); } -void MojoGLES2Impl::CopySubTextureCHROMIUM(GLenum target, - GLenum source_id, +void MojoGLES2Impl::CopySubTextureCHROMIUM(GLenum source_id, GLenum dest_id, GLint xoffset, GLint yoffset, @@ -1515,9 +1513,9 @@ GLboolean unpack_premultiply_alpha, GLboolean unpack_unmultiply_alpha) { MojoGLES2MakeCurrent(context_); - glCopySubTextureCHROMIUM(target, source_id, dest_id, xoffset, yoffset, x, y, - width, height, unpack_flip_y, - unpack_premultiply_alpha, unpack_unmultiply_alpha); + glCopySubTextureCHROMIUM(source_id, dest_id, xoffset, yoffset, x, y, width, + height, unpack_flip_y, unpack_premultiply_alpha, + unpack_unmultiply_alpha); } void MojoGLES2Impl::CompressedCopyTextureCHROMIUM(GLenum target, GLenum source_id, @@ -1525,19 +1523,6 @@ MojoGLES2MakeCurrent(context_); glCompressedCopyTextureCHROMIUM(target, source_id, dest_id); } -void MojoGLES2Impl::CompressedCopySubTextureCHROMIUM(GLenum target, - GLenum source_id, - GLenum dest_id, - GLint xoffset, - GLint yoffset, - GLint x, - GLint y, - GLsizei width, - GLsizei height) { - MojoGLES2MakeCurrent(context_); - glCompressedCopySubTextureCHROMIUM(target, source_id, dest_id, xoffset, - yoffset, x, y, width, height); -} void MojoGLES2Impl::DrawArraysInstancedANGLE(GLenum mode, GLint first, GLsizei count,
diff --git a/mojo/gpu/mojo_gles2_impl_autogen.h b/mojo/gpu/mojo_gles2_impl_autogen.h index ce84596..99fdad5 100644 --- a/mojo/gpu/mojo_gles2_impl_autogen.h +++ b/mojo/gpu/mojo_gles2_impl_autogen.h
@@ -691,16 +691,14 @@ GLsizei height, GLuint ioSurfaceId, GLuint plane) override; - void CopyTextureCHROMIUM(GLenum target, - GLenum source_id, + void CopyTextureCHROMIUM(GLenum source_id, GLenum dest_id, GLint internalformat, GLenum dest_type, GLboolean unpack_flip_y, GLboolean unpack_premultiply_alpha, GLboolean unpack_unmultiply_alpha) override; - void CopySubTextureCHROMIUM(GLenum target, - GLenum source_id, + void CopySubTextureCHROMIUM(GLenum source_id, GLenum dest_id, GLint xoffset, GLint yoffset, @@ -714,15 +712,6 @@ void CompressedCopyTextureCHROMIUM(GLenum target, GLenum source_id, GLenum dest_id) override; - void CompressedCopySubTextureCHROMIUM(GLenum target, - GLenum source_id, - GLenum dest_id, - GLint xoffset, - GLint yoffset, - GLint x, - GLint y, - GLsizei width, - GLsizei height) override; void DrawArraysInstancedANGLE(GLenum mode, GLint first, GLsizei count,
diff --git a/mojo/message_pump/message_pump_mojo.cc b/mojo/message_pump/message_pump_mojo.cc index 696e083..3f60dd7 100644 --- a/mojo/message_pump/message_pump_mojo.cc +++ b/mojo/message_pump/message_pump_mojo.cc
@@ -7,8 +7,10 @@ #include <stdint.h> #include <algorithm> +#include <map> #include <vector> +#include "base/containers/small_map.h" #include "base/debug/alias.h" #include "base/lazy_instance.h" #include "base/logging.h" @@ -16,6 +18,7 @@ #include "base/time/time.h" #include "mojo/message_pump/message_pump_mojo_handler.h" #include "mojo/message_pump/time_helper.h" +#include "mojo/public/c/system/wait_set.h" namespace mojo { namespace common { @@ -37,13 +40,6 @@ } // namespace -// State needed for one iteration of WaitMany. The first handle and flags -// corresponds to that of the control pipe. -struct MessagePumpMojo::WaitState { - std::vector<Handle> handles; - std::vector<MojoHandleSignals> wait_signals; -}; - struct MessagePumpMojo::RunState { RunState() : should_quit(false) {} @@ -61,6 +57,17 @@ CHECK_EQ(result, MOJO_RESULT_OK); CHECK(read_handle_.is_valid()); CHECK(write_handle_.is_valid()); + + MojoHandle handle; + result = MojoCreateWaitSet(&handle); + CHECK_EQ(result, MOJO_RESULT_OK); + wait_set_handle_.reset(Handle(handle)); + CHECK(wait_set_handle_.is_valid()); + + result = + MojoAddHandle(wait_set_handle_.get().value(), read_handle_.get().value(), + MOJO_HANDLE_SIGNAL_READABLE); + CHECK_EQ(result, MOJO_RESULT_OK); } MessagePumpMojo::~MessagePumpMojo() { @@ -96,9 +103,24 @@ bool inserted = deadline_handles_.insert(handle).second; DCHECK(inserted); } + + MojoResult result = MojoAddHandle(wait_set_handle_.get().value(), + handle.value(), wait_signals); + // Because stopping a HandleWatcher is now asynchronous, it's possible for the + // handle to no longer be open at this point. + CHECK(result == MOJO_RESULT_OK || result == MOJO_RESULT_INVALID_ARGUMENT); } void MessagePumpMojo::RemoveHandler(const Handle& handle) { + MojoResult result = + MojoRemoveHandle(wait_set_handle_.get().value(), handle.value()); + // At this point, it's possible that the handle has been closed, which would + // cause MojoRemoveHandle() to return MOJO_RESULT_INVALID_ARGUMENT. It's also + // possible for the handle to have already been removed, so all of the + // possible error codes are valid here. + CHECK(result == MOJO_RESULT_OK || result == MOJO_RESULT_NOT_FOUND || + result == MOJO_RESULT_INVALID_ARGUMENT); + handlers_.erase(handle); deadline_handles_.erase(handle); } @@ -172,51 +194,150 @@ } bool MessagePumpMojo::DoInternalWork(const RunState& run_state, bool block) { - const MojoDeadline deadline = block ? GetDeadlineForWait(run_state) : 0; - const WaitState wait_state = GetWaitState(); + bool did_work = block; + if (block) { + // If the wait isn't blocking (deadline == 0), there's no point in waiting. + // Wait sets do not require a wait operation to be performed in order to + // retreive any ready handles. Performing a wait with deadline == 0 is + // unnecessary work. + did_work = WaitForReadyHandles(run_state); + } - std::vector<MojoHandleSignalsState> states(wait_state.handles.size()); - const WaitManyResult wait_many_result = - WaitMany(wait_state.handles, wait_state.wait_signals, deadline, &states); - const MojoResult result = wait_many_result.result; - bool did_work = true; - if (result == MOJO_RESULT_OK) { - if (wait_many_result.index == 0) { - if (states[0].satisfied_signals & MOJO_HANDLE_SIGNAL_PEER_CLOSED) { - // The Mojo EDK is shutting down. The ThreadQuitHelper task in - // base::Thread won't get run since the control pipe depends on the EDK - // staying alive. So quit manually to avoid this thread hanging. - Quit(); - } else { - // Control pipe was written to. - ReadMessageRaw(read_handle_.get(), NULL, NULL, NULL, NULL, - MOJO_READ_MESSAGE_FLAG_MAY_DISCARD); - } - } else { - DCHECK(handlers_.find(wait_state.handles[wait_many_result.index]) != - handlers_.end()); - WillSignalHandler(); - handlers_[wait_state.handles[wait_many_result.index]] - .handler->OnHandleReady(wait_state.handles[wait_many_result.index]); - DidSignalHandler(); + did_work |= ProcessReadyHandles(); + did_work |= RemoveExpiredHandles(); + + return did_work; +} + +bool MessagePumpMojo::WaitForReadyHandles(const RunState& run_state) const { + const MojoDeadline deadline = GetDeadlineForWait(run_state); + const MojoResult wait_result = Wait( + wait_set_handle_.get(), MOJO_HANDLE_SIGNAL_READABLE, deadline, nullptr); + if (wait_result == MOJO_RESULT_OK) { + // Handles may be ready. Or not since wake-ups can be spurious in certain + // circumstances. + return true; + } else if (wait_result == MOJO_RESULT_DEADLINE_EXCEEDED) { + return false; + } + + base::debug::Alias(&wait_result); + // Unexpected result is likely fatal, crash so we can determine cause. + CHECK(false); + return false; +} + +bool MessagePumpMojo::ProcessReadyHandles() { + // Maximum number of handles to retrieve and process. Experimentally, the 95th + // percentile is 1 handle, and the long-term average is 1.1. However, this has + // been seen to reach >10 under heavy load. 8 is a hand-wavy compromise. + const uint32_t kMaxServiced = 8; + uint32_t num_ready_handles = kMaxServiced; + MojoHandle handles[kMaxServiced]; + MojoResult handle_results[kMaxServiced]; + + const MojoResult get_result = + MojoGetReadyHandles(wait_set_handle_.get().value(), &num_ready_handles, + handles, handle_results, nullptr); + CHECK(get_result == MOJO_RESULT_OK || get_result == MOJO_RESULT_SHOULD_WAIT); + if (get_result != MOJO_RESULT_OK) + return false; + + DCHECK(num_ready_handles); + DCHECK_LE(num_ready_handles, kMaxServiced); + // Do this in two steps, because notifying a handler may remove/add other + // handles that may have also been woken up. + // First, enumerate the IDs of the ready handles. Then, iterate over the + // handles and only take action if the ID hasn't changed. + // Since the size of this map is bounded by |kMaxServiced|, use a SmallMap to + // avoid the per-element allocation. + base::SmallMap<std::map<Handle, int>, kMaxServiced> ready_handles; + for (uint32_t i = 0; i < num_ready_handles; i++) { + const Handle handle = Handle(handles[i]); + // Skip the control handle. It's special. + if (handle.value() == read_handle_.get().value()) + continue; + DCHECK(handle.is_valid()); + const auto it = handlers_.find(handle); + // Skip handles that have been removed. This is possible because + // RemoveHandler() can be called with a handle that has been closed. Because + // the handle is closed, the MojoRemoveHandle() call in RemoveHandler() + // would have failed, but the handle is still in the wait set. Once the + // handle is retrieved using MojoGetReadyHandles(), it is implicitly removed + // from the set. The result is either the pending result that existed when + // the handle was closed, or |MOJO_RESULT_CANCELLED| to indicate that the + // handle was closed. + if (it == handlers_.end()) + continue; + ready_handles[handle] = it->second.id; + } + + for (uint32_t i = 0; i < num_ready_handles; i++) { + const Handle handle = Handle(handles[i]); + + // If the handle has been removed, or it's ID has changed, skip over it. + // If the handle's ID has changed, and it still satisfies its signals, + // then it'll be caught in the next message pump iteration. + const auto it = handlers_.find(handle); + if ((handle.value() != read_handle_.get().value()) && + (it == handlers_.end() || it->second.id != ready_handles[handle])) { + continue; } - } else { - switch (result) { + + switch (handle_results[i]) { case MOJO_RESULT_CANCELLED: case MOJO_RESULT_FAILED_PRECONDITION: - case MOJO_RESULT_INVALID_ARGUMENT: - RemoveInvalidHandle(wait_state, result, wait_many_result.index); + DVLOG(1) << "Error: " << handle_results[i] + << " handle: " << handle.value(); + if (handle.value() == read_handle_.get().value()) { + // The Mojo EDK is shutting down. The ThreadQuitHelper task in + // base::Thread won't get run since the control pipe depends on the + // EDK staying alive. So quit manually to avoid this thread hanging. + Quit(); + } else { + RemoveInvalidHandle(handle_results[i], handle); + } break; - case MOJO_RESULT_DEADLINE_EXCEEDED: - did_work = false; + case MOJO_RESULT_OK: + if (handle.value() == read_handle_.get().value()) { + DVLOG(1) << "Signaled control pipe"; + // Control pipe was written to. + ReadMessageRaw(read_handle_.get(), nullptr, nullptr, nullptr, nullptr, + MOJO_READ_MESSAGE_FLAG_MAY_DISCARD); + } else { + DVLOG(1) << "Handle ready: " << handle.value(); + SignalHandleReady(handle); + } break; default: - base::debug::Alias(&result); + base::debug::Alias(&i); + base::debug::Alias(&handle_results[i]); // Unexpected result is likely fatal, crash so we can determine cause. CHECK(false); } } + return true; +} +void MessagePumpMojo::RemoveInvalidHandle(MojoResult result, Handle handle) { + // TODO(sky): deal with control pipe going bad. + CHECK(result == MOJO_RESULT_FAILED_PRECONDITION || + result == MOJO_RESULT_CANCELLED || + result == MOJO_RESULT_DEADLINE_EXCEEDED); + // Indicates the control pipe went bad. + CHECK_NE(handle.value(), read_handle_.get().value()); + + auto it = handlers_.find(handle); + CHECK(it != handlers_.end()); + MessagePumpMojoHandler* handler = it->second.handler; + RemoveHandler(handle); + WillSignalHandler(); + handler->OnHandleError(handle, result); + DidSignalHandler(); +} + +bool MessagePumpMojo::RemoveExpiredHandles() { + bool removed = false; // Notify and remove any handlers whose time has expired. First, iterate over // the set of handles that have a deadline, and add the expired handles to a // map of <Handle, id>. Then, iterate over those expired handles and remove @@ -232,40 +353,20 @@ if (!it->second.deadline.is_null() && it->second.deadline < now) expired_handles[handle] = it->second.id; } - for (auto& pair : expired_handles) { + for (const auto& pair : expired_handles) { auto it = handlers_.find(pair.first); // Don't need to check deadline again since it can't change if id hasn't // changed. if (it != handlers_.end() && it->second.id == pair.second) { - MessagePumpMojoHandler* handler = handlers_[pair.first].handler; + MessagePumpMojoHandler* handler = it->second.handler; RemoveHandler(pair.first); WillSignalHandler(); handler->OnHandleError(pair.first, MOJO_RESULT_DEADLINE_EXCEEDED); DidSignalHandler(); - did_work = true; + removed = true; } } - return did_work; -} - -void MessagePumpMojo::RemoveInvalidHandle(const WaitState& wait_state, - MojoResult result, - uint32_t index) { - // TODO(sky): deal with control pipe going bad. - CHECK(result == MOJO_RESULT_INVALID_ARGUMENT || - result == MOJO_RESULT_FAILED_PRECONDITION || - result == MOJO_RESULT_CANCELLED); - CHECK_NE(index, 0u); // Indicates the control pipe went bad. - - // Remove the handle first, this way if OnHandleError() tries to remove the - // handle our iterator isn't invalidated. - Handle handle = wait_state.handles[index]; - CHECK(handlers_.find(handle) != handlers_.end()); - MessagePumpMojoHandler* handler = handlers_[handle].handler; - RemoveHandler(handle); - WillSignalHandler(); - handler->OnHandleError(handle, result); - DidSignalHandler(); + return removed; } void MessagePumpMojo::SignalControlPipe() { @@ -282,20 +383,6 @@ CHECK_EQ(MOJO_RESULT_OK, result); } -MessagePumpMojo::WaitState MessagePumpMojo::GetWaitState() const { - WaitState wait_state; - wait_state.handles.push_back(read_handle_.get()); - wait_state.wait_signals.push_back( - MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED); - - for (HandleToHandler::const_iterator i = handlers_.begin(); - i != handlers_.end(); ++i) { - wait_state.handles.push_back(i->first); - wait_state.wait_signals.push_back(i->second.wait_signals); - } - return wait_state; -} - MojoDeadline MessagePumpMojo::GetDeadlineForWait( const RunState& run_state) const { const base::TimeTicks now(internal::NowTicks()); @@ -310,6 +397,13 @@ return deadline; } +void MessagePumpMojo::SignalHandleReady(Handle handle) { + DCHECK(handlers_.find(handle) != handlers_.end()); + WillSignalHandler(); + handlers_[handle].handler->OnHandleReady(handle); + DidSignalHandler(); +} + void MessagePumpMojo::WillSignalHandler() { FOR_EACH_OBSERVER(Observer, observers_, WillSignalHandler()); }
diff --git a/mojo/message_pump/message_pump_mojo.h b/mojo/message_pump/message_pump_mojo.h index 192438f..345bdb6 100644 --- a/mojo/message_pump/message_pump_mojo.h +++ b/mojo/message_pump/message_pump_mojo.h
@@ -71,7 +71,6 @@ private: struct RunState; - struct WaitState; // Contains the data needed to track a request to AddHandler(). struct Handler { @@ -94,19 +93,34 @@ // handle has become ready, |false| otherwise. bool DoInternalWork(const RunState& run_state, bool block); - // Removes the given invalid handle. This is called if MojoWaitMany finds an - // invalid handle. - void RemoveInvalidHandle(const WaitState& wait_state, - MojoResult result, - uint32_t result_index); + // Waits for handles in the wait set to become ready. Returns |true| if ready + // handles may be available, or |false| if the wait's deadline was exceeded. + // Note, ready handles may be unavailable, even though |true| was returned. + bool WaitForReadyHandles(const RunState& run_state) const; + + // Retrieves any 'ready' handles from the wait set, and runs the handler's + // OnHandleReady() or OnHandleError() functions as necessary. Returns |true| + // if any handles were ready and processed. + bool ProcessReadyHandles(); + + // Removes the given invalid handle. This is called if MojoGetReadyHandles + // finds an invalid or closed handle. + void RemoveInvalidHandle(MojoResult result, Handle handle); + + // Removes any handles that have expired their deadline. Runs the handler's + // OnHandleError() function with |MOJO_RESULT_DEADLINE_EXCEEDED| as the + // result. Returns |true| if any handles were removed. + bool RemoveExpiredHandles(); void SignalControlPipe(); - WaitState GetWaitState() const; - - // Returns the deadline for the call to MojoWaitMany(). + // Returns the deadline for the call to MojoWait(). MojoDeadline GetDeadlineForWait(const RunState& run_state) const; + // Run |OnHandleReady()| for the handler registered with |handle|. |handle| + // must be registered. + void SignalHandleReady(Handle handle); + void WillSignalHandler(); void DidSignalHandler(); @@ -134,6 +148,8 @@ base::ObserverList<Observer> observers_; + // Mojo handle for the wait set. + ScopedHandle wait_set_handle_; // Used to wake up run loop from |SignalControlPipe()|. ScopedMessagePipeHandle read_handle_; ScopedMessagePipeHandle write_handle_;
diff --git a/mojo/message_pump/message_pump_mojo_unittest.cc b/mojo/message_pump/message_pump_mojo_unittest.cc index 5c8fbb40..805b141 100644 --- a/mojo/message_pump/message_pump_mojo_unittest.cc +++ b/mojo/message_pump/message_pump_mojo_unittest.cc
@@ -159,6 +159,35 @@ EXPECT_EQ(1, handler.error_count()); } +TEST(MessagePumpMojo, AddClosedHandle) { + base::MessageLoop message_loop(MessagePumpMojo::Create()); + CountingMojoHandler handler; + MessagePipe handles; + Handle closed_handle = handles.handle0.get(); + handles.handle0.reset(); + MessagePumpMojo::current()->AddHandler( + &handler, closed_handle, MOJO_HANDLE_SIGNAL_READABLE, base::TimeTicks()); + base::RunLoop run_loop; + run_loop.RunUntilIdle(); + MessagePumpMojo::current()->RemoveHandler(closed_handle); + EXPECT_EQ(0, handler.error_count()); + EXPECT_EQ(0, handler.success_count()); +} + +TEST(MessagePumpMojo, CloseAfterAdding) { + base::MessageLoop message_loop(MessagePumpMojo::Create()); + CountingMojoHandler handler; + MessagePipe handles; + MessagePumpMojo::current()->AddHandler(&handler, handles.handle0.get(), + MOJO_HANDLE_SIGNAL_READABLE, + base::TimeTicks()); + handles.handle0.reset(); + base::RunLoop run_loop; + run_loop.RunUntilIdle(); + EXPECT_EQ(1, handler.error_count()); + EXPECT_EQ(0, handler.success_count()); +} + } // namespace test } // namespace common } // namespace mojo
diff --git a/mojo/public/c/gles2/gles2_call_visitor_chromium_extension_autogen.h b/mojo/public/c/gles2/gles2_call_visitor_chromium_extension_autogen.h index 3344493..9414658 100644 --- a/mojo/public/c/gles2/gles2_call_visitor_chromium_extension_autogen.h +++ b/mojo/public/c/gles2/gles2_call_visitor_chromium_extension_autogen.h
@@ -183,16 +183,14 @@ (target, width, height, ioSurfaceId, plane)) VISIT_GL_CALL(CopyTextureCHROMIUM, void, - (GLenum target, - GLenum source_id, + (GLenum source_id, GLenum dest_id, GLint internalformat, GLenum dest_type, GLboolean unpack_flip_y, GLboolean unpack_premultiply_alpha, GLboolean unpack_unmultiply_alpha), - (target, - source_id, + (source_id, dest_id, internalformat, dest_type, @@ -201,8 +199,7 @@ unpack_unmultiply_alpha)) VISIT_GL_CALL(CopySubTextureCHROMIUM, void, - (GLenum target, - GLenum source_id, + (GLenum source_id, GLenum dest_id, GLint xoffset, GLint yoffset, @@ -213,8 +210,7 @@ GLboolean unpack_flip_y, GLboolean unpack_premultiply_alpha, GLboolean unpack_unmultiply_alpha), - (target, - source_id, + (source_id, dest_id, xoffset, yoffset, @@ -229,19 +225,6 @@ void, (GLenum target, GLenum source_id, GLenum dest_id), (target, source_id, dest_id)) -VISIT_GL_CALL( - CompressedCopySubTextureCHROMIUM, - void, - (GLenum target, - GLenum source_id, - GLenum dest_id, - GLint xoffset, - GLint yoffset, - GLint x, - GLint y, - GLsizei width, - GLsizei height), - (target, source_id, dest_id, xoffset, yoffset, x, y, width, height)) VISIT_GL_CALL(DrawArraysInstancedANGLE, void, (GLenum mode, GLint first, GLsizei count, GLsizei primcount),
diff --git a/mojo/public/cpp/bindings/binding.h b/mojo/public/cpp/bindings/binding.h index 6cb4e80..781f3f3 100644 --- a/mojo/public/cpp/bindings/binding.h +++ b/mojo/public/cpp/bindings/binding.h
@@ -58,6 +58,11 @@ // implementation runs on. If writing library code that has to work on different // types of threads callers may need to provide different waiter // implementations. +// +// This class is thread hostile while bound to a message pipe. All calls to this +// class must be from the thread that bound it. The interface implementation's +// methods will be called from the thread that bound this. If a Binding is not +// bound to a message pipe, it may be bound or destroyed on any thread. template <typename Interface> class Binding { public:
diff --git a/mojo/public/cpp/bindings/interface_ptr.h b/mojo/public/cpp/bindings/interface_ptr.h index 85761a2..2929a65 100644 --- a/mojo/public/cpp/bindings/interface_ptr.h +++ b/mojo/public/cpp/bindings/interface_ptr.h
@@ -24,12 +24,14 @@ // 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. // -// 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 -// InterfacePtrInfo (containing just the message pipe and any version -// information) using PassInterface(), pass it to a different thread, and -// create and bind a new InterfacePtr from that thread. +// This class is thread hostile, as is the local proxy it manages, while bound +// to a message pipe. All calls to this class or the proxy should be from the +// same thread that bound it. If you need to move the proxy to a different +// thread, extract the InterfacePtrInfo (containing just the message pipe and +// any version information) using PassInterface(), pass it to a different +// thread, and create and bind a new InterfacePtr from that thread. If an +// InterfacePtr is not bound to a message pipe, it may be bound or destroyed on +// any thread. template <typename Interface> class InterfacePtr { DISALLOW_COPY_AND_ASSIGN_WITH_MOVE_FOR_BIND(InterfacePtr)
diff --git a/mojo/public/cpp/bindings/lib/connector.cc b/mojo/public/cpp/bindings/lib/connector.cc index e6f2d83..854a80c 100644 --- a/mojo/public/cpp/bindings/lib/connector.cc +++ b/mojo/public/cpp/bindings/lib/connector.cc
@@ -212,6 +212,7 @@ void Connector::WaitToReadMore() { CHECK(!async_wait_id_); + CHECK(!paused_); async_wait_id_ = waiter_->AsyncWait(message_pipe_.get().value(), MOJO_HANDLE_SIGNAL_READABLE, MOJO_DEADLINE_INDEFINITE, @@ -220,6 +221,8 @@ } bool Connector::ReadSingleMessage(MojoResult* read_result) { + CHECK(!paused_); + bool receiver_result = false; // Detect if |this| was destroyed during message dispatch. Allow for the @@ -263,6 +266,9 @@ if (!ReadSingleMessage(&rv)) return; + if (paused_) + return; + if (rv == MOJO_RESULT_SHOULD_WAIT) { // ReadSingleMessage could end up calling HandleError which resets // message_pipe_ to a dummy one that is closed. The old EDK will see the
diff --git a/mojo/public/cpp/bindings/strong_binding.h b/mojo/public/cpp/bindings/strong_binding.h index 777b512..0b2ce66 100644 --- a/mojo/public/cpp/bindings/strong_binding.h +++ b/mojo/public/cpp/bindings/strong_binding.h
@@ -44,6 +44,9 @@ // // instance of StronglyBound. // } // }; +// +// This class is thread hostile once it is bound to a message pipe. Until it is +// bound, it may be bound or destroyed on any thread. template <typename Interface> class StrongBinding { MOJO_MOVE_ONLY_TYPE(StrongBinding)
diff --git a/mojo/public/cpp/bindings/tests/connector_unittest.cc b/mojo/public/cpp/bindings/tests/connector_unittest.cc index 6669764..879abfa 100644 --- a/mojo/public/cpp/bindings/tests/connector_unittest.cc +++ b/mojo/public/cpp/bindings/tests/connector_unittest.cc
@@ -24,14 +24,13 @@ class MessageAccumulator : public MessageReceiver { public: MessageAccumulator() {} - explicit MessageAccumulator(const base::Closure& closure) - : closure_(closure) {} + explicit MessageAccumulator(const Closure& closure) : closure_(closure) {} bool Accept(Message* message) override { queue_.Push(message); if (!closure_.is_null()) closure_.Run(); - closure_.Reset(); + closure_.reset(); return true; } @@ -43,9 +42,11 @@ closure_ = closure; } + size_t size() const { return queue_.size(); } + private: MessageQueue queue_; - base::Closure closure_; + Closure closure_; }; class ConnectorDeletingMessageAccumulator : public MessageAccumulator { @@ -494,6 +495,37 @@ EXPECT_TRUE(connector1.is_valid()); } +TEST_F(ConnectorTest, PauseWithQueuedMessages) { + internal::Connector connector0(std::move(handle0_), + internal::Connector::SINGLE_THREADED_SEND); + internal::Connector connector1(std::move(handle1_), + internal::Connector::SINGLE_THREADED_SEND); + + const char kText[] = "hello world"; + + Message message; + AllocMessage(kText, &message); + + // Queue up two messages. + connector0.Accept(&message); + connector0.Accept(&message); + + base::RunLoop run_loop; + // Configure the accumulator such that it pauses after the first message is + // received. + MessageAccumulator accumulator([&connector1, &run_loop]() { + connector1.PauseIncomingMethodCallProcessing(); + run_loop.Quit(); + }); + connector1.set_incoming_receiver(&accumulator); + + run_loop.Run(); + + // As we paused after the first message we should only have gotten one + // message. + ASSERT_EQ(1u, accumulator.size()); +} + } // namespace } // namespace test } // namespace mojo
diff --git a/mojo/public/cpp/bindings/tests/message_queue.h b/mojo/public/cpp/bindings/tests/message_queue.h index c3091db..823758d 100644 --- a/mojo/public/cpp/bindings/tests/message_queue.h +++ b/mojo/public/cpp/bindings/tests/message_queue.h
@@ -29,6 +29,8 @@ // ownership of its handles to the given |message|. void Pop(Message* message); + size_t size() const { return queue_.size(); } + private: void Pop();
diff --git a/mojo/runner/BUILD.gn b/mojo/runner/BUILD.gn index 64ba3f87..3a4f30e 100644 --- a/mojo/runner/BUILD.gn +++ b/mojo/runner/BUILD.gn
@@ -226,6 +226,8 @@ shared_library("bootstrap") { sources = [ "android/bootstrap.cc", + "register_local_aliases.cc", + "register_local_aliases.h", ] deps = [ ":jni_headers",
diff --git a/mojo/runner/host/child_process_host.cc b/mojo/runner/host/child_process_host.cc index a648edb..f8777db5 100644 --- a/mojo/runner/host/child_process_host.cc +++ b/mojo/runner/host/child_process_host.cc
@@ -68,7 +68,8 @@ CHECK(!controller_) << "Destroying ChildProcessHost before calling Join"; } -void ChildProcessHost::Start() { +void ChildProcessHost::Start( + const base::Callback<void(base::ProcessId)>& pid_available_callback) { DCHECK(!child_process_.IsValid()); DCHECK(child_message_pipe_.is_valid()); @@ -93,11 +94,8 @@ launch_process_runner_->PostTaskAndReply( FROM_HERE, base::Bind(&ChildProcessHost::DoLaunch, base::Unretained(this)), - base::Bind(&ChildProcessHost::DidStart, weak_factory_.GetWeakPtr())); -} - -base::ProcessId ChildProcessHost::GetChildPID() const { - return child_process_.IsValid() ? child_process_.Pid() : base::kNullProcessId; + base::Bind(&ChildProcessHost::DidStart, weak_factory_.GetWeakPtr(), + pid_available_callback)); } int ChildProcessHost::Join() { @@ -129,10 +127,13 @@ controller_->ExitNow(exit_code); } -void ChildProcessHost::DidStart() { +void ChildProcessHost::DidStart( + const base::Callback<void(base::ProcessId)>& pid_available_callback) { DVLOG(2) << "ChildProcessHost::DidStart()"; - if (!child_process_.IsValid()) { + if (child_process_.IsValid()) { + pid_available_callback.Run(child_process_.Pid()); + } else { LOG(ERROR) << "Failed to start child process"; AppCompleted(MOJO_RESULT_UNKNOWN); }
diff --git a/mojo/runner/host/child_process_host.h b/mojo/runner/host/child_process_host.h index 1f4f757e..dc26087 100644 --- a/mojo/runner/host/child_process_host.h +++ b/mojo/runner/host/child_process_host.h
@@ -52,9 +52,8 @@ // |Start()|s the child process; calls |DidStart()| (on the thread on which // |Start()| was called) when the child has been started (or failed to start). - void Start(); - - base::ProcessId GetChildPID() const; + void Start( + const base::Callback<void(base::ProcessId)>& pid_available_callback); // Waits for the child process to terminate, and returns its exit code. int Join(); @@ -66,7 +65,8 @@ protected: // virtual for testing. - virtual void DidStart(); + virtual void DidStart( + const base::Callback<void(base::ProcessId)>& pid_available_callback); private: void DoLaunch();
diff --git a/mojo/runner/host/child_process_host_unittest.cc b/mojo/runner/host/child_process_host_unittest.cc index 0ca49c7..6cff8ef 100644 --- a/mojo/runner/host/child_process_host_unittest.cc +++ b/mojo/runner/host/child_process_host_unittest.cc
@@ -6,6 +6,7 @@ #include "mojo/runner/host/child_process_host.h" +#include "base/bind.h" #include "base/logging.h" #include "base/macros.h" #include "base/message_loop/message_loop.h" @@ -20,6 +21,10 @@ namespace runner { namespace { +using PidAvailableCallback = base::Callback<void(base::ProcessId)>; + +void EmptyCallback(base::ProcessId pid) {} + // Subclass just so we can observe |DidStart()|. class TestChildProcessHost : public ChildProcessHost { public: @@ -27,8 +32,8 @@ : ChildProcessHost(launch_process_runner, false, base::FilePath()) {} ~TestChildProcessHost() override {} - void DidStart() override { - ChildProcessHost::DidStart(); + void DidStart(const PidAvailableCallback& pid_available_callback) override { + ChildProcessHost::DidStart(pid_available_callback); base::MessageLoop::current()->QuitWhenIdle(); } @@ -73,7 +78,7 @@ embedder::ScopedPlatformHandle()); TestChildProcessHost child_process_host(blocking_pool.get()); - child_process_host.Start(); + child_process_host.Start(base::Bind(&EmptyCallback)); message_loop.Run(); child_process_host.ExitNow(123); int exit_code = child_process_host.Join();
diff --git a/mojo/runner/host/in_process_native_runner.cc b/mojo/runner/host/in_process_native_runner.cc index 70ccfe7..6f5b47f 100644 --- a/mojo/runner/host/in_process_native_runner.cc +++ b/mojo/runner/host/in_process_native_runner.cc
@@ -36,6 +36,7 @@ const base::FilePath& app_path, bool start_sandboxed, InterfaceRequest<Application> application_request, + const base::Callback<void(base::ProcessId)>& pid_available_callback, const base::Closure& app_completed_callback) { app_path_ = app_path; @@ -50,6 +51,7 @@ DCHECK(!thread_); thread_.reset(new base::DelegateSimpleThread(this, "app_thread")); thread_->Start(); + pid_available_callback.Run(base::kNullProcessId); } void InProcessNativeRunner::InitHost( @@ -58,10 +60,6 @@ NOTREACHED(); // Can't host another process in this runner. } -base::ProcessId InProcessNativeRunner::GetApplicationPID() const { - return base::kNullProcessId; -} - void InProcessNativeRunner::Run() { DVLOG(2) << "Loading/running Mojo app in process from library: " << app_path_.value()
diff --git a/mojo/runner/host/in_process_native_runner.h b/mojo/runner/host/in_process_native_runner.h index e118df1a..8d51dccc 100644 --- a/mojo/runner/host/in_process_native_runner.h +++ b/mojo/runner/host/in_process_native_runner.h
@@ -30,13 +30,14 @@ ~InProcessNativeRunner() override; // NativeRunner: - void Start(const base::FilePath& app_path, - bool start_sandboxed, - InterfaceRequest<Application> application_request, - const base::Closure& app_completed_callback) override; + void Start( + const base::FilePath& app_path, + bool start_sandboxed, + InterfaceRequest<Application> application_request, + const base::Callback<void(base::ProcessId)>& pid_available_callback, + const base::Closure& app_completed_callback) override; void InitHost(ScopedHandle channel, InterfaceRequest<Application> application_request) override; - base::ProcessId GetApplicationPID() const override; private: // |base::DelegateSimpleThread::Delegate| method:
diff --git a/mojo/runner/host/out_of_process_native_runner.cc b/mojo/runner/host/out_of_process_native_runner.cc index 19f6e40..46316c6 100644 --- a/mojo/runner/host/out_of_process_native_runner.cc +++ b/mojo/runner/host/out_of_process_native_runner.cc
@@ -32,6 +32,7 @@ const base::FilePath& app_path, bool start_sandboxed, InterfaceRequest<Application> application_request, + const base::Callback<void(base::ProcessId)>& pid_available_callback, const base::Closure& app_completed_callback) { app_path_ = app_path; @@ -40,7 +41,7 @@ child_process_host_.reset( new ChildProcessHost(launch_process_runner_, start_sandboxed, app_path)); - child_process_host_->Start(); + child_process_host_->Start(pid_available_callback); child_process_host_->StartApp( std::move(application_request), @@ -58,10 +59,6 @@ base::Unretained(this))); } -base::ProcessId OutOfProcessNativeRunner::GetApplicationPID() const { - return child_process_host_->GetChildPID(); -} - void OutOfProcessNativeRunner::AppCompleted(int32_t result) { DVLOG(2) << "OutOfProcessNativeRunner::AppCompleted(" << result << ")";
diff --git a/mojo/runner/host/out_of_process_native_runner.h b/mojo/runner/host/out_of_process_native_runner.h index 96e1fd8..7c00c75 100644 --- a/mojo/runner/host/out_of_process_native_runner.h +++ b/mojo/runner/host/out_of_process_native_runner.h
@@ -30,13 +30,14 @@ ~OutOfProcessNativeRunner() override; // NativeRunner: - void Start(const base::FilePath& app_path, - bool start_sandboxed, - InterfaceRequest<Application> application_request, - const base::Closure& app_completed_callback) override; + void Start( + const base::FilePath& app_path, + bool start_sandboxed, + InterfaceRequest<Application> application_request, + const base::Callback<void(base::ProcessId)>& pid_available_callback, + const base::Closure& app_completed_callback) override; void InitHost(ScopedHandle channel, InterfaceRequest<Application> application_request) override; - base::ProcessId GetApplicationPID() const override; private: // |ChildController::StartApp()| callback:
diff --git a/mojo/shell/application_instance.cc b/mojo/shell/application_instance.cc index b4857482..4043529 100644 --- a/mojo/shell/application_instance.cc +++ b/mojo/shell/application_instance.cc
@@ -8,6 +8,7 @@ #include <utility> +#include "base/atomic_sequence_num.h" #include "base/bind.h" #include "base/stl_util.h" #include "mojo/application/public/interfaces/content_handler.mojom.h" @@ -17,6 +18,13 @@ namespace mojo { namespace shell { +namespace { + +base::StaticAtomicSequenceNumber g_instance_id; + +const int kInvalidInstanceId = -1; + +} // namespace ApplicationInstance::ApplicationInstance( ApplicationPtr application, @@ -25,6 +33,7 @@ uint32_t requesting_content_handler_id, const base::Closure& on_application_end) : manager_(manager), + id_(GenerateUniqueID()), identity_(identity), allow_any_application_(identity.filter().size() == 1 && identity.filter().count("*") == 1), @@ -32,6 +41,7 @@ on_application_end_(on_application_end), application_(std::move(application)), binding_(this), + pid_receiver_binding_(this), queue_requests_(false), native_runner_(nullptr), pid_(base::kNullProcessId) {} @@ -61,11 +71,11 @@ void ApplicationInstance::SetNativeRunner(NativeRunner* native_runner) { native_runner_ = native_runner; - pid_ = native_runner_->GetApplicationPID(); } -base::ProcessId ApplicationInstance::GetProcessId() const { - return pid_; +void ApplicationInstance::BindPIDReceiver( + InterfaceRequest<mojom::PIDReceiver> pid_receiver) { + pid_receiver_binding_.Bind(std::move(pid_receiver)); } // Shell implementation: @@ -113,6 +123,19 @@ base::Unretained(this))); } +void ApplicationInstance::SetPID(uint32_t pid) { + // This will call us back to update pid_. + manager_->ApplicationPIDAvailable(id_, pid); +} + +// static +int ApplicationInstance::GenerateUniqueID() { + int id = g_instance_id.GetNext() + 1; + CHECK_NE(0, id); + CHECK_NE(kInvalidInstanceId, id); + return id; +} + void ApplicationInstance::CallAcceptConnection( scoped_ptr<ConnectToApplicationParams> params) { params->connect_callback().Run(requesting_content_handler_id_);
diff --git a/mojo/shell/application_instance.h b/mojo/shell/application_instance.h index a8877edc..a7795eb 100644 --- a/mojo/shell/application_instance.h +++ b/mojo/shell/application_instance.h
@@ -14,6 +14,7 @@ #include "base/memory/scoped_ptr.h" #include "base/process/process_handle.h" #include "mojo/application/public/interfaces/application.mojom.h" +#include "mojo/application/public/interfaces/application_manager.mojom.h" #include "mojo/application/public/interfaces/shell.mojom.h" #include "mojo/public/cpp/bindings/binding.h" #include "mojo/shell/capability_filter.h" @@ -29,7 +30,8 @@ // Encapsulates a connection to an instance of an application, tracked by the // shell's ApplicationManager. -class ApplicationInstance : public Shell { +class ApplicationInstance : public Shell, + public mojom::PIDReceiver { public: // |requesting_content_handler_id| is the id of the content handler that // loaded this app. If the app was not loaded by a content handler the id @@ -49,10 +51,13 @@ // Required before GetProcessId can be called. void SetNativeRunner(NativeRunner* native_runner); - base::ProcessId GetProcessId() const; + void BindPIDReceiver(InterfaceRequest<mojom::PIDReceiver> pid_receiver); Application* application() { return application_.get(); } const Identity& identity() const { return identity_; } + int id() const { return id_; } + base::ProcessId pid() const { return pid_; } + void set_pid(base::ProcessId pid) { pid_ = pid; } base::Closure on_application_end() const { return on_application_end_; } void set_requesting_content_handler_id(uint32_t id) { requesting_content_handler_id_ = id; @@ -71,6 +76,11 @@ const ConnectToApplicationCallback& callback) override; void QuitApplication() override; + // PIDReceiver implementation: + void SetPID(uint32_t pid) override; + + static int GenerateUniqueID(); + void CallAcceptConnection(scoped_ptr<ConnectToApplicationParams> params); void OnConnectionError(); @@ -80,12 +90,17 @@ void DestroyRunner(); ApplicationManager* const manager_; + // An id that identifies this instance. Distinct from pid, as a single process + // may vend multiple application instances, and this object may exist before a + // process is launched. + const int id_; const Identity identity_; const bool allow_any_application_; uint32_t requesting_content_handler_id_; base::Closure on_application_end_; ApplicationPtr application_; Binding<Shell> binding_; + Binding<mojom::PIDReceiver> pid_receiver_binding_; bool queue_requests_; std::vector<ConnectToApplicationParams*> queued_client_requests_; NativeRunner* native_runner_;
diff --git a/mojo/shell/application_manager.cc b/mojo/shell/application_manager.cc index 58473fc4..e8d4263 100644 --- a/mojo/shell/application_manager.cc +++ b/mojo/shell/application_manager.cc
@@ -12,6 +12,7 @@ #include "base/command_line.h" #include "base/logging.h" #include "base/macros.h" +#include "base/process/process.h" #include "base/stl_util.h" #include "base/strings/string_util.h" #include "base/trace_event/trace_event.h" @@ -120,9 +121,11 @@ return it != identity_to_instance_.end() ? it->second : nullptr; } -void ApplicationManager::CreateInstanceForHandle(ScopedHandle channel, - const GURL& url, - CapabilityFilterPtr filter) { +void ApplicationManager::CreateInstanceForHandle( + ScopedHandle channel, + const GURL& url, + CapabilityFilterPtr filter, + InterfaceRequest<mojom::PIDReceiver> pid_receiver) { // Instances created by others are considered unique, and thus have no // identity. As such they cannot be connected to by anyone else, and so we // never call ConnectToClient(). @@ -134,6 +137,7 @@ ApplicationInstance* instance = nullptr; InterfaceRequest<Application> application_request = CreateInstance(target_id, base::Closure(), &instance); + instance->BindPIDReceiver(std::move(pid_receiver)); scoped_ptr<NativeRunner> runner = native_runner_factory_->Create(base::FilePath()); runner->InitHost(std::move(channel), std::move(application_request)); @@ -151,6 +155,21 @@ listeners_.AddInterfacePtr(std::move(listener)); } +void ApplicationManager::ApplicationPIDAvailable( + int id, + base::ProcessId pid) { + for (auto& instance : identity_to_instance_) { + if (instance.second->id() == id) { + instance.second->set_pid(pid); + break; + } + } + listeners_.ForAllPtrs( + [this, id, pid](mojom::ApplicationManagerListener* listener) { + listener->ApplicationPIDAvailable(id, pid); + }); +} + InterfaceRequest<Application> ApplicationManager::CreateAndConnectToInstance( scoped_ptr<ConnectToApplicationParams> params, ApplicationInstance** resulting_instance) { @@ -179,7 +198,7 @@ CreateApplicationInfoForInstance(instance); listeners_.ForAllPtrs( [this, &application_info](mojom::ApplicationManagerListener* listener) { - listener->ApplicationStarted(application_info.Clone()); + listener->ApplicationInstanceCreated(application_info.Clone()); }); instance->InitializeApplication(); if (resulting_instance) @@ -276,6 +295,8 @@ path.AsUTF8Unsafe()); scoped_ptr<NativeRunner> runner = native_runner_factory_->Create(path); runner->Start(path, start_sandboxed, std::move(application_request), + base::Bind(&ApplicationManager::ApplicationPIDAvailable, + weak_ptr_factory_.GetWeakPtr(), instance->id()), base::Bind(&ApplicationManager::CleanupRunner, weak_ptr_factory_.GetWeakPtr(), runner.get())); instance->SetNativeRunner(runner.get()); @@ -300,9 +321,13 @@ mojom::ApplicationInfoPtr ApplicationManager::CreateApplicationInfoForInstance( ApplicationInstance* instance) const { mojom::ApplicationInfoPtr info(mojom::ApplicationInfo::New()); + info->id = instance->id(); info->url = instance->identity().url().spec(); info->qualifier = instance->identity().qualifier(); - info->pid = instance->GetProcessId(); + if (instance->identity().url().spec() == "mojo://shell/") + info->pid = base::Process::Current().Pid(); + else + info->pid = instance->pid(); return info; } @@ -314,12 +339,12 @@ // Remove the shell. auto it = identity_to_instance_.find(identity); DCHECK(it != identity_to_instance_.end()); - base::ProcessId pid = instance->GetProcessId(); + int id = instance->id(); delete it->second; identity_to_instance_.erase(it); listeners_.ForAllPtrs( - [this, pid](mojom::ApplicationManagerListener* listener) { - listener->ApplicationEnded(pid); + [this, id](mojom::ApplicationManagerListener* listener) { + listener->ApplicationInstanceDestroyed(id); }); if (!on_application_end.is_null()) on_application_end.Run();
diff --git a/mojo/shell/application_manager.h b/mojo/shell/application_manager.h index e51672c..ebe825e 100644 --- a/mojo/shell/application_manager.h +++ b/mojo/shell/application_manager.h
@@ -95,13 +95,17 @@ ApplicationInstance* GetApplicationInstance(const Identity& identity) const; - void CreateInstanceForHandle(ScopedHandle channel, - const GURL& url, - CapabilityFilterPtr filter); + void CreateInstanceForHandle( + ScopedHandle channel, + const GURL& url, + CapabilityFilterPtr filter, + InterfaceRequest<mojom::PIDReceiver> pid_receiver); void AddListener(mojom::ApplicationManagerListenerPtr listener); void GetRunningApplications( const Callback<void(Array<mojom::ApplicationInfoPtr>)>& callback); + void ApplicationPIDAvailable(int id, base::ProcessId pid); + private: using IdentityToInstanceMap = std::map<Identity, ApplicationInstance*>; using URLToLoaderMap = std::map<GURL, ApplicationLoader*>;
diff --git a/mojo/shell/application_manager_apptest.cc b/mojo/shell/application_manager_apptest.cc index 4d84d34..363f34b4 100644 --- a/mojo/shell/application_manager_apptest.cc +++ b/mojo/shell/application_manager_apptest.cc
@@ -143,10 +143,12 @@ for (size_t i = 0; i < applications.size(); ++i) names_.insert(applications[i]->url); } - void ApplicationStarted(mojom::ApplicationInfoPtr application) override { + void ApplicationInstanceCreated( + mojom::ApplicationInfoPtr application) override { names_.insert(application->url); } - void ApplicationEnded(uint32_t pid) override {} + void ApplicationInstanceDestroyed(int id) override {} + void ApplicationPIDAvailable(int id, uint32_t pid) override {} std::set<std::string> names_; Binding<mojom::ApplicationManagerListener> binding_;
diff --git a/mojo/shell/application_manager_apptest_driver.cc b/mojo/shell/application_manager_apptest_driver.cc index 06336fe8..8eb919bc 100644 --- a/mojo/shell/application_manager_apptest_driver.cc +++ b/mojo/shell/application_manager_apptest_driver.cc
@@ -105,9 +105,13 @@ mojo::shell::test::mojom::CreateInstanceForHandleTest::Name_); filter->filter.insert("mojo:mojo_shell_apptests", std::move(test_interfaces)); + mojo::shell::mojom::PIDReceiverPtr receiver; + mojo::InterfaceRequest<mojo::shell::mojom::PIDReceiver> request = + GetProxy(&receiver); application_manager->CreateInstanceForHandle( mojo::ScopedHandle(mojo::Handle(handle.release().value())), - "exe:application_manager_apptest_target", std::move(filter)); + "exe:application_manager_apptest_target", std::move(filter), + std::move(request)); // Put the other end on the command line used to launch the target. platform_channel_pair.PrepareToPassClientHandleToChildProcess( &child_command_line, &handle_passing_info);
diff --git a/mojo/shell/native_runner.h b/mojo/shell/native_runner.h index f36f443e..00ccfd9f 100644 --- a/mojo/shell/native_runner.h +++ b/mojo/shell/native_runner.h
@@ -29,25 +29,18 @@ virtual ~NativeRunner() {} // Loads the app in the file at |app_path| and runs it on some other - // thread/process. If |cleanup| is |DELETE|, this takes ownership of the file. - // |app_completed_callback| is posted (to the thread on which |Start()| was - // called) after |MojoMain()| completes. - // TODO(vtl): |app_path| and |cleanup| should probably be moved to the - // factory's Create(). Rationale: The factory may need information from the - // file to decide what kind of NativeRunner to make. - virtual void Start(const base::FilePath& app_path, - bool start_sandboxed, - InterfaceRequest<Application> application_request, - const base::Closure& app_completed_callback) = 0; + // thread/process. + virtual void Start( + const base::FilePath& app_path, + bool start_sandboxed, + InterfaceRequest<Application> application_request, + const base::Callback<void(base::ProcessId)>& pid_available_callback, + const base::Closure& app_completed_callback) = 0; // Like Start(), but used to initialize the host for a child process started // by someone else. Provides |application_request| via |channel|. virtual void InitHost(ScopedHandle channel, InterfaceRequest<Application> application_request) = 0; - - // Returns the pid of the application. This will be base::kNullProcessId if - // the application was run in process. - virtual base::ProcessId GetApplicationPID() const = 0; }; class NativeRunnerFactory {
diff --git a/mojo/shell/shell_application_delegate.cc b/mojo/shell/shell_application_delegate.cc index d5c664d..650740d 100644 --- a/mojo/shell/shell_application_delegate.cc +++ b/mojo/shell/shell_application_delegate.cc
@@ -37,9 +37,10 @@ void ShellApplicationDelegate::CreateInstanceForHandle( ScopedHandle channel, const String& url, - CapabilityFilterPtr filter) { + CapabilityFilterPtr filter, + InterfaceRequest<mojom::PIDReceiver> pid_receiver) { manager_->CreateInstanceForHandle(std::move(channel), GURL(url), - std::move(filter)); + std::move(filter), std::move(pid_receiver)); } void ShellApplicationDelegate::RegisterProcessWithBroker(
diff --git a/mojo/shell/shell_application_delegate.h b/mojo/shell/shell_application_delegate.h index 62bbaeb..d2dd94b 100644 --- a/mojo/shell/shell_application_delegate.h +++ b/mojo/shell/shell_application_delegate.h
@@ -37,9 +37,11 @@ InterfaceRequest<mojom::ApplicationManager> request) override; // Overridden from mojom::ApplicationManager: - void CreateInstanceForHandle(ScopedHandle channel, - const String& url, - CapabilityFilterPtr filter) override; + void CreateInstanceForHandle( + ScopedHandle channel, + const String& url, + CapabilityFilterPtr filter, + InterfaceRequest<mojom::PIDReceiver> pid_receiver) override; void RegisterProcessWithBroker(uint32_t pid, ScopedHandle pipe) override; void AddListener( mojom::ApplicationManagerListenerPtr listener) override;
diff --git a/native_client_sdk/doc_generated/pepper_beta/cpp/audio__buffer_8h__incl.png b/native_client_sdk/doc_generated/pepper_beta/cpp/audio__buffer_8h__incl.png index f0dd5317..e4f7864 100644 --- a/native_client_sdk/doc_generated/pepper_beta/cpp/audio__buffer_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_beta/cpp/audio__buffer_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_beta/cpp/audio__encoder_8h__incl.png b/native_client_sdk/doc_generated/pepper_beta/cpp/audio__encoder_8h__incl.png index 9eb1bf12..6613246 100644 --- a/native_client_sdk/doc_generated/pepper_beta/cpp/audio__encoder_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_beta/cpp/audio__encoder_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_beta/cpp/classpp_1_1_var.html b/native_client_sdk/doc_generated/pepper_beta/cpp/classpp_1_1_var.html index e6c84eaa..6d653cf 100644 --- a/native_client_sdk/doc_generated/pepper_beta/cpp/classpp_1_1_var.html +++ b/native_client_sdk/doc_generated/pepper_beta/cpp/classpp_1_1_var.html
@@ -599,7 +599,7 @@ </div> <div class="memdoc"> <p>This function determines if this <code><a class="el" href="classpp_1_1_var.html" title="A generic type used for passing data types between the module and the page.">Var</a></code> is a number. </p> -<dl class="return"><dt><b>Returns:</b></dt><dd>true if this <code><a class="el" href="classpp_1_1_var.html" title="A generic type used for passing data types between the module and the page.">Var</a></code> is an int32 or double number, otherwise false. </dd></dl> +<dl class="return"><dt><b>Returns:</b></dt><dd>true if this <code><a class="el" href="classpp_1_1_var.html" title="A generic type used for passing data types between the module and the page.">Var</a></code> is an int32_t or double number, otherwise false. </dd></dl> </div> </div> <a class="anchor" id="a79ed26c49d64b536619a1ee574848a36"></a><!-- doxytag: member="pp::Var::is_object" ref="a79ed26c49d64b536619a1ee574848a36" args="() const " -->
diff --git a/native_client_sdk/doc_generated/pepper_beta/cpp/completion__callback_8h__incl.png b/native_client_sdk/doc_generated/pepper_beta/cpp/completion__callback_8h__incl.png index 06d514f..78d0f0e 100644 --- a/native_client_sdk/doc_generated/pepper_beta/cpp/completion__callback_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_beta/cpp/completion__callback_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_beta/cpp/completion__callback__factory_8h__incl.png b/native_client_sdk/doc_generated/pepper_beta/cpp/completion__callback__factory_8h__incl.png index c2f590e..8b9d5194 100644 --- a/native_client_sdk/doc_generated/pepper_beta/cpp/completion__callback__factory_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_beta/cpp/completion__callback__factory_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_beta/cpp/compositor_8h__incl.png b/native_client_sdk/doc_generated/pepper_beta/cpp/compositor_8h__incl.png index 753eea6..286df56 100644 --- a/native_client_sdk/doc_generated/pepper_beta/cpp/compositor_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_beta/cpp/compositor_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_beta/cpp/compositor__layer_8h__incl.png b/native_client_sdk/doc_generated/pepper_beta/cpp/compositor__layer_8h__incl.png index 7f643cb..339a781 100644 --- a/native_client_sdk/doc_generated/pepper_beta/cpp/compositor__layer_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_beta/cpp/compositor__layer_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_beta/cpp/core_8h__incl.png b/native_client_sdk/doc_generated/pepper_beta/cpp/core_8h__incl.png index 3ffa9e8..1423f71d 100644 --- a/native_client_sdk/doc_generated/pepper_beta/cpp/core_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_beta/cpp/core_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_beta/cpp/file__io_8h__incl.png b/native_client_sdk/doc_generated/pepper_beta/cpp/file__io_8h__incl.png index 41185888..064edae 100644 --- a/native_client_sdk/doc_generated/pepper_beta/cpp/file__io_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_beta/cpp/file__io_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_beta/cpp/graphics__3d_8h__incl.png b/native_client_sdk/doc_generated/pepper_beta/cpp/graphics__3d_8h__incl.png index 025025c..d8a0b23 100644 --- a/native_client_sdk/doc_generated/pepper_beta/cpp/graphics__3d_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_beta/cpp/graphics__3d_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_beta/cpp/image__data_8h__incl.png b/native_client_sdk/doc_generated/pepper_beta/cpp/image__data_8h__incl.png index 587aad2c..a20f57d 100644 --- a/native_client_sdk/doc_generated/pepper_beta/cpp/image__data_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_beta/cpp/image__data_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_beta/cpp/input__event_8h__incl.png b/native_client_sdk/doc_generated/pepper_beta/cpp/input__event_8h__incl.png index b5da1709..0da30cf6 100644 --- a/native_client_sdk/doc_generated/pepper_beta/cpp/input__event_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_beta/cpp/input__event_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_beta/cpp/media__stream__audio__track_8h__incl.png b/native_client_sdk/doc_generated/pepper_beta/cpp/media__stream__audio__track_8h__incl.png index 06344361..ef6cef0 100644 --- a/native_client_sdk/doc_generated/pepper_beta/cpp/media__stream__audio__track_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_beta/cpp/media__stream__audio__track_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_beta/cpp/media__stream__video__track_8h__incl.png b/native_client_sdk/doc_generated/pepper_beta/cpp/media__stream__video__track_8h__incl.png index 26fa7c4..5e8b2c89 100644 --- a/native_client_sdk/doc_generated/pepper_beta/cpp/media__stream__video__track_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_beta/cpp/media__stream__video__track_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_beta/cpp/message__loop_8h__incl.png b/native_client_sdk/doc_generated/pepper_beta/cpp/message__loop_8h__incl.png index 12b1f7b1..54ec545 100644 --- a/native_client_sdk/doc_generated/pepper_beta/cpp/message__loop_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_beta/cpp/message__loop_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_beta/cpp/network__list_8h__incl.png b/native_client_sdk/doc_generated/pepper_beta/cpp/network__list_8h__incl.png index 87c862c..b41f7c0 100644 --- a/native_client_sdk/doc_generated/pepper_beta/cpp/network__list_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_beta/cpp/network__list_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_beta/cpp/network__monitor_8h__incl.png b/native_client_sdk/doc_generated/pepper_beta/cpp/network__monitor_8h__incl.png index 9d090d0..b7ae67ee 100644 --- a/native_client_sdk/doc_generated/pepper_beta/cpp/network__monitor_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_beta/cpp/network__monitor_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_beta/cpp/network__proxy_8h__incl.png b/native_client_sdk/doc_generated/pepper_beta/cpp/network__proxy_8h__incl.png index f2d8df7e..f9a92b6 100644 --- a/native_client_sdk/doc_generated/pepper_beta/cpp/network__proxy_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_beta/cpp/network__proxy_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_beta/cpp/point_8h__incl.png b/native_client_sdk/doc_generated/pepper_beta/cpp/point_8h__incl.png index 21568624..e8aa5b7 100644 --- a/native_client_sdk/doc_generated/pepper_beta/cpp/point_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_beta/cpp/point_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_beta/cpp/rect_8h__incl.png b/native_client_sdk/doc_generated/pepper_beta/cpp/rect_8h__incl.png index e9bce1c5..9e334c29 100644 --- a/native_client_sdk/doc_generated/pepper_beta/cpp/rect_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_beta/cpp/rect_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_beta/cpp/tcp__socket_8h__incl.png b/native_client_sdk/doc_generated/pepper_beta/cpp/tcp__socket_8h__incl.png index ca769e3c..4d37568 100644 --- a/native_client_sdk/doc_generated/pepper_beta/cpp/tcp__socket_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_beta/cpp/tcp__socket_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_beta/cpp/text__input__controller_8h__incl.png b/native_client_sdk/doc_generated/pepper_beta/cpp/text__input__controller_8h__incl.png index e78f7103..33eca1a9 100644 --- a/native_client_sdk/doc_generated/pepper_beta/cpp/text__input__controller_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_beta/cpp/text__input__controller_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_beta/cpp/touch__point_8h__incl.png b/native_client_sdk/doc_generated/pepper_beta/cpp/touch__point_8h__incl.png index 31f06bd..18b4e00 100644 --- a/native_client_sdk/doc_generated/pepper_beta/cpp/touch__point_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_beta/cpp/touch__point_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_beta/cpp/udp__socket_8h__incl.png b/native_client_sdk/doc_generated/pepper_beta/cpp/udp__socket_8h__incl.png index adbc171..4fded65f 100644 --- a/native_client_sdk/doc_generated/pepper_beta/cpp/udp__socket_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_beta/cpp/udp__socket_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_beta/cpp/url__request__info_8h__incl.png b/native_client_sdk/doc_generated/pepper_beta/cpp/url__request__info_8h__incl.png index db9e9b9..1c8fdd87 100644 --- a/native_client_sdk/doc_generated/pepper_beta/cpp/url__request__info_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_beta/cpp/url__request__info_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_beta/cpp/url__response__info_8h__incl.png b/native_client_sdk/doc_generated/pepper_beta/cpp/url__response__info_8h__incl.png index 2cecef2..952534cf 100644 --- a/native_client_sdk/doc_generated/pepper_beta/cpp/url__response__info_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_beta/cpp/url__response__info_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_beta/cpp/var_8h__incl.png b/native_client_sdk/doc_generated/pepper_beta/cpp/var_8h__incl.png index e7ac005..ab216f4 100644 --- a/native_client_sdk/doc_generated/pepper_beta/cpp/var_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_beta/cpp/var_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_beta/cpp/var__array__buffer_8h__incl.png b/native_client_sdk/doc_generated/pepper_beta/cpp/var__array__buffer_8h__incl.png index b2359a8..c3fe5fd6 100644 --- a/native_client_sdk/doc_generated/pepper_beta/cpp/var__array__buffer_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_beta/cpp/var__array__buffer_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_beta/cpp/video__decoder_8h__incl.png b/native_client_sdk/doc_generated/pepper_beta/cpp/video__decoder_8h__incl.png index 3d4177b..a67b2f2a 100644 --- a/native_client_sdk/doc_generated/pepper_beta/cpp/video__decoder_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_beta/cpp/video__decoder_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_beta/cpp/video__encoder_8h__incl.png b/native_client_sdk/doc_generated/pepper_beta/cpp/video__encoder_8h__incl.png index 553cbab9..58543d80 100644 --- a/native_client_sdk/doc_generated/pepper_beta/cpp/video__encoder_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_beta/cpp/video__encoder_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_beta/cpp/video__frame_8h__incl.png b/native_client_sdk/doc_generated/pepper_beta/cpp/video__frame_8h__incl.png index 1f602eb..270c65a3 100644 --- a/native_client_sdk/doc_generated/pepper_beta/cpp/video__frame_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_beta/cpp/video__frame_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_beta/cpp/websocket_8h__incl.png b/native_client_sdk/doc_generated/pepper_beta/cpp/websocket_8h__incl.png index ac9f41e..8922a4158 100644 --- a/native_client_sdk/doc_generated/pepper_beta/cpp/websocket_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_beta/cpp/websocket_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_dev/cpp/audio__buffer_8h__incl.png b/native_client_sdk/doc_generated/pepper_dev/cpp/audio__buffer_8h__incl.png index f0dd5317..e4f7864 100644 --- a/native_client_sdk/doc_generated/pepper_dev/cpp/audio__buffer_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_dev/cpp/audio__buffer_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_dev/cpp/audio__encoder_8h__incl.png b/native_client_sdk/doc_generated/pepper_dev/cpp/audio__encoder_8h__incl.png index 9eb1bf12..6613246 100644 --- a/native_client_sdk/doc_generated/pepper_dev/cpp/audio__encoder_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_dev/cpp/audio__encoder_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_dev/cpp/classpp_1_1_var.html b/native_client_sdk/doc_generated/pepper_dev/cpp/classpp_1_1_var.html index e6c84eaa..6d653cf 100644 --- a/native_client_sdk/doc_generated/pepper_dev/cpp/classpp_1_1_var.html +++ b/native_client_sdk/doc_generated/pepper_dev/cpp/classpp_1_1_var.html
@@ -599,7 +599,7 @@ </div> <div class="memdoc"> <p>This function determines if this <code><a class="el" href="classpp_1_1_var.html" title="A generic type used for passing data types between the module and the page.">Var</a></code> is a number. </p> -<dl class="return"><dt><b>Returns:</b></dt><dd>true if this <code><a class="el" href="classpp_1_1_var.html" title="A generic type used for passing data types between the module and the page.">Var</a></code> is an int32 or double number, otherwise false. </dd></dl> +<dl class="return"><dt><b>Returns:</b></dt><dd>true if this <code><a class="el" href="classpp_1_1_var.html" title="A generic type used for passing data types between the module and the page.">Var</a></code> is an int32_t or double number, otherwise false. </dd></dl> </div> </div> <a class="anchor" id="a79ed26c49d64b536619a1ee574848a36"></a><!-- doxytag: member="pp::Var::is_object" ref="a79ed26c49d64b536619a1ee574848a36" args="() const " -->
diff --git a/native_client_sdk/doc_generated/pepper_dev/cpp/completion__callback_8h__incl.png b/native_client_sdk/doc_generated/pepper_dev/cpp/completion__callback_8h__incl.png index 06d514f..78d0f0e 100644 --- a/native_client_sdk/doc_generated/pepper_dev/cpp/completion__callback_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_dev/cpp/completion__callback_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_dev/cpp/completion__callback__factory_8h__incl.png b/native_client_sdk/doc_generated/pepper_dev/cpp/completion__callback__factory_8h__incl.png index c2f590e..8b9d5194 100644 --- a/native_client_sdk/doc_generated/pepper_dev/cpp/completion__callback__factory_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_dev/cpp/completion__callback__factory_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_dev/cpp/compositor_8h__incl.png b/native_client_sdk/doc_generated/pepper_dev/cpp/compositor_8h__incl.png index 753eea6..286df56 100644 --- a/native_client_sdk/doc_generated/pepper_dev/cpp/compositor_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_dev/cpp/compositor_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_dev/cpp/compositor__layer_8h__incl.png b/native_client_sdk/doc_generated/pepper_dev/cpp/compositor__layer_8h__incl.png index 7f643cb..339a781 100644 --- a/native_client_sdk/doc_generated/pepper_dev/cpp/compositor__layer_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_dev/cpp/compositor__layer_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_dev/cpp/core_8h__incl.png b/native_client_sdk/doc_generated/pepper_dev/cpp/core_8h__incl.png index 3ffa9e8..1423f71d 100644 --- a/native_client_sdk/doc_generated/pepper_dev/cpp/core_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_dev/cpp/core_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_dev/cpp/file__io_8h__incl.png b/native_client_sdk/doc_generated/pepper_dev/cpp/file__io_8h__incl.png index 41185888..064edae 100644 --- a/native_client_sdk/doc_generated/pepper_dev/cpp/file__io_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_dev/cpp/file__io_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_dev/cpp/graphics__3d_8h__incl.png b/native_client_sdk/doc_generated/pepper_dev/cpp/graphics__3d_8h__incl.png index 025025c..d8a0b23 100644 --- a/native_client_sdk/doc_generated/pepper_dev/cpp/graphics__3d_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_dev/cpp/graphics__3d_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_dev/cpp/image__data_8h__incl.png b/native_client_sdk/doc_generated/pepper_dev/cpp/image__data_8h__incl.png index 587aad2c..a20f57d 100644 --- a/native_client_sdk/doc_generated/pepper_dev/cpp/image__data_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_dev/cpp/image__data_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_dev/cpp/input__event_8h__incl.png b/native_client_sdk/doc_generated/pepper_dev/cpp/input__event_8h__incl.png index b5da1709..0da30cf6 100644 --- a/native_client_sdk/doc_generated/pepper_dev/cpp/input__event_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_dev/cpp/input__event_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_dev/cpp/media__stream__audio__track_8h__incl.png b/native_client_sdk/doc_generated/pepper_dev/cpp/media__stream__audio__track_8h__incl.png index 06344361..ef6cef0 100644 --- a/native_client_sdk/doc_generated/pepper_dev/cpp/media__stream__audio__track_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_dev/cpp/media__stream__audio__track_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_dev/cpp/media__stream__video__track_8h__incl.png b/native_client_sdk/doc_generated/pepper_dev/cpp/media__stream__video__track_8h__incl.png index 26fa7c4..5e8b2c89 100644 --- a/native_client_sdk/doc_generated/pepper_dev/cpp/media__stream__video__track_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_dev/cpp/media__stream__video__track_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_dev/cpp/message__loop_8h__incl.png b/native_client_sdk/doc_generated/pepper_dev/cpp/message__loop_8h__incl.png index 12b1f7b1..54ec545 100644 --- a/native_client_sdk/doc_generated/pepper_dev/cpp/message__loop_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_dev/cpp/message__loop_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_dev/cpp/network__list_8h__incl.png b/native_client_sdk/doc_generated/pepper_dev/cpp/network__list_8h__incl.png index 87c862c..b41f7c0 100644 --- a/native_client_sdk/doc_generated/pepper_dev/cpp/network__list_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_dev/cpp/network__list_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_dev/cpp/network__monitor_8h__incl.png b/native_client_sdk/doc_generated/pepper_dev/cpp/network__monitor_8h__incl.png index 9d090d0..b7ae67ee 100644 --- a/native_client_sdk/doc_generated/pepper_dev/cpp/network__monitor_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_dev/cpp/network__monitor_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_dev/cpp/network__proxy_8h__incl.png b/native_client_sdk/doc_generated/pepper_dev/cpp/network__proxy_8h__incl.png index f2d8df7e..f9a92b6 100644 --- a/native_client_sdk/doc_generated/pepper_dev/cpp/network__proxy_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_dev/cpp/network__proxy_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_dev/cpp/point_8h__incl.png b/native_client_sdk/doc_generated/pepper_dev/cpp/point_8h__incl.png index 21568624..e8aa5b7 100644 --- a/native_client_sdk/doc_generated/pepper_dev/cpp/point_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_dev/cpp/point_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_dev/cpp/rect_8h__incl.png b/native_client_sdk/doc_generated/pepper_dev/cpp/rect_8h__incl.png index e9bce1c5..9e334c29 100644 --- a/native_client_sdk/doc_generated/pepper_dev/cpp/rect_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_dev/cpp/rect_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_dev/cpp/tcp__socket_8h__incl.png b/native_client_sdk/doc_generated/pepper_dev/cpp/tcp__socket_8h__incl.png index ca769e3c..4d37568 100644 --- a/native_client_sdk/doc_generated/pepper_dev/cpp/tcp__socket_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_dev/cpp/tcp__socket_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_dev/cpp/text__input__controller_8h__incl.png b/native_client_sdk/doc_generated/pepper_dev/cpp/text__input__controller_8h__incl.png index e78f7103..33eca1a9 100644 --- a/native_client_sdk/doc_generated/pepper_dev/cpp/text__input__controller_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_dev/cpp/text__input__controller_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_dev/cpp/touch__point_8h__incl.png b/native_client_sdk/doc_generated/pepper_dev/cpp/touch__point_8h__incl.png index 31f06bd..18b4e00 100644 --- a/native_client_sdk/doc_generated/pepper_dev/cpp/touch__point_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_dev/cpp/touch__point_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_dev/cpp/udp__socket_8h__incl.png b/native_client_sdk/doc_generated/pepper_dev/cpp/udp__socket_8h__incl.png index adbc171..4fded65f 100644 --- a/native_client_sdk/doc_generated/pepper_dev/cpp/udp__socket_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_dev/cpp/udp__socket_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_dev/cpp/url__request__info_8h__incl.png b/native_client_sdk/doc_generated/pepper_dev/cpp/url__request__info_8h__incl.png index db9e9b9..1c8fdd87 100644 --- a/native_client_sdk/doc_generated/pepper_dev/cpp/url__request__info_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_dev/cpp/url__request__info_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_dev/cpp/url__response__info_8h__incl.png b/native_client_sdk/doc_generated/pepper_dev/cpp/url__response__info_8h__incl.png index 2cecef2..952534cf 100644 --- a/native_client_sdk/doc_generated/pepper_dev/cpp/url__response__info_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_dev/cpp/url__response__info_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_dev/cpp/var_8h__incl.png b/native_client_sdk/doc_generated/pepper_dev/cpp/var_8h__incl.png index e7ac005..ab216f4 100644 --- a/native_client_sdk/doc_generated/pepper_dev/cpp/var_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_dev/cpp/var_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_dev/cpp/var__array__buffer_8h__incl.png b/native_client_sdk/doc_generated/pepper_dev/cpp/var__array__buffer_8h__incl.png index b2359a8..c3fe5fd6 100644 --- a/native_client_sdk/doc_generated/pepper_dev/cpp/var__array__buffer_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_dev/cpp/var__array__buffer_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_dev/cpp/video__decoder_8h__incl.png b/native_client_sdk/doc_generated/pepper_dev/cpp/video__decoder_8h__incl.png index 3d4177b..a67b2f2a 100644 --- a/native_client_sdk/doc_generated/pepper_dev/cpp/video__decoder_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_dev/cpp/video__decoder_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_dev/cpp/video__encoder_8h__incl.png b/native_client_sdk/doc_generated/pepper_dev/cpp/video__encoder_8h__incl.png index 553cbab9..58543d80 100644 --- a/native_client_sdk/doc_generated/pepper_dev/cpp/video__encoder_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_dev/cpp/video__encoder_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_dev/cpp/video__frame_8h__incl.png b/native_client_sdk/doc_generated/pepper_dev/cpp/video__frame_8h__incl.png index 1f602eb..270c65a3 100644 --- a/native_client_sdk/doc_generated/pepper_dev/cpp/video__frame_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_dev/cpp/video__frame_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_dev/cpp/websocket_8h__incl.png b/native_client_sdk/doc_generated/pepper_dev/cpp/websocket_8h__incl.png index ac9f41e..8922a4158 100644 --- a/native_client_sdk/doc_generated/pepper_dev/cpp/websocket_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_dev/cpp/websocket_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_stable/cpp/audio__buffer_8h__incl.png b/native_client_sdk/doc_generated/pepper_stable/cpp/audio__buffer_8h__incl.png index f0dd5317..e4f7864 100644 --- a/native_client_sdk/doc_generated/pepper_stable/cpp/audio__buffer_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_stable/cpp/audio__buffer_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_stable/cpp/audio__encoder_8h__incl.png b/native_client_sdk/doc_generated/pepper_stable/cpp/audio__encoder_8h__incl.png index 9eb1bf12..6613246 100644 --- a/native_client_sdk/doc_generated/pepper_stable/cpp/audio__encoder_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_stable/cpp/audio__encoder_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_stable/cpp/classpp_1_1_var.html b/native_client_sdk/doc_generated/pepper_stable/cpp/classpp_1_1_var.html index e6c84eaa..6d653cf 100644 --- a/native_client_sdk/doc_generated/pepper_stable/cpp/classpp_1_1_var.html +++ b/native_client_sdk/doc_generated/pepper_stable/cpp/classpp_1_1_var.html
@@ -599,7 +599,7 @@ </div> <div class="memdoc"> <p>This function determines if this <code><a class="el" href="classpp_1_1_var.html" title="A generic type used for passing data types between the module and the page.">Var</a></code> is a number. </p> -<dl class="return"><dt><b>Returns:</b></dt><dd>true if this <code><a class="el" href="classpp_1_1_var.html" title="A generic type used for passing data types between the module and the page.">Var</a></code> is an int32 or double number, otherwise false. </dd></dl> +<dl class="return"><dt><b>Returns:</b></dt><dd>true if this <code><a class="el" href="classpp_1_1_var.html" title="A generic type used for passing data types between the module and the page.">Var</a></code> is an int32_t or double number, otherwise false. </dd></dl> </div> </div> <a class="anchor" id="a79ed26c49d64b536619a1ee574848a36"></a><!-- doxytag: member="pp::Var::is_object" ref="a79ed26c49d64b536619a1ee574848a36" args="() const " -->
diff --git a/native_client_sdk/doc_generated/pepper_stable/cpp/completion__callback_8h__incl.png b/native_client_sdk/doc_generated/pepper_stable/cpp/completion__callback_8h__incl.png index 06d514f..78d0f0e 100644 --- a/native_client_sdk/doc_generated/pepper_stable/cpp/completion__callback_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_stable/cpp/completion__callback_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_stable/cpp/completion__callback__factory_8h__incl.png b/native_client_sdk/doc_generated/pepper_stable/cpp/completion__callback__factory_8h__incl.png index c2f590e..8b9d5194 100644 --- a/native_client_sdk/doc_generated/pepper_stable/cpp/completion__callback__factory_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_stable/cpp/completion__callback__factory_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_stable/cpp/compositor_8h__incl.png b/native_client_sdk/doc_generated/pepper_stable/cpp/compositor_8h__incl.png index 753eea6..286df56 100644 --- a/native_client_sdk/doc_generated/pepper_stable/cpp/compositor_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_stable/cpp/compositor_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_stable/cpp/compositor__layer_8h__incl.png b/native_client_sdk/doc_generated/pepper_stable/cpp/compositor__layer_8h__incl.png index 7f643cb..339a781 100644 --- a/native_client_sdk/doc_generated/pepper_stable/cpp/compositor__layer_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_stable/cpp/compositor__layer_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_stable/cpp/core_8h__incl.png b/native_client_sdk/doc_generated/pepper_stable/cpp/core_8h__incl.png index 3ffa9e8..1423f71d 100644 --- a/native_client_sdk/doc_generated/pepper_stable/cpp/core_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_stable/cpp/core_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_stable/cpp/file__io_8h__incl.png b/native_client_sdk/doc_generated/pepper_stable/cpp/file__io_8h__incl.png index 41185888..064edae 100644 --- a/native_client_sdk/doc_generated/pepper_stable/cpp/file__io_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_stable/cpp/file__io_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_stable/cpp/graphics__3d_8h__incl.png b/native_client_sdk/doc_generated/pepper_stable/cpp/graphics__3d_8h__incl.png index 025025c..d8a0b23 100644 --- a/native_client_sdk/doc_generated/pepper_stable/cpp/graphics__3d_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_stable/cpp/graphics__3d_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_stable/cpp/image__data_8h__incl.png b/native_client_sdk/doc_generated/pepper_stable/cpp/image__data_8h__incl.png index 587aad2c..a20f57d 100644 --- a/native_client_sdk/doc_generated/pepper_stable/cpp/image__data_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_stable/cpp/image__data_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_stable/cpp/input__event_8h__incl.png b/native_client_sdk/doc_generated/pepper_stable/cpp/input__event_8h__incl.png index b5da1709..0da30cf6 100644 --- a/native_client_sdk/doc_generated/pepper_stable/cpp/input__event_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_stable/cpp/input__event_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_stable/cpp/media__stream__audio__track_8h__incl.png b/native_client_sdk/doc_generated/pepper_stable/cpp/media__stream__audio__track_8h__incl.png index 06344361..ef6cef0 100644 --- a/native_client_sdk/doc_generated/pepper_stable/cpp/media__stream__audio__track_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_stable/cpp/media__stream__audio__track_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_stable/cpp/media__stream__video__track_8h__incl.png b/native_client_sdk/doc_generated/pepper_stable/cpp/media__stream__video__track_8h__incl.png index 26fa7c4..5e8b2c89 100644 --- a/native_client_sdk/doc_generated/pepper_stable/cpp/media__stream__video__track_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_stable/cpp/media__stream__video__track_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_stable/cpp/message__loop_8h__incl.png b/native_client_sdk/doc_generated/pepper_stable/cpp/message__loop_8h__incl.png index 12b1f7b1..54ec545 100644 --- a/native_client_sdk/doc_generated/pepper_stable/cpp/message__loop_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_stable/cpp/message__loop_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_stable/cpp/network__list_8h__incl.png b/native_client_sdk/doc_generated/pepper_stable/cpp/network__list_8h__incl.png index 87c862c..b41f7c0 100644 --- a/native_client_sdk/doc_generated/pepper_stable/cpp/network__list_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_stable/cpp/network__list_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_stable/cpp/network__monitor_8h__incl.png b/native_client_sdk/doc_generated/pepper_stable/cpp/network__monitor_8h__incl.png index 9d090d0..b7ae67ee 100644 --- a/native_client_sdk/doc_generated/pepper_stable/cpp/network__monitor_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_stable/cpp/network__monitor_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_stable/cpp/network__proxy_8h__incl.png b/native_client_sdk/doc_generated/pepper_stable/cpp/network__proxy_8h__incl.png index f2d8df7e..f9a92b6 100644 --- a/native_client_sdk/doc_generated/pepper_stable/cpp/network__proxy_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_stable/cpp/network__proxy_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_stable/cpp/point_8h__incl.png b/native_client_sdk/doc_generated/pepper_stable/cpp/point_8h__incl.png index 21568624..e8aa5b7 100644 --- a/native_client_sdk/doc_generated/pepper_stable/cpp/point_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_stable/cpp/point_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_stable/cpp/rect_8h__incl.png b/native_client_sdk/doc_generated/pepper_stable/cpp/rect_8h__incl.png index e9bce1c5..9e334c29 100644 --- a/native_client_sdk/doc_generated/pepper_stable/cpp/rect_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_stable/cpp/rect_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_stable/cpp/tcp__socket_8h__incl.png b/native_client_sdk/doc_generated/pepper_stable/cpp/tcp__socket_8h__incl.png index ca769e3c..4d37568 100644 --- a/native_client_sdk/doc_generated/pepper_stable/cpp/tcp__socket_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_stable/cpp/tcp__socket_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_stable/cpp/text__input__controller_8h__incl.png b/native_client_sdk/doc_generated/pepper_stable/cpp/text__input__controller_8h__incl.png index e78f7103..33eca1a9 100644 --- a/native_client_sdk/doc_generated/pepper_stable/cpp/text__input__controller_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_stable/cpp/text__input__controller_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_stable/cpp/touch__point_8h__incl.png b/native_client_sdk/doc_generated/pepper_stable/cpp/touch__point_8h__incl.png index 31f06bd..18b4e00 100644 --- a/native_client_sdk/doc_generated/pepper_stable/cpp/touch__point_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_stable/cpp/touch__point_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_stable/cpp/udp__socket_8h__incl.png b/native_client_sdk/doc_generated/pepper_stable/cpp/udp__socket_8h__incl.png index adbc171..4fded65f 100644 --- a/native_client_sdk/doc_generated/pepper_stable/cpp/udp__socket_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_stable/cpp/udp__socket_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_stable/cpp/url__request__info_8h__incl.png b/native_client_sdk/doc_generated/pepper_stable/cpp/url__request__info_8h__incl.png index db9e9b9..1c8fdd87 100644 --- a/native_client_sdk/doc_generated/pepper_stable/cpp/url__request__info_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_stable/cpp/url__request__info_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_stable/cpp/url__response__info_8h__incl.png b/native_client_sdk/doc_generated/pepper_stable/cpp/url__response__info_8h__incl.png index 2cecef2..952534cf 100644 --- a/native_client_sdk/doc_generated/pepper_stable/cpp/url__response__info_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_stable/cpp/url__response__info_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_stable/cpp/var_8h__incl.png b/native_client_sdk/doc_generated/pepper_stable/cpp/var_8h__incl.png index e7ac005..ab216f4 100644 --- a/native_client_sdk/doc_generated/pepper_stable/cpp/var_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_stable/cpp/var_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_stable/cpp/var__array__buffer_8h__incl.png b/native_client_sdk/doc_generated/pepper_stable/cpp/var__array__buffer_8h__incl.png index b2359a8..c3fe5fd6 100644 --- a/native_client_sdk/doc_generated/pepper_stable/cpp/var__array__buffer_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_stable/cpp/var__array__buffer_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_stable/cpp/video__decoder_8h__incl.png b/native_client_sdk/doc_generated/pepper_stable/cpp/video__decoder_8h__incl.png index 3d4177b..a67b2f2a 100644 --- a/native_client_sdk/doc_generated/pepper_stable/cpp/video__decoder_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_stable/cpp/video__decoder_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_stable/cpp/video__encoder_8h__incl.png b/native_client_sdk/doc_generated/pepper_stable/cpp/video__encoder_8h__incl.png index 553cbab9..58543d80 100644 --- a/native_client_sdk/doc_generated/pepper_stable/cpp/video__encoder_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_stable/cpp/video__encoder_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_stable/cpp/video__frame_8h__incl.png b/native_client_sdk/doc_generated/pepper_stable/cpp/video__frame_8h__incl.png index 1f602eb..270c65a3 100644 --- a/native_client_sdk/doc_generated/pepper_stable/cpp/video__frame_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_stable/cpp/video__frame_8h__incl.png Binary files differ
diff --git a/native_client_sdk/doc_generated/pepper_stable/cpp/websocket_8h__incl.png b/native_client_sdk/doc_generated/pepper_stable/cpp/websocket_8h__incl.png index ac9f41e..8922a4158 100644 --- a/native_client_sdk/doc_generated/pepper_stable/cpp/websocket_8h__incl.png +++ b/native_client_sdk/doc_generated/pepper_stable/cpp/websocket_8h__incl.png Binary files differ
diff --git a/net/BUILD.gn b/net/BUILD.gn index 4c453f3..953c6e3 100644 --- a/net/BUILD.gn +++ b/net/BUILD.gn
@@ -449,7 +449,6 @@ sources += [ "base/filename_util_icu.cc", "base/net_string_util_icu.cc", - "base/net_util_icu.cc", ] # Brotli support. @@ -1266,8 +1265,8 @@ "tools/quic/quic_in_memory_cache.h", "tools/quic/quic_per_connection_packet_writer.cc", "tools/quic/quic_per_connection_packet_writer.h", - "tools/quic/quic_server_session.cc", - "tools/quic/quic_server_session.h", + "tools/quic/quic_server_session_base.cc", + "tools/quic/quic_server_session_base.h", "tools/quic/quic_simple_client.cc", "tools/quic/quic_simple_client.h", "tools/quic/quic_simple_per_connection_packet_writer.cc", @@ -1276,6 +1275,8 @@ "tools/quic/quic_simple_server.h", "tools/quic/quic_simple_server_packet_writer.cc", "tools/quic/quic_simple_server_packet_writer.h", + "tools/quic/quic_simple_server_session.cc", + "tools/quic/quic_simple_server_session.h", "tools/quic/quic_simple_server_stream.cc", "tools/quic/quic_simple_server_stream.h", "tools/quic/quic_spdy_client_stream.cc", @@ -1531,6 +1532,7 @@ if (disable_file_support) { sources -= [ "base/directory_lister_unittest.cc", + "base/directory_listing_unittest.cc", "url_request/url_request_file_job_unittest.cc", ] }
diff --git a/net/DEPS b/net/DEPS index c7d79514..6f3c3d3 100644 --- a/net/DEPS +++ b/net/DEPS
@@ -24,17 +24,16 @@ "+base/i18n", ], + # Functions largely not used by the rest of net. + "directory_listing\.cc": [ + "+base/i18n", + ], + # Within net, only used by file: requests. "filename_util_icu\.cc": [ "+base/i18n/file_util_icu.h", ], - # Functions largely not used by the rest of net. - "net_util_icu\.cc": [ - "+base/i18n", - "+third_party/icu", - ], - # Consolidated string functions that depend on icu. "net_string_util_icu\.cc": [ "+base/i18n/i18n_constants.h",
diff --git a/net/base/net_util_icu.cc b/net/base/directory_listing.cc similarity index 67% rename from net/base/net_util_icu.cc rename to net/base/directory_listing.cc index 62766c1..25d98bc 100644 --- a/net/base/net_util_icu.cc +++ b/net/base/directory_listing.cc
@@ -1,18 +1,40 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// 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/base/net_util.h" +#include "net/base/directory_listing.h" #include "base/i18n/time_formatting.h" #include "base/json/string_escape.h" +#include "base/logging.h" +#include "base/strings/string_piece.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "base/time/time.h" #include "net/base/escape.h" +#include "net/base/net_module.h" +#include "net/grit/net_resources.h" namespace net { +std::string GetDirectoryListingHeader(const base::string16& title) { + static const base::StringPiece header( + NetModule::GetResource(IDR_DIR_HEADER_HTML)); + // This can be null in unit tests. + DLOG_IF(WARNING, header.empty()) + << "Missing resource: directory listing header"; + + std::string result; + if (!header.empty()) + result.assign(header.data(), header.size()); + + result.append("<script>start("); + base::EscapeJSONString(title, true, &result); + result.append(");</script>\n"); + + return result; +} + std::string GetDirectoryListingEntry(const base::string16& name, const std::string& raw_bytes, bool is_dir,
diff --git a/net/base/directory_listing.h b/net/base/directory_listing.h new file mode 100644 index 0000000..7f6301ad --- /dev/null +++ b/net/base/directory_listing.h
@@ -0,0 +1,44 @@ +// 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_BASE_DIRECTORY_LISTING_H_ +#define NET_BASE_DIRECTORY_LISTING_H_ + +#include <stdint.h> +#include <string> + +#include "base/strings/string16.h" +#include "net/base/net_export.h" + +namespace base { +class Time; +} + +namespace net { + +// Call these functions to get the html snippet for a directory listing. +// The return values of both functions are in UTF-8. +NET_EXPORT std::string GetDirectoryListingHeader(const base::string16& title); + +// Given the name of a file in a directory (ftp or local) and +// other information (is_dir, size, modification time), it returns +// the html snippet to add the entry for the file to the directory listing. +// Currently, it's a script tag containing a call to a Javascript function +// |addRow|. +// +// |name| is the file name to be displayed. |raw_bytes| will be used +// as the actual target of the link (so for example, ftp links should use +// server's encoding). If |raw_bytes| is an empty string, UTF-8 encoded |name| +// will be used. +// +// Both |name| and |raw_bytes| are escaped internally. +NET_EXPORT std::string GetDirectoryListingEntry(const base::string16& name, + const std::string& raw_bytes, + bool is_dir, + int64_t size, + base::Time modified); + +} // namespace net + +#endif // NET_BASE_DIRECTORY_LISTING_H_
diff --git a/net/base/net_util_icu_unittest.cc b/net/base/directory_listing_unittest.cc similarity index 93% rename from net/base/net_util_icu_unittest.cc rename to net/base/directory_listing_unittest.cc index cac922f5..7470c2a 100644 --- a/net/base/net_util_icu_unittest.cc +++ b/net/base/directory_listing_unittest.cc
@@ -2,16 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "net/base/net_util.h" - -#include <stdint.h> - -#include <string> +#include "net/base/directory_listing.h" #include "base/strings/utf_string_conversions.h" #include "base/time/time.h" #include "testing/gtest/include/gtest/gtest.h" -#include "url/gurl.h" namespace net { @@ -26,7 +21,7 @@ const char* const expected; }; -TEST(NetUtilTest, GetDirectoryListingEntry) { +TEST(DirectoryListingTest, GetDirectoryListingEntry) { const GetDirectoryListingEntryCase test_cases[] = { {L"Foo", "",
diff --git a/net/base/filename_util_internal.cc b/net/base/filename_util_internal.cc index 4cfedcd8..2f038ad 100644 --- a/net/base/filename_util_internal.cc +++ b/net/base/filename_util_internal.cc
@@ -20,6 +20,61 @@ namespace net { +namespace { + +// Examines the current extension in |file_name| and tries to return the correct +// extension the file should actually be using. Used by EnsureSafeExtension. +// All other code should use EnsureSafeExtension, as it includes additional +// safety checks. +base::FilePath::StringType GetCorrectedExtensionUnsafe( + const std::string& mime_type, + bool ignore_extension, + const base::FilePath& file_name) { + // See if the file name already contains an extension. + base::FilePath::StringType extension = file_name.Extension(); + if (!extension.empty()) + extension.erase(extension.begin()); // Erase preceding '.'. + + // Nothing to do if there's no mime type. + if (mime_type.empty()) + return extension; + + // Nothing to do there's an extension, unless |ignore_extension| is true. + if (!extension.empty() && !ignore_extension) + return extension; + + // Don't do anything if there's not a preferred extension for the mime + // type. + base::FilePath::StringType preferred_mime_extension; + if (!GetPreferredExtensionForMimeType(mime_type, &preferred_mime_extension)) + return extension; + + // If the existing extension is in the list of valid extensions for the + // given type, use it. This avoids doing things like pointlessly renaming + // "foo.jpg" to "foo.jpeg". + std::vector<base::FilePath::StringType> all_mime_extensions; + GetExtensionsForMimeType(mime_type, &all_mime_extensions); + if (ContainsValue(all_mime_extensions, extension)) + return extension; + + // Get the "final" extension. In most cases, this is the same as the + // |extension|, but in cases like "foo.tar.gz", it's "gz" while + // |extension| is "tar.gz". + base::FilePath::StringType final_extension = file_name.FinalExtension(); + // Erase preceding '.'. + if (!final_extension.empty()) + final_extension.erase(final_extension.begin()); + + // If there's a double extension, and the second extension is in the + // list of valid extensions for the given type, keep the double extension. + // This avoids renaming things like "foo.tar.gz" to "foo.gz". + if (ContainsValue(all_mime_extensions, final_extension)) + return extension; + return preferred_mime_extension; +} + +} // namespace + void SanitizeGeneratedFileName(base::FilePath::StringType* filename, bool replace_trailing) { const base::FilePath::CharType kReplace[] = FILE_PATH_LITERAL("-"); @@ -129,35 +184,19 @@ void EnsureSafeExtension(const std::string& mime_type, bool ignore_extension, base::FilePath* file_name) { - // See if our file name already contains an extension. - base::FilePath::StringType extension = file_name->Extension(); - if (!extension.empty()) - extension.erase(extension.begin()); // Erase preceding '.'. - - if ((ignore_extension || extension.empty()) && !mime_type.empty()) { - base::FilePath::StringType preferred_mime_extension; - std::vector<base::FilePath::StringType> all_mime_extensions; - GetPreferredExtensionForMimeType(mime_type, &preferred_mime_extension); - GetExtensionsForMimeType(mime_type, &all_mime_extensions); - // If the existing extension is in the list of valid extensions for the - // given type, use it. This avoids doing things like pointlessly renaming - // "foo.jpg" to "foo.jpeg". - if (ContainsValue(all_mime_extensions, extension)) { - // leave |extension| alone - } else if (!preferred_mime_extension.empty()) { - extension = preferred_mime_extension; - } - } + DCHECK(file_name); + base::FilePath::StringType extension = + GetCorrectedExtensionUnsafe(mime_type, ignore_extension, *file_name); #if defined(OS_WIN) - static const base::FilePath::CharType default_extension[] = + const base::FilePath::CharType kDefaultExtension[] = FILE_PATH_LITERAL("download"); // Rename shell-integrated extensions. // TODO(asanka): Consider stripping out the bad extension and replacing it // with the preferred extension for the MIME type if one is available. if (IsShellIntegratedExtension(extension)) - extension.assign(default_extension); + extension = kDefaultExtension; #endif *file_name = file_name->ReplaceExtension(extension);
diff --git a/net/base/filename_util_unittest.cc b/net/base/filename_util_unittest.cc index 453106c6..5e3fb7e1 100644 --- a/net/base/filename_util_unittest.cc +++ b/net/base/filename_util_unittest.cc
@@ -792,407 +792,150 @@ // a correct extension should be added if necessary. const GenerateFilenameCase generation_tests[] = { // Dotfiles. Ensures preceeding period(s) stripped. - {__LINE__, - "http://www.google.com/.test.html", - "", - "", - "", - "", - L"", + {__LINE__, "http://www.google.com/.test.html", "", "", "", "", L"", L"test.html"}, {__LINE__, "http://www.google.com/.test", "", "", "", "", L"", L"test"}, {__LINE__, "http://www.google.com/..test", "", "", "", "", L"", L"test"}, {// Disposition has relative paths, remove directory separators - __LINE__, - "http://www.evil.com/my_download.txt", - "filename=../../../../././../a_file_name.txt", - "", - "", - "text/plain", - L"download", - L"-..-..-..-.-.-..-a_file_name.txt"}, + __LINE__, "http://www.evil.com/my_download.txt", + "filename=../../../../././../a_file_name.txt", "", "", "text/plain", + L"download", L"-..-..-..-.-.-..-a_file_name.txt"}, {// Disposition has parent directories, remove directory separators - __LINE__, - "http://www.evil.com/my_download.txt", - "filename=dir1/dir2/a_file_name.txt", - "", - "", - "text/plain", - L"download", + __LINE__, "http://www.evil.com/my_download.txt", + "filename=dir1/dir2/a_file_name.txt", "", "", "text/plain", L"download", L"dir1-dir2-a_file_name.txt"}, {// Disposition has relative paths, remove directory separators - __LINE__, - "http://www.evil.com/my_download.txt", - "filename=..\\..\\..\\..\\.\\.\\..\\a_file_name.txt", - "", - "", - "text/plain", - L"download", - L"-..-..-..-.-.-..-a_file_name.txt"}, + __LINE__, "http://www.evil.com/my_download.txt", + "filename=..\\..\\..\\..\\.\\.\\..\\a_file_name.txt", "", "", "text/plain", + L"download", L"-..-..-..-.-.-..-a_file_name.txt"}, {// Disposition has parent directories, remove directory separators - __LINE__, - "http://www.evil.com/my_download.txt", - "filename=dir1\\dir2\\a_file_name.txt", - "", - "", - "text/plain", - L"download", + __LINE__, "http://www.evil.com/my_download.txt", + "filename=dir1\\dir2\\a_file_name.txt", "", "", "text/plain", L"download", L"dir1-dir2-a_file_name.txt"}, {// No useful information in disposition or URL, use default - __LINE__, - "http://www.truncated.com/path/", - "", - "", - "", - "text/plain", - L"download", - L"download" TXT_EXT}, + __LINE__, "http://www.truncated.com/path/", "", "", "", "text/plain", + L"download", L"download" TXT_EXT}, {// Filename looks like HTML? - __LINE__, - "http://www.evil.com/get/malware/here", - "filename=\"<blink>Hello kitty</blink>\"", - "", - "", - "text/plain", - L"default", - L"-blink-Hello kitty--blink-"}, + __LINE__, "http://www.evil.com/get/malware/here", + "filename=\"<blink>Hello kitty</blink>\"", "", "", "text/plain", + L"default", L"-blink-Hello kitty--blink-"}, {// A normal avi should get .avi and not .avi.avi - __LINE__, - "https://blah.google.com/misc/2.avi", - "", - "", - "", - "video/x-msvideo", - L"download", - L"2.avi"}, + __LINE__, "https://blah.google.com/misc/2.avi", "", "", "", + "video/x-msvideo", L"download", L"2.avi"}, {// Extension generation - __LINE__, - "http://www.example.com/my-cat", - "filename=my-cat", - "", - "", - "image/jpeg", - L"download", - L"my-cat"}, - {__LINE__, - "http://www.example.com/my-cat", - "filename=my-cat", - "", - "", - "text/plain", - L"download", - L"my-cat"}, - {__LINE__, - "http://www.example.com/my-cat", - "filename=my-cat", - "", - "", - "text/html", - L"download", - L"my-cat"}, + __LINE__, "http://www.example.com/my-cat", "filename=my-cat", "", "", + "image/jpeg", L"download", L"my-cat"}, + {__LINE__, "http://www.example.com/my-cat", "filename=my-cat", "", "", + "text/plain", L"download", L"my-cat"}, + {__LINE__, "http://www.example.com/my-cat", "filename=my-cat", "", "", + "text/html", L"download", L"my-cat"}, {// Unknown MIME type - __LINE__, - "http://www.example.com/my-cat", - "filename=my-cat", - "", - "", - "dance/party", - L"download", - L"my-cat"}, - {__LINE__, - "http://www.example.com/my-cat.jpg", - "filename=my-cat.jpg", - "", - "", - "text/plain", - L"download", - L"my-cat.jpg"}, + __LINE__, "http://www.example.com/my-cat", "filename=my-cat", "", "", + "dance/party", L"download", L"my-cat"}, + {__LINE__, "http://www.example.com/my-cat.jpg", "filename=my-cat.jpg", "", + "", "text/plain", L"download", L"my-cat.jpg"}, // Windows specific tests #if defined(OS_WIN) - {__LINE__, - "http://www.goodguy.com/evil.exe", - "filename=evil.exe", - "", - "", - "image/jpeg", - L"download", - L"evil.exe"}, - {__LINE__, - "http://www.goodguy.com/ok.exe", - "filename=ok.exe", - "", - "", - "binary/octet-stream", - L"download", - L"ok.exe"}, - {__LINE__, - "http://www.goodguy.com/evil.dll", - "filename=evil.dll", - "", - "", - "dance/party", - L"download", - L"evil.dll"}, - {__LINE__, - "http://www.goodguy.com/evil.exe", - "filename=evil", - "", - "", - "application/rss+xml", - L"download", - L"evil"}, + {__LINE__, "http://www.goodguy.com/evil.exe", "filename=evil.exe", "", "", + "image/jpeg", L"download", L"evil.exe"}, + {__LINE__, "http://www.goodguy.com/ok.exe", "filename=ok.exe", "", "", + "binary/octet-stream", L"download", L"ok.exe"}, + {__LINE__, "http://www.goodguy.com/evil.dll", "filename=evil.dll", "", "", + "dance/party", L"download", L"evil.dll"}, + {__LINE__, "http://www.goodguy.com/evil.exe", "filename=evil", "", "", + "application/rss+xml", L"download", L"evil"}, // Test truncation of trailing dots and spaces - {__LINE__, - "http://www.goodguy.com/evil.exe ", - "filename=evil.exe ", - "", - "", - "binary/octet-stream", - L"download", - L"evil.exe"}, - {__LINE__, - "http://www.goodguy.com/evil.exe.", - "filename=evil.exe.", - "", - "", - "binary/octet-stream", - L"download", - L"evil.exe-"}, - {__LINE__, - "http://www.goodguy.com/evil.exe. . .", - "filename=evil.exe. . .", - "", - "", - "binary/octet-stream", - L"download", + {__LINE__, "http://www.goodguy.com/evil.exe ", "filename=evil.exe ", "", "", + "binary/octet-stream", L"download", L"evil.exe"}, + {__LINE__, "http://www.goodguy.com/evil.exe.", "filename=evil.exe.", "", "", + "binary/octet-stream", L"download", L"evil.exe-"}, + {__LINE__, "http://www.goodguy.com/evil.exe. . .", + "filename=evil.exe. . .", "", "", "binary/octet-stream", L"download", L"evil.exe-------"}, - {__LINE__, - "http://www.goodguy.com/evil.", - "filename=evil.", - "", - "", - "binary/octet-stream", - L"download", - L"evil-"}, - {__LINE__, - "http://www.goodguy.com/. . . . .", - "filename=. . . . .", - "", - "", - "binary/octet-stream", - L"download", - L"download"}, - {__LINE__, - "http://www.badguy.com/attachment?name=meh.exe%C2%A0", - "attachment; filename=\"meh.exe\xC2\xA0\"", - "", - "", - "binary/octet-stream", - L"", - L"meh.exe-"}, + {__LINE__, "http://www.goodguy.com/evil.", "filename=evil.", "", "", + "binary/octet-stream", L"download", L"evil-"}, + {__LINE__, "http://www.goodguy.com/. . . . .", "filename=. . . . .", "", "", + "binary/octet-stream", L"download", L"download"}, + {__LINE__, "http://www.badguy.com/attachment?name=meh.exe%C2%A0", + "attachment; filename=\"meh.exe\xC2\xA0\"", "", "", "binary/octet-stream", + L"", L"meh.exe-"}, #endif // OS_WIN - {__LINE__, - "http://www.goodguy.com/utils.js", - "filename=utils.js", - "", - "", - "application/x-javascript", - L"download", - L"utils.js"}, - {__LINE__, - "http://www.goodguy.com/contacts.js", - "filename=contacts.js", - "", - "", - "application/json", - L"download", - L"contacts.js"}, - {__LINE__, - "http://www.goodguy.com/utils.js", - "filename=utils.js", - "", - "", - "text/javascript", - L"download", - L"utils.js"}, - {__LINE__, - "http://www.goodguy.com/utils.js", - "filename=utils.js", - "", - "", - "text/javascript;version=2", - L"download", - L"utils.js"}, - {__LINE__, - "http://www.goodguy.com/utils.js", - "filename=utils.js", - "", - "", - "application/ecmascript", - L"download", - L"utils.js"}, - {__LINE__, - "http://www.goodguy.com/utils.js", - "filename=utils.js", - "", - "", - "application/ecmascript;version=4", - L"download", - L"utils.js"}, - {__LINE__, - "http://www.goodguy.com/program.exe", - "filename=program.exe", - "", - "", - "application/foo-bar", - L"download", - L"program.exe"}, - {__LINE__, - "http://www.evil.com/../foo.txt", - "filename=../foo.txt", - "", - "", - "text/plain", - L"download", - L"-foo.txt"}, - {__LINE__, - "http://www.evil.com/..\\foo.txt", - "filename=..\\foo.txt", - "", - "", - "text/plain", - L"download", - L"-foo.txt"}, - {__LINE__, - "http://www.evil.com/.hidden", - "filename=.hidden", - "", - "", - "text/plain", - L"download", - L"hidden"}, - {__LINE__, - "http://www.evil.com/trailing.", - "filename=trailing.", - "", - "", - "dance/party", - L"download", + {__LINE__, "http://www.goodguy.com/utils.js", "filename=utils.js", "", "", + "application/x-javascript", L"download", L"utils.js"}, + {__LINE__, "http://www.goodguy.com/contacts.js", "filename=contacts.js", "", + "", "application/json", L"download", L"contacts.js"}, + {__LINE__, "http://www.goodguy.com/utils.js", "filename=utils.js", "", "", + "text/javascript", L"download", L"utils.js"}, + {__LINE__, "http://www.goodguy.com/utils.js", "filename=utils.js", "", "", + "text/javascript;version=2", L"download", L"utils.js"}, + {__LINE__, "http://www.goodguy.com/utils.js", "filename=utils.js", "", "", + "application/ecmascript", L"download", L"utils.js"}, + {__LINE__, "http://www.goodguy.com/utils.js", "filename=utils.js", "", "", + "application/ecmascript;version=4", L"download", L"utils.js"}, + {__LINE__, "http://www.goodguy.com/program.exe", "filename=program.exe", "", + "", "application/foo-bar", L"download", L"program.exe"}, + {__LINE__, "http://www.evil.com/../foo.txt", "filename=../foo.txt", "", "", + "text/plain", L"download", L"-foo.txt"}, + {__LINE__, "http://www.evil.com/..\\foo.txt", "filename=..\\foo.txt", "", + "", "text/plain", L"download", L"-foo.txt"}, + {__LINE__, "http://www.evil.com/.hidden", "filename=.hidden", "", "", + "text/plain", L"download", L"hidden"}, + {__LINE__, "http://www.evil.com/trailing.", "filename=trailing.", "", "", + "dance/party", L"download", #if defined(OS_WIN) L"trailing-" #else L"trailing" #endif }, - {__LINE__, - "http://www.evil.com/trailing.", - "filename=trailing.", - "", - "", - "text/plain", - L"download", + {__LINE__, "http://www.evil.com/trailing.", "filename=trailing.", "", "", + "text/plain", L"download", #if defined(OS_WIN) L"trailing-" #else L"trailing" #endif }, - {__LINE__, - "http://www.evil.com/.", - "filename=.", - "", - "", - "dance/party", - L"download", - L"download"}, - {__LINE__, - "http://www.evil.com/..", - "filename=..", - "", - "", - "dance/party", - L"download", - L"download"}, - {__LINE__, - "http://www.evil.com/...", - "filename=...", - "", - "", - "dance/party", - L"download", - L"download"}, + {__LINE__, "http://www.evil.com/.", "filename=.", "", "", "dance/party", + L"download", L"download"}, + {__LINE__, "http://www.evil.com/..", "filename=..", "", "", "dance/party", + L"download", L"download"}, + {__LINE__, "http://www.evil.com/...", "filename=...", "", "", "dance/party", + L"download", L"download"}, {// Note that this one doesn't have "filename=" on it. - __LINE__, - "http://www.evil.com/", - "a_file_name.txt", - "", - "", - "image/jpeg", - L"download", - L"download" JPEG_EXT}, - {__LINE__, - "http://www.evil.com/", - "filename=", - "", - "", - "image/jpeg", - L"download", - L"download" JPEG_EXT}, - {__LINE__, - "http://www.example.com/simple", - "filename=simple", - "", - "", - "application/octet-stream", - L"download", - L"simple"}, + __LINE__, "http://www.evil.com/", "a_file_name.txt", "", "", "image/jpeg", + L"download", L"download" JPEG_EXT}, + {__LINE__, "http://www.evil.com/", "filename=", "", "", "image/jpeg", + L"download", L"download" JPEG_EXT}, + {__LINE__, "http://www.example.com/simple", "filename=simple", "", "", + "application/octet-stream", L"download", L"simple"}, // Reserved words on Windows - {__LINE__, - "http://www.goodguy.com/COM1", - "filename=COM1", - "", - "", - "application/foo-bar", - L"download", + {__LINE__, "http://www.goodguy.com/COM1", "filename=COM1", "", "", + "application/foo-bar", L"download", #if defined(OS_WIN) L"_COM1" #else L"COM1" #endif }, - {__LINE__, - "http://www.goodguy.com/COM4.txt", - "filename=COM4.txt", - "", - "", - "text/plain", - L"download", + {__LINE__, "http://www.goodguy.com/COM4.txt", "filename=COM4.txt", "", "", + "text/plain", L"download", #if defined(OS_WIN) L"_COM4.txt" #else L"COM4.txt" #endif }, - {__LINE__, - "http://www.goodguy.com/lpt1.TXT", - "filename=lpt1.TXT", - "", - "", - "text/plain", - L"download", + {__LINE__, "http://www.goodguy.com/lpt1.TXT", "filename=lpt1.TXT", "", "", + "text/plain", L"download", #if defined(OS_WIN) L"_lpt1.TXT" #else L"lpt1.TXT" #endif }, - {__LINE__, - "http://www.goodguy.com/clock$.txt", - "filename=clock$.txt", - "", - "", - "text/plain", - L"download", + {__LINE__, "http://www.goodguy.com/clock$.txt", "filename=clock$.txt", "", + "", "text/plain", L"download", #if defined(OS_WIN) L"_clock$.txt" #else @@ -1200,46 +943,26 @@ #endif }, {// Validation should also apply to sugested name - __LINE__, - "http://www.goodguy.com/blah$.txt", - "filename=clock$.txt", - "", - "clock$.txt", - "text/plain", - L"download", + __LINE__, "http://www.goodguy.com/blah$.txt", "filename=clock$.txt", "", + "clock$.txt", "text/plain", L"download", #if defined(OS_WIN) L"_clock$.txt" #else L"clock$.txt" #endif }, - {__LINE__, - "http://www.goodguy.com/mycom1.foo", - "filename=mycom1.foo", - "", - "", - "text/plain", - L"download", - L"mycom1.foo"}, - {__LINE__, - "http://www.badguy.com/Setup.exe.local", - "filename=Setup.exe.local", - "", - "", - "application/foo-bar", - L"download", + {__LINE__, "http://www.goodguy.com/mycom1.foo", "filename=mycom1.foo", "", + "", "text/plain", L"download", L"mycom1.foo"}, + {__LINE__, "http://www.badguy.com/Setup.exe.local", + "filename=Setup.exe.local", "", "", "application/foo-bar", L"download", #if defined(OS_WIN) L"Setup.exe.download" #else L"Setup.exe.local" #endif }, - {__LINE__, - "http://www.badguy.com/Setup.exe.local", - "filename=Setup.exe.local.local", - "", - "", - "application/foo-bar", + {__LINE__, "http://www.badguy.com/Setup.exe.local", + "filename=Setup.exe.local.local", "", "", "application/foo-bar", L"download", #if defined(OS_WIN) L"Setup.exe.local.download" @@ -1247,159 +970,79 @@ L"Setup.exe.local.local" #endif }, - {__LINE__, - "http://www.badguy.com/Setup.exe.lnk", - "filename=Setup.exe.lnk", - "", - "", - "application/foo-bar", - L"download", + {__LINE__, "http://www.badguy.com/Setup.exe.lnk", "filename=Setup.exe.lnk", + "", "", "application/foo-bar", L"download", #if defined(OS_WIN) L"Setup.exe.download" #else L"Setup.exe.lnk" #endif }, - {__LINE__, - "http://www.badguy.com/Desktop.ini", - "filename=Desktop.ini", - "", - "", - "application/foo-bar", - L"download", + {__LINE__, "http://www.badguy.com/Desktop.ini", "filename=Desktop.ini", "", + "", "application/foo-bar", L"download", #if defined(OS_WIN) L"_Desktop.ini" #else L"Desktop.ini" #endif }, - {__LINE__, - "http://www.badguy.com/Thumbs.db", - "filename=Thumbs.db", - "", - "", - "application/foo-bar", - L"download", + {__LINE__, "http://www.badguy.com/Thumbs.db", "filename=Thumbs.db", "", "", + "application/foo-bar", L"download", #if defined(OS_WIN) L"_Thumbs.db" #else L"Thumbs.db" #endif }, - {__LINE__, - "http://www.hotmail.com", - "filename=source.jpg", - "", - "", - "application/x-javascript", - L"download", - L"source.jpg"}, + {__LINE__, "http://www.hotmail.com", "filename=source.jpg", "", "", + "application/x-javascript", L"download", L"source.jpg"}, {// http://crbug.com/5772. - __LINE__, - "http://www.example.com/foo.tar.gz", - "", - "", - "", - "application/x-tar", - L"download", - L"foo.tar.gz"}, + __LINE__, "http://www.example.com/foo.tar.gz", "", "", "", + "application/x-tar", L"download", L"foo.tar.gz"}, {// http://crbug.com/52250. - __LINE__, - "http://www.example.com/foo.tgz", - "", - "", - "", - "application/x-tar", - L"download", - L"foo.tgz"}, + __LINE__, "http://www.example.com/foo.tgz", "", "", "", + "application/x-tar", L"download", L"foo.tgz"}, {// http://crbug.com/7337. - __LINE__, - "http://maged.lordaeron.org/blank.reg", - "", - "", - "", - "text/x-registry", - L"download", - L"blank.reg"}, - {__LINE__, - "http://www.example.com/bar.tar", - "", - "", - "", - "application/x-tar", - L"download", - L"bar.tar"}, - {__LINE__, - "http://www.example.com/bar.bogus", - "", - "", - "", - "application/x-tar", - L"download", - L"bar.bogus"}, + __LINE__, "http://maged.lordaeron.org/blank.reg", "", "", "", + "text/x-registry", L"download", L"blank.reg"}, + {__LINE__, "http://www.example.com/bar.tar", "", "", "", + "application/x-tar", L"download", L"bar.tar"}, + {__LINE__, "http://www.example.com/bar.bogus", "", "", "", + "application/x-tar", L"download", L"bar.bogus"}, {// http://crbug.com/20337 - __LINE__, - "http://www.example.com/.download.txt", - "filename=.download.txt", - "", - "", - "text/plain", - L"-download", - L"download.txt"}, + __LINE__, "http://www.example.com/.download.txt", "filename=.download.txt", + "", "", "text/plain", L"-download", L"download.txt"}, {// http://crbug.com/56855. - __LINE__, - "http://www.example.com/bar.sh", - "", - "", - "", - "application/x-sh", - L"download", - L"bar.sh"}, + __LINE__, "http://www.example.com/bar.sh", "", "", "", "application/x-sh", + L"download", L"bar.sh"}, {// http://crbug.com/61571 - __LINE__, - "http://www.example.com/npdf.php?fn=foobar.pdf", - "", - "", - "", - "text/plain", - L"download", - L"npdf" TXT_EXT}, + __LINE__, "http://www.example.com/npdf.php?fn=foobar.pdf", "", "", "", + "text/plain", L"download", L"npdf" TXT_EXT}, {// Shouldn't overwrite C-D specified extension. - __LINE__, - "http://www.example.com/npdf.php?fn=foobar.pdf", - "filename=foobar.jpg", - "", - "", - "text/plain", - L"download", - L"foobar.jpg"}, + __LINE__, "http://www.example.com/npdf.php?fn=foobar.pdf", + "filename=foobar.jpg", "", "", "text/plain", L"download", L"foobar.jpg"}, {// http://crbug.com/87719 - __LINE__, - "http://www.example.com/image.aspx?id=blargh", - "", - "", - "", - "image/jpeg", - L"download", - L"image" JPEG_EXT}, - {__LINE__, - "http://www.example.com/image.aspx?id=blargh", - "", - "", - " .foo", - "", - L"download", - L"-.foo"}, + __LINE__, "http://www.example.com/image.aspx?id=blargh", "", "", "", + "image/jpeg", L"download", L"image" JPEG_EXT}, + {__LINE__, "http://www.example.com/image.aspx?id=blargh", "", "", " .foo", + "", L"download", L"-.foo"}, + + // Note that the next 4 tests will not fail on all platforms on regression. + // They only fail if application/[x-]gzip has a default extension, which + // can vary across platforms (And even by OS install). + {__LINE__, "http://www.example.com/goat.tar.gz?wearing_hat=true", "", "", + "", "application/gzip", L"", L"goat.tar.gz"}, + {__LINE__, "http://www.example.com/goat.tar.gz?wearing_hat=true", "", "", + "", "application/x-gzip", L"", L"goat.tar.gz"}, + {__LINE__, "http://www.example.com/goat.tgz?wearing_hat=true", "", "", "", + "application/gzip", L"", L"goat.tgz"}, + {__LINE__, "http://www.example.com/goat.tgz?wearing_hat=true", "", "", "", + "application/x-gzip", L"", L"goat.tgz"}, + #if defined(OS_CHROMEOS) {// http://crosbug.com/26028 - __LINE__, - "http://www.example.com/fooa%cc%88.txt", - "", - "", - "", - "image/jpeg", - L"foo\xe4", - L"foo\xe4.txt"}, + __LINE__, "http://www.example.com/fooa%cc%88.txt", "", "", "", + "image/jpeg", L"foo\xe4", L"foo\xe4.txt"}, #endif };
diff --git a/net/base/mime_util.cc b/net/base/mime_util.cc index 0d51120..d1e202b 100644 --- a/net/base/mime_util.cc +++ b/net/base/mime_util.cc
@@ -59,54 +59,54 @@ static base::LazyInstance<MimeUtil>::Leaky g_mime_util = LAZY_INSTANCE_INITIALIZER; -static const MimeInfo primary_mappings[] = { - { "text/html", "html,htm,shtml,shtm" }, - { "text/css", "css" }, - { "text/xml", "xml" }, - { "image/gif", "gif" }, - { "image/jpeg", "jpeg,jpg" }, - { "image/webp", "webp" }, - { "image/png", "png" }, - { "video/mp4", "mp4,m4v" }, - { "audio/x-m4a", "m4a" }, - { "audio/mp3", "mp3" }, - { "video/ogg", "ogv,ogm" }, - { "audio/ogg", "ogg,oga,opus" }, - { "video/webm", "webm" }, - { "audio/webm", "webm" }, - { "audio/wav", "wav" }, - { "audio/flac", "flac" }, - { "application/xhtml+xml", "xhtml,xht,xhtm" }, - { "application/x-chrome-extension", "crx" }, - { "multipart/related", "mhtml,mht" } -}; +static const MimeInfo kPrimaryMappings[] = { + {"text/html", "html,htm,shtml,shtm"}, + {"text/css", "css"}, + {"text/xml", "xml"}, + {"image/gif", "gif"}, + {"image/jpeg", "jpeg,jpg"}, + {"image/webp", "webp"}, + {"image/png", "png"}, + {"video/mp4", "mp4,m4v"}, + {"audio/x-m4a", "m4a"}, + {"audio/mp3", "mp3"}, + {"video/ogg", "ogv,ogm"}, + {"audio/ogg", "ogg,oga,opus"}, + {"video/webm", "webm"}, + {"audio/webm", "webm"}, + {"audio/wav", "wav"}, + {"audio/flac", "flac"}, + {"application/xhtml+xml", "xhtml,xht,xhtm"}, + {"application/x-chrome-extension", "crx"}, + {"multipart/related", "mhtml,mht"}}; -static const MimeInfo secondary_mappings[] = { - { "application/octet-stream", "exe,com,bin" }, - { "application/gzip", "gz" }, - { "application/pdf", "pdf" }, - { "application/postscript", "ps,eps,ai" }, - { "application/javascript", "js" }, - { "application/font-woff", "woff" }, - { "image/bmp", "bmp" }, - { "image/x-icon", "ico" }, - { "image/vnd.microsoft.icon", "ico" }, - { "image/jpeg", "jfif,pjpeg,pjp" }, - { "image/tiff", "tiff,tif" }, - { "image/x-xbitmap", "xbm" }, - { "image/svg+xml", "svg,svgz" }, - { "image/x-png", "png"}, - { "message/rfc822", "eml" }, - { "text/plain", "txt,text" }, - { "text/html", "ehtml" }, - { "application/rss+xml", "rss" }, - { "application/rdf+xml", "rdf" }, - { "text/xml", "xsl,xbl,xslt" }, - { "application/vnd.mozilla.xul+xml", "xul" }, - { "application/x-shockwave-flash", "swf,swl" }, - { "application/pkcs7-mime", "p7m,p7c,p7z" }, - { "application/pkcs7-signature", "p7s" }, - { "application/x-mpegurl", "m3u8" }, +static const MimeInfo kSecondaryMappings[] = { + {"application/octet-stream", "exe,com,bin"}, + {"application/gzip", "gz,tgz"}, + {"application/x-gzip", "gz,tgz"}, + {"application/pdf", "pdf"}, + {"application/postscript", "ps,eps,ai"}, + {"application/javascript", "js"}, + {"application/font-woff", "woff"}, + {"image/bmp", "bmp"}, + {"image/x-icon", "ico"}, + {"image/vnd.microsoft.icon", "ico"}, + {"image/jpeg", "jfif,pjpeg,pjp"}, + {"image/tiff", "tiff,tif"}, + {"image/x-xbitmap", "xbm"}, + {"image/svg+xml", "svg,svgz"}, + {"image/x-png", "png"}, + {"message/rfc822", "eml"}, + {"text/plain", "txt,text"}, + {"text/html", "ehtml"}, + {"application/rss+xml", "rss"}, + {"application/rdf+xml", "rdf"}, + {"text/xml", "xsl,xbl,xslt"}, + {"application/vnd.mozilla.xul+xml", "xul"}, + {"application/x-shockwave-flash", "swf,swl"}, + {"application/pkcs7-mime", "p7m,p7c,p7z"}, + {"application/pkcs7-signature", "p7s"}, + {"application/x-mpegurl", "m3u8"}, }; const char* FindMimeType(const MimeInfo* mappings, @@ -174,7 +174,7 @@ base::FilePath path_ext(ext); const string ext_narrow_str = path_ext.AsUTF8Unsafe(); const char* mime_type = FindMimeType( - primary_mappings, arraysize(primary_mappings), ext_narrow_str); + kPrimaryMappings, arraysize(kPrimaryMappings), ext_narrow_str); if (mime_type) { *result = mime_type; return true; @@ -183,7 +183,7 @@ if (include_platform_types && GetPlatformMimeTypeFromExtension(ext, result)) return true; - mime_type = FindMimeType(secondary_mappings, arraysize(secondary_mappings), + mime_type = FindMimeType(kSecondaryMappings, arraysize(kSecondaryMappings), ext_narrow_str); if (mime_type) { *result = mime_type; @@ -490,15 +490,13 @@ // Also look up the extensions from hard-coded mappings in case that some // supported extensions are not registered in the system registry, like ogg. - GetExtensionsFromHardCodedMappings(primary_mappings, - arraysize(primary_mappings), - leading_mime_type, - extensions); + GetExtensionsFromHardCodedMappings(kPrimaryMappings, + arraysize(kPrimaryMappings), + leading_mime_type, extensions); - GetExtensionsFromHardCodedMappings(secondary_mappings, - arraysize(secondary_mappings), - leading_mime_type, - extensions); + GetExtensionsFromHardCodedMappings(kSecondaryMappings, + arraysize(kSecondaryMappings), + leading_mime_type, extensions); } // Note that the elements in the source set will be appended to the target @@ -547,14 +545,12 @@ // Also look up the extensions from hard-coded mappings in case that some // supported extensions are not registered in the system registry, like ogg. - GetExtensionsFromHardCodedMappings(primary_mappings, - arraysize(primary_mappings), - mime_type, + GetExtensionsFromHardCodedMappings(kPrimaryMappings, + arraysize(kPrimaryMappings), mime_type, &unique_extensions); - GetExtensionsFromHardCodedMappings(secondary_mappings, - arraysize(secondary_mappings), - mime_type, + GetExtensionsFromHardCodedMappings(kSecondaryMappings, + arraysize(kSecondaryMappings), mime_type, &unique_extensions); }
diff --git a/net/base/net_util.cc b/net/base/net_util.cc index 52c8bf8..afd4824 100644 --- a/net/base/net_util.cc +++ b/net/base/net_util.cc
@@ -23,7 +23,6 @@ #include <unistd.h> #endif // defined(OS_POSIX) -#include "base/json/string_escape.h" #include "base/logging.h" #include "base/strings/string_split.h" #include "base/strings/string_util.h" @@ -34,10 +33,8 @@ #include "net/base/address_list.h" #include "net/base/escape.h" #include "net/base/ip_address_number.h" -#include "net/base/net_module.h" #include "net/base/registry_controlled_domains/registry_controlled_domain.h" #include "net/base/url_util.h" -#include "net/grit/net_resources.h" #include "url/gurl.h" #include "url/third_party/mozilla/url_parse.h" #include "url/url_canon.h" @@ -97,24 +94,6 @@ return canon_host; } -std::string GetDirectoryListingHeader(const base::string16& title) { - static const base::StringPiece header( - NetModule::GetResource(IDR_DIR_HEADER_HTML)); - // This can be null in unit tests. - DLOG_IF(WARNING, header.empty()) << - "Missing resource: directory listing header"; - - std::string result; - if (!header.empty()) - result.assign(header.data(), header.size()); - - result.append("<script>start("); - base::EscapeJSONString(title, true, &result); - result.append(");</script>\n"); - - return result; -} - inline bool IsHostCharAlphanumeric(char c) { // We can just check lowercase because uppercase characters have already been // normalized.
diff --git a/net/base/net_util.h b/net/base/net_util.h index 85851b8..eb869b4e 100644 --- a/net/base/net_util.h +++ b/net/base/net_util.h
@@ -117,28 +117,6 @@ // CanonicalizeHost(), or you may not get accurate results. NET_EXPORT bool IsCanonicalizedHostCompliant(const std::string& host); -// Call these functions to get the html snippet for a directory listing. -// The return values of both functions are in UTF-8. -NET_EXPORT std::string GetDirectoryListingHeader(const base::string16& title); - -// Given the name of a file in a directory (ftp or local) and -// other information (is_dir, size, modification time), it returns -// the html snippet to add the entry for the file to the directory listing. -// Currently, it's a script tag containing a call to a Javascript function -// |addRow|. -// -// |name| is the file name to be displayed. |raw_bytes| will be used -// as the actual target of the link (so for example, ftp links should use -// server's encoding). If |raw_bytes| is an empty string, UTF-8 encoded |name| -// will be used. -// -// Both |name| and |raw_bytes| are escaped internally. -NET_EXPORT std::string GetDirectoryListingEntry(const base::string16& name, - const std::string& raw_bytes, - bool is_dir, - int64_t size, - base::Time modified); - // Strip the portions of |url| that aren't core to the network request. // - user name / password // - reference section
diff --git a/net/dns/mdns_cache.cc b/net/dns/mdns_cache.cc index a55fdca5..2c57828 100644 --- a/net/dns/mdns_cache.cc +++ b/net/dns/mdns_cache.cc
@@ -8,7 +8,6 @@ #include <tuple> #include <utility> -#include "base/stl_util.h" #include "base/strings/string_number_conversions.h" #include "net/dns/dns_protocol.h" #include "net/dns/record_parsed.h" @@ -66,20 +65,14 @@ } MDnsCache::~MDnsCache() { - Clear(); -} - -void MDnsCache::Clear() { - next_expiration_ = base::Time(); - STLDeleteValues(&mdns_cache_); } const RecordParsed* MDnsCache::LookupKey(const Key& key) { RecordMap::iterator found = mdns_cache_.find(key); if (found != mdns_cache_.end()) { - return found->second; + return found->second.get(); } - return NULL; + return nullptr; } MDnsCache::UpdateType MDnsCache::UpdateDnsRecord( @@ -95,20 +88,18 @@ new_expiration = std::min(new_expiration, next_expiration_); std::pair<RecordMap::iterator, bool> insert_result = - mdns_cache_.insert(std::make_pair(cache_key, (const RecordParsed*)NULL)); + mdns_cache_.insert(std::make_pair(cache_key, nullptr)); UpdateType type = NoChange; if (insert_result.second) { type = RecordAdded; } else { - const RecordParsed* other_record = insert_result.first->second; - - if (record->ttl() != 0 && !record->IsEqual(other_record, true)) { + if (record->ttl() != 0 && + !record->IsEqual(insert_result.first->second.get(), true)) { type = RecordChanged; } - delete other_record; } - insert_result.first->second = record.release(); + insert_result.first->second = std::move(record); next_expiration_ = new_expiration; return type; } @@ -125,10 +116,9 @@ for (RecordMap::iterator i = mdns_cache_.begin(); i != mdns_cache_.end(); ) { - base::Time expiration = GetEffectiveExpiration(i->second); + base::Time expiration = GetEffectiveExpiration(i->second.get()); if (now >= expiration) { - record_removed_callback.Run(i->second); - delete i->second; + record_removed_callback.Run(i->second.get()); mdns_cache_.erase(i++); } else { if (next_expiration == base::Time() || expiration < next_expiration) { @@ -155,7 +145,7 @@ break; } - const RecordParsed* record = i->second; + const RecordParsed* record = i->second.get(); // Records are deleted only upon request. if (now >= GetEffectiveExpiration(record)) continue; @@ -169,17 +159,17 @@ Key key = Key::CreateFor(record); RecordMap::iterator found = mdns_cache_.find(key); - if (found != mdns_cache_.end() && found->second == record) { + if (found != mdns_cache_.end() && found->second.get() == record) { + scoped_ptr<const RecordParsed> result = std::move(found->second); mdns_cache_.erase(key); - return scoped_ptr<const RecordParsed>(record); + return result; } return scoped_ptr<const RecordParsed>(); } // static -std::string MDnsCache::GetOptionalFieldForRecord( - const RecordParsed* record) { +std::string MDnsCache::GetOptionalFieldForRecord(const RecordParsed* record) { switch (record->type()) { case PtrRecordRdata::kType: { const PtrRecordRdata* rdata = record->rdata<PtrRecordRdata>();
diff --git a/net/dns/mdns_cache.h b/net/dns/mdns_cache.h index e8f9153..38f121a 100644 --- a/net/dns/mdns_cache.h +++ b/net/dns/mdns_cache.h
@@ -93,10 +93,8 @@ // passed in if it was removed, scoped null otherwise. scoped_ptr<const RecordParsed> RemoveRecord(const RecordParsed* record); - void Clear(); - private: - typedef std::map<Key, const RecordParsed*> RecordMap; + typedef std::map<Key, scoped_ptr<const RecordParsed>> RecordMap; // Get the effective expiration of a cache entry, based on its creation time // and TTL. Does adjustments so entries with a TTL of zero will have a @@ -106,8 +104,7 @@ // Get optional part of the DNS key for shared records. For example, in PTR // records this is the pointed domain, since multiple PTR records may exist // for the same name. - static std::string GetOptionalFieldForRecord( - const RecordParsed* record); + static std::string GetOptionalFieldForRecord(const RecordParsed* record); RecordMap mdns_cache_;
diff --git a/net/http/http_auth_handler_factory.cc b/net/http/http_auth_handler_factory.cc index 9e83c09..c03792f 100644 --- a/net/http/http_auth_handler_factory.cc +++ b/net/http/http_auth_handler_factory.cc
@@ -100,8 +100,6 @@ } HttpAuthHandlerRegistryFactory::~HttpAuthHandlerRegistryFactory() { - STLDeleteContainerPairSecondPointers(factory_map_.begin(), - factory_map_.end()); } void HttpAuthHandlerRegistryFactory::SetHttpAuthPreferences( @@ -117,14 +115,10 @@ HttpAuthHandlerFactory* factory) { factory->set_http_auth_preferences(http_auth_preferences()); std::string lower_scheme = base::ToLowerASCII(scheme); - FactoryMap::iterator it = factory_map_.find(lower_scheme); - if (it != factory_map_.end()) { - delete it->second; - } if (factory) - factory_map_[lower_scheme] = factory; + factory_map_[lower_scheme] = make_scoped_ptr(factory); else - factory_map_.erase(it); + factory_map_.erase(lower_scheme); } HttpAuthHandlerFactory* HttpAuthHandlerRegistryFactory::GetSchemeFactory( @@ -134,7 +128,7 @@ if (it == factory_map_.end()) { return NULL; // |scheme| is not registered. } - return it->second; + return it->second.get(); } // static @@ -158,7 +152,7 @@ scoped_ptr<HttpAuthHandlerRegistryFactory> registry_factory( CreateAuthHandlerRegistryFactory(*prefs, host_resolver)); registry_factory->set_http_auth_preferences(prefs); - for (auto factory_entry : registry_factory->factory_map_) { + for (auto& factory_entry : registry_factory->factory_map_) { factory_entry.second->set_http_auth_preferences(prefs); } return registry_factory;
diff --git a/net/http/http_auth_handler_factory.h b/net/http/http_auth_handler_factory.h index 2cbf345..a98f9d7 100644 --- a/net/http/http_auth_handler_factory.h +++ b/net/http/http_auth_handler_factory.h
@@ -184,7 +184,7 @@ scoped_ptr<HttpAuthHandler>* handler) override; private: - typedef std::map<std::string, HttpAuthHandlerFactory*> FactoryMap; + using FactoryMap = std::map<std::string, scoped_ptr<HttpAuthHandlerFactory>>; FactoryMap factory_map_; DISALLOW_COPY_AND_ASSIGN(HttpAuthHandlerRegistryFactory);
diff --git a/net/http/http_network_session.cc b/net/http/http_network_session.cc index 94f4b0c..59b955f 100644 --- a/net/http/http_network_session.cc +++ b/net/http/http_network_session.cc
@@ -119,7 +119,8 @@ quic_random(NULL), quic_max_packet_length(kDefaultMaxPacketSize), enable_user_alternate_protocol_ports(false), - quic_crypto_client_stream_factory(NULL), + quic_crypto_client_stream_factory( + QuicCryptoClientStreamFactory::GetDefaultFactory()), quic_max_recent_disabled_reasons(kQuicMaxRecentDisabledReasons), quic_threshold_public_resets_post_handshake(0), quic_threshold_timeouts_streams_open(0),
diff --git a/net/http/http_request_headers.cc b/net/http/http_request_headers.cc index 8e6d88f..d3f1401c 100644 --- a/net/http/http_request_headers.cc +++ b/net/http/http_request_headers.cc
@@ -156,15 +156,9 @@ void HttpRequestHeaders::AddHeadersFromString( const base::StringPiece& headers) { - // TODO(willchan): Consider adding more StringPiece support in string_util.h - // to eliminate copies. - std::vector<std::string> header_line_vector; - base::SplitStringUsingSubstr(headers.as_string(), "\r\n", - &header_line_vector); - for (std::vector<std::string>::const_iterator it = header_line_vector.begin(); - it != header_line_vector.end(); ++it) { - if (!it->empty()) - AddHeaderFromString(*it); + for (const base::StringPiece& header : base::SplitStringPieceUsingSubstr( + headers, "\r\n", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY)) { + AddHeaderFromString(header); } }
diff --git a/net/http/http_server_properties_manager.cc b/net/http/http_server_properties_manager.cc index ffe234a..70dc3e8 100644 --- a/net/http/http_server_properties_manager.cc +++ b/net/http/http_server_properties_manager.cc
@@ -35,7 +35,7 @@ const int kMissingVersion = 0; // The version number of persisted http_server_properties. -const int kVersionNumber = 3; +const int kVersionNumber = 4; // Persist 200 MRU AlternateProtocolHostPortPairs. const int kMaxAlternateProtocolHostsToPersist = 200; @@ -445,23 +445,44 @@ return; } - // The properties for a given server is in - // http_server_properties_dict["servers"][server]. - // Server data was stored in the following format in alphabetical order. - // - // "http_server_properties": { - // "servers": { - // "accounts.google.com:443": {...}, - // "accounts.youtube.com:443": {...}, - // "android.clients.google.com:443": {...}, - // ... - // }, ... - // }, - const base::DictionaryValue* servers_dict = NULL; - if (!http_server_properties_dict.GetDictionaryWithoutPathExpansion( - kServersKey, &servers_dict)) { - DVLOG(1) << "Malformed http_server_properties for servers."; - return; + const base::DictionaryValue* servers_dict = nullptr; + const base::ListValue* servers_list = nullptr; + if (version < 4) { + // The properties for a given server is in + // http_server_properties_dict["servers"][server]. + // Before Version 4, server data was stored in the following format in + // alphabetical order. + // + // "http_server_properties": { + // "servers": { + // "0-edge-chat.facebook.com:443" : {...}, + // "0.client-channel.google.com:443" : {...}, + // "yt3.ggpht.com:443" : {...}, + // ... + // }, ... + // }, + if (!http_server_properties_dict.GetDictionaryWithoutPathExpansion( + kServersKey, &servers_dict)) { + DVLOG(1) << "Malformed http_server_properties for servers."; + return; + } + } else { + // From Version 4 onwards, data was stored in the following format. + // |servers| are saved in MRU order. + // + // "http_server_properties": { + // "servers": [ + // {"yt3.ggpht.com:443" : {...}}, + // {"0.client-channel.google.com:443" : {...}}, + // {"0-edge-chat.facebook.com:443" : {...}}, + // ... + // ], ... + // }, + if (!http_server_properties_dict.GetListWithoutPathExpansion( + kServersKey, &servers_list)) { + DVLOG(1) << "Malformed http_server_properties for servers list."; + return; + } } IPAddressNumber* addr = new IPAddressNumber; @@ -478,10 +499,26 @@ scoped_ptr<QuicServerInfoMap> quic_server_info_map( new QuicServerInfoMap(kMaxQuicServersToPersist)); - if (!AddServersData(*servers_dict, spdy_servers.get(), - spdy_settings_map.get(), alternative_service_map.get(), - server_network_stats_map.get())) { - detected_corrupted_prefs = true; + if (version < 4) { + if (!AddServersData(*servers_dict, spdy_servers.get(), + spdy_settings_map.get(), alternative_service_map.get(), + server_network_stats_map.get())) { + detected_corrupted_prefs = true; + } + } else { + for (base::ListValue::const_iterator it = servers_list->begin(); + it != servers_list->end(); ++it) { + if (!(*it)->GetAsDictionary(&servers_dict)) { + DVLOG(1) << "Malformed http_server_properties for servers dictionary."; + detected_corrupted_prefs = true; + continue; + } + if (!AddServersData( + *servers_dict, spdy_servers.get(), spdy_settings_map.get(), + alternative_service_map.get(), server_network_stats_map.get())) { + detected_corrupted_prefs = true; + } + } } if (!AddToQuicServerInfoMap(http_server_properties_dict, @@ -517,7 +554,7 @@ return false; } - const base::DictionaryValue* server_pref_dict = NULL; + const base::DictionaryValue* server_pref_dict = nullptr; if (!it.value().GetAsDictionary(&server_pref_dict)) { DVLOG(1) << "Malformed http_server_properties server: " << server_str; return false; @@ -546,7 +583,7 @@ SpdySettingsMap* spdy_settings_map) { // Get SpdySettings. DCHECK(spdy_settings_map->Peek(server) == spdy_settings_map->end()); - const base::DictionaryValue* spdy_settings_dict = NULL; + const base::DictionaryValue* spdy_settings_dict = nullptr; if (!server_pref_dict.GetDictionaryWithoutPathExpansion( kSettingsKey, &spdy_settings_dict)) { return; @@ -693,7 +730,7 @@ bool HttpServerPropertiesManager::ReadSupportsQuic( const base::DictionaryValue& http_server_properties_dict, IPAddressNumber* last_quic_address) { - const base::DictionaryValue* supports_quic_dict = NULL; + const base::DictionaryValue* supports_quic_dict = nullptr; if (!http_server_properties_dict.GetDictionaryWithoutPathExpansion( kSupportsQuicKey, &supports_quic_dict)) { return true; @@ -722,7 +759,7 @@ const base::DictionaryValue& server_pref_dict, ServerNetworkStatsMap* network_stats_map) { DCHECK(network_stats_map->Peek(server) == network_stats_map->end()); - const base::DictionaryValue* server_network_stats_dict = NULL; + const base::DictionaryValue* server_network_stats_dict = nullptr; if (!server_pref_dict.GetDictionaryWithoutPathExpansion( kNetworkStatsKey, &server_network_stats_dict)) { return true; @@ -745,7 +782,7 @@ bool HttpServerPropertiesManager::AddToQuicServerInfoMap( const base::DictionaryValue& http_server_properties_dict, QuicServerInfoMap* quic_server_info_map) { - const base::DictionaryValue* quic_servers_dict = NULL; + const base::DictionaryValue* quic_servers_dict = nullptr; if (!http_server_properties_dict.GetDictionaryWithoutPathExpansion( kQuicServers, &quic_servers_dict)) { DVLOG(1) << "Malformed http_server_properties for quic_servers."; @@ -765,7 +802,7 @@ continue; } - const base::DictionaryValue* quic_server_pref_dict = NULL; + const base::DictionaryValue* quic_server_pref_dict = nullptr; if (!it.value().GetAsDictionary(&quic_server_pref_dict)) { DVLOG(1) << "Malformed http_server_properties quic server dict: " << quic_server_id_str; @@ -861,6 +898,7 @@ const base::Closure& completion) { DCHECK(network_task_runner_->RunsTasksOnCurrentThread()); + // It is in MRU order. base::ListValue* spdy_server_list = new base::ListValue; http_server_properties_impl_->GetSpdyServerList( spdy_server_list, kMaxSupportsSpdyServerHostsToPersist); @@ -870,8 +908,9 @@ const SpdySettingsMap& main_map = http_server_properties_impl_->spdy_settings_map(); int count = 0; - for (SpdySettingsMap::const_iterator it = main_map.begin(); - it != main_map.end() && count < kMaxSpdySettingsHostsToPersist; + // Maintain MRU order. + for (SpdySettingsMap::const_reverse_iterator it = main_map.rbegin(); + it != main_map.rend() && count < kMaxSpdySettingsHostsToPersist; ++it, ++count) { spdy_settings_map->Put(it->first, it->second); } @@ -885,8 +924,9 @@ count = 0; typedef std::map<std::string, bool> CanonicalHostPersistedMap; CanonicalHostPersistedMap persisted_map; - for (AlternativeServiceMap::const_iterator it = map.begin(); - it != map.end() && count < kMaxAlternateProtocolHostsToPersist; ++it) { + // Maintain MRU order. + for (AlternativeServiceMap::const_reverse_iterator it = map.rbegin(); + it != map.rend() && count < kMaxAlternateProtocolHostsToPersist; ++it) { const HostPortPair& server = it->first; AlternativeServiceInfoVector notbroken_alternative_service_info_vector; for (const AlternativeServiceInfo& alternative_service_info : it->second) { @@ -928,14 +968,15 @@ const ServerNetworkStatsMap& network_stats_map = http_server_properties_impl_->server_network_stats_map(); count = 0; - for (ServerNetworkStatsMap::const_iterator it = network_stats_map.begin(); - it != network_stats_map.end() && + for (ServerNetworkStatsMap::const_reverse_iterator + it = network_stats_map.rbegin(); + it != network_stats_map.rend() && count < kMaxServerNetworkStatsHostsToPersist; ++it, ++count) { server_network_stats_map->Put(it->first, it->second); } - QuicServerInfoMap* quic_server_info_map = NULL; + QuicServerInfoMap* quic_server_info_map = nullptr; const QuicServerInfoMap& main_quic_server_info_map = http_server_properties_impl_->quic_server_info_map(); if (main_quic_server_info_map.size() > 0) { @@ -965,10 +1006,10 @@ struct ServerPref { ServerPref() : supports_spdy(false), - settings_map(NULL), - alternative_service_info_vector(NULL), - supports_quic(NULL), - server_network_stats(NULL) {} + settings_map(nullptr), + alternative_service_info_vector(nullptr), + supports_quic(nullptr), + server_network_stats(nullptr) {} ServerPref( bool supports_spdy, const SettingsMap* settings_map, @@ -987,6 +1028,7 @@ const ServerNetworkStats* server_network_stats; }; +// All maps and lists are in MRU order. void HttpServerPropertiesManager::UpdatePrefsOnPrefThread( base::ListValue* spdy_server_list, SpdySettingsMap* spdy_settings_map, @@ -995,54 +1037,80 @@ ServerNetworkStatsMap* server_network_stats_map, QuicServerInfoMap* quic_server_info_map, const base::Closure& completion) { - typedef std::map<HostPortPair, ServerPref> ServerPrefMap; - ServerPrefMap server_pref_map; + typedef base::MRUCache<HostPortPair, ServerPref> ServerPrefMap; + ServerPrefMap server_pref_map(ServerPrefMap::NO_AUTO_EVICT); DCHECK(pref_task_runner_->RunsTasksOnCurrentThread()); - // Add servers that support spdy to server_pref_map. - std::string s; - for (base::ListValue::const_iterator list_it = spdy_server_list->begin(); - list_it != spdy_server_list->end(); - ++list_it) { - if ((*list_it)->GetAsString(&s)) { + // Add servers that support spdy to server_pref_map in the MRU order. + for (size_t index = spdy_server_list->GetSize(); index > 0; --index) { + std::string s; + if (spdy_server_list->GetString(index - 1, &s)) { HostPortPair server = HostPortPair::FromString(s); - server_pref_map[server].supports_spdy = true; + ServerPrefMap::iterator it = server_pref_map.Get(server); + if (it == server_pref_map.end()) { + ServerPref server_pref; + server_pref.supports_spdy = true; + server_pref_map.Put(server, server_pref); + } else { + it->second.supports_spdy = true; + } } } - // Add servers that have SpdySettings to server_pref_map. - for (SpdySettingsMap::iterator map_it = spdy_settings_map->begin(); - map_it != spdy_settings_map->end(); ++map_it) { + // Add servers that have SpdySettings to server_pref_map in the MRU order. + for (SpdySettingsMap::reverse_iterator map_it = spdy_settings_map->rbegin(); + map_it != spdy_settings_map->rend(); ++map_it) { const HostPortPair& server = map_it->first; - server_pref_map[server].settings_map = &map_it->second; + ServerPrefMap::iterator it = server_pref_map.Get(server); + if (it == server_pref_map.end()) { + ServerPref server_pref; + server_pref.settings_map = &map_it->second; + server_pref_map.Put(server, server_pref); + } else { + it->second.settings_map = &map_it->second; + } } - // Add alternative services to server_pref_map. - for (AlternativeServiceMap::const_iterator map_it = - alternative_service_map->begin(); - map_it != alternative_service_map->end(); ++map_it) { - server_pref_map[map_it->first].alternative_service_info_vector = - &map_it->second; - } - - // Add ServerNetworkStats servers to server_pref_map. - for (ServerNetworkStatsMap::const_iterator map_it = - server_network_stats_map->begin(); - map_it != server_network_stats_map->end(); ++map_it) { + // Add alternative services to server_pref_map in the MRU order. + for (AlternativeServiceMap::const_reverse_iterator map_it = + alternative_service_map->rbegin(); + map_it != alternative_service_map->rend(); ++map_it) { const HostPortPair& server = map_it->first; - server_pref_map[server].server_network_stats = &map_it->second; + ServerPrefMap::iterator it = server_pref_map.Get(server); + if (it == server_pref_map.end()) { + ServerPref server_pref; + server_pref.alternative_service_info_vector = &map_it->second; + server_pref_map.Put(server, server_pref); + } else { + it->second.alternative_service_info_vector = &map_it->second; + } } - // Persist properties to the |path_|. + // Add ServerNetworkStats servers to server_pref_map in the MRU order. + for (ServerNetworkStatsMap::const_reverse_iterator map_it = + server_network_stats_map->rbegin(); + map_it != server_network_stats_map->rend(); ++map_it) { + const HostPortPair& server = map_it->first; + ServerPrefMap::iterator it = server_pref_map.Get(server); + if (it == server_pref_map.end()) { + ServerPref server_pref; + server_pref.server_network_stats = &map_it->second; + server_pref_map.Put(server, server_pref); + } else { + it->second.server_network_stats = &map_it->second; + } + } + + // Persist properties to the |path_| in the MRU order. base::DictionaryValue http_server_properties_dict; - base::DictionaryValue* servers_dict = new base::DictionaryValue; - for (ServerPrefMap::const_iterator map_it = server_pref_map.begin(); - map_it != server_pref_map.end(); - ++map_it) { + base::ListValue* servers_list = new base::ListValue; + for (ServerPrefMap::const_reverse_iterator map_it = server_pref_map.rbegin(); + map_it != server_pref_map.rend(); ++map_it) { const HostPortPair& server = map_it->first; const ServerPref& server_pref = map_it->second; + base::DictionaryValue* servers_dict = new base::DictionaryValue; base::DictionaryValue* server_pref_dict = new base::DictionaryValue; // Save supports_spdy. @@ -1055,10 +1123,12 @@ server_pref_dict); servers_dict->SetWithoutPathExpansion(server.ToString(), server_pref_dict); + bool value = servers_list->AppendIfNotPresent(servers_dict); + DCHECK(value); // Should never happen. } http_server_properties_dict.SetWithoutPathExpansion(kServersKey, - servers_dict); + servers_list); SetVersion(&http_server_properties_dict, kVersionNumber); SaveSupportsQuicToPrefs(last_quic_address, &http_server_properties_dict);
diff --git a/net/http/http_server_properties_manager_unittest.cc b/net/http/http_server_properties_manager_unittest.cc index 5461872..4256ae4 100644 --- a/net/http/http_server_properties_manager_unittest.cc +++ b/net/http/http_server_properties_manager_unittest.cc
@@ -106,7 +106,11 @@ } // namespace -class HttpServerPropertiesManagerTest : public testing::Test { +// TODO(rtenneti): After we stop supporting version 3 and everyone has migrated +// to version 4, delete the following code. +static const int kHttpServerPropertiesVersions[] = {3, 4}; + +class HttpServerPropertiesManagerTest : public testing::TestWithParam<int> { protected: HttpServerPropertiesManagerTest() {} @@ -183,7 +187,11 @@ DISALLOW_COPY_AND_ASSIGN(HttpServerPropertiesManagerTest); }; -TEST_F(HttpServerPropertiesManagerTest, +INSTANTIATE_TEST_CASE_P(Tests, + HttpServerPropertiesManagerTest, + ::testing::ValuesIn(kHttpServerPropertiesVersions)); + +TEST_P(HttpServerPropertiesManagerTest, SingleUpdateForTwoSpdyServerPrefChanges) { ExpectCacheUpdate(); @@ -218,6 +226,13 @@ // Set the server preference for www.google.com:80. base::DictionaryValue* servers_dict = new base::DictionaryValue; servers_dict->SetWithoutPathExpansion("www.google.com:80", server_pref_dict); + base::ListValue* servers_list = nullptr; + if (GetParam() == 4) { + servers_list = new base::ListValue; + // |servers_list| takes ownership of |servers_dict|. + servers_list->AppendIfNotPresent(servers_dict); + servers_dict = new base::DictionaryValue; + } // Set the preference for mail.google.com server. base::DictionaryValue* server_pref_dict1 = new base::DictionaryValue; @@ -234,18 +249,27 @@ server_pref_dict1->SetWithoutPathExpansion("alternative_service", alternative_service_list1); - // Set up ServerNetworkStats for mail.google.com:80. + // Set up ServerNetworkStats for mail.google.com:80 and it is the MRU server. base::DictionaryValue* stats1 = new base::DictionaryValue; stats1->SetInteger("srtt", 20); server_pref_dict1->SetWithoutPathExpansion("network_stats", stats1); // Set the server preference for mail.google.com:80. servers_dict->SetWithoutPathExpansion("mail.google.com:80", server_pref_dict1); - base::DictionaryValue* http_server_properties_dict = new base::DictionaryValue; - HttpServerPropertiesManager::SetVersion(http_server_properties_dict, -1); - http_server_properties_dict->SetWithoutPathExpansion("servers", servers_dict); + if (GetParam() == 4) { + // |servers_list| takes ownership of |servers_dict|. + servers_list->AppendIfNotPresent(servers_dict); + HttpServerPropertiesManager::SetVersion(http_server_properties_dict, -1); + http_server_properties_dict->SetWithoutPathExpansion("servers", + servers_list); + } else { + HttpServerPropertiesManager::SetVersion(http_server_properties_dict, + GetParam()); + http_server_properties_dict->SetWithoutPathExpansion("servers", + servers_dict); + } base::DictionaryValue* supports_quic = new base::DictionaryValue; supports_quic->SetBoolean("used_quic", true); supports_quic->SetString("address", "127.0.0.1"); @@ -292,24 +316,46 @@ HostPortPair::FromString("foo.google.com:1337"))); // Verify alternative service. - const AlternativeServiceMap& map = - http_server_props_manager_->alternative_service_map(); - ASSERT_EQ(2u, map.size()); - AlternativeServiceMap::const_iterator map_it = map.begin(); - EXPECT_EQ("www.google.com", map_it->first.host()); - ASSERT_EQ(2u, map_it->second.size()); - EXPECT_EQ(NPN_HTTP_2, map_it->second[0].alternative_service.protocol); - EXPECT_TRUE(map_it->second[0].alternative_service.host.empty()); - EXPECT_EQ(443, map_it->second[0].alternative_service.port); - EXPECT_EQ(QUIC, map_it->second[1].alternative_service.protocol); - EXPECT_TRUE(map_it->second[1].alternative_service.host.empty()); - EXPECT_EQ(1234, map_it->second[1].alternative_service.port); - ++map_it; - EXPECT_EQ("mail.google.com", map_it->first.host()); - ASSERT_EQ(1u, map_it->second.size()); - EXPECT_EQ(NPN_SPDY_3_1, map_it->second[0].alternative_service.protocol); - EXPECT_TRUE(map_it->second[0].alternative_service.host.empty()); - EXPECT_EQ(444, map_it->second[0].alternative_service.port); + if (GetParam() == 4) { + const AlternativeServiceMap& map = + http_server_props_manager_->alternative_service_map(); + ASSERT_EQ(2u, map.size()); + + AlternativeServiceMap::const_iterator map_it = map.begin(); + EXPECT_EQ("mail.google.com", map_it->first.host()); + ASSERT_EQ(1u, map_it->second.size()); + EXPECT_EQ(NPN_SPDY_3_1, map_it->second[0].alternative_service.protocol); + EXPECT_TRUE(map_it->second[0].alternative_service.host.empty()); + EXPECT_EQ(444, map_it->second[0].alternative_service.port); + ++map_it; + EXPECT_EQ("www.google.com", map_it->first.host()); + ASSERT_EQ(2u, map_it->second.size()); + EXPECT_EQ(NPN_HTTP_2, map_it->second[0].alternative_service.protocol); + EXPECT_TRUE(map_it->second[0].alternative_service.host.empty()); + EXPECT_EQ(443, map_it->second[0].alternative_service.port); + EXPECT_EQ(QUIC, map_it->second[1].alternative_service.protocol); + EXPECT_TRUE(map_it->second[1].alternative_service.host.empty()); + EXPECT_EQ(1234, map_it->second[1].alternative_service.port); + } else { + const AlternativeServiceMap& map = + http_server_props_manager_->alternative_service_map(); + ASSERT_EQ(2u, map.size()); + AlternativeServiceMap::const_iterator map_it = map.begin(); + EXPECT_EQ("www.google.com", map_it->first.host()); + ASSERT_EQ(2u, map_it->second.size()); + EXPECT_EQ(NPN_HTTP_2, map_it->second[0].alternative_service.protocol); + EXPECT_TRUE(map_it->second[0].alternative_service.host.empty()); + EXPECT_EQ(443, map_it->second[0].alternative_service.port); + EXPECT_EQ(QUIC, map_it->second[1].alternative_service.protocol); + EXPECT_TRUE(map_it->second[1].alternative_service.host.empty()); + EXPECT_EQ(1234, map_it->second[1].alternative_service.port); + ++map_it; + EXPECT_EQ("mail.google.com", map_it->first.host()); + ASSERT_EQ(1u, map_it->second.size()); + EXPECT_EQ(NPN_SPDY_3_1, map_it->second[0].alternative_service.protocol); + EXPECT_TRUE(map_it->second[0].alternative_service.host.empty()); + EXPECT_EQ(444, map_it->second[0].alternative_service.port); + } // Verify SupportsQuic. IPAddressNumber last_address; @@ -331,7 +377,7 @@ mail_quic_server_id)); } -TEST_F(HttpServerPropertiesManagerTest, BadCachedHostPortPair) { +TEST_P(HttpServerPropertiesManagerTest, BadCachedHostPortPair) { ExpectCacheUpdate(); // The prefs are automaticalls updated in the case corruption is detected. ExpectPrefsUpdate(); @@ -360,6 +406,21 @@ base::DictionaryValue* servers_dict = new base::DictionaryValue; servers_dict->SetWithoutPathExpansion("www.google.com:65536", server_pref_dict); + base::DictionaryValue* http_server_properties_dict = + new base::DictionaryValue; + if (GetParam() == 4) { + base::ListValue* servers_list = new base::ListValue; + // |servers_list| takes ownership of |servers_dict|. + servers_list->AppendIfNotPresent(servers_dict); + HttpServerPropertiesManager::SetVersion(http_server_properties_dict, -1); + http_server_properties_dict->SetWithoutPathExpansion("servers", + servers_list); + } else { + HttpServerPropertiesManager::SetVersion(http_server_properties_dict, + GetParam()); + http_server_properties_dict->SetWithoutPathExpansion("servers", + servers_dict); + } // Set quic_server_info for www.google.com:65536. base::DictionaryValue* quic_servers_dict = new base::DictionaryValue; @@ -369,10 +430,6 @@ quic_servers_dict->SetWithoutPathExpansion("http://mail.google.com:65536", quic_server_pref_dict1); - base::DictionaryValue* http_server_properties_dict = - new base::DictionaryValue; - HttpServerPropertiesManager::SetVersion(http_server_properties_dict, -1); - http_server_properties_dict->SetWithoutPathExpansion("servers", servers_dict); http_server_properties_dict->SetWithoutPathExpansion("quic_servers", quic_servers_dict); @@ -391,11 +448,11 @@ const ServerNetworkStats* stats1 = http_server_props_manager_->GetServerNetworkStats( HostPortPair::FromString("www.google.com:65536")); - EXPECT_EQ(NULL, stats1); + EXPECT_EQ(nullptr, stats1); EXPECT_EQ(0u, http_server_props_manager_->quic_server_info_map().size()); } -TEST_F(HttpServerPropertiesManagerTest, BadCachedAltProtocolPort) { +TEST_P(HttpServerPropertiesManagerTest, BadCachedAltProtocolPort) { ExpectCacheUpdate(); // The prefs are automaticalls updated in the case corruption is detected. ExpectPrefsUpdate(); @@ -418,11 +475,21 @@ // Set the server preference for www.google.com:80. base::DictionaryValue* servers_dict = new base::DictionaryValue; servers_dict->SetWithoutPathExpansion("www.google.com:80", server_pref_dict); - base::DictionaryValue* http_server_properties_dict = new base::DictionaryValue; - HttpServerPropertiesManager::SetVersion(http_server_properties_dict, -1); - http_server_properties_dict->SetWithoutPathExpansion("servers", servers_dict); + if (GetParam() == 4) { + base::ListValue* servers_list = new base::ListValue; + // |servers_list| takes ownership of |servers_dict|. + servers_list->AppendIfNotPresent(servers_dict); + HttpServerPropertiesManager::SetVersion(http_server_properties_dict, -1); + http_server_properties_dict->SetWithoutPathExpansion("servers", + servers_list); + } else { + HttpServerPropertiesManager::SetVersion(http_server_properties_dict, + GetParam()); + http_server_properties_dict->SetWithoutPathExpansion("servers", + servers_dict); + } // Set up the pref. pref_service_.SetManagedPref(kTestHttpServerProperties, @@ -436,7 +503,7 @@ HasAlternativeService(HostPortPair::FromString("www.google.com:80"))); } -TEST_F(HttpServerPropertiesManagerTest, SupportsSpdy) { +TEST_P(HttpServerPropertiesManagerTest, SupportsSpdy) { ExpectPrefsUpdate(); ExpectScheduleUpdatePrefsOnNetworkThread(); @@ -459,7 +526,7 @@ Mock::VerifyAndClearExpectations(http_server_props_manager_.get()); } -TEST_F(HttpServerPropertiesManagerTest, SetSpdySetting) { +TEST_P(HttpServerPropertiesManagerTest, SetSpdySetting) { ExpectPrefsUpdate(); ExpectScheduleUpdatePrefsOnNetworkThread(); @@ -486,7 +553,7 @@ Mock::VerifyAndClearExpectations(http_server_props_manager_.get()); } -TEST_F(HttpServerPropertiesManagerTest, ClearSpdySetting) { +TEST_P(HttpServerPropertiesManagerTest, ClearSpdySetting) { ExpectPrefsUpdateRepeatedly(); ExpectScheduleUpdatePrefsOnNetworkThreadRepeatedly(); @@ -525,7 +592,7 @@ Mock::VerifyAndClearExpectations(http_server_props_manager_.get()); } -TEST_F(HttpServerPropertiesManagerTest, ClearAllSpdySetting) { +TEST_P(HttpServerPropertiesManagerTest, ClearAllSpdySetting) { ExpectPrefsUpdateRepeatedly(); ExpectScheduleUpdatePrefsOnNetworkThreadRepeatedly(); @@ -563,7 +630,7 @@ Mock::VerifyAndClearExpectations(http_server_props_manager_.get()); } -TEST_F(HttpServerPropertiesManagerTest, GetAlternativeServices) { +TEST_P(HttpServerPropertiesManagerTest, GetAlternativeServices) { ExpectPrefsUpdate(); ExpectScheduleUpdatePrefsOnNetworkThread(); @@ -587,7 +654,7 @@ EXPECT_EQ(alternative_service, alternative_service_vector[0]); } -TEST_F(HttpServerPropertiesManagerTest, SetAlternativeServices) { +TEST_P(HttpServerPropertiesManagerTest, SetAlternativeServices) { ExpectPrefsUpdate(); ExpectScheduleUpdatePrefsOnNetworkThread(); @@ -618,7 +685,7 @@ EXPECT_EQ(alternative_service2, alternative_service_vector[1]); } -TEST_F(HttpServerPropertiesManagerTest, SetAlternativeServicesEmpty) { +TEST_P(HttpServerPropertiesManagerTest, SetAlternativeServicesEmpty) { HostPortPair spdy_server_mail("mail.google.com", 80); EXPECT_FALSE(HasAlternativeService(spdy_server_mail)); const AlternativeService alternative_service(NPN_HTTP_2, "mail.google.com", @@ -634,7 +701,7 @@ EXPECT_FALSE(HasAlternativeService(spdy_server_mail)); } -TEST_F(HttpServerPropertiesManagerTest, ClearAlternativeServices) { +TEST_P(HttpServerPropertiesManagerTest, ClearAlternativeServices) { ExpectPrefsUpdate(); ExpectScheduleUpdatePrefsOnNetworkThread(); @@ -655,7 +722,7 @@ EXPECT_FALSE(HasAlternativeService(spdy_server_mail)); } -TEST_F(HttpServerPropertiesManagerTest, ConfirmAlternativeService) { +TEST_P(HttpServerPropertiesManagerTest, ConfirmAlternativeService) { ExpectPrefsUpdate(); HostPortPair spdy_server_mail("mail.google.com", 80); @@ -701,7 +768,7 @@ alternative_service)); } -TEST_F(HttpServerPropertiesManagerTest, SupportsQuic) { +TEST_P(HttpServerPropertiesManagerTest, SupportsQuic) { ExpectPrefsUpdate(); ExpectScheduleUpdatePrefsOnNetworkThread(); @@ -722,14 +789,14 @@ EXPECT_EQ(actual_address, address); } -TEST_F(HttpServerPropertiesManagerTest, ServerNetworkStats) { +TEST_P(HttpServerPropertiesManagerTest, ServerNetworkStats) { ExpectPrefsUpdate(); ExpectScheduleUpdatePrefsOnNetworkThread(); HostPortPair mail_server("mail.google.com", 80); const ServerNetworkStats* stats = http_server_props_manager_->GetServerNetworkStats(mail_server); - EXPECT_EQ(NULL, stats); + EXPECT_EQ(nullptr, stats); ServerNetworkStats stats1; stats1.srtt = base::TimeDelta::FromMicroseconds(10); http_server_props_manager_->SetServerNetworkStats(mail_server, stats1); @@ -745,7 +812,7 @@ EXPECT_EQ(10, stats2->srtt.ToInternalValue()); } -TEST_F(HttpServerPropertiesManagerTest, QuicServerInfo) { +TEST_P(HttpServerPropertiesManagerTest, QuicServerInfo) { ExpectPrefsUpdate(); ExpectScheduleUpdatePrefsOnNetworkThread(); @@ -767,7 +834,7 @@ mail_quic_server_id)); } -TEST_F(HttpServerPropertiesManagerTest, Clear) { +TEST_P(HttpServerPropertiesManagerTest, Clear) { ExpectPrefsUpdate(); ExpectScheduleUpdatePrefsOnNetworkThreadRepeatedly(); @@ -833,7 +900,7 @@ EXPECT_FALSE(http_server_props_manager_->GetSupportsQuic(&address)); const ServerNetworkStats* stats2 = http_server_props_manager_->GetServerNetworkStats(spdy_server_mail); - EXPECT_EQ(NULL, stats2); + EXPECT_EQ(nullptr, stats2); EXPECT_EQ(nullptr, http_server_props_manager_->GetQuicServerInfo(mail_quic_server_id)); @@ -846,10 +913,13 @@ // https://crbug.com/444956: Add 200 alternative_service servers followed by // supports_quic and verify we have read supports_quic from prefs. -TEST_F(HttpServerPropertiesManagerTest, BadSupportsQuic) { +TEST_P(HttpServerPropertiesManagerTest, BadSupportsQuic) { ExpectCacheUpdate(); base::DictionaryValue* servers_dict = new base::DictionaryValue; + base::ListValue* servers_list = nullptr; + if (GetParam() == 4) + servers_list = new base::ListValue; for (int i = 0; i < 200; ++i) { // Set up alternative_service for www.google.com:i. @@ -861,8 +931,16 @@ base::DictionaryValue* server_pref_dict = new base::DictionaryValue; server_pref_dict->SetWithoutPathExpansion("alternative_service", alternative_service_list); - servers_dict->SetWithoutPathExpansion(StringPrintf("www.google.com:%d", i), - server_pref_dict); + if (GetParam() == 4) { + servers_dict->SetWithoutPathExpansion( + StringPrintf("www.google.com:%d", i), server_pref_dict); + // |servers_list| takes ownership of |servers_dict|. + servers_list->AppendIfNotPresent(servers_dict); + servers_dict = new base::DictionaryValue; + } else { + servers_dict->SetWithoutPathExpansion( + StringPrintf("www.google.com:%d", i), server_pref_dict); + } } // Set the preference for mail.google.com server. @@ -871,11 +949,20 @@ // Set the server preference for mail.google.com:80. servers_dict->SetWithoutPathExpansion("mail.google.com:80", server_pref_dict1); - base::DictionaryValue* http_server_properties_dict = new base::DictionaryValue; - HttpServerPropertiesManager::SetVersion(http_server_properties_dict, -1); - http_server_properties_dict->SetWithoutPathExpansion("servers", servers_dict); + if (GetParam() == 4) { + // |servers_list| takes ownership of |servers_dict|. + servers_list->AppendIfNotPresent(servers_dict); + HttpServerPropertiesManager::SetVersion(http_server_properties_dict, -1); + http_server_properties_dict->SetWithoutPathExpansion("servers", + servers_list); + } else { + HttpServerPropertiesManager::SetVersion(http_server_properties_dict, + GetParam()); + http_server_properties_dict->SetWithoutPathExpansion("servers", + servers_dict); + } // Set up SupportsQuic for 127.0.0.1 base::DictionaryValue* supports_quic = new base::DictionaryValue; @@ -908,7 +995,7 @@ EXPECT_EQ("127.0.0.1", IPAddressToString(address)); } -TEST_F(HttpServerPropertiesManagerTest, UpdateCacheWithPrefs) { +TEST_P(HttpServerPropertiesManagerTest, UpdateCacheWithPrefs) { ExpectScheduleUpdatePrefsOnNetworkThreadRepeatedly(); const HostPortPair server_www("www.google.com", 80); @@ -962,16 +1049,19 @@ const char expected_json[] = "{\"quic_servers\":{\"https://" "mail.google.com:80\":{\"server_info\":\"quic_server_info1\"}}," - "\"servers\":{\"mail.google.com:80\":{\"alternative_service\":[{" - "\"expiration\":\"9223372036854775807\",\"host\":\"foo.google.com\"," - "\"port\":444,\"probability\":0.2,\"protocol_str\":\"npn-spdy/3.1\"}]," - "\"network_stats\":{\"srtt\":42}},\"www.google.com:80\":{" + "\"servers\":[" + "{\"www.google.com:80\":{" "\"alternative_service\":[{\"expiration\":\"13756212000000000\"," "\"port\":443,\"probability\":1.0,\"protocol_str\":\"npn-h2\"}," "{\"expiration\":\"13758804000000000\",\"host\":\"www.google.com\"," "\"port\":1234,\"probability\":0.7,\"protocol_str\":\"npn-h2\"}]}}," + "{\"mail.google.com:80\":{\"alternative_service\":[{" + "\"expiration\":\"9223372036854775807\",\"host\":\"foo.google.com\"," + "\"port\":444,\"probability\":0.2,\"protocol_str\":\"npn-spdy/3.1\"}]," + "\"network_stats\":{\"srtt\":42}}}" + "]," "\"supports_quic\":{\"address\":\"127.0.0.1\",\"used_quic\":true}," - "\"version\":3}"; + "\"version\":4}"; const base::Value* http_server_properties = pref_service_.GetUserPref(kTestHttpServerProperties); @@ -982,7 +1072,7 @@ EXPECT_EQ(expected_json, preferences_json); } -TEST_F(HttpServerPropertiesManagerTest, AddToAlternativeServiceMap) { +TEST_P(HttpServerPropertiesManagerTest, AddToAlternativeServiceMap) { scoped_ptr<base::Value> server_value = base::JSONReader::Read( "{\"alternative_service\":[{\"port\":443,\"protocol_str\":\"npn-h2\"}," "{\"port\":123,\"protocol_str\":\"quic\",\"probability\":0.7," @@ -1037,7 +1127,7 @@ } // Do not persist expired or broken alternative service entries to disk. -TEST_F(HttpServerPropertiesManagerTest, +TEST_P(HttpServerPropertiesManagerTest, DoNotPersistExpiredOrBrokenAlternativeService) { ExpectScheduleUpdatePrefsOnNetworkThreadRepeatedly(); @@ -1081,8 +1171,11 @@ const base::DictionaryValue* pref_dict; ASSERT_TRUE(pref_value->GetAsDictionary(&pref_dict)); + const base::ListValue* servers_list = nullptr; + ASSERT_TRUE(pref_dict->GetListWithoutPathExpansion("servers", &servers_list)); + base::ListValue::const_iterator it = servers_list->begin(); const base::DictionaryValue* server_pref_dict; - ASSERT_TRUE(pref_dict->GetDictionary("servers", &server_pref_dict)); + ASSERT_TRUE((*it)->GetAsDictionary(&server_pref_dict)); const base::DictionaryValue* example_pref_dict; ASSERT_TRUE(server_pref_dict->GetDictionaryWithoutPathExpansion( @@ -1102,7 +1195,7 @@ } // Test that expired alternative service entries on disk are ignored. -TEST_F(HttpServerPropertiesManagerTest, DoNotLoadExpiredAlternativeService) { +TEST_P(HttpServerPropertiesManagerTest, DoNotLoadExpiredAlternativeService) { scoped_ptr<base::ListValue> alternative_service_list(new base::ListValue); base::DictionaryValue* expired_dict = new base::DictionaryValue; expired_dict->SetString("protocol_str", "npn-h2"); @@ -1148,7 +1241,7 @@ EXPECT_EQ(one_day_from_now_, alternative_service_info_vector[0].expiration); } -TEST_F(HttpServerPropertiesManagerTest, ShutdownWithPendingUpdateCache0) { +TEST_P(HttpServerPropertiesManagerTest, ShutdownWithPendingUpdateCache0) { // Post an update task to the UI thread. http_server_props_manager_->ScheduleUpdateCacheOnPrefThread(); // Shutdown comes before the task is executed. @@ -1158,7 +1251,7 @@ base::RunLoop().RunUntilIdle(); } -TEST_F(HttpServerPropertiesManagerTest, ShutdownWithPendingUpdateCache1) { +TEST_P(HttpServerPropertiesManagerTest, ShutdownWithPendingUpdateCache1) { // Post an update task. http_server_props_manager_->ScheduleUpdateCacheOnPrefThread(); // Shutdown comes before the task is executed. @@ -1170,7 +1263,7 @@ base::RunLoop().RunUntilIdle(); } -TEST_F(HttpServerPropertiesManagerTest, ShutdownWithPendingUpdateCache2) { +TEST_P(HttpServerPropertiesManagerTest, ShutdownWithPendingUpdateCache2) { http_server_props_manager_->UpdateCacheFromPrefsOnUIConcrete(); // Shutdown comes before the task is executed. http_server_props_manager_->ShutdownOnPrefThread(); @@ -1184,7 +1277,7 @@ // // Tests for shutdown when updating prefs. // -TEST_F(HttpServerPropertiesManagerTest, ShutdownWithPendingUpdatePrefs0) { +TEST_P(HttpServerPropertiesManagerTest, ShutdownWithPendingUpdatePrefs0) { // Post an update task to the IO thread. http_server_props_manager_->ScheduleUpdatePrefsOnNetworkThread(); // Shutdown comes before the task is executed. @@ -1194,7 +1287,7 @@ base::RunLoop().RunUntilIdle(); } -TEST_F(HttpServerPropertiesManagerTest, ShutdownWithPendingUpdatePrefs1) { +TEST_P(HttpServerPropertiesManagerTest, ShutdownWithPendingUpdatePrefs1) { ExpectPrefsUpdate(); // Post an update task. http_server_props_manager_->ScheduleUpdatePrefsOnNetworkThread(); @@ -1207,7 +1300,7 @@ base::RunLoop().RunUntilIdle(); } -TEST_F(HttpServerPropertiesManagerTest, ShutdownWithPendingUpdatePrefs2) { +TEST_P(HttpServerPropertiesManagerTest, ShutdownWithPendingUpdatePrefs2) { // This posts a task to the UI thread. http_server_props_manager_->UpdatePrefsFromCacheOnNetworkThreadConcrete( base::Closure());
diff --git a/net/http/transport_security_state_static.h b/net/http/transport_security_state_static.h index 21ff83a..7a63771 100644 --- a/net/http/transport_security_state_static.h +++ b/net/http/transport_security_state_static.h
@@ -735,3695 +735,3999 @@ // Otherwise it's a pointer to the n'th element of the array. static const uint8_t kHSTSHuffmanTree[] = { 0xf0, 0xe4, 0x00, 0xf2, 0x01, 0x80, 0xf9, 0xe6, 0x03, 0xe7, 0xe9, 0x04, - 0xb7, 0xb6, 0xb1, 0x06, 0xb0, 0xb3, 0x07, 0x08, 0x09, 0xea, 0xf8, 0x0a, + 0xb7, 0xb6, 0x06, 0xb1, 0xb0, 0xb3, 0x07, 0x08, 0x09, 0xea, 0xf8, 0x0a, 0x0b, 0xf7, 0xed, 0x0c, 0x0d, 0xef, 0x05, 0x0e, 0x02, 0x0f, 0xeb, 0xe2, - 0xe3, 0x11, 0xe1, 0x12, 0x13, 0xff, 0xf3, 0xec, 0xe5, 0x15, 0xb9, 0xb5, + 0xe3, 0x11, 0xe1, 0x12, 0x13, 0xff, 0xec, 0xf3, 0xe5, 0x15, 0xb9, 0xb5, 0xb8, 0x17, 0xb2, 0x18, 0xb4, 0xf1, 0x19, 0x1a, 0xfa, 0x1b, 0x1c, 0xf6, 0x1d, 0xe8, 0x1e, 0xee, 0xad, 0xae, 0x20, 0xf5, 0xf4, 0x21, 0x1f, 0x22, 0x16, 0x23, 0x14, 0x24, 0x10, 0x25, }; static const uint8_t kPreloadedHSTSData[] = { - 0xfe, 0xfb, 0x9b, 0x5b, 0xba, 0xcd, 0x11, 0x2a, 0xe0, 0x7e, 0x72, 0xf4, + 0xfe, 0xfb, 0x9a, 0x5b, 0xba, 0xcd, 0x11, 0x2a, 0xe0, 0x7e, 0x72, 0xf4, 0x85, 0xac, 0xe5, 0xdc, 0xf8, 0xe5, 0xff, 0xf4, 0x76, 0x24, 0x2e, 0xaf, - 0x32, 0x8c, 0xf1, 0xcb, 0x9f, 0x47, 0x2a, 0x47, 0xfa, 0x11, 0x84, 0x4f, - 0xbf, 0xd8, 0xd8, 0xc7, 0xba, 0x87, 0x2f, 0xff, 0x6b, 0xf6, 0x74, 0x73, - 0x9f, 0x0b, 0xf4, 0xe5, 0xd9, 0xa3, 0x97, 0x9d, 0xd6, 0x68, 0x8b, 0x55, - 0x24, 0x44, 0xe2, 0x5a, 0xc5, 0xae, 0xde, 0x8e, 0x56, 0xcf, 0x1b, 0x45, - 0xf7, 0xff, 0xef, 0xdf, 0xb8, 0x3b, 0xde, 0x73, 0x2f, 0x23, 0x0e, 0x5c, - 0xb8, 0x39, 0x7f, 0xef, 0xdd, 0x41, 0xc9, 0xb7, 0x0d, 0x9c, 0xb8, 0x5b, - 0x39, 0x58, 0x7d, 0xdd, 0x16, 0x6d, 0x06, 0xff, 0xf4, 0xa3, 0x07, 0xdf, - 0xb8, 0x75, 0x0a, 0x9c, 0xbf, 0x82, 0x30, 0xb6, 0x7e, 0x72, 0xfe, 0x8e, - 0x43, 0xb7, 0x91, 0xcb, 0x82, 0x13, 0x97, 0xfc, 0xd8, 0xa6, 0x90, 0x79, - 0x91, 0xcb, 0x92, 0x73, 0x97, 0xfd, 0xef, 0xf6, 0xfa, 0x7c, 0xe9, 0xca, - 0x09, 0xe8, 0x20, 0xbd, 0x62, 0x30, 0x50, 0x5d, 0xe1, 0x13, 0x7f, 0xf2, - 0xf7, 0x0a, 0xc0, 0xfb, 0x85, 0x70, 0xa6, 0xa0, 0xe5, 0xfe, 0x4e, 0x8f, - 0xee, 0xaa, 0xce, 0x5c, 0x3a, 0x39, 0x50, 0x8a, 0x0c, 0x56, 0x13, 0x4b, - 0xff, 0x84, 0x63, 0x95, 0x33, 0x7a, 0xc6, 0xce, 0x5f, 0xe5, 0xa6, 0xb7, - 0xb8, 0x91, 0xcb, 0xff, 0xf6, 0x03, 0x49, 0xcb, 0x78, 0xb8, 0x1f, 0xde, - 0x47, 0x2f, 0xfe, 0x8c, 0x1f, 0x6b, 0xd9, 0x8d, 0xe8, 0xe5, 0x22, 0x62, - 0x3d, 0x45, 0x13, 0x3f, 0x2b, 0x5d, 0x9c, 0x94, 0xb4, 0x14, 0xb0, 0x36, - 0x69, 0xc0, 0x2f, 0x7f, 0xbd, 0x9b, 0x03, 0x13, 0x45, 0x3e, 0x9a, 0x7b, - 0xfa, 0x5d, 0x4e, 0x39, 0x31, 0xca, 0x83, 0xf5, 0x74, 0x5b, 0xfb, 0xa8, - 0xb8, 0x62, 0x1c, 0xbf, 0xd0, 0x09, 0xde, 0x50, 0xd6, 0x72, 0xc3, 0x07, - 0xc4, 0x25, 0x96, 0xfa, 0xd4, 0x32, 0x05, 0x78, 0x58, 0x62, 0x21, 0x39, - 0x39, 0x76, 0x46, 0x02, 0xa9, 0x12, 0xe1, 0x89, 0xc9, 0x7a, 0x25, 0x4c, - 0x5d, 0xd8, 0x77, 0x8c, 0x34, 0xb5, 0x19, 0xf3, 0x48, 0x7f, 0xa9, 0x08, - 0x2b, 0xff, 0xff, 0x9d, 0x9f, 0x53, 0x7b, 0xff, 0x7b, 0x81, 0xc5, 0x53, - 0xbd, 0xc5, 0x0e, 0x5f, 0xfe, 0xe1, 0x4a, 0xb6, 0xd7, 0x38, 0x78, 0x6f, - 0x9f, 0x3a, 0xd0, 0xe5, 0xfb, 0x6b, 0x77, 0x59, 0xa2, 0xa2, 0x5f, 0x77, - 0x37, 0x87, 0x2f, 0x24, 0xdc, 0x07, 0x2a, 0x0f, 0x07, 0xa4, 0x37, 0xff, - 0xf7, 0xe2, 0xea, 0xfc, 0xf2, 0xb0, 0x32, 0xce, 0xa3, 0x0e, 0x5f, 0xff, - 0x81, 0x29, 0xf8, 0x54, 0x35, 0x73, 0xaf, 0x7f, 0x3e, 0x75, 0xa1, 0xcb, - 0xff, 0xfb, 0xf1, 0x75, 0x7e, 0x79, 0x58, 0x19, 0x67, 0x51, 0x87, 0x2f, - 0xb7, 0xbc, 0x68, 0x72, 0x98, 0x88, 0x27, 0x5e, 0xbf, 0xff, 0x3c, 0x86, - 0x35, 0x9c, 0xac, 0x5f, 0x39, 0x59, 0xcb, 0x7d, 0x92, 0xab, 0xbc, 0x64, - 0x5b, 0xab, 0x08, 0x7a, 0xbd, 0xa8, 0x76, 0xf1, 0x22, 0xbf, 0xf0, 0x71, - 0x9f, 0x5a, 0x60, 0xa7, 0x8e, 0x5e, 0xc6, 0xf0, 0xe5, 0xfd, 0x93, 0x86, - 0x30, 0x27, 0x2f, 0x83, 0xd4, 0x98, 0xe5, 0x61, 0xe8, 0x39, 0x6d, 0xee, - 0xc0, 0x4e, 0x5f, 0xe8, 0x84, 0x11, 0xfd, 0xac, 0xe5, 0xcf, 0xf9, 0xcb, - 0xee, 0xa7, 0x7e, 0xf0, 0x88, 0xf3, 0x55, 0xb2, 0x62, 0x0e, 0x8e, 0x36, - 0x69, 0x7e, 0xda, 0xdd, 0xd6, 0x68, 0xaf, 0x57, 0xe4, 0xe0, 0x5f, 0xf3, - 0x9c, 0xba, 0x24, 0x72, 0xe8, 0x01, 0xcb, 0xfa, 0x75, 0x1a, 0x38, 0x80, - 0xe5, 0xff, 0x9c, 0x41, 0x9e, 0x81, 0x40, 0x1c, 0xa8, 0x3e, 0xc6, 0x86, - 0x36, 0xfb, 0x89, 0x8e, 0x6c, 0xd1, 0xcb, 0x40, 0x2c, 0xa4, 0x20, 0xaf, - 0xfe, 0xfa, 0xf2, 0xfb, 0x9b, 0x5b, 0xba, 0xcd, 0x12, 0x32, 0xff, 0xf7, - 0xd6, 0x3c, 0xbe, 0xe6, 0xd6, 0xee, 0xb3, 0x44, 0xf0, 0xbf, 0xfd, 0xf5, - 0x8f, 0x2f, 0xb9, 0xb5, 0xbb, 0xac, 0xd1, 0x3f, 0xaf, 0xff, 0x7d, 0x63, - 0xcb, 0xee, 0x6d, 0x6e, 0xeb, 0x34, 0x50, 0xcb, 0xff, 0x98, 0xf2, 0xfb, - 0x9b, 0x5b, 0xba, 0xcd, 0x14, 0x42, 0xff, 0xd2, 0xfb, 0xfe, 0xbe, 0x46, - 0xa2, 0x47, 0x2b, 0xea, 0x25, 0xa1, 0x4a, 0xff, 0xd3, 0x27, 0x79, 0xcf, - 0x07, 0x18, 0x72, 0xff, 0xc2, 0xff, 0x7c, 0x3f, 0xbc, 0xb4, 0x72, 0xfd, - 0xb5, 0xbb, 0xac, 0xd1, 0x48, 0xaf, 0xfe, 0xef, 0x17, 0xde, 0x9f, 0xba, - 0x89, 0xce, 0x5f, 0xfc, 0xfc, 0xeb, 0xad, 0xc0, 0x3e, 0x28, 0xc3, 0x97, - 0xfd, 0x12, 0x8d, 0xcf, 0x1b, 0x9c, 0xe5, 0xe7, 0x97, 0xdc, 0x47, 0xfb, - 0x9a, 0x01, 0x1c, 0x52, 0xaf, 0xff, 0xee, 0x3f, 0x54, 0x5e, 0x7a, 0x07, - 0xda, 0x71, 0xff, 0x0e, 0x5f, 0xfe, 0x97, 0xdd, 0xb8, 0x1f, 0xc9, 0xbc, - 0x61, 0xcb, 0xfa, 0x59, 0xde, 0xbc, 0x8e, 0x5f, 0xff, 0xd8, 0x1e, 0xc2, - 0x9f, 0x7c, 0x2e, 0x0d, 0x6a, 0x00, 0x52, 0xdf, 0x61, 0x58, 0x02, 0xd0, - 0x19, 0x19, 0xff, 0x53, 0x5d, 0x7f, 0xc9, 0x6d, 0x0b, 0x6f, 0xff, 0xbb, - 0x1d, 0x45, 0x75, 0xac, 0x10, 0x34, 0xc3, 0x97, 0xcb, 0x77, 0x59, 0xa2, - 0x50, 0x5f, 0xfa, 0x00, 0xc7, 0x97, 0x61, 0xf6, 0x72, 0xa4, 0x8b, 0xcd, - 0xa8, 0x89, 0x75, 0xff, 0xe1, 0x7f, 0x69, 0x41, 0xfe, 0x43, 0x8c, 0x39, - 0x7d, 0xf5, 0xe5, 0xf7, 0x0f, 0xe5, 0x85, 0xf5, 0x3b, 0x6e, 0x3d, 0x2a, - 0x42, 0xb0, 0x63, 0x11, 0x5c, 0xb3, 0x04, 0x74, 0x6b, 0x8c, 0xd3, 0x71, - 0xc3, 0xb1, 0x5f, 0xaa, 0x80, 0x5a, 0xe1, 0xd6, 0xb5, 0x0f, 0x0f, 0xe5, - 0x92, 0x70, 0x47, 0x53, 0x7f, 0xfb, 0xeb, 0x1e, 0x5f, 0x73, 0x6b, 0x77, - 0x59, 0xa2, 0x73, 0x5f, 0xfe, 0xfa, 0xc7, 0x97, 0xdc, 0xda, 0xdd, 0xd6, - 0x68, 0xa2, 0x57, 0xfd, 0xfb, 0xee, 0x4d, 0x4f, 0x88, 0x10, 0xe5, 0xfc, - 0x9a, 0x9a, 0x48, 0x03, 0x97, 0xfa, 0x27, 0x51, 0xa3, 0x88, 0x0e, 0x5d, - 0x2f, 0xa1, 0x45, 0x37, 0x50, 0x94, 0x2e, 0xbf, 0xfd, 0xf7, 0x43, 0x80, - 0x80, 0x6f, 0x70, 0xd9, 0xca, 0xda, 0x22, 0xc0, 0x7f, 0x5b, 0x54, 0x11, - 0xa5, 0xaf, 0xe3, 0x8b, 0xbf, 0x6d, 0x6e, 0xeb, 0x34, 0x43, 0x8b, 0xfb, - 0xf5, 0xed, 0x20, 0x4e, 0x5b, 0xee, 0x1f, 0x0f, 0x4d, 0x2f, 0xfa, 0x37, - 0x8b, 0xec, 0x73, 0x23, 0x97, 0xcb, 0x77, 0x59, 0xa2, 0x2f, 0x5f, 0x85, - 0xc0, 0xfa, 0x39, 0x7e, 0xc9, 0xa4, 0xfa, 0x39, 0x5b, 0x3f, 0xcf, 0x17, - 0x28, 0x4d, 0x7f, 0x60, 0x7b, 0x80, 0x73, 0x97, 0xd1, 0xff, 0x0f, 0xa3, - 0x95, 0xa3, 0xd4, 0x6c, 0xb2, 0xe1, 0x9c, 0xe5, 0xff, 0x78, 0x61, 0x8a, - 0x07, 0xb0, 0x72, 0xa0, 0xf4, 0x10, 0x5e, 0xed, 0x72, 0x72, 0xfb, 0xd2, - 0x85, 0x4a, 0x53, 0x0d, 0xdb, 0x8c, 0x5f, 0x9e, 0x7f, 0x67, 0x4e, 0x5b, - 0xec, 0xea, 0x93, 0xf2, 0x16, 0xb3, 0x42, 0x13, 0xae, 0x62, 0xb6, 0xd0, - 0x82, 0xff, 0xff, 0xf8, 0x5f, 0xee, 0x7f, 0xc3, 0xa2, 0xa9, 0xee, 0xe2, - 0x4b, 0x5f, 0x31, 0x58, 0x91, 0xcb, 0xf6, 0x69, 0x81, 0x83, 0x97, 0xfe, - 0x79, 0x7d, 0xcd, 0xad, 0xdd, 0x66, 0x89, 0x91, 0x6f, 0xab, 0x47, 0xce, - 0xe1, 0x0c, 0xc2, 0x7b, 0xde, 0xc6, 0x1c, 0xbb, 0xac, 0x39, 0x7e, 0xda, - 0xdd, 0xd6, 0x68, 0xb7, 0x96, 0xfb, 0x07, 0xce, 0x11, 0xcc, 0x17, 0xbf, - 0xfd, 0xf5, 0x8f, 0x2f, 0xb9, 0xb5, 0xbb, 0xac, 0xd1, 0x49, 0xae, 0x6a, - 0x9a, 0xb3, 0x97, 0xf6, 0x78, 0x62, 0x18, 0x72, 0xfe, 0xe4, 0x0a, 0x6d, - 0xc0, 0x72, 0xee, 0xfd, 0xe1, 0x0f, 0xf3, 0xa4, 0x2e, 0x57, 0x50, 0xbb, - 0x9d, 0x29, 0x4f, 0x19, 0x1b, 0x36, 0xa1, 0x49, 0xc4, 0xd5, 0x48, 0x6b, - 0x5f, 0xef, 0xb9, 0xb5, 0xbb, 0xac, 0xd1, 0x0e, 0xaf, 0xdb, 0x5b, 0xba, - 0xcd, 0x12, 0xc2, 0xfb, 0x00, 0xc4, 0x39, 0x7e, 0xfa, 0xc7, 0x97, 0xdc, - 0x3d, 0x56, 0x86, 0x97, 0xfb, 0xee, 0x6d, 0x6e, 0xeb, 0x34, 0x46, 0x0b, - 0xff, 0xfb, 0x4e, 0x06, 0x99, 0xf4, 0x5f, 0xd2, 0xcf, 0x60, 0x4e, 0x5f, - 0x7d, 0x96, 0x68, 0xe5, 0xff, 0xff, 0x4b, 0x5f, 0x57, 0xd7, 0x99, 0x7d, - 0xcd, 0xb5, 0x1d, 0x99, 0x9a, 0x39, 0x7e, 0xcf, 0x02, 0x16, 0x72, 0xff, - 0xf4, 0x79, 0x01, 0x12, 0x0f, 0x60, 0x56, 0x72, 0xfd, 0xb5, 0xbb, 0xac, - 0xd1, 0x1e, 0xaf, 0xb4, 0xfc, 0xf1, 0x39, 0x74, 0xbe, 0xe1, 0xec, 0xf8, - 0xd2, 0xff, 0xfe, 0x7f, 0xa3, 0xfe, 0x77, 0x04, 0x18, 0x3e, 0xee, 0x1c, - 0xb7, 0xde, 0x53, 0xc3, 0x99, 0xcb, 0x64, 0xef, 0x0a, 0x11, 0x2f, 0xbf, - 0x6d, 0x6e, 0xeb, 0x34, 0x58, 0x6b, 0xfd, 0x21, 0x8c, 0xd6, 0x09, 0xcb, - 0x92, 0x47, 0x2d, 0xf7, 0x0f, 0xeb, 0x93, 0x40, 0x18, 0x5f, 0xff, 0xfe, - 0x8d, 0x8c, 0x46, 0xbe, 0xf8, 0x28, 0xce, 0x65, 0xae, 0x65, 0x9b, 0x9c, - 0xe5, 0xfe, 0xfb, 0x9b, 0x5b, 0xba, 0xcd, 0x17, 0x3a, 0xff, 0xff, 0xff, - 0xe8, 0xe1, 0x79, 0x4e, 0xbe, 0xfc, 0xf9, 0xd6, 0x9f, 0x67, 0xfd, 0x5e, - 0x16, 0x8e, 0x13, 0x99, 0xe7, 0x5b, 0x3e, 0x7c, 0xeb, 0x43, 0x95, 0x0b, - 0xbe, 0x53, 0xc2, 0x5a, 0x48, 0x98, 0x82, 0xb5, 0xd4, 0x8f, 0x9d, 0x90, - 0xd2, 0xe9, 0xbf, 0x9f, 0x38, 0x10, 0x6f, 0xf7, 0xdc, 0xda, 0xdd, 0xd6, - 0x68, 0x87, 0x97, 0xcb, 0x77, 0x59, 0xa2, 0x26, 0x5f, 0xd9, 0xc1, 0xfb, - 0x30, 0x27, 0x2f, 0xf7, 0xbf, 0x7e, 0x7b, 0x1c, 0x4e, 0x56, 0xd1, 0x2c, - 0x25, 0xde, 0x31, 0xbf, 0x03, 0x5f, 0x30, 0x27, 0x2f, 0xf2, 0x37, 0x83, - 0x9c, 0xf8, 0xe5, 0x21, 0xee, 0xec, 0xaa, 0xff, 0xfd, 0x1b, 0x07, 0x63, - 0x8c, 0xd1, 0x0c, 0xd6, 0x04, 0xe5, 0xff, 0x77, 0xb1, 0xc6, 0x59, 0xb8, - 0x39, 0x6f, 0x75, 0x12, 0x2e, 0xaf, 0x7f, 0xc9, 0xe4, 0xf6, 0x02, 0x36, - 0x72, 0xfa, 0x7e, 0xff, 0x39, 0xca, 0xc4, 0x42, 0xb9, 0x47, 0xe6, 0xf7, - 0xb0, 0x3d, 0x39, 0x7f, 0xff, 0x7b, 0xb1, 0xb0, 0x6b, 0x03, 0xef, 0xdd, - 0x79, 0xb3, 0x97, 0x79, 0x87, 0x2f, 0xff, 0x67, 0x54, 0x9f, 0x50, 0x9c, - 0xfa, 0x18, 0x72, 0xff, 0xd3, 0xc4, 0x94, 0xcd, 0xeb, 0x1b, 0x39, 0x58, - 0x98, 0x07, 0x2b, 0x9d, 0x17, 0xfd, 0x32, 0xff, 0xe4, 0xf8, 0x1c, 0xe3, - 0xb7, 0xe3, 0xd4, 0x39, 0x7d, 0x2e, 0xa9, 0xa3, 0x97, 0x3a, 0x86, 0x88, - 0x5d, 0x6f, 0x72, 0x79, 0x1f, 0x92, 0x5f, 0xbb, 0x93, 0xfe, 0x27, 0x2f, - 0x9f, 0x71, 0xc4, 0xe5, 0x04, 0xf3, 0x00, 0x53, 0x7e, 0x9a, 0x58, 0xe2, - 0x72, 0xdf, 0x71, 0x72, 0x77, 0x70, 0x8c, 0xec, 0x66, 0xe2, 0x5f, 0xa8, - 0xc7, 0x3c, 0x7f, 0xfc, 0x24, 0x78, 0xbb, 0x34, 0x22, 0xbf, 0xf6, 0xff, - 0x9f, 0x3b, 0x30, 0xc0, 0x4e, 0x5d, 0xd7, 0x39, 0x6f, 0xce, 0x56, 0x1a, - 0x8d, 0x0b, 0x5e, 0x06, 0xbe, 0xc2, 0x22, 0x7c, 0xd3, 0x7f, 0xfd, 0x89, - 0x2d, 0x7d, 0xce, 0x64, 0xf3, 0xa8, 0xb3, 0x95, 0x08, 0x8a, 0xe9, 0xb5, - 0xff, 0x35, 0x5c, 0x26, 0xf3, 0xc9, 0xdf, 0xce, 0x5f, 0x69, 0x27, 0xe1, - 0x0e, 0x53, 0x54, 0x7d, 0x8d, 0x42, 0x25, 0xff, 0xcd, 0x53, 0x55, 0xc2, - 0x24, 0xf1, 0xf1, 0x7a, 0xc3, 0x97, 0xfe, 0xe1, 0x33, 0xca, 0x4e, 0xfb, - 0x49, 0x8e, 0x5f, 0xcd, 0x52, 0x9d, 0xee, 0x4e, 0x72, 0xdd, 0x39, 0x4d, - 0x51, 0xe3, 0x7e, 0x6b, 0x7c, 0x1c, 0x19, 0x8e, 0x5c, 0x9e, 0x39, 0x6f, - 0x21, 0xb8, 0xe9, 0x15, 0xfe, 0xe7, 0xdc, 0xcb, 0xf1, 0x54, 0xe5, 0xff, - 0xa2, 0x61, 0xce, 0x2e, 0xc6, 0x21, 0xca, 0x73, 0xf7, 0xfc, 0xe2, 0xff, - 0xff, 0xee, 0xfe, 0x14, 0xcd, 0xcc, 0x39, 0xc7, 0xb8, 0x18, 0xd6, 0xa1, - 0x53, 0x97, 0xff, 0x92, 0x69, 0x67, 0x32, 0xf8, 0xc7, 0x71, 0x39, 0x73, - 0xf0, 0x1c, 0xb7, 0x09, 0x89, 0xcc, 0xab, 0x09, 0xd5, 0x91, 0x75, 0xd5, - 0xd3, 0x2e, 0x68, 0xa9, 0xcb, 0xe7, 0x94, 0x00, 0xe5, 0xfb, 0xaf, 0xe7, - 0x91, 0xcb, 0xf9, 0x36, 0x39, 0x9b, 0x39, 0x7f, 0xa5, 0xa8, 0xd3, 0x52, - 0x6a, 0x9a, 0xa3, 0x97, 0xff, 0x33, 0xe6, 0x87, 0x39, 0x90, 0xbc, 0xe7, - 0x2f, 0x69, 0x00, 0x72, 0xb0, 0xf8, 0xd1, 0x1e, 0xf3, 0x6d, 0xb6, 0x52, - 0xfc, 0xe3, 0xee, 0xe1, 0x4f, 0xa6, 0x82, 0xff, 0xff, 0xe8, 0x9f, 0xe6, - 0xbf, 0x8e, 0x7d, 0xdc, 0x66, 0x78, 0x60, 0x00, 0x83, 0x97, 0xde, 0x9b, - 0x3c, 0x72, 0x82, 0x89, 0x87, 0x75, 0xa0, 0xa6, 0x64, 0x04, 0x01, 0x86, - 0x85, 0xfb, 0xa2, 0xd4, 0xda, 0x70, 0x1c, 0xb9, 0xdc, 0xe5, 0xba, 0x87, - 0x90, 0xe6, 0x77, 0xff, 0x01, 0x26, 0xf9, 0xd8, 0x4d, 0xfe, 0xd6, 0x72, - 0xfe, 0xda, 0x70, 0x6f, 0x5a, 0x39, 0x7f, 0x0f, 0xfe, 0x49, 0xe0, 0xe5, - 0xff, 0x91, 0x58, 0x18, 0xd4, 0x23, 0x0e, 0x5f, 0xd9, 0xc7, 0xf9, 0x66, - 0x8e, 0x5f, 0x60, 0x72, 0x73, 0x97, 0xcd, 0x7f, 0x21, 0xa8, 0x39, 0x76, - 0xe0, 0xe5, 0x05, 0x71, 0xa7, 0x08, 0x56, 0x4f, 0xc9, 0x5a, 0x47, 0xb2, - 0xd6, 0xfb, 0x31, 0x36, 0xd2, 0xd8, 0x63, 0xd2, 0xe1, 0x3c, 0xf1, 0x87, - 0x12, 0x2e, 0x02, 0xcb, 0xf3, 0x71, 0x81, 0x43, 0x97, 0xbf, 0xf6, 0x8e, - 0x5f, 0xff, 0xff, 0xf6, 0xbe, 0x77, 0x27, 0x86, 0xf9, 0x96, 0xbe, 0x7e, - 0xbd, 0xee, 0x3e, 0x4c, 0xaf, 0x3f, 0x3e, 0x75, 0xa1, 0xca, 0xc4, 0x78, - 0x2c, 0x9f, 0xc3, 0xd7, 0x7e, 0x03, 0x97, 0x34, 0x6a, 0x8e, 0x5e, 0xf9, - 0x25, 0x9c, 0xa8, 0x3d, 0x55, 0x46, 0x18, 0x3d, 0x7f, 0xff, 0x6f, 0xe0, - 0xe7, 0x1c, 0xdc, 0xbe, 0x40, 0x5e, 0x6d, 0x1c, 0xbf, 0xff, 0xf8, 0x79, - 0x85, 0x47, 0x03, 0xd4, 0x9b, 0xe6, 0xb3, 0x99, 0x6f, 0x1b, 0x39, 0x58, - 0x8d, 0x81, 0x61, 0xbe, 0xf7, 0xf1, 0x39, 0xcb, 0xfd, 0x2c, 0xee, 0x32, - 0x16, 0x72, 0x90, 0xf5, 0xbc, 0x49, 0x7f, 0xff, 0x73, 0x2d, 0x33, 0x07, - 0xe7, 0x02, 0x76, 0x74, 0xcd, 0x9c, 0xb3, 0x59, 0xca, 0xc3, 0xf5, 0x5b, - 0x0d, 0xff, 0xff, 0x9b, 0xf8, 0x38, 0xbe, 0xa0, 0xe7, 0xfc, 0xfb, 0xe3, - 0xb7, 0x8a, 0x9c, 0xbf, 0xca, 0x87, 0xf8, 0xe8, 0xc1, 0xcb, 0xfd, 0xcc, - 0xb4, 0xaf, 0xf1, 0xc9, 0xcb, 0xfc, 0xed, 0xff, 0x34, 0x79, 0xce, 0x54, - 0x26, 0x29, 0x8e, 0x68, 0x68, 0x27, 0x17, 0xff, 0xe1, 0xc0, 0xf7, 0xf6, - 0xf4, 0x9e, 0xea, 0x38, 0x0e, 0x5f, 0xe1, 0xce, 0x3f, 0x24, 0xc9, 0x1c, - 0xad, 0xa2, 0x37, 0x4a, 0xd7, 0x6b, 0x89, 0xca, 0x83, 0x79, 0xf9, 0x1d, - 0xf0, 0x3c, 0x93, 0x9c, 0xbf, 0xde, 0xea, 0x08, 0x14, 0x61, 0xcb, 0xff, - 0xfb, 0xa9, 0x83, 0x88, 0x1c, 0x80, 0x3a, 0xdf, 0x67, 0x2f, 0xf4, 0xf0, - 0xc1, 0x8e, 0x40, 0x72, 0xa4, 0x8b, 0xee, 0x4d, 0x1d, 0x5a, 0xfd, 0xdf, - 0x8f, 0x9a, 0x39, 0x50, 0x7b, 0x38, 0x61, 0x7f, 0xf3, 0xee, 0x5f, 0x3c, - 0x31, 0x2c, 0xf1, 0xca, 0x85, 0xd0, 0x5c, 0x77, 0x48, 0x4b, 0x6e, 0x33, - 0x5e, 0xc6, 0x06, 0xe4, 0x23, 0x19, 0xd7, 0xe4, 0x16, 0x6b, 0x39, 0x7f, - 0xfd, 0xb4, 0xff, 0x87, 0x8f, 0x9a, 0xfc, 0x0c, 0xcf, 0x1c, 0xbf, 0xf4, - 0x2f, 0x50, 0x9c, 0xfa, 0x18, 0x72, 0xd2, 0x39, 0x42, 0x79, 0xff, 0x9f, - 0x5f, 0xa0, 0x1a, 0x9f, 0xc7, 0x2f, 0x3f, 0xb4, 0x72, 0xef, 0xe7, 0x39, - 0x52, 0x36, 0xbb, 0x1c, 0xbf, 0x64, 0xba, 0xf2, 0x39, 0x70, 0xfa, 0x63, - 0xc8, 0xe9, 0x0d, 0xfe, 0x71, 0x53, 0xbd, 0x80, 0x9c, 0xbf, 0xbf, 0x5f, - 0xc0, 0xf2, 0xd9, 0xcb, 0xfe, 0x86, 0xfb, 0x83, 0xcc, 0x2a, 0x72, 0xed, - 0xc8, 0xe5, 0x42, 0x39, 0xb9, 0x2e, 0x43, 0x3d, 0x9a, 0x30, 0xea, 0xff, - 0x6e, 0x03, 0x1d, 0x89, 0x1c, 0xbf, 0xfe, 0x8f, 0x7c, 0x1f, 0xf8, 0x3e, - 0x67, 0x9a, 0x67, 0x8e, 0x52, 0x22, 0x2f, 0xf3, 0x2b, 0xff, 0xbb, 0x0a, - 0xfc, 0xf0, 0xbf, 0xa3, 0xc7, 0x2f, 0xf7, 0xce, 0x64, 0x9d, 0xfd, 0x87, - 0x28, 0x07, 0xfc, 0x28, 0xd7, 0xff, 0x67, 0x1c, 0x0f, 0xcf, 0x2a, 0x8d, - 0xe8, 0xe5, 0xff, 0xb7, 0x37, 0xcd, 0x42, 0x4e, 0xfe, 0x39, 0x50, 0x8a, - 0xd0, 0x90, 0xfe, 0x95, 0x73, 0x80, 0xe5, 0xff, 0xf7, 0xc1, 0x8d, 0x44, - 0xe3, 0x81, 0xea, 0x4c, 0x72, 0xff, 0xff, 0xed, 0x6c, 0x62, 0x6f, 0x8a, - 0x79, 0x25, 0x9c, 0xfb, 0x38, 0x8e, 0x68, 0xe5, 0x6d, 0x19, 0x02, 0xa3, - 0x5e, 0x4c, 0x03, 0xf8, 0x6f, 0x51, 0xcb, 0xa6, 0x91, 0xca, 0x83, 0x47, - 0xb0, 0xbb, 0xff, 0x87, 0xda, 0xe2, 0x9e, 0x8c, 0x19, 0x8e, 0x5f, 0xb6, - 0x9a, 0x8e, 0x4e, 0x56, 0x1f, 0x6b, 0xa2, 0xdf, 0xe9, 0xf8, 0x49, 0xa4, - 0x9e, 0xd1, 0xcb, 0xf0, 0xfb, 0xb9, 0xc0, 0x72, 0xfd, 0x36, 0x9f, 0x6a, - 0x9c, 0xbc, 0xed, 0xee, 0x0f, 0x53, 0x0a, 0xaa, 0x48, 0xe1, 0x42, 0x0d, - 0xc2, 0x3e, 0xff, 0xba, 0x9b, 0x9b, 0xaf, 0x9b, 0x39, 0x7f, 0xff, 0xff, - 0x03, 0x43, 0x8f, 0xcf, 0xc0, 0xf7, 0xff, 0x83, 0x9c, 0xcb, 0x3f, 0x9c, - 0x71, 0xf9, 0x39, 0x4b, 0x46, 0x4a, 0x1c, 0xde, 0x77, 0x59, 0xa2, 0x98, - 0x56, 0x1e, 0x52, 0xc8, 0xaf, 0xfd, 0x83, 0xcc, 0xb5, 0xe8, 0xdc, 0xc7, - 0x2f, 0xfc, 0xfc, 0xe2, 0x6d, 0x19, 0x0a, 0x9c, 0xbd, 0x88, 0x03, 0x96, - 0xc3, 0x97, 0xb9, 0x1c, 0x01, 0xab, 0xe2, 0x37, 0x48, 0x8d, 0xdd, 0xa0, - 0x3b, 0x4d, 0xd3, 0xcc, 0x72, 0xcd, 0x9c, 0xb9, 0x02, 0x72, 0x9a, 0xcd, - 0x46, 0x84, 0xae, 0x0c, 0xc7, 0x2f, 0xb7, 0xd7, 0xf9, 0x07, 0xfb, 0x88, - 0x2c, 0x24, 0xbf, 0xdf, 0x39, 0x90, 0xc6, 0x68, 0xe5, 0x21, 0xfd, 0xba, - 0x35, 0xff, 0xf8, 0x09, 0xaf, 0x9d, 0x7d, 0x7a, 0x26, 0xd7, 0x70, 0xe5, - 0xfc, 0x9d, 0x74, 0x9e, 0x0e, 0x5e, 0x94, 0x72, 0x72, 0xff, 0x30, 0x3d, - 0x89, 0xf1, 0xb3, 0x95, 0x87, 0xfd, 0xc9, 0x63, 0x8e, 0xdd, 0xad, 0x1c, - 0xb6, 0x1c, 0xbf, 0xf4, 0xc8, 0xaa, 0x78, 0x73, 0x83, 0xe6, 0xcd, 0x3f, - 0x11, 0x7b, 0xff, 0xfc, 0x38, 0xbf, 0x7a, 0x3d, 0xa9, 0x87, 0x1b, 0xf9, - 0x0d, 0x41, 0xcb, 0xff, 0x2e, 0x19, 0xdc, 0xd6, 0x20, 0x9c, 0xa8, 0x45, - 0x27, 0x5a, 0x2f, 0xdb, 0x8e, 0x31, 0xb3, 0x97, 0xf3, 0x8f, 0xc0, 0xc0, - 0x9c, 0xa8, 0x4d, 0xe3, 0x23, 0x00, 0x42, 0x2f, 0xca, 0x6f, 0xfa, 0x1b, - 0x5a, 0x4f, 0x9c, 0xf8, 0xe5, 0x35, 0x6c, 0xe2, 0x28, 0x14, 0x9e, 0x15, - 0x12, 0x22, 0x0c, 0x71, 0x8a, 0xc3, 0x51, 0x71, 0xa7, 0x73, 0x19, 0x82, - 0x26, 0xcd, 0x1b, 0x76, 0xe3, 0x47, 0x64, 0x3f, 0xbb, 0x19, 0x30, 0x08, - 0x06, 0x1a, 0xde, 0x8f, 0x37, 0x8a, 0x15, 0xff, 0x6d, 0xdb, 0xf8, 0xe1, - 0x79, 0xce, 0x5f, 0xce, 0xdc, 0xc2, 0x81, 0x39, 0x7f, 0xff, 0x83, 0x93, - 0xb8, 0xfb, 0x50, 0xbf, 0x8c, 0x62, 0x0a, 0xce, 0x5f, 0xc1, 0xd3, 0xc7, - 0x32, 0x39, 0x50, 0x89, 0x07, 0x62, 0xbf, 0xe8, 0x9b, 0xa9, 0x0c, 0x70, - 0x9c, 0xa5, 0x53, 0x53, 0xd9, 0xe0, 0xc2, 0xfb, 0xf2, 0x1b, 0xec, 0x15, - 0x5a, 0xce, 0x5f, 0xff, 0xff, 0xba, 0x9e, 0xee, 0x6e, 0x38, 0xfc, 0x67, - 0xfc, 0x1f, 0x33, 0x99, 0x67, 0xe2, 0x0d, 0x1c, 0xb7, 0x91, 0x16, 0x9a, - 0x25, 0xbf, 0xf4, 0x2f, 0xe0, 0xbe, 0x99, 0x02, 0x72, 0xff, 0xfd, 0x99, - 0xd4, 0x5f, 0x73, 0xe6, 0xbf, 0xec, 0x35, 0x9c, 0xbf, 0xfe, 0xf7, 0x70, - 0x1f, 0x19, 0x19, 0xe0, 0xe0, 0x9c, 0xb3, 0x67, 0x2f, 0xe7, 0x0e, 0xf7, - 0xfc, 0xe7, 0x2f, 0xd1, 0x83, 0xe6, 0x87, 0x29, 0x53, 0xea, 0x58, 0x93, - 0x0c, 0x2f, 0xbc, 0x9b, 0xc3, 0x96, 0xe7, 0xe1, 0xe8, 0xe1, 0x85, 0xb5, - 0x89, 0x9a, 0xbc, 0x61, 0x74, 0xc4, 0xfe, 0xc4, 0xfb, 0xd1, 0xc7, 0xdf, - 0xff, 0xff, 0x67, 0x32, 0x4d, 0x0e, 0x71, 0xee, 0x4d, 0xd8, 0x19, 0xbe, - 0x3a, 0xd3, 0x89, 0xcb, 0xff, 0xfe, 0xc1, 0x57, 0xe6, 0xe3, 0x8a, 0x7b, - 0x58, 0xaa, 0x6d, 0xf9, 0x39, 0x42, 0x8e, 0xe5, 0x21, 0x07, 0x48, 0x9a, - 0x67, 0xf1, 0x92, 0x5f, 0xfe, 0x40, 0xfc, 0x62, 0x7c, 0x80, 0xbc, 0xda, - 0x39, 0x74, 0xa4, 0x72, 0xdb, 0x83, 0xe5, 0x9d, 0x3a, 0xfd, 0x28, 0xe6, - 0x5a, 0x39, 0x7f, 0xff, 0xff, 0xec, 0x15, 0x7e, 0x27, 0x7f, 0xfb, 0x32, - 0x7a, 0x18, 0x2e, 0xaf, 0x53, 0xee, 0x77, 0x90, 0x40, 0x4a, 0x5f, 0xff, - 0xfc, 0xb4, 0x6c, 0x3f, 0xef, 0xe7, 0xf1, 0x3e, 0x97, 0xdf, 0xfb, 0xcb, - 0xb6, 0x72, 0xef, 0xe7, 0xe5, 0x34, 0x84, 0x29, 0xd4, 0x28, 0xaa, 0x17, - 0x6c, 0xbb, 0x2d, 0xbd, 0xe1, 0x1e, 0x31, 0xb8, 0x5f, 0xe7, 0x96, 0x31, - 0xc4, 0x07, 0x2f, 0xb3, 0xb1, 0x31, 0xcb, 0xcc, 0x5f, 0xce, 0x9e, 0x9b, - 0x98, 0xdf, 0xff, 0xfe, 0xda, 0xc7, 0x38, 0xfc, 0xd2, 0x60, 0x83, 0xe0, - 0xe7, 0x11, 0xcd, 0x71, 0x39, 0x7f, 0xb1, 0xd9, 0xf1, 0xa4, 0x30, 0xe5, - 0xff, 0xe9, 0x46, 0xbb, 0xfe, 0xf3, 0xde, 0x46, 0x1c, 0xa5, 0xa2, 0x07, - 0x93, 0x6a, 0xc4, 0xc8, 0xf7, 0x0f, 0xfb, 0xff, 0xf2, 0x0f, 0xbb, 0x9c, - 0x1e, 0x9b, 0x1a, 0xdc, 0x40, 0x72, 0xf9, 0xbf, 0x9a, 0x98, 0xe5, 0xbc, - 0x72, 0xa0, 0xdc, 0x39, 0x3d, 0xff, 0x86, 0x71, 0xce, 0x3a, 0xfe, 0x39, - 0x39, 0x7f, 0xe0, 0xf6, 0x39, 0xf8, 0xd4, 0xf8, 0x81, 0x0e, 0x54, 0x22, - 0x32, 0x74, 0x2a, 0x44, 0xe2, 0x34, 0x51, 0xe8, 0x49, 0x7f, 0x0a, 0xbb, - 0xff, 0x9b, 0xcd, 0x7f, 0x0a, 0xea, 0x37, 0x31, 0xcb, 0xed, 0xc9, 0xc2, - 0x72, 0xff, 0xc3, 0x25, 0xf5, 0x3a, 0x3f, 0xce, 0x72, 0xf7, 0xb3, 0x87, - 0x39, 0x50, 0x7c, 0x38, 0x81, 0x79, 0xa6, 0x74, 0xe5, 0xd8, 0x13, 0x95, - 0x3a, 0xe2, 0x3c, 0xa5, 0x70, 0x62, 0x43, 0xa4, 0x6a, 0x10, 0x7e, 0x20, - 0xe2, 0x3d, 0x7e, 0x4f, 0x6b, 0x00, 0x72, 0xfd, 0xdc, 0xe2, 0x9c, 0x4e, - 0x5e, 0x4c, 0x01, 0xcb, 0xf8, 0x30, 0x3d, 0x79, 0x1c, 0xbd, 0x01, 0x83, - 0x97, 0xec, 0xf6, 0x9e, 0x6f, 0x87, 0x8e, 0xc2, 0xcb, 0xe6, 0xad, 0xa9, - 0x70, 0xcd, 0x59, 0xcb, 0xe4, 0x71, 0x09, 0xcb, 0x37, 0xf0, 0xf6, 0x02, - 0x71, 0x52, 0x46, 0x22, 0x42, 0x66, 0xff, 0xfd, 0xbf, 0xf7, 0xb8, 0x1c, - 0x55, 0x3b, 0xdc, 0x50, 0xe5, 0xf7, 0xef, 0xcf, 0x8e, 0x54, 0x95, 0x0d, - 0x04, 0x9d, 0x52, 0xb9, 0xa3, 0x26, 0xd9, 0x3f, 0x55, 0xe8, 0xe5, 0xfd, - 0xa5, 0xad, 0xc5, 0x53, 0x95, 0xc2, 0x8d, 0xcf, 0x82, 0xef, 0xf0, 0xfc, - 0xe3, 0xcc, 0xb5, 0x31, 0xcb, 0xa7, 0xe4, 0xe5, 0xfb, 0xae, 0xd7, 0x00, - 0x39, 0x41, 0x3f, 0xd7, 0x3a, 0xe0, 0x19, 0xbf, 0xdb, 0x98, 0x73, 0xaf, - 0xe3, 0x95, 0x09, 0x84, 0x64, 0x29, 0x10, 0xc6, 0xfc, 0x9b, 0x0e, 0x09, - 0xcb, 0xf0, 0x33, 0xca, 0x4e, 0x72, 0xff, 0x37, 0xec, 0xef, 0xce, 0x74, - 0x72, 0xa0, 0xf8, 0x9c, 0xaa, 0xa4, 0x8d, 0xbe, 0x99, 0x8c, 0x22, 0x2f, - 0xee, 0xe2, 0xe5, 0x0c, 0x39, 0x7f, 0xbb, 0x92, 0x71, 0xce, 0x4e, 0x56, - 0x1e, 0xff, 0x8b, 0x6f, 0xff, 0xf8, 0x5c, 0x1a, 0x9f, 0x10, 0x7c, 0x39, - 0xc7, 0xe6, 0x9b, 0x13, 0x97, 0xf7, 0x70, 0x79, 0x85, 0x4e, 0x50, 0xa2, - 0xe3, 0xc4, 0x2d, 0xb4, 0xde, 0xc4, 0x98, 0xe5, 0xff, 0x93, 0x26, 0xf9, - 0xa8, 0xeb, 0xb5, 0x9c, 0xbf, 0xee, 0x72, 0x39, 0x98, 0x61, 0x87, 0x2f, - 0xee, 0x75, 0xdc, 0x7d, 0x9c, 0xbf, 0xff, 0xf2, 0x33, 0x69, 0x9c, 0x8f, - 0xfe, 0x8e, 0xfc, 0xe2, 0x9e, 0x9a, 0x0e, 0x53, 0xa2, 0x7f, 0xc5, 0xd5, - 0x3a, 0x6b, 0x41, 0x1c, 0xea, 0x1f, 0xa1, 0xb3, 0x7f, 0xfd, 0x8f, 0x3f, - 0x61, 0x3d, 0xa8, 0x9f, 0x34, 0x72, 0xff, 0xb3, 0x73, 0xc2, 0x6f, 0x04, - 0xe5, 0x98, 0x73, 0xe1, 0xb7, 0xbc, 0x38, 0x13, 0x95, 0x06, 0xfb, 0x92, - 0x3b, 0xfb, 0x9d, 0x66, 0x0a, 0xa7, 0x2f, 0x98, 0xa4, 0x00, 0xe5, 0xff, - 0xe9, 0xc3, 0xb7, 0x58, 0xe7, 0x1d, 0xa6, 0x8e, 0x56, 0x22, 0x75, 0x0b, - 0xbf, 0x23, 0xbf, 0xcf, 0xee, 0xbc, 0xca, 0x30, 0xe5, 0xef, 0xf9, 0x01, - 0xcb, 0xfb, 0x51, 0xc8, 0x37, 0x07, 0x2e, 0x0a, 0x1c, 0xa8, 0x5c, 0x17, - 0xc8, 0xe2, 0x96, 0x88, 0x90, 0xc4, 0xdc, 0x2f, 0x9c, 0xbc, 0x4d, 0x74, - 0x3f, 0xc4, 0xba, 0xfe, 0xf3, 0xf7, 0xe0, 0x60, 0xe5, 0xff, 0xef, 0x69, - 0x4d, 0x7c, 0xf0, 0xc4, 0xb3, 0xc7, 0x2f, 0xf7, 0x92, 0x7c, 0xef, 0xfe, - 0x39, 0x7d, 0xed, 0x42, 0xa7, 0x2d, 0x31, 0xcb, 0xfb, 0x3f, 0xce, 0xae, - 0x73, 0x96, 0xe6, 0x0f, 0x07, 0x42, 0x55, 0x08, 0x8c, 0xc6, 0x4b, 0xfb, - 0xaf, 0x26, 0x6d, 0x0e, 0x5f, 0xfc, 0xaa, 0xaf, 0xed, 0x78, 0x63, 0x99, - 0x1c, 0xbf, 0xbc, 0x31, 0x2c, 0xf1, 0xca, 0x83, 0xf3, 0x92, 0x3d, 0xc9, - 0xa3, 0x96, 0x61, 0xcb, 0xdb, 0xce, 0x4e, 0x50, 0x4f, 0x13, 0xa2, 0xc0, - 0x11, 0xbf, 0xfc, 0xea, 0xf9, 0x58, 0x19, 0x67, 0x51, 0x87, 0x2f, 0xc9, - 0xad, 0x43, 0x0e, 0x52, 0x22, 0x80, 0x4b, 0xf8, 0xa5, 0x54, 0x2b, 0x33, - 0xc2, 0xf5, 0x53, 0x52, 0x18, 0x20, 0x21, 0x18, 0x50, 0x7f, 0x18, 0x2d, - 0xf8, 0x28, 0x2e, 0x13, 0x97, 0xb4, 0x1e, 0x4e, 0x5c, 0x05, 0x9c, 0xbf, - 0xfd, 0x93, 0x76, 0x05, 0x51, 0xcf, 0x77, 0xf3, 0x94, 0xa9, 0xf1, 0x74, - 0x5e, 0xbe, 0x22, 0x8e, 0x50, 0x80, 0xa4, 0x47, 0x9e, 0xe1, 0x93, 0x7f, - 0xff, 0x93, 0x39, 0x96, 0xbd, 0xd8, 0x64, 0x20, 0x7e, 0x43, 0x50, 0x72, - 0xff, 0x38, 0xfc, 0x5e, 0x80, 0x13, 0x97, 0xfe, 0xff, 0x5f, 0x18, 0xa7, - 0x5f, 0xb0, 0x72, 0xfd, 0x9e, 0xff, 0x39, 0x39, 0x79, 0x5c, 0xe4, 0xe5, - 0xd1, 0x37, 0xc3, 0xc7, 0xf1, 0x4d, 0x0a, 0x2e, 0xbf, 0x84, 0x55, 0xff, - 0xff, 0xfb, 0xf1, 0xf8, 0xdb, 0xf3, 0x2d, 0xb8, 0x3e, 0x6b, 0xf8, 0xe7, - 0xb8, 0x83, 0x8a, 0x9c, 0xbf, 0xff, 0xde, 0xff, 0x07, 0xe2, 0x67, 0x86, - 0x01, 0xf3, 0x10, 0x27, 0x2f, 0xf9, 0x98, 0xcf, 0x8c, 0x6b, 0xe3, 0x23, - 0x95, 0xb4, 0x51, 0xb1, 0x8a, 0xff, 0xfb, 0x7b, 0xcf, 0x6b, 0xa9, 0x9f, - 0x3a, 0x08, 0x39, 0x48, 0x7e, 0x9f, 0x91, 0xd6, 0x27, 0x89, 0xd8, 0xe8, - 0xaf, 0xd8, 0x2b, 0x51, 0x87, 0x2f, 0xfe, 0xee, 0x40, 0xcc, 0x39, 0xed, - 0x39, 0xcb, 0x4b, 0xc7, 0xd5, 0xc0, 0x51, 0x7f, 0xfe, 0x0e, 0x33, 0xe7, - 0x07, 0xa3, 0x53, 0x49, 0xf7, 0x39, 0xcb, 0xff, 0xfb, 0xc9, 0x3e, 0x07, - 0xe3, 0x1e, 0x5b, 0x49, 0xdd, 0x87, 0x2f, 0xf4, 0xee, 0xc1, 0x8d, 0xcc, - 0x72, 0xff, 0xb9, 0xc5, 0x40, 0xcc, 0xf9, 0xbc, 0x44, 0x92, 0x2f, 0x5f, - 0xf6, 0x0c, 0xff, 0x00, 0xef, 0x31, 0xcb, 0xff, 0xec, 0xff, 0x7f, 0x26, - 0xef, 0xea, 0xa6, 0x0a, 0xa7, 0x2f, 0xfb, 0x73, 0xc4, 0xf3, 0xff, 0xb9, - 0xce, 0x5f, 0xfb, 0xe4, 0xdd, 0xfd, 0x54, 0xc1, 0x54, 0xe5, 0xfe, 0x1f, - 0x9a, 0xfd, 0xa7, 0xfb, 0x39, 0x58, 0x7f, 0xdf, 0xa2, 0x54, 0x23, 0x7f, - 0x50, 0xbd, 0xbf, 0xfd, 0x3f, 0xcd, 0x77, 0xff, 0x9e, 0xd6, 0xa3, 0x67, - 0x2f, 0xff, 0xbb, 0x13, 0xfc, 0x1c, 0xe2, 0xfd, 0xec, 0x72, 0x72, 0xff, - 0xff, 0xb9, 0xd2, 0x63, 0x7f, 0x3b, 0x9e, 0xd6, 0x4f, 0xf3, 0x10, 0x27, - 0x28, 0x28, 0xc0, 0xc5, 0x4b, 0xfa, 0x7f, 0x4c, 0x30, 0xc3, 0x97, 0xff, - 0xf6, 0x4f, 0x88, 0x11, 0xff, 0xbf, 0x20, 0x2f, 0x36, 0x8e, 0x5f, 0xf6, - 0x37, 0x9d, 0x4d, 0xf5, 0xce, 0x56, 0x27, 0xf2, 0x91, 0x89, 0x39, 0x16, - 0x8b, 0xfc, 0xbd, 0x53, 0xb2, 0x48, 0x02, 0xce, 0xac, 0x3b, 0xd7, 0x1f, - 0x67, 0x30, 0x93, 0x42, 0xbd, 0xc3, 0xbd, 0x8a, 0x7d, 0x3b, 0xd4, 0x66, - 0xbe, 0x94, 0x41, 0x7f, 0xbc, 0x39, 0xee, 0xe4, 0xe7, 0x2f, 0xfc, 0xfb, - 0xee, 0x7a, 0x05, 0x00, 0x72, 0xff, 0xf8, 0x72, 0x7f, 0x80, 0xff, 0xd9, - 0x8c, 0x03, 0x67, 0x2f, 0xa5, 0xe4, 0x9c, 0xe5, 0xff, 0x63, 0x7c, 0xcb, - 0x5f, 0x3c, 0x87, 0x2f, 0xfd, 0x28, 0xc0, 0x77, 0x30, 0x56, 0x72, 0xff, - 0xf7, 0x50, 0x43, 0xf1, 0x45, 0x8e, 0x77, 0x0e, 0x56, 0x22, 0x1e, 0x63, - 0xcb, 0xfe, 0xea, 0x32, 0x30, 0x7d, 0xa3, 0x97, 0xff, 0xfb, 0xff, 0x6f, - 0xf9, 0xbe, 0x7a, 0x6e, 0xfe, 0x0f, 0x26, 0x70, 0x1c, 0xbe, 0x85, 0xc3, - 0x3e, 0x23, 0x1d, 0x64, 0x62, 0x6f, 0x50, 0xaa, 0xe1, 0x66, 0x7b, 0x3c, - 0x75, 0x41, 0x23, 0xe0, 0x8e, 0x2e, 0xff, 0xfe, 0xde, 0x3b, 0x3e, 0x2a, - 0xfc, 0xf7, 0x3b, 0xd8, 0xf1, 0xcb, 0xec, 0xdc, 0xd2, 0x39, 0x7f, 0xf9, - 0x54, 0xe6, 0x5a, 0xf8, 0x14, 0xe3, 0x01, 0x39, 0x7f, 0xd9, 0x34, 0xb3, - 0xb9, 0xc7, 0x47, 0x2f, 0xff, 0xc1, 0xef, 0xfa, 0xf9, 0xd4, 0xf7, 0x73, - 0x71, 0xc4, 0xe5, 0xfd, 0x9c, 0x8e, 0x60, 0x0e, 0x56, 0x22, 0x1c, 0x56, - 0xee, 0x86, 0x62, 0x6a, 0xca, 0x91, 0xed, 0x40, 0x61, 0x85, 0x68, 0x39, - 0x7c, 0x9b, 0x7e, 0x4e, 0x5c, 0x9e, 0x43, 0x65, 0xa1, 0x0b, 0xff, 0x93, - 0x8a, 0x07, 0xe4, 0x4c, 0x17, 0x6c, 0xe5, 0xff, 0xff, 0xe1, 0x45, 0x7a, - 0xf3, 0x7c, 0x1f, 0xf8, 0x3e, 0x67, 0x32, 0xcf, 0xc4, 0x1a, 0x39, 0x7e, - 0xea, 0x40, 0xce, 0x72, 0xd0, 0xc4, 0x54, 0xf1, 0x84, 0x15, 0x69, 0x32, - 0x1f, 0x43, 0xca, 0xa4, 0x9b, 0xaa, 0x46, 0x99, 0x7a, 0x6f, 0xc2, 0x72, - 0xa1, 0xb1, 0x0e, 0xca, 0x4a, 0x3a, 0x4b, 0x78, 0xda, 0xff, 0x63, 0xb4, - 0x78, 0xfd, 0x3f, 0x29, 0xbf, 0x40, 0xf9, 0x38, 0x9c, 0xbe, 0xf6, 0x9c, - 0x07, 0x2f, 0xfe, 0xea, 0x7c, 0x4d, 0xff, 0x3b, 0xed, 0x67, 0x2f, 0x93, - 0xaf, 0x39, 0xcb, 0xee, 0x31, 0xe8, 0x39, 0x7e, 0xd6, 0x79, 0x34, 0x72, - 0xff, 0xe4, 0xf7, 0x53, 0x30, 0x23, 0x8d, 0x9c, 0xbd, 0xb4, 0x54, 0xe5, + 0x32, 0x8c, 0xf1, 0xcb, 0x9f, 0x67, 0x2a, 0x47, 0xfa, 0x11, 0x84, 0x4f, + 0xbf, 0xd8, 0xd8, 0xc7, 0xba, 0x87, 0x2f, 0xfe, 0xfd, 0x9d, 0x1c, 0xe7, + 0xc2, 0xfd, 0x39, 0x7f, 0xfe, 0x90, 0xbf, 0x9d, 0x9b, 0x80, 0xc7, 0x62, + 0x47, 0x2b, 0x68, 0x98, 0x51, 0x16, 0xec, 0xd9, 0xcb, 0xce, 0xeb, 0x34, + 0x45, 0xaa, 0x91, 0xf1, 0x61, 0x22, 0xc5, 0xae, 0xd6, 0xce, 0x56, 0x8f, + 0x17, 0x65, 0xd7, 0xff, 0xef, 0xdf, 0xb8, 0x3a, 0xd6, 0x73, 0x2f, 0x23, + 0x0e, 0x5c, 0xb8, 0x39, 0x7f, 0xef, 0xdd, 0x41, 0xc9, 0xb5, 0x0d, 0x9c, + 0xb8, 0x5b, 0x39, 0x58, 0x7d, 0xdd, 0x16, 0x6d, 0x06, 0xff, 0xf4, 0xa3, + 0x07, 0xdf, 0xb8, 0x77, 0x0a, 0x9c, 0xbf, 0x82, 0x30, 0xb6, 0x7e, 0x72, + 0xfe, 0x8e, 0x43, 0xa7, 0x91, 0xcb, 0xc2, 0x18, 0x39, 0x70, 0x42, 0x72, + 0xff, 0x9b, 0x14, 0xda, 0x0f, 0x32, 0x39, 0x72, 0x4e, 0x72, 0xff, 0xbd, + 0xfe, 0x9f, 0x6f, 0x9d, 0x39, 0x41, 0x3d, 0x04, 0x17, 0xac, 0x46, 0x0a, + 0x0b, 0xbc, 0x22, 0x6f, 0xfe, 0x5e, 0xa1, 0x58, 0x1f, 0x70, 0xae, 0x14, + 0xd4, 0x9c, 0xbf, 0xc9, 0xd1, 0xfd, 0xd5, 0x59, 0xcb, 0x87, 0x67, 0x2a, + 0x11, 0x41, 0x8a, 0xc2, 0x69, 0x7f, 0xcb, 0x53, 0xc9, 0x26, 0xf3, 0xa7, + 0x2f, 0xfd, 0x1d, 0xec, 0x4b, 0xca, 0xa6, 0x8e, 0x59, 0xac, 0xe5, 0xf6, + 0xb7, 0x8d, 0x9c, 0xbe, 0x18, 0xe5, 0x48, 0x36, 0xf8, 0x29, 0x53, 0xa2, + 0xb4, 0x5d, 0xaf, 0xf2, 0xd3, 0x7a, 0xd4, 0x48, 0xe5, 0xff, 0xfb, 0x01, + 0xb4, 0xe5, 0xbc, 0x5c, 0x0f, 0xef, 0x23, 0x97, 0xff, 0x46, 0x0f, 0xb7, + 0xec, 0xc6, 0xf6, 0x72, 0xa1, 0x3d, 0x74, 0x87, 0x47, 0x48, 0xc4, 0xcf, + 0xca, 0xd7, 0x67, 0x25, 0x2d, 0x05, 0x2c, 0x0d, 0x1a, 0x70, 0x0b, 0xdf, + 0xef, 0x66, 0x80, 0xc4, 0xd9, 0x4f, 0xa6, 0x9e, 0xfe, 0x97, 0x53, 0x8e, + 0x4c, 0x72, 0xa0, 0xfd, 0x5d, 0x16, 0xfe, 0xea, 0x2e, 0x18, 0x87, 0x2f, + 0xf4, 0x02, 0x77, 0x94, 0x35, 0x9c, 0xb0, 0xc1, 0xf1, 0x09, 0x65, 0xbe, + 0xb5, 0x2c, 0x97, 0x7e, 0x16, 0x18, 0x88, 0x4e, 0x4e, 0x5d, 0x91, 0xb8, + 0xaa, 0x44, 0xb8, 0x62, 0x72, 0x5e, 0x89, 0x53, 0x17, 0x68, 0xbb, 0xb0, + 0xdc, 0x18, 0x69, 0x6e, 0x50, 0x23, 0x48, 0xc4, 0x14, 0x84, 0x15, 0xff, + 0xff, 0xce, 0xcf, 0xa9, 0xad, 0x7f, 0xad, 0x40, 0xe2, 0xa9, 0xde, 0xe2, + 0x87, 0x2f, 0xff, 0x70, 0xa5, 0x5b, 0x6b, 0x9c, 0x3c, 0x37, 0xcf, 0x9d, + 0x68, 0x72, 0xf9, 0x6e, 0xeb, 0x34, 0x54, 0x4b, 0xf3, 0x8c, 0x91, 0x87, + 0x2b, 0x47, 0xa8, 0xc2, 0xeb, 0xee, 0xe6, 0xb0, 0xe5, 0xe4, 0x9b, 0x80, + 0xe5, 0x41, 0xe0, 0xf4, 0x86, 0xfc, 0xb7, 0xec, 0x74, 0xe5, 0xff, 0xfd, + 0xf8, 0xba, 0xbf, 0x3c, 0xac, 0x0c, 0xb3, 0xa8, 0xc3, 0x97, 0xff, 0xe0, + 0x4a, 0x7e, 0x15, 0x0d, 0x5c, 0xeb, 0xd7, 0xcf, 0x9d, 0x68, 0x72, 0xff, + 0xfe, 0xfc, 0x5d, 0x5f, 0x9e, 0x56, 0x06, 0x59, 0xd4, 0x61, 0xcb, 0xed, + 0x6b, 0x1a, 0x1c, 0xa6, 0x22, 0x09, 0xd7, 0xaf, 0xff, 0xcf, 0x21, 0x8d, + 0xe7, 0x2b, 0x17, 0xce, 0x56, 0x72, 0xdf, 0x64, 0xac, 0x93, 0x21, 0x70, + 0xb6, 0x34, 0x21, 0x61, 0x3f, 0x57, 0xb7, 0x0e, 0xde, 0x24, 0x57, 0xfe, + 0x0e, 0x33, 0xeb, 0x4c, 0x14, 0xf1, 0xcb, 0xd8, 0xde, 0x1c, 0xbd, 0xfc, + 0x4e, 0x72, 0xfe, 0xc9, 0xc3, 0x18, 0x13, 0x97, 0xc1, 0xea, 0x4c, 0x72, + 0xb0, 0xf4, 0x1c, 0xb6, 0xf7, 0x60, 0x27, 0x2f, 0xf4, 0x42, 0x08, 0xfe, + 0xd6, 0x72, 0xe7, 0xfc, 0xe5, 0xfc, 0xf3, 0xe9, 0xdf, 0xc7, 0x2f, 0xba, + 0x9d, 0xfb, 0xc2, 0x26, 0x7c, 0x11, 0xc5, 0x5b, 0xa6, 0x20, 0xe8, 0xe3, + 0x66, 0x8d, 0x05, 0xef, 0xda, 0x5b, 0xba, 0xcd, 0x15, 0xea, 0xfc, 0x9c, + 0x0b, 0xfe, 0x73, 0x97, 0x44, 0x8e, 0x5d, 0x00, 0x39, 0x7f, 0x4e, 0xa3, + 0x47, 0x10, 0x1c, 0xbf, 0xf3, 0x88, 0x33, 0xd0, 0x28, 0x03, 0x95, 0x07, + 0xd8, 0xd0, 0xc6, 0xdf, 0x71, 0x31, 0xcd, 0x1a, 0x39, 0x68, 0x05, 0x94, + 0x84, 0x15, 0xff, 0xdf, 0x5e, 0x5f, 0x73, 0x4b, 0x77, 0x59, 0xa2, 0x46, + 0x5f, 0xfe, 0xfa, 0xc7, 0x97, 0xdc, 0xd2, 0xdd, 0xd6, 0x68, 0x9e, 0x17, + 0xff, 0xbe, 0xb1, 0xe5, 0xf7, 0x34, 0xb7, 0x75, 0x9a, 0x27, 0xf5, 0xff, + 0xef, 0xac, 0x79, 0x7d, 0xcd, 0x2d, 0xdd, 0x66, 0x8a, 0x19, 0x7f, 0xf3, + 0x1e, 0x5f, 0x73, 0x4b, 0x77, 0x59, 0xa2, 0x88, 0x5f, 0xfa, 0x5f, 0x7f, + 0xdf, 0xc8, 0xdc, 0x48, 0xe5, 0x7d, 0x44, 0xb4, 0x29, 0x5f, 0xfa, 0x64, + 0xef, 0x39, 0xe0, 0xe3, 0x0e, 0x5f, 0x67, 0xb0, 0x07, 0x2f, 0xc3, 0xfb, + 0xcb, 0x67, 0x2f, 0x0b, 0xfd, 0x13, 0xc9, 0xf1, 0x0d, 0xfb, 0x4b, 0x77, + 0x59, 0xa2, 0x91, 0x5f, 0xfd, 0xde, 0x2f, 0xad, 0xbf, 0x77, 0x13, 0x9c, + 0xbf, 0xf9, 0xf9, 0xdf, 0x5b, 0x80, 0x7c, 0x51, 0x87, 0x2f, 0xfa, 0x25, + 0x1a, 0x9e, 0x35, 0x39, 0xcb, 0xcf, 0x2f, 0xb8, 0x8f, 0xf7, 0x34, 0x02, + 0x38, 0xa5, 0x5f, 0xff, 0xdc, 0x7e, 0xa8, 0xbc, 0xf4, 0x0f, 0xb6, 0xe3, + 0xfe, 0x1c, 0xbf, 0xfd, 0x2f, 0xba, 0x70, 0x3f, 0x93, 0x58, 0xc3, 0x97, + 0xfe, 0x07, 0xdd, 0xff, 0xa0, 0x7c, 0x0c, 0xc7, 0x2f, 0xe9, 0x67, 0x7a, + 0xf2, 0x39, 0x7f, 0xff, 0x60, 0x7b, 0x0a, 0x7d, 0xf0, 0xb8, 0x37, 0xb8, + 0x01, 0x4b, 0x7d, 0x85, 0x70, 0x6b, 0x84, 0x4b, 0x23, 0x32, 0xea, 0x6b, + 0xaf, 0x81, 0x2f, 0xc8, 0xed, 0x0b, 0x6f, 0xff, 0xbb, 0x1d, 0x45, 0x77, + 0xbc, 0x10, 0x34, 0xc3, 0x97, 0xcb, 0x77, 0x59, 0xa2, 0x50, 0x5f, 0xfa, + 0x00, 0xc7, 0x97, 0x61, 0xf4, 0x72, 0xa4, 0x8b, 0xcd, 0x28, 0x89, 0x75, + 0xff, 0xe1, 0x7f, 0x6d, 0x41, 0xfe, 0x43, 0x8c, 0x39, 0x7d, 0xf5, 0xe5, + 0xf7, 0x0f, 0xe5, 0x85, 0xf5, 0x3b, 0x74, 0x0d, 0x2a, 0x4d, 0xc0, 0x63, + 0x20, 0x5c, 0xb9, 0x94, 0x84, 0x2b, 0x5c, 0x6f, 0xfa, 0x8e, 0x91, 0x8a, + 0xfd, 0x54, 0x02, 0xd7, 0x0e, 0xb5, 0xb8, 0x78, 0x7f, 0x2e, 0x9f, 0x82, + 0x3b, 0xbb, 0xff, 0xdf, 0x58, 0xf2, 0xfb, 0x9a, 0x5b, 0xba, 0xcd, 0x13, + 0x9a, 0xff, 0xf7, 0xd6, 0x3c, 0xbe, 0xe6, 0x96, 0xee, 0xb3, 0x45, 0x12, + 0xbf, 0xef, 0xdf, 0x52, 0x6a, 0x3c, 0x40, 0x87, 0x2f, 0xe4, 0xdc, 0xd2, + 0x40, 0x1c, 0xbf, 0xd1, 0x3a, 0x8d, 0x1c, 0x40, 0x72, 0xe9, 0x7d, 0x0a, + 0x29, 0xba, 0x84, 0xa1, 0x75, 0xff, 0xef, 0xbb, 0x1c, 0x04, 0x03, 0x5a, + 0x86, 0xce, 0x56, 0x91, 0x16, 0x03, 0xfa, 0xd2, 0xa0, 0x8d, 0xad, 0x7f, + 0x1c, 0x5d, 0xfb, 0x4b, 0x77, 0x59, 0xa2, 0x1c, 0x5f, 0xdf, 0xaf, 0x49, + 0x02, 0x72, 0xdf, 0x70, 0xf8, 0x7a, 0x69, 0x7f, 0xd1, 0xac, 0x5f, 0x63, + 0x99, 0x1c, 0xbf, 0xf8, 0x5d, 0x55, 0xf5, 0x35, 0xa8, 0x6c, 0xe5, 0xf2, + 0xdd, 0xd6, 0x68, 0x8b, 0xd7, 0xe1, 0x70, 0x3e, 0xce, 0x5f, 0xb2, 0x69, + 0x3e, 0xce, 0x56, 0x8f, 0xf3, 0xc5, 0xca, 0x13, 0x5f, 0xd8, 0x1e, 0xe0, + 0x1c, 0xe5, 0xf4, 0x7f, 0xc3, 0xec, 0xe5, 0x6c, 0xf5, 0x1b, 0x2c, 0xb8, + 0x67, 0x39, 0x7f, 0xde, 0x18, 0x62, 0x81, 0xec, 0x1c, 0xa8, 0x3d, 0x04, + 0x17, 0xbb, 0x7c, 0x9c, 0xbe, 0xf4, 0xa1, 0x52, 0x94, 0xc3, 0x76, 0xe3, + 0x17, 0xe7, 0xe7, 0xf7, 0xf1, 0xcb, 0xf3, 0xcf, 0xec, 0xe9, 0xcb, 0x7d, + 0x9d, 0x55, 0xe8, 0x4e, 0x72, 0x18, 0x33, 0x42, 0x13, 0xae, 0x62, 0xb7, + 0xf9, 0x03, 0x42, 0x9b, 0xff, 0xff, 0xe1, 0x7f, 0xb9, 0xff, 0x0e, 0x8a, + 0xa7, 0xbb, 0x89, 0x2d, 0xfc, 0xc5, 0x62, 0x47, 0x2f, 0xd9, 0xb6, 0x06, + 0x0e, 0x5f, 0xf9, 0xe5, 0xf7, 0x34, 0xb7, 0x75, 0x9a, 0x26, 0x45, 0xbe, + 0xad, 0x1f, 0x3a, 0x84, 0x33, 0x09, 0xef, 0x7b, 0x18, 0x72, 0xee, 0xb0, + 0xe5, 0xfb, 0x4b, 0x77, 0x59, 0xa2, 0xde, 0x5b, 0xec, 0x1f, 0x38, 0x47, + 0x30, 0x5e, 0xff, 0xf7, 0xd6, 0x3c, 0xbe, 0xe6, 0x96, 0xee, 0xb3, 0x45, + 0x26, 0xb9, 0xaa, 0x6a, 0xce, 0x5f, 0xd9, 0xe1, 0x88, 0x61, 0xcb, 0xfb, + 0x90, 0x29, 0xa7, 0x01, 0xcb, 0xbb, 0xf7, 0x84, 0x3f, 0xce, 0x90, 0xb9, + 0x5d, 0x42, 0xf2, 0xbc, 0xa5, 0x73, 0x64, 0x70, 0x3b, 0x85, 0x27, 0x13, + 0x55, 0x21, 0xad, 0x7f, 0xbe, 0xe6, 0x96, 0xee, 0xb3, 0x44, 0x3a, 0xbf, + 0x69, 0x6e, 0xeb, 0x34, 0x4b, 0x0b, 0xec, 0x03, 0x10, 0xe5, 0xfb, 0xeb, + 0x1e, 0x5f, 0x70, 0xf5, 0x5a, 0x1a, 0x5f, 0xef, 0xb9, 0xa5, 0xbb, 0xac, + 0xd1, 0x18, 0x2f, 0xf7, 0xdf, 0xe5, 0x9b, 0x7d, 0x9c, 0xbf, 0xff, 0x38, + 0x1a, 0x67, 0xd1, 0x7f, 0x4b, 0x3d, 0x81, 0x39, 0x42, 0x88, 0xdd, 0x9b, + 0x5f, 0x7d, 0x96, 0x6c, 0xe5, 0xff, 0xff, 0x4b, 0x7f, 0x57, 0xd7, 0x99, + 0x7d, 0xcd, 0x35, 0x3d, 0x99, 0x9b, 0x39, 0x7e, 0xcf, 0x02, 0x16, 0x72, + 0xff, 0xf4, 0x79, 0x01, 0x12, 0x0f, 0x60, 0x56, 0x72, 0xfd, 0xa5, 0xbb, + 0xac, 0xd1, 0x1e, 0xaf, 0xb6, 0xfc, 0xf1, 0x39, 0x74, 0xbe, 0xe1, 0xec, + 0xf8, 0xd2, 0xff, 0xfe, 0x7f, 0xa3, 0xfe, 0x77, 0x04, 0x18, 0x3e, 0xee, + 0x1c, 0xb7, 0xde, 0x53, 0xc3, 0x99, 0xcb, 0x44, 0xef, 0x0a, 0x11, 0x2f, + 0xbf, 0x69, 0x6e, 0xeb, 0x34, 0x58, 0x6b, 0xfd, 0x21, 0x8c, 0xde, 0x09, + 0xcb, 0x92, 0x47, 0x2d, 0xf7, 0x0f, 0xeb, 0x93, 0x40, 0x18, 0x5f, 0xde, + 0x18, 0x04, 0x98, 0x72, 0xff, 0xff, 0xa2, 0x37, 0xf7, 0xc1, 0x46, 0x73, + 0x2d, 0xf3, 0x2c, 0xd4, 0xe7, 0x2e, 0x8d, 0x7d, 0x44, 0xc8, 0x96, 0xdf, + 0xef, 0xb9, 0xa5, 0xbb, 0xac, 0xd1, 0x73, 0xaf, 0xff, 0xff, 0xfe, 0x8e, + 0x17, 0x94, 0xeb, 0xef, 0xcf, 0x9d, 0x69, 0xf6, 0x7f, 0xd5, 0xe1, 0x68, + 0xe1, 0x39, 0x9e, 0x75, 0xb3, 0xe7, 0xce, 0xb4, 0x39, 0x50, 0xbd, 0x21, + 0x3c, 0x25, 0xa4, 0x89, 0x90, 0xce, 0x59, 0x12, 0x47, 0xce, 0xc8, 0x69, + 0x76, 0x1a, 0x1e, 0x2f, 0xe0, 0x41, 0xbf, 0xdf, 0x73, 0x4b, 0x77, 0x59, + 0xa2, 0x1e, 0x5f, 0x2d, 0xdd, 0x66, 0x88, 0x99, 0x7f, 0x67, 0x07, 0xec, + 0xc0, 0x9c, 0xb7, 0xe7, 0x2f, 0xf7, 0xbf, 0x7e, 0x7b, 0x1c, 0x4e, 0x56, + 0x91, 0x50, 0x25, 0xdb, 0x31, 0xf0, 0x95, 0xf8, 0x1b, 0xf9, 0x81, 0x39, + 0x7f, 0x91, 0xbc, 0x1c, 0xe7, 0xc7, 0x29, 0x0f, 0x77, 0x45, 0x57, 0xff, + 0xe8, 0xd0, 0x3b, 0x1c, 0x66, 0x88, 0x66, 0xf0, 0x27, 0x2f, 0xfb, 0xbd, + 0x8e, 0x32, 0xcd, 0x41, 0xcb, 0x7b, 0xa8, 0x91, 0x75, 0x7b, 0xfe, 0x4f, + 0x27, 0xb0, 0x11, 0xa3, 0x97, 0xd3, 0xf7, 0xf9, 0xce, 0x56, 0x22, 0x15, + 0xca, 0x3f, 0x37, 0xbd, 0x81, 0xe9, 0xcb, 0xff, 0xfb, 0xdd, 0x8d, 0x03, + 0x78, 0x1f, 0x7e, 0xeb, 0xcd, 0x1c, 0xbb, 0xcc, 0x39, 0x7f, 0xfb, 0x3a, + 0xa4, 0xfb, 0x84, 0xe7, 0xd0, 0xc3, 0x97, 0xfd, 0x12, 0x53, 0x35, 0xbc, + 0x6c, 0xe5, 0xfe, 0x94, 0x2a, 0x9d, 0x79, 0xce, 0x54, 0xe7, 0xdc, 0x87, + 0x55, 0x89, 0xa7, 0xf2, 0xb9, 0xd1, 0x7f, 0xe1, 0x75, 0x7f, 0xc1, 0xce, + 0x3a, 0x7e, 0x3d, 0x43, 0x97, 0xe6, 0xff, 0x8d, 0x4e, 0x72, 0xc9, 0xf0, + 0xf9, 0xdb, 0x3c, 0xbe, 0x97, 0x54, 0xd9, 0xcb, 0x9d, 0x43, 0x44, 0x2e, + 0xb7, 0xb9, 0x3c, 0x8f, 0xc9, 0x2f, 0xdd, 0xc9, 0xff, 0x13, 0x97, 0xcf, + 0xa8, 0xe2, 0x72, 0x82, 0x79, 0x80, 0x29, 0xbf, 0x4d, 0x2c, 0x71, 0x39, + 0x6f, 0xb8, 0xba, 0x8d, 0xa8, 0x4c, 0xf6, 0x33, 0x71, 0x2f, 0xdc, 0x6d, + 0x7e, 0x85, 0x5f, 0xee, 0x5c, 0x5d, 0x9a, 0x11, 0x5f, 0xfb, 0x5f, 0xcf, + 0x9d, 0x98, 0x60, 0x27, 0x2f, 0xff, 0xf3, 0xa7, 0xbf, 0xd3, 0xef, 0x07, + 0xb9, 0x83, 0x2d, 0x9c, 0xbb, 0xae, 0x72, 0xdf, 0x9c, 0xac, 0x35, 0x1b, + 0x16, 0xbc, 0x0d, 0xfd, 0x84, 0x73, 0xf5, 0x07, 0xd0, 0x86, 0xbf, 0xfe, + 0xc4, 0x96, 0xfe, 0xe7, 0x32, 0x79, 0xd4, 0x59, 0xca, 0x84, 0x4e, 0x75, + 0x22, 0xff, 0x9a, 0xae, 0x13, 0x59, 0xe4, 0xef, 0xe7, 0x2f, 0xb6, 0x93, + 0xf0, 0x87, 0x29, 0xaa, 0x3e, 0xc6, 0xa5, 0x12, 0xff, 0xcd, 0x57, 0x08, + 0x93, 0xc7, 0xc5, 0xef, 0x0e, 0x5d, 0xc2, 0x84, 0xe5, 0x35, 0x47, 0xce, + 0xd4, 0xa5, 0xdf, 0xfb, 0x84, 0xcf, 0x29, 0x3b, 0xe9, 0x26, 0x39, 0x7f, + 0x35, 0x4a, 0x77, 0xb9, 0x39, 0xcb, 0x74, 0xe5, 0x35, 0x47, 0x8d, 0xf9, + 0xad, 0xf0, 0x70, 0x66, 0x39, 0x72, 0x78, 0xe5, 0xbc, 0x86, 0xe3, 0xa4, + 0x57, 0xfb, 0x9f, 0x73, 0x2f, 0xc5, 0x53, 0x97, 0xfe, 0x89, 0x87, 0x38, + 0xbb, 0x18, 0x87, 0x29, 0xcf, 0xdf, 0xf3, 0x8b, 0xff, 0xff, 0xbb, 0xf8, + 0x53, 0x35, 0x30, 0xe7, 0x1e, 0xe0, 0x63, 0x7b, 0x85, 0x4e, 0x5f, 0xfe, + 0x49, 0xa5, 0x9c, 0xcb, 0xe3, 0x1d, 0xc4, 0xe5, 0xcf, 0xc0, 0x72, 0xff, + 0xff, 0x6f, 0x3d, 0xf3, 0xb8, 0xb8, 0x6c, 0x70, 0x3d, 0x49, 0x8e, 0x5b, + 0x84, 0xc4, 0xff, 0x15, 0x84, 0xea, 0xc8, 0xba, 0xea, 0xe9, 0x9e, 0x19, + 0xb9, 0xa2, 0xa7, 0x2f, 0x9e, 0x50, 0x03, 0x97, 0xee, 0xbf, 0x9e, 0x47, + 0x2f, 0xe4, 0xd0, 0xe6, 0x68, 0xe5, 0xe5, 0xcf, 0xd3, 0x97, 0xf6, 0xe3, + 0x6d, 0x41, 0xaa, 0x6a, 0x8e, 0x57, 0xc3, 0xdc, 0x90, 0xf5, 0xff, 0xcc, + 0xf9, 0xb1, 0xce, 0x64, 0x2f, 0x39, 0xcb, 0xdb, 0x40, 0x1c, 0xac, 0x3e, + 0x34, 0x47, 0xbc, 0xdb, 0x6d, 0x94, 0xbf, 0x38, 0xfb, 0xb8, 0x53, 0xe9, + 0xa0, 0xbf, 0xff, 0xfa, 0x27, 0xf9, 0xbf, 0xe3, 0x9f, 0x77, 0x19, 0x9e, + 0x18, 0x00, 0x20, 0xe5, 0xf7, 0xa6, 0xcf, 0x1c, 0xa0, 0xa2, 0x61, 0xdd, + 0x68, 0x29, 0x99, 0x01, 0x00, 0x61, 0xa1, 0x7e, 0xe8, 0xb5, 0x16, 0x9c, + 0x07, 0x2e, 0x77, 0x39, 0x6e, 0xa1, 0xe4, 0x39, 0x9d, 0xff, 0xfc, 0x0d, + 0x47, 0xcd, 0x47, 0xb9, 0x94, 0x2b, 0xa7, 0x6c, 0xe5, 0xff, 0x92, 0x6f, + 0x9d, 0x84, 0xd7, 0xed, 0x67, 0x2a, 0x11, 0x4a, 0x06, 0x0b, 0xfb, 0x49, + 0xc1, 0xad, 0xec, 0xe5, 0xfc, 0x3f, 0xf9, 0x27, 0x83, 0x97, 0xfe, 0x45, + 0x60, 0x63, 0x70, 0x8c, 0x39, 0x7e, 0xe3, 0xfc, 0xb3, 0x67, 0x2f, 0x80, + 0x83, 0xf9, 0xca, 0xc3, 0xcd, 0xfc, 0xae, 0xfb, 0x03, 0x93, 0x9c, 0xbe, + 0x6b, 0xf9, 0x0d, 0x49, 0xcb, 0xb5, 0x07, 0x28, 0x2b, 0xac, 0x18, 0x42, + 0xb2, 0x7e, 0x61, 0x0e, 0x91, 0xdc, 0xb5, 0xbe, 0xcd, 0x0c, 0xbd, 0x11, + 0x30, 0xc7, 0xa5, 0xc3, 0x08, 0x9f, 0x11, 0x71, 0x22, 0xe0, 0x2c, 0xbf, + 0x37, 0x18, 0x14, 0x39, 0x7b, 0xff, 0x6c, 0xe5, 0xff, 0xff, 0xff, 0x6f, + 0xe7, 0x72, 0x78, 0x6f, 0x99, 0x6f, 0xe7, 0xeb, 0xd6, 0xa3, 0xe4, 0xca, + 0xf3, 0xf3, 0xe7, 0x5a, 0x1c, 0xbf, 0xb9, 0xf9, 0x36, 0x62, 0xce, 0x56, + 0x26, 0x42, 0xb2, 0x7f, 0x0f, 0x7f, 0x0a, 0xbb, 0xbf, 0x01, 0xcb, 0x9a, + 0x35, 0x47, 0x2f, 0x7c, 0x92, 0xce, 0x54, 0x1e, 0xaa, 0xa3, 0x0c, 0x1e, + 0xbf, 0xff, 0xb5, 0xf0, 0x73, 0x8e, 0x6a, 0x5f, 0x20, 0x2f, 0x36, 0xce, + 0x5f, 0xff, 0xfc, 0x3c, 0xc2, 0xa3, 0x81, 0xea, 0x4d, 0xf3, 0x79, 0xcc, + 0xb5, 0x8d, 0x9c, 0xac, 0x46, 0xc0, 0xb0, 0xdf, 0x7b, 0xf8, 0x9c, 0xe5, + 0xfe, 0x96, 0x77, 0x19, 0x0b, 0x39, 0x48, 0x7a, 0xde, 0x24, 0xbf, 0xff, + 0xb9, 0x96, 0xd9, 0x83, 0xf3, 0x81, 0x3b, 0x3a, 0x66, 0x8e, 0x59, 0xac, + 0xe5, 0x61, 0xfa, 0xad, 0x86, 0xff, 0xff, 0xcd, 0xfc, 0x1c, 0x5f, 0x50, + 0x73, 0xfe, 0x7d, 0xf1, 0xdb, 0xc5, 0x4e, 0x5f, 0xe5, 0x43, 0xfc, 0x74, + 0x60, 0xe5, 0xfe, 0xe6, 0x5b, 0x57, 0xf8, 0xe4, 0xe5, 0xfe, 0x76, 0xff, + 0x9a, 0x3c, 0xe7, 0x2f, 0x71, 0xf2, 0x87, 0x2a, 0x13, 0x34, 0xc7, 0x34, + 0x34, 0x13, 0x86, 0xcd, 0x6f, 0xff, 0xc3, 0x81, 0xef, 0xed, 0xed, 0x3d, + 0xd4, 0x70, 0x1c, 0xbf, 0xc3, 0x9c, 0x7e, 0x49, 0x92, 0x39, 0x5a, 0x44, + 0x6e, 0xd5, 0xae, 0xdf, 0x13, 0x95, 0x06, 0xf3, 0xf2, 0x3b, 0xe0, 0x79, + 0x27, 0x39, 0x7f, 0xbd, 0xd4, 0x10, 0x28, 0xc3, 0x97, 0xff, 0xf7, 0x53, + 0x07, 0x10, 0x39, 0x00, 0x75, 0xbe, 0x8e, 0x5f, 0xe9, 0xe1, 0x83, 0x1c, + 0x80, 0xe5, 0x49, 0x17, 0xdc, 0x9a, 0x3a, 0xb5, 0xfb, 0xbf, 0x1f, 0x36, + 0x72, 0xa0, 0xf6, 0x70, 0xc2, 0xff, 0xe7, 0xd4, 0xbe, 0x78, 0x62, 0x59, + 0xe3, 0x95, 0x0b, 0xa6, 0x78, 0xee, 0x90, 0x96, 0xd4, 0x6a, 0xbd, 0x8c, + 0x45, 0xc8, 0x46, 0x33, 0xaf, 0xc8, 0x2c, 0xd6, 0x72, 0xff, 0xfb, 0x49, + 0xff, 0x0f, 0x1f, 0x37, 0xf8, 0x19, 0x9e, 0x39, 0x7f, 0xe8, 0x5e, 0xe1, + 0x39, 0xf4, 0x30, 0xe5, 0xa4, 0x72, 0x84, 0xf3, 0xff, 0x3e, 0xbf, 0x40, + 0x37, 0x3f, 0x8e, 0x5e, 0x7f, 0x6c, 0xe5, 0xdf, 0xce, 0x72, 0xa4, 0x6d, + 0x74, 0x39, 0x7e, 0xc9, 0x75, 0xe4, 0x72, 0xe1, 0xf4, 0xc7, 0x91, 0xd2, + 0x1b, 0xfc, 0xe2, 0xa7, 0x7b, 0x01, 0x39, 0x7f, 0x7e, 0xbf, 0x81, 0xe5, + 0xb3, 0x97, 0xfd, 0x0d, 0xf7, 0x07, 0x98, 0x54, 0xe5, 0xda, 0x91, 0xca, + 0x84, 0x73, 0x72, 0x5c, 0x86, 0x7a, 0x34, 0x61, 0xd5, 0xfe, 0xd4, 0x06, + 0x3b, 0x12, 0x39, 0x7f, 0xfd, 0x1e, 0xf8, 0x3f, 0xf0, 0x7c, 0xcf, 0x34, + 0xcf, 0x1c, 0xa4, 0x44, 0x5f, 0xe6, 0x57, 0xff, 0x76, 0x15, 0xf9, 0xe1, + 0x7f, 0x47, 0x8e, 0x5f, 0xef, 0x9c, 0xc9, 0x3b, 0xfb, 0x0e, 0x50, 0x0f, + 0xf8, 0x51, 0xaf, 0xfe, 0xce, 0x38, 0x1f, 0x9e, 0x55, 0x1b, 0xd9, 0xcb, + 0xff, 0x6a, 0x6f, 0x9b, 0x84, 0x9d, 0xfc, 0x72, 0xa1, 0x15, 0xa1, 0x21, + 0xfd, 0x2a, 0xe7, 0x01, 0xcb, 0xff, 0xef, 0x83, 0x1b, 0x89, 0xc7, 0x03, + 0xd4, 0x98, 0xe5, 0xff, 0xff, 0xdb, 0xd0, 0xc4, 0xdf, 0x14, 0xf2, 0x4b, + 0x39, 0xf6, 0x71, 0x1c, 0xd9, 0xca, 0xd2, 0x32, 0x05, 0x46, 0xbc, 0x98, + 0x07, 0xf0, 0xde, 0xa3, 0x97, 0xbd, 0xf1, 0x53, 0x97, 0x4d, 0x23, 0x95, + 0x07, 0x87, 0xc8, 0x5e, 0x88, 0x2f, 0xfe, 0x1f, 0x6f, 0x8a, 0x7a, 0x30, + 0x66, 0x39, 0x7e, 0xd2, 0x6e, 0x39, 0x39, 0x58, 0x7d, 0xae, 0x8b, 0x7f, + 0xa7, 0xe1, 0x26, 0x92, 0x7b, 0x67, 0x2f, 0xc3, 0xee, 0xe7, 0x01, 0xcb, + 0xf4, 0xdb, 0x7d, 0x2a, 0x72, 0xf3, 0xb7, 0xa8, 0x3d, 0x4c, 0x2a, 0xa9, + 0x23, 0x85, 0x08, 0x35, 0x08, 0xfb, 0xfe, 0xea, 0x6a, 0x6e, 0xbe, 0x68, + 0xe5, 0xff, 0xff, 0xfc, 0x0d, 0x8e, 0x3f, 0x3f, 0x03, 0xdf, 0xfe, 0x0e, + 0x73, 0x2c, 0xfe, 0x71, 0xc7, 0xe4, 0xe5, 0x2d, 0x19, 0x28, 0x73, 0x79, + 0xdd, 0x66, 0x8a, 0x61, 0x58, 0x79, 0x4b, 0x22, 0xbf, 0xf6, 0x0f, 0x32, + 0xdf, 0xa3, 0x53, 0x1c, 0xbf, 0xf3, 0xf3, 0x89, 0xa4, 0x64, 0x2a, 0x72, + 0xf6, 0x20, 0x0e, 0x5b, 0x0e, 0x5e, 0xe4, 0x70, 0x06, 0xaf, 0x88, 0xdd, + 0x22, 0x37, 0x74, 0x80, 0xed, 0x37, 0xb3, 0xfd, 0x1c, 0xba, 0x79, 0x8e, + 0x59, 0xb3, 0x97, 0x20, 0x4e, 0x53, 0x59, 0xa8, 0xd8, 0x95, 0xc1, 0x98, + 0xe5, 0xca, 0xce, 0x72, 0xfb, 0x5d, 0x7f, 0x90, 0x89, 0x6c, 0x41, 0x61, + 0x23, 0x63, 0x17, 0xfb, 0xe7, 0x32, 0x18, 0xcd, 0x9c, 0xae, 0x53, 0x3d, + 0x48, 0x59, 0xba, 0xad, 0xff, 0xf8, 0x09, 0xbf, 0x9d, 0x7d, 0xfa, 0x26, + 0xdf, 0x70, 0xe5, 0xfd, 0xd7, 0xdf, 0x5e, 0x47, 0x2f, 0xe4, 0xeb, 0xa4, + 0xf0, 0x72, 0xf4, 0xa3, 0x93, 0x97, 0xf9, 0x81, 0xec, 0x4f, 0x8d, 0x9c, + 0xa8, 0x45, 0x5e, 0x16, 0xf2, 0x58, 0xe3, 0xb7, 0xf6, 0x72, 0xb1, 0x8e, + 0x27, 0x2e, 0xde, 0xce, 0x5b, 0x0e, 0x5f, 0xfa, 0x64, 0x55, 0x3c, 0x39, + 0xc1, 0xf3, 0x46, 0x9f, 0x88, 0xbd, 0xff, 0xfe, 0x1c, 0x5f, 0xbd, 0x1e, + 0xdc, 0xc3, 0x8d, 0xfc, 0x86, 0xa4, 0xe5, 0xff, 0x97, 0x0c, 0xee, 0x6f, + 0x10, 0x4e, 0x54, 0x22, 0x93, 0xad, 0x17, 0xed, 0x47, 0x18, 0xd1, 0xcb, + 0xf9, 0xc7, 0xe0, 0x60, 0x4e, 0x54, 0x26, 0xf1, 0x91, 0x80, 0x21, 0x17, + 0xe5, 0x37, 0xfd, 0x0d, 0xad, 0x27, 0xce, 0x7c, 0x72, 0x9a, 0xb6, 0x78, + 0xa4, 0x0a, 0x4f, 0x0a, 0x89, 0x11, 0x06, 0x38, 0xc5, 0x61, 0xa8, 0xb8, + 0xd3, 0xb9, 0x8c, 0xc1, 0x1b, 0x66, 0x8d, 0xf7, 0x51, 0xa3, 0xb2, 0x1f, + 0xdd, 0x8d, 0xac, 0x06, 0xa3, 0x18, 0x1e, 0xce, 0xfd, 0x1e, 0x77, 0x14, + 0x2b, 0xfe, 0xd3, 0xb7, 0xf1, 0xc2, 0xf3, 0x9c, 0xbf, 0x9d, 0xb9, 0x85, + 0x02, 0x72, 0xff, 0xff, 0x07, 0x27, 0x71, 0xf6, 0xe1, 0x7f, 0x18, 0xc4, + 0x15, 0x9c, 0xbf, 0x83, 0xb7, 0x8e, 0x64, 0x72, 0xa1, 0x12, 0x0e, 0xc5, + 0x7f, 0xd1, 0x37, 0x52, 0x18, 0xe1, 0x39, 0x4a, 0xa6, 0xa7, 0xa3, 0xc1, + 0x85, 0xf7, 0xe4, 0x37, 0xd8, 0x2a, 0xb5, 0x9c, 0xbf, 0xff, 0xff, 0x75, + 0x3d, 0xdc, 0xd4, 0x71, 0xf8, 0xcf, 0xf8, 0x3e, 0x67, 0x32, 0xcf, 0xc4, + 0x1b, 0x39, 0x6f, 0x22, 0x2d, 0x36, 0x4b, 0x7f, 0xe8, 0x5f, 0xc1, 0x7d, + 0xb2, 0x04, 0xe5, 0xff, 0xfb, 0x33, 0xa8, 0xbe, 0xe7, 0xcd, 0xff, 0xd8, + 0x6b, 0x39, 0x7f, 0xfd, 0xee, 0xe0, 0x3e, 0x32, 0x33, 0xc1, 0xc1, 0x39, + 0x66, 0xce, 0x5f, 0xce, 0x1d, 0x6b, 0xf9, 0xce, 0x5f, 0xa3, 0x07, 0xcd, + 0x0e, 0x52, 0xa7, 0xd4, 0xb1, 0x26, 0x18, 0x5f, 0x79, 0x35, 0x87, 0x2d, + 0xcf, 0xc3, 0xd1, 0xc3, 0x0b, 0x6f, 0x13, 0x35, 0x78, 0xc2, 0xe9, 0x89, + 0xfd, 0x89, 0xf7, 0xa3, 0x8f, 0xbf, 0xff, 0xfe, 0xce, 0x64, 0x9b, 0x1c, + 0xe3, 0xdc, 0x9b, 0xb0, 0x33, 0x7c, 0x75, 0xa7, 0x13, 0x97, 0xff, 0xfd, + 0x82, 0xaf, 0xcd, 0x47, 0x14, 0xf6, 0xf1, 0x54, 0xd3, 0xf2, 0x72, 0x85, + 0x1d, 0xca, 0x42, 0x0e, 0x91, 0x34, 0xcf, 0xe3, 0x24, 0xbf, 0xfc, 0x81, + 0xf8, 0xc4, 0xf9, 0x01, 0x79, 0xb6, 0x72, 0xe9, 0x48, 0xe5, 0xb5, 0x07, + 0xcb, 0x3a, 0x75, 0xfa, 0x51, 0xcc, 0xb6, 0x72, 0xff, 0xff, 0xff, 0xd8, + 0x2a, 0xfc, 0x4e, 0xff, 0xf6, 0x64, 0xf4, 0x30, 0x5d, 0x5e, 0xa7, 0xdc, + 0xef, 0x20, 0x80, 0x94, 0xbf, 0xff, 0xf9, 0x68, 0xd8, 0x7f, 0xd7, 0xcf, + 0xe2, 0x7d, 0xaf, 0xbf, 0xf7, 0x97, 0x6c, 0xe5, 0xdf, 0xcf, 0xca, 0x69, + 0x08, 0x53, 0xb8, 0x51, 0x5f, 0xca, 0x8e, 0x7b, 0xa8, 0x72, 0xa1, 0x77, + 0x7f, 0xb2, 0xdb, 0xde, 0x11, 0xe3, 0x1b, 0x87, 0xe8, 0x96, 0x61, 0xcb, + 0xfc, 0xf2, 0xc6, 0x38, 0x80, 0xe5, 0xf6, 0x76, 0x26, 0x39, 0x79, 0x8b, + 0xf8, 0xd5, 0x9f, 0x27, 0x44, 0x5c, 0xc6, 0xff, 0xff, 0xf6, 0x96, 0x39, + 0xc7, 0xe6, 0xd3, 0x04, 0x1f, 0x07, 0x38, 0x8e, 0x6f, 0x89, 0xcb, 0xfd, + 0x8e, 0xcf, 0x8d, 0x21, 0x87, 0x2f, 0xff, 0x4a, 0x37, 0xdf, 0xf5, 0x9e, + 0xf2, 0x30, 0xe5, 0x2d, 0x10, 0x3c, 0x9b, 0x5f, 0xff, 0xbf, 0x8f, 0x83, + 0x81, 0xea, 0x2a, 0x18, 0x54, 0x07, 0x2b, 0x13, 0x7c, 0xd4, 0x3f, 0xc4, + 0x92, 0xff, 0xfc, 0x83, 0xee, 0xe7, 0x07, 0xa6, 0xc6, 0xb7, 0x10, 0x1c, + 0xbe, 0x6f, 0xe6, 0xe6, 0x39, 0x6f, 0x1c, 0xa8, 0x37, 0x0e, 0x4f, 0x7f, + 0xe1, 0x9c, 0x73, 0x8e, 0xff, 0x8e, 0x4e, 0x5f, 0xf8, 0x3d, 0x8e, 0x7e, + 0x35, 0x1e, 0x20, 0x43, 0x95, 0x08, 0x8c, 0x9d, 0x0a, 0x91, 0x39, 0x4d, + 0x9a, 0x7a, 0x12, 0x5f, 0xc2, 0xae, 0xff, 0xe6, 0xf3, 0x7f, 0xc2, 0xbb, + 0x8d, 0x4c, 0x72, 0xfb, 0x52, 0x70, 0x9c, 0xbf, 0xf0, 0xc9, 0x7d, 0x4e, + 0x8f, 0xf3, 0x9c, 0xbd, 0xec, 0xe1, 0xce, 0x54, 0x1f, 0x0e, 0x20, 0x5e, + 0x69, 0x9d, 0x39, 0x76, 0x04, 0xe5, 0x4e, 0xb9, 0x7d, 0x29, 0x6a, 0xf8, + 0x90, 0xe9, 0x1b, 0x84, 0x1f, 0x88, 0x38, 0x8f, 0x5f, 0x93, 0xdb, 0xc0, + 0x1c, 0xbf, 0x77, 0x38, 0xa7, 0x13, 0x97, 0xff, 0xfe, 0x17, 0xf7, 0x62, + 0x6f, 0x83, 0x9d, 0x4f, 0x6f, 0xf5, 0xff, 0x07, 0x2e, 0xc0, 0x1c, 0xbf, + 0xf8, 0x40, 0x38, 0x93, 0x76, 0x05, 0x53, 0x94, 0x87, 0xb2, 0xe2, 0xd7, + 0xf0, 0x60, 0x7a, 0xf2, 0x39, 0x7a, 0x03, 0x07, 0x2f, 0xd9, 0xed, 0xbc, + 0xdf, 0x0f, 0x1d, 0x85, 0x97, 0xcd, 0x5b, 0x50, 0xe1, 0x9a, 0xb3, 0x97, + 0xc8, 0xe2, 0x13, 0x96, 0x6f, 0xe1, 0xec, 0x04, 0xe2, 0xa4, 0x8c, 0x44, + 0x84, 0xcd, 0xff, 0xfb, 0x5f, 0xeb, 0x50, 0x38, 0xaa, 0x77, 0xb8, 0xa1, + 0xcb, 0xef, 0xdf, 0x9f, 0x1c, 0xa9, 0x2a, 0xe7, 0x09, 0x3e, 0x15, 0xab, + 0x0c, 0x89, 0xa3, 0x2b, 0xd1, 0x3f, 0x55, 0xe8, 0xe5, 0xfd, 0xb5, 0xad, + 0xc5, 0x53, 0x95, 0xc2, 0x8d, 0xcf, 0x82, 0xef, 0xf0, 0xfc, 0xe3, 0xcc, + 0xb7, 0x31, 0xcb, 0xa7, 0xe4, 0xe5, 0xfb, 0xae, 0xd7, 0x00, 0x39, 0x41, + 0x3f, 0xd7, 0x3a, 0xe0, 0x19, 0xbf, 0xda, 0x98, 0x73, 0xaf, 0xe3, 0x95, + 0x09, 0x84, 0x64, 0x29, 0x10, 0xc6, 0xfc, 0x9a, 0x0e, 0x09, 0xcb, 0xf0, + 0x33, 0xca, 0x4e, 0x72, 0xff, 0x37, 0xec, 0xef, 0xce, 0x76, 0x72, 0xa0, + 0xf8, 0x9c, 0xaa, 0xa4, 0x8d, 0xbe, 0x99, 0x8c, 0x22, 0x2f, 0xee, 0xe2, + 0xe5, 0x0c, 0x39, 0x7f, 0xbb, 0x92, 0x71, 0xce, 0x4e, 0x56, 0x1e, 0xff, + 0x8b, 0x6f, 0xff, 0xf8, 0x5c, 0x1b, 0x9f, 0x10, 0x7c, 0x39, 0xc7, 0xe6, + 0xdb, 0x13, 0x97, 0xf7, 0x70, 0x79, 0x85, 0x4e, 0x50, 0xa2, 0xe3, 0xc4, + 0x2d, 0xb4, 0xde, 0xc4, 0x98, 0xe5, 0xff, 0x93, 0x26, 0xf9, 0xb8, 0xeb, + 0xb5, 0x9c, 0xbf, 0xee, 0x72, 0x39, 0x98, 0x61, 0x87, 0x2f, 0xee, 0x77, + 0xdc, 0x7d, 0x1c, 0xbf, 0xff, 0xf2, 0x33, 0x49, 0x9c, 0x8f, 0xfe, 0x8e, + 0xfc, 0xe2, 0x9e, 0x9a, 0x0e, 0x53, 0xa2, 0x7f, 0xc5, 0xd5, 0x3a, 0x6b, + 0x41, 0x1c, 0xea, 0x1f, 0xa1, 0xb3, 0x7f, 0xfd, 0x8f, 0x3f, 0x61, 0x3d, + 0xb8, 0x9f, 0x36, 0x72, 0xff, 0xb3, 0x53, 0xc2, 0x6b, 0x04, 0xe5, 0x98, + 0x73, 0xe1, 0xb7, 0xbc, 0x38, 0x13, 0x95, 0x06, 0xfb, 0x92, 0x3b, 0xfb, + 0x9d, 0xe6, 0x0a, 0xa7, 0x2f, 0x98, 0xa4, 0x00, 0xe5, 0xff, 0xe9, 0xc3, + 0xa7, 0x58, 0xe7, 0x1d, 0x26, 0xce, 0x56, 0x22, 0x75, 0x0b, 0xbf, 0x23, + 0xbf, 0xbd, 0xd7, 0x99, 0x46, 0x1c, 0xbf, 0xbd, 0x00, 0x96, 0x6c, 0xe5, + 0x39, 0xee, 0x89, 0x85, 0xef, 0xf9, 0x01, 0xcb, 0xfb, 0x71, 0xc8, 0x35, + 0x07, 0x2e, 0x0a, 0x1c, 0xa8, 0x5c, 0x5f, 0xc8, 0xe2, 0x96, 0x88, 0x90, + 0xc4, 0xd4, 0x2f, 0x9e, 0x11, 0x82, 0x41, 0xb1, 0xfe, 0x25, 0xd7, 0xf7, + 0x9f, 0xbf, 0x03, 0x07, 0x2f, 0xff, 0x7b, 0x6a, 0x6f, 0xe7, 0x86, 0x25, + 0x9e, 0x39, 0x7f, 0xbc, 0x93, 0xe7, 0x7f, 0xf1, 0xcb, 0xef, 0x6e, 0x15, + 0x39, 0x69, 0x8e, 0x5f, 0xd9, 0xfe, 0x75, 0x73, 0x9c, 0xb7, 0x30, 0x78, + 0x3b, 0x12, 0xa8, 0x44, 0x66, 0x32, 0x5f, 0xdd, 0x79, 0x33, 0x48, 0x72, + 0xff, 0xe5, 0x55, 0x7f, 0x6f, 0xc3, 0x1c, 0xc8, 0xe5, 0xfd, 0xe1, 0x89, + 0x67, 0x8e, 0x54, 0x1f, 0x9c, 0x91, 0xee, 0x4d, 0x9c, 0xb3, 0x0e, 0x5e, + 0xd6, 0x72, 0x72, 0x82, 0x78, 0x9d, 0x16, 0x00, 0x8d, 0xff, 0xe7, 0x57, + 0xca, 0xc0, 0xcb, 0x3a, 0x8c, 0x39, 0x7e, 0x4d, 0xee, 0x18, 0x72, 0x91, + 0x14, 0x02, 0x5f, 0xc5, 0x2a, 0xa1, 0x59, 0x9e, 0x17, 0xaa, 0x9a, 0x90, + 0xc1, 0x01, 0x08, 0xc2, 0x83, 0xf8, 0xc1, 0x6f, 0xc1, 0x41, 0x70, 0x9c, + 0xbd, 0xb0, 0xf2, 0x72, 0xe0, 0x2c, 0xe5, 0xff, 0xec, 0x9b, 0xb0, 0x2a, + 0x8e, 0x7b, 0xbf, 0x9c, 0xa5, 0x4f, 0x8b, 0xa2, 0xf5, 0xf1, 0x14, 0x72, + 0x84, 0x05, 0x22, 0x3c, 0xf5, 0x0c, 0x9b, 0xff, 0xfc, 0x99, 0xcc, 0xb7, + 0xee, 0xc3, 0x21, 0x03, 0xf2, 0x1a, 0x93, 0x97, 0xf9, 0xc7, 0xe2, 0xf6, + 0x00, 0x9c, 0xbf, 0xf7, 0xfb, 0xf8, 0xc5, 0x3a, 0xfd, 0x83, 0x97, 0xec, + 0xf7, 0xf9, 0xc9, 0xcb, 0xca, 0xe7, 0x27, 0x2e, 0x89, 0xbe, 0x1e, 0x3f, + 0x8a, 0x68, 0x51, 0x75, 0xfc, 0x22, 0xaf, 0xff, 0xff, 0xdf, 0x8f, 0xc6, + 0xdf, 0x99, 0x69, 0xc1, 0xf3, 0x7f, 0xc7, 0x3d, 0xc4, 0x1c, 0x54, 0xe5, + 0xff, 0xfe, 0xf7, 0xf8, 0x3f, 0x13, 0x3c, 0x30, 0x0f, 0x98, 0x81, 0x39, + 0x7f, 0xcc, 0xc6, 0x7c, 0x63, 0x5f, 0x19, 0x1c, 0xad, 0x22, 0x8d, 0x8c, + 0x57, 0xff, 0xda, 0xd6, 0x7b, 0x7d, 0x4c, 0xf9, 0xd0, 0x41, 0xca, 0x43, + 0xf4, 0xfc, 0x8e, 0xb1, 0x3c, 0x4e, 0xc7, 0x45, 0x7e, 0xc1, 0x5a, 0x8c, + 0x39, 0x7f, 0xf7, 0x72, 0x06, 0x61, 0xcf, 0x6d, 0xce, 0x5a, 0x5e, 0x3e, + 0xae, 0x02, 0x8b, 0xff, 0xf0, 0x71, 0x9f, 0x38, 0x3d, 0x1b, 0x9a, 0x4f, + 0xa9, 0xce, 0x5f, 0xff, 0xde, 0x49, 0xf0, 0x3f, 0x18, 0xf2, 0xd2, 0x4e, + 0xec, 0x39, 0x7f, 0xa7, 0x76, 0x0c, 0x6a, 0x63, 0x97, 0xfd, 0xce, 0x2a, + 0x06, 0x67, 0xcd, 0x62, 0x24, 0x91, 0x7a, 0xff, 0xb0, 0x67, 0xf8, 0x07, + 0x79, 0x8e, 0x5f, 0xff, 0x67, 0xfa, 0xf9, 0x37, 0x7f, 0x55, 0x30, 0x55, + 0x39, 0x7f, 0xda, 0x9e, 0x27, 0x9f, 0xfd, 0x4e, 0x72, 0xff, 0xdf, 0x26, + 0xef, 0xea, 0xa6, 0x0a, 0xa7, 0x2f, 0xf0, 0xfc, 0xdf, 0xed, 0x3f, 0xd1, + 0xca, 0xc3, 0xfe, 0xfd, 0x12, 0xa1, 0x1b, 0xfb, 0x85, 0xed, 0xff, 0xe9, + 0xfe, 0x6f, 0xbf, 0xfc, 0xf6, 0xf7, 0x1a, 0x39, 0x7f, 0xfd, 0xd8, 0x9f, + 0xe0, 0xe7, 0x17, 0xef, 0x63, 0x93, 0x97, 0xff, 0xfd, 0xce, 0xd3, 0x1b, + 0xf9, 0xdc, 0xf6, 0xf2, 0x7f, 0x98, 0x81, 0x39, 0x41, 0x46, 0x06, 0x2a, + 0x5f, 0xf0, 0xe6, 0xb1, 0x78, 0x81, 0x39, 0x7f, 0x4f, 0xe9, 0x86, 0x18, + 0x72, 0xff, 0xfe, 0xc9, 0xf1, 0x02, 0x3f, 0xf7, 0xe4, 0x05, 0xe6, 0xd9, + 0xcb, 0xfe, 0xc6, 0xf3, 0xa9, 0xae, 0xb9, 0xca, 0xc5, 0x45, 0xe9, 0x18, + 0x97, 0x48, 0x9c, 0xdb, 0x65, 0xfe, 0x5e, 0xa9, 0xd9, 0x2c, 0x81, 0x67, + 0x56, 0x1d, 0xeb, 0x8f, 0xb3, 0x98, 0x49, 0xa1, 0x5e, 0xa1, 0xde, 0xc5, + 0x3e, 0x9d, 0xee, 0x33, 0x5f, 0x4a, 0x56, 0xbf, 0xde, 0x1c, 0xf7, 0x72, + 0x73, 0x97, 0xfe, 0x7d, 0x77, 0x3d, 0x02, 0x80, 0x39, 0x7f, 0xfc, 0x39, + 0x3f, 0xc0, 0x7f, 0xec, 0xc6, 0x01, 0xb3, 0x97, 0xd2, 0xf2, 0x4e, 0x72, + 0xff, 0xb1, 0xbe, 0x65, 0xbf, 0x9e, 0x43, 0x97, 0xfe, 0x94, 0x60, 0x3b, + 0x98, 0x2b, 0x39, 0x7f, 0xfb, 0xa8, 0x21, 0xf8, 0xa2, 0xc7, 0x3b, 0x87, + 0x2b, 0x11, 0x0f, 0x31, 0xe5, 0xff, 0x75, 0x19, 0x18, 0x3e, 0xd9, 0xcb, + 0xff, 0xfd, 0xff, 0xb5, 0xfc, 0xdf, 0x3d, 0x37, 0x7f, 0x07, 0x93, 0x38, + 0x0e, 0x5f, 0x42, 0xe1, 0x9f, 0x11, 0x8e, 0xb2, 0x31, 0x37, 0xa8, 0x55, + 0x70, 0xb3, 0x3d, 0x1e, 0x3a, 0xa0, 0x91, 0xf0, 0x47, 0x17, 0x7f, 0xff, + 0x6b, 0x1d, 0x9f, 0x15, 0x7e, 0x7b, 0x9d, 0xec, 0x78, 0xe5, 0xf6, 0x6a, + 0x69, 0x1c, 0xbf, 0xfc, 0xaa, 0x73, 0x2d, 0xfc, 0x0a, 0x71, 0x80, 0x9c, + 0xbf, 0xec, 0x9a, 0x59, 0xdc, 0xe3, 0xb3, 0x97, 0xff, 0xe0, 0xf7, 0xfd, + 0xfc, 0xea, 0x7b, 0xb9, 0xa8, 0xe2, 0x72, 0xfe, 0xce, 0x47, 0x30, 0x07, + 0x2b, 0x11, 0x0e, 0x2b, 0x77, 0x43, 0x31, 0x35, 0x65, 0x48, 0xf4, 0xa0, + 0x30, 0xc2, 0xb4, 0x1c, 0xbe, 0x4d, 0x3f, 0x27, 0x2e, 0x4f, 0x21, 0xb2, + 0xd8, 0x85, 0xff, 0xc9, 0xc5, 0x03, 0xf2, 0x26, 0x0b, 0xb6, 0x72, 0xff, + 0xff, 0xf0, 0xa2, 0xbd, 0x79, 0xbe, 0x0f, 0xfc, 0x1f, 0x33, 0x99, 0x67, + 0xe2, 0x0d, 0x9c, 0xbf, 0x75, 0x20, 0x67, 0x39, 0x4c, 0x45, 0x4f, 0x18, + 0x41, 0x5f, 0x31, 0x11, 0xb3, 0x95, 0x07, 0x98, 0xe5, 0x55, 0xb4, 0xd7, + 0xbd, 0x19, 0xf5, 0x49, 0x3b, 0x34, 0x8e, 0x26, 0xf4, 0xdf, 0x84, 0xe5, + 0x43, 0x63, 0x21, 0x94, 0x98, 0xb4, 0x96, 0xf1, 0xa5, 0xfe, 0xc7, 0x68, + 0xf2, 0x8c, 0xbf, 0x29, 0xbf, 0x40, 0xf9, 0x38, 0x9c, 0xbe, 0xf6, 0xdc, + 0x07, 0x2f, 0xfe, 0xea, 0x7c, 0x4d, 0x7f, 0x3b, 0xe9, 0x67, 0x2f, 0x93, + 0xaf, 0x39, 0xcb, 0xee, 0x31, 0xe8, 0x39, 0x7e, 0xde, 0x79, 0x36, 0x72, + 0xff, 0xe4, 0xf7, 0x53, 0x30, 0x23, 0x8d, 0x9c, 0xbd, 0xa4, 0x54, 0xe5, 0xff, 0xf7, 0xf8, 0x9d, 0xc5, 0xf5, 0x3e, 0x36, 0xc5, 0x9c, 0xbd, 0xec, 0x6c, 0xe5, 0xec, 0xfe, 0x71, 0x3f, 0x0f, 0x29, 0xdf, 0xbf, 0xe1, 0xc5, - 0xfc, 0x72, 0xfe, 0xeb, 0xcf, 0xf2, 0x5e, 0x39, 0x7f, 0x3c, 0xca, 0x6a, - 0x30, 0xe5, 0xf9, 0xf6, 0x3c, 0xa1, 0xca, 0x84, 0x59, 0xa1, 0x6f, 0x4c, - 0x7c, 0x5d, 0x41, 0x55, 0xdf, 0x85, 0x0a, 0x91, 0x2d, 0x21, 0x08, 0xa6, - 0x23, 0x61, 0x3b, 0xa1, 0x0c, 0x23, 0x7d, 0x0e, 0x7b, 0xe1, 0xf4, 0x30, - 0xe5, 0xfe, 0xec, 0x20, 0xbe, 0xd5, 0x39, 0x7f, 0x42, 0x0b, 0xed, 0x53, - 0x97, 0xf3, 0x83, 0x7b, 0x4d, 0xfc, 0x3d, 0xee, 0x99, 0x5f, 0xff, 0xfe, - 0xf8, 0xc8, 0xcf, 0x7c, 0xc9, 0x27, 0x11, 0xcd, 0x7c, 0x80, 0xbc, 0xda, - 0x39, 0x7f, 0x0a, 0xfe, 0x37, 0xa0, 0x1c, 0xa9, 0x22, 0xbd, 0xdf, 0xa9, - 0x13, 0x96, 0x03, 0xff, 0xf0, 0xf5, 0xbd, 0xaf, 0x21, 0xcb, 0xd3, 0x03, - 0x93, 0x97, 0xa1, 0x5f, 0x8b, 0x37, 0x60, 0x1c, 0xb0, 0x0e, 0x5f, 0xd1, - 0xb9, 0xe3, 0x73, 0x9c, 0xbd, 0xfb, 0xe8, 0xe5, 0x48, 0xf3, 0x14, 0x2f, - 0xbf, 0xff, 0x93, 0x7f, 0x31, 0x30, 0x55, 0xea, 0x63, 0x31, 0x67, 0x2f, - 0xff, 0xf9, 0x27, 0xdc, 0x33, 0x5f, 0xc7, 0xc8, 0xdc, 0x07, 0xb0, 0xc3, - 0x95, 0x88, 0xc3, 0xda, 0xd5, 0xf8, 0x1a, 0x4e, 0x5b, 0x39, 0x7f, 0xed, - 0xe7, 0x3d, 0xe6, 0x19, 0x3c, 0x1c, 0xbf, 0xff, 0xfd, 0xbd, 0xa4, 0xff, - 0x3b, 0x9e, 0x18, 0x9b, 0xb9, 0x3c, 0x73, 0xef, 0xd6, 0x72, 0xff, 0xff, - 0xe8, 0x57, 0xb1, 0xf0, 0x73, 0xf5, 0x7e, 0x73, 0x2d, 0x20, 0xa9, 0x13, - 0x9c, 0xbf, 0x73, 0xa4, 0xc1, 0x39, 0x58, 0x8a, 0x1f, 0xde, 0xa9, 0x13, - 0x42, 0xec, 0x63, 0xf7, 0xff, 0x6c, 0x79, 0xcd, 0x7f, 0x30, 0xc3, 0x0e, - 0x5f, 0xf2, 0x2b, 0xd8, 0x49, 0xe1, 0x53, 0x96, 0x92, 0x22, 0x03, 0x48, - 0xd7, 0xfc, 0x3f, 0xcc, 0x39, 0xd7, 0xf1, 0xcb, 0xfd, 0xd8, 0x6c, 0x3d, - 0x76, 0x1c, 0xbf, 0xe6, 0x66, 0xbe, 0x4c, 0x30, 0xc3, 0x94, 0x13, 0xef, - 0x61, 0xa5, 0xff, 0xff, 0x3e, 0xfb, 0x9e, 0x4c, 0x19, 0xf5, 0x18, 0x21, - 0xec, 0x1c, 0xbe, 0xf7, 0xc9, 0xf6, 0x72, 0xb9, 0x44, 0x4b, 0xb1, 0xdf, - 0xff, 0xfb, 0x9c, 0x9f, 0xfe, 0x0f, 0x9c, 0xcb, 0xd0, 0xdf, 0xcc, 0xd8, - 0x01, 0x07, 0x2f, 0xff, 0x36, 0xe3, 0x3b, 0x3f, 0x40, 0xa0, 0xa1, 0xcb, - 0xfa, 0x6e, 0x65, 0xfc, 0x78, 0xe5, 0xff, 0xfd, 0x28, 0xdf, 0x32, 0xd7, - 0xce, 0xc2, 0x0b, 0xed, 0x53, 0x97, 0xf6, 0x4b, 0xc3, 0x92, 0x39, 0x7f, - 0xdd, 0x76, 0x0e, 0x75, 0xfc, 0x72, 0xfb, 0x36, 0x06, 0xce, 0x54, 0x26, - 0x2b, 0xc9, 0x8f, 0x57, 0xb4, 0x59, 0xe3, 0x7b, 0xff, 0xb3, 0xda, 0xf9, - 0xbc, 0x4e, 0xc0, 0x4e, 0x5f, 0xd9, 0xed, 0xef, 0x24, 0x72, 0x8e, 0x5f, - 0xb3, 0xa3, 0x8b, 0x39, 0x40, 0x36, 0x22, 0x17, 0x7c, 0x39, 0xaf, 0x93, - 0x1f, 0xf7, 0x97, 0xaf, 0xfb, 0x19, 0xd8, 0x4d, 0xfe, 0xd6, 0x72, 0x82, - 0xbe, 0xe7, 0x84, 0x4a, 0x95, 0x2e, 0x38, 0x3e, 0x61, 0x52, 0x85, 0x1b, - 0x85, 0x47, 0x61, 0x56, 0xe4, 0x7a, 0x79, 0xf4, 0x6b, 0xff, 0xa5, 0xf1, - 0x86, 0x1a, 0x87, 0x77, 0xfd, 0x0c, 0x1c, 0x0e, 0xd2, 0x73, 0x97, 0xfc, - 0xd8, 0xe7, 0xf8, 0xac, 0x80, 0x72, 0xa4, 0x7e, 0x78, 0x71, 0x7f, 0xe1, - 0xcf, 0x9b, 0xce, 0x8e, 0x4c, 0x72, 0xff, 0xff, 0x75, 0xc1, 0xaf, 0x83, - 0x9c, 0x47, 0x35, 0x8c, 0x85, 0x9c, 0xa1, 0x45, 0x0e, 0x8f, 0xeb, 0x85, - 0x32, 0xbc, 0xa1, 0x77, 0x29, 0x0b, 0x3c, 0xc6, 0xb0, 0xf0, 0xc2, 0xbf, - 0xb3, 0xaa, 0x0f, 0x20, 0x39, 0x7f, 0x77, 0x07, 0xc0, 0xfc, 0xe5, 0xff, - 0x90, 0x21, 0x80, 0x7c, 0xce, 0x7c, 0x72, 0xff, 0x6b, 0x50, 0x93, 0xbf, - 0x8e, 0x5f, 0xca, 0x8e, 0x6a, 0x36, 0x72, 0xd2, 0x83, 0xe0, 0xfc, 0xce, - 0xfc, 0x30, 0xc7, 0x09, 0xcb, 0xfd, 0x93, 0x77, 0x3d, 0x01, 0x39, 0x7f, - 0x0f, 0x9d, 0x89, 0xe3, 0x96, 0x91, 0xca, 0x83, 0x7b, 0xe2, 0xcb, 0xc2, - 0xb8, 0x39, 0x7f, 0xff, 0xfd, 0xdc, 0xf6, 0x9e, 0x6f, 0x83, 0x9c, 0xcb, - 0x3f, 0x9c, 0x70, 0x3d, 0x49, 0x8e, 0x5d, 0xfa, 0xa7, 0x29, 0x11, 0x6d, - 0xb1, 0xbf, 0x42, 0x0a, 0xff, 0x01, 0x3d, 0xef, 0x63, 0x67, 0x2f, 0xec, - 0x9c, 0x73, 0x9d, 0x1c, 0xbf, 0xf8, 0x40, 0xd3, 0x3a, 0x90, 0xc7, 0x09, - 0xcb, 0xff, 0xff, 0xf4, 0xb5, 0xaf, 0xe3, 0xc8, 0x1c, 0x19, 0xbe, 0x0e, - 0x6e, 0x07, 0xdd, 0xce, 0x03, 0x97, 0xff, 0x73, 0x2d, 0x63, 0x39, 0x8e, - 0xf6, 0x0e, 0x57, 0x28, 0xcd, 0xdc, 0x21, 0xed, 0xa3, 0x95, 0x89, 0xa5, - 0xff, 0x18, 0x8a, 0x85, 0x36, 0x9c, 0xe5, 0xfb, 0x79, 0xcc, 0xb4, 0x72, - 0xf2, 0xfb, 0x87, 0x2d, 0x93, 0x9e, 0x2e, 0xca, 0x6e, 0x99, 0x0e, 0x56, - 0x22, 0x58, 0x55, 0xf8, 0x94, 0x5f, 0xd9, 0xcc, 0xa0, 0x10, 0x72, 0xfc, - 0x39, 0xd7, 0xf1, 0xca, 0xe4, 0xf4, 0xd8, 0x5b, 0x7c, 0x9c, 0x73, 0x67, - 0x2a, 0x0f, 0x1b, 0xa4, 0x77, 0xdf, 0x17, 0x3b, 0x67, 0x2f, 0xd3, 0xfc, - 0xfe, 0x26, 0x39, 0x7f, 0xff, 0xc3, 0x00, 0xe6, 0x5a, 0xfe, 0x3c, 0x38, - 0x14, 0xcd, 0xcc, 0x72, 0x9d, 0x12, 0x9e, 0x2d, 0xa8, 0x5f, 0x08, 0x09, - 0x7e, 0x17, 0x73, 0x0a, 0x14, 0x28, 0x98, 0x9b, 0xae, 0x0f, 0x0d, 0x60, - 0x1a, 0x09, 0xa6, 0xa3, 0x79, 0xf4, 0x33, 0xbf, 0x86, 0x4f, 0x12, 0x15, - 0x21, 0x77, 0x7e, 0x92, 0x6f, 0x39, 0x39, 0x7b, 0x5d, 0xc3, 0x97, 0xec, - 0xd4, 0xf8, 0xd9, 0xca, 0xe4, 0xfb, 0x66, 0x28, 0xe8, 0xe5, 0xff, 0xff, - 0x47, 0xb5, 0xdc, 0xe7, 0x1f, 0x9f, 0x81, 0x89, 0xfe, 0x2a, 0xa9, 0xcb, - 0xff, 0xe9, 0xf1, 0x61, 0xea, 0x62, 0xbf, 0x15, 0xfe, 0x0e, 0x5f, 0xfd, - 0x24, 0xf7, 0x73, 0x7b, 0xcf, 0x68, 0xe5, 0xff, 0x7c, 0x53, 0xc9, 0xc6, - 0x05, 0x67, 0x29, 0x11, 0xad, 0x32, 0xaf, 0x51, 0x2f, 0xff, 0x47, 0x32, - 0xd7, 0x9e, 0x7e, 0x01, 0xce, 0x4e, 0x5f, 0xf7, 0x67, 0x4c, 0x1e, 0x65, - 0xa3, 0x97, 0xfd, 0xcf, 0x71, 0x63, 0x9f, 0xb5, 0x9c, 0xbf, 0xfe, 0x6f, - 0x17, 0xac, 0xf4, 0xd8, 0xa8, 0xe0, 0x0e, 0x5a, 0x50, 0x8c, 0x8c, 0x3a, - 0x43, 0xdb, 0xf9, 0x39, 0x06, 0xdc, 0x27, 0x2f, 0x66, 0xc0, 0x72, 0xfd, - 0xa4, 0xc1, 0x01, 0xcb, 0x62, 0x1e, 0x16, 0x87, 0x2f, 0xc8, 0x00, 0x66, - 0xce, 0x57, 0x51, 0x7a, 0x2e, 0x1a, 0x26, 0xbe, 0xe0, 0xf6, 0x74, 0xe5, - 0xc8, 0xc3, 0x97, 0xff, 0xfe, 0xe6, 0x4f, 0xcf, 0xc1, 0xff, 0x83, 0xe6, - 0x73, 0x2c, 0xfc, 0x41, 0xa3, 0x94, 0xc4, 0x47, 0x70, 0x0b, 0x5e, 0x68, - 0x9c, 0x39, 0xca, 0xf8, 0x99, 0x5c, 0xe5, 0xf9, 0x0b, 0x36, 0x84, 0xd7, - 0xff, 0xff, 0xdc, 0xeb, 0xf8, 0xe7, 0xe7, 0x70, 0x3f, 0x07, 0x3f, 0x57, - 0xe6, 0x80, 0x04, 0xf1, 0xcb, 0xff, 0xff, 0xcd, 0x8e, 0x05, 0x8c, 0x8f, - 0x6b, 0x3d, 0xad, 0xa6, 0x2c, 0x70, 0x27, 0x2a, 0x11, 0xff, 0x90, 0x89, - 0xbf, 0x40, 0xf2, 0xf3, 0x9c, 0xbf, 0xff, 0xff, 0xf6, 0x2e, 0x3b, 0x0c, - 0xf6, 0x6b, 0x51, 0xbd, 0xc0, 0xe4, 0xf9, 0xfe, 0xbf, 0x98, 0x61, 0x87, - 0x2f, 0x7f, 0xb5, 0x4e, 0x53, 0x11, 0x72, 0xd2, 0x13, 0x57, 0xe7, 0x02, - 0x8f, 0x39, 0xca, 0xc3, 0xd3, 0x42, 0xab, 0xc8, 0x08, 0x39, 0x7f, 0x04, - 0x73, 0xaf, 0xe3, 0x97, 0xef, 0x73, 0x24, 0xd9, 0xca, 0xc3, 0xd5, 0xd1, - 0x65, 0x4e, 0x89, 0x10, 0x38, 0x5e, 0xdb, 0xa8, 0x72, 0xfd, 0x1e, 0x62, - 0x78, 0xe5, 0xa7, 0x73, 0xc4, 0xfc, 0x76, 0xff, 0xd0, 0xaf, 0x07, 0xf8, - 0x33, 0x28, 0xc3, 0x95, 0x87, 0xdd, 0xc9, 0x4d, 0xff, 0xb3, 0x01, 0xaf, - 0x9b, 0xd0, 0x74, 0x72, 0xff, 0x6f, 0x17, 0xd4, 0xdc, 0xc7, 0x2d, 0xe0, - 0x9f, 0xae, 0x20, 0xdf, 0xec, 0x5a, 0x7b, 0x7f, 0xb0, 0xe5, 0x61, 0xed, - 0xa1, 0x3d, 0xe4, 0x1f, 0x1c, 0xbf, 0xa5, 0xa7, 0x67, 0xfa, 0x39, 0x53, - 0x9e, 0x53, 0x8d, 0xdf, 0xb3, 0xbd, 0x79, 0x1c, 0xbf, 0xbc, 0x9b, 0x9f, - 0x16, 0x72, 0xa1, 0x95, 0xa4, 0x13, 0x1c, 0x8d, 0x15, 0x53, 0x0e, 0x63, - 0x17, 0x49, 0x43, 0x7b, 0x8d, 0x19, 0x84, 0xdd, 0x8c, 0xd1, 0xe1, 0x62, - 0x30, 0xd6, 0xd4, 0x3c, 0xbf, 0x6a, 0x68, 0x45, 0xc0, 0x4f, 0x79, 0xd7, - 0x87, 0x2f, 0xfd, 0x37, 0xcf, 0x0e, 0x37, 0x89, 0xa3, 0x95, 0xc3, 0x1e, - 0xe4, 0x0d, 0xd1, 0xcb, 0xfb, 0x19, 0x1d, 0x7e, 0x9c, 0xbb, 0xe4, 0xc7, - 0x2b, 0xe1, 0xe3, 0x04, 0xb2, 0xff, 0xfb, 0x99, 0x0c, 0x7c, 0x60, 0xc2, - 0xbe, 0x49, 0xce, 0x54, 0x23, 0x23, 0x14, 0x50, 0x92, 0xfd, 0xbf, 0x83, - 0xc5, 0xb3, 0x97, 0xdd, 0x70, 0x41, 0xcb, 0xdd, 0xcd, 0x9c, 0xa8, 0x3e, - 0xa7, 0x2d, 0xe0, 0x21, 0xbf, 0xa7, 0x9a, 0x5c, 0x36, 0xe7, 0x39, 0x7e, - 0x62, 0x07, 0x02, 0x72, 0xd3, 0x1c, 0xba, 0x18, 0x72, 0xde, 0x39, 0x5b, - 0x34, 0xee, 0x2d, 0x41, 0x3d, 0x9e, 0x9c, 0xde, 0xdc, 0x4c, 0x72, 0xf6, - 0x9f, 0x93, 0x94, 0xe6, 0xeb, 0xc3, 0xb7, 0x4c, 0xe7, 0x2f, 0xe7, 0x6e, - 0x3d, 0x93, 0x9c, 0xbf, 0x93, 0x7c, 0xc8, 0x60, 0xe5, 0xfe, 0x0f, 0x63, - 0x99, 0x67, 0x8e, 0x57, 0x4f, 0x87, 0xc5, 0xb7, 0xfe, 0x69, 0x03, 0xed, - 0xa7, 0x1c, 0x09, 0xcb, 0x86, 0x63, 0x94, 0xd5, 0x2a, 0x53, 0x83, 0x7c, - 0x84, 0x02, 0x2e, 0x30, 0x80, 0x45, 0xff, 0x84, 0x7b, 0x42, 0x25, 0x10, - 0x6f, 0xf3, 0x79, 0x21, 0xfd, 0xf4, 0x72, 0xfd, 0xcb, 0x6e, 0x20, 0x39, - 0x70, 0xaa, 0x72, 0xda, 0x43, 0xc0, 0xfc, 0xa6, 0xff, 0xfc, 0xc1, 0xc5, - 0xf3, 0xe1, 0x7e, 0xb2, 0x33, 0xc7, 0x2f, 0xff, 0xb2, 0x77, 0x15, 0xfc, - 0xd4, 0x31, 0xf9, 0xf1, 0xca, 0x84, 0x53, 0x6d, 0x52, 0xff, 0xff, 0xf9, - 0x3b, 0xfb, 0x18, 0xf2, 0xf9, 0xc0, 0x38, 0xc8, 0x5f, 0xc5, 0x27, 0x9d, - 0xf9, 0x39, 0x7f, 0xfe, 0x8d, 0xc2, 0xf1, 0x90, 0xb9, 0x26, 0xbf, 0x61, - 0xca, 0x85, 0x48, 0x53, 0x3a, 0x76, 0x19, 0xde, 0x22, 0x69, 0x08, 0x9b, - 0xfb, 0x79, 0x0a, 0xc0, 0x9c, 0xbc, 0x2e, 0xc3, 0x97, 0x02, 0x0e, 0x5e, - 0x15, 0x27, 0x39, 0x52, 0x3f, 0xb4, 0x2c, 0x11, 0xbf, 0x0b, 0x53, 0x54, - 0xff, 0x75, 0x0d, 0x41, 0x67, 0x08, 0xac, 0xd5, 0xc2, 0x33, 0x86, 0x8f, - 0xe7, 0x85, 0xd6, 0xa2, 0x72, 0x0e, 0x78, 0xef, 0xe5, 0x08, 0x40, 0xcf, - 0x06, 0x65, 0x3a, 0xa5, 0x59, 0x50, 0x6b, 0x9e, 0xaa, 0xe6, 0x73, 0xa5, - 0x25, 0x47, 0x4d, 0x29, 0xf7, 0x73, 0xac, 0x4c, 0x97, 0x83, 0xda, 0xc9, - 0xd5, 0xe5, 0xb8, 0x82, 0x51, 0x5f, 0x0e, 0xe2, 0x34, 0xb2, 0x7d, 0x4f, - 0xb7, 0x7a, 0x98, 0x5d, 0xfc, 0x6b, 0xbc, 0x61, 0xdc, 0xdc, 0x25, 0xda, - 0x4a, 0x83, 0x52, 0x56, 0x8f, 0x04, 0x34, 0xef, 0xff, 0xef, 0xd7, 0xf7, - 0x9f, 0x6e, 0x33, 0x9e, 0x18, 0x2e, 0xea, 0x9c, 0xaf, 0xaa, 0xbb, 0xd2, - 0x54, 0x4d, 0xfc, 0xe9, 0xed, 0x20, 0x9c, 0xbc, 0x9b, 0xc3, 0x94, 0xd6, - 0x78, 0xda, 0x2b, 0xbf, 0x6d, 0x6e, 0xeb, 0x34, 0x53, 0xab, 0xb3, 0x93, - 0x97, 0xff, 0xbf, 0xfc, 0x50, 0x63, 0xa8, 0xcc, 0xd1, 0xcb, 0x7d, 0x84, - 0x5c, 0xe1, 0x2f, 0x26, 0x8c, 0x17, 0xbf, 0xf9, 0x37, 0xf5, 0xa3, 0xcf, - 0xed, 0x38, 0x0e, 0x5f, 0xb6, 0xb7, 0x75, 0x9a, 0x2a, 0x35, 0xff, 0x9e, - 0x5f, 0x73, 0x6b, 0x77, 0x59, 0xa2, 0x68, 0x5f, 0x0c, 0x67, 0x27, 0x2b, - 0x11, 0x42, 0xc3, 0x4f, 0x26, 0x5f, 0xe5, 0x1f, 0x8f, 0xdf, 0x24, 0xe7, - 0x2b, 0xe9, 0xf4, 0x41, 0x7d, 0xfb, 0x6b, 0x77, 0x59, 0xa2, 0xaf, 0x5f, - 0xd9, 0xc6, 0x07, 0xbf, 0x9c, 0xbf, 0x90, 0x21, 0x8d, 0xc1, 0xcb, 0xff, - 0xfb, 0x90, 0x0f, 0xec, 0x50, 0x21, 0x80, 0x32, 0x33, 0xc7, 0x2d, 0xf7, - 0x11, 0xdb, 0xb3, 0x4e, 0x97, 0xa8, 0x59, 0x7e, 0xda, 0xdd, 0xd6, 0x68, - 0xad, 0x97, 0xfd, 0x2f, 0xb9, 0xb5, 0xbb, 0xac, 0xd1, 0x20, 0xad, 0xf7, - 0x0f, 0xed, 0xcd, 0x2f, 0xfe, 0xfa, 0xf2, 0xfb, 0x9b, 0x5b, 0xba, 0xcd, - 0x12, 0x1a, 0xff, 0xda, 0xfb, 0x9e, 0x40, 0xe0, 0xcc, 0x72, 0xf3, 0xba, - 0xcf, 0x18, 0x1a, 0xa0, 0xfa, 0x16, 0x81, 0x77, 0x5a, 0xce, 0x5f, 0xfa, - 0x5d, 0x8f, 0x69, 0xa8, 0xd3, 0x56, 0x27, 0x2f, 0xbd, 0xec, 0xe0, 0x39, - 0x7f, 0xfb, 0x85, 0xb8, 0x59, 0xa8, 0xec, 0x30, 0x5f, 0xa9, 0xb3, 0x96, - 0xe4, 0xe5, 0xc8, 0x27, 0x2f, 0xe8, 0x0c, 0x79, 0xc2, 0x72, 0x82, 0x7a, - 0x73, 0x09, 0x78, 0x56, 0xfb, 0xda, 0x4e, 0x27, 0x2f, 0xfe, 0x41, 0x9e, - 0x15, 0x50, 0x00, 0x8e, 0x4e, 0x5f, 0x60, 0x83, 0x47, 0x2f, 0xa7, 0xd7, - 0x28, 0x72, 0xb0, 0xf1, 0x74, 0x43, 0x7e, 0x70, 0xa9, 0x02, 0x72, 0xff, - 0xdb, 0xf2, 0x82, 0xeb, 0xc1, 0x59, 0xcb, 0xe5, 0xbb, 0xac, 0xd1, 0x62, - 0x2f, 0xdb, 0xdb, 0x8f, 0x8e, 0x5e, 0x44, 0x6c, 0xe5, 0xef, 0xc6, 0x47, - 0x2f, 0xf2, 0xe3, 0x36, 0x00, 0x78, 0xe5, 0x4e, 0x99, 0x36, 0x13, 0xec, - 0xf9, 0x85, 0xc2, 0x4f, 0xe1, 0xcf, 0xc7, 0x6f, 0xd9, 0xb8, 0x15, 0x4e, - 0x59, 0x0e, 0x59, 0x0e, 0x5a, 0x4a, 0x9a, 0x00, 0x08, 0x5f, 0x94, 0x69, - 0x9b, 0x83, 0x97, 0xb5, 0x02, 0x72, 0xa0, 0xf1, 0x50, 0xaa, 0x95, 0x44, - 0x6f, 0x5b, 0x6f, 0xfe, 0x8c, 0xd6, 0x08, 0x50, 0x10, 0x27, 0x2f, 0x0c, - 0x4e, 0x72, 0x84, 0xf7, 0x3f, 0x40, 0xbe, 0x8d, 0xc3, 0x0e, 0x54, 0x8f, - 0x0f, 0x44, 0x57, 0x98, 0xfe, 0x39, 0x7f, 0xfd, 0xec, 0xe6, 0x43, 0xff, - 0x9d, 0x06, 0x02, 0x72, 0xe4, 0x01, 0xca, 0xda, 0x20, 0x7c, 0x38, 0xd1, - 0x3e, 0xfb, 0x8f, 0xef, 0xa3, 0x96, 0x43, 0x94, 0x86, 0xd6, 0x62, 0x5b, - 0xfe, 0x0f, 0x71, 0x98, 0xfb, 0x9c, 0xe5, 0xfb, 0xde, 0x79, 0x68, 0xe5, - 0xff, 0xbf, 0xce, 0x43, 0xc7, 0xb8, 0xf3, 0x1c, 0xae, 0x4f, 0xaf, 0x89, - 0x45, 0xa4, 0x72, 0xfb, 0x31, 0xbd, 0x1c, 0xa8, 0x36, 0x7e, 0x11, 0xbb, - 0xf1, 0x39, 0x50, 0x99, 0x9e, 0x42, 0x93, 0x6b, 0x1a, 0x20, 0xbf, 0xda, - 0x53, 0x37, 0x99, 0x31, 0xcb, 0xf0, 0xf8, 0x7f, 0x9c, 0xe5, 0x41, 0xee, - 0xfe, 0x69, 0x7f, 0x6e, 0x40, 0xcc, 0x98, 0xe5, 0xf3, 0xc2, 0x34, 0x39, - 0x58, 0x7a, 0x1b, 0x2e, 0xbe, 0x92, 0x9d, 0x83, 0x97, 0xb7, 0x12, 0x39, - 0x4e, 0x6f, 0xf8, 0x91, 0xdf, 0xd0, 0xcc, 0x4d, 0xcc, 0x72, 0xf9, 0x48, - 0xe0, 0xd1, 0xcb, 0xf6, 0x07, 0xb1, 0xd3, 0x97, 0xdb, 0x46, 0xda, 0xce, - 0x50, 0x9e, 0x6e, 0x89, 0xe8, 0x28, 0x94, 0xd3, 0x9d, 0x42, 0x6c, 0xc8, - 0xc1, 0xd2, 0x27, 0x86, 0x0d, 0xfc, 0x82, 0xec, 0x8e, 0x9c, 0xbf, 0xfd, - 0x0c, 0x89, 0x04, 0x63, 0xaf, 0x9b, 0x39, 0x47, 0x2a, 0x47, 0xa4, 0xd1, - 0x1e, 0xf7, 0xb0, 0x07, 0x2f, 0xe6, 0x26, 0xb4, 0x81, 0x39, 0x79, 0xf6, - 0xa9, 0xca, 0xfc, 0xf2, 0x9b, 0x2d, 0xbf, 0xcb, 0x1c, 0xe2, 0x39, 0xa3, - 0x97, 0xf9, 0xaf, 0xe2, 0x90, 0x2e, 0xa9, 0xcb, 0xfd, 0x27, 0xc1, 0xcf, - 0x68, 0xe5, 0x61, 0xf5, 0x72, 0x73, 0x7f, 0xec, 0xe6, 0x5d, 0x8d, 0x2b, - 0xd8, 0x39, 0x52, 0x54, 0x55, 0xcb, 0xec, 0xc4, 0x9b, 0x66, 0xe9, 0x20, - 0xc2, 0x77, 0x80, 0x8a, 0xcd, 0x0e, 0x5d, 0x2d, 0x1c, 0xb3, 0xc8, 0xd5, - 0x72, 0x27, 0x7d, 0xe4, 0x16, 0xca, 0x5b, 0xf3, 0x96, 0x8c, 0x36, 0x9d, - 0x22, 0xbf, 0xe7, 0x1f, 0x6b, 0x9d, 0x3b, 0x59, 0xca, 0x74, 0x5e, 0x01, - 0x6f, 0xf2, 0x5b, 0xfb, 0xa9, 0xad, 0xef, 0x0e, 0x5f, 0xf9, 0x33, 0xda, - 0xde, 0x6a, 0x39, 0x39, 0x7f, 0xe8, 0x6d, 0x49, 0xf5, 0x8c, 0x86, 0xb3, - 0x97, 0x3b, 0x67, 0x29, 0x68, 0xc6, 0xe9, 0x6f, 0x8f, 0xb8, 0xa2, 0x5d, - 0x9a, 0x39, 0x58, 0x7a, 0xaa, 0x1f, 0xdf, 0xfd, 0xd7, 0x4f, 0x4b, 0x15, - 0x1c, 0x01, 0xcb, 0xf0, 0xcd, 0x1d, 0x83, 0x97, 0xe0, 0x3f, 0x1c, 0x09, - 0xcb, 0xf6, 0x77, 0x97, 0x6b, 0x39, 0x7c, 0x0d, 0x40, 0x9c, 0xbf, 0xdb, - 0xeb, 0xa6, 0x93, 0x89, 0xcb, 0x95, 0x43, 0x95, 0x07, 0xd9, 0x84, 0x2e, - 0x69, 0x7f, 0xf7, 0x70, 0x45, 0xfd, 0xf2, 0x50, 0xc3, 0x94, 0x89, 0xcd, - 0x3a, 0x18, 0x09, 0xc4, 0xa7, 0x50, 0x97, 0xf1, 0x65, 0xfc, 0xdc, 0x6f, - 0x6f, 0x31, 0xcb, 0xfe, 0x0c, 0x2d, 0x40, 0x02, 0x39, 0x39, 0x7f, 0xcf, - 0xbc, 0x62, 0x34, 0x86, 0x1c, 0xa5, 0x9f, 0xa7, 0xe7, 0x77, 0xde, 0x8e, - 0x64, 0x72, 0xfe, 0x40, 0x34, 0x14, 0x01, 0xca, 0x9c, 0xf4, 0x76, 0x47, - 0x7b, 0xd8, 0xa1, 0xca, 0x84, 0xd5, 0xf2, 0x14, 0x6e, 0xe9, 0xc0, 0x47, - 0x7f, 0x0c, 0x4a, 0x38, 0xc1, 0xcb, 0xa0, 0x07, 0x2f, 0xee, 0x3b, 0x78, - 0x46, 0x87, 0x2d, 0x87, 0x29, 0x11, 0x07, 0x31, 0x6b, 0x05, 0x84, 0xc2, - 0xfa, 0x7f, 0x62, 0xce, 0x5f, 0xe7, 0x55, 0x4e, 0xf6, 0x24, 0x72, 0x9c, - 0xf6, 0x1a, 0x11, 0xdf, 0xfb, 0xb8, 0x10, 0xa7, 0x39, 0xcf, 0x8e, 0x5f, - 0xdf, 0x02, 0xa3, 0xef, 0x67, 0x2a, 0x73, 0xf1, 0x0a, 0x05, 0xf3, 0xc2, - 0x34, 0x39, 0x7f, 0xec, 0x0f, 0xcc, 0xd4, 0x66, 0xc0, 0x72, 0xff, 0x20, - 0x7c, 0x2f, 0xce, 0x8e, 0x5f, 0xef, 0x69, 0x39, 0xce, 0x7c, 0x72, 0xa0, - 0xfa, 0x1c, 0xce, 0xa1, 0x30, 0xc0, 0x91, 0xf4, 0x88, 0x61, 0x4f, 0x4d, - 0x43, 0x6b, 0xc0, 0xd5, 0x8d, 0x70, 0xc9, 0x2d, 0x48, 0x96, 0x21, 0x5f, - 0x39, 0x84, 0x89, 0x03, 0x08, 0xcc, 0x8d, 0x1d, 0x56, 0x55, 0xc3, 0x53, - 0x98, 0x61, 0xa4, 0x28, 0xe6, 0x67, 0xdc, 0x6a, 0x8c, 0x84, 0xf7, 0x63, - 0xd8, 0x79, 0x4d, 0x40, 0x8d, 0x54, 0x63, 0x4b, 0xd4, 0x77, 0x9e, 0x8e, - 0xc7, 0xf8, 0x63, 0x34, 0x84, 0xa2, 0x91, 0xd0, 0x5f, 0xb8, 0x1d, 0x71, - 0xb3, 0x97, 0xfe, 0x48, 0xf7, 0x5d, 0x5c, 0x10, 0x1c, 0xbf, 0xfc, 0xfb, - 0xf8, 0xfe, 0xf9, 0xee, 0x56, 0x82, 0x72, 0xba, 0x88, 0xbe, 0x27, 0xb7, - 0xf6, 0x7a, 0x11, 0x9a, 0x39, 0x7f, 0x83, 0x12, 0xcd, 0xe6, 0x8e, 0x5e, - 0xd2, 0x9a, 0x39, 0x7f, 0xfd, 0x9c, 0xcb, 0xdf, 0xcf, 0xf7, 0xae, 0xc4, - 0xd1, 0xcb, 0xfe, 0xfd, 0xf0, 0x29, 0xc8, 0xb9, 0xcb, 0xde, 0x18, 0x39, - 0x77, 0x7e, 0xc2, 0x7f, 0xd9, 0x0b, 0x59, 0x89, 0x58, 0x58, 0xe6, 0x42, - 0x3d, 0xa5, 0x55, 0x0e, 0x2b, 0xea, 0xe2, 0x5c, 0x4b, 0xc8, 0xbf, 0xb3, - 0x6b, 0x77, 0x59, 0xa2, 0xcd, 0x5f, 0xfd, 0xbe, 0xbf, 0xd6, 0x7f, 0x37, - 0x50, 0x27, 0x2f, 0xfd, 0x1b, 0x07, 0xb5, 0xdc, 0x40, 0x9c, 0xbf, 0x64, - 0xd2, 0x8e, 0x4e, 0x5f, 0x20, 0xbc, 0xe7, 0x2b, 0xa8, 0x88, 0x13, 0xed, - 0x14, 0xdf, 0x7d, 0xec, 0x74, 0xe5, 0x7d, 0x3d, 0x3e, 0x02, 0xfa, 0xfa, - 0x9c, 0x22, 0x1c, 0xbc, 0x64, 0x97, 0xc8, 0xc5, 0x36, 0x72, 0xf9, 0x07, - 0x7f, 0x9c, 0xbf, 0xd1, 0xc5, 0x4f, 0x0c, 0x00, 0xe5, 0xcc, 0xfb, 0x07, - 0xf5, 0x31, 0x1f, 0x48, 0xae, 0xc4, 0x39, 0x76, 0x04, 0xe5, 0xff, 0x9e, - 0x5f, 0x73, 0x6b, 0x77, 0x59, 0xa2, 0x80, 0x5f, 0xe4, 0x64, 0x35, 0xf7, - 0x27, 0x39, 0x6f, 0xb2, 0x45, 0x6e, 0x0a, 0xb0, 0x5b, 0xa9, 0x97, 0xcf, - 0xbe, 0x64, 0x72, 0xfd, 0xed, 0x49, 0x00, 0x72, 0xb0, 0xf2, 0xdc, 0x8e, - 0xfe, 0x97, 0xdc, 0x9a, 0x24, 0x72, 0xbe, 0x9e, 0x84, 0x10, 0x5d, 0xff, - 0x4e, 0x5f, 0xda, 0x86, 0x0c, 0x4c, 0x72, 0xdd, 0x39, 0x79, 0x41, 0x98, - 0xe5, 0xd9, 0xec, 0x35, 0xe0, 0x11, 0xa0, 0x22, 0x1c, 0x57, 0x2e, 0xf9, - 0xa3, 0x97, 0xbf, 0x0e, 0x1c, 0xbf, 0xd9, 0xbf, 0x0c, 0x33, 0x47, 0x2c, - 0xd0, 0xe5, 0x21, 0xf1, 0x74, 0x74, 0x06, 0x57, 0xcb, 0x77, 0x59, 0xa2, - 0xdf, 0x5e, 0x68, 0xfe, 0x39, 0x7f, 0x29, 0xe7, 0x5b, 0xec, 0xe5, 0x6c, - 0xfe, 0x98, 0x5c, 0x01, 0xeb, 0x95, 0x6c, 0xe5, 0xf6, 0x0a, 0x4c, 0x72, - 0xf7, 0x63, 0x67, 0x2f, 0xdd, 0x4d, 0xf5, 0xce, 0x5f, 0xfe, 0xec, 0x4f, - 0xec, 0xe8, 0xe7, 0xba, 0x87, 0x2f, 0x33, 0x02, 0x72, 0xcc, 0x39, 0x7f, - 0xdd, 0x89, 0xc3, 0x8d, 0xeb, 0xec, 0x22, 0xe7, 0x07, 0x26, 0x27, 0x74, - 0x95, 0x07, 0x2f, 0xde, 0x96, 0x94, 0xd1, 0xcb, 0xda, 0xe8, 0x4e, 0x5f, - 0x94, 0xf0, 0xc0, 0x0e, 0x53, 0x0f, 0x17, 0x88, 0xed, 0xff, 0xde, 0xd2, - 0x6a, 0x07, 0x3d, 0xd4, 0x39, 0x78, 0x73, 0xa7, 0x29, 0x87, 0xbb, 0xc5, - 0x0a, 0xfc, 0x18, 0x6b, 0xfd, 0x87, 0x2f, 0xf9, 0xf5, 0x18, 0x21, 0xec, - 0x1c, 0xbf, 0xfb, 0x19, 0xbc, 0xe7, 0xa2, 0xed, 0x73, 0x9c, 0xbb, 0x5a, - 0xd9, 0xff, 0x09, 0xb5, 0x42, 0x6f, 0x99, 0x08, 0x14, 0x24, 0x78, 0x55, - 0x5f, 0x3a, 0x0f, 0x8e, 0x5f, 0x81, 0xaf, 0x43, 0x0e, 0x5e, 0xdc, 0x78, - 0xe5, 0xfd, 0x33, 0x87, 0xa8, 0xc3, 0x97, 0xf7, 0x93, 0x03, 0x0c, 0x39, - 0x5e, 0x3d, 0xa6, 0xcb, 0xae, 0xd0, 0x9c, 0xbf, 0xb9, 0xd4, 0x2f, 0x18, - 0x72, 0xa1, 0x30, 0x5d, 0x94, 0x3b, 0xb6, 0x88, 0xff, 0x16, 0xbf, 0x92, - 0x68, 0x11, 0x83, 0x97, 0xdd, 0x54, 0x2c, 0x39, 0x69, 0x1c, 0xbf, 0xc0, - 0x07, 0xfa, 0x6b, 0xce, 0x4e, 0x56, 0x1e, 0x53, 0x88, 0xd6, 0x22, 0x38, - 0x5b, 0xa9, 0xab, 0x5f, 0xf9, 0x88, 0x4f, 0xc8, 0x88, 0x2f, 0x79, 0x0a, - 0x8e, 0x4b, 0xd0, 0x66, 0x68, 0x6d, 0x6d, 0xef, 0xb1, 0xf5, 0x81, 0x10, - 0x63, 0x25, 0xd2, 0x57, 0xa1, 0x73, 0x7f, 0x3f, 0x3f, 0x58, 0xfe, 0x39, - 0x5f, 0x53, 0x15, 0x18, 0x72, 0xdf, 0xc1, 0xfb, 0xaf, 0x6b, 0x93, 0x97, - 0x35, 0x4d, 0x59, 0xcb, 0xcc, 0x7e, 0x4e, 0x5e, 0x03, 0xf4, 0xe5, 0xdc, - 0x50, 0xe5, 0xf6, 0xf7, 0x8a, 0x1c, 0xbf, 0x6a, 0x7c, 0x6f, 0xeb, 0x50, - 0x89, 0x58, 0x21, 0xc1, 0xd9, 0x87, 0x1c, 0x62, 0xa1, 0x33, 0x54, 0x86, - 0x3d, 0xff, 0xff, 0x70, 0xe9, 0xef, 0xde, 0x7f, 0xb9, 0x2e, 0xc6, 0xf3, - 0x05, 0x53, 0x97, 0xff, 0xff, 0x91, 0x6f, 0xb7, 0xec, 0xb3, 0xd8, 0x1d, - 0x3b, 0x33, 0x73, 0xc7, 0x27, 0x2f, 0xdb, 0x5b, 0xba, 0xcd, 0x14, 0xa2, - 0xff, 0xf9, 0xfc, 0x39, 0x3e, 0xe3, 0xa9, 0xdc, 0xd9, 0xcb, 0xcf, 0x2f, - 0xb0, 0x8f, 0x9c, 0x77, 0x01, 0xa5, 0xff, 0x4b, 0xee, 0x6d, 0x6e, 0xeb, - 0x34, 0x49, 0xcb, 0x7d, 0x62, 0x22, 0x1d, 0x06, 0xa2, 0x16, 0xe1, 0x93, - 0xce, 0xba, 0x4a, 0x3b, 0x50, 0xdf, 0xf9, 0x2e, 0x46, 0x58, 0xaa, 0x22, - 0xe3, 0x52, 0x48, 0xc4, 0x1a, 0xe1, 0x81, 0x31, 0x46, 0xe1, 0x78, 0xca, - 0xe9, 0x33, 0xb1, 0xd9, 0x3c, 0x2c, 0x41, 0x0e, 0xa1, 0x86, 0xfe, 0xa9, - 0x26, 0x3e, 0x8d, 0x7f, 0xf2, 0x7e, 0x31, 0xf7, 0xdf, 0xb6, 0xb7, 0x75, - 0x9a, 0x21, 0xf5, 0xff, 0x9e, 0x5f, 0x73, 0x6b, 0x77, 0x59, 0xa2, 0x53, - 0x5b, 0xee, 0x22, 0x01, 0x86, 0x97, 0xfb, 0xee, 0x6d, 0x6e, 0xeb, 0x34, - 0x44, 0xeb, 0xf2, 0x7b, 0x5f, 0xb0, 0xe5, 0xee, 0xc4, 0xc7, 0x2a, 0x63, - 0xc6, 0xe9, 0x4d, 0xff, 0xee, 0x14, 0xab, 0x6d, 0x73, 0x87, 0x86, 0xf9, - 0xf3, 0xad, 0x0e, 0x5f, 0xb6, 0xb7, 0x75, 0x9a, 0x23, 0x15, 0xff, 0xfd, - 0xf8, 0xba, 0xbf, 0x3c, 0xac, 0x0c, 0xb3, 0xa8, 0xc3, 0x97, 0xd0, 0xc5, - 0x80, 0xe5, 0xff, 0xf4, 0xa7, 0xe1, 0x50, 0xd5, 0xce, 0xbd, 0xfc, 0xf9, - 0xd6, 0x87, 0x2b, 0xa8, 0x87, 0x01, 0x15, 0xfd, 0x9e, 0x8c, 0xe7, 0xc7, - 0x2f, 0xfd, 0xe5, 0x60, 0x65, 0x9d, 0x46, 0x1c, 0xbf, 0xe5, 0x60, 0x65, - 0x9d, 0x46, 0x1c, 0xbf, 0x33, 0xf1, 0x75, 0x7e, 0x1f, 0xb7, 0x8f, 0xaf, - 0x93, 0x99, 0x35, 0x67, 0x2f, 0xdf, 0x26, 0x18, 0x09, 0xcb, 0x7d, 0x85, - 0x5f, 0x52, 0x23, 0xc6, 0x46, 0x1a, 0x76, 0x1c, 0xa2, 0x47, 0xa8, 0x51, - 0xf9, 0x09, 0xa1, 0x45, 0xff, 0xef, 0xac, 0x79, 0x7d, 0xcd, 0xad, 0xdd, - 0x66, 0x89, 0xe5, 0x7d, 0x1c, 0x63, 0xa7, 0x2f, 0xa0, 0x65, 0xa3, 0x97, - 0xee, 0xa0, 0xe7, 0x13, 0x95, 0xb3, 0xec, 0x01, 0x1a, 0x84, 0x37, 0xdf, - 0xbe, 0xe4, 0x72, 0xfc, 0xe1, 0xec, 0x68, 0xe5, 0xbe, 0x84, 0xf2, 0x84, - 0x8e, 0xbe, 0xa2, 0x8d, 0xb7, 0xaa, 0x85, 0xdc, 0xb9, 0xca, 0xa5, 0x2e, - 0x07, 0xb0, 0x91, 0xf4, 0x6d, 0x37, 0xed, 0xad, 0xdd, 0x66, 0x88, 0x81, - 0x7f, 0xe7, 0x97, 0xdc, 0xda, 0xdd, 0xd6, 0x68, 0x95, 0x17, 0xf6, 0xff, - 0xec, 0x0a, 0xce, 0x5f, 0xcb, 0x4c, 0xe0, 0xec, 0x1c, 0xa8, 0x3d, 0xdc, - 0x2e, 0xb7, 0xdc, 0x47, 0xeb, 0x0d, 0x06, 0x15, 0x37, 0xed, 0xad, 0xdd, - 0x66, 0x88, 0xa1, 0x7a, 0x01, 0x87, 0x2d, 0xf7, 0x0f, 0x3d, 0x43, 0x4b, - 0xfd, 0xf7, 0x36, 0xb7, 0x75, 0x9a, 0x23, 0x25, 0xfb, 0x6b, 0x77, 0x59, - 0xa2, 0x65, 0x5f, 0xa5, 0x9e, 0x75, 0x9c, 0xbf, 0x7d, 0x63, 0xcb, 0xee, - 0x1e, 0xdf, 0x26, 0x97, 0xed, 0xad, 0xdd, 0x66, 0x8a, 0x91, 0x61, 0x39, - 0x65, 0x0e, 0x5b, 0xee, 0x1e, 0xb3, 0x59, 0xa7, 0xe2, 0x17, 0xfb, 0xee, - 0x6d, 0x6e, 0xeb, 0x34, 0x57, 0x4b, 0xfd, 0xf7, 0x36, 0xb7, 0x75, 0x9a, - 0x2c, 0x55, 0xff, 0xcc, 0x79, 0x7d, 0xcd, 0xad, 0xdd, 0x66, 0x89, 0xe9, - 0x7f, 0x76, 0x13, 0x69, 0xc3, 0x9c, 0xbf, 0x42, 0x34, 0x4e, 0x03, 0x97, - 0x37, 0xf5, 0x67, 0xb8, 0xe6, 0x37, 0xff, 0xff, 0x83, 0x8d, 0xfd, 0x1c, - 0x55, 0x57, 0xf6, 0x90, 0x66, 0x85, 0xef, 0x39, 0x39, 0x7f, 0xfe, 0x98, - 0x61, 0x9f, 0x73, 0x48, 0xd8, 0x5d, 0xd5, 0x39, 0x76, 0xbc, 0x72, 0xec, - 0xd1, 0xcb, 0xb4, 0x03, 0x97, 0xe1, 0x76, 0x0c, 0x1c, 0xbf, 0xbf, 0xd7, - 0x5e, 0x5f, 0x5a, 0xb3, 0xe9, 0x71, 0x76, 0xc5, 0x94, 0x17, 0xbd, 0x3c, - 0x35, 0x9c, 0xbf, 0x67, 0xb4, 0x8c, 0x39, 0x7f, 0xfa, 0x39, 0xf6, 0x4c, - 0x9b, 0xf6, 0xbf, 0x6b, 0x39, 0x79, 0xf9, 0xfb, 0x08, 0x97, 0x12, 0x0f, - 0x13, 0xd6, 0x2a, 0x02, 0xdc, 0x30, 0x75, 0x0f, 0xfa, 0x0a, 0xab, 0x9f, - 0x4a, 0x7e, 0xaf, 0xaa, 0xf0, 0xe2, 0x15, 0xc9, 0x2b, 0xa6, 0xfc, 0x9d, - 0x17, 0x98, 0xe5, 0xfa, 0x58, 0x1f, 0x98, 0x72, 0xb8, 0x43, 0xd0, 0x82, - 0x7b, 0x98, 0x03, 0x97, 0xec, 0xf2, 0x7f, 0xa3, 0x97, 0x35, 0x0d, 0x48, - 0xe5, 0x35, 0x07, 0xc2, 0xd4, 0x85, 0xf8, 0x51, 0x45, 0xfb, 0x85, 0x9a, - 0x8d, 0x6f, 0xc7, 0x2f, 0xf2, 0x83, 0x9b, 0xdc, 0x2c, 0xe5, 0x35, 0x07, - 0xd1, 0xc3, 0x1a, 0xdf, 0x6d, 0x9e, 0xe4, 0xe5, 0xfc, 0xd4, 0x35, 0x5c, - 0x24, 0x49, 0x87, 0x2f, 0x2f, 0x3a, 0x52, 0xf3, 0x23, 0x47, 0x2f, 0x03, - 0x70, 0x72, 0xfe, 0xc0, 0x24, 0xc8, 0xd9, 0xcb, 0xff, 0x3e, 0xbe, 0x6b, - 0x59, 0x29, 0x41, 0xcb, 0xff, 0xf0, 0xba, 0xa9, 0xb8, 0x94, 0xb3, 0x40, - 0x04, 0x1c, 0xbf, 0xcf, 0xef, 0xf3, 0x05, 0x53, 0x94, 0x14, 0x7a, 0xaa, - 0x5d, 0xd4, 0x00, 0x2a, 0x5f, 0xff, 0xdb, 0x4e, 0x07, 0x67, 0xd8, 0xde, - 0xd3, 0x81, 0x7f, 0xce, 0x72, 0xf9, 0x3a, 0xa3, 0x0e, 0x5f, 0xfe, 0x45, - 0x7e, 0x60, 0xbf, 0x3a, 0x55, 0x57, 0x39, 0x4b, 0x3f, 0x11, 0x23, 0xbf, - 0xfc, 0xfa, 0x1c, 0x07, 0xde, 0xa2, 0xdf, 0x67, 0x2e, 0x16, 0xce, 0x5f, - 0xc1, 0xc5, 0x7d, 0x8b, 0x39, 0x7d, 0xd8, 0x62, 0xce, 0x54, 0x1f, 0x3b, - 0x8b, 0xf8, 0xba, 0xfc, 0x14, 0x99, 0x1b, 0x39, 0x7f, 0xf7, 0xc8, 0x81, - 0x86, 0x7c, 0xf9, 0xd6, 0x87, 0x2a, 0x0f, 0xd0, 0x4a, 0x6f, 0xfd, 0xdc, - 0x9b, 0xa9, 0xd8, 0xdc, 0x1c, 0xb9, 0xf9, 0x39, 0x7f, 0x9f, 0x4f, 0xdf, - 0xc6, 0x73, 0x94, 0x27, 0x97, 0xf8, 0xbd, 0x4e, 0xb8, 0xff, 0x21, 0xc4, - 0x8c, 0x47, 0x67, 0xcc, 0x86, 0xb7, 0x48, 0x46, 0x16, 0x3e, 0x85, 0x0a, - 0x84, 0x1c, 0x10, 0x89, 0xbc, 0x2f, 0xe3, 0x97, 0x85, 0x34, 0x72, 0xcd, - 0xf0, 0x86, 0xda, 0x06, 0xee, 0x8e, 0x9c, 0xbe, 0xdf, 0x17, 0x61, 0xcb, - 0xf0, 0xe7, 0xa1, 0xb3, 0x97, 0xe6, 0x0b, 0xfb, 0x47, 0x2f, 0x46, 0x6c, - 0xe5, 0xff, 0xe5, 0xbe, 0xdf, 0xc9, 0xa8, 0x18, 0x01, 0xcb, 0x4b, 0xa7, - 0xc4, 0xa0, 0xdd, 0x72, 0x8b, 0x2d, 0xc2, 0x26, 0xb1, 0x36, 0x85, 0x96, - 0x20, 0xb6, 0x89, 0x3f, 0x86, 0xcd, 0xf3, 0xa2, 0x8c, 0x39, 0x7b, 0x5c, - 0x1c, 0x07, 0x2f, 0x6f, 0x02, 0x72, 0xff, 0x3f, 0xa2, 0x6d, 0x23, 0x0e, - 0x52, 0xa7, 0x9f, 0xd1, 0xcb, 0xfd, 0x12, 0x1c, 0xe7, 0xd8, 0x72, 0xff, - 0xf9, 0x3a, 0xeb, 0x81, 0x0c, 0xd2, 0x8d, 0xce, 0x72, 0xff, 0xfb, 0xda, - 0x0e, 0xf1, 0x15, 0xeb, 0x6e, 0x33, 0x9c, 0xbe, 0x10, 0xe2, 0xa7, 0x2f, - 0x77, 0xf6, 0x1c, 0xa9, 0x27, 0x97, 0x84, 0x48, 0xe5, 0xb2, 0x3e, 0x99, - 0x69, 0x43, 0xca, 0x5f, 0x91, 0x5f, 0xde, 0xd4, 0xd0, 0x33, 0x9c, 0xbf, - 0x0a, 0xa9, 0x9a, 0x39, 0x7e, 0x6d, 0xfc, 0xeb, 0x39, 0x7f, 0xf6, 0x36, - 0xe0, 0xc5, 0xf5, 0xc1, 0xa3, 0x97, 0xfe, 0xd3, 0xf3, 0x02, 0xe1, 0xc5, - 0x4e, 0x52, 0x23, 0x47, 0xa4, 0xe2, 0x51, 0xe4, 0x4b, 0xa3, 0xa7, 0x2c, - 0x13, 0x94, 0xc3, 0x4e, 0x22, 0xd7, 0xc2, 0x1f, 0x8a, 0x9c, 0xbf, 0xb3, - 0x4d, 0xb8, 0xce, 0x72, 0xb0, 0xfc, 0xdc, 0x80, 0x49, 0x6f, 0xdb, 0xff, - 0x4e, 0xb3, 0x97, 0xca, 0xe8, 0x30, 0x72, 0xa0, 0xf3, 0x3f, 0x29, 0xbc, - 0xc4, 0xd1, 0xcb, 0xfe, 0xc1, 0x79, 0x6a, 0x4d, 0xce, 0x72, 0xfa, 0x5a, - 0x41, 0x39, 0x68, 0x91, 0xed, 0xf2, 0x75, 0x7f, 0x9f, 0x72, 0x85, 0xa2, - 0xce, 0x54, 0x2b, 0x40, 0xc8, 0xc0, 0x12, 0x1a, 0xbd, 0x78, 0x72, 0x21, - 0x77, 0xfc, 0xa2, 0xff, 0xf2, 0xaf, 0x9c, 0xfb, 0xd1, 0x9c, 0x51, 0x67, - 0x2f, 0xf0, 0xe6, 0xbc, 0xee, 0x27, 0x29, 0x53, 0xfc, 0xe2, 0x99, 0x7f, - 0xff, 0xe4, 0xde, 0xe1, 0x4f, 0x20, 0xff, 0x2c, 0xd0, 0x7f, 0x7d, 0xc8, - 0xe5, 0xff, 0xfc, 0x38, 0xae, 0x0f, 0xcd, 0x7b, 0xb8, 0xc5, 0x20, 0x07, - 0x2a, 0x11, 0x97, 0x8d, 0xd7, 0xfb, 0xf7, 0xd2, 0x4c, 0x8d, 0x9c, 0xa4, - 0x4d, 0x1b, 0xb0, 0xf0, 0x12, 0x1b, 0xdd, 0x81, 0x39, 0x7b, 0x9f, 0x30, - 0xe5, 0x2c, 0xdc, 0xb8, 0xdd, 0xfa, 0x70, 0xed, 0x1b, 0x39, 0x7f, 0x94, - 0x7e, 0x29, 0x32, 0x36, 0x72, 0xff, 0x7f, 0xb9, 0xd9, 0x19, 0xe3, 0x97, - 0xfd, 0xa8, 0x60, 0x7b, 0x02, 0xb3, 0x97, 0x20, 0xe1, 0xf6, 0xaa, 0x6b, - 0x50, 0x8d, 0x00, 0xc2, 0x92, 0xf4, 0xbf, 0xd1, 0xcb, 0xf8, 0x2f, 0xb0, - 0x34, 0xc3, 0x97, 0xba, 0xa7, 0x13, 0x97, 0xfd, 0x0c, 0x1c, 0x5e, 0xd0, - 0x07, 0x2f, 0xc1, 0x7d, 0x6b, 0x0e, 0x54, 0x8f, 0xfb, 0x44, 0x1f, 0x9b, - 0xdf, 0xf4, 0x4b, 0x13, 0x5a, 0xfe, 0x0e, 0x5f, 0xfb, 0xd0, 0xce, 0x56, - 0x9c, 0xe6, 0xce, 0x5f, 0xbb, 0x9b, 0x4d, 0x1c, 0xbc, 0x29, 0x2e, 0x4f, - 0x9f, 0xc8, 0x17, 0xfe, 0x7c, 0x04, 0x0b, 0x87, 0x15, 0x39, 0x53, 0xa6, - 0x1d, 0x28, 0x4f, 0x80, 0xce, 0xff, 0x3f, 0x3a, 0xf7, 0xb1, 0xac, 0xe5, - 0xcc, 0x91, 0xcb, 0xfe, 0x7c, 0x58, 0x73, 0x60, 0x43, 0x97, 0x26, 0xc2, - 0x79, 0xdd, 0x17, 0xbf, 0xe8, 0x96, 0x86, 0x00, 0xec, 0x39, 0x7e, 0xf4, - 0x60, 0xac, 0xe5, 0xf7, 0x3e, 0x86, 0x1c, 0xa5, 0x4f, 0x27, 0x92, 0x6b, - 0xfe, 0x92, 0x9e, 0x4e, 0xa0, 0xf8, 0xe5, 0xff, 0xe8, 0xce, 0x7d, 0xd8, - 0xf0, 0xc0, 0x34, 0x72, 0xe8, 0x01, 0xcb, 0xba, 0xc3, 0x94, 0xb3, 0x5b, - 0xa1, 0x6a, 0x44, 0x7a, 0x39, 0x27, 0x8e, 0x7f, 0x76, 0xbd, 0x3a, 0x6c, - 0xe5, 0xfd, 0xfe, 0xbd, 0xac, 0xf1, 0xcb, 0xfb, 0xfe, 0x1d, 0x26, 0x46, - 0xce, 0x5d, 0x9d, 0x39, 0x79, 0xb6, 0xdb, 0x29, 0x7f, 0xfb, 0xc9, 0xed, - 0x75, 0x1a, 0x29, 0xb8, 0x91, 0x4f, 0xa6, 0x82, 0x95, 0x4c, 0x59, 0x07, - 0x5c, 0xbf, 0xc6, 0xbf, 0x9b, 0x5f, 0xff, 0xf2, 0x7a, 0x50, 0x39, 0xee, - 0xa6, 0x7a, 0x18, 0x9b, 0x91, 0xca, 0x93, 0x20, 0x50, 0x2d, 0xb8, 0x40, - 0xb8, 0x7d, 0x72, 0x4e, 0x83, 0xd3, 0x42, 0xb7, 0x71, 0x9f, 0x30, 0xdf, - 0xb0, 0x85, 0x01, 0x68, 0xc6, 0xe9, 0xe8, 0xd4, 0xb8, 0xa5, 0xdf, 0xf7, - 0x32, 0xd6, 0xb0, 0x2f, 0xe3, 0x96, 0xc3, 0x97, 0xdb, 0x17, 0xe2, 0x72, - 0xa0, 0xfb, 0x55, 0x3a, 0x41, 0x0b, 0xc0, 0xd6, 0x1c, 0xb3, 0x9c, 0xbd, - 0x1d, 0xd1, 0xca, 0xe4, 0xd6, 0x20, 0x85, 0xff, 0xa1, 0x7f, 0x30, 0x63, - 0xfe, 0x1f, 0x47, 0x2f, 0xff, 0xe7, 0xf2, 0x75, 0xd9, 0xf3, 0x35, 0x19, - 0xbc, 0x13, 0x97, 0xff, 0x69, 0xf9, 0xd6, 0xb0, 0x40, 0xd3, 0x0e, 0x5f, - 0xfe, 0x45, 0xea, 0x1a, 0x67, 0xa5, 0x2c, 0xd1, 0xca, 0xda, 0x6a, 0x0c, - 0x21, 0x14, 0x5f, 0x2c, 0xf1, 0x46, 0xbe, 0xdf, 0x70, 0x4e, 0x52, 0x1f, - 0x6b, 0xa6, 0x5f, 0xc3, 0xf1, 0x4d, 0x46, 0x1c, 0xbe, 0xf4, 0x72, 0xd9, - 0xca, 0x5a, 0xa7, 0x8e, 0xca, 0x05, 0x01, 0x03, 0x65, 0xf7, 0xff, 0xef, - 0x7e, 0xa7, 0x86, 0x00, 0xfe, 0x02, 0x83, 0x23, 0x97, 0x37, 0xd3, 0x97, - 0xff, 0xa0, 0x56, 0xa6, 0xdc, 0x09, 0xee, 0xc1, 0xcb, 0xf9, 0x9f, 0x3b, - 0x80, 0x73, 0x97, 0xf3, 0x7a, 0xcc, 0x19, 0xce, 0x56, 0x1e, 0xea, 0x17, - 0xdf, 0x46, 0xa3, 0x89, 0xcb, 0xff, 0xa0, 0x5f, 0xd2, 0x85, 0x5d, 0xbf, - 0x1c, 0xae, 0x9f, 0x3f, 0xe4, 0x77, 0xbe, 0x3a, 0xce, 0x54, 0x27, 0xbc, - 0xb5, 0x80, 0x0c, 0x6a, 0x14, 0xde, 0x84, 0x3f, 0x01, 0x1d, 0xf3, 0x14, - 0x81, 0x39, 0x7c, 0x81, 0xc6, 0x1c, 0xbe, 0x77, 0x10, 0x1c, 0xb3, 0x70, - 0x78, 0x2a, 0x90, 0xdd, 0xfb, 0x0e, 0x5f, 0xe6, 0xde, 0x6c, 0x94, 0x35, - 0x9c, 0xa4, 0x3f, 0x8e, 0x94, 0xe8, 0x62, 0xff, 0xd0, 0x8c, 0xef, 0x2e, - 0xd7, 0xed, 0x1c, 0xbf, 0xd0, 0xfb, 0xeb, 0x6e, 0x12, 0x97, 0x36, 0xd9, - 0x4a, 0x09, 0xe6, 0x36, 0x67, 0x7b, 0xc8, 0xd6, 0x53, 0xe9, 0xa3, 0xbf, - 0xb9, 0x5a, 0x6b, 0xa8, 0x72, 0xfb, 0xf9, 0x7f, 0xe3, 0x94, 0x8a, 0x8f, - 0xa6, 0x86, 0xdb, 0x0b, 0xb5, 0x0b, 0x1f, 0x18, 0xb4, 0x2e, 0xbe, 0xde, - 0x3b, 0x59, 0xcb, 0x9b, 0xd1, 0xcb, 0x61, 0xcb, 0x73, 0x86, 0xa3, 0xc3, - 0x17, 0xdc, 0xcb, 0x84, 0xe4, 0xe5, 0xff, 0xda, 0xd0, 0x46, 0x03, 0xd8, - 0xf6, 0x8e, 0x54, 0x22, 0x57, 0x09, 0xff, 0x2a, 0xbf, 0xdd, 0x47, 0x97, - 0x92, 0x73, 0x97, 0xfe, 0xf2, 0x6d, 0xc1, 0xc1, 0xec, 0xe9, 0xcb, 0xfe, - 0x46, 0xc7, 0x3c, 0x9f, 0x80, 0xe5, 0xf9, 0x36, 0x18, 0x9c, 0xe5, 0xfe, - 0x7d, 0xfb, 0x42, 0x8a, 0x9c, 0xbf, 0xfd, 0xac, 0x57, 0x3f, 0xdb, 0x86, - 0x3b, 0x07, 0x2a, 0x49, 0xc0, 0xf2, 0x5e, 0x86, 0x6d, 0x68, 0x3d, 0x39, - 0x72, 0x8d, 0x19, 0xdf, 0xff, 0xf9, 0xd3, 0xd1, 0xd1, 0xcf, 0x75, 0x14, - 0x94, 0x71, 0x41, 0x01, 0xcb, 0xf2, 0xf1, 0x91, 0xa3, 0x95, 0xd4, 0x49, - 0x3b, 0x5d, 0xec, 0x4d, 0x9c, 0xbf, 0xd2, 0x46, 0x77, 0x97, 0x6b, 0x39, - 0x7c, 0xfb, 0x89, 0x1c, 0xbf, 0xe7, 0xe7, 0xe7, 0x3a, 0xc1, 0x54, 0xe5, - 0x4e, 0x8b, 0x0e, 0x46, 0xd8, 0x6f, 0xe2, 0x1b, 0xee, 0xb5, 0xa3, 0x0e, - 0x5e, 0x18, 0x01, 0xcb, 0xd0, 0xcc, 0xf8, 0x78, 0x1a, 0x25, 0xbf, 0xf4, - 0x73, 0xd8, 0x62, 0xfa, 0x93, 0x1c, 0xa8, 0x4f, 0x17, 0x21, 0xa4, 0x8f, - 0xfb, 0x34, 0xbf, 0x84, 0x3a, 0xd2, 0x30, 0xe5, 0xf9, 0x6f, 0x3e, 0x36, - 0x72, 0xfd, 0x1b, 0x0e, 0x09, 0xca, 0xc3, 0xfc, 0x12, 0xdf, 0x14, 0xdf, - 0xa1, 0xa2, 0x77, 0xf3, 0x97, 0xff, 0x40, 0x23, 0xac, 0x17, 0x57, 0xa8, - 0x72, 0xdc, 0x31, 0xcb, 0xfb, 0xb0, 0x2d, 0xbf, 0x27, 0x2f, 0xfc, 0x33, - 0x46, 0x0c, 0xf9, 0xcf, 0x8e, 0x50, 0x4f, 0xb5, 0xcb, 0xaf, 0x2a, 0xa3, - 0x0e, 0x5f, 0xfc, 0x81, 0xec, 0x2e, 0x00, 0xe2, 0x03, 0x97, 0xe7, 0xd4, - 0xe9, 0xb3, 0x97, 0xff, 0xf9, 0xc7, 0x99, 0x7d, 0x6f, 0x13, 0x8e, 0x0e, - 0x05, 0xe4, 0x78, 0xbd, 0x54, 0x14, 0x4c, 0x30, 0xa2, 0xfc, 0xaf, 0x9d, - 0xc4, 0xe5, 0xe1, 0xfe, 0x73, 0x94, 0xe7, 0x8b, 0xe2, 0x7a, 0x44, 0x44, - 0x8b, 0x45, 0x42, 0xae, 0x10, 0x96, 0xec, 0xa9, 0x88, 0x6f, 0x08, 0x31, - 0x21, 0xd0, 0xff, 0xf1, 0xb1, 0xdc, 0xd4, 0x35, 0x67, 0x2f, 0x24, 0x6c, - 0xe5, 0x70, 0xc6, 0xf3, 0xa4, 0x37, 0xff, 0x6d, 0x19, 0x0d, 0x63, 0x8c, - 0xe6, 0x0e, 0x54, 0x8f, 0xb2, 0x62, 0x6b, 0xe4, 0x17, 0x09, 0xcb, 0xd3, - 0xb1, 0x0e, 0x50, 0x4d, 0xe8, 0x90, 0x5f, 0xa5, 0x9c, 0x62, 0x47, 0x2f, - 0x66, 0xe0, 0xe5, 0x72, 0x8c, 0x44, 0x60, 0xd9, 0x07, 0x4a, 0x6e, 0x19, - 0x8e, 0x5f, 0xc9, 0xce, 0xbb, 0x8b, 0x39, 0x7f, 0xfd, 0x9e, 0xd6, 0x4d, - 0xd8, 0xe3, 0x9d, 0xec, 0x1c, 0xbf, 0xff, 0xff, 0x26, 0x73, 0xa4, 0xc6, - 0xfe, 0x67, 0x32, 0xd2, 0x7b, 0x49, 0xc8, 0x43, 0xfc, 0xe7, 0x2f, 0xff, - 0xc8, 0x21, 0xf8, 0xa7, 0x93, 0x4e, 0x83, 0xfc, 0x8e, 0x5f, 0x3c, 0xfd, - 0x43, 0x95, 0x89, 0xcc, 0xcc, 0x2e, 0x25, 0xde, 0x51, 0xe3, 0x08, 0xa6, - 0x8a, 0xf7, 0xbf, 0xdc, 0x8e, 0x5f, 0xcf, 0xe0, 0x28, 0x32, 0x39, 0x7f, - 0xa4, 0xa4, 0x08, 0xfe, 0xc3, 0x95, 0xf1, 0x10, 0x13, 0x8f, 0x39, 0x75, - 0xfe, 0x89, 0x27, 0xd6, 0xdb, 0x6c, 0xa5, 0xd9, 0xd3, 0x97, 0x95, 0xc0, - 0x9c, 0xbf, 0xba, 0xfb, 0x5c, 0x78, 0xe5, 0xce, 0x13, 0x97, 0xf6, 0xdf, - 0x5d, 0x79, 0x1c, 0xb7, 0x27, 0x2e, 0x46, 0xce, 0x5c, 0xa0, 0x0e, 0x54, - 0xc6, 0xbc, 0x02, 0xf7, 0xa4, 0xe1, 0x39, 0x73, 0x6d, 0x9c, 0xa9, 0x23, - 0x6f, 0x05, 0x96, 0x5a, 0x88, 0x3a, 0x22, 0x6c, 0x72, 0xf7, 0x94, 0x01, - 0x4f, 0xa7, 0xad, 0x7f, 0xdd, 0xc6, 0x20, 0x67, 0xff, 0x47, 0x2f, 0xf9, - 0x03, 0x8c, 0x49, 0x91, 0xb3, 0x97, 0xff, 0x9c, 0x39, 0x82, 0xae, 0xb5, - 0x82, 0x03, 0x97, 0xdd, 0xfd, 0xd5, 0x84, 0x40, 0xb0, 0xe6, 0xf0, 0xc7, - 0x4e, 0x5f, 0xff, 0xd2, 0x7d, 0x6a, 0x32, 0x7f, 0xe4, 0x1d, 0x8b, 0xb6, - 0x72, 0xd0, 0x14, 0x59, 0xaa, 0x76, 0x83, 0x75, 0xa4, 0xe9, 0x3d, 0x1b, - 0x7d, 0xfc, 0x8c, 0x5e, 0x0a, 0xce, 0x5f, 0x3c, 0xfa, 0xe9, 0xca, 0xd9, - 0xe7, 0xe8, 0xb2, 0xbe, 0x2e, 0x00, 0xc8, 0x58, 0x23, 0xbc, 0xc6, 0xbc, - 0x91, 0xea, 0xf9, 0xe6, 0xfd, 0xc5, 0x4e, 0xa7, 0x8e, 0x5f, 0xf6, 0x7b, - 0xb1, 0xbf, 0x62, 0xce, 0x5e, 0x8d, 0xcc, 0x72, 0xa1, 0x90, 0x13, 0x91, - 0xeb, 0x24, 0x38, 0x3a, 0x64, 0xf3, 0x87, 0x20, 0x68, 0x12, 0xb6, 0x87, - 0x17, 0xb4, 0xf3, 0x1c, 0xbf, 0xfd, 0x9c, 0xe7, 0x18, 0x08, 0xe7, 0xb0, - 0x07, 0x2e, 0x50, 0x07, 0x2b, 0x67, 0xc4, 0x04, 0xab, 0xff, 0x90, 0x2f, - 0xe4, 0xd6, 0x4b, 0x3a, 0x72, 0xe7, 0xe0, 0x39, 0x6c, 0xe9, 0xed, 0xf9, - 0x0a, 0xb9, 0x4c, 0x8f, 0x6f, 0xe2, 0xfb, 0x78, 0x57, 0xc0, 0x72, 0xff, - 0xfe, 0xe7, 0x42, 0xfa, 0xee, 0x4b, 0x3a, 0x9b, 0xeb, 0x9c, 0xbe, 0xce, - 0x67, 0xe2, 0x72, 0xff, 0x84, 0x38, 0x3f, 0xcb, 0x34, 0x72, 0xfd, 0x1c, - 0xeb, 0xf0, 0x1c, 0xbf, 0xca, 0x78, 0x72, 0x74, 0xd9, 0xcb, 0xef, 0x26, - 0x90, 0xe5, 0x62, 0x6a, 0xc8, 0x3f, 0xb5, 0xa7, 0x26, 0x01, 0xc0, 0x95, - 0x7e, 0x69, 0x7f, 0xf4, 0xf0, 0xa0, 0x3f, 0x94, 0x9f, 0xbf, 0x9c, 0xbf, - 0xee, 0xa0, 0x53, 0x87, 0x81, 0x43, 0x97, 0xf9, 0xe5, 0x81, 0xde, 0xb4, - 0x72, 0xfa, 0x31, 0x40, 0x9c, 0xbf, 0xca, 0xa7, 0x9f, 0xad, 0xb5, 0x9c, - 0xbf, 0xd9, 0x37, 0x73, 0x4e, 0x27, 0x2f, 0xfc, 0x1c, 0xe6, 0x5a, 0xf6, - 0x9c, 0x07, 0x2b, 0x67, 0xe5, 0xf9, 0x95, 0xff, 0xc8, 0xcf, 0x8b, 0xea, - 0x75, 0x69, 0xa3, 0x97, 0xfb, 0x25, 0x9f, 0xf0, 0xee, 0x27, 0x2b, 0x67, - 0xfb, 0xd4, 0x6b, 0xff, 0xfc, 0x83, 0x9c, 0xf9, 0x57, 0xf7, 0x63, 0xb9, - 0xc5, 0xe4, 0x72, 0x82, 0xa8, 0x8d, 0x66, 0x68, 0x45, 0xb8, 0x55, 0x7a, - 0x14, 0x1c, 0x48, 0xae, 0x18, 0x39, 0x7f, 0xc1, 0x4d, 0xc7, 0x10, 0x6a, - 0x47, 0x2e, 0x86, 0x1c, 0xa8, 0x3d, 0x1e, 0x9d, 0xd7, 0x51, 0x0f, 0xe6, - 0x6b, 0xff, 0x46, 0x9f, 0xa8, 0x15, 0xa4, 0xe7, 0x2a, 0x15, 0xd5, 0x64, - 0xa5, 0xe7, 0x87, 0x5f, 0xe4, 0x77, 0xa0, 0x7c, 0x72, 0xff, 0xfa, 0x37, - 0x9c, 0x53, 0xc0, 0xfc, 0x74, 0x81, 0x39, 0x7f, 0x93, 0xa9, 0xb9, 0x4d, - 0x07, 0x2f, 0xff, 0xc9, 0xfa, 0xd4, 0xe4, 0x0f, 0xa7, 0xda, 0x72, 0x03, - 0x97, 0xcf, 0xb8, 0x91, 0xcb, 0xff, 0xf9, 0x05, 0xd0, 0x41, 0xb8, 0xeb, - 0xa7, 0xa3, 0xa7, 0x28, 0x4f, 0xdf, 0xc4, 0x37, 0xe4, 0xf6, 0xbf, 0x9c, - 0xe5, 0xff, 0xe1, 0x40, 0x7b, 0x95, 0xa6, 0xd4, 0x80, 0x9c, 0xbf, 0xee, - 0xa8, 0x1f, 0xfd, 0xa0, 0x41, 0xca, 0x84, 0x43, 0xba, 0x5d, 0x05, 0x3c, - 0x34, 0x86, 0x83, 0x08, 0x7d, 0x0b, 0x1b, 0xf6, 0xff, 0x5f, 0x60, 0xe5, - 0xfd, 0xb9, 0xa4, 0x9e, 0xd1, 0xcb, 0x0c, 0x1e, 0xc6, 0x14, 0xdf, 0xe9, - 0x9e, 0x67, 0xe6, 0x5a, 0x39, 0x7f, 0x3c, 0xe9, 0x32, 0x36, 0x72, 0xff, - 0xff, 0x3b, 0x7e, 0xce, 0xfc, 0x0e, 0x4d, 0x27, 0xdc, 0xfd, 0xfc, 0xe5, - 0x62, 0x33, 0x1c, 0xd8, 0x4b, 0xef, 0xe9, 0xf0, 0x67, 0xc6, 0xce, 0x5f, - 0xf4, 0x4e, 0xa4, 0xbb, 0xfb, 0xce, 0x72, 0xb0, 0xfb, 0x36, 0x5f, 0x6e, - 0x18, 0xe5, 0xfa, 0x37, 0xbc, 0xe9, 0xcb, 0xf8, 0x5d, 0x58, 0x64, 0x1c, - 0xae, 0x10, 0xfa, 0x64, 0x2d, 0xf9, 0x3d, 0xf4, 0x4e, 0xaa, 0xa7, 0x2f, - 0xff, 0xc8, 0xb8, 0x66, 0x9f, 0x78, 0xcf, 0xd6, 0xf2, 0x39, 0x72, 0x71, - 0x39, 0x6e, 0x9c, 0xa9, 0x1f, 0xf3, 0x5a, 0xaf, 0xe3, 0x17, 0x83, 0x0c, - 0x39, 0x7f, 0xb0, 0x19, 0x34, 0x73, 0xa3, 0x95, 0x07, 0xa1, 0x83, 0x97, - 0xf7, 0x5e, 0x51, 0xa9, 0x1c, 0xbf, 0xec, 0xea, 0x73, 0xae, 0xff, 0xa3, - 0x97, 0x60, 0xac, 0xfa, 0x00, 0x5b, 0x7f, 0x0b, 0x80, 0x38, 0x27, 0x2f, - 0xc8, 0xd3, 0x36, 0xa9, 0xcb, 0x95, 0x91, 0xcb, 0xf7, 0x53, 0x8a, 0x2c, - 0xe5, 0xd9, 0xd9, 0x1e, 0x0a, 0xc6, 0x29, 0x88, 0x98, 0x68, 0xd7, 0x79, - 0xb6, 0xdb, 0x29, 0x7f, 0xed, 0x8f, 0xee, 0xa6, 0x4d, 0x0c, 0x39, 0xf4, - 0xd0, 0x5f, 0xba, 0x93, 0x23, 0x67, 0x2c, 0xb3, 0x95, 0x08, 0x8c, 0xc5, - 0x2d, 0x94, 0xdf, 0xe8, 0x0e, 0x4a, 0x05, 0x67, 0x2a, 0x19, 0x22, 0xf3, - 0x8d, 0xc9, 0x47, 0x23, 0xf6, 0x6b, 0x84, 0xfc, 0xd0, 0xf1, 0xdc, 0x26, - 0x59, 0x08, 0xae, 0x9a, 0xbc, 0x28, 0xc6, 0x10, 0x7a, 0x84, 0x47, 0x8b, - 0x3f, 0x86, 0x1b, 0x70, 0xd1, 0x50, 0xba, 0xfb, 0x7b, 0xce, 0x9c, 0xbf, - 0xba, 0x9c, 0x1c, 0x1f, 0xaa, 0x72, 0xa0, 0xf6, 0x16, 0x45, 0x6e, 0x1c, - 0xe5, 0x90, 0xe5, 0xff, 0x7a, 0x37, 0xae, 0xc0, 0xf8, 0xe5, 0xb8, 0x73, - 0x97, 0xfd, 0xe8, 0xde, 0xbb, 0x03, 0xe3, 0x97, 0x6a, 0x0e, 0x5e, 0x60, - 0x60, 0xe5, 0xfe, 0x1f, 0x3c, 0xda, 0x8f, 0x1c, 0xa4, 0x3c, 0xf7, 0x1c, - 0xbe, 0x47, 0xc5, 0x9c, 0xbf, 0xf6, 0x71, 0x1c, 0xd4, 0xc3, 0x01, 0x39, - 0x7c, 0xb0, 0xc4, 0xe7, 0x2e, 0x04, 0x1c, 0xbd, 0xa4, 0xd9, 0xca, 0xc3, - 0xd5, 0x01, 0x1f, 0x85, 0xaf, 0xf4, 0xb0, 0x50, 0x38, 0x27, 0x2f, 0x7b, - 0x5f, 0x61, 0x3e, 0x5c, 0x16, 0x98, 0xe3, 0xac, 0xa0, 0x20, 0x12, 0x0d, - 0x42, 0x53, 0xc5, 0xd7, 0x6a, 0x0e, 0x5e, 0x60, 0x60, 0xe5, 0xfe, 0x1f, - 0x3c, 0xda, 0x8f, 0x1c, 0xa4, 0x3c, 0xf7, 0x1c, 0xbe, 0x47, 0xc5, 0x9c, - 0xbf, 0xf6, 0x71, 0x1c, 0xd4, 0xc3, 0x01, 0x39, 0x7c, 0xb0, 0xc4, 0xe7, - 0x2f, 0xe9, 0x80, 0x8d, 0x6f, 0x31, 0xcb, 0x81, 0x07, 0x2f, 0x69, 0x36, - 0x72, 0xb1, 0x10, 0xeb, 0x23, 0x01, 0x97, 0x85, 0xaf, 0xf4, 0xb0, 0x50, - 0x38, 0x27, 0x2f, 0xe1, 0x70, 0xe2, 0xbf, 0x61, 0x72, 0x8c, 0x22, 0xd8, - 0x20, 0xb9, 0x43, 0xb3, 0x42, 0x27, 0xac, 0xa0, 0x20, 0x12, 0x0d, 0x43, - 0x1b, 0xc7, 0x97, 0xff, 0x6e, 0x39, 0xd0, 0xc3, 0x33, 0x9f, 0x1c, 0xbf, - 0xff, 0x38, 0x73, 0x05, 0x55, 0x06, 0x06, 0x74, 0xd9, 0xcb, 0xcf, 0xb9, - 0xcf, 0x20, 0x92, 0xfa, 0x59, 0xcc, 0x8f, 0x20, 0x92, 0xf6, 0x90, 0x27, - 0x90, 0x49, 0x73, 0x6d, 0x9e, 0x41, 0x25, 0x2d, 0x15, 0x33, 0x15, 0x78, - 0xc1, 0xb2, 0x9b, 0x9f, 0xc5, 0x90, 0x48, 0xfa, 0x6f, 0xef, 0xec, 0xee, - 0x60, 0xaa, 0x72, 0xf3, 0x88, 0x3e, 0x2f, 0xb4, 0x44, 0xe6, 0x26, 0xe1, - 0x82, 0xc4, 0x51, 0x8c, 0xf3, 0xc6, 0xd7, 0xcd, 0x31, 0xfa, 0x72, 0xd8, - 0xd6, 0x8a, 0x00, 0x3e, 0xda, 0x47, 0x2f, 0xe9, 0x7f, 0x3f, 0x92, 0x72, - 0x97, 0xce, 0x1e, 0xe1, 0xcb, 0xff, 0x76, 0x3c, 0x83, 0x0c, 0x8d, 0x1c, - 0xa5, 0x4f, 0x77, 0x44, 0x35, 0x32, 0x2c, 0x7b, 0x08, 0xeb, 0xfe, 0x81, - 0x90, 0xc0, 0x1d, 0x87, 0x2d, 0x07, 0x2f, 0xf2, 0x4b, 0xf7, 0xd7, 0x50, - 0xe5, 0xfd, 0x9c, 0x5d, 0x99, 0xd3, 0x96, 0x91, 0x4b, 0xcf, 0xb9, 0xca, - 0x51, 0x4a, 0x83, 0x72, 0xb1, 0x16, 0x0e, 0xde, 0x80, 0x2c, 0xa7, 0xd3, - 0x5b, 0x4c, 0x46, 0x10, 0xc2, 0x52, 0xa1, 0x31, 0xcc, 0x87, 0xad, 0xfb, - 0x60, 0x62, 0x68, 0xe5, 0xfc, 0xa0, 0xcb, 0x5d, 0x09, 0xcc, 0x35, 0x17, - 0xdf, 0xbe, 0xe4, 0x72, 0xcc, 0x39, 0x76, 0x48, 0x26, 0xd2, 0x62, 0x3b, - 0xff, 0xb3, 0x9f, 0x69, 0x06, 0x00, 0xec, 0x39, 0x7d, 0x93, 0x23, 0x0e, - 0x54, 0xe7, 0xca, 0xda, 0x1d, 0xfc, 0xb8, 0x9a, 0x50, 0x02, 0x96, 0x43, - 0x97, 0xfd, 0x3f, 0xf2, 0x0f, 0x7f, 0x71, 0x39, 0x7f, 0x24, 0x32, 0x7c, - 0x6c, 0xe5, 0xfb, 0x27, 0x66, 0x30, 0xe5, 0xed, 0x26, 0xce, 0x50, 0x9e, - 0x27, 0x8a, 0x2f, 0xe1, 0x70, 0x03, 0xfd, 0x1c, 0xbf, 0x91, 0x55, 0x21, - 0x9f, 0x42, 0x98, 0x6e, 0x08, 0x6c, 0xf3, 0x4e, 0x5e, 0x21, 0xac, 0x4f, - 0x3d, 0x09, 0x06, 0x33, 0xbb, 0xe1, 0xc9, 0xff, 0x39, 0x7f, 0xd9, 0xef, - 0x83, 0x80, 0x53, 0x93, 0x95, 0x25, 0xe2, 0xd0, 0x95, 0xe4, 0x30, 0x95, - 0x29, 0xd9, 0xb7, 0x63, 0x2c, 0x02, 0x78, 0xb9, 0x6a, 0x53, 0x0f, 0x8d, - 0x1a, 0x11, 0xdf, 0xff, 0xa7, 0xde, 0xf0, 0x2e, 0xce, 0xbf, 0x86, 0x26, - 0x39, 0x7f, 0xff, 0xfb, 0xfd, 0xff, 0x30, 0xb8, 0x35, 0xac, 0x57, 0x3f, - 0xdb, 0x86, 0x3b, 0x07, 0x2f, 0xfb, 0xeb, 0x1c, 0x3d, 0x81, 0xfc, 0xe5, - 0xf7, 0x07, 0x7f, 0x50, 0xe5, 0xe6, 0xdb, 0x6c, 0xa5, 0xd2, 0x82, 0x9f, - 0x4d, 0x05, 0x42, 0x6f, 0x93, 0xab, 0x63, 0xdf, 0x27, 0x7b, 0x48, 0xbf, - 0xfe, 0x4f, 0x4d, 0x9b, 0xdb, 0xcd, 0x9b, 0xcf, 0x1c, 0xbf, 0x95, 0x8d, - 0xef, 0x3a, 0x72, 0xfe, 0x9e, 0x69, 0x70, 0xdb, 0x9c, 0xe5, 0xff, 0xe0, - 0x31, 0xe5, 0xf2, 0x03, 0x3b, 0x23, 0x67, 0x2f, 0x92, 0x07, 0xc7, 0x2f, - 0x4e, 0xe2, 0x72, 0xb6, 0x88, 0x9e, 0xa6, 0xf8, 0x82, 0xff, 0xca, 0xff, - 0xa9, 0x26, 0xe7, 0xfc, 0x07, 0x2f, 0x3f, 0x2d, 0x9c, 0xa5, 0x4f, 0x8b, - 0xa8, 0x97, 0xe9, 0xf6, 0x90, 0xc3, 0x97, 0xff, 0xd0, 0xa7, 0x86, 0x00, - 0xfe, 0x02, 0x83, 0x23, 0x94, 0xd5, 0x27, 0xdb, 0x90, 0xc0, 0x48, 0x49, - 0x39, 0x1f, 0x8a, 0x2f, 0x94, 0x0f, 0x50, 0xe5, 0xff, 0x9f, 0xda, 0x6f, - 0x3a, 0x07, 0xf1, 0xcb, 0xff, 0xff, 0x67, 0xa1, 0x63, 0x98, 0x31, 0x2f, - 0x75, 0xd8, 0x39, 0xc4, 0xe5, 0x4e, 0x8c, 0xb0, 0x91, 0xb6, 0x7f, 0x79, - 0x40, 0xcc, 0x72, 0xf4, 0x90, 0x4e, 0x5f, 0x4e, 0xa7, 0x03, 0x67, 0x2f, - 0xfa, 0x3a, 0xe9, 0xe9, 0x91, 0xb3, 0x97, 0xfe, 0x06, 0x6d, 0x01, 0x80, - 0xdb, 0x0e, 0x5f, 0xfe, 0x56, 0x35, 0xb8, 0xe8, 0xe7, 0xa1, 0x87, 0x2f, - 0xfb, 0x43, 0x9c, 0x52, 0x64, 0x6c, 0xe5, 0xff, 0xfd, 0xfb, 0xce, 0xbf, - 0xe7, 0xf6, 0x74, 0x73, 0xdd, 0x43, 0x97, 0xe8, 0x98, 0x7f, 0xd1, 0xca, - 0xc4, 0xc2, 0xd1, 0x27, 0xa7, 0x7e, 0x5e, 0xb9, 0x04, 0xe5, 0xfc, 0xe2, - 0x0c, 0xf2, 0xa7, 0x2a, 0x15, 0x4a, 0xce, 0x65, 0x21, 0xf7, 0x1b, 0x12, - 0x9d, 0x1c, 0xfa, 0x34, 0x9e, 0x27, 0x8d, 0x05, 0x6f, 0x87, 0xd0, 0xd0, - 0xe5, 0xf7, 0x7f, 0x64, 0x1c, 0xb9, 0xf4, 0x72, 0xef, 0xf8, 0x73, 0x94, - 0xd5, 0x1f, 0xcb, 0x91, 0x89, 0x1f, 0xe2, 0xd7, 0x3f, 0xde, 0x11, 0xf7, - 0xb7, 0x5a, 0xb8, 0x43, 0xf0, 0xd0, 0xa8, 0xe1, 0x72, 0xc6, 0xa4, 0x49, - 0xc2, 0xc7, 0xb1, 0x39, 0x37, 0x3c, 0xa4, 0x99, 0x4a, 0x1a, 0x0c, 0xbb, - 0x1c, 0xa5, 0x21, 0xab, 0x1a, 0x92, 0xe5, 0x53, 0x73, 0x28, 0x95, 0x25, - 0x51, 0x35, 0xb2, 0xcd, 0x29, 0x8b, 0x72, 0xaf, 0x99, 0x2e, 0x77, 0xb4, - 0x9f, 0x17, 0x8e, 0xa0, 0x11, 0xc3, 0xf0, 0xec, 0x43, 0x2f, 0xcf, 0x54, - 0x96, 0x0f, 0x53, 0xe8, 0x7f, 0x94, 0x55, 0xc5, 0x2d, 0xb5, 0x06, 0x92, - 0x86, 0xd4, 0x97, 0x6f, 0xc1, 0x18, 0x0d, 0xf9, 0x98, 0x8e, 0x03, 0x97, - 0xcb, 0x77, 0x59, 0xa2, 0x8a, 0x5f, 0xff, 0x9c, 0x10, 0xbe, 0xa6, 0xba, - 0x9e, 0xee, 0x09, 0xca, 0xda, 0x20, 0x44, 0xba, 0xf3, 0xcb, 0xec, 0x23, - 0x27, 0x21, 0x4f, 0x7f, 0xfe, 0x0a, 0x4c, 0x31, 0xed, 0x7b, 0x95, 0xa0, - 0xce, 0x72, 0xdf, 0x58, 0x89, 0x0d, 0x1c, 0xdf, 0xef, 0xb9, 0xb5, 0xbb, - 0xac, 0xd1, 0x74, 0x2f, 0xfe, 0xfa, 0xf2, 0xfb, 0x9b, 0x5b, 0xba, 0xcd, - 0x12, 0x5a, 0xfd, 0xb5, 0xbb, 0xac, 0xd1, 0x79, 0x2e, 0x7e, 0x27, 0x2d, - 0xf7, 0x0f, 0x31, 0xa1, 0xa5, 0x43, 0xf5, 0x7e, 0xcf, 0x08, 0xa9, 0x15, - 0x64, 0x27, 0x17, 0x09, 0x99, 0x8e, 0x98, 0x83, 0xd9, 0xc0, 0x41, 0xbd, - 0xf6, 0xbd, 0x4b, 0xf3, 0xf1, 0x5f, 0xe8, 0x3c, 0x61, 0x41, 0x7f, 0xfb, - 0xeb, 0x1e, 0x5f, 0x73, 0x6b, 0x77, 0x59, 0xa2, 0x59, 0x5d, 0xff, 0x4e, - 0x5f, 0xe4, 0x0f, 0x71, 0x05, 0x53, 0x97, 0xdd, 0x7f, 0x7e, 0x72, 0xfb, - 0xb0, 0xd6, 0xc3, 0x97, 0xbf, 0x5b, 0x9c, 0xa9, 0x22, 0x5d, 0x0c, 0x9a, - 0xc8, 0xd4, 0x25, 0xbf, 0x83, 0xef, 0xde, 0x5a, 0x39, 0x7c, 0x8d, 0x71, - 0x39, 0xcb, 0xde, 0x76, 0x1c, 0xbf, 0x7f, 0xe4, 0xec, 0x1c, 0xbf, 0xf7, - 0x63, 0xa8, 0xaf, 0xb4, 0xe0, 0x39, 0x7f, 0xcf, 0x2d, 0x7f, 0xe8, 0xf6, - 0x8e, 0x5f, 0xc3, 0xed, 0xc3, 0xac, 0xe5, 0xcf, 0xa3, 0x97, 0xff, 0xe7, - 0x79, 0x3f, 0x7e, 0x64, 0xff, 0xf9, 0x3b, 0x07, 0x2a, 0x73, 0xed, 0x98, - 0x5a, 0xf9, 0x6e, 0xeb, 0x34, 0x46, 0x6b, 0xf9, 0x21, 0x93, 0xe3, 0x67, - 0x2e, 0x19, 0x1c, 0xb3, 0x0e, 0x5f, 0x93, 0x7d, 0x7f, 0xbb, 0x3d, 0x56, - 0x17, 0x28, 0x2d, 0x7f, 0x3c, 0x93, 0x6f, 0xb3, 0x97, 0xff, 0x69, 0x3f, - 0xd6, 0x0f, 0xf2, 0xcd, 0x1c, 0xbd, 0xa8, 0xe4, 0xe5, 0x4e, 0xaa, 0xf6, - 0x45, 0x01, 0x3f, 0xc3, 0xa4, 0x84, 0xce, 0xc9, 0x19, 0x08, 0x31, 0x4e, - 0xd1, 0x67, 0x91, 0x6f, 0xfb, 0x6e, 0xdf, 0x52, 0x37, 0x07, 0x2f, 0xfa, - 0x5a, 0xc8, 0xf9, 0x1a, 0x61, 0xcb, 0xee, 0x7b, 0x1a, 0x39, 0x7d, 0xa8, - 0xf6, 0x8e, 0x56, 0x1e, 0x2e, 0x88, 0xef, 0xfe, 0xf2, 0x6d, 0xc1, 0xf3, - 0x99, 0x43, 0x0e, 0x5f, 0x86, 0x25, 0xa7, 0x39, 0x48, 0x7d, 0xbc, 0x51, - 0xed, 0xd3, 0x97, 0xff, 0xff, 0x79, 0x19, 0xb4, 0xce, 0x47, 0xff, 0x47, - 0x7e, 0x71, 0x4f, 0x4d, 0x07, 0x2d, 0x98, 0x88, 0x8f, 0x08, 0xdf, 0xe7, - 0x96, 0xb4, 0xe3, 0x23, 0x97, 0xfe, 0xf3, 0x88, 0x3e, 0x29, 0x9c, 0xb6, - 0x72, 0xfb, 0xde, 0x86, 0x1c, 0xac, 0x3e, 0x55, 0x50, 0xef, 0xff, 0x7a, - 0x16, 0x9e, 0x46, 0x4d, 0xa4, 0x13, 0x97, 0xf9, 0x99, 0xb0, 0x0f, 0xe0, - 0x39, 0x69, 0x1c, 0xa4, 0x44, 0x73, 0xa4, 0xa8, 0x69, 0x7e, 0x04, 0x7a, - 0x02, 0x72, 0x91, 0x30, 0x67, 0x85, 0x87, 0xe5, 0xf7, 0xff, 0xdf, 0xfb, - 0x5c, 0xca, 0x04, 0x1a, 0xf9, 0xf8, 0x9c, 0xbd, 0x1e, 0x83, 0x94, 0x13, - 0xf0, 0xe2, 0xab, 0x7b, 0xb8, 0x27, 0x29, 0x0d, 0xff, 0xe4, 0x97, 0x76, - 0x63, 0x97, 0xfb, 0x9d, 0x0e, 0x6c, 0x30, 0x72, 0x90, 0xf2, 0xdc, 0x62, - 0xff, 0xbd, 0xac, 0xd8, 0x07, 0xf0, 0x1c, 0xbe, 0xf3, 0xf6, 0x0e, 0x5f, - 0x7b, 0xbf, 0xb4, 0x39, 0x7f, 0xb2, 0x36, 0xf2, 0x4e, 0x9c, 0xbf, 0xc8, - 0xde, 0xa3, 0xae, 0xd6, 0x72, 0xb6, 0x7c, 0xfe, 0x31, 0xae, 0x51, 0xa0, - 0x84, 0x2c, 0x84, 0x6d, 0xff, 0xe4, 0xef, 0xed, 0x61, 0xef, 0xfa, 0xe6, - 0x4e, 0x72, 0xa1, 0x39, 0x0c, 0x8c, 0x29, 0xcd, 0x6f, 0x29, 0x9c, 0x31, - 0xcb, 0xff, 0xdf, 0x81, 0x88, 0x38, 0x01, 0xc7, 0x98, 0xe5, 0xfe, 0x4e, - 0xa4, 0x0c, 0xdf, 0x9c, 0xbf, 0xc9, 0xbc, 0xc1, 0xe7, 0xc7, 0x2a, 0x0f, - 0x95, 0xcc, 0xef, 0xfd, 0xf8, 0x77, 0x9f, 0xf6, 0x19, 0x87, 0x2b, 0x13, - 0x30, 0xd9, 0x17, 0x61, 0x5d, 0xa2, 0x0b, 0xff, 0xee, 0x64, 0x9b, 0x0f, - 0x7f, 0xde, 0x2f, 0xb8, 0x72, 0xe4, 0x6c, 0xe5, 0xdc, 0x18, 0x72, 0xb4, - 0x6c, 0x3c, 0x2f, 0x7f, 0x6a, 0x3d, 0xae, 0xa1, 0xcb, 0xf0, 0xe3, 0x37, - 0x87, 0x2f, 0xb7, 0xc7, 0x02, 0x72, 0xb0, 0xfd, 0xd8, 0x5b, 0xf9, 0x35, - 0xf0, 0x13, 0x99, 0x1c, 0xbf, 0xd0, 0x3e, 0x49, 0xc6, 0x0e, 0x5f, 0xfe, - 0x4d, 0xa4, 0xf0, 0x39, 0xdd, 0xff, 0xc4, 0xe5, 0x01, 0x14, 0x02, 0x47, - 0xe3, 0x1a, 0x6a, 0xd9, 0xe4, 0x71, 0x0a, 0xf9, 0xd0, 0x24, 0x5e, 0x12, - 0x5c, 0x95, 0xb2, 0xac, 0x25, 0x79, 0x38, 0x47, 0xf9, 0xa1, 0x1d, 0xb8, - 0x55, 0xb0, 0x9f, 0xb1, 0xce, 0xbc, 0x39, 0x00, 0xd8, 0x31, 0xd8, 0x6a, - 0x36, 0x4f, 0x21, 0x71, 0x84, 0x13, 0x48, 0x4c, 0x29, 0x0c, 0xfb, 0xce, - 0xe0, 0x39, 0x7e, 0x70, 0xbb, 0xf2, 0x72, 0xef, 0x7d, 0xe9, 0xe1, 0x38, - 0xdd, 0xff, 0xff, 0xdf, 0xf3, 0x2f, 0xae, 0x3e, 0xc6, 0x68, 0x3d, 0x8d, - 0x85, 0xdd, 0xb3, 0x95, 0xf5, 0x52, 0x7e, 0x47, 0x54, 0x25, 0xf7, 0xff, - 0xbe, 0xb1, 0xe5, 0xf7, 0x36, 0xb7, 0x75, 0x9a, 0x26, 0x95, 0xff, 0xef, - 0xac, 0x79, 0x7d, 0xcd, 0xad, 0xdd, 0x66, 0x89, 0xc5, 0x7f, 0xe7, 0x97, - 0xdc, 0xda, 0xdd, 0xd6, 0x68, 0xa0, 0x57, 0xda, 0x1e, 0x64, 0x72, 0xdf, - 0x58, 0x7d, 0xfe, 0x4c, 0xbf, 0x6d, 0x6e, 0xeb, 0x34, 0x5c, 0x0b, 0xf8, - 0x73, 0xcb, 0x4d, 0x1c, 0xba, 0x10, 0xe5, 0xf7, 0x7f, 0x79, 0x1c, 0xbf, - 0xc3, 0x28, 0x40, 0xe3, 0x0e, 0x56, 0x23, 0x25, 0x86, 0x9d, 0x2c, 0xf0, - 0xaf, 0xe4, 0x77, 0xe9, 0x7d, 0x57, 0x84, 0x54, 0xe5, 0x7d, 0x3f, 0xc8, - 0x4a, 0xb9, 0xc0, 0x72, 0xfd, 0x34, 0xa0, 0x64, 0x72, 0x8e, 0x56, 0x1b, - 0x31, 0x28, 0xbe, 0x80, 0x63, 0x67, 0x2e, 0x4f, 0xbb, 0x44, 0x50, 0xa4, - 0xa8, 0x3f, 0x7f, 0xd2, 0xfb, 0x9b, 0x5b, 0xba, 0xcd, 0x12, 0x4a, 0xdf, - 0x7a, 0x88, 0x47, 0x3d, 0xb9, 0xb0, 0x1c, 0xbf, 0xcf, 0xe1, 0xc9, 0xdc, - 0x4e, 0x5c, 0xab, 0x67, 0x2f, 0xe9, 0x3e, 0xe7, 0x0c, 0x1c, 0xbf, 0xb0, - 0x5f, 0x99, 0x68, 0xe5, 0xff, 0xfb, 0xf1, 0x75, 0x7c, 0xac, 0x0c, 0xb3, - 0xa8, 0xc3, 0x97, 0xf4, 0x33, 0x78, 0x1f, 0x1c, 0xb9, 0xfe, 0x85, 0x34, - 0x05, 0x46, 0x39, 0x31, 0x98, 0x67, 0x65, 0xcc, 0x2d, 0xd2, 0xb5, 0x4e, - 0xdb, 0xd3, 0x4a, 0xb1, 0xcc, 0x59, 0xc4, 0xcb, 0x40, 0x86, 0x4e, 0xa3, - 0x6f, 0xf4, 0x66, 0x3c, 0x63, 0x6a, 0xbf, 0xf2, 0xaf, 0xf7, 0x36, 0xb7, - 0x75, 0x9a, 0x2d, 0x45, 0xff, 0x9e, 0x5f, 0x73, 0x6b, 0x77, 0x59, 0xa2, - 0x55, 0x5c, 0x8d, 0x9c, 0xa3, 0x96, 0xfa, 0xaa, 0x2e, 0xd8, 0x9b, 0xe4, - 0xce, 0x01, 0x7b, 0xfb, 0x36, 0xb7, 0x75, 0x9a, 0x22, 0x95, 0xff, 0x9d, - 0xd9, 0x9b, 0x00, 0xfe, 0x03, 0x97, 0xfe, 0x8f, 0x6b, 0x36, 0x01, 0xfc, - 0x07, 0x2f, 0x93, 0x50, 0xe7, 0x2f, 0xf0, 0xb8, 0x35, 0xec, 0x59, 0xcb, - 0x99, 0xf7, 0xa8, 0xcf, 0x13, 0xed, 0x1f, 0xf8, 0x82, 0xbe, 0xa6, 0xa4, - 0xf1, 0x84, 0x5f, 0xef, 0xb9, 0xb5, 0xbb, 0xac, 0xd1, 0x1a, 0x2e, 0xff, - 0xa7, 0x2f, 0xfc, 0x1c, 0x62, 0x6f, 0x35, 0x34, 0x1c, 0xbf, 0xff, 0xe7, - 0xff, 0x5d, 0xc0, 0xa8, 0xa6, 0x91, 0x4f, 0x26, 0xa6, 0x50, 0xe5, 0xff, - 0xe9, 0x91, 0x3b, 0x36, 0x7a, 0x3d, 0x01, 0x39, 0x79, 0x1d, 0xb2, 0x94, - 0x89, 0x88, 0xb5, 0x9f, 0x4c, 0xda, 0xc4, 0xab, 0xe5, 0xbb, 0xac, 0xd1, - 0x4f, 0xae, 0xf4, 0x1c, 0xad, 0x9e, 0x27, 0x8b, 0xaf, 0xfd, 0xe9, 0xa3, - 0xdd, 0x79, 0xbe, 0x61, 0xcb, 0xdf, 0xf7, 0xf3, 0x97, 0xff, 0x91, 0x83, - 0xff, 0x53, 0x79, 0xa9, 0xa0, 0xe5, 0xff, 0xdf, 0xfb, 0x7f, 0xcd, 0xa5, - 0xbc, 0xda, 0x39, 0x7f, 0xf6, 0x4d, 0xf8, 0xcf, 0xa5, 0xbc, 0xda, 0x39, - 0x7d, 0xff, 0x53, 0x67, 0x2d, 0xf5, 0xab, 0x56, 0x61, 0x11, 0x94, 0xe4, - 0x21, 0x50, 0x8b, 0xa8, 0x4e, 0x3e, 0x29, 0x5e, 0x4a, 0x68, 0x91, 0x7f, - 0xfb, 0xeb, 0x1e, 0x5f, 0x73, 0x6b, 0x77, 0x59, 0xa2, 0x6a, 0x5f, 0xd9, - 0xb5, 0xbb, 0xac, 0xd1, 0x5d, 0xaf, 0xff, 0x67, 0x02, 0x79, 0x25, 0xf0, - 0x63, 0xda, 0x39, 0x47, 0x2e, 0x6f, 0xef, 0x4f, 0x61, 0xb4, 0xda, 0xfa, - 0x8c, 0x34, 0x84, 0x8d, 0xed, 0x43, 0x0e, 0x5c, 0xc1, 0x39, 0x7c, 0xb7, - 0x75, 0x9a, 0x2b, 0xe5, 0xe6, 0xdb, 0x6c, 0xa5, 0x84, 0xa7, 0xd3, 0x41, - 0x5b, 0x3f, 0x06, 0x27, 0x5e, 0x94, 0x72, 0x72, 0xf4, 0xd9, 0xd3, 0x97, - 0xfe, 0xce, 0xb6, 0xfe, 0xd4, 0x64, 0xe7, 0x2d, 0xe3, 0x97, 0xfc, 0x9b, - 0xc9, 0xd2, 0x58, 0x13, 0x95, 0xb3, 0xc9, 0x71, 0x1b, 0xf7, 0x3c, 0x1d, - 0xfd, 0x43, 0x96, 0xd9, 0xca, 0x39, 0x48, 0x5e, 0x6c, 0x46, 0xe9, 0xd5, - 0x39, 0x5d, 0x37, 0x0e, 0x3f, 0x6f, 0xb0, 0xa9, 0x2a, 0x71, 0xcc, 0x84, - 0x34, 0xc4, 0x4e, 0x3a, 0x23, 0xba, 0x84, 0x47, 0xe4, 0x2d, 0x21, 0x07, - 0x7f, 0xfb, 0xeb, 0x1e, 0x5f, 0x73, 0x6b, 0x77, 0x59, 0xa2, 0x7b, 0x5f, - 0x47, 0x03, 0xf2, 0x72, 0xf2, 0x08, 0x0e, 0x57, 0x4f, 0x03, 0x89, 0x2d, - 0xfb, 0x6b, 0x77, 0x59, 0xa2, 0xe1, 0x5b, 0xec, 0x1e, 0xc6, 0x12, 0x5f, - 0xfd, 0xf5, 0xe5, 0xf7, 0x36, 0xb7, 0x75, 0x9a, 0x24, 0xf5, 0x43, 0x2d, - 0x8a, 0x78, 0xe6, 0xe4, 0x56, 0xac, 0xb7, 0x15, 0xc2, 0x56, 0x68, 0xc7, - 0x77, 0x29, 0xcf, 0xb0, 0x98, 0xd4, 0x3c, 0xb8, 0x94, 0x5f, 0xef, 0xb9, - 0xb5, 0xbb, 0xac, 0xd1, 0x15, 0x2f, 0xdb, 0x5b, 0xba, 0xcd, 0x14, 0xca, - 0xfe, 0x4e, 0xe3, 0xf2, 0x03, 0x96, 0xfb, 0x87, 0xc2, 0xd0, 0xd2, 0xff, - 0xf7, 0xd6, 0x3c, 0xbe, 0xe6, 0xd6, 0xee, 0xb3, 0x44, 0xce, 0xbf, 0xfd, - 0xf5, 0x8f, 0x2f, 0xb9, 0xb5, 0xbb, 0xac, 0xd1, 0x46, 0xaa, 0x74, 0xe0, - 0x43, 0x0a, 0x25, 0x4a, 0xfc, 0xb5, 0x7f, 0xe7, 0x97, 0xdc, 0xda, 0xdd, - 0xd6, 0x68, 0x8e, 0x97, 0xff, 0x6e, 0x7f, 0xba, 0x1c, 0xf6, 0xa1, 0x87, - 0x2b, 0xea, 0x24, 0xe1, 0x32, 0xef, 0xfa, 0x72, 0xf9, 0x6b, 0xfd, 0x67, - 0x2f, 0xd8, 0x21, 0xc9, 0xce, 0x5f, 0xe8, 0x85, 0xe6, 0xf7, 0x87, 0x29, - 0x0f, 0x60, 0x49, 0xef, 0xd9, 0xb5, 0xfe, 0xa9, 0xcb, 0xff, 0x0e, 0x2a, - 0xf3, 0x6b, 0xb0, 0x13, 0x97, 0xa6, 0x7f, 0x1c, 0xbe, 0x5b, 0xba, 0xcd, - 0x14, 0xd2, 0xfd, 0x9c, 0xb6, 0xfd, 0x39, 0x7f, 0xf6, 0xb0, 0x43, 0x1f, - 0x1a, 0x9f, 0x10, 0x21, 0xca, 0x0a, 0x65, 0x48, 0x55, 0x31, 0xfe, 0xc7, - 0x44, 0xbb, 0x45, 0x37, 0xff, 0xfd, 0x83, 0xed, 0x22, 0xf0, 0x74, 0xbe, - 0xa7, 0x56, 0xa4, 0xe7, 0x2f, 0xfb, 0x4f, 0xce, 0x4d, 0x1d, 0xd1, 0xcb, - 0xba, 0x82, 0x8a, 0x1f, 0x33, 0xdf, 0xfd, 0x2e, 0xa0, 0xcf, 0xaf, 0xe3, - 0x73, 0x1c, 0xbc, 0x0f, 0x21, 0xcb, 0xfd, 0xa5, 0xa6, 0xf6, 0x93, 0x9c, - 0xa7, 0x3d, 0x0d, 0x0e, 0x5f, 0xef, 0xdc, 0x57, 0xf2, 0x7d, 0x1c, 0xbf, - 0xe6, 0xdc, 0x0f, 0xef, 0x67, 0x4e, 0x5d, 0xdf, 0xce, 0x56, 0x1e, 0x88, - 0x0e, 0x6f, 0xf7, 0x61, 0x00, 0xfe, 0xfc, 0xe5, 0xff, 0x87, 0xff, 0x77, - 0x26, 0x94, 0x72, 0x72, 0xd3, 0x1c, 0xbf, 0x67, 0x5c, 0x42, 0x72, 0xa7, - 0x37, 0x00, 0x12, 0xba, 0x15, 0x39, 0x7f, 0x38, 0x35, 0xc2, 0xb8, 0x57, - 0x0a, 0x39, 0x7f, 0x24, 0x32, 0x7c, 0x6c, 0xe5, 0xff, 0xf6, 0x7b, 0xb9, - 0x2d, 0xb8, 0xfb, 0xaf, 0x23, 0x97, 0x40, 0x0e, 0x5f, 0xe7, 0xe6, 0x16, - 0x8b, 0xfb, 0xb4, 0x49, 0x09, 0x72, 0x89, 0xd5, 0x89, 0xef, 0x23, 0xcf, - 0x48, 0x84, 0x5f, 0x50, 0xd2, 0xbf, 0x03, 0xb1, 0x2d, 0x1c, 0xbc, 0xdb, - 0xce, 0x72, 0xff, 0xa0, 0x0f, 0xe0, 0x28, 0x32, 0x39, 0x5d, 0x3d, 0x71, - 0x1e, 0xa8, 0x45, 0x07, 0x9f, 0xed, 0xf5, 0xab, 0x5f, 0x84, 0x81, 0x80, - 0xbe, 0x64, 0x69, 0x4b, 0x87, 0xc7, 0x25, 0xbb, 0x84, 0xb8, 0x08, 0x46, - 0x11, 0x1a, 0x21, 0xf4, 0xa1, 0x15, 0x21, 0xdb, 0x7e, 0xda, 0xdd, 0xd6, - 0x68, 0xaa, 0x97, 0xfe, 0x79, 0x7d, 0xcd, 0xad, 0xdd, 0x66, 0x89, 0xb5, - 0x6f, 0xb8, 0x88, 0x06, 0x1a, 0x5f, 0xef, 0xb9, 0xb5, 0xbb, 0xac, 0xd1, - 0x5f, 0xaf, 0xdb, 0x5b, 0xba, 0xcd, 0x16, 0x32, 0xee, 0x09, 0x1c, 0xb7, - 0xdc, 0x3c, 0xe9, 0x8d, 0x2f, 0xda, 0x5f, 0x61, 0x53, 0x97, 0xf8, 0x7f, - 0x96, 0x69, 0xfc, 0x72, 0xfe, 0x6a, 0x82, 0xd5, 0xb5, 0x62, 0xa9, 0xcb, - 0xfe, 0x1f, 0xe7, 0x9a, 0x51, 0xb9, 0xce, 0x5d, 0xbf, 0x1c, 0xbe, 0x79, - 0x60, 0x4e, 0x5f, 0xde, 0xcd, 0x87, 0x04, 0xe5, 0xb0, 0x27, 0x9b, 0xe2, - 0x1b, 0xca, 0xcb, 0x0e, 0x5b, 0xee, 0x26, 0xac, 0xc3, 0x3e, 0x9f, 0x39, - 0xe8, 0xb2, 0x68, 0x9e, 0xc9, 0xf5, 0x3d, 0xcd, 0xc6, 0xff, 0x7e, 0xda, - 0xdd, 0xd6, 0x68, 0xb5, 0x57, 0xfe, 0x79, 0x7d, 0xcd, 0xad, 0xdd, 0x66, - 0x8a, 0x09, 0x7e, 0x86, 0xda, 0x66, 0xce, 0x5b, 0xee, 0x22, 0xa9, 0x86, - 0x8a, 0x26, 0x5f, 0xf9, 0xdb, 0xf6, 0x77, 0xeb, 0xef, 0xc7, 0x2f, 0xf4, - 0x08, 0x21, 0xad, 0xd8, 0x72, 0xff, 0xf4, 0xd1, 0xc5, 0xf7, 0xad, 0x26, - 0xf1, 0x53, 0x97, 0xfd, 0x09, 0x34, 0x71, 0x7d, 0xe8, 0xe5, 0xdb, 0x83, - 0x95, 0x24, 0x68, 0xa1, 0xa7, 0x53, 0x78, 0x0e, 0xaf, 0x96, 0xee, 0xb3, - 0x45, 0xc4, 0xbf, 0xbf, 0x7e, 0x43, 0x9b, 0x39, 0x5b, 0x3d, 0xdd, 0x17, - 0x5e, 0xdc, 0x30, 0xe5, 0xf3, 0xf0, 0x24, 0xe7, 0x2f, 0xdd, 0xfd, 0x5c, - 0x13, 0x97, 0xe0, 0xe3, 0x5c, 0x74, 0xe5, 0xee, 0x04, 0x59, 0xca, 0x09, - 0xf9, 0x6c, 0xa7, 0x80, 0xaa, 0xff, 0x31, 0xe5, 0xa4, 0x0e, 0x1c, 0xbe, - 0x85, 0x63, 0x47, 0x2f, 0xc3, 0xe1, 0x75, 0x4e, 0x51, 0xcb, 0x6b, 0x0d, - 0x93, 0x42, 0x7b, 0xf9, 0x8f, 0xc6, 0x37, 0xc0, 0x72, 0xff, 0xc8, 0x1c, - 0xe2, 0xcc, 0x97, 0x32, 0x39, 0x50, 0x7e, 0x78, 0x65, 0x7f, 0x66, 0xdf, - 0xdf, 0xc1, 0xcb, 0xff, 0xe7, 0x18, 0x4e, 0x0d, 0x26, 0xb3, 0xb8, 0xd0, - 0xe5, 0x04, 0xff, 0xb8, 0x96, 0xdf, 0xfc, 0x83, 0xfc, 0xb3, 0x5a, 0x40, - 0xe1, 0xca, 0x98, 0xf9, 0xfc, 0x49, 0x6f, 0xb0, 0xaf, 0xb3, 0x21, 0x39, - 0xb2, 0x2e, 0x8e, 0x3c, 0x25, 0xc0, 0x64, 0x26, 0x5a, 0x54, 0xf4, 0x26, - 0xd4, 0x8c, 0x16, 0xfd, 0xc3, 0x70, 0xb8, 0x15, 0x83, 0x97, 0xfe, 0x4e, - 0x78, 0x56, 0xb7, 0xf3, 0xe7, 0x5a, 0x1c, 0xbe, 0xec, 0x79, 0x67, 0x29, - 0xa9, 0x1f, 0x78, 0x53, 0x6f, 0xff, 0x70, 0xa5, 0x5b, 0x6b, 0x9c, 0x3c, - 0x37, 0xcf, 0x9d, 0x68, 0x72, 0xfd, 0xb5, 0xbb, 0xac, 0xd1, 0x74, 0xaf, - 0xd0, 0x2e, 0x18, 0x39, 0x7a, 0x3d, 0xc0, 0x72, 0xfb, 0x03, 0x81, 0x39, - 0x7f, 0xcf, 0xc6, 0x3d, 0xaf, 0xd7, 0xc3, 0x9c, 0xbe, 0xd4, 0xee, 0xa1, - 0xcb, 0x7d, 0xe1, 0x4a, 0x8b, 0xa2, 0x14, 0x92, 0x28, 0xc6, 0x44, 0x34, - 0xe9, 0x2b, 0x8f, 0x89, 0x0f, 0x90, 0x6f, 0xff, 0xb0, 0x7c, 0x8c, 0xec, - 0x20, 0xbe, 0xd5, 0x39, 0x7f, 0x66, 0x69, 0x7e, 0x83, 0x97, 0xf4, 0xf1, - 0xe7, 0x57, 0xf3, 0x94, 0x72, 0xff, 0xe8, 0xd8, 0x3e, 0x6b, 0xb0, 0xc7, - 0x13, 0x97, 0xfa, 0x36, 0xa7, 0x7b, 0x80, 0x39, 0x52, 0x3f, 0x9e, 0xa2, - 0xdf, 0xd2, 0x79, 0x38, 0xac, 0xe5, 0xff, 0xec, 0xf4, 0x36, 0xa4, 0xfa, - 0xc6, 0x43, 0x59, 0xcb, 0x7d, 0x6a, 0x93, 0x21, 0xc8, 0x42, 0x4c, 0x44, - 0x25, 0x95, 0xb4, 0xe8, 0x19, 0x1a, 0x8d, 0xf6, 0x36, 0xd5, 0x30, 0xe5, - 0xfc, 0x31, 0xcb, 0x1f, 0xc7, 0x2f, 0xff, 0x36, 0xe1, 0xec, 0x73, 0xe8, - 0xeb, 0xb5, 0x9c, 0xb2, 0x6c, 0xfe, 0xfa, 0x5b, 0x7f, 0xff, 0xdf, 0xee, - 0x5a, 0xeb, 0xa6, 0xf7, 0xbf, 0xf9, 0x4d, 0xbe, 0x8e, 0x5f, 0xf8, 0x5d, - 0xbf, 0x67, 0x5e, 0x67, 0x39, 0x7f, 0xff, 0x74, 0x7f, 0x76, 0xbc, 0x97, - 0x71, 0x5c, 0x0c, 0xdf, 0x9c, 0xb9, 0x78, 0x72, 0xa0, 0xfd, 0xd5, 0x61, - 0xbf, 0xcf, 0xed, 0x47, 0x54, 0x98, 0xe5, 0xe9, 0x43, 0x0e, 0x5e, 0x57, - 0x52, 0x39, 0x7f, 0xe9, 0x66, 0xf6, 0xf2, 0x9f, 0x1b, 0x39, 0x7f, 0xf6, - 0x06, 0x25, 0x1b, 0x85, 0x1c, 0x4e, 0x5f, 0xfb, 0x8e, 0x49, 0x81, 0x4e, - 0x30, 0x13, 0x94, 0xc4, 0x42, 0x3a, 0x15, 0xcf, 0xf6, 0x75, 0x52, 0xd3, - 0x35, 0x6e, 0x16, 0xbd, 0x22, 0x73, 0x5d, 0x0e, 0x78, 0x79, 0x48, 0x62, - 0x57, 0x55, 0xa4, 0x8c, 0xab, 0xdb, 0xfd, 0x2c, 0xf7, 0x61, 0x41, 0x39, - 0x7f, 0xef, 0x22, 0xd0, 0x2e, 0x2a, 0xc1, 0xcb, 0xfe, 0x8e, 0x7a, 0xfa, - 0xf4, 0x36, 0x72, 0xa0, 0xfd, 0xf6, 0x7b, 0x77, 0xfd, 0x39, 0x7e, 0x1c, - 0xeb, 0xf8, 0xe5, 0xfd, 0x27, 0xce, 0x30, 0x13, 0x95, 0xc2, 0x1e, 0xa3, - 0x53, 0x26, 0xbe, 0x4f, 0xe5, 0x07, 0x2f, 0xcf, 0x34, 0x93, 0xc7, 0x2f, - 0xfd, 0x01, 0xdc, 0x49, 0x39, 0xf6, 0x1c, 0xa9, 0x22, 0x20, 0x04, 0x5e, - 0x28, 0xbf, 0xf4, 0x6f, 0x5d, 0x45, 0xaf, 0xf9, 0xce, 0x5f, 0xff, 0xf4, - 0x07, 0xb9, 0xcf, 0x85, 0xfa, 0x07, 0xd6, 0x9f, 0x6b, 0x39, 0x7f, 0xb3, - 0x31, 0x55, 0x5e, 0x47, 0x29, 0x54, 0x4c, 0xf9, 0x9a, 0xfd, 0x9a, 0x5f, - 0xa0, 0xe5, 0xff, 0xe4, 0x6f, 0x4b, 0xea, 0x73, 0xed, 0xee, 0x0e, 0x5f, - 0xff, 0xf3, 0xb6, 0xa6, 0x6c, 0x5f, 0x99, 0x2e, 0x3d, 0xac, 0xe7, 0xc7, - 0x2b, 0x11, 0xb9, 0xb2, 0x77, 0x4c, 0xbf, 0x71, 0x4d, 0xe0, 0x4e, 0x5f, - 0xff, 0x6b, 0xa9, 0xaf, 0x77, 0x02, 0x9a, 0xc1, 0x39, 0x7b, 0xb0, 0x38, - 0x7e, 0xff, 0x94, 0xdf, 0xe8, 0x66, 0x23, 0x21, 0xac, 0xe5, 0xfe, 0x93, - 0x34, 0x83, 0xcc, 0x8e, 0x52, 0xcf, 0xa2, 0x63, 0x4b, 0xff, 0xd9, 0xbd, - 0xbc, 0xb4, 0x38, 0xc5, 0x39, 0x39, 0x79, 0xdd, 0x66, 0x89, 0x31, 0x7b, - 0x81, 0x34, 0x72, 0x96, 0x78, 0xfc, 0x05, 0x17, 0xe5, 0xf0, 0xae, 0x19, - 0xaa, 0xe1, 0x0e, 0x5f, 0xfe, 0xe6, 0x5a, 0xce, 0x2e, 0xcc, 0x56, 0x34, - 0x72, 0xff, 0x67, 0x3e, 0xf3, 0xcb, 0x47, 0x2a, 0x11, 0x7f, 0x87, 0xdb, - 0x4d, 0xbf, 0xc2, 0xfe, 0xd2, 0xff, 0x13, 0x97, 0xff, 0xc0, 0x40, 0x37, - 0x89, 0xc4, 0x73, 0xdd, 0x43, 0x97, 0xf9, 0xf9, 0xd3, 0xbc, 0xb4, 0x72, - 0xdb, 0xc4, 0x41, 0xf5, 0x42, 0xb1, 0x1b, 0xc9, 0x0b, 0x6b, 0xff, 0xfd, - 0xfb, 0xf3, 0x83, 0x0d, 0xa9, 0xe1, 0x80, 0x67, 0x3e, 0x39, 0x52, 0x57, - 0x91, 0x90, 0x9a, 0x59, 0x1e, 0xe1, 0x24, 0xc8, 0x72, 0x76, 0x30, 0xcd, - 0x13, 0x5f, 0xc1, 0x07, 0x09, 0xa0, 0x34, 0x39, 0x7b, 0x48, 0x13, 0x97, - 0xf0, 0xc7, 0x2c, 0x7f, 0x1c, 0xbf, 0xe8, 0x5f, 0xbf, 0xee, 0xe1, 0xb3, - 0x97, 0xf9, 0x69, 0xbd, 0x4d, 0x0e, 0x72, 0xff, 0xef, 0xf5, 0xd7, 0x97, - 0x5e, 0x50, 0x27, 0x2b, 0x93, 0xf7, 0xd9, 0x9d, 0xdd, 0x49, 0x93, 0x1e, - 0xd8, 0xe3, 0x0b, 0x7d, 0x0b, 0x2b, 0xef, 0x23, 0x1c, 0xe5, 0x95, 0x39, - 0x7f, 0x77, 0x51, 0xe8, 0x09, 0xca, 0xc3, 0x7e, 0x82, 0x55, 0x87, 0xff, - 0xe6, 0x0b, 0xfe, 0x8e, 0xf9, 0x27, 0x64, 0x2c, 0xe5, 0xff, 0xf9, 0xd7, - 0xb8, 0xe8, 0xe7, 0xb3, 0xeb, 0x6d, 0xb6, 0x52, 0xa4, 0x8b, 0x3d, 0x10, - 0xf8, 0xe6, 0xfe, 0x5a, 0xff, 0x58, 0xc1, 0xcb, 0xff, 0xd9, 0xcc, 0x86, - 0x25, 0xb8, 0xf3, 0xf8, 0xe5, 0xff, 0x9f, 0xd1, 0xbd, 0x76, 0x07, 0xc7, - 0x2f, 0xd9, 0x24, 0x7e, 0x27, 0x28, 0x4f, 0x97, 0x47, 0xb5, 0x24, 0x67, - 0xff, 0x0a, 0xeb, 0xcc, 0x7e, 0x9c, 0xbf, 0xfc, 0x31, 0x2d, 0xef, 0xfe, - 0x53, 0x6f, 0xa3, 0x97, 0xff, 0xda, 0xc5, 0x47, 0x3d, 0xac, 0x90, 0xbb, - 0x67, 0x2c, 0x9d, 0x44, 0xd7, 0x92, 0xe9, 0x11, 0xbd, 0xc6, 0x16, 0xd7, - 0xdc, 0x11, 0xdd, 0x1c, 0xbf, 0xec, 0x9f, 0xc3, 0x1f, 0xfb, 0x47, 0x2a, - 0x11, 0x11, 0x85, 0x3b, 0x25, 0xbc, 0x00, 0x41, 0xcb, 0xf0, 0xff, 0x3f, - 0x2d, 0x67, 0x2b, 0x47, 0x95, 0xe1, 0xcb, 0xff, 0xd1, 0x38, 0xe6, 0x4f, - 0xe5, 0x60, 0x64, 0x72, 0xff, 0xce, 0x33, 0xf5, 0xd8, 0x9a, 0x43, 0x94, - 0xe8, 0xa9, 0x12, 0x26, 0xd2, 0xaf, 0x36, 0xdb, 0x65, 0x2f, 0xa7, 0x62, - 0x68, 0xa7, 0xd3, 0x41, 0x74, 0x04, 0xe5, 0xb6, 0xe7, 0x96, 0x26, 0xb7, - 0xe8, 0xc1, 0x76, 0x1c, 0xbf, 0xf3, 0xcb, 0xa9, 0xc8, 0x36, 0xe1, 0x39, - 0x7f, 0xff, 0xe7, 0x15, 0xef, 0x38, 0xc0, 0xf9, 0x91, 0x82, 0x1c, 0xe7, - 0xc7, 0x28, 0x08, 0xcf, 0x12, 0x5f, 0xcf, 0xef, 0xf4, 0xa3, 0x73, 0xc6, - 0xe7, 0x39, 0x7f, 0x6b, 0x49, 0x82, 0x03, 0x97, 0xb7, 0x8d, 0x67, 0x2f, - 0xfd, 0x0d, 0xa9, 0x3e, 0xb1, 0x90, 0xd6, 0x72, 0xb6, 0x88, 0xf6, 0x16, - 0x78, 0x7e, 0xa1, 0x1e, 0x99, 0x0c, 0x4b, 0xff, 0xe4, 0x98, 0x63, 0xda, - 0xf7, 0x2b, 0x41, 0x9c, 0xe5, 0xff, 0xff, 0xe4, 0x10, 0x28, 0x39, 0xbd, - 0xe3, 0x78, 0xd7, 0x83, 0x00, 0x63, 0xc8, 0xe5, 0xff, 0xfd, 0xed, 0x7e, - 0x1e, 0xa6, 0x4c, 0xe8, 0xd6, 0x9c, 0xc8, 0xe5, 0xff, 0xfc, 0x38, 0x07, - 0x10, 0x6f, 0x78, 0xde, 0x01, 0xf9, 0x39, 0x42, 0x8b, 0xaf, 0x30, 0x5f, - 0x93, 0xd3, 0xe3, 0x67, 0x2f, 0xfa, 0x17, 0xd1, 0xff, 0xd1, 0xa3, 0x97, - 0xff, 0x27, 0x04, 0x2e, 0x19, 0x81, 0x76, 0x1c, 0xbf, 0xff, 0x7b, 0xb9, - 0x2f, 0x8b, 0xea, 0x7b, 0x95, 0xa6, 0xce, 0x54, 0x95, 0x2a, 0x24, 0x66, - 0x5b, 0x22, 0x61, 0x4f, 0x4e, 0x45, 0x16, 0xff, 0xff, 0xe7, 0x4f, 0x7f, - 0xb7, 0xd2, 0xfa, 0x93, 0x0b, 0xb7, 0xec, 0xeb, 0x0e, 0x5f, 0xf3, 0x23, - 0x7c, 0x73, 0x71, 0x31, 0xcb, 0xff, 0x6d, 0x6c, 0x8e, 0x75, 0x9c, 0x70, - 0xe5, 0xfe, 0x10, 0x34, 0xc0, 0xe3, 0x0e, 0x5f, 0xc3, 0xf1, 0xa6, 0x6e, - 0x0e, 0x54, 0x22, 0x97, 0x10, 0x5c, 0xd2, 0xff, 0xb1, 0xc1, 0xf3, 0x02, - 0xf2, 0x39, 0x7f, 0xf9, 0xe7, 0xea, 0x40, 0xe4, 0xc9, 0xb4, 0x39, 0x41, - 0x5d, 0x03, 0xc9, 0x54, 0xbd, 0x5d, 0x03, 0x9e, 0xa1, 0xc1, 0xe2, 0xd6, - 0xce, 0x6f, 0xc3, 0x9d, 0x7f, 0x1c, 0xbf, 0xf4, 0xa0, 0x67, 0x53, 0x63, - 0xfc, 0x8e, 0x5f, 0xc2, 0xe1, 0x07, 0x20, 0x39, 0x4d, 0x68, 0x95, 0x98, - 0x9b, 0x48, 0x37, 0xde, 0x9f, 0x02, 0x72, 0xff, 0x91, 0x55, 0x36, 0x06, - 0x26, 0x8e, 0x54, 0xc7, 0xbc, 0xd0, 0x8e, 0xf3, 0x6d, 0xb6, 0x72, 0xff, - 0xfd, 0x8c, 0xf0, 0xc0, 0x30, 0x3a, 0xc6, 0x42, 0xca, 0x7d, 0x34, 0x17, - 0xfe, 0xce, 0x7e, 0x0e, 0x71, 0xda, 0x68, 0xe5, 0xfc, 0xbe, 0xa4, 0x0a, - 0xce, 0x54, 0x1f, 0x76, 0x21, 0x5f, 0xed, 0xc7, 0x91, 0x68, 0x13, 0x97, - 0xe9, 0x4d, 0x98, 0xb3, 0x96, 0xd9, 0xca, 0x6a, 0x0f, 0xae, 0x0c, 0x94, - 0x28, 0xac, 0x54, 0xd2, 0x90, 0x92, 0xea, 0x28, 0xc3, 0x4f, 0x50, 0x8b, - 0xbd, 0xe9, 0x74, 0xe5, 0x90, 0xe5, 0xfd, 0xd8, 0xf8, 0xb4, 0x9c, 0xe5, - 0xff, 0xe9, 0xba, 0xec, 0xcd, 0xaa, 0xaf, 0xe3, 0xe3, 0x97, 0xf6, 0xdf, - 0x63, 0x12, 0x39, 0x7f, 0xfc, 0xfe, 0xee, 0x71, 0xea, 0x7c, 0xd6, 0x91, - 0x87, 0x2f, 0xfc, 0x92, 0x4d, 0xf3, 0x03, 0x1a, 0x39, 0x5c, 0x2e, 0x9a, - 0x50, 0x44, 0x30, 0xc3, 0x69, 0xc2, 0x59, 0xe5, 0x3b, 0xa5, 0xf5, 0xab, - 0x6f, 0x0b, 0x78, 0x66, 0xc8, 0x85, 0xac, 0xe6, 0x12, 0x86, 0xd0, 0x63, - 0x00, 0xc9, 0xc6, 0xd5, 0x5e, 0x97, 0x1a, 0xa7, 0x31, 0xc0, 0xa1, 0x84, - 0xd0, 0xfd, 0xdc, 0x71, 0xfd, 0x8c, 0x85, 0xe1, 0x34, 0x08, 0x7a, 0x8c, - 0x64, 0x9a, 0x9d, 0x29, 0xf4, 0xb7, 0x16, 0x8b, 0x0a, 0x46, 0xcf, 0x7f, - 0xfb, 0x78, 0xd8, 0x7b, 0x93, 0x0e, 0x6e, 0x47, 0x2f, 0x6f, 0x1a, 0xce, - 0x5f, 0xfa, 0x1b, 0x52, 0x7d, 0x63, 0x21, 0xac, 0xe5, 0x6d, 0x15, 0xcc, - 0x4b, 0xf0, 0xfd, 0xff, 0xf3, 0xb2, 0x36, 0xbd, 0xfe, 0xae, 0xff, 0x7d, - 0x1c, 0xac, 0x44, 0x1f, 0xe6, 0x17, 0xfb, 0x6b, 0xfd, 0xc2, 0xc8, 0x39, - 0x7f, 0xf4, 0x6d, 0x4f, 0x27, 0xbb, 0x81, 0x43, 0x97, 0xfe, 0xe8, 0xc4, - 0xea, 0x77, 0xae, 0xd6, 0x72, 0xa1, 0x17, 0x73, 0x9a, 0x62, 0x25, 0xe6, - 0xa6, 0xd4, 0x48, 0xe5, 0xe7, 0xdc, 0xe7, 0x2e, 0x6d, 0xb3, 0x97, 0x9d, - 0x7f, 0x56, 0x6d, 0x9b, 0x1d, 0xbf, 0xa3, 0x6f, 0x24, 0xe9, 0xcb, 0xf6, - 0x33, 0xae, 0x13, 0x96, 0xfb, 0x0e, 0xa0, 0x24, 0x29, 0xb9, 0x1e, 0x62, - 0xa5, 0x4b, 0x97, 0xd9, 0x31, 0x5e, 0xe1, 0x54, 0xf5, 0xe2, 0x70, 0xca, - 0xc4, 0xd4, 0x37, 0xbc, 0x5f, 0xc5, 0x79, 0xb3, 0x5e, 0x02, 0xca, 0x93, - 0xbe, 0x32, 0x0c, 0xfd, 0x47, 0x31, 0xaa, 0xec, 0xa9, 0x90, 0x8f, 0xec, - 0xa0, 0x60, 0x43, 0x6c, 0x4e, 0x35, 0x39, 0xfd, 0xe9, 0x5a, 0xbf, 0xda, - 0x89, 0x7b, 0xfb, 0x51, 0x34, 0x92, 0x63, 0x97, 0xfd, 0xe8, 0x14, 0x06, - 0x73, 0xe3, 0x97, 0xcd, 0x1c, 0x40, 0x72, 0xe8, 0x9f, 0x0f, 0x6d, 0x43, - 0x8b, 0x7d, 0xd2, 0x2e, 0x14, 0x84, 0x55, 0xff, 0x9d, 0x7f, 0x7f, 0x02, - 0x4b, 0x24, 0x72, 0xfd, 0xb5, 0xbb, 0xac, 0xd1, 0x1a, 0xaf, 0x2b, 0xce, - 0x8e, 0x5b, 0xec, 0xe8, 0x94, 0xc4, 0x1f, 0x1a, 0x5f, 0xff, 0xee, 0x30, - 0x3e, 0xfa, 0xfc, 0x5c, 0x38, 0x17, 0x63, 0x84, 0xe5, 0xfb, 0x6b, 0x77, - 0x59, 0xa2, 0xa5, 0x5c, 0xeb, 0x34, 0x43, 0x4b, 0x7d, 0xc3, 0xd7, 0x73, - 0x4b, 0xf6, 0xd6, 0xee, 0xb3, 0x44, 0x7c, 0xbf, 0xfb, 0xfd, 0x81, 0x7d, - 0x49, 0x86, 0x00, 0x72, 0xff, 0xf8, 0x5f, 0xd2, 0x85, 0x7e, 0x47, 0xb5, - 0x00, 0x39, 0x79, 0xe5, 0xf7, 0x11, 0x97, 0xa3, 0x45, 0x11, 0xaf, 0xfc, - 0xf3, 0xc7, 0x53, 0x69, 0x0c, 0x39, 0x7f, 0xa3, 0x78, 0x3e, 0xce, 0x9c, - 0xbc, 0xcc, 0xfa, 0xd0, 0xfb, 0x94, 0x3d, 0xaf, 0xa8, 0xe9, 0x88, 0x58, - 0xdf, 0xff, 0xf4, 0xbf, 0xda, 0xaf, 0xac, 0x0c, 0x73, 0xa5, 0x3c, 0xaa, - 0x2a, 0x72, 0xf3, 0x6a, 0xac, 0xe5, 0xfb, 0x9e, 0x65, 0x9e, 0x39, 0x5a, - 0x3c, 0x9f, 0xc7, 0xef, 0xff, 0x70, 0xa5, 0x5b, 0x6b, 0x9c, 0x3c, 0x37, - 0xcf, 0x9d, 0x68, 0x72, 0xfd, 0xb5, 0xbb, 0xac, 0xd1, 0x63, 0xaf, 0xf6, - 0x20, 0xcf, 0xec, 0xe9, 0xcb, 0x9f, 0x47, 0x2f, 0xe9, 0xd4, 0xde, 0xf3, - 0x67, 0x2a, 0x47, 0x8c, 0xe2, 0xd7, 0xfc, 0x2e, 0xaf, 0x52, 0x06, 0x73, - 0x97, 0xff, 0xf7, 0xe2, 0xea, 0xfc, 0xf2, 0xb0, 0x32, 0xce, 0xa3, 0x0e, - 0x5f, 0xff, 0x81, 0x29, 0xf8, 0x54, 0x35, 0x73, 0xaf, 0x7f, 0x3e, 0x75, - 0xa1, 0xcb, 0x92, 0x47, 0x2f, 0xf7, 0x87, 0x38, 0xf5, 0xe4, 0x72, 0x82, - 0x79, 0x58, 0x2d, 0x7e, 0x4f, 0x79, 0x3c, 0x72, 0xff, 0xfd, 0xf8, 0xba, - 0xbe, 0x56, 0x06, 0x59, 0xd4, 0x61, 0xcb, 0xed, 0xef, 0x1a, 0x1c, 0xac, - 0x45, 0x0b, 0x09, 0xdd, 0x5a, 0xfd, 0x9b, 0xcc, 0x98, 0xe5, 0xbe, 0xc2, - 0xe3, 0x64, 0xf0, 0xb6, 0x91, 0x1e, 0x32, 0x2a, 0x68, 0x8f, 0x13, 0x10, - 0xb0, 0xe3, 0xab, 0xc3, 0x0b, 0x5d, 0x43, 0x09, 0x42, 0xeb, 0xdc, 0x29, - 0x8a, 0x9c, 0xbf, 0xb8, 0x41, 0xce, 0xbf, 0x8e, 0x5f, 0xe7, 0x06, 0x9f, - 0xde, 0x73, 0x97, 0x31, 0x67, 0x28, 0x4f, 0x27, 0xc6, 0x57, 0xfe, 0xc6, - 0xf7, 0x82, 0xfc, 0xcb, 0x47, 0x2f, 0xdd, 0x76, 0x40, 0x9c, 0xbe, 0xd7, - 0x51, 0xb3, 0x97, 0xe8, 0x6f, 0xd9, 0xd3, 0x97, 0xa1, 0x4c, 0x39, 0x5f, - 0x11, 0x1b, 0x84, 0xc2, 0x47, 0xa2, 0x8b, 0xe0, 0x31, 0x36, 0x72, 0xfe, - 0x4f, 0x26, 0x38, 0x9c, 0xbf, 0xff, 0xe8, 0xd8, 0xe0, 0x73, 0xbd, 0x45, - 0xf5, 0x3d, 0xa7, 0xe4, 0xe5, 0xff, 0x3f, 0x23, 0x9e, 0xd6, 0x36, 0x72, - 0x91, 0x1d, 0x4d, 0x64, 0x5d, 0x2a, 0xfd, 0x96, 0xfd, 0xd4, 0xdf, 0xf2, - 0x39, 0x7f, 0x46, 0xc0, 0xd3, 0xff, 0x1c, 0xbf, 0xe8, 0x1f, 0x70, 0xcf, - 0xef, 0xe0, 0xe5, 0xff, 0xe8, 0xec, 0x31, 0x7d, 0x4f, 0x66, 0x30, 0xe5, - 0xf0, 0x00, 0x8a, 0x1c, 0xbf, 0x4b, 0x53, 0xe3, 0x67, 0x2f, 0x3b, 0xac, - 0xd1, 0x68, 0x2f, 0xfc, 0xed, 0xf0, 0x2d, 0xf7, 0x3e, 0x36, 0x72, 0xfe, - 0x04, 0x0c, 0x7b, 0x47, 0x2a, 0x11, 0x84, 0xb2, 0xad, 0x94, 0x01, 0x12, - 0xff, 0xff, 0xf9, 0x37, 0xd7, 0x14, 0x8f, 0x27, 0x63, 0x5d, 0xcd, 0x6f, - 0x17, 0x9e, 0x39, 0x7f, 0xff, 0xfb, 0xfd, 0x3e, 0xe5, 0xa4, 0x0e, 0x6e, - 0x74, 0xd7, 0x5c, 0x1a, 0xc1, 0x39, 0x7f, 0x44, 0xec, 0x77, 0x13, 0x97, - 0xff, 0xee, 0xe3, 0x7e, 0x64, 0x67, 0xbb, 0x98, 0x2b, 0x39, 0x7f, 0xfe, - 0x4f, 0x4b, 0x37, 0xb7, 0x92, 0x82, 0xfe, 0xd1, 0xca, 0x85, 0x78, 0xd2, - 0x29, 0x09, 0x8a, 0xcf, 0x51, 0x23, 0x70, 0xe5, 0xe9, 0xe0, 0xbc, 0xe9, - 0xe3, 0xc5, 0x9c, 0x55, 0x2e, 0xc6, 0x1c, 0xbf, 0xf9, 0xf9, 0xe3, 0xd6, - 0xb4, 0xf0, 0xc3, 0x0e, 0x56, 0xcf, 0x7d, 0xc5, 0xaf, 0xff, 0xc9, 0xed, - 0x3f, 0x3a, 0xd6, 0x75, 0x35, 0xfc, 0xe7, 0x2f, 0xff, 0xbf, 0x9f, 0x69, - 0xe9, 0xff, 0xdc, 0xb4, 0xd6, 0x87, 0x2b, 0xa8, 0xb0, 0x15, 0x8b, 0xfb, - 0x4e, 0xa6, 0x73, 0xe3, 0x97, 0xf9, 0x03, 0x8c, 0xf9, 0x81, 0x39, 0x7f, - 0xfd, 0xfe, 0xf7, 0x03, 0x8a, 0xa7, 0x7b, 0x8a, 0x1c, 0xb7, 0x0e, 0x72, - 0xb6, 0x7c, 0xff, 0xa8, 0xdf, 0xe6, 0x7e, 0x3e, 0xd7, 0xfb, 0x39, 0x52, - 0x47, 0xa6, 0xe1, 0x36, 0xd0, 0x8e, 0xfe, 0x76, 0xbc, 0x16, 0x21, 0xcb, - 0xff, 0x9d, 0xbf, 0x67, 0x75, 0x36, 0x64, 0xe7, 0x2f, 0xd3, 0x77, 0x00, - 0xe7, 0x2b, 0xa8, 0x9c, 0x12, 0xee, 0x28, 0xd7, 0xff, 0xfb, 0x33, 0xda, - 0x89, 0xbb, 0x1c, 0x47, 0x03, 0xd8, 0xd1, 0xcb, 0xf0, 0xad, 0xf4, 0x87, - 0x2f, 0xff, 0xed, 0x8c, 0x47, 0x3f, 0x35, 0xe1, 0x80, 0xf6, 0x3c, 0x72, - 0xe4, 0xe9, 0xcb, 0xe9, 0x0b, 0xa8, 0x72, 0xff, 0x05, 0xc1, 0xbd, 0xb8, - 0x0e, 0x5f, 0x6d, 0x6d, 0x6d, 0x9c, 0xbe, 0x57, 0x84, 0x76, 0xce, 0x56, - 0x1e, 0x83, 0x93, 0xd2, 0x22, 0x8c, 0x61, 0x07, 0x50, 0x9c, 0x1e, 0x13, - 0x35, 0xae, 0x38, 0xb7, 0xf0, 0xc5, 0xbc, 0xed, 0x68, 0x72, 0xff, 0xca, - 0x79, 0x54, 0x56, 0x30, 0x60, 0xe5, 0xf9, 0x4f, 0x0c, 0x00, 0xe5, 0x72, - 0x88, 0x5d, 0x8f, 0x71, 0x3f, 0xbf, 0x47, 0xb3, 0xb0, 0x72, 0xff, 0xff, - 0xf7, 0x50, 0x38, 0x93, 0xf6, 0x23, 0xe6, 0x73, 0x2d, 0x27, 0x9c, 0x70, - 0xe5, 0xff, 0xb3, 0x99, 0x6a, 0x6d, 0xbf, 0xb4, 0x72, 0xff, 0xf7, 0xb5, - 0x93, 0x76, 0x38, 0xe7, 0x7b, 0x07, 0x2f, 0xf3, 0x83, 0x4c, 0x7e, 0x7c, - 0x72, 0xb1, 0x10, 0x0e, 0x99, 0x7f, 0xc3, 0x11, 0x36, 0x71, 0x4d, 0x9c, - 0xa9, 0xd3, 0xb8, 0x59, 0x30, 0x1d, 0xc6, 0x18, 0x3e, 0x21, 0xbf, 0x7c, - 0x9a, 0x49, 0x31, 0xca, 0x85, 0x4c, 0xf9, 0x1f, 0x5a, 0x28, 0x5f, 0xfd, - 0xd4, 0xf9, 0x83, 0x89, 0xb7, 0xe2, 0x72, 0xff, 0xe4, 0x17, 0x08, 0xe0, - 0x7b, 0x1a, 0x39, 0x79, 0x48, 0xd9, 0xcb, 0xff, 0xfd, 0xd8, 0x1c, 0x06, - 0xb0, 0x3d, 0x89, 0xd9, 0xf8, 0x84, 0xe5, 0xf9, 0x3d, 0xe8, 0x91, 0xca, - 0x55, 0x32, 0xb5, 0xa2, 0xed, 0x07, 0xc3, 0xbc, 0x58, 0x6f, 0xff, 0xe8, - 0x9b, 0x03, 0xd8, 0xe3, 0xdc, 0xf0, 0xc4, 0x30, 0xe5, 0xfd, 0xce, 0x94, - 0x9f, 0xf1, 0x39, 0x7f, 0xd0, 0xbe, 0xa4, 0xce, 0xf3, 0x9c, 0xa6, 0x23, - 0x19, 0xd6, 0xc0, 0x65, 0x7f, 0xa5, 0x1b, 0x9e, 0x37, 0x39, 0xcb, 0xf8, - 0x67, 0x7e, 0xa0, 0x9c, 0xbf, 0xe4, 0xfc, 0x65, 0xb8, 0xc0, 0x9c, 0xbf, - 0xff, 0xee, 0xe4, 0x97, 0xd4, 0xec, 0x66, 0xe5, 0xe1, 0x86, 0x68, 0xe5, - 0xf7, 0xf1, 0xc8, 0x4e, 0x53, 0xa3, 0xb7, 0x45, 0x9e, 0x38, 0x6d, 0x96, - 0xfb, 0x82, 0x37, 0x39, 0xca, 0x84, 0xe1, 0x72, 0x32, 0x27, 0x3d, 0xbf, - 0xdb, 0x5c, 0xd8, 0x9d, 0xfc, 0xe5, 0xff, 0x93, 0x88, 0xe6, 0xbc, 0xaa, - 0x2c, 0xe5, 0xfe, 0xf7, 0x5a, 0xd3, 0xaf, 0x31, 0xcb, 0xfa, 0x16, 0x2f, - 0xcf, 0x8e, 0x54, 0x91, 0x48, 0xd6, 0x80, 0xc3, 0x7b, 0xf4, 0x7a, 0x7c, - 0x6c, 0xe5, 0xff, 0xb9, 0x58, 0xbc, 0xef, 0x24, 0xe9, 0xca, 0xd9, 0xf4, - 0x7e, 0x53, 0x79, 0xc4, 0x07, 0x2f, 0xff, 0xff, 0x93, 0xfd, 0xf7, 0x26, - 0x99, 0xf7, 0x37, 0xbb, 0xf8, 0x35, 0x89, 0xc4, 0x30, 0x72, 0xfd, 0xee, - 0xb8, 0xaa, 0x72, 0xff, 0x87, 0xf9, 0xc3, 0xdc, 0x18, 0x39, 0x6c, 0x0a, - 0x39, 0x72, 0x10, 0x8b, 0x28, 0xbf, 0xf8, 0x0b, 0x00, 0xe7, 0xb4, 0xee, - 0x27, 0x2f, 0x31, 0xf9, 0x39, 0x5b, 0x3d, 0xf0, 0x21, 0x54, 0x2b, 0x51, - 0xc8, 0x6c, 0xa4, 0x26, 0xdc, 0x8c, 0x63, 0x00, 0xfe, 0x13, 0x17, 0xfb, - 0x3b, 0x32, 0x75, 0x18, 0x72, 0xff, 0x4b, 0x37, 0xa1, 0x89, 0xce, 0x5e, - 0x69, 0x93, 0x9c, 0xbf, 0xe8, 0x18, 0x5e, 0xd2, 0x18, 0x72, 0xf6, 0x75, - 0xce, 0x5f, 0xa6, 0x0f, 0xff, 0x89, 0xca, 0x09, 0xe3, 0x38, 0xdd, 0xe6, - 0xb4, 0x61, 0xcb, 0xff, 0xf3, 0xb8, 0x35, 0x00, 0xf6, 0x20, 0x70, 0x66, - 0x39, 0xd2, 0xfe, 0xff, 0x63, 0x78, 0xb5, 0xe3, 0x67, 0x2f, 0xfb, 0x96, - 0x66, 0x0f, 0x9a, 0x61, 0xcb, 0xca, 0xcb, 0xf3, 0x97, 0xee, 0xc6, 0xe7, - 0x61, 0xcb, 0xfd, 0xfb, 0x8f, 0x71, 0xe6, 0x39, 0x6e, 0x66, 0x3d, 0xc6, - 0xca, 0x69, 0x11, 0x4c, 0xef, 0x75, 0x89, 0x9a, 0xb9, 0xa0, 0xc3, 0x82, - 0xb1, 0x58, 0x5f, 0x26, 0x68, 0x67, 0xd1, 0xf7, 0x7c, 0x14, 0x0d, 0x47, - 0x2f, 0x78, 0x70, 0x07, 0x2d, 0x07, 0x28, 0x06, 0xaf, 0xc3, 0x77, 0x3f, - 0x8e, 0x56, 0xcd, 0xbf, 0x48, 0x6f, 0x99, 0x1b, 0xd1, 0xcb, 0xfe, 0xde, - 0x77, 0x27, 0xf8, 0x9a, 0x39, 0x58, 0x7f, 0xc8, 0x43, 0xf9, 0x15, 0xfc, - 0x83, 0xfc, 0xb3, 0x47, 0x2f, 0xfd, 0x9e, 0x8e, 0x40, 0xfd, 0xea, 0x1c, - 0xb3, 0x0e, 0x5f, 0xc8, 0x3f, 0xcb, 0x35, 0xf0, 0xf3, 0xf8, 0x9f, 0x52, - 0xa8, 0xc4, 0xf3, 0xe5, 0xbe, 0xb5, 0x6d, 0xeb, 0x8f, 0x0c, 0x49, 0x0f, - 0x53, 0x90, 0xca, 0x19, 0x81, 0x8c, 0x9f, 0x27, 0x01, 0x95, 0x87, 0xea, - 0xe1, 0xa3, 0xc9, 0x12, 0x46, 0x47, 0x34, 0x34, 0xf6, 0x62, 0xc8, 0xf9, - 0x3b, 0x2c, 0xf5, 0xe3, 0x60, 0x04, 0x62, 0x83, 0x1d, 0xa6, 0xa5, 0xc2, - 0xfa, 0x5b, 0xab, 0x48, 0xd2, 0x54, 0x87, 0x95, 0xfd, 0xc0, 0x81, 0x18, - 0x98, 0xe5, 0xe8, 0x71, 0x39, 0x7d, 0x9d, 0x7f, 0x1c, 0xb7, 0x09, 0x87, - 0xd7, 0xd3, 0x01, 0x1a, 0xbf, 0xff, 0xfd, 0xd7, 0x1f, 0x6a, 0x12, 0x59, - 0xc0, 0x3e, 0x8e, 0xc2, 0xbf, 0xc7, 0x01, 0xcb, 0xec, 0xd0, 0x10, 0xe5, - 0xfb, 0x6b, 0x77, 0x59, 0xa2, 0xd6, 0x5f, 0xe6, 0x23, 0x1e, 0x6c, 0xe9, - 0xcb, 0xfb, 0x38, 0x34, 0xe2, 0xb3, 0x97, 0xb7, 0x0c, 0x39, 0x7f, 0x77, - 0x35, 0x13, 0xf0, 0x1c, 0xbf, 0xe9, 0x7d, 0xcd, 0xad, 0xdd, 0x66, 0x8a, - 0x0d, 0x58, 0x7f, 0x0e, 0x63, 0x7d, 0x93, 0x47, 0x8e, 0x5f, 0xf4, 0x4a, - 0x37, 0x3c, 0x6e, 0x73, 0x97, 0xf9, 0x22, 0x60, 0x38, 0xcc, 0x72, 0xff, - 0xfb, 0x49, 0x3b, 0xe9, 0xc5, 0xfd, 0xd8, 0x98, 0xe5, 0xff, 0x9c, 0x41, - 0x9e, 0x81, 0x40, 0x1c, 0xaf, 0x22, 0x29, 0xa2, 0x7d, 0xbe, 0xf0, 0xca, - 0xd7, 0x60, 0xe2, 0x4f, 0x98, 0x42, 0x86, 0x93, 0x19, 0xec, 0xbd, 0x90, - 0x94, 0xe9, 0x00, 0x91, 0x78, 0xe9, 0x48, 0x5e, 0xdf, 0xfe, 0xfa, 0xc7, - 0x97, 0xdc, 0xda, 0xdd, 0xd6, 0x68, 0xa2, 0xd7, 0xfb, 0xee, 0x6d, 0x6e, - 0xeb, 0x34, 0x5d, 0x4a, 0x87, 0x5a, 0x31, 0x28, 0x62, 0xe1, 0xc2, 0xe1, - 0x76, 0x91, 0xee, 0x32, 0x72, 0x57, 0xb5, 0xf1, 0x80, 0x27, 0x5a, 0x35, - 0x0b, 0xcf, 0x2d, 0x5f, 0xb6, 0xb7, 0x75, 0x9a, 0x22, 0x15, 0xee, 0xa0, - 0x9c, 0xbb, 0x02, 0x72, 0xcb, 0x39, 0x4b, 0x3c, 0x2e, 0x8d, 0x88, 0xb5, - 0xf6, 0x71, 0x4d, 0x9c, 0xbe, 0x4d, 0xe7, 0x27, 0x2d, 0xf7, 0x11, 0xd3, - 0xcb, 0xb3, 0x59, 0x73, 0x42, 0x3b, 0x34, 0x39, 0x7d, 0x1d, 0x86, 0x1c, - 0xbe, 0x5b, 0xba, 0xcd, 0x11, 0xb2, 0x96, 0x79, 0xfb, 0x21, 0xb7, 0xd0, - 0xa2, 0x13, 0x18, 0xaf, 0xf7, 0xdc, 0xda, 0xdd, 0xd6, 0x68, 0xa6, 0xd7, - 0xed, 0xad, 0xdd, 0x66, 0x8a, 0x81, 0x7b, 0x39, 0x6c, 0xe5, 0xbe, 0xe1, - 0xe9, 0x74, 0xd2, 0xff, 0x7d, 0xcd, 0xad, 0xdd, 0x66, 0x8a, 0x99, 0x7e, - 0xda, 0xdd, 0xd6, 0x68, 0xac, 0x17, 0xe4, 0x6c, 0x3f, 0xec, 0xe5, 0xda, - 0x13, 0x97, 0x33, 0x47, 0x2f, 0xe4, 0x68, 0xf0, 0x8d, 0x0e, 0x5f, 0xef, - 0xb9, 0xb5, 0xbb, 0xac, 0xd1, 0x1f, 0xaf, 0x0c, 0x04, 0xe5, 0x42, 0x22, - 0xe4, 0x5e, 0x88, 0x37, 0xb2, 0x27, 0x39, 0x7f, 0x73, 0x27, 0x92, 0x09, - 0xcb, 0xd0, 0x33, 0x1c, 0xac, 0x3c, 0x95, 0x4b, 0x6e, 0x7f, 0x1c, 0xbb, - 0xde, 0x39, 0x6f, 0xb8, 0x9f, 0xc2, 0xcd, 0x10, 0xa9, 0x82, 0xcf, 0x0a, - 0x21, 0x2e, 0xf3, 0x2b, 0x42, 0x2e, 0x01, 0x6b, 0xff, 0xdf, 0x58, 0xf2, - 0xfb, 0x9b, 0x5b, 0xba, 0xcd, 0x13, 0x7a, 0xff, 0xe6, 0x3c, 0xbe, 0xe6, - 0xd6, 0xee, 0xb3, 0x44, 0xfc, 0xbc, 0xb5, 0x18, 0x72, 0xfd, 0xb8, 0xef, - 0xf0, 0x72, 0xfd, 0xdc, 0xf4, 0x04, 0xe5, 0x70, 0x87, 0xda, 0x83, 0xce, - 0x51, 0x70, 0xac, 0xe5, 0xf6, 0xa6, 0x66, 0x8e, 0x5c, 0xb5, 0x9c, 0xbf, - 0xcb, 0xea, 0x7b, 0x31, 0x87, 0x2e, 0xe2, 0xb3, 0xc6, 0x04, 0xa8, 0x45, - 0x4a, 0x0b, 0x00, 0x93, 0x42, 0xfe, 0x32, 0xbf, 0x35, 0x5c, 0x23, 0x4c, - 0xe4, 0xe5, 0xfc, 0xd4, 0x3c, 0xfd, 0x46, 0xb3, 0x97, 0xe6, 0xad, 0x55, - 0x71, 0xac, 0xe5, 0xfd, 0xe4, 0x16, 0xf0, 0x4e, 0x5d, 0xc5, 0x67, 0x8c, - 0x05, 0x6e, 0x9c, 0xa6, 0xa1, 0x30, 0x0e, 0x10, 0xd7, 0x85, 0x8d, 0xb0, - 0xcb, 0xc5, 0x9f, 0x93, 0x5f, 0x35, 0x7b, 0x7c, 0x39, 0x7d, 0xc3, 0x4e, - 0xcd, 0x1c, 0xbf, 0xff, 0x0b, 0xfa, 0x05, 0x68, 0xc0, 0xfe, 0xfb, 0x91, - 0xcb, 0xf3, 0x7e, 0xf4, 0x30, 0xe5, 0x35, 0x67, 0xfb, 0x3a, 0xa5, 0xff, - 0x3f, 0x53, 0x8f, 0xd6, 0xdb, 0x6c, 0xa5, 0xfe, 0xeb, 0xfb, 0xce, 0xed, - 0x9c, 0xae, 0x19, 0x34, 0x16, 0xa7, 0x0a, 0x66, 0xa4, 0x51, 0xc2, 0xc8, - 0x17, 0xff, 0xf9, 0xaa, 0xe1, 0x35, 0xb8, 0x4f, 0x77, 0x02, 0x9a, 0xc1, - 0x01, 0xcb, 0xf9, 0xae, 0x36, 0xef, 0x23, 0x97, 0xee, 0xa3, 0x83, 0x85, - 0x8e, 0x53, 0x50, 0x8c, 0x6e, 0x14, 0xd3, 0xe2, 0xfb, 0x39, 0xcb, 0xe1, - 0xc4, 0x01, 0xcb, 0xee, 0x17, 0x02, 0xb0, 0x72, 0xb8, 0x43, 0xca, 0xe1, - 0x88, 0x2f, 0xfd, 0x11, 0x11, 0x11, 0x1c, 0xe8, 0xe5, 0xe9, 0xa3, 0xc7, - 0x2e, 0x88, 0x83, 0xd8, 0x98, 0xee, 0xf2, 0x73, 0x87, 0x2f, 0xdb, 0x49, - 0xdd, 0x85, 0x2e, 0x6d, 0xb2, 0x95, 0x87, 0x82, 0xd9, 0x45, 0xbf, 0x29, - 0xf4, 0xd1, 0x5e, 0xee, 0x2c, 0xe5, 0x42, 0x3a, 0xc0, 0x59, 0xa7, 0xf5, - 0x09, 0x2f, 0xdf, 0xb4, 0x8f, 0xf9, 0x39, 0x7c, 0xe3, 0x1c, 0x07, 0x2b, - 0x0f, 0x41, 0xcb, 0x6f, 0xff, 0x20, 0xe3, 0x23, 0x5a, 0xc9, 0x34, 0xc3, - 0x97, 0xfb, 0x02, 0x9c, 0x74, 0x05, 0x9c, 0xbf, 0xff, 0xf6, 0x71, 0x4f, - 0x4b, 0x01, 0xa1, 0xc0, 0x6e, 0x27, 0x7d, 0xac, 0xe5, 0xd1, 0x27, 0x45, - 0x16, 0x8d, 0x6f, 0xef, 0x6b, 0x32, 0x78, 0x39, 0x5d, 0x3d, 0xa1, 0x2d, - 0xbe, 0xd0, 0x7d, 0xf9, 0xcb, 0xfd, 0xbf, 0xc7, 0xff, 0x7f, 0xe3, 0x97, - 0xbb, 0x02, 0x72, 0xd0, 0x87, 0xa5, 0xe3, 0x7a, 0x84, 0x5e, 0xac, 0x87, - 0xae, 0xd7, 0x85, 0x20, 0xe5, 0xfa, 0x14, 0x67, 0x50, 0xe5, 0x6c, 0xf0, - 0x84, 0x6a, 0xfc, 0xf3, 0xc3, 0xac, 0xe5, 0xfc, 0xa7, 0xc8, 0xd4, 0x30, - 0xe5, 0x74, 0xf5, 0xdc, 0x9e, 0xfe, 0x96, 0xbd, 0x82, 0xa9, 0xcb, 0xff, - 0xa1, 0x79, 0xbc, 0xea, 0x6f, 0xae, 0x72, 0xf3, 0x6e, 0xd9, 0xcb, 0xff, - 0xde, 0xdb, 0xce, 0x1e, 0xc6, 0xbd, 0xff, 0x4e, 0x5d, 0x8c, 0xda, 0x2b, - 0x7a, 0x85, 0xa1, 0xeb, 0xf3, 0xaf, 0xa9, 0xb3, 0x97, 0xff, 0xff, 0x85, - 0xd5, 0x4d, 0xc4, 0xbe, 0x75, 0x18, 0x18, 0xf8, 0xd3, 0xfe, 0xa6, 0xce, - 0x5f, 0x3c, 0x93, 0x93, 0x97, 0xfe, 0xea, 0x7b, 0x37, 0xbf, 0xe7, 0xe2, - 0x72, 0xff, 0x93, 0xd9, 0xbd, 0xff, 0x3f, 0x13, 0x97, 0xb5, 0xf8, 0xfc, - 0x44, 0x07, 0x50, 0xe8, 0x29, 0xdc, 0xec, 0xef, 0xa4, 0xe2, 0xfd, 0xa8, - 0x51, 0x5f, 0x31, 0x03, 0x07, 0x2f, 0xe4, 0xee, 0xf6, 0x93, 0x9c, 0xa8, - 0x3c, 0xfe, 0x90, 0xdc, 0xdf, 0x8e, 0x5f, 0xfc, 0x89, 0xd9, 0xb3, 0xd1, - 0xe8, 0x09, 0xcb, 0x41, 0xcb, 0xff, 0xe8, 0xe6, 0x4e, 0x20, 0xf8, 0x04, - 0xda, 0x2a, 0x72, 0xa1, 0x17, 0xb3, 0x0c, 0x34, 0x43, 0xe0, 0x10, 0xbe, - 0xf6, 0xba, 0x87, 0x2f, 0xa7, 0x62, 0x48, 0xe5, 0xf4, 0x01, 0x46, 0x1c, - 0xbe, 0x1f, 0xde, 0x47, 0x29, 0x67, 0x8b, 0xa2, 0x3b, 0xfd, 0xd8, 0x67, - 0xd0, 0x02, 0x0e, 0x54, 0x22, 0xff, 0x1a, 0x10, 0x8a, 0xfe, 0x99, 0x3b, - 0xec, 0x59, 0xca, 0xc4, 0xcf, 0x37, 0x0e, 0x17, 0x2d, 0xbf, 0xee, 0x42, - 0xa4, 0x35, 0xf7, 0xfd, 0x1c, 0xb9, 0xfa, 0x72, 0xf2, 0xb1, 0xe3, 0x97, - 0xff, 0xe0, 0xf6, 0x36, 0x80, 0x85, 0x22, 0x61, 0x86, 0x1c, 0xbf, 0xca, - 0xc0, 0xfb, 0x4f, 0xd3, 0x94, 0x88, 0x88, 0x75, 0x5b, 0xf0, 0xe3, 0x8c, - 0xe7, 0x2a, 0x13, 0x42, 0x44, 0x07, 0x16, 0x18, 0x52, 0xe8, 0x86, 0xff, - 0x76, 0x27, 0xdc, 0x60, 0x4e, 0x5f, 0xff, 0x0e, 0x71, 0x5b, 0xee, 0x77, - 0xf3, 0xf2, 0x03, 0x95, 0x08, 0x85, 0x73, 0x3b, 0xfc, 0x2f, 0x3f, 0x32, - 0x8e, 0x03, 0x97, 0xfb, 0x5d, 0x75, 0x3b, 0x12, 0x39, 0x53, 0x9f, 0x5f, - 0x26, 0xf7, 0xb3, 0x26, 0x39, 0x7f, 0xfe, 0x9b, 0xb0, 0xc4, 0xda, 0x70, - 0x42, 0x93, 0xe3, 0x67, 0x2f, 0xfc, 0x9b, 0x8d, 0x28, 0x23, 0x1b, 0x39, - 0x7f, 0xd1, 0x21, 0x7f, 0x49, 0x38, 0x9c, 0xbc, 0xa4, 0x00, 0xe5, 0x74, - 0xf5, 0xb4, 0x73, 0x66, 0xb3, 0x97, 0xbd, 0x2c, 0x39, 0x76, 0xb0, 0xe5, - 0xff, 0xda, 0x8d, 0xaf, 0xc3, 0x93, 0xb8, 0x9c, 0xa8, 0x4e, 0x66, 0x75, - 0xbc, 0x84, 0x9a, 0x11, 0x38, 0xa0, 0x07, 0x3c, 0x2d, 0x7f, 0x7f, 0x37, - 0xfe, 0x8e, 0x9c, 0xbf, 0xf8, 0x31, 0xe7, 0xd6, 0x77, 0xa8, 0xc3, 0x97, - 0xf0, 0x61, 0xf6, 0x0f, 0xce, 0x5d, 0x9d, 0x39, 0x53, 0x9e, 0x27, 0x12, - 0xeb, 0xde, 0x49, 0x8e, 0x54, 0x23, 0x27, 0x21, 0x0f, 0xa2, 0x5b, 0xfe, - 0xda, 0x6b, 0xae, 0xc8, 0x6b, 0x39, 0x7e, 0x86, 0xb4, 0x6d, 0x67, 0x2a, - 0x19, 0xfd, 0xb3, 0xc2, 0x36, 0x44, 0x01, 0x94, 0x05, 0x8e, 0x2b, 0x78, - 0xe4, 0x85, 0x25, 0x4a, 0x35, 0xc2, 0x7a, 0x68, 0x6f, 0x6e, 0x37, 0xe6, - 0x46, 0xed, 0xd8, 0x68, 0xbc, 0x23, 0x00, 0x48, 0x31, 0xda, 0xe9, 0x9f, - 0xd0, 0xfa, 0xe2, 0x66, 0xa1, 0xdd, 0xff, 0xff, 0x35, 0x3e, 0x1a, 0x31, - 0xa9, 0x6f, 0x86, 0xe1, 0x5c, 0x5a, 0xf8, 0x5b, 0xff, 0x9f, 0x3a, 0xd0, - 0xe5, 0xe9, 0x94, 0x61, 0xcb, 0xfe, 0xcf, 0x6b, 0x3d, 0xdc, 0x01, 0xca, - 0x73, 0xd7, 0x11, 0xfb, 0x9c, 0x4e, 0x56, 0xcd, 0xab, 0x08, 0x2f, 0xa3, - 0xd8, 0xc3, 0x97, 0xef, 0x40, 0xa0, 0x0e, 0x5f, 0xd8, 0xdb, 0x81, 0x98, - 0x72, 0xbe, 0x1f, 0xa6, 0x10, 0x89, 0x35, 0xfc, 0x83, 0xee, 0xe4, 0x8e, - 0x5f, 0xe1, 0x86, 0xda, 0x66, 0xe0, 0xe5, 0x9b, 0x91, 0xf0, 0x04, 0xb2, - 0xfd, 0xb9, 0xe3, 0xda, 0x39, 0x7c, 0xfb, 0x79, 0x1c, 0xb6, 0xf0, 0xf2, - 0x84, 0xa6, 0xf3, 0x6d, 0xb6, 0x72, 0xfa, 0x71, 0x48, 0x29, 0xf4, 0xd0, - 0x5f, 0xf3, 0x5f, 0x5c, 0x64, 0x18, 0x9c, 0xe5, 0xdc, 0xc8, 0xe5, 0xfe, - 0x56, 0x3d, 0xae, 0xbf, 0xe7, 0x2f, 0xc9, 0x3e, 0x73, 0xe3, 0x97, 0x22, - 0xce, 0x54, 0x22, 0x31, 0x51, 0x86, 0x1a, 0xf8, 0xa6, 0xfc, 0xab, 0xeb, - 0x8c, 0x8e, 0x57, 0x27, 0xd1, 0xe3, 0xda, 0xe1, 0x4b, 0x90, 0xf1, 0x19, - 0x20, 0x61, 0x2b, 0x90, 0x8f, 0x47, 0x3e, 0xa3, 0x39, 0x9f, 0xf1, 0x98, - 0x5f, 0xfd, 0xc5, 0xbc, 0xd0, 0xa4, 0x6f, 0x27, 0x39, 0x7f, 0xff, 0xff, - 0xe6, 0xbf, 0x9d, 0xce, 0x65, 0xd6, 0x7c, 0x5f, 0x7f, 0xf7, 0xb0, 0x7b, - 0x9e, 0x80, 0xfc, 0xf9, 0xd6, 0x87, 0x2f, 0xf8, 0x39, 0xff, 0x0e, 0x9d, - 0x76, 0x1c, 0xbf, 0x43, 0x07, 0x26, 0x39, 0x86, 0xfa, 0xf7, 0x1c, 0x09, - 0xcb, 0xfb, 0xa9, 0x03, 0xfc, 0x1c, 0xbf, 0xd0, 0xd6, 0xae, 0x69, 0xda, - 0xce, 0x52, 0xa7, 0xcb, 0xd2, 0xca, 0xea, 0x29, 0x9e, 0x10, 0x74, 0x14, - 0xc0, 0xf5, 0x0d, 0xcb, 0xfa, 0x25, 0xd8, 0xe2, 0x87, 0x2f, 0xcc, 0xfc, - 0x61, 0x87, 0x2f, 0xb7, 0xfb, 0xe8, 0xe5, 0x41, 0xe5, 0xb9, 0x45, 0xd2, - 0xf1, 0xcb, 0xe9, 0xa3, 0xce, 0x72, 0xfb, 0xf0, 0x60, 0xac, 0xdc, 0xfe, - 0x2f, 0x69, 0x1c, 0xa9, 0xcf, 0x2b, 0xa7, 0x37, 0xff, 0x47, 0x54, 0x0f, - 0x93, 0x26, 0x86, 0x1c, 0xbf, 0xf7, 0x91, 0xb5, 0xf5, 0x38, 0xa0, 0x4e, - 0x5f, 0xed, 0xcb, 0xb9, 0xc6, 0x18, 0x72, 0xb9, 0x3f, 0x64, 0x41, 0xbf, - 0x3c, 0xb4, 0x9c, 0x4e, 0x5f, 0xf6, 0x6f, 0x3e, 0x66, 0xe0, 0x27, 0x2f, - 0xec, 0x97, 0x32, 0xcf, 0x1c, 0xb7, 0xa4, 0x7c, 0xfd, 0x39, 0xbe, 0x8f, - 0x7e, 0xc3, 0x94, 0x68, 0x83, 0x97, 0xf3, 0xce, 0x07, 0x10, 0x92, 0xb0, - 0x6a, 0xda, 0x59, 0xe9, 0xb4, 0x18, 0xa6, 0x22, 0x83, 0xce, 0xd7, 0xff, - 0xe6, 0x69, 0xe5, 0xd4, 0xcf, 0x6b, 0x78, 0x1c, 0x39, 0x7f, 0xd1, 0xe1, - 0xce, 0x23, 0x9a, 0x39, 0x50, 0x8a, 0xfc, 0x23, 0xd2, 0xa5, 0xfc, 0xfd, - 0x86, 0xbf, 0xe4, 0x72, 0xa4, 0xb9, 0x04, 0xb7, 0x9d, 0xc2, 0x8d, 0x84, - 0x7d, 0x85, 0xd8, 0x08, 0x86, 0x12, 0x1e, 0x8d, 0xdf, 0x89, 0x75, 0xfd, - 0x21, 0xce, 0x7d, 0x87, 0x2f, 0xff, 0xca, 0x00, 0x11, 0xce, 0x4e, 0x17, - 0x75, 0xb8, 0x4e, 0x54, 0x22, 0x13, 0x65, 0xb7, 0xf0, 0xfa, 0x59, 0xbc, - 0x39, 0x73, 0x47, 0x39, 0x4e, 0x78, 0x8a, 0x16, 0x5f, 0xee, 0xe2, 0xdf, - 0xb1, 0xd3, 0x97, 0xff, 0x3a, 0x7a, 0x05, 0x79, 0xee, 0xa1, 0xcb, 0xf8, - 0x50, 0x1a, 0xea, 0x1c, 0xbb, 0x61, 0x39, 0x73, 0x6d, 0x9c, 0xa9, 0x1b, - 0x06, 0xc5, 0xef, 0x42, 0x71, 0x29, 0xf4, 0xd1, 0x5f, 0xf2, 0x0a, 0x03, - 0x59, 0xd7, 0x39, 0x58, 0x9a, 0xb7, 0x4c, 0x9d, 0x07, 0x4f, 0xde, 0x2f, - 0xb8, 0x1a, 0x39, 0x7f, 0x27, 0x51, 0x55, 0x60, 0xe5, 0xda, 0x50, 0x27, - 0x8b, 0xe1, 0x7a, 0x44, 0x5e, 0xa9, 0x08, 0xeb, 0xcd, 0xb6, 0xd9, 0x4a, - 0x29, 0xf4, 0xd0, 0x5f, 0x23, 0x69, 0x31, 0x4a, 0x59, 0xe0, 0x20, 0xed, - 0xfb, 0x37, 0x1c, 0x70, 0xe5, 0x43, 0x2d, 0x92, 0x74, 0x6c, 0x8f, 0xb1, - 0x27, 0x2a, 0xf7, 0x18, 0xdb, 0x19, 0xbb, 0x28, 0xd4, 0x61, 0x11, 0xa2, - 0x1b, 0xed, 0xcb, 0xfc, 0x39, 0x7f, 0x87, 0x9f, 0x29, 0xd7, 0x01, 0xcb, - 0xc2, 0x9a, 0x39, 0x7c, 0x17, 0x10, 0x1c, 0xbf, 0xfa, 0x04, 0x03, 0x1c, - 0xcd, 0x02, 0x03, 0x95, 0x88, 0xb4, 0x43, 0x50, 0x0d, 0xe8, 0x86, 0xfd, - 0x33, 0x40, 0x34, 0xc3, 0x96, 0x43, 0x97, 0xfc, 0xea, 0xaf, 0xa8, 0x17, - 0x91, 0xcb, 0xe9, 0xe7, 0x7e, 0x4e, 0x5c, 0x0d, 0x21, 0xf7, 0x08, 0x82, - 0x87, 0x37, 0xe8, 0xcd, 0xf5, 0x0e, 0x5f, 0xfe, 0x6c, 0x1d, 0xcc, 0x9d, - 0x33, 0x8c, 0x72, 0x72, 0xff, 0xf0, 0x21, 0x9b, 0xdc, 0x4f, 0xe7, 0x75, - 0x4e, 0x5f, 0xe9, 0x67, 0x71, 0x90, 0xb3, 0x97, 0xb1, 0x8d, 0x67, 0x2f, - 0xfc, 0xfc, 0x71, 0x41, 0x8e, 0xa4, 0xe7, 0x2f, 0xf6, 0x68, 0x73, 0xdd, - 0x43, 0x94, 0x14, 0x48, 0x6c, 0x7c, 0x50, 0x2b, 0x13, 0xe9, 0x98, 0xeb, - 0xa4, 0xc0, 0x4d, 0xf2, 0x5f, 0x18, 0x61, 0x5f, 0xde, 0xc9, 0x86, 0x18, - 0x78, 0x80, 0x97, 0xe7, 0x10, 0xf6, 0x0d, 0x10, 0x13, 0xe9, 0xba, 0xbf, - 0xf9, 0x39, 0xd0, 0x70, 0x60, 0x7f, 0x83, 0x97, 0xff, 0x7e, 0xb5, 0x77, - 0x9c, 0xe8, 0x0f, 0xe3, 0x97, 0xe8, 0x93, 0xf2, 0xd9, 0xcb, 0xff, 0x2f, - 0xe6, 0xf7, 0x9d, 0xe6, 0x5a, 0x39, 0x7e, 0x76, 0xc2, 0xaf, 0x13, 0x95, - 0x89, 0x91, 0xa2, 0x1e, 0xd2, 0x1c, 0xa4, 0x50, 0xed, 0x39, 0xcb, 0xf7, - 0xcc, 0x99, 0x18, 0x72, 0xff, 0xf7, 0xf1, 0xf3, 0x83, 0xc9, 0xae, 0xf2, - 0xed, 0x9c, 0xa9, 0xcf, 0xf3, 0x45, 0x57, 0xfe, 0xc0, 0xf5, 0xfe, 0xc7, - 0x63, 0x93, 0x95, 0xc2, 0x23, 0xc7, 0x70, 0x8e, 0x61, 0x1d, 0xff, 0x0a, - 0xbb, 0x14, 0x5f, 0xe2, 0x72, 0xfd, 0xe8, 0xc1, 0x83, 0x94, 0x87, 0xbc, - 0x27, 0x37, 0xd3, 0xa8, 0x3e, 0x39, 0x7f, 0xfe, 0x7e, 0x79, 0xd4, 0x0f, - 0x94, 0x9b, 0xa9, 0xed, 0x1c, 0xa8, 0x4c, 0xd7, 0x21, 0x30, 0x84, 0x1f, - 0x92, 0x5f, 0x32, 0x31, 0x87, 0x2f, 0xfd, 0x8c, 0x85, 0xa7, 0xb7, 0xfb, - 0x0e, 0x5e, 0x4e, 0x74, 0x72, 0xa4, 0x7b, 0x80, 0x3f, 0xbe, 0xdb, 0xca, - 0x63, 0x97, 0xed, 0x6a, 0x00, 0xd4, 0x1c, 0xa5, 0x4f, 0x41, 0xb2, 0x3a, - 0x84, 0x4b, 0x3b, 0x95, 0xfe, 0xdc, 0xda, 0x41, 0xf2, 0x1c, 0xbf, 0xdd, - 0x4e, 0x41, 0xb7, 0x09, 0xcb, 0xee, 0x41, 0xb8, 0x29, 0x73, 0x6d, 0x94, - 0xa8, 0x37, 0x8d, 0x91, 0xdc, 0x28, 0x53, 0xe9, 0xa1, 0xbf, 0xff, 0xf8, - 0x7e, 0xe6, 0x70, 0x44, 0xc8, 0xc8, 0x9b, 0xe0, 0xf3, 0x2e, 0xfe, 0x03, - 0x94, 0x72, 0xf3, 0xee, 0x5f, 0x13, 0x3e, 0x94, 0x24, 0x79, 0x27, 0x03, - 0xdd, 0x35, 0x6c, 0xb4, 0x18, 0x86, 0xbc, 0x8e, 0xf2, 0x54, 0x22, 0x42, - 0x67, 0x71, 0xb4, 0x76, 0x53, 0x6b, 0xa0, 0x8c, 0x62, 0x7e, 0x21, 0xfe, - 0x37, 0x1b, 0xde, 0x46, 0xce, 0x5e, 0x9d, 0xd8, 0x72, 0xf7, 0x91, 0xb3, - 0xc6, 0x10, 0xbe, 0xf7, 0xee, 0xa1, 0xa2, 0x07, 0x72, 0x6a, 0xa9, 0xd1, - 0x13, 0xfa, 0x3d, 0xe1, 0xdf, 0x0e, 0x72, 0xff, 0x62, 0xe2, 0x71, 0x85, - 0x9c, 0xb0, 0x0e, 0x59, 0xaf, 0xe1, 0xe1, 0xa1, 0x95, 0xd1, 0xf9, 0xcb, - 0xf7, 0xe2, 0x05, 0x24, 0x72, 0xff, 0xf8, 0x73, 0x5f, 0x14, 0xec, 0x01, - 0x8f, 0x2f, 0x98, 0x78, 0x3a, 0x17, 0xaf, 0xd1, 0xaf, 0xc5, 0xb6, 0xff, - 0xdd, 0xfe, 0x78, 0xf9, 0x1e, 0x80, 0x9c, 0xbc, 0xfb, 0x9c, 0xe5, 0xcd, - 0xb6, 0x72, 0xff, 0x6d, 0x33, 0x8a, 0x92, 0xfa, 0xb3, 0x6c, 0xd8, 0xed, - 0xff, 0x91, 0x5f, 0x9a, 0xfc, 0x0c, 0x89, 0x1c, 0xbf, 0xda, 0xcf, 0x3b, - 0x30, 0x4e, 0x50, 0x53, 0x3b, 0xdb, 0xc7, 0x53, 0xfc, 0x87, 0x7f, 0xed, - 0x60, 0xe7, 0x71, 0x78, 0x27, 0x2f, 0xfd, 0x8a, 0xf5, 0xe4, 0xa3, 0xf3, - 0x07, 0x2a, 0x47, 0xf6, 0x27, 0x75, 0x08, 0xda, 0xc8, 0x5c, 0xdf, 0xfc, - 0xc6, 0x3c, 0xb3, 0x6b, 0x77, 0x59, 0xa2, 0x18, 0x5f, 0xff, 0xfe, 0x7d, - 0x60, 0xe2, 0xfb, 0x1c, 0xc9, 0xa6, 0x75, 0x69, 0x82, 0xea, 0x9c, 0xac, - 0x46, 0x3f, 0xea, 0x15, 0x0b, 0x90, 0xc9, 0x19, 0xdf, 0x65, 0x1d, 0x8c, - 0x3b, 0x6f, 0xee, 0xbc, 0xe3, 0x12, 0x29, 0x7f, 0xef, 0x75, 0xd3, 0xd1, - 0xb8, 0x01, 0xcb, 0xf7, 0x5c, 0x54, 0x9c, 0xe5, 0x31, 0x12, 0x62, 0x5a, - 0xd9, 0xed, 0xff, 0x91, 0x71, 0xa7, 0xde, 0xd1, 0xb3, 0x97, 0xff, 0xda, - 0x02, 0x6d, 0x55, 0xf5, 0x3a, 0x3f, 0xce, 0x72, 0xed, 0x7e, 0x72, 0xfe, - 0x97, 0x5d, 0xc6, 0x0e, 0x5a, 0x16, 0x78, 0x7c, 0x8c, 0x5f, 0xb6, 0xb7, - 0x75, 0x9a, 0x20, 0xa5, 0xee, 0xc3, 0x0e, 0x5f, 0xfa, 0x27, 0x7f, 0x6f, - 0x24, 0xd3, 0x0e, 0x56, 0x22, 0x41, 0x0d, 0x04, 0x72, 0xfd, 0xd8, 0x67, - 0xfc, 0x9c, 0xbe, 0xf6, 0xa0, 0x05, 0x2f, 0x3e, 0xe7, 0x29, 0x7d, 0xf8, - 0xba, 0xa5, 0x2f, 0xf2, 0x4f, 0x9e, 0xd4, 0x00, 0xa5, 0x14, 0xbf, 0xb1, - 0x71, 0xd8, 0x61, 0x4b, 0x9b, 0x6c, 0xa5, 0xfc, 0x30, 0x33, 0xa6, 0xca, - 0x56, 0x26, 0x22, 0xb2, 0x26, 0x0e, 0xf4, 0x8c, 0x06, 0x62, 0x16, 0xd9, - 0x62, 0x83, 0x37, 0x26, 0xca, 0x7d, 0x3f, 0x2a, 0x92, 0xa0, 0x39, 0x8b, - 0x7b, 0x1d, 0x6d, 0xff, 0xfa, 0x1b, 0xd0, 0xe7, 0x3e, 0x71, 0x9f, 0x39, - 0xf1, 0xca, 0x85, 0xc4, 0xfc, 0x30, 0x43, 0xee, 0xc2, 0x59, 0xe5, 0x5d, - 0x89, 0xcd, 0xfd, 0x83, 0xa4, 0x1c, 0x39, 0x7b, 0xbf, 0xb0, 0xe5, 0x74, - 0xf2, 0x38, 0x0a, 0xaf, 0xf3, 0x8e, 0x6b, 0x71, 0xa3, 0x97, 0xf0, 0x70, - 0x5f, 0xda, 0x39, 0x68, 0x91, 0xee, 0xe8, 0xc6, 0xfd, 0xbe, 0x65, 0x9e, - 0x39, 0x7f, 0xfc, 0xe8, 0x0d, 0x62, 0xae, 0xcd, 0xc6, 0x09, 0xcb, 0xf7, - 0x93, 0x39, 0xf1, 0xcb, 0xff, 0xfe, 0xea, 0x6f, 0x02, 0xec, 0xc1, 0xf0, - 0xc3, 0x79, 0xed, 0x1c, 0xb4, 0x1c, 0xbe, 0x8e, 0x21, 0x85, 0x9f, 0xa0, - 0x19, 0x2f, 0xfc, 0xf2, 0xeb, 0xfb, 0x58, 0x32, 0x39, 0x5d, 0x3f, 0x7f, - 0x1d, 0x56, 0xd3, 0xab, 0xe9, 0x4e, 0x93, 0x7d, 0x18, 0x9d, 0xfd, 0x26, - 0x90, 0xbc, 0x61, 0xcb, 0xf9, 0xf7, 0x1e, 0x4e, 0x27, 0x2b, 0x93, 0xdd, - 0x12, 0xfb, 0xff, 0xff, 0x6f, 0x71, 0xcc, 0xb9, 0xd2, 0x6d, 0x7d, 0xc5, - 0x36, 0x90, 0x13, 0x97, 0xfc, 0xfb, 0xce, 0x65, 0x00, 0x83, 0x95, 0x08, - 0xc9, 0xc2, 0x2f, 0xdb, 0xef, 0xff, 0xcb, 0x55, 0xf5, 0x9b, 0x92, 0x75, - 0xc7, 0x99, 0x1c, 0xbf, 0xf2, 0xe3, 0xda, 0xcf, 0x27, 0x2d, 0x9c, 0xb3, - 0xe2, 0x25, 0x95, 0x56, 0xa8, 0x54, 0xaf, 0xd8, 0xda, 0x86, 0x18, 0xb7, - 0xcf, 0x3a, 0x8b, 0x39, 0x73, 0x80, 0xe5, 0x48, 0xdd, 0x78, 0x92, 0xff, - 0xfc, 0xef, 0x27, 0xef, 0xcc, 0x9f, 0xff, 0x7e, 0xea, 0x1a, 0x2f, 0xb5, - 0xe0, 0x40, 0x4e, 0x5f, 0xce, 0xb8, 0x18, 0x01, 0xcb, 0xff, 0x69, 0x07, - 0x99, 0x6f, 0xf8, 0xd1, 0xca, 0x99, 0x1d, 0xdb, 0x67, 0xe8, 0xe7, 0x8a, - 0xef, 0xdd, 0xc9, 0xa1, 0xac, 0xe5, 0xf8, 0x3b, 0xde, 0x36, 0x72, 0xd1, - 0x39, 0xea, 0x09, 0x5d, 0x96, 0x72, 0xff, 0xff, 0x01, 0x36, 0xaf, 0x61, - 0x93, 0x49, 0x07, 0xb1, 0xb8, 0x39, 0x6f, 0x61, 0xf9, 0x68, 0x46, 0xfb, - 0xc3, 0x92, 0x39, 0x50, 0x79, 0x08, 0x4f, 0x7f, 0xe1, 0x49, 0x7b, 0xb9, - 0xb4, 0xd1, 0xcb, 0xfa, 0x24, 0x39, 0x93, 0x9c, 0xbf, 0xce, 0x18, 0x04, - 0x37, 0xa3, 0x95, 0xd3, 0xdf, 0x72, 0xcb, 0xf9, 0xa3, 0x52, 0xf9, 0xf3, - 0xad, 0x0f, 0x10, 0x0a, 0xff, 0x78, 0x0a, 0x0c, 0xbb, 0x87, 0x88, 0x05, - 0x79, 0xf7, 0x23, 0xc4, 0x02, 0xac, 0x3e, 0xaf, 0xd0, 0x6e, 0x79, 0x1e, - 0x20, 0x15, 0xf3, 0x8f, 0x32, 0x3c, 0x40, 0x2b, 0xfc, 0x8b, 0xee, 0x00, - 0x10, 0x78, 0x80, 0x57, 0x90, 0x42, 0x78, 0x80, 0x54, 0x14, 0x5c, 0xb0, - 0x8f, 0xa5, 0xfc, 0x4f, 0xec, 0xa9, 0xe2, 0x01, 0x5e, 0xdc, 0x78, 0xf1, - 0x00, 0xa8, 0xf1, 0x00, 0xaf, 0x34, 0x40, 0x1e, 0x20, 0x15, 0xd0, 0xc3, - 0xc4, 0x02, 0xa0, 0x9f, 0x36, 0x0c, 0x21, 0x5d, 0xf2, 0x30, 0x30, 0x78, - 0x80, 0x57, 0xbc, 0xeb, 0x3c, 0x40, 0x2b, 0xff, 0x0b, 0xcb, 0xef, 0x51, - 0x6f, 0xb3, 0xc4, 0x02, 0xbf, 0xf9, 0xfd, 0xfc, 0xe8, 0x3e, 0xeb, 0xc8, - 0xf1, 0x00, 0xae, 0x70, 0x9e, 0x20, 0x15, 0xfe, 0x17, 0x6f, 0x5a, 0x80, - 0x1e, 0x20, 0x15, 0xf9, 0x15, 0x71, 0x01, 0xe2, 0x01, 0x5c, 0x9a, 0x3c, - 0x40, 0x2a, 0xd9, 0xeb, 0xf8, 0xd2, 0xff, 0xf7, 0x53, 0xde, 0xcd, 0x7c, - 0xda, 0x43, 0x0f, 0x10, 0x0a, 0xfd, 0xe1, 0x8e, 0x64, 0x68, 0x80, 0x57, - 0x02, 0x0f, 0x10, 0x0b, 0xe9, 0xb5, 0xbf, 0x24, 0x31, 0xc2, 0x78, 0x80, - 0x57, 0xdf, 0xb8, 0xac, 0xf1, 0x00, 0xaf, 0x46, 0xd6, 0x78, 0x80, 0x57, - 0xfe, 0xce, 0x74, 0x18, 0xc1, 0x06, 0x8f, 0x10, 0x0a, 0xfd, 0xfb, 0xca, - 0x50, 0x78, 0x80, 0x57, 0xe7, 0x5f, 0x63, 0x93, 0xc4, 0x02, 0xac, 0x45, - 0xaf, 0x52, 0xff, 0x35, 0xbb, 0x60, 0x3c, 0x40, 0x2a, 0x92, 0xb3, 0x20, - 0x91, 0xe4, 0x25, 0xd6, 0x44, 0x90, 0x8d, 0xe9, 0xa8, 0x0c, 0xf4, 0x5f, - 0xe8, 0x6f, 0x7e, 0x61, 0x7e, 0xcf, 0x69, 0xf9, 0x3c, 0x40, 0x2b, 0xfc, - 0x18, 0x5c, 0xdb, 0x8f, 0x1e, 0x20, 0x10, 0x4d, 0xad, 0xed, 0xc3, 0x67, - 0x88, 0x05, 0x4b, 0x3f, 0xbd, 0xa8, 0xdf, 0xef, 0xde, 0x52, 0x85, 0x18, - 0x78, 0x80, 0x57, 0xc8, 0x32, 0xd1, 0xe2, 0x01, 0x5f, 0xcf, 0x34, 0xb3, - 0x99, 0x1e, 0x20, 0x15, 0x62, 0x33, 0xba, 0x44, 0x04, 0x2f, 0xcb, 0xaf, - 0xfb, 0xb1, 0xaf, 0xba, 0xff, 0x60, 0x3c, 0x40, 0x2b, 0x21, 0xe2, 0x01, - 0x5c, 0xf3, 0x84, 0xf9, 0xfa, 0x95, 0x76, 0xc0, 0x78, 0x80, 0x57, 0xe7, - 0xf6, 0x93, 0x93, 0xc4, 0x02, 0xbf, 0x90, 0x7f, 0x96, 0x68, 0xf1, 0x00, - 0xaa, 0x11, 0x26, 0x24, 0x9e, 0x35, 0xa8, 0x65, 0x3e, 0x06, 0x16, 0x99, - 0x0d, 0xb4, 0x3f, 0x98, 0x7f, 0x70, 0x8f, 0xe9, 0x6b, 0x97, 0x00, 0xa4, - 0x53, 0x35, 0x2e, 0x13, 0xd2, 0x86, 0x5a, 0x42, 0x91, 0x48, 0x60, 0xde, - 0xf2, 0x36, 0x78, 0xc2, 0x57, 0x9d, 0xd6, 0x68, 0x80, 0x5f, 0x53, 0x13, - 0xe6, 0x1d, 0x37, 0xca, 0xf0, 0xb8, 0x58, 0x72, 0xee, 0x33, 0x9c, 0xbf, - 0x71, 0x18, 0x0f, 0x4e, 0x54, 0x1e, 0x1a, 0x0d, 0x5f, 0xfd, 0x21, 0xc5, - 0xf5, 0x00, 0x0f, 0xe6, 0x39, 0x7e, 0xf6, 0x05, 0xfa, 0x72, 0xe0, 0x41, - 0x4b, 0x2a, 0x52, 0xf7, 0x62, 0x73, 0x97, 0x36, 0xd9, 0x4a, 0x43, 0xde, - 0x6b, 0x16, 0x98, 0x49, 0xb1, 0xdb, 0x68, 0xa7, 0xd3, 0xc0, 0xb3, 0x31, - 0x1d, 0x29, 0x0c, 0x5b, 0xc9, 0xff, 0x8e, 0x5f, 0xfe, 0xf6, 0xb1, 0x54, - 0xda, 0x80, 0x04, 0x72, 0x72, 0xa7, 0x67, 0x87, 0xc8, 0x80, 0x30, 0x9c, - 0x5d, 0x2e, 0xc1, 0x14, 0x36, 0xdc, 0xe4, 0x00, 0x8c, 0xbf, 0xc5, 0x8a, - 0x0e, 0xdf, 0xf6, 0x49, 0x02, 0xeb, 0xd4, 0x8e, 0x5f, 0xf3, 0x10, 0x56, - 0x9b, 0x40, 0x1c, 0xa5, 0x9f, 0x7f, 0x4e, 0x2f, 0x2f, 0xa2, 0x72, 0xff, - 0xef, 0x34, 0xc9, 0xa4, 0xfb, 0x9c, 0x30, 0x72, 0x98, 0x7c, 0x82, 0x39, - 0x7f, 0x79, 0x4e, 0x3c, 0x63, 0x47, 0x2f, 0xf6, 0x73, 0xef, 0x3c, 0xb4, - 0x72, 0xf4, 0xb8, 0x79, 0x1c, 0xbb, 0x99, 0x1e, 0x30, 0x05, 0x72, 0x78, - 0xe2, 0x45, 0x50, 0x9b, 0xbe, 0x42, 0x19, 0x08, 0x76, 0x66, 0xef, 0x77, - 0xff, 0xf2, 0x08, 0xff, 0xce, 0x73, 0xe0, 0xed, 0xf9, 0xc9, 0xce, 0x5f, - 0xa6, 0x94, 0x6e, 0x73, 0x97, 0xd0, 0xac, 0x30, 0xe5, 0x49, 0x15, 0x5b, - 0x5e, 0x61, 0x55, 0xff, 0xa5, 0xaf, 0x83, 0x8c, 0x8d, 0xaa, 0x72, 0xfe, - 0x94, 0x6c, 0x0a, 0x30, 0xe5, 0xff, 0xdc, 0x47, 0x35, 0xec, 0x19, 0x66, - 0x8e, 0x5f, 0x32, 0x3f, 0xf1, 0xca, 0xc3, 0xe7, 0x74, 0x4b, 0xf3, 0xfb, - 0xcf, 0xb3, 0x97, 0xbc, 0xe2, 0x72, 0xee, 0xbe, 0x23, 0xe0, 0x61, 0x2d, - 0xa2, 0x0e, 0x02, 0x7b, 0xfe, 0x86, 0xb0, 0xf6, 0x27, 0x71, 0x39, 0x7f, - 0xd0, 0xb8, 0x62, 0x30, 0x08, 0x72, 0xb6, 0x8c, 0x0e, 0xa7, 0x70, 0x1d, - 0xdf, 0xca, 0x37, 0xb4, 0xce, 0x94, 0xbf, 0x6b, 0xb1, 0x93, 0x9c, 0xbf, - 0xf8, 0x02, 0x99, 0xcf, 0xa6, 0x93, 0xec, 0xe5, 0xf4, 0xdd, 0x79, 0x8e, - 0x5f, 0x2d, 0xf7, 0x39, 0xcb, 0xf6, 0x4d, 0x28, 0xe4, 0xe5, 0xee, 0xa4, - 0xc7, 0x2f, 0x0c, 0x48, 0xa5, 0xff, 0x84, 0x09, 0xc1, 0xc1, 0xfc, 0xa1, - 0xac, 0xe5, 0x61, 0xf1, 0xb8, 0xdd, 0x7c, 0x4d, 0xf7, 0x92, 0x8d, 0xa2, - 0xf4, 0x90, 0x48, 0xfc, 0x53, 0xc1, 0x08, 0x0a, 0x85, 0xc7, 0x7c, 0x30, - 0x48, 0xfe, 0x7a, 0x66, 0xf1, 0xd6, 0x5f, 0xdc, 0xeb, 0x7b, 0x8f, 0x1c, - 0xbf, 0xa5, 0xa5, 0x76, 0xeb, 0x39, 0x78, 0x7d, 0xa3, 0x97, 0x85, 0x24, - 0x72, 0xfd, 0xaf, 0xc7, 0xf5, 0x9c, 0xbf, 0xbd, 0x34, 0xb3, 0x99, 0x1c, - 0xa8, 0x46, 0x02, 0x17, 0xb8, 0xe7, 0xe3, 0x6a, 0x15, 0x5f, 0xfd, 0xd6, - 0xe3, 0x7a, 0xc6, 0xdf, 0x6a, 0x9c, 0xbe, 0x08, 0x71, 0x87, 0x2e, 0x04, - 0x14, 0xb9, 0xb6, 0xca, 0x52, 0x1a, 0xf6, 0xc5, 0xaf, 0xc1, 0xfd, 0xf7, - 0x22, 0x9f, 0x4d, 0x0d, 0x62, 0x2b, 0x55, 0x72, 0xbf, 0xfd, 0xee, 0x56, - 0x9d, 0x69, 0x1e, 0xea, 0x9a, 0x39, 0x7f, 0xa2, 0x49, 0xe9, 0x47, 0x8e, - 0x5d, 0xc3, 0xe8, 0xe6, 0xcd, 0x95, 0xff, 0x75, 0xfd, 0xa5, 0x8e, 0x4e, - 0x72, 0xe5, 0xa1, 0xcb, 0xe1, 0x4e, 0x64, 0x72, 0xff, 0x93, 0x9e, 0xe0, - 0x76, 0xeb, 0x39, 0x50, 0x7b, 0x7b, 0x22, 0xbf, 0xda, 0xc4, 0xf2, 0xa9, - 0xd3, 0x97, 0xfd, 0xd8, 0xdc, 0x2d, 0x05, 0x67, 0x2f, 0x2a, 0xfa, 0x5a, - 0x3f, 0x36, 0xe3, 0xe2, 0x1e, 0x03, 0x3a, 0xc4, 0xe1, 0xfd, 0x19, 0xad, - 0x49, 0x5b, 0xa6, 0xe1, 0xe8, 0xc2, 0x3f, 0xe1, 0x02, 0xdc, 0x76, 0x77, - 0xf3, 0x6a, 0xbf, 0x86, 0x0e, 0x5f, 0x7e, 0xcc, 0x09, 0xca, 0xe4, 0xf4, - 0x78, 0x0b, 0xaf, 0xfd, 0xdc, 0xe0, 0x71, 0x57, 0x39, 0xf1, 0xcb, 0xfe, - 0xc5, 0xf5, 0x03, 0xdf, 0xd5, 0x39, 0x7b, 0xd8, 0xb3, 0x94, 0xc3, 0xd7, - 0xd1, 0xdd, 0xe9, 0x30, 0x07, 0x29, 0x54, 0x6c, 0x02, 0x13, 0x3e, 0x22, - 0xbf, 0xe5, 0x5f, 0xe4, 0x30, 0x51, 0x53, 0x97, 0xfe, 0x7d, 0x32, 0x13, - 0x7b, 0x46, 0xce, 0x5b, 0x4a, 0x9f, 0xcf, 0x4e, 0xef, 0x9e, 0x4f, 0xb3, - 0x97, 0xfd, 0x9e, 0xf2, 0x2b, 0xec, 0x59, 0xcb, 0xfa, 0x39, 0xd6, 0x73, - 0xe3, 0x97, 0x6e, 0x0e, 0x50, 0x4f, 0x17, 0xc5, 0xf7, 0xfb, 0xc8, 0xb4, - 0x0c, 0x78, 0xe5, 0xfb, 0x50, 0xbc, 0x61, 0xca, 0x83, 0xd9, 0xd1, 0x95, - 0xb4, 0x14, 0xc6, 0xb1, 0xfb, 0x6f, 0x75, 0xca, 0x73, 0x4c, 0x29, 0xf4, - 0x67, 0x77, 0xfd, 0xe4, 0x9e, 0x39, 0x06, 0xe0, 0xe5, 0xed, 0x7b, 0x0e, - 0x5d, 0x9a, 0xf8, 0x7a, 0xca, 0x1d, 0x5f, 0xfd, 0x9e, 0x4e, 0x64, 0x31, - 0xc3, 0x35, 0x36, 0x87, 0x2f, 0xff, 0x7f, 0x2e, 0xba, 0x79, 0x07, 0xdf, - 0xf4, 0xe5, 0xfb, 0x3c, 0x07, 0xf1, 0xca, 0x92, 0x30, 0xf6, 0xa2, 0xd1, - 0x2e, 0xff, 0xfd, 0x1d, 0x7c, 0x18, 0xda, 0xa1, 0xfd, 0xf7, 0x23, 0x95, - 0x24, 0xde, 0xbd, 0x0f, 0x3e, 0x03, 0x2a, 0x85, 0xe3, 0x7c, 0x85, 0x7a, - 0x43, 0xf9, 0xe5, 0x24, 0xff, 0x28, 0x22, 0xfb, 0xa8, 0xf2, 0x39, 0x7f, - 0xb0, 0x65, 0x9a, 0x51, 0x87, 0x2f, 0xcc, 0xd0, 0x1d, 0xce, 0x57, 0x8f, - 0x69, 0x43, 0x3b, 0xfe, 0xde, 0x0f, 0xce, 0xe7, 0x2d, 0x9c, 0xbf, 0xe9, - 0x0f, 0xe0, 0xf8, 0xb6, 0x00, 0xe5, 0x4e, 0x98, 0xbc, 0x9e, 0xf0, 0x8f, - 0x93, 0xcb, 0xff, 0x9f, 0xba, 0x49, 0x27, 0xa3, 0xda, 0x39, 0x7f, 0xb3, - 0xdd, 0x46, 0x8f, 0x39, 0xcb, 0xfe, 0x18, 0xce, 0x7d, 0x9b, 0x83, 0x97, - 0xfe, 0x8e, 0xa9, 0xa1, 0xcf, 0x77, 0x0e, 0x54, 0x26, 0x58, 0x87, 0xfd, - 0x43, 0x73, 0x50, 0x1b, 0xdf, 0x9f, 0x88, 0x43, 0x07, 0x2e, 0xd6, 0x8e, - 0x5e, 0x6d, 0xb6, 0xce, 0x5c, 0x07, 0x29, 0xf4, 0xd0, 0x56, 0xcf, 0x7f, - 0x46, 0xf7, 0xfe, 0xcd, 0x0b, 0xab, 0x30, 0xa4, 0xc7, 0x2f, 0xe0, 0x44, - 0xba, 0xa6, 0x8e, 0x5f, 0xc8, 0x20, 0x5a, 0xd0, 0xe5, 0xe7, 0x06, 0x14, - 0xa9, 0x26, 0xbe, 0xc8, 0x44, 0x74, 0x88, 0x07, 0xfc, 0x4b, 0xda, 0x16, - 0x5f, 0x40, 0x50, 0x27, 0x2f, 0xc1, 0xda, 0x7f, 0x39, 0xcb, 0xfc, 0xde, - 0x0e, 0x71, 0x4d, 0x9c, 0xbf, 0x87, 0x39, 0x02, 0x92, 0x39, 0x53, 0x22, - 0x34, 0x4a, 0xbc, 0x69, 0x7e, 0xcc, 0xf7, 0x70, 0xe5, 0xce, 0xc3, 0x97, - 0xfb, 0x38, 0xe7, 0xd6, 0xdb, 0x6c, 0xa5, 0xfa, 0x68, 0xce, 0xe8, 0xe5, - 0x09, 0xf1, 0x28, 0x75, 0x7f, 0xb8, 0x78, 0xfd, 0x7d, 0x4d, 0x9c, 0xbc, - 0xc7, 0xf1, 0xca, 0x99, 0x1d, 0xfd, 0x78, 0xfc, 0x8b, 0x89, 0xcd, 0xfc, - 0x3c, 0x5d, 0x88, 0xc3, 0x97, 0xec, 0x9a, 0x51, 0x23, 0x97, 0xf4, 0xe1, - 0x8c, 0x10, 0x9c, 0xa8, 0x56, 0x31, 0x26, 0x14, 0x85, 0x77, 0x4c, 0x1e, - 0x31, 0x5d, 0x20, 0xf8, 0xb9, 0x42, 0x8b, 0xce, 0x04, 0x39, 0x7f, 0xc1, - 0x1f, 0xf5, 0x93, 0xe4, 0xe7, 0x2f, 0x46, 0xc4, 0xe5, 0xfe, 0xc0, 0x8b, - 0xe9, 0x02, 0x72, 0xdd, 0x39, 0x7b, 0xf7, 0x9c, 0x4f, 0x0b, 0x46, 0x36, - 0x4d, 0xa2, 0x47, 0xcb, 0xb4, 0xc4, 0xc3, 0xdc, 0x6f, 0x87, 0x86, 0x65, - 0x84, 0xe5, 0xf4, 0x4f, 0x12, 0x39, 0x4e, 0x6c, 0x84, 0x42, 0xff, 0xf6, - 0x05, 0xd9, 0x9c, 0xcb, 0x01, 0x81, 0x39, 0x77, 0x5c, 0xe5, 0xd3, 0x68, - 0xe5, 0xfb, 0x38, 0xa0, 0x87, 0x0d, 0x72, 0x82, 0xd7, 0xf7, 0xcf, 0x66, - 0xb5, 0x07, 0x2f, 0xdd, 0xce, 0x7d, 0x07, 0x2f, 0xdc, 0x0f, 0x3a, 0x92, - 0x39, 0x5f, 0x13, 0x39, 0xfa, 0xef, 0x07, 0xd8, 0x5f, 0xf9, 0x45, 0xf0, - 0x73, 0xae, 0x72, 0xff, 0xd8, 0x32, 0xee, 0x08, 0xc3, 0x67, 0x2f, 0xfd, - 0x9b, 0xdb, 0xcb, 0xe7, 0x18, 0x6b, 0x39, 0x50, 0x88, 0x19, 0x1e, 0x56, - 0xd3, 0x12, 0x14, 0xef, 0x42, 0x8a, 0xff, 0x6f, 0x5d, 0xc1, 0x4d, 0x1c, - 0xa8, 0x55, 0xa2, 0x92, 0x9a, 0x9c, 0xd6, 0xff, 0xb0, 0x38, 0x30, 0x3f, - 0xc1, 0xcb, 0xa1, 0xb3, 0x95, 0x0f, 0x83, 0x6f, 0x3c, 0x29, 0xa5, 0x39, - 0x52, 0x19, 0xd3, 0x1c, 0x85, 0x4a, 0xb0, 0x82, 0x5c, 0xe1, 0x4f, 0x2e, - 0xa9, 0x18, 0x7c, 0xd0, 0x92, 0xdd, 0x3f, 0xc1, 0x92, 0xa2, 0x7b, 0x3a, - 0xda, 0xea, 0xa0, 0x87, 0x78, 0xd2, 0x7d, 0x35, 0x2a, 0x97, 0xd3, 0x97, - 0xff, 0xc7, 0x17, 0xc6, 0x59, 0xea, 0x86, 0xdc, 0x06, 0xd7, 0xfd, 0x9b, - 0x18, 0xf4, 0xb3, 0xa7, 0x2f, 0xe1, 0x06, 0x05, 0xe4, 0x72, 0xff, 0xbd, - 0xae, 0xa4, 0x31, 0xc2, 0x72, 0xff, 0xdd, 0x41, 0x8e, 0x74, 0x8c, 0x83, - 0x97, 0xb5, 0x1b, 0x39, 0x77, 0xb4, 0xb3, 0xd9, 0xe4, 0xf6, 0xa1, 0x18, - 0x1f, 0xc2, 0x46, 0xff, 0x2c, 0x72, 0x52, 0x7d, 0x1c, 0xbf, 0x9d, 0xbc, - 0x02, 0x9e, 0x39, 0x7e, 0x79, 0x7c, 0x0a, 0x1c, 0xbf, 0xb5, 0x81, 0x4d, - 0x4e, 0x72, 0xf4, 0xa0, 0x07, 0x2f, 0xca, 0x4d, 0x28, 0x6b, 0x29, 0x50, - 0xa9, 0x33, 0x0d, 0xd5, 0x87, 0x62, 0x14, 0x6c, 0xcb, 0xa5, 0xfa, 0x29, - 0xf1, 0x72, 0x83, 0x96, 0x59, 0xcb, 0xff, 0x95, 0x1f, 0xdd, 0x4c, 0xd2, - 0x40, 0x9c, 0xbc, 0xd1, 0x02, 0x72, 0xb6, 0x7c, 0x4c, 0x44, 0xbf, 0x99, - 0xee, 0xc7, 0x18, 0x39, 0x7f, 0xf7, 0x3e, 0xfd, 0x9d, 0x84, 0x17, 0x09, - 0xcb, 0xe5, 0x76, 0xed, 0x9c, 0xb2, 0x86, 0x88, 0x15, 0x6f, 0x1a, 0x81, - 0x45, 0x78, 0xde, 0xb6, 0x3f, 0x58, 0x88, 0x34, 0x61, 0xbf, 0x93, 0x87, - 0x5f, 0x61, 0xb3, 0x97, 0xfb, 0xa8, 0xa7, 0xd0, 0x02, 0x0a, 0x56, 0xcf, - 0xa5, 0xa1, 0x9d, 0xf0, 0xf0, 0x70, 0xfa, 0x39, 0x48, 0x79, 0xca, 0x12, - 0x5f, 0xdd, 0xcf, 0xf8, 0x7c, 0xd1, 0xcb, 0xfe, 0x1f, 0x6b, 0xfe, 0x7c, - 0x8d, 0x9c, 0xbf, 0xdf, 0xbe, 0xb3, 0x05, 0x53, 0x95, 0x07, 0xdf, 0xd3, - 0xcb, 0xfe, 0x8f, 0x6b, 0xe6, 0x31, 0x02, 0x72, 0xff, 0xdf, 0x05, 0xd5, - 0xf9, 0xa0, 0x02, 0x0e, 0x5f, 0xfe, 0x9f, 0xf0, 0x6a, 0x49, 0xad, 0x46, - 0xe4, 0x72, 0xc8, 0xaa, 0x24, 0x36, 0x87, 0x7f, 0x9f, 0xbc, 0xea, 0x07, - 0xc7, 0x2b, 0x47, 0xb9, 0xe2, 0x9b, 0xfd, 0xd4, 0x9a, 0x50, 0x32, 0x39, - 0x7f, 0xe8, 0x6f, 0x5c, 0x23, 0xaf, 0x39, 0xf1, 0xca, 0x59, 0xfc, 0x78, - 0xce, 0xfa, 0x5d, 0xc9, 0xce, 0x5f, 0xf4, 0x72, 0xc7, 0xf6, 0x73, 0xe3, - 0x95, 0xc9, 0xee, 0x89, 0x1d, 0xfb, 0xfe, 0xee, 0x1b, 0x39, 0x73, 0x47, - 0x39, 0x74, 0x2f, 0xc7, 0x84, 0xa1, 0x55, 0xdb, 0x73, 0x97, 0xff, 0x71, - 0x4d, 0x6b, 0x05, 0x6e, 0x20, 0x39, 0x7f, 0xba, 0x81, 0x0e, 0x37, 0x31, - 0xcb, 0xd1, 0xb0, 0x61, 0xfc, 0xad, 0x12, 0xb6, 0x8c, 0x1e, 0xc2, 0x3e, - 0xff, 0xcf, 0xce, 0xb3, 0xc8, 0xc7, 0x91, 0xcb, 0x78, 0xe5, 0x00, 0xf3, - 0xd4, 0x3e, 0xbf, 0xff, 0xd3, 0x0c, 0x33, 0x70, 0xbc, 0xde, 0x75, 0x37, - 0xd7, 0x39, 0x7f, 0xfc, 0xfb, 0x03, 0x4c, 0xdc, 0x49, 0x39, 0xf6, 0x1c, - 0xbf, 0xff, 0xfb, 0xfd, 0x75, 0xe5, 0xa9, 0x27, 0x94, 0xdc, 0x76, 0x3d, - 0xa7, 0xe4, 0xe5, 0xfa, 0x30, 0x7c, 0xd0, 0xe5, 0xfc, 0x9c, 0x83, 0x6e, - 0x13, 0x96, 0x61, 0xca, 0x61, 0xf3, 0xf4, 0xa0, 0x4b, 0xae, 0xdb, 0x59, - 0xcb, 0xd2, 0xfc, 0x27, 0x2e, 0x7e, 0x7e, 0x1f, 0x34, 0xc5, 0xce, 0x35, - 0x58, 0xa8, 0xbd, 0x17, 0xf6, 0xa3, 0xa8, 0xd0, 0xaf, 0xff, 0xec, 0x19, - 0xf5, 0xa8, 0x06, 0x75, 0x36, 0xed, 0xf8, 0xe5, 0xfc, 0x1c, 0x15, 0x77, - 0x07, 0x2a, 0x4b, 0xfd, 0x21, 0x85, 0x12, 0xc8, 0x79, 0x8c, 0x9a, 0x68, - 0x4d, 0x6d, 0xfd, 0x8c, 0x9d, 0x87, 0x78, 0x1d, 0xfd, 0x29, 0x49, 0xb4, - 0x36, 0x8b, 0x77, 0xff, 0xf8, 0x70, 0x3d, 0x86, 0xc7, 0x12, 0x76, 0x9f, - 0xf5, 0x36, 0x72, 0xa1, 0x92, 0x6e, 0x94, 0x80, 0xbf, 0xe1, 0x93, 0x68, - 0x39, 0x7f, 0xfd, 0x33, 0xbc, 0xb5, 0x0c, 0x0f, 0x60, 0x56, 0x72, 0xa0, - 0xf7, 0xd0, 0x42, 0xff, 0xb2, 0x69, 0x47, 0x39, 0xcf, 0x8e, 0x5d, 0xb9, - 0xf0, 0xf6, 0xc4, 0x82, 0xf8, 0x3d, 0xfe, 0x73, 0x97, 0xf8, 0x2f, 0x2c, - 0x9f, 0xf1, 0x39, 0x7f, 0xed, 0xe3, 0x5c, 0xdd, 0x76, 0x26, 0x8e, 0x5a, - 0x78, 0x44, 0xde, 0x12, 0xec, 0xd2, 0xee, 0x1f, 0x0e, 0x56, 0x1e, 0x83, - 0x9a, 0xdf, 0xde, 0x69, 0xff, 0x71, 0x67, 0x2f, 0xf6, 0xe3, 0xc8, 0x08, - 0x91, 0xcb, 0xfb, 0x99, 0xde, 0x50, 0xd6, 0x72, 0xe1, 0x91, 0xca, 0x83, - 0xc8, 0x9c, 0xca, 0xb8, 0x46, 0x74, 0xdc, 0x39, 0xaa, 0x44, 0x85, 0xec, - 0x86, 0x47, 0x69, 0x41, 0xef, 0x0f, 0xb1, 0x8c, 0x63, 0x44, 0x1e, 0x31, - 0xfd, 0xea, 0xff, 0xdc, 0x22, 0x90, 0xc5, 0xf5, 0xf9, 0x01, 0xcb, 0xfd, - 0x29, 0xb0, 0x5f, 0xb8, 0x72, 0xfb, 0x99, 0x43, 0x0e, 0x5f, 0xcf, 0x30, - 0x60, 0x67, 0x39, 0x53, 0x9e, 0x8f, 0x12, 0x3b, 0xf3, 0xc4, 0xc9, 0xd3, - 0x97, 0xd1, 0xff, 0x0e, 0x87, 0x2f, 0xf2, 0x6e, 0x27, 0x7d, 0xac, 0xe5, - 0xbd, 0xf1, 0x10, 0x3b, 0x27, 0xf1, 0x3d, 0xff, 0xed, 0xac, 0x73, 0x88, - 0xe4, 0x6e, 0x34, 0x72, 0xff, 0x3c, 0xdd, 0xc6, 0x66, 0x8e, 0x56, 0x1f, - 0xe7, 0x14, 0x9b, 0xfc, 0x2a, 0xfc, 0x8e, 0x29, 0xc4, 0xe5, 0xf9, 0x5f, - 0x66, 0x30, 0xe5, 0x61, 0xf0, 0xa1, 0xcd, 0xff, 0xe9, 0x87, 0x15, 0x55, - 0xfd, 0xa4, 0x19, 0x8e, 0x5f, 0xb0, 0x29, 0xbd, 0x1c, 0xbf, 0x6d, 0x71, - 0x93, 0x9c, 0xbd, 0xef, 0x72, 0x72, 0xff, 0xee, 0x56, 0x9d, 0xf9, 0xc1, - 0x9d, 0x46, 0x1c, 0xa0, 0x1f, 0x47, 0x87, 0xae, 0xff, 0x67, 0x2b, 0x11, - 0x95, 0xa8, 0x48, 0x34, 0x22, 0xb4, 0x4e, 0x99, 0x3b, 0x70, 0xf1, 0xa8, - 0x57, 0x43, 0x90, 0xa6, 0x48, 0x5a, 0x76, 0x10, 0x8e, 0x41, 0xe8, 0xdc, - 0xef, 0xfc, 0x28, 0xa7, 0x39, 0xc7, 0x98, 0x50, 0xe5, 0xff, 0xe4, 0xcd, - 0x86, 0x1b, 0xce, 0xc7, 0x3a, 0x39, 0x7c, 0xa4, 0x6c, 0x07, 0x2f, 0xfd, - 0x1c, 0xf7, 0xb1, 0x3c, 0x7e, 0xc3, 0x97, 0x3e, 0xce, 0x5f, 0xde, 0x49, - 0xd9, 0x0b, 0x39, 0x41, 0x3c, 0x4e, 0x8b, 0x5f, 0xfe, 0x04, 0xd2, 0x4d, - 0xca, 0x69, 0x26, 0xe4, 0x72, 0xf7, 0x92, 0x73, 0x95, 0xc9, 0xf5, 0x6d, - 0x36, 0xec, 0xe0, 0x39, 0x7c, 0x05, 0x06, 0x47, 0x2c, 0xe2, 0x6f, 0x3c, - 0x33, 0x7e, 0xd6, 0xb0, 0x40, 0x72, 0x80, 0x79, 0x82, 0x4b, 0x50, 0x9a, - 0xc2, 0x42, 0x33, 0xf8, 0x55, 0xdd, 0xcc, 0xc7, 0x2f, 0xca, 0x78, 0x0c, - 0xc3, 0x94, 0xc3, 0xc2, 0x00, 0xcd, 0xe5, 0xc6, 0x8e, 0x5f, 0xf4, 0x9f, - 0x7e, 0x18, 0x66, 0x8e, 0x5f, 0xe8, 0x0c, 0x6f, 0xf8, 0x01, 0xcb, 0x99, - 0xa9, 0x8f, 0xad, 0x87, 0x17, 0xff, 0xf3, 0xb6, 0x17, 0x7d, 0xcf, 0xd7, - 0xf7, 0x53, 0x72, 0x39, 0x7f, 0xe8, 0x71, 0xcf, 0x79, 0x1b, 0xf1, 0xca, - 0x84, 0xdc, 0x70, 0x89, 0x21, 0x0e, 0x25, 0xff, 0xae, 0x57, 0x0c, 0xc9, - 0x9b, 0x84, 0x69, 0x4e, 0x12, 0x63, 0x52, 0xd0, 0xe6, 0x4a, 0xe9, 0x1e, - 0xa3, 0xdd, 0xf4, 0x7d, 0xb7, 0xf4, 0x7f, 0xca, 0x73, 0xc0, 0x72, 0xfd, - 0x8d, 0xe7, 0x3e, 0x39, 0x5f, 0x0f, 0x71, 0x0c, 0xef, 0xf7, 0x32, 0xc0, - 0xf7, 0x27, 0x39, 0x5b, 0x3d, 0x81, 0x23, 0xbe, 0x57, 0x79, 0xa3, 0x97, - 0xff, 0x60, 0xfe, 0xbe, 0xe3, 0x26, 0x75, 0x9c, 0xa4, 0x3e, 0x8d, 0x11, - 0xdf, 0xe1, 0x57, 0xb0, 0xc6, 0x09, 0xcb, 0xf9, 0xad, 0x23, 0x83, 0xff, - 0x1c, 0xbf, 0x44, 0xd9, 0x8b, 0x39, 0x58, 0x88, 0xe4, 0x33, 0xe9, 0xa5, - 0xff, 0xbb, 0x93, 0x24, 0xdf, 0xf0, 0x7f, 0xa3, 0x97, 0x93, 0x6a, 0x9c, - 0xa4, 0x3e, 0x31, 0x46, 0xbf, 0x47, 0x07, 0x62, 0x63, 0x95, 0x23, 0xcb, - 0xd1, 0x05, 0xff, 0xdf, 0xcc, 0x9d, 0x8e, 0x65, 0x13, 0x41, 0xcb, 0xf0, - 0x5c, 0x63, 0xa7, 0x2f, 0xe9, 0x47, 0x3e, 0xce, 0x9c, 0xbf, 0xfd, 0xed, - 0x20, 0x22, 0x5a, 0xcc, 0xe7, 0xc7, 0x2a, 0x63, 0xf8, 0xd1, 0x75, 0x75, - 0x18, 0x2d, 0xc2, 0x7a, 0xff, 0x75, 0xe6, 0xc4, 0xe0, 0x09, 0xca, 0x43, - 0xdf, 0xd1, 0x4d, 0xff, 0xfb, 0x7f, 0xef, 0x70, 0x38, 0xaa, 0x77, 0xb8, - 0xa1, 0xcb, 0xf3, 0xa0, 0x60, 0x4e, 0x5d, 0x1f, 0x9c, 0xa1, 0x37, 0x9a, - 0x25, 0xbe, 0x9e, 0x38, 0x20, 0xe5, 0xf7, 0x40, 0xfe, 0x39, 0x6e, 0x9c, - 0xb7, 0x17, 0x36, 0x7f, 0x91, 0x5f, 0xfc, 0x8c, 0x4d, 0x76, 0x13, 0x7f, - 0xb5, 0x9c, 0xa8, 0x46, 0x42, 0x2c, 0x39, 0x4d, 0xfc, 0x3a, 0x4e, 0x30, - 0x13, 0x97, 0x85, 0x15, 0x39, 0x7f, 0x79, 0x36, 0x9e, 0xfc, 0xe5, 0xa1, - 0x87, 0x94, 0xa0, 0xe5, 0xfd, 0xfa, 0x9d, 0xce, 0x74, 0x72, 0xff, 0xff, - 0xfd, 0xb8, 0xf0, 0xba, 0xd3, 0x53, 0x26, 0xd7, 0x1a, 0xf4, 0x73, 0x0a, - 0x66, 0x8e, 0x5f, 0xee, 0xe7, 0x31, 0xb4, 0x61, 0xcb, 0xff, 0xff, 0xfe, - 0xd6, 0x7b, 0xae, 0xcd, 0x6f, 0x69, 0xcf, 0x9d, 0xd5, 0xcc, 0x9b, 0xff, - 0x43, 0x7c, 0xc1, 0xcb, 0xf7, 0xf3, 0x63, 0x4c, 0x39, 0x5a, 0x46, 0x1f, - 0xa1, 0x31, 0x7b, 0xb9, 0xb3, 0x97, 0xf7, 0x85, 0xc1, 0x82, 0x72, 0xfc, - 0x2e, 0x0c, 0x13, 0x95, 0xf0, 0xf4, 0x3c, 0x57, 0x50, 0xa8, 0xc4, 0x30, - 0x83, 0x78, 0x7b, 0x78, 0xa3, 0xf6, 0xcb, 0xff, 0x79, 0x34, 0x2f, 0xe9, - 0x9c, 0x27, 0x2f, 0x80, 0xfc, 0xe8, 0xe5, 0xcd, 0xb6, 0x72, 0xb4, 0x6f, - 0x1b, 0x23, 0xbe, 0xeb, 0xe7, 0x4a, 0x7d, 0x34, 0x55, 0x88, 0xcf, 0x48, - 0x4e, 0x5f, 0x94, 0xc6, 0x26, 0xce, 0x5f, 0xf7, 0xfe, 0x81, 0x5b, 0x56, - 0x06, 0x1c, 0xbd, 0xd8, 0x01, 0xcb, 0xff, 0x7e, 0x1e, 0xa6, 0xd3, 0x99, - 0xa0, 0xe5, 0x62, 0x31, 0x10, 0xa1, 0xcf, 0xc4, 0x72, 0xf7, 0x7e, 0x35, - 0x9c, 0xbf, 0x76, 0x07, 0x27, 0x39, 0x50, 0x79, 0x2e, 0x45, 0x7f, 0xbb, - 0x1e, 0xfd, 0x9f, 0xf8, 0xe5, 0x43, 0x2d, 0x3a, 0x50, 0x89, 0x0c, 0x2b, - 0xf9, 0x86, 0xe3, 0x59, 0x14, 0xd1, 0xb3, 0xec, 0x85, 0x90, 0x93, 0xec, - 0x3a, 0x1c, 0xb4, 0x0f, 0x1c, 0x39, 0x40, 0xca, 0x62, 0xd4, 0x64, 0x9e, - 0x87, 0x57, 0x18, 0x41, 0x70, 0x10, 0x5f, 0x26, 0xd4, 0x98, 0xe5, 0xd9, - 0x87, 0x2f, 0x97, 0xd4, 0x50, 0xe5, 0x74, 0xf7, 0x38, 0x72, 0x45, 0x05, - 0x6f, 0xd3, 0x44, 0xdd, 0x83, 0x97, 0x29, 0x07, 0x2f, 0x36, 0xdb, 0x65, - 0x2f, 0xa5, 0xec, 0x59, 0x4f, 0xa6, 0x82, 0xfd, 0x81, 0x40, 0x68, 0xf7, - 0x7f, 0x2b, 0x67, 0xd0, 0x26, 0x95, 0x08, 0xe9, 0xd9, 0x4b, 0xc2, 0x7e, - 0xef, 0x68, 0xe5, 0xfe, 0xf7, 0x63, 0xda, 0xea, 0x1c, 0xbf, 0x7c, 0xc9, - 0x92, 0x73, 0x95, 0xf0, 0xf7, 0xb4, 0x67, 0x6d, 0x1c, 0xbf, 0xde, 0xe6, - 0x5d, 0x81, 0x9c, 0xa5, 0xff, 0xb3, 0x99, 0x26, 0x08, 0xe0, 0x4e, 0x5f, - 0xa7, 0x67, 0xfc, 0xf8, 0xe5, 0x42, 0x68, 0xfc, 0xba, 0xec, 0x90, 0x44, - 0x74, 0x6b, 0xe3, 0xcb, 0xfd, 0xcc, 0xbf, 0x75, 0x1c, 0x27, 0x2f, 0xf8, - 0x61, 0xbd, 0x20, 0xf3, 0x23, 0x97, 0x42, 0xce, 0x50, 0x9e, 0x7f, 0x13, - 0x9b, 0xe9, 0xd4, 0x86, 0xb3, 0x97, 0xe1, 0x86, 0xf0, 0x4e, 0x5f, 0xf7, - 0x79, 0x85, 0x66, 0x94, 0x35, 0x9c, 0xb6, 0x82, 0x7c, 0xb8, 0x4d, 0x5b, - 0x45, 0x9f, 0xa1, 0x19, 0x50, 0x9e, 0xd6, 0x2b, 0xa4, 0x21, 0x5e, 0x1a, - 0xd7, 0xf0, 0xf3, 0xa9, 0xb3, 0xc7, 0x2f, 0xe4, 0xf0, 0xb8, 0x34, 0x72, - 0xff, 0xf7, 0xa6, 0xcd, 0xe3, 0xb2, 0x3a, 0x81, 0x39, 0x7f, 0x7e, 0xcc, - 0xef, 0x2e, 0x72, 0x95, 0x45, 0x20, 0x96, 0x69, 0x26, 0xff, 0xf2, 0x04, - 0x5f, 0x91, 0xcf, 0x62, 0x00, 0xe5, 0xf2, 0xc3, 0xfc, 0xe7, 0x2f, 0x4b, - 0x5f, 0x9c, 0xba, 0x3d, 0x87, 0x87, 0xd2, 0x5b, 0xf7, 0x5f, 0x79, 0xb3, - 0x97, 0x7e, 0xe7, 0x29, 0x66, 0xf8, 0x49, 0xef, 0xed, 0xc2, 0x49, 0xf4, - 0x72, 0xff, 0xdc, 0xe9, 0x15, 0xcf, 0x26, 0xf0, 0xe5, 0xa2, 0x74, 0x45, - 0x89, 0x07, 0x8b, 0x2f, 0xd3, 0xb5, 0xa6, 0x72, 0x72, 0xfc, 0x9a, 0x89, - 0xd8, 0x7b, 0x3f, 0x57, 0xe8, 0x7d, 0x83, 0xf3, 0xd9, 0xfa, 0xb9, 0xe4, - 0x7b, 0x3f, 0x57, 0xdf, 0xcb, 0x34, 0x7b, 0x3f, 0x54, 0x13, 0xd3, 0x12, - 0x3b, 0xf4, 0x66, 0xb0, 0x4f, 0x67, 0xea, 0x8f, 0x67, 0xea, 0xe7, 0xf1, - 0xec, 0xfd, 0x30, 0xb8, 0xb4, 0x84, 0xff, 0x3f, 0x4a, 0xbe, 0xc6, 0x88, - 0x03, 0xd9, 0xfa, 0xa3, 0xd9, 0xfa, 0xb8, 0x10, 0x7b, 0x3f, 0x57, 0xfd, - 0x80, 0x7d, 0xe7, 0x1c, 0x09, 0xec, 0xfd, 0x5f, 0xd9, 0xd4, 0xd7, 0xf3, - 0x9e, 0xcf, 0xd5, 0x01, 0x14, 0xa2, 0x47, 0xa4, 0x6b, 0xed, 0xcf, 0x1e, - 0x3d, 0x9f, 0xaa, 0x3d, 0x9f, 0xac, 0x36, 0x17, 0x36, 0xd9, 0xec, 0xfd, - 0x54, 0x95, 0x8d, 0x84, 0xd7, 0x21, 0x11, 0xcc, 0x27, 0x76, 0x50, 0xc3, - 0x0d, 0x42, 0xf7, 0xcb, 0xed, 0x93, 0xde, 0x94, 0x2a, 0x5b, 0x3f, 0x4f, - 0xa8, 0x90, 0xbf, 0xda, 0xc9, 0x4a, 0x3d, 0xc9, 0xca, 0xc3, 0xf3, 0xd1, - 0xfd, 0xff, 0xb1, 0x61, 0xcd, 0xb6, 0xfd, 0x98, 0xe5, 0xff, 0xda, 0x1c, - 0x9a, 0x27, 0x03, 0xf3, 0xa3, 0x97, 0x4a, 0x72, 0x97, 0xd3, 0x3b, 0xec, - 0xe5, 0x4e, 0x8e, 0x1e, 0x48, 0x7a, 0x80, 0x28, 0xdc, 0x03, 0x17, 0x24, - 0xe7, 0x2b, 0x6b, 0xb2, 0x0f, 0x3a, 0x57, 0xe4, 0xeb, 0xfc, 0xcd, 0x0e, - 0x7b, 0x00, 0x72, 0xfe, 0xf6, 0x76, 0x36, 0x03, 0x97, 0xfc, 0xb8, 0x00, - 0x7f, 0x7d, 0xc8, 0xe5, 0xff, 0x9d, 0xe7, 0xc6, 0x38, 0xf3, 0x23, 0x97, - 0x9d, 0x5d, 0x61, 0xfc, 0x4c, 0x75, 0x66, 0xfe, 0x23, 0x64, 0x61, 0x4b, - 0x50, 0x99, 0xdb, 0xc6, 0x17, 0x7e, 0x1f, 0x77, 0x27, 0x39, 0x70, 0x5b, - 0x39, 0x50, 0x78, 0x18, 0x51, 0x7f, 0xfe, 0x96, 0xe3, 0x8b, 0xcd, 0x01, - 0xec, 0x31, 0xe6, 0x39, 0x7f, 0xb8, 0x1f, 0x49, 0xa9, 0xb0, 0xe5, 0x72, - 0x88, 0xed, 0xac, 0x54, 0x33, 0xa3, 0xa5, 0x2d, 0x53, 0x11, 0x12, 0x1a, - 0x6d, 0x66, 0x1b, 0x84, 0x57, 0x61, 0xea, 0xf3, 0xb8, 0xa3, 0x1b, 0xae, - 0x9a, 0x3f, 0x85, 0x75, 0xff, 0xff, 0x27, 0x5f, 0xb1, 0x2f, 0xb8, 0x08, - 0x96, 0x83, 0xd8, 0xd9, 0xcb, 0xff, 0x2b, 0x1c, 0x8c, 0x77, 0xbf, 0xac, - 0xe5, 0xff, 0xdb, 0x8c, 0x1c, 0x92, 0x77, 0x38, 0x9c, 0xbf, 0xfe, 0x17, - 0x57, 0x59, 0xc6, 0x39, 0xf6, 0xbf, 0x61, 0xca, 0x0a, 0x25, 0xc5, 0x0e, - 0xfe, 0x17, 0x57, 0xaf, 0x23, 0x97, 0xe5, 0xe3, 0x23, 0x47, 0x2f, 0x36, - 0xdb, 0x65, 0x2f, 0x29, 0x00, 0x29, 0xf4, 0xd0, 0x5f, 0xf3, 0xc9, 0x4d, - 0xe7, 0x17, 0xd9, 0xcb, 0xff, 0xf7, 0x72, 0x4a, 0x08, 0xe4, 0xf3, 0x4a, - 0x37, 0x39, 0xca, 0x14, 0x49, 0xf8, 0xee, 0xff, 0xbc, 0xe3, 0x9a, 0xdc, - 0x68, 0xe5, 0xf4, 0xa0, 0x1c, 0x9c, 0xbf, 0x81, 0x03, 0x9c, 0xf8, 0xe5, - 0xce, 0x0f, 0x87, 0xa0, 0xa1, 0x1d, 0x3a, 0x2d, 0xc6, 0x10, 0xf7, 0xb8, - 0xc6, 0xce, 0x54, 0x95, 0xda, 0x05, 0x9f, 0x21, 0xb0, 0xc2, 0x27, 0x2d, - 0x02, 0x38, 0xc3, 0x0b, 0xd0, 0xd9, 0xe2, 0x4d, 0x72, 0x4e, 0x72, 0xff, - 0x0a, 0xc2, 0x9c, 0x60, 0x27, 0x28, 0x27, 0x97, 0xf8, 0xbd, 0x80, 0x72, - 0xff, 0xb2, 0x1a, 0xfe, 0x75, 0xf3, 0x67, 0x2f, 0x31, 0x26, 0x39, 0x7e, - 0xc0, 0x6a, 0x24, 0x72, 0xfc, 0x8c, 0x08, 0x70, 0xe5, 0x80, 0x27, 0x9c, - 0xd0, 0x9e, 0xff, 0xbd, 0xdc, 0xd7, 0xcf, 0x24, 0xe7, 0x2a, 0x0f, 0x95, - 0x0a, 0x6f, 0xf8, 0x53, 0xfe, 0x1f, 0x4d, 0x23, 0xc7, 0x2a, 0x49, 0xbe, - 0xcc, 0x22, 0xc3, 0xce, 0xc3, 0x40, 0x48, 0x2f, 0xb3, 0xca, 0x4e, 0x72, - 0xf3, 0x6d, 0xb6, 0x58, 0x84, 0x0b, 0xe5, 0xbb, 0xac, 0xb1, 0x08, 0x1f, - 0x4d, 0x75, 0xf3, 0xef, 0x1b, 0x39, 0x5b, 0x3e, 0x3e, 0x28, 0x37, 0x9b, - 0x6d, 0xb2, 0xc4, 0x1e, 0x51, 0x62, 0x0f, 0x3e, 0x9a, 0xeb, 0xfb, 0x3d, - 0xdf, 0xde, 0x47, 0x2f, 0x36, 0xdb, 0x67, 0x2f, 0x6a, 0x15, 0x29, 0xf4, - 0xd0, 0x56, 0x23, 0xe9, 0x6a, 0x42, 0x57, 0xe4, 0xea, 0x6b, 0x4f, 0xa9, - 0x91, 0xd7, 0xdf, 0xfd, 0xd8, 0x92, 0x7b, 0x3a, 0xb8, 0x61, 0xca, 0x83, - 0xf0, 0xe2, 0x5b, 0x7f, 0xfb, 0x3a, 0x9b, 0xeb, 0xe6, 0x91, 0xe7, 0x39, - 0x7d, 0x1e, 0x86, 0x1c, 0xa6, 0x1f, 0x4f, 0x92, 0x2f, 0xe6, 0xdc, 0x3f, - 0xba, 0x87, 0x2f, 0x85, 0x21, 0x53, 0x97, 0x94, 0x80, 0x1c, 0xa9, 0xcd, - 0xf3, 0x08, 0x6f, 0xcb, 0x8e, 0xc3, 0x0a, 0x5f, 0x85, 0xc4, 0x70, 0xa5, - 0xd8, 0xb2, 0x97, 0x36, 0xd9, 0x4a, 0xc3, 0xfa, 0xd1, 0x3f, 0x89, 0x1b, - 0x16, 0xbf, 0xc2, 0xa4, 0x03, 0xb9, 0xc0, 0x53, 0xe9, 0xbc, 0xbf, 0xfd, - 0x38, 0x76, 0xeb, 0x1c, 0xe3, 0xb4, 0xd1, 0xca, 0x84, 0xff, 0x30, 0x89, - 0x1b, 0x9e, 0x1b, 0x1f, 0xa4, 0x5f, 0xfd, 0x00, 0xd6, 0x60, 0x5c, 0x5d, - 0x53, 0x97, 0xff, 0xee, 0xa7, 0x14, 0x10, 0xea, 0x36, 0x99, 0xce, 0x8e, - 0x5f, 0xc3, 0x19, 0xb7, 0x01, 0xcb, 0xff, 0x46, 0xfb, 0x09, 0xd8, 0x14, - 0x39, 0x74, 0xb4, 0xb4, 0x5e, 0x79, 0x59, 0xb2, 0xbb, 0xfd, 0x03, 0x8c, - 0x4e, 0x64, 0x72, 0xff, 0xfb, 0x43, 0x9c, 0x81, 0xf4, 0xfb, 0x4e, 0x40, - 0x72, 0xb9, 0x45, 0xff, 0x8f, 0x5b, 0x32, 0xae, 0xa7, 0xde, 0xf1, 0xde, - 0xdf, 0xda, 0x50, 0x3f, 0x8c, 0x8e, 0x5f, 0xc8, 0xb0, 0xe3, 0x80, 0xe5, - 0xff, 0xfb, 0xda, 0xe7, 0xe0, 0x70, 0x30, 0xfb, 0xc1, 0x01, 0xcb, 0xff, - 0xff, 0x7c, 0xf4, 0xb0, 0x0d, 0x33, 0xe0, 0x70, 0x30, 0xfb, 0xc1, 0x01, - 0x10, 0xbf, 0xfb, 0x3d, 0xf1, 0x7d, 0x4e, 0xf5, 0x00, 0x68, 0x42, 0xd5, - 0x24, 0x63, 0xe9, 0xd2, 0xf4, 0x4f, 0xf7, 0x49, 0xa0, 0xfa, 0x31, 0xeb, - 0xf3, 0x34, 0xdb, 0xf2, 0x72, 0xda, 0x09, 0xf4, 0x28, 0x7d, 0x7f, 0x64, - 0xd2, 0x4d, 0xe8, 0xe5, 0xfd, 0x1c, 0xa9, 0xa8, 0xc3, 0x95, 0x0c, 0xc9, - 0xa0, 0xc3, 0x67, 0x23, 0xa0, 0x49, 0x55, 0x5b, 0x95, 0x10, 0xf2, 0x8f, - 0x38, 0x72, 0x91, 0x30, 0xd4, 0x7a, 0xbe, 0x29, 0xfc, 0xba, 0xf3, 0x6d, - 0xb6, 0x52, 0xf3, 0x88, 0x4a, 0x7d, 0x34, 0x17, 0xd9, 0xbc, 0xf1, 0xca, - 0x01, 0xe7, 0x68, 0xb6, 0xfb, 0xa8, 0xf2, 0x39, 0x7f, 0xbd, 0xa4, 0xde, - 0xd1, 0x87, 0x2f, 0x32, 0x70, 0x9c, 0xa1, 0x3d, 0x1f, 0x19, 0xde, 0xf8, - 0xab, 0x43, 0x97, 0xbc, 0xe1, 0x39, 0x5b, 0x37, 0xda, 0x22, 0xbf, 0x97, - 0x00, 0x4d, 0xaa, 0x52, 0xfe, 0x53, 0x37, 0x99, 0x31, 0xcb, 0xf3, 0xf7, - 0xe0, 0x60, 0xe5, 0x49, 0x39, 0x90, 0x91, 0x63, 0x92, 0x2f, 0x89, 0x0e, - 0x8b, 0xbc, 0x5d, 0x7e, 0x7d, 0xef, 0x39, 0x39, 0x7f, 0xfb, 0xdd, 0x47, - 0x06, 0x6c, 0x30, 0x32, 0x39, 0x7f, 0xfb, 0x9f, 0x9c, 0x82, 0x05, 0x6f, - 0x38, 0xb9, 0xca, 0x84, 0x5e, 0xe1, 0x40, 0xa4, 0x5f, 0xa3, 0x4a, 0x0c, - 0x8e, 0x5f, 0x7c, 0x5a, 0x48, 0xe5, 0xff, 0x97, 0x9b, 0xc4, 0xd7, 0x63, - 0x89, 0xcb, 0xff, 0xff, 0x9d, 0x3c, 0x9d, 0x5a, 0x7c, 0x92, 0x75, 0xc7, - 0xd2, 0xcd, 0xe1, 0xcb, 0xdd, 0xce, 0x03, 0x95, 0xd4, 0x47, 0xbb, 0x85, - 0xff, 0x0c, 0x73, 0xa8, 0xf4, 0x04, 0xe5, 0xed, 0x29, 0xaf, 0x87, 0xb5, - 0x84, 0x54, 0x14, 0xe0, 0xb9, 0x24, 0xf4, 0x65, 0x17, 0xff, 0xff, 0xfd, - 0x1a, 0x8f, 0x4f, 0x8d, 0xef, 0x3a, 0xea, 0x6b, 0x15, 0x71, 0x04, 0x0c, - 0x4d, 0xd8, 0x39, 0x7e, 0xd7, 0x5d, 0x70, 0x72, 0x85, 0x17, 0x6d, 0xc2, - 0x52, 0xff, 0xff, 0xe4, 0x57, 0x99, 0x7b, 0x07, 0xda, 0xf9, 0xad, 0x66, - 0xf0, 0x5e, 0x47, 0x2f, 0xfe, 0xfa, 0x11, 0x8f, 0xd7, 0x8a, 0xa6, 0xce, - 0x5d, 0x8d, 0x9c, 0xb6, 0x41, 0xef, 0x69, 0x1e, 0xff, 0x07, 0xb1, 0x33, - 0xbf, 0x27, 0x2f, 0x74, 0x1c, 0x4e, 0x56, 0xcf, 0x4f, 0x80, 0xd2, 0xa4, - 0x89, 0xe7, 0x79, 0xbf, 0xfb, 0x36, 0x06, 0x26, 0x94, 0xd4, 0x61, 0xcb, - 0xf0, 0x77, 0x1c, 0xb5, 0x9c, 0xbf, 0xff, 0xf7, 0xa3, 0x60, 0x5f, 0x52, - 0x49, 0xb7, 0x07, 0x86, 0x19, 0xa3, 0x97, 0x35, 0xe8, 0xe5, 0x2a, 0x88, - 0x57, 0x6b, 0xa9, 0x26, 0x31, 0x88, 0x8f, 0x0b, 0x1b, 0xcd, 0x40, 0x80, - 0xe5, 0xd8, 0xc3, 0x97, 0xff, 0x60, 0x83, 0xe2, 0x9b, 0x03, 0x13, 0x47, - 0x28, 0x27, 0xba, 0xc1, 0x6b, 0xe0, 0x7b, 0x00, 0x72, 0xfd, 0x1a, 0xd2, - 0x71, 0x39, 0x48, 0x7d, 0xbb, 0x22, 0xe9, 0x15, 0xe6, 0x9c, 0xc1, 0xcb, - 0xfe, 0x5f, 0x46, 0x39, 0x48, 0xe9, 0xca, 0x86, 0x42, 0xfc, 0xa3, 0x1f, - 0x09, 0x6e, 0x47, 0x54, 0x90, 0xf3, 0xd9, 0x43, 0xc6, 0xe0, 0x31, 0x9d, - 0x68, 0xd3, 0xf8, 0x75, 0xb4, 0x2e, 0x50, 0x7e, 0xff, 0xce, 0x81, 0xff, - 0xda, 0x9f, 0x1b, 0x39, 0x7e, 0xd6, 0x2b, 0x1a, 0x39, 0x7f, 0x35, 0xe9, - 0x07, 0x99, 0x1c, 0xbf, 0xf3, 0xed, 0xa2, 0x77, 0x1f, 0x90, 0x1c, 0xbf, - 0xff, 0x27, 0xa1, 0x99, 0xcf, 0xa1, 0x8a, 0x6d, 0xc0, 0x72, 0xf9, 0x05, - 0xc2, 0x72, 0xff, 0xb5, 0x1b, 0xf4, 0x7d, 0x0a, 0x1c, 0xa9, 0x22, 0xc0, - 0x2a, 0xda, 0x20, 0xbf, 0xfd, 0xa4, 0xdc, 0x4b, 0xb1, 0x30, 0xfe, 0xa9, - 0xcb, 0x96, 0xd0, 0xe5, 0xfc, 0xaf, 0xa3, 0xb1, 0xa3, 0x97, 0xf7, 0x53, - 0x9d, 0x3f, 0x27, 0x2a, 0x47, 0xec, 0x83, 0x20, 0x2e, 0xbf, 0xe7, 0x9b, - 0xaf, 0xbd, 0xa0, 0x4e, 0x5f, 0x27, 0x5d, 0x87, 0x28, 0x4f, 0x6b, 0xc7, - 0x37, 0xed, 0xe6, 0x91, 0xb3, 0x97, 0xa1, 0xa9, 0xb9, 0xcb, 0xf9, 0x48, - 0xfd, 0x7f, 0xb0, 0xe5, 0xc8, 0x27, 0x2f, 0xa5, 0x02, 0xb3, 0x94, 0x13, - 0x6d, 0x82, 0xb7, 0xf4, 0x7b, 0x84, 0x78, 0xe4, 0xe5, 0x7c, 0x3d, 0x24, - 0x20, 0xbe, 0x80, 0x60, 0x9c, 0xa9, 0x2e, 0x14, 0xe1, 0x42, 0xcc, 0x52, - 0x1e, 0x13, 0x18, 0x6e, 0x18, 0x4c, 0x84, 0x43, 0x90, 0xe8, 0xa3, 0xf2, - 0x16, 0xe1, 0x72, 0xd0, 0x8e, 0xfc, 0x8c, 0xe1, 0x4d, 0x4d, 0xab, 0x39, - 0x7c, 0xa4, 0x37, 0xa3, 0x97, 0x03, 0xc7, 0x2e, 0x07, 0x4e, 0x5f, 0x6f, - 0x79, 0xa3, 0x97, 0x64, 0xc7, 0x2d, 0x2f, 0x88, 0x8b, 0x9c, 0x91, 0x82, - 0xee, 0x2e, 0xa1, 0x15, 0xf9, 0x3c, 0xe3, 0x87, 0x2f, 0xdb, 0x0e, 0x60, - 0x9c, 0xbf, 0xf9, 0xad, 0x33, 0xb1, 0xc7, 0x5d, 0x8e, 0x4e, 0x5f, 0xdc, - 0xef, 0xfe, 0x7d, 0x23, 0x94, 0xe8, 0xa1, 0xd1, 0x37, 0xe9, 0x37, 0xe6, - 0xfd, 0xec, 0x9c, 0xe5, 0xff, 0x60, 0xef, 0x35, 0x89, 0xd3, 0x97, 0xff, - 0xd2, 0xf0, 0xe3, 0xf8, 0x73, 0xde, 0xc6, 0xce, 0x5d, 0x9c, 0x4e, 0x5f, - 0xf2, 0xfb, 0x81, 0x62, 0x6f, 0x0e, 0x54, 0xe7, 0xa1, 0x83, 0x17, 0xf4, - 0x46, 0xfb, 0x1c, 0x4e, 0x5f, 0xfe, 0xf6, 0xb2, 0x6e, 0xc7, 0x1c, 0xef, - 0x60, 0xe5, 0xfd, 0xd0, 0xa7, 0x18, 0x09, 0xca, 0xc3, 0xfb, 0x74, 0xcb, - 0xed, 0x26, 0x00, 0xe5, 0xf6, 0x79, 0x34, 0x72, 0xfe, 0x6a, 0x26, 0x16, - 0xae, 0x7f, 0xce, 0x56, 0x8f, 0x73, 0xc4, 0x35, 0x25, 0x6f, 0xc1, 0x86, - 0x36, 0x18, 0x2c, 0xab, 0x93, 0x6d, 0xc2, 0x7b, 0xa4, 0x43, 0x0a, 0x9d, - 0x10, 0x79, 0xf6, 0xff, 0xfd, 0xe4, 0xd4, 0xf8, 0xde, 0x92, 0x71, 0x7e, - 0x7c, 0x72, 0xf3, 0x79, 0xd3, 0x97, 0xfb, 0x48, 0xaf, 0x5c, 0x50, 0xe5, - 0xfa, 0x70, 0x8b, 0xaa, 0x72, 0xf9, 0x35, 0x81, 0xc4, 0x68, 0x3a, 0xc7, - 0x87, 0x54, 0x32, 0xbf, 0xf3, 0xb5, 0x83, 0xfd, 0x20, 0xf3, 0x23, 0x97, - 0xf8, 0x38, 0x28, 0xdf, 0x7f, 0x39, 0x7f, 0xfd, 0xd4, 0x8f, 0x20, 0x22, - 0x5f, 0x5b, 0x6d, 0xb2, 0x97, 0xff, 0x24, 0x78, 0x11, 0x2f, 0xad, 0xb6, - 0xd9, 0x4a, 0xc4, 0x4e, 0xf5, 0x52, 0xa7, 0x47, 0x9f, 0xa1, 0xa3, 0x7f, - 0xbb, 0xfb, 0xb0, 0x2e, 0xc3, 0x94, 0x27, 0xbb, 0xe2, 0x9b, 0xe0, 0xe6, - 0x2a, 0x52, 0xf9, 0xc0, 0xfe, 0x39, 0x7f, 0xdb, 0x75, 0xfc, 0xec, 0x28, - 0x27, 0x2f, 0x7f, 0x1b, 0x39, 0x77, 0xb4, 0x13, 0xd8, 0x98, 0xee, 0xf4, - 0x87, 0xf3, 0x44, 0x32, 0xbd, 0xd8, 0x9c, 0xe5, 0xfb, 0xd1, 0x25, 0x58, - 0x72, 0xf3, 0x6d, 0xb6, 0x52, 0xf6, 0x0a, 0xca, 0x7d, 0x34, 0x17, 0xfe, - 0xc9, 0xf0, 0x2f, 0x21, 0x89, 0xce, 0x54, 0x22, 0xd0, 0x09, 0x22, 0x5b, - 0x7c, 0xe2, 0xd4, 0xb8, 0x63, 0x97, 0x35, 0x26, 0xa4, 0x72, 0xfd, 0x9e, - 0xf7, 0xf3, 0x9c, 0xb4, 0x9a, 0x91, 0xe6, 0x89, 0x1d, 0xe7, 0x6b, 0x83, - 0x97, 0xec, 0x0f, 0x5d, 0xac, 0xe5, 0xf8, 0x70, 0x30, 0xc3, 0x95, 0x0a, - 0xca, 0x27, 0x21, 0x09, 0x16, 0x3c, 0xf2, 0x5f, 0x31, 0x56, 0xe1, 0xa3, - 0xd2, 0xe7, 0x79, 0xfc, 0xb7, 0x88, 0xf3, 0x65, 0x57, 0xf3, 0x31, 0x37, - 0x34, 0x8e, 0x5f, 0xff, 0x2a, 0xa3, 0x8f, 0x5e, 0x5a, 0xc6, 0x43, 0x59, - 0xca, 0x84, 0x40, 0xa1, 0x75, 0xef, 0x24, 0x1c, 0xbb, 0x04, 0xe5, 0x21, - 0xb0, 0xfc, 0x6e, 0xfc, 0x31, 0xcc, 0x68, 0xe5, 0xff, 0xb1, 0x05, 0xfd, - 0xa6, 0xe0, 0x4e, 0x5e, 0xeb, 0xee, 0x0f, 0x8f, 0x44, 0xf7, 0xc9, 0xb8, - 0xf1, 0xcb, 0xed, 0x64, 0x48, 0xe5, 0x04, 0xf0, 0x84, 0x86, 0xfd, 0x12, - 0xee, 0x72, 0x72, 0xee, 0x40, 0x72, 0xfe, 0x64, 0x68, 0x08, 0xb3, 0x97, - 0xb5, 0x0a, 0x80, 0xf1, 0x74, 0x31, 0x7f, 0xbf, 0xcd, 0x80, 0x08, 0x27, - 0x2f, 0x3b, 0x57, 0x39, 0xcb, 0xff, 0x63, 0x10, 0x3b, 0xc0, 0xbb, 0x0e, - 0x5f, 0x63, 0x14, 0x09, 0xca, 0xe9, 0xf0, 0x09, 0xed, 0xff, 0xe4, 0x0f, - 0x54, 0xd6, 0x6d, 0x6e, 0xeb, 0x34, 0x41, 0x8b, 0xff, 0x77, 0xf7, 0x57, - 0x3d, 0xec, 0xe9, 0xcb, 0xff, 0x68, 0x0f, 0xce, 0x94, 0xdf, 0x5c, 0xe5, - 0xf7, 0xfd, 0xc5, 0x9c, 0xa9, 0x23, 0xec, 0x2a, 0xfe, 0x40, 0x68, 0x83, - 0x7f, 0xda, 0xd4, 0x6e, 0x4b, 0x49, 0xce, 0x5f, 0xdf, 0xaa, 0x39, 0x3f, - 0xe7, 0x2a, 0x0f, 0xaf, 0xa7, 0x57, 0xbb, 0xfb, 0x59, 0xcb, 0xff, 0xdb, - 0x7e, 0x38, 0x2b, 0xea, 0x01, 0x4f, 0x1c, 0xa8, 0x4c, 0xe2, 0x50, 0xaa, - 0xe1, 0xc8, 0x7f, 0x21, 0xae, 0x55, 0xc2, 0xf4, 0xd0, 0x4c, 0xf5, 0x08, - 0x2f, 0x4a, 0x54, 0xbc, 0xfc, 0x70, 0xe5, 0xc0, 0x01, 0xcb, 0xfe, 0x5f, - 0x53, 0x62, 0x9e, 0xd1, 0xca, 0x61, 0xe7, 0x80, 0x5e, 0xff, 0x01, 0x3b, - 0xdc, 0x03, 0x9c, 0xbf, 0xff, 0xe6, 0x67, 0xbc, 0xfb, 0x18, 0xe6, 0x4a, - 0x6c, 0x0c, 0x4d, 0x1c, 0xbf, 0xe6, 0x23, 0x78, 0x21, 0xec, 0x1c, 0xbb, - 0xbf, 0x9c, 0xbf, 0xff, 0x49, 0x04, 0x3d, 0xce, 0x54, 0x71, 0xf0, 0x84, - 0xe5, 0xe4, 0x6d, 0xac, 0xe5, 0xfe, 0xce, 0x3a, 0xf7, 0xa1, 0x87, 0x2b, - 0x67, 0xab, 0xd2, 0x0a, 0x84, 0xe1, 0x31, 0xa1, 0x0e, 0x26, 0x18, 0xd4, - 0x2a, 0xaf, 0xe4, 0x62, 0xf0, 0x56, 0x72, 0xfe, 0xcd, 0x34, 0xcd, 0xc1, - 0xca, 0xd9, 0xed, 0x34, 0x2c, 0xa9, 0x32, 0x1c, 0xc3, 0x08, 0x4c, 0x74, - 0x59, 0x0a, 0x4b, 0xf2, 0x62, 0xc3, 0xb6, 0x00, 0x8b, 0x51, 0xdb, 0x7a, - 0x15, 0x17, 0xfb, 0x5a, 0xc1, 0x03, 0x4c, 0x39, 0x7c, 0x29, 0xc1, 0x07, - 0x2d, 0x31, 0xcb, 0xfb, 0x58, 0x20, 0x69, 0x87, 0x2d, 0xc7, 0xe2, 0x25, - 0xf0, 0xd0, 0x04, 0x7a, 0x12, 0xbf, 0xef, 0xfc, 0x0f, 0xd9, 0x19, 0xe3, - 0x97, 0xff, 0x86, 0x7f, 0x93, 0x20, 0xe0, 0x70, 0x55, 0x39, 0x7f, 0x27, - 0x3c, 0x1d, 0x8f, 0x1c, 0xbc, 0xa6, 0x41, 0xca, 0x84, 0x4c, 0xb5, 0xa6, - 0x39, 0x8d, 0xff, 0xfe, 0xc1, 0x7f, 0x6b, 0x36, 0x00, 0x46, 0x73, 0xed, - 0x21, 0xcb, 0xb1, 0xa1, 0xcb, 0x38, 0x4f, 0xdf, 0xcb, 0xf7, 0xa3, 0x73, - 0x1c, 0xaf, 0x8d, 0xeb, 0x54, 0x4e, 0x35, 0x4f, 0x0b, 0xe0, 0xc3, 0x13, - 0x25, 0xe8, 0xae, 0x36, 0xbe, 0x54, 0x92, 0x72, 0xef, 0xb1, 0x98, 0xbd, - 0x23, 0x10, 0x11, 0x9d, 0x0a, 0x37, 0xf0, 0xd4, 0x6e, 0x15, 0x0d, 0x09, - 0xef, 0x73, 0x3f, 0x13, 0x97, 0xf7, 0xc5, 0xf6, 0x39, 0xe0, 0x39, 0x7b, - 0xe0, 0x1b, 0x39, 0x5c, 0x9e, 0xa7, 0x8d, 0x2f, 0xec, 0x6f, 0x30, 0x55, - 0x39, 0x7c, 0xc7, 0xcd, 0x1c, 0xa4, 0x3c, 0xe7, 0x2d, 0xbf, 0xfe, 0x5c, - 0x6b, 0x50, 0xcc, 0xf2, 0x6b, 0xae, 0x72, 0xff, 0x08, 0xc4, 0x99, 0x08, - 0x72, 0xff, 0x79, 0x38, 0xa7, 0xa5, 0x05, 0x2c, 0xc3, 0x97, 0xf6, 0x0a, - 0xbb, 0x8f, 0xa8, 0x78, 0xaa, 0x1a, 0x56, 0x26, 0x12, 0x89, 0xda, 0x75, - 0xbe, 0xdf, 0xfc, 0xc8, 0xe5, 0xfe, 0x19, 0x0e, 0x32, 0x16, 0x72, 0xf3, - 0x03, 0x87, 0x2a, 0x0f, 0xcb, 0x09, 0x5c, 0xc6, 0xf3, 0x4f, 0xfc, 0x72, - 0xf9, 0xf6, 0xea, 0x1c, 0xbf, 0xfd, 0xe8, 0x62, 0x07, 0x05, 0x5e, 0xc3, - 0x0e, 0x52, 0xd1, 0x17, 0xa2, 0x0f, 0x11, 0x5f, 0xff, 0x27, 0xbb, 0x1a, - 0x8e, 0xc2, 0x4f, 0x0a, 0x9c, 0xbf, 0xdd, 0x89, 0xa4, 0x9b, 0x91, 0xcb, - 0xfd, 0xe4, 0x6e, 0x61, 0x76, 0xce, 0x5f, 0xbd, 0xed, 0x38, 0x0e, 0x5f, - 0xa1, 0x9e, 0xc5, 0x9c, 0xb9, 0x27, 0x39, 0x50, 0x98, 0xf0, 0x53, 0xf9, - 0x34, 0x43, 0x5e, 0x94, 0x78, 0x9e, 0xfc, 0xda, 0x07, 0x81, 0x0e, 0x5f, - 0xf7, 0x62, 0x48, 0x38, 0xc8, 0x39, 0x7f, 0xd9, 0xee, 0xe3, 0x05, 0xfc, - 0x72, 0xfe, 0xe2, 0x9b, 0xe6, 0x1a, 0xce, 0x58, 0x42, 0x7d, 0x58, 0x6f, - 0x7e, 0x64, 0x2e, 0x70, 0x9c, 0xbe, 0x94, 0x31, 0xce, 0x5f, 0xb6, 0x06, - 0x26, 0x8e, 0x5d, 0xed, 0x61, 0xf9, 0x39, 0x4a, 0x84, 0x35, 0x08, 0xd2, - 0xfe, 0x13, 0x16, 0xd1, 0xcb, 0xfa, 0x27, 0xc1, 0x45, 0x4e, 0x56, 0xcd, - 0xf6, 0x84, 0x6f, 0xfe, 0x81, 0x7e, 0xc0, 0x3e, 0xef, 0x5a, 0x29, 0x53, - 0xaa, 0x3e, 0x0c, 0x6e, 0x58, 0xcc, 0xc2, 0x1b, 0xfc, 0xe1, 0xd6, 0xa3, - 0x72, 0x39, 0x77, 0xf3, 0x9c, 0xbf, 0xdc, 0xcb, 0x9d, 0x27, 0xa0, 0xe5, - 0xe4, 0xe7, 0x47, 0x2b, 0x0f, 0x49, 0x0d, 0x69, 0x11, 0x17, 0xd6, 0xbb, - 0xb1, 0x67, 0x2f, 0x6f, 0x34, 0x73, 0xc5, 0xb5, 0xff, 0xf0, 0x7e, 0x3a, - 0x66, 0xa2, 0x7c, 0x14, 0x54, 0xe5, 0xfe, 0xdb, 0x23, 0x9f, 0x3a, 0xce, - 0x5f, 0xff, 0xc3, 0x9e, 0xee, 0x4b, 0x17, 0x0b, 0xf0, 0xbb, 0x0e, 0x56, - 0x23, 0x71, 0x14, 0x34, 0x69, 0x7c, 0x8c, 0x89, 0x8e, 0x5f, 0xfd, 0xa4, - 0xe4, 0x72, 0x6d, 0xc7, 0xb4, 0x72, 0xfb, 0x27, 0xfe, 0x47, 0x2a, 0x64, - 0x45, 0x80, 0x89, 0xb4, 0x5b, 0xef, 0xc2, 0x18, 0x39, 0x50, 0x7a, 0xae, - 0x65, 0x76, 0x36, 0x72, 0x8b, 0x88, 0x61, 0x7f, 0x69, 0x48, 0xdc, 0x30, - 0xb8, 0x86, 0x14, 0x5c, 0x43, 0x0a, 0x2e, 0x21, 0x85, 0x17, 0x10, 0xc2, - 0x8b, 0x88, 0x61, 0x52, 0x45, 0xca, 0x0c, 0x80, 0xf3, 0xf1, 0x96, 0x83, - 0x3c, 0x03, 0x37, 0x77, 0x0b, 0x88, 0x61, 0x7f, 0x3b, 0xfa, 0x68, 0x61, - 0x71, 0x0c, 0x3e, 0x1a, 0x4b, 0x70, 0xe5, 0xc4, 0x30, 0xa2, 0xe2, 0x18, - 0x51, 0x71, 0x0c, 0x2a, 0x46, 0xc9, 0x06, 0x68, 0xb8, 0x86, 0x14, 0x5c, - 0x43, 0x0a, 0x2e, 0x21, 0x85, 0x17, 0x10, 0xc2, 0x8b, 0x88, 0x61, 0x45, - 0xc4, 0x30, 0xa9, 0xd1, 0x2c, 0x11, 0x94, 0x19, 0x00, 0xce, 0x86, 0x78, - 0x8c, 0xd1, 0x71, 0x0c, 0x28, 0xb8, 0x86, 0x15, 0x23, 0x65, 0xa1, 0x9a, - 0x2e, 0x21, 0x85, 0x17, 0x10, 0xc2, 0x8b, 0x88, 0x61, 0x45, 0xc4, 0x30, - 0xa9, 0x1f, 0x20, 0x06, 0x7c, 0x33, 0xc0, 0x33, 0x45, 0xc4, 0x30, 0xa2, - 0xe2, 0x18, 0x51, 0x71, 0x0c, 0x28, 0xb8, 0x86, 0x15, 0x39, 0xf2, 0x2a, - 0x33, 0xb1, 0x9e, 0x8c, 0xd9, 0x52, 0xe2, 0x18, 0x51, 0x71, 0x0c, 0x28, - 0xb8, 0x86, 0x14, 0x5c, 0x43, 0x0a, 0x2e, 0x21, 0x85, 0x04, 0xf9, 0x39, - 0x19, 0x00, 0xcf, 0xe3, 0x34, 0x5c, 0x43, 0x0a, 0x2e, 0x21, 0x85, 0x17, - 0x10, 0xc2, 0xfd, 0xd8, 0x06, 0xb0, 0xb8, 0x86, 0x14, 0x5c, 0x43, 0x0a, - 0x92, 0x26, 0x56, 0x33, 0xd1, 0x97, 0x19, 0x01, 0xad, 0x96, 0x5c, 0x43, - 0x0a, 0x2e, 0x21, 0x85, 0x17, 0x10, 0xc2, 0x8b, 0x88, 0x61, 0x45, 0xc4, - 0x30, 0xa9, 0x1f, 0x27, 0x23, 0x28, 0x33, 0xc4, 0x66, 0x8b, 0x88, 0x61, - 0x45, 0xc4, 0x30, 0xa2, 0xe2, 0x18, 0x51, 0x71, 0x0c, 0x2a, 0x47, 0xc8, - 0x11, 0x9e, 0x8c, 0x88, 0xcd, 0xba, 0x5c, 0x43, 0x0a, 0x2e, 0x21, 0x85, - 0x17, 0x10, 0xc2, 0xd2, 0x2e, 0x21, 0x85, 0x17, 0x10, 0xc3, 0x92, 0xfe, - 0x8b, 0x88, 0x61, 0x45, 0xc4, 0x30, 0xa2, 0xe2, 0x18, 0x51, 0x71, 0x0c, - 0x2a, 0x74, 0x6f, 0x48, 0x65, 0x53, 0x85, 0x94, 0xcc, 0x32, 0x01, 0x9f, - 0x0c, 0xdb, 0x0b, 0x88, 0x61, 0x45, 0xc4, 0x30, 0xa2, 0xe2, 0x18, 0x5a, - 0x45, 0xc4, 0x30, 0xa2, 0xe2, 0x18, 0x72, 0x5f, 0xd1, 0x71, 0x0c, 0x28, - 0xb8, 0x86, 0x15, 0x08, 0xac, 0x90, 0xca, 0x1c, 0x6c, 0xa5, 0x83, 0x34, + 0xfc, 0x72, 0xfe, 0xeb, 0xcf, 0xf2, 0x5e, 0x39, 0x7f, 0x3c, 0xca, 0x6e, + 0x30, 0xe5, 0xf9, 0xf4, 0x3c, 0xa1, 0xca, 0x84, 0x59, 0xa1, 0x6f, 0x4c, + 0x7c, 0x5d, 0x7b, 0xae, 0x27, 0x28, 0x2a, 0xc2, 0xb0, 0xa1, 0x52, 0x25, + 0xa4, 0x21, 0x14, 0xc4, 0x6c, 0x27, 0x74, 0x21, 0x84, 0x6f, 0xa1, 0xce, + 0xd9, 0xdd, 0xf0, 0xfa, 0x18, 0x72, 0xff, 0x76, 0x10, 0x5f, 0x4a, 0x9c, + 0xbf, 0xa1, 0x05, 0xf4, 0xa9, 0xcb, 0xf9, 0xc1, 0xad, 0x26, 0xbe, 0x1e, + 0xf7, 0x4c, 0xaf, 0xff, 0xff, 0x7c, 0x64, 0x67, 0xbe, 0x64, 0x93, 0x88, + 0xe6, 0xfe, 0x40, 0x5e, 0x6d, 0x9c, 0xbf, 0x85, 0x7f, 0x1b, 0xd8, 0x0e, + 0x54, 0x91, 0x5e, 0xef, 0xd4, 0x89, 0xcb, 0x01, 0xff, 0xf8, 0x7a, 0xde, + 0xdf, 0x90, 0xe5, 0xe9, 0x81, 0xc9, 0xcb, 0xd0, 0xaf, 0xc5, 0x9b, 0xb0, + 0x0e, 0x58, 0x07, 0x2f, 0xe8, 0xd4, 0xf1, 0xa9, 0xce, 0x5e, 0xfd, 0xf6, + 0x72, 0xa4, 0x79, 0x8a, 0x17, 0xdf, 0xff, 0xc9, 0xaf, 0x98, 0x98, 0x2a, + 0xf5, 0x31, 0x98, 0xb3, 0x97, 0xff, 0xfe, 0x66, 0xd7, 0xd8, 0x5f, 0x32, + 0x1f, 0xc3, 0xf1, 0x15, 0x71, 0x01, 0xcb, 0xff, 0xfd, 0x3e, 0xa1, 0x9b, + 0xfe, 0x3e, 0x46, 0xa0, 0x3d, 0x86, 0x1c, 0xac, 0x46, 0xaa, 0x38, 0xd6, + 0x26, 0xa1, 0xa8, 0xcb, 0xef, 0xc0, 0xda, 0x72, 0xd9, 0xcb, 0xff, 0x6b, + 0x39, 0xef, 0x30, 0xc9, 0xe0, 0xe5, 0xff, 0xff, 0xed, 0x69, 0x27, 0xf9, + 0xdc, 0xf0, 0xc4, 0xdd, 0xc9, 0xe3, 0x9f, 0x7e, 0xb3, 0x97, 0xff, 0xff, + 0x42, 0xbd, 0x8f, 0x83, 0x9f, 0xab, 0xf3, 0x99, 0x6d, 0x05, 0x48, 0x9c, + 0xe5, 0xfb, 0x9d, 0xa6, 0x09, 0xca, 0xc4, 0x50, 0xfe, 0xf5, 0x48, 0x9a, + 0x17, 0x63, 0x1f, 0xbf, 0xfb, 0x43, 0xce, 0x6f, 0xf9, 0x86, 0x18, 0x72, + 0xff, 0x91, 0x5e, 0xc2, 0x4f, 0x0a, 0x9c, 0xb4, 0x91, 0x10, 0x1b, 0x46, + 0xbf, 0xe1, 0xfe, 0x61, 0xce, 0xbf, 0x8e, 0x5f, 0xee, 0xc3, 0x61, 0xeb, + 0xb0, 0xe5, 0xff, 0x33, 0x37, 0xf2, 0x61, 0x86, 0x1c, 0xa0, 0x9f, 0x7b, + 0x0d, 0x2f, 0xff, 0xf9, 0xf5, 0xdc, 0xf2, 0x60, 0xcf, 0xb8, 0xc1, 0x0f, + 0x60, 0xe5, 0xf7, 0xbe, 0x4f, 0xa3, 0x95, 0xca, 0x22, 0x5d, 0x8e, 0xff, + 0xff, 0xdc, 0xe4, 0xff, 0xf0, 0x7c, 0xe6, 0x5e, 0x86, 0xfe, 0x66, 0x80, + 0x08, 0x39, 0x7f, 0xf9, 0xb7, 0x19, 0xd9, 0xfa, 0x05, 0x05, 0x0e, 0x5f, + 0xd3, 0x73, 0x2f, 0xe3, 0xc7, 0x2f, 0xff, 0xe9, 0x46, 0xb9, 0x96, 0xfe, + 0x76, 0x10, 0x5f, 0x4a, 0x9c, 0xbf, 0xb2, 0x5e, 0x1c, 0x91, 0xcb, 0xfe, + 0xeb, 0xb0, 0x73, 0xaf, 0xe3, 0x97, 0xd9, 0xa0, 0x36, 0x72, 0xa1, 0x31, + 0x5e, 0x4c, 0x7a, 0xbd, 0xb2, 0xcf, 0x1b, 0xdf, 0xfd, 0x9e, 0xdf, 0xcd, + 0x62, 0x76, 0x02, 0x72, 0xfe, 0xcf, 0x6b, 0x59, 0x23, 0x94, 0x72, 0xfd, + 0x9d, 0x1c, 0x59, 0xca, 0x01, 0xb1, 0x10, 0xbb, 0xe1, 0xcd, 0xfc, 0x98, + 0xff, 0xbc, 0xbd, 0x7f, 0xd8, 0xce, 0xc2, 0x6b, 0xf6, 0xb3, 0x94, 0x15, + 0xf7, 0xac, 0x29, 0x54, 0xa9, 0x71, 0xc1, 0xf3, 0x0a, 0x94, 0x28, 0xd4, + 0x2a, 0x3b, 0x0a, 0xb7, 0x23, 0xdb, 0xcf, 0xa3, 0x5f, 0xfd, 0x2f, 0x8c, + 0x30, 0xd4, 0x3b, 0xbf, 0xe8, 0x60, 0xe0, 0x74, 0x93, 0x9c, 0xbf, 0xff, + 0xcd, 0xf7, 0xf8, 0xe7, 0xe6, 0xb5, 0x13, 0x8b, 0xbe, 0x95, 0x39, 0x7f, + 0x87, 0x3f, 0xc5, 0x64, 0x03, 0x94, 0xe8, 0x9b, 0x6d, 0x9e, 0xa4, 0x8f, + 0x6c, 0x86, 0x9d, 0xff, 0x87, 0x3e, 0x6b, 0x3a, 0x39, 0x31, 0xcb, 0xff, + 0xfd, 0xd7, 0x06, 0xfe, 0x0e, 0x71, 0x1c, 0xde, 0x32, 0x16, 0x72, 0x85, + 0x14, 0x3b, 0x3f, 0xae, 0x14, 0xcc, 0x0f, 0x85, 0xdc, 0xa4, 0x76, 0xf3, + 0x1e, 0xdb, 0xc3, 0x22, 0xfe, 0xce, 0xa8, 0x3c, 0x80, 0xe5, 0xfd, 0xdc, + 0x1f, 0x03, 0xf3, 0x97, 0xfc, 0x10, 0xc0, 0x3e, 0x67, 0x3e, 0x39, 0x7a, + 0x19, 0xb3, 0x94, 0x87, 0xb0, 0x27, 0x97, 0xfb, 0x7b, 0x84, 0x9d, 0xfc, + 0x72, 0xfe, 0x54, 0x73, 0x71, 0xa3, 0x96, 0x94, 0x1f, 0x07, 0xe6, 0x76, + 0x91, 0xcb, 0xe8, 0x63, 0x84, 0xe5, 0x41, 0xb2, 0x11, 0x1b, 0xfd, 0x93, + 0x77, 0x3d, 0x01, 0x39, 0x7f, 0x0f, 0x9d, 0x89, 0xe3, 0x96, 0x91, 0xca, + 0x83, 0x7b, 0xe2, 0xcb, 0xc2, 0xb8, 0x39, 0x7f, 0xff, 0xfd, 0xdc, 0xf6, + 0xde, 0x6f, 0x83, 0x9c, 0xcb, 0x3f, 0x9c, 0x70, 0x3d, 0x49, 0x8e, 0x5d, + 0xfa, 0xa7, 0x29, 0x11, 0x6d, 0xa1, 0xbf, 0x42, 0x0a, 0xff, 0x01, 0x3d, + 0xef, 0x63, 0x67, 0x2f, 0xec, 0x9c, 0x73, 0x9d, 0x9c, 0xbf, 0xf8, 0x40, + 0xd3, 0x3a, 0x90, 0xc7, 0x09, 0xcb, 0xff, 0xff, 0xf4, 0xb7, 0xbf, 0xe3, + 0xc8, 0x1c, 0x19, 0xbe, 0x0e, 0x6a, 0x07, 0xdd, 0xce, 0x03, 0x97, 0xff, + 0x73, 0x2d, 0xe3, 0x39, 0x8e, 0xf6, 0x0e, 0x57, 0x28, 0xcd, 0xd4, 0x21, + 0xed, 0xb3, 0x95, 0x89, 0xa5, 0xff, 0x18, 0x8a, 0x85, 0x36, 0x9c, 0xe5, + 0xfb, 0x59, 0xcc, 0xb6, 0x72, 0xf2, 0xfb, 0x87, 0x2d, 0x93, 0x9e, 0x2e, + 0x8a, 0x6f, 0xfb, 0x98, 0xd4, 0xff, 0x31, 0x02, 0x72, 0xe9, 0x90, 0xe5, + 0x62, 0x34, 0x85, 0x5f, 0xf2, 0x8e, 0x27, 0x97, 0xf6, 0x73, 0x28, 0x04, + 0x1c, 0xbf, 0x0e, 0x75, 0xfc, 0x72, 0xb9, 0x3d, 0x36, 0x16, 0xdf, 0x27, + 0x1c, 0xd1, 0xca, 0x83, 0xc6, 0xe9, 0x1d, 0xf7, 0xc5, 0xce, 0xd9, 0xcb, + 0xf4, 0xff, 0x3f, 0x89, 0x8e, 0x5f, 0xff, 0xf0, 0xc0, 0x39, 0x96, 0xff, + 0x8f, 0x0e, 0x05, 0x33, 0x53, 0x1c, 0xa7, 0x44, 0xa7, 0x8b, 0x6a, 0x17, + 0xed, 0x02, 0x5f, 0x90, 0x86, 0xe6, 0x10, 0x08, 0xb5, 0x30, 0xff, 0x5c, + 0x1e, 0x1a, 0xc0, 0x34, 0x13, 0x4d, 0xc6, 0xf3, 0xe8, 0xc2, 0xbf, 0x86, + 0xbf, 0x12, 0x15, 0x21, 0x77, 0x7e, 0x92, 0x6b, 0x39, 0x39, 0x7b, 0x7d, + 0xc3, 0x97, 0xec, 0xdc, 0xf8, 0xd9, 0xca, 0xe4, 0xfb, 0x66, 0x28, 0xe8, + 0xe5, 0xff, 0xfe, 0xf6, 0xfb, 0x9c, 0xe3, 0xf3, 0xf0, 0x31, 0x3f, 0xc5, + 0x55, 0x39, 0x7f, 0xd8, 0xa8, 0xe7, 0xba, 0x8d, 0x9c, 0xa8, 0x45, 0x1e, + 0x9a, 0xaf, 0xff, 0xa7, 0xc5, 0x87, 0xa9, 0x8a, 0xfc, 0x57, 0xf8, 0x39, + 0x7f, 0xf4, 0x93, 0xdd, 0xcd, 0x6b, 0x3d, 0xb3, 0x97, 0xfd, 0xf1, 0x4f, + 0x27, 0x18, 0x15, 0x9c, 0xa4, 0x46, 0xb4, 0xca, 0xbd, 0x44, 0xbf, 0xfd, + 0x1c, 0xcb, 0x7e, 0x79, 0xf8, 0x07, 0x39, 0x39, 0x7f, 0xdd, 0x9d, 0x30, + 0x79, 0x96, 0xce, 0x5f, 0xf7, 0x3d, 0xc5, 0x8e, 0x7e, 0xd6, 0x72, 0xff, + 0xf9, 0xbc, 0x5e, 0xf3, 0xd3, 0x62, 0xa3, 0x80, 0x39, 0x69, 0x42, 0x32, + 0x30, 0xe9, 0x0f, 0x6f, 0xe4, 0xe4, 0x1a, 0x70, 0x9c, 0xbd, 0x9a, 0x01, + 0xcb, 0xf6, 0xd3, 0x04, 0x07, 0x2d, 0x88, 0x78, 0x5b, 0x1c, 0xbf, 0x20, + 0x01, 0x9a, 0x39, 0x5d, 0x45, 0xe8, 0xb8, 0x6c, 0x9a, 0xfb, 0x83, 0xd9, + 0xd3, 0x97, 0x23, 0x0e, 0x5f, 0xff, 0xfb, 0x99, 0x3f, 0x3f, 0x07, 0xfe, + 0x0f, 0x99, 0xcc, 0xb3, 0xf1, 0x06, 0xce, 0x53, 0x11, 0x1d, 0xc0, 0x2d, + 0x79, 0xa2, 0x70, 0xe7, 0x2b, 0xe2, 0x65, 0x73, 0x97, 0xe4, 0x2c, 0xda, + 0x13, 0x5f, 0xff, 0xff, 0x73, 0xbf, 0xe3, 0x9f, 0x9d, 0xc0, 0xfc, 0x1c, + 0xfd, 0x5f, 0x9b, 0x00, 0x13, 0xc7, 0x2f, 0xff, 0xff, 0x36, 0x38, 0x16, + 0x32, 0x3d, 0xbc, 0xf6, 0xf4, 0x98, 0xb1, 0xc0, 0x9c, 0xa8, 0x47, 0xfe, + 0x42, 0x26, 0xfd, 0x03, 0xcb, 0xce, 0x72, 0xff, 0xff, 0xff, 0xd8, 0xb8, + 0xec, 0x33, 0xd9, 0xbd, 0xc6, 0xb5, 0x03, 0x93, 0xe7, 0xfb, 0xfe, 0x61, + 0x86, 0x1c, 0xbd, 0xfe, 0x95, 0x39, 0x4c, 0x45, 0xcb, 0x48, 0x4d, 0x5f, + 0x9c, 0x0a, 0x3c, 0xe7, 0x2b, 0x0f, 0x4d, 0x0a, 0xaf, 0x20, 0x20, 0xe5, + 0xfc, 0x11, 0xce, 0xbf, 0x8e, 0x5f, 0xbd, 0xcc, 0x93, 0x47, 0x2b, 0x0f, + 0x57, 0x65, 0x95, 0x3a, 0x24, 0x40, 0xe1, 0x7b, 0x4e, 0xa1, 0xcb, 0xf4, + 0x79, 0x89, 0xe3, 0x96, 0x9d, 0xcf, 0x13, 0xf1, 0xdb, 0xff, 0x42, 0xbc, + 0x1f, 0xe0, 0xcc, 0xa3, 0x0e, 0x5f, 0xff, 0xff, 0xe5, 0x47, 0x3e, 0x26, + 0x0b, 0xfb, 0xb1, 0x37, 0xc1, 0xce, 0xa7, 0xb7, 0xfa, 0xff, 0x83, 0x95, + 0x89, 0x80, 0x72, 0x53, 0xfa, 0x2d, 0xff, 0xb3, 0x01, 0xbf, 0x9a, 0xd8, + 0x76, 0x72, 0xff, 0x6b, 0x17, 0xd4, 0xd4, 0xc7, 0x2d, 0xe0, 0x9f, 0xae, + 0x20, 0xdf, 0xec, 0x5a, 0x7b, 0x5f, 0xb0, 0xe5, 0x61, 0xed, 0xa1, 0x3d, + 0xe4, 0x1f, 0x1c, 0xbf, 0xa5, 0xb7, 0x67, 0xfb, 0x39, 0x53, 0x9e, 0x53, + 0x8d, 0xdf, 0xb3, 0xbd, 0x79, 0x1c, 0xbf, 0xbc, 0x9a, 0x9f, 0x16, 0x72, + 0xa1, 0x97, 0x94, 0x18, 0x6a, 0x64, 0x3e, 0x15, 0x30, 0xe6, 0x31, 0x74, + 0x94, 0x37, 0xa8, 0xd1, 0x98, 0x4d, 0xd8, 0xcd, 0x1e, 0x16, 0x23, 0x1b, + 0x46, 0xe3, 0x02, 0xfd, 0xa9, 0xa1, 0x17, 0x01, 0x3d, 0xe7, 0x5e, 0x1c, + 0xbf, 0xf4, 0xdf, 0x3c, 0x38, 0xde, 0x26, 0xce, 0x57, 0x0c, 0x7b, 0x90, + 0x37, 0x47, 0x2f, 0xec, 0x64, 0x75, 0xfa, 0x72, 0xef, 0x93, 0x1c, 0xaf, + 0x87, 0x8c, 0x12, 0xcb, 0xff, 0xee, 0x64, 0x31, 0xf1, 0x83, 0x0a, 0xf9, + 0x27, 0x39, 0x50, 0x8c, 0x8c, 0x51, 0x42, 0x4b, 0xf6, 0xbe, 0x0f, 0x16, + 0xce, 0x5f, 0x75, 0xc1, 0x07, 0x2f, 0x77, 0x34, 0x72, 0xa0, 0xfa, 0x9c, + 0xb7, 0x80, 0x86, 0xfe, 0x9e, 0x69, 0x70, 0xda, 0x9c, 0xe5, 0xf9, 0x88, + 0x1c, 0x09, 0xcb, 0x4c, 0x72, 0xe8, 0x61, 0xcb, 0x78, 0xe5, 0x68, 0xd3, + 0xb8, 0xb5, 0x04, 0xf6, 0x7a, 0x73, 0x7b, 0x51, 0x31, 0xcb, 0xdb, 0x7e, + 0x4e, 0x53, 0x9b, 0xaf, 0x0e, 0xdd, 0x33, 0x9c, 0xbf, 0x9d, 0xb8, 0xf6, + 0x4e, 0x72, 0xfe, 0x4d, 0x73, 0x21, 0x83, 0x97, 0xf8, 0x3d, 0x8e, 0x65, + 0x9e, 0x39, 0x5d, 0x3e, 0x1f, 0x16, 0xdf, 0xf9, 0xa4, 0x0f, 0xb4, 0x9c, + 0x70, 0x27, 0x2e, 0x19, 0x8e, 0x53, 0x54, 0xa9, 0x4e, 0x0d, 0xf2, 0x10, + 0x08, 0xb8, 0xc2, 0x01, 0x17, 0xfe, 0x11, 0xed, 0x08, 0x94, 0x41, 0xbf, + 0xcd, 0xe4, 0x87, 0xf7, 0xd9, 0xcb, 0xf7, 0x2d, 0xb8, 0x80, 0xe5, 0xc2, + 0xa9, 0xcb, 0x6d, 0x0f, 0x03, 0xf2, 0x9b, 0xff, 0xf3, 0x07, 0x17, 0xcf, + 0x85, 0xfa, 0xc8, 0xcf, 0x1c, 0xbf, 0xfe, 0xc9, 0xdc, 0x57, 0xf3, 0x70, + 0xc7, 0xe7, 0xc7, 0x2a, 0x11, 0x4d, 0xa5, 0x4b, 0xff, 0xff, 0xe4, 0xef, + 0xec, 0x63, 0xcb, 0xe7, 0x00, 0xe3, 0x21, 0x7f, 0x14, 0x9e, 0x77, 0xe4, + 0xe5, 0xff, 0xfa, 0x35, 0x0b, 0xc6, 0x42, 0xe4, 0x9b, 0xfd, 0x87, 0x2a, + 0x15, 0x21, 0x4c, 0xe9, 0xd8, 0x67, 0x78, 0x89, 0xa4, 0x22, 0x6f, 0xed, + 0x64, 0x2b, 0x02, 0x72, 0xf0, 0xbb, 0x0e, 0x5c, 0x08, 0x39, 0x7f, 0xf7, + 0x59, 0x9c, 0xcb, 0x6f, 0x1c, 0xc8, 0xe5, 0xca, 0x4e, 0x72, 0x90, 0xf7, + 0xc5, 0x1a, 0xa4, 0x8d, 0xc4, 0x2c, 0x11, 0xbf, 0x3a, 0xd3, 0x55, 0x08, + 0x49, 0x76, 0xa6, 0x12, 0x7c, 0x21, 0x63, 0x57, 0x08, 0xce, 0x1a, 0x52, + 0xe7, 0x0b, 0xb3, 0xc4, 0xeb, 0xd4, 0xf1, 0xff, 0xca, 0x13, 0x01, 0x9e, + 0x3a, 0xca, 0x7c, 0xda, 0xb2, 0xa4, 0x57, 0x3d, 0xaf, 0xcc, 0xeb, 0xfa, + 0x4b, 0x5b, 0x9a, 0x54, 0x76, 0xa7, 0x6a, 0x99, 0x2f, 0x1b, 0xb5, 0x97, + 0xbb, 0xcb, 0x8d, 0x04, 0xa3, 0x9e, 0x1d, 0xc4, 0x69, 0x88, 0x9b, 0xa4, + 0x0d, 0x7a, 0x9a, 0x59, 0xfc, 0x6c, 0x7c, 0x61, 0xdc, 0xdc, 0x25, 0xda, + 0x4a, 0x83, 0x52, 0x56, 0x8f, 0x04, 0x66, 0x97, 0xff, 0xf7, 0xeb, 0xfb, + 0xcf, 0xb5, 0x19, 0xcf, 0x0c, 0x17, 0x75, 0x4e, 0x57, 0xd5, 0x5f, 0x09, + 0x2a, 0x4a, 0xfe, 0x74, 0xf6, 0xd0, 0x4e, 0x5e, 0x4d, 0x61, 0xca, 0x6b, + 0x3c, 0x6d, 0x95, 0xdf, 0xb4, 0xb7, 0x75, 0x9a, 0x29, 0xd5, 0xd9, 0xc9, + 0xcb, 0xff, 0xdf, 0xfe, 0x28, 0x31, 0xd4, 0x66, 0x6c, 0xe5, 0xbe, 0xc2, + 0x2e, 0x70, 0x97, 0x93, 0x46, 0x0b, 0xdf, 0xfc, 0x9a, 0xfa, 0xd1, 0xe7, + 0xf6, 0xdc, 0x07, 0x2f, 0xda, 0x5b, 0xba, 0xcd, 0x15, 0x1a, 0xff, 0xcf, + 0x2f, 0xb9, 0xa5, 0xbb, 0xac, 0xd1, 0x34, 0x2f, 0xff, 0x0e, 0x4d, 0x27, + 0xd4, 0x87, 0x38, 0xb9, 0xcb, 0xe1, 0x8c, 0xe4, 0xe5, 0x62, 0x3a, 0xd8, + 0x69, 0xb4, 0xcf, 0x25, 0x5f, 0xe5, 0x1f, 0x8f, 0xdf, 0x24, 0xe7, 0x2b, + 0xe9, 0xfa, 0xc1, 0xe5, 0xfb, 0x4b, 0x77, 0x59, 0xa2, 0xaf, 0x5f, 0xd9, + 0xc6, 0x07, 0xbf, 0x9c, 0xbf, 0x90, 0x21, 0x8d, 0x41, 0xcb, 0xff, 0xfb, + 0x90, 0x0f, 0xec, 0x50, 0x21, 0x80, 0x32, 0x33, 0xc7, 0x2d, 0xf7, 0x11, + 0xdb, 0xa3, 0x4e, 0x97, 0xa8, 0x59, 0x7e, 0xd2, 0xdd, 0xd6, 0x68, 0xad, + 0x97, 0xfd, 0x2f, 0xb9, 0xa5, 0xbb, 0xac, 0xd1, 0x20, 0xad, 0xf7, 0x0f, + 0xed, 0xcd, 0x2f, 0xfe, 0xfa, 0xf2, 0xfb, 0x9a, 0x5b, 0xba, 0xcd, 0x12, + 0x1a, 0xff, 0xdb, 0xfb, 0x9e, 0x40, 0xe0, 0xcc, 0x72, 0xf3, 0xba, 0xcf, + 0x18, 0x1a, 0xa0, 0xfa, 0x16, 0x81, 0x77, 0x5a, 0xce, 0x5f, 0xfa, 0x5d, + 0x8f, 0x6d, 0xa9, 0xdb, 0x56, 0x27, 0x2f, 0xbd, 0xec, 0xe0, 0x39, 0x7f, + 0xfb, 0x85, 0xb8, 0x59, 0xa9, 0xec, 0x30, 0x5f, 0xa9, 0xa3, 0x96, 0xe4, + 0xe5, 0xc8, 0x27, 0x2f, 0xf6, 0x33, 0x16, 0x2e, 0xd6, 0x72, 0xfe, 0x80, + 0xc7, 0x9c, 0x27, 0x2e, 0xf3, 0x9c, 0xa0, 0xa2, 0x76, 0x61, 0x2d, 0x8a, + 0xf8, 0xd1, 0x42, 0xcb, 0xef, 0x6d, 0x38, 0x9c, 0xbf, 0xf9, 0x06, 0x78, + 0x55, 0x40, 0x02, 0x39, 0x39, 0x7d, 0x82, 0x0d, 0x9c, 0xbf, 0xf8, 0x5d, + 0xbe, 0xa3, 0xcb, 0xc9, 0x39, 0xcb, 0xe9, 0xf7, 0xca, 0x1c, 0xac, 0x44, + 0x4e, 0x88, 0x76, 0x89, 0x7e, 0x70, 0xa9, 0x02, 0x72, 0xff, 0xda, 0xf2, + 0x82, 0xeb, 0xc1, 0x59, 0xcb, 0xe5, 0xbb, 0xac, 0xd1, 0x62, 0x2f, 0xda, + 0xd3, 0x8f, 0x8e, 0x5f, 0x38, 0x7b, 0xf9, 0xcb, 0xc8, 0x8d, 0x9c, 0xbd, + 0xf8, 0xc8, 0xe5, 0xfe, 0x5c, 0x66, 0x80, 0x0f, 0x1c, 0xa9, 0xd3, 0x49, + 0xc2, 0x7d, 0x1f, 0x30, 0xbb, 0xa4, 0xe2, 0x47, 0xe1, 0xcf, 0xc7, 0x6f, + 0xd9, 0xa8, 0x15, 0x4e, 0x59, 0x0e, 0x59, 0x0e, 0x5a, 0x4a, 0x9a, 0x00, + 0x08, 0x5f, 0x94, 0x69, 0x9a, 0x83, 0x97, 0xef, 0x7a, 0x06, 0x73, 0x97, + 0xb7, 0x02, 0x72, 0xa0, 0xfb, 0x70, 0xa9, 0x0a, 0x29, 0x54, 0x60, 0xf6, + 0x12, 0xb7, 0xff, 0x46, 0x6f, 0x04, 0x28, 0x08, 0x13, 0x97, 0x86, 0x27, + 0x39, 0x42, 0x7b, 0x9f, 0xa0, 0x5f, 0x46, 0xa1, 0x87, 0x2a, 0x47, 0x87, + 0xb2, 0x2b, 0xcc, 0x7f, 0x1c, 0xbf, 0xfe, 0xf6, 0x73, 0x21, 0xff, 0xce, + 0x83, 0x01, 0x39, 0x72, 0x00, 0xe5, 0x69, 0x10, 0x3e, 0x1c, 0x68, 0x9f, + 0x7f, 0xfe, 0x7d, 0x49, 0x83, 0x1a, 0x80, 0xe4, 0xd1, 0xd3, 0x97, 0xdc, + 0x7f, 0x7d, 0x9c, 0xb2, 0x1c, 0xa9, 0x22, 0x25, 0x15, 0x26, 0x25, 0xbf, + 0xe0, 0xf7, 0x19, 0x8f, 0xa9, 0xce, 0x5f, 0xbd, 0xe7, 0x96, 0xce, 0x5f, + 0xfb, 0xfc, 0xe4, 0x3c, 0x7b, 0x8f, 0x31, 0xca, 0xe4, 0xfa, 0xf8, 0x94, + 0x5a, 0x47, 0x2f, 0xb3, 0x1b, 0xd9, 0xca, 0x83, 0x67, 0xe1, 0x1b, 0xbf, + 0x13, 0x95, 0x09, 0x99, 0xe4, 0x29, 0x34, 0xb1, 0xb2, 0x0b, 0xfd, 0xb5, + 0x33, 0x59, 0x93, 0x1c, 0xbf, 0x0f, 0x87, 0xf9, 0xce, 0x54, 0x1e, 0xef, + 0xe6, 0x97, 0xf6, 0xa4, 0x0c, 0xc9, 0x8e, 0x5f, 0x3c, 0x23, 0x43, 0x95, + 0x87, 0xa1, 0xa2, 0xeb, 0xe9, 0x29, 0xd8, 0x39, 0x7b, 0x51, 0x23, 0x94, + 0xe6, 0xff, 0x89, 0x1d, 0xfd, 0x0c, 0xc4, 0xd4, 0xc7, 0x2f, 0x94, 0x8e, + 0x0d, 0x9c, 0xbf, 0x60, 0x7b, 0x1d, 0x39, 0x7d, 0xa4, 0x6d, 0xac, 0xe5, + 0x09, 0xe6, 0xec, 0x9e, 0x82, 0x89, 0x4d, 0xb9, 0xd4, 0x26, 0xcc, 0x8c, + 0x1d, 0x22, 0x78, 0x60, 0xdf, 0xdc, 0xaf, 0xb1, 0xcf, 0x01, 0xcb, 0xf9, + 0x05, 0xd9, 0x1d, 0x39, 0x7f, 0xfa, 0x19, 0x12, 0x08, 0xc7, 0x5f, 0x34, + 0x72, 0x8e, 0x54, 0x8f, 0x49, 0xa2, 0x3d, 0xef, 0x60, 0x0e, 0x5f, 0xcc, + 0x4d, 0xed, 0x02, 0x72, 0xf3, 0xe9, 0x53, 0x95, 0xf9, 0xe5, 0x36, 0x5b, + 0x7f, 0x96, 0x39, 0xc4, 0x73, 0x67, 0x2f, 0xf3, 0x5f, 0xc5, 0x20, 0x5d, + 0x53, 0x97, 0xfa, 0x4f, 0x83, 0x9e, 0xd9, 0xca, 0xc3, 0xea, 0xe4, 0xe6, + 0xff, 0xd9, 0xcc, 0xbb, 0x1b, 0x57, 0xb0, 0x72, 0xa1, 0x52, 0xec, 0x8c, + 0xf9, 0x7d, 0x98, 0x93, 0x4c, 0xdd, 0x24, 0x18, 0x4e, 0xf0, 0x11, 0x59, + 0xa1, 0xcb, 0xa5, 0xb3, 0x96, 0x79, 0x1a, 0xae, 0x44, 0xef, 0xbc, 0x82, + 0xd9, 0x4b, 0x7e, 0x72, 0xd1, 0x86, 0xd3, 0xa4, 0x57, 0xfc, 0xe3, 0xed, + 0xf3, 0xb7, 0x6b, 0x39, 0x4e, 0x8b, 0xc0, 0x2d, 0xfe, 0x4b, 0x7f, 0xe6, + 0x7f, 0x37, 0x3b, 0x89, 0x93, 0x89, 0xcb, 0xfb, 0xa9, 0xbd, 0x6b, 0x0e, + 0x5f, 0xf9, 0x33, 0xdb, 0xd6, 0x6e, 0x39, 0x39, 0x7f, 0xe8, 0x6d, 0x49, + 0xf7, 0x8c, 0x86, 0xb3, 0x97, 0x3b, 0x67, 0x29, 0x68, 0xc6, 0xe9, 0x6f, + 0x8f, 0xb8, 0xa2, 0x5d, 0x9b, 0x39, 0x50, 0x9b, 0x06, 0x46, 0x16, 0xa1, + 0xfd, 0xff, 0xdd, 0x74, 0xf4, 0xb1, 0x51, 0xc0, 0x1c, 0xbf, 0xcc, 0x4d, + 0xf5, 0x21, 0x0e, 0x5f, 0x86, 0x68, 0xec, 0x1c, 0xbf, 0x01, 0xf8, 0xe0, + 0x4e, 0x5f, 0xb3, 0xbc, 0xbb, 0x59, 0xcb, 0xe0, 0x6e, 0x04, 0xe5, 0xfe, + 0xd7, 0x5d, 0x36, 0x9c, 0x4e, 0x5c, 0xaa, 0x1c, 0xa8, 0x3e, 0xcc, 0x21, + 0x73, 0x4b, 0xff, 0xbb, 0x82, 0x2f, 0xef, 0x92, 0x86, 0x1c, 0xa4, 0x4f, + 0x2d, 0x88, 0x6e, 0x62, 0x02, 0x71, 0x29, 0xdc, 0x25, 0xfc, 0x59, 0x7f, + 0x37, 0x1a, 0xd3, 0xcc, 0x72, 0xff, 0x83, 0x0b, 0x50, 0x00, 0x8e, 0x4e, + 0x5f, 0xf3, 0xeb, 0x18, 0x8d, 0x21, 0x87, 0x29, 0x67, 0xe9, 0xf9, 0xdd, + 0xf7, 0xa3, 0x99, 0x1c, 0xbf, 0x90, 0x0d, 0x05, 0x00, 0x72, 0xa7, 0x3d, + 0x1d, 0x11, 0xdf, 0x7e, 0x1e, 0xa1, 0xcb, 0xde, 0xc5, 0x0e, 0x54, 0x26, + 0xf5, 0x90, 0xa3, 0x77, 0x4d, 0x91, 0xf0, 0x11, 0xdf, 0xc3, 0x12, 0x8e, + 0x30, 0x72, 0xe8, 0x01, 0xcb, 0xfb, 0x8e, 0x9e, 0x11, 0xa1, 0xcb, 0x92, + 0x73, 0x96, 0xc3, 0x94, 0x88, 0x9a, 0x98, 0xb5, 0x82, 0xce, 0x60, 0x22, + 0xf7, 0xd3, 0xfb, 0x16, 0x72, 0xff, 0x3a, 0xaa, 0x77, 0xb1, 0x23, 0x94, + 0xe7, 0xb0, 0xd0, 0x8e, 0xff, 0xdd, 0xc0, 0x85, 0x39, 0xce, 0x7c, 0x72, + 0xfe, 0xf8, 0x15, 0x1f, 0x5a, 0x39, 0x53, 0x9f, 0x88, 0x50, 0x2f, 0xf0, + 0x73, 0xdd, 0x81, 0x59, 0xcb, 0xe7, 0x84, 0x68, 0x72, 0xff, 0x83, 0xf3, + 0x37, 0x19, 0xa0, 0x1c, 0xbd, 0xd5, 0x36, 0x72, 0xb0, 0xf6, 0x1c, 0xea, + 0xff, 0x20, 0x7c, 0x2f, 0xce, 0xce, 0x5f, 0xef, 0x6d, 0x39, 0xce, 0x7c, + 0x72, 0xa0, 0xfa, 0x1c, 0xce, 0xa1, 0x37, 0x79, 0xc8, 0xc2, 0x65, 0xd7, + 0xa1, 0x84, 0x45, 0x35, 0x2d, 0xc8, 0x33, 0x56, 0x35, 0xc3, 0x24, 0xb5, + 0x02, 0x58, 0x87, 0xcc, 0xe9, 0x92, 0x24, 0x0c, 0x34, 0x32, 0x37, 0x85, + 0x5c, 0x97, 0x18, 0x47, 0x30, 0xc8, 0x48, 0x51, 0xcd, 0x0b, 0xbd, 0x46, + 0xc6, 0xc8, 0x4f, 0x76, 0x3d, 0x87, 0x95, 0x3a, 0x08, 0xd8, 0x46, 0x39, + 0x0d, 0xca, 0x01, 0xf4, 0x7c, 0x3f, 0xc3, 0xa9, 0xa4, 0x28, 0x14, 0x94, + 0x17, 0x7e, 0xe0, 0x75, 0xc6, 0x8e, 0x5f, 0xf9, 0x23, 0xdd, 0x75, 0x70, + 0x40, 0x72, 0xff, 0xf3, 0xeb, 0xe3, 0xfb, 0xe7, 0xb9, 0x5a, 0x09, 0xca, + 0xea, 0x22, 0xf8, 0x9e, 0xdf, 0xd9, 0xe8, 0x46, 0x6c, 0xe5, 0xfe, 0x0c, + 0x4b, 0x35, 0x9b, 0x39, 0x7f, 0xfd, 0x9a, 0xd7, 0xf2, 0xd6, 0x47, 0x32, + 0x46, 0x1c, 0xbd, 0xb5, 0x36, 0x72, 0xff, 0xfb, 0x39, 0x97, 0xbf, 0x9f, + 0xef, 0x5d, 0x89, 0xb3, 0x97, 0xfe, 0xf4, 0x33, 0x70, 0x93, 0xbf, 0x8e, + 0x5f, 0xce, 0xd6, 0xf9, 0xcf, 0x8e, 0x57, 0x27, 0xdd, 0xd3, 0xeb, 0xfc, + 0xf8, 0x14, 0xe4, 0x5c, 0xe5, 0x61, 0xea, 0x7e, 0x47, 0x73, 0x62, 0x72, + 0xf7, 0x86, 0x0e, 0x5d, 0xdf, 0xb0, 0xac, 0x4b, 0x21, 0x6b, 0x31, 0x2b, + 0x0b, 0x3a, 0x64, 0xea, 0x22, 0x3d, 0xb8, 0xc5, 0xdb, 0x22, 0x50, 0x5e, + 0xbe, 0xae, 0xc4, 0xc4, 0xe7, 0x25, 0xfd, 0x9a, 0x5b, 0xba, 0xcd, 0x16, + 0x6a, 0xff, 0xed, 0x75, 0xfe, 0xb3, 0xf9, 0xba, 0x81, 0x39, 0x7f, 0xe8, + 0xd0, 0x3d, 0xbe, 0xe2, 0x04, 0xe5, 0xfb, 0x26, 0x94, 0x72, 0x72, 0xf9, + 0x05, 0xe7, 0x39, 0x5d, 0x44, 0x40, 0x9f, 0x6c, 0xa6, 0xdd, 0x39, 0x74, + 0x74, 0xe5, 0xbe, 0xce, 0x69, 0xfa, 0x23, 0x5f, 0x51, 0x01, 0xc0, 0xad, + 0x5f, 0x53, 0xb2, 0x43, 0x97, 0x8d, 0x46, 0xf9, 0x18, 0xa6, 0x8e, 0x5f, + 0x42, 0xf3, 0xa7, 0x2f, 0x90, 0x75, 0xf9, 0xcb, 0xfd, 0x1c, 0x54, 0xf0, + 0xc0, 0x0e, 0x5f, 0x28, 0x39, 0xb3, 0x97, 0x33, 0xec, 0x22, 0xf5, 0x08, + 0xe6, 0x21, 0xe9, 0x13, 0x9a, 0xdd, 0x88, 0x72, 0xec, 0x09, 0xcb, 0xff, + 0x3c, 0xbe, 0xe6, 0x96, 0xee, 0xb3, 0x45, 0x00, 0xbf, 0xc8, 0xc8, 0x6b, + 0xee, 0x4e, 0x72, 0xdf, 0x64, 0x8a, 0xdc, 0x15, 0x60, 0xb7, 0x53, 0x2e, + 0x93, 0x0e, 0x5f, 0x3e, 0xb9, 0x91, 0xcb, 0xf4, 0x73, 0xe7, 0xd1, 0xcb, + 0xf7, 0xb7, 0x24, 0x01, 0xca, 0x92, 0x22, 0xb0, 0x5d, 0x08, 0xdc, 0xa2, + 0xfd, 0xf7, 0x26, 0x89, 0x1c, 0xbf, 0xe8, 0xf7, 0x71, 0x99, 0xac, 0x39, + 0x7d, 0x36, 0x62, 0xce, 0x5f, 0xbc, 0xab, 0xef, 0xee, 0x8f, 0x65, 0x43, + 0x7a, 0x92, 0x31, 0x9b, 0x84, 0x1d, 0x7d, 0x4c, 0xa6, 0x23, 0x00, 0xbb, + 0xfe, 0x9c, 0xbf, 0xff, 0x71, 0x8e, 0xa0, 0x7b, 0x12, 0xdb, 0xf5, 0x36, + 0x72, 0xfe, 0xdc, 0x30, 0x62, 0x63, 0x96, 0xe9, 0xcb, 0xca, 0x0c, 0xc7, + 0x2d, 0xec, 0x35, 0xe0, 0x11, 0xbb, 0x27, 0x39, 0x58, 0x6f, 0x44, 0x9a, + 0x91, 0x30, 0xe0, 0x2b, 0x0c, 0x26, 0x6e, 0xf9, 0xb3, 0x97, 0xbf, 0x0e, + 0x1c, 0xbf, 0xd9, 0xaf, 0x0c, 0x33, 0x67, 0x2c, 0xd0, 0xe5, 0x21, 0xf1, + 0x74, 0x74, 0x06, 0x57, 0xcb, 0x77, 0x59, 0xa2, 0xdf, 0x5e, 0x68, 0xfe, + 0x39, 0x7f, 0x29, 0xe7, 0x5b, 0xe8, 0xe5, 0x68, 0xfe, 0x98, 0x5c, 0x01, + 0xeb, 0x95, 0x6c, 0xe5, 0xf6, 0x0a, 0x4c, 0x72, 0xf7, 0x63, 0x47, 0x2f, + 0xdd, 0x4d, 0x75, 0xce, 0x5f, 0xfe, 0xec, 0x4f, 0xec, 0xe8, 0xe7, 0xba, + 0x87, 0x2f, 0x33, 0x02, 0x72, 0xcc, 0x39, 0x7f, 0xdd, 0x89, 0xc3, 0x8d, + 0xef, 0xec, 0x22, 0xe7, 0x07, 0x26, 0x27, 0x74, 0x95, 0x07, 0x2f, 0xde, + 0x96, 0xd4, 0xd9, 0xcb, 0xdb, 0xe8, 0x4e, 0x5f, 0x94, 0xf0, 0xc0, 0x0e, + 0x53, 0x0f, 0x17, 0x88, 0xed, 0xff, 0xde, 0xda, 0x6e, 0x07, 0x3d, 0xd4, + 0x39, 0x78, 0x73, 0xa7, 0x29, 0x87, 0xbb, 0xc5, 0x0a, 0xfc, 0x18, 0x6b, + 0xfd, 0x87, 0x2f, 0xf9, 0xf7, 0x18, 0x21, 0xec, 0x1c, 0xbf, 0xfb, 0x19, + 0xac, 0xe7, 0xa2, 0xed, 0x73, 0x9c, 0xbb, 0x7b, 0xd1, 0xff, 0x09, 0xb5, + 0x42, 0x6f, 0x99, 0x08, 0x14, 0x24, 0x78, 0x55, 0x5f, 0x3a, 0x0f, 0x8e, + 0x5f, 0x81, 0xbf, 0x43, 0x0e, 0x5e, 0xd4, 0x78, 0xe5, 0xfd, 0x33, 0x87, + 0xa8, 0xc3, 0x97, 0xf7, 0x93, 0x03, 0x0c, 0x39, 0x5e, 0x3d, 0xa6, 0xcb, + 0xae, 0xd8, 0x9c, 0xbf, 0xb9, 0xdc, 0x2f, 0x18, 0x72, 0xa1, 0x30, 0x5d, + 0x14, 0x3b, 0xb6, 0xc8, 0xff, 0x16, 0xbf, 0x92, 0x68, 0x11, 0x83, 0x97, + 0xdd, 0x54, 0x2c, 0x39, 0x69, 0x1c, 0xbf, 0xc0, 0x07, 0xfb, 0x6b, 0xce, + 0x4e, 0x56, 0x1e, 0x53, 0x88, 0xd6, 0x22, 0x38, 0x5b, 0xa9, 0xab, 0x64, + 0x49, 0x44, 0x64, 0xd2, 0x34, 0x0b, 0xde, 0x42, 0xa3, 0x92, 0xf4, 0x19, + 0x9a, 0x1b, 0x5a, 0x7b, 0xec, 0x7d, 0x60, 0x44, 0x18, 0xc9, 0x76, 0x95, + 0xe8, 0x5c, 0xdf, 0xcf, 0xcf, 0xd6, 0x3f, 0x8e, 0x57, 0xd4, 0xc5, 0xc6, + 0x1c, 0xf7, 0xf0, 0x7e, 0xef, 0xdb, 0xe4, 0xe5, 0xcd, 0x53, 0x56, 0x72, + 0xf3, 0x1f, 0x93, 0x97, 0x80, 0xfd, 0x39, 0x77, 0x14, 0x39, 0x7d, 0xad, + 0x62, 0x87, 0x2f, 0xdb, 0x9f, 0x1b, 0xfa, 0xd4, 0xa2, 0x56, 0x08, 0x70, + 0x76, 0x61, 0xc7, 0x18, 0xa8, 0x4c, 0xd5, 0x21, 0x8f, 0x7f, 0xff, 0xdc, + 0x3a, 0x7b, 0xf7, 0x9f, 0xee, 0x4b, 0xb1, 0xac, 0xc1, 0x54, 0xe5, 0xff, + 0xff, 0xe4, 0x5b, 0xe9, 0xfb, 0x2c, 0xf6, 0x07, 0x6e, 0xcc, 0xd4, 0xf1, + 0xc9, 0xcb, 0xf6, 0x96, 0xee, 0xb3, 0x45, 0x28, 0xbf, 0xfe, 0x7f, 0x0e, + 0x4f, 0xa8, 0xea, 0x77, 0x34, 0x72, 0xf3, 0xcb, 0xec, 0x23, 0xe7, 0x1d, + 0xc0, 0x69, 0x7f, 0xd2, 0xfb, 0x9a, 0x5b, 0xba, 0xcd, 0x12, 0x72, 0x98, + 0x88, 0x87, 0x41, 0xbf, 0xda, 0xfb, 0x9d, 0x89, 0x9c, 0xe5, 0x7d, 0x3d, + 0x77, 0x22, 0xa8, 0x86, 0x44, 0x04, 0xf3, 0xc5, 0xf2, 0x94, 0x4a, 0x1c, + 0x44, 0x0e, 0xe4, 0x65, 0x8a, 0xa2, 0x2e, 0x3a, 0x94, 0x8c, 0x41, 0xae, + 0x18, 0x13, 0x14, 0x6a, 0x17, 0x8c, 0xaf, 0xac, 0x3b, 0x1f, 0x0b, 0xc3, + 0xd0, 0x11, 0x81, 0x8c, 0x7e, 0xfb, 0xa4, 0xea, 0x7a, 0x35, 0xff, 0xc9, + 0xf8, 0xca, 0x46, 0xbf, 0x69, 0x6e, 0xeb, 0x34, 0x43, 0xeb, 0xff, 0x3c, + 0xbe, 0xe6, 0x96, 0xee, 0xb3, 0x44, 0xa6, 0xb7, 0xdc, 0x44, 0x03, 0x0d, + 0x2f, 0xf7, 0xdc, 0xd2, 0xdd, 0xd6, 0x68, 0x89, 0xd7, 0xe4, 0xf6, 0xff, + 0x61, 0xcb, 0xdd, 0x89, 0x8e, 0x54, 0xc7, 0x8d, 0xd2, 0x9b, 0xff, 0xdc, + 0x29, 0x56, 0xda, 0xe7, 0x0f, 0x0d, 0xf3, 0xe7, 0x5a, 0x1c, 0xbf, 0x69, + 0x6e, 0xeb, 0x34, 0x46, 0x2b, 0xff, 0xfb, 0xf1, 0x75, 0x7e, 0x79, 0x58, + 0x19, 0x67, 0x51, 0x87, 0x2f, 0xa1, 0x8b, 0x01, 0xcb, 0xff, 0xe9, 0x4f, + 0xc2, 0xa1, 0xab, 0x9d, 0x7a, 0xf9, 0xf3, 0xad, 0x0e, 0x57, 0x51, 0x0e, + 0x02, 0x2b, 0xfb, 0x3d, 0x19, 0xcf, 0x8e, 0x5f, 0xfb, 0xca, 0xc0, 0xcb, + 0x3a, 0x8c, 0x39, 0x7f, 0xca, 0xc0, 0xcb, 0x3a, 0x8c, 0x39, 0x7d, 0xf8, + 0xba, 0xbf, 0x0f, 0xdb, 0xc7, 0xd7, 0xed, 0x01, 0x3b, 0x07, 0x29, 0x87, + 0xc7, 0xf9, 0xe5, 0xf2, 0x73, 0x26, 0xac, 0xe5, 0xfb, 0xe4, 0xc3, 0x01, + 0x39, 0x6f, 0xb0, 0xac, 0xfa, 0x44, 0x78, 0xc8, 0xc3, 0x4e, 0xc3, 0x94, + 0x48, 0xf7, 0x18, 0x37, 0x88, 0xda, 0x14, 0x5f, 0xfe, 0xfa, 0xc7, 0x97, + 0xdc, 0xd2, 0xdd, 0xd6, 0x68, 0x9e, 0x57, 0xd1, 0xc6, 0x3a, 0x72, 0xfa, + 0x06, 0x5b, 0x39, 0x7e, 0xea, 0x0e, 0x71, 0x39, 0x5a, 0x3e, 0xc0, 0x11, + 0xa8, 0x43, 0x7d, 0xfb, 0xea, 0x47, 0x2f, 0xce, 0x1e, 0xc6, 0xce, 0x5b, + 0xe8, 0x4f, 0x28, 0x48, 0xeb, 0xea, 0x28, 0xdb, 0x7a, 0xa8, 0x5e, 0x10, + 0x9c, 0xaa, 0x52, 0xf1, 0x7b, 0x09, 0x2f, 0x46, 0xd3, 0x7e, 0xd2, 0xdd, + 0xd6, 0x68, 0x88, 0x17, 0xfe, 0x79, 0x7d, 0xcd, 0x2d, 0xdd, 0x66, 0x89, + 0x51, 0x7f, 0x6b, 0xfe, 0xc0, 0xac, 0xe5, 0xfc, 0xb4, 0xce, 0x0e, 0xc1, + 0xca, 0x83, 0xdd, 0xc2, 0xeb, 0x7d, 0xc4, 0x7e, 0xb0, 0xd0, 0x61, 0x53, + 0x7e, 0xd2, 0xdd, 0xd6, 0x68, 0x8a, 0x17, 0xa0, 0x18, 0x72, 0xdf, 0x70, + 0xf3, 0xd4, 0x34, 0xbf, 0xdf, 0x73, 0x4b, 0x77, 0x59, 0xa2, 0x32, 0x5f, + 0xb4, 0xb7, 0x75, 0x9a, 0x26, 0x55, 0xfa, 0x59, 0xe7, 0x59, 0xcb, 0xf7, + 0xd6, 0x3c, 0xbe, 0xe1, 0xed, 0xf2, 0x69, 0x7e, 0xd2, 0xdd, 0xd6, 0x68, + 0xa9, 0x16, 0x13, 0x96, 0x50, 0xe5, 0xbe, 0xe1, 0xeb, 0x35, 0x9a, 0x7e, + 0x21, 0x7f, 0xbe, 0xe6, 0x96, 0xee, 0xb3, 0x45, 0x74, 0xbf, 0xdf, 0x73, + 0x4b, 0x77, 0x59, 0xa2, 0xc5, 0x5f, 0xfc, 0xc7, 0x97, 0xdc, 0xd2, 0xdd, + 0xd6, 0x68, 0x9e, 0x97, 0x9b, 0x75, 0x9c, 0xbf, 0xbb, 0x09, 0xa4, 0xe1, + 0xce, 0x5f, 0xa1, 0x1a, 0x27, 0x01, 0xcb, 0x9b, 0xfb, 0x87, 0xf2, 0xb1, + 0xd7, 0x31, 0xbf, 0xff, 0xfc, 0x1c, 0x6f, 0xe8, 0xe2, 0xaa, 0xbf, 0xb6, + 0x83, 0x34, 0x2f, 0x59, 0xc9, 0xcb, 0xff, 0xf4, 0xc3, 0x0c, 0xfb, 0x9b, + 0x46, 0xc2, 0xee, 0xa9, 0xcb, 0xb7, 0xe3, 0x97, 0x66, 0xce, 0x5d, 0xb0, + 0x1c, 0xbf, 0x0b, 0xb0, 0x60, 0xe5, 0xfd, 0xfe, 0xfa, 0xf2, 0xfa, 0xd5, + 0x9f, 0x4b, 0x8b, 0xb6, 0x2c, 0xa0, 0xbd, 0xe9, 0xe1, 0xac, 0xe5, 0xfb, + 0x3d, 0xb4, 0x61, 0xcb, 0xff, 0xd1, 0xcf, 0xb2, 0x64, 0xd7, 0xb7, 0xfb, + 0x59, 0xcb, 0xcf, 0xcf, 0xd8, 0x44, 0xb8, 0x90, 0x78, 0x9e, 0xb1, 0x50, + 0x16, 0xa1, 0x83, 0xb8, 0x7f, 0xd0, 0x55, 0x5c, 0xfa, 0x53, 0xf5, 0x7d, + 0x57, 0xd9, 0x10, 0xcb, 0x49, 0x5e, 0xb7, 0xe6, 0xa5, 0x23, 0xfe, 0x1c, + 0xe5, 0xf9, 0x3a, 0x2f, 0x31, 0xcb, 0xf4, 0xb0, 0x3f, 0x30, 0xe5, 0x70, + 0x87, 0xa1, 0x04, 0xf7, 0x30, 0x07, 0x2f, 0xd9, 0xe4, 0xff, 0x67, 0x2e, + 0x6a, 0x5a, 0x81, 0xca, 0x6a, 0x4f, 0x85, 0xa8, 0x0b, 0xf0, 0xa2, 0x8b, + 0xf7, 0x0b, 0x35, 0x3b, 0xd7, 0x8e, 0x5f, 0xe5, 0x07, 0x35, 0xa8, 0x59, + 0xca, 0x6a, 0x4f, 0xa3, 0x86, 0x35, 0xbe, 0xd3, 0x3d, 0xc9, 0xcb, 0xf9, + 0xa9, 0x6a, 0xb8, 0x48, 0x93, 0x0e, 0x5e, 0x5e, 0x74, 0xa5, 0xe6, 0x46, + 0xce, 0x5e, 0x06, 0xa0, 0xe5, 0xfd, 0x80, 0x49, 0x91, 0xb3, 0x97, 0xfe, + 0x7d, 0xfc, 0xde, 0xf2, 0x52, 0x83, 0x96, 0xd9, 0xcb, 0xff, 0xf0, 0xba, + 0xa9, 0xa8, 0x94, 0xb3, 0x60, 0x04, 0x1c, 0xbf, 0xcf, 0xef, 0xf3, 0x05, + 0x53, 0x94, 0x14, 0xc1, 0x95, 0x2e, 0x99, 0x03, 0xa2, 0x20, 0x54, 0xbf, + 0xff, 0xb4, 0x9c, 0x0e, 0xcf, 0xb1, 0xad, 0x27, 0x02, 0xff, 0x9c, 0xe5, + 0xf2, 0x75, 0x46, 0x1c, 0xbf, 0xfc, 0x8a, 0xfc, 0xc1, 0x7e, 0x76, 0xaa, + 0xae, 0x72, 0x96, 0x7e, 0x22, 0x47, 0x7f, 0xf9, 0xf6, 0x38, 0x0f, 0xbd, + 0x45, 0xbe, 0x8e, 0x5c, 0x2d, 0x9c, 0xbf, 0x83, 0x8a, 0xfb, 0x16, 0x72, + 0xfb, 0xb0, 0xc5, 0x9c, 0xa8, 0x3e, 0x77, 0x17, 0xf1, 0x75, 0xf8, 0x29, + 0x32, 0x36, 0x72, 0xff, 0xef, 0x91, 0x03, 0x0c, 0xf9, 0xf3, 0xad, 0x0e, + 0x54, 0x1f, 0xa0, 0x94, 0xdf, 0xfb, 0xb9, 0x37, 0x53, 0xb1, 0xa8, 0x39, + 0x73, 0xf2, 0x72, 0xff, 0x3e, 0xdf, 0xbf, 0x8c, 0xe7, 0x28, 0x4f, 0x2f, + 0xf1, 0x7a, 0x9d, 0x72, 0x7e, 0x43, 0x89, 0x19, 0x16, 0x93, 0x59, 0x0d, + 0x6e, 0x90, 0x8c, 0x2c, 0x7d, 0x0a, 0x15, 0x08, 0x38, 0x21, 0x13, 0x78, + 0x5f, 0xc7, 0x2f, 0x0a, 0x6c, 0xe5, 0x9b, 0xe1, 0x0d, 0xb4, 0x0d, 0xdd, + 0x1d, 0x39, 0x7d, 0xae, 0x2e, 0xc3, 0x97, 0xe1, 0xcf, 0x43, 0x67, 0x2f, + 0xff, 0x27, 0xce, 0xe4, 0xc9, 0xce, 0xfb, 0x8b, 0x39, 0x7e, 0x60, 0xbf, + 0xb6, 0x72, 0xf4, 0x66, 0x8e, 0x5f, 0xfe, 0x5b, 0xe9, 0xfc, 0x9b, 0x81, + 0x80, 0x1c, 0xb4, 0xba, 0x7c, 0x4a, 0x0d, 0xd7, 0x28, 0xb2, 0xd4, 0x22, + 0x6b, 0x13, 0xb5, 0x59, 0x62, 0x0b, 0x6c, 0x93, 0xc4, 0xff, 0xc3, 0xfe, + 0xf9, 0xd1, 0x46, 0x1c, 0xbd, 0xbe, 0x0e, 0x03, 0x97, 0xdf, 0x24, 0x06, + 0x1c, 0xbd, 0xac, 0x09, 0xcb, 0xfc, 0xfe, 0x89, 0xb6, 0x8c, 0x39, 0x4a, + 0x9e, 0x7f, 0x47, 0x2f, 0xf4, 0x48, 0x73, 0x9f, 0x61, 0xcb, 0xff, 0xe4, + 0xeb, 0xae, 0x04, 0x33, 0x4a, 0x35, 0x39, 0xcb, 0xff, 0xef, 0x6c, 0x3a, + 0xc4, 0x57, 0xad, 0xb8, 0xce, 0x72, 0xf8, 0x43, 0x8a, 0x9c, 0xbd, 0xdf, + 0xd8, 0x72, 0xa4, 0x9f, 0x86, 0x11, 0x72, 0x46, 0x8e, 0x9a, 0x23, 0xe9, + 0x96, 0xd4, 0x3c, 0xa5, 0xf9, 0x15, 0xfd, 0xed, 0xcd, 0x03, 0x39, 0xcb, + 0xf0, 0xaa, 0x99, 0xb3, 0x97, 0xe6, 0xdf, 0xce, 0xb3, 0x97, 0xff, 0x63, + 0x6e, 0x0c, 0x5f, 0x5c, 0x1b, 0x39, 0x7f, 0xed, 0xbf, 0x30, 0x2e, 0x1c, + 0x54, 0xe5, 0x22, 0x34, 0x7a, 0x4e, 0x25, 0x1e, 0x44, 0xba, 0x3a, 0x72, + 0xc1, 0x39, 0x4c, 0x34, 0xe2, 0x2d, 0x7c, 0x21, 0xf8, 0xa9, 0xcb, 0xfb, + 0x36, 0xdb, 0x8c, 0xe7, 0x2b, 0x0f, 0xcd, 0xc8, 0x04, 0x96, 0xfd, 0xaf, + 0xf6, 0xeb, 0x39, 0x7c, 0xae, 0xc3, 0x07, 0x2a, 0x0f, 0x33, 0xf2, 0x9b, + 0x6c, 0xe5, 0xb0, 0xe5, 0x98, 0x86, 0x87, 0x80, 0x46, 0xff, 0xb0, 0x5e, + 0x5b, 0x93, 0x73, 0x9c, 0xbe, 0x96, 0xd0, 0x4e, 0x5a, 0x24, 0x7b, 0x7c, + 0x9d, 0x5f, 0xe7, 0xd4, 0xa1, 0x68, 0xb3, 0x95, 0x0a, 0xdb, 0xb2, 0x30, + 0x04, 0x86, 0xaf, 0x5e, 0x1d, 0x0c, 0x61, 0x09, 0xf9, 0x45, 0xff, 0xe5, + 0x5f, 0x39, 0xf7, 0xa3, 0x38, 0xa2, 0xce, 0x5f, 0xe1, 0xcd, 0xf9, 0xdc, + 0x4e, 0x52, 0xa7, 0xf9, 0xc5, 0x32, 0xff, 0xff, 0xc9, 0xad, 0x42, 0x9e, + 0x41, 0xfe, 0x59, 0xb0, 0xfe, 0xfa, 0x91, 0xcb, 0xff, 0xf8, 0x71, 0x5c, + 0x1f, 0x9b, 0xf7, 0x71, 0x8a, 0x40, 0x0e, 0x54, 0x23, 0x2f, 0x1b, 0xaf, + 0xf7, 0xef, 0xb4, 0x99, 0x1b, 0x39, 0x48, 0x9a, 0x37, 0x61, 0xe0, 0x24, + 0x37, 0xbb, 0x02, 0x72, 0xf7, 0x3e, 0x61, 0xca, 0x59, 0xb9, 0x71, 0xbb, + 0xf4, 0xe1, 0xd2, 0x36, 0x72, 0xff, 0x28, 0xfc, 0x52, 0x64, 0x6c, 0xe5, + 0xfe, 0xff, 0x53, 0xb2, 0x33, 0xc7, 0x2f, 0xfb, 0x70, 0xc0, 0xf6, 0x05, + 0x67, 0x2e, 0x41, 0xc3, 0xed, 0x54, 0xd6, 0xa1, 0x1a, 0x01, 0x85, 0x25, + 0xe9, 0x7f, 0xb3, 0x97, 0xf0, 0x5f, 0x40, 0x69, 0x87, 0x2f, 0x75, 0x4e, + 0x27, 0x2f, 0xfa, 0x18, 0x38, 0xbd, 0x20, 0x0e, 0x5f, 0x82, 0xfb, 0xde, + 0x1c, 0xa9, 0x1f, 0xf6, 0xc8, 0x3f, 0x37, 0xbf, 0xe8, 0x96, 0x26, 0xf7, + 0xfc, 0x1c, 0xbf, 0xf7, 0xa1, 0x9c, 0xad, 0x39, 0xcd, 0x1c, 0xbf, 0x77, + 0x34, 0x9b, 0x39, 0x78, 0x52, 0x5c, 0x9f, 0x3f, 0x90, 0x2f, 0xfc, 0xf8, + 0x08, 0x17, 0x0e, 0x2a, 0x72, 0xa7, 0x4c, 0x3a, 0x50, 0x9f, 0x01, 0x9d, + 0xf7, 0xbd, 0x8d, 0x67, 0x2f, 0xfa, 0x32, 0x5d, 0xc4, 0x96, 0xce, 0x5c, + 0xfc, 0xec, 0xf7, 0x3c, 0x4b, 0x73, 0x24, 0x72, 0xff, 0x9f, 0x16, 0x1c, + 0xd0, 0x10, 0xe5, 0xc9, 0xa0, 0x9e, 0x77, 0x45, 0xef, 0xfa, 0x25, 0xb1, + 0x80, 0x3b, 0x0e, 0x5f, 0xbd, 0x18, 0x2b, 0x39, 0x7d, 0xcf, 0xa1, 0x87, + 0x29, 0x53, 0xc9, 0xe4, 0x9a, 0xff, 0xa4, 0xa7, 0x93, 0xa8, 0x3e, 0x39, + 0x7f, 0xfa, 0x33, 0x9f, 0x76, 0x3c, 0x30, 0x0d, 0x9c, 0xba, 0x00, 0x72, + 0xee, 0xb0, 0xe5, 0x2c, 0xd6, 0xec, 0x5a, 0x91, 0x1e, 0x8e, 0x49, 0xe3, + 0x9f, 0xdd, 0xaf, 0xff, 0x0f, 0xef, 0x26, 0x7f, 0xee, 0xc7, 0xfc, 0x39, + 0xcb, 0xd3, 0xa6, 0x8e, 0x5f, 0xf6, 0xd3, 0x9f, 0x4d, 0x28, 0xe4, 0xe5, + 0xfb, 0x7e, 0xde, 0x78, 0xe5, 0x6c, 0xf9, 0x3f, 0x3c, 0xbf, 0xbf, 0xe1, + 0xd2, 0x64, 0x6c, 0xe5, 0xd9, 0xd3, 0x97, 0x9b, 0x6d, 0xb2, 0x97, 0xff, + 0xbc, 0x9e, 0xdf, 0x51, 0xa2, 0x9a, 0x89, 0x14, 0xfa, 0x68, 0x29, 0x54, + 0xdb, 0x92, 0x10, 0x2e, 0x47, 0xe3, 0x5f, 0xcd, 0xaf, 0xff, 0xf9, 0x3d, + 0x28, 0x1c, 0xf7, 0x53, 0x3d, 0x0c, 0x4d, 0x48, 0xe5, 0x49, 0x92, 0x2c, + 0x16, 0xdc, 0x20, 0x5c, 0x3e, 0xb9, 0x27, 0x41, 0xe9, 0xa1, 0x5b, 0xa8, + 0xcf, 0x99, 0x09, 0x3e, 0xbe, 0x00, 0xb4, 0x63, 0x74, 0xd9, 0xe7, 0xa3, + 0xc0, 0xe2, 0xa1, 0x7f, 0xdc, 0xcb, 0x7b, 0xc0, 0xbf, 0x8e, 0x5b, 0x0e, + 0x5f, 0x68, 0x5f, 0x89, 0xca, 0x83, 0xed, 0x54, 0xe9, 0x04, 0x2f, 0x03, + 0x78, 0x72, 0xce, 0x72, 0xf4, 0x77, 0x67, 0x2b, 0x93, 0x58, 0x82, 0x17, + 0xfe, 0x85, 0xfc, 0xc1, 0x8f, 0xf8, 0x7d, 0x9c, 0xbf, 0xff, 0x9f, 0xc9, + 0xd7, 0x67, 0xcc, 0xdc, 0x66, 0xb0, 0x4e, 0x5f, 0xfd, 0xb7, 0xe7, 0x7b, + 0xc1, 0x03, 0x4c, 0x39, 0x7f, 0xf9, 0x17, 0xb8, 0x69, 0x9e, 0x94, 0xb3, + 0x67, 0x2b, 0x49, 0xa8, 0x30, 0x84, 0x51, 0x7c, 0xb3, 0xc5, 0x1a, 0xfb, + 0x5d, 0xc1, 0x39, 0x48, 0x7d, 0xae, 0x99, 0x7f, 0x0f, 0xc5, 0x37, 0x18, + 0x72, 0xfb, 0xd1, 0xcb, 0x67, 0x29, 0x6a, 0x9e, 0x3b, 0x28, 0x14, 0x04, + 0x0d, 0x97, 0xdf, 0xff, 0xbd, 0xfa, 0x9e, 0x18, 0x03, 0xf8, 0x0a, 0x0c, + 0x8e, 0x5c, 0xdf, 0x4e, 0x5f, 0xfe, 0x81, 0x5a, 0x9a, 0x70, 0x27, 0xbb, + 0x07, 0x2f, 0xe6, 0x7c, 0xee, 0x01, 0xce, 0x5f, 0xcd, 0xef, 0x30, 0x67, + 0x39, 0x58, 0x7b, 0xa8, 0x5f, 0x7d, 0x1b, 0x8e, 0x27, 0x2f, 0xfe, 0x81, + 0x7f, 0x4a, 0x15, 0x76, 0xfc, 0x72, 0xba, 0x7c, 0xff, 0x91, 0xde, 0xf8, + 0xeb, 0x39, 0x50, 0x9e, 0xf2, 0xd6, 0x00, 0x31, 0xb8, 0x53, 0x7a, 0x10, + 0xfc, 0x04, 0x77, 0xf4, 0x94, 0x63, 0x11, 0xac, 0xe5, 0xf3, 0x14, 0x81, + 0x39, 0x7c, 0x81, 0xc6, 0x1c, 0xbe, 0x77, 0x10, 0x1c, 0xb3, 0x70, 0x78, + 0x2a, 0x90, 0xdd, 0xfb, 0x0e, 0x5f, 0xe6, 0xde, 0x6c, 0x94, 0x35, 0x9c, + 0xbf, 0x70, 0x7f, 0x32, 0x4c, 0x72, 0x91, 0x14, 0xdd, 0x29, 0xd8, 0xc7, + 0xe6, 0xf7, 0xfe, 0x84, 0x67, 0x79, 0x76, 0xbf, 0x6c, 0xe5, 0xfe, 0x87, + 0xd7, 0x5b, 0x70, 0x94, 0xb9, 0xb6, 0xca, 0x50, 0x4f, 0x31, 0xb3, 0x3b, + 0xde, 0x46, 0xb2, 0x9f, 0x4d, 0x1d, 0xfd, 0xca, 0xd3, 0x7d, 0x43, 0x97, + 0xdf, 0xcb, 0xff, 0x1c, 0xa8, 0x55, 0x5a, 0x86, 0x53, 0x46, 0x12, 0xc3, + 0xdd, 0xc2, 0xc7, 0xc6, 0x2d, 0x0b, 0xaf, 0x84, 0x3d, 0x73, 0x97, 0xb1, + 0xda, 0xce, 0x56, 0x1b, 0xfd, 0x10, 0xdc, 0xde, 0xce, 0x5b, 0x0e, 0x5b, + 0x9c, 0x35, 0x1e, 0x18, 0xbe, 0xe6, 0x5c, 0x27, 0x27, 0x2f, 0xfe, 0xde, + 0xc2, 0x30, 0x1e, 0xc7, 0xb6, 0x72, 0xa1, 0x12, 0xb8, 0x4f, 0xf9, 0x55, + 0xfe, 0xea, 0x3c, 0xbc, 0x93, 0x9c, 0xbf, 0xf7, 0x93, 0x4e, 0x0e, 0x0f, + 0x67, 0x4e, 0x5f, 0xf2, 0x36, 0x39, 0xe4, 0xfc, 0x07, 0x2f, 0xc9, 0xa0, + 0xc4, 0xe7, 0x2f, 0xf3, 0xeb, 0xdb, 0x14, 0x54, 0xe5, 0xff, 0xed, 0xe2, + 0xb9, 0xfe, 0x9c, 0x31, 0xd8, 0x39, 0x52, 0x4e, 0x07, 0x92, 0xf4, 0x33, + 0x6b, 0x41, 0xe9, 0xcb, 0x94, 0x6c, 0xce, 0xff, 0xff, 0xce, 0x9e, 0x8e, + 0x8e, 0x7b, 0xa8, 0xa4, 0xa3, 0x8a, 0x08, 0x0e, 0x5f, 0x97, 0x8c, 0x8d, + 0x9c, 0xae, 0xa2, 0x49, 0xda, 0xef, 0x62, 0x68, 0xe5, 0xfe, 0x92, 0x33, + 0xbc, 0xbb, 0x59, 0xcb, 0xe7, 0xd4, 0x48, 0xe5, 0xff, 0x3f, 0x3f, 0x39, + 0xde, 0x0a, 0xa7, 0x2a, 0x74, 0x58, 0x72, 0x36, 0xc3, 0x7f, 0x10, 0xdf, + 0x75, 0xad, 0x18, 0x72, 0xf0, 0xc0, 0x0e, 0x5e, 0x86, 0x67, 0xc3, 0xc0, + 0xd9, 0x2d, 0xff, 0xa3, 0x9e, 0xc3, 0x17, 0xd4, 0x98, 0xe5, 0x42, 0x78, + 0xb9, 0x0d, 0x24, 0x7f, 0xd1, 0xa5, 0xfc, 0x21, 0xde, 0xd1, 0x87, 0x2f, + 0xcb, 0x79, 0xf1, 0xb3, 0x97, 0xe8, 0xd0, 0x70, 0x4e, 0x56, 0x1f, 0xe0, + 0x96, 0xf8, 0xa6, 0xfd, 0x0d, 0x13, 0xbf, 0x9c, 0xbf, 0xfa, 0x01, 0x1d, + 0x60, 0xba, 0xbd, 0x43, 0x96, 0xe1, 0x8e, 0x5f, 0xdd, 0x81, 0x6d, 0xf9, + 0x39, 0x7f, 0xe1, 0x9a, 0x30, 0x67, 0xce, 0x7c, 0x72, 0x82, 0x7d, 0xae, + 0x5d, 0x79, 0x55, 0x18, 0x72, 0xff, 0xe4, 0x0f, 0x61, 0x70, 0x07, 0x10, + 0x1c, 0xbf, 0x3e, 0xe7, 0x4d, 0x1c, 0xbf, 0xff, 0xce, 0x3c, 0xcb, 0xeb, + 0x78, 0x9c, 0x70, 0x70, 0x2f, 0x23, 0xc5, 0xea, 0xa0, 0xa2, 0x61, 0x85, + 0x17, 0xe5, 0x7c, 0xee, 0x27, 0x2f, 0x0f, 0xf3, 0x9c, 0xa7, 0x3c, 0x5f, + 0x13, 0xd2, 0x22, 0x24, 0x5a, 0x2a, 0x15, 0x70, 0x84, 0xb7, 0x45, 0x4c, + 0x43, 0x78, 0x41, 0x89, 0x0e, 0xc7, 0xff, 0x8d, 0x8e, 0xe6, 0xa5, 0xab, + 0x39, 0x79, 0x23, 0x47, 0x2b, 0x86, 0x37, 0x9d, 0x21, 0xbf, 0xfb, 0x48, + 0xc8, 0x6b, 0x1c, 0x67, 0x30, 0x72, 0xa4, 0x7d, 0x93, 0x13, 0x5f, 0x20, + 0xb8, 0x4e, 0x5e, 0x9d, 0x88, 0x72, 0x82, 0x6f, 0x44, 0x82, 0xfd, 0x2c, + 0xe3, 0x12, 0x39, 0x7b, 0x35, 0x07, 0x2b, 0x94, 0x62, 0x23, 0x06, 0x88, + 0x3a, 0x53, 0x70, 0xcc, 0x72, 0xfe, 0xeb, 0xcd, 0xa8, 0x9c, 0xe5, 0xfc, + 0x9c, 0xef, 0xb8, 0xb3, 0x97, 0xff, 0xd9, 0xed, 0xe4, 0xdd, 0x8e, 0x39, + 0xde, 0xc1, 0xcb, 0xff, 0xff, 0xf2, 0x67, 0x3b, 0x4c, 0x6f, 0xe6, 0x73, + 0x2d, 0xa7, 0xb6, 0x9c, 0x84, 0x3f, 0xce, 0x72, 0xff, 0xfc, 0x82, 0x1f, + 0x8a, 0x79, 0x36, 0xe8, 0x3f, 0xc8, 0xe5, 0xf3, 0xcf, 0xd4, 0x39, 0x58, + 0x9e, 0x42, 0x0b, 0xcc, 0x5e, 0x25, 0xde, 0x51, 0xe3, 0x08, 0xa6, 0x8a, + 0xf7, 0xbf, 0xd4, 0x8e, 0x5f, 0xf9, 0x8e, 0x1d, 0x47, 0xbb, 0x81, 0x39, + 0x7f, 0x3f, 0x80, 0xa0, 0xc8, 0xe5, 0xff, 0x05, 0xdd, 0xb0, 0x3f, 0xb6, + 0x72, 0xff, 0x49, 0x48, 0x11, 0xfd, 0x87, 0x2b, 0xe2, 0x3d, 0xe0, 0x7a, + 0x73, 0xe5, 0x4b, 0x9c, 0xe6, 0xff, 0x44, 0x93, 0xeb, 0x6d, 0xb6, 0x52, + 0xec, 0xe9, 0xcb, 0xca, 0xe0, 0x4e, 0x5f, 0xdd, 0x7d, 0x2e, 0x3c, 0x72, + 0xe7, 0x09, 0xcb, 0xfb, 0x4f, 0xbe, 0xbc, 0x8e, 0x5b, 0x93, 0x97, 0x23, + 0x67, 0x2e, 0x50, 0x07, 0x2a, 0x63, 0x5e, 0x01, 0x7b, 0xd2, 0x70, 0x9c, + 0xb9, 0xb6, 0xce, 0x54, 0x91, 0xb7, 0x82, 0xcb, 0x2d, 0x44, 0x1d, 0x91, + 0x36, 0x39, 0x7b, 0xca, 0x00, 0xa7, 0xd3, 0xd6, 0xbf, 0xd8, 0xc4, 0x0c, + 0xff, 0xec, 0xe5, 0xfb, 0x37, 0x9c, 0xf8, 0xe5, 0x74, 0xf7, 0x76, 0x6b, + 0x7f, 0xc8, 0x1c, 0x62, 0x4c, 0x8d, 0x9c, 0xbf, 0xfc, 0xe1, 0xcc, 0x15, + 0x77, 0xbc, 0x10, 0x1c, 0xbe, 0xef, 0xee, 0xac, 0x22, 0x05, 0x87, 0x37, + 0x86, 0x3a, 0x72, 0xff, 0xfe, 0x93, 0xef, 0x71, 0x93, 0xff, 0x20, 0xe8, + 0x5d, 0xb3, 0x96, 0x80, 0xa2, 0xcd, 0x53, 0xb4, 0x1b, 0xad, 0xa7, 0x17, + 0xe8, 0xd5, 0xaf, 0xe4, 0x62, 0xf0, 0x56, 0x72, 0xf9, 0xe7, 0xdf, 0x4e, + 0x56, 0x8f, 0x3f, 0x65, 0x95, 0xf1, 0x71, 0x16, 0x42, 0xc1, 0x1d, 0xe6, + 0x35, 0xe4, 0x94, 0x33, 0xe7, 0x9b, 0xf7, 0x15, 0x3a, 0x9e, 0x39, 0x7f, + 0xd9, 0xee, 0xc6, 0xbd, 0x8b, 0x39, 0x7a, 0x35, 0x31, 0xca, 0x86, 0x48, + 0xd6, 0x4a, 0x05, 0x48, 0xd8, 0xfa, 0x98, 0xf3, 0x8f, 0xa0, 0x69, 0x12, + 0xb6, 0x87, 0x17, 0xb6, 0xf3, 0x1c, 0xbf, 0xfd, 0x9c, 0xe7, 0x18, 0x08, + 0xe7, 0xb0, 0x07, 0x2e, 0x50, 0x07, 0x2b, 0x47, 0xc4, 0x04, 0xab, 0xff, + 0x90, 0x2f, 0xe4, 0xde, 0x4b, 0x3a, 0x72, 0xe7, 0xe0, 0x39, 0x6c, 0xe9, + 0xed, 0xf9, 0x0a, 0xb9, 0x4c, 0x8f, 0x4f, 0xe2, 0xfb, 0x78, 0x57, 0xc0, + 0x72, 0xff, 0xfe, 0xe7, 0x62, 0xfb, 0xee, 0x4b, 0x3a, 0x9a, 0xeb, 0x9c, + 0xbe, 0xce, 0x67, 0xe2, 0x72, 0xff, 0x84, 0x38, 0x3f, 0xcb, 0x36, 0x72, + 0xfd, 0x1c, 0xef, 0xf0, 0x1c, 0xbf, 0xca, 0x78, 0x72, 0x74, 0xd1, 0xcb, + 0xef, 0x26, 0xd0, 0xe5, 0x62, 0x6a, 0xc8, 0x3f, 0xa5, 0xa7, 0x26, 0x01, + 0xc0, 0x95, 0x7e, 0x69, 0x7f, 0xf4, 0xf0, 0xa0, 0x3f, 0x94, 0x9f, 0xbf, + 0x9c, 0xbf, 0xee, 0xa0, 0x53, 0x87, 0x81, 0x43, 0x97, 0xf9, 0xe5, 0x81, + 0xd6, 0xf6, 0x72, 0xfa, 0x31, 0x40, 0x9c, 0xbf, 0xff, 0xa4, 0x31, 0x9b, + 0xc1, 0xf7, 0x70, 0x3f, 0xfb, 0x67, 0x2f, 0xf2, 0xa9, 0xe7, 0xeb, 0x6d, + 0x67, 0x2f, 0xe8, 0x9d, 0xa6, 0x6a, 0x0e, 0x5f, 0xec, 0x9b, 0xb9, 0xb7, + 0x13, 0x97, 0xfe, 0x0e, 0x73, 0x2d, 0xfb, 0x6e, 0x03, 0x95, 0xa3, 0xf2, + 0xfc, 0xca, 0xff, 0x36, 0x1e, 0xe7, 0x1c, 0xd1, 0xcb, 0xff, 0x91, 0x9f, + 0x17, 0xd4, 0xea, 0xd3, 0x67, 0x2f, 0xf6, 0x4b, 0x3f, 0xe1, 0xdc, 0x4e, + 0x5f, 0xfd, 0x12, 0xec, 0x73, 0xe8, 0xeb, 0xb5, 0x9c, 0xa8, 0x47, 0xd6, + 0x8d, 0xba, 0x8c, 0x26, 0xf7, 0xff, 0xf9, 0x07, 0x39, 0xf2, 0xaf, 0xee, + 0xc7, 0x73, 0x8b, 0xc8, 0xe5, 0x05, 0x5a, 0x12, 0xcc, 0xf9, 0x22, 0x45, + 0xa9, 0x8e, 0x35, 0x0a, 0x1f, 0x46, 0x3b, 0xc4, 0xee, 0xe1, 0x83, 0x97, + 0xfc, 0x14, 0xd4, 0x71, 0x06, 0xe4, 0x72, 0xe8, 0x61, 0xca, 0x83, 0xd1, + 0xe9, 0xdd, 0x75, 0x10, 0xfe, 0x66, 0xbf, 0xf4, 0x6d, 0xfa, 0x81, 0x5a, + 0x4e, 0x72, 0xa1, 0x73, 0x9b, 0x25, 0xbe, 0xbc, 0x61, 0x1f, 0x91, 0xde, + 0x81, 0xf1, 0xcb, 0xff, 0xe8, 0xd6, 0x71, 0x4f, 0x03, 0xf1, 0xda, 0x04, + 0xe5, 0xfe, 0x4e, 0xa6, 0xa5, 0x34, 0x1c, 0xbf, 0xff, 0x27, 0xeb, 0x53, + 0x90, 0x3e, 0xdf, 0x49, 0xc8, 0x0e, 0x5f, 0x3e, 0xa2, 0x47, 0x2f, 0xff, + 0xe4, 0x17, 0x41, 0x06, 0xa3, 0xae, 0x9e, 0x8e, 0x9c, 0xa1, 0x3f, 0x7f, + 0x10, 0xdf, 0x93, 0xdb, 0xfe, 0x73, 0x97, 0xff, 0x85, 0x01, 0xee, 0x56, + 0x9a, 0x52, 0x02, 0x72, 0xff, 0xba, 0xa0, 0x7f, 0xf6, 0xc1, 0x07, 0x2a, + 0x11, 0x0e, 0xe9, 0x74, 0x14, 0xf0, 0xd2, 0x1a, 0x0c, 0x21, 0xf4, 0x2c, + 0x6f, 0xda, 0xfd, 0x7d, 0x83, 0x97, 0xf6, 0xa6, 0x92, 0x7b, 0x67, 0x2c, + 0x30, 0x7b, 0x18, 0x53, 0x7f, 0xa6, 0x79, 0x9f, 0x99, 0x6c, 0xe5, 0xfc, + 0xf3, 0xa4, 0xc8, 0xd9, 0xcb, 0xff, 0xfc, 0xed, 0xfb, 0x3b, 0xf0, 0x39, + 0x34, 0x9f, 0x53, 0xf7, 0xf3, 0x95, 0x88, 0xcc, 0x73, 0x61, 0x2f, 0xbf, + 0x60, 0xcf, 0x8d, 0x9c, 0xbf, 0x3b, 0x3a, 0x8d, 0x9c, 0xa9, 0xcf, 0x40, + 0x25, 0x17, 0xfd, 0x13, 0xa9, 0x2e, 0xfe, 0xf3, 0x9c, 0xac, 0x3e, 0x0d, + 0x11, 0xdb, 0x86, 0x39, 0x7e, 0x8d, 0x6b, 0x3a, 0x72, 0xfe, 0x17, 0x56, + 0x19, 0x07, 0x2b, 0x84, 0x3e, 0x99, 0x0b, 0x7e, 0x4f, 0x7d, 0x13, 0xaa, + 0xa9, 0xcb, 0xff, 0xf2, 0x2e, 0x19, 0xb7, 0xd6, 0x33, 0xf5, 0xbc, 0x8e, + 0x5c, 0x9c, 0x4e, 0x5b, 0xa7, 0x2a, 0x47, 0xfc, 0xd6, 0xab, 0xf8, 0xc5, + 0xe0, 0xc3, 0x0e, 0x5f, 0xec, 0x06, 0x4d, 0x1c, 0xec, 0xe5, 0x41, 0xe8, + 0x60, 0xe5, 0xfd, 0xd7, 0x94, 0x6e, 0x47, 0x2f, 0xfb, 0x3a, 0x9c, 0xef, + 0xbf, 0xec, 0xe5, 0xd8, 0x2b, 0x3e, 0x80, 0x16, 0xdf, 0xc2, 0xe0, 0x0e, + 0x09, 0xcb, 0xf2, 0x34, 0xcd, 0x2a, 0x72, 0xe5, 0x64, 0x72, 0xfd, 0xd4, + 0xe2, 0x8b, 0x39, 0x76, 0x76, 0x47, 0x82, 0xb1, 0x8a, 0x62, 0x26, 0x1a, + 0x35, 0xde, 0x6d, 0xb6, 0xca, 0x5f, 0xfb, 0x43, 0xfb, 0xa9, 0x93, 0x43, + 0x0e, 0x7d, 0x34, 0x17, 0xee, 0xa4, 0xc8, 0xd9, 0xcb, 0x2c, 0xe5, 0x42, + 0x23, 0x31, 0x4b, 0x45, 0x37, 0xfa, 0x03, 0x92, 0x81, 0x59, 0xca, 0x86, + 0x4a, 0xdc, 0xe3, 0x72, 0x51, 0xc8, 0xfd, 0x9a, 0xe1, 0x3f, 0x34, 0x3c, + 0x75, 0x0d, 0xd6, 0x42, 0x2b, 0xa6, 0xaf, 0x0a, 0x31, 0x84, 0x1e, 0xe1, + 0x11, 0xe2, 0xcf, 0xe1, 0x86, 0xdc, 0x34, 0x54, 0x2e, 0xbe, 0xd6, 0xb3, + 0xa7, 0x2f, 0xee, 0xa7, 0x07, 0x07, 0xea, 0x9c, 0xa8, 0x3d, 0x85, 0x91, + 0x5b, 0x87, 0x39, 0x64, 0x39, 0x7f, 0xde, 0x8d, 0x6f, 0xb0, 0x3e, 0x39, + 0x6e, 0x1c, 0xe5, 0xff, 0x7a, 0x35, 0xbe, 0xc0, 0xf8, 0xe5, 0xdb, 0x83, + 0x97, 0x98, 0x18, 0x39, 0x7f, 0x87, 0xcf, 0x36, 0xe3, 0xc7, 0x29, 0x0f, + 0x3d, 0xc7, 0x2f, 0x91, 0xf1, 0x67, 0x2f, 0xfd, 0x9c, 0x47, 0x37, 0x30, + 0xc0, 0x4e, 0x5f, 0x2c, 0x31, 0x39, 0xcb, 0x81, 0x07, 0x2f, 0x6d, 0x34, + 0x72, 0xb0, 0xf5, 0x40, 0x47, 0xe1, 0x6b, 0xfd, 0x2c, 0x14, 0x0e, 0x09, + 0xcb, 0xde, 0xdf, 0xd8, 0x4f, 0x97, 0x05, 0xa6, 0x38, 0xeb, 0x28, 0x08, + 0x04, 0x83, 0x70, 0x94, 0xf1, 0x75, 0xdb, 0x83, 0x97, 0x98, 0x18, 0x39, + 0x7f, 0x87, 0xcf, 0x36, 0xe3, 0xc7, 0x29, 0x0f, 0x3d, 0xc7, 0x2f, 0x91, + 0xf1, 0x67, 0x2f, 0xfd, 0x9c, 0x47, 0x37, 0x30, 0xc0, 0x4e, 0x5f, 0x2c, + 0x31, 0x39, 0xcb, 0xfa, 0x60, 0x23, 0x5b, 0xcc, 0x72, 0xe0, 0x41, 0xcb, + 0xdb, 0x4d, 0x1c, 0xac, 0x44, 0x3a, 0xc8, 0xc0, 0x65, 0xe1, 0x6b, 0xfd, + 0x2c, 0x14, 0x0e, 0x09, 0xcb, 0xf8, 0x5c, 0x38, 0xaf, 0xd8, 0x5c, 0xa3, + 0x08, 0xb6, 0x08, 0x2e, 0x50, 0xec, 0xd0, 0x89, 0xeb, 0x28, 0x08, 0x04, + 0x83, 0x70, 0xc6, 0xf1, 0xe5, 0xff, 0xda, 0x8e, 0x76, 0x30, 0xcc, 0xe7, + 0xc7, 0x2f, 0xff, 0xce, 0x1c, 0xc1, 0x55, 0x41, 0x81, 0x9d, 0x34, 0x72, + 0xf3, 0xea, 0x73, 0xc8, 0x24, 0xbe, 0x96, 0x73, 0x23, 0xc8, 0x24, 0xbd, + 0xb4, 0x09, 0xe4, 0x12, 0x5c, 0xdb, 0x67, 0x90, 0x49, 0x4b, 0x45, 0x4c, + 0xc5, 0x5e, 0x30, 0x6c, 0xa6, 0xe7, 0xf1, 0x64, 0x12, 0x3e, 0x9b, 0xfb, + 0xfb, 0x3b, 0x98, 0x2a, 0x9c, 0xbc, 0xe2, 0x0f, 0x8b, 0xed, 0x11, 0x39, + 0x89, 0xa8, 0x60, 0xb1, 0x14, 0x63, 0x3c, 0xf1, 0xb5, 0xf3, 0x4c, 0x7e, + 0x9c, 0xb6, 0x35, 0xa2, 0x80, 0x0f, 0xb6, 0x91, 0xcb, 0xfa, 0x5f, 0xcf, + 0xe4, 0x9c, 0xa5, 0xf3, 0x87, 0xb8, 0x72, 0xf0, 0x51, 0x87, 0x2f, 0xfd, + 0xd8, 0xf2, 0x0c, 0x32, 0x36, 0x72, 0x95, 0x3f, 0x97, 0x21, 0xd8, 0xe5, + 0x4c, 0x8d, 0x9e, 0xc2, 0xaa, 0xff, 0xa0, 0x64, 0x30, 0x07, 0x61, 0xcb, + 0xf4, 0xd1, 0xdf, 0xf4, 0x72, 0xd0, 0x72, 0xff, 0x24, 0xbf, 0x7d, 0xf5, + 0x0e, 0x5f, 0xd9, 0xc5, 0xd9, 0x9d, 0x39, 0x69, 0x14, 0xbc, 0xfa, 0x9c, + 0xa5, 0x14, 0xa8, 0x37, 0x2b, 0x11, 0x60, 0xed, 0xe8, 0x02, 0xca, 0x7d, + 0x35, 0xb4, 0xc4, 0x61, 0x0c, 0x25, 0x2a, 0x13, 0x1c, 0xc8, 0x7a, 0xdf, + 0xb4, 0x06, 0x26, 0xce, 0x5f, 0xca, 0x0c, 0xb7, 0xd0, 0x9c, 0xc3, 0x51, + 0x7d, 0xfb, 0xea, 0x47, 0x2c, 0xc3, 0x97, 0x64, 0x82, 0x6d, 0x26, 0x23, + 0xbf, 0xfb, 0x39, 0xf6, 0xd0, 0x60, 0x0e, 0xc3, 0x97, 0xd9, 0x32, 0x30, + 0xe5, 0x4e, 0x7c, 0xad, 0xa1, 0xdf, 0xa2, 0x69, 0x40, 0x0a, 0x5f, 0xff, + 0xbb, 0x89, 0x2d, 0xfc, 0xf7, 0x70, 0x3f, 0xfb, 0x67, 0x29, 0x68, 0x81, + 0xf1, 0x45, 0x90, 0xe5, 0xff, 0x4f, 0xfc, 0x83, 0xdf, 0xdc, 0x4e, 0x5f, + 0xc9, 0x0c, 0x9f, 0x1b, 0x39, 0x7e, 0xc9, 0xd9, 0x8c, 0x39, 0x7b, 0x69, + 0xa3, 0x94, 0x27, 0x89, 0xe2, 0x8b, 0xf8, 0x5c, 0x00, 0xff, 0x67, 0x2f, + 0xe4, 0x55, 0x48, 0x67, 0xd0, 0xa6, 0x1b, 0x82, 0x1a, 0x3c, 0xdb, 0x97, + 0x88, 0x6b, 0x15, 0x22, 0xa4, 0x29, 0x46, 0x33, 0x0b, 0xfb, 0xbd, 0xc9, + 0xfd, 0xb3, 0x97, 0xb2, 0x7f, 0xce, 0x56, 0x1e, 0x68, 0x97, 0xdf, 0xf6, + 0x7b, 0xe0, 0xe0, 0x14, 0xe4, 0xe5, 0x49, 0x7d, 0x14, 0x25, 0x79, 0x0e, + 0xa5, 0x4a, 0x50, 0xdb, 0x45, 0x5d, 0x8c, 0xb0, 0x09, 0xe2, 0xe5, 0xb9, + 0x5a, 0xfe, 0x84, 0x3b, 0x42, 0x0b, 0xff, 0xf4, 0xfa, 0xd6, 0x05, 0xd9, + 0xd7, 0xf0, 0xc4, 0xc7, 0x2f, 0xff, 0xff, 0x7f, 0xaf, 0xe6, 0x17, 0x06, + 0xf7, 0x8a, 0xe7, 0xfa, 0x70, 0xc7, 0x60, 0xe5, 0xff, 0x7d, 0x63, 0x87, + 0xb0, 0x3f, 0x9c, 0xbe, 0xe0, 0xef, 0xea, 0x1c, 0xbc, 0xdb, 0x6d, 0x94, + 0xba, 0x50, 0x53, 0xe9, 0xa0, 0xa8, 0x4d, 0xf2, 0x75, 0x6c, 0x7b, 0xe4, + 0xef, 0x49, 0x17, 0xff, 0xc9, 0xe9, 0xb3, 0x5a, 0x79, 0xb3, 0x59, 0xe3, + 0x97, 0xf2, 0xb1, 0xad, 0x67, 0x4e, 0x5f, 0xd3, 0xcd, 0x2e, 0x1b, 0x53, + 0x9c, 0xbf, 0xfc, 0x06, 0x3c, 0xbe, 0x40, 0x67, 0x64, 0x68, 0xe5, 0xf2, + 0x40, 0xf8, 0xe5, 0xe9, 0xdc, 0x4e, 0x56, 0x91, 0x13, 0xd4, 0xdf, 0x10, + 0x5f, 0xf9, 0x5f, 0xf7, 0x24, 0xd4, 0xff, 0x80, 0xe5, 0xc3, 0x87, 0x2f, + 0x3f, 0x2d, 0x9c, 0xa5, 0x4f, 0xdd, 0x11, 0x3a, 0x2b, 0x7e, 0x9f, 0x49, + 0x0c, 0x39, 0x7f, 0xfd, 0x0a, 0x78, 0x60, 0x0f, 0xe0, 0x28, 0x32, 0x39, + 0x4d, 0x52, 0xa0, 0xec, 0x86, 0x02, 0x42, 0x9d, 0xcb, 0xfc, 0x51, 0x7c, + 0xa0, 0x7a, 0x87, 0x2f, 0xfc, 0xfe, 0xdb, 0x79, 0xd0, 0x3f, 0x8e, 0x5f, + 0xff, 0xfb, 0x3d, 0x0b, 0x1c, 0xc1, 0x89, 0x7b, 0xae, 0xc1, 0xce, 0x27, + 0x2a, 0x74, 0x65, 0x84, 0x8d, 0xb3, 0xfb, 0xca, 0x06, 0x63, 0x97, 0xa4, + 0x82, 0x72, 0xfa, 0x75, 0x38, 0x1b, 0x39, 0x7f, 0xd1, 0xd7, 0x4f, 0x4c, + 0x8d, 0x9c, 0xbf, 0xf0, 0x33, 0x48, 0x0c, 0x06, 0x98, 0x72, 0xff, 0xf2, + 0xb1, 0xbd, 0x47, 0x47, 0x3d, 0x0c, 0x39, 0x7f, 0xdb, 0x1c, 0xe2, 0x93, + 0x23, 0x67, 0x2f, 0xff, 0xef, 0xde, 0x75, 0xff, 0x3f, 0xb3, 0xa3, 0x9e, + 0xea, 0x1c, 0xbf, 0x44, 0xc3, 0xfe, 0xce, 0x56, 0x26, 0x16, 0x89, 0x3d, + 0x3b, 0xf2, 0xf5, 0xc8, 0x27, 0x2f, 0xe7, 0x10, 0x67, 0x95, 0x39, 0x50, + 0xaa, 0x56, 0x73, 0x29, 0x0f, 0xb8, 0xd8, 0x94, 0xec, 0xe7, 0xd1, 0xa4, + 0xf1, 0x3c, 0x68, 0x2b, 0x7c, 0x3e, 0x86, 0x87, 0x2f, 0xbb, 0xfb, 0x20, + 0xe5, 0xcf, 0xb3, 0x97, 0x7f, 0xc3, 0x9c, 0xa6, 0xa8, 0xfe, 0x5c, 0x8c, + 0x48, 0xff, 0x16, 0xb9, 0xfe, 0xb5, 0x4f, 0xcb, 0xcb, 0xc2, 0x42, 0x09, + 0xab, 0x84, 0x3f, 0x0d, 0x0a, 0x8e, 0x17, 0x2c, 0x6a, 0x04, 0x9c, 0x2c, + 0x7b, 0x13, 0x97, 0x73, 0xca, 0x96, 0x94, 0xa4, 0xc0, 0xcb, 0xed, 0xca, + 0x5a, 0x52, 0xb1, 0xaf, 0xae, 0x55, 0x37, 0x32, 0x89, 0x52, 0x58, 0x8b, + 0x5c, 0x2c, 0x66, 0x94, 0xbd, 0xa9, 0x57, 0xcc, 0x97, 0x3b, 0xda, 0x58, + 0x13, 0xc7, 0x54, 0x08, 0xe1, 0xf8, 0x76, 0x21, 0x9d, 0x2f, 0xdd, 0x26, + 0x9b, 0xd5, 0x85, 0xcf, 0xf2, 0x8e, 0xf8, 0xa5, 0xb6, 0xa0, 0xd2, 0x51, + 0xe2, 0x92, 0xee, 0x38, 0x23, 0x01, 0xbf, 0x33, 0x11, 0xc0, 0x72, 0xf9, + 0x6e, 0xeb, 0x34, 0x51, 0x4b, 0xff, 0xf3, 0x82, 0x17, 0xd4, 0xdf, 0x53, + 0xdd, 0xc1, 0x39, 0x5a, 0x44, 0x08, 0x97, 0x5e, 0x79, 0x7d, 0x84, 0x64, + 0xe4, 0x29, 0xef, 0xff, 0xc1, 0x49, 0x86, 0x3d, 0xbf, 0x72, 0xb4, 0x19, + 0xce, 0x5b, 0xeb, 0x11, 0x21, 0xb3, 0x9b, 0xfd, 0xf7, 0x34, 0xb7, 0x75, + 0x9a, 0x2e, 0x85, 0xff, 0xdf, 0x5e, 0x5f, 0x73, 0x4b, 0x77, 0x59, 0xa2, + 0x4b, 0x5f, 0xb4, 0xb7, 0x75, 0x9a, 0x2f, 0x25, 0xcf, 0xc4, 0xe5, 0xbe, + 0xe1, 0xe6, 0x34, 0x34, 0xa8, 0x7f, 0x1f, 0xc9, 0xe1, 0x15, 0x22, 0xac, + 0x84, 0xe2, 0xe1, 0x33, 0x31, 0xd3, 0x10, 0x7b, 0x38, 0x5a, 0x37, 0xcc, + 0x47, 0xb9, 0xc1, 0x1f, 0x15, 0xfe, 0x83, 0xc6, 0x14, 0x17, 0xff, 0xbe, + 0xb1, 0xe5, 0xf7, 0x34, 0xb7, 0x75, 0x9a, 0x25, 0x95, 0xb8, 0x63, 0x96, + 0xe9, 0xca, 0x6a, 0x8d, 0x3f, 0xe2, 0xd7, 0xf9, 0x03, 0xdc, 0x41, 0x54, + 0xe5, 0xf7, 0x5f, 0xdf, 0x9c, 0xbe, 0xec, 0x35, 0xb0, 0xe5, 0xef, 0xd6, + 0xe7, 0x2a, 0x48, 0x97, 0x43, 0x26, 0xb2, 0x35, 0x09, 0x6f, 0xe0, 0xfb, + 0xf7, 0x96, 0xce, 0x5f, 0x23, 0x5c, 0x4e, 0x72, 0xf7, 0x9d, 0x87, 0x2f, + 0xdf, 0xf9, 0x3b, 0x07, 0x2f, 0xfd, 0xd8, 0xea, 0x2b, 0xed, 0xb8, 0x0e, + 0x5f, 0xf3, 0xcb, 0x7f, 0xfa, 0x3d, 0xb3, 0x97, 0xf0, 0xfb, 0x50, 0xeb, + 0x39, 0x73, 0xec, 0xe5, 0xff, 0xf9, 0xde, 0x4f, 0xdf, 0x99, 0x3f, 0xfe, + 0x4e, 0xc1, 0xca, 0x9c, 0xfb, 0x66, 0x16, 0xbc, 0xee, 0xb3, 0x44, 0x66, + 0xbf, 0xff, 0xfb, 0x3d, 0xbf, 0x79, 0x3b, 0xcc, 0xb6, 0x3f, 0xe2, 0xaa, + 0xa3, 0xc8, 0xe5, 0x2d, 0x13, 0xba, 0x28, 0xbf, 0x92, 0x19, 0x3e, 0x36, + 0x72, 0xe1, 0x91, 0xcb, 0x30, 0xe5, 0xf9, 0x35, 0xd7, 0xfb, 0xa3, 0xd5, + 0x61, 0x72, 0x82, 0xd7, 0xf3, 0xc9, 0x34, 0xfa, 0x39, 0x7f, 0xf6, 0xd3, + 0xfd, 0xe0, 0xff, 0x2c, 0xd9, 0xcb, 0xdb, 0x8e, 0x4e, 0x54, 0xea, 0xd3, + 0xe4, 0x50, 0x13, 0xfc, 0x3a, 0x48, 0x4c, 0xea, 0x18, 0x2c, 0x78, 0x14, + 0xed, 0x96, 0x79, 0x16, 0xff, 0xb4, 0xed, 0xf5, 0x23, 0x50, 0x72, 0xff, + 0xa5, 0xbc, 0x8f, 0x91, 0xb6, 0x1c, 0xbe, 0xe7, 0xb1, 0xb3, 0x97, 0xa3, + 0xdb, 0x39, 0x7f, 0xec, 0x57, 0x71, 0x82, 0x1e, 0xc1, 0xca, 0xd9, 0xec, + 0xfe, 0x39, 0x58, 0x89, 0xfd, 0xbe, 0x5f, 0xfd, 0xe4, 0xd3, 0x83, 0xe7, + 0x32, 0x86, 0x1c, 0xbf, 0x0c, 0x4b, 0x6e, 0x72, 0x90, 0xfb, 0x78, 0xa3, + 0xdb, 0xa7, 0x2f, 0xff, 0xfe, 0xf2, 0x33, 0x49, 0x9c, 0x8f, 0xfe, 0x8e, + 0xfc, 0xe2, 0x9e, 0x9a, 0x0e, 0x5b, 0x31, 0x11, 0x1e, 0x11, 0xbf, 0xcf, + 0x2d, 0xed, 0xc6, 0x47, 0x2f, 0x2d, 0xc2, 0x72, 0xff, 0xde, 0x71, 0x07, + 0xc5, 0x33, 0x96, 0xce, 0x5f, 0x7b, 0xd0, 0xc3, 0x95, 0x87, 0xca, 0xaa, + 0x1d, 0xff, 0xef, 0x42, 0xd3, 0xc8, 0xc9, 0xb6, 0x82, 0x72, 0xff, 0x33, + 0x34, 0x01, 0xfc, 0x07, 0x2d, 0x23, 0x94, 0x88, 0x8e, 0x74, 0x95, 0x0d, + 0x2f, 0xc0, 0x8f, 0x40, 0x4e, 0x54, 0x27, 0x0e, 0x90, 0x81, 0x78, 0x58, + 0x7e, 0x5f, 0x7f, 0xfd, 0xff, 0xb7, 0xcc, 0xa0, 0x41, 0xbf, 0x9f, 0x89, + 0xcb, 0xd1, 0xe8, 0x39, 0x41, 0x3f, 0x0e, 0x2a, 0xb7, 0xbb, 0x82, 0x72, + 0x90, 0xdf, 0xfe, 0x49, 0x77, 0x66, 0x39, 0x7d, 0x93, 0x64, 0xc7, 0x2f, + 0xb3, 0x41, 0x83, 0x97, 0x73, 0xbf, 0x87, 0x88, 0x24, 0x74, 0x88, 0x8c, + 0x75, 0xcb, 0xfe, 0xf6, 0xf3, 0x40, 0x1f, 0xc0, 0x72, 0xfb, 0xcf, 0xd8, + 0x39, 0x7d, 0xee, 0xfe, 0xd0, 0xe5, 0xfe, 0xc8, 0xd3, 0xc9, 0x3a, 0x72, + 0xff, 0x23, 0x7b, 0x8e, 0xbb, 0x59, 0xca, 0xd1, 0xf3, 0xf8, 0xc6, 0xb9, + 0x46, 0x82, 0x10, 0xb2, 0x11, 0xb7, 0xff, 0x93, 0xbf, 0xb5, 0x87, 0xbf, + 0xef, 0x99, 0x39, 0xca, 0x84, 0xe4, 0x32, 0x30, 0xa7, 0x35, 0xbc, 0xa6, + 0x70, 0xc7, 0x2f, 0xff, 0x7e, 0x06, 0x20, 0xe0, 0x07, 0x1e, 0x63, 0x97, + 0xf9, 0x3a, 0x90, 0x33, 0x7e, 0x72, 0xff, 0x26, 0xb3, 0x07, 0x9f, 0x1c, + 0xa8, 0x3e, 0x57, 0x33, 0xbf, 0xf7, 0xe1, 0xd6, 0x7f, 0xd8, 0x66, 0x1c, + 0xac, 0x4c, 0xc3, 0x44, 0x5d, 0x85, 0x76, 0xc8, 0x2f, 0xff, 0xb9, 0x92, + 0x68, 0x3d, 0xff, 0x58, 0xbe, 0xe1, 0xcb, 0x91, 0xb3, 0x97, 0x70, 0x61, + 0xca, 0xd9, 0xb0, 0xf0, 0xbd, 0xfd, 0xb8, 0xf6, 0xfa, 0x87, 0x2f, 0xc3, + 0x8c, 0xd6, 0x1c, 0xbe, 0xd7, 0x1c, 0x09, 0xca, 0xc3, 0xf7, 0x61, 0x6f, + 0xe4, 0xd7, 0x83, 0x9e, 0x39, 0x7c, 0x04, 0xe6, 0x47, 0x2f, 0xf4, 0x0f, + 0x92, 0x71, 0x83, 0x97, 0xff, 0x93, 0x49, 0x3c, 0x0e, 0x77, 0x5f, 0xf1, + 0x39, 0x41, 0x45, 0xe0, 0x07, 0x04, 0x8f, 0xc6, 0x37, 0xff, 0xff, 0x93, + 0x1b, 0xe6, 0x5b, 0xf8, 0xac, 0x0a, 0xdf, 0xce, 0xaa, 0x93, 0xc4, 0xe7, + 0x29, 0xab, 0x6c, 0x4d, 0xa2, 0x17, 0xd3, 0xa0, 0x48, 0xbc, 0x24, 0xb9, + 0x2d, 0xad, 0x58, 0x4a, 0xf2, 0x70, 0x90, 0xd9, 0x9a, 0x11, 0xfa, 0x85, + 0x5b, 0x09, 0xfb, 0x1d, 0xcb, 0xc3, 0xd4, 0x10, 0xad, 0x18, 0xec, 0x77, + 0x1b, 0x27, 0x90, 0xb8, 0xc2, 0x09, 0xa4, 0x26, 0x14, 0x87, 0x5f, 0x01, + 0xe5, 0xfc, 0xc9, 0x44, 0x6d, 0x0e, 0x5c, 0xe0, 0x39, 0x50, 0x78, 0x4e, + 0x59, 0x7e, 0x70, 0xbb, 0xf2, 0x72, 0xef, 0x7d, 0xe9, 0xe3, 0xb9, 0x05, + 0xff, 0xff, 0xdf, 0xf3, 0x2f, 0xae, 0x3e, 0xc6, 0x6c, 0x3d, 0x8d, 0x05, + 0xdd, 0xb3, 0x95, 0xf5, 0x55, 0x8e, 0x4a, 0x0c, 0x12, 0xfb, 0xff, 0xdf, + 0x58, 0xf2, 0xfb, 0x9a, 0x5b, 0xba, 0xcd, 0x13, 0x4a, 0xff, 0xf7, 0xd6, + 0x3c, 0xbe, 0xe6, 0x96, 0xee, 0xb3, 0x44, 0xe2, 0xbf, 0x4b, 0x3d, 0x29, + 0x1c, 0xbf, 0xdc, 0x63, 0xbf, 0x06, 0x24, 0x72, 0xff, 0xcf, 0x2f, 0xb9, + 0xa5, 0xbb, 0xac, 0xd1, 0x40, 0xaf, 0xff, 0x24, 0x31, 0xc3, 0xa8, 0xf7, + 0x70, 0x27, 0x2f, 0xb6, 0x3c, 0xc8, 0xe5, 0xbe, 0xf2, 0x98, 0xaa, 0x14, + 0x30, 0xdb, 0xa9, 0x9e, 0x48, 0xbf, 0x69, 0x6e, 0xeb, 0x34, 0x5c, 0x0b, + 0xf8, 0x73, 0xcb, 0x4d, 0x9c, 0xba, 0x10, 0xe5, 0xf7, 0x7f, 0x79, 0x1c, + 0xbf, 0xc3, 0x28, 0x40, 0xe3, 0x0e, 0x56, 0x23, 0x25, 0x86, 0x9d, 0x2c, + 0xf0, 0xaf, 0xe4, 0x77, 0xe9, 0x7d, 0x57, 0x84, 0x54, 0xe5, 0x7d, 0x3f, + 0xc8, 0x4a, 0xb9, 0xc0, 0x72, 0xfd, 0x34, 0xa0, 0x64, 0x72, 0x8e, 0x56, + 0x1b, 0x31, 0x28, 0xbe, 0x80, 0x63, 0x67, 0x2e, 0x4f, 0xba, 0x44, 0x50, + 0xa4, 0xa8, 0x3f, 0x7f, 0xd2, 0xfb, 0x9a, 0x5b, 0xba, 0xcd, 0x12, 0x4a, + 0xdf, 0x7a, 0x88, 0x47, 0x3d, 0xb9, 0xb0, 0x1c, 0xbf, 0xcf, 0xe1, 0xc9, + 0xdc, 0x4e, 0x5c, 0xab, 0x67, 0x2f, 0xe9, 0x3e, 0xa7, 0x0c, 0x1c, 0xbf, + 0xb0, 0x5f, 0x99, 0x6c, 0xe5, 0xff, 0xfb, 0xf1, 0x75, 0x7c, 0xac, 0x0c, + 0xb3, 0xa8, 0xc3, 0x97, 0xf4, 0x33, 0x58, 0x1f, 0x1c, 0xbf, 0x70, 0x76, + 0x05, 0x53, 0x97, 0x3f, 0xd0, 0xa6, 0xd6, 0xa8, 0xc7, 0x26, 0x33, 0x0c, + 0xe8, 0xb9, 0x85, 0xbb, 0x56, 0xf1, 0x6d, 0x4e, 0xdd, 0xa5, 0x4a, 0xb4, + 0x68, 0x59, 0xcc, 0xcb, 0x40, 0x8d, 0xbf, 0x71, 0xcc, 0x7a, 0x33, 0x1e, + 0x31, 0xca, 0xdf, 0xf9, 0x57, 0xfb, 0x9a, 0x5b, 0xba, 0xcd, 0x16, 0xa2, + 0xff, 0xcf, 0x2f, 0xb9, 0xa5, 0xbb, 0xac, 0xd1, 0x2a, 0xae, 0x46, 0xce, + 0x51, 0xcb, 0x7d, 0x55, 0x17, 0x6c, 0x4d, 0xf2, 0x67, 0x00, 0xbd, 0xfd, + 0x9a, 0x5b, 0xba, 0xcd, 0x11, 0x4a, 0xff, 0xce, 0xec, 0xcd, 0x00, 0x7f, + 0x01, 0xcb, 0xff, 0x47, 0xb7, 0x9a, 0x00, 0xfe, 0x03, 0x97, 0xc9, 0xb8, + 0x73, 0x97, 0xf8, 0x5c, 0x1b, 0xf6, 0x2c, 0xe5, 0xcc, 0xfb, 0xd4, 0x67, + 0x89, 0xf6, 0xcf, 0xfc, 0x41, 0x5f, 0x53, 0x52, 0x78, 0xc2, 0x2f, 0xf7, + 0xdc, 0xd2, 0xdd, 0xd6, 0x68, 0x8d, 0x17, 0x7f, 0xd3, 0x97, 0xfe, 0x0e, + 0x31, 0x35, 0x9b, 0x9a, 0x0e, 0x5f, 0xff, 0xf3, 0xff, 0xbe, 0xe0, 0x54, + 0x53, 0x68, 0xa7, 0x93, 0x73, 0x28, 0x72, 0xff, 0xf4, 0xc8, 0x9d, 0x9b, + 0x3d, 0x1e, 0x80, 0x9c, 0xbc, 0x8e, 0xd9, 0x4a, 0x44, 0xc4, 0x5a, 0xcf, + 0xa6, 0x6d, 0x62, 0x55, 0xf2, 0xdd, 0xd6, 0x68, 0xa7, 0xd7, 0x7a, 0x0e, + 0x56, 0x8f, 0x13, 0xc5, 0xd7, 0xfe, 0xf4, 0xd1, 0xee, 0xbc, 0xdf, 0x30, + 0xe5, 0xef, 0xfb, 0xf9, 0xcb, 0xff, 0xc8, 0xc1, 0xff, 0xa9, 0xac, 0xdc, + 0xd0, 0x72, 0xff, 0xef, 0xfd, 0xaf, 0xe6, 0xda, 0xde, 0x6d, 0x9c, 0xbf, + 0xfb, 0x26, 0xfc, 0x67, 0xda, 0xde, 0x6d, 0x9c, 0xbe, 0xff, 0xa9, 0xa3, + 0x96, 0xfa, 0xd5, 0xab, 0x30, 0x88, 0xca, 0x72, 0x10, 0xa8, 0x45, 0xd4, + 0x27, 0x1f, 0x14, 0xaf, 0x25, 0x34, 0x48, 0xbf, 0xfd, 0xf5, 0x8f, 0x2f, + 0xb9, 0xa5, 0xbb, 0xac, 0xd1, 0x35, 0x2f, 0xec, 0xd2, 0xdd, 0xd6, 0x68, + 0xae, 0xd7, 0xff, 0xb3, 0x81, 0x3c, 0x92, 0xf8, 0x31, 0xed, 0x9c, 0xa3, + 0x97, 0x37, 0xf7, 0xa7, 0xb0, 0xda, 0x6d, 0x7d, 0x46, 0x1a, 0x42, 0x46, + 0xf6, 0xe1, 0x87, 0x2e, 0x60, 0x9c, 0xbe, 0x5b, 0xba, 0xcd, 0x15, 0xf2, + 0xf3, 0x6d, 0xb6, 0x52, 0xc2, 0x53, 0xe9, 0xa0, 0xad, 0x1f, 0x83, 0x13, + 0xaf, 0x4a, 0x39, 0x39, 0x7a, 0x6c, 0xe9, 0xcb, 0xff, 0x67, 0x5b, 0x7f, + 0x6e, 0x32, 0x73, 0x96, 0xf1, 0xcb, 0xfe, 0x4d, 0x64, 0xe9, 0x2c, 0x09, + 0xca, 0xd1, 0xe4, 0xb8, 0x8d, 0xfb, 0x9e, 0x0e, 0xfe, 0xa1, 0xcb, 0x68, + 0xe5, 0x1c, 0xa4, 0x2f, 0x34, 0x23, 0x74, 0xea, 0x9c, 0xae, 0x9b, 0x87, + 0x1f, 0xb7, 0xd8, 0x54, 0x95, 0x38, 0xe6, 0x42, 0x1a, 0x62, 0x27, 0x1d, + 0x11, 0xdd, 0xc2, 0x23, 0xf2, 0x16, 0x90, 0x83, 0xbf, 0xfd, 0xf5, 0x8f, + 0x2f, 0xb9, 0xa5, 0xbb, 0xac, 0xd1, 0x3d, 0xaf, 0xa3, 0x81, 0xf9, 0x39, + 0x79, 0x04, 0x07, 0x2b, 0xa7, 0x81, 0xc4, 0x96, 0xfd, 0xa5, 0xbb, 0xac, + 0xd1, 0x70, 0xad, 0xf6, 0x0f, 0x63, 0x09, 0x2f, 0xfe, 0xfa, 0xf2, 0xfb, + 0x9a, 0x5b, 0xba, 0xcd, 0x12, 0x7a, 0xa1, 0x96, 0xc5, 0x3c, 0x73, 0x72, + 0x2b, 0x56, 0x5b, 0x8a, 0xe1, 0x2b, 0x34, 0x63, 0xba, 0x94, 0xe7, 0xd8, + 0x4c, 0x6e, 0x1e, 0x5c, 0x4a, 0x2f, 0xf7, 0xdc, 0xd2, 0xdd, 0xd6, 0x68, + 0x8a, 0x97, 0xed, 0x2d, 0xdd, 0x66, 0x8a, 0x65, 0x7f, 0x27, 0x71, 0xf9, + 0x01, 0xcb, 0x7d, 0xc3, 0xe1, 0x68, 0x69, 0x7f, 0xfb, 0xeb, 0x1e, 0x5f, + 0x73, 0x4b, 0x77, 0x59, 0xa2, 0x67, 0x5f, 0xfe, 0xfa, 0xc7, 0x97, 0xdc, + 0xd2, 0xdd, 0xd6, 0x68, 0xa3, 0x55, 0x3a, 0x70, 0x21, 0x85, 0x12, 0xa5, + 0x7e, 0x5a, 0xbf, 0xf3, 0xcb, 0xee, 0x69, 0x6e, 0xeb, 0x34, 0x47, 0x4b, + 0xff, 0xb5, 0x3f, 0xdd, 0x8e, 0x7b, 0x70, 0xc3, 0x97, 0xff, 0xfb, 0x52, + 0xfb, 0x83, 0xff, 0xbf, 0x57, 0xdc, 0xad, 0x35, 0xb3, 0x95, 0xf5, 0x1f, + 0x70, 0x98, 0x88, 0xf7, 0x7f, 0xd3, 0x97, 0xcb, 0x5f, 0xeb, 0x39, 0x7e, + 0xc1, 0x0e, 0x4e, 0x72, 0xff, 0x44, 0x2f, 0x35, 0xac, 0x39, 0x48, 0x7b, + 0x02, 0x4f, 0x7e, 0xcd, 0x2f, 0xf5, 0x4e, 0x5f, 0xf8, 0x71, 0x57, 0x9b, + 0x7d, 0x80, 0x9c, 0xbd, 0x33, 0xf8, 0xe5, 0xf2, 0xdd, 0xd6, 0x68, 0xa6, + 0x97, 0xec, 0xe5, 0xb7, 0xe9, 0xcb, 0xff, 0xb7, 0x82, 0x18, 0xf8, 0xd4, + 0x78, 0x81, 0x0e, 0x50, 0x53, 0x2a, 0x42, 0xa9, 0x8f, 0xf4, 0x3a, 0x25, + 0xdb, 0x29, 0xbf, 0xff, 0xec, 0x1f, 0x6d, 0x17, 0x83, 0xb5, 0xf5, 0x3a, + 0xb5, 0x27, 0x39, 0x7f, 0xdb, 0x7e, 0x72, 0x68, 0xee, 0xce, 0x5d, 0xd4, + 0x14, 0x50, 0xf9, 0x9e, 0xff, 0xe9, 0x75, 0x06, 0x7d, 0xff, 0x1a, 0x98, + 0xe5, 0xe9, 0x32, 0x47, 0x2f, 0x03, 0xc8, 0x72, 0xff, 0x6d, 0x69, 0xad, + 0x24, 0xe7, 0x29, 0xcf, 0x43, 0x63, 0x97, 0xff, 0xfd, 0x93, 0xcf, 0xfe, + 0xa6, 0xdc, 0xf1, 0x36, 0xfb, 0x81, 0x4e, 0x27, 0x2f, 0xf7, 0xee, 0x2b, + 0xf9, 0x3e, 0xce, 0x5f, 0xd0, 0x3e, 0x69, 0x9e, 0x39, 0x7f, 0x9c, 0x0f, + 0xef, 0x67, 0x4e, 0x54, 0x8f, 0x81, 0xb2, 0xeb, 0xbb, 0xf9, 0xca, 0xc3, + 0x76, 0x02, 0x3b, 0xfd, 0xd8, 0x40, 0x3f, 0xbf, 0x39, 0x7f, 0xe1, 0xff, + 0xdd, 0xc9, 0xa5, 0x1c, 0x9c, 0xb4, 0xc7, 0x2f, 0xd9, 0xd7, 0x10, 0x9c, + 0xa9, 0xcd, 0xc0, 0x04, 0xae, 0x85, 0x4e, 0x5f, 0xce, 0x0d, 0xf0, 0xae, + 0x15, 0xc2, 0x8e, 0x5f, 0xc9, 0x0c, 0x9f, 0x1b, 0x39, 0x7f, 0xfd, 0x9e, + 0xee, 0x4b, 0x4e, 0x3e, 0xeb, 0xc8, 0xe5, 0xd0, 0x03, 0x97, 0xf9, 0xf9, + 0x85, 0xa2, 0xfe, 0xe9, 0x12, 0x42, 0x5c, 0xa2, 0x75, 0x62, 0x7b, 0xc8, + 0xf3, 0xd2, 0x21, 0x17, 0xdc, 0x34, 0xaf, 0xc0, 0xec, 0x4b, 0x67, 0x2f, + 0x36, 0xf3, 0x9c, 0xbf, 0xe8, 0x03, 0xf8, 0x0a, 0x0c, 0x8e, 0x57, 0x4f, + 0x5c, 0x47, 0xaa, 0x11, 0x41, 0xe7, 0xfb, 0x7d, 0x6a, 0xd9, 0x0b, 0x30, + 0x30, 0x17, 0xcc, 0x8d, 0x29, 0x70, 0xf8, 0xe4, 0xb5, 0x11, 0xf4, 0xdb, + 0xd2, 0x10, 0x37, 0x8c, 0x34, 0xb6, 0x41, 0xe9, 0x42, 0x2a, 0x43, 0xb6, + 0xfd, 0xa5, 0xbb, 0xac, 0xd1, 0x55, 0x2f, 0xfc, 0xf2, 0xfb, 0x9a, 0x5b, + 0xba, 0xcd, 0x13, 0x6a, 0xdf, 0x71, 0x10, 0x0c, 0x34, 0xbf, 0xdf, 0x73, + 0x4b, 0x77, 0x59, 0xa2, 0xbf, 0x5f, 0xb4, 0xb7, 0x75, 0x9a, 0x2c, 0x65, + 0xdc, 0x12, 0x39, 0x6f, 0xb8, 0x79, 0xd3, 0x1a, 0x5f, 0xb6, 0xbe, 0xc2, + 0xa7, 0x2f, 0xf0, 0xff, 0x2c, 0xdb, 0xf8, 0xe5, 0xfc, 0xd5, 0x05, 0xab, + 0x6a, 0xc5, 0x53, 0x97, 0xfc, 0x3f, 0xcf, 0x34, 0xa3, 0x53, 0x9c, 0xbb, + 0x5e, 0x39, 0x7c, 0xf2, 0xc0, 0x9c, 0xbf, 0xbd, 0x9a, 0x0e, 0x09, 0xcb, + 0x60, 0x4f, 0x37, 0xc4, 0x37, 0x95, 0x96, 0x1c, 0xbf, 0xb3, 0x5e, 0xee, + 0x4e, 0x72, 0xdf, 0x71, 0x38, 0x46, 0x19, 0xf4, 0xf9, 0xcf, 0x45, 0x93, + 0x64, 0xea, 0x0e, 0xd9, 0x3e, 0xaa, 0x18, 0xd4, 0x75, 0xb7, 0xed, 0x2d, + 0xdd, 0x66, 0x8b, 0x55, 0x7f, 0xe7, 0x97, 0xdc, 0xd2, 0xdd, 0xd6, 0x68, + 0xa0, 0x97, 0xe8, 0x6d, 0xa6, 0x68, 0xe5, 0xbe, 0xe2, 0x2a, 0x98, 0x68, + 0xa2, 0x65, 0xff, 0x9d, 0xbf, 0x67, 0x7e, 0xbe, 0xbc, 0x72, 0xff, 0x40, + 0x82, 0x1a, 0xdd, 0x87, 0x2f, 0xff, 0x4d, 0x1c, 0x5f, 0x5b, 0xda, 0x6b, + 0x15, 0x39, 0x7f, 0xd0, 0x93, 0x47, 0x17, 0xd6, 0xce, 0x5d, 0xa8, 0x39, + 0x52, 0x46, 0x8a, 0x1a, 0x75, 0x37, 0x80, 0xea, 0xf9, 0x6e, 0xeb, 0x34, + 0x5c, 0x4b, 0xfb, 0xf7, 0xe4, 0x39, 0xa3, 0x95, 0xa3, 0xdd, 0xd9, 0x75, + 0xfb, 0x18, 0x9c, 0x01, 0x39, 0x74, 0x30, 0xe5, 0x35, 0x9e, 0x06, 0x8a, + 0xaf, 0x9f, 0x81, 0x27, 0x39, 0x7e, 0xef, 0xea, 0xe0, 0x9c, 0xbf, 0x07, + 0x1a, 0xe3, 0xa7, 0x2f, 0x70, 0x22, 0xce, 0x50, 0x4f, 0xcb, 0x45, 0x3c, + 0x05, 0x57, 0xf9, 0x8f, 0x2d, 0xa0, 0x70, 0xe5, 0xf4, 0x2b, 0x1b, 0x39, + 0x7e, 0x1f, 0x0b, 0xaa, 0x72, 0x8e, 0x5b, 0x78, 0x6c, 0x9a, 0x13, 0xdf, + 0xcc, 0x7e, 0x31, 0xae, 0x03, 0x97, 0xfe, 0x40, 0xe7, 0x16, 0x64, 0xb9, + 0x91, 0xca, 0x83, 0xf3, 0xc3, 0x2b, 0xfb, 0x34, 0xfe, 0xfe, 0x0e, 0x5f, + 0xff, 0x38, 0xc2, 0x70, 0x6d, 0x37, 0x9d, 0xc6, 0x87, 0x28, 0x27, 0xfd, + 0xc4, 0xb6, 0xff, 0xe4, 0x1f, 0xe5, 0x9b, 0xda, 0x07, 0x0e, 0x54, 0xc7, + 0xcf, 0xe2, 0x4b, 0x7d, 0x85, 0xc3, 0x5c, 0x84, 0xe6, 0x98, 0xba, 0x4a, + 0xf0, 0x97, 0x01, 0x90, 0x99, 0x6d, 0x53, 0xd0, 0x9b, 0x52, 0x30, 0x5b, + 0xfc, 0xd5, 0x0b, 0x57, 0xe6, 0x8d, 0x58, 0x4e, 0x5f, 0xb8, 0x6e, 0x17, + 0x02, 0xb0, 0x72, 0xff, 0xc9, 0xcf, 0x0a, 0xde, 0xbe, 0x7c, 0xeb, 0x43, + 0x97, 0xdd, 0x8f, 0x2c, 0xe5, 0x35, 0x03, 0xef, 0x0a, 0x6d, 0xff, 0xee, + 0x14, 0xab, 0x6d, 0x73, 0x87, 0x86, 0xf9, 0xf3, 0xad, 0x0e, 0x5f, 0xb4, + 0xb7, 0x75, 0x9a, 0x2e, 0x95, 0xfa, 0x05, 0xc3, 0x07, 0x2f, 0x47, 0xb8, + 0x0e, 0x5f, 0x60, 0x70, 0x27, 0x2f, 0xf9, 0xf8, 0xc7, 0xb7, 0xfa, 0xf8, + 0x73, 0x97, 0xdb, 0x9d, 0xd4, 0x39, 0x6f, 0xad, 0x4a, 0xa7, 0x3e, 0x14, + 0x8b, 0x10, 0xa4, 0x91, 0x46, 0x32, 0x21, 0xa7, 0x49, 0x5c, 0x7c, 0x48, + 0x7c, 0x83, 0x7f, 0xfd, 0x83, 0xe4, 0x67, 0x61, 0x05, 0xf4, 0xa9, 0xcb, + 0xfb, 0x33, 0x6b, 0xf4, 0x1c, 0xbf, 0xa7, 0x8f, 0x3a, 0xbf, 0x9c, 0xa3, + 0x97, 0xff, 0x46, 0x81, 0xf3, 0x7d, 0x86, 0x38, 0x9c, 0xbf, 0xd1, 0xa5, + 0x3b, 0xdc, 0x01, 0xca, 0x91, 0xfc, 0xf5, 0x16, 0xfe, 0x93, 0xc9, 0xc5, + 0x67, 0x2f, 0xff, 0x67, 0xa1, 0xb5, 0x27, 0xde, 0x32, 0x1a, 0xce, 0x5b, + 0xeb, 0x54, 0x99, 0x0e, 0x42, 0x12, 0x62, 0x21, 0x2c, 0xad, 0x27, 0x40, + 0xc8, 0xd4, 0x6f, 0xb1, 0xb6, 0xa9, 0x87, 0x2f, 0xe1, 0x8e, 0x58, 0xfe, + 0x39, 0x7f, 0xf9, 0xb7, 0x0f, 0x63, 0x9f, 0x47, 0x5d, 0xac, 0xe5, 0x93, + 0x47, 0xf7, 0xd2, 0xdb, 0xff, 0xfe, 0xff, 0x52, 0xdf, 0x5d, 0x35, 0xad, + 0x7f, 0xca, 0x69, 0xf6, 0x72, 0xff, 0xc2, 0xed, 0xfb, 0x3a, 0xf3, 0x39, + 0xcb, 0xff, 0xfb, 0xa3, 0xfb, 0xb5, 0xe4, 0xbb, 0x8a, 0xe0, 0x66, 0xfc, + 0xe5, 0xcb, 0xc3, 0x95, 0x07, 0xee, 0xab, 0x0d, 0xfe, 0x7f, 0x6e, 0x3a, + 0xa4, 0xc7, 0x2f, 0x4a, 0x18, 0x72, 0xf2, 0xbb, 0x91, 0xcb, 0xfd, 0xad, + 0x3c, 0xa7, 0xc6, 0xce, 0x5d, 0x37, 0xe7, 0x2d, 0x2c, 0x3c, 0xe6, 0xcd, + 0x6f, 0xfe, 0xc0, 0xc4, 0xa3, 0x50, 0xa3, 0x89, 0xcb, 0xff, 0x71, 0xc9, + 0x30, 0x29, 0xc6, 0x02, 0x72, 0x98, 0x88, 0x47, 0x42, 0xb9, 0xfe, 0xce, + 0xab, 0x32, 0x66, 0xad, 0x42, 0xd7, 0xa4, 0x4e, 0x6b, 0xb1, 0xcf, 0x36, + 0x29, 0x0a, 0xca, 0xea, 0xb7, 0xf1, 0x95, 0xe7, 0x7f, 0xa5, 0x9e, 0xec, + 0x28, 0x27, 0x2f, 0xfd, 0xe4, 0x5a, 0x05, 0xc5, 0x58, 0x39, 0x7f, 0xd1, + 0xcf, 0x5f, 0x7e, 0x86, 0xce, 0x54, 0x1f, 0xbe, 0x8f, 0x6e, 0xff, 0xa7, + 0x2f, 0xc3, 0x9d, 0x7f, 0x1c, 0xbf, 0xa4, 0xf9, 0xc6, 0x02, 0x72, 0xb8, + 0x43, 0xd4, 0x6a, 0x24, 0xd7, 0xc9, 0xfc, 0xa0, 0xe5, 0xf9, 0xe6, 0x92, + 0x78, 0xe5, 0xff, 0xa0, 0x3a, 0x89, 0x27, 0x3e, 0xc3, 0x95, 0x24, 0x44, + 0x00, 0x8b, 0xc5, 0x17, 0xfe, 0x8d, 0x6f, 0xa8, 0xb5, 0xff, 0x39, 0xcb, + 0xff, 0xfe, 0x80, 0xf7, 0x39, 0xf0, 0xbf, 0x40, 0xfb, 0xdb, 0xe9, 0x67, + 0x2f, 0xf6, 0x66, 0x2a, 0xab, 0xc8, 0xe5, 0x2a, 0x89, 0x9f, 0x33, 0x5f, + 0xb3, 0x6b, 0xf4, 0x1c, 0xbf, 0xfc, 0x8d, 0xed, 0x7d, 0x4e, 0x7d, 0xad, + 0x41, 0xcb, 0xff, 0xfe, 0x76, 0xd4, 0xcd, 0x0b, 0xf3, 0x25, 0xc7, 0xb7, + 0x9c, 0xf8, 0xe5, 0x62, 0x37, 0x34, 0x4e, 0xe9, 0x97, 0xee, 0x29, 0xac, + 0x09, 0xcb, 0xff, 0xed, 0xf5, 0x37, 0xee, 0xe0, 0x53, 0x78, 0x27, 0x2f, + 0x76, 0x07, 0x0f, 0xdf, 0xf2, 0x9b, 0xf3, 0xf6, 0x42, 0xb3, 0x97, 0xfa, + 0x19, 0x88, 0xc8, 0x6b, 0x39, 0x7f, 0xa4, 0xcd, 0xa0, 0xf3, 0x23, 0x94, + 0xb3, 0xe8, 0x98, 0xd2, 0xff, 0xf6, 0x6b, 0x4f, 0x2d, 0x8e, 0x31, 0x4e, + 0x4e, 0x5e, 0x77, 0x59, 0xa2, 0x4c, 0x5e, 0xe0, 0x4d, 0x9c, 0xa5, 0x9e, + 0x3f, 0x01, 0x45, 0xf9, 0x7c, 0x2b, 0x86, 0x6a, 0xb8, 0x43, 0x97, 0xff, + 0xb9, 0x96, 0xf3, 0x8b, 0xb3, 0x15, 0x8d, 0x9c, 0xbf, 0xd9, 0xcf, 0xbc, + 0xf2, 0xd9, 0xca, 0x84, 0x5f, 0xe1, 0xf6, 0x93, 0x6f, 0xf0, 0xbf, 0xb6, + 0xbf, 0xc4, 0xe5, 0xff, 0xf0, 0x10, 0x0d, 0xe2, 0x71, 0x1c, 0xf7, 0x50, + 0xe5, 0xfe, 0x7e, 0x76, 0xef, 0x2d, 0x9c, 0xb6, 0xb1, 0x10, 0x7d, 0x50, + 0xac, 0x46, 0xf2, 0x42, 0xda, 0xff, 0xff, 0x7e, 0xfc, 0xe0, 0xc3, 0x6a, + 0x78, 0x60, 0x19, 0xcf, 0x8e, 0x54, 0x95, 0xf7, 0x84, 0xcb, 0x21, 0x1e, + 0xb2, 0x3d, 0x42, 0x49, 0x90, 0xe4, 0xec, 0x61, 0x9b, 0x26, 0xbf, 0x82, + 0x0e, 0x13, 0x60, 0x68, 0x72, 0xf6, 0xd0, 0x27, 0x2f, 0xe1, 0x8e, 0x58, + 0xfe, 0x39, 0x7f, 0xd0, 0xbf, 0x7f, 0xdd, 0x43, 0x67, 0x2f, 0xf9, 0x31, + 0xb5, 0xf6, 0x11, 0xa1, 0xcb, 0xfc, 0xb4, 0xd6, 0xe6, 0x87, 0x39, 0x7f, + 0xf7, 0xfb, 0xeb, 0xcb, 0xaf, 0x28, 0x13, 0x95, 0xc9, 0xfb, 0xe8, 0xce, + 0xee, 0xa4, 0xc9, 0xac, 0x68, 0x71, 0x85, 0xbc, 0x39, 0xdf, 0xa1, 0x63, + 0x7d, 0xe4, 0x63, 0x9c, 0xb2, 0xa7, 0x2f, 0xee, 0xee, 0x3d, 0x01, 0x39, + 0x58, 0x6f, 0xd0, 0x4a, 0xb0, 0xff, 0xfc, 0xc1, 0x7f, 0xd1, 0xdf, 0x24, + 0xec, 0x85, 0x9c, 0xbf, 0xff, 0x3a, 0xf5, 0x1d, 0x1c, 0xf6, 0x7d, 0x6d, + 0xb6, 0xca, 0x54, 0x91, 0x67, 0xb2, 0x1f, 0x1c, 0xdf, 0xcb, 0x5f, 0xeb, + 0x18, 0x39, 0x7f, 0xf7, 0x32, 0x18, 0x96, 0xa3, 0xcf, 0xe3, 0x97, 0x44, + 0x8e, 0x56, 0x1e, 0xd0, 0xa2, 0x5f, 0xf9, 0xfd, 0x1a, 0xdf, 0x60, 0x7c, + 0x72, 0xfd, 0x92, 0x47, 0xe2, 0x72, 0x84, 0xf9, 0x76, 0x7b, 0x52, 0x45, + 0x37, 0xf0, 0x85, 0xbc, 0xc7, 0xe9, 0xcb, 0xff, 0xc3, 0x12, 0xd6, 0xbf, + 0xe5, 0x34, 0xfb, 0x39, 0x7f, 0xfd, 0xbc, 0x54, 0x73, 0xdb, 0xc9, 0x0b, + 0xb6, 0x72, 0xc9, 0xd4, 0x4d, 0x79, 0x2e, 0x91, 0x1b, 0xdc, 0x61, 0x6d, + 0x7d, 0xc1, 0x1d, 0xd9, 0xcb, 0xfe, 0xc9, 0xfc, 0x31, 0xff, 0xb6, 0x72, + 0xa1, 0x11, 0x18, 0x53, 0xa2, 0x5b, 0xc0, 0x04, 0x1c, 0xbf, 0x0f, 0xf3, + 0xf2, 0xd6, 0x72, 0xb6, 0x79, 0x5e, 0x1c, 0xbf, 0xfd, 0x13, 0x8e, 0x64, + 0xfe, 0x56, 0x06, 0x47, 0x2f, 0xfc, 0xe3, 0x3f, 0x5d, 0x89, 0xb4, 0x39, + 0x4e, 0x8a, 0x91, 0x22, 0x6d, 0x2a, 0xf3, 0x6d, 0xb6, 0x52, 0xfa, 0x76, + 0x26, 0xca, 0x7d, 0x34, 0x17, 0x40, 0x4e, 0x5b, 0x4e, 0x79, 0x62, 0x6b, + 0x7e, 0x8c, 0x17, 0x61, 0xcb, 0xff, 0x3c, 0xba, 0x9c, 0x83, 0x4e, 0x13, + 0x97, 0xff, 0xfe, 0x71, 0x5e, 0xb3, 0x8c, 0x0f, 0x99, 0x18, 0x21, 0xce, + 0x7c, 0x72, 0x80, 0x8c, 0xf1, 0x25, 0xfc, 0xfe, 0xff, 0x4a, 0x35, 0x3c, + 0x6a, 0x73, 0x97, 0xf6, 0xf6, 0x98, 0x20, 0x39, 0x7b, 0x58, 0xd6, 0x72, + 0xff, 0xd0, 0xda, 0x93, 0xef, 0x19, 0x0d, 0x67, 0x2b, 0x48, 0x8f, 0x61, + 0x67, 0x87, 0xea, 0x11, 0xe9, 0x90, 0xc4, 0xbf, 0xfe, 0x49, 0x86, 0x3d, + 0xbf, 0x72, 0xb4, 0x19, 0xce, 0x5f, 0xff, 0xfe, 0x41, 0x02, 0x83, 0x9a, + 0xd6, 0x37, 0x8d, 0x78, 0x30, 0x06, 0x3c, 0x8e, 0x5f, 0xff, 0xde, 0xdf, + 0xe1, 0xea, 0x64, 0xce, 0x8d, 0x69, 0xcc, 0x8e, 0x5f, 0xff, 0xc3, 0x80, + 0x71, 0x06, 0xb5, 0x8d, 0xe0, 0x1f, 0x93, 0x94, 0x28, 0xba, 0xf3, 0x05, + 0xf9, 0x3d, 0x3e, 0x36, 0x72, 0xff, 0xa1, 0x7d, 0x1f, 0xfd, 0x1b, 0x39, + 0x7f, 0xf2, 0x70, 0x42, 0xe1, 0x98, 0x17, 0x61, 0xcb, 0xff, 0xf7, 0xbb, + 0x92, 0xf8, 0xbe, 0xa7, 0xb9, 0x5a, 0x68, 0xe5, 0x49, 0x52, 0xa2, 0x46, + 0x65, 0xa2, 0x26, 0x14, 0xf4, 0xe4, 0x51, 0x6f, 0xfc, 0xb5, 0xfe, 0xd7, + 0xb4, 0x6f, 0x34, 0x72, 0xff, 0xff, 0xc9, 0xef, 0xf4, 0xfb, 0x5f, 0x52, + 0x61, 0x76, 0xfd, 0x9d, 0x61, 0xca, 0x44, 0x59, 0x3a, 0x25, 0xff, 0x32, + 0x35, 0xc7, 0x35, 0x13, 0x1c, 0xbf, 0xf6, 0x96, 0xc8, 0xe7, 0x79, 0xc7, + 0x0e, 0x5c, 0xed, 0x67, 0x2f, 0xf0, 0x81, 0xa6, 0x07, 0x18, 0x72, 0xfe, + 0x1f, 0x8d, 0x33, 0x50, 0x72, 0xa1, 0x17, 0xd3, 0xa0, 0xe0, 0xcb, 0x9a, + 0x5f, 0xe7, 0x07, 0xcc, 0x0b, 0xc8, 0xe5, 0xff, 0xb3, 0xae, 0x06, 0x3c, + 0x9f, 0x67, 0x2b, 0x0f, 0xc7, 0xa6, 0x97, 0xff, 0x9e, 0x7e, 0xa4, 0x0e, + 0x4c, 0x9a, 0x43, 0x94, 0x15, 0xde, 0x3c, 0x95, 0x4b, 0xd8, 0xc3, 0xc0, + 0x43, 0xb8, 0x7c, 0xfa, 0x15, 0x8d, 0x90, 0xdf, 0x87, 0x3a, 0xfe, 0x39, + 0x7f, 0xe9, 0x40, 0xce, 0xa6, 0x87, 0xf9, 0x1c, 0xbf, 0x85, 0xc2, 0x0e, + 0x40, 0x72, 0x9a, 0xd1, 0x2b, 0x31, 0x36, 0xd0, 0x6f, 0xbd, 0x3e, 0x04, + 0xe5, 0xff, 0x22, 0xaa, 0x68, 0x0c, 0x4d, 0x9c, 0xa9, 0x8f, 0x79, 0xa1, + 0x1d, 0xe6, 0xdb, 0x6c, 0xe5, 0xff, 0xfb, 0x19, 0xe1, 0x80, 0x60, 0x77, + 0x8c, 0x85, 0x94, 0xfa, 0x68, 0x2f, 0xfd, 0x9c, 0xfc, 0x1c, 0xe3, 0xa4, + 0xd9, 0xcb, 0xf9, 0x7d, 0x48, 0x15, 0x9c, 0xa8, 0x3e, 0xec, 0x42, 0xbf, + 0xda, 0x8f, 0x22, 0xd0, 0x27, 0x2f, 0xd2, 0x9b, 0x31, 0x67, 0x2d, 0xa3, + 0x94, 0xd4, 0x9f, 0x5c, 0x19, 0x28, 0x51, 0x58, 0xa9, 0xa5, 0x21, 0x25, + 0xd4, 0x51, 0x86, 0x9e, 0xe1, 0x17, 0x7b, 0xd2, 0xe9, 0xcb, 0x21, 0xcb, + 0xfb, 0xb1, 0xf1, 0x69, 0x39, 0xcb, 0xff, 0xd3, 0x75, 0xd9, 0x9a, 0x55, + 0x5f, 0xc7, 0xc7, 0x2f, 0xed, 0x3e, 0x86, 0x24, 0x72, 0xff, 0xf9, 0xfd, + 0xdc, 0xe3, 0xd4, 0xf9, 0xbd, 0xa3, 0x0e, 0x5f, 0xf9, 0x24, 0x9a, 0xe6, + 0x06, 0x36, 0x72, 0xb8, 0x5d, 0x34, 0xa0, 0x88, 0x61, 0x86, 0x93, 0x84, + 0xb3, 0xca, 0x77, 0x4b, 0xeb, 0x56, 0xde, 0xe4, 0xf0, 0xcd, 0x91, 0x0b, + 0x59, 0xcc, 0x25, 0x0d, 0xa0, 0xc6, 0x01, 0x93, 0x92, 0x8a, 0xc2, 0x1d, + 0x71, 0xc7, 0x73, 0x1c, 0x9a, 0x18, 0x4d, 0x19, 0x76, 0xa3, 0x8f, 0xec, + 0x64, 0x2f, 0x09, 0xa0, 0x43, 0xd4, 0x63, 0x24, 0xdc, 0xf0, 0x4f, 0xa5, + 0xbe, 0x34, 0x58, 0x52, 0x36, 0x7b, 0xff, 0xda, 0xc6, 0xc3, 0xdc, 0x98, + 0x73, 0x52, 0x39, 0x7b, 0x58, 0xd6, 0x72, 0xff, 0xd0, 0xda, 0x93, 0xef, + 0x19, 0x0d, 0x67, 0x2b, 0x48, 0xae, 0x62, 0x5f, 0x87, 0xef, 0xff, 0x9d, + 0x91, 0xa5, 0xeb, 0xf5, 0x75, 0xfb, 0xec, 0xe5, 0x62, 0x20, 0xff, 0x30, + 0xbf, 0xda, 0x5f, 0xee, 0x16, 0x41, 0xcb, 0xff, 0xa3, 0x4a, 0x79, 0x3d, + 0xdc, 0x0a, 0x1c, 0xbf, 0xc3, 0xc8, 0x33, 0x6e, 0xd6, 0x72, 0xff, 0x86, + 0x27, 0x53, 0xbd, 0x76, 0xb3, 0x95, 0x87, 0xe7, 0xd3, 0x6a, 0x84, 0xc3, + 0x27, 0x34, 0xc8, 0x5b, 0xde, 0x6a, 0x2d, 0x4c, 0x8e, 0x5e, 0x7d, 0x4e, + 0x72, 0xe6, 0xdb, 0x39, 0x79, 0xd7, 0xf5, 0x66, 0xd9, 0xb1, 0xdb, 0xfa, + 0x34, 0xf2, 0x4e, 0x9c, 0xbf, 0x63, 0x3a, 0xe1, 0x39, 0x6f, 0xb0, 0xea, + 0x8e, 0x02, 0x9b, 0x91, 0xe6, 0x2a, 0x54, 0xb9, 0xc2, 0x29, 0x8a, 0xf5, + 0x0a, 0xa7, 0xaf, 0x7a, 0x86, 0x56, 0x56, 0xe3, 0x2f, 0xf1, 0xaf, 0x15, + 0xe6, 0xcd, 0x78, 0x0b, 0x2a, 0x4f, 0x84, 0x6e, 0x1a, 0x44, 0x4f, 0x31, + 0xb5, 0x68, 0xa9, 0x90, 0x8f, 0xec, 0xa4, 0x20, 0x43, 0x70, 0x4e, 0x37, + 0x3a, 0x8f, 0xe9, 0x63, 0x7f, 0xda, 0xad, 0x8b, 0xfb, 0x71, 0x34, 0x92, + 0x63, 0x97, 0xfd, 0xe8, 0x14, 0x06, 0x73, 0xe3, 0x97, 0xcd, 0x1c, 0x40, + 0x72, 0xe8, 0x9f, 0x0f, 0x6d, 0x43, 0x8a, 0xda, 0x2e, 0x14, 0x84, 0x55, + 0xff, 0x22, 0xd0, 0x3f, 0x7b, 0x00, 0x39, 0x5f, 0x4f, 0x8f, 0xc5, 0x37, + 0xfe, 0x75, 0xfd, 0xfc, 0x09, 0x2c, 0x91, 0xcb, 0xf6, 0x96, 0xee, 0xb3, + 0x44, 0x6a, 0xbc, 0xaf, 0x3b, 0x39, 0x6f, 0xb3, 0xa2, 0x53, 0x10, 0x7c, + 0x69, 0x7f, 0xff, 0xb8, 0xc0, 0xfb, 0xeb, 0xf1, 0x70, 0xe0, 0x5d, 0x8e, + 0x13, 0x97, 0xed, 0x2d, 0xdd, 0x66, 0x8a, 0x95, 0x73, 0xac, 0xd1, 0x0d, + 0x2d, 0xf7, 0x0f, 0x5d, 0xcd, 0x2f, 0xda, 0x5b, 0xba, 0xcd, 0x11, 0xf2, + 0xff, 0xef, 0xf4, 0x05, 0xf5, 0x26, 0x18, 0x01, 0xcb, 0xff, 0xe1, 0x7f, + 0x4a, 0x15, 0xf9, 0x1e, 0xdc, 0x00, 0xe5, 0xe7, 0x97, 0xdc, 0x46, 0x5e, + 0xcd, 0x14, 0x46, 0xbf, 0xf3, 0xcf, 0x1d, 0x4d, 0x24, 0x30, 0xe5, 0xfe, + 0x8d, 0x60, 0xfb, 0x3a, 0x72, 0xf3, 0x33, 0xeb, 0x43, 0xee, 0x50, 0xf6, + 0xbe, 0xa3, 0xa6, 0x21, 0x63, 0x7f, 0xff, 0xd2, 0xff, 0x4a, 0xbe, 0xf0, + 0x31, 0xce, 0xd4, 0xf2, 0xa8, 0xa9, 0xcb, 0xcd, 0xaa, 0xb3, 0x97, 0xee, + 0x79, 0x96, 0x78, 0xe5, 0x6c, 0xf2, 0x7f, 0x1f, 0xbf, 0xfd, 0xc2, 0x95, + 0x6d, 0xae, 0x70, 0xf0, 0xdf, 0x3e, 0x75, 0xa1, 0xcb, 0xf6, 0x96, 0xee, + 0xb3, 0x45, 0x8e, 0xbf, 0xd8, 0x83, 0x3f, 0xb3, 0xa7, 0x2e, 0x7d, 0x9c, + 0xbf, 0xa7, 0x53, 0x5a, 0xcd, 0x1c, 0xa9, 0x1e, 0x33, 0x8b, 0x5f, 0xf0, + 0xba, 0xbd, 0x48, 0x19, 0xce, 0x5f, 0xff, 0xdf, 0x8b, 0xab, 0xf3, 0xca, + 0xc0, 0xcb, 0x3a, 0x8c, 0x39, 0x7f, 0xfe, 0x04, 0xa7, 0xe1, 0x50, 0xd5, + 0xce, 0xbd, 0x7c, 0xf9, 0xd6, 0x87, 0x2e, 0x49, 0x1c, 0xbf, 0xde, 0x1c, + 0xe3, 0xd7, 0x91, 0xca, 0x09, 0xe5, 0x60, 0xb5, 0xf9, 0x3d, 0xe4, 0xf1, + 0xcb, 0xff, 0xf7, 0xe2, 0xea, 0xf9, 0x58, 0x19, 0x67, 0x51, 0x87, 0x2f, + 0xb5, 0xac, 0x68, 0x72, 0xb1, 0x14, 0x2c, 0x27, 0x75, 0x6b, 0xf6, 0x6b, + 0x32, 0x63, 0x96, 0xfb, 0x0b, 0x8d, 0x93, 0xc2, 0xda, 0x44, 0x78, 0xc8, + 0xa9, 0xa2, 0x3c, 0x4c, 0x42, 0xc3, 0x8e, 0xaf, 0x0c, 0x2d, 0x77, 0x0c, + 0x25, 0x0b, 0xaf, 0x95, 0x4d, 0x4c, 0x72, 0xf7, 0x0a, 0x62, 0xa7, 0x2f, + 0xee, 0x10, 0x73, 0xaf, 0xe3, 0x97, 0xf9, 0xc1, 0xb7, 0xf7, 0x9c, 0xe5, + 0xcc, 0x59, 0xca, 0x13, 0xc9, 0xf1, 0x95, 0xff, 0xb1, 0xbd, 0x60, 0xbf, + 0x32, 0xd9, 0xcb, 0xf7, 0x5d, 0x90, 0x27, 0x2f, 0xb7, 0xd4, 0x6c, 0xe5, + 0xfa, 0x1b, 0xf6, 0x74, 0xe5, 0xe8, 0x53, 0x0e, 0x57, 0xc4, 0x46, 0xe1, + 0x30, 0x91, 0xec, 0xa2, 0xf8, 0x0c, 0x4d, 0x1c, 0xbd, 0x8e, 0x27, 0x2f, + 0x76, 0x26, 0x39, 0x72, 0x79, 0x0d, 0xbb, 0x8d, 0x5f, 0xff, 0xf4, 0x68, + 0x70, 0x39, 0xde, 0xa2, 0xfa, 0x9e, 0xdb, 0xf2, 0x72, 0xff, 0xfd, 0x93, + 0x67, 0x00, 0xe7, 0x11, 0xc0, 0x32, 0x24, 0x72, 0xff, 0x9f, 0x91, 0xcf, + 0x6f, 0x1b, 0x39, 0x48, 0x9b, 0xcb, 0x5a, 0xcf, 0x4a, 0x85, 0x97, 0xf5, + 0x8b, 0xf7, 0x53, 0x5f, 0xc8, 0xe5, 0xfd, 0x1a, 0x03, 0x4f, 0xfc, 0x72, + 0xff, 0xa0, 0x7d, 0xc3, 0x3f, 0xbf, 0x83, 0x97, 0xff, 0xa3, 0xb0, 0xc5, + 0xf5, 0x3d, 0x98, 0xc3, 0x97, 0xc0, 0x02, 0x28, 0x72, 0xfd, 0x2d, 0xcf, + 0x8d, 0x9c, 0xbc, 0xee, 0xb3, 0x45, 0xa0, 0xbf, 0xf3, 0xb7, 0xc0, 0xb7, + 0xd4, 0xf8, 0xd9, 0xcb, 0xf8, 0x10, 0x31, 0xed, 0x9c, 0xa8, 0x46, 0x12, + 0xca, 0xb4, 0x50, 0x04, 0x4b, 0xff, 0xff, 0xe4, 0xd7, 0x5c, 0x52, 0x3c, + 0x9d, 0x8d, 0xf7, 0x37, 0xac, 0x5e, 0x78, 0xe5, 0xff, 0xff, 0xef, 0xf6, + 0xfa, 0x96, 0xd0, 0x39, 0xa9, 0xd3, 0x7d, 0x70, 0x6f, 0x04, 0xe5, 0xfd, + 0x13, 0xb1, 0xdc, 0x4e, 0x5f, 0xff, 0xbb, 0x8d, 0xf9, 0x91, 0x9e, 0xee, + 0x60, 0xac, 0xe5, 0xff, 0xf9, 0x3d, 0x2c, 0xd6, 0x9e, 0x4a, 0x0b, 0xfb, + 0x67, 0x2a, 0x15, 0xe3, 0x48, 0xa4, 0x26, 0x2b, 0x3d, 0x44, 0x8d, 0x43, + 0x97, 0xa7, 0x82, 0xf3, 0xb7, 0x8f, 0x16, 0x71, 0x54, 0xbb, 0x18, 0x72, + 0xff, 0xe7, 0xe7, 0x8f, 0x5a, 0xd3, 0xc3, 0x0c, 0x39, 0x5a, 0x3d, 0xf7, + 0x16, 0xbf, 0xff, 0x27, 0xb6, 0xfc, 0xef, 0x79, 0xd4, 0xdf, 0xf3, 0x9c, + 0xbf, 0xfe, 0xfe, 0x7d, 0x27, 0xa7, 0xff, 0x52, 0xdb, 0x5a, 0x1c, 0xae, + 0xa2, 0xc0, 0x56, 0x2f, 0xed, 0xba, 0x99, 0xcf, 0x8e, 0x5f, 0xe4, 0x0e, + 0x33, 0xe6, 0x04, 0xe5, 0xff, 0xf7, 0xfa, 0xd4, 0x0e, 0x2a, 0x9d, 0xee, + 0x28, 0x72, 0xdc, 0x39, 0xca, 0xd1, 0xf3, 0xfe, 0xa3, 0x7f, 0x99, 0xf8, + 0xfb, 0x7f, 0xe8, 0xe5, 0x49, 0x1e, 0x9a, 0x84, 0xdb, 0x42, 0x3b, 0xf9, + 0xda, 0xf0, 0x58, 0x87, 0x2f, 0xfe, 0x76, 0xfd, 0x9d, 0xdc, 0xd9, 0x93, + 0x9c, 0xbf, 0x4d, 0xdc, 0x03, 0x9c, 0xae, 0xa2, 0x70, 0x4b, 0xb8, 0xa3, + 0x5f, 0xff, 0xec, 0xcf, 0x6e, 0x26, 0xec, 0x71, 0x1c, 0x0f, 0x63, 0x67, + 0x2f, 0xc2, 0xb7, 0xda, 0x1c, 0xbf, 0xff, 0xb4, 0x31, 0x1c, 0xfc, 0xdf, + 0x86, 0x03, 0xd8, 0xf1, 0xcb, 0x93, 0xa7, 0x2f, 0xa4, 0x2e, 0xa1, 0xcb, + 0xfc, 0x17, 0x06, 0xb4, 0xe0, 0x39, 0x7d, 0xa5, 0xb5, 0xb6, 0x72, 0xf9, + 0x5e, 0x11, 0xdb, 0x39, 0x58, 0x7a, 0x0e, 0x4f, 0x48, 0x8a, 0x31, 0x84, + 0x1d, 0x42, 0x70, 0x78, 0x4c, 0xd6, 0xb8, 0xe2, 0xdf, 0xc3, 0x16, 0xf3, + 0xb5, 0xa1, 0xcb, 0xff, 0x29, 0xe5, 0x51, 0x58, 0xc1, 0x83, 0x97, 0xe5, + 0x3c, 0x30, 0x03, 0x95, 0xca, 0x21, 0x74, 0x3d, 0xc4, 0xfe, 0xfd, 0x1e, + 0xce, 0xc1, 0xcb, 0xff, 0x67, 0x32, 0xda, 0x79, 0xc7, 0x0e, 0x5f, 0xec, + 0x67, 0x72, 0x67, 0x98, 0xe5, 0xff, 0xba, 0x81, 0xc4, 0x9f, 0xb1, 0x1f, + 0x0f, 0xc7, 0xc7, 0xb7, 0xfe, 0xce, 0x65, 0xb9, 0xb4, 0xfe, 0xd9, 0xcb, + 0xf0, 0xc2, 0xe4, 0xc3, 0x97, 0xff, 0x6f, 0x26, 0xec, 0x71, 0xce, 0xf6, + 0x0e, 0x50, 0x4f, 0xb7, 0xc4, 0xf7, 0xf9, 0xc1, 0xb6, 0x3f, 0x3e, 0x39, + 0x58, 0x7a, 0xce, 0x45, 0x7f, 0xa2, 0x26, 0xce, 0x29, 0xa3, 0x97, 0xc9, + 0xac, 0x13, 0x94, 0x27, 0xa9, 0xb3, 0x4a, 0x9d, 0x54, 0x32, 0xe1, 0x2e, + 0x05, 0x61, 0x8c, 0x13, 0xce, 0x97, 0xef, 0x93, 0x49, 0x26, 0x39, 0x50, + 0xac, 0xf3, 0x25, 0x5c, 0xa2, 0xbd, 0xff, 0xdd, 0x4f, 0x98, 0x38, 0x9a, + 0x7e, 0x27, 0x2f, 0xfe, 0x41, 0x70, 0x8e, 0x07, 0xb1, 0xb3, 0x97, 0x94, + 0x8d, 0x1c, 0xbf, 0xff, 0xdd, 0x81, 0xc0, 0x6f, 0x03, 0xd8, 0x9d, 0x9f, + 0x88, 0x4e, 0x5f, 0x93, 0xde, 0x89, 0x1c, 0xa5, 0x53, 0x2b, 0x5a, 0x2e, + 0x90, 0x7c, 0x3b, 0xc5, 0x86, 0xff, 0xfe, 0x89, 0xb0, 0x3d, 0x8e, 0x3d, + 0xcf, 0x0c, 0x43, 0x0e, 0x5f, 0xdc, 0xed, 0x49, 0xff, 0x13, 0x97, 0xfd, + 0x0b, 0xea, 0x4c, 0xef, 0x39, 0xca, 0x62, 0x31, 0x9d, 0x6c, 0x06, 0x57, + 0xfa, 0x51, 0xa9, 0xe3, 0x53, 0x9c, 0xbf, 0xf2, 0x71, 0x71, 0x07, 0x70, + 0x0e, 0x72, 0xfe, 0x19, 0xdf, 0xa8, 0x27, 0x2f, 0xf9, 0x3f, 0x19, 0x6a, + 0x30, 0x27, 0x2f, 0xff, 0xfb, 0xb9, 0x25, 0xf5, 0x3b, 0x19, 0xa9, 0x78, + 0x61, 0x9b, 0x39, 0x7d, 0xfc, 0x72, 0x13, 0x94, 0x14, 0xca, 0xdc, 0xfb, + 0x65, 0x9e, 0x38, 0x6d, 0x96, 0xfb, 0x82, 0x35, 0x39, 0xca, 0x84, 0xf4, + 0x72, 0x36, 0x07, 0x4b, 0xbf, 0xda, 0x5c, 0xd8, 0x9d, 0xfc, 0xe5, 0xff, + 0x93, 0x88, 0xe6, 0xfc, 0xaa, 0x2c, 0xe5, 0xfe, 0xf7, 0x5a, 0xd3, 0xaf, + 0x31, 0xcb, 0xfa, 0x16, 0x2f, 0xcf, 0x8e, 0x54, 0x91, 0x48, 0xd6, 0x80, + 0xc3, 0x7b, 0xf4, 0x7a, 0x7c, 0x6c, 0xe5, 0xff, 0xb9, 0x58, 0xbc, 0xef, + 0x24, 0xe9, 0xca, 0xd1, 0xf4, 0x7e, 0x53, 0x79, 0xc4, 0x07, 0x2f, 0xff, + 0xff, 0x93, 0xfd, 0x77, 0x26, 0x99, 0xf5, 0x37, 0xbb, 0xf8, 0x37, 0x89, + 0xc4, 0x30, 0x72, 0xfd, 0xee, 0xb8, 0xaa, 0x72, 0xff, 0x87, 0xf9, 0xc3, + 0xdc, 0x18, 0x39, 0x6c, 0x0a, 0x39, 0x72, 0x10, 0x8b, 0x28, 0xbf, 0xf8, + 0x0b, 0x00, 0xe7, 0xb6, 0xee, 0x27, 0x2f, 0x31, 0xf9, 0x39, 0x5a, 0x3d, + 0xf0, 0x21, 0x54, 0x2b, 0x51, 0xc8, 0x6c, 0xa4, 0x26, 0xdc, 0x8c, 0x63, + 0x00, 0xfe, 0x13, 0x17, 0xfb, 0x3b, 0x32, 0x75, 0x18, 0x72, 0xff, 0x4b, + 0x35, 0xb1, 0x89, 0xce, 0x5e, 0x69, 0x93, 0x9c, 0xbf, 0xe8, 0x18, 0x5e, + 0x92, 0x18, 0x72, 0xf6, 0x75, 0xce, 0x5f, 0xa6, 0x0f, 0xff, 0x89, 0xca, + 0x09, 0xe3, 0x38, 0xdd, 0xe6, 0xb4, 0x61, 0xcb, 0xff, 0xf3, 0xb8, 0x37, + 0x00, 0xf6, 0x20, 0x70, 0x66, 0x39, 0xd2, 0xfe, 0xfe, 0x6f, 0x16, 0xbc, + 0x6c, 0xe5, 0xe8, 0x5f, 0x13, 0x95, 0x87, 0x9b, 0xe2, 0xfb, 0xfe, 0xe5, + 0x99, 0x83, 0xe6, 0x98, 0x72, 0xf2, 0xb2, 0xfc, 0xe5, 0xfb, 0xb1, 0xa9, + 0xd8, 0x72, 0xff, 0x7e, 0xe3, 0xdc, 0x79, 0x8e, 0x5b, 0x99, 0x8f, 0x71, + 0xb2, 0x9a, 0x44, 0x53, 0x3b, 0xdd, 0x62, 0x64, 0x4e, 0x42, 0x30, 0xe0, + 0xac, 0x56, 0x8b, 0xc9, 0x9a, 0x19, 0xf4, 0x7d, 0xdf, 0x05, 0x03, 0x71, + 0xe8, 0xde, 0x1c, 0x01, 0xcb, 0x41, 0xca, 0x01, 0xab, 0xf0, 0xdd, 0xcf, + 0xe3, 0x95, 0xa3, 0x6f, 0xd2, 0x1b, 0xe6, 0x46, 0xb6, 0x72, 0xff, 0xb5, + 0x9d, 0xc9, 0xfe, 0x26, 0xce, 0x56, 0x1f, 0xf2, 0x10, 0xfe, 0x45, 0x7f, + 0x20, 0xff, 0x2c, 0xd9, 0xcb, 0xff, 0x67, 0xa3, 0x90, 0x3f, 0x7a, 0x87, + 0x2c, 0xc3, 0x97, 0xf2, 0x0f, 0xf2, 0xcd, 0xfc, 0x3c, 0xfe, 0x27, 0xd4, + 0xaa, 0x31, 0x3c, 0xf9, 0x6f, 0xad, 0x4b, 0x7f, 0x1a, 0xd5, 0x92, 0x70, + 0xc4, 0x90, 0xf5, 0x39, 0x0c, 0xa1, 0x98, 0x18, 0xed, 0xb2, 0x70, 0x4d, + 0x58, 0x7e, 0xae, 0x1a, 0x3c, 0x91, 0x24, 0x64, 0x73, 0x43, 0x4f, 0x46, + 0x2c, 0x8f, 0x93, 0xb3, 0x82, 0x4f, 0x1b, 0x08, 0x23, 0x14, 0x19, 0x40, + 0x1b, 0x97, 0x0b, 0xe9, 0x75, 0xed, 0x23, 0x49, 0x52, 0x1e, 0x57, 0xf7, + 0x02, 0x04, 0x62, 0x63, 0x97, 0xa1, 0xc4, 0xe5, 0xf6, 0x75, 0xfc, 0x72, + 0xdc, 0x26, 0x1f, 0x5f, 0x4c, 0x04, 0x6a, 0xff, 0xff, 0xf7, 0x5c, 0x7d, + 0xb8, 0x49, 0x67, 0x00, 0xfa, 0x3b, 0x0a, 0xff, 0x1c, 0x07, 0x2f, 0xb3, + 0x60, 0x43, 0x97, 0xed, 0x2d, 0xdd, 0x66, 0x8b, 0x59, 0x7f, 0x98, 0x8c, + 0x79, 0xb3, 0xa7, 0x2f, 0xec, 0xe0, 0xdb, 0x8a, 0xce, 0x5e, 0xd4, 0x30, + 0xe5, 0xfd, 0xdc, 0xdc, 0x4f, 0xc0, 0x72, 0xff, 0xa5, 0xf7, 0x34, 0xb7, + 0x75, 0x9a, 0x28, 0x35, 0x61, 0xfc, 0x39, 0x8d, 0xf6, 0x4d, 0x1e, 0x39, + 0x7f, 0xd1, 0x28, 0xd4, 0xf1, 0xa9, 0xce, 0x5f, 0x2b, 0xec, 0xe9, 0xcb, + 0xfc, 0x91, 0x30, 0x1c, 0x66, 0x39, 0x7f, 0xfd, 0xb4, 0x9d, 0xf6, 0xe2, + 0xfe, 0xec, 0x4c, 0x72, 0xff, 0xce, 0x20, 0xcf, 0x40, 0xa0, 0x0e, 0x57, + 0x91, 0x14, 0xd1, 0x3e, 0xdf, 0x78, 0x65, 0x70, 0x10, 0x71, 0x27, 0xcc, + 0x21, 0x43, 0x49, 0x8c, 0xf4, 0x5e, 0xc8, 0x4a, 0x74, 0x80, 0x48, 0xb6, + 0x75, 0xe2, 0x35, 0x21, 0x7b, 0x7f, 0xfb, 0xeb, 0x1e, 0x5f, 0x73, 0x4b, + 0x77, 0x59, 0xa2, 0x8b, 0x5f, 0xef, 0xb9, 0xa5, 0xbb, 0xac, 0xd1, 0x75, + 0x2a, 0x1d, 0x7b, 0x5c, 0xa1, 0x71, 0x87, 0x0b, 0x85, 0xda, 0x47, 0xb8, + 0xc9, 0xc9, 0x5e, 0xda, 0x04, 0xc0, 0x4e, 0xcf, 0xee, 0x19, 0x3e, 0x5a, + 0xbf, 0x69, 0x6e, 0xeb, 0x34, 0x44, 0x2b, 0xdd, 0x41, 0x39, 0x76, 0x04, + 0xe5, 0x96, 0x72, 0x96, 0x78, 0x5d, 0x1b, 0x11, 0x6b, 0xec, 0xe2, 0x9a, + 0x39, 0x7c, 0x9a, 0xce, 0x4e, 0x56, 0x23, 0xa7, 0x97, 0x66, 0xb2, 0xe6, + 0x84, 0x77, 0xfb, 0xdf, 0x66, 0x18, 0x06, 0xce, 0x57, 0xd3, 0xf8, 0xc4, + 0x2b, 0x34, 0x39, 0x7d, 0x1d, 0x86, 0x1c, 0xbe, 0x5b, 0xba, 0xcd, 0x11, + 0xb2, 0x96, 0x79, 0xfa, 0x21, 0xb7, 0xd0, 0xa2, 0x13, 0x18, 0xaf, 0xf7, + 0xdc, 0xd2, 0xdd, 0xd6, 0x68, 0xa6, 0xd7, 0xed, 0x2d, 0xdd, 0x66, 0x8a, + 0x81, 0x7b, 0x39, 0x6c, 0xe5, 0xbe, 0xe1, 0xe9, 0x74, 0xd2, 0xff, 0x7d, + 0xcd, 0x2d, 0xdd, 0x66, 0x8a, 0x99, 0x7e, 0xd2, 0xdd, 0xd6, 0x68, 0xac, + 0x17, 0xe4, 0x6c, 0x3f, 0xe8, 0xe5, 0xe0, 0x29, 0x23, 0x97, 0x6c, 0x4e, + 0x5c, 0xcd, 0x9c, 0xbf, 0x91, 0xa3, 0xc2, 0x34, 0x39, 0x7f, 0xbe, 0xe6, + 0x96, 0xee, 0xb3, 0x44, 0x7e, 0xbc, 0x30, 0x13, 0x95, 0x08, 0x8b, 0x91, + 0x7a, 0x20, 0xda, 0x0e, 0x5d, 0x13, 0x9c, 0xa9, 0x1a, 0x7c, 0x10, 0xbf, + 0xb9, 0x93, 0xc9, 0x04, 0xe5, 0xe8, 0x19, 0x8e, 0x56, 0x1e, 0x4a, 0xa5, + 0xb7, 0x3f, 0x8e, 0x5d, 0xef, 0x1c, 0xb7, 0xdc, 0x54, 0x82, 0xb3, 0x4e, + 0x4a, 0x90, 0x79, 0x82, 0xcf, 0x0a, 0x21, 0x55, 0xf3, 0x4b, 0x42, 0x2e, + 0x01, 0x6b, 0xff, 0xdf, 0x58, 0xf2, 0xfb, 0x9a, 0x5b, 0xba, 0xcd, 0x13, + 0x7a, 0xff, 0xe6, 0x3c, 0xbe, 0xe6, 0x96, 0xee, 0xb3, 0x44, 0xfc, 0xbd, + 0xc2, 0xef, 0x23, 0x97, 0x96, 0xa3, 0x0e, 0x5f, 0xb5, 0x1d, 0xfe, 0x0e, + 0x5f, 0xbb, 0x9e, 0x80, 0x9c, 0xae, 0x10, 0xfb, 0x50, 0x79, 0xca, 0x2e, + 0x15, 0x9c, 0xbe, 0xdc, 0xcc, 0xd9, 0xcb, 0x96, 0xb3, 0x97, 0xf9, 0x7d, + 0x4f, 0x66, 0x30, 0xe5, 0xdc, 0x56, 0x78, 0xc0, 0x95, 0x08, 0xa9, 0x41, + 0x60, 0x12, 0x6c, 0x5f, 0xc6, 0x57, 0xe6, 0xab, 0x84, 0x69, 0x9c, 0x9c, + 0xbf, 0x9a, 0x97, 0x9f, 0xa8, 0xd6, 0x72, 0xfc, 0xd5, 0xaa, 0xae, 0x35, + 0x9c, 0xbf, 0xbc, 0x82, 0xde, 0x09, 0xcb, 0xb8, 0xac, 0xf1, 0x80, 0xad, + 0xd3, 0x94, 0xd4, 0xa6, 0x01, 0xc2, 0x1a, 0xf0, 0xb1, 0xb6, 0x19, 0x78, + 0xb3, 0xf2, 0x6b, 0xda, 0x7c, 0x39, 0x7c, 0xe1, 0xc6, 0x1c, 0xa6, 0xac, + 0xde, 0x35, 0x11, 0xbb, 0xee, 0x1a, 0x76, 0x6c, 0xe5, 0xff, 0xf8, 0x5f, + 0xd0, 0x2b, 0x46, 0x07, 0xf7, 0xd4, 0x8e, 0x5f, 0x9b, 0xf7, 0xa1, 0x87, + 0x29, 0xab, 0x3f, 0xd9, 0xd5, 0x2f, 0xf9, 0xfa, 0x9c, 0x7e, 0xb6, 0xdb, + 0x65, 0x2f, 0xf7, 0x5f, 0xde, 0x77, 0x6c, 0xe5, 0x70, 0xc9, 0xa0, 0xb5, + 0x18, 0x53, 0x35, 0x02, 0x8e, 0x16, 0x40, 0xbf, 0xff, 0xcd, 0x57, 0x09, + 0xbd, 0x42, 0x7b, 0xb8, 0x14, 0xde, 0x08, 0x0e, 0x5f, 0xcd, 0x71, 0xa7, + 0x79, 0x1c, 0xbf, 0x75, 0x1c, 0x1c, 0x2c, 0x72, 0x9a, 0x94, 0x63, 0x70, + 0xa6, 0x9f, 0x17, 0xdf, 0xf9, 0xab, 0x6a, 0x66, 0x18, 0x0e, 0x73, 0xe3, + 0x94, 0x72, 0x9a, 0xb3, 0xd5, 0x74, 0xab, 0xe1, 0xc4, 0x01, 0xcb, 0xee, + 0x17, 0x02, 0xb0, 0x72, 0xb8, 0x43, 0xca, 0xe1, 0x88, 0x2f, 0xfd, 0x11, + 0x11, 0x11, 0x1c, 0xec, 0xe5, 0xe9, 0xa3, 0xc7, 0x2e, 0x88, 0x83, 0xd8, + 0x98, 0xee, 0xf2, 0x73, 0x87, 0x2f, 0xda, 0x49, 0xdd, 0x85, 0x2e, 0x6d, + 0xb2, 0x95, 0x87, 0x82, 0xd9, 0x45, 0xbf, 0x29, 0xf4, 0xd1, 0x5e, 0xee, + 0x2c, 0xe5, 0x42, 0x3a, 0xc0, 0x59, 0xb7, 0xf5, 0x09, 0x2f, 0xdf, 0xb4, + 0x8f, 0xf9, 0x39, 0x7c, 0xe3, 0x1c, 0x07, 0x2b, 0x0f, 0x41, 0xcb, 0x6f, + 0xfe, 0x1c, 0x64, 0x6f, 0x79, 0x26, 0x98, 0x72, 0xff, 0xcf, 0xe5, 0xf5, + 0x04, 0x63, 0x93, 0x94, 0x88, 0x81, 0xea, 0x25, 0xfe, 0xc0, 0xa7, 0x1d, + 0x81, 0x67, 0x2f, 0xff, 0xfd, 0x9c, 0x53, 0xd2, 0xc0, 0x6c, 0x70, 0x1a, + 0x89, 0xdf, 0x4b, 0x39, 0x74, 0x49, 0xd1, 0x45, 0xb3, 0x5b, 0xfb, 0xdb, + 0xcc, 0x9e, 0x0e, 0x57, 0x4f, 0x68, 0x4b, 0x6f, 0xb6, 0x1f, 0x7e, 0x72, + 0xff, 0xff, 0xee, 0x31, 0xac, 0x08, 0xbe, 0x95, 0x7f, 0x7f, 0xe4, 0xf6, + 0xfa, 0x87, 0x2f, 0xf6, 0xbf, 0x1f, 0xfd, 0xff, 0x8e, 0x5e, 0xec, 0x09, + 0xcb, 0x42, 0x1e, 0x97, 0x8d, 0xea, 0x13, 0x31, 0x59, 0x0a, 0x12, 0x76, + 0x18, 0xd7, 0x85, 0x20, 0xe5, 0xfa, 0x14, 0x67, 0x50, 0xe5, 0x68, 0xf0, + 0x84, 0x6a, 0xfc, 0xf3, 0xc3, 0xac, 0xe5, 0xfc, 0xa7, 0xc8, 0xdc, 0x30, + 0xe5, 0x74, 0xf5, 0xdc, 0x9e, 0xfe, 0x96, 0xfd, 0x82, 0xa9, 0xcb, 0xff, + 0xa1, 0x79, 0xac, 0xea, 0x6b, 0xae, 0x72, 0xf3, 0x6e, 0xd9, 0xcb, 0xff, + 0xa3, 0x52, 0x5f, 0x52, 0x61, 0x76, 0xce, 0x5f, 0xfd, 0xa7, 0x9c, 0x3d, + 0x8d, 0xfb, 0xfe, 0x9c, 0xad, 0xa2, 0x33, 0xc8, 0xb6, 0x66, 0x93, 0x0f, + 0xea, 0x16, 0xe1, 0x55, 0x7f, 0x91, 0x48, 0x6c, 0x38, 0xc3, 0x95, 0x87, + 0xe1, 0xd3, 0xcb, 0xfe, 0x8e, 0xc7, 0x32, 0x94, 0x4e, 0x72, 0xf9, 0x7d, + 0x4d, 0x1c, 0xad, 0x1e, 0xe3, 0x9d, 0x5f, 0xff, 0xfe, 0x17, 0x55, 0x35, + 0x12, 0xf9, 0xd4, 0x60, 0x63, 0xe3, 0x4f, 0xfa, 0x9a, 0x39, 0x7c, 0xf2, + 0x4e, 0x4e, 0x5f, 0xfb, 0xa9, 0xec, 0xd6, 0xbf, 0x9f, 0x89, 0xcb, 0xfe, + 0x4f, 0x66, 0xb5, 0xfc, 0xfc, 0x4e, 0x5e, 0xdf, 0xe3, 0xf1, 0x10, 0x1d, + 0x43, 0xa0, 0xa7, 0xeb, 0xa7, 0xde, 0x90, 0x8b, 0xf6, 0xe1, 0x45, 0x7c, + 0xc4, 0x0c, 0x1c, 0xbf, 0x93, 0xba, 0xd2, 0x4e, 0x72, 0xa0, 0xf3, 0xfa, + 0x43, 0x73, 0x7e, 0x39, 0x7f, 0xf2, 0x27, 0x66, 0xcf, 0x47, 0xa0, 0x27, + 0x2d, 0x07, 0x2f, 0xff, 0xa3, 0x99, 0x38, 0x83, 0xe0, 0x13, 0x48, 0xa9, + 0xca, 0x84, 0x5e, 0xcc, 0x30, 0xd1, 0x0f, 0x80, 0x42, 0xfb, 0xdb, 0xea, + 0x1c, 0xbe, 0x9d, 0x89, 0x23, 0x97, 0xd0, 0x05, 0x18, 0x72, 0xf8, 0x7f, + 0x79, 0x1c, 0xa5, 0x9e, 0x2e, 0xc8, 0xef, 0xf7, 0x61, 0x9f, 0x40, 0x08, + 0x39, 0x50, 0x8b, 0xfc, 0x68, 0x42, 0x2b, 0xfa, 0x64, 0xef, 0xb1, 0x67, + 0x2b, 0x13, 0x3c, 0xd4, 0x38, 0x5c, 0xb6, 0xff, 0xb9, 0x0a, 0x90, 0xd7, + 0xdf, 0xf6, 0x72, 0xf6, 0xe1, 0xb3, 0x97, 0x3f, 0x4e, 0x5e, 0x56, 0x3c, + 0x72, 0xff, 0xfc, 0x1e, 0xc6, 0x90, 0x10, 0xa4, 0x4c, 0x30, 0xc3, 0x97, + 0xf9, 0x58, 0x1f, 0x6d, 0xfa, 0x72, 0x91, 0x11, 0x0e, 0xab, 0x7e, 0x1c, + 0x71, 0x9c, 0xe5, 0x42, 0x6b, 0xf8, 0x80, 0x83, 0xae, 0x2c, 0x30, 0xa5, + 0xd9, 0x0d, 0xfe, 0xec, 0x4f, 0xa8, 0xc0, 0x9c, 0xbf, 0xfe, 0x1c, 0xe2, + 0xb7, 0xd4, 0xef, 0xe7, 0xe4, 0x07, 0x2a, 0x11, 0x0a, 0xe6, 0x77, 0xf8, + 0x5e, 0x7e, 0x65, 0x1c, 0x07, 0x2f, 0xf6, 0xfa, 0xea, 0x76, 0x24, 0x72, + 0xa7, 0x3e, 0xbe, 0x4d, 0xef, 0x66, 0x4c, 0x72, 0xff, 0xfd, 0x37, 0x61, + 0x89, 0xa4, 0xe0, 0x85, 0x27, 0xc6, 0xce, 0x5f, 0xf9, 0x35, 0x1b, 0x50, + 0x46, 0x34, 0x72, 0xff, 0xa2, 0x42, 0xfe, 0x92, 0x71, 0x39, 0x79, 0x48, + 0x01, 0xca, 0xe9, 0xeb, 0x6c, 0xe6, 0xcd, 0x67, 0x2f, 0x7a, 0x58, 0x72, + 0xed, 0xe1, 0xcb, 0xff, 0xb7, 0x1a, 0x5f, 0x87, 0x27, 0x71, 0x39, 0x50, + 0x9c, 0xcc, 0xeb, 0x79, 0x09, 0x34, 0x22, 0x71, 0x40, 0x0e, 0x78, 0x5a, + 0xef, 0x30, 0xe5, 0xfa, 0x6f, 0xfd, 0x1d, 0x39, 0x50, 0x78, 0x3f, 0x8b, + 0xdf, 0xfa, 0x3c, 0xfb, 0xce, 0xf5, 0x18, 0x72, 0xfc, 0x31, 0x3c, 0x4e, + 0x72, 0x82, 0x7c, 0xb3, 0x1e, 0xdf, 0xc1, 0x87, 0xd0, 0x3f, 0x39, 0x76, + 0x74, 0xe5, 0x4e, 0x78, 0x9c, 0x4b, 0xaf, 0x79, 0x26, 0x39, 0x50, 0x8a, + 0x9c, 0x67, 0xd9, 0x2d, 0xff, 0x69, 0x37, 0xd7, 0x64, 0x35, 0x9c, 0xbf, + 0x43, 0x5a, 0x36, 0xb3, 0x95, 0x0d, 0x93, 0xb4, 0xf0, 0x8d, 0x94, 0x28, + 0x43, 0x29, 0x3f, 0x21, 0x06, 0xb7, 0x8e, 0x48, 0x52, 0x5d, 0x13, 0x5c, + 0x27, 0xa6, 0x86, 0xf6, 0xa3, 0x7e, 0x64, 0x72, 0x7d, 0x86, 0xeb, 0xc2, + 0x30, 0x04, 0x83, 0x1d, 0xae, 0xe1, 0x51, 0xe8, 0xcc, 0x38, 0x97, 0x28, + 0x77, 0x72, 0xbe, 0x39, 0x7f, 0xff, 0xcd, 0x47, 0x86, 0x8c, 0x6a, 0x1a, + 0xe1, 0xb8, 0x57, 0x16, 0xbe, 0x16, 0xff, 0xe7, 0xce, 0xb4, 0x39, 0x7a, + 0x65, 0x18, 0x72, 0xff, 0xb3, 0xdb, 0xcf, 0x77, 0x00, 0x72, 0x9c, 0xf5, + 0xc4, 0x7e, 0xe7, 0x13, 0x95, 0xa3, 0x6a, 0xc2, 0x0b, 0xe8, 0xf6, 0x30, + 0xe5, 0xfb, 0xd0, 0x28, 0x03, 0x97, 0xed, 0x7f, 0xc4, 0x0d, 0x9c, 0xbf, + 0xb1, 0xb7, 0x03, 0x30, 0xe5, 0x7c, 0x45, 0x0e, 0x10, 0xf4, 0x98, 0x4b, + 0x6f, 0xfd, 0x0c, 0x4e, 0x77, 0xfc, 0xdf, 0xaa, 0x72, 0xfe, 0x41, 0xf7, + 0x72, 0x47, 0x2f, 0xf0, 0xc3, 0x6d, 0x33, 0x50, 0x72, 0xcd, 0xfc, 0x45, + 0x24, 0x91, 0x02, 0x59, 0x7e, 0xd4, 0xf1, 0xed, 0x9c, 0xbe, 0x7d, 0x3c, + 0x8e, 0x5b, 0x58, 0x79, 0x42, 0x53, 0x79, 0xb6, 0xdb, 0x39, 0x7d, 0x38, + 0xa4, 0x14, 0xfa, 0x68, 0x2f, 0xf9, 0xaf, 0xae, 0x32, 0x0c, 0x4e, 0x72, + 0xf9, 0xfd, 0x01, 0x39, 0x77, 0x32, 0x39, 0x7f, 0x95, 0x8f, 0x6f, 0xaf, + 0xf9, 0xcb, 0xf2, 0x4f, 0x9c, 0xf8, 0xe5, 0xc8, 0xb3, 0x95, 0x08, 0x8c, + 0x54, 0x61, 0x86, 0xbe, 0x29, 0xbf, 0x2a, 0xfb, 0xe3, 0x23, 0x95, 0xc9, + 0xf4, 0x78, 0xf6, 0xf6, 0x7e, 0xd0, 0xe5, 0x70, 0x8b, 0xad, 0xdc, 0x28, + 0x62, 0x23, 0x24, 0x0c, 0x30, 0xb2, 0x1c, 0x29, 0x08, 0x3e, 0xa3, 0x39, + 0x98, 0x9e, 0x7f, 0x18, 0xab, 0x42, 0x3b, 0xff, 0xb8, 0xb7, 0x9b, 0x14, + 0x8d, 0x64, 0xe7, 0x2f, 0xff, 0xff, 0xfc, 0xd7, 0xf3, 0xb9, 0xcc, 0xba, + 0xcf, 0x8b, 0xef, 0xfe, 0xf6, 0x0f, 0x73, 0xd0, 0x1f, 0x9f, 0x3a, 0xd0, + 0xe5, 0xff, 0x07, 0x3f, 0xe1, 0xd3, 0xae, 0xc3, 0x97, 0xe8, 0x60, 0xe4, + 0xc7, 0x30, 0xdf, 0x5e, 0xe3, 0x81, 0x39, 0x7f, 0x75, 0x20, 0x7f, 0x83, + 0x97, 0xfa, 0x1a, 0xd5, 0xcd, 0xbb, 0x59, 0xca, 0x54, 0xf9, 0x7a, 0x59, + 0x5d, 0x45, 0x33, 0xc2, 0x0e, 0x82, 0x98, 0x1e, 0xe1, 0xb9, 0x7f, 0x44, + 0xbb, 0x1c, 0x50, 0xe5, 0xf9, 0x9f, 0x8c, 0x30, 0xe5, 0x82, 0x72, 0xe7, + 0xd9, 0xcb, 0x69, 0x86, 0x9f, 0xf1, 0x1a, 0x83, 0xf7, 0x74, 0xfb, 0xa5, + 0xe3, 0x97, 0xd3, 0x47, 0x9c, 0xe5, 0xf7, 0xe0, 0xc1, 0x59, 0xb9, 0xfc, + 0x5e, 0xd2, 0x39, 0x53, 0x9e, 0x57, 0x4e, 0x6f, 0xfe, 0x8e, 0xa8, 0x1f, + 0x26, 0x4d, 0x0c, 0x39, 0x7f, 0xef, 0x23, 0x6b, 0xea, 0x71, 0x40, 0x9c, + 0xbf, 0xda, 0x97, 0x73, 0x8c, 0x30, 0xe5, 0x72, 0x7e, 0xc8, 0x83, 0x7e, + 0x79, 0x6d, 0x38, 0x9c, 0xbf, 0xec, 0xd6, 0x7c, 0xcd, 0x40, 0x4e, 0x5f, + 0xd9, 0x2e, 0x65, 0x9e, 0x39, 0x6f, 0x48, 0xf9, 0xfa, 0x73, 0x7d, 0x1e, + 0xfd, 0x87, 0x28, 0xd1, 0x07, 0x2f, 0xe7, 0x9c, 0x0e, 0x21, 0x25, 0x60, + 0xd5, 0xb6, 0xb3, 0xd3, 0x68, 0x31, 0x4c, 0x45, 0x07, 0x9d, 0xaf, 0xff, + 0xcc, 0xdb, 0xcb, 0xa9, 0x9e, 0xde, 0xb0, 0x38, 0x72, 0xff, 0xa3, 0xc3, + 0x9c, 0x47, 0x36, 0x72, 0xa1, 0x15, 0xf8, 0x47, 0xb5, 0x4b, 0xf9, 0xfb, + 0x0d, 0x7f, 0xc8, 0xe5, 0x49, 0x72, 0xb9, 0x70, 0xa5, 0xd4, 0x28, 0xd8, + 0x47, 0xd8, 0x5d, 0x80, 0x88, 0x61, 0x21, 0xe8, 0xdd, 0xf8, 0x97, 0x5f, + 0xd2, 0x1c, 0xe7, 0xd8, 0x72, 0xff, 0xfc, 0xa0, 0x01, 0x1c, 0xe4, 0xe1, + 0x77, 0x5b, 0x84, 0xe5, 0x42, 0x21, 0x34, 0x5b, 0x7f, 0x0f, 0xa5, 0x9a, + 0xc3, 0x97, 0x34, 0x73, 0x94, 0xe7, 0x88, 0xa1, 0x65, 0xfe, 0xee, 0x2d, + 0xfb, 0x1d, 0x39, 0x7f, 0xf3, 0xa7, 0xa0, 0x57, 0x9e, 0xea, 0x1c, 0xbf, + 0x85, 0x01, 0xbe, 0xa1, 0xcb, 0xb4, 0x13, 0x97, 0x36, 0xd9, 0xca, 0x91, + 0xb0, 0x6c, 0x5e, 0xf4, 0x27, 0x12, 0x9f, 0x4d, 0x15, 0xff, 0x20, 0xa0, + 0x37, 0x9d, 0x73, 0x95, 0x89, 0xab, 0x74, 0xc9, 0xd0, 0x76, 0xfd, 0xe2, + 0xfb, 0xfa, 0x07, 0xdd, 0xc9, 0x1c, 0xb8, 0x1b, 0x39, 0x7f, 0x27, 0x51, + 0x55, 0x60, 0xe5, 0x94, 0x09, 0xe2, 0xf8, 0x5e, 0xb4, 0x89, 0xad, 0xb8, + 0xd2, 0x26, 0x0c, 0xa4, 0x38, 0xef, 0x36, 0xdb, 0x65, 0x28, 0xa7, 0xd3, + 0x41, 0x7c, 0x8d, 0xa4, 0xc5, 0x29, 0x67, 0x80, 0x83, 0xb7, 0xec, 0xd4, + 0x71, 0xc3, 0x95, 0x0c, 0xbd, 0xf9, 0xd1, 0xb2, 0x3e, 0xc4, 0x9c, 0xd7, + 0xd4, 0x64, 0x0c, 0x66, 0xec, 0xa7, 0xe1, 0x84, 0x4e, 0xc8, 0x6f, 0xb5, + 0x2f, 0xf0, 0xe5, 0xfe, 0x1e, 0x7c, 0xa7, 0x5c, 0x07, 0x2f, 0x0a, 0x6c, + 0xe5, 0xf0, 0x5c, 0x40, 0x72, 0xff, 0xe8, 0x10, 0x0c, 0x73, 0x34, 0x08, + 0x0e, 0x56, 0x22, 0xd1, 0x0d, 0x40, 0x37, 0xb2, 0x1b, 0xe9, 0x02, 0x42, + 0x72, 0xfd, 0x33, 0x40, 0x34, 0xc3, 0x96, 0x43, 0x97, 0xfc, 0xea, 0xaf, + 0xa8, 0x17, 0x91, 0xcb, 0xe9, 0xe7, 0x7e, 0x4e, 0x5c, 0x0d, 0xa1, 0xf7, + 0x08, 0x82, 0x87, 0x37, 0xd9, 0xae, 0xa1, 0xcb, 0xff, 0xcf, 0x21, 0xce, + 0x2f, 0x34, 0x67, 0xb6, 0x72, 0xa0, 0xfa, 0xdc, 0x86, 0xff, 0xf3, 0x60, + 0xee, 0x64, 0xe9, 0x9c, 0x63, 0x93, 0x97, 0xff, 0x81, 0x0c, 0xd6, 0xa2, + 0x7f, 0x3b, 0xaa, 0x72, 0xff, 0x4b, 0x3b, 0x8c, 0x85, 0x9c, 0xbd, 0x8c, + 0x6b, 0x39, 0x7f, 0xe7, 0xe3, 0x8a, 0x0c, 0x75, 0x27, 0x39, 0x7f, 0xb3, + 0x63, 0x9e, 0xea, 0x1c, 0xa0, 0xa2, 0x43, 0x43, 0xe2, 0x81, 0x58, 0xa9, + 0x3a, 0x68, 0x52, 0xf4, 0x80, 0x09, 0xbe, 0x4b, 0xe3, 0x0c, 0x2b, 0xfb, + 0xd9, 0x30, 0xc3, 0x0f, 0x10, 0x12, 0xfc, 0xe2, 0x1e, 0xc1, 0xa2, 0x02, + 0x7d, 0x37, 0x57, 0xff, 0x27, 0x3b, 0x0e, 0x0c, 0x0f, 0xf0, 0x72, 0xff, + 0xef, 0xd6, 0xae, 0xb3, 0x9d, 0x81, 0xfc, 0x72, 0xfd, 0x12, 0x7e, 0x5b, + 0x39, 0x7f, 0xdf, 0x35, 0xac, 0xef, 0x32, 0xd9, 0xcb, 0xff, 0xfd, 0x9b, + 0xfd, 0xf9, 0xcc, 0x15, 0x77, 0xbc, 0x1f, 0x6c, 0xe5, 0x2d, 0x13, 0xdc, + 0x9e, 0xdf, 0x9d, 0xb0, 0xab, 0xc4, 0xe5, 0x62, 0x74, 0x48, 0x87, 0xa4, + 0x87, 0x86, 0x38, 0x92, 0x5a, 0x73, 0x97, 0xef, 0x99, 0x32, 0x30, 0xe5, + 0xff, 0xef, 0xe3, 0xe7, 0x07, 0x93, 0x7d, 0xe5, 0xdb, 0x39, 0x53, 0x9f, + 0xe6, 0xca, 0xaf, 0xfd, 0x81, 0xeb, 0xfd, 0x8e, 0xc7, 0x27, 0x2b, 0x84, + 0x47, 0x8e, 0xa1, 0x1c, 0xc2, 0x3b, 0xfe, 0x15, 0x74, 0x28, 0xbf, 0xc4, + 0xe5, 0xfb, 0xd1, 0x83, 0x07, 0x29, 0x0f, 0x78, 0x4e, 0x6f, 0x28, 0x3e, + 0x39, 0x79, 0x18, 0xe7, 0x2a, 0x73, 0x70, 0xa8, 0xed, 0xff, 0xf9, 0xf9, + 0xe7, 0x70, 0x3e, 0x52, 0x6e, 0xa7, 0xb6, 0x72, 0xa1, 0x36, 0xcc, 0x84, + 0xc2, 0x2c, 0x7e, 0x47, 0x7c, 0xc8, 0xc6, 0x1c, 0xbf, 0xf6, 0x32, 0x16, + 0x9e, 0xd7, 0xec, 0x39, 0x79, 0x39, 0xd9, 0xca, 0x91, 0xee, 0x00, 0xfe, + 0xfb, 0x4f, 0x29, 0x8e, 0x5f, 0xb7, 0xb8, 0x03, 0x52, 0x72, 0x95, 0x3d, + 0x06, 0xc8, 0xea, 0x11, 0x2c, 0xee, 0x57, 0xfb, 0x53, 0x6d, 0x07, 0xc8, + 0x72, 0xff, 0x75, 0x39, 0x06, 0x9c, 0x27, 0x2f, 0xb9, 0x06, 0xa0, 0xa5, + 0xcd, 0xb6, 0x52, 0xa0, 0xde, 0x36, 0x47, 0x70, 0xa1, 0x4f, 0xa6, 0x86, + 0xff, 0xff, 0xe1, 0xfb, 0x99, 0xc1, 0x13, 0x23, 0x22, 0x6f, 0x83, 0xcc, + 0xbb, 0xf8, 0x0e, 0x51, 0xcb, 0xcf, 0xa9, 0x7c, 0x4c, 0xfa, 0x50, 0x91, + 0xe4, 0x9c, 0x0f, 0x77, 0xf3, 0x8c, 0x97, 0xfc, 0xe7, 0x29, 0xab, 0x66, + 0x5c, 0x44, 0x35, 0xe7, 0x3b, 0x91, 0x16, 0x4a, 0xe9, 0x48, 0x4f, 0xea, + 0x3e, 0x7e, 0xca, 0xa9, 0x74, 0x11, 0x8c, 0x4f, 0xc4, 0x3f, 0xc6, 0xe2, + 0xda, 0xbd, 0xef, 0x23, 0x67, 0x2f, 0x4e, 0xec, 0x39, 0x7b, 0xc8, 0xd9, + 0xe3, 0x08, 0x5f, 0x7b, 0xf7, 0x50, 0xd1, 0x03, 0xb9, 0x35, 0x54, 0xe8, + 0x89, 0xfd, 0x1e, 0xf0, 0xeb, 0x87, 0x39, 0x7f, 0xb1, 0x71, 0x38, 0xc2, + 0xce, 0x58, 0x07, 0x2c, 0xd7, 0xf0, 0xf0, 0xd0, 0xca, 0xe8, 0xfc, 0xe5, + 0xfb, 0xf1, 0x02, 0x92, 0x39, 0x7f, 0xfc, 0x39, 0xbf, 0x8a, 0x76, 0x00, + 0xc7, 0x97, 0xcc, 0x3c, 0x1d, 0x8b, 0xd7, 0xe8, 0xd7, 0xe2, 0xdb, 0x7f, + 0xee, 0xff, 0x3c, 0x7c, 0x8f, 0x40, 0x4e, 0x5e, 0x7d, 0x4e, 0x72, 0xe6, + 0xdb, 0x39, 0x7f, 0xb4, 0x99, 0xc5, 0x49, 0x7d, 0x59, 0xb6, 0x6c, 0x76, + 0xff, 0xc8, 0xaf, 0xcd, 0xfe, 0x06, 0x44, 0x8e, 0x5f, 0xed, 0xe7, 0x9d, + 0x98, 0x27, 0x28, 0x29, 0x9d, 0xe9, 0xe3, 0xa9, 0xfe, 0x43, 0xbf, 0xf6, + 0xf0, 0x73, 0xb8, 0xbc, 0x13, 0x97, 0xfd, 0x2d, 0xfb, 0xb8, 0xcc, 0x91, + 0xcb, 0xff, 0x62, 0xbd, 0x79, 0x28, 0xfc, 0xc1, 0xca, 0x92, 0x2d, 0x10, + 0xec, 0x4e, 0x6a, 0x13, 0x20, 0xc8, 0x79, 0x5f, 0xfc, 0xc6, 0x3c, 0xb3, + 0x4b, 0x77, 0x59, 0xa2, 0x18, 0x5f, 0xff, 0xfe, 0x7d, 0xe0, 0xe2, 0xfb, + 0x1c, 0xc9, 0xa6, 0x75, 0x69, 0x82, 0xea, 0x9c, 0xac, 0x46, 0x3f, 0xea, + 0x15, 0x0b, 0x99, 0xa9, 0x19, 0xdf, 0x65, 0x40, 0x8c, 0x3b, 0xaf, 0xc3, + 0x00, 0xe4, 0x07, 0x2f, 0xee, 0xbc, 0xe3, 0x12, 0x29, 0x7f, 0xef, 0x75, + 0xd3, 0xd1, 0xa8, 0x01, 0xcb, 0xf7, 0x5c, 0x54, 0x9c, 0xe5, 0x49, 0x17, + 0x6c, 0x28, 0x12, 0xd6, 0xcf, 0x6f, 0xfc, 0x8b, 0x8d, 0xbe, 0xb4, 0x8d, + 0x9c, 0xbf, 0xfe, 0xd8, 0x13, 0x4a, 0xaf, 0xa9, 0xd1, 0xfe, 0x73, 0x97, + 0x6f, 0xf3, 0x97, 0xf4, 0xba, 0xee, 0x30, 0x72, 0xd0, 0xb3, 0xc3, 0xe4, + 0x62, 0xff, 0xec, 0xf4, 0x75, 0x31, 0x55, 0x62, 0x47, 0x2f, 0xda, 0x5b, + 0xba, 0xcd, 0x10, 0x52, 0xf7, 0x61, 0x87, 0x2f, 0xfd, 0x13, 0xbf, 0xb5, + 0x92, 0x69, 0x87, 0x28, 0x28, 0xd4, 0xc4, 0x44, 0x34, 0x11, 0xcb, 0xf7, + 0x61, 0x9f, 0xf2, 0x72, 0xfb, 0xdb, 0x80, 0x14, 0xbc, 0xfa, 0x9c, 0xa5, + 0xf7, 0xe2, 0xea, 0x94, 0xbf, 0xc9, 0x3e, 0x7b, 0x70, 0x02, 0x94, 0x52, + 0xfe, 0xc5, 0xc7, 0x61, 0x85, 0x2e, 0x6d, 0xb2, 0x97, 0xf0, 0xc0, 0xce, + 0x9a, 0x29, 0x58, 0x98, 0x8a, 0xc8, 0x98, 0x3b, 0xd2, 0x30, 0x19, 0x88, + 0x5b, 0x65, 0x8a, 0x0c, 0xdc, 0x9a, 0x29, 0xf4, 0xfc, 0xaa, 0x4a, 0x84, + 0x26, 0x3a, 0xec, 0x75, 0xb7, 0xff, 0xe8, 0x6f, 0x63, 0x9c, 0xf9, 0xc6, + 0x7c, 0xe7, 0xc7, 0x2a, 0x17, 0x2b, 0x70, 0xf5, 0x0f, 0xbb, 0x09, 0x67, + 0x96, 0x18, 0x27, 0x37, 0xff, 0xfc, 0x39, 0xef, 0x47, 0x32, 0xf9, 0xd8, + 0x67, 0xfc, 0xef, 0xb0, 0x72, 0xfe, 0xc1, 0xda, 0x0e, 0x1c, 0xbd, 0xdf, + 0xd8, 0x72, 0x9a, 0xd1, 0x67, 0xd6, 0xbe, 0x02, 0xab, 0xfc, 0xe3, 0x9b, + 0xd4, 0x6c, 0xe5, 0xfc, 0x1c, 0x17, 0xf6, 0xce, 0x54, 0x8f, 0x77, 0x66, + 0x37, 0xf6, 0xbe, 0x3c, 0xd9, 0xd3, 0x95, 0x07, 0xa4, 0x84, 0x57, 0xed, + 0x73, 0x2c, 0xf1, 0xcb, 0xff, 0xe7, 0x40, 0x6f, 0x15, 0x76, 0x6a, 0x30, + 0x4e, 0x5f, 0xbc, 0x99, 0xcf, 0x8e, 0x5f, 0xff, 0xf7, 0x53, 0x58, 0x17, + 0x66, 0x0f, 0x86, 0x1b, 0xcf, 0x6c, 0xe5, 0xa0, 0xe5, 0xf4, 0x71, 0x0c, + 0x2c, 0xfd, 0x00, 0xc9, 0x7f, 0xe7, 0x97, 0x5f, 0xdb, 0xc1, 0x91, 0xca, + 0xe9, 0xfb, 0xf8, 0xea, 0xb4, 0x9d, 0x5f, 0x4a, 0x76, 0x9b, 0xe8, 0xc4, + 0xef, 0x2f, 0x18, 0x72, 0xfe, 0x0b, 0xfb, 0x7f, 0xc8, 0xe5, 0xd2, 0x69, + 0x07, 0x96, 0xa0, 0xe5, 0xfc, 0xfa, 0x8f, 0x27, 0x13, 0x95, 0xc9, 0xef, + 0x09, 0x85, 0xff, 0xff, 0xb5, 0xa8, 0xe6, 0x5c, 0xed, 0x34, 0xbe, 0xe2, + 0x9a, 0x48, 0x09, 0xcb, 0xfe, 0x7d, 0x67, 0x32, 0x80, 0x41, 0xca, 0x84, + 0x64, 0xe1, 0x17, 0xed, 0xf7, 0xff, 0xe5, 0xaa, 0xfb, 0xcd, 0x49, 0x3a, + 0xe3, 0xcc, 0x8e, 0x5f, 0xf9, 0x71, 0xed, 0xe7, 0x93, 0x96, 0xce, 0x59, + 0xf1, 0x12, 0xca, 0xab, 0x54, 0x2a, 0xa3, 0xec, 0x76, 0xc3, 0x0c, 0x5b, + 0xf6, 0xc7, 0xfe, 0x32, 0x39, 0x7a, 0x75, 0x16, 0x72, 0xa0, 0xf2, 0x9c, + 0xae, 0xe7, 0x01, 0xca, 0x91, 0xb6, 0xf1, 0x05, 0xff, 0xf9, 0xde, 0x4f, + 0xdf, 0x99, 0x3f, 0xfe, 0xfd, 0xd4, 0x34, 0x5f, 0x6b, 0xc0, 0x80, 0x9c, + 0xbf, 0x9d, 0x70, 0x30, 0x03, 0x97, 0xfe, 0xda, 0x0f, 0x32, 0xd7, 0xf1, + 0xb3, 0x95, 0x32, 0x3b, 0xb4, 0xcf, 0xd1, 0xcf, 0x15, 0xdf, 0xbb, 0x93, + 0x43, 0x59, 0xcb, 0xf0, 0x75, 0xac, 0x6c, 0xe5, 0xa2, 0x73, 0xd4, 0x12, + 0xbb, 0x2c, 0xe5, 0xff, 0xfe, 0x02, 0x69, 0x5e, 0xc3, 0x26, 0x92, 0x0f, + 0x63, 0x50, 0x72, 0xde, 0xc3, 0xf2, 0xd8, 0x8d, 0xf7, 0x87, 0x24, 0x72, + 0xa0, 0xf2, 0x10, 0x9e, 0xff, 0xc2, 0x92, 0xf7, 0x73, 0x49, 0xb3, 0x97, + 0xe9, 0x0e, 0x64, 0xe7, 0x2e, 0xd4, 0xe7, 0x2a, 0x0d, 0xfe, 0x13, 0xdf, + 0xe7, 0x0c, 0x02, 0x1b, 0xd9, 0xca, 0xe9, 0xe9, 0x38, 0xfd, 0xfc, 0xd1, + 0xa8, 0x7c, 0xf9, 0xd6, 0x87, 0x88, 0x05, 0x7f, 0xbc, 0x05, 0x06, 0x5d, + 0xc3, 0xc4, 0x02, 0xbc, 0xfa, 0x91, 0xe2, 0x01, 0x56, 0x1f, 0x57, 0xe8, + 0x37, 0x3c, 0x8f, 0x10, 0x0a, 0xf9, 0xc7, 0x99, 0x1e, 0x20, 0x15, 0xfe, + 0x45, 0xf7, 0x00, 0x08, 0x3c, 0x40, 0x2b, 0xc8, 0x21, 0x3c, 0x40, 0x2a, + 0x0a, 0x2e, 0x58, 0x47, 0xd2, 0xfe, 0x27, 0xf6, 0x54, 0xf1, 0x00, 0xaf, + 0x6a, 0x3c, 0x78, 0x80, 0x54, 0x78, 0x80, 0x57, 0x9a, 0x20, 0x0f, 0x10, + 0x0a, 0xe8, 0x61, 0xe2, 0x01, 0x50, 0x4f, 0x9b, 0x06, 0x10, 0xae, 0xf9, + 0x18, 0x18, 0x3c, 0x40, 0x2b, 0xde, 0x75, 0x9e, 0x20, 0x15, 0xff, 0x85, + 0xe5, 0xf7, 0xa8, 0xb7, 0xd1, 0xe2, 0x01, 0x5f, 0xfc, 0xfe, 0xfe, 0x74, + 0x1f, 0x75, 0xe4, 0x78, 0x80, 0x57, 0x38, 0x4f, 0x10, 0x0a, 0xff, 0x0b, + 0xb7, 0xbd, 0xc0, 0x0f, 0x10, 0x0a, 0xfc, 0x8a, 0xb8, 0x80, 0xf1, 0x00, + 0xae, 0x4d, 0x9e, 0x20, 0x15, 0x68, 0xf5, 0xfc, 0x69, 0x7f, 0xfb, 0xa9, + 0xef, 0x66, 0xfe, 0x69, 0x21, 0x87, 0x88, 0x05, 0x7e, 0xf0, 0xc7, 0x32, + 0x34, 0x40, 0x2b, 0x81, 0x07, 0x88, 0x05, 0xf4, 0xda, 0xdf, 0x92, 0x18, + 0xe1, 0x3c, 0x40, 0x2b, 0xef, 0xdc, 0x56, 0x78, 0x80, 0x57, 0xa3, 0x4b, + 0x3c, 0x40, 0x2b, 0xff, 0x67, 0x3b, 0x0c, 0x60, 0x83, 0x67, 0x88, 0x05, + 0x7e, 0xfd, 0xe5, 0x28, 0x3c, 0x40, 0x2b, 0xf3, 0xaf, 0xb1, 0xc9, 0xe2, + 0x01, 0x56, 0x22, 0xd7, 0xa9, 0x7f, 0x9a, 0xdd, 0xa0, 0x1e, 0x20, 0x15, + 0x49, 0x59, 0x90, 0x48, 0xf2, 0x12, 0xeb, 0x22, 0x48, 0x46, 0xf4, 0xd4, + 0x06, 0x7b, 0x2f, 0xf4, 0x37, 0xbf, 0x30, 0xbf, 0x67, 0xb6, 0xfc, 0x9e, + 0x20, 0x15, 0xfe, 0x0c, 0x2e, 0x6d, 0x47, 0x8f, 0x10, 0x08, 0x26, 0xd6, + 0xf6, 0xa1, 0xb3, 0xc4, 0x02, 0xa5, 0x9f, 0xde, 0x94, 0x6f, 0xf7, 0xef, + 0x29, 0x42, 0x8c, 0x3c, 0x40, 0x2b, 0xe4, 0x19, 0x6c, 0xf1, 0x00, 0xaf, + 0xe7, 0x9a, 0x59, 0xcc, 0x8f, 0x10, 0x0a, 0xb1, 0x19, 0xdd, 0x22, 0x02, + 0x17, 0xe5, 0xd7, 0xfd, 0xd8, 0xdf, 0xdd, 0xff, 0xa0, 0x1e, 0x20, 0x15, + 0x90, 0xf1, 0x00, 0xae, 0x79, 0xc2, 0x7c, 0xfd, 0x4a, 0xbb, 0x40, 0x3c, + 0x40, 0x2b, 0xf3, 0xfb, 0x69, 0xc9, 0xe2, 0x01, 0x5f, 0xc8, 0x3f, 0xcb, + 0x36, 0x78, 0x80, 0x55, 0x08, 0x93, 0x12, 0x4f, 0x1a, 0xd4, 0x32, 0x9f, + 0x03, 0x0b, 0x4c, 0x86, 0xda, 0x1f, 0xcc, 0x3f, 0xa8, 0x47, 0xf4, 0xb5, + 0xcb, 0x80, 0x52, 0x29, 0x9b, 0x97, 0x09, 0xe9, 0x43, 0x2d, 0x21, 0x48, + 0xa4, 0x30, 0x6f, 0x79, 0x1b, 0x3c, 0x61, 0x2b, 0xce, 0xeb, 0x34, 0x40, + 0x2f, 0xa9, 0x89, 0xf3, 0x0e, 0x9b, 0xe5, 0x78, 0x5c, 0x2c, 0x39, 0x77, + 0x19, 0xce, 0x5f, 0xb8, 0x8c, 0x07, 0xa7, 0x2a, 0x0f, 0x0d, 0x06, 0xaf, + 0xfe, 0x90, 0xe2, 0xfa, 0x80, 0x07, 0xf3, 0x1c, 0xbf, 0x7b, 0x02, 0xfd, + 0x39, 0x70, 0x20, 0xa5, 0x95, 0x29, 0x7b, 0xb1, 0x39, 0xcb, 0x9b, 0x6c, + 0xa5, 0x21, 0xef, 0x35, 0x8b, 0x4c, 0x24, 0xd8, 0xed, 0xb6, 0x53, 0xe9, + 0xe0, 0x59, 0x98, 0x8e, 0x94, 0x86, 0x2d, 0xfd, 0xed, 0xe3, 0x7d, 0x43, + 0x96, 0xf1, 0xcb, 0x27, 0x8d, 0xff, 0xe5, 0xd7, 0xff, 0xbd, 0xbc, 0x55, + 0x34, 0xa0, 0x01, 0x1c, 0x9c, 0xa9, 0xd9, 0xf1, 0x52, 0x20, 0x0c, 0x33, + 0x97, 0x4b, 0xb0, 0x45, 0x0d, 0x37, 0x39, 0x00, 0x23, 0x2f, 0xf3, 0x5a, + 0x84, 0xf7, 0xfd, 0x92, 0x40, 0xba, 0xf7, 0x23, 0x97, 0xfc, 0xc4, 0x15, + 0xa6, 0x90, 0x07, 0x29, 0x67, 0xdf, 0xd3, 0x8b, 0xcb, 0xe8, 0x9c, 0xbf, + 0xfb, 0xcd, 0x32, 0x69, 0x3e, 0xa7, 0x0c, 0x1c, 0xa6, 0x1f, 0x20, 0x8e, + 0x5f, 0xde, 0x53, 0x8f, 0x18, 0xd9, 0xcb, 0xfd, 0x9c, 0xfb, 0xcf, 0x2d, + 0x9c, 0xbd, 0x2e, 0x1e, 0x47, 0x2e, 0xe6, 0x47, 0x8c, 0x01, 0x5c, 0x9e, + 0x38, 0x91, 0x5f, 0xff, 0xa3, 0x3b, 0xb1, 0x7f, 0x7f, 0xe0, 0xf5, 0x15, + 0x39, 0x50, 0x9e, 0x6e, 0x42, 0x19, 0x08, 0x74, 0x66, 0xef, 0x62, 0x45, + 0x7f, 0xfe, 0x11, 0xff, 0x9c, 0xe7, 0xc1, 0xd3, 0xf3, 0x93, 0x9c, 0xbf, + 0x67, 0xb5, 0x1b, 0x39, 0x48, 0x88, 0x01, 0x59, 0xbf, 0x4d, 0x28, 0xd4, + 0xe7, 0x2f, 0xa1, 0x58, 0x61, 0xca, 0x91, 0xf6, 0xe8, 0x85, 0x85, 0x57, + 0xfe, 0x96, 0xfe, 0x0e, 0x32, 0x34, 0xa9, 0xcb, 0xfa, 0x51, 0xa0, 0x28, + 0xc3, 0x97, 0xff, 0x71, 0x1c, 0xdf, 0xb0, 0x65, 0x9b, 0x39, 0x7c, 0xc8, + 0xff, 0xc7, 0x2b, 0x0f, 0x9d, 0xd1, 0x2f, 0xcf, 0xef, 0x3e, 0x8e, 0x5e, + 0xf3, 0x89, 0xcb, 0xba, 0xf8, 0x8f, 0x81, 0x84, 0xb6, 0xc8, 0x38, 0x09, + 0xef, 0xfa, 0x1a, 0xc3, 0xd8, 0x9d, 0xc4, 0xe5, 0xff, 0x42, 0xe1, 0x88, + 0xc0, 0x21, 0xca, 0xd2, 0x30, 0x3a, 0x9d, 0xc0, 0x77, 0x7f, 0x28, 0xde, + 0x93, 0x3a, 0x52, 0xfd, 0xbe, 0xc6, 0x4e, 0x72, 0xff, 0xe0, 0x0a, 0x67, + 0x3e, 0x9a, 0x4f, 0xa3, 0x97, 0xd3, 0x75, 0xe6, 0x39, 0x7c, 0xb7, 0xd4, + 0xe7, 0x2f, 0xd9, 0x34, 0xa3, 0x93, 0x97, 0x24, 0xc7, 0x2f, 0xed, 0xe6, + 0x83, 0xdc, 0x39, 0x5d, 0x3c, 0x4d, 0x8b, 0xde, 0x18, 0x91, 0x4b, 0xff, + 0x08, 0x13, 0x83, 0x83, 0xf9, 0x43, 0x59, 0xca, 0xc3, 0xe3, 0x71, 0xba, + 0xf8, 0x9e, 0x37, 0x25, 0x1a, 0x45, 0xe9, 0x20, 0x91, 0xf9, 0xb7, 0x82, + 0x10, 0xb5, 0x0b, 0x97, 0xf8, 0x5e, 0x91, 0xfc, 0xf4, 0xcd, 0xe3, 0xf5, + 0xbf, 0xb9, 0xde, 0xb5, 0x1e, 0x39, 0x7f, 0x4b, 0x6a, 0xe9, 0xd6, 0x72, + 0xf0, 0xfb, 0x67, 0x2f, 0x0a, 0x48, 0xe5, 0xfb, 0x7f, 0x8f, 0xeb, 0x39, + 0x7f, 0x7a, 0x69, 0x67, 0x32, 0x39, 0x50, 0x8c, 0x04, 0x2f, 0x71, 0xcf, + 0xc6, 0xd4, 0x2a, 0xbf, 0xfb, 0xad, 0xc6, 0xb7, 0x8d, 0xbe, 0x95, 0x39, + 0x7c, 0x10, 0xe3, 0x0e, 0x5c, 0x08, 0x29, 0x73, 0x6d, 0x94, 0xa4, 0x35, + 0xed, 0x8b, 0x5f, 0x83, 0xfb, 0xea, 0x45, 0x3e, 0x9a, 0x1a, 0xc4, 0x56, + 0xaa, 0xe5, 0x7f, 0xfb, 0xdc, 0xad, 0x3a, 0xd2, 0x3d, 0xd5, 0x36, 0x72, + 0xff, 0x44, 0x93, 0xd2, 0x8f, 0x1c, 0xbb, 0x87, 0xd9, 0xcd, 0x1b, 0x2b, + 0xfe, 0xeb, 0xfb, 0x6b, 0x1c, 0x9c, 0xe5, 0xcb, 0x43, 0x97, 0xc2, 0x9c, + 0xc8, 0xe5, 0xff, 0x27, 0x3d, 0xc0, 0xe9, 0xd6, 0x72, 0xa0, 0xf6, 0xf4, + 0x45, 0x7f, 0xb7, 0x89, 0xe5, 0x53, 0xa7, 0x2f, 0xfb, 0xb1, 0xa8, 0x5a, + 0x0a, 0xce, 0x5e, 0x55, 0xf6, 0xb4, 0x7e, 0x69, 0xc7, 0xc4, 0x3c, 0x06, + 0x75, 0x89, 0xc3, 0xfa, 0x33, 0x5a, 0x92, 0xb7, 0x4d, 0x43, 0xd1, 0x84, + 0x7f, 0xc2, 0x05, 0xb8, 0xec, 0xef, 0xe6, 0xd5, 0x7f, 0x0c, 0x1c, 0xbe, + 0xfd, 0x98, 0x13, 0x95, 0xc9, 0xe8, 0xf0, 0x17, 0x5f, 0xfb, 0xb9, 0xc0, + 0xe2, 0xae, 0x73, 0xe3, 0x97, 0xfd, 0x8b, 0xea, 0x07, 0xbf, 0xaa, 0x72, + 0xf7, 0xb1, 0x67, 0x29, 0x87, 0xaf, 0xb3, 0xbb, 0xd2, 0x60, 0x0e, 0x52, + 0xa8, 0xd8, 0x04, 0x26, 0x7c, 0x45, 0x7f, 0xca, 0xbf, 0xc8, 0x60, 0xa2, + 0xa7, 0x2f, 0xfc, 0xfb, 0x64, 0x26, 0xb4, 0x8d, 0x9c, 0xb6, 0xd5, 0x3f, + 0x9e, 0x9d, 0xdf, 0x3c, 0x9f, 0x47, 0x2f, 0xfb, 0x3d, 0xe4, 0x57, 0xd8, + 0xb3, 0x97, 0xf4, 0x73, 0xbc, 0xe7, 0xc7, 0x2e, 0xd4, 0x1c, 0xa0, 0x9e, + 0x2f, 0x8b, 0xef, 0xf7, 0x91, 0x68, 0x18, 0xf1, 0xcb, 0xf6, 0xe1, 0x78, + 0xc3, 0x95, 0x07, 0xb3, 0xb3, 0x2b, 0x6c, 0x29, 0x8d, 0x63, 0xf6, 0x9e, + 0xeb, 0x94, 0xe6, 0x98, 0x53, 0xe8, 0xce, 0xef, 0xfb, 0xc9, 0x3c, 0x72, + 0x0d, 0x41, 0xcb, 0xdb, 0xf6, 0x1c, 0xbb, 0x37, 0xf0, 0xf5, 0x94, 0x3a, + 0xbf, 0xfb, 0x3c, 0x9c, 0xc8, 0x63, 0x86, 0x6a, 0x2d, 0x0e, 0x5f, 0xfe, + 0xfe, 0x5d, 0x74, 0xf2, 0x0f, 0xbf, 0xe9, 0xcb, 0xfc, 0xaf, 0xb9, 0x5a, + 0x6b, 0x67, 0x2f, 0xd9, 0xe0, 0x3f, 0x8e, 0x54, 0x91, 0xf3, 0xa5, 0x1f, + 0xd2, 0xda, 0x1b, 0x5f, 0xff, 0xa3, 0xaf, 0x83, 0x1a, 0x54, 0x3f, 0xbe, + 0xa4, 0x72, 0xa4, 0x9d, 0xf7, 0xa3, 0x29, 0xe0, 0x40, 0xa8, 0x5e, 0x7c, + 0xc8, 0x57, 0xa4, 0x3f, 0x9e, 0x52, 0x4f, 0xf2, 0x93, 0x2f, 0xba, 0x8f, + 0x23, 0x97, 0xfb, 0x06, 0x59, 0xb5, 0x18, 0x72, 0xfc, 0xcd, 0x81, 0xdc, + 0xe5, 0x78, 0xf6, 0x94, 0x33, 0xbf, 0xed, 0x60, 0xfc, 0xee, 0x72, 0xd9, + 0xcb, 0xfe, 0x90, 0xfe, 0x0f, 0x8b, 0x60, 0x0e, 0x54, 0xe9, 0x8b, 0xc9, + 0xef, 0x08, 0xf9, 0x3c, 0xbf, 0xf9, 0xfb, 0xb4, 0x92, 0x7a, 0x3d, 0xb3, + 0x97, 0xfb, 0x3d, 0xd4, 0x68, 0xf3, 0x9c, 0xbf, 0xe1, 0x8c, 0xe7, 0xd9, + 0xa8, 0x39, 0x7f, 0xe8, 0xea, 0x9b, 0x1c, 0xf7, 0x70, 0xe5, 0x42, 0x65, + 0x88, 0x7f, 0xd4, 0x37, 0x35, 0x01, 0xbd, 0xf9, 0xf8, 0x84, 0x30, 0x72, + 0xed, 0xec, 0xe5, 0xe6, 0xdb, 0x6c, 0xe5, 0xc0, 0x72, 0x9f, 0x4d, 0x05, + 0x68, 0xf7, 0xf6, 0x6f, 0x7f, 0xec, 0xd8, 0xba, 0xb3, 0x0a, 0x4c, 0x72, + 0xfe, 0x04, 0x4b, 0xaa, 0x6c, 0xe5, 0xfc, 0x82, 0x05, 0xad, 0x0e, 0x5e, + 0x70, 0x61, 0x4a, 0x92, 0x6b, 0xec, 0x84, 0x47, 0x48, 0x80, 0x7f, 0xc4, + 0xbd, 0xa1, 0x65, 0xf4, 0x05, 0x02, 0x72, 0xfc, 0x1d, 0x27, 0xf3, 0x9c, + 0xbf, 0xcd, 0xe0, 0xe7, 0x14, 0xd1, 0xcb, 0xf8, 0x73, 0x90, 0x29, 0x23, + 0x95, 0x32, 0x23, 0x44, 0xab, 0xc6, 0x97, 0xec, 0xcf, 0x77, 0x0e, 0x5c, + 0xec, 0x39, 0x7f, 0xb3, 0x8e, 0x7d, 0x6d, 0xb6, 0xca, 0x5f, 0xa6, 0x8c, + 0xee, 0xce, 0x50, 0x9f, 0x12, 0x87, 0x57, 0xfb, 0x87, 0x8f, 0xd7, 0xd4, + 0xd1, 0xcb, 0xcc, 0x7f, 0x1c, 0xa9, 0x91, 0xdf, 0xd7, 0x8f, 0xc8, 0xb8, + 0x9c, 0xdc, 0x06, 0xa8, 0xe5, 0xfb, 0x8b, 0xb1, 0x18, 0x72, 0xa0, 0xf1, + 0x44, 0x72, 0xfd, 0x93, 0x4a, 0x24, 0x72, 0xfe, 0x9c, 0x31, 0x82, 0x13, + 0x95, 0x0a, 0xd3, 0xe4, 0xc2, 0x90, 0xae, 0xe9, 0x83, 0xc6, 0x2b, 0xb8, + 0x43, 0x78, 0x81, 0x42, 0x8b, 0xce, 0x04, 0x39, 0x7f, 0xc1, 0x1f, 0xf7, + 0x93, 0xe4, 0xe7, 0x2f, 0x46, 0x84, 0xe5, 0xfe, 0xc0, 0x8b, 0xed, 0x02, + 0x72, 0xdd, 0x39, 0x7b, 0xf7, 0x9c, 0x4f, 0x0b, 0x66, 0x36, 0x4d, 0x22, + 0x47, 0xcb, 0xb4, 0xc4, 0xc3, 0xdc, 0x6f, 0x87, 0x86, 0x65, 0x84, 0xe5, + 0xf4, 0x4f, 0x12, 0x39, 0x4e, 0x6c, 0x84, 0x42, 0xff, 0xf6, 0x05, 0xd9, + 0x9c, 0xcb, 0x01, 0x81, 0x39, 0x77, 0x5c, 0xe5, 0xd3, 0x6c, 0xe5, 0xfb, + 0x38, 0xa0, 0x87, 0x0d, 0x72, 0x82, 0xd7, 0xf7, 0xcf, 0x66, 0xf7, 0x07, + 0x2f, 0xdd, 0xce, 0x7d, 0x07, 0x2f, 0xdc, 0x0f, 0x3a, 0x92, 0x39, 0x5f, + 0x13, 0x39, 0xfa, 0xef, 0x07, 0xd8, 0x5f, 0xf9, 0x45, 0xf0, 0x73, 0xae, + 0x72, 0xff, 0xd8, 0x32, 0xee, 0x08, 0xc3, 0x67, 0x2f, 0xfd, 0x9a, 0xd3, + 0xcb, 0xe7, 0x18, 0x6b, 0x39, 0x50, 0x88, 0x19, 0x1e, 0x56, 0x93, 0x12, + 0x14, 0xef, 0x42, 0x8a, 0xff, 0x6b, 0x7d, 0xc1, 0x4d, 0x9c, 0xa8, 0x55, + 0xa2, 0x92, 0x9a, 0x9c, 0xd6, 0xff, 0xb0, 0x38, 0x30, 0x3f, 0xc1, 0xcb, + 0xa1, 0xb3, 0x95, 0x0f, 0x8b, 0x8d, 0x3c, 0x29, 0xa5, 0x39, 0xe0, 0x19, + 0xdb, 0x7c, 0x8c, 0x51, 0x58, 0x72, 0xae, 0x71, 0xbb, 0x98, 0x5d, 0xa4, + 0x61, 0xf3, 0x42, 0x4b, 0x55, 0x83, 0x5b, 0x25, 0x6f, 0xf6, 0x78, 0x11, + 0xd5, 0x41, 0x0e, 0xf1, 0xa5, 0x1c, 0xee, 0x55, 0x2f, 0xa7, 0x3d, 0xbf, + 0x8e, 0x43, 0x8c, 0xb3, 0xd5, 0x0d, 0xb8, 0x0d, 0xaf, 0xfb, 0x34, 0x31, + 0xe9, 0x67, 0x4e, 0x5f, 0xfc, 0x2b, 0x55, 0xf7, 0x92, 0x81, 0x59, 0xcb, + 0xf0, 0x30, 0x2f, 0x23, 0x94, 0x87, 0xd4, 0x28, 0x77, 0xfd, 0xed, 0xf5, + 0x21, 0x8e, 0x13, 0x97, 0xfe, 0xea, 0x0c, 0x73, 0xb4, 0x64, 0x1c, 0xbd, + 0xb8, 0xd1, 0xcb, 0xbd, 0xb5, 0x9e, 0xcf, 0x27, 0xb5, 0x08, 0xc0, 0xfe, + 0x12, 0x37, 0xf9, 0x63, 0x92, 0x93, 0xec, 0xe5, 0xfc, 0xed, 0xe0, 0x14, + 0xf1, 0xcb, 0xf3, 0xcb, 0xe0, 0x50, 0xe5, 0xfd, 0xbc, 0x0a, 0x6e, 0x73, + 0x97, 0xa5, 0x00, 0x39, 0x7e, 0x52, 0x69, 0x43, 0x59, 0x4a, 0x85, 0x55, + 0x59, 0x0a, 0x15, 0x61, 0xc0, 0x85, 0x1a, 0x32, 0xe9, 0x7e, 0xca, 0x7c, + 0x5c, 0xa0, 0xe5, 0x96, 0x72, 0xff, 0xe5, 0x47, 0xf7, 0x53, 0x36, 0x90, + 0x27, 0x2f, 0x34, 0x40, 0x9c, 0xad, 0x1f, 0x13, 0x11, 0x2f, 0xe6, 0x7b, + 0xb1, 0xc6, 0x0e, 0x5f, 0xfd, 0xcf, 0xbf, 0x67, 0x61, 0x05, 0xc2, 0x72, + 0xf9, 0x5d, 0x3b, 0x67, 0x2c, 0xa1, 0xa2, 0x05, 0x5b, 0xc6, 0xa0, 0x51, + 0x5e, 0x37, 0xad, 0x8f, 0xd6, 0x22, 0x0d, 0x18, 0x6f, 0xe4, 0xe1, 0xd7, + 0xd8, 0x6c, 0xe5, 0xfe, 0xea, 0x29, 0xf4, 0x00, 0x82, 0x95, 0xa3, 0xe9, + 0x68, 0x67, 0x7c, 0x3c, 0x1c, 0x3e, 0xce, 0x52, 0x1e, 0x72, 0x84, 0x97, + 0xf7, 0x73, 0xfe, 0x1f, 0x36, 0x72, 0xff, 0x87, 0xdb, 0xff, 0x9f, 0x23, + 0x67, 0x2f, 0xf7, 0xef, 0xbc, 0xc1, 0x54, 0xe5, 0x41, 0xf7, 0xf4, 0xf2, + 0xff, 0xa3, 0xdb, 0xf9, 0x8c, 0x40, 0x9c, 0xbf, 0xf7, 0xc1, 0x75, 0x7e, + 0x6c, 0x00, 0x83, 0x97, 0xff, 0xa7, 0xfc, 0x1b, 0x92, 0x6f, 0x71, 0xa9, + 0x1c, 0xb2, 0x2a, 0x89, 0x0d, 0x21, 0xdf, 0xe7, 0xef, 0x3b, 0x81, 0xf1, + 0xca, 0xd9, 0xee, 0x78, 0xa6, 0xff, 0xff, 0xa7, 0x0f, 0x61, 0x7d, 0x49, + 0x9d, 0xe4, 0xab, 0xa8, 0xed, 0x67, 0x2f, 0xf7, 0x52, 0x69, 0x40, 0xc8, + 0xe5, 0xff, 0xa1, 0xbd, 0xf0, 0x8e, 0xbc, 0xe7, 0xc7, 0x2a, 0x11, 0xc8, + 0xb6, 0xcf, 0x19, 0xdf, 0x4b, 0xb9, 0x39, 0xcb, 0xfe, 0x8e, 0x58, 0xfe, + 0xce, 0x7c, 0x72, 0xe7, 0x9c, 0xe5, 0x72, 0x7e, 0x82, 0x46, 0xd9, 0xd5, + 0xfb, 0xfe, 0xea, 0x1b, 0x39, 0x73, 0x47, 0x39, 0x74, 0x2f, 0xc7, 0x84, + 0xa1, 0x55, 0xda, 0x73, 0x97, 0xff, 0x71, 0x4d, 0xef, 0x05, 0x6e, 0x20, + 0x39, 0x7f, 0xba, 0x81, 0x0e, 0x37, 0x31, 0xcb, 0xd1, 0xa0, 0x61, 0xfc, + 0xad, 0x12, 0xb4, 0x8c, 0x1e, 0xc2, 0x3e, 0xff, 0xcf, 0xce, 0xf3, 0xc8, + 0xc7, 0x91, 0xcb, 0x78, 0xe5, 0x00, 0xf3, 0xd4, 0x3e, 0xbf, 0xff, 0xd3, + 0x0c, 0x33, 0x50, 0xbc, 0xd6, 0x75, 0x35, 0xd7, 0x39, 0x7f, 0xfc, 0xfa, + 0x03, 0x4c, 0xd4, 0x49, 0x39, 0xf6, 0x1c, 0xbf, 0xff, 0xfb, 0xfd, 0xf5, + 0xe5, 0xb9, 0x27, 0x94, 0xd4, 0x76, 0x3d, 0xb7, 0xe4, 0xe5, 0xfa, 0x30, + 0x7c, 0xd0, 0xe5, 0xfc, 0x9c, 0x83, 0x4e, 0x13, 0x96, 0x61, 0xca, 0x61, + 0xf3, 0xf4, 0xa0, 0x4b, 0xae, 0xd3, 0x59, 0xcb, 0xd2, 0xfc, 0x27, 0x2e, + 0x7e, 0x7e, 0x1f, 0x34, 0xc5, 0xce, 0x35, 0x58, 0xa8, 0xbd, 0x17, 0xf4, + 0xa3, 0xb8, 0xd0, 0xaf, 0xff, 0xec, 0x19, 0xf7, 0xb8, 0x06, 0x75, 0x34, + 0xed, 0xf8, 0xe5, 0xfc, 0x1c, 0x15, 0x75, 0x07, 0x2a, 0x4c, 0x88, 0x70, + 0xc2, 0x89, 0x64, 0x3c, 0xc6, 0x4d, 0x34, 0x60, 0xda, 0x85, 0x1b, 0x1c, + 0xbb, 0x0e, 0xf0, 0x3b, 0xfa, 0x52, 0x93, 0x68, 0x6d, 0x16, 0xef, 0xff, + 0xf0, 0xe0, 0x7b, 0x0d, 0x8e, 0x24, 0xed, 0x3f, 0xea, 0x68, 0xe5, 0x43, + 0x27, 0x71, 0x29, 0x15, 0x3f, 0xc3, 0x42, 0xd0, 0x72, 0xff, 0xfa, 0x67, + 0x79, 0x6e, 0x18, 0x1e, 0xc0, 0xac, 0xe5, 0x41, 0xef, 0xa0, 0x85, 0xff, + 0x64, 0xd2, 0x8e, 0x73, 0x9f, 0x1c, 0xbb, 0x53, 0xe1, 0xed, 0x89, 0x05, + 0xf0, 0x7b, 0xfc, 0xe7, 0x2f, 0xf0, 0x5e, 0x59, 0x3f, 0xe2, 0x72, 0xff, + 0xda, 0xc6, 0xb9, 0xba, 0xec, 0x4d, 0x9c, 0xb4, 0xf0, 0x89, 0xbc, 0x25, + 0xd1, 0xa5, 0xdc, 0x3e, 0x1c, 0xac, 0x3d, 0x07, 0x35, 0xbf, 0xbc, 0xd3, + 0xfe, 0xe2, 0xce, 0x5f, 0xed, 0x47, 0x90, 0x11, 0x23, 0x97, 0xf7, 0x33, + 0xbc, 0xa1, 0xac, 0xe5, 0xc3, 0x23, 0x95, 0x07, 0x91, 0x39, 0x95, 0x70, + 0x8c, 0xf4, 0x08, 0x73, 0x54, 0x89, 0x0b, 0xd9, 0x0c, 0x8e, 0xd2, 0xad, + 0x1e, 0x1f, 0x63, 0x18, 0xc6, 0xc8, 0x3c, 0x63, 0xfb, 0xd5, 0xff, 0xb8, + 0x45, 0x21, 0x8b, 0xeb, 0xf2, 0x03, 0x97, 0xfa, 0x53, 0x60, 0xbf, 0x70, + 0xe5, 0xf7, 0x32, 0x86, 0x1c, 0xba, 0x3a, 0x72, 0xfe, 0x79, 0x83, 0x03, + 0x39, 0xca, 0x9c, 0xf9, 0xc4, 0x8f, 0x88, 0xb5, 0xf4, 0x4c, 0x9d, 0x39, + 0x7b, 0x82, 0x18, 0x72, 0x9c, 0xf0, 0x78, 0x08, 0xaf, 0xb8, 0x20, 0x56, + 0x72, 0xfe, 0xee, 0x2a, 0xf1, 0x39, 0xcb, 0xe8, 0xff, 0x87, 0x43, 0x97, + 0xe7, 0xdf, 0x92, 0x63, 0x97, 0xf9, 0x35, 0x13, 0xbe, 0x96, 0x72, 0xde, + 0xf8, 0x8f, 0x8c, 0x24, 0x59, 0x26, 0x8b, 0xb6, 0x4f, 0xe2, 0x8b, 0xff, + 0xda, 0x58, 0xe7, 0x11, 0xc8, 0xd4, 0x6c, 0xe5, 0xfe, 0x79, 0xbb, 0x8c, + 0xcd, 0x9c, 0xac, 0x3f, 0xce, 0x29, 0x37, 0xf8, 0x55, 0xf9, 0x1c, 0x53, + 0x89, 0xcb, 0xf2, 0xbe, 0xcc, 0x61, 0xca, 0xc3, 0xe1, 0x43, 0x9b, 0xff, + 0xd3, 0x0e, 0x2a, 0xab, 0xfb, 0x68, 0x33, 0x1c, 0xbf, 0x60, 0x53, 0x5b, + 0x39, 0x7e, 0x52, 0x48, 0x0d, 0x9c, 0xbf, 0x69, 0x71, 0x93, 0x9c, 0xbd, + 0xef, 0x72, 0x72, 0xff, 0xee, 0x56, 0x9d, 0xf9, 0xc1, 0x9d, 0x46, 0x1c, + 0xa0, 0x1f, 0x47, 0x87, 0xae, 0xff, 0x47, 0x2b, 0x11, 0x95, 0xb8, 0x48, + 0x34, 0x22, 0xb4, 0x4e, 0x9a, 0x83, 0x09, 0xdb, 0x87, 0x9d, 0x42, 0xe6, + 0x0e, 0x46, 0xd4, 0x90, 0xda, 0xec, 0x21, 0x1c, 0x83, 0xd1, 0xce, 0x5f, + 0xf8, 0x51, 0x4e, 0x73, 0x8f, 0x30, 0xa1, 0xcb, 0xff, 0xc9, 0x9a, 0x0c, + 0x37, 0x9d, 0x8e, 0x76, 0x72, 0xf9, 0x48, 0xd0, 0x0e, 0x5f, 0xfa, 0x39, + 0xef, 0x62, 0x78, 0xfd, 0x87, 0x2e, 0x7d, 0x1c, 0xbf, 0xbc, 0x93, 0xb2, + 0x16, 0x72, 0x82, 0x78, 0x9d, 0x16, 0xbf, 0xfc, 0x09, 0xa4, 0x9a, 0x94, + 0xd2, 0x4d, 0x48, 0xe5, 0xef, 0x24, 0xe7, 0x2b, 0x93, 0xea, 0xd2, 0x6d, + 0xf9, 0x99, 0xfe, 0xa7, 0x39, 0x76, 0x70, 0x1c, 0xbe, 0x02, 0x83, 0x23, + 0x96, 0x71, 0x37, 0x9e, 0x19, 0xbf, 0x6f, 0x78, 0x20, 0x39, 0x40, 0x3c, + 0xc1, 0x25, 0xa8, 0x4e, 0x09, 0x21, 0x18, 0xe4, 0x7f, 0xc2, 0xca, 0xee, + 0x66, 0x39, 0x7e, 0x53, 0xc0, 0x66, 0x1c, 0xa6, 0x1e, 0x10, 0x06, 0x6f, + 0x2e, 0x36, 0x72, 0xff, 0xa4, 0xfa, 0xf0, 0xc3, 0x36, 0x72, 0xff, 0x40, + 0x63, 0x5f, 0xc0, 0x0e, 0x5c, 0xcd, 0xcc, 0x7d, 0x6c, 0x38, 0xbf, 0xfe, + 0x8c, 0xe7, 0xdd, 0xc4, 0x92, 0x2a, 0xae, 0x1c, 0xbf, 0xff, 0x9d, 0xb0, + 0xbb, 0xea, 0x7e, 0xbf, 0xba, 0x9a, 0x91, 0xcb, 0xff, 0x43, 0x8e, 0x7b, + 0xc8, 0xdf, 0x8e, 0x54, 0x27, 0x83, 0x84, 0x49, 0x08, 0x7d, 0x17, 0x8a, + 0x87, 0xeb, 0x95, 0xc3, 0x32, 0xd9, 0xa1, 0x1a, 0x53, 0xab, 0x58, 0xd8, + 0xb4, 0x39, 0x92, 0xba, 0x47, 0xb9, 0x40, 0xfe, 0x94, 0x93, 0x7f, 0x47, + 0xfc, 0xa7, 0x3c, 0x07, 0x2f, 0xd8, 0xde, 0x73, 0xe3, 0x95, 0xf0, 0xf7, + 0x10, 0xce, 0xff, 0x73, 0x2c, 0x0f, 0x72, 0x73, 0x95, 0xa3, 0xd8, 0x12, + 0x3b, 0xda, 0xcd, 0x9c, 0xbf, 0x20, 0xf1, 0xc9, 0x1c, 0xa5, 0x4f, 0x11, + 0x83, 0x97, 0xf4, 0x4f, 0x9e, 0xc6, 0x1c, 0xbf, 0xfb, 0x07, 0xf5, 0xf7, + 0x19, 0x33, 0xac, 0xe5, 0x22, 0x25, 0x74, 0x47, 0xb2, 0xdb, 0xe6, 0x24, + 0x04, 0xe5, 0xfe, 0x15, 0x7b, 0x0c, 0x60, 0x9c, 0xbf, 0x9a, 0xd2, 0x38, + 0x3f, 0xf1, 0xcb, 0xf4, 0x4d, 0x98, 0xb3, 0x95, 0x08, 0xaf, 0xc2, 0x14, + 0x33, 0xe9, 0xa5, 0xff, 0xbb, 0x93, 0x24, 0xdf, 0xf0, 0x7f, 0xb3, 0x97, + 0x93, 0x4a, 0x9c, 0xa4, 0x3e, 0x31, 0x46, 0xbf, 0x47, 0x07, 0x62, 0x63, + 0x95, 0x23, 0xcb, 0xd9, 0x05, 0xff, 0xdf, 0xcc, 0x9d, 0x8e, 0x65, 0x13, + 0x41, 0xcb, 0xf0, 0x5c, 0x63, 0xa7, 0x2f, 0xe9, 0x47, 0x3e, 0xce, 0x9c, + 0xbf, 0xfd, 0xed, 0xa0, 0x22, 0x5b, 0xcc, 0xe7, 0xc7, 0x2a, 0x63, 0xf8, + 0xd9, 0x75, 0x75, 0x18, 0x2d, 0xc2, 0x7a, 0xff, 0x75, 0xe6, 0xc4, 0xe0, + 0x09, 0xca, 0x43, 0xdf, 0xd9, 0x4d, 0xff, 0xfb, 0x5f, 0xeb, 0x50, 0x38, + 0xaa, 0x77, 0xb8, 0xa1, 0xcb, 0xf3, 0xa0, 0x60, 0x4e, 0x5d, 0x1f, 0x9c, + 0xa1, 0x37, 0x9b, 0x25, 0xbe, 0x9e, 0x38, 0x20, 0xe5, 0xf7, 0x40, 0xfe, + 0x39, 0x6e, 0x9c, 0xb7, 0x17, 0x36, 0x7f, 0x91, 0x5f, 0xfc, 0x8c, 0x4d, + 0xf6, 0x13, 0x5f, 0xb5, 0x9c, 0xa8, 0x46, 0x42, 0x2c, 0x39, 0x4d, 0xfc, + 0x3b, 0x4e, 0x30, 0x13, 0x97, 0x85, 0x15, 0x39, 0x7f, 0x79, 0x34, 0x9e, + 0xfc, 0xe5, 0xa1, 0x87, 0x94, 0xa0, 0xe5, 0xfd, 0xfa, 0x9d, 0xce, 0x76, + 0x72, 0xff, 0xff, 0xfd, 0xa8, 0xf0, 0xba, 0xd3, 0x73, 0x26, 0x97, 0x1b, + 0xf4, 0x73, 0x0a, 0x66, 0xce, 0x5f, 0xee, 0xe7, 0x31, 0xa4, 0x61, 0xcb, + 0xff, 0xff, 0xfe, 0xde, 0x7b, 0xae, 0xcd, 0xeb, 0x49, 0xcf, 0x9d, 0xd5, + 0xcc, 0x9b, 0xff, 0x43, 0x7c, 0xc1, 0xcb, 0xf7, 0xf3, 0x63, 0x4c, 0x39, + 0x5b, 0x46, 0x1f, 0xa1, 0x31, 0x7f, 0xdc, 0xec, 0x51, 0x9e, 0xc6, 0xb3, + 0x97, 0x66, 0x8e, 0x54, 0x1e, 0x97, 0x4f, 0x2f, 0xef, 0x0b, 0x83, 0x04, + 0xe5, 0xf8, 0x5c, 0x18, 0x27, 0x2b, 0xe1, 0xe8, 0x78, 0xae, 0xa1, 0x54, + 0x40, 0x61, 0x06, 0xf0, 0xf6, 0xf3, 0xd7, 0xee, 0x37, 0xfe, 0xf2, 0x6c, + 0x5f, 0xd3, 0x38, 0x4e, 0x5f, 0x01, 0xf9, 0xd9, 0xcb, 0x9b, 0x6c, 0xe5, + 0x6c, 0xde, 0x36, 0x47, 0x7d, 0xd7, 0xce, 0x94, 0xfa, 0x68, 0xab, 0x11, + 0x9e, 0x90, 0x9c, 0xbf, 0x29, 0x8c, 0x4d, 0x1c, 0xbf, 0xef, 0xfd, 0x02, + 0xb6, 0xac, 0x0c, 0x39, 0x7b, 0xb0, 0x03, 0x97, 0xfe, 0xfc, 0x3d, 0x4d, + 0x27, 0x33, 0x41, 0xca, 0xc4, 0x62, 0x21, 0x43, 0x9f, 0x88, 0xe5, 0xee, + 0xfc, 0x6b, 0x39, 0x7e, 0xec, 0x0e, 0x4e, 0x72, 0xa0, 0xf2, 0x5c, 0x8a, + 0xff, 0x76, 0x3d, 0xfb, 0x3f, 0xf1, 0xca, 0x86, 0x62, 0x8c, 0xa1, 0xf4, + 0x18, 0x6f, 0x73, 0x0e, 0x86, 0xb2, 0x29, 0xa3, 0x67, 0xd1, 0x0b, 0x21, + 0x27, 0xd8, 0x74, 0x39, 0x68, 0x1e, 0x38, 0x72, 0x81, 0x95, 0x73, 0xb8, + 0xc9, 0x3d, 0x0e, 0xae, 0x30, 0x82, 0xe0, 0x20, 0xbe, 0x4d, 0x29, 0x31, + 0xcb, 0xff, 0x08, 0x18, 0xf2, 0x18, 0xf6, 0xce, 0x5d, 0x98, 0x72, 0xf9, + 0x7d, 0x45, 0x0e, 0x57, 0x51, 0x32, 0xe4, 0x9c, 0x39, 0xea, 0x82, 0xb7, + 0xe9, 0xa2, 0x6e, 0xc1, 0xcb, 0xff, 0xc3, 0xed, 0xa9, 0xe4, 0x1f, 0xe5, + 0x9b, 0x39, 0x72, 0x90, 0x72, 0xf3, 0x6d, 0xb6, 0x52, 0xfa, 0x5e, 0xc5, + 0x94, 0xfa, 0x68, 0x2f, 0xd8, 0x14, 0x06, 0xcf, 0x77, 0xf2, 0xb4, 0x7d, + 0x02, 0x69, 0x50, 0x99, 0xa6, 0x14, 0xe9, 0x2d, 0xe1, 0x3f, 0x77, 0xb6, + 0x72, 0xff, 0x7b, 0xb1, 0xed, 0xf5, 0x0e, 0x5f, 0xbe, 0x64, 0xc9, 0x39, + 0xca, 0xf8, 0x7b, 0xdb, 0x33, 0xb6, 0xce, 0x5f, 0xef, 0x73, 0x2e, 0xc0, + 0xce, 0x52, 0xff, 0xd9, 0xcc, 0x93, 0x04, 0x70, 0x27, 0x2f, 0xd3, 0xb3, + 0xfe, 0x7c, 0x72, 0xa1, 0x34, 0x7e, 0x5d, 0x74, 0x48, 0x22, 0x3b, 0x35, + 0xf1, 0xe5, 0x90, 0xe5, 0xf3, 0xa8, 0xe1, 0x39, 0x77, 0x32, 0x73, 0x65, + 0xf8, 0x85, 0xff, 0x0c, 0x37, 0xb4, 0x1e, 0x64, 0x72, 0xe8, 0x59, 0xca, + 0x13, 0xcf, 0xe2, 0x73, 0x7d, 0x3a, 0x90, 0xd6, 0x72, 0xfc, 0x30, 0xde, + 0x09, 0xcb, 0xfe, 0xef, 0x30, 0xac, 0xd2, 0x86, 0xb3, 0x96, 0xd8, 0x4f, + 0x97, 0x09, 0xab, 0x48, 0xb3, 0xf4, 0x23, 0x2a, 0x15, 0x02, 0x64, 0x22, + 0x51, 0xf5, 0xe1, 0xad, 0x7f, 0x0f, 0x3b, 0x9b, 0x3c, 0x72, 0xfe, 0x4f, + 0x0b, 0x83, 0x67, 0x2f, 0xff, 0x7a, 0x6c, 0xd6, 0x3b, 0x23, 0xa8, 0x13, + 0x97, 0xf7, 0xec, 0xce, 0xf2, 0xe7, 0x29, 0x54, 0x52, 0x09, 0x66, 0xd2, + 0x6f, 0xff, 0x20, 0x45, 0xf9, 0x1c, 0xf6, 0x20, 0x0e, 0x5f, 0x2c, 0x3f, + 0xce, 0x72, 0xf4, 0xb7, 0xf9, 0xcb, 0xa3, 0xd8, 0x78, 0x7d, 0x25, 0xbf, + 0x75, 0xf5, 0x9a, 0x39, 0x77, 0xee, 0x72, 0x96, 0x6f, 0x84, 0x9e, 0xfa, + 0x5e, 0xfc, 0x27, 0x2f, 0xd0, 0x92, 0x7d, 0x9c, 0xae, 0x4f, 0x2b, 0x44, + 0x97, 0xfe, 0xe7, 0x68, 0xae, 0x79, 0x35, 0x87, 0x2d, 0x13, 0xa3, 0x30, + 0x5a, 0xbc, 0x47, 0x7e, 0x9d, 0xad, 0x33, 0x93, 0x97, 0xe4, 0xdc, 0x4e, + 0xc3, 0xd9, 0xfa, 0xbf, 0x43, 0xe8, 0x1f, 0x9e, 0xcf, 0xd5, 0xcf, 0x23, + 0xd9, 0xfa, 0xbe, 0xfe, 0x59, 0xb3, 0xd9, 0xfa, 0xa0, 0x9e, 0x98, 0x91, + 0xdf, 0xa3, 0x37, 0x82, 0x7b, 0x3f, 0x54, 0x7b, 0x3f, 0x57, 0x3f, 0x8f, + 0x67, 0xe9, 0x85, 0xc5, 0xa4, 0x27, 0xf9, 0xfa, 0x55, 0xf6, 0x34, 0x40, + 0x1e, 0xcf, 0xd5, 0x1e, 0xcf, 0xd5, 0xc0, 0x83, 0xd9, 0xfa, 0xbf, 0xec, + 0x03, 0xeb, 0x38, 0xe0, 0x4f, 0x67, 0xea, 0xfe, 0xce, 0xa6, 0xff, 0x9c, + 0xf6, 0x7e, 0xa8, 0x08, 0xa5, 0x12, 0x3d, 0xa3, 0x5f, 0x6a, 0x78, 0xf1, + 0xec, 0xfd, 0x51, 0xec, 0xfd, 0x61, 0xb0, 0xb9, 0xb6, 0xcf, 0x67, 0xea, + 0xa4, 0xac, 0x6c, 0x26, 0xb9, 0x08, 0x8e, 0x61, 0x3b, 0xa2, 0x86, 0x18, + 0x6e, 0x17, 0xbe, 0x5f, 0x6c, 0x9e, 0xf4, 0xa1, 0x52, 0xd9, 0xfa, 0x7d, + 0x44, 0x85, 0xfd, 0x18, 0xa4, 0x4a, 0x47, 0x2f, 0xf6, 0xf2, 0x52, 0x8f, + 0x72, 0x72, 0xb1, 0x14, 0x02, 0x7f, 0xb2, 0xdb, 0xff, 0x62, 0xc3, 0x9a, + 0x6d, 0xfb, 0x31, 0xcb, 0xff, 0xb6, 0x39, 0x34, 0x4e, 0x07, 0xe7, 0x67, + 0x2e, 0x94, 0xe5, 0x2f, 0xa6, 0x77, 0xd1, 0xca, 0x9d, 0x1d, 0xdc, 0x97, + 0x75, 0x00, 0x51, 0xb8, 0x06, 0x2e, 0x49, 0xce, 0x56, 0x97, 0x72, 0x9e, + 0x75, 0x97, 0xc9, 0xd7, 0xf9, 0x9b, 0x1c, 0xf6, 0x00, 0xe5, 0xfd, 0xec, + 0xec, 0x68, 0x07, 0x2f, 0xf9, 0x70, 0x00, 0xfe, 0xfa, 0x91, 0xcb, 0xff, + 0x3b, 0xcf, 0x8c, 0x71, 0xe6, 0x47, 0x2f, 0x3a, 0xbb, 0xc3, 0xf8, 0x98, + 0xea, 0xcd, 0xfc, 0x46, 0xc8, 0xc2, 0x96, 0xa1, 0x33, 0xb7, 0x8c, 0x2e, + 0xfc, 0x3e, 0xee, 0x4e, 0x72, 0xe0, 0xb6, 0x72, 0xa0, 0xf0, 0x30, 0xa2, + 0xff, 0xfd, 0x2d, 0x47, 0x17, 0x9a, 0x03, 0xd8, 0x63, 0xcc, 0x72, 0xff, + 0x70, 0x3e, 0xd3, 0x73, 0x61, 0xca, 0xe5, 0x11, 0xda, 0x58, 0xa8, 0x67, + 0xa0, 0xca, 0x5c, 0x5e, 0x22, 0xa4, 0x34, 0xda, 0xcc, 0x35, 0x08, 0xae, + 0xc6, 0x6c, 0xf3, 0xbf, 0xe3, 0x1b, 0xae, 0xda, 0x3f, 0x85, 0x75, 0xff, + 0xff, 0x27, 0x5f, 0xb1, 0x2f, 0xb8, 0x08, 0x96, 0xc3, 0xd8, 0xd1, 0xcb, + 0xff, 0x2b, 0x1c, 0x8c, 0x77, 0xbf, 0xac, 0xe5, 0xff, 0xda, 0x8c, 0x1c, + 0x92, 0x77, 0x38, 0x9c, 0xbf, 0xfe, 0x17, 0x57, 0x79, 0xc6, 0x39, 0xf6, + 0xff, 0x61, 0xca, 0x0a, 0x25, 0xc5, 0x0e, 0xfe, 0x17, 0x57, 0xaf, 0x23, + 0x97, 0xe5, 0xe3, 0x23, 0x67, 0x2f, 0x36, 0xdb, 0x65, 0x2f, 0x29, 0x00, + 0x29, 0xf4, 0xd0, 0x5f, 0xf3, 0xc9, 0x4d, 0x67, 0x17, 0xd1, 0xcb, 0xff, + 0xf7, 0x72, 0x4a, 0x08, 0xe4, 0xf3, 0x4a, 0x35, 0x39, 0xca, 0x14, 0x49, + 0xf8, 0xee, 0xff, 0xf0, 0x22, 0x4e, 0x32, 0x46, 0x67, 0x3e, 0x39, 0x7f, + 0xde, 0x71, 0xcd, 0xea, 0x36, 0x72, 0xfa, 0x50, 0x0e, 0x4e, 0x5f, 0xc0, + 0x81, 0xce, 0x7c, 0x72, 0xe7, 0x07, 0xc3, 0xd0, 0x50, 0x8e, 0xff, 0xf2, + 0x83, 0x32, 0xae, 0x1e, 0xe2, 0xf3, 0x47, 0x29, 0x13, 0x4c, 0x74, 0x91, + 0x84, 0x3e, 0xcc, 0x2f, 0x71, 0x8d, 0x1c, 0xa9, 0x2e, 0x31, 0x85, 0x9f, + 0x21, 0xb0, 0xc2, 0x27, 0x2d, 0x02, 0x38, 0xc3, 0x0b, 0xd1, 0xb7, 0x71, + 0x40, 0xb9, 0x27, 0x39, 0x7f, 0x85, 0x61, 0x4e, 0x30, 0x13, 0x94, 0x13, + 0xcb, 0xfc, 0x5e, 0xc0, 0x39, 0x7f, 0xd9, 0x0d, 0x7f, 0x3a, 0xf9, 0xa3, + 0x97, 0x98, 0x93, 0x1c, 0xbf, 0x60, 0x37, 0x12, 0x39, 0x7e, 0x46, 0x04, + 0x38, 0x72, 0xc0, 0x13, 0xce, 0x68, 0x4f, 0x7f, 0xde, 0xee, 0x6f, 0xe7, + 0x92, 0x73, 0x95, 0x07, 0xca, 0x85, 0x37, 0xfc, 0x29, 0xff, 0x0f, 0xb6, + 0x91, 0xe3, 0x95, 0x24, 0xdf, 0x66, 0x11, 0x61, 0xe7, 0x61, 0xa0, 0x24, + 0x17, 0xd9, 0xe5, 0x27, 0x39, 0x79, 0xb6, 0xdb, 0x2c, 0x42, 0x05, 0xf2, + 0xdd, 0xd6, 0x58, 0x84, 0x0f, 0xa6, 0xba, 0xf9, 0xf5, 0x8d, 0x9c, 0xad, + 0x1f, 0x1f, 0x14, 0x1b, 0xcd, 0xb6, 0xd9, 0x62, 0x0f, 0x28, 0xb1, 0x07, + 0x9f, 0x4d, 0x75, 0xfd, 0x9e, 0xef, 0xef, 0x23, 0x97, 0x9b, 0x6d, 0xb3, + 0x97, 0xb7, 0x0a, 0x94, 0xfa, 0x68, 0x2b, 0x11, 0xf4, 0xb5, 0x21, 0x2b, + 0xf2, 0x75, 0x35, 0xa7, 0xd4, 0xc8, 0xeb, 0xef, 0xfe, 0xec, 0x49, 0x3d, + 0x9d, 0x5c, 0x30, 0xe5, 0x41, 0xf8, 0x71, 0x2d, 0xbf, 0xed, 0x8c, 0x33, + 0x7b, 0xfc, 0x4e, 0x5f, 0xfe, 0xce, 0xa6, 0xba, 0xf9, 0xb4, 0x79, 0xce, + 0x5f, 0x47, 0xa1, 0x87, 0x2b, 0x94, 0x51, 0x30, 0xe7, 0xc9, 0x17, 0xf3, + 0x6e, 0x1f, 0xdd, 0x43, 0x97, 0xc2, 0x90, 0xa9, 0xcb, 0xca, 0x40, 0x0e, + 0x54, 0xe6, 0xf9, 0x84, 0x37, 0xe5, 0xc7, 0x61, 0x85, 0x2f, 0xc2, 0xe2, + 0x38, 0x52, 0xec, 0x59, 0x4b, 0x9b, 0x6c, 0xa5, 0x61, 0xfd, 0x6c, 0x9f, + 0xc4, 0x8d, 0x8b, 0x5f, 0xe1, 0x52, 0x01, 0xdc, 0xe0, 0x29, 0xf4, 0xde, + 0x5f, 0xfe, 0x9c, 0x3a, 0x75, 0x8e, 0x71, 0xd2, 0x6c, 0xe5, 0x42, 0xa0, + 0xbc, 0x31, 0x46, 0xe7, 0x86, 0xc7, 0xe9, 0x17, 0xff, 0x40, 0x37, 0x98, + 0x17, 0x17, 0x54, 0xe5, 0xff, 0xfb, 0xa9, 0xc5, 0x04, 0x3b, 0x8d, 0x26, + 0x73, 0xb3, 0x97, 0xf0, 0xc6, 0x69, 0xc0, 0x72, 0xff, 0xd1, 0xae, 0xc2, + 0x76, 0x05, 0x0e, 0x5d, 0x2d, 0xad, 0x17, 0x9e, 0x56, 0x6c, 0xae, 0xff, + 0x40, 0xe3, 0x13, 0x99, 0x1c, 0xbf, 0xfe, 0xd8, 0xe7, 0x20, 0x7d, 0xbe, + 0x93, 0x90, 0x1c, 0xae, 0x51, 0x7f, 0xe3, 0xd6, 0xcc, 0xab, 0xa9, 0xf7, + 0xbc, 0x77, 0xb7, 0xf6, 0xd4, 0x0f, 0xe3, 0x23, 0x97, 0xf2, 0x2c, 0x38, + 0xe0, 0x39, 0x7f, 0xfe, 0xf6, 0xf9, 0xf8, 0x1c, 0x0c, 0x3e, 0xb0, 0x40, + 0x72, 0xff, 0xff, 0xdf, 0x3d, 0x2c, 0x03, 0x4c, 0xf8, 0x1c, 0x0c, 0x3e, + 0xb0, 0x40, 0x44, 0x2f, 0xfe, 0xcf, 0x7c, 0x5f, 0x53, 0xbd, 0x40, 0x1a, + 0x10, 0xb5, 0x49, 0x18, 0xfb, 0x74, 0xbd, 0x13, 0xfd, 0xda, 0x68, 0x3e, + 0x8c, 0x7a, 0xfc, 0xcd, 0xb6, 0xfc, 0x9c, 0xb6, 0xc2, 0x7d, 0x0a, 0x1f, + 0x5f, 0xd9, 0x34, 0x93, 0x5b, 0x39, 0x7f, 0x47, 0x2a, 0x6e, 0x30, 0xe5, + 0x43, 0x33, 0x94, 0x30, 0xdb, 0xc8, 0xe8, 0x12, 0x55, 0x56, 0xa5, 0x68, + 0x3c, 0xa3, 0xde, 0x1c, 0xa4, 0x4c, 0x37, 0x1e, 0xaf, 0x8a, 0x7f, 0x2e, + 0xbc, 0xdb, 0x6d, 0x94, 0xbc, 0xe2, 0x12, 0x9f, 0x4d, 0x05, 0xf6, 0x6b, + 0x3c, 0x72, 0x80, 0x79, 0xdb, 0x2d, 0xbe, 0xea, 0x3c, 0x8e, 0x5f, 0xef, + 0x6d, 0x35, 0xa4, 0x61, 0xcb, 0xcc, 0x9c, 0x27, 0x28, 0x4f, 0x47, 0xc6, + 0x77, 0xbe, 0x2a, 0xd0, 0xe5, 0xef, 0x38, 0x4e, 0x56, 0x8d, 0xf6, 0xc8, + 0xaf, 0xe5, 0xc0, 0x13, 0x4a, 0x94, 0xbf, 0x94, 0xcd, 0x66, 0x4c, 0x72, + 0xfc, 0xfd, 0xf8, 0x18, 0x39, 0x52, 0x4e, 0x64, 0x24, 0x58, 0xe4, 0x8b, + 0xe2, 0x43, 0xb2, 0xef, 0x17, 0x5f, 0x9f, 0x5a, 0xce, 0x4e, 0x5f, 0xfe, + 0xf7, 0x51, 0xc1, 0x9a, 0x0c, 0x0c, 0x8e, 0x5f, 0xfe, 0xe7, 0xe7, 0x20, + 0x81, 0x5b, 0xce, 0x2e, 0x72, 0xa1, 0x17, 0xb8, 0x50, 0x29, 0x17, 0xe8, + 0xda, 0x83, 0x23, 0x97, 0xdf, 0x16, 0x92, 0x39, 0x7f, 0xe5, 0xe6, 0xb1, + 0x37, 0xd8, 0xe2, 0x72, 0xff, 0xff, 0xe7, 0x4f, 0x27, 0x56, 0x9f, 0x24, + 0x9d, 0x71, 0xf4, 0xb3, 0x58, 0x72, 0xf7, 0x73, 0x80, 0xe5, 0x75, 0x11, + 0xee, 0xe1, 0x7f, 0xc3, 0x1c, 0xee, 0x3d, 0x01, 0x39, 0x7b, 0x6a, 0x6f, + 0xe1, 0xed, 0x61, 0x15, 0x05, 0x38, 0x2e, 0x49, 0x3d, 0x19, 0x45, 0xff, + 0xff, 0xff, 0x46, 0xe3, 0xd3, 0xe3, 0x7a, 0xce, 0xba, 0x9b, 0xc5, 0x5c, + 0x41, 0x03, 0x13, 0x76, 0x0e, 0x5f, 0xb7, 0xd7, 0x5c, 0x1c, 0xa1, 0x45, + 0xdb, 0x70, 0x94, 0xbf, 0xff, 0xf9, 0x15, 0xe6, 0x5e, 0xc1, 0xf6, 0xfe, + 0x6f, 0x79, 0xac, 0x17, 0x91, 0xcb, 0xff, 0xbe, 0x84, 0x63, 0xf5, 0xe2, + 0xa9, 0xa3, 0x97, 0x63, 0x67, 0x2d, 0x90, 0x7b, 0xdb, 0x47, 0xbf, 0xa7, + 0xeb, 0xfb, 0x50, 0x72, 0xff, 0x07, 0xb1, 0x33, 0xbf, 0x27, 0x2f, 0x74, + 0x1c, 0x4e, 0x56, 0x8f, 0x4f, 0x80, 0xd2, 0xa4, 0x8c, 0xcd, 0x13, 0x3c, + 0x20, 0x6f, 0xfe, 0xcd, 0x01, 0x89, 0xb5, 0x37, 0x18, 0x72, 0xfc, 0x1d, + 0x47, 0x2d, 0x67, 0x2f, 0xff, 0xfd, 0xe8, 0xd0, 0x17, 0xd4, 0x92, 0x69, + 0xc1, 0xe1, 0x86, 0x6c, 0xe5, 0xcd, 0x7b, 0x39, 0x4a, 0xa2, 0x15, 0xda, + 0xea, 0x49, 0x8c, 0x62, 0x23, 0xc2, 0xc6, 0xf3, 0x52, 0x20, 0x39, 0x76, + 0x30, 0xe5, 0xff, 0xd8, 0x20, 0xf8, 0xa6, 0x80, 0xc4, 0xd9, 0xca, 0x09, + 0xee, 0xb0, 0x5a, 0xf8, 0x1e, 0xc0, 0x1c, 0xbf, 0x46, 0xf6, 0x9c, 0x4e, + 0x52, 0x1f, 0x6e, 0x88, 0xba, 0x45, 0x79, 0xa7, 0x30, 0x72, 0xff, 0x97, + 0xd1, 0x8e, 0x52, 0x3a, 0x72, 0xa1, 0x91, 0x3f, 0x28, 0xc7, 0xc2, 0x5b, + 0x91, 0xd5, 0x24, 0x3c, 0xf4, 0x50, 0xf1, 0xcf, 0x0c, 0x69, 0x9b, 0x34, + 0xfe, 0x1d, 0x6d, 0x0b, 0x94, 0x1f, 0xbf, 0xf3, 0xa0, 0x7f, 0xf6, 0xe7, + 0xc6, 0xce, 0x5f, 0xb7, 0x8a, 0xc6, 0xce, 0x5f, 0xcd, 0x7b, 0x41, 0xe6, + 0x47, 0x2f, 0xfc, 0xfa, 0x68, 0x9d, 0xc7, 0xe4, 0x07, 0x2f, 0xff, 0xc9, + 0xe8, 0x66, 0x73, 0xe8, 0x62, 0x9a, 0x70, 0x1c, 0xbe, 0x41, 0x70, 0x9c, + 0xbf, 0xed, 0xc6, 0xbd, 0x1f, 0x42, 0x87, 0x2a, 0x48, 0xb0, 0x0a, 0xb6, + 0xc8, 0x2f, 0xff, 0x6d, 0x35, 0x12, 0xec, 0x4c, 0x3f, 0xaa, 0x72, 0xe5, + 0xb4, 0x39, 0x7f, 0x2b, 0xe8, 0xec, 0x6c, 0xe5, 0xfd, 0xd4, 0xe7, 0x6f, + 0xc9, 0xca, 0x91, 0xfb, 0x20, 0xc8, 0x0b, 0xaf, 0xf9, 0xe6, 0xeb, 0xeb, + 0x48, 0x13, 0x97, 0xc9, 0xd7, 0x61, 0xcb, 0xfe, 0x11, 0xc9, 0xfd, 0xe8, + 0x61, 0xca, 0x14, 0x49, 0x78, 0xe5, 0x42, 0x1b, 0xf6, 0xb3, 0x68, 0xd9, + 0xcb, 0xd0, 0xd4, 0x5c, 0xe5, 0xfc, 0xa4, 0x7e, 0xbf, 0xd8, 0x72, 0xe4, + 0x13, 0x97, 0xd2, 0x81, 0x59, 0xca, 0x09, 0xb6, 0xc1, 0x5b, 0xfa, 0x3d, + 0xc2, 0x3c, 0x72, 0x72, 0xbe, 0x1e, 0x92, 0x10, 0x5f, 0x40, 0x30, 0x4e, + 0x54, 0x97, 0x1c, 0x30, 0xa1, 0x66, 0x29, 0x0f, 0x09, 0x8c, 0x35, 0x0c, + 0x26, 0x43, 0x01, 0xcc, 0x36, 0x51, 0xf9, 0x0b, 0x70, 0xb9, 0x68, 0x47, + 0x7c, 0xce, 0x14, 0xd4, 0x5a, 0xb3, 0x97, 0x7b, 0x67, 0x29, 0x0f, 0x2e, + 0x63, 0x4b, 0xe5, 0x21, 0xbd, 0x9c, 0xb8, 0x1e, 0x39, 0x70, 0x3a, 0x72, + 0xfb, 0x5a, 0xcd, 0x9c, 0xbb, 0x26, 0x39, 0x69, 0x7c, 0x44, 0x5c, 0xe4, + 0x8c, 0x17, 0x71, 0x75, 0x08, 0xaf, 0xc9, 0xe7, 0x1c, 0x39, 0x7e, 0xd0, + 0x73, 0x04, 0xe5, 0xff, 0xcd, 0x69, 0x9d, 0x8e, 0x3b, 0xec, 0x72, 0x72, + 0xfe, 0xe7, 0x5f, 0xf3, 0xe9, 0x1c, 0xa7, 0x45, 0x0e, 0xc9, 0xbf, 0x49, + 0xbf, 0x37, 0xef, 0x64, 0xe7, 0x2f, 0xfb, 0x07, 0x59, 0xbc, 0x4e, 0x9c, + 0xbf, 0xfe, 0x97, 0x87, 0x1f, 0xc3, 0x9e, 0xf6, 0x36, 0x72, 0xec, 0xe2, + 0x72, 0xff, 0x97, 0xdc, 0x0b, 0x13, 0x58, 0x72, 0xa7, 0x3d, 0x0c, 0x18, + 0xbf, 0xa2, 0x35, 0xd8, 0xe2, 0x72, 0xff, 0xf7, 0xb7, 0x93, 0x76, 0x38, + 0xe7, 0x7b, 0x07, 0x2f, 0xee, 0x85, 0x38, 0xc0, 0x4e, 0x56, 0x1f, 0xdb, + 0xa6, 0x5f, 0x6d, 0x30, 0x07, 0x2f, 0xb3, 0xc9, 0xb3, 0x97, 0xf3, 0x53, + 0x30, 0xb5, 0x73, 0xfe, 0x72, 0xb6, 0x7b, 0x9e, 0x21, 0xa9, 0x2b, 0x7e, + 0x0c, 0x31, 0xb0, 0xc1, 0x65, 0x5c, 0x9b, 0x6a, 0x13, 0xdd, 0x22, 0x18, + 0x54, 0xec, 0x83, 0xcf, 0xb7, 0xff, 0xef, 0x26, 0xe7, 0xc6, 0xf6, 0x93, + 0x8b, 0xf3, 0xe3, 0x97, 0x9b, 0xce, 0x9c, 0xbf, 0xdb, 0x45, 0x7a, 0xe2, + 0x87, 0x2f, 0xd3, 0x84, 0x5d, 0x53, 0x97, 0xc9, 0xbc, 0x0e, 0x23, 0x41, + 0xd6, 0x3c, 0x3a, 0xa1, 0x95, 0xff, 0x9d, 0xac, 0x1f, 0xed, 0x07, 0x99, + 0x1c, 0xbf, 0xc1, 0xc1, 0x46, 0xfb, 0xf9, 0xcb, 0xff, 0xee, 0xa4, 0x79, + 0x01, 0x12, 0xfa, 0xdb, 0x6d, 0x94, 0xbf, 0xf9, 0x23, 0xc0, 0x89, 0x7d, + 0x6d, 0xb6, 0xca, 0x56, 0x22, 0x77, 0xaa, 0x95, 0x3a, 0x3c, 0xfd, 0x0d, + 0x1b, 0xfd, 0xdf, 0xdd, 0x81, 0x76, 0x1c, 0xa1, 0x3d, 0xdf, 0x14, 0xdf, + 0x07, 0x31, 0x52, 0x97, 0xce, 0x07, 0xf1, 0xcb, 0xfe, 0xd3, 0xaf, 0xe7, + 0x61, 0x41, 0x39, 0x7b, 0xf8, 0xd1, 0xcb, 0xbd, 0xb0, 0x9e, 0xc4, 0xc7, + 0x77, 0xa4, 0x3f, 0x9a, 0x21, 0x95, 0xee, 0xc4, 0xe7, 0x2f, 0xde, 0x89, + 0x2a, 0xc3, 0x97, 0x9b, 0x6d, 0xb2, 0x97, 0xb0, 0x56, 0x53, 0xe9, 0xa0, + 0xbf, 0xf6, 0x4f, 0x81, 0x79, 0x0c, 0x4e, 0x72, 0xa1, 0x16, 0x80, 0x49, + 0x12, 0xdb, 0xe7, 0x16, 0xa1, 0xc3, 0x1c, 0xb9, 0xa8, 0x35, 0x03, 0x97, + 0xec, 0xf7, 0xbf, 0x9c, 0xe5, 0xa4, 0xd4, 0x0f, 0x34, 0x48, 0xef, 0x3b, + 0x5c, 0x1c, 0xbf, 0x60, 0x7a, 0xed, 0x67, 0x2f, 0xc3, 0x81, 0x86, 0x1c, + 0xa8, 0x56, 0x51, 0x39, 0x08, 0x48, 0xb1, 0xe7, 0x92, 0xf9, 0x8a, 0xb5, + 0x0d, 0x1e, 0x97, 0x3b, 0xcf, 0xe5, 0xbc, 0x47, 0x9b, 0x2a, 0xbf, 0x99, + 0x89, 0xa9, 0xa4, 0x72, 0xff, 0xf9, 0x55, 0x1c, 0x7a, 0xf2, 0xde, 0x32, + 0x1a, 0xce, 0x54, 0x22, 0x05, 0x0b, 0xaf, 0x79, 0x20, 0xe5, 0xd8, 0x27, + 0x29, 0x0d, 0x87, 0xe3, 0x77, 0xe1, 0x8e, 0x63, 0x67, 0x2f, 0xfd, 0x88, + 0x2f, 0xed, 0xb7, 0x02, 0x72, 0xf7, 0x5f, 0x50, 0x7c, 0x7b, 0x27, 0xbe, + 0x4d, 0x47, 0x8e, 0x5f, 0x6f, 0x22, 0x47, 0x28, 0x27, 0x84, 0x24, 0x37, + 0xe8, 0x97, 0x73, 0x93, 0x97, 0x72, 0x03, 0x97, 0xf3, 0x23, 0x60, 0x45, + 0x9c, 0xbd, 0xb8, 0x54, 0x07, 0x8b, 0xb1, 0x8b, 0xfd, 0xfe, 0x68, 0x00, + 0x41, 0x39, 0x79, 0xda, 0xb9, 0xce, 0x5f, 0xfb, 0x18, 0x81, 0xd6, 0x05, + 0xd8, 0x72, 0xfb, 0x18, 0xa0, 0x4e, 0x57, 0x4f, 0x80, 0x4f, 0x6f, 0xff, + 0x20, 0x7a, 0xa6, 0xf3, 0x4b, 0x77, 0x59, 0xa2, 0x0c, 0x5f, 0xfb, 0xbf, + 0xba, 0xb9, 0xef, 0x67, 0x4e, 0x5f, 0xfb, 0x60, 0x7e, 0x76, 0xa6, 0xba, + 0xe7, 0x2f, 0xbf, 0xee, 0x2c, 0xe5, 0x49, 0x1f, 0x61, 0x57, 0xf2, 0x03, + 0x44, 0x1b, 0xfe, 0xde, 0xe3, 0x52, 0x5a, 0x4e, 0x72, 0xfe, 0xfd, 0x51, + 0xc9, 0xff, 0x39, 0x50, 0x7d, 0x7d, 0x3a, 0xbd, 0xdf, 0xda, 0xce, 0x5f, + 0xfe, 0xd3, 0xf1, 0xc1, 0x5f, 0x50, 0x0a, 0x78, 0xe5, 0x42, 0x67, 0x12, + 0x85, 0x57, 0x0e, 0x43, 0xf9, 0x0d, 0x72, 0xae, 0x17, 0xa6, 0x82, 0x67, + 0xb8, 0x41, 0x7a, 0x52, 0xa5, 0xfe, 0xd7, 0xee, 0xa7, 0xee, 0xa1, 0xcb, + 0xb8, 0xe1, 0xca, 0xc3, 0xcf, 0x73, 0x7b, 0x80, 0x03, 0x97, 0xfc, 0xbe, + 0xa6, 0x85, 0x3d, 0xb3, 0x94, 0xc3, 0xcf, 0x00, 0xbd, 0xfe, 0x02, 0x77, + 0xb8, 0x07, 0x39, 0x7f, 0xff, 0xcc, 0xcf, 0x79, 0xf4, 0x31, 0xcc, 0x94, + 0xd0, 0x18, 0x9b, 0x39, 0x7f, 0xcc, 0x46, 0xf0, 0x43, 0xd8, 0x39, 0x77, + 0x7f, 0x39, 0x7f, 0xfe, 0x92, 0x08, 0x7b, 0x9c, 0xa8, 0xe3, 0xe1, 0x09, + 0xcb, 0xc8, 0xdb, 0x59, 0xcb, 0xfd, 0x9c, 0x77, 0xef, 0x43, 0x0e, 0x56, + 0x8f, 0x57, 0xa4, 0x15, 0x09, 0xc2, 0x63, 0x42, 0x1c, 0x4c, 0x31, 0xb8, + 0x55, 0x5f, 0xc8, 0xc5, 0xe0, 0xac, 0xe5, 0xfd, 0x9b, 0x69, 0x9a, 0x83, + 0x95, 0xa3, 0xda, 0x68, 0x59, 0x52, 0x64, 0x62, 0x86, 0x10, 0x98, 0xe8, + 0xb2, 0x14, 0x97, 0xe4, 0xc8, 0x53, 0xbb, 0x78, 0x08, 0xb7, 0x1d, 0xb7, + 0xa1, 0x51, 0x7f, 0xb7, 0xbc, 0x10, 0x34, 0xc3, 0x97, 0xc2, 0x9c, 0x10, + 0x72, 0xf9, 0x41, 0xcd, 0x9c, 0xb4, 0xc7, 0x2f, 0xed, 0xe0, 0x81, 0xa6, + 0x1c, 0xaf, 0x88, 0xb9, 0xc3, 0x47, 0x23, 0x01, 0x16, 0xc4, 0xaf, 0xbc, + 0xee, 0x27, 0x2b, 0x89, 0xf5, 0x36, 0x95, 0x7f, 0xdf, 0xf8, 0x1f, 0xb2, + 0x33, 0xc7, 0x2f, 0xff, 0x0c, 0xff, 0x26, 0x41, 0xc0, 0xe0, 0xaa, 0x72, + 0xfe, 0x4e, 0x78, 0x3b, 0x1e, 0x39, 0x79, 0x4c, 0x83, 0x97, 0xfd, 0xdc, + 0x0e, 0x9d, 0x7e, 0x01, 0xca, 0x84, 0x69, 0x35, 0xa6, 0x39, 0x8e, 0xc7, + 0x2f, 0xff, 0xf6, 0x0b, 0xfb, 0x79, 0xa0, 0x02, 0x33, 0x9f, 0x6d, 0x0e, + 0x5d, 0x8d, 0x0e, 0x59, 0xc2, 0x7e, 0xfe, 0x5f, 0xbd, 0x1a, 0x98, 0xe5, + 0x7c, 0x6f, 0xbb, 0x62, 0x72, 0xc6, 0x78, 0xc2, 0x43, 0x0a, 0xdc, 0x97, + 0xa2, 0xb8, 0xda, 0xf9, 0x52, 0x49, 0xcb, 0xbe, 0xc6, 0x62, 0xf4, 0x91, + 0x60, 0x47, 0x96, 0x24, 0xbf, 0xc6, 0x1a, 0xdc, 0x2d, 0x5a, 0x13, 0xde, + 0xe6, 0x7e, 0x27, 0x2f, 0xcb, 0xec, 0x73, 0xc0, 0x72, 0xfd, 0xd7, 0xd3, + 0x10, 0xe5, 0x7c, 0x3d, 0x35, 0x96, 0x5e, 0xf8, 0x06, 0xce, 0x57, 0x27, + 0x89, 0xe2, 0x4b, 0xfb, 0x1b, 0xcc, 0x15, 0x4e, 0x5f, 0x31, 0xf3, 0x67, + 0x29, 0x0f, 0x39, 0xcb, 0x6f, 0xff, 0x97, 0x1b, 0xdc, 0x33, 0x3c, 0x9b, + 0xeb, 0x9c, 0xbf, 0xc2, 0x31, 0x26, 0x42, 0x1c, 0xbf, 0xde, 0x4e, 0x29, + 0xe9, 0x41, 0x4b, 0x30, 0xe5, 0xfd, 0x82, 0xae, 0xa3, 0xea, 0x1e, 0x2a, + 0x86, 0x95, 0x89, 0x84, 0xa2, 0x76, 0xdd, 0x6f, 0x7f, 0xcc, 0x8e, 0x5f, + 0x4b, 0x4f, 0xc4, 0xe5, 0x68, 0xf0, 0xc4, 0x7e, 0xff, 0x0c, 0x87, 0x19, + 0x0b, 0x39, 0x79, 0xf6, 0x87, 0x2f, 0x30, 0x38, 0x72, 0xa1, 0x11, 0x38, + 0x43, 0xd3, 0x17, 0x1b, 0xbc, 0xd3, 0xff, 0x1c, 0xb9, 0x38, 0x9c, 0xbe, + 0x7d, 0x3a, 0x87, 0x2f, 0xff, 0x7a, 0x18, 0x81, 0xc1, 0x57, 0xb0, 0xc3, + 0x94, 0xb4, 0x51, 0xb0, 0x83, 0x63, 0x1e, 0x22, 0xbc, 0xaa, 0x9d, 0x39, + 0x7f, 0xfc, 0x9e, 0xec, 0x6e, 0x3b, 0x09, 0x3c, 0x2a, 0x72, 0xff, 0x76, + 0x26, 0x92, 0x6a, 0x47, 0x2f, 0xf7, 0x91, 0xb9, 0x85, 0xdb, 0x39, 0x7e, + 0xf7, 0xb6, 0xe0, 0x39, 0x7e, 0x86, 0x7b, 0x16, 0x72, 0xe4, 0x9c, 0xe5, + 0x42, 0x63, 0xc1, 0x4f, 0xe4, 0xd1, 0x0d, 0x7a, 0x51, 0xe2, 0x7b, 0xf3, + 0x68, 0x1e, 0x04, 0x39, 0x7f, 0xdd, 0x89, 0x20, 0xe3, 0x20, 0xe5, 0xff, + 0x67, 0xbb, 0x8c, 0x17, 0xf1, 0xcb, 0xfb, 0x8a, 0x6b, 0x98, 0x6b, 0x39, + 0x61, 0x09, 0xf5, 0x61, 0xbd, 0xf9, 0x90, 0xb9, 0xc2, 0x72, 0xfa, 0x50, + 0xc7, 0x39, 0x7e, 0xd0, 0x18, 0x9b, 0x39, 0x77, 0xb7, 0x87, 0xe4, 0xe5, + 0x2a, 0x10, 0xd4, 0x23, 0x4b, 0xf8, 0x4c, 0x5b, 0x67, 0x2f, 0xe8, 0x9f, + 0x05, 0x15, 0x39, 0x5a, 0x37, 0xdb, 0x11, 0xbf, 0xfa, 0x05, 0xfb, 0x00, + 0xfb, 0xad, 0xec, 0xa5, 0x4e, 0xa8, 0xf8, 0x31, 0xb9, 0x63, 0x33, 0x08, + 0x6f, 0xf3, 0x87, 0x7b, 0x8d, 0x48, 0xe5, 0xdf, 0xce, 0x72, 0xff, 0x73, + 0x2e, 0x76, 0x9e, 0x83, 0x97, 0x93, 0x9d, 0x9c, 0xac, 0x3d, 0x24, 0x35, + 0xa4, 0x44, 0x5f, 0x5a, 0xee, 0xc5, 0x9c, 0xbd, 0xac, 0xd9, 0xcf, 0x16, + 0xd7, 0xff, 0xc1, 0xf8, 0xe9, 0x9b, 0x89, 0xf0, 0x51, 0x53, 0x97, 0xfb, + 0x4c, 0x8e, 0x7c, 0xeb, 0x39, 0x7f, 0xff, 0x0e, 0x7b, 0xb9, 0x2c, 0x5c, + 0x2f, 0xc2, 0xec, 0x39, 0x58, 0x8d, 0xc4, 0x50, 0xd9, 0xa5, 0xf2, 0x32, + 0x26, 0x39, 0x7f, 0xf6, 0xd3, 0x91, 0xc9, 0xb5, 0x1e, 0xd9, 0xcb, 0xec, + 0x9f, 0xf9, 0x1c, 0xa9, 0x91, 0x16, 0x02, 0x26, 0xd1, 0x6f, 0xe0, 0x4e, + 0xf2, 0x86, 0xb3, 0x97, 0x82, 0x18, 0x39, 0x5c, 0x9e, 0x6f, 0xe6, 0x35, + 0x08, 0xa3, 0x77, 0xfb, 0xb1, 0xb3, 0x94, 0x5c, 0x43, 0x0b, 0xfb, 0x6a, + 0x46, 0xa1, 0x85, 0xc4, 0x30, 0xa2, 0xe2, 0x18, 0x51, 0x71, 0x0c, 0x28, + 0xb8, 0x86, 0x14, 0x5c, 0x43, 0x0a, 0x92, 0x2e, 0x50, 0x64, 0x07, 0x9f, + 0x8c, 0xb4, 0x19, 0xe0, 0x19, 0xbb, 0xb8, 0x5c, 0x43, 0x0b, 0xf9, 0xdf, + 0xd3, 0x43, 0x0b, 0x88, 0x61, 0xf0, 0xd2, 0x5b, 0x87, 0x2e, 0x21, 0x85, + 0x17, 0x10, 0xc2, 0x8b, 0x88, 0x61, 0x52, 0x36, 0x48, 0x33, 0x45, 0xc4, + 0x30, 0xa2, 0xe2, 0x18, 0x51, 0x71, 0x0c, 0x28, 0xb8, 0x86, 0x14, 0x5c, + 0x43, 0x0a, 0x2e, 0x21, 0x85, 0x4e, 0x89, 0x60, 0x8c, 0xa0, 0xc8, 0x06, + 0x76, 0x33, 0xc4, 0x66, 0x8b, 0x88, 0x61, 0x45, 0xc4, 0x30, 0xa9, 0x1b, + 0x2d, 0x8c, 0xd1, 0x71, 0x0c, 0x28, 0xb8, 0x86, 0x14, 0x5c, 0x43, 0x0a, + 0x2e, 0x21, 0x85, 0x48, 0xf9, 0x00, 0x33, 0xe1, 0x9e, 0x01, 0x9a, 0x2e, + 0x21, 0x85, 0x17, 0x10, 0xc2, 0x8b, 0x88, 0x61, 0x45, 0xc4, 0x30, 0xa9, + 0xcf, 0x91, 0x51, 0x9d, 0x0c, 0xf4, 0x66, 0xca, 0x97, 0x10, 0xc2, 0x8b, + 0x88, 0x61, 0x45, 0xc4, 0x30, 0xa2, 0xe2, 0x18, 0x51, 0x71, 0x0c, 0x28, + 0x27, 0xc9, 0xc8, 0xc8, 0x06, 0x7f, 0x19, 0xa2, 0xe2, 0x18, 0x51, 0x71, + 0x0c, 0x28, 0xb8, 0x86, 0x17, 0xee, 0xc0, 0x37, 0x85, 0xc4, 0x30, 0xa2, + 0xe2, 0x18, 0x54, 0x91, 0x32, 0xb1, 0x9e, 0x8c, 0xb8, 0xc8, 0x0d, 0x6c, + 0xb2, 0xe2, 0x18, 0x51, 0x71, 0x0c, 0x28, 0xb8, 0x86, 0x14, 0x5c, 0x43, + 0x0a, 0x2e, 0x21, 0x85, 0x48, 0xf9, 0x39, 0x19, 0x41, 0x9e, 0x23, 0x34, 0x5c, 0x43, 0x0a, 0x2e, 0x21, 0x85, 0x17, 0x10, 0xc2, 0x8b, 0x88, 0x61, - 0x45, 0xc4, 0x30, 0xa8, 0x3f, 0xde, 0x46, 0x76, 0x32, 0xc1, 0x91, 0x19, - 0xa2, 0xe2, 0x18, 0x51, 0x71, 0x0c, 0x28, 0xb8, 0x86, 0x15, 0xb3, 0xcb, - 0xd0, 0xcf, 0x86, 0x68, 0xb8, 0x86, 0x14, 0x5c, 0x43, 0x0a, 0x2e, 0x21, - 0x85, 0x30, 0xf2, 0xc4, 0x67, 0xc3, 0x36, 0x61, 0x71, 0x0c, 0x28, 0xb8, - 0x86, 0x14, 0x5c, 0x43, 0x0a, 0x01, 0xb2, 0xfc, 0x66, 0x8b, 0x88, 0x61, - 0x45, 0xc4, 0x30, 0xa2, 0xe2, 0x18, 0x51, 0x71, 0x0c, 0x2a, 0x0f, 0x92, - 0x61, 0x9e, 0x8c, 0xfe, 0x33, 0x50, 0xcc, 0x10, 0x9e, 0x10, 0x12, 0x4d, - 0x0a, 0xb6, 0x42, 0xd9, 0x70, 0x8b, 0xe6, 0x10, 0xa9, 0x0a, 0x36, 0xb3, - 0xe9, 0xa1, 0x09, 0xb8, 0x6b, 0xb1, 0x27, 0xb0, 0x83, 0x78, 0x51, 0x00, - 0xec, 0x61, 0xfb, 0xa6, 0x7f, 0x43, 0x2b, 0xf8, 0x62, 0xf1, 0x84, 0x9b, - 0x6f, 0x4d, 0x0b, 0x94, 0x51, 0xe0, 0x84, 0x35, 0xfa, 0x43, 0x19, 0xa2, - 0xe2, 0x18, 0x7d, 0x4e, 0x5a, 0xf2, 0x43, 0x0b, 0x88, 0x61, 0x7c, 0x8b, - 0x7d, 0x9f, 0x10, 0xc5, 0xe4, 0x0e, 0x1f, 0x10, 0xc5, 0xbe, 0xf2, 0x8c, - 0x8d, 0xa4, 0xf4, 0xa7, 0xc5, 0xd6, 0x8e, 0x2c, 0xf8, 0x45, 0x29, 0xe7, - 0xd7, 0xfb, 0xa8, 0xd8, 0x77, 0x13, 0x9c, 0xbc, 0x9c, 0x78, 0x73, 0x95, - 0xca, 0x24, 0x26, 0x38, 0xf1, 0xad, 0xfb, 0x32, 0x67, 0x50, 0xe5, 0xc0, - 0x83, 0x97, 0xf6, 0xdc, 0x54, 0x80, 0x1c, 0xb9, 0xf6, 0x72, 0xc8, 0x71, - 0x65, 0xb5, 0x96, 0x72, 0xcc, 0x39, 0x73, 0x4f, 0xa8, 0x89, 0xad, 0x8b, - 0x75, 0x0d, 0xc7, 0xd4, 0x11, 0xbf, 0xee, 0xc3, 0x32, 0x68, 0x19, 0xce, - 0x5f, 0xfd, 0xf1, 0xd6, 0x1e, 0xc0, 0x30, 0x40, 0x72, 0xe0, 0x41, 0xca, - 0xc3, 0xdb, 0x02, 0x2d, 0x62, 0x61, 0xc0, 0x59, 0xfe, 0x12, 0x97, 0xff, - 0x08, 0xc4, 0xe3, 0x89, 0xc6, 0x1a, 0x1c, 0xbd, 0x1c, 0xe8, 0xe5, 0x39, - 0xf1, 0x69, 0x16, 0xf3, 0xee, 0x0e, 0x5f, 0x91, 0xa3, 0x88, 0x0e, 0x54, - 0x8f, 0x0d, 0x83, 0x77, 0xfc, 0xa3, 0x87, 0x58, 0xc8, 0x6b, 0x39, 0x7b, - 0x39, 0x6c, 0xe5, 0xee, 0x41, 0x9b, 0x3d, 0xa1, 0x3c, 0xbe, 0xe3, 0x9b, - 0x91, 0xcb, 0xc1, 0x71, 0x39, 0x48, 0x6f, 0xdc, 0x92, 0xff, 0xfa, 0x3e, - 0x3e, 0xf6, 0xe0, 0x8f, 0xad, 0xb6, 0xd9, 0xca, 0x84, 0xd8, 0xdd, 0xf3, - 0x4e, 0x5f, 0x8f, 0xdf, 0xfd, 0xfa, 0x93, 0x7c, 0x85, 0x1d, 0x71, 0xd3, - 0x95, 0xc2, 0x37, 0xfc, 0x30, 0xeb, 0x3b, 0x8c, 0xa3, 0x29, 0x0c, 0x28, - 0x72, 0x16, 0xeb, 0x8d, 0x3b, 0x95, 0x74, 0x94, 0xd2, 0xd6, 0x8b, 0x34, - 0x2f, 0xb6, 0x70, 0xc8, 0xc1, 0xfb, 0x18, 0x73, 0xd6, 0x06, 0x80, 0x32, - 0x18, 0xf4, 0x35, 0x09, 0x8f, 0x47, 0x8e, 0xa1, 0xed, 0xe6, 0x69, 0x67, - 0x2f, 0x0a, 0xe0, 0xe5, 0x7c, 0x37, 0x08, 0x3b, 0x7f, 0x36, 0xfb, 0xdb, - 0xf2, 0x72, 0xff, 0xfd, 0xad, 0xed, 0x26, 0xd6, 0xe3, 0xc8, 0xb4, 0x09, - 0xca, 0x62, 0x29, 0xc4, 0x89, 0xb2, 0xfb, 0xe6, 0x7a, 0x34, 0x72, 0xfc, - 0x04, 0x9d, 0x02, 0x72, 0xfb, 0x68, 0x2a, 0x9c, 0xbf, 0xde, 0x8f, 0xd7, - 0xd4, 0xd9, 0xcb, 0xfb, 0x17, 0xd8, 0xe6, 0x47, 0x2f, 0xe6, 0x69, 0x15, - 0xf3, 0x67, 0x2f, 0xd1, 0xcf, 0x62, 0x47, 0x2b, 0x68, 0xdc, 0x12, 0x2f, - 0x1a, 0x28, 0x5d, 0xc0, 0x61, 0x7f, 0xd9, 0xc8, 0xe7, 0xbd, 0x93, 0x9c, - 0xbb, 0x9f, 0x1c, 0xbf, 0x60, 0xce, 0x9b, 0x39, 0x7e, 0xf3, 0x8f, 0xf8, - 0x72, 0xff, 0x6b, 0x18, 0x9e, 0xeb, 0x9c, 0xb4, 0x62, 0x26, 0x36, 0x30, - 0x24, 0xfe, 0x27, 0xbd, 0xf1, 0x88, 0x72, 0xe1, 0x61, 0xca, 0x91, 0xb4, - 0xd0, 0xf5, 0xee, 0x0d, 0xc1, 0xcb, 0xfd, 0xb4, 0x98, 0x73, 0x8b, 0x9c, - 0xbb, 0x9d, 0x7c, 0x3f, 0x48, 0x21, 0xd8, 0xfd, 0xff, 0x0c, 0x3c, 0xfd, - 0x8d, 0x80, 0xe5, 0xfe, 0x4d, 0x8f, 0xbd, 0x93, 0x9c, 0xb9, 0xf8, 0x9c, - 0xbf, 0xa4, 0x29, 0x2e, 0xe1, 0xcb, 0xf4, 0xe9, 0xb8, 0x91, 0xca, 0x55, - 0x13, 0xf3, 0x19, 0xec, 0x60, 0x4b, 0x2f, 0xdf, 0xf9, 0xa6, 0x78, 0xe5, - 0xe0, 0xa2, 0xa7, 0x2a, 0x0f, 0x23, 0x0a, 0xef, 0x6c, 0x0a, 0x1c, 0xbf, - 0xf9, 0x3d, 0x1e, 0xd7, 0x5d, 0x3b, 0xf9, 0xca, 0x83, 0xe2, 0x71, 0xeb, - 0xe1, 0x1f, 0xe4, 0x72, 0xff, 0xdd, 0x8d, 0x80, 0x71, 0xb7, 0x01, 0xcb, - 0xd9, 0x93, 0x1c, 0xb6, 0x74, 0xf6, 0x80, 0x7d, 0x7a, 0x39, 0x6c, 0xe5, - 0xfb, 0x7f, 0xb1, 0xc4, 0xe5, 0x78, 0xf1, 0xbf, 0x1e, 0xbe, 0x64, 0x64, - 0xe7, 0x2f, 0xd9, 0xc4, 0x63, 0x93, 0x94, 0x87, 0x97, 0xa2, 0x2b, 0xe8, - 0x1f, 0x2c, 0xe5, 0x05, 0x5c, 0xc6, 0x43, 0x5f, 0x70, 0x86, 0xec, 0x20, - 0x9c, 0x80, 0x5f, 0x34, 0xdb, 0xe6, 0xe6, 0x84, 0x37, 0xf8, 0x0a, 0x60, - 0x87, 0xb0, 0x72, 0xa1, 0x18, 0x2f, 0x08, 0xeb, 0xfb, 0x58, 0xc4, 0xec, - 0x1c, 0xbd, 0xcc, 0xb4, 0x72, 0xb9, 0x3c, 0xad, 0x96, 0x5e, 0xd0, 0x1b, - 0x39, 0x7f, 0xd2, 0x63, 0xcb, 0xda, 0x85, 0x4e, 0x54, 0x1f, 0xde, 0x11, - 0xb8, 0xf5, 0xf7, 0xef, 0xb9, 0x1c, 0xbe, 0x8f, 0xf8, 0x7d, 0x14, 0xbf, - 0x4b, 0xeb, 0x6d, 0xb6, 0x72, 0x84, 0xf5, 0xbf, 0x28, 0xbe, 0x7f, 0x33, - 0xc7, 0x28, 0x28, 0xbd, 0xc7, 0x90, 0x11, 0x5f, 0xe5, 0x04, 0x5d, 0xb7, - 0xe9, 0xca, 0x86, 0x51, 0x46, 0x18, 0x72, 0x44, 0x91, 0x82, 0x6d, 0x35, - 0x90, 0xd1, 0x78, 0x74, 0x02, 0x72, 0x58, 0x61, 0xd7, 0xfc, 0x3a, 0x5b, - 0x2f, 0xbc, 0xd5, 0x35, 0x3e, 0x10, 0xe5, 0xe9, 0x0b, 0x9c, 0xb7, 0x2d, - 0x51, 0xe4, 0x41, 0x6d, 0xfb, 0x82, 0x25, 0xb8, 0x39, 0x7b, 0xce, 0x03, - 0x97, 0xf4, 0x6e, 0x78, 0xdc, 0xe7, 0x2f, 0xfd, 0x03, 0xee, 0xfe, 0xf2, - 0x94, 0x1c, 0xbf, 0x7e, 0x0c, 0x15, 0x9c, 0xbd, 0xb8, 0x98, 0xe5, 0xf2, - 0x0b, 0xcc, 0x72, 0xff, 0xc3, 0x0a, 0xf5, 0xfc, 0xa6, 0x00, 0xe5, 0xed, - 0x6f, 0x0e, 0x5f, 0xd9, 0xb0, 0x0f, 0xe0, 0x39, 0x48, 0x79, 0x5a, 0x1c, - 0xb3, 0x59, 0xcb, 0xfb, 0x14, 0x89, 0x93, 0x47, 0x28, 0x4f, 0x0b, 0xc2, - 0x95, 0x0a, 0x89, 0xa7, 0x2a, 0x90, 0xe0, 0x4b, 0xf6, 0x7c, 0xc2, 0x8e, - 0x8e, 0x89, 0x0f, 0xa1, 0x13, 0xc5, 0x8e, 0xff, 0xa1, 0x3b, 0x0c, 0x9f, - 0x1b, 0x39, 0x7e, 0xea, 0x4e, 0xe2, 0x72, 0xfd, 0xfa, 0xae, 0x20, 0x39, - 0x7f, 0x6b, 0x71, 0x81, 0x43, 0x95, 0x07, 0xf9, 0xd2, 0x7e, 0x25, 0x37, - 0xfd, 0x38, 0xe4, 0xbb, 0x80, 0xd1, 0xcb, 0xff, 0x60, 0xf3, 0x2d, 0x6f, - 0xf8, 0x01, 0xcb, 0xf6, 0x7b, 0x58, 0xa9, 0xca, 0x43, 0xe8, 0x62, 0x05, - 0xfc, 0x3e, 0xf9, 0xdc, 0xe0, 0x39, 0x78, 0x31, 0xc4, 0xe5, 0xff, 0xe1, - 0x18, 0x6c, 0x23, 0x1c, 0xc9, 0x04, 0xe5, 0xf9, 0x99, 0xd7, 0xe0, 0x39, - 0x58, 0x7e, 0x48, 0x91, 0x7f, 0xf9, 0xfe, 0x4d, 0x28, 0xdc, 0xff, 0x1b, - 0xce, 0x9c, 0xa8, 0x4c, 0xcc, 0x26, 0x5d, 0x84, 0x80, 0x90, 0x5f, 0xf3, - 0x3b, 0x9e, 0xcf, 0xf7, 0x39, 0xcb, 0xff, 0xe5, 0x5f, 0xda, 0x41, 0x9a, - 0x17, 0xbc, 0xe4, 0xe5, 0xff, 0x47, 0xb3, 0x6b, 0x77, 0x59, 0xa2, 0xf8, - 0x5f, 0xb3, 0x71, 0xcc, 0x8e, 0x5e, 0xec, 0x31, 0x67, 0xd9, 0xe4, 0x4b, - 0xff, 0xf0, 0xaf, 0xe7, 0x61, 0x36, 0x8c, 0x46, 0x90, 0xc3, 0x97, 0x9f, - 0x73, 0x9a, 0x2f, 0xf5, 0x42, 0x2d, 0x30, 0xcd, 0x6a, 0xf7, 0xfc, 0xfe, - 0xd2, 0x0f, 0x32, 0x61, 0xcb, 0xfe, 0x8c, 0xdf, 0xc9, 0x27, 0x32, 0x39, - 0x40, 0x3f, 0x4f, 0x1c, 0xdf, 0xff, 0xee, 0xbe, 0x92, 0x35, 0xf3, 0xdd, - 0xc6, 0x62, 0xdf, 0x67, 0x2e, 0x8e, 0x03, 0x97, 0xda, 0xd3, 0xb0, 0xe5, - 0x75, 0x13, 0x80, 0x61, 0xf0, 0xcd, 0xf7, 0x32, 0xf3, 0x9c, 0xbf, 0xfe, - 0x0a, 0xfa, 0x83, 0x9c, 0x5e, 0x5a, 0x40, 0x9c, 0xb4, 0xb0, 0xfc, 0xdc, - 0x8e, 0xff, 0xa1, 0x9f, 0x03, 0x98, 0x0d, 0x1c, 0xbe, 0x46, 0x6e, 0x73, - 0x97, 0xfe, 0xf4, 0x6b, 0x50, 0x93, 0xbf, 0x8e, 0x5f, 0xf2, 0x60, 0x85, - 0x54, 0xcd, 0x9c, 0xa4, 0x46, 0x96, 0xce, 0xbc, 0x47, 0xc0, 0x7d, 0x7b, - 0xd9, 0xc9, 0xcb, 0xf9, 0xf7, 0xcc, 0xb3, 0xc7, 0x2f, 0xfd, 0xed, 0x26, - 0xfc, 0x3f, 0xbc, 0x8e, 0x5f, 0xfe, 0x64, 0x34, 0xcf, 0xc7, 0x33, 0x8c, - 0x72, 0x72, 0xff, 0xd1, 0x9b, 0xcd, 0x81, 0x89, 0xa3, 0x97, 0x9f, 0x9e, - 0x03, 0x97, 0xf3, 0xfb, 0x51, 0x93, 0x9c, 0xa8, 0x4d, 0x13, 0x0b, 0x90, - 0xfc, 0x53, 0x78, 0x9e, 0xb6, 0x41, 0x7f, 0xdf, 0xc3, 0x35, 0x8c, 0x86, - 0xb3, 0x97, 0xfe, 0xdc, 0xf8, 0x1c, 0xef, 0x71, 0xac, 0xe5, 0xff, 0xb0, - 0x7d, 0xa5, 0x38, 0xc6, 0x72, 0x72, 0xb1, 0x10, 0x7a, 0x42, 0xbf, 0xfe, - 0x94, 0x6e, 0x7f, 0x22, 0xba, 0xd3, 0x8c, 0x8e, 0x5f, 0xd3, 0xeb, 0x19, - 0x0d, 0x67, 0x2c, 0xdc, 0xc8, 0x82, 0x51, 0x46, 0xf2, 0x75, 0x0e, 0x5f, - 0x4b, 0x61, 0x91, 0xcb, 0xe6, 0x79, 0x27, 0x39, 0x58, 0x78, 0xc8, 0x47, - 0x7f, 0xf7, 0x1f, 0x2b, 0x03, 0x2c, 0xea, 0x30, 0xe5, 0xd3, 0xf8, 0xe5, - 0xfe, 0xe3, 0xd7, 0x94, 0x60, 0x9c, 0xa8, 0x3c, 0xbc, 0x18, 0xbf, 0xff, - 0x4b, 0xb1, 0xb7, 0xf7, 0xfe, 0x4f, 0x6b, 0xa8, 0x72, 0xfe, 0xc6, 0xd4, - 0xeb, 0xf8, 0xe5, 0xfd, 0x26, 0x78, 0x7f, 0x98, 0xe5, 0xff, 0xf2, 0x92, - 0x8e, 0x28, 0x20, 0xda, 0x43, 0x30, 0xa5, 0x6d, 0x10, 0x1e, 0x30, 0xbe, - 0xea, 0x9c, 0xf8, 0xe5, 0xfb, 0x19, 0x89, 0xc4, 0xe5, 0xe9, 0xe6, 0x6b, - 0x39, 0x50, 0x9c, 0xbc, 0xea, 0xd9, 0x0a, 0xf5, 0x91, 0xa1, 0x2f, 0xe5, - 0x17, 0x7b, 0x0e, 0x5f, 0xb6, 0x93, 0xbb, 0x0d, 0x30, 0x9a, 0xfb, 0xdf, - 0xc3, 0x9a, 0x61, 0x35, 0xc0, 0x83, 0x50, 0x26, 0xbf, 0xc2, 0xea, 0xfa, - 0x36, 0x03, 0x50, 0x26, 0xbf, 0xda, 0xce, 0xa6, 0xbf, 0x9c, 0xd3, 0x09, - 0xae, 0xc0, 0x9a, 0x61, 0x35, 0xcd, 0xb6, 0x79, 0x84, 0xd5, 0x89, 0xa9, - 0x72, 0x6a, 0x85, 0xec, 0x23, 0xd2, 0x07, 0x14, 0x26, 0xc8, 0xed, 0xe2, - 0xcc, 0x26, 0x7d, 0x3e, 0x7b, 0x27, 0x2a, 0x80, 0x5b, 0x8f, 0x3e, 0xa1, - 0x76, 0x11, 0x0b, 0x3a, 0xc2, 0xe4, 0x03, 0x09, 0x1d, 0x47, 0x6f, 0xe9, - 0x4b, 0xb7, 0xcf, 0xc7, 0x1b, 0x39, 0x7f, 0xfe, 0xeb, 0xcb, 0xb1, 0x09, - 0xed, 0x20, 0xf3, 0x23, 0x97, 0x84, 0x0c, 0x39, 0x7f, 0xd1, 0xff, 0x85, - 0x38, 0xa8, 0xc3, 0x97, 0x66, 0xb0, 0xf6, 0x36, 0x39, 0x5b, 0x47, 0xe3, - 0x92, 0x0c, 0x2b, 0x2f, 0xb1, 0x36, 0xa9, 0xcb, 0xc1, 0x04, 0xc7, 0x2a, - 0x1b, 0x19, 0xf9, 0xe1, 0x42, 0x18, 0xd5, 0x31, 0x05, 0x53, 0xb5, 0xc6, - 0xe3, 0xcc, 0x28, 0x92, 0x17, 0xd3, 0x42, 0x8f, 0x70, 0xf8, 0x61, 0xff, - 0x63, 0x61, 0x15, 0x7d, 0x42, 0xff, 0xd3, 0xc5, 0x1c, 0x63, 0x71, 0x68, - 0x66, 0xa1, 0x15, 0xf8, 0x39, 0xb4, 0x54, 0xe5, 0xfd, 0xd8, 0x50, 0x79, - 0x01, 0xcb, 0xcd, 0x5e, 0x70, 0x1c, 0xbd, 0x98, 0xd9, 0xcb, 0x91, 0x53, - 0x95, 0x39, 0xb3, 0x41, 0xcb, 0xf7, 0xb2, 0x64, 0x61, 0xcb, 0xf4, 0x72, - 0x00, 0x41, 0xca, 0x83, 0xd0, 0x12, 0x8b, 0xf4, 0x71, 0x81, 0xf1, 0xcb, - 0xf2, 0x71, 0xf2, 0x4e, 0x72, 0xfc, 0xf2, 0xf6, 0x2c, 0xe5, 0xf8, 0x71, - 0x4c, 0x98, 0xe5, 0xff, 0xf0, 0xad, 0x18, 0x1f, 0xdf, 0x72, 0xce, 0x7c, - 0x72, 0xff, 0xce, 0x20, 0xe7, 0xdb, 0x8c, 0x6c, 0xe5, 0xff, 0xb5, 0xd4, - 0xf9, 0xcc, 0xa3, 0x27, 0x39, 0x6c, 0x6b, 0x44, 0x08, 0x0f, 0xef, 0xfb, - 0xae, 0xce, 0xa4, 0x73, 0x23, 0x97, 0xf2, 0x83, 0x26, 0x8f, 0x39, 0xca, - 0x84, 0xd9, 0xe5, 0x0d, 0x24, 0x2b, 0x01, 0xcd, 0x4e, 0xa9, 0xa4, 0x24, - 0x0b, 0x28, 0xd9, 0x50, 0x93, 0xfa, 0x38, 0xfb, 0xff, 0x63, 0xf6, 0x64, - 0x1e, 0xe7, 0x27, 0x2f, 0xe0, 0x4d, 0x28, 0xf6, 0x8e, 0x5f, 0xff, 0xff, - 0xb3, 0xb8, 0x20, 0xc1, 0xf7, 0x73, 0xb1, 0x93, 0x26, 0xe6, 0xea, 0x73, - 0xe3, 0x97, 0xc3, 0x18, 0xd9, 0xcb, 0xe8, 0xe7, 0x4e, 0x72, 0xa1, 0xb9, - 0x6b, 0x9e, 0x12, 0x61, 0x85, 0xae, 0x56, 0x39, 0xe9, 0x19, 0xdb, 0x59, - 0x44, 0xc5, 0xfb, 0x57, 0x79, 0x5b, 0x42, 0xbf, 0xe3, 0xef, 0xcb, 0xf8, - 0xc2, 0x09, 0x42, 0x1b, 0xff, 0xe4, 0x1c, 0x64, 0x28, 0x3f, 0xc8, 0x71, - 0x87, 0x2f, 0xf8, 0x29, 0x83, 0xfc, 0xb3, 0x47, 0x2f, 0xfb, 0x7b, 0x85, - 0xf7, 0x97, 0x6b, 0x39, 0x6f, 0xce, 0x5f, 0xcb, 0xfd, 0xc2, 0xc8, 0x39, - 0x7f, 0xdd, 0x49, 0x75, 0xe4, 0x8c, 0x39, 0x7f, 0xed, 0x20, 0xf3, 0x2f, - 0x26, 0x90, 0xe5, 0x61, 0xfb, 0x78, 0xe2, 0xfd, 0xa6, 0x40, 0x60, 0xe5, - 0x49, 0x3c, 0x1c, 0x4e, 0x43, 0x89, 0x8f, 0x76, 0x24, 0xc8, 0x52, 0x78, - 0x86, 0xf8, 0x63, 0x72, 0x39, 0x7f, 0xdd, 0x89, 0x20, 0x8f, 0xfc, 0x9c, - 0xbf, 0xe8, 0x92, 0x7a, 0x50, 0x20, 0x39, 0x7f, 0xd1, 0x9e, 0x50, 0x00, - 0x8e, 0x4e, 0x5b, 0x70, 0x8c, 0xbc, 0x21, 0xd9, 0xcb, 0x0d, 0xef, 0xe1, - 0x85, 0xee, 0x24, 0x72, 0xff, 0xfb, 0xae, 0x9e, 0x97, 0xe3, 0xed, 0x75, - 0xe4, 0x71, 0x43, 0x59, 0x7f, 0xed, 0x29, 0xe4, 0x1f, 0xe5, 0x9a, 0x39, - 0x70, 0x74, 0x72, 0x9a, 0xd1, 0x71, 0xd6, 0x11, 0x40, 0xbf, 0xff, 0xb3, - 0x9c, 0xd3, 0x8f, 0x52, 0x3d, 0xdf, 0xdd, 0x87, 0x2a, 0x13, 0xb1, 0x78, - 0xc9, 0x44, 0xca, 0xfd, 0xfb, 0x13, 0xb0, 0x72, 0xfd, 0x9b, 0x5c, 0x61, - 0xca, 0x13, 0xce, 0x50, 0xa2, 0xff, 0xfc, 0xe3, 0xe7, 0x7e, 0x8c, 0x7b, - 0x4d, 0xe7, 0x4e, 0x5f, 0xf4, 0x7b, 0xb8, 0xcc, 0xde, 0x1c, 0xbf, 0x7b, - 0xa9, 0x1a, 0x39, 0x7a, 0x77, 0x1d, 0x9e, 0xf6, 0x8d, 0xef, 0xfa, 0x01, - 0xa0, 0xfe, 0xfb, 0x91, 0xcb, 0xdb, 0xd6, 0x8f, 0x10, 0x1a, 0xf9, 0x6e, - 0xeb, 0x34, 0x40, 0x6f, 0xa6, 0xaa, 0xfe, 0xdc, 0x76, 0x3e, 0x64, 0x91, - 0x49, 0xb6, 0x4a, 0x74, 0xc7, 0x54, 0x86, 0xbd, 0x01, 0x3f, 0x7f, 0x47, - 0x9d, 0x7b, 0x8c, 0x74, 0xe5, 0x62, 0xa6, 0x14, 0x94, 0x32, 0xa1, 0x55, - 0xee, 0xbb, 0x59, 0xcb, 0xe8, 0x03, 0x4c, 0x39, 0x40, 0x3c, 0x2f, 0x0f, - 0xdf, 0x0f, 0x81, 0xf9, 0xcb, 0xf3, 0x1a, 0xa6, 0xa9, 0xaa, 0x6a, 0x0e, - 0x5f, 0xff, 0xd2, 0xcd, 0x26, 0xf6, 0x8c, 0x53, 0xdd, 0xc6, 0xfc, 0x72, - 0xb1, 0x17, 0xa8, 0x46, 0xe7, 0xb7, 0xff, 0x9b, 0xc1, 0xf6, 0x0c, 0xb3, - 0x4a, 0x30, 0xe5, 0xff, 0xe9, 0x67, 0x32, 0x52, 0x01, 0xf5, 0xb6, 0xdb, - 0x29, 0x7e, 0x63, 0x78, 0x9c, 0x4e, 0x5e, 0x96, 0x0c, 0xc7, 0xf8, 0xa2, - 0x95, 0x42, 0x3e, 0x9e, 0x18, 0xd5, 0x0a, 0x8b, 0x3b, 0x0d, 0xf1, 0x8c, - 0x9e, 0xff, 0x90, 0x65, 0xa6, 0xa4, 0xd4, 0x35, 0x4d, 0x41, 0xcb, 0xe9, - 0xb5, 0x93, 0x1c, 0xbf, 0x02, 0x3d, 0x8d, 0x67, 0x2f, 0xf4, 0x66, 0xd6, - 0xee, 0xb3, 0x44, 0x12, 0xbf, 0xe8, 0xf6, 0x6d, 0x6e, 0xeb, 0x34, 0x5f, - 0x2b, 0xf3, 0x87, 0xb0, 0xa9, 0xcb, 0xc3, 0x9a, 0x0a, 0x2a, 0x96, 0x7c, - 0xc4, 0x4a, 0x14, 0xc5, 0x38, 0xc3, 0x52, 0xff, 0xe8, 0xea, 0x2b, 0x9b, - 0x9d, 0x9f, 0xf2, 0x72, 0xff, 0x83, 0xbc, 0x66, 0x49, 0xc2, 0x72, 0xb1, - 0x3e, 0x24, 0x8c, 0xe3, 0xa5, 0x4e, 0x91, 0x7f, 0xbf, 0xeb, 0x4e, 0xa2, - 0xfa, 0x72, 0xff, 0xd3, 0xbf, 0x2d, 0x33, 0xc2, 0xfc, 0x4e, 0x5f, 0xff, - 0x67, 0xa0, 0x7d, 0xac, 0xc5, 0x55, 0x79, 0x1c, 0xbf, 0x95, 0xcf, 0x7b, - 0x02, 0x72, 0xff, 0xd8, 0x18, 0x94, 0x77, 0x00, 0xe7, 0x2f, 0xe7, 0x97, - 0xf2, 0x70, 0x9c, 0xbf, 0xba, 0x93, 0xeb, 0x4e, 0x72, 0xf3, 0x6d, 0xb6, - 0x52, 0xfd, 0xdc, 0x5b, 0xec, 0xa7, 0xd3, 0x41, 0x7f, 0xff, 0xa6, 0xdc, - 0x71, 0xf8, 0xab, 0xfc, 0x52, 0x6d, 0x7c, 0xce, 0x7c, 0x72, 0xa1, 0x1e, - 0xde, 0x4e, 0x50, 0xe6, 0xff, 0xf2, 0x6d, 0x3d, 0xfe, 0x79, 0xd9, 0x82, - 0x72, 0xa7, 0x55, 0x30, 0xb4, 0x3d, 0xa7, 0xb0, 0xb8, 0x07, 0x83, 0x19, - 0x27, 0x8c, 0x2f, 0xfc, 0xc8, 0xe7, 0x43, 0x93, 0xa9, 0x23, 0x97, 0xff, - 0xf9, 0x3a, 0xe3, 0xcc, 0x94, 0x94, 0x0c, 0x9d, 0x98, 0x13, 0x97, 0xff, - 0xb3, 0x3a, 0x1e, 0xc6, 0xb3, 0xa8, 0x03, 0x97, 0xf9, 0x5f, 0x93, 0x4a, - 0x37, 0xa3, 0x95, 0x3a, 0x64, 0x32, 0x41, 0x0b, 0x02, 0x24, 0x5f, 0x7c, - 0x4e, 0xfe, 0x72, 0xfd, 0x92, 0xec, 0x6c, 0xe5, 0x2c, 0xf3, 0x1a, 0xc9, - 0x6f, 0xf7, 0xa1, 0x3a, 0xac, 0x72, 0x72, 0xff, 0xef, 0x69, 0xe5, 0xac, - 0x5c, 0x31, 0x0e, 0x5f, 0xfe, 0xe4, 0x7e, 0x2f, 0xa8, 0x00, 0x46, 0xe4, - 0x72, 0xa1, 0x1d, 0x28, 0x4b, 0xf9, 0xa2, 0x88, 0x77, 0xf2, 0x6b, 0x02, - 0xa6, 0x1c, 0xbf, 0x70, 0x20, 0xe7, 0x13, 0x97, 0xfb, 0x78, 0x14, 0xfd, - 0x7d, 0x59, 0xec, 0x39, 0x6d, 0xfe, 0xd0, 0xe7, 0x1e, 0xbc, 0x8e, 0x5e, - 0xd4, 0xb8, 0x9c, 0xa4, 0x3d, 0x36, 0xb3, 0x4b, 0xff, 0xd1, 0x3a, 0x9d, - 0x8e, 0x7d, 0x93, 0x88, 0x4e, 0x52, 0x26, 0x1c, 0xf0, 0x9d, 0x12, 0x4b, - 0xfd, 0x18, 0x3e, 0xe1, 0x1b, 0x59, 0xcb, 0xfd, 0xdc, 0xe3, 0xf3, 0x52, - 0x59, 0xcb, 0x7f, 0xa3, 0xf0, 0xf1, 0xc5, 0xfc, 0x3f, 0x14, 0xdf, 0x5c, - 0xe5, 0xff, 0xbf, 0x79, 0x7c, 0x84, 0x0e, 0x30, 0xe5, 0x39, 0xf8, 0x09, - 0x85, 0xfb, 0x36, 0xfc, 0xb6, 0x72, 0xff, 0xff, 0x4f, 0x8d, 0x8e, 0x07, - 0x69, 0xfc, 0xe1, 0xec, 0x0c, 0xe7, 0x2a, 0x74, 0x46, 0xe8, 0xa6, 0xff, - 0x4c, 0x2e, 0xdf, 0xb3, 0xa7, 0x2f, 0x36, 0xdb, 0x65, 0x2f, 0xe0, 0x40, - 0xe7, 0x3e, 0x29, 0xf4, 0xd0, 0x57, 0xc4, 0x49, 0xa8, 0xa9, 0x7f, 0xff, - 0x70, 0xff, 0x17, 0xd4, 0x08, 0x71, 0xbf, 0x9e, 0xd6, 0x4e, 0x72, 0xba, - 0x88, 0xdf, 0xc9, 0xa9, 0x13, 0x68, 0x78, 0xd1, 0x2a, 0x76, 0x6a, 0xe4, - 0xa5, 0x18, 0x05, 0x05, 0x25, 0x67, 0xee, 0x38, 0xd6, 0x46, 0xe7, 0xd8, - 0xe8, 0xc6, 0x14, 0x7a, 0x84, 0xcf, 0xa5, 0x0a, 0xdf, 0xfb, 0x10, 0x67, - 0x71, 0xf6, 0x30, 0xe5, 0xff, 0xed, 0xaa, 0xa7, 0x93, 0x43, 0x9c, 0x50, - 0x27, 0x2f, 0xf9, 0x1b, 0x0f, 0x73, 0xcd, 0x30, 0xe5, 0x42, 0x22, 0x3a, - 0x9b, 0x7c, 0x2f, 0xcf, 0x8e, 0x5e, 0xc1, 0x01, 0xcb, 0xec, 0xf4, 0xd2, - 0x39, 0x7f, 0xf7, 0x00, 0xc7, 0x06, 0x9c, 0x54, 0x06, 0x8e, 0x57, 0x4f, - 0xb5, 0xc8, 0xef, 0xfd, 0x9e, 0x8d, 0xeb, 0xb0, 0x3e, 0x3c, 0x41, 0x0b, - 0xfb, 0x36, 0xb7, 0x75, 0x9a, 0x20, 0x87, 0xd3, 0xca, 0xbd, 0x01, 0x43, - 0x95, 0x07, 0xcf, 0xa4, 0xcb, 0xdc, 0x61, 0x87, 0x2f, 0xe7, 0xee, 0xf6, - 0x8d, 0x9c, 0xbf, 0x9a, 0xc2, 0xdb, 0x8c, 0x8e, 0x56, 0x1f, 0xe8, 0x8f, - 0x7e, 0x5d, 0x7f, 0xfe, 0x80, 0xcd, 0x24, 0x1f, 0x40, 0x26, 0x14, 0x98, - 0xe5, 0x4e, 0xaa, 0x79, 0x52, 0x2e, 0xc2, 0x20, 0x10, 0xd2, 0x18, 0x4f, - 0x71, 0x2e, 0xbf, 0xbb, 0x9e, 0xf2, 0x30, 0xe5, 0xfd, 0xe5, 0x33, 0xaf, - 0xc9, 0xca, 0xe4, 0xf7, 0x04, 0xb6, 0xfe, 0xce, 0x7d, 0xbd, 0xc1, 0xcb, - 0xff, 0xb4, 0x2f, 0xe7, 0x62, 0x91, 0x3e, 0x1c, 0xa0, 0x9f, 0x96, 0x8b, - 0xaa, 0x11, 0x6d, 0xfc, 0x25, 0x2f, 0xec, 0x5a, 0x9c, 0x7b, 0x87, 0x2e, - 0x85, 0x4e, 0x5c, 0x82, 0x72, 0xcd, 0x9c, 0xa0, 0x9a, 0x75, 0x05, 0x6f, - 0x0f, 0xf3, 0x9c, 0xbf, 0x75, 0xe5, 0x82, 0x72, 0xfe, 0x4f, 0x0e, 0x75, - 0x0e, 0x5d, 0x9d, 0xf8, 0x7a, 0x30, 0x4d, 0x73, 0xb7, 0xf1, 0x1f, 0xb8, - 0x7d, 0xd2, 0x2f, 0x37, 0xd4, 0x93, 0x9f, 0xc2, 0x81, 0x8c, 0xb6, 0xfe, - 0xd2, 0x04, 0x38, 0x27, 0x2f, 0xff, 0xef, 0x77, 0x35, 0xac, 0xcf, 0xf7, - 0x3e, 0x7e, 0x3e, 0x39, 0x7f, 0xdd, 0x8d, 0xf8, 0x63, 0x39, 0x39, 0x7f, - 0xff, 0xc9, 0x3c, 0x4b, 0x5b, 0xda, 0x73, 0x34, 0x9f, 0x6c, 0xce, 0x4e, - 0x5f, 0xe8, 0x79, 0xdf, 0x6e, 0xa1, 0xcb, 0xdd, 0xc1, 0x0a, 0x35, 0x7a, - 0x71, 0xe6, 0xaa, 0xc4, 0xe7, 0x90, 0xb3, 0xd1, 0x99, 0x5f, 0xa3, 0x73, - 0x6a, 0x73, 0x97, 0xfd, 0xd8, 0xcd, 0xcb, 0x5f, 0xb0, 0xe5, 0x4e, 0x7c, - 0x8b, 0x2a, 0xb9, 0x34, 0x72, 0xff, 0xb2, 0x77, 0xf0, 0x14, 0x19, 0x1c, - 0xbf, 0x9f, 0xdf, 0x22, 0x4a, 0x9c, 0xbf, 0x94, 0x66, 0x9b, 0x7e, 0x4e, - 0x54, 0x26, 0xdb, 0x90, 0x99, 0x54, 0x8f, 0x62, 0xce, 0x75, 0xe3, 0x0b, - 0xdb, 0xce, 0x9c, 0xbd, 0xa4, 0x61, 0xca, 0xd9, 0xb8, 0xf0, 0xe5, 0xc9, - 0x39, 0xca, 0x83, 0x71, 0xc0, 0x43, 0x7f, 0xf7, 0x52, 0x07, 0xe3, 0x8c, - 0x91, 0x87, 0x2f, 0x92, 0x64, 0x6c, 0xe5, 0xff, 0xcc, 0x7e, 0x54, 0xf2, - 0x6e, 0x3f, 0xe1, 0xce, 0x5f, 0xff, 0xbf, 0x9c, 0x63, 0x3b, 0xf6, 0x3d, - 0x9d, 0xff, 0x67, 0x2f, 0xbd, 0xa5, 0x35, 0xf1, 0x30, 0xb0, 0xa1, 0xe1, - 0x1a, 0x89, 0x97, 0xed, 0x33, 0x3d, 0xa3, 0x97, 0xff, 0x22, 0xb9, 0xe4, - 0xee, 0x7a, 0x36, 0x72, 0xfc, 0xf2, 0x14, 0x83, 0x97, 0xf4, 0x38, 0xfb, - 0x04, 0xe5, 0x49, 0x52, 0x0e, 0x46, 0x5c, 0x8b, 0x3b, 0x28, 0x62, 0x18, - 0x92, 0xdf, 0xba, 0x8d, 0x11, 0x53, 0x97, 0xd8, 0x04, 0xe2, 0x72, 0x96, - 0x79, 0xa2, 0x55, 0x7f, 0xf9, 0x01, 0x1a, 0x64, 0x26, 0xf6, 0x8d, 0x9c, - 0xbe, 0x6b, 0xee, 0x4e, 0x72, 0xff, 0x40, 0x73, 0xc9, 0xdf, 0xce, 0x59, - 0x90, 0x7b, 0x21, 0x26, 0xbf, 0xf7, 0x94, 0x04, 0x29, 0x00, 0x80, 0x1c, - 0xbf, 0xff, 0xf3, 0x1c, 0x41, 0x24, 0xd7, 0xec, 0xea, 0x47, 0xbb, 0xfb, - 0xb0, 0xe5, 0xff, 0xf0, 0xff, 0xe9, 0x20, 0x3a, 0xe9, 0xe7, 0x61, 0xcb, - 0xbe, 0x35, 0x9c, 0xbf, 0xff, 0x3a, 0x79, 0x03, 0x81, 0xcf, 0x23, 0x13, - 0x67, 0x2f, 0xff, 0x42, 0xc3, 0x8a, 0x79, 0x37, 0x1f, 0xf0, 0xe7, 0x2f, - 0x6d, 0xf5, 0x89, 0x86, 0xed, 0x3f, 0xa3, 0x82, 0xa5, 0x6f, 0x3a, 0x78, - 0xff, 0xc6, 0xf5, 0x5c, 0xaa, 0x37, 0x49, 0x40, 0xf7, 0x4a, 0x0e, 0x5f, - 0xfe, 0x9c, 0x3d, 0x8e, 0xe7, 0x20, 0xcf, 0x68, 0xe5, 0x39, 0xf1, 0x7e, - 0x2d, 0x41, 0x57, 0xa3, 0x84, 0x29, 0x0a, 0x27, 0x94, 0xbc, 0x30, 0x8e, - 0xbf, 0xb7, 0x13, 0xa0, 0xf8, 0xe5, 0xe0, 0xa8, 0xc3, 0x97, 0xe1, 0x80, - 0xe4, 0xc7, 0x2f, 0xb5, 0xfe, 0xd5, 0x39, 0x7e, 0x8e, 0xfa, 0x24, 0x72, - 0xf8, 0x3f, 0xfb, 0x50, 0x7e, 0x7c, 0x93, 0x80, 0x96, 0xfc, 0x0c, 0x64, - 0x74, 0xe5, 0xff, 0xff, 0xec, 0x9f, 0x50, 0xab, 0xeb, 0xd2, 0xc5, 0x55, - 0xce, 0x7d, 0xb8, 0xce, 0x4e, 0x5f, 0xa3, 0xe6, 0xc6, 0x47, 0x2b, 0x48, - 0xa5, 0xfd, 0xf2, 0xf7, 0x0f, 0xdc, 0x39, 0x41, 0x54, 0x2f, 0x85, 0xa9, - 0x09, 0x11, 0x48, 0xf4, 0x33, 0x3f, 0x24, 0xbd, 0xb5, 0x34, 0x72, 0xdc, - 0x2e, 0x72, 0xfd, 0xef, 0x7b, 0x1b, 0x39, 0x50, 0x78, 0x28, 0x31, 0x7f, - 0xe7, 0x15, 0xe6, 0xd6, 0xee, 0xb3, 0x44, 0x22, 0xba, 0x53, 0x9c, 0xa8, - 0x47, 0x00, 0x17, 0xff, 0x20, 0xe2, 0x93, 0x7e, 0xc9, 0xf4, 0x07, 0x39, - 0x7f, 0xff, 0xfb, 0xb9, 0xfe, 0xd5, 0xea, 0x73, 0x1e, 0xff, 0xa3, 0x9c, - 0xfb, 0xf7, 0xd1, 0xcb, 0xff, 0xb3, 0x95, 0x3c, 0x83, 0xfc, 0xb3, 0x47, - 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xd8, 0x33, 0x8b, 0x86, 0x06, 0x78, - 0xd8, 0x70, 0x73, 0xda, 0x45, 0xe0, 0xa9, 0x3e, 0x6e, 0x34, 0x2e, 0xae, - 0xb1, 0x00, 0x0f, 0xc0, 0x2e, 0x18, 0x19, 0xe3, 0x67, 0x2a, 0x13, 0x4e, - 0xc4, 0x6b, 0xff, 0xbc, 0xe3, 0x3f, 0x32, 0x18, 0xcd, 0x1c, 0xbf, 0xff, - 0x40, 0x26, 0x94, 0x4e, 0x2e, 0xae, 0x86, 0x24, 0x72, 0xff, 0xca, 0x67, - 0x5d, 0x9f, 0x5b, 0x6d, 0xb3, 0x97, 0xff, 0xec, 0x5f, 0x60, 0x42, 0x29, - 0x3e, 0x0a, 0x2a, 0x72, 0xcf, 0x3a, 0x26, 0x24, 0x8b, 0x52, 0x4c, 0x5d, - 0xe1, 0xdd, 0x7f, 0xff, 0x4c, 0x30, 0x0d, 0x2f, 0xa9, 0xb9, 0x86, 0x01, - 0xa3, 0x97, 0xff, 0x7b, 0xa9, 0xc7, 0xaf, 0x2d, 0xc2, 0xa7, 0x2f, 0xef, - 0xfc, 0x9f, 0x8a, 0xa7, 0x2f, 0xec, 0x6f, 0x07, 0xf0, 0x1c, 0xbf, 0x4b, - 0x3d, 0x00, 0x39, 0x74, 0x32, 0x73, 0xd5, 0xe4, 0xba, 0xff, 0xff, 0xe0, - 0x31, 0xe5, 0xd7, 0x4f, 0x20, 0x70, 0x39, 0xe4, 0x62, 0x6c, 0xe5, 0x69, - 0x13, 0xdf, 0x97, 0xdf, 0xff, 0x87, 0x35, 0x9d, 0x7e, 0x05, 0xf5, 0x19, - 0x0b, 0x39, 0x7e, 0x9d, 0x90, 0x18, 0x39, 0x52, 0x5d, 0xd8, 0x0c, 0x79, - 0x7c, 0x91, 0x4d, 0x1a, 0xde, 0xca, 0x3a, 0xb9, 0xa4, 0x7f, 0x46, 0x47, - 0xc4, 0x91, 0x45, 0x6b, 0xff, 0x42, 0xaa, 0xc0, 0xe7, 0xba, 0x87, 0x2f, - 0xf4, 0x6b, 0x51, 0x3e, 0x36, 0x72, 0xff, 0x77, 0x19, 0x9d, 0xfc, 0x4e, - 0x50, 0x4f, 0x9f, 0xc6, 0x97, 0xd9, 0xb5, 0x50, 0xe5, 0x42, 0xfc, 0x76, - 0x4f, 0x00, 0x24, 0x29, 0x5e, 0x14, 0xbf, 0x91, 0x5e, 0x6d, 0xb6, 0xca, - 0x5f, 0xf6, 0x01, 0xf7, 0x9c, 0x70, 0x25, 0x3e, 0x9a, 0x0b, 0x9b, 0x6c, - 0xa5, 0xe6, 0xdb, 0x6c, 0xa5, 0xfc, 0xf3, 0x87, 0xb1, 0xa2, 0x9f, 0x4d, - 0x05, 0x0a, 0x31, 0x1b, 0x4b, 0x68, 0x73, 0x7e, 0x5a, 0x05, 0x46, 0x14, - 0xfa, 0x6c, 0xaf, 0x36, 0xdb, 0x65, 0x2f, 0x6a, 0x36, 0x53, 0xe9, 0xa0, - 0xbe, 0x71, 0xe7, 0xc7, 0x2c, 0x04, 0x45, 0x5f, 0x96, 0xdb, 0x2e, 0xbf, - 0x82, 0x31, 0x27, 0x59, 0xcb, 0xf6, 0xbf, 0x9d, 0xa0, 0x9c, 0xbf, 0x05, - 0x38, 0xc0, 0x4e, 0x5f, 0x60, 0xe3, 0x59, 0xca, 0xd9, 0xe6, 0x30, 0xa6, - 0x91, 0x13, 0x4a, 0x3c, 0x5f, 0xfd, 0xd7, 0x90, 0xba, 0xb3, 0x0a, 0x4c, - 0x72, 0xff, 0xdb, 0x9e, 0x39, 0xd2, 0x0e, 0x00, 0xe5, 0xff, 0x62, 0xe2, - 0x70, 0xf6, 0x34, 0x72, 0xb0, 0xfe, 0x1a, 0x1f, 0xdf, 0xdd, 0xce, 0x39, - 0xed, 0x1c, 0xa5, 0xa6, 0x1e, 0x08, 0x5e, 0xf8, 0x8e, 0xb6, 0xa8, 0xbb, - 0xb0, 0xc6, 0x18, 0xcc, 0xae, 0x9f, 0xc7, 0x2a, 0x15, 0x5c, 0x64, 0xa6, - 0x41, 0x3c, 0xbd, 0xcb, 0x52, 0x6a, 0x0e, 0x5f, 0x97, 0x1d, 0x86, 0x1c, - 0xb9, 0xfc, 0x72, 0xfd, 0x8d, 0x6e, 0x20, 0xc3, 0x7a, 0x24, 0xf7, 0xfd, - 0x03, 0x21, 0x0f, 0x62, 0x73, 0x97, 0xf0, 0x73, 0x6d, 0x18, 0x13, 0x97, - 0xba, 0x93, 0x14, 0xad, 0x9e, 0x6e, 0x8c, 0x2f, 0xf9, 0xf9, 0xf6, 0x4d, - 0xfe, 0xd5, 0x39, 0x65, 0xa1, 0xef, 0xfe, 0x45, 0x7f, 0x87, 0x39, 0x96, - 0x91, 0x53, 0x97, 0xce, 0xfb, 0x54, 0xe5, 0x7c, 0x3d, 0x69, 0xcd, 0x2f, - 0xfb, 0x31, 0x60, 0x8c, 0xe6, 0x47, 0x2f, 0xa1, 0xd9, 0xc4, 0xa5, 0xff, - 0xdd, 0x47, 0x00, 0x20, 0x11, 0xdd, 0x1c, 0xbf, 0xbb, 0x8c, 0x63, 0xc8, - 0xe5, 0xe6, 0xdb, 0x6c, 0xa5, 0xfe, 0x1f, 0x75, 0x20, 0x67, 0x29, 0xf4, - 0xd0, 0x5e, 0x80, 0x64, 0x91, 0x23, 0x89, 0xb5, 0xe4, 0xc1, 0x94, 0x86, - 0xa5, 0xb1, 0x69, 0xa9, 0xb2, 0x32, 0x9b, 0xf8, 0x10, 0x08, 0xee, 0x8e, - 0x5f, 0xe8, 0x53, 0x7b, 0x4f, 0x68, 0xe5, 0x42, 0xe2, 0x2c, 0x99, 0x95, - 0x3d, 0xe6, 0x1c, 0x88, 0xfd, 0x31, 0x2f, 0x63, 0x8b, 0x01, 0x78, 0x96, - 0xdf, 0x81, 0x89, 0xd5, 0x4e, 0x5f, 0xff, 0x62, 0xe0, 0x5f, 0xda, 0x0f, - 0xef, 0xb9, 0x1c, 0xae, 0x4f, 0xdd, 0x85, 0x17, 0xf4, 0x0a, 0xda, 0xa6, - 0xa6, 0xd5, 0x9c, 0xbf, 0x43, 0x37, 0x1c, 0x4e, 0x5f, 0xff, 0xfc, 0x2e, - 0xc8, 0xda, 0xc3, 0xd8, 0xd7, 0xee, 0x92, 0xd7, 0x5e, 0x47, 0x2f, 0x7f, - 0xed, 0x1c, 0xbc, 0xb8, 0xd1, 0xcb, 0xff, 0x94, 0x96, 0x75, 0xfa, 0x9b, - 0xdc, 0x1c, 0xac, 0x3e, 0x00, 0x0e, 0x5f, 0xa3, 0xda, 0xe3, 0x87, 0x2f, - 0xdf, 0xed, 0x5e, 0xa1, 0xca, 0x84, 0xfb, 0x02, 0x46, 0xb3, 0xd7, 0x29, - 0x03, 0x88, 0xbf, 0x78, 0x85, 0xa1, 0x4d, 0xfe, 0x17, 0x6f, 0x05, 0xd5, - 0x39, 0x7f, 0xf6, 0x7b, 0x4a, 0x69, 0x83, 0x1b, 0x83, 0x97, 0xb8, 0xe0, - 0x84, 0xfd, 0x98, 0x65, 0x7f, 0xf3, 0x71, 0xb1, 0x79, 0xe3, 0x71, 0x23, - 0x94, 0x87, 0xf1, 0xd3, 0x4b, 0xff, 0xfe, 0x0f, 0x51, 0xbc, 0xe0, 0x46, - 0x3f, 0xb5, 0xfc, 0xb3, 0x9f, 0x1c, 0xac, 0x44, 0x6b, 0x90, 0xdf, 0xf4, - 0xcb, 0xea, 0x32, 0x36, 0xa9, 0xcb, 0xf4, 0xff, 0x3f, 0x89, 0x8e, 0x5a, - 0x47, 0x2f, 0x28, 0x33, 0x1c, 0xa9, 0x1a, 0xf0, 0x08, 0xd6, 0x22, 0xe1, - 0xce, 0xf4, 0xb9, 0x50, 0xf8, 0x5b, 0x53, 0xca, 0xe5, 0x94, 0xae, 0x30, - 0xca, 0xa6, 0xca, 0x6c, 0xba, 0xb0, 0xbf, 0x5c, 0x31, 0x12, 0x56, 0x04, - 0xd2, 0xc7, 0x37, 0x2d, 0x01, 0x92, 0xc3, 0x3b, 0x38, 0xf4, 0xf2, 0x9c, - 0x01, 0x1a, 0x08, 0xcf, 0xe6, 0xea, 0x73, 0x57, 0xd3, 0x8f, 0x7f, 0xca, - 0xef, 0x6e, 0x3e, 0xc5, 0x21, 0xb3, 0x7b, 0x8c, 0x09, 0xcb, 0xff, 0xec, - 0x1f, 0xbe, 0x55, 0x39, 0xd7, 0x70, 0x0e, 0x72, 0xa4, 0x7d, 0xe1, 0x1d, - 0xb8, 0x10, 0x72, 0xfc, 0xbc, 0xf7, 0x50, 0xe5, 0x9d, 0x0d, 0xe8, 0x8b, - 0x5f, 0xff, 0xf6, 0x75, 0xd4, 0xd6, 0x2a, 0xe2, 0x08, 0x18, 0x9b, 0xb0, - 0x72, 0xd0, 0x72, 0xff, 0xfd, 0x1b, 0xec, 0x33, 0x83, 0xf8, 0x18, 0x9b, - 0xb0, 0x72, 0xfc, 0x9b, 0x9a, 0x3b, 0xb4, 0x66, 0x81, 0x94, 0x44, 0x2b, - 0x94, 0xe7, 0x18, 0xbe, 0xa4, 0x3c, 0x6d, 0xc2, 0xe7, 0x2f, 0xfc, 0xe2, - 0x0f, 0x81, 0xfd, 0xf7, 0x23, 0x97, 0xc8, 0x33, 0xc1, 0xcb, 0xde, 0xdc, - 0x1c, 0xbf, 0xe1, 0x86, 0x20, 0xe3, 0x20, 0xe5, 0xc8, 0x1c, 0x3d, 0x19, - 0x87, 0x29, 0xad, 0x1c, 0x1b, 0x41, 0x17, 0x2b, 0xff, 0x87, 0xda, 0xeb, - 0xcb, 0xe6, 0x73, 0xe3, 0x94, 0xd4, 0xd3, 0x71, 0xc8, 0x7c, 0x7e, 0x65, - 0x7a, 0x06, 0x73, 0x97, 0xc9, 0xd4, 0x61, 0xcb, 0x75, 0x0d, 0xec, 0xc3, - 0x97, 0xf4, 0x2e, 0x35, 0xe4, 0x39, 0x7f, 0xd1, 0xee, 0xb8, 0x1f, 0x9d, - 0x1c, 0xa0, 0x9f, 0x28, 0x96, 0x5f, 0xff, 0xe1, 0xfd, 0xd7, 0xaf, 0xdd, - 0x25, 0x02, 0xbc, 0xe7, 0xc7, 0x2f, 0xfd, 0xb0, 0x7c, 0xea, 0x2f, 0xfd, - 0x80, 0xe5, 0xe9, 0xbf, 0xd9, 0xcb, 0xff, 0x3a, 0x6f, 0x39, 0xfa, 0xdb, - 0x6d, 0x9c, 0xa8, 0x45, 0x33, 0xa1, 0xe8, 0x7e, 0xff, 0xf8, 0x62, 0x5f, - 0x14, 0xf2, 0x0f, 0xf2, 0xcd, 0x1c, 0xac, 0x54, 0x68, 0xb8, 0x46, 0x30, - 0x87, 0xb1, 0x83, 0x80, 0xba, 0xf0, 0x1d, 0x87, 0x2e, 0xc0, 0x1c, 0xa8, - 0x36, 0x58, 0x39, 0x79, 0xf1, 0x87, 0x2e, 0x19, 0x09, 0xba, 0xe0, 0x1f, - 0xbf, 0xcd, 0xe8, 0x70, 0x22, 0xe7, 0x2f, 0xb4, 0xb5, 0xa1, 0xca, 0x84, - 0x41, 0x21, 0x73, 0x99, 0x5f, 0xb7, 0xa1, 0x89, 0xce, 0x5f, 0xff, 0x37, - 0x8b, 0xd6, 0x7a, 0x6c, 0x54, 0x70, 0x07, 0x2b, 0x0f, 0xe5, 0x0a, 0x2f, - 0xe7, 0xf7, 0x5c, 0x40, 0x72, 0xff, 0xcf, 0xec, 0x99, 0xe0, 0x62, 0x63, - 0x97, 0xfe, 0xea, 0x62, 0x99, 0x33, 0x71, 0xc9, 0xcb, 0x26, 0xd1, 0x55, - 0xd2, 0xcd, 0x1e, 0xdc, 0xb5, 0x9a, 0x30, 0x45, 0x49, 0x32, 0x35, 0xc3, - 0x28, 0x06, 0xb7, 0x60, 0x9c, 0xbf, 0xfd, 0xe8, 0x15, 0xe7, 0xba, 0x9b, - 0x02, 0xce, 0x5f, 0x82, 0x9a, 0xea, 0x1c, 0xbf, 0x90, 0x73, 0xdd, 0x43, - 0x96, 0x8c, 0x3d, 0x2d, 0x13, 0xd0, 0x51, 0xad, 0x82, 0xbf, 0xc2, 0x6e, - 0xff, 0xe0, 0x6b, 0xa9, 0xbc, 0xf6, 0x9f, 0x93, 0x97, 0xfa, 0x19, 0xad, - 0x38, 0xce, 0x72, 0xff, 0x81, 0xa9, 0x27, 0x5d, 0x27, 0x39, 0x7d, 0xac, - 0x1f, 0x1c, 0xbd, 0xc1, 0x1b, 0x39, 0x48, 0x7f, 0x2e, 0x73, 0xf9, 0x0d, + 0x52, 0x3e, 0x40, 0x8c, 0xf4, 0x64, 0x46, 0x6d, 0xd2, 0xe2, 0x18, 0x51, + 0x71, 0x0c, 0x28, 0xb8, 0x86, 0x16, 0x91, 0x71, 0x0c, 0x28, 0xb8, 0x86, + 0x1c, 0x97, 0xf4, 0x5c, 0x43, 0x0a, 0x2e, 0x21, 0x85, 0x17, 0x10, 0xc2, + 0x8b, 0x88, 0x61, 0x53, 0xa3, 0x7a, 0x43, 0x2a, 0x9c, 0x2c, 0xa6, 0x61, + 0x90, 0x0c, 0xf8, 0x66, 0xd8, 0x5c, 0x43, 0x0a, 0x2e, 0x21, 0x85, 0x17, + 0x10, 0xc2, 0xd2, 0x2e, 0x21, 0x85, 0x17, 0x10, 0xc3, 0x92, 0xfe, 0x8b, + 0x88, 0x61, 0x45, 0xc4, 0x30, 0xa8, 0x45, 0x64, 0x86, 0x50, 0xe3, 0x45, + 0x2c, 0x19, 0xa2, 0xe2, 0x18, 0x51, 0x71, 0x0c, 0x28, 0xb8, 0x86, 0x14, + 0x5c, 0x43, 0x0a, 0x2e, 0x21, 0x85, 0x41, 0xfe, 0xf2, 0x33, 0xa1, 0x96, + 0x0c, 0x88, 0xcd, 0x17, 0x10, 0xc2, 0x8b, 0x88, 0x61, 0x45, 0xc4, 0x30, + 0xad, 0x1e, 0x5e, 0xc6, 0x7c, 0x33, 0x45, 0xc4, 0x30, 0xa2, 0xe2, 0x18, + 0x51, 0x71, 0x0c, 0x29, 0x87, 0x96, 0x23, 0x3e, 0x19, 0xb3, 0x0b, 0x88, + 0x61, 0x45, 0xc4, 0x30, 0xa2, 0xe2, 0x18, 0x50, 0x0d, 0x97, 0xe3, 0x34, + 0x5c, 0x43, 0x0a, 0x2e, 0x21, 0x85, 0x17, 0x10, 0xc2, 0x8b, 0x88, 0x61, + 0x50, 0x7c, 0x93, 0x0c, 0xf4, 0x67, 0xf1, 0x9a, 0x86, 0x60, 0x84, 0xf0, + 0x80, 0x92, 0x68, 0x55, 0xb2, 0x16, 0xcb, 0x84, 0x5f, 0x30, 0x85, 0x48, + 0x51, 0xb5, 0x9f, 0x4d, 0x08, 0x4d, 0x43, 0x5d, 0x89, 0x3d, 0x84, 0x1b, + 0xc2, 0x88, 0x07, 0x63, 0x0f, 0xdd, 0xb3, 0xfa, 0x19, 0x5f, 0xc3, 0x17, + 0x8c, 0x24, 0xdb, 0x7a, 0x68, 0x5c, 0xa2, 0x8f, 0x04, 0x21, 0xaf, 0xd2, + 0x18, 0xcd, 0x97, 0x10, 0xc3, 0xea, 0x72, 0xd7, 0x92, 0x18, 0x5c, 0x43, + 0x0b, 0xe4, 0x5b, 0xe8, 0xf8, 0x86, 0x2f, 0x20, 0x70, 0xf8, 0x86, 0x2d, + 0xf7, 0x94, 0x64, 0x69, 0x27, 0xa5, 0x3e, 0x2e, 0xb4, 0x71, 0x67, 0xc2, + 0x29, 0x4f, 0x3e, 0xbf, 0xdd, 0x46, 0xc3, 0xa8, 0x9c, 0xe5, 0xe4, 0xe3, + 0xc3, 0x9c, 0xae, 0x51, 0x21, 0x31, 0xc7, 0x8d, 0x6f, 0xd9, 0x93, 0x3a, + 0x87, 0x2e, 0x04, 0x1c, 0xbf, 0xb4, 0xe2, 0xa4, 0x00, 0xe5, 0xcf, 0xa3, + 0x96, 0x43, 0x8b, 0x2d, 0xac, 0xb3, 0x96, 0x61, 0xcb, 0x9a, 0x7d, 0x44, + 0x4d, 0x68, 0x5b, 0xa8, 0x6e, 0x3e, 0xa0, 0x8d, 0xff, 0x76, 0x19, 0x93, + 0x40, 0xce, 0x72, 0xff, 0xef, 0x8e, 0xb0, 0xf6, 0x01, 0x82, 0x03, 0x97, + 0x02, 0x0e, 0x56, 0x1e, 0xd8, 0x11, 0x6b, 0x13, 0x0e, 0x02, 0xcf, 0xf0, + 0x94, 0xbf, 0xf8, 0x46, 0x27, 0x1c, 0x4e, 0x30, 0xd0, 0xe5, 0xe8, 0xe7, + 0x67, 0x29, 0xcf, 0x8b, 0x68, 0xb7, 0x9f, 0x50, 0x72, 0xfc, 0x8d, 0x1c, + 0x40, 0x72, 0xfc, 0x9c, 0xed, 0xf9, 0x39, 0x52, 0x3e, 0xc6, 0x0d, 0xec, + 0xa2, 0xff, 0x94, 0x70, 0xef, 0x19, 0x0d, 0x67, 0x2f, 0x67, 0x2d, 0x9c, + 0xbd, 0xc8, 0x33, 0x47, 0xb4, 0x27, 0x97, 0xdc, 0x73, 0x52, 0x39, 0x78, + 0x2e, 0x27, 0x29, 0x0d, 0xfb, 0x92, 0x5f, 0xfc, 0xfa, 0xd3, 0x82, 0x3e, + 0xb6, 0xdb, 0x67, 0x2f, 0xfc, 0xae, 0x73, 0xe4, 0xf6, 0xbf, 0x61, 0xcb, + 0x47, 0xc4, 0x45, 0xf9, 0x26, 0xa1, 0x3c, 0xf7, 0x84, 0x4e, 0xdc, 0xbf, + 0x85, 0x55, 0xff, 0xdf, 0xa9, 0x37, 0xc8, 0x51, 0xd7, 0x1d, 0x39, 0x5c, + 0x23, 0xa1, 0xbe, 0x88, 0x5c, 0x4e, 0xe3, 0x28, 0xca, 0x43, 0x0f, 0xbc, + 0x86, 0xea, 0xa7, 0xab, 0x8c, 0xf7, 0x95, 0x74, 0x94, 0xd2, 0xd6, 0x8b, + 0x34, 0x2f, 0xb4, 0x70, 0xc8, 0xc1, 0xfb, 0x1a, 0xe3, 0xd6, 0x06, 0xa0, + 0x32, 0x18, 0xf4, 0x37, 0x09, 0x8f, 0x4a, 0x5c, 0x51, 0x1e, 0xf3, 0x36, + 0xb3, 0x97, 0x85, 0x70, 0x72, 0xbe, 0x1b, 0x84, 0x1d, 0xbf, 0x9b, 0x7d, + 0x69, 0xf9, 0x39, 0x7f, 0xfe, 0xde, 0xb4, 0x93, 0x6f, 0x51, 0xe4, 0x5a, + 0x04, 0xe5, 0x31, 0x14, 0xe2, 0x44, 0xd9, 0x7d, 0xf3, 0x3d, 0x1b, 0x39, + 0x7e, 0x02, 0x4e, 0x81, 0x39, 0x7d, 0xa4, 0x15, 0x4e, 0x5f, 0xef, 0x47, + 0xeb, 0xea, 0x68, 0xe5, 0xfd, 0x8b, 0xec, 0x73, 0x23, 0x97, 0xf3, 0x36, + 0x8a, 0xf9, 0xb3, 0x97, 0xe8, 0xe7, 0xb1, 0x23, 0x95, 0xa4, 0x6e, 0x09, + 0x17, 0x8d, 0x14, 0x2e, 0xe0, 0x30, 0xbf, 0xec, 0xe4, 0x73, 0xde, 0xc9, + 0xce, 0x5d, 0xcf, 0x8e, 0x5f, 0xb0, 0x67, 0x4d, 0x1c, 0xbf, 0x79, 0xc7, + 0xfc, 0x39, 0x7f, 0xb7, 0x8c, 0x4f, 0x75, 0xce, 0x5a, 0x31, 0x13, 0x1a, + 0x18, 0x12, 0x7f, 0x13, 0xde, 0xf8, 0xc4, 0x39, 0x70, 0xb0, 0xe5, 0x48, + 0xda, 0x6c, 0x7a, 0xf7, 0x06, 0xa0, 0xe5, 0xfe, 0xd2, 0x4c, 0x39, 0xc5, + 0xce, 0x5d, 0xce, 0xfe, 0x1f, 0xa4, 0x10, 0xe8, 0x7e, 0xff, 0x86, 0x1e, + 0x7e, 0xc6, 0x80, 0x72, 0xff, 0x26, 0x87, 0xde, 0xc9, 0xce, 0x5c, 0xfc, + 0x4e, 0x5f, 0xd2, 0x14, 0x97, 0x70, 0xe5, 0xfa, 0x74, 0xd4, 0x48, 0xe5, + 0x2a, 0x89, 0xf9, 0x8c, 0xf4, 0x30, 0x25, 0x97, 0xef, 0xfc, 0xd3, 0x3c, + 0x72, 0xf0, 0x51, 0x53, 0x95, 0x07, 0x91, 0x85, 0x77, 0xb4, 0x05, 0x0e, + 0x5f, 0xfc, 0x9e, 0x8f, 0x6f, 0xae, 0x9d, 0xfc, 0xe5, 0x41, 0xf1, 0x38, + 0xf5, 0xf0, 0x8f, 0xf2, 0x39, 0x7f, 0xee, 0xc6, 0x80, 0x38, 0xdb, 0x80, + 0xe5, 0xec, 0xc9, 0x8e, 0x5b, 0x3a, 0x7b, 0x40, 0x3e, 0xbd, 0x1c, 0xb6, + 0x72, 0xfd, 0xaf, 0xd8, 0xe2, 0x72, 0xbc, 0x78, 0xdf, 0x8f, 0x5f, 0x32, + 0x32, 0x73, 0x97, 0xec, 0xe2, 0x31, 0xc9, 0xca, 0x43, 0xcb, 0xd9, 0x15, + 0xf4, 0x0f, 0x96, 0x72, 0x82, 0xae, 0x63, 0x21, 0xaf, 0xa8, 0x43, 0x76, + 0x10, 0x4e, 0x40, 0x2f, 0x9b, 0x6d, 0xf3, 0x73, 0x42, 0x1b, 0xfc, 0x05, + 0x30, 0x43, 0xd8, 0x39, 0x50, 0x8c, 0x17, 0x84, 0x75, 0xfd, 0xbc, 0x62, + 0x76, 0x0e, 0x5e, 0xe6, 0x5b, 0x39, 0x5c, 0x9e, 0x56, 0x8b, 0x2f, 0x6c, + 0x0d, 0x9c, 0xbf, 0xe9, 0x31, 0xe5, 0xed, 0xc2, 0xa7, 0x2a, 0x0f, 0xef, + 0x08, 0xdc, 0x7a, 0xff, 0xc8, 0xd8, 0xe6, 0xb7, 0xdc, 0x59, 0xcb, 0xef, + 0xdf, 0x52, 0x39, 0x7d, 0x1f, 0xf0, 0xfb, 0x29, 0x7e, 0x97, 0xd6, 0xdb, + 0x6c, 0xe5, 0x09, 0xeb, 0x7e, 0x51, 0x7c, 0xfe, 0x67, 0x8e, 0x50, 0x51, + 0x7b, 0x8f, 0x20, 0x22, 0xbf, 0xc0, 0x1c, 0xe3, 0xa4, 0xd9, 0xcb, 0xfc, + 0xa0, 0x8b, 0xb6, 0xfd, 0x39, 0x50, 0xca, 0x9a, 0xc3, 0x0e, 0x48, 0x92, + 0x30, 0x4d, 0x26, 0xb2, 0x1a, 0x2f, 0x0e, 0x80, 0x4e, 0x4b, 0x0c, 0x3a, + 0xf6, 0x59, 0xfc, 0x3e, 0xf8, 0x97, 0xb6, 0x69, 0x79, 0xaa, 0x6a, 0x3c, + 0x21, 0xcb, 0xd2, 0x17, 0x39, 0x6e, 0x5a, 0xa3, 0xc8, 0x82, 0xdb, 0xf7, + 0x04, 0x4b, 0x50, 0x72, 0xf7, 0x9c, 0x07, 0x2f, 0xe8, 0xd4, 0xf1, 0xa9, + 0xce, 0x5f, 0xfa, 0x07, 0xdd, 0xfd, 0xe5, 0x28, 0x39, 0x7e, 0xfc, 0x18, + 0x2b, 0x39, 0x7b, 0x51, 0x31, 0xcb, 0xe4, 0x17, 0x98, 0xe5, 0xff, 0x86, + 0x15, 0xeb, 0xf9, 0x4c, 0x01, 0xcb, 0xdb, 0xd6, 0x1c, 0xbf, 0xb3, 0x40, + 0x1f, 0xc0, 0x72, 0x90, 0xf2, 0xb6, 0x39, 0x66, 0xb3, 0x97, 0xf6, 0x29, + 0x13, 0x26, 0xce, 0x50, 0x9e, 0x17, 0x85, 0x2a, 0x15, 0x13, 0x4e, 0x55, + 0x21, 0xc0, 0x97, 0xe8, 0xf9, 0x85, 0x1d, 0x1d, 0x12, 0x1f, 0x42, 0x27, + 0x8b, 0x1d, 0xff, 0x42, 0x76, 0x19, 0x3e, 0x36, 0x72, 0xfd, 0xd4, 0x9d, + 0xc4, 0xe5, 0xfb, 0xf5, 0x5c, 0x40, 0x72, 0xfe, 0xde, 0xa3, 0x02, 0x87, + 0x2a, 0x0f, 0xf3, 0xa4, 0xfc, 0x4a, 0x6f, 0xfa, 0x71, 0xc9, 0x77, 0x01, + 0xb3, 0x97, 0xfe, 0xc1, 0xe6, 0x5b, 0xd7, 0xf0, 0x03, 0x97, 0xec, 0xf6, + 0xf1, 0x53, 0x94, 0x87, 0xd0, 0xc4, 0x0b, 0xff, 0x6b, 0xad, 0xb8, 0x78, + 0xfb, 0x16, 0x72, 0xfd, 0xef, 0x9d, 0xce, 0x03, 0x94, 0xe7, 0xde, 0x28, + 0x57, 0x83, 0x1c, 0x4e, 0x5f, 0xfe, 0x11, 0x86, 0xc2, 0x31, 0xcc, 0x90, + 0x4e, 0x5f, 0x99, 0x9d, 0x7e, 0x03, 0x95, 0x87, 0xe4, 0x89, 0x17, 0xff, + 0x9f, 0xe4, 0xd2, 0x8d, 0x4f, 0xf1, 0xbc, 0xe9, 0xca, 0x84, 0xc8, 0x42, + 0x41, 0xd8, 0x48, 0x09, 0x05, 0xff, 0x33, 0xb9, 0xec, 0xff, 0x53, 0x9c, + 0xbf, 0xfb, 0xdb, 0x41, 0x9a, 0x17, 0xac, 0xe4, 0xe5, 0xf8, 0x2a, 0xab, + 0xff, 0x27, 0x2c, 0xab, 0x9f, 0x97, 0xe8, 0xb7, 0xfd, 0x1e, 0xcd, 0x2d, + 0xdd, 0x66, 0x8b, 0xe1, 0x7e, 0xcd, 0x47, 0x32, 0x39, 0x7b, 0xb0, 0xc5, + 0x9f, 0x67, 0x91, 0x2f, 0xff, 0xc2, 0xbf, 0x9d, 0x84, 0xd2, 0x31, 0x1a, + 0x43, 0x0e, 0x5e, 0x7d, 0x4e, 0x68, 0xbf, 0xd5, 0x08, 0xb4, 0xc3, 0x35, + 0xab, 0xdf, 0xf3, 0xfb, 0x68, 0x3c, 0xc9, 0x87, 0x2f, 0xfa, 0x33, 0x5f, + 0x24, 0x9c, 0xc8, 0xe5, 0x00, 0xfd, 0x3c, 0x73, 0x7f, 0xff, 0xba, 0xfb, + 0x48, 0xdf, 0xcf, 0x77, 0x19, 0x8b, 0x7d, 0x1c, 0xba, 0x38, 0x0e, 0x5f, + 0x6f, 0x6e, 0xc3, 0x95, 0xd4, 0x4e, 0x01, 0x87, 0xc3, 0x37, 0xfe, 0x9f, + 0x39, 0xf2, 0x9d, 0xee, 0x35, 0x9c, 0xbe, 0xe6, 0x5e, 0x73, 0x97, 0xff, + 0xc1, 0x5f, 0x50, 0x73, 0x8b, 0xcb, 0x68, 0x13, 0x95, 0x87, 0xe6, 0xe4, + 0x77, 0xe0, 0x6f, 0xd9, 0xd3, 0x97, 0xf3, 0x7e, 0xce, 0xcb, 0x0e, 0x54, + 0x1e, 0xb3, 0x94, 0x54, 0x26, 0x9d, 0x28, 0x5c, 0x0b, 0xb5, 0xff, 0x43, + 0x3e, 0x07, 0x30, 0x1b, 0x39, 0x7c, 0x8c, 0xd4, 0xe7, 0x2f, 0xfd, 0xe8, + 0xde, 0xe1, 0x27, 0x7f, 0x1c, 0xbf, 0xe4, 0xc1, 0x0a, 0xa9, 0x9a, 0x39, + 0x48, 0x8d, 0x2d, 0x1d, 0x78, 0x8f, 0x80, 0xfa, 0xf7, 0xb3, 0x93, 0x97, + 0xf3, 0xeb, 0x99, 0x67, 0x8e, 0x5f, 0xfb, 0xdb, 0x4d, 0x78, 0x7f, 0x79, + 0x1c, 0xbf, 0xff, 0x26, 0xf0, 0x3d, 0xcf, 0x26, 0x6e, 0x7c, 0x6c, 0xe5, + 0xff, 0xe6, 0x43, 0x4c, 0xfc, 0x73, 0x38, 0xc7, 0x27, 0x2f, 0xfd, 0x19, + 0xac, 0xd0, 0x18, 0x9b, 0x39, 0x79, 0xf9, 0xe0, 0x39, 0x7f, 0x3f, 0xb7, + 0x19, 0x39, 0xca, 0x84, 0xe6, 0x70, 0xb9, 0x67, 0xe8, 0xaa, 0x29, 0xbc, + 0x4f, 0x5b, 0x20, 0xbf, 0xef, 0xe1, 0x9b, 0xc6, 0x43, 0x59, 0xcb, 0xff, + 0x6a, 0x7c, 0x0e, 0x77, 0xb8, 0xd6, 0x72, 0xca, 0x9c, 0xbf, 0xde, 0xda, + 0x9c, 0x63, 0x39, 0x39, 0x6c, 0x83, 0xc9, 0x11, 0x2a, 0xc4, 0x58, 0x6e, + 0x11, 0x77, 0xf6, 0xde, 0x43, 0x0c, 0x39, 0x7f, 0xfd, 0x28, 0xd4, 0xfe, + 0x45, 0x77, 0xb7, 0x19, 0x1c, 0xbf, 0xa7, 0xde, 0x32, 0x1a, 0xce, 0x54, + 0xc8, 0x82, 0x51, 0x46, 0xb4, 0x8d, 0x36, 0xe1, 0x5d, 0x79, 0x3a, 0x87, + 0x2f, 0xa5, 0xa0, 0xc8, 0xe5, 0xf3, 0x3c, 0x93, 0x9c, 0xac, 0x3c, 0x64, + 0x23, 0xbf, 0xfb, 0x8f, 0x95, 0x81, 0x96, 0x75, 0x18, 0x72, 0xe9, 0xfc, + 0x72, 0xff, 0x71, 0xeb, 0xca, 0x30, 0x4e, 0x54, 0x1e, 0x5e, 0x0c, 0x5f, + 0xff, 0xa5, 0xd8, 0xd3, 0xfb, 0xff, 0x27, 0xb7, 0xd4, 0x39, 0x7f, 0x63, + 0x6a, 0x75, 0xfc, 0x72, 0xfe, 0x93, 0x3c, 0x3f, 0xcc, 0x72, 0xff, 0xf9, + 0x49, 0x47, 0x14, 0x10, 0x69, 0x21, 0x98, 0x52, 0xb4, 0x88, 0x0f, 0x18, + 0x5f, 0x75, 0x4e, 0x7c, 0x72, 0xfd, 0x8c, 0xc4, 0xe2, 0x72, 0xf4, 0xf3, + 0x35, 0x9c, 0xa8, 0x4e, 0x5e, 0x75, 0x6c, 0x85, 0x7a, 0xc8, 0xd0, 0x97, + 0xf2, 0x8b, 0xbd, 0x87, 0x2f, 0xda, 0x49, 0xdd, 0x86, 0x98, 0x4d, 0x7d, + 0xef, 0xe1, 0xcd, 0x30, 0x9a, 0xe0, 0x41, 0xa8, 0x13, 0x5f, 0xe1, 0x75, + 0x7d, 0x1a, 0x01, 0xa8, 0x13, 0x5f, 0xed, 0xe7, 0x53, 0x7f, 0xce, 0x69, + 0x84, 0xd7, 0x60, 0x4d, 0x30, 0x9a, 0xe6, 0xdb, 0x3c, 0xc2, 0x6a, 0xc4, + 0xd4, 0xb9, 0x35, 0x42, 0xf6, 0x11, 0xed, 0x03, 0x8a, 0x13, 0x64, 0x76, + 0xf1, 0x66, 0x13, 0x3e, 0x9f, 0x3d, 0x93, 0x95, 0x40, 0x2d, 0xc7, 0x9f, + 0x50, 0xbb, 0x02, 0x85, 0x3d, 0x61, 0x72, 0x01, 0x84, 0x8e, 0xe3, 0xb7, + 0xf4, 0xa5, 0xdb, 0xe7, 0xe3, 0x8d, 0x9c, 0xbf, 0xff, 0x75, 0xe5, 0xd8, + 0x84, 0xf6, 0xd0, 0x79, 0x91, 0xcb, 0xc2, 0x06, 0x1c, 0xbf, 0xe8, 0xff, + 0xc2, 0x9c, 0x54, 0x61, 0xcb, 0xb3, 0x78, 0x7b, 0x1a, 0x1c, 0xad, 0x23, + 0xf1, 0xc9, 0x06, 0x15, 0x97, 0xd8, 0x9a, 0x54, 0xe5, 0xe0, 0x82, 0x63, + 0x95, 0x0d, 0xa0, 0x8c, 0xf0, 0xa1, 0x0c, 0x76, 0x38, 0x82, 0xac, 0x2b, + 0x57, 0x1a, 0x4f, 0x30, 0xa2, 0x48, 0x5f, 0x4d, 0x1b, 0xf6, 0xa3, 0x06, + 0x61, 0xff, 0x63, 0xb6, 0x16, 0x4d, 0xc3, 0xb3, 0xd3, 0xcf, 0x7c, 0x63, + 0x71, 0x68, 0x66, 0xa1, 0x15, 0xfb, 0xbc, 0xed, 0x20, 0xe5, 0xf6, 0x69, + 0x15, 0x39, 0x50, 0x79, 0x41, 0x28, 0xbf, 0xbb, 0x0a, 0x0f, 0x20, 0x39, + 0x79, 0xab, 0xce, 0x03, 0x97, 0xb3, 0x1b, 0x39, 0x72, 0x2a, 0x72, 0xa7, + 0x36, 0x68, 0x39, 0x7e, 0xf6, 0x4c, 0x8c, 0x39, 0x7e, 0x8e, 0x40, 0x08, + 0x39, 0x50, 0x7a, 0x02, 0x51, 0x7e, 0x8e, 0x30, 0x3e, 0x39, 0x7e, 0x4e, + 0x3e, 0x49, 0xce, 0x5f, 0xf9, 0x82, 0x8a, 0xc7, 0xb6, 0x9a, 0x39, 0x7d, + 0x2f, 0x62, 0xce, 0x56, 0x1f, 0x03, 0x9f, 0x5f, 0x87, 0x14, 0xc9, 0x8e, + 0x5f, 0xff, 0x0a, 0xd1, 0x81, 0xfd, 0xf5, 0x2c, 0xe7, 0xc7, 0x2f, 0xfc, + 0xe2, 0x0e, 0x7d, 0xa8, 0xc6, 0xce, 0x5f, 0xfb, 0x7d, 0x4f, 0x9c, 0xca, + 0x32, 0x73, 0x96, 0xc6, 0xb4, 0x40, 0x80, 0xfe, 0xff, 0xba, 0xec, 0xea, + 0x47, 0x32, 0x39, 0x7f, 0x28, 0x32, 0x68, 0xf3, 0x9c, 0xa8, 0x4d, 0x9e, + 0x50, 0xd2, 0x42, 0xb0, 0x1c, 0xd4, 0xea, 0xb0, 0x82, 0x40, 0xb2, 0x8d, + 0x42, 0x28, 0x48, 0x3d, 0x1c, 0x7d, 0xff, 0xb1, 0xfb, 0x32, 0x0f, 0x73, + 0x93, 0x97, 0xf0, 0x26, 0x94, 0x7b, 0x67, 0x2f, 0xff, 0xff, 0xbb, 0x82, + 0x0c, 0x1f, 0x77, 0x3b, 0x19, 0x32, 0x6a, 0x6e, 0xa7, 0x3e, 0x39, 0x7f, + 0x99, 0xa4, 0x5f, 0x72, 0x63, 0x95, 0x88, 0xb1, 0x77, 0xdb, 0xe1, 0x8c, + 0x6c, 0xe5, 0xf4, 0x73, 0xb7, 0x39, 0x50, 0xde, 0x6a, 0xcf, 0x09, 0x30, + 0xc2, 0xd7, 0x2b, 0x44, 0x14, 0x8e, 0x31, 0xac, 0x86, 0x62, 0xfd, 0x2b, + 0xbc, 0xb3, 0x31, 0x64, 0xf1, 0xf7, 0xf0, 0xe0, 0xe2, 0x42, 0xa1, 0x0d, + 0xff, 0xf2, 0x0e, 0x32, 0x14, 0x1f, 0xe4, 0x38, 0xc3, 0x97, 0xfc, 0x14, + 0xc1, 0xfe, 0x59, 0xb3, 0x97, 0xfd, 0xad, 0x42, 0xfb, 0xcb, 0xb5, 0x9c, + 0xb7, 0xe7, 0x2f, 0xe5, 0xfe, 0xe1, 0x64, 0x1c, 0xbf, 0xee, 0xa4, 0xba, + 0xf2, 0x46, 0x1c, 0xbf, 0xf6, 0xd0, 0x79, 0x97, 0x93, 0x68, 0x72, 0xb0, + 0xfd, 0xbc, 0x71, 0x7e, 0xdb, 0x20, 0x30, 0x72, 0xa4, 0x9e, 0x0e, 0x27, + 0x21, 0xc4, 0xc7, 0xba, 0x12, 0x64, 0x29, 0x3c, 0x43, 0x7c, 0x31, 0xa9, + 0x1c, 0xbf, 0xee, 0xc4, 0x90, 0x47, 0xfe, 0x4e, 0x5f, 0xf4, 0x49, 0x3d, + 0x28, 0x10, 0x1c, 0xbf, 0xe8, 0xcf, 0x28, 0x00, 0x47, 0x27, 0x2d, 0xa8, + 0x46, 0x5e, 0x10, 0xe8, 0xe5, 0x86, 0xf7, 0xf0, 0xc2, 0xf5, 0x12, 0x39, + 0x7f, 0xfd, 0xd7, 0x4f, 0x4b, 0xf1, 0xf6, 0xfa, 0xf2, 0x38, 0xa1, 0xac, + 0xbf, 0xf6, 0xd4, 0xf2, 0x0f, 0xf2, 0xcd, 0x9c, 0xb8, 0x3b, 0x39, 0x4d, + 0x68, 0xb8, 0xeb, 0x08, 0xa0, 0x5f, 0xff, 0xd9, 0xce, 0x6d, 0xc7, 0xa9, + 0x1e, 0xef, 0xee, 0xc3, 0x95, 0x09, 0xd8, 0xbc, 0x64, 0xa2, 0x65, 0x7e, + 0xfd, 0x89, 0xd8, 0x39, 0x7e, 0xcd, 0x2e, 0x30, 0xe5, 0x09, 0xe7, 0x28, + 0x51, 0x7f, 0xf3, 0xb0, 0x63, 0x96, 0x8a, 0xfb, 0x3a, 0x72, 0xff, 0xfc, + 0xe3, 0xe7, 0x7e, 0x8c, 0x7b, 0x6d, 0xe7, 0x4e, 0x5f, 0xfc, 0xcd, 0xbc, + 0xb5, 0x1b, 0x81, 0x9c, 0xe5, 0xff, 0x47, 0xbb, 0x8c, 0xcd, 0x61, 0xcb, + 0xf7, 0xba, 0x91, 0xb3, 0x97, 0xa7, 0x71, 0xd1, 0xef, 0x6c, 0xde, 0xff, + 0xa0, 0x1b, 0x0f, 0xef, 0xa9, 0x1c, 0xbd, 0xad, 0xec, 0xf1, 0x01, 0xaf, + 0x96, 0xee, 0xb3, 0x44, 0x06, 0xfa, 0x6a, 0xaf, 0xed, 0x47, 0x63, 0xe6, + 0x49, 0x14, 0x9a, 0x64, 0xac, 0x4e, 0xfd, 0xe1, 0x44, 0xa4, 0x35, 0xeb, + 0xaa, 0xa4, 0xc0, 0x8f, 0xe9, 0x42, 0x57, 0xb8, 0xc7, 0x4e, 0x56, 0x2b, + 0x0c, 0x49, 0x56, 0xaa, 0x1c, 0xdc, 0xfc, 0x9c, 0xbd, 0xd7, 0x6b, 0x39, + 0x7d, 0x00, 0x69, 0x87, 0x2f, 0x98, 0xc7, 0xf1, 0xca, 0x61, 0xfd, 0x80, + 0x5f, 0xc3, 0xea, 0x11, 0xdf, 0x0f, 0x81, 0xf9, 0xcb, 0xf3, 0x1a, 0xa6, + 0xa9, 0xaa, 0x6a, 0x4e, 0x5f, 0xff, 0xd2, 0xcd, 0xa6, 0xb4, 0x8c, 0x53, + 0xdd, 0xc6, 0xfc, 0x72, 0xb1, 0x17, 0xa8, 0x46, 0xe7, 0xb7, 0xff, 0x9b, + 0xc1, 0xf6, 0x0c, 0xb3, 0x6a, 0x30, 0xe5, 0xff, 0xe9, 0x67, 0x32, 0x52, + 0x01, 0xf5, 0xb6, 0xdb, 0x29, 0x7e, 0x63, 0x78, 0x9c, 0x4e, 0x5e, 0x96, + 0x0c, 0xc7, 0xf8, 0xa2, 0x95, 0x42, 0x3e, 0x9e, 0x18, 0xd7, 0xff, 0xe7, + 0xd4, 0x83, 0xd8, 0xd8, 0xe3, 0x6f, 0xa5, 0x4e, 0x54, 0x2a, 0x9d, 0xec, + 0x3e, 0x86, 0x32, 0x7f, 0xc9, 0xaf, 0xf9, 0x06, 0x5b, 0x6a, 0x0d, 0x4b, + 0x54, 0xd4, 0x9c, 0xbe, 0x9b, 0x79, 0x31, 0xcb, 0xf0, 0x23, 0xd8, 0xd6, + 0x72, 0xff, 0x46, 0x69, 0x6e, 0xeb, 0x34, 0x41, 0x2b, 0xfe, 0x8f, 0x66, + 0x96, 0xee, 0xb3, 0x45, 0xf2, 0xbf, 0x38, 0x7b, 0x0a, 0x9c, 0xbc, 0x39, + 0xb0, 0xa2, 0xa9, 0x67, 0xcc, 0x44, 0xa1, 0x4c, 0x53, 0x8c, 0x35, 0x2f, + 0xfe, 0x8e, 0xa2, 0xb9, 0xa9, 0xd9, 0xff, 0x27, 0x2f, 0xf8, 0x3a, 0xc6, + 0x64, 0x9c, 0x27, 0x2b, 0x13, 0xe2, 0x48, 0xce, 0x3a, 0x54, 0xe9, 0x17, + 0xe9, 0x60, 0x14, 0xf1, 0xcb, 0xfb, 0xad, 0x3a, 0x8b, 0xe9, 0xca, 0x73, + 0xd9, 0xfc, 0xa6, 0xff, 0xde, 0x86, 0x6e, 0x12, 0x77, 0xf1, 0xcb, 0xff, + 0x4e, 0xfc, 0xb4, 0xcf, 0x0b, 0xf1, 0x39, 0x7f, 0xfd, 0x9e, 0x81, 0xf6, + 0xf3, 0x15, 0x55, 0xe4, 0x72, 0xfe, 0x57, 0x3d, 0xec, 0x09, 0xcb, 0xff, + 0x60, 0x62, 0x51, 0xdc, 0x03, 0x9c, 0xbf, 0x9e, 0x5f, 0xc9, 0xc2, 0x72, + 0xfe, 0xea, 0x4f, 0xbd, 0xb9, 0xcb, 0xcd, 0xb6, 0xd9, 0x4b, 0xf7, 0x71, + 0x6f, 0xa2, 0x9f, 0x4d, 0x05, 0xff, 0xfe, 0x9b, 0x51, 0xc7, 0xe2, 0xaf, + 0xf1, 0x49, 0xb7, 0xf3, 0x39, 0xf1, 0xca, 0x84, 0x7b, 0x79, 0x39, 0x43, + 0x9b, 0xff, 0xc9, 0xa4, 0xf7, 0xf9, 0xe7, 0x66, 0x09, 0xca, 0x9d, 0x54, + 0xc2, 0xd0, 0xf4, 0x9e, 0xc2, 0xe0, 0x1e, 0x0c, 0x64, 0x9e, 0x30, 0xbf, + 0xf3, 0x23, 0x9d, 0x8e, 0x4e, 0xa4, 0x8e, 0x5f, 0xff, 0xe4, 0xeb, 0x8f, + 0x32, 0x52, 0x50, 0x32, 0x76, 0x60, 0x4e, 0x5f, 0xfe, 0xcc, 0xe8, 0x7b, + 0x1b, 0xce, 0xa0, 0x0e, 0x5f, 0xa6, 0x94, 0x6b, 0x67, 0x2f, 0xf6, 0x0f, + 0xf2, 0xdc, 0xee, 0x72, 0xca, 0xfc, 0x3d, 0xd0, 0x94, 0xd4, 0xe9, 0xb8, + 0xc9, 0x04, 0x2c, 0x09, 0x0a, 0x5b, 0xef, 0x89, 0xdf, 0xce, 0x5f, 0xb2, + 0x5d, 0x8d, 0x1c, 0xa5, 0x9e, 0x63, 0x59, 0x2d, 0xfe, 0xf4, 0x27, 0x55, + 0x8e, 0x4e, 0x5f, 0xfd, 0xed, 0xbc, 0xb7, 0x8b, 0x86, 0x21, 0xcb, 0xff, + 0xdc, 0x8f, 0xc5, 0xf5, 0x00, 0x08, 0xd4, 0x8e, 0x54, 0x23, 0xa5, 0x09, + 0x7f, 0x34, 0x51, 0x0e, 0xfe, 0x4d, 0xe0, 0x54, 0xc3, 0x97, 0xee, 0x04, + 0x1c, 0xe2, 0x72, 0xff, 0x6b, 0x02, 0x9f, 0xaf, 0xab, 0x3d, 0x87, 0x2d, + 0xbf, 0xdb, 0x1c, 0xe3, 0xd7, 0x91, 0xcb, 0xdb, 0x97, 0x13, 0x94, 0x87, + 0xa6, 0xd6, 0x69, 0x7f, 0xfa, 0x27, 0x53, 0xb1, 0xcf, 0xb2, 0x71, 0x09, + 0xca, 0x44, 0xc3, 0x9e, 0x13, 0xa2, 0x49, 0x7f, 0xfb, 0xaf, 0x2c, 0x08, + 0xa3, 0xf6, 0x18, 0x72, 0xff, 0x46, 0x0f, 0xb8, 0x46, 0xd6, 0x72, 0xff, + 0x77, 0x38, 0xfc, 0xdc, 0x96, 0x72, 0xb6, 0x7e, 0x1e, 0x38, 0xaf, 0x23, + 0x67, 0xf8, 0x5b, 0xdf, 0xc3, 0xf1, 0x4d, 0x75, 0xce, 0x5f, 0xfb, 0xf7, + 0x97, 0xc8, 0x40, 0xe3, 0x0e, 0x53, 0x9f, 0x80, 0x98, 0x5f, 0xfb, 0x48, + 0x09, 0xfb, 0x1b, 0xff, 0x67, 0x2f, 0xd9, 0xa7, 0xe5, 0xb3, 0x97, 0xff, + 0xfa, 0x7c, 0x6c, 0x70, 0x3a, 0x4f, 0xe7, 0x0f, 0x60, 0x67, 0x39, 0x53, + 0xa2, 0x37, 0x65, 0x37, 0xfa, 0x61, 0x76, 0xfd, 0x9d, 0x39, 0x7b, 0xb8, + 0xb3, 0x97, 0x9b, 0x6d, 0xb2, 0x97, 0xf0, 0x20, 0x73, 0x9f, 0x14, 0xfa, + 0x68, 0x2b, 0xe2, 0x2b, 0xda, 0x1a, 0x28, 0x79, 0x7f, 0xff, 0x70, 0xff, + 0x17, 0xd4, 0x08, 0x71, 0xbf, 0x9e, 0xde, 0x4e, 0x72, 0xba, 0x89, 0xcf, + 0xcd, 0x6a, 0x15, 0x30, 0xa4, 0x33, 0x9e, 0x36, 0xfb, 0xfe, 0x52, 0x37, + 0x8d, 0xa8, 0x3e, 0x39, 0x53, 0xb3, 0xd5, 0x65, 0x28, 0xc0, 0x30, 0x9a, + 0xe4, 0x89, 0x25, 0x6b, 0x6a, 0x3d, 0xd6, 0x46, 0xf1, 0xd8, 0xe8, 0xc6, + 0x30, 0xcd, 0xc2, 0x67, 0xd2, 0xa0, 0x54, 0x3a, 0xbf, 0xf6, 0x20, 0xce, + 0xe3, 0xec, 0x61, 0xcb, 0xff, 0xda, 0x55, 0x4f, 0x26, 0xc7, 0x38, 0xa0, + 0x4e, 0x5f, 0xf2, 0x36, 0x1e, 0xe7, 0x9a, 0x61, 0xca, 0x84, 0x44, 0x75, + 0x36, 0xf8, 0x5f, 0x9f, 0x1c, 0xbd, 0x82, 0x03, 0x97, 0xd9, 0xe9, 0xa4, + 0x72, 0xff, 0xee, 0x01, 0x8e, 0x0d, 0xb8, 0xa8, 0x0d, 0x9c, 0xae, 0x9f, + 0x6b, 0x91, 0xdf, 0xfb, 0x3d, 0x1a, 0xdf, 0x60, 0x7c, 0x78, 0x82, 0x17, + 0xf6, 0x69, 0x6e, 0xeb, 0x34, 0x41, 0x0f, 0xa7, 0x95, 0x7a, 0x02, 0x87, + 0x2a, 0x0f, 0x9f, 0x69, 0x97, 0xb8, 0xc3, 0x0e, 0x5f, 0xcf, 0xdd, 0x69, + 0x1b, 0x39, 0x7f, 0x35, 0x85, 0xb7, 0x19, 0x1c, 0xac, 0x3f, 0xd1, 0x1e, + 0xfc, 0xba, 0xff, 0xf4, 0xd2, 0x41, 0xf4, 0x02, 0x61, 0x49, 0x8e, 0x5c, + 0x33, 0x1c, 0xb4, 0x04, 0xf8, 0xb1, 0x2e, 0xa7, 0x55, 0xa0, 0xa9, 0x17, + 0x61, 0x10, 0x08, 0x69, 0x0c, 0x27, 0xb8, 0xc2, 0x42, 0xfe, 0xee, 0x7b, + 0xc8, 0xc3, 0x97, 0xf7, 0x94, 0xce, 0xbf, 0x27, 0x2b, 0x93, 0xdc, 0x12, + 0xdb, 0xfb, 0x39, 0xf6, 0xb5, 0x07, 0x2f, 0xfe, 0xd8, 0xbf, 0x9d, 0x8a, + 0x44, 0xf8, 0x72, 0x82, 0x7e, 0x5b, 0x2e, 0xa8, 0x45, 0xb7, 0xf0, 0x94, + 0xbf, 0xb1, 0x6a, 0x71, 0xee, 0x1c, 0xba, 0x15, 0x39, 0x72, 0x09, 0xcb, + 0x36, 0x72, 0x82, 0x69, 0xd4, 0x15, 0xbc, 0x3f, 0xce, 0x72, 0xfd, 0xd7, + 0x96, 0x09, 0xcb, 0xf9, 0x3c, 0x39, 0xd4, 0x39, 0x76, 0x77, 0xe1, 0xe8, + 0xc1, 0x35, 0xce, 0xdf, 0xc4, 0x7e, 0xe1, 0xf7, 0x48, 0xbc, 0xdf, 0x52, + 0x4e, 0x7f, 0x0a, 0x06, 0x32, 0xdb, 0xfb, 0x68, 0x10, 0xe0, 0x9c, 0xbf, + 0xff, 0xbd, 0xdc, 0xde, 0xf3, 0x3f, 0xd4, 0xf9, 0xf8, 0xf8, 0xe5, 0xff, + 0x76, 0x35, 0xe1, 0x8c, 0xe4, 0xe5, 0xff, 0xff, 0x24, 0xf1, 0x2d, 0xeb, + 0x49, 0xcc, 0xd2, 0x7d, 0x33, 0x39, 0x39, 0x7f, 0xa1, 0xe7, 0x7d, 0x3a, + 0x87, 0x2f, 0x77, 0x04, 0x28, 0xd5, 0xe9, 0xc7, 0x9a, 0xab, 0x13, 0x9e, + 0x42, 0xcf, 0x46, 0x65, 0x7e, 0x8d, 0x4d, 0xb9, 0xce, 0x5f, 0xf7, 0x63, + 0x35, 0x2d, 0xfe, 0xc3, 0x95, 0x39, 0xf2, 0x2c, 0xaa, 0xe4, 0xd9, 0xcb, + 0xfe, 0xc9, 0xdf, 0xc0, 0x50, 0x64, 0x72, 0xfe, 0x7f, 0x7c, 0x89, 0x2a, + 0x72, 0xfe, 0x51, 0x9b, 0x6d, 0xf9, 0x39, 0x50, 0x9b, 0x6e, 0x42, 0x65, + 0x52, 0x3d, 0x0b, 0x39, 0xd7, 0x8c, 0x2f, 0x6b, 0x3a, 0x72, 0xf6, 0xd1, + 0x87, 0x2b, 0x46, 0xe3, 0xc3, 0x97, 0x24, 0xe7, 0x2a, 0x0d, 0xc7, 0x01, + 0x0d, 0xff, 0xdd, 0x48, 0x1f, 0x8e, 0x32, 0x46, 0x1c, 0xbe, 0x49, 0x91, + 0xb3, 0x97, 0xff, 0x31, 0xf9, 0x53, 0xc9, 0xa8, 0xff, 0x87, 0x39, 0x7f, + 0xfe, 0xfe, 0x71, 0x8c, 0xef, 0xd8, 0xf6, 0x77, 0xfd, 0x1c, 0xbe, 0xf6, + 0xd4, 0xdf, 0xc4, 0xc2, 0xc2, 0x87, 0x84, 0x6a, 0x26, 0x5f, 0xb6, 0xcc, + 0xf6, 0xce, 0x5f, 0xfc, 0x8a, 0xe7, 0x93, 0xb9, 0xe8, 0xd1, 0xcb, 0xf3, + 0xc8, 0x52, 0x0e, 0x5f, 0xd0, 0xe3, 0xec, 0x13, 0x95, 0x25, 0x48, 0x39, + 0x19, 0x72, 0x2c, 0xe8, 0xa1, 0x88, 0x62, 0x4b, 0x7e, 0xea, 0x34, 0x45, + 0x4e, 0x5f, 0x60, 0x13, 0x89, 0xca, 0x59, 0xe6, 0x89, 0x55, 0xff, 0xc0, + 0x8d, 0xb2, 0x13, 0x5a, 0x46, 0xce, 0x5e, 0x77, 0x91, 0xca, 0x43, 0xdf, + 0x02, 0x25, 0xfc, 0x3b, 0xc6, 0x43, 0x59, 0xcb, 0xe6, 0xbe, 0xe4, 0xe7, + 0x2f, 0xf4, 0x07, 0x3c, 0x9d, 0xfc, 0xe5, 0x41, 0xec, 0x84, 0x9a, 0xa1, + 0x15, 0x2c, 0x84, 0x45, 0xff, 0xbc, 0xa0, 0x21, 0x48, 0x04, 0x00, 0xe5, + 0xff, 0xff, 0x98, 0xe2, 0x09, 0x26, 0xff, 0x67, 0x52, 0x3d, 0xdf, 0xdd, + 0x87, 0x2f, 0xff, 0x87, 0xff, 0x49, 0x01, 0xd7, 0x4f, 0x3b, 0x0e, 0x5d, + 0xf1, 0xac, 0xe5, 0xff, 0xf9, 0xd3, 0xc8, 0x1c, 0x0e, 0x79, 0x18, 0x9a, + 0x39, 0x7f, 0xfa, 0x16, 0x1c, 0x53, 0xc9, 0xa8, 0xff, 0x87, 0x39, 0x7b, + 0x4f, 0xbc, 0x4c, 0x37, 0x49, 0xfd, 0x1c, 0x15, 0x2b, 0x79, 0xd3, 0xc7, + 0xfe, 0x37, 0xaa, 0xe5, 0x51, 0xba, 0x4a, 0x07, 0xba, 0x50, 0x72, 0xff, + 0xf4, 0xe1, 0xec, 0x77, 0x39, 0x06, 0x7b, 0x67, 0x29, 0xcf, 0x8b, 0xf1, + 0x6a, 0x0a, 0xe2, 0xc6, 0x42, 0x01, 0x21, 0x94, 0xf2, 0x97, 0x86, 0x11, + 0xd7, 0xf6, 0xa2, 0x74, 0x1f, 0x1c, 0xbc, 0x15, 0x18, 0x72, 0xfc, 0x30, + 0x1c, 0x98, 0xe5, 0xf6, 0xff, 0xd2, 0xa7, 0x2f, 0xd1, 0xdf, 0x44, 0x8e, + 0x5f, 0x07, 0xff, 0x6e, 0x0f, 0xcf, 0x92, 0x70, 0x12, 0xdf, 0x81, 0x8c, + 0x8e, 0x9c, 0xbf, 0xff, 0xfd, 0x93, 0xee, 0x15, 0x7d, 0xfa, 0x58, 0xaa, + 0xb9, 0xcf, 0xb5, 0x19, 0xc9, 0xcb, 0xf4, 0x7c, 0xd0, 0xc8, 0xe5, 0x6d, + 0x14, 0xbf, 0xbe, 0x5e, 0xe1, 0xfb, 0x87, 0x28, 0x2a, 0x85, 0xf0, 0xb5, + 0x21, 0x22, 0x29, 0x1e, 0x86, 0x67, 0xe4, 0x97, 0xb4, 0xa6, 0xce, 0x5f, + 0xf7, 0x63, 0x9f, 0x47, 0x5d, 0xac, 0xe5, 0x1c, 0xaf, 0x87, 0x8f, 0xc2, + 0xe7, 0x97, 0xef, 0x7b, 0xd8, 0xd9, 0xca, 0x83, 0xd4, 0x42, 0xbb, 0xff, + 0x38, 0xaf, 0x34, 0xb7, 0x75, 0x9a, 0x21, 0x15, 0xd2, 0x9c, 0xe5, 0x42, + 0x67, 0x40, 0x85, 0xcf, 0xe4, 0x1c, 0x52, 0x6f, 0xd9, 0x3e, 0xc0, 0xe7, + 0x2f, 0xff, 0xff, 0x77, 0x3f, 0xd2, 0xbd, 0x4e, 0x63, 0xdf, 0xf4, 0x73, + 0x9f, 0x7e, 0xfb, 0x39, 0x7f, 0xf6, 0x72, 0xa7, 0x90, 0x7f, 0x96, 0x6c, + 0xe5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfb, 0x06, 0x71, 0x70, 0xc0, 0xcf, + 0x1a, 0x0e, 0x0e, 0x7b, 0x68, 0xbc, 0x15, 0x27, 0xcd, 0x46, 0xc5, 0xd5, + 0xde, 0x20, 0x01, 0xf8, 0x05, 0xc3, 0x03, 0x3c, 0x68, 0xe5, 0x42, 0x69, + 0xd8, 0x8d, 0x7f, 0xf7, 0x9c, 0x67, 0xe6, 0x43, 0x19, 0xb3, 0x97, 0xff, + 0xe8, 0x04, 0xd2, 0x89, 0xc5, 0xd5, 0xd8, 0xc4, 0x8e, 0x5f, 0xf9, 0x4c, + 0xeb, 0xb3, 0xeb, 0x6d, 0xb6, 0x72, 0xff, 0xfd, 0x8b, 0xec, 0x08, 0x45, + 0x27, 0xc1, 0x45, 0x4e, 0x59, 0xe7, 0x44, 0xc4, 0x91, 0x6a, 0x49, 0x8b, + 0xbc, 0x3b, 0xaf, 0xff, 0xe9, 0x86, 0x01, 0xb5, 0xf5, 0x35, 0x30, 0xc0, + 0x36, 0x72, 0xff, 0xfe, 0xf6, 0xe1, 0x59, 0x27, 0x5c, 0x7d, 0x2c, 0xd6, + 0x1c, 0xbf, 0xf2, 0x6f, 0x03, 0xf1, 0xc0, 0xd3, 0x0e, 0x5f, 0xfb, 0xa9, + 0xc7, 0xaf, 0x2d, 0x42, 0xa7, 0x2b, 0x11, 0xb8, 0xb5, 0xaf, 0x20, 0xdf, + 0xdf, 0xf9, 0x3f, 0x15, 0x4e, 0x5f, 0xd8, 0xde, 0x0f, 0xe0, 0x39, 0x7e, + 0x96, 0x7a, 0x00, 0x72, 0xe8, 0x64, 0xe7, 0xab, 0xc9, 0x75, 0xff, 0xff, + 0xc0, 0x63, 0xcb, 0xae, 0x9e, 0x40, 0xe0, 0x73, 0xc8, 0xc4, 0xd1, 0xca, + 0xda, 0x27, 0xbf, 0x2f, 0xbf, 0xff, 0x0e, 0x6f, 0x3a, 0xfc, 0x0b, 0xea, + 0x32, 0x16, 0x72, 0xfd, 0x3b, 0x20, 0x30, 0x72, 0xa4, 0xbd, 0x38, 0x18, + 0xf2, 0xf9, 0x22, 0x9a, 0x35, 0xbd, 0x14, 0x76, 0x33, 0x8d, 0x97, 0xfa, + 0x32, 0x3e, 0x24, 0x8a, 0x2b, 0x5f, 0xfa, 0x15, 0x56, 0x07, 0x3d, 0xd4, + 0x39, 0x7f, 0xa3, 0x7b, 0x89, 0xf1, 0xb3, 0x97, 0xfb, 0xb8, 0xcc, 0xef, + 0xe2, 0x72, 0x82, 0x7c, 0xfe, 0x34, 0xbe, 0xcd, 0x2a, 0x87, 0x2a, 0x19, + 0x0b, 0x19, 0x3d, 0x88, 0x90, 0xab, 0x78, 0x52, 0xfe, 0x45, 0x79, 0xb6, + 0xdb, 0x29, 0x7f, 0xd8, 0x07, 0xd6, 0x71, 0xc0, 0x94, 0xfa, 0x68, 0x2e, + 0x6d, 0xb2, 0x97, 0x9b, 0x6d, 0xb2, 0x97, 0xf3, 0xce, 0x1e, 0xc6, 0xca, + 0x7d, 0x34, 0x14, 0x28, 0xc4, 0x6d, 0x2d, 0xa1, 0xcd, 0xf9, 0x68, 0x15, + 0x18, 0x53, 0xe9, 0xb2, 0xbc, 0xdb, 0x6d, 0x94, 0xbd, 0xb8, 0xd1, 0x4f, + 0xa6, 0x82, 0xf9, 0xc7, 0x9f, 0x1c, 0xb0, 0x11, 0x15, 0x7e, 0x5b, 0x6c, + 0xba, 0xfe, 0x08, 0xc4, 0x9d, 0x67, 0x2f, 0xdb, 0xfe, 0x76, 0x82, 0x72, + 0xfc, 0x14, 0xe3, 0x01, 0x39, 0x7d, 0x83, 0x8d, 0x67, 0x2b, 0x47, 0x98, + 0xc2, 0x9a, 0x44, 0x4d, 0x28, 0xf1, 0x7f, 0xf7, 0x5e, 0x42, 0xea, 0xcc, + 0x29, 0x31, 0xcb, 0xff, 0x6a, 0x78, 0xe7, 0x68, 0x38, 0x03, 0x97, 0xfd, + 0x8b, 0x89, 0xc3, 0xd8, 0xd9, 0xca, 0xc3, 0xf8, 0x68, 0x7f, 0x7f, 0x77, + 0x38, 0xe7, 0xb6, 0x72, 0x96, 0x98, 0x78, 0x21, 0x7b, 0xe2, 0x3a, 0xd2, + 0xa2, 0xee, 0xc3, 0x18, 0x63, 0x32, 0xba, 0x7f, 0x1c, 0xa8, 0x55, 0x71, + 0x92, 0x99, 0x04, 0xf2, 0xe6, 0xa0, 0xd4, 0x9c, 0xbf, 0x6e, 0x6d, 0xc7, + 0x8e, 0x57, 0x27, 0x97, 0xe2, 0x2b, 0xf2, 0xe3, 0xb0, 0xc3, 0x97, 0x3f, + 0x8e, 0x5f, 0xb1, 0xad, 0xc4, 0x18, 0x6f, 0x44, 0x9e, 0xff, 0xa0, 0x64, + 0x21, 0xec, 0x4e, 0x72, 0xfe, 0x0e, 0x69, 0xa3, 0x02, 0x72, 0xf7, 0x52, + 0x62, 0x95, 0xa3, 0xcd, 0xd9, 0x85, 0xff, 0x3f, 0x3e, 0xc9, 0xbf, 0xd2, + 0xa7, 0x2c, 0xb4, 0x3d, 0xff, 0xc8, 0xaf, 0xf0, 0xe7, 0x32, 0xda, 0x2a, + 0x72, 0xf9, 0xdf, 0x4a, 0x9c, 0xaf, 0x87, 0xad, 0x39, 0xa5, 0xff, 0x66, + 0x2c, 0x11, 0x9c, 0xc8, 0xe5, 0xf4, 0x3b, 0x38, 0x94, 0xbf, 0xfb, 0xa8, + 0xe0, 0x04, 0x02, 0x3b, 0xb3, 0x97, 0xf7, 0x71, 0x8c, 0x79, 0x1c, 0xbc, + 0xdb, 0x6d, 0x94, 0xbf, 0xc3, 0xee, 0xa4, 0x0c, 0xe5, 0x3e, 0x9a, 0x0b, + 0xd0, 0x0c, 0x92, 0x24, 0x71, 0x36, 0xbc, 0x98, 0x32, 0x90, 0xd4, 0xb6, + 0x2d, 0x35, 0x36, 0x46, 0x53, 0x7f, 0x02, 0x01, 0x1d, 0xd9, 0xcb, 0xfd, + 0x0a, 0x6b, 0x49, 0xed, 0x9c, 0xa8, 0x5c, 0x3f, 0x93, 0x02, 0xa7, 0xbc, + 0xc3, 0x91, 0x1f, 0xa6, 0x25, 0xec, 0x71, 0x60, 0x2f, 0x12, 0xdb, 0xf0, + 0x31, 0x3a, 0xa9, 0xcb, 0xff, 0xec, 0x5c, 0x0b, 0xfb, 0x61, 0xfd, 0xf5, + 0x23, 0x95, 0xc9, 0xfb, 0xb0, 0xa2, 0xfe, 0x81, 0x5b, 0x54, 0xd4, 0x5a, + 0xb3, 0x97, 0xe8, 0x66, 0xa3, 0x89, 0xcb, 0xff, 0xda, 0x85, 0xf8, 0x61, + 0xbc, 0xf6, 0xf6, 0x72, 0xff, 0xff, 0xe1, 0x76, 0x46, 0x96, 0x1e, 0xc6, + 0xff, 0x74, 0x96, 0xfa, 0xf2, 0x39, 0x7b, 0xff, 0x6c, 0xe5, 0xe5, 0xc6, + 0xce, 0x5f, 0xfc, 0xa4, 0xb3, 0xaf, 0xd4, 0xd6, 0xa0, 0xe5, 0x61, 0xf0, + 0x00, 0x72, 0xfd, 0x1e, 0xdf, 0x1c, 0x39, 0x7e, 0xff, 0x4a, 0xf5, 0x0e, + 0x54, 0x2a, 0x36, 0x09, 0x1a, 0xcf, 0x74, 0x52, 0xe9, 0x40, 0x71, 0x17, + 0xef, 0x10, 0xb4, 0x29, 0xbf, 0xc2, 0xed, 0xe0, 0xba, 0xa7, 0x2f, 0xfe, + 0xcf, 0x6d, 0x4d, 0xb0, 0x63, 0x50, 0x72, 0xf7, 0x1c, 0x10, 0x9f, 0xb3, + 0x0c, 0xaf, 0xfe, 0x6e, 0x34, 0x2f, 0x3c, 0x6a, 0x24, 0x72, 0x90, 0xfe, + 0x3a, 0x69, 0x7f, 0xff, 0xc1, 0xea, 0x37, 0x9c, 0x08, 0xc7, 0xf6, 0xff, + 0x96, 0x73, 0xe3, 0x95, 0x88, 0x8d, 0x72, 0x1b, 0xfe, 0x99, 0x7d, 0x46, + 0x46, 0x95, 0x39, 0x7e, 0x9f, 0xe7, 0xf1, 0x31, 0xcb, 0x48, 0xe5, 0xe5, + 0x06, 0x63, 0x95, 0x23, 0x5e, 0x01, 0x1a, 0xc4, 0x5c, 0x39, 0xde, 0xd7, + 0x2a, 0x1f, 0x23, 0x92, 0x79, 0x5c, 0xb2, 0x97, 0x1c, 0x19, 0x6a, 0x19, + 0x4f, 0x9e, 0x56, 0x1c, 0x2b, 0x86, 0x22, 0x4a, 0xf2, 0x9a, 0x59, 0x0e, + 0xa5, 0xa0, 0x32, 0x58, 0x67, 0x67, 0x40, 0x5e, 0x53, 0xb0, 0x23, 0x9b, + 0x1a, 0x44, 0xee, 0xe7, 0x35, 0xbd, 0x39, 0x81, 0xfc, 0xb3, 0x96, 0xe3, + 0xfa, 0x52, 0x1b, 0x37, 0xb8, 0xc0, 0x9c, 0xbf, 0xfe, 0xc1, 0xfb, 0xe5, + 0x53, 0x9d, 0xf7, 0x00, 0xe7, 0x2a, 0x47, 0xde, 0x11, 0xdb, 0xce, 0xed, + 0x9c, 0xb8, 0x10, 0x72, 0xfc, 0xbc, 0xf7, 0x50, 0xe5, 0x9c, 0x27, 0xb2, + 0x83, 0x82, 0x2d, 0x7f, 0xff, 0xd9, 0xd7, 0x53, 0x78, 0xab, 0x88, 0x20, + 0x62, 0x6e, 0xc1, 0xcb, 0x41, 0xcb, 0xff, 0xf4, 0x6b, 0xb0, 0xce, 0x0f, + 0xe0, 0x62, 0x6e, 0xc1, 0xcb, 0xf2, 0x6a, 0x68, 0xee, 0x91, 0x9a, 0x06, + 0x51, 0x10, 0xae, 0x53, 0xc6, 0x63, 0xda, 0x90, 0xff, 0xb7, 0x0b, 0x9c, + 0xbf, 0xf7, 0xba, 0xf2, 0xf4, 0xc3, 0x0c, 0x39, 0x7f, 0xe7, 0x10, 0x7c, + 0x0f, 0xef, 0xa9, 0x1c, 0xbe, 0x41, 0x9e, 0x0e, 0x5e, 0xf6, 0xa0, 0xe5, + 0xff, 0x0c, 0x31, 0x07, 0x19, 0x07, 0x2e, 0x40, 0xe1, 0xe8, 0xcc, 0x39, + 0x4d, 0x68, 0xe0, 0xd2, 0x08, 0xb9, 0x5f, 0xfc, 0x3e, 0xdf, 0x5e, 0x5f, + 0x33, 0x9f, 0x1c, 0xa6, 0xa2, 0x9d, 0x84, 0x0c, 0x64, 0x63, 0xff, 0x99, + 0x5f, 0xf3, 0xb5, 0xcd, 0xb8, 0xeb, 0xb5, 0x9c, 0xbd, 0x03, 0x39, 0xcb, + 0xe4, 0xea, 0x30, 0xe5, 0xba, 0x86, 0xf6, 0x61, 0xcb, 0xfa, 0x17, 0x1b, + 0xf2, 0x1c, 0xbf, 0xe8, 0xf7, 0x5c, 0x0f, 0xce, 0xce, 0x50, 0x4f, 0x94, + 0x4b, 0x2f, 0xff, 0xf0, 0xfe, 0xeb, 0xdf, 0xee, 0x92, 0x81, 0x5e, 0x73, + 0xe3, 0x97, 0xfe, 0xd0, 0x3e, 0x75, 0x17, 0xfe, 0x80, 0x72, 0xf4, 0xdf, + 0xe8, 0xe5, 0xff, 0x9d, 0x35, 0x9c, 0xfd, 0x6d, 0xb6, 0xce, 0x54, 0x22, + 0x99, 0xd0, 0xf6, 0x3f, 0x7f, 0xfc, 0x31, 0x2f, 0x8a, 0x79, 0x07, 0xf9, + 0x66, 0xce, 0x56, 0x2a, 0x34, 0x5c, 0x23, 0x18, 0x43, 0xd8, 0xc1, 0xc0, + 0x5d, 0x78, 0x0e, 0xc3, 0x97, 0x60, 0x0e, 0x54, 0x1b, 0x2c, 0x1c, 0xbc, + 0xf8, 0xc3, 0x97, 0x0c, 0x84, 0xdd, 0x70, 0x0f, 0xdf, 0xe6, 0xf6, 0x38, + 0x11, 0x73, 0x97, 0x2d, 0x0e, 0x5f, 0x86, 0x27, 0x8e, 0x4e, 0x5b, 0x6b, + 0x37, 0xc8, 0x2d, 0x50, 0x8c, 0x44, 0x2e, 0x77, 0x0b, 0xf6, 0xb6, 0x31, + 0x39, 0xcb, 0xff, 0xe6, 0xf1, 0x7b, 0xcf, 0x4d, 0x8a, 0x8e, 0x00, 0xe5, + 0x61, 0xfc, 0xa1, 0x45, 0xfc, 0xfe, 0xeb, 0x88, 0x0e, 0x5f, 0xf9, 0xfd, + 0x93, 0x3c, 0x0c, 0x4c, 0x72, 0xff, 0xdd, 0x4c, 0x53, 0x26, 0x6e, 0x39, + 0x39, 0x64, 0xd2, 0x2a, 0xba, 0x59, 0xb3, 0xdb, 0x96, 0xb3, 0x46, 0x08, + 0xa9, 0x26, 0x46, 0xb8, 0x65, 0x00, 0xd6, 0xff, 0x35, 0x3b, 0x08, 0xe7, + 0x78, 0x43, 0x97, 0x60, 0x9c, 0xbf, 0xfd, 0xe8, 0x15, 0xe7, 0xba, 0x9a, + 0x02, 0xce, 0x5f, 0x82, 0x9b, 0xea, 0x1c, 0xbf, 0x90, 0x73, 0xdd, 0x43, + 0x96, 0x8c, 0x3d, 0x2d, 0x93, 0xd0, 0x51, 0xad, 0x82, 0xbf, 0xc2, 0x6e, + 0xff, 0xe0, 0x6f, 0xa9, 0xac, 0xf6, 0xdf, 0x93, 0x97, 0xfa, 0x19, 0xbd, + 0xb8, 0xce, 0x72, 0xff, 0x81, 0xb9, 0x27, 0x5d, 0x27, 0x39, 0x7d, 0xbc, + 0x1f, 0x1c, 0xbd, 0xc1, 0x1a, 0x39, 0x48, 0x7f, 0x2e, 0x73, 0xf9, 0x0d, 0xef, 0x3b, 0x59, 0xcb, 0xfd, 0xee, 0xa7, 0xd0, 0x3a, 0x1c, 0xbb, 0xf1, - 0x39, 0x72, 0x98, 0x72, 0x82, 0x9e, 0xae, 0xcd, 0x7a, 0x8a, 0x30, 0xac, - 0xf1, 0x77, 0xe3, 0xed, 0x0d, 0x14, 0x17, 0xbf, 0x2a, 0x04, 0x9b, 0x47, - 0x2f, 0xba, 0x8f, 0x23, 0x97, 0x82, 0xf2, 0x39, 0x50, 0x6f, 0x70, 0x86, - 0xdf, 0xc2, 0x21, 0x80, 0xcf, 0x77, 0xb4, 0x72, 0xfc, 0xea, 0xb7, 0x1b, - 0x39, 0x4e, 0x78, 0x02, 0x2f, 0x7f, 0xf2, 0x2c, 0x71, 0x91, 0x30, 0x62, - 0x73, 0x97, 0xfc, 0xbc, 0xf4, 0x71, 0x41, 0x01, 0xcb, 0xff, 0xfb, 0xf8, - 0xf6, 0xb0, 0x7e, 0x6e, 0x10, 0x22, 0xf2, 0x39, 0x7e, 0x5f, 0x79, 0x76, - 0xb3, 0x97, 0xff, 0x20, 0x47, 0xff, 0x6a, 0x06, 0x34, 0x72, 0x96, 0x9a, - 0x3a, 0x22, 0x09, 0xcf, 0xeb, 0x7c, 0x4b, 0x2f, 0xfc, 0xfb, 0xce, 0x38, - 0x1d, 0x8b, 0x67, 0x2f, 0xff, 0xe4, 0xfc, 0x65, 0x83, 0xe4, 0x69, 0x9e, - 0x17, 0x91, 0xca, 0x02, 0x26, 0xbc, 0x81, 0x7f, 0xff, 0x0e, 0x6b, 0xff, - 0x99, 0xd7, 0x1c, 0x9a, 0x51, 0xc9, 0xcb, 0xf6, 0xd6, 0xee, 0xb3, 0x44, - 0x0c, 0xbf, 0x9e, 0x70, 0x38, 0x84, 0x95, 0x83, 0xd7, 0xb3, 0x5f, 0xe1, - 0xf7, 0xb4, 0x34, 0xbd, 0xd7, 0x97, 0xc4, 0xc0, 0x46, 0x19, 0x97, 0xfd, - 0xd4, 0xc1, 0xc5, 0x87, 0x0e, 0x53, 0x13, 0x95, 0xf4, 0x64, 0x9c, 0x4e, - 0xef, 0x7b, 0xf8, 0x39, 0x7c, 0x0d, 0xeb, 0x47, 0x2f, 0xf0, 0x3c, 0x93, - 0xb2, 0x16, 0x72, 0xb9, 0x3f, 0x47, 0x1d, 0x12, 0x3b, 0xf0, 0x5a, 0xb7, - 0x0b, 0x56, 0x72, 0xa1, 0x5c, 0x46, 0x4a, 0x7b, 0x48, 0x56, 0xb9, 0x75, - 0xc9, 0x23, 0x97, 0xf7, 0x3e, 0x0e, 0x62, 0xa7, 0x28, 0x27, 0x8b, 0x82, - 0xd7, 0xf6, 0x7a, 0x05, 0x00, 0x72, 0xff, 0x83, 0xb1, 0x76, 0xd4, 0xe5, - 0xb3, 0x97, 0x9f, 0x73, 0x9a, 0x30, 0x55, 0xff, 0x9f, 0x78, 0x20, 0xd7, - 0xb5, 0xc9, 0xcb, 0xff, 0xff, 0xfb, 0x3d, 0xd7, 0x15, 0x7e, 0x6b, 0x6e, - 0xfe, 0xe3, 0x81, 0xf9, 0x8c, 0x71, 0xe6, 0x47, 0x88, 0x2d, 0x7f, 0xe7, - 0x75, 0x56, 0xe1, 0xf8, 0xab, 0x67, 0x88, 0x2d, 0x7f, 0xf7, 0x53, 0xa9, - 0x03, 0xef, 0x8a, 0xb6, 0x78, 0x82, 0xd7, 0xfa, 0x10, 0x7d, 0xf1, 0x56, - 0xcf, 0x10, 0x5a, 0xfe, 0x66, 0x07, 0xe2, 0xad, 0x9e, 0x20, 0xb5, 0xff, - 0xff, 0x38, 0x8a, 0x33, 0xe6, 0x97, 0xd4, 0xda, 0x2b, 0x3e, 0x36, 0x78, - 0x82, 0xd7, 0x73, 0xf0, 0x29, 0xce, 0x2d, 0x43, 0x6a, 0x8e, 0x86, 0x27, - 0xf5, 0x0a, 0xb3, 0xba, 0x7e, 0x32, 0x8d, 0xef, 0xf2, 0x42, 0xba, 0xf6, - 0xb9, 0x39, 0x7c, 0xfb, 0x03, 0x9c, 0xbf, 0xfb, 0xa9, 0xd4, 0x81, 0xf7, - 0xc5, 0x5b, 0x3c, 0x41, 0x6b, 0xfe, 0x9b, 0x4b, 0x49, 0xfe, 0x2a, 0xd9, - 0xe2, 0x0b, 0x5f, 0xbd, 0xa8, 0x67, 0xc5, 0xa2, 0x85, 0x45, 0x4b, 0xff, - 0xdf, 0x17, 0xd4, 0x5c, 0x7b, 0x5f, 0x15, 0x6c, 0xf1, 0x05, 0xaf, 0xff, - 0xfe, 0x11, 0x46, 0x7c, 0xff, 0x3e, 0x69, 0x7d, 0x4d, 0xa2, 0xb3, 0xe3, - 0x67, 0x88, 0x2d, 0x58, 0x99, 0x37, 0x28, 0x6e, 0xbd, 0x7f, 0xdd, 0x4d, - 0xa2, 0xb3, 0xe3, 0x67, 0x88, 0x2d, 0x7f, 0xfc, 0xef, 0xcc, 0xb5, 0xd4, - 0x08, 0x63, 0x70, 0x52, 0xff, 0xd9, 0x29, 0x7f, 0xad, 0x8c, 0xed, 0x0f, - 0x10, 0x5a, 0x96, 0x8e, 0x7d, 0xa4, 0x69, 0x3e, 0xff, 0xcb, 0x4d, 0xf9, - 0xc1, 0xaf, 0x8d, 0x9e, 0x20, 0xb5, 0xfd, 0xd4, 0xef, 0x50, 0x06, 0x80, - 0x2d, 0x7e, 0xc0, 0x7c, 0x55, 0xb3, 0xc4, 0x16, 0xbb, 0x3c, 0xb3, 0xf3, - 0xe9, 0xd5, 0x72, 0x8e, 0xfd, 0x43, 0x0a, 0xfe, 0x66, 0x07, 0xe2, 0xad, - 0x9e, 0x20, 0xb5, 0xff, 0x97, 0xd4, 0xda, 0x2b, 0x3e, 0x36, 0x78, 0x82, - 0xd7, 0x67, 0xc7, 0x44, 0x6e, 0x8f, 0xef, 0xf7, 0xe8, 0xc7, 0x1e, 0x64, - 0x78, 0x82, 0xd7, 0xfe, 0xc4, 0xe3, 0x83, 0x81, 0x79, 0x1e, 0x20, 0xb3, - 0x0f, 0x06, 0x82, 0xbc, 0x17, 0xb3, 0x70, 0x1a, 0x8c, 0x7d, 0x1a, 0x8c, - 0x5f, 0xd1, 0x8f, 0xff, 0x0b, 0x66, 0xdc, 0x2e, 0x04, 0x1a, 0x20, 0xb7, - 0xd4, 0x46, 0x5c, 0xeb, 0x39, 0x6d, 0x2d, 0x93, 0xb8, 0x0a, 0x4c, 0x7f, - 0x8d, 0xee, 0x97, 0x01, 0xcb, 0xd1, 0x2e, 0x03, 0x95, 0x06, 0xe4, 0x46, - 0xaa, 0x76, 0x58, 0x00, 0x48, 0x79, 0x2b, 0x05, 0x28, 0x64, 0x5f, 0x2f, - 0xfe, 0xc9, 0x0e, 0x7b, 0xa9, 0x9c, 0xf8, 0xe5, 0xfe, 0x8e, 0xa3, 0x7c, - 0xcb, 0x47, 0x2f, 0xd1, 0xed, 0x75, 0x0e, 0x5f, 0xf7, 0x23, 0x88, 0xcc, - 0x10, 0x1c, 0xbf, 0xf6, 0xa6, 0x97, 0xe1, 0x9a, 0x5f, 0x84, 0xe5, 0x4e, - 0x8d, 0x89, 0x1a, 0xe1, 0x3f, 0x8d, 0xef, 0xfe, 0x8e, 0x64, 0xa3, 0x35, - 0xe8, 0xe5, 0xb3, 0x97, 0xe9, 0x70, 0x70, 0x7f, 0x39, 0xcb, 0x75, 0x0f, - 0xe9, 0xd2, 0x6f, 0xdb, 0x8e, 0x65, 0xa3, 0x95, 0x23, 0xcf, 0xd9, 0x35, - 0xe6, 0x3f, 0x8e, 0x5f, 0xfb, 0xfd, 0x34, 0xcd, 0x81, 0x89, 0xa3, 0x97, - 0xff, 0x71, 0xe3, 0x1a, 0x7e, 0xf3, 0x2c, 0xf1, 0xca, 0x02, 0x22, 0xd4, - 0x42, 0xbf, 0xc0, 0xff, 0xc3, 0x1e, 0xd1, 0xca, 0x92, 0x3f, 0xc1, 0x0a, - 0x7d, 0x12, 0x54, 0x2a, 0x5c, 0xc8, 0xc1, 0x9e, 0x32, 0x1b, 0xf9, 0xe5, - 0x1c, 0x5f, 0xa7, 0x2f, 0xfe, 0xce, 0x7d, 0xa4, 0x18, 0x03, 0xb0, 0xe5, - 0xff, 0xb8, 0x7c, 0x11, 0xc5, 0x20, 0x40, 0x72, 0xa7, 0x44, 0x27, 0xe8, - 0x77, 0xdc, 0xea, 0x39, 0x39, 0x7f, 0xe9, 0x67, 0x32, 0xdc, 0x79, 0xfc, - 0x72, 0xf3, 0x22, 0x47, 0x2f, 0xd8, 0x1e, 0xfe, 0xd9, 0xca, 0xf8, 0x8a, - 0x99, 0x89, 0x1c, 0xfc, 0x47, 0x2f, 0x05, 0xfc, 0x72, 0xff, 0xda, 0x81, - 0x89, 0x7b, 0xb8, 0x27, 0x2b, 0x68, 0x96, 0x73, 0xed, 0x0e, 0x5e, 0x46, - 0x98, 0x72, 0xf3, 0xec, 0x07, 0x2d, 0xcc, 0x1b, 0x9f, 0x0e, 0xdf, 0x37, - 0x9d, 0x73, 0x97, 0xca, 0xed, 0x1b, 0x39, 0x7e, 0x9d, 0xfb, 0x0d, 0x67, - 0x29, 0xa8, 0x3c, 0xfc, 0x24, 0xa8, 0x56, 0x79, 0x90, 0xb2, 0x48, 0xd9, - 0x1d, 0xa0, 0x04, 0xe2, 0xe3, 0x7f, 0xf0, 0xc4, 0xec, 0xea, 0x6f, 0x6f, - 0x23, 0x94, 0x72, 0x84, 0xf3, 0xda, 0x22, 0x5f, 0xe9, 0xe7, 0x81, 0xe7, - 0x3c, 0x72, 0xb0, 0xf6, 0x10, 0x8e, 0xff, 0xed, 0x8f, 0xfc, 0xf8, 0x72, - 0x77, 0x13, 0x97, 0x9f, 0x73, 0x9c, 0xb8, 0x10, 0x72, 0xf9, 0x21, 0x98, - 0x72, 0x8e, 0x5f, 0xce, 0xaf, 0xa3, 0x60, 0x39, 0x41, 0x37, 0x22, 0x17, - 0x7f, 0xff, 0xa1, 0x02, 0x31, 0xfa, 0xfd, 0x8b, 0x0c, 0x2d, 0x46, 0x1c, - 0xb8, 0x10, 0x72, 0xe8, 0x54, 0xe5, 0xff, 0x67, 0xb5, 0x0c, 0x53, 0x26, - 0x39, 0x7f, 0xb5, 0x9d, 0x4d, 0x7f, 0x39, 0xcb, 0x9b, 0x6c, 0xa5, 0xff, - 0x0e, 0x71, 0x79, 0x69, 0x02, 0x72, 0x96, 0x9f, 0xda, 0x0e, 0xec, 0x59, - 0x8b, 0x3d, 0x20, 0x03, 0x0f, 0x0e, 0x2c, 0x22, 0xfa, 0x3a, 0x6c, 0xd5, - 0x41, 0x9b, 0xcd, 0xb6, 0xd9, 0x4b, 0x30, 0xa7, 0xd3, 0x41, 0x7d, 0x33, - 0xbe, 0xca, 0x7d, 0x47, 0x0a, 0x90, 0xbe, 0xa9, 0xd5, 0xb5, 0x3c, 0xb2, - 0x1b, 0xfb, 0xd1, 0x9d, 0xc9, 0xce, 0x5d, 0x8c, 0x39, 0x5c, 0x9e, 0x1e, - 0x8b, 0x6a, 0x1d, 0x44, 0x84, 0xa3, 0xa9, 0xc9, 0x55, 0xaa, 0xc6, 0x89, - 0xcc, 0x79, 0x29, 0x2b, 0x87, 0x71, 0x80, 0x31, 0xa7, 0xb3, 0x9d, 0xef, - 0x4b, 0x8c, 0x02, 0xc0, 0xcb, 0x77, 0xd4, 0xb7, 0x7f, 0x46, 0x0d, 0xfc, - 0xb8, 0xae, 0x2d, 0xf7, 0xf6, 0x00, 0x09, 0xb9, 0x1c, 0xb9, 0x78, 0x72, - 0x82, 0x78, 0x6e, 0x5b, 0x76, 0x36, 0x72, 0xe8, 0xf1, 0xca, 0x9c, 0xd6, - 0xac, 0x5e, 0xcc, 0x39, 0x58, 0x6c, 0xfc, 0x45, 0x7f, 0xa4, 0x83, 0x8c, - 0xff, 0xa7, 0x2f, 0xfd, 0x9e, 0xd7, 0x51, 0x8f, 0x9b, 0x39, 0x50, 0x7e, - 0x02, 0x67, 0x7e, 0xcf, 0x98, 0x0f, 0x1c, 0xbe, 0xf9, 0xe8, 0xe2, 0x72, - 0xfb, 0x19, 0x9e, 0x39, 0x7b, 0xce, 0xa9, 0xcb, 0xe7, 0x63, 0xcc, 0x72, - 0xff, 0xff, 0xcf, 0x37, 0xf2, 0xfd, 0x7f, 0x3a, 0x9e, 0xf4, 0x73, 0x13, - 0xc6, 0x8e, 0x5f, 0x85, 0xda, 0xe7, 0x98, 0xe5, 0xf4, 0xda, 0x8f, 0x1c, - 0xa5, 0xa3, 0x0a, 0x67, 0x3f, 0xcb, 0x2f, 0xff, 0xf9, 0xac, 0x5d, 0xf8, - 0xc4, 0xbb, 0x1b, 0x9e, 0x3d, 0xa7, 0x91, 0xcb, 0xc9, 0xcc, 0xc7, 0x2f, - 0xd9, 0x93, 0xff, 0xa3, 0x97, 0xdb, 0x14, 0x01, 0xcb, 0xe4, 0x5b, 0xec, - 0xe5, 0xd0, 0x03, 0x97, 0xdf, 0xcf, 0xff, 0xde, 0x9b, 0x75, 0x08, 0x69, - 0x11, 0x2f, 0xd5, 0x8b, 0x9a, 0xc0, 0x72, 0xfc, 0xf1, 0xce, 0x2c, 0xe5, - 0xff, 0x75, 0xf5, 0xd4, 0x9d, 0xc4, 0xe5, 0xf3, 0xce, 0xa4, 0x8e, 0x57, - 0x0c, 0xb9, 0xb7, 0x10, 0x81, 0x94, 0x24, 0x02, 0x41, 0x85, 0x3c, 0x93, - 0x21, 0x0b, 0x58, 0xee, 0xe1, 0xc8, 0xe6, 0x40, 0x6a, 0xd0, 0xf7, 0xa1, - 0x81, 0xf9, 0x13, 0x63, 0x4a, 0x13, 0xf0, 0x1c, 0x5f, 0xc3, 0xf8, 0x58, - 0xf2, 0x39, 0x79, 0x27, 0xfc, 0xe5, 0xfa, 0x00, 0x9c, 0xe1, 0xcb, 0x99, - 0xc4, 0xe5, 0x83, 0x07, 0x80, 0x24, 0xf7, 0xff, 0xa4, 0x31, 0xf1, 0x83, - 0x0a, 0xf9, 0x27, 0x39, 0x7e, 0x76, 0x67, 0x58, 0x72, 0xb9, 0x3f, 0x3f, - 0x26, 0x5e, 0xf6, 0xe0, 0xe5, 0xfe, 0xd7, 0xb8, 0xe0, 0xe0, 0x4e, 0x5f, - 0xd9, 0xac, 0x92, 0x6c, 0xe5, 0xee, 0xc7, 0x13, 0x97, 0xb5, 0x29, 0xce, - 0x56, 0x1b, 0xc5, 0x07, 0xaa, 0x15, 0x10, 0xc8, 0xbb, 0x17, 0x92, 0x13, - 0x2c, 0x23, 0x71, 0xc1, 0x34, 0xf3, 0x45, 0xe7, 0xf8, 0xa1, 0xcb, 0xd3, - 0x27, 0x4e, 0x5f, 0xd1, 0xb7, 0x99, 0x3a, 0x72, 0xfd, 0xa0, 0xc0, 0xce, - 0xe7, 0x95, 0xa1, 0xdb, 0xcc, 0x86, 0x1c, 0xae, 0x4f, 0x69, 0x87, 0xd7, - 0xff, 0xc3, 0x2f, 0x98, 0x14, 0xd7, 0x3e, 0xfd, 0xf4, 0x72, 0xfd, 0xdf, - 0xc6, 0x38, 0x9c, 0xbf, 0x85, 0xfd, 0x28, 0x54, 0xe5, 0x41, 0xeb, 0xa8, - 0x55, 0x7d, 0x99, 0xcc, 0x8e, 0x5e, 0xd2, 0x4c, 0x72, 0xca, 0x89, 0xbf, - 0xd1, 0x15, 0xff, 0x6d, 0x23, 0xd9, 0xc5, 0xc2, 0x72, 0xff, 0xe7, 0x9c, - 0x63, 0x94, 0x08, 0xc4, 0xe7, 0x2b, 0x68, 0xa4, 0xe9, 0x38, 0x9c, 0xdf, - 0xbe, 0x76, 0x37, 0x23, 0x95, 0xf1, 0x57, 0x74, 0x43, 0x0f, 0x08, 0xd7, - 0x0a, 0xa7, 0x8c, 0x15, 0xb2, 0xfb, 0xcc, 0xd4, 0x1c, 0xbf, 0xa7, 0x9a, - 0x5c, 0x36, 0xe7, 0x39, 0x7c, 0xcc, 0x7e, 0x9c, 0xb4, 0xe7, 0x2f, 0xde, - 0xea, 0x33, 0x67, 0x2a, 0x46, 0xeb, 0x62, 0x57, 0xba, 0x14, 0x39, 0x7e, - 0xee, 0x24, 0xb4, 0x72, 0xff, 0xfb, 0xb0, 0xa7, 0xdf, 0x0b, 0x83, 0x5a, - 0x80, 0x14, 0xbf, 0x67, 0x9f, 0xfe, 0x1c, 0xe5, 0xfb, 0x6b, 0x77, 0x59, - 0xe2, 0x04, 0x5e, 0xd4, 0x72, 0x72, 0xc0, 0xc3, 0xd1, 0xe4, 0xd2, 0xf7, - 0x92, 0x73, 0x97, 0xa7, 0x71, 0x39, 0x52, 0x4d, 0x60, 0x24, 0xfc, 0xa9, - 0x6d, 0xf9, 0x85, 0x1e, 0x1d, 0xbf, 0x85, 0x6e, 0xaf, 0x50, 0xe5, 0xdc, - 0x12, 0x39, 0x7d, 0xe9, 0xdc, 0x4e, 0x5e, 0x17, 0x54, 0xe5, 0xfe, 0x57, - 0x27, 0xff, 0xdc, 0x7c, 0x72, 0xff, 0x9e, 0x5b, 0x89, 0xdf, 0x6b, 0x39, - 0x79, 0x54, 0xf1, 0xcb, 0xda, 0x7f, 0x1c, 0xa5, 0x4d, 0xcf, 0x23, 0xb7, - 0x7c, 0xe9, 0xcb, 0xf9, 0x9e, 0x40, 0xff, 0x07, 0x2f, 0x33, 0xcb, 0x39, - 0x6f, 0x41, 0xe5, 0xe1, 0x75, 0xfd, 0x0c, 0xc5, 0x63, 0x47, 0x2a, 0x74, - 0xf7, 0x70, 0x69, 0x64, 0x5b, 0x1c, 0x61, 0xcf, 0x5c, 0x80, 0x46, 0x2c, - 0x9e, 0x26, 0xbb, 0x7f, 0x9c, 0xbf, 0xc2, 0xed, 0xeb, 0x50, 0x03, 0x97, - 0x9a, 0x3a, 0xa7, 0x2f, 0xfa, 0x19, 0x2c, 0x9f, 0x3f, 0xe1, 0xce, 0x5f, - 0x3f, 0xb8, 0x79, 0xce, 0x56, 0x22, 0x19, 0x07, 0xdc, 0xfe, 0xf3, 0x70, - 0xa1, 0xcb, 0xcd, 0xb6, 0xd9, 0xea, 0xfa, 0x5e, 0x71, 0x09, 0x6a, 0xfa, - 0xbe, 0x9a, 0xdb, 0xe9, 0x7f, 0x0a, 0x9c, 0xb0, 0x0e, 0x56, 0x1b, 0x57, - 0x24, 0xa8, 0x4f, 0x60, 0x23, 0x1b, 0x85, 0xcf, 0x4b, 0x40, 0x97, 0xe7, - 0x0b, 0xfd, 0xee, 0xe4, 0xba, 0x9c, 0x4e, 0x5f, 0x33, 0x7f, 0xce, 0x72, - 0xff, 0xf8, 0x51, 0x5f, 0xba, 0xf7, 0x7f, 0x79, 0x4a, 0x0e, 0x54, 0x1f, - 0xc6, 0x12, 0xd4, 0xe9, 0x94, 0xc9, 0x71, 0x58, 0x56, 0xdf, 0x60, 0x5e, - 0x47, 0x2f, 0xce, 0x22, 0x8c, 0x39, 0x72, 0x74, 0xe5, 0xe0, 0xbc, 0x8e, - 0x5f, 0xe4, 0xde, 0x23, 0x21, 0xac, 0xe5, 0x04, 0xf9, 0xb0, 0x5b, 0xa3, - 0x97, 0xe4, 0x63, 0x8e, 0x1c, 0xaf, 0x8c, 0x95, 0xc6, 0xa8, 0x72, 0x0d, - 0xe4, 0xb6, 0x12, 0x1c, 0x8d, 0xd1, 0x55, 0x94, 0x94, 0x14, 0xf2, 0xdf, - 0xc0, 0x70, 0x24, 0x3f, 0xc2, 0x2d, 0xa1, 0x75, 0xfd, 0x9d, 0xc5, 0xff, - 0x87, 0x2f, 0xc9, 0xe8, 0xf6, 0x8a, 0x5f, 0x2e, 0x3d, 0xa2, 0x97, 0x36, - 0xd9, 0x4a, 0x91, 0xf1, 0x61, 0x3b, 0x64, 0x57, 0x63, 0x65, 0x3e, 0x9a, - 0xfb, 0xe9, 0x85, 0xdb, 0x39, 0x7f, 0xfd, 0xe8, 0x5e, 0x60, 0xfb, 0xa9, - 0x03, 0x39, 0xca, 0x39, 0x58, 0x7b, 0x1a, 0x4d, 0xa9, 0x93, 0x83, 0x04, - 0x2f, 0x84, 0xa5, 0xb7, 0xbb, 0xff, 0xc3, 0x1c, 0x83, 0x06, 0x25, 0xbd, - 0xc1, 0xcb, 0xff, 0x7b, 0x58, 0xbe, 0xb8, 0xfb, 0x47, 0x2f, 0x20, 0x80, - 0xe7, 0xc3, 0x7d, 0x68, 0x62, 0x2c, 0xf8, 0xc2, 0x1a, 0xfb, 0xae, 0xfa, - 0x39, 0x7e, 0x97, 0x7f, 0x8d, 0x9c, 0xbf, 0xf9, 0xd9, 0xb8, 0xe2, 0x9c, - 0x47, 0xfd, 0x1c, 0xae, 0x4f, 0xc7, 0xa5, 0x37, 0xec, 0xfd, 0x91, 0xa3, - 0x94, 0x72, 0xec, 0x9b, 0x66, 0xcf, 0x45, 0x17, 0xfc, 0x9f, 0xf0, 0xfd, - 0x85, 0x06, 0x73, 0x97, 0xfd, 0x13, 0xc7, 0x3e, 0x1c, 0x9c, 0xe5, 0x62, - 0x29, 0xd6, 0x5a, 0x88, 0x17, 0xe7, 0x60, 0xc7, 0x27, 0x2a, 0x64, 0xd4, - 0xb7, 0x0f, 0xde, 0x97, 0x5f, 0x67, 0x72, 0x73, 0x97, 0xa4, 0xfb, 0x39, - 0x7e, 0x96, 0x7b, 0x02, 0x52, 0xfa, 0x04, 0x60, 0xe5, 0x4c, 0x7c, 0x5e, - 0x1c, 0x50, 0x9e, 0xf8, 0x1a, 0x66, 0xce, 0x52, 0xa8, 0xd8, 0x48, 0x42, - 0x78, 0xc6, 0xff, 0x87, 0x3b, 0x9f, 0x3b, 0x93, 0x9c, 0xbf, 0xff, 0xf8, - 0x10, 0x2b, 0x7f, 0x3f, 0x20, 0xe7, 0xc8, 0xcd, 0x76, 0x14, 0x13, 0x97, - 0xf7, 0xfc, 0x3a, 0x6f, 0x78, 0x72, 0xfb, 0xca, 0xe7, 0x4e, 0x5f, 0xf8, - 0x73, 0xde, 0xfe, 0x7f, 0x62, 0xce, 0x5f, 0x83, 0xfb, 0xee, 0x47, 0x2d, - 0xa3, 0x97, 0x20, 0x0e, 0x5d, 0xd4, 0x39, 0x77, 0xfa, 0xf8, 0x6b, 0x26, - 0x16, 0xa7, 0x3e, 0xe0, 0x1e, 0xdc, 0x08, 0x39, 0x70, 0x20, 0xe5, 0xfb, - 0xf9, 0x60, 0xfd, 0x43, 0x58, 0x01, 0x6a, 0x84, 0xe1, 0x95, 0x23, 0x44, - 0x00, 0x42, 0x5c, 0x53, 0x6f, 0xff, 0xb0, 0x5f, 0x9d, 0x2a, 0xab, 0xfc, - 0x5b, 0x00, 0x72, 0xff, 0xef, 0x77, 0x18, 0xa4, 0x03, 0x39, 0xf1, 0xcb, - 0xfd, 0xca, 0xd3, 0x6a, 0x40, 0x4e, 0x5f, 0x01, 0x8f, 0x2f, 0x88, 0xcf, - 0xd2, 0xa7, 0x91, 0xae, 0xff, 0xc7, 0x2f, 0xe0, 0x31, 0x4d, 0x29, 0x39, - 0xcb, 0xfb, 0x48, 0x23, 0x1c, 0x9c, 0xbb, 0x39, 0x39, 0x5c, 0x9f, 0xaf, - 0x8c, 0x9a, 0x16, 0x5f, 0x03, 0x69, 0xb3, 0x95, 0x09, 0x95, 0x49, 0x25, - 0xe1, 0x1a, 0xd9, 0x95, 0xef, 0xf9, 0xf1, 0xcb, 0x39, 0xca, 0xd1, 0xaf, - 0xf0, 0xfd, 0xd8, 0xd9, 0xcb, 0xfe, 0x8e, 0x70, 0x11, 0xc7, 0x27, 0x39, - 0x7f, 0x0e, 0x7b, 0x4e, 0x03, 0x95, 0xb3, 0xfe, 0x00, 0xbe, 0x8e, 0xef, - 0xfa, 0x27, 0xd6, 0xf1, 0x71, 0x39, 0xcb, 0xfd, 0x83, 0x3e, 0x05, 0xfa, - 0x72, 0xa6, 0x3e, 0xc6, 0xce, 0xaf, 0xec, 0x66, 0x05, 0x1b, 0x39, 0x73, - 0x20, 0xe5, 0x30, 0xf0, 0xdc, 0xb6, 0xfe, 0x1c, 0x9b, 0xa9, 0xe3, 0x97, - 0xd9, 0x9d, 0xd1, 0xca, 0xc4, 0x6b, 0x3b, 0x3f, 0x88, 0x78, 0x0b, 0x6f, - 0x36, 0xdb, 0x65, 0x2f, 0xd8, 0xa8, 0xff, 0xa2, 0x9f, 0x4d, 0x05, 0xf7, - 0xd6, 0xdb, 0x6c, 0xe5, 0xd8, 0x03, 0x95, 0x86, 0xfb, 0xc5, 0x15, 0x08, - 0x99, 0xf3, 0xcd, 0xff, 0xf2, 0x49, 0xf4, 0xc6, 0x3c, 0x9d, 0x5e, 0xa1, - 0xcb, 0xe4, 0xd8, 0x34, 0x72, 0xff, 0xb5, 0xb8, 0xff, 0xc2, 0x9c, 0x4e, - 0x5f, 0xf8, 0x73, 0x4b, 0xea, 0x2e, 0x04, 0xe5, 0xff, 0xfe, 0x55, 0xb7, - 0xda, 0xbf, 0x75, 0x92, 0x1f, 0xdf, 0x58, 0x27, 0x2a, 0x11, 0xb9, 0x87, - 0x68, 0x79, 0x7c, 0xdb, 0x8c, 0x8e, 0x5f, 0xf7, 0xa3, 0x90, 0x3f, 0x7a, - 0x87, 0x2d, 0xd3, 0x95, 0x87, 0x94, 0xb3, 0x9b, 0xf0, 0xe7, 0xa3, 0x67, - 0x2f, 0x36, 0xdb, 0x65, 0x2f, 0xce, 0xaf, 0x53, 0xc5, 0x3e, 0x9a, 0x0a, - 0x84, 0x40, 0x22, 0x35, 0xee, 0x30, 0xc3, 0x97, 0xbc, 0x8d, 0x9c, 0xbd, - 0xa7, 0xd9, 0xca, 0xe4, 0xdc, 0xf8, 0x76, 0xf7, 0x60, 0x27, 0x2b, 0x11, - 0x2a, 0x8a, 0xee, 0x45, 0x7e, 0xc0, 0x66, 0x4c, 0x72, 0xda, 0xf8, 0x9d, - 0x5e, 0xe1, 0x43, 0xd8, 0x5b, 0x09, 0x6d, 0xdf, 0xc8, 0x2a, 0x99, 0xb2, - 0x50, 0xbd, 0xfb, 0x87, 0xec, 0x4f, 0xf9, 0xcb, 0xff, 0x93, 0xd1, 0xbc, - 0x1f, 0x3b, 0x89, 0xca, 0x99, 0x70, 0xe3, 0xb0, 0xfe, 0x19, 0x52, 0x7f, - 0x9c, 0x71, 0x2f, 0xbd, 0x1c, 0x60, 0xe5, 0x62, 0xe8, 0x02, 0x4e, 0x43, - 0x8a, 0xe5, 0xe1, 0x8e, 0x27, 0x2f, 0xfe, 0xdc, 0x2f, 0xa2, 0xfe, 0x18, - 0x6c, 0xe5, 0xdc, 0x3a, 0x1c, 0xb9, 0x3a, 0x72, 0xa7, 0x36, 0x3b, 0x1b, - 0xa8, 0x44, 0xb3, 0xba, 0x5f, 0x7b, 0x5f, 0xb5, 0x9c, 0xbf, 0xd0, 0x32, - 0x14, 0x8e, 0x4e, 0x54, 0x36, 0x5f, 0x32, 0x87, 0xb8, 0x4b, 0xf2, 0x3e, - 0x45, 0x63, 0x0f, 0x59, 0xaf, 0x27, 0x48, 0xe7, 0xb8, 0xee, 0x7b, 0x29, - 0x1d, 0xdc, 0x41, 0x09, 0xf1, 0x8d, 0xc7, 0x50, 0xf7, 0xf4, 0xe9, 0x17, - 0x13, 0x86, 0x90, 0xb3, 0x50, 0x87, 0x80, 0x9e, 0xfc, 0x93, 0x49, 0x04, - 0xe5, 0xcd, 0x42, 0x1c, 0xbf, 0xe9, 0xbd, 0xc1, 0xa8, 0x9b, 0xfd, 0x9c, - 0xbf, 0xc1, 0x81, 0x64, 0x06, 0x0e, 0x54, 0x1f, 0x8b, 0xa0, 0x5f, 0xfd, - 0x89, 0xd8, 0x0f, 0x7f, 0x8e, 0x74, 0x72, 0xf0, 0x55, 0x01, 0xcb, 0xf3, - 0x37, 0xb7, 0xf1, 0xca, 0xf8, 0x78, 0xd0, 0x3d, 0x7f, 0xf4, 0xce, 0xbe, - 0xc4, 0xbc, 0x38, 0xc3, 0x97, 0xf6, 0xf0, 0x45, 0xe7, 0x39, 0x4b, 0x3f, - 0x04, 0x44, 0xbf, 0xfe, 0x46, 0x73, 0x2d, 0x7c, 0xc1, 0x1c, 0x40, 0x1c, - 0xbc, 0x9d, 0xfc, 0xe5, 0x7c, 0x54, 0xfe, 0xd5, 0x13, 0xca, 0x11, 0x9b, - 0x20, 0xec, 0x22, 0xde, 0x12, 0x7e, 0x21, 0xe2, 0xa1, 0x6f, 0xad, 0x44, - 0x7b, 0x1e, 0x5c, 0x24, 0x36, 0xda, 0xb8, 0xd2, 0x38, 0x66, 0x9e, 0x17, - 0x8d, 0x9d, 0xa9, 0xc6, 0x42, 0xd4, 0x8e, 0xf8, 0x52, 0xd4, 0x56, 0x2b, - 0x93, 0xce, 0xed, 0x4a, 0x97, 0xe2, 0x1a, 0x5f, 0x06, 0x5e, 0x13, 0xf2, - 0xb2, 0xfd, 0x17, 0x4f, 0x1f, 0xe6, 0x94, 0xa6, 0x94, 0xc9, 0xc6, 0xb8, - 0xe2, 0x26, 0xa7, 0xd6, 0x6e, 0xb1, 0x12, 0x65, 0x2c, 0xa7, 0xb5, 0xf1, - 0xa3, 0xda, 0x0f, 0xb0, 0x53, 0x1a, 0x78, 0x78, 0xc1, 0x06, 0xbb, 0xbe, - 0xd5, 0xe2, 0xc4, 0xfa, 0xd6, 0x19, 0xff, 0x3c, 0x9f, 0xc6, 0x59, 0x4b, - 0x72, 0xd8, 0x5a, 0x52, 0x71, 0x54, 0xad, 0x54, 0x78, 0x25, 0xe2, 0x57, - 0xd8, 0xf7, 0x30, 0xe5, 0x9e, 0xcd, 0x8d, 0xe6, 0x67, 0x8e, 0x5f, 0xe7, - 0x64, 0x79, 0x34, 0x87, 0x2d, 0xf4, 0x07, 0x9a, 0x23, 0x97, 0xfb, 0xee, - 0x6d, 0x6e, 0xeb, 0x34, 0x5c, 0x6b, 0xfd, 0xf7, 0x36, 0xb7, 0x75, 0x9a, - 0x2e, 0xb5, 0xff, 0xdf, 0x5e, 0x5f, 0x73, 0x6b, 0x77, 0x59, 0xa2, 0x51, - 0x54, 0x47, 0xc6, 0x3f, 0x28, 0x67, 0x04, 0xa9, 0x58, 0x49, 0xac, 0xa5, - 0x25, 0x1c, 0xb5, 0xc2, 0x35, 0xf3, 0xdd, 0x1d, 0x04, 0x22, 0x74, 0x53, - 0xe4, 0x1e, 0x04, 0x1b, 0xff, 0xdf, 0x58, 0xf2, 0xfb, 0x9b, 0x5b, 0xba, - 0xcd, 0x12, 0xd2, 0xff, 0xb8, 0x5b, 0xa8, 0xd6, 0xf1, 0xcf, 0x01, 0xcb, - 0xf6, 0xd6, 0xee, 0xb3, 0x44, 0x6e, 0xbf, 0xfb, 0xb0, 0x9b, 0x4e, 0x1d, - 0x7d, 0x86, 0xce, 0x5f, 0xf9, 0xe5, 0xf7, 0x36, 0xb7, 0x75, 0x9a, 0x25, - 0xf5, 0xfd, 0x1e, 0x53, 0xaf, 0xe3, 0x97, 0xfb, 0x14, 0xda, 0xbd, 0xff, - 0x47, 0x2f, 0xbf, 0xea, 0x6c, 0xe5, 0xe9, 0xb5, 0xb3, 0x96, 0xfa, 0xd4, - 0x93, 0xb5, 0xc4, 0x65, 0x9a, 0x31, 0x27, 0xa9, 0x82, 0x5c, 0xd0, 0xdd, - 0x42, 0x3b, 0xff, 0xdc, 0xcb, 0xc9, 0x37, 0xd0, 0xa7, 0x18, 0x09, 0xcb, - 0xfd, 0xf7, 0x36, 0xb7, 0x75, 0x9a, 0x2a, 0xb5, 0xc9, 0xc0, 0x72, 0xf9, - 0x18, 0xfc, 0x4e, 0x52, 0xa6, 0xf3, 0xc3, 0x37, 0x87, 0x81, 0xb3, 0x97, - 0xf7, 0x63, 0x8f, 0xe1, 0xc3, 0x97, 0xf3, 0xf6, 0x61, 0x80, 0x9c, 0xbf, - 0xfb, 0xdd, 0x8d, 0x0b, 0xff, 0xc3, 0xa6, 0xce, 0x5e, 0x89, 0x61, 0xca, - 0x92, 0x30, 0x42, 0x61, 0xc9, 0x6c, 0xc9, 0x37, 0xfc, 0xae, 0x0e, 0x73, - 0xe7, 0x61, 0xcb, 0xdc, 0x11, 0xe3, 0x97, 0xfb, 0x70, 0xc5, 0x20, 0x56, - 0x72, 0xf7, 0x2f, 0xc9, 0xcb, 0xe7, 0xf3, 0xf2, 0x72, 0xe0, 0xa1, 0xcb, - 0xfb, 0x36, 0xb7, 0x75, 0x9a, 0x24, 0x05, 0x7c, 0x3c, 0xff, 0xa2, 0xd7, - 0xed, 0x38, 0xbf, 0x27, 0x2e, 0xfe, 0x0e, 0x54, 0x8f, 0x93, 0x92, 0x6d, - 0x93, 0xdf, 0xe9, 0x46, 0xe7, 0x8d, 0xce, 0x72, 0xff, 0x6e, 0x76, 0x40, - 0xcb, 0x47, 0x2a, 0x0f, 0xa7, 0x0d, 0x6f, 0xb2, 0x77, 0x09, 0xcb, 0xb8, - 0x4e, 0x9c, 0xbf, 0xfd, 0x93, 0x75, 0xd9, 0xee, 0xc7, 0xbf, 0x61, 0xca, - 0x9d, 0x70, 0x0c, 0x24, 0x59, 0x0e, 0x15, 0x4f, 0xda, 0xce, 0x66, 0x1f, - 0x61, 0x9f, 0x47, 0x9e, 0x1a, 0xa3, 0x09, 0x9f, 0x10, 0x34, 0x22, 0x50, - 0x72, 0xfd, 0x02, 0x39, 0xe3, 0x97, 0xdb, 0xda, 0x2c, 0xe5, 0xf0, 0xe4, - 0xff, 0x5a, 0x1e, 0x3a, 0x84, 0xb7, 0xfb, 0xef, 0x5d, 0x99, 0x01, 0x39, - 0x5f, 0x53, 0x83, 0xdc, 0x62, 0x2d, 0x0f, 0xaf, 0xf7, 0xdc, 0xda, 0xdd, - 0xd6, 0x68, 0xb2, 0x17, 0xfb, 0xee, 0x6d, 0x6e, 0xeb, 0x34, 0x5a, 0xeb, - 0xff, 0xd8, 0xa4, 0x4f, 0xf7, 0x26, 0xf0, 0x60, 0x4e, 0x5f, 0xef, 0xb9, - 0xb5, 0xbb, 0xac, 0xd1, 0x72, 0x2f, 0xdb, 0x5b, 0xba, 0xcd, 0x17, 0x62, - 0xff, 0xcf, 0x2f, 0xb9, 0xb5, 0xbb, 0xac, 0xd1, 0x47, 0x2d, 0xf7, 0x11, - 0x00, 0xc3, 0x4b, 0xe1, 0x89, 0x30, 0xe5, 0xff, 0xb8, 0x6e, 0x11, 0x91, - 0xb9, 0x62, 0x71, 0x39, 0x69, 0x1c, 0xbf, 0x6d, 0x6e, 0xeb, 0x34, 0x52, - 0xab, 0xfe, 0x5f, 0x52, 0x6e, 0xc4, 0xf8, 0x72, 0xff, 0xf7, 0x62, 0x78, - 0xea, 0x71, 0x70, 0xf5, 0x0e, 0x7d, 0x37, 0x57, 0x4b, 0xee, 0x23, 0x2e, - 0x66, 0xea, 0xe5, 0x30, 0xd7, 0x86, 0xe5, 0xff, 0x9d, 0x3d, 0x2f, 0xc2, - 0xe2, 0x03, 0x96, 0xfa, 0x14, 0xf7, 0xf9, 0x21, 0x64, 0x6a, 0xfd, 0x29, - 0xa9, 0xd9, 0xa0, 0x92, 0x94, 0x1f, 0x90, 0x81, 0xe5, 0x41, 0x27, 0x80, - 0xd8, 0x76, 0x04, 0x11, 0x41, 0xd2, 0x6f, 0xa1, 0x83, 0xc6, 0x50, 0x4d, - 0xff, 0x4b, 0xee, 0x6d, 0x6e, 0xeb, 0x34, 0x47, 0x0b, 0xfe, 0x4f, 0xb9, - 0xb5, 0xbb, 0xac, 0xd1, 0x5a, 0xad, 0xf5, 0xd1, 0x1b, 0xe4, 0x7b, 0xff, - 0xdf, 0x58, 0xf2, 0xfb, 0x9b, 0x5b, 0xba, 0xcd, 0x12, 0xda, 0xf7, 0xfb, - 0x01, 0xcb, 0xb3, 0x93, 0x97, 0xf8, 0x38, 0xc6, 0x42, 0x68, 0xe5, 0xee, - 0x3f, 0xc8, 0xe5, 0x2d, 0x10, 0xfc, 0x8f, 0x20, 0xbf, 0x13, 0x2b, 0xdd, - 0x0c, 0x8e, 0x5f, 0xf6, 0x72, 0x38, 0x00, 0x3c, 0x8e, 0x5c, 0xc5, 0x9c, - 0xbf, 0xd8, 0x9c, 0xe8, 0x38, 0x27, 0x2a, 0x11, 0x03, 0x23, 0x8d, 0x8b, - 0xdf, 0x0c, 0x73, 0x23, 0x97, 0xff, 0xe7, 0xe4, 0x01, 0xeb, 0xcb, 0x34, - 0x3f, 0xba, 0x87, 0x2f, 0x81, 0x9b, 0x98, 0xe5, 0x2d, 0x13, 0x9d, 0x22, - 0x02, 0xbd, 0x95, 0x39, 0x7f, 0x26, 0xc5, 0x3d, 0xa3, 0x97, 0xed, 0xb8, - 0xe4, 0x1c, 0xa3, 0x44, 0x36, 0x43, 0xe3, 0xe8, 0x93, 0x96, 0x5d, 0x02, - 0x72, 0xfe, 0x41, 0x0e, 0x20, 0x4e, 0x54, 0x1e, 0x04, 0x85, 0x6f, 0xb2, - 0x69, 0x61, 0xcb, 0xff, 0x3c, 0xbe, 0xe6, 0xd6, 0xee, 0xb3, 0x44, 0xc0, - 0xbc, 0xda, 0x00, 0xe5, 0xf6, 0x9c, 0x40, 0x72, 0xa6, 0x37, 0xc0, 0x1d, - 0xbf, 0xdf, 0xf3, 0xb4, 0x86, 0x61, 0xcb, 0xf7, 0x52, 0x06, 0x73, 0x97, - 0xfd, 0x13, 0xf8, 0x63, 0xff, 0x68, 0xe5, 0xbd, 0xd4, 0x4a, 0xe8, 0xd1, - 0xa1, 0x3d, 0xf7, 0x2b, 0x45, 0x4e, 0x56, 0x1e, 0xe7, 0x8e, 0x2f, 0xf6, - 0xd3, 0xd8, 0xc8, 0xe9, 0xcb, 0xfd, 0xa4, 0xea, 0x33, 0x15, 0x39, 0x7f, - 0xf9, 0xe7, 0xea, 0x40, 0xe4, 0xc9, 0xb4, 0x39, 0x58, 0x8a, 0xdf, 0x19, - 0x36, 0x67, 0x72, 0xf0, 0xe5, 0xdf, 0x80, 0xa5, 0x21, 0xae, 0xd8, 0xb5, - 0xf9, 0x58, 0x96, 0x04, 0xe5, 0xfe, 0xc0, 0x8e, 0x7b, 0xb8, 0x72, 0xee, - 0x19, 0x67, 0x8c, 0x29, 0x7f, 0x4e, 0xa3, 0x47, 0x10, 0x1c, 0xbf, 0xb3, - 0xde, 0x8d, 0xe8, 0xe5, 0xfc, 0xe2, 0x09, 0xc1, 0xe3, 0x95, 0x08, 0x8c, - 0x13, 0x16, 0x85, 0xb6, 0xfb, 0x0b, 0xe4, 0xd3, 0x9f, 0x86, 0x13, 0xd9, - 0x0c, 0xb5, 0xc2, 0x4f, 0x98, 0x40, 0xec, 0x85, 0x84, 0x4f, 0x08, 0xa1, - 0x8c, 0x4f, 0x50, 0xce, 0xf2, 0xf7, 0xe4, 0x1c, 0x4a, 0x1b, 0x31, 0x52, - 0x16, 0xb7, 0x99, 0xfe, 0xca, 0x5f, 0xf9, 0xe5, 0xf7, 0x36, 0xb7, 0x75, - 0x9a, 0x26, 0x35, 0xf4, 0x6e, 0x38, 0x0e, 0x5b, 0xea, 0x22, 0x39, 0x83, - 0xdd, 0x4c, 0xbe, 0x89, 0xe3, 0x67, 0x2f, 0xd9, 0x13, 0x23, 0x0e, 0x52, - 0x1e, 0x4e, 0xc8, 0xaf, 0xe0, 0xb2, 0x33, 0xda, 0x39, 0x7f, 0xbb, 0x1b, - 0x9d, 0x4f, 0xc0, 0x72, 0xe7, 0xd1, 0xcb, 0xef, 0x9e, 0xce, 0x9c, 0xb4, - 0x74, 0xdd, 0x68, 0x5a, 0xf4, 0x0c, 0xe7, 0x2f, 0xff, 0xff, 0xa5, 0xae, - 0xe7, 0xed, 0xeb, 0xb8, 0xbc, 0xd7, 0xcc, 0xe6, 0x5a, 0x41, 0x43, 0x97, - 0x9d, 0xd6, 0x68, 0xac, 0x57, 0xce, 0xa4, 0x2a, 0x72, 0x96, 0x79, 0x7b, - 0x28, 0xbf, 0xf3, 0x4c, 0xf0, 0xe7, 0xf0, 0x3e, 0x39, 0x4a, 0xa6, 0xde, - 0xb2, 0x6e, 0x47, 0x37, 0x0c, 0xcf, 0x11, 0x5f, 0xfc, 0x3e, 0x57, 0xf8, - 0x1c, 0x5c, 0x6c, 0xe5, 0xfe, 0xdc, 0xfe, 0xd3, 0xf2, 0xb3, 0x95, 0x07, - 0xf4, 0xe8, 0x97, 0xee, 0x0f, 0x67, 0x33, 0x1c, 0xbf, 0xff, 0xff, 0xcf, - 0xef, 0x67, 0x74, 0xf2, 0x41, 0xf4, 0xb3, 0x79, 0xac, 0xeb, 0xce, 0x31, - 0x23, 0x95, 0x08, 0xb8, 0xd1, 0x6d, 0xfd, 0xfb, 0x45, 0xf5, 0x38, 0x73, - 0x97, 0xf6, 0x6b, 0x99, 0x47, 0x4e, 0x5d, 0x1c, 0x4e, 0x57, 0x4f, 0x18, - 0x4b, 0xaf, 0xf4, 0xcf, 0x89, 0x25, 0x18, 0x72, 0x82, 0x7a, 0xa8, 0x43, - 0x7f, 0xd1, 0xcc, 0xa6, 0x93, 0xee, 0x73, 0x95, 0x09, 0x97, 0x64, 0x34, - 0x50, 0x86, 0xf4, 0x4b, 0xc7, 0x2f, 0xfd, 0x81, 0xda, 0x7f, 0x38, 0x35, - 0x23, 0x97, 0xcc, 0x7e, 0x7c, 0x72, 0xff, 0xe9, 0xe3, 0xdf, 0x14, 0x5a, - 0x9c, 0x0a, 0x68, 0xe5, 0xff, 0x6e, 0x34, 0xfb, 0x18, 0x91, 0xca, 0xda, - 0x21, 0xb8, 0xa7, 0xde, 0x93, 0xce, 0x72, 0xf7, 0xc9, 0xd8, 0x72, 0xe0, - 0xf8, 0xe5, 0x70, 0xc9, 0x91, 0x64, 0x2a, 0x79, 0x25, 0x41, 0xd1, 0x20, - 0xbf, 0xf0, 0xb8, 0x7b, 0x1c, 0x7a, 0xe2, 0x72, 0xff, 0xff, 0xdf, 0xcf, - 0x8b, 0xf8, 0x3f, 0xf0, 0x7c, 0xce, 0x65, 0x9f, 0x88, 0x34, 0x72, 0xff, - 0xf4, 0xf9, 0xcf, 0xb4, 0x83, 0x00, 0x76, 0x1c, 0xbf, 0xdc, 0x8e, 0x07, - 0xae, 0xd9, 0xca, 0xc3, 0xfe, 0x74, 0xaa, 0x0a, 0x6a, 0x82, 0x7d, 0xa8, - 0x7b, 0x5f, 0xd3, 0xcd, 0x2e, 0x1b, 0x73, 0x9c, 0xbe, 0x11, 0xcf, 0x1c, - 0xbf, 0x23, 0x5e, 0xf6, 0x87, 0x29, 0xaa, 0x44, 0x0c, 0x1b, 0xf4, 0x82, - 0xfe, 0x9d, 0x46, 0x8e, 0x20, 0x39, 0x7c, 0xd7, 0x1a, 0x13, 0x97, 0xfe, - 0xeb, 0xb3, 0xdd, 0x8f, 0x7e, 0xc3, 0x95, 0x87, 0xc9, 0x31, 0x25, 0xff, - 0xd9, 0x8a, 0xb2, 0x13, 0x7b, 0x46, 0xce, 0x5f, 0xf2, 0x49, 0x3b, 0xfb, - 0x18, 0x87, 0x2e, 0xcf, 0x1c, 0xa8, 0x4d, 0x2b, 0x21, 0x2b, 0xb2, 0x2f, - 0x22, 0x34, 0x39, 0xbd, 0xd4, 0xfb, 0x0c, 0xaf, 0xf9, 0xc8, 0x64, 0x5b, - 0x91, 0xf0, 0x2e, 0x19, 0x9b, 0x86, 0xc7, 0x63, 0x50, 0x73, 0x31, 0x1c, - 0xd4, 0x6c, 0x7e, 0x8e, 0x9d, 0xa4, 0x2d, 0x94, 0x8d, 0xfa, 0xf7, 0x0b, - 0x34, 0x6a, 0x8e, 0x5d, 0x21, 0x39, 0x7f, 0x6f, 0x70, 0x1c, 0x61, 0xcb, - 0xe9, 0xf7, 0x13, 0x9c, 0xb9, 0x40, 0x1c, 0xbd, 0xd4, 0x61, 0xcb, 0x4c, - 0x72, 0x9c, 0xd7, 0x7e, 0x39, 0x7e, 0x71, 0x9f, 0xfd, 0x1c, 0xbf, 0xe8, - 0x0f, 0x70, 0x3b, 0x75, 0x9c, 0xa4, 0x4c, 0x65, 0xcb, 0x40, 0x48, 0x28, - 0xda, 0x21, 0xf1, 0x4d, 0xba, 0x72, 0xf6, 0x94, 0xd1, 0xcb, 0xee, 0x67, - 0x85, 0x4e, 0x54, 0xe7, 0xa8, 0x11, 0x1f, 0xc7, 0xae, 0xf4, 0x1c, 0xbf, - 0xdc, 0xee, 0x12, 0x4f, 0xa3, 0x97, 0xd8, 0x31, 0x23, 0x95, 0x87, 0xa6, - 0xc3, 0x3b, 0xfd, 0x80, 0xd6, 0x79, 0x36, 0x72, 0xfb, 0xff, 0x66, 0x8e, - 0x5f, 0x46, 0xdc, 0x4e, 0x5f, 0xb3, 0x72, 0x86, 0x1c, 0xbf, 0xcf, 0xb9, - 0x01, 0x39, 0xd1, 0xcb, 0xed, 0x6a, 0x00, 0x72, 0xa1, 0x31, 0x3c, 0x21, - 0x43, 0x2e, 0x91, 0xb9, 0x07, 0xe4, 0xed, 0x9a, 0x5f, 0xc8, 0x23, 0x9c, - 0x5c, 0xe5, 0xe9, 0x29, 0xe3, 0x97, 0xd2, 0x07, 0xf2, 0x39, 0x7d, 0xb5, - 0x20, 0x07, 0x2a, 0x0f, 0x1d, 0x09, 0x2f, 0xf2, 0x4e, 0xec, 0x00, 0x20, - 0xe5, 0xc8, 0x13, 0x97, 0xfc, 0x8b, 0xee, 0x4c, 0x30, 0x13, 0x97, 0xd2, - 0xf6, 0x28, 0x72, 0xf2, 0xe0, 0x07, 0x2f, 0x6e, 0x18, 0x72, 0x9c, 0xf6, - 0xff, 0x23, 0x6c, 0x72, 0xfa, 0x75, 0x32, 0x63, 0x97, 0xa3, 0x73, 0x9c, - 0xa8, 0x3c, 0x24, 0x25, 0xbd, 0x03, 0x23, 0x97, 0xde, 0x14, 0xe0, 0x39, - 0x41, 0x54, 0xbd, 0xc9, 0x64, 0xcc, 0xbb, 0x20, 0x61, 0x9f, 0x45, 0x86, - 0x12, 0x7a, 0x72, 0xf1, 0x07, 0xe3, 0x77, 0xfb, 0xaf, 0x2e, 0x0e, 0x0f, - 0xe7, 0x39, 0x77, 0x5a, 0x1c, 0xbf, 0xf4, 0x66, 0xbe, 0x42, 0x05, 0x49, - 0x1c, 0xbf, 0x91, 0xbd, 0x4f, 0x8d, 0x9c, 0xa1, 0x3f, 0x0f, 0x20, 0x5f, - 0xa0, 0x3e, 0xc5, 0x9c, 0xbe, 0xec, 0x0a, 0xce, 0x54, 0x8f, 0xa7, 0x44, - 0x3e, 0x27, 0xbe, 0x71, 0x79, 0x8e, 0x5f, 0x93, 0xc3, 0x92, 0x39, 0x7d, - 0x0d, 0xc4, 0xc7, 0x2e, 0x51, 0x87, 0x2f, 0xef, 0x0b, 0x83, 0x04, 0xe5, - 0xf8, 0x5c, 0x18, 0x27, 0x2d, 0xff, 0xc3, 0xd0, 0xf1, 0x5d, 0x4e, 0x8f, - 0xd5, 0x48, 0x50, 0x9b, 0xa4, 0x62, 0xd1, 0x7f, 0xa1, 0xb0, 0xfe, 0xfb, - 0x91, 0xcb, 0xf9, 0x37, 0xce, 0xa2, 0x47, 0x2d, 0xc4, 0xe5, 0x6c, 0xfd, - 0xba, 0x6b, 0xc0, 0x5d, 0x78, 0x51, 0x53, 0x97, 0xd8, 0x14, 0xe2, 0x72, - 0xe8, 0x66, 0x1b, 0xf7, 0x1c, 0xbf, 0xec, 0x6d, 0xf9, 0xec, 0x28, 0x27, - 0x2d, 0xa3, 0x94, 0x87, 0xeb, 0xb2, 0xa7, 0x3a, 0xb7, 0x27, 0x2e, 0x04, - 0x14, 0xb9, 0xb6, 0xca, 0x52, 0x1a, 0xf6, 0xc5, 0xaf, 0xe9, 0x0e, 0x7b, - 0xa8, 0x53, 0xe9, 0xa1, 0xa0, 0xa2, 0x81, 0xd8, 0xaf, 0x3f, 0x3a, 0x39, - 0x6d, 0x1c, 0xbe, 0x53, 0xaf, 0xe3, 0x94, 0x13, 0xd1, 0xe4, 0x77, 0xc2, - 0x37, 0xa0, 0x66, 0x39, 0x70, 0xc1, 0xcb, 0x4c, 0x72, 0xa6, 0x3c, 0x3d, - 0x8e, 0x38, 0xad, 0xff, 0xca, 0xa0, 0xaf, 0x50, 0xc7, 0xe7, 0xc7, 0x2f, - 0x03, 0x38, 0x0e, 0x52, 0xa7, 0xc9, 0xb4, 0x5b, 0xe6, 0x6b, 0xf6, 0x1c, - 0xb2, 0xa7, 0x2c, 0xd0, 0xe5, 0xdb, 0x54, 0xe5, 0x41, 0xf0, 0xa1, 0x27, - 0xe2, 0x4a, 0x09, 0xdf, 0xff, 0x77, 0x25, 0xa8, 0xf4, 0xb1, 0xad, 0xc4, - 0x07, 0x2f, 0xfd, 0x24, 0xf7, 0x73, 0x9f, 0x7f, 0x07, 0x2e, 0xcd, 0x1c, - 0xa8, 0x3d, 0x69, 0x20, 0x56, 0x91, 0x91, 0xe8, 0x53, 0xd8, 0x07, 0x2f, - 0xc9, 0x0c, 0x86, 0x1c, 0xb6, 0x1c, 0xa4, 0x3e, 0xf7, 0x28, 0xd0, 0x8b, - 0x42, 0x6a, 0x85, 0x67, 0x38, 0xe6, 0x90, 0x93, 0xec, 0x21, 0x1e, 0x37, - 0x3b, 0xda, 0x89, 0x8e, 0x5f, 0xd8, 0x1c, 0xe2, 0x9b, 0x39, 0x47, 0x2c, - 0xc3, 0x95, 0xe2, 0xf3, 0x88, 0x5d, 0xf8, 0x09, 0xb4, 0x54, 0xe5, 0xce, - 0xa9, 0xca, 0x99, 0x19, 0x0c, 0x1d, 0xea, 0x50, 0x08, 0x84, 0xa2, 0xec, - 0xd9, 0xcb, 0xbd, 0x07, 0x2f, 0xd1, 0xdc, 0xe2, 0xe7, 0x29, 0x87, 0xa8, - 0xe2, 0xc0, 0x16, 0xbf, 0x93, 0xd9, 0xd7, 0x54, 0xe5, 0xfd, 0xdf, 0xde, - 0x7e, 0xa1, 0xcb, 0xcd, 0xb6, 0xd9, 0x4b, 0xfe, 0x0c, 0x4e, 0xa6, 0x75, - 0xf9, 0x29, 0xf4, 0xd0, 0x5d, 0x93, 0x9c, 0xbd, 0x28, 0x61, 0xca, 0x0a, - 0x33, 0xd6, 0x9e, 0x89, 0xb3, 0x0b, 0xde, 0x86, 0x21, 0xca, 0xc3, 0xd8, - 0x59, 0xed, 0xf2, 0x6f, 0x80, 0x27, 0x2f, 0xdd, 0x8e, 0x5d, 0xac, 0xe5, - 0xff, 0xf4, 0x7b, 0x41, 0xcf, 0x27, 0x7f, 0xce, 0x7c, 0x72, 0xba, 0x7f, - 0x9e, 0x2b, 0xb6, 0xce, 0x5f, 0xec, 0xc5, 0xa9, 0xc7, 0xb8, 0x72, 0xff, - 0xc9, 0x03, 0xe1, 0xcf, 0x43, 0x67, 0x2f, 0x7b, 0x7f, 0x9c, 0xb6, 0x8e, - 0x50, 0x9a, 0xff, 0xc7, 0xaf, 0xff, 0xd8, 0x18, 0xce, 0x54, 0xf2, 0x0f, - 0xf2, 0xcd, 0x1c, 0xb9, 0x80, 0x39, 0x73, 0x89, 0xca, 0xe9, 0xac, 0x71, - 0x7b, 0xf3, 0x13, 0xc0, 0x73, 0x95, 0x3a, 0xa5, 0xec, 0x85, 0x0b, 0x59, - 0x14, 0xc2, 0x3b, 0x35, 0x76, 0xb1, 0x21, 0xf4, 0x20, 0xbf, 0x20, 0xbb, - 0x6a, 0x9c, 0xbe, 0xef, 0x92, 0x73, 0x97, 0xf9, 0x69, 0xa1, 0xce, 0x2e, - 0x72, 0xfa, 0x27, 0x79, 0x1c, 0xbe, 0xf6, 0xba, 0x87, 0x2f, 0xe1, 0x7f, - 0x4f, 0x8d, 0x9c, 0xa3, 0x94, 0x26, 0xe7, 0xc5, 0xd5, 0x07, 0xf7, 0x8b, - 0x77, 0xec, 0x9c, 0x73, 0x93, 0x95, 0x09, 0xa9, 0xe0, 0xc7, 0x24, 0x7b, - 0x33, 0xec, 0x27, 0x44, 0x82, 0xf0, 0xa3, 0x59, 0xcb, 0xe0, 0xb4, 0x75, - 0x4e, 0x54, 0x1e, 0x1e, 0x0f, 0x5e, 0xec, 0x04, 0xe5, 0xdb, 0xd1, 0xca, - 0x38, 0x85, 0xbd, 0xfe, 0x81, 0x93, 0xb3, 0x02, 0x72, 0xfb, 0xcc, 0x66, - 0xce, 0x5f, 0xfc, 0x08, 0x15, 0xbf, 0x80, 0xa0, 0xc8, 0xe5, 0xe9, 0x27, - 0x4e, 0x5f, 0x78, 0x72, 0x47, 0x2f, 0xd9, 0xff, 0x0f, 0xa7, 0x39, 0x7f, - 0xf9, 0x35, 0xdc, 0x08, 0xe7, 0x11, 0xcd, 0x1c, 0xa9, 0x26, 0x96, 0xa9, - 0x8f, 0x24, 0x73, 0x22, 0x6c, 0x70, 0x48, 0x7c, 0x5b, 0x4d, 0x53, 0x73, - 0xb3, 0xc3, 0x15, 0xc4, 0x65, 0xf3, 0xc2, 0xa6, 0x46, 0x21, 0x8d, 0xf3, - 0x25, 0x60, 0xab, 0x09, 0x45, 0x9e, 0x73, 0x0f, 0x24, 0x8c, 0xb2, 0x68, - 0x60, 0x6e, 0x1c, 0xcc, 0x86, 0x6f, 0x65, 0xd6, 0x3c, 0x64, 0x00, 0x84, - 0xf7, 0x0e, 0x5c, 0x31, 0xaa, 0x6a, 0x53, 0xff, 0xa3, 0xe0, 0xe3, 0x09, - 0xe6, 0xc8, 0x1a, 0x19, 0xa9, 0x1b, 0x25, 0xff, 0x7d, 0xf2, 0x67, 0x06, - 0xbf, 0x83, 0x97, 0xff, 0xfd, 0xfc, 0x7d, 0xf6, 0x93, 0xae, 0x9e, 0xcd, - 0x81, 0x8f, 0x23, 0x95, 0xf5, 0x53, 0xa4, 0xf1, 0xe7, 0x04, 0xfa, 0xfd, - 0xb5, 0xbb, 0xac, 0xd1, 0x5b, 0xaf, 0xfc, 0xf2, 0xfb, 0x9b, 0x5b, 0xba, - 0xcd, 0x13, 0x82, 0xdf, 0x71, 0x10, 0x0c, 0x34, 0xbb, 0x86, 0x09, 0xcb, - 0x74, 0xe5, 0xb4, 0x72, 0xbf, 0x34, 0x4d, 0x04, 0x6f, 0x96, 0xee, 0xb3, - 0x45, 0xa2, 0xbf, 0xfd, 0x81, 0xeb, 0xab, 0x34, 0xc9, 0xaf, 0xd8, 0x72, - 0xb6, 0x7f, 0x9d, 0x2e, 0xbe, 0x5b, 0x88, 0x0e, 0x5f, 0xf4, 0xd8, 0xd7, - 0xad, 0xed, 0xfc, 0x72, 0xfe, 0x87, 0x1f, 0xc3, 0x87, 0x2f, 0xfe, 0x1c, - 0xe3, 0xac, 0xee, 0x0a, 0x81, 0x39, 0x7f, 0xb3, 0x60, 0xc9, 0x94, 0xd1, - 0xcb, 0x2a, 0x72, 0xff, 0xb2, 0x27, 0xc9, 0xb6, 0x9a, 0x39, 0x48, 0x79, - 0x73, 0x09, 0x5f, 0xff, 0xa7, 0x8f, 0x40, 0x77, 0x1d, 0x7d, 0x0e, 0x00, - 0xe5, 0xff, 0xa3, 0x97, 0x6b, 0xe8, 0xbb, 0x5c, 0xe7, 0x2f, 0xfd, 0x1b, - 0x06, 0x26, 0x6f, 0xdf, 0x9c, 0xa8, 0x46, 0xbf, 0x55, 0x34, 0x8b, 0x6c, - 0x0a, 0x7d, 0xa8, 0x8b, 0x34, 0x20, 0x35, 0x0f, 0x9b, 0xfd, 0xde, 0xfe, - 0xab, 0x23, 0x47, 0x2f, 0xff, 0xc9, 0xa1, 0xce, 0x2f, 0xe1, 0xcd, 0x75, - 0xe6, 0x39, 0x7e, 0x8f, 0x69, 0x4e, 0x9c, 0xac, 0x45, 0xa4, 0xc6, 0xc2, - 0xab, 0x7d, 0x80, 0x7e, 0x9c, 0xbb, 0xba, 0x39, 0x6f, 0xbc, 0x22, 0xe6, - 0xfb, 0x56, 0x7d, 0x90, 0xa0, 0x59, 0x14, 0xc4, 0x2c, 0x3d, 0xec, 0xa1, - 0x9f, 0x46, 0x02, 0xd0, 0xbd, 0x42, 0x1b, 0xff, 0xff, 0x76, 0x00, 0xc7, - 0x97, 0xcf, 0x77, 0x19, 0x8b, 0x8e, 0xc3, 0x0e, 0x5f, 0xc9, 0x3f, 0xc7, - 0x10, 0x1c, 0xbe, 0x5b, 0xba, 0xcd, 0x16, 0xd2, 0xff, 0xfe, 0x87, 0xf4, - 0x76, 0x34, 0x89, 0x24, 0xde, 0x04, 0xe5, 0xfd, 0xd8, 0x64, 0x20, 0x4e, - 0x52, 0x26, 0x9b, 0x33, 0x6e, 0xcb, 0xf4, 0x5d, 0xe5, 0x7b, 0xff, 0x75, - 0x02, 0xf2, 0x0f, 0x51, 0x87, 0x2f, 0xfb, 0x31, 0x6d, 0x3f, 0xea, 0x6c, - 0xe5, 0xf4, 0x71, 0xc4, 0x39, 0x77, 0x80, 0x72, 0xff, 0xa2, 0x51, 0xb9, - 0xe3, 0x73, 0x9c, 0xbf, 0xff, 0x7e, 0x29, 0xc5, 0x3d, 0xd8, 0xf6, 0xa3, - 0x8c, 0x1c, 0xb9, 0xc2, 0x72, 0xff, 0xa3, 0x7f, 0x35, 0x1d, 0x74, 0x39, - 0x7f, 0xba, 0x8f, 0x2f, 0x24, 0xe7, 0x2f, 0xc1, 0x8c, 0x14, 0x39, 0x58, - 0xa8, 0xd9, 0x69, 0x73, 0x1f, 0x6c, 0xed, 0x84, 0x42, 0x2f, 0xa3, 0xaf, - 0x2c, 0x36, 0x2c, 0xd0, 0xe5, 0x43, 0x3b, 0xf9, 0x57, 0xd8, 0x7f, 0x13, - 0x97, 0xbf, 0xe6, 0x47, 0x2f, 0xe1, 0x68, 0x9b, 0xc5, 0x4e, 0x5f, 0x92, - 0x76, 0x42, 0xce, 0x5f, 0x9f, 0x99, 0x29, 0xa3, 0x97, 0xfe, 0x49, 0xb5, - 0xc5, 0xc6, 0x7f, 0xc2, 0x72, 0xdf, 0x55, 0x4c, 0x4b, 0xa5, 0xe2, 0x3f, - 0xe2, 0xfe, 0x25, 0x0a, 0x15, 0x57, 0xd5, 0x42, 0x40, 0x8e, 0xbe, 0xe6, - 0x74, 0xe5, 0xfb, 0x6b, 0x77, 0x59, 0xa2, 0xe5, 0x5f, 0xce, 0x1e, 0xc0, - 0xce, 0x72, 0xdf, 0x42, 0x7f, 0x18, 0x2f, 0xd3, 0x4b, 0xf6, 0xd6, 0xee, - 0xb3, 0x45, 0xda, 0xbf, 0xe4, 0x94, 0x90, 0x41, 0x12, 0x39, 0x7c, 0x9b, - 0x70, 0x1c, 0xb7, 0xdc, 0x44, 0x63, 0x9a, 0x68, 0xde, 0xa1, 0xf0, 0x0f, - 0x27, 0x2a, 0x95, 0x20, 0x1c, 0x31, 0xcf, 0x2b, 0x4b, 0x7f, 0x4a, 0xf5, - 0x0d, 0xae, 0x17, 0x7d, 0x9d, 0x09, 0x19, 0xe4, 0xad, 0x42, 0x97, 0xd0, - 0xc2, 0xbf, 0xdf, 0x73, 0x6b, 0x77, 0x59, 0xa2, 0xa7, 0x5f, 0x87, 0xee, - 0xf5, 0xa3, 0x97, 0x4e, 0xc3, 0x97, 0xee, 0x58, 0xee, 0x27, 0x28, 0x26, - 0xff, 0xf1, 0x8b, 0x78, 0xe5, 0xff, 0x43, 0xcf, 0xf3, 0x9d, 0x40, 0x4e, - 0x52, 0x1e, 0x68, 0x88, 0xdf, 0x2d, 0xdd, 0x66, 0x8a, 0xe5, 0x7f, 0xbe, - 0xe6, 0xd6, 0xee, 0xb3, 0x45, 0x9c, 0xbc, 0xef, 0x23, 0x97, 0xf2, 0x6b, - 0x05, 0xdb, 0x39, 0x5b, 0x45, 0xb7, 0x4b, 0x85, 0x07, 0xc3, 0x77, 0xff, - 0xbd, 0x1a, 0xf9, 0xfe, 0xbd, 0x13, 0x4c, 0x87, 0x2f, 0xe4, 0x64, 0xff, - 0xee, 0x47, 0x2f, 0xcc, 0xc9, 0x9c, 0x07, 0x2f, 0xa7, 0xeb, 0xf8, 0xe5, - 0x39, 0xe5, 0xfe, 0x51, 0x7f, 0xa3, 0xbf, 0x18, 0xd5, 0xf0, 0x9e, 0x39, - 0x58, 0x99, 0x67, 0x53, 0xc5, 0xef, 0x89, 0x15, 0xfb, 0x79, 0xe4, 0x61, - 0xcb, 0xe7, 0x18, 0x09, 0xcb, 0xf4, 0xd0, 0xc8, 0x50, 0xe5, 0xd2, 0x61, - 0xca, 0xc3, 0xc0, 0x12, 0x9b, 0xff, 0xdd, 0x4f, 0x9d, 0x74, 0xf4, 0x60, - 0x50, 0xe5, 0xfb, 0x6b, 0x77, 0x59, 0xa2, 0x42, 0x5f, 0xfb, 0x19, 0x8f, - 0xb9, 0xfe, 0x72, 0xc3, 0x97, 0xfb, 0x9d, 0x78, 0x61, 0x9a, 0x39, 0x7f, - 0xf9, 0xc5, 0x7f, 0x02, 0x2f, 0x2e, 0xbc, 0x8e, 0x52, 0x1f, 0xf7, 0xe6, - 0x96, 0xfb, 0x24, 0xd7, 0xf1, 0x27, 0xa6, 0x80, 0x86, 0x05, 0xc9, 0xd3, - 0x97, 0xfe, 0x75, 0x26, 0x14, 0xf0, 0xc0, 0x0e, 0x54, 0x91, 0x3d, 0xca, - 0x57, 0x85, 0xaf, 0xfe, 0xea, 0x33, 0x35, 0xf3, 0x99, 0x67, 0x8e, 0x5f, - 0x4b, 0xaa, 0x68, 0xe5, 0x41, 0xf5, 0xe2, 0x3d, 0xf3, 0x57, 0xd8, 0x61, - 0xcb, 0xfb, 0xba, 0xd6, 0x6e, 0x73, 0x97, 0x43, 0x67, 0x2b, 0x0f, 0x19, - 0x0b, 0xef, 0x33, 0x8c, 0x8e, 0x5f, 0xfe, 0xec, 0x01, 0x8f, 0x2d, 0x7b, - 0x31, 0x87, 0x2d, 0xf6, 0x75, 0xf4, 0x00, 0xb7, 0xe4, 0x35, 0x92, 0x36, - 0x8d, 0x9f, 0x30, 0x9f, 0xac, 0x0f, 0x28, 0x74, 0x61, 0x39, 0xa2, 0x0f, - 0x36, 0xfe, 0x40, 0xa0, 0xfd, 0xff, 0xec, 0xe7, 0xe8, 0x7f, 0x7d, 0xcb, - 0xad, 0xb9, 0xcb, 0xff, 0xbe, 0xf5, 0xf4, 0x39, 0xef, 0x40, 0x0e, 0x5f, - 0xfe, 0xfa, 0xc7, 0x97, 0xdc, 0xda, 0xdd, 0xd6, 0x68, 0x9f, 0x14, 0xb6, - 0x4d, 0x5a, 0x20, 0xb5, 0xcf, 0xd4, 0xee, 0x1a, 0x6c, 0x4f, 0xea, 0x2d, - 0xff, 0xfd, 0xf8, 0xba, 0xbf, 0x3c, 0xac, 0x0c, 0xb3, 0xa8, 0xc3, 0x97, - 0x27, 0x27, 0x2f, 0xff, 0xa5, 0x3f, 0x0a, 0x86, 0xae, 0x75, 0xef, 0xe7, - 0xce, 0xb4, 0x39, 0x52, 0x3f, 0xc0, 0x0b, 0xdf, 0xfe, 0x19, 0xfb, 0x09, - 0xed, 0x20, 0xf3, 0x23, 0x97, 0xfe, 0xf2, 0xb0, 0x32, 0xce, 0xa3, 0x0e, - 0x5f, 0xf2, 0xb0, 0x32, 0xce, 0xa3, 0x0e, 0x5f, 0x7e, 0x2e, 0xaf, 0xc3, - 0xf6, 0xf1, 0xf5, 0xfb, 0x60, 0x4e, 0xc1, 0xca, 0x61, 0xf1, 0xfe, 0x79, - 0x7e, 0xcd, 0xe6, 0x4c, 0x72, 0xdf, 0x58, 0xa9, 0xa7, 0xb0, 0xda, 0x72, - 0x2d, 0x46, 0x46, 0xa1, 0x1d, 0xfb, 0x6b, 0x77, 0x59, 0xa2, 0xb2, 0x5f, - 0xf9, 0xe5, 0xf7, 0x36, 0xb7, 0x75, 0x9a, 0x26, 0xe5, 0xbe, 0xe2, 0x20, - 0x18, 0x69, 0x4b, 0x4c, 0x25, 0x21, 0xbf, 0x7c, 0xb7, 0x75, 0x9a, 0x25, - 0x65, 0xff, 0xf6, 0xe7, 0x18, 0xdb, 0x84, 0x5f, 0x71, 0xc4, 0xe5, 0x6c, - 0xff, 0xbf, 0x2e, 0xbf, 0x0c, 0x05, 0xfa, 0x72, 0xff, 0x42, 0x0c, 0x4a, - 0x38, 0x0e, 0x5f, 0xbe, 0xb1, 0xe5, 0xf7, 0x0f, 0xf1, 0x08, 0xf4, 0x4d, - 0x7f, 0xef, 0x67, 0xdc, 0xda, 0x4e, 0xec, 0x39, 0x7f, 0xf9, 0xa8, 0x6a, - 0xb8, 0x4d, 0x63, 0xc9, 0x33, 0x78, 0x72, 0xff, 0xc9, 0xaf, 0xd8, 0x29, - 0xc7, 0xf7, 0x39, 0x7f, 0x40, 0xba, 0xdd, 0xac, 0xe5, 0x48, 0xfb, 0xd8, - 0x83, 0x70, 0x76, 0x72, 0xfd, 0xb5, 0xbb, 0xac, 0xd1, 0x2e, 0x2f, 0xf9, - 0x1e, 0x5e, 0x18, 0x66, 0x8e, 0x5f, 0xa4, 0xd1, 0x3a, 0xe7, 0x2f, 0x43, - 0x48, 0x39, 0x79, 0x06, 0x0e, 0x54, 0x8f, 0x80, 0x25, 0x3c, 0x47, 0x6f, - 0xff, 0xcf, 0xe4, 0xfe, 0x42, 0x92, 0x8f, 0x0f, 0xf2, 0x39, 0x7f, 0x4b, - 0xb8, 0x38, 0xb3, 0x97, 0xa5, 0xdf, 0x1c, 0xbb, 0xb0, 0x87, 0x93, 0xd2, - 0xcb, 0xff, 0x85, 0x01, 0xad, 0xc2, 0x49, 0xf4, 0x72, 0xb0, 0xfb, 0x90, - 0xb2, 0xfe, 0xda, 0x30, 0x5e, 0x47, 0x2f, 0x3c, 0xbe, 0xb5, 0x35, 0x6a, - 0x71, 0x0c, 0x69, 0x11, 0x60, 0xbf, 0x4d, 0x1e, 0x12, 0xfa, 0x31, 0xf4, - 0x61, 0x9f, 0x90, 0x5f, 0xfb, 0xf6, 0x7d, 0xd4, 0x0f, 0xb3, 0x67, 0x2f, - 0xf8, 0x39, 0xf6, 0x36, 0x9d, 0xfc, 0xe5, 0xbe, 0xa2, 0xe5, 0xb3, 0x25, - 0xc9, 0xea, 0x14, 0xff, 0xa0, 0xdf, 0xfd, 0xf5, 0xe5, 0xf7, 0x36, 0xb7, - 0x75, 0x9a, 0x23, 0xb5, 0xff, 0x7b, 0xb9, 0x2f, 0xae, 0x3a, 0x39, 0x7f, - 0x70, 0xc3, 0x0b, 0xc1, 0x39, 0x77, 0xfd, 0x39, 0x7f, 0x70, 0x83, 0x9d, - 0x7f, 0x1c, 0xbf, 0xff, 0xbd, 0x24, 0x0f, 0x53, 0x8f, 0xcc, 0x0e, 0xd3, - 0xf5, 0x9c, 0xbf, 0xd8, 0xde, 0xa0, 0x7d, 0xa3, 0x97, 0xf0, 0x07, 0x39, - 0xf6, 0x1c, 0xbf, 0x3a, 0xbd, 0xc0, 0x1c, 0xbf, 0x84, 0x0f, 0xb7, 0x50, - 0xe5, 0x42, 0x20, 0xb6, 0x5a, 0xe5, 0x17, 0xfe, 0x4d, 0xfc, 0xd0, 0xe3, - 0x21, 0x67, 0x2f, 0xfd, 0x03, 0xff, 0x91, 0xf8, 0xbc, 0x8e, 0x5f, 0xf8, - 0x7f, 0x97, 0xcc, 0x41, 0x86, 0x1c, 0xbe, 0x5b, 0xba, 0xcd, 0x15, 0x0a, - 0xff, 0xb3, 0xb8, 0x2f, 0xbd, 0xa1, 0xca, 0x55, 0x32, 0x15, 0x9f, 0xa1, - 0xfe, 0xcf, 0xf4, 0x5d, 0x79, 0xad, 0xe0, 0xe5, 0xd2, 0xc3, 0x97, 0xfd, - 0x2f, 0x26, 0xdd, 0x68, 0x27, 0x2f, 0xa4, 0x0d, 0x61, 0xcb, 0xff, 0xce, - 0xcc, 0xd8, 0xe2, 0x71, 0x4d, 0xb9, 0xcb, 0xff, 0xba, 0x39, 0x37, 0xbb, - 0x9b, 0x4d, 0x1c, 0xbf, 0x72, 0x28, 0xc4, 0x39, 0x7e, 0x8e, 0x1a, 0x7c, - 0x6c, 0xe5, 0x42, 0x38, 0x71, 0x21, 0x11, 0x36, 0x4f, 0x7f, 0xa3, 0xcf, - 0xdf, 0x81, 0x83, 0x97, 0xfe, 0xcf, 0x6b, 0x79, 0x37, 0x51, 0x53, 0x97, - 0xfe, 0x1c, 0x57, 0x18, 0x8d, 0x21, 0x87, 0x2f, 0xfb, 0xe3, 0x8e, 0x70, - 0x7c, 0xef, 0xe7, 0x29, 0x11, 0x7e, 0xe8, 0x1f, 0x9f, 0xdf, 0xe9, 0x46, - 0xe7, 0x8d, 0xce, 0x72, 0xff, 0xda, 0xc1, 0xf6, 0xb2, 0x49, 0xd3, 0x97, - 0xf6, 0xb3, 0x88, 0xc7, 0x27, 0x2b, 0x47, 0xd9, 0xe3, 0xdb, 0xff, 0xe8, - 0x06, 0x0f, 0xc7, 0xf7, 0xce, 0xe0, 0x1c, 0xe5, 0xc3, 0x39, 0xca, 0x84, - 0xca, 0xf2, 0x14, 0x28, 0x44, 0x2a, 0x37, 0xf7, 0x17, 0x67, 0x5b, 0x73, - 0x97, 0xff, 0xf9, 0x23, 0xcf, 0xdf, 0xba, 0xee, 0x0f, 0xbe, 0x02, 0x5a, - 0x39, 0x48, 0x89, 0x41, 0x30, 0xbd, 0xaf, 0xf6, 0x72, 0xb0, 0xdf, 0xa1, - 0x0d, 0xf7, 0x7d, 0x93, 0x9c, 0xbf, 0x64, 0xee, 0x3c, 0x4e, 0x5f, 0xff, - 0xff, 0xe8, 0x97, 0xcf, 0x75, 0x23, 0x5f, 0x33, 0xf5, 0xc7, 0x1f, 0x99, - 0xbd, 0xe7, 0x1f, 0xdf, 0xa7, 0x2f, 0xba, 0x2f, 0xc0, 0x72, 0xb1, 0x30, - 0x91, 0x23, 0xd1, 0x4f, 0xa1, 0x33, 0x7f, 0xff, 0xdf, 0xbb, 0x5a, 0x4f, - 0xd7, 0x4f, 0x47, 0x53, 0xda, 0xc0, 0x9c, 0xb7, 0xde, 0x11, 0x94, 0x02, - 0xd5, 0x98, 0x70, 0xc3, 0x10, 0x63, 0x3b, 0x00, 0x61, 0x6b, 0x91, 0xa7, - 0xaa, 0x96, 0xb1, 0xee, 0x45, 0x90, 0xdf, 0x71, 0x81, 0xb0, 0xeb, 0xb0, - 0xf3, 0x18, 0xd6, 0xb5, 0x18, 0x97, 0xa3, 0x28, 0x68, 0x83, 0x7c, 0xb7, - 0x75, 0x9a, 0x2a, 0x85, 0xfe, 0xdc, 0x71, 0xe6, 0x59, 0xe3, 0x95, 0xb3, - 0xe4, 0xfc, 0xba, 0xff, 0xcf, 0x2f, 0xb9, 0xb5, 0xbb, 0xac, 0xd1, 0x35, - 0xaf, 0xa3, 0x71, 0xe3, 0x97, 0x3f, 0x8e, 0x50, 0x4d, 0xbb, 0x08, 0x6d, - 0xf7, 0x11, 0x8e, 0xc2, 0x37, 0x84, 0x1d, 0xfb, 0x6b, 0x77, 0x59, 0xa2, - 0xac, 0x5f, 0xf4, 0x4a, 0x37, 0x3c, 0x6e, 0x73, 0x96, 0xfb, 0x87, 0xdc, - 0x26, 0x97, 0xfd, 0xd8, 0xe7, 0xd1, 0xd7, 0x6b, 0x39, 0x7f, 0xf0, 0x30, - 0x7e, 0xc8, 0x1a, 0x9d, 0xc4, 0xe5, 0x7d, 0x44, 0x14, 0x1e, 0x5f, 0xfd, - 0xf5, 0xe5, 0xf7, 0x36, 0xb7, 0x75, 0x9a, 0x24, 0x45, 0xfb, 0x6b, 0x77, - 0x59, 0xa2, 0xd2, 0x5f, 0xf9, 0xe5, 0xf7, 0x36, 0xb7, 0x75, 0x9a, 0x27, - 0xd5, 0xbe, 0xe2, 0x20, 0x18, 0x69, 0x7f, 0xfb, 0xeb, 0x1e, 0x5f, 0x73, - 0x6b, 0x77, 0x59, 0xa2, 0x84, 0x5f, 0xfd, 0x8d, 0xfd, 0xf2, 0xaf, 0xa4, - 0xf4, 0x1c, 0xbf, 0x7b, 0xf5, 0xbe, 0x8e, 0x5f, 0x24, 0xf1, 0xb3, 0x94, - 0xc3, 0xcb, 0xe9, 0x4d, 0xfb, 0x6b, 0x77, 0x59, 0xa2, 0x8f, 0x5f, 0xf4, - 0x4a, 0x37, 0x3c, 0x6e, 0x73, 0x97, 0xff, 0xff, 0xf9, 0x44, 0xdc, 0xd1, - 0xdd, 0xe7, 0x5d, 0x4d, 0x62, 0xae, 0x20, 0x81, 0x89, 0xbb, 0x07, 0x2f, - 0xcf, 0xa4, 0xf4, 0x1c, 0xbf, 0xe8, 0x9a, 0x06, 0x26, 0xec, 0x1c, 0xa8, - 0x47, 0x6a, 0xb0, 0x8f, 0x12, 0x6b, 0xff, 0xfb, 0x03, 0xd8, 0x53, 0xef, - 0x85, 0xc1, 0xad, 0x40, 0x0a, 0x5e, 0x79, 0x7d, 0x85, 0x41, 0xd8, 0x44, - 0x26, 0x9e, 0x8c, 0x9d, 0xa1, 0xa5, 0xff, 0xd9, 0xdf, 0xbe, 0x55, 0xf4, - 0x9e, 0x83, 0x96, 0xfb, 0x3a, 0xb4, 0xa6, 0x4a, 0xa0, 0xf3, 0x25, 0x43, - 0x71, 0x49, 0x3c, 0xe8, 0x24, 0x95, 0x31, 0x51, 0x5a, 0x51, 0xda, 0xe5, - 0x31, 0x73, 0x0a, 0x94, 0x85, 0x54, 0xc4, 0x9d, 0x86, 0xa0, 0x0a, 0xbd, - 0x2e, 0x92, 0xff, 0x7d, 0xcd, 0xad, 0xdd, 0x66, 0x88, 0x89, 0x7f, 0x66, - 0xd6, 0xee, 0xb3, 0x44, 0x56, 0xbf, 0xe6, 0xbf, 0xb9, 0xb5, 0xbb, 0xac, - 0xd1, 0x5c, 0x2b, 0xea, 0x20, 0xdc, 0xe6, 0xff, 0xf0, 0x20, 0x57, 0xf5, - 0xfc, 0x05, 0x06, 0x47, 0x2f, 0xbe, 0xcf, 0x33, 0x59, 0xcb, 0x27, 0x27, - 0xec, 0x04, 0xcb, 0xec, 0xeb, 0xf8, 0xe5, 0xfe, 0xc4, 0xd8, 0x01, 0xfe, - 0x8e, 0x5b, 0x84, 0x13, 0xd5, 0xd1, 0x0d, 0xff, 0xfd, 0xed, 0x27, 0x5d, - 0x24, 0x83, 0xef, 0xfb, 0xbc, 0x39, 0x7e, 0xda, 0xdd, 0xd6, 0x68, 0xa7, - 0x97, 0xf9, 0x88, 0x1f, 0xdf, 0x72, 0x39, 0x73, 0x10, 0xe5, 0x41, 0xe5, - 0x2c, 0xd2, 0xff, 0xff, 0x4a, 0x3d, 0xaf, 0xd8, 0xb4, 0x04, 0x67, 0x53, - 0xf5, 0x9c, 0xbf, 0xff, 0xb7, 0xbf, 0xf7, 0xb8, 0x1c, 0x55, 0x3b, 0xdc, - 0x50, 0xe5, 0xff, 0xc9, 0x2c, 0x10, 0x43, 0x13, 0x72, 0x39, 0x7f, 0xa5, - 0x1b, 0x9e, 0x37, 0x39, 0xcb, 0xef, 0x82, 0xf2, 0x39, 0x7e, 0x7c, 0xea, - 0x30, 0xe5, 0x68, 0xf2, 0x78, 0x91, 0xd4, 0x22, 0x8b, 0x1f, 0xaf, 0xfb, - 0x8b, 0xb3, 0xe0, 0x7a, 0x8c, 0x39, 0x7f, 0xc3, 0x0c, 0x89, 0x0e, 0x30, - 0xe5, 0x61, 0xf9, 0xa1, 0xed, 0xff, 0x40, 0xaf, 0x38, 0xe7, 0xb4, 0x72, - 0xfc, 0xf3, 0xc6, 0xff, 0x39, 0x5c, 0x32, 0xbd, 0xe8, 0x2c, 0xc5, 0xa5, - 0xbf, 0x72, 0x42, 0x8c, 0x4e, 0xba, 0x30, 0xe4, 0xd4, 0x25, 0x38, 0x90, - 0x34, 0x39, 0xbf, 0xfc, 0xf2, 0xfa, 0x11, 0x76, 0xf5, 0xa8, 0x01, 0xcb, - 0xff, 0xc0, 0x07, 0xfa, 0xfa, 0xa0, 0xbb, 0x06, 0x0e, 0x5f, 0xfc, 0x38, - 0x07, 0x10, 0x7d, 0x62, 0x30, 0xe5, 0x6d, 0x12, 0x3e, 0x4d, 0xbf, 0xff, - 0xc8, 0x20, 0x1c, 0xf7, 0x73, 0xef, 0x5f, 0xbd, 0x49, 0x8e, 0x57, 0xd5, - 0x41, 0x41, 0x85, 0x4a, 0x43, 0x77, 0x44, 0x76, 0xc3, 0x97, 0xe1, 0x8f, - 0xf8, 0x7d, 0x1c, 0xbf, 0x95, 0xdb, 0x85, 0xc4, 0xe5, 0x04, 0xfa, 0xb0, - 0x41, 0xcb, 0x6f, 0xfe, 0x40, 0xed, 0xf9, 0xfb, 0xbd, 0xc4, 0xe7, 0x2b, - 0xe9, 0xfa, 0xf4, 0xb6, 0xe0, 0xc1, 0xcb, 0xff, 0xf7, 0x63, 0x79, 0x24, - 0x7f, 0x60, 0x53, 0xf5, 0x94, 0xbf, 0x44, 0x81, 0xfc, 0x8e, 0x5f, 0x2d, - 0xdd, 0x66, 0x8a, 0xcd, 0x53, 0x1e, 0xbe, 0xca, 0x6f, 0xbc, 0x8c, 0xd1, - 0xcb, 0xca, 0xe9, 0x53, 0x97, 0xf4, 0xec, 0x81, 0x96, 0x8e, 0x5f, 0x7b, - 0x4a, 0x68, 0xe5, 0x9c, 0xe5, 0x61, 0xb4, 0xd1, 0x25, 0xd3, 0xa1, 0xcb, - 0xfd, 0xa9, 0x90, 0x7b, 0x9c, 0x9c, 0xa8, 0x3c, 0xbc, 0x17, 0xbf, 0x78, - 0x0a, 0x0c, 0x8e, 0x5f, 0xff, 0x43, 0x3d, 0x98, 0x3e, 0xd7, 0x70, 0x0e, - 0x72, 0xf7, 0xef, 0xa3, 0x97, 0xfd, 0x92, 0x4f, 0xda, 0xda, 0xb0, 0x30, - 0xe5, 0x90, 0xe5, 0xfd, 0xdc, 0x11, 0x7f, 0x1c, 0xd1, 0x61, 0x7e, 0xc9, - 0xa7, 0xfc, 0x07, 0x2f, 0xef, 0x46, 0xc1, 0x13, 0x1c, 0xb7, 0xd8, 0x57, - 0x14, 0x11, 0x6c, 0x85, 0x5f, 0x24, 0x68, 0x45, 0xb1, 0xf6, 0x31, 0x75, - 0xad, 0xc8, 0x00, 0x52, 0x29, 0xba, 0x1d, 0xf2, 0x92, 0x87, 0x5c, 0x05, - 0x77, 0xfe, 0xea, 0x79, 0xf7, 0x3c, 0x20, 0x4e, 0x5f, 0xfb, 0xdf, 0xb3, - 0x17, 0xbe, 0x5d, 0xb3, 0x97, 0xfb, 0x70, 0xae, 0x0a, 0x2a, 0x72, 0xff, - 0xf4, 0x36, 0xa3, 0x07, 0x39, 0xf4, 0x63, 0x67, 0x2f, 0xde, 0x41, 0xc6, - 0x1c, 0xbe, 0x93, 0x8f, 0xdc, 0x4c, 0x97, 0x93, 0xed, 0xa1, 0x28, 0x67, - 0xc0, 0x99, 0x7f, 0xe7, 0x97, 0xdc, 0xda, 0xdd, 0xd6, 0x68, 0x91, 0x57, - 0xff, 0xef, 0x77, 0x07, 0xef, 0x9d, 0xf9, 0xd2, 0xaa, 0xb9, 0xcb, 0xff, - 0x3f, 0xbe, 0xc2, 0x6d, 0x3d, 0xf9, 0xca, 0xfa, 0x8e, 0x58, 0x4c, 0x75, - 0x9b, 0xfb, 0x36, 0xb7, 0x75, 0x9a, 0x2c, 0x95, 0xff, 0xef, 0x69, 0x4d, - 0x7d, 0xc9, 0xd0, 0x65, 0xa3, 0x95, 0xf5, 0x10, 0xf8, 0x73, 0x7f, 0x75, - 0x37, 0x12, 0xd1, 0xcb, 0xf9, 0x9e, 0x4e, 0xbb, 0x0e, 0x5f, 0xfe, 0x4f, - 0x77, 0x3d, 0x83, 0x1e, 0x80, 0x9c, 0xa8, 0x3f, 0x47, 0x2d, 0xbf, 0xe7, - 0x4f, 0x7f, 0xb7, 0xd7, 0xd5, 0xa3, 0x07, 0xb0, 0xa1, 0xbf, 0xb3, 0x6b, - 0x77, 0x59, 0xa2, 0xd8, 0x5f, 0xff, 0xdc, 0x27, 0x7e, 0x0e, 0x6f, 0xda, - 0xec, 0xdf, 0x3e, 0x75, 0xa1, 0xcb, 0xdb, 0xff, 0xa7, 0x2e, 0xf7, 0xd8, - 0x44, 0x4e, 0xda, 0xeb, 0xea, 0x3c, 0x92, 0x18, 0x57, 0xb3, 0x58, 0x72, - 0xf9, 0x6e, 0xeb, 0x34, 0x5b, 0x6b, 0xed, 0x4e, 0xfb, 0x39, 0x5b, 0x3d, - 0x1f, 0x17, 0x5f, 0xc9, 0xdf, 0x20, 0x3f, 0x39, 0x7f, 0xd1, 0x28, 0xdc, - 0xf1, 0xb9, 0xce, 0x5b, 0xec, 0x91, 0xed, 0x8d, 0x93, 0x11, 0x09, 0x75, - 0xff, 0xec, 0x10, 0x7d, 0x63, 0x87, 0x30, 0x55, 0x39, 0x7b, 0x86, 0xe8, - 0x4e, 0x5e, 0x9f, 0xa8, 0x72, 0xff, 0xdc, 0x37, 0x0d, 0xc2, 0xfe, 0xee, - 0x0c, 0x00, 0xe5, 0xe6, 0xa7, 0xc2, 0xcd, 0x4c, 0xe5, 0xfd, 0x03, 0x20, - 0xfe, 0xc3, 0x97, 0xfd, 0x9b, 0xdc, 0x49, 0xf9, 0x6c, 0xe5, 0xf2, 0xdd, - 0xd6, 0x68, 0xbc, 0x17, 0xef, 0x72, 0xb4, 0xd9, 0xcb, 0xff, 0x3f, 0xa3, - 0x8e, 0xf7, 0x9c, 0xe8, 0xe5, 0x6d, 0x13, 0x0c, 0x2e, 0x12, 0x9b, 0xef, - 0x34, 0xce, 0x9c, 0xbf, 0x32, 0x06, 0x4e, 0x72, 0xfe, 0x81, 0xf7, 0x17, - 0x59, 0xcb, 0xfa, 0x51, 0xc6, 0x37, 0xc9, 0xca, 0x91, 0xef, 0x61, 0x75, - 0xfe, 0x8f, 0x3f, 0x7e, 0x06, 0x0e, 0x5f, 0xf9, 0x46, 0x73, 0x2f, 0x60, - 0xfb, 0x47, 0x2e, 0xc5, 0x4e, 0x54, 0x1e, 0xc6, 0x20, 0xdf, 0x24, 0xf8, - 0xc3, 0x97, 0xec, 0x10, 0x70, 0x41, 0xcb, 0xf4, 0x29, 0xfb, 0xe8, 0xe5, - 0xff, 0xcc, 0x85, 0xfc, 0xc1, 0xfe, 0x59, 0xa3, 0x97, 0xff, 0xfe, 0x74, - 0xf3, 0xb1, 0xc4, 0x0b, 0xea, 0x6e, 0x4a, 0x4b, 0x04, 0xe5, 0xfd, 0x1c, - 0xf3, 0x27, 0xe4, 0xe5, 0x62, 0x38, 0x3a, 0x8d, 0xfb, 0x55, 0xff, 0xd9, - 0xde, 0xbc, 0x98, 0x91, 0xb9, 0x1c, 0xba, 0x00, 0x72, 0xa4, 0x7b, 0x3e, - 0x43, 0xae, 0x11, 0x75, 0x87, 0x86, 0x22, 0x6a, 0x63, 0xbc, 0x2c, 0x9f, - 0x39, 0x80, 0x4b, 0xb2, 0x1a, 0x5c, 0x97, 0xa1, 0x24, 0xd0, 0x84, 0x61, - 0x0f, 0x61, 0x18, 0xe4, 0x00, 0x22, 0x12, 0x9d, 0x46, 0x13, 0xe8, 0x44, - 0xdf, 0xee, 0x7e, 0xe0, 0x1f, 0x7a, 0x39, 0x7f, 0x81, 0xf6, 0x69, 0x40, - 0xf8, 0xe5, 0x7d, 0x4e, 0x16, 0x23, 0x19, 0xd9, 0xb5, 0xe4, 0xce, 0x4e, - 0x5f, 0x2d, 0xdd, 0x66, 0x8b, 0xd1, 0x7f, 0xe4, 0xf7, 0x45, 0xe4, 0x07, - 0x01, 0xca, 0xd9, 0xf5, 0xb0, 0xba, 0xf3, 0x13, 0xc7, 0x2f, 0xf9, 0xfd, - 0x28, 0x57, 0xc9, 0x39, 0xca, 0x61, 0xeb, 0x08, 0xe5, 0xfb, 0x19, 0xd7, - 0x09, 0xca, 0x0a, 0x68, 0xf9, 0x08, 0x75, 0x1e, 0x38, 0x08, 0x6f, 0xff, - 0xf7, 0x1c, 0x1f, 0xa1, 0xc0, 0xf7, 0x18, 0xc7, 0x96, 0x09, 0xcb, 0xfd, - 0xf7, 0xd9, 0x34, 0x9c, 0x27, 0x29, 0x11, 0x31, 0xd6, 0x2a, 0xfa, 0x98, - 0x06, 0x43, 0x7a, 0xa1, 0xbe, 0x08, 0x9e, 0x18, 0x92, 0x84, 0xd6, 0x4f, - 0x32, 0xae, 0x32, 0x94, 0x97, 0x5d, 0x34, 0xa0, 0x0d, 0xc6, 0x98, 0xc8, - 0x5b, 0xf6, 0x1c, 0xa0, 0x8d, 0x28, 0x63, 0x1f, 0xd2, 0x27, 0xf3, 0xe6, - 0x0d, 0xca, 0x7f, 0xbb, 0xfe, 0x9c, 0xbf, 0xfb, 0xf8, 0x98, 0x73, 0x8b, - 0xb1, 0x88, 0x72, 0xfb, 0x3a, 0xfe, 0x39, 0x7f, 0xb1, 0x36, 0x00, 0x7f, - 0xa3, 0x96, 0xe1, 0x15, 0x44, 0xd8, 0xa3, 0x68, 0x86, 0xfb, 0xd1, 0xcc, - 0xe7, 0x2f, 0xfb, 0xda, 0xce, 0x65, 0xdf, 0xd5, 0x39, 0x48, 0x7c, 0x22, - 0x49, 0x7d, 0x1c, 0x62, 0x47, 0x2f, 0xf7, 0xef, 0xb9, 0x0f, 0xee, 0x72, - 0xf3, 0xba, 0xcd, 0x11, 0x1a, 0xf9, 0x55, 0xbe, 0xce, 0x52, 0xcf, 0x2d, - 0x0a, 0x2f, 0xdc, 0x37, 0xb4, 0xe0, 0x39, 0x5b, 0x3c, 0xe6, 0x10, 0xdf, - 0xff, 0x77, 0xfd, 0x6b, 0x18, 0x39, 0xc7, 0xe4, 0x35, 0x07, 0x2f, 0xfa, - 0x27, 0xde, 0x7b, 0xc9, 0xe3, 0x97, 0x86, 0x39, 0x39, 0x52, 0x3d, 0x50, - 0x9c, 0xdf, 0xf6, 0x6f, 0x35, 0x8e, 0x33, 0x9c, 0xbd, 0x81, 0x61, 0xcb, - 0xff, 0xfd, 0xd7, 0x4f, 0x47, 0x47, 0x3d, 0xd4, 0xee, 0x23, 0x67, 0x2f, - 0xff, 0xff, 0x7b, 0xc8, 0xcd, 0xa6, 0x72, 0x3f, 0xfa, 0x3b, 0xf3, 0x8a, - 0x7a, 0x68, 0x39, 0x7f, 0xd8, 0xe2, 0x0d, 0xff, 0x00, 0x39, 0x50, 0x98, - 0x9e, 0x2f, 0x6d, 0xf6, 0xff, 0x3b, 0x33, 0x72, 0x86, 0x1c, 0xba, 0x76, - 0x14, 0xb9, 0xb6, 0xca, 0x5f, 0xfb, 0xea, 0xfa, 0x93, 0x76, 0x27, 0xfa, - 0x03, 0x62, 0xd8, 0xc5, 0xf7, 0x18, 0xf4, 0x1c, 0xa9, 0x1f, 0xfa, 0x2e, - 0x5f, 0xd8, 0xec, 0xce, 0x7c, 0x72, 0xff, 0xbf, 0x8e, 0xe4, 0xd2, 0x79, - 0xce, 0x5f, 0xdf, 0x74, 0x9b, 0x70, 0x1c, 0xac, 0x3e, 0xa7, 0x3b, 0xb3, - 0x59, 0xcb, 0xfe, 0x8c, 0xe6, 0x1e, 0x4f, 0x23, 0x94, 0xd5, 0x1e, 0x58, - 0x45, 0x2f, 0xc3, 0x9d, 0x7f, 0x1c, 0xbd, 0xf3, 0x4b, 0x39, 0x4d, 0x67, - 0x8b, 0xd2, 0x6b, 0xfc, 0x8e, 0x0d, 0xef, 0xfe, 0x9c, 0xbf, 0xa1, 0x5c, - 0x14, 0x54, 0xe5, 0xfd, 0x9e, 0xe0, 0xf6, 0x74, 0xe5, 0x62, 0x2d, 0xba, - 0x4a, 0x26, 0x9a, 0x2d, 0xbf, 0xff, 0x97, 0xf7, 0x6e, 0x29, 0xef, 0xbb, - 0x8f, 0x0b, 0x80, 0xe5, 0x35, 0x6c, 0x8a, 0x5e, 0x1a, 0x16, 0x71, 0x09, - 0xc9, 0x10, 0x04, 0x8f, 0x21, 0x9a, 0xb2, 0x2e, 0x61, 0x5c, 0x84, 0x53, - 0x1b, 0xee, 0x32, 0xfe, 0x97, 0xbc, 0x38, 0x80, 0x42, 0x30, 0x97, 0xd3, - 0x5f, 0xa3, 0x22, 0xe2, 0x77, 0x77, 0x07, 0x4e, 0x5f, 0xb6, 0xb7, 0x75, - 0x9a, 0x22, 0xe5, 0xfb, 0xc0, 0x50, 0x64, 0x52, 0xfd, 0xaf, 0x76, 0x00, - 0x72, 0xfc, 0xf3, 0xc6, 0xff, 0x39, 0x6f, 0xb3, 0xa3, 0x23, 0x06, 0x9c, - 0xd3, 0xf2, 0x96, 0x85, 0x15, 0xf5, 0x52, 0x34, 0xa3, 0xf2, 0xbf, 0xf9, - 0x8f, 0x2f, 0xb9, 0xb5, 0xbb, 0xac, 0xd1, 0x33, 0x2f, 0xee, 0x15, 0xc2, - 0xfc, 0x26, 0xa3, 0xc7, 0x2f, 0x73, 0x1a, 0x39, 0x79, 0x68, 0xc3, 0x97, - 0xdc, 0x37, 0x9c, 0x4e, 0x5c, 0xd1, 0xaa, 0x39, 0x76, 0x7e, 0x72, 0xff, - 0xe8, 0x63, 0xfb, 0x39, 0x03, 0x14, 0xe9, 0xcb, 0xff, 0xe8, 0x5e, 0xff, - 0x9f, 0x9d, 0x26, 0xd7, 0xdc, 0x39, 0x5d, 0x44, 0xc8, 0xa3, 0x5f, 0x24, - 0xff, 0x89, 0xcb, 0xf6, 0x4f, 0x80, 0x98, 0xe5, 0x7c, 0x3c, 0xcf, 0x11, - 0xdf, 0xef, 0x98, 0x2f, 0xb0, 0x34, 0x39, 0x7f, 0xfe, 0x63, 0xf7, 0x39, - 0x07, 0x5b, 0x7e, 0xcd, 0xdf, 0xce, 0x5f, 0xd9, 0xa8, 0x50, 0x60, 0xe5, - 0x05, 0x17, 0x98, 0x6d, 0xd5, 0xab, 0xb5, 0x87, 0x2e, 0xe0, 0xf1, 0xcb, - 0x70, 0xe7, 0x2c, 0x08, 0x36, 0x1f, 0x8d, 0x5f, 0xff, 0xf9, 0x06, 0x16, - 0x30, 0xcf, 0x91, 0xbd, 0xa7, 0x1d, 0xbb, 0x80, 0xe5, 0x35, 0x4a, 0xc9, - 0x16, 0x3c, 0x90, 0xb0, 0x99, 0xbb, 0xb0, 0xe0, 0x72, 0xf0, 0x23, 0x78, - 0x9e, 0xfe, 0x6e, 0x04, 0x73, 0xc7, 0x2f, 0x9f, 0xa9, 0x31, 0xcb, 0xee, - 0xcd, 0x01, 0x39, 0x58, 0x7e, 0x2b, 0x2c, 0x72, 0x2b, 0xf0, 0xc7, 0x9e, - 0x63, 0x97, 0xf9, 0x69, 0x82, 0x1e, 0xc1, 0xca, 0x39, 0x7c, 0xfe, 0x90, - 0x0e, 0x5f, 0xf6, 0x91, 0x6f, 0x9b, 0xcf, 0x1c, 0xbf, 0xcf, 0xb4, 0x86, - 0xb4, 0x61, 0xca, 0xea, 0x23, 0x7c, 0x45, 0xc4, 0xde, 0xff, 0xf7, 0xce, - 0xba, 0x78, 0x1f, 0x88, 0xbc, 0x8e, 0x5e, 0x6a, 0x6d, 0x57, 0x08, 0x72, - 0xa1, 0x39, 0xac, 0x27, 0x59, 0x8a, 0x42, 0x61, 0x86, 0x42, 0x97, 0x7f, - 0xff, 0xff, 0xff, 0xf9, 0xa9, 0xf0, 0x98, 0xd4, 0xf8, 0x6e, 0x17, 0xe1, - 0x75, 0xf0, 0xf1, 0xc2, 0xdc, 0x36, 0xe7, 0xe0, 0xcf, 0xc2, 0xd4, 0xa1, - 0xa7, 0x2a, 0x77, 0x86, 0x88, 0xe1, 0x9a, 0xf8, 0x57, 0xbe, 0x7c, 0xeb, - 0x43, 0x97, 0xff, 0xe0, 0x73, 0x2e, 0xff, 0x1b, 0xfb, 0xd4, 0x5b, 0xec, - 0xe5, 0xff, 0xdc, 0xb7, 0x1e, 0x0a, 0x35, 0xea, 0x18, 0x72, 0xf9, 0x07, - 0xda, 0x39, 0x7f, 0xff, 0xcc, 0x4d, 0xf7, 0xfd, 0x4a, 0x38, 0xee, 0x07, - 0xdd, 0xc9, 0x1c, 0xa9, 0x22, 0x29, 0x08, 0x6f, 0xfc, 0x9e, 0x45, 0xa0, - 0x7d, 0x8b, 0x39, 0x58, 0x99, 0x97, 0xa1, 0xa7, 0xc0, 0x45, 0x7d, 0xe6, - 0x99, 0xd3, 0x97, 0xff, 0xf9, 0xc5, 0x63, 0x81, 0xef, 0xff, 0x3b, 0x12, - 0xdc, 0x4e, 0x72, 0xb1, 0x10, 0xff, 0x92, 0x5f, 0xff, 0xe7, 0x54, 0x70, - 0x1f, 0xeb, 0xe4, 0x93, 0xb0, 0xb1, 0x73, 0x97, 0xde, 0x4e, 0xa1, 0xcb, - 0xfe, 0x7d, 0xcb, 0xe6, 0x2c, 0x38, 0x72, 0xb8, 0x65, 0xc5, 0xf8, 0x8c, - 0xd3, 0x23, 0x8c, 0xec, 0x2f, 0xdc, 0x8c, 0x58, 0xbf, 0x21, 0xb6, 0xce, - 0x5f, 0xde, 0xc6, 0x73, 0x8c, 0x39, 0x6e, 0xe1, 0xbf, 0x41, 0x1b, 0xfd, - 0xf8, 0x5e, 0x5a, 0x49, 0x1c, 0xbf, 0x2f, 0xf1, 0xf6, 0x8e, 0x5f, 0x44, - 0x9a, 0x36, 0x72, 0xff, 0xc3, 0x0b, 0x55, 0xf3, 0x68, 0x03, 0x97, 0xf6, - 0xb1, 0x37, 0xb7, 0x39, 0x53, 0x9f, 0x48, 0x0f, 0x6f, 0xff, 0x90, 0x67, - 0xcd, 0x23, 0xf7, 0xeb, 0x6d, 0xb6, 0x52, 0xa0, 0xfd, 0xc2, 0x47, 0x7f, - 0x73, 0x9d, 0xff, 0x90, 0x1c, 0xbf, 0x76, 0x27, 0xef, 0xe7, 0x2b, 0x0f, - 0x6f, 0xc6, 0x37, 0xfc, 0x39, 0x0a, 0xbf, 0x9d, 0x53, 0x97, 0xe9, 0x68, - 0x1f, 0xcc, 0x72, 0xf2, 0xff, 0x59, 0xca, 0xe4, 0xf2, 0x7f, 0x2b, 0xbf, - 0xe9, 0xf0, 0x01, 0xfd, 0xf7, 0x23, 0x97, 0xf3, 0xb8, 0x78, 0xe0, 0x4e, - 0x5e, 0x77, 0x59, 0xa2, 0xcf, 0x5f, 0xc0, 0x71, 0x92, 0x30, 0xe5, 0x4e, - 0x8b, 0xd0, 0x9d, 0xac, 0xb8, 0x05, 0x17, 0xfb, 0xbe, 0xd3, 0xf2, 0xa3, - 0x0e, 0x5f, 0xf7, 0x62, 0x49, 0xe8, 0xf6, 0x8e, 0x54, 0x1f, 0x72, 0x1b, - 0x5f, 0xfe, 0xdf, 0x5f, 0xe6, 0x71, 0x1c, 0xd6, 0x09, 0xcb, 0xfe, 0x84, - 0x0e, 0x31, 0xbc, 0xe9, 0xcb, 0xff, 0xb5, 0xe4, 0x99, 0xb7, 0x0c, 0x73, - 0xa3, 0x94, 0x88, 0xca, 0x74, 0xbf, 0xce, 0x2f, 0x36, 0xdb, 0x65, 0x2f, - 0xfc, 0xf2, 0xd0, 0xe2, 0xc3, 0x9b, 0x29, 0xf4, 0xd0, 0x5f, 0xb8, 0x3f, - 0x66, 0x04, 0xe5, 0xfe, 0xf7, 0x73, 0x8f, 0xc9, 0x30, 0xe5, 0x61, 0xf2, - 0x7e, 0x59, 0x7f, 0xee, 0x64, 0x3f, 0x83, 0xe2, 0xd8, 0x03, 0x97, 0x42, - 0xa7, 0x2f, 0xf8, 0x30, 0x30, 0x09, 0x75, 0x0e, 0x54, 0x22, 0x4a, 0x74, - 0x44, 0x17, 0xbf, 0xdd, 0x40, 0x8b, 0xbc, 0xc7, 0x2f, 0xf0, 0x7b, 0xfb, - 0x81, 0xa6, 0x1c, 0xa8, 0x3e, 0x84, 0x32, 0xbf, 0xd1, 0xf3, 0xd9, 0xad, - 0x41, 0xcb, 0xf8, 0x2a, 0x07, 0xff, 0x68, 0xe5, 0x93, 0x67, 0xca, 0x26, - 0x97, 0xa0, 0x55, 0x39, 0x52, 0x64, 0x18, 0x04, 0x97, 0x0d, 0x15, 0x29, - 0x5c, 0x60, 0xbc, 0xbe, 0x21, 0x0c, 0xd0, 0x81, 0xdc, 0x38, 0x59, 0x0a, - 0xce, 0xc3, 0xa8, 0x09, 0xe3, 0x0b, 0x3d, 0x42, 0xd3, 0xd0, 0x97, 0xe3, - 0x08, 0x55, 0x09, 0xae, 0x06, 0x8e, 0x5f, 0xf7, 0xfe, 0xd0, 0xe4, 0xd0, - 0xc3, 0x97, 0xc0, 0x76, 0xfc, 0x72, 0xff, 0x3b, 0x7d, 0x48, 0xdc, 0x1c, - 0xa0, 0xa2, 0x99, 0x51, 0x74, 0x3a, 0xd9, 0x1d, 0xff, 0xb6, 0x9a, 0x92, - 0x9d, 0x81, 0x83, 0x97, 0xdb, 0x48, 0x61, 0xcb, 0xff, 0xf7, 0x95, 0xfe, - 0x30, 0x3d, 0xcd, 0x73, 0x28, 0xe9, 0xca, 0xda, 0x2d, 0xd8, 0x7c, 0x24, - 0x37, 0x3c, 0x8e, 0x5f, 0xff, 0xff, 0xc2, 0xed, 0xfb, 0x3a, 0x39, 0xef, - 0xc0, 0xc7, 0x93, 0x86, 0x05, 0xf6, 0xf2, 0x39, 0x7f, 0xb3, 0xbd, 0xff, - 0xce, 0x27, 0x2f, 0xf9, 0x79, 0xd5, 0xbe, 0xde, 0x47, 0x2f, 0x24, 0xda, - 0x39, 0x50, 0x7a, 0xac, 0x38, 0xb2, 0x05, 0x34, 0x59, 0x85, 0xb7, 0x08, - 0x66, 0x42, 0x22, 0xfe, 0xf8, 0x9d, 0x76, 0x21, 0xcb, 0xdc, 0x70, 0x27, - 0x2d, 0xb9, 0xcf, 0x32, 0x62, 0xeb, 0xff, 0x63, 0x7c, 0x1b, 0xce, 0x01, - 0xfd, 0xb3, 0x95, 0x0a, 0x9f, 0xfb, 0x1b, 0xa3, 0xc2, 0x68, 0x4a, 0xaf, - 0xff, 0xff, 0x81, 0xac, 0xc1, 0x55, 0x4d, 0x8c, 0x67, 0x7e, 0xe8, 0x72, - 0x76, 0x63, 0x0e, 0x5f, 0x94, 0x81, 0x51, 0x87, 0x2b, 0x11, 0x51, 0xe7, - 0xfb, 0xf7, 0x17, 0xec, 0x28, 0x72, 0xff, 0xfb, 0xfe, 0x65, 0xa0, 0xf6, - 0x36, 0x17, 0x76, 0xce, 0x56, 0x22, 0x7d, 0x08, 0x84, 0xaa, 0xf6, 0xa2, - 0x73, 0x97, 0xfd, 0x18, 0xbe, 0xa7, 0x17, 0xd9, 0xcb, 0xb3, 0xa7, 0x28, - 0x4f, 0x3d, 0xa1, 0xcd, 0x49, 0x17, 0x9a, 0x2d, 0xf3, 0x65, 0xee, 0xfe, - 0xd9, 0xcb, 0xc0, 0xfd, 0x67, 0x2f, 0x7b, 0x14, 0x39, 0x7f, 0x47, 0x3a, - 0xf9, 0xb8, 0x39, 0x78, 0x3f, 0xac, 0xe5, 0xf0, 0x46, 0x24, 0x72, 0x90, - 0xdf, 0xb8, 0xf5, 0x05, 0x1d, 0x1c, 0x8f, 0xa0, 0xf3, 0x07, 0x7a, 0xdf, - 0x7f, 0x92, 0x67, 0x14, 0xe7, 0x47, 0x2e, 0xc5, 0x9c, 0xbf, 0xb6, 0x9c, - 0x70, 0x74, 0x72, 0xfe, 0xe7, 0xd9, 0xdf, 0xda, 0xce, 0x5f, 0xdb, 0xce, - 0xf7, 0xff, 0x1c, 0xbf, 0x74, 0x63, 0x36, 0x62, 0xfe, 0xcd, 0xcf, 0xfb, - 0x84, 0xd1, 0x06, 0xbe, 0x9a, 0x6b, 0x6e, 0x74, 0x51, 0xc9, 0x56, 0xf8, - 0x7b, 0x9c, 0x9c, 0xa8, 0x4c, 0x89, 0x21, 0xac, 0xe5, 0x57, 0xe7, 0x5a, - 0x32, 0x0e, 0x5f, 0xd2, 0xe8, 0xbf, 0x3e, 0x39, 0x4b, 0x3d, 0x41, 0x26, - 0xbe, 0x50, 0x5e, 0x73, 0x95, 0x87, 0x89, 0xa2, 0x1b, 0xf4, 0x7b, 0xe3, - 0x1b, 0x39, 0x7f, 0xa4, 0x8c, 0x8e, 0xa8, 0x13, 0x97, 0xff, 0xa3, 0x07, - 0x9f, 0x66, 0xd2, 0x77, 0x61, 0xcb, 0xf3, 0xb7, 0xec, 0xee, 0x8f, 0xf7, - 0xc6, 0x95, 0xf1, 0x5b, 0x63, 0x56, 0x67, 0x02, 0xd2, 0x8d, 0x43, 0x21, - 0x97, 0xb2, 0x11, 0x85, 0x45, 0xed, 0x64, 0x8e, 0x5d, 0x8a, 0x1c, 0xbe, - 0x07, 0x60, 0x27, 0x2f, 0xfa, 0x00, 0xc8, 0xc1, 0xf6, 0x8e, 0x52, 0x1e, - 0xcf, 0x48, 0xaf, 0xc9, 0xcc, 0x90, 0x4e, 0x5e, 0x4e, 0xe1, 0xcb, 0xa1, - 0x98, 0x78, 0x4b, 0x27, 0xbf, 0x9b, 0xc6, 0x46, 0xd5, 0x39, 0x7c, 0x1d, - 0x76, 0x0e, 0x5f, 0x87, 0x6d, 0xbc, 0xe7, 0x2a, 0x0f, 0xeb, 0x0b, 0xdc, - 0x8a, 0xfd, 0x9e, 0xd2, 0x30, 0xe5, 0xdf, 0x89, 0xca, 0x84, 0xff, 0xe4, - 0x39, 0x8e, 0x08, 0xc7, 0xb8, 0x53, 0x09, 0x66, 0x89, 0xef, 0x77, 0x04, - 0xe5, 0xe7, 0xf4, 0x1c, 0xbf, 0xd3, 0x44, 0xec, 0x79, 0xa0, 0xe5, 0xff, - 0xf3, 0xab, 0xe8, 0xd8, 0x37, 0x1e, 0x17, 0x01, 0xcb, 0xf8, 0x70, 0x18, - 0x32, 0x39, 0x7f, 0xfc, 0xaf, 0xc5, 0x05, 0xfd, 0xa4, 0xe7, 0xa8, 0xd9, - 0xcb, 0x0e, 0x22, 0x01, 0xca, 0xeb, 0x13, 0x60, 0xd8, 0xdb, 0x8d, 0x89, - 0xaf, 0xf0, 0xcf, 0xbb, 0x5c, 0x4e, 0x5c, 0x9e, 0x39, 0x7c, 0x82, 0xe1, - 0x39, 0x7f, 0xe6, 0x67, 0xb4, 0xa6, 0x9e, 0x58, 0x72, 0xfd, 0xa8, 0xdf, - 0xa0, 0xe7, 0xd3, 0x7f, 0x41, 0x44, 0xc6, 0x97, 0xef, 0xca, 0x4c, 0xef, - 0xb3, 0x97, 0xdd, 0xc4, 0xe2, 0x72, 0xfe, 0xd2, 0x6f, 0x3f, 0xd9, 0xcb, - 0xff, 0xfd, 0x13, 0x7c, 0x45, 0xff, 0xbd, 0x7f, 0xf1, 0x89, 0xee, 0xa1, - 0xca, 0xc4, 0xf3, 0x15, 0x19, 0x48, 0x57, 0x30, 0x8f, 0xa5, 0x3e, 0x23, - 0xe0, 0x2e, 0xb9, 0x9c, 0x21, 0xa2, 0xfc, 0x5f, 0x6b, 0x79, 0x87, 0x2f, - 0xfe, 0x97, 0xbf, 0x94, 0x99, 0xef, 0x43, 0x0e, 0x5f, 0xef, 0x6a, 0x27, - 0xcd, 0x04, 0xe5, 0xdd, 0xc3, 0x97, 0xff, 0xdd, 0x80, 0xe2, 0xfe, 0x60, - 0xe0, 0x7b, 0x07, 0x2f, 0xfe, 0x4c, 0x1c, 0xcd, 0x7c, 0x96, 0x98, 0x72, - 0xff, 0xcf, 0x1c, 0xcb, 0xe6, 0xb9, 0x0c, 0x1c, 0xa0, 0xa7, 0x0f, 0xc9, - 0x0a, 0x23, 0xb5, 0x9a, 0x4c, 0x2d, 0xa4, 0xff, 0x22, 0x5e, 0x56, 0x36, - 0x72, 0xfe, 0x0c, 0x03, 0x79, 0xc9, 0xca, 0xfa, 0x79, 0x6c, 0x1d, 0xbf, - 0xd0, 0xcc, 0x4d, 0xcd, 0x23, 0x97, 0x24, 0xc7, 0x2f, 0xf6, 0xe1, 0x50, - 0x8c, 0x72, 0x72, 0xff, 0xf7, 0xa3, 0xa2, 0xf3, 0xc6, 0xf6, 0xf2, 0x39, - 0x7b, 0xc9, 0x39, 0xcb, 0xf0, 0x1f, 0x98, 0x98, 0xe5, 0xe1, 0x85, 0x9c, - 0xbf, 0xf8, 0x29, 0x37, 0x63, 0x7c, 0xca, 0x36, 0x72, 0xff, 0xf2, 0x0b, - 0xf3, 0xad, 0x66, 0xc3, 0xdc, 0x39, 0x5f, 0x13, 0x84, 0x90, 0xba, 0x1a, - 0x31, 0x25, 0xc7, 0x44, 0xa7, 0x43, 0x7c, 0x08, 0xd6, 0x83, 0x97, 0xba, - 0x9e, 0x39, 0x6e, 0x38, 0x6b, 0x14, 0x10, 0xa8, 0x5d, 0x74, 0x0b, 0x66, - 0x47, 0x60, 0x90, 0xb4, 0xe9, 0x23, 0xc7, 0x6e, 0x08, 0x50, 0x5e, 0x63, - 0xa8, 0x72, 0xff, 0xb0, 0x64, 0x38, 0xc8, 0x59, 0xcb, 0xf7, 0x53, 0x8e, - 0x04, 0xe5, 0xff, 0x83, 0x03, 0x83, 0xfc, 0xb3, 0x47, 0x2f, 0xce, 0xc4, - 0xe0, 0xc3, 0x97, 0xf6, 0x75, 0xfc, 0xf3, 0x1c, 0xba, 0x39, 0x39, 0x5c, - 0x9e, 0x27, 0x8b, 0x6b, 0x11, 0x20, 0xed, 0xb7, 0xa1, 0x26, 0x39, 0x76, - 0xf0, 0xe5, 0xe1, 0x6a, 0xb8, 0x0e, 0x5f, 0xb2, 0x76, 0x46, 0x8e, 0x5f, - 0xff, 0xfa, 0x3a, 0x8c, 0xfb, 0x34, 0x9f, 0x6a, 0x75, 0x39, 0xd2, 0xd2, - 0x73, 0x95, 0x3a, 0xa5, 0xa0, 0x8e, 0xaa, 0x6c, 0x85, 0x33, 0x43, 0x37, - 0xa4, 0x20, 0x1c, 0x11, 0x6d, 0x12, 0x70, 0x14, 0x5e, 0x4e, 0xe8, 0xe5, - 0xf7, 0xc7, 0x93, 0x50, 0x72, 0xff, 0xec, 0xe3, 0x81, 0xc1, 0xfe, 0x59, - 0xa3, 0x97, 0xed, 0xc7, 0x54, 0x09, 0xca, 0xd9, 0xf7, 0x3a, 0x2d, 0xf4, - 0x24, 0xf0, 0x72, 0xf9, 0xb7, 0xcd, 0x1c, 0xbf, 0x83, 0x00, 0x1c, 0xe4, - 0xe5, 0xff, 0x49, 0x8f, 0x2f, 0x6a, 0x15, 0x39, 0x50, 0x88, 0x9c, 0x22, - 0x72, 0xdb, 0xda, 0x41, 0x39, 0x7e, 0x15, 0xfc, 0xd7, 0x27, 0x2f, 0xf2, - 0x92, 0x8e, 0x28, 0x20, 0x39, 0x58, 0x7f, 0x6e, 0x36, 0x25, 0x75, 0x8a, - 0x94, 0x9a, 0xc7, 0x1e, 0x12, 0xe0, 0x21, 0x18, 0x55, 0x7f, 0x0a, 0x8b, - 0xa7, 0x91, 0xcb, 0xc9, 0xd4, 0x39, 0x5c, 0x9b, 0x3f, 0x0c, 0x5f, 0x29, - 0xfb, 0xe8, 0xe5, 0xff, 0x22, 0xb0, 0x18, 0xe3, 0x9d, 0x39, 0x7f, 0xdd, - 0x46, 0xf9, 0x96, 0xb1, 0x67, 0x2f, 0xef, 0xf5, 0x13, 0x7f, 0xb3, 0x97, - 0xbf, 0xce, 0x4e, 0x57, 0x4f, 0x3f, 0xc6, 0x37, 0xfa, 0x5f, 0x8c, 0xfa, - 0x4e, 0x4e, 0x5f, 0x00, 0x19, 0xc9, 0xcb, 0xfb, 0x83, 0xd8, 0xe2, 0xb3, - 0x97, 0xfd, 0xfb, 0xc8, 0x39, 0x80, 0xd1, 0xcb, 0xfc, 0x04, 0xe7, 0x99, - 0x67, 0x8e, 0x57, 0x4f, 0xbb, 0x47, 0x37, 0xee, 0x74, 0xc4, 0x6b, 0x39, - 0x7f, 0xfe, 0xcd, 0x7c, 0xeb, 0xa7, 0x81, 0xf8, 0x8b, 0xc8, 0xe5, 0x42, - 0x20, 0x84, 0xb2, 0xfe, 0x79, 0xc0, 0xe2, 0x13, 0x95, 0x3a, 0xac, 0xe0, - 0x9d, 0x2e, 0x11, 0x53, 0x11, 0x6c, 0xdb, 0xa4, 0x7e, 0x84, 0xef, 0x18, - 0x52, 0x34, 0x21, 0xbf, 0xca, 0x42, 0xda, 0x66, 0xe0, 0xe5, 0xff, 0x07, - 0x3f, 0xdc, 0xeb, 0x49, 0xce, 0x5f, 0xd1, 0xd4, 0xdc, 0x30, 0xe5, 0x75, - 0x13, 0xae, 0x6b, 0xe3, 0xca, 0x85, 0xc5, 0x3c, 0x95, 0xe4, 0xf1, 0x99, - 0x5d, 0x37, 0xe7, 0x2c, 0xc3, 0x95, 0xc9, 0xaa, 0xe1, 0xc6, 0x6f, 0xf7, - 0x81, 0xf8, 0xe9, 0x02, 0x72, 0xfd, 0x20, 0x66, 0x04, 0xe5, 0xf4, 0x6f, - 0x38, 0xa1, 0xed, 0xb9, 0xa5, 0xff, 0xe9, 0x86, 0x3d, 0xaf, 0x72, 0xb4, - 0x19, 0xce, 0x5f, 0xcf, 0xcc, 0x86, 0x02, 0x72, 0xff, 0xa3, 0x99, 0x20, - 0xb1, 0xfc, 0x72, 0x91, 0x16, 0x2e, 0x98, 0x25, 0xb7, 0xe7, 0x96, 0x4f, - 0x07, 0x2f, 0xfe, 0x8d, 0x6b, 0x19, 0xe1, 0x86, 0x68, 0xe5, 0xff, 0xc9, - 0x1a, 0x17, 0x97, 0xcd, 0x66, 0xce, 0x5f, 0xff, 0xe4, 0xd4, 0xf8, 0xde, - 0x0f, 0xfc, 0x11, 0xf7, 0x05, 0xf6, 0x72, 0xff, 0x73, 0x2d, 0x4d, 0x28, - 0x9c, 0xe5, 0x05, 0x34, 0xa5, 0x93, 0x8a, 0x1f, 0x91, 0x3f, 0x65, 0xbf, - 0xff, 0xf7, 0x53, 0x9f, 0x67, 0x3e, 0xde, 0xe3, 0xc0, 0x50, 0x65, 0xdc, - 0x39, 0x7e, 0xec, 0x71, 0x0c, 0x1c, 0xbc, 0x17, 0x13, 0x97, 0xb7, 0x1c, - 0x4e, 0x5d, 0xfe, 0xce, 0x54, 0x8f, 0xe8, 0x25, 0x3b, 0x1b, 0xd0, 0xf5, - 0xff, 0xa5, 0x03, 0xed, 0xa7, 0x1c, 0x09, 0xcb, 0xff, 0x3f, 0xb5, 0xfc, - 0x94, 0x0a, 0x78, 0xe5, 0xff, 0x9f, 0xab, 0x47, 0xf9, 0xa7, 0xe9, 0xcb, - 0xfb, 0xae, 0x3c, 0xc9, 0x0e, 0x5f, 0xff, 0xb4, 0x3f, 0x3a, 0xe9, 0xe0, - 0x7e, 0x22, 0xf2, 0x39, 0x7f, 0xba, 0x8a, 0xb4, 0xff, 0x6a, 0x9c, 0xbf, - 0xe8, 0x6d, 0x9d, 0x84, 0x19, 0xce, 0x5f, 0xff, 0x0e, 0x6b, 0x19, 0x0b, - 0xcf, 0x26, 0xf0, 0xe5, 0xb1, 0x68, 0xbe, 0xf1, 0xcf, 0x13, 0x9b, 0xfa, - 0x7c, 0xda, 0x2e, 0x0e, 0x5f, 0x08, 0x61, 0x87, 0x2f, 0xff, 0xbf, 0x1f, - 0x6b, 0xa9, 0x30, 0xc3, 0x1e, 0x47, 0x2f, 0xb0, 0x7f, 0x73, 0x94, 0xc3, - 0xf1, 0xe2, 0xa1, 0x7f, 0x38, 0x30, 0x2f, 0x23, 0x95, 0x08, 0xe2, 0xc8, - 0x49, 0x21, 0x25, 0x22, 0x68, 0x3d, 0x8c, 0x3e, 0xa1, 0x7f, 0xce, 0x78, - 0x41, 0x06, 0x1d, 0x39, 0x1b, 0xba, 0xd2, 0xd2, 0x1d, 0x33, 0x1e, 0x30, - 0xff, 0xa8, 0x2e, 0x7e, 0x02, 0xd1, 0x8c, 0x53, 0xd1, 0xbc, 0x5f, 0xfd, - 0x82, 0x0c, 0xcd, 0xeb, 0xd1, 0x87, 0x2f, 0xfb, 0x9f, 0x66, 0xd2, 0x77, - 0x61, 0xcb, 0xd9, 0xc7, 0x0e, 0x5b, 0x00, 0x89, 0x81, 0x41, 0xd1, 0xd5, - 0xee, 0x1e, 0x48, 0x72, 0xfa, 0x05, 0xe4, 0x72, 0xfd, 0x8d, 0x6e, 0x20, - 0xf8, 0x78, 0x3b, 0x21, 0xbf, 0xb8, 0xf5, 0x23, 0x7a, 0x39, 0x7f, 0xee, - 0xa3, 0x03, 0x93, 0x46, 0x6c, 0xe5, 0xe9, 0x47, 0x27, 0x2f, 0xa0, 0x0e, - 0xc3, 0x97, 0x0c, 0xb0, 0xff, 0x26, 0x3e, 0x11, 0xdb, 0xed, 0x27, 0xa0, - 0xe5, 0x41, 0xed, 0x39, 0xcd, 0xf2, 0xfa, 0x93, 0x1c, 0xbf, 0xff, 0x0e, - 0x2a, 0xaa, 0x07, 0xa9, 0x37, 0x53, 0x9f, 0x1c, 0xa8, 0x3f, 0xbc, 0x23, - 0xbc, 0xb7, 0xd9, 0xcb, 0xf6, 0x97, 0x1b, 0x54, 0xe5, 0x74, 0xf1, 0x40, - 0x39, 0x7f, 0x4b, 0x10, 0x3d, 0x43, 0x97, 0x9f, 0x6a, 0x9c, 0xac, 0x3c, - 0x97, 0x2c, 0xbf, 0xfb, 0x39, 0xf6, 0x90, 0x60, 0x0e, 0xc3, 0x97, 0xa4, - 0xce, 0x9c, 0xa9, 0xcf, 0x83, 0xc8, 0x77, 0xf7, 0x3a, 0xc6, 0x43, 0x59, - 0xcb, 0xe4, 0x55, 0x1b, 0x39, 0x58, 0x7e, 0xee, 0x46, 0x26, 0x37, 0x7c, - 0xc3, 0x97, 0xda, 0x18, 0x61, 0xca, 0x83, 0x73, 0xc8, 0xc5, 0xee, 0xc9, - 0x87, 0x2e, 0xea, 0x1c, 0xac, 0x36, 0x7e, 0x1d, 0xa8, 0x5c, 0xf7, 0x93, - 0xae, 0x21, 0x2b, 0x18, 0x2f, 0x61, 0x36, 0xec, 0xa2, 0xd7, 0xa8, 0x7b, - 0xfe, 0xca, 0xd1, 0x52, 0xf0, 0x58, 0xb3, 0x96, 0xe9, 0xcb, 0x00, 0xe5, - 0xda, 0x91, 0xca, 0x01, 0xb9, 0xd0, 0x8f, 0xe2, 0x37, 0xf4, 0xf3, 0x4b, - 0x86, 0xdc, 0xe7, 0x2f, 0x3e, 0x6c, 0xe5, 0xe1, 0xcf, 0x1c, 0xae, 0x9b, - 0x61, 0x1b, 0xbb, 0xc2, 0x72, 0xf4, 0x73, 0xa3, 0x97, 0xc8, 0x32, 0xc3, - 0x97, 0xa7, 0x71, 0x39, 0x41, 0x3d, 0x96, 0x0e, 0xf8, 0x82, 0xfd, 0x9e, - 0xea, 0x78, 0xe5, 0xf9, 0xf9, 0xce, 0x7c, 0x72, 0xca, 0xf4, 0xf4, 0x3c, - 0x4f, 0x72, 0x6c, 0xe5, 0xfd, 0x3f, 0xc9, 0xdd, 0xfa, 0x72, 0x9a, 0xa4, - 0xfa, 0xe1, 0xb6, 0x44, 0x18, 0xde, 0x8f, 0xfd, 0x29, 0x71, 0x6b, 0xfe, - 0xc0, 0x85, 0x39, 0xce, 0x7c, 0x72, 0xf9, 0x63, 0x12, 0x39, 0x5d, 0x3d, - 0xb7, 0x3a, 0xbf, 0xd1, 0x9e, 0x8e, 0xb8, 0x4e, 0x54, 0xe7, 0xa4, 0x12, - 0x1b, 0xff, 0x83, 0x01, 0xdc, 0x79, 0x16, 0x81, 0x39, 0x7d, 0x34, 0x70, - 0x48, 0xe5, 0xfd, 0xe5, 0x84, 0x2c, 0xd9, 0xcb, 0xfe, 0x9b, 0x5c, 0x5c, - 0x67, 0xfc, 0x27, 0x2f, 0xb3, 0xd8, 0xc3, 0x97, 0x0a, 0xa7, 0x2d, 0xa7, - 0x37, 0x1f, 0x90, 0xdf, 0xdd, 0xfe, 0x79, 0xba, 0x87, 0x2f, 0x84, 0x73, - 0xc7, 0x2a, 0x13, 0xa9, 0x09, 0x1e, 0x21, 0xaa, 0x4c, 0x85, 0xf3, 0x3b, - 0x74, 0x9f, 0xc6, 0x37, 0xf7, 0xc9, 0xa3, 0xc3, 0xc4, 0xe5, 0xff, 0xe1, - 0x8e, 0x3b, 0x8d, 0xe2, 0x76, 0x02, 0x72, 0xf0, 0xbb, 0x0e, 0x54, 0x91, - 0x2d, 0x86, 0x48, 0x93, 0x6f, 0xad, 0x53, 0xe6, 0x5e, 0xb5, 0x68, 0x1c, - 0x2e, 0x3a, 0xd4, 0x87, 0x22, 0x5a, 0x54, 0xf0, 0xf2, 0x94, 0x78, 0xe1, - 0x9c, 0xb8, 0xca, 0x47, 0x4a, 0xb1, 0xe0, 0xae, 0x5b, 0x9f, 0x32, 0x92, - 0x92, 0x31, 0x89, 0xa5, 0xdb, 0x6e, 0x53, 0xcb, 0x23, 0xc6, 0xec, 0xfc, - 0x73, 0xca, 0xd3, 0x04, 0xae, 0x8e, 0x1e, 0x13, 0x83, 0x38, 0xeb, 0xaa, - 0x42, 0xd7, 0xa7, 0x98, 0xbf, 0x84, 0xf3, 0x6a, 0xcd, 0x25, 0x0d, 0x29, - 0x2a, 0xf3, 0x82, 0x30, 0x7a, 0xfa, 0xf9, 0xea, 0x9d, 0xbc, 0xd0, 0xfb, - 0xff, 0xdf, 0x58, 0xf2, 0xfb, 0x9b, 0x5b, 0xba, 0xcd, 0x13, 0x62, 0xff, - 0x7d, 0xcd, 0xad, 0xdd, 0x66, 0x8a, 0xb5, 0x7f, 0xa5, 0x2f, 0xfc, 0x31, - 0x23, 0x97, 0xd9, 0xd7, 0xf1, 0xcb, 0x70, 0x98, 0x7a, 0xa2, 0x69, 0x7f, - 0xd8, 0x38, 0xc8, 0x97, 0xfb, 0x39, 0x7f, 0xb7, 0x8b, 0x80, 0x28, 0xc3, - 0x97, 0xfb, 0xb1, 0x3e, 0xe3, 0x02, 0x72, 0xff, 0xfd, 0x13, 0xc6, 0xe1, - 0x91, 0x1e, 0xea, 0x01, 0x87, 0x2a, 0x11, 0x0f, 0xd3, 0x3a, 0x5a, 0x62, - 0xbb, 0x38, 0xec, 0x2e, 0xef, 0xd1, 0xb6, 0x74, 0x27, 0x2f, 0x07, 0x04, - 0xe5, 0xe7, 0x75, 0x9a, 0x2b, 0x45, 0xf9, 0x5e, 0x75, 0xff, 0x27, 0x29, - 0x67, 0xaa, 0x85, 0x17, 0xff, 0x93, 0xd2, 0x85, 0xf5, 0x3d, 0xa7, 0xe4, - 0xe5, 0x6c, 0xfa, 0xf8, 0x90, 0xdf, 0xfe, 0xea, 0x32, 0x17, 0x8c, 0xc1, - 0xf3, 0x43, 0x97, 0xff, 0xcb, 0x8d, 0xe0, 0x1d, 0x8f, 0x28, 0x45, 0x9c, - 0xbf, 0xfe, 0x96, 0xb0, 0x61, 0x8f, 0x9e, 0xf4, 0x30, 0xe5, 0xde, 0xf4, - 0x22, 0x69, 0xd3, 0x6f, 0xff, 0xff, 0x47, 0x14, 0xf6, 0xb1, 0x55, 0xf5, - 0x3d, 0x93, 0x0c, 0x32, 0x7c, 0x6c, 0xe5, 0xfe, 0x8f, 0x3f, 0x7e, 0x06, - 0x0e, 0x5f, 0x4b, 0xc9, 0x39, 0xcb, 0xf2, 0x9e, 0x18, 0x01, 0xca, 0xe4, - 0xf2, 0xf8, 0x91, 0xdf, 0xe7, 0x97, 0x92, 0x7e, 0xa1, 0xca, 0x83, 0xd8, - 0x42, 0x5b, 0xf6, 0x75, 0x31, 0x87, 0x2f, 0xc8, 0x06, 0x26, 0xce, 0x5f, - 0xfc, 0x2e, 0x8b, 0xeb, 0xff, 0x3e, 0xd0, 0xe5, 0x4e, 0x89, 0x10, 0x93, - 0x74, 0x9e, 0xff, 0x4a, 0x37, 0x3c, 0x6e, 0x73, 0x97, 0xd2, 0xde, 0x30, - 0xe5, 0xec, 0xd8, 0x0e, 0x5f, 0xa6, 0xc0, 0xb1, 0xac, 0xe5, 0xfc, 0x30, - 0xdf, 0x32, 0xd1, 0xca, 0xe5, 0x13, 0x28, 0x45, 0x30, 0xe7, 0x01, 0x65, - 0x42, 0x61, 0xf9, 0x0c, 0xeb, 0xff, 0xff, 0xfb, 0x11, 0x79, 0xe8, 0x1f, - 0x6b, 0xe4, 0x20, 0x71, 0x9f, 0x37, 0x09, 0x27, 0xd1, 0xcb, 0xfb, 0x3c, - 0xe2, 0x0f, 0xce, 0x5f, 0xdd, 0xf8, 0x93, 0xb8, 0x9c, 0xbf, 0xd0, 0xcd, - 0x04, 0x5d, 0xb3, 0x97, 0xce, 0x07, 0x09, 0xca, 0x92, 0x2c, 0x30, 0xb4, - 0x4b, 0xf4, 0x67, 0x6f, 0xbc, 0x33, 0x22, 0x2e, 0x23, 0x40, 0x9c, 0xd8, - 0x25, 0x19, 0x0d, 0xb5, 0x92, 0x24, 0x39, 0x36, 0x5a, 0xc7, 0xbe, 0xc3, - 0x5d, 0xe1, 0x62, 0x31, 0xa0, 0x68, 0x9f, 0xd1, 0x9c, 0x5f, 0xb6, 0xb7, - 0x75, 0x9a, 0x2c, 0x05, 0xf9, 0xd6, 0xa7, 0x66, 0x39, 0x6f, 0xb8, 0x7b, - 0xda, 0x34, 0xbf, 0x6d, 0x6e, 0xeb, 0x34, 0x4e, 0xab, 0xff, 0xfd, 0xd8, - 0x9c, 0x38, 0xcf, 0xba, 0xd6, 0x75, 0x35, 0xfc, 0xe7, 0x2f, 0xdf, 0x58, - 0xf2, 0xfb, 0x88, 0x9a, 0x98, 0xd2, 0xf2, 0xb0, 0xc3, 0x97, 0xce, 0xb5, - 0x18, 0x72, 0xf4, 0xb5, 0xf5, 0x53, 0xc0, 0xe2, 0x3b, 0x7e, 0xda, 0xdd, - 0xd6, 0x68, 0xb6, 0x57, 0xf7, 0x9f, 0xbf, 0x03, 0x07, 0x2f, 0xff, 0xe9, - 0x7d, 0xd4, 0x26, 0x05, 0x33, 0x59, 0xe1, 0x83, 0x95, 0x08, 0x88, 0x72, - 0xfb, 0xff, 0x02, 0x35, 0xf7, 0xa8, 0xb7, 0xd9, 0xcb, 0xfe, 0x89, 0x46, - 0xe7, 0x8d, 0xce, 0x72, 0xdf, 0x71, 0x35, 0x76, 0x42, 0xf1, 0xc8, 0x45, - 0x02, 0xff, 0xc3, 0xf5, 0x9f, 0xa7, 0x85, 0xf8, 0x0e, 0x5f, 0xfd, 0xfe, - 0xbe, 0xe6, 0xdf, 0x5d, 0x79, 0x1c, 0xb9, 0xc1, 0x88, 0x8a, 0x02, 0x1d, - 0xdc, 0xac, 0xe5, 0xf2, 0xdd, 0xd6, 0x68, 0xb9, 0x96, 0x61, 0xca, 0xd9, - 0xbf, 0x6c, 0xba, 0xff, 0x6c, 0x73, 0x90, 0x24, 0x8e, 0x5d, 0x33, 0x0e, - 0x51, 0xcb, 0x7d, 0x84, 0x67, 0xe2, 0xba, 0x11, 0x36, 0x66, 0xd0, 0x62, - 0xfd, 0xb5, 0xbb, 0xac, 0xd1, 0x77, 0xaf, 0xf4, 0xbe, 0xeb, 0x7b, 0x46, - 0xce, 0x5b, 0xee, 0x1f, 0x5b, 0x9a, 0x5f, 0x7d, 0x54, 0x20, 0x39, 0x50, - 0xfc, 0x06, 0x99, 0x79, 0xf0, 0x2b, 0x38, 0xe5, 0x69, 0x29, 0x24, 0x3b, - 0x8d, 0x41, 0x90, 0xc3, 0x78, 0x42, 0x02, 0x39, 0x01, 0x86, 0x96, 0xa1, - 0xf9, 0xe8, 0x5e, 0xa8, 0x51, 0x7f, 0xe6, 0xdc, 0x67, 0xd2, 0x0f, 0x32, - 0x39, 0x7f, 0xf6, 0x4f, 0x8d, 0xf7, 0x35, 0x88, 0x27, 0x2e, 0x4f, 0xbd, - 0x44, 0x18, 0xa0, 0x5f, 0xb5, 0xa6, 0x3c, 0x8e, 0x5f, 0xff, 0xff, 0xfb, - 0xa9, 0xd4, 0x81, 0xf0, 0xba, 0xb9, 0xef, 0xfc, 0x9e, 0xd7, 0x53, 0x71, - 0x3b, 0xed, 0x67, 0x2e, 0xd4, 0x1c, 0xbf, 0xfb, 0x95, 0xfe, 0xfc, 0xfb, - 0x30, 0x55, 0x39, 0x78, 0x5f, 0xec, 0x26, 0x3c, 0xb2, 0x8d, 0x42, 0x67, - 0xc2, 0xd7, 0xbf, 0x76, 0x1c, 0xbf, 0x67, 0x07, 0xa1, 0x53, 0x96, 0xe0, - 0x39, 0x53, 0x9b, 0xfc, 0x2b, 0xad, 0x9f, 0xe8, 0xae, 0x5f, 0xfb, 0x4e, - 0xaf, 0x52, 0x07, 0xf8, 0x39, 0x7f, 0xee, 0xbf, 0x9f, 0xbc, 0xcb, 0x3c, - 0x72, 0xb0, 0xff, 0x50, 0xfa, 0xe7, 0x01, 0xcb, 0xff, 0xff, 0xc2, 0xed, - 0x8e, 0x7b, 0xd9, 0x3c, 0x0b, 0xab, 0xa6, 0x46, 0x08, 0x4e, 0x5e, 0xc5, - 0x34, 0x72, 0xb1, 0x15, 0x1b, 0x16, 0xe0, 0x75, 0xbf, 0xdd, 0xc0, 0xa7, - 0x1d, 0xe1, 0xcb, 0xfc, 0xf2, 0xde, 0x34, 0x40, 0x1c, 0xbc, 0xee, 0xb3, - 0x44, 0xae, 0xbf, 0xca, 0xb8, 0x83, 0xd9, 0xd3, 0x94, 0xb3, 0xdb, 0x42, - 0x8b, 0xfd, 0xc8, 0xba, 0xaf, 0xe9, 0x1c, 0xbf, 0xfb, 0xb9, 0x25, 0xf5, - 0x03, 0x03, 0xe3, 0x94, 0x87, 0xef, 0xe3, 0x4a, 0x92, 0x6f, 0x81, 0x34, - 0xdc, 0x23, 0xc6, 0x13, 0x17, 0xff, 0xff, 0xdb, 0x71, 0x52, 0x01, 0x92, - 0xec, 0x71, 0x0c, 0x7d, 0xc1, 0xfe, 0x59, 0xa3, 0x97, 0x4a, 0x73, 0x97, - 0xff, 0xf9, 0xf9, 0xd6, 0x6f, 0xde, 0x79, 0xd4, 0x60, 0x7a, 0x8a, 0x9c, - 0xbf, 0xec, 0x4e, 0x23, 0x19, 0xb9, 0x1c, 0xbf, 0xff, 0x7a, 0x58, 0xd6, - 0xe2, 0x0e, 0x7d, 0xb8, 0xc6, 0xce, 0x36, 0x6e, 0x2f, 0xdc, 0xfb, 0xb0, - 0x03, 0x94, 0xe8, 0x93, 0xfd, 0xaa, 0xff, 0xf4, 0xc3, 0x1e, 0xd7, 0xb9, - 0x5a, 0x0c, 0xe7, 0x2f, 0xf9, 0xdb, 0x0f, 0x62, 0x7c, 0x6c, 0xe5, 0x22, - 0x21, 0xc5, 0x32, 0xff, 0xfd, 0x88, 0x0c, 0x62, 0x7b, 0x50, 0xc7, 0xe7, - 0xc7, 0x2f, 0xfa, 0x19, 0xec, 0x9a, 0x49, 0xe3, 0x95, 0x24, 0x46, 0xf9, - 0x52, 0xfb, 0xf7, 0xdc, 0x8e, 0x5f, 0xc3, 0x13, 0x81, 0xfc, 0x72, 0xff, - 0x38, 0x54, 0xe0, 0x81, 0x91, 0xcb, 0x42, 0xcf, 0x8d, 0x85, 0xb7, 0xff, - 0xf9, 0x3c, 0xec, 0x71, 0x07, 0x5b, 0x71, 0x9d, 0x69, 0x39, 0xca, 0x0a, - 0x61, 0xc9, 0x08, 0x67, 0x27, 0xbf, 0xef, 0xc0, 0xc7, 0x96, 0xb6, 0x13, - 0x97, 0xff, 0xfb, 0x10, 0x7d, 0x83, 0xf0, 0x5c, 0x30, 0x33, 0xc6, 0xce, - 0x5b, 0x3c, 0x89, 0x9e, 0x27, 0x77, 0xfd, 0xc8, 0x33, 0x79, 0x9e, 0xd1, - 0xca, 0x0a, 0xb0, 0xfc, 0x85, 0x77, 0x63, 0x31, 0x18, 0x66, 0xa8, 0x55, - 0x7f, 0xec, 0xef, 0x5e, 0x40, 0xde, 0x72, 0x72, 0xff, 0xb3, 0x9d, 0x06, - 0x1c, 0x67, 0x39, 0x7f, 0xcf, 0x2d, 0x76, 0x36, 0xa0, 0x4e, 0x54, 0x91, - 0x65, 0x87, 0xfe, 0x39, 0xbf, 0xfb, 0xc9, 0xc5, 0x3d, 0x34, 0xa0, 0x7c, - 0x72, 0xff, 0xf3, 0xe4, 0xbb, 0x88, 0x38, 0x06, 0x98, 0x72, 0xf3, 0xcb, - 0xec, 0x32, 0xa9, 0xa5, 0x09, 0xe0, 0xc3, 0x23, 0x23, 0xae, 0xda, 0x3b, - 0x21, 0x00, 0x01, 0x81, 0x8c, 0xc3, 0x52, 0xee, 0x7d, 0x18, 0x6a, 0x85, - 0xfc, 0x08, 0xd7, 0xff, 0xb3, 0xbf, 0x47, 0x02, 0x83, 0xec, 0xe9, 0xcb, - 0xde, 0x80, 0x94, 0xbf, 0xfd, 0xd7, 0x4f, 0x44, 0x93, 0x73, 0xfe, 0x02, - 0x97, 0xf9, 0xd7, 0xf4, 0x3b, 0xe1, 0xfe, 0xc1, 0xf3, 0xe8, 0x72, 0xdf, - 0x42, 0xce, 0xac, 0x5c, 0x69, 0xac, 0xa5, 0xbb, 0xfa, 0x1c, 0xbc, 0x61, - 0x61, 0x7f, 0xfb, 0xeb, 0x1e, 0x5f, 0x73, 0x6b, 0x77, 0x59, 0xa2, 0x61, - 0x5f, 0xff, 0xd9, 0xc5, 0xc3, 0xd8, 0xfb, 0xee, 0xe0, 0x7f, 0xf6, 0x8e, - 0x5f, 0xfe, 0xdb, 0x83, 0xea, 0xbe, 0x93, 0x71, 0xa9, 0x1c, 0xbb, 0x3e, - 0x8a, 0x2b, 0xd4, 0x60, 0xb9, 0x9c, 0x4e, 0x5f, 0xfd, 0xc2, 0x67, 0x32, - 0xfd, 0xfc, 0x31, 0x23, 0x97, 0xe6, 0xad, 0xab, 0x6a, 0x1a, 0x35, 0x47, - 0x2f, 0xd8, 0xcf, 0x9c, 0xb5, 0x9c, 0xbf, 0xa1, 0x98, 0x08, 0xe2, 0x72, - 0x82, 0x7b, 0x9d, 0x2e, 0xbf, 0xdb, 0xc5, 0xc0, 0x14, 0x61, 0xcb, 0xf7, - 0x60, 0x28, 0xa9, 0xca, 0x43, 0xfe, 0xd9, 0x17, 0x01, 0xa5, 0xfe, 0x87, - 0x9f, 0xca, 0xbe, 0xce, 0x5f, 0x9f, 0x72, 0x76, 0x1c, 0xa1, 0x3d, 0xbf, - 0xcd, 0x2f, 0xf6, 0xa3, 0x04, 0x3d, 0x83, 0x97, 0xf4, 0x60, 0x87, 0xb0, - 0x72, 0xf7, 0xfb, 0x9b, 0xe1, 0xee, 0x68, 0xc6, 0xff, 0xf6, 0xd3, 0xfc, - 0x57, 0x3d, 0xfc, 0x72, 0x13, 0x97, 0xff, 0xe4, 0xdf, 0x5f, 0xe0, 0x72, - 0x5d, 0x8e, 0x21, 0x83, 0x97, 0xfc, 0xda, 0x9d, 0x85, 0xf5, 0x26, 0x39, - 0x7d, 0xfb, 0x30, 0x27, 0x2d, 0x9c, 0x9e, 0xff, 0x01, 0xe5, 0xfd, 0x1b, - 0x89, 0x6b, 0x0e, 0x52, 0xd3, 0x93, 0xd9, 0xc7, 0x53, 0x46, 0x16, 0xfe, - 0x2b, 0xbf, 0xfd, 0x0b, 0xd7, 0xfe, 0x4e, 0xa2, 0xbd, 0x43, 0x97, 0xf3, - 0x23, 0x07, 0xcd, 0x0e, 0x5b, 0x47, 0x2f, 0xd1, 0x83, 0xe6, 0x87, 0x2f, - 0x69, 0xf9, 0xf8, 0x7c, 0xf3, 0x17, 0x30, 0x46, 0x98, 0x8f, 0x6f, 0x42, - 0xca, 0xff, 0x9a, 0xf0, 0x3d, 0x86, 0xb1, 0x83, 0x96, 0xea, 0x1f, 0x2b, - 0x94, 0x5f, 0xde, 0x86, 0x71, 0x04, 0x8e, 0x5d, 0xe4, 0x39, 0x52, 0x3c, - 0x65, 0x4c, 0x2f, 0xff, 0xf3, 0x7c, 0x1e, 0xce, 0xfc, 0x1c, 0x9d, 0x30, - 0x79, 0x96, 0x8e, 0x5f, 0x9b, 0xf6, 0x75, 0x67, 0x2c, 0x38, 0x89, 0x07, - 0x67, 0xbf, 0xfd, 0xe1, 0x70, 0x77, 0x10, 0x3f, 0xfb, 0x47, 0x2f, 0xfa, - 0x27, 0x52, 0x5d, 0xfd, 0xe7, 0x39, 0x50, 0x88, 0x7d, 0xa5, 0x5f, 0xfd, - 0x9c, 0xcb, 0xe7, 0x5d, 0x70, 0x21, 0x39, 0x7c, 0x91, 0xce, 0x8e, 0x5f, - 0x94, 0xf0, 0xc0, 0x0e, 0x57, 0x8f, 0x2b, 0x89, 0x15, 0xf7, 0xbd, 0x8d, - 0x9c, 0xbf, 0xfd, 0x1e, 0x04, 0x4b, 0x39, 0xf4, 0xff, 0xb6, 0x72, 0xf6, - 0x9c, 0x07, 0x2a, 0x11, 0x63, 0x84, 0x88, 0x47, 0xe4, 0xeb, 0x9e, 0x47, - 0x2f, 0xff, 0x26, 0xa2, 0x5f, 0x33, 0xa9, 0xbe, 0xb9, 0xca, 0x6b, 0x3e, - 0x0e, 0x8b, 0x5f, 0xce, 0x0d, 0xed, 0x36, 0x72, 0xf7, 0xbe, 0x61, 0xca, - 0x01, 0xe5, 0xa8, 0x5b, 0x7d, 0xdf, 0xf9, 0xf1, 0xcb, 0xff, 0x75, 0x3c, - 0x98, 0xc1, 0xc9, 0xce, 0x5f, 0xda, 0x45, 0x58, 0xfe, 0x39, 0x7f, 0xff, - 0xed, 0xe7, 0x18, 0x1f, 0x7c, 0x50, 0x63, 0xae, 0x9e, 0x8f, 0x68, 0xe5, - 0xfc, 0x39, 0xaf, 0x8b, 0xe1, 0x8e, 0x52, 0xd3, 0x0d, 0xe4, 0xf7, 0x65, - 0xdc, 0x5b, 0xaf, 0xbe, 0x71, 0xe0, 0x9c, 0xe5, 0x05, 0x39, 0xec, 0x8c, - 0xc9, 0x54, 0x1b, 0x35, 0x9c, 0xbf, 0x33, 0x78, 0x1f, 0x1c, 0xbb, 0xd8, - 0x72, 0xff, 0x83, 0x03, 0x00, 0x77, 0xe0, 0x39, 0x7f, 0xfb, 0x87, 0x18, - 0x63, 0xa7, 0x5f, 0xdd, 0x83, 0x95, 0x08, 0x9b, 0x41, 0x6f, 0xce, 0x6f, - 0xf7, 0x52, 0x67, 0x5e, 0xa4, 0x72, 0xfe, 0x1f, 0x3b, 0x13, 0xc7, 0x2f, - 0xfc, 0x9e, 0xff, 0x6f, 0xaf, 0x8c, 0xf1, 0xca, 0x83, 0xee, 0x72, 0xcb, - 0xfe, 0xc4, 0xc6, 0x0e, 0x4e, 0xe7, 0x2f, 0xd1, 0xed, 0x03, 0xf3, 0x94, - 0xd5, 0x2a, 0x27, 0x81, 0x4c, 0x86, 0x1a, 0xcb, 0xfb, 0x0a, 0x21, 0x20, - 0xf1, 0xb5, 0xff, 0xfb, 0xa3, 0x9e, 0xea, 0x67, 0x3e, 0xce, 0x31, 0xa3, - 0x97, 0xcf, 0xaf, 0x4e, 0x72, 0xff, 0xe7, 0x1e, 0xc2, 0x05, 0x35, 0x92, - 0x39, 0x7a, 0x00, 0xa1, 0xcb, 0xfb, 0x38, 0xf5, 0x01, 0x31, 0xca, 0xc4, - 0xc1, 0xd5, 0x56, 0x72, 0x31, 0x41, 0xd0, 0xed, 0xe5, 0x03, 0x87, 0x2f, - 0x70, 0xfa, 0xe1, 0x8e, 0x53, 0x9e, 0x26, 0x87, 0x6f, 0xbe, 0x33, 0xe2, - 0xce, 0x5e, 0xc5, 0x84, 0xe5, 0xf7, 0xb0, 0x40, 0x72, 0xfe, 0x76, 0xe3, - 0xd9, 0x39, 0xca, 0xc3, 0xeb, 0x41, 0xc1, 0x21, 0xbe, 0x6e, 0x6d, 0x41, - 0xcb, 0xff, 0x3f, 0xb4, 0x1d, 0xbf, 0xbb, 0xf9, 0xca, 0xe4, 0xf9, 0x04, - 0x92, 0xdf, 0x5a, 0xa6, 0xc6, 0x1b, 0x86, 0x19, 0x6a, 0x49, 0x51, 0x18, - 0xc8, 0x61, 0x19, 0x92, 0x84, 0x57, 0x1d, 0x57, 0x2d, 0x93, 0x42, 0xcf, - 0x70, 0xad, 0x61, 0x17, 0x63, 0x41, 0x78, 0x4d, 0x01, 0xc0, 0x63, 0xc1, - 0xd4, 0xa5, 0xef, 0x46, 0xf3, 0xfc, 0x23, 0x5b, 0x21, 0x69, 0x09, 0x25, - 0x21, 0x21, 0x7f, 0xfd, 0xb4, 0xe6, 0x5a, 0x4f, 0x76, 0x37, 0xe8, 0x39, - 0x7e, 0xda, 0xdd, 0xd6, 0x68, 0xab, 0x97, 0xb7, 0x0c, 0x39, 0x7f, 0xa3, - 0x7e, 0x81, 0x80, 0x1c, 0xbf, 0xe9, 0x7d, 0xcd, 0xad, 0xdd, 0x66, 0x88, - 0xf1, 0x7f, 0xd1, 0x28, 0xdc, 0xf1, 0xb9, 0xce, 0x5f, 0xfa, 0x3c, 0x9f, - 0xf0, 0xf9, 0x29, 0xe6, 0x39, 0x7f, 0xdc, 0xad, 0x35, 0xd4, 0xf2, 0x1c, - 0xbf, 0xdc, 0x0e, 0x18, 0xc0, 0xa1, 0xcb, 0x7d, 0x0a, 0xa0, 0x5c, 0x50, - 0xd9, 0xa7, 0x47, 0x1c, 0xc4, 0x51, 0xf4, 0x75, 0xe4, 0x6e, 0x03, 0x9b, - 0xf6, 0xd6, 0xee, 0xb3, 0x45, 0x82, 0xbc, 0xac, 0x4e, 0x72, 0xff, 0xfe, - 0x1f, 0xde, 0x76, 0x63, 0x4f, 0xf7, 0x9b, 0x92, 0x92, 0x39, 0x7e, 0xc1, - 0xcf, 0x68, 0xe5, 0xfe, 0xdb, 0xb1, 0x4d, 0xbf, 0x27, 0x2d, 0xf7, 0x13, - 0x0e, 0x54, 0xd1, 0x63, 0xce, 0xc2, 0xa1, 0x35, 0xfe, 0xfb, 0x9b, 0x5b, - 0xba, 0xcd, 0x16, 0x52, 0xfd, 0xb5, 0xbb, 0xac, 0xd1, 0x69, 0xaf, 0xf9, - 0xc3, 0xd7, 0x9b, 0xa8, 0xc3, 0x96, 0xfb, 0x87, 0xda, 0xc3, 0x4b, 0xf7, - 0x0b, 0xb5, 0x36, 0xa9, 0xaa, 0x6a, 0xce, 0x5f, 0xf7, 0x0d, 0xd4, 0x6c, - 0x2e, 0xeb, 0x39, 0x7e, 0xe1, 0x7e, 0x13, 0x59, 0x07, 0x2f, 0xf2, 0x8c, - 0xcf, 0x69, 0x34, 0x72, 0xc8, 0x72, 0xb8, 0x63, 0xc4, 0x68, 0x69, 0x7f, - 0xff, 0x27, 0x5c, 0x7d, 0x2c, 0xde, 0x40, 0x8e, 0x78, 0xe5, 0xfb, 0x8b, - 0x87, 0x18, 0x72, 0xf9, 0x91, 0xce, 0x8e, 0x5f, 0xfc, 0x98, 0xe0, 0x89, - 0x6e, 0x30, 0x4e, 0x5f, 0x27, 0x1e, 0xf1, 0x39, 0x52, 0x4c, 0x23, 0x15, - 0xa6, 0x29, 0x12, 0x3d, 0x20, 0x5f, 0xe6, 0x28, 0xc0, 0x31, 0x00, 0x72, - 0xfd, 0xf3, 0x7b, 0xff, 0xa7, 0x2f, 0xc8, 0xac, 0x0a, 0xce, 0x56, 0x8f, - 0x4f, 0xc5, 0x95, 0x08, 0xaa, 0xc8, 0x44, 0x5f, 0xff, 0x0a, 0xfa, 0x9d, - 0x4d, 0xc4, 0xcd, 0xe7, 0x4e, 0x5f, 0xf9, 0x8c, 0x79, 0x34, 0xff, 0xa9, - 0xb3, 0x97, 0xe7, 0xd7, 0xa0, 0x27, 0x2a, 0x0f, 0xa7, 0xf4, 0x2b, 0xfc, - 0xfb, 0x93, 0xf9, 0xd6, 0x72, 0xa1, 0x30, 0xde, 0xc2, 0xe7, 0xf2, 0x2b, - 0xe8, 0x52, 0x3a, 0x72, 0xf9, 0x6e, 0xeb, 0x34, 0x5b, 0x8b, 0xe9, 0xa0, - 0x38, 0x72, 0xff, 0xd9, 0xbc, 0x1f, 0x9d, 0xce, 0x5b, 0x39, 0x7e, 0x10, - 0x3f, 0x3a, 0x39, 0x50, 0x7d, 0x2e, 0x83, 0x5c, 0xa3, 0xef, 0x64, 0x4e, - 0x5d, 0xa8, 0x45, 0xdf, 0xe7, 0x10, 0x4c, 0x30, 0xc3, 0x97, 0x98, 0x28, - 0x72, 0xc2, 0x72, 0xff, 0xbb, 0xfb, 0xeb, 0x30, 0x55, 0x39, 0x7e, 0xd3, - 0xf2, 0xe1, 0x39, 0x64, 0x09, 0xf0, 0xf8, 0xe6, 0xa1, 0x16, 0x78, 0x37, - 0xd7, 0x1b, 0xfe, 0x87, 0x1e, 0xe6, 0x0a, 0xce, 0x5f, 0xef, 0x79, 0x27, - 0x64, 0x09, 0xca, 0x91, 0xf4, 0x61, 0xad, 0xff, 0x40, 0xfe, 0xc8, 0xd7, - 0x90, 0xe5, 0xe8, 0xcd, 0x9c, 0xbf, 0xdd, 0x89, 0x23, 0x4c, 0x61, 0xca, - 0x09, 0xe7, 0xe8, 0x6e, 0xfd, 0xf3, 0x9d, 0x22, 0xa7, 0x2c, 0xf3, 0x9e, - 0x77, 0x24, 0x57, 0xff, 0x4b, 0x3a, 0x9b, 0x0f, 0x60, 0x56, 0x72, 0xff, - 0x73, 0x28, 0x1f, 0x60, 0x0e, 0x5f, 0x68, 0x09, 0xe3, 0x94, 0xe8, 0xc1, - 0xd1, 0x4f, 0xe8, 0x6a, 0x19, 0xdf, 0x9f, 0x7e, 0xce, 0x9c, 0xbf, 0xf2, - 0x02, 0x24, 0x1e, 0xc0, 0xac, 0xe5, 0x48, 0xf9, 0x3c, 0x4f, 0x7f, 0x7a, - 0x59, 0xbc, 0xd1, 0xca, 0x39, 0x7b, 0xf7, 0xf1, 0xcb, 0xbf, 0x83, 0x95, - 0x23, 0x69, 0xe1, 0xda, 0x39, 0x7d, 0xca, 0xd3, 0x67, 0x2f, 0x43, 0x3e, - 0xe2, 0x23, 0xb9, 0x3f, 0x61, 0x0f, 0x82, 0xea, 0x13, 0x2d, 0xc2, 0x24, - 0x85, 0xdd, 0xe1, 0xf3, 0x43, 0x97, 0xbe, 0x35, 0x6d, 0x59, 0xcb, 0xfe, - 0x97, 0xdc, 0xda, 0xdd, 0xd6, 0x68, 0xa1, 0xd4, 0x88, 0x8e, 0x98, 0x79, - 0xca, 0x6f, 0xc0, 0x85, 0xe3, 0x0e, 0x5f, 0x44, 0xd8, 0x13, 0x95, 0xb3, - 0xc9, 0xd1, 0x3d, 0xff, 0x64, 0x07, 0xb1, 0xc1, 0x13, 0x1c, 0xbf, 0xc0, - 0x4e, 0xf7, 0x00, 0xe7, 0x29, 0x87, 0xda, 0x03, 0xba, 0x84, 0x58, 0xbc, - 0x23, 0xef, 0xfc, 0xe1, 0x80, 0xf5, 0x05, 0x18, 0x72, 0xff, 0xdc, 0x5f, - 0x7a, 0x7e, 0xea, 0x27, 0x39, 0x7f, 0xb5, 0xfa, 0xf3, 0xc3, 0x07, 0x29, - 0x88, 0xb0, 0xe9, 0xe7, 0x90, 0x6f, 0xfe, 0xfe, 0x5d, 0x7d, 0xf3, 0xe8, - 0x49, 0xce, 0x5f, 0xe9, 0x46, 0xe7, 0x8d, 0xce, 0x72, 0xfc, 0xfa, 0xe3, - 0x9a, 0x39, 0x50, 0x7b, 0xc0, 0x35, 0xbf, 0x7c, 0xee, 0x01, 0xce, 0x5f, - 0xe8, 0x93, 0xef, 0x39, 0xf1, 0xcb, 0xfe, 0xcf, 0x69, 0x4d, 0x6d, 0xf4, - 0x72, 0xfc, 0x9e, 0xd3, 0xa1, 0xcb, 0xfe, 0xd8, 0x36, 0xe3, 0xec, 0x01, - 0xca, 0x9d, 0x1e, 0x9b, 0x29, 0x61, 0x98, 0x0e, 0xbf, 0x26, 0xbc, 0xa6, - 0xe4, 0x72, 0xfe, 0x53, 0xdf, 0xc6, 0x4e, 0x72, 0xa4, 0x79, 0xd3, 0x0f, - 0x5f, 0xfc, 0xb1, 0x8f, 0x0e, 0x71, 0xcd, 0xc8, 0xe5, 0xff, 0x7e, 0x2a, - 0xa9, 0xde, 0xff, 0xa3, 0x97, 0xfc, 0xa4, 0x02, 0x69, 0x46, 0xe7, 0x39, - 0x7f, 0x0b, 0xf9, 0x48, 0x59, 0xca, 0x61, 0xf4, 0x89, 0xe5, 0xf0, 0x82, - 0x70, 0x1c, 0xac, 0x3c, 0x44, 0x21, 0xbf, 0xda, 0xf9, 0xef, 0x81, 0xc1, - 0x39, 0x60, 0x1c, 0xb2, 0x72, 0x79, 0x1b, 0x37, 0xbf, 0x3f, 0x3a, 0xf2, - 0x1c, 0xa8, 0x54, 0x15, 0x84, 0x68, 0x89, 0xd8, 0x75, 0x8b, 0x46, 0x8a, - 0x2f, 0xcf, 0xfa, 0xb0, 0xa1, 0xcb, 0xf7, 0x0d, 0x9b, 0x8d, 0x1c, 0xa9, - 0x8f, 0x58, 0x4a, 0xaf, 0xec, 0xf2, 0x07, 0x18, 0x72, 0xf8, 0x64, 0x8c, - 0x39, 0x6f, 0x93, 0x1e, 0x6b, 0x96, 0x5f, 0xed, 0x44, 0xdc, 0xcb, 0x38, - 0x9c, 0xa0, 0x9f, 0x0b, 0x95, 0x5f, 0xff, 0x83, 0xd8, 0x53, 0xef, 0x85, - 0xc1, 0xad, 0x40, 0x0a, 0x5c, 0x1c, 0x39, 0x7e, 0x9e, 0x27, 0x7d, 0x1c, - 0xac, 0x44, 0xba, 0x2c, 0x38, 0xb5, 0xc0, 0xfc, 0xe5, 0xfc, 0xe0, 0x98, - 0x60, 0x27, 0x2f, 0xf8, 0x72, 0x70, 0xf7, 0x07, 0xc7, 0x2a, 0x0f, 0xf7, - 0xa3, 0x02, 0x5b, 0x4d, 0x43, 0x6a, 0x46, 0xd5, 0xa2, 0xb5, 0x33, 0xee, - 0x14, 0xef, 0x11, 0x98, 0xca, 0x1e, 0x81, 0x8c, 0xcf, 0x23, 0x31, 0x55, - 0x09, 0x70, 0xe5, 0xe6, 0x12, 0xc8, 0x43, 0x34, 0x72, 0xdb, 0x8f, 0x3d, - 0x90, 0xc1, 0xec, 0x65, 0x2f, 0x0d, 0x60, 0x18, 0x0c, 0x29, 0x75, 0x18, - 0xaf, 0xa5, 0x52, 0x7f, 0x0b, 0x0e, 0x30, 0xd0, 0x69, 0x0b, 0x85, 0x21, - 0x55, 0x7f, 0xfe, 0x5f, 0xd0, 0x6f, 0x39, 0x5f, 0x53, 0xda, 0x7e, 0x4e, - 0x57, 0xd5, 0x45, 0x5f, 0xc7, 0xa1, 0x7d, 0x1b, 0x93, 0x0e, 0x5f, 0x73, - 0xa7, 0x6b, 0x39, 0x79, 0xf6, 0xa9, 0xcb, 0x7d, 0x9c, 0xf9, 0x50, 0x89, - 0xb2, 0x6b, 0xfd, 0xf7, 0x36, 0xb7, 0x75, 0x9a, 0x2f, 0x35, 0x43, 0xb1, - 0xd7, 0x93, 0x88, 0x63, 0x09, 0xca, 0xc6, 0xdb, 0x99, 0x71, 0xdb, 0x8e, - 0x59, 0x8a, 0x7d, 0x85, 0x70, 0xd6, 0xee, 0xda, 0x84, 0x9f, 0x13, 0x8b, - 0xfd, 0xf7, 0x36, 0xb7, 0x75, 0x9a, 0x29, 0x65, 0xfb, 0x6b, 0x77, 0x59, - 0xa2, 0xc2, 0x5f, 0xff, 0xa3, 0x04, 0x31, 0xd8, 0xe7, 0xd8, 0x2e, 0xc3, - 0x96, 0xd1, 0xcb, 0xfb, 0xfd, 0xa4, 0xee, 0xc3, 0x96, 0xfb, 0x88, 0xc6, - 0x61, 0xa6, 0x94, 0x9a, 0x08, 0xdf, 0xef, 0xb9, 0xb5, 0xbb, 0xac, 0xd1, - 0x65, 0xad, 0x23, 0x97, 0x6d, 0x53, 0x97, 0xdf, 0x55, 0xe1, 0x4d, 0x41, - 0xca, 0x29, 0x7b, 0xea, 0x8c, 0x39, 0x4b, 0x3d, 0xcd, 0x18, 0xfe, 0x17, - 0x4a, 0xa2, 0xd4, 0x44, 0x74, 0xe9, 0x74, 0x74, 0xe5, 0x80, 0x72, 0xe5, - 0x67, 0x39, 0x6d, 0xc8, 0xd5, 0x60, 0x8d, 0x2c, 0xf9, 0x9d, 0x02, 0xe4, - 0x01, 0xcb, 0xfe, 0x7e, 0x47, 0x39, 0xf4, 0x2a, 0x72, 0xff, 0x4f, 0xce, - 0xa0, 0x3e, 0x43, 0x97, 0xe8, 0xce, 0x31, 0xa3, 0x96, 0x87, 0x3d, 0xd6, - 0xcd, 0x69, 0xd1, 0x7c, 0x30, 0x97, 0xbe, 0x79, 0x48, 0x27, 0x2f, 0xe7, - 0xdc, 0x79, 0xfa, 0x72, 0xf3, 0x6d, 0xb6, 0x52, 0xff, 0xa2, 0x5c, 0xfb, - 0x71, 0x9c, 0x94, 0xfa, 0x68, 0x2f, 0xfb, 0xf7, 0xe7, 0x3c, 0x9c, 0xb6, - 0x72, 0xe8, 0xd1, 0xca, 0x0a, 0x61, 0x9d, 0x22, 0x14, 0xcd, 0x26, 0x71, - 0x3c, 0xbb, 0x85, 0x35, 0x07, 0x2f, 0xe4, 0x7d, 0x03, 0x5f, 0x9c, 0xbf, - 0xf9, 0x24, 0xfa, 0x71, 0xfd, 0x79, 0xa2, 0x97, 0xff, 0xf7, 0x53, 0xdd, - 0xcd, 0x0e, 0x33, 0xfd, 0x75, 0xe4, 0x72, 0xff, 0x44, 0xbc, 0xfd, 0x70, - 0x9c, 0xa8, 0x46, 0x86, 0x21, 0xed, 0x6e, 0xd2, 0x39, 0x69, 0x1c, 0xb4, - 0x8e, 0x54, 0x1b, 0x35, 0x44, 0x50, 0x46, 0xfe, 0xff, 0x5d, 0x79, 0x61, - 0xcb, 0xff, 0xed, 0x22, 0xf0, 0x77, 0x03, 0x81, 0xc5, 0x4e, 0x53, 0x0f, - 0xef, 0xc5, 0xd6, 0xe4, 0xe5, 0x95, 0x39, 0x6f, 0xce, 0x50, 0x9a, 0x4d, - 0x09, 0x56, 0x1f, 0xc6, 0x88, 0xbc, 0x6d, 0x76, 0x95, 0x39, 0x6c, 0x39, - 0x77, 0xe0, 0x83, 0x50, 0x11, 0x8b, 0x92, 0x0e, 0x5f, 0xc3, 0x0c, 0x18, - 0xc3, 0x97, 0x4a, 0x0e, 0x54, 0xe8, 0x82, 0x09, 0x6c, 0xc2, 0xbf, 0x95, - 0x5f, 0xff, 0xff, 0x76, 0x3d, 0xa4, 0xd6, 0xa3, 0xdd, 0x48, 0xd8, 0x18, - 0xf2, 0x97, 0x95, 0x39, 0x72, 0x72, 0x72, 0xe8, 0x61, 0xcb, 0xff, 0xf4, - 0x0f, 0xf2, 0x94, 0x7b, 0xb8, 0xc5, 0x20, 0x07, 0x2f, 0xff, 0x90, 0x7f, - 0x96, 0x6b, 0x70, 0x92, 0x7d, 0x14, 0xa9, 0x22, 0x93, 0xca, 0xd7, 0x2f, - 0xec, 0x32, 0x0d, 0x27, 0x84, 0xb4, 0x88, 0x43, 0x0d, 0x4c, 0x8c, 0xc9, - 0x54, 0xc5, 0x91, 0x6e, 0x1f, 0xce, 0xc2, 0x31, 0x90, 0x6a, 0x1b, 0x1e, - 0x40, 0xe2, 0xfc, 0xd0, 0x5d, 0x48, 0x5d, 0x5f, 0xfe, 0xfa, 0xc7, 0x97, - 0xdc, 0xda, 0xdd, 0xd6, 0x68, 0xa3, 0x17, 0xee, 0x31, 0xb8, 0x01, 0xcb, - 0xf0, 0xb8, 0x21, 0x43, 0x97, 0xfe, 0x4e, 0x65, 0xa1, 0xcf, 0x77, 0xf3, - 0x97, 0xfc, 0x9b, 0xee, 0x60, 0xcb, 0x47, 0x2d, 0xcc, 0x8f, 0xdd, 0x68, - 0x17, 0xfe, 0x79, 0x2f, 0xa8, 0xc8, 0xda, 0xa7, 0x2d, 0xf6, 0x13, 0x2f, - 0xe9, 0x4f, 0xa1, 0x3c, 0xd9, 0x4d, 0x49, 0x9a, 0xa3, 0xb8, 0xc1, 0xd8, - 0x8c, 0xf4, 0x92, 0xad, 0x46, 0x0d, 0xe8, 0xe2, 0x6f, 0xfe, 0xfa, 0xf2, - 0xfb, 0x9b, 0x5b, 0xba, 0xcd, 0x11, 0xca, 0xff, 0xf7, 0xd6, 0x3c, 0xbe, - 0xe6, 0xd6, 0xee, 0xb3, 0x44, 0xe4, 0xbf, 0xdf, 0x73, 0x6b, 0x77, 0x59, - 0xa2, 0xcc, 0x5f, 0xf4, 0xb4, 0xec, 0xfb, 0xdf, 0x00, 0xe5, 0xff, 0x70, - 0xb0, 0x71, 0x91, 0xcc, 0x30, 0xe5, 0xfe, 0xdc, 0x7b, 0xaf, 0xcc, 0x8e, - 0x5f, 0xff, 0xff, 0x44, 0xdd, 0x8f, 0x42, 0x89, 0xb9, 0xa3, 0xb9, 0xc7, - 0x3b, 0x81, 0xe3, 0x87, 0x28, 0x08, 0xb5, 0x13, 0x4b, 0xfe, 0xcd, 0x3f, - 0x80, 0xa0, 0xc8, 0xe5, 0xfe, 0xcd, 0x6f, 0x79, 0xce, 0x8e, 0x5e, 0xde, - 0x30, 0xe5, 0xf2, 0x0e, 0x68, 0xe5, 0xb3, 0xc6, 0xf3, 0x80, 0x72, 0xff, - 0xc8, 0x31, 0xa8, 0xf4, 0xf8, 0xd9, 0xcb, 0xfb, 0x6b, 0xeb, 0xa7, 0x0e, - 0x72, 0xfc, 0xe3, 0x1c, 0x7f, 0x39, 0x77, 0x2c, 0x39, 0x6f, 0xad, 0x42, - 0xa9, 0xa8, 0x87, 0xac, 0xe4, 0x52, 0x39, 0x0b, 0x83, 0x0a, 0x7f, 0x3e, - 0xe2, 0x64, 0xd0, 0xa6, 0xff, 0x7d, 0xcd, 0xad, 0xdd, 0x66, 0x8b, 0x75, - 0x7f, 0x0b, 0xfd, 0xdc, 0xfd, 0x39, 0x79, 0x39, 0x01, 0xcb, 0xff, 0xb6, - 0xeb, 0x07, 0xfa, 0xf4, 0x72, 0xd9, 0xcb, 0x85, 0x53, 0x97, 0xcb, 0x77, - 0x59, 0xa2, 0x90, 0x56, 0x1e, 0x2e, 0xc5, 0xef, 0xf4, 0xbc, 0x8d, 0xe8, - 0x08, 0x72, 0xff, 0xd9, 0xd4, 0xe3, 0xdc, 0xc1, 0x59, 0xcb, 0xcf, 0x2f, - 0xa1, 0x4c, 0x83, 0x21, 0x1b, 0xc9, 0x0e, 0x8d, 0x2f, 0xf2, 0x07, 0xff, - 0x69, 0x82, 0x72, 0xf3, 0x8c, 0x8e, 0x5b, 0xea, 0xd5, 0x09, 0x6c, 0xc1, - 0x91, 0x9e, 0xba, 0xb3, 0x66, 0x97, 0xff, 0x7d, 0x79, 0x7d, 0xcd, 0xad, - 0xdd, 0x66, 0x89, 0x49, 0x53, 0xaf, 0xae, 0xcc, 0xa8, 0xc5, 0xa7, 0x41, - 0x04, 0xad, 0x61, 0x84, 0xbf, 0xa5, 0x29, 0xf0, 0x2d, 0x5f, 0xe9, 0x20, - 0xfb, 0x10, 0x27, 0x2f, 0x6b, 0xf6, 0x1c, 0xb7, 0xde, 0x4f, 0x3d, 0x0c, - 0x6f, 0x0b, 0xc8, 0xe5, 0xfb, 0x6b, 0x77, 0x59, 0xa2, 0x76, 0x5f, 0xfd, - 0x9d, 0x17, 0x97, 0xe0, 0x63, 0xc8, 0xe5, 0xe7, 0x97, 0xdc, 0x3f, 0x81, - 0x34, 0xba, 0x76, 0xb3, 0x97, 0xff, 0xe4, 0x0f, 0xec, 0x8e, 0x07, 0x08, - 0xc0, 0xe2, 0xce, 0x5f, 0xe9, 0x46, 0xe7, 0x8d, 0xce, 0x72, 0xff, 0xdd, - 0x17, 0x97, 0xe0, 0x63, 0xc8, 0xe5, 0x41, 0xfa, 0x61, 0xad, 0xbe, 0xe2, - 0x79, 0x6c, 0x84, 0x9f, 0x4c, 0xdc, 0x6c, 0x61, 0x95, 0x7f, 0xfd, 0xf5, - 0x46, 0x8e, 0x20, 0xcf, 0x40, 0xa0, 0x0e, 0x5f, 0xfc, 0xec, 0xee, 0x2d, - 0xfb, 0x0a, 0x48, 0xe5, 0xe4, 0x0b, 0x9c, 0xbf, 0xf8, 0x73, 0xaf, 0x3e, - 0x68, 0x5f, 0x93, 0x97, 0x34, 0xfa, 0x14, 0x51, 0x75, 0x13, 0x43, 0x75, - 0x25, 0x70, 0x6c, 0x8f, 0xd7, 0x4b, 0x4d, 0x21, 0xe9, 0x7f, 0xff, 0x05, - 0xfd, 0xf7, 0x35, 0x03, 0xc8, 0x35, 0xa8, 0x01, 0xcb, 0xf6, 0xd6, 0xee, - 0xb3, 0x44, 0x58, 0xbf, 0xf3, 0xcb, 0xee, 0x6d, 0x6e, 0xeb, 0x34, 0x4b, - 0xab, 0xff, 0xfb, 0x03, 0xd8, 0x53, 0xef, 0x85, 0xc1, 0xad, 0x40, 0x0a, - 0x5b, 0xee, 0x23, 0x75, 0x86, 0x8d, 0x13, 0x2f, 0xfe, 0x63, 0xcb, 0xee, - 0x6d, 0x6e, 0xeb, 0x34, 0x4c, 0x4b, 0xff, 0xec, 0x5c, 0x7d, 0xeb, 0xa3, - 0x44, 0x06, 0x04, 0xe5, 0x7d, 0x45, 0x1f, 0x54, 0xaf, 0xdb, 0x5b, 0xba, - 0xcd, 0x15, 0x4a, 0xd8, 0x72, 0xb0, 0xf1, 0x15, 0x34, 0xbf, 0xf7, 0xef, - 0xb9, 0x0e, 0x36, 0xe0, 0x39, 0x7f, 0xf3, 0xeb, 0x68, 0xdf, 0xba, 0x9b, - 0x91, 0xcb, 0xfe, 0xdb, 0xf7, 0x99, 0x67, 0xbe, 0x85, 0x10, 0x9d, 0x3f, - 0xaf, 0xa8, 0xfa, 0x78, 0x53, 0x5f, 0xfe, 0xfa, 0xc7, 0x97, 0xdc, 0xda, - 0xdd, 0xd6, 0x68, 0x9d, 0x17, 0xf9, 0x1f, 0x71, 0x27, 0xe2, 0x72, 0xfd, - 0x34, 0x4d, 0x1a, 0x39, 0x7f, 0x37, 0x89, 0xc7, 0x04, 0xe5, 0x21, 0xeb, - 0xe8, 0xa6, 0xf2, 0x76, 0x0e, 0x7d, 0x34, 0x37, 0xff, 0x7f, 0xaf, 0x47, - 0x3f, 0x7f, 0x99, 0x18, 0x72, 0x98, 0x7f, 0x1d, 0x2d, 0xbf, 0xf3, 0xcb, - 0xee, 0x6d, 0x6e, 0xeb, 0x34, 0x4e, 0xeb, 0xf7, 0xbf, 0x76, 0x21, 0x4b, - 0xff, 0x0c, 0x7b, 0x35, 0x99, 0xcc, 0x8e, 0x50, 0x53, 0xf6, 0xc8, 0xc8, - 0xd8, 0x44, 0xe9, 0x9e, 0x28, 0xbf, 0xe0, 0xc4, 0xa3, 0xeb, 0x7a, 0x01, - 0xcb, 0xfa, 0x3e, 0x80, 0x70, 0x27, 0x2b, 0xea, 0x2e, 0x71, 0x3c, 0x4f, - 0x2f, 0xff, 0x7d, 0x63, 0xcb, 0xee, 0x6d, 0x6e, 0xeb, 0x34, 0x50, 0xab, - 0xff, 0xe7, 0xf4, 0xb0, 0x50, 0x3f, 0x75, 0x3c, 0x6c, 0xe5, 0xff, 0xff, - 0xee, 0xfe, 0xc6, 0x3c, 0xbe, 0xaf, 0xbf, 0xfa, 0x07, 0x27, 0x57, 0xf8, - 0x98, 0xe5, 0xfb, 0xfe, 0x7c, 0x8b, 0x39, 0x7e, 0xc0, 0x63, 0x89, 0xcb, - 0xed, 0x23, 0x7e, 0x39, 0x7a, 0x01, 0xf6, 0x73, 0xf2, 0x12, 0xaf, 0x12, - 0xd2, 0x26, 0x68, 0x30, 0xf2, 0xbf, 0xfd, 0xf5, 0x8f, 0x2f, 0xb9, 0xb5, - 0xbb, 0xac, 0xd1, 0x49, 0x2f, 0xff, 0xf6, 0x6b, 0xea, 0x99, 0x37, 0x5d, - 0x9e, 0xec, 0x7b, 0xf6, 0x1c, 0xa8, 0x64, 0xd0, 0xcf, 0x19, 0xd4, 0xa1, - 0xb8, 0xb8, 0xd8, 0xf6, 0x52, 0xc9, 0x61, 0x20, 0x30, 0x15, 0xaf, 0x47, - 0x0b, 0xf9, 0x3b, 0x45, 0xab, 0xfd, 0xf7, 0x36, 0xb7, 0x75, 0x9a, 0x22, - 0x45, 0xff, 0xef, 0xac, 0x79, 0x7d, 0xcd, 0xad, 0xdd, 0x66, 0x89, 0x79, - 0x79, 0xa8, 0x60, 0x0e, 0x5f, 0x6f, 0xff, 0x68, 0xe5, 0xfb, 0x60, 0x62, - 0x68, 0xe5, 0xe8, 0x1e, 0x4e, 0x5f, 0xbc, 0xa3, 0x06, 0x0e, 0x59, 0x3a, - 0x78, 0x82, 0x39, 0x7f, 0xfb, 0xbc, 0x60, 0x40, 0xd7, 0x81, 0xcd, 0xf2, - 0x72, 0xe8, 0xf1, 0xcb, 0xfe, 0x79, 0xf7, 0x1c, 0xc9, 0x18, 0x72, 0xff, - 0xf7, 0xe1, 0x4d, 0xa9, 0x37, 0x07, 0xee, 0x33, 0x1c, 0xa9, 0x26, 0x2e, - 0x84, 0xc0, 0x4f, 0x11, 0x6d, 0x1d, 0x5f, 0xc0, 0xec, 0x6d, 0x18, 0x72, - 0xff, 0xd3, 0x6a, 0x38, 0xbf, 0x63, 0x99, 0x8e, 0x54, 0x1f, 0x83, 0x96, - 0xdf, 0xb2, 0x7c, 0xd3, 0x0e, 0x5f, 0xcf, 0x3b, 0xe9, 0xc0, 0x72, 0xff, - 0xe9, 0xbe, 0x28, 0x31, 0xc5, 0xf8, 0xc4, 0xc7, 0x28, 0xe5, 0xfa, 0x4f, - 0xe7, 0xe2, 0x72, 0xfc, 0xfa, 0x8e, 0x38, 0x72, 0xa6, 0x3d, 0x1e, 0x25, - 0x35, 0x08, 0xcd, 0xc4, 0xc7, 0x5c, 0xbb, 0x70, 0x72, 0x82, 0xaf, 0x95, - 0x09, 0x26, 0x8e, 0x0f, 0x70, 0xb9, 0x12, 0x0f, 0x14, 0x71, 0x87, 0xd7, - 0x01, 0x6d, 0xd8, 0x27, 0x2f, 0xef, 0x9a, 0xee, 0x27, 0x8e, 0x50, 0x4f, - 0x11, 0x05, 0x6e, 0x0f, 0x27, 0x2f, 0xe1, 0xff, 0xd3, 0x42, 0xa7, 0x2f, - 0x70, 0xe9, 0xb3, 0x96, 0x47, 0x3d, 0x1f, 0xcc, 0x2f, 0xc3, 0x93, 0xa9, - 0xc4, 0xe5, 0xf6, 0x4e, 0xa7, 0x13, 0x97, 0xe0, 0xc7, 0x21, 0x7f, 0x87, - 0xa2, 0x25, 0x77, 0xff, 0xc9, 0xbf, 0x9d, 0x84, 0xf6, 0xbf, 0x5f, 0xf0, - 0x72, 0xf9, 0x27, 0x03, 0x59, 0xcb, 0xe5, 0xbb, 0xac, 0xd1, 0x4b, 0xaf, - 0x87, 0xd1, 0xb3, 0x97, 0xfd, 0x9b, 0x6b, 0xc0, 0xe6, 0xf9, 0x39, 0x48, - 0x7b, 0xbc, 0x48, 0x6a, 0x49, 0xb3, 0xaa, 0x81, 0x32, 0x9e, 0xc9, 0xbb, - 0x08, 0xbb, 0xf8, 0x3c, 0xc6, 0xd3, 0x93, 0x97, 0xde, 0x9f, 0x1b, 0x39, - 0x48, 0x7a, 0x62, 0x5f, 0x7e, 0x45, 0x77, 0x9a, 0x39, 0x7f, 0xe8, 0x18, - 0xef, 0xcf, 0xc7, 0xf5, 0x9c, 0xbd, 0xfb, 0xe8, 0xe5, 0xf4, 0xdf, 0xbc, - 0xc7, 0x2f, 0xd0, 0x07, 0xe7, 0x47, 0x2f, 0x0a, 0x00, 0xe5, 0xec, 0xf6, - 0x8e, 0x54, 0x1b, 0x7d, 0x0d, 0xd4, 0x93, 0x2a, 0x09, 0x44, 0xc8, 0x3d, - 0x1d, 0x01, 0x2f, 0x97, 0xef, 0xcd, 0x6e, 0x21, 0xe0, 0x39, 0x74, 0x72, - 0x72, 0xff, 0x81, 0xad, 0xc7, 0x32, 0x46, 0x1c, 0xbd, 0xe7, 0xe2, 0x72, - 0xfd, 0x3f, 0xf3, 0x43, 0x59, 0xcb, 0xef, 0xe6, 0x86, 0xb3, 0x97, 0x3c, - 0xff, 0x0f, 0x56, 0x72, 0xea, 0x84, 0x6f, 0x39, 0xd7, 0xee, 0x77, 0xfc, - 0x9a, 0x99, 0x07, 0xd0, 0x03, 0x97, 0xff, 0x0f, 0xb8, 0xc6, 0xf4, 0xe3, - 0x0d, 0x67, 0x2a, 0x48, 0xae, 0x61, 0x7e, 0x8e, 0x2f, 0xf4, 0x35, 0xea, - 0x18, 0xfe, 0x39, 0x73, 0x89, 0xcb, 0xfe, 0x80, 0x7c, 0xec, 0x31, 0xc4, - 0xe5, 0x72, 0x79, 0xdc, 0x45, 0x6a, 0x48, 0xa8, 0xdc, 0x20, 0xef, 0xe8, - 0x6d, 0x3b, 0xfb, 0x59, 0xcb, 0xfb, 0x99, 0x69, 0xc7, 0x93, 0x95, 0x0a, - 0xcc, 0x64, 0x5b, 0x91, 0xd1, 0xa4, 0x36, 0x36, 0x50, 0xa1, 0x95, 0xed, - 0xc3, 0x0e, 0x5f, 0xd0, 0x33, 0x79, 0x15, 0x39, 0x7f, 0xd2, 0xcd, 0xcd, - 0x83, 0x0c, 0x39, 0x7e, 0x04, 0x2f, 0x18, 0x72, 0xff, 0x64, 0xfa, 0x89, - 0xbf, 0xd9, 0xca, 0x44, 0x4a, 0xec, 0xe0, 0x49, 0xee, 0x96, 0x1c, 0xbe, - 0xd8, 0xc3, 0x0e, 0x5e, 0x80, 0x68, 0xe5, 0x42, 0x20, 0x42, 0x5d, 0x82, - 0xcd, 0x90, 0xdf, 0x3f, 0x5e, 0x73, 0x97, 0xee, 0xfe, 0xae, 0x09, 0xcb, - 0xfc, 0xd8, 0xbf, 0xa4, 0xe1, 0x39, 0x7f, 0xd1, 0xdd, 0x3f, 0xa3, 0x7c, - 0x07, 0x2f, 0xfc, 0xc7, 0x0a, 0x93, 0x4a, 0x07, 0x93, 0x94, 0x13, 0xfc, - 0x43, 0xbb, 0xed, 0x81, 0x4e, 0x27, 0x2f, 0x23, 0x7e, 0x39, 0x5d, 0x3c, - 0x3d, 0x13, 0x54, 0xe9, 0xc0, 0x04, 0x8b, 0x92, 0x9e, 0xc2, 0xbf, 0xcc, - 0x97, 0xf8, 0x7d, 0x9a, 0x47, 0xe9, 0xcb, 0xfe, 0x02, 0x77, 0x36, 0xf3, - 0x68, 0xe5, 0xff, 0xfa, 0x24, 0x31, 0x3a, 0x93, 0x6b, 0xb9, 0xc1, 0xb0, - 0x1c, 0xbf, 0xbe, 0x33, 0x3c, 0xfe, 0x39, 0x65, 0x9c, 0xbb, 0x9d, 0x61, - 0xe0, 0x39, 0x7d, 0xe8, 0x40, 0x9c, 0xa8, 0x4d, 0x37, 0x93, 0x16, 0x1c, - 0xbc, 0x26, 0xf4, 0x5b, 0x7f, 0xb1, 0xb9, 0x26, 0xbf, 0x61, 0xcb, 0xb8, - 0xe8, 0xe5, 0xfd, 0xfe, 0xa2, 0x6f, 0xf6, 0x72, 0xfd, 0x93, 0xe7, 0x74, - 0x72, 0xa0, 0xfc, 0xba, 0x32, 0x26, 0x37, 0xb3, 0x7a, 0x39, 0x4b, 0x3c, - 0x9e, 0x25, 0xb7, 0xfc, 0x08, 0x02, 0x9c, 0x60, 0x78, 0x0e, 0x54, 0x26, - 0xa5, 0x90, 0xf0, 0x42, 0x4b, 0xff, 0xff, 0xbb, 0x1b, 0xe5, 0x69, 0xcf, - 0xc5, 0x5f, 0xe6, 0xba, 0xeb, 0x81, 0x09, 0xcb, 0xe4, 0x55, 0xa6, 0x1c, - 0xbf, 0x94, 0xf4, 0x4e, 0x3c, 0x9c, 0xbc, 0x28, 0xc3, 0x95, 0xb3, 0xef, - 0x01, 0x27, 0x8c, 0x2f, 0xf0, 0xc3, 0x8f, 0xb0, 0x4e, 0x5f, 0xe8, 0xe7, - 0x4d, 0x71, 0xb5, 0x4e, 0x5f, 0xee, 0xbc, 0xc9, 0xb8, 0x9c, 0xe5, 0xd8, - 0xc3, 0x94, 0x14, 0xf1, 0xf2, 0x1c, 0xec, 0x2f, 0xe9, 0x7b, 0x9c, 0x71, - 0x34, 0xbf, 0x70, 0x23, 0x23, 0x47, 0x2f, 0xcf, 0xc7, 0x37, 0xa3, 0x94, - 0x13, 0xd3, 0x61, 0x55, 0xfb, 0xae, 0x28, 0xc3, 0x97, 0xca, 0xcd, 0xa8, - 0x39, 0x7f, 0x03, 0x90, 0x66, 0xf0, 0xe5, 0xfc, 0xb8, 0x4f, 0x24, 0x8e, - 0x5f, 0xce, 0x06, 0x46, 0x78, 0xe5, 0x42, 0x21, 0xb0, 0xb9, 0x0b, 0x2f, - 0xf3, 0x83, 0x51, 0xd8, 0xd1, 0xcb, 0xf7, 0x3e, 0xd6, 0x4e, 0x72, 0xec, - 0x9c, 0xe5, 0x39, 0xe0, 0x89, 0x55, 0x42, 0x76, 0x58, 0x44, 0x84, 0xdd, - 0x85, 0x50, 0x96, 0xe9, 0xce, 0xe0, 0x2c, 0xe5, 0xb4, 0x72, 0xe4, 0x57, - 0x46, 0xa3, 0xf1, 0x7b, 0xc0, 0x75, 0x9c, 0xbe, 0x6e, 0x6d, 0x41, 0xcb, - 0xfb, 0x42, 0xf3, 0xc7, 0x8e, 0x5f, 0xa7, 0x7d, 0x64, 0x8e, 0x5f, 0xff, - 0x07, 0x38, 0xbe, 0xe6, 0x52, 0x4f, 0xe7, 0x61, 0xca, 0x83, 0xfb, 0x42, - 0x8b, 0xf9, 0xf9, 0x03, 0x13, 0x47, 0x2a, 0x13, 0x36, 0xe4, 0x72, 0x62, - 0x4d, 0xc2, 0xa3, 0xa4, 0x17, 0xfb, 0xc8, 0xdb, 0xcd, 0x0c, 0x39, 0x6f, - 0xad, 0x5b, 0x74, 0x71, 0x13, 0x80, 0xf3, 0xc3, 0x2e, 0x44, 0x21, 0x69, - 0xc8, 0xf7, 0xf9, 0x85, 0x2a, 0x46, 0x95, 0x34, 0xb8, 0xad, 0xb1, 0x30, - 0x73, 0xb1, 0xa2, 0x3c, 0x77, 0x80, 0x8e, 0x7c, 0x63, 0xa1, 0xd4, 0x7f, - 0x5e, 0x94, 0xc4, 0xd2, 0x10, 0x2a, 0x46, 0xc9, 0xc0, 0xa3, 0x7f, 0xbe, - 0xe6, 0xd6, 0xee, 0xb3, 0x45, 0x38, 0xbf, 0xcc, 0x86, 0x67, 0x04, 0x78, - 0xe5, 0xff, 0x93, 0x6f, 0xae, 0xe6, 0x0a, 0xce, 0x5f, 0x99, 0xbd, 0xe6, - 0x8e, 0x5f, 0xff, 0xbb, 0xff, 0xb7, 0x1e, 0xd6, 0x2f, 0x51, 0xb5, 0x9c, - 0xbf, 0xed, 0x22, 0xb9, 0x28, 0x06, 0x8e, 0x5f, 0xff, 0xde, 0xc9, 0x85, - 0x35, 0xe8, 0x51, 0x37, 0x34, 0x74, 0xe5, 0xfe, 0x46, 0x06, 0x35, 0xf8, - 0x9c, 0xbf, 0x9f, 0x9d, 0x7c, 0xd2, 0x87, 0x2f, 0xec, 0xf7, 0x32, 0x86, - 0xce, 0x5f, 0xf9, 0x39, 0xd0, 0xe0, 0x7a, 0xed, 0x9c, 0xbf, 0xfe, 0xc9, - 0xf3, 0x9f, 0x69, 0x06, 0x00, 0xec, 0x39, 0x4a, 0xa2, 0x3b, 0x47, 0xf7, - 0xfe, 0xce, 0xc6, 0xf3, 0xeb, 0x6d, 0xb6, 0x52, 0xe4, 0x6c, 0xe5, 0xd3, - 0xfd, 0x85, 0x64, 0xa1, 0x35, 0xc3, 0xc5, 0x94, 0x72, 0xae, 0x87, 0x3d, - 0x5c, 0x01, 0x98, 0x99, 0x7a, 0x17, 0xad, 0x09, 0x38, 0x10, 0xef, 0xdb, - 0x5b, 0xba, 0xcd, 0x15, 0xe2, 0xff, 0xfe, 0xc0, 0xf6, 0x14, 0xfb, 0xe1, - 0x70, 0x6b, 0x50, 0x02, 0x96, 0xfb, 0x88, 0x91, 0x68, 0x69, 0x7f, 0xf7, - 0xd7, 0x97, 0xdc, 0xda, 0xdd, 0xd6, 0x68, 0x91, 0xd7, 0x97, 0x8c, 0x39, - 0x79, 0x01, 0x07, 0x2f, 0x2f, 0x18, 0x53, 0xe9, 0x77, 0x7e, 0xda, 0xdd, - 0xd6, 0x68, 0x92, 0x17, 0xff, 0xf4, 0x26, 0xd3, 0x82, 0x06, 0x78, 0xf2, - 0x75, 0xe7, 0x39, 0x7f, 0xf8, 0x70, 0x0d, 0x33, 0x71, 0x3b, 0xed, 0x67, - 0x2e, 0x97, 0xd8, 0x4c, 0x23, 0x0b, 0x7a, 0x69, 0xe5, 0xcb, 0xf6, 0x77, - 0xee, 0x30, 0xe5, 0xbe, 0xc2, 0x76, 0x4f, 0x19, 0xff, 0x92, 0xaf, 0xfe, - 0xfa, 0xf2, 0xfb, 0x9b, 0x5b, 0xba, 0xcd, 0x12, 0x52, 0xfd, 0xb5, 0xbb, - 0xac, 0xd1, 0x78, 0xaf, 0xfa, 0x5f, 0x73, 0x6b, 0x77, 0x59, 0xa2, 0x4d, - 0x5b, 0xee, 0x1f, 0xdb, 0x9a, 0x5f, 0xd1, 0xa4, 0x64, 0x4c, 0x72, 0xdd, - 0x39, 0x4c, 0x37, 0xcd, 0x96, 0xdf, 0x90, 0x1a, 0xc1, 0x39, 0x7f, 0xf2, - 0x7e, 0xbd, 0x69, 0xf7, 0xe8, 0x54, 0xe5, 0xf4, 0xbf, 0x8e, 0x4e, 0x5f, - 0xff, 0x7e, 0xfc, 0xe6, 0x2a, 0xab, 0xcb, 0x39, 0xf1, 0xca, 0x92, 0x38, - 0xc2, 0x4d, 0x32, 0x36, 0x89, 0x2f, 0xfc, 0x90, 0xce, 0xe0, 0x42, 0x9c, - 0x9c, 0xbd, 0x2e, 0x55, 0x39, 0x7f, 0xf3, 0x81, 0x7d, 0x4d, 0x8a, 0x7b, - 0x47, 0x2e, 0x19, 0xce, 0x50, 0x4f, 0xe5, 0xc7, 0xd4, 0x43, 0xbb, 0x7e, - 0x39, 0x7e, 0xf2, 0x76, 0x38, 0x9c, 0xb8, 0x67, 0x39, 0x50, 0x78, 0x13, - 0x14, 0xdc, 0xeb, 0x39, 0x7f, 0x2c, 0x3f, 0xce, 0xa3, 0x0e, 0x54, 0x1e, - 0x46, 0x0b, 0x58, 0x4e, 0x5c, 0xa2, 0x87, 0x28, 0x06, 0xa5, 0x41, 0x0b, - 0x9a, 0x7d, 0x85, 0x6a, 0xb9, 0x18, 0x2e, 0xcf, 0xbb, 0x0b, 0x77, 0x2f, - 0xd2, 0xbf, 0x9a, 0x94, 0x49, 0xa8, 0x75, 0x10, 0x93, 0xa0, 0xca, 0xba, - 0x92, 0x0c, 0x6f, 0x09, 0x2d, 0x9a, 0x68, 0xd3, 0x98, 0x59, 0xd9, 0x40, - 0xde, 0x3d, 0xfe, 0x19, 0xea, 0x4b, 0xbb, 0xa8, 0x9d, 0x48, 0x9d, 0x9e, - 0x58, 0x64, 0xa7, 0x9a, 0x03, 0x3c, 0xc9, 0x98, 0xb7, 0xab, 0x56, 0x7f, - 0x39, 0x77, 0xd8, 0xb3, 0xcd, 0x71, 0x20, 0x94, 0xcb, 0x86, 0xb9, 0x47, - 0xb3, 0x5b, 0xf0, 0xad, 0xda, 0xea, 0x86, 0x67, 0xc9, 0x8b, 0xda, 0x6e, - 0xfb, 0xde, 0x0c, 0x30, 0x29, 0x51, 0xbc, 0x3c, 0xbd, 0xc1, 0xae, 0x71, - 0xb5, 0x5f, 0x70, 0xfa, 0xfb, 0x10, 0x7f, 0xbc, 0x1f, 0x6e, 0x34, 0xe2, - 0x06, 0xe7, 0xf4, 0x9a, 0x4e, 0x2e, 0x29, 0x49, 0xed, 0xe0, 0xb5, 0x28, - 0x14, + 0x39, 0x72, 0x98, 0x72, 0xa7, 0x55, 0xd0, 0x18, 0xc4, 0xf4, 0x6b, 0xd4, + 0x51, 0x85, 0x67, 0x8b, 0xbf, 0x1f, 0x68, 0x68, 0xa0, 0xbd, 0xf9, 0x50, + 0x24, 0xdb, 0x39, 0x7d, 0xd4, 0x79, 0x1c, 0xbc, 0x17, 0x91, 0xca, 0x83, + 0x7b, 0x84, 0x36, 0xfe, 0x11, 0x0c, 0x06, 0x7b, 0xbd, 0xb3, 0x97, 0xe7, + 0x55, 0xb8, 0xd1, 0xca, 0x73, 0xc0, 0x11, 0x7b, 0xff, 0x91, 0x63, 0x8c, + 0x89, 0x83, 0x13, 0x9c, 0xbf, 0xe5, 0xe7, 0xa3, 0x8a, 0x08, 0x0e, 0x5f, + 0xff, 0xdf, 0xc7, 0xb7, 0x83, 0xf3, 0x50, 0x81, 0x17, 0x91, 0xcb, 0xf2, + 0xfb, 0xcb, 0xb5, 0x9c, 0xbf, 0xf9, 0x02, 0x3f, 0xfb, 0x70, 0x31, 0xb3, + 0x94, 0xb4, 0xd1, 0xd1, 0x10, 0x4e, 0x7f, 0x5b, 0xe2, 0x59, 0x7f, 0xe7, + 0xd6, 0x71, 0xc0, 0xe8, 0x5b, 0x39, 0x7f, 0xff, 0x27, 0xe3, 0x2c, 0x1f, + 0x23, 0x4c, 0xf0, 0xbc, 0x8e, 0x50, 0x11, 0x35, 0xe4, 0x0b, 0xff, 0xf8, + 0x73, 0x7f, 0xfc, 0xce, 0xb8, 0xe4, 0xd2, 0x8e, 0x4e, 0x5f, 0xb4, 0xb7, + 0x75, 0x9a, 0x20, 0x65, 0xfc, 0xf3, 0x81, 0xc4, 0x24, 0xac, 0x1e, 0xbd, + 0x9b, 0xff, 0x0f, 0xbd, 0xa1, 0xa5, 0xee, 0xbc, 0xbe, 0x26, 0x02, 0x30, + 0xcc, 0xbf, 0xee, 0xa6, 0x0e, 0x2c, 0x38, 0x72, 0x98, 0x9c, 0xaf, 0xa3, + 0x24, 0xe2, 0x77, 0x7b, 0xdf, 0xc1, 0xcb, 0xe0, 0x6b, 0x7b, 0x39, 0x7f, + 0x81, 0xe4, 0x9d, 0x90, 0xb3, 0x95, 0xc9, 0xfa, 0x38, 0xe8, 0x91, 0xdf, + 0x82, 0xd5, 0xb8, 0x5a, 0xb3, 0x97, 0xff, 0xe7, 0x96, 0xd0, 0x3f, 0x33, + 0x39, 0x03, 0x8f, 0x8e, 0x54, 0x2b, 0xde, 0xc9, 0x4f, 0x69, 0x0a, 0xd7, + 0x2e, 0xfc, 0xca, 0xe4, 0x91, 0xcb, 0xfb, 0x9f, 0x07, 0x31, 0x53, 0x94, + 0x13, 0xc5, 0xc1, 0x6b, 0xfb, 0x3d, 0x02, 0x80, 0x39, 0x7f, 0xb4, 0x2e, + 0xda, 0x9c, 0xb6, 0x72, 0xe0, 0x71, 0x39, 0x41, 0x3d, 0x0e, 0x9b, 0xde, + 0x7d, 0x4e, 0x68, 0xc1, 0x57, 0xfe, 0x7d, 0x60, 0x83, 0x7e, 0xdf, 0x27, + 0x2f, 0xff, 0xff, 0xec, 0xf7, 0x5c, 0x55, 0xf9, 0xbd, 0x3b, 0xfb, 0x8e, + 0x07, 0xe6, 0x31, 0xc7, 0x99, 0x1e, 0x20, 0xb5, 0xff, 0x9d, 0xd5, 0x5b, + 0x87, 0xe2, 0xad, 0x9e, 0x20, 0xb5, 0xff, 0xdd, 0x4e, 0xa4, 0x0f, 0xbe, + 0x2a, 0xd9, 0xe2, 0x0b, 0x5f, 0xe8, 0x41, 0xf7, 0xc5, 0x5b, 0x3c, 0x41, + 0x6b, 0xf9, 0x98, 0x1f, 0x8a, 0xb6, 0x78, 0x82, 0xd7, 0xff, 0xfc, 0xe2, + 0x28, 0xcf, 0x9b, 0x5f, 0x53, 0x48, 0xac, 0xf8, 0xd9, 0xe2, 0x0b, 0x5d, + 0xcf, 0xc0, 0xa7, 0x38, 0xb5, 0x0d, 0x2a, 0x3a, 0x18, 0x9f, 0xd4, 0x2a, + 0xce, 0xe9, 0xf8, 0xca, 0x37, 0xbf, 0xc9, 0x0a, 0xef, 0xdb, 0xe4, 0xe5, + 0xf3, 0xe8, 0x0e, 0x72, 0xff, 0xee, 0xa7, 0x52, 0x07, 0xdf, 0x15, 0x6c, + 0xf1, 0x05, 0xaf, 0xfa, 0x6d, 0xad, 0x27, 0xf8, 0xab, 0x67, 0x88, 0x2d, + 0x7e, 0xf6, 0xe1, 0x9f, 0x16, 0x8a, 0x15, 0x15, 0x2f, 0xff, 0x7c, 0x5f, + 0x51, 0x71, 0xed, 0xfc, 0x55, 0xb3, 0xc4, 0x16, 0xbf, 0xff, 0xf8, 0x45, + 0x19, 0xf3, 0xfc, 0xf9, 0xb5, 0xf5, 0x34, 0x8a, 0xcf, 0x8d, 0x9e, 0x20, + 0xb5, 0x62, 0x64, 0xdc, 0xa1, 0xba, 0xf5, 0xff, 0x75, 0x34, 0x8a, 0xcf, + 0x8d, 0x9e, 0x20, 0xb5, 0xff, 0xf3, 0xbf, 0x32, 0xdf, 0x50, 0x21, 0x8d, + 0x41, 0x4b, 0xff, 0x64, 0xa5, 0xfe, 0xf4, 0x33, 0xb4, 0x3c, 0x41, 0x6a, + 0x5a, 0x39, 0xf4, 0x91, 0xb4, 0xfb, 0xff, 0x2d, 0x35, 0xe7, 0x06, 0xfe, + 0x36, 0x78, 0x82, 0xd7, 0xf7, 0x53, 0xbd, 0x40, 0x1a, 0x00, 0xb5, 0xfb, + 0x01, 0xf1, 0x56, 0xcf, 0x10, 0x5a, 0xec, 0xf2, 0xcf, 0xcf, 0xa7, 0x55, + 0xca, 0x3b, 0xf7, 0x0c, 0x2b, 0xf9, 0x98, 0x1f, 0x8a, 0xb6, 0x78, 0x82, + 0xd7, 0xfe, 0x5f, 0x53, 0x48, 0xac, 0xf8, 0xd9, 0xe2, 0x0b, 0x5d, 0x9f, + 0x1d, 0x11, 0xbb, 0x3f, 0xbf, 0xdf, 0xa3, 0x1c, 0x79, 0x91, 0xe2, 0x0b, + 0x5f, 0xfb, 0x13, 0x8e, 0x0e, 0x05, 0xe4, 0x78, 0x82, 0xcc, 0x3c, 0x1a, + 0x0a, 0xf0, 0x5e, 0x8d, 0xc0, 0x6a, 0x31, 0xf4, 0x6e, 0x31, 0x7f, 0x46, + 0x3f, 0xfc, 0x2d, 0x9b, 0x70, 0xb8, 0x10, 0x68, 0x82, 0xdf, 0x51, 0x19, + 0x73, 0xac, 0xe5, 0xb6, 0xb6, 0x4e, 0xe0, 0x29, 0x31, 0xfe, 0x37, 0xba, + 0x5c, 0x07, 0x2f, 0x44, 0xb8, 0x0e, 0x54, 0x1b, 0x91, 0x1a, 0xa9, 0xd9, + 0x66, 0xa1, 0x21, 0xe5, 0xec, 0x14, 0x9f, 0xe1, 0x7c, 0xbf, 0xfb, 0x24, + 0x39, 0xee, 0xa6, 0x73, 0xe3, 0x97, 0xfa, 0x3a, 0x8d, 0xf3, 0x2d, 0x9c, + 0xbf, 0x47, 0xb7, 0xd4, 0x39, 0x7f, 0xdc, 0x8e, 0x23, 0x30, 0x40, 0x72, + 0xff, 0xdb, 0x9a, 0x5f, 0x86, 0x69, 0x7e, 0x13, 0x95, 0x3a, 0x36, 0x24, + 0x6b, 0x84, 0xfe, 0x37, 0xbf, 0xfa, 0x39, 0x92, 0x8c, 0xdf, 0xa3, 0x96, + 0xce, 0x5f, 0xa5, 0xc1, 0xc1, 0xfc, 0xe7, 0x2d, 0xd4, 0x3f, 0xa7, 0x49, + 0xbf, 0x6a, 0x39, 0x96, 0xce, 0x54, 0x8f, 0x3f, 0x44, 0xd7, 0x98, 0xfe, + 0x39, 0x7f, 0xef, 0xf6, 0xd3, 0x34, 0x06, 0x26, 0xce, 0x5f, 0xfd, 0xc7, + 0x8c, 0x6d, 0xfb, 0xcc, 0xb3, 0xc7, 0x28, 0x08, 0x8b, 0x51, 0x0a, 0xff, + 0x03, 0xff, 0x0c, 0x7b, 0x67, 0x2a, 0x48, 0xff, 0x04, 0x29, 0xf6, 0x49, + 0x50, 0xa9, 0x73, 0x23, 0x06, 0x78, 0xc8, 0x6f, 0xe7, 0x94, 0x71, 0x7e, + 0x9c, 0xbf, 0xfb, 0x39, 0xf6, 0xd0, 0x60, 0x0e, 0xc3, 0x97, 0xfe, 0xe1, + 0xf0, 0x47, 0x14, 0x81, 0x01, 0xca, 0x9d, 0x10, 0x9f, 0xa1, 0xdf, 0x73, + 0xb8, 0xe4, 0xe5, 0xff, 0xa5, 0x9c, 0xcb, 0x51, 0xe7, 0xf1, 0xcb, 0xcc, + 0x89, 0x1c, 0xbf, 0x60, 0x7b, 0xfb, 0x67, 0x2b, 0xe2, 0x2a, 0x66, 0x24, + 0x73, 0xf1, 0x1c, 0xbc, 0x17, 0xf1, 0xcb, 0xff, 0x6e, 0x06, 0x25, 0xee, + 0xe0, 0x9c, 0xad, 0x22, 0x59, 0xcf, 0xb6, 0x39, 0x79, 0x1a, 0x61, 0xcb, + 0xcf, 0xa0, 0x1c, 0xb7, 0x30, 0x6e, 0x7c, 0x3b, 0x7c, 0xde, 0x75, 0xce, + 0x5f, 0x2b, 0xa4, 0x6c, 0xe5, 0xfa, 0x77, 0xec, 0x35, 0x9c, 0xa6, 0xa4, + 0xf3, 0xf0, 0x92, 0xa1, 0x59, 0xe6, 0x42, 0xc9, 0x23, 0x64, 0x76, 0x80, + 0x13, 0x8b, 0x8d, 0xff, 0xc3, 0x13, 0xb3, 0xa9, 0xad, 0x3c, 0x8e, 0x51, + 0xca, 0x13, 0xcf, 0x68, 0x89, 0x7f, 0xa7, 0x9e, 0x07, 0x9c, 0xf1, 0xca, + 0xc3, 0xd8, 0x42, 0x3b, 0xff, 0xb4, 0x3f, 0xf3, 0xe1, 0xc9, 0xdc, 0x4e, + 0x5f, 0xff, 0xc1, 0xef, 0xf3, 0xa6, 0x6b, 0x59, 0x1c, 0xc9, 0x18, 0x72, + 0xf3, 0xea, 0x73, 0x97, 0x02, 0x0e, 0x5f, 0x24, 0x33, 0x0e, 0x51, 0xcb, + 0xf9, 0xd5, 0xf4, 0x68, 0x07, 0x28, 0x26, 0xe4, 0x42, 0xef, 0xff, 0xf4, + 0x20, 0x46, 0x3f, 0x5f, 0xb1, 0x61, 0x85, 0xa8, 0xc3, 0x97, 0x02, 0x0e, + 0x5d, 0x0a, 0x9c, 0xbf, 0xec, 0xf6, 0xe1, 0x8a, 0x64, 0xc7, 0x2f, 0xf6, + 0xf3, 0xa9, 0xbf, 0xe7, 0x39, 0x73, 0x6d, 0x94, 0xbf, 0xe1, 0xce, 0x2f, + 0x2d, 0xa0, 0x4e, 0x52, 0xd3, 0xfb, 0x41, 0xdd, 0x0b, 0x31, 0x67, 0xa4, + 0x00, 0x61, 0xe1, 0xc5, 0x84, 0x5f, 0x67, 0x4d, 0x9a, 0xa8, 0x33, 0x79, + 0xb6, 0xdb, 0x29, 0x66, 0x14, 0xfa, 0x68, 0x2f, 0xa6, 0x77, 0xd1, 0x4f, + 0xa8, 0xe1, 0x52, 0x17, 0xd5, 0x3a, 0xbc, 0x75, 0xa2, 0xbc, 0xb3, 0x9b, + 0xfb, 0xd1, 0x9d, 0xc9, 0xce, 0x5d, 0x8c, 0x39, 0x5c, 0x9e, 0x1e, 0xcb, + 0x6a, 0x1d, 0x55, 0x94, 0xa3, 0xe8, 0x0a, 0x4e, 0x4a, 0xb0, 0x56, 0x38, + 0x6e, 0x63, 0xc9, 0x49, 0x63, 0xda, 0x8c, 0x55, 0x8d, 0x3d, 0x9d, 0x45, + 0x7a, 0x5e, 0x78, 0x16, 0x06, 0x5b, 0xbe, 0xe5, 0xbb, 0xfa, 0x30, 0x6f, + 0xe5, 0xf3, 0xf1, 0x7c, 0xbf, 0xb0, 0x00, 0x4d, 0x48, 0xe5, 0xcb, 0xc3, + 0x94, 0x13, 0xc3, 0x72, 0xdb, 0xb1, 0xb3, 0x97, 0x47, 0x8e, 0x54, 0xe6, + 0xb5, 0x62, 0xf6, 0x61, 0xca, 0xc3, 0x67, 0xe2, 0x2b, 0xfd, 0x24, 0x1c, + 0x67, 0xfd, 0x39, 0x7f, 0xec, 0xf6, 0xfa, 0x8c, 0x7c, 0xd1, 0xca, 0x83, + 0xf0, 0x13, 0x3b, 0xf6, 0x7c, 0xc0, 0x78, 0xe5, 0xf7, 0xcf, 0x47, 0x13, + 0x97, 0xd8, 0xcc, 0xf1, 0xcb, 0xde, 0x75, 0x4e, 0x5f, 0x3b, 0x1e, 0x63, + 0x97, 0xe1, 0x7f, 0x73, 0xb3, 0x97, 0xff, 0xfe, 0x79, 0xbf, 0x97, 0xeb, + 0xf9, 0xd4, 0xf7, 0xa3, 0x98, 0x9e, 0x36, 0x72, 0xfc, 0x2e, 0xd7, 0x3c, + 0xc7, 0x2f, 0xa6, 0xdc, 0x78, 0xe5, 0x2d, 0x18, 0x53, 0x39, 0xfe, 0x59, + 0x7f, 0xff, 0xcd, 0x62, 0xef, 0xc6, 0x25, 0xd8, 0xd4, 0xf1, 0xed, 0xbc, + 0x8e, 0x5e, 0x4e, 0x66, 0x39, 0x7d, 0xff, 0x0e, 0xc4, 0x39, 0x7e, 0xcc, + 0x9f, 0xfd, 0x9c, 0xbe, 0xd0, 0xa0, 0x0e, 0x5f, 0x22, 0xdf, 0x47, 0x2e, + 0x80, 0x1c, 0xbe, 0xfe, 0x7f, 0xfe, 0xf4, 0xdb, 0xa8, 0x43, 0x48, 0x89, + 0x7e, 0xac, 0x5c, 0xd6, 0x03, 0x97, 0xe7, 0x8e, 0x71, 0x67, 0x2f, 0xfb, + 0xaf, 0xbe, 0xa4, 0xee, 0x27, 0x2f, 0x9e, 0x75, 0x24, 0x72, 0xb8, 0x65, + 0xd2, 0xb8, 0x84, 0x0c, 0xa1, 0x20, 0x12, 0x0c, 0x29, 0xe4, 0x99, 0x08, + 0x5a, 0xc7, 0x66, 0x22, 0xd4, 0x3a, 0x9c, 0xc8, 0x0d, 0x5c, 0x38, 0xf6, + 0xca, 0x3d, 0x0c, 0x0f, 0xc8, 0x9b, 0x1a, 0x50, 0x9f, 0x80, 0xe2, 0xfe, + 0x1f, 0xc2, 0xc7, 0x91, 0xcb, 0xc9, 0x3f, 0xe7, 0x2f, 0xd0, 0x04, 0xe7, + 0x0e, 0x5c, 0xce, 0x27, 0x2c, 0x18, 0x3c, 0x01, 0x27, 0xbf, 0xfd, 0x21, + 0x8f, 0x8c, 0x18, 0x57, 0xc9, 0x39, 0xcb, 0xf3, 0xb3, 0x3a, 0xc3, 0x95, + 0xc9, 0xf9, 0xf9, 0x32, 0xf7, 0xb5, 0x07, 0x2f, 0xf6, 0xfd, 0xc7, 0x07, + 0x02, 0x72, 0xfe, 0xcd, 0xe4, 0x93, 0x47, 0x2f, 0x76, 0x38, 0x9c, 0xbd, + 0xb9, 0x4e, 0x72, 0xb0, 0xde, 0x28, 0x3d, 0x50, 0xa8, 0x86, 0x45, 0xd8, + 0xbc, 0x90, 0x99, 0x61, 0x1b, 0x8e, 0x09, 0xa7, 0x9a, 0x2f, 0x3f, 0xc5, + 0x0e, 0x5e, 0x99, 0x3a, 0x72, 0xfe, 0x8d, 0x3c, 0xc9, 0xd3, 0x97, 0xed, + 0x86, 0x06, 0x77, 0x3c, 0xad, 0x8e, 0xde, 0x64, 0x30, 0xe5, 0x72, 0x7b, + 0x4c, 0x3e, 0xbf, 0xfe, 0x19, 0x7c, 0xc0, 0xa6, 0xf9, 0xf7, 0xef, 0xb3, + 0x97, 0xee, 0xfe, 0x31, 0xc4, 0xe5, 0xfc, 0x2f, 0xe9, 0x42, 0xa7, 0x2a, + 0x0f, 0x5d, 0x42, 0xab, 0xec, 0xce, 0x64, 0x72, 0xf6, 0xd2, 0x63, 0x96, + 0x54, 0x4d, 0xfe, 0xc8, 0xaf, 0xfb, 0x49, 0x1e, 0xce, 0x2e, 0x13, 0x97, + 0xff, 0x3c, 0xe3, 0x1c, 0xa0, 0x46, 0x27, 0x39, 0x5a, 0x45, 0x27, 0x49, + 0xc4, 0xe6, 0xfd, 0xf3, 0xb1, 0xa9, 0x1c, 0xaf, 0x8a, 0xbb, 0xa2, 0x18, + 0x78, 0x46, 0xb8, 0x55, 0x3c, 0x60, 0xad, 0x97, 0xde, 0x66, 0xe0, 0xe5, + 0xfd, 0x3c, 0xd2, 0xe1, 0xb5, 0x39, 0xcb, 0xe6, 0x63, 0xf4, 0xe5, 0xa7, + 0x39, 0x7e, 0xf7, 0x51, 0x9a, 0x39, 0x52, 0x37, 0x5a, 0x12, 0xbd, 0xd0, + 0xa1, 0xcb, 0xf7, 0x71, 0x25, 0xb3, 0x97, 0xff, 0xdd, 0x85, 0x3e, 0xf8, + 0x5c, 0x1b, 0xdc, 0x00, 0xa5, 0xfb, 0x3c, 0xff, 0xf0, 0xe7, 0x2f, 0xda, + 0x5b, 0xba, 0xcf, 0x10, 0x22, 0xf6, 0xe3, 0x93, 0x96, 0x06, 0x1e, 0x8f, + 0x26, 0x97, 0xbc, 0x93, 0x9c, 0xbd, 0x3b, 0x89, 0xca, 0x92, 0x6b, 0x01, + 0x27, 0xe5, 0x4b, 0x4f, 0xcc, 0x28, 0xf0, 0xed, 0xfc, 0x2b, 0x75, 0x7a, + 0x87, 0x2e, 0xe0, 0x91, 0xcb, 0xef, 0x4e, 0xe2, 0x72, 0xf0, 0xba, 0xa7, + 0x2f, 0xf2, 0xb9, 0x3f, 0xfe, 0xe3, 0xe3, 0x97, 0xfc, 0xf2, 0xd4, 0x4e, + 0xfa, 0x59, 0xcb, 0xca, 0xa7, 0x8e, 0x5e, 0xdb, 0xf8, 0xe5, 0x2a, 0x6e, + 0x79, 0x1d, 0xbb, 0xe7, 0x4e, 0x5f, 0xcc, 0xf2, 0x07, 0xf8, 0x39, 0x79, + 0x9e, 0x59, 0xcb, 0x7a, 0x0f, 0x2f, 0x0b, 0xaf, 0xe8, 0x66, 0x2b, 0x1b, + 0x39, 0x53, 0xa7, 0xbb, 0x83, 0x4b, 0x22, 0xd0, 0xe3, 0x0e, 0x7a, 0xe4, + 0x02, 0x31, 0x64, 0xf1, 0x35, 0xda, 0xfc, 0xe5, 0xfe, 0x17, 0x6f, 0x7b, + 0x80, 0x1c, 0xbc, 0xd1, 0xd5, 0x39, 0x7f, 0xd0, 0xc9, 0x64, 0xf9, 0xff, + 0x0e, 0x72, 0xff, 0xa0, 0x09, 0x2e, 0xa0, 0x80, 0xe5, 0xa7, 0x39, 0x73, + 0xfb, 0x47, 0x93, 0xc3, 0x9b, 0xd6, 0x23, 0x65, 0x07, 0xde, 0x11, 0x17, + 0x9b, 0x85, 0x0e, 0x5e, 0x6d, 0xb6, 0xcf, 0x57, 0xd2, 0xf3, 0x88, 0x4b, + 0x57, 0xd5, 0xf4, 0xd6, 0xdf, 0x4b, 0xf8, 0x54, 0xe5, 0x80, 0x72, 0xb0, + 0xda, 0xb9, 0x25, 0x42, 0xa3, 0x00, 0x8c, 0x6a, 0x30, 0xce, 0x99, 0x01, + 0x2f, 0xce, 0x17, 0xfb, 0xdd, 0xc9, 0x75, 0x38, 0x9c, 0xbe, 0x66, 0xbf, + 0x9c, 0xe5, 0xff, 0xf0, 0xa2, 0xbf, 0x77, 0xee, 0xfe, 0xf2, 0x94, 0x1c, + 0xa8, 0x3f, 0x8c, 0x25, 0xa9, 0xd3, 0x2b, 0x92, 0xf2, 0xb0, 0xad, 0xbe, + 0xc0, 0xbc, 0x8e, 0x5f, 0x9c, 0x45, 0x18, 0x72, 0xf6, 0x71, 0x50, 0xe5, + 0xc9, 0xd3, 0x97, 0x82, 0xf2, 0x39, 0x7f, 0x93, 0x58, 0x8c, 0x86, 0xb3, + 0x94, 0x13, 0xe6, 0xc1, 0x6e, 0x8e, 0x5f, 0x91, 0x8e, 0x38, 0x72, 0xbe, + 0x32, 0x75, 0x5a, 0xa1, 0xc8, 0x37, 0x92, 0xd8, 0x48, 0x72, 0x37, 0x45, + 0x56, 0x52, 0x50, 0x53, 0xcb, 0xd9, 0x01, 0xc0, 0x90, 0xec, 0x97, 0xf8, + 0x42, 0xb4, 0x2e, 0xbf, 0xb3, 0xb8, 0xbf, 0xf0, 0xe5, 0xf9, 0x3d, 0x1e, + 0xd9, 0x4b, 0xe5, 0xc7, 0xb6, 0x52, 0xe6, 0xdb, 0x29, 0x52, 0x3e, 0x2c, + 0x27, 0x6c, 0x8a, 0xcd, 0x94, 0xfa, 0x6b, 0xef, 0x38, 0x80, 0xe5, 0x61, + 0xbf, 0x54, 0x92, 0xfa, 0x61, 0x76, 0xce, 0x5e, 0x9b, 0xa8, 0x72, 0xff, + 0xfb, 0xd0, 0xbc, 0xc1, 0xf7, 0x52, 0x06, 0x73, 0x94, 0x72, 0xb0, 0xf6, + 0x36, 0x9b, 0x53, 0x27, 0xae, 0x08, 0x7e, 0x89, 0x0e, 0xc8, 0xdb, 0x75, + 0xbf, 0xfc, 0x31, 0xc8, 0x30, 0x62, 0x5a, 0xd4, 0x1c, 0xbf, 0xf7, 0xb7, + 0x8b, 0xeb, 0x8f, 0xb6, 0x72, 0xf2, 0x08, 0x0e, 0x7c, 0x37, 0xd6, 0x86, + 0x22, 0xcf, 0x8c, 0x21, 0xaf, 0xf4, 0xf1, 0xd8, 0xec, 0x4e, 0x72, 0xe7, + 0xd9, 0xcb, 0x76, 0x0f, 0x29, 0xcd, 0x2f, 0xd2, 0xef, 0xf1, 0xa3, 0x97, + 0xff, 0x3b, 0x35, 0x1c, 0x53, 0x88, 0xff, 0xb3, 0x95, 0xc9, 0xf8, 0xf4, + 0xa6, 0xfd, 0x9f, 0xb2, 0x36, 0x72, 0x8e, 0x5d, 0x93, 0x68, 0xd9, 0xec, + 0xa2, 0xff, 0x93, 0xfe, 0x1f, 0xb0, 0xa0, 0xce, 0x72, 0xff, 0xa2, 0x78, + 0xe7, 0xc3, 0x93, 0x9c, 0xac, 0x45, 0x3a, 0xcb, 0x51, 0x02, 0xfc, 0xec, + 0x18, 0xe4, 0xe5, 0x4c, 0x9a, 0x96, 0xa1, 0xfb, 0xd2, 0xeb, 0xec, 0xee, + 0x4e, 0x72, 0xf4, 0x9f, 0x47, 0x2f, 0xe0, 0x31, 0xe5, 0x81, 0x39, 0x7d, + 0x9e, 0xc0, 0x94, 0xbe, 0x75, 0x40, 0xd9, 0xca, 0x91, 0xe2, 0x89, 0x0d, + 0xf4, 0x08, 0xc1, 0xca, 0x99, 0x19, 0xda, 0x1c, 0xf3, 0x92, 0x84, 0x37, + 0xc0, 0xdb, 0x34, 0x72, 0x95, 0x4d, 0x49, 0x21, 0xe1, 0xe3, 0xfb, 0xfe, + 0x1c, 0xee, 0x7c, 0xee, 0x4e, 0x72, 0xff, 0xff, 0xe0, 0x40, 0xad, 0xfc, + 0xfc, 0x83, 0x9f, 0x23, 0x37, 0xd8, 0x50, 0x4e, 0x5f, 0xdf, 0xf0, 0xe9, + 0xad, 0x61, 0xcb, 0xef, 0x2b, 0x9d, 0x39, 0x7f, 0xe1, 0xcf, 0x7b, 0xf9, + 0xfd, 0x8b, 0x39, 0x7e, 0x0f, 0xef, 0xa9, 0x1c, 0xb6, 0xce, 0x5c, 0x80, + 0x39, 0x77, 0x50, 0xe5, 0xdf, 0xef, 0xe1, 0xac, 0x98, 0x5a, 0x9c, 0xfb, + 0x80, 0x7b, 0x70, 0x20, 0xe5, 0xc0, 0x83, 0x97, 0xef, 0xe5, 0x83, 0xf5, + 0x0d, 0x60, 0x05, 0xaa, 0x13, 0x86, 0x54, 0x8d, 0x10, 0x01, 0x09, 0x71, + 0x4d, 0xbf, 0xfe, 0xc1, 0x7e, 0x76, 0xaa, 0xaf, 0xf1, 0x6c, 0x01, 0xcb, + 0xff, 0xbd, 0xdc, 0x62, 0x90, 0x0c, 0xe7, 0xc7, 0x2f, 0xf7, 0x2b, 0x4d, + 0x29, 0x01, 0x39, 0x7c, 0x06, 0x3c, 0xbe, 0x23, 0x3f, 0x6a, 0x9e, 0x46, + 0xbb, 0xff, 0x1c, 0xbf, 0x80, 0xc5, 0x36, 0xa4, 0xe7, 0x2f, 0xed, 0xa0, + 0x8c, 0x72, 0x72, 0xec, 0xe4, 0xe5, 0x72, 0x7e, 0xbe, 0x32, 0x68, 0x59, + 0x7c, 0x0d, 0x26, 0x8e, 0x54, 0x26, 0x55, 0x24, 0x97, 0x84, 0x6b, 0x66, + 0x57, 0xbf, 0xe7, 0xc7, 0x2c, 0xe7, 0x2b, 0x66, 0xbf, 0xc3, 0xf7, 0x63, + 0x67, 0x2f, 0xfa, 0x39, 0xc0, 0x47, 0x1c, 0x9c, 0xe5, 0xfc, 0x39, 0xed, + 0xb8, 0x0e, 0x56, 0x8f, 0xf8, 0x02, 0xfb, 0x3b, 0xbf, 0xe8, 0x9f, 0x7a, + 0xc5, 0xc4, 0xe7, 0x2f, 0xf6, 0x0c, 0xf8, 0x17, 0xe9, 0xca, 0x98, 0xfb, + 0x1b, 0x3a, 0xbf, 0xb1, 0x98, 0x14, 0x6c, 0xe5, 0xcc, 0x83, 0x94, 0xc3, + 0xc3, 0x72, 0xdb, 0xf8, 0x72, 0x6e, 0xa7, 0x8e, 0x5f, 0x66, 0x77, 0x67, + 0x2b, 0x11, 0xac, 0xec, 0xfe, 0x21, 0xe0, 0x2d, 0xbc, 0xdb, 0x6d, 0x94, + 0xbf, 0x62, 0xa3, 0xfe, 0xca, 0x7d, 0x34, 0x17, 0xdf, 0x5b, 0x6d, 0xb3, + 0x97, 0x60, 0x0e, 0x56, 0x1b, 0xef, 0x14, 0x54, 0x22, 0x67, 0xcf, 0x37, + 0xff, 0xc9, 0x27, 0xdb, 0x18, 0xf2, 0x75, 0x7a, 0x87, 0x2f, 0x93, 0x40, + 0xd9, 0xcb, 0xfe, 0xde, 0xa3, 0xff, 0x0a, 0x71, 0x39, 0x7f, 0xe1, 0xcd, + 0xaf, 0xa8, 0xb8, 0x13, 0x97, 0xff, 0xf9, 0x56, 0xdf, 0x4a, 0xfd, 0xde, + 0x48, 0x7f, 0x7d, 0xe0, 0x9c, 0xa8, 0x46, 0xe6, 0x1d, 0xa1, 0xe5, 0xf3, + 0x6e, 0x32, 0x39, 0x7f, 0xde, 0x8e, 0x40, 0xfd, 0xea, 0x1c, 0xb7, 0x4e, + 0x56, 0x1e, 0x52, 0xce, 0x6f, 0xb6, 0x8c, 0x83, 0x97, 0xe1, 0xcf, 0x46, + 0x8e, 0x5e, 0x6d, 0xb6, 0xca, 0x5f, 0x9d, 0x5e, 0xa7, 0x8a, 0x7d, 0x34, + 0x15, 0x08, 0x80, 0x44, 0x6b, 0xdc, 0x61, 0x87, 0x2f, 0x79, 0x1b, 0x39, + 0x7b, 0x6f, 0xa3, 0x95, 0xc9, 0xb9, 0xf0, 0xed, 0xee, 0xc0, 0x4e, 0x56, + 0x22, 0x55, 0x15, 0xdc, 0x8a, 0xfd, 0x80, 0xcc, 0x98, 0xe5, 0xb7, 0xf1, + 0x3c, 0xce, 0x48, 0x75, 0x0a, 0x1e, 0xc2, 0xd8, 0x4b, 0x6e, 0xfe, 0x41, + 0x55, 0x2b, 0x92, 0x8e, 0x2f, 0xdc, 0x3f, 0x62, 0x7f, 0xce, 0x5f, 0xfc, + 0x9e, 0x8d, 0x60, 0xf9, 0xdc, 0x4e, 0x54, 0xcb, 0x8c, 0xfd, 0x87, 0xf0, + 0xca, 0xc2, 0xfc, 0xe3, 0x89, 0x7d, 0xe8, 0xe3, 0x07, 0x2b, 0x17, 0x4b, + 0xd2, 0x72, 0xd8, 0x57, 0x2f, 0x0c, 0x71, 0x39, 0x7f, 0xf6, 0xa1, 0x7d, + 0x17, 0xf0, 0xc3, 0x67, 0x2e, 0xe1, 0xd0, 0xe5, 0xc9, 0xd3, 0x95, 0x39, + 0xb1, 0xd0, 0xdd, 0x42, 0x25, 0x9d, 0xd2, 0xfb, 0xdb, 0xfd, 0xac, 0xe5, + 0xfe, 0x81, 0x90, 0xa4, 0x72, 0x72, 0xa1, 0xb3, 0xff, 0x94, 0x60, 0x81, + 0x79, 0xc8, 0xfa, 0x55, 0x8e, 0x25, 0x66, 0xdc, 0x9d, 0x23, 0x9e, 0xa3, + 0xb9, 0xec, 0xa4, 0x77, 0x71, 0x04, 0x27, 0xc6, 0x37, 0x1d, 0xc3, 0xdf, + 0xd3, 0xaa, 0x3c, 0x4e, 0x1a, 0x42, 0xcd, 0x42, 0x1e, 0x02, 0x7b, 0xf2, + 0x4d, 0x24, 0x13, 0x97, 0x35, 0x28, 0x72, 0xff, 0xa6, 0xf7, 0x06, 0xe2, + 0x6f, 0xf4, 0x72, 0xff, 0x06, 0x05, 0x90, 0x18, 0x39, 0x50, 0x7e, 0x2e, + 0x81, 0x7f, 0xf6, 0x27, 0x60, 0x3d, 0xfe, 0x39, 0xd9, 0xcb, 0xc1, 0x54, + 0x07, 0x2f, 0xcc, 0xd6, 0x9f, 0xc7, 0x2b, 0xe1, 0xe3, 0x40, 0xf5, 0xff, + 0xd3, 0x3a, 0xfb, 0x12, 0xf0, 0xe3, 0x0e, 0x5f, 0xda, 0xc1, 0x17, 0x9c, + 0xe5, 0x2c, 0xfc, 0x11, 0x12, 0xff, 0xf9, 0x19, 0xcc, 0xb7, 0xf3, 0x04, + 0x71, 0x00, 0x72, 0xf2, 0x77, 0xf3, 0x95, 0xf1, 0x53, 0xfb, 0x54, 0x4f, + 0x28, 0x46, 0x68, 0x83, 0xb0, 0x8b, 0x78, 0x49, 0xf8, 0x87, 0x8a, 0x85, + 0xbe, 0xb5, 0x51, 0xfe, 0x42, 0xb5, 0x30, 0x90, 0xe1, 0x21, 0xb6, 0xd5, + 0xc6, 0x91, 0xc3, 0x42, 0x97, 0x85, 0xe3, 0x6d, 0x6a, 0x31, 0x90, 0xb5, + 0x08, 0x48, 0x70, 0xa7, 0x08, 0xac, 0xf9, 0x67, 0x9e, 0xd2, 0x95, 0x32, + 0x78, 0x34, 0xd5, 0x7c, 0xbc, 0x6a, 0x95, 0x67, 0x16, 0x57, 0x4f, 0xc9, + 0xe6, 0x98, 0x3c, 0x94, 0xda, 0x16, 0xb8, 0xf1, 0x66, 0xac, 0x2d, 0xf5, + 0x59, 0x06, 0xb2, 0x96, 0xd3, 0xda, 0xfe, 0xdd, 0xed, 0x16, 0xd0, 0x29, + 0x9e, 0x1c, 0x3c, 0x64, 0x03, 0x5f, 0x94, 0x6e, 0xf2, 0xe4, 0xfd, 0x6b, + 0xa0, 0x3f, 0x9e, 0xac, 0xe3, 0x2d, 0x25, 0xb9, 0x6c, 0x2d, 0x29, 0x47, + 0xca, 0x56, 0xd7, 0x1c, 0x12, 0xf1, 0x6b, 0xec, 0xa0, 0x00, 0xc9, 0x67, + 0xf9, 0xaf, 0x79, 0x99, 0xe3, 0x97, 0xf9, 0xd9, 0x1e, 0x4d, 0xa1, 0xcb, + 0xf6, 0x69, 0x4f, 0x6c, 0xe5, 0xbe, 0x80, 0xfd, 0x84, 0x73, 0x66, 0x37, + 0xfb, 0xee, 0x69, 0x6e, 0xeb, 0x34, 0x5c, 0x6b, 0xfd, 0xf7, 0x34, 0xb7, + 0x75, 0x9a, 0x2e, 0xb5, 0xff, 0xdf, 0x5e, 0x5f, 0x73, 0x4b, 0x77, 0x59, + 0xa2, 0x51, 0x54, 0x4a, 0x06, 0xd0, 0x94, 0x29, 0xc2, 0x54, 0xac, 0x24, + 0xd6, 0x52, 0x92, 0xa0, 0x9a, 0xe1, 0x38, 0xfa, 0x80, 0x19, 0x81, 0x0b, + 0x3d, 0x9b, 0x79, 0x07, 0x81, 0x06, 0xff, 0xf7, 0xd6, 0x3c, 0xbe, 0xe6, + 0x96, 0xee, 0xb3, 0x44, 0xb4, 0xbf, 0xee, 0x16, 0xea, 0x35, 0xbc, 0x73, + 0xc0, 0x72, 0xfd, 0xa5, 0xbb, 0xac, 0xd1, 0x1b, 0xaf, 0xfe, 0xec, 0x26, + 0x93, 0x87, 0x5f, 0x61, 0xb3, 0x97, 0xed, 0x43, 0x6c, 0x09, 0xcb, 0xff, + 0x3c, 0xbe, 0xe6, 0x96, 0xee, 0xb3, 0x44, 0xbe, 0xbf, 0xa3, 0xca, 0x75, + 0xfc, 0x72, 0xfe, 0x53, 0x4a, 0xf7, 0xfd, 0x9c, 0xbd, 0x1a, 0x83, 0x95, + 0x87, 0x9a, 0x86, 0x57, 0xfd, 0xdc, 0x4d, 0x4b, 0xa8, 0xd9, 0xcb, 0xef, + 0xfa, 0x9a, 0x39, 0x7a, 0x6d, 0xe8, 0xe5, 0xbe, 0xb5, 0x05, 0x49, 0xb8, + 0x8c, 0xb3, 0x4d, 0x24, 0xb0, 0xa7, 0xa9, 0x82, 0xf7, 0xe2, 0x06, 0x87, + 0x2a, 0x11, 0xdf, 0xfe, 0xe6, 0x5e, 0x49, 0xbe, 0x85, 0x38, 0xc0, 0x4e, + 0x5f, 0xef, 0xb9, 0xa5, 0xbb, 0xac, 0xd1, 0x55, 0xae, 0x4e, 0x03, 0x97, + 0xc8, 0xc7, 0xe2, 0x72, 0x95, 0x37, 0x9e, 0x19, 0xbc, 0x3c, 0x0d, 0x9c, + 0xbf, 0xbb, 0x1c, 0x7f, 0x0e, 0x1c, 0xbf, 0x9f, 0xb3, 0x0c, 0x04, 0xe5, + 0xff, 0xde, 0xec, 0x6c, 0x5f, 0xfe, 0x1d, 0x34, 0x72, 0xf4, 0x4b, 0x0e, + 0x54, 0x91, 0x82, 0x13, 0x0e, 0x4b, 0x66, 0x49, 0xbf, 0xe5, 0x70, 0x73, + 0x9f, 0x3b, 0x0e, 0x5e, 0xe0, 0x8f, 0x1c, 0xbf, 0xda, 0x86, 0x29, 0x02, + 0xb3, 0x97, 0xb9, 0x7e, 0x4e, 0x5f, 0x3f, 0x9f, 0x93, 0x97, 0x05, 0x0e, + 0x5f, 0xd9, 0xa5, 0xbb, 0xac, 0xd1, 0x20, 0x2b, 0xe1, 0xe7, 0xfd, 0x16, + 0xbf, 0x6d, 0xc5, 0xf9, 0x39, 0x77, 0xf0, 0x72, 0xa4, 0x7c, 0x9c, 0x93, + 0x68, 0x9e, 0xff, 0x4a, 0x35, 0x3c, 0x6a, 0x73, 0x97, 0xfb, 0x53, 0xb2, + 0x06, 0x5b, 0x39, 0x50, 0x7d, 0x38, 0x6b, 0x7a, 0x77, 0x09, 0xcb, 0xfc, + 0xb4, 0xc6, 0xff, 0x1f, 0x1c, 0xac, 0x3d, 0x1e, 0x47, 0x6e, 0xe1, 0x3a, + 0x72, 0xff, 0xf6, 0x4d, 0xd7, 0x67, 0xbb, 0x1e, 0xfd, 0x87, 0x2a, 0x75, + 0xc5, 0x40, 0x91, 0x64, 0x38, 0x55, 0x3f, 0x6b, 0x39, 0x98, 0x7d, 0x86, + 0x7d, 0x1e, 0x78, 0x6a, 0x8c, 0x26, 0x7c, 0xe2, 0xd0, 0x89, 0x41, 0xcb, + 0xf4, 0x08, 0xe7, 0x8e, 0x5f, 0x6b, 0x48, 0xb3, 0x97, 0xc3, 0x93, 0xfd, + 0x68, 0x78, 0xea, 0x12, 0xdf, 0xef, 0xbd, 0x76, 0x64, 0x04, 0xe5, 0x7d, + 0x4e, 0x0f, 0x51, 0x88, 0xb4, 0x3e, 0xbf, 0xdf, 0x73, 0x4b, 0x77, 0x59, + 0xa2, 0xc8, 0x5f, 0xef, 0xb9, 0xa5, 0xbb, 0xac, 0xd1, 0x6b, 0xaf, 0xff, + 0x62, 0x91, 0x3f, 0xdc, 0x9b, 0xc1, 0x81, 0x39, 0x7f, 0xbe, 0xe6, 0x96, + 0xee, 0xb3, 0x45, 0xc8, 0xbf, 0x69, 0x6e, 0xeb, 0x34, 0x5d, 0x8b, 0xff, + 0x3c, 0xbe, 0xe6, 0x96, 0xee, 0xb3, 0x45, 0x1c, 0xb7, 0xdc, 0x44, 0x03, + 0x0d, 0x2f, 0x86, 0x24, 0xc3, 0x97, 0xfe, 0xe1, 0xb8, 0x46, 0x46, 0xa5, + 0x89, 0xc4, 0xe5, 0xa4, 0x72, 0xfd, 0xa5, 0xbb, 0xac, 0xd1, 0x4a, 0xaf, + 0xf9, 0x7d, 0x49, 0xbb, 0x13, 0xe1, 0xcb, 0xff, 0xdd, 0x89, 0xe3, 0xa9, + 0xc5, 0xc3, 0xd4, 0x39, 0xf4, 0xdd, 0x5d, 0x2f, 0xb8, 0x8c, 0xb9, 0x9b, + 0xab, 0x94, 0xc3, 0x5e, 0x1b, 0x97, 0xfe, 0x74, 0xf4, 0xbf, 0x0b, 0x88, + 0x0e, 0x5b, 0xe8, 0x53, 0xdf, 0xe4, 0x85, 0x91, 0xab, 0xf4, 0xa6, 0xa7, + 0x67, 0x04, 0x4a, 0x55, 0x3e, 0x42, 0x73, 0x95, 0x04, 0x9e, 0x54, 0x61, + 0xd8, 0x10, 0x45, 0x07, 0x69, 0xbe, 0x86, 0x0f, 0x19, 0x41, 0x37, 0xfd, + 0x2f, 0xb9, 0xa5, 0xbb, 0xac, 0xd1, 0x1c, 0x2f, 0xf9, 0x3e, 0xe6, 0x96, + 0xee, 0xb3, 0x45, 0x6a, 0xb7, 0xd7, 0x44, 0x6f, 0x91, 0xef, 0xff, 0x7d, + 0x63, 0xcb, 0xee, 0x69, 0x6e, 0xeb, 0x34, 0x4b, 0x6b, 0xdf, 0xe8, 0x07, + 0x2e, 0xce, 0x4e, 0x5f, 0xe0, 0xe3, 0x19, 0x09, 0xb3, 0x97, 0xb8, 0xff, + 0x23, 0x94, 0xb4, 0x43, 0xf2, 0x3c, 0x82, 0xfc, 0x4c, 0xaf, 0x74, 0x32, + 0x39, 0x7f, 0xd9, 0xc8, 0xe0, 0x00, 0xf2, 0x39, 0x73, 0x16, 0x72, 0xff, + 0x62, 0x73, 0xb0, 0xe0, 0x9c, 0xa8, 0x44, 0x0c, 0x8e, 0x34, 0x2f, 0x7c, + 0x31, 0xcc, 0x8e, 0x5f, 0xd3, 0xc2, 0xdf, 0x40, 0x39, 0x7f, 0xfe, 0x7e, + 0x40, 0x1e, 0xbc, 0xb3, 0x63, 0xfb, 0xa8, 0x72, 0xf8, 0x19, 0xa9, 0x8e, + 0x52, 0xd1, 0x95, 0xa2, 0x2e, 0x97, 0x01, 0x5e, 0xca, 0x9c, 0xbf, 0x93, + 0x42, 0x9e, 0xd9, 0xcb, 0xf6, 0x9c, 0x72, 0x0e, 0x51, 0xa2, 0x1b, 0x21, + 0xf1, 0xf4, 0x49, 0xcb, 0x2e, 0x81, 0x39, 0x7b, 0x10, 0x27, 0x2f, 0x07, + 0x18, 0x72, 0xe4, 0x10, 0x9b, 0x74, 0x1b, 0xa8, 0x3f, 0x69, 0x26, 0x5f, + 0x64, 0xd2, 0xc3, 0x97, 0xfe, 0x79, 0x7d, 0xcd, 0x2d, 0xdd, 0x66, 0x89, + 0x81, 0x79, 0xb4, 0x01, 0xcb, 0xed, 0xb8, 0x80, 0xe5, 0x4c, 0x6f, 0x80, + 0x3b, 0x7f, 0xbf, 0xe7, 0x49, 0x0c, 0xc3, 0x97, 0xee, 0xa4, 0x0c, 0xe7, + 0x2f, 0xfa, 0x27, 0xf0, 0xc7, 0xfe, 0xd9, 0xcb, 0x7b, 0xa8, 0x95, 0xd9, + 0xa3, 0x42, 0x7b, 0xee, 0x56, 0x8a, 0x9c, 0xac, 0x3d, 0xcf, 0x1c, 0x5f, + 0xc9, 0xec, 0x64, 0x74, 0xe5, 0xff, 0xd1, 0xa4, 0x04, 0xfd, 0x8d, 0xff, + 0xb3, 0x95, 0xa3, 0xf2, 0xf1, 0x65, 0xff, 0xb1, 0x99, 0xac, 0xe6, 0x59, + 0xe3, 0x97, 0xf2, 0x75, 0x19, 0x8a, 0x9c, 0xae, 0x9f, 0x5e, 0xcf, 0xaf, + 0xff, 0x3c, 0xfd, 0x48, 0x1c, 0x99, 0x34, 0x87, 0x2b, 0x11, 0xef, 0xe8, + 0x46, 0xb6, 0x45, 0x72, 0xf0, 0xe5, 0xdf, 0x80, 0xa5, 0x21, 0xae, 0xd0, + 0xb5, 0xf9, 0x58, 0x96, 0x04, 0xe5, 0xfe, 0xc0, 0x8e, 0x7b, 0xb8, 0x72, + 0xee, 0x19, 0x67, 0x8c, 0x29, 0x7e, 0x51, 0xa3, 0x88, 0x0e, 0x5f, 0xd9, + 0xd7, 0x50, 0x7c, 0x72, 0xa7, 0x3d, 0x70, 0x95, 0x5f, 0xd9, 0xef, 0x46, + 0xb6, 0x72, 0xfe, 0x71, 0x04, 0xe0, 0xf1, 0xca, 0x83, 0xfe, 0x12, 0x36, + 0x85, 0xb6, 0xfb, 0x0c, 0x8a, 0x09, 0xcf, 0xc3, 0x09, 0xec, 0x87, 0xca, + 0xe1, 0x41, 0xcc, 0x2d, 0xf4, 0x42, 0xc2, 0x27, 0x84, 0x50, 0xc6, 0x27, + 0xb8, 0xe2, 0xbc, 0xc7, 0xf9, 0x07, 0x12, 0x86, 0xcc, 0x54, 0x87, 0xf5, + 0xe6, 0x7f, 0xa2, 0x97, 0xfe, 0x79, 0x7d, 0xcd, 0x2d, 0xdd, 0x66, 0x89, + 0x8d, 0x7d, 0x1a, 0x8e, 0x03, 0x96, 0xfa, 0x88, 0x8e, 0x60, 0xf7, 0x53, + 0x2f, 0xf8, 0x29, 0xc7, 0xef, 0x20, 0x52, 0x47, 0x2f, 0xa2, 0x78, 0xd1, + 0xcb, 0xde, 0x89, 0x8e, 0x5f, 0xb2, 0x26, 0x46, 0x1c, 0xa4, 0x3e, 0x69, + 0x88, 0xb4, 0x3b, 0x7f, 0x05, 0x91, 0x9e, 0xd9, 0xcb, 0xfd, 0xd8, 0xd4, + 0xea, 0x7e, 0x03, 0x97, 0x3e, 0xce, 0x5f, 0x7c, 0xf6, 0x74, 0xe5, 0xa3, + 0xa6, 0xeb, 0x62, 0xd7, 0xa0, 0x67, 0x39, 0x7f, 0xff, 0xfd, 0x2d, 0xf7, + 0x3f, 0x6f, 0x7d, 0xc5, 0xe6, 0xfe, 0x67, 0x32, 0xda, 0x0a, 0x1c, 0xbc, + 0xee, 0xb3, 0x45, 0x62, 0xbe, 0x75, 0x21, 0x53, 0x94, 0xb3, 0xcb, 0xd1, + 0x45, 0xff, 0x9a, 0x67, 0x87, 0x3f, 0x81, 0xf1, 0xcb, 0xfc, 0x39, 0xb0, + 0x66, 0x04, 0xe5, 0x2a, 0x9d, 0x02, 0xc9, 0xb9, 0x1c, 0xd4, 0x33, 0x3c, + 0x45, 0xc4, 0xfe, 0xff, 0xe5, 0x7f, 0xf6, 0xc7, 0x38, 0x8e, 0x6c, 0xe5, + 0xff, 0xc3, 0xe5, 0x7f, 0x81, 0xc5, 0xc6, 0x8e, 0x5f, 0xed, 0x4f, 0xed, + 0xbf, 0x2b, 0x39, 0x50, 0x7f, 0x4e, 0x89, 0x7f, 0xd2, 0xcf, 0x60, 0xc3, + 0x6d, 0x0e, 0x5f, 0xb8, 0x3d, 0x9c, 0xcc, 0x72, 0xff, 0xff, 0xff, 0x3f, + 0xbd, 0x9d, 0xdb, 0xc9, 0x07, 0xd2, 0xcd, 0x66, 0xf3, 0xaf, 0x38, 0xc4, + 0x8e, 0x54, 0x22, 0xe3, 0x65, 0xb7, 0xf7, 0xed, 0x17, 0xd4, 0xe1, 0xce, + 0x5f, 0xd9, 0xbe, 0x65, 0x1d, 0x39, 0x74, 0x71, 0x39, 0x5d, 0x3c, 0x61, + 0x2e, 0xbf, 0xd3, 0x3e, 0x24, 0x94, 0x61, 0xca, 0x09, 0xea, 0xa1, 0x0d, + 0xff, 0x47, 0x32, 0x9a, 0x4f, 0xa9, 0xce, 0x54, 0x26, 0x5d, 0x90, 0xd1, + 0x42, 0x1b, 0xd1, 0x2f, 0x1c, 0xbf, 0xf6, 0x07, 0x49, 0xfc, 0xe0, 0xdc, + 0x8e, 0x5f, 0x31, 0xf9, 0xf1, 0xcb, 0xff, 0xa7, 0x8f, 0x7c, 0x51, 0x6a, + 0x70, 0x29, 0xb3, 0x97, 0xfd, 0xa8, 0xdb, 0xe8, 0x62, 0x47, 0x2b, 0x48, + 0x86, 0xe2, 0x9f, 0x7a, 0x4f, 0x39, 0xcb, 0xdf, 0x27, 0x61, 0xcb, 0x83, + 0xe3, 0x95, 0xc3, 0x26, 0x45, 0x90, 0xa9, 0xe4, 0x95, 0x07, 0x44, 0x82, + 0xff, 0xc2, 0xe1, 0xec, 0x71, 0xeb, 0x89, 0xcb, 0xff, 0xff, 0x7f, 0x3e, + 0x2f, 0xe0, 0xff, 0xc1, 0xf3, 0x39, 0x96, 0x7e, 0x20, 0xd9, 0xcb, 0xff, + 0xd3, 0xe7, 0x3e, 0xda, 0x0c, 0x01, 0xd8, 0x72, 0xff, 0x72, 0x38, 0x1e, + 0xbb, 0x67, 0x2b, 0x0f, 0xf9, 0xd2, 0xa8, 0x29, 0xaa, 0x09, 0xf6, 0xe1, + 0xed, 0x7f, 0x4f, 0x34, 0xb8, 0x6d, 0x4e, 0x72, 0xf8, 0x47, 0x3c, 0x72, + 0xfc, 0x8d, 0x7a, 0xd2, 0x1c, 0xa6, 0xa9, 0x10, 0x30, 0x6f, 0xd2, 0x0b, + 0xfa, 0x75, 0x1a, 0x38, 0x80, 0xe5, 0xf3, 0x5c, 0x6c, 0x4e, 0x5f, 0xfb, + 0xae, 0xcf, 0x76, 0x3d, 0xfb, 0x0e, 0x56, 0x1f, 0x24, 0xc4, 0x97, 0xff, + 0x66, 0x2a, 0xc8, 0x4d, 0x69, 0x1b, 0x39, 0x7f, 0xc9, 0x24, 0xef, 0xec, + 0x62, 0x1c, 0xbb, 0x3c, 0x72, 0xa1, 0x34, 0xac, 0x84, 0xae, 0x88, 0xbc, + 0x88, 0xd0, 0xe6, 0xf0, 0xbf, 0x01, 0xcb, 0xdd, 0x4f, 0xb0, 0xcb, 0xec, + 0x9c, 0xbe, 0x45, 0xb9, 0x28, 0x45, 0x56, 0x15, 0xc3, 0x07, 0x92, 0x0d, + 0x43, 0xcb, 0xb1, 0xa8, 0x39, 0x98, 0x8e, 0x6e, 0x36, 0x3f, 0x47, 0x4e, + 0xd2, 0x16, 0xca, 0x46, 0xfd, 0xc0, 0xa1, 0x7b, 0x85, 0x9a, 0x35, 0x47, + 0x2e, 0x90, 0x9c, 0xbf, 0xb5, 0xa8, 0x0e, 0x30, 0xe5, 0xf4, 0xfa, 0x89, + 0xce, 0x5c, 0xa0, 0x0e, 0x5e, 0xea, 0x30, 0xe5, 0xa6, 0x39, 0x4e, 0x6b, + 0xbf, 0x1c, 0xbf, 0x38, 0xcf, 0xfe, 0xce, 0x5f, 0xf4, 0x07, 0xb8, 0x1d, + 0x3a, 0xce, 0x52, 0x26, 0x32, 0xe5, 0xa0, 0x24, 0x14, 0x6d, 0x90, 0xf8, + 0xa6, 0xdd, 0x39, 0x7b, 0x6a, 0x6c, 0xe5, 0xf7, 0x33, 0xc2, 0xa7, 0x2a, + 0x73, 0xd4, 0x08, 0x8f, 0xe3, 0xd7, 0x7a, 0x0e, 0x5f, 0xee, 0x75, 0x09, + 0x27, 0xd9, 0xcb, 0xec, 0x18, 0x91, 0xca, 0xc3, 0xd3, 0x61, 0x9d, 0x9a, + 0x1c, 0xbf, 0xd8, 0x0d, 0xe7, 0x93, 0x47, 0x2f, 0xbf, 0xf6, 0x6c, 0xe5, + 0xed, 0x38, 0x9c, 0xb7, 0x27, 0x2a, 0x0d, 0x6f, 0xe3, 0x77, 0xec, 0xd4, + 0xa1, 0x87, 0x2f, 0xf3, 0xea, 0x40, 0x4e, 0x76, 0x72, 0xfb, 0x7b, 0x80, + 0x1c, 0xa8, 0x4d, 0x50, 0x24, 0x38, 0x26, 0x86, 0x5d, 0x50, 0x72, 0x1f, + 0xc9, 0xdb, 0x34, 0xbf, 0x90, 0x47, 0x38, 0xb9, 0xcb, 0xd2, 0x53, 0xc7, + 0x2f, 0xa4, 0x0f, 0xe4, 0x72, 0xfb, 0x4a, 0x40, 0x0e, 0x54, 0x1e, 0x3a, + 0x12, 0x5f, 0xe4, 0x9d, 0xd8, 0x00, 0x41, 0xcb, 0x90, 0x27, 0x2f, 0xf9, + 0x17, 0xdc, 0x98, 0x60, 0x27, 0x2f, 0xa5, 0xec, 0x50, 0xe5, 0xe5, 0xc0, + 0x0e, 0x5e, 0xd4, 0x30, 0xe5, 0x39, 0xed, 0xfe, 0x46, 0xd8, 0xe5, 0xf4, + 0xea, 0x64, 0xc7, 0x2f, 0x46, 0xa7, 0x39, 0x50, 0x78, 0x48, 0x4b, 0x7a, + 0x06, 0x47, 0x2f, 0xbc, 0x29, 0xc0, 0x72, 0x82, 0xa9, 0x7b, 0x92, 0xc9, + 0x99, 0x74, 0x40, 0xc3, 0x3e, 0x8b, 0x0c, 0x24, 0xf6, 0xe5, 0xe2, 0x0f, + 0xc6, 0xef, 0xf7, 0x5e, 0x5c, 0x1c, 0x1f, 0xce, 0x72, 0xee, 0xb4, 0x39, + 0x7f, 0xe8, 0xcd, 0xfc, 0x84, 0x0a, 0x92, 0x39, 0x7f, 0x23, 0x7b, 0x9f, + 0x1b, 0x39, 0x42, 0x7e, 0x1e, 0x40, 0xbf, 0x40, 0x7d, 0x8b, 0x39, 0x7a, + 0x05, 0x67, 0x2f, 0xff, 0xe7, 0x6c, 0x2e, 0xfa, 0x9f, 0xaf, 0xee, 0xa6, + 0xa4, 0x72, 0xba, 0x7e, 0xe2, 0x37, 0x52, 0x47, 0x06, 0xc8, 0x7d, 0x09, + 0xeb, 0xe7, 0x17, 0x98, 0xe5, 0xf9, 0x3c, 0x39, 0x23, 0x97, 0xd0, 0xdc, + 0x4c, 0x72, 0xe5, 0x18, 0x72, 0xfe, 0xf0, 0xb8, 0x30, 0x4e, 0x5f, 0x85, + 0xc1, 0x82, 0x72, 0xdf, 0xfc, 0x3d, 0x0f, 0x15, 0xd4, 0xe8, 0xfd, 0x54, + 0x85, 0x09, 0xba, 0x46, 0x2d, 0x17, 0xfa, 0x1b, 0x0f, 0xef, 0xa9, 0x1c, + 0xbf, 0x93, 0x5c, 0xee, 0x24, 0x72, 0xdc, 0x4e, 0x56, 0x8f, 0xdb, 0xa6, + 0xbc, 0x05, 0xd7, 0x85, 0x15, 0x39, 0x7d, 0x81, 0x4e, 0x27, 0x2e, 0x86, + 0x61, 0xbf, 0x71, 0xcb, 0xfe, 0xc6, 0xdf, 0x9e, 0xc2, 0x82, 0x72, 0xdb, + 0x39, 0x48, 0x7e, 0xba, 0x2a, 0x73, 0xab, 0x72, 0x72, 0xe0, 0x41, 0x4b, + 0x9b, 0x6c, 0xa5, 0x21, 0xaf, 0x6c, 0x5a, 0xfe, 0x90, 0xe7, 0xba, 0x85, + 0x3e, 0x9a, 0x1a, 0x0a, 0x28, 0x1d, 0x8a, 0xf3, 0xf3, 0xb3, 0x96, 0xd9, + 0xcb, 0xe5, 0x3a, 0xfe, 0x39, 0x41, 0x3d, 0x1e, 0x47, 0x7c, 0x23, 0x7a, + 0x06, 0x63, 0x97, 0x0c, 0x1c, 0xb4, 0xc7, 0x2a, 0x63, 0xc3, 0xd0, 0xe3, + 0x8a, 0xdf, 0xfc, 0xaa, 0x0a, 0xf7, 0x0c, 0x7e, 0x7c, 0x72, 0xf0, 0x33, + 0x80, 0xe5, 0x2a, 0x7c, 0x9a, 0x45, 0xbe, 0x66, 0xff, 0x61, 0xcb, 0x2a, + 0x72, 0xcd, 0x0e, 0x5d, 0xa5, 0x4e, 0x54, 0x1f, 0x0a, 0x12, 0x7e, 0x24, + 0xa0, 0x9d, 0xff, 0xf7, 0x72, 0x5b, 0x8f, 0x4b, 0x1a, 0xdc, 0x40, 0x72, + 0xff, 0x93, 0xdd, 0xce, 0x7d, 0xfc, 0x1c, 0xbe, 0x52, 0x34, 0x03, 0x95, + 0x23, 0xdd, 0xe9, 0xd5, 0xd9, 0xb3, 0x95, 0x06, 0xe2, 0x44, 0x55, 0xb4, + 0xc1, 0xbd, 0x0e, 0x6b, 0x00, 0xe5, 0xf9, 0x21, 0x90, 0xc3, 0x96, 0xc3, + 0x94, 0x87, 0xe0, 0xe5, 0x3b, 0x11, 0x68, 0x4d, 0x65, 0x4e, 0x54, 0x2b, + 0x8a, 0xc7, 0x34, 0x84, 0x9f, 0x61, 0x08, 0xf1, 0xd9, 0x70, 0x1e, 0x5e, + 0xdc, 0x4c, 0x72, 0xfe, 0xc0, 0xe7, 0x14, 0xd1, 0xca, 0x39, 0x66, 0x1c, + 0xaf, 0x17, 0x9c, 0x42, 0xef, 0x82, 0xef, 0xc9, 0xcb, 0xf0, 0x13, 0x48, + 0xa9, 0xcb, 0x9d, 0x53, 0x97, 0x67, 0x27, 0x2a, 0x64, 0xc0, 0x58, 0x3b, + 0xd4, 0xa7, 0x22, 0x01, 0x10, 0x94, 0x34, 0x17, 0xbb, 0x34, 0x72, 0xef, + 0x41, 0xcb, 0xf4, 0x77, 0x38, 0xb9, 0xca, 0x61, 0xea, 0x38, 0xb0, 0x05, + 0xaf, 0xe4, 0xf6, 0x75, 0xd5, 0x39, 0x7f, 0x77, 0xf7, 0x9f, 0xa8, 0x72, + 0xf3, 0x6d, 0xb6, 0x52, 0xff, 0x83, 0x13, 0xa9, 0x9d, 0x7e, 0x4a, 0x7d, + 0x34, 0x17, 0x64, 0xe7, 0x2f, 0x4a, 0x18, 0x72, 0x82, 0x8c, 0xf5, 0xa7, + 0xa2, 0x6c, 0xc2, 0xf7, 0xa1, 0x88, 0x72, 0xb0, 0xf6, 0x16, 0x7b, 0x7c, + 0x9a, 0xe0, 0x09, 0xcb, 0xf7, 0x63, 0x97, 0x6b, 0x39, 0x7f, 0xfd, 0x1e, + 0xd8, 0x73, 0xc9, 0xdf, 0xf3, 0x9f, 0x1c, 0xae, 0x9f, 0xe7, 0x8a, 0xed, + 0xa3, 0x97, 0xfb, 0x31, 0x6a, 0x71, 0xee, 0x1c, 0xbf, 0xe8, 0x1f, 0x0e, + 0x7a, 0x1b, 0x39, 0x7f, 0xb1, 0xbd, 0xa0, 0xf3, 0x23, 0x94, 0x87, 0xd7, + 0xa3, 0x7b, 0xde, 0xd7, 0xe7, 0x2d, 0xb3, 0x94, 0x26, 0xbf, 0xf1, 0xeb, + 0xff, 0xf6, 0x06, 0x33, 0x95, 0x3c, 0x83, 0xfc, 0xb3, 0x67, 0x2e, 0x60, + 0x0e, 0x5c, 0xe2, 0x72, 0xba, 0x6b, 0x1c, 0x5e, 0xfc, 0xc4, 0xf0, 0x1c, + 0xe5, 0x4e, 0xaa, 0xbb, 0x21, 0x42, 0xd6, 0x45, 0x30, 0x8e, 0xa1, 0x40, + 0xea, 0x02, 0x43, 0xe8, 0x41, 0x7e, 0x41, 0x76, 0x95, 0x39, 0x7d, 0xdf, + 0x24, 0xe7, 0x2f, 0xf2, 0xd3, 0x63, 0x9c, 0x5c, 0xe5, 0xf4, 0x4e, 0xf2, + 0x39, 0x7d, 0xed, 0xf5, 0x0e, 0x5f, 0xc2, 0xfe, 0x9f, 0x1b, 0x39, 0x47, + 0x28, 0x4d, 0xcf, 0x8b, 0xaa, 0x0f, 0xef, 0x16, 0xef, 0xd9, 0x38, 0xe7, + 0x27, 0x2f, 0xd9, 0xe4, 0x1d, 0x9c, 0xa8, 0x4d, 0xe7, 0x06, 0x39, 0x23, + 0xd1, 0x9f, 0x61, 0x3a, 0x24, 0x1b, 0x28, 0xbc, 0xa7, 0xea, 0x1c, 0xbc, + 0x28, 0xd6, 0x72, 0xf8, 0x2d, 0x1d, 0x53, 0x95, 0x07, 0x87, 0x83, 0xd7, + 0xbb, 0x01, 0x39, 0x76, 0xb6, 0x72, 0x8e, 0x21, 0x6f, 0x7f, 0xa0, 0x64, + 0xec, 0xc0, 0x9c, 0xbe, 0xf3, 0x19, 0xa3, 0x97, 0xff, 0x02, 0x05, 0x6f, + 0xe0, 0x28, 0x32, 0x39, 0x7a, 0x49, 0xd3, 0x97, 0xde, 0x1c, 0x91, 0xcb, + 0xef, 0xf8, 0x7d, 0xb9, 0xcb, 0xf4, 0xe1, 0x77, 0x6c, 0xe5, 0x61, 0xe8, + 0xfe, 0x51, 0x7f, 0xf9, 0x37, 0xdc, 0x08, 0xe7, 0x11, 0xcd, 0x9c, 0xa9, + 0x27, 0x22, 0xa9, 0x8f, 0x24, 0x73, 0x22, 0x68, 0x70, 0x5c, 0xbc, 0x45, + 0x4d, 0x53, 0x78, 0x91, 0xc3, 0x15, 0xc4, 0x65, 0xf3, 0xc2, 0xa6, 0x46, + 0x21, 0x8e, 0xf7, 0x25, 0x67, 0x2b, 0x09, 0x45, 0x9e, 0x73, 0x1b, 0x4a, + 0x46, 0x65, 0x34, 0x30, 0x35, 0x0e, 0x66, 0x43, 0x37, 0xb2, 0xff, 0x5e, + 0x36, 0x90, 0x42, 0xeb, 0x87, 0x2e, 0x18, 0xd5, 0x37, 0x2b, 0x3f, 0xd2, + 0x82, 0xff, 0x68, 0xe2, 0xc6, 0xd9, 0x03, 0x43, 0x35, 0x23, 0xaa, 0xbf, + 0xef, 0xbe, 0x4c, 0xe0, 0xdf, 0xf0, 0x72, 0xff, 0xff, 0xbf, 0x8f, 0xbe, + 0xda, 0x75, 0xd3, 0xd9, 0xa0, 0x31, 0xe4, 0x72, 0xbe, 0xaa, 0x7f, 0x9e, + 0x3d, 0x90, 0x9f, 0x5f, 0xb4, 0xb7, 0x75, 0x9a, 0x2b, 0x75, 0xff, 0x9e, + 0x5f, 0x73, 0x4b, 0x77, 0x59, 0xa2, 0x70, 0x5b, 0xee, 0x22, 0x01, 0x86, + 0x97, 0x70, 0xc1, 0x39, 0x6e, 0x9c, 0xb6, 0xce, 0x57, 0xe6, 0x89, 0xa0, + 0x8d, 0xf2, 0xdd, 0xd6, 0x68, 0xb4, 0x57, 0xff, 0xb0, 0x3d, 0x75, 0x66, + 0x99, 0x37, 0xfb, 0x0e, 0x56, 0x8f, 0xf3, 0xa5, 0xd7, 0xcb, 0x71, 0x01, + 0xcb, 0xfe, 0x9b, 0x1a, 0xf7, 0xad, 0x3f, 0x8e, 0x5f, 0xd0, 0xe3, 0xf8, + 0x70, 0xe5, 0xff, 0xc3, 0x9c, 0x77, 0x9d, 0xc1, 0x50, 0x27, 0x2f, 0xf6, + 0x68, 0x19, 0x32, 0x9b, 0x39, 0x65, 0x4e, 0x5f, 0xf6, 0x44, 0xf9, 0x36, + 0x93, 0x67, 0x29, 0x0f, 0x2e, 0x61, 0x2b, 0xff, 0xf4, 0xf1, 0xe8, 0x0e, + 0xa3, 0xaf, 0xb1, 0xc0, 0x1c, 0xbf, 0xf4, 0x72, 0xed, 0x7d, 0x17, 0x6b, + 0x9c, 0xe5, 0xff, 0xa3, 0x40, 0xc4, 0xcd, 0x7b, 0xf3, 0x95, 0x08, 0xd7, + 0xea, 0xa6, 0xd1, 0x6d, 0x81, 0x4f, 0xb5, 0x11, 0x66, 0x84, 0x06, 0xe1, + 0xf3, 0x72, 0x48, 0xe5, 0xfe, 0xef, 0x7f, 0x55, 0x91, 0xb3, 0x97, 0xff, + 0xe4, 0xd8, 0xe7, 0x17, 0xf0, 0xe6, 0xfa, 0xf3, 0x1c, 0xbf, 0x47, 0xb6, + 0xa7, 0x4e, 0x54, 0x23, 0x2b, 0x05, 0xa6, 0x36, 0x15, 0x5b, 0xec, 0x03, + 0xf4, 0xe5, 0xdd, 0xd9, 0xcb, 0x7d, 0xe1, 0x17, 0x40, 0x5a, 0xb3, 0xec, + 0x85, 0x02, 0xc8, 0xa6, 0x21, 0x61, 0xef, 0x65, 0x0c, 0xfa, 0x31, 0x76, + 0x87, 0x6a, 0x10, 0xde, 0xdb, 0x36, 0x72, 0xff, 0xff, 0xdd, 0x80, 0x31, + 0xe5, 0xf3, 0xdd, 0xc6, 0x62, 0xe3, 0xb0, 0xc3, 0x97, 0xf2, 0x4f, 0xf1, + 0xc4, 0x07, 0x2f, 0x96, 0xee, 0xb3, 0x45, 0xb4, 0xbf, 0xff, 0xa1, 0xfd, + 0x1d, 0x8d, 0xa2, 0x49, 0x35, 0x81, 0x39, 0x7f, 0x76, 0x19, 0x08, 0x13, + 0x94, 0x89, 0xa6, 0xcc, 0xdb, 0xa2, 0xfd, 0x97, 0x79, 0x5e, 0xff, 0xdd, + 0x40, 0xbc, 0x83, 0xd4, 0x61, 0xcb, 0xfe, 0xcc, 0x5b, 0x4f, 0xfa, 0x9a, + 0x39, 0x7d, 0x1c, 0x71, 0x0e, 0x59, 0xa9, 0x39, 0x7f, 0xf6, 0x7a, 0x18, + 0x2e, 0xa8, 0xe0, 0x0e, 0x58, 0x07, 0x2a, 0x63, 0xe9, 0x11, 0x6f, 0x21, + 0x5f, 0xfb, 0xf8, 0x07, 0x62, 0x71, 0xcd, 0x9c, 0xbf, 0xe8, 0x94, 0x6a, + 0x78, 0xd4, 0xe7, 0x2f, 0xff, 0xf4, 0x20, 0xbf, 0xbf, 0xf6, 0x06, 0x18, + 0x1e, 0xc7, 0x27, 0x2f, 0xff, 0x85, 0x38, 0xa7, 0xbb, 0x1e, 0xdc, 0x71, + 0x83, 0x95, 0xa4, 0x58, 0xfe, 0xc1, 0x73, 0x84, 0xe5, 0xff, 0x46, 0xbe, + 0x6e, 0x3a, 0xe8, 0x72, 0xff, 0x75, 0x1e, 0x5e, 0x49, 0xce, 0x5f, 0x83, + 0x18, 0x28, 0x72, 0x9a, 0x95, 0xcd, 0xdc, 0x8d, 0xa9, 0x69, 0x73, 0x1f, + 0x68, 0xed, 0x90, 0x8b, 0xe9, 0x78, 0x9f, 0xee, 0x1d, 0x7e, 0x24, 0x6c, + 0x59, 0xa1, 0xca, 0x86, 0x77, 0xf2, 0xaf, 0xa0, 0xfe, 0x27, 0x2f, 0xfa, + 0x3c, 0x8b, 0x40, 0xf2, 0x27, 0x2f, 0x7f, 0xcc, 0x8e, 0x5f, 0xc2, 0xd1, + 0x35, 0x8a, 0x9c, 0xbf, 0x24, 0xec, 0x85, 0x9c, 0xbf, 0x3f, 0x32, 0x53, + 0x67, 0x2f, 0xfc, 0x93, 0x6f, 0x8b, 0x8c, 0xff, 0x84, 0xe5, 0xbe, 0xaa, + 0x9a, 0x56, 0x8b, 0xfa, 0x70, 0x23, 0xfe, 0x2f, 0xe2, 0x50, 0xa1, 0x55, + 0x7d, 0x55, 0x0e, 0x09, 0x42, 0xf7, 0x33, 0xa7, 0x2f, 0xda, 0x5b, 0xba, + 0xcd, 0x17, 0x2a, 0xfe, 0x70, 0xf6, 0x06, 0x73, 0x96, 0xfa, 0x13, 0xf8, + 0xc1, 0x7e, 0x9a, 0x5f, 0xb4, 0xb7, 0x75, 0x9a, 0x2e, 0xd5, 0xff, 0x24, + 0xa4, 0x82, 0x08, 0x91, 0xcb, 0xe4, 0xd3, 0x80, 0xe5, 0xbe, 0xe2, 0x23, + 0x1c, 0xd3, 0x66, 0xf5, 0x0f, 0x8f, 0x37, 0x39, 0x54, 0xa9, 0x30, 0x21, + 0x8e, 0x83, 0x0d, 0xd5, 0xa6, 0x49, 0x25, 0x7f, 0xd4, 0xd7, 0x0b, 0xbe, + 0xce, 0x95, 0x8d, 0x20, 0x67, 0x70, 0xa6, 0xf4, 0x30, 0xaf, 0xf7, 0xdc, + 0xd2, 0xdd, 0xd6, 0x68, 0xa9, 0xd7, 0xe1, 0xfb, 0xad, 0xec, 0xe5, 0xd3, + 0xb0, 0xe5, 0xfb, 0x96, 0x3b, 0x89, 0xca, 0x09, 0xbf, 0xfc, 0x62, 0xde, + 0x39, 0x7f, 0xd0, 0xf3, 0xfc, 0xe7, 0x70, 0x13, 0x94, 0x87, 0x9a, 0x22, + 0x37, 0xcb, 0x77, 0x59, 0xa2, 0xb9, 0x5f, 0xef, 0xb9, 0xa5, 0xbb, 0xac, + 0xd1, 0x67, 0x2e, 0x79, 0x1c, 0xbf, 0xa5, 0xee, 0x56, 0x9b, 0x39, 0x4e, + 0x78, 0xbf, 0x8b, 0x5f, 0xc9, 0xbc, 0x17, 0x6c, 0xe5, 0x69, 0x30, 0x2e, + 0x97, 0x0c, 0x21, 0xbc, 0x45, 0x7f, 0xfb, 0xd1, 0xbf, 0x9f, 0xef, 0xd1, + 0x34, 0xc8, 0x72, 0xfe, 0x46, 0x4f, 0xfe, 0xa4, 0x72, 0xfc, 0xcc, 0x99, + 0xc0, 0x72, 0xfa, 0x7e, 0xbf, 0x8e, 0x53, 0x9e, 0x5f, 0xe5, 0x17, 0xfa, + 0x3b, 0xf1, 0x8d, 0x5f, 0x09, 0xe3, 0x95, 0x89, 0x96, 0x75, 0x3c, 0x5e, + 0xf8, 0x91, 0x5f, 0xf0, 0xc3, 0x37, 0xfc, 0x9d, 0x53, 0x97, 0xed, 0x67, + 0x91, 0x87, 0x2f, 0x9c, 0x60, 0x27, 0x2f, 0xd3, 0x43, 0x21, 0x43, 0x97, + 0x49, 0x87, 0x2b, 0x0f, 0x00, 0x4a, 0x6f, 0xff, 0x75, 0x3e, 0x75, 0xd3, + 0xd1, 0x81, 0x43, 0x97, 0xed, 0x2d, 0xdd, 0x66, 0x89, 0x09, 0x7f, 0xff, + 0x6d, 0x34, 0xbe, 0xe7, 0xcd, 0x6b, 0x1b, 0x69, 0x0c, 0x39, 0x7f, 0xec, + 0x66, 0x3e, 0xa7, 0xf9, 0xcb, 0x0e, 0x5f, 0xee, 0x77, 0xe1, 0x86, 0x6c, + 0xe5, 0xff, 0xe7, 0x15, 0xfc, 0x08, 0xbc, 0xba, 0xf2, 0x39, 0x48, 0x7f, + 0xdf, 0x9a, 0x5f, 0xd8, 0x28, 0x0d, 0xc1, 0xcb, 0x7d, 0x92, 0x7d, 0x58, + 0x93, 0xc9, 0xa7, 0x58, 0x01, 0x0c, 0x0d, 0x91, 0x5c, 0x9d, 0x39, 0x7f, + 0xe7, 0x52, 0x61, 0x4f, 0x0c, 0x00, 0xe5, 0x49, 0x17, 0x3c, 0xb2, 0xf8, + 0x5a, 0xff, 0xee, 0xa3, 0x33, 0x7f, 0x39, 0x96, 0x78, 0xe5, 0xf4, 0xba, + 0xa6, 0xce, 0x54, 0x1f, 0x5e, 0x23, 0xdf, 0x35, 0x7d, 0x86, 0x1c, 0xbf, + 0xbb, 0xbd, 0xe6, 0xa7, 0x39, 0x74, 0x36, 0x72, 0xff, 0x81, 0x81, 0x17, + 0x04, 0x71, 0x39, 0x58, 0x7f, 0xe8, 0x5e, 0xe2, 0xf7, 0x99, 0xc6, 0x47, + 0x2f, 0xff, 0x76, 0x00, 0xc7, 0x96, 0xfd, 0x98, 0xc3, 0x96, 0xfb, 0x3b, + 0x22, 0xdc, 0x2d, 0xf9, 0x19, 0x12, 0x46, 0xdd, 0x31, 0xf6, 0x8e, 0x98, + 0x4f, 0xd6, 0x07, 0x95, 0x86, 0x30, 0x9c, 0xd9, 0x07, 0xa1, 0x4d, 0xf9, + 0x62, 0x83, 0xf7, 0xff, 0xb3, 0x9f, 0xa1, 0xfd, 0xf5, 0x2e, 0xb6, 0xe7, + 0x2f, 0xfe, 0xfb, 0xd7, 0xd8, 0xe7, 0xbd, 0x00, 0x39, 0x7f, 0xfb, 0xeb, + 0x1e, 0x5f, 0x73, 0x4b, 0x77, 0x59, 0xa2, 0x7c, 0x52, 0xd9, 0x66, 0xe8, + 0x82, 0xd7, 0x49, 0x20, 0xd4, 0x3a, 0x18, 0x9f, 0xd4, 0x5b, 0xff, 0xfb, + 0xf1, 0x75, 0x7e, 0x79, 0x58, 0x19, 0x67, 0x51, 0x87, 0x2e, 0x4e, 0x4e, + 0x5f, 0xff, 0x4a, 0x7e, 0x15, 0x0d, 0x5c, 0xeb, 0xd7, 0xcf, 0x9d, 0x68, + 0x72, 0xa4, 0x7f, 0x80, 0x17, 0xbf, 0xfc, 0x33, 0xf6, 0x13, 0xdb, 0x41, + 0xe6, 0x47, 0x2f, 0xfd, 0xe5, 0x60, 0x65, 0x9d, 0x46, 0x1c, 0xbf, 0xe5, + 0x60, 0x65, 0x9d, 0x46, 0x1c, 0xbe, 0xfc, 0x5d, 0x5f, 0x87, 0xed, 0xe3, + 0xeb, 0xf6, 0x80, 0x9d, 0x83, 0x94, 0xc3, 0xe3, 0xfc, 0xf2, 0xfd, 0x9a, + 0xcc, 0x98, 0xe5, 0xbe, 0xb1, 0x53, 0x4f, 0x61, 0xb4, 0xe4, 0x5b, 0x8c, + 0x8d, 0x42, 0x3b, 0xf6, 0x96, 0xee, 0xb3, 0x45, 0x64, 0xbf, 0xf3, 0xcb, + 0xee, 0x69, 0x6e, 0xeb, 0x34, 0x4d, 0xcb, 0x7d, 0xc4, 0x40, 0x30, 0xd2, + 0x96, 0x98, 0x4a, 0x43, 0x7e, 0xf9, 0x6e, 0xeb, 0x34, 0x4a, 0xcb, 0xff, + 0xed, 0x4e, 0x31, 0xa7, 0x08, 0xbe, 0xa3, 0x89, 0xca, 0xd1, 0xff, 0x7e, + 0x5d, 0x7e, 0x18, 0x0b, 0xf4, 0xe5, 0xfe, 0x84, 0x18, 0x94, 0x70, 0x1c, + 0xbf, 0x7d, 0x63, 0xcb, 0xee, 0x1f, 0xe2, 0x11, 0xec, 0x9a, 0xff, 0xde, + 0xcf, 0xb9, 0xa4, 0x9d, 0xd8, 0x72, 0xff, 0xf3, 0x52, 0xd5, 0x70, 0x9b, + 0xc7, 0x92, 0x66, 0xb0, 0xe5, 0xff, 0x93, 0x7f, 0xb0, 0x53, 0x8f, 0xee, + 0x72, 0xfe, 0x81, 0x75, 0xbb, 0x59, 0xca, 0x91, 0xf7, 0xb1, 0x06, 0xe0, + 0xe8, 0xe5, 0xfb, 0x4b, 0x77, 0x59, 0xa2, 0x5c, 0x5f, 0xf2, 0x3c, 0xbc, + 0x30, 0xcd, 0x9c, 0xbf, 0x49, 0xa2, 0x75, 0xce, 0x5e, 0x86, 0x90, 0x72, + 0xff, 0xfe, 0xcf, 0xd7, 0xd8, 0x18, 0x93, 0x86, 0x39, 0xd2, 0x1c, 0xbc, + 0x83, 0x07, 0x2a, 0x48, 0xba, 0x09, 0x4b, 0x58, 0xef, 0x15, 0xab, 0xff, + 0xbf, 0x90, 0xa4, 0xa3, 0xc3, 0xfc, 0x8e, 0x5f, 0xa3, 0x60, 0x67, 0x8e, + 0x5c, 0xfe, 0x43, 0xed, 0xea, 0x2d, 0xfd, 0x2e, 0xe0, 0xe2, 0xce, 0x5e, + 0x97, 0x7c, 0x72, 0xee, 0xc2, 0x1e, 0x4f, 0x4b, 0x2f, 0xfe, 0x14, 0x06, + 0xf5, 0x09, 0x27, 0xd9, 0xca, 0xc3, 0xee, 0x42, 0xcb, 0xfb, 0x48, 0xc1, + 0x79, 0x1c, 0xbf, 0xf7, 0x32, 0xcf, 0x66, 0x97, 0x18, 0x72, 0xf3, 0xcb, + 0xeb, 0x51, 0x5c, 0x40, 0x88, 0x63, 0x48, 0x8b, 0x05, 0xfa, 0x68, 0xf0, + 0xf1, 0xdc, 0x2b, 0xfd, 0x0e, 0x3f, 0xc8, 0x38, 0x0b, 0x2f, 0xfd, 0xfb, + 0x3e, 0xee, 0x07, 0xd9, 0xa3, 0x97, 0xfc, 0x1c, 0xfb, 0x1a, 0x4e, 0xfe, + 0x72, 0xdf, 0x51, 0x76, 0xe1, 0x93, 0x90, 0x1b, 0x85, 0xe7, 0xe8, 0x37, + 0xff, 0x7d, 0x79, 0x7d, 0xcd, 0x2d, 0xdd, 0x66, 0x88, 0xed, 0x7f, 0xde, + 0xee, 0x4b, 0xeb, 0x8e, 0xce, 0x5f, 0xdc, 0x30, 0xc2, 0xf0, 0x4e, 0x5d, + 0xff, 0x4e, 0x5f, 0xdc, 0x20, 0xe7, 0x5f, 0xc7, 0x2f, 0xff, 0xef, 0x49, + 0x03, 0xd4, 0xe3, 0xf3, 0x03, 0xa4, 0xfd, 0x67, 0x2f, 0xf6, 0x37, 0xb8, + 0x1f, 0x6c, 0xe5, 0xfc, 0x01, 0xce, 0x7d, 0x87, 0x2f, 0xce, 0xaf, 0x70, + 0x07, 0x2f, 0xe1, 0x03, 0xe9, 0xd4, 0x39, 0x50, 0x88, 0x2d, 0x16, 0xb9, + 0x45, 0xff, 0xff, 0xfb, 0xb1, 0xde, 0xb8, 0x45, 0xfe, 0x6f, 0xb1, 0xbf, + 0x9f, 0xbf, 0xc9, 0x67, 0x18, 0x39, 0x7f, 0xe4, 0xd7, 0xcd, 0x8e, 0x32, + 0x16, 0x72, 0xff, 0x7f, 0xe4, 0x7e, 0x2f, 0x23, 0x97, 0xf3, 0xf1, 0x0e, + 0x0a, 0xa7, 0x2d, 0x02, 0x7c, 0x8a, 0x1a, 0xdf, 0xf8, 0x7f, 0x97, 0xcc, + 0x41, 0x86, 0x1c, 0xbe, 0x5b, 0xba, 0xcd, 0x15, 0x0a, 0xff, 0xb3, 0xb8, + 0x2f, 0xad, 0x21, 0xca, 0x92, 0x7e, 0xea, 0xc2, 0x29, 0x70, 0xa3, 0x42, + 0x7d, 0x1f, 0xec, 0xba, 0xf3, 0x5b, 0xc1, 0xcb, 0xa5, 0x87, 0x2f, 0xfa, + 0x5e, 0x4d, 0x3a, 0xd0, 0x4e, 0x5e, 0x06, 0xf0, 0xe5, 0xfe, 0xdf, 0xf3, + 0x38, 0x5e, 0x63, 0x95, 0x23, 0xd2, 0xe4, 0x72, 0xfd, 0x21, 0x86, 0x2a, + 0x72, 0xff, 0xe6, 0x66, 0x87, 0x13, 0x8a, 0x69, 0xce, 0x57, 0x27, 0xd6, + 0xe5, 0x17, 0xfe, 0x1c, 0x9b, 0xdd, 0xcd, 0x26, 0xce, 0x5f, 0xfc, 0xec, + 0xf8, 0xc7, 0xf7, 0xce, 0xfb, 0x47, 0x2b, 0xa8, 0x87, 0x13, 0xeb, 0xf7, + 0x22, 0x8c, 0x43, 0x97, 0xe8, 0xe1, 0xa7, 0xc6, 0xce, 0x54, 0x26, 0x41, + 0x90, 0xa9, 0x42, 0x2d, 0x13, 0xdf, 0xe8, 0xf3, 0xf7, 0xe0, 0x60, 0xe5, + 0xff, 0xb3, 0xdb, 0xd6, 0x4d, 0xd4, 0x54, 0xe5, 0xff, 0x87, 0x15, 0xc6, + 0x23, 0x48, 0x61, 0xcb, 0xfe, 0xf8, 0xe3, 0x9c, 0x1f, 0x3b, 0xf9, 0xca, + 0x44, 0x5f, 0xba, 0x07, 0xe7, 0xf7, 0xfa, 0x51, 0xa9, 0xe3, 0x53, 0x9c, + 0xbf, 0xf6, 0xf0, 0x7d, 0xbc, 0x92, 0x74, 0xe5, 0xfd, 0xbc, 0xe2, 0x31, + 0xc9, 0xca, 0xd9, 0xf6, 0x78, 0xf6, 0xff, 0xfa, 0x01, 0x83, 0xf1, 0xfd, + 0xf3, 0xb8, 0x07, 0x39, 0x70, 0xce, 0x72, 0xa1, 0x32, 0xbc, 0x85, 0x0a, + 0x11, 0x0a, 0x8d, 0xfd, 0xc5, 0xd9, 0xd6, 0xdc, 0xe5, 0xff, 0xfe, 0x48, + 0xf3, 0xf7, 0xee, 0xfb, 0x83, 0xef, 0x80, 0x96, 0xce, 0x52, 0x22, 0x50, + 0x4c, 0x2f, 0x6f, 0xfd, 0x1c, 0xac, 0x37, 0xe8, 0x43, 0x7b, 0xd9, 0x39, + 0xcb, 0xf6, 0x2f, 0xf7, 0x9c, 0xe5, 0x74, 0xf1, 0x84, 0x76, 0xfd, 0x93, + 0xb8, 0xf1, 0x39, 0x7f, 0xff, 0xff, 0xa2, 0x5f, 0x3d, 0xd4, 0x8d, 0xfc, + 0xcf, 0xd7, 0x1c, 0x7e, 0x66, 0xb5, 0x9c, 0x7f, 0x7e, 0x9c, 0xbe, 0xe8, + 0xbf, 0x01, 0xca, 0xc4, 0xc1, 0xc4, 0x87, 0x65, 0x3e, 0x84, 0xcd, 0xff, + 0xff, 0x7e, 0xed, 0x69, 0x3f, 0x5d, 0x3d, 0x1d, 0x4f, 0x6f, 0x02, 0x72, + 0xff, 0xf0, 0xe7, 0x17, 0x96, 0x08, 0x46, 0x24, 0x72, 0xdf, 0x78, 0x46, + 0x63, 0xeb, 0x56, 0x61, 0xc3, 0x0c, 0x41, 0x8c, 0xec, 0x01, 0x85, 0xae, + 0x4a, 0x25, 0x55, 0x89, 0x63, 0xdc, 0x8b, 0x24, 0x22, 0x75, 0x1d, 0x73, + 0x10, 0x3b, 0x0f, 0x31, 0x8d, 0x6b, 0x71, 0x89, 0x7a, 0x36, 0xc6, 0x88, + 0x2a, 0x34, 0xdf, 0x2d, 0xdd, 0x66, 0x8a, 0xa1, 0x7f, 0xb5, 0x1c, 0x79, + 0x96, 0x78, 0xe5, 0x68, 0xf9, 0x3f, 0x2e, 0xbf, 0xf3, 0xcb, 0xee, 0x69, + 0x6e, 0xeb, 0x34, 0x4d, 0x6b, 0xe8, 0xd4, 0x78, 0xe5, 0xcf, 0xe3, 0x94, + 0x13, 0x6e, 0xc2, 0x1b, 0x7d, 0xc4, 0x63, 0xb0, 0x8d, 0xe1, 0x07, 0x7e, + 0xd2, 0xdd, 0xd6, 0x68, 0xab, 0x17, 0xfd, 0x12, 0x8d, 0x4f, 0x1a, 0x9c, + 0xe5, 0xbe, 0xe1, 0xf7, 0x09, 0xa5, 0xff, 0x76, 0x39, 0xf4, 0x75, 0xda, + 0xce, 0x5f, 0xfc, 0x0c, 0x1f, 0xb2, 0x06, 0xe7, 0x71, 0x39, 0x5f, 0x51, + 0x05, 0x07, 0x97, 0xed, 0xc4, 0xd1, 0xc9, 0xcb, 0xfe, 0x97, 0xdc, 0xd2, + 0xdd, 0xd6, 0x68, 0x91, 0x16, 0xfb, 0x87, 0xe0, 0xe5, 0x37, 0xed, 0x2d, + 0xdd, 0x66, 0x8b, 0x49, 0x7f, 0xe7, 0x97, 0xdc, 0xd2, 0xdd, 0xd6, 0x68, + 0x9f, 0x56, 0xfb, 0x88, 0x80, 0x61, 0xa5, 0xff, 0xef, 0xac, 0x79, 0x7d, + 0xcd, 0x2d, 0xdd, 0x66, 0x8a, 0x11, 0x7f, 0xf6, 0x37, 0xf7, 0xca, 0xbe, + 0xd3, 0xd0, 0x72, 0xfd, 0xef, 0xd6, 0xfb, 0x39, 0x7c, 0x93, 0xc6, 0x8e, + 0x53, 0x0f, 0x2f, 0xa5, 0x37, 0xed, 0x2d, 0xdd, 0x66, 0x8a, 0x3d, 0x7f, + 0xd1, 0x28, 0xd4, 0xf1, 0xa9, 0xce, 0x5f, 0xff, 0xff, 0xe5, 0x13, 0x53, + 0x47, 0x75, 0x9d, 0x75, 0x37, 0x8a, 0xb8, 0x82, 0x06, 0x26, 0xec, 0x1c, + 0xbf, 0x3e, 0xd3, 0xd0, 0x72, 0xff, 0xa2, 0x68, 0x18, 0x9b, 0xb0, 0x72, + 0xa1, 0x1d, 0xaa, 0xc2, 0x3c, 0x49, 0xaf, 0xff, 0xec, 0x0f, 0x61, 0x4f, + 0xbe, 0x17, 0x06, 0xf7, 0x00, 0x29, 0x79, 0xe5, 0xf6, 0x15, 0x07, 0x61, + 0x10, 0x9a, 0x7a, 0x32, 0x76, 0x86, 0x97, 0xff, 0x67, 0x7e, 0xf9, 0x57, + 0xda, 0x7a, 0x0e, 0x5b, 0xec, 0xea, 0xd2, 0x99, 0x2a, 0x83, 0xcc, 0x95, + 0x0d, 0xe3, 0xdc, 0xf3, 0xc0, 0xd2, 0x55, 0xc5, 0x45, 0x69, 0x96, 0xeb, + 0x94, 0xed, 0xcc, 0x2a, 0x52, 0x15, 0x53, 0x42, 0x53, 0xb0, 0xa8, 0x01, + 0x57, 0xa5, 0xd2, 0x5f, 0xef, 0xb9, 0xa5, 0xbb, 0xac, 0xd1, 0x11, 0x2f, + 0xec, 0xd2, 0xdd, 0xd6, 0x68, 0x8a, 0xd7, 0xfc, 0xd7, 0xf7, 0x34, 0xb7, + 0x75, 0x9a, 0x2b, 0x85, 0x7d, 0x44, 0x1b, 0x9c, 0xdf, 0xfe, 0x04, 0x0a, + 0xfe, 0xbf, 0x80, 0xa0, 0xc8, 0xe5, 0xf7, 0xd9, 0xe6, 0x6b, 0x39, 0x64, + 0xe4, 0xfd, 0x80, 0x99, 0x7d, 0x9d, 0x7f, 0x1c, 0xbf, 0xd8, 0x9a, 0x00, + 0x3f, 0xd9, 0xcb, 0x70, 0x82, 0x7a, 0xbb, 0x21, 0xbf, 0xff, 0xbd, 0xb4, + 0xeb, 0xa4, 0x90, 0x7d, 0xff, 0x75, 0x87, 0x2f, 0xda, 0x5b, 0xba, 0xcd, + 0x14, 0xf2, 0xff, 0x04, 0x1f, 0x21, 0xae, 0x24, 0x72, 0xff, 0x31, 0x03, + 0xfb, 0xea, 0x47, 0x2e, 0x62, 0x1c, 0xa8, 0x3c, 0xa5, 0x9a, 0x5f, 0xff, + 0xd1, 0xed, 0xfe, 0xc5, 0xa0, 0x23, 0x3a, 0x9f, 0xac, 0xe5, 0xfd, 0x0c, + 0xdc, 0x24, 0xe7, 0x2a, 0x48, 0x89, 0xf2, 0xe5, 0xf4, 0xa3, 0x27, 0x39, + 0x7f, 0xfe, 0xd7, 0xfa, 0xd4, 0x0e, 0x2a, 0x9d, 0xee, 0x28, 0x72, 0xb9, + 0x3f, 0x9d, 0x11, 0x5f, 0xfc, 0x92, 0xc1, 0x04, 0x31, 0x35, 0x23, 0x97, + 0xfa, 0x51, 0xa9, 0xe3, 0x53, 0x9c, 0xbe, 0xf8, 0x2f, 0x23, 0x97, 0xe7, + 0xce, 0xa3, 0x0e, 0x56, 0xcf, 0x27, 0x89, 0x1d, 0x42, 0x28, 0xb1, 0xfa, + 0xff, 0xb8, 0xbb, 0x3e, 0x07, 0xa8, 0xc3, 0x97, 0xfc, 0x30, 0xc8, 0x90, + 0xe3, 0x0e, 0x56, 0x1f, 0x9a, 0x1e, 0xdf, 0xf4, 0x0a, 0xf3, 0x8e, 0x7b, + 0x67, 0x2f, 0xcf, 0x3c, 0x6b, 0xf3, 0x95, 0xc3, 0x2e, 0x4f, 0xc1, 0x66, + 0x2d, 0x2a, 0x68, 0xb8, 0x41, 0x73, 0x0a, 0xa4, 0x84, 0xe3, 0x91, 0x8c, + 0x39, 0x37, 0x09, 0x4e, 0x24, 0x0d, 0x0e, 0x6f, 0xff, 0x3c, 0xbe, 0x84, + 0x5d, 0xbd, 0xee, 0x00, 0x72, 0xff, 0xf0, 0x01, 0xfe, 0xfe, 0xa8, 0x2e, + 0xc1, 0x83, 0x97, 0xff, 0x0e, 0x01, 0xc4, 0x1f, 0x58, 0x8c, 0x39, 0x5a, + 0x44, 0x8f, 0x93, 0x6f, 0xff, 0xf2, 0x08, 0x07, 0x3d, 0xdc, 0xfb, 0xd7, + 0xef, 0x52, 0x63, 0x95, 0xf5, 0x51, 0x40, 0x61, 0x8e, 0x90, 0xdd, 0xd9, + 0x1d, 0xb0, 0xe5, 0xf8, 0x63, 0xfe, 0x1f, 0x67, 0x2f, 0xe5, 0x74, 0xe1, + 0x71, 0x39, 0x41, 0x3e, 0xac, 0x10, 0x72, 0xdb, 0xff, 0x90, 0x3a, 0x7e, + 0x7e, 0xeb, 0x51, 0x39, 0xca, 0xfa, 0x7e, 0xbd, 0x2d, 0xb8, 0x30, 0x72, + 0xff, 0xfd, 0xd8, 0xd6, 0x49, 0x1f, 0xd8, 0x14, 0xfd, 0x65, 0x2f, 0xd1, + 0x20, 0x7f, 0x23, 0x97, 0xcb, 0x77, 0x59, 0xa2, 0xb3, 0x54, 0xc7, 0xaf, + 0xa2, 0x9b, 0xef, 0x23, 0x36, 0x72, 0xf2, 0xbb, 0x54, 0xe5, 0xfd, 0x3b, + 0x20, 0x65, 0xb3, 0x97, 0xde, 0xda, 0x9b, 0x39, 0x67, 0x39, 0x58, 0x6d, + 0x36, 0x49, 0x74, 0xe8, 0x72, 0xff, 0x6e, 0x64, 0x1e, 0xe7, 0x27, 0x2a, + 0x0f, 0x2f, 0x05, 0xef, 0xde, 0x02, 0x83, 0x23, 0x97, 0xff, 0xd0, 0xcf, + 0x66, 0x0f, 0xb7, 0xdc, 0x03, 0x9c, 0xbd, 0xfb, 0xec, 0xe5, 0xff, 0x64, + 0x93, 0xf6, 0xb6, 0xac, 0x0c, 0x39, 0x64, 0x39, 0x7f, 0x77, 0x04, 0x5f, + 0xc7, 0x36, 0x58, 0x5f, 0xb2, 0x69, 0xff, 0x01, 0xcb, 0xfb, 0xd1, 0xa0, + 0x44, 0xc7, 0x2d, 0xf6, 0x15, 0xc5, 0x04, 0x5b, 0x21, 0x57, 0xc9, 0x1a, + 0x11, 0x68, 0x7d, 0x8c, 0x5d, 0x6b, 0x72, 0x00, 0x14, 0x8a, 0x6e, 0xc7, + 0x7c, 0xa4, 0xa1, 0xd7, 0x01, 0x5d, 0xff, 0xba, 0x9e, 0x7d, 0x4f, 0x08, + 0x13, 0x97, 0xfe, 0xf7, 0xec, 0xc5, 0xeb, 0x97, 0x6c, 0xe5, 0xfe, 0xd4, + 0x2b, 0x82, 0x8a, 0x9c, 0xbf, 0xfd, 0x0d, 0xa8, 0xc1, 0xce, 0x7d, 0x18, + 0xd9, 0xcb, 0xf7, 0x90, 0x71, 0x87, 0x2f, 0xa4, 0xe3, 0xf7, 0x13, 0x25, + 0xe4, 0xfb, 0x48, 0x4a, 0x19, 0xf0, 0x26, 0x5f, 0xf9, 0xe5, 0xf7, 0x34, + 0xb7, 0x75, 0x9a, 0x24, 0x55, 0xff, 0xfb, 0xdd, 0xc1, 0xfb, 0xe7, 0x7e, + 0x76, 0xaa, 0xae, 0x72, 0xff, 0xcf, 0xef, 0xb0, 0x9a, 0x4f, 0x7e, 0x72, + 0xbe, 0xa3, 0x96, 0x13, 0x1d, 0x66, 0xfe, 0xcd, 0x2d, 0xdd, 0x66, 0x8b, + 0x25, 0x7e, 0x9d, 0x06, 0x5b, 0x39, 0x7f, 0xbf, 0x9f, 0xb1, 0xed, 0xa1, + 0xcb, 0xf7, 0xb6, 0xa6, 0xfe, 0xe1, 0xee, 0xe8, 0xa2, 0xbe, 0xa3, 0x63, + 0x21, 0x2d, 0x7f, 0xb8, 0x11, 0x91, 0xd5, 0x02, 0x72, 0xfe, 0xea, 0x6a, + 0x25, 0xb3, 0x97, 0xf3, 0x3c, 0x9d, 0x76, 0x1c, 0xbf, 0xfc, 0x9e, 0xee, + 0x7b, 0x06, 0x3d, 0x01, 0x39, 0x50, 0x7e, 0x8e, 0x5b, 0x7f, 0xce, 0x9e, + 0xff, 0x4f, 0xbf, 0xb8, 0x8f, 0x85, 0x9b, 0xf6, 0x14, 0x37, 0xf6, 0x69, + 0x6e, 0xeb, 0x34, 0x5b, 0x0b, 0xff, 0xfb, 0x84, 0xef, 0xc1, 0xcd, 0x7b, + 0x7d, 0x9b, 0xe7, 0xce, 0xb4, 0x39, 0x7b, 0x5f, 0xf4, 0xe5, 0xde, 0xfb, + 0x08, 0x89, 0xd3, 0x5d, 0x7d, 0x47, 0x92, 0x43, 0x0a, 0xf6, 0x6f, 0x0e, + 0x5f, 0x2d, 0xdd, 0x66, 0x8b, 0x6d, 0x7d, 0xb9, 0xdf, 0x47, 0x2b, 0x47, + 0xa3, 0xe2, 0xeb, 0xf9, 0x3b, 0xe4, 0x07, 0xe7, 0x2f, 0xfa, 0x25, 0x1a, + 0x9e, 0x35, 0x39, 0xcb, 0xe8, 0x9b, 0x68, 0x72, 0xa4, 0x98, 0xc6, 0x36, + 0x4c, 0x44, 0x25, 0xdc, 0x07, 0x57, 0xfe, 0x0e, 0x93, 0xf9, 0xfe, 0xef, + 0x5e, 0x39, 0x5f, 0x51, 0x23, 0x89, 0xb7, 0xff, 0xb0, 0x41, 0xf5, 0x8e, + 0x1c, 0xc1, 0x54, 0xe5, 0xee, 0x1b, 0xa1, 0x39, 0x7a, 0x7e, 0xa1, 0xcb, + 0xff, 0x70, 0xdc, 0x37, 0x0b, 0xfb, 0xb8, 0x30, 0x03, 0x97, 0x9a, 0x8f, + 0x0b, 0x35, 0x13, 0x97, 0xf4, 0x0c, 0x83, 0xfb, 0x0e, 0x5f, 0xf6, 0x6b, + 0x51, 0x27, 0xe5, 0xb3, 0x97, 0xcb, 0x77, 0x59, 0xa2, 0xf0, 0x5f, 0xbd, + 0xca, 0xd3, 0x47, 0x2f, 0xfc, 0xfe, 0x8e, 0x3a, 0xd6, 0x73, 0xb3, 0x95, + 0xa4, 0x4c, 0x30, 0xb8, 0x4a, 0x6f, 0xbc, 0xd3, 0x3a, 0x72, 0xfc, 0xc8, + 0x19, 0x39, 0xcb, 0xfa, 0x07, 0xdc, 0x5d, 0x67, 0x2f, 0xe9, 0x47, 0x18, + 0xd7, 0x27, 0x2a, 0x47, 0xbd, 0x85, 0xd7, 0xfa, 0x3c, 0xfd, 0xf8, 0x18, + 0x39, 0x7f, 0xe5, 0x19, 0xcc, 0xbd, 0x83, 0xed, 0x9c, 0xbb, 0x15, 0x39, + 0x50, 0x7b, 0x18, 0x83, 0x7c, 0x93, 0xe3, 0x0e, 0x5f, 0xb0, 0x41, 0xc1, + 0x07, 0x2f, 0xd0, 0xa7, 0xef, 0xb3, 0x97, 0xff, 0x32, 0x17, 0xf3, 0x07, + 0xf9, 0x66, 0xce, 0x5f, 0xee, 0xa3, 0x6a, 0xe9, 0xdb, 0x39, 0x7f, 0xff, + 0xe7, 0x4f, 0x3b, 0x1c, 0x40, 0xbe, 0xa6, 0xa4, 0xa4, 0xb0, 0x4e, 0x5f, + 0xd1, 0xcf, 0x32, 0x7e, 0x4e, 0x56, 0x26, 0x2c, 0xb4, 0x6e, 0x9b, 0x7e, + 0xd5, 0x7f, 0xf6, 0x77, 0xaf, 0x26, 0x24, 0x6a, 0x47, 0x2f, 0xa0, 0x64, + 0xd6, 0x72, 0xe8, 0x01, 0xca, 0x91, 0xfe, 0xaa, 0x87, 0xe2, 0x4a, 0xe1, + 0x17, 0x75, 0xf8, 0x62, 0x26, 0xa2, 0x3b, 0xc2, 0xc9, 0xf3, 0x98, 0x04, + 0xbb, 0x21, 0xa5, 0xc9, 0x7a, 0x12, 0x4d, 0x08, 0x46, 0x10, 0xf6, 0x11, + 0x8e, 0x40, 0x02, 0x21, 0x29, 0xdc, 0x67, 0xfe, 0x85, 0xdd, 0xfe, 0xe7, + 0xee, 0x01, 0xf5, 0xb3, 0x97, 0xf8, 0x1f, 0x66, 0x94, 0x0f, 0x8e, 0x57, + 0xd4, 0xe1, 0x62, 0x31, 0x9d, 0x1b, 0x5e, 0x4c, 0xe4, 0xe5, 0xf2, 0xdd, + 0xd6, 0x68, 0xbd, 0x17, 0xfe, 0x4f, 0x74, 0x5e, 0x40, 0x70, 0x1c, 0xad, + 0x1f, 0x5b, 0x0b, 0xaf, 0xfc, 0xe9, 0xef, 0xf4, 0xfc, 0x70, 0x27, 0x2f, + 0x31, 0x3c, 0x72, 0xff, 0x9f, 0xd2, 0x85, 0x7c, 0x93, 0x9c, 0xa6, 0x1e, + 0xb0, 0x8e, 0x5f, 0xb1, 0x9d, 0x70, 0x9c, 0xa0, 0xa7, 0x0f, 0x90, 0x87, + 0xe9, 0x12, 0x90, 0x96, 0xe0, 0x21, 0xbf, 0xff, 0xdc, 0x70, 0x7e, 0x87, + 0x03, 0xdc, 0x63, 0x1e, 0x58, 0x27, 0x2f, 0xf7, 0xdf, 0x64, 0xd2, 0x70, + 0x9c, 0xa4, 0x44, 0xc7, 0x58, 0xab, 0xea, 0x62, 0x59, 0x0f, 0x0a, 0x87, + 0x41, 0xb7, 0x3c, 0x31, 0x25, 0x09, 0xac, 0x9f, 0x44, 0x5c, 0x65, 0x29, + 0x2e, 0xba, 0x69, 0x40, 0x1a, 0x8d, 0x31, 0x91, 0x84, 0x76, 0x32, 0x10, + 0x46, 0xac, 0x31, 0xe9, 0x6c, 0x93, 0xf9, 0xfa, 0x66, 0xe5, 0x68, 0xdd, + 0xff, 0x4e, 0x5f, 0xfd, 0xfc, 0x4c, 0x39, 0xc5, 0xd8, 0xc4, 0x39, 0x7d, + 0x9d, 0x7f, 0x1c, 0xbf, 0xd8, 0x9a, 0x00, 0x3f, 0xd9, 0xcb, 0x70, 0x8a, + 0xa2, 0x6c, 0x51, 0xb6, 0x43, 0x7f, 0xfb, 0xdb, 0xfe, 0x37, 0x9e, 0x46, + 0x3c, 0x8e, 0x5e, 0x8e, 0x67, 0x39, 0x42, 0x7d, 0x1e, 0x4a, 0xbf, 0xef, + 0x6f, 0x39, 0x97, 0x7f, 0x54, 0xe5, 0x21, 0xef, 0x09, 0x0d, 0xf4, 0x71, + 0x89, 0x1c, 0xbf, 0x9f, 0x52, 0x1f, 0xdc, 0xe5, 0xc8, 0xc3, 0x95, 0xf9, + 0xe1, 0xf0, 0x16, 0xde, 0x77, 0x59, 0xa2, 0x23, 0x5f, 0x2a, 0xb7, 0xd1, + 0xca, 0x59, 0xe5, 0xa1, 0x45, 0xfb, 0x86, 0xf6, 0xdc, 0x07, 0x2b, 0x47, + 0x9c, 0xc2, 0x1b, 0xff, 0xee, 0xff, 0xbd, 0xe3, 0x07, 0x38, 0xfc, 0x86, + 0xa4, 0xe5, 0xff, 0x44, 0xfa, 0xcf, 0x79, 0x3c, 0x72, 0xf0, 0xc7, 0x27, + 0x2a, 0x47, 0xaa, 0x13, 0x9b, 0xfe, 0xcd, 0x66, 0xf1, 0xc6, 0x73, 0x97, + 0xb0, 0x2c, 0x39, 0x7f, 0xff, 0xba, 0xe9, 0xe8, 0xe8, 0xe7, 0xba, 0x9d, + 0xc4, 0x6c, 0xe5, 0xff, 0xff, 0xef, 0x79, 0x19, 0xa4, 0xce, 0x47, 0xff, + 0x47, 0x7e, 0x71, 0x4f, 0x4d, 0x07, 0x2f, 0xfb, 0x1c, 0x41, 0xaf, 0xe0, + 0x07, 0x2a, 0x13, 0x13, 0xc5, 0xed, 0x3e, 0xdf, 0xe7, 0x66, 0x6a, 0x50, + 0xc3, 0x97, 0x4e, 0xc2, 0x97, 0x36, 0xd9, 0x4b, 0xff, 0x7d, 0x5f, 0x52, + 0x6e, 0xc4, 0xff, 0x40, 0x6c, 0x5b, 0x18, 0xbe, 0xe3, 0x1e, 0x83, 0x95, + 0x23, 0xff, 0x45, 0xcb, 0xfb, 0x1d, 0x99, 0xcf, 0x8e, 0x5f, 0xf7, 0xf1, + 0xdc, 0x9a, 0x4f, 0x39, 0xcb, 0xfb, 0xee, 0xd3, 0x4e, 0x03, 0x95, 0x87, + 0xd4, 0xe7, 0x76, 0x6b, 0x39, 0x7f, 0xd1, 0x9c, 0xc3, 0xc9, 0xe4, 0x72, + 0xff, 0x07, 0x01, 0xf0, 0x70, 0x07, 0x2f, 0x99, 0xe0, 0x39, 0xca, 0x6a, + 0x91, 0x42, 0x11, 0x4c, 0x37, 0x73, 0x4b, 0xf0, 0xe7, 0x5f, 0xc7, 0x2f, + 0x7c, 0xda, 0xce, 0x53, 0x59, 0xe2, 0xf4, 0x9a, 0xff, 0x23, 0x83, 0x5a, + 0xff, 0xa7, 0x2f, 0xe8, 0x57, 0x05, 0x15, 0x39, 0x7f, 0x67, 0xb8, 0x3d, + 0x9d, 0x39, 0x58, 0x8b, 0x6e, 0x92, 0x89, 0xa6, 0xcb, 0x6f, 0xff, 0xe5, + 0xfd, 0xd3, 0x8a, 0x7b, 0xee, 0xa3, 0xc2, 0xe0, 0x39, 0x4d, 0x5b, 0x26, + 0xbb, 0x86, 0x85, 0x9c, 0x46, 0x03, 0x22, 0x00, 0xb3, 0x64, 0x2f, 0xd6, + 0x45, 0xcc, 0x2b, 0x90, 0x8a, 0x63, 0x7d, 0x46, 0x5f, 0xd2, 0xf7, 0x87, + 0x10, 0x08, 0x46, 0x12, 0xfb, 0x86, 0x0f, 0xa3, 0x3b, 0xe2, 0x77, 0x77, + 0x07, 0x4e, 0x5f, 0xb4, 0xb7, 0x75, 0x9a, 0x22, 0xe5, 0xfb, 0xc0, 0x50, + 0x64, 0x52, 0xfd, 0xbf, 0x76, 0x00, 0x72, 0xfc, 0xf3, 0xc6, 0xbf, 0x39, + 0x6f, 0xb3, 0xa3, 0x23, 0x06, 0x9c, 0xd3, 0xf2, 0x96, 0x85, 0x15, 0xf5, + 0x52, 0x64, 0xa3, 0xf8, 0xbf, 0xf9, 0x8f, 0x2f, 0xb9, 0xa5, 0xbb, 0xac, + 0xd1, 0x33, 0x2f, 0xee, 0x15, 0xc2, 0xfc, 0x26, 0xe3, 0xc7, 0x2f, 0x73, + 0x1b, 0x39, 0x7f, 0xfb, 0x84, 0xf4, 0xb3, 0xbd, 0x79, 0x22, 0x09, 0xcb, + 0xcb, 0x46, 0x1c, 0xbe, 0xe1, 0xbc, 0xe2, 0x72, 0xe6, 0x8d, 0x51, 0xcb, + 0xb3, 0xf3, 0x97, 0xff, 0x43, 0x1f, 0xd9, 0xc8, 0x18, 0xa7, 0x4e, 0x5f, + 0xff, 0x42, 0xf5, 0xfc, 0xfc, 0xed, 0x34, 0xbe, 0xe1, 0xca, 0xea, 0x26, + 0x45, 0x1a, 0xf9, 0x27, 0xfc, 0x4e, 0x5f, 0xb2, 0x7c, 0x04, 0xc7, 0x2b, + 0xe1, 0xe6, 0x78, 0x8e, 0xff, 0x7c, 0xc1, 0x7d, 0x01, 0xa1, 0xcb, 0xff, + 0xf3, 0x1f, 0xb9, 0xc8, 0x3a, 0xdb, 0xf6, 0x6e, 0xfe, 0x72, 0xfe, 0xcd, + 0xc2, 0x83, 0x07, 0x28, 0x28, 0xbc, 0xc3, 0x6e, 0xad, 0x5d, 0xbc, 0x39, + 0x77, 0x07, 0x8e, 0x5b, 0x87, 0x39, 0x60, 0x41, 0xb0, 0xfc, 0x6a, 0xff, + 0xff, 0xc8, 0x30, 0xb1, 0x86, 0x7c, 0x8d, 0x69, 0x38, 0xe9, 0xdc, 0x07, + 0x2f, 0x93, 0xd1, 0x23, 0x94, 0xd5, 0x2b, 0x45, 0x58, 0xf2, 0x42, 0xc2, + 0x66, 0xee, 0xc3, 0x81, 0xcb, 0xc0, 0x8d, 0xe2, 0x7e, 0x2d, 0x97, 0xf3, + 0x70, 0x23, 0x9e, 0x39, 0x7c, 0xfd, 0x49, 0x8e, 0x5f, 0x76, 0x68, 0x09, + 0xca, 0xc3, 0xf1, 0x59, 0x63, 0x91, 0x5f, 0x86, 0x3c, 0xf3, 0x1c, 0xbf, + 0xcb, 0x4c, 0x10, 0xf6, 0x0e, 0x51, 0xcb, 0xe7, 0xf4, 0x80, 0x72, 0xff, + 0xb6, 0x8b, 0x7c, 0xd6, 0x78, 0xe5, 0xfe, 0x7d, 0x24, 0x35, 0xa3, 0x0e, + 0x57, 0x51, 0x1b, 0xe2, 0x2e, 0x26, 0xf7, 0xff, 0xbe, 0x75, 0xd3, 0xc0, + 0xfc, 0x45, 0xe4, 0x72, 0xff, 0x94, 0x66, 0x6d, 0xdf, 0x99, 0x1c, 0xbc, + 0xd4, 0x5a, 0xae, 0x10, 0xe5, 0x42, 0x7a, 0x98, 0x4e, 0xb3, 0x14, 0x84, + 0xc3, 0x0c, 0x80, 0x96, 0x27, 0x57, 0xff, 0xff, 0xff, 0xff, 0x9a, 0x8f, + 0x09, 0x8d, 0x47, 0x86, 0xe1, 0x7e, 0x17, 0x5f, 0x0f, 0x1c, 0x2d, 0xc3, + 0x6a, 0x7e, 0x0c, 0xfc, 0x2d, 0x42, 0x1a, 0x72, 0xa7, 0x78, 0x68, 0x8e, + 0x19, 0xaf, 0x85, 0x7b, 0xe7, 0xce, 0xb4, 0x39, 0x7f, 0xfe, 0x07, 0x32, + 0xef, 0xf1, 0xaf, 0xbd, 0x45, 0xbe, 0x8e, 0x5f, 0xfb, 0xb8, 0x38, 0xae, + 0x0e, 0x04, 0xe5, 0xff, 0xdc, 0xb7, 0x1e, 0x0a, 0x35, 0xee, 0x18, 0x72, + 0xf9, 0x07, 0xdb, 0x39, 0x7f, 0xff, 0xcc, 0x4d, 0x77, 0xfd, 0xca, 0x38, + 0xea, 0x07, 0xdd, 0xc9, 0x1c, 0xa9, 0x22, 0x29, 0x08, 0x6f, 0xfc, 0x9e, + 0x45, 0xa0, 0x7d, 0x8b, 0x39, 0x52, 0x4d, 0xbb, 0x0f, 0x3d, 0x0d, 0x3e, + 0x02, 0x2b, 0xef, 0x34, 0xce, 0x9c, 0xbf, 0xff, 0xce, 0x2b, 0x1c, 0x0f, + 0x7f, 0xf9, 0xd8, 0x96, 0xa2, 0x73, 0x95, 0x88, 0x87, 0xfc, 0x92, 0xff, + 0xff, 0x3a, 0xa3, 0x80, 0xff, 0x7f, 0x24, 0x9d, 0x85, 0x8b, 0x9c, 0xbe, + 0x6e, 0x19, 0xe3, 0x97, 0x93, 0xa8, 0x72, 0xa0, 0xdf, 0x78, 0x8e, 0xff, + 0x9f, 0x52, 0xf9, 0x8b, 0x0e, 0x1c, 0xae, 0x19, 0x73, 0x96, 0x23, 0x34, + 0xc8, 0xf2, 0x3b, 0x0c, 0xc7, 0x23, 0x18, 0x50, 0x7e, 0x41, 0x6d, 0x1c, + 0xbf, 0xbd, 0x8c, 0xe7, 0x18, 0x72, 0xdd, 0xc3, 0x7e, 0x82, 0x37, 0xfb, + 0xf0, 0xbc, 0xb6, 0x92, 0x39, 0x7e, 0x5f, 0xe3, 0xed, 0x9c, 0xbe, 0x89, + 0x34, 0x6c, 0xe5, 0xff, 0x86, 0x16, 0xab, 0xe6, 0x90, 0x07, 0x2f, 0xed, + 0xe2, 0x6b, 0x4e, 0x72, 0xa7, 0x3e, 0x90, 0x1e, 0xdf, 0xff, 0x20, 0xcf, + 0x9b, 0x47, 0xef, 0xd6, 0xdb, 0x6c, 0xa5, 0x41, 0xfb, 0x84, 0x8e, 0xfe, + 0xe7, 0x3b, 0xff, 0x20, 0x39, 0x7e, 0xec, 0x4f, 0xdf, 0xce, 0x56, 0x1e, + 0xdf, 0x8c, 0x6f, 0xf8, 0x72, 0x15, 0x7f, 0x3a, 0xa7, 0x2f, 0xd2, 0xd8, + 0x3f, 0x98, 0xe5, 0xe5, 0xfe, 0xb3, 0x95, 0xc9, 0xe4, 0xfe, 0x57, 0x7f, + 0xd3, 0xe0, 0x03, 0xfb, 0xea, 0x47, 0x2f, 0xe7, 0x70, 0xf1, 0xc0, 0x9c, + 0xbc, 0xee, 0xb3, 0x45, 0x9e, 0xbf, 0x80, 0xe3, 0x24, 0x61, 0xca, 0x9d, + 0x17, 0xa1, 0x3b, 0x59, 0x70, 0x0a, 0x2f, 0xf7, 0x7d, 0xb7, 0xe5, 0x46, + 0x1c, 0xbf, 0xee, 0xc4, 0x93, 0xd1, 0xed, 0x9c, 0xa8, 0x3e, 0xe4, 0x36, + 0xbf, 0xfd, 0xae, 0xbf, 0xcc, 0xe2, 0x39, 0xbc, 0x13, 0x97, 0xfd, 0x08, + 0x1c, 0x63, 0x79, 0xd3, 0x97, 0xff, 0x6f, 0xc9, 0x33, 0x6e, 0x18, 0xe7, + 0x67, 0x29, 0x11, 0x94, 0xe9, 0x7f, 0x9c, 0x5e, 0x6d, 0xb6, 0xca, 0x5f, + 0xf9, 0xe5, 0xb1, 0xc5, 0x87, 0x34, 0x53, 0xe9, 0xa0, 0xbf, 0x70, 0x7e, + 0xcc, 0x09, 0xcb, 0xfd, 0xee, 0xe7, 0x1f, 0x92, 0x61, 0xca, 0xc3, 0xe4, + 0xfc, 0xb2, 0xff, 0xdc, 0xc8, 0x7f, 0x07, 0xc5, 0xb0, 0x07, 0x2e, 0x85, + 0x4e, 0x5f, 0xf0, 0x60, 0x60, 0x12, 0xea, 0x1c, 0xa8, 0x44, 0x94, 0xe8, + 0x88, 0x2f, 0x7f, 0xba, 0x81, 0x17, 0x79, 0x8e, 0x5f, 0xe0, 0xf7, 0xf7, + 0x03, 0x4c, 0x39, 0x50, 0x7d, 0x08, 0x65, 0x7f, 0xa3, 0xe7, 0xb3, 0x7b, + 0x83, 0x97, 0xf0, 0x54, 0x0f, 0xfe, 0xd9, 0xcb, 0x26, 0x8f, 0x94, 0x4d, + 0x2f, 0x40, 0xaa, 0x72, 0xa4, 0xc8, 0x30, 0x09, 0x2e, 0x1a, 0x2a, 0x52, + 0xb8, 0xc1, 0x79, 0x7c, 0x42, 0x19, 0xa1, 0x03, 0xa8, 0x70, 0xb2, 0x15, + 0x9d, 0x87, 0x50, 0x13, 0xc6, 0x16, 0x7b, 0x85, 0xa7, 0xa1, 0x2f, 0xc6, + 0x10, 0xaa, 0x13, 0x5c, 0x0d, 0x9c, 0xbf, 0xef, 0xfd, 0xb1, 0xc9, 0xa1, + 0x87, 0x2f, 0x80, 0xed, 0xf8, 0xe5, 0xfe, 0x76, 0xfa, 0x91, 0xa8, 0x39, + 0x41, 0x45, 0x32, 0xa2, 0xe8, 0x75, 0xa2, 0x3b, 0xff, 0x69, 0x37, 0x25, + 0x3b, 0x03, 0x07, 0x2f, 0xb4, 0x90, 0xc3, 0x97, 0xff, 0xef, 0x2b, 0xfc, + 0x60, 0x7b, 0x9b, 0xe6, 0x51, 0xd3, 0x95, 0xa4, 0x5b, 0xb0, 0xf8, 0x48, + 0x6e, 0x79, 0x1c, 0xbf, 0xff, 0xff, 0x85, 0xdb, 0xf6, 0x74, 0x73, 0xdf, + 0x81, 0x8f, 0x27, 0x0c, 0x0b, 0xe9, 0xe4, 0x72, 0xff, 0x67, 0x7b, 0xff, + 0x9c, 0x4e, 0x5f, 0xf2, 0xf3, 0xab, 0x7d, 0x3c, 0x8e, 0x5e, 0x49, 0xb6, + 0x72, 0xa0, 0xf5, 0x58, 0x71, 0x64, 0x0a, 0x68, 0xb3, 0x0b, 0x6a, 0x10, + 0xcc, 0x84, 0x45, 0xfd, 0xf1, 0x3a, 0xec, 0x43, 0x97, 0xb8, 0xe0, 0x4e, + 0x5b, 0x53, 0x9e, 0x64, 0xc5, 0xd7, 0xfe, 0xc6, 0xf8, 0x35, 0x9c, 0x03, + 0xfb, 0x67, 0x2a, 0x15, 0x3f, 0xf6, 0x37, 0x47, 0x84, 0xd0, 0x95, 0x5f, + 0xff, 0xff, 0x03, 0x79, 0x82, 0xaa, 0x9a, 0x18, 0xce, 0xfd, 0xd8, 0xe4, + 0xec, 0xc6, 0x1c, 0xbf, 0x29, 0x02, 0xa3, 0x0e, 0x56, 0x22, 0xa3, 0xcf, + 0xf7, 0x03, 0x67, 0x2f, 0x9f, 0xb0, 0xa1, 0xca, 0xc3, 0x73, 0xc4, 0x5e, + 0xff, 0xfb, 0xfe, 0x65, 0xb0, 0xf6, 0x34, 0x17, 0x76, 0xce, 0x56, 0x23, + 0x41, 0x16, 0xc4, 0x8a, 0xf0, 0xb1, 0x0e, 0x5e, 0xdc, 0x4e, 0x72, 0xf0, + 0x62, 0x47, 0x2f, 0xfa, 0x31, 0x7d, 0x4e, 0x2f, 0xa3, 0x97, 0x67, 0x4e, + 0x53, 0x9f, 0x58, 0x8e, 0x34, 0x39, 0xbb, 0x02, 0x72, 0xa4, 0x98, 0xae, + 0x16, 0xec, 0x6f, 0xd0, 0x88, 0xe2, 0x5f, 0x7b, 0xbf, 0xb6, 0x72, 0xf0, + 0x3f, 0x59, 0xcb, 0xde, 0xc5, 0x0e, 0x5f, 0xe8, 0x67, 0xfb, 0xf6, 0x78, + 0xe5, 0xfd, 0x1c, 0xef, 0xe6, 0xa0, 0xe5, 0xe0, 0xfe, 0xb3, 0x97, 0xc1, + 0x18, 0x91, 0xca, 0x43, 0x7e, 0xe3, 0xd4, 0x14, 0xc7, 0x39, 0x1f, 0x41, + 0xe9, 0x87, 0x58, 0x69, 0xd6, 0xfb, 0xfc, 0x93, 0x38, 0xa7, 0x3b, 0x39, + 0x76, 0x2c, 0xe5, 0xfd, 0xa4, 0xe3, 0x83, 0xb3, 0x97, 0xf7, 0x3e, 0xce, + 0xfe, 0xd6, 0x72, 0xfe, 0xd6, 0x77, 0xbf, 0xf8, 0xe5, 0xfb, 0xa3, 0x19, + 0xa3, 0x17, 0xf6, 0x6a, 0x7f, 0xdc, 0x26, 0x88, 0x35, 0xf4, 0xd3, 0x5b, + 0x53, 0xa2, 0x8e, 0x4a, 0xb7, 0xc3, 0xdc, 0xe4, 0xe5, 0x42, 0x64, 0x49, + 0x0d, 0x67, 0x2a, 0xbf, 0x3a, 0xd1, 0x90, 0x72, 0xfe, 0x97, 0x45, 0xf9, + 0xf1, 0xca, 0x59, 0xea, 0x09, 0x35, 0xf2, 0x82, 0xf3, 0x9c, 0xac, 0x3c, + 0x4d, 0x90, 0xdf, 0xa3, 0xdf, 0x18, 0xd9, 0xcb, 0xfd, 0x24, 0x64, 0x75, + 0x40, 0x9c, 0xbf, 0xfd, 0x18, 0x3c, 0xfb, 0x34, 0x93, 0xbb, 0x0e, 0x5f, + 0x9d, 0xbf, 0x67, 0x76, 0x7f, 0xbe, 0x34, 0xaf, 0x8a, 0xdb, 0x1a, 0xb3, + 0x38, 0x16, 0x94, 0x6a, 0x19, 0x0c, 0xbd, 0x10, 0x8c, 0x2a, 0x2f, 0x6f, + 0x24, 0x72, 0xec, 0x50, 0xe5, 0xf0, 0x3b, 0x01, 0x39, 0x7f, 0xd0, 0x06, + 0x46, 0x0f, 0xb6, 0x72, 0x90, 0xf6, 0x7a, 0x45, 0x7e, 0x4e, 0x64, 0x82, + 0x72, 0xf2, 0x77, 0x0e, 0x5d, 0x0c, 0xc3, 0xc2, 0x59, 0x3d, 0xfc, 0xde, + 0x32, 0x34, 0xa9, 0xcb, 0xe0, 0xef, 0xb0, 0x72, 0xfc, 0x3a, 0x6d, 0xe7, + 0x39, 0x50, 0x7f, 0x58, 0x5e, 0xe4, 0x57, 0xec, 0xf6, 0xd1, 0x87, 0x2e, + 0xfc, 0x4e, 0x54, 0x27, 0xff, 0x21, 0xcc, 0x70, 0x46, 0x3d, 0x42, 0x98, + 0x4b, 0x36, 0x4f, 0x7b, 0xb8, 0x27, 0x2f, 0x3f, 0xa0, 0xe5, 0xfe, 0x9a, + 0x27, 0x63, 0xcd, 0x07, 0x2f, 0xff, 0x9d, 0x5f, 0x46, 0x81, 0xa8, 0xf0, + 0xb8, 0x0e, 0x5f, 0xc3, 0x80, 0xc1, 0x91, 0xcb, 0xff, 0xe5, 0x7e, 0x28, + 0x2f, 0xed, 0xa7, 0x3d, 0x46, 0xce, 0x58, 0x71, 0x10, 0x0e, 0x57, 0x58, + 0x9b, 0x06, 0x86, 0xdc, 0x6c, 0x4d, 0x7f, 0x86, 0x7d, 0xdb, 0xe2, 0x72, + 0xe4, 0xf1, 0xcb, 0xe4, 0x17, 0x09, 0xcb, 0xff, 0x33, 0x3d, 0xb5, 0x36, + 0xf2, 0xc3, 0x97, 0xed, 0xc6, 0xbd, 0x07, 0x3e, 0x9b, 0xfa, 0x0a, 0x26, + 0x36, 0xbf, 0x7e, 0x52, 0x67, 0x7d, 0x1c, 0xbe, 0xee, 0x27, 0x13, 0x97, + 0xf6, 0xd3, 0x59, 0xfe, 0x8e, 0x5f, 0xff, 0xd3, 0x7c, 0x45, 0xff, 0xad, + 0xff, 0xf1, 0x89, 0xee, 0xa1, 0xcb, 0xa1, 0x53, 0x95, 0x07, 0xf4, 0x8c, + 0x75, 0x89, 0xff, 0x2a, 0x32, 0x90, 0xae, 0x61, 0x1f, 0x4a, 0x7c, 0x47, + 0xc1, 0x0a, 0x8b, 0x99, 0xc2, 0x1a, 0x2f, 0xc5, 0xf6, 0xf5, 0x98, 0x72, + 0xff, 0xe9, 0x7b, 0xf9, 0x49, 0x9e, 0xf4, 0x30, 0xe5, 0xfe, 0xf6, 0xe2, + 0x7c, 0xd8, 0x4e, 0x5d, 0xdc, 0x39, 0x7f, 0xfd, 0xd8, 0x0e, 0x2f, 0xe6, + 0x0e, 0x07, 0xb0, 0x72, 0xff, 0xb5, 0x1d, 0x4e, 0x3a, 0x89, 0x1c, 0xbf, + 0xf9, 0x30, 0x73, 0x37, 0xf2, 0x5b, 0x61, 0xcb, 0xff, 0x3c, 0x73, 0x2f, + 0x9b, 0xe4, 0x30, 0x72, 0x82, 0x9e, 0x0f, 0x24, 0x28, 0x8e, 0xd6, 0x69, + 0x30, 0xb6, 0x93, 0xf6, 0x75, 0xe4, 0x4b, 0xca, 0xc6, 0x8e, 0x5f, 0xc1, + 0x80, 0x6b, 0x39, 0x39, 0x5f, 0x4f, 0x2d, 0x83, 0xb7, 0x2e, 0x73, 0x97, + 0xfa, 0x19, 0x89, 0xa9, 0xa4, 0x72, 0xe4, 0x98, 0xe5, 0xfe, 0xd4, 0x2a, + 0x11, 0x8e, 0x4e, 0x5f, 0xfe, 0xf4, 0x74, 0x5e, 0x78, 0xd6, 0x9e, 0x47, + 0x2f, 0x79, 0x27, 0x39, 0x7e, 0x03, 0xf3, 0x13, 0x1c, 0xbc, 0x30, 0xb3, + 0x97, 0xff, 0x05, 0x26, 0xec, 0x6b, 0x99, 0x46, 0x8e, 0x5f, 0xfe, 0x41, + 0x7e, 0x77, 0xbc, 0xd0, 0x7b, 0x87, 0x2b, 0xe2, 0x70, 0x92, 0x17, 0x43, + 0x46, 0x24, 0xb8, 0xe8, 0x94, 0xec, 0x6f, 0x81, 0x1a, 0xd0, 0x72, 0xf7, + 0x53, 0xc7, 0x2d, 0xc7, 0x0d, 0x62, 0x82, 0x15, 0x0b, 0xbb, 0x01, 0x71, + 0xc8, 0xfa, 0x92, 0x18, 0x2c, 0x24, 0xe8, 0xc3, 0xc7, 0x6e, 0x08, 0x50, + 0x5e, 0x63, 0xa8, 0x72, 0xff, 0xb0, 0x64, 0x38, 0xc8, 0x59, 0xcb, 0xf7, + 0x53, 0x8e, 0x04, 0xe5, 0xff, 0x83, 0x03, 0x83, 0xfc, 0xb3, 0x67, 0x2f, + 0xce, 0xc4, 0xe0, 0xc3, 0x97, 0xf6, 0x75, 0xfc, 0xf3, 0x1c, 0xba, 0x39, + 0x39, 0x5c, 0x9e, 0x27, 0x8b, 0x6b, 0x11, 0x20, 0xed, 0xb7, 0xa1, 0x26, + 0x39, 0x76, 0xb0, 0xe5, 0xe1, 0x6a, 0xb8, 0x0e, 0x5f, 0xb2, 0x76, 0x46, + 0xce, 0x5f, 0xff, 0xfa, 0x3a, 0x8c, 0xfb, 0x34, 0x9f, 0x4a, 0x75, 0x39, + 0xda, 0xd2, 0x73, 0x95, 0x3a, 0xa5, 0xa0, 0x8e, 0xaa, 0x6c, 0x85, 0x33, + 0x43, 0x37, 0xa4, 0x20, 0x1c, 0x11, 0x6d, 0x92, 0x70, 0x14, 0x5e, 0x4e, + 0xec, 0xe5, 0xf7, 0xc7, 0x93, 0x52, 0x72, 0xff, 0xec, 0xe3, 0x81, 0xc1, + 0xfe, 0x59, 0xb3, 0x97, 0xed, 0x47, 0x54, 0x09, 0xca, 0xd1, 0xf7, 0x3a, + 0x2d, 0xf4, 0x24, 0xf0, 0x72, 0xf9, 0xb7, 0xcd, 0x9c, 0xbf, 0x83, 0x00, + 0x1c, 0xe4, 0xe5, 0xff, 0x49, 0x8f, 0x2f, 0x6e, 0x15, 0x39, 0x50, 0x88, + 0x9c, 0x22, 0x72, 0xdb, 0xdb, 0x41, 0x39, 0x7e, 0x15, 0xfc, 0xdf, 0x27, + 0x2f, 0xf2, 0x92, 0x8e, 0x28, 0x20, 0x39, 0x58, 0x7f, 0x6e, 0x36, 0x25, + 0x75, 0x8a, 0x94, 0x9a, 0xc7, 0x1e, 0x12, 0xe0, 0x21, 0x18, 0x55, 0x7f, + 0x0a, 0x8b, 0xa7, 0x91, 0xcb, 0xc9, 0xd4, 0x39, 0x5c, 0x9b, 0x3f, 0x0c, + 0x5f, 0x29, 0xfb, 0xec, 0xe5, 0xff, 0x22, 0xb0, 0x18, 0xe3, 0x9d, 0x39, + 0x7f, 0xdd, 0x46, 0xf9, 0x96, 0xf1, 0x67, 0x2f, 0xef, 0xf7, 0x13, 0x7f, + 0xa3, 0x97, 0xbf, 0xce, 0x4e, 0x57, 0x4f, 0x3f, 0xc6, 0x37, 0xfa, 0x5f, + 0x8c, 0xfb, 0x4e, 0x4e, 0x5f, 0x00, 0x19, 0xc9, 0xcb, 0xfb, 0x83, 0xd8, + 0xe2, 0xb3, 0x97, 0xfd, 0xfb, 0xc8, 0x39, 0x80, 0xd9, 0xcb, 0xff, 0x73, + 0x2e, 0xc3, 0x1f, 0x99, 0x61, 0xcb, 0xf9, 0x39, 0xe6, 0x59, 0xe3, 0x95, + 0x87, 0xde, 0x04, 0x0a, 0xea, 0x32, 0x77, 0x0a, 0x8b, 0xf7, 0x3b, 0x62, + 0x35, 0x9c, 0xbf, 0xff, 0x66, 0xfe, 0x75, 0xd3, 0xc0, 0xfc, 0x45, 0xe4, + 0x72, 0xa1, 0x10, 0x42, 0x59, 0x7f, 0x3c, 0xe0, 0x71, 0x09, 0xca, 0x9d, + 0x59, 0x78, 0x4e, 0x97, 0x08, 0xa9, 0x88, 0xb4, 0x6d, 0xd2, 0x3f, 0x43, + 0xe3, 0x8c, 0x2a, 0x9a, 0x10, 0xde, 0xf6, 0x09, 0xcb, 0xdd, 0x76, 0xb3, + 0x97, 0xf9, 0x48, 0x5b, 0x4c, 0xd4, 0x1c, 0xbf, 0xe0, 0xe7, 0xfa, 0x9d, + 0x69, 0x39, 0xcb, 0xfa, 0x3a, 0x9a, 0x86, 0x1c, 0xa9, 0x23, 0x5d, 0x51, + 0xbe, 0x8f, 0xb9, 0xaf, 0x8f, 0x2a, 0x17, 0x42, 0x72, 0x5a, 0x9b, 0xc6, + 0xd9, 0x74, 0xdf, 0x9c, 0xb3, 0x0e, 0x57, 0x26, 0xab, 0x87, 0x19, 0xbf, + 0xde, 0x07, 0xe3, 0xb4, 0x09, 0xcb, 0xf4, 0x81, 0x98, 0x13, 0x97, 0xd1, + 0xac, 0xe2, 0x87, 0xb6, 0xe6, 0x97, 0xff, 0xa6, 0x18, 0xf6, 0xfd, 0xca, + 0xd0, 0x67, 0x39, 0x7e, 0x46, 0x29, 0x36, 0xce, 0x5f, 0xcf, 0xcc, 0x86, + 0x02, 0x72, 0xff, 0xa3, 0x99, 0x20, 0xb1, 0xfc, 0x72, 0x91, 0x1b, 0x7d, + 0x4c, 0x72, 0xa1, 0x2d, 0xbf, 0x3c, 0xb2, 0x78, 0x39, 0x7f, 0xf4, 0x6f, + 0x78, 0xcf, 0x0c, 0x33, 0x67, 0x2f, 0xfe, 0x48, 0xd8, 0xbc, 0xbe, 0x6f, + 0x34, 0x72, 0xff, 0xff, 0x26, 0xe7, 0xc6, 0xf0, 0x7f, 0xe0, 0x8f, 0xb8, + 0x2f, 0xa3, 0x97, 0xfb, 0x99, 0x6e, 0x69, 0x44, 0xe7, 0x28, 0x29, 0xa5, + 0x2c, 0x9c, 0x50, 0xfc, 0x89, 0xfb, 0x2d, 0xff, 0xff, 0xba, 0x9c, 0xfb, + 0x39, 0xf6, 0xb5, 0x1e, 0x02, 0x83, 0x2e, 0xe1, 0xcb, 0xf7, 0x63, 0x88, + 0x60, 0xe5, 0xe0, 0xb8, 0x9c, 0xb7, 0x13, 0x97, 0xee, 0x7c, 0x31, 0xd3, + 0x96, 0xd4, 0x1b, 0xb7, 0x13, 0xbb, 0xfd, 0x1c, 0xa9, 0x22, 0xf0, 0x25, + 0x3a, 0x56, 0xd9, 0x2d, 0xff, 0xa5, 0x03, 0xed, 0x27, 0x1c, 0x09, 0xcb, + 0xff, 0x3f, 0xb7, 0xfc, 0x94, 0x0a, 0x78, 0xe5, 0xec, 0x4d, 0x9c, 0xbf, + 0xfe, 0x9d, 0xfb, 0x81, 0xf9, 0x82, 0x38, 0x80, 0x39, 0x53, 0x9f, 0x56, + 0x86, 0xef, 0xfb, 0xab, 0x47, 0xf9, 0xb7, 0xe9, 0xca, 0xc3, 0xdd, 0x72, + 0x3b, 0xfb, 0xae, 0x3c, 0xc9, 0x0e, 0x5f, 0xff, 0xb6, 0x3f, 0x3a, 0xe9, + 0xe0, 0x7e, 0x22, 0xf2, 0x39, 0x7f, 0xba, 0x8a, 0xb4, 0xff, 0x4a, 0x9c, + 0xbf, 0xe8, 0x6d, 0x9d, 0x84, 0x19, 0xce, 0x5f, 0xff, 0x0e, 0x6f, 0x19, + 0x0b, 0xcf, 0x26, 0xb0, 0xe5, 0xb1, 0x68, 0xbe, 0xf1, 0xcf, 0x13, 0x9b, + 0xfa, 0x7c, 0xd2, 0x2e, 0x0e, 0x5f, 0x08, 0x61, 0x87, 0x2f, 0xff, 0xbf, + 0x1f, 0x6f, 0xa9, 0x30, 0xc3, 0x1e, 0x47, 0x2f, 0xb0, 0x7f, 0x73, 0x94, + 0xc3, 0xf1, 0xe2, 0xa1, 0x7f, 0x38, 0x30, 0x2f, 0x23, 0x95, 0x08, 0xe2, + 0xc8, 0x49, 0x21, 0x25, 0x22, 0x68, 0x3d, 0x8c, 0x3e, 0xa1, 0x92, 0x2b, + 0x3c, 0x20, 0x83, 0x18, 0x9e, 0x47, 0x08, 0xb4, 0xb4, 0x8c, 0xae, 0x63, + 0xd6, 0x1f, 0xf6, 0x30, 0x87, 0x20, 0x01, 0x68, 0xc6, 0x29, 0xe8, 0xde, + 0x2f, 0xfe, 0xc1, 0x06, 0x66, 0xb7, 0xe8, 0xc3, 0x97, 0xfd, 0xcf, 0xb3, + 0x49, 0x3b, 0xb0, 0xe5, 0xec, 0xe3, 0x87, 0x2d, 0x80, 0x44, 0xc0, 0xa0, + 0xec, 0xea, 0xf7, 0x0f, 0x24, 0x39, 0x7d, 0x02, 0xf2, 0x39, 0x7e, 0xc6, + 0xb7, 0x10, 0x7c, 0x3c, 0x1d, 0x10, 0xdf, 0xdc, 0x7a, 0x91, 0xad, 0x9c, + 0xbf, 0xf7, 0x51, 0x81, 0xc9, 0xa3, 0x34, 0x72, 0xf4, 0xa3, 0x93, 0x97, + 0xd0, 0x07, 0x61, 0xcb, 0x86, 0x58, 0x7f, 0x93, 0x1f, 0x08, 0xed, 0xf6, + 0xd3, 0xd0, 0x72, 0xa0, 0xf6, 0x9c, 0xe6, 0xff, 0xe5, 0xa6, 0xbe, 0x0b, + 0xce, 0x31, 0xc9, 0xcb, 0xe5, 0xf5, 0x26, 0x39, 0x7f, 0xfe, 0x1c, 0x55, + 0x54, 0x0f, 0x52, 0x6e, 0xa7, 0x3e, 0x39, 0x50, 0x7f, 0x78, 0x47, 0x79, + 0x6f, 0xa3, 0x97, 0xed, 0xae, 0x34, 0xa9, 0xcb, 0xf9, 0x01, 0xcc, 0xb3, + 0xc7, 0x2b, 0xa7, 0xe6, 0x01, 0xce, 0x25, 0x37, 0xf4, 0xb1, 0x03, 0xd4, + 0x39, 0x79, 0xf4, 0xa9, 0xca, 0xc3, 0xc9, 0x72, 0xcb, 0xff, 0xb3, 0x9f, + 0x6d, 0x06, 0x00, 0xec, 0x39, 0x7a, 0x4c, 0xe9, 0xca, 0x9c, 0xf8, 0x3c, + 0x87, 0x7f, 0x73, 0xbc, 0x64, 0x35, 0x9c, 0xbe, 0x45, 0x51, 0xb3, 0x95, + 0x87, 0xee, 0xe4, 0x62, 0x63, 0x77, 0xcc, 0x39, 0x7d, 0xb1, 0x86, 0x1c, + 0xa8, 0x37, 0x3c, 0x8c, 0x5e, 0xec, 0x98, 0x72, 0xee, 0xa1, 0xca, 0xc3, + 0x67, 0xe1, 0xda, 0x85, 0xd7, 0xa9, 0x3a, 0xe2, 0x12, 0xb1, 0x82, 0xf2, + 0x41, 0xd8, 0x60, 0xbc, 0x24, 0xc5, 0xeb, 0x70, 0xf7, 0xfd, 0x95, 0xa2, + 0xa5, 0xfe, 0x89, 0x93, 0x9d, 0xfe, 0xc3, 0x97, 0x31, 0x67, 0x2a, 0x73, + 0xcd, 0x09, 0xb5, 0xba, 0x72, 0xc0, 0x39, 0x76, 0xe4, 0x72, 0x80, 0x6e, + 0x76, 0x23, 0xf8, 0x8d, 0xfd, 0x3c, 0xd2, 0xe1, 0xb5, 0x39, 0xcb, 0xcf, + 0x9a, 0x39, 0x78, 0x73, 0xc7, 0x2b, 0xa6, 0xd8, 0x46, 0xee, 0xf0, 0x9c, + 0xbd, 0x1c, 0xec, 0xe5, 0xf2, 0x0c, 0xb0, 0xe5, 0xe9, 0xdc, 0x4e, 0x50, + 0x4f, 0x65, 0x83, 0xbe, 0x20, 0xbf, 0x67, 0xba, 0x9e, 0x39, 0x7e, 0x7e, + 0x73, 0x9f, 0x1c, 0xb2, 0xbd, 0x3d, 0x0f, 0x13, 0xdc, 0x9a, 0x39, 0x7f, + 0x4f, 0xf2, 0x77, 0x7e, 0x9c, 0xa6, 0xa9, 0x3e, 0xb8, 0x6d, 0x91, 0x06, + 0x37, 0xa3, 0xff, 0x4a, 0x5c, 0x5a, 0xff, 0xb0, 0x21, 0x4e, 0x73, 0x9f, + 0x1c, 0xbe, 0x58, 0xc4, 0x8e, 0x57, 0x4f, 0x6d, 0xce, 0xaf, 0xf4, 0x67, + 0xa3, 0xae, 0x13, 0x95, 0x39, 0xe9, 0x04, 0x86, 0xfc, 0x1f, 0xdf, 0x52, + 0x39, 0x7f, 0xf0, 0x60, 0x3a, 0x8f, 0x22, 0xd0, 0x27, 0x2f, 0xa6, 0x8e, + 0x09, 0x1c, 0xbf, 0xbc, 0xb0, 0x85, 0x9a, 0x39, 0x7f, 0xd3, 0x6f, 0x8b, + 0x8c, 0xff, 0x84, 0xe5, 0xf6, 0x7b, 0x18, 0x72, 0xe1, 0x54, 0xe5, 0xb6, + 0xe6, 0xe3, 0xf2, 0x1b, 0xfb, 0xbf, 0xcf, 0x37, 0x50, 0xe5, 0xff, 0xe1, + 0xfe, 0x59, 0xb5, 0xf5, 0x05, 0xe7, 0x39, 0x78, 0x73, 0xc7, 0x29, 0x0f, + 0x94, 0x52, 0xaa, 0x15, 0x1b, 0xc8, 0x8c, 0x25, 0x38, 0x86, 0xa9, 0x32, + 0x17, 0xcc, 0xed, 0xd2, 0x7f, 0x42, 0x5a, 0xfe, 0xf9, 0x34, 0x78, 0x78, + 0x9c, 0xbf, 0xfc, 0x31, 0xc7, 0x51, 0xac, 0x4e, 0xc0, 0x4e, 0x5c, 0xec, + 0x39, 0x74, 0xcd, 0x0e, 0x50, 0x9b, 0x0e, 0x22, 0xd5, 0x24, 0x66, 0xe1, + 0x92, 0x3c, 0xdb, 0xeb, 0x54, 0xfa, 0x67, 0xed, 0x5a, 0x07, 0x0c, 0x3b, + 0xc2, 0xe9, 0xad, 0x40, 0x72, 0x25, 0xb5, 0xcf, 0x18, 0x0c, 0xa5, 0x00, + 0x86, 0x75, 0x2f, 0x29, 0x1d, 0xca, 0xc7, 0x82, 0xb9, 0x6e, 0x7c, 0xca, + 0xd4, 0x48, 0xdb, 0x66, 0x97, 0x8b, 0xa9, 0x4f, 0x2c, 0x8f, 0x1b, 0xb4, + 0x82, 0x47, 0x95, 0xc0, 0x09, 0x5d, 0x1c, 0x3c, 0x27, 0x06, 0x74, 0xaf, + 0x74, 0x97, 0xcf, 0x4f, 0x77, 0x7f, 0x0f, 0xe6, 0xd7, 0x1a, 0x4a, 0x1a, + 0x52, 0x5a, 0x57, 0x04, 0x6a, 0x35, 0xf5, 0xf5, 0x7a, 0xfb, 0x7a, 0x72, + 0x37, 0xff, 0xbe, 0xb1, 0xe5, 0xf7, 0x34, 0xb7, 0x75, 0x9a, 0x26, 0xc5, + 0xfe, 0xfb, 0x9a, 0x5b, 0xba, 0xcd, 0x15, 0x6a, 0xff, 0x4a, 0x5f, 0xf8, + 0x62, 0x47, 0x2f, 0xb3, 0xaf, 0xe3, 0x96, 0xe1, 0x30, 0xf5, 0x44, 0xd2, + 0xff, 0xff, 0xd2, 0x8e, 0x30, 0x9a, 0x5a, 0x31, 0xe4, 0x83, 0x81, 0xc5, + 0x4e, 0x5f, 0xf6, 0x0e, 0x32, 0x25, 0xfe, 0x8e, 0x5f, 0xed, 0x62, 0xe0, + 0x0a, 0x30, 0xe5, 0xfe, 0xec, 0x4f, 0xa8, 0xc0, 0x9c, 0xbf, 0xff, 0x44, + 0xf1, 0xa8, 0x64, 0x47, 0xba, 0x80, 0x61, 0xca, 0x84, 0x43, 0xf4, 0xce, + 0xa4, 0x9c, 0x02, 0xda, 0xf4, 0x71, 0xd8, 0x5d, 0xdf, 0x69, 0x9d, 0x09, + 0xcb, 0xff, 0xb5, 0x21, 0xcf, 0x6e, 0x19, 0xe5, 0x9c, 0xa8, 0x3e, 0x7f, + 0xc8, 0xef, 0x07, 0x04, 0xe5, 0xe7, 0x75, 0x9a, 0x2b, 0x45, 0xf9, 0x5e, + 0x77, 0xff, 0x27, 0x29, 0x67, 0xaa, 0x85, 0x17, 0xff, 0x93, 0xd2, 0x85, + 0xf5, 0x3d, 0xb7, 0xe4, 0xe5, 0x68, 0xfa, 0xf8, 0x90, 0xdf, 0xe0, 0x83, + 0xe6, 0x69, 0x15, 0x39, 0x7f, 0xfb, 0xa8, 0xc8, 0x5e, 0x33, 0x07, 0xcd, + 0x0e, 0x5e, 0x97, 0x32, 0x39, 0x7f, 0xfc, 0xb8, 0xd6, 0x01, 0xd8, 0xf2, + 0x84, 0x59, 0xcb, 0xff, 0xe9, 0x6f, 0x06, 0x18, 0xf9, 0xef, 0x43, 0x0e, + 0x5d, 0xef, 0x42, 0x26, 0x9d, 0x36, 0xff, 0xff, 0xf4, 0x71, 0x4f, 0x6f, + 0x15, 0x5f, 0x53, 0xd9, 0x30, 0xc3, 0x27, 0xc6, 0xce, 0x5f, 0xe8, 0xf3, + 0xf7, 0xe0, 0x60, 0xe5, 0xf4, 0xbc, 0x93, 0x9c, 0xbf, 0x29, 0xe1, 0x80, + 0x1c, 0xae, 0x4f, 0x2f, 0x89, 0x1d, 0xfe, 0x79, 0x79, 0x27, 0xea, 0x1c, + 0xa8, 0x3d, 0x84, 0x25, 0xbf, 0x67, 0x53, 0x18, 0x72, 0xfc, 0x80, 0x62, + 0x68, 0xe5, 0xff, 0xc2, 0xe8, 0xbe, 0xbf, 0xf3, 0xe9, 0x0e, 0x54, 0xe8, + 0x91, 0x09, 0x37, 0x49, 0xef, 0xf4, 0xa3, 0x53, 0xc6, 0xa7, 0x39, 0x7d, + 0x2d, 0x63, 0x0e, 0x5e, 0xcd, 0x00, 0xe5, 0xfa, 0x6c, 0x0b, 0x1a, 0xce, + 0x5f, 0xc3, 0x0d, 0xf3, 0x2d, 0x9c, 0xae, 0x51, 0x32, 0x84, 0x53, 0x0e, + 0x70, 0x16, 0x54, 0x26, 0x1f, 0x90, 0xce, 0xbf, 0xff, 0xff, 0xb1, 0x17, + 0x9e, 0x81, 0xf6, 0xfe, 0x42, 0x07, 0x19, 0xf3, 0x50, 0x92, 0x7d, 0x9c, + 0xbf, 0xb3, 0xce, 0x20, 0xfc, 0xe5, 0xfd, 0xdf, 0x89, 0x3b, 0x89, 0xcb, + 0xfd, 0x0c, 0xd8, 0x45, 0xdb, 0x39, 0x7c, 0xe0, 0x70, 0x9c, 0xa9, 0x22, + 0xc3, 0x0b, 0x44, 0xbf, 0x66, 0x76, 0xfb, 0xc3, 0x32, 0x6e, 0x22, 0x3a, + 0xb9, 0xe1, 0x54, 0x12, 0x2c, 0x86, 0xda, 0xa4, 0x8b, 0x36, 0xe5, 0x29, + 0x21, 0x71, 0xa2, 0xd6, 0x3d, 0xf6, 0x1a, 0xef, 0x0b, 0x11, 0x8d, 0x03, + 0x64, 0xfe, 0x8c, 0xe2, 0xfd, 0xa5, 0xbb, 0xac, 0xd1, 0x60, 0x2f, 0xce, + 0xb5, 0x3b, 0x31, 0xcb, 0x7d, 0xc3, 0xde, 0xd9, 0xa5, 0xfb, 0x4b, 0x77, + 0x59, 0xa2, 0x75, 0x5f, 0xff, 0xee, 0xc4, 0xe1, 0xc6, 0x7d, 0xde, 0xf3, + 0xa9, 0xbf, 0xe7, 0x39, 0x7e, 0xfa, 0xc7, 0x97, 0xdc, 0x44, 0xd4, 0xc6, + 0x97, 0xff, 0xfa, 0x07, 0xf8, 0xf6, 0xf0, 0x7e, 0x80, 0x11, 0xd7, 0x9c, + 0xe5, 0xe5, 0x61, 0x87, 0x2f, 0x9d, 0x6a, 0x30, 0xe5, 0xe9, 0x6f, 0xea, + 0xa7, 0x81, 0xc4, 0x76, 0xfd, 0xa5, 0xbb, 0xac, 0xd1, 0x6c, 0xaf, 0xef, + 0x3f, 0x7e, 0x06, 0x0e, 0x5f, 0xff, 0xd2, 0xfb, 0xb8, 0x4c, 0x0a, 0x66, + 0xf3, 0xc3, 0x07, 0x2a, 0x11, 0x10, 0xe5, 0xf7, 0xe9, 0x42, 0x71, 0x83, + 0x97, 0xfd, 0x1b, 0xfb, 0xd4, 0x5b, 0xe8, 0xe5, 0x41, 0xf1, 0x00, 0xa2, + 0xff, 0xa2, 0x51, 0xa9, 0xe3, 0x53, 0x9c, 0xb7, 0xdc, 0x4e, 0x69, 0x90, + 0xbc, 0x78, 0x41, 0x89, 0x0d, 0xff, 0x87, 0xeb, 0x3f, 0x4f, 0x0b, 0xf0, + 0x1c, 0xbf, 0xfb, 0xfd, 0xfd, 0xcd, 0x3e, 0xfa, 0xf2, 0x39, 0x73, 0x83, + 0x11, 0x14, 0x04, 0x3b, 0xb9, 0x59, 0xcb, 0xe5, 0xbb, 0xac, 0xd1, 0x73, + 0x2c, 0xc3, 0x95, 0xa3, 0x7e, 0xd9, 0x75, 0xfe, 0xd0, 0xe7, 0x20, 0x49, + 0x1c, 0xba, 0x66, 0x1c, 0xa3, 0x96, 0xfb, 0x08, 0xcf, 0xc5, 0x74, 0x22, + 0x6c, 0xcd, 0xa0, 0xc5, 0xfb, 0x4b, 0x77, 0x59, 0xa2, 0xef, 0x5f, 0xe9, + 0x7d, 0xde, 0xb4, 0x8d, 0x9c, 0xb7, 0xdc, 0x3e, 0xb7, 0x34, 0xbe, 0xfa, + 0xa8, 0x40, 0x72, 0xa1, 0xfa, 0x30, 0xf2, 0xf5, 0x86, 0x16, 0x71, 0xca, + 0xd2, 0x52, 0x93, 0xb5, 0x1b, 0x8b, 0x21, 0x87, 0xd4, 0x47, 0x85, 0x10, + 0x23, 0xd3, 0x18, 0x6b, 0xee, 0x1f, 0x9e, 0x85, 0xea, 0x85, 0x17, 0xfe, + 0x6d, 0xc6, 0x7d, 0xa0, 0xf3, 0x23, 0x97, 0xff, 0x64, 0xf8, 0xdf, 0x73, + 0x78, 0x82, 0x72, 0xe4, 0xfb, 0xd4, 0x41, 0x8a, 0x05, 0xfb, 0x7b, 0x63, + 0xc8, 0xe5, 0xff, 0xff, 0xff, 0xba, 0x9d, 0x48, 0x1f, 0x0b, 0xab, 0x9e, + 0xff, 0xc9, 0xed, 0xf5, 0x35, 0x13, 0xbe, 0x96, 0x72, 0xed, 0xc1, 0xcb, + 0xff, 0xb9, 0x5f, 0xef, 0xcf, 0xb3, 0x05, 0x53, 0x97, 0x85, 0xfe, 0xc2, + 0x63, 0xcb, 0x28, 0xdc, 0x26, 0x7c, 0x2d, 0x7b, 0xf7, 0x61, 0xcb, 0xf6, + 0x70, 0x7a, 0x15, 0x39, 0x6e, 0x03, 0x95, 0x39, 0xbf, 0xc2, 0xba, 0xd1, + 0xfe, 0x8a, 0xe5, 0xff, 0xb6, 0xea, 0xf5, 0x20, 0x7f, 0x83, 0x97, 0xfe, + 0xeb, 0xf9, 0xfb, 0xcc, 0xb3, 0xc7, 0x2b, 0x0f, 0xf5, 0x0f, 0xae, 0x70, + 0x1c, 0xbf, 0xff, 0xfc, 0x2e, 0xd8, 0xe7, 0xbd, 0x93, 0xc0, 0xba, 0xbb, + 0x64, 0x60, 0x84, 0xe5, 0xec, 0x53, 0x67, 0x2b, 0x11, 0x51, 0xa1, 0x6e, + 0x07, 0x5b, 0xfd, 0xdc, 0x0a, 0x71, 0xd6, 0x1c, 0xbf, 0xcf, 0x2d, 0x63, + 0x44, 0x01, 0xcb, 0xce, 0xeb, 0x34, 0x4a, 0xeb, 0xfc, 0xab, 0x88, 0x3d, + 0x9d, 0x39, 0x4b, 0x3d, 0xb4, 0x28, 0xbf, 0xdc, 0x8b, 0xaa, 0xfe, 0x91, + 0xcb, 0xff, 0xbb, 0x92, 0x5f, 0x50, 0x30, 0x3e, 0x39, 0x48, 0x7e, 0xfe, + 0x34, 0xa9, 0x26, 0xf8, 0x13, 0x4d, 0x42, 0x3c, 0x61, 0x31, 0x7f, 0xa3, + 0x4f, 0x27, 0xe6, 0x47, 0x2f, 0xff, 0xff, 0xb4, 0xe2, 0xa4, 0x03, 0x25, + 0xd8, 0xe2, 0x18, 0xfb, 0x83, 0xfc, 0xb3, 0x67, 0x2e, 0x94, 0xe7, 0x2f, + 0xff, 0xf3, 0xf3, 0xbc, 0xd7, 0xbc, 0xf3, 0xa8, 0xc0, 0xf5, 0x15, 0x39, + 0x7f, 0xd8, 0x9c, 0x46, 0x33, 0x52, 0x39, 0x7f, 0xfe, 0xf4, 0xb1, 0xad, + 0xc4, 0x1c, 0xfb, 0x51, 0x8d, 0x9c, 0x6c, 0xdc, 0x5f, 0xb9, 0xf7, 0x60, + 0x07, 0x29, 0xd1, 0x27, 0xfb, 0x55, 0xff, 0xe9, 0x86, 0x3d, 0xbf, 0x72, + 0xb4, 0x19, 0xce, 0x5f, 0xf3, 0xb6, 0x1e, 0xc4, 0xf8, 0xd9, 0xca, 0x44, + 0x43, 0x8a, 0x65, 0xff, 0xfb, 0x10, 0x18, 0xc4, 0xf6, 0xe1, 0x8f, 0xcf, + 0x8e, 0x5f, 0xf4, 0x33, 0xd9, 0x34, 0x93, 0xc7, 0x2a, 0x48, 0x8d, 0xf2, + 0xa5, 0xf7, 0xef, 0xa9, 0x1c, 0xbf, 0x86, 0x27, 0x03, 0xf8, 0xe5, 0xfe, + 0x70, 0xa9, 0xc1, 0x03, 0x23, 0x96, 0x85, 0x9f, 0x1b, 0x0b, 0x6f, 0xff, + 0xf2, 0x79, 0xd8, 0xe2, 0x0e, 0xb6, 0xe3, 0x3a, 0xd2, 0x73, 0x94, 0x14, + 0xc3, 0x92, 0x10, 0xce, 0x4f, 0x7f, 0xdf, 0x81, 0x8f, 0x2d, 0xe8, 0x27, + 0x2f, 0xff, 0xf6, 0x20, 0xfb, 0x07, 0xe0, 0xb8, 0x60, 0x67, 0x8d, 0x1c, + 0xb6, 0x79, 0x13, 0x3c, 0x4e, 0xef, 0xfb, 0x90, 0x66, 0xb3, 0x3d, 0xb3, + 0x94, 0x15, 0x61, 0xf9, 0x0a, 0xee, 0xc6, 0x62, 0x30, 0xcd, 0x50, 0xaa, + 0xff, 0xd9, 0xde, 0xbc, 0x81, 0xac, 0xe4, 0xe5, 0xff, 0x67, 0x3b, 0x0c, + 0x38, 0xce, 0x72, 0xff, 0x9e, 0x5b, 0xec, 0x69, 0x40, 0x9c, 0xa9, 0x22, + 0xcb, 0x0f, 0xfc, 0x73, 0x7f, 0xf7, 0x93, 0x8a, 0x7a, 0x69, 0x40, 0xf8, + 0xe5, 0xff, 0xe7, 0xc9, 0x77, 0x10, 0x70, 0x0d, 0x30, 0xe5, 0xe7, 0x97, + 0xd8, 0x65, 0x6c, 0xca, 0x13, 0xc1, 0x86, 0x46, 0x47, 0x5d, 0xca, 0x3e, + 0x8c, 0xd9, 0x08, 0x00, 0x0c, 0x0c, 0x66, 0x1b, 0x97, 0x73, 0xe8, 0xc3, + 0x54, 0x2f, 0xe0, 0x46, 0xbf, 0xfd, 0x9d, 0xfa, 0x38, 0x14, 0x1f, 0x67, + 0x4e, 0x5e, 0xf4, 0x04, 0xa5, 0xff, 0xee, 0xba, 0x7a, 0x24, 0x9a, 0x9f, + 0xf0, 0x14, 0xbf, 0xce, 0xbf, 0xa1, 0xd7, 0x0f, 0xf6, 0x0f, 0x9f, 0x63, + 0x96, 0xfa, 0x16, 0x77, 0x6a, 0xe3, 0x4d, 0x65, 0x2e, 0xab, 0xd0, 0xf3, + 0xe3, 0x0b, 0x0b, 0xff, 0xdf, 0x58, 0xf2, 0xfb, 0x9a, 0x5b, 0xba, 0xcd, + 0x13, 0x0a, 0xff, 0xfe, 0xce, 0x2e, 0x1e, 0xc7, 0xdf, 0x77, 0x03, 0xff, + 0xb6, 0x72, 0xff, 0xf6, 0x9c, 0x1f, 0x55, 0xf4, 0x9b, 0x8d, 0xc8, 0xe5, + 0xd9, 0xf4, 0x51, 0x5e, 0xa3, 0x05, 0xcc, 0xe2, 0x72, 0xff, 0xee, 0x13, + 0x39, 0x97, 0xef, 0xe1, 0x89, 0x1c, 0xbf, 0x35, 0x6d, 0x5b, 0x52, 0xd1, + 0xaa, 0x39, 0x7e, 0xc6, 0x7c, 0xe5, 0xac, 0xe5, 0xfd, 0x0c, 0xc0, 0x47, + 0x13, 0x94, 0x13, 0xdc, 0xe9, 0x75, 0xfe, 0xd6, 0x2e, 0x00, 0xa3, 0x0e, + 0x5f, 0xd1, 0xa8, 0x62, 0x68, 0xe5, 0xfb, 0xb0, 0x14, 0x54, 0xe5, 0x22, + 0x2a, 0xb4, 0x44, 0xc3, 0x4e, 0x02, 0xcb, 0xdc, 0x5f, 0x67, 0x2f, 0xf4, + 0x3c, 0xfe, 0x55, 0xf4, 0x72, 0xfc, 0xfa, 0x93, 0xb0, 0xe5, 0x61, 0xfc, + 0x88, 0xf7, 0xe6, 0x97, 0xfb, 0x71, 0x82, 0x1e, 0xc1, 0xcb, 0xfa, 0x30, + 0x43, 0xd8, 0x39, 0x7b, 0xfd, 0x4d, 0xf0, 0xf7, 0x36, 0x63, 0x7f, 0xfb, + 0x49, 0xfe, 0x2b, 0x9e, 0xfe, 0x39, 0x09, 0xcb, 0xff, 0xf2, 0x6b, 0xaf, + 0xf0, 0x39, 0x2e, 0xc7, 0x10, 0xc1, 0xcb, 0xfe, 0x6d, 0x4e, 0xc2, 0xfa, + 0x93, 0x1c, 0xbe, 0xfd, 0x98, 0x13, 0x96, 0xce, 0x4f, 0x7f, 0x80, 0xf2, + 0xfe, 0x8d, 0x44, 0xb7, 0x87, 0x29, 0x69, 0xc9, 0xe8, 0xe3, 0xa9, 0xa3, + 0x0b, 0x7f, 0x15, 0xdf, 0xfe, 0x85, 0xef, 0xff, 0x27, 0x51, 0x5e, 0xa1, + 0xcb, 0xf9, 0x91, 0x83, 0xe6, 0x87, 0x2d, 0xb3, 0x97, 0xe8, 0xc1, 0xf3, + 0x43, 0x97, 0xb6, 0xfc, 0xfc, 0x3e, 0x79, 0x8b, 0x98, 0x23, 0x4c, 0x47, + 0xb7, 0xa1, 0x65, 0x7f, 0xcd, 0x78, 0x1e, 0xc3, 0x58, 0xc1, 0xcb, 0x75, + 0x0f, 0x95, 0xca, 0x2f, 0xef, 0x43, 0x38, 0x82, 0x47, 0x2e, 0xf2, 0x1c, + 0xa9, 0x1e, 0x32, 0xa6, 0x17, 0xb5, 0xfe, 0xce, 0x5f, 0xff, 0x76, 0x07, + 0x3d, 0xdc, 0xf7, 0x63, 0xfe, 0x1c, 0xe5, 0xff, 0xfe, 0x6f, 0x83, 0xd9, + 0xdf, 0x83, 0x93, 0xa6, 0x0f, 0x32, 0xd9, 0xcb, 0xf3, 0x7e, 0xce, 0xac, + 0xe5, 0x62, 0x24, 0x1d, 0x9e, 0xb1, 0x32, 0x34, 0x1e, 0x18, 0x72, 0x5f, + 0xfe, 0xf0, 0xb8, 0x3b, 0x88, 0x1f, 0xfd, 0xb3, 0x97, 0xdc, 0x70, 0x30, + 0x72, 0xff, 0xa2, 0x75, 0x25, 0xdf, 0xde, 0x73, 0x95, 0x08, 0xaa, 0xc4, + 0xad, 0x11, 0xdf, 0xfd, 0x9c, 0xcb, 0xe7, 0x5d, 0x70, 0x21, 0x39, 0x7c, + 0x91, 0xce, 0xce, 0x5f, 0x94, 0xf0, 0xc0, 0x0e, 0x57, 0x8f, 0x2b, 0x89, + 0x15, 0xf7, 0xbd, 0x8d, 0x9c, 0xbf, 0xfd, 0x1e, 0x04, 0x4b, 0x39, 0xf4, + 0xff, 0xb6, 0x72, 0xf6, 0xdc, 0x07, 0x2a, 0x11, 0x63, 0x84, 0x88, 0x47, + 0xe4, 0xeb, 0x9e, 0x47, 0x2f, 0xff, 0x26, 0xe2, 0x5f, 0x33, 0xa9, 0xae, + 0xb9, 0xca, 0x6b, 0x3e, 0x0e, 0x8b, 0x5f, 0xce, 0x0d, 0x69, 0x34, 0x72, + 0xf7, 0xbe, 0x61, 0xca, 0x01, 0xe5, 0xa8, 0x5b, 0x7d, 0xdf, 0xf9, 0xf1, + 0xcb, 0xff, 0x75, 0x3c, 0x98, 0xc1, 0xc9, 0xce, 0x5f, 0xdb, 0x45, 0x58, + 0xfe, 0x39, 0x7f, 0xff, 0xed, 0x67, 0x18, 0x1f, 0x7c, 0x50, 0x63, 0xae, + 0x9e, 0x8f, 0x6c, 0xe5, 0xfc, 0x39, 0xbf, 0x8b, 0xe1, 0x8e, 0x52, 0xd3, + 0x0d, 0xe4, 0xf7, 0x45, 0xdc, 0x5b, 0xaf, 0xbe, 0x71, 0xe0, 0x9c, 0xe5, + 0x05, 0x39, 0xec, 0x8c, 0xc9, 0x54, 0x1b, 0x35, 0x9c, 0xbf, 0x33, 0x58, + 0x1f, 0x1c, 0xbb, 0xd8, 0x72, 0xff, 0x83, 0x03, 0x00, 0x77, 0xe0, 0x39, + 0x7e, 0xde, 0x7b, 0x50, 0x72, 0xff, 0xf7, 0x0e, 0x30, 0xc7, 0x4e, 0xbf, + 0xbb, 0x07, 0x2a, 0x11, 0x84, 0x82, 0xdb, 0x39, 0xfc, 0x9e, 0xff, 0x75, + 0x26, 0x75, 0xee, 0x47, 0x2f, 0xdf, 0xf0, 0x26, 0x30, 0xe5, 0xfb, 0xce, + 0xc4, 0xf1, 0xca, 0x54, 0xf4, 0x84, 0xae, 0xff, 0xc9, 0xef, 0xf4, 0xfb, + 0xf8, 0xcf, 0x1c, 0xa8, 0x3e, 0x47, 0x22, 0xbf, 0xec, 0x4c, 0x60, 0xe4, + 0xee, 0x72, 0xfd, 0x1e, 0xd8, 0x3f, 0x39, 0x4d, 0x52, 0xaa, 0x38, 0x14, + 0xc8, 0x75, 0x2c, 0xf3, 0xb0, 0xea, 0x12, 0x0f, 0x1b, 0x5f, 0xff, 0xba, + 0x39, 0xee, 0xa6, 0x73, 0xec, 0xe3, 0x1b, 0x39, 0x7c, 0xfb, 0xf4, 0xe7, + 0x2f, 0xfe, 0x71, 0xec, 0x20, 0x53, 0x79, 0x23, 0x97, 0xa0, 0x0a, 0x1c, + 0xbf, 0xb3, 0x8f, 0x50, 0x13, 0x1c, 0xac, 0x4c, 0x1d, 0x55, 0x67, 0x23, + 0x14, 0x1d, 0x8e, 0xdf, 0x76, 0x37, 0x07, 0x2f, 0x28, 0x1c, 0x39, 0x7b, + 0x87, 0xdf, 0x0c, 0x72, 0x82, 0x7c, 0xae, 0x43, 0xb1, 0xdb, 0xef, 0x8c, + 0xf8, 0xb3, 0x97, 0xb1, 0x61, 0x39, 0x7d, 0xec, 0x10, 0x1c, 0xbf, 0x9d, + 0xb8, 0xf6, 0x4e, 0x72, 0xb0, 0xfa, 0xd0, 0x70, 0x48, 0x6f, 0x9b, 0x9b, + 0x70, 0x72, 0xff, 0xcf, 0xed, 0x87, 0x4f, 0xee, 0xfe, 0x72, 0xb9, 0x3e, + 0x41, 0x24, 0xb7, 0xd6, 0xa9, 0xb3, 0x63, 0xe1, 0x86, 0x5a, 0x82, 0x54, + 0x46, 0x8a, 0x18, 0x5c, 0x64, 0xa1, 0xd5, 0xc7, 0x55, 0xcb, 0x64, 0xd1, + 0xa3, 0x6a, 0x1b, 0xac, 0x2e, 0xec, 0x68, 0x2f, 0x09, 0xa0, 0x38, 0x0c, + 0x78, 0x3b, 0x95, 0xb5, 0xe8, 0xde, 0x7f, 0x85, 0x73, 0x65, 0xcd, 0x21, + 0x24, 0xa4, 0x24, 0x2f, 0xff, 0xb4, 0x9c, 0xcb, 0x69, 0xee, 0xc6, 0xbd, + 0x07, 0x2f, 0x3b, 0xac, 0xd1, 0x57, 0x2f, 0xe7, 0x53, 0xbd, 0x76, 0x1c, + 0xa5, 0x9e, 0xb7, 0x4a, 0x2f, 0xe4, 0xd7, 0x5d, 0x46, 0x1c, 0xad, 0x1e, + 0x87, 0x48, 0xaf, 0x87, 0x83, 0x6e, 0x72, 0xf6, 0xa1, 0x87, 0x2f, 0xf4, + 0x6b, 0xd0, 0x30, 0x03, 0x97, 0xfb, 0xee, 0x69, 0x6e, 0xeb, 0x34, 0x47, + 0x8b, 0xfe, 0xc0, 0xe7, 0x53, 0x5d, 0x73, 0x95, 0x23, 0xf8, 0x62, 0x0d, + 0xff, 0x44, 0xa3, 0x53, 0xc6, 0xa7, 0x39, 0x7f, 0xde, 0x4f, 0xf8, 0x7c, + 0x94, 0xf3, 0x1c, 0xbf, 0x87, 0x3d, 0xbc, 0x6c, 0xe5, 0x41, 0xf7, 0x3a, + 0x0d, 0xff, 0x72, 0xb4, 0xdf, 0x53, 0xc8, 0x72, 0xfd, 0xef, 0x60, 0x80, + 0xe5, 0xfe, 0xe0, 0x70, 0xc6, 0x05, 0x0e, 0x5b, 0xe8, 0x55, 0xbf, 0xe4, + 0x3d, 0x90, 0x8b, 0x44, 0x9d, 0x1c, 0x78, 0x54, 0x89, 0x16, 0xe1, 0x51, + 0xe2, 0x05, 0x0e, 0x78, 0x09, 0xef, 0xda, 0x5b, 0xba, 0xcd, 0x16, 0x0a, + 0xf2, 0xb1, 0x39, 0xcb, 0xff, 0xf8, 0x7f, 0x79, 0xd9, 0x8d, 0x3f, 0xd6, + 0x6a, 0x4a, 0x48, 0xe5, 0xfb, 0x07, 0x3d, 0xb3, 0x97, 0xfb, 0x4e, 0xc5, + 0x34, 0xfc, 0x9c, 0xb7, 0xdc, 0x4c, 0x39, 0x53, 0x45, 0x8f, 0x3b, 0x0a, + 0x84, 0xd7, 0xfb, 0xee, 0x69, 0x6e, 0xeb, 0x34, 0x59, 0x4b, 0xf6, 0x96, + 0xee, 0xb3, 0x45, 0xa6, 0xbf, 0xe7, 0x0f, 0x5e, 0x6e, 0xa3, 0x0e, 0x5b, + 0xee, 0x1f, 0x6b, 0x0d, 0x2f, 0xdc, 0x2e, 0xd4, 0x5a, 0xa6, 0xa9, 0xab, + 0x39, 0x7f, 0xdc, 0x37, 0x51, 0xb0, 0xbb, 0xac, 0xe5, 0xfb, 0x85, 0xf8, + 0x4d, 0xe4, 0x1c, 0xbf, 0xca, 0x33, 0x3d, 0xb4, 0xd9, 0xcb, 0x21, 0xca, + 0xe1, 0x8f, 0x11, 0xa1, 0xa5, 0xfe, 0x89, 0xf4, 0xe1, 0x9d, 0xce, 0x5f, + 0xff, 0xba, 0xe3, 0xe9, 0x66, 0xb2, 0x04, 0x73, 0xc7, 0x2a, 0x48, 0x85, + 0x43, 0x4b, 0xf7, 0x17, 0x0e, 0x30, 0xe5, 0xf3, 0x23, 0x9d, 0x9c, 0xbf, + 0xf9, 0x31, 0xc1, 0x12, 0xd4, 0x60, 0x9c, 0xbe, 0x4e, 0x3d, 0xe2, 0x72, + 0xff, 0x70, 0x20, 0x3e, 0x3f, 0x7f, 0x39, 0x52, 0x4c, 0x37, 0x08, 0xa6, + 0x29, 0x12, 0x3d, 0xa0, 0x70, 0x13, 0x5f, 0xe6, 0x28, 0xc0, 0x31, 0x00, + 0x72, 0xfd, 0xf3, 0x5a, 0xff, 0xa7, 0x2f, 0xc8, 0xac, 0x0a, 0xce, 0x56, + 0xcf, 0x4f, 0xc5, 0x95, 0x08, 0xaa, 0xc8, 0x44, 0x5f, 0xff, 0x0a, 0xfa, + 0x9d, 0x4d, 0x44, 0xcd, 0xe7, 0x4e, 0x5f, 0xfb, 0x69, 0xf3, 0xaf, 0xa8, + 0xe3, 0x07, 0x2f, 0xf9, 0x8f, 0x26, 0x9f, 0xf5, 0x34, 0x72, 0xb4, 0x7f, + 0xac, 0x41, 0xbf, 0x3e, 0xfd, 0x01, 0x39, 0x50, 0x79, 0x3f, 0x91, 0x5f, + 0xe7, 0xd4, 0x9f, 0xce, 0xb3, 0x95, 0x09, 0xb5, 0x76, 0x31, 0x6f, 0xc8, + 0xaf, 0xa1, 0x48, 0xe9, 0xcb, 0xe5, 0xbb, 0xac, 0xd1, 0x6e, 0x2f, 0xa6, + 0x80, 0xe1, 0xcb, 0xff, 0x66, 0xb0, 0x7e, 0x77, 0x39, 0x6c, 0xe5, 0xf8, + 0x40, 0xfc, 0xec, 0xe5, 0x41, 0xf4, 0xba, 0x0d, 0x72, 0x8f, 0xbd, 0x11, + 0x39, 0x76, 0xe1, 0x17, 0x7f, 0x9c, 0x41, 0x30, 0xc3, 0x0e, 0x5e, 0x60, + 0xa1, 0xcb, 0x09, 0xcb, 0xfe, 0xef, 0xef, 0xbc, 0xc1, 0x54, 0xe5, 0xfb, + 0x6f, 0xcb, 0x84, 0xe5, 0x90, 0x27, 0xc3, 0xe3, 0x9a, 0x84, 0x59, 0xe0, + 0xdf, 0x5c, 0x6f, 0xfa, 0x1c, 0x7b, 0x98, 0x2b, 0x39, 0x7f, 0xbd, 0xe4, + 0x9d, 0x90, 0x27, 0x2a, 0x47, 0xd1, 0x86, 0xb7, 0xfd, 0x03, 0xfb, 0x23, + 0x7e, 0x43, 0x97, 0xa3, 0x34, 0x72, 0xff, 0x76, 0x24, 0x8d, 0x31, 0x87, + 0x28, 0x27, 0x9f, 0xb1, 0xbb, 0xf7, 0xce, 0x76, 0x8a, 0x9c, 0xb3, 0xce, + 0x79, 0xdc, 0x91, 0x5f, 0xfd, 0x2c, 0xea, 0x68, 0x3d, 0x81, 0x59, 0xcb, + 0xfd, 0xcc, 0xa0, 0x7d, 0x80, 0x39, 0x7d, 0xb0, 0x27, 0x8e, 0x53, 0xa3, + 0x07, 0x65, 0x3f, 0xa1, 0xa8, 0x67, 0x7e, 0x7d, 0x7b, 0x3a, 0x72, 0xff, + 0xc8, 0x08, 0x90, 0x7b, 0x02, 0xb3, 0x95, 0x23, 0xe4, 0xf1, 0x3d, 0xfd, + 0xe9, 0x66, 0xb3, 0x67, 0x28, 0xe5, 0xef, 0xdf, 0xc7, 0x2e, 0xfe, 0x0e, + 0x54, 0x8d, 0xa7, 0x87, 0x68, 0xe5, 0xf7, 0x2b, 0x4d, 0x1c, 0xbd, 0x0c, + 0xfb, 0x88, 0x8e, 0xe4, 0xfd, 0x84, 0x3e, 0x0b, 0xbf, 0xe1, 0xf7, 0x5e, + 0x5f, 0xba, 0x87, 0x2a, 0x13, 0x67, 0xc2, 0x24, 0x85, 0xdb, 0xa8, 0x5e, + 0x1f, 0x34, 0x39, 0x7b, 0xe3, 0x56, 0xd5, 0x9c, 0xbf, 0xe9, 0x7d, 0xcd, + 0x2d, 0xdd, 0x66, 0x8a, 0x1d, 0x48, 0x88, 0xe9, 0x87, 0x9c, 0xa6, 0xfc, + 0x08, 0x5e, 0x30, 0xe5, 0xf4, 0x4d, 0x81, 0x39, 0x5a, 0x3c, 0x9d, 0x93, + 0xdf, 0xf6, 0x40, 0x7b, 0x1c, 0x11, 0x31, 0xcb, 0xfc, 0x04, 0xef, 0x70, + 0x0e, 0x72, 0x98, 0x7d, 0xa0, 0x3b, 0xa8, 0x45, 0x8b, 0xc2, 0x3e, 0xff, + 0xce, 0x18, 0x0f, 0x50, 0x51, 0x87, 0x2f, 0xfd, 0xc5, 0xf5, 0xb7, 0xee, + 0xe2, 0x73, 0x97, 0xfb, 0x7f, 0xaf, 0x3c, 0x30, 0x72, 0x98, 0x8b, 0x0e, + 0x9e, 0x79, 0x06, 0xff, 0xef, 0xe5, 0xd7, 0xd7, 0x3e, 0x84, 0x9c, 0xe5, + 0xfe, 0x94, 0x6a, 0x78, 0xd4, 0xe7, 0x2f, 0xcf, 0xbe, 0x39, 0xb3, 0x95, + 0x07, 0xbc, 0x03, 0x5b, 0xf7, 0xce, 0xe0, 0x1c, 0xe5, 0xfd, 0x27, 0xd6, + 0x73, 0xe3, 0x97, 0xf0, 0x5d, 0x9d, 0x46, 0xce, 0x54, 0x1e, 0xe6, 0x17, + 0x5f, 0xf6, 0x7b, 0x6a, 0x6f, 0x4f, 0xb3, 0x97, 0xe4, 0xf6, 0xdd, 0x0e, + 0x5f, 0xf6, 0x81, 0xa7, 0x1f, 0x60, 0x0e, 0x54, 0xe9, 0x9e, 0xea, 0x10, + 0xac, 0x20, 0x01, 0xd7, 0xe4, 0xd7, 0x94, 0xd4, 0x8e, 0x5f, 0xca, 0x7b, + 0xf8, 0xc9, 0xce, 0x5f, 0xc0, 0xeb, 0xa7, 0x7f, 0x39, 0x52, 0x3f, 0xc9, + 0x87, 0xb4, 0x61, 0x7f, 0xf2, 0xc6, 0x3c, 0x39, 0xc7, 0x35, 0x23, 0x97, + 0xfd, 0xf8, 0xaa, 0xa7, 0x7b, 0xfe, 0xce, 0x5f, 0xf2, 0x90, 0x09, 0xa5, + 0x1a, 0x9c, 0xe5, 0xfc, 0x2f, 0xe5, 0x21, 0x67, 0x29, 0x87, 0xd2, 0x27, + 0x97, 0xc2, 0x09, 0xc0, 0x72, 0xb0, 0xf1, 0x10, 0x86, 0xff, 0x6f, 0xe7, + 0xbe, 0x07, 0x04, 0xe5, 0x80, 0x72, 0xc9, 0xc9, 0xe4, 0x68, 0xde, 0xfc, + 0xfc, 0xef, 0xc8, 0x72, 0xa1, 0x50, 0xbe, 0x18, 0x22, 0x27, 0x61, 0xd6, + 0x2d, 0x1b, 0x28, 0xbf, 0x3f, 0xea, 0xc2, 0x87, 0x2f, 0xdc, 0x36, 0x6a, + 0x36, 0x72, 0xa6, 0x3d, 0x61, 0x2a, 0xbf, 0xb3, 0xc8, 0x1c, 0x61, 0xcb, + 0xe1, 0x92, 0x30, 0xe5, 0xbe, 0x4c, 0x79, 0xae, 0x59, 0x7f, 0xb7, 0x13, + 0x73, 0x2c, 0xe2, 0x72, 0x82, 0x7c, 0x2e, 0x55, 0x7f, 0xfe, 0x0f, 0x61, + 0x4f, 0xbe, 0x17, 0x06, 0xf7, 0x00, 0x29, 0x70, 0x70, 0xe5, 0xfa, 0x78, + 0x9d, 0xf6, 0x72, 0xb1, 0x12, 0xe8, 0xb0, 0xe2, 0xd7, 0x03, 0xf3, 0x97, + 0xf3, 0x82, 0x61, 0x80, 0x9c, 0xbf, 0xe1, 0xc9, 0xc3, 0xdc, 0x1f, 0x1c, + 0xa8, 0x3f, 0xde, 0x8c, 0x09, 0x6d, 0x35, 0x2d, 0xb7, 0x5b, 0x56, 0x8a, + 0xd4, 0x4f, 0xb8, 0x53, 0xbc, 0x47, 0x77, 0x28, 0xc1, 0x03, 0x1c, 0x86, + 0x46, 0x64, 0xaa, 0x12, 0xe1, 0xcb, 0xcc, 0x25, 0x90, 0x86, 0x68, 0xe5, + 0xb5, 0x28, 0x25, 0x90, 0xcd, 0xec, 0x65, 0x2f, 0x0d, 0x60, 0x18, 0x0c, + 0x29, 0x77, 0x1a, 0xf7, 0xa5, 0x72, 0xff, 0x0b, 0x0e, 0x30, 0xd0, 0x69, + 0x0b, 0x85, 0x21, 0x55, 0x7f, 0xfe, 0x5f, 0xd0, 0x6b, 0x39, 0x5f, 0x53, + 0xdb, 0x7e, 0x4e, 0x57, 0xd5, 0x45, 0x9f, 0xc7, 0xa5, 0x7d, 0x1a, 0x93, + 0x0e, 0x5f, 0x73, 0xb7, 0x6b, 0x39, 0x79, 0xf4, 0xa9, 0xcb, 0x7d, 0x9c, + 0xf9, 0x50, 0x89, 0xb2, 0x6b, 0xfd, 0xf7, 0x34, 0xb7, 0x75, 0x9a, 0x2f, + 0x35, 0x43, 0xb7, 0x22, 0x93, 0x88, 0x63, 0x09, 0xca, 0xce, 0x4f, 0x99, + 0xd0, 0x9d, 0x47, 0x7e, 0xc5, 0x3e, 0xc2, 0xb8, 0x6b, 0x94, 0x0d, 0xc2, + 0x4f, 0x89, 0xc5, 0xfe, 0xfb, 0x9a, 0x5b, 0xba, 0xcd, 0x14, 0xb2, 0xfd, + 0xa5, 0xbb, 0xac, 0xd1, 0x61, 0x2f, 0xff, 0xd1, 0x82, 0x18, 0xec, 0x73, + 0xec, 0x17, 0x61, 0xcb, 0x6c, 0xe5, 0xfd, 0xfe, 0x92, 0x77, 0x61, 0xcb, + 0x7d, 0xc4, 0x63, 0x30, 0xd3, 0x6a, 0x4d, 0x04, 0x6f, 0xf7, 0xdc, 0xd2, + 0xdd, 0xd6, 0x68, 0xb2, 0xd6, 0x91, 0xcb, 0xb4, 0xa9, 0xcb, 0xef, 0xaa, + 0xf0, 0xa6, 0xa4, 0xe5, 0x14, 0xbd, 0xf5, 0x46, 0x1c, 0xa5, 0x9e, 0xe6, + 0xcc, 0x7f, 0x0b, 0xa5, 0x51, 0x6a, 0x22, 0x3b, 0x74, 0xba, 0x3a, 0x72, + 0xc0, 0x39, 0x72, 0xb3, 0x9c, 0xb6, 0xa4, 0x6a, 0xb0, 0x46, 0x96, 0x7c, + 0xce, 0x81, 0x72, 0x00, 0xe5, 0xff, 0x3f, 0x23, 0x9c, 0xfa, 0x15, 0x39, + 0x7f, 0xa7, 0xe7, 0x70, 0x1f, 0x21, 0xcb, 0xf4, 0x67, 0x18, 0xd9, 0xcb, + 0x43, 0x9e, 0xeb, 0x66, 0xb4, 0xe8, 0xbe, 0x18, 0x4b, 0xdf, 0x3c, 0xa4, + 0x13, 0x97, 0xf3, 0xea, 0x3c, 0xfd, 0x39, 0x79, 0xb6, 0xdb, 0x29, 0x7f, + 0xd1, 0x2e, 0x7d, 0xa8, 0xce, 0x4a, 0x7d, 0x34, 0x17, 0xfd, 0xfb, 0xf3, + 0x9e, 0x4e, 0x5b, 0x39, 0x74, 0x6c, 0xe5, 0x05, 0x30, 0xce, 0x91, 0x0a, + 0x66, 0xd3, 0x38, 0x9e, 0x5d, 0xc2, 0x9a, 0x93, 0x97, 0xf2, 0x3e, 0xc1, + 0xbf, 0xce, 0x5f, 0xfc, 0x92, 0x7d, 0xb8, 0xfe, 0xbc, 0xd9, 0x4b, 0xff, + 0xfb, 0xa9, 0xee, 0xe6, 0xc7, 0x19, 0xfe, 0xfa, 0xf2, 0x39, 0x7f, 0xa2, + 0x5e, 0x7e, 0xb8, 0x4e, 0x54, 0x23, 0x43, 0x10, 0xf4, 0xb7, 0x69, 0x1c, + 0xb4, 0x8e, 0x5a, 0x47, 0x2a, 0x0d, 0x9a, 0xa2, 0x28, 0x23, 0x7f, 0x7f, + 0xbe, 0xbc, 0xb0, 0xe5, 0xff, 0xf6, 0xd1, 0x78, 0x3a, 0x81, 0xc0, 0xe2, + 0xa7, 0x29, 0x87, 0xf7, 0xe2, 0xeb, 0x72, 0x72, 0xca, 0x9c, 0xb7, 0xe7, + 0x28, 0x4d, 0x26, 0xc4, 0xab, 0x0f, 0xe3, 0x64, 0x5e, 0x36, 0xbb, 0x6a, + 0x9c, 0xb6, 0x1c, 0xbb, 0xf0, 0x41, 0xa8, 0x08, 0xc5, 0xc9, 0x07, 0x2f, + 0xe1, 0x86, 0x0c, 0x61, 0xcb, 0xff, 0xa1, 0xf5, 0xee, 0xe0, 0x7f, 0xf6, + 0xce, 0x5d, 0x28, 0x39, 0x53, 0xa3, 0x1c, 0x25, 0xb3, 0x0a, 0xf4, 0xab, + 0xf4, 0x5b, 0xff, 0xff, 0xee, 0xc7, 0xb6, 0x9b, 0xdc, 0x7b, 0xa9, 0x1a, + 0x03, 0x1e, 0x52, 0xf2, 0xa7, 0x2e, 0x4e, 0x4e, 0x5d, 0x0c, 0x39, 0x7f, + 0xfe, 0x81, 0xfe, 0x52, 0x8f, 0x77, 0x18, 0xa4, 0x00, 0xe5, 0xff, 0xf2, + 0x0f, 0xf2, 0xcd, 0xea, 0x12, 0x4f, 0xb2, 0x95, 0x24, 0x52, 0x79, 0x5a, + 0xe5, 0xfd, 0x86, 0x44, 0x34, 0xf0, 0x96, 0x91, 0x08, 0x61, 0xa9, 0x91, + 0x99, 0x2a, 0x98, 0xb2, 0x2d, 0x43, 0xf9, 0xd8, 0x46, 0x32, 0x0d, 0xc6, + 0x3b, 0xe4, 0xde, 0x2f, 0xcd, 0x05, 0xd4, 0x85, 0xd5, 0xff, 0xef, 0xac, + 0x79, 0x7d, 0xcd, 0x2d, 0xdd, 0x66, 0x8a, 0x31, 0x7e, 0xe3, 0x1a, 0x80, + 0x1c, 0xbf, 0x0b, 0x82, 0x14, 0x39, 0x7f, 0xe4, 0xe6, 0x5b, 0x1c, 0xf7, + 0x7f, 0x39, 0x7f, 0xc9, 0xae, 0xe6, 0x0c, 0xb6, 0x72, 0xdc, 0xc8, 0xfd, + 0xd6, 0x81, 0x7f, 0xe7, 0x92, 0xfa, 0x8c, 0x8d, 0x2a, 0x72, 0xdf, 0x61, + 0x32, 0xfe, 0x94, 0xfa, 0x13, 0xcd, 0x94, 0xd4, 0x99, 0xb4, 0x9a, 0x8c, + 0x1d, 0x88, 0xcf, 0x49, 0x7c, 0xdc, 0x60, 0xfe, 0x8e, 0x26, 0xff, 0xef, + 0xaf, 0x2f, 0xb9, 0xa5, 0xbb, 0xac, 0xd1, 0x1c, 0xaf, 0xff, 0x7d, 0x63, + 0xcb, 0xee, 0x69, 0x6e, 0xeb, 0x34, 0x4e, 0x4b, 0xfd, 0xf7, 0x34, 0xb7, + 0x75, 0x9a, 0x2c, 0xc5, 0xff, 0x4b, 0x6e, 0xcf, 0xbd, 0xf0, 0x0e, 0x5f, + 0xf7, 0x0b, 0x07, 0x19, 0x1c, 0xc3, 0x0e, 0x5f, 0xed, 0x47, 0xba, 0xfc, + 0xc8, 0xe5, 0xff, 0xff, 0xf4, 0x4d, 0xd8, 0xf4, 0x28, 0x9a, 0x9a, 0x3b, + 0x9c, 0x73, 0xb8, 0x1e, 0x38, 0x72, 0x80, 0x8b, 0x51, 0x34, 0xbf, 0xec, + 0xdb, 0xf8, 0x0a, 0x0c, 0x8e, 0x5f, 0xec, 0xde, 0xb5, 0x9c, 0xec, 0xe5, + 0xed, 0x63, 0x0e, 0x5f, 0x20, 0xe6, 0xce, 0x5b, 0x3c, 0x6f, 0x38, 0x07, + 0x2f, 0xfc, 0x83, 0x1b, 0x8f, 0x4f, 0x8d, 0x9c, 0xbb, 0xe2, 0x87, 0x2f, + 0xed, 0x2f, 0xae, 0x9c, 0x39, 0xcb, 0xf3, 0x8c, 0x71, 0xfc, 0xe5, 0xdc, + 0xb0, 0xe5, 0xbe, 0xb5, 0x2a, 0xad, 0x22, 0x1e, 0xb3, 0x91, 0x48, 0xe4, + 0x2e, 0x0c, 0x29, 0xd9, 0xf7, 0xe3, 0x5c, 0x4c, 0x9a, 0x14, 0xdf, 0xef, + 0xb9, 0xa5, 0xbb, 0xac, 0xd1, 0x6e, 0xaf, 0xe1, 0x7f, 0xba, 0x9f, 0xa7, + 0x2f, 0x27, 0x20, 0x39, 0x7f, 0xf6, 0x9d, 0x60, 0xff, 0x7e, 0x8e, 0x5b, + 0x39, 0x70, 0xaa, 0x72, 0xf9, 0x6e, 0xeb, 0x34, 0x52, 0x0a, 0xc3, 0xc5, + 0xd0, 0xbd, 0xfe, 0x97, 0x91, 0xbd, 0x81, 0x0e, 0x5f, 0xfb, 0x3a, 0x9c, + 0x7b, 0x98, 0x2b, 0x39, 0x79, 0xe5, 0xf4, 0x29, 0x90, 0x64, 0x23, 0x79, + 0x21, 0xd9, 0xa5, 0xfe, 0x40, 0xff, 0xed, 0xb0, 0x4e, 0x5e, 0x71, 0x91, + 0xcb, 0x7d, 0x5a, 0xa1, 0x2d, 0x18, 0x32, 0x33, 0xd7, 0x56, 0x6c, 0xd2, + 0xff, 0xef, 0xaf, 0x2f, 0xb9, 0xa5, 0xbb, 0xac, 0xd1, 0x29, 0x2a, 0x75, + 0xf8, 0x49, 0x95, 0x18, 0xb4, 0xe8, 0x20, 0x95, 0xe0, 0x30, 0xa4, 0xf4, + 0xa5, 0x3e, 0x05, 0xab, 0xf9, 0x07, 0xd8, 0x81, 0x39, 0x74, 0xbc, 0x72, + 0xf0, 0xc3, 0x67, 0x2e, 0x8f, 0xba, 0x36, 0x62, 0x2f, 0x52, 0x44, 0x5f, + 0x97, 0xaf, 0x6f, 0xf6, 0x1c, 0xb7, 0xde, 0x4f, 0x05, 0x08, 0xef, 0x0b, + 0xc8, 0xe5, 0xfb, 0x4b, 0x77, 0x59, 0xa2, 0x76, 0x5f, 0xfd, 0x9d, 0x17, + 0x97, 0xe0, 0x63, 0xc8, 0xe5, 0xe7, 0x97, 0xdc, 0x3f, 0x81, 0x34, 0xba, + 0x76, 0xb3, 0x97, 0xff, 0xe4, 0x0f, 0xec, 0x8e, 0x07, 0x08, 0xc0, 0xe2, + 0xce, 0x5f, 0xe9, 0x46, 0xa7, 0x8d, 0x4e, 0x72, 0xff, 0xdd, 0x17, 0x97, + 0xe0, 0x63, 0xc8, 0xe5, 0x41, 0xfa, 0x61, 0xad, 0xbe, 0xe2, 0x79, 0x6c, + 0x84, 0x9f, 0x4c, 0xdc, 0x6c, 0x61, 0x95, 0x7c, 0x9a, 0x8e, 0x27, 0x2f, + 0xfe, 0x68, 0xe2, 0x0c, 0xf4, 0x0a, 0x00, 0xe5, 0xbe, 0xec, 0xf9, 0x94, + 0x23, 0xbf, 0xf9, 0xd9, 0xdc, 0x5b, 0xf6, 0x14, 0x91, 0xcb, 0xc8, 0x17, + 0x39, 0x7f, 0xf0, 0xe7, 0x5e, 0x7c, 0xd8, 0xbf, 0x27, 0x2e, 0x69, 0xf4, + 0x28, 0xa2, 0xea, 0x26, 0xc6, 0xea, 0x4a, 0xf0, 0x99, 0x1f, 0xae, 0xe1, + 0x80, 0xd2, 0x19, 0xb7, 0xff, 0xf0, 0x5f, 0xdf, 0x73, 0x70, 0x3c, 0x83, + 0x7b, 0x80, 0x1c, 0xbf, 0x69, 0x6e, 0xeb, 0x34, 0x45, 0x8b, 0xff, 0x3c, + 0xbe, 0xe6, 0x96, 0xee, 0xb3, 0x44, 0xba, 0xbf, 0xff, 0xb0, 0x3d, 0x85, + 0x3e, 0xf8, 0x5c, 0x1b, 0xdc, 0x00, 0xa5, 0xbe, 0xe2, 0x37, 0x58, 0x68, + 0xd1, 0x32, 0xff, 0xe6, 0x3c, 0xbe, 0xe6, 0x96, 0xee, 0xb3, 0x44, 0xc4, + 0xbf, 0xfe, 0xc5, 0xc7, 0xde, 0xba, 0x34, 0x40, 0x60, 0x4e, 0x57, 0xd4, + 0x51, 0xf5, 0x4a, 0xfd, 0xa5, 0xbb, 0xac, 0xd1, 0x54, 0xad, 0x87, 0x2b, + 0x0f, 0x11, 0x53, 0x4b, 0xff, 0x7e, 0xfa, 0x90, 0xe3, 0x6e, 0x03, 0x97, + 0xff, 0x3e, 0xf4, 0x8d, 0xfb, 0xa9, 0xa9, 0x1c, 0xbf, 0xed, 0x3f, 0x79, + 0x96, 0x7b, 0xe8, 0x51, 0x09, 0xd3, 0xfa, 0xfa, 0x8f, 0xa7, 0x85, 0x35, + 0xff, 0xef, 0xac, 0x79, 0x7d, 0xcd, 0x2d, 0xdd, 0x66, 0x89, 0xd1, 0x7f, + 0x91, 0xf5, 0x12, 0x7e, 0x27, 0x2f, 0xd3, 0x44, 0xd1, 0xb3, 0x97, 0xf3, + 0x78, 0x9c, 0x70, 0x4e, 0x52, 0x1e, 0xbe, 0xca, 0x6f, 0x27, 0x60, 0xe7, + 0xd3, 0x43, 0x7f, 0xf7, 0xfb, 0xf4, 0x73, 0xf7, 0xf9, 0x91, 0x87, 0x29, + 0x87, 0xf1, 0xd2, 0xdb, 0xff, 0x3c, 0xbe, 0xe6, 0x96, 0xee, 0xb3, 0x44, + 0xee, 0xbf, 0x7b, 0xf7, 0x62, 0x14, 0xbf, 0xf0, 0xc7, 0xb3, 0x79, 0x9c, + 0xc8, 0xe5, 0x05, 0x3f, 0x6c, 0x8c, 0x8d, 0x84, 0x4e, 0x99, 0xe2, 0x8b, + 0xfe, 0x0c, 0x4a, 0x3e, 0xb7, 0xb0, 0x1c, 0xbf, 0xa3, 0xe8, 0x07, 0x02, + 0x72, 0xbe, 0xa2, 0xe7, 0x13, 0xc4, 0xf2, 0xff, 0xf7, 0xd6, 0x3c, 0xbe, + 0xe6, 0x96, 0xee, 0xb3, 0x45, 0x0a, 0xbf, 0xfe, 0x7f, 0x4b, 0x05, 0x03, + 0xf7, 0x73, 0xc6, 0x8e, 0x5f, 0xff, 0xfe, 0xef, 0xec, 0x63, 0xcb, 0xea, + 0xfb, 0xff, 0xa0, 0x72, 0x75, 0x7f, 0x89, 0x8e, 0x5f, 0xbf, 0xe7, 0xc8, + 0xb3, 0x97, 0xec, 0x06, 0x38, 0x9c, 0xbe, 0xda, 0x37, 0xe3, 0x97, 0xa0, + 0x1f, 0x67, 0x3f, 0x21, 0x2a, 0xf1, 0x2d, 0x22, 0x66, 0x83, 0x0f, 0x2b, + 0xff, 0xdf, 0x58, 0xf2, 0xfb, 0x9a, 0x5b, 0xba, 0xcd, 0x14, 0x92, 0xff, + 0xff, 0x66, 0xfe, 0xa9, 0x93, 0x75, 0xd9, 0xee, 0xc7, 0xbf, 0x61, 0xca, + 0x86, 0x4d, 0x0c, 0xf1, 0x9d, 0x4a, 0x1b, 0x8b, 0x8d, 0x8f, 0x45, 0x2c, + 0x96, 0x12, 0x03, 0x01, 0x5a, 0xf4, 0x70, 0xbf, 0x93, 0xb4, 0x5a, 0xbf, + 0xdf, 0x73, 0x4b, 0x77, 0x59, 0xa2, 0x24, 0x5f, 0xfe, 0xfa, 0xc7, 0x97, + 0xdc, 0xd2, 0xdd, 0xd6, 0x68, 0x97, 0x97, 0xff, 0x47, 0x17, 0x99, 0x35, + 0xcc, 0xa2, 0x63, 0x97, 0x9a, 0x96, 0x00, 0xe5, 0xf6, 0xbf, 0xf6, 0xce, + 0x5f, 0xb4, 0x06, 0x26, 0xce, 0x5e, 0x81, 0xe4, 0xe5, 0xfb, 0xca, 0x30, + 0x60, 0xe5, 0x93, 0xa7, 0x88, 0x23, 0x97, 0xff, 0xbb, 0xc6, 0x04, 0x0d, + 0x78, 0x1c, 0xd7, 0x27, 0x2e, 0x8f, 0x1c, 0xbf, 0xe7, 0x9f, 0x51, 0xcc, + 0x91, 0x87, 0x2f, 0xff, 0x7e, 0x14, 0xd2, 0x93, 0x70, 0x7e, 0xe3, 0x31, + 0xca, 0x92, 0x62, 0xe8, 0x4c, 0x04, 0xf1, 0x16, 0xd9, 0xd5, 0xfc, 0x0e, + 0xc6, 0x91, 0x87, 0x2f, 0xfd, 0x36, 0xe3, 0x8b, 0xf6, 0x39, 0x98, 0xe5, + 0x41, 0xf8, 0x39, 0x6d, 0xf2, 0x70, 0x28, 0xc3, 0x97, 0xec, 0x9f, 0x36, + 0xc3, 0x97, 0xf3, 0xce, 0xfb, 0x70, 0x1c, 0xbf, 0xfa, 0x6f, 0x8a, 0x0c, + 0x71, 0x7e, 0x31, 0x31, 0xca, 0x39, 0x7e, 0x93, 0xf9, 0xf8, 0x9c, 0xbf, + 0x3e, 0xe3, 0x8e, 0x1c, 0xa9, 0x8f, 0x47, 0x89, 0x4d, 0x42, 0x33, 0x71, + 0x31, 0xd7, 0x2e, 0xd4, 0x1c, 0xa0, 0xae, 0x05, 0xa1, 0x24, 0xd1, 0xc1, + 0xea, 0x17, 0x3d, 0x20, 0x12, 0x6f, 0x14, 0x71, 0x87, 0xd7, 0x01, 0x6d, + 0xd8, 0x27, 0x2f, 0xef, 0x9b, 0xee, 0x27, 0x8e, 0x50, 0x4f, 0x11, 0x05, + 0x6e, 0x0f, 0x27, 0x2f, 0xe1, 0xff, 0xd3, 0x42, 0xa7, 0x2f, 0x70, 0xe9, + 0xa3, 0x96, 0x47, 0x3d, 0x1f, 0xcc, 0x2f, 0xc3, 0x93, 0xa9, 0xc4, 0xe5, + 0xf6, 0x4e, 0xa7, 0x13, 0x97, 0xe0, 0xc7, 0x21, 0x7f, 0x87, 0xa2, 0x25, + 0x77, 0xff, 0xc9, 0xaf, 0x9d, 0x84, 0xf6, 0xff, 0x5f, 0xf0, 0x72, 0xf9, + 0x27, 0x03, 0x59, 0xcb, 0xe5, 0xbb, 0xac, 0xd1, 0x4b, 0xaf, 0x87, 0xd1, + 0xa3, 0x97, 0xfd, 0x9a, 0x6b, 0xc0, 0xe6, 0xb9, 0x39, 0x48, 0x7b, 0xbc, + 0x48, 0x6a, 0x49, 0xb3, 0xaa, 0x81, 0x32, 0x9e, 0x89, 0xbb, 0x08, 0xbb, + 0xf8, 0x3c, 0xc6, 0x93, 0x93, 0x97, 0xde, 0x9f, 0x1b, 0x39, 0x48, 0x7a, + 0x62, 0x5f, 0x7e, 0x45, 0x75, 0x9b, 0x39, 0x7f, 0xe8, 0x18, 0xef, 0xcf, + 0xc7, 0xf5, 0x9c, 0xbd, 0xfb, 0xec, 0xe5, 0xf4, 0xdf, 0xbc, 0xc7, 0x2f, + 0xd0, 0x07, 0xe7, 0x67, 0x2f, 0x0a, 0x00, 0xe5, 0xec, 0xf6, 0xce, 0x54, + 0x1b, 0x7d, 0x8d, 0xd4, 0x93, 0x2a, 0x09, 0x44, 0xc8, 0x3d, 0x1d, 0x01, + 0x2f, 0x97, 0xef, 0xcd, 0x6e, 0x21, 0xe0, 0x39, 0x74, 0x72, 0x72, 0xff, + 0x81, 0xbd, 0x47, 0x32, 0x46, 0x1c, 0xbd, 0xe7, 0xe2, 0x72, 0xfd, 0x3f, + 0xf3, 0x43, 0x59, 0xcb, 0xef, 0xe6, 0x86, 0xb3, 0x97, 0x3c, 0xff, 0x0f, + 0x56, 0x72, 0xea, 0x84, 0x6f, 0x39, 0xd7, 0xee, 0x77, 0xfc, 0x9b, 0x99, + 0x07, 0xd0, 0x03, 0x97, 0xff, 0x0f, 0xb8, 0xc6, 0xb6, 0xe3, 0x0d, 0x67, + 0x2a, 0x48, 0xae, 0x61, 0x7e, 0xce, 0x2f, 0xf4, 0x35, 0xee, 0x18, 0xfe, + 0x39, 0x73, 0x89, 0xcb, 0xfe, 0x80, 0x7c, 0xec, 0x31, 0xc4, 0xe5, 0x72, + 0x79, 0xdc, 0x45, 0x6a, 0x48, 0xa8, 0xd4, 0x20, 0xef, 0xe8, 0x6d, 0x3b, + 0xfb, 0x59, 0xcb, 0xfb, 0x99, 0x6d, 0xc7, 0x93, 0x95, 0x0a, 0xcc, 0x64, + 0x5b, 0x91, 0xd1, 0xa4, 0x36, 0x34, 0x50, 0xa1, 0x95, 0xff, 0x86, 0x6f, + 0x9a, 0x8e, 0x64, 0x8c, 0x39, 0x74, 0x30, 0xe5, 0x41, 0xec, 0x69, 0x0a, + 0xfe, 0x81, 0x9b, 0xc8, 0xa9, 0xcb, 0xfe, 0x96, 0x6a, 0x6c, 0x18, 0x61, + 0xcb, 0xf0, 0x21, 0x78, 0xc3, 0x97, 0xfb, 0x27, 0xdc, 0x4d, 0xfe, 0x8e, + 0x52, 0x22, 0x57, 0x47, 0x02, 0x4f, 0x74, 0xb0, 0xe5, 0xfb, 0x6a, 0xe9, + 0xdb, 0x39, 0x78, 0x61, 0x87, 0x28, 0x27, 0x8b, 0xa2, 0xab, 0xd0, 0x0d, + 0x9c, 0xa8, 0x46, 0x38, 0x4b, 0xb1, 0x6d, 0xb2, 0x2b, 0xe7, 0xeb, 0xce, + 0x72, 0xfd, 0xdf, 0xd5, 0xc1, 0x39, 0x7f, 0x9b, 0x17, 0xf4, 0x9c, 0x27, + 0x2f, 0xde, 0x52, 0x78, 0xe9, 0xcb, 0xfe, 0x8e, 0xed, 0xfd, 0x1a, 0xe0, + 0x39, 0x7f, 0xe6, 0x38, 0x54, 0x9a, 0x50, 0x3c, 0x9c, 0xa0, 0x9f, 0xe2, + 0x1d, 0xdf, 0x68, 0x0a, 0x71, 0x39, 0x79, 0x1b, 0xf1, 0xca, 0xe9, 0xe1, + 0xec, 0x9a, 0xa7, 0x4e, 0xa8, 0x24, 0x5c, 0x94, 0xcc, 0x67, 0xd8, 0x53, + 0x79, 0x92, 0xff, 0x0f, 0xb3, 0x68, 0xfd, 0x39, 0x7f, 0xc0, 0x4e, 0xe6, + 0x9e, 0x6d, 0x9c, 0xbf, 0xff, 0x44, 0x86, 0x27, 0x52, 0x6d, 0xf7, 0x38, + 0x34, 0x03, 0x97, 0xf7, 0xc6, 0x67, 0x9f, 0xc7, 0x2f, 0xee, 0xa0, 0x53, + 0x4b, 0x39, 0x65, 0x9c, 0xbb, 0x9d, 0xe1, 0xf6, 0xac, 0xbd, 0xcb, 0x6f, + 0x42, 0x04, 0xe5, 0x42, 0x70, 0xfc, 0x98, 0xb0, 0xe5, 0xe1, 0x91, 0xb3, + 0xab, 0xfd, 0x8d, 0xc9, 0x37, 0xfb, 0x0e, 0x5d, 0xc7, 0x67, 0x2f, 0xef, + 0xf7, 0x13, 0x7f, 0xa3, 0x97, 0xec, 0x9f, 0x3b, 0xb3, 0x95, 0x07, 0xe5, + 0xd1, 0x91, 0x31, 0xbd, 0x9a, 0xd9, 0xca, 0x59, 0xe4, 0xf1, 0x2d, 0xbf, + 0xe0, 0x40, 0x14, 0xe3, 0x03, 0xc0, 0x72, 0xa1, 0x35, 0x2c, 0x87, 0x82, + 0x12, 0x5f, 0xff, 0xfd, 0xd8, 0xd7, 0x2b, 0x4e, 0x7e, 0x2a, 0xff, 0x37, + 0xd7, 0x5c, 0x08, 0x4e, 0x5f, 0x22, 0xad, 0x30, 0xe5, 0xfc, 0xa7, 0xa2, + 0x71, 0xe4, 0xe5, 0xe1, 0x46, 0x1c, 0xad, 0x1f, 0x78, 0x09, 0x3c, 0x61, + 0x7f, 0x86, 0x1c, 0x7d, 0x82, 0x72, 0xff, 0x47, 0x3b, 0x6b, 0x8d, 0x2a, + 0x72, 0xff, 0x75, 0xe6, 0x4d, 0x44, 0xe7, 0x2f, 0xec, 0xe0, 0x64, 0x67, + 0x8e, 0x5d, 0x8c, 0x39, 0x41, 0x4f, 0xdb, 0x21, 0xce, 0xc2, 0xfe, 0x97, + 0xb9, 0xc7, 0xe6, 0x9c, 0x4b, 0xef, 0xdc, 0x08, 0xc8, 0xd9, 0xcb, 0xf3, + 0xf1, 0xcd, 0x6c, 0xe5, 0x04, 0xf4, 0xd8, 0x55, 0x7e, 0xeb, 0x8a, 0x30, + 0xe5, 0xf2, 0xb3, 0x6e, 0x0e, 0x5f, 0xc0, 0xe4, 0x19, 0xac, 0x39, 0x7f, + 0x2e, 0x13, 0xc9, 0x23, 0x97, 0xf3, 0x81, 0x91, 0x9e, 0x39, 0x50, 0x88, + 0x6c, 0x2e, 0x42, 0xcb, 0xfc, 0xe0, 0xdc, 0x76, 0x36, 0x72, 0xfd, 0xcf, + 0xb7, 0x93, 0x9c, 0xbb, 0x27, 0x39, 0x4e, 0x78, 0x22, 0x55, 0x50, 0x9d, + 0x96, 0x11, 0x21, 0x37, 0x61, 0x54, 0x25, 0xbb, 0x73, 0xb8, 0x0b, 0x39, + 0x6d, 0x9c, 0xb9, 0x15, 0xd9, 0xa8, 0xfc, 0x5e, 0xf0, 0x1d, 0x67, 0x2f, + 0x9b, 0x9b, 0x70, 0x72, 0xfe, 0xd8, 0xbc, 0xf1, 0xe3, 0x97, 0xe9, 0xdf, + 0x79, 0x23, 0x97, 0xff, 0xc1, 0xce, 0x2f, 0xa9, 0x94, 0x93, 0xf9, 0xd8, + 0x72, 0xa0, 0xfe, 0xd0, 0xa2, 0xfe, 0x7e, 0x40, 0xc4, 0xd9, 0xca, 0x84, + 0xcd, 0xb9, 0x1c, 0x98, 0x93, 0x50, 0xa8, 0xe9, 0x05, 0xfe, 0xf2, 0x36, + 0xf3, 0x43, 0x0e, 0x5b, 0xef, 0x08, 0xde, 0x03, 0x35, 0x69, 0x11, 0x38, + 0x5b, 0x3c, 0x36, 0x64, 0x42, 0x16, 0x9c, 0x8f, 0x7f, 0x98, 0x52, 0xa4, + 0x69, 0x53, 0x4b, 0x8a, 0xd4, 0x2e, 0x98, 0x43, 0xd8, 0xe2, 0x9e, 0x3e, + 0x60, 0x47, 0xce, 0x31, 0xd0, 0xee, 0x51, 0x4f, 0xa5, 0x38, 0x34, 0x84, + 0x0a, 0x91, 0xb2, 0x70, 0x28, 0xdf, 0xef, 0xb9, 0xa5, 0xbb, 0xac, 0xd1, + 0x4e, 0x2f, 0xf3, 0x21, 0x99, 0xc1, 0x1e, 0x39, 0x7d, 0x9b, 0x52, 0x47, + 0x2f, 0xfc, 0x9a, 0x7d, 0xf7, 0x30, 0x56, 0x72, 0xfc, 0xcd, 0x6b, 0x36, + 0x72, 0xff, 0xfd, 0xdf, 0xfd, 0xa8, 0xf6, 0xf1, 0x7b, 0x8d, 0x2c, 0xe5, + 0xff, 0x6d, 0x15, 0xc9, 0x40, 0x36, 0x72, 0xff, 0xfe, 0xf6, 0x4c, 0x29, + 0xbf, 0x42, 0x89, 0xa9, 0xa3, 0xa7, 0x2f, 0xf2, 0x30, 0x31, 0xbf, 0xc4, + 0xe5, 0xfc, 0xfc, 0xef, 0xe6, 0xd4, 0x39, 0x7e, 0xf7, 0x32, 0x86, 0xce, + 0x5f, 0xce, 0xa6, 0x71, 0x8d, 0x9c, 0xac, 0x3d, 0x9f, 0xca, 0xaf, 0xfc, + 0x9c, 0xec, 0x70, 0x3d, 0x76, 0xce, 0x5f, 0xff, 0x64, 0xf9, 0xcf, 0xb6, + 0x83, 0x00, 0x76, 0x1c, 0xa5, 0x51, 0x1d, 0xb3, 0xfb, 0xff, 0x67, 0x63, + 0x59, 0xf5, 0xb6, 0xdb, 0x29, 0x72, 0x36, 0x72, 0xe9, 0xfe, 0xc2, 0xb9, + 0x49, 0x1a, 0x84, 0x8f, 0x0f, 0x16, 0x51, 0xca, 0xba, 0x1c, 0xf5, 0x70, + 0x06, 0x63, 0x08, 0xbf, 0x42, 0xc1, 0xa1, 0x27, 0x02, 0x1d, 0xfb, 0x4b, + 0x77, 0x59, 0xa2, 0xbc, 0x5f, 0xff, 0xd8, 0x1e, 0xc2, 0x9f, 0x7c, 0x2e, + 0x0d, 0xee, 0x00, 0x52, 0xdf, 0x71, 0x12, 0x2d, 0x0d, 0x2f, 0xfe, 0xfa, + 0xf2, 0xfb, 0x9a, 0x5b, 0xba, 0xcd, 0x12, 0x3a, 0xf2, 0xf1, 0x87, 0x2f, + 0x20, 0x20, 0xe5, 0xe5, 0xe3, 0x0a, 0x7d, 0x2e, 0xef, 0xda, 0x5b, 0xba, + 0xcd, 0x12, 0x42, 0xff, 0xfe, 0x84, 0xd2, 0x70, 0x40, 0xcf, 0x1e, 0x4e, + 0xbc, 0xe7, 0x2f, 0xff, 0x3f, 0xa6, 0xde, 0x04, 0x3f, 0xbe, 0xa4, 0x72, + 0xff, 0xf0, 0xe0, 0x1a, 0x66, 0xa2, 0x77, 0xd2, 0xce, 0x5d, 0x2f, 0xb0, + 0x9a, 0xa6, 0x16, 0xf4, 0xd0, 0x0b, 0x9e, 0x4c, 0xbf, 0x67, 0x7e, 0xe3, + 0x0e, 0x5b, 0xec, 0x2a, 0x0b, 0x78, 0xe2, 0xfc, 0xaf, 0x7f, 0xf7, 0xd7, + 0x97, 0xdc, 0xd2, 0xdd, 0xd6, 0x68, 0x92, 0x97, 0xed, 0x2d, 0xdd, 0x66, + 0x8b, 0xc5, 0x7f, 0xd2, 0xfb, 0x9a, 0x5b, 0xba, 0xcd, 0x12, 0x6a, 0xdf, + 0x70, 0xfe, 0xdc, 0xd2, 0xff, 0xb4, 0xb8, 0x9f, 0x30, 0x7c, 0x72, 0xfe, + 0x8d, 0xa3, 0x22, 0x63, 0x96, 0xe9, 0xca, 0x43, 0xf6, 0x61, 0xc3, 0x65, + 0xb7, 0xfd, 0x80, 0x0f, 0x60, 0x61, 0xb3, 0x97, 0xc0, 0xde, 0x09, 0xca, + 0x83, 0xd9, 0x43, 0x8b, 0xff, 0x93, 0xf5, 0xef, 0x6f, 0xaf, 0x42, 0xa7, + 0x2f, 0xa5, 0xfc, 0x72, 0x72, 0xff, 0xfb, 0xf7, 0xe7, 0x31, 0x55, 0x5e, + 0x59, 0xcf, 0x8e, 0x54, 0x91, 0xba, 0x12, 0x09, 0x91, 0xb6, 0x49, 0x7f, + 0xe4, 0x86, 0x77, 0x02, 0x14, 0xe4, 0xe5, 0xf7, 0x02, 0x42, 0xa7, 0x2f, + 0x4b, 0x95, 0x4e, 0x5e, 0xfc, 0x3c, 0x9c, 0xbf, 0xf9, 0xc0, 0xbe, 0xa6, + 0x85, 0x3d, 0xb3, 0x97, 0x0c, 0xe7, 0x2a, 0x11, 0x7a, 0x12, 0x54, 0x1f, + 0x71, 0xf5, 0x10, 0xee, 0xd7, 0x8e, 0x5f, 0xfb, 0xdb, 0x86, 0x0e, 0x4a, + 0x04, 0xe5, 0xe6, 0x9c, 0x33, 0x67, 0x2b, 0x0f, 0x87, 0x80, 0xf2, 0xfd, + 0xe4, 0xec, 0x71, 0x39, 0x70, 0xce, 0x72, 0xf7, 0xa3, 0x47, 0x2a, 0x0f, + 0x72, 0x62, 0x9f, 0xc5, 0xee, 0x75, 0x9c, 0xbf, 0x96, 0x1f, 0xe7, 0x51, + 0x87, 0x2f, 0x83, 0x9d, 0x83, 0x95, 0x07, 0xd3, 0x82, 0xce, 0x65, 0x7e, + 0x9b, 0x7b, 0x46, 0x1c, 0xbf, 0xfe, 0x9d, 0xb7, 0x96, 0xf7, 0x9a, 0x6e, + 0x34, 0xa9, 0xcb, 0x09, 0xcb, 0x94, 0x50, 0xe5, 0x62, 0x29, 0x9c, 0xa4, + 0x0a, 0x8a, 0x08, 0x5c, 0xd3, 0xec, 0x2e, 0xc2, 0xe4, 0x6c, 0xba, 0x3e, + 0xec, 0x3e, 0xdd, 0x20, 0x5e, 0x37, 0x08, 0x0f, 0x42, 0x65, 0x48, 0x69, + 0x54, 0x3a, 0xdc, 0x99, 0xd0, 0x65, 0x5e, 0x30, 0x06, 0x39, 0x04, 0x97, + 0xab, 0x34, 0x6c, 0x0c, 0x2c, 0xec, 0xa5, 0xff, 0x1f, 0x7f, 0x0c, 0xf5, + 0x27, 0x88, 0xea, 0x27, 0x6d, 0xfb, 0xe7, 0x96, 0x23, 0x29, 0xef, 0x10, + 0xcf, 0x81, 0x66, 0x32, 0x4a, 0x55, 0xa4, 0x0c, 0x2e, 0xfc, 0xd6, 0x39, + 0xaf, 0x0d, 0x52, 0x99, 0x72, 0xd7, 0x28, 0xf6, 0x6b, 0xc3, 0x77, 0xd5, + 0xb1, 0x60, 0x66, 0xa0, 0x8e, 0xfe, 0xd3, 0xb9, 0x5e, 0xf2, 0x39, 0x41, + 0x4c, 0x26, 0xe1, 0xe5, 0xee, 0x8d, 0x7b, 0x3b, 0xbb, 0x43, 0x73, 0xeb, + 0xf5, 0xe2, 0xfe, 0xf1, 0xe3, 0xf8, 0xd3, 0x9d, 0x1b, 0x9f, 0xf9, 0x69, + 0x3a, 0x30, 0xa5, 0x27, 0xcb, 0x82, 0xd7, 0x42, 0xd0, }; -static const unsigned kPreloadedHSTSBits = 352806; +static const unsigned kPreloadedHSTSBits = 382052; -static const unsigned kHSTSRootPosition = 352187; +static const unsigned kHSTSRootPosition = 381429; #endif // NET_HTTP_TRANSPORT_SECURITY_STATE_STATIC_H_
diff --git a/net/http/transport_security_state_static.json b/net/http/transport_security_state_static.json index 08e9c51..09cdf44 100644 --- a/net/http/transport_security_state_static.json +++ b/net/http/transport_security_state_static.json
@@ -5038,7 +5038,418 @@ { "name": "yecl.net", "include_subdomains": true, "mode": "force-https" }, { "name": "yolobert.de", "include_subdomains": true, "mode": "force-https" }, { "name": "ys-shop.biz", "include_subdomains": true, "mode": "force-https" }, - { "name": "zooparadies.eu", "include_subdomains": true, "mode": "force-https" } + { "name": "zooparadies.eu", "include_subdomains": true, "mode": "force-https" }, + { "name": "0paste.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "1km.ro", "include_subdomains": true, "mode": "force-https" }, + { "name": "2nerds1bit.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "403.ch", "include_subdomains": true, "mode": "force-https" }, + { "name": "acr.im", "include_subdomains": true, "mode": "force-https" }, + { "name": "adevel.eu", "include_subdomains": true, "mode": "force-https" }, + { "name": "adrl.ca", "include_subdomains": true, "mode": "force-https" }, + { "name": "aishnair.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "alair.cn", "include_subdomains": true, "mode": "force-https" }, + { "name": "alexbaker.org", "include_subdomains": true, "mode": "force-https" }, + { "name": "altesses.eu", "include_subdomains": true, "mode": "force-https" }, + { "name": "altonblom.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "amishsecurity.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "andreasfeusi.ch", "include_subdomains": true, "mode": "force-https" }, + { "name": "anedot.xyz", "include_subdomains": true, "mode": "force-https" }, + { "name": "aniplus.cf", "include_subdomains": true, "mode": "force-https" }, + { "name": "anshuman-chatterjee.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "asandu.eu", "include_subdomains": true, "mode": "force-https" }, + { "name": "aspires.co.jp", "include_subdomains": true, "mode": "force-https" }, + { "name": "augustiner-kantorei-erfurt.de", "include_subdomains": true, "mode": "force-https" }, + { "name": "augustiner-kantorei.de", "include_subdomains": true, "mode": "force-https" }, + { "name": "avalon-island.ru", "include_subdomains": true, "mode": "force-https" }, + { "name": "avec-ou-sans-ordonnance.fr", "include_subdomains": true, "mode": "force-https" }, + { "name": "aviacao.pt", "include_subdomains": true, "mode": "force-https" }, + { "name": "babarkata.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "babyfotograf-schweiz.ch", "include_subdomains": true, "mode": "force-https" }, + { "name": "bacchanallia.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "balkonien.org", "include_subdomains": true, "mode": "force-https" }, + { "name": "bananabandy.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "baofengtech.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "baud.ninja", "include_subdomains": true, "mode": "force-https" }, + { "name": "beachi.es", "include_subdomains": true, "mode": "force-https" }, + { "name": "bentley.link", "include_subdomains": true, "mode": "force-https" }, + { "name": "berra.se", "include_subdomains": true, "mode": "force-https" }, + { "name": "bfw-online.de", "include_subdomains": true, "mode": "force-https" }, + { "name": "bgmn.net", "include_subdomains": true, "mode": "force-https" }, + { "name": "biasmath.es", "include_subdomains": true, "mode": "force-https" }, + { "name": "biou.me", "include_subdomains": true, "mode": "force-https" }, + { "name": "bitcoinworld.me", "include_subdomains": true, "mode": "force-https" }, + { "name": "blauwwit.be", "include_subdomains": true, "mode": "force-https" }, + { "name": "blendle.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "bluemosh.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "bonapp.restaurant", "include_subdomains": true, "mode": "force-https" }, + { "name": "bonifacius.be", "include_subdomains": true, "mode": "force-https" }, + { "name": "boringsecurity.net", "include_subdomains": true, "mode": "force-https" }, + { "name": "bougeret.fr", "include_subdomains": true, "mode": "force-https" }, + { "name": "bowling.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "brasalcosmetics.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "bratteng.me", "include_subdomains": true, "mode": "force-https" }, + { "name": "bugcrowd.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "cadoth.net", "include_subdomains": true, "mode": "force-https" }, + { "name": "caffeinatedcode.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "cais.de", "include_subdomains": true, "mode": "force-https" }, + { "name": "caja-pdf.es", "include_subdomains": true, "mode": "force-https" }, + { "name": "calvinallen.net", "include_subdomains": true, "mode": "force-https" }, + { "name": "camperverzekerd.nl", "include_subdomains": true, "mode": "force-https" }, + { "name": "canadasmotorcycle.ca", "include_subdomains": true, "mode": "force-https" }, + { "name": "car-navi.ph", "include_subdomains": true, "mode": "force-https" }, + { "name": "carck.co.uk", "include_subdomains": true, "mode": "force-https" }, + { "name": "cardrecovery.fr", "include_subdomains": true, "mode": "force-https" }, + { "name": "cativa.net", "include_subdomains": true, "mode": "force-https" }, + { "name": "ccayearbook.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "cctech.ph", "include_subdomains": true, "mode": "force-https" }, + { "name": "cementscience.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "centralync.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "cevrimici.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "chaoschemnitz.de", "include_subdomains": true, "mode": "force-https" }, + { "name": "chch.it", "include_subdomains": true, "mode": "force-https" }, + { "name": "chocolah.com.au", "include_subdomains": true, "mode": "force-https" }, + { "name": "choosemypc.net", "include_subdomains": true, "mode": "force-https" }, + { "name": "chriswells.io", "include_subdomains": true, "mode": "force-https" }, + { "name": "ciat.no", "include_subdomains": true, "mode": "force-https" }, + { "name": "clintonbloodworth.io", "include_subdomains": true, "mode": "force-https" }, + { "name": "cloudcy.net", "include_subdomains": true, "mode": "force-https" }, + { "name": "clouddesktop.co.nz", "include_subdomains": true, "mode": "force-https" }, + { "name": "cmci.dk", "include_subdomains": true, "mode": "force-https" }, + { "name": "co50.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "coiffeurschnittstelle.ch", "include_subdomains": true, "mode": "force-https" }, + { "name": "comitesaustria.at", "include_subdomains": true, "mode": "force-https" }, + { "name": "consonare.de", "include_subdomains": true, "mode": "force-https" }, + { "name": "coopens.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "custodyxchange.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "cvursache.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "cyph.im", "include_subdomains": true, "mode": "force-https" }, + { "name": "cyph.video", "include_subdomains": true, "mode": "force-https" }, + { "name": "cysec.biz", "include_subdomains": true, "mode": "force-https" }, + { "name": "d3xt3r01.tk", "include_subdomains": true, "mode": "force-https" }, + { "name": "daimadi.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "datorb.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "decomplify.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "deepserve.info", "include_subdomains": true, "mode": "force-https" }, + { "name": "dentaldomain.org", "include_subdomains": true, "mode": "force-https" }, + { "name": "dentaldomain.ph", "include_subdomains": true, "mode": "force-https" }, + { "name": "dereferenced.net", "include_subdomains": true, "mode": "force-https" }, + { "name": "devh.net", "include_subdomains": true, "mode": "force-https" }, + { "name": "devolution.ws", "include_subdomains": true, "mode": "force-https" }, + { "name": "die-blahuts.de", "include_subdomains": true, "mode": "force-https" }, + { "name": "diegelernten.de", "include_subdomains": true, "mode": "force-https" }, + { "name": "dmlogic.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "dmwall.cn", "include_subdomains": true, "mode": "force-https" }, + { "name": "dogan.ch", "include_subdomains": true, "mode": "force-https" }, + { "name": "dutchrank.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "dynamize.solutions", "include_subdomains": true, "mode": "force-https" }, + { "name": "dzimejl.sk", "include_subdomains": true, "mode": "force-https" }, + { "name": "eagletechz.com.br", "include_subdomains": true, "mode": "force-https" }, + { "name": "echomanchester.net", "include_subdomains": true, "mode": "force-https" }, + { "name": "ecnetworker.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "efficienthealth.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "electronicfasteners.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "elemental.software", "include_subdomains": true, "mode": "force-https" }, + { "name": "endlesstone.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "eriix.org", "include_subdomains": true, "mode": "force-https" }, + { "name": "expo-designers.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "ezmod.org", "include_subdomains": true, "mode": "force-https" }, + { "name": "f-thie.de", "include_subdomains": true, "mode": "force-https" }, + { "name": "faesser.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "faizan.net", "include_subdomains": true, "mode": "force-https" }, + { "name": "faizan.xyz", "include_subdomains": true, "mode": "force-https" }, + { "name": "federicomigliavacca.it", "include_subdomains": true, "mode": "force-https" }, + { "name": "file-pdf.it", "include_subdomains": true, "mode": "force-https" }, + { "name": "findtutorsnearme.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "flawlesscowboy.xyz", "include_subdomains": true, "mode": "force-https" }, + { "name": "floorball-haunwoehr.de", "include_subdomains": true, "mode": "force-https" }, + { "name": "flowersandclouds.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "fmarchal.fr", "include_subdomains": true, "mode": "force-https" }, + { "name": "focusmark.jp", "include_subdomains": true, "mode": "force-https" }, + { "name": "frankierprofi.de", "include_subdomains": true, "mode": "force-https" }, + { "name": "franzt.ovh", "include_subdomains": true, "mode": "force-https" }, + { "name": "fredvoyage.fr", "include_subdomains": true, "mode": "force-https" }, + { "name": "fukushima-web.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "fzn.io", "include_subdomains": true, "mode": "force-https" }, + { "name": "geek-hub.de", "include_subdomains": true, "mode": "force-https" }, + { "name": "geeky.software", "include_subdomains": true, "mode": "force-https" }, + { "name": "genshiken-itb.org", "include_subdomains": true, "mode": "force-https" }, + { "name": "genslerwisp.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "genxnotes.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "getvdownloader.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "glidingshop.cz", "include_subdomains": true, "mode": "force-https" }, + { "name": "gowe.wang", "include_subdomains": true, "mode": "force-https" }, + { "name": "gracesofgrief.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "grantedby.me", "include_subdomains": true, "mode": "force-https" }, + { "name": "grazetech.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "grcnode.co.uk", "include_subdomains": true, "mode": "force-https" }, + { "name": "gtmasterclub.it", "include_subdomains": true, "mode": "force-https" }, + { "name": "habarisoft.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "hackthissite.org", "include_subdomains": true, "mode": "force-https" }, + { "name": "hakase.kr", "include_subdomains": true, "mode": "force-https" }, + { "name": "handmadetutorials.ro", "include_subdomains": true, "mode": "force-https" }, + { "name": "harbor-light.net", "include_subdomains": true, "mode": "force-https" }, + { "name": "harringtonca.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "hduin.xyz", "include_subdomains": true, "mode": "force-https" }, + { "name": "hexo.io", "include_subdomains": true, "mode": "force-https" }, + { "name": "homads.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "hoodoo.io", "include_subdomains": true, "mode": "force-https" }, + { "name": "hoshisato.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "huffduffer.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "hund.io", "include_subdomains": true, "mode": "force-https" }, + { "name": "iainsimms.me", "include_subdomains": true, "mode": "force-https" }, + { "name": "ilhadocaranguejo.com.br", "include_subdomains": true, "mode": "force-https" }, + { "name": "imlonghao.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "imququ.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "imreh.net", "include_subdomains": true, "mode": "force-https" }, + { "name": "indust.me", "include_subdomains": true, "mode": "force-https" }, + { "name": "inksay.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "institutoflordelavida.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "interfug.de", "include_subdomains": true, "mode": "force-https" }, + { "name": "inwesttitle.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "iocheck.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "isaacman.tech", "include_subdomains": true, "mode": "force-https" }, + { "name": "iskaz.rs", "include_subdomains": true, "mode": "force-https" }, + { "name": "isondo.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "istanbul.systems", "include_subdomains": true, "mode": "force-https" }, + { "name": "jacobphono.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "jamesrains.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "jayharris.ca", "include_subdomains": true, "mode": "force-https" }, + { "name": "jcraft.us", "include_subdomains": true, "mode": "force-https" }, + { "name": "jennythebaker.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "jetmirshatri.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "jimmycai.org", "include_subdomains": true, "mode": "force-https" }, + { "name": "jobss.co.uk", "include_subdomains": true, "mode": "force-https" }, + { "name": "jonaskjodt.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "jonathan-apps.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "jonathancarter.org", "include_subdomains": true, "mode": "force-https" }, + { "name": "jonfor.net", "include_subdomains": true, "mode": "force-https" }, + { "name": "jorgemesa.me", "include_subdomains": true, "mode": "force-https" }, + { "name": "josephrees.uk", "include_subdomains": true, "mode": "force-https" }, + { "name": "joyofcookingandbaking.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "kachlikova2.cz", "include_subdomains": true, "mode": "force-https" }, + { "name": "kanotijd.nl", "include_subdomains": true, "mode": "force-https" }, + { "name": "katka.info", "include_subdomains": true, "mode": "force-https" }, + { "name": "kd-plus.pp.ua", "include_subdomains": true, "mode": "force-https" }, + { "name": "keke-shop.ch", "include_subdomains": true, "mode": "force-https" }, + { "name": "kengilmour.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "kikuzuki.org", "include_subdomains": true, "mode": "force-https" }, + { "name": "kinderwagen-test24.de", "include_subdomains": true, "mode": "force-https" }, + { "name": "kitsostech.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "klif1.nl", "include_subdomains": true, "mode": "force-https" }, + { "name": "kodokushi.fr", "include_subdomains": true, "mode": "force-https" }, + { "name": "kokenmetaanbiedingen.nl", "include_subdomains": true, "mode": "force-https" }, + { "name": "kreavis.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "latus.xyz", "include_subdomains": true, "mode": "force-https" }, + { "name": "legendofkrystal.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "levendwater.org", "include_subdomains": true, "mode": "force-https" }, + { "name": "lewisjuggins.co.uk", "include_subdomains": true, "mode": "force-https" }, + { "name": "liftcannabis.ca", "include_subdomains": true, "mode": "force-https" }, + { "name": "limalama.eu", "include_subdomains": true, "mode": "force-https" }, + { "name": "listafirmelor.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "lothai.re", "include_subdomains": true, "mode": "force-https" }, + { "name": "ltn-tom-morel.fr", "include_subdomains": true, "mode": "force-https" }, + { "name": "luehne.de", "include_subdomains": true, "mode": "force-https" }, + { "name": "lunakit.org", "include_subdomains": true, "mode": "force-https" }, + { "name": "m3-gmbh.de", "include_subdomains": true, "mode": "force-https" }, + { "name": "manoirdecontres.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "marcoslater.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "marktcontact.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "mattberryman.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "maxwell-english.co.jp", "include_subdomains": true, "mode": "force-https" }, + { "name": "mazz-tech.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "mcc.re", "include_subdomains": true, "mode": "force-https" }, + { "name": "mcgarderen.nl", "include_subdomains": true, "mode": "force-https" }, + { "name": "mcpart.land", "include_subdomains": true, "mode": "force-https" }, + { "name": "medirich.co", "include_subdomains": true, "mode": "force-https" }, + { "name": "medo64.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "medwayindia.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "meizufans.eu", "include_subdomains": true, "mode": "force-https" }, + { "name": "metebalci.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "michaelcullen.name", "include_subdomains": true, "mode": "force-https" }, + { "name": "michaelleibundgut.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "michal-kral.cz", "include_subdomains": true, "mode": "force-https" }, + { "name": "microme.ga", "include_subdomains": true, "mode": "force-https" }, + { "name": "midonet.org", "include_subdomains": true, "mode": "force-https" }, + { "name": "misskey.xyz", "include_subdomains": true, "mode": "force-https" }, + { "name": "mizd.at", "include_subdomains": true, "mode": "force-https" }, + { "name": "monnyonle.hu", "include_subdomains": true, "mode": "force-https" }, + { "name": "mpc-hc.org", "include_subdomains": true, "mode": "force-https" }, + { "name": "mtasa.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "multitheftauto.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "mushikabu.net", "include_subdomains": true, "mode": "force-https" }, + { "name": "myonline.hu", "include_subdomains": true, "mode": "force-https" }, + { "name": "myzina.cz", "include_subdomains": true, "mode": "force-https" }, + { "name": "nabytko.cz", "include_subdomains": true, "mode": "force-https" }, + { "name": "nakedalarmclock.me", "include_subdomains": true, "mode": "force-https" }, + { "name": "nanogi.ga", "include_subdomains": true, "mode": "force-https" }, + { "name": "narach.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "narthollis.net", "include_subdomains": true, "mode": "force-https" }, + { "name": "nb.zone", "include_subdomains": true, "mode": "force-https" }, + { "name": "nbg-ha.de", "include_subdomains": true, "mode": "force-https" }, + { "name": "negai.moe", "include_subdomains": true, "mode": "force-https" }, + { "name": "neko-life.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "netfs.pl", "include_subdomains": true, "mode": "force-https" }, + { "name": "netfxharmonics.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "netsparker.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "newcitygas.ca", "include_subdomains": true, "mode": "force-https" }, + { "name": "nyffo.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "obdolbacca.ru", "include_subdomains": true, "mode": "force-https" }, + { "name": "obscuredfiles.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "okane.love", "include_subdomains": true, "mode": "force-https" }, + { "name": "omifind.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "ondrej.org", "include_subdomains": true, "mode": "force-https" }, + { "name": "onlinedemo.hu", "include_subdomains": true, "mode": "force-https" }, + { "name": "openprovider.nl", "include_subdomains": true, "mode": "force-https" }, + { "name": "optmos.at", "include_subdomains": true, "mode": "force-https" }, + { "name": "oszri.hu", "include_subdomains": true, "mode": "force-https" }, + { "name": "otya.me", "include_subdomains": true, "mode": "force-https" }, + { "name": "overclockers.ge", "include_subdomains": true, "mode": "force-https" }, + { "name": "pan.digital", "include_subdomains": true, "mode": "force-https" }, + { "name": "per-pedes.at", "include_subdomains": true, "mode": "force-https" }, + { "name": "performaterm.ro", "include_subdomains": true, "mode": "force-https" }, + { "name": "peter.org.ua", "include_subdomains": true, "mode": "force-https" }, + { "name": "pfadfinder-aurich.de", "include_subdomains": true, "mode": "force-https" }, + { "name": "phparcade.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "pierre-denoblens.net", "include_subdomains": true, "mode": "force-https" }, + { "name": "playnation.io", "include_subdomains": true, "mode": "force-https" }, + { "name": "plogable.co", "include_subdomains": true, "mode": "force-https" }, + { "name": "pretty.hu", "include_subdomains": true, "mode": "force-https" }, + { "name": "principaltoolbox.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "profi-durchgangsmelder.de", "include_subdomains": true, "mode": "force-https" }, + { "name": "profpay.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "ptgoldensun.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "quai10.org", "include_subdomains": true, "mode": "force-https" }, + { "name": "quantenteranik.eu", "include_subdomains": true, "mode": "force-https" }, + { "name": "quantumcourse.org", "include_subdomains": true, "mode": "force-https" }, + { "name": "r811.de", "include_subdomains": true, "mode": "force-https" }, + { "name": "racermaster.xyz", "include_subdomains": true, "mode": "force-https" }, + { "name": "rcpcbd.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "relisten.nl", "include_subdomains": true, "mode": "force-https" }, + { "name": "retcor.net", "include_subdomains": true, "mode": "force-https" }, + { "name": "rhdigital.pro", "include_subdomains": true, "mode": "force-https" }, + { "name": "riiconnect24.net", "include_subdomains": true, "mode": "force-https" }, + { "name": "ronwo.de", "include_subdomains": true, "mode": "force-https" }, + { "name": "rootwpn.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "russmarshall.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "rww.name", "include_subdomains": true, "mode": "force-https" }, + { "name": "saltercane.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "saveyour.biz", "include_subdomains": true, "mode": "force-https" }, + { "name": "scienceathome.org", "include_subdomains": true, "mode": "force-https" }, + { "name": "screenresolution.space", "include_subdomains": true, "mode": "force-https" }, + { "name": "secpatrol.de", "include_subdomains": true, "mode": "force-https" }, + { "name": "securitystreak.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "serbanpaun.ro", "include_subdomains": true, "mode": "force-https" }, + { "name": "serverstuff.info", "include_subdomains": true, "mode": "force-https" }, + { "name": "seryo.moe", "include_subdomains": true, "mode": "force-https" }, + { "name": "seryovpn.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "shtorku.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "siebens.net", "include_subdomains": true, "mode": "force-https" }, + { "name": "sightcure.jp", "include_subdomains": true, "mode": "force-https" }, + { "name": "silverpvp.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "sinoscandinavia.se", "include_subdomains": true, "mode": "force-https" }, + { "name": "skia.org", "include_subdomains": true, "mode": "force-https" }, + { "name": "skyminds.net", "include_subdomains": true, "mode": "force-https" }, + { "name": "slightfuture.click", "include_subdomains": true, "mode": "force-https" }, + { "name": "slightfuture.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "smares.de", "include_subdomains": true, "mode": "force-https" }, + { "name": "sms1.ro", "include_subdomains": true, "mode": "force-https" }, + { "name": "socomponents.co.uk", "include_subdomains": true, "mode": "force-https" }, + { "name": "sosecu.red", "include_subdomains": true, "mode": "force-https" }, + { "name": "soved.eu", "include_subdomains": true, "mode": "force-https" }, + { "name": "spark.team", "include_subdomains": true, "mode": "force-https" }, + { "name": "speich.net", "include_subdomains": true, "mode": "force-https" }, + { "name": "spicymatch.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "sritest.io", "include_subdomains": true, "mode": "force-https" }, + { "name": "sstewartgallus.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "starcomproj.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "stbennett.org", "include_subdomains": true, "mode": "force-https" }, + { "name": "steakovercooked.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "stkbn.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "stopwoodfin.org", "include_subdomains": true, "mode": "force-https" }, + { "name": "stressfreehousehold.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "student-scientist.org", "include_subdomains": true, "mode": "force-https" }, + { "name": "studentloans.gov", "include_subdomains": true, "mode": "force-https" }, + { "name": "studentresearcher.org", "include_subdomains": true, "mode": "force-https" }, + { "name": "styles.pm", "include_subdomains": true, "mode": "force-https" }, + { "name": "sulek.eu", "include_subdomains": true, "mode": "force-https" }, + { "name": "susanbpilates.co", "include_subdomains": true, "mode": "force-https" }, + { "name": "susanbpilates.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "synony.me", "include_subdomains": true, "mode": "force-https" }, + { "name": "taskstats.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "tcl.ath.cx", "include_subdomains": true, "mode": "force-https" }, + { "name": "teamzeus.cz", "include_subdomains": true, "mode": "force-https" }, + { "name": "techelements.co", "include_subdomains": true, "mode": "force-https" }, + { "name": "techpivot.net", "include_subdomains": true, "mode": "force-https" }, + { "name": "teddy.ch", "include_subdomains": true, "mode": "force-https" }, + { "name": "tetsumaki.net", "include_subdomains": true, "mode": "force-https" }, + { "name": "textracer.dk", "include_subdomains": true, "mode": "force-https" }, + { "name": "tf2b.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "thedark1337.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "themicrocapital.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "theojones.name", "include_subdomains": true, "mode": "force-https" }, + { "name": "thesession.org", "include_subdomains": true, "mode": "force-https" }, + { "name": "tls.builders", "include_subdomains": true, "mode": "force-https" }, + { "name": "tmaward.net", "include_subdomains": true, "mode": "force-https" }, + { "name": "tmpsantos.com.br", "include_subdomains": true, "mode": "force-https" }, + { "name": "tobiasmathes.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "tobiasmathes.name", "include_subdomains": true, "mode": "force-https" }, + { "name": "tommyads.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "toolbox.ninja", "include_subdomains": true, "mode": "force-https" }, + { "name": "touhou.cc", "include_subdomains": true, "mode": "force-https" }, + { "name": "treebaglia.xyz", "include_subdomains": true, "mode": "force-https" }, + { "name": "trophee-discount.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "truweight.in", "include_subdomains": true, "mode": "force-https" }, + { "name": "tryoneday.co", "include_subdomains": true, "mode": "force-https" }, + { "name": "trywesayyes.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "typecodes.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "ukwct.org.uk", "include_subdomains": true, "mode": "force-https" }, + { "name": "undone.me", "include_subdomains": true, "mode": "force-https" }, + { "name": "unionplat.ru", "include_subdomains": true, "mode": "force-https" }, + { "name": "uno-pizza.ru", "include_subdomains": true, "mode": "force-https" }, + { "name": "uripura.de", "include_subdomains": true, "mode": "force-https" }, + { "name": "use.be", "include_subdomains": true, "mode": "force-https" }, + { "name": "valis.sx", "include_subdomains": true, "mode": "force-https" }, + { "name": "vapordepot.jp", "include_subdomains": true, "mode": "force-https" }, + { "name": "varghese.de", "include_subdomains": true, "mode": "force-https" }, + { "name": "vgatest.nl", "include_subdomains": true, "mode": "force-https" }, + { "name": "videnskabsklubben.dk", "include_subdomains": true, "mode": "force-https" }, + { "name": "vikashkumar.me", "include_subdomains": true, "mode": "force-https" }, + { "name": "vimeo.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "volcrado.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "vpnhot.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "w4xzr.xyz", "include_subdomains": true, "mode": "force-https" }, + { "name": "wallingford.cc", "include_subdomains": true, "mode": "force-https" }, + { "name": "warandpeace.xyz", "include_subdomains": true, "mode": "force-https" }, + { "name": "warr.ath.cx", "include_subdomains": true, "mode": "force-https" }, + { "name": "wasema.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "webseitendesigner.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "westeros.hu", "include_subdomains": true, "mode": "force-https" }, + { "name": "wiimotion.de", "include_subdomains": true, "mode": "force-https" }, + { "name": "winclient.cn", "include_subdomains": true, "mode": "force-https" }, + { "name": "winmodels.org", "include_subdomains": true, "mode": "force-https" }, + { "name": "winmodels.ru", "include_subdomains": true, "mode": "force-https" }, + { "name": "winterfeldt.de", "include_subdomains": true, "mode": "force-https" }, + { "name": "wolfachtal-alpaka.de", "include_subdomains": true, "mode": "force-https" }, + { "name": "wolfsden.cz", "include_subdomains": true, "mode": "force-https" }, + { "name": "wolfwings.us", "include_subdomains": true, "mode": "force-https" }, + { "name": "woodbury.io", "include_subdomains": true, "mode": "force-https" }, + { "name": "woodomat.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "workingclassmedia.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "wpfortify.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "wpvulndb.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "xdd.io", "include_subdomains": true, "mode": "force-https" }, + { "name": "xiangweiqing.co.uk", "include_subdomains": true, "mode": "force-https" }, + { "name": "xkviz.net", "include_subdomains": true, "mode": "force-https" }, + { "name": "xuexb.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "xwaretech.info", "include_subdomains": true, "mode": "force-https" }, + { "name": "y-s.pw", "include_subdomains": true, "mode": "force-https" }, + { "name": "youcontrol.ru", "include_subdomains": true, "mode": "force-https" }, + { "name": "youyoulemon.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "ytvwld.de", "include_subdomains": true, "mode": "force-https" }, + { "name": "yuyu.io", "include_subdomains": true, "mode": "force-https" }, + { "name": "yvesx.com", "include_subdomains": true, "mode": "force-https" }, + { "name": "zhanghao.me", "include_subdomains": true, "mode": "force-https" }, + { "name": "zorz.info", "include_subdomains": true, "mode": "force-https" } ], // |ReportUMAOnPinFailure| uses these to report which domain was associated
diff --git a/net/net.gyp b/net/net.gyp index 98bb5c0..dd67a2a 100644 --- a/net/net.gyp +++ b/net/net.gyp
@@ -117,7 +117,6 @@ 'sources': [ 'base/filename_util_icu.cc', 'base/net_string_util_icu.cc', - 'base/net_util_icu.cc', 'filter/brotli_filter.cc', ], 'includes': [ 'net_common.gypi' ], @@ -273,6 +272,7 @@ ['disable_file_support==1', { 'sources!': [ 'base/directory_lister_unittest.cc', + 'base/directory_listing_unittest.cc', 'url_request/url_request_file_job_unittest.cc', ], }], @@ -836,8 +836,8 @@ 'tools/quic/quic_in_memory_cache.h', 'tools/quic/quic_per_connection_packet_writer.cc', 'tools/quic/quic_per_connection_packet_writer.h', - 'tools/quic/quic_server_session.cc', - 'tools/quic/quic_server_session.h', + 'tools/quic/quic_server_session_base.cc', + 'tools/quic/quic_server_session_base.h', 'tools/quic/quic_simple_client.cc', 'tools/quic/quic_simple_client.h', 'tools/quic/quic_simple_per_connection_packet_writer.cc', @@ -846,6 +846,8 @@ 'tools/quic/quic_simple_server.h', 'tools/quic/quic_simple_server_packet_writer.cc', 'tools/quic/quic_simple_server_packet_writer.h', + 'tools/quic/quic_simple_server_session.cc', + 'tools/quic/quic_simple_server_session.h', 'tools/quic/quic_spdy_client_stream.cc', 'tools/quic/quic_spdy_client_stream.h', 'tools/quic/quic_simple_server_stream.cc',
diff --git a/net/net.gypi b/net/net.gypi index 2bb7137c..eddea8a 100644 --- a/net/net.gypi +++ b/net/net.gypi
@@ -28,10 +28,10 @@ 'base/host_port_pair.h', 'base/io_buffer.cc', 'base/io_buffer.h', - 'base/ip_address_number.cc', - 'base/ip_address_number.h', 'base/ip_address.cc', 'base/ip_address.h', + 'base/ip_address_number.cc', + 'base/ip_address_number.h', 'base/ip_endpoint.cc', 'base/ip_endpoint.h', 'base/load_timing_info.cc', @@ -101,12 +101,12 @@ 'cert/internal/signature_algorithm.h', 'cert/internal/signature_policy.cc', 'cert/internal/signature_policy.h', + 'cert/internal/verify_certificate_chain.cc', + 'cert/internal/verify_certificate_chain.h', 'cert/internal/verify_name_match.cc', 'cert/internal/verify_name_match.h', 'cert/internal/verify_signed_data.cc', 'cert/internal/verify_signed_data.h', - 'cert/internal/verify_certificate_chain.cc', - 'cert/internal/verify_certificate_chain.h', 'cert/pem_tokenizer.cc', 'cert/pem_tokenizer.h', 'cert/sha256_legacy_support_win.cc', @@ -135,10 +135,10 @@ 'der/tag.h', 'dns/dns_util.cc', 'dns/dns_util.h', - 'http/http_auth_scheme.cc', - 'http/http_auth_scheme.h', 'http/http_auth_challenge_tokenizer.cc', 'http/http_auth_challenge_tokenizer.h', + 'http/http_auth_scheme.cc', + 'http/http_auth_scheme.h', 'http/http_byte_range.cc', 'http/http_byte_range.h', 'http/http_log_util.cc', @@ -992,6 +992,8 @@ 'quic/crypto/aead_base_encrypter_nss.cc', 'quic/crypto/aes_128_gcm_12_decrypter_nss.cc', 'quic/crypto/aes_128_gcm_12_encrypter_nss.cc', + 'quic/crypto/cert_compressor.cc', + 'quic/crypto/cert_compressor.h', 'quic/crypto/chacha20_poly1305_decrypter_nss.cc', 'quic/crypto/chacha20_poly1305_encrypter_nss.cc', 'quic/crypto/chacha20_poly1305_rfc7539_decrypter_nss.cc', @@ -1001,38 +1003,37 @@ 'quic/crypto/proof_source_chromium.h', 'quic/crypto/proof_source_chromium_nss.cc', 'quic/crypto/proof_source_chromium_openssl.cc', - 'quic/quic_chromium_client_session.cc', - 'quic/quic_chromium_client_session.h', - 'quic/quic_client_session_base.cc', - 'quic/quic_client_session_base.h', - 'quic/quic_headers_stream.cc', - 'quic/quic_headers_stream.h', - 'quic/quic_http_stream.cc', - 'quic/quic_http_stream.h', - 'quic/quic_http_utils.cc', - 'quic/quic_http_utils.h', - 'quic/quic_stream_factory.cc', - 'quic/quic_stream_factory.h', - 'quic/spdy_utils.cc', - 'quic/crypto/cert_compressor.cc', - 'quic/crypto/cert_compressor.h', 'quic/crypto/quic_crypto_client_config.cc', 'quic/crypto/quic_crypto_client_config.h', 'quic/crypto/quic_crypto_server_config.cc', 'quic/crypto/quic_crypto_server_config.h', 'quic/network_connection.cc', 'quic/network_connection.h', + 'quic/quic_chromium_client_session.cc', + 'quic/quic_chromium_client_session.h', + 'quic/quic_client_session_base.cc', + 'quic/quic_client_session_base.h', 'quic/quic_crypto_client_stream.cc', 'quic/quic_crypto_client_stream.h', + 'quic/quic_crypto_client_stream_factory.cc', 'quic/quic_crypto_client_stream_factory.h', 'quic/quic_crypto_server_stream.cc', 'quic/quic_crypto_server_stream.h', + 'quic/quic_headers_stream.cc', + 'quic/quic_headers_stream.h', + 'quic/quic_http_stream.cc', + 'quic/quic_http_stream.h', + 'quic/quic_http_utils.cc', + 'quic/quic_http_utils.h', 'quic/quic_reliable_client_stream.cc', 'quic/quic_reliable_client_stream.h', 'quic/quic_spdy_session.cc', 'quic/quic_spdy_session.h', 'quic/quic_spdy_stream.cc', 'quic/quic_spdy_stream.h', + 'quic/quic_stream_factory.cc', + 'quic/quic_stream_factory.h', + 'quic/spdy_utils.cc', 'quic/spdy_utils.h', 'sdch/sdch_owner.cc', 'sdch/sdch_owner.h', @@ -1116,6 +1117,7 @@ 'spdy/hpack/hpack_output_stream.h', 'spdy/hpack/hpack_static_table.cc', 'spdy/hpack/hpack_static_table.h', + 'spdy/priority_write_scheduler.h', 'spdy/spdy_alt_svc_wire_format.cc', 'spdy/spdy_alt_svc_wire_format.h', 'spdy/spdy_bitmasks.h', @@ -1160,7 +1162,6 @@ 'spdy/spdy_write_queue.cc', 'spdy/spdy_write_queue.h', 'spdy/write_blocked_list.h', - 'spdy/priority_write_scheduler.h', 'ssl/client_cert_store.h', 'ssl/client_cert_store_mac.cc', 'ssl/client_cert_store_mac.h', @@ -1173,11 +1174,11 @@ 'ssl/ssl_key_logger.cc', 'ssl/ssl_key_logger.h', 'ssl/ssl_platform_key.h', - 'ssl/ssl_platform_key_task_runner.cc', - 'ssl/ssl_platform_key_task_runner.h', 'ssl/ssl_platform_key_android.cc', 'ssl/ssl_platform_key_mac.cc', 'ssl/ssl_platform_key_nss.cc', + 'ssl/ssl_platform_key_task_runner.cc', + 'ssl/ssl_platform_key_task_runner.h', 'ssl/ssl_platform_key_win.cc', 'ssl/threaded_ssl_private_key.cc', 'ssl/threaded_ssl_private_key.h', @@ -1301,6 +1302,7 @@ 'base/chunked_upload_data_stream_unittest.cc', 'base/data_url_unittest.cc', 'base/directory_lister_unittest.cc', + 'base/directory_listing_unittest.cc', 'base/elements_upload_data_stream_unittest.cc', 'base/escape_unittest.cc', 'base/expiring_cache_unittest.cc', @@ -1318,7 +1320,6 @@ 'base/lookup_string_in_fixed_set_unittest.cc', 'base/mime_sniffer_unittest.cc', 'base/mime_util_unittest.cc', - 'base/net_util_icu_unittest.cc', 'base/net_util_unittest.cc', 'base/network_activity_monitor_unittest.cc', 'base/network_change_notifier_unittest.cc', @@ -1331,8 +1332,8 @@ 'base/registry_controlled_domains/registry_controlled_domain_unittest.cc', 'base/sdch_dictionary_unittest.cc', 'base/sdch_manager_unittest.cc', - 'base/static_cookie_policy_unittest.cc', 'base/stale_while_revalidate_experiment_domains_unittest.cc', + 'base/static_cookie_policy_unittest.cc', 'base/test_completion_callback_unittest.cc', 'base/upload_bytes_element_reader_unittest.cc', 'base/upload_file_element_reader_unittest.cc', @@ -1558,8 +1559,8 @@ 'quic/crypto/quic_crypto_server_config_test.cc', 'quic/crypto/quic_random_test.cc', 'quic/crypto/strike_register_test.cc', - 'quic/interval_test.cc', 'quic/interval_set_test.cc', + 'quic/interval_test.cc', 'quic/iovector_test.cc', 'quic/network_connection_unittest.cc', 'quic/p2p/quic_p2p_session_test.cc', @@ -1707,6 +1708,7 @@ 'spdy/hpack/hpack_static_table_test.cc', 'spdy/mock_spdy_framer_visitor.cc', 'spdy/mock_spdy_framer_visitor.h', + 'spdy/priority_write_scheduler_test.cc', 'spdy/spdy_alt_svc_wire_format_test.cc', 'spdy/spdy_buffer_unittest.cc', 'spdy/spdy_frame_builder_test.cc', @@ -1735,7 +1737,6 @@ 'spdy/spdy_test_utils.cc', 'spdy/spdy_test_utils.h', 'spdy/spdy_write_queue_unittest.cc', - 'spdy/priority_write_scheduler_test.cc', 'spdy/write_blocked_list_test.cc', 'ssl/channel_id_service_unittest.cc', 'ssl/client_cert_store_mac_unittest.cc', @@ -1816,11 +1817,11 @@ 'tools/quic/quic_epoll_clock_test.cc', 'tools/quic/quic_epoll_connection_helper_test.cc', 'tools/quic/quic_in_memory_cache_test.cc', - 'tools/quic/quic_server_session_test.cc', + 'tools/quic/quic_server_session_base_test.cc', 'tools/quic/quic_server_test.cc', + 'tools/quic/quic_simple_server_session_test.cc', 'tools/quic/quic_simple_server_test.cc', 'tools/quic/quic_spdy_client_stream_test.cc', - 'tools/quic/quic_simple_server_stream_test.cc', 'tools/quic/quic_time_wait_list_manager_test.cc', 'tools/quic/spdy_balsa_utils_test.cc', 'tools/quic/test_tools/http_message.cc', @@ -1860,6 +1861,8 @@ 'net_file_support_sources': [ "base/directory_lister.cc", "base/directory_lister.h", + "base/directory_listing.cc", + "base/directory_listing.h", "url_request/file_protocol_handler.cc", "url_request/file_protocol_handler.h", "url_request/url_request_file_dir_job.cc",
diff --git a/net/quic/congestion_control/tcp_cubic_bytes_sender_test.cc b/net/quic/congestion_control/tcp_cubic_bytes_sender_test.cc index 48f290c..b2acbee 100644 --- a/net/quic/congestion_control/tcp_cubic_bytes_sender_test.cc +++ b/net/quic/congestion_control/tcp_cubic_bytes_sender_test.cc
@@ -24,7 +24,7 @@ // TODO(ianswett): A number of theses tests were written with the assumption of // an initial CWND of 10. They have carefully calculated values which should be -// updated to be based on kInitialCongestionWindowInsecure. +// updated to be based on kInitialCongestionWindow. const uint32_t kInitialCongestionWindowPackets = 10; const uint32_t kDefaultWindowTCP = kInitialCongestionWindowPackets * kDefaultTCPMSS;
diff --git a/net/quic/congestion_control/tcp_cubic_sender_test.cc b/net/quic/congestion_control/tcp_cubic_sender_test.cc index 493933a..f37e505 100644 --- a/net/quic/congestion_control/tcp_cubic_sender_test.cc +++ b/net/quic/congestion_control/tcp_cubic_sender_test.cc
@@ -26,7 +26,7 @@ // TODO(ianswett): A number of theses tests were written with the assumption of // an initial CWND of 10. They have carefully calculated values which should be -// updated to be based on kInitialCongestionWindowInsecure. +// updated to be based on kInitialCongestionWindow. const uint32_t kInitialCongestionWindowPackets = 10; const uint32_t kDefaultWindowTCP = kInitialCongestionWindowPackets * kDefaultTCPMSS;
diff --git a/net/quic/crypto/chacha20_poly1305_rfc7539_decrypter_test.cc b/net/quic/crypto/chacha20_poly1305_rfc7539_decrypter_test.cc index e9441a1..0cee4b4 100644 --- a/net/quic/crypto/chacha20_poly1305_rfc7539_decrypter_test.cc +++ b/net/quic/crypto/chacha20_poly1305_rfc7539_decrypter_test.cc
@@ -14,7 +14,7 @@ // The test vectors come from RFC 7539 Section 2.8.2. // Each test vector consists of six strings of lowercase hexadecimal digits. -// The strings may be empty (zero length). A test vector with a NULL |key| +// The strings may be empty (zero length). A test vector with a nullptr |key| // marks the end of an array of test vectors. struct TestVector { // Input:
diff --git a/net/quic/crypto/chacha20_poly1305_rfc7539_encrypter_test.cc b/net/quic/crypto/chacha20_poly1305_rfc7539_encrypter_test.cc index 3b25cc4..1654ea3 100644 --- a/net/quic/crypto/chacha20_poly1305_rfc7539_encrypter_test.cc +++ b/net/quic/crypto/chacha20_poly1305_rfc7539_encrypter_test.cc
@@ -17,7 +17,7 @@ // The test vectors come from RFC 7539 Section 2.8.2. // Each test vector consists of five strings of lowercase hexadecimal digits. -// The strings may be empty (zero length). A test vector with a NULL |key| +// The strings may be empty (zero length). A test vector with a nullptr |key| // marks the end of an array of test vectors. struct TestVector { const char* key; @@ -58,7 +58,7 @@ "6116" "1ae10b594f09e26a7e902ecb", // "d0600691" truncated }, - {NULL}}; + {nullptr}}; } // namespace
diff --git a/net/quic/crypto/quic_crypto_client_config.h b/net/quic/crypto/quic_crypto_client_config.h index ef65d20..34be5484 100644 --- a/net/quic/crypto/quic_crypto_client_config.h +++ b/net/quic/crypto/quic_crypto_client_config.h
@@ -243,8 +243,7 @@ // true for that server's CachedState. If the rejection message contains state // about a future handshake (i.e. an nonce value from the server), then it // will be saved in |out_params|. |now| is used to judge whether the server - // config in the rejection message has expired. |is_https| is used to track - // reject reason for secure vs insecure QUIC. + // config in the rejection message has expired. QuicErrorCode ProcessRejection(const CryptoHandshakeMessage& rej, QuicWallTime now, QuicVersion version,
diff --git a/net/quic/crypto/quic_crypto_server_config.cc b/net/quic/crypto/quic_crypto_server_config.cc index 875f826..c7b83bfb 100644 --- a/net/quic/crypto/quic_crypto_server_config.cc +++ b/net/quic/crypto/quic_crypto_server_config.cc
@@ -704,13 +704,8 @@ hkdf_suffix.append(client_hello_serialized.data(), client_hello_serialized.length()); hkdf_suffix.append(requested_config->serialized); - // The addition of x509_supported in this if statement is so that an insecure - // quic client talking to a secure quic server will not result in the secure - // quic server adding the cert to the kdf. - // TODO(nharper): Should a server that is configured to be secure (i.e. one - // that has a proof_source_) be accepting responses from an insecure client? DCHECK(proof_source_.get()); - if (version > QUIC_VERSION_25 && x509_supported) { + if (version > QUIC_VERSION_25) { if (crypto_proof->certs->empty()) { *error_details = "Failed to get certs"; return QUIC_CRYPTO_INTERNAL_ERROR;
diff --git a/net/quic/quic_chromium_client_session.cc b/net/quic/quic_chromium_client_session.cc index 501732f..5cb49788 100644 --- a/net/quic/quic_chromium_client_session.cc +++ b/net/quic/quic_chromium_client_session.cc
@@ -201,13 +201,10 @@ disabled_reason_(QUIC_DISABLED_NOT), weak_factory_(this) { crypto_stream_.reset( - crypto_client_stream_factory - ? crypto_client_stream_factory->CreateQuicCryptoClientStream( - server_id, this, crypto_config) - : new QuicCryptoClientStream( - server_id, this, - new ProofVerifyContextChromium(cert_verify_flags, net_log_), - crypto_config)); + crypto_client_stream_factory->CreateQuicCryptoClientStream( + server_id, this, make_scoped_ptr(new ProofVerifyContextChromium( + cert_verify_flags, net_log_)), + crypto_config)); connection->set_debug_visitor(logger_.get()); net_log_.BeginEvent(NetLog::TYPE_QUIC_SESSION, base::Bind(NetLogQuicClientSessionCallback, &server_id, @@ -566,8 +563,8 @@ } SSLInfo ssl_info; if (!GetSSLInfo(&ssl_info) || !ssl_info.cert.get()) { - // We can always pool with insecure QUIC sessions. - return true; + NOTREACHED() << "QUIC should always have certificates."; + return false; } return SpdySession::CanPool(transport_security_state_, ssl_info,
diff --git a/net/quic/quic_chromium_client_session_test.cc b/net/quic/quic_chromium_client_session_test.cc index 38dd849a..ba831ef 100644 --- a/net/quic/quic_chromium_client_session_test.cc +++ b/net/quic/quic_chromium_client_session_test.cc
@@ -22,6 +22,7 @@ #include "net/quic/crypto/quic_decrypter.h" #include "net/quic/crypto/quic_encrypter.h" #include "net/quic/crypto/quic_server_info.h" +#include "net/quic/quic_crypto_client_stream_factory.h" #include "net/quic/quic_flags.h" #include "net/quic/quic_packet_reader.h" #include "net/quic/quic_protocol.h" @@ -56,7 +57,7 @@ connection_, GetSocket(), /*stream_factory=*/nullptr, - /*crypto_client_stream_factory=*/nullptr, + QuicCryptoClientStreamFactory::GetDefaultFactory(), &clock_, &transport_security_state_, make_scoped_ptr((QuicServerInfo*)nullptr),
diff --git a/net/quic/quic_client_session_base.h b/net/quic/quic_client_session_base.h index 8acfd4f..ba7be85 100644 --- a/net/quic/quic_client_session_base.h +++ b/net/quic/quic_client_session_base.h
@@ -20,9 +20,7 @@ // Called when the proof in |cached| is marked valid. If this is a secure // QUIC session, then this will happen only after the proof verifier - // completes. If this is an insecure QUIC connection, this will happen - // as soon as a valid config is discovered (either from the cache or - // from the server). + // completes. virtual void OnProofValid( const QuicCryptoClientConfig::CachedState& cached) = 0;
diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc index 322a20b..a3298bc 100644 --- a/net/quic/quic_connection.cc +++ b/net/quic/quic_connection.cc
@@ -1121,12 +1121,6 @@ LOG(DFATAL) << "Attempt to send empty stream frame"; return QuicConsumedData(0, false); } - if (FLAGS_quic_never_write_unencrypted_data && id != kCryptoStreamId && - encryption_level_ == ENCRYPTION_NONE) { - LOG(DFATAL) << "Cannot send stream data without encryption."; - CloseConnection(QUIC_UNENCRYPTED_STREAM_DATA, false); - return QuicConsumedData(0, false); - } // Opportunistically bundle an ack with every outgoing packet. // Particularly, we want to bundle with handshake packets since we don't know @@ -2019,10 +2013,6 @@ return group_map_[fec_group_num]; } -void QuicConnection::SendConnectionClose(QuicErrorCode error) { - SendConnectionCloseWithDetails(error, string()); -} - void QuicConnection::SendConnectionCloseWithDetails(QuicErrorCode error, const string& details) { // If we're write blocked, WritePacket() will not send, but will capture the
diff --git a/net/quic/quic_connection.h b/net/quic/quic_connection.h index ac1b284c..4b23ba9 100644 --- a/net/quic/quic_connection.h +++ b/net/quic/quic_connection.h
@@ -353,7 +353,6 @@ // Sends a connection close frame to the peer, and closes the connection by // calling CloseConnection(notifying the visitor as it does so). - virtual void SendConnectionClose(QuicErrorCode error); virtual void SendConnectionCloseWithDetails(QuicErrorCode error, const std::string& details); // Notifies the visitor of the close and marks the connection as disconnected.
diff --git a/net/quic/quic_crypto_client_stream.cc b/net/quic/quic_crypto_client_stream.cc index 2942eef..acf0035 100644 --- a/net/quic/quic_crypto_client_stream.cc +++ b/net/quic/quic_crypto_client_stream.cc
@@ -258,6 +258,8 @@ // expiration because it may have been a while since we last verified // the proof. DCHECK(crypto_config_->proof_verifier()); + // Track proof verification time when cached server config is used. + proof_verify_start_time_ = base::TimeTicks::Now(); // If the cached state needs to be verified, do it now. next_state_ = STATE_VERIFY_PROOF; } else { @@ -480,6 +482,10 @@ void QuicCryptoClientStream::DoVerifyProofComplete( QuicCryptoClientConfig::CachedState* cached) { + if (!proof_verify_start_time_.is_null()) { + UMA_HISTOGRAM_TIMES("Net.QuicSession.VerifyProofTime.CachedServerConfig", + base::TimeTicks::Now() - proof_verify_start_time_); + } if (!verify_ok_) { if (verify_details_.get()) { client_session()->OnProofVerifyDetailsAvailable(*verify_details_);
diff --git a/net/quic/quic_crypto_client_stream.h b/net/quic/quic_crypto_client_stream.h index 01fd8d3..cd2e7da 100644 --- a/net/quic/quic_crypto_client_stream.h +++ b/net/quic/quic_crypto_client_stream.h
@@ -236,6 +236,8 @@ // STATE_VERIFY_PROOF*, and subsequent STATE_SEND_CHLO state. bool stateless_reject_received_; + base::TimeTicks proof_verify_start_time_; + DISALLOW_COPY_AND_ASSIGN(QuicCryptoClientStream); };
diff --git a/net/quic/quic_crypto_client_stream_factory.cc b/net/quic/quic_crypto_client_stream_factory.cc new file mode 100644 index 0000000..03565ba --- /dev/null +++ b/net/quic/quic_crypto_client_stream_factory.cc
@@ -0,0 +1,39 @@ +// Copyright (c) 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/quic/quic_crypto_client_stream_factory.h" + +#include "base/lazy_instance.h" +#include "net/quic/crypto/proof_verifier_chromium.h" +#include "net/quic/quic_chromium_client_session.h" +#include "net/quic/quic_crypto_client_stream.h" + +namespace net { + +namespace { + +class DefaultCryptoStreamFactory : public QuicCryptoClientStreamFactory { + public: + QuicCryptoClientStream* CreateQuicCryptoClientStream( + const QuicServerId& server_id, + QuicChromiumClientSession* session, + scoped_ptr<ProofVerifyContext> proof_verify_context, + QuicCryptoClientConfig* crypto_config) override { + return new QuicCryptoClientStream( + server_id, session, proof_verify_context.release(), crypto_config); + } +}; + +static base::LazyInstance<DefaultCryptoStreamFactory>::Leaky + g_default_crypto_stream_factory = LAZY_INSTANCE_INITIALIZER; + +} // namespace + +// static +QuicCryptoClientStreamFactory* +QuicCryptoClientStreamFactory::GetDefaultFactory() { + return g_default_crypto_stream_factory.Pointer(); +} + +} // namespace net
diff --git a/net/quic/quic_crypto_client_stream_factory.h b/net/quic/quic_crypto_client_stream_factory.h index 6c9194e..cd1d430 100644 --- a/net/quic/quic_crypto_client_stream_factory.h +++ b/net/quic/quic_crypto_client_stream_factory.h
@@ -7,11 +7,14 @@ #include <string> +#include "base/memory/scoped_ptr.h" #include "net/base/net_export.h" namespace net { +class ProofVerifyContext; class QuicChromiumClientSession; +class QuicCryptoClientConfig; class QuicCryptoClientStream; class QuicServerId; @@ -24,7 +27,10 @@ virtual QuicCryptoClientStream* CreateQuicCryptoClientStream( const QuicServerId& server_id, QuicChromiumClientSession* session, + scoped_ptr<ProofVerifyContext> proof_verify_context, QuicCryptoClientConfig* crypto_config) = 0; + + static QuicCryptoClientStreamFactory* GetDefaultFactory(); }; } // namespace net
diff --git a/net/quic/quic_flags.cc b/net/quic/quic_flags.cc index 17c2e624..e330230 100644 --- a/net/quic/quic_flags.cc +++ b/net/quic/quic_flags.cc
@@ -136,3 +136,6 @@ // If true, drop not awaited QUIC packets before decrypting them. bool FLAGS_quic_drop_non_awaited_packets = false; + +// If true, use the fast implementation of IncrementalHash/FNV1a_128_Hash. +bool FLAGS_quic_utils_use_fast_incremental_hash = true;
diff --git a/net/quic/quic_flags.h b/net/quic/quic_flags.h index 29c68e9b..c890f6f 100644 --- a/net/quic/quic_flags.h +++ b/net/quic/quic_flags.h
@@ -43,4 +43,5 @@ NET_EXPORT_PRIVATE extern bool FLAGS_quic_inplace_encryption; NET_EXPORT_PRIVATE extern bool FLAGS_quic_use_rfc7539; NET_EXPORT_PRIVATE extern bool FLAGS_quic_drop_non_awaited_packets; +NET_EXPORT_PRIVATE extern bool FLAGS_quic_utils_use_fast_incremental_hash; #endif // NET_QUIC_QUIC_FLAGS_H_
diff --git a/net/quic/quic_framer.cc b/net/quic/quic_framer.cc index 3ca7903..d4660bfa2 100644 --- a/net/quic/quic_framer.cc +++ b/net/quic/quic_framer.cc
@@ -137,6 +137,7 @@ entropy_calculator_(nullptr), error_(QUIC_NO_ERROR), last_packet_number_(0), + last_path_id_(kInvalidPathId), last_serialized_connection_id_(0), supported_versions_(supported_versions), decrypter_level_(ENCRYPTION_NONE), @@ -822,8 +823,35 @@ return QuicTime::Delta::FromMicroseconds(time); } +bool QuicFramer::IsValidPath(QuicPathId path_id, + QuicPacketNumber* last_packet_number) { + if (ContainsKey(closed_paths_, path_id)) { + // Path is closed. + return false; + } + + if (path_id == last_path_id_) { + *last_packet_number = last_packet_number_; + return true; + } + + if (ContainsKey(last_packet_numbers_, path_id)) { + *last_packet_number = last_packet_numbers_[path_id]; + } else { + *last_packet_number = 0; + } + + return true; +} + +void QuicFramer::OnPathClosed(QuicPathId path_id) { + closed_paths_.insert(path_id); + last_packet_numbers_.erase(path_id); +} + QuicPacketNumber QuicFramer::CalculatePacketNumberFromWire( QuicPacketNumberLength packet_number_length, + QuicPacketNumber last_packet_number, QuicPacketNumber packet_number) const { // The new packet number might have wrapped to the next epoch, or // it might have reverse wrapped to the previous epoch, or it might @@ -835,8 +863,8 @@ // number or an adjacent epoch. const QuicPacketNumber epoch_delta = UINT64_C(1) << (8 * packet_number_length); - QuicPacketNumber next_packet_number = last_packet_number_ + 1; - QuicPacketNumber epoch = last_packet_number_ & ~(epoch_delta - 1); + QuicPacketNumber next_packet_number = last_packet_number + 1; + QuicPacketNumber epoch = last_packet_number & ~(epoch_delta - 1); QuicPacketNumber prev_epoch = epoch - epoch_delta; QuicPacketNumber next_epoch = epoch + epoch_delta; @@ -1020,9 +1048,16 @@ return RaiseError(QUIC_INVALID_PACKET_HEADER); } - if (!ProcessPacketSequenceNumber(encrypted_reader, - header->public_header.packet_number_length, - &header->packet_number)) { + QuicPacketNumber last_packet_number = last_packet_number_; + if (header->public_header.multipath_flag && + !IsValidPath(header->path_id, &last_packet_number)) { + // Stop processing because path is closed. + return false; + } + + if (!ProcessPacketSequenceNumber( + encrypted_reader, header->public_header.packet_number_length, + last_packet_number, &header->packet_number)) { set_detailed_error("Unable to read packet number."); return RaiseError(QUIC_INVALID_PACKET_HEADER); } @@ -1074,6 +1109,15 @@ header->entropy_hash = GetPacketEntropyHash(*header); // Set the last packet number after we have decrypted the packet // so we are confident is not attacker controlled. + if (header->public_header.multipath_flag && + header->path_id != last_path_id_) { + if (last_path_id_ != kInvalidPathId) { + // Save current last packet number before changing path. + last_packet_numbers_[last_path_id_] = last_packet_number_; + } + // Change path. + last_path_id_ = header->path_id; + } last_packet_number_ = header->packet_number; return true; } @@ -1089,6 +1133,7 @@ bool QuicFramer::ProcessPacketSequenceNumber( QuicDataReader* reader, QuicPacketNumberLength packet_number_length, + QuicPacketNumber last_packet_number, QuicPacketNumber* packet_number) { QuicPacketNumber wire_packet_number = 0u; if (!reader->ReadBytes(&wire_packet_number, packet_number_length)) { @@ -1097,8 +1142,8 @@ // TODO(ianswett): Explore the usefulness of trying multiple packet numbers // in case the first guess is incorrect. - *packet_number = - CalculatePacketNumberFromWire(packet_number_length, wire_packet_number); + *packet_number = CalculatePacketNumberFromWire( + packet_number_length, last_packet_number, wire_packet_number); return true; }
diff --git a/net/quic/quic_framer.h b/net/quic/quic_framer.h index 3e5e719..a7fd9fa 100644 --- a/net/quic/quic_framer.h +++ b/net/quic/quic_framer.h
@@ -357,6 +357,9 @@ static QuicPacketEntropyHash GetPacketEntropyHash( const QuicPacketHeader& header); + // Called when a PATH_CLOSED frame has been sent/received on |path_id|. + void OnPathClosed(QuicPathId path_id); + private: friend class test::QuicFramerPeer; @@ -400,6 +403,7 @@ bool ProcessPathId(QuicDataReader* reader, QuicPathId* path_id); bool ProcessPacketSequenceNumber(QuicDataReader* reader, QuicPacketNumberLength packet_number_length, + QuicPacketNumber last_packet_number, QuicPacketNumber* packet_number); bool ProcessFrameData(QuicDataReader* reader, const QuicPacketHeader& header); bool ProcessStreamFrame(QuicDataReader* reader, @@ -427,10 +431,16 @@ size_t buffer_length, size_t* decrypted_length); + // Checks if |path_id| is a viable path to receive packets on. Returns true + // and sets |last_packet_number| if the path is not closed. Returns false + // otherwise. + bool IsValidPath(QuicPathId path_id, QuicPacketNumber* last_packet_number); + // Returns the full packet number from the truncated // wire format version and the last seen packet number. QuicPacketNumber CalculatePacketNumberFromWire( QuicPacketNumberLength packet_number_length, + QuicPacketNumber last_packet_number, QuicPacketNumber packet_number) const; // Returns the QuicTime::Delta corresponding to the time from when the framer @@ -499,8 +509,18 @@ QuicFramerVisitorInterface* visitor_; QuicReceivedEntropyHashCalculatorInterface* entropy_calculator_; QuicErrorCode error_; + // Set of closed paths. A path is considered as closed if a PATH_CLOSED frame + // has been sent/received. + // TODO(fayang): this set is never cleaned up. A possible improvement is to + // use intervals. + base::hash_set<QuicPathId> closed_paths_; + // Map mapping path id to packet number of last successfully decrypted/revived + // received packet. + base::hash_map<QuicPathId, QuicPacketNumber> last_packet_numbers_; // Updated by ProcessPacketHeader when it succeeds. QuicPacketNumber last_packet_number_; + // The path on which last successfully decrypted/revived packet was received. + QuicPathId last_path_id_; // Updated by WritePacketHeader. QuicConnectionId last_serialized_connection_id_; // Version of the protocol being used.
diff --git a/net/quic/quic_framer_test.cc b/net/quic/quic_framer_test.cc index 5b5b9859..da33b64 100644 --- a/net/quic/quic_framer_test.cc +++ b/net/quic/quic_framer_test.cc
@@ -475,9 +475,11 @@ QuicPacketNumber last_packet_number) { QuicPacketNumber wire_packet_number = expected_packet_number & kMask; QuicFramerPeer::SetLastPacketNumber(&framer_, last_packet_number); - EXPECT_EQ(expected_packet_number, - QuicFramerPeer::CalculatePacketNumberFromWire( - &framer_, PACKET_6BYTE_PACKET_NUMBER, wire_packet_number)) + EXPECT_EQ( + expected_packet_number, + QuicFramerPeer::CalculatePacketNumberFromWire( + &framer_, PACKET_6BYTE_PACKET_NUMBER, + QuicFramerPeer::GetLastPacketNumber(&framer_), wire_packet_number)) << "last_packet_number: " << last_packet_number << " wire_packet_number: " << wire_packet_number; } @@ -1040,6 +1042,113 @@ } } +TEST_P(QuicFramerTest, PacketHeaderWithPathChange) { + // Packet 1 from path 0x42. + // clang-format off + unsigned char packet1[] = { + // public flags (version) + 0x7C, + // connection_id + 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, + // path_id + 0x42, + // packet number + 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, + // private flags + 0x00, + }; + // clang-format on + + EXPECT_EQ(0u, QuicFramerPeer::GetLastPacketNumber(&framer_)); + EXPECT_EQ(kInvalidPathId, QuicFramerPeer::GetLastPathId(&framer_)); + QuicEncryptedPacket encrypted1(AsChars(packet1), arraysize(packet1), false); + EXPECT_FALSE(framer_.ProcessPacket(encrypted1)); + EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error()); + ASSERT_TRUE(visitor_.header_.get()); + EXPECT_EQ(kConnectionId, visitor_.header_->public_header.connection_id); + EXPECT_EQ(kPathId, visitor_.header_->path_id); + EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number); + EXPECT_EQ(kPacketNumber, QuicFramerPeer::GetLastPacketNumber(&framer_)); + EXPECT_EQ(kPathId, QuicFramerPeer::GetLastPathId(&framer_)); + + // Packet 2 from default path. + // clang-format off + unsigned char packet2[] = { + // public flags (version) + 0x7C, + // connection_id + 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, + // path_id + 0x00, + // packet number + 0xCC, 0x9A, 0x78, 0x56, 0x34, 0x12, + // private flags + 0x00, + }; + // clang-format on + + QuicEncryptedPacket encrypted2(AsChars(packet2), arraysize(packet2), false); + EXPECT_FALSE(framer_.ProcessPacket(encrypted2)); + EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error()); + ASSERT_TRUE(visitor_.header_.get()); + EXPECT_EQ(kConnectionId, visitor_.header_->public_header.connection_id); + EXPECT_EQ(kDefaultPathId, visitor_.header_->path_id); + EXPECT_EQ(kPacketNumber + 16, visitor_.header_->packet_number); + EXPECT_EQ(kPacketNumber + 16, QuicFramerPeer::GetLastPacketNumber(&framer_)); + EXPECT_EQ(kDefaultPathId, QuicFramerPeer::GetLastPathId(&framer_)); + + // Packet 3 from path 0x42. + // clang-format off + unsigned char packet3[] = { + // public flags (version) + 0x7C, + // connection_id + 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, + // path_id + 0x42, + // packet number + 0xBD, 0x9A, 0x78, 0x56, 0x34, 0x12, + // private flags + 0x00, + }; + // clang-format on + + QuicEncryptedPacket encrypted3(AsChars(packet3), arraysize(packet3), false); + EXPECT_FALSE(framer_.ProcessPacket(encrypted3)); + EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error()); + ASSERT_TRUE(visitor_.header_.get()); + EXPECT_EQ(kConnectionId, visitor_.header_->public_header.connection_id); + EXPECT_EQ(kPathId, visitor_.header_->path_id); + EXPECT_EQ(kPacketNumber + 1, visitor_.header_->packet_number); + EXPECT_EQ(kPacketNumber + 1, QuicFramerPeer::GetLastPacketNumber(&framer_)); + EXPECT_EQ(kPathId, QuicFramerPeer::GetLastPathId(&framer_)); +} + +TEST_P(QuicFramerTest, ReceivedPacketOnClosedPath) { + // Packet 1 from path 0x42. + // clang-format off + unsigned char packet[] = { + // public flags (version) + 0x7C, + // connection_id + 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, + // path_id + 0x42, + // packet number + 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, + // private flags + 0x00, + }; + // clang-format on + + framer_.OnPathClosed(kPathId); + QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false); + EXPECT_FALSE(framer_.ProcessPacket(encrypted)); + EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + EXPECT_EQ(0u, QuicFramerPeer::GetLastPacketNumber(&framer_)); + EXPECT_EQ(kInvalidPathId, QuicFramerPeer::GetLastPathId(&framer_)); +} + TEST_P(QuicFramerTest, PacketHeaderWith4BytePacketNumber) { QuicFramerPeer::SetLastPacketNumber(&framer_, kPacketNumber - 2);
diff --git a/net/quic/quic_network_transaction_unittest.cc b/net/quic/quic_network_transaction_unittest.cc index 22ad48c..4beb01d 100644 --- a/net/quic/quic_network_transaction_unittest.cc +++ b/net/quic/quic_network_transaction_unittest.cc
@@ -636,6 +636,7 @@ MockQuicData mock_quic_data2; mock_quic_data2.AddRead(ASYNC, ERR_SOCKET_NOT_CONNECTED); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details_); mock_quic_data1.AddSocketDataToFactory(&socket_factory_); mock_quic_data2.AddSocketDataToFactory(&socket_factory_);
diff --git a/net/quic/quic_packet_creator.cc b/net/quic/quic_packet_creator.cc index 403bd01..233fa9db 100644 --- a/net/quic/quic_packet_creator.cc +++ b/net/quic/quic_packet_creator.cc
@@ -258,7 +258,6 @@ QuicFrame* frame, FecProtection fec_protection) { if (!HasRoomForStreamFrame(id, offset)) { - Flush(); return false; } if (fec_protection == MUST_FEC_PROTECT) { @@ -266,11 +265,14 @@ MaybeStartFecProtection(); } CreateStreamFrame(id, iov, iov_offset, offset, fin, frame); - bool success = AddFrame(*frame, /*save_retransmittable_frames=*/true); + if (!AddFrame(*frame, /*save_retransmittable_frames=*/true)) { + // Fails if we try to write unencrypted stream data. + delete frame->stream_frame; + return false; + } if (needs_padding) { needs_padding_ = true; } - DCHECK(success); if (fec_protection == MUST_FEC_PROTECT && iov_offset + frame->stream_frame->frame_length == iov.total_length) { // Turn off FEC protection when we're done writing protected data. @@ -736,6 +738,13 @@ bool QuicPacketCreator::AddFrame(const QuicFrame& frame, bool save_retransmittable_frames) { DVLOG(1) << "Adding frame: " << frame; + if (FLAGS_quic_never_write_unencrypted_data && frame.type == STREAM_FRAME && + frame.stream_frame->stream_id != kCryptoStreamId && + encryption_level_ == ENCRYPTION_NONE) { + LOG(DFATAL) << "Cannot send stream data without encryption."; + delegate_->CloseConnection(QUIC_UNENCRYPTED_STREAM_DATA, false); + return false; + } InFecGroup is_in_fec_group = MaybeUpdateLengthsAndStartFec(); size_t frame_len = framer_->GetSerializedFrameLength(
diff --git a/net/quic/quic_packet_creator_test.cc b/net/quic/quic_packet_creator_test.cc index a8bc9f4..5dddc54 100644 --- a/net/quic/quic_packet_creator_test.cc +++ b/net/quic/quic_packet_creator_test.cc
@@ -133,6 +133,8 @@ client_framer_.set_visitor(&framer_visitor_); client_framer_.set_received_entropy_calculator(&entropy_calculator_); server_framer_.set_visitor(&framer_visitor_); + // TODO(ianswett): Fix this test so it uses a non-null encrypter. + FLAGS_quic_never_write_unencrypted_data = false; } ~QuicPacketCreatorTest() override {} @@ -1576,6 +1578,15 @@ ClearSerializedPacket(&serialized_packet_); } +TEST_P(QuicPacketCreatorTest, AddUnencryptedStreamDataClosesConnection) { + FLAGS_quic_never_write_unencrypted_data = true; + EXPECT_CALL(delegate_, CloseConnection(_, _)); + QuicStreamFrame stream_frame(kHeadersStreamId, /*fin=*/false, 0u, + StringPiece()); + EXPECT_DFATAL(creator_.AddSavedFrame(QuicFrame(&stream_frame)), + "Cannot send stream data without encryption."); +} + } // namespace } // namespace test } // namespace net
diff --git a/net/quic/quic_packet_generator.cc b/net/quic/quic_packet_generator.cc index 0ca3d50a..00293a18 100644 --- a/net/quic/quic_packet_generator.cc +++ b/net/quic/quic_packet_generator.cc
@@ -130,8 +130,10 @@ if (!packet_creator_.ConsumeData(id, iov, total_bytes_consumed, offset + total_bytes_consumed, fin, has_handshake, &frame, fec_protection)) { - // Current packet is full and flushed. - continue; + // The creator is always flushed if there's not enough room for a new + // stream frame before ConsumeData, so ConsumeData should always succeed. + LOG(DFATAL) << "Failed to ConsumeData, stream:" << id; + return QuicConsumedData(0, false); } // A stream frame is created and added. @@ -157,6 +159,8 @@ // if we're simply writing a fin. break; } + // TODO(ianswett): Move to having the creator flush itself when it's full. + packet_creator_.Flush(); } // Don't allow the handshake to be bundled with other retransmittable frames.
diff --git a/net/quic/quic_packet_generator_test.cc b/net/quic/quic_packet_generator_test.cc index 44f909a..f8c0285c 100644 --- a/net/quic/quic_packet_generator_test.cc +++ b/net/quic/quic_packet_generator_test.cc
@@ -117,6 +117,8 @@ generator_(42, &framer_, &random_, &buffer_allocator_, &delegate_), creator_(QuicPacketGeneratorPeer::GetPacketCreator(&generator_)) { generator_.set_fec_send_policy(GetParam()); + // TODO(ianswett): Fix this test so it uses a non-null encrypter. + FLAGS_quic_never_write_unencrypted_data = false; } ~QuicPacketGeneratorTest() override {
diff --git a/net/quic/quic_protocol.h b/net/quic/quic_protocol.h index aee3543..a816607 100644 --- a/net/quic/quic_protocol.h +++ b/net/quic/quic_protocol.h
@@ -37,6 +37,7 @@ class QuicPacket; struct QuicPacketHeader; +class QuicAckListenerInterface; typedef uint64_t QuicConnectionId; typedef uint32_t QuicStreamId;
diff --git a/net/quic/quic_stream_factory.cc b/net/quic/quic_stream_factory.cc index e48985d..dbfd508 100644 --- a/net/quic/quic_stream_factory.cc +++ b/net/quic/quic_stream_factory.cc
@@ -317,7 +317,8 @@ void QuicStreamFactory::Job::Cancel() { callback_.Reset(); if (session_) - session_->connection()->SendConnectionClose(QUIC_CONNECTION_CANCELLED); + session_->connection()->SendConnectionCloseWithDetails( + QUIC_CONNECTION_CANCELLED, "New job canceled."); } void QuicStreamFactory::Job::CancelWaitForDataReadyCallback() { @@ -473,7 +474,9 @@ // existing session instead. AddressList address(session_->connection()->peer_address()); if (factory_->OnResolution(server_id_, address)) { - session_->connection()->SendConnectionClose(QUIC_CONNECTION_IP_POOLED); + session_->connection()->SendConnectionCloseWithDetails( + QUIC_CONNECTION_IP_POOLED, + "An active session exists for the given IP."); session_ = nullptr; return OK; }
diff --git a/net/quic/quic_stream_factory_test.cc b/net/quic/quic_stream_factory_test.cc index 30868c1..477bb52 100644 --- a/net/quic/quic_stream_factory_test.cc +++ b/net/quic/quic_stream_factory_test.cc
@@ -49,7 +49,10 @@ namespace test { namespace { -const char kDefaultServerHostName[] = "www.google.com"; +const char kDefaultServerHostName[] = "www.example.org"; +const char kServer2HostName[] = "mail.example.org"; +const char kServer3HostName[] = "docs.example.org"; +const char kServer4HostName[] = "images.example.org"; const int kDefaultServerPort = 443; // Run all tests with all the combinations of versions and @@ -248,10 +251,9 @@ } static ProofVerifyDetailsChromium DefaultProofVerifyDetails() { - // Load a certificate that is valid for www.example.org, mail.example.org, - // and mail.example.com. + // Load a certificate that is valid for *.example.org scoped_refptr<X509Certificate> test_cert( - ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem")); + ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem")); EXPECT_TRUE(test_cert.get()); ProofVerifyDetailsChromium verify_details; verify_details.cert_verify_result.verified_cert = test_cert; @@ -311,6 +313,8 @@ TEST_P(QuicStreamFactoryTest, Create) { Initialize(); + ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)}; SequencedSocketData socket_data(reads, arraysize(reads), nullptr, 0); @@ -346,6 +350,8 @@ TEST_P(QuicStreamFactoryTest, CreateZeroRtt) { Initialize(); + ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)}; SequencedSocketData socket_data(reads, arraysize(reads), nullptr, 0); @@ -370,6 +376,8 @@ TEST_P(QuicStreamFactoryTest, CreateZeroRttPost) { Initialize(); + ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)}; SequencedSocketData socket_data(reads, arraysize(reads), nullptr, 0); @@ -401,6 +409,8 @@ TEST_P(QuicStreamFactoryTest, NoZeroRttForDifferentHost) { Initialize(); + ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)}; SequencedSocketData socket_data(reads, arraysize(reads), nullptr, 0); @@ -413,9 +423,9 @@ "192.168.0.1", ""); QuicStreamRequest request(factory_.get()); - int rv = request.Request( - host_port_pair_, privacy_mode_, /*cert_verify_flags=*/0, - "different.host.example.com", "GET", net_log_, callback_.callback()); + int rv = + request.Request(host_port_pair_, privacy_mode_, /*cert_verify_flags=*/0, + kServer2HostName, "GET", net_log_, callback_.callback()); // If server and origin have different hostnames, then handshake confirmation // should be required, so Request will return asynchronously. EXPECT_EQ(ERR_IO_PENDING, rv); @@ -432,6 +442,8 @@ TEST_P(QuicStreamFactoryTest, GoAway) { Initialize(); + ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)}; SequencedSocketData socket_data(reads, arraysize(reads), nullptr, 0); @@ -461,17 +473,18 @@ TEST_P(QuicStreamFactoryTest, Pooling) { Initialize(); + ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)}; SequencedSocketData socket_data(reads, arraysize(reads), nullptr, 0); socket_factory_.AddSocketDataProvider(&socket_data); - HostPortPair server2("mail.google.com", kDefaultServerPort); + HostPortPair server2(kServer2HostName, kDefaultServerPort); host_resolver_.set_synchronous_mode(true); - host_resolver_.rules()->AddIPLiteralRule(kDefaultServerHostName, + host_resolver_.rules()->AddIPLiteralRule(host_port_pair_.host(), "192.168.0.1", ""); - host_resolver_.rules()->AddIPLiteralRule("mail.google.com", "192.168.0.1", - ""); + host_resolver_.rules()->AddIPLiteralRule(server2.host(), "192.168.0.1", ""); QuicStreamRequest request(factory_.get()); EXPECT_EQ(OK, request.Request(host_port_pair_, privacy_mode_, @@ -499,6 +512,9 @@ TEST_P(QuicStreamFactoryTest, NoPoolingIfDisabled) { disable_connection_pooling_ = true; Initialize(); + ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)}; SequencedSocketData socket_data1(reads, arraysize(reads), nullptr, 0); @@ -506,12 +522,11 @@ socket_factory_.AddSocketDataProvider(&socket_data1); socket_factory_.AddSocketDataProvider(&socket_data2); - HostPortPair server2("mail.google.com", kDefaultServerPort); + HostPortPair server2(kServer2HostName, kDefaultServerPort); host_resolver_.set_synchronous_mode(true); - host_resolver_.rules()->AddIPLiteralRule(kDefaultServerHostName, + host_resolver_.rules()->AddIPLiteralRule(host_port_pair_.host(), "192.168.0.1", ""); - host_resolver_.rules()->AddIPLiteralRule("mail.google.com", "192.168.0.1", - ""); + host_resolver_.rules()->AddIPLiteralRule(server2.host(), "192.168.0.1", ""); QuicStreamRequest request(factory_.get()); EXPECT_EQ(OK, request.Request(host_port_pair_, privacy_mode_, @@ -540,6 +555,9 @@ TEST_P(QuicStreamFactoryTest, NoPoolingAfterGoAway) { Initialize(); + ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)}; SequencedSocketData socket_data1(reads, arraysize(reads), nullptr, 0); @@ -547,12 +565,11 @@ socket_factory_.AddSocketDataProvider(&socket_data1); socket_factory_.AddSocketDataProvider(&socket_data2); - HostPortPair server2("mail.google.com", kDefaultServerPort); + HostPortPair server2(kServer2HostName, kDefaultServerPort); host_resolver_.set_synchronous_mode(true); - host_resolver_.rules()->AddIPLiteralRule(kDefaultServerHostName, + host_resolver_.rules()->AddIPLiteralRule(host_port_pair_.host(), "192.168.0.1", ""); - host_resolver_.rules()->AddIPLiteralRule("mail.google.com", "192.168.0.1", - ""); + host_resolver_.rules()->AddIPLiteralRule(server2.host(), "192.168.0.1", ""); QuicStreamRequest request(factory_.get()); EXPECT_EQ(OK, request.Request(host_port_pair_, privacy_mode_, @@ -594,12 +611,13 @@ TEST_P(QuicStreamFactoryTest, HttpsPooling) { Initialize(); + MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)}; SequencedSocketData socket_data(reads, arraysize(reads), nullptr, 0); socket_factory_.AddSocketDataProvider(&socket_data); - HostPortPair server1("www.example.org", 443); - HostPortPair server2("mail.example.org", 443); + HostPortPair server1(kDefaultServerHostName, 443); + HostPortPair server2(kServer2HostName, 443); ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); @@ -640,11 +658,12 @@ socket_factory_.AddSocketDataProvider(&socket_data1); socket_factory_.AddSocketDataProvider(&socket_data2); - HostPortPair server1("www.example.org", 443); - HostPortPair server2("mail.example.org", 443); + HostPortPair server1(kDefaultServerHostName, 443); + HostPortPair server2(kServer2HostName, 443); ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); host_resolver_.set_synchronous_mode(true); host_resolver_.rules()->AddIPLiteralRule(server1.host(), "192.168.0.1", ""); @@ -682,11 +701,11 @@ SequencedSocketData socket_data1(reads, arraysize(reads), nullptr, 0); socket_factory_.AddSocketDataProvider(&socket_data1); - HostPortPair server1("www.example.org", 443); - HostPortPair server2("mail.example.org", 443); + HostPortPair server1(kDefaultServerHostName, 443); + HostPortPair server2(kServer2HostName, 443); - std::string origin_host(valid ? "mail.example.org" : "invalid.example.org"); - HostPortPair alternative("www.example.org", 443); + std::string origin_host(valid ? kServer2HostName : "invalid.example.com"); + HostPortPair alternative(kDefaultServerHostName, 443); ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); bool common_name_fallback_used; @@ -751,11 +770,11 @@ SequencedSocketData socket_data(reads, arraysize(reads), nullptr, 0); socket_factory_.AddSocketDataProvider(&socket_data); - HostPortPair server1("www.example.org", 443); - HostPortPair server2("mail.example.org", 443); + HostPortPair server1(kDefaultServerHostName, 443); + HostPortPair server2(kServer2HostName, 443); uint8_t primary_pin = 1; uint8_t backup_pin = 2; - test::AddPin(&transport_security_state_, "mail.example.org", primary_pin, + test::AddPin(&transport_security_state_, kServer2HostName, primary_pin, backup_pin); ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); @@ -799,17 +818,18 @@ socket_factory_.AddSocketDataProvider(&socket_data1); socket_factory_.AddSocketDataProvider(&socket_data2); - HostPortPair server1("www.example.org", 443); - HostPortPair server2("mail.example.org", 443); + HostPortPair server1(kDefaultServerHostName, 443); + HostPortPair server2(kServer2HostName, 443); uint8_t primary_pin = 1; uint8_t backup_pin = 2; - test::AddPin(&transport_security_state_, "mail.example.org", primary_pin, + test::AddPin(&transport_security_state_, kServer2HostName, primary_pin, backup_pin); ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); verify_details.cert_verify_result.public_key_hashes.push_back( test::GetTestHashValue(primary_pin)); crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); host_resolver_.set_synchronous_mode(true); host_resolver_.rules()->AddIPLiteralRule(server1.host(), "192.168.0.1", ""); @@ -847,12 +867,12 @@ socket_factory_.AddSocketDataProvider(&socket_data1); socket_factory_.AddSocketDataProvider(&socket_data2); - HostPortPair server1("www.example.org", 443); - HostPortPair server2("mail.example.org", 443); + HostPortPair server1(kDefaultServerHostName, 443); + HostPortPair server2(kServer2HostName, 443); uint8_t primary_pin = 1; uint8_t backup_pin = 2; uint8_t bad_pin = 3; - test::AddPin(&transport_security_state_, "mail.example.org", primary_pin, + test::AddPin(&transport_security_state_, kServer2HostName, primary_pin, backup_pin); ProofVerifyDetailsChromium verify_details1 = DefaultProofVerifyDetails(); @@ -895,6 +915,10 @@ TEST_P(QuicStreamFactoryTest, Goaway) { Initialize(); + ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); + MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)}; SequencedSocketData socket_data(reads, arraysize(reads), nullptr, 0); socket_factory_.AddSocketDataProvider(&socket_data); @@ -951,6 +975,9 @@ TEST_P(QuicStreamFactoryTest, MaxOpenStream) { Initialize(); + ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); + QuicStreamId stream_id = kClientDataStreamId1; scoped_ptr<QuicEncryptedPacket> client_rst( maker_.MakeRstPacket(1, true, stream_id, QUIC_STREAM_CANCELLED)); @@ -1080,12 +1107,16 @@ TEST_P(QuicStreamFactoryTest, CreateConsistentEphemeralPort) { Initialize(); + ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); // Sequentially connect to the default host, then another host, and then the // default host. Verify that the default host gets a consistent ephemeral // port, that is different from the other host's connection. - std::string other_server_name = "other.google.com"; + std::string other_server_name = kServer2HostName; EXPECT_NE(kDefaultServerHostName, other_server_name); HostPortPair host_port_pair2(other_server_name, kDefaultServerPort); @@ -1096,6 +1127,10 @@ TEST_P(QuicStreamFactoryTest, GoAwayDisablesConsistentEphemeralPort) { Initialize(); + ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); // Get a session to the host using the port suggester. int original_port = GetSourcePortForNewSessionAndGoAway(host_port_pair_); @@ -1107,6 +1142,10 @@ TEST_P(QuicStreamFactoryTest, CloseAllSessions) { Initialize(); + ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); + MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)}; scoped_ptr<QuicEncryptedPacket> rst(ConstructRstPacket()); std::vector<MockWrite> writes; @@ -1159,6 +1198,9 @@ TEST_P(QuicStreamFactoryTest, OnIPAddressChanged) { close_sessions_on_ip_change_ = true; Initialize(); + ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)}; scoped_ptr<QuicEncryptedPacket> rst(ConstructRstPacket()); @@ -1212,6 +1254,10 @@ TEST_P(QuicStreamFactoryTest, OnSSLConfigChanged) { Initialize(); + ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); + MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)}; scoped_ptr<QuicEncryptedPacket> rst(ConstructRstPacket()); std::vector<MockWrite> writes; @@ -1263,6 +1309,10 @@ TEST_P(QuicStreamFactoryTest, OnCertAdded) { Initialize(); + ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); + MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)}; scoped_ptr<QuicEncryptedPacket> rst(ConstructRstPacket()); std::vector<MockWrite> writes; @@ -1315,6 +1365,10 @@ TEST_P(QuicStreamFactoryTest, OnCACertChanged) { Initialize(); + ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); + MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)}; scoped_ptr<QuicEncryptedPacket> rst(ConstructRstPacket()); std::vector<MockWrite> writes; @@ -1367,6 +1421,7 @@ TEST_P(QuicStreamFactoryTest, SharedCryptoConfig) { Initialize(); + vector<string> cannoncial_suffixes; cannoncial_suffixes.push_back(string(".c.youtube.com")); cannoncial_suffixes.push_back(string(".googlevideo.com")); @@ -1439,6 +1494,8 @@ TEST_P(QuicStreamFactoryTest, RacingConnections) { disable_disk_cache_ = false; Initialize(); + ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); if (!GetParam().enable_connection_racing) return; @@ -1491,6 +1548,9 @@ TEST_P(QuicStreamFactoryTest, EnableNotLoadFromDiskCache) { disable_disk_cache_ = true; Initialize(); + ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); + QuicStreamFactoryPeer::SetTaskRunner(factory_.get(), runner_.get()); MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)}; @@ -1522,6 +1582,12 @@ disable_disk_cache_ = false; max_number_of_lossy_connections_ = 2; Initialize(); + ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); + QuicStreamFactoryPeer::SetTaskRunner(factory_.get(), runner_.get()); EXPECT_FALSE(QuicStreamFactoryPeer::IsQuicDisabled(factory_.get(), @@ -1542,9 +1608,9 @@ SequencedSocketData socket_data4(nullptr, 0, nullptr, 0); socket_factory_.AddSocketDataProvider(&socket_data4); - HostPortPair server2("mail.example.org", kDefaultServerPort); - HostPortPair server3("docs.example.org", kDefaultServerPort); - HostPortPair server4("images.example.org", kDefaultServerPort); + HostPortPair server2(kServer2HostName, kDefaultServerPort); + HostPortPair server3(kServer3HostName, kDefaultServerPort); + HostPortPair server4(kServer4HostName, kDefaultServerPort); crypto_client_stream_factory_.set_handshake_mode( MockCryptoClientStream::ZERO_RTT); @@ -1689,6 +1755,9 @@ disable_disk_cache_ = false; threshold_public_resets_post_handshake_ = 2; Initialize(); + ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); QuicStreamFactoryPeer::SetTaskRunner(factory_.get(), runner_.get()); EXPECT_FALSE(QuicStreamFactoryPeer::IsQuicDisabled(factory_.get(), @@ -1703,7 +1772,7 @@ SequencedSocketData socket_data2(reads, arraysize(reads), nullptr, 0); socket_factory_.AddSocketDataProvider(&socket_data2); - HostPortPair server2("mail.example.org", kDefaultServerPort); + HostPortPair server2(kServer2HostName, kDefaultServerPort); crypto_client_stream_factory_.set_handshake_mode( MockCryptoClientStream::CONFIRM_HANDSHAKE); @@ -1769,6 +1838,9 @@ disable_disk_cache_ = true; threshold_timeouts_with_open_streams_ = 2; Initialize(); + ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); QuicStreamFactoryPeer::SetTaskRunner(factory_.get(), runner_.get()); EXPECT_FALSE(QuicStreamFactoryPeer::IsQuicDisabled(factory_.get(), @@ -1783,7 +1855,7 @@ SequencedSocketData socket_data2(reads, arraysize(reads), nullptr, 0); socket_factory_.AddSocketDataProvider(&socket_data2); - HostPortPair server2("mail.example.org", kDefaultServerPort); + HostPortPair server2(kServer2HostName, kDefaultServerPort); crypto_client_stream_factory_.set_handshake_mode( MockCryptoClientStream::CONFIRM_HANDSHAKE); @@ -1856,6 +1928,10 @@ disable_disk_cache_ = true; threshold_public_resets_post_handshake_ = 2; Initialize(); + ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); EXPECT_FALSE(QuicStreamFactoryPeer::IsQuicDisabled(factory_.get(), host_port_pair_.port())); @@ -1872,8 +1948,8 @@ SequencedSocketData socket_data3(reads, arraysize(reads), nullptr, 0); socket_factory_.AddSocketDataProvider(&socket_data3); - HostPortPair server2("mail.example.org", kDefaultServerPort); - HostPortPair server3("docs.example.org", kDefaultServerPort); + HostPortPair server2(kServer2HostName, kDefaultServerPort); + HostPortPair server3(kServer3HostName, kDefaultServerPort); crypto_client_stream_factory_.set_handshake_mode( MockCryptoClientStream::CONFIRM_HANDSHAKE); @@ -1965,6 +2041,10 @@ disable_disk_cache_ = true; threshold_public_resets_post_handshake_ = 2; Initialize(); + ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); QuicStreamFactoryPeer::SetTaskRunner(factory_.get(), runner_.get()); EXPECT_FALSE(QuicStreamFactoryPeer::IsQuicDisabled(factory_.get(), @@ -1983,8 +2063,8 @@ SequencedSocketData socket_data3(reads, arraysize(reads), nullptr, 0); socket_factory_.AddSocketDataProvider(&socket_data3); - HostPortPair server2("mail.example.org", kDefaultServerPort); - HostPortPair server3("docs.example.org", kDefaultServerPort); + HostPortPair server2(kServer2HostName, kDefaultServerPort); + HostPortPair server3(kServer3HostName, kDefaultServerPort); crypto_client_stream_factory_.set_handshake_mode( MockCryptoClientStream::CONFIRM_HANDSHAKE); @@ -2083,6 +2163,11 @@ disable_disk_cache_ = true; threshold_public_resets_post_handshake_ = 2; Initialize(); + ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); QuicStreamFactoryPeer::SetTaskRunner(factory_.get(), runner_.get()); EXPECT_FALSE(QuicStreamFactoryPeer::IsQuicDisabled(factory_.get(), @@ -2103,9 +2188,9 @@ SequencedSocketData socket_data4(reads, arraysize(reads), nullptr, 0); socket_factory_.AddSocketDataProvider(&socket_data4); - HostPortPair server2("mail.example.org", kDefaultServerPort); - HostPortPair server3("docs.example.org", kDefaultServerPort); - HostPortPair server4("images.example.org", kDefaultServerPort); + HostPortPair server2(kServer2HostName, kDefaultServerPort); + HostPortPair server3(kServer3HostName, kDefaultServerPort); + HostPortPair server4(kServer4HostName, kDefaultServerPort); crypto_client_stream_factory_.set_handshake_mode( MockCryptoClientStream::CONFIRM_HANDSHAKE); @@ -2217,6 +2302,11 @@ disable_disk_cache_ = true; threshold_public_resets_post_handshake_ = 2; Initialize(); + ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); QuicStreamFactoryPeer::SetTaskRunner(factory_.get(), runner_.get()); EXPECT_FALSE(QuicStreamFactoryPeer::IsQuicDisabled(factory_.get(), @@ -2238,9 +2328,9 @@ SequencedSocketData socket_data4(reads, arraysize(reads), nullptr, 0); socket_factory_.AddSocketDataProvider(&socket_data4); - HostPortPair server2("mail.example.org", kDefaultServerPort); - HostPortPair server3("docs.example.org", kDefaultServerPort); - HostPortPair server4("images.example.org", kDefaultServerPort); + HostPortPair server2(kServer2HostName, kDefaultServerPort); + HostPortPair server3(kServer3HostName, kDefaultServerPort); + HostPortPair server4(kServer4HostName, kDefaultServerPort); crypto_client_stream_factory_.set_handshake_mode( MockCryptoClientStream::CONFIRM_HANDSHAKE); @@ -2357,6 +2447,8 @@ TEST_P(QuicStreamFactoryTest, EnableDelayTcpRace) { Initialize(); + ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); bool delay_tcp_race = QuicStreamFactoryPeer::GetDelayTcpRace(factory_.get()); QuicStreamFactoryPeer::SetDelayTcpRace(factory_.get(), false); MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)}; @@ -2407,6 +2499,8 @@ store_server_configs_in_properties_ = true; idle_connection_timeout_seconds_ = 500; Initialize(); + ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); const QuicConfig* config = QuicStreamFactoryPeer::GetConfig(factory_.get()); EXPECT_EQ(500, config->IdleConnectionStateLifetime().ToSeconds()); @@ -2422,7 +2516,8 @@ http_server_properties_.SetAlternativeServices( host_port_pair_, alternative_service_info_vector); - QuicServerId quic_server_id("www.google.com", 80, PRIVACY_MODE_DISABLED); + QuicServerId quic_server_id(kDefaultServerHostName, 80, + PRIVACY_MODE_DISABLED); QuicServerInfoFactory* quic_server_info_factory = new PropertiesBasedQuicServerInfoFactory( http_server_properties_.GetWeakPtr()); @@ -2497,6 +2592,8 @@ TEST_P(QuicStreamFactoryTest, YieldAfterPackets) { Initialize(); + ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); QuicStreamFactoryPeer::SetYieldAfterPackets(factory_.get(), 0); scoped_ptr<QuicEncryptedPacket> close_packet( @@ -2541,6 +2638,8 @@ TEST_P(QuicStreamFactoryTest, YieldAfterDuration) { Initialize(); + ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); QuicStreamFactoryPeer::SetYieldAfterDuration( factory_.get(), QuicTime::Delta::FromMilliseconds(-1));
diff --git a/net/quic/quic_utils.cc b/net/quic/quic_utils.cc index 6748d6a..792aca4 100644 --- a/net/quic/quic_utils.cc +++ b/net/quic/quic_utils.cc
@@ -15,12 +15,68 @@ #include "base/strings/string_number_conversions.h" #include "base/strings/string_split.h" #include "base/strings/stringprintf.h" +#include "net/quic/quic_flags.h" #include "net/quic/quic_write_blocked_list.h" using base::StringPiece; using std::string; namespace net { +namespace { + +// We know that >= GCC 4.8 and Clang have a __uint128_t intrinsic. Other +// compilers don't necessarily, notably MSVC. +#if defined(__x86_64__) && \ + ((defined(__GNUC__) && \ + (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))) || \ + defined(__clang__)) +#define QUIC_UTIL_HAS_UINT128 1 +#endif + +#ifdef QUIC_UTIL_HAS_UINT128 +uint128 IncrementalHashFast(uint128 uhash, const char* data, size_t len) { + // This code ends up faster than the naive implementation for 2 reasons: + // 1. uint128 from base/int128.h is sufficiently complicated that the compiler + // cannot transform the multiplication by kPrime into a shift-multiply-add; + // it has go through all of the instructions for a 128-bit multiply. + // 2. Because there are so fewer instructions (around 13), the hot loop fits + // nicely in the instruction queue of many Intel CPUs. + // kPrime = 309485009821345068724781371 + static const __uint128_t kPrime = + (static_cast<__uint128_t>(16777216) << 64) + 315; + __uint128_t xhash = (static_cast<__uint128_t>(Uint128High64(uhash)) << 64) + + Uint128Low64(uhash); + const uint8_t* octets = reinterpret_cast<const uint8_t*>(data); + for (size_t i = 0; i < len; ++i) { + xhash = (xhash ^ octets[i]) * kPrime; + } + return uint128(static_cast<uint64_t>(xhash >> 64), + static_cast<uint64_t>(xhash & UINT64_C(0xFFFFFFFFFFFFFFFF))); +} +#endif + +uint128 IncrementalHashSlow(uint128 hash, const char* data, size_t len) { + // kPrime = 309485009821345068724781371 + static const uint128 kPrime(16777216, 315); + const uint8_t* octets = reinterpret_cast<const uint8_t*>(data); + for (size_t i = 0; i < len; ++i) { + hash = hash ^ uint128(0, octets[i]); + hash = hash * kPrime; + } + return hash; +} + +uint128 IncrementalHash(uint128 hash, const char* data, size_t len) { +#ifdef QUIC_UTIL_HAS_UINT128 + return FLAGS_quic_utils_use_fast_incremental_hash + ? IncrementalHashFast(hash, data, len) + : IncrementalHashSlow(hash, data, len); +#else + return IncrementalHashSlow(hash, data, len); +#endif +} + +} // namespace // static uint64_t QuicUtils::FNV1a_64_Hash(const char* data, int len) { @@ -51,7 +107,7 @@ int len2) { // The two constants are defined as part of the hash algorithm. // see http://www.isthe.com/chongo/tech/comp/fnv/ - // 144066263297769815596495629667062367629 + // kOffset = 144066263297769815596495629667062367629 const uint128 kOffset(UINT64_C(7809847782465536322), UINT64_C(7113472399480571277)); @@ -63,18 +119,6 @@ } // static -uint128 QuicUtils::IncrementalHash(uint128 hash, const char* data, size_t len) { - // 309485009821345068724781371 - const uint128 kPrime(16777216, 315); - const uint8_t* octets = reinterpret_cast<const uint8_t*>(data); - for (size_t i = 0; i < len; ++i) { - hash = hash ^ uint128(0, octets[i]); - hash = hash * kPrime; - } - return hash; -} - -// static bool QuicUtils::FindMutualTag(const QuicTagVector& our_tags_vector, const QuicTag* their_tags, size_t num_their_tags,
diff --git a/net/quic/quic_utils.h b/net/quic/quic_utils.h index d1c0e109..35b675c 100644 --- a/net/quic/quic_utils.h +++ b/net/quic/quic_utils.h
@@ -42,10 +42,6 @@ const char* data2, int len2); - // returns the 128 bit FNV1a hash of the |data|, starting with the - // previous hash. - static uint128 IncrementalHash(uint128 hash, const char* data, size_t len); - // FindMutualTag sets |out_result| to the first tag in the priority list that // is also in the other list and returns true. If there is no intersection it // returns false.
diff --git a/net/quic/quic_utils_test.cc b/net/quic/quic_utils_test.cc index 4108bd7..2c4aacb3 100644 --- a/net/quic/quic_utils_test.cc +++ b/net/quic/quic_utils_test.cc
@@ -5,6 +5,7 @@ #include "net/quic/quic_utils.h" #include "net/quic/crypto/crypto_protocol.h" +#include "net/quic/quic_flags.h" #include "testing/gtest/include/gtest/gtest.h" using base::StringPiece; @@ -99,6 +100,44 @@ EXPECT_EQ(expected_options, parsed_options); } +uint128 IncrementalHashReference(const void* data, size_t len) { + // The two constants are defined as part of the hash algorithm. + // see http://www.isthe.com/chongo/tech/comp/fnv/ + // hash = 144066263297769815596495629667062367629 + uint128 hash = + uint128(UINT64_C(7809847782465536322), UINT64_C(7113472399480571277)); + // kPrime = 309485009821345068724781371 + const uint128 kPrime(16777216, 315); + const uint8_t* octets = reinterpret_cast<const uint8_t*>(data); + for (size_t i = 0; i < len; ++i) { + hash = hash ^ uint128(0, octets[i]); + hash = hash * kPrime; + } + return hash; +} + +TEST(QuicUtilsHashTest, ReferenceTestSlow) { + FLAGS_quic_utils_use_fast_incremental_hash = false; + std::vector<uint8_t> data(32); + for (size_t i = 0; i < data.size(); ++i) { + data[i] = i % 255; + } + EXPECT_EQ(IncrementalHashReference(data.data(), data.size()), + QuicUtils::FNV1a_128_Hash( + reinterpret_cast<const char*>(data.data()), data.size())); +} + +TEST(QuicUtilsHashTest, ReferenceTestFast) { + FLAGS_quic_utils_use_fast_incremental_hash = true; + std::vector<uint8_t> data(32); + for (size_t i = 0; i < data.size(); ++i) { + data[i] = i % 255; + } + EXPECT_EQ(IncrementalHashReference(data.data(), data.size()), + QuicUtils::FNV1a_128_Hash( + reinterpret_cast<const char*>(data.data()), data.size())); +} + } // namespace } // namespace test } // namespace net
diff --git a/net/quic/reliable_quic_stream.cc b/net/quic/reliable_quic_stream.cc index f42687ad..f590074 100644 --- a/net/quic/reliable_quic_stream.cc +++ b/net/quic/reliable_quic_stream.cc
@@ -176,10 +176,6 @@ rst_sent_ = true; } -void ReliableQuicStream::CloseConnection(QuicErrorCode error) { - session()->connection()->SendConnectionClose(error); -} - void ReliableQuicStream::CloseConnectionWithDetails(QuicErrorCode error, const string& details) { session()->connection()->SendConnectionCloseWithDetails(error, details);
diff --git a/net/quic/reliable_quic_stream.h b/net/quic/reliable_quic_stream.h index dfb86b3..22dce10 100644 --- a/net/quic/reliable_quic_stream.h +++ b/net/quic/reliable_quic_stream.h
@@ -92,7 +92,6 @@ // Called by the subclass or the sequencer to close the entire connection from // this end. - virtual void CloseConnection(QuicErrorCode error); virtual void CloseConnectionWithDetails(QuicErrorCode error, const std::string& details);
diff --git a/net/quic/test_tools/mock_crypto_client_stream.cc b/net/quic/test_tools/mock_crypto_client_stream.cc index 0b0b1d85..b0db4dd 100644 --- a/net/quic/test_tools/mock_crypto_client_stream.cc +++ b/net/quic/test_tools/mock_crypto_client_stream.cc
@@ -29,7 +29,8 @@ void MockCryptoClientStream::OnHandshakeMessage( const CryptoHandshakeMessage& message) { - CloseConnection(QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE); + CloseConnectionWithDetails(QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE, + "Forced mock failure"); } void MockCryptoClientStream::CryptoConnect() { @@ -37,6 +38,11 @@ case ZERO_RTT: { encryption_established_ = true; handshake_confirmed_ = false; + crypto_negotiated_params_.key_exchange = kC255; + crypto_negotiated_params_.aead = kAESG; + if (proof_verify_details_) { + client_session()->OnProofVerifyDetailsAvailable(*proof_verify_details_); + } session()->connection()->SetDecrypter(ENCRYPTION_INITIAL, QuicDecrypter::Create(kNULL)); session()->connection()->SetEncrypter(ENCRYPTION_INITIAL,
diff --git a/net/quic/test_tools/mock_crypto_client_stream_factory.cc b/net/quic/test_tools/mock_crypto_client_stream_factory.cc index 77ddbd7..1773059 100644 --- a/net/quic/test_tools/mock_crypto_client_stream_factory.cc +++ b/net/quic/test_tools/mock_crypto_client_stream_factory.cc
@@ -23,6 +23,7 @@ MockCryptoClientStreamFactory::CreateQuicCryptoClientStream( const QuicServerId& server_id, QuicChromiumClientSession* session, + scoped_ptr<ProofVerifyContext> /*proof_verify_context*/, QuicCryptoClientConfig* crypto_config) { const ProofVerifyDetails* proof_verify_details = nullptr; if (!proof_verify_details_queue_.empty()) {
diff --git a/net/quic/test_tools/mock_crypto_client_stream_factory.h b/net/quic/test_tools/mock_crypto_client_stream_factory.h index 11beaa6f..5ca04bf 100644 --- a/net/quic/test_tools/mock_crypto_client_stream_factory.h +++ b/net/quic/test_tools/mock_crypto_client_stream_factory.h
@@ -25,6 +25,7 @@ QuicCryptoClientStream* CreateQuicCryptoClientStream( const QuicServerId& server_id, QuicChromiumClientSession* session, + scoped_ptr<ProofVerifyContext> proof_verify_context, QuicCryptoClientConfig* crypto_config) override; void set_handshake_mode(
diff --git a/net/quic/test_tools/quic_framer_peer.cc b/net/quic/test_tools/quic_framer_peer.cc index 10eac7a..dd99736 100644 --- a/net/quic/test_tools/quic_framer_peer.cc +++ b/net/quic/test_tools/quic_framer_peer.cc
@@ -14,9 +14,10 @@ QuicPacketNumber QuicFramerPeer::CalculatePacketNumberFromWire( QuicFramer* framer, QuicPacketNumberLength packet_number_length, + QuicPacketNumber last_packet_number, QuicPacketNumber packet_number) { - return framer->CalculatePacketNumberFromWire(packet_number_length, - packet_number); + return framer->CalculatePacketNumberFromWire( + packet_number_length, last_packet_number, packet_number); } // static @@ -64,5 +65,15 @@ return framer->encrypter_[level].get(); } +// static +QuicPacketNumber QuicFramerPeer::GetLastPacketNumber(QuicFramer* framer) { + return framer->last_packet_number_; +} + +// static +QuicPathId QuicFramerPeer::GetLastPathId(QuicFramer* framer) { + return framer->last_path_id_; +} + } // namespace test } // namespace net
diff --git a/net/quic/test_tools/quic_framer_peer.h b/net/quic/test_tools/quic_framer_peer.h index 2dd5774..a31ab26 100644 --- a/net/quic/test_tools/quic_framer_peer.h +++ b/net/quic/test_tools/quic_framer_peer.h
@@ -19,6 +19,7 @@ static QuicPacketNumber CalculatePacketNumberFromWire( QuicFramer* framer, QuicPacketNumberLength packet_number_length, + QuicPacketNumber last_packet_number, QuicPacketNumber packet_number); static void SetLastSerializedConnectionId(QuicFramer* framer, QuicConnectionId connection_id); @@ -32,6 +33,10 @@ static QuicEncrypter* GetEncrypter(QuicFramer* framer, EncryptionLevel level); + static QuicPacketNumber GetLastPacketNumber(QuicFramer* framer); + + static QuicPathId GetLastPathId(QuicFramer* framer); + private: DISALLOW_COPY_AND_ASSIGN(QuicFramerPeer); };
diff --git a/net/quic/test_tools/quic_test_utils.cc b/net/quic/test_tools/quic_test_utils.cc index 033ea75..ada8262 100644 --- a/net/quic/test_tools/quic_test_utils.cc +++ b/net/quic/test_tools/quic_test_utils.cc
@@ -333,15 +333,21 @@ QuicConnection* connection, const QuicConfig& config, const QuicCryptoServerConfig* crypto_config) - : QuicServerSession(config, connection, &visitor_, crypto_config) { + : QuicServerSessionBase(config, connection, &visitor_, crypto_config) { Initialize(); } TestQuicSpdyServerSession::~TestQuicSpdyServerSession() {} +QuicCryptoServerStreamBase* +TestQuicSpdyServerSession::CreateQuicCryptoServerStream( + const QuicCryptoServerConfig* crypto_config) { + return new QuicCryptoServerStream(crypto_config, this); +} + QuicCryptoServerStream* TestQuicSpdyServerSession::GetCryptoStream() { return static_cast<QuicCryptoServerStream*>( - QuicServerSession::GetCryptoStream()); + QuicServerSessionBase::GetCryptoStream()); } TestQuicSpdyClientSession::TestQuicSpdyClientSession(
diff --git a/net/quic/test_tools/quic_test_utils.h b/net/quic/test_tools/quic_test_utils.h index 44cfa2e3..6868410 100644 --- a/net/quic/test_tools/quic_test_utils.h +++ b/net/quic/test_tools/quic_test_utils.h
@@ -29,7 +29,7 @@ #include "net/spdy/spdy_framer.h" #include "net/tools/quic/quic_dispatcher.h" #include "net/tools/quic/quic_per_connection_packet_writer.h" -#include "net/tools/quic/quic_server_session.h" +#include "net/tools/quic/quic_server_session_base.h" #include "net/tools/quic/test_tools/mock_quic_server_session_visitor.h" #include "testing/gmock/include/gmock/gmock.h" @@ -481,7 +481,7 @@ DISALLOW_COPY_AND_ASSIGN(MockQuicSpdySession); }; -class TestQuicSpdyServerSession : public tools::QuicServerSession { +class TestQuicSpdyServerSession : public tools::QuicServerSessionBase { public: TestQuicSpdyServerSession(QuicConnection* connection, const QuicConfig& config, @@ -491,6 +491,8 @@ MOCK_METHOD1(CreateIncomingDynamicStream, QuicSpdyStream*(QuicStreamId id)); MOCK_METHOD1(CreateOutgoingDynamicStream, QuicSpdyStream*(SpdyPriority priority)); + QuicCryptoServerStreamBase* CreateQuicCryptoServerStream( + const QuicCryptoServerConfig* crypto_config) override; QuicCryptoServerStream* GetCryptoStream() override;
diff --git a/net/sdch/sdch_owner.cc b/net/sdch/sdch_owner.cc index 30b9476..45c4946 100644 --- a/net/sdch/sdch_owner.cc +++ b/net/sdch/sdch_owner.cc
@@ -55,11 +55,12 @@ // use of it must be namespace restricted. // Schema: // pref_store_->GetValue(kPreferenceName) -> Dictionary { -// 'version' -> 1 [int] +// 'version' -> 2 [int] // 'dictionaries' -> Dictionary { // server_hash -> { // 'url' -> URL [string] // 'last_used' -> seconds since unix epoch [double] +// 'created_time' -> seconds since unix epoch [double] // 'use_count' -> use count [int] // 'size' -> size [int] // } @@ -69,10 +70,11 @@ const char kDictionariesKey[] = "dictionaries"; const char kDictionaryUrlKey[] = "url"; const char kDictionaryLastUsedKey[] = "last_used"; +const char kDictionaryCreatedTimeKey[] = "created_time"; const char kDictionaryUseCountKey[] = "use_count"; const char kDictionarySizeKey[] = "size"; -const int kVersion = 1; +const int kVersion = 2; // This function returns store[kPreferenceName/kDictionariesKey]. The caller // is responsible for making sure any needed calls to @@ -128,15 +130,21 @@ const std::string& server_hash() const { return server_hash_; } const GURL& url() const { return url_; } base::Time last_used() const { return last_used_; } + base::Time created_time() const { return created_time_; } int use_count() const { return use_count_; } int size() const { return size_; } private: - void LoadDictionaryOrDie(); + // Load Dictionary silently skipping any that are malformed. + void LoadNextDictionary(); + // Try to load Dictionary from current iterator's position. Returns true if + // succeeded. + bool TryLoadDictionary(); std::string server_hash_; GURL url_; base::Time last_used_; + base::Time created_time_; int use_count_; int size_; @@ -145,9 +153,10 @@ DictionaryPreferenceIterator::DictionaryPreferenceIterator( WriteablePrefStore* pref_store) - : dictionary_iterator_(*GetPersistentStoreDictionaryMap(pref_store)) { - if (!IsAtEnd()) - LoadDictionaryOrDie(); + : use_count_(0), + size_(0), + dictionary_iterator_(*GetPersistentStoreDictionaryMap(pref_store)) { + LoadNextDictionary(); } bool DictionaryPreferenceIterator::IsAtEnd() const { @@ -156,34 +165,54 @@ void DictionaryPreferenceIterator::Advance() { dictionary_iterator_.Advance(); - if (!IsAtEnd()) - LoadDictionaryOrDie(); + LoadNextDictionary(); } -void DictionaryPreferenceIterator::LoadDictionaryOrDie() { - double last_used_seconds_from_epoch; +void DictionaryPreferenceIterator::LoadNextDictionary() { + while (!IsAtEnd()) { + if (TryLoadDictionary()) + return; + dictionary_iterator_.Advance(); + } +} + +bool DictionaryPreferenceIterator::TryLoadDictionary() { const base::DictionaryValue* dict = nullptr; - bool success = - dictionary_iterator_.value().GetAsDictionary(&dict); - DCHECK(success); + + bool success = dictionary_iterator_.value().GetAsDictionary(&dict); + if (!success) + return false; server_hash_ = dictionary_iterator_.key(); std::string url_spec; success = dict->GetString(kDictionaryUrlKey, &url_spec); - DCHECK(success); + if (!success) + return false; url_ = GURL(url_spec); - success = dict->GetDouble(kDictionaryLastUsedKey, - &last_used_seconds_from_epoch); - DCHECK(success); + double last_used_seconds_from_epoch = 0; + success = + dict->GetDouble(kDictionaryLastUsedKey, &last_used_seconds_from_epoch); + if (!success) + return false; last_used_ = base::Time::FromDoubleT(last_used_seconds_from_epoch); success = dict->GetInteger(kDictionaryUseCountKey, &use_count_); - DCHECK(success); + if (!success) + return false; success = dict->GetInteger(kDictionarySizeKey, &size_); - DCHECK(success); + if (!success) + return false; + + double created_time_seconds = 0; + success = dict->GetDouble(kDictionaryCreatedTimeKey, &created_time_seconds); + if (!success) + return false; + created_time_ = base::Time::FromDoubleT(created_time_seconds); + + return true; } // Triggers a ReportValueChanged() on the specified WriteablePrefStore @@ -314,6 +343,7 @@ } void SdchOwner::OnDictionaryFetched(base::Time last_used, + base::Time created_time, int use_count, const std::string& dictionary_text, const GURL& dictionary_url, @@ -443,6 +473,8 @@ dictionary_description->SetString(kDictionaryUrlKey, dictionary_url.spec()); dictionary_description->SetDouble(kDictionaryLastUsedKey, last_used.ToDoubleT()); + dictionary_description->SetDouble(kDictionaryCreatedTimeKey, + created_time.ToDoubleT()); dictionary_description->SetInteger(kDictionaryUseCountKey, use_count); dictionary_description->SetInteger(kDictionarySizeKey, dictionary_text.size()); @@ -495,6 +527,16 @@ UMA_HISTOGRAM_CUSTOM_TIMES("Sdch3.UsageInterval2", time_since_last_used, base::TimeDelta(), base::TimeDelta::FromDays(7), 50); + } else { + double created_time = 0; + success = specific_dictionary_map->GetDouble(kDictionaryCreatedTimeKey, + &created_time); + DCHECK(success); + base::TimeDelta time_since_created(now - + base::Time::FromDoubleT(created_time)); + UMA_HISTOGRAM_CUSTOM_TIMES("Sdch3.FirstUseInterval", time_since_created, + base::TimeDelta(), base::TimeDelta::FromDays(7), + 50); } specific_dictionary_map->SetDouble(kDictionaryLastUsedKey, now.ToDoubleT()); @@ -525,10 +567,11 @@ return; } - fetcher_->Schedule(dictionary_url, - base::Bind(&SdchOwner::OnDictionaryFetched, - // SdchOwner will outlive its member variables. - base::Unretained(this), base::Time(), 0)); + fetcher_->Schedule( + dictionary_url, + base::Bind(&SdchOwner::OnDictionaryFetched, + // SdchOwner will outlive its member variables. + base::Unretained(this), base::Time(), base::Time::Now(), 0)); } void SdchOwner::OnClearDictionaries() { @@ -696,20 +739,24 @@ continue; GURL dict_url(url_string); - double last_used; + double last_used = 0; if (!dict_info->GetDouble(kDictionaryLastUsedKey, &last_used)) continue; - int use_count; + int use_count = 0; if (!dict_info->GetInteger(kDictionaryUseCountKey, &use_count)) continue; + double created_time = 0; + if (!dict_info->GetDouble(kDictionaryCreatedTimeKey, &created_time)) + continue; + fetcher_->ScheduleReload( - dict_url, base::Bind(&SdchOwner::OnDictionaryFetched, - // SdchOwner will outlive its member variables. - base::Unretained(this), - base::Time::FromDoubleT(last_used), - use_count)); + dict_url, + base::Bind(&SdchOwner::OnDictionaryFetched, + // SdchOwner will outlive its member variables. + base::Unretained(this), base::Time::FromDoubleT(last_used), + base::Time::FromDoubleT(created_time), use_count)); } return true;
diff --git a/net/sdch/sdch_owner.h b/net/sdch/sdch_owner.h index 86f3b0f2..3c965d9 100644 --- a/net/sdch/sdch_owner.h +++ b/net/sdch/sdch_owner.h
@@ -76,6 +76,7 @@ // gotten the dictionary. The first two arguments are bound locally. // Public for testing. void OnDictionaryFetched(base::Time last_used, + base::Time created_time, int use_count, const std::string& dictionary_text, const GURL& dictionary_url,
diff --git a/net/sdch/sdch_owner_unittest.cc b/net/sdch/sdch_owner_unittest.cc index b575084e..9ce9579 100644 --- a/net/sdch/sdch_owner_unittest.cc +++ b/net/sdch/sdch_owner_unittest.cc
@@ -315,8 +315,9 @@ // SdchOwner::OnDictionaryFetched(), and return whether that // addition was successful or not. bool CreateAndAddDictionary(size_t size, - std::string* server_hash_p, - base::Time last_used_time) { + base::Time last_used_time, + base::Time created_time, + std::string* server_hash_p) { GURL dictionary_url( base::StringPrintf("%s/d%d", generic_url, dictionary_creation_index_)); std::string dictionary_text(NewSdchDictionary(size - 4)); @@ -328,13 +329,21 @@ if (DictionaryPresentInManager(server_hash)) return false; - sdch_owner().OnDictionaryFetched(last_used_time, 0, dictionary_text, - dictionary_url, net_log_, false); + sdch_owner().OnDictionaryFetched(last_used_time, created_time, 0, + dictionary_text, dictionary_url, net_log_, + false); if (server_hash_p) *server_hash_p = server_hash; return DictionaryPresentInManager(server_hash); } + bool CreateAndAddDictionary(size_t size, + base::Time last_used_time, + std::string* server_hash_p) { + return CreateAndAddDictionary(size, last_used_time, base::Time(), + server_hash_p); + } + void ResetOwner() { sdch_owner_.reset(new SdchOwner(&sdch_manager_, &url_request_context_)); } @@ -370,8 +379,9 @@ // Fetch generated when half full. GURL dict_url2(std::string(generic_url) + "/d2"); std::string dictionary1(NewSdchDictionary(kMaxSizeForTesting / 2)); - sdch_owner().OnDictionaryFetched(base::Time::Now(), 1, dictionary1, - dict_url1, bound_net_log(), false); + sdch_owner().OnDictionaryFetched(base::Time::Now(), base::Time::Now(), 1, + dictionary1, dict_url1, bound_net_log(), + false); EXPECT_EQ(0, JobsRecentlyCreated()); SignalGetDictionaryAndClearJobs(request_url, dict_url2); EXPECT_EQ(1, JobsRecentlyCreated()); @@ -380,8 +390,9 @@ GURL dict_url3(std::string(generic_url) + "/d3"); std::string dictionary2(NewSdchDictionary( (kMaxSizeForTesting / 2 - kMinFetchSpaceForTesting / 2))); - sdch_owner().OnDictionaryFetched(base::Time::Now(), 1, dictionary2, - dict_url2, bound_net_log(), false); + sdch_owner().OnDictionaryFetched(base::Time::Now(), base::Time::Now(), 1, + dictionary2, dict_url2, bound_net_log(), + false); EXPECT_EQ(0, JobsRecentlyCreated()); SignalGetDictionaryAndClearJobs(request_url, dict_url3); EXPECT_EQ(0, JobsRecentlyCreated()); @@ -398,18 +409,18 @@ base::TimeDelta::FromMinutes(30)); // Add successful when empty. - EXPECT_TRUE(CreateAndAddDictionary(kMaxSizeForTesting / 2, nullptr, - dictionary_last_used_time)); + EXPECT_TRUE(CreateAndAddDictionary(kMaxSizeForTesting / 2, + dictionary_last_used_time, nullptr)); EXPECT_EQ(0, JobsRecentlyCreated()); // Add successful when half full. - EXPECT_TRUE(CreateAndAddDictionary(kMaxSizeForTesting / 2, nullptr, - dictionary_last_used_time)); + EXPECT_TRUE(CreateAndAddDictionary(kMaxSizeForTesting / 2, + dictionary_last_used_time, nullptr)); EXPECT_EQ(0, JobsRecentlyCreated()); // Add unsuccessful when full. - EXPECT_FALSE(CreateAndAddDictionary(kMaxSizeForTesting / 2, nullptr, - dictionary_last_used_time)); + EXPECT_FALSE(CreateAndAddDictionary(kMaxSizeForTesting / 2, + dictionary_last_used_time, nullptr)); EXPECT_EQ(0, JobsRecentlyCreated()); } @@ -429,9 +440,9 @@ base::Time stale(base::Time::Now() - base::TimeDelta::FromHours(25)); EXPECT_TRUE( - CreateAndAddDictionary(kMaxSizeForTesting / 2, &server_hash_d1, fresh)); + CreateAndAddDictionary(kMaxSizeForTesting / 2, fresh, &server_hash_d1)); EXPECT_TRUE( - CreateAndAddDictionary(kMaxSizeForTesting / 2, &server_hash_d2, stale)); + CreateAndAddDictionary(kMaxSizeForTesting / 2, stale, &server_hash_d2)); EXPECT_TRUE(DictionaryPresentInManager(server_hash_d1)); EXPECT_TRUE(DictionaryPresentInManager(server_hash_d2)); @@ -442,7 +453,7 @@ test_clock->Advance(synthetic_delta); EXPECT_TRUE( - CreateAndAddDictionary(kMaxSizeForTesting / 2, &server_hash_d3, fresh)); + CreateAndAddDictionary(kMaxSizeForTesting / 2, fresh, &server_hash_d3)); EXPECT_TRUE(DictionaryPresentInManager(server_hash_d1)); EXPECT_FALSE(DictionaryPresentInManager(server_hash_d2)); EXPECT_TRUE(DictionaryPresentInManager(server_hash_d3)); @@ -485,12 +496,12 @@ base::Time fresh(base::Time::Now() - base::TimeDelta::FromHours(23)); base::Time stale(base::Time::Now() - base::TimeDelta::FromHours(25)); EXPECT_TRUE( - CreateAndAddDictionary(kMaxSizeForTesting / 2, &server_hash_d1, fresh)); + CreateAndAddDictionary(kMaxSizeForTesting / 2, fresh, &server_hash_d1)); EXPECT_TRUE( - CreateAndAddDictionary(kMaxSizeForTesting / 4, &server_hash_d2, stale)); + CreateAndAddDictionary(kMaxSizeForTesting / 4, stale, &server_hash_d2)); EXPECT_TRUE( - CreateAndAddDictionary(kMaxSizeForTesting / 4, &server_hash_d3, stale)); + CreateAndAddDictionary(kMaxSizeForTesting / 4, stale, &server_hash_d3)); EXPECT_TRUE(DictionaryPresentInManager(server_hash_d1)); EXPECT_TRUE(DictionaryPresentInManager(server_hash_d2)); @@ -498,7 +509,7 @@ std::string server_hash_d4; EXPECT_TRUE( - CreateAndAddDictionary(kMaxSizeForTesting / 2, &server_hash_d4, fresh)); + CreateAndAddDictionary(kMaxSizeForTesting / 2, fresh, &server_hash_d4)); EXPECT_TRUE(DictionaryPresentInManager(server_hash_d1)); EXPECT_FALSE(DictionaryPresentInManager(server_hash_d2)); EXPECT_FALSE(DictionaryPresentInManager(server_hash_d3)); @@ -518,13 +529,13 @@ base::Time stale_older(base::Time::Now() - base::TimeDelta::FromHours(71)); EXPECT_TRUE( - CreateAndAddDictionary(kMaxSizeForTesting / 4, &server_hash_d1, fresh)); + CreateAndAddDictionary(kMaxSizeForTesting / 4, fresh, &server_hash_d1)); - EXPECT_TRUE(CreateAndAddDictionary(kMaxSizeForTesting / 4, &server_hash_d2, - stale_newer)); + EXPECT_TRUE(CreateAndAddDictionary(kMaxSizeForTesting / 4, stale_newer, + &server_hash_d2)); - EXPECT_TRUE(CreateAndAddDictionary(kMaxSizeForTesting / 4, &server_hash_d3, - stale_older)); + EXPECT_TRUE(CreateAndAddDictionary(kMaxSizeForTesting / 4, stale_older, + &server_hash_d3)); EXPECT_TRUE(DictionaryPresentInManager(server_hash_d1)); EXPECT_TRUE(DictionaryPresentInManager(server_hash_d2)); @@ -535,7 +546,7 @@ std::string server_hash_d4; EXPECT_TRUE( - CreateAndAddDictionary(kMaxSizeForTesting / 2, &server_hash_d4, fresh)); + CreateAndAddDictionary(kMaxSizeForTesting / 2, fresh, &server_hash_d4)); EXPECT_TRUE(DictionaryPresentInManager(server_hash_d1)); EXPECT_TRUE(DictionaryPresentInManager(server_hash_d2)); EXPECT_FALSE(DictionaryPresentInManager(server_hash_d3)); @@ -555,13 +566,13 @@ base::Time stale_older(base::Time::Now() - base::TimeDelta::FromHours(71)); EXPECT_TRUE( - CreateAndAddDictionary(kMaxSizeForTesting / 4, &server_hash_d1, fresh)); + CreateAndAddDictionary(kMaxSizeForTesting / 4, fresh, &server_hash_d1)); - EXPECT_TRUE(CreateAndAddDictionary(kMaxSizeForTesting / 4, &server_hash_d2, - stale_newer)); + EXPECT_TRUE(CreateAndAddDictionary(kMaxSizeForTesting / 4, stale_newer, + &server_hash_d2)); - EXPECT_TRUE(CreateAndAddDictionary(kMaxSizeForTesting / 4, &server_hash_d3, - stale_older)); + EXPECT_TRUE(CreateAndAddDictionary(kMaxSizeForTesting / 4, stale_older, + &server_hash_d3)); EXPECT_TRUE(DictionaryPresentInManager(server_hash_d1)); EXPECT_TRUE(DictionaryPresentInManager(server_hash_d2)); @@ -574,7 +585,7 @@ // newer stale one. std::string server_hash_d4; EXPECT_TRUE( - CreateAndAddDictionary(kMaxSizeForTesting / 2, &server_hash_d4, fresh)); + CreateAndAddDictionary(kMaxSizeForTesting / 2, fresh, &server_hash_d4)); EXPECT_TRUE(DictionaryPresentInManager(server_hash_d1)); EXPECT_FALSE(DictionaryPresentInManager(server_hash_d2)); EXPECT_TRUE(DictionaryPresentInManager(server_hash_d3)); @@ -594,13 +605,13 @@ base::Time stale_older(base::Time::Now() - base::TimeDelta::FromHours(71)); EXPECT_TRUE( - CreateAndAddDictionary(kMaxSizeForTesting / 4, &server_hash_d1, fresh)); + CreateAndAddDictionary(kMaxSizeForTesting / 4, fresh, &server_hash_d1)); - EXPECT_TRUE(CreateAndAddDictionary(kMaxSizeForTesting / 4, &server_hash_d2, - stale_newer)); + EXPECT_TRUE(CreateAndAddDictionary(kMaxSizeForTesting / 4, stale_newer, + &server_hash_d2)); - EXPECT_TRUE(CreateAndAddDictionary(kMaxSizeForTesting / 4, &server_hash_d3, - stale_older)); + EXPECT_TRUE(CreateAndAddDictionary(kMaxSizeForTesting / 4, stale_older, + &server_hash_d3)); EXPECT_TRUE(DictionaryPresentInManager(server_hash_d1)); EXPECT_TRUE(DictionaryPresentInManager(server_hash_d2)); @@ -613,7 +624,7 @@ // The addition of a new dictionary should fail, not evicting anything. std::string server_hash_d4; EXPECT_FALSE( - CreateAndAddDictionary(kMaxSizeForTesting / 2, &server_hash_d4, fresh)); + CreateAndAddDictionary(kMaxSizeForTesting / 2, fresh, &server_hash_d4)); EXPECT_TRUE(DictionaryPresentInManager(server_hash_d1)); EXPECT_TRUE(DictionaryPresentInManager(server_hash_d2)); EXPECT_TRUE(DictionaryPresentInManager(server_hash_d3)); @@ -626,11 +637,11 @@ std::string server_hash_d2; // Take up all the space. - EXPECT_TRUE(CreateAndAddDictionary(kMaxSizeForTesting, &server_hash_d1, - base::Time::Now())); + EXPECT_TRUE(CreateAndAddDictionary(kMaxSizeForTesting, base::Time::Now(), + &server_hash_d1)); // Addition should fail. - EXPECT_FALSE(CreateAndAddDictionary(kMaxSizeForTesting, &server_hash_d2, - base::Time::Now())); + EXPECT_FALSE(CreateAndAddDictionary(kMaxSizeForTesting, base::Time::Now(), + &server_hash_d2)); EXPECT_TRUE(DictionaryPresentInManager(server_hash_d1)); EXPECT_FALSE(DictionaryPresentInManager(server_hash_d2)); sdch_manager().ClearData(); @@ -639,7 +650,7 @@ // Addition should now succeed. EXPECT_TRUE( - CreateAndAddDictionary(kMaxSizeForTesting, nullptr, base::Time::Now())); + CreateAndAddDictionary(kMaxSizeForTesting, base::Time::Now(), nullptr)); } // Confirm memory pressure gets all the space back. @@ -648,12 +659,12 @@ std::string server_hash_d2; // Take up all the space. - EXPECT_TRUE(CreateAndAddDictionary(kMaxSizeForTesting, &server_hash_d1, - base::Time::Now())); + EXPECT_TRUE(CreateAndAddDictionary(kMaxSizeForTesting, base::Time::Now(), + &server_hash_d1)); // Addition should fail. - EXPECT_FALSE(CreateAndAddDictionary(kMaxSizeForTesting, &server_hash_d2, - base::Time::Now())); + EXPECT_FALSE(CreateAndAddDictionary(kMaxSizeForTesting, base::Time::Now(), + &server_hash_d2)); EXPECT_TRUE(DictionaryPresentInManager(server_hash_d1)); EXPECT_FALSE(DictionaryPresentInManager(server_hash_d2)); @@ -670,7 +681,7 @@ // Addition should now succeed. EXPECT_TRUE( - CreateAndAddDictionary(kMaxSizeForTesting, nullptr, base::Time::Now())); + CreateAndAddDictionary(kMaxSizeForTesting, base::Time::Now(), nullptr)); } // Confirm that use of a pinned dictionary after its removal works properly. @@ -679,8 +690,8 @@ sdch_owner().EnablePersistentStorage(&pref_store()); std::string server_hash_d1; - EXPECT_TRUE(CreateAndAddDictionary(kMaxSizeForTesting / 2, &server_hash_d1, - base::Time::Now())); + EXPECT_TRUE(CreateAndAddDictionary(kMaxSizeForTesting / 2, base::Time::Now(), + &server_hash_d1)); scoped_ptr<SdchManager::DictionarySet> return_set( sdch_manager().GetDictionarySet( @@ -715,6 +726,27 @@ EXPECT_FALSE(dict_result->Get("dictionaries." + server_hash_d1, &result)); } +TEST_F(SdchOwnerTest, UsageIntervalMetrics) { + const GURL url("http://www.example.com/dict0"); + + std::string server_hash; + base::Time last_used_time(base::Time::Now() - base::TimeDelta::FromHours(23)); + base::Time created_time(base::Time::Now() - base::TimeDelta::FromHours(47)); + + EXPECT_TRUE(CreateAndAddDictionary(kMaxSizeForTesting / 3, last_used_time, + created_time, &server_hash)); + + base::HistogramTester tester; + + sdch_owner().OnDictionaryUsed(server_hash); + tester.ExpectTotalCount("Sdch3.FirstUseInterval", 1); + tester.ExpectTotalCount("Sdch3.UsageInterval2", 0); + + sdch_owner().OnDictionaryUsed(server_hash); + tester.ExpectTotalCount("Sdch3.FirstUseInterval", 1); // count didn't change + tester.ExpectTotalCount("Sdch3.UsageInterval2", 1); +} + class SdchOwnerPersistenceTest : public ::testing::Test { public: SdchOwnerPersistenceTest() : pref_store_(new TestingPrefStore()) { @@ -743,9 +775,9 @@ } void InsertDictionaryForURL(const GURL& url, const std::string& nonce) { - owner_->OnDictionaryFetched(base::Time::Now(), 1, - CreateDictionary(url, nonce), - url, net_log_, false); + owner_->OnDictionaryFetched(base::Time::Now(), base::Time::Now(), 1, + CreateDictionary(url, nonce), url, net_log_, + false); } bool CompleteLoadFromURL(const GURL& url, const std::string& nonce,
diff --git a/net/socket/socket_descriptor.cc b/net/socket/socket_descriptor.cc index 2744d66..0822d2d9 100644 --- a/net/socket/socket_descriptor.cc +++ b/net/socket/socket_descriptor.cc
@@ -17,19 +17,7 @@ namespace net { -PlatformSocketFactory* g_socket_factory = nullptr; - -PlatformSocketFactory::PlatformSocketFactory() { -} - -PlatformSocketFactory::~PlatformSocketFactory() { -} - -void PlatformSocketFactory::SetInstance(PlatformSocketFactory* factory) { - g_socket_factory = factory; -} - -SocketDescriptor CreateSocketDefault(int family, int type, int protocol) { +SocketDescriptor CreatePlatformSocket(int family, int type, int protocol) { #if defined(OS_WIN) EnsureWinsockInit(); SocketDescriptor result = ::WSASocket(family, type, protocol, nullptr, 0, @@ -47,13 +35,7 @@ #else // OS_WIN return ::socket(family, type, protocol); #endif // OS_WIN -} -SocketDescriptor CreatePlatformSocket(int family, int type, int protocol) { - if (g_socket_factory) - return g_socket_factory->CreateSocket(family, type, protocol); - else - return CreateSocketDefault(family, type, protocol); } } // namespace net
diff --git a/net/socket/socket_descriptor.h b/net/socket/socket_descriptor.h index b2a22234..e58e140 100644 --- a/net/socket/socket_descriptor.h +++ b/net/socket/socket_descriptor.h
@@ -22,23 +22,6 @@ const SocketDescriptor kInvalidSocket = INVALID_SOCKET; #endif -// Interface to create native socket. -// Usually such factories are used for testing purposes, which is not true in -// this case. This interface is used to substitute WSASocket/socket to make -// possible execution of some network code in sandbox. -class NET_EXPORT PlatformSocketFactory { - public: - PlatformSocketFactory(); - virtual ~PlatformSocketFactory(); - - // Replace WSASocket/socket with given factory. The factory will be used by - // CreatePlatformSocket. - static void SetInstance(PlatformSocketFactory* factory); - - // Creates socket. See WSASocket/socket documentation of parameters. - virtual SocketDescriptor CreateSocket(int family, int type, int protocol) = 0; -}; - // Creates socket. See WSASocket/socket documentation of parameters. SocketDescriptor NET_EXPORT CreatePlatformSocket(int family, int type,
diff --git a/net/socket/ssl_server_socket_nss.cc b/net/socket/ssl_server_socket_nss.cc index 8293bab..a676aa05 100644 --- a/net/socket/ssl_server_socket_nss.cc +++ b/net/socket/ssl_server_socket_nss.cc
@@ -105,13 +105,10 @@ transport_socket_(transport_socket.Pass()), ssl_config_(ssl_config), cert_(cert), + key_(key.Copy()), next_handshake_state_(STATE_NONE), completed_handshake_(false) { - // TODO(hclam): Need a better way to clone a key. - std::vector<uint8_t> key_bytes; - CHECK(key.ExportPrivateKey(&key_bytes)); - key_.reset(crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(key_bytes)); - CHECK(key_.get()); + CHECK(key_); } SSLServerSocketNSS::~SSLServerSocketNSS() { @@ -198,7 +195,7 @@ const CompletionCallback& callback) { DCHECK(user_read_callback_.is_null()); DCHECK(user_handshake_callback_.is_null()); - DCHECK(!user_read_buf_.get()); + DCHECK(!user_read_buf_); DCHECK(nss_bufs_); DCHECK(!callback.is_null()); @@ -221,7 +218,7 @@ int SSLServerSocketNSS::Write(IOBuffer* buf, int buf_len, const CompletionCallback& callback) { DCHECK(user_write_callback_.is_null()); - DCHECK(!user_write_buf_.get()); + DCHECK(!user_write_buf_); DCHECK(nss_bufs_); DCHECK(!callback.is_null()); @@ -523,7 +520,7 @@ if (!completed_handshake_) return; - if (user_write_buf_.get()) { + if (user_write_buf_) { int rv = DoWriteLoop(result); if (rv != ERR_IO_PENDING) DoWriteCallback(rv); @@ -542,7 +539,7 @@ // Network layer received some data, check if client requested to read // decrypted data. - if (!user_read_buf_.get() || !completed_handshake_) + if (!user_read_buf_ || !completed_handshake_) return; int rv = DoReadLoop(result); @@ -663,7 +660,7 @@ } int SSLServerSocketNSS::DoPayloadRead() { - DCHECK(user_read_buf_.get()); + DCHECK(user_read_buf_); DCHECK_GT(user_read_buf_len_, 0); int rv = PR_Read(nss_fd_, user_read_buf_->data(), user_read_buf_len_); if (rv >= 0) @@ -679,7 +676,7 @@ } int SSLServerSocketNSS::DoPayloadWrite() { - DCHECK(user_write_buf_.get()); + DCHECK(user_write_buf_); int rv = PR_Write(nss_fd_, user_write_buf_->data(), user_write_buf_len_); if (rv >= 0) return rv;
diff --git a/net/socket/ssl_server_socket_openssl.cc b/net/socket/ssl_server_socket_openssl.cc index abdab619..c3869cd 100644 --- a/net/socket/ssl_server_socket_openssl.cc +++ b/net/socket/ssl_server_socket_openssl.cc
@@ -52,13 +52,10 @@ transport_socket_(std::move(transport_socket)), ssl_config_(ssl_config), cert_(certificate), + key_(key.Copy()), next_handshake_state_(STATE_NONE), completed_handshake_(false) { - // TODO(byungchul): Need a better way to clone a key. - std::vector<uint8_t> key_bytes; - CHECK(key.ExportPrivateKey(&key_bytes)); - key_.reset(crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(key_bytes)); - CHECK(key_.get()); + CHECK(key_); } SSLServerSocketOpenSSL::~SSLServerSocketOpenSSL() { @@ -135,7 +132,7 @@ const CompletionCallback& callback) { DCHECK(user_read_callback_.is_null()); DCHECK(user_handshake_callback_.is_null()); - DCHECK(!user_read_buf_.get()); + DCHECK(!user_read_buf_); DCHECK(!callback.is_null()); user_read_buf_ = buf; @@ -158,7 +155,7 @@ int SSLServerSocketOpenSSL::Write(IOBuffer* buf, int buf_len, const CompletionCallback& callback) { DCHECK(user_write_callback_.is_null()); - DCHECK(!user_write_buf_.get()); + DCHECK(!user_write_buf_); DCHECK(!callback.is_null()); user_write_buf_ = buf; @@ -270,7 +267,7 @@ if (!completed_handshake_) return; - if (user_write_buf_.get()) { + if (user_write_buf_) { int rv = DoWriteLoop(result); if (rv != ERR_IO_PENDING) DoWriteCallback(rv); @@ -289,7 +286,7 @@ // Network layer received some data, check if client requested to read // decrypted data. - if (!user_read_buf_.get() || !completed_handshake_) + if (!user_read_buf_ || !completed_handshake_) return; int rv = DoReadLoop(result); @@ -314,7 +311,7 @@ if (transport_send_busy_) return ERR_IO_PENDING; - if (!send_buffer_.get()) { + if (!send_buffer_) { // Get a fresh send buffer out of the send BIO. size_t max_read = BIO_pending(transport_bio_); if (!max_read) @@ -363,7 +360,7 @@ (void)BIO_shutdown_wr(transport_bio_); send_buffer_ = NULL; } else { - DCHECK(send_buffer_.get()); + DCHECK(send_buffer_); send_buffer_->DidConsume(result); DCHECK_GE(send_buffer_->BytesRemaining(), 0); if (send_buffer_->BytesRemaining() <= 0) @@ -432,7 +429,7 @@ // the CHECK. http://crbug.com/335557. result = transport_write_error_; } else { - DCHECK(recv_buffer_.get()); + DCHECK(recv_buffer_); int ret = BIO_write(transport_bio_, recv_buffer_->data(), result); // A write into a memory BIO should always succeed. DCHECK_EQ(result, ret); @@ -461,7 +458,7 @@ } int SSLServerSocketOpenSSL::DoPayloadRead() { - DCHECK(user_read_buf_.get()); + DCHECK(user_read_buf_); DCHECK_GT(user_read_buf_len_, 0); crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE); int rv = SSL_read(ssl_, user_read_buf_->data(), user_read_buf_len_); @@ -480,7 +477,7 @@ } int SSLServerSocketOpenSSL::DoPayloadWrite() { - DCHECK(user_write_buf_.get()); + DCHECK(user_write_buf_); crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE); int rv = SSL_write(ssl_, user_write_buf_->data(), user_write_buf_len_); if (rv >= 0) @@ -653,7 +650,7 @@ reinterpret_cast<const unsigned char*>(der_string.data()); ScopedX509 x509(d2i_X509(NULL, &der_string_array, der_string.length())); - if (!x509.get()) + if (!x509) return ERR_UNEXPECTED; // On success, SSL_use_certificate acquires a reference to |x509|.
diff --git a/net/tools/quic/end_to_end_test.cc b/net/tools/quic/end_to_end_test.cc index eb593e19..6e40815 100644 --- a/net/tools/quic/end_to_end_test.cc +++ b/net/tools/quic/end_to_end_test.cc
@@ -2061,7 +2061,7 @@ QuicDispatcherPeer::session_map(dispatcher); QuicDispatcher::SessionMap::const_iterator it = map.begin(); EXPECT_TRUE(it != map.end()); - QuicServerSession* server_session = it->second; + QuicServerSessionBase* server_session = it->second; // The stream is not waiting for the arrival of the peer's final offset. EXPECT_EQ(
diff --git a/net/tools/quic/quic_dispatcher.cc b/net/tools/quic/quic_dispatcher.cc index bfdace606..04c8b38 100644 --- a/net/tools/quic/quic_dispatcher.cc +++ b/net/tools/quic/quic_dispatcher.cc
@@ -13,6 +13,7 @@ #include "net/quic/quic_flags.h" #include "net/quic/quic_utils.h" #include "net/tools/quic/quic_per_connection_packet_writer.h" +#include "net/tools/quic/quic_simple_server_session.h" #include "net/tools/quic/quic_time_wait_list_manager.h" namespace net { @@ -288,7 +289,7 @@ switch (fate) { case kFateProcess: { // Create a session and process the packet. - QuicServerSession* session = + QuicServerSessionBase* session = CreateQuicSession(connection_id, current_client_address_); DVLOG(1) << "Created new session for " << connection_id; session_map_.insert(std::make_pair(connection_id, session)); @@ -387,7 +388,7 @@ void QuicDispatcher::Shutdown() { while (!session_map_.empty()) { - QuicServerSession* session = session_map_.begin()->second; + QuicServerSessionBase* session = session_map_.begin()->second; session->connection()->SendConnectionCloseWithDetails( QUIC_PEER_GOING_AWAY, "Server shutdown imminent"); // Validate that the session removes itself from the session map on close. @@ -443,16 +444,16 @@ DVLOG(1) << "Connection " << connection_id << " removed from time wait list."; } -QuicServerSession* QuicDispatcher::CreateQuicSession( +QuicServerSessionBase* QuicDispatcher::CreateQuicSession( QuicConnectionId connection_id, const IPEndPoint& client_address) { - // The QuicServerSession takes ownership of |connection| below. + // The QuicServerSessionBase takes ownership of |connection| below. QuicConnection* connection = new QuicConnection( connection_id, client_address, helper_.get(), connection_writer_factory_, /* owns_writer= */ true, Perspective::IS_SERVER, supported_versions_); - QuicServerSession* session = - new QuicServerSession(config_, connection, this, crypto_config_); + QuicServerSessionBase* session = + new QuicSimpleServerSession(config_, connection, this, crypto_config_); session->Initialize(); return session; }
diff --git a/net/tools/quic/quic_dispatcher.h b/net/tools/quic/quic_dispatcher.h index a7e169d..24f8b4b 100644 --- a/net/tools/quic/quic_dispatcher.h +++ b/net/tools/quic/quic_dispatcher.h
@@ -18,14 +18,14 @@ #include "net/quic/quic_blocked_writer_interface.h" #include "net/quic/quic_connection.h" #include "net/quic/quic_protocol.h" -#include "net/tools/quic/quic_server_session.h" +#include "net/tools/quic/quic_server_session_base.h" #include "net/tools/quic/quic_time_wait_list_manager.h" namespace net { class QuicConfig; class QuicCryptoServerConfig; -class QuicServerSession; +class QuicServerSessionBase; namespace tools { @@ -117,7 +117,7 @@ void OnConnectionRemovedFromTimeWaitList( QuicConnectionId connection_id) override; - typedef base::hash_map<QuicConnectionId, QuicServerSession*> SessionMap; + typedef base::hash_map<QuicConnectionId, QuicServerSessionBase*> SessionMap; const SessionMap& session_map() const { return session_map_; } @@ -136,7 +136,7 @@ "relative to kInitialCongestionWindow."); protected: - virtual QuicServerSession* CreateQuicSession( + virtual QuicServerSessionBase* CreateQuicSession( QuicConnectionId connection_id, const IPEndPoint& client_address); @@ -238,7 +238,7 @@ scoped_ptr<QuicTimeWaitListManager> time_wait_list_manager_; // The list of closed but not-yet-deleted sessions. - std::vector<QuicServerSession*> closed_session_list_; + std::vector<QuicServerSessionBase*> closed_session_list_; // The helper used for all connections. scoped_ptr<QuicConnectionHelperInterface> helper_;
diff --git a/net/tools/quic/quic_dispatcher_test.cc b/net/tools/quic/quic_dispatcher_test.cc index e7f2181..e17526d 100644 --- a/net/tools/quic/quic_dispatcher_test.cc +++ b/net/tools/quic/quic_dispatcher_test.cc
@@ -48,13 +48,13 @@ namespace test { namespace { -class TestQuicSpdyServerSession : public QuicServerSession { +class TestQuicSpdyServerSession : public QuicServerSessionBase { public: TestQuicSpdyServerSession(const QuicConfig& config, QuicConnection* connection, const QuicCryptoServerConfig* crypto_config) - : QuicServerSession(config, connection, nullptr, crypto_config), - crypto_stream_(QuicServerSession::GetCryptoStream()) {} + : QuicServerSessionBase(config, connection, nullptr, crypto_config), + crypto_stream_(QuicServerSessionBase::GetCryptoStream()) {} ~TestQuicSpdyServerSession() override{}; MOCK_METHOD2(OnConnectionClosed, void(QuicErrorCode error, bool from_peer)); @@ -62,6 +62,11 @@ MOCK_METHOD1(CreateOutgoingDynamicStream, QuicSpdyStream*(SpdyPriority priority)); + QuicCryptoServerStreamBase* CreateQuicCryptoServerStream( + const QuicCryptoServerConfig* crypto_config) override { + return new QuicCryptoServerStream(crypto_config, this); + } + void SetCryptoStream(QuicCryptoServerStream* crypto_stream) { crypto_stream_ = crypto_stream; } @@ -88,8 +93,8 @@ new QuicEpollConnectionHelper(eps)) {} MOCK_METHOD2(CreateQuicSession, - QuicServerSession*(QuicConnectionId connection_id, - const IPEndPoint& client_address)); + QuicServerSessionBase*(QuicConnectionId connection_id, + const IPEndPoint& client_address)); using QuicDispatcher::current_server_address; using QuicDispatcher::current_client_address; @@ -116,13 +121,14 @@ QuicDispatcher* dispatcher_; }; -QuicServerSession* CreateSession(QuicDispatcher* dispatcher, - const QuicConfig& config, - QuicConnectionId connection_id, - const IPEndPoint& client_address, - MockConnectionHelper* helper, - const QuicCryptoServerConfig* crypto_config, - TestQuicSpdyServerSession** session) { +QuicServerSessionBase* CreateSession( + QuicDispatcher* dispatcher, + const QuicConfig& config, + QuicConnectionId connection_id, + const IPEndPoint& client_address, + MockConnectionHelper* helper, + const QuicCryptoServerConfig* crypto_config, + TestQuicSpdyServerSession** session) { MockServerConnection* connection = new MockServerConnection(connection_id, helper, dispatcher); *session = new TestQuicSpdyServerSession(config, connection, crypto_config); @@ -406,7 +412,7 @@ // Sets up dispatcher_, sesession1_, and crypto_stream1_ based on // the test parameters. - QuicServerSession* CreateSessionBasedOnTestParams( + QuicServerSessionBase* CreateSessionBasedOnTestParams( QuicConnectionId connection_id, const IPEndPoint& client_address) { CreateSession(&dispatcher_, config_, connection_id, client_address,
diff --git a/net/tools/quic/quic_server_session.cc b/net/tools/quic/quic_server_session_base.cc similarity index 83% rename from net/tools/quic/quic_server_session.cc rename to net/tools/quic/quic_server_session_base.cc index 9c50faf..835df61 100644 --- a/net/tools/quic/quic_server_session.cc +++ b/net/tools/quic/quic_server_session_base.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "net/tools/quic/quic_server_session.h" +#include "net/tools/quic/quic_server_session_base.h" #include "base/logging.h" #include "net/quic/proto/cached_network_parameters.pb.h" @@ -10,12 +10,11 @@ #include "net/quic/quic_flags.h" #include "net/quic/quic_spdy_session.h" #include "net/quic/reliable_quic_stream.h" -#include "net/tools/quic/quic_simple_server_stream.h" namespace net { namespace tools { -QuicServerSession::QuicServerSession( +QuicServerSessionBase::QuicServerSessionBase( const QuicConfig& config, QuicConnection* connection, QuicServerSessionVisitor* visitor, @@ -28,19 +27,14 @@ last_scup_time_(QuicTime::Zero()), last_scup_packet_number_(0) {} -QuicServerSession::~QuicServerSession() {} +QuicServerSessionBase::~QuicServerSessionBase() {} -void QuicServerSession::Initialize() { +void QuicServerSessionBase::Initialize() { crypto_stream_.reset(CreateQuicCryptoServerStream(crypto_config_)); QuicSpdySession::Initialize(); } -QuicCryptoServerStreamBase* QuicServerSession::CreateQuicCryptoServerStream( - const QuicCryptoServerConfig* crypto_config) { - return new QuicCryptoServerStream(crypto_config, this); -} - -void QuicServerSession::OnConfigNegotiated() { +void QuicServerSessionBase::OnConfigNegotiated() { QuicSession::OnConfigNegotiated(); if (!config()->HasReceivedConnectionOptions()) { @@ -79,8 +73,8 @@ } } -void QuicServerSession::OnConnectionClosed(QuicErrorCode error, - bool from_peer) { +void QuicServerSessionBase::OnConnectionClosed(QuicErrorCode error, + bool from_peer) { QuicSession::OnConnectionClosed(error, from_peer); // In the unlikely event we get a connection close while doing an asynchronous // crypto event, make sure we cancel the callback. @@ -90,12 +84,12 @@ visitor_->OnConnectionClosed(connection()->connection_id(), error); } -void QuicServerSession::OnWriteBlocked() { +void QuicServerSessionBase::OnWriteBlocked() { QuicSession::OnWriteBlocked(); visitor_->OnWriteBlocked(connection()); } -void QuicServerSession::OnCongestionWindowChange(QuicTime now) { +void QuicServerSessionBase::OnCongestionWindowChange(QuicTime now) { if (!bandwidth_resumption_enabled_) { return; } @@ -182,7 +176,7 @@ last_scup_packet_number_ = connection()->packet_number_of_last_sent_packet(); } -bool QuicServerSession::ShouldCreateIncomingDynamicStream(QuicStreamId id) { +bool QuicServerSessionBase::ShouldCreateIncomingDynamicStream(QuicStreamId id) { if (!connection()->connected()) { LOG(DFATAL) << "ShouldCreateIncomingDynamicStream called when disconnected"; return false; @@ -197,16 +191,7 @@ return true; } -QuicSpdyStream* QuicServerSession::CreateIncomingDynamicStream( - QuicStreamId id) { - if (!ShouldCreateIncomingDynamicStream(id)) { - return nullptr; - } - - return new QuicSimpleServerStream(id, this); -} - -bool QuicServerSession::ShouldCreateOutgoingDynamicStream() { +bool QuicServerSessionBase::ShouldCreateOutgoingDynamicStream() { if (!connection()->connected()) { LOG(DFATAL) << "ShouldCreateOutgoingDynamicStream called when disconnected"; return false; @@ -223,20 +208,7 @@ return true; } -QuicSpdyStream* QuicServerSession::CreateOutgoingDynamicStream( - SpdyPriority priority) { - if (!ShouldCreateOutgoingDynamicStream()) { - return nullptr; - } - - QuicSpdyStream* stream = - new QuicSimpleServerStream(GetNextOutgoingStreamId(), this); - stream->SetPriority(priority); - ActivateStream(stream); - return stream; -} - -QuicCryptoServerStreamBase* QuicServerSession::GetCryptoStream() { +QuicCryptoServerStreamBase* QuicServerSessionBase::GetCryptoStream() { return crypto_stream_.get(); }
diff --git a/net/tools/quic/quic_server_session.h b/net/tools/quic/quic_server_session_base.h similarity index 81% rename from net/tools/quic/quic_server_session.h rename to net/tools/quic/quic_server_session_base.h index e3958553..a68d52b 100644 --- a/net/tools/quic/quic_server_session.h +++ b/net/tools/quic/quic_server_session_base.h
@@ -4,8 +4,8 @@ // // A server specific QuicSession subclass. -#ifndef NET_TOOLS_QUIC_QUIC_SERVER_SESSION_H_ -#define NET_TOOLS_QUIC_QUIC_SERVER_SESSION_H_ +#ifndef NET_TOOLS_QUIC_QUIC_SERVER_SESSION_BASE_H_ +#define NET_TOOLS_QUIC_QUIC_SERVER_SESSION_BASE_H_ #include <stdint.h> @@ -31,7 +31,8 @@ namespace tools { namespace test { -class QuicServerSessionPeer; +class QuicServerSessionBasePeer; +class QuicSimpleServerSessionPeer; } // namespace test // An interface from the session to the entity owning the session. @@ -52,13 +53,13 @@ QuicConnectionId connection_id) {} }; -class QuicServerSession : public QuicSpdySession { +class QuicServerSessionBase : public QuicSpdySession { public: // |crypto_config| must outlive the session. - QuicServerSession(const QuicConfig& config, - QuicConnection* connection, - QuicServerSessionVisitor* visitor, - const QuicCryptoServerConfig* crypto_config); + QuicServerSessionBase(const QuicConfig& config, + QuicConnection* connection, + QuicServerSessionVisitor* visitor, + const QuicCryptoServerConfig* crypto_config); // Override the base class to notify the owner of the connection close. void OnConnectionClosed(QuicErrorCode error, bool from_peer) override; @@ -68,7 +69,7 @@ // estimate. void OnCongestionWindowChange(QuicTime now) override; - ~QuicServerSession() override; + ~QuicServerSessionBase() override; void Initialize() override; @@ -84,9 +85,7 @@ } protected: - // QuicSession methods: - QuicSpdyStream* CreateIncomingDynamicStream(QuicStreamId id) override; - QuicSpdyStream* CreateOutgoingDynamicStream(SpdyPriority priority) override; + // QuicSession methods(override them with return type of QuicSpdyStream*): QuicCryptoServerStreamBase* GetCryptoStream() override; // If an outgoing stream can be created, return true. @@ -101,12 +100,13 @@ virtual bool ShouldCreateIncomingDynamicStream(QuicStreamId id); virtual QuicCryptoServerStreamBase* CreateQuicCryptoServerStream( - const QuicCryptoServerConfig* crypto_config); + const QuicCryptoServerConfig* crypto_config) = 0; const QuicCryptoServerConfig* crypto_config() { return crypto_config_; } private: - friend class test::QuicServerSessionPeer; + friend class test::QuicServerSessionBasePeer; + friend class test::QuicSimpleServerSessionPeer; const QuicCryptoServerConfig* crypto_config_; scoped_ptr<QuicCryptoServerStreamBase> crypto_stream_; @@ -128,10 +128,10 @@ // Number of packets sent to the peer, at the time we last sent a SCUP. int64_t last_scup_packet_number_; - DISALLOW_COPY_AND_ASSIGN(QuicServerSession); + DISALLOW_COPY_AND_ASSIGN(QuicServerSessionBase); }; } // namespace tools } // namespace net -#endif // NET_TOOLS_QUIC_QUIC_SERVER_SESSION_H_ +#endif // NET_TOOLS_QUIC_QUIC_SERVER_SESSION_BASE_H_
diff --git a/net/tools/quic/quic_server_session_test.cc b/net/tools/quic/quic_server_session_base_test.cc similarity index 77% rename from net/tools/quic/quic_server_session_test.cc rename to net/tools/quic/quic_server_session_base_test.cc index 93c1663..36432aa 100644 --- a/net/tools/quic/quic_server_session_test.cc +++ b/net/tools/quic/quic_server_session_base_test.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "net/tools/quic/quic_server_session.h" +#include "net/tools/quic/quic_server_session_base.h" #include "base/macros.h" #include "net/quic/crypto/quic_crypto_server_config.h" @@ -52,34 +52,65 @@ namespace tools { namespace test { -class QuicServerSessionPeer { +class QuicServerSessionBasePeer { public: - static ReliableQuicStream* GetOrCreateDynamicStream(QuicServerSession* s, + static ReliableQuicStream* GetOrCreateDynamicStream(QuicServerSessionBase* s, QuicStreamId id) { return s->GetOrCreateDynamicStream(id); } - static void SetCryptoStream(QuicServerSession* s, + static void SetCryptoStream(QuicServerSessionBase* s, QuicCryptoServerStream* crypto_stream) { s->crypto_stream_.reset(crypto_stream); s->static_streams()[kCryptoStreamId] = crypto_stream; } - static bool IsBandwidthResumptionEnabled(QuicServerSession* s) { + static bool IsBandwidthResumptionEnabled(QuicServerSessionBase* s) { return s->bandwidth_resumption_enabled_; } - - static QuicSpdyStream* CreateOutgoingDynamicStream(QuicServerSession* s, - SpdyPriority priority) { - return s->CreateOutgoingDynamicStream(priority); - } }; namespace { +class TestServerSession : public QuicServerSessionBase { + public: + TestServerSession(const QuicConfig& config, + QuicConnection* connection, + QuicServerSessionVisitor* visitor, + const QuicCryptoServerConfig* crypto_config) + : QuicServerSessionBase(config, connection, visitor, crypto_config) {} + + ~TestServerSession() override{}; + + protected: + QuicSpdyStream* CreateIncomingDynamicStream(QuicStreamId id) override { + if (!ShouldCreateIncomingDynamicStream(id)) { + return nullptr; + } + return new QuicSimpleServerStream(id, this); + } + + QuicSpdyStream* CreateOutgoingDynamicStream(SpdyPriority priority) override { + if (!ShouldCreateOutgoingDynamicStream()) { + return nullptr; + } + + QuicSpdyStream* stream = + new QuicSimpleServerStream(GetNextOutgoingStreamId(), this); + stream->SetPriority(priority); + ActivateStream(stream); + return stream; + } + + QuicCryptoServerStreamBase* CreateQuicCryptoServerStream( + const QuicCryptoServerConfig* crypto_config) override { + return new QuicCryptoServerStream(crypto_config, this); + } +}; + const size_t kMaxStreamsForTest = 10; -class QuicServerSessionTest : public ::testing::TestWithParam<QuicVersion> { +class QuicServerSessionBaseTest : public ::testing::TestWithParam<QuicVersion> { protected: - QuicServerSessionTest() + QuicServerSessionBaseTest() : crypto_config_(QuicCryptoServerConfig::TESTING, QuicRandom::GetInstance(), CryptoTestUtils::ProofSourceForTesting()) { @@ -92,7 +123,7 @@ connection_ = new StrictMock<MockConnection>( &helper_, Perspective::IS_SERVER, SupportedVersions(GetParam())); session_.reset( - new QuicServerSession(config_, connection_, &owner_, &crypto_config_)); + new TestServerSession(config_, connection_, &owner_, &crypto_config_)); MockClock clock; handshake_message_.reset(crypto_config_.AddDefaultConfig( QuicRandom::GetInstance(), &clock, @@ -106,7 +137,7 @@ StrictMock<MockConnection>* connection_; QuicConfig config_; QuicCryptoServerConfig crypto_config_; - scoped_ptr<QuicServerSession> session_; + scoped_ptr<TestServerSession> session_; scoped_ptr<CryptoHandshakeMessage> handshake_message_; QuicConnectionVisitorInterface* visitor_; }; @@ -128,10 +159,10 @@ } INSTANTIATE_TEST_CASE_P(Tests, - QuicServerSessionTest, + QuicServerSessionBaseTest, ::testing::ValuesIn(QuicSupportedVersions())); -TEST_P(QuicServerSessionTest, CloseStreamDueToReset) { +TEST_P(QuicServerSessionBaseTest, CloseStreamDueToReset) { // Open a stream, then reset it. // Send two bytes of payload to open it. QuicStreamFrame data1(kClientDataStreamId1, false, 0, StringPiece("HT")); @@ -154,7 +185,7 @@ EXPECT_TRUE(connection_->connected()); } -TEST_P(QuicServerSessionTest, NeverOpenStreamDueToReset) { +TEST_P(QuicServerSessionBaseTest, NeverOpenStreamDueToReset) { // Send a reset (and expect the peer to send a RST in response). QuicRstStreamFrame rst1(kClientDataStreamId1, QUIC_ERROR_PROCESSING_STREAM, 0); @@ -172,7 +203,7 @@ EXPECT_TRUE(connection_->connected()); } -TEST_P(QuicServerSessionTest, AcceptClosedStream) { +TEST_P(QuicServerSessionBaseTest, AcceptClosedStream) { // Send (empty) compressed headers followed by two bytes of data. QuicStreamFrame frame1(kClientDataStreamId1, false, 0, StringPiece("\1\0\0\0\0\0\0\0HT")); @@ -200,7 +231,7 @@ EXPECT_TRUE(connection_->connected()); } -TEST_P(QuicServerSessionTest, MaxOpenStreams) { +TEST_P(QuicServerSessionBaseTest, MaxOpenStreams) { // Test that the server refuses if a client attempts to open too many data // streams. The server accepts slightly more than the negotiated stream limit // to deal with rare cases where a client FIN/RST is lost. @@ -218,15 +249,15 @@ QuicStreamId stream_id = kClientDataStreamId1; // Open the max configured number of streams, should be no problem. for (size_t i = 0; i < kMaxStreamsForTest; ++i) { - EXPECT_TRUE(QuicServerSessionPeer::GetOrCreateDynamicStream(session_.get(), - stream_id)); + EXPECT_TRUE(QuicServerSessionBasePeer::GetOrCreateDynamicStream( + session_.get(), stream_id)); stream_id += 2; } // Open more streams: server should accept slightly more than the limit. for (size_t i = 0; i < kMaxStreamsMinimumIncrement; ++i) { - EXPECT_TRUE(QuicServerSessionPeer::GetOrCreateDynamicStream(session_.get(), - stream_id)); + EXPECT_TRUE(QuicServerSessionBasePeer::GetOrCreateDynamicStream( + session_.get(), stream_id)); stream_id += 2; } @@ -241,11 +272,11 @@ EXPECT_CALL(*connection_, SendRstStream(stream_id, QUIC_REFUSED_STREAM, 0)); } // Even if the connection remains open, the stream creation should fail. - EXPECT_FALSE(QuicServerSessionPeer::GetOrCreateDynamicStream(session_.get(), - stream_id)); + EXPECT_FALSE(QuicServerSessionBasePeer::GetOrCreateDynamicStream( + session_.get(), stream_id)); } -TEST_P(QuicServerSessionTest, MaxAvailableStreams) { +TEST_P(QuicServerSessionBaseTest, MaxAvailableStreams) { // Test that the server closes the connection if a client makes too many data // streams available. The server accepts slightly more than the negotiated // stream limit to deal with rare cases where a client FIN/RST is lost. @@ -261,13 +292,13 @@ EXPECT_LE(10 * kMaxStreamsForTest, kAvailableStreamLimit); EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams()); - EXPECT_TRUE(QuicServerSessionPeer::GetOrCreateDynamicStream( + EXPECT_TRUE(QuicServerSessionBasePeer::GetOrCreateDynamicStream( session_.get(), kClientDataStreamId1)); // Establish available streams up to the server's limit. const int kLimitingStreamId = kClientDataStreamId1 + (kAvailableStreamLimit)*2 + 2; - EXPECT_TRUE(QuicServerSessionPeer::GetOrCreateDynamicStream( + EXPECT_TRUE(QuicServerSessionBasePeer::GetOrCreateDynamicStream( session_.get(), kLimitingStreamId)); // A further available stream will result in connection close. @@ -275,27 +306,27 @@ QUIC_TOO_MANY_AVAILABLE_STREAMS, _)); // This forces stream kLimitingStreamId + 2 to become available, which // violates the quota. - EXPECT_FALSE(QuicServerSessionPeer::GetOrCreateDynamicStream( + EXPECT_FALSE(QuicServerSessionBasePeer::GetOrCreateDynamicStream( session_.get(), kLimitingStreamId + 4)); } -TEST_P(QuicServerSessionTest, GetEvenIncomingError) { +TEST_P(QuicServerSessionBaseTest, GetEvenIncomingError) { // Incoming streams on the server session must be odd. EXPECT_CALL(*connection_, SendConnectionCloseWithDetails(QUIC_INVALID_STREAM_ID, _)); - EXPECT_EQ(nullptr, - QuicServerSessionPeer::GetOrCreateDynamicStream(session_.get(), 4)); + EXPECT_EQ(nullptr, QuicServerSessionBasePeer::GetOrCreateDynamicStream( + session_.get(), 4)); } -TEST_P(QuicServerSessionTest, GetStreamDisconnected) { +TEST_P(QuicServerSessionBaseTest, GetStreamDisconnected) { // Don't create new streams if the connection is disconnected. QuicConnectionPeer::CloseConnection(connection_); EXPECT_DFATAL( - QuicServerSessionPeer::GetOrCreateDynamicStream(session_.get(), 5), + QuicServerSessionBasePeer::GetOrCreateDynamicStream(session_.get(), 5), "ShouldCreateIncomingDynamicStream called when disconnected"); } -TEST_P(QuicServerSessionTest, SetFecProtectionFromConfig) { +TEST_P(QuicServerSessionBaseTest, SetFecProtectionFromConfig) { ValueRestore<bool> old_flag(&FLAGS_enable_quic_fec, true); // Set received config to have FEC connection option. @@ -309,8 +340,9 @@ EXPECT_EQ( FEC_PROTECT_ALWAYS, QuicSpdySessionPeer::GetHeadersStream(session_.get())->fec_policy()); - ReliableQuicStream* stream = QuicServerSessionPeer::GetOrCreateDynamicStream( - session_.get(), kClientDataStreamId1); + ReliableQuicStream* stream = + QuicServerSessionBasePeer::GetOrCreateDynamicStream(session_.get(), + kClientDataStreamId1); ASSERT_TRUE(stream); EXPECT_EQ(FEC_PROTECT_OPTIONAL, stream->fec_policy()); } @@ -334,7 +366,7 @@ DISALLOW_COPY_AND_ASSIGN(MockQuicCryptoServerStream); }; -TEST_P(QuicServerSessionTest, BandwidthEstimates) { +TEST_P(QuicServerSessionBaseTest, BandwidthEstimates) { // Test that bandwidth estimate updates are sent to the client, only when // bandwidth resumption is enabled, the bandwidth estimate has changed // sufficiently, enough time has passed, @@ -346,7 +378,7 @@ QuicConfigPeer::SetReceivedConnectionOptions(session_->config(), copt); session_->OnConfigNegotiated(); EXPECT_TRUE( - QuicServerSessionPeer::IsBandwidthResumptionEnabled(session_.get())); + QuicServerSessionBasePeer::IsBandwidthResumptionEnabled(session_.get())); int32_t bandwidth_estimate_kbytes_per_second = 123; int32_t max_bandwidth_estimate_kbytes_per_second = 134; @@ -356,7 +388,7 @@ MockQuicCryptoServerStream* crypto_stream = new MockQuicCryptoServerStream(&crypto_config_, session_.get()); - QuicServerSessionPeer::SetCryptoStream(session_.get(), crypto_stream); + QuicServerSessionBasePeer::SetCryptoStream(session_.get(), crypto_stream); // Set some initial bandwidth values. QuicSentPacketManager* sent_packet_manager = @@ -433,7 +465,7 @@ session_->OnCongestionWindowChange(now); } -TEST_P(QuicServerSessionTest, BandwidthResumptionExperiment) { +TEST_P(QuicServerSessionBaseTest, BandwidthResumptionExperiment) { // Test that if a client provides a CachedNetworkParameters with the same // serving region as the current server, and which was made within an hour of // now, that this data is passed down to the send algorithm. @@ -481,9 +513,9 @@ session_->OnConfigNegotiated(); } -TEST_P(QuicServerSessionTest, BandwidthMaxEnablesResumption) { +TEST_P(QuicServerSessionBaseTest, BandwidthMaxEnablesResumption) { EXPECT_FALSE( - QuicServerSessionPeer::IsBandwidthResumptionEnabled(session_.get())); + QuicServerSessionBasePeer::IsBandwidthResumptionEnabled(session_.get())); // Client has sent kBWMX connection option to trigger bandwidth resumption. QuicTagVector copt; @@ -491,73 +523,15 @@ QuicConfigPeer::SetReceivedConnectionOptions(session_->config(), copt); session_->OnConfigNegotiated(); EXPECT_TRUE( - QuicServerSessionPeer::IsBandwidthResumptionEnabled(session_.get())); + QuicServerSessionBasePeer::IsBandwidthResumptionEnabled(session_.get())); } -TEST_P(QuicServerSessionTest, NoBandwidthResumptionByDefault) { +TEST_P(QuicServerSessionBaseTest, NoBandwidthResumptionByDefault) { EXPECT_FALSE( - QuicServerSessionPeer::IsBandwidthResumptionEnabled(session_.get())); + QuicServerSessionBasePeer::IsBandwidthResumptionEnabled(session_.get())); session_->OnConfigNegotiated(); EXPECT_FALSE( - QuicServerSessionPeer::IsBandwidthResumptionEnabled(session_.get())); -} - -TEST_P(QuicServerSessionTest, CreateOutgoingDynamicStreamDisconnected) { - // Tests that outgoing stream creation fails when connection is not connected. - size_t initial_num_open_stream = session_->GetNumOpenOutgoingStreams(); - QuicConnectionPeer::CloseConnection(connection_); - EXPECT_DFATAL(QuicServerSessionPeer::CreateOutgoingDynamicStream( - session_.get(), kDefaultPriority), - "ShouldCreateOutgoingDynamicStream called when disconnected"); - EXPECT_EQ(initial_num_open_stream, session_->GetNumOpenOutgoingStreams()); -} - -TEST_P(QuicServerSessionTest, CreateOutgoingDynamicStreamUnencrypted) { - // Tests that outgoing stream creation fails when encryption has not yet been - // established. - size_t initial_num_open_stream = session_->GetNumOpenOutgoingStreams(); - EXPECT_DFATAL(QuicServerSessionPeer::CreateOutgoingDynamicStream( - session_.get(), kDefaultPriority), - "Encryption not established so no outgoing stream created."); - EXPECT_EQ(initial_num_open_stream, session_->GetNumOpenOutgoingStreams()); -} - -TEST_P(QuicServerSessionTest, CreateOutgoingDynamicStreamUptoLimit) { - // Tests that outgoing stream creation should not be affected by existing - // incoming stream and vice-versa. But when reaching the limit of max outgoing - // stream allowed, creation should fail. - - // Receive some data to initiate a incoming stream which should not effect - // creating outgoing streams. - QuicStreamFrame data1(kClientDataStreamId1, false, 0, StringPiece("HT")); - session_->OnStreamFrame(data1); - EXPECT_EQ(1u, session_->GetNumOpenIncomingStreams()); - EXPECT_EQ(0u, session_->GetNumOpenOutgoingStreams()); - - // Assume encryption already established. - MockQuicCryptoServerStream* crypto_stream = - new MockQuicCryptoServerStream(&crypto_config_, session_.get()); - crypto_stream->set_encryption_established(true); - QuicServerSessionPeer::SetCryptoStream(session_.get(), crypto_stream); - - // Create push streams till reaching the upper limit of allowed open streams. - for (size_t i = 0; i < kMaxStreamsForTest; ++i) { - QuicSpdyStream* created_stream = - QuicServerSessionPeer::CreateOutgoingDynamicStream(session_.get(), - kDefaultPriority); - EXPECT_EQ(2 * (i + 1), created_stream->id()); - EXPECT_EQ(i + 1, session_->GetNumOpenOutgoingStreams()); - } - - // Continuing creating push stream would fail. - EXPECT_EQ(nullptr, QuicServerSessionPeer::CreateOutgoingDynamicStream( - session_.get(), kDefaultPriority)); - EXPECT_EQ(kMaxStreamsForTest, session_->GetNumOpenOutgoingStreams()); - - // Create peer initiated stream should have no problem. - QuicStreamFrame data2(kClientDataStreamId2, false, 0, StringPiece("HT")); - session_->OnStreamFrame(data2); - EXPECT_EQ(2u, session_->GetNumOpenIncomingStreams()); + QuicServerSessionBasePeer::IsBandwidthResumptionEnabled(session_.get())); } } // namespace
diff --git a/net/tools/quic/quic_simple_client.cc b/net/tools/quic/quic_simple_client.cc index d7a3004..9890e0c 100644 --- a/net/tools/quic/quic_simple_client.cc +++ b/net/tools/quic/quic_simple_client.cc
@@ -232,7 +232,8 @@ DCHECK(initialized_); if (connected()) { - session()->connection()->SendConnectionClose(QUIC_PEER_GOING_AWAY); + session()->connection()->SendConnectionCloseWithDetails( + QUIC_PEER_GOING_AWAY, "Client disconnecting"); } STLDeleteElements(&data_to_resend_on_connect_); STLDeleteElements(&data_sent_before_handshake_);
diff --git a/net/tools/quic/quic_simple_server_session.cc b/net/tools/quic/quic_simple_server_session.cc new file mode 100644 index 0000000..0c6aeb87 --- /dev/null +++ b/net/tools/quic/quic_simple_server_session.cc
@@ -0,0 +1,56 @@ +// 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 "net/tools/quic/quic_simple_server_session.h" + +#include "base/logging.h" +#include "net/quic/proto/cached_network_parameters.pb.h" +#include "net/quic/quic_connection.h" +#include "net/quic/quic_flags.h" +#include "net/quic/quic_spdy_session.h" +#include "net/quic/reliable_quic_stream.h" +#include "net/tools/quic/quic_simple_server_stream.h" + +namespace net { +namespace tools { + +QuicSimpleServerSession::QuicSimpleServerSession( + const QuicConfig& config, + QuicConnection* connection, + QuicServerSessionVisitor* visitor, + const QuicCryptoServerConfig* crypto_config) + : QuicServerSessionBase(config, connection, visitor, crypto_config) {} + +QuicSimpleServerSession::~QuicSimpleServerSession() {} + +QuicCryptoServerStreamBase* +QuicSimpleServerSession::CreateQuicCryptoServerStream( + const QuicCryptoServerConfig* crypto_config) { + return new QuicCryptoServerStream(crypto_config, this); +} + +QuicSpdyStream* QuicSimpleServerSession::CreateIncomingDynamicStream( + QuicStreamId id) { + if (!ShouldCreateIncomingDynamicStream(id)) { + return nullptr; + } + + return new QuicSimpleServerStream(id, this); +} + +QuicSimpleServerStream* QuicSimpleServerSession::CreateOutgoingDynamicStream( + SpdyPriority priority) { + if (!ShouldCreateOutgoingDynamicStream()) { + return nullptr; + } + + QuicSimpleServerStream* stream = + new QuicSimpleServerStream(GetNextOutgoingStreamId(), this); + stream->SetPriority(priority); + ActivateStream(stream); + return stream; +} + +} // namespace tools +} // namespace net
diff --git a/net/tools/quic/quic_simple_server_session.h b/net/tools/quic/quic_simple_server_session.h new file mode 100644 index 0000000..12d2b0d4 --- /dev/null +++ b/net/tools/quic/quic_simple_server_session.h
@@ -0,0 +1,66 @@ +// 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. +// +// A toy server specific QuicSession subclass. + +#ifndef NET_TOOLS_QUIC_QUIC_SIMPLE_SERVER_SESSION_H_ +#define NET_TOOLS_QUIC_QUIC_SIMPLE_SERVER_SESSION_H_ + +#include <stdint.h> + +#include <set> +#include <string> +#include <vector> + +#include "base/containers/hash_tables.h" +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" +#include "net/quic/quic_crypto_server_stream.h" +#include "net/quic/quic_protocol.h" +#include "net/quic/quic_spdy_session.h" +#include "net/tools/quic/quic_server_session_base.h" +#include "net/tools/quic/quic_simple_server_stream.h" + +namespace net { + +class QuicBlockedWriterInterface; +class QuicConfig; +class QuicConnection; +class QuicCryptoServerConfig; +class ReliableQuicStream; + +namespace tools { + +namespace test { +class QuicSimpleServerSessionPeer; +} // namespace test + +class QuicSimpleServerSession : public QuicServerSessionBase { + public: + QuicSimpleServerSession(const QuicConfig& config, + QuicConnection* connection, + QuicServerSessionVisitor* visitor, + const QuicCryptoServerConfig* crypto_config); + + ~QuicSimpleServerSession() override; + + protected: + // QuicSession methods: + QuicSpdyStream* CreateIncomingDynamicStream(QuicStreamId id) override; + QuicSimpleServerStream* CreateOutgoingDynamicStream( + SpdyPriority priority) override; + + QuicCryptoServerStreamBase* CreateQuicCryptoServerStream( + const QuicCryptoServerConfig* crypto_config) override; + + private: + friend class test::QuicSimpleServerSessionPeer; + + DISALLOW_COPY_AND_ASSIGN(QuicSimpleServerSession); +}; + +} // namespace tools +} // namespace net + +#endif // NET_TOOLS_QUIC_QUIC_SERVER_SESSION_H_
diff --git a/net/tools/quic/quic_simple_server_session_test.cc b/net/tools/quic/quic_simple_server_session_test.cc new file mode 100644 index 0000000..f2e451d --- /dev/null +++ b/net/tools/quic/quic_simple_server_session_test.cc
@@ -0,0 +1,296 @@ +// 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 "net/tools/quic/quic_simple_server_session.h" + +#include "base/macros.h" +#include "net/quic/crypto/quic_crypto_server_config.h" +#include "net/quic/crypto/quic_random.h" +#include "net/quic/proto/cached_network_parameters.pb.h" +#include "net/quic/quic_connection.h" +#include "net/quic/quic_crypto_server_stream.h" +#include "net/quic/quic_utils.h" +#include "net/quic/test_tools/crypto_test_utils.h" +#include "net/quic/test_tools/quic_config_peer.h" +#include "net/quic/test_tools/quic_connection_peer.h" +#include "net/quic/test_tools/quic_sent_packet_manager_peer.h" +#include "net/quic/test_tools/quic_session_peer.h" +#include "net/quic/test_tools/quic_spdy_session_peer.h" +#include "net/quic/test_tools/quic_spdy_stream_peer.h" +#include "net/quic/test_tools/quic_sustained_bandwidth_recorder_peer.h" +#include "net/quic/test_tools/quic_test_utils.h" +#include "net/test/gtest_util.h" +#include "net/tools/quic/quic_simple_server_stream.h" +#include "net/tools/quic/test_tools/mock_quic_server_session_visitor.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using __gnu_cxx::vector; +using net::test::CryptoTestUtils; +using net::test::MockConnection; +using net::test::MockConnectionHelper; +using net::test::QuicConfigPeer; +using net::test::QuicConnectionPeer; +using net::test::QuicSpdyStreamPeer; +using net::test::QuicSentPacketManagerPeer; +using net::test::QuicSessionPeer; +using net::test::QuicSpdySessionPeer; +using net::test::QuicSustainedBandwidthRecorderPeer; +using net::test::SupportedVersions; +using net::test::ValueRestore; +using net::test::kClientDataStreamId1; +using net::test::kClientDataStreamId2; +using net::test::kClientDataStreamId3; +using net::test::kInitialSessionFlowControlWindowForTest; +using net::test::kInitialStreamFlowControlWindowForTest; +using std::string; +using testing::StrictMock; +using testing::_; + +namespace net { +namespace tools { +namespace test { + +class QuicSimpleServerSessionPeer { + public: + static void SetCryptoStream(QuicSimpleServerSession* s, + QuicCryptoServerStream* crypto_stream) { + s->crypto_stream_.reset(crypto_stream); + s->static_streams()[kCryptoStreamId] = crypto_stream; + } + + static QuicSpdyStream* CreateIncomingDynamicStream(QuicSimpleServerSession* s, + QuicStreamId id) { + return s->CreateIncomingDynamicStream(id); + } + + static QuicSimpleServerStream* CreateOutgoingDynamicStream( + QuicSimpleServerSession* s, + SpdyPriority priority) { + return s->CreateOutgoingDynamicStream(priority); + } +}; + +namespace { + +const size_t kMaxStreamsForTest = 10; + +class QuicSimpleServerSessionTest + : public ::testing::TestWithParam<QuicVersion> { + protected: + QuicSimpleServerSessionTest() + : crypto_config_(QuicCryptoServerConfig::TESTING, + QuicRandom::GetInstance(), + CryptoTestUtils::ProofSourceForTesting()) { + config_.SetMaxStreamsPerConnection(kMaxStreamsForTest, kMaxStreamsForTest); + config_.SetInitialStreamFlowControlWindowToSend( + kInitialStreamFlowControlWindowForTest); + config_.SetInitialSessionFlowControlWindowToSend( + kInitialSessionFlowControlWindowForTest); + + connection_ = new StrictMock<MockConnection>( + &helper_, Perspective::IS_SERVER, SupportedVersions(GetParam())); + session_.reset(new QuicSimpleServerSession(config_, connection_, &owner_, + &crypto_config_)); + MockClock clock; + handshake_message_.reset(crypto_config_.AddDefaultConfig( + QuicRandom::GetInstance(), &clock, + QuicCryptoServerConfig::ConfigOptions())); + session_->Initialize(); + visitor_ = QuicConnectionPeer::GetVisitor(connection_); + } + + StrictMock<MockQuicServerSessionVisitor> owner_; + MockConnectionHelper helper_; + StrictMock<MockConnection>* connection_; + QuicConfig config_; + QuicCryptoServerConfig crypto_config_; + scoped_ptr<QuicSimpleServerSession> session_; + scoped_ptr<CryptoHandshakeMessage> handshake_message_; + QuicConnectionVisitorInterface* visitor_; +}; + +INSTANTIATE_TEST_CASE_P(Tests, + QuicSimpleServerSessionTest, + ::testing::ValuesIn(QuicSupportedVersions())); + +TEST_P(QuicSimpleServerSessionTest, CloseStreamDueToReset) { + // Open a stream, then reset it. + // Send two bytes of payload to open it. + QuicStreamFrame data1(kClientDataStreamId1, false, 0, StringPiece("HT")); + session_->OnStreamFrame(data1); + EXPECT_EQ(1u, session_->GetNumOpenIncomingStreams()); + + // Send a reset (and expect the peer to send a RST in response). + QuicRstStreamFrame rst1(kClientDataStreamId1, QUIC_ERROR_PROCESSING_STREAM, + 0); + EXPECT_CALL(*connection_, + SendRstStream(kClientDataStreamId1, QUIC_RST_ACKNOWLEDGEMENT, 0)); + visitor_->OnRstStream(rst1); + EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams()); + + // Send the same two bytes of payload in a new packet. + visitor_->OnStreamFrame(data1); + + // The stream should not be re-opened. + EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams()); + EXPECT_TRUE(connection_->connected()); +} + +TEST_P(QuicSimpleServerSessionTest, NeverOpenStreamDueToReset) { + // Send a reset (and expect the peer to send a RST in response). + QuicRstStreamFrame rst1(kClientDataStreamId1, QUIC_ERROR_PROCESSING_STREAM, + 0); + EXPECT_CALL(*connection_, + SendRstStream(kClientDataStreamId1, QUIC_RST_ACKNOWLEDGEMENT, 0)); + visitor_->OnRstStream(rst1); + EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams()); + + // Send two bytes of payload. + QuicStreamFrame data1(kClientDataStreamId1, false, 0, StringPiece("HT")); + visitor_->OnStreamFrame(data1); + + // The stream should never be opened, now that the reset is received. + EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams()); + EXPECT_TRUE(connection_->connected()); +} + +TEST_P(QuicSimpleServerSessionTest, AcceptClosedStream) { + // Send (empty) compressed headers followed by two bytes of data. + QuicStreamFrame frame1(kClientDataStreamId1, false, 0, + StringPiece("\1\0\0\0\0\0\0\0HT")); + QuicStreamFrame frame2(kClientDataStreamId2, false, 0, + StringPiece("\2\0\0\0\0\0\0\0HT")); + visitor_->OnStreamFrame(frame1); + visitor_->OnStreamFrame(frame2); + EXPECT_EQ(2u, session_->GetNumOpenIncomingStreams()); + + // Send a reset (and expect the peer to send a RST in response). + QuicRstStreamFrame rst(kClientDataStreamId1, QUIC_ERROR_PROCESSING_STREAM, 0); + EXPECT_CALL(*connection_, + SendRstStream(kClientDataStreamId1, QUIC_RST_ACKNOWLEDGEMENT, 0)); + visitor_->OnRstStream(rst); + + // If we were tracking, we'd probably want to reject this because it's data + // past the reset point of stream 3. As it's a closed stream we just drop the + // data on the floor, but accept the packet because it has data for stream 5. + QuicStreamFrame frame3(kClientDataStreamId1, false, 2, StringPiece("TP")); + QuicStreamFrame frame4(kClientDataStreamId2, false, 2, StringPiece("TP")); + visitor_->OnStreamFrame(frame3); + visitor_->OnStreamFrame(frame4); + // The stream should never be opened, now that the reset is received. + EXPECT_EQ(1u, session_->GetNumOpenIncomingStreams()); + EXPECT_TRUE(connection_->connected()); +} + +TEST_P(QuicSimpleServerSessionTest, CreateIncomingDynamicStreamDisconnected) { + // Tests that incoming stream creation fails when connection is not connected. + size_t initial_num_open_stream = session_->GetNumOpenIncomingStreams(); + QuicConnectionPeer::CloseConnection(connection_); + EXPECT_DFATAL(QuicSimpleServerSessionPeer::CreateIncomingDynamicStream( + session_.get(), kClientDataStreamId1), + "ShouldCreateIncomingDynamicStream called when disconnected"); + EXPECT_EQ(initial_num_open_stream, session_->GetNumOpenIncomingStreams()); +} + +TEST_P(QuicSimpleServerSessionTest, CreateEvenIncomingDynamicStream) { + // Tests that incoming stream creation fails when given stream id is even. + size_t initial_num_open_stream = session_->GetNumOpenIncomingStreams(); + EXPECT_CALL(*connection_, SendConnectionCloseWithDetails( + QUIC_INVALID_STREAM_ID, + "Client created even numbered stream")); + QuicSimpleServerSessionPeer::CreateIncomingDynamicStream(session_.get(), 2); + EXPECT_EQ(initial_num_open_stream, session_->GetNumOpenIncomingStreams()); +} + +TEST_P(QuicSimpleServerSessionTest, CreateIncomingDynamicStream) { + std::unique_ptr<QuicSpdyStream> stream( + QuicSimpleServerSessionPeer::CreateIncomingDynamicStream( + session_.get(), kClientDataStreamId1)); + EXPECT_NE(nullptr, stream); + EXPECT_EQ(kClientDataStreamId1, stream->id()); +} + +class MockQuicCryptoServerStream : public QuicCryptoServerStream { + public: + explicit MockQuicCryptoServerStream( + const QuicCryptoServerConfig* crypto_config, + QuicSession* session) + : QuicCryptoServerStream(crypto_config, session) {} + ~MockQuicCryptoServerStream() override {} + + MOCK_METHOD1(SendServerConfigUpdate, + void(const CachedNetworkParameters* cached_network_parameters)); + + void set_encryption_established(bool has_established) { + encryption_established_ = has_established; + } + + private: + DISALLOW_COPY_AND_ASSIGN(MockQuicCryptoServerStream); +}; + +TEST_P(QuicSimpleServerSessionTest, CreateOutgoingDynamicStreamDisconnected) { + // Tests that outgoing stream creation fails when connection is not connected. + size_t initial_num_open_stream = session_->GetNumOpenOutgoingStreams(); + QuicConnectionPeer::CloseConnection(connection_); + EXPECT_DFATAL(QuicSimpleServerSessionPeer::CreateOutgoingDynamicStream( + session_.get(), kDefaultPriority), + "ShouldCreateOutgoingDynamicStream called when disconnected"); + + EXPECT_EQ(initial_num_open_stream, session_->GetNumOpenOutgoingStreams()); +} + +TEST_P(QuicSimpleServerSessionTest, CreateOutgoingDynamicStreamUnencrypted) { + // Tests that outgoing stream creation fails when encryption has not yet been + // established. + size_t initial_num_open_stream = session_->GetNumOpenOutgoingStreams(); + EXPECT_DFATAL(QuicSimpleServerSessionPeer::CreateOutgoingDynamicStream( + session_.get(), kDefaultPriority), + "Encryption not established so no outgoing stream created."); + EXPECT_EQ(initial_num_open_stream, session_->GetNumOpenOutgoingStreams()); +} + +TEST_P(QuicSimpleServerSessionTest, CreateOutgoingDynamicStreamUptoLimit) { + // Tests that outgoing stream creation should not be affected by existing + // incoming stream and vice-versa. But when reaching the limit of max outgoing + // stream allowed, creation should fail. + + // Receive some data to initiate a incoming stream which should not effect + // creating outgoing streams. + QuicStreamFrame data1(kClientDataStreamId1, false, 0, StringPiece("HT")); + session_->OnStreamFrame(data1); + EXPECT_EQ(1u, session_->GetNumOpenIncomingStreams()); + EXPECT_EQ(0u, session_->GetNumOpenOutgoingStreams()); + + // Assume encryption already established. + MockQuicCryptoServerStream* crypto_stream = + new MockQuicCryptoServerStream(&crypto_config_, session_.get()); + crypto_stream->set_encryption_established(true); + QuicSimpleServerSessionPeer::SetCryptoStream(session_.get(), crypto_stream); + + // Create push streams till reaching the upper limit of allowed open streams. + for (size_t i = 0; i < kMaxStreamsForTest; ++i) { + QuicSpdyStream* created_stream = + QuicSimpleServerSessionPeer::CreateOutgoingDynamicStream( + session_.get(), kDefaultPriority); + EXPECT_EQ(2 * (i + 1), created_stream->id()); + EXPECT_EQ(i + 1, session_->GetNumOpenOutgoingStreams()); + } + + // Continuing creating push stream would fail. + EXPECT_EQ(nullptr, QuicSimpleServerSessionPeer::CreateOutgoingDynamicStream( + session_.get(), kDefaultPriority)); + EXPECT_EQ(kMaxStreamsForTest, session_->GetNumOpenOutgoingStreams()); + + // Create peer initiated stream should have no problem. + QuicStreamFrame data2(kClientDataStreamId2, false, 0, StringPiece("HT")); + session_->OnStreamFrame(data2); + EXPECT_EQ(2u, session_->GetNumOpenIncomingStreams()); +} + +} // namespace +} // namespace test +} // namespace tools +} // namespace net
diff --git a/net/tools/quic/quic_simple_server_stream.h b/net/tools/quic/quic_simple_server_stream.h index 9756c79..015a96a 100644 --- a/net/tools/quic/quic_simple_server_stream.h +++ b/net/tools/quic/quic_simple_server_stream.h
@@ -16,8 +16,6 @@ namespace net { -class QuicSpdySession; - namespace tools { namespace test {
diff --git a/net/tools/quic/quic_time_wait_list_manager.cc b/net/tools/quic/quic_time_wait_list_manager.cc index fb834577..9472e73 100644 --- a/net/tools/quic/quic_time_wait_list_manager.cc +++ b/net/tools/quic/quic_time_wait_list_manager.cc
@@ -19,7 +19,7 @@ #include "net/quic/quic_framer.h" #include "net/quic/quic_protocol.h" #include "net/quic/quic_utils.h" -#include "net/tools/quic/quic_server_session.h" +#include "net/tools/quic/quic_server_session_base.h" using base::StringPiece;
diff --git a/net/tools/quic/test_tools/mock_quic_server_session_visitor.h b/net/tools/quic/test_tools/mock_quic_server_session_visitor.h index 63c2385..15fba1d 100644 --- a/net/tools/quic/test_tools/mock_quic_server_session_visitor.h +++ b/net/tools/quic/test_tools/mock_quic_server_session_visitor.h
@@ -6,7 +6,7 @@ #define NET_TOOLS_QUIC_TEST_TOOLS_MOCK_QUIC_SERVER_SESSION_VISITOR_H_ #include "base/macros.h" -#include "net/tools/quic/quic_server_session.h" +#include "net/tools/quic/quic_server_session_base.h" #include "testing/gmock/include/gmock/gmock.h" namespace net {
diff --git a/net/tools/quic/test_tools/quic_test_server.cc b/net/tools/quic/test_tools/quic_test_server.cc index 417d2a6..4ba113f9 100644 --- a/net/tools/quic/test_tools/quic_test_server.cc +++ b/net/tools/quic/test_tools/quic_test_server.cc
@@ -20,14 +20,14 @@ #include "net/quic/quic_protocol.h" #include "net/tools/quic/quic_dispatcher.h" #include "net/tools/quic/quic_epoll_connection_helper.h" -#include "net/tools/quic/quic_server_session.h" +#include "net/tools/quic/quic_simple_server_session.h" #include "net/tools/quic/quic_simple_server_stream.h" namespace net { namespace tools { namespace test { -class CustomStreamSession : public QuicServerSession { +class CustomStreamSession : public QuicSimpleServerSession { public: CustomStreamSession( const QuicConfig& config, @@ -36,7 +36,7 @@ const QuicCryptoServerConfig* crypto_config, QuicTestServer::StreamFactory* factory, QuicTestServer::CryptoStreamFactory* crypto_stream_factory) - : QuicServerSession(config, connection, visitor, crypto_config), + : QuicSimpleServerSession(config, connection, visitor, crypto_config), stream_factory_(factory), crypto_stream_factory_(crypto_stream_factory) {} @@ -47,7 +47,7 @@ if (stream_factory_) { return stream_factory_->CreateStream(id, this); } - return QuicServerSession::CreateIncomingDynamicStream(id); + return QuicSimpleServerSession::CreateIncomingDynamicStream(id); } QuicCryptoServerStreamBase* CreateQuicCryptoServerStream( @@ -55,7 +55,7 @@ if (crypto_stream_factory_) { return crypto_stream_factory_->CreateCryptoStream(crypto_config, this); } - return QuicServerSession::CreateQuicCryptoServerStream(crypto_config); + return QuicSimpleServerSession::CreateQuicCryptoServerStream(crypto_config); } private: @@ -75,8 +75,8 @@ stream_factory_(nullptr), crypto_stream_factory_(nullptr) {} - QuicServerSession* CreateQuicSession(QuicConnectionId id, - const IPEndPoint& client) override { + QuicServerSessionBase* CreateQuicSession(QuicConnectionId id, + const IPEndPoint& client) override { base::AutoLock lock(factory_lock_); if (session_factory_ == nullptr && stream_factory_ == nullptr && crypto_stream_factory_ == nullptr) { @@ -86,7 +86,7 @@ id, client, helper(), connection_writer_factory(), /* owns_writer= */ true, Perspective::IS_SERVER, supported_versions()); - QuicServerSession* session = nullptr; + QuicServerSessionBase* session = nullptr; if (stream_factory_ != nullptr || crypto_stream_factory_ != nullptr) { session = new CustomStreamSession(config(), connection, this, crypto_config(), @@ -164,7 +164,7 @@ QuicConnection* connection, QuicServerSessionVisitor* visitor, const QuicCryptoServerConfig* crypto_config) - : QuicServerSession(config, connection, visitor, crypto_config) { + : QuicSimpleServerSession(config, connection, visitor, crypto_config) { SendGoAway(QUIC_PEER_GOING_AWAY, ""); }
diff --git a/net/tools/quic/test_tools/quic_test_server.h b/net/tools/quic/test_tools/quic_test_server.h index 09e3141..a38923cc 100644 --- a/net/tools/quic/test_tools/quic_test_server.h +++ b/net/tools/quic/test_tools/quic_test_server.h
@@ -12,6 +12,7 @@ #include "net/quic/quic_session.h" #include "net/tools/quic/quic_dispatcher.h" #include "net/tools/quic/quic_server.h" +#include "net/tools/quic/quic_simple_server_session.h" #include "net/tools/quic/quic_simple_server_stream.h" namespace net { @@ -31,7 +32,7 @@ virtual ~SessionFactory() {} // Returns a new session owned by the caller. - virtual QuicServerSession* CreateSession( + virtual QuicServerSessionBase* CreateSession( const QuicConfig& config, QuicConnection* connection, QuicServerSessionVisitor* visitor, @@ -84,7 +85,7 @@ // Test session which sends a GOAWAY immedaitely on creation, before crypto // credentials have even been established. -class ImmediateGoAwaySession : public QuicServerSession { +class ImmediateGoAwaySession : public QuicSimpleServerSession { public: ImmediateGoAwaySession(const QuicConfig& config, QuicConnection* connection,
diff --git a/net/url_request/url_request_file_dir_job.cc b/net/url_request/url_request_file_dir_job.cc index 1dafbf2..b331e442 100644 --- a/net/url_request/url_request_file_dir_job.cc +++ b/net/url_request/url_request_file_dir_job.cc
@@ -12,8 +12,8 @@ #include "base/strings/utf_string_conversions.h" #include "base/thread_task_runner_handle.h" #include "base/time/time.h" +#include "net/base/directory_listing.h" #include "net/base/io_buffer.h" -#include "net/base/net_util.h" #include "net/url_request/url_request_status.h" #include "url/gurl.h"
diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc index eea6a69..78e44c9 100644 --- a/net/url_request/url_request_unittest.cc +++ b/net/url_request/url_request_unittest.cc
@@ -43,6 +43,7 @@ #include "base/thread_task_runner_handle.h" #include "base/values.h" #include "net/base/chunked_upload_data_stream.h" +#include "net/base/directory_listing.h" #include "net/base/elements_upload_data_stream.h" #include "net/base/external_estimate_provider.h" #include "net/base/load_flags.h"
diff --git a/net/websockets/websocket_channel.h b/net/websockets/websocket_channel.h index a5642704..114bb5e 100644 --- a/net/websockets/websocket_channel.h +++ b/net/websockets/websocket_channel.h
@@ -98,6 +98,12 @@ // processing to OnClosingHandshake() if necessary. void StartClosingHandshake(uint16_t code, const std::string& reason); + // Returns the current send quota. This value is unsafe to use outside of the + // browser IO thread because it changes asynchronously. The value is only + // valid for the execution of the current Task or until SendFrame() is called, + // whichever happens sooner. + int current_send_quota() const { return current_send_quota_; } + // Starts the connection process, using a specified creator callback rather // than the default. This is exposed for testing. void SendAddChannelRequestForTesting(
diff --git a/net/websockets/websocket_channel_test.cc b/net/websockets/websocket_channel_test.cc index 5413444..fabd81d7 100644 --- a/net/websockets/websocket_channel_test.cc +++ b/net/websockets/websocket_channel_test.cc
@@ -5,8 +5,8 @@ #include "net/websockets/websocket_channel.h" #include <limits.h> +#include <stddef.h> #include <string.h> - #include <iostream> #include <iterator> #include <string> @@ -3421,5 +3421,28 @@ completion.WaitForResult(); } +// Verify that current_send_quota() returns a non-zero value for a newly +// connected channel. +TEST_F(WebSocketChannelTest, CurrentSendQuotaNonZero) { + CreateChannelAndConnectSuccessfully(); + EXPECT_GT(channel_->current_send_quota(), 0); +} + +// Verify that current_send_quota() is updated when SendFrame() is called. +TEST_F(WebSocketChannelTest, CurrentSendQuotaUpdated) { + const int kMessageSize = 5; + set_stream(make_scoped_ptr(new WriteableFakeWebSocketStream)); + CreateChannelAndConnectSuccessfully(); + + int initial_send_quota = channel_->current_send_quota(); + EXPECT_GE(initial_send_quota, kMessageSize); + + channel_->SendFrame( + true, WebSocketFrameHeader::kOpCodeText, + std::vector<char>(static_cast<size_t>(kMessageSize), 'a')); + int new_send_quota = channel_->current_send_quota(); + EXPECT_EQ(kMessageSize, initial_send_quota - new_send_quota); +} + } // namespace } // namespace net
diff --git a/pdf/chunk_stream.cc b/pdf/chunk_stream.cc index bdb5399..adb3cb6 100644 --- a/pdf/chunk_stream.cc +++ b/pdf/chunk_stream.cc
@@ -35,7 +35,7 @@ stream_size_ = stream_size; } -size_t ChunkStream::GetSize() { +size_t ChunkStream::GetSize() const { return data_.size(); }
diff --git a/pdf/chunk_stream.h b/pdf/chunk_stream.h index 048f958..d2d8d2a1 100644 --- a/pdf/chunk_stream.h +++ b/pdf/chunk_stream.h
@@ -23,7 +23,7 @@ void Clear(); void Preallocate(size_t stream_size); - size_t GetSize(); + size_t GetSize() const; bool WriteData(size_t offset, void* buffer, size_t size); bool ReadData(size_t offset, size_t size, void* buffer) const;
diff --git a/pdf/out_of_process_instance.cc b/pdf/out_of_process_instance.cc index 875642f..869fdf24 100644 --- a/pdf/out_of_process_instance.cc +++ b/pdf/out_of_process_instance.cc
@@ -702,11 +702,11 @@ engine_->PrePaint(); - for (size_t i = 0; i < paint_rects.size(); i++) { + for (const auto& paint_rect : paint_rects) { // Intersect with plugin area since there could be pending invalidates from // when the plugin area was larger. pp::Rect rect = - paint_rects[i].Intersect(pp::Rect(pp::Point(), plugin_size_)); + paint_rect.Intersect(pp::Rect(pp::Point(), plugin_size_)); if (rect.IsEmpty()) continue; @@ -717,14 +717,14 @@ std::vector<pp::Rect> pdf_ready; std::vector<pp::Rect> pdf_pending; engine_->Paint(pdf_rect, &image_data_, &pdf_ready, &pdf_pending); - for (size_t j = 0; j < pdf_ready.size(); ++j) { - pdf_ready[j].Offset(available_area_.point()); + for (auto& ready_rect : pdf_ready) { + ready_rect.Offset(available_area_.point()); ready->push_back( - PaintManager::ReadyRect(pdf_ready[j], image_data_, false)); + PaintManager::ReadyRect(ready_rect, image_data_, false)); } - for (size_t j = 0; j < pdf_pending.size(); ++j) { - pdf_pending[j].Offset(available_area_.point()); - pending->push_back(pdf_pending[j]); + for (auto& pending_rect : pdf_pending) { + pending_rect.Offset(available_area_.point()); + pending->push_back(pending_rect); } } @@ -738,10 +738,10 @@ FillRect(region, background_color_); } - for (size_t j = 0; j < background_parts_.size(); ++j) { - pp::Rect intersection = background_parts_[j].location.Intersect(rect); + for (const auto& background_part : background_parts_) { + pp::Rect intersection = background_part.location.Intersect(rect); if (!intersection.IsEmpty()) { - FillRect(intersection, background_parts_[j].color); + FillRect(intersection, background_part.color); ready->push_back( PaintManager::ReadyRect(intersection, image_data_, false)); } @@ -922,8 +922,8 @@ const std::vector<pp::Rect>& tickmarks) { float inverse_scale = 1.0f / device_scale_; std::vector<pp::Rect> scaled_tickmarks = tickmarks; - for (size_t i = 0; i < scaled_tickmarks.size(); i++) - ScaleRect(inverse_scale, &scaled_tickmarks[i]); + for (auto& tickmark : scaled_tickmarks) + ScaleRect(inverse_scale, &tickmark); tickmarks_ = scaled_tickmarks; }
diff --git a/pdf/paint_aggregator.cc b/pdf/paint_aggregator.cc index c14dded8..50d77fe4 100644 --- a/pdf/paint_aggregator.cc +++ b/pdf/paint_aggregator.cc
@@ -105,15 +105,15 @@ // Include the scroll damage (if any) in the paint rects. // Code invalidates damaged rect here, it pick it up from the list of paint // rects in the next block. - if (ret.has_scroll && !update_.synthesized_scroll_damage_rect_) { + if (ret.has_scroll && !update_.synthesized_scroll_damage_rect_) { update_.synthesized_scroll_damage_rect_ = true; pp::Rect scroll_damage = update_.GetScrollDamage(); InvalidateRectInternal(scroll_damage, false); } ret.paint_rects.reserve(update_.paint_rects.size() + 1); - for (size_t i = 0; i < update_.paint_rects.size(); i++) - ret.paint_rects.push_back(update_.paint_rects[i]); + ret.paint_rects.insert(ret.paint_rects.end(), update_.paint_rects.begin(), + update_.paint_rects.end()); return ret; } @@ -217,14 +217,12 @@ } } - for (size_t i = 0; i < leftover_rects.size(); ++i) - InvalidateRectInternal(leftover_rects[i], false); + for (const auto& leftover_rect : leftover_rects) + InvalidateRectInternal(leftover_rect, false); - for (size_t i = 0; i < update_.ready_rects.size(); ++i) { - if (update_.scroll_rect.Contains(update_.ready_rects[i].rect)) { - update_.ready_rects[i].rect = - ScrollPaintRect(update_.ready_rects[i].rect, amount); - } + for (auto& update_rect : update_.ready_rects) { + if (update_.scroll_rect.Contains(update_rect.rect)) + update_rect.rect = ScrollPaintRect(update_rect.rect, amount); } if (update_.synthesized_scroll_damage_rect_) {
diff --git a/pdf/paint_manager.cc b/pdf/paint_manager.cc index b1f543d..226994c 100644 --- a/pdf/paint_manager.cc +++ b/pdf/paint_manager.cc
@@ -211,8 +211,7 @@ std::vector<PaintAggregator::ReadyRect> ready_now; if (pending.empty()) { std::vector<PaintAggregator::ReadyRect> temp_ready; - for (size_t i = 0; i < ready.size(); ++i) - temp_ready.push_back(ready[i]); + temp_ready.insert(temp_ready.end(), ready.begin(), ready.end()); aggregator_.SetIntermediateResults(temp_ready, pending); ready_now = aggregator_.GetReadyRects(); aggregator_.ClearPendingUpdate(); @@ -224,17 +223,17 @@ view_size_changed_waiting_for_paint_ = false; } else { std::vector<PaintAggregator::ReadyRect> ready_later; - for (size_t i = 0; i < ready.size(); ++i) { + for (const auto& ready_rect : ready) { // Don't flush any part (i.e. scrollbars) if we're resizing the browser, // as that'll lead to flashes. Until we flush, the browser will use the // previous image, but if we flush, it'll revert to using the blank image. // We make an exception for the first paint since we want to show the // default background color instead of the pepper default of black. - if (ready[i].flush_now && + if (ready_rect.flush_now && (!view_size_changed_waiting_for_paint_ || first_paint_)) { - ready_now.push_back(ready[i]); + ready_now.push_back(ready_rect); } else { - ready_later.push_back(ready[i]); + ready_later.push_back(ready_rect); } } // Take the rectangles, except the ones that need to be flushed right away, @@ -248,9 +247,9 @@ } } - for (size_t i = 0; i < ready_now.size(); ++i) { + for (const auto& ready_rect : ready_now) { graphics_.PaintImageData( - ready_now[i].image_data, ready_now[i].offset, ready_now[i].rect); + ready_rect.image_data, ready_rect.offset, ready_rect.rect); } int32_t result = graphics_.Flush(
diff --git a/pdf/pdfium/pdfium_engine.cc b/pdf/pdfium/pdfium_engine.cc index 4151bb2..10f11d12 100644 --- a/pdf/pdfium/pdfium_engine.cc +++ b/pdf/pdfium/pdfium_engine.cc
@@ -609,8 +609,8 @@ } PDFiumEngine::~PDFiumEngine() { - for (size_t i = 0; i < pages_.size(); ++i) - pages_[i]->Unload(); + for (auto& page : pages_) + page->Unload(); if (doc_) { FORM_DoDocumentAAction(form_, FPDFDOC_AACTION_WC); @@ -882,11 +882,9 @@ int file_flag, FPDF_WIDESTRING url, const char* mode) { - std::string url_str = "NULL"; - if (url != NULL) { - url_str = - base::UTF16ToUTF8(reinterpret_cast<const base::char16*>(url)); - } + std::string url_str = url ? + base::UTF16ToUTF8(reinterpret_cast<const base::char16*>(url)) : "NULL"; + // TODO: need to implement open file from the url // Use a file path for the ease of testing FILE* file = fopen(XFA_TESTFILE("tem.txt"), mode); @@ -978,8 +976,8 @@ } void PDFiumEngine::PrePaint() { - for (size_t i = 0; i < progressive_paints_.size(); ++i) - progressive_paints_[i].painted_ = false; + for (auto& paint : progressive_paints_) + paint.painted_ = false; } void PDFiumEngine::Paint(const pp::Rect& rect, @@ -1139,11 +1137,11 @@ // need to run the code below in that case. bool update_pages = false; std::vector<int> still_pending; - for (size_t i = 0; i < pending_pages_.size(); ++i) { - if (CheckPageAvailable(pending_pages_[i], &still_pending)) { + for (int pending_page : pending_pages_) { + if (CheckPageAvailable(pending_page, &still_pending)) { update_pages = true; - if (IsPageVisible(pending_pages_[i])) - client_->Invalidate(GetPageScreenRect(pending_pages_[i])); + if (IsPageVisible(pending_page)) + client_->Invalidate(GetPageScreenRect(pending_page)); } } pending_pages_.swap(still_pending); @@ -1280,8 +1278,8 @@ DCHECK(defer_page_unload_); defer_page_unload_ = false; - for (size_t i = 0; i < deferred_page_unloads_.size(); ++i) - pages_[deferred_page_unloads_[i]]->Unload(); + for (int page_index : deferred_page_unloads_) + pages_[page_index]->Unload(); deferred_page_unloads_.clear(); return rv; } @@ -1389,8 +1387,7 @@ // Collect pages to print and sizes of source pages. std::vector<uint32_t> page_numbers = GetPageNumbersFromPrintPageNumberRange(page_ranges, page_range_count); - for (size_t i = 0; i < page_numbers.size(); ++i) { - uint32_t page_number = page_numbers[i]; + for (uint32_t page_number : page_numbers) { FPDF_PAGE pdf_page = FPDF_LoadPage(doc_, page_number); double source_page_width = FPDF_GetPageWidth(pdf_page); double source_page_height = FPDF_GetPageHeight(pdf_page); @@ -1503,10 +1500,9 @@ std::vector<uint32_t> page_numbers = GetPageNumbersFromPrintPageNumberRange(page_ranges, page_range_count); - for (size_t i = 0; i < page_numbers.size(); ++i) { - uint32_t page_number = page_numbers[i]; + for (uint32_t page_number : page_numbers) { pages_[page_number]->GetPage(); - if (!IsPageVisible(page_numbers[i])) + if (!IsPageVisible(page_number)) pages_[page_number]->Unload(); } @@ -1569,9 +1565,9 @@ 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_in_page)) { - page = visible_pages_[i]; + for (int visible_page : visible_pages_) { + if (pages_[visible_page]->rect().Contains(point_in_page)) { + page = visible_page; break; } } @@ -1580,8 +1576,8 @@ // If the page hasn't finished rendering, calling into the page sometimes // leads to hangs. - for (size_t i = 0; i < progressive_paints_.size(); ++i) { - if (progressive_paints_[i].page_index == page) + for (const auto& paint : progressive_paints_) { + if (paint.page_index == page) return PDFiumPage::NONSELECTABLE_AREA; } @@ -1592,14 +1588,14 @@ bool PDFiumEngine::OnMouseDown(const pp::MouseInputEvent& event) { if (event.GetButton() == PP_INPUTEVENT_MOUSEBUTTON_RIGHT) { - if (!selection_.size()) + if (selection_.empty()) return false; std::vector<pp::Rect> selection_rect_vector; GetAllScreenRectsUnion(&selection_, GetVisibleRect().point(), &selection_rect_vector); pp::Point point = event.GetPosition(); - for (size_t i = 0; i < selection_rect_vector.size(); ++i) { - if (selection_rect_vector[i].Contains(point.x(), point.y())) + for (const auto& rect : selection_rect_vector) { + if (rect.Contains(point.x(), point.y())) return false; } SelectionChangeInvalidator selection_invalidator(this); @@ -1815,7 +1811,7 @@ } } - if (selection_.size() == 0) + if (selection_.empty()) return false; int last = selection_.size() - 1; @@ -2071,15 +2067,15 @@ std::vector<PDFEngine::Client::SearchStringResult> results; client_->SearchString( page_text.c_str(), term.c_str(), case_sensitive, &results); - for (size_t i = 0; i < results.size(); ++i) { + for (const auto& result : results) { // Need to map the indexes from the page text, which may have generated // characters like space etc, to character indices from the page. - int temp_start = results[i].start_index + character_to_start_searching_from; + int temp_start = result.start_index + character_to_start_searching_from; int start = FPDFText_GetCharIndexFromTextIndex( pages_[current_page]->GetTextPage(), temp_start); int end = FPDFText_GetCharIndexFromTextIndex( pages_[current_page]->GetTextPage(), - temp_start + results[i].length); + temp_start + result.length); AddFindResult(PDFiumRange(pages_[current_page], start, end - start)); } } @@ -2150,8 +2146,8 @@ std::vector<pp::Rect> rects; rects = find_results_[current_find_index_.GetIndex()].GetScreenRects( pp::Point(), 1.0, current_rotation_); - for (size_t i = 0; i < rects.size(); ++i) - bounding_rect = bounding_rect.Union(rects[i]); + for (const auto& rect : rects) + bounding_rect = bounding_rect.Union(rect); if (!visible_rect.Contains(bounding_rect)) { pp::Point center = bounding_rect.CenterPoint(); // Make the page centered. @@ -2193,14 +2189,13 @@ void PDFiumEngine::GetAllScreenRectsUnion(std::vector<PDFiumRange>* rect_range, const pp::Point& offset_point, std::vector<pp::Rect>* rect_vector) { - for (std::vector<PDFiumRange>::iterator it = rect_range->begin(); - it != rect_range->end(); ++it) { - pp::Rect rect; + for (auto& range : *rect_range) { + pp::Rect result_rect; std::vector<pp::Rect> rects = - it->GetScreenRects(offset_point, current_zoom_, current_rotation_); - for (size_t j = 0; j < rects.size(); ++j) - rect = rect.Union(rects[j]); - rect_vector->push_back(rect); + range.GetScreenRects(offset_point, current_zoom_, current_rotation_); + for (const auto& rect : rects) + result_rect = result_rect.Union(rect); + rect_vector->push_back(result_rect); } } @@ -2307,11 +2302,10 @@ SelectionChangeInvalidator selection_invalidator(this); selection_.clear(); - for (size_t i = 0; i < pages_.size(); ++i) - if (pages_[i]->available()) { - selection_.push_back(PDFiumRange(pages_[i], 0, - pages_[i]->GetCharCount())); - } + for (const auto& page : pages_) { + if (page->available()) + selection_.push_back(PDFiumRange(page, 0, page->GetCharCount())); + } } int PDFiumEngine::GetNumberOfPages() { @@ -2502,7 +2496,7 @@ if (doc_) return true; - const char* password_cstr = NULL; + const char* password_cstr = nullptr; if (with_password) { password_cstr = password.c_str(); password_tries_remaining_--; @@ -2515,7 +2509,7 @@ if (!doc_ && FPDF_GetLastError() == FPDF_ERR_PASSWORD) *needs_password = true; - return doc_ != NULL; + return !!doc_; } void PDFiumEngine::GetPasswordAndLoad() { @@ -2684,10 +2678,9 @@ // screen coordinates. form_highlights_.clear(); - int most_visible_page = visible_pages_.empty() ? 0 : visible_pages_.front(); - DCHECK_GE(most_visible_page, 0); + int most_visible_page = visible_pages_.empty() ? -1 : visible_pages_.front(); // Check if the next page is more visible than the first one. - if (!pages_.empty() && + if (most_visible_page != -1 && !pages_.empty() && most_visible_page < static_cast<int>(pages_.size()) - 1) { pp::Rect rc_first = visible_rect.Intersect(GetPageScreenRect(most_visible_page)); @@ -2701,12 +2694,7 @@ } bool PDFiumEngine::IsPageVisible(int index) const { - for (size_t i = 0; i < visible_pages_.size(); ++i) { - if (visible_pages_[i] == index) - return true; - } - - return false; + return ContainsValue(visible_pages_, index); } bool PDFiumEngine::CheckPageAvailable(int index, std::vector<int>* pending) { @@ -2835,9 +2823,9 @@ } void PDFiumEngine::CancelPaints() { - for (size_t i = 0; i < progressive_paints_.size(); ++i) { - FPDF_RenderPage_Close(pages_[progressive_paints_[i].page_index]->GetPage()); - FPDFBitmap_Destroy(progressive_paints_[i].bitmap); + for (const auto& paint : progressive_paints_) { + FPDF_RenderPage_Close(pages_[paint.page_index]->GetPage()); + FPDFBitmap_Destroy(paint.bitmap); } progressive_paints_.clear(); } @@ -2933,13 +2921,14 @@ std::vector<pp::Rect> highlighted_rects; pp::Rect visible_rect = GetVisibleRect(); - for (size_t k = 0; k < selection_.size(); ++k) { - if (selection_[k].page_index() != page_index) + for (auto& range : selection_) { + if (range.page_index() != page_index) continue; - std::vector<pp::Rect> rects = selection_[k].GetScreenRects( + + std::vector<pp::Rect> rects = range.GetScreenRects( visible_rect.point(), current_zoom_, current_rotation_); - for (size_t j = 0; j < rects.size(); ++j) { - pp::Rect visible_selection = rects[j].Intersect(dirty_in_screen); + for (const auto& rect : rects) { + pp::Rect visible_selection = rect.Intersect(dirty_in_screen); if (visible_selection.IsEmpty()) continue; @@ -2949,8 +2938,8 @@ } } - for (size_t k = 0; k < form_highlights_.size(); ++k) { - pp::Rect visible_selection = form_highlights_[k].Intersect(dirty_in_screen); + for (const auto& highlight : form_highlights_) { + pp::Rect visible_selection = highlight.Intersect(dirty_in_screen); if (visible_selection.IsEmpty()) continue; @@ -3060,8 +3049,8 @@ return; pp::Rect new_rect = rect; - for (size_t i = 0; i < highlighted_rects->size(); ++i) - new_rect = new_rect.Subtract((*highlighted_rects)[i]); + for (const auto& highlighted : *highlighted_rects) + new_rect = new_rect.Subtract(highlighted); highlighted_rects->push_back(new_rect); int l = new_rect.x(); @@ -3089,45 +3078,43 @@ PDFiumEngine::SelectionChangeInvalidator::~SelectionChangeInvalidator() { // Offset the old selections if the document scrolled since we recorded them. pp::Point offset = previous_origin_ - engine_->GetVisibleRect().point(); - for (size_t i = 0; i < old_selections_.size(); ++i) - old_selections_[i].Offset(offset); + for (auto& old_selection : old_selections_) + old_selection.Offset(offset); std::vector<pp::Rect> new_selections; GetVisibleSelectionsScreenRects(&new_selections); - for (size_t i = 0; i < new_selections.size(); ++i) { - for (size_t j = 0; j < old_selections_.size(); ++j) { - if (!old_selections_[j].IsEmpty() && - new_selections[i] == old_selections_[j]) { + for (auto& new_selection : new_selections) { + for (auto& old_selection : old_selections_) { + if (!old_selection.IsEmpty() && new_selection == old_selection) { // Rectangle was selected before and after, so no need to invalidate it. // Mark the rectangles by setting them to empty. - new_selections[i] = old_selections_[j] = pp::Rect(); + new_selection = old_selection = pp::Rect(); break; } } } - for (size_t i = 0; i < old_selections_.size(); ++i) { - if (!old_selections_[i].IsEmpty()) - engine_->client_->Invalidate(old_selections_[i]); + for (const auto& old_selection : old_selections_) { + if (!old_selection.IsEmpty()) + engine_->client_->Invalidate(old_selection); } - for (size_t i = 0; i < new_selections.size(); ++i) { - if (!new_selections[i].IsEmpty()) - engine_->client_->Invalidate(new_selections[i]); + for (const auto& new_selection : new_selections) { + if (!new_selection.IsEmpty()) + engine_->client_->Invalidate(new_selection); } engine_->OnSelectionChanged(); } -void -PDFiumEngine::SelectionChangeInvalidator::GetVisibleSelectionsScreenRects( +void PDFiumEngine::SelectionChangeInvalidator::GetVisibleSelectionsScreenRects( std::vector<pp::Rect>* rects) { pp::Rect visible_rect = engine_->GetVisibleRect(); - for (size_t i = 0; i < engine_->selection_.size(); ++i) { - int page_index = engine_->selection_[i].page_index(); + for (auto& range : engine_->selection_) { + int page_index = range.page_index(); if (!engine_->IsPageVisible(page_index)) continue; // This selection is on a page that's not currently visible. std::vector<pp::Rect> selection_rects = - engine_->selection_[i].GetScreenRects( + range.GetScreenRects( visible_rect.point(), engine_->current_zoom_, engine_->current_rotation_); @@ -3158,14 +3145,16 @@ bool PDFiumEngine::MouseDownState::Matches( const PDFiumPage::Area& area, const PDFiumPage::LinkTarget& target) const { - if (area_ == area) { - if (area == PDFiumPage::WEBLINK_AREA) - return target_.url == target.url; - if (area == PDFiumPage::DOCLINK_AREA) - return target_.page == target.page; - return true; - } - return false; + if (area_ != area) + return false; + + if (area == PDFiumPage::WEBLINK_AREA) + return target_.url == target.url; + + if (area == PDFiumPage::DOCLINK_AREA) + return target_.page == target.page; + + return true; } PDFiumEngine::FindTextIndex::FindTextIndex() @@ -3211,9 +3200,9 @@ } int PDFiumEngine::GetVisiblePageIndex(FPDF_PAGE page) { - for (size_t i = 0; i < visible_pages_.size(); ++i) { - if (pages_[visible_pages_[i]]->GetPage() == page) - return visible_pages_[i]; + for (int page_index : visible_pages_) { + if (pages_[page_index]->GetPage() == page) + return page_index; } return -1; }
diff --git a/pdf/pdfium/pdfium_page.cc b/pdf/pdfium/pdfium_page.cc index 5e0b192..95a8fba 100644 --- a/pdf/pdfium/pdfium_page.cc +++ b/pdf/pdfium/pdfium_page.cc
@@ -175,7 +175,7 @@ pp::Rect rect( PageToScreen(pp::Point(), 1.0, left, top, right, bottom, rotation)); GetLinks(rect, &targets); - area = targets.size() == 0 ? TEXT_AREA : WEBLINK_AREA; + area = targets.empty() ? TEXT_AREA : WEBLINK_AREA; } int char_index = FPDFText_GetCharIndexAtPos(GetTextPage(), left, top, @@ -198,17 +198,17 @@ text_nodes->Append(CreateURLNode(text_utf8, targets[0].url)); } else if (area == WEBLINK_AREA && !link) { size_t start = 0; - for (size_t i = 0; i < targets.size(); ++i) { + for (const auto& target : targets) { // If there is an extra NULL character at end, find() will not return any // matches. There should not be any though. - if (!targets[i].url.empty()) - DCHECK(targets[i].url[targets[i].url.size() - 1] != '\0'); + if (!target.url.empty()) + DCHECK_NE(target.url.back(), '\0'); // PDFium may change the case of generated links. - std::string lowerCaseURL = base::ToLowerASCII(targets[i].url); + std::string lowerCaseURL = base::ToLowerASCII(target.url); std::string lowerCaseText = base::ToLowerASCII(text_utf8); size_t pos = lowerCaseText.find(lowerCaseURL, start); - size_t length = targets[i].url.size(); + size_t length = target.url.size(); if (pos == std::string::npos) { // Check if the link is a "mailto:" URL if (lowerCaseURL.compare(0, 7, "mailto:") == 0) { @@ -223,15 +223,15 @@ } std::string before_text = text_utf8.substr(start, pos - start); - if (before_text.size() > 0) + if (!before_text.empty()) text_nodes->Append(CreateTextNode(before_text)); std::string link_text = text_utf8.substr(pos, length); - text_nodes->Append(CreateURLNode(link_text, targets[i].url)); + text_nodes->Append(CreateURLNode(link_text, target.url)); start = pos + length; } std::string before_text = text_utf8.substr(start); - if (before_text.size() > 0) + if (!before_text.empty()) text_nodes->Append(CreateTextNode(before_text)); } else { text_nodes->Append(CreateTextNode(text_utf8)); @@ -328,9 +328,9 @@ } PDFiumPage::Area PDFiumPage::GetLinkTarget( - FPDF_LINK link, PDFiumPage::LinkTarget* target) { + FPDF_LINK link, PDFiumPage::LinkTarget* target) const { FPDF_DEST dest = FPDFLink_GetDest(engine_->doc(), link); - if (dest != NULL) + if (dest) return GetDestinationTarget(dest, target); FPDF_ACTION action = FPDFLink_GetAction(link); @@ -368,11 +368,9 @@ } PDFiumPage::Area PDFiumPage::GetDestinationTarget( - FPDF_DEST destination, PDFiumPage::LinkTarget* target) { - int page_index = FPDFDest_GetPageIndex(engine_->doc(), destination); - if (target) { - target->page = page_index; - } + FPDF_DEST destination, PDFiumPage::LinkTarget* target) const { + if (target) + target->page = FPDFDest_GetPageIndex(engine_->doc(), destination); return DOCLINK_AREA; } @@ -390,8 +388,8 @@ pp::Point origin( PageToScreen(pp::Point(), 1.0, left, top, right, bottom, 0).point()); for (size_t i = 0; i < links_.size(); ++i) { - for (size_t j = 0; j < links_[i].rects.size(); ++j) { - if (links_[i].rects[j].Contains(origin)) { + for (const auto& rect : links_[i].rects) { + if (rect.Contains(origin)) { if (target) target->url = links_[i].url; return i; @@ -403,16 +401,15 @@ std::vector<int> PDFiumPage::GetLinks(pp::Rect text_area, std::vector<LinkTarget>* targets) { + std::vector<int> links; if (!available_) - return std::vector<int>(); + return links; CalculateLinks(); - std::vector<int> links; - for (size_t i = 0; i < links_.size(); ++i) { - for (size_t j = 0; j < links_[i].rects.size(); ++j) { - if (links_[i].rects[j].Intersects(text_area)) { + for (const auto& rect : links_[i].rects) { + if (rect.Intersects(text_area)) { if (targets) { LinkTarget target; target.url = links_[i].url; @@ -487,7 +484,7 @@ double top, double right, double bottom, - int rotation) { + int rotation) const { if (!available_) return pp::Rect();
diff --git a/pdf/pdfium/pdfium_page.h b/pdf/pdfium/pdfium_page.h index eee57e0f..da30504 100644 --- a/pdf/pdfium/pdfium_page.h +++ b/pdf/pdfium/pdfium_page.h
@@ -30,6 +30,7 @@ const pp::Rect& r, bool available); ~PDFiumPage(); + // Unloads the PDFium data for this page from memory. void Unload(); // Gets the FPDF_PAGE for this page, loading and parsing it if necessary. @@ -79,7 +80,7 @@ double top, double right, double bottom, - int rotation); + int rotation) const; int index() const { return index_; } pp::Rect rect() const { return rect_; } @@ -102,9 +103,9 @@ void CalculateLinks(); // Returns link type and target associated with a link. Returns // NONSELECTABLE_AREA if link detection failed. - Area GetLinkTarget(FPDF_LINK link, LinkTarget* target); + Area GetLinkTarget(FPDF_LINK link, LinkTarget* target) const; // Returns target associated with a destination. - Area GetDestinationTarget(FPDF_DEST destination, LinkTarget* target); + Area GetDestinationTarget(FPDF_DEST destination, LinkTarget* target) const; // Returns the text in the supplied box as a Value Node base::Value* GetTextBoxAsValue(double page_height, double left, double top, double right, double bottom, int rotation);
diff --git a/pdf/pdfium/pdfium_range.cc b/pdf/pdfium/pdfium_range.cc index b0474fc7..3b8371f 100644 --- a/pdf/pdfium/pdfium_range.cc +++ b/pdf/pdfium/pdfium_range.cc
@@ -57,7 +57,7 @@ return cached_screen_rects_; } -base::string16 PDFiumRange::GetText() { +base::string16 PDFiumRange::GetText() const { int index = char_index_; int count = char_count_; base::string16 rv;
diff --git a/pdf/pdfium/pdfium_range.h b/pdf/pdfium/pdfium_range.h index ed8daf65..a0f9ea1 100644 --- a/pdf/pdfium/pdfium_range.h +++ b/pdf/pdfium/pdfium_range.h
@@ -34,13 +34,13 @@ int rotation); // Gets the string of characters in this range. - base::string16 GetText(); + base::string16 GetText() const; private: PDFiumPage* page_; // Index of first character. int char_index_; - // How many characters are part of this range (negative if backwards). + // How many characters are part of this range (negative if backwards). int char_count_; // Cache of ScreenRect, and the associated variables used when caching it.
diff --git a/ppapi/lib/gl/include/GLES2/gl2ext.h b/ppapi/lib/gl/include/GLES2/gl2ext.h index d3dc0e5..130eea2 100644 --- a/ppapi/lib/gl/include/GLES2/gl2ext.h +++ b/ppapi/lib/gl/include/GLES2/gl2ext.h
@@ -1926,7 +1926,6 @@ #define glCopySubTextureCHROMIUM GLES2_GET_FUN(CopySubTextureCHROMIUM) #if !defined(GLES2_USE_CPP_BINDINGS) GL_APICALL void GL_APIENTRY glCopyTextureCHROMIUM( - GLenum target, GLenum source_id, GLenum dest_id, GLint internalformat, @@ -1935,7 +1934,6 @@ GLboolean unpack_premultiply_alpha, GLboolean unpack_unmultiply_alpha); GL_APICALL void GL_APIENTRY glCopySubTextureCHROMIUM( - GLenum target, GLenum source_id, GLenum dest_id, GLint xoffset, @@ -1950,7 +1948,6 @@ #endif #else typedef void(GL_APIENTRYP PFNGLCOPYTEXTURECHROMIUM)( - GLenum target, GLenum source_id, GLenum dest_id, GLint internalformat, @@ -1959,7 +1956,6 @@ GLboolean unpack_premultiply_alpha, GLboolean unpack_unmultiply_alpha); typedef void(GL_APIENTRYP PFNGLCOPYSUBTEXTURECHROMIUM)( - GLenum target, GLenum source_id, GLenum dest_id, GLint xoffset,
diff --git a/printing/cups_config_helper.py b/printing/cups_config_helper.py index 138a688..48cb3337 100755 --- a/printing/cups_config_helper.py +++ b/printing/cups_config_helper.py
@@ -22,8 +22,8 @@ import sys def usage(): - print 'usage: %s {--api-version|--cflags|--ldflags|--libs|--libs-for-gn}' % \ - sys.argv[0] + print ('usage: %s {--api-version|--cflags|--ldflags|--libs|--libs-for-gn} ' + '[sysroot]' % sys.argv[0]) def run_cups_config(cups_config, mode): @@ -63,7 +63,7 @@ return 1 mode = sys.argv[1] - if len(sys.argv) > 2: + if len(sys.argv) > 2 and sys.argv[2]: sysroot = sys.argv[2] cups_config = os.path.join(sysroot, 'usr', 'bin', 'cups-config') if not os.path.exists(cups_config):
diff --git a/remoting/client/chromoting_client.cc b/remoting/client/chromoting_client.cc index 9a9506fd..67973e26 100644 --- a/remoting/client/chromoting_client.cc +++ b/remoting/client/chromoting_client.cc
@@ -11,7 +11,6 @@ #include "remoting/client/audio_player.h" #include "remoting/client/client_context.h" #include "remoting/client/client_user_interface.h" -#include "remoting/client/video_renderer.h" #include "remoting/protocol/authenticator.h" #include "remoting/protocol/connection_to_host.h" #include "remoting/protocol/host_stub.h" @@ -20,12 +19,13 @@ #include "remoting/protocol/jingle_session_manager.h" #include "remoting/protocol/session_config.h" #include "remoting/protocol/transport_context.h" +#include "remoting/protocol/video_renderer.h" namespace remoting { ChromotingClient::ChromotingClient(ClientContext* client_context, ClientUserInterface* user_interface, - VideoRenderer* video_renderer, + protocol::VideoRenderer* video_renderer, scoped_ptr<AudioPlayer> audio_player) : user_interface_(user_interface), video_renderer_(video_renderer), @@ -67,7 +67,7 @@ connection_->set_client_stub(this); connection_->set_clipboard_stub(this); - connection_->set_video_stub(video_renderer_->GetVideoStub()); + connection_->set_video_renderer(video_renderer_); connection_->set_audio_stub(audio_decode_scheduler_.get()); session_manager_.reset(new protocol::JingleSessionManager(signal_strategy)); @@ -209,7 +209,6 @@ DCHECK(thread_checker_.CalledOnValidThread()); // Initialize the decoder. - video_renderer_->OnSessionConfig(connection_->config()); if (connection_->config().is_audio_enabled()) audio_decode_scheduler_->Initialize(connection_->config()); }
diff --git a/remoting/client/chromoting_client.h b/remoting/client/chromoting_client.h index dffbc5a..48cd5f9 100644 --- a/remoting/client/chromoting_client.h +++ b/remoting/client/chromoting_client.h
@@ -31,6 +31,7 @@ class CandidateSessionConfig; class SessionManager; class TransportContext; +class VideoRenderer; } // namespace protocol class AudioDecodeScheduler; @@ -38,8 +39,6 @@ class ClientContext; class ClientUserInterface; class FrameConsumerProxy; -class FrameProducer; -class VideoRenderer; class ChromotingClient : public SignalStrategy::Listener, public protocol::ConnectionToHost::HostEventCallback, @@ -50,7 +49,7 @@ // requested. ChromotingClient(ClientContext* client_context, ClientUserInterface* user_interface, - VideoRenderer* video_renderer, + protocol::VideoRenderer* video_renderer, scoped_ptr<AudioPlayer> audio_player); ~ChromotingClient() override; @@ -118,7 +117,7 @@ // The following are not owned by this class. ClientUserInterface* user_interface_ = nullptr; - VideoRenderer* video_renderer_ = nullptr; + protocol::VideoRenderer* video_renderer_ = nullptr; SignalStrategy* signal_strategy_ = nullptr; std::string host_jid_;
diff --git a/remoting/client/jni/chromoting_jni_instance.h b/remoting/client/jni/chromoting_jni_instance.h index 89e2bd2..044ac24 100644 --- a/remoting/client/jni/chromoting_jni_instance.h +++ b/remoting/client/jni/chromoting_jni_instance.h
@@ -27,13 +27,13 @@ class ClipboardEvent; class CursorShapeInfo; class PerformanceTracker; +class VideoRenderer; } // namespace protocol class ChromotingJniRuntime; class ClientStatusLogger; class JniFrameConsumer; class TokenFetcherProxy; -class VideoRenderer; // ClientUserInterface that indirectly makes and receives JNI calls. class ChromotingJniInstance @@ -154,7 +154,7 @@ scoped_ptr<ClientContext> client_context_; scoped_ptr<protocol::PerformanceTracker> perf_tracker_; scoped_ptr<JniFrameConsumer> view_; - scoped_ptr<VideoRenderer> video_renderer_; + scoped_ptr<protocol::VideoRenderer> video_renderer_; scoped_ptr<protocol::Authenticator> authenticator_; scoped_ptr<ChromotingClient> client_; XmppSignalStrategy::XmppServerConfig xmpp_config_;
diff --git a/remoting/client/jni/jni_frame_consumer.cc b/remoting/client/jni/jni_frame_consumer.cc index 25923da..066110c 100644 --- a/remoting/client/jni/jni_frame_consumer.cc +++ b/remoting/client/jni/jni_frame_consumer.cc
@@ -115,7 +115,7 @@ done.Run(); } -FrameConsumer::PixelFormat JniFrameConsumer::GetPixelFormat() { +protocol::FrameConsumer::PixelFormat JniFrameConsumer::GetPixelFormat() { return FORMAT_RGBA; }
diff --git a/remoting/client/jni/jni_frame_consumer.h b/remoting/client/jni/jni_frame_consumer.h index 5c72e9b..e635032d 100644 --- a/remoting/client/jni/jni_frame_consumer.h +++ b/remoting/client/jni/jni_frame_consumer.h
@@ -11,7 +11,7 @@ #include "base/macros.h" #include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" -#include "remoting/client/frame_consumer.h" +#include "remoting/protocol/frame_consumer.h" #include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h" namespace remoting { @@ -19,7 +19,7 @@ class ChromotingJniRuntime; // FrameConsumer implementation that draws onto a JNI direct byte buffer. -class JniFrameConsumer : public FrameConsumer { +class JniFrameConsumer : public protocol::FrameConsumer { public: // Does not take ownership of |jni_runtime|. explicit JniFrameConsumer(ChromotingJniRuntime* jni_runtime);
diff --git a/remoting/client/plugin/pepper_video_renderer.h b/remoting/client/plugin/pepper_video_renderer.h index bcf4f325..a5637bc 100644 --- a/remoting/client/plugin/pepper_video_renderer.h +++ b/remoting/client/plugin/pepper_video_renderer.h
@@ -5,7 +5,7 @@ #ifndef REMOTING_CLIENT_PLUGIN_PEPPER_VIDEO_RENDERER_H_ #define REMOTING_CLIENT_PLUGIN_PEPPER_VIDEO_RENDERER_H_ -#include "remoting/client/video_renderer.h" +#include "remoting/protocol/video_renderer.h" namespace webrtc { class DesktopSize; @@ -27,7 +27,7 @@ } // namespace protocol // Interface for video renderers that render video in pepper plugin. -class PepperVideoRenderer : public VideoRenderer { +class PepperVideoRenderer : public protocol::VideoRenderer { public: class EventHandler { public:
diff --git a/remoting/client/plugin/pepper_video_renderer_2d.cc b/remoting/client/plugin/pepper_video_renderer_2d.cc index 4e6e4ba..978335b 100644 --- a/remoting/client/plugin/pepper_video_renderer_2d.cc +++ b/remoting/client/plugin/pepper_video_renderer_2d.cc
@@ -114,6 +114,12 @@ return software_video_renderer_->GetVideoStub(); } +protocol::FrameConsumer* PepperVideoRenderer2D::GetFrameConsumer() { + DCHECK(thread_checker_.CalledOnValidThread()); + + return software_video_renderer_->GetFrameConsumer(); +} + scoped_ptr<webrtc::DesktopFrame> PepperVideoRenderer2D::AllocateFrame( const webrtc::DesktopSize& size) { DCHECK(thread_checker_.CalledOnValidThread()); @@ -187,7 +193,7 @@ Flush(); } -FrameConsumer::PixelFormat PepperVideoRenderer2D::GetPixelFormat() { +protocol::FrameConsumer::PixelFormat PepperVideoRenderer2D::GetPixelFormat() { return FORMAT_BGRA; }
diff --git a/remoting/client/plugin/pepper_video_renderer_2d.h b/remoting/client/plugin/pepper_video_renderer_2d.h index 6a17f4d..014ccec 100644 --- a/remoting/client/plugin/pepper_video_renderer_2d.h +++ b/remoting/client/plugin/pepper_video_renderer_2d.h
@@ -18,8 +18,8 @@ #include "ppapi/cpp/point.h" #include "ppapi/cpp/view.h" #include "ppapi/utility/completion_callback_factory.h" -#include "remoting/client/frame_consumer.h" #include "remoting/client/plugin/pepper_video_renderer.h" +#include "remoting/protocol/frame_consumer.h" #include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h" #include "third_party/webrtc/modules/desktop_capture/desktop_region.h" @@ -39,7 +39,7 @@ // Video renderer that wraps SoftwareVideoRenderer and displays it using Pepper // 2D graphics API. class PepperVideoRenderer2D : public PepperVideoRenderer, - public FrameConsumer { + public protocol::FrameConsumer { public: PepperVideoRenderer2D(); ~PepperVideoRenderer2D() override; @@ -55,9 +55,10 @@ // VideoRenderer interface. void OnSessionConfig(const protocol::SessionConfig& config) override; protocol::VideoStub* GetVideoStub() override; + protocol::FrameConsumer* GetFrameConsumer() override; private: - // FrameConsumer implementation. + // protocol::FrameConsumer implementation. scoped_ptr<webrtc::DesktopFrame> AllocateFrame( const webrtc::DesktopSize& size) override; void DrawFrame(scoped_ptr<webrtc::DesktopFrame> frame,
diff --git a/remoting/client/plugin/pepper_video_renderer_3d.cc b/remoting/client/plugin/pepper_video_renderer_3d.cc index 732b77b..4c22b14 100644 --- a/remoting/client/plugin/pepper_video_renderer_3d.cc +++ b/remoting/client/plugin/pepper_video_renderer_3d.cc
@@ -178,6 +178,13 @@ return this; } +protocol::FrameConsumer* PepperVideoRenderer3D::GetFrameConsumer() { + // GetFrameConsumer() is used only for WebRTC-based connections which are not + // supported by the plugin. + NOTREACHED(); + return nullptr; +} + void PepperVideoRenderer3D::ProcessVideoPacket(scoped_ptr<VideoPacket> packet, const base::Closure& done) { base::ScopedClosureRunner done_runner(done);
diff --git a/remoting/client/plugin/pepper_video_renderer_3d.h b/remoting/client/plugin/pepper_video_renderer_3d.h index 414cffa6..d7df94f 100644 --- a/remoting/client/plugin/pepper_video_renderer_3d.h +++ b/remoting/client/plugin/pepper_video_renderer_3d.h
@@ -45,6 +45,7 @@ // VideoRenderer interface. void OnSessionConfig(const protocol::SessionConfig& config) override; protocol::VideoStub* GetVideoStub() override; + protocol::FrameConsumer* GetFrameConsumer() override; // protocol::VideoStub interface. void ProcessVideoPacket(scoped_ptr<VideoPacket> packet,
diff --git a/remoting/client/software_video_renderer.cc b/remoting/client/software_video_renderer.cc index 9726cd5..2fa0fb2 100644 --- a/remoting/client/software_video_renderer.cc +++ b/remoting/client/software_video_renderer.cc
@@ -14,11 +14,11 @@ #include "base/single_thread_task_runner.h" #include "base/task_runner_util.h" #include "remoting/base/util.h" -#include "remoting/client/frame_consumer.h" #include "remoting/codec/video_decoder.h" #include "remoting/codec/video_decoder_verbatim.h" #include "remoting/codec/video_decoder_vpx.h" #include "remoting/proto/video.pb.h" +#include "remoting/protocol/frame_consumer.h" #include "remoting/protocol/session_config.h" #include "third_party/libyuv/include/libyuv/convert_argb.h" #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" @@ -72,7 +72,7 @@ SoftwareVideoRenderer::SoftwareVideoRenderer( scoped_refptr<base::SingleThreadTaskRunner> decode_task_runner, - FrameConsumer* consumer, + protocol::FrameConsumer* consumer, protocol::PerformanceTracker* perf_tracker) : decode_task_runner_(decode_task_runner), consumer_(consumer), @@ -100,7 +100,7 @@ NOTREACHED() << "Invalid Encoding found: " << codec; } - if (consumer_->GetPixelFormat() == FrameConsumer::FORMAT_RGBA) { + if (consumer_->GetPixelFormat() == protocol::FrameConsumer::FORMAT_RGBA) { decoder_ = make_scoped_ptr(new RgbToBgrVideoDecoderFilter(std::move(decoder_))); } @@ -111,6 +111,10 @@ return this; } +protocol::FrameConsumer* SoftwareVideoRenderer::GetFrameConsumer() { + return consumer_; +} + void SoftwareVideoRenderer::ProcessVideoPacket(scoped_ptr<VideoPacket> packet, const base::Closure& done) { DCHECK(thread_checker_.CalledOnValidThread());
diff --git a/remoting/client/software_video_renderer.h b/remoting/client/software_video_renderer.h index d67e3e5b..5951cf3 100644 --- a/remoting/client/software_video_renderer.h +++ b/remoting/client/software_video_renderer.h
@@ -12,8 +12,8 @@ #include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" #include "base/threading/thread_checker.h" -#include "remoting/client/video_renderer.h" #include "remoting/protocol/performance_tracker.h" +#include "remoting/protocol/video_renderer.h" #include "remoting/protocol/video_stub.h" #include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h" @@ -27,16 +27,16 @@ namespace remoting { -class FrameConsumer; class VideoDecoder; namespace protocol { +class FrameConsumer; class PerformanceTracker; } // namespace protocol // Implementation of VideoRenderer interface that decodes frame on CPU (on a // decode thread) and then passes decoded frames to a FrameConsumer. -class SoftwareVideoRenderer : public VideoRenderer, +class SoftwareVideoRenderer : public protocol::VideoRenderer, public protocol::VideoStub { public: // All methods must be called on the same thread the renderer is created. The @@ -45,13 +45,14 @@ // tracking is disabled in that case. SoftwareVideoRenderer( scoped_refptr<base::SingleThreadTaskRunner> decode_task_runner, - FrameConsumer* consumer, + protocol::FrameConsumer* consumer, protocol::PerformanceTracker* perf_tracker); ~SoftwareVideoRenderer() override; // VideoRenderer interface. void OnSessionConfig(const protocol::SessionConfig& config) override; protocol::VideoStub* GetVideoStub() override; + protocol::FrameConsumer* GetFrameConsumer() override; // protocol::VideoStub interface. void ProcessVideoPacket(scoped_ptr<VideoPacket> packet, @@ -64,7 +65,7 @@ void OnFrameRendered(int32_t frame_id, const base::Closure& done); scoped_refptr<base::SingleThreadTaskRunner> decode_task_runner_; - FrameConsumer* consumer_; + protocol::FrameConsumer* consumer_; protocol::PerformanceTracker* perf_tracker_; scoped_ptr<VideoDecoder> decoder_;
diff --git a/remoting/client/software_video_renderer_unittest.cc b/remoting/client/software_video_renderer_unittest.cc index d57e7b91..9b658fdb 100644 --- a/remoting/client/software_video_renderer_unittest.cc +++ b/remoting/client/software_video_renderer_unittest.cc
@@ -14,9 +14,9 @@ #include "base/message_loop/message_loop.h" #include "base/run_loop.h" #include "base/threading/thread.h" -#include "remoting/client/frame_consumer.h" #include "remoting/codec/video_encoder_verbatim.h" #include "remoting/proto/video.pb.h" +#include "remoting/protocol/frame_consumer.h" #include "remoting/protocol/session_config.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" @@ -30,7 +30,7 @@ const int kFrameWidth = 200; const int kFrameHeight = 200; -class TestFrameConsumer : public FrameConsumer { +class TestFrameConsumer : public protocol::FrameConsumer { public: TestFrameConsumer() {} ~TestFrameConsumer() override {}
diff --git a/remoting/client/video_renderer.h b/remoting/client/video_renderer.h deleted file mode 100644 index 8005168..0000000 --- a/remoting/client/video_renderer.h +++ /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. - -#ifndef REMOTING_CLIENT_VIDEO_RENDERER_H_ -#define REMOTING_CLIENT_VIDEO_RENDERER_H_ - -namespace remoting { - -namespace protocol { -class SessionConfig; -class VideoStub; -} // namespace protocol; - -// VideoRenderer is responsible for decoding and displaying incoming video -// stream. -class VideoRenderer { - public: - virtual ~VideoRenderer() {} - - // Configures the renderer with the supplied |config|. This must be called - // exactly once before video data is supplied to the renderer. - virtual void OnSessionConfig(const protocol::SessionConfig& config) = 0; - - // Returns the VideoStub interface of this renderer. - virtual protocol::VideoStub* GetVideoStub() = 0; -}; - -} // namespace remoting - -#endif // REMOTING_CLIENT_VIDEO_RENDERER_H_
diff --git a/remoting/host/installer/mac/Keystone/GoogleSoftwareUpdate.pkg b/remoting/host/installer/mac/Keystone/GoogleSoftwareUpdate.pkg index d4e4bd2..67bca5f 100644 --- a/remoting/host/installer/mac/Keystone/GoogleSoftwareUpdate.pkg +++ b/remoting/host/installer/mac/Keystone/GoogleSoftwareUpdate.pkg Binary files differ
diff --git a/remoting/protocol/BUILD.gn b/remoting/protocol/BUILD.gn index 14934aa..c9f30f37 100644 --- a/remoting/protocol/BUILD.gn +++ b/remoting/protocol/BUILD.gn
@@ -73,6 +73,8 @@ "fake_session.h", "fake_stream_socket.cc", "fake_stream_socket.h", + "fake_video_renderer.cc", + "fake_video_renderer.h", "protocol_mock_objects.cc", "protocol_mock_objects.h", ]
diff --git a/remoting/protocol/connection_to_host.h b/remoting/protocol/connection_to_host.h index d92905b..575f1da 100644 --- a/remoting/protocol/connection_to_host.h +++ b/remoting/protocol/connection_to_host.h
@@ -24,7 +24,7 @@ class SessionConfig; class TransportContext; struct TransportRoute; -class VideoStub; +class VideoRenderer; class ConnectionToHost { public: @@ -70,7 +70,7 @@ // is called. virtual void set_client_stub(ClientStub* client_stub) = 0; virtual void set_clipboard_stub(ClipboardStub* clipboard_stub) = 0; - virtual void set_video_stub(VideoStub* video_stub) = 0; + virtual void set_video_renderer(VideoRenderer* video_renderer) = 0; // If no audio stub is specified then audio will not be requested. virtual void set_audio_stub(AudioStub* audio_stub) = 0;
diff --git a/remoting/protocol/connection_unittest.cc b/remoting/protocol/connection_unittest.cc index b5be849..12624356 100644 --- a/remoting/protocol/connection_unittest.cc +++ b/remoting/protocol/connection_unittest.cc
@@ -10,6 +10,7 @@ #include "base/run_loop.h" #include "remoting/base/constants.h" #include "remoting/protocol/fake_session.h" +#include "remoting/protocol/fake_video_renderer.h" #include "remoting/protocol/ice_connection_to_client.h" #include "remoting/protocol/ice_connection_to_host.h" #include "remoting/protocol/protocol_mock_objects.h" @@ -38,6 +39,10 @@ arg.pressed() == event.pressed(); } +ACTION_P(QuitRunLoop, run_loop) { + run_loop->Quit(); +} + class MockConnectionToHostEventCallback : public ConnectionToHost::HostEventCallback { public: @@ -90,7 +95,7 @@ // Setup client side. client_connection_->set_client_stub(&client_stub_); client_connection_->set_clipboard_stub(&client_clipboard_stub_); - client_connection_->set_video_stub(&client_video_stub_); + client_connection_->set_video_renderer(&client_video_renderer_); } void Connect() { @@ -167,7 +172,7 @@ MockConnectionToHostEventCallback client_event_handler_; MockClientStub client_stub_; MockClipboardStub client_clipboard_stub_; - MockVideoStub client_video_stub_; + FakeVideoRenderer client_video_renderer_; scoped_ptr<ConnectionToHost> client_connection_; FakeSession* client_session_; // Owned by |client_connection_|. scoped_ptr<FakeSession> owned_client_session_; @@ -177,9 +182,7 @@ DISALLOW_COPY_AND_ASSIGN(ConnectionTest); }; -// TODO(sergeyu): Disabled due to failures on Vista bots. See -// https://crbug.com/573366. -// INSTANTIATE_TEST_CASE_P(Ice, ConnectionTest, ::testing::Values(false)); +INSTANTIATE_TEST_CASE_P(Ice, ConnectionTest, ::testing::Values(false)); INSTANTIATE_TEST_CASE_P(Webrtc, ConnectionTest, ::testing::Values(true)); TEST_P(ConnectionTest, RejectConnection) { @@ -213,13 +216,16 @@ Capabilities capabilities_msg; capabilities_msg.set_capabilities("test_capability"); + base::RunLoop run_loop; + EXPECT_CALL(client_stub_, - SetCapabilities(EqualsCapabilitiesMessage(capabilities_msg))); + SetCapabilities(EqualsCapabilitiesMessage(capabilities_msg))) + .WillOnce(QuitRunLoop(&run_loop)); // Send capabilities from the host. host_connection_->client_stub()->SetCapabilities(capabilities_msg); - base::RunLoop().RunUntilIdle(); + run_loop.Run(); } TEST_P(ConnectionTest, Events) { @@ -229,14 +235,17 @@ event.set_usb_keycode(3); event.set_pressed(true); + base::RunLoop run_loop; + EXPECT_CALL(host_event_handler_, OnInputEventReceived(host_connection_.get(), _)); - EXPECT_CALL(host_input_stub_, InjectKeyEvent(EqualsKeyEvent(event))); + EXPECT_CALL(host_input_stub_, InjectKeyEvent(EqualsKeyEvent(event))) + .WillOnce(QuitRunLoop(&run_loop)); // Send capabilities from the client. client_connection_->input_stub()->InjectKeyEvent(event); - base::RunLoop().RunUntilIdle(); + run_loop.Run(); } } // namespace protocol
diff --git a/remoting/protocol/fake_connection_to_host.cc b/remoting/protocol/fake_connection_to_host.cc index cbec7691f..36703ee 100644 --- a/remoting/protocol/fake_connection_to_host.cc +++ b/remoting/protocol/fake_connection_to_host.cc
@@ -19,7 +19,8 @@ void FakeConnectionToHost::set_clipboard_stub( protocol::ClipboardStub* clipboard_stub) {} -void FakeConnectionToHost::set_video_stub(protocol::VideoStub* video_stub) {} +void FakeConnectionToHost::set_video_renderer( + protocol::VideoRenderer* video_renderer) {} void FakeConnectionToHost::set_audio_stub(protocol::AudioStub* audio_stub) {}
diff --git a/remoting/protocol/fake_connection_to_host.h b/remoting/protocol/fake_connection_to_host.h index 62f93b1..082a95ff 100644 --- a/remoting/protocol/fake_connection_to_host.h +++ b/remoting/protocol/fake_connection_to_host.h
@@ -22,7 +22,7 @@ // ConnectionToHost interface. void set_client_stub(protocol::ClientStub* client_stub) override; void set_clipboard_stub(protocol::ClipboardStub* clipboard_stub) override; - void set_video_stub(protocol::VideoStub* video_stub) override; + void set_video_renderer(protocol::VideoRenderer* video_renderer) override; void set_audio_stub(protocol::AudioStub* audio_stub) override; void Connect(scoped_ptr<protocol::Session> session, scoped_refptr<protocol::TransportContext> transport_context,
diff --git a/remoting/protocol/fake_video_renderer.cc b/remoting/protocol/fake_video_renderer.cc new file mode 100644 index 0000000..faecf9b3 --- /dev/null +++ b/remoting/protocol/fake_video_renderer.cc
@@ -0,0 +1,40 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "remoting/protocol/fake_video_renderer.h" + +#include <utility> + +#include "base/callback.h" +#include "base/logging.h" +#include "remoting/proto/video.pb.h" + +namespace remoting { +namespace protocol { + +FakeVideoStub::FakeVideoStub() {} +FakeVideoStub::~FakeVideoStub() {} + +void FakeVideoStub::ProcessVideoPacket(scoped_ptr<VideoPacket> video_packet, + const base::Closure& done) { + received_packets_.push_back(std::move(video_packet)); + done.Run(); +} + +FakeVideoRenderer::FakeVideoRenderer() {} +FakeVideoRenderer::~FakeVideoRenderer() {} + +void FakeVideoRenderer::OnSessionConfig(const SessionConfig& config) {} + +FakeVideoStub* FakeVideoRenderer::GetVideoStub() { + return &video_stub_; +} + +FrameConsumer* FakeVideoRenderer::GetFrameConsumer() { + NOTIMPLEMENTED(); + return nullptr; +} + +} // namespace protocol +} // namespace remoting
diff --git a/remoting/protocol/fake_video_renderer.h b/remoting/protocol/fake_video_renderer.h new file mode 100644 index 0000000..a23f748 --- /dev/null +++ b/remoting/protocol/fake_video_renderer.h
@@ -0,0 +1,45 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef REMOTING_PROTOCOL_FAKE_VIDEO_RENDERER_H_ +#define REMOTING_PROTOCOL_FAKE_VIDEO_RENDERER_H_ + +#include <list> + +#include "remoting/protocol/video_renderer.h" +#include "remoting/protocol/video_stub.h" + +namespace remoting { +namespace protocol { + +class FakeVideoStub : public VideoStub { + public: + FakeVideoStub(); + ~FakeVideoStub() override; + + // VideoStub interface. + void ProcessVideoPacket(scoped_ptr<VideoPacket> video_packet, + const base::Closure& done) override; + private: + std::list<scoped_ptr<VideoPacket>> received_packets_; +}; + +class FakeVideoRenderer : public VideoRenderer { + public: + FakeVideoRenderer(); + ~FakeVideoRenderer() override; + + // VideoRenderer interface. + void OnSessionConfig(const SessionConfig& config) override; + FakeVideoStub* GetVideoStub() override; + FrameConsumer* GetFrameConsumer() override; + + private: + FakeVideoStub video_stub_; +}; + +} // namespace protocol +} // namespace remoting + +#endif // REMOTING_PROTOCOL_FAKE_VIDEO_RENDERER_H_
diff --git a/remoting/client/frame_consumer.h b/remoting/protocol/frame_consumer.h similarity index 78% rename from remoting/client/frame_consumer.h rename to remoting/protocol/frame_consumer.h index 792d2f6..87c8ca20 100644 --- a/remoting/client/frame_consumer.h +++ b/remoting/protocol/frame_consumer.h
@@ -1,21 +1,19 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Copyright 2016 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef REMOTING_CLIENT_FRAME_CONSUMER_H_ -#define REMOTING_CLIENT_FRAME_CONSUMER_H_ +#ifndef REMOTING_PROTOCOL_FRAME_CONSUMER_H_ +#define REMOTING_PROTOCOL_FRAME_CONSUMER_H_ #include "base/macros.h" namespace webrtc { class DesktopFrame; -class DesktopRect; -class DesktopRegion; class DesktopSize; -class DesktopVector; } // namespace webrtc namespace remoting { +namespace protocol { class FrameConsumer { public: @@ -42,6 +40,7 @@ DISALLOW_COPY_AND_ASSIGN(FrameConsumer); }; +} // namespace protocol } // namespace remoting -#endif // REMOTING_CLIENT_FRAME_CONSUMER_H_ +#endif // REMOTING_PROTOCOL_FRAME_CONSUMER_H_
diff --git a/remoting/protocol/ice_connection_to_host.cc b/remoting/protocol/ice_connection_to_host.cc index ddb77c73..28e5e62 100644 --- a/remoting/protocol/ice_connection_to_host.cc +++ b/remoting/protocol/ice_connection_to_host.cc
@@ -21,7 +21,7 @@ #include "remoting/protocol/errors.h" #include "remoting/protocol/ice_transport.h" #include "remoting/protocol/transport_context.h" -#include "remoting/protocol/video_stub.h" +#include "remoting/protocol/video_renderer.h" namespace remoting { namespace protocol { @@ -35,7 +35,7 @@ HostEventCallback* event_callback) { DCHECK(client_stub_); DCHECK(clipboard_stub_); - DCHECK(monitored_video_stub_); + DCHECK(video_renderer_); transport_.reset(new IceTransport(transport_context, this)); @@ -73,13 +73,10 @@ clipboard_stub_ = clipboard_stub; } -void IceConnectionToHost::set_video_stub(VideoStub* video_stub) { - DCHECK(video_stub); - monitored_video_stub_.reset(new MonitoredVideoStub( - video_stub, base::TimeDelta::FromSeconds( - MonitoredVideoStub::kConnectivityCheckDelaySeconds), - base::Bind(&IceConnectionToHost::OnVideoChannelStatus, - base::Unretained(this)))); +void IceConnectionToHost::set_video_renderer(VideoRenderer* video_renderer) { + DCHECK(video_renderer); + DCHECK(!monitored_video_stub_); + video_renderer_ = video_renderer; } void IceConnectionToHost::set_audio_stub(AudioStub* audio_stub) { @@ -101,19 +98,31 @@ case Session::AUTHENTICATED: SetState(AUTHENTICATED, OK); + + // Setup control channel. control_dispatcher_.reset(new ClientControlDispatcher()); control_dispatcher_->Init(transport_->GetMultiplexedChannelFactory(), this); control_dispatcher_->set_client_stub(client_stub_); control_dispatcher_->set_clipboard_stub(clipboard_stub_); + // Setup event channel. event_dispatcher_.reset(new ClientEventDispatcher()); event_dispatcher_->Init(transport_->GetMultiplexedChannelFactory(), this); + // Configure video pipeline. + video_renderer_->OnSessionConfig(session_->config()); + monitored_video_stub_.reset(new MonitoredVideoStub( + video_renderer_->GetVideoStub(), + base::TimeDelta::FromSeconds( + MonitoredVideoStub::kConnectivityCheckDelaySeconds), + base::Bind(&IceConnectionToHost::OnVideoChannelStatus, + base::Unretained(this)))); video_dispatcher_.reset( new ClientVideoDispatcher(monitored_video_stub_.get())); video_dispatcher_->Init(transport_->GetStreamChannelFactory(), this); + // Configure audio pipeline if necessary. if (session_->config().is_audio_enabled()) { audio_reader_.reset(new AudioReader(audio_stub_)); audio_reader_->Init(transport_->GetMultiplexedChannelFactory(), this);
diff --git a/remoting/protocol/ice_connection_to_host.h b/remoting/protocol/ice_connection_to_host.h index 6cc8e15..717106c3 100644 --- a/remoting/protocol/ice_connection_to_host.h +++ b/remoting/protocol/ice_connection_to_host.h
@@ -45,7 +45,7 @@ // ConnectionToHost interface. void set_client_stub(ClientStub* client_stub) override; void set_clipboard_stub(ClipboardStub* clipboard_stub) override; - void set_video_stub(VideoStub* video_stub) override; + void set_video_renderer(VideoRenderer* video_renderer) override; void set_audio_stub(AudioStub* audio_stub) override; void Connect(scoped_ptr<Session> session, scoped_refptr<TransportContext> transport_context, @@ -87,6 +87,7 @@ // Stub for incoming messages. ClientStub* client_stub_ = nullptr; ClipboardStub* clipboard_stub_ = nullptr; + VideoRenderer* video_renderer_ = nullptr; AudioStub* audio_stub_ = nullptr; scoped_ptr<Session> session_;
diff --git a/remoting/protocol/ice_transport_channel.cc b/remoting/protocol/ice_transport_channel.cc index 45919ab..75413d7 100644 --- a/remoting/protocol/ice_transport_channel.cc +++ b/remoting/protocol/ice_transport_channel.cc
@@ -110,8 +110,6 @@ this, &IceTransportChannel::OnCandidateGathered); channel_->SignalRouteChange.connect( this, &IceTransportChannel::OnRouteChange); - channel_->SignalReceivingState.connect( - this, &IceTransportChannel::OnReceivingState); channel_->SignalWritableState.connect( this, &IceTransportChannel::OnWritableState); channel_->set_incoming_only(!(transport_context_->network_settings().flags & @@ -137,6 +135,10 @@ reconnect_timer_.Start( FROM_HERE, base::TimeDelta::FromSeconds(kReconnectDelaySeconds), this, &IceTransportChannel::TryReconnect); + + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::Bind(&IceTransportChannel::NotifyConnected, + weak_factory_.GetWeakPtr())); } void IceTransportChannel::NotifyConnected() { @@ -202,13 +204,6 @@ NotifyRouteChanged(); } -void IceTransportChannel::OnReceivingState(cricket::TransportChannel* channel) { - DCHECK_EQ(channel, static_cast<cricket::TransportChannel*>(channel_.get())); - - if (channel->receiving() && !callback_.is_null()) - NotifyConnected(); -} - void IceTransportChannel::OnWritableState(cricket::TransportChannel* channel) { DCHECK_EQ(channel, static_cast<cricket::TransportChannel*>(channel_.get()));
diff --git a/remoting/protocol/ice_transport_channel.h b/remoting/protocol/ice_transport_channel.h index 08acad99..ca69d1f 100644 --- a/remoting/protocol/ice_transport_channel.h +++ b/remoting/protocol/ice_transport_channel.h
@@ -95,7 +95,6 @@ const cricket::Candidate& candidate); void OnRouteChange(cricket::TransportChannel* channel, const cricket::Candidate& candidate); - void OnReceivingState(cricket::TransportChannel* channel); void OnWritableState(cricket::TransportChannel* channel); // Callback for TransportChannelSocketAdapter to notify when the socket is
diff --git a/remoting/protocol/video_renderer.h b/remoting/protocol/video_renderer.h new file mode 100644 index 0000000..85ccb0d --- /dev/null +++ b/remoting/protocol/video_renderer.h
@@ -0,0 +1,39 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef REMOTING_CLIENT_VIDEO_RENDERER_H_ +#define REMOTING_CLIENT_VIDEO_RENDERER_H_ + +namespace remoting { +namespace protocol { + +class FrameConsumer; +class SessionConfig; +class VideoStub; + +// VideoRenderer is responsible for decoding and displaying incoming video +// stream. This interface is used by ConnectionToHost implementations to +// render received video frames. ConnectionToHost may feed encoded frames to the +// VideoStub or decode them and pass decoded frames to the FrameConsumer. +// +// TODO(sergeyu): Reconsider this design. +class VideoRenderer { + public: + virtual ~VideoRenderer() {} + + // Configures the renderer with the supplied |config|. This must be called + // exactly once before video data is supplied to the renderer. + virtual void OnSessionConfig(const SessionConfig& config) = 0; + + // Returns the VideoStub interface of this renderer. + virtual VideoStub* GetVideoStub() = 0; + + // Returns the FrameConsumer interface for this renderer. + virtual FrameConsumer* GetFrameConsumer() = 0; +}; + +} // namespace protocol; +} // namespace remoting + +#endif // REMOTING_CLIENT_VIDEO_RENDERER_H_
diff --git a/remoting/protocol/webrtc_connection_to_client.cc b/remoting/protocol/webrtc_connection_to_client.cc index 9d732e0..3f31804 100644 --- a/remoting/protocol/webrtc_connection_to_client.cc +++ b/remoting/protocol/webrtc_connection_to_client.cc
@@ -147,20 +147,9 @@ case Session::AUTHENTICATING: event_handler_->OnConnectionAuthenticating(this); break; - case Session::AUTHENTICATED: { - // Initialize channels. - control_dispatcher_->Init(transport_.GetStreamChannelFactory(), this); - - event_dispatcher_->Init(transport_.GetStreamChannelFactory(), this); - event_dispatcher_->set_on_input_event_callback(base::Bind( - &ConnectionToClient::OnInputEventReceived, base::Unretained(this))); - - // Notify the handler after initializing the channels, so that - // ClientSession can get a client clipboard stub. + case Session::AUTHENTICATED: event_handler_->OnConnectionAuthenticated(this); break; - } - case Session::CLOSED: case Session::FAILED: control_dispatcher_.reset(); @@ -171,7 +160,16 @@ } } +void WebrtcConnectionToClient::OnWebrtcTransportConnecting() { + control_dispatcher_->Init(transport_.outgoing_channel_factory(), this); + + event_dispatcher_->Init(transport_.incoming_channel_factory(), this); + event_dispatcher_->set_on_input_event_callback(base::Bind( + &ConnectionToClient::OnInputEventReceived, base::Unretained(this))); +} + void WebrtcConnectionToClient::OnWebrtcTransportConnected() { + DCHECK(thread_checker_.CalledOnValidThread()); event_handler_->OnConnectionChannelsConnected(this); }
diff --git a/remoting/protocol/webrtc_connection_to_client.h b/remoting/protocol/webrtc_connection_to_client.h index 39e2433..1786374 100644 --- a/remoting/protocol/webrtc_connection_to_client.h +++ b/remoting/protocol/webrtc_connection_to_client.h
@@ -51,6 +51,7 @@ void OnSessionStateChange(Session::State state) override; // WebrtcTransport::EventHandler interface + void OnWebrtcTransportConnecting() override; void OnWebrtcTransportConnected() override; void OnWebrtcTransportError(ErrorCode error) override;
diff --git a/remoting/protocol/webrtc_connection_to_host.cc b/remoting/protocol/webrtc_connection_to_host.cc index 43b7a4f8..9733163a 100644 --- a/remoting/protocol/webrtc_connection_to_host.cc +++ b/remoting/protocol/webrtc_connection_to_host.cc
@@ -63,7 +63,7 @@ clipboard_stub_ = clipboard_stub; } -void WebrtcConnectionToHost::set_video_stub(VideoStub* video_stub) { +void WebrtcConnectionToHost::set_video_renderer(VideoRenderer* video_renderer) { NOTIMPLEMENTED(); } @@ -85,14 +85,6 @@ case Session::AUTHENTICATED: SetState(AUTHENTICATED, OK); - - control_dispatcher_.reset(new ClientControlDispatcher()); - control_dispatcher_->Init(transport_->GetStreamChannelFactory(), this); - control_dispatcher_->set_client_stub(client_stub_); - control_dispatcher_->set_clipboard_stub(clipboard_stub_); - - event_dispatcher_.reset(new ClientEventDispatcher()); - event_dispatcher_->Init(transport_->GetStreamChannelFactory(), this); break; case Session::CLOSED: @@ -103,6 +95,16 @@ } } +void WebrtcConnectionToHost::OnWebrtcTransportConnecting() { + control_dispatcher_.reset(new ClientControlDispatcher()); + control_dispatcher_->Init(transport_->incoming_channel_factory(), this); + control_dispatcher_->set_client_stub(client_stub_); + control_dispatcher_->set_clipboard_stub(clipboard_stub_); + + event_dispatcher_.reset(new ClientEventDispatcher()); + event_dispatcher_->Init(transport_->outgoing_channel_factory(), this); +} + void WebrtcConnectionToHost::OnWebrtcTransportConnected() {} void WebrtcConnectionToHost::OnWebrtcTransportError(ErrorCode error) {
diff --git a/remoting/protocol/webrtc_connection_to_host.h b/remoting/protocol/webrtc_connection_to_host.h index 79b97e06..030adcc 100644 --- a/remoting/protocol/webrtc_connection_to_host.h +++ b/remoting/protocol/webrtc_connection_to_host.h
@@ -35,7 +35,7 @@ // ConnectionToHost interface. void set_client_stub(ClientStub* client_stub) override; void set_clipboard_stub(ClipboardStub* clipboard_stub) override; - void set_video_stub(VideoStub* video_stub) override; + void set_video_renderer(VideoRenderer* video_renderer) override; void set_audio_stub(AudioStub* audio_stub) override; void Connect(scoped_ptr<Session> session, scoped_refptr<TransportContext> transport_context, @@ -51,6 +51,7 @@ void OnSessionStateChange(Session::State state) override; // WebrtcTransport::EventHandler interface. + void OnWebrtcTransportConnecting() override; void OnWebrtcTransportConnected() override; void OnWebrtcTransportError(ErrorCode error) override;
diff --git a/remoting/protocol/webrtc_data_stream_adapter.cc b/remoting/protocol/webrtc_data_stream_adapter.cc index 8658f56..845f1fec 100644 --- a/remoting/protocol/webrtc_data_stream_adapter.cc +++ b/remoting/protocol/webrtc_data_stream_adapter.cc
@@ -204,32 +204,24 @@ } } -WebrtcDataStreamAdapter::WebrtcDataStreamAdapter() : weak_factory_(this) {} +WebrtcDataStreamAdapter::WebrtcDataStreamAdapter(bool outgoing) + : outgoing_(outgoing), weak_factory_(this) {} WebrtcDataStreamAdapter::~WebrtcDataStreamAdapter() { DCHECK(pending_channels_.empty()); } void WebrtcDataStreamAdapter::Initialize( - rtc::scoped_refptr<webrtc::PeerConnectionInterface> peer_connection, - bool outgoing) { + rtc::scoped_refptr<webrtc::PeerConnectionInterface> peer_connection) { peer_connection_ = peer_connection; - outgoing_ = outgoing; - - if (outgoing_) { - for (auto& channel : pending_channels_) { - webrtc::DataChannelInit config; - config.reliable = true; - channel.second->Start( - peer_connection_->CreateDataChannel(channel.first, &config)); - } - } } void WebrtcDataStreamAdapter::OnIncomingDataChannel( webrtc::DataChannelInterface* data_channel) { + DCHECK(!outgoing_); + auto it = pending_channels_.find(data_channel->label()); - if (outgoing_ || it == pending_channels_.end()) { + if (it == pending_channels_.end()) { LOG(ERROR) << "Received unexpected data channel " << data_channel->label(); return; } @@ -239,6 +231,7 @@ void WebrtcDataStreamAdapter::CreateChannel( const std::string& name, const ChannelCreatedCallback& callback) { + DCHECK(peer_connection_); DCHECK(pending_channels_.find(name) == pending_channels_.end()); Channel* channel = @@ -246,7 +239,7 @@ base::Unretained(this), callback)); pending_channels_[name] = channel; - if (peer_connection_ && outgoing_) { + if (outgoing_) { webrtc::DataChannelInit config; config.reliable = true; channel->Start(peer_connection_->CreateDataChannel(name, &config));
diff --git a/remoting/protocol/webrtc_data_stream_adapter.h b/remoting/protocol/webrtc_data_stream_adapter.h index fc7e42f..f669e8f7 100644 --- a/remoting/protocol/webrtc_data_stream_adapter.h +++ b/remoting/protocol/webrtc_data_stream_adapter.h
@@ -24,15 +24,14 @@ // send and receive data over PeerConnection data channels. class WebrtcDataStreamAdapter : public StreamChannelFactory { public: - WebrtcDataStreamAdapter(); + explicit WebrtcDataStreamAdapter(bool outgoing); ~WebrtcDataStreamAdapter() override; // Initializes the adapter for |peer_connection|. If |outgoing| is set to true // all channels will be created as outgoing. Otherwise CreateChannel() will // wait for the other end to create connection. void Initialize( - rtc::scoped_refptr<webrtc::PeerConnectionInterface> peer_connection, - bool outgoing); + rtc::scoped_refptr<webrtc::PeerConnectionInterface> peer_connection); // Called by WebrtcTransport. void OnIncomingDataChannel(webrtc::DataChannelInterface* data_channel); @@ -49,8 +48,9 @@ Channel* channel, bool connected); + const bool outgoing_; + rtc::scoped_refptr<webrtc::PeerConnectionInterface> peer_connection_; - bool outgoing_ = false; std::map<std::string, Channel*> pending_channels_;
diff --git a/remoting/protocol/webrtc_transport.cc b/remoting/protocol/webrtc_transport.cc index 59711e0..0950e7c 100644 --- a/remoting/protocol/webrtc_transport.cc +++ b/remoting/protocol/webrtc_transport.cc
@@ -110,6 +110,8 @@ : worker_thread_(worker_thread), transport_context_(transport_context), event_handler_(event_handler), + outgoing_data_stream_adapter_(true), + incoming_data_stream_adapter_(false), weak_factory_(this) {} WebrtcTransport::~WebrtcTransport() {} @@ -155,8 +157,10 @@ rtc::scoped_ptr<cricket::PortAllocator>(port_allocator.release()), nullptr, this); - data_stream_adapter_.Initialize( - peer_connection_, transport_context_->role() == TransportRole::SERVER); + outgoing_data_stream_adapter_.Initialize(peer_connection_); + incoming_data_stream_adapter_.Initialize(peer_connection_); + + event_handler_->OnWebrtcTransportConnecting(); if (transport_context_->role() == TransportRole::SERVER) RequestNegotiation(); @@ -248,11 +252,6 @@ return true; } -StreamChannelFactory* WebrtcTransport::GetStreamChannelFactory() { - DCHECK(thread_checker_.CalledOnValidThread()); - return &data_stream_adapter_; -} - void WebrtcTransport::OnLocalSessionDescriptionCreated( scoped_ptr<webrtc::SessionDescriptionInterface> description, const std::string& error) { @@ -363,7 +362,7 @@ void WebrtcTransport::OnDataChannel( webrtc::DataChannelInterface* data_channel) { DCHECK(thread_checker_.CalledOnValidThread()); - data_stream_adapter_.OnIncomingDataChannel(data_channel); + incoming_data_stream_adapter_.OnIncomingDataChannel(data_channel); } void WebrtcTransport::OnRenegotiationNeeded() { @@ -393,8 +392,11 @@ webrtc::PeerConnectionInterface::IceConnectionState new_state) { DCHECK(thread_checker_.CalledOnValidThread()); - if (new_state == webrtc::PeerConnectionInterface::kIceConnectionConnected) + if (!connected_ && + new_state == webrtc::PeerConnectionInterface::kIceConnectionConnected) { + connected_ = true; event_handler_->OnWebrtcTransportConnected(); + } } void WebrtcTransport::OnIceGatheringChange(
diff --git a/remoting/protocol/webrtc_transport.h b/remoting/protocol/webrtc_transport.h index a000029..d11bfa78 100644 --- a/remoting/protocol/webrtc_transport.h +++ b/remoting/protocol/webrtc_transport.h
@@ -32,6 +32,14 @@ public: class EventHandler { public: + // Called after |peer_connection| has been created but before handshake. The + // handler should create data channels and media streams. Renegotiation will + // be required in two cases after this method returns: + // 1. When the first data channel is created, if it wasn't created by this + // event handler. + // 2. Whenever a media stream is added or removed. + virtual void OnWebrtcTransportConnecting() = 0; + // Called when the transport is connected. virtual void OnWebrtcTransportConnected() = 0; @@ -51,7 +59,14 @@ return peer_connection_factory_; } - StreamChannelFactory* GetStreamChannelFactory(); + // Factories for outgoing and incoming data channels. Must be used only after + // the transport is connected. + StreamChannelFactory* outgoing_channel_factory() { + return &outgoing_data_stream_adapter_; + } + StreamChannelFactory* incoming_channel_factory() { + return &incoming_data_stream_adapter_; + } // Transport interface. void Start(Authenticator* authenticator, @@ -106,6 +121,8 @@ bool negotiation_pending_ = false; + bool connected_ = false; + scoped_ptr<buzz::XmlElement> pending_transport_info_message_; base::OneShotTimer transport_info_timer_; @@ -114,7 +131,8 @@ std::list<rtc::scoped_refptr<webrtc::MediaStreamInterface>> unclaimed_streams_; - WebrtcDataStreamAdapter data_stream_adapter_; + WebrtcDataStreamAdapter outgoing_data_stream_adapter_; + WebrtcDataStreamAdapter incoming_data_stream_adapter_; base::WeakPtrFactory<WebrtcTransport> weak_factory_;
diff --git a/remoting/protocol/webrtc_transport_unittest.cc b/remoting/protocol/webrtc_transport_unittest.cc index 4c70e1f..737f2914f 100644 --- a/remoting/protocol/webrtc_transport_unittest.cc +++ b/remoting/protocol/webrtc_transport_unittest.cc
@@ -36,8 +36,11 @@ TestTransportEventHandler() {} ~TestTransportEventHandler() {} - // Both callbacks must be set before the test handler is passed to a Transport + // All callbacks must be set before the test handler is passed to a Transport // object. + void set_connecting_callback(const base::Closure& callback) { + connecting_callback_ = callback; + } void set_connected_callback(const base::Closure& callback) { connected_callback_ = callback; } @@ -46,14 +49,20 @@ } // WebrtcTransport::EventHandler interface. + void OnWebrtcTransportConnecting() override { + if (!connecting_callback_.is_null()) + connecting_callback_.Run(); + } void OnWebrtcTransportConnected() override { - connected_callback_.Run(); + if (!connected_callback_.is_null()) + connected_callback_.Run(); } void OnWebrtcTransportError(ErrorCode error) override { error_callback_.Run(error); } private: + base::Closure connecting_callback_; base::Closure connected_callback_; ErrorCallback error_callback_; @@ -70,6 +79,15 @@ NetworkSettings(NetworkSettings::NAT_TRAVERSAL_OUTGOING); } + void TearDown() override { + run_loop_.reset(); + client_socket_.reset(); + client_transport_.reset(); + host_socket_.reset(); + host_transport_.reset(); + base::RunLoop().RunUntilIdle(); + } + void ProcessTransportInfo(scoped_ptr<WebrtcTransport>* target_transport, scoped_ptr<buzz::XmlElement> transport_info) { ASSERT_TRUE(target_transport); @@ -77,7 +95,6 @@ ->ProcessTransportInfo(transport_info.get())); } - protected: void InitializeConnection() { host_transport_.reset( new WebrtcTransport(jingle_glue::JingleThreadWrapper::current(), @@ -126,14 +143,20 @@ run_loop_.reset(new base::RunLoop()); run_loop_->Run(); + host_event_handler_.set_connected_callback(base::Closure()); + client_event_handler_.set_connected_callback(base::Closure()); + EXPECT_EQ(OK, error_); } - void CreateDataStream() { - client_transport_->GetStreamChannelFactory()->CreateChannel( + void CreateClientDataStream() { + client_transport_->incoming_channel_factory()->CreateChannel( kChannelName, base::Bind(&WebrtcTransportTest::OnClientChannelCreated, base::Unretained(this))); - host_transport_->GetStreamChannelFactory()->CreateChannel( + } + + void CreateHostDataStream() { + host_transport_->outgoing_channel_factory()->CreateChannel( kChannelName, base::Bind(&WebrtcTransportTest::OnHostChannelCreated, base::Unretained(this))); } @@ -188,13 +211,20 @@ } TEST_F(WebrtcTransportTest, DataStream) { + client_event_handler_.set_connecting_callback(base::Bind( + &WebrtcTransportTest::CreateClientDataStream, base::Unretained(this))); + host_event_handler_.set_connecting_callback(base::Bind( + &WebrtcTransportTest::CreateHostDataStream, base::Unretained(this))); + InitializeConnection(); - CreateDataStream(); StartConnection(); run_loop_.reset(new base::RunLoop()); run_loop_->Run(); + EXPECT_TRUE(client_socket_); + EXPECT_TRUE(host_socket_); + const int kMessageSize = 1024; const int kMessages = 100; StreamConnectionTester tester(host_socket_.get(), client_socket_.get(), @@ -204,5 +234,21 @@ tester.CheckResults(); } +// Verify that data streams can be created after connection has been initiated. +TEST_F(WebrtcTransportTest, DataStreamLate) { + InitializeConnection(); + StartConnection(); + WaitUntilConnected(); + + CreateClientDataStream(); + CreateHostDataStream(); + + run_loop_.reset(new base::RunLoop()); + run_loop_->Run(); + + EXPECT_TRUE(client_socket_); + EXPECT_TRUE(host_socket_); +} + } // namespace protocol } // namespace remoting
diff --git a/remoting/remoting_srcs.gypi b/remoting/remoting_srcs.gypi index bfc279a..656b4e2 100644 --- a/remoting/remoting_srcs.gypi +++ b/remoting/remoting_srcs.gypi
@@ -108,6 +108,7 @@ 'protocol/datagram_channel_factory.h', 'protocol/errors.cc', 'protocol/errors.h', + 'protocol/frame_consumer.h', 'protocol/host_control_dispatcher.cc', 'protocol/host_control_dispatcher.h', 'protocol/host_event_dispatcher.cc', @@ -196,6 +197,7 @@ 'protocol/transport_context.h', 'protocol/v2_authenticator.cc', 'protocol/v2_authenticator.h', + 'protocol/video_renderer.h', 'protocol/video_stub.h', ], @@ -262,7 +264,6 @@ 'client/client_user_interface.h', 'client/empty_cursor_filter.cc', 'client/empty_cursor_filter.h', - 'client/frame_consumer.h', 'client/key_event_mapper.cc', 'client/key_event_mapper.h', 'client/normalizing_input_filter_cros.cc', @@ -279,7 +280,6 @@ 'client/token_fetcher_proxy.h', 'client/touch_input_scaler.cc', 'client/touch_input_scaler.h', - 'client/video_renderer.h', ], 'remoting_client_plugin_sources': [
diff --git a/remoting/remoting_test.gypi b/remoting/remoting_test.gypi index 7f86751..fe8edf4 100644 --- a/remoting/remoting_test.gypi +++ b/remoting/remoting_test.gypi
@@ -44,6 +44,8 @@ 'protocol/fake_session.h', 'protocol/fake_stream_socket.cc', 'protocol/fake_stream_socket.h', + 'protocol/fake_video_renderer.cc', + 'protocol/fake_video_renderer.h', 'protocol/protocol_mock_objects.cc', 'protocol/protocol_mock_objects.h', 'protocol/test_event_matchers.h',
diff --git a/remoting/test/protocol_perftest.cc b/remoting/test/protocol_perftest.cc index 91b3eaa..bbafe94 100644 --- a/remoting/test/protocol_perftest.cc +++ b/remoting/test/protocol_perftest.cc
@@ -21,7 +21,6 @@ #include "remoting/client/chromoting_client.h" #include "remoting/client/client_context.h" #include "remoting/client/client_user_interface.h" -#include "remoting/client/video_renderer.h" #include "remoting/host/chromoting_host.h" #include "remoting/host/chromoting_host_context.h" #include "remoting/host/fake_desktop_environment.h" @@ -31,6 +30,7 @@ #include "remoting/protocol/session_config.h" #include "remoting/protocol/transport_context.h" #include "remoting/protocol/video_frame_pump.h" +#include "remoting/protocol/video_renderer.h" #include "remoting/signaling/fake_signal_strategy.h" #include "remoting/test/fake_network_dispatcher.h" #include "remoting/test/fake_port_allocator.h" @@ -77,7 +77,7 @@ : public testing::Test, public testing::WithParamInterface<NetworkPerformanceParams>, public ClientUserInterface, - public VideoRenderer, + public protocol::VideoRenderer, public protocol::VideoStub, public HostStatusObserver { public: @@ -123,6 +123,10 @@ // VideoRenderer interface. void OnSessionConfig(const protocol::SessionConfig& config) override {} protocol::VideoStub* GetVideoStub() override { return this; } + protocol::FrameConsumer* GetFrameConsumer() override { + NOTREACHED(); + return nullptr; + } // protocol::VideoStub interface. void ProcessVideoPacket(scoped_ptr<VideoPacket> video_packet,
diff --git a/remoting/test/test_chromoting_client.cc b/remoting/test/test_chromoting_client.cc index 37d6264..027cd01 100644 --- a/remoting/test/test_chromoting_client.cc +++ b/remoting/test/test_chromoting_client.cc
@@ -70,7 +70,7 @@ : TestChromotingClient(nullptr) {} TestChromotingClient::TestChromotingClient( - scoped_ptr<VideoRenderer> video_renderer) + scoped_ptr<protocol::VideoRenderer> video_renderer) : connection_to_host_state_(protocol::ConnectionToHost::INITIALIZING), connection_error_code_(protocol::OK), video_renderer_(std::move(video_renderer)) {}
diff --git a/remoting/test/test_chromoting_client.h b/remoting/test/test_chromoting_client.h index 15c5db13..33e69f6 100644 --- a/remoting/test/test_chromoting_client.h +++ b/remoting/test/test_chromoting_client.h
@@ -21,12 +21,12 @@ class ClientContext; class XmppSignalStrategy; -class VideoRenderer; namespace protocol { class ClipboardStub; class HostStub; class InputStub; +class VideoRenderer; } // namespace protocol namespace test { @@ -44,7 +44,8 @@ public protocol::CursorShapeStub { public: TestChromotingClient(); - explicit TestChromotingClient(scoped_ptr<VideoRenderer> video_renderer); + explicit TestChromotingClient( + scoped_ptr<protocol::VideoRenderer> video_renderer); ~TestChromotingClient() override; // Starts a Chromoting connection using the specified connection setup info. @@ -114,7 +115,7 @@ scoped_ptr<ClientContext> client_context_; // Processes video packets from the host. - scoped_ptr<VideoRenderer> video_renderer_; + scoped_ptr<protocol::VideoRenderer> video_renderer_; // SignalStrategy used for connection signaling. scoped_ptr<SignalStrategy> signal_strategy_;
diff --git a/remoting/test/test_video_renderer.cc b/remoting/test/test_video_renderer.cc index 53557725..42bd96f 100644 --- a/remoting/test/test_video_renderer.cc +++ b/remoting/test/test_video_renderer.cc
@@ -310,6 +310,12 @@ return this; } +protocol::FrameConsumer* TestVideoRenderer::GetFrameConsumer() { + DCHECK(thread_checker_.CalledOnValidThread()); + NOTREACHED(); + return nullptr; +} + void TestVideoRenderer::ProcessVideoPacket(scoped_ptr<VideoPacket> video_packet, const base::Closure& done) { DCHECK(thread_checker_.CalledOnValidThread());
diff --git a/remoting/test/test_video_renderer.h b/remoting/test/test_video_renderer.h index d58266b..1ea4905 100644 --- a/remoting/test/test_video_renderer.h +++ b/remoting/test/test_video_renderer.h
@@ -9,8 +9,8 @@ #include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" #include "base/threading/thread_checker.h" -#include "remoting/client/video_renderer.h" #include "remoting/protocol/session_config.h" +#include "remoting/protocol/video_renderer.h" #include "remoting/protocol/video_stub.h" namespace base { @@ -32,7 +32,8 @@ // used from a thread running a message loop and this class will use that // message loop to execute the done callbacks passed by the caller of // ProcessVideoPacket. -class TestVideoRenderer : public VideoRenderer, public protocol::VideoStub { +class TestVideoRenderer : public protocol::VideoRenderer, + public protocol::VideoStub { public: TestVideoRenderer(); ~TestVideoRenderer() override; @@ -40,6 +41,7 @@ // VideoRenderer interface. void OnSessionConfig(const protocol::SessionConfig& config) override; protocol::VideoStub* GetVideoStub() override; + protocol::FrameConsumer* GetFrameConsumer() override; // protocol::VideoStub interface. void ProcessVideoPacket(scoped_ptr<VideoPacket> video_packet,
diff --git a/sandbox/win/src/lpc_policy_test.cc b/sandbox/win/src/lpc_policy_test.cc index ac7b39f3..22db795 100644 --- a/sandbox/win/src/lpc_policy_test.cc +++ b/sandbox/win/src/lpc_policy_test.cc
@@ -137,11 +137,11 @@ // GetUserDefaultLocaleName is not available on WIN XP. So we'll // load it on-the-fly. HMODULE kernel32_dll = ::GetModuleHandle(kKernel32DllName); - EXPECT_NE(NULL, int(kernel32_dll)); + EXPECT_NE(nullptr, kernel32_dll); GetUserDefaultLocaleName_func = reinterpret_cast<GetUserDefaultLocaleNameFunction>( GetProcAddress(kernel32_dll, "GetUserDefaultLocaleName")); - EXPECT_NE(NULL, int(GetUserDefaultLocaleName_func)); + EXPECT_NE(nullptr, GetUserDefaultLocaleName_func); } wchar_t locale_name[LOCALE_NAME_MAX_LENGTH] = {0}; EXPECT_NE(0, GetUserDefaultLocaleName_func(
diff --git a/skia/config/SkUserConfig.h b/skia/config/SkUserConfig.h index f7b0845..f9dce786 100644 --- a/skia/config/SkUserConfig.h +++ b/skia/config/SkUserConfig.h
@@ -214,6 +214,10 @@ # define SK_SUPPORT_LEGACY_GETDEVICE #endif +#ifndef SK_SUPPORT_LEGACY_REFENCODEDDATA_NOCTX +# define SK_SUPPORT_LEGACY_REFENCODEDDATA_NOCTX +#endif + #ifndef SK_IGNORE_ETC1_SUPPORT # define SK_IGNORE_ETC1_SUPPORT #endif @@ -226,10 +230,6 @@ # define SK_SUPPORT_LEGACY_HQ_DOWNSAMPLING #endif -#ifndef SK_SUPPORT_LEGACY_BITMAP_SAMPLER_BIAS -# define SK_SUPPORT_LEGACY_BITMAP_SAMPLER_BIAS -#endif - #ifndef SK_SUPPORT_LEGACY_PATH_MEASURE_TVALUE # define SK_SUPPORT_LEGACY_PATH_MEASURE_TVALUE #endif
diff --git a/storage/browser/fileapi/file_system_dir_url_request_job.cc b/storage/browser/fileapi/file_system_dir_url_request_job.cc index 0c3ef36..b280d55 100644 --- a/storage/browser/fileapi/file_system_dir_url_request_job.cc +++ b/storage/browser/fileapi/file_system_dir_url_request_job.cc
@@ -15,8 +15,8 @@ #include "base/strings/utf_string_conversions.h" #include "base/time/time.h" #include "build/build_config.h" +#include "net/base/directory_listing.h" #include "net/base/io_buffer.h" -#include "net/base/net_util.h" #include "net/url_request/url_request.h" #include "storage/browser/fileapi/file_system_context.h" #include "storage/browser/fileapi/file_system_operation_runner.h"
diff --git a/sync/engine/backoff_delay_provider.cc b/sync/engine/backoff_delay_provider.cc index cb8b0f19..864401c 100644 --- a/sync/engine/backoff_delay_provider.cc +++ b/sync/engine/backoff_delay_provider.cc
@@ -65,27 +65,13 @@ TimeDelta BackoffDelayProvider::GetInitialDelay( const sessions::ModelNeutralState& state) const { - // NETWORK_CONNECTION_UNAVAILABLE implies we did not even manage to hit the - // wire; the failure occurred locally. Note that if commit_result is *not* - // UNSET, this implies download_updates_result succeeded. Also note that - // last_get_key_result is coupled to last_download_updates_result in that - // they are part of the same GetUpdates request, so we only check if - // the download request is CONNECTION_UNAVAILABLE. - // - // TODO(tim): Should we treat NETWORK_IO_ERROR similarly? It's different - // from CONNECTION_UNAVAILABLE in that a request may well have succeeded - // in contacting the server (e.g we got a 200 back), but we failed - // trying to parse the response (actual content length != HTTP response - // header content length value). For now since we're considering - // merging this code to branches and I haven't audited all the - // NETWORK_IO_ERROR cases carefully, I'm going to target the fix - // very tightly (see bug chromium-os:35073). DIRECTORY_LOOKUP_FAILED is - // another example of something that shouldn't backoff, though the - // scheduler should probably be handling these cases differently. See - // the TODO(rlarocque) in ScheduleNextSync. + // NETWORK_CONNECTION_UNAVAILABLE implies we did not receive HTTP response + // from server because of some network error. If network is unavailable then + // on next connection type or address change scheduler will run canary job. + // Otherwise we'll retry in 30 seconds. if (state.commit_result == NETWORK_CONNECTION_UNAVAILABLE || state.last_download_updates_result == NETWORK_CONNECTION_UNAVAILABLE) { - return short_initial_backoff_; + return default_initial_backoff_; } if (SyncerErrorIsError(state.last_get_key_result))
diff --git a/sync/engine/backoff_delay_provider_unittest.cc b/sync/engine/backoff_delay_provider_unittest.cc index 2e58186..f1a78d8a 100644 --- a/sync/engine/backoff_delay_provider_unittest.cc +++ b/sync/engine/backoff_delay_provider_unittest.cc
@@ -46,7 +46,7 @@ delay->GetInitialDelay(state).InSeconds()); state.last_download_updates_result = NETWORK_CONNECTION_UNAVAILABLE; - EXPECT_EQ(kInitialBackoffImmediateRetrySeconds, + EXPECT_EQ(kInitialBackoffRetrySeconds, delay->GetInitialDelay(state).InSeconds()); state.last_download_updates_result = SERVER_RETURN_TRANSIENT_ERROR; @@ -74,7 +74,7 @@ delay->GetInitialDelay(state).InSeconds()); state.commit_result = NETWORK_CONNECTION_UNAVAILABLE; - EXPECT_EQ(kInitialBackoffImmediateRetrySeconds, + EXPECT_EQ(kInitialBackoffRetrySeconds, delay->GetInitialDelay(state).InSeconds()); state.commit_result = SERVER_RETURN_CONFLICT;
diff --git a/sync/engine/get_commit_ids.cc b/sync/engine/get_commit_ids.cc index 85c14d8..a4c7f6b 100644 --- a/sync/engine/get_commit_ids.cc +++ b/sync/engine/get_commit_ids.cc
@@ -119,20 +119,17 @@ return false; } -// An entry is not considered ready for commit if any are true: -// 1. It's in conflict. -// 2. It requires encryption (either the type is encrypted but a passphrase +// An entry may not commit if any are true: +// 1. It requires encryption (either the type is encrypted but a passphrase // is missing from the cryptographer, or the entry itself wasn't properly // encrypted). -// 3. It's type is currently throttled. -// 4. It's a delete but has not been committed. -bool IsEntryReadyForCommit(ModelTypeSet requested_types, - ModelTypeSet encrypted_types, - bool passphrase_missing, - const syncable::Entry& entry) { +// 2. It's type is currently throttled. +// 3. It's a delete but has not been committed. +bool MayEntryCommit(ModelTypeSet requested_types, + ModelTypeSet encrypted_types, + bool passphrase_missing, + const syncable::Entry& entry) { DCHECK(entry.GetIsUnsynced()); - if (IsEntryInConflict(entry)) - return false; const ModelType type = entry.GetModelType(); // We special case the nigori node because even though it is considered an @@ -186,6 +183,74 @@ return true; } +bool SupportsHierarchy(const syncable::Entry& item) { + // Types with explicit server supported hierarchy only. + return IsTypeWithServerGeneratedRoot(item.GetModelType()); +} + +// Excludes ancestors of deleted conflicted items from +// |ready_unsynced_set|. +void ExcludeDeletedAncestors( + syncable::BaseTransaction* trans, + const std::vector<int64_t>& deleted_conflicted_items, + std::set<int64_t>* ready_unsynced_set) { + for (auto iter = deleted_conflicted_items.begin(); + iter != deleted_conflicted_items.end(); ++iter) { + syncable::Entry item(trans, syncable::GET_BY_HANDLE, *iter); + syncable::Id parent_id = item.GetParentId(); + DCHECK(!parent_id.IsNull()); + + while (!parent_id.IsRoot()) { + syncable::Entry parent(trans, syncable::GET_BY_ID, parent_id); + CHECK(parent.good()) << "Bad user-only parent in item path."; + int64_t handle = parent.GetMetahandle(); + + if (!parent.GetIsDel()) + break; + + auto ready_iter = ready_unsynced_set->find(handle); + if (ready_iter == ready_unsynced_set->end()) + break; + + // Remove this entry from |ready_unsynced_set|. + ready_unsynced_set->erase(ready_iter); + parent_id = parent.GetParentId(); + } + } +} + +// Iterates over children of items from |conflicted_items| list that are in +// |ready_unsynced_set|, exludes them from |ready_unsynced_set| and adds them +// to |excluded_items| list. +void ExcludeChildren(syncable::BaseTransaction* trans, + const std::vector<int64_t>& conflicted_items, + std::vector<int64_t>* excluded_items, + std::set<int64_t>* ready_unsynced_set) { + for (auto iter = conflicted_items.begin(); iter != conflicted_items.end(); + ++iter) { + syncable::Entry entry(trans, syncable::GET_BY_HANDLE, *iter); + + if (!entry.GetIsDir() || entry.GetIsDel()) + continue; + + std::vector<int64_t> children; + entry.GetChildHandles(&children); + + for (std::vector<int64_t>::const_iterator child_iter = children.begin(); + child_iter != children.end(); ++child_iter) { + // Collect all child handles that are in |ready_unsynced_set|. + int64_t child_handle = *child_iter; + auto ready_iter = ready_unsynced_set->find(child_handle); + if (ready_iter != ready_unsynced_set->end()) { + // Remove this entry from |ready_unsynced_set| and add it + // to |excluded_items|. + ready_unsynced_set->erase(ready_iter); + excluded_items->push_back(child_handle); + } + } + } +} + // Filters |unsynced_handles| to remove all entries that do not belong to the // specified |requested_types|, or are not eligible for a commit at this time. void FilterUnreadyEntries( @@ -195,21 +260,51 @@ bool passphrase_missing, const syncable::Directory::Metahandles& unsynced_handles, std::set<int64_t>* ready_unsynced_set) { - for (syncable::Directory::Metahandles::const_iterator iter = - unsynced_handles.begin(); iter != unsynced_handles.end(); ++iter) { + std::vector<int64_t> deleted_conflicted_items; + std::vector<int64_t> conflicted_items; + + // Go over all unsynced handles, filter the ones that might be committed based + // on type / encryption, then based on whether they are in conflict add them + // to either |ready_unsynced_set| or one of the conflicted lists. + for (auto iter = unsynced_handles.begin(); iter != unsynced_handles.end(); + ++iter) { syncable::Entry entry(trans, syncable::GET_BY_HANDLE, *iter); // TODO(maniscalco): While we check if entry is ready to be committed, we // also need to check that all of its ancestors (parents, transitive) are // ready to be committed. Once attachments can prevent an entry from being // committable, this method must ensure all ancestors are ready for commit // (bug 356273). - if (IsEntryReadyForCommit(requested_types, - encrypted_types, - passphrase_missing, - entry)) { - ready_unsynced_set->insert(*iter); + if (MayEntryCommit(requested_types, encrypted_types, passphrase_missing, + entry)) { + if (IsEntryInConflict(entry)) { + // Conflicting hierarchical entries might prevent their ancestors or + // descendants from being committed. + if (SupportsHierarchy(entry)) { + if (entry.GetIsDel()) { + deleted_conflicted_items.push_back(*iter); + } else if (entry.GetIsDir()) { + // Populate the initial version of |conflicted_items| with folder + // items that are in conflict. + conflicted_items.push_back(*iter); + } + } + } else { + ready_unsynced_set->insert(*iter); + } } } + + // If there are any deleted conflicted entries, remove their deleted ancestors + // from |ready_unsynced_set| as well. + ExcludeDeletedAncestors(trans, deleted_conflicted_items, ready_unsynced_set); + + // Starting with conflicted_items containing conflicted folders go down and + // exclude all descendants from |ready_unsynced_set|. + while (!conflicted_items.empty()) { + std::vector<int64_t> new_list; + ExcludeChildren(trans, conflicted_items, &new_list, ready_unsynced_set); + conflicted_items.swap(new_list); + } } // This class helps to implement OrderCommitIds(). Its members track the @@ -231,21 +326,19 @@ private: // The following functions do not modify the traversal directly. They return // their results in the |result| vector instead. - bool AddUncommittedParents(const std::set<int64_t>& ready_unsynced_set, + void AddUncommittedParents(const std::set<int64_t>& ready_unsynced_set, const syncable::Entry& item, syncable::Directory::Metahandles* result) const; - void TryAddItem(const std::set<int64_t>& ready_unsynced_set, + bool TryAddItem(const std::set<int64_t>& ready_unsynced_set, const syncable::Entry& item, syncable::Directory::Metahandles* result) const; - bool AddDeletedParents(const std::set<int64_t>& ready_unsynced_set, + void AddDeletedParents(const std::set<int64_t>& ready_unsynced_set, const syncable::Entry& item, const syncable::Directory::Metahandles& traversed, syncable::Directory::Metahandles* result) const; - bool SupportsHierarchy(const syncable::Entry& item) const; - // Returns true if we've collected enough items. bool IsFull() const; @@ -273,7 +366,7 @@ Traversal::~Traversal() {} -bool Traversal::AddUncommittedParents( +void Traversal::AddUncommittedParents( const std::set<int64_t>& ready_unsynced_set, const syncable::Entry& item, syncable::Directory::Metahandles* result) const { @@ -291,41 +384,40 @@ // We can return early. break; } - if (IsEntryInConflict(parent)) { - // We ignore all entries that are children of a conflicing item. Return - // false immediately to forget the traversal we've built up so far. - DVLOG(1) << "Parent was in conflict, omitting " << item; - return false; + + if (!TryAddItem(ready_unsynced_set, parent, &dependencies)) { + // The parent isn't in |ready_unsynced_set|. + break; } - TryAddItem(ready_unsynced_set, parent, &dependencies); + parent_id = parent.GetParentId(); } // Reverse what we added to get the correct order. result->insert(result->end(), dependencies.rbegin(), dependencies.rend()); - return true; } // Adds the given item to the list if it is unsynced and ready for commit. -void Traversal::TryAddItem(const std::set<int64_t>& ready_unsynced_set, +bool Traversal::TryAddItem(const std::set<int64_t>& ready_unsynced_set, const syncable::Entry& item, syncable::Directory::Metahandles* result) const { DCHECK(item.GetIsUnsynced()); int64_t item_handle = item.GetMetahandle(); if (ready_unsynced_set.count(item_handle) != 0) { result->push_back(item_handle); + return true; } + return false; } // Traverses the tree from bottom to top, adding the deleted parents of the // given |item|. Stops traversing if it encounters a non-deleted node, or -// a node that was already listed in the |traversed| list. Returns an error -// (false) if a node along the traversal is in a conflict state. +// a node that was already listed in the |traversed| list. // // The result list is reversed before it is returned, so the resulting // traversal is in top to bottom order. Also note that this function appends // to the result list without clearing it. -bool Traversal::AddDeletedParents( +void Traversal::AddDeletedParents( const std::set<int64_t>& ready_unsynced_set, const syncable::Entry& item, const syncable::Directory::Metahandles& traversed, @@ -363,19 +455,17 @@ // We can return early. break; } - if (IsEntryInConflict(parent)) { - // We ignore all entries that are children of a conflicing item. Return - // false immediately to forget the traversal we've built up so far. - DVLOG(1) << "Parent was in conflict, omitting " << item; - return false; + + if (!TryAddItem(ready_unsynced_set, parent, &dependencies)) { + // The parent isn't in ready_unsynced_set. + break; } - TryAddItem(ready_unsynced_set, parent, &dependencies); + parent_id = parent.GetParentId(); } // Reverse what we added to get the correct order. result->insert(result->end(), dependencies.rbegin(), dependencies.rend()); - return true; } bool Traversal::IsFull() const { @@ -386,11 +476,6 @@ return added_handles_.find(handle) != added_handles_.end(); } -bool Traversal::SupportsHierarchy(const syncable::Entry& item) const { - // Types with explicit server supported hierarchy only. - return IsTypeWithServerGeneratedRoot(item.GetModelType()); -} - void Traversal::AppendManyToTraversal( const syncable::Directory::Metahandles& handles) { out_->insert(out_->end(), handles.begin(), handles.end()); @@ -419,11 +504,9 @@ // We only commit an item + its dependencies if it and all its // dependencies are not in conflict. syncable::Directory::Metahandles item_dependencies; - if (AddUncommittedParents(ready_unsynced_set, entry, - &item_dependencies)) { - TryAddItem(ready_unsynced_set, entry, &item_dependencies); - AppendManyToTraversal(item_dependencies); - } + AddUncommittedParents(ready_unsynced_set, entry, &item_dependencies); + TryAddItem(ready_unsynced_set, entry, &item_dependencies); + AppendManyToTraversal(item_dependencies); } else { // No hierarchy dependencies, just commit the item itself. AppendToTraversal(metahandle); @@ -461,16 +544,12 @@ if (entry.GetIsDel()) { if (SupportsHierarchy(entry)) { syncable::Directory::Metahandles parents; - if (AddDeletedParents(ready_unsynced_set, entry, deletion_list, - &parents)) { - // Append parents and chilren in top to bottom order. - deletion_list.insert(deletion_list.end(), parents.begin(), - parents.end()); - deletion_list.push_back(metahandle); - } - } else { - deletion_list.push_back(metahandle); + AddDeletedParents(ready_unsynced_set, entry, deletion_list, &parents); + // Append parents and chilren in top to bottom order. + deletion_list.insert(deletion_list.end(), parents.begin(), + parents.end()); } + deletion_list.push_back(metahandle); } }
diff --git a/sync/engine/net/server_connection_manager.cc b/sync/engine/net/server_connection_manager.cc index 83fbafe2..a5be7a5 100644 --- a/sync/engine/net/server_connection_manager.cc +++ b/sync/engine/net/server_connection_manager.cc
@@ -55,23 +55,6 @@ #undef ENUM_CASE -// TODO(clamy): check if all errors are in the right category. -HttpResponse::ServerConnectionCode -HttpResponse::ServerConnectionCodeFromNetError(int error_code) { - switch (error_code) { - case net::ERR_ABORTED: - case net::ERR_SOCKET_NOT_CONNECTED: - case net::ERR_NETWORK_CHANGED: - case net::ERR_CONNECTION_FAILED: - case net::ERR_NAME_NOT_RESOLVED: - case net::ERR_INTERNET_DISCONNECTED: - case net::ERR_NETWORK_ACCESS_DENIED: - case net::ERR_NETWORK_IO_SUSPENDED: - return CONNECTION_UNAVAILABLE; - } - return IO_ERROR; -} - ServerConnectionManager::Connection::Connection( ServerConnectionManager* scm) : scm_(scm) { }
diff --git a/sync/engine/net/server_connection_manager.h b/sync/engine/net/server_connection_manager.h index 6cb653f..62248eab 100644 --- a/sync/engine/net/server_connection_manager.h +++ b/sync/engine/net/server_connection_manager.h
@@ -91,9 +91,6 @@ static const char* GetServerConnectionCodeString( ServerConnectionCode code); - - static ServerConnectionCode ServerConnectionCodeFromNetError( - int error_code); }; struct ServerConnectionEvent {
diff --git a/sync/engine/syncer_unittest.cc b/sync/engine/syncer_unittest.cc index 073ac51..b2a92de 100644 --- a/sync/engine/syncer_unittest.cc +++ b/sync/engine/syncer_unittest.cc
@@ -62,6 +62,7 @@ #include "sync/util/cryptographer.h" #include "sync/util/extensions_activity.h" #include "sync/util/time.h" +#include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" using base::TimeDelta; @@ -2809,6 +2810,177 @@ EXPECT_EQ(0, GetCommitCounters(BOOKMARKS).num_commits_conflict); } +// Test conflict resolution when deleting a hierarchy of nodes within a folder +// and running into a conflict in one of items. The conflict in a deleted +// item must prevent all deleted ancestors from being committed as well; +// otherwise the conflicting item would end up being orphaned. +TEST_F(SyncerTest, DeletingFolderWithConflictInSubfolder) { + int64_t top_handle, nested_handle, leaf_handle; + { + WriteTransaction trans(FROM_HERE, UNITTEST, directory()); + MutableEntry top_entry(&trans, CREATE, BOOKMARKS, trans.root_id(), "top"); + ASSERT_TRUE(top_entry.good()); + top_entry.PutIsDir(true); + top_entry.PutSpecifics(DefaultBookmarkSpecifics()); + top_entry.PutIsUnsynced(true); + top_handle = top_entry.GetMetahandle(); + + MutableEntry nested_entry(&trans, CREATE, BOOKMARKS, top_entry.GetId(), + "nested"); + ASSERT_TRUE(nested_entry.good()); + nested_entry.PutIsDir(true); + nested_entry.PutSpecifics(DefaultBookmarkSpecifics()); + nested_entry.PutIsUnsynced(true); + nested_handle = nested_entry.GetMetahandle(); + + MutableEntry leaf_entry(&trans, CREATE, BOOKMARKS, nested_entry.GetId(), + "leaf"); + ASSERT_TRUE(leaf_entry.good()); + leaf_entry.PutSpecifics(DefaultBookmarkSpecifics()); + leaf_entry.PutIsUnsynced(true); + leaf_handle = leaf_entry.GetMetahandle(); + } + EXPECT_TRUE(SyncShareNudge()); + + // Delete all 3 entries and also add unapplied update to the middle one. + { + WriteTransaction trans(FROM_HERE, UNITTEST, directory()); + MutableEntry leaf_entry(&trans, GET_BY_HANDLE, leaf_handle); + ASSERT_TRUE(leaf_entry.good()); + EXPECT_TRUE(leaf_entry.GetId().ServerKnows()); + leaf_entry.PutIsUnsynced(true); + leaf_entry.PutIsDel(true); + + MutableEntry nested_entry(&trans, GET_BY_HANDLE, nested_handle); + ASSERT_TRUE(nested_entry.good()); + EXPECT_TRUE(nested_entry.GetId().ServerKnows()); + nested_entry.PutIsUnsynced(true); + nested_entry.PutIsDel(true); + + sync_pb::EntitySpecifics specifics; + specifics.mutable_bookmark()->set_url("http://demo/"); + specifics.mutable_bookmark()->set_favicon("PNG"); + nested_entry.PutServerSpecifics(specifics); + // This will put the entry into conflict. + nested_entry.PutIsUnappliedUpdate(true); + nested_entry.PutServerVersion(nested_entry.GetBaseVersion() + 1); + + MutableEntry top_entry(&trans, GET_BY_HANDLE, top_handle); + ASSERT_TRUE(top_entry.good()); + EXPECT_TRUE(top_entry.GetId().ServerKnows()); + top_entry.PutIsUnsynced(true); + top_entry.PutIsDel(true); + } + EXPECT_TRUE(SyncShareNudge()); + + // Verify that the top folder hasn't been committed. Doing so would + // orphan the nested folder. + syncable::Id top_id; + { + syncable::ReadTransaction trans(FROM_HERE, directory()); + Entry top_entry(&trans, GET_BY_HANDLE, top_handle); + ASSERT_TRUE(top_entry.good()); + top_id = top_entry.GetId(); + + EXPECT_TRUE(top_entry.GetIsUnsynced()); + EXPECT_TRUE(top_entry.GetIsDel()); + } + + EXPECT_THAT(mock_server_->committed_ids(), + testing::Not(testing::Contains(top_id))); +} + +// Test conflict resolution when committing a hierarchy of items and running +// into a conflict in a parent folder. A conflicting parent must prevent any +// of its descendants from being committed. +TEST_F(SyncerTest, CommittingItemsWithConflictInParentFolder) { + int64_t top_handle, nested_handle, leaf_handle; + { + WriteTransaction trans(FROM_HERE, UNITTEST, directory()); + MutableEntry top_entry(&trans, CREATE, BOOKMARKS, trans.root_id(), "top"); + ASSERT_TRUE(top_entry.good()); + top_entry.PutIsDir(true); + top_entry.PutSpecifics(DefaultBookmarkSpecifics()); + top_entry.PutIsUnsynced(true); + top_handle = top_entry.GetMetahandle(); + + MutableEntry nested_entry(&trans, CREATE, BOOKMARKS, top_entry.GetId(), + "nested"); + ASSERT_TRUE(nested_entry.good()); + nested_entry.PutIsDir(true); + nested_entry.PutSpecifics(DefaultBookmarkSpecifics()); + nested_entry.PutIsUnsynced(true); + nested_handle = nested_entry.GetMetahandle(); + + MutableEntry leaf_entry(&trans, CREATE, BOOKMARKS, nested_entry.GetId(), + "leaf"); + ASSERT_TRUE(leaf_entry.good()); + leaf_entry.PutSpecifics(DefaultBookmarkSpecifics()); + leaf_entry.PutIsUnsynced(true); + leaf_handle = leaf_entry.GetMetahandle(); + } + EXPECT_TRUE(SyncShareNudge()); + + // Touch all 3 entries and also add unapplied update to the top one. + syncable::Id top_id, nested_id, leaf_id; + { + WriteTransaction trans(FROM_HERE, UNITTEST, directory()); + sync_pb::EntitySpecifics specifics; + specifics.mutable_bookmark()->set_url("http://demo/"); + + MutableEntry top_entry(&trans, GET_BY_HANDLE, top_handle); + ASSERT_TRUE(top_entry.good()); + top_id = top_entry.GetId(); + EXPECT_TRUE(top_id.ServerKnows()); + top_entry.PutIsUnsynced(true); + top_entry.PutSpecifics(specifics); + + // This will put the top entry into conflict. + top_entry.PutIsUnappliedUpdate(true); + top_entry.PutServerIsDel(true); + top_entry.PutServerVersion(top_entry.GetBaseVersion() + 1); + + MutableEntry nested_entry(&trans, GET_BY_HANDLE, nested_handle); + ASSERT_TRUE(nested_entry.good()); + nested_id = nested_entry.GetId(); + EXPECT_TRUE(nested_id.ServerKnows()); + nested_entry.PutSpecifics(specifics); + nested_entry.PutIsUnsynced(true); + + MutableEntry leaf_entry(&trans, GET_BY_HANDLE, leaf_handle); + ASSERT_TRUE(leaf_entry.good()); + leaf_id = leaf_entry.GetId(); + EXPECT_TRUE(leaf_id.ServerKnows()); + leaf_entry.PutSpecifics(specifics); + leaf_entry.PutIsUnsynced(true); + } + EXPECT_TRUE(SyncShareNudge()); + + // Verify that all 3 entries remain unsynced + EXPECT_THAT(mock_server_->committed_ids(), + testing::Not(testing::Contains(top_id))); + EXPECT_THAT(mock_server_->committed_ids(), + testing::Not(testing::Contains(nested_id))); + EXPECT_THAT(mock_server_->committed_ids(), + testing::Not(testing::Contains(leaf_id))); + + { + syncable::ReadTransaction trans(FROM_HERE, directory()); + + Entry top_entry(&trans, GET_BY_HANDLE, top_handle); + ASSERT_TRUE(top_entry.good()); + ASSERT_TRUE(top_entry.GetIsUnsynced()); + + Entry nested_entry(&trans, GET_BY_HANDLE, nested_handle); + ASSERT_TRUE(nested_entry.good()); + ASSERT_TRUE(nested_entry.GetIsUnsynced()); + + Entry leaf_entry(&trans, GET_BY_HANDLE, leaf_handle); + ASSERT_TRUE(leaf_entry.good()); + ASSERT_TRUE(leaf_entry.GetIsUnsynced()); + } +} + // Test conflict resolution when handling an update for an item with specified // Parent ID and having an implicit (unset) Parent ID in the update. TEST_F(SyncerTest, ConflictWithImplicitParent) {
diff --git a/sync/internal_api/http_bridge.cc b/sync/internal_api/http_bridge.cc index 842adf3..b8d57cc 100644 --- a/sync/internal_api/http_bridge.cc +++ b/sync/internal_api/http_bridge.cc
@@ -512,7 +512,7 @@ fetch_state_.request_completed = true; fetch_state_.request_succeeded = false; fetch_state_.http_response_code = -1; - fetch_state_.error_code = net::URLRequestStatus::FAILED; + fetch_state_.error_code = net::ERR_TIMED_OUT; // This method is called by the timer, not the url fetcher implementation, // so it's safe to delete the fetcher here.
diff --git a/sync/internal_api/syncapi_server_connection_manager.cc b/sync/internal_api/syncapi_server_connection_manager.cc index 16646ec7..a54fcbc8 100644 --- a/sync/internal_api/syncapi_server_connection_manager.cc +++ b/sync/internal_api/syncapi_server_connection_manager.cc
@@ -53,9 +53,9 @@ int error_code = 0; int response_code = 0; if (!http->MakeSynchronousPost(&error_code, &response_code)) { + DCHECK_NE(error_code, net::OK); DVLOG(1) << "Http POST failed, error returns: " << error_code; - response->server_status = HttpResponse::ServerConnectionCodeFromNetError( - error_code); + response->server_status = HttpResponse::CONNECTION_UNAVAILABLE; return false; }
diff --git a/sync/internal_api/syncapi_server_connection_manager.h b/sync/internal_api/syncapi_server_connection_manager.h index aa1fe1e1..225959ba 100644 --- a/sync/internal_api/syncapi_server_connection_manager.h +++ b/sync/internal_api/syncapi_server_connection_manager.h
@@ -67,6 +67,8 @@ VeryEarlyAbortPost); FRIEND_TEST_ALL_PREFIXES(SyncAPIServerConnectionManagerTest, EarlyAbortPost); FRIEND_TEST_ALL_PREFIXES(SyncAPIServerConnectionManagerTest, AbortPost); + FRIEND_TEST_ALL_PREFIXES(SyncAPIServerConnectionManagerTest, + FailPostWithTimedOut); // A factory creating concrete HttpPostProviders for use whenever we need to // issue a POST to sync servers.
diff --git a/sync/internal_api/syncapi_server_connection_manager_unittest.cc b/sync/internal_api/syncapi_server_connection_manager_unittest.cc index 208b3a2..9e67be8 100644 --- a/sync/internal_api/syncapi_server_connection_manager_unittest.cc +++ b/sync/internal_api/syncapi_server_connection_manager_unittest.cc
@@ -120,4 +120,70 @@ abort_thread.Stop(); } +namespace { + +class FailingHttpPost : public HttpPostProviderInterface { + public: + explicit FailingHttpPost(int error_code) : error_code_(error_code) {} + ~FailingHttpPost() override {} + + void SetExtraRequestHeaders(const char* headers) override {} + void SetURL(const char* url, int port) override {} + void SetPostPayload(const char* content_type, + int content_length, + const char* content) override {} + bool MakeSynchronousPost(int* error_code, int* response_code) override { + *error_code = error_code_; + return false; + } + int GetResponseContentLength() const override { return 0; } + const char* GetResponseContent() const override { return ""; } + const std::string GetResponseHeaderValue( + const std::string& name) const override { + return std::string(); + } + void Abort() override {} + + private: + int error_code_; +}; + +class FailingHttpPostFactory : public HttpPostProviderFactory { + public: + explicit FailingHttpPostFactory(int error_code) : error_code_(error_code) {} + ~FailingHttpPostFactory() override {} + void Init(const std::string& user_agent, + const BindToTrackerCallback& bind_to_tracker_callback) override {} + + HttpPostProviderInterface* Create() override { + return new FailingHttpPost(error_code_); + } + void Destroy(HttpPostProviderInterface* http) override { + delete static_cast<FailingHttpPost*>(http); + } + + private: + int error_code_; +}; + +} // namespace + +// Fail request with TIMED_OUT error. Make sure server status is +// CONNECTION_UNAVAILABLE and therefore request will be retried after network +// change. +TEST(SyncAPIServerConnectionManagerTest, FailPostWithTimedOut) { + CancelationSignal signal; + SyncAPIServerConnectionManager server( + "server", 0, true, new FailingHttpPostFactory(net::ERR_TIMED_OUT), + &signal); + + ServerConnectionManager::PostBufferParams params; + + bool result = server.PostBufferToPath(¶ms, "/testpath", "testauth"); + + EXPECT_FALSE(result); + EXPECT_EQ(HttpResponse::CONNECTION_UNAVAILABLE, + params.response.server_status); +} + } // namespace syncer
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json index ebceebf..713c0a2 100644 --- a/testing/buildbot/chromium.fyi.json +++ b/testing/buildbot/chromium.fyi.json
@@ -5742,7 +5742,7 @@ { "args": [ "--isolate-extensions", - "--gtest_filter=-PhishingClassifierDelegateTest.*:WebNavigationApiTest.*" + "--gtest_filter=-PhishingClassifierDelegateTest.*:WebNavigationApiTest.*:SSLUITest.TestMarkNonSecureAs" ], "test": "browser_tests" },
diff --git a/testing/buildbot/chromium.gpu.fyi.json b/testing/buildbot/chromium.gpu.fyi.json index 92d4168..5254df7 100644 --- a/testing/buildbot/chromium.gpu.fyi.json +++ b/testing/buildbot/chromium.gpu.fyi.json
@@ -3,6 +3,8 @@ "GPU NextGen Linux Builder (dbg)": {}, "GPU NextGen Mac Builder": {}, "GPU NextGen Mac Builder (dbg)": {}, + "GPU NextGen Win Builder": {}, + "GPU NextGen Win Builder (dbg)": {}, "Linux NextGen Debug (NVIDIA)": { "gtest_tests": [ { @@ -1502,5 +1504,809 @@ } } ] + }, + "Win7 NextGen Debug (NVIDIA)": { + "gtest_tests": [ + { + "args": [ + "--use-gpu-in-tests" + ], + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "gpu": "10de:104a", + "os": "Windows" + } + ] + }, + "test": "angle_end2end_tests" + }, + { + "args": [ + "--use-gpu-in-tests" + ], + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "gpu": "10de:104a", + "os": "Windows" + } + ] + }, + "test": "angle_unittests" + }, + { + "args": [ + "--use-gpu-in-tests" + ], + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "gpu": "10de:104a", + "os": "Windows" + } + ] + }, + "test": "audio_unittests" + }, + { + "args": [ + "--use-gpu-in-tests" + ], + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "gpu": "10de:104a", + "os": "Windows" + } + ] + }, + "test": "content_gl_tests" + }, + { + "args": [ + "--use-gpu-in-tests" + ], + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "gpu": "10de:104a", + "os": "Windows" + } + ] + }, + "test": "gl_tests" + }, + { + "args": [ + "--use-gpu-in-tests" + ], + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "gpu": "10de:104a", + "os": "Windows" + } + ] + }, + "test": "gl_unittests" + } + ], + "isolated_scripts": [ + { + "args": [ + "context_lost", + "--show-stdout", + "--browser=debug", + "-v", + "--extra-browser-args=\"--enable-logging=stderr --js-flags=--expose-gc\"" + ], + "isolate_name": "telemetry_gpu_test", + "name": "context_lost_tests", + "override_compile_targets": [ + "telemetry_gpu_test_run" + ], + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "gpu": "10de:104a", + "os": "Windows" + } + ] + } + }, + { + "args": [ + "gpu_process", + "--show-stdout", + "--browser=debug", + "-v", + "--extra-browser-args=\"--enable-logging=stderr --js-flags=--expose-gc\"" + ], + "isolate_name": "telemetry_gpu_test", + "name": "gpu_process_launch_tests", + "override_compile_targets": [ + "telemetry_gpu_test_run" + ], + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "gpu": "10de:104a", + "os": "Windows" + } + ] + } + }, + { + "args": [ + "gpu_rasterization", + "--show-stdout", + "--browser=debug", + "-v", + "--extra-browser-args=\"--enable-logging=stderr --js-flags=--expose-gc\"" + ], + "isolate_name": "telemetry_gpu_test", + "name": "gpu_rasterization_tests", + "override_compile_targets": [ + "telemetry_gpu_test_run" + ], + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "gpu": "10de:104a", + "os": "Windows" + } + ] + } + }, + { + "args": [ + "hardware_accelerated_feature", + "--show-stdout", + "--browser=debug", + "-v", + "--extra-browser-args=\"--enable-logging=stderr --js-flags=--expose-gc\"" + ], + "isolate_name": "telemetry_gpu_test", + "name": "hardware_accelerated_feature_tests", + "override_compile_targets": [ + "telemetry_gpu_test_run" + ], + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "gpu": "10de:104a", + "os": "Windows" + } + ] + } + }, + { + "args": [ + "maps", + "--show-stdout", + "--browser=debug", + "-v", + "--extra-browser-args=\"--enable-logging=stderr --js-flags=--expose-gc\"" + ], + "isolate_name": "telemetry_gpu_test", + "name": "maps_pixel_test", + "override_compile_targets": [ + "telemetry_gpu_test_run" + ], + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "gpu": "10de:104a", + "os": "Windows" + } + ] + } + }, + { + "args": [ + "memory_test", + "--show-stdout", + "--browser=debug", + "-v", + "--extra-browser-args=\"--enable-logging=stderr --js-flags=--expose-gc\"" + ], + "isolate_name": "telemetry_gpu_test", + "name": "memory_test", + "override_compile_targets": [ + "telemetry_gpu_test_run" + ], + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "gpu": "10de:104a", + "os": "Windows" + } + ] + } + }, + { + "args": [ + "pixel", + "--show-stdout", + "--browser=debug", + "-v", + "--extra-browser-args=\"--enable-logging=stderr --js-flags=--expose-gc\"", + "--upload-refimg-to-cloud-storage", + "--refimg-cloud-storage-bucket", + "chromium-gpu-archive/reference-images", + "--os-type", + "linux" + ], + "isolate_name": "telemetry_gpu_test", + "name": "pixel_test", + "override_compile_targets": [ + "telemetry_gpu_test_run" + ], + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "gpu": "10de:104a", + "os": "Windows" + } + ] + } + }, + { + "args": [ + "screenshot_sync", + "--show-stdout", + "--browser=debug", + "-v", + "--extra-browser-args=\"--enable-logging=stderr --js-flags=--expose-gc\"" + ], + "isolate_name": "telemetry_gpu_test", + "name": "screenshot_sync_tests", + "override_compile_targets": [ + "telemetry_gpu_test_run" + ], + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "gpu": "10de:104a", + "os": "Windows" + } + ] + } + }, + { + "args": [ + "trace_test", + "--show-stdout", + "--browser=debug", + "-v", + "--extra-browser-args=\"--enable-logging=stderr --js-flags=--expose-gc\"" + ], + "isolate_name": "telemetry_gpu_test", + "name": "trace_test", + "override_compile_targets": [ + "telemetry_gpu_test_run" + ], + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "gpu": "10de:104a", + "os": "Windows" + } + ] + } + }, + { + "args": [ + "webgl_conformance", + "--show-stdout", + "--browser=debug", + "-v", + "--extra-browser-args=\"--enable-logging=stderr --js-flags=--expose-gc\"" + ], + "isolate_name": "telemetry_gpu_test", + "name": "webgl_conformance_tests", + "override_compile_targets": [ + "telemetry_gpu_test_run" + ], + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "gpu": "10de:104a", + "os": "Windows" + } + ] + } + }, + { + "args": [ + "webgl_conformance", + "--show-stdout", + "--browser=debug", + "-v", + "--extra-browser-args=\"--enable-logging=stderr --js-flags=--expose-gc --use-angle=d3d9\"" + ], + "isolate_name": "telemetry_gpu_test", + "name": "webgl_conformance_d3d9_tests", + "override_compile_targets": [ + "telemetry_gpu_test_run" + ], + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "gpu": "10de:104a", + "os": "Windows" + } + ] + } + }, + { + "args": [ + "webgl_conformance", + "--show-stdout", + "--browser=debug", + "-v", + "--extra-browser-args=\"--enable-logging=stderr --js-flags=--expose-gc --use-angle=gl\"" + ], + "isolate_name": "telemetry_gpu_test", + "name": "webgl_conformance_gl_tests", + "override_compile_targets": [ + "telemetry_gpu_test_run" + ], + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "gpu": "10de:104a", + "os": "Windows" + } + ] + } + }, + { + "args": [ + "webgl_conformance", + "--show-stdout", + "--browser=debug", + "-v", + "--extra-browser-args=\"--enable-logging=stderr --js-flags=--expose-gc\"", + "--webgl-conformance-version=2.0.0", + "--webgl2-only=true" + ], + "isolate_name": "telemetry_gpu_test", + "name": "webgl2_conformance_tests", + "override_compile_targets": [ + "telemetry_gpu_test_run" + ], + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "gpu": "10de:104a", + "os": "Windows" + } + ] + } + } + ] + }, + "Win7 NextGen Release (NVIDIA)": { + "gtest_tests": [ + { + "args": [ + "--use-gpu-in-tests" + ], + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "gpu": "10de:104a", + "os": "Windows" + } + ] + }, + "test": "angle_unittests" + }, + { + "args": [ + "--use-gpu-in-tests" + ], + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "gpu": "10de:104a", + "os": "Windows" + } + ] + }, + "test": "audio_unittests" + }, + { + "args": [ + "--use-gpu-in-tests" + ], + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "gpu": "10de:104a", + "os": "Windows" + } + ] + }, + "test": "content_gl_tests" + }, + { + "args": [ + "--use-gpu-in-tests" + ], + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "gpu": "10de:104a", + "os": "Windows" + } + ] + }, + "test": "gl_tests" + }, + { + "args": [ + "--use-gpu-in-tests" + ], + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "gpu": "10de:104a", + "os": "Windows" + } + ] + }, + "test": "gl_unittests" + }, + { + "override_compile_targets": [ + "tab_capture_end2end_tests_run" + ], + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "gpu": "10de:104a", + "os": "Windows" + } + ] + }, + "test": "tab_capture_end2end_tests" + } + ], + "isolated_scripts": [ + { + "args": [ + "context_lost", + "--show-stdout", + "--browser=release", + "-v", + "--extra-browser-args=\"--enable-logging=stderr --js-flags=--expose-gc\"" + ], + "isolate_name": "telemetry_gpu_test", + "name": "context_lost_tests", + "override_compile_targets": [ + "telemetry_gpu_test_run" + ], + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "gpu": "10de:104a", + "os": "Windows" + } + ] + } + }, + { + "args": [ + "gpu_process", + "--show-stdout", + "--browser=release", + "-v", + "--extra-browser-args=\"--enable-logging=stderr --js-flags=--expose-gc\"" + ], + "isolate_name": "telemetry_gpu_test", + "name": "gpu_process_launch_tests", + "override_compile_targets": [ + "telemetry_gpu_test_run" + ], + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "gpu": "10de:104a", + "os": "Windows" + } + ] + } + }, + { + "args": [ + "gpu_rasterization", + "--show-stdout", + "--browser=release", + "-v", + "--extra-browser-args=\"--enable-logging=stderr --js-flags=--expose-gc\"" + ], + "isolate_name": "telemetry_gpu_test", + "name": "gpu_rasterization_tests", + "override_compile_targets": [ + "telemetry_gpu_test_run" + ], + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "gpu": "10de:104a", + "os": "Windows" + } + ] + } + }, + { + "args": [ + "hardware_accelerated_feature", + "--show-stdout", + "--browser=release", + "-v", + "--extra-browser-args=\"--enable-logging=stderr --js-flags=--expose-gc\"" + ], + "isolate_name": "telemetry_gpu_test", + "name": "hardware_accelerated_feature_tests", + "override_compile_targets": [ + "telemetry_gpu_test_run" + ], + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "gpu": "10de:104a", + "os": "Windows" + } + ] + } + }, + { + "args": [ + "maps", + "--show-stdout", + "--browser=release", + "-v", + "--extra-browser-args=\"--enable-logging=stderr --js-flags=--expose-gc\"" + ], + "isolate_name": "telemetry_gpu_test", + "name": "maps_pixel_test", + "override_compile_targets": [ + "telemetry_gpu_test_run" + ], + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "gpu": "10de:104a", + "os": "Windows" + } + ] + } + }, + { + "args": [ + "memory_test", + "--show-stdout", + "--browser=release", + "-v", + "--extra-browser-args=\"--enable-logging=stderr --js-flags=--expose-gc\"" + ], + "isolate_name": "telemetry_gpu_test", + "name": "memory_test", + "override_compile_targets": [ + "telemetry_gpu_test_run" + ], + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "gpu": "10de:104a", + "os": "Windows" + } + ] + } + }, + { + "args": [ + "pixel", + "--show-stdout", + "--browser=release", + "-v", + "--extra-browser-args=\"--enable-logging=stderr --js-flags=--expose-gc\"", + "--upload-refimg-to-cloud-storage", + "--refimg-cloud-storage-bucket", + "chromium-gpu-archive/reference-images", + "--os-type", + "linux" + ], + "isolate_name": "telemetry_gpu_test", + "name": "pixel_test", + "override_compile_targets": [ + "telemetry_gpu_test_run" + ], + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "gpu": "10de:104a", + "os": "Windows" + } + ] + } + }, + { + "args": [ + "screenshot_sync", + "--show-stdout", + "--browser=release", + "-v", + "--extra-browser-args=\"--enable-logging=stderr --js-flags=--expose-gc\"" + ], + "isolate_name": "telemetry_gpu_test", + "name": "screenshot_sync_tests", + "override_compile_targets": [ + "telemetry_gpu_test_run" + ], + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "gpu": "10de:104a", + "os": "Windows" + } + ] + } + }, + { + "args": [ + "trace_test", + "--show-stdout", + "--browser=release", + "-v", + "--extra-browser-args=\"--enable-logging=stderr --js-flags=--expose-gc\"" + ], + "isolate_name": "telemetry_gpu_test", + "name": "trace_test", + "override_compile_targets": [ + "telemetry_gpu_test_run" + ], + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "gpu": "10de:104a", + "os": "Windows" + } + ] + } + }, + { + "args": [ + "webgl_conformance", + "--show-stdout", + "--browser=release", + "-v", + "--extra-browser-args=\"--enable-logging=stderr --js-flags=--expose-gc\"" + ], + "isolate_name": "telemetry_gpu_test", + "name": "webgl_conformance_tests", + "override_compile_targets": [ + "telemetry_gpu_test_run" + ], + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "gpu": "10de:104a", + "os": "Windows" + } + ] + } + }, + { + "args": [ + "webgl_conformance", + "--show-stdout", + "--browser=debug", + "-v", + "--extra-browser-args=\"--enable-logging=stderr --js-flags=--expose-gc --use-angle=d3d9\"" + ], + "isolate_name": "telemetry_gpu_test", + "name": "webgl_conformance_d3d9_tests", + "override_compile_targets": [ + "telemetry_gpu_test_run" + ], + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "gpu": "10de:104a", + "os": "Windows" + } + ] + } + }, + { + "args": [ + "webgl_conformance", + "--show-stdout", + "--browser=debug", + "-v", + "--extra-browser-args=\"--enable-logging=stderr --js-flags=--expose-gc --use-angle=gl\"" + ], + "isolate_name": "telemetry_gpu_test", + "name": "webgl_conformance_gl_tests", + "override_compile_targets": [ + "telemetry_gpu_test_run" + ], + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "gpu": "10de:104a", + "os": "Windows" + } + ] + } + }, + { + "args": [ + "webgl_conformance", + "--show-stdout", + "--browser=release", + "-v", + "--extra-browser-args=\"--enable-logging=stderr --js-flags=--expose-gc\"", + "--webgl-conformance-version=2.0.0", + "--webgl2-only=true" + ], + "isolate_name": "telemetry_gpu_test", + "name": "webgl2_conformance_tests", + "override_compile_targets": [ + "telemetry_gpu_test_run" + ], + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "gpu": "10de:104a", + "os": "Windows" + } + ] + } + } + ] } }
diff --git a/testing/libfuzzer/fuzzers/BUILD.gn b/testing/libfuzzer/fuzzers/BUILD.gn index abcd7ab..26a8a64e 100644 --- a/testing/libfuzzer/fuzzers/BUILD.gn +++ b/testing/libfuzzer/fuzzers/BUILD.gn
@@ -216,7 +216,7 @@ "//third_party/pdfium:pdfium_config", "//v8:external_startup_data", ] - dict = "pdf.dict" + dict = "dicts/pdf.dict" } fuzzer_test("websocket_frame_parser_fuzzer") { @@ -254,6 +254,7 @@ deps = [ "//third_party/sqlite", ] + dict = "dicts/sql.dict" } fuzzer_test("libxml_xml_read_memory_fuzzer") {
diff --git a/testing/libfuzzer/fuzzers/pdf.dict b/testing/libfuzzer/fuzzers/dicts/pdf.dict similarity index 100% rename from testing/libfuzzer/fuzzers/pdf.dict rename to testing/libfuzzer/fuzzers/dicts/pdf.dict
diff --git a/testing/libfuzzer/fuzzers/dicts/sql.dict b/testing/libfuzzer/fuzzers/dicts/sql.dict new file mode 100644 index 0000000..5834247 --- /dev/null +++ b/testing/libfuzzer/fuzzers/dicts/sql.dict
@@ -0,0 +1,282 @@ +# +# AFL dictionary for SQL +# ---------------------- +# +# Modeled based on SQLite documentation, contains some number of SQLite +# extensions. Other dialects of SQL may benefit from customized dictionaries. +# +# If you append @1 to the file name when loading this dictionary, afl-fuzz +# will also additionally load a selection of pragma keywords that are very +# specific to SQLite (and are probably less interesting from the security +# standpoint, because they are usually not allowed in non-privileged +# contexts). +# +# Created by Michal Zalewski <lcamtuf@google.com> +# + +function_abs=" abs(1)" +function_avg=" avg(1)" +function_changes=" changes()" +function_char=" char(1)" +function_coalesce=" coalesce(1,1)" +function_count=" count(1)" +function_date=" date(1,1,1)" +function_datetime=" datetime(1,1,1)" +function_decimal=" decimal(1,1)" +function_glob=" glob(1,1)" +function_group_concat=" group_concat(1,1)" +function_hex=" hex(1)" +function_ifnull=" ifnull(1,1)" +function_instr=" instr(1,1)" +function_julianday=" julianday(1,1,1)" +function_last_insert_rowid=" last_insert_rowid()" +function_length=" length(1)" +function_like=" like(1,1)" +function_likelihood=" likelihood(1,1)" +function_likely=" likely(1)" +function_load_extension=" load_extension(1,1)" +function_lower=" lower(1)" +function_ltrim=" ltrim(1,1)" +function_max=" max(1,1)" +function_min=" min(1,1)" +function_nullif=" nullif(1,1)" +function_printf=" printf(1,1)" +function_quote=" quote(1)" +function_random=" random()" +function_randomblob=" randomblob(1)" +function_replace=" replace(1,1,1)" +function_round=" round(1,1)" +function_rtrim=" rtrim(1,1)" +function_soundex=" soundex(1)" +function_sqlite_compileoption_get=" sqlite_compileoption_get(1)" +function_sqlite_compileoption_used=" sqlite_compileoption_used(1)" +function_sqlite_source_id=" sqlite_source_id()" +function_sqlite_version=" sqlite_version()" +function_strftime=" strftime(1,1,1,1)" +function_substr=" substr(1,1,1)" +function_sum=" sum(1)" +function_time=" time(1,1,1)" +function_total=" total(1)" +function_total_changes=" total_changes()" +function_trim=" trim(1,1)" +function_typeof=" typeof(1)" +function_unicode=" unicode(1)" +function_unlikely=" unlikely(1)" +function_upper=" upper(1)" +function_varchar=" varchar(1)" +function_zeroblob=" zeroblob(1)" + +keyword_ABORT="ABORT" +keyword_ACTION="ACTION" +keyword_ADD="ADD" +keyword_AFTER="AFTER" +keyword_ALL="ALL" +keyword_ALTER="ALTER" +keyword_ANALYZE="ANALYZE" +keyword_AND="AND" +keyword_AS="AS" +keyword_ASC="ASC" +keyword_ATTACH="ATTACH" +keyword_AUTOINCREMENT="AUTOINCREMENT" +keyword_BEFORE="BEFORE" +keyword_BEGIN="BEGIN" +keyword_BETWEEN="BETWEEN" +keyword_BY="BY" +keyword_CASCADE="CASCADE" +keyword_CASE="CASE" +keyword_CAST="CAST" +keyword_CHECK="CHECK" +keyword_COLLATE="COLLATE" +keyword_COLUMN="COLUMN" +keyword_COMMIT="COMMIT" +keyword_CONFLICT="CONFLICT" +keyword_CONSTRAINT="CONSTRAINT" +keyword_CREATE="CREATE" +keyword_CROSS="CROSS" +keyword_CURRENT_DATE="CURRENT_DATE" +keyword_CURRENT_TIME="CURRENT_TIME" +keyword_CURRENT_TIMESTAMP="CURRENT_TIMESTAMP" +keyword_DATABASE="DATABASE" +keyword_DEFAULT="DEFAULT" +keyword_DEFERRABLE="DEFERRABLE" +keyword_DEFERRED="DEFERRED" +keyword_DELETE="DELETE" +keyword_DESC="DESC" +keyword_DETACH="DETACH" +keyword_DISTINCT="DISTINCT" +keyword_DROP="DROP" +keyword_EACH="EACH" +keyword_ELSE="ELSE" +keyword_END="END" +keyword_ESCAPE="ESCAPE" +keyword_EXCEPT="EXCEPT" +keyword_EXCLUSIVE="EXCLUSIVE" +keyword_EXISTS="EXISTS" +keyword_EXPLAIN="EXPLAIN" +keyword_FAIL="FAIL" +keyword_FOR="FOR" +keyword_FOREIGN="FOREIGN" +keyword_FROM="FROM" +keyword_FULL="FULL" +keyword_GLOB="GLOB" +keyword_GROUP="GROUP" +keyword_HAVING="HAVING" +keyword_IF="IF" +keyword_IGNORE="IGNORE" +keyword_IMMEDIATE="IMMEDIATE" +keyword_IN="IN" +keyword_INDEX="INDEX" +keyword_INDEXED="INDEXED" +keyword_INITIALLY="INITIALLY" +keyword_INNER="INNER" +keyword_INSERT="INSERT" +keyword_INSTEAD="INSTEAD" +keyword_INTERSECT="INTERSECT" +keyword_INTO="INTO" +keyword_IS="IS" +keyword_ISNULL="ISNULL" +keyword_JOIN="JOIN" +keyword_KEY="KEY" +keyword_LEFT="LEFT" +keyword_LIKE="LIKE" +keyword_LIMIT="LIMIT" +keyword_MATCH="MATCH" +keyword_NATURAL="NATURAL" +keyword_NO="NO" +keyword_NOT="NOT" +keyword_NOTNULL="NOTNULL" +keyword_NULL="NULL" +keyword_OF="OF" +keyword_OFFSET="OFFSET" +keyword_ON="ON" +keyword_OR="OR" +keyword_ORDER="ORDER" +keyword_OUTER="OUTER" +keyword_PLAN="PLAN" +keyword_PRAGMA="PRAGMA" +keyword_PRIMARY="PRIMARY" +keyword_QUERY="QUERY" +keyword_RAISE="RAISE" +keyword_RECURSIVE="RECURSIVE" +keyword_REFERENCES="REFERENCES" +keyword_REGEXP="REGEXP" +keyword_REINDEX="REINDEX" +keyword_RELEASE="RELEASE" +keyword_RENAME="RENAME" +keyword_REPLACE="REPLACE" +keyword_RESTRICT="RESTRICT" +keyword_RIGHT="RIGHT" +keyword_ROLLBACK="ROLLBACK" +keyword_ROW="ROW" +keyword_SAVEPOINT="SAVEPOINT" +keyword_SELECT="SELECT" +keyword_SET="SET" +keyword_TABLE="TABLE" +keyword_TEMP="TEMP" +keyword_TEMPORARY="TEMPORARY" +keyword_THEN="THEN" +keyword_TO="TO" +keyword_TRANSACTION="TRANSACTION" +keyword_TRIGGER="TRIGGER" +keyword_UNION="UNION" +keyword_UNIQUE="UNIQUE" +keyword_UPDATE="UPDATE" +keyword_USING="USING" +keyword_VACUUM="VACUUM" +keyword_VALUES="VALUES" +keyword_VIEW="VIEW" +keyword_VIRTUAL="VIRTUAL" +keyword_WHEN="WHEN" +keyword_WHERE="WHERE" +keyword_WITH="WITH" +keyword_WITHOUT="WITHOUT" + +operator_concat=" || " +operator_ebove_eq=" >=" + +snippet_1eq1=" 1=1" +snippet_at=" @1" +snippet_backticks=" `a`" +snippet_blob=" blob" +snippet_brackets=" [a]" +snippet_colon=" :1" +snippet_comment=" /* */" +snippet_date="2001-01-01" +snippet_dollar=" $1" +snippet_dotref=" a.b" +snippet_fmtY="%Y" +snippet_int=" int" +snippet_neg1=" -1" +snippet_pair=" a,b" +snippet_parentheses=" (1)" +snippet_plus2days="+2 days" +snippet_qmark=" ?1" +snippet_semicolon=" ;" +snippet_star=" *" +snippet_string_pair=" \"a\",\"b\"" + +string_dbl_q=" \"a\"" +string_escaped_q=" 'a''b'" +string_single_q=" 'a'" + +pragma_application_id@1=" application_id" +pragma_auto_vacuum@1=" auto_vacuum" +pragma_automatic_index@1=" automatic_index" +pragma_busy_timeout@1=" busy_timeout" +pragma_cache_size@1=" cache_size" +pragma_cache_spill@1=" cache_spill" +pragma_case_sensitive_like@1=" case_sensitive_like" +pragma_checkpoint_fullfsync@1=" checkpoint_fullfsync" +pragma_collation_list@1=" collation_list" +pragma_compile_options@1=" compile_options" +pragma_count_changes@1=" count_changes" +pragma_data_store_directory@1=" data_store_directory" +pragma_database_list@1=" database_list" +pragma_default_cache_size@1=" default_cache_size" +pragma_defer_foreign_keys@1=" defer_foreign_keys" +pragma_empty_result_callbacks@1=" empty_result_callbacks" +pragma_encoding@1=" encoding" +pragma_foreign_key_check@1=" foreign_key_check" +pragma_foreign_key_list@1=" foreign_key_list" +pragma_foreign_keys@1=" foreign_keys" +pragma_freelist_count@1=" freelist_count" +pragma_full_column_names@1=" full_column_names" +pragma_fullfsync@1=" fullfsync" +pragma_ignore_check_constraints@1=" ignore_check_constraints" +pragma_incremental_vacuum@1=" incremental_vacuum" +pragma_index_info@1=" index_info" +pragma_index_list@1=" index_list" +pragma_integrity_check@1=" integrity_check" +pragma_journal_mode@1=" journal_mode" +pragma_journal_size_limit@1=" journal_size_limit" +pragma_legacy_file_format@1=" legacy_file_format" +pragma_locking_mode@1=" locking_mode" +pragma_max_page_count@1=" max_page_count" +pragma_mmap_size@1=" mmap_size" +pragma_page_count@1=" page_count" +pragma_page_size@1=" page_size" +pragma_parser_trace@1=" parser_trace" +pragma_query_only@1=" query_only" +pragma_quick_check@1=" quick_check" +pragma_read_uncommitted@1=" read_uncommitted" +pragma_recursive_triggers@1=" recursive_triggers" +pragma_reverse_unordered_selects@1=" reverse_unordered_selects" +pragma_schema_version@1=" schema_version" +pragma_secure_delete@1=" secure_delete" +pragma_short_column_names@1=" short_column_names" +pragma_shrink_memory@1=" shrink_memory" +pragma_soft_heap_limit@1=" soft_heap_limit" +pragma_stats@1=" stats" +pragma_synchronous@1=" synchronous" +pragma_table_info@1=" table_info" +pragma_temp_store@1=" temp_store" +pragma_temp_store_directory@1=" temp_store_directory" +pragma_threads@1=" threads" +pragma_user_version@1=" user_version" +pragma_vdbe_addoptrace@1=" vdbe_addoptrace" +pragma_vdbe_debug@1=" vdbe_debug" +pragma_vdbe_listing@1=" vdbe_listing" +pragma_vdbe_trace@1=" vdbe_trace" +pragma_wal_autocheckpoint@1=" wal_autocheckpoint" +pragma_wal_checkpoint@1=" wal_checkpoint" +pragma_writable_schema@1=" writable_schema"
diff --git a/testing/variations/fieldtrial_testing_config_android.json b/testing/variations/fieldtrial_testing_config_android.json index 73e6282..fe0c9d97 100644 --- a/testing/variations/fieldtrial_testing_config_android.json +++ b/testing/variations/fieldtrial_testing_config_android.json
@@ -36,14 +36,7 @@ { "group_name": "OptOut", "params": { - "enabled": "true", - "promo_on_limited_taps": "true", - "promo_opt_out": "true", - "tap_prefetch_limit_for_decided": "50", - "tap_prefetch_limit_for_undecided": "20", - "tap_resolve_limit_for_decided": "50", - "tap_resolve_limit_for_undecided": "20", - "tap_triggered_promo_limit": "50" + "enabled": "true" } } ], @@ -293,6 +286,11 @@ "group_name": "Enabled" } ], + "SpdyEnableDependencies": [ + { + "group_name": "Enable" + } + ], "SpeculativeResourcePrefetching": [ { "group_name": "v=1a:Prefetching=Enabled:Predictor=Url"
diff --git a/testing/variations/fieldtrial_testing_config_chromeos.json b/testing/variations/fieldtrial_testing_config_chromeos.json index a497a4e8..4d5fb40 100644 --- a/testing/variations/fieldtrial_testing_config_chromeos.json +++ b/testing/variations/fieldtrial_testing_config_chromeos.json
@@ -113,6 +113,11 @@ "group_name": "Enabled" } ], + "SpdyEnableDependencies": [ + { + "group_name": "Enable" + } + ], "StrictSecureCookies": [ { "group_name": "Enabled"
diff --git a/testing/variations/fieldtrial_testing_config_ios.json b/testing/variations/fieldtrial_testing_config_ios.json index 53a49dbb..f7bbd07 100644 --- a/testing/variations/fieldtrial_testing_config_ios.json +++ b/testing/variations/fieldtrial_testing_config_ios.json
@@ -51,6 +51,11 @@ "group_name": "Enabled" } ], + "SpdyEnableDependencies": [ + { + "group_name": "Enable" + } + ], "SyncHttpContentCompression": [ { "group_name": "Enabled"
diff --git a/testing/variations/fieldtrial_testing_config_linux.json b/testing/variations/fieldtrial_testing_config_linux.json index 421ffdd..1d8dec0b 100644 --- a/testing/variations/fieldtrial_testing_config_linux.json +++ b/testing/variations/fieldtrial_testing_config_linux.json
@@ -152,6 +152,11 @@ "group_name": "Enabled" } ], + "SpdyEnableDependencies": [ + { + "group_name": "Enable" + } + ], "StrictSecureCookies": [ { "group_name": "Enabled"
diff --git a/testing/variations/fieldtrial_testing_config_mac.json b/testing/variations/fieldtrial_testing_config_mac.json index f3e916e..f7502fe 100644 --- a/testing/variations/fieldtrial_testing_config_mac.json +++ b/testing/variations/fieldtrial_testing_config_mac.json
@@ -162,6 +162,11 @@ "group_name": "Enabled" } ], + "SpdyEnableDependencies": [ + { + "group_name": "Enable" + } + ], "StrictSecureCookies": [ { "group_name": "Enabled"
diff --git a/testing/variations/fieldtrial_testing_config_win.json b/testing/variations/fieldtrial_testing_config_win.json index 2b2eccc0..78a53ee8 100644 --- a/testing/variations/fieldtrial_testing_config_win.json +++ b/testing/variations/fieldtrial_testing_config_win.json
@@ -236,6 +236,11 @@ "group_name": "enforce_always_with_extensions_and_dse" } ], + "SpdyEnableDependencies": [ + { + "group_name": "Enable" + } + ], "StrictSecureCookies": [ { "group_name": "Enabled"
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations index b31f8ed..7185d68 100644 --- a/third_party/WebKit/LayoutTests/TestExpectations +++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -88,8 +88,6 @@ crbug.com/563650 inspector/elements/css-rule-hover-highlights-selectors.html [ Pass Failure ] -crbug.com/570317 fast/images/color-profile-munsell-adobe-to-srgb.html [ NeedsManualRebaseline ] - crbug.com/522641 inspector/elements/styles-4/styles-update-links.html [ Pass Timeout ] crbug.com/522645 [ Linux ] virtual/android/fullscreen/video-fixed-background.html [ Failure Pass ] crbug.com/522647 http/tests/notifications/close-dispatch-asynchronous.html [ Failure Pass ] @@ -301,7 +299,6 @@ crbug.com/498539 [ Win7 ] inspector/elements/styles-3/selector-list.html [ Failure Pass ] crbug.com/498539 [ Win7 Debug ] inspector/elements/styles-3/styles-computed-trace.html [ Crash Pass ] crbug.com/498539 [ Win7 ] inspector/elements/styles-4/styles-update-from-js.html [ Crash Pass ] -crbug.com/565059 [ Debug ] inspector/console/console-uncaught-promise.html [ Crash Pass ] crbug.com/571478 [ Win10 XP ] svg/custom/text-match-highlight.html [ Failure Pass Crash ] @@ -431,13 +428,13 @@ crbug.com/542660 fast/inline/nested-text-descendants.html [ Failure ] # Ref tests that pass but causes 1px diff on images. -crbug.com/391260 [ Win ] fast/text/international/dir-isolation/dir-isolation-002c.html [ Failure ] -crbug.com/391260 [ Mac ] fast/text/international/dir-isolation/dir-isolation-006a.html [ Failure ] -crbug.com/391260 [ Mac ] fast/text/international/dir-isolation/dir-isolation-006b.html [ Failure ] -crbug.com/391260 [ Mac Win ] fast/text/international/dir-isolation/dir-isolation-006c.html [ Failure ] -crbug.com/391260 [ Mac ] fast/text/international/dir-isolation/dir-isolation-009a.html [ Failure ] -crbug.com/391260 [ Mac ] fast/text/international/dir-isolation/dir-isolation-009b.html [ Failure ] -crbug.com/391260 [ Mac ] fast/text/international/dir-isolation/dir-isolation-009c.html [ Failure ] +crbug.com/391260 [ Win ] imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-002c.html [ Failure ] +crbug.com/391260 [ Mac ] imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-006a.html [ Failure ] +crbug.com/391260 [ Mac ] imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-006b.html [ Failure ] +crbug.com/391260 [ Mac Win ] imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-006c.html [ Failure ] +crbug.com/391260 [ Mac ] imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-009a.html [ Failure ] +crbug.com/391260 [ Mac ] imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-009b.html [ Failure ] +crbug.com/391260 [ Mac ] imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-009c.html [ Failure ] # Ref tests that needs investigation. crbug.com/404597 [ Mac ] fast/css3-text/css3-text-justify/text-justify-crash.html [ Failure ] @@ -882,7 +879,6 @@ crbug.com/498021 [ Linux ] fast/text/emphasis-complex.html [ Failure ] crbug.com/498021 [ Linux ] fast/text/international/danda-space.html [ Failure ] crbug.com/498021 [ Linux ] fast/text/international/hindi-whitespace.html [ Failure ] -crbug.com/498021 [ Linux ] fast/text/international/thai-line-breaks.html [ Failure ] crbug.com/498021 [ Linux ] fast/text/selection-multiple-runs.html [ Failure ] crbug.com/498021 [ Linux ] editing/pasteboard/4944770-2.html [ Failure ] crbug.com/498021 [ Linux ] fast/encoding/invalid-UTF-8.html [ Failure ] @@ -965,7 +961,6 @@ # Temporarily disabled after chromium change crbug.com/492511 [ Mac ] fast/text/atsui-negative-spacing-features.html [ Failure ] -crbug.com/492511 [ Mac ] fast/text/atsui-spacing-features.html [ Failure ] crbug.com/492511 [ Mac ] fast/text/international/arabic-justify.html [ Failure ] # Ref tests that fail due to differences in inline box structure, even though they contain the same text. @@ -1073,11 +1068,9 @@ crbug.com/521730 [ Win10 ] fast/text-autosizing/tables/wide-specified-width.html [ Failure ] crbug.com/521730 [ Win10 ] fast/text/atsui-kerning-and-ligatures.html [ Failure ] crbug.com/521730 [ Win10 ] fast/text/atsui-multiple-renderers.html [ Failure ] -crbug.com/521730 [ Win10 ] fast/text/atsui-spacing-features.html [ Failure ] crbug.com/521730 [ Win10 ] fast/text/basic/009.html [ Failure ] crbug.com/521730 [ Win10 ] fast/text/basic/generic-family-changes.html [ Failure ] crbug.com/521730 [ Win10 ] fast/text/capitalize-boundaries.html [ Failure ] -crbug.com/521730 [ Win10 ] fast/text/drawBidiText.html [ Failure ] crbug.com/521730 [ Win10 ] fast/text/emoji-web-font.html [ Failure ] crbug.com/521730 [ Win10 ] fast/text/firstline/001.html [ Failure ] crbug.com/521730 [ Win10 ] fast/text/firstline/002.html [ Failure ] @@ -1288,17 +1281,8 @@ crbug.com/568778 [ XP ] tables/mozilla_expected_failures/bugs/97619.html [ Failure ] crbug.com/568778 [ XP ] tables/mozilla_expected_failures/bugs/bug85016.html [ Failure ] -# FIXME crbug.com/570401 bad rebaselines submited, wrong size scale factor affecting the text result expected -# backing size, some image results twice a big as expected, or become all-white squares. -crbug.com/569919 compositing/color-matching/image-color-matching.html [ Failure ] -crbug.com/569919 fast/canvas/canvas-toBlob-jpeg-maximum-quality.html [ Failure ] -crbug.com/569919 fast/canvas/canvas-toBlob-jpeg-medium-quality.html [ Failure ] -crbug.com/569919 fast/canvas/canvas-toBlob-webp-maximum-quality.html [ Failure ] -crbug.com/570401 paint/selection/selection-within-composited-scroller.html [ NeedsManualRebaseline ] -crbug.com/570401 fast/canvas/canvas-shadow-source-in.html [ Failure ] -crbug.com/570401 virtual/display_list_2d_canvas/fast/canvas/canvas-shadow-source-in.html [ Failure ] -crbug.com/570401 compositing/overflow/updating-scrolling-content.html [ Failure ] -crbug.com/570401 compositing/repaint/should-not-clip-composited-overflow-scrolling-layer.html [ Failure ] +crbug.com/504837 [ XP ] svg/batik/filters/feTile.svg [ Failure ] +crbug.com/504837 [ XP ] svg/filters/feTile.svg [ Failure ] crbug.com/568867 [ Win Debug ] transforms/3d/point-mapping/3d-point-mapping-deep.html [ Failure ] crbug.com/568867 [ Win Debug ] transforms/3d/point-mapping/3d-point-mapping-preserve-3d.html [ Failure ] @@ -1352,8 +1336,6 @@ crbug.com/572726 inspector/tracing/timeline-node-reference.html [ Timeout Pass Crash ] -crbug.com/561426 [ XP ] fast/text/decorations-with-text-combine.html [ NeedsRebaseline ] -crbug.com/561426 [ XP ] fast/text/emphasis.html [ NeedsRebaseline ] -crbug.com/561426 [ XP ] fast/text/emphasis-combined-text.html [ NeedsRebaseline ] -crbug.com/561426 [ XP ] fast/text/emphasis-vertical.html [ NeedsRebaseline ] -crbug.com/574189 [ Mac10.8 XP ] virtual/gpu/fast/canvas/image-object-in-canvas.html [ NeedsRebaseline ] +crbug.com/575037 [ Android ] webaudio/codec-tests/aac/vbr-128kbps-44khz.html [ Skip ] +crbug.com/575037 [ Android ] webaudio/codec-tests/mp3/128kbps-44khz.html [ Skip ] +crbug.com/575037 [ Android ] webaudio/codec-tests/wav/24bit-22khz-resample.html [ Skip ]
diff --git a/third_party/WebKit/LayoutTests/W3CImportExpectations b/third_party/WebKit/LayoutTests/W3CImportExpectations index 7956625..75fb2b12c 100644 --- a/third_party/WebKit/LayoutTests/W3CImportExpectations +++ b/third_party/WebKit/LayoutTests/W3CImportExpectations
@@ -171,6 +171,7 @@ imported/web-platform-tests/tools [ Skip ] imported/web-platform-tests/touch-events [ Skip ] imported/web-platform-tests/typedarrays [ Skip ] +imported/web-platform-tests/uievents [ Skip ] imported/web-platform-tests/url [ Skip ] ## Owners: jsbell@chromium.org # imported/web-platform-tests/user-timing [ Pass ] @@ -614,3 +615,6 @@ # crbug.com/441355: MutationObserver incorrect for replaceChild (causes timeout) imported/web-platform-tests/dom/nodes/MutationObserver-childList.html [ Skip ] + +# crbug.com/574461: update-w3c-deps imports .py file with x-bit cleared +imported/web-platform-tests/dom/nodes/Document-createElement-namespace-tests/generate.py [ Skip ]
diff --git a/third_party/WebKit/LayoutTests/css-parser/counter-parsing.html b/third_party/WebKit/LayoutTests/css-parser/counter-parsing.html index e1b89fe..c00ec0c 100644 --- a/third_party/WebKit/LayoutTests/css-parser/counter-parsing.html +++ b/third_party/WebKit/LayoutTests/css-parser/counter-parsing.html
@@ -3,7 +3,8 @@ <script src="../resources/testharnessreport.js"></script> <script src="resources/property-parsing-test.js"></script> <script> -assert_valid_value("counterIncrement", "hello world 999", "hello 1, world 999"); +assert_valid_value("counterIncrement", "hello world 999", "hello 1 world 999"); +assert_valid_value("counterIncrement", "a 1234567"); assert_invalid_value("counterIncrement", 'hello "world"'); assert_invalid_value("counterIncrement", "40"); assert_invalid_value("counterReset", 'c 10 20');
diff --git a/third_party/WebKit/LayoutTests/css-parser/whitespace-declaration.html b/third_party/WebKit/LayoutTests/css-parser/whitespace-declaration.html new file mode 100644 index 0000000..3f45c7c --- /dev/null +++ b/third_party/WebKit/LayoutTests/css-parser/whitespace-declaration.html
@@ -0,0 +1,15 @@ +<!DOCTYPE html> +<script src="../resources/testharness.js"></script> +<script src="../resources/testharnessreport.js"></script> +<script src="../fast/css/getComputedStyle/resources/computed-style-listing.js"></script> +<div id="target"></div> +<script> +test(function() { + var style = getComputedStyle(target); + for (var i = 0; i < style.length; i++) { + var property = style.item(i); + assert_false(CSS.supports(property, ''), property + ":;"); + assert_false(CSS.supports(property, ' '), property + ": ;"); + } +}, 'Verify that property values consisting of only whitespace are not accepted.'); +</script>
diff --git a/third_party/WebKit/LayoutTests/editing/selection/selectallchildren-crash.html b/third_party/WebKit/LayoutTests/editing/selection/selectallchildren-crash.html index a06510a..c5cb80e 100644 --- a/third_party/WebKit/LayoutTests/editing/selection/selectallchildren-crash.html +++ b/third_party/WebKit/LayoutTests/editing/selection/selectallchildren-crash.html
@@ -30,11 +30,6 @@ function selectLater() { selection.selectAllChildren(doc2); - - // TODO(tkent): A workdaround of a testharnessreport.js issue. Without this, - // testharnessreport.js has a null access. - if (!document.documentElement) - document.appendChild(document.createElement('html')); test.done(); } </script>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-imageSmoothingQuality.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-imageSmoothingQuality.html index b3f327e..c02d6e5 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-imageSmoothingQuality.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-imageSmoothingQuality.html
@@ -23,7 +23,7 @@ } for (var x = 0; x < source.width; x++) { - for (var y = 2; y < 4; y++) { + for (var y = 1; y < 3; y++) { drawBlackDot(x, y); } }
diff --git a/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-auto-flow-resolution.html b/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-auto-flow-resolution.html index 88d7f2f..cf8bb80 100644 --- a/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-auto-flow-resolution.html +++ b/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-auto-flow-resolution.html
@@ -22,8 +22,6 @@ grid-column: auto / 8; } -/* These 2 classes forces the grid to be sized after the grid-{end|after}, thus end up in the - first row / columns. */ .negativeOverflowingRowFirstColumn { grid-row: auto / -10; grid-column: 1; @@ -132,15 +130,15 @@ <div class="unconstrainedContainer"> <div class="grid bigGrid gridAutoFlowColumnDense"> - <div class="sizedToGridArea negativeOverflowingRowFirstColumn" data-offset-x="0" data-offset-y="0" data-expected-width="50" data-expected-height="50">XXXXX XXXXX XXXXX</div> - <div class="sizedToGridArea secondRowNegativeOverflowingColumn" data-offset-x="0" data-offset-y="50" data-expected-width="50" data-expected-height="100">XXXXX XXXXX XXXXX</div> + <div class="sizedToGridArea negativeOverflowingRowFirstColumn" data-offset-x="170" data-offset-y="0" data-expected-width="50" data-expected-height="30">XXXXX XXXXX XXXXX</div> + <div class="sizedToGridArea secondRowNegativeOverflowingColumn" data-offset-x="0" data-offset-y="80" data-expected-width="170" data-expected-height="100">XXXXX XXXXX XXXXX</div> </div> </div> <div class="unconstrainedContainer"> <div class="grid bigGrid gridAutoFlowRowDense"> - <div class="sizedToGridArea negativeOverflowingRowFirstColumn" data-offset-x="0" data-offset-y="0" data-expected-width="50" data-expected-height="50">XXXXX XXXXX XXXXX</div> - <div class="sizedToGridArea secondRowNegativeOverflowingColumn" data-offset-x="0" data-offset-y="50" data-expected-width="50" data-expected-height="100">XXXXX XXXXX XXXXX</div> + <div class="sizedToGridArea negativeOverflowingRowFirstColumn" data-offset-x="170" data-offset-y="0" data-expected-width="50" data-expected-height="30">XXXXX XXXXX XXXXX</div> + <div class="sizedToGridArea secondRowNegativeOverflowingColumn" data-offset-x="0" data-offset-y="80" data-expected-width="170" data-expected-height="100">XXXXX XXXXX XXXXX</div> </div> </div>
diff --git a/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-item-negative-position-resolution.html b/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-item-negative-position-resolution.html index b63c6fb..8a7152b 100644 --- a/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-item-negative-position-resolution.html +++ b/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-item-negative-position-resolution.html
@@ -158,8 +158,8 @@ </div> <div style="position: relative"> -<div class="grid" data-expected-width="150" data-expected-height="150"> - <div class="sizedToGridArea negativeEndPositionStartSpanInRowDirection" data-offset-x="0" data-offset-y="0" data-expected-width="50" data-expected-height="150"></div> +<div class="grid" data-expected-width="150" data-expected-height="750"> + <div class="sizedToGridArea negativeEndPositionStartSpanInRowDirection" data-offset-x="0" data-offset-y="0" data-expected-width="50" data-expected-height="750"></div> </div> </div> @@ -170,8 +170,8 @@ </div> <div style="position: relative"> -<div class="grid" data-expected-width="150" data-expected-height="150"> - <div class="sizedToGridArea negativeNamedGridLineEndPositionStartSpanInRowDirection" data-offset-x="0" data-offset-y="0" data-expected-width="50" data-expected-height="150"></div> +<div class="grid" data-expected-width="150" data-expected-height="750"> + <div class="sizedToGridArea negativeNamedGridLineEndPositionStartSpanInRowDirection" data-offset-x="0" data-offset-y="0" data-expected-width="50" data-expected-height="750"></div> </div> </div> @@ -182,8 +182,8 @@ </div> <div style="position: relative"> -<div class="grid" data-expected-width="150" data-expected-height="150"> - <div class="sizedToGridArea negativeEndPositionStartNegativeInRowDirection" data-offset-x="0" data-offset-y="0" data-expected-width="50" data-expected-height="50"></div> +<div class="grid" data-expected-width="550" data-expected-height="150"> + <div class="sizedToGridArea negativeEndPositionStartNegativeInRowDirection" data-offset-x="0" data-offset-y="0" data-expected-width="450" data-expected-height="50"></div> </div> </div> @@ -194,8 +194,8 @@ </div> <div style="position: relative"> -<div class="grid" data-expected-width="150" data-expected-height="150"> - <div class="sizedToGridArea namedGridLineEndPositionStartNegativeInRowDirection" data-offset-x="0" data-offset-y="0" data-expected-width="50" data-expected-height="50"></div> +<div class="grid" data-expected-width="550" data-expected-height="150"> + <div class="sizedToGridArea namedGridLineEndPositionStartNegativeInRowDirection" data-offset-x="0" data-offset-y="0" data-expected-width="450" data-expected-height="50"></div> </div> </div>
diff --git a/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-item-spanning-resolution.html b/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-item-spanning-resolution.html index a4e19bfc..4afa300f 100644 --- a/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-item-spanning-resolution.html +++ b/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-item-spanning-resolution.html
@@ -7,6 +7,8 @@ grid-template-rows: 30% 70%; width: 400px; height: 300px; + grid-auto-columns: 200px; + grid-auto-rows: 250px; } #bigGrid { @@ -124,25 +126,25 @@ <div style="position: relative"> <div class="grid" data-expected-width="400" data-expected-height="300"> - <div class="sizedToGridArea negativeOverflowRowFirstColumn" data-offset-x="0" data-offset-y="0" data-expected-width="160" data-expected-height="90"></div> + <div class="sizedToGridArea negativeOverflowRowFirstColumn" data-offset-x="0" data-offset-y="0" data-expected-width="160" data-expected-height="500"></div> </div> </div> <div style="position: relative"> <div class="grid" data-expected-width="400" data-expected-height="300"> - <div class="sizedToGridArea overflowRowFirstColumn" data-offset-x="0" data-offset-y="0" data-expected-width="160" data-expected-height="300"></div> + <div class="sizedToGridArea overflowRowFirstColumn" data-offset-x="0" data-offset-y="0" data-expected-width="160" data-expected-height="800"></div> </div> </div> <div style="position: relative"> <div class="grid" data-expected-width="400" data-expected-height="300"> - <div class="sizedToGridArea firstRowNegativeOverflowColumn" data-offset-x="0" data-offset-y="0" data-expected-width="160" data-expected-height="90"></div> + <div class="sizedToGridArea firstRowNegativeOverflowColumn" data-offset-x="0" data-offset-y="0" data-expected-width="400" data-expected-height="90"></div> </div> </div> <div style="position: relative"> <div class="grid" data-expected-width="400" data-expected-height="300"> - <div class="sizedToGridArea firstRowOverflowColumn" data-offset-x="0" data-offset-y="0" data-expected-width="400" data-expected-height="90"></div> + <div class="sizedToGridArea firstRowOverflowColumn" data-offset-x="0" data-offset-y="0" data-expected-width="800" data-expected-height="90"></div> </div> </div> @@ -154,7 +156,7 @@ <div style="position: relative"> <div class="grid" data-expected-width="400" data-expected-height="300"> - <div class="sizedToGridArea autoSecondRowAutoFirstColumn" data-offset-x="0" data-offset-y="0" data-expected-width="160" data-expected-height="90"></div> + <div class="sizedToGridArea autoSecondRowAutoFirstColumn" data-offset-x="0" data-offset-y="0" data-expected-width="200" data-expected-height="90"></div> </div> </div> @@ -188,7 +190,7 @@ <div style="position: relative"> <div class="grid" id="bigGrid" data-expected-width="200" data-expected-height="100"> - <div class="sizedToGridArea underflowSpanning" data-offset-x="0" data-offset-y="0" data-expected-width="100" data-expected-height="75"></div> + <div class="sizedToGridArea underflowSpanning" data-offset-x="0" data-offset-y="0" data-expected-width="300" data-expected-height="1325"></div> </div> <!-- Check that the end span is ignored when two opposing spans are specified-->
diff --git a/third_party/WebKit/LayoutTests/fast/css-grid-layout/implicit-tracks-before-explicit.html b/third_party/WebKit/LayoutTests/fast/css-grid-layout/implicit-tracks-before-explicit.html new file mode 100644 index 0000000..ab91b07 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/css-grid-layout/implicit-tracks-before-explicit.html
@@ -0,0 +1,236 @@ +<!DOCTYPE html> + +<link href="resources/grid.css" rel="stylesheet"> +<style> +.grid { + grid: 100px / 50px; + font: 10px/1 Ahem; + position: relative; + margin: 25px; +} + +.firstNegativeRowFirstColumn { + background-color: purple; + grid-row: -3; + grid-column: 1; +} + +.firstNegativeRowFirstNegativeColumn { + background-color: navy; + grid-row: -3; + grid-column: -3; +} + +.secondNegativeRowFirstColumn { + background-color: lime; + grid-row: -4; + grid-column: 1; +} + +.secondNegativeRowSecondNegativeColumn { + background-color: orange; + grid-row: -4; + grid-column: -4; +} + +.firstRowFirstNegativeColumn { + background-color: magenta; + grid-row: 1; + grid-column: -3; +} + +.firstNegativeRowFirstNegativeColumn { + background-color: maroon; + grid-row: -3; + grid-column: -3; +} + +.firstRowSecondNegativeColumn { + background-color: aqua; + grid-row: 1; + grid-column: -4; +} + +</style> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> +<script src="../../resources/check-layout-th.js"></script> + +<body onload="checkLayout('.grid')"> +<div id="log"></div> + +<p>This test checks that it's possible to create implicit tracks before the explicit ones using negative indexes.</p> + +<div class="grid"> + <div class="autoRowAutoColumn" data-offset-x="0" data-offset-y="0" data-expected-width="100" data-expected-height="50">XX</div> +</div> + +<div class="grid"> + <div class="firstNegativeRowFirstColumn" data-offset-x="0" data-offset-y="0" data-expected-width="100" data-expected-height="10">X</div> + <div class="autoRowAutoColumn" data-offset-x="0" data-offset-y="10" data-expected-width="100" data-expected-height="50">XX</div> +</div> + +<div class="grid"> + <div class="firstNegativeRowFirstColumn" data-offset-x="0" data-offset-y="0" data-expected-width="100" data-expected-height="10">X</div> + <div class="firstRowFirstColumn" data-offset-x="0" data-offset-y="10" data-expected-width="100" data-expected-height="50">XX</div> +</div> + +<div class="grid"> + <div class="firstNegativeRowFirstNegativeColumn" data-offset-x="0" data-offset-y="0" data-expected-width="10" data-expected-height="10">X</div> + <div class="autoRowAutoColumn" data-offset-x="10" data-offset-y="0" data-expected-width="100" data-expected-height="10">XX</div> +</div> + +<div class="grid"> + <div class="firstNegativeRowFirstNegativeColumn" data-offset-x="0" data-offset-y="0" data-expected-width="10" data-expected-height="10">X</div> + <div class="firstRowFirstColumn" data-offset-x="10" data-offset-y="10" data-expected-width="100" data-expected-height="50">XX</div> +</div> + +<div class="grid"> + <div class="secondNegativeRowFirstColumn" data-offset-x="0" data-offset-y="0" data-expected-width="100" data-expected-height="10">X</div> + <div class="autoRowAutoColumn" data-offset-x="0" data-offset-y="10" data-expected-width="100" data-expected-height="10">XX</div> +</div> + +<div class="grid"> + <div class="secondNegativeRowFirstColumn" data-offset-x="0" data-offset-y="0" data-expected-width="100" data-expected-height="10">X</div> + <div class="firstRowFirstColumn" data-offset-x="0" data-offset-y="10" data-expected-width="100" data-expected-height="50">XX</div> +</div> + +<div class="grid"> + <div class="secondNegativeRowSecondNegativeColumn" data-offset-x="0" data-offset-y="0" data-expected-width="10" data-expected-height="10">X</div> + <div class="autoRowAutoColumn" data-offset-x="10" data-offset-y="0" data-expected-width="20" data-expected-height="10">XX</div> +</div> + +<div class="grid"> + <div class="secondNegativeRowSecondNegativeColumn" data-offset-x="0" data-offset-y="0" data-expected-width="10" data-expected-height="10">X</div> + <div class="firstRowFirstColumn" data-offset-x="10" data-offset-y="10" data-expected-width="100" data-expected-height="50">XX</div> +</div> + +<div class="grid"> + <div class="secondNegativeRowFirstColumn" data-offset-x="0" data-offset-y="0" data-expected-width="100" data-expected-height="10">X</div> + <div class="firstNegativeRowFirstColumn" data-offset-x="0" data-offset-y="10" data-expected-width="100" data-expected-height="10">XX</div> + <div class="autoRowAutoColumn" data-offset-x="0" data-offset-y="20" data-expected-width="100" data-expected-height="50">XXX</div> +</div> + +<div class="grid"> + <div class="secondNegativeRowFirstColumn" data-offset-x="0" data-offset-y="0" data-expected-width="100" data-expected-height="10">X</div> + <div class="firstNegativeRowFirstColumn" data-offset-x="0" data-offset-y="10" data-expected-width="100" data-expected-height="10">XX</div> + <div class="firstRowFirstColumn" data-offset-x="0" data-offset-y="20" data-expected-width="100" data-expected-height="50">XXX</div> +</div> + +<div class="grid"> + <div class="secondNegativeRowSecondNegativeColumn" data-offset-x="0" data-offset-y="0" data-expected-width="10" data-expected-height="10">X</div> + <div class="firstNegativeRowFirstNegativeColumn" data-offset-x="10" data-offset-y="10" data-expected-width="30" data-expected-height="10">XX</div> + <div class="autoRowAutoColumn" data-offset-x="10" data-offset-y="0" data-expected-width="30" data-expected-height="10">XXX</div> +</div> + +<div class="grid"> + <div class="secondNegativeRowSecondNegativeColumn" data-offset-x="0" data-offset-y="0" data-expected-width="10" data-expected-height="10">X</div> + <div class="firstNegativeRowFirstNegativeColumn" data-offset-x="10" data-offset-y="10" data-expected-width="20" data-expected-height="10">XX</div> + <div class="firstRowFirstColumn" data-offset-x="30" data-offset-y="20" data-expected-width="100" data-expected-height="50">XXX</div> +</div> + +<div class="grid"> + <div class="firstRowFirstNegativeColumn" data-offset-x="0" data-offset-y="0" data-expected-width="10" data-expected-height="50">X</div> + <div class="autoRowAutoColumn" data-offset-x="10" data-offset-y="0" data-expected-width="100" data-expected-height="50">XX</div> +</div> + +<div class="grid"> + <div class="firstRowFirstNegativeColumn" data-offset-x="0" data-offset-y="0" data-expected-width="10" data-expected-height="50">X</div> + <div class="firstRowFirstColumn" data-offset-x="10" data-offset-y="0" data-expected-width="100" data-expected-height="50">XX</div> +</div> + +<div class="grid"> + <div class="firstNegativeRowFirstNegativeColumn" data-offset-x="0" data-offset-y="0" data-expected-width="10" data-expected-height="10">X</div> + <div class="autoRowAutoColumn" data-offset-x="10" data-offset-y="0" data-expected-width="100" data-expected-height="10">XX</div> +</div> + +<div class="grid"> + <div class="firstNegativeRowFirstNegativeColumn" data-offset-x="0" data-offset-y="0" data-expected-width="10" data-expected-height="10">X</div> + <div class="firstRowFirstColumn" data-offset-x="10" data-offset-y="10" data-expected-width="100" data-expected-height="50">XX</div> +</div> + +<div class="grid"> + <div class="firstRowSecondNegativeColumn" data-offset-x="0" data-offset-y="0" data-expected-width="10" data-expected-height="50">X</div> + <div class="autoRowAutoColumn" data-offset-x="10" data-offset-y="0" data-expected-width="20" data-expected-height="50">XX</div> +</div> + +<div class="grid"> + <div class="firstRowSecondNegativeColumn" data-offset-x="0" data-offset-y="0" data-expected-width="10" data-expected-height="50">X</div> + <div class="firstRowFirstColumn" data-offset-x="10" data-offset-y="0" data-expected-width="100" data-expected-height="50">XX</div> +</div> + +<div class="grid"> + <div class="secondNegativeRowSecondNegativeColumn" data-offset-x="0" data-offset-y="0" data-expected-width="10" data-expected-height="10">X</div> + <div class="autoRowAutoColumn" data-offset-x="10" data-offset-y="0" data-expected-width="20" data-expected-height="10">XX</div> +</div> + +<div class="grid"> + <div class="secondNegativeRowSecondNegativeColumn" data-offset-x="0" data-offset-y="0" data-expected-width="10" data-expected-height="10">X</div> + <div class="firstRowFirstColumn" data-offset-x="10" data-offset-y="10" data-expected-width="100" data-expected-height="50">XX</div> +</div> + +<div class="grid"> + <div class="firstRowSecondNegativeColumn" data-offset-x="0" data-offset-y="0" data-expected-width="10" data-expected-height="50">X</div> + <div class="firstRowFirstNegativeColumn" data-offset-x="10" data-offset-y="0" data-expected-width="20" data-expected-height="50">XX</div> + <div class="autoRowAutoColumn" data-offset-x="30" data-offset-y="0" data-expected-width="100" data-expected-height="50">XXX</div> +</div> + +<div class="grid"> + <div class="firstRowSecondNegativeColumn" data-offset-x="0" data-offset-y="0" data-expected-width="10" data-expected-height="50">X</div> + <div class="firstRowFirstNegativeColumn" data-offset-x="10" data-offset-y="0" data-expected-width="20" data-expected-height="50">XX</div> + <div class="firstRowFirstColumn" data-offset-x="30" data-offset-y="0" data-expected-width="100" data-expected-height="50">XXX</div> +</div> + +<div class="grid"> + <div class="secondNegativeRowSecondNegativeColumn" data-offset-x="0" data-offset-y="0" data-expected-width="10" data-expected-height="10">X</div> + <div class="firstNegativeRowFirstNegativeColumn" data-offset-x="10" data-offset-y="10" data-expected-width="30" data-expected-height="10">XX</div> + <div class="autoRowAutoColumn" data-offset-x="10" data-offset-y="0" data-expected-width="30" data-expected-height="10">XXX</div> +</div> + +<div class="grid"> + <div class="secondNegativeRowSecondNegativeColumn" data-offset-x="0" data-offset-y="0" data-expected-width="10" data-expected-height="10">X</div> + <div class="firstNegativeRowFirstNegativeColumn" data-offset-x="10" data-offset-y="10" data-expected-width="20" data-expected-height="10">XX</div> + <div class="firstRowFirstColumn" data-offset-x="30" data-offset-y="20" data-expected-width="100" data-expected-height="50">XXX</div> +</div> + +<div class="grid"> + <div class="firstNegativeRowFirstColumn" data-offset-x="30" data-offset-y="0" data-expected-width="100" data-expected-height="10">X</div> + <div class="firstRowFirstNegativeColumn" data-offset-x="0" data-offset-y="10" data-expected-width="30" data-expected-height="50">XX</div> + <div class="autoRowAutoColumn" data-offset-x="0" data-offset-y="0" data-expected-width="30" data-expected-height="10">XXX</div> +</div> + +<div class="grid"> + <div class="firstNegativeRowFirstColumn" data-offset-x="20" data-offset-y="0" data-expected-width="100" data-expected-height="10">X</div> + <div class="firstRowFirstNegativeColumn" data-offset-x="0" data-offset-y="10" data-expected-width="20" data-expected-height="50">XX</div> + <div class="firstRowFirstColumn" data-offset-x="20" data-offset-y="10" data-expected-width="100" data-expected-height="50">XXX</div> +</div> + +<div class="grid"> + <div class="secondNegativeRowFirstColumn" data-offset-x="30" data-offset-y="0" data-expected-width="100" data-expected-height="10">X</div> + <div class="firstRowSecondNegativeColumn" data-offset-x="0" data-offset-y="10" data-expected-width="30" data-expected-height="50">XX</div> + <div class="autoRowAutoColumn" data-offset-x="0" data-offset-y="0" data-expected-width="30" data-expected-height="10">XXX</div> +</div> + +<div class="grid"> + <div class="secondNegativeRowFirstColumn" data-offset-x="20" data-offset-y="0" data-expected-width="100" data-expected-height="10">X</div> + <div class="firstRowSecondNegativeColumn" data-offset-x="0" data-offset-y="10" data-expected-width="20" data-expected-height="50">XX</div> + <div class="firstRowFirstColumn" data-offset-x="20" data-offset-y="10" data-expected-width="100" data-expected-height="50">XXX</div> +</div> + +<div class="grid"> + <div class="secondNegativeRowFirstColumn" data-offset-x="90" data-offset-y="0" data-expected-width="100" data-expected-height="10">X</div> + <div class="firstRowSecondNegativeColumn" data-offset-x="0" data-offset-y="20" data-expected-width="50" data-expected-height="50">XX</div> + <div class="firstNegativeRowFirstColumn" data-offset-x="90" data-offset-y="10" data-expected-width="100" data-expected-height="10">XXX</div> + <div class="firstRowFirstNegativeColumn" data-offset-x="50" data-offset-y="20" data-expected-width="40" data-expected-height="50">XXXX</div> + <div class="autoRowAutoColumn" data-offset-x="0" data-offset-y="0" data-expected-width="50" data-expected-height="10">XXXXX</div> +</div> + +<div class="grid"> + <div class="secondNegativeRowFirstColumn" data-offset-x="60" data-offset-y="0" data-expected-width="100" data-expected-height="10">X</div> + <div class="firstRowSecondNegativeColumn" data-offset-x="0" data-offset-y="20" data-expected-width="20" data-expected-height="50">XX</div> + <div class="firstNegativeRowFirstColumn" data-offset-x="60" data-offset-y="10" data-expected-width="100" data-expected-height="10">XXX</div> + <div class="firstRowFirstNegativeColumn" data-offset-x="20" data-offset-y="20" data-expected-width="40" data-expected-height="50">XXXX</div> + <div class="firstRowFirstColumn" data-offset-x="60" data-offset-y="20" data-expected-width="100" data-expected-height="50">XXXXX</div> +</div> + +</body>
diff --git a/third_party/WebKit/LayoutTests/fast/css/complex-ridge-outline-large-negative-offset-expected.txt b/third_party/WebKit/LayoutTests/fast/css/complex-ridge-outline-large-negative-offset-expected.txt new file mode 100644 index 0000000..df3e183 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/css/complex-ridge-outline-large-negative-offset-expected.txt
@@ -0,0 +1,2 @@ +Passes if no assertion failure. +A B C D E F G H I J K L M N O P Q R S T
diff --git a/third_party/WebKit/LayoutTests/fast/css/complex-ridge-outline-large-negative-offset.html b/third_party/WebKit/LayoutTests/fast/css/complex-ridge-outline-large-negative-offset.html new file mode 100644 index 0000000..746c56c1 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/css/complex-ridge-outline-large-negative-offset.html
@@ -0,0 +1,10 @@ +<!DOCTYPE html> +<script> +if (window.testRunner) + testRunner.dumpAsText(); +</script> +Passes if no assertion failure. +<div style="width: 150px"> + A B C D <span style="outline: 20px ridge blue; outline-offset: -15px">E F G H I J K L M N O P </span> Q R S T +</div> +
diff --git a/third_party/WebKit/LayoutTests/fast/css/cursor-parsing-expected.txt b/third_party/WebKit/LayoutTests/fast/css/cursor-parsing-expected.txt index 8ec41bc..edb7aa2b 100644 --- a/third_party/WebKit/LayoutTests/fast/css/cursor-parsing-expected.txt +++ b/third_party/WebKit/LayoutTests/fast/css/cursor-parsing-expected.txt
@@ -27,11 +27,13 @@ PASS roundtripCssRule(`cursor: inline;`) is "" PASS roundtripCssRule(`cursor: hand;`) is "" PASS roundtripCssRule(`cursor: url("file:///foo.png");`) is "" +PASS roundtripCssRule(`cursor: url("file:///foo.png"),;`) is "" PASS roundtripCssRule(`cursor: url("file:///foo.png"), url("file:///foo2.png");`) is "" PASS roundtripCssRule(`cursor: url("file:///foo.png") 12;`) is "" PASS roundtripCssRule(`cursor: url("file:///foo.png") 12 3 5;`) is "" PASS roundtripCssRule(`cursor: url("file:///foo.png") x y;`) is "" PASS roundtripCssRule(`cursor: url("file:///foo.png") auto;`) is "" +PASS roundtripCssRule(`cursor: url("file:///foo.png") hand;`) is "" PASS successfullyParsed is true TEST COMPLETE
diff --git a/third_party/WebKit/LayoutTests/fast/css/cursor-parsing.html b/third_party/WebKit/LayoutTests/fast/css/cursor-parsing.html index 01b67f1..9b2467a 100644 --- a/third_party/WebKit/LayoutTests/fast/css/cursor-parsing.html +++ b/third_party/WebKit/LayoutTests/fast/css/cursor-parsing.html
@@ -64,11 +64,13 @@ testInvalidCursorRule('inline'); testInvalidCursorRule('hand'); testInvalidCursorRule('url("file:///foo.png")'); +testInvalidCursorRule('url("file:///foo.png"),'); testInvalidCursorRule('url("file:///foo.png"), url("file:///foo2.png")'); testInvalidCursorRule('url("file:///foo.png") 12'); testInvalidCursorRule('url("file:///foo.png") 12 3 5'); testInvalidCursorRule('url("file:///foo.png") x y'); testInvalidCursorRule('url("file:///foo.png") auto'); +testInvalidCursorRule('url("file:///foo.png") hand'); successfullyParsed = true; </script>
diff --git a/third_party/WebKit/LayoutTests/fast/dom/shadow/resources/shadow-dom.js b/third_party/WebKit/LayoutTests/fast/dom/shadow/resources/shadow-dom.js index 05d1586..ab9c30b 100644 --- a/third_party/WebKit/LayoutTests/fast/dom/shadow/resources/shadow-dom.js +++ b/third_party/WebKit/LayoutTests/fast/dom/shadow/resources/shadow-dom.js
@@ -90,7 +90,7 @@ var parent = template.parentNode; parent.removeChild(template); var shadowRoot; - if (!mode) { + if (!mode || mode == 'v0'){ shadowRoot = parent.createShadowRoot(); } else { shadowRoot = parent.attachShadow({'mode': mode});
diff --git a/third_party/WebKit/LayoutTests/fast/dom/shadow/v1-slots-api-in-v0.html b/third_party/WebKit/LayoutTests/fast/dom/shadow/v1-slots-api-in-v0.html new file mode 100644 index 0000000..7680cee --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/dom/shadow/v1-slots-api-in-v0.html
@@ -0,0 +1,42 @@ +<!DOCTYPE html> +<script src='../../../resources/testharness.js'></script> +<script src='../../../resources/testharnessreport.js'></script> +<script src='resources/shadow-dom.js'></script> +<div id='host'> + <template data-mode='v0'> + <slot name='slot1'> + <div id='fallback1'></div> + </slot> + <slot name='slot2'> + <div id='fallback2'></div> + </slot> + </template> + <slot id='slot0'> + <div id='fallback0'></div> + </slot> + <div id='child1' slot='slot1'></div> +</div> +<script> +'use strict'; +convertTemplatesToShadowRootsWithin(host); +removeWhiteSpaceOnlyTextNodes(host); +document.body.offsetLeft; + +const slot1 = host.shadowRoot.querySelector('[name=slot1]'); +const slot2 = host.shadowRoot.querySelector('[name=slot2]'); +const fallback1 = host.shadowRoot.querySelector('#fallback1'); +const fallback2 = host.shadowRoot.querySelector('#fallback2'); + +test(() => { + assert_equals(fallback0.assignedSlot, null); + assert_equals(fallback1.assignedSlot, null); + assert_equals(fallback2.assignedSlot, null); + assert_equals(child1.assignedSlot, null); +}, "assignedSlot"); + +test(() => { + assert_array_equals(slot0.getAssignedNodes(), []); + assert_array_equals(slot1.getAssignedNodes(), []); + assert_array_equals(slot2.getAssignedNodes(), []); +}, "getAssignedNodes"); +</script>
diff --git a/third_party/WebKit/LayoutTests/fast/dom/shadow/v1-slots-fallback-1-expected.html b/third_party/WebKit/LayoutTests/fast/dom/shadow/v1-slots-fallback-1-expected.html new file mode 100644 index 0000000..a1044adb --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/dom/shadow/v1-slots-fallback-1-expected.html
@@ -0,0 +1,5 @@ +<!DOCTYPE html> +<div> + <div>child1</div> + <div>fallback2</div> +</div>
diff --git a/third_party/WebKit/LayoutTests/fast/dom/shadow/v1-slots-fallback-1.html b/third_party/WebKit/LayoutTests/fast/dom/shadow/v1-slots-fallback-1.html new file mode 100644 index 0000000..1dfa3e2 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/dom/shadow/v1-slots-fallback-1.html
@@ -0,0 +1,16 @@ +<!DOCTYPE html> +<script src='resources/shadow-dom.js'></script> +<div id='host'> + <template data-mode='open'> + <slot name='slot1'> + <div>fallback1</div> + </slot> + <slot name='slot2'> + <div>fallback2</div> + </slot> + </template> + <div slot='slot1'>child1</div> +</div> +<script> +convertTemplatesToShadowRootsWithin(host); +</script>
diff --git a/third_party/WebKit/LayoutTests/fast/dom/shadow/v1-slots-fallback-2-expected.html b/third_party/WebKit/LayoutTests/fast/dom/shadow/v1-slots-fallback-2-expected.html new file mode 100644 index 0000000..f4bba86 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/dom/shadow/v1-slots-fallback-2-expected.html
@@ -0,0 +1,6 @@ +<!DOCTYPE html> +<div id='host'> + <div id='fallback1'></div> + <div id='child1' slot='slot2'></div> + <div id='fallback3'></div> +</div>
diff --git a/third_party/WebKit/LayoutTests/fast/dom/shadow/v1-slots-fallback-2.html b/third_party/WebKit/LayoutTests/fast/dom/shadow/v1-slots-fallback-2.html new file mode 100644 index 0000000..7afd360 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/dom/shadow/v1-slots-fallback-2.html
@@ -0,0 +1,21 @@ +<!DOCTYPE html> +<script src='resources/shadow-dom.js'></script> +<div id='host'> + <template data-mode='open'> + <slot name='slot1'> + <div id='fallback1'></div> + <slot name='slot2'> + <div id='fallback2'></div> + </slot> + </slot> + <slot name='slot3'> + <slot name='slot4'> + <div id='fallback3'></div> + </slot> + </slot> + </template> + <div id='child1' slot='slot2'></div> +</div> +<script> +convertTemplatesToShadowRootsWithin(host); +</script>
diff --git a/third_party/WebKit/LayoutTests/fast/dom/shadow/v1-slots-fallback-3-expected.html b/third_party/WebKit/LayoutTests/fast/dom/shadow/v1-slots-fallback-3-expected.html new file mode 100644 index 0000000..aa7a03f67 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/dom/shadow/v1-slots-fallback-3-expected.html
@@ -0,0 +1,8 @@ +<!DOCTYPE html> +<div id='host'> + <div id='host2'> + <div id='fallback1'></div> + <div id='child1' slot='slot2'></div> + <div id='fallback-a'></div> + </div> +</div>
diff --git a/third_party/WebKit/LayoutTests/fast/dom/shadow/v1-slots-fallback-3.html b/third_party/WebKit/LayoutTests/fast/dom/shadow/v1-slots-fallback-3.html new file mode 100644 index 0000000..16097ed --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/dom/shadow/v1-slots-fallback-3.html
@@ -0,0 +1,30 @@ +<!DOCTYPE html> +<script src='resources/shadow-dom.js'></script> +<div id='host'> + <template data-mode='open'> + <div id='host2'> + <template data-mode='open'> + <slot name='slot-a'> + <slot name='slot-b'> + </slot> + <div id='fallback-a'></div> + </slot> + </template> + <slot name='slot1' slot='slot-b'> + <div id='fallback1'></div> + <slot name='slot2'> + <div id='fallback2'></div> + </slot> + </slot> + <slot name='slot3'> + <slot name='slot4'> + <div id='fallback3'></div> + </slot> + </slot> + </div> + </template> + <div id='child1' slot='slot2'></div> +</div> +<script> +convertTemplatesToShadowRootsWithin(host); +</script>
diff --git a/third_party/WebKit/LayoutTests/fast/dom/shadow/v1-slots-fallback-api-1.html b/third_party/WebKit/LayoutTests/fast/dom/shadow/v1-slots-fallback-api-1.html new file mode 100644 index 0000000..15dbd5f --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/dom/shadow/v1-slots-fallback-api-1.html
@@ -0,0 +1,39 @@ +<!DOCTYPE html> +<script src='../../../resources/testharness.js'></script> +<script src='../../../resources/testharnessreport.js'></script> +<script src='resources/shadow-dom.js'></script> +<div id='host'> + <template data-mode='open'> + <slot name='slot1'> + <div id='fallback1'></div> + </slot> + <slot name='slot2'> + <div id='fallback2'></div> + </slot> + </template> + <div id='child1' slot='slot1'></div> +</div> +<script> +'use strict'; +convertTemplatesToShadowRootsWithin(host); +removeWhiteSpaceOnlyTextNodes(host); +document.body.offsetLeft; + +const slot1 = host.shadowRoot.querySelector('[name=slot1]'); +const slot2 = host.shadowRoot.querySelector('[name=slot2]'); +const fallback2 = host.shadowRoot.querySelector('#fallback2'); + +test(() => { + assert_equals(child1.assignedSlot, slot1); +}, "assignedSlot"); + +test(() => { + assert_array_equals(slot1.getAssignedNodes(), [child1]); + assert_array_equals(slot2.getAssignedNodes(), []); +}, "getAssignedNodes"); + +test(() => { + assert_array_equals(slot1.getDistributedNodes(), [child1]); + assert_array_equals(slot2.getDistributedNodes(), [fallback2]); +}, "getDistributedNodes"); +</script>
diff --git a/third_party/WebKit/LayoutTests/fast/dom/shadow/v1-slots-fallback-api-2.html b/third_party/WebKit/LayoutTests/fast/dom/shadow/v1-slots-fallback-api-2.html new file mode 100644 index 0000000..32e26f8 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/dom/shadow/v1-slots-fallback-api-2.html
@@ -0,0 +1,55 @@ +<!DOCTYPE html> +<script src='../../../resources/testharness.js'></script> +<script src='../../../resources/testharnessreport.js'></script> +<script src='resources/shadow-dom.js'></script> +<div id='host'> + <template data-mode='open'> + <slot name='slot1'> + <div id='fallback1'></div> + <slot name='slot2'> + <div id='fallback2'></div> + </slot> + </slot> + <slot name='slot3'> + <slot name='slot4'> + <div id='fallback3'></div> + </slot> + </slot> + </template> + <div id='child1' slot='slot2'></div> +</div> +<script> +'use strict'; +convertTemplatesToShadowRootsWithin(host); +removeWhiteSpaceOnlyTextNodes(host); +document.body.offsetLeft; + +const slot1 = host.shadowRoot.querySelector('[name=slot1]'); +const slot2 = host.shadowRoot.querySelector('[name=slot2]'); +const slot3 = host.shadowRoot.querySelector('[name=slot3]'); +const slot4 = host.shadowRoot.querySelector('[name=slot4]'); +const fallback1 = host.shadowRoot.querySelector('#fallback1'); +const fallback2 = host.shadowRoot.querySelector('#fallback2'); +const fallback3 = host.shadowRoot.querySelector('#fallback3'); + +test(() => { + assert_equals(child1.assignedSlot, slot2); + assert_equals(fallback1.assignedSlot, null); + assert_equals(fallback2.assignedSlot, null); + assert_equals(fallback3.assignedSlot, null); +}, "assignedSlot"); + +test(() => { + assert_array_equals(slot1.getAssignedNodes(), []); + assert_array_equals(slot2.getAssignedNodes(), [child1]); + assert_array_equals(slot3.getAssignedNodes(), []); + assert_array_equals(slot4.getAssignedNodes(), []); +}, "getAssignedNodes"); + +test(() => { + assert_array_equals(slot1.getDistributedNodes(), [fallback1, child1]); + assert_array_equals(slot2.getDistributedNodes(), [child1]); + assert_array_equals(slot3.getDistributedNodes(), [fallback3]); + assert_array_equals(slot4.getDistributedNodes(), [fallback3]); +}, "getDistributedNodes"); +</script>
diff --git a/third_party/WebKit/LayoutTests/fast/dom/shadow/v1-slots-fallback-api-3.html b/third_party/WebKit/LayoutTests/fast/dom/shadow/v1-slots-fallback-api-3.html new file mode 100644 index 0000000..b548272d --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/dom/shadow/v1-slots-fallback-api-3.html
@@ -0,0 +1,85 @@ +<!DOCTYPE html> +<script src='../../../resources/testharness.js'></script> +<script src='../../../resources/testharnessreport.js'></script> +<script src='resources/shadow-dom.js'></script> +<div id='host'> + <template data-mode='open'> + <div id='host2'> + <template data-mode='open'> + <slot name='slot-a'> + <slot name='slot-b'> + </slot> + <div id='fallback-a'></div> + </slot> + </template> + <slot name='slot1' slot='slot-b'> + <div id='fallback1'></div> + <slot name='slot2'> + <div id='fallback2'></div> + </slot> + </slot> + <slot name='slot3'> + <slot name='slot4'> + <div id='fallback3'></div> + </slot> + </slot> + </div> + </template> + <div id='child1' slot='slot2'></div> +</div> +<script> +'use strict'; +convertTemplatesToShadowRootsWithin(host); +removeWhiteSpaceOnlyTextNodes(host); +document.body.offsetLeft; + +const slot1 = host.shadowRoot.querySelector('[name=slot1]'); +const slot2 = host.shadowRoot.querySelector('[name=slot2]'); +const slot3 = host.shadowRoot.querySelector('[name=slot3]'); +const slot4 = host.shadowRoot.querySelector('[name=slot4]'); +const fallback1 = host.shadowRoot.querySelector('#fallback1'); +const fallback2 = host.shadowRoot.querySelector('#fallback2'); +const fallback3 = host.shadowRoot.querySelector('#fallback3'); + +const host2 = host.shadowRoot.querySelector('#host2'); + +const slot_a = host2.shadowRoot.querySelector('[name=slot-a]'); +const slot_b = host2.shadowRoot.querySelector('[name=slot-b]'); +const fallback_a = host2.shadowRoot.querySelector('#fallback-a'); + +test(() => { + assert_equals(child1.assignedSlot, slot2); + assert_equals(fallback1.assignedSlot, null); + assert_equals(fallback2.assignedSlot, null); + assert_equals(fallback3.assignedSlot, null); + + assert_equals(slot1.assignedSlot, slot_b); + assert_equals(slot2.assignedSlot, null); + assert_equals(slot3.assignedSlot, null); + assert_equals(slot4.assignedSlot, null); + + assert_equals(slot_a.assignedSlot, null); + assert_equals(slot_b.assignedSlot, null); + assert_equals(fallback_a.assignedSlot, null); +}, "assignedSlot"); + +test(() => { + assert_array_equals(slot1.getAssignedNodes(), []); + assert_array_equals(slot2.getAssignedNodes(), [child1]); + assert_array_equals(slot3.getAssignedNodes(), []); + assert_array_equals(slot4.getAssignedNodes(), []); + + assert_array_equals(slot_a.getAssignedNodes(), []); + assert_array_equals(slot_b.getAssignedNodes(), [slot1]); +}, "getAssignedNodes"); + +test(() => { + assert_array_equals(slot1.getDistributedNodes(), [fallback1, child1]); + assert_array_equals(slot2.getDistributedNodes(), [child1]); + assert_array_equals(slot3.getDistributedNodes(), [fallback3]); + assert_array_equals(slot4.getDistributedNodes(), [fallback3]); + + assert_array_equals(slot_a.getDistributedNodes(), [fallback1, child1, fallback_a]); + assert_array_equals(slot_b.getDistributedNodes(), [fallback1, child1]); +}, "getDistributedNodes"); +</script>
diff --git a/third_party/WebKit/LayoutTests/fast/dom/shadow/v1-slots-in-v0-expected.html b/third_party/WebKit/LayoutTests/fast/dom/shadow/v1-slots-in-v0-expected.html new file mode 100644 index 0000000..3dedb03 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/dom/shadow/v1-slots-in-v0-expected.html
@@ -0,0 +1,5 @@ +<!DOCTYPE html> +<div id='host'> + <div id='fallback1'></div> + <div id='fallback2'></div> +</div>
diff --git a/third_party/WebKit/LayoutTests/fast/dom/shadow/v1-slots-in-v0.html b/third_party/WebKit/LayoutTests/fast/dom/shadow/v1-slots-in-v0.html new file mode 100644 index 0000000..36bcf06 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/dom/shadow/v1-slots-in-v0.html
@@ -0,0 +1,19 @@ +<!DOCTYPE html> +<script src='resources/shadow-dom.js'></script> +<div id='host'> + <template data-mode='v0'> + <slot name='slot1'> + <div id='fallback1'></div> + </slot> + <slot name='slot2'> + <div id='fallback2'></div> + </slot> + </template> + <slot id='slot0'> + <div id='fallback0'></div> + </slot> + <div id='child1' slot='slot1'></div> +</div> +<script> +convertTemplatesToShadowRootsWithin(host); +</script>
diff --git a/third_party/WebKit/LayoutTests/fast/events/mouse-cursor-expected.txt b/third_party/WebKit/LayoutTests/fast/events/mouse-cursor-expected.txt index d74ca2a..3b1ba13b 100644 --- a/third_party/WebKit/LayoutTests/fast/events/mouse-cursor-expected.txt +++ b/third_party/WebKit/LayoutTests/fast/events/mouse-cursor-expected.txt
@@ -25,7 +25,7 @@ Cursor Info: type=Grabbing hotSpot=0,0 TEST CASE: Existing 25x25 image -Cursor Info: type=Custom hotSpot=0,0 image=25x25 +Cursor Info: type=IBeam hotSpot=0,0 TEST CASE: Invalid URL with fallback to pointer Cursor Info: type=Hand hotSpot=0,0
diff --git a/third_party/WebKit/LayoutTests/fast/forms/search/search-change-type-before-onsearch.html b/third_party/WebKit/LayoutTests/fast/forms/search/search-change-type-before-onsearch.html new file mode 100644 index 0000000..6b1f75b --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/forms/search/search-change-type-before-onsearch.html
@@ -0,0 +1,26 @@ +<!DOCTYPE html> +<body> +<script src="../../../resources/testharness.js"></script> +<script src="../../../resources/testharnessreport.js"></script> +<div id="log"></div> +<input type="search" incremental> +<script> +var input = document.querySelector('input'); + +var test = async_test('Changing the input type before dispatching a search event should not crash.'); +test.step(function() { + input.offsetTop; + // Trigger 'search' event. + var enterEvent = document.createEvent('TextEvent'); + enterEvent.initTextEvent('textInput', true, true, document.defaultView, '\n'); + input.dispatchEvent(enterEvent); + // A 'search' event dispatching task was scheduled. Changing the input type + // before the task is performed. + input.type = 'text'; +}); +setTimeout(function() { test.step(function() { + // No crash. + test.done(); +})}, 0); +</script> +</body>
diff --git a/third_party/WebKit/LayoutTests/fast/forms/select/menulist-change-event-with-reset-blur.html b/third_party/WebKit/LayoutTests/fast/forms/select/menulist-change-event-with-reset-blur.html new file mode 100644 index 0000000..4509efbc --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/forms/select/menulist-change-event-with-reset-blur.html
@@ -0,0 +1,26 @@ +<!DOCTYPE html> +<body> +<script src="../../../resources/testharness.js"></script> +<script src="../../../resources/testharnessreport.js"></script> +<div id="log"></div> +<form> +<select> +<option selected>1</option> +<option>2</option> +</select> +</form> +<script> +var select = document.querySelector('select'); +var changeEventCounter = 0; +select.addEventListener('change', function() { ++changeEventCounter; }, false); + +test(function() { + select.focus(); + eventSender.keyDown('2'); + assert_equals(changeEventCounter, 1); + document.querySelector('form').reset(); + select.blur(); + assert_equals(changeEventCounter, 1); +}, 'Form reset and blur() should trigger no change event.'); +</script> +</body>
diff --git a/third_party/WebKit/LayoutTests/fast/repaint/positioned-great-grandparent-change-location-expected.txt b/third_party/WebKit/LayoutTests/fast/repaint/positioned-great-grandparent-change-location-expected.txt index 1a22a5a2..2337f69b 100644 --- a/third_party/WebKit/LayoutTests/fast/repaint/positioned-great-grandparent-change-location-expected.txt +++ b/third_party/WebKit/LayoutTests/fast/repaint/positioned-great-grandparent-change-location-expected.txt
@@ -7,9 +7,9 @@ "drawsContent": true, "repaintRects": [ [100, 200, 100, 100], - [100, 200, 42, 18], + [100, 200, 41, 18], [100, 100, 100, 100], - [100, 100, 42, 18] + [100, 100, 41, 18] ], "paintInvalidationClients": [ "LayoutBlockFlow (positioned) DIV id='great-grandparent'",
diff --git a/third_party/WebKit/LayoutTests/fast/replaced/aspect-ratio-of-replaced-child-with-auto-height-expected.txt b/third_party/WebKit/LayoutTests/fast/replaced/aspect-ratio-of-replaced-child-with-auto-height-expected.txt new file mode 100644 index 0000000..cf1b018 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/replaced/aspect-ratio-of-replaced-child-with-auto-height-expected.txt
@@ -0,0 +1,4 @@ +Tests that a replaced child with percentage height should keep the aspect ratio when the size of its container changes. + + +PASS
diff --git a/third_party/WebKit/LayoutTests/fast/replaced/aspect-ratio-of-replaced-child-with-auto-height.html b/third_party/WebKit/LayoutTests/fast/replaced/aspect-ratio-of-replaced-child-with-auto-height.html new file mode 100644 index 0000000..90ec1ba --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/replaced/aspect-ratio-of-replaced-child-with-auto-height.html
@@ -0,0 +1,33 @@ +<!DOCTYPE html> +<style> +#container { + height: 400px; + text-align: center; + background-color: lime; +} +#child { + height: 100%; +} +</style> + +<p> +Tests that a replaced child with percentage height should keep the aspect ratio +when the size of its container changes. +</p> + +<div id="container"> + <img id="child" src="resources/square-blue-100x100.png" data-expected-width="200" /> +</div> + +<script src="../../resources/check-layout.js"></script> + +<script> +function runTest() { + document.body.offsetTop; + var container = document.getElementById('container'); + container.style.height = "200px"; + document.body.offsetTop; + checkLayout("#container"); +} +window.onload = runTest; +</script>
diff --git a/third_party/WebKit/LayoutTests/fast/table/border-collapsing/composited-cell-collapsed-border-expected.html b/third_party/WebKit/LayoutTests/fast/table/border-collapsing/composited-cell-collapsed-border-expected.html new file mode 100644 index 0000000..085d2918 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/table/border-collapsing/composited-cell-collapsed-border-expected.html
@@ -0,0 +1,9 @@ +<!DOCTYPE html> +Tests compositing/painting of a composited cell in the table with collapsed borders. +Passes if there are complete 1px solid green borders around all table cells. +<table style="border: 1px solid green; border-collapse: collapse"> + <tr> + <td style="background-color: blue">Cell1</td> + <td>Cell2</td> + </tr> +</table>
diff --git a/third_party/WebKit/LayoutTests/fast/table/border-collapsing/composited-cell-collapsed-border.html b/third_party/WebKit/LayoutTests/fast/table/border-collapsing/composited-cell-collapsed-border.html new file mode 100644 index 0000000..5651eac --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/table/border-collapsing/composited-cell-collapsed-border.html
@@ -0,0 +1,9 @@ +<!DOCTYPE html> +Tests compositing/painting of a composited cell in the table with collapsed borders. +Passes if there are complete 1px solid green borders around all table cells. +<table style="border: 1px solid green; border-collapse: collapse"> + <tr> + <td style="will-change: transform; background-color: blue">Cell1</td> + <td>Cell2</td> + </tr> +</table>
diff --git a/third_party/WebKit/LayoutTests/fast/table/border-collapsing/composited-row-collapsed-border-expected.html b/third_party/WebKit/LayoutTests/fast/table/border-collapsing/composited-row-collapsed-border-expected.html new file mode 100644 index 0000000..db0a707 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/table/border-collapsing/composited-row-collapsed-border-expected.html
@@ -0,0 +1,9 @@ +<!DOCTYPE html> +Tests compositing/painting of a composited row in the table with collapsed borders. +Passes if there are complete 1px solid green borders around all table cells. +<table style="border: 1px solid green; border-collapse: collapse"> + <tr style="background-color: blue"> + <td>Cell1</td> + <td>Cell2</td> + </tr> +</table>
diff --git a/third_party/WebKit/LayoutTests/fast/table/border-collapsing/composited-row-collapsed-border.html b/third_party/WebKit/LayoutTests/fast/table/border-collapsing/composited-row-collapsed-border.html new file mode 100644 index 0000000..bdbf7fe --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/table/border-collapsing/composited-row-collapsed-border.html
@@ -0,0 +1,9 @@ +<!DOCTYPE html> +Tests compositing/painting of a composited row in the table with collapsed borders. +Passes if there are complete 1px solid green borders around all table cells. +<table style="border: 1px solid green; border-collapse: collapse"> + <tr style="will-change: transform; background-color: blue"> + <td>Cell1</td> + <td>Cell2</td> + </tr> +</table>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/README.chromium b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/README.chromium deleted file mode 100644 index b577efa89..0000000 --- a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/README.chromium +++ /dev/null
@@ -1,6 +0,0 @@ -This directory contains a copy of a test suite created by W3C I18N WG. - -A pull request to web-platform-tests is being worked on: -https://github.com/w3c/web-platform-tests/pull/2357 - -This directory should be removed when the pull request is merged and imported.
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-004b-expected.html b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-004b-expected.html deleted file mode 100644 index cb83dde..0000000 --- a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-004b-expected.html +++ /dev/null
@@ -1,16 +0,0 @@ -<!doctype html> -<html> -<head> -<meta charset="utf-8"/> -<title>The dir attribute: numbers isolated from preceding text, opposite direction</title> -<style type="text/css"> -.test, .ref { font-size: 150%; border: 1px solid orange; margin: 10px; margin-right: 200px; padding: 5px; clear: both; } -input { margin: 5px; } -</style> -</head> -<body> -<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> -<div class="ref"><div dir="ltr">‭א 3‬</div><div dir="ltr">‭a 3‬</div><div dir="rtl">‭3 א‬</div><div dir="rtl">‭3 a‬</div></div> -<div class="ref"><div dir="ltr">‭א 3‬</div><div dir="ltr">‭a 3‬</div><div dir="rtl">‭3 א‬</div><div dir="rtl">‭3 a‬</div></div> -</body> -</html>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-004c-expected.html b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-004c-expected.html deleted file mode 100644 index cb83dde..0000000 --- a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-004c-expected.html +++ /dev/null
@@ -1,16 +0,0 @@ -<!doctype html> -<html> -<head> -<meta charset="utf-8"/> -<title>The dir attribute: numbers isolated from preceding text, opposite direction</title> -<style type="text/css"> -.test, .ref { font-size: 150%; border: 1px solid orange; margin: 10px; margin-right: 200px; padding: 5px; clear: both; } -input { margin: 5px; } -</style> -</head> -<body> -<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> -<div class="ref"><div dir="ltr">‭א 3‬</div><div dir="ltr">‭a 3‬</div><div dir="rtl">‭3 א‬</div><div dir="rtl">‭3 a‬</div></div> -<div class="ref"><div dir="ltr">‭א 3‬</div><div dir="ltr">‭a 3‬</div><div dir="rtl">‭3 א‬</div><div dir="rtl">‭3 a‬</div></div> -</body> -</html>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-005b-expected.html b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-005b-expected.html deleted file mode 100644 index 4a6c301a..0000000 --- a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-005b-expected.html +++ /dev/null
@@ -1,16 +0,0 @@ -<!doctype html> -<html> -<head> -<meta charset="utf-8"/> -<title>The dir attribute: isolated from following text, opposite direction</title> -<style type="text/css"> -.test, .ref { font-size: 150%; border: 1px solid orange; margin: 10px; margin-right: 200px; padding: 5px; clear: both; } -input { margin: 5px; } -</style> -</head> -<body> -<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> -<div class="ref"><div dir="ltr">‭א ב...‬</div><div dir="ltr">‭a b...‬</div><div dir="rtl">‭...b a‬</div><div dir="rtl">‭...ב א‬</div></div> -<div class="ref"><div dir="ltr">‭א ב...‬</div><div dir="ltr">‭a b...‬</div><div dir="rtl">‭...b a‬</div><div dir="rtl">‭...ב א‬</div></div> -</body> -</html>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-005c-expected.html b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-005c-expected.html deleted file mode 100644 index 4a6c301a..0000000 --- a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-005c-expected.html +++ /dev/null
@@ -1,16 +0,0 @@ -<!doctype html> -<html> -<head> -<meta charset="utf-8"/> -<title>The dir attribute: isolated from following text, opposite direction</title> -<style type="text/css"> -.test, .ref { font-size: 150%; border: 1px solid orange; margin: 10px; margin-right: 200px; padding: 5px; clear: both; } -input { margin: 5px; } -</style> -</head> -<body> -<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> -<div class="ref"><div dir="ltr">‭א ב...‬</div><div dir="ltr">‭a b...‬</div><div dir="rtl">‭...b a‬</div><div dir="rtl">‭...ב א‬</div></div> -<div class="ref"><div dir="ltr">‭א ב...‬</div><div dir="ltr">‭a b...‬</div><div dir="rtl">‭...b a‬</div><div dir="rtl">‭...ב א‬</div></div> -</body> -</html>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-006b-expected.html b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-006b-expected.html deleted file mode 100644 index 0f6b7bbb..0000000 --- a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-006b-expected.html +++ /dev/null
@@ -1,16 +0,0 @@ -<!doctype html> -<html> -<head> -<meta charset="utf-8"/> -<title>The dir attribute: isolated from following text with intervening neutrals, opposite direction</title> -<style type="text/css"> -.test, .ref { font-size: 150%; border: 1px solid orange; margin: 10px; margin-right: 200px; padding: 5px; clear: both; } -input { margin: 5px; } -</style> -</head> -<body> -<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> -<div class="ref"><div dir="ltr">‭< א < > ב >...‬</div><div dir="rtl">‭...< b < > a >‬</div></div> -<div class="ref"><div dir="ltr">‭< א < > ב >...‬</div><div dir="rtl">‭...< b < > a >‬</div></div> -</body> -</html>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-007b-expected.html b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-007b-expected.html deleted file mode 100644 index 665153d..0000000 --- a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-007b-expected.html +++ /dev/null
@@ -1,16 +0,0 @@ -<!doctype html> -<html> -<head> -<meta charset="utf-8"/> -<title>The dir attribute: isolated from immediately following text, opposite direction</title> -<style type="text/css"> -.test, .ref { font-size: 150%; border: 1px solid orange; margin: 10px; margin-right: 200px; padding: 5px; clear: both; } -input { margin: 5px; } -</style> -</head> -<body> -<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> -<div class="ref"><div dir="ltr">‭אב...‬</div><div dir="ltr">‭ab...‬</div><div dir="rtl">‭...ba‬</div><div dir="rtl">‭...בא‬</div></div> -<div class="ref"><div dir="ltr">‭אב...‬</div><div dir="ltr">‭ab...‬</div><div dir="rtl">‭...ba‬</div><div dir="rtl">‭...בא‬</div></div> -</body> -</html>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-007c-expected.html b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-007c-expected.html deleted file mode 100644 index 665153d..0000000 --- a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-007c-expected.html +++ /dev/null
@@ -1,16 +0,0 @@ -<!doctype html> -<html> -<head> -<meta charset="utf-8"/> -<title>The dir attribute: isolated from immediately following text, opposite direction</title> -<style type="text/css"> -.test, .ref { font-size: 150%; border: 1px solid orange; margin: 10px; margin-right: 200px; padding: 5px; clear: both; } -input { margin: 5px; } -</style> -</head> -<body> -<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> -<div class="ref"><div dir="ltr">‭אב...‬</div><div dir="ltr">‭ab...‬</div><div dir="rtl">‭...ba‬</div><div dir="rtl">‭...בא‬</div></div> -<div class="ref"><div dir="ltr">‭אב...‬</div><div dir="ltr">‭ab...‬</div><div dir="rtl">‭...ba‬</div><div dir="rtl">‭...בא‬</div></div> -</body> -</html>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-008b-expected.html b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-008b-expected.html deleted file mode 100644 index 8eb90f8..0000000 --- a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-008b-expected.html +++ /dev/null
@@ -1,16 +0,0 @@ -<!doctype html> -<html> -<head> -<meta charset="utf-8"/> -<title>The dir attribute: isolated from preceding text, opposite direction</title> -<style type="text/css"> -.test, .ref { font-size: 150%; border: 1px solid orange; margin: 10px; margin-right: 200px; padding: 5px; clear: both; } -input { margin: 5px; } -</style> -</head> -<body> -<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> -<div class="ref"><div dir="ltr">‭א ב‬</div><div dir="ltr">‭a b‬</div><div dir="rtl">‭ב א‬</div><div dir="rtl">‭b a‬</div></div> -<div class="ref"><div dir="ltr">‭א ב‬</div><div dir="ltr">‭a b‬</div><div dir="rtl">‭ב א‬</div><div dir="rtl">‭b a‬</div></div> -</body> -</html>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-008c-expected.html b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-008c-expected.html deleted file mode 100644 index 8eb90f8..0000000 --- a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-008c-expected.html +++ /dev/null
@@ -1,16 +0,0 @@ -<!doctype html> -<html> -<head> -<meta charset="utf-8"/> -<title>The dir attribute: isolated from preceding text, opposite direction</title> -<style type="text/css"> -.test, .ref { font-size: 150%; border: 1px solid orange; margin: 10px; margin-right: 200px; padding: 5px; clear: both; } -input { margin: 5px; } -</style> -</head> -<body> -<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> -<div class="ref"><div dir="ltr">‭א ב‬</div><div dir="ltr">‭a b‬</div><div dir="rtl">‭ב א‬</div><div dir="rtl">‭b a‬</div></div> -<div class="ref"><div dir="ltr">‭א ב‬</div><div dir="ltr">‭a b‬</div><div dir="rtl">‭ב א‬</div><div dir="rtl">‭b a‬</div></div> -</body> -</html>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-009c-expected.html b/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-009c-expected.html deleted file mode 100644 index 30ee14c..0000000 --- a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-009c-expected.html +++ /dev/null
@@ -1,16 +0,0 @@ -<!doctype html> -<html> -<head> -<meta charset="utf-8"/> -<title>The dir attribute: isolated from surrounding text, auto</title> -<style type="text/css"> -.test, .ref { font-size: 150%; border: 1px solid orange; margin: 10px; margin-right: 200px; padding: 5px; clear: both; } -input { margin: 5px; } -</style> -</head> -<body> -<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> -<div class="ref"><div dir="ltr">‭ג < > b > < א...‬</div><div dir="rtl">‭...a > < ב < > c‬</div></div> -<div class="ref"><div dir="ltr">‭ג < > b > < א...‬</div><div dir="rtl">‭...a > < ב < > c‬</div></div> -</body> -</html>
diff --git a/third_party/WebKit/LayoutTests/fast/text/whitespace/nowrap-trailing-space-expected.txt b/third_party/WebKit/LayoutTests/fast/text/whitespace/nowrap-trailing-space-expected.txt new file mode 100644 index 0000000..69bb5cb --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/text/whitespace/nowrap-trailing-space-expected.txt
@@ -0,0 +1,3 @@ +crbug.com/561997: Trailing space in a no-wrap span should not prevent setting a line-break on that span. + +All text should be on same line.
diff --git a/third_party/WebKit/LayoutTests/fast/text/whitespace/nowrap-trailing-space.html b/third_party/WebKit/LayoutTests/fast/text/whitespace/nowrap-trailing-space.html new file mode 100644 index 0000000..be52b0e --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/text/whitespace/nowrap-trailing-space.html
@@ -0,0 +1,16 @@ +<!DOCTYPE html> +<style> +.wrapper { + float: left; +} +.nowrap { + white-space: nowrap; +} +</style> +<p>crbug.com/561997: Trailing space in a no-wrap span should not prevent setting a line-break on that span.</p> +<div class="wrapper"><span>All text should be on same</span> <span class="nowrap">line. </span></div> +<script> + if (window.testRunner) + testRunner.dumpAsText(); +</script> +
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/debugger-test.js b/third_party/WebKit/LayoutTests/http/tests/inspector/debugger-test.js index 83557fff..978fb69 100644 --- a/third_party/WebKit/LayoutTests/http/tests/inspector/debugger-test.js +++ b/third_party/WebKit/LayoutTests/http/tests/inspector/debugger-test.js
@@ -386,27 +386,6 @@ InspectorTest.addSniffer(WebInspector.SourcesView.prototype, "_addUISourceCode", InspectorTest.waitForScriptSource.bind(InspectorTest, scriptName, callback)); }; -InspectorTest.dumpNavigatorView = function(navigatorView) -{ - dumpNavigatorTreeOutline(navigatorView._scriptsTree); - - function dumpNavigatorTreeElement(prefix, treeElement) - { - InspectorTest.addResult(prefix + treeElement.title); - treeElement.expand(); - var children = treeElement.children(); - for (var i = 0; i < children.length; ++i) - dumpNavigatorTreeElement(prefix + " ", children[i]); - } - - function dumpNavigatorTreeOutline(treeOutline) - { - var children = treeOutline.rootElement().children(); - for (var i = 0; i < children.length; ++i) - dumpNavigatorTreeElement("", children[i]); - } -}; - InspectorTest.setBreakpoint = function(sourceFrame, lineNumber, condition, enabled) { if (!sourceFrame._muted)
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/inspector-test.js b/third_party/WebKit/LayoutTests/http/tests/inspector/inspector-test.js index 7d75817c..d0db2418a 100644 --- a/third_party/WebKit/LayoutTests/http/tests/inspector/inspector-test.js +++ b/third_party/WebKit/LayoutTests/http/tests/inspector/inspector-test.js
@@ -413,6 +413,45 @@ } } +InspectorTest.dumpNavigatorView = function(navigatorView) +{ + dumpNavigatorTreeOutline(navigatorView._scriptsTree); + + function dumpNavigatorTreeElement(prefix, treeElement) + { + InspectorTest.addResult(prefix + treeElement.title); + treeElement.expand(); + var children = treeElement.children(); + for (var i = 0; i < children.length; ++i) + dumpNavigatorTreeElement(prefix + " ", children[i]); + } + + function dumpNavigatorTreeOutline(treeOutline) + { + var children = treeOutline.rootElement().children(); + for (var i = 0; i < children.length; ++i) + dumpNavigatorTreeElement("", children[i]); + } +} + +InspectorTest.dumpNavigatorViewInAllModes = function(view) +{ + ["frame", "frame/domain", "frame/domain/folder", "domain", "domain/folder"].forEach(InspectorTest.dumpNavigatorViewInMode.bind(InspectorTest, view)); +} + +InspectorTest.dumpNavigatorViewInMode = function(view, mode) +{ + InspectorTest.addResult(view instanceof WebInspector.SourcesNavigatorView ? "Sources:" : "Content Scripts:"); + if (WebInspector.moduleSetting("navigatorGroupByFrame").get() !== mode.includes("frame")) + WebInspector.moduleSetting("navigatorGroupByFrame").set(mode.includes("frame")); + if (WebInspector.moduleSetting("navigatorGroupByDomain") !== mode.includes("domain")) + WebInspector.moduleSetting("navigatorGroupByDomain").set(mode.includes("domain")); + if (WebInspector.moduleSetting("navigatorGroupByFolder") !== mode.includes("folder")) + WebInspector.moduleSetting("navigatorGroupByFolder").set(mode.includes("folder")); + InspectorTest.addResult("-------- Setting mode: [" + mode + "]"); + InspectorTest.dumpNavigatorView(view); +} + InspectorTest.assertGreaterOrEqual = function(a, b, message) { if (a < b)
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/network-test.js b/third_party/WebKit/LayoutTests/http/tests/inspector/network-test.js index 3780e5d..b10ec60b 100644 --- a/third_party/WebKit/LayoutTests/http/tests/inspector/network-test.js +++ b/third_party/WebKit/LayoutTests/http/tests/inspector/network-test.js
@@ -71,6 +71,14 @@ InspectorTest.addResult(requests[i].url); } +// |url| must be a regular expression to match request URLs. +InspectorTest.findRequestsByURLPattern = function(urlPattern) +{ + return InspectorTest.networkRequests().filter(function(value) { + return urlPattern.test(value.url) + }); +} + InspectorTest.makeSimpleXHR = function(method, url, async, callback) { InspectorTest.makeXHR(method, url, async, undefined, undefined, [], false, undefined, undefined, callback);
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/network/network-document-initiator.html b/third_party/WebKit/LayoutTests/http/tests/inspector/network/network-document-initiator.html index 010aa34..088bd37f 100644 --- a/third_party/WebKit/LayoutTests/http/tests/inspector/network/network-document-initiator.html +++ b/third_party/WebKit/LayoutTests/http/tests/inspector/network/network-document-initiator.html
@@ -14,15 +14,6 @@ InspectorTest.evaluateInPage("navigateFromScript()"); InspectorTest.runWhenPageLoads(step1); - function findRequestByURL(url) - { - var requests = InspectorTest.networkRequests(); - for (var i = 0; i < requests.length; ++i) { - if (url.test(requests[i].url)) - return requests[i]; - } - } - function dumpInitiator(request) { var initiator = request.initiator(); @@ -43,7 +34,9 @@ function step1() { - dumpInitiator(findRequestByURL(/\?foo/)); + var results = InspectorTest.findRequestsByURLPattern(/\?foo/); + InspectorTest.assertTrue(results.length !== 0); + dumpInitiator(results[0]); InspectorTest.completeTest(); } }
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/network/network-initiator-from-console.html b/third_party/WebKit/LayoutTests/http/tests/inspector/network/network-initiator-from-console.html index 7ff6f80..34d2f40 100644 --- a/third_party/WebKit/LayoutTests/http/tests/inspector/network/network-initiator-from-console.html +++ b/third_party/WebKit/LayoutTests/http/tests/inspector/network/network-initiator-from-console.html
@@ -7,15 +7,6 @@ { InspectorTest.reloadPage(step1); - function findRequestByURL(url) - { - var requests = InspectorTest.networkRequests(); - for (var i = 0; i < requests.length; ++i) { - if (url.test(requests[i].url)) - return requests[i]; - } - } - function step1() { InspectorTest.networkManager.addEventListener(WebInspector.NetworkManager.EventTypes.RequestStarted, onRequest); @@ -35,7 +26,8 @@ function step2() { - if (!findRequestByURL(/silent_script.js/)) + var results = InspectorTest.findRequestsByURLPattern(/silent_script.js/); + if (results.length === 0) return; InspectorTest.completeTest();
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/network/network-initiator.html b/third_party/WebKit/LayoutTests/http/tests/inspector/network/network-initiator.html index 04cfa98..3adb5917 100644 --- a/third_party/WebKit/LayoutTests/http/tests/inspector/network/network-initiator.html +++ b/third_party/WebKit/LayoutTests/http/tests/inspector/network/network-initiator.html
@@ -27,15 +27,6 @@ { step2(); - function findRequestByURL(url) - { - var requests = InspectorTest.networkRequests(); - for (var i = 0; i < requests.length; ++i) { - if (url.test(requests[i].url)) - return requests[i]; - } - } - /*function step1() { InspectorTest.networkManager.addEventListener(WebInspector.NetworkManager.EventTypes.RequestFinished, onRequest); @@ -51,7 +42,7 @@ function step2() { - //if (!findRequestByURL(/size=300/)) + //if (InspectorTest.findRequestsByURLPattern(/size=300/).length === 0) // return; InspectorTest.addConsoleSniffer(step3); @@ -62,11 +53,12 @@ { function dumpInitiator(url) { - var request = findRequestByURL(new RegExp(url.replace(".", "\\."))); - if (!request) { + var matching_requests = InspectorTest.findRequestsByURLPattern(new RegExp(url.replace(".", "\\."))); + if (matching_requests.length === 0) { InspectorTest.addResult(url + " NOT FOUND"); return; } + var request = matching_requests[0]; var initiator = request.initiator(); InspectorTest.addResult(request.url + ": " + initiator.type); if (initiator.url)
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/network/resources/call-success-with-integrity-frame.html b/third_party/WebKit/LayoutTests/http/tests/inspector/network/resources/call-success-with-integrity-frame.html new file mode 100644 index 0000000..82637db --- /dev/null +++ b/third_party/WebKit/LayoutTests/http/tests/inspector/network/resources/call-success-with-integrity-frame.html
@@ -0,0 +1,14 @@ +<!DOCTYPE HTML> +<html> +<script> +function success() { + console.log("Script loaded successfully."); +} + +function scriptFail() { + console.log("Script failed to load."); +} +</script> + +<script onerror='scriptFail();' integrity='sha256-B0/62fJSJFrdjEFR9ba04m/D+LHQ+zG6PGcaR0Trpxg=' src='call-success.js'></script> +</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/network/resources/call-success.js b/third_party/WebKit/LayoutTests/http/tests/inspector/network/resources/call-success.js new file mode 100644 index 0000000..679b655 --- /dev/null +++ b/third_party/WebKit/LayoutTests/http/tests/inspector/network/resources/call-success.js
@@ -0,0 +1 @@ +success();
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/network/resources/style-with-integrity-frame.html b/third_party/WebKit/LayoutTests/http/tests/inspector/network/resources/style-with-integrity-frame.html new file mode 100644 index 0000000..469ef95 --- /dev/null +++ b/third_party/WebKit/LayoutTests/http/tests/inspector/network/resources/style-with-integrity-frame.html
@@ -0,0 +1,13 @@ +<!DOCTYPE HTML> +<html> +<script> +function styleLoad() { + console.log("Stylesheet loaded successfully."); +} + +function styleError() { + console.log("Stylesheet failed to load."); +} +</script> +<link onload="styleLoad();" onerror="styleError();" href="style.css" rel="stylesheet" /> +</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/network/subresource-integrity-number-of-requests-for-script-expected.txt b/third_party/WebKit/LayoutTests/http/tests/inspector/network/subresource-integrity-number-of-requests-for-script-expected.txt new file mode 100644 index 0000000..86cde36 --- /dev/null +++ b/third_party/WebKit/LayoutTests/http/tests/inspector/network/subresource-integrity-number-of-requests-for-script-expected.txt
@@ -0,0 +1,4 @@ +CONSOLE MESSAGE: line 5: Script loaded successfully. +Verify that only one request is made for basic script requests with integrity attribute. + +
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/network/subresource-integrity-number-of-requests-for-script.html b/third_party/WebKit/LayoutTests/http/tests/inspector/network/subresource-integrity-number-of-requests-for-script.html new file mode 100644 index 0000000..1ffcd1d --- /dev/null +++ b/third_party/WebKit/LayoutTests/http/tests/inspector/network/subresource-integrity-number-of-requests-for-script.html
@@ -0,0 +1,30 @@ +<!DOCTYPE html> +<html> +<head> +<script src="../inspector-test.js"></script> +<script src="../network-test.js"></script> +<script> +// Regression test for https://crbug.com/573269. +function loadIFrame() { + var iframe = document.createElement('iframe'); + iframe.src = 'resources/call-success-with-integrity-frame.html'; + document.body.appendChild(iframe); +} + +function test() { + InspectorTest.addConsoleSniffer(step1); + InspectorTest.evaluateInPage("loadIFrame()"); + + function step1() { + var requests = InspectorTest.findRequestsByURLPattern(/call-success.js/); + InspectorTest.assertTrue(requests.length === 1); + InspectorTest.completeTest(); + } +} +</script> +</head> +<body> +<script>runTest();</script> +<p>Verify that only one request is made for basic script requests with integrity attribute.</p> +</body> +</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/network/subresource-integrity-number-of-requests-for-stylesheet-expected.txt b/third_party/WebKit/LayoutTests/http/tests/inspector/network/subresource-integrity-number-of-requests-for-stylesheet-expected.txt new file mode 100644 index 0000000..80f40fe --- /dev/null +++ b/third_party/WebKit/LayoutTests/http/tests/inspector/network/subresource-integrity-number-of-requests-for-stylesheet-expected.txt
@@ -0,0 +1,4 @@ +CONSOLE MESSAGE: line 5: Stylesheet loaded successfully. +Verify that only one request is made for basic stylesheet requests with integrity attribute. + +
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/network/subresource-integrity-number-of-requests-for-stylesheet.html b/third_party/WebKit/LayoutTests/http/tests/inspector/network/subresource-integrity-number-of-requests-for-stylesheet.html new file mode 100644 index 0000000..c84e13d --- /dev/null +++ b/third_party/WebKit/LayoutTests/http/tests/inspector/network/subresource-integrity-number-of-requests-for-stylesheet.html
@@ -0,0 +1,30 @@ +<!DOCTYPE html> +<html> +<head> +<script src="../inspector-test.js"></script> +<script src="../network-test.js"></script> +<script> +// Regression test for https://crbug.com/573269. +function loadIFrame() { + var iframe = document.createElement('iframe'); + iframe.src = 'resources/style-with-integrity-frame.html'; + document.body.appendChild(iframe); +} + +function test() { + InspectorTest.addConsoleSniffer(step1); + InspectorTest.evaluateInPage("loadIFrame()"); + + function step1() { + var requests = InspectorTest.findRequestsByURLPattern(/style.css/); + InspectorTest.assertTrue(requests.length === 1); + InspectorTest.completeTest(); + } +} +</script> +</head> +<body> +<script>runTest();</script> +<p>Verify that only one request is made for basic stylesheet requests with integrity attribute.</p> +</body> +</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/resource-tree/resource-tree-frame-add-expected.txt b/third_party/WebKit/LayoutTests/http/tests/inspector/resource-tree/resource-tree-frame-add-expected.txt index aef7ac94..6393515 100644 --- a/third_party/WebKit/LayoutTests/http/tests/inspector/resource-tree/resource-tree-frame-add-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/inspector/resource-tree/resource-tree-frame-add-expected.txt
@@ -1,4 +1,4 @@ -CONSOLE MESSAGE: line 21: iframe navigated +CONSOLE MESSAGE: line 4: iframe loaded Tests resource tree model on iframe addition, compares resource tree against golden. Every line is important. @@ -28,6 +28,54 @@ Stylesheets styles-initial.css resource-tree-frame-add.html +Sources: +-------- Setting mode: [frame] +top + resource-tree-frame-add.html + inspector-test.js + resource-tree-test.js + resources-test.js + styles-initial.css +Sources: +-------- Setting mode: [frame/domain] +top + 127.0.0.1:8000 + resource-tree-frame-add.html + inspector-test.js + resource-tree-test.js + resources-test.js + styles-initial.css +Sources: +-------- Setting mode: [frame/domain/folder] +top + 127.0.0.1:8000 + inspector + resource-tree + resources + styles-initial.css + resource-tree-frame-add.html + resource-tree-test.js + inspector-test.js + resources-test.js +Sources: +-------- Setting mode: [domain] +127.0.0.1:8000 + resource-tree-frame-add.html + inspector-test.js + resource-tree-test.js + resources-test.js + styles-initial.css +Sources: +-------- Setting mode: [domain/folder] +127.0.0.1:8000 + inspector + resource-tree + resources + styles-initial.css + resource-tree-frame-add.html + resource-tree-test.js + inspector-test.js + resources-test.js After addition ==================================== @@ -67,4 +115,73 @@ Stylesheets styles-initial.css resource-tree-frame-add.html +Sources: +-------- Setting mode: [frame] +top + resource-tree-frame-add.html + inspector-test.js + resource-tree-test.js + resources-test.js + styles-initial.css + resource-tree-frame-add-iframe.html + resource-tree-frame-add-iframe.html + script-navigated.js + styles-navigated.css +Sources: +-------- Setting mode: [frame/domain] +top + 127.0.0.1:8000 + resource-tree-frame-add.html + inspector-test.js + resource-tree-test.js + resources-test.js + styles-initial.css + resource-tree-frame-add-iframe.html + 127.0.0.1:8000 + resource-tree-frame-add-iframe.html + script-navigated.js + styles-navigated.css +Sources: +-------- Setting mode: [frame/domain/folder] +top + 127.0.0.1:8000 + inspector + resource-tree + resources + styles-initial.css + resource-tree-frame-add.html + resource-tree-test.js + inspector-test.js + resources-test.js + resource-tree-frame-add-iframe.html + 127.0.0.1:8000 + inspector/resource-tree/resources + resource-tree-frame-add-iframe.html + script-navigated.js + styles-navigated.css +Sources: +-------- Setting mode: [domain] +127.0.0.1:8000 + resource-tree-frame-add-iframe.html + resource-tree-frame-add.html + inspector-test.js + resource-tree-test.js + resources-test.js + script-navigated.js + styles-initial.css + styles-navigated.css +Sources: +-------- Setting mode: [domain/folder] +127.0.0.1:8000 + inspector + resource-tree + resources + resource-tree-frame-add-iframe.html + script-navigated.js + styles-initial.css + styles-navigated.css + resource-tree-frame-add.html + resource-tree-test.js + inspector-test.js + resources-test.js
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/resource-tree/resource-tree-frame-add.html b/third_party/WebKit/LayoutTests/http/tests/inspector/resource-tree/resource-tree-frame-add.html index 75b95f8..b9d8678 100644 --- a/third_party/WebKit/LayoutTests/http/tests/inspector/resource-tree/resource-tree-frame-add.html +++ b/third_party/WebKit/LayoutTests/http/tests/inspector/resource-tree/resource-tree-frame-add.html
@@ -7,40 +7,23 @@ <link rel="stylesheet" href="resources/styles-initial.css"> <script> - function createIframe() { var iframe = document.createElement("iframe"); iframe.setAttribute("src", "resources/resource-tree-frame-add-iframe.html"); - iframe.onload = onIframeLoad; document.body.appendChild(iframe); } -function onIframeLoad() -{ - console.log("iframe navigated"); -} - function test() { - InspectorTest.runAfterResourcesAreFinished(["resource-tree-frame-add.html", "resource-tree-test.js", "styles-initial.css"], step1); - - function step1() - { - InspectorTest.addResult("Before addition"); - InspectorTest.addResult("===================================="); - InspectorTest.dumpResourceTreeEverything(); - InspectorTest.addConsoleSniffer(step2); - InspectorTest.evaluateInPage("createIframe()"); - } + InspectorTest.addResult("Before addition"); + InspectorTest.addResult("===================================="); + InspectorTest.dumpResourceTreeEverything(); + InspectorTest.addConsoleSniffer(step2); + InspectorTest.evaluateInPage("createIframe()"); function step2() { - InspectorTest.runAfterResourcesAreFinished(["resource-tree-frame-add-iframe.html", "styles-navigated.css", "script-navigated.js"], step3); - } - - function step3() - { InspectorTest.addResult(""); InspectorTest.addResult("After addition"); InspectorTest.addResult("====================================");
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/resource-tree/resource-tree-frame-navigate-expected.txt b/third_party/WebKit/LayoutTests/http/tests/inspector/resource-tree/resource-tree-frame-navigate-expected.txt index ddab759..356a6fe 100644 --- a/third_party/WebKit/LayoutTests/http/tests/inspector/resource-tree/resource-tree-frame-navigate-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/inspector/resource-tree/resource-tree-frame-navigate-expected.txt
@@ -1,4 +1,4 @@ -CONSOLE MESSAGE: line 22: iframe navigated +CONSOLE MESSAGE: line 4: iframe loaded Tests resource tree model on iframe navigation, compares resource tree against golden. Every line is important. @@ -40,6 +40,75 @@ Stylesheets styles-initial.css resource-tree-frame-navigate.html +Sources: +-------- Setting mode: [frame] +top + resource-tree-frame-navigate.html + inspector-test.js + resource-tree-test.js + resources-test.js + styles-initial.css + iframe (resource-tree-frame-navigate-iframe-before.html) + resource-tree-frame-navigate-iframe-before.html + script-initial.js + styles-initial-2.css +Sources: +-------- Setting mode: [frame/domain] +top + 127.0.0.1:8000 + resource-tree-frame-navigate.html + inspector-test.js + resource-tree-test.js + resources-test.js + styles-initial.css + iframe (resource-tree-frame-navigate-iframe-before.html) + 127.0.0.1:8000 + resource-tree-frame-navigate-iframe-before.html + script-initial.js + styles-initial-2.css +Sources: +-------- Setting mode: [frame/domain/folder] +top + 127.0.0.1:8000 + inspector + resource-tree + resources + styles-initial.css + resource-tree-frame-navigate.html + resource-tree-test.js + inspector-test.js + resources-test.js + iframe (resource-tree-frame-navigate-iframe-before.html) + 127.0.0.1:8000 + inspector/resource-tree/resources + resource-tree-frame-navigate-iframe-before.html + script-initial.js + styles-initial-2.css +Sources: +-------- Setting mode: [domain] +127.0.0.1:8000 + resource-tree-frame-navigate-iframe-before.html + resource-tree-frame-navigate.html + inspector-test.js + resource-tree-test.js + resources-test.js + script-initial.js + styles-initial-2.css + styles-initial.css +Sources: +-------- Setting mode: [domain/folder] +127.0.0.1:8000 + inspector + resource-tree + resources + resource-tree-frame-navigate-iframe-before.html + script-initial.js + styles-initial-2.css + styles-initial.css + resource-tree-frame-navigate.html + resource-tree-test.js + inspector-test.js + resources-test.js After navigation ==================================== @@ -79,4 +148,73 @@ Stylesheets styles-initial.css resource-tree-frame-navigate.html +Sources: +-------- Setting mode: [frame] +top + resource-tree-frame-navigate.html + inspector-test.js + resource-tree-test.js + resources-test.js + styles-initial.css + iframe (resource-tree-frame-navigate-iframe-after.html) + resource-tree-frame-navigate-iframe-after.html + script-navigated.js + styles-navigated.css +Sources: +-------- Setting mode: [frame/domain] +top + 127.0.0.1:8000 + resource-tree-frame-navigate.html + inspector-test.js + resource-tree-test.js + resources-test.js + styles-initial.css + iframe (resource-tree-frame-navigate-iframe-after.html) + 127.0.0.1:8000 + resource-tree-frame-navigate-iframe-after.html + script-navigated.js + styles-navigated.css +Sources: +-------- Setting mode: [frame/domain/folder] +top + 127.0.0.1:8000 + inspector + resource-tree + resources + styles-initial.css + resource-tree-frame-navigate.html + resource-tree-test.js + inspector-test.js + resources-test.js + iframe (resource-tree-frame-navigate-iframe-after.html) + 127.0.0.1:8000 + inspector/resource-tree/resources + resource-tree-frame-navigate-iframe-after.html + script-navigated.js + styles-navigated.css +Sources: +-------- Setting mode: [domain] +127.0.0.1:8000 + resource-tree-frame-navigate-iframe-after.html + resource-tree-frame-navigate.html + inspector-test.js + resource-tree-test.js + resources-test.js + script-navigated.js + styles-initial.css + styles-navigated.css +Sources: +-------- Setting mode: [domain/folder] +127.0.0.1:8000 + inspector + resource-tree + resources + resource-tree-frame-navigate-iframe-after.html + script-navigated.js + styles-initial.css + styles-navigated.css + resource-tree-frame-navigate.html + resource-tree-test.js + inspector-test.js + resources-test.js
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/resource-tree/resource-tree-frame-navigate.html b/third_party/WebKit/LayoutTests/http/tests/inspector/resource-tree/resource-tree-frame-navigate.html index 86e529d6..7cc024d 100644 --- a/third_party/WebKit/LayoutTests/http/tests/inspector/resource-tree/resource-tree-frame-navigate.html +++ b/third_party/WebKit/LayoutTests/http/tests/inspector/resource-tree/resource-tree-frame-navigate.html
@@ -7,41 +7,23 @@ <link rel="stylesheet" href="resources/styles-initial.css"> <script> - function navigateIframe() { var iframe = document.getElementById("iframe"); - iframe.removeAttribute("onload"); - iframe.onload = onIframeLoad; iframe.setAttribute("src", "resources/resource-tree-frame-navigate-iframe-after.html"); document.body.appendChild(iframe); } -function onIframeLoad() -{ - console.log("iframe navigated"); -} - function test() { - InspectorTest.runAfterResourcesAreFinished(["resource-tree-frame-navigate-iframe-before.html", "script-initial.js", "styles-initial.css", "styles-initial-2.css"], step1); - - function step1() - { - InspectorTest.addResult("Before navigation"); - InspectorTest.addResult("===================================="); - InspectorTest.dumpResourceTreeEverything(); - InspectorTest.addConsoleSniffer(step2); - InspectorTest.evaluateInPage("navigateIframe()"); - } + InspectorTest.addResult("Before navigation"); + InspectorTest.addResult("===================================="); + InspectorTest.dumpResourceTreeEverything(); + InspectorTest.addConsoleSniffer(step2); + InspectorTest.evaluateInPage("navigateIframe()"); function step2() { - InspectorTest.runAfterResourcesAreFinished(["resource-tree-frame-navigate-iframe-after.html", "styles-navigated.css", "script-navigated.js"], step3); - } - - function step3() - { InspectorTest.addResult(""); InspectorTest.addResult("After navigation"); InspectorTest.addResult("====================================");
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/resource-tree/resource-tree-htmlimports-expected.txt b/third_party/WebKit/LayoutTests/http/tests/inspector/resource-tree/resource-tree-htmlimports-expected.txt index 4b9a526..1fc755a 100644 --- a/third_party/WebKit/LayoutTests/http/tests/inspector/resource-tree/resource-tree-htmlimports-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/inspector/resource-tree/resource-tree-htmlimports-expected.txt
@@ -29,4 +29,62 @@ import-child.html import-hello.html resource-tree-htmlimports.html +Sources: +-------- Setting mode: [frame] +top + import-child.html + import-hello.html + resource-tree-htmlimports.html + import-hello.js + inspector-test.js + resource-tree-test.js + resources-test.js +Sources: +-------- Setting mode: [frame/domain] +top + 127.0.0.1:8000 + import-child.html + import-hello.html + resource-tree-htmlimports.html + import-hello.js + inspector-test.js + resource-tree-test.js + resources-test.js +Sources: +-------- Setting mode: [frame/domain/folder] +top + 127.0.0.1:8000 + inspector + resource-tree + resources + import-child.html + import-hello.html + import-hello.js + resource-tree-htmlimports.html + resource-tree-test.js + inspector-test.js + resources-test.js +Sources: +-------- Setting mode: [domain] +127.0.0.1:8000 + import-child.html + import-hello.html + resource-tree-htmlimports.html + import-hello.js + inspector-test.js + resource-tree-test.js + resources-test.js +Sources: +-------- Setting mode: [domain/folder] +127.0.0.1:8000 + inspector + resource-tree + resources + import-child.html + import-hello.html + import-hello.js + resource-tree-htmlimports.html + resource-tree-test.js + inspector-test.js + resources-test.js
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/resource-tree/resource-tree-non-unique-url-expected.txt b/third_party/WebKit/LayoutTests/http/tests/inspector/resource-tree/resource-tree-non-unique-url-expected.txt index cbc501efa..559be63 100644 --- a/third_party/WebKit/LayoutTests/http/tests/inspector/resource-tree/resource-tree-non-unique-url-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/inspector/resource-tree/resource-tree-non-unique-url-expected.txt
@@ -15,4 +15,62 @@ resource-tree-test.js resources-test.js resource-tree-non-unique-url.html +Sources: +-------- Setting mode: [frame] +top + resource-tree-non-unique-url.html + inspector-test.js + resource-tree-test.js + resources-test.js + resource-tree-non-unique-url-iframe.html + resource-tree-non-unique-url-iframe.html + styles-non-unique-url.css +Sources: +-------- Setting mode: [frame/domain] +top + 127.0.0.1:8000 + resource-tree-non-unique-url.html + inspector-test.js + resource-tree-test.js + resources-test.js + resource-tree-non-unique-url-iframe.html + 127.0.0.1:8000 + resource-tree-non-unique-url-iframe.html + styles-non-unique-url.css +Sources: +-------- Setting mode: [frame/domain/folder] +top + 127.0.0.1:8000 + inspector + resource-tree + resource-tree-non-unique-url.html + resource-tree-test.js + inspector-test.js + resources-test.js + resource-tree-non-unique-url-iframe.html + 127.0.0.1:8000 + inspector/resource-tree/resources + resource-tree-non-unique-url-iframe.html + styles-non-unique-url.css +Sources: +-------- Setting mode: [domain] +127.0.0.1:8000 + resource-tree-non-unique-url-iframe.html + resource-tree-non-unique-url.html + inspector-test.js + resource-tree-test.js + resources-test.js + styles-non-unique-url.css +Sources: +-------- Setting mode: [domain/folder] +127.0.0.1:8000 + inspector + resource-tree + resources + resource-tree-non-unique-url-iframe.html + styles-non-unique-url.css + resource-tree-non-unique-url.html + resource-tree-test.js + inspector-test.js + resources-test.js
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/resource-tree/resource-tree-reload-expected.txt b/third_party/WebKit/LayoutTests/http/tests/inspector/resource-tree/resource-tree-reload-expected.txt index 8683746f..21e1ae4 100644 --- a/third_party/WebKit/LayoutTests/http/tests/inspector/resource-tree/resource-tree-reload-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/inspector/resource-tree/resource-tree-reload-expected.txt
@@ -38,4 +38,73 @@ Stylesheets styles-initial.css resource-tree-reload.html +Sources: +-------- Setting mode: [frame] +top + resource-tree-reload.html + inspector-test.js + resource-tree-test.js + resources-test.js + styles-initial.css + resource-tree-reload-iframe.html + resource-tree-reload-iframe.html + script-initial.js + styles-initial-2.css +Sources: +-------- Setting mode: [frame/domain] +top + 127.0.0.1:8000 + resource-tree-reload.html + inspector-test.js + resource-tree-test.js + resources-test.js + styles-initial.css + resource-tree-reload-iframe.html + 127.0.0.1:8000 + resource-tree-reload-iframe.html + script-initial.js + styles-initial-2.css +Sources: +-------- Setting mode: [frame/domain/folder] +top + 127.0.0.1:8000 + inspector + resource-tree + resources + styles-initial.css + resource-tree-reload.html + resource-tree-test.js + inspector-test.js + resources-test.js + resource-tree-reload-iframe.html + 127.0.0.1:8000 + inspector/resource-tree/resources + resource-tree-reload-iframe.html + script-initial.js + styles-initial-2.css +Sources: +-------- Setting mode: [domain] +127.0.0.1:8000 + resource-tree-reload-iframe.html + resource-tree-reload.html + inspector-test.js + resource-tree-test.js + resources-test.js + script-initial.js + styles-initial-2.css + styles-initial.css +Sources: +-------- Setting mode: [domain/folder] +127.0.0.1:8000 + inspector + resource-tree + resources + resource-tree-reload-iframe.html + script-initial.js + styles-initial-2.css + styles-initial.css + resource-tree-reload.html + resource-tree-test.js + inspector-test.js + resources-test.js
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/resource-tree/resource-tree-test.js b/third_party/WebKit/LayoutTests/http/tests/inspector/resource-tree/resource-tree-test.js index d606e5d..d5db94208 100644 --- a/third_party/WebKit/LayoutTests/http/tests/inspector/resource-tree/resource-tree-test.js +++ b/third_party/WebKit/LayoutTests/http/tests/inspector/resource-tree/resource-tree-test.js
@@ -65,6 +65,12 @@ } dump(WebInspector.panels.resources.resourcesListTreeElement, ""); + if (!InspectorTest._testSourceNavigator) { + InspectorTest._testSourceNavigator = new WebInspector.SourcesNavigatorView(); + InspectorTest._testSourceNavigator.setWorkspace(WebInspector.workspace); + InspectorTest._testSourceNavigator.show(WebInspector.inspectorView.element); + } + InspectorTest.dumpNavigatorViewInAllModes(InspectorTest._testSourceNavigator); } InspectorTest.dumpResourceTreeEverything = function()
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/resource-tree/resources/resource-tree-frame-add-iframe.html b/third_party/WebKit/LayoutTests/http/tests/inspector/resource-tree/resources/resource-tree-frame-add-iframe.html index 0c884c8..894b4eac 100644 --- a/third_party/WebKit/LayoutTests/http/tests/inspector/resource-tree/resources/resource-tree-frame-add-iframe.html +++ b/third_party/WebKit/LayoutTests/http/tests/inspector/resource-tree/resources/resource-tree-frame-add-iframe.html
@@ -1,8 +1,8 @@ <html> <head> -<script src="script-navigated.js"></script> <link rel="stylesheet" href="styles-navigated.css"> +<script src="script-navigated.js"></script> </head> <body>
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/resource-tree/resources/resource-tree-frame-navigate-iframe-after.html b/third_party/WebKit/LayoutTests/http/tests/inspector/resource-tree/resources/resource-tree-frame-navigate-iframe-after.html index 0c884c8..894b4eac 100644 --- a/third_party/WebKit/LayoutTests/http/tests/inspector/resource-tree/resources/resource-tree-frame-navigate-iframe-after.html +++ b/third_party/WebKit/LayoutTests/http/tests/inspector/resource-tree/resources/resource-tree-frame-navigate-iframe-after.html
@@ -1,8 +1,8 @@ <html> <head> -<script src="script-navigated.js"></script> <link rel="stylesheet" href="styles-navigated.css"> +<script src="script-navigated.js"></script> </head> <body>
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/resource-tree/resources/script-navigated.js b/third_party/WebKit/LayoutTests/http/tests/inspector/resource-tree/resources/script-navigated.js index 6940729..a064c9a3 100644 --- a/third_party/WebKit/LayoutTests/http/tests/inspector/resource-tree/resources/script-navigated.js +++ b/third_party/WebKit/LayoutTests/http/tests/inspector/resource-tree/resources/script-navigated.js
@@ -1,2 +1,4 @@ function foo() { } + +console.log("iframe loaded");
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/resources-test.js b/third_party/WebKit/LayoutTests/http/tests/inspector/resources-test.js index b1a7508a..32ac359 100644 --- a/third_party/WebKit/LayoutTests/http/tests/inspector/resources-test.js +++ b/third_party/WebKit/LayoutTests/http/tests/inspector/resources-test.js
@@ -1,5 +1,6 @@ var initialize_ResourceTest = function() { +InspectorTest.preloadPanel("sources"); InspectorTest.preloadPanel("resources"); InspectorTest.requestURLComparer = function(r1, r2)
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/search/sources-search-scope-in-files.html b/third_party/WebKit/LayoutTests/http/tests/inspector/search/sources-search-scope-in-files.html index 01c072a..89361af 100644 --- a/third_party/WebKit/LayoutTests/http/tests/inspector/search/sources-search-scope-in-files.html +++ b/third_party/WebKit/LayoutTests/http/tests/inspector/search/sources-search-scope-in-files.html
@@ -57,7 +57,7 @@ var paths = []; for (var i = 0; i < names.length; ++i) paths.push("/var/www/" + names[i]); - WebInspector.networkMapping._fileSystemWorkspaceBinding._onSearchCompleted({data: {requestId: requestId, fileSystemPath: path, files: paths}}); + WebInspector.isolatedFileSystemManager._onSearchCompleted({data: {requestId: requestId, fileSystemPath: path, files: paths}}); } }
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/search/sources-search-scope-many-projects.html b/third_party/WebKit/LayoutTests/http/tests/inspector/search/sources-search-scope-many-projects.html index 6539139..73cc102 100644 --- a/third_party/WebKit/LayoutTests/http/tests/inspector/search/sources-search-scope-many-projects.html +++ b/third_party/WebKit/LayoutTests/http/tests/inspector/search/sources-search-scope-many-projects.html
@@ -80,7 +80,7 @@ var paths = []; for (var i = 0; i < names.length; ++i) paths.push("/var/www/" + names[i]); - WebInspector.networkMapping._fileSystemWorkspaceBinding._onSearchCompleted({data: {requestId: requestId, fileSystemPath: path, files: paths}}); + WebInspector.isolatedFileSystemManager._onSearchCompleted({data: {requestId: requestId, fileSystemPath: path, files: paths}}); } }
diff --git a/third_party/WebKit/LayoutTests/http/tests/resources/testharnessreport.js b/third_party/WebKit/LayoutTests/http/tests/resources/testharnessreport.js index 0d9a8a6..56dcac54 100644 --- a/third_party/WebKit/LayoutTests/http/tests/resources/testharnessreport.js +++ b/third_party/WebKit/LayoutTests/http/tests/resources/testharnessreport.js
@@ -117,8 +117,11 @@ } // Add results element to document. - if (!document.body) + if (!document.body) { + if (!document.documentElement) + document.appendChild(document.createElement('html')); document.documentElement.appendChild(document.createElement("body")); + } document.body.appendChild(results); if (self.testRunner)
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/oninstall-script-error.html b/third_party/WebKit/LayoutTests/http/tests/serviceworker/oninstall-script-error.html index fb63bc32e..55fad3b 100644 --- a/third_party/WebKit/LayoutTests/http/tests/serviceworker/oninstall-script-error.html +++ b/third_party/WebKit/LayoutTests/http/tests/serviceworker/oninstall-script-error.html
@@ -45,15 +45,21 @@ script: 'resources/oninstall-throw-error-from-nested-event-worker.js', expect_install: true }, + + // The following two cases test what happens when the ServiceWorkerGlobalScope + // 'error' event handler cancels the resulting error event. Since the + // original 'install' event handler threw, the installation should still + // be stopped in this case. See: + // https://github.com/slightlyoff/ServiceWorker/issues/778 { name: 'install handler throws an error that is cancelled', script: 'resources/oninstall-throw-error-then-cancel-worker.js', - expect_install: true + expect_install: false }, { name: 'install handler throws an error and prevents default', script: 'resources/oninstall-throw-error-then-prevent-default-worker.js', - expect_install: true + expect_install: false } ].forEach(function(test_case) { make_test(test_case.name, test_case.script, test_case.expect_install);
diff --git a/third_party/WebKit/LayoutTests/http/tests/streams/readable-streams/bad-strategies.js b/third_party/WebKit/LayoutTests/http/tests/streams/readable-streams/bad-strategies.js index 7d085c7..5cecb8f 100644 --- a/third_party/WebKit/LayoutTests/http/tests/streams/readable-streams/bad-strategies.js +++ b/third_party/WebKit/LayoutTests/http/tests/streams/readable-streams/bad-strategies.js
@@ -19,6 +19,60 @@ }, 'Readable stream: throwing strategy.size getter'); +test(() => { + + const theError = new Error('a unique string'); + + let controller; + const rs = new ReadableStream( + { + start(c) { + controller = c; + } + }, + { + size() { + controller.error(theError); + throw theError; + }, + highWaterMark: 5 + } + ); + + assert_throws(theError, () => { + controller.enqueue('a'); + }, 'enqueue should re-throw the error'); + +}, 'Readable stream: strategy.size errors the stream and then throws'); + +test(() => { + + const theError = new Error('a unique string'); + + let controller; + const rs = new ReadableStream( + { + start(c) { + controller = c; + } + }, + { + size() { + controller.error(theError); + return Infinity; + }, + highWaterMark: 5 + } + ); + + try { + controller.enqueue('a'); + } catch (error) { + assert_equals(error.name, 'RangeError', 'enqueue should throw a RangeError'); + } + +}, 'Readable stream: strategy.size errors the stream and then returns Infinity'); + promise_test(() => { const theError = new Error('a unique string');
diff --git a/third_party/WebKit/LayoutTests/http/tests/w3c/resources/testharnessreport.js b/third_party/WebKit/LayoutTests/http/tests/w3c/resources/testharnessreport.js index 0d9a8a6..56dcac54 100644 --- a/third_party/WebKit/LayoutTests/http/tests/w3c/resources/testharnessreport.js +++ b/third_party/WebKit/LayoutTests/http/tests/w3c/resources/testharnessreport.js
@@ -117,8 +117,11 @@ } // Add results element to document. - if (!document.body) + if (!document.body) { + if (!document.documentElement) + document.appendChild(document.createElement('html')); document.documentElement.appendChild(document.createElement("body")); + } document.body.appendChild(results); if (self.testRunner)
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/custom-elements/custom-element-lifecycle/types-of-callbacks/attached-callback-test.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/custom-elements/custom-element-lifecycle/types-of-callbacks/attached-callback-test.html index 97d107a..5d117e3 100644 --- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/custom-elements/custom-element-lifecycle/types-of-callbacks/attached-callback-test.html +++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/custom-elements/custom-element-lifecycle/types-of-callbacks/attached-callback-test.html
@@ -2,6 +2,7 @@ <html> <head> <title>Attached callback of a custom element should be called </title> +<meta name="timeout" content="long"> <meta name="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru"> <meta name="assert" content="attached callback ... must be enqueued whenever custom element is inserted into a document and this document has a browsing context."> <link rel="help" href="http://www.w3.org/TR/custom-elements/#types-of-callbacks">
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/dom/lists/DOMTokenList-stringifier-expected.txt b/third_party/WebKit/LayoutTests/imported/web-platform-tests/dom/lists/DOMTokenList-stringifier-expected.txt deleted file mode 100644 index 1b6c3abf..0000000 --- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/dom/lists/DOMTokenList-stringifier-expected.txt +++ /dev/null
@@ -1,4 +0,0 @@ -This is a testharness.js-based test. -FAIL DOMTokenList stringifier assert_equals: String(classList) should compress whitespace expected "a b" but got " a a b" -Harness: the test ran to completion. -
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/dom/lists/DOMTokenList-stringifier.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/dom/lists/DOMTokenList-stringifier.html index d81c576..65eae8d 100644 --- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/dom/lists/DOMTokenList-stringifier.html +++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/dom/lists/DOMTokenList-stringifier.html
@@ -6,18 +6,20 @@ <script src="../../../../resources/testharness.js"></script> <script src="../../../../resources/testharnessreport.js"></script> <div id=log></div> -<span class=" a a b"></span> +<span class=" a a b "></span> <script> test(function() { + assert_equals(String(document.createElement("span").classList), "", + "String(classList) should return the empty list for an undefined class attribute"); var span = document.querySelector("span"); - assert_equals(span.getAttribute("class"), " a a b", + assert_equals(span.getAttribute("class"), " a a b ", "getAttribute should return the literal value"); - assert_equals(span.className, " a a b", + assert_equals(span.className, " a a b ", "className should return the literal value"); - assert_equals(String(span.classList), "a b", - "String(classList) should compress whitespace"); - assert_equals(span.classList.toString(), "a b", - "classList.toString() should compress whitespace"); + assert_equals(String(span.classList), " a a b ", + "String(classList) should return the literal value"); + assert_equals(span.classList.toString(), " a a b ", + "classList.toString() should return the literal value"); assert_class_string(span.classList, "DOMTokenList"); }); </script>
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/dom/nodes/Document-createElement-namespace-tests/generate.py b/third_party/WebKit/LayoutTests/imported/web-platform-tests/dom/nodes/Document-createElement-namespace-tests/generate.py deleted file mode 100755 index 88c4da19..0000000 --- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/dom/nodes/Document-createElement-namespace-tests/generate.py +++ /dev/null
@@ -1,77 +0,0 @@ -#!/usr/bin/python -import os -import sys - -THIS_NAME = "generate.py" - -# Note: these lists must be kept in sync with the lists in -# Document-createElement-namespace.html, and this script must be run whenever -# the lists are updated. (We could keep the lists in a shared JSON file, but -# seems like too much effort.) -FILES = ( - ("empty", ""), - ("minimal_html", "<!doctype html><title></title>"), - - ("xhtml", '<html xmlns="http://www.w3.org/1999/xhtml"></html>'), - ("svg", '<svg xmlns="http://www.w3.org/2000/svg"></svg>'), - ("mathml", '<mathml xmlns="http://www.w3.org/1998/Math/MathML"></mathml>'), - - ("bare_xhtml", "<html></html>"), - ("bare_svg", "<svg></svg>"), - ("bare_mathml", "<math></math>"), - - ("xhtml_ns_removed", """\ -<html xmlns="http://www.w3.org/1999/xhtml"> - <head><script> - var newRoot = document.createElementNS(null, "html"); - document.removeChild(document.documentElement); - document.appendChild(newRoot); - </script></head> -</html> -"""), - ("xhtml_ns_changed", """\ -<html xmlns="http://www.w3.org/1999/xhtml"> - <head><script> - var newRoot = document.createElementNS("http://www.w3.org/2000/svg", "abc"); - document.removeChild(document.documentElement); - document.appendChild(newRoot); - </script></head> -</html> -"""), -) - -EXTENSIONS = ( - "html", - "xhtml", - "xml", - "svg", - # Was not able to get server MIME type working properly :( - #"mml", -) - -def __main__(): - if len(sys.argv) > 1: - print "No arguments expected, aborting" - return - - if not os.access(THIS_NAME, os.F_OK): - print "Must be run from the directory of " + THIS_NAME + ", aborting" - return - - for name in os.listdir("."): - if name == THIS_NAME: - continue - os.remove(name) - - manifest = open("MANIFEST", "w") - - for name, contents in FILES: - for extension in EXTENSIONS: - f = open(name + "." + extension, "w") - f.write(contents) - f.close() - manifest.write("support " + name + "." + extension + "\n") - - manifest.close() - -__main__()
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/dom/nodes/Element-classlist-expected.txt b/third_party/WebKit/LayoutTests/imported/web-platform-tests/dom/nodes/Element-classlist-expected.txt index 077f8ca71..a1c66b3 100644 --- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/dom/nodes/Element-classlist-expected.txt +++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/dom/nodes/Element-classlist-expected.txt
@@ -13,7 +13,7 @@ PASS classList[index] must be undefined for out-of-range index PASS classList[index] must be undefined for negative index FAIL className should contain initial markup whitespace assert_equals: expected " " but got "" -FAIL empty classList should return the empty string since the ordered set parser skip the whitespaces assert_equals: implicit expected "" but got " " +PASS classList should contain initial markup whitespace PASS .contains(empty_string) must throw a SYNTAX_ERR PASS .add(empty_string) must throw a SYNTAX_ERR PASS .remove(empty_string) must throw a SYNTAX_ERR
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/dom/nodes/Element-classlist.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/dom/nodes/Element-classlist.html index c25a12a..dba18f0 100644 --- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/dom/nodes/Element-classlist.html +++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/dom/nodes/Element-classlist.html
@@ -62,9 +62,9 @@ assert_equals( elem.className, ' ' ); }, 'className should contain initial markup whitespace'); test(function () { - assert_equals( elem.classList + '', '', 'implicit' ); - assert_equals( elem.classList.toString(), '', 'explicit' ); -}, 'empty classList should return the empty string since the ordered set parser skip the whitespaces'); + assert_equals( elem.classList + '', ' ', 'implicit' ); + assert_equals( elem.classList.toString(), ' ', 'explicit' ); +}, 'classList should contain initial markup whitespace'); test(function () { assert_throws( 'SYNTAX_ERR', function () { elem.classList.contains(''); } ); }, '.contains(empty_string) must throw a SYNTAX_ERR');
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/dom/nodes/attributes-expected.txt b/third_party/WebKit/LayoutTests/imported/web-platform-tests/dom/nodes/attributes-expected.txt index aa40064a..d33593b 100644 --- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/dom/nodes/attributes-expected.txt +++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/dom/nodes/attributes-expected.txt
@@ -41,5 +41,10 @@ PASS Basic functionality of setAttributeNodeNS PASS Basic functionality of removeAttributeNode PASS setAttributeNode on bound attribute should throw InUseAttributeError +FAIL getAttributeNames tests el.getAttributeNames is not a function +FAIL Own property correctness with basic attributes assert_array_equals: lengths differ, expected 2 got 0 +FAIL Own property correctness with non-namespaced attribute before same-name namespaced one assert_array_equals: lengths differ, expected 3 got 0 +FAIL Own property correctness with namespaced attribute before same-name non-namespaced one assert_array_equals: lengths differ, expected 3 got 0 +FAIL Own property correctness with two namespaced attributes with the same name-with-prefix assert_array_equals: lengths differ, expected 3 got 0 Harness: the test ran to completion.
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/dom/nodes/attributes.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/dom/nodes/attributes.html index 94d82715..ab7922f 100644 --- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/dom/nodes/attributes.html +++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/dom/nodes/attributes.html
@@ -459,4 +459,104 @@ var el2 = document.createElement("div"); assert_throws("INUSE_ATTRIBUTE_ERR", function(){el2.setAttributeNode(attrNode)}); }, "setAttributeNode on bound attribute should throw InUseAttributeError") + +test(function() { + var el = document.createElement("div"); + el.setAttribute("foo", "bar"); + assert_equals(el.getAttributeNames().length, 1); + assert_equals(el.getAttributeNames()[0], el.attributes[0].name); + assert_equals(el.getAttributeNames()[0], "foo"); + + el.removeAttribute("foo"); + assert_equals(el.getAttributeNames().length, 0); + + el.setAttribute("foo", "bar"); + el.setAttributeNS("", "FOO", "bar"); + el.setAttributeNS("dummy1", "foo", "bar"); + el.setAttributeNS("dummy2", "dummy:foo", "bar"); + assert_equals(el.getAttributeNames().length, 4); + assert_equals(el.getAttributeNames()[0], "foo"); + assert_equals(el.getAttributeNames()[1], "FOO"); + assert_equals(el.getAttributeNames()[2], "foo"); + assert_equals(el.getAttributeNames()[3], "dummy:foo"); + assert_equals(el.getAttributeNames()[0], el.attributes[0].name); + assert_equals(el.getAttributeNames()[1], el.attributes[1].name); + assert_equals(el.getAttributeNames()[2], el.attributes[2].name); + assert_equals(el.getAttributeNames()[3], el.attributes[3].name); + + el.removeAttributeNS("", "FOO"); + assert_equals(el.getAttributeNames().length, 3); + assert_equals(el.getAttributeNames()[0], "foo"); + assert_equals(el.getAttributeNames()[1], "foo"); + assert_equals(el.getAttributeNames()[2], "dummy:foo"); + assert_equals(el.getAttributeNames()[0], el.attributes[0].name); + assert_equals(el.getAttributeNames()[1], el.attributes[1].name); + assert_equals(el.getAttributeNames()[2], el.attributes[2].name); +}, "getAttributeNames tests"); + +function getEnumerableOwnProps1(obj) { + var arr = []; + for (var prop in obj) { + if (obj.hasOwnProperty(prop)) { + arr.push(prop); + } + } + return arr; +} + +function getEnumerableOwnProps2(obj) { + return Object.getOwnPropertyNames(obj).filter( + (name) => Object.getOwnPropertyDescriptor(obj, name).enumerable) +} + +test(function() { + var el = document.createElement("div"); + el.setAttribute("a", ""); + el.setAttribute("b", ""); + assert_array_equals(getEnumerableOwnProps1(el.attributes), + ["0", "1"]) + assert_array_equals(getEnumerableOwnProps2(el.attributes), + ["0", "1"]) + assert_array_equals(Object.getOwnPropertyNames(el.attributes), + ["0", "1", "a", "b"]) +}, "Own property correctness with basic attributes"); + +test(function() { + var el = document.createElement("div"); + el.setAttributeNS("", "a", ""); + el.setAttribute("b", ""); + el.setAttributeNS("foo", "a", ""); + assert_array_equals(getEnumerableOwnProps1(el.attributes), + ["0", "1", "2"]) + assert_array_equals(getEnumerableOwnProps2(el.attributes), + ["0", "1", "2"]) + assert_array_equals(Object.getOwnPropertyNames(el.attributes), + ["0", "1", "2", "a", "b"]) +}, "Own property correctness with non-namespaced attribute before same-name namespaced one"); + +test(function() { + var el = document.createElement("div"); + el.setAttributeNS("foo", "a", ""); + el.setAttribute("b", ""); + el.setAttributeNS("", "a", ""); + assert_array_equals(getEnumerableOwnProps1(el.attributes), + ["0", "1", "2"]) + assert_array_equals(getEnumerableOwnProps2(el.attributes), + ["0", "1", "2"]) + assert_array_equals(Object.getOwnPropertyNames(el.attributes), + ["0", "1", "2", "a", "b"]) +}, "Own property correctness with namespaced attribute before same-name non-namespaced one"); + +test(function() { + var el = document.createElement("div"); + el.setAttributeNS("foo", "a:b", ""); + el.setAttributeNS("foo", "c:d", ""); + el.setAttributeNS("bar", "a:b", ""); + assert_array_equals(getEnumerableOwnProps1(el.attributes), + ["0", "1", "2"]) + assert_array_equals(getEnumerableOwnProps2(el.attributes), + ["0", "1", "2"]) + assert_array_equals(Object.getOwnPropertyNames(el.attributes), + ["0", "1", "2", "a:b", "c:d"]) +}, "Own property correctness with two namespaced attributes with the same name-with-prefix"); </script>
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/hr-time/basic.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/hr-time/basic.html index ff15cdc7c..fe8a7e7 100644 --- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/hr-time/basic.html +++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/hr-time/basic.html
@@ -7,7 +7,6 @@ <link rel="help" href="http://www.w3.org/TR/hr-time/#sec-extenstions-performance-interface"/> <script src="../../../resources/testharness.js"></script> <script src="../../../resources/testharnessreport.js"></script> -<link rel="stylesheet" href="../../../resources/testharness.css" /> <script> test(function() { assert_equals(typeof window.performance, "object");
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/hr-time/monotonic-clock.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/hr-time/monotonic-clock.html index 0711ff3..d99ee80 100644 --- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/hr-time/monotonic-clock.html +++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/hr-time/monotonic-clock.html
@@ -7,7 +7,6 @@ <link rel="help" href="http://www.w3.org/TR/hr-time/#sec-monotonic-clock"/> <script src="../../../resources/testharness.js"></script> <script src="../../../resources/testharnessreport.js"></script> -<link rel="stylesheet" href="../../../resources/testharness.css" /> <script> test(function() { assert_true(window.performance.now() > 0, "window.performance.now() returns positive numbers");
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/browsers/browsing-the-web/scroll-to-fragid/007.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/browsers/browsing-the-web/scroll-to-fragid/007.html index 645ec9c4..bf79762e 100644 --- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/browsers/browsing-the-web/scroll-to-fragid/007.html +++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/browsers/browsing-the-web/scroll-to-fragid/007.html
@@ -1,12 +1,13 @@ <!doctype html> <!-- this tests the spec as it hopefully will be once bug https://www.w3.org/Bugs/Public/show_bug.cgi?id=17155 is fixed --> <title>Fragment Navigation: hashchange event multiple changes old/newURL</title> +<meta name=timeout content=long> <script src="../../../../../../resources/testharness.js"></script> <script src="../../../../../../resources/testharnessreport.js"></script> <body> <div id="log"></div> <script> -var t = async_test(undefined, {timeout:30000}); +var t = async_test(); t.step(function() { var original_url = location.href; assert_equals(location.hash, "", "Page must be loaded with no hash"); @@ -19,12 +20,12 @@ addEventListener("hashchange", t.step_func(function(e) { - if (count < 1000) { + if (count < 100) { location.hash = "test" + count++; hashes.push(location.hash); - } else if (count === 1000) { + } else if (count === 100) { expected = []; - for (var i=0; i<1000; i++) { + for (var i=0; i<100; i++) { expected.push("#test" + i); } assert_array_equals(hashes, expected);
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-001a-expected.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-001a-expected.html similarity index 87% rename from third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-001a-expected.html rename to third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-001a-expected.html index b5882eb..d2a6d9af 100644 --- a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-001a-expected.html +++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-001a-expected.html
@@ -9,7 +9,7 @@ </style> </head> <body> -<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<p class="instructions" dir="ltr" style="display:none">Test passes if the two boxes are identical.</p> <div class="ref"><div dir="ltr">‭א 3‬</div><div dir="ltr">‭a 3‬</div><div dir="rtl">‭3 א‬</div><div dir="rtl">‭3 a‬</div></div> <div class="ref"><div dir="ltr">‭א 3‬</div><div dir="ltr">‭a 3‬</div><div dir="rtl">‭3 א‬</div><div dir="rtl">‭3 a‬</div></div> </body>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-001a.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-001a.html similarity index 92% rename from third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-001a.html rename to third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-001a.html index 16a308a..434e2d5 100644 --- a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-001a.html +++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-001a.html
@@ -13,14 +13,14 @@ </style> </head> <body> -<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> -<!--Notes: +<p class="instructions" dir="ltr" style="display:none">Test passes if the two boxes are identical.</p> +<!-- Notes: Key to entities used below: א ... ו - The first six Hebrew letters (strongly RTL). ‭ - The LRO (left-to-right-override) formatting character. ‬ - The PDF (pop directional formatting) formatting character; closes LRO. The punctuation is moved around in the source to make it easier to do visual comparisons when the test is run. ---> + --> <div class="test"> <div dir="ltr"><span dir="rtl">א</span> 3</div> <div dir="ltr"><span dir="rtl">a</span> 3</div>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-001b-expected.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-001b-expected.html similarity index 87% rename from third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-001b-expected.html rename to third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-001b-expected.html index b5882eb..d2a6d9af 100644 --- a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-001b-expected.html +++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-001b-expected.html
@@ -9,7 +9,7 @@ </style> </head> <body> -<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<p class="instructions" dir="ltr" style="display:none">Test passes if the two boxes are identical.</p> <div class="ref"><div dir="ltr">‭א 3‬</div><div dir="ltr">‭a 3‬</div><div dir="rtl">‭3 א‬</div><div dir="rtl">‭3 a‬</div></div> <div class="ref"><div dir="ltr">‭א 3‬</div><div dir="ltr">‭a 3‬</div><div dir="rtl">‭3 א‬</div><div dir="rtl">‭3 a‬</div></div> </body>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-001b.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-001b.html similarity index 92% rename from third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-001b.html rename to third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-001b.html index 197f49a..ca4a6af 100644 --- a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-001b.html +++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-001b.html
@@ -13,14 +13,14 @@ </style> </head> <body> -<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> -<!--Notes: +<p class="instructions" dir="ltr" style="display:none">Test passes if the two boxes are identical.</p> +<!-- Notes: Key to entities used below: א ... ו - The first six Hebrew letters (strongly RTL). ‭ - The LRO (left-to-right-override) formatting character. ‬ - The PDF (pop directional formatting) formatting character; closes LRO. The punctuation is moved around in the source to make it easier to do visual comparisons when the test is run. ---> + --> <div class="test"> <div dir="ltr"><span dir="auto">א</span> 3</div> <div dir="ltr"><span dir="auto">a</span> 3</div>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-001c-expected.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-001c-expected.html similarity index 87% rename from third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-001c-expected.html rename to third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-001c-expected.html index b5882eb..d2a6d9af 100644 --- a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-001c-expected.html +++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-001c-expected.html
@@ -9,7 +9,7 @@ </style> </head> <body> -<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<p class="instructions" dir="ltr" style="display:none">Test passes if the two boxes are identical.</p> <div class="ref"><div dir="ltr">‭א 3‬</div><div dir="ltr">‭a 3‬</div><div dir="rtl">‭3 א‬</div><div dir="rtl">‭3 a‬</div></div> <div class="ref"><div dir="ltr">‭א 3‬</div><div dir="ltr">‭a 3‬</div><div dir="rtl">‭3 א‬</div><div dir="rtl">‭3 a‬</div></div> </body>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-001c.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-001c.html similarity index 92% rename from third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-001c.html rename to third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-001c.html index 95ec6c73..684fcf65 100644 --- a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-001c.html +++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-001c.html
@@ -13,14 +13,14 @@ </style> </head> <body> -<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> -<!--Notes: +<p class="instructions" dir="ltr" style="display:none">Test passes if the two boxes are identical.</p> +<!-- Notes: Key to entities used below: א ... ו - The first six Hebrew letters (strongly RTL). ‭ - The LRO (left-to-right-override) formatting character. ‬ - The PDF (pop directional formatting) formatting character; closes LRO. The punctuation is moved around in the source to make it easier to do visual comparisons when the test is run. ---> + --> <div class="test"> <div dir="ltr"><span dir="ltr">א</span> 3</div> <div dir="ltr"><span dir="ltr">a</span> 3</div>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-002a-expected.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-002a-expected.html similarity index 89% rename from third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-002a-expected.html rename to third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-002a-expected.html index f28559b5..1480a29 100644 --- a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-002a-expected.html +++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-002a-expected.html
@@ -9,7 +9,7 @@ </style> </head> <body> -<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<p class="instructions" dir="ltr" style="display:none">Test passes if the two boxes are identical.</p> <div class="ref"><div dir="ltr">‭< א < > 3 >‬</div><div dir="ltr">‭< a < > 3 >‬</div><div dir="rtl">‭< 3 < > א >‬</div><div dir="rtl">‭< 3 < > a >‬</div></div> <div class="ref"><div dir="ltr">‭< א < > 3 >‬</div><div dir="ltr">‭< a < > 3 >‬</div><div dir="rtl">‭< 3 < > א >‬</div><div dir="rtl">‭< 3 < > a >‬</div></div> </body>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-002a.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-002a.html similarity index 92% rename from third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-002a.html rename to third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-002a.html index 7b7029a2..7724922 100644 --- a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-002a.html +++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-002a.html
@@ -13,14 +13,14 @@ </style> </head> <body> -<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> -<!--Notes: +<p class="instructions" dir="ltr" style="display:none">Test passes if the two boxes are identical.</p> +<!-- Notes: Key to entities used below: א ... ו - The first six Hebrew letters (strongly RTL). ‭ - The LRO (left-to-right-override) formatting character. ‬ - The PDF (pop directional formatting) formatting character; closes LRO. The punctuation is moved around in the source to make it easier to do visual comparisons when the test is run. ---> + --> <div class="test"> <div dir="ltr"><span dir="rtl">> א ></span> > 3 ></div> <div dir="ltr"><span dir="rtl">> a ></span> > 3 ></div>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-002b-expected.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-002b-expected.html similarity index 89% rename from third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-002b-expected.html rename to third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-002b-expected.html index d4eda21..b265384a 100644 --- a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-002b-expected.html +++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-002b-expected.html
@@ -9,7 +9,7 @@ </style> </head> <body> -<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<p class="instructions" dir="ltr" style="display:none">Test passes if the two boxes are identical.</p> <div class="ref"><div dir="ltr">‭< א < > 3 >‬</div><div dir="ltr">‭> a > > 3 >‬</div><div dir="rtl">‭< 3 < < א <‬</div><div dir="rtl">‭< 3 < > a >‬</div></div> <div class="ref"><div dir="ltr">‭< א < > 3 >‬</div><div dir="ltr">‭> a > > 3 >‬</div><div dir="rtl">‭< 3 < < א <‬</div><div dir="rtl">‭< 3 < > a >‬</div></div> </body>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-002b.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-002b.html similarity index 92% rename from third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-002b.html rename to third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-002b.html index d448de5..bf2c0e8 100644 --- a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-002b.html +++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-002b.html
@@ -13,14 +13,14 @@ </style> </head> <body> -<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> -<!--Notes: +<p class="instructions" dir="ltr" style="display:none">Test passes if the two boxes are identical.</p> +<!-- Notes: Key to entities used below: א ... ו - The first six Hebrew letters (strongly RTL). ‭ - The LRO (left-to-right-override) formatting character. ‬ - The PDF (pop directional formatting) formatting character; closes LRO. The punctuation is moved around in the source to make it easier to do visual comparisons when the test is run. ---> + --> <div class="test"> <div dir="ltr"><span dir="auto">> א ></span> > 3 ></div> <div dir="ltr"><span dir="auto">> a ></span> > 3 ></div>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-002c-expected.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-002c-expected.html similarity index 89% rename from third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-002c-expected.html rename to third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-002c-expected.html index 6c21d014..f647577 100644 --- a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-002c-expected.html +++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-002c-expected.html
@@ -9,7 +9,7 @@ </style> </head> <body> -<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<p class="instructions" dir="ltr" style="display:none">Test passes if the two boxes are identical.</p> <div class="ref"><div dir="ltr">‭> א > > 3 >‬</div><div dir="ltr">‭> a > > 3 >‬</div><div dir="rtl">‭< 3 < < א <‬</div><div dir="rtl">‭< 3 < < a <‬</div></div> <div class="ref"><div dir="ltr">‭> א > > 3 >‬</div><div dir="ltr">‭> a > > 3 >‬</div><div dir="rtl">‭< 3 < < א <‬</div><div dir="rtl">‭< 3 < < a <‬</div></div> </body>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-002c.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-002c.html similarity index 93% rename from third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-002c.html rename to third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-002c.html index e88fb1c..aa007c1 100644 --- a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-002c.html +++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-002c.html
@@ -13,14 +13,14 @@ </style> </head> <body> -<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> -<!--Notes: +<p class="instructions" dir="ltr" style="display:none">Test passes if the two boxes are identical.</p> +<!-- Notes: Key to entities used below: א ... ו - The first six Hebrew letters (strongly RTL). ‭ - The LRO (left-to-right-override) formatting character. ‬ - The PDF (pop directional formatting) formatting character; closes LRO. The punctuation is moved around in the source to make it easier to do visual comparisons when the test is run. ---> + --> <div class="test"> <div dir="ltr"><span dir="ltr">> א ></span> > 3 ></div> <div dir="ltr"><span dir="ltr">> a ></span> > 3 ></div>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-003a-expected.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-003a-expected.html similarity index 87% rename from third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-003a-expected.html rename to third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-003a-expected.html index 4c29838e..d8ad6bf 100644 --- a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-003a-expected.html +++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-003a-expected.html
@@ -9,7 +9,7 @@ </style> </head> <body> -<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<p class="instructions" dir="ltr" style="display:none">Test passes if the two boxes are identical.</p> <div class="ref"><div dir="ltr">‭א3‬</div><div dir="ltr">‭a3‬</div><div dir="rtl">‭3א‬</div><div dir="rtl">‭3a‬</div></div> <div class="ref"><div dir="ltr">‭א3‬</div><div dir="ltr">‭a3‬</div><div dir="rtl">‭3א‬</div><div dir="rtl">‭3a‬</div></div> </body>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-003a.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-003a.html similarity index 92% rename from third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-003a.html rename to third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-003a.html index 9cf65c81..b5d61c83 100644 --- a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-003a.html +++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-003a.html
@@ -13,14 +13,14 @@ </style> </head> <body> -<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> -<!--Notes: +<p class="instructions" dir="ltr" style="display:none">Test passes if the two boxes are identical.</p> +<!-- Notes: Key to entities used below: א ... ו - The first six Hebrew letters (strongly RTL). ‭ - The LRO (left-to-right-override) formatting character. ‬ - The PDF (pop directional formatting) formatting character; closes LRO. The punctuation is moved around in the source to make it easier to do visual comparisons when the test is run. ---> + --> <div class="test"> <div dir="ltr"><span dir="rtl">א</span>3</div> <div dir="ltr"><span dir="rtl">a</span>3</div>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-003b-expected.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-003b-expected.html similarity index 87% rename from third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-003b-expected.html rename to third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-003b-expected.html index 4c29838e..d8ad6bf 100644 --- a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-003b-expected.html +++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-003b-expected.html
@@ -9,7 +9,7 @@ </style> </head> <body> -<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<p class="instructions" dir="ltr" style="display:none">Test passes if the two boxes are identical.</p> <div class="ref"><div dir="ltr">‭א3‬</div><div dir="ltr">‭a3‬</div><div dir="rtl">‭3א‬</div><div dir="rtl">‭3a‬</div></div> <div class="ref"><div dir="ltr">‭א3‬</div><div dir="ltr">‭a3‬</div><div dir="rtl">‭3א‬</div><div dir="rtl">‭3a‬</div></div> </body>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-003b.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-003b.html similarity index 92% rename from third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-003b.html rename to third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-003b.html index 2c6b553..edd80230 100644 --- a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-003b.html +++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-003b.html
@@ -13,14 +13,14 @@ </style> </head> <body> -<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> -<!--Notes: +<p class="instructions" dir="ltr" style="display:none">Test passes if the two boxes are identical.</p> +<!-- Notes: Key to entities used below: א ... ו - The first six Hebrew letters (strongly RTL). ‭ - The LRO (left-to-right-override) formatting character. ‬ - The PDF (pop directional formatting) formatting character; closes LRO. The punctuation is moved around in the source to make it easier to do visual comparisons when the test is run. ---> + --> <div class="test"> <div dir="ltr"><span dir="auto">א</span>3</div> <div dir="ltr"><span dir="auto">a</span>3</div>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-003c-expected.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-003c-expected.html similarity index 87% rename from third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-003c-expected.html rename to third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-003c-expected.html index 4c29838e..d8ad6bf 100644 --- a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-003c-expected.html +++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-003c-expected.html
@@ -9,7 +9,7 @@ </style> </head> <body> -<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<p class="instructions" dir="ltr" style="display:none">Test passes if the two boxes are identical.</p> <div class="ref"><div dir="ltr">‭א3‬</div><div dir="ltr">‭a3‬</div><div dir="rtl">‭3א‬</div><div dir="rtl">‭3a‬</div></div> <div class="ref"><div dir="ltr">‭א3‬</div><div dir="ltr">‭a3‬</div><div dir="rtl">‭3א‬</div><div dir="rtl">‭3a‬</div></div> </body>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-003c.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-003c.html similarity index 92% rename from third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-003c.html rename to third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-003c.html index ac873512..73f46dc 100644 --- a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-003c.html +++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-003c.html
@@ -13,14 +13,14 @@ </style> </head> <body> -<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> -<!--Notes: +<p class="instructions" dir="ltr" style="display:none">Test passes if the two boxes are identical.</p> +<!-- Notes: Key to entities used below: א ... ו - The first six Hebrew letters (strongly RTL). ‭ - The LRO (left-to-right-override) formatting character. ‬ - The PDF (pop directional formatting) formatting character; closes LRO. The punctuation is moved around in the source to make it easier to do visual comparisons when the test is run. ---> + --> <div class="test"> <div dir="ltr"><span dir="ltr">א</span>3</div> <div dir="ltr"><span dir="ltr">a</span>3</div>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-004a-expected.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-004a-expected.html similarity index 87% rename from third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-004a-expected.html rename to third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-004a-expected.html index cb83dde..936959b 100644 --- a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-004a-expected.html +++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-004a-expected.html
@@ -9,7 +9,7 @@ </style> </head> <body> -<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<p class="instructions" dir="ltr" style="display:none">Test passes if the two boxes are identical.</p> <div class="ref"><div dir="ltr">‭א 3‬</div><div dir="ltr">‭a 3‬</div><div dir="rtl">‭3 א‬</div><div dir="rtl">‭3 a‬</div></div> <div class="ref"><div dir="ltr">‭א 3‬</div><div dir="ltr">‭a 3‬</div><div dir="rtl">‭3 א‬</div><div dir="rtl">‭3 a‬</div></div> </body>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-004a.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-004a.html similarity index 92% rename from third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-004a.html rename to third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-004a.html index 27a674c..5ad6beb 100644 --- a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-004a.html +++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-004a.html
@@ -13,14 +13,14 @@ </style> </head> <body> -<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> -<!--Notes: +<p class="instructions" dir="ltr" style="display:none">Test passes if the two boxes are identical.</p> +<!-- Notes: Key to entities used below: א ... ו - The first six Hebrew letters (strongly RTL). ‭ - The LRO (left-to-right-override) formatting character. ‬ - The PDF (pop directional formatting) formatting character; closes LRO. The punctuation is moved around in the source to make it easier to do visual comparisons when the test is run. ---> + --> <div class="test"> <div dir="ltr">א <span dir="rtl">3</span></div> <div dir="ltr">a <span dir="rtl">3</span></div>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-004a-expected.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-004b-expected.html similarity index 87% copy from third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-004a-expected.html copy to third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-004b-expected.html index cb83dde..936959b 100644 --- a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-004a-expected.html +++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-004b-expected.html
@@ -9,7 +9,7 @@ </style> </head> <body> -<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<p class="instructions" dir="ltr" style="display:none">Test passes if the two boxes are identical.</p> <div class="ref"><div dir="ltr">‭א 3‬</div><div dir="ltr">‭a 3‬</div><div dir="rtl">‭3 א‬</div><div dir="rtl">‭3 a‬</div></div> <div class="ref"><div dir="ltr">‭א 3‬</div><div dir="ltr">‭a 3‬</div><div dir="rtl">‭3 א‬</div><div dir="rtl">‭3 a‬</div></div> </body>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-004b.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-004b.html similarity index 92% rename from third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-004b.html rename to third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-004b.html index 6fe74393..62e0b45 100644 --- a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-004b.html +++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-004b.html
@@ -13,14 +13,14 @@ </style> </head> <body> -<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> -<!--Notes: +<p class="instructions" dir="ltr" style="display:none">Test passes if the two boxes are identical.</p> +<!-- Notes: Key to entities used below: א ... ו - The first six Hebrew letters (strongly RTL). ‭ - The LRO (left-to-right-override) formatting character. ‬ - The PDF (pop directional formatting) formatting character; closes LRO. The punctuation is moved around in the source to make it easier to do visual comparisons when the test is run. ---> + --> <div class="test"> <div dir="ltr">א <span dir="auto">3</span></div> <div dir="ltr">a <span dir="auto">3</span></div>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-004a-expected.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-004c-expected.html similarity index 87% copy from third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-004a-expected.html copy to third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-004c-expected.html index cb83dde..936959b 100644 --- a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-004a-expected.html +++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-004c-expected.html
@@ -9,7 +9,7 @@ </style> </head> <body> -<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<p class="instructions" dir="ltr" style="display:none">Test passes if the two boxes are identical.</p> <div class="ref"><div dir="ltr">‭א 3‬</div><div dir="ltr">‭a 3‬</div><div dir="rtl">‭3 א‬</div><div dir="rtl">‭3 a‬</div></div> <div class="ref"><div dir="ltr">‭א 3‬</div><div dir="ltr">‭a 3‬</div><div dir="rtl">‭3 א‬</div><div dir="rtl">‭3 a‬</div></div> </body>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-004c.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-004c.html similarity index 92% rename from third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-004c.html rename to third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-004c.html index 43d994b..e7c419f 100644 --- a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-004c.html +++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-004c.html
@@ -13,14 +13,14 @@ </style> </head> <body> -<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> -<!--Notes: +<p class="instructions" dir="ltr" style="display:none">Test passes if the two boxes are identical.</p> +<!-- Notes: Key to entities used below: א ... ו - The first six Hebrew letters (strongly RTL). ‭ - The LRO (left-to-right-override) formatting character. ‬ - The PDF (pop directional formatting) formatting character; closes LRO. The punctuation is moved around in the source to make it easier to do visual comparisons when the test is run. ---> + --> <div class="test"> <div dir="ltr">א <span dir="ltr">3</span></div> <div dir="ltr">a <span dir="ltr">3</span></div>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-005a-expected.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-005a-expected.html similarity index 87% rename from third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-005a-expected.html rename to third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-005a-expected.html index 4a6c301a..30d08af 100644 --- a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-005a-expected.html +++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-005a-expected.html
@@ -9,7 +9,7 @@ </style> </head> <body> -<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<p class="instructions" dir="ltr" style="display:none">Test passes if the two boxes are identical.</p> <div class="ref"><div dir="ltr">‭א ב...‬</div><div dir="ltr">‭a b...‬</div><div dir="rtl">‭...b a‬</div><div dir="rtl">‭...ב א‬</div></div> <div class="ref"><div dir="ltr">‭א ב...‬</div><div dir="ltr">‭a b...‬</div><div dir="rtl">‭...b a‬</div><div dir="rtl">‭...ב א‬</div></div> </body>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-005a.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-005a.html similarity index 92% rename from third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-005a.html rename to third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-005a.html index 2fbddbd..f4cda0e 100644 --- a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-005a.html +++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-005a.html
@@ -13,14 +13,14 @@ </style> </head> <body> -<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> -<!--Notes: +<p class="instructions" dir="ltr" style="display:none">Test passes if the two boxes are identical.</p> +<!-- Notes: Key to entities used below: א ... ו - The first six Hebrew letters (strongly RTL). ‭ - The LRO (left-to-right-override) formatting character. ‬ - The PDF (pop directional formatting) formatting character; closes LRO. The punctuation is moved around in the source to make it easier to do visual comparisons when the test is run. ---> + --> <div class="test"> <div dir="ltr"><span dir="rtl">א</span> ב...</div> <div dir="ltr"><span dir="rtl">a</span> b...</div>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-005a-expected.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-005b-expected.html similarity index 87% copy from third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-005a-expected.html copy to third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-005b-expected.html index 4a6c301a..30d08af 100644 --- a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-005a-expected.html +++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-005b-expected.html
@@ -9,7 +9,7 @@ </style> </head> <body> -<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<p class="instructions" dir="ltr" style="display:none">Test passes if the two boxes are identical.</p> <div class="ref"><div dir="ltr">‭א ב...‬</div><div dir="ltr">‭a b...‬</div><div dir="rtl">‭...b a‬</div><div dir="rtl">‭...ב א‬</div></div> <div class="ref"><div dir="ltr">‭א ב...‬</div><div dir="ltr">‭a b...‬</div><div dir="rtl">‭...b a‬</div><div dir="rtl">‭...ב א‬</div></div> </body>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-005b.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-005b.html similarity index 92% rename from third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-005b.html rename to third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-005b.html index d61e258f2..fc49cc9 100644 --- a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-005b.html +++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-005b.html
@@ -13,14 +13,14 @@ </style> </head> <body> -<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> -<!--Notes: +<p class="instructions" dir="ltr" style="display:none">Test passes if the two boxes are identical.</p> +<!-- Notes: Key to entities used below: א ... ו - The first six Hebrew letters (strongly RTL). ‭ - The LRO (left-to-right-override) formatting character. ‬ - The PDF (pop directional formatting) formatting character; closes LRO. The punctuation is moved around in the source to make it easier to do visual comparisons when the test is run. ---> + --> <div class="test"> <div dir="ltr"><span dir="auto">א</span> ב...</div> <div dir="ltr"><span dir="auto">a</span> b...</div>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-005a-expected.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-005c-expected.html similarity index 87% copy from third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-005a-expected.html copy to third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-005c-expected.html index 4a6c301a..30d08af 100644 --- a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-005a-expected.html +++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-005c-expected.html
@@ -9,7 +9,7 @@ </style> </head> <body> -<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<p class="instructions" dir="ltr" style="display:none">Test passes if the two boxes are identical.</p> <div class="ref"><div dir="ltr">‭א ב...‬</div><div dir="ltr">‭a b...‬</div><div dir="rtl">‭...b a‬</div><div dir="rtl">‭...ב א‬</div></div> <div class="ref"><div dir="ltr">‭א ב...‬</div><div dir="ltr">‭a b...‬</div><div dir="rtl">‭...b a‬</div><div dir="rtl">‭...ב א‬</div></div> </body>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-005c.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-005c.html similarity index 92% rename from third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-005c.html rename to third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-005c.html index d544275..834b94f 100644 --- a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-005c.html +++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-005c.html
@@ -13,14 +13,14 @@ </style> </head> <body> -<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> -<!--Notes: +<p class="instructions" dir="ltr" style="display:none">Test passes if the two boxes are identical.</p> +<!-- Notes: Key to entities used below: א ... ו - The first six Hebrew letters (strongly RTL). ‭ - The LRO (left-to-right-override) formatting character. ‬ - The PDF (pop directional formatting) formatting character; closes LRO. The punctuation is moved around in the source to make it easier to do visual comparisons when the test is run. ---> + --> <div class="test"> <div dir="ltr"><span dir="ltr">א</span> ב...</div> <div dir="ltr"><span dir="ltr">a</span> b...</div>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-006a-expected.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-006a-expected.html similarity index 86% rename from third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-006a-expected.html rename to third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-006a-expected.html index 0f6b7bbb..9fffe6c 100644 --- a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-006a-expected.html +++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-006a-expected.html
@@ -9,7 +9,7 @@ </style> </head> <body> -<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<p class="instructions" dir="ltr" style="display:none">Test passes if the two boxes are identical.</p> <div class="ref"><div dir="ltr">‭< א < > ב >...‬</div><div dir="rtl">‭...< b < > a >‬</div></div> <div class="ref"><div dir="ltr">‭< א < > ב >...‬</div><div dir="rtl">‭...< b < > a >‬</div></div> </body>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-006a.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-006a.html similarity index 92% rename from third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-006a.html rename to third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-006a.html index 430df00d..0dcf53d9 100644 --- a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-006a.html +++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-006a.html
@@ -13,14 +13,14 @@ </style> </head> <body> -<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> -<!--Notes: +<p class="instructions" dir="ltr" style="display:none">Test passes if the two boxes are identical.</p> +<!-- Notes: Key to entities used below: א ... ו - The first six Hebrew letters (strongly RTL). ‭ - The LRO (left-to-right-override) formatting character. ‬ - The PDF (pop directional formatting) formatting character; closes LRO. The punctuation is moved around in the source to make it easier to do visual comparisons when the test is run. ---> + --> <div class="test"> <div dir="ltr"><span dir="rtl">> א ></span> > ב >...</div> <div dir="rtl"><span dir="ltr">> a ></span> > b >...</div>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-006a-expected.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-006b-expected.html similarity index 86% copy from third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-006a-expected.html copy to third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-006b-expected.html index 0f6b7bbb..9fffe6c 100644 --- a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-006a-expected.html +++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-006b-expected.html
@@ -9,7 +9,7 @@ </style> </head> <body> -<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<p class="instructions" dir="ltr" style="display:none">Test passes if the two boxes are identical.</p> <div class="ref"><div dir="ltr">‭< א < > ב >...‬</div><div dir="rtl">‭...< b < > a >‬</div></div> <div class="ref"><div dir="ltr">‭< א < > ב >...‬</div><div dir="rtl">‭...< b < > a >‬</div></div> </body>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-006b.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-006b.html similarity index 92% rename from third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-006b.html rename to third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-006b.html index a6da487..0402214 100644 --- a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-006b.html +++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-006b.html
@@ -13,14 +13,14 @@ </style> </head> <body> -<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> -<!--Notes: +<p class="instructions" dir="ltr" style="display:none">Test passes if the two boxes are identical.</p> +<!-- Notes: Key to entities used below: א ... ו - The first six Hebrew letters (strongly RTL). ‭ - The LRO (left-to-right-override) formatting character. ‬ - The PDF (pop directional formatting) formatting character; closes LRO. The punctuation is moved around in the source to make it easier to do visual comparisons when the test is run. ---> + --> <div class="test"> <div dir="ltr"><span dir="auto">> א ></span> > ב >...</div> <div dir="rtl"><span dir="auto">> a ></span> > b >...</div>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-006c-expected.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-006c-expected.html similarity index 86% rename from third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-006c-expected.html rename to third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-006c-expected.html index 0347c09..187a458 100644 --- a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-006c-expected.html +++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-006c-expected.html
@@ -9,7 +9,7 @@ </style> </head> <body> -<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<p class="instructions" dir="ltr" style="display:none">Test passes if the two boxes are identical.</p> <div class="ref"><div dir="ltr">‭> א > > ב >...‬</div><div dir="rtl">‭...< b < < a <‬</div></div> <div class="ref"><div dir="ltr">‭> א > > ב >...‬</div><div dir="rtl">‭...< b < < a <‬</div></div> </body>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-006c.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-006c.html similarity index 92% rename from third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-006c.html rename to third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-006c.html index 3407d37..6f062d0 100644 --- a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-006c.html +++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-006c.html
@@ -13,14 +13,14 @@ </style> </head> <body> -<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> -<!--Notes: +<p class="instructions" dir="ltr" style="display:none">Test passes if the two boxes are identical.</p> +<!-- Notes: Key to entities used below: א ... ו - The first six Hebrew letters (strongly RTL). ‭ - The LRO (left-to-right-override) formatting character. ‬ - The PDF (pop directional formatting) formatting character; closes LRO. The punctuation is moved around in the source to make it easier to do visual comparisons when the test is run. ---> + --> <div class="test"> <div dir="ltr"><span dir="ltr">> א ></span> > ב >...</div> <div dir="rtl"><span dir="rtl">> a ></span> > b >...</div>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-007a-expected.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-007a-expected.html similarity index 87% rename from third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-007a-expected.html rename to third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-007a-expected.html index 665153d..b62ff23 100644 --- a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-007a-expected.html +++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-007a-expected.html
@@ -9,7 +9,7 @@ </style> </head> <body> -<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<p class="instructions" dir="ltr" style="display:none">Test passes if the two boxes are identical.</p> <div class="ref"><div dir="ltr">‭אב...‬</div><div dir="ltr">‭ab...‬</div><div dir="rtl">‭...ba‬</div><div dir="rtl">‭...בא‬</div></div> <div class="ref"><div dir="ltr">‭אב...‬</div><div dir="ltr">‭ab...‬</div><div dir="rtl">‭...ba‬</div><div dir="rtl">‭...בא‬</div></div> </body>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-007a.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-007a.html similarity index 92% rename from third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-007a.html rename to third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-007a.html index e8b37b1b..ebeb54b 100644 --- a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-007a.html +++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-007a.html
@@ -13,14 +13,14 @@ </style> </head> <body> -<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> -<!--Notes: +<p class="instructions" dir="ltr" style="display:none">Test passes if the two boxes are identical.</p> +<!-- Notes: Key to entities used below: א ... ו - The first six Hebrew letters (strongly RTL). ‭ - The LRO (left-to-right-override) formatting character. ‬ - The PDF (pop directional formatting) formatting character; closes LRO. The punctuation is moved around in the source to make it easier to do visual comparisons when the test is run. ---> + --> <div class="test"> <div dir="ltr"><span dir="rtl">א</span>ב...</div> <div dir="ltr"><span dir="rtl">a</span>b...</div>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-007a-expected.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-007b-expected.html similarity index 87% copy from third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-007a-expected.html copy to third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-007b-expected.html index 665153d..b62ff23 100644 --- a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-007a-expected.html +++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-007b-expected.html
@@ -9,7 +9,7 @@ </style> </head> <body> -<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<p class="instructions" dir="ltr" style="display:none">Test passes if the two boxes are identical.</p> <div class="ref"><div dir="ltr">‭אב...‬</div><div dir="ltr">‭ab...‬</div><div dir="rtl">‭...ba‬</div><div dir="rtl">‭...בא‬</div></div> <div class="ref"><div dir="ltr">‭אב...‬</div><div dir="ltr">‭ab...‬</div><div dir="rtl">‭...ba‬</div><div dir="rtl">‭...בא‬</div></div> </body>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-007b.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-007b.html similarity index 92% rename from third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-007b.html rename to third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-007b.html index c54e63d..d4a1f9c 100644 --- a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-007b.html +++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-007b.html
@@ -13,14 +13,14 @@ </style> </head> <body> -<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> -<!--Notes: +<p class="instructions" dir="ltr" style="display:none">Test passes if the two boxes are identical.</p> +<!-- Notes: Key to entities used below: א ... ו - The first six Hebrew letters (strongly RTL). ‭ - The LRO (left-to-right-override) formatting character. ‬ - The PDF (pop directional formatting) formatting character; closes LRO. The punctuation is moved around in the source to make it easier to do visual comparisons when the test is run. ---> + --> <div class="test"> <div dir="ltr"><span dir="auto">א</span>ב...</div> <div dir="ltr"><span dir="auto">a</span>b...</div>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-007a-expected.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-007c-expected.html similarity index 87% copy from third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-007a-expected.html copy to third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-007c-expected.html index 665153d..b62ff23 100644 --- a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-007a-expected.html +++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-007c-expected.html
@@ -9,7 +9,7 @@ </style> </head> <body> -<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<p class="instructions" dir="ltr" style="display:none">Test passes if the two boxes are identical.</p> <div class="ref"><div dir="ltr">‭אב...‬</div><div dir="ltr">‭ab...‬</div><div dir="rtl">‭...ba‬</div><div dir="rtl">‭...בא‬</div></div> <div class="ref"><div dir="ltr">‭אב...‬</div><div dir="ltr">‭ab...‬</div><div dir="rtl">‭...ba‬</div><div dir="rtl">‭...בא‬</div></div> </body>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-007c.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-007c.html similarity index 92% rename from third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-007c.html rename to third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-007c.html index b9c5219..f7f17cd6 100644 --- a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-007c.html +++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-007c.html
@@ -13,14 +13,14 @@ </style> </head> <body> -<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> -<!--Notes: +<p class="instructions" dir="ltr" style="display:none">Test passes if the two boxes are identical.</p> +<!-- Notes: Key to entities used below: א ... ו - The first six Hebrew letters (strongly RTL). ‭ - The LRO (left-to-right-override) formatting character. ‬ - The PDF (pop directional formatting) formatting character; closes LRO. The punctuation is moved around in the source to make it easier to do visual comparisons when the test is run. ---> + --> <div class="test"> <div dir="ltr"><span dir="ltr">א</span>ב...</div> <div dir="ltr"><span dir="ltr">a</span>b...</div>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-008a-expected.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-008a-expected.html similarity index 87% rename from third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-008a-expected.html rename to third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-008a-expected.html index 8eb90f8..7a7c841 100644 --- a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-008a-expected.html +++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-008a-expected.html
@@ -9,7 +9,7 @@ </style> </head> <body> -<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<p class="instructions" dir="ltr" style="display:none">Test passes if the two boxes are identical.</p> <div class="ref"><div dir="ltr">‭א ב‬</div><div dir="ltr">‭a b‬</div><div dir="rtl">‭ב א‬</div><div dir="rtl">‭b a‬</div></div> <div class="ref"><div dir="ltr">‭א ב‬</div><div dir="ltr">‭a b‬</div><div dir="rtl">‭ב א‬</div><div dir="rtl">‭b a‬</div></div> </body>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-008a.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-008a.html similarity index 92% rename from third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-008a.html rename to third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-008a.html index 1455fd5..c90dd38 100644 --- a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-008a.html +++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-008a.html
@@ -13,14 +13,14 @@ </style> </head> <body> -<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> -<!--Notes: +<p class="instructions" dir="ltr" style="display:none">Test passes if the two boxes are identical.</p> +<!-- Notes: Key to entities used below: א ... ו - The first six Hebrew letters (strongly RTL). ‭ - The LRO (left-to-right-override) formatting character. ‬ - The PDF (pop directional formatting) formatting character; closes LRO. The punctuation is moved around in the source to make it easier to do visual comparisons when the test is run. ---> + --> <div class="test"> <div dir="ltr">א <span dir="rtl">ב</span></div> <div dir="ltr">a <span dir="rtl">b</span></div>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-008a-expected.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-008b-expected.html similarity index 87% copy from third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-008a-expected.html copy to third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-008b-expected.html index 8eb90f8..7a7c841 100644 --- a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-008a-expected.html +++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-008b-expected.html
@@ -9,7 +9,7 @@ </style> </head> <body> -<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<p class="instructions" dir="ltr" style="display:none">Test passes if the two boxes are identical.</p> <div class="ref"><div dir="ltr">‭א ב‬</div><div dir="ltr">‭a b‬</div><div dir="rtl">‭ב א‬</div><div dir="rtl">‭b a‬</div></div> <div class="ref"><div dir="ltr">‭א ב‬</div><div dir="ltr">‭a b‬</div><div dir="rtl">‭ב א‬</div><div dir="rtl">‭b a‬</div></div> </body>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-008b.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-008b.html similarity index 92% rename from third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-008b.html rename to third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-008b.html index f12e6d6..e7b91ce0 100644 --- a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-008b.html +++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-008b.html
@@ -13,14 +13,14 @@ </style> </head> <body> -<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> -<!--Notes: +<p class="instructions" dir="ltr" style="display:none">Test passes if the two boxes are identical.</p> +<!-- Notes: Key to entities used below: א ... ו - The first six Hebrew letters (strongly RTL). ‭ - The LRO (left-to-right-override) formatting character. ‬ - The PDF (pop directional formatting) formatting character; closes LRO. The punctuation is moved around in the source to make it easier to do visual comparisons when the test is run. ---> + --> <div class="test"> <div dir="ltr">א <span dir="auto">ב</span></div> <div dir="ltr">a <span dir="auto">b</span></div>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-008a-expected.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-008c-expected.html similarity index 87% copy from third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-008a-expected.html copy to third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-008c-expected.html index 8eb90f8..7a7c841 100644 --- a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-008a-expected.html +++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-008c-expected.html
@@ -9,7 +9,7 @@ </style> </head> <body> -<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<p class="instructions" dir="ltr" style="display:none">Test passes if the two boxes are identical.</p> <div class="ref"><div dir="ltr">‭א ב‬</div><div dir="ltr">‭a b‬</div><div dir="rtl">‭ב א‬</div><div dir="rtl">‭b a‬</div></div> <div class="ref"><div dir="ltr">‭א ב‬</div><div dir="ltr">‭a b‬</div><div dir="rtl">‭ב א‬</div><div dir="rtl">‭b a‬</div></div> </body>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-008c.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-008c.html similarity index 92% rename from third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-008c.html rename to third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-008c.html index b1754cf..9f7d64e 100644 --- a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-008c.html +++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-008c.html
@@ -13,14 +13,14 @@ </style> </head> <body> -<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> -<!--Notes: +<p class="instructions" dir="ltr" style="display:none">Test passes if the two boxes are identical.</p> +<!-- Notes: Key to entities used below: א ... ו - The first six Hebrew letters (strongly RTL). ‭ - The LRO (left-to-right-override) formatting character. ‬ - The PDF (pop directional formatting) formatting character; closes LRO. The punctuation is moved around in the source to make it easier to do visual comparisons when the test is run. ---> + --> <div class="test"> <div dir="ltr">א <span dir="ltr">ב</span></div> <div dir="ltr">a <span dir="ltr">b</span></div>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-009a-expected.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-009a-expected.html similarity index 86% rename from third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-009a-expected.html rename to third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-009a-expected.html index 1d2f57c..8c7cd39 100644 --- a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-009a-expected.html +++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-009a-expected.html
@@ -9,7 +9,7 @@ </style> </head> <body> -<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<p class="instructions" dir="ltr" style="display:none">Test passes if the two boxes are identical.</p> <div class="ref"><div dir="ltr">‭ג < < b < < א...‬</div><div dir="rtl">‭...a > > ב > > c‬</div></div> <div class="ref"><div dir="ltr">‭ג < < b < < א...‬</div><div dir="rtl">‭...a > > ב > > c‬</div></div> </body>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-009a.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-009a.html similarity index 91% rename from third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-009a.html rename to third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-009a.html index 63a9706..a7e1e75 100644 --- a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-009a.html +++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-009a.html
@@ -13,14 +13,14 @@ </style> </head> <body> -<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> -<!-- Key to entities used below: +<p class="instructions" dir="ltr" style="display:none">Test passes if the two boxes are identical.</p> +<!-- Key to entities used below: א ... ו - The first six Hebrew letters (strongly RTL). ‭ - The LRO (left-to-right-override) formatting character. ‬ - The PDF (pop directional formatting) formatting character; closes LRO. If the BDI in the test's first DIV were a SPAN, its b would prevent the א and the ב from forming a single RTL run and thus keep the >s between from being mirrored into <s. ---> + --> <div class="test"> <div dir="ltr">א > <span dir="rtl">> b ></span> > ג...</div> <div dir="rtl">a > <span dir="ltr">> ב ></span> > c...</div>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-009b-expected.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-009b-expected.html similarity index 86% rename from third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-009b-expected.html rename to third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-009b-expected.html index 30ee14c..e8dea25 100644 --- a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-009b-expected.html +++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-009b-expected.html
@@ -9,7 +9,7 @@ </style> </head> <body> -<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<p class="instructions" dir="ltr" style="display:none">Test passes if the two boxes are identical.</p> <div class="ref"><div dir="ltr">‭ג < > b > < א...‬</div><div dir="rtl">‭...a > < ב < > c‬</div></div> <div class="ref"><div dir="ltr">‭ג < > b > < א...‬</div><div dir="rtl">‭...a > < ב < > c‬</div></div> </body>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-009b.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-009b.html similarity index 91% rename from third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-009b.html rename to third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-009b.html index 57098fa..90fefff 100644 --- a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-009b.html +++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-009b.html
@@ -13,14 +13,14 @@ </style> </head> <body> -<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> -<!-- Key to entities used below: +<p class="instructions" dir="ltr" style="display:none">Test passes if the two boxes are identical.</p> +<!-- Key to entities used below: א ... ו - The first six Hebrew letters (strongly RTL). ‭ - The LRO (left-to-right-override) formatting character. ‬ - The PDF (pop directional formatting) formatting character; closes LRO. If the BDI in the test's first DIV were a SPAN, its b would prevent the א and the ב from forming a single RTL run and thus keep the >s between from being mirrored into <s. ---> + --> <div class="test"> <div dir="ltr">א > <span dir="auto">> b ></span> > ג...</div> <div dir="rtl">a > <span dir="auto">> ב ></span> > c...</div>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-009b-expected.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-009c-expected.html similarity index 86% copy from third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-009b-expected.html copy to third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-009c-expected.html index 30ee14c..e8dea25 100644 --- a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-009b-expected.html +++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-009c-expected.html
@@ -9,7 +9,7 @@ </style> </head> <body> -<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> +<p class="instructions" dir="ltr" style="display:none">Test passes if the two boxes are identical.</p> <div class="ref"><div dir="ltr">‭ג < > b > < א...‬</div><div dir="rtl">‭...a > < ב < > c‬</div></div> <div class="ref"><div dir="ltr">‭ג < > b > < א...‬</div><div dir="rtl">‭...a > < ב < > c‬</div></div> </body>
diff --git a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-009c.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-009c.html similarity index 91% rename from third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-009c.html rename to third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-009c.html index 4aac3184..4e036c2 100644 --- a/third_party/WebKit/LayoutTests/fast/text/international/dir-isolation/dir-isolation-009c.html +++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/dir-isolation-009c.html
@@ -13,14 +13,14 @@ </style> </head> <body> -<p class="instructions" dir="ltr">Test passes if the two boxes are identical.</p> -<!-- Key to entities used below: +<p class="instructions" dir="ltr" style="display:none">Test passes if the two boxes are identical.</p> +<!-- Key to entities used below: א ... ו - The first six Hebrew letters (strongly RTL). ‭ - The LRO (left-to-right-override) formatting character. ‬ - The PDF (pop directional formatting) formatting character; closes LRO. If the BDI in the test's first DIV were a SPAN, its b would prevent the א and the ב from forming a single RTL run and thus keep the >s between from being mirrored into <s. ---> + --> <div class="test"> <div dir="ltr">א > <span dir="ltr">> b ></span> > ג...</div> <div dir="rtl">a > <span dir="rtl">> ב ></span> > c...</div>
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/resources/testharnessreport.js b/third_party/WebKit/LayoutTests/imported/web-platform-tests/resources/testharnessreport.js index 0d9a8a6..56dcac54 100644 --- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/resources/testharnessreport.js +++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/resources/testharnessreport.js
@@ -117,8 +117,11 @@ } // Add results element to document. - if (!document.body) + if (!document.body) { + if (!document.documentElement) + document.appendChild(document.createElement('html')); document.documentElement.appendChild(document.createElement("body")); + } document.body.appendChild(results); if (self.testRunner)
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/uievents/constructors/README.md b/third_party/WebKit/LayoutTests/imported/web-platform-tests/uievents/constructors/README.md deleted file mode 100644 index 097a510..0000000 --- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/uievents/constructors/README.md +++ /dev/null
@@ -1,4 +0,0 @@ -Constructors and States tests -============================== - -These test that each of the defined interfaces can be constructed synthetically, and that all attributes can be set to the appropriate state via the constructors.
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/uievents/hierarchy/README.md b/third_party/WebKit/LayoutTests/imported/web-platform-tests/uievents/hierarchy/README.md deleted file mode 100644 index 3bf23b4..0000000 --- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/uievents/hierarchy/README.md +++ /dev/null
@@ -1,34 +0,0 @@ -Verify the Class Hierarchy -========================== - -Make sure the events inherit from the correct interfaces: - e.g., UIEvent > MouseEvent - -Requires manual and automated tests -* manually create event and verify hierarchy -* WebDriver create the event and verify hierarchy - -UIEvent - * load, unload, abort, error, select, resize, scroll - * Note: some event types may be dropped given that they don't appear to be UIEvents by other specs that define them. - -FocusEvent - * blur, focus, focusin, focusout - * blur and focus are handled in HTML5 - * but they aren't sure if focusin/out are needed: see bug: https://www.w3.org/Bugs/Public/show_bug.cgi?id=25877 - -MouseEvent - * click, dblclick, mousedown, mouseenter, mouseleave, mousemove, mouseout, mouseover, mouseup - -WheelEvent - * wheel - -KeyboardEvent - * keydown, keyup - * need to show interaction with beforeinput and input, which are in the Editing spec - -CompositionEvent - * compositionstart - * compositionupdate - * compositionend - * need to show interaction with the keyboard events: keydown, keyup
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/uievents/interface/README.md b/third_party/WebKit/LayoutTests/imported/web-platform-tests/uievents/interface/README.md deleted file mode 100644 index 970fdd4..0000000 --- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/uievents/interface/README.md +++ /dev/null
@@ -1,13 +0,0 @@ -Interface tests -============================== - -These test that the basic UI Events interfaces exist, specifically: - -1. Does the interface exist -2. Are all the members defined on the interface accounted for: - * UIEvent - * MouseEvent - * FocusEvent - * KeyboardEvent - * WheelEvent - * CompositionEvent
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/uievents/order-of-events/README.md b/third_party/WebKit/LayoutTests/imported/web-platform-tests/uievents/order-of-events/README.md deleted file mode 100644 index a6ef35eb..0000000 --- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/uievents/order-of-events/README.md +++ /dev/null
@@ -1,15 +0,0 @@ -Order of events -============================ - -Testing of how events fire in relation to one another - -(this is the big work item) - -Expecting to need: - * braindead test (does it work at all?) - * specific functional tests - * specific edge cases - -Notes: - * small tests so that they can be given specific names for what's broken if it fails - * include a link to the corresponding test in the spec.
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/uievents/resources/eventrecorder.js b/third_party/WebKit/LayoutTests/imported/web-platform-tests/uievents/resources/eventrecorder.js deleted file mode 100644 index 936b136..0000000 --- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/uievents/resources/eventrecorder.js +++ /dev/null
@@ -1,283 +0,0 @@ -// interface EventRecorder { -// static void start(); -// static void stop(); -// static void clearRecords(); -// static sequence<EventRecord> getRecords(); -// static void configure(EventRecorderOptions options); -// }; -// * getRecords -// * returns an array of EventRecord objects; the array represents the sequence of events captured at anytime after the last clear() -// call, between when the recorder was started and stopped (including multiple start/stop pairs) -// * configure -// * sets options that should apply to the recorder. If the recorder has any existing records, than this API throws an exception. -// * start -// * starts/un-pauses the recorder -// * stop -// * stops/pauses the recorder -// * clear -// * purges all recorded records - -// ---------------------- - -// dictionary EventRecorderOptions { -// sequence<SupportedEventTypes> mergeEventTypes; -// ObjectNamedMap objectMap; -// }; -// * mergeEventTypes -// * a list of event types that should be consolidated into one record when all of the following conditions are true: -// 1) The events are of the same type and follow each other chronologically -// 2) The events' currentTarget is the same -// * The default is an empty list (no event types are merged). -// * objectMap -// * Sets up a series - -// dictionary ObjectNamedMap { -// //<keys will be 'targetTestID' names, with values of the objects which they label> -// }; -// * targetTestID = the string identifier that the associated target object should be known as (for purposes of unique identification. This -// need not be the same as the Node's id attribute if it has one. If no 'targetTestID' string mapping is provided via this -// map, but is encountered later when recording specific events, a generic targetTestID of 'UNKNOWN_OBJECT' is used. - -// ---------------------- - -// dictionary EventRecord { -// unsigned long chronologicalOrder; -// unsigned long sequentialOccurrences; -// sequence<EventRecord>? nestedEvents; -// DOMString interfaceType; -// EventRecordDetails event; -// }; -// * chronologicalOrder -// * Since some events may be dispatched re-entrantly (e.g., while existing events are being dispatched), and others may be merged -// given the 'mergeEventTypes' option in the EventRecorder, this value is the actual chronological order that the event fired -// * sequentialOccurrences -// * If this event was fired multiple times in a row (see the 'mergeEventTypes' option), this value is the count of occurrences. -// A value of 1 means this was the only occurrence of this event (that no events were merged with it). A value greater than 1 -// indicates that the event occurred that many times in a row. -// * nestedEvents -// * The holds all the events that were sequentially dispatched synchronously while the current event was still being dispatched -// (e.g., between the time that this event listener was triggered and when it returned). -// * Has the value null if no nested events were recorded during the invocation of this listener. -// * interfaceType -// * The string indicating which Event object (or derived Event object type) the recorded event object instance is based on. -// * event -// * Access to the recorded event properties for the event instance (not the actual event instance itself). A snapshot of the -// enumerable properties of the event object instance at the moment the listener was first triggered. - -// ---------------------- - -// dictionary EventRecordDetails { -// //<recorded property names with their values for all enumerable properties of the event object instance> -// }; -// * EventRecordDetails -// * For records with 'sequentialOccurrences' > 1, only the first occurence is recorded (subsequent event details are dropped). -// * Object reference values (e.g., event.target, event.currentTarget, etc.) are replaced with their mapped 'targetTestID' string. -// If no 'targetTestID' string mapping is available for a particular object, the value 'UNKNOWN_OBJECT' is returned. - -// ---------------------- - -// [NoInterfaceObject] -// interface EventRecorderRegistration { -// void addRecordedEventListener(SupportedEventTypes type, EventListener? handler, optional boolean capturePhase = false); -// void removeRecordedEventListener(SupportedEventTypes type, EventListener? handler, optional boolean capturePhase = false); -// }; -// Node implements EventRecorderRegistration; -// -// enum SupportedEventTypes = { -// "mousemove", -// etc... -// }; -// * addRecordedEventListener -// * handler = pass null if you want only a default recording of the event (and don't need any other special handling). Otherwise, -// the handler will be invoked normally as part of the event's dispatch. -// * <other params> are the same as those defined on addEventListener/removeEventListenter APIs (see DOM4) -// * Use this API *instead of* addEventListener to record your events for testing purposes. - -(function EventRecorderScope(global) { - "use strict"; - - if (global.EventRecorder) - return; // Already initialized. - - // WeakMap polyfill - if (!global.WeakMap) { - throw new Error("EventRecorder depends on WeakMap! Please polyfill for completeness to run in this user agent!"); - } - - // Globally applicable variables - var allRecords = []; - var recording = false; - var rawOrder = 1; - var mergeTypesTruthMap = {}; // format of { eventType: true, ... } - var eventsInScope = []; // Tracks synchronous event dispatches - var handlerMap = new WeakMap(); // Keeps original handlers (so that they can be used to un-register for events. - - // Find all Event Object Constructors on the global and add them to the map along with their name (sans 'Event') - var eventConstructorsNameMap = new WeakMap(); // format of key: hostObject, value: alias to use. - var regex = /[A-Z][A-Za-z0-9]+Event$/; - Object.getOwnPropertyNames(global).forEach(function (propName) { - if (regex.test(propName)) - eventConstructorsNameMap.set(global[propName], propName); - }); - var knownObjectsMap = eventConstructorsNameMap; - - Object.defineProperty(global, "EventRecorder", { - writable: true, - configurable: true, - value: Object.create(null, { - start: { - enumerable: true, configurable: true, writable: true, value: function start() { recording = true; } - }, - stop: { - enumerable: true, configurable: true, writable: true, value: function stop() { recording = false; } - }, - clearRecords: { - enumerable: true, configurable: true, writable: true, value: function clearRecords() { - rawOrder = 1; - allRecords = []; - } - }, - getRecords: { - enumerable: true, configurable: true, writable: true, value: function getRecords() { return allRecords; } - }, - configure: { - enumerable: true, configurable: true, writable: true, value: function configure(options) { - if (allRecords.length > 0) - throw new Error("Wrong time to call me: EventRecorder.configure must only be called when no recorded events are present. Try 'clearRecords' first."); - - // Un-configure existing options by calling again with no options set... - mergeTypesTruthMap = {}; - knownObjectsMap = eventConstructorsNameMap; - - if (!(options instanceof Object)) - return; - // Sanitize the passed object (tease-out getter functions) - var sanitizedOptions = {}; - for (var x in options) { - sanitizedOptions[x] = options[x]; - } - if (sanitizedOptions.mergeEventTypes && Array.isArray(sanitizedOptions.mergeEventTypes)) { - sanitizedOptions.mergeEventTypes.forEach(function (eventType) { - if (typeof eventType == "string") - mergeTypesTruthMap[eventType] = true; - }); - } - if (sanitizedOptions.objectMap && (sanitizedOptions.objectMap instanceof Object)) { - for (var y in sanitizedOptions.objectMap) { - knownObjectsMap.set(sanitizedOptions.objectMap[y], y); - } - } - } - } - }) - }); - - function EventRecord(rawEvent) { - this.chronologicalOrder = rawOrder++; - this.sequentialOccurrences = 1; - this.nestedEvents = null; // potentially a [] - this.interfaceType = knownObjectsMap.get(rawEvent.constructor); - if (!this.interfaceType) // In case (somehow) this event's constructor is not named something with an 'Event' suffix... - this.interfaceType = rawEvent.constructor.toString(); - this.event = new CloneObjectLike(rawEvent); - } - - // Only enumerable props including prototype-chain (non-recursive), w/no functions. - function CloneObjectLike(object) { - for (var prop in object) { - var val = object[prop]; - if (Array.isArray(val)) - this[prop] = CloneArray(val); - else if (typeof val == "function") - continue; - else if ((typeof val == "object") && (val != null)) { - this[prop] = knownObjectsMap.get(val); - if (this[prop] === undefined) - this[prop] = "UNKNOWN_OBJECT (" + val.toString() + ")"; - } - else - this[prop] = val; - } - } - - function CloneArray(array) { - var dup = []; - for (var i = 0, len = array.length; i < len; i++) { - var val = array[i] - if (typeof val == "undefined") - throw new Error("Ugg. Sparce arrays are not supported. Sorry!"); - else if (Array.isArray(val)) - dup[i] = "UNKNOWN_ARRAY"; - else if (typeof val == "function") - dup[i] = "UNKNOWN_FUNCTION"; - else if ((typeof val == "object") && (val != null)) { - dup[i] = knownObjectsMap.get(val); - if (dup[i] === undefined) - dup[i] = "UNKNOWN_OBJECT (" + val.toString() + ")"; - } - else - dup[i] = val; - } - return dup; - } - - function generateRecordedEventHandlerWithCallback(callback) { - return function(e) { - if (recording) { - // Setup the scope for any synchronous events - eventsInScope.push(recordEvent(e)); - callback.call(this, e); - eventsInScope.pop(); - } - } - } - - function recordedEventHandler(e) { - if (recording) - recordEvent(e); - } - - function recordEvent(e) { - var record = new EventRecord(e); - var recordList = allRecords; - // Adjust which sequential list to use depending on scope - if (eventsInScope.length > 0) { - recordList = eventsInScope[eventsInScope.length - 1].nestedEvents; - if (recordList == null) // This top-of-stack event record hasn't had any nested events yet. - recordList = eventsInScope[eventsInScope.length - 1].nestedEvents = []; - } - if (mergeTypesTruthMap[e.type] && (recordList.length > 0)) { - var tail = recordList[recordList.length-1]; - // Same type and currentTarget? - if ((tail.event.type == record.event.type) && (tail.event.currentTarget == record.event.currentTarget)) { - tail.sequentialOccurrences++; - return; - } - } - recordList.push(record); - return record; - } - - Object.defineProperties(Node.prototype, { - addRecordedEventListener: { - enumerable: true, writable: true, configurable: true, - value: function addRecordedEventListener(type, handler, capture) { - if (handler == null) - this.addEventListener(type, recordedEventHandler, capture); - else { - var subvertedHandler = generateRecordedEventHandlerWithCallback(handler); - handlerMap.set(handler, subvertedHandler); - this.addEventListener(type, subvertedHandler, capture); - } - } - }, - removeRecordedEventListener: { - enumerable: true, writable: true, configurable: true, - value: function addRecordedEventListener(type, handler, capture) { - var alternateHandlerUsed = handlerMap.get(handler); - this.removeEventListenter(type, alternateHandlerUsed ? alternateHandlerUsed : recordedEventHandler, capture); - } - } - }); - -})(window); \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/inspector/components/file-path-scoring.html b/third_party/WebKit/LayoutTests/inspector/components/file-path-scoring.html index 37a07389..6f0177e 100644 --- a/third_party/WebKit/LayoutTests/inspector/components/file-path-scoring.html +++ b/third_party/WebKit/LayoutTests/inspector/components/file-path-scoring.html
@@ -45,7 +45,7 @@ var scorer = new WebInspector.FilePathScoreFunction(query); var bestScore = -1; var bestIndex = -1; - var filter = WebInspector.FilePathScoreFunction.filterRegex(query); + var filter = WebInspector.FilteredListWidget.filterRegex(query); for(var i = 0; i < paths.length; ++i) { if (!filter.test(paths[i])) continue;
diff --git a/third_party/WebKit/LayoutTests/inspector/filtered-item-selection-dialog-filtering.html b/third_party/WebKit/LayoutTests/inspector/filtered-item-selection-dialog-filtering.html index fd2a7252..483ccbc 100644 --- a/third_party/WebKit/LayoutTests/inspector/filtered-item-selection-dialog-filtering.html +++ b/third_party/WebKit/LayoutTests/inspector/filtered-item-selection-dialog-filtering.html
@@ -13,7 +13,7 @@ function StubDelegate() { - WebInspector.SelectionDialogContentProvider.call(this, history); + WebInspector.FilteredListWidget.Delegate.call(this, history); } StubDelegate.prototype = { itemKeyAt: function(itemIndex) { return overridenInput[itemIndex]; }, @@ -25,7 +25,7 @@ }, shouldShowMatchingItems: function() { return overrideShowMatchingItems; }, - __proto__: WebInspector.SelectionDialogContentProvider.prototype + __proto__: WebInspector.FilteredListWidget.Delegate.prototype } var delegate = new StubDelegate(); @@ -37,7 +37,8 @@ InspectorTest.addResult("Input:" + JSON.stringify(input)); - var filteredSelectionDialog = new WebInspector.FilteredItemSelectionDialog(delegate); + var filteredSelectionDialog = new WebInspector.FilteredListWidget(delegate); + filteredSelectionDialog.showAsDialog(); InspectorTest.addSniffer(filteredSelectionDialog, "_autocompletedForTests", onautocomplete); filteredSelectionDialog.setQuery(query); filteredSelectionDialog._updateAfterItemsLoaded();
diff --git a/third_party/WebKit/LayoutTests/inspector/filtered-item-selection-dialog-rendering.html b/third_party/WebKit/LayoutTests/inspector/filtered-item-selection-dialog-rendering.html index b93c133e..c87bb3f 100644 --- a/third_party/WebKit/LayoutTests/inspector/filtered-item-selection-dialog-rendering.html +++ b/third_party/WebKit/LayoutTests/inspector/filtered-item-selection-dialog-rendering.html
@@ -11,7 +11,7 @@ <script> function test() { - var delegate = new WebInspector.SelectUISourceCodeDialog(); + var delegate = new WebInspector.FilteredUISourceCodeListDelegate(); InspectorTest.runTestSuite([ function testRenderingInNameOnly(next)
diff --git a/third_party/WebKit/LayoutTests/inspector/initial-modules-load-expected.txt b/third_party/WebKit/LayoutTests/inspector/initial-modules-load-expected.txt index 109028d..d53923c9 100644 --- a/third_party/WebKit/LayoutTests/inspector/initial-modules-load-expected.txt +++ b/third_party/WebKit/LayoutTests/inspector/initial-modules-load-expected.txt
@@ -37,6 +37,7 @@ common components components_lazy + diff elements emulation extensions
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/scripts-panel-expected.txt b/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/scripts-panel-expected.txt index cd5de4ea4..8df374d19 100644 --- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/scripts-panel-expected.txt +++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/scripts-panel-expected.txt
@@ -2,6 +2,7 @@ Running: testInitialLoad +Navigator: mock-target-1 top (no domain) @@ -11,6 +12,7 @@ foobar.js Running: testReset +Navigator: mock-target-2 top (no domain) @@ -18,22 +20,28 @@ baz.js foo.js Revealing in navigator. +Navigator: mock-target-2 top (no domain) bar.js baz.js foo.js +Navigator: +mock-target-2 +Navigator: mock-target-2 top (no domain) bar.js Running: testDebuggerUISourceCodeAddedAndRemoved +Navigator: mock-target-3 top (no domain) foo.js +Navigator: mock-target-3 top (no domain)
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/scripts-panel.html b/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/scripts-panel.html index baa71ae..2b39aa2 100644 --- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/scripts-panel.html +++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/scripts-panel.html
@@ -8,6 +8,7 @@ { function dumpNavigator(sourcesNavigatorView) { + InspectorTest.addResult("Navigator:"); InspectorTest.dumpNavigatorView(sourcesNavigatorView); }
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/scripts-sorting.html b/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/scripts-sorting.html index c74a435..4d2b1c767 100644 --- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/scripts-sorting.html +++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/scripts-sorting.html
@@ -7,11 +7,6 @@ <script> function test() { - function dumpNavigator(sourcesNavigatorView) - { - InspectorTest.dumpNavigatorView(sourcesNavigatorView); - } - function createNavigatorView(constructor) { var navigatorView = new constructor(); @@ -32,31 +27,18 @@ uiSourceCodes.push(uiSourceCode); } - function dumpNavigator(view) - { - ["frame", "frame/domain", "frame/domain/folder", "domain", "domain/folder"].forEach(dumpNavigatorInMode.bind(null, view)); - } - - function dumpNavigatorInMode(view, mode) - { - InspectorTest.addResult(view === sourcesNavigatorView ? "Sources:" : "Content Scripts:"); - WebInspector.moduleSetting("navigatorGrouping").set(mode); - InspectorTest.addResult("-------- Setting mode: [" + mode + "]"); - InspectorTest.dumpNavigatorView(view); - } - function dumpScriptsList() { - dumpNavigator(sourcesNavigatorView); - dumpNavigator(contentScriptsNavigatorView); + InspectorTest.dumpNavigatorViewInAllModes(sourcesNavigatorView); + InspectorTest.dumpNavigatorViewInAllModes(contentScriptsNavigatorView); for (var i = 0; i < uiSourceCodes.length; ++i) { sourcesNavigatorView.revealUISourceCode(uiSourceCodes[i]); contentScriptsNavigatorView.revealUISourceCode(uiSourceCodes[i]); } - dumpNavigator(sourcesNavigatorView); - dumpNavigator(contentScriptsNavigatorView); + InspectorTest.dumpNavigatorViewInAllModes(sourcesNavigatorView); + InspectorTest.dumpNavigatorViewInAllModes(contentScriptsNavigatorView); } var scripts = [
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/source-frame-count-expected.txt b/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/source-frame-count-expected.txt index 6ecb5f7..475f28ca 100644 --- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/source-frame-count-expected.txt +++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/source-frame-count-expected.txt
@@ -2,5 +2,8 @@ Running: testSourceFramesCount +Reloading page... Page reloaded. +Less than 3 frames opened +Visible view: script5.js
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/source-frame-count.html b/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/source-frame-count.html index c0b8986..b98a2ae 100644 --- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/source-frame-count.html +++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/source-frame-count.html
@@ -2,58 +2,54 @@ <head> <script src="../../../http/tests/inspector/inspector-test.js"></script> <script src="../../../http/tests/inspector/debugger-test.js"></script> -<script src="../debugger/resources/script1.js"></script> -<script src="../debugger/resources/script2.js"></script> -<script src="../debugger/resources/script3.js"></script> <script> +function createScriptsAndRun() +{ + eval("window.foo1 = function() {}\n//# sourceURL=script1.js"); + eval("window.foo2 = function() {}\n//# sourceURL=script2.js"); + eval("window.foo3 = function() {}\n//# sourceURL=script3.js"); + eval("window.foo4 = function() {}\n//# sourceURL=script4.js"); + eval("window.foo5 = function() {}\n//# sourceURL=script5.js"); + + runTest(); +} function test() { + var framesOpened = 0; + InspectorTest.runDebuggerTestSuite([ function testSourceFramesCount(next) { var panel = WebInspector.panels.sources; - var sourceFrameCount = 0; - InspectorTest.showScriptSource("source-frame-count.html", step2); + InspectorTest.showScriptSource("source-frame-count.html", function() {}); + InspectorTest.showScriptSource("script1.js", function() {}); + InspectorTest.showScriptSource("script2.js", function() {}); + InspectorTest.showScriptSource("script3.js", function() {}); + InspectorTest.showScriptSource("script4.js", function() {}); + InspectorTest.showScriptSource("script5.js", reloadThePage); - function step2() + function reloadThePage() { - InspectorTest.showScriptSource("script1.js", step3); - } - - function step3() - { - InspectorTest.showScriptSource("script2.js", didShowScriptSources); - } - - function didShowScriptSources() - { - var alreadyShownURLs = {}; + InspectorTest.addResult("Reloading page..."); + InspectorTest.reloadPage(didReload); function didCreateSourceFrame() { - if (!alreadyShownURLs[this._uiSourceCode.originURL()]) - sourceFrameCount += 1; - alreadyShownURLs[this._uiSourceCode.originURL()] = true; + framesOpened++; } InspectorTest.addSniffer(WebInspector.SourceFrame.prototype, "wasShown", didCreateSourceFrame, true); - InspectorTest.reloadPage(didReload); + } function didReload() { - InspectorTest.showScriptSource("script3.js", didShowScriptSourceAgain); - } - - function didShowScriptSourceAgain() - { - InspectorTest.assertTrue(panel.visibleView._uiSourceCode.originURL().indexOf("script3.js") !== -1); - // There should be maximum 3 source frames shown: - // - first one is the first shown (first tab added) - // - second one is the last viewed ("script2.js") - // - third one is explicitly selected script3.js. - InspectorTest.assertEquals(true, sourceFrameCount <= 3, "too many source frames created after page reload"); + if (framesOpened > 3) + InspectorTest.addResult("Too many frames opened: " + framesOpened); + else + InspectorTest.addResult("Less than 3 frames opened"); + InspectorTest.addResult("Visible view: " + panel.visibleView._uiSourceCode.name()); next(); } } @@ -85,7 +81,7 @@ </head> -<body onload="runTest()"> +<body onload="createScriptsAndRun()"> <p>Tests that scripts panel does not create too many source frames.</p> </body>
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger/navigator-view-expected.txt b/third_party/WebKit/LayoutTests/inspector/sources/debugger/navigator-view-expected.txt index 35cf51c..11c72cd 100644 --- a/third_party/WebKit/LayoutTests/inspector/sources/debugger/navigator-view-expected.txt +++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger/navigator-view-expected.txt
@@ -70,7 +70,7 @@ top script.js script.js?a=2 - childframe( iframeurl.html ) + childframe (iframeurl.html) script.js script.js?a=1 Sources: @@ -79,7 +79,7 @@ localhost:8080 script.js script.js?a=2 - childframe( iframeurl.html ) + childframe (iframeurl.html) localhost:8080 script.js script.js?a=1 @@ -90,7 +90,7 @@ LayoutTests/inspector/debugger/foo/bar script.js script.js?a=2 - childframe( iframeurl.html ) + childframe (iframeurl.html) localhost:8080 LayoutTests/inspector/debugger/foo bar @@ -109,12 +109,11 @@ localhost:8080 LayoutTests/inspector/debugger/foo bar + script.js script.js?a=1 + script.js?a=2 baz script.js - LayoutTests/inspector/debugger/foo/bar - script.js - script.js?a=2 ================================================ @@ -124,7 +123,7 @@ top script.js script.js?a=2 - childframe( iframeurl.html ) + childframe (iframeurl.html) script.js script.js?a=1 mock-target-100 @@ -137,7 +136,7 @@ localhost:8080 script.js script.js?a=2 - childframe( iframeurl.html ) + childframe (iframeurl.html) localhost:8080 script.js script.js?a=1 @@ -153,7 +152,7 @@ LayoutTests/inspector/debugger/foo/bar script.js script.js?a=2 - childframe( iframeurl.html ) + childframe (iframeurl.html) localhost:8080 LayoutTests/inspector/debugger/foo bar @@ -191,12 +190,11 @@ localhost:8080 LayoutTests/inspector/debugger/foo bar + script.js script.js?a=1 + script.js?a=2 baz script.js - LayoutTests/inspector/debugger/foo/bar - script.js - script.js?a=2 ================================================ @@ -216,7 +214,7 @@ script.js?a=2 very_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo… white space.html - childframe( iframeurl.html ) + childframe (iframeurl.html) script.js script.js?a=1 mock-target-100 @@ -241,7 +239,7 @@ contentScript2.js?a=1 script.js script.js?a=2 - childframe( iframeurl.html ) + childframe (iframeurl.html) localhost:8080 script.js script.js?a=1 @@ -271,7 +269,7 @@ contentScript2.js?a=1 script.js script.js?a=2 - childframe( iframeurl.html ) + childframe (iframeurl.html) localhost:8080 LayoutTests/inspector/debugger/foo bar @@ -332,15 +330,14 @@ localhost:8080 LayoutTests/inspector/debugger/foo bar + contentScript.js?a=1 + contentScript.js?a=2 + contentScript2.js?a=1 + script.js script.js?a=1 + script.js?a=2 baz script.js - LayoutTests/inspector/debugger/foo/bar - contentScript.js?a=1 - contentScript.js?a=2 - contentScript2.js?a=1 - script.js - script.js?a=2 Content Scripts: -------- Setting mode: [frame] Content Scripts: @@ -370,7 +367,7 @@ script.js?a=2 very_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo… white space.html - childframe( iframeurl.html ) + childframe (iframeurl.html) script.js script.js?a=1 mock-target-100 @@ -395,7 +392,7 @@ contentScript2.js?a=1 script.js script.js?a=2 - childframe( iframeurl.html ) + childframe (iframeurl.html) localhost:8080 script.js script.js?a=1 @@ -425,7 +422,7 @@ contentScript2.js?a=1 script.js script.js?a=2 - childframe( iframeurl.html ) + childframe (iframeurl.html) localhost:8080 LayoutTests/inspector/debugger/foo bar @@ -486,15 +483,14 @@ localhost:8080 LayoutTests/inspector/debugger/foo bar + contentScript.js?a=1 + contentScript.js?a=2 + contentScript2.js?a=1 + script.js script.js?a=1 + script.js?a=2 baz script.js - LayoutTests/inspector/debugger/foo/bar - contentScript.js?a=1 - contentScript.js?a=2 - contentScript2.js?a=1 - script.js - script.js?a=2 ================================================ @@ -515,7 +511,7 @@ script.js?a=2 very_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo… white space.html - childframe( iframeurl.html ) + childframe (iframeurl.html) script.js script.js?a=1 mock-target-100 @@ -541,7 +537,7 @@ script.js script.js script.js?a=2 - childframe( iframeurl.html ) + childframe (iframeurl.html) localhost:8080 script.js script.js?a=1 @@ -574,7 +570,7 @@ script.js?a=2 debugger2/foo/bar script.js - childframe( iframeurl.html ) + childframe (iframeurl.html) localhost:8080 LayoutTests/inspector/debugger/foo bar @@ -634,18 +630,17 @@ (index) ?a=b localhost:8080 - LayoutTests/inspector/debugger/foo - bar - script.js?a=1 - baz - script.js LayoutTests/inspector - debugger/foo/bar - contentScript.js?a=1 - contentScript.js?a=2 - contentScript2.js?a=1 - script.js - script.js?a=2 + debugger/foo + bar + contentScript.js?a=1 + contentScript.js?a=2 + contentScript2.js?a=1 + script.js + script.js?a=1 + script.js?a=2 + baz + script.js debugger2/foo/bar script.js @@ -669,7 +664,7 @@ script.js?a=2 very_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo… white space.html - childframe( iframeurl.html ) + childframe (iframeurl.html) script.js script.js?a=1 mock-target-100 @@ -696,7 +691,7 @@ script.js script.js?a=2 script.js?a=2 - childframe( iframeurl.html ) + childframe (iframeurl.html) localhost:8080 script.js script.js?a=1 @@ -730,7 +725,7 @@ debugger2/foo/bar script.js script.js?a=2 - childframe( iframeurl.html ) + childframe (iframeurl.html) localhost:8080 LayoutTests/inspector/debugger/foo bar @@ -791,18 +786,17 @@ (index) ?a=b localhost:8080 - LayoutTests/inspector/debugger/foo - bar - script.js?a=1 - baz - script.js LayoutTests/inspector - debugger/foo/bar - contentScript.js?a=1 - contentScript.js?a=2 - contentScript2.js?a=1 - script.js - script.js?a=2 + debugger/foo + bar + contentScript.js?a=1 + contentScript.js?a=2 + contentScript2.js?a=1 + script.js + script.js?a=1 + script.js?a=2 + baz + script.js debugger2/foo/bar script.js script.js?a=2 @@ -829,7 +823,7 @@ script.js?a=2 very_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo… white space.html - childframe( iframeurl.html ) + childframe (iframeurl.html) script.js script.js?a=1 mock-target-100 @@ -858,7 +852,7 @@ script.js?a=1 script.js?a=2 script.js?a=2 - childframe( iframeurl.html ) + childframe (iframeurl.html) localhost:8080 script.js script.js?a=1 @@ -896,7 +890,7 @@ script.js?a=2 baz script.js - childframe( iframeurl.html ) + childframe (iframeurl.html) localhost:8080 LayoutTests/inspector/debugger/foo bar @@ -959,18 +953,17 @@ (index) ?a=b localhost:8080 - LayoutTests/inspector/debugger/foo - bar - script.js?a=1 - baz - script.js LayoutTests/inspector - debugger/foo/bar - contentScript.js?a=1 - contentScript.js?a=2 - contentScript2.js?a=1 - script.js - script.js?a=2 + debugger/foo + bar + contentScript.js?a=1 + contentScript.js?a=2 + contentScript2.js?a=1 + script.js + script.js?a=1 + script.js?a=2 + baz + script.js debugger2/foo bar script.js @@ -1003,7 +996,7 @@ script.js?a=2 very_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo… white space.html - childframe( iframeurl.html ) + childframe (iframeurl.html) script.js script.js?a=1 mock-target-100 @@ -1035,7 +1028,7 @@ script.js?a=1 script.js?a=2 script.js?a=2 - childframe( iframeurl.html ) + childframe (iframeurl.html) localhost:8080 script.js script.js?a=1 @@ -1079,7 +1072,7 @@ foo.js foo.js foo.js - childframe( iframeurl.html ) + childframe (iframeurl.html) localhost:8080 LayoutTests/inspector/debugger/foo bar @@ -1145,18 +1138,17 @@ (index) ?a=b localhost:8080 - LayoutTests/inspector/debugger/foo - bar - script.js?a=1 - baz - script.js LayoutTests/inspector - debugger/foo/bar - contentScript.js?a=1 - contentScript.js?a=2 - contentScript2.js?a=1 - script.js - script.js?a=2 + debugger/foo + bar + contentScript.js?a=1 + contentScript.js?a=2 + contentScript2.js?a=1 + script.js + script.js?a=1 + script.js?a=2 + baz + script.js debugger2/foo bar script.js @@ -1196,7 +1188,7 @@ script.js?a=2 very_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo… white space.html - childframe( iframeurl.html ) + childframe (iframeurl.html) script.js script.js?a=1 mock-target-100 @@ -1228,7 +1220,7 @@ script.js?a=1 script.js?a=2 script.js?a=2 - childframe( iframeurl.html ) + childframe (iframeurl.html) localhost:8080 script.js script.js?a=1 @@ -1272,7 +1264,7 @@ foo.js foo.js foo.js - childframe( iframeurl.html ) + childframe (iframeurl.html) localhost:8080 LayoutTests/inspector/debugger/foo bar @@ -1338,18 +1330,17 @@ (index) ?a=b localhost:8080 - LayoutTests/inspector/debugger/foo - bar - script.js?a=1 - baz - script.js LayoutTests/inspector - debugger/foo/bar - contentScript.js?a=1 - contentScript.js?a=2 - contentScript2.js?a=1 - script.js - script.js?a=2 + debugger/foo + bar + contentScript.js?a=1 + contentScript.js?a=2 + contentScript2.js?a=1 + script.js + script.js?a=1 + script.js?a=2 + baz + script.js debugger2/foo bar script.js @@ -1399,7 +1390,7 @@ script.js?a=2 very_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo… white space.html - childframe( iframeurl.html ) + childframe (iframeurl.html) script.js script.js?a=1 Sources: @@ -1427,7 +1418,7 @@ script.js?a=1 script.js?a=2 script.js?a=2 - childframe( iframeurl.html ) + childframe (iframeurl.html) localhost:8080 script.js script.js?a=1 @@ -1466,7 +1457,7 @@ foo.js foo.js foo.js - childframe( iframeurl.html ) + childframe (iframeurl.html) localhost:8080 LayoutTests/inspector/debugger/foo bar @@ -1513,18 +1504,17 @@ (index) ?a=b localhost:8080 - LayoutTests/inspector/debugger/foo - bar - script.js?a=1 - baz - script.js LayoutTests/inspector - debugger/foo/bar - contentScript.js?a=1 - contentScript.js?a=2 - contentScript2.js?a=1 - script.js - script.js?a=2 + debugger/foo + bar + contentScript.js?a=1 + contentScript.js?a=2 + contentScript2.js?a=1 + script.js + script.js?a=1 + script.js?a=2 + baz + script.js debugger2/foo bar script.js
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger/navigator-view.html b/third_party/WebKit/LayoutTests/inspector/sources/debugger/navigator-view.html index 10a6332..ced0e9de 100644 --- a/third_party/WebKit/LayoutTests/inspector/sources/debugger/navigator-view.html +++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger/navigator-view.html
@@ -48,42 +48,29 @@ contentScriptsNavigatorView.revealUISourceCode(uiSourceCode); } - function dumpNavigator(view) - { - ["frame", "frame/domain", "frame/domain/folder", "domain", "domain/folder"].forEach(dumpNavigatorInMode.bind(null, view)); - } - - function dumpNavigatorInMode(view, mode) - { - InspectorTest.addResult(view === sourcesNavigatorView ? "Sources:" : "Content Scripts:"); - WebInspector.moduleSetting("navigatorGrouping").set(mode); - InspectorTest.addResult("-------- Setting mode: [" + mode + "]"); - InspectorTest.dumpNavigatorView(view); - } - var rootURL = "http://localhost:8080/LayoutTests/inspector/debugger/"; InspectorTest.addResult("\n\n================================================"); InspectorTest.addResult("Adding first resource:"); addUISourceCode(rootURL + "foo/bar/script.js", false); - dumpNavigator(sourcesNavigatorView); + InspectorTest.dumpNavigatorViewInAllModes(sourcesNavigatorView); InspectorTest.addResult("\n\n================================================"); InspectorTest.addResult("Adding second resource:"); addUISourceCode(rootURL + "foo/bar/script.js?a=2", false); - dumpNavigator(sourcesNavigatorView); + InspectorTest.dumpNavigatorViewInAllModes(sourcesNavigatorView); InspectorTest.addResult("\n\n================================================"); InspectorTest.addResult("Adding resources into another frame:"); addUISourceCode(rootURL + "foo/bar/script.js?a=1", false, subframe); addUISourceCode(rootURL + "foo/baz/script.js", false, subframe); - dumpNavigator(sourcesNavigatorView); + InspectorTest.dumpNavigatorViewInAllModes(sourcesNavigatorView); InspectorTest.addResult("\n\n================================================"); InspectorTest.addResult("Adding resources into another target:"); addUISourceCode2(rootURL + "foo/bar/script.js?a=3", false); addUISourceCode2(rootURL + "foo/baz/script.js", false); - dumpNavigator(sourcesNavigatorView); + InspectorTest.dumpNavigatorViewInAllModes(sourcesNavigatorView); InspectorTest.addResult("\n\n================================================"); InspectorTest.addResult("Adding content scripts and some random resources:"); @@ -98,51 +85,51 @@ addUISourceCode("http://example.com/path%20with%20spaces/white%20space.html", false); addUISourceCode("?a=b", false); addUISourceCode("very_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_url", false); - dumpNavigator(sourcesNavigatorView); - dumpNavigator(contentScriptsNavigatorView); + InspectorTest.dumpNavigatorViewInAllModes(sourcesNavigatorView); + InspectorTest.dumpNavigatorViewInAllModes(contentScriptsNavigatorView); InspectorTest.addResult("\n\n================================================"); InspectorTest.addResult("Revealing first resource:"); revealUISourceCode(uiSourceCodes[0]); - dumpNavigator(sourcesNavigatorView); + InspectorTest.dumpNavigatorViewInAllModes(sourcesNavigatorView); // Here we keep http://localhost:8080/LayoutTests/inspector/debugger2/ folder collapsed while adding resources into it. InspectorTest.addResult("\n\n================================================"); InspectorTest.addResult("Adding some resources to change the way debugger folder looks like, first:"); var rootURL2 = "http://localhost:8080/LayoutTests/inspector/debugger2/"; addUISourceCode(rootURL2 + "foo/bar/script.js", false); - dumpNavigator(sourcesNavigatorView); + InspectorTest.dumpNavigatorViewInAllModes(sourcesNavigatorView); InspectorTest.addResult("\n\n================================================"); InspectorTest.addResult("Second:"); addUISourceCode(rootURL2 + "foo/bar/script.js?a=2", false); - dumpNavigator(sourcesNavigatorView); + InspectorTest.dumpNavigatorViewInAllModes(sourcesNavigatorView); InspectorTest.addResult("\n\n================================================"); InspectorTest.addResult("Others:"); addUISourceCode(rootURL2 + "foo/bar/script.js?a=1", false); addUISourceCode(rootURL2 + "foo/baz/script.js", false); - dumpNavigator(sourcesNavigatorView); + InspectorTest.dumpNavigatorViewInAllModes(sourcesNavigatorView); InspectorTest.addResult("\n\n================================================"); var rootURL3 = "http://localhost:8080/LayoutTests/inspector/debugger3/"; addUISourceCode(rootURL3 + "hasOwnProperty/__proto__/constructor/foo.js", false); addUISourceCode(rootURL3 + "hasOwnProperty/__proto__/foo.js", false); addUISourceCode(rootURL3 + "hasOwnProperty/foo.js", false); - dumpNavigator(sourcesNavigatorView); + InspectorTest.dumpNavigatorViewInAllModes(sourcesNavigatorView); InspectorTest.addResult("\n\n================================================"); InspectorTest.addResult("Revealing all resources:"); for (var i = 0; i < uiSourceCodes.length; ++i) revealUISourceCode(uiSourceCodes[i]); - dumpNavigator(sourcesNavigatorView); - dumpNavigator(contentScriptsNavigatorView); + InspectorTest.dumpNavigatorViewInAllModes(sourcesNavigatorView); + InspectorTest.dumpNavigatorViewInAllModes(contentScriptsNavigatorView); InspectorTest.addResult("\n\n================================================"); InspectorTest.addResult("Removing all resources:"); InspectorTest.testNetworkProject._reset(target); - dumpNavigator(sourcesNavigatorView); - dumpNavigator(contentScriptsNavigatorView); + InspectorTest.dumpNavigatorViewInAllModes(sourcesNavigatorView); + InspectorTest.dumpNavigatorViewInAllModes(contentScriptsNavigatorView); InspectorTest.completeTest(); }
diff --git a/third_party/WebKit/LayoutTests/paint/lists/invalidate-list-marker-color-expected.html b/third_party/WebKit/LayoutTests/paint/lists/invalidate-list-marker-color-expected.html new file mode 100644 index 0000000..c8d3b75 --- /dev/null +++ b/third_party/WebKit/LayoutTests/paint/lists/invalidate-list-marker-color-expected.html
@@ -0,0 +1,11 @@ +<!doctype HTML> +<style> +ul { + color:black; + background:gray; +} +</style> +The test succeeds if the bullet is black. +<ul id='target'> + <li>Test</li> +</ul>
diff --git a/third_party/WebKit/LayoutTests/paint/lists/invalidate-list-marker-color.html b/third_party/WebKit/LayoutTests/paint/lists/invalidate-list-marker-color.html new file mode 100644 index 0000000..6f3a46b --- /dev/null +++ b/third_party/WebKit/LayoutTests/paint/lists/invalidate-list-marker-color.html
@@ -0,0 +1,25 @@ +<!doctype HTML> +<style> +ul { + color: white; + background:gray; +} +</style> +The test succeeds if the bullet is black. +<ul id='target'> + <li>Test</li> +</ul> +<script> + +if (window.testRunner) + window.testRunner.waitUntilDone(); + +onload = function() { + requestAnimationFrame(function() { + requestAnimationFrame(function() { + target.style.color = 'black'; + window.testRunner.notifyDone(); + }); + }); +}; +</script>
diff --git a/third_party/WebKit/LayoutTests/platform/android/css1/box_properties/float_on_text_elements-expected.png b/third_party/WebKit/LayoutTests/platform/android/css1/box_properties/float_on_text_elements-expected.png new file mode 100644 index 0000000..3f7cf98742 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/android/css1/box_properties/float_on_text_elements-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/css2.1/t0905-c5525-fltwidth-00-c-g-expected.png b/third_party/WebKit/LayoutTests/platform/android/css2.1/t0905-c5525-fltwidth-00-c-g-expected.png new file mode 100644 index 0000000..e6a7cc2f --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/android/css2.1/t0905-c5525-fltwidth-00-c-g-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/canvas/canvas-shadow-source-in-expected.txt b/third_party/WebKit/LayoutTests/platform/android/fast/canvas/canvas-shadow-source-in-expected.txt deleted file mode 100644 index a13484d9..0000000 --- a/third_party/WebKit/LayoutTests/platform/android/fast/canvas/canvas-shadow-source-in-expected.txt +++ /dev/null
@@ -1,21 +0,0 @@ -layer at (0,0) size 800x600 - LayoutView at (0,0) size 800x600 -layer at (0,0) size 800x470 - LayoutBlockFlow {HTML} at (0,0) size 800x470 - LayoutBlockFlow {BODY} at (8,8) size 784x454 - LayoutBlockFlow {DIV} at (0,0) size 784x20 - LayoutText {#text} at (0,0) size 57x19 - text run at (0,0) width 57: "Test Rect" - LayoutBlockFlow (anonymous) at (0,20) size 784x207 - LayoutText {#text} at (0,0) size 0x0 - LayoutBlockFlow {DIV} at (0,227) size 784x20 - LayoutText {#text} at (0,0) size 66x19 - text run at (0,0) width 66: "Test Image" - LayoutBlockFlow (anonymous) at (0,247) size 784x207 - LayoutText {#text} at (0,0) size 0x0 - LayoutText {#text} at (0,0) size 0x0 - LayoutText {#text} at (0,0) size 0x0 -layer at (8,28) size 202x202 - LayoutHTMLCanvas {CANVAS} at (0,0) size 202x202 [border: (1px solid #999999)] -layer at (8,255) size 202x202 - LayoutHTMLCanvas {CANVAS} at (0,0) size 202x202 [border: (1px solid #999999)]
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/canvas/canvas-toBlob-jpeg-maximum-quality-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/canvas/canvas-toBlob-jpeg-maximum-quality-expected.png deleted file mode 100644 index e374c1c5..0000000 --- a/third_party/WebKit/LayoutTests/platform/android/fast/canvas/canvas-toBlob-jpeg-maximum-quality-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/canvas/canvas-toBlob-jpeg-medium-quality-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/canvas/canvas-toBlob-jpeg-medium-quality-expected.png deleted file mode 100644 index 8019bf0..0000000 --- a/third_party/WebKit/LayoutTests/platform/android/fast/canvas/canvas-toBlob-jpeg-medium-quality-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/repaint/make-children-non-inline-expected.txt b/third_party/WebKit/LayoutTests/platform/android/fast/repaint/make-children-non-inline-expected.txt new file mode 100644 index 0000000..847a541 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/android/fast/repaint/make-children-non-inline-expected.txt
@@ -0,0 +1,99 @@ +{ + "bounds": [800, 600], + "children": [ + { + "bounds": [800, 600], + "contentsOpaque": true, + "drawsContent": true, + "repaintRects": [ + [8, 324, 61, 19], + [8, 304, 27, 19], + [8, 284, 65, 19], + [8, 264, 784, 80], + [8, 264, 106, 19], + [8, 224, 61, 19], + [8, 204, 27, 19], + [8, 184, 65, 19], + [8, 164, 106, 19], + [8, 164, 10, 100], + [8, 144, 77, 19], + [8, 124, 42, 19], + [8, 104, 77, 19], + [8, 84, 42, 19], + [8, 64, 784, 280], + [8, 64, 784, 180], + [8, 64, 784, 100], + [8, 64, 39, 19] + ], + "paintInvalidationClients": [ + "InlineTextBox 'Word,'", + "InlineTextBox '\n'", + "RootInlineBox", + "InlineTextBox 'words,'", + "InlineTextBox '\n'", + "RootInlineBox", + "InlineTextBox 'more words.'", + "InlineTextBox '\n'", + "RootInlineBox", + "InlineTextBox 'I could'", + "InlineTextBox '\n'", + "RootInlineBox", + "InlineTextBox 'write a book'", + "InlineTextBox '\n'", + "RootInlineBox", + "InlineTextBox 'about all the stuff'", + "InlineTextBox '\n'", + "RootInlineBox", + "InlineTextBox 'that comes'", + "InlineTextBox '\n'", + "RootInlineBox", + "InlineTextBox 'after'", + "InlineTextBox '\n'", + "RootInlineBox", + "InlineTextBox 'the break.'", + "RootInlineBox", + "LayoutBlockFlow DIV", + "LayoutBlockFlow (anonymous)", + "RootInlineBox", + "LayoutText #text", + "InlineTextBox 'Word,'", + "LayoutBR BR", + "InlineTextBox '\n'", + "LayoutText #text", + "InlineTextBox 'words,'", + "LayoutBR BR", + "InlineTextBox '\n'", + "LayoutText #text", + "InlineTextBox 'more words.'", + "LayoutBR BR", + "InlineTextBox '\n'", + "LayoutText #text", + "InlineTextBox 'I could'", + "LayoutBR BR", + "InlineTextBox '\n'", + "LayoutText #text", + "InlineTextBox 'write a book'", + "LayoutBR BR", + "InlineTextBox '\n'", + "LayoutBlockFlow DIV id='target'", + "LayoutBlockFlow (anonymous)", + "RootInlineBox", + "LayoutText #text", + "InlineTextBox 'about all the stuff'", + "LayoutBR BR", + "InlineTextBox '\n'", + "LayoutText #text", + "InlineTextBox 'that comes'", + "LayoutBR BR", + "InlineTextBox '\n'", + "LayoutText #text", + "InlineTextBox 'after'", + "LayoutBR BR", + "InlineTextBox '\n'", + "LayoutText #text", + "InlineTextBox 'the break.'" + ] + } + ] +} +
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/text/international/thai-line-breaks-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/text/international/thai-line-breaks-expected.png new file mode 100644 index 0000000..87846ec8 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/android/fast/text/international/thai-line-breaks-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/text/international/thai-line-breaks-expected.txt b/third_party/WebKit/LayoutTests/platform/android/fast/text/international/thai-line-breaks-expected.txt new file mode 100644 index 0000000..0d802192 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/android/fast/text/international/thai-line-breaks-expected.txt
@@ -0,0 +1,2618 @@ +layer at (0,0) size 800x600 clip at (0,0) size 785x600 scrollHeight 39994 + LayoutView at (0,0) size 800x600 +layer at (0,0) size 785x600 + LayoutBlockFlow {HTML} at (0,0) size 785x600 + LayoutBlockFlow {BODY} at (8,8) size 769x576 + LayoutBlockFlow {P} at (0,0) size 769x60 + LayoutText {#text} at (0,0) size 747x59 + text run at (0,0) width 747: "The column on the right has explicit spaces. Line breaks should be roughly the same if Thai line breaks are working well. The" + text run at (0,20) width 734: "original source of this text was ICU, and the test program said \"by it's very nature, Thai word breaking is not exact\", so the" + text run at (0,40) width 742: "columns don't match exactly. In a future version we might decide to tweak the right column to match our expected behavior." +layer at (236,84) size 1x38040 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600 + LayoutBlockFlow (positioned) {DIV} at (235.50,84) size 1x38040 + LayoutText {#text} at (0,6) size 84x38029 + text run at (0,6) width 21: "\x{E1A}\x{E17}" + text run at (0,36) width 49: "\x{E17}\x{E35}\x{E48}\x{E51}\x{E1E}\x{E32}\x{E22}\x{E38}" + text run at (0,66) width 54: "\x{E44}\x{E0B}\x{E42}\x{E04}\x{E25}\x{E19}" + text run at (0,96) width 17: "\x{E42}\x{E14}" + text run at (0,126) width 24: "\x{E42}\x{E23}\x{E18}\x{E35}" + text run at (0,156) width 36: "\x{E2D}\x{E32}\x{E28}\x{E31}\x{E22}" + text run at (0,186) width 19: "\x{E2D}\x{E22}\x{E39}\x{E48}" + text run at (0,216) width 63: "\x{E17}\x{E48}\x{E32}\x{E21}\x{E01}\x{E25}\x{E32}\x{E07}" + text run at (0,246) width 48: "\x{E17}\x{E38}\x{E48}\x{E07}\x{E43}\x{E2B}\x{E0D}\x{E48}" + text run at (0,276) width 17: "\x{E43}\x{E19}" + text run at (0,306) width 50: "\x{E41}\x{E04}\x{E19}\x{E0B}\x{E31}\x{E2A}" + text run at (0,336) width 20: "\x{E01}\x{E31}\x{E1A}" + text run at (0,366) width 17: "\x{E25}\x{E38}\x{E07}" + text run at (0,396) width 14: "\x{E40}\x{E2E}" + text run at (0,426) width 19: "\x{E19}\x{E23}\x{E35}" + text run at (0,456) width 41: "\x{E0A}\x{E32}\x{E27}\x{E44}\x{E23}\x{E48}" + text run at (0,486) width 27: "\x{E41}\x{E25}\x{E30}" + text run at (0,516) width 17: "\x{E1B}\x{E49}\x{E32}" + text run at (0,546) width 25: "\x{E40}\x{E2D}\x{E47}\x{E21}" + text run at (0,576) width 44: "\x{E20}\x{E23}\x{E23}\x{E22}\x{E32}" + text run at (0,606) width 41: "\x{E0A}\x{E32}\x{E27}\x{E44}\x{E23}\x{E48}" + text run at (0,636) width 28: "\x{E1A}\x{E49}\x{E32}\x{E19}" + text run at (0,666) width 27: "\x{E02}\x{E2D}\x{E07}" + text run at (0,696) width 30: "\x{E1E}\x{E27}\x{E01}" + text run at (0,726) width 22: "\x{E40}\x{E02}\x{E32}" + text run at (0,756) width 27: "\x{E2B}\x{E25}\x{E31}\x{E07}" + text run at (0,786) width 24: "\x{E40}\x{E25}\x{E47}\x{E01}" + text run at (0,816) width 39: "\x{E40}\x{E1E}\x{E23}\x{E32}\x{E30}" + text run at (0,846) width 18: "\x{E44}\x{E21}\x{E49}" + text run at (0,876) width 32: "\x{E2A}\x{E23}\x{E49}\x{E32}\x{E07}" + text run at (0,906) width 28: "\x{E1A}\x{E49}\x{E32}\x{E19}" + text run at (0,936) width 27: "\x{E15}\x{E49}\x{E2D}\x{E07}" + text run at (0,966) width 21: "\x{E02}\x{E19}" + text run at (0,996) width 18: "\x{E21}\x{E32}" + text run at (0,1026) width 29: "\x{E14}\x{E49}\x{E27}\x{E22}" + text run at (0,1056) width 45: "\x{E40}\x{E01}\x{E27}\x{E35}\x{E22}\x{E19}" + text run at (0,1086) width 26: "\x{E40}\x{E1B}\x{E47}\x{E19}" + text run at (0,1116) width 34: "\x{E23}\x{E30}\x{E22}\x{E30}" + text run at (0,1146) width 26: "\x{E17}\x{E32}\x{E07}" + text run at (0,1176) width 36: "\x{E2B}\x{E25}\x{E32}\x{E22}" + text run at (0,1206) width 27: "\x{E44}\x{E21}\x{E25}\x{E4C}" + text run at (0,1236) width 28: "\x{E1A}\x{E49}\x{E32}\x{E19}" + text run at (0,1266) width 11: "\x{E21}\x{E35}" + text run at (0,1296) width 9: "\x{E2A}\x{E35}\x{E48}" + text run at (0,1326) width 17: "\x{E1D}\x{E32}" + text run at (0,1356) width 11: "\x{E21}\x{E35}" + text run at (0,1386) width 22: "\x{E1E}\x{E37}\x{E49}\x{E19}" + text run at (0,1416) width 20: "\x{E01}\x{E31}\x{E1A}" + text run at (0,1446) width 44: "\x{E2B}\x{E25}\x{E31}\x{E07}\x{E04}\x{E32}" + text run at (0,1476) width 28: "\x{E23}\x{E27}\x{E21}" + text run at (0,1506) width 18: "\x{E17}\x{E33}" + text run at (0,1536) width 26: "\x{E40}\x{E1B}\x{E47}\x{E19}" + text run at (0,1566) width 27: "\x{E2B}\x{E49}\x{E2D}\x{E07}" + text run at (0,1596) width 34: "\x{E40}\x{E14}\x{E35}\x{E22}\x{E27}" + text run at (0,1626) width 17: "\x{E43}\x{E19}" + text run at (0,1656) width 27: "\x{E2B}\x{E49}\x{E2D}\x{E07}" + text run at (0,1686) width 11: "\x{E21}\x{E35}" + text run at (0,1716) width 19: "\x{E17}\x{E31}\x{E49}\x{E07}" + text run at (0,1746) width 22: "\x{E40}\x{E15}\x{E32}" + text run at (0,1776) width 18: "\x{E2B}\x{E38}\x{E07}" + text run at (0,1806) width 21: "\x{E15}\x{E49}\x{E21}" + text run at (0,1836) width 11: "\x{E17}\x{E35}\x{E48}" + text run at (0,1866) width 31: "\x{E2A}\x{E19}\x{E34}\x{E21}" + text run at (0,1896) width 10: "\x{E14}\x{E39}" + text run at (0,1926) width 21: "\x{E02}\x{E36}\x{E49}\x{E19}" + text run at (0,1956) width 31: "\x{E40}\x{E25}\x{E2D}\x{E30}" + text run at (0,1986) width 11: "\x{E21}\x{E35}" + text run at (0,2016) width 10: "\x{E15}\x{E39}\x{E49}" + text run at (0,2046) width 15: "\x{E43}\x{E2A}\x{E48}" + text run at (0,2076) width 29: "\x{E16}\x{E49}\x{E27}\x{E22}" + text run at (0,2106) width 28: "\x{E0A}\x{E32}\x{E21}" + text run at (0,2136) width 25: "\x{E42}\x{E15}\x{E4A}\x{E30}" + text run at (0,2166) width 31: "\x{E40}\x{E01}\x{E49}\x{E32}\x{E2D}\x{E35}\x{E49}" + text run at (0,2196) width 27: "\x{E2A}\x{E32}\x{E21}" + text run at (0,2226) width 27: "\x{E2B}\x{E23}\x{E37}\x{E2D}" + text run at (0,2256) width 9: "\x{E2A}\x{E35}\x{E48}" + text run at (0,2286) width 19: "\x{E15}\x{E31}\x{E27}" + text run at (0,2316) width 28: "\x{E41}\x{E25}\x{E49}\x{E27}" + text run at (0,2346) width 10: "\x{E01}\x{E47}" + text run at (0,2376) width 11: "\x{E21}\x{E35}" + text run at (0,2406) width 33: "\x{E40}\x{E15}\x{E35}\x{E22}\x{E07}" + text run at (0,2436) width 31: "\x{E19}\x{E2D}\x{E19}" + text run at (0,2466) width 17: "\x{E25}\x{E38}\x{E07}" + text run at (0,2496) width 14: "\x{E40}\x{E2E}" + text run at (0,2526) width 19: "\x{E19}\x{E23}\x{E35}" + text run at (0,2556) width 20: "\x{E01}\x{E31}\x{E1A}" + text run at (0,2586) width 17: "\x{E1B}\x{E49}\x{E32}" + text run at (0,2616) width 25: "\x{E40}\x{E2D}\x{E47}\x{E21}" + text run at (0,2646) width 11: "\x{E21}\x{E35}" + text run at (0,2676) width 33: "\x{E40}\x{E15}\x{E35}\x{E22}\x{E07}" + text run at (0,2706) width 31: "\x{E19}\x{E2D}\x{E19}" + text run at (0,2736) width 29: "\x{E43}\x{E2B}\x{E0D}\x{E48}" + text run at (0,2766) width 19: "\x{E2D}\x{E22}\x{E39}\x{E48}" + text run at (0,2796) width 11: "\x{E17}\x{E35}\x{E48}" + text run at (0,2826) width 22: "\x{E21}\x{E38}\x{E21}" + text run at (0,2856) width 29: "\x{E2B}\x{E19}\x{E36}\x{E48}\x{E07}" + text run at (0,2886) width 29: "\x{E2A}\x{E48}\x{E27}\x{E19}" + text run at (0,2916) width 17: "\x{E42}\x{E14}" + text run at (0,2946) width 15: "\x{E42}\x{E23}" + text run at (0,2976) width 20: "\x{E18}\x{E35}\x{E21}\x{E35}" + text run at (0,3006) width 33: "\x{E40}\x{E15}\x{E35}\x{E22}\x{E07}" + text run at (0,3036) width 24: "\x{E40}\x{E25}\x{E47}\x{E01}" + text run at (0,3066) width 19: "\x{E2D}\x{E35}\x{E01}" + text run at (0,3096) width 11: "\x{E17}\x{E35}\x{E48}" + text run at (0,3126) width 22: "\x{E21}\x{E38}\x{E21}" + text run at (0,3156) width 29: "\x{E2B}\x{E19}\x{E36}\x{E48}\x{E07}" + text run at (0,3186) width 29: "\x{E44}\x{E21}\x{E48}\x{E21}\x{E35}" + text run at (0,3216) width 27: "\x{E2B}\x{E49}\x{E2D}\x{E07}" + text run at (0,3246) width 16: "\x{E43}\x{E15}\x{E49}" + text run at (0,3276) width 44: "\x{E40}\x{E1E}\x{E14}\x{E32}\x{E19}" + text run at (0,3306) width 24: "\x{E40}\x{E25}\x{E22}" + text run at (0,3336) width 27: "\x{E2B}\x{E49}\x{E2D}\x{E07}" + text run at (0,3366) width 37: "\x{E43}\x{E15}\x{E49}\x{E16}\x{E38}\x{E19}" + text run at (0,3396) width 10: "\x{E01}\x{E47}" + text run at (0,3426) width 29: "\x{E44}\x{E21}\x{E48}\x{E21}\x{E35}" + text run at (0,3456) width 25: "\x{E40}\x{E27}\x{E49}\x{E19}" + text run at (0,3486) width 20: "\x{E41}\x{E15}\x{E48}" + text run at (0,3516) width 11: "\x{E21}\x{E35}" + text run at (0,3546) width 18: "\x{E42}\x{E1E}" + text run at (0,3576) width 16: "\x{E23}\x{E07}" + text run at (0,3606) width 33: "\x{E40}\x{E25}\x{E47}\x{E01}\x{E46}" + text run at (0,3636) width 11: "\x{E17}\x{E35}\x{E48}" + text run at (0,3666) width 20: "\x{E02}\x{E38}\x{E14}" + text run at (0,3696) width 17: "\x{E44}\x{E1B}" + text run at (0,3726) width 16: "\x{E43}\x{E15}\x{E49}" + text run at (0,3756) width 22: "\x{E1E}\x{E37}\x{E49}\x{E19}" + text run at (0,3786) width 33: "\x{E40}\x{E23}\x{E35}\x{E22}\x{E01}" + text run at (0,3816) width 16: "\x{E27}\x{E48}\x{E32}" + text run at (0,3846) width 39: "\"\x{E42}\x{E1E}\x{E23}\x{E07}" + text run at (0,3876) width 59: "\x{E44}\x{E0B}\x{E42}\x{E04}\x{E25}\x{E19}\"" + text run at (0,3906) width 26: "\x{E40}\x{E1B}\x{E47}\x{E19}" + text run at (0,3936) width 11: "\x{E17}\x{E35}\x{E48}" + text run at (0,3966) width 64: "\x{E04}\x{E23}\x{E2D}\x{E1A}\x{E04}\x{E23}\x{E31}\x{E27}" + text run at (0,3996) width 11: "\x{E19}\x{E35}\x{E49}" + text run at (0,4026) width 17: "\x{E08}\x{E30}" + text run at (0,4056) width 21: "\x{E21}\x{E38}\x{E14}" + text run at (0,4086) width 39: "\x{E40}\x{E02}\x{E49}\x{E32}\x{E44}\x{E1B}" + text run at (0,4116) width 25: "\x{E40}\x{E21}\x{E37}\x{E48}\x{E2D}" + text run at (0,4146) width 25: "\x{E40}\x{E01}\x{E34}\x{E14}" + text run at (0,4176) width 20: "\x{E25}\x{E21}" + text run at (0,4206) width 28: "\x{E21}\x{E2B}\x{E32}" + text run at (0,4236) width 21: "\x{E20}\x{E31}\x{E22}" + text run at (0,4266) width 18: "\x{E0B}\x{E36}\x{E48}\x{E07}" + text run at (0,4296) width 53: "\x{E01}\x{E23}\x{E30}\x{E42}\x{E0A}\x{E01}" + text run at (0,4326) width 26: "\x{E41}\x{E23}\x{E07}" + text run at (0,4356) width 20: "\x{E08}\x{E19}" + text run at (0,4386) width 40: "\x{E1A}\x{E14}\x{E02}\x{E22}\x{E35}\x{E49}" + text run at (0,4416) width 17: "\x{E2A}\x{E34}\x{E48}\x{E07}" + text run at (0,4446) width 19: "\x{E01}\x{E48}\x{E2D}" + text run at (0,4476) width 32: "\x{E2A}\x{E23}\x{E49}\x{E32}\x{E07}" + text run at (0,4506) width 25: "\x{E43}\x{E14}\x{E46}" + text run at (0,4536) width 11: "\x{E17}\x{E35}\x{E48}" + text run at (0,4566) width 34: "\x{E02}\x{E27}\x{E32}\x{E07}" + text run at (0,4596) width 26: "\x{E17}\x{E32}\x{E07}" + text run at (0,4626) width 22: "\x{E21}\x{E31}\x{E19}" + text run at (0,4656) width 17: "\x{E44}\x{E14}\x{E49}" + text run at (0,4686) width 26: "\x{E15}\x{E23}\x{E07}" + text run at (0,4716) width 34: "\x{E01}\x{E25}\x{E32}\x{E07}" + text run at (0,4746) width 22: "\x{E1E}\x{E37}\x{E49}\x{E19}" + text run at (0,4776) width 11: "\x{E21}\x{E35}" + text run at (0,4806) width 17: "\x{E1D}\x{E32}" + text run at (0,4836) width 25: "\x{E40}\x{E1B}\x{E34}\x{E14}" + text run at (0,4866) width 39: "\x{E40}\x{E02}\x{E49}\x{E32}\x{E44}\x{E1B}" + text run at (0,4896) width 26: "\x{E08}\x{E32}\x{E01}" + text run at (0,4926) width 22: "\x{E19}\x{E31}\x{E49}\x{E19}" + text run at (0,4956) width 11: "\x{E21}\x{E35}" + text run at (0,4986) width 38: "\x{E1A}\x{E31}\x{E19}\x{E44}\x{E14}" + text run at (0,5016) width 17: "\x{E25}\x{E07}" + text run at (0,5046) width 17: "\x{E44}\x{E1B}" + text run at (0,5076) width 18: "\x{E16}\x{E36}\x{E07}" + text run at (0,5106) width 34: "\x{E42}\x{E1E}\x{E23}\x{E07}" + text run at (0,5136) width 21: "\x{E21}\x{E37}\x{E14}" + text run at (0,5166) width 33: "\x{E40}\x{E25}\x{E47}\x{E01}\x{E46}" + text run at (0,5196) width 25: "\x{E40}\x{E21}\x{E37}\x{E48}\x{E2D}" + text run at (0,5226) width 17: "\x{E42}\x{E14}" + text run at (0,5256) width 24: "\x{E42}\x{E23}\x{E18}\x{E35}" + text run at (0,5286) width 21: "\x{E22}\x{E37}\x{E19}" + text run at (0,5316) width 11: "\x{E17}\x{E35}\x{E48}" + text run at (0,5346) width 27: "\x{E1B}\x{E32}\x{E01}" + text run at (0,5376) width 36: "\x{E1B}\x{E23}\x{E30}\x{E15}\x{E39}" + text run at (0,5406) width 27: "\x{E41}\x{E25}\x{E30}" + text run at (0,5436) width 28: "\x{E21}\x{E2D}\x{E07}" + text run at (0,5466) width 17: "\x{E44}\x{E1B}" + text run at (0,5496) width 36: "\x{E23}\x{E2D}\x{E1A}\x{E46}" + text run at (0,5526) width 23: "\x{E40}\x{E18}\x{E2D}" + text run at (0,5556) width 18: "\x{E44}\x{E21}\x{E48}" + text run at (0,5586) width 26: "\x{E40}\x{E2B}\x{E47}\x{E19}" + text run at (0,5616) width 32: "\x{E2D}\x{E30}\x{E44}\x{E23}" + text run at (0,5646) width 56: "\x{E19}\x{E2D}\x{E01}\x{E08}\x{E32}\x{E01}" + text run at (0,5676) width 28: "\x{E17}\x{E49}\x{E2D}\x{E07}" + text run at (0,5706) width 19: "\x{E17}\x{E38}\x{E48}\x{E07}" + text run at (0,5736) width 34: "\x{E01}\x{E27}\x{E49}\x{E32}\x{E07}" + text run at (0,5766) width 9: "\x{E2A}\x{E35}" + text run at (0,5796) width 23: "\x{E40}\x{E17}\x{E32}" + text run at (0,5826) width 32: "\x{E2B}\x{E21}\x{E48}\x{E19}" + text run at (0,5856) width 20: "\x{E17}\x{E31}\x{E48}\x{E27}" + text run at (0,5886) width 21: "\x{E17}\x{E38}\x{E01}" + text run at (0,5916) width 28: "\x{E14}\x{E49}\x{E32}\x{E19}" + text run at (0,5946) width 29: "\x{E44}\x{E21}\x{E48}\x{E21}\x{E35}" + text run at (0,5976) width 21: "\x{E41}\x{E21}\x{E49}" + text run at (0,6006) width 39: "\x{E15}\x{E49}\x{E19}\x{E44}\x{E21}\x{E49}" + text run at (0,6036) width 19: "\x{E2A}\x{E31}\x{E01}" + text run at (0,6066) width 21: "\x{E15}\x{E49}\x{E19}" + text run at (0,6096) width 27: "\x{E2B}\x{E23}\x{E37}\x{E2D}" + text run at (0,6126) width 28: "\x{E1A}\x{E49}\x{E32}\x{E19}" + text run at (0,6156) width 19: "\x{E2A}\x{E31}\x{E01}" + text run at (0,6186) width 27: "\x{E2B}\x{E25}\x{E31}\x{E07}" + text run at (0,6216) width 11: "\x{E17}\x{E35}\x{E48}" + text run at (0,6246) width 26: "\x{E42}\x{E1C}\x{E25}\x{E48}" + text run at (0,6276) width 22: "\x{E1E}\x{E49}\x{E19}" + text run at (0,6306) width 74: "\x{E20}\x{E39}\x{E21}\x{E34}\x{E1B}\x{E23}\x{E30}\x{E40}\x{E17}\x{E28}" + text run at (0,6336) width 20: "\x{E2D}\x{E31}\x{E19}" + text run at (0,6366) width 25: "\x{E23}\x{E32}\x{E1A}" + text run at (0,6396) width 33: "\x{E40}\x{E23}\x{E35}\x{E22}\x{E1A}" + text run at (0,6426) width 20: "\x{E41}\x{E1C}\x{E48}" + text run at (0,6456) width 17: "\x{E44}\x{E1B}" + text run at (0,6486) width 26: "\x{E44}\x{E01}\x{E25}" + text run at (0,6516) width 20: "\x{E08}\x{E19}" + text run at (0,6546) width 19: "\x{E08}\x{E14}" + text run at (0,6576) width 29: "\x{E02}\x{E2D}\x{E1A}" + text run at (0,6606) width 18: "\x{E1F}\x{E49}\x{E32}" + text run at (0,6636) width 20: "\x{E17}\x{E31}\x{E48}\x{E27}" + text run at (0,6666) width 21: "\x{E17}\x{E38}\x{E01}" + text run at (0,6696) width 21: "\x{E17}\x{E34}\x{E28}" + text run at (0,6726) width 65: "\x{E14}\x{E27}\x{E07}\x{E15}\x{E30}\x{E27}\x{E31}\x{E19}" + text run at (0,6756) width 22: "\x{E40}\x{E1C}\x{E32}" + text run at (0,6786) width 21: "\x{E1C}\x{E37}\x{E19}" + text run at (0,6816) width 21: "\x{E14}\x{E34}\x{E19}" + text run at (0,6846) width 11: "\x{E17}\x{E35}\x{E48}" + text run at (0,6876) width 17: "\x{E44}\x{E16}" + text run at (0,6906) width 28: "\x{E41}\x{E25}\x{E49}\x{E27}" + text run at (0,6936) width 20: "\x{E08}\x{E19}" + text run at (0,6966) width 36: "\x{E01}\x{E25}\x{E32}\x{E22}" + text run at (0,6996) width 26: "\x{E40}\x{E1B}\x{E47}\x{E19}" + text run at (0,7026) width 31: "\x{E41}\x{E1C}\x{E48}\x{E19}" + text run at (0,7056) width 39: "\x{E21}\x{E2B}\x{E36}\x{E21}\x{E32}" + text run at (0,7086) width 9: "\x{E2A}\x{E35}" + text run at (0,7116) width 17: "\x{E14}\x{E33}" + text run at (0,7146) width 11: "\x{E21}\x{E35}" + text run at (0,7176) width 27: "\x{E23}\x{E2D}\x{E22}" + text run at (0,7206) width 30: "\x{E41}\x{E15}\x{E01}" + text run at (0,7236) width 44: "\x{E23}\x{E30}\x{E41}\x{E2B}\x{E07}" + text run at (0,7266) width 19: "\x{E2D}\x{E22}\x{E39}\x{E48}" + text run at (0,7296) width 38: "\x{E15}\x{E25}\x{E2D}\x{E14}" + text run at (0,7326) width 41: "\x{E41}\x{E21}\x{E49}\x{E41}\x{E15}\x{E48}" + text run at (0,7356) width 30: "\x{E2B}\x{E0D}\x{E49}\x{E32}" + text run at (0,7386) width 10: "\x{E01}\x{E47}" + text run at (0,7416) width 18: "\x{E44}\x{E21}\x{E48}" + text run at (0,7446) width 34: "\x{E40}\x{E02}\x{E35}\x{E22}\x{E27}" + text run at (0,7476) width 39: "\x{E40}\x{E1E}\x{E23}\x{E32}\x{E30}" + text run at (0,7506) width 65: "\x{E14}\x{E27}\x{E07}\x{E15}\x{E30}\x{E27}\x{E31}\x{E19}" + text run at (0,7536) width 22: "\x{E40}\x{E1C}\x{E32}" + text run at (0,7566) width 29: "\x{E22}\x{E2D}\x{E14}" + text run at (0,7596) width 16: "\x{E43}\x{E1A}" + text run at (0,7626) width 26: "\x{E22}\x{E32}\x{E27}" + text run at (0,7656) width 24: "\x{E40}\x{E2A}\x{E35}\x{E22}" + text run at (0,7686) width 20: "\x{E08}\x{E19}" + text run at (0,7716) width 26: "\x{E40}\x{E1B}\x{E47}\x{E19}" + text run at (0,7746) width 9: "\x{E2A}\x{E35}" + text run at (0,7776) width 23: "\x{E40}\x{E17}\x{E32}" + text run at (0,7806) width 32: "\x{E2B}\x{E21}\x{E48}\x{E19}" + text run at (0,7836) width 28: "\x{E21}\x{E2D}\x{E07}" + text run at (0,7866) width 26: "\x{E40}\x{E2B}\x{E47}\x{E19}" + text run at (0,7896) width 19: "\x{E2D}\x{E22}\x{E39}\x{E48}" + text run at (0,7926) width 37: "\x{E17}\x{E31}\x{E48}\x{E27}\x{E44}\x{E1B}" + text run at (0,7956) width 26: "\x{E04}\x{E23}\x{E31}\x{E49}\x{E07}" + text run at (0,7986) width 29: "\x{E2B}\x{E19}\x{E36}\x{E48}\x{E07}" + text run at (0,8016) width 25: "\x{E40}\x{E04}\x{E22}" + text run at (0,8046) width 27: "\x{E17}\x{E32}\x{E2A}\x{E35}" + text run at (0,8076) width 28: "\x{E1A}\x{E49}\x{E32}\x{E19}" + text run at (0,8106) width 21: "\x{E40}\x{E2D}\x{E32}" + text run at (0,8136) width 16: "\x{E44}\x{E27}\x{E49}" + text run at (0,8166) width 20: "\x{E41}\x{E15}\x{E48}" + text run at (0,8196) width 10: "\x{E01}\x{E47}" + text run at (0,8226) width 20: "\x{E16}\x{E39}\x{E01}" + text run at (0,8256) width 65: "\x{E14}\x{E27}\x{E07}\x{E15}\x{E30}\x{E27}\x{E31}\x{E19}" + text run at (0,8286) width 22: "\x{E40}\x{E1C}\x{E32}" + text run at (0,8316) width 24: "\x{E40}\x{E2A}\x{E35}\x{E22}" + text run at (0,8346) width 20: "\x{E08}\x{E19}" + text run at (0,8376) width 9: "\x{E2A}\x{E35}" + text run at (0,8406) width 28: "\x{E1E}\x{E2D}\x{E07}" + text run at (0,8436) width 28: "\x{E41}\x{E25}\x{E49}\x{E27}" + text run at (0,8466) width 21: "\x{E1D}\x{E19}" + text run at (0,8496) width 10: "\x{E01}\x{E47}" + text run at (0,8526) width 18: "\x{E0A}\x{E30}" + text run at (0,8556) width 22: "\x{E21}\x{E31}\x{E19}" + text run at (0,8586) width 29: "\x{E2B}\x{E25}\x{E38}\x{E14}" + text run at (0,8616) width 17: "\x{E44}\x{E1B}" + text run at (0,8646) width 20: "\x{E08}\x{E19}" + text run at (0,8676) width 31: "\x{E2B}\x{E21}\x{E14}" + text run at (0,8706) width 27: "\x{E41}\x{E25}\x{E30}" + text run at (0,8736) width 30: "\x{E15}\x{E2D}\x{E19}" + text run at (0,8766) width 11: "\x{E19}\x{E35}\x{E49}" + text run at (0,8796) width 28: "\x{E1A}\x{E49}\x{E32}\x{E19}" + text run at (0,8826) width 17: "\x{E08}\x{E36}\x{E07}" + text run at (0,8856) width 10: "\x{E14}\x{E39}" + text run at (0,8886) width 70: "\x{E2B}\x{E21}\x{E48}\x{E19}\x{E2B}\x{E21}\x{E2D}\x{E07}" + text run at (0,8916) width 26: "\x{E40}\x{E1B}\x{E47}\x{E19}" + text run at (0,8946) width 9: "\x{E2A}\x{E35}" + text run at (0,8976) width 23: "\x{E40}\x{E17}\x{E32}" + text run at (0,9006) width 46: "\x{E40}\x{E2B}\x{E21}\x{E37}\x{E2D}\x{E19}" + text run at (0,9036) width 17: "\x{E2A}\x{E34}\x{E48}\x{E07}" + text run at (0,9066) width 29: "\x{E2D}\x{E37}\x{E48}\x{E19}\x{E46}" + text run at (0,9096) width 29: "\x{E14}\x{E49}\x{E27}\x{E22}" + text run at (0,9126) width 30: "\x{E15}\x{E2D}\x{E19}" + text run at (0,9156) width 11: "\x{E17}\x{E35}\x{E48}" + text run at (0,9186) width 17: "\x{E1B}\x{E49}\x{E32}" + text run at (0,9216) width 25: "\x{E40}\x{E2D}\x{E47}\x{E21}" + text run at (0,9246) width 27: "\x{E22}\x{E49}\x{E32}\x{E22}" + text run at (0,9276) width 18: "\x{E21}\x{E32}" + text run at (0,9306) width 19: "\x{E2D}\x{E22}\x{E39}\x{E48}" + text run at (0,9336) width 11: "\x{E17}\x{E35}\x{E48}" + text run at (0,9366) width 11: "\x{E19}\x{E35}\x{E48}" + text run at (0,9396) width 23: "\x{E40}\x{E18}\x{E2D}" + text run at (0,9426) width 18: "\x{E22}\x{E31}\x{E07}" + text run at (0,9456) width 25: "\x{E2A}\x{E32}\x{E27}" + text run at (0,9486) width 26: "\x{E40}\x{E1B}\x{E47}\x{E19}" + text run at (0,9516) width 44: "\x{E20}\x{E23}\x{E23}\x{E22}\x{E32}" + text run at (0,9546) width 11: "\x{E17}\x{E35}\x{E48}" + text run at (0,9576) width 44: "\x{E07}\x{E14}\x{E07}\x{E32}\x{E21}" + text run at (0,9606) width 28: "\x{E41}\x{E25}\x{E49}\x{E27}" + text run at (0,9636) width 30: "\x{E41}\x{E14}\x{E14}" + text run at (0,9666) width 27: "\x{E41}\x{E25}\x{E30}" + text run at (0,9696) width 20: "\x{E25}\x{E21}" + text run at (0,9726) width 27: "\x{E01}\x{E47}\x{E44}\x{E14}\x{E49}" + text run at (0,9756) width 45: "\x{E40}\x{E1B}\x{E25}\x{E35}\x{E48}\x{E22}\x{E19}" + text run at (0,9786) width 23: "\x{E40}\x{E18}\x{E2D}" + text run at (0,9816) width 17: "\x{E44}\x{E1B}" + text run at (0,9846) width 21: "\x{E40}\x{E2D}\x{E32}" + text run at (0,9876) width 53: "\x{E1B}\x{E23}\x{E30}\x{E01}\x{E32}\x{E22}" + text run at (0,9906) width 17: "\x{E44}\x{E1B}" + text run at (0,9936) width 26: "\x{E08}\x{E32}\x{E01}" + text run at (0,9966) width 44: "\x{E14}\x{E27}\x{E07}\x{E15}\x{E32}" + text run at (0,9996) width 23: "\x{E40}\x{E18}\x{E2D}" + text run at (0,10026) width 38: "\x{E1B}\x{E25}\x{E48}\x{E2D}\x{E22}" + text run at (0,10056) width 16: "\x{E44}\x{E27}\x{E49}" + text run at (0,10086) width 20: "\x{E41}\x{E15}\x{E48}" + text run at (0,10116) width 37: "\x{E04}\x{E27}\x{E32}\x{E21}" + text run at (0,10146) width 30: "\x{E2A}\x{E38}\x{E02}\x{E38}\x{E21}" + text run at (0,10176) width 34: "\x{E2D}\x{E22}\x{E48}\x{E32}\x{E07}" + text run at (0,10206) width 70: "\x{E2B}\x{E21}\x{E48}\x{E19}\x{E2B}\x{E21}\x{E2D}\x{E07}" + text run at (0,10236) width 21: "\x{E40}\x{E2D}\x{E32}" + text run at (0,10266) width 9: "\x{E2A}\x{E35}" + text run at (0,10296) width 28: "\x{E41}\x{E14}\x{E07}" + text run at (0,10326) width 26: "\x{E08}\x{E32}\x{E01}" + text run at (0,10356) width 31: "\x{E41}\x{E01}\x{E49}\x{E21}" + text run at (0,10386) width 27: "\x{E41}\x{E25}\x{E30}" + text run at (0,10416) width 19: "\x{E23}\x{E34}\x{E21}" + text run at (0,10446) width 37: "\x{E1D}\x{E35}\x{E1B}\x{E32}\x{E01}" + text run at (0,10476) width 23: "\x{E40}\x{E18}\x{E2D}" + text run at (0,10506) width 17: "\x{E44}\x{E1B}" + text run at (0,10536) width 36: "\x{E01}\x{E25}\x{E32}\x{E22}" + text run at (0,10566) width 26: "\x{E40}\x{E1B}\x{E47}\x{E19}" + text run at (0,10596) width 9: "\x{E2A}\x{E35}" + text run at (0,10626) width 41: "\x{E2B}\x{E21}\x{E48}\x{E19}\x{E46}" + text run at (0,10656) width 46: "\x{E40}\x{E2B}\x{E21}\x{E37}\x{E2D}\x{E19}" + text run at (0,10686) width 21: "\x{E01}\x{E31}\x{E19}" + text run at (0,10716) width 23: "\x{E40}\x{E18}\x{E2D}" + text run at (0,10746) width 30: "\x{E1C}\x{E2D}\x{E21}" + text run at (0,10776) width 27: "\x{E41}\x{E25}\x{E30}" + text run at (0,10806) width 27: "\x{E2B}\x{E25}\x{E31}\x{E07}" + text run at (0,10836) width 25: "\x{E42}\x{E04}\x{E49}\x{E07}" + text run at (0,10866) width 27: "\x{E41}\x{E25}\x{E30}" + text run at (0,10896) width 34: "\x{E40}\x{E14}\x{E35}\x{E4B}\x{E22}\x{E27}" + text run at (0,10926) width 11: "\x{E19}\x{E35}\x{E49}" + text run at (0,10956) width 18: "\x{E44}\x{E21}\x{E48}" + text run at (0,10986) width 25: "\x{E40}\x{E04}\x{E22}" + text run at (0,11016) width 21: "\x{E22}\x{E34}\x{E49}\x{E21}" + text run at (0,11046) width 24: "\x{E40}\x{E25}\x{E22}" + text run at (0,11076) width 25: "\x{E40}\x{E21}\x{E37}\x{E48}\x{E2D}" + text run at (0,11106) width 17: "\x{E42}\x{E14}" + text run at (0,11136) width 24: "\x{E42}\x{E23}\x{E18}\x{E35}" + text run at (0,11166) width 18: "\x{E0B}\x{E36}\x{E48}\x{E07}" + text run at (0,11196) width 26: "\x{E40}\x{E1B}\x{E47}\x{E19}" + text run at (0,11226) width 25: "\x{E40}\x{E14}\x{E47}\x{E01}" + text run at (0,11256) width 43: "\x{E01}\x{E33}\x{E1E}\x{E23}\x{E49}\x{E32}" + text run at (0,11286) width 18: "\x{E21}\x{E32}" + text run at (0,11316) width 19: "\x{E2D}\x{E22}\x{E39}\x{E48}" + text run at (0,11346) width 20: "\x{E01}\x{E31}\x{E1A}" + text run at (0,11376) width 23: "\x{E40}\x{E18}\x{E2D}" + text run at (0,11406) width 30: "\x{E15}\x{E2D}\x{E19}" + text run at (0,11436) width 28: "\x{E41}\x{E23}\x{E01}" + text run at (0,11466) width 17: "\x{E1B}\x{E49}\x{E32}" + text run at (0,11496) width 25: "\x{E40}\x{E2D}\x{E47}\x{E21}" + text run at (0,11526) width 21: "\x{E15}\x{E37}\x{E48}\x{E19}" + text run at (0,11556) width 26: "\x{E40}\x{E15}\x{E49}\x{E19}" + text run at (0,11586) width 20: "\x{E01}\x{E31}\x{E1A}" + text run at (0,11616) width 32: "\x{E40}\x{E2A}\x{E35}\x{E22}\x{E07}" + text run at (0,11646) width 47: "\x{E2B}\x{E31}\x{E27}\x{E40}\x{E23}\x{E32}\x{E30}" + text run at (0,11676) width 27: "\x{E02}\x{E2D}\x{E07}" + text run at (0,11706) width 25: "\x{E40}\x{E14}\x{E47}\x{E01}" + text run at (0,11736) width 30: "\x{E19}\x{E49}\x{E2D}\x{E22}" + text run at (0,11766) width 28: "\x{E21}\x{E32}\x{E01}" + text run at (0,11796) width 23: "\x{E40}\x{E18}\x{E2D}" + text run at (0,11826) width 17: "\x{E08}\x{E30}" + text run at (0,11856) width 17: "\x{E2A}\x{E48}\x{E07}" + text run at (0,11886) width 32: "\x{E40}\x{E2A}\x{E35}\x{E22}\x{E07}" + text run at (0,11916) width 25: "\x{E23}\x{E49}\x{E2D}\x{E07}" + text run at (0,11946) width 28: "\x{E41}\x{E25}\x{E49}\x{E27}" + text run at (0,11976) width 21: "\x{E40}\x{E2D}\x{E32}" + text run at (0,12006) width 20: "\x{E21}\x{E37}\x{E2D}" + text run at (0,12036) width 28: "\x{E17}\x{E32}\x{E1A}" + text run at (0,12066) width 19: "\x{E2D}\x{E01}" + text run at (0,12096) width 21: "\x{E17}\x{E38}\x{E01}" + text run at (0,12126) width 26: "\x{E04}\x{E23}\x{E31}\x{E49}\x{E07}" + text run at (0,12156) width 11: "\x{E17}\x{E35}\x{E48}" + text run at (0,12186) width 32: "\x{E40}\x{E2A}\x{E35}\x{E22}\x{E07}" + text run at (0,12216) width 20: "\x{E2D}\x{E31}\x{E19}" + text run at (0,12246) width 36: "\x{E23}\x{E48}\x{E32}\x{E40}\x{E23}\x{E34}\x{E07}" + text run at (0,12276) width 27: "\x{E02}\x{E2D}\x{E07}" + text run at (0,12306) width 17: "\x{E42}\x{E14}" + text run at (0,12336) width 24: "\x{E42}\x{E23}\x{E18}\x{E35}" + text run at (0,12366) width 32: "\x{E40}\x{E02}\x{E49}\x{E32}\x{E2B}\x{E39}" + text run at (0,12396) width 23: "\x{E40}\x{E18}\x{E2D}" + text run at (0,12426) width 27: "\x{E41}\x{E25}\x{E30}" + text run at (0,12456) width 23: "\x{E40}\x{E18}\x{E2D}" + text run at (0,12486) width 22: "\x{E40}\x{E1D}\x{E49}\x{E32}" + text run at (0,12516) width 28: "\x{E21}\x{E2D}\x{E07}" + text run at (0,12546) width 25: "\x{E40}\x{E14}\x{E47}\x{E01}" + text run at (0,12576) width 31: "\x{E2B}\x{E0D}\x{E34}\x{E07}" + text run at (0,12606) width 39: "\x{E19}\x{E49}\x{E2D}\x{E22}\x{E46}" + text run at (0,12636) width 29: "\x{E14}\x{E49}\x{E27}\x{E22}" + text run at (0,12666) width 37: "\x{E04}\x{E27}\x{E32}\x{E21}" + text run at (0,12696) width 62: "\x{E1B}\x{E23}\x{E30}\x{E2B}\x{E25}\x{E32}\x{E14}" + text run at (0,12726) width 15: "\x{E43}\x{E08}" + text run at (0,12756) width 29: "\x{E14}\x{E49}\x{E27}\x{E22}" + text run at (0,12786) width 18: "\x{E22}\x{E31}\x{E07}" + text run at (0,12816) width 17: "\x{E2B}\x{E32}" + text run at (0,12846) width 32: "\x{E2D}\x{E30}\x{E44}\x{E23}" + text run at (0,12876) width 18: "\x{E21}\x{E32}" + text run at (0,12906) width 26: "\x{E40}\x{E1B}\x{E47}\x{E19}" + text run at (0,12936) width 30: "\x{E40}\x{E23}\x{E37}\x{E48}\x{E2D}\x{E07}" + text run at (0,12966) width 47: "\x{E2B}\x{E31}\x{E27}\x{E40}\x{E23}\x{E32}\x{E30}" + text run at (0,12996) width 17: "\x{E44}\x{E14}\x{E49}" + text run at (0,13026) width 17: "\x{E25}\x{E38}\x{E07}" + text run at (0,13056) width 14: "\x{E40}\x{E2E}" + text run at (0,13086) width 19: "\x{E19}\x{E23}\x{E35}" + text run at (0,13116) width 18: "\x{E44}\x{E21}\x{E48}" + text run at (0,13146) width 25: "\x{E40}\x{E04}\x{E22}" + text run at (0,13176) width 47: "\x{E2B}\x{E31}\x{E27}\x{E40}\x{E23}\x{E32}\x{E30}" + text run at (0,13206) width 17: "\x{E25}\x{E38}\x{E07}" + text run at (0,13236) width 44: "\x{E17}\x{E33}\x{E07}\x{E32}\x{E19}" + text run at (0,13266) width 31: "\x{E2B}\x{E19}\x{E31}\x{E01}" + text run at (0,13296) width 26: "\x{E08}\x{E32}\x{E01}" + text run at (0,13326) width 22: "\x{E40}\x{E0A}\x{E49}\x{E32}" + text run at (0,13356) width 21: "\x{E22}\x{E31}\x{E19}" + text run at (0,13386) width 17: "\x{E04}\x{E48}\x{E33}" + text run at (0,13416) width 27: "\x{E41}\x{E25}\x{E30}" + text run at (0,13446) width 18: "\x{E44}\x{E21}\x{E48}" + text run at (0,13476) width 25: "\x{E40}\x{E04}\x{E22}" + text run at (0,13506) width 27: "\x{E23}\x{E39}\x{E49}\x{E08}\x{E31}\x{E01}" + text run at (0,13536) width 16: "\x{E27}\x{E48}\x{E32}" + text run at (0,13566) width 37: "\x{E04}\x{E27}\x{E32}\x{E21}" + text run at (0,13596) width 36: "\x{E23}\x{E48}\x{E32}\x{E40}\x{E23}\x{E34}\x{E07}" + text run at (0,13626) width 19: "\x{E04}\x{E37}\x{E2D}" + text run at (0,13656) width 32: "\x{E2D}\x{E30}\x{E44}\x{E23}" + text run at (0,13686) width 17: "\x{E25}\x{E38}\x{E07}" + text run at (0,13716) width 10: "\x{E14}\x{E39}" + text run at (0,13746) width 70: "\x{E2B}\x{E21}\x{E48}\x{E19}\x{E2B}\x{E21}\x{E2D}\x{E07}" + text run at (0,13776) width 17: "\x{E44}\x{E1B}" + text run at (0,13806) width 31: "\x{E2B}\x{E21}\x{E14}" + text run at (0,13836) width 38: "\x{E15}\x{E31}\x{E49}\x{E07}\x{E41}\x{E15}\x{E48}" + text run at (0,13866) width 30: "\x{E40}\x{E04}\x{E23}\x{E32}" + text run at (0,13896) width 26: "\x{E22}\x{E32}\x{E27}" + text run at (0,13926) width 20: "\x{E08}\x{E19}" + text run at (0,13956) width 19: "\x{E08}\x{E14}" + text run at (0,13986) width 48: "\x{E23}\x{E2D}\x{E07}\x{E40}\x{E17}\x{E49}\x{E32}" + text run at (0,14016) width 20: "\x{E1A}\x{E39}\x{E15}" + text run at (0,14046) width 20: "\x{E2D}\x{E31}\x{E19}" + text run at (0,14076) width 37: "\x{E2B}\x{E22}\x{E32}\x{E1A}" + text run at (0,14106) width 28: "\x{E41}\x{E25}\x{E49}\x{E27}" + text run at (0,14136) width 17: "\x{E25}\x{E38}\x{E07}" + text run at (0,14166) width 10: "\x{E01}\x{E47}" + text run at (0,14196) width 10: "\x{E14}\x{E39}" + text run at (0,14226) width 60: "\x{E40}\x{E04}\x{E23}\x{E48}\x{E07}\x{E02}\x{E23}\x{E36}\x{E21}" + text run at (0,14256) width 18: "\x{E19}\x{E48}\x{E32}" + text run at (0,14286) width 31: "\x{E40}\x{E01}\x{E23}\x{E07}" + text run at (0,14316) width 28: "\x{E02}\x{E32}\x{E21}" + text run at (0,14346) width 18: "\x{E44}\x{E21}\x{E48}" + text run at (0,14376) width 29: "\x{E04}\x{E48}\x{E2D}\x{E22}" + text run at (0,14406) width 17: "\x{E08}\x{E30}" + text run at (0,14436) width 21: "\x{E1E}\x{E39}\x{E14}" + text run at (0,14466) width 11: "\x{E21}\x{E35}" + text run at (0,14496) width 17: "\x{E42}\x{E15}" + text run at (0,14526) width 17: "\x{E42}\x{E15}\x{E49}" + text run at (0,14556) width 11: "\x{E17}\x{E35}\x{E48}" + text run at (0,14586) width 34: "\x{E17}\x{E33}\x{E43}\x{E2B}\x{E49}" + text run at (0,14616) width 17: "\x{E42}\x{E14}" + text run at (0,14646) width 24: "\x{E42}\x{E23}\x{E18}\x{E35}" + text run at (0,14676) width 47: "\x{E2B}\x{E31}\x{E27}\x{E40}\x{E23}\x{E32}\x{E30}" + text run at (0,14706) width 17: "\x{E44}\x{E14}\x{E49}" + text run at (0,14736) width 27: "\x{E41}\x{E25}\x{E30}" + text run at (0,14766) width 29: "\x{E0A}\x{E48}\x{E27}\x{E22}" + text run at (0,14796) width 23: "\x{E40}\x{E18}\x{E2D}" + text run at (0,14826) width 16: "\x{E43}\x{E2B}\x{E49}" + text run at (0,14856) width 22: "\x{E1E}\x{E49}\x{E19}" + text run at (0,14886) width 26: "\x{E08}\x{E32}\x{E01}" + text run at (0,14916) width 35: "\x{E01}\x{E32}\x{E23}\x{E01}" + text run at (0,14946) width 26: "\x{E25}\x{E32}\x{E22}" + text run at (0,14976) width 26: "\x{E40}\x{E1B}\x{E47}\x{E19}" + text run at (0,15006) width 9: "\x{E2A}\x{E35}" + text run at (0,15036) width 23: "\x{E40}\x{E17}\x{E32}" + text run at (0,15066) width 32: "\x{E2B}\x{E21}\x{E48}\x{E19}" + text run at (0,15096) width 46: "\x{E40}\x{E2B}\x{E21}\x{E37}\x{E2D}\x{E19}" + text run at (0,15126) width 20: "\x{E01}\x{E31}\x{E1A}" + text run at (0,15156) width 17: "\x{E2A}\x{E34}\x{E48}\x{E07}" + text run at (0,15186) width 27: "\x{E23}\x{E2D}\x{E1A}" + text run at (0,15216) width 19: "\x{E15}\x{E31}\x{E27}" + text run at (0,15246) width 29: "\x{E2D}\x{E37}\x{E48}\x{E19}\x{E46}" + text run at (0,15276) width 17: "\x{E42}\x{E15}" + text run at (0,15306) width 17: "\x{E42}\x{E15}\x{E49}" + text run at (0,15336) width 9: "\x{E2A}\x{E35}" + text run at (0,15366) width 18: "\x{E44}\x{E21}\x{E48}" + text run at (0,15396) width 23: "\x{E40}\x{E17}\x{E32}" + text run at (0,15426) width 32: "\x{E2B}\x{E21}\x{E48}\x{E19}" + text run at (0,15456) width 20: "\x{E41}\x{E15}\x{E48}" + text run at (0,15486) width 22: "\x{E21}\x{E31}\x{E19}" + text run at (0,15516) width 26: "\x{E40}\x{E1B}\x{E47}\x{E19}" + text run at (0,15546) width 28: "\x{E2B}\x{E21}\x{E32}" + text run at (0,15576) width 9: "\x{E2A}\x{E35}" + text run at (0,15606) width 17: "\x{E14}\x{E33}" + text run at (0,15636) width 19: "\x{E15}\x{E31}\x{E27}" + text run at (0,15666) width 39: "\x{E19}\x{E49}\x{E2D}\x{E22}\x{E46}" + text run at (0,15696) width 21: "\x{E02}\x{E19}" + text run at (0,15726) width 26: "\x{E22}\x{E32}\x{E27}" + text run at (0,15756) width 20: "\x{E1B}\x{E38}\x{E22}" + text run at (0,15786) width 44: "\x{E23}\x{E32}\x{E27}\x{E01}\x{E31}\x{E1A}" + text run at (0,15816) width 28: "\x{E44}\x{E2B}\x{E21}" + text run at (0,15846) width 11: "\x{E21}\x{E35}" + text run at (0,15876) width 17: "\x{E15}\x{E32}" + text run at (0,15906) width 17: "\x{E14}\x{E33}" + text run at (0,15936) width 24: "\x{E40}\x{E25}\x{E47}\x{E01}" + text run at (0,15966) width 26: "\x{E40}\x{E1B}\x{E47}\x{E19}" + text run at (0,15996) width 53: "\x{E1B}\x{E23}\x{E30}\x{E01}\x{E32}\x{E22}" + text run at (0,16026) width 40: "\x{E23}\x{E37}\x{E48}\x{E19}\x{E40}\x{E23}\x{E34}\x{E07}" + text run at (0,16056) width 19: "\x{E2D}\x{E22}\x{E39}\x{E48}" + text run at (0,16086) width 26: "\x{E2A}\x{E2D}\x{E07}" + text run at (0,16116) width 25: "\x{E02}\x{E49}\x{E32}\x{E07}" + text run at (0,16146) width 30: "\x{E08}\x{E21}\x{E39}\x{E01}" + text run at (0,16176) width 24: "\x{E40}\x{E25}\x{E47}\x{E01}" + text run at (0,16206) width 20: "\x{E2D}\x{E31}\x{E19}" + text run at (0,16236) width 18: "\x{E19}\x{E48}\x{E32}" + text run at (0,16266) width 21: "\x{E02}\x{E31}\x{E19}" + text run at (0,16296) width 27: "\x{E02}\x{E2D}\x{E07}" + text run at (0,16326) width 22: "\x{E21}\x{E31}\x{E19}" + text run at (0,16356) width 17: "\x{E42}\x{E15}" + text run at (0,16386) width 17: "\x{E42}\x{E15}\x{E49}" + text run at (0,16416) width 25: "\x{E40}\x{E25}\x{E48}\x{E19}" + text run at (0,16446) width 19: "\x{E17}\x{E31}\x{E49}\x{E07}" + text run at (0,16476) width 20: "\x{E27}\x{E31}\x{E19}" + text run at (0,16506) width 27: "\x{E41}\x{E25}\x{E30}" + text run at (0,16536) width 17: "\x{E42}\x{E14}" + text run at (0,16566) width 24: "\x{E42}\x{E23}\x{E18}\x{E35}" + text run at (0,16596) width 10: "\x{E01}\x{E47}" + text run at (0,16626) width 25: "\x{E40}\x{E25}\x{E48}\x{E19}" + text run at (0,16656) width 20: "\x{E01}\x{E31}\x{E1A}" + text run at (0,16686) width 22: "\x{E21}\x{E31}\x{E19}" + text run at (0,16716) width 27: "\x{E41}\x{E25}\x{E30}" + text run at (0,16746) width 18: "\x{E23}\x{E31}\x{E01}" + text run at (0,16776) width 22: "\x{E21}\x{E31}\x{E19}" + text run at (0,16806) width 33: "\x{E40}\x{E2B}\x{E25}\x{E37}\x{E2D}" + text run at (0,16836) width 26: "\x{E40}\x{E01}\x{E34}\x{E19}" + text run at (0,16866) width 49: "\x{E2D}\x{E22}\x{E48}\x{E32}\x{E07}\x{E44}\x{E23}" + text run at (0,16896) width 38: "\x{E01}\x{E47}\x{E15}\x{E32}\x{E21}" + text run at (0,16926) width 20: "\x{E27}\x{E31}\x{E19}" + text run at (0,16956) width 11: "\x{E19}\x{E35}\x{E49}" + text run at (0,16986) width 19: "\x{E17}\x{E31}\x{E49}\x{E07}" + text run at (0,17016) width 10: "\x{E04}\x{E39}\x{E48}" + text run at (0,17046) width 18: "\x{E44}\x{E21}\x{E48}" + text run at (0,17076) width 17: "\x{E44}\x{E14}\x{E49}" + text run at (0,17106) width 25: "\x{E40}\x{E25}\x{E48}\x{E19}" + text run at (0,17136) width 17: "\x{E25}\x{E38}\x{E07}" + text run at (0,17166) width 14: "\x{E40}\x{E2E}" + text run at (0,17196) width 19: "\x{E19}\x{E23}\x{E35}" + text run at (0,17226) width 19: "\x{E19}\x{E31}\x{E48}\x{E07}" + text run at (0,17256) width 19: "\x{E2D}\x{E22}\x{E39}\x{E48}" + text run at (0,17286) width 11: "\x{E17}\x{E35}\x{E48}" + text run at (0,17316) width 38: "\x{E1A}\x{E31}\x{E19}\x{E44}\x{E14}" + text run at (0,17346) width 36: "\x{E1B}\x{E23}\x{E30}\x{E15}\x{E39}" + text run at (0,17376) width 27: "\x{E41}\x{E25}\x{E30}" + text run at (0,17406) width 22: "\x{E40}\x{E1D}\x{E49}\x{E32}" + text run at (0,17436) width 36: "\x{E01}\x{E31}\x{E07}\x{E27}\x{E25}" + text run at (0,17466) width 26: "\x{E08}\x{E49}\x{E2D}\x{E07}" + text run at (0,17496) width 10: "\x{E14}\x{E39}" + text run at (0,17526) width 46: "\x{E17}\x{E49}\x{E2D}\x{E07}\x{E1F}\x{E49}\x{E32}" + text run at (0,17556) width 9: "\x{E2A}\x{E35}" + text run at (0,17586) width 23: "\x{E40}\x{E17}\x{E32}" + text run at (0,17616) width 32: "\x{E2B}\x{E21}\x{E48}\x{E19}" + text run at (0,17646) width 20: "\x{E1C}\x{E34}\x{E14}" + text run at (0,17676) width 30: "\x{E1B}\x{E01}\x{E15}\x{E34}" + text run at (0,17706) width 17: "\x{E42}\x{E14}" + text run at (0,17736) width 24: "\x{E42}\x{E23}\x{E18}\x{E35}" + text run at (0,17766) width 21: "\x{E22}\x{E37}\x{E19}" + text run at (0,17796) width 11: "\x{E17}\x{E35}\x{E48}" + text run at (0,17826) width 36: "\x{E1B}\x{E23}\x{E30}\x{E15}\x{E39}" + text run at (0,17856) width 29: "\x{E01}\x{E2D}\x{E14}" + text run at (0,17886) width 17: "\x{E42}\x{E15}" + text run at (0,17916) width 17: "\x{E42}\x{E15}\x{E49}" + text run at (0,17946) width 16: "\x{E44}\x{E27}\x{E49}" + text run at (0,17976) width 17: "\x{E43}\x{E19}" + text run at (0,18006) width 29: "\x{E2D}\x{E49}\x{E2D}\x{E21}" + text run at (0,18036) width 31: "\x{E41}\x{E02}\x{E19}" + text run at (0,18066) width 27: "\x{E41}\x{E25}\x{E30}" + text run at (0,18096) width 10: "\x{E01}\x{E47}" + text run at (0,18126) width 28: "\x{E21}\x{E2D}\x{E07}" + text run at (0,18156) width 10: "\x{E14}\x{E39}" + text run at (0,18186) width 46: "\x{E17}\x{E49}\x{E2D}\x{E07}\x{E1F}\x{E49}\x{E32}" + text run at (0,18216) width 19: "\x{E2D}\x{E22}\x{E39}\x{E48}" + text run at (0,18246) width 46: "\x{E40}\x{E2B}\x{E21}\x{E37}\x{E2D}\x{E19}" + text run at (0,18276) width 21: "\x{E01}\x{E31}\x{E19}" + text run at (0,18306) width 17: "\x{E1B}\x{E49}\x{E32}" + text run at (0,18336) width 14: "\x{E40}\x{E2D}\x{E47}" + text run at (0,18366) width 28: "\x{E21}\x{E01}\x{E33}" + text run at (0,18396) width 17: "\x{E25}\x{E31}\x{E07}" + text run at (0,18426) width 24: "\x{E25}\x{E49}\x{E32}\x{E07}" + text run at (0,18456) width 28: "\x{E0A}\x{E32}\x{E21}" + text run at (0,18486) width 19: "\x{E2D}\x{E22}\x{E39}\x{E48}" + text run at (0,18516) width 26: "\x{E08}\x{E32}\x{E01}" + text run at (0,18546) width 28: "\x{E14}\x{E49}\x{E32}\x{E19}" + text run at (0,18576) width 35: "\x{E40}\x{E2B}\x{E19}\x{E37}\x{E2D}" + text run at (0,18606) width 26: "\x{E44}\x{E01}\x{E25}" + text run at (0,18636) width 28: "\x{E2D}\x{E2D}\x{E01}" + text run at (0,18666) width 17: "\x{E44}\x{E1B}" + text run at (0,18696) width 11: "\x{E21}\x{E35}" + text run at (0,18726) width 32: "\x{E40}\x{E2A}\x{E35}\x{E22}\x{E07}" + text run at (0,18756) width 20: "\x{E25}\x{E21}" + text run at (0,18786) width 33: "\x{E04}\x{E23}\x{E32}\x{E07}" + text run at (0,18816) width 29: "\x{E41}\x{E1C}\x{E48}\x{E27}" + text run at (0,18846) width 22: "\x{E40}\x{E1A}\x{E32}" + text run at (0,18876) width 38: "\x{E44}\x{E14}\x{E49}\x{E22}\x{E34}\x{E19}" + text run at (0,18906) width 18: "\x{E21}\x{E32}" + text run at (0,18936) width 17: "\x{E25}\x{E38}\x{E07}" + text run at (0,18966) width 14: "\x{E40}\x{E2E}" + text run at (0,18996) width 19: "\x{E19}\x{E23}\x{E35}" + text run at (0,19026) width 27: "\x{E41}\x{E25}\x{E30}" + text run at (0,19056) width 17: "\x{E42}\x{E14}" + text run at (0,19086) width 24: "\x{E42}\x{E23}\x{E18}\x{E35}" + text run at (0,19116) width 26: "\x{E40}\x{E2B}\x{E47}\x{E19}" + text run at (0,19146) width 21: "\x{E15}\x{E49}\x{E19}" + text run at (0,19176) width 30: "\x{E2B}\x{E0D}\x{E49}\x{E32}" + text run at (0,19206) width 17: "\x{E2A}\x{E39}\x{E07}" + text run at (0,19236) width 25: "\x{E40}\x{E2D}\x{E19}" + text run at (0,19266) width 26: "\x{E40}\x{E1B}\x{E47}\x{E19}" + text run at (0,19296) width 30: "\x{E04}\x{E25}\x{E37}\x{E48}\x{E19}" + text run at (0,19326) width 30: "\x{E01}\x{E48}\x{E2D}\x{E19}" + text run at (0,19356) width 11: "\x{E17}\x{E35}\x{E48}" + text run at (0,19386) width 28: "\x{E1E}\x{E32}\x{E22}\x{E38}" + text run at (0,19416) width 17: "\x{E08}\x{E30}" + text run at (0,19446) width 18: "\x{E21}\x{E32}" + text run at (0,19476) width 18: "\x{E16}\x{E36}\x{E07}" + text run at (0,19506) width 28: "\x{E41}\x{E25}\x{E49}\x{E27}" + text run at (0,19536) width 10: "\x{E01}\x{E47}" + text run at (0,19566) width 11: "\x{E21}\x{E35}" + text run at (0,19596) width 32: "\x{E40}\x{E2A}\x{E35}\x{E22}\x{E07}" + text run at (0,19626) width 29: "\x{E2B}\x{E27}\x{E35}\x{E14}" + text run at (0,19656) width 28: "\x{E2B}\x{E27}\x{E34}\x{E27}" + text run at (0,19686) width 45: "\x{E0A}\x{E31}\x{E14}\x{E40}\x{E08}\x{E19}" + text run at (0,19716) width 18: "\x{E21}\x{E32}" + text run at (0,19746) width 26: "\x{E08}\x{E32}\x{E01}" + text run at (0,19776) width 70: "\x{E1A}\x{E23}\x{E23}\x{E22}\x{E32}\x{E01}\x{E32}\x{E28}" + text run at (0,19806) width 26: "\x{E17}\x{E32}\x{E07}" + text run at (0,19836) width 16: "\x{E43}\x{E15}\x{E49}" + text run at (0,19866) width 27: "\x{E41}\x{E25}\x{E30}" + text run at (0,19896) width 25: "\x{E40}\x{E21}\x{E37}\x{E48}\x{E2D}" + text run at (0,19926) width 43: "\x{E40}\x{E2B}\x{E25}\x{E37}\x{E2D}\x{E1A}" + text run at (0,19956) width 17: "\x{E15}\x{E32}" + text run at (0,19986) width 17: "\x{E44}\x{E1B}" + text run at (0,20016) width 26: "\x{E17}\x{E32}\x{E07}" + text run at (0,20046) width 28: "\x{E14}\x{E49}\x{E32}\x{E19}" + text run at (0,20076) width 22: "\x{E19}\x{E31}\x{E49}\x{E19}" + text run at (0,20106) width 10: "\x{E01}\x{E47}" + text run at (0,20136) width 26: "\x{E40}\x{E2B}\x{E47}\x{E19}" + text run at (0,20166) width 30: "\x{E04}\x{E25}\x{E37}\x{E48}\x{E19}" + text run at (0,20196) width 30: "\x{E2B}\x{E0D}\x{E49}\x{E32}" + text run at (0,20226) width 18: "\x{E21}\x{E32}" + text run at (0,20256) width 26: "\x{E17}\x{E32}\x{E07}" + text run at (0,20286) width 28: "\x{E14}\x{E49}\x{E32}\x{E19}" + text run at (0,20316) width 22: "\x{E19}\x{E31}\x{E49}\x{E19}" + text run at (0,20346) width 29: "\x{E14}\x{E49}\x{E27}\x{E22}" + text run at (0,20376) width 17: "\x{E25}\x{E38}\x{E07}" + text run at (0,20406) width 14: "\x{E40}\x{E2E}" + text run at (0,20436) width 19: "\x{E19}\x{E23}\x{E35}" + text run at (0,20466) width 20: "\x{E1C}\x{E38}\x{E14}" + text run at (0,20496) width 19: "\x{E25}\x{E38}\x{E01}" + text run at (0,20526) width 21: "\x{E02}\x{E36}\x{E49}\x{E19}" + text run at (0,20556) width 38: "\x{E17}\x{E31}\x{E19}\x{E43}\x{E14}" + text run at (0,20586) width 25: "\"\x{E25}\x{E21}" + text run at (0,20616) width 54: "\x{E44}\x{E0B}\x{E42}\x{E04}\x{E25}\x{E19}" + text run at (0,20646) width 18: "\x{E21}\x{E32}" + text run at (0,20676) width 30: "\x{E40}\x{E2D}\x{E47}\x{E21}\"" + text run at (0,20706) width 17: "\x{E25}\x{E38}\x{E07}" + text run at (0,20736) width 25: "\x{E23}\x{E49}\x{E2D}\x{E07}" + text run at (0,20766) width 29: "\x{E1A}\x{E2D}\x{E01}" + text run at (0,20796) width 44: "\x{E20}\x{E23}\x{E23}\x{E22}\x{E32}" + text run at (0,20826) width 22: "\"\x{E02}\x{E49}\x{E32}" + text run at (0,20856) width 17: "\x{E08}\x{E30}" + text run at (0,20886) width 17: "\x{E44}\x{E1B}" + text run at (0,20916) width 10: "\x{E14}\x{E39}" + text run at (0,20946) width 28: "\x{E2A}\x{E31}\x{E15}\x{E27}\x{E4C}" + text run at (0,20976) width 32: "\x{E40}\x{E25}\x{E35}\x{E49}\x{E22}\x{E07}" + text run at (0,21006) width 45: "\x{E2B}\x{E19}\x{E48}\x{E2D}\x{E22}\"" + text run at (0,21036) width 28: "\x{E41}\x{E25}\x{E49}\x{E27}" + text run at (0,21066) width 17: "\x{E25}\x{E38}\x{E07}" + text run at (0,21096) width 10: "\x{E01}\x{E47}" + text run at (0,21126) width 17: "\x{E27}\x{E34}\x{E48}\x{E07}" + text run at (0,21156) width 17: "\x{E44}\x{E1B}" + text run at (0,21186) width 18: "\x{E22}\x{E31}\x{E07}" + text run at (0,21216) width 24: "\x{E40}\x{E1E}\x{E34}\x{E07}" + text run at (0,21246) width 11: "\x{E17}\x{E35}\x{E48}" + text run at (0,21276) width 18: "\x{E27}\x{E31}\x{E27}" + text run at (0,21306) width 27: "\x{E41}\x{E25}\x{E30}" + text run at (0,21336) width 18: "\x{E21}\x{E49}\x{E32}" + text run at (0,21366) width 36: "\x{E2D}\x{E32}\x{E28}\x{E31}\x{E22}" + text run at (0,21396) width 19: "\x{E2D}\x{E22}\x{E39}\x{E48}" + text run at (0,21426) width 17: "\x{E1B}\x{E49}\x{E32}" + text run at (0,21456) width 25: "\x{E40}\x{E2D}\x{E47}\x{E21}" + text run at (0,21486) width 30: "\x{E2B}\x{E22}\x{E38}\x{E14}" + text run at (0,21516) width 44: "\x{E17}\x{E33}\x{E07}\x{E32}\x{E19}" + text run at (0,21546) width 27: "\x{E41}\x{E25}\x{E30}" + text run at (0,21576) width 18: "\x{E21}\x{E32}" + text run at (0,21606) width 11: "\x{E17}\x{E35}\x{E48}" + text run at (0,21636) width 36: "\x{E1B}\x{E23}\x{E30}\x{E15}\x{E39}" + text run at (0,21666) width 34: "\x{E40}\x{E1E}\x{E35}\x{E22}\x{E07}" + text run at (0,21696) width 44: "\x{E0A}\x{E32}\x{E22}\x{E15}\x{E32}" + text run at (0,21726) width 28: "\x{E21}\x{E2D}\x{E07}" + text run at (0,21756) width 17: "\x{E1B}\x{E49}\x{E32}" + text run at (0,21786) width 10: "\x{E01}\x{E47}" + text run at (0,21816) width 29: "\x{E1A}\x{E2D}\x{E01}" + text run at (0,21846) width 17: "\x{E44}\x{E14}\x{E49}" + text run at (0,21876) width 16: "\x{E27}\x{E48}\x{E32}" + text run at (0,21906) width 55: "\x{E2D}\x{E31}\x{E19}\x{E15}\x{E23}\x{E32}\x{E22}" + text run at (0,21936) width 18: "\x{E21}\x{E32}" + text run at (0,21966) width 18: "\x{E16}\x{E36}\x{E07}" + text run at (0,21996) width 28: "\x{E41}\x{E25}\x{E49}\x{E27}" + text run at (0,22026) width 27: "\"\x{E40}\x{E23}\x{E47}\x{E27}" + text run at (0,22056) width 17: "\x{E42}\x{E14}" + text run at (0,22086) width 34: "\x{E42}\x{E23}\x{E18}\x{E35}!\"" + text run at (0,22116) width 17: "\x{E1B}\x{E49}\x{E32}" + text run at (0,22146) width 46: "\x{E15}\x{E30}\x{E42}\x{E01}\x{E19}" + text run at (0,22176) width 22: "\"\x{E27}\x{E34}\x{E48}\x{E07}" + text run at (0,22206) width 17: "\x{E44}\x{E1B}" + text run at (0,22236) width 27: "\x{E2B}\x{E49}\x{E2D}\x{E07}" + text run at (0,22266) width 42: "\x{E43}\x{E15}\x{E49}\x{E16}\x{E38}\x{E19}\"" + text run at (0,22296) width 17: "\x{E42}\x{E15}" + text run at (0,22326) width 17: "\x{E42}\x{E15}\x{E49}" + text run at (0,22356) width 30: "\x{E1C}\x{E25}\x{E38}\x{E19}" + text run at (0,22386) width 53: "\x{E01}\x{E23}\x{E30}\x{E42}\x{E14}\x{E14}" + text run at (0,22416) width 17: "\x{E25}\x{E07}" + text run at (0,22446) width 26: "\x{E08}\x{E32}\x{E01}" + text run at (0,22476) width 29: "\x{E2D}\x{E49}\x{E2D}\x{E21}" + text run at (0,22506) width 31: "\x{E41}\x{E02}\x{E19}" + text run at (0,22536) width 17: "\x{E42}\x{E14}" + text run at (0,22566) width 24: "\x{E42}\x{E23}\x{E18}\x{E35}" + text run at (0,22596) width 28: "\x{E41}\x{E25}\x{E49}\x{E27}" + text run at (0,22626) width 39: "\x{E40}\x{E02}\x{E49}\x{E32}\x{E44}\x{E1B}" + text run at (0,22656) width 30: "\x{E0B}\x{E48}\x{E2D}\x{E19}" + text run at (0,22686) width 19: "\x{E2D}\x{E22}\x{E39}\x{E48}" + text run at (0,22716) width 16: "\x{E43}\x{E15}\x{E49}" + text run at (0,22746) width 33: "\x{E40}\x{E15}\x{E35}\x{E22}\x{E07}" + text run at (0,22776) width 25: "\x{E40}\x{E14}\x{E47}\x{E01}" + text run at (0,22806) width 31: "\x{E2B}\x{E0D}\x{E34}\x{E07}" + text run at (0,22836) width 30: "\x{E19}\x{E49}\x{E2D}\x{E22}" + text run at (0,22866) width 39: "\x{E40}\x{E02}\x{E49}\x{E32}\x{E44}\x{E1B}" + text run at (0,22896) width 18: "\x{E14}\x{E36}\x{E07}" + text run at (0,22926) width 22: "\x{E21}\x{E31}\x{E19}" + text run at (0,22956) width 28: "\x{E2D}\x{E2D}\x{E01}" + text run at (0,22986) width 18: "\x{E21}\x{E32}" + text run at (0,23016) width 17: "\x{E1B}\x{E49}\x{E32}" + text run at (0,23046) width 14: "\x{E40}\x{E2D}\x{E47}" + text run at (0,23076) width 21: "\x{E21}\x{E01}" + text run at (0,23106) width 16: "\x{E23}\x{E30}" + text run at (0,23136) width 27: "\x{E0A}\x{E32}\x{E01}" + text run at (0,23166) width 17: "\x{E1D}\x{E32}" + text run at (0,23196) width 11: "\x{E17}\x{E35}\x{E48}" + text run at (0,23226) width 22: "\x{E1E}\x{E37}\x{E49}\x{E19}" + text run at (0,23256) width 28: "\x{E2D}\x{E2D}\x{E01}" + text run at (0,23286) width 34: "\x{E2D}\x{E22}\x{E48}\x{E32}\x{E07}" + text run at (0,23316) width 19: "\x{E2D}\x{E01}" + text run at (0,23346) width 20: "\x{E2A}\x{E31}\x{E48}\x{E19}" + text run at (0,23376) width 32: "\x{E02}\x{E27}\x{E31}\x{E0D}" + text run at (0,23406) width 27: "\x{E2B}\x{E32}\x{E22}" + text run at (0,23436) width 21: "\x{E1B}\x{E35}\x{E19}" + text run at (0,23466) width 38: "\x{E1A}\x{E31}\x{E19}\x{E44}\x{E14}" + text run at (0,23496) width 18: "\x{E44}\x{E21}\x{E49}" + text run at (0,23526) width 17: "\x{E25}\x{E07}" + text run at (0,23556) width 17: "\x{E44}\x{E1B}" + text run at (0,23586) width 17: "\x{E43}\x{E19}" + text run at (0,23616) width 34: "\x{E42}\x{E1E}\x{E23}\x{E07}" + text run at (0,23646) width 24: "\x{E40}\x{E25}\x{E47}\x{E01}" + text run at (0,23676) width 20: "\x{E2D}\x{E31}\x{E19}" + text run at (0,23706) width 21: "\x{E21}\x{E37}\x{E14}" + text run at (0,23736) width 21: "\x{E17}\x{E36}\x{E1A}" + text run at (0,23766) width 17: "\x{E42}\x{E14}" + text run at (0,23796) width 24: "\x{E42}\x{E23}\x{E18}\x{E35}" + text run at (0,23826) width 19: "\x{E08}\x{E31}\x{E1A}" + text run at (0,23856) width 17: "\x{E42}\x{E15}" + text run at (0,23886) width 17: "\x{E42}\x{E15}\x{E49}" + text run at (0,23916) width 17: "\x{E44}\x{E14}\x{E49}" + text run at (0,23946) width 17: "\x{E43}\x{E19}" + text run at (0,23976) width 30: "\x{E17}\x{E35}\x{E48}\x{E2A}\x{E38}\x{E14}" + text run at (0,24006) width 27: "\x{E41}\x{E25}\x{E30}" + text run at (0,24036) width 17: "\x{E27}\x{E34}\x{E48}\x{E07}" + text run at (0,24066) width 28: "\x{E15}\x{E32}\x{E21}" + text run at (0,24096) width 17: "\x{E1B}\x{E49}\x{E32}" + text run at (0,24126) width 23: "\x{E40}\x{E18}\x{E2D}" + text run at (0,24156) width 17: "\x{E44}\x{E1B}" + text run at (0,24186) width 25: "\x{E40}\x{E21}\x{E37}\x{E48}\x{E2D}" + text run at (0,24216) width 23: "\x{E40}\x{E18}\x{E2D}" + text run at (0,24246) width 18: "\x{E21}\x{E32}" + text run at (0,24276) width 17: "\x{E44}\x{E14}\x{E49}" + text run at (0,24306) width 26: "\x{E04}\x{E23}\x{E36}\x{E48}\x{E07}" + text run at (0,24336) width 27: "\x{E2B}\x{E49}\x{E2D}\x{E07}" + text run at (0,24366) width 10: "\x{E01}\x{E47}" + text run at (0,24396) width 11: "\x{E21}\x{E35}" + text run at (0,24426) width 32: "\x{E40}\x{E2A}\x{E35}\x{E22}\x{E07}" + text run at (0,24456) width 29: "\x{E2B}\x{E27}\x{E35}\x{E14}" + text run at (0,24486) width 28: "\x{E2B}\x{E27}\x{E37}\x{E2D}" + text run at (0,24516) width 29: "\x{E2A}\x{E48}\x{E27}\x{E19}" + text run at (0,24546) width 28: "\x{E1A}\x{E49}\x{E32}\x{E19}" + text run at (0,24576) width 10: "\x{E01}\x{E47}" + text run at (0,24606) width 20: "\x{E2A}\x{E31}\x{E48}\x{E19}" + text run at (0,24636) width 34: "\x{E2D}\x{E22}\x{E48}\x{E32}\x{E07}" + text run at (0,24666) width 26: "\x{E41}\x{E23}\x{E07}" + text run at (0,24696) width 20: "\x{E08}\x{E19}" + text run at (0,24726) width 23: "\x{E40}\x{E18}\x{E2D}" + text run at (0,24756) width 20: "\x{E2B}\x{E01}" + text run at (0,24786) width 36: "\x{E04}\x{E30}\x{E21}\x{E33}" + text run at (0,24816) width 19: "\x{E19}\x{E31}\x{E48}\x{E07}" + text run at (0,24846) width 38: "\x{E08}\x{E49}\x{E33}\x{E40}\x{E1A}\x{E49}\x{E32}" + text run at (0,24876) width 19: "\x{E2D}\x{E22}\x{E39}\x{E48}" + text run at (0,24906) width 20: "\x{E01}\x{E31}\x{E1A}" + text run at (0,24936) width 22: "\x{E1E}\x{E37}\x{E49}\x{E19}" + text run at (0,24966) width 28: "\x{E41}\x{E25}\x{E49}\x{E27}" + text run at (0,24996) width 17: "\x{E2A}\x{E34}\x{E48}\x{E07}" + text run at (0,25026) width 62: "\x{E1B}\x{E23}\x{E30}\x{E2B}\x{E25}\x{E32}\x{E14}" + text run at (0,25056) width 10: "\x{E01}\x{E47}" + text run at (0,25086) width 25: "\x{E40}\x{E01}\x{E34}\x{E14}" + text run at (0,25116) width 21: "\x{E02}\x{E36}\x{E49}\x{E19}" + text run at (0,25146) width 28: "\x{E1A}\x{E49}\x{E32}\x{E19}" + text run at (0,25176) width 32: "\x{E2B}\x{E21}\x{E38}\x{E19}" + text run at (0,25206) width 17: "\x{E44}\x{E1B}" + text run at (0,25236) width 32: "\x{E2B}\x{E21}\x{E38}\x{E19}" + text run at (0,25266) width 27: "\x{E21}\x{E32}\x{E2A}" + text run at (0,25296) width 17: "\x{E2D}\x{E07}" + text run at (0,25326) width 27: "\x{E2A}\x{E32}\x{E21}" + text run at (0,25356) width 27: "\x{E23}\x{E2D}\x{E1A}" + text run at (0,25386) width 28: "\x{E41}\x{E25}\x{E49}\x{E27}" + text run at (0,25416) width 10: "\x{E01}\x{E47}" + text run at (0,25446) width 28: "\x{E25}\x{E2D}\x{E22}" + text run at (0,25476) width 21: "\x{E02}\x{E36}\x{E49}\x{E19}" + text run at (0,25506) width 9: "\x{E2A}\x{E39}\x{E48}" + text run at (0,25536) width 43: "\x{E2D}\x{E32}\x{E01}\x{E32}\x{E28}" + text run at (0,25566) width 34: "\x{E2D}\x{E22}\x{E48}\x{E32}\x{E07}" + text run at (0,25596) width 26: "\x{E0A}\x{E49}\x{E32}\x{E46}" + text run at (0,25626) width 17: "\x{E42}\x{E14}" + text run at (0,25656) width 15: "\x{E42}\x{E23}" + text run at (0,25686) width 17: "\x{E18}\x{E35}\x{E23}\x{E39}\x{E49}" + text run at (0,25716) width 19: "\x{E2A}\x{E36}\x{E01}" + text run at (0,25746) width 44: "\x{E23}\x{E32}\x{E27}\x{E01}\x{E31}\x{E1A}" + text run at (0,25776) width 16: "\x{E27}\x{E48}\x{E32}" + text run at (0,25806) width 23: "\x{E40}\x{E18}\x{E2D}" + text run at (0,25836) width 17: "\x{E44}\x{E14}\x{E49}" + text run at (0,25866) width 21: "\x{E02}\x{E36}\x{E49}\x{E19}" + text run at (0,25896) width 17: "\x{E44}\x{E1B}" + text run at (0,25926) width 20: "\x{E01}\x{E31}\x{E1A}" + text run at (0,25956) width 19: "\x{E25}\x{E39}\x{E01}" + text run at (0,25986) width 48: "\x{E1A}\x{E2D}\x{E25}\x{E25}\x{E39}\x{E19}" + text run at (0,26016) width 28: "\x{E1E}\x{E32}\x{E22}\x{E38}" + text run at (0,26046) width 35: "\x{E40}\x{E2B}\x{E19}\x{E37}\x{E2D}" + text run at (0,26076) width 20: "\x{E01}\x{E31}\x{E1A}" + text run at (0,26106) width 28: "\x{E1E}\x{E32}\x{E22}\x{E38}" + text run at (0,26136) width 16: "\x{E43}\x{E15}\x{E49}" + text run at (0,26166) width 18: "\x{E21}\x{E32}" + text run at (0,26196) width 21: "\x{E1E}\x{E1A}" + text run at (0,26226) width 21: "\x{E01}\x{E31}\x{E19}" + text run at (0,26256) width 26: "\x{E15}\x{E23}\x{E07}" + text run at (0,26286) width 11: "\x{E17}\x{E35}\x{E48}" + text run at (0,26316) width 28: "\x{E1A}\x{E49}\x{E32}\x{E19}" + text run at (0,26346) width 30: "\x{E1E}\x{E2D}\x{E14}\x{E35}" + text run at (0,26376) width 27: "\x{E41}\x{E25}\x{E30}" + text run at (0,26406) width 34: "\x{E17}\x{E33}\x{E43}\x{E2B}\x{E49}" + text run at (0,26436) width 26: "\x{E15}\x{E23}\x{E07}" + text run at (0,26466) width 22: "\x{E19}\x{E31}\x{E49}\x{E19}" + text run at (0,26496) width 26: "\x{E40}\x{E1B}\x{E47}\x{E19}" + text run at (0,26526) width 84: "\x{E08}\x{E38}\x{E14}\x{E28}\x{E39}\x{E19}\x{E22}\x{E4C}\x{E01}\x{E25}\x{E32}\x{E07}" + text run at (0,26556) width 27: "\x{E02}\x{E2D}\x{E07}" + text run at (0,26586) width 28: "\x{E1E}\x{E32}\x{E22}\x{E38}" + text run at (0,26616) width 54: "\x{E44}\x{E0B}\x{E42}\x{E04}\x{E25}\x{E19}" + text run at (0,26646) width 28: "\x{E15}\x{E32}\x{E21}" + text run at (0,26676) width 30: "\x{E1B}\x{E01}\x{E15}\x{E34}" + text run at (0,26706) width 26: "\x{E15}\x{E23}\x{E07}" + text run at (0,26736) width 34: "\x{E01}\x{E25}\x{E32}\x{E07}" + text run at (0,26766) width 28: "\x{E1E}\x{E32}\x{E22}\x{E38}" + text run at (0,26796) width 54: "\x{E44}\x{E0B}\x{E42}\x{E04}\x{E25}\x{E19}" + text run at (0,26826) width 43: "\x{E2D}\x{E32}\x{E01}\x{E32}\x{E28}" + text run at (0,26856) width 17: "\x{E08}\x{E30}" + text run at (0,26886) width 19: "\x{E19}\x{E34}\x{E48}\x{E07}" + text run at (0,26916) width 20: "\x{E41}\x{E15}\x{E48}" + text run at (0,26946) width 37: "\x{E04}\x{E27}\x{E32}\x{E21}" + text run at (0,26976) width 41: "\x{E01}\x{E14}\x{E14}\x{E31}\x{E19}" + text run at (0,27006) width 34: "\x{E2D}\x{E22}\x{E48}\x{E32}\x{E07}" + text run at (0,27036) width 31: "\x{E2B}\x{E19}\x{E31}\x{E01}" + text run at (0,27066) width 27: "\x{E02}\x{E2D}\x{E07}" + text run at (0,27096) width 20: "\x{E25}\x{E21}" + text run at (0,27126) width 21: "\x{E17}\x{E38}\x{E01}" + text run at (0,27156) width 28: "\x{E14}\x{E49}\x{E32}\x{E19}" + text run at (0,27186) width 27: "\x{E23}\x{E2D}\x{E1A}" + text run at (0,27216) width 28: "\x{E1A}\x{E49}\x{E32}\x{E19}" + text run at (0,27246) width 34: "\x{E17}\x{E33}\x{E43}\x{E2B}\x{E49}" + text run at (0,27276) width 28: "\x{E1A}\x{E49}\x{E32}\x{E19}" + text run at (0,27306) width 28: "\x{E25}\x{E2D}\x{E22}" + text run at (0,27336) width 17: "\x{E2A}\x{E39}\x{E07}" + text run at (0,27366) width 30: "\x{E02}\x{E36}\x{E49}\x{E19}\x{E46}" + text run at (0,27396) width 20: "\x{E08}\x{E19}" + text run at (0,27426) width 45: "\x{E01}\x{E23}\x{E30}\x{E17}\x{E31}\x{E48}\x{E07}" + text run at (0,27456) width 21: "\x{E02}\x{E36}\x{E49}\x{E19}" + text run at (0,27486) width 17: "\x{E44}\x{E1B}" + text run at (0,27516) width 19: "\x{E2D}\x{E22}\x{E39}\x{E48}" + text run at (0,27546) width 19: "\x{E2A}\x{E38}\x{E14}" + text run at (0,27576) width 29: "\x{E22}\x{E2D}\x{E14}" + text run at (0,27606) width 27: "\x{E02}\x{E2D}\x{E07}" + text run at (0,27636) width 28: "\x{E1E}\x{E32}\x{E22}\x{E38}" + text run at (0,27666) width 54: "\x{E44}\x{E0B}\x{E42}\x{E04}\x{E25}\x{E19}" + text run at (0,27696) width 27: "\x{E41}\x{E25}\x{E30}" + text run at (0,27726) width 26: "\x{E08}\x{E32}\x{E01}" + text run at (0,27756) width 26: "\x{E15}\x{E23}\x{E07}" + text run at (0,27786) width 22: "\x{E19}\x{E31}\x{E49}\x{E19}" + text run at (0,27816) width 10: "\x{E01}\x{E47}" + text run at (0,27846) width 20: "\x{E16}\x{E39}\x{E01}" + text run at (0,27876) width 29: "\x{E2B}\x{E2D}\x{E1A}" + text run at (0,27906) width 17: "\x{E44}\x{E1B}" + text run at (0,27936) width 36: "\x{E2B}\x{E25}\x{E32}\x{E22}" + text run at (0,27966) width 27: "\x{E44}\x{E21}\x{E25}\x{E4C}" + text run at (0,27996) width 52: "\x{E07}\x{E48}\x{E32}\x{E22}\x{E14}\x{E32}\x{E22}" + text run at (0,28026) width 44: "\x{E23}\x{E32}\x{E27}\x{E01}\x{E31}\x{E1A}" + text run at (0,28056) width 29: "\x{E2B}\x{E2D}\x{E1A}" + text run at (0,28086) width 21: "\x{E02}\x{E19}" + text run at (0,28116) width 21: "\x{E19}\x{E01}" + text run at (0,28146) width 21: "\x{E21}\x{E37}\x{E14}" + text run at (0,28176) width 28: "\x{E21}\x{E32}\x{E01}" + text run at (0,28206) width 28: "\x{E41}\x{E25}\x{E49}\x{E27}" + text run at (0,28236) width 20: "\x{E25}\x{E21}" + text run at (0,28266) width 18: "\x{E22}\x{E31}\x{E07}" + text run at (0,28296) width 17: "\x{E2A}\x{E48}\x{E07}" + text run at (0,28326) width 32: "\x{E40}\x{E2A}\x{E35}\x{E22}\x{E07}" + text run at (0,28356) width 29: "\x{E2B}\x{E27}\x{E35}\x{E14}" + text run at (0,28386) width 28: "\x{E2B}\x{E27}\x{E37}\x{E2D}" + text run at (0,28416) width 18: "\x{E19}\x{E48}\x{E32}" + text run at (0,28446) width 28: "\x{E01}\x{E25}\x{E31}\x{E27}" + text run at (0,28476) width 19: "\x{E2D}\x{E22}\x{E39}\x{E48}" + text run at (0,28506) width 27: "\x{E23}\x{E2D}\x{E1A}" + text run at (0,28536) width 19: "\x{E15}\x{E31}\x{E27}" + text run at (0,28566) width 23: "\x{E40}\x{E18}\x{E2D}" + text run at (0,28596) width 20: "\x{E41}\x{E15}\x{E48}" + text run at (0,28626) width 17: "\x{E42}\x{E14}" + text run at (0,28656) width 24: "\x{E42}\x{E23}\x{E18}\x{E35}" + text run at (0,28686) width 26: "\x{E40}\x{E2B}\x{E47}\x{E19}" + text run at (0,28716) width 16: "\x{E27}\x{E48}\x{E32}" + text run at (0,28746) width 23: "\x{E40}\x{E18}\x{E2D}" + text run at (0,28776) width 52: "\x{E2A}\x{E32}\x{E21}\x{E32}\x{E23}\x{E16}" + text run at (0,28806) width 19: "\x{E19}\x{E31}\x{E48}\x{E07}" + text run at (0,28836) width 17: "\x{E44}\x{E1B}" + text run at (0,28866) width 17: "\x{E44}\x{E14}\x{E49}" + text run at (0,28896) width 34: "\x{E2D}\x{E22}\x{E48}\x{E32}\x{E07}" + text run at (0,28926) width 52: "\x{E07}\x{E48}\x{E32}\x{E22}\x{E14}\x{E32}\x{E22}" + text run at (0,28956) width 21: "\x{E19}\x{E31}\x{E01}" + text run at (0,28986) width 26: "\x{E04}\x{E23}\x{E31}\x{E49}\x{E07}" + text run at (0,29016) width 29: "\x{E2B}\x{E19}\x{E36}\x{E48}\x{E07}" + text run at (0,29046) width 27: "\x{E2B}\x{E25}\x{E31}\x{E07}" + text run at (0,29076) width 26: "\x{E08}\x{E32}\x{E01}" + text run at (0,29106) width 11: "\x{E17}\x{E35}\x{E48}" + text run at (0,29136) width 28: "\x{E1A}\x{E49}\x{E32}\x{E19}" + text run at (0,29166) width 37: "\x{E2A}\x{E30}\x{E14}\x{E38}\x{E14}" + text run at (0,29196) width 34: "\x{E2D}\x{E22}\x{E48}\x{E32}\x{E07}" + text run at (0,29226) width 26: "\x{E41}\x{E23}\x{E07}" + text run at (0,29256) width 27: "\x{E41}\x{E25}\x{E30}" + text run at (0,29286) width 32: "\x{E2B}\x{E21}\x{E38}\x{E19}" + text run at (0,29316) width 17: "\x{E44}\x{E1B}" + text run at (0,29346) width 36: "\x{E23}\x{E2D}\x{E1A}\x{E46}" + text run at (0,29376) width 26: "\x{E2A}\x{E2D}\x{E07}" + text run at (0,29406) width 27: "\x{E2A}\x{E32}\x{E21}" + text run at (0,29436) width 26: "\x{E04}\x{E23}\x{E31}\x{E49}\x{E07}" + text run at (0,29466) width 17: "\x{E43}\x{E19}" + text run at (0,29496) width 30: "\x{E15}\x{E2D}\x{E19}" + text run at (0,29526) width 28: "\x{E41}\x{E23}\x{E01}" + text run at (0,29556) width 23: "\x{E40}\x{E18}\x{E2D}" + text run at (0,29586) width 10: "\x{E01}\x{E47}" + text run at (0,29616) width 27: "\x{E23}\x{E39}\x{E49}\x{E2A}\x{E36}\x{E01}" + text run at (0,29646) width 16: "\x{E27}\x{E48}\x{E32}" + text run at (0,29676) width 19: "\x{E15}\x{E31}\x{E27}" + text run at (0,29706) width 22: "\x{E40}\x{E2D}\x{E07}" + text run at (0,29736) width 20: "\x{E16}\x{E39}\x{E01}" + text run at (0,29766) width 37: "\x{E41}\x{E01}\x{E27}\x{E48}\x{E07}" + text run at (0,29796) width 34: "\x{E2D}\x{E22}\x{E48}\x{E32}\x{E07}" + text run at (0,29826) width 29: "\x{E41}\x{E1C}\x{E48}\x{E27}" + text run at (0,29856) width 22: "\x{E40}\x{E1A}\x{E32}" + text run at (0,29886) width 24: "\x{E23}\x{E32}\x{E27}" + text run at (0,29916) width 36: "\x{E17}\x{E32}\x{E23}\x{E01}" + text run at (0,29946) width 17: "\x{E43}\x{E19}" + text run at (0,29976) width 24: "\x{E40}\x{E1B}\x{E25}" + text run at (0,30006) width 17: "\x{E42}\x{E15}" + text run at (0,30036) width 17: "\x{E42}\x{E15}\x{E49}" + text run at (0,30066) width 18: "\x{E44}\x{E21}\x{E48}" + text run at (0,30096) width 44: "\x{E0A}\x{E2D}\x{E1A}\x{E43}\x{E08}" + text run at (0,30126) width 24: "\x{E40}\x{E25}\x{E22}" + text run at (0,30156) width 22: "\x{E21}\x{E31}\x{E19}" + text run at (0,30186) width 17: "\x{E27}\x{E34}\x{E48}\x{E07}" + text run at (0,30216) width 17: "\x{E44}\x{E1B}" + text run at (0,30246) width 17: "\x{E27}\x{E34}\x{E48}\x{E07}" + text run at (0,30276) width 26: "\x{E21}\x{E32}\x{E23}" + text run at (0,30306) width 19: "\x{E2D}\x{E1A}" + text run at (0,30336) width 27: "\x{E2B}\x{E49}\x{E2D}\x{E07}" + text run at (0,30366) width 26: "\x{E17}\x{E32}\x{E07}" + text run at (0,30396) width 29: "\x{E42}\x{E19}\x{E49}\x{E19}" + text run at (0,30426) width 11: "\x{E17}\x{E35}" + text run at (0,30456) width 26: "\x{E17}\x{E32}\x{E07}" + text run at (0,30486) width 11: "\x{E19}\x{E35}\x{E49}" + text run at (0,30516) width 11: "\x{E17}\x{E35}" + text run at (0,30546) width 17: "\x{E2A}\x{E48}\x{E07}" + text run at (0,30576) width 32: "\x{E40}\x{E2A}\x{E35}\x{E22}\x{E07}" + text run at (0,30606) width 22: "\x{E40}\x{E2B}\x{E48}\x{E32}" + text run at (0,30636) width 18: "\x{E14}\x{E31}\x{E07}" + text run at (0,30666) width 27: "\x{E01}\x{E49}\x{E2D}\x{E07}" + text run at (0,30696) width 20: "\x{E41}\x{E15}\x{E48}" + text run at (0,30726) width 17: "\x{E42}\x{E14}" + text run at (0,30756) width 24: "\x{E42}\x{E23}\x{E18}\x{E35}" + text run at (0,30786) width 19: "\x{E19}\x{E31}\x{E48}\x{E07}" + text run at (0,30816) width 19: "\x{E19}\x{E34}\x{E48}\x{E07}" + text run at (0,30846) width 19: "\x{E2D}\x{E22}\x{E39}\x{E48}" + text run at (0,30876) width 21: "\x{E1A}\x{E19}" + text run at (0,30906) width 22: "\x{E1E}\x{E37}\x{E49}\x{E19}" + text run at (0,30936) width 22: "\x{E40}\x{E1D}\x{E49}\x{E32}" + text run at (0,30966) width 29: "\x{E04}\x{E2D}\x{E22}" + text run at (0,30996) width 10: "\x{E14}\x{E39}" + text run at (0,31026) width 16: "\x{E27}\x{E48}\x{E32}" + text run at (0,31056) width 17: "\x{E08}\x{E30}" + text run at (0,31086) width 25: "\x{E40}\x{E01}\x{E34}\x{E14}" + text run at (0,31116) width 32: "\x{E2D}\x{E30}\x{E44}\x{E23}" + text run at (0,31146) width 21: "\x{E02}\x{E36}\x{E49}\x{E19}" + text run at (0,31176) width 26: "\x{E04}\x{E23}\x{E31}\x{E49}\x{E07}" + text run at (0,31206) width 29: "\x{E2B}\x{E19}\x{E36}\x{E48}\x{E07}" + text run at (0,31236) width 17: "\x{E42}\x{E15}" + text run at (0,31266) width 17: "\x{E42}\x{E15}\x{E49}" + text run at (0,31296) width 39: "\x{E40}\x{E02}\x{E49}\x{E32}\x{E44}\x{E1B}" + text run at (0,31326) width 25: "\x{E43}\x{E01}\x{E25}\x{E49}" + text run at (0,31356) width 17: "\x{E1D}\x{E32}" + text run at (0,31386) width 11: "\x{E17}\x{E35}\x{E48}" + text run at (0,31416) width 22: "\x{E1E}\x{E37}\x{E49}\x{E19}" + text run at (0,31446) width 28: "\x{E21}\x{E32}\x{E01}" + text run at (0,31476) width 17: "\x{E44}\x{E1B}" + text run at (0,31506) width 24: "\x{E40}\x{E25}\x{E22}" + text run at (0,31536) width 30: "\x{E1E}\x{E25}\x{E31}\x{E14}" + text run at (0,31566) width 37: "\x{E15}\x{E01}\x{E25}\x{E07}" + text run at (0,31596) width 17: "\x{E44}\x{E1B}" + text run at (0,31626) width 11: "\x{E17}\x{E35}" + text run at (0,31656) width 28: "\x{E41}\x{E23}\x{E01}" + text run at (0,31686) width 25: "\x{E40}\x{E14}\x{E47}\x{E01}" + text run at (0,31716) width 31: "\x{E2B}\x{E0D}\x{E34}\x{E07}" + text run at (0,31746) width 20: "\x{E04}\x{E34}\x{E14}" + text run at (0,31776) width 16: "\x{E27}\x{E48}\x{E32}" + text run at (0,31806) width 23: "\x{E40}\x{E18}\x{E2D}" + text run at (0,31836) width 17: "\x{E08}\x{E30}" + text run at (0,31866) width 22: "\x{E2A}\x{E39}\x{E0D}" + text run at (0,31896) width 24: "\x{E40}\x{E2A}\x{E35}\x{E22}" + text run at (0,31926) width 22: "\x{E21}\x{E31}\x{E19}" + text run at (0,31956) width 17: "\x{E44}\x{E1B}" + text run at (0,31986) width 24: "\x{E40}\x{E2A}\x{E35}\x{E22}" + text run at (0,32016) width 28: "\x{E41}\x{E25}\x{E49}\x{E27}" + text run at (0,32046) width 20: "\x{E41}\x{E15}\x{E48}" + text run at (0,32076) width 19: "\x{E0A}\x{E31}\x{E48}\x{E27}" + text run at (0,32106) width 18: "\x{E04}\x{E23}\x{E39}\x{E48}" + text run at (0,32136) width 23: "\x{E40}\x{E18}\x{E2D}" + text run at (0,32166) width 10: "\x{E01}\x{E47}" + text run at (0,32196) width 26: "\x{E40}\x{E2B}\x{E47}\x{E19}" + text run at (0,32226) width 10: "\x{E2B}\x{E39}" + text run at (0,32256) width 27: "\x{E02}\x{E2D}\x{E07}" + text run at (0,32286) width 22: "\x{E21}\x{E31}\x{E19}" + text run at (0,32316) width 26: "\x{E42}\x{E1C}\x{E25}\x{E48}" + text run at (0,32346) width 21: "\x{E02}\x{E36}\x{E49}\x{E19}" + text run at (0,32376) width 18: "\x{E21}\x{E32}" + text run at (0,32406) width 26: "\x{E08}\x{E32}\x{E01}" + text run at (0,32436) width 27: "\x{E0A}\x{E48}\x{E2D}\x{E07}" + text run at (0,32466) width 22: "\x{E19}\x{E31}\x{E49}\x{E19}" + text run at (0,32496) width 30: "\x{E17}\x{E31}\x{E49}\x{E07}\x{E19}\x{E35}\x{E49}" + text run at (0,32526) width 39: "\x{E40}\x{E1E}\x{E23}\x{E32}\x{E30}" + text run at (0,32556) width 26: "\x{E41}\x{E23}\x{E07}" + text run at (0,32586) width 20: "\x{E01}\x{E14}" + text run at (0,32616) width 34: "\x{E2D}\x{E22}\x{E48}\x{E32}\x{E07}" + text run at (0,32646) width 31: "\x{E2B}\x{E19}\x{E31}\x{E01}" + text run at (0,32676) width 27: "\x{E02}\x{E2D}\x{E07}" + text run at (0,32706) width 43: "\x{E2D}\x{E32}\x{E01}\x{E32}\x{E28}" + text run at (0,32736) width 34: "\x{E17}\x{E33}\x{E43}\x{E2B}\x{E49}" + text run at (0,32766) width 17: "\x{E42}\x{E15}" + text run at (0,32796) width 17: "\x{E42}\x{E15}\x{E49}" + text run at (0,32826) width 18: "\x{E44}\x{E21}\x{E48}" + text run at (0,32856) width 37: "\x{E15}\x{E01}\x{E25}\x{E07}" + text run at (0,32886) width 17: "\x{E44}\x{E1B}" + text run at (0,32916) width 25: "\x{E02}\x{E49}\x{E32}\x{E07}" + text run at (0,32946) width 24: "\x{E25}\x{E48}\x{E32}\x{E07}" + text run at (0,32976) width 17: "\x{E42}\x{E14}" + text run at (0,33006) width 24: "\x{E42}\x{E23}\x{E18}\x{E35}" + text run at (0,33036) width 37: "\x{E04}\x{E25}\x{E32}\x{E19}" + text run at (0,33066) width 17: "\x{E44}\x{E1B}" + text run at (0,33096) width 11: "\x{E17}\x{E35}\x{E48}" + text run at (0,33126) width 27: "\x{E0A}\x{E48}\x{E2D}\x{E07}" + text run at (0,33156) width 22: "\x{E19}\x{E31}\x{E49}\x{E19}" + text run at (0,33186) width 19: "\x{E08}\x{E31}\x{E1A}" + text run at (0,33216) width 10: "\x{E2B}\x{E39}" + text run at (0,33246) width 17: "\x{E42}\x{E15}" + text run at (0,33276) width 17: "\x{E42}\x{E15}\x{E49}" + text run at (0,33306) width 16: "\x{E44}\x{E27}\x{E49}" + text run at (0,33336) width 17: "\x{E44}\x{E14}\x{E49}" + text run at (0,33366) width 27: "\x{E41}\x{E25}\x{E30}" + text run at (0,33396) width 26: "\x{E25}\x{E32}\x{E01}" + text run at (0,33426) width 22: "\x{E21}\x{E31}\x{E19}" + text run at (0,33456) width 18: "\x{E21}\x{E32}" + text run at (0,33486) width 11: "\x{E17}\x{E35}\x{E48}" + text run at (0,33516) width 27: "\x{E2B}\x{E49}\x{E2D}\x{E07}" + text run at (0,33546) width 19: "\x{E2D}\x{E35}\x{E01}" + text run at (0,33576) width 27: "\x{E2B}\x{E25}\x{E31}\x{E07}" + text run at (0,33606) width 26: "\x{E08}\x{E32}\x{E01}" + text run at (0,33636) width 22: "\x{E19}\x{E31}\x{E49}\x{E19}" + text run at (0,33666) width 10: "\x{E01}\x{E47}" + text run at (0,33696) width 20: "\x{E1B}\x{E34}\x{E14}" + text run at (0,33726) width 17: "\x{E1D}\x{E32}" + text run at (0,33756) width 22: "\x{E1E}\x{E37}\x{E49}\x{E19}" + text run at (0,33786) width 25: "\x{E40}\x{E1E}\x{E37}\x{E48}\x{E2D}" + text run at (0,33816) width 17: "\x{E08}\x{E30}" + text run at (0,33846) width 17: "\x{E44}\x{E14}\x{E49}" + text run at (0,33876) width 18: "\x{E44}\x{E21}\x{E48}" + text run at (0,33906) width 25: "\x{E40}\x{E01}\x{E34}\x{E14}" + text run at (0,33936) width 54: "\x{E2D}\x{E38}\x{E1A}\x{E31}\x{E15}\x{E34}\x{E40}\x{E2B}\x{E15}\x{E38}" + text run at (0,33966) width 19: "\x{E2D}\x{E35}\x{E01}" + text run at (0,33996) width 45: "\x{E0A}\x{E31}\x{E48}\x{E27}\x{E42}\x{E21}\x{E07}" + text run at (0,34026) width 28: "\x{E41}\x{E25}\x{E49}\x{E27}" + text run at (0,34056) width 45: "\x{E0A}\x{E31}\x{E48}\x{E27}\x{E42}\x{E21}\x{E07}" + text run at (0,34086) width 21: "\x{E40}\x{E25}\x{E48}\x{E32}" + text run at (0,34116) width 28: "\x{E1C}\x{E48}\x{E32}\x{E19}" + text run at (0,34146) width 17: "\x{E44}\x{E1B}" + text run at (0,34176) width 17: "\x{E42}\x{E14}" + text run at (0,34206) width 24: "\x{E42}\x{E23}\x{E18}\x{E35}" + text run at (0,34236) width 38: "\x{E04}\x{E48}\x{E2D}\x{E22}\x{E46}" + text run at (0,34266) width 27: "\x{E2B}\x{E32}\x{E22}" + text run at (0,34296) width 28: "\x{E01}\x{E25}\x{E31}\x{E27}" + text run at (0,34326) width 20: "\x{E41}\x{E15}\x{E48}" + text run at (0,34356) width 23: "\x{E40}\x{E18}\x{E2D}" + text run at (0,34386) width 27: "\x{E23}\x{E39}\x{E49}\x{E2A}\x{E36}\x{E01}" + text run at (0,34416) width 30: "\x{E40}\x{E2B}\x{E07}\x{E32}" + text run at (0,34446) width 33: "\x{E40}\x{E2B}\x{E25}\x{E37}\x{E2D}" + text run at (0,34476) width 26: "\x{E40}\x{E01}\x{E34}\x{E19}" + text run at (0,34506) width 27: "\x{E41}\x{E25}\x{E30}" + text run at (0,34536) width 20: "\x{E25}\x{E21}" + text run at (0,34566) width 10: "\x{E01}\x{E47}" + text run at (0,34596) width 17: "\x{E2A}\x{E48}\x{E07}" + text run at (0,34626) width 32: "\x{E40}\x{E2A}\x{E35}\x{E22}\x{E07}" + text run at (0,34656) width 29: "\x{E2B}\x{E27}\x{E35}\x{E14}" + text run at (0,34686) width 28: "\x{E2B}\x{E27}\x{E37}\x{E2D}" + text run at (0,34716) width 18: "\x{E14}\x{E31}\x{E07}" + text run at (0,34746) width 24: "\x{E40}\x{E2A}\x{E35}\x{E22}" + text run at (0,34776) width 20: "\x{E08}\x{E19}" + text run at (0,34806) width 23: "\x{E40}\x{E18}\x{E2D}" + text run at (0,34836) width 31: "\x{E41}\x{E17}\x{E1A}" + text run at (0,34866) width 17: "\x{E08}\x{E30}" + text run at (0,34896) width 10: "\x{E2B}\x{E39}" + text run at (0,34926) width 40: "\x{E2B}\x{E19}\x{E27}\x{E01}" + text run at (0,34956) width 11: "\x{E17}\x{E35}" + text run at (0,34986) width 28: "\x{E41}\x{E23}\x{E01}" + text run at (0,35016) width 23: "\x{E40}\x{E18}\x{E2D}" + text run at (0,35046) width 36: "\x{E2A}\x{E07}\x{E2A}\x{E31}\x{E22}" + text run at (0,35076) width 16: "\x{E27}\x{E48}\x{E32}" + text run at (0,35106) width 35: "\x{E04}\x{E07}\x{E08}\x{E30}" + text run at (0,35136) width 20: "\x{E16}\x{E39}\x{E01}" + text run at (0,35166) width 20: "\x{E09}\x{E35}\x{E01}" + text run at (0,35196) width 53: "\x{E01}\x{E23}\x{E30}\x{E0A}\x{E32}\x{E01}" + text run at (0,35226) width 28: "\x{E2D}\x{E2D}\x{E01}" + text run at (0,35256) width 26: "\x{E40}\x{E1B}\x{E47}\x{E19}" + text run at (0,35286) width 21: "\x{E0A}\x{E34}\x{E49}\x{E19}" + text run at (0,35316) width 24: "\x{E40}\x{E25}\x{E47}\x{E01}" + text run at (0,35346) width 21: "\x{E0A}\x{E34}\x{E49}\x{E19}" + text run at (0,35376) width 30: "\x{E19}\x{E49}\x{E2D}\x{E22}" + text run at (0,35406) width 25: "\x{E40}\x{E21}\x{E37}\x{E48}\x{E2D}" + text run at (0,35436) width 28: "\x{E1A}\x{E49}\x{E32}\x{E19}" + text run at (0,35466) width 25: "\x{E40}\x{E2D}\x{E19}" + text run at (0,35496) width 20: "\x{E25}\x{E49}\x{E21}" + text run at (0,35526) width 17: "\x{E25}\x{E07}" + text run at (0,35556) width 19: "\x{E2D}\x{E35}\x{E01}" + text run at (0,35586) width 26: "\x{E04}\x{E23}\x{E31}\x{E49}\x{E07}" + text run at (0,35616) width 20: "\x{E41}\x{E15}\x{E48}" + text run at (0,35646) width 36: "\x{E2B}\x{E25}\x{E32}\x{E22}" + text run at (0,35676) width 45: "\x{E0A}\x{E31}\x{E48}\x{E27}\x{E42}\x{E21}\x{E07}" + text run at (0,35706) width 28: "\x{E1C}\x{E48}\x{E32}\x{E19}" + text run at (0,35736) width 17: "\x{E44}\x{E1B}" + text run at (0,35766) width 10: "\x{E01}\x{E47}" + text run at (0,35796) width 29: "\x{E44}\x{E21}\x{E48}\x{E21}\x{E35}" + text run at (0,35826) width 32: "\x{E2D}\x{E30}\x{E44}\x{E23}" + text run at (0,35856) width 25: "\x{E40}\x{E01}\x{E34}\x{E14}" + text run at (0,35886) width 21: "\x{E02}\x{E36}\x{E49}\x{E19}" + text run at (0,35916) width 23: "\x{E40}\x{E18}\x{E2D}" + text run at (0,35946) width 24: "\x{E40}\x{E25}\x{E22}" + text run at (0,35976) width 24: "\x{E40}\x{E25}\x{E34}\x{E01}" + text run at (0,36006) width 29: "\x{E27}\x{E34}\x{E15}\x{E01}" + text run at (0,36036) width 27: "\x{E41}\x{E25}\x{E30}" + text run at (0,36066) width 40: "\x{E15}\x{E31}\x{E14}\x{E2A}\x{E34}\x{E19}" + text run at (0,36096) width 15: "\x{E43}\x{E08}" + text run at (0,36126) width 29: "\x{E04}\x{E2D}\x{E22}" + text run at (0,36156) width 10: "\x{E14}\x{E39}" + text run at (0,36186) width 34: "\x{E2D}\x{E22}\x{E48}\x{E32}\x{E07}" + text run at (0,36216) width 27: "\x{E2A}\x{E07}\x{E1A}" + text run at (0,36246) width 27: "\x{E41}\x{E25}\x{E30}" + text run at (0,36276) width 17: "\x{E23}\x{E2D}" + text run at (0,36306) width 16: "\x{E27}\x{E48}\x{E32}" + text run at (0,36336) width 47: "\x{E2D}\x{E19}\x{E32}\x{E04}\x{E15}" + text run at (0,36366) width 17: "\x{E08}\x{E30}" + text run at (0,36396) width 26: "\x{E40}\x{E1B}\x{E47}\x{E19}" + text run at (0,36426) width 49: "\x{E2D}\x{E22}\x{E48}\x{E32}\x{E07}\x{E44}\x{E23}" + text run at (0,36456) width 17: "\x{E43}\x{E19}" + text run at (0,36486) width 30: "\x{E17}\x{E35}\x{E48}\x{E2A}\x{E38}\x{E14}" + text run at (0,36516) width 23: "\x{E40}\x{E18}\x{E2D}" + text run at (0,36546) width 37: "\x{E04}\x{E25}\x{E32}\x{E19}" + text run at (0,36576) width 26: "\x{E08}\x{E32}\x{E01}" + text run at (0,36606) width 22: "\x{E1E}\x{E37}\x{E49}\x{E19}" + text run at (0,36636) width 27: "\x{E2B}\x{E49}\x{E2D}\x{E07}" + text run at (0,36666) width 11: "\x{E17}\x{E35}\x{E48}" + text run at (0,36696) width 27: "\x{E42}\x{E22}\x{E01}" + text run at (0,36726) width 17: "\x{E44}\x{E1B}" + text run at (0,36756) width 18: "\x{E21}\x{E32}" + text run at (0,36786) width 21: "\x{E02}\x{E36}\x{E49}\x{E19}" + text run at (0,36816) width 17: "\x{E44}\x{E1B}" + text run at (0,36846) width 21: "\x{E1A}\x{E19}" + text run at (0,36876) width 33: "\x{E40}\x{E15}\x{E35}\x{E22}\x{E07}" + text run at (0,36906) width 28: "\x{E41}\x{E25}\x{E49}\x{E27}" + text run at (0,36936) width 10: "\x{E01}\x{E47}" + text run at (0,36966) width 31: "\x{E19}\x{E2D}\x{E19}" + text run at (0,36996) width 17: "\x{E25}\x{E07}" + text run at (0,37026) width 17: "\x{E42}\x{E15}" + text run at (0,37056) width 17: "\x{E42}\x{E15}\x{E49}" + text run at (0,37086) width 28: "\x{E15}\x{E32}\x{E21}" + text run at (0,37116) width 20: "\x{E15}\x{E34}\x{E14}" + text run at (0,37146) width 18: "\x{E21}\x{E32}" + text run at (0,37176) width 31: "\x{E19}\x{E2D}\x{E19}" + text run at (0,37206) width 17: "\x{E25}\x{E07}" + text run at (0,37236) width 34: "\x{E43}\x{E01}\x{E25}\x{E49}\x{E46}" + text run at (0,37266) width 23: "\x{E40}\x{E18}\x{E2D}" + text run at (0,37296) width 18: "\x{E44}\x{E21}\x{E48}" + text run at (0,37326) width 17: "\x{E0A}\x{E49}\x{E32}" + text run at (0,37356) width 17: "\x{E42}\x{E14}" + text run at (0,37386) width 24: "\x{E42}\x{E23}\x{E18}\x{E35}" + text run at (0,37416) width 10: "\x{E01}\x{E47}" + text run at (0,37446) width 20: "\x{E1B}\x{E34}\x{E14}" + text run at (0,37476) width 17: "\x{E15}\x{E32}" + text run at (0,37506) width 17: "\x{E25}\x{E07}" + text run at (0,37536) width 29: "\x{E2B}\x{E25}\x{E31}\x{E1A}" + text run at (0,37566) width 38: "\x{E1C}\x{E25}\x{E47}\x{E2D}\x{E22}" + text run at (0,37596) width 17: "\x{E44}\x{E1B}" + text run at (0,37626) width 34: "\x{E2D}\x{E22}\x{E48}\x{E32}\x{E07}" + text run at (0,37656) width 31: "\x{E2A}\x{E19}\x{E34}\x{E17}" + text run at (0,37686) width 28: "\x{E17}\x{E31}\x{E49}\x{E07}\x{E46}" + text run at (0,37716) width 11: "\x{E17}\x{E35}\x{E48}" + text run at (0,37746) width 28: "\x{E1A}\x{E49}\x{E32}\x{E19}" + text run at (0,37776) width 27: "\x{E42}\x{E22}\x{E01}" + text run at (0,37806) width 17: "\x{E44}\x{E1B}" + text run at (0,37836) width 18: "\x{E21}\x{E32}" + text run at (0,37866) width 27: "\x{E41}\x{E25}\x{E30}" + text run at (0,37896) width 20: "\x{E25}\x{E21}" + text run at (0,37926) width 10: "\x{E01}\x{E47}" + text run at (0,37956) width 33: "\x{E04}\x{E23}\x{E32}\x{E07}" + text run at (0,37986) width 29: "\x{E2B}\x{E27}\x{E35}\x{E14}" + text run at (0,38016) width 28: "\x{E2B}\x{E27}\x{E37}\x{E2D}" +layer at (471,84) size 1x39910 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600 + LayoutBlockFlow (positioned) {DIV} at (471,84) size 1x39910 + LayoutText {#text} at (0,6) size 70x39899 + text run at (0,6) width 21: "\x{E1A}\x{E17}" + text run at (0,36) width 11: "\x{E17}\x{E35}\x{E48}" + text run at (0,66) width 10: "\x{E51}" + text run at (0,96) width 28: "\x{E1E}\x{E32}\x{E22}\x{E38}" + text run at (0,126) width 54: "\x{E44}\x{E0B}\x{E42}\x{E04}\x{E25}\x{E19}" + text run at (0,156) width 17: "\x{E42}\x{E14}" + text run at (0,186) width 24: "\x{E42}\x{E23}\x{E18}\x{E35}" + text run at (0,216) width 36: "\x{E2D}\x{E32}\x{E28}\x{E31}\x{E22}" + text run at (0,246) width 19: "\x{E2D}\x{E22}\x{E39}\x{E48}" + text run at (0,276) width 29: "\x{E17}\x{E48}\x{E32}\x{E21}" + text run at (0,306) width 34: "\x{E01}\x{E25}\x{E32}\x{E07}" + text run at (0,336) width 19: "\x{E17}\x{E38}\x{E48}\x{E07}" + text run at (0,366) width 29: "\x{E43}\x{E2B}\x{E0D}\x{E48}" + text run at (0,396) width 17: "\x{E43}\x{E19}" + text run at (0,426) width 50: "\x{E41}\x{E04}\x{E19}\x{E0B}\x{E31}\x{E2A}" + text run at (0,456) width 20: "\x{E01}\x{E31}\x{E1A}" + text run at (0,486) width 17: "\x{E25}\x{E38}\x{E07}" + text run at (0,516) width 14: "\x{E40}\x{E2E}" + text run at (0,546) width 19: "\x{E19}\x{E23}\x{E35}" + text run at (0,576) width 26: "\x{E0A}\x{E32}\x{E27}" + text run at (0,606) width 15: "\x{E44}\x{E23}\x{E48}" + text run at (0,636) width 27: "\x{E41}\x{E25}\x{E30}" + text run at (0,666) width 17: "\x{E1B}\x{E49}\x{E32}" + text run at (0,696) width 25: "\x{E40}\x{E2D}\x{E47}\x{E21}" + text run at (0,726) width 44: "\x{E20}\x{E23}\x{E23}\x{E22}\x{E32}" + text run at (0,756) width 41: "\x{E0A}\x{E32}\x{E27}\x{E44}\x{E23}\x{E48}" + text run at (0,786) width 28: "\x{E1A}\x{E49}\x{E32}\x{E19}" + text run at (0,816) width 27: "\x{E02}\x{E2D}\x{E07}" + text run at (0,846) width 30: "\x{E1E}\x{E27}\x{E01}" + text run at (0,876) width 22: "\x{E40}\x{E02}\x{E32}" + text run at (0,906) width 27: "\x{E2B}\x{E25}\x{E31}\x{E07}" + text run at (0,936) width 24: "\x{E40}\x{E25}\x{E47}\x{E01}" + text run at (0,966) width 39: "\x{E40}\x{E1E}\x{E23}\x{E32}\x{E30}" + text run at (0,996) width 18: "\x{E44}\x{E21}\x{E49}" + text run at (0,1026) width 32: "\x{E2A}\x{E23}\x{E49}\x{E32}\x{E07}" + text run at (0,1056) width 28: "\x{E1A}\x{E49}\x{E32}\x{E19}" + text run at (0,1086) width 27: "\x{E15}\x{E49}\x{E2D}\x{E07}" + text run at (0,1116) width 21: "\x{E02}\x{E19}" + text run at (0,1146) width 18: "\x{E21}\x{E32}" + text run at (0,1176) width 29: "\x{E14}\x{E49}\x{E27}\x{E22}" + text run at (0,1206) width 45: "\x{E40}\x{E01}\x{E27}\x{E35}\x{E22}\x{E19}" + text run at (0,1236) width 26: "\x{E40}\x{E1B}\x{E47}\x{E19}" + text run at (0,1266) width 34: "\x{E23}\x{E30}\x{E22}\x{E30}" + text run at (0,1296) width 26: "\x{E17}\x{E32}\x{E07}" + text run at (0,1326) width 36: "\x{E2B}\x{E25}\x{E32}\x{E22}" + text run at (0,1356) width 27: "\x{E44}\x{E21}\x{E25}\x{E4C}" + text run at (0,1386) width 28: "\x{E1A}\x{E49}\x{E32}\x{E19}" + text run at (0,1416) width 11: "\x{E21}\x{E35}" + text run at (0,1446) width 9: "\x{E2A}\x{E35}\x{E48}" + text run at (0,1476) width 17: "\x{E1D}\x{E32}" + text run at (0,1506) width 11: "\x{E21}\x{E35}" + text run at (0,1536) width 22: "\x{E1E}\x{E37}\x{E49}\x{E19}" + text run at (0,1566) width 20: "\x{E01}\x{E31}\x{E1A}" + text run at (0,1596) width 44: "\x{E2B}\x{E25}\x{E31}\x{E07}\x{E04}\x{E32}" + text run at (0,1626) width 28: "\x{E23}\x{E27}\x{E21}" + text run at (0,1656) width 18: "\x{E17}\x{E33}" + text run at (0,1686) width 26: "\x{E40}\x{E1B}\x{E47}\x{E19}" + text run at (0,1716) width 27: "\x{E2B}\x{E49}\x{E2D}\x{E07}" + text run at (0,1746) width 34: "\x{E40}\x{E14}\x{E35}\x{E22}\x{E27}" + text run at (0,1776) width 17: "\x{E43}\x{E19}" + text run at (0,1806) width 27: "\x{E2B}\x{E49}\x{E2D}\x{E07}" + text run at (0,1836) width 11: "\x{E21}\x{E35}" + text run at (0,1866) width 19: "\x{E17}\x{E31}\x{E49}\x{E07}" + text run at (0,1896) width 22: "\x{E40}\x{E15}\x{E32}" + text run at (0,1926) width 18: "\x{E2B}\x{E38}\x{E07}" + text run at (0,1956) width 21: "\x{E15}\x{E49}\x{E21}" + text run at (0,1986) width 11: "\x{E17}\x{E35}\x{E48}" + text run at (0,2016) width 31: "\x{E2A}\x{E19}\x{E34}\x{E21}" + text run at (0,2046) width 10: "\x{E14}\x{E39}" + text run at (0,2076) width 21: "\x{E02}\x{E36}\x{E49}\x{E19}" + text run at (0,2106) width 31: "\x{E40}\x{E25}\x{E2D}\x{E30}" + text run at (0,2136) width 11: "\x{E21}\x{E35}" + text run at (0,2166) width 10: "\x{E15}\x{E39}\x{E49}" + text run at (0,2196) width 15: "\x{E43}\x{E2A}\x{E48}" + text run at (0,2226) width 29: "\x{E16}\x{E49}\x{E27}\x{E22}" + text run at (0,2256) width 28: "\x{E0A}\x{E32}\x{E21}" + text run at (0,2286) width 25: "\x{E42}\x{E15}\x{E4A}\x{E30}" + text run at (0,2316) width 31: "\x{E40}\x{E01}\x{E49}\x{E32}\x{E2D}\x{E35}\x{E49}" + text run at (0,2346) width 27: "\x{E2A}\x{E32}\x{E21}" + text run at (0,2376) width 27: "\x{E2B}\x{E23}\x{E37}\x{E2D}" + text run at (0,2406) width 9: "\x{E2A}\x{E35}\x{E48}" + text run at (0,2436) width 19: "\x{E15}\x{E31}\x{E27}" + text run at (0,2466) width 28: "\x{E41}\x{E25}\x{E49}\x{E27}" + text run at (0,2496) width 10: "\x{E01}\x{E47}" + text run at (0,2526) width 11: "\x{E21}\x{E35}" + text run at (0,2556) width 33: "\x{E40}\x{E15}\x{E35}\x{E22}\x{E07}" + text run at (0,2586) width 31: "\x{E19}\x{E2D}\x{E19}" + text run at (0,2616) width 17: "\x{E25}\x{E38}\x{E07}" + text run at (0,2646) width 14: "\x{E40}\x{E2E}" + text run at (0,2676) width 19: "\x{E19}\x{E23}\x{E35}" + text run at (0,2706) width 20: "\x{E01}\x{E31}\x{E1A}" + text run at (0,2736) width 17: "\x{E1B}\x{E49}\x{E32}" + text run at (0,2766) width 25: "\x{E40}\x{E2D}\x{E47}\x{E21}" + text run at (0,2796) width 11: "\x{E21}\x{E35}" + text run at (0,2826) width 33: "\x{E40}\x{E15}\x{E35}\x{E22}\x{E07}" + text run at (0,2856) width 31: "\x{E19}\x{E2D}\x{E19}" + text run at (0,2886) width 29: "\x{E43}\x{E2B}\x{E0D}\x{E48}" + text run at (0,2916) width 19: "\x{E2D}\x{E22}\x{E39}\x{E48}" + text run at (0,2946) width 11: "\x{E17}\x{E35}\x{E48}" + text run at (0,2976) width 22: "\x{E21}\x{E38}\x{E21}" + text run at (0,3006) width 29: "\x{E2B}\x{E19}\x{E36}\x{E48}\x{E07}" + text run at (0,3036) width 29: "\x{E2A}\x{E48}\x{E27}\x{E19}" + text run at (0,3066) width 17: "\x{E42}\x{E14}" + text run at (0,3096) width 24: "\x{E42}\x{E23}\x{E18}\x{E35}" + text run at (0,3126) width 11: "\x{E21}\x{E35}" + text run at (0,3156) width 33: "\x{E40}\x{E15}\x{E35}\x{E22}\x{E07}" + text run at (0,3186) width 24: "\x{E40}\x{E25}\x{E47}\x{E01}" + text run at (0,3216) width 19: "\x{E2D}\x{E35}\x{E01}" + text run at (0,3246) width 11: "\x{E17}\x{E35}\x{E48}" + text run at (0,3276) width 22: "\x{E21}\x{E38}\x{E21}" + text run at (0,3306) width 29: "\x{E2B}\x{E19}\x{E36}\x{E48}\x{E07}" + text run at (0,3336) width 18: "\x{E44}\x{E21}\x{E48}" + text run at (0,3366) width 11: "\x{E21}\x{E35}" + text run at (0,3396) width 27: "\x{E2B}\x{E49}\x{E2D}\x{E07}" + text run at (0,3426) width 16: "\x{E43}\x{E15}\x{E49}" + text run at (0,3456) width 44: "\x{E40}\x{E1E}\x{E14}\x{E32}\x{E19}" + text run at (0,3486) width 24: "\x{E40}\x{E25}\x{E22}" + text run at (0,3516) width 27: "\x{E2B}\x{E49}\x{E2D}\x{E07}" + text run at (0,3546) width 37: "\x{E43}\x{E15}\x{E49}\x{E16}\x{E38}\x{E19}" + text run at (0,3576) width 10: "\x{E01}\x{E47}" + text run at (0,3606) width 18: "\x{E44}\x{E21}\x{E48}" + text run at (0,3636) width 11: "\x{E21}\x{E35}" + text run at (0,3666) width 25: "\x{E40}\x{E27}\x{E49}\x{E19}" + text run at (0,3696) width 20: "\x{E41}\x{E15}\x{E48}" + text run at (0,3726) width 11: "\x{E21}\x{E35}" + text run at (0,3756) width 34: "\x{E42}\x{E1E}\x{E23}\x{E07}" + text run at (0,3786) width 33: "\x{E40}\x{E25}\x{E47}\x{E01}\x{E46}" + text run at (0,3816) width 11: "\x{E17}\x{E35}\x{E48}" + text run at (0,3846) width 20: "\x{E02}\x{E38}\x{E14}" + text run at (0,3876) width 17: "\x{E44}\x{E1B}" + text run at (0,3906) width 16: "\x{E43}\x{E15}\x{E49}" + text run at (0,3936) width 22: "\x{E1E}\x{E37}\x{E49}\x{E19}" + text run at (0,3966) width 33: "\x{E40}\x{E23}\x{E35}\x{E22}\x{E01}" + text run at (0,3996) width 16: "\x{E27}\x{E48}\x{E32}" + text run at (0,4020) width 5: "\"" + text run at (0,4046) width 34: "\x{E42}\x{E1E}\x{E23}\x{E07}" + text run at (0,4076) width 54: "\x{E44}\x{E0B}\x{E42}\x{E04}\x{E25}\x{E19}" + text run at (0,4100) width 5: "\"" + text run at (0,4126) width 26: "\x{E40}\x{E1B}\x{E47}\x{E19}" + text run at (0,4156) width 11: "\x{E17}\x{E35}\x{E48}" + text run at (0,4186) width 64: "\x{E04}\x{E23}\x{E2D}\x{E1A}\x{E04}\x{E23}\x{E31}\x{E27}" + text run at (0,4216) width 11: "\x{E19}\x{E35}\x{E49}" + text run at (0,4246) width 17: "\x{E08}\x{E30}" + text run at (0,4276) width 21: "\x{E21}\x{E38}\x{E14}" + text run at (0,4306) width 22: "\x{E40}\x{E02}\x{E49}\x{E32}" + text run at (0,4336) width 17: "\x{E44}\x{E1B}" + text run at (0,4366) width 25: "\x{E40}\x{E21}\x{E37}\x{E48}\x{E2D}" + text run at (0,4396) width 25: "\x{E40}\x{E01}\x{E34}\x{E14}" + text run at (0,4426) width 20: "\x{E25}\x{E21}" + text run at (0,4456) width 28: "\x{E21}\x{E2B}\x{E32}" + text run at (0,4486) width 21: "\x{E20}\x{E31}\x{E22}" + text run at (0,4516) width 18: "\x{E0B}\x{E36}\x{E48}\x{E07}" + text run at (0,4546) width 53: "\x{E01}\x{E23}\x{E30}\x{E42}\x{E0A}\x{E01}" + text run at (0,4576) width 26: "\x{E41}\x{E23}\x{E07}" + text run at (0,4606) width 20: "\x{E08}\x{E19}" + text run at (0,4636) width 20: "\x{E1A}\x{E14}" + text run at (0,4666) width 20: "\x{E02}\x{E22}\x{E35}\x{E49}" + text run at (0,4696) width 17: "\x{E2A}\x{E34}\x{E48}\x{E07}" + text run at (0,4726) width 19: "\x{E01}\x{E48}\x{E2D}" + text run at (0,4756) width 32: "\x{E2A}\x{E23}\x{E49}\x{E32}\x{E07}" + text run at (0,4786) width 16: "\x{E43}\x{E14}" + text run at (0,4816) width 9: "\x{E46}" + text run at (0,4846) width 11: "\x{E17}\x{E35}\x{E48}" + text run at (0,4876) width 34: "\x{E02}\x{E27}\x{E32}\x{E07}" + text run at (0,4906) width 26: "\x{E17}\x{E32}\x{E07}" + text run at (0,4936) width 22: "\x{E21}\x{E31}\x{E19}" + text run at (0,4966) width 17: "\x{E44}\x{E14}\x{E49}" + text run at (0,4996) width 26: "\x{E15}\x{E23}\x{E07}" + text run at (0,5026) width 34: "\x{E01}\x{E25}\x{E32}\x{E07}" + text run at (0,5056) width 22: "\x{E1E}\x{E37}\x{E49}\x{E19}" + text run at (0,5086) width 11: "\x{E21}\x{E35}" + text run at (0,5116) width 17: "\x{E1D}\x{E32}" + text run at (0,5146) width 25: "\x{E40}\x{E1B}\x{E34}\x{E14}" + text run at (0,5176) width 22: "\x{E40}\x{E02}\x{E49}\x{E32}" + text run at (0,5206) width 17: "\x{E44}\x{E1B}" + text run at (0,5236) width 26: "\x{E08}\x{E32}\x{E01}" + text run at (0,5266) width 22: "\x{E19}\x{E31}\x{E49}\x{E19}" + text run at (0,5296) width 11: "\x{E21}\x{E35}" + text run at (0,5326) width 38: "\x{E1A}\x{E31}\x{E19}\x{E44}\x{E14}" + text run at (0,5356) width 17: "\x{E25}\x{E07}" + text run at (0,5386) width 17: "\x{E44}\x{E1B}" + text run at (0,5416) width 18: "\x{E16}\x{E36}\x{E07}" + text run at (0,5446) width 34: "\x{E42}\x{E1E}\x{E23}\x{E07}" + text run at (0,5476) width 21: "\x{E21}\x{E37}\x{E14}" + text run at (0,5506) width 24: "\x{E40}\x{E25}\x{E47}\x{E01}" + text run at (0,5536) width 9: "\x{E46}" + text run at (0,5566) width 25: "\x{E40}\x{E21}\x{E37}\x{E48}\x{E2D}" + text run at (0,5596) width 17: "\x{E42}\x{E14}" + text run at (0,5626) width 24: "\x{E42}\x{E23}\x{E18}\x{E35}" + text run at (0,5656) width 21: "\x{E22}\x{E37}\x{E19}" + text run at (0,5686) width 11: "\x{E17}\x{E35}\x{E48}" + text run at (0,5716) width 27: "\x{E1B}\x{E32}\x{E01}" + text run at (0,5746) width 36: "\x{E1B}\x{E23}\x{E30}\x{E15}\x{E39}" + text run at (0,5776) width 27: "\x{E41}\x{E25}\x{E30}" + text run at (0,5806) width 28: "\x{E21}\x{E2D}\x{E07}" + text run at (0,5836) width 17: "\x{E44}\x{E1B}" + text run at (0,5866) width 27: "\x{E23}\x{E2D}\x{E1A}" + text run at (0,5896) width 9: "\x{E46}" + text run at (0,5926) width 23: "\x{E40}\x{E18}\x{E2D}" + text run at (0,5956) width 18: "\x{E44}\x{E21}\x{E48}" + text run at (0,5986) width 26: "\x{E40}\x{E2B}\x{E47}\x{E19}" + text run at (0,6016) width 32: "\x{E2D}\x{E30}\x{E44}\x{E23}" + text run at (0,6046) width 30: "\x{E19}\x{E2D}\x{E01}" + text run at (0,6076) width 26: "\x{E08}\x{E32}\x{E01}" + text run at (0,6106) width 28: "\x{E17}\x{E49}\x{E2D}\x{E07}" + text run at (0,6136) width 19: "\x{E17}\x{E38}\x{E48}\x{E07}" + text run at (0,6166) width 34: "\x{E01}\x{E27}\x{E49}\x{E32}\x{E07}" + text run at (0,6196) width 9: "\x{E2A}\x{E35}" + text run at (0,6226) width 23: "\x{E40}\x{E17}\x{E32}" + text run at (0,6256) width 32: "\x{E2B}\x{E21}\x{E48}\x{E19}" + text run at (0,6286) width 20: "\x{E17}\x{E31}\x{E48}\x{E27}" + text run at (0,6316) width 21: "\x{E17}\x{E38}\x{E01}" + text run at (0,6346) width 28: "\x{E14}\x{E49}\x{E32}\x{E19}" + text run at (0,6376) width 18: "\x{E44}\x{E21}\x{E48}" + text run at (0,6406) width 11: "\x{E21}\x{E35}" + text run at (0,6436) width 21: "\x{E41}\x{E21}\x{E49}" + text run at (0,6466) width 39: "\x{E15}\x{E49}\x{E19}\x{E44}\x{E21}\x{E49}" + text run at (0,6496) width 19: "\x{E2A}\x{E31}\x{E01}" + text run at (0,6526) width 21: "\x{E15}\x{E49}\x{E19}" + text run at (0,6556) width 27: "\x{E2B}\x{E23}\x{E37}\x{E2D}" + text run at (0,6586) width 28: "\x{E1A}\x{E49}\x{E32}\x{E19}" + text run at (0,6616) width 19: "\x{E2A}\x{E31}\x{E01}" + text run at (0,6646) width 27: "\x{E2B}\x{E25}\x{E31}\x{E07}" + text run at (0,6676) width 11: "\x{E17}\x{E35}\x{E48}" + text run at (0,6706) width 26: "\x{E42}\x{E1C}\x{E25}\x{E48}" + text run at (0,6736) width 22: "\x{E1E}\x{E49}\x{E19}" + text run at (0,6766) width 22: "\x{E20}\x{E39}\x{E21}\x{E34}" + text run at (0,6796) width 52: "\x{E1B}\x{E23}\x{E30}\x{E40}\x{E17}\x{E28}" + text run at (0,6826) width 20: "\x{E2D}\x{E31}\x{E19}" + text run at (0,6856) width 25: "\x{E23}\x{E32}\x{E1A}" + text run at (0,6886) width 33: "\x{E40}\x{E23}\x{E35}\x{E22}\x{E1A}" + text run at (0,6916) width 20: "\x{E41}\x{E1C}\x{E48}" + text run at (0,6946) width 17: "\x{E44}\x{E1B}" + text run at (0,6976) width 26: "\x{E44}\x{E01}\x{E25}" + text run at (0,7006) width 20: "\x{E08}\x{E19}" + text run at (0,7036) width 19: "\x{E08}\x{E14}" + text run at (0,7066) width 29: "\x{E02}\x{E2D}\x{E1A}" + text run at (0,7096) width 18: "\x{E1F}\x{E49}\x{E32}" + text run at (0,7126) width 20: "\x{E17}\x{E31}\x{E48}\x{E27}" + text run at (0,7156) width 21: "\x{E17}\x{E38}\x{E01}" + text run at (0,7186) width 21: "\x{E17}\x{E34}\x{E28}" + text run at (0,7216) width 27: "\x{E14}\x{E27}\x{E07}" + text run at (0,7246) width 38: "\x{E15}\x{E30}\x{E27}\x{E31}\x{E19}" + text run at (0,7276) width 22: "\x{E40}\x{E1C}\x{E32}" + text run at (0,7306) width 21: "\x{E1C}\x{E37}\x{E19}" + text run at (0,7336) width 21: "\x{E14}\x{E34}\x{E19}" + text run at (0,7366) width 11: "\x{E17}\x{E35}\x{E48}" + text run at (0,7396) width 17: "\x{E44}\x{E16}" + text run at (0,7426) width 28: "\x{E41}\x{E25}\x{E49}\x{E27}" + text run at (0,7456) width 20: "\x{E08}\x{E19}" + text run at (0,7486) width 36: "\x{E01}\x{E25}\x{E32}\x{E22}" + text run at (0,7516) width 26: "\x{E40}\x{E1B}\x{E47}\x{E19}" + text run at (0,7546) width 31: "\x{E41}\x{E1C}\x{E48}\x{E19}" + text run at (0,7576) width 39: "\x{E21}\x{E2B}\x{E36}\x{E21}\x{E32}" + text run at (0,7606) width 9: "\x{E2A}\x{E35}" + text run at (0,7636) width 17: "\x{E14}\x{E33}" + text run at (0,7666) width 11: "\x{E21}\x{E35}" + text run at (0,7696) width 27: "\x{E23}\x{E2D}\x{E22}" + text run at (0,7726) width 30: "\x{E41}\x{E15}\x{E01}" + text run at (0,7756) width 44: "\x{E23}\x{E30}\x{E41}\x{E2B}\x{E07}" + text run at (0,7786) width 19: "\x{E2D}\x{E22}\x{E39}\x{E48}" + text run at (0,7816) width 38: "\x{E15}\x{E25}\x{E2D}\x{E14}" + text run at (0,7846) width 41: "\x{E41}\x{E21}\x{E49}\x{E41}\x{E15}\x{E48}" + text run at (0,7876) width 30: "\x{E2B}\x{E0D}\x{E49}\x{E32}" + text run at (0,7906) width 10: "\x{E01}\x{E47}" + text run at (0,7936) width 18: "\x{E44}\x{E21}\x{E48}" + text run at (0,7966) width 34: "\x{E40}\x{E02}\x{E35}\x{E22}\x{E27}" + text run at (0,7996) width 39: "\x{E40}\x{E1E}\x{E23}\x{E32}\x{E30}" + text run at (0,8026) width 27: "\x{E14}\x{E27}\x{E07}" + text run at (0,8056) width 38: "\x{E15}\x{E30}\x{E27}\x{E31}\x{E19}" + text run at (0,8086) width 22: "\x{E40}\x{E1C}\x{E32}" + text run at (0,8116) width 29: "\x{E22}\x{E2D}\x{E14}" + text run at (0,8146) width 16: "\x{E43}\x{E1A}" + text run at (0,8176) width 26: "\x{E22}\x{E32}\x{E27}" + text run at (0,8206) width 24: "\x{E40}\x{E2A}\x{E35}\x{E22}" + text run at (0,8236) width 20: "\x{E08}\x{E19}" + text run at (0,8266) width 26: "\x{E40}\x{E1B}\x{E47}\x{E19}" + text run at (0,8296) width 9: "\x{E2A}\x{E35}" + text run at (0,8326) width 23: "\x{E40}\x{E17}\x{E32}" + text run at (0,8356) width 32: "\x{E2B}\x{E21}\x{E48}\x{E19}" + text run at (0,8386) width 28: "\x{E21}\x{E2D}\x{E07}" + text run at (0,8416) width 26: "\x{E40}\x{E2B}\x{E47}\x{E19}" + text run at (0,8446) width 19: "\x{E2D}\x{E22}\x{E39}\x{E48}" + text run at (0,8476) width 20: "\x{E17}\x{E31}\x{E48}\x{E27}" + text run at (0,8506) width 17: "\x{E44}\x{E1B}" + text run at (0,8536) width 26: "\x{E04}\x{E23}\x{E31}\x{E49}\x{E07}" + text run at (0,8566) width 29: "\x{E2B}\x{E19}\x{E36}\x{E48}\x{E07}" + text run at (0,8596) width 25: "\x{E40}\x{E04}\x{E22}" + text run at (0,8626) width 18: "\x{E17}\x{E32}" + text run at (0,8656) width 9: "\x{E2A}\x{E35}" + text run at (0,8686) width 28: "\x{E1A}\x{E49}\x{E32}\x{E19}" + text run at (0,8716) width 21: "\x{E40}\x{E2D}\x{E32}" + text run at (0,8746) width 16: "\x{E44}\x{E27}\x{E49}" + text run at (0,8776) width 20: "\x{E41}\x{E15}\x{E48}" + text run at (0,8806) width 10: "\x{E01}\x{E47}" + text run at (0,8836) width 20: "\x{E16}\x{E39}\x{E01}" + text run at (0,8866) width 27: "\x{E14}\x{E27}\x{E07}" + text run at (0,8896) width 38: "\x{E15}\x{E30}\x{E27}\x{E31}\x{E19}" + text run at (0,8926) width 22: "\x{E40}\x{E1C}\x{E32}" + text run at (0,8956) width 24: "\x{E40}\x{E2A}\x{E35}\x{E22}" + text run at (0,8986) width 20: "\x{E08}\x{E19}" + text run at (0,9016) width 9: "\x{E2A}\x{E35}" + text run at (0,9046) width 28: "\x{E1E}\x{E2D}\x{E07}" + text run at (0,9076) width 28: "\x{E41}\x{E25}\x{E49}\x{E27}" + text run at (0,9106) width 21: "\x{E1D}\x{E19}" + text run at (0,9136) width 10: "\x{E01}\x{E47}" + text run at (0,9166) width 18: "\x{E0A}\x{E30}" + text run at (0,9196) width 22: "\x{E21}\x{E31}\x{E19}" + text run at (0,9226) width 29: "\x{E2B}\x{E25}\x{E38}\x{E14}" + text run at (0,9256) width 17: "\x{E44}\x{E1B}" + text run at (0,9286) width 20: "\x{E08}\x{E19}" + text run at (0,9316) width 31: "\x{E2B}\x{E21}\x{E14}" + text run at (0,9346) width 27: "\x{E41}\x{E25}\x{E30}" + text run at (0,9376) width 30: "\x{E15}\x{E2D}\x{E19}" + text run at (0,9406) width 11: "\x{E19}\x{E35}\x{E49}" + text run at (0,9436) width 28: "\x{E1A}\x{E49}\x{E32}\x{E19}" + text run at (0,9466) width 17: "\x{E08}\x{E36}\x{E07}" + text run at (0,9496) width 10: "\x{E14}\x{E39}" + text run at (0,9526) width 70: "\x{E2B}\x{E21}\x{E48}\x{E19}\x{E2B}\x{E21}\x{E2D}\x{E07}" + text run at (0,9556) width 26: "\x{E40}\x{E1B}\x{E47}\x{E19}" + text run at (0,9586) width 9: "\x{E2A}\x{E35}" + text run at (0,9616) width 23: "\x{E40}\x{E17}\x{E32}" + text run at (0,9646) width 46: "\x{E40}\x{E2B}\x{E21}\x{E37}\x{E2D}\x{E19}" + text run at (0,9676) width 17: "\x{E2A}\x{E34}\x{E48}\x{E07}" + text run at (0,9706) width 20: "\x{E2D}\x{E37}\x{E48}\x{E19}" + text run at (0,9736) width 9: "\x{E46}" + text run at (0,9766) width 29: "\x{E14}\x{E49}\x{E27}\x{E22}" + text run at (0,9796) width 30: "\x{E15}\x{E2D}\x{E19}" + text run at (0,9826) width 11: "\x{E17}\x{E35}\x{E48}" + text run at (0,9856) width 17: "\x{E1B}\x{E49}\x{E32}" + text run at (0,9886) width 25: "\x{E40}\x{E2D}\x{E47}\x{E21}" + text run at (0,9916) width 27: "\x{E22}\x{E49}\x{E32}\x{E22}" + text run at (0,9946) width 18: "\x{E21}\x{E32}" + text run at (0,9976) width 19: "\x{E2D}\x{E22}\x{E39}\x{E48}" + text run at (0,10006) width 11: "\x{E17}\x{E35}\x{E48}" + text run at (0,10036) width 11: "\x{E19}\x{E35}\x{E48}" + text run at (0,10066) width 23: "\x{E40}\x{E18}\x{E2D}" + text run at (0,10096) width 18: "\x{E22}\x{E31}\x{E07}" + text run at (0,10126) width 25: "\x{E2A}\x{E32}\x{E27}" + text run at (0,10156) width 26: "\x{E40}\x{E1B}\x{E47}\x{E19}" + text run at (0,10186) width 44: "\x{E20}\x{E23}\x{E23}\x{E22}\x{E32}" + text run at (0,10216) width 11: "\x{E17}\x{E35}\x{E48}" + text run at (0,10246) width 44: "\x{E07}\x{E14}\x{E07}\x{E32}\x{E21}" + text run at (0,10276) width 28: "\x{E41}\x{E25}\x{E49}\x{E27}" + text run at (0,10306) width 30: "\x{E41}\x{E14}\x{E14}" + text run at (0,10336) width 27: "\x{E41}\x{E25}\x{E30}" + text run at (0,10366) width 20: "\x{E25}\x{E21}" + text run at (0,10396) width 10: "\x{E01}\x{E47}" + text run at (0,10426) width 17: "\x{E44}\x{E14}\x{E49}" + text run at (0,10456) width 45: "\x{E40}\x{E1B}\x{E25}\x{E35}\x{E48}\x{E22}\x{E19}" + text run at (0,10486) width 23: "\x{E40}\x{E18}\x{E2D}" + text run at (0,10516) width 17: "\x{E44}\x{E1B}" + text run at (0,10546) width 21: "\x{E40}\x{E2D}\x{E32}" + text run at (0,10576) width 53: "\x{E1B}\x{E23}\x{E30}\x{E01}\x{E32}\x{E22}" + text run at (0,10606) width 17: "\x{E44}\x{E1B}" + text run at (0,10636) width 26: "\x{E08}\x{E32}\x{E01}" + text run at (0,10666) width 44: "\x{E14}\x{E27}\x{E07}\x{E15}\x{E32}" + text run at (0,10696) width 23: "\x{E40}\x{E18}\x{E2D}" + text run at (0,10726) width 38: "\x{E1B}\x{E25}\x{E48}\x{E2D}\x{E22}" + text run at (0,10756) width 16: "\x{E44}\x{E27}\x{E49}" + text run at (0,10786) width 20: "\x{E41}\x{E15}\x{E48}" + text run at (0,10816) width 37: "\x{E04}\x{E27}\x{E32}\x{E21}" + text run at (0,10846) width 30: "\x{E2A}\x{E38}\x{E02}\x{E38}\x{E21}" + text run at (0,10876) width 34: "\x{E2D}\x{E22}\x{E48}\x{E32}\x{E07}" + text run at (0,10906) width 70: "\x{E2B}\x{E21}\x{E48}\x{E19}\x{E2B}\x{E21}\x{E2D}\x{E07}" + text run at (0,10936) width 21: "\x{E40}\x{E2D}\x{E32}" + text run at (0,10966) width 9: "\x{E2A}\x{E35}" + text run at (0,10996) width 28: "\x{E41}\x{E14}\x{E07}" + text run at (0,11026) width 26: "\x{E08}\x{E32}\x{E01}" + text run at (0,11056) width 31: "\x{E41}\x{E01}\x{E49}\x{E21}" + text run at (0,11086) width 27: "\x{E41}\x{E25}\x{E30}" + text run at (0,11116) width 19: "\x{E23}\x{E34}\x{E21}" + text run at (0,11146) width 37: "\x{E1D}\x{E35}\x{E1B}\x{E32}\x{E01}" + text run at (0,11176) width 23: "\x{E40}\x{E18}\x{E2D}" + text run at (0,11206) width 17: "\x{E44}\x{E1B}" + text run at (0,11236) width 36: "\x{E01}\x{E25}\x{E32}\x{E22}" + text run at (0,11266) width 26: "\x{E40}\x{E1B}\x{E47}\x{E19}" + text run at (0,11296) width 9: "\x{E2A}\x{E35}" + text run at (0,11326) width 32: "\x{E2B}\x{E21}\x{E48}\x{E19}" + text run at (0,11356) width 9: "\x{E46}" + text run at (0,11386) width 46: "\x{E40}\x{E2B}\x{E21}\x{E37}\x{E2D}\x{E19}" + text run at (0,11416) width 21: "\x{E01}\x{E31}\x{E19}" + text run at (0,11446) width 23: "\x{E40}\x{E18}\x{E2D}" + text run at (0,11476) width 30: "\x{E1C}\x{E2D}\x{E21}" + text run at (0,11506) width 27: "\x{E41}\x{E25}\x{E30}" + text run at (0,11536) width 27: "\x{E2B}\x{E25}\x{E31}\x{E07}" + text run at (0,11566) width 25: "\x{E42}\x{E04}\x{E49}\x{E07}" + text run at (0,11596) width 27: "\x{E41}\x{E25}\x{E30}" + text run at (0,11626) width 34: "\x{E40}\x{E14}\x{E35}\x{E4B}\x{E22}\x{E27}" + text run at (0,11656) width 11: "\x{E19}\x{E35}\x{E49}" + text run at (0,11686) width 18: "\x{E44}\x{E21}\x{E48}" + text run at (0,11716) width 25: "\x{E40}\x{E04}\x{E22}" + text run at (0,11746) width 21: "\x{E22}\x{E34}\x{E49}\x{E21}" + text run at (0,11776) width 24: "\x{E40}\x{E25}\x{E22}" + text run at (0,11806) width 25: "\x{E40}\x{E21}\x{E37}\x{E48}\x{E2D}" + text run at (0,11836) width 17: "\x{E42}\x{E14}" + text run at (0,11866) width 24: "\x{E42}\x{E23}\x{E18}\x{E35}" + text run at (0,11896) width 18: "\x{E0B}\x{E36}\x{E48}\x{E07}" + text run at (0,11926) width 26: "\x{E40}\x{E1B}\x{E47}\x{E19}" + text run at (0,11956) width 25: "\x{E40}\x{E14}\x{E47}\x{E01}" + text run at (0,11986) width 43: "\x{E01}\x{E33}\x{E1E}\x{E23}\x{E49}\x{E32}" + text run at (0,12016) width 18: "\x{E21}\x{E32}" + text run at (0,12046) width 19: "\x{E2D}\x{E22}\x{E39}\x{E48}" + text run at (0,12076) width 20: "\x{E01}\x{E31}\x{E1A}" + text run at (0,12106) width 23: "\x{E40}\x{E18}\x{E2D}" + text run at (0,12136) width 30: "\x{E15}\x{E2D}\x{E19}" + text run at (0,12166) width 28: "\x{E41}\x{E23}\x{E01}" + text run at (0,12196) width 17: "\x{E1B}\x{E49}\x{E32}" + text run at (0,12226) width 25: "\x{E40}\x{E2D}\x{E47}\x{E21}" + text run at (0,12256) width 21: "\x{E15}\x{E37}\x{E48}\x{E19}" + text run at (0,12286) width 26: "\x{E40}\x{E15}\x{E49}\x{E19}" + text run at (0,12316) width 20: "\x{E01}\x{E31}\x{E1A}" + text run at (0,12346) width 32: "\x{E40}\x{E2A}\x{E35}\x{E22}\x{E07}" + text run at (0,12376) width 47: "\x{E2B}\x{E31}\x{E27}\x{E40}\x{E23}\x{E32}\x{E30}" + text run at (0,12406) width 27: "\x{E02}\x{E2D}\x{E07}" + text run at (0,12436) width 25: "\x{E40}\x{E14}\x{E47}\x{E01}" + text run at (0,12466) width 30: "\x{E19}\x{E49}\x{E2D}\x{E22}" + text run at (0,12496) width 28: "\x{E21}\x{E32}\x{E01}" + text run at (0,12526) width 23: "\x{E40}\x{E18}\x{E2D}" + text run at (0,12556) width 17: "\x{E08}\x{E30}" + text run at (0,12586) width 17: "\x{E2A}\x{E48}\x{E07}" + text run at (0,12616) width 32: "\x{E40}\x{E2A}\x{E35}\x{E22}\x{E07}" + text run at (0,12646) width 25: "\x{E23}\x{E49}\x{E2D}\x{E07}" + text run at (0,12676) width 28: "\x{E41}\x{E25}\x{E49}\x{E27}" + text run at (0,12706) width 21: "\x{E40}\x{E2D}\x{E32}" + text run at (0,12736) width 20: "\x{E21}\x{E37}\x{E2D}" + text run at (0,12766) width 28: "\x{E17}\x{E32}\x{E1A}" + text run at (0,12796) width 19: "\x{E2D}\x{E01}" + text run at (0,12826) width 21: "\x{E17}\x{E38}\x{E01}" + text run at (0,12856) width 26: "\x{E04}\x{E23}\x{E31}\x{E49}\x{E07}" + text run at (0,12886) width 11: "\x{E17}\x{E35}\x{E48}" + text run at (0,12916) width 32: "\x{E40}\x{E2A}\x{E35}\x{E22}\x{E07}" + text run at (0,12946) width 20: "\x{E2D}\x{E31}\x{E19}" + text run at (0,12976) width 36: "\x{E23}\x{E48}\x{E32}\x{E40}\x{E23}\x{E34}\x{E07}" + text run at (0,13006) width 27: "\x{E02}\x{E2D}\x{E07}" + text run at (0,13036) width 17: "\x{E42}\x{E14}" + text run at (0,13066) width 24: "\x{E42}\x{E23}\x{E18}\x{E35}" + text run at (0,13096) width 22: "\x{E40}\x{E02}\x{E49}\x{E32}" + text run at (0,13126) width 10: "\x{E2B}\x{E39}" + text run at (0,13156) width 23: "\x{E40}\x{E18}\x{E2D}" + text run at (0,13186) width 27: "\x{E41}\x{E25}\x{E30}" + text run at (0,13216) width 23: "\x{E40}\x{E18}\x{E2D}" + text run at (0,13246) width 22: "\x{E40}\x{E1D}\x{E49}\x{E32}" + text run at (0,13276) width 28: "\x{E21}\x{E2D}\x{E07}" + text run at (0,13306) width 25: "\x{E40}\x{E14}\x{E47}\x{E01}" + text run at (0,13336) width 31: "\x{E2B}\x{E0D}\x{E34}\x{E07}" + text run at (0,13366) width 30: "\x{E19}\x{E49}\x{E2D}\x{E22}" + text run at (0,13396) width 9: "\x{E46}" + text run at (0,13426) width 29: "\x{E14}\x{E49}\x{E27}\x{E22}" + text run at (0,13456) width 37: "\x{E04}\x{E27}\x{E32}\x{E21}" + text run at (0,13486) width 62: "\x{E1B}\x{E23}\x{E30}\x{E2B}\x{E25}\x{E32}\x{E14}" + text run at (0,13516) width 15: "\x{E43}\x{E08}" + text run at (0,13546) width 29: "\x{E14}\x{E49}\x{E27}\x{E22}" + text run at (0,13576) width 18: "\x{E22}\x{E31}\x{E07}" + text run at (0,13606) width 17: "\x{E2B}\x{E32}" + text run at (0,13636) width 32: "\x{E2D}\x{E30}\x{E44}\x{E23}" + text run at (0,13666) width 18: "\x{E21}\x{E32}" + text run at (0,13696) width 26: "\x{E40}\x{E1B}\x{E47}\x{E19}" + text run at (0,13726) width 30: "\x{E40}\x{E23}\x{E37}\x{E48}\x{E2D}\x{E07}" + text run at (0,13756) width 47: "\x{E2B}\x{E31}\x{E27}\x{E40}\x{E23}\x{E32}\x{E30}" + text run at (0,13786) width 17: "\x{E44}\x{E14}\x{E49}" + text run at (0,13816) width 17: "\x{E25}\x{E38}\x{E07}" + text run at (0,13846) width 14: "\x{E40}\x{E2E}" + text run at (0,13876) width 19: "\x{E19}\x{E23}\x{E35}" + text run at (0,13906) width 18: "\x{E44}\x{E21}\x{E48}" + text run at (0,13936) width 25: "\x{E40}\x{E04}\x{E22}" + text run at (0,13966) width 47: "\x{E2B}\x{E31}\x{E27}\x{E40}\x{E23}\x{E32}\x{E30}" + text run at (0,13996) width 17: "\x{E25}\x{E38}\x{E07}" + text run at (0,14026) width 44: "\x{E17}\x{E33}\x{E07}\x{E32}\x{E19}" + text run at (0,14056) width 31: "\x{E2B}\x{E19}\x{E31}\x{E01}" + text run at (0,14086) width 26: "\x{E08}\x{E32}\x{E01}" + text run at (0,14116) width 22: "\x{E40}\x{E0A}\x{E49}\x{E32}" + text run at (0,14146) width 21: "\x{E22}\x{E31}\x{E19}" + text run at (0,14176) width 17: "\x{E04}\x{E48}\x{E33}" + text run at (0,14206) width 27: "\x{E41}\x{E25}\x{E30}" + text run at (0,14236) width 18: "\x{E44}\x{E21}\x{E48}" + text run at (0,14266) width 25: "\x{E40}\x{E04}\x{E22}" + text run at (0,14296) width 27: "\x{E23}\x{E39}\x{E49}\x{E08}\x{E31}\x{E01}" + text run at (0,14326) width 16: "\x{E27}\x{E48}\x{E32}" + text run at (0,14356) width 37: "\x{E04}\x{E27}\x{E32}\x{E21}" + text run at (0,14386) width 36: "\x{E23}\x{E48}\x{E32}\x{E40}\x{E23}\x{E34}\x{E07}" + text run at (0,14416) width 19: "\x{E04}\x{E37}\x{E2D}" + text run at (0,14446) width 32: "\x{E2D}\x{E30}\x{E44}\x{E23}" + text run at (0,14476) width 17: "\x{E25}\x{E38}\x{E07}" + text run at (0,14506) width 10: "\x{E14}\x{E39}" + text run at (0,14536) width 70: "\x{E2B}\x{E21}\x{E48}\x{E19}\x{E2B}\x{E21}\x{E2D}\x{E07}" + text run at (0,14566) width 17: "\x{E44}\x{E1B}" + text run at (0,14596) width 31: "\x{E2B}\x{E21}\x{E14}" + text run at (0,14626) width 18: "\x{E15}\x{E31}\x{E49}\x{E07}" + text run at (0,14656) width 20: "\x{E41}\x{E15}\x{E48}" + text run at (0,14686) width 30: "\x{E40}\x{E04}\x{E23}\x{E32}" + text run at (0,14716) width 26: "\x{E22}\x{E32}\x{E27}" + text run at (0,14746) width 20: "\x{E08}\x{E19}" + text run at (0,14776) width 19: "\x{E08}\x{E14}" + text run at (0,14806) width 48: "\x{E23}\x{E2D}\x{E07}\x{E40}\x{E17}\x{E49}\x{E32}" + text run at (0,14836) width 20: "\x{E1A}\x{E39}\x{E15}" + text run at (0,14866) width 20: "\x{E2D}\x{E31}\x{E19}" + text run at (0,14896) width 37: "\x{E2B}\x{E22}\x{E32}\x{E1A}" + text run at (0,14926) width 28: "\x{E41}\x{E25}\x{E49}\x{E27}" + text run at (0,14956) width 17: "\x{E25}\x{E38}\x{E07}" + text run at (0,14986) width 10: "\x{E01}\x{E47}" + text run at (0,15016) width 10: "\x{E14}\x{E39}" + text run at (0,15046) width 60: "\x{E40}\x{E04}\x{E23}\x{E48}\x{E07}\x{E02}\x{E23}\x{E36}\x{E21}" + text run at (0,15076) width 18: "\x{E19}\x{E48}\x{E32}" + text run at (0,15106) width 31: "\x{E40}\x{E01}\x{E23}\x{E07}" + text run at (0,15136) width 28: "\x{E02}\x{E32}\x{E21}" + text run at (0,15166) width 18: "\x{E44}\x{E21}\x{E48}" + text run at (0,15196) width 29: "\x{E04}\x{E48}\x{E2D}\x{E22}" + text run at (0,15226) width 17: "\x{E08}\x{E30}" + text run at (0,15256) width 21: "\x{E1E}\x{E39}\x{E14}" + text run at (0,15286) width 11: "\x{E21}\x{E35}" + text run at (0,15316) width 17: "\x{E42}\x{E15}" + text run at (0,15346) width 17: "\x{E42}\x{E15}\x{E49}" + text run at (0,15376) width 11: "\x{E17}\x{E35}\x{E48}" + text run at (0,15406) width 18: "\x{E17}\x{E33}" + text run at (0,15436) width 16: "\x{E43}\x{E2B}\x{E49}" + text run at (0,15466) width 17: "\x{E42}\x{E14}" + text run at (0,15496) width 24: "\x{E42}\x{E23}\x{E18}\x{E35}" + text run at (0,15526) width 47: "\x{E2B}\x{E31}\x{E27}\x{E40}\x{E23}\x{E32}\x{E30}" + text run at (0,15556) width 17: "\x{E44}\x{E14}\x{E49}" + text run at (0,15586) width 27: "\x{E41}\x{E25}\x{E30}" + text run at (0,15616) width 29: "\x{E0A}\x{E48}\x{E27}\x{E22}" + text run at (0,15646) width 23: "\x{E40}\x{E18}\x{E2D}" + text run at (0,15676) width 16: "\x{E43}\x{E2B}\x{E49}" + text run at (0,15706) width 22: "\x{E1E}\x{E49}\x{E19}" + text run at (0,15736) width 26: "\x{E08}\x{E32}\x{E01}" + text run at (0,15766) width 25: "\x{E01}\x{E32}\x{E23}" + text run at (0,15796) width 36: "\x{E01}\x{E25}\x{E32}\x{E22}" + text run at (0,15826) width 26: "\x{E40}\x{E1B}\x{E47}\x{E19}" + text run at (0,15856) width 9: "\x{E2A}\x{E35}" + text run at (0,15886) width 23: "\x{E40}\x{E17}\x{E32}" + text run at (0,15916) width 32: "\x{E2B}\x{E21}\x{E48}\x{E19}" + text run at (0,15946) width 46: "\x{E40}\x{E2B}\x{E21}\x{E37}\x{E2D}\x{E19}" + text run at (0,15976) width 20: "\x{E01}\x{E31}\x{E1A}" + text run at (0,16006) width 17: "\x{E2A}\x{E34}\x{E48}\x{E07}" + text run at (0,16036) width 27: "\x{E23}\x{E2D}\x{E1A}" + text run at (0,16066) width 19: "\x{E15}\x{E31}\x{E27}" + text run at (0,16096) width 20: "\x{E2D}\x{E37}\x{E48}\x{E19}" + text run at (0,16126) width 9: "\x{E46}" + text run at (0,16156) width 17: "\x{E42}\x{E15}" + text run at (0,16186) width 17: "\x{E42}\x{E15}\x{E49}" + text run at (0,16216) width 9: "\x{E2A}\x{E35}" + text run at (0,16246) width 18: "\x{E44}\x{E21}\x{E48}" + text run at (0,16276) width 23: "\x{E40}\x{E17}\x{E32}" + text run at (0,16306) width 32: "\x{E2B}\x{E21}\x{E48}\x{E19}" + text run at (0,16336) width 20: "\x{E41}\x{E15}\x{E48}" + text run at (0,16366) width 22: "\x{E21}\x{E31}\x{E19}" + text run at (0,16396) width 26: "\x{E40}\x{E1B}\x{E47}\x{E19}" + text run at (0,16426) width 28: "\x{E2B}\x{E21}\x{E32}" + text run at (0,16456) width 9: "\x{E2A}\x{E35}" + text run at (0,16486) width 17: "\x{E14}\x{E33}" + text run at (0,16516) width 19: "\x{E15}\x{E31}\x{E27}" + text run at (0,16546) width 30: "\x{E19}\x{E49}\x{E2D}\x{E22}" + text run at (0,16576) width 9: "\x{E46}" + text run at (0,16606) width 21: "\x{E02}\x{E19}" + text run at (0,16636) width 26: "\x{E22}\x{E32}\x{E27}" + text run at (0,16666) width 20: "\x{E1B}\x{E38}\x{E22}" + text run at (0,16696) width 24: "\x{E23}\x{E32}\x{E27}" + text run at (0,16726) width 20: "\x{E01}\x{E31}\x{E1A}" + text run at (0,16756) width 28: "\x{E44}\x{E2B}\x{E21}" + text run at (0,16786) width 11: "\x{E21}\x{E35}" + text run at (0,16816) width 17: "\x{E15}\x{E32}" + text run at (0,16846) width 17: "\x{E14}\x{E33}" + text run at (0,16876) width 24: "\x{E40}\x{E25}\x{E47}\x{E01}" + text run at (0,16906) width 26: "\x{E40}\x{E1B}\x{E47}\x{E19}" + text run at (0,16936) width 53: "\x{E1B}\x{E23}\x{E30}\x{E01}\x{E32}\x{E22}" + text run at (0,16966) width 40: "\x{E23}\x{E37}\x{E48}\x{E19}\x{E40}\x{E23}\x{E34}\x{E07}" + text run at (0,16996) width 19: "\x{E2D}\x{E22}\x{E39}\x{E48}" + text run at (0,17026) width 26: "\x{E2A}\x{E2D}\x{E07}" + text run at (0,17056) width 25: "\x{E02}\x{E49}\x{E32}\x{E07}" + text run at (0,17086) width 30: "\x{E08}\x{E21}\x{E39}\x{E01}" + text run at (0,17116) width 24: "\x{E40}\x{E25}\x{E47}\x{E01}" + text run at (0,17146) width 20: "\x{E2D}\x{E31}\x{E19}" + text run at (0,17176) width 18: "\x{E19}\x{E48}\x{E32}" + text run at (0,17206) width 21: "\x{E02}\x{E31}\x{E19}" + text run at (0,17236) width 27: "\x{E02}\x{E2D}\x{E07}" + text run at (0,17266) width 22: "\x{E21}\x{E31}\x{E19}" + text run at (0,17296) width 17: "\x{E42}\x{E15}" + text run at (0,17326) width 17: "\x{E42}\x{E15}\x{E49}" + text run at (0,17356) width 25: "\x{E40}\x{E25}\x{E48}\x{E19}" + text run at (0,17386) width 19: "\x{E17}\x{E31}\x{E49}\x{E07}" + text run at (0,17416) width 20: "\x{E27}\x{E31}\x{E19}" + text run at (0,17446) width 27: "\x{E41}\x{E25}\x{E30}" + text run at (0,17476) width 17: "\x{E42}\x{E14}" + text run at (0,17506) width 24: "\x{E42}\x{E23}\x{E18}\x{E35}" + text run at (0,17536) width 10: "\x{E01}\x{E47}" + text run at (0,17566) width 25: "\x{E40}\x{E25}\x{E48}\x{E19}" + text run at (0,17596) width 20: "\x{E01}\x{E31}\x{E1A}" + text run at (0,17626) width 22: "\x{E21}\x{E31}\x{E19}" + text run at (0,17656) width 27: "\x{E41}\x{E25}\x{E30}" + text run at (0,17686) width 18: "\x{E23}\x{E31}\x{E01}" + text run at (0,17716) width 22: "\x{E21}\x{E31}\x{E19}" + text run at (0,17746) width 33: "\x{E40}\x{E2B}\x{E25}\x{E37}\x{E2D}" + text run at (0,17776) width 26: "\x{E40}\x{E01}\x{E34}\x{E19}" + text run at (0,17806) width 49: "\x{E2D}\x{E22}\x{E48}\x{E32}\x{E07}\x{E44}\x{E23}" + text run at (0,17836) width 10: "\x{E01}\x{E47}" + text run at (0,17866) width 28: "\x{E15}\x{E32}\x{E21}" + text run at (0,17896) width 20: "\x{E27}\x{E31}\x{E19}" + text run at (0,17926) width 11: "\x{E19}\x{E35}\x{E49}" + text run at (0,17956) width 19: "\x{E17}\x{E31}\x{E49}\x{E07}" + text run at (0,17986) width 10: "\x{E04}\x{E39}\x{E48}" + text run at (0,18016) width 18: "\x{E44}\x{E21}\x{E48}" + text run at (0,18046) width 17: "\x{E44}\x{E14}\x{E49}" + text run at (0,18076) width 25: "\x{E40}\x{E25}\x{E48}\x{E19}" + text run at (0,18106) width 17: "\x{E25}\x{E38}\x{E07}" + text run at (0,18136) width 14: "\x{E40}\x{E2E}" + text run at (0,18166) width 19: "\x{E19}\x{E23}\x{E35}" + text run at (0,18196) width 19: "\x{E19}\x{E31}\x{E48}\x{E07}" + text run at (0,18226) width 19: "\x{E2D}\x{E22}\x{E39}\x{E48}" + text run at (0,18256) width 11: "\x{E17}\x{E35}\x{E48}" + text run at (0,18286) width 38: "\x{E1A}\x{E31}\x{E19}\x{E44}\x{E14}" + text run at (0,18316) width 36: "\x{E1B}\x{E23}\x{E30}\x{E15}\x{E39}" + text run at (0,18346) width 27: "\x{E41}\x{E25}\x{E30}" + text run at (0,18376) width 22: "\x{E40}\x{E1D}\x{E49}\x{E32}" + text run at (0,18406) width 36: "\x{E01}\x{E31}\x{E07}\x{E27}\x{E25}" + text run at (0,18436) width 26: "\x{E08}\x{E49}\x{E2D}\x{E07}" + text run at (0,18466) width 10: "\x{E14}\x{E39}" + text run at (0,18496) width 28: "\x{E17}\x{E49}\x{E2D}\x{E07}" + text run at (0,18526) width 18: "\x{E1F}\x{E49}\x{E32}" + text run at (0,18556) width 9: "\x{E2A}\x{E35}" + text run at (0,18586) width 23: "\x{E40}\x{E17}\x{E32}" + text run at (0,18616) width 32: "\x{E2B}\x{E21}\x{E48}\x{E19}" + text run at (0,18646) width 20: "\x{E1C}\x{E34}\x{E14}" + text run at (0,18676) width 30: "\x{E1B}\x{E01}\x{E15}\x{E34}" + text run at (0,18706) width 17: "\x{E42}\x{E14}" + text run at (0,18736) width 24: "\x{E42}\x{E23}\x{E18}\x{E35}" + text run at (0,18766) width 21: "\x{E22}\x{E37}\x{E19}" + text run at (0,18796) width 11: "\x{E17}\x{E35}\x{E48}" + text run at (0,18826) width 36: "\x{E1B}\x{E23}\x{E30}\x{E15}\x{E39}" + text run at (0,18856) width 29: "\x{E01}\x{E2D}\x{E14}" + text run at (0,18886) width 17: "\x{E42}\x{E15}" + text run at (0,18916) width 17: "\x{E42}\x{E15}\x{E49}" + text run at (0,18946) width 16: "\x{E44}\x{E27}\x{E49}" + text run at (0,18976) width 17: "\x{E43}\x{E19}" + text run at (0,19006) width 29: "\x{E2D}\x{E49}\x{E2D}\x{E21}" + text run at (0,19036) width 31: "\x{E41}\x{E02}\x{E19}" + text run at (0,19066) width 27: "\x{E41}\x{E25}\x{E30}" + text run at (0,19096) width 10: "\x{E01}\x{E47}" + text run at (0,19126) width 28: "\x{E21}\x{E2D}\x{E07}" + text run at (0,19156) width 10: "\x{E14}\x{E39}" + text run at (0,19186) width 28: "\x{E17}\x{E49}\x{E2D}\x{E07}" + text run at (0,19216) width 18: "\x{E1F}\x{E49}\x{E32}" + text run at (0,19246) width 19: "\x{E2D}\x{E22}\x{E39}\x{E48}" + text run at (0,19276) width 46: "\x{E40}\x{E2B}\x{E21}\x{E37}\x{E2D}\x{E19}" + text run at (0,19306) width 21: "\x{E01}\x{E31}\x{E19}" + text run at (0,19336) width 17: "\x{E1B}\x{E49}\x{E32}" + text run at (0,19366) width 25: "\x{E40}\x{E2D}\x{E47}\x{E21}" + text run at (0,19396) width 34: "\x{E01}\x{E33}\x{E25}\x{E31}\x{E07}" + text run at (0,19426) width 24: "\x{E25}\x{E49}\x{E32}\x{E07}" + text run at (0,19456) width 28: "\x{E0A}\x{E32}\x{E21}" + text run at (0,19486) width 19: "\x{E2D}\x{E22}\x{E39}\x{E48}" + text run at (0,19516) width 26: "\x{E08}\x{E32}\x{E01}" + text run at (0,19546) width 28: "\x{E14}\x{E49}\x{E32}\x{E19}" + text run at (0,19576) width 35: "\x{E40}\x{E2B}\x{E19}\x{E37}\x{E2D}" + text run at (0,19606) width 26: "\x{E44}\x{E01}\x{E25}" + text run at (0,19636) width 28: "\x{E2D}\x{E2D}\x{E01}" + text run at (0,19666) width 17: "\x{E44}\x{E1B}" + text run at (0,19696) width 11: "\x{E21}\x{E35}" + text run at (0,19726) width 32: "\x{E40}\x{E2A}\x{E35}\x{E22}\x{E07}" + text run at (0,19756) width 20: "\x{E25}\x{E21}" + text run at (0,19786) width 33: "\x{E04}\x{E23}\x{E32}\x{E07}" + text run at (0,19816) width 29: "\x{E41}\x{E1C}\x{E48}\x{E27}" + text run at (0,19846) width 22: "\x{E40}\x{E1A}\x{E32}" + text run at (0,19876) width 38: "\x{E44}\x{E14}\x{E49}\x{E22}\x{E34}\x{E19}" + text run at (0,19906) width 18: "\x{E21}\x{E32}" + text run at (0,19936) width 17: "\x{E25}\x{E38}\x{E07}" + text run at (0,19966) width 14: "\x{E40}\x{E2E}" + text run at (0,19996) width 19: "\x{E19}\x{E23}\x{E35}" + text run at (0,20026) width 27: "\x{E41}\x{E25}\x{E30}" + text run at (0,20056) width 17: "\x{E42}\x{E14}" + text run at (0,20086) width 24: "\x{E42}\x{E23}\x{E18}\x{E35}" + text run at (0,20116) width 26: "\x{E40}\x{E2B}\x{E47}\x{E19}" + text run at (0,20146) width 21: "\x{E15}\x{E49}\x{E19}" + text run at (0,20176) width 30: "\x{E2B}\x{E0D}\x{E49}\x{E32}" + text run at (0,20206) width 17: "\x{E2A}\x{E39}\x{E07}" + text run at (0,20236) width 25: "\x{E40}\x{E2D}\x{E19}" + text run at (0,20266) width 26: "\x{E40}\x{E1B}\x{E47}\x{E19}" + text run at (0,20296) width 30: "\x{E04}\x{E25}\x{E37}\x{E48}\x{E19}" + text run at (0,20326) width 30: "\x{E01}\x{E48}\x{E2D}\x{E19}" + text run at (0,20356) width 11: "\x{E17}\x{E35}\x{E48}" + text run at (0,20386) width 28: "\x{E1E}\x{E32}\x{E22}\x{E38}" + text run at (0,20416) width 17: "\x{E08}\x{E30}" + text run at (0,20446) width 18: "\x{E21}\x{E32}" + text run at (0,20476) width 18: "\x{E16}\x{E36}\x{E07}" + text run at (0,20506) width 28: "\x{E41}\x{E25}\x{E49}\x{E27}" + text run at (0,20536) width 10: "\x{E01}\x{E47}" + text run at (0,20566) width 11: "\x{E21}\x{E35}" + text run at (0,20596) width 32: "\x{E40}\x{E2A}\x{E35}\x{E22}\x{E07}" + text run at (0,20626) width 29: "\x{E2B}\x{E27}\x{E35}\x{E14}" + text run at (0,20656) width 28: "\x{E2B}\x{E27}\x{E34}\x{E27}" + text run at (0,20686) width 45: "\x{E0A}\x{E31}\x{E14}\x{E40}\x{E08}\x{E19}" + text run at (0,20716) width 18: "\x{E21}\x{E32}" + text run at (0,20746) width 26: "\x{E08}\x{E32}\x{E01}" + text run at (0,20776) width 70: "\x{E1A}\x{E23}\x{E23}\x{E22}\x{E32}\x{E01}\x{E32}\x{E28}" + text run at (0,20806) width 26: "\x{E17}\x{E32}\x{E07}" + text run at (0,20836) width 16: "\x{E43}\x{E15}\x{E49}" + text run at (0,20866) width 27: "\x{E41}\x{E25}\x{E30}" + text run at (0,20896) width 25: "\x{E40}\x{E21}\x{E37}\x{E48}\x{E2D}" + text run at (0,20926) width 43: "\x{E40}\x{E2B}\x{E25}\x{E37}\x{E2D}\x{E1A}" + text run at (0,20956) width 17: "\x{E15}\x{E32}" + text run at (0,20986) width 17: "\x{E44}\x{E1B}" + text run at (0,21016) width 26: "\x{E17}\x{E32}\x{E07}" + text run at (0,21046) width 28: "\x{E14}\x{E49}\x{E32}\x{E19}" + text run at (0,21076) width 22: "\x{E19}\x{E31}\x{E49}\x{E19}" + text run at (0,21106) width 10: "\x{E01}\x{E47}" + text run at (0,21136) width 26: "\x{E40}\x{E2B}\x{E47}\x{E19}" + text run at (0,21166) width 30: "\x{E04}\x{E25}\x{E37}\x{E48}\x{E19}" + text run at (0,21196) width 30: "\x{E2B}\x{E0D}\x{E49}\x{E32}" + text run at (0,21226) width 18: "\x{E21}\x{E32}" + text run at (0,21256) width 26: "\x{E17}\x{E32}\x{E07}" + text run at (0,21286) width 28: "\x{E14}\x{E49}\x{E32}\x{E19}" + text run at (0,21316) width 22: "\x{E19}\x{E31}\x{E49}\x{E19}" + text run at (0,21346) width 29: "\x{E14}\x{E49}\x{E27}\x{E22}" + text run at (0,21376) width 17: "\x{E25}\x{E38}\x{E07}" + text run at (0,21406) width 14: "\x{E40}\x{E2E}" + text run at (0,21436) width 19: "\x{E19}\x{E23}\x{E35}" + text run at (0,21466) width 20: "\x{E1C}\x{E38}\x{E14}" + text run at (0,21496) width 19: "\x{E25}\x{E38}\x{E01}" + text run at (0,21526) width 21: "\x{E02}\x{E36}\x{E49}\x{E19}" + text run at (0,21556) width 22: "\x{E17}\x{E31}\x{E19}" + text run at (0,21586) width 16: "\x{E43}\x{E14}" + text run at (0,21610) width 5: "\"" + text run at (0,21636) width 20: "\x{E25}\x{E21}" + text run at (0,21666) width 54: "\x{E44}\x{E0B}\x{E42}\x{E04}\x{E25}\x{E19}" + text run at (0,21696) width 18: "\x{E21}\x{E32}" + text run at (0,21726) width 25: "\x{E40}\x{E2D}\x{E47}\x{E21}" + text run at (0,21750) width 5: "\"" + text run at (0,21776) width 17: "\x{E25}\x{E38}\x{E07}" + text run at (0,21806) width 25: "\x{E23}\x{E49}\x{E2D}\x{E07}" + text run at (0,21836) width 29: "\x{E1A}\x{E2D}\x{E01}" + text run at (0,21866) width 44: "\x{E20}\x{E23}\x{E23}\x{E22}\x{E32}" + text run at (0,21890) width 5: "\"" + text run at (0,21916) width 17: "\x{E02}\x{E49}\x{E32}" + text run at (0,21946) width 17: "\x{E08}\x{E30}" + text run at (0,21976) width 17: "\x{E44}\x{E1B}" + text run at (0,22006) width 10: "\x{E14}\x{E39}" + text run at (0,22036) width 28: "\x{E2A}\x{E31}\x{E15}\x{E27}\x{E4C}" + text run at (0,22066) width 32: "\x{E40}\x{E25}\x{E35}\x{E49}\x{E22}\x{E07}" + text run at (0,22096) width 40: "\x{E2B}\x{E19}\x{E48}\x{E2D}\x{E22}" + text run at (0,22120) width 5: "\"" + text run at (0,22146) width 28: "\x{E41}\x{E25}\x{E49}\x{E27}" + text run at (0,22176) width 17: "\x{E25}\x{E38}\x{E07}" + text run at (0,22206) width 10: "\x{E01}\x{E47}" + text run at (0,22236) width 17: "\x{E27}\x{E34}\x{E48}\x{E07}" + text run at (0,22266) width 17: "\x{E44}\x{E1B}" + text run at (0,22296) width 18: "\x{E22}\x{E31}\x{E07}" + text run at (0,22326) width 24: "\x{E40}\x{E1E}\x{E34}\x{E07}" + text run at (0,22356) width 11: "\x{E17}\x{E35}\x{E48}" + text run at (0,22386) width 18: "\x{E27}\x{E31}\x{E27}" + text run at (0,22416) width 27: "\x{E41}\x{E25}\x{E30}" + text run at (0,22446) width 18: "\x{E21}\x{E49}\x{E32}" + text run at (0,22476) width 36: "\x{E2D}\x{E32}\x{E28}\x{E31}\x{E22}" + text run at (0,22506) width 19: "\x{E2D}\x{E22}\x{E39}\x{E48}" + text run at (0,22536) width 17: "\x{E1B}\x{E49}\x{E32}" + text run at (0,22566) width 25: "\x{E40}\x{E2D}\x{E47}\x{E21}" + text run at (0,22596) width 30: "\x{E2B}\x{E22}\x{E38}\x{E14}" + text run at (0,22626) width 44: "\x{E17}\x{E33}\x{E07}\x{E32}\x{E19}" + text run at (0,22656) width 27: "\x{E41}\x{E25}\x{E30}" + text run at (0,22686) width 18: "\x{E21}\x{E32}" + text run at (0,22716) width 11: "\x{E17}\x{E35}\x{E48}" + text run at (0,22746) width 36: "\x{E1B}\x{E23}\x{E30}\x{E15}\x{E39}" + text run at (0,22776) width 34: "\x{E40}\x{E1E}\x{E35}\x{E22}\x{E07}" + text run at (0,22806) width 44: "\x{E0A}\x{E32}\x{E22}\x{E15}\x{E32}" + text run at (0,22836) width 28: "\x{E21}\x{E2D}\x{E07}" + text run at (0,22866) width 17: "\x{E1B}\x{E49}\x{E32}" + text run at (0,22896) width 10: "\x{E01}\x{E47}" + text run at (0,22926) width 29: "\x{E1A}\x{E2D}\x{E01}" + text run at (0,22956) width 17: "\x{E44}\x{E14}\x{E49}" + text run at (0,22986) width 16: "\x{E27}\x{E48}\x{E32}" + text run at (0,23016) width 55: "\x{E2D}\x{E31}\x{E19}\x{E15}\x{E23}\x{E32}\x{E22}" + text run at (0,23046) width 18: "\x{E21}\x{E32}" + text run at (0,23076) width 18: "\x{E16}\x{E36}\x{E07}" + text run at (0,23106) width 28: "\x{E41}\x{E25}\x{E49}\x{E27}" + text run at (0,23130) width 5: "\"" + text run at (0,23156) width 22: "\x{E40}\x{E23}\x{E47}\x{E27}" + text run at (0,23186) width 17: "\x{E42}\x{E14}" + text run at (0,23216) width 24: "\x{E42}\x{E23}\x{E18}\x{E35}" + text run at (0,23240) width 5: "!" + text run at (0,23260) width 5: "\"" + text run at (0,23286) width 17: "\x{E1B}\x{E49}\x{E32}" + text run at (0,23316) width 46: "\x{E15}\x{E30}\x{E42}\x{E01}\x{E19}" + text run at (0,23340) width 5: "\"" + text run at (0,23366) width 17: "\x{E27}\x{E34}\x{E48}\x{E07}" + text run at (0,23396) width 17: "\x{E44}\x{E1B}" + text run at (0,23426) width 27: "\x{E2B}\x{E49}\x{E2D}\x{E07}" + text run at (0,23456) width 37: "\x{E43}\x{E15}\x{E49}\x{E16}\x{E38}\x{E19}" + text run at (0,23480) width 5: "\"" + text run at (0,23506) width 17: "\x{E42}\x{E15}" + text run at (0,23536) width 17: "\x{E42}\x{E15}\x{E49}" + text run at (0,23566) width 30: "\x{E1C}\x{E25}\x{E38}\x{E19}" + text run at (0,23596) width 53: "\x{E01}\x{E23}\x{E30}\x{E42}\x{E14}\x{E14}" + text run at (0,23626) width 17: "\x{E25}\x{E07}" + text run at (0,23656) width 26: "\x{E08}\x{E32}\x{E01}" + text run at (0,23686) width 29: "\x{E2D}\x{E49}\x{E2D}\x{E21}" + text run at (0,23716) width 31: "\x{E41}\x{E02}\x{E19}" + text run at (0,23746) width 17: "\x{E42}\x{E14}" + text run at (0,23776) width 24: "\x{E42}\x{E23}\x{E18}\x{E35}" + text run at (0,23806) width 28: "\x{E41}\x{E25}\x{E49}\x{E27}" + text run at (0,23836) width 22: "\x{E40}\x{E02}\x{E49}\x{E32}" + text run at (0,23866) width 17: "\x{E44}\x{E1B}" + text run at (0,23896) width 30: "\x{E0B}\x{E48}\x{E2D}\x{E19}" + text run at (0,23926) width 19: "\x{E2D}\x{E22}\x{E39}\x{E48}" + text run at (0,23956) width 16: "\x{E43}\x{E15}\x{E49}" + text run at (0,23986) width 33: "\x{E40}\x{E15}\x{E35}\x{E22}\x{E07}" + text run at (0,24016) width 25: "\x{E40}\x{E14}\x{E47}\x{E01}" + text run at (0,24046) width 31: "\x{E2B}\x{E0D}\x{E34}\x{E07}" + text run at (0,24076) width 30: "\x{E19}\x{E49}\x{E2D}\x{E22}" + text run at (0,24106) width 22: "\x{E40}\x{E02}\x{E49}\x{E32}" + text run at (0,24136) width 17: "\x{E44}\x{E1B}" + text run at (0,24166) width 18: "\x{E14}\x{E36}\x{E07}" + text run at (0,24196) width 22: "\x{E21}\x{E31}\x{E19}" + text run at (0,24226) width 28: "\x{E2D}\x{E2D}\x{E01}" + text run at (0,24256) width 18: "\x{E21}\x{E32}" + text run at (0,24286) width 17: "\x{E1B}\x{E49}\x{E32}" + text run at (0,24316) width 25: "\x{E40}\x{E2D}\x{E47}\x{E21}" + text run at (0,24346) width 53: "\x{E01}\x{E23}\x{E30}\x{E0A}\x{E32}\x{E01}" + text run at (0,24376) width 17: "\x{E1D}\x{E32}" + text run at (0,24406) width 11: "\x{E17}\x{E35}\x{E48}" + text run at (0,24436) width 22: "\x{E1E}\x{E37}\x{E49}\x{E19}" + text run at (0,24466) width 28: "\x{E2D}\x{E2D}\x{E01}" + text run at (0,24496) width 34: "\x{E2D}\x{E22}\x{E48}\x{E32}\x{E07}" + text run at (0,24526) width 19: "\x{E2D}\x{E01}" + text run at (0,24556) width 20: "\x{E2A}\x{E31}\x{E48}\x{E19}" + text run at (0,24586) width 32: "\x{E02}\x{E27}\x{E31}\x{E0D}" + text run at (0,24616) width 27: "\x{E2B}\x{E32}\x{E22}" + text run at (0,24646) width 21: "\x{E1B}\x{E35}\x{E19}" + text run at (0,24676) width 38: "\x{E1A}\x{E31}\x{E19}\x{E44}\x{E14}" + text run at (0,24706) width 18: "\x{E44}\x{E21}\x{E49}" + text run at (0,24736) width 17: "\x{E25}\x{E07}" + text run at (0,24766) width 17: "\x{E44}\x{E1B}" + text run at (0,24796) width 17: "\x{E43}\x{E19}" + text run at (0,24826) width 34: "\x{E42}\x{E1E}\x{E23}\x{E07}" + text run at (0,24856) width 24: "\x{E40}\x{E25}\x{E47}\x{E01}" + text run at (0,24886) width 20: "\x{E2D}\x{E31}\x{E19}" + text run at (0,24916) width 21: "\x{E21}\x{E37}\x{E14}" + text run at (0,24946) width 21: "\x{E17}\x{E36}\x{E1A}" + text run at (0,24976) width 17: "\x{E42}\x{E14}" + text run at (0,25006) width 24: "\x{E42}\x{E23}\x{E18}\x{E35}" + text run at (0,25036) width 19: "\x{E08}\x{E31}\x{E1A}" + text run at (0,25066) width 17: "\x{E42}\x{E15}" + text run at (0,25096) width 17: "\x{E42}\x{E15}\x{E49}" + text run at (0,25126) width 17: "\x{E44}\x{E14}\x{E49}" + text run at (0,25156) width 17: "\x{E43}\x{E19}" + text run at (0,25186) width 11: "\x{E17}\x{E35}\x{E48}" + text run at (0,25216) width 19: "\x{E2A}\x{E38}\x{E14}" + text run at (0,25246) width 27: "\x{E41}\x{E25}\x{E30}" + text run at (0,25276) width 17: "\x{E27}\x{E34}\x{E48}\x{E07}" + text run at (0,25306) width 28: "\x{E15}\x{E32}\x{E21}" + text run at (0,25336) width 17: "\x{E1B}\x{E49}\x{E32}" + text run at (0,25366) width 23: "\x{E40}\x{E18}\x{E2D}" + text run at (0,25396) width 17: "\x{E44}\x{E1B}" + text run at (0,25426) width 25: "\x{E40}\x{E21}\x{E37}\x{E48}\x{E2D}" + text run at (0,25456) width 23: "\x{E40}\x{E18}\x{E2D}" + text run at (0,25486) width 18: "\x{E21}\x{E32}" + text run at (0,25516) width 17: "\x{E44}\x{E14}\x{E49}" + text run at (0,25546) width 26: "\x{E04}\x{E23}\x{E36}\x{E48}\x{E07}" + text run at (0,25576) width 27: "\x{E2B}\x{E49}\x{E2D}\x{E07}" + text run at (0,25606) width 10: "\x{E01}\x{E47}" + text run at (0,25636) width 11: "\x{E21}\x{E35}" + text run at (0,25666) width 32: "\x{E40}\x{E2A}\x{E35}\x{E22}\x{E07}" + text run at (0,25696) width 29: "\x{E2B}\x{E27}\x{E35}\x{E14}" + text run at (0,25726) width 28: "\x{E2B}\x{E27}\x{E37}\x{E2D}" + text run at (0,25756) width 29: "\x{E2A}\x{E48}\x{E27}\x{E19}" + text run at (0,25786) width 28: "\x{E1A}\x{E49}\x{E32}\x{E19}" + text run at (0,25816) width 10: "\x{E01}\x{E47}" + text run at (0,25846) width 20: "\x{E2A}\x{E31}\x{E48}\x{E19}" + text run at (0,25876) width 34: "\x{E2D}\x{E22}\x{E48}\x{E32}\x{E07}" + text run at (0,25906) width 26: "\x{E41}\x{E23}\x{E07}" + text run at (0,25936) width 20: "\x{E08}\x{E19}" + text run at (0,25966) width 23: "\x{E40}\x{E18}\x{E2D}" + text run at (0,25996) width 20: "\x{E2B}\x{E01}" + text run at (0,26026) width 36: "\x{E04}\x{E30}\x{E21}\x{E33}" + text run at (0,26056) width 19: "\x{E19}\x{E31}\x{E48}\x{E07}" + text run at (0,26086) width 38: "\x{E08}\x{E49}\x{E33}\x{E40}\x{E1A}\x{E49}\x{E32}" + text run at (0,26116) width 19: "\x{E2D}\x{E22}\x{E39}\x{E48}" + text run at (0,26146) width 20: "\x{E01}\x{E31}\x{E1A}" + text run at (0,26176) width 22: "\x{E1E}\x{E37}\x{E49}\x{E19}" + text run at (0,26206) width 28: "\x{E41}\x{E25}\x{E49}\x{E27}" + text run at (0,26236) width 17: "\x{E2A}\x{E34}\x{E48}\x{E07}" + text run at (0,26266) width 62: "\x{E1B}\x{E23}\x{E30}\x{E2B}\x{E25}\x{E32}\x{E14}" + text run at (0,26296) width 10: "\x{E01}\x{E47}" + text run at (0,26326) width 25: "\x{E40}\x{E01}\x{E34}\x{E14}" + text run at (0,26356) width 21: "\x{E02}\x{E36}\x{E49}\x{E19}" + text run at (0,26386) width 28: "\x{E1A}\x{E49}\x{E32}\x{E19}" + text run at (0,26416) width 32: "\x{E2B}\x{E21}\x{E38}\x{E19}" + text run at (0,26446) width 17: "\x{E44}\x{E1B}" + text run at (0,26476) width 32: "\x{E2B}\x{E21}\x{E38}\x{E19}" + text run at (0,26506) width 18: "\x{E21}\x{E32}" + text run at (0,26536) width 26: "\x{E2A}\x{E2D}\x{E07}" + text run at (0,26566) width 27: "\x{E2A}\x{E32}\x{E21}" + text run at (0,26596) width 27: "\x{E23}\x{E2D}\x{E1A}" + text run at (0,26626) width 28: "\x{E41}\x{E25}\x{E49}\x{E27}" + text run at (0,26656) width 10: "\x{E01}\x{E47}" + text run at (0,26686) width 28: "\x{E25}\x{E2D}\x{E22}" + text run at (0,26716) width 21: "\x{E02}\x{E36}\x{E49}\x{E19}" + text run at (0,26746) width 9: "\x{E2A}\x{E39}\x{E48}" + text run at (0,26776) width 43: "\x{E2D}\x{E32}\x{E01}\x{E32}\x{E28}" + text run at (0,26806) width 34: "\x{E2D}\x{E22}\x{E48}\x{E32}\x{E07}" + text run at (0,26836) width 17: "\x{E0A}\x{E49}\x{E32}" + text run at (0,26866) width 9: "\x{E46}" + text run at (0,26896) width 17: "\x{E42}\x{E14}" + text run at (0,26926) width 24: "\x{E42}\x{E23}\x{E18}\x{E35}" + text run at (0,26956) width 27: "\x{E23}\x{E39}\x{E49}\x{E2A}\x{E36}\x{E01}" + text run at (0,26986) width 24: "\x{E23}\x{E32}\x{E27}" + text run at (0,27016) width 20: "\x{E01}\x{E31}\x{E1A}" + text run at (0,27046) width 16: "\x{E27}\x{E48}\x{E32}" + text run at (0,27076) width 23: "\x{E40}\x{E18}\x{E2D}" + text run at (0,27106) width 17: "\x{E44}\x{E14}\x{E49}" + text run at (0,27136) width 21: "\x{E02}\x{E36}\x{E49}\x{E19}" + text run at (0,27166) width 17: "\x{E44}\x{E1B}" + text run at (0,27196) width 20: "\x{E01}\x{E31}\x{E1A}" + text run at (0,27226) width 19: "\x{E25}\x{E39}\x{E01}" + text run at (0,27256) width 48: "\x{E1A}\x{E2D}\x{E25}\x{E25}\x{E39}\x{E19}" + text run at (0,27286) width 28: "\x{E1E}\x{E32}\x{E22}\x{E38}" + text run at (0,27316) width 35: "\x{E40}\x{E2B}\x{E19}\x{E37}\x{E2D}" + text run at (0,27346) width 20: "\x{E01}\x{E31}\x{E1A}" + text run at (0,27376) width 28: "\x{E1E}\x{E32}\x{E22}\x{E38}" + text run at (0,27406) width 16: "\x{E43}\x{E15}\x{E49}" + text run at (0,27436) width 18: "\x{E21}\x{E32}" + text run at (0,27466) width 21: "\x{E1E}\x{E1A}" + text run at (0,27496) width 21: "\x{E01}\x{E31}\x{E19}" + text run at (0,27526) width 26: "\x{E15}\x{E23}\x{E07}" + text run at (0,27556) width 11: "\x{E17}\x{E35}\x{E48}" + text run at (0,27586) width 28: "\x{E1A}\x{E49}\x{E32}\x{E19}" + text run at (0,27616) width 20: "\x{E1E}\x{E2D}" + text run at (0,27646) width 10: "\x{E14}\x{E35}" + text run at (0,27676) width 27: "\x{E41}\x{E25}\x{E30}" + text run at (0,27706) width 18: "\x{E17}\x{E33}" + text run at (0,27736) width 16: "\x{E43}\x{E2B}\x{E49}" + text run at (0,27766) width 26: "\x{E15}\x{E23}\x{E07}" + text run at (0,27796) width 22: "\x{E19}\x{E31}\x{E49}\x{E19}" + text run at (0,27826) width 26: "\x{E40}\x{E1B}\x{E47}\x{E19}" + text run at (0,27856) width 19: "\x{E08}\x{E38}\x{E14}" + text run at (0,27886) width 31: "\x{E28}\x{E39}\x{E19}\x{E22}\x{E4C}" + text run at (0,27916) width 34: "\x{E01}\x{E25}\x{E32}\x{E07}" + text run at (0,27946) width 27: "\x{E02}\x{E2D}\x{E07}" + text run at (0,27976) width 28: "\x{E1E}\x{E32}\x{E22}\x{E38}" + text run at (0,28006) width 54: "\x{E44}\x{E0B}\x{E42}\x{E04}\x{E25}\x{E19}" + text run at (0,28036) width 28: "\x{E15}\x{E32}\x{E21}" + text run at (0,28066) width 30: "\x{E1B}\x{E01}\x{E15}\x{E34}" + text run at (0,28096) width 26: "\x{E15}\x{E23}\x{E07}" + text run at (0,28126) width 34: "\x{E01}\x{E25}\x{E32}\x{E07}" + text run at (0,28156) width 28: "\x{E1E}\x{E32}\x{E22}\x{E38}" + text run at (0,28186) width 54: "\x{E44}\x{E0B}\x{E42}\x{E04}\x{E25}\x{E19}" + text run at (0,28216) width 43: "\x{E2D}\x{E32}\x{E01}\x{E32}\x{E28}" + text run at (0,28246) width 17: "\x{E08}\x{E30}" + text run at (0,28276) width 19: "\x{E19}\x{E34}\x{E48}\x{E07}" + text run at (0,28306) width 20: "\x{E41}\x{E15}\x{E48}" + text run at (0,28336) width 37: "\x{E04}\x{E27}\x{E32}\x{E21}" + text run at (0,28366) width 41: "\x{E01}\x{E14}\x{E14}\x{E31}\x{E19}" + text run at (0,28396) width 34: "\x{E2D}\x{E22}\x{E48}\x{E32}\x{E07}" + text run at (0,28426) width 31: "\x{E2B}\x{E19}\x{E31}\x{E01}" + text run at (0,28456) width 27: "\x{E02}\x{E2D}\x{E07}" + text run at (0,28486) width 20: "\x{E25}\x{E21}" + text run at (0,28516) width 21: "\x{E17}\x{E38}\x{E01}" + text run at (0,28546) width 28: "\x{E14}\x{E49}\x{E32}\x{E19}" + text run at (0,28576) width 27: "\x{E23}\x{E2D}\x{E1A}" + text run at (0,28606) width 28: "\x{E1A}\x{E49}\x{E32}\x{E19}" + text run at (0,28636) width 18: "\x{E17}\x{E33}" + text run at (0,28666) width 16: "\x{E43}\x{E2B}\x{E49}" + text run at (0,28696) width 28: "\x{E1A}\x{E49}\x{E32}\x{E19}" + text run at (0,28726) width 28: "\x{E25}\x{E2D}\x{E22}" + text run at (0,28756) width 17: "\x{E2A}\x{E39}\x{E07}" + text run at (0,28786) width 21: "\x{E02}\x{E36}\x{E49}\x{E19}" + text run at (0,28816) width 9: "\x{E46}" + text run at (0,28846) width 20: "\x{E08}\x{E19}" + text run at (0,28876) width 45: "\x{E01}\x{E23}\x{E30}\x{E17}\x{E31}\x{E48}\x{E07}" + text run at (0,28906) width 21: "\x{E02}\x{E36}\x{E49}\x{E19}" + text run at (0,28936) width 17: "\x{E44}\x{E1B}" + text run at (0,28966) width 19: "\x{E2D}\x{E22}\x{E39}\x{E48}" + text run at (0,28996) width 19: "\x{E2A}\x{E38}\x{E14}" + text run at (0,29026) width 29: "\x{E22}\x{E2D}\x{E14}" + text run at (0,29056) width 27: "\x{E02}\x{E2D}\x{E07}" + text run at (0,29086) width 28: "\x{E1E}\x{E32}\x{E22}\x{E38}" + text run at (0,29116) width 54: "\x{E44}\x{E0B}\x{E42}\x{E04}\x{E25}\x{E19}" + text run at (0,29146) width 27: "\x{E41}\x{E25}\x{E30}" + text run at (0,29176) width 26: "\x{E08}\x{E32}\x{E01}" + text run at (0,29206) width 26: "\x{E15}\x{E23}\x{E07}" + text run at (0,29236) width 22: "\x{E19}\x{E31}\x{E49}\x{E19}" + text run at (0,29266) width 10: "\x{E01}\x{E47}" + text run at (0,29296) width 20: "\x{E16}\x{E39}\x{E01}" + text run at (0,29326) width 29: "\x{E2B}\x{E2D}\x{E1A}" + text run at (0,29356) width 17: "\x{E44}\x{E1B}" + text run at (0,29386) width 36: "\x{E2B}\x{E25}\x{E32}\x{E22}" + text run at (0,29416) width 27: "\x{E44}\x{E21}\x{E25}\x{E4C}" + text run at (0,29446) width 25: "\x{E07}\x{E48}\x{E32}\x{E22}" + text run at (0,29476) width 27: "\x{E14}\x{E32}\x{E22}" + text run at (0,29506) width 24: "\x{E23}\x{E32}\x{E27}" + text run at (0,29536) width 20: "\x{E01}\x{E31}\x{E1A}" + text run at (0,29566) width 29: "\x{E2B}\x{E2D}\x{E1A}" + text run at (0,29596) width 21: "\x{E02}\x{E19}" + text run at (0,29626) width 21: "\x{E19}\x{E01}" + text run at (0,29656) width 21: "\x{E21}\x{E37}\x{E14}" + text run at (0,29686) width 28: "\x{E21}\x{E32}\x{E01}" + text run at (0,29716) width 28: "\x{E41}\x{E25}\x{E49}\x{E27}" + text run at (0,29746) width 20: "\x{E25}\x{E21}" + text run at (0,29776) width 18: "\x{E22}\x{E31}\x{E07}" + text run at (0,29806) width 17: "\x{E2A}\x{E48}\x{E07}" + text run at (0,29836) width 32: "\x{E40}\x{E2A}\x{E35}\x{E22}\x{E07}" + text run at (0,29866) width 29: "\x{E2B}\x{E27}\x{E35}\x{E14}" + text run at (0,29896) width 28: "\x{E2B}\x{E27}\x{E37}\x{E2D}" + text run at (0,29926) width 18: "\x{E19}\x{E48}\x{E32}" + text run at (0,29956) width 28: "\x{E01}\x{E25}\x{E31}\x{E27}" + text run at (0,29986) width 19: "\x{E2D}\x{E22}\x{E39}\x{E48}" + text run at (0,30016) width 27: "\x{E23}\x{E2D}\x{E1A}" + text run at (0,30046) width 19: "\x{E15}\x{E31}\x{E27}" + text run at (0,30076) width 23: "\x{E40}\x{E18}\x{E2D}" + text run at (0,30106) width 20: "\x{E41}\x{E15}\x{E48}" + text run at (0,30136) width 17: "\x{E42}\x{E14}" + text run at (0,30166) width 24: "\x{E42}\x{E23}\x{E18}\x{E35}" + text run at (0,30196) width 26: "\x{E40}\x{E2B}\x{E47}\x{E19}" + text run at (0,30226) width 16: "\x{E27}\x{E48}\x{E32}" + text run at (0,30256) width 23: "\x{E40}\x{E18}\x{E2D}" + text run at (0,30286) width 52: "\x{E2A}\x{E32}\x{E21}\x{E32}\x{E23}\x{E16}" + text run at (0,30316) width 19: "\x{E19}\x{E31}\x{E48}\x{E07}" + text run at (0,30346) width 17: "\x{E44}\x{E1B}" + text run at (0,30376) width 17: "\x{E44}\x{E14}\x{E49}" + text run at (0,30406) width 26: "\x{E2D}\x{E22}\x{E48}\x{E32}" + text run at (0,30436) width 33: "\x{E07}\x{E07}\x{E48}\x{E32}\x{E22}" + text run at (0,30466) width 27: "\x{E14}\x{E32}\x{E22}" + text run at (0,30496) width 21: "\x{E19}\x{E31}\x{E01}" + text run at (0,30526) width 26: "\x{E04}\x{E23}\x{E31}\x{E49}\x{E07}" + text run at (0,30556) width 29: "\x{E2B}\x{E19}\x{E36}\x{E48}\x{E07}" + text run at (0,30586) width 27: "\x{E2B}\x{E25}\x{E31}\x{E07}" + text run at (0,30616) width 26: "\x{E08}\x{E32}\x{E01}" + text run at (0,30646) width 11: "\x{E17}\x{E35}\x{E48}" + text run at (0,30676) width 28: "\x{E1A}\x{E49}\x{E32}\x{E19}" + text run at (0,30706) width 37: "\x{E2A}\x{E30}\x{E14}\x{E38}\x{E14}" + text run at (0,30736) width 34: "\x{E2D}\x{E22}\x{E48}\x{E32}\x{E07}" + text run at (0,30766) width 26: "\x{E41}\x{E23}\x{E07}" + text run at (0,30796) width 27: "\x{E41}\x{E25}\x{E30}" + text run at (0,30826) width 32: "\x{E2B}\x{E21}\x{E38}\x{E19}" + text run at (0,30856) width 17: "\x{E44}\x{E1B}" + text run at (0,30886) width 27: "\x{E23}\x{E2D}\x{E1A}" + text run at (0,30916) width 9: "\x{E46}" + text run at (0,30946) width 26: "\x{E2A}\x{E2D}\x{E07}" + text run at (0,30976) width 27: "\x{E2A}\x{E32}\x{E21}" + text run at (0,31006) width 26: "\x{E04}\x{E23}\x{E31}\x{E49}\x{E07}" + text run at (0,31036) width 17: "\x{E43}\x{E19}" + text run at (0,31066) width 30: "\x{E15}\x{E2D}\x{E19}" + text run at (0,31096) width 28: "\x{E41}\x{E23}\x{E01}" + text run at (0,31126) width 23: "\x{E40}\x{E18}\x{E2D}" + text run at (0,31156) width 10: "\x{E01}\x{E47}" + text run at (0,31186) width 27: "\x{E23}\x{E39}\x{E49}\x{E2A}\x{E36}\x{E01}" + text run at (0,31216) width 16: "\x{E27}\x{E48}\x{E32}" + text run at (0,31246) width 19: "\x{E15}\x{E31}\x{E27}" + text run at (0,31276) width 22: "\x{E40}\x{E2D}\x{E07}" + text run at (0,31306) width 20: "\x{E16}\x{E39}\x{E01}" + text run at (0,31336) width 37: "\x{E41}\x{E01}\x{E27}\x{E48}\x{E07}" + text run at (0,31366) width 34: "\x{E2D}\x{E22}\x{E48}\x{E32}\x{E07}" + text run at (0,31396) width 29: "\x{E41}\x{E1C}\x{E48}\x{E27}" + text run at (0,31426) width 22: "\x{E40}\x{E1A}\x{E32}" + text run at (0,31456) width 24: "\x{E23}\x{E32}\x{E27}" + text run at (0,31486) width 36: "\x{E17}\x{E32}\x{E23}\x{E01}" + text run at (0,31516) width 17: "\x{E43}\x{E19}" + text run at (0,31546) width 24: "\x{E40}\x{E1B}\x{E25}" + text run at (0,31576) width 17: "\x{E42}\x{E15}" + text run at (0,31606) width 17: "\x{E42}\x{E15}\x{E49}" + text run at (0,31636) width 18: "\x{E44}\x{E21}\x{E48}" + text run at (0,31666) width 29: "\x{E0A}\x{E2D}\x{E1A}" + text run at (0,31696) width 15: "\x{E43}\x{E08}" + text run at (0,31726) width 24: "\x{E40}\x{E25}\x{E22}" + text run at (0,31756) width 22: "\x{E21}\x{E31}\x{E19}" + text run at (0,31786) width 17: "\x{E27}\x{E34}\x{E48}\x{E07}" + text run at (0,31816) width 17: "\x{E44}\x{E1B}" + text run at (0,31846) width 17: "\x{E27}\x{E34}\x{E48}\x{E07}" + text run at (0,31876) width 18: "\x{E21}\x{E32}" + text run at (0,31906) width 27: "\x{E23}\x{E2D}\x{E1A}" + text run at (0,31936) width 27: "\x{E2B}\x{E49}\x{E2D}\x{E07}" + text run at (0,31966) width 26: "\x{E17}\x{E32}\x{E07}" + text run at (0,31996) width 29: "\x{E42}\x{E19}\x{E49}\x{E19}" + text run at (0,32026) width 11: "\x{E17}\x{E35}" + text run at (0,32056) width 26: "\x{E17}\x{E32}\x{E07}" + text run at (0,32086) width 11: "\x{E19}\x{E35}\x{E49}" + text run at (0,32116) width 11: "\x{E17}\x{E35}" + text run at (0,32146) width 17: "\x{E2A}\x{E48}\x{E07}" + text run at (0,32176) width 32: "\x{E40}\x{E2A}\x{E35}\x{E22}\x{E07}" + text run at (0,32206) width 22: "\x{E40}\x{E2B}\x{E48}\x{E32}" + text run at (0,32236) width 18: "\x{E14}\x{E31}\x{E07}" + text run at (0,32266) width 27: "\x{E01}\x{E49}\x{E2D}\x{E07}" + text run at (0,32296) width 20: "\x{E41}\x{E15}\x{E48}" + text run at (0,32326) width 17: "\x{E42}\x{E14}" + text run at (0,32356) width 24: "\x{E42}\x{E23}\x{E18}\x{E35}" + text run at (0,32386) width 19: "\x{E19}\x{E31}\x{E48}\x{E07}" + text run at (0,32416) width 19: "\x{E19}\x{E34}\x{E48}\x{E07}" + text run at (0,32446) width 19: "\x{E2D}\x{E22}\x{E39}\x{E48}" + text run at (0,32476) width 21: "\x{E1A}\x{E19}" + text run at (0,32506) width 22: "\x{E1E}\x{E37}\x{E49}\x{E19}" + text run at (0,32536) width 22: "\x{E40}\x{E1D}\x{E49}\x{E32}" + text run at (0,32566) width 29: "\x{E04}\x{E2D}\x{E22}" + text run at (0,32596) width 10: "\x{E14}\x{E39}" + text run at (0,32626) width 16: "\x{E27}\x{E48}\x{E32}" + text run at (0,32656) width 17: "\x{E08}\x{E30}" + text run at (0,32686) width 25: "\x{E40}\x{E01}\x{E34}\x{E14}" + text run at (0,32716) width 32: "\x{E2D}\x{E30}\x{E44}\x{E23}" + text run at (0,32746) width 21: "\x{E02}\x{E36}\x{E49}\x{E19}" + text run at (0,32776) width 26: "\x{E04}\x{E23}\x{E31}\x{E49}\x{E07}" + text run at (0,32806) width 29: "\x{E2B}\x{E19}\x{E36}\x{E48}\x{E07}" + text run at (0,32836) width 17: "\x{E42}\x{E15}" + text run at (0,32866) width 17: "\x{E42}\x{E15}\x{E49}" + text run at (0,32896) width 22: "\x{E40}\x{E02}\x{E49}\x{E32}" + text run at (0,32926) width 17: "\x{E44}\x{E1B}" + text run at (0,32956) width 25: "\x{E43}\x{E01}\x{E25}\x{E49}" + text run at (0,32986) width 17: "\x{E1D}\x{E32}" + text run at (0,33016) width 11: "\x{E17}\x{E35}\x{E48}" + text run at (0,33046) width 22: "\x{E1E}\x{E37}\x{E49}\x{E19}" + text run at (0,33076) width 28: "\x{E21}\x{E32}\x{E01}" + text run at (0,33106) width 17: "\x{E44}\x{E1B}" + text run at (0,33136) width 24: "\x{E40}\x{E25}\x{E22}" + text run at (0,33166) width 30: "\x{E1E}\x{E25}\x{E31}\x{E14}" + text run at (0,33196) width 37: "\x{E15}\x{E01}\x{E25}\x{E07}" + text run at (0,33226) width 17: "\x{E44}\x{E1B}" + text run at (0,33256) width 11: "\x{E17}\x{E35}" + text run at (0,33286) width 28: "\x{E41}\x{E23}\x{E01}" + text run at (0,33316) width 25: "\x{E40}\x{E14}\x{E47}\x{E01}" + text run at (0,33346) width 31: "\x{E2B}\x{E0D}\x{E34}\x{E07}" + text run at (0,33376) width 20: "\x{E04}\x{E34}\x{E14}" + text run at (0,33406) width 16: "\x{E27}\x{E48}\x{E32}" + text run at (0,33436) width 23: "\x{E40}\x{E18}\x{E2D}" + text run at (0,33466) width 17: "\x{E08}\x{E30}" + text run at (0,33496) width 22: "\x{E2A}\x{E39}\x{E0D}" + text run at (0,33526) width 24: "\x{E40}\x{E2A}\x{E35}\x{E22}" + text run at (0,33556) width 22: "\x{E21}\x{E31}\x{E19}" + text run at (0,33586) width 17: "\x{E44}\x{E1B}" + text run at (0,33616) width 24: "\x{E40}\x{E2A}\x{E35}\x{E22}" + text run at (0,33646) width 28: "\x{E41}\x{E25}\x{E49}\x{E27}" + text run at (0,33676) width 20: "\x{E41}\x{E15}\x{E48}" + text run at (0,33706) width 19: "\x{E0A}\x{E31}\x{E48}\x{E27}" + text run at (0,33736) width 18: "\x{E04}\x{E23}\x{E39}\x{E48}" + text run at (0,33766) width 23: "\x{E40}\x{E18}\x{E2D}" + text run at (0,33796) width 10: "\x{E01}\x{E47}" + text run at (0,33826) width 26: "\x{E40}\x{E2B}\x{E47}\x{E19}" + text run at (0,33856) width 10: "\x{E2B}\x{E39}" + text run at (0,33886) width 27: "\x{E02}\x{E2D}\x{E07}" + text run at (0,33916) width 22: "\x{E21}\x{E31}\x{E19}" + text run at (0,33946) width 26: "\x{E42}\x{E1C}\x{E25}\x{E48}" + text run at (0,33976) width 21: "\x{E02}\x{E36}\x{E49}\x{E19}" + text run at (0,34006) width 18: "\x{E21}\x{E32}" + text run at (0,34036) width 26: "\x{E08}\x{E32}\x{E01}" + text run at (0,34066) width 27: "\x{E0A}\x{E48}\x{E2D}\x{E07}" + text run at (0,34096) width 22: "\x{E19}\x{E31}\x{E49}\x{E19}" + text run at (0,34126) width 19: "\x{E17}\x{E31}\x{E49}\x{E07}" + text run at (0,34156) width 11: "\x{E19}\x{E35}\x{E49}" + text run at (0,34186) width 39: "\x{E40}\x{E1E}\x{E23}\x{E32}\x{E30}" + text run at (0,34216) width 26: "\x{E41}\x{E23}\x{E07}" + text run at (0,34246) width 20: "\x{E01}\x{E14}" + text run at (0,34276) width 34: "\x{E2D}\x{E22}\x{E48}\x{E32}\x{E07}" + text run at (0,34306) width 31: "\x{E2B}\x{E19}\x{E31}\x{E01}" + text run at (0,34336) width 27: "\x{E02}\x{E2D}\x{E07}" + text run at (0,34366) width 43: "\x{E2D}\x{E32}\x{E01}\x{E32}\x{E28}" + text run at (0,34396) width 18: "\x{E17}\x{E33}" + text run at (0,34426) width 16: "\x{E43}\x{E2B}\x{E49}" + text run at (0,34456) width 17: "\x{E42}\x{E15}" + text run at (0,34486) width 17: "\x{E42}\x{E15}\x{E49}" + text run at (0,34516) width 18: "\x{E44}\x{E21}\x{E48}" + text run at (0,34546) width 37: "\x{E15}\x{E01}\x{E25}\x{E07}" + text run at (0,34576) width 17: "\x{E44}\x{E1B}" + text run at (0,34606) width 25: "\x{E02}\x{E49}\x{E32}\x{E07}" + text run at (0,34636) width 24: "\x{E25}\x{E48}\x{E32}\x{E07}" + text run at (0,34666) width 17: "\x{E42}\x{E14}" + text run at (0,34696) width 24: "\x{E42}\x{E23}\x{E18}\x{E35}" + text run at (0,34726) width 37: "\x{E04}\x{E25}\x{E32}\x{E19}" + text run at (0,34756) width 17: "\x{E44}\x{E1B}" + text run at (0,34786) width 11: "\x{E17}\x{E35}\x{E48}" + text run at (0,34816) width 27: "\x{E0A}\x{E48}\x{E2D}\x{E07}" + text run at (0,34846) width 22: "\x{E19}\x{E31}\x{E49}\x{E19}" + text run at (0,34876) width 19: "\x{E08}\x{E31}\x{E1A}" + text run at (0,34906) width 10: "\x{E2B}\x{E39}" + text run at (0,34936) width 17: "\x{E42}\x{E15}" + text run at (0,34966) width 17: "\x{E42}\x{E15}\x{E49}" + text run at (0,34996) width 16: "\x{E44}\x{E27}\x{E49}" + text run at (0,35026) width 17: "\x{E44}\x{E14}\x{E49}" + text run at (0,35056) width 27: "\x{E41}\x{E25}\x{E30}" + text run at (0,35086) width 26: "\x{E25}\x{E32}\x{E01}" + text run at (0,35116) width 22: "\x{E21}\x{E31}\x{E19}" + text run at (0,35146) width 18: "\x{E21}\x{E32}" + text run at (0,35176) width 11: "\x{E17}\x{E35}\x{E48}" + text run at (0,35206) width 27: "\x{E2B}\x{E49}\x{E2D}\x{E07}" + text run at (0,35236) width 19: "\x{E2D}\x{E35}\x{E01}" + text run at (0,35266) width 27: "\x{E2B}\x{E25}\x{E31}\x{E07}" + text run at (0,35296) width 26: "\x{E08}\x{E32}\x{E01}" + text run at (0,35326) width 22: "\x{E19}\x{E31}\x{E49}\x{E19}" + text run at (0,35356) width 10: "\x{E01}\x{E47}" + text run at (0,35386) width 20: "\x{E1B}\x{E34}\x{E14}" + text run at (0,35416) width 17: "\x{E1D}\x{E32}" + text run at (0,35446) width 22: "\x{E1E}\x{E37}\x{E49}\x{E19}" + text run at (0,35476) width 25: "\x{E40}\x{E1E}\x{E37}\x{E48}\x{E2D}" + text run at (0,35506) width 17: "\x{E08}\x{E30}" + text run at (0,35536) width 17: "\x{E44}\x{E14}\x{E49}" + text run at (0,35566) width 18: "\x{E44}\x{E21}\x{E48}" + text run at (0,35596) width 25: "\x{E40}\x{E01}\x{E34}\x{E14}" + text run at (0,35626) width 54: "\x{E2D}\x{E38}\x{E1A}\x{E31}\x{E15}\x{E34}\x{E40}\x{E2B}\x{E15}\x{E38}" + text run at (0,35656) width 19: "\x{E2D}\x{E35}\x{E01}" + text run at (0,35686) width 45: "\x{E0A}\x{E31}\x{E48}\x{E27}\x{E42}\x{E21}\x{E07}" + text run at (0,35716) width 28: "\x{E41}\x{E25}\x{E49}\x{E27}" + text run at (0,35746) width 45: "\x{E0A}\x{E31}\x{E48}\x{E27}\x{E42}\x{E21}\x{E07}" + text run at (0,35776) width 21: "\x{E40}\x{E25}\x{E48}\x{E32}" + text run at (0,35806) width 28: "\x{E1C}\x{E48}\x{E32}\x{E19}" + text run at (0,35836) width 17: "\x{E44}\x{E1B}" + text run at (0,35866) width 17: "\x{E42}\x{E14}" + text run at (0,35896) width 24: "\x{E42}\x{E23}\x{E18}\x{E35}" + text run at (0,35926) width 29: "\x{E04}\x{E48}\x{E2D}\x{E22}" + text run at (0,35956) width 9: "\x{E46}" + text run at (0,35986) width 27: "\x{E2B}\x{E32}\x{E22}" + text run at (0,36016) width 28: "\x{E01}\x{E25}\x{E31}\x{E27}" + text run at (0,36046) width 20: "\x{E41}\x{E15}\x{E48}" + text run at (0,36076) width 23: "\x{E40}\x{E18}\x{E2D}" + text run at (0,36106) width 27: "\x{E23}\x{E39}\x{E49}\x{E2A}\x{E36}\x{E01}" + text run at (0,36136) width 30: "\x{E40}\x{E2B}\x{E07}\x{E32}" + text run at (0,36166) width 33: "\x{E40}\x{E2B}\x{E25}\x{E37}\x{E2D}" + text run at (0,36196) width 26: "\x{E40}\x{E01}\x{E34}\x{E19}" + text run at (0,36226) width 27: "\x{E41}\x{E25}\x{E30}" + text run at (0,36256) width 20: "\x{E25}\x{E21}" + text run at (0,36286) width 10: "\x{E01}\x{E47}" + text run at (0,36316) width 17: "\x{E2A}\x{E48}\x{E07}" + text run at (0,36346) width 32: "\x{E40}\x{E2A}\x{E35}\x{E22}\x{E07}" + text run at (0,36376) width 29: "\x{E2B}\x{E27}\x{E35}\x{E14}" + text run at (0,36406) width 28: "\x{E2B}\x{E27}\x{E37}\x{E2D}" + text run at (0,36436) width 18: "\x{E14}\x{E31}\x{E07}" + text run at (0,36466) width 24: "\x{E40}\x{E2A}\x{E35}\x{E22}" + text run at (0,36496) width 20: "\x{E08}\x{E19}" + text run at (0,36526) width 23: "\x{E40}\x{E18}\x{E2D}" + text run at (0,36556) width 31: "\x{E41}\x{E17}\x{E1A}" + text run at (0,36586) width 17: "\x{E08}\x{E30}" + text run at (0,36616) width 10: "\x{E2B}\x{E39}" + text run at (0,36646) width 40: "\x{E2B}\x{E19}\x{E27}\x{E01}" + text run at (0,36676) width 11: "\x{E17}\x{E35}" + text run at (0,36706) width 28: "\x{E41}\x{E23}\x{E01}" + text run at (0,36736) width 23: "\x{E40}\x{E18}\x{E2D}" + text run at (0,36766) width 36: "\x{E2A}\x{E07}\x{E2A}\x{E31}\x{E22}" + text run at (0,36796) width 16: "\x{E27}\x{E48}\x{E32}" + text run at (0,36826) width 18: "\x{E04}\x{E07}" + text run at (0,36856) width 17: "\x{E08}\x{E30}" + text run at (0,36886) width 20: "\x{E16}\x{E39}\x{E01}" + text run at (0,36916) width 20: "\x{E09}\x{E35}\x{E01}" + text run at (0,36946) width 53: "\x{E01}\x{E23}\x{E30}\x{E0A}\x{E32}\x{E01}" + text run at (0,36976) width 28: "\x{E2D}\x{E2D}\x{E01}" + text run at (0,37006) width 26: "\x{E40}\x{E1B}\x{E47}\x{E19}" + text run at (0,37036) width 21: "\x{E0A}\x{E34}\x{E49}\x{E19}" + text run at (0,37066) width 24: "\x{E40}\x{E25}\x{E47}\x{E01}" + text run at (0,37096) width 21: "\x{E0A}\x{E34}\x{E49}\x{E19}" + text run at (0,37126) width 30: "\x{E19}\x{E49}\x{E2D}\x{E22}" + text run at (0,37156) width 25: "\x{E40}\x{E21}\x{E37}\x{E48}\x{E2D}" + text run at (0,37186) width 28: "\x{E1A}\x{E49}\x{E32}\x{E19}" + text run at (0,37216) width 25: "\x{E40}\x{E2D}\x{E19}" + text run at (0,37246) width 20: "\x{E25}\x{E49}\x{E21}" + text run at (0,37276) width 17: "\x{E25}\x{E07}" + text run at (0,37306) width 19: "\x{E2D}\x{E35}\x{E01}" + text run at (0,37336) width 26: "\x{E04}\x{E23}\x{E31}\x{E49}\x{E07}" + text run at (0,37366) width 20: "\x{E41}\x{E15}\x{E48}" + text run at (0,37396) width 36: "\x{E2B}\x{E25}\x{E32}\x{E22}" + text run at (0,37426) width 45: "\x{E0A}\x{E31}\x{E48}\x{E27}\x{E42}\x{E21}\x{E07}" + text run at (0,37456) width 28: "\x{E1C}\x{E48}\x{E32}\x{E19}" + text run at (0,37486) width 17: "\x{E44}\x{E1B}" + text run at (0,37516) width 10: "\x{E01}\x{E47}" + text run at (0,37546) width 18: "\x{E44}\x{E21}\x{E48}" + text run at (0,37576) width 11: "\x{E21}\x{E35}" + text run at (0,37606) width 32: "\x{E2D}\x{E30}\x{E44}\x{E23}" + text run at (0,37636) width 25: "\x{E40}\x{E01}\x{E34}\x{E14}" + text run at (0,37666) width 21: "\x{E02}\x{E36}\x{E49}\x{E19}" + text run at (0,37696) width 23: "\x{E40}\x{E18}\x{E2D}" + text run at (0,37726) width 24: "\x{E40}\x{E25}\x{E22}" + text run at (0,37756) width 24: "\x{E40}\x{E25}\x{E34}\x{E01}" + text run at (0,37786) width 29: "\x{E27}\x{E34}\x{E15}\x{E01}" + text run at (0,37816) width 27: "\x{E41}\x{E25}\x{E30}" + text run at (0,37846) width 40: "\x{E15}\x{E31}\x{E14}\x{E2A}\x{E34}\x{E19}" + text run at (0,37876) width 15: "\x{E43}\x{E08}" + text run at (0,37906) width 29: "\x{E04}\x{E2D}\x{E22}" + text run at (0,37936) width 10: "\x{E14}\x{E39}" + text run at (0,37966) width 34: "\x{E2D}\x{E22}\x{E48}\x{E32}\x{E07}" + text run at (0,37996) width 27: "\x{E2A}\x{E07}\x{E1A}" + text run at (0,38026) width 27: "\x{E41}\x{E25}\x{E30}" + text run at (0,38056) width 17: "\x{E23}\x{E2D}" + text run at (0,38086) width 16: "\x{E27}\x{E48}\x{E32}" + text run at (0,38116) width 47: "\x{E2D}\x{E19}\x{E32}\x{E04}\x{E15}" + text run at (0,38146) width 17: "\x{E08}\x{E30}" + text run at (0,38176) width 26: "\x{E40}\x{E1B}\x{E47}\x{E19}" + text run at (0,38206) width 49: "\x{E2D}\x{E22}\x{E48}\x{E32}\x{E07}\x{E44}\x{E23}" + text run at (0,38236) width 17: "\x{E43}\x{E19}" + text run at (0,38266) width 11: "\x{E17}\x{E35}\x{E48}" + text run at (0,38296) width 19: "\x{E2A}\x{E38}\x{E14}" + text run at (0,38326) width 23: "\x{E40}\x{E18}\x{E2D}" + text run at (0,38356) width 37: "\x{E04}\x{E25}\x{E32}\x{E19}" + text run at (0,38386) width 26: "\x{E08}\x{E32}\x{E01}" + text run at (0,38416) width 22: "\x{E1E}\x{E37}\x{E49}\x{E19}" + text run at (0,38446) width 27: "\x{E2B}\x{E49}\x{E2D}\x{E07}" + text run at (0,38476) width 11: "\x{E17}\x{E35}\x{E48}" + text run at (0,38506) width 27: "\x{E42}\x{E22}\x{E01}" + text run at (0,38536) width 17: "\x{E44}\x{E1B}" + text run at (0,38566) width 18: "\x{E21}\x{E32}" + text run at (0,38596) width 21: "\x{E02}\x{E36}\x{E49}\x{E19}" + text run at (0,38626) width 17: "\x{E44}\x{E1B}" + text run at (0,38656) width 21: "\x{E1A}\x{E19}" + text run at (0,38686) width 33: "\x{E40}\x{E15}\x{E35}\x{E22}\x{E07}" + text run at (0,38716) width 28: "\x{E41}\x{E25}\x{E49}\x{E27}" + text run at (0,38746) width 10: "\x{E01}\x{E47}" + text run at (0,38776) width 31: "\x{E19}\x{E2D}\x{E19}" + text run at (0,38806) width 17: "\x{E25}\x{E07}" + text run at (0,38836) width 17: "\x{E42}\x{E15}" + text run at (0,38866) width 17: "\x{E42}\x{E15}\x{E49}" + text run at (0,38896) width 28: "\x{E15}\x{E32}\x{E21}" + text run at (0,38926) width 20: "\x{E15}\x{E34}\x{E14}" + text run at (0,38956) width 18: "\x{E21}\x{E32}" + text run at (0,38986) width 31: "\x{E19}\x{E2D}\x{E19}" + text run at (0,39016) width 17: "\x{E25}\x{E07}" + text run at (0,39046) width 25: "\x{E43}\x{E01}\x{E25}\x{E49}" + text run at (0,39076) width 9: "\x{E46}" + text run at (0,39106) width 23: "\x{E40}\x{E18}\x{E2D}" + text run at (0,39136) width 18: "\x{E44}\x{E21}\x{E48}" + text run at (0,39166) width 17: "\x{E0A}\x{E49}\x{E32}" + text run at (0,39196) width 17: "\x{E42}\x{E14}" + text run at (0,39226) width 24: "\x{E42}\x{E23}\x{E18}\x{E35}" + text run at (0,39256) width 10: "\x{E01}\x{E47}" + text run at (0,39286) width 20: "\x{E1B}\x{E34}\x{E14}" + text run at (0,39316) width 17: "\x{E15}\x{E32}" + text run at (0,39346) width 17: "\x{E25}\x{E07}" + text run at (0,39376) width 29: "\x{E2B}\x{E25}\x{E31}\x{E1A}" + text run at (0,39406) width 38: "\x{E1C}\x{E25}\x{E47}\x{E2D}\x{E22}" + text run at (0,39436) width 17: "\x{E44}\x{E1B}" + text run at (0,39466) width 34: "\x{E2D}\x{E22}\x{E48}\x{E32}\x{E07}" + text run at (0,39496) width 31: "\x{E2A}\x{E19}\x{E34}\x{E17}" + text run at (0,39526) width 19: "\x{E17}\x{E31}\x{E49}\x{E07}" + text run at (0,39556) width 9: "\x{E46}" + text run at (0,39586) width 11: "\x{E17}\x{E35}\x{E48}" + text run at (0,39616) width 28: "\x{E1A}\x{E49}\x{E32}\x{E19}" + text run at (0,39646) width 27: "\x{E42}\x{E22}\x{E01}" + text run at (0,39676) width 17: "\x{E44}\x{E1B}" + text run at (0,39706) width 18: "\x{E21}\x{E32}" + text run at (0,39736) width 27: "\x{E41}\x{E25}\x{E30}" + text run at (0,39766) width 20: "\x{E25}\x{E21}" + text run at (0,39796) width 10: "\x{E01}\x{E47}" + text run at (0,39826) width 33: "\x{E04}\x{E23}\x{E32}\x{E07}" + text run at (0,39856) width 29: "\x{E2B}\x{E27}\x{E35}\x{E14}" + text run at (0,39886) width 28: "\x{E2B}\x{E27}\x{E37}\x{E2D}"
diff --git a/third_party/WebKit/LayoutTests/platform/android/svg/text/bidi-text-anchor-direction-expected.png b/third_party/WebKit/LayoutTests/platform/android/svg/text/bidi-text-anchor-direction-expected.png new file mode 100644 index 0000000..d3609fa7 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/android/svg/text/bidi-text-anchor-direction-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/virtual/gpu/fast/canvas/canvas-imageSmoothingQuality-expected.txt b/third_party/WebKit/LayoutTests/platform/android/virtual/gpu/fast/canvas/canvas-imageSmoothingQuality-expected.txt new file mode 100644 index 0000000..4bbed49a --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/android/virtual/gpu/fast/canvas/canvas-imageSmoothingQuality-expected.txt
@@ -0,0 +1,68 @@ +CONSOLE WARNING: The provided value '3223' is not a valid enum value of type ImageSmoothingQuality. +CONSOLE WARNING: The provided value 'bad_input' is not a valid enum value of type ImageSmoothingQuality. +CONSOLE WARNING: The provided value 'LOW' is not a valid enum value of type ImageSmoothingQuality. +CONSOLE WARNING: The provided value 'Medium' is not a valid enum value of type ImageSmoothingQuality. +Tests for the imageSmoothingQuality attribute. + +On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". + + +On getting, must return the last value it was set to. +PASS lowContext.imageSmoothingQuality is 'low' +PASS mediumContext.imageSmoothingQuality is 'medium' +PASS highContext.imageSmoothingQuality is 'high' + +FAIL lowData should not be {"0":0,"1":0,"2":0,"3":100}. +FAIL mediumData should not be {"0":0,"1":0,"2":0,"3":100}. +FAIL lowData should not be {"0":0,"1":0,"2":0,"3":100}. + +FAIL sampleAlpha(noFilterData) should be > sampleAlpha(lowData). Was 0 (of type number). +FAIL sampleAlpha(lowData) should be > sampleAlpha(mediumData). Was 100 (of type number). +FAIL sampleAlpha(mediumData) should be > sampleAlpha(highData). Was 100 (of type number). + + +On setting, it must be set to the new value. +highContext.imageSmoothingQuality = 'medium'; +PASS highContext.imageSmoothingQuality is 'medium' +PASS scaleImageData(highCanvas, highCanvas.imageSmoothingQuality); is mediumData +highContext.imageSmoothingQuality = 'high'; +PASS highContext.imageSmoothingQuality is 'high' +PASS scaleImageData(highCanvas, highCanvas.imageSmoothingQuality); is highData + + +When the CanvasRenderingContext2D object is created, the attribute must be set to 'low'. +PASS document.getElementById("default").getContext("2d").imageSmoothingQuality is 'low' + + +ImageSmoothingQuality can be set without real effect when imageSmoothingEnabled is false. +highContext.imageSmoothingEnabled = false; +PASS highContext.imageSmoothingQuality is 'high' +PASS scaleImageData(highCanvas, highCanvas.imageSmoothingQuality) is noFilterData +highContext.imageSmoothingQuality = 'medium' +PASS highContext.imageSmoothingQuality is 'medium' +PASS scaleImageData(highCanvas, highCanvas.imageSmoothingQuality) is noFilterData + + +Invalid Input is not accpeted. +highContext.imageSmoothingEnabled = true; highContext.imageSmoothingQuality = 'high'; +PASS scaleImageData(highCanvas, '3223') did not throw exception. +PASS highContext.imageSmoothingQuality is 'high' +PASS scaleImageData(highCanvas, 'bad_input') did not throw exception. +PASS highContext.imageSmoothingQuality is 'high' +PASS scaleImageData(highCanvas, 'LOW') did not throw exception. +PASS highContext.imageSmoothingQuality is 'high' +PASS scaleImageData(highCanvas, 'Medium') did not throw exception. +PASS highContext.imageSmoothingQuality is 'high' + + +The save() and restore() should work. +highContext.save(); highContext.imageSmoothingQuality = 'medium'; +PASS highContext.imageSmoothingQuality is 'medium' +PASS scaleImageData(highCanvas, highCanvas.imageSmoothingQuality); is mediumData +PASS highContext.restore(); highContext.imageSmoothingQuality is 'high' +PASS scaleImageData(highCanvas, highCanvas.imageSmoothingQuality); is highData + +PASS successfullyParsed is true + +TEST COMPLETE +
diff --git a/third_party/WebKit/LayoutTests/platform/android/webaudio/codec-tests/aac/vbr-128kbps-44khz-expected.wav b/third_party/WebKit/LayoutTests/platform/android/webaudio/codec-tests/aac/vbr-128kbps-44khz-expected.wav deleted file mode 100644 index 101fe59..0000000 --- a/third_party/WebKit/LayoutTests/platform/android/webaudio/codec-tests/aac/vbr-128kbps-44khz-expected.wav +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/webaudio/codec-tests/mp3/128kbps-44khz-expected.wav b/third_party/WebKit/LayoutTests/platform/android/webaudio/codec-tests/mp3/128kbps-44khz-expected.wav deleted file mode 100644 index 839cc6a6..0000000 --- a/third_party/WebKit/LayoutTests/platform/android/webaudio/codec-tests/mp3/128kbps-44khz-expected.wav +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/webaudio/codec-tests/vorbis/vbr-128kbps-44khz-expected.wav b/third_party/WebKit/LayoutTests/platform/android/webaudio/codec-tests/vorbis/vbr-128kbps-44khz-expected.wav deleted file mode 100644 index 47589fb7..0000000 --- a/third_party/WebKit/LayoutTests/platform/android/webaudio/codec-tests/vorbis/vbr-128kbps-44khz-expected.wav +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/webaudio/codec-tests/vorbis/vbr-70kbps-44khz-expected.wav b/third_party/WebKit/LayoutTests/platform/android/webaudio/codec-tests/vorbis/vbr-70kbps-44khz-expected.wav deleted file mode 100644 index 2a68ec50..0000000 --- a/third_party/WebKit/LayoutTests/platform/android/webaudio/codec-tests/vorbis/vbr-70kbps-44khz-expected.wav +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/webaudio/codec-tests/vorbis/vbr-96kbps-44khz-expected.wav b/third_party/WebKit/LayoutTests/platform/android/webaudio/codec-tests/vorbis/vbr-96kbps-44khz-expected.wav deleted file mode 100644 index 12d546b..0000000 --- a/third_party/WebKit/LayoutTests/platform/android/webaudio/codec-tests/vorbis/vbr-96kbps-44khz-expected.wav +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/webaudio/codec-tests/wav/24bit-22khz-resample-expected.wav b/third_party/WebKit/LayoutTests/platform/android/webaudio/codec-tests/wav/24bit-22khz-resample-expected.wav deleted file mode 100644 index db1aa4ab..0000000 --- a/third_party/WebKit/LayoutTests/platform/android/webaudio/codec-tests/wav/24bit-22khz-resample-expected.wav +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux-precise/compositing/overflow/updating-scrolling-content-expected.txt b/third_party/WebKit/LayoutTests/platform/linux-precise/compositing/overflow/updating-scrolling-content-expected.txt deleted file mode 100644 index a7f39b53..0000000 --- a/third_party/WebKit/LayoutTests/platform/linux-precise/compositing/overflow/updating-scrolling-content-expected.txt +++ /dev/null
@@ -1,64 +0,0 @@ -{ - "bounds": [800, 600], - "children": [ - { - "bounds": [800, 600], - "contentsOpaque": true, - "drawsContent": true, - "children": [ - { - "position": [8, 8], - "bounds": [200, 200], - "shouldFlattenTransform": false, - "drawsContent": true, - "repaintRects": [ - [0, 0, 185, 200] - ], - "paintInvalidationClients": [ - "LayoutBlockFlow DIV id='indicator'" - ], - "children": [ - { - "bounds": [185, 185], - "shouldFlattenTransform": false, - "children": [ - { - "bounds": [185, 1200], - "drawsContent": true, - "repaintRects": [ - [0, 0, 185, 200] - ], - "paintInvalidationClients": [ - "LayoutBlockFlow DIV id='indicator'" - ] - } - ] - }, - { - "bounds": [200, 200], - "children": [ - { - "position": [0, 185], - "bounds": [185, 15] - }, - { - "position": [185, 0], - "bounds": [15, 185], - "repaintRects": [ - [0, 0, 15, 185] - ] - }, - { - "position": [185, 185], - "bounds": [15, 15], - "drawsContent": true - } - ] - } - ] - } - ] - } - ] -} -
diff --git a/third_party/WebKit/LayoutTests/platform/linux-precise/fast/canvas/canvas-shadow-source-in-expected.png b/third_party/WebKit/LayoutTests/platform/linux-precise/fast/canvas/canvas-shadow-source-in-expected.png deleted file mode 100644 index 86319185..0000000 --- a/third_party/WebKit/LayoutTests/platform/linux-precise/fast/canvas/canvas-shadow-source-in-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux-precise/fast/canvas/canvas-shadow-source-in-expected.txt b/third_party/WebKit/LayoutTests/platform/linux-precise/fast/canvas/canvas-shadow-source-in-expected.txt deleted file mode 100644 index a13484d9..0000000 --- a/third_party/WebKit/LayoutTests/platform/linux-precise/fast/canvas/canvas-shadow-source-in-expected.txt +++ /dev/null
@@ -1,21 +0,0 @@ -layer at (0,0) size 800x600 - LayoutView at (0,0) size 800x600 -layer at (0,0) size 800x470 - LayoutBlockFlow {HTML} at (0,0) size 800x470 - LayoutBlockFlow {BODY} at (8,8) size 784x454 - LayoutBlockFlow {DIV} at (0,0) size 784x20 - LayoutText {#text} at (0,0) size 57x19 - text run at (0,0) width 57: "Test Rect" - LayoutBlockFlow (anonymous) at (0,20) size 784x207 - LayoutText {#text} at (0,0) size 0x0 - LayoutBlockFlow {DIV} at (0,227) size 784x20 - LayoutText {#text} at (0,0) size 66x19 - text run at (0,0) width 66: "Test Image" - LayoutBlockFlow (anonymous) at (0,247) size 784x207 - LayoutText {#text} at (0,0) size 0x0 - LayoutText {#text} at (0,0) size 0x0 - LayoutText {#text} at (0,0) size 0x0 -layer at (8,28) size 202x202 - LayoutHTMLCanvas {CANVAS} at (0,0) size 202x202 [border: (1px solid #999999)] -layer at (8,255) size 202x202 - LayoutHTMLCanvas {CANVAS} at (0,0) size 202x202 [border: (1px solid #999999)]
diff --git a/third_party/WebKit/LayoutTests/platform/linux-precise/fast/canvas/canvas-toBlob-jpeg-maximum-quality-expected.png b/third_party/WebKit/LayoutTests/platform/linux-precise/fast/canvas/canvas-toBlob-jpeg-maximum-quality-expected.png deleted file mode 100644 index e374c1c5..0000000 --- a/third_party/WebKit/LayoutTests/platform/linux-precise/fast/canvas/canvas-toBlob-jpeg-maximum-quality-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux-precise/fast/canvas/canvas-toBlob-jpeg-medium-quality-expected.png b/third_party/WebKit/LayoutTests/platform/linux-precise/fast/canvas/canvas-toBlob-jpeg-medium-quality-expected.png deleted file mode 100644 index 8019bf0..0000000 --- a/third_party/WebKit/LayoutTests/platform/linux-precise/fast/canvas/canvas-toBlob-jpeg-medium-quality-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux-precise/fast/canvas/canvas-toBlob-webp-maximum-quality-expected.png b/third_party/WebKit/LayoutTests/platform/linux-precise/fast/canvas/canvas-toBlob-webp-maximum-quality-expected.png deleted file mode 100644 index 1fd814b37..0000000 --- a/third_party/WebKit/LayoutTests/platform/linux-precise/fast/canvas/canvas-toBlob-webp-maximum-quality-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux-precise/fast/text/international/thai-line-breaks-expected.png b/third_party/WebKit/LayoutTests/platform/linux-precise/fast/text/international/thai-line-breaks-expected.png new file mode 100644 index 0000000..c15ebfc --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/linux-precise/fast/text/international/thai-line-breaks-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux-precise/paint/selection/selection-within-composited-scroller-expected.txt b/third_party/WebKit/LayoutTests/platform/linux-precise/paint/selection/selection-within-composited-scroller-expected.txt deleted file mode 100644 index 8215dfa..0000000 --- a/third_party/WebKit/LayoutTests/platform/linux-precise/paint/selection/selection-within-composited-scroller-expected.txt +++ /dev/null
@@ -1,73 +0,0 @@ -{ - "bounds": [800, 600], - "children": [ - { - "bounds": [800, 600], - "contentsOpaque": true, - "drawsContent": true, - "paintInvalidationClients": [ - "LayoutBlockFlow HTML", - "LayoutBlockFlow BODY" - ], - "children": [ - { - "position": [8, 8], - "bounds": [200, 200], - "contentsOpaque": true, - "shouldFlattenTransform": false, - "drawsContent": true, - "backgroundColor": "#D3D3D3", - "repaintRects": [ - [0, 160, 21, 19] - ], - "paintInvalidationClients": [ - "LayoutBlockFlow DIV id='scroller'", - "LayoutBlockFlow DIV id='target'", - "LayoutText #text", - "InlineTextBox 'test'" - ], - "children": [ - { - "bounds": [185, 185], - "shouldFlattenTransform": false, - "children": [ - { - "bounds": [200, 1620], - "drawsContent": true, - "repaintRects": [ - [0, 610, 21, 19] - ], - "paintInvalidationClients": [ - "LayoutBlockFlow DIV id='scroller'", - "LayoutBlockFlow DIV id='target'", - "LayoutText #text", - "InlineTextBox 'test'" - ] - } - ] - }, - { - "bounds": [200, 200], - "children": [ - { - "position": [0, 185], - "bounds": [185, 15] - }, - { - "position": [185, 0], - "bounds": [15, 185] - }, - { - "position": [185, 185], - "bounds": [15, 15], - "drawsContent": true - } - ] - } - ] - } - ] - } - ] -} -
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/canvas/canvas-shadow-source-in-expected.png b/third_party/WebKit/LayoutTests/platform/linux-precise/virtual/display_list_2d_canvas/fast/canvas/canvas-shadow-source-in-expected.png similarity index 100% copy from third_party/WebKit/LayoutTests/platform/android/fast/canvas/canvas-shadow-source-in-expected.png copy to third_party/WebKit/LayoutTests/platform/linux-precise/virtual/display_list_2d_canvas/fast/canvas/canvas-shadow-source-in-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/canvas/canvas-shadow-source-in-expected.png b/third_party/WebKit/LayoutTests/platform/linux-x86/virtual/display_list_2d_canvas/fast/canvas/canvas-shadow-source-in-expected.png similarity index 100% rename from third_party/WebKit/LayoutTests/platform/android/fast/canvas/canvas-shadow-source-in-expected.png rename to third_party/WebKit/LayoutTests/platform/linux-x86/virtual/display_list_2d_canvas/fast/canvas/canvas-shadow-source-in-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/compositing/overflow/updating-scrolling-content-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/compositing/overflow/updating-scrolling-content-expected.txt deleted file mode 100644 index c1d6cc2..0000000 --- a/third_party/WebKit/LayoutTests/platform/linux/compositing/overflow/updating-scrolling-content-expected.txt +++ /dev/null
@@ -1,64 +0,0 @@ -{ - "bounds": [1600, 1200], - "children": [ - { - "bounds": [1600, 1200], - "contentsOpaque": true, - "drawsContent": true, - "children": [ - { - "position": [8, 8], - "bounds": [200, 200], - "shouldFlattenTransform": false, - "drawsContent": true, - "repaintRects": [ - [0, 0, 185, 200] - ], - "paintInvalidationClients": [ - "LayoutBlockFlow DIV id='indicator'" - ], - "children": [ - { - "bounds": [185, 185], - "shouldFlattenTransform": false, - "children": [ - { - "bounds": [185, 1200], - "drawsContent": true, - "repaintRects": [ - [0, 0, 185, 200] - ], - "paintInvalidationClients": [ - "LayoutBlockFlow DIV id='indicator'" - ] - } - ] - }, - { - "bounds": [200, 200], - "children": [ - { - "position": [0, 185], - "bounds": [185, 15] - }, - { - "position": [185, 0], - "bounds": [15, 185], - "repaintRects": [ - [0, 0, 15, 185] - ] - }, - { - "position": [185, 185], - "bounds": [15, 15], - "drawsContent": true - } - ] - } - ] - } - ] - } - ] -} -
diff --git a/third_party/WebKit/LayoutTests/platform/linux/compositing/repaint/should-not-clip-composited-overflow-scrolling-layer-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/compositing/repaint/should-not-clip-composited-overflow-scrolling-layer-expected.txt index e6b501c..8e980e48 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/compositing/repaint/should-not-clip-composited-overflow-scrolling-layer-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/compositing/repaint/should-not-clip-composited-overflow-scrolling-layer-expected.txt
@@ -15,7 +15,8 @@ [-2000, -2000, 5000, 5000] ], "paintInvalidationClients": [ - "LayoutBlockFlow DIV id='content'" + "LayoutBlockFlow DIV id='content'", + "RootInlineBox" ], "children": [ { @@ -29,7 +30,8 @@ [0, 0, 5000, 5000] ], "paintInvalidationClients": [ - "LayoutBlockFlow DIV id='content'" + "LayoutBlockFlow DIV id='content'", + "RootInlineBox" ] } ]
diff --git a/third_party/WebKit/LayoutTests/platform/linux/css1/box_properties/float_on_text_elements-expected.png b/third_party/WebKit/LayoutTests/platform/linux/css1/box_properties/float_on_text_elements-expected.png index 3f7cf98742..e65c0282 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/css1/box_properties/float_on_text_elements-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/css1/box_properties/float_on_text_elements-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/css2.1/t0905-c5525-fltwidth-00-c-g-expected.png b/third_party/WebKit/LayoutTests/platform/linux/css2.1/t0905-c5525-fltwidth-00-c-g-expected.png index e6a7cc2f..7f4df964 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/css2.1/t0905-c5525-fltwidth-00-c-g-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/css2.1/t0905-c5525-fltwidth-00-c-g-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/canvas/canvas-shadow-source-in-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/canvas/canvas-shadow-source-in-expected.png index b5daa85..7f82cd3 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/fast/canvas/canvas-shadow-source-in-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/fast/canvas/canvas-shadow-source-in-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/canvas/canvas-shadow-source-in-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/fast/canvas/canvas-shadow-source-in-expected.txt index c895823..a13484d9 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/fast/canvas/canvas-shadow-source-in-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/fast/canvas/canvas-shadow-source-in-expected.txt
@@ -1,17 +1,17 @@ -layer at (0,0) size 1600x1200 - LayoutView at (0,0) size 1600x1200 -layer at (0,0) size 1600x470 - LayoutBlockFlow {HTML} at (0,0) size 1600x470 - LayoutBlockFlow {BODY} at (8,8) size 1584x454 - LayoutBlockFlow {DIV} at (0,0) size 1584x20 +layer at (0,0) size 800x600 + LayoutView at (0,0) size 800x600 +layer at (0,0) size 800x470 + LayoutBlockFlow {HTML} at (0,0) size 800x470 + LayoutBlockFlow {BODY} at (8,8) size 784x454 + LayoutBlockFlow {DIV} at (0,0) size 784x20 LayoutText {#text} at (0,0) size 57x19 text run at (0,0) width 57: "Test Rect" - LayoutBlockFlow (anonymous) at (0,20) size 1584x207 + LayoutBlockFlow (anonymous) at (0,20) size 784x207 LayoutText {#text} at (0,0) size 0x0 - LayoutBlockFlow {DIV} at (0,227) size 1584x20 + LayoutBlockFlow {DIV} at (0,227) size 784x20 LayoutText {#text} at (0,0) size 66x19 text run at (0,0) width 66: "Test Image" - LayoutBlockFlow (anonymous) at (0,247) size 1584x207 + LayoutBlockFlow (anonymous) at (0,247) size 784x207 LayoutText {#text} at (0,0) size 0x0 LayoutText {#text} at (0,0) size 0x0 LayoutText {#text} at (0,0) size 0x0
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/images/color-profile-munsell-adobe-to-srgb-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/images/color-profile-munsell-adobe-to-srgb-expected.png new file mode 100644 index 0000000..04db618 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/linux/fast/images/color-profile-munsell-adobe-to-srgb-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/images/color-profile-munsell-adobe-to-srgb-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/fast/images/color-profile-munsell-adobe-to-srgb-expected.txt new file mode 100644 index 0000000..d5d9e0d21 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/linux/fast/images/color-profile-munsell-adobe-to-srgb-expected.txt
@@ -0,0 +1,42 @@ + +Color Actual Expected dE +-------------------------------------------- +Dark Skin 115,80,64 115,80,64 0 +Light Skin 195,150,130 195,151,130 1 +Blue Sky 94,123,157 94,123,156 1 +Foliage 89,108,65 88,108,65 1 +Blue Flower 130,129,177 130,129,177 0 +Bluish Green 100,190,171 100,190,171 0 +-------------------------------------------- +Orange 216,122,37 217,122,37 1 +Purplish Blue 72,91,166 72,91,165 1 +Moderate Red 194,84,97 194,84,98 1 +Purple 91,60,107 91,59,107 1 +Yellow Green 160,187,60 160,188,60 1 +Orange Yellow 230,163,42 230,163,42 0 +-------------------------------------------- +Blue 47,60,153 46,60,153 1 +Green 70,149,69 71,150,69 1 +Red 177,44,56 177,44,56 0 +Yellow 239,200,27 238,200,27 1 +Magenta 187,82,147 187,82,148 1 +Cyan (*) 0,135,166 0,135,166 0 +-------------------------------------------- +White 243,241,236 243,242,237 1 +Neutral 8 201,201,200 201,201,201 1 +Neutral 6.5 160,161,160 161,161,161 1 +Neutral 5 123,122,121 122,122,121 1 +Neutral 3.5 83,83,83 83,83,83 0 +Black 50,50,50 50,49,50 1 +-------------------------------------------- + +Result: total RMS color error: 0.84 + * Munsell Cyan is outside 255 sRGB gamut + + + + + + + +
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/repaint/make-children-non-inline-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/fast/repaint/make-children-non-inline-expected.txt index 847a541..7a15ab6 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/fast/repaint/make-children-non-inline-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/fast/repaint/make-children-non-inline-expected.txt
@@ -10,11 +10,11 @@ [8, 304, 27, 19], [8, 284, 65, 19], [8, 264, 784, 80], - [8, 264, 106, 19], + [8, 264, 105, 19], [8, 224, 61, 19], [8, 204, 27, 19], [8, 184, 65, 19], - [8, 164, 106, 19], + [8, 164, 105, 19], [8, 164, 10, 100], [8, 144, 77, 19], [8, 124, 42, 19],
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/text/drawBidiText-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/fast/text/drawBidiText-expected.txt index 64bbf30..dea626fc5 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/fast/text/drawBidiText-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/fast/text/drawBidiText-expected.txt
@@ -32,8 +32,8 @@ LayoutText {#text} at (2,0) size 100x21 text run at (2,0) width 100 RTL: "\x{5DE}\x{5E9}\x{5D4}\x{5D5} \x{5E2}\x{5DD} \x{5E0}\x{5B4}\x{5E7}\x{5BC}\x{5D5}\x{5BC}\x{5D3}" LayoutBlockFlow {OPTION} at (1,116) size 309.69x23 - LayoutText {#text} at (2,0) size 70x21 - text run at (2,0) width 70 RTL: "\x{627}\x{644}\x{644}\x{63A}\x{629} \x{627}\x{644}\x{639}\x{631}\x{628}\x{64A}\x{629}" + LayoutText {#text} at (2,0) size 76x21 + text run at (2,0) width 76 RTL: "\x{627}\x{644}\x{644}\x{63A}\x{629} \x{627}\x{644}\x{639}\x{631}\x{628}\x{64A}\x{629}" LayoutBlockFlow {OPTION} at (1,139) size 309.69x23 LayoutText {#text} at (2,0) size 126x21 text run at (2,0) width 126: "Et volia\x{300}: ATSUI!"
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/text/international/thai-line-breaks-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/text/international/thai-line-breaks-expected.png index 87846ec8..7ae9e49e 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/fast/text/international/thai-line-breaks-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/fast/text/international/thai-line-breaks-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/text/international/thai-line-breaks-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/fast/text/international/thai-line-breaks-expected.txt index 0d802192..9fdcddd 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/fast/text/international/thai-line-breaks-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/fast/text/international/thai-line-breaks-expected.txt
@@ -7,7 +7,7 @@ LayoutText {#text} at (0,0) size 747x59 text run at (0,0) width 747: "The column on the right has explicit spaces. Line breaks should be roughly the same if Thai line breaks are working well. The" text run at (0,20) width 734: "original source of this text was ICU, and the test program said \"by it's very nature, Thai word breaking is not exact\", so the" - text run at (0,40) width 742: "columns don't match exactly. In a future version we might decide to tweak the right column to match our expected behavior." + text run at (0,40) width 741: "columns don't match exactly. In a future version we might decide to tweak the right column to match our expected behavior." layer at (236,84) size 1x38040 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600 LayoutBlockFlow (positioned) {DIV} at (235.50,84) size 1x38040 LayoutText {#text} at (0,6) size 84x38029
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/selection/selection-within-composited-scroller-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/selection/selection-within-composited-scroller-expected.txt index 4f797c0..8215dfa 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/paint/selection/selection-within-composited-scroller-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/paint/selection/selection-within-composited-scroller-expected.txt
@@ -18,7 +18,7 @@ "drawsContent": true, "backgroundColor": "#D3D3D3", "repaintRects": [ - [0, 160, 21, 17] + [0, 160, 21, 19] ], "paintInvalidationClients": [ "LayoutBlockFlow DIV id='scroller'", @@ -35,7 +35,7 @@ "bounds": [200, 1620], "drawsContent": true, "repaintRects": [ - [0, 610, 21, 17] + [0, 610, 21, 19] ], "paintInvalidationClients": [ "LayoutBlockFlow DIV id='scroller'",
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/batik/filters/feTile-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/batik/filters/feTile-expected.png index ff40f47d..9f768af 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/svg/batik/filters/feTile-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/svg/batik/filters/feTile-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/text/bidi-text-anchor-direction-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/text/bidi-text-anchor-direction-expected.png index d3609fa7..97c2cb3 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/svg/text/bidi-text-anchor-direction-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/svg/text/bidi-text-anchor-direction-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/display_list_2d_canvas/fast/canvas/canvas-shadow-source-in-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/display_list_2d_canvas/fast/canvas/canvas-shadow-source-in-expected.png index 86319185..7f82cd3 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/virtual/display_list_2d_canvas/fast/canvas/canvas-shadow-source-in-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/display_list_2d_canvas/fast/canvas/canvas-shadow-source-in-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux-x86/virtual/display_list_2d_canvas/fast/canvas/canvas-shadow-source-in-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/display_list_2d_canvas/fast/canvas/canvas-shadow-source-in-expected.txt similarity index 100% rename from third_party/WebKit/LayoutTests/platform/linux-x86/virtual/display_list_2d_canvas/fast/canvas/canvas-shadow-source-in-expected.txt rename to third_party/WebKit/LayoutTests/platform/linux/virtual/display_list_2d_canvas/fast/canvas/canvas-shadow-source-in-expected.txt
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/compositing/color-matching/image-color-matching-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-lion/compositing/color-matching/image-color-matching-expected.txt deleted file mode 100644 index 07761c2..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac-lion/compositing/color-matching/image-color-matching-expected.txt +++ /dev/null
@@ -1,22 +0,0 @@ -layer at (0,0) size 800x600 - LayoutView at (0,0) size 800x600 -layer at (0,0) size 800x546 - LayoutBlockFlow {HTML} at (0,0) size 800x546 - LayoutBlockFlow {BODY} at (8,16) size 784x522 [color=#FFFFFF] [bgcolor=#000000] - LayoutBlockFlow {P} at (0,0) size 784x18 - LayoutText {#text} at (0,0) size 210x18 - text run at (0,0) width 210: "Images should all look the same." - LayoutBlockFlow {DIV} at (0,34) size 784x244 - LayoutImage {IMG} at (0,0) size 360x240 - LayoutText {#text} at (360,226) size 4x18 - text run at (360,226) width 4: " " - LayoutImage {IMG} at (364,0) size 360x240 - LayoutText {#text} at (0,0) size 0x0 - LayoutBlockFlow {DIV} at (0,278) size 784x244 - LayoutText {#text} at (360,226) size 4x18 - text run at (360,226) width 4: " " - LayoutText {#text} at (0,0) size 0x0 -layer at (8,294) size 360x240 - LayoutImage {IMG} at (0,0) size 360x240 -layer at (372,294) size 360x240 - LayoutImage {IMG} at (364,0) size 360x240
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/compositing/overflow/updating-scrolling-content-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-lion/compositing/overflow/updating-scrolling-content-expected.txt deleted file mode 100644 index a7f39b53..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac-lion/compositing/overflow/updating-scrolling-content-expected.txt +++ /dev/null
@@ -1,64 +0,0 @@ -{ - "bounds": [800, 600], - "children": [ - { - "bounds": [800, 600], - "contentsOpaque": true, - "drawsContent": true, - "children": [ - { - "position": [8, 8], - "bounds": [200, 200], - "shouldFlattenTransform": false, - "drawsContent": true, - "repaintRects": [ - [0, 0, 185, 200] - ], - "paintInvalidationClients": [ - "LayoutBlockFlow DIV id='indicator'" - ], - "children": [ - { - "bounds": [185, 185], - "shouldFlattenTransform": false, - "children": [ - { - "bounds": [185, 1200], - "drawsContent": true, - "repaintRects": [ - [0, 0, 185, 200] - ], - "paintInvalidationClients": [ - "LayoutBlockFlow DIV id='indicator'" - ] - } - ] - }, - { - "bounds": [200, 200], - "children": [ - { - "position": [0, 185], - "bounds": [185, 15] - }, - { - "position": [185, 0], - "bounds": [15, 185], - "repaintRects": [ - [0, 0, 15, 185] - ] - }, - { - "position": [185, 185], - "bounds": [15, 15], - "drawsContent": true - } - ] - } - ] - } - ] - } - ] -} -
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/frames/iframe-scaling-with-scroll-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/frames/iframe-scaling-with-scroll-expected.png index dc13afe..afde499 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/frames/iframe-scaling-with-scroll-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/frames/iframe-scaling-with-scroll-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/text/atsui-spacing-features-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/text/atsui-spacing-features-expected.png new file mode 100644 index 0000000..c3fff4b --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/text/atsui-spacing-features-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/text/international/thai-line-breaks-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/text/international/thai-line-breaks-expected.png index 299314a6..72154ee 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/text/international/thai-line-breaks-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/text/international/thai-line-breaks-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/virtual/display_list_2d_canvas/fast/canvas/canvas-shadow-source-in-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/virtual/display_list_2d_canvas/fast/canvas/canvas-shadow-source-in-expected.png new file mode 100644 index 0000000..6dcdb8e1 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac-lion/virtual/display_list_2d_canvas/fast/canvas/canvas-shadow-source-in-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/virtual/gpu/fast/canvas/image-object-in-canvas-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/virtual/gpu/fast/canvas/image-object-in-canvas-expected.png deleted file mode 100644 index e6c9851c..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac-lion/virtual/gpu/fast/canvas/image-object-in-canvas-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/compositing/color-matching/image-color-matching-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mavericks/compositing/color-matching/image-color-matching-expected.txt deleted file mode 100644 index d28c7e3..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/compositing/color-matching/image-color-matching-expected.txt +++ /dev/null
@@ -1,22 +0,0 @@ -layer at (0,0) size 1600x1200 - LayoutView at (0,0) size 1600x1200 -layer at (0,0) size 1600x546 - LayoutBlockFlow {HTML} at (0,0) size 1600x546 - LayoutBlockFlow {BODY} at (8,16) size 1584x522 [color=#FFFFFF] [bgcolor=#000000] - LayoutBlockFlow {P} at (0,0) size 1584x18 - LayoutText {#text} at (0,0) size 210x18 - text run at (0,0) width 210: "Images should all look the same." - LayoutBlockFlow {DIV} at (0,34) size 1584x244 - LayoutImage {IMG} at (0,0) size 360x240 - LayoutText {#text} at (360,226) size 4x18 - text run at (360,226) width 4: " " - LayoutImage {IMG} at (364,0) size 360x240 - LayoutText {#text} at (0,0) size 0x0 - LayoutBlockFlow {DIV} at (0,278) size 1584x244 - LayoutText {#text} at (360,226) size 4x18 - text run at (360,226) width 4: " " - LayoutText {#text} at (0,0) size 0x0 -layer at (8,294) size 360x240 - LayoutImage {IMG} at (0,0) size 360x240 -layer at (372,294) size 360x240 - LayoutImage {IMG} at (364,0) size 360x240
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/compositing/overflow/updating-scrolling-content-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mavericks/compositing/overflow/updating-scrolling-content-expected.txt deleted file mode 100644 index c1d6cc2..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/compositing/overflow/updating-scrolling-content-expected.txt +++ /dev/null
@@ -1,64 +0,0 @@ -{ - "bounds": [1600, 1200], - "children": [ - { - "bounds": [1600, 1200], - "contentsOpaque": true, - "drawsContent": true, - "children": [ - { - "position": [8, 8], - "bounds": [200, 200], - "shouldFlattenTransform": false, - "drawsContent": true, - "repaintRects": [ - [0, 0, 185, 200] - ], - "paintInvalidationClients": [ - "LayoutBlockFlow DIV id='indicator'" - ], - "children": [ - { - "bounds": [185, 185], - "shouldFlattenTransform": false, - "children": [ - { - "bounds": [185, 1200], - "drawsContent": true, - "repaintRects": [ - [0, 0, 185, 200] - ], - "paintInvalidationClients": [ - "LayoutBlockFlow DIV id='indicator'" - ] - } - ] - }, - { - "bounds": [200, 200], - "children": [ - { - "position": [0, 185], - "bounds": [185, 15] - }, - { - "position": [185, 0], - "bounds": [15, 185], - "repaintRects": [ - [0, 0, 15, 185] - ] - }, - { - "position": [185, 185], - "bounds": [15, 15], - "drawsContent": true - } - ] - } - ] - } - ] - } - ] -} -
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/canvas/canvas-shadow-source-in-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/canvas/canvas-shadow-source-in-expected.png deleted file mode 100644 index b5daa85..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/canvas/canvas-shadow-source-in-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/canvas/canvas-shadow-source-in-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/canvas/canvas-shadow-source-in-expected.txt deleted file mode 100644 index f3fc678..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/canvas/canvas-shadow-source-in-expected.txt +++ /dev/null
@@ -1,21 +0,0 @@ -layer at (0,0) size 1600x1200 - LayoutView at (0,0) size 1600x1200 -layer at (0,0) size 1600x464 - LayoutBlockFlow {HTML} at (0,0) size 1600x464 - LayoutBlockFlow {BODY} at (8,8) size 1584x448 - LayoutBlockFlow {DIV} at (0,0) size 1584x18 - LayoutText {#text} at (0,0) size 60x18 - text run at (0,0) width 60: "Test Rect" - LayoutBlockFlow (anonymous) at (0,18) size 1584x206 - LayoutText {#text} at (0,0) size 0x0 - LayoutBlockFlow {DIV} at (0,224) size 1584x18 - LayoutText {#text} at (0,0) size 71x18 - text run at (0,0) width 71: "Test Image" - LayoutBlockFlow (anonymous) at (0,242) size 1584x206 - LayoutText {#text} at (0,0) size 0x0 - LayoutText {#text} at (0,0) size 0x0 - LayoutText {#text} at (0,0) size 0x0 -layer at (8,26) size 202x202 - LayoutHTMLCanvas {CANVAS} at (0,0) size 202x202 [border: (1px solid #999999)] -layer at (8,250) size 202x202 - LayoutHTMLCanvas {CANVAS} at (0,0) size 202x202 [border: (1px solid #999999)]
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/frames/iframe-scaling-with-scroll-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/frames/iframe-scaling-with-scroll-expected.png index 0765410..a229235 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/frames/iframe-scaling-with-scroll-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/frames/iframe-scaling-with-scroll-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/text/drawBidiText-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/text/drawBidiText-expected.txt index 3467d947..df3d85b 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/text/drawBidiText-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/text/drawBidiText-expected.txt
@@ -32,8 +32,8 @@ LayoutText {#text} at (2,0) size 113x21 text run at (2,0) width 113 RTL: "\x{5DE}\x{5E9}\x{5D4}\x{5D5} \x{5E2}\x{5DD} \x{5E0}\x{5B4}\x{5E7}\x{5BC}\x{5D5}\x{5BC}\x{5D3}" LayoutBlockFlow {OPTION} at (1,113.97) size 331.80x25 - LayoutText {#text} at (2,0) size 74x21 - text run at (2,0) width 74 RTL: "\x{627}\x{644}\x{644}\x{63A}\x{629} \x{627}\x{644}\x{639}\x{631}\x{628}\x{64A}\x{629}" + LayoutText {#text} at (2,0) size 77x21 + text run at (2,0) width 77 RTL: "\x{627}\x{644}\x{644}\x{63A}\x{629} \x{627}\x{644}\x{639}\x{631}\x{628}\x{64A}\x{629}" LayoutBlockFlow {OPTION} at (1,138.97) size 331.80x22.59 LayoutText {#text} at (2,0) size 132x21 text run at (2,0) width 132: "Et volia\x{300}: ATSUI!"
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/text/international/thai-line-breaks-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/text/international/thai-line-breaks-expected.png index 436a3c86..5c4f715 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/text/international/thai-line-breaks-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/text/international/thai-line-breaks-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/virtual/display_list_2d_canvas/fast/canvas/canvas-shadow-source-in-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/virtual/display_list_2d_canvas/fast/canvas/canvas-shadow-source-in-expected.png new file mode 100644 index 0000000..6dcdb8e1 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/virtual/display_list_2d_canvas/fast/canvas/canvas-shadow-source-in-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mountainlion/fast/canvas/canvas-shadow-source-in-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mountainlion/fast/canvas/canvas-shadow-source-in-expected.png deleted file mode 100644 index b7a76dd..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac-mountainlion/fast/canvas/canvas-shadow-source-in-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mountainlion/fast/text/atsui-spacing-features-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mountainlion/fast/text/atsui-spacing-features-expected.png new file mode 100644 index 0000000..f92096f --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac-mountainlion/fast/text/atsui-spacing-features-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mountainlion/fast/text/international/thai-line-breaks-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mountainlion/fast/text/international/thai-line-breaks-expected.png index 35cf628..807fc1a6 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mountainlion/fast/text/international/thai-line-breaks-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mountainlion/fast/text/international/thai-line-breaks-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mountainlion/virtual/display_list_2d_canvas/fast/canvas/canvas-shadow-source-in-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mountainlion/virtual/display_list_2d_canvas/fast/canvas/canvas-shadow-source-in-expected.png new file mode 100644 index 0000000..6dcdb8e1 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac-mountainlion/virtual/display_list_2d_canvas/fast/canvas/canvas-shadow-source-in-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mountainlion/virtual/gpu/fast/canvas/image-object-in-canvas-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mountainlion/virtual/gpu/fast/canvas/image-object-in-canvas-expected.png deleted file mode 100644 index 89124bdd..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac-mountainlion/virtual/gpu/fast/canvas/image-object-in-canvas-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/compositing/overflow/updating-scrolling-content-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-retina/compositing/overflow/updating-scrolling-content-expected.txt deleted file mode 100644 index a7f39b53..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac-retina/compositing/overflow/updating-scrolling-content-expected.txt +++ /dev/null
@@ -1,64 +0,0 @@ -{ - "bounds": [800, 600], - "children": [ - { - "bounds": [800, 600], - "contentsOpaque": true, - "drawsContent": true, - "children": [ - { - "position": [8, 8], - "bounds": [200, 200], - "shouldFlattenTransform": false, - "drawsContent": true, - "repaintRects": [ - [0, 0, 185, 200] - ], - "paintInvalidationClients": [ - "LayoutBlockFlow DIV id='indicator'" - ], - "children": [ - { - "bounds": [185, 185], - "shouldFlattenTransform": false, - "children": [ - { - "bounds": [185, 1200], - "drawsContent": true, - "repaintRects": [ - [0, 0, 185, 200] - ], - "paintInvalidationClients": [ - "LayoutBlockFlow DIV id='indicator'" - ] - } - ] - }, - { - "bounds": [200, 200], - "children": [ - { - "position": [0, 185], - "bounds": [185, 15] - }, - { - "position": [185, 0], - "bounds": [15, 185], - "repaintRects": [ - [0, 0, 15, 185] - ] - }, - { - "position": [185, 185], - "bounds": [15, 15], - "drawsContent": true - } - ] - } - ] - } - ] - } - ] -} -
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/fast/canvas/canvas-shadow-source-in-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/fast/canvas/canvas-shadow-source-in-expected.png deleted file mode 100644 index b7a76dd..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac-retina/fast/canvas/canvas-shadow-source-in-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/fast/canvas/canvas-shadow-source-in-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-retina/fast/canvas/canvas-shadow-source-in-expected.txt deleted file mode 100644 index 74c840a..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac-retina/fast/canvas/canvas-shadow-source-in-expected.txt +++ /dev/null
@@ -1,21 +0,0 @@ -layer at (0,0) size 800x600 - LayoutView at (0,0) size 800x600 -layer at (0,0) size 800x464 - LayoutBlockFlow {HTML} at (0,0) size 800x464 - LayoutBlockFlow {BODY} at (8,8) size 784x448 - LayoutBlockFlow {DIV} at (0,0) size 784x18 - LayoutText {#text} at (0,0) size 60x18 - text run at (0,0) width 60: "Test Rect" - LayoutBlockFlow (anonymous) at (0,18) size 784x206 - LayoutText {#text} at (0,0) size 0x0 - LayoutBlockFlow {DIV} at (0,224) size 784x18 - LayoutText {#text} at (0,0) size 71x18 - text run at (0,0) width 71: "Test Image" - LayoutBlockFlow (anonymous) at (0,242) size 784x206 - LayoutText {#text} at (0,0) size 0x0 - LayoutText {#text} at (0,0) size 0x0 - LayoutText {#text} at (0,0) size 0x0 -layer at (8,26) size 202x202 - LayoutHTMLCanvas {CANVAS} at (0,0) size 202x202 [border: (1px solid #999999)] -layer at (8,250) size 202x202 - LayoutHTMLCanvas {CANVAS} at (0,0) size 202x202 [border: (1px solid #999999)]
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/virtual/display_list_2d_canvas/fast/canvas/canvas-shadow-source-in-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/virtual/display_list_2d_canvas/fast/canvas/canvas-shadow-source-in-expected.png new file mode 100644 index 0000000..6dcdb8e1 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac-retina/virtual/display_list_2d_canvas/fast/canvas/canvas-shadow-source-in-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/color-matching/image-color-matching-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/color-matching/image-color-matching-expected.txt deleted file mode 100644 index d28c7e3..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/color-matching/image-color-matching-expected.txt +++ /dev/null
@@ -1,22 +0,0 @@ -layer at (0,0) size 1600x1200 - LayoutView at (0,0) size 1600x1200 -layer at (0,0) size 1600x546 - LayoutBlockFlow {HTML} at (0,0) size 1600x546 - LayoutBlockFlow {BODY} at (8,16) size 1584x522 [color=#FFFFFF] [bgcolor=#000000] - LayoutBlockFlow {P} at (0,0) size 1584x18 - LayoutText {#text} at (0,0) size 210x18 - text run at (0,0) width 210: "Images should all look the same." - LayoutBlockFlow {DIV} at (0,34) size 1584x244 - LayoutImage {IMG} at (0,0) size 360x240 - LayoutText {#text} at (360,226) size 4x18 - text run at (360,226) width 4: " " - LayoutImage {IMG} at (364,0) size 360x240 - LayoutText {#text} at (0,0) size 0x0 - LayoutBlockFlow {DIV} at (0,278) size 1584x244 - LayoutText {#text} at (360,226) size 4x18 - text run at (360,226) width 4: " " - LayoutText {#text} at (0,0) size 0x0 -layer at (8,294) size 360x240 - LayoutImage {IMG} at (0,0) size 360x240 -layer at (372,294) size 360x240 - LayoutImage {IMG} at (364,0) size 360x240
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/repaint/should-not-clip-composited-overflow-scrolling-layer-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/repaint/should-not-clip-composited-overflow-scrolling-layer-expected.txt index 146d486..740e6fcf 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/repaint/should-not-clip-composited-overflow-scrolling-layer-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/compositing/repaint/should-not-clip-composited-overflow-scrolling-layer-expected.txt
@@ -1,8 +1,8 @@ { - "bounds": [1600, 1200], + "bounds": [800, 600], "children": [ { - "bounds": [1600, 1200], + "bounds": [800, 600], "contentsOpaque": true, "drawsContent": true, "children": [ @@ -15,7 +15,8 @@ [-2000, -2000, 5000, 5000] ], "paintInvalidationClients": [ - "LayoutBlockFlow DIV id='content'" + "LayoutBlockFlow DIV id='content'", + "RootInlineBox" ], "children": [ { @@ -29,7 +30,8 @@ [0, 0, 5000, 5000] ], "paintInvalidationClients": [ - "LayoutBlockFlow DIV id='content'" + "LayoutBlockFlow DIV id='content'", + "RootInlineBox" ] } ]
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/canvas/canvas-shadow-source-in-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/canvas/canvas-shadow-source-in-expected.png deleted file mode 100644 index b5daa85..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/canvas/canvas-shadow-source-in-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/canvas/canvas-shadow-source-in-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/canvas/canvas-shadow-source-in-expected.txt deleted file mode 100644 index f3fc678..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/canvas/canvas-shadow-source-in-expected.txt +++ /dev/null
@@ -1,21 +0,0 @@ -layer at (0,0) size 1600x1200 - LayoutView at (0,0) size 1600x1200 -layer at (0,0) size 1600x464 - LayoutBlockFlow {HTML} at (0,0) size 1600x464 - LayoutBlockFlow {BODY} at (8,8) size 1584x448 - LayoutBlockFlow {DIV} at (0,0) size 1584x18 - LayoutText {#text} at (0,0) size 60x18 - text run at (0,0) width 60: "Test Rect" - LayoutBlockFlow (anonymous) at (0,18) size 1584x206 - LayoutText {#text} at (0,0) size 0x0 - LayoutBlockFlow {DIV} at (0,224) size 1584x18 - LayoutText {#text} at (0,0) size 71x18 - text run at (0,0) width 71: "Test Image" - LayoutBlockFlow (anonymous) at (0,242) size 1584x206 - LayoutText {#text} at (0,0) size 0x0 - LayoutText {#text} at (0,0) size 0x0 - LayoutText {#text} at (0,0) size 0x0 -layer at (8,26) size 202x202 - LayoutHTMLCanvas {CANVAS} at (0,0) size 202x202 [border: (1px solid #999999)] -layer at (8,250) size 202x202 - LayoutHTMLCanvas {CANVAS} at (0,0) size 202x202 [border: (1px solid #999999)]
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/frames/iframe-scaling-with-scroll-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/frames/iframe-scaling-with-scroll-expected.png index cfa23469..25ff661 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/frames/iframe-scaling-with-scroll-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/frames/iframe-scaling-with-scroll-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/text/atsui-spacing-features-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/text/atsui-spacing-features-expected.png new file mode 100644 index 0000000..93482a4 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/text/atsui-spacing-features-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/text/international/thai-line-breaks-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/text/international/thai-line-breaks-expected.png index 4ebe969..7e90dc0b1 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/text/international/thai-line-breaks-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/text/international/thai-line-breaks-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/display_list_2d_canvas/fast/canvas/canvas-shadow-source-in-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/display_list_2d_canvas/fast/canvas/canvas-shadow-source-in-expected.png new file mode 100644 index 0000000..6dcdb8e1 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/virtual/display_list_2d_canvas/fast/canvas/canvas-shadow-source-in-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/compositing/repaint/should-not-clip-composited-overflow-scrolling-layer-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/compositing/repaint/should-not-clip-composited-overflow-scrolling-layer-expected.txt index e6b501c..8e980e48 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/compositing/repaint/should-not-clip-composited-overflow-scrolling-layer-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/compositing/repaint/should-not-clip-composited-overflow-scrolling-layer-expected.txt
@@ -15,7 +15,8 @@ [-2000, -2000, 5000, 5000] ], "paintInvalidationClients": [ - "LayoutBlockFlow DIV id='content'" + "LayoutBlockFlow DIV id='content'", + "RootInlineBox" ], "children": [ { @@ -29,7 +30,8 @@ [0, 0, 5000, 5000] ], "paintInvalidationClients": [ - "LayoutBlockFlow DIV id='content'" + "LayoutBlockFlow DIV id='content'", + "RootInlineBox" ] } ]
diff --git a/third_party/WebKit/LayoutTests/platform/mac/css3/flexbox/repaint-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/css3/flexbox/repaint-expected.txt index db38a1b..4c59eb9 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/css3/flexbox/repaint-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/css3/flexbox/repaint-expected.txt
@@ -8,7 +8,7 @@ "repaintRects": [ [400, 116, 392, 162], [400, 116, 392, 162], - [400, 116, 392, 162], + [400, 116, 391, 162], [148, 116, 644, 108], [148, 116, 644, 108], [148, 116, 644, 108],
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/canvas/canvas-shadow-source-in-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/canvas/canvas-shadow-source-in-expected.png index b7a76dd..6dcdb8e1 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/canvas/canvas-shadow-source-in-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/canvas/canvas-shadow-source-in-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/canvas/canvas-toBlob-webp-maximum-quality-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/canvas/canvas-toBlob-webp-maximum-quality-expected.png index 4b6bb7d..265102c 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/canvas/canvas-toBlob-webp-maximum-quality-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/canvas/canvas-toBlob-webp-maximum-quality-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/frames/iframe-scaling-with-scroll-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/frames/iframe-scaling-with-scroll-expected.png index f725ad1..d952db7 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/frames/iframe-scaling-with-scroll-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/frames/iframe-scaling-with-scroll-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/images/color-profile-munsell-adobe-to-srgb-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/images/color-profile-munsell-adobe-to-srgb-expected.png new file mode 100644 index 0000000..2829404 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/images/color-profile-munsell-adobe-to-srgb-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/images/color-profile-munsell-adobe-to-srgb-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/fast/images/color-profile-munsell-adobe-to-srgb-expected.txt new file mode 100644 index 0000000..44a84f4 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/images/color-profile-munsell-adobe-to-srgb-expected.txt
@@ -0,0 +1,42 @@ + +Color Actual Expected dE +-------------------------------------------- +Dark Skin 94,62,49 115,80,64 31 +Light Skin 180,131,111 195,151,130 31 +Blue Sky 76,102,138 94,123,156 33 +Foliage 71,90,49 88,108,65 29 +Blue Flower 111,107,161 130,129,177 33 +Bluish Green 84,179,154 100,190,171 26 +-------------------------------------------- +Orange 205,101,28 217,122,37 26 +Purplish Blue 56,69,148 72,91,165 32 +Moderate Red 178,62,79 194,84,98 33 +Purple 71,42,87 91,59,107 33 +Yellow Green 143,176,46 160,188,60 25 +Orange Yellow 222,147,32 230,163,42 20 +-------------------------------------------- +Blue 35,39,134 46,60,153 30 +Green 57,134,53 71,150,69 27 +Red 159,26,42 177,44,56 29 +Yellow 233,190,23 238,200,27 12 +Magenta 170,57,128 187,82,148 36 +Cyan (*) 0,116,148 0,135,166 26 +-------------------------------------------- +White 239,238,231 243,242,237 8 +Neutral 8 189,189,188 201,201,201 21 +Neutral 6.5 142,144,143 161,161,161 31 +Neutral 5 104,102,101 122,122,121 34 +Neutral 3.5 65,65,65 83,83,83 31 +Black 37,37,37 50,49,50 22 +-------------------------------------------- + +Result: total RMS color error: 28.26 + * Munsell Cyan is outside 255 sRGB gamut + + + + + + + +
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/bugzilla-6278-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/bugzilla-6278-expected.txt index c5b8139..0a7bb431 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/bugzilla-6278-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/bugzilla-6278-expected.txt
@@ -9,11 +9,11 @@ [304, 132, 2, 199], [254, 132, 52, 235], [252, 132, 50, 199], - [251, 132, 35, 144], + [250, 132, 36, 144], [10, 331, 242, 36], [10, 317, 242, 50], [10, 281, 292, 50], - [10, 276, 241, 36], + [10, 276, 240, 36], [10, 132, 292, 144], [10, 132, 242, 180] ],
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/inline-style-change-in-scrolled-view-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/inline-style-change-in-scrolled-view-expected.txt index dcb055c..2946adf7 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/inline-style-change-in-scrolled-view-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/inline-style-change-in-scrolled-view-expected.txt
@@ -6,7 +6,7 @@ "contentsOpaque": true, "drawsContent": true, "repaintRects": [ - [0, 288, 416, 18] + [0, 288, 415, 18] ], "paintInvalidationClients": [ "LayoutText #text",
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/layout-state-scrolloffset-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/layout-state-scrolloffset-expected.txt index 18747a40..33ab68c 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/layout-state-scrolloffset-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/layout-state-scrolloffset-expected.txt
@@ -8,7 +8,7 @@ "repaintRects": [ [100, 118, 50, 18], [100, 118, 41, 18], - [100, 118, 31, 18] + [100, 118, 30, 18] ], "paintInvalidationClients": [ "InlineTextBox ''",
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/layout-state-scrolloffset2-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/layout-state-scrolloffset2-expected.txt index 0358c51..3a13b6ba 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/layout-state-scrolloffset2-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/layout-state-scrolloffset2-expected.txt
@@ -8,7 +8,7 @@ "repaintRects": [ [102, 120, 50, 18], [102, 120, 41, 18], - [102, 120, 31, 18] + [102, 120, 30, 18] ], "paintInvalidationClients": [ "InlineTextBox ''",
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/layout-state-scrolloffset3-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/layout-state-scrolloffset3-expected.txt index 3d873f5..05d3266 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/layout-state-scrolloffset3-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/layout-state-scrolloffset3-expected.txt
@@ -8,7 +8,7 @@ "repaintRects": [ [100, 118, 35, 18], [100, 118, 35, 18], - [100, 118, 31, 18] + [100, 118, 30, 18] ], "paintInvalidationClients": [ "InlineTextBox ''",
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/line-flow-with-floats-1-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/line-flow-with-floats-1-expected.txt index 074aa08..f66a4cb 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/line-flow-with-floats-1-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/line-flow-with-floats-1-expected.txt
@@ -7,8 +7,8 @@ "drawsContent": true, "repaintRects": [ [378, 138, 70, 30], - [369, 80, 51, 108], - [305, 170, 41, 18], + [368, 80, 52, 108], + [305, 170, 40, 18], [301, 404, 67, 18], [178, 350, 145, 18], [65, 386, 304, 36], @@ -19,8 +19,8 @@ [14, 335, 48, 65], [14, 242, 406, 126], [14, 224, 406, 126], - [14, 188, 407, 72], - [14, 188, 41, 18], + [14, 188, 406, 72], + [14, 188, 40, 18], [14, 170, 407, 72], [8, 116, 418, 450] ],
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/line-flow-with-floats-10-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/line-flow-with-floats-10-expected.txt new file mode 100644 index 0000000..ff7bea1 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/line-flow-with-floats-10-expected.txt
@@ -0,0 +1,67 @@ +{ + "bounds": [800, 600], + "children": [ + { + "bounds": [800, 600], + "contentsOpaque": true, + "drawsContent": true, + "repaintRects": [ + [368, 422, 1, 54], + [65, 404, 304, 36], + [14, 404, 355, 36], + [14, 364, 48, 64], + [14, 353, 48, 65], + [8, 332, 418, 234] + ], + "paintInvalidationClients": [ + "InlineTextBox 'other parts of\n'", + "InlineTextBox 'the ground, Alice soon came to the conclusion'", + "RootInlineBox", + "InlineTextBox 'that it was a very\n'", + "InlineTextBox 'difficult game indeed.\n'", + "RootInlineBox", + "InlineTextBox 'The players all played at once without waiting'", + "RootInlineBox", + "InlineTextBox 'for turns,\n'", + "InlineTextBox 'quarrelling all the while, and fighting'", + "RootInlineBox", + "InlineTextBox 'for the hedgehogs; and in\n'", + "InlineTextBox 'a very short time '", + "InlineTextBox 'the'", + "RootInlineBox", + "InlineTextBox 'Queen'", + "InlineTextBox ' was in a furious passion, and went\n'", + "InlineTextBox 'stamping'", + "RootInlineBox", + "InlineTextBox 'about, and shouting \u2018Off with his head!\u2019 or \u2018Off with'", + "RootInlineBox", + "InlineTextBox 'her head!\u2019 about once in a minute.\n'", + "RootInlineBox", + "InlineTextBox 'Alice began to feel very uneasy: to be sure, she had not as\n'", + "InlineTextBox 'yet'", + "RootInlineBox", + "InlineTextBox 'had any dispute with the Queen, but she knew that it might'", + "RootInlineBox", + "InlineTextBox 'happen any minute, \u2018and then,\u2019 thought she, \u2018what would'", + "RootInlineBox", + "InlineTextBox 'become of\n'", + "InlineTextBox 'me? They\u2019re dreadfully fond of beheading people'", + "RootInlineBox", + "InlineTextBox 'here; the great\n'", + "InlineTextBox 'wonder is, that there\u2018s any one left alive!\u2019'", + "RootInlineBox", + "LayoutBlockFlow P", + "LayoutBlockFlow (floating) SPAN id='blueFloat'", + "LayoutText #text", + "InlineTextBox 'the'", + "InlineTextBox 'Queen'", + "LayoutText #text", + "InlineTextBox ' was in a furious passion, and went'", + "InlineTextBox 'stamping about, and shouting \u2018Off with his head!\u2019 or'", + "InlineTextBox '\u2018Off with\n'", + "InlineTextBox 'her head!\u2019 about once in a minute.\n'" + ] + } + ] +} +
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/line-flow-with-floats-2-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/line-flow-with-floats-2-expected.txt index 45069d3b..1bf1d22 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/line-flow-with-floats-2-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/line-flow-with-floats-2-expected.txt
@@ -14,8 +14,8 @@ [65, 386, 304, 36], [65, 372, 304, 18], [65, 368, 304, 18], - [14, 480, 407, 90], - [14, 476, 407, 90], + [14, 480, 406, 90], + [14, 476, 406, 90], [14, 426, 355, 54], [14, 422, 355, 54], [14, 408, 355, 36], @@ -24,10 +24,10 @@ [14, 353, 48, 65], [14, 246, 406, 126], [14, 242, 406, 126], - [14, 191, 407, 73], - [14, 188, 407, 72], + [14, 191, 406, 73], + [14, 188, 406, 72], [14, 188, 45, 22], - [14, 188, 41, 18], + [14, 188, 40, 18], [8, 572, 418, 4], [8, 569, 418, 7], [8, 170, 418, 400]
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/line-flow-with-floats-3-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/line-flow-with-floats-3-expected.txt index 1e506ad..e628fa6 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/line-flow-with-floats-3-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/line-flow-with-floats-3-expected.txt
@@ -9,9 +9,9 @@ [372, 371, 48, 81], [369, 368, 32, 18], [356, 389, 64, 81], - [354, 422, 15, 54], + [353, 422, 16, 54], [65, 386, 304, 36], - [65, 368, 356, 54], + [65, 368, 355, 54], [14, 422, 72, 18], [14, 404, 355, 36], [8, 368, 418, 198]
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/line-flow-with-floats-4-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/line-flow-with-floats-4-expected.txt index 4715f1f..1d4050ab 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/line-flow-with-floats-4-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/line-flow-with-floats-4-expected.txt
@@ -7,7 +7,7 @@ "drawsContent": true, "repaintRects": [ [372, 435, 48, 17], - [369, 422, 52, 54], + [369, 422, 51, 54], [8, 368, 418, 198] ], "paintInvalidationClients": [
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/line-flow-with-floats-5-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/line-flow-with-floats-5-expected.txt index 66fa42e..b75e9aa 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/line-flow-with-floats-5-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/line-flow-with-floats-5-expected.txt
@@ -10,7 +10,7 @@ [162, 350, 145, 18], [65, 386, 304, 36], [65, 368, 304, 18], - [49, 368, 321, 54], + [49, 368, 320, 54], [49, 368, 301, 18], [46, 353, 16, 65], [8, 332, 418, 234]
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/line-flow-with-floats-9-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/line-flow-with-floats-9-expected.txt index 00edc76..52ee896 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/line-flow-with-floats-9-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/line-flow-with-floats-9-expected.txt
@@ -17,8 +17,8 @@ [65, 386, 304, 18], [65, 368, 304, 18], [65, 368, 145, 18], - [14, 494, 407, 90], - [14, 476, 407, 90], + [14, 494, 406, 90], + [14, 476, 406, 90], [14, 440, 355, 54], [14, 422, 355, 54], [14, 404, 355, 36],
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/make-children-non-inline-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/make-children-non-inline-expected.txt index ab6369d..d38a65d0 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/make-children-non-inline-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/make-children-non-inline-expected.txt
@@ -7,14 +7,14 @@ "drawsContent": true, "repaintRects": [ [8, 304, 64, 18], - [8, 286, 31, 18], + [8, 286, 30, 18], [8, 268, 69, 18], [8, 250, 784, 72], - [8, 250, 114, 18], + [8, 250, 113, 18], [8, 204, 64, 18], - [8, 186, 31, 18], + [8, 186, 30, 18], [8, 168, 69, 18], - [8, 150, 114, 18], + [8, 150, 113, 18], [8, 150, 10, 100], [8, 132, 80, 18], [8, 114, 45, 18],
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/table-collapsed-border-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/table-collapsed-border-expected.txt index d0c5e72..faf45e9 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/table-collapsed-border-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/repaint/table-collapsed-border-expected.txt
@@ -8,9 +8,9 @@ "repaintRects": [ [83, 268, 26, 76], [79, 268, 30, 76], - [23, 297, 78, 18], - [23, 211, 35, 18], - [23, 125, 78, 18], + [23, 297, 77, 18], + [23, 211, 34, 18], + [23, 125, 77, 18], [22, 316, 87, 28], [22, 316, 61, 28], [22, 296, 87, 20],
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/text/atsui-spacing-features-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/text/atsui-spacing-features-expected.png index 781da945..1ba74c4 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/text/atsui-spacing-features-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/text/atsui-spacing-features-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/text/atsui-spacing-features-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/fast/text/atsui-spacing-features-expected.txt index 2f9d66e..6968d45 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/text/atsui-spacing-features-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/text/atsui-spacing-features-expected.txt
@@ -4,17 +4,17 @@ LayoutBlockFlow {HTML} at (0,0) size 800x372 LayoutBlockFlow {BODY} at (8,16) size 784x348 LayoutBlockFlow {P} at (0,0) size 784x36 - LayoutText {#text} at (0,0) size 180x18 - text run at (0,0) width 180: "Test for regressions against " - LayoutInline {I} at (0,0) size 776x36 + LayoutText {#text} at (0,0) size 179x18 + text run at (0,0) width 179: "Test for regressions against " + LayoutInline {I} at (0,0) size 772x36 LayoutInline {A} at (0,0) size 354x18 [color=#0000EE] - LayoutText {#text} at (179,0) size 354x18 - text run at (179,0) width 354: "http://bugzilla.opendarwin.org/show_bug.cgi?id=3922" - LayoutText {#text} at (532,0) size 776x36 - text run at (532,0) width 244: " Variable word/letter spacing and full" - text run at (0,18) width 330: "justification not supported for ATSUI-rendered text" - LayoutText {#text} at (329,18) size 5x18 - text run at (329,18) width 5: "." + LayoutText {#text} at (178,0) size 354x18 + text run at (178,0) width 354: "http://bugzilla.opendarwin.org/show_bug.cgi?id=3922" + LayoutText {#text} at (531,0) size 772x36 + text run at (531,0) width 241: " Variable word/letter spacing and full" + text run at (0,18) width 327: "justification not supported for ATSUI-rendered text" + LayoutText {#text} at (326,18) size 5x18 + text run at (326,18) width 5: "." LayoutBlockFlow (anonymous) at (0,52) size 784x18 LayoutText {#text} at (0,0) size 517x18 text run at (0,0) width 517: "Each green box should be identical to the blue box it follows, except for accents." @@ -29,8 +29,8 @@ LayoutText {#text} at (56,1) size 92x18 text run at (56,1) width 92: "Letter spacing" LayoutTableCell {TD} at (414,2) size 204x20 [r=0 c=2 rs=1 cs=1] - LayoutText {#text} at (62,1) size 80x18 - text run at (62,1) width 80: "Justification" + LayoutText {#text} at (63,1) size 78x18 + text run at (63,1) width 78: "Justification" LayoutTableRow {TR} at (0,24) size 620x234 LayoutTableCell {TD} at (2,24) size 204x180 [r=1 c=0 rs=1 cs=1] LayoutBlockFlow {DIV} at (1,1) size 202x178
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/text/drawBidiText-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/fast/text/drawBidiText-expected.txt index c4a5e2e0..26311ba 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/text/drawBidiText-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/text/drawBidiText-expected.txt
@@ -32,8 +32,8 @@ LayoutText {#text} at (2,0) size 112x21 text run at (2,0) width 112 RTL: "\x{5DE}\x{5E9}\x{5D4}\x{5D5} \x{5E2}\x{5DD} \x{5E0}\x{5B4}\x{5E7}\x{5BC}\x{5D5}\x{5BC}\x{5D3}" LayoutBlockFlow {OPTION} at (1,113.97) size 321.19x25 - LayoutText {#text} at (2,0) size 74x21 - text run at (2,0) width 74 RTL: "\x{627}\x{644}\x{644}\x{63A}\x{629} \x{627}\x{644}\x{639}\x{631}\x{628}\x{64A}\x{629}" + LayoutText {#text} at (2,0) size 77x21 + text run at (2,0) width 77 RTL: "\x{627}\x{644}\x{644}\x{63A}\x{629} \x{627}\x{644}\x{639}\x{631}\x{628}\x{64A}\x{629}" LayoutBlockFlow {OPTION} at (1,138.97) size 321.19x22.59 LayoutText {#text} at (2,0) size 125x21 text run at (2,0) width 125: "Et volia\x{300}: ATSUI!"
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/text/international/thai-line-breaks-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/text/international/thai-line-breaks-expected.png index 31e7281..50a68bf 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/text/international/thai-line-breaks-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/text/international/thai-line-breaks-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/batik/filters/feTile-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/batik/filters/feTile-expected.png index 8bb440a..0d0af1d 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/svg/batik/filters/feTile-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/svg/batik/filters/feTile-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/display_list_2d_canvas/fast/canvas/canvas-shadow-source-in-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/display_list_2d_canvas/fast/canvas/canvas-shadow-source-in-expected.png index b7a76dd..6dcdb8e1 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/virtual/display_list_2d_canvas/fast/canvas/canvas-shadow-source-in-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/display_list_2d_canvas/fast/canvas/canvas-shadow-source-in-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/compositing/color-matching/image-color-matching-expected.txt b/third_party/WebKit/LayoutTests/platform/win-xp/compositing/color-matching/image-color-matching-expected.txt index d19f814..7c1dd64 100644 --- a/third_party/WebKit/LayoutTests/platform/win-xp/compositing/color-matching/image-color-matching-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win-xp/compositing/color-matching/image-color-matching-expected.txt
@@ -1,18 +1,18 @@ -layer at (0,0) size 1600x1200 - LayoutView at (0,0) size 1600x1200 -layer at (0,0) size 1600x550 - LayoutBlockFlow {HTML} at (0,0) size 1600x550 - LayoutBlockFlow {BODY} at (8,16) size 1584x526 [color=#FFFFFF] [bgcolor=#000000] - LayoutBlockFlow {P} at (0,0) size 1584x20 +layer at (0,0) size 800x600 + LayoutView at (0,0) size 800x600 +layer at (0,0) size 800x550 + LayoutBlockFlow {HTML} at (0,0) size 800x550 + LayoutBlockFlow {BODY} at (8,16) size 784x526 [color=#FFFFFF] [bgcolor=#000000] + LayoutBlockFlow {P} at (0,0) size 784x20 LayoutText {#text} at (0,0) size 195x19 text run at (0,0) width 195: "Images should all look the same." - LayoutBlockFlow {DIV} at (0,36) size 1584x245 + LayoutBlockFlow {DIV} at (0,36) size 784x245 LayoutImage {IMG} at (0,0) size 360x240 LayoutText {#text} at (360,225) size 4x19 text run at (360,225) width 4: " " LayoutImage {IMG} at (364,0) size 360x240 LayoutText {#text} at (0,0) size 0x0 - LayoutBlockFlow {DIV} at (0,281) size 1584x245 + LayoutBlockFlow {DIV} at (0,281) size 784x245 LayoutText {#text} at (360,225) size 4x19 text run at (360,225) width 4: " " LayoutText {#text} at (0,0) size 0x0
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/compositing/repaint/should-not-clip-composited-overflow-scrolling-layer-expected.txt b/third_party/WebKit/LayoutTests/platform/win-xp/compositing/repaint/should-not-clip-composited-overflow-scrolling-layer-expected.txt index e6b501c..8e980e48 100644 --- a/third_party/WebKit/LayoutTests/platform/win-xp/compositing/repaint/should-not-clip-composited-overflow-scrolling-layer-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win-xp/compositing/repaint/should-not-clip-composited-overflow-scrolling-layer-expected.txt
@@ -15,7 +15,8 @@ [-2000, -2000, 5000, 5000] ], "paintInvalidationClients": [ - "LayoutBlockFlow DIV id='content'" + "LayoutBlockFlow DIV id='content'", + "RootInlineBox" ], "children": [ { @@ -29,7 +30,8 @@ [0, 0, 5000, 5000] ], "paintInvalidationClients": [ - "LayoutBlockFlow DIV id='content'" + "LayoutBlockFlow DIV id='content'", + "RootInlineBox" ] } ]
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/css1/box_properties/float_on_text_elements-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/css1/box_properties/float_on_text_elements-expected.png index 132505e..48691b8 100644 --- a/third_party/WebKit/LayoutTests/platform/win-xp/css1/box_properties/float_on_text_elements-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win-xp/css1/box_properties/float_on_text_elements-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/css2.1/t0905-c5525-fltwidth-00-c-g-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/css2.1/t0905-c5525-fltwidth-00-c-g-expected.png index 3e51f1ed..18dc458 100644 --- a/third_party/WebKit/LayoutTests/platform/win-xp/css2.1/t0905-c5525-fltwidth-00-c-g-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win-xp/css2.1/t0905-c5525-fltwidth-00-c-g-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/canvas/canvas-shadow-source-in-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/fast/canvas/canvas-shadow-source-in-expected.png index 49d21a21..cbaefe7 100644 --- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/canvas/canvas-shadow-source-in-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/canvas/canvas-shadow-source-in-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/images/color-profile-munsell-adobe-to-srgb-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/fast/images/color-profile-munsell-adobe-to-srgb-expected.png new file mode 100644 index 0000000..7799897 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/images/color-profile-munsell-adobe-to-srgb-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/text/decorations-with-text-combine-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/fast/text/decorations-with-text-combine-expected.png index ed5e012..d013b92 100644 --- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/text/decorations-with-text-combine-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/text/decorations-with-text-combine-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/text/decorations-with-text-combine-expected.txt b/third_party/WebKit/LayoutTests/platform/win-xp/fast/text/decorations-with-text-combine-expected.txt index e8ec882..e6358b71 100644 --- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/text/decorations-with-text-combine-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/text/decorations-with-text-combine-expected.txt
@@ -1,153 +1,153 @@ layer at (0,0) size 800x600 - RenderView at (0,0) size 800x600 + LayoutView at (0,0) size 800x600 layer at (0,0) size 800x600 - RenderBlock {HTML} at (0,0) size 800x600 - RenderBody {BODY} at (8,8) size 782x584 - RenderBlock {DIV} at (0,0) size 66x584 - RenderBlock {DIV} at (0,0) size 28x584 - RenderText {#text} at (0,0) size 27x69 + LayoutBlockFlow {HTML} at (0,0) size 800x600 + LayoutBlockFlow {BODY} at (8,8) size 782x584 + LayoutBlockFlow {DIV} at (0,0) size 66x584 + LayoutBlockFlow {DIV} at (0,0) size 28x584 + LayoutText {#text} at (0,0) size 27x69 text run at (0,0) width 69: "\x{305D}\x{306E}\x{5973}" - RenderInline {SPAN} at (0,0) size 27x25 [color=#0000FF] - RenderCombineText {#text} at (0,68) size 27x25 + LayoutInline {SPAN} at (0,0) size 27x25 [color=#0000FF] + LayoutTextCombine {#text} at (0,68) size 27x25 text run at (0,68) width 24: "1" - RenderText {#text} at (0,92) size 27x47 + LayoutText {#text} at (0,92) size 27x47 text run at (0,92) width 46: "\x{304C}\x{306D}" - RenderInline {SPAN} at (0,0) size 27x25 [color=#0000FF] - RenderCombineText {#text} at (0,138) size 27x25 + LayoutInline {SPAN} at (0,0) size 27x25 [color=#0000FF] + LayoutTextCombine {#text} at (0,138) size 27x25 text run at (0,138) width 24: "123" - RenderText {#text} at (0,162) size 27x107 + LayoutText {#text} at (0,162) size 27x107 text run at (0,162) width 107: "\x{304B}\x{3057}\x{3064}\x{3051}\x{306B}" - RenderInline {SPAN} at (0,0) size 27x25 [color=#0000FF] - RenderCombineText {#text} at (0,268) size 27x25 + LayoutInline {SPAN} at (0,0) size 27x25 [color=#0000FF] + LayoutTextCombine {#text} at (0,268) size 27x25 text run at (0,268) width 24: "12345" - RenderText {#text} at (0,292) size 27x162 + LayoutText {#text} at (0,292) size 27x162 text run at (0,292) width 162: "\x{6765}\x{3066}\x{304F}\x{308C}\x{308B}\x{307E}\x{3067}" - RenderBlock {DIV} at (38,0) size 28x584 - RenderText {#text} at (0,0) size 27x69 + LayoutBlockFlow {DIV} at (38,0) size 28x584 + LayoutText {#text} at (0,0) size 27x69 text run at (0,0) width 69: "\x{305D}\x{306E}\x{5973}" - RenderInline {SPAN} at (0,0) size 27x25 [color=#0000FF] - RenderCombineText {#text} at (0,68) size 27x25 + LayoutInline {SPAN} at (0,0) size 27x25 [color=#0000FF] + LayoutTextCombine {#text} at (0,68) size 27x25 text run at (0,68) width 24: "1" - RenderText {#text} at (0,92) size 27x47 + LayoutText {#text} at (0,92) size 27x47 text run at (0,92) width 46: "\x{304C}\x{306D}" - RenderInline {SPAN} at (0,0) size 27x25 [color=#0000FF] - RenderCombineText {#text} at (0,138) size 27x25 + LayoutInline {SPAN} at (0,0) size 27x25 [color=#0000FF] + LayoutTextCombine {#text} at (0,138) size 27x25 text run at (0,138) width 24: "123" - RenderText {#text} at (0,162) size 27x107 + LayoutText {#text} at (0,162) size 27x107 text run at (0,162) width 107: "\x{304B}\x{3057}\x{3064}\x{3051}\x{306B}" - RenderInline {SPAN} at (0,0) size 27x25 [color=#0000FF] - RenderCombineText {#text} at (0,268) size 27x25 + LayoutInline {SPAN} at (0,0) size 27x25 [color=#0000FF] + LayoutTextCombine {#text} at (0,268) size 27x25 text run at (0,268) width 24: "12345" - RenderText {#text} at (0,292) size 27x162 + LayoutText {#text} at (0,292) size 27x162 text run at (0,292) width 162: "\x{6765}\x{3066}\x{304F}\x{308C}\x{308B}\x{307E}\x{3067}" - RenderBlock {DIV} at (76,0) size 66x584 - RenderBlock {DIV} at (0,0) size 28x584 - RenderText {#text} at (0,0) size 27x69 + LayoutBlockFlow {DIV} at (76,0) size 66x584 + LayoutBlockFlow {DIV} at (0,0) size 28x584 + LayoutText {#text} at (0,0) size 27x69 text run at (0,0) width 69: "\x{305D}\x{306E}\x{5973}" - RenderInline {SPAN} at (0,0) size 27x25 [color=#0000FF] - RenderCombineText {#text} at (0,68) size 27x25 + LayoutInline {SPAN} at (0,0) size 27x25 [color=#0000FF] + LayoutTextCombine {#text} at (0,68) size 27x25 text run at (0,68) width 24: "1" - RenderText {#text} at (0,92) size 27x47 + LayoutText {#text} at (0,92) size 27x47 text run at (0,92) width 46: "\x{304C}\x{306D}" - RenderInline {SPAN} at (0,0) size 27x25 [color=#0000FF] - RenderCombineText {#text} at (0,138) size 27x25 + LayoutInline {SPAN} at (0,0) size 27x25 [color=#0000FF] + LayoutTextCombine {#text} at (0,138) size 27x25 text run at (0,138) width 24: "123" - RenderText {#text} at (0,162) size 27x107 + LayoutText {#text} at (0,162) size 27x107 text run at (0,162) width 107: "\x{304B}\x{3057}\x{3064}\x{3051}\x{306B}" - RenderInline {SPAN} at (0,0) size 27x25 [color=#0000FF] - RenderCombineText {#text} at (0,268) size 27x25 + LayoutInline {SPAN} at (0,0) size 27x25 [color=#0000FF] + LayoutTextCombine {#text} at (0,268) size 27x25 text run at (0,268) width 24: "12345" - RenderText {#text} at (0,292) size 27x162 + LayoutText {#text} at (0,292) size 27x162 text run at (0,292) width 162: "\x{6765}\x{3066}\x{304F}\x{308C}\x{308B}\x{307E}\x{3067}" - RenderBlock {DIV} at (38,0) size 28x584 - RenderText {#text} at (0,0) size 27x69 + LayoutBlockFlow {DIV} at (38,0) size 28x584 + LayoutText {#text} at (0,0) size 27x69 text run at (0,0) width 69: "\x{305D}\x{306E}\x{5973}" - RenderInline {SPAN} at (0,0) size 27x25 [color=#0000FF] - RenderCombineText {#text} at (0,68) size 27x25 + LayoutInline {SPAN} at (0,0) size 27x25 [color=#0000FF] + LayoutTextCombine {#text} at (0,68) size 27x25 text run at (0,68) width 24: "1" - RenderText {#text} at (0,92) size 27x47 + LayoutText {#text} at (0,92) size 27x47 text run at (0,92) width 46: "\x{304C}\x{306D}" - RenderInline {SPAN} at (0,0) size 27x25 [color=#0000FF] - RenderCombineText {#text} at (0,138) size 27x25 + LayoutInline {SPAN} at (0,0) size 27x25 [color=#0000FF] + LayoutTextCombine {#text} at (0,138) size 27x25 text run at (0,138) width 24: "123" - RenderText {#text} at (0,162) size 27x107 + LayoutText {#text} at (0,162) size 27x107 text run at (0,162) width 107: "\x{304B}\x{3057}\x{3064}\x{3051}\x{306B}" - RenderInline {SPAN} at (0,0) size 27x25 [color=#0000FF] - RenderCombineText {#text} at (0,268) size 27x25 + LayoutInline {SPAN} at (0,0) size 27x25 [color=#0000FF] + LayoutTextCombine {#text} at (0,268) size 27x25 text run at (0,268) width 24: "12345" - RenderText {#text} at (0,292) size 27x162 + LayoutText {#text} at (0,292) size 27x162 text run at (0,292) width 162: "\x{6765}\x{3066}\x{304F}\x{308C}\x{308B}\x{307E}\x{3067}" - RenderBlock {DIV} at (152,0) size 66x584 - RenderBlock {DIV} at (0,0) size 28x584 - RenderText {#text} at (0,0) size 27x69 + LayoutBlockFlow {DIV} at (152,0) size 66x584 + LayoutBlockFlow {DIV} at (0,0) size 28x584 + LayoutText {#text} at (0,0) size 27x69 text run at (0,0) width 69: "\x{305D}\x{306E}\x{5973}" - RenderInline {SPAN} at (0,0) size 27x25 [color=#0000FF] - RenderCombineText {#text} at (0,68) size 27x25 + LayoutInline {SPAN} at (0,0) size 27x25 [color=#0000FF] + LayoutTextCombine {#text} at (0,68) size 27x25 text run at (0,68) width 24: "1" - RenderText {#text} at (0,92) size 27x47 + LayoutText {#text} at (0,92) size 27x47 text run at (0,92) width 46: "\x{304C}\x{306D}" - RenderInline {SPAN} at (0,0) size 27x25 [color=#0000FF] - RenderCombineText {#text} at (0,138) size 27x25 + LayoutInline {SPAN} at (0,0) size 27x25 [color=#0000FF] + LayoutTextCombine {#text} at (0,138) size 27x25 text run at (0,138) width 24: "123" - RenderText {#text} at (0,162) size 27x107 + LayoutText {#text} at (0,162) size 27x107 text run at (0,162) width 107: "\x{304B}\x{3057}\x{3064}\x{3051}\x{306B}" - RenderInline {SPAN} at (0,0) size 27x25 [color=#0000FF] - RenderCombineText {#text} at (0,268) size 27x25 + LayoutInline {SPAN} at (0,0) size 27x25 [color=#0000FF] + LayoutTextCombine {#text} at (0,268) size 27x25 text run at (0,268) width 24: "12345" - RenderText {#text} at (0,292) size 27x162 + LayoutText {#text} at (0,292) size 27x162 text run at (0,292) width 162: "\x{6765}\x{3066}\x{304F}\x{308C}\x{308B}\x{307E}\x{3067}" - RenderBlock {DIV} at (38,0) size 28x584 - RenderText {#text} at (0,0) size 27x69 + LayoutBlockFlow {DIV} at (38,0) size 28x584 + LayoutText {#text} at (0,0) size 27x69 text run at (0,0) width 69: "\x{305D}\x{306E}\x{5973}" - RenderInline {SPAN} at (0,0) size 27x25 [color=#0000FF] - RenderCombineText {#text} at (0,68) size 27x25 + LayoutInline {SPAN} at (0,0) size 27x25 [color=#0000FF] + LayoutTextCombine {#text} at (0,68) size 27x25 text run at (0,68) width 24: "1" - RenderText {#text} at (0,92) size 27x47 + LayoutText {#text} at (0,92) size 27x47 text run at (0,92) width 46: "\x{304C}\x{306D}" - RenderInline {SPAN} at (0,0) size 27x25 [color=#0000FF] - RenderCombineText {#text} at (0,138) size 27x25 + LayoutInline {SPAN} at (0,0) size 27x25 [color=#0000FF] + LayoutTextCombine {#text} at (0,138) size 27x25 text run at (0,138) width 24: "123" - RenderText {#text} at (0,162) size 27x107 + LayoutText {#text} at (0,162) size 27x107 text run at (0,162) width 107: "\x{304B}\x{3057}\x{3064}\x{3051}\x{306B}" - RenderInline {SPAN} at (0,0) size 27x25 [color=#0000FF] - RenderCombineText {#text} at (0,268) size 27x25 + LayoutInline {SPAN} at (0,0) size 27x25 [color=#0000FF] + LayoutTextCombine {#text} at (0,268) size 27x25 text run at (0,268) width 24: "12345" - RenderText {#text} at (0,292) size 27x162 + LayoutText {#text} at (0,292) size 27x162 text run at (0,292) width 162: "\x{6765}\x{3066}\x{304F}\x{308C}\x{308B}\x{307E}\x{3067}" - RenderBlock {DIV} at (228,0) size 120x584 - RenderBlock {DIV} at (0,0) size 55x584 - RenderText {#text} at (27,0) size 27x69 - text run at (27,0) width 69: "\x{305D}\x{306E}\x{5973}" - RenderInline {SPAN} at (0,0) size 27x25 [color=#0000FF] - RenderCombineText {#text} at (27,68) size 27x25 - text run at (27,68) width 24: "1" - RenderText {#text} at (27,92) size 27x47 - text run at (27,92) width 46: "\x{304C}\x{306D}" - RenderInline {SPAN} at (0,0) size 27x25 [color=#0000FF] - RenderCombineText {#text} at (27,138) size 27x25 - text run at (27,138) width 24: "123" - RenderText {#text} at (27,162) size 27x107 - text run at (27,162) width 107: "\x{304B}\x{3057}\x{3064}\x{3051}\x{306B}" - RenderInline {SPAN} at (0,0) size 27x25 [color=#0000FF] - RenderCombineText {#text} at (27,268) size 27x25 - text run at (27,268) width 24: "12345" - RenderText {#text} at (27,292) size 27x162 - text run at (27,292) width 162: "\x{6765}\x{3066}\x{304F}\x{308C}\x{308B}\x{307E}\x{3067}" - RenderBlock {DIV} at (65,0) size 55x584 - RenderText {#text} at (27,0) size 27x69 - text run at (27,0) width 69: "\x{305D}\x{306E}\x{5973}" - RenderInline {SPAN} at (0,0) size 27x25 [color=#0000FF] - RenderCombineText {#text} at (27,68) size 27x25 - text run at (27,68) width 24: "1" - RenderText {#text} at (27,92) size 27x47 - text run at (27,92) width 46: "\x{304C}\x{306D}" - RenderInline {SPAN} at (0,0) size 27x25 [color=#0000FF] - RenderCombineText {#text} at (27,138) size 27x25 - text run at (27,138) width 24: "123" - RenderText {#text} at (27,162) size 27x107 - text run at (27,162) width 107: "\x{304B}\x{3057}\x{3064}\x{3051}\x{306B}" - RenderInline {SPAN} at (0,0) size 27x25 [color=#0000FF] - RenderCombineText {#text} at (27,268) size 27x25 - text run at (27,268) width 24: "12345" - RenderText {#text} at (27,292) size 27x162 - text run at (27,292) width 162: "\x{6765}\x{3066}\x{304F}\x{308C}\x{308B}\x{307E}\x{3067}" + LayoutBlockFlow {DIV} at (228,0) size 96x584 + LayoutBlockFlow {DIV} at (0,0) size 43x584 + LayoutText {#text} at (15,0) size 27x69 + text run at (15,0) width 69: "\x{305D}\x{306E}\x{5973}" + LayoutInline {SPAN} at (0,0) size 27x25 [color=#0000FF] + LayoutTextCombine {#text} at (15,68) size 27x25 + text run at (15,68) width 24: "1" + LayoutText {#text} at (15,92) size 27x47 + text run at (15,92) width 46: "\x{304C}\x{306D}" + LayoutInline {SPAN} at (0,0) size 27x25 [color=#0000FF] + LayoutTextCombine {#text} at (15,138) size 27x25 + text run at (15,138) width 24: "123" + LayoutText {#text} at (15,162) size 27x107 + text run at (15,162) width 107: "\x{304B}\x{3057}\x{3064}\x{3051}\x{306B}" + LayoutInline {SPAN} at (0,0) size 27x25 [color=#0000FF] + LayoutTextCombine {#text} at (15,268) size 27x25 + text run at (15,268) width 24: "12345" + LayoutText {#text} at (15,292) size 27x162 + text run at (15,292) width 162: "\x{6765}\x{3066}\x{304F}\x{308C}\x{308B}\x{307E}\x{3067}" + LayoutBlockFlow {DIV} at (53,0) size 43x584 + LayoutText {#text} at (15,0) size 27x69 + text run at (15,0) width 69: "\x{305D}\x{306E}\x{5973}" + LayoutInline {SPAN} at (0,0) size 27x25 [color=#0000FF] + LayoutTextCombine {#text} at (15,68) size 27x25 + text run at (15,68) width 24: "1" + LayoutText {#text} at (15,92) size 27x47 + text run at (15,92) width 46: "\x{304C}\x{306D}" + LayoutInline {SPAN} at (0,0) size 27x25 [color=#0000FF] + LayoutTextCombine {#text} at (15,138) size 27x25 + text run at (15,138) width 24: "123" + LayoutText {#text} at (15,162) size 27x107 + text run at (15,162) width 107: "\x{304B}\x{3057}\x{3064}\x{3051}\x{306B}" + LayoutInline {SPAN} at (0,0) size 27x25 [color=#0000FF] + LayoutTextCombine {#text} at (15,268) size 27x25 + text run at (15,268) width 24: "12345" + LayoutText {#text} at (15,292) size 27x162 + text run at (15,292) width 162: "\x{6765}\x{3066}\x{304F}\x{308C}\x{308B}\x{307E}\x{3067}"
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/text/drawBidiText-expected.txt b/third_party/WebKit/LayoutTests/platform/win-xp/fast/text/drawBidiText-expected.txt index 7fb684b..877babc 100644 --- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/text/drawBidiText-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/text/drawBidiText-expected.txt
@@ -32,8 +32,8 @@ LayoutText {#text} at (2,0) size 100x21 text run at (2,0) width 100 RTL: "\x{5DE}\x{5E9}\x{5D4}\x{5D5} \x{5E2}\x{5DD} \x{5E0}\x{5B4}\x{5E7}\x{5BC}\x{5D5}\x{5BC}\x{5D3}" LayoutBlockFlow {OPTION} at (1,116) size 310x23 - LayoutText {#text} at (2,0) size 70x21 - text run at (2,0) width 70 RTL: "\x{627}\x{644}\x{644}\x{63A}\x{629} \x{627}\x{644}\x{639}\x{631}\x{628}\x{64A}\x{629}" + LayoutText {#text} at (2,0) size 76x21 + text run at (2,0) width 76 RTL: "\x{627}\x{644}\x{644}\x{63A}\x{629} \x{627}\x{644}\x{639}\x{631}\x{628}\x{64A}\x{629}" LayoutBlockFlow {OPTION} at (1,139) size 310x23 LayoutText {#text} at (2,0) size 127x21 text run at (2,0) width 127: "Et volia\x{300}: ATSUI!"
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/text/emphasis-combined-text-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/fast/text/emphasis-combined-text-expected.png index e20b6a2..855b9b9 100644 --- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/text/emphasis-combined-text-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/text/emphasis-combined-text-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/text/emphasis-combined-text-expected.txt b/third_party/WebKit/LayoutTests/platform/win-xp/fast/text/emphasis-combined-text-expected.txt index 33ef199a..d5a0a10 100644 --- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/text/emphasis-combined-text-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/text/emphasis-combined-text-expected.txt
@@ -1,35 +1,35 @@ layer at (0,0) size 800x600 - RenderView at (0,0) size 800x600 + LayoutView at (0,0) size 800x600 layer at (0,0) size 800x600 - RenderBlock {HTML} at (0,0) size 800x600 - RenderBody {BODY} at (8,8) size 744x584 - RenderBlock {P} at (0,0) size 111x584 - RenderInline {SPAN} at (0,0) size 55x192 - RenderText {#text} at (55,0) size 55x96 - text run at (55,0) width 96: "\x{6587}\x{5B57}" - RenderInline {SPAN} at (0,0) size 55x48 - RenderCombineText {#text} at (55,96) size 55x48 - text run at (55,96) width 48: "90" - RenderText {#text} at (55,144) size 55x48 - text run at (55,144) width 48: "\x{5E74}" - RenderText {#text} at (0,0) size 0x0 - RenderBlock {P} at (159,0) size 83x584 - RenderInline {SPAN} at (0,0) size 55x192 - RenderText {#text} at (27,0) size 55x96 + LayoutBlockFlow {HTML} at (0,0) size 800x600 + LayoutBlockFlow {BODY} at (8,8) size 744x584 + LayoutBlockFlow {P} at (0,0) size 83x584 + LayoutInline {SPAN} at (0,0) size 55x192 + LayoutText {#text} at (27,0) size 55x96 text run at (27,0) width 96: "\x{6587}\x{5B57}" - RenderInline {SPAN} at (0,0) size 55x48 - RenderCombineText {#text} at (27,96) size 55x48 + LayoutInline {SPAN} at (0,0) size 55x48 + LayoutTextCombine {#text} at (27,96) size 55x48 text run at (27,96) width 48: "90" - RenderText {#text} at (27,144) size 55x48 + LayoutText {#text} at (27,144) size 55x48 text run at (27,144) width 48: "\x{5E74}" - RenderText {#text} at (0,0) size 0x0 - RenderBlock {P} at (290,0) size 80x584 - RenderInline {SPAN} at (0,0) size 55x192 - RenderText {#text} at (24,0) size 55x96 + LayoutText {#text} at (0,0) size 0x0 + LayoutBlockFlow {P} at (131,0) size 83x584 + LayoutInline {SPAN} at (0,0) size 55x192 + LayoutText {#text} at (27,0) size 55x96 + text run at (27,0) width 96: "\x{6587}\x{5B57}" + LayoutInline {SPAN} at (0,0) size 55x48 + LayoutTextCombine {#text} at (27,96) size 55x48 + text run at (27,96) width 48: "90" + LayoutText {#text} at (27,144) size 55x48 + text run at (27,144) width 48: "\x{5E74}" + LayoutText {#text} at (0,0) size 0x0 + LayoutBlockFlow {P} at (262,0) size 80x584 + LayoutInline {SPAN} at (0,0) size 55x192 + LayoutText {#text} at (24,0) size 55x96 text run at (24,0) width 96: "\x{6587}\x{5B57}" - RenderInline {SPAN} at (0,0) size 55x48 - RenderCombineText {#text} at (24,96) size 55x48 + LayoutInline {SPAN} at (0,0) size 55x48 + LayoutTextCombine {#text} at (24,96) size 55x48 text run at (24,96) width 48: "90" - RenderText {#text} at (24,144) size 55x48 + LayoutText {#text} at (24,144) size 55x48 text run at (24,144) width 48: "\x{5E74}" - RenderText {#text} at (0,0) size 0x0 + LayoutText {#text} at (0,0) size 0x0
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/text/emphasis-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/fast/text/emphasis-expected.png index 16d771fc..6e620ca 100644 --- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/text/emphasis-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/text/emphasis-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/text/emphasis-expected.txt b/third_party/WebKit/LayoutTests/platform/win-xp/fast/text/emphasis-expected.txt index 452e0374..0d5aa9d2 100644 --- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/text/emphasis-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/text/emphasis-expected.txt
@@ -1,8 +1,8 @@ layer at (0,0) size 800x600 LayoutView at (0,0) size 800x600 -layer at (0,0) size 800x569 - LayoutBlockFlow {HTML} at (0,0) size 800x569 - LayoutBlockFlow {BODY} at (8,8) size 784x553 +layer at (0,0) size 800x554 + LayoutBlockFlow {HTML} at (0,0) size 800x554 + LayoutBlockFlow {BODY} at (8,8) size 784x538 LayoutBlockFlow {DIV} at (4,4) size 366x146 [border: (3px solid #000000)] LayoutText {#text} at (3,3) size 270x27 text run at (3,3) width 270: "Lorem ipsum dolor sit amet," @@ -38,7 +38,7 @@ text run at (124,73) width 209: "lobortis eu iaculis vel," text run at (3,115) width 208: "scelerisque nec dolor." LayoutText {#text} at (0,0) size 0x0 - LayoutBlockFlow {DIV} at (4,158) size 366x185 [border: (3px solid #000000)] + LayoutBlockFlow {DIV} at (4,165) size 366x163 [border: (3px solid #000000)] LayoutText {#text} at (3,18) size 70x27 text run at (3,18) width 70: "Lorem " LayoutInline {SPAN} at (0,0) size 57x27 @@ -62,103 +62,103 @@ LayoutText {#text} at (267,18) size 6x27 text run at (267,18) width 6: "," LayoutInline {SPAN} at (0,0) size 111x27 - LayoutText {#text} at (3,72) size 111x27 - text run at (3,72) width 111: "consectetur" - LayoutText {#text} at (114,72) size 6x27 - text run at (114,72) width 6: " " + LayoutText {#text} at (3,61) size 111x27 + text run at (3,61) width 111: "consectetur" + LayoutText {#text} at (114,61) size 6x27 + text run at (114,61) width 6: " " LayoutInline {SPAN} at (0,0) size 96x27 - LayoutText {#text} at (120,72) size 96x27 - text run at (120,72) width 96: "adipiscing" - LayoutText {#text} at (216,72) size 6x27 - text run at (216,72) width 6: " " + LayoutText {#text} at (120,61) size 96x27 + text run at (120,61) width 96: "adipiscing" + LayoutText {#text} at (216,61) size 6x27 + text run at (216,61) width 6: " " LayoutInline {SPAN} at (0,0) size 30x27 - LayoutText {#text} at (222,72) size 30x27 - text run at (222,72) width 30: "elit" - LayoutText {#text} at (252,72) size 12x27 - text run at (252,72) width 12: ". " + LayoutText {#text} at (222,61) size 30x27 + text run at (222,61) width 30: "elit" + LayoutText {#text} at (252,61) size 12x27 + text run at (252,61) width 12: ". " LayoutInline {SPAN} at (0,0) size 82x27 - LayoutText {#text} at (264,72) size 82x27 - text run at (264,72) width 82: "Aliquam" - LayoutText {#text} at (346,72) size 6x27 - text run at (346,72) width 6: "," + LayoutText {#text} at (264,61) size 82x27 + text run at (264,61) width 82: "Aliquam" + LayoutText {#text} at (346,61) size 6x27 + text run at (346,61) width 6: "," LayoutInline {SPAN} at (0,0) size 42x27 - LayoutText {#text} at (3,126) size 42x27 - text run at (3,126) width 42: "odio" - LayoutText {#text} at (45,126) size 6x27 - text run at (45,126) width 6: " " + LayoutText {#text} at (3,104) size 42x27 + text run at (3,104) width 42: "odio" + LayoutText {#text} at (45,104) size 6x27 + text run at (45,104) width 6: " " LayoutInline {SPAN} at (0,0) size 61x27 - LayoutText {#text} at (51,126) size 61x27 - text run at (51,126) width 61: "sapien" - LayoutText {#text} at (112,126) size 12x27 - text run at (112,126) width 12: ", " + LayoutText {#text} at (51,104) size 61x27 + text run at (51,104) width 61: "sapien" + LayoutText {#text} at (112,104) size 12x27 + text run at (112,104) width 12: ", " LayoutInline {SPAN} at (0,0) size 72x27 - LayoutText {#text} at (124,126) size 72x27 - text run at (124,126) width 72: "lobortis" - LayoutText {#text} at (196,126) size 330x55 - text run at (196,126) width 6: " " - text run at (202,126) width 131: "eu iaculis vel," - text run at (3,154) width 208: "scelerisque nec dolor." - LayoutText {#text} at (374,312) size 6x27 - text run at (374,312) width 6: " " - LayoutBlockFlow {DIV} at (384,173) size 366x156 [border: (3px solid #000000)] - LayoutText {#text} at (30,3) size 27x70 - text run at (30,3) width 70: "Lorem " + LayoutText {#text} at (124,104) size 72x27 + text run at (124,104) width 72: "lobortis" + LayoutText {#text} at (196,104) size 330x55 + text run at (196,104) width 6: " " + text run at (202,104) width 131: "eu iaculis vel," + text run at (3,132) width 208: "scelerisque nec dolor." + LayoutText {#text} at (374,297) size 6x27 + text run at (374,297) width 6: " " + LayoutBlockFlow {DIV} at (384,158) size 366x156 [border: (3px solid #000000)] + LayoutText {#text} at (18,3) size 27x70 + text run at (18,3) width 70: "Lorem " LayoutInline {SPAN} at (0,0) size 27x57 - LayoutText {#text} at (30,73) size 27x57 - text run at (30,73) width 57: "ipsum" + LayoutText {#text} at (18,73) size 27x57 + text run at (18,73) width 57: "ipsum" LayoutText {#text} at (0,0) size 0x0 LayoutInline {SPAN} at (0,0) size 27x50 - LayoutText {#text} at (84,3) size 27x50 - text run at (84,3) width 50: "dolor" - LayoutText {#text} at (84,53) size 27x6 - text run at (84,53) width 6: " " + LayoutText {#text} at (60,3) size 27x50 + text run at (60,3) width 50: "dolor" + LayoutText {#text} at (60,53) size 27x6 + text run at (60,53) width 6: " " LayoutInline {SPAN} at (0,0) size 27x22 - LayoutText {#text} at (84,59) size 27x22 - text run at (84,59) width 22: "sit" - LayoutText {#text} at (84,81) size 27x6 - text run at (84,81) width 6: " " + LayoutText {#text} at (60,59) size 27x22 + text run at (60,59) width 22: "sit" + LayoutText {#text} at (60,81) size 27x6 + text run at (60,81) width 6: " " LayoutInline {SPAN} at (0,0) size 27x47 - LayoutText {#text} at (84,87) size 27x47 - text run at (84,87) width 47: "amet" - LayoutText {#text} at (84,134) size 27x6 - text run at (84,134) width 6: "," + LayoutText {#text} at (60,87) size 27x47 + text run at (60,87) width 47: "amet" + LayoutText {#text} at (60,134) size 27x6 + text run at (60,134) width 6: "," LayoutInline {SPAN} at (0,0) size 27x111 - LayoutText {#text} at (127,3) size 27x111 - text run at (127,3) width 111: "consectetur" + LayoutText {#text} at (103,3) size 27x111 + text run at (103,3) width 111: "consectetur" LayoutText {#text} at (0,0) size 0x0 LayoutInline {SPAN} at (0,0) size 27x96 - LayoutText {#text} at (181,3) size 27x96 - text run at (181,3) width 96: "adipiscing" - LayoutText {#text} at (181,99) size 27x6 - text run at (181,99) width 6: " " + LayoutText {#text} at (145,3) size 27x96 + text run at (145,3) width 96: "adipiscing" + LayoutText {#text} at (145,99) size 27x6 + text run at (145,99) width 6: " " LayoutInline {SPAN} at (0,0) size 27x30 - LayoutText {#text} at (181,105) size 27x30 - text run at (181,105) width 30: "elit" - LayoutText {#text} at (181,135) size 27x6 - text run at (181,135) width 6: "." + LayoutText {#text} at (145,105) size 27x30 + text run at (145,105) width 30: "elit" + LayoutText {#text} at (145,135) size 27x6 + text run at (145,135) width 6: "." LayoutInline {SPAN} at (0,0) size 27x82 - LayoutText {#text} at (224,3) size 27x82 - text run at (224,3) width 82: "Aliquam" - LayoutText {#text} at (224,85) size 27x12 - text run at (224,85) width 12: ", " + LayoutText {#text} at (188,3) size 27x82 + text run at (188,3) width 82: "Aliquam" + LayoutText {#text} at (188,85) size 27x12 + text run at (188,85) width 12: ", " LayoutInline {SPAN} at (0,0) size 27x42 - LayoutText {#text} at (224,97) size 27x42 - text run at (224,97) width 42: "odio" + LayoutText {#text} at (188,97) size 27x42 + text run at (188,97) width 42: "odio" LayoutText {#text} at (0,0) size 0x0 LayoutInline {SPAN} at (0,0) size 27x61 - LayoutText {#text} at (278,3) size 27x61 - text run at (278,3) width 61: "sapien" - LayoutText {#text} at (278,64) size 27x12 - text run at (278,64) width 12: ", " + LayoutText {#text} at (231,3) size 27x61 + text run at (231,3) width 61: "sapien" + LayoutText {#text} at (231,64) size 27x12 + text run at (231,64) width 12: ", " LayoutInline {SPAN} at (0,0) size 27x72 - LayoutText {#text} at (278,76) size 27x72 - text run at (278,76) width 72: "lobortis" - LayoutText {#text} at (306,3) size 83x146 - text run at (306,3) width 131: "eu iaculis vel," - text run at (334,3) width 146: "scelerisque nec" - text run at (362,3) width 56: "dolor." + LayoutText {#text} at (231,76) size 27x72 + text run at (231,76) width 72: "lobortis" + LayoutText {#text} at (259,3) size 83x146 + text run at (259,3) width 131: "eu iaculis vel," + text run at (287,3) width 146: "scelerisque nec" + text run at (315,3) width 56: "dolor." LayoutText {#text} at (0,0) size 0x0 - LayoutBlockFlow {DIV} at (4,351) size 366x198 [border: (3px solid #000000)] + LayoutBlockFlow {DIV} at (4,336) size 366x198 [border: (3px solid #000000)] LayoutText {#text} at (3,13) size 270x27 text run at (3,13) width 270: "Lorem ipsum dolor sit amet," LayoutInline {SPAN} at (0,0) size 213x27 @@ -174,9 +174,9 @@ text run at (112,109) width 12: ", " text run at (124,109) width 209: "lobortis eu iaculis vel," text run at (3,157) width 208: "scelerisque nec dolor." - LayoutText {#text} at (374,508) size 6x27 - text run at (374,508) width 6: " " - LayoutBlockFlow {DIV} at (384,393) size 366x146 [border: (3px solid #000000)] + LayoutText {#text} at (374,493) size 6x27 + text run at (374,493) width 6: " " + LayoutBlockFlow {DIV} at (384,378) size 366x146 [border: (3px solid #000000)] LayoutText {#text} at (3,3) size 270x27 text run at (3,3) width 270: "Lorem ipsum dolor sit amet," LayoutInline {SPAN} at (0,0) size 213x27
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/text/emphasis-vertical-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/fast/text/emphasis-vertical-expected.png index 9777e277..3298995e 100644 --- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/text/emphasis-vertical-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/text/emphasis-vertical-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/text/emphasis-vertical-expected.txt b/third_party/WebKit/LayoutTests/platform/win-xp/fast/text/emphasis-vertical-expected.txt index 624ab46..48005d62 100644 --- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/text/emphasis-vertical-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/text/emphasis-vertical-expected.txt
@@ -1,7 +1,7 @@ -layer at (0,0) size 800x600 scrollX 1.00 scrollWidth 801 +layer at (0,0) size 800x600 LayoutView at (0,0) size 800x600 -layer at (-1,0) size 801x600 backgroundClip at (0,0) size 800x600 clip at (0,0) size 800x600 - LayoutBlockFlow {HTML} at (0,0) size 801x600 +layer at (59,0) size 741x600 + LayoutBlockFlow {HTML} at (0,0) size 741x600 LayoutBlockFlow {BODY} at (8,8) size 0x584 LayoutBlockFlow (floating) {DIV} at (8,8) size 156x366 [border: (3px solid #000000)] LayoutText {#text} at (15,3) size 20x252 @@ -20,48 +20,48 @@ text run at (79,229) width 130: "\x{8A2A}\x{554F}\x{3057}\x{305F}\x{30A6}\x{30A7}\x{30D6}\x{30DA}" text run at (111,3) width 353: "\x{30FC}\x{30B8}\x{306E}\x{30B3}\x{30F3}\x{30C6}\x{30F3}\x{30C4}\x{304B}\x{3089}\x{3082}\x{691C}\x{7D22}\x{3059}\x{308B}\x{3053}\x{3068}\x{304C}\x{3067}\x{304D}\x{307E}" text run at (132,3) width 30: "\x{3059}\x{3002}" - LayoutBlockFlow (floating) {DIV} at (180,8) size 182x366 [border: (3px solid #000000)] - LayoutText {#text} at (23,3) size 20x47 - text run at (23,3) width 47: "\x{305B}\x{3063}\x{304B}" + LayoutBlockFlow (floating) {DIV} at (180,8) size 162x366 [border: (3px solid #000000)] + LayoutText {#text} at (15,3) size 20x47 + text run at (15,3) width 47: "\x{305B}\x{3063}\x{304B}" LayoutInline {SPAN} at (0,0) size 20x103 - LayoutText {#text} at (23,49) size 20x103 - text run at (23,49) width 102: "\x{304F}\x{898B}\x{3064}\x{3051}\x{305F}\x{3059}" + LayoutText {#text} at (15,49) size 20x103 + text run at (15,49) width 102: "\x{304F}\x{898B}\x{3064}\x{3051}\x{305F}\x{3059}" LayoutInline {SPAN} at (0,0) size 20x68 - LayoutText {#text} at (23,151) size 20x68 - text run at (23,151) width 68: "\x{3070}\x{3089}\x{3057}\x{3044}" + LayoutText {#text} at (15,151) size 20x68 + text run at (15,151) width 68: "\x{3070}\x{3089}\x{3057}\x{3044}" LayoutInline {SPAN} at (0,0) size 20x71 - LayoutText {#text} at (23,218) size 20x71 - text run at (23,218) width 71: "\x{8A18}\x{4E8B}\x{304C}\x{3069}" + LayoutText {#text} at (15,218) size 20x71 + text run at (15,218) width 71: "\x{8A18}\x{4E8B}\x{304C}\x{3069}" LayoutInline {SPAN} at (0,0) size 20x64 - LayoutText {#text} at (23,288) size 20x64 - text run at (23,288) width 63: "\x{3053}\x{306B}\x{3042}\x{3063}" + LayoutText {#text} at (15,288) size 20x64 + text run at (15,288) width 63: "\x{3053}\x{306B}\x{3042}\x{3063}" LayoutInline {SPAN} at (0,0) size 20x103 - LayoutText {#text} at (63,3) size 20x103 - text run at (63,3) width 103: "\x{305F}\x{304B}\x{5FD8}\x{308C}\x{3066}\x{3057}" + LayoutText {#text} at (49,3) size 20x103 + text run at (49,3) width 103: "\x{305F}\x{304B}\x{5FD8}\x{308C}\x{3066}\x{3057}" LayoutInline {SPAN} at (0,0) size 20x85 - LayoutText {#text} at (63,105) size 20x85 - text run at (63,105) width 85: "\x{307E}\x{3063}\x{305F}\x{7D4C}\x{9A13}" + LayoutText {#text} at (49,105) size 20x85 + text run at (49,105) width 85: "\x{307E}\x{3063}\x{305F}\x{7D4C}\x{9A13}" LayoutInline {SPAN} at (0,0) size 20x106 - LayoutText {#text} at (63,189) size 20x106 - text run at (63,189) width 106: "\x{306F}\x{3042}\x{308A}\x{307E}\x{3059}\x{304B}" - LayoutInline {SPAN} at (0,0) size 60x346 - LayoutText {#text} at (63,294) size 60x346 - text run at (63,294) width 54: "\x{306A}\x{3089}\x{30BF}" - text run at (103,3) width 66: "\x{30A4}\x{30C8}\x{30EB}\x{3068}" + LayoutText {#text} at (49,189) size 20x106 + text run at (49,189) width 106: "\x{306F}\x{3042}\x{308A}\x{307E}\x{3059}\x{304B}" + LayoutInline {SPAN} at (0,0) size 54x346 + LayoutText {#text} at (49,294) size 54x346 + text run at (49,294) width 54: "\x{306A}\x{3089}\x{30BF}" + text run at (83,3) width 66: "\x{30A4}\x{30C8}\x{30EB}\x{3068}" LayoutInline {SPAN} at (0,0) size 20x133 - LayoutText {#text} at (103,68) size 20x133 - text run at (103,68) width 133: "\x{30A2}\x{30C9}\x{30EC}\x{30B9}\x{3060}\x{3051}\x{3067}\x{306A}" + LayoutText {#text} at (83,68) size 20x133 + text run at (83,68) width 133: "\x{30A2}\x{30C9}\x{30EC}\x{30B9}\x{3060}\x{3051}\x{3067}\x{306A}" LayoutInline {SPAN} at (0,0) size 20x118 - LayoutText {#text} at (103,200) size 20x118 - text run at (103,200) width 118: "\x{304F}\x{3001}\x{8A2A}\x{554F}\x{3057}\x{305F}\x{30A6}" + LayoutText {#text} at (83,200) size 20x118 + text run at (83,200) width 118: "\x{304F}\x{3001}\x{8A2A}\x{554F}\x{3057}\x{305F}\x{30A6}" LayoutInline {SPAN} at (0,0) size 54x356 - LayoutText {#text} at (103,317) size 54x356 - text run at (103,317) width 42: "\x{30A7}\x{30D6}\x{30DA}" - text run at (137,3) width 96: "\x{30FC}\x{30B8}\x{306E}\x{30B3}\x{30F3}\x{30C6}" - LayoutText {#text} at (137,98) size 41x353 - text run at (137,98) width 257: "\x{30F3}\x{30C4}\x{304B}\x{3089}\x{3082}\x{691C}\x{7D22}\x{3059}\x{308B}\x{3053}\x{3068}\x{304C}\x{3067}\x{304D}\x{307E}" - text run at (158,3) width 30: "\x{3059}\x{3002}" - LayoutBlockFlow (floating) {DIV} at (378,8) size 181x366 [border: (3px solid #000000)] + LayoutText {#text} at (83,317) size 54x356 + text run at (83,317) width 42: "\x{30A7}\x{30D6}\x{30DA}" + text run at (117,3) width 96: "\x{30FC}\x{30B8}\x{306E}\x{30B3}\x{30F3}\x{30C6}" + LayoutText {#text} at (117,98) size 41x353 + text run at (117,98) width 257: "\x{30F3}\x{30C4}\x{304B}\x{3089}\x{3082}\x{691C}\x{7D22}\x{3059}\x{308B}\x{3053}\x{3068}\x{304C}\x{3067}\x{304D}\x{307E}" + text run at (138,3) width 30: "\x{3059}\x{3002}" + LayoutBlockFlow (floating) {DIV} at (358,8) size 161x366 [border: (3px solid #000000)] LayoutText {#text} at (3,3) size 20x47 text run at (3,3) width 47: "\x{305B}\x{3063}\x{304B}" LayoutInline {SPAN} at (0,0) size 20x103 @@ -77,45 +77,45 @@ LayoutText {#text} at (3,288) size 20x64 text run at (3,288) width 63: "\x{3053}\x{306B}\x{3042}\x{3063}" LayoutInline {SPAN} at (0,0) size 20x103 - LayoutText {#text} at (43,3) size 20x103 - text run at (43,3) width 103: "\x{305F}\x{304B}\x{5FD8}\x{308C}\x{3066}\x{3057}" + LayoutText {#text} at (35,3) size 20x103 + text run at (35,3) width 103: "\x{305F}\x{304B}\x{5FD8}\x{308C}\x{3066}\x{3057}" LayoutInline {SPAN} at (0,0) size 20x85 - LayoutText {#text} at (43,105) size 20x85 - text run at (43,105) width 85: "\x{307E}\x{3063}\x{305F}\x{7D4C}\x{9A13}" + LayoutText {#text} at (35,105) size 20x85 + text run at (35,105) width 85: "\x{307E}\x{3063}\x{305F}\x{7D4C}\x{9A13}" LayoutInline {SPAN} at (0,0) size 20x106 - LayoutText {#text} at (43,189) size 20x106 - text run at (43,189) width 106: "\x{306F}\x{3042}\x{308A}\x{307E}\x{3059}\x{304B}" - LayoutInline {SPAN} at (0,0) size 60x346 - LayoutText {#text} at (43,294) size 60x346 - text run at (43,294) width 54: "\x{306A}\x{3089}\x{30BF}" - text run at (83,3) width 66: "\x{30A4}\x{30C8}\x{30EB}\x{3068}" + LayoutText {#text} at (35,189) size 20x106 + text run at (35,189) width 106: "\x{306F}\x{3042}\x{308A}\x{307E}\x{3059}\x{304B}" + LayoutInline {SPAN} at (0,0) size 54x346 + LayoutText {#text} at (35,294) size 54x346 + text run at (35,294) width 54: "\x{306A}\x{3089}\x{30BF}" + text run at (69,3) width 66: "\x{30A4}\x{30C8}\x{30EB}\x{3068}" LayoutInline {SPAN} at (0,0) size 20x133 - LayoutText {#text} at (83,68) size 20x133 - text run at (83,68) width 133: "\x{30A2}\x{30C9}\x{30EC}\x{30B9}\x{3060}\x{3051}\x{3067}\x{306A}" + LayoutText {#text} at (69,68) size 20x133 + text run at (69,68) width 133: "\x{30A2}\x{30C9}\x{30EC}\x{30B9}\x{3060}\x{3051}\x{3067}\x{306A}" LayoutInline {SPAN} at (0,0) size 20x118 - LayoutText {#text} at (83,200) size 20x118 - text run at (83,200) width 118: "\x{304F}\x{3001}\x{8A2A}\x{554F}\x{3057}\x{305F}\x{30A6}" - LayoutInline {SPAN} at (0,0) size 60x356 - LayoutText {#text} at (83,317) size 60x356 - text run at (83,317) width 42: "\x{30A7}\x{30D6}\x{30DA}" - text run at (123,3) width 96: "\x{30FC}\x{30B8}\x{306E}\x{30B3}\x{30F3}\x{30C6}" - LayoutText {#text} at (123,98) size 54x353 - text run at (123,98) width 257: "\x{30F3}\x{30C4}\x{304B}\x{3089}\x{3082}\x{691C}\x{7D22}\x{3059}\x{308B}\x{3053}\x{3068}\x{304C}\x{3067}\x{304D}\x{307E}" - text run at (157,3) width 30: "\x{3059}\x{3002}" - LayoutBlockFlow (floating) {DIV} at (575,8) size 210x366 [border: (3px solid #000000)] - LayoutText {#text} at (23,3) size 20x252 - text run at (23,3) width 252: "\x{305B}\x{3063}\x{304B}\x{304F}\x{898B}\x{3064}\x{3051}\x{305F}\x{3059}\x{3070}\x{3089}\x{3057}\x{3044}\x{8A18}\x{4E8B}" - LayoutInline {SPAN} at (0,0) size 60x349 - LayoutText {#text} at (23,254) size 60x349 - text run at (23,254) width 97: "\x{304C}\x{3069}\x{3053}\x{306B}\x{3042}\x{3063}" - text run at (63,3) width 121: "\x{305F}\x{304B}\x{5FD8}\x{308C}\x{3066}\x{3057}\x{307E}" - LayoutText {#text} at (63,123) size 20x172 - text run at (63,123) width 172: "\x{3063}\x{305F}\x{7D4C}\x{9A13}\x{306F}\x{3042}\x{308A}\x{307E}\x{3059}\x{304B}" - LayoutInline {SPAN} at (0,0) size 60x346 - LayoutText {#text} at (63,294) size 60x346 - text run at (63,294) width 54: "\x{306A}\x{3089}\x{30BF}" - text run at (103,3) width 227: "\x{30A4}\x{30C8}\x{30EB}\x{3068}\x{30A2}\x{30C9}\x{30EC}\x{30B9}\x{3060}\x{3051}\x{3067}\x{306A}\x{304F}\x{3001}" - LayoutText {#text} at (103,229) size 96x356 - text run at (103,229) width 130: "\x{8A2A}\x{554F}\x{3057}\x{305F}\x{30A6}\x{30A7}\x{30D6}\x{30DA}" - text run at (143,3) width 353: "\x{30FC}\x{30B8}\x{306E}\x{30B3}\x{30F3}\x{30C6}\x{30F3}\x{30C4}\x{304B}\x{3089}\x{3082}\x{691C}\x{7D22}\x{3059}\x{308B}\x{3053}\x{3068}\x{304C}\x{3067}\x{304D}\x{307E}" - text run at (179,3) width 30: "\x{3059}\x{3002}" + LayoutText {#text} at (69,200) size 20x118 + text run at (69,200) width 118: "\x{304F}\x{3001}\x{8A2A}\x{554F}\x{3057}\x{305F}\x{30A6}" + LayoutInline {SPAN} at (0,0) size 54x356 + LayoutText {#text} at (69,317) size 54x356 + text run at (69,317) width 42: "\x{30A7}\x{30D6}\x{30DA}" + text run at (103,3) width 96: "\x{30FC}\x{30B8}\x{306E}\x{30B3}\x{30F3}\x{30C6}" + LayoutText {#text} at (103,98) size 54x353 + text run at (103,98) width 257: "\x{30F3}\x{30C4}\x{304B}\x{3089}\x{3082}\x{691C}\x{7D22}\x{3059}\x{308B}\x{3053}\x{3068}\x{304C}\x{3067}\x{304D}\x{307E}" + text run at (137,3) width 30: "\x{3059}\x{3002}" + LayoutBlockFlow (floating) {DIV} at (535,8) size 190x366 [border: (3px solid #000000)] + LayoutText {#text} at (15,3) size 20x252 + text run at (15,3) width 252: "\x{305B}\x{3063}\x{304B}\x{304F}\x{898B}\x{3064}\x{3051}\x{305F}\x{3059}\x{3070}\x{3089}\x{3057}\x{3044}\x{8A18}\x{4E8B}" + LayoutInline {SPAN} at (0,0) size 56x349 + LayoutText {#text} at (15,254) size 56x349 + text run at (15,254) width 97: "\x{304C}\x{3069}\x{3053}\x{306B}\x{3042}\x{3063}" + text run at (51,3) width 121: "\x{305F}\x{304B}\x{5FD8}\x{308C}\x{3066}\x{3057}\x{307E}" + LayoutText {#text} at (51,123) size 20x172 + text run at (51,123) width 172: "\x{3063}\x{305F}\x{7D4C}\x{9A13}\x{306F}\x{3042}\x{308A}\x{307E}\x{3059}\x{304B}" + LayoutInline {SPAN} at (0,0) size 56x346 + LayoutText {#text} at (51,294) size 56x346 + text run at (51,294) width 54: "\x{306A}\x{3089}\x{30BF}" + text run at (87,3) width 227: "\x{30A4}\x{30C8}\x{30EB}\x{3068}\x{30A2}\x{30C9}\x{30EC}\x{30B9}\x{3060}\x{3051}\x{3067}\x{306A}\x{304F}\x{3001}" + LayoutText {#text} at (87,229) size 92x356 + text run at (87,229) width 130: "\x{8A2A}\x{554F}\x{3057}\x{305F}\x{30A6}\x{30A7}\x{30D6}\x{30DA}" + text run at (123,3) width 353: "\x{30FC}\x{30B8}\x{306E}\x{30B3}\x{30F3}\x{30C6}\x{30F3}\x{30C4}\x{304B}\x{3089}\x{3082}\x{691C}\x{7D22}\x{3059}\x{308B}\x{3053}\x{3068}\x{304C}\x{3067}\x{304D}\x{307E}" + text run at (159,3) width 30: "\x{3059}\x{3002}"
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/svg/filters/feTile-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/svg/filters/feTile-expected.png new file mode 100644 index 0000000..2b2b022 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/win-xp/svg/filters/feTile-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/svg/hixie/viewbox/preserveAspectRatio/001-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/svg/hixie/viewbox/preserveAspectRatio/001-expected.png index 26eb0de..45e7e14 100644 --- a/third_party/WebKit/LayoutTests/platform/win-xp/svg/hixie/viewbox/preserveAspectRatio/001-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win-xp/svg/hixie/viewbox/preserveAspectRatio/001-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/svg/text/bidi-text-anchor-direction-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/svg/text/bidi-text-anchor-direction-expected.png index bace5d4..7b323a05 100644 --- a/third_party/WebKit/LayoutTests/platform/win-xp/svg/text/bidi-text-anchor-direction-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win-xp/svg/text/bidi-text-anchor-direction-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/virtual/display_list_2d_canvas/fast/canvas/canvas-shadow-source-in-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/virtual/display_list_2d_canvas/fast/canvas/canvas-shadow-source-in-expected.png index 49d21a21..cbaefe7 100644 --- a/third_party/WebKit/LayoutTests/platform/win-xp/virtual/display_list_2d_canvas/fast/canvas/canvas-shadow-source-in-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win-xp/virtual/display_list_2d_canvas/fast/canvas/canvas-shadow-source-in-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/virtual/gpu/fast/canvas/image-object-in-canvas-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/virtual/gpu/fast/canvas/image-object-in-canvas-expected.png index 7cafffd..b3df32a 100644 --- a/third_party/WebKit/LayoutTests/platform/win-xp/virtual/gpu/fast/canvas/image-object-in-canvas-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win-xp/virtual/gpu/fast/canvas/image-object-in-canvas-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/repaint/should-not-clip-composited-overflow-scrolling-layer-expected.txt b/third_party/WebKit/LayoutTests/platform/win/compositing/repaint/should-not-clip-composited-overflow-scrolling-layer-expected.txt index 0c47f756..7ebae0a8 100644 --- a/third_party/WebKit/LayoutTests/platform/win/compositing/repaint/should-not-clip-composited-overflow-scrolling-layer-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/compositing/repaint/should-not-clip-composited-overflow-scrolling-layer-expected.txt
@@ -15,7 +15,8 @@ [-2001, -2000, 5001, 5000] ], "paintInvalidationClients": [ - "LayoutBlockFlow DIV id='content'" + "LayoutBlockFlow DIV id='content'", + "RootInlineBox" ], "children": [ { @@ -29,7 +30,8 @@ [-1, 0, 5001, 5000] ], "paintInvalidationClients": [ - "LayoutBlockFlow DIV id='content'" + "LayoutBlockFlow DIV id='content'", + "RootInlineBox" ] } ]
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/canvas/canvas-shadow-source-in-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/canvas/canvas-shadow-source-in-expected.png index cb58a88..647e06c0 100644 --- a/third_party/WebKit/LayoutTests/platform/win/fast/canvas/canvas-shadow-source-in-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/fast/canvas/canvas-shadow-source-in-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/canvas/canvas-toBlob-jpeg-maximum-quality-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/canvas/canvas-toBlob-jpeg-maximum-quality-expected.png index b5daa85..e374c1c5 100644 --- a/third_party/WebKit/LayoutTests/platform/win/fast/canvas/canvas-toBlob-jpeg-maximum-quality-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/fast/canvas/canvas-toBlob-jpeg-maximum-quality-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/canvas/canvas-toBlob-jpeg-medium-quality-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/canvas/canvas-toBlob-jpeg-medium-quality-expected.png index b5daa85..8019bf0 100644 --- a/third_party/WebKit/LayoutTests/platform/win/fast/canvas/canvas-toBlob-jpeg-medium-quality-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/fast/canvas/canvas-toBlob-jpeg-medium-quality-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/canvas/canvas-toBlob-webp-maximum-quality-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/canvas/canvas-toBlob-webp-maximum-quality-expected.png index b5daa85..55b79651 100644 --- a/third_party/WebKit/LayoutTests/platform/win/fast/canvas/canvas-toBlob-webp-maximum-quality-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/fast/canvas/canvas-toBlob-webp-maximum-quality-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/css/vertical-text-overflow-ellipsis-text-align-center-expected.txt b/third_party/WebKit/LayoutTests/platform/win/fast/css/vertical-text-overflow-ellipsis-text-align-center-expected.txt index 568dcd3..3ac4a44c 100644 --- a/third_party/WebKit/LayoutTests/platform/win/fast/css/vertical-text-overflow-ellipsis-text-align-center-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/fast/css/vertical-text-overflow-ellipsis-text-align-center-expected.txt
@@ -52,42 +52,42 @@ LayoutImage {IMG} at (1,186.95) size 25x25 LayoutText {#text} at (12,211) size 17x556 text run at (12,211) width 555: " consectetur adipiscing elit. Vivamus vitae eros non libero faucibus sagittis sed ut eros." -layer at (8,1161) size 31x310 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 scrollHeight 761 +layer at (8,1161) size 31x310 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 scrollHeight 762 LayoutBlockFlow {DIV} at (0,1152.88) size 31x310 [border: (1px solid #000000)] LayoutText {#text} at (12,1) size 17x278 text run at (12,1) width 278: "Lorem ipsum dolor sit amet, consectetur ad" LayoutImage {IMG} at (1,278.70) size 25x25 LayoutText {#text} at (12,303) size 17x460 text run at (12,303) width 459: "ipiscing elit. Vivamus vitae eros non libero faucibus sagittis sed ut eros." -layer at (8,1532) size 20x310 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 scrollY 428.00 scrollHeight 736 +layer at (8,1532) size 20x310 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 scrollY 430.00 scrollHeight 738 LayoutBlockFlow {DIV} at (0,1523.59) size 20x310 [border: (1px solid #000000)] - LayoutText {#text} at (1,-427) size 17x737 - text run at (1,-427) width 737 RTL override: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vitae eros non libero faucibus sagittis sed ut eros." -layer at (8,1902) size 74x310 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 scrollY 428.00 scrollHeight 737 + LayoutText {#text} at (1,-429) size 17x739 + text run at (1,-429) width 738 RTL override: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vitae eros non libero faucibus sagittis sed ut eros." +layer at (8,1902) size 74x310 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 scrollY 430.00 scrollHeight 739 LayoutBlockFlow {DIV} at (0,1894.31) size 74x310 [border: (1px solid #000000)] - LayoutText {#text} at (1,-427) size 17x737 - text run at (1,-427) width 737 RTL override: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vitae eros non libero faucibus sagittis sed ut eros." + LayoutText {#text} at (1,-429) size 17x739 + text run at (1,-429) width 738 RTL override: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vitae eros non libero faucibus sagittis sed ut eros." LayoutBR {BR} at (0,0) size 0x0 - LayoutText {#text} at (19,-418) size 17x728 - text run at (19,-418) width 727 RTL override: "orem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vitae eros non libero faucibus sagittis sed ut eros." + LayoutText {#text} at (19,-419) size 17x729 + text run at (19,-419) width 728 RTL override: "orem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vitae eros non libero faucibus sagittis sed ut eros." LayoutBR {BR} at (0,0) size 0x0 - LayoutText {#text} at (37,-409) size 17x719 - text run at (37,-409) width 719 RTL override: "rem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vitae eros non libero faucibus sagittis sed ut eros." + LayoutText {#text} at (37,-411) size 17x721 + text run at (37,-411) width 720 RTL override: "rem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vitae eros non libero faucibus sagittis sed ut eros." LayoutBR {BR} at (0,0) size 0x0 - LayoutText {#text} at (55,-405) size 17x714 - text run at (55,-405) width 714 RTL override: "em ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vitae eros non libero faucibus sagittis sed ut eros." + LayoutText {#text} at (55,-406) size 17x715 + text run at (55,-406) width 715 RTL override: "em ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vitae eros non libero faucibus sagittis sed ut eros." LayoutBR {BR} at (0,0) size 0x0 -layer at (8,2273) size 31x310 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 scrollY 457.00 scrollHeight 765 +layer at (8,2273) size 31x310 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 scrollY 458.00 scrollHeight 767 LayoutBlockFlow {DIV} at (0,2265.03) size 31x310 [border: (1px solid #000000)] LayoutText {#text} at (12,123) size 17x186 text run at (12,123) width 186 RTL override: "Lorem ipsum dolor sit amet, " LayoutImage {IMG} at (1,98.25) size 25x25 - LayoutText {#text} at (12,-456) size 17x556 - text run at (12,-456) width 555 RTL override: " consectetur adipiscing elit. Vivamus vitae eros non libero faucibus sagittis sed ut eros." -layer at (8,2644) size 31x310 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 scrollY 453.00 scrollHeight 761 + LayoutText {#text} at (12,-457) size 17x557 + text run at (12,-457) width 556 RTL override: " consectetur adipiscing elit. Vivamus vitae eros non libero faucibus sagittis sed ut eros." +layer at (8,2644) size 31x310 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 scrollY 454.00 scrollHeight 762 LayoutBlockFlow {DIV} at (0,2635.75) size 31x310 [border: (1px solid #000000)] LayoutText {#text} at (12,31) size 17x278 text run at (12,31) width 278 RTL override: "Lorem ipsum dolor sit amet, consectetur ad" LayoutImage {IMG} at (1,6.30) size 25x25 - LayoutText {#text} at (12,-452) size 17x460 - text run at (12,-452) width 459 RTL override: "ipiscing elit. Vivamus vitae eros non libero faucibus sagittis sed ut eros." + LayoutText {#text} at (12,-453) size 17x461 + text run at (12,-453) width 460 RTL override: "ipiscing elit. Vivamus vitae eros non libero faucibus sagittis sed ut eros."
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/css/vertical-text-overflow-ellipsis-text-align-justify-expected.txt b/third_party/WebKit/LayoutTests/platform/win/fast/css/vertical-text-overflow-ellipsis-text-align-justify-expected.txt index f842ac7..7aff13d3 100644 --- a/third_party/WebKit/LayoutTests/platform/win/fast/css/vertical-text-overflow-ellipsis-text-align-justify-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/fast/css/vertical-text-overflow-ellipsis-text-align-justify-expected.txt
@@ -52,42 +52,42 @@ LayoutImage {IMG} at (1,186.75) size 25x25 LayoutText {#text} at (12,211) size 17x556 text run at (12,211) width 555: " consectetur adipiscing elit. Vivamus vitae eros non libero faucibus sagittis sed ut eros." -layer at (8,1161) size 31x310 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 scrollHeight 761 +layer at (8,1161) size 31x310 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 scrollHeight 762 LayoutBlockFlow {DIV} at (0,1152.88) size 31x310 [border: (1px solid #000000)] LayoutText {#text} at (12,1) size 17x278 text run at (12,1) width 278: "Lorem ipsum dolor sit amet, consectetur ad" LayoutImage {IMG} at (1,278.70) size 25x25 LayoutText {#text} at (12,303) size 17x460 text run at (12,303) width 459: "ipiscing elit. Vivamus vitae eros non libero faucibus sagittis sed ut eros." -layer at (8,1532) size 20x310 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 scrollY 428.00 scrollHeight 736 +layer at (8,1532) size 20x310 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 scrollY 429.00 scrollHeight 737 LayoutBlockFlow {DIV} at (0,1523.59) size 20x310 [border: (1px solid #000000)] - LayoutText {#text} at (1,-427) size 17x737 - text run at (1,-427) width 737 RTL override: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vitae eros non libero faucibus sagittis sed ut eros." + LayoutText {#text} at (1,-428) size 17x738 + text run at (1,-428) width 738 RTL override: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vitae eros non libero faucibus sagittis sed ut eros." layer at (8,1902) size 74x310 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 LayoutBlockFlow {DIV} at (0,1894.31) size 74x310 [border: (1px solid #000000)] - LayoutText {#text} at (1,1) size 17x737 - text run at (1,1) width 737 RTL override: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vitae eros non libero faucibus sagittis sed ut eros." + LayoutText {#text} at (1,1) size 17x738 + text run at (1,1) width 738 RTL override: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vitae eros non libero faucibus sagittis sed ut eros." LayoutBR {BR} at (0,0) size 0x0 - LayoutText {#text} at (19,1) size 17x727 - text run at (19,1) width 727 RTL override: "orem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vitae eros non libero faucibus sagittis sed ut eros." + LayoutText {#text} at (19,1) size 17x728 + text run at (19,1) width 728 RTL override: "orem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vitae eros non libero faucibus sagittis sed ut eros." LayoutBR {BR} at (0,0) size 0x0 - LayoutText {#text} at (37,1) size 17x719 - text run at (37,1) width 719 RTL override: "rem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vitae eros non libero faucibus sagittis sed ut eros." + LayoutText {#text} at (37,1) size 17x720 + text run at (37,1) width 720 RTL override: "rem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vitae eros non libero faucibus sagittis sed ut eros." LayoutBR {BR} at (0,0) size 0x0 - LayoutText {#text} at (55,1) size 17x714 - text run at (55,1) width 714 RTL override: "em ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vitae eros non libero faucibus sagittis sed ut eros." + LayoutText {#text} at (55,1) size 17x715 + text run at (55,1) width 715 RTL override: "em ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vitae eros non libero faucibus sagittis sed ut eros." LayoutBR {BR} at (0,0) size 0x0 -layer at (8,2273) size 31x310 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 scrollY 457.00 scrollHeight 765 +layer at (8,2273) size 31x310 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 scrollY 458.00 scrollHeight 767 LayoutBlockFlow {DIV} at (0,2265.03) size 31x310 [border: (1px solid #000000)] LayoutText {#text} at (12,123) size 17x186 text run at (12,123) width 186 RTL override: "Lorem ipsum dolor sit amet, " LayoutImage {IMG} at (1,98.25) size 25x25 - LayoutText {#text} at (12,-456) size 17x556 - text run at (12,-456) width 555 RTL override: " consectetur adipiscing elit. Vivamus vitae eros non libero faucibus sagittis sed ut eros." -layer at (8,2644) size 31x310 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 scrollY 453.00 scrollHeight 761 + LayoutText {#text} at (12,-457) size 17x557 + text run at (12,-457) width 556 RTL override: " consectetur adipiscing elit. Vivamus vitae eros non libero faucibus sagittis sed ut eros." +layer at (8,2644) size 31x310 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 scrollY 454.00 scrollHeight 762 LayoutBlockFlow {DIV} at (0,2635.75) size 31x310 [border: (1px solid #000000)] LayoutText {#text} at (12,31) size 17x278 text run at (12,31) width 278 RTL override: "Lorem ipsum dolor sit amet, consectetur ad" LayoutImage {IMG} at (1,6.30) size 25x25 - LayoutText {#text} at (12,-452) size 17x460 - text run at (12,-452) width 459 RTL override: "ipiscing elit. Vivamus vitae eros non libero faucibus sagittis sed ut eros." + LayoutText {#text} at (12,-453) size 17x461 + text run at (12,-453) width 460 RTL override: "ipiscing elit. Vivamus vitae eros non libero faucibus sagittis sed ut eros."
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/css/vertical-text-overflow-ellipsis-text-align-left-expected.txt b/third_party/WebKit/LayoutTests/platform/win/fast/css/vertical-text-overflow-ellipsis-text-align-left-expected.txt index d797ae8a..f48e576f1 100644 --- a/third_party/WebKit/LayoutTests/platform/win/fast/css/vertical-text-overflow-ellipsis-text-align-left-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/fast/css/vertical-text-overflow-ellipsis-text-align-left-expected.txt
@@ -52,42 +52,42 @@ LayoutImage {IMG} at (1,186.75) size 25x25 LayoutText {#text} at (12,211) size 17x556 text run at (12,211) width 555: " consectetur adipiscing elit. Vivamus vitae eros non libero faucibus sagittis sed ut eros." -layer at (8,1161) size 31x310 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 scrollHeight 761 +layer at (8,1161) size 31x310 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 scrollHeight 762 LayoutBlockFlow {DIV} at (0,1152.88) size 31x310 [border: (1px solid #000000)] LayoutText {#text} at (12,1) size 17x278 text run at (12,1) width 278: "Lorem ipsum dolor sit amet, consectetur ad" LayoutImage {IMG} at (1,278.70) size 25x25 LayoutText {#text} at (12,303) size 17x460 text run at (12,303) width 459: "ipiscing elit. Vivamus vitae eros non libero faucibus sagittis sed ut eros." -layer at (8,1532) size 20x310 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 scrollY 428.00 scrollHeight 736 +layer at (8,1532) size 20x310 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 scrollY 431.00 scrollHeight 739 LayoutBlockFlow {DIV} at (0,1523.59) size 20x310 [border: (1px solid #000000)] - LayoutText {#text} at (1,-427) size 17x737 - text run at (1,-427) width 737 RTL override: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vitae eros non libero faucibus sagittis sed ut eros." -layer at (8,1902) size 74x310 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 scrollY 428.00 scrollHeight 737 + LayoutText {#text} at (1,-430) size 17x739 + text run at (1,-430) width 738 RTL override: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vitae eros non libero faucibus sagittis sed ut eros." +layer at (8,1902) size 74x310 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 scrollY 431.00 scrollHeight 740 LayoutBlockFlow {DIV} at (0,1894.31) size 74x310 [border: (1px solid #000000)] - LayoutText {#text} at (1,-427) size 17x737 - text run at (1,-427) width 737 RTL override: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vitae eros non libero faucibus sagittis sed ut eros." + LayoutText {#text} at (1,-430) size 17x739 + text run at (1,-430) width 738 RTL override: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vitae eros non libero faucibus sagittis sed ut eros." LayoutBR {BR} at (0,0) size 0x0 - LayoutText {#text} at (19,-418) size 17x728 - text run at (19,-418) width 727 RTL override: "orem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vitae eros non libero faucibus sagittis sed ut eros." + LayoutText {#text} at (19,-419) size 17x729 + text run at (19,-419) width 728 RTL override: "orem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vitae eros non libero faucibus sagittis sed ut eros." LayoutBR {BR} at (0,0) size 0x0 - LayoutText {#text} at (37,-409) size 17x719 - text run at (37,-409) width 719 RTL override: "rem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vitae eros non libero faucibus sagittis sed ut eros." + LayoutText {#text} at (37,-412) size 17x721 + text run at (37,-412) width 720 RTL override: "rem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vitae eros non libero faucibus sagittis sed ut eros." LayoutBR {BR} at (0,0) size 0x0 - LayoutText {#text} at (55,-407) size 17x714 - text run at (55,-407) width 714 RTL override: "em ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vitae eros non libero faucibus sagittis sed ut eros." + LayoutText {#text} at (55,-407) size 17x715 + text run at (55,-407) width 715 RTL override: "em ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vitae eros non libero faucibus sagittis sed ut eros." LayoutBR {BR} at (0,0) size 0x0 -layer at (8,2273) size 31x310 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 scrollY 457.00 scrollHeight 765 +layer at (8,2273) size 31x310 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 scrollY 458.00 scrollHeight 767 LayoutBlockFlow {DIV} at (0,2265.03) size 31x310 [border: (1px solid #000000)] LayoutText {#text} at (12,123) size 17x186 text run at (12,123) width 186 RTL override: "Lorem ipsum dolor sit amet, " LayoutImage {IMG} at (1,98.25) size 25x25 - LayoutText {#text} at (12,-456) size 17x556 - text run at (12,-456) width 555 RTL override: " consectetur adipiscing elit. Vivamus vitae eros non libero faucibus sagittis sed ut eros." -layer at (8,2644) size 31x310 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 scrollY 453.00 scrollHeight 761 + LayoutText {#text} at (12,-457) size 17x557 + text run at (12,-457) width 556 RTL override: " consectetur adipiscing elit. Vivamus vitae eros non libero faucibus sagittis sed ut eros." +layer at (8,2644) size 31x310 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 scrollY 454.00 scrollHeight 762 LayoutBlockFlow {DIV} at (0,2635.75) size 31x310 [border: (1px solid #000000)] LayoutText {#text} at (12,31) size 17x278 text run at (12,31) width 278 RTL override: "Lorem ipsum dolor sit amet, consectetur ad" LayoutImage {IMG} at (1,6.30) size 25x25 - LayoutText {#text} at (12,-452) size 17x460 - text run at (12,-452) width 459 RTL override: "ipiscing elit. Vivamus vitae eros non libero faucibus sagittis sed ut eros." + LayoutText {#text} at (12,-453) size 17x461 + text run at (12,-453) width 460 RTL override: "ipiscing elit. Vivamus vitae eros non libero faucibus sagittis sed ut eros."
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/css/vertical-text-overflow-ellipsis-text-align-right-expected.txt b/third_party/WebKit/LayoutTests/platform/win/fast/css/vertical-text-overflow-ellipsis-text-align-right-expected.txt index f1c99d4..eca3eef 100644 --- a/third_party/WebKit/LayoutTests/platform/win/fast/css/vertical-text-overflow-ellipsis-text-align-right-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/fast/css/vertical-text-overflow-ellipsis-text-align-right-expected.txt
@@ -50,44 +50,44 @@ LayoutText {#text} at (12,1) size 17x187 text run at (12,1) width 186: "Lorem ipsum dolor sit amet, " LayoutImage {IMG} at (1,187.16) size 25x25 - LayoutText {#text} at (12,212) size 17x555 + LayoutText {#text} at (12,212) size 17x556 text run at (12,212) width 555: " consectetur adipiscing elit. Vivamus vitae eros non libero faucibus sagittis sed ut eros." -layer at (8,1161) size 31x310 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 scrollHeight 761 +layer at (8,1161) size 31x310 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 scrollHeight 762 LayoutBlockFlow {DIV} at (0,1152.88) size 31x310 [border: (1px solid #000000)] LayoutText {#text} at (12,1) size 17x278 text run at (12,1) width 278: "Lorem ipsum dolor sit amet, consectetur ad" LayoutImage {IMG} at (1,278.70) size 25x25 LayoutText {#text} at (12,303) size 17x460 text run at (12,303) width 459: "ipiscing elit. Vivamus vitae eros non libero faucibus sagittis sed ut eros." -layer at (8,1532) size 20x310 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 scrollY 428.00 scrollHeight 736 +layer at (8,1532) size 20x310 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 scrollY 429.00 scrollHeight 737 LayoutBlockFlow {DIV} at (0,1523.59) size 20x310 [border: (1px solid #000000)] - LayoutText {#text} at (1,-427) size 17x737 - text run at (1,-427) width 737 RTL override: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vitae eros non libero faucibus sagittis sed ut eros." -layer at (8,1902) size 74x310 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 scrollY 428.00 scrollHeight 737 + LayoutText {#text} at (1,-428) size 17x738 + text run at (1,-428) width 738 RTL override: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vitae eros non libero faucibus sagittis sed ut eros." +layer at (8,1902) size 74x310 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 scrollY 429.00 scrollHeight 738 LayoutBlockFlow {DIV} at (0,1894.31) size 74x310 [border: (1px solid #000000)] - LayoutText {#text} at (1,-427) size 17x737 - text run at (1,-427) width 737 RTL override: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vitae eros non libero faucibus sagittis sed ut eros." + LayoutText {#text} at (1,-428) size 17x738 + text run at (1,-428) width 738 RTL override: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vitae eros non libero faucibus sagittis sed ut eros." LayoutBR {BR} at (0,0) size 0x0 - LayoutText {#text} at (19,-417) size 17x727 - text run at (19,-417) width 727 RTL override: "orem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vitae eros non libero faucibus sagittis sed ut eros." + LayoutText {#text} at (19,-418) size 17x728 + text run at (19,-418) width 728 RTL override: "orem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vitae eros non libero faucibus sagittis sed ut eros." LayoutBR {BR} at (0,0) size 0x0 - LayoutText {#text} at (37,-409) size 17x719 - text run at (37,-409) width 719 RTL override: "rem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vitae eros non libero faucibus sagittis sed ut eros." + LayoutText {#text} at (37,-410) size 17x720 + text run at (37,-410) width 720 RTL override: "rem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vitae eros non libero faucibus sagittis sed ut eros." LayoutBR {BR} at (0,0) size 0x0 - LayoutText {#text} at (55,-404) size 17x714 - text run at (55,-404) width 714 RTL override: "em ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vitae eros non libero faucibus sagittis sed ut eros." + LayoutText {#text} at (55,-405) size 17x715 + text run at (55,-405) width 715 RTL override: "em ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vitae eros non libero faucibus sagittis sed ut eros." LayoutBR {BR} at (0,0) size 0x0 -layer at (8,2273) size 31x310 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 scrollY 457.00 scrollHeight 765 +layer at (8,2273) size 31x310 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 scrollY 458.00 scrollHeight 767 LayoutBlockFlow {DIV} at (0,2265.03) size 31x310 [border: (1px solid #000000)] LayoutText {#text} at (12,123) size 17x186 text run at (12,123) width 186 RTL override: "Lorem ipsum dolor sit amet, " LayoutImage {IMG} at (1,98.25) size 25x25 - LayoutText {#text} at (12,-456) size 17x556 - text run at (12,-456) width 555 RTL override: " consectetur adipiscing elit. Vivamus vitae eros non libero faucibus sagittis sed ut eros." -layer at (8,2644) size 31x310 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 scrollY 453.00 scrollHeight 761 + LayoutText {#text} at (12,-457) size 17x557 + text run at (12,-457) width 556 RTL override: " consectetur adipiscing elit. Vivamus vitae eros non libero faucibus sagittis sed ut eros." +layer at (8,2644) size 31x310 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 scrollY 454.00 scrollHeight 762 LayoutBlockFlow {DIV} at (0,2635.75) size 31x310 [border: (1px solid #000000)] LayoutText {#text} at (12,31) size 17x278 text run at (12,31) width 278 RTL override: "Lorem ipsum dolor sit amet, consectetur ad" LayoutImage {IMG} at (1,6.30) size 25x25 - LayoutText {#text} at (12,-452) size 17x460 - text run at (12,-452) width 459 RTL override: "ipiscing elit. Vivamus vitae eros non libero faucibus sagittis sed ut eros." + LayoutText {#text} at (12,-453) size 17x461 + text run at (12,-453) width 460 RTL override: "ipiscing elit. Vivamus vitae eros non libero faucibus sagittis sed ut eros."
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/images/color-profile-munsell-adobe-to-srgb-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/images/color-profile-munsell-adobe-to-srgb-expected.png new file mode 100644 index 0000000..84238156 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/win/fast/images/color-profile-munsell-adobe-to-srgb-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/images/color-profile-munsell-adobe-to-srgb-expected.txt b/third_party/WebKit/LayoutTests/platform/win/fast/images/color-profile-munsell-adobe-to-srgb-expected.txt new file mode 100644 index 0000000..d113221 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/win/fast/images/color-profile-munsell-adobe-to-srgb-expected.txt
@@ -0,0 +1,42 @@ + +Color Actual Expected dE +-------------------------------------------- +Dark Skin 115,80,64 115,80,64 0 +Light Skin 195,150,130 195,151,130 1 +Blue Sky 94,123,157 94,123,156 1 +Foliage 89,108,65 88,108,65 1 +Blue Flower 130,129,177 130,129,177 0 +Bluish Green 100,190,171 100,190,171 0 +-------------------------------------------- +Orange 216,122,37 217,122,37 1 +Purplish Blue 72,91,166 72,91,165 1 +Moderate Red 194,84,97 194,84,98 1 +Purple 91,60,107 91,59,107 1 +Yellow Green 160,187,60 160,188,60 1 +Orange Yellow 230,164,42 230,163,42 1 +-------------------------------------------- +Blue 47,60,153 46,60,153 1 +Green 70,149,69 71,150,69 1 +Red 177,44,56 177,44,56 0 +Yellow 239,200,27 238,200,27 1 +Magenta 187,82,147 187,82,148 1 +Cyan (*) 0,135,166 0,135,166 0 +-------------------------------------------- +White 243,241,236 243,242,237 1 +Neutral 8 201,201,200 201,201,201 1 +Neutral 6.5 160,161,160 161,161,161 1 +Neutral 5 123,122,121 122,122,121 1 +Neutral 3.5 83,83,83 83,83,83 0 +Black 50,50,50 50,49,50 1 +-------------------------------------------- + +Result: total RMS color error: 0.87 + * Munsell Cyan is outside 255 sRGB gamut + + + + + + + +
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/lists/003-vertical-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/lists/003-vertical-expected.png index 5ddb46b..41645c9c 100644 --- a/third_party/WebKit/LayoutTests/platform/win/fast/lists/003-vertical-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/fast/lists/003-vertical-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/lists/003-vertical-expected.txt b/third_party/WebKit/LayoutTests/platform/win/fast/lists/003-vertical-expected.txt index 9ff4e6f..2e3de0e1 100644 --- a/third_party/WebKit/LayoutTests/platform/win/fast/lists/003-vertical-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/fast/lists/003-vertical-expected.txt
@@ -177,14 +177,14 @@ LayoutBlockFlow {UL} at (194,0) size 108x584 LayoutListItem {LI} at (0,40) size 18x544 LayoutListMarker (anonymous) at (0,293.39) size 17x7: bullet - LayoutInline {A} at (0,0) size 17x91 [color=#0000EE] - LayoutText {#text} at (0,453) size 17x91 - text run at (0,453) width 91: "RSS Validator" + LayoutInline {A} at (0,0) size 17x92 [color=#0000EE] + LayoutText {#text} at (0,452) size 17x92 + text run at (0,452) width 92: "RSS Validator" LayoutListItem {LI} at (18,40) size 18x544 LayoutListMarker (anonymous) at (0,293.39) size 17x7: bullet - LayoutInline {A} at (0,0) size 17x148 [color=#0000EE] - LayoutText {#text} at (0,396) size 17x148 - text run at (0,396) width 148: "Dive Into Accessibility" + LayoutInline {A} at (0,0) size 17x149 [color=#0000EE] + LayoutText {#text} at (0,395) size 17x149 + text run at (0,395) width 149: "Dive Into Accessibility" LayoutListItem {LI} at (36,40) size 18x544 LayoutListMarker (anonymous) at (0,293.39) size 17x7: bullet LayoutInline {A} at (0,0) size 17x101 [color=#0000EE]
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/repaint/bugzilla-6278-expected.txt b/third_party/WebKit/LayoutTests/platform/win/fast/repaint/bugzilla-6278-expected.txt index 195ea58e..6915b1b 100644 --- a/third_party/WebKit/LayoutTests/platform/win/fast/repaint/bugzilla-6278-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/fast/repaint/bugzilla-6278-expected.txt
@@ -10,12 +10,12 @@ [254, 132, 52, 235], [252, 132, 50, 199], [252, 132, 50, 199], - [251, 132, 35, 144], + [250, 132, 36, 144], [10, 331, 242, 36], [10, 317, 242, 50], [10, 281, 292, 50], [9, 331, 243, 36], - [9, 276, 242, 36], + [9, 276, 241, 36], [9, 132, 293, 144], [9, 132, 243, 180] ],
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/repaint/inline-style-change-in-scrolled-view-expected.txt b/third_party/WebKit/LayoutTests/platform/win/fast/repaint/inline-style-change-in-scrolled-view-expected.txt index 10f53e1..f6e8d04 100644 --- a/third_party/WebKit/LayoutTests/platform/win/fast/repaint/inline-style-change-in-scrolled-view-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/fast/repaint/inline-style-change-in-scrolled-view-expected.txt
@@ -6,7 +6,7 @@ "contentsOpaque": true, "drawsContent": true, "repaintRects": [ - [0, 288, 416, 17] + [0, 288, 415, 17] ], "paintInvalidationClients": [ "LayoutText #text",
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/repaint/layout-state-scrolloffset-expected.txt b/third_party/WebKit/LayoutTests/platform/win/fast/repaint/layout-state-scrolloffset-expected.txt index e870dbc..f41f0e4 100644 --- a/third_party/WebKit/LayoutTests/platform/win/fast/repaint/layout-state-scrolloffset-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/fast/repaint/layout-state-scrolloffset-expected.txt
@@ -6,16 +6,14 @@ "contentsOpaque": true, "drawsContent": true, "repaintRects": [ - [100, 118, 50, 50], - [100, 118, 31, 17], - [99, 118, 51, 50], - [99, 118, 42, 17] + [100, 118, 50, 17], + [100, 118, 41, 17], + [100, 118, 30, 17] ], "paintInvalidationClients": [ "InlineTextBox ''", "RootInlineBox", "LayoutBlockFlow DIV id='target'", - "RootInlineBox", "LayoutText #text", "InlineTextBox 'after'" ]
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/repaint/layout-state-scrolloffset2-expected.txt b/third_party/WebKit/LayoutTests/platform/win/fast/repaint/layout-state-scrolloffset2-expected.txt index dbb98747..d4fd759 100644 --- a/third_party/WebKit/LayoutTests/platform/win/fast/repaint/layout-state-scrolloffset2-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/fast/repaint/layout-state-scrolloffset2-expected.txt
@@ -6,16 +6,14 @@ "contentsOpaque": true, "drawsContent": true, "repaintRects": [ - [102, 120, 50, 50], - [102, 120, 31, 17], - [101, 120, 51, 50], - [101, 120, 42, 17] + [102, 120, 50, 17], + [102, 120, 41, 17], + [102, 120, 30, 17] ], "paintInvalidationClients": [ "InlineTextBox ''", "RootInlineBox", "LayoutBlockFlow DIV id='target'", - "RootInlineBox", "LayoutText #text", "InlineTextBox 'after'" ]
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/repaint/layout-state-scrolloffset3-expected.txt b/third_party/WebKit/LayoutTests/platform/win/fast/repaint/layout-state-scrolloffset3-expected.txt index e42c12d..137d1bf 100644 --- a/third_party/WebKit/LayoutTests/platform/win/fast/repaint/layout-state-scrolloffset3-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/fast/repaint/layout-state-scrolloffset3-expected.txt
@@ -6,16 +6,14 @@ "contentsOpaque": true, "drawsContent": true, "repaintRects": [ - [100, 118, 35, 50], - [100, 118, 31, 17], - [99, 118, 36, 50], - [99, 118, 36, 17] + [100, 118, 35, 17], + [100, 118, 35, 17], + [100, 118, 30, 17] ], "paintInvalidationClients": [ "InlineTextBox ''", "RootInlineBox", "LayoutBlockFlow DIV id='target'", - "RootInlineBox", "LayoutText #text", "InlineTextBox 'after'" ]
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/repaint/line-flow-with-floats-1-expected.txt b/third_party/WebKit/LayoutTests/platform/win/fast/repaint/line-flow-with-floats-1-expected.txt index 7034ebb4..13ef3c2 100644 --- a/third_party/WebKit/LayoutTests/platform/win/fast/repaint/line-flow-with-floats-1-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/fast/repaint/line-flow-with-floats-1-expected.txt
@@ -7,9 +7,8 @@ "drawsContent": true, "repaintRects": [ [378, 138, 70, 30], - [369, 422, 1, 53], - [369, 80, 51, 108], - [305, 170, 41, 17], + [368, 80, 52, 108], + [305, 170, 40, 17], [301, 404, 67, 18], [178, 350, 146, 18], [65, 386, 303, 36], @@ -18,11 +17,11 @@ [14, 386, 354, 36], [14, 353, 48, 65], [14, 335, 48, 65], + [14, 242, 406, 126], [14, 224, 406, 126], - [14, 188, 41, 17], - [14, 170, 408, 72], - [13, 242, 407, 126], - [13, 188, 408, 71], + [14, 188, 40, 17], + [14, 170, 407, 72], + [13, 188, 407, 71], [8, 116, 418, 450] ], "paintInvalidationClients": [ @@ -140,13 +139,7 @@ "InlineTextBox 'for the hedgehogs; and in\n'", "InlineTextBox 'a very short time '", "LayoutText #text", - "InlineTextBox 'the Queen'", - "LayoutText #text", - "InlineTextBox 'was in a furious passion, and went\n'", - "InlineTextBox 'stamping about, and'", - "InlineTextBox 'shouting \u2018Off with his head!\u2019 or \u2018Off with\n'", - "InlineTextBox 'her head!\u2019'", - "InlineTextBox 'about once in a minute.\n'" + "InlineTextBox 'the Queen'" ] } ]
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/repaint/line-flow-with-floats-2-expected.txt b/third_party/WebKit/LayoutTests/platform/win/fast/repaint/line-flow-with-floats-2-expected.txt index f13d66b5a..2348718 100644 --- a/third_party/WebKit/LayoutTests/platform/win/fast/repaint/line-flow-with-floats-2-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/fast/repaint/line-flow-with-floats-2-expected.txt
@@ -14,20 +14,20 @@ [65, 386, 303, 36], [65, 371, 304, 18], [65, 368, 304, 18], + [14, 479, 406, 90], + [14, 476, 406, 90], [14, 425, 355, 53], [14, 422, 355, 53], [14, 407, 355, 36], [14, 404, 355, 36], [14, 356, 48, 65], [14, 353, 48, 65], + [14, 245, 406, 126], + [14, 242, 406, 126], [14, 188, 45, 20], - [14, 188, 41, 17], - [13, 479, 408, 90], - [13, 476, 408, 90], - [13, 245, 407, 126], - [13, 242, 407, 126], - [13, 190, 408, 72], - [13, 188, 408, 71], + [14, 188, 40, 17], + [13, 190, 407, 72], + [13, 188, 407, 71], [8, 572, 418, 3], [8, 569, 418, 6], [8, 170, 418, 399]
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/repaint/line-flow-with-floats-3-expected.txt b/third_party/WebKit/LayoutTests/platform/win/fast/repaint/line-flow-with-floats-3-expected.txt index ed2e469f..91031ca 100644 --- a/third_party/WebKit/LayoutTests/platform/win/fast/repaint/line-flow-with-floats-3-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/fast/repaint/line-flow-with-floats-3-expected.txt
@@ -9,9 +9,9 @@ [372, 371, 48, 81], [369, 368, 32, 18], [356, 389, 64, 81], - [354, 422, 15, 53], + [353, 422, 16, 53], [65, 386, 303, 36], - [65, 368, 356, 54], + [65, 368, 355, 54], [14, 422, 72, 18], [14, 404, 355, 36], [8, 368, 418, 198]
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/repaint/line-flow-with-floats-4-expected.txt b/third_party/WebKit/LayoutTests/platform/win/fast/repaint/line-flow-with-floats-4-expected.txt index 1af78851..fca2f9f 100644 --- a/third_party/WebKit/LayoutTests/platform/win/fast/repaint/line-flow-with-floats-4-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/fast/repaint/line-flow-with-floats-4-expected.txt
@@ -7,7 +7,7 @@ "drawsContent": true, "repaintRects": [ [372, 435, 48, 17], - [369, 422, 52, 53], + [369, 422, 51, 53], [8, 368, 418, 198] ], "paintInvalidationClients": [
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/repaint/line-flow-with-floats-5-expected.txt b/third_party/WebKit/LayoutTests/platform/win/fast/repaint/line-flow-with-floats-5-expected.txt index 44fe33f6..5f9fed5 100644 --- a/third_party/WebKit/LayoutTests/platform/win/fast/repaint/line-flow-with-floats-5-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/fast/repaint/line-flow-with-floats-5-expected.txt
@@ -10,7 +10,7 @@ [162, 350, 146, 18], [65, 386, 303, 36], [65, 368, 304, 18], - [49, 368, 321, 54], + [49, 368, 320, 54], [49, 368, 301, 18], [46, 353, 16, 65], [8, 332, 418, 234]
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/repaint/line-flow-with-floats-9-expected.txt b/third_party/WebKit/LayoutTests/platform/win/fast/repaint/line-flow-with-floats-9-expected.txt index 91d85d1..939205b 100644 --- a/third_party/WebKit/LayoutTests/platform/win/fast/repaint/line-flow-with-floats-9-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/fast/repaint/line-flow-with-floats-9-expected.txt
@@ -17,14 +17,12 @@ [65, 386, 303, 36], [65, 368, 304, 18], [65, 368, 145, 18], - [14, 440, 356, 53], + [14, 494, 406, 90], + [14, 476, 406, 90], + [14, 440, 355, 53], [14, 422, 355, 53], [14, 404, 355, 36], [14, 404, 354, 36], - [14, 242, 406, 126], - [13, 494, 408, 90], - [13, 476, 408, 90], - [13, 242, 407, 126], [8, 572, 418, 18], [8, 569, 418, 21], [0, 0, 500, 600], @@ -117,19 +115,6 @@ "RootInlineBox", "LayoutBlockFlow (floating) SPAN id='yellowFloat'", "LayoutText #text", - "InlineTextBox 'begin again, it was very provoking to find that the'", - "InlineTextBox 'hedgehog had\n'", - "InlineTextBox 'unrolled itself, and was in the act of'", - "InlineTextBox 'crawling away: besides all\n'", - "InlineTextBox 'this, there was generally a'", - "InlineTextBox 'ridge or furrow in the way wherever\n'", - "InlineTextBox 'she wanted to'", - "InlineTextBox 'send the hedgehog to, and, as the doubled-up\n'", - "InlineTextBox 'soldiers were'", - "InlineTextBox 'always getting up and walking off to other parts of\n'", - "InlineTextBox 'the ground,'", - "InlineTextBox 'Alice soon came to the conclusion that it was a very'", - "LayoutText #text", "InlineTextBox 'difficult game indeed.\n'", "LayoutText #text", "InlineTextBox 'The players all played at once without waiting'",
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/repaint/line-overflow-expected.txt b/third_party/WebKit/LayoutTests/platform/win/fast/repaint/line-overflow-expected.txt index f780fdf..3709b89 100644 --- a/third_party/WebKit/LayoutTests/platform/win/fast/repaint/line-overflow-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/fast/repaint/line-overflow-expected.txt
@@ -6,15 +6,15 @@ "contentsOpaque": true, "drawsContent": true, "repaintRects": [ - [114, 114, 38, 18], - [114, 84, 38, 48], + [115, 114, 37, 18], + [115, 84, 37, 48], [37, 132, 37, 18], [37, 132, 37, 18], [8, 132, 192, 71], [8, 78, 200, 200], [8, 16, 784, 262], - [7, 114, 202, 89], - [7, 78, 202, 200], + [7, 114, 201, 89], + [7, 78, 201, 200], [7, 16, 785, 262] ], "paintInvalidationClients": [
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/repaint/make-children-non-inline-expected.txt b/third_party/WebKit/LayoutTests/platform/win/fast/repaint/make-children-non-inline-expected.txt index 24a90f1..39054a27 100644 --- a/third_party/WebKit/LayoutTests/platform/win/fast/repaint/make-children-non-inline-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/fast/repaint/make-children-non-inline-expected.txt
@@ -7,17 +7,17 @@ "drawsContent": true, "repaintRects": [ [8, 304, 64, 17], - [8, 286, 31, 17], + [8, 286, 30, 17], [8, 268, 69, 17], [8, 250, 784, 72], - [8, 250, 115, 17], + [8, 250, 114, 17], [8, 204, 64, 17], - [8, 186, 31, 17], + [8, 186, 30, 17], [8, 168, 69, 17], - [8, 150, 115, 17], + [8, 150, 114, 17], [8, 150, 10, 100], [8, 132, 81, 17], - [8, 114, 46, 17], + [8, 114, 45, 17], [8, 96, 80, 17], [8, 78, 44, 17], [8, 60, 784, 262],
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/repaint/overflow-scroll-delete-expected.txt b/third_party/WebKit/LayoutTests/platform/win/fast/repaint/overflow-scroll-delete-expected.txt deleted file mode 100644 index 5fc364b..0000000 --- a/third_party/WebKit/LayoutTests/platform/win/fast/repaint/overflow-scroll-delete-expected.txt +++ /dev/null
@@ -1,26 +0,0 @@ -{ - "bounds": [800, 600], - "children": [ - { - "bounds": [800, 600], - "contentsOpaque": true, - "drawsContent": true, - "repaintRects": [ - [8, 112, 80, 35], - [8, 112, 45, 35], - [8, 112, 41, 35] - ], - "paintInvalidationClients": [ - "InlineTextBox ''", - "RootInlineBox", - "InlineTextBox ''", - "RootInlineBox", - "LayoutBlockFlow DIV id='t'", - "LayoutText #text", - "InlineTextBox 'Passed'", - "InlineTextBox 'Test'" - ] - } - ] -} -
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/repaint/remove-block-after-layout-expected.txt b/third_party/WebKit/LayoutTests/platform/win/fast/repaint/remove-block-after-layout-expected.txt deleted file mode 100644 index fb6e072..0000000 --- a/third_party/WebKit/LayoutTests/platform/win/fast/repaint/remove-block-after-layout-expected.txt +++ /dev/null
@@ -1,23 +0,0 @@ -{ - "bounds": [800, 600], - "children": [ - { - "bounds": [800, 600], - "contentsOpaque": true, - "drawsContent": true, - "repaintRects": [ - [8, 108, 101, 100], - [8, 108, 101, 36] - ], - "paintInvalidationClients": [ - "InlineTextBox 'This div should'", - "InlineTextBox 'disappear.'", - "LayoutText #text", - "RootInlineBox", - "RootInlineBox", - "LayoutBlockFlow (positioned) DIV id='target'" - ] - } - ] -} -
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/repaint/selection-after-remove-expected.txt b/third_party/WebKit/LayoutTests/platform/win/fast/repaint/selection-after-remove-expected.txt index e925e1ce..4df7064c 100644 --- a/third_party/WebKit/LayoutTests/platform/win/fast/repaint/selection-after-remove-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/fast/repaint/selection-after-remove-expected.txt
@@ -6,8 +6,8 @@ "contentsOpaque": true, "drawsContent": true, "repaintRects": [ - [112, 165, 43, 17], - [74, 75, 40, 17], + [112, 165, 42, 17], + [74, 75, 39, 17], [39, 75, 119, 107], [39, 75, 36, 17], [38, 94, 152, 90],
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/repaint/selection-clear-expected.txt b/third_party/WebKit/LayoutTests/platform/win/fast/repaint/selection-clear-expected.txt index a9d8dca..f3504d7c 100644 --- a/third_party/WebKit/LayoutTests/platform/win/fast/repaint/selection-clear-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/fast/repaint/selection-clear-expected.txt
@@ -8,7 +8,7 @@ "repaintRects": [ [8, 208, 100, 100], [8, 108, 100, 100], - [8, 49, 95, 117], + [8, 49, 94, 117], [8, 49, 4, 17], [8, 8, 100, 200], [8, 8, 100, 100]
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/repaint/table-collapsed-border-expected.txt b/third_party/WebKit/LayoutTests/platform/win/fast/repaint/table-collapsed-border-expected.txt index ba3b64b..a968781 100644 --- a/third_party/WebKit/LayoutTests/platform/win/fast/repaint/table-collapsed-border-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/fast/repaint/table-collapsed-border-expected.txt
@@ -8,9 +8,9 @@ "repaintRects": [ [83, 268, 26, 76], [79, 268, 30, 76], - [23, 297, 78, 18], - [23, 211, 35, 17], - [23, 125, 78, 18], + [23, 297, 77, 18], + [23, 211, 34, 17], + [23, 125, 77, 18], [22, 316, 87, 28], [22, 316, 61, 28], [22, 296, 87, 20],
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/text/atsui-spacing-features-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/text/atsui-spacing-features-expected.png index 9cba3dc..087c2843 100644 --- a/third_party/WebKit/LayoutTests/platform/win/fast/text/atsui-spacing-features-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/fast/text/atsui-spacing-features-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/text/atsui-spacing-features-expected.txt b/third_party/WebKit/LayoutTests/platform/win/fast/text/atsui-spacing-features-expected.txt index 6dc63832..13ed13fc 100644 --- a/third_party/WebKit/LayoutTests/platform/win/fast/text/atsui-spacing-features-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/fast/text/atsui-spacing-features-expected.txt
@@ -4,17 +4,17 @@ LayoutBlockFlow {HTML} at (0,0) size 800x354 LayoutBlockFlow {BODY} at (8,16) size 784x330 LayoutBlockFlow {P} at (0,0) size 784x36 - LayoutText {#text} at (0,0) size 180x17 - text run at (0,0) width 180: "Test for regressions against " - LayoutInline {I} at (0,0) size 776x35 + LayoutText {#text} at (0,0) size 179x17 + text run at (0,0) width 179: "Test for regressions against " + LayoutInline {I} at (0,0) size 772x35 LayoutInline {A} at (0,0) size 354x17 [color=#0000EE] - LayoutText {#text} at (179,0) size 354x17 - text run at (179,0) width 354: "http://bugzilla.opendarwin.org/show_bug.cgi?id=3922" - LayoutText {#text} at (532,0) size 776x35 - text run at (532,0) width 244: " Variable word/letter spacing and full" - text run at (0,18) width 330: "justification not supported for ATSUI-rendered text" - LayoutText {#text} at (329,18) size 5x17 - text run at (329,18) width 5: "." + LayoutText {#text} at (178,0) size 354x17 + text run at (178,0) width 354: "http://bugzilla.opendarwin.org/show_bug.cgi?id=3922" + LayoutText {#text} at (531,0) size 772x35 + text run at (531,0) width 241: " Variable word/letter spacing and full" + text run at (0,18) width 328: "justification not supported for ATSUI-rendered text" + LayoutText {#text} at (327,18) size 5x17 + text run at (327,18) width 5: "." LayoutBlockFlow (anonymous) at (0,52) size 784x18 LayoutText {#text} at (0,0) size 517x17 text run at (0,0) width 517: "Each green box should be identical to the blue box it follows, except for accents." @@ -23,8 +23,8 @@ LayoutTableSection {TBODY} at (0,0) size 620x242 LayoutTableRow {TR} at (0,2) size 620x20 LayoutTableCell {TD} at (2,2) size 204x20 [r=0 c=0 rs=1 cs=1] - LayoutText {#text} at (57,1) size 90x17 - text run at (57,1) width 90: "Word spacing" + LayoutText {#text} at (57,1) size 89x17 + text run at (57,1) width 89: "Word spacing" LayoutTableCell {TD} at (208,2) size 204x20 [r=0 c=1 rs=1 cs=1] LayoutText {#text} at (56,1) size 92x17 text run at (56,1) width 92: "Letter spacing"
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/text/drawBidiText-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/text/drawBidiText-expected.png index c1d1aac0..32ca61aa 100644 --- a/third_party/WebKit/LayoutTests/platform/win/fast/text/drawBidiText-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/fast/text/drawBidiText-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/text/drawBidiText-expected.txt b/third_party/WebKit/LayoutTests/platform/win/fast/text/drawBidiText-expected.txt index 059fe60..ec8781f 100644 --- a/third_party/WebKit/LayoutTests/platform/win/fast/text/drawBidiText-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/fast/text/drawBidiText-expected.txt
@@ -4,51 +4,51 @@ LayoutBlockFlow {HTML} at (0,0) size 800x600 LayoutBlockFlow {BODY} at (8,8) size 784x584 LayoutBlockFlow {P} at (0,0) size 784x18 - LayoutText {#text} at (0,0) size 286x17 - text run at (0,0) width 286: "This tests GraphicsContext::drawBidiText()." + LayoutText {#text} at (0,0) size 285x17 + text run at (0,0) width 285: "This tests GraphicsContext::drawBidiText()." layer at (8,42) size 322x205 clip at (9,43) size 305x203 - LayoutListBox {SELECT} at (0,34) size 322.36x205.34 [bgcolor=#FFFFFF] [border: (1px solid #A9A9A9)] - LayoutBlockFlow {OPTION} at (1,1) size 305.36x22.59 + LayoutListBox {SELECT} at (0,34) size 322.03x205.34 [bgcolor=#FFFFFF] [border: (1px solid #A9A9A9)] + LayoutBlockFlow {OPTION} at (1,1) size 305.03x22.59 LayoutText {#text} at (2,0) size 199x20 text run at (2,0) width 40: "First " text run at (41,0) width 61 RTL: ") \x{5E8}\x{5D1}\x{5D9}\x{5E2}\x{5D9}\x{5EA}" text run at (101,0) width 21: "03" text run at (121,0) width 46 RTL: "\x{5E9}\x{5E0}\x{5D9}\x{5D4} (" text run at (166,0) width 35: " fifth" - LayoutBlockFlow {OPTION} at (1,23.59) size 305.36x22.59 + LayoutBlockFlow {OPTION} at (1,23.59) size 305.03x22.59 LayoutText {#text} at (104,0) size 200x20 text run at (104,0) width 30: "fifth" - text run at (133,0) width 66 RTL: ") \x{5E8}\x{5D1}\x{5D9}\x{5E2}\x{5D9}\x{5EA} " - text run at (198,0) width 21: "03" - text run at (218,0) width 51 RTL: " \x{5E9}\x{5E0}\x{5D9}\x{5D4} (" + text run at (133,0) width 65 RTL: ") \x{5E8}\x{5D1}\x{5D9}\x{5E2}\x{5D9}\x{5EA} " + text run at (197,0) width 21: "03" + text run at (217,0) width 52 RTL: " \x{5E9}\x{5E0}\x{5D9}\x{5D4} (" text run at (268,0) width 36: "First" - LayoutBlockFlow {OPTION} at (1,46.19) size 305.36x22.59 + LayoutBlockFlow {OPTION} at (1,46.19) size 305.03x22.59 LayoutText {#text} at (2,0) size 200x20 text run at (2,0) width 200 LTR override: "First \x{5E9}\x{5E0}\x{5D9}\x{5D4} (03) \x{5E8}\x{5D1}\x{5D9}\x{5E2}\x{5D9}\x{5EA} fifth" - LayoutBlockFlow {OPTION} at (1,68.78) size 305.36x22.59 + LayoutBlockFlow {OPTION} at (1,68.78) size 305.03x22.59 LayoutText {#text} at (104,0) size 200x20 text run at (104,0) width 200 RTL override: "First \x{5E9}\x{5E0}\x{5D9}\x{5D4} (03) \x{5E8}\x{5D1}\x{5D9}\x{5E2}\x{5D9}\x{5EA} fifth" - LayoutBlockFlow {OPTION} at (1,91.38) size 305.36x22.59 + LayoutBlockFlow {OPTION} at (1,91.38) size 305.03x22.59 LayoutText {#text} at (2,0) size 100x20 text run at (2,0) width 100 RTL: "\x{5DE}\x{5E9}\x{5D4}\x{5D5} \x{5E2}\x{5DD} \x{5E0}\x{5B4}\x{5E7}\x{5BC}\x{5D5}\x{5BC}\x{5D3}" - LayoutBlockFlow {OPTION} at (1,113.97) size 305.36x22.59 - LayoutText {#text} at (2,0) size 69x20 - text run at (2,0) width 69 RTL: "\x{627}\x{644}\x{644}\x{63A}\x{629} \x{627}\x{644}\x{639}\x{631}\x{628}\x{64A}\x{629}" - LayoutBlockFlow {OPTION} at (1,136.56) size 305.36x22.59 + LayoutBlockFlow {OPTION} at (1,113.97) size 305.03x22.59 + LayoutText {#text} at (2,0) size 78x20 + text run at (2,0) width 78 RTL: "\x{627}\x{644}\x{644}\x{63A}\x{629} \x{627}\x{644}\x{639}\x{631}\x{628}\x{64A}\x{629}" + LayoutBlockFlow {OPTION} at (1,136.56) size 305.03x22.59 LayoutText {#text} at (2,0) size 126x20 text run at (2,0) width 126: "Et volia\x{300}: ATSUI!" - LayoutBlockFlow {OPTION} at (1,159.16) size 305.36x22.59 + LayoutBlockFlow {OPTION} at (1,159.16) size 305.03x22.59 LayoutText {#text} at (2,0) size 283x20 text run at (2,0) width 91: "Directional " text run at (92,0) width 75 RTL override: "\x{202E}overrides" text run at (166,0) width 119: "\x{202C} are confusing." - LayoutBlockFlow {OPTION} at (1,181.75) size 305.36x22.59 - LayoutText {#text} at (2,0) size 302x20 + LayoutBlockFlow {OPTION} at (1,181.75) size 305.03x22.59 + LayoutText {#text} at (2,0) size 301x20 text run at (2,0) width 82: "She said \x{201C}" text run at (83,0) width 67 RTL: " \x{5D1}\x{5DE}\x{5D6}\x{5D5}\x{5D5}\x{5D3}\x{5D4}!" text run at (149,0) width 36: "TNT" text run at (184,0) width 23 RTL: "\x{202B}\x{5D9}\x{5E9} " - text run at (206,0) width 98: "\x{202C}\x{201D} and ran off" + text run at (206,0) width 97: "\x{202C}\x{201D} and ran off" layer at (8,247) size 366x18 clip at (9,248) size 349x16 LayoutListBox {SELECT} at (0,239.34) size 366x18 [bgcolor=#FFFFFF] [border: (1px solid #A9A9A9)] LayoutBlockFlow {OPTION} at (1,1) size 349x15.39
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/text/justify-ideograph-complex-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/text/justify-ideograph-complex-expected.png index fc4e226..81d7a070 100644 --- a/third_party/WebKit/LayoutTests/platform/win/fast/text/justify-ideograph-complex-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/fast/text/justify-ideograph-complex-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/writing-mode/vertical-lr-replaced-selection-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/writing-mode/vertical-lr-replaced-selection-expected.png index e63e914c..611bebb8 100644 --- a/third_party/WebKit/LayoutTests/platform/win/fast/writing-mode/vertical-lr-replaced-selection-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/fast/writing-mode/vertical-lr-replaced-selection-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/writing-mode/vertical-lr-replaced-selection-expected.txt b/third_party/WebKit/LayoutTests/platform/win/fast/writing-mode/vertical-lr-replaced-selection-expected.txt index e7982a6..493c448 100644 --- a/third_party/WebKit/LayoutTests/platform/win/fast/writing-mode/vertical-lr-replaced-selection-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/fast/writing-mode/vertical-lr-replaced-selection-expected.txt
@@ -9,7 +9,7 @@ LayoutImage {IMG} at (50,0) size 50x20 [bgcolor=#008000] LayoutText {#text} at (42,20) size 40x379 text run at (42,20) width 379: " This is the second line of " - LayoutImage {IMG} at (50,398.28) size 100x20 [bgcolor=#800080] + LayoutImage {IMG} at (50,398.92) size 100x20 [bgcolor=#800080] LayoutText {#text} at (42,418) size 40x73 text run at (42,418) width 72: " text." selection start: position 1 of child 0 {#text} of body
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/batik/filters/feTile-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/batik/filters/feTile-expected.png index 7c72384..2f8c6cb 100644 --- a/third_party/WebKit/LayoutTests/platform/win/svg/batik/filters/feTile-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/svg/batik/filters/feTile-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/display_list_2d_canvas/fast/canvas/canvas-shadow-source-in-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/display_list_2d_canvas/fast/canvas/canvas-shadow-source-in-expected.png index cb58a88..647e06c0 100644 --- a/third_party/WebKit/LayoutTests/platform/win/virtual/display_list_2d_canvas/fast/canvas/canvas-shadow-source-in-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/virtual/display_list_2d_canvas/fast/canvas/canvas-shadow-source-in-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/compositing/color-matching/image-color-matching-expected.txt b/third_party/WebKit/LayoutTests/platform/win7/compositing/color-matching/image-color-matching-expected.txt deleted file mode 100644 index 3e72c0c..0000000 --- a/third_party/WebKit/LayoutTests/platform/win7/compositing/color-matching/image-color-matching-expected.txt +++ /dev/null
@@ -1,22 +0,0 @@ -layer at (0,0) size 1600x1200 - LayoutView at (0,0) size 1600x1200 -layer at (0,0) size 1600x546 - LayoutBlockFlow {HTML} at (0,0) size 1600x546 - LayoutBlockFlow {BODY} at (8,16) size 1584x522 [color=#FFFFFF] [bgcolor=#000000] - LayoutBlockFlow {P} at (0,0) size 1584x18 - LayoutText {#text} at (0,0) size 210x17 - text run at (0,0) width 210: "Images should all look the same." - LayoutBlockFlow {DIV} at (0,34) size 1584x244 - LayoutImage {IMG} at (0,0) size 360x240 - LayoutText {#text} at (360,226) size 4x17 - text run at (360,226) width 4: " " - LayoutImage {IMG} at (364,0) size 360x240 - LayoutText {#text} at (0,0) size 0x0 - LayoutBlockFlow {DIV} at (0,278) size 1584x244 - LayoutText {#text} at (360,226) size 4x17 - text run at (360,226) width 4: " " - LayoutText {#text} at (0,0) size 0x0 -layer at (8,294) size 360x240 - LayoutImage {IMG} at (0,0) size 360x240 -layer at (372,294) size 360x240 - LayoutImage {IMG} at (364,0) size 360x240
diff --git a/third_party/WebKit/LayoutTests/platform/win7/fast/canvas/canvas-shadow-source-in-expected.png b/third_party/WebKit/LayoutTests/platform/win7/fast/canvas/canvas-shadow-source-in-expected.png deleted file mode 100644 index b5daa85..0000000 --- a/third_party/WebKit/LayoutTests/platform/win7/fast/canvas/canvas-shadow-source-in-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/fast/canvas/canvas-shadow-source-in-expected.txt b/third_party/WebKit/LayoutTests/platform/win7/fast/canvas/canvas-shadow-source-in-expected.txt deleted file mode 100644 index 78b5f8a..0000000 --- a/third_party/WebKit/LayoutTests/platform/win7/fast/canvas/canvas-shadow-source-in-expected.txt +++ /dev/null
@@ -1,21 +0,0 @@ -layer at (0,0) size 1600x1200 - LayoutView at (0,0) size 1600x1200 -layer at (0,0) size 1600x464 - LayoutBlockFlow {HTML} at (0,0) size 1600x464 - LayoutBlockFlow {BODY} at (8,8) size 1584x448 - LayoutBlockFlow {DIV} at (0,0) size 1584x18 - LayoutText {#text} at (0,0) size 60x17 - text run at (0,0) width 60: "Test Rect" - LayoutBlockFlow (anonymous) at (0,18) size 1584x206 - LayoutText {#text} at (0,0) size 0x0 - LayoutBlockFlow {DIV} at (0,224) size 1584x18 - LayoutText {#text} at (0,0) size 71x17 - text run at (0,0) width 71: "Test Image" - LayoutBlockFlow (anonymous) at (0,242) size 1584x206 - LayoutText {#text} at (0,0) size 0x0 - LayoutText {#text} at (0,0) size 0x0 - LayoutText {#text} at (0,0) size 0x0 -layer at (8,26) size 202x202 - LayoutHTMLCanvas {CANVAS} at (0,0) size 202x202 [border: (1px solid #999999)] -layer at (8,250) size 202x202 - LayoutHTMLCanvas {CANVAS} at (0,0) size 202x202 [border: (1px solid #999999)]
diff --git a/third_party/WebKit/LayoutTests/platform/win7/fast/text/atsui-spacing-features-expected.png b/third_party/WebKit/LayoutTests/platform/win7/fast/text/atsui-spacing-features-expected.png index 425d078..7bdd925 100644 --- a/third_party/WebKit/LayoutTests/platform/win7/fast/text/atsui-spacing-features-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win7/fast/text/atsui-spacing-features-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/fast/text/atsui-spacing-features-expected.txt b/third_party/WebKit/LayoutTests/platform/win7/fast/text/atsui-spacing-features-expected.txt deleted file mode 100644 index 13ed13fc..0000000 --- a/third_party/WebKit/LayoutTests/platform/win7/fast/text/atsui-spacing-features-expected.txt +++ /dev/null
@@ -1,84 +0,0 @@ -layer at (0,0) size 800x600 - LayoutView at (0,0) size 800x600 -layer at (0,0) size 800x354 - LayoutBlockFlow {HTML} at (0,0) size 800x354 - LayoutBlockFlow {BODY} at (8,16) size 784x330 - LayoutBlockFlow {P} at (0,0) size 784x36 - LayoutText {#text} at (0,0) size 179x17 - text run at (0,0) width 179: "Test for regressions against " - LayoutInline {I} at (0,0) size 772x35 - LayoutInline {A} at (0,0) size 354x17 [color=#0000EE] - LayoutText {#text} at (178,0) size 354x17 - text run at (178,0) width 354: "http://bugzilla.opendarwin.org/show_bug.cgi?id=3922" - LayoutText {#text} at (531,0) size 772x35 - text run at (531,0) width 241: " Variable word/letter spacing and full" - text run at (0,18) width 328: "justification not supported for ATSUI-rendered text" - LayoutText {#text} at (327,18) size 5x17 - text run at (327,18) width 5: "." - LayoutBlockFlow (anonymous) at (0,52) size 784x18 - LayoutText {#text} at (0,0) size 517x17 - text run at (0,0) width 517: "Each green box should be identical to the blue box it follows, except for accents." - LayoutBlockFlow {HR} at (0,78) size 784x2 [border: (1px inset #EEEEEE)] - LayoutTable {TABLE} at (0,88) size 620x242 - LayoutTableSection {TBODY} at (0,0) size 620x242 - LayoutTableRow {TR} at (0,2) size 620x20 - LayoutTableCell {TD} at (2,2) size 204x20 [r=0 c=0 rs=1 cs=1] - LayoutText {#text} at (57,1) size 89x17 - text run at (57,1) width 89: "Word spacing" - LayoutTableCell {TD} at (208,2) size 204x20 [r=0 c=1 rs=1 cs=1] - LayoutText {#text} at (56,1) size 92x17 - text run at (56,1) width 92: "Letter spacing" - LayoutTableCell {TD} at (414,2) size 204x20 [r=0 c=2 rs=1 cs=1] - LayoutText {#text} at (62,1) size 80x17 - text run at (62,1) width 80: "Justification" - LayoutTableRow {TR} at (0,24) size 620x216 - LayoutTableCell {TD} at (2,24) size 204x162 [r=1 c=0 rs=1 cs=1] - LayoutBlockFlow {DIV} at (1,1) size 202x160 - LayoutBlockFlow {DIV} at (0,0) size 202x38 [border: (1px solid #0000FF)] - LayoutText {#text} at (24,1) size 182x35 - text run at (24,1) width 177 RTL: "\x{5D9}\x{5B0}\x{5D4}\x{5B4}\x{5D9}, \x{5D0}\x{5B8}\x{5D7}\x{5B4}\x{5D9}, \x{5DC}\x{5B0}\x{5DA}\x{5B8} \x{5E1}\x{5B5}\x{5E4}\x{5B6}\x{5E8} \x{5E9}\x{5C1}\x{5B0}\x{5DC}\x{5B7}\x{5D7}\x{5B0}\x{5EA}\x{5BC}\x{5B4}\x{5D9}\x{5D5}" - text run at (19,19) width 126 RTL: "\x{5E6}\x{5B0}\x{5DE}\x{5B4}\x{5D9}\x{5EA}\x{5D5}\x{5BC}\x{5EA} \x{5DC}\x{5B8}\x{5DA}\x{5B0} \x{5DE}\x{5B0}\x{5DB}\x{5B7}\x{5E8}\x{5B0}\x{5EA}\x{5BC}\x{5B4}\x{5D9}\x{5D5}." - text run at (144,19) width 57 RTL: "\x{5D5}\x{5BC}\x{5DE}\x{5B4}\x{5DE}\x{5B0}\x{5DB}\x{5BC}\x{5B6}\x{5E8}\x{5B6}\x{5EA} " - LayoutBlockFlow {DIV} at (0,43) size 202x56 [border: (1px solid #0000FF)] - LayoutText {#text} at (1,1) size 173x53 - text run at (1,1) width 173: "Lore\x{300}m ipsum dolor sit" - text run at (1,19) width 130: "ame\x{300}t, consectetuer" - text run at (1,37) width 105: "adipiscing e\x{300}lit." - LayoutBlockFlow {DIV} at (0,104) size 202x56 [border: (1px solid #008000)] - LayoutText {#text} at (1,1) size 173x53 - text run at (1,1) width 173: "Lorem ipsum dolor sit" - text run at (1,19) width 130: "amet, consectetuer" - text run at (1,37) width 105: "adipiscing elit." - LayoutTableCell {TD} at (208,24) size 204x216 [r=1 c=1 rs=1 cs=1] - LayoutBlockFlow {DIV} at (1,1) size 202x214 - LayoutBlockFlow {DIV} at (0,0) size 202x56 [border: (1px solid #0000FF)] - LayoutText {#text} at (29,1) size 190x53 - text run at (29,1) width 172 RTL: "\x{5D9}\x{5B0}\x{5D4}\x{5B4}\x{5D9}, \x{5D0}\x{5B8}\x{5D7}\x{5B4}\x{5D9}, \x{5DC}\x{5B0}\x{5DA}\x{5B8} \x{5E1}\x{5B5}\x{5E4}\x{5B6}\x{5E8}" - text run at (48,19) width 153 RTL: "\x{5E9}\x{5C1}\x{5B0}\x{5DC}\x{5B7}\x{5D7}\x{5B0}\x{5EA}\x{5BC}\x{5B4}\x{5D9}\x{5D5} \x{5D5}\x{5BC}\x{5DE}\x{5B4}\x{5DE}\x{5B0}\x{5DB}\x{5BC}\x{5B6}\x{5E8}\x{5B6}\x{5EA}" - text run at (11,37) width 190 RTL: "\x{5E6}\x{5B0}\x{5DE}\x{5B4}\x{5D9}\x{5EA}\x{5D5}\x{5BC}\x{5EA} \x{5DC}\x{5B8}\x{5DA}\x{5B0} \x{5DE}\x{5B0}\x{5DB}\x{5B7}\x{5E8}\x{5B0}\x{5EA}\x{5BC}\x{5B4}\x{5D9}\x{5D5}." - LayoutBlockFlow {DIV} at (0,61) size 202x74 [border: (1px solid #0000FF)] - LayoutText {#text} at (1,1) size 175x71 - text run at (1,1) width 141: "Lore\x{300}m ipsum" - text run at (1,19) width 167: "dolor sit ame\x{300}t," - text run at (1,37) width 140: "consectetue\x{300}r" - text run at (1,55) width 175: "adipiscing e\x{300}lit." - LayoutBlockFlow {DIV} at (0,140) size 202x74 [border: (1px solid #008000)] - LayoutText {#text} at (1,1) size 175x71 - text run at (1,1) width 141: "Lorem ipsum" - text run at (1,19) width 167: "dolor sit amet," - text run at (1,37) width 140: "consectetuer" - text run at (1,55) width 175: "adipiscing elit." - LayoutTableCell {TD} at (414,24) size 204x126 [r=1 c=2 rs=1 cs=1] - LayoutBlockFlow {DIV} at (1,1) size 202x124 - LayoutBlockFlow {DIV} at (0,0) size 202x38 [border: (1px solid #0000FF)] - LayoutText {#text} at (1,1) size 200x35 - text run at (1,1) width 200 RTL: "\x{5D9}\x{5B0}\x{5D4}\x{5B4}\x{5D9}, \x{5D0}\x{5B8}\x{5D7}\x{5B4}\x{5D9}, \x{5DC}\x{5B0}\x{5DA}\x{5B8} \x{5E1}\x{5B5}\x{5E4}\x{5B6}\x{5E8} \x{5E9}\x{5C1}\x{5B0}\x{5DC}\x{5B7}\x{5D7}\x{5B0}\x{5EA}\x{5BC}\x{5B4}\x{5D9}\x{5D5} \x{5D5}\x{5BC}\x{5DE}\x{5B4}\x{5DE}\x{5B0}\x{5DB}\x{5BC}\x{5B6}\x{5E8}\x{5B6}\x{5EA}" - text run at (96,19) width 105 RTL: "\x{5E6}\x{5B0}\x{5DE}\x{5B4}\x{5D9}\x{5EA}\x{5D5}\x{5BC}\x{5EA} \x{5DC}\x{5B8}\x{5DA}\x{5B0} \x{5DE}\x{5B0}\x{5DB}\x{5B7}\x{5E8}\x{5B0}\x{5EA}\x{5BC}\x{5B4}\x{5D9}\x{5D5}." - LayoutBlockFlow {DIV} at (0,43) size 202x38 [border: (1px solid #0000FF)] - LayoutText {#text} at (1,1) size 200x35 - text run at (1,1) width 200: "Lore\x{300}m ipsum dolor sit ame\x{300}t," - text run at (1,19) width 179: "consectetue\x{300}r adipiscing e\x{300}lit." - LayoutBlockFlow {DIV} at (0,86) size 202x38 [border: (1px solid #008000)] - LayoutText {#text} at (1,1) size 200x35 - text run at (1,1) width 200: "Lorem ipsum dolor sit amet," - text run at (1,19) width 179: "consectetuer adipiscing elit."
diff --git a/third_party/WebKit/LayoutTests/platform/win7/fast/text/drawBidiText-expected.txt b/third_party/WebKit/LayoutTests/platform/win7/fast/text/drawBidiText-expected.txt deleted file mode 100644 index 63dc6f5..0000000 --- a/third_party/WebKit/LayoutTests/platform/win7/fast/text/drawBidiText-expected.txt +++ /dev/null
@@ -1,56 +0,0 @@ -layer at (0,0) size 800x600 - LayoutView at (0,0) size 800x600 -layer at (0,0) size 800x600 - LayoutBlockFlow {HTML} at (0,0) size 800x600 - LayoutBlockFlow {BODY} at (8,8) size 784x584 - LayoutBlockFlow {P} at (0,0) size 784x18 - LayoutText {#text} at (0,0) size 285x17 - text run at (0,0) width 285: "This tests GraphicsContext::drawBidiText()." -layer at (8,42) size 322x205 clip at (9,43) size 305x203 - LayoutListBox {SELECT} at (0,34) size 322.03x205.34 [bgcolor=#FFFFFF] [border: (1px solid #A9A9A9)] - LayoutBlockFlow {OPTION} at (1,1) size 305.03x22.59 - LayoutText {#text} at (2,0) size 199x20 - text run at (2,0) width 40: "First " - text run at (41,0) width 61 RTL: ") \x{5E8}\x{5D1}\x{5D9}\x{5E2}\x{5D9}\x{5EA}" - text run at (101,0) width 21: "03" - text run at (121,0) width 46 RTL: "\x{5E9}\x{5E0}\x{5D9}\x{5D4} (" - text run at (166,0) width 35: " fifth" - LayoutBlockFlow {OPTION} at (1,23.59) size 305.03x22.59 - LayoutText {#text} at (104,0) size 200x20 - text run at (104,0) width 30: "fifth" - text run at (133,0) width 65 RTL: ") \x{5E8}\x{5D1}\x{5D9}\x{5E2}\x{5D9}\x{5EA} " - text run at (197,0) width 21: "03" - text run at (217,0) width 52 RTL: " \x{5E9}\x{5E0}\x{5D9}\x{5D4} (" - text run at (268,0) width 36: "First" - LayoutBlockFlow {OPTION} at (1,46.19) size 305.03x22.59 - LayoutText {#text} at (2,0) size 200x20 - text run at (2,0) width 200 LTR override: "First \x{5E9}\x{5E0}\x{5D9}\x{5D4} (03) \x{5E8}\x{5D1}\x{5D9}\x{5E2}\x{5D9}\x{5EA} fifth" - LayoutBlockFlow {OPTION} at (1,68.78) size 305.03x22.59 - LayoutText {#text} at (104,0) size 200x20 - text run at (104,0) width 200 RTL override: "First \x{5E9}\x{5E0}\x{5D9}\x{5D4} (03) \x{5E8}\x{5D1}\x{5D9}\x{5E2}\x{5D9}\x{5EA} fifth" - LayoutBlockFlow {OPTION} at (1,91.38) size 305.03x22.59 - LayoutText {#text} at (2,0) size 100x20 - text run at (2,0) width 100 RTL: "\x{5DE}\x{5E9}\x{5D4}\x{5D5} \x{5E2}\x{5DD} \x{5E0}\x{5B4}\x{5E7}\x{5BC}\x{5D5}\x{5BC}\x{5D3}" - LayoutBlockFlow {OPTION} at (1,113.97) size 305.03x22.59 - LayoutText {#text} at (2,0) size 69x20 - text run at (2,0) width 69 RTL: "\x{627}\x{644}\x{644}\x{63A}\x{629} \x{627}\x{644}\x{639}\x{631}\x{628}\x{64A}\x{629}" - LayoutBlockFlow {OPTION} at (1,136.56) size 305.03x22.59 - LayoutText {#text} at (2,0) size 126x20 - text run at (2,0) width 126: "Et volia\x{300}: ATSUI!" - LayoutBlockFlow {OPTION} at (1,159.16) size 305.03x22.59 - LayoutText {#text} at (2,0) size 283x20 - text run at (2,0) width 91: "Directional " - text run at (92,0) width 75 RTL override: "\x{202E}overrides" - text run at (166,0) width 119: "\x{202C} are confusing." - LayoutBlockFlow {OPTION} at (1,181.75) size 305.03x22.59 - LayoutText {#text} at (2,0) size 301x20 - text run at (2,0) width 82: "She said \x{201C}" - text run at (83,0) width 67 RTL: " \x{5D1}\x{5DE}\x{5D6}\x{5D5}\x{5D5}\x{5D3}\x{5D4}!" - text run at (149,0) width 36: "TNT" - text run at (184,0) width 23 RTL: "\x{202B}\x{5D9}\x{5E9} " - text run at (206,0) width 97: "\x{202C}\x{201D} and ran off" -layer at (8,247) size 366x18 clip at (9,248) size 349x16 - LayoutListBox {SELECT} at (0,239.34) size 366x18 [bgcolor=#FFFFFF] [border: (1px solid #A9A9A9)] - LayoutBlockFlow {OPTION} at (1,1) size 349x15.39 - LayoutText {#text} at (2,0) size 345x14 - text run at (2,0) width 345: "There are two ways to measure text: my way and the wrong way"
diff --git a/third_party/WebKit/LayoutTests/platform/win7/virtual/display_list_2d_canvas/fast/canvas/canvas-shadow-source-in-expected.png b/third_party/WebKit/LayoutTests/platform/win7/virtual/display_list_2d_canvas/fast/canvas/canvas-shadow-source-in-expected.png new file mode 100644 index 0000000..647e06c0 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/win7/virtual/display_list_2d_canvas/fast/canvas/canvas-shadow-source-in-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mountainlion/fast/canvas/canvas-shadow-source-in-expected.txt b/third_party/WebKit/LayoutTests/platform/win7/virtual/display_list_2d_canvas/fast/canvas/canvas-shadow-source-in-expected.txt similarity index 90% rename from third_party/WebKit/LayoutTests/platform/mac-mountainlion/fast/canvas/canvas-shadow-source-in-expected.txt rename to third_party/WebKit/LayoutTests/platform/win7/virtual/display_list_2d_canvas/fast/canvas/canvas-shadow-source-in-expected.txt index 74c840a..f50a5f9 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mountainlion/fast/canvas/canvas-shadow-source-in-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win7/virtual/display_list_2d_canvas/fast/canvas/canvas-shadow-source-in-expected.txt
@@ -4,12 +4,12 @@ LayoutBlockFlow {HTML} at (0,0) size 800x464 LayoutBlockFlow {BODY} at (8,8) size 784x448 LayoutBlockFlow {DIV} at (0,0) size 784x18 - LayoutText {#text} at (0,0) size 60x18 + LayoutText {#text} at (0,0) size 60x17 text run at (0,0) width 60: "Test Rect" LayoutBlockFlow (anonymous) at (0,18) size 784x206 LayoutText {#text} at (0,0) size 0x0 LayoutBlockFlow {DIV} at (0,224) size 784x18 - LayoutText {#text} at (0,0) size 71x18 + LayoutText {#text} at (0,0) size 71x17 text run at (0,0) width 71: "Test Image" LayoutBlockFlow (anonymous) at (0,242) size 784x206 LayoutText {#text} at (0,0) size 0x0
diff --git a/third_party/WebKit/LayoutTests/resources/testharnessreport.js b/third_party/WebKit/LayoutTests/resources/testharnessreport.js index 0d9a8a6..56dcac54 100644 --- a/third_party/WebKit/LayoutTests/resources/testharnessreport.js +++ b/third_party/WebKit/LayoutTests/resources/testharnessreport.js
@@ -117,8 +117,11 @@ } // Add results element to document. - if (!document.body) + if (!document.body) { + if (!document.documentElement) + document.appendChild(document.createElement('html')); document.documentElement.appendChild(document.createElement("body")); + } document.body.appendChild(results); if (self.testRunner)
diff --git a/third_party/WebKit/LayoutTests/svg/filters/feTile-expected.png b/third_party/WebKit/LayoutTests/svg/filters/feTile-expected.png index 2b2b022..1d91fcb 100644 --- a/third_party/WebKit/LayoutTests/svg/filters/feTile-expected.png +++ b/third_party/WebKit/LayoutTests/svg/filters/feTile-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/typedcssom/simplelength.html b/third_party/WebKit/LayoutTests/typedcssom/simplelength.html new file mode 100644 index 0000000..0ca8983 --- /dev/null +++ b/third_party/WebKit/LayoutTests/typedcssom/simplelength.html
@@ -0,0 +1,112 @@ +<!DOCTYPE html> +<script src='../resources/testharness.js'></script> +<script src='../resources/testharnessreport.js'></script> + +<script> + +test(function() { + var simpleLength1 = new SimpleLength(5.1, 'px'); + var simpleLength2 = new SimpleLength(10, 'px'); + + var result = simpleLength1.add(simpleLength2); + + assert_not_equals(simpleLength1, result); + assert_not_equals(simpleLength2, result); + assert_true(result instanceof SimpleLength); + assert_equals(result.value, 15.1); + assert_equals(result.type, 'px'); +}, 'Test that adding SimpleLengths produces a new SimpleLength with the correct value.'); + +test(function() { + var simpleLength1 = new SimpleLength(5.1, 'px'); + var simpleLength2 = new SimpleLength(10, 'px'); + + var result = simpleLength1.subtract(simpleLength2); + + assert_not_equals(simpleLength1, result); + assert_not_equals(simpleLength2, result); + assert_true(result instanceof SimpleLength); + assert_equals(result.value, -4.9); + assert_equals(result.type, 'px'); +}, 'Test that subtracting SimpleLengths produces a new SimpleLength with the correct value.'); + +test(function() { + var simpleLength = new SimpleLength(5.2, 'px'); + var result = simpleLength.multiply(4); + + assert_not_equals(simpleLength, result); + assert_true(result instanceof SimpleLength); + assert_approx_equals(result.value, 20.8, 0.00000001); + assert_equals(result.type, 'px'); +}, 'Test that multiplying a SimpleLength produces a new SimpleLength with the correct value.'); + +test(function() { + var simpleLength = new SimpleLength(25, 'px'); + var result = simpleLength.divide(2); + + assert_not_equals(simpleLength, result); + assert_true(result instanceof SimpleLength); + assert_equals(result.value, 12.5); + assert_equals(result.type, 'px'); +}, 'Test that dividing a SimpleLength produces a new SimpleLength with the correct value.'); + +test(function() { + var values = [ + {input: new SimpleLength(1, 'px'), cssString: '1px' }, + {input: new SimpleLength(2, 'percent'), cssString: '2%' }, + {input: new SimpleLength(3, '%'), cssString: '3%' }, + {input: new SimpleLength(4, 'em'), cssString: '4em' }, + {input: new SimpleLength(5, 'ex'), cssString: '5ex' }, + {input: new SimpleLength(6, 'ch'), cssString: '6ch' }, + {input: new SimpleLength(7, 'rem'), cssString: '7rem' }, + {input: new SimpleLength(8, 'vw'), cssString: '8vw' }, + {input: new SimpleLength(9, 'vh'), cssString: '9vh' }, + {input: new SimpleLength(10, 'vmin'), cssString: '10vmin' }, + {input: new SimpleLength(11, 'vmax'), cssString: '11vmax' }, + {input: new SimpleLength(12, 'cm'), cssString: '12cm' }, + {input: new SimpleLength(13, 'mm'), cssString: '13mm' }, + {input: new SimpleLength(14, 'in'), cssString: '14in' }, + {input: new SimpleLength(15, 'pc'), cssString: '15pc' }, + {input: new SimpleLength(16, 'pt'), cssString: '16pt' }, + // Same again to double check that it's case insensitive. + {input: new SimpleLength(1, 'PX'), cssString: '1px' }, + {input: new SimpleLength(2, 'PERCENT'), cssString: '2%' }, + {input: new SimpleLength(3, '%'), cssString: '3%' }, + {input: new SimpleLength(4, 'EM'), cssString: '4em' }, + {input: new SimpleLength(5, 'EX'), cssString: '5ex' }, + {input: new SimpleLength(6, 'CH'), cssString: '6ch' }, + {input: new SimpleLength(7, 'REM'), cssString: '7rem' }, + {input: new SimpleLength(8, 'VW'), cssString: '8vw' }, + {input: new SimpleLength(9, 'VH'), cssString: '9vh' }, + {input: new SimpleLength(10, 'VMIN'), cssString: '10vmin' }, + {input: new SimpleLength(11, 'VMAX'), cssString: '11vmax' }, + {input: new SimpleLength(12, 'CM'), cssString: '12cm' }, + {input: new SimpleLength(13, 'MM'), cssString: '13mm' }, + {input: new SimpleLength(14, 'IN'), cssString: '14in' }, + {input: new SimpleLength(15, 'PC'), cssString: '15pc' }, + {input: new SimpleLength(16, 'PT'), cssString: '16pt' }, + ]; + + for (var i = 0; i < values.length; ++i) { + assert_equals(values[i].input.cssString, values[i].cssString); + } +}, 'Test that the SimpleLength css string is generated correctly for each unit type.'); + +test(function() { + var values = [ + {value: NaN, unit: 'px'}, + {value: Infinity, unit: 'px'}, + {value: -Infinity, unit: 'px'}, + {value: 5, unit: 'puppies'} + ]; + + for (var i = 0; i < values.length; ++i) { + assert_throws(null, function() { new SimpleLength(values[i].value, values[i].unit); }); + } + +}, 'Test that invalid input throws an exception.'); + +</script> + +<body> +</body>
diff --git a/third_party/WebKit/LayoutTests/virtual/gpu/fast/canvas/canvas-imageSmoothingQuality-expected.txt b/third_party/WebKit/LayoutTests/virtual/gpu/fast/canvas/canvas-imageSmoothingQuality-expected.txt index 4bbed49a..6534bbc 100644 --- a/third_party/WebKit/LayoutTests/virtual/gpu/fast/canvas/canvas-imageSmoothingQuality-expected.txt +++ b/third_party/WebKit/LayoutTests/virtual/gpu/fast/canvas/canvas-imageSmoothingQuality-expected.txt
@@ -12,13 +12,13 @@ PASS mediumContext.imageSmoothingQuality is 'medium' PASS highContext.imageSmoothingQuality is 'high' -FAIL lowData should not be {"0":0,"1":0,"2":0,"3":100}. -FAIL mediumData should not be {"0":0,"1":0,"2":0,"3":100}. -FAIL lowData should not be {"0":0,"1":0,"2":0,"3":100}. +FAIL lowData should not be {"0":0,"1":0,"2":0,"3":201}. +FAIL mediumData should not be {"0":0,"1":0,"2":0,"3":201}. +FAIL lowData should not be {"0":0,"1":0,"2":0,"3":201}. -FAIL sampleAlpha(noFilterData) should be > sampleAlpha(lowData). Was 0 (of type number). -FAIL sampleAlpha(lowData) should be > sampleAlpha(mediumData). Was 100 (of type number). -FAIL sampleAlpha(mediumData) should be > sampleAlpha(highData). Was 100 (of type number). +FAIL sampleAlpha(noFilterData) should be > sampleAlpha(lowData). Was 201 (of type number). +FAIL sampleAlpha(lowData) should be > sampleAlpha(mediumData). Was 201 (of type number). +FAIL sampleAlpha(mediumData) should be > sampleAlpha(highData). Was 201 (of type number). On setting, it must be set to the new value.
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-loop-grain-no-duration-expected.txt b/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-loop-grain-no-duration-expected.txt index d605807b..60a9dee 100644 --- a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-loop-grain-no-duration-expected.txt +++ b/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-loop-grain-no-duration-expected.txt
@@ -3,7 +3,8 @@ On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". -PASS Source looped correctly +PASS The output of actual and expected loops is identical to the array [0,0.125,0.25,0.375,0.5,0.625,0.75,0.875,0,0.125,0.25,0.375,0.5,0.625,0.75,0.875...]. +PASS The content of the left and right channel is identical to the array [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0...]. PASS successfullyParsed is true TEST COMPLETE
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-loop-grain-no-duration.html b/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-loop-grain-no-duration.html index 47858df..c8715e5f 100644 --- a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-loop-grain-no-duration.html +++ b/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-loop-grain-no-duration.html
@@ -1,79 +1,115 @@ -<!doctype html> +<!DOCTYPE html> <html> - <head> - <title>Test AudioBufferSourceNode looping without explicit duration</title> - <script src="resources/compatibility.js"></script> - <script src="resources/audio-testing.js"></script> - <script src="../resources/js-test.js"></script> - </head> - <body> - <script> - description("Test AudioBufferSourceNode looping without explicit duration"); +<head> + <title>Test AudioBufferSourceNode looping without explicit duration</title> + <script src="../resources/js-test.js"></script> + <script src="resources/compatibility.js"></script> + <script src="resources/audio-testing.js"></script> +</head> - var context; - var buffer; - var output; - var expected; - var sampleRate = 44100; - var sourceFrames = 8; - // How many loops of the source we want to render. Any whole number greater than 1 will work. +<body> + <script> + description("Test AudioBufferSourceNode looping without explicit duration"); + window.jsTestIsAsync = true; + + // Reasonably low sample rate for the optimum test speed. + var sampleRate = 4096; + + var audit = Audit.createTaskRunner(); + + // Task: create a short linear ramp and enable looping. The test will + // verify that the ramp was looped the appropriate number of times. + audit.defineTask('loop-count', function (done) { + // How many loops of the source we want to render. Any whole number + // greater than 1 will work. var loopCount = 4; + var sourceFrames = 8; var renderFrames = sourceFrames * loopCount; - - function checkResult(renderedBuffer) { + var context = new OfflineAudioContext(1, renderFrames, sampleRate); + var source = context.createBufferSource(); + var linearRampBuffer = createLinearRampBuffer(context, sourceFrames); + + source.buffer = linearRampBuffer; + source.connect(context.destination); + + // Enable looping and start the source with an offset, but without a + // duration. In this case, the source should loop "forever". + // See crbug.com/457009. + source.loop = true; + source.start(0, 0); + + context.startRendering().then(function (renderedBuffer) { var badIndex = -1; var success = true; - expected = buffer.getChannelData(0); - output = renderedBuffer.getChannelData(0); + var actual = renderedBuffer.getChannelData(0); + var linearRamp = linearRampBuffer.getChannelData(0); - // Verify the output has the expected data. The actual output should be a loopCount copies - // of the source buffer. - for (var k = 0; k < loopCount; ++k) { - // Check that this current subset is a linear ramp matching the original source. - for (var n = 0; n < sourceFrames; ++n) { - if (expected[n] != output[n + k * sourceFrames]) { - // Remember the first bad sample and exit all loops now. - badIndex = n + k * sourceFrames; - success = false; - break; - } - } - if (!success) - break; - } + // Manually create a |loopCount| copies of linear ramps. + var expected = new Float32Array(linearRamp.length * loopCount); + for (var i = 0; i < loopCount; i++) + expected.set(linearRamp, linearRamp.length * i); - if (success) { - testPassed("Source looped correctly"); - } else { - testFailed("First incorrect sample at index " + badIndex); - } - } + // The actual output should match the created loop. + Should('The output of actual and expected loops', actual) + .beEqualToArray(expected); + }).then(done); + }); - function runTest() { - window.jsTestIsAsync = true; + // Task: Test that looping an AudioBufferSource works correctly if the + // source is started and the buffer is assigned later, but before the source + // would start. + audit.defineTask('delayed-start', function (done) { + var renderDuration = 2; + var context = new OfflineAudioContext(2, sampleRate * renderDuration, sampleRate); + var linearRampBuffer = createLinearRampBuffer(context, 128); - // Create a short linear ramp and enable looping. The test will verify that the ramp was - // looped the appropriate number of times. - context = new OfflineAudioContext(1, renderFrames, sampleRate); - buffer = createLinearRampBuffer(context, sourceFrames); - var source = context.createBufferSource(); - source.buffer = buffer; - source.connect(context.destination); + var normal = context.createBufferSource(); + var delayed = context.createBufferSource(); + var merger = context.createChannelMerger(2); - // Loop the source, and start the source with an offset, but without a duration. In this - // case, the source should loop "forever". See crbug.com/457009. The case where the - // duration is given is covered in other tests. - source.loop = true; - source.start(0, 0); - context.startRendering() - .then(checkResult) - .then(finishJSTest); - } + // Connect the normally started source to the left channel, and the + // delayed to the right channel. + normal.connect(merger, 0, 0); + delayed.connect(merger, 0, 1); + merger.connect(context.destination); - runTest(); - </script> - </body> + normal.buffer = linearRampBuffer; + normal.loop = true; + delayed.loop = true; + + normal.start(1, 0); + delayed.start(1, 0); + + // Assign the buffer to the delayed source node at 0.5 second. + context.suspend(0.5).then(function () { + delayed.buffer = linearRampBuffer; + context.resume(); + }); + + context.startRendering().then(function (buffer) { + // The left and right channel must match regardless of the timing + // of buffer assignment. + Should('The content of the left and right channel', + buffer.getChannelData(0)).beEqualToArray(buffer.getChannelData(1)); + }).then(done); + }); + + audit.defineTask('finish', function (done) { + finishJSTest(); + done(); + }); + + audit.runTasks( + 'loop-count', + 'delayed-start', + 'finish' + ); + + successfullyParsed = true; + </script> +</body> + </html>
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt index c7d93e6..5af0ae9e 100644 --- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt +++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
@@ -5124,6 +5124,11 @@ getter workerStart method constructor setter onerror +interface SimpleLength : LengthValue + getter type + getter value + method constructor + setter value interface SpeechSynthesisEvent : Event getter charIndex getter elapsedTime
diff --git a/third_party/WebKit/ManualTests/webaudio/audiobuffersource-loop-grain-no-duration.html b/third_party/WebKit/ManualTests/webaudio/audiobuffersource-loop-grain-no-duration.html deleted file mode 100644 index 8d543a3..0000000 --- a/third_party/WebKit/ManualTests/webaudio/audiobuffersource-loop-grain-no-duration.html +++ /dev/null
@@ -1,70 +0,0 @@ -<!doctype html> -<html> - <head> - <title>Loop AudioBufferSourceNode, with buffer set after start</title> - <script> - var context = new AudioContext() || new webkitAudioContext(); - var normalSource; - var delayedSource - var buffer; - var request = new XMLHttpRequest(); - request.open("GET", "../../LayoutTests/webaudio/resources/media/128kbps-44khz.mp3", true); - request.responseType = "arraybuffer"; - request.onload = function() { - context.decodeAudioData(request.response, - function(b) { - buffer = b; - document.getElementById("Start").disabled = false; - document.getElementById("StartDelayed").disabled = false; - }, - function () { - alert("Could not load file"); - }); - }; - request.send(); - - function normalStart() { - console.log("normalStart"); - normalSource = context.createBufferSource(); - normalSource.loop = true; - normalSource.buffer = buffer; - normalSource.connect(context.destination); - normalSource.start(context.currentTime + 2, 0); - } - function delayedStart() { - console.log("delayedStart"); - delayedSource = context.createBufferSource(); - delayedSource.loop = true; - delayedSource.connect(context.destination); - delayedSource.start(context.currentTime + 2, 0); - setTimeout(function () { - delayedSource.buffer = buffer; - }, 1000); - } - </script> - </head> - - <body> - <h1>Loop AudioBufferSourceNode, with buffer set after start</h1> - - <p>Test that looping an AudioBufferSource works correctly if the source is started and the - buffer is assigned later, but before the source would start. This can't be easily tested in an - offline context because we can't precisely control when the assignment of the buffer to the - source is done.</p> - - <p>Press the "Start" button for the normal case where the buffer is assigned before start.</p> - - <p>Press the "Start delayed" button for the case where the source is started and the buffer - assigned later.</p> - - <p>You should hear audio about 2 sec after pressing the button. It should continue until you - press the corresponding Stop button.</p> - - <button id="Start" disabled onclick='normalStart()'>Start</button> - <button id="Stop" onclick="normalSource.stop()">Stop</button> - <br> - <button id="StartDelayed" disabled onclick='delayedStart()'>Start Delayed</button> - <button id="StopDelayed" onclick='delayedSource.stop()'>Stop Delayed Source</button> - - </body> -</html>
diff --git a/third_party/WebKit/PerformanceTests/DOM/select-long-word.html b/third_party/WebKit/PerformanceTests/DOM/select-long-word.html new file mode 100644 index 0000000..e0cc502 --- /dev/null +++ b/third_party/WebKit/PerformanceTests/DOM/select-long-word.html
@@ -0,0 +1,36 @@ +<!DOCTYPE html> + +<style> +div { + width: 800px; + word-wrap: break-word; +} +</style> + +<script src="../resources/runner.js"></script> + +<div id="long"> +</div> + +<script> +var longDiv = document.getElementById('long'); +var sel = window.getSelection(); + +PerfTestRunner.measureTime({ + description: "Measures performance of detecting long word boundaries.", + + setup: function() { + var text = 'GrumpywizardsmaketoxicbrewfortheevilQueenandJack'; + for (i = 0; i < 12; i++) + text = text + text; + longDiv.appendChild(document.createTextNode(text)); + }, + + run: function() { + sel.setPosition(longDiv, 0); + sel.modify("extend", "forward", "word"); + }, + + done: function () { document.body.removeChild(longDiv) } +}); +</script>
diff --git a/third_party/WebKit/PerformanceTests/Layout/ArabicLineLayout.html b/third_party/WebKit/PerformanceTests/Layout/ArabicLineLayout.html index e795c9c..35215cc8 100644 --- a/third_party/WebKit/PerformanceTests/Layout/ArabicLineLayout.html +++ b/third_party/WebKit/PerformanceTests/Layout/ArabicLineLayout.html
@@ -36,11 +36,11 @@ function test() { style.display = "block"; style.width = "280px"; - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); style.width = "300px"; - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); style.width = "290px"; - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); style.display = "none"; }
diff --git a/third_party/WebKit/PerformanceTests/Layout/Shapes/MultipleShapes.html b/third_party/WebKit/PerformanceTests/Layout/Shapes/MultipleShapes.html index 91f7711..9dc6fed 100644 --- a/third_party/WebKit/PerformanceTests/Layout/Shapes/MultipleShapes.html +++ b/third_party/WebKit/PerformanceTests/Layout/Shapes/MultipleShapes.html
@@ -15,7 +15,7 @@ iframe.contentDocument.write(test800); iframe.contentDocument.close(); iframe.style.width = '800px'; - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); document.body.removeChild(iframe); var iframe2 = iframe.cloneNode(); @@ -25,7 +25,7 @@ iframe2.contentDocument.write(test600); iframe2.contentDocument.close(); iframe2.style.width = '600px'; - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); document.body.removeChild(iframe2); var iframe3 = iframe.cloneNode(); @@ -35,7 +35,7 @@ iframe3.contentDocument.write(test400); iframe3.contentDocument.close(); iframe3.style.width = '400px'; - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); document.body.removeChild(iframe3); }});
diff --git a/third_party/WebKit/PerformanceTests/Layout/Shapes/resources/shapes.js b/third_party/WebKit/PerformanceTests/Layout/Shapes/resources/shapes.js index c0169638..6665f918 100644 --- a/third_party/WebKit/PerformanceTests/Layout/Shapes/resources/shapes.js +++ b/third_party/WebKit/PerformanceTests/Layout/Shapes/resources/shapes.js
@@ -67,11 +67,11 @@ description: "Testing shapes with " + properties['webkitShapeOutside'] +" using " + shapeObjectCount + " shapes.", run: function() { applyFloating(); - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); }, setup: function() { PerfTestRunner.resetRandomSeed(); - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); }, done: function() { document.body.removeChild(floatingObjects);
diff --git a/third_party/WebKit/PerformanceTests/Layout/SimpleTextPathLineLayout.html b/third_party/WebKit/PerformanceTests/Layout/SimpleTextPathLineLayout.html index 6ce624f..e8900a9 100644 --- a/third_party/WebKit/PerformanceTests/Layout/SimpleTextPathLineLayout.html +++ b/third_party/WebKit/PerformanceTests/Layout/SimpleTextPathLineLayout.html
@@ -31,11 +31,11 @@ function test() { style.display = "block"; style.width = "200px"; - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); style.width = "200px"; - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); style.width = "200px"; - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); style.display = "none"; }
diff --git a/third_party/WebKit/PerformanceTests/Layout/add-remove-inline-floats.html b/third_party/WebKit/PerformanceTests/Layout/add-remove-inline-floats.html index be1959bf..75005b9 100644 --- a/third_party/WebKit/PerformanceTests/Layout/add-remove-inline-floats.html +++ b/third_party/WebKit/PerformanceTests/Layout/add-remove-inline-floats.html
@@ -28,7 +28,7 @@ function test() { addFloats(); - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); removeFloats(); }
diff --git a/third_party/WebKit/PerformanceTests/Layout/auto-grid-lots-of-data.html b/third_party/WebKit/PerformanceTests/Layout/auto-grid-lots-of-data.html index 8c1d338..01102030 100644 --- a/third_party/WebKit/PerformanceTests/Layout/auto-grid-lots-of-data.html +++ b/third_party/WebKit/PerformanceTests/Layout/auto-grid-lots-of-data.html
@@ -21,14 +21,14 @@ <script src="../resources/runner.js"></script> <script> function startTest() { - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); var index = 0; PerfTestRunner.measureRunsPerSecond({ description: "Measures performance of layout on a page using CSS grid layout.", run: function() { document.body.style.width = ++index % 2 ? "99%" : "98%"; - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); } }); }
diff --git a/third_party/WebKit/PerformanceTests/Layout/chapter-reflow-once-random.html b/third_party/WebKit/PerformanceTests/Layout/chapter-reflow-once-random.html index 6177470..775808d 100644 --- a/third_party/WebKit/PerformanceTests/Layout/chapter-reflow-once-random.html +++ b/third_party/WebKit/PerformanceTests/Layout/chapter-reflow-once-random.html
@@ -68,7 +68,7 @@ style.display = "block"; style.width = "280px"; - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); style.display = "none"; }
diff --git a/third_party/WebKit/PerformanceTests/Layout/chapter-reflow-once.html b/third_party/WebKit/PerformanceTests/Layout/chapter-reflow-once.html index c4bdc8b..65ad70c1 100644 --- a/third_party/WebKit/PerformanceTests/Layout/chapter-reflow-once.html +++ b/third_party/WebKit/PerformanceTests/Layout/chapter-reflow-once.html
@@ -73,11 +73,11 @@ style.fontSize = "10px"; style.width = "280px"; - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); style.fontSize = "12px"; style.width = "300px"; - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); style.display = "none"; }
diff --git a/third_party/WebKit/PerformanceTests/Layout/chapter-reflow-thrice.html b/third_party/WebKit/PerformanceTests/Layout/chapter-reflow-thrice.html index 47d2867..a60e2f8 100644 --- a/third_party/WebKit/PerformanceTests/Layout/chapter-reflow-thrice.html +++ b/third_party/WebKit/PerformanceTests/Layout/chapter-reflow-thrice.html
@@ -73,19 +73,19 @@ style.fontSize = "10px"; style.width = "280px"; - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); style.width = "300px"; - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); style.width = "290px"; - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); style.fontSize = "12px"; style.width = "280px"; - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); style.width = "300px"; - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); style.width = "290px"; - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); style.display = "none"; }
diff --git a/third_party/WebKit/PerformanceTests/Layout/chapter-reflow-twice.html b/third_party/WebKit/PerformanceTests/Layout/chapter-reflow-twice.html index 910af403..66991d9 100644 --- a/third_party/WebKit/PerformanceTests/Layout/chapter-reflow-twice.html +++ b/third_party/WebKit/PerformanceTests/Layout/chapter-reflow-twice.html
@@ -73,15 +73,15 @@ style.fontSize = "10px"; style.width = "280px"; - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); style.width = "300px"; - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); style.fontSize = "12px"; style.width = "280px"; - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); style.width = "300px"; - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); style.display = "none"; }
diff --git a/third_party/WebKit/PerformanceTests/Layout/chapter-reflow.html b/third_party/WebKit/PerformanceTests/Layout/chapter-reflow.html index f88a1b03..d40fc85 100644 --- a/third_party/WebKit/PerformanceTests/Layout/chapter-reflow.html +++ b/third_party/WebKit/PerformanceTests/Layout/chapter-reflow.html
@@ -71,11 +71,11 @@ function test() { style.display = "block"; style.width = "280px"; - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); style.width = "300px"; - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); style.width = "290px"; - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); style.display = "none"; }
diff --git a/third_party/WebKit/PerformanceTests/Layout/fixed-grid-lots-of-data.html b/third_party/WebKit/PerformanceTests/Layout/fixed-grid-lots-of-data.html index 7fc6a46f..918ef4aa 100644 --- a/third_party/WebKit/PerformanceTests/Layout/fixed-grid-lots-of-data.html +++ b/third_party/WebKit/PerformanceTests/Layout/fixed-grid-lots-of-data.html
@@ -21,14 +21,14 @@ <script src="../resources/runner.js"></script> <script> function startTest() { - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); var index = 0; PerfTestRunner.measureRunsPerSecond({ description: "Measures performance of layout on a page using CSS grid layout (fixed).", run: function() { document.body.style.width = ++index % 2 ? "99%" : "98%"; - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); } }); }
diff --git a/third_party/WebKit/PerformanceTests/Layout/fixed-grid-lots-of-stretched-data.html b/third_party/WebKit/PerformanceTests/Layout/fixed-grid-lots-of-stretched-data.html index aa426dc43..f6962c9 100644 --- a/third_party/WebKit/PerformanceTests/Layout/fixed-grid-lots-of-stretched-data.html +++ b/third_party/WebKit/PerformanceTests/Layout/fixed-grid-lots-of-stretched-data.html
@@ -21,14 +21,14 @@ <script src="../resources/runner.js"></script> <script> function startTest() { - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); var index = 0; PerfTestRunner.measureRunsPerSecond({ description: "Measures performance of layout on a page using CSS grid layout (fixed).", run: function() { document.body.style.width = ++index % 2 ? "99%" : "98%"; - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); } }); }
diff --git a/third_party/WebKit/PerformanceTests/Layout/flexbox-column-nowrap.html b/third_party/WebKit/PerformanceTests/Layout/flexbox-column-nowrap.html index 9db61c97..7821962 100644 --- a/third_party/WebKit/PerformanceTests/Layout/flexbox-column-nowrap.html +++ b/third_party/WebKit/PerformanceTests/Layout/flexbox-column-nowrap.html
@@ -23,9 +23,9 @@ function runTest() { document.getElementById("flexbox").style.display = 'flex'; - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); document.getElementById("flexbox").style.display = ''; - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); } PerfTestRunner.measureRunsPerSecond({
diff --git a/third_party/WebKit/PerformanceTests/Layout/flexbox-column-wrap.html b/third_party/WebKit/PerformanceTests/Layout/flexbox-column-wrap.html index cd44c5b..c4fb01e 100644 --- a/third_party/WebKit/PerformanceTests/Layout/flexbox-column-wrap.html +++ b/third_party/WebKit/PerformanceTests/Layout/flexbox-column-wrap.html
@@ -23,9 +23,9 @@ function runTest() { document.getElementById("flexbox").style.display = 'flex'; - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); document.getElementById("flexbox").style.display = ''; - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); } PerfTestRunner.measureRunsPerSecond({
diff --git a/third_party/WebKit/PerformanceTests/Layout/flexbox-lots-of-data.html b/third_party/WebKit/PerformanceTests/Layout/flexbox-lots-of-data.html index 24dc4ac1..b25f3a85 100644 --- a/third_party/WebKit/PerformanceTests/Layout/flexbox-lots-of-data.html +++ b/third_party/WebKit/PerformanceTests/Layout/flexbox-lots-of-data.html
@@ -52,7 +52,7 @@ description: "Measures performance of flexbox with lots of data laid out in as a table.", run: function() { document.body.style.width = ++index % 2 ? "99%" : "98%"; - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); } }); }
diff --git a/third_party/WebKit/PerformanceTests/Layout/flexbox-row-nowrap.html b/third_party/WebKit/PerformanceTests/Layout/flexbox-row-nowrap.html index 032d9b29..7240f7a 100644 --- a/third_party/WebKit/PerformanceTests/Layout/flexbox-row-nowrap.html +++ b/third_party/WebKit/PerformanceTests/Layout/flexbox-row-nowrap.html
@@ -23,9 +23,9 @@ function runTest() { document.getElementById("flexbox").style.display = 'flex'; - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); document.getElementById("flexbox").style.display = ''; - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); } PerfTestRunner.measureRunsPerSecond({
diff --git a/third_party/WebKit/PerformanceTests/Layout/flexbox-row-wrap.html b/third_party/WebKit/PerformanceTests/Layout/flexbox-row-wrap.html index df46b0c..70dc1c7 100644 --- a/third_party/WebKit/PerformanceTests/Layout/flexbox-row-wrap.html +++ b/third_party/WebKit/PerformanceTests/Layout/flexbox-row-wrap.html
@@ -23,9 +23,9 @@ function runTest() { document.getElementById("flexbox").style.display = 'flex'; - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); document.getElementById("flexbox").style.display = ''; - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); } PerfTestRunner.measureRunsPerSecond({
diff --git a/third_party/WebKit/PerformanceTests/Layout/flexbox-with-stretch-layout.html b/third_party/WebKit/PerformanceTests/Layout/flexbox-with-stretch-layout.html index 0698e78..b4c6f1a 100644 --- a/third_party/WebKit/PerformanceTests/Layout/flexbox-with-stretch-layout.html +++ b/third_party/WebKit/PerformanceTests/Layout/flexbox-with-stretch-layout.html
@@ -44,7 +44,7 @@ div.appendChild(span); container.appendChild(div); }; - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); }; setupTest(); @@ -56,7 +56,7 @@ var inlineBlocks = document.getElementsByClassName("inlineBlock"); for (var i = inlineBlocks.length - 1; i >= 0; i--) { inlineBlocks[i].innerText = switcher ? " " : nbsp; - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); }; switcher = !switcher; };
diff --git a/third_party/WebKit/PerformanceTests/Layout/hindi-line-layout.html b/third_party/WebKit/PerformanceTests/Layout/hindi-line-layout.html index c9b4fea..3d1c36bd 100644 --- a/third_party/WebKit/PerformanceTests/Layout/hindi-line-layout.html +++ b/third_party/WebKit/PerformanceTests/Layout/hindi-line-layout.html
@@ -27,11 +27,11 @@ function test() { style.display = "block"; style.width = "280px"; - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); style.width = "300px"; - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); style.width = "290px"; - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); style.display = "none"; }
diff --git a/third_party/WebKit/PerformanceTests/Layout/latin-complex-text.html b/third_party/WebKit/PerformanceTests/Layout/latin-complex-text.html index bef68615..37840d0 100644 --- a/third_party/WebKit/PerformanceTests/Layout/latin-complex-text.html +++ b/third_party/WebKit/PerformanceTests/Layout/latin-complex-text.html
@@ -96,10 +96,10 @@ }; function runTest() { - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); var now = PerfTestRunner.now(); document.body.appendChild(docFragment.cloneNode(true)); - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); var resultTime = PerfTestRunner.now() - now; document.body.removeChild(document.body.lastChild); return resultTime;
diff --git a/third_party/WebKit/PerformanceTests/Layout/layers_overlap_2d.html b/third_party/WebKit/PerformanceTests/Layout/layers_overlap_2d.html index 0c3a8f85..f906cdc 100644 --- a/third_party/WebKit/PerformanceTests/Layout/layers_overlap_2d.html +++ b/third_party/WebKit/PerformanceTests/Layout/layers_overlap_2d.html
@@ -43,7 +43,7 @@ container.appendChild(outer); } document.body.appendChild(container); - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); container.remove(); } }
diff --git a/third_party/WebKit/PerformanceTests/Layout/layers_overlap_3d.html b/third_party/WebKit/PerformanceTests/Layout/layers_overlap_3d.html index cff4971..acdb58ff 100644 --- a/third_party/WebKit/PerformanceTests/Layout/layers_overlap_3d.html +++ b/third_party/WebKit/PerformanceTests/Layout/layers_overlap_3d.html
@@ -36,7 +36,7 @@ container.appendChild(outer); } document.body.appendChild(container); - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); container.remove(); } }
diff --git a/third_party/WebKit/PerformanceTests/Layout/line-layout-line-height.html b/third_party/WebKit/PerformanceTests/Layout/line-layout-line-height.html index 2ebab30..8fb6890 100644 --- a/third_party/WebKit/PerformanceTests/Layout/line-layout-line-height.html +++ b/third_party/WebKit/PerformanceTests/Layout/line-layout-line-height.html
@@ -21,11 +21,11 @@ function test() { style.display = "block"; style.width = "280px"; - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); style.width = "300px"; - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); style.width = "290px"; - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); style.display = "none"; }
diff --git a/third_party/WebKit/PerformanceTests/Layout/line-layout.html b/third_party/WebKit/PerformanceTests/Layout/line-layout.html index 32b4eef..1d8e9f41 100644 --- a/third_party/WebKit/PerformanceTests/Layout/line-layout.html +++ b/third_party/WebKit/PerformanceTests/Layout/line-layout.html
@@ -78,11 +78,11 @@ function test() { style.display = "block"; style.width = "280px"; - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); style.width = "300px"; - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); style.width = "290px"; - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); style.display = "none"; }
diff --git a/third_party/WebKit/PerformanceTests/Layout/multicol/fixed-height-with-spanner-and-nested-tables.html b/third_party/WebKit/PerformanceTests/Layout/multicol/fixed-height-with-spanner-and-nested-tables.html index f887fe40..82e8f49 100644 --- a/third_party/WebKit/PerformanceTests/Layout/multicol/fixed-height-with-spanner-and-nested-tables.html +++ b/third_party/WebKit/PerformanceTests/Layout/multicol/fixed-height-with-spanner-and-nested-tables.html
@@ -38,9 +38,9 @@ function test() { style.display = "block"; - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); style.display = "none"; - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); } PerfTestRunner.measureRunsPerSecond({
diff --git a/third_party/WebKit/PerformanceTests/Layout/multicol/lots-of-text-autofill.html b/third_party/WebKit/PerformanceTests/Layout/multicol/lots-of-text-autofill.html index a5ac20a..7a17dca 100644 --- a/third_party/WebKit/PerformanceTests/Layout/multicol/lots-of-text-autofill.html +++ b/third_party/WebKit/PerformanceTests/Layout/multicol/lots-of-text-autofill.html
@@ -656,9 +656,9 @@ function test() { style.display = "block"; - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); style.display = "none"; - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); } PerfTestRunner.measureRunsPerSecond({
diff --git a/third_party/WebKit/PerformanceTests/Layout/multicol/lots-of-text-balanced.html b/third_party/WebKit/PerformanceTests/Layout/multicol/lots-of-text-balanced.html index 1e71362..a44a893 100644 --- a/third_party/WebKit/PerformanceTests/Layout/multicol/lots-of-text-balanced.html +++ b/third_party/WebKit/PerformanceTests/Layout/multicol/lots-of-text-balanced.html
@@ -656,9 +656,9 @@ function test() { style.display = "block"; - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); style.display = "none"; - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); } PerfTestRunner.measureRunsPerSecond({
diff --git a/third_party/WebKit/PerformanceTests/Layout/multicol/tall-content-short-columns-realistic.html b/third_party/WebKit/PerformanceTests/Layout/multicol/tall-content-short-columns-realistic.html index 95f2a977..4dd38ad 100644 --- a/third_party/WebKit/PerformanceTests/Layout/multicol/tall-content-short-columns-realistic.html +++ b/third_party/WebKit/PerformanceTests/Layout/multicol/tall-content-short-columns-realistic.html
@@ -13,13 +13,13 @@ function test() { style.display = "block"; - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); // Do some hit-testing. document.caretRangeFromPoint(10, 10); style.display = "none"; - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); } PerfTestRunner.measureRunsPerSecond({
diff --git a/third_party/WebKit/PerformanceTests/Layout/multicol/tall-content-short-columns.html b/third_party/WebKit/PerformanceTests/Layout/multicol/tall-content-short-columns.html index 23bfe62..06a750c 100644 --- a/third_party/WebKit/PerformanceTests/Layout/multicol/tall-content-short-columns.html +++ b/third_party/WebKit/PerformanceTests/Layout/multicol/tall-content-short-columns.html
@@ -13,13 +13,13 @@ function test() { style.display = "block"; - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); // Do some hit-testing. document.caretRangeFromPoint(10, 10); style.display = "none"; - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); } PerfTestRunner.measureRunsPerSecond({
diff --git a/third_party/WebKit/PerformanceTests/Layout/nested-blocks-with-percent-height-and-max-height.html b/third_party/WebKit/PerformanceTests/Layout/nested-blocks-with-percent-height-and-max-height.html index 27bd023..61cb1d1 100644 --- a/third_party/WebKit/PerformanceTests/Layout/nested-blocks-with-percent-height-and-max-height.html +++ b/third_party/WebKit/PerformanceTests/Layout/nested-blocks-with-percent-height-and-max-height.html
@@ -55,9 +55,9 @@ function test() { style.display = "block"; - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); style.display = "none"; - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); } PerfTestRunner.measureRunsPerSecond({
diff --git a/third_party/WebKit/PerformanceTests/Layout/resources/character_fallback_test.js b/third_party/WebKit/PerformanceTests/Layout/resources/character_fallback_test.js index 9bf43a1..fa0a140 100644 --- a/third_party/WebKit/PerformanceTests/Layout/resources/character_fallback_test.js +++ b/third_party/WebKit/PerformanceTests/Layout/resources/character_fallback_test.js
@@ -21,7 +21,7 @@ while (target.firstChild) target.removeChild(target.firstChild); target.appendChild(document.createTextNode(charSelection)); - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); } function cleanup() {
diff --git a/third_party/WebKit/PerformanceTests/Layout/resources/floats.js b/third_party/WebKit/PerformanceTests/Layout/resources/floats.js index d0dfdec..d37c26b 100644 --- a/third_party/WebKit/PerformanceTests/Layout/resources/floats.js +++ b/third_party/WebKit/PerformanceTests/Layout/resources/floats.js
@@ -49,7 +49,7 @@ var y = Math.floor(Math.random() * height); var el = document.getElementById("float" + x + "_" + y); el.className = toggle(el.className, "float", "float big"); - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); } resetTest(); container.style.display = "none";
diff --git a/third_party/WebKit/PerformanceTests/Layout/resources/large-table-with-collapsed-borders.js b/third_party/WebKit/PerformanceTests/Layout/resources/large-table-with-collapsed-borders.js index f935798..5a9628ed 100644 --- a/third_party/WebKit/PerformanceTests/Layout/resources/large-table-with-collapsed-borders.js +++ b/third_party/WebKit/PerformanceTests/Layout/resources/large-table-with-collapsed-borders.js
@@ -24,7 +24,7 @@ function createTestFunction(width, height, colspan) { return function() { var table = createTable(width, height, colspan); - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); } }
diff --git a/third_party/WebKit/PerformanceTests/Layout/subtree-detaching.html b/third_party/WebKit/PerformanceTests/Layout/subtree-detaching.html index f705c30..97abd50 100644 --- a/third_party/WebKit/PerformanceTests/Layout/subtree-detaching.html +++ b/third_party/WebKit/PerformanceTests/Layout/subtree-detaching.html
@@ -19,7 +19,7 @@ function setup() { wrapper.style.display = "block"; - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); } function runTest() { @@ -28,7 +28,7 @@ var now = PerfTestRunner.now(); wrapper.style.display = "none"; - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); return PerfTestRunner.now() - now; }
diff --git a/third_party/WebKit/PerformanceTests/Layout/vertical-japanese-kokoro-insert.html b/third_party/WebKit/PerformanceTests/Layout/vertical-japanese-kokoro-insert.html index 5ba9274..67507e4e 100644 --- a/third_party/WebKit/PerformanceTests/Layout/vertical-japanese-kokoro-insert.html +++ b/third_party/WebKit/PerformanceTests/Layout/vertical-japanese-kokoro-insert.html
@@ -1612,10 +1612,10 @@ }; function runTest() { - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); var now = PerfTestRunner.now(); insertInto.appendChild(docFragment.cloneNode(true)); - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); var resultTime = PerfTestRunner.now() - now; insertInto.innerHTML = ''; return resultTime;
diff --git a/third_party/WebKit/PerformanceTests/SVG/SvgCubics.html b/third_party/WebKit/PerformanceTests/SVG/SvgCubics.html index bc3615f..6934171 100644 --- a/third_party/WebKit/PerformanceTests/SVG/SvgCubics.html +++ b/third_party/WebKit/PerformanceTests/SVG/SvgCubics.html
@@ -907,7 +907,7 @@ text += ('text on a path! ' + t + ' '); textPath.textContent = text; - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); t++; }, done:function() {
diff --git a/third_party/WebKit/PerformanceTests/SVG/SvgNestedUse.html b/third_party/WebKit/PerformanceTests/SVG/SvgNestedUse.html index e9c54d0..802b714 100644 --- a/third_party/WebKit/PerformanceTests/SVG/SvgNestedUse.html +++ b/third_party/WebKit/PerformanceTests/SVG/SvgNestedUse.html
@@ -64,7 +64,7 @@ document.getElementById("FPS").textContent = (1000 / avg).toFixed(2); unit.setAttribute('transform', 'scale(' + (Math.abs(frame++ % 20 - 10) / 10) + ')'); - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); }; function animate() {
diff --git a/third_party/WebKit/PerformanceTests/ShadowDOM/ChangingClassName.html b/third_party/WebKit/PerformanceTests/ShadowDOM/ChangingClassName.html index a60bf3d2..1b7c631 100644 --- a/third_party/WebKit/PerformanceTests/ShadowDOM/ChangingClassName.html +++ b/third_party/WebKit/PerformanceTests/ShadowDOM/ChangingClassName.html
@@ -47,7 +47,7 @@ nonSelected.appendChild(array[j]); } } - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); } }
diff --git a/third_party/WebKit/PerformanceTests/ShadowDOM/ChangingClassNameShadowDOM.html b/third_party/WebKit/PerformanceTests/ShadowDOM/ChangingClassNameShadowDOM.html index a1098c8..c4c2b41 100644 --- a/third_party/WebKit/PerformanceTests/ShadowDOM/ChangingClassNameShadowDOM.html +++ b/third_party/WebKit/PerformanceTests/ShadowDOM/ChangingClassNameShadowDOM.html
@@ -39,7 +39,7 @@ for (var i = 2; i < 100; ++i) { for (var j = 0; j < nDivs; ++j) array[j].className = (j % i == 0) ? 'selected' : ''; - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); } }
diff --git a/third_party/WebKit/PerformanceTests/ShadowDOM/ChangingSelect.html b/third_party/WebKit/PerformanceTests/ShadowDOM/ChangingSelect.html index 76dfc2af..26d3b54 100644 --- a/third_party/WebKit/PerformanceTests/ShadowDOM/ChangingSelect.html +++ b/third_party/WebKit/PerformanceTests/ShadowDOM/ChangingSelect.html
@@ -42,7 +42,7 @@ for (var i = 0; i < 100; ++i) { for (var j = 0; j < typeNames.length; ++j) { contentSelected.select = '.' + typeNames[j]; - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); } } }
diff --git a/third_party/WebKit/PerformanceTests/ShadowDOM/ChangingSelectWithoutShadow.html b/third_party/WebKit/PerformanceTests/ShadowDOM/ChangingSelectWithoutShadow.html index 01ffa60..b042d1f 100644 --- a/third_party/WebKit/PerformanceTests/ShadowDOM/ChangingSelectWithoutShadow.html +++ b/third_party/WebKit/PerformanceTests/ShadowDOM/ChangingSelectWithoutShadow.html
@@ -47,7 +47,7 @@ else nonSelected.appendChild(array[k]); } - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); } } }
diff --git a/third_party/WebKit/PerformanceTests/ShadowDOM/ContentReprojection.html b/third_party/WebKit/PerformanceTests/ShadowDOM/ContentReprojection.html index c8bb0eb..e5ba374b 100644 --- a/third_party/WebKit/PerformanceTests/ShadowDOM/ContentReprojection.html +++ b/third_party/WebKit/PerformanceTests/ShadowDOM/ContentReprojection.html
@@ -42,7 +42,7 @@ for (var i = 0; i < nLoops; ++i) { host.appendChild(div); host.removeChild(div); - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); } }
diff --git a/third_party/WebKit/PerformanceTests/ShadowDOM/DistributionWithMultipleShadowRoots.html b/third_party/WebKit/PerformanceTests/ShadowDOM/DistributionWithMultipleShadowRoots.html index 4400086..ff3218d 100644 --- a/third_party/WebKit/PerformanceTests/ShadowDOM/DistributionWithMultipleShadowRoots.html +++ b/third_party/WebKit/PerformanceTests/ShadowDOM/DistributionWithMultipleShadowRoots.html
@@ -42,7 +42,7 @@ for (var i = 0; i < nLoops; ++i) { host.appendChild(div); host.removeChild(div); - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); } }
diff --git a/third_party/WebKit/PerformanceTests/ShadowDOM/MultipleInsertionPoints.html b/third_party/WebKit/PerformanceTests/ShadowDOM/MultipleInsertionPoints.html index 17a633de..aa293077 100644 --- a/third_party/WebKit/PerformanceTests/ShadowDOM/MultipleInsertionPoints.html +++ b/third_party/WebKit/PerformanceTests/ShadowDOM/MultipleInsertionPoints.html
@@ -50,7 +50,7 @@ for (var i = 0; i < nLoops; ++i) { host.appendChild(div); host.removeChild(div); - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); } }
diff --git a/third_party/WebKit/PerformanceTests/ShadowDOM/ShadowReprojection.html b/third_party/WebKit/PerformanceTests/ShadowDOM/ShadowReprojection.html index 35b25404..d9f6229 100644 --- a/third_party/WebKit/PerformanceTests/ShadowDOM/ShadowReprojection.html +++ b/third_party/WebKit/PerformanceTests/ShadowDOM/ShadowReprojection.html
@@ -42,7 +42,7 @@ for (var i = 0; i < nLoops; ++i) { host.appendChild(div); host.removeChild(div); - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); } }
diff --git a/third_party/WebKit/PerformanceTests/ShadowDOM/SmallDistributionWithLayout.html b/third_party/WebKit/PerformanceTests/ShadowDOM/SmallDistributionWithLayout.html index 347fd10..14ef0643 100644 --- a/third_party/WebKit/PerformanceTests/ShadowDOM/SmallDistributionWithLayout.html +++ b/third_party/WebKit/PerformanceTests/ShadowDOM/SmallDistributionWithLayout.html
@@ -37,7 +37,7 @@ for (var i = 0; i < nLoops; ++i) { host.appendChild(div); host.removeChild(div); - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); } }
diff --git a/third_party/WebKit/PerformanceTests/ShadowDOM/shadow-style-share-attr-selectors.html b/third_party/WebKit/PerformanceTests/ShadowDOM/shadow-style-share-attr-selectors.html index 4ead003..71b4888 100644 --- a/third_party/WebKit/PerformanceTests/ShadowDOM/shadow-style-share-attr-selectors.html +++ b/third_party/WebKit/PerformanceTests/ShadowDOM/shadow-style-share-attr-selectors.html
@@ -24,7 +24,7 @@ list.appendChild(host); } while (++i < listSize); - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); return PerfTestRunner.now() - start; } });
diff --git a/third_party/WebKit/PerformanceTests/ShadowDOM/shadow-style-share-media-query.html b/third_party/WebKit/PerformanceTests/ShadowDOM/shadow-style-share-media-query.html index c851736..8f2d952 100644 --- a/third_party/WebKit/PerformanceTests/ShadowDOM/shadow-style-share-media-query.html +++ b/third_party/WebKit/PerformanceTests/ShadowDOM/shadow-style-share-media-query.html
@@ -19,7 +19,7 @@ list.appendChild(host); } while (++i < listSize); - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); return PerfTestRunner.now() - start; } });
diff --git a/third_party/WebKit/PerformanceTests/ShadowDOM/shadow-style-share-with-distribution.html b/third_party/WebKit/PerformanceTests/ShadowDOM/shadow-style-share-with-distribution.html index 0513cec9..10d2494 100644 --- a/third_party/WebKit/PerformanceTests/ShadowDOM/shadow-style-share-with-distribution.html +++ b/third_party/WebKit/PerformanceTests/ShadowDOM/shadow-style-share-with-distribution.html
@@ -29,7 +29,7 @@ } while (++i < listSize); document.querySelector('#list').appendChild(frag); - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); return PerfTestRunner.now() - start; }, done: function() {
diff --git a/third_party/WebKit/PerformanceTests/ShadowDOM/shadow-style-share.html b/third_party/WebKit/PerformanceTests/ShadowDOM/shadow-style-share.html index 9a0f7921..7935cbb 100644 --- a/third_party/WebKit/PerformanceTests/ShadowDOM/shadow-style-share.html +++ b/third_party/WebKit/PerformanceTests/ShadowDOM/shadow-style-share.html
@@ -24,7 +24,7 @@ list.appendChild(host); } while (++i < listSize); - PerfTestRunner.forceLayoutOrFullFrame(); + PerfTestRunner.forceLayout(); return PerfTestRunner.now() - start; } });
diff --git a/third_party/WebKit/PerformanceTests/resources/runner.js b/third_party/WebKit/PerformanceTests/resources/runner.js index 11a0636..ff74d8d 100644 --- a/third_party/WebKit/PerformanceTests/resources/runner.js +++ b/third_party/WebKit/PerformanceTests/resources/runner.js
@@ -137,21 +137,8 @@ finish(); } - // Force a layout (including style recalc) if window.fullFrameMeasurement is false, - // or a full frame update (including style recalc, layout, compositing update and paint invalidation, - // not including painting). - PerfTestRunner.forceLayoutOrFullFrame = function(doc) { + PerfTestRunner.forceLayout = function(doc) { doc = doc || document; - // Forcing full frame is only feasible when window.internals is available. - if (window.fullFrameMeasurement) { - if (window.internals) - internals.forceCompositingUpdate(doc); - else - PerfTestRunner.logFatalError('window.internals API is required for full frame measurement.'); - return; - } - - // Otherwise just force style recalc and layout without compositing update and paint invalidation. if (doc.body) doc.body.offsetHeight; else if (doc.documentElement) @@ -334,7 +321,7 @@ for (var chunkIndex = 0; chunkIndex < chunks.length; chunkIndex++) { iframe.contentDocument.write(chunks[chunkIndex]); - PerfTestRunner.forceLayoutOrFullFrame(iframe.contentDocument); + PerfTestRunner.forceLayout(iframe.contentDocument); } iframe.contentDocument.close();
diff --git a/third_party/WebKit/Source/bindings/core/v8/ActiveDOMCallback.cpp b/third_party/WebKit/Source/bindings/core/v8/ActiveDOMCallback.cpp index ce03d62..392f9bc0 100644 --- a/third_party/WebKit/Source/bindings/core/v8/ActiveDOMCallback.cpp +++ b/third_party/WebKit/Source/bindings/core/v8/ActiveDOMCallback.cpp
@@ -55,7 +55,7 @@ { ExecutionContext* context = executionContext(); if (context && context->isWorkerGlobalScope()) { - WorkerScriptController* scriptController = toWorkerGlobalScope(context)->script(); + WorkerOrWorkletScriptController* scriptController = toWorkerGlobalScope(context)->script(); if (!scriptController || scriptController->isExecutionForbidden() || scriptController->isExecutionTerminating()) return true; }
diff --git a/third_party/WebKit/Source/bindings/core/v8/ModuleProxy.cpp b/third_party/WebKit/Source/bindings/core/v8/ModuleProxy.cpp deleted file mode 100644 index fe51218..0000000 --- a/third_party/WebKit/Source/bindings/core/v8/ModuleProxy.cpp +++ /dev/null
@@ -1,17 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "bindings/core/v8/ModuleProxy.h" - -#include "wtf/StdLibExtras.h" - -namespace blink { - -ModuleProxy& ModuleProxy::moduleProxy() -{ - DEFINE_STATIC_LOCAL(ModuleProxy, moduleProxy, ()); - return moduleProxy; -} - -} // namespace blink
diff --git a/third_party/WebKit/Source/bindings/core/v8/ModuleProxy.h b/third_party/WebKit/Source/bindings/core/v8/ModuleProxy.h deleted file mode 100644 index 781dfc3..0000000 --- a/third_party/WebKit/Source/bindings/core/v8/ModuleProxy.h +++ /dev/null
@@ -1,26 +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 ModuleProxy_h -#define ModuleProxy_h - -#include "wtf/Allocator.h" -#include <v8.h> - -namespace blink { - -// A proxy class to invoke functions implemented in bindings/modules -// from bindings/core. -class ModuleProxy { - USING_FAST_MALLOC(ModuleProxy); -public: - static ModuleProxy& moduleProxy(); - -private: - ModuleProxy() { } -}; - -} // namespace blink - -#endif // ModuleProxy_h
diff --git a/third_party/WebKit/Source/bindings/core/v8/NPV8Object.cpp b/third_party/WebKit/Source/bindings/core/v8/NPV8Object.cpp index 34e3f9a..c60f1b9 100644 --- a/third_party/WebKit/Source/bindings/core/v8/NPV8Object.cpp +++ b/third_party/WebKit/Source/bindings/core/v8/NPV8Object.cpp
@@ -91,10 +91,7 @@ LocalDOMWindow* window = object->rootObject; if (!window || !window->frame()) return nullptr; - ScriptState* scriptState = ScriptState::forMainWorld(window->frame()); - if (!scriptState->contextIsValid()) - return nullptr; - return scriptState; + return ScriptState::forMainWorld(window->frame()); } static PassOwnPtr<v8::Local<v8::Value>[]> createValueListFromVariantArgs(v8::Isolate* isolate, const NPVariant* arguments, uint32_t argumentCount, NPObject* owner)
diff --git a/third_party/WebKit/Source/bindings/core/v8/PrivateScriptRunner.cpp b/third_party/WebKit/Source/bindings/core/v8/PrivateScriptRunner.cpp index f5eca22..87cc553 100644 --- a/third_party/WebKit/Source/bindings/core/v8/PrivateScriptRunner.cpp +++ b/third_party/WebKit/Source/bindings/core/v8/PrivateScriptRunner.cpp
@@ -232,7 +232,7 @@ v8::HandleScope handleScope(toIsolate(document)); ScriptState* scriptState = ScriptState::forWorld(document->contextDocument()->frame(), DOMWrapperWorld::privateScriptIsolatedWorld()); - if (!scriptState->contextIsValid()) + if (!scriptState) return v8::Local<v8::Value>(); ScriptState::Scope scope(scriptState);
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptController.cpp b/third_party/WebKit/Source/bindings/core/v8/ScriptController.cpp index 8c16730..eb0cc560 100644 --- a/third_party/WebKit/Source/bindings/core/v8/ScriptController.cpp +++ b/third_party/WebKit/Source/bindings/core/v8/ScriptController.cpp
@@ -239,7 +239,7 @@ bool ScriptController::bindToWindowObject(LocalFrame* frame, const String& key, NPObject* object) { ScriptState* scriptState = ScriptState::forMainWorld(frame); - if (!scriptState->contextIsValid()) + if (!scriptState) return false; ScriptState::Scope scope(scriptState); @@ -251,18 +251,19 @@ void ScriptController::enableEval() { - if (!m_windowProxyManager->mainWorldProxy()->isContextInitialized()) - return; v8::HandleScope handleScope(isolate()); - m_windowProxyManager->mainWorldProxy()->context()->AllowCodeGenerationFromStrings(true); + v8::Local<v8::Context> v8Context = m_windowProxyManager->mainWorldProxy()->contextIfInitialized(); + if (v8Context.IsEmpty()) + return; + v8Context->AllowCodeGenerationFromStrings(true); } void ScriptController::disableEval(const String& errorMessage) { - if (!m_windowProxyManager->mainWorldProxy()->isContextInitialized()) - return; v8::HandleScope handleScope(isolate()); - v8::Local<v8::Context> v8Context = m_windowProxyManager->mainWorldProxy()->context(); + v8::Local<v8::Context> v8Context = m_windowProxyManager->mainWorldProxy()->contextIfInitialized(); + if (v8Context.IsEmpty()) + return; v8Context->AllowCodeGenerationFromStrings(false); v8Context->SetErrorMessageForCodeGenerationFromStrings(v8String(isolate(), errorMessage)); } @@ -348,7 +349,7 @@ static NPObject* createScriptObject(LocalFrame* frame, v8::Isolate* isolate) { ScriptState* scriptState = ScriptState::forMainWorld(frame); - if (!scriptState->contextIsValid()) + if (!scriptState) return createNoScriptObject(); ScriptState::Scope scope(scriptState); @@ -386,7 +387,7 @@ return createNoScriptObject(); ScriptState* scriptState = ScriptState::forMainWorld(frame()); - if (!scriptState->contextIsValid()) + if (!scriptState) return createNoScriptObject(); ScriptState::Scope scope(scriptState); @@ -553,7 +554,7 @@ m_sourceURL = &sourceURL; ScriptState* scriptState = ScriptState::forMainWorld(frame()); - if (!scriptState->contextIsValid()) + if (!scriptState) return v8::Local<v8::Value>(); v8::EscapableHandleScope handleScope(isolate()); ScriptState::Scope scope(scriptState);
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptState.cpp b/third_party/WebKit/Source/bindings/core/v8/ScriptState.cpp index e46ccfe..489cdb8e 100644 --- a/third_party/WebKit/Source/bindings/core/v8/ScriptState.cpp +++ b/third_party/WebKit/Source/bindings/core/v8/ScriptState.cpp
@@ -135,9 +135,13 @@ ScriptState* ScriptState::forWorld(LocalFrame* frame, DOMWrapperWorld& world) { ASSERT(frame); - v8::Isolate* isolate = toIsolate(frame); - v8::HandleScope handleScope(isolate); - return ScriptState::from(toV8ContextEvenIfDetached(frame, world)); + v8::HandleScope handleScope(toIsolate(frame)); + v8::Local<v8::Context> context = toV8Context(frame, world); + if (context.IsEmpty()) + return nullptr; + ScriptState* scriptState = ScriptState::from(context); + ASSERT(scriptState->contextIsValid()); + return scriptState; } }
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptState.h b/third_party/WebKit/Source/bindings/core/v8/ScriptState.h index 41fbed0..2988c0c 100644 --- a/third_party/WebKit/Source/bindings/core/v8/ScriptState.h +++ b/third_party/WebKit/Source/bindings/core/v8/ScriptState.h
@@ -79,8 +79,8 @@ return scriptState; } - // The context of the returned ScriptState may have been already detached. - // You must check scriptState->contextIsValid() before using the context. + // These methods can return nullptr if the context associated with the + // ScriptState has already been detached. static ScriptState* forMainWorld(LocalFrame*); static ScriptState* forWorld(LocalFrame*, DOMWrapperWorld&);
diff --git a/third_party/WebKit/Source/bindings/core/v8/SerializedScriptValueTest.cpp b/third_party/WebKit/Source/bindings/core/v8/SerializedScriptValueTest.cpp index 393bf9c..db3e4c0 100644 --- a/third_party/WebKit/Source/bindings/core/v8/SerializedScriptValueTest.cpp +++ b/third_party/WebKit/Source/bindings/core/v8/SerializedScriptValueTest.cpp
@@ -10,8 +10,7 @@ #include "bindings/core/v8/V8BindingForTesting.h" #include "bindings/core/v8/V8File.h" #include "core/fileapi/File.h" -#include "public/platform/Platform.h" -#include "public/platform/WebUnitTestSupport.h" +#include "platform/testing/UnitTestHelpers.h" #include "testing/gtest/include/gtest/gtest.h" namespace blink { @@ -32,7 +31,7 @@ TEST_F(SerializedScriptValueTest, UserSelectedFile) { - String filePath = Platform::current()->unitTestSupport()->webKitRootDir(); + String filePath = testing::blinkRootDir(); filePath.append("/Source/bindings/core/v8/SerializedScriptValueTest.cpp"); File* originalFile = File::create(filePath); ASSERT_TRUE(originalFile->hasBackingFile());
diff --git a/third_party/WebKit/Source/bindings/core/v8/ToV8.cpp b/third_party/WebKit/Source/bindings/core/v8/ToV8.cpp index a8cd968..bafa276d 100644 --- a/third_party/WebKit/Source/bindings/core/v8/ToV8.cpp +++ b/third_party/WebKit/Source/bindings/core/v8/ToV8.cpp
@@ -50,7 +50,7 @@ if (UNLIKELY(!impl)) return v8::Null(isolate); - WorkerScriptController* script = impl->script(); + WorkerOrWorkletScriptController* script = impl->script(); if (!script) return v8::Null(isolate);
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8Binding.cpp b/third_party/WebKit/Source/bindings/core/v8/V8Binding.cpp index b4830c5f..d816d9b 100644 --- a/third_party/WebKit/Source/bindings/core/v8/V8Binding.cpp +++ b/third_party/WebKit/Source/bindings/core/v8/V8Binding.cpp
@@ -43,7 +43,7 @@ #include "bindings/core/v8/V8WorkerGlobalScope.h" #include "bindings/core/v8/V8XPathNSResolver.h" #include "bindings/core/v8/WindowProxy.h" -#include "bindings/core/v8/WorkerScriptController.h" +#include "bindings/core/v8/WorkerOrWorkletScriptController.h" #include "bindings/core/v8/custom/V8CustomXPathNSResolver.h" #include "core/dom/Document.h" #include "core/dom/Element.h" @@ -777,7 +777,7 @@ if (LocalFrame* frame = toDocument(context)->frame()) return toV8Context(frame, world); } else if (context->isWorkerGlobalScope()) { - if (WorkerScriptController* script = toWorkerGlobalScope(context)->script()) { + if (WorkerOrWorkletScriptController* script = toWorkerGlobalScope(context)->script()) { if (script->scriptState()->contextIsValid()) return script->scriptState()->context(); } @@ -790,6 +790,8 @@ if (!frame) return v8::Local<v8::Context>(); v8::Local<v8::Context> context = toV8ContextEvenIfDetached(frame, world); + if (context.IsEmpty()) + return v8::Local<v8::Context>(); ScriptState* scriptState = ScriptState::from(context); if (scriptState->contextIsValid()) { ASSERT(toFrameIfNotDetached(context) == frame); @@ -801,7 +803,7 @@ v8::Local<v8::Context> toV8ContextEvenIfDetached(Frame* frame, DOMWrapperWorld& world) { ASSERT(frame); - return frame->windowProxy(world)->context(); + return frame->windowProxy(world)->contextIfInitialized(); } void crashIfIsolateIsDead(v8::Isolate* isolate)
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8Initializer.cpp b/third_party/WebKit/Source/bindings/core/v8/V8Initializer.cpp index db2d6b93..60a08f4 100644 --- a/third_party/WebKit/Source/bindings/core/v8/V8Initializer.cpp +++ b/third_party/WebKit/Source/bindings/core/v8/V8Initializer.cpp
@@ -41,7 +41,7 @@ #include "bindings/core/v8/V8Location.h" #include "bindings/core/v8/V8PerContextData.h" #include "bindings/core/v8/V8Window.h" -#include "bindings/core/v8/WorkerScriptController.h" +#include "bindings/core/v8/WorkerOrWorkletScriptController.h" #include "core/dom/Document.h" #include "core/dom/ExceptionCode.h" #include "core/fetch/AccessControlStatus.h" @@ -287,7 +287,7 @@ return; ASSERT(executionContext->isWorkerGlobalScope()); - WorkerScriptController* scriptController = toWorkerGlobalScope(executionContext)->script(); + WorkerOrWorkletScriptController* scriptController = toWorkerGlobalScope(executionContext)->script(); ASSERT(scriptController); promiseRejectHandler(data, *scriptController->rejectedPromises(), String());
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8PerContextData.cpp b/third_party/WebKit/Source/bindings/core/v8/V8PerContextData.cpp index 50cd207..60cea9d5 100644 --- a/third_party/WebKit/Source/bindings/core/v8/V8PerContextData.cpp +++ b/third_party/WebKit/Source/bindings/core/v8/V8PerContextData.cpp
@@ -115,7 +115,10 @@ return v8::Local<v8::Function>(); } - v8::Local<v8::Object> prototypeObject = interfaceObject->Get(currentContext, v8AtomicString(m_isolate, "prototype")).ToLocalChecked().As<v8::Object>(); + v8::Local<v8::Value> prototypeValue; + if (!interfaceObject->Get(currentContext, v8AtomicString(m_isolate, "prototype")).ToLocal(&prototypeValue) || !prototypeValue->IsObject()) + return v8::Local<v8::Function>(); + v8::Local<v8::Object> prototypeObject = prototypeValue.As<v8::Object>(); if (prototypeObject->InternalFieldCount() == v8PrototypeInternalFieldcount && type->wrapperTypePrototype == WrapperTypeInfo::WrapperTypeObjectPrototype) prototypeObject->SetAlignedPointerInInternalField(v8PrototypeTypeIndex, const_cast<WrapperTypeInfo*>(type));
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8WorkerGlobalScopeEventListener.cpp b/third_party/WebKit/Source/bindings/core/v8/V8WorkerGlobalScopeEventListener.cpp index 3b8db4b4..ceaa250 100644 --- a/third_party/WebKit/Source/bindings/core/v8/V8WorkerGlobalScopeEventListener.cpp +++ b/third_party/WebKit/Source/bindings/core/v8/V8WorkerGlobalScopeEventListener.cpp
@@ -36,7 +36,7 @@ #include "bindings/core/v8/V8EventTarget.h" #include "bindings/core/v8/V8GCController.h" #include "bindings/core/v8/V8ScriptRunner.h" -#include "bindings/core/v8/WorkerScriptController.h" +#include "bindings/core/v8/WorkerOrWorkletScriptController.h" #include "core/inspector/InspectorInstrumentation.h" #include "core/inspector/InspectorTraceEvents.h" #include "core/workers/WorkerGlobalScope.h" @@ -54,7 +54,7 @@ // See issue 889829. RefPtrWillBeRawPtr<V8AbstractEventListener> protect(this); - WorkerScriptController* script = toWorkerGlobalScope(scriptState->executionContext())->script(); + WorkerOrWorkletScriptController* script = toWorkerGlobalScope(scriptState->executionContext())->script(); if (!script) return;
diff --git a/third_party/WebKit/Source/bindings/core/v8/WindowProxy.h b/third_party/WebKit/Source/bindings/core/v8/WindowProxy.h index c21737b..fbcb3f4 100644 --- a/third_party/WebKit/Source/bindings/core/v8/WindowProxy.h +++ b/third_party/WebKit/Source/bindings/core/v8/WindowProxy.h
@@ -58,7 +58,7 @@ ~WindowProxy(); DECLARE_TRACE(); - v8::Local<v8::Context> context() const { return m_scriptState ? m_scriptState->context() : v8::Local<v8::Context>(); } + v8::Local<v8::Context> contextIfInitialized() const { return m_scriptState ? m_scriptState->context() : v8::Local<v8::Context>(); } ScriptState* scriptState() const { return m_scriptState.get(); } // Update document object of the frame.
diff --git a/third_party/WebKit/Source/bindings/core/v8/WorkerScriptController.cpp b/third_party/WebKit/Source/bindings/core/v8/WorkerOrWorkletScriptController.cpp similarity index 83% rename from third_party/WebKit/Source/bindings/core/v8/WorkerScriptController.cpp rename to third_party/WebKit/Source/bindings/core/v8/WorkerOrWorkletScriptController.cpp index 4f5668b..26c75c3d 100644 --- a/third_party/WebKit/Source/bindings/core/v8/WorkerScriptController.cpp +++ b/third_party/WebKit/Source/bindings/core/v8/WorkerOrWorkletScriptController.cpp
@@ -28,7 +28,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "bindings/core/v8/WorkerScriptController.h" +#include "bindings/core/v8/WorkerOrWorkletScriptController.h" #include "bindings/core/v8/ScriptSourceCode.h" #include "bindings/core/v8/ScriptValue.h" @@ -54,10 +54,10 @@ namespace blink { -class WorkerScriptController::ExecutionState final { +class WorkerOrWorkletScriptController::ExecutionState final { STACK_ALLOCATED(); public: - explicit ExecutionState(WorkerScriptController* controller) + explicit ExecutionState(WorkerOrWorkletScriptController* controller) : hadException(false) , lineNumber(0) , columnNumber(0) @@ -87,26 +87,26 @@ RefPtrWillBeMember<ErrorEvent> m_errorEventFromImportedScript; // A ExecutionState context is stack allocated by - // WorkerScriptController::evaluate(), with the contoller using it + // WorkerOrWorkletScriptController::evaluate(), with the contoller using it // during script evaluation. To handle nested evaluate() uses, // ExecutionStates are chained together; // |m_outerState| keeps a pointer to the context object one level out // (or 0, if outermost.) Upon return from evaluate(), the - // WorkerScriptController's ExecutionState is popped and the previous one - // restored (see above dtor.) + // WorkerOrWorkletScriptController's ExecutionState is popped and the + // previous one restored (see above dtor.) // // With Oilpan, |m_outerState| isn't traced. It'll be "up the stack" // and its fields will be traced when scanning the stack. - RawPtrWillBeMember<WorkerScriptController> m_controller; + RawPtrWillBeMember<WorkerOrWorkletScriptController> m_controller; ExecutionState* m_outerState; }; -PassOwnPtrWillBeRawPtr<WorkerScriptController> WorkerScriptController::create(WorkerGlobalScope* workerGlobalScope, v8::Isolate* isolate) +PassOwnPtrWillBeRawPtr<WorkerOrWorkletScriptController> WorkerOrWorkletScriptController::create(WorkerGlobalScope* workerGlobalScope, v8::Isolate* isolate) { - return adoptPtrWillBeNoop(new WorkerScriptController(workerGlobalScope, isolate)); + return adoptPtrWillBeNoop(new WorkerOrWorkletScriptController(workerGlobalScope, isolate)); } -WorkerScriptController::WorkerScriptController(WorkerGlobalScope* workerGlobalScope, v8::Isolate* isolate) +WorkerOrWorkletScriptController::WorkerOrWorkletScriptController(WorkerGlobalScope* workerGlobalScope, v8::Isolate* isolate) : m_workerGlobalScope(workerGlobalScope) , m_executionForbidden(false) , m_executionScheduledToTerminate(false) @@ -117,12 +117,12 @@ m_world = DOMWrapperWorld::create(isolate, WorkerWorldId); } -WorkerScriptController::~WorkerScriptController() +WorkerOrWorkletScriptController::~WorkerOrWorkletScriptController() { ASSERT(!m_rejectedPromises); } -void WorkerScriptController::dispose() +void WorkerOrWorkletScriptController::dispose() { m_rejectedPromises->dispose(); m_rejectedPromises.release(); @@ -133,7 +133,7 @@ m_scriptState->disposePerContextData(); } -bool WorkerScriptController::initializeContextIfNeeded() +bool WorkerOrWorkletScriptController::initializeContextIfNeeded() { v8::HandleScope handleScope(isolate()); @@ -169,12 +169,12 @@ return v8CallBoolean(globalObject->SetPrototype(context, jsWorkerGlobalScope)); } -v8::Isolate* WorkerScriptController::isolate() const +v8::Isolate* WorkerOrWorkletScriptController::isolate() const { return m_workerGlobalScope->thread()->isolate(); } -ScriptValue WorkerScriptController::evaluate(const String& script, const String& fileName, const TextPosition& scriptStartPosition, CachedMetadataHandler* cacheHandler, V8CacheOptions v8CacheOptions) +ScriptValue WorkerOrWorkletScriptController::evaluate(const String& script, const String& fileName, const TextPosition& scriptStartPosition, CachedMetadataHandler* cacheHandler, V8CacheOptions v8CacheOptions) { if (!initializeContextIfNeeded()) return ScriptValue(); @@ -226,7 +226,7 @@ return ScriptValue(m_scriptState.get(), result); } -bool WorkerScriptController::evaluate(const ScriptSourceCode& sourceCode, RefPtrWillBeRawPtr<ErrorEvent>* errorEvent, CachedMetadataHandler* cacheHandler, V8CacheOptions v8CacheOptions) +bool WorkerOrWorkletScriptController::evaluate(const ScriptSourceCode& sourceCode, RefPtrWillBeRawPtr<ErrorEvent>* errorEvent, CachedMetadataHandler* cacheHandler, V8CacheOptions v8CacheOptions) { if (isExecutionForbidden()) return false; @@ -261,7 +261,7 @@ return true; } -void WorkerScriptController::willScheduleExecutionTermination() +void WorkerOrWorkletScriptController::willScheduleExecutionTermination() { // The mutex provides a memory barrier to ensure that once // termination is scheduled, isExecutionTerminating will @@ -270,31 +270,31 @@ m_executionScheduledToTerminate = true; } -bool WorkerScriptController::isExecutionTerminating() const +bool WorkerOrWorkletScriptController::isExecutionTerminating() const { // See comments in willScheduleExecutionTermination regarding mutex usage. MutexLocker locker(m_scheduledTerminationMutex); return m_executionScheduledToTerminate; } -void WorkerScriptController::forbidExecution() +void WorkerOrWorkletScriptController::forbidExecution() { ASSERT(m_workerGlobalScope->isContextThread()); m_executionForbidden = true; } -bool WorkerScriptController::isExecutionForbidden() const +bool WorkerOrWorkletScriptController::isExecutionForbidden() const { ASSERT(m_workerGlobalScope->isContextThread()); return m_executionForbidden; } -void WorkerScriptController::disableEval(const String& errorMessage) +void WorkerOrWorkletScriptController::disableEval(const String& errorMessage) { m_disableEvalPending = errorMessage; } -void WorkerScriptController::rethrowExceptionFromImportedScript(PassRefPtrWillBeRawPtr<ErrorEvent> errorEvent, ExceptionState& exceptionState) +void WorkerOrWorkletScriptController::rethrowExceptionFromImportedScript(PassRefPtrWillBeRawPtr<ErrorEvent> errorEvent, ExceptionState& exceptionState) { const String& errorMessage = errorEvent->message(); if (m_executionState) @@ -302,7 +302,7 @@ exceptionState.rethrowV8Exception(V8ThrowException::createGeneralError(isolate(), errorMessage)); } -DEFINE_TRACE(WorkerScriptController) +DEFINE_TRACE(WorkerOrWorkletScriptController) { visitor->trace(m_workerGlobalScope); visitor->trace(m_rejectedPromises);
diff --git a/third_party/WebKit/Source/bindings/core/v8/WorkerScriptController.h b/third_party/WebKit/Source/bindings/core/v8/WorkerOrWorkletScriptController.h similarity index 82% rename from third_party/WebKit/Source/bindings/core/v8/WorkerScriptController.h rename to third_party/WebKit/Source/bindings/core/v8/WorkerOrWorkletScriptController.h index f4e53bf..91c8793 100644 --- a/third_party/WebKit/Source/bindings/core/v8/WorkerScriptController.h +++ b/third_party/WebKit/Source/bindings/core/v8/WorkerOrWorkletScriptController.h
@@ -28,8 +28,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef WorkerScriptController_h -#define WorkerScriptController_h +#ifndef WorkerOrWorkletScriptController_h +#define WorkerOrWorkletScriptController_h #include "bindings/core/v8/RejectedPromises.h" #include "bindings/core/v8/ScriptValue.h" @@ -50,12 +50,12 @@ class ScriptSourceCode; class WorkerGlobalScope; -class CORE_EXPORT WorkerScriptController : public NoBaseWillBeGarbageCollectedFinalized<WorkerScriptController> { - USING_FAST_MALLOC_WILL_BE_REMOVED(WorkerScriptController); - WTF_MAKE_NONCOPYABLE(WorkerScriptController); +class CORE_EXPORT WorkerOrWorkletScriptController : public NoBaseWillBeGarbageCollectedFinalized<WorkerOrWorkletScriptController> { + USING_FAST_MALLOC_WILL_BE_REMOVED(WorkerOrWorkletScriptController); + WTF_MAKE_NONCOPYABLE(WorkerOrWorkletScriptController); public: - static PassOwnPtrWillBeRawPtr<WorkerScriptController> create(WorkerGlobalScope*, v8::Isolate*); - virtual ~WorkerScriptController(); + static PassOwnPtrWillBeRawPtr<WorkerOrWorkletScriptController> create(WorkerGlobalScope*, v8::Isolate*); + virtual ~WorkerOrWorkletScriptController(); void dispose(); bool isExecutionForbidden() const; @@ -70,12 +70,11 @@ // Used by WorkerThread: bool initializeContextIfNeeded(); - // Async request to terminate future JavaScript execution on the - // worker thread. JavaScript evaluation exits with a - // non-continuable exception and WorkerScriptController calls - // forbidExecution to prevent further JavaScript execution. Use - // forbidExecution()/isExecutionForbidden() to guard against - // reentry into JavaScript. + // Async request to terminate future JavaScript execution on the worker + // thread. JavaScript evaluation exits with a non-continuable exception and + // WorkerOrWorkletScriptController calls forbidExecution to prevent further + // JavaScript execution. Use forbidExecution()/isExecutionForbidden() to + // guard against reentry into JavaScript. void willScheduleExecutionTermination(); // Used by WorkerGlobalScope: @@ -95,7 +94,7 @@ bool isContextInitialized() const { return m_scriptState && !!m_scriptState->perContextData(); } private: - WorkerScriptController(WorkerGlobalScope*, v8::Isolate*); + WorkerOrWorkletScriptController(WorkerGlobalScope*, v8::Isolate*); class ExecutionState; v8::Isolate* isolate() const; @@ -124,4 +123,4 @@ } // namespace blink -#endif // WorkerScriptController_h +#endif // WorkerOrWorkletScriptController_h
diff --git a/third_party/WebKit/Source/bindings/core/v8/v8.gypi b/third_party/WebKit/Source/bindings/core/v8/v8.gypi index 781f2b5d..bd534eb 100644 --- a/third_party/WebKit/Source/bindings/core/v8/v8.gypi +++ b/third_party/WebKit/Source/bindings/core/v8/v8.gypi
@@ -38,8 +38,6 @@ 'ExceptionStatePlaceholder.h', 'Iterable.h', 'Maplike.h', - 'ModuleProxy.cpp', - 'ModuleProxy.h', 'NativeValueTraits.h', 'NPV8Object.cpp', 'NPV8Object.h', @@ -173,8 +171,8 @@ 'WindowProxy.h', 'WindowProxyManager.cpp', 'WindowProxyManager.h', - 'WorkerScriptController.cpp', - 'WorkerScriptController.h', + 'WorkerOrWorkletScriptController.cpp', + 'WorkerOrWorkletScriptController.h', 'WrapperTypeInfo.cpp', 'WrapperTypeInfo.h', 'npruntime.cpp',
diff --git a/third_party/WebKit/Source/bindings/modules/v8/ModuleBindingsInitializer.cpp b/third_party/WebKit/Source/bindings/modules/v8/ModuleBindingsInitializer.cpp index 82b32d68..d13e81f 100644 --- a/third_party/WebKit/Source/bindings/modules/v8/ModuleBindingsInitializer.cpp +++ b/third_party/WebKit/Source/bindings/modules/v8/ModuleBindingsInitializer.cpp
@@ -4,7 +4,6 @@ #include "bindings/modules/v8/ModuleBindingsInitializer.h" -#include "bindings/core/v8/ModuleProxy.h" #include "bindings/core/v8/V8PerIsolateData.h" #include "bindings/modules/v8/SerializedScriptValueForModulesFactory.h" #include "core/dom/ExecutionContext.h"
diff --git a/third_party/WebKit/Source/bindings/templates/attributes.cpp b/third_party/WebKit/Source/bindings/templates/attributes.cpp index 441b774c..049777d6 100644 --- a/third_party/WebKit/Source/bindings/templates/attributes.cpp +++ b/third_party/WebKit/Source/bindings/templates/attributes.cpp
@@ -415,10 +415,10 @@ v8::HandleScope handleScope(toIsolate(frame)); ScriptForbiddenScope::AllowUserAgentScript script; ScriptState* scriptState = ScriptState::forWorld(frame, DOMWrapperWorld::privateScriptIsolatedWorld()); - if (!scriptState->contextIsValid()) + if (!scriptState) return false; ScriptState* scriptStateInUserScript = ScriptState::forMainWorld(frame); - if (!scriptState->contextIsValid()) + if (!scriptStateInUserScript) return false; ScriptState::Scope scope(scriptState); @@ -450,10 +450,10 @@ v8::HandleScope handleScope(toIsolate(frame)); ScriptForbiddenScope::AllowUserAgentScript script; ScriptState* scriptState = ScriptState::forWorld(frame, DOMWrapperWorld::privateScriptIsolatedWorld()); - if (!scriptState->contextIsValid()) + if (!scriptState) return false; ScriptState* scriptStateInUserScript = ScriptState::forMainWorld(frame); - if (!scriptState->contextIsValid()) + if (!scriptStateInUserScript) return false; ScriptState::Scope scope(scriptState);
diff --git a/third_party/WebKit/Source/bindings/templates/methods.cpp b/third_party/WebKit/Source/bindings/templates/methods.cpp index 11ddba1..412cbfc 100644 --- a/third_party/WebKit/Source/bindings/templates/methods.cpp +++ b/third_party/WebKit/Source/bindings/templates/methods.cpp
@@ -593,10 +593,10 @@ v8::HandleScope handleScope(toIsolate(frame)); ScriptForbiddenScope::AllowUserAgentScript script; ScriptState* scriptState = ScriptState::forWorld(frame, DOMWrapperWorld::privateScriptIsolatedWorld()); - if (!scriptState->contextIsValid()) + if (!scriptState) return false; ScriptState* scriptStateInUserScript = ScriptState::forMainWorld(frame); - if (!scriptState->contextIsValid()) + if (!scriptStateInUserScript) return false; ScriptState::Scope scope(scriptState);
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/V8TestInterface.cpp b/third_party/WebKit/Source/bindings/tests/results/core/V8TestInterface.cpp index b40583ce..13df3f8 100644 --- a/third_party/WebKit/Source/bindings/tests/results/core/V8TestInterface.cpp +++ b/third_party/WebKit/Source/bindings/tests/results/core/V8TestInterface.cpp
@@ -3358,10 +3358,10 @@ v8::HandleScope handleScope(toIsolate(frame)); ScriptForbiddenScope::AllowUserAgentScript script; ScriptState* scriptState = ScriptState::forWorld(frame, DOMWrapperWorld::privateScriptIsolatedWorld()); - if (!scriptState->contextIsValid()) + if (!scriptState) return false; ScriptState* scriptStateInUserScript = ScriptState::forMainWorld(frame); - if (!scriptState->contextIsValid()) + if (!scriptStateInUserScript) return false; ScriptState::Scope scope(scriptState); @@ -3390,10 +3390,10 @@ v8::HandleScope handleScope(toIsolate(frame)); ScriptForbiddenScope::AllowUserAgentScript script; ScriptState* scriptState = ScriptState::forWorld(frame, DOMWrapperWorld::privateScriptIsolatedWorld()); - if (!scriptState->contextIsValid()) + if (!scriptState) return false; ScriptState* scriptStateInUserScript = ScriptState::forMainWorld(frame); - if (!scriptState->contextIsValid()) + if (!scriptStateInUserScript) return false; ScriptState::Scope scope(scriptState); @@ -3428,10 +3428,10 @@ v8::HandleScope handleScope(toIsolate(frame)); ScriptForbiddenScope::AllowUserAgentScript script; ScriptState* scriptState = ScriptState::forWorld(frame, DOMWrapperWorld::privateScriptIsolatedWorld()); - if (!scriptState->contextIsValid()) + if (!scriptState) return false; ScriptState* scriptStateInUserScript = ScriptState::forMainWorld(frame); - if (!scriptState->contextIsValid()) + if (!scriptStateInUserScript) return false; ScriptState::Scope scope(scriptState);
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/V8TestObject.cpp b/third_party/WebKit/Source/bindings/tests/results/core/V8TestObject.cpp index 75869ed..874b8d2 100644 --- a/third_party/WebKit/Source/bindings/tests/results/core/V8TestObject.cpp +++ b/third_party/WebKit/Source/bindings/tests/results/core/V8TestObject.cpp
@@ -13916,10 +13916,10 @@ v8::HandleScope handleScope(toIsolate(frame)); ScriptForbiddenScope::AllowUserAgentScript script; ScriptState* scriptState = ScriptState::forWorld(frame, DOMWrapperWorld::privateScriptIsolatedWorld()); - if (!scriptState->contextIsValid()) + if (!scriptState) return false; ScriptState* scriptStateInUserScript = ScriptState::forMainWorld(frame); - if (!scriptState->contextIsValid()) + if (!scriptStateInUserScript) return false; ScriptState::Scope scope(scriptState); @@ -13943,10 +13943,10 @@ v8::HandleScope handleScope(toIsolate(frame)); ScriptForbiddenScope::AllowUserAgentScript script; ScriptState* scriptState = ScriptState::forWorld(frame, DOMWrapperWorld::privateScriptIsolatedWorld()); - if (!scriptState->contextIsValid()) + if (!scriptState) return false; ScriptState* scriptStateInUserScript = ScriptState::forMainWorld(frame); - if (!scriptState->contextIsValid()) + if (!scriptStateInUserScript) return false; ScriptState::Scope scope(scriptState); @@ -13974,10 +13974,10 @@ v8::HandleScope handleScope(toIsolate(frame)); ScriptForbiddenScope::AllowUserAgentScript script; ScriptState* scriptState = ScriptState::forWorld(frame, DOMWrapperWorld::privateScriptIsolatedWorld()); - if (!scriptState->contextIsValid()) + if (!scriptState) return false; ScriptState* scriptStateInUserScript = ScriptState::forMainWorld(frame); - if (!scriptState->contextIsValid()) + if (!scriptStateInUserScript) return false; ScriptState::Scope scope(scriptState); @@ -14006,10 +14006,10 @@ v8::HandleScope handleScope(toIsolate(frame)); ScriptForbiddenScope::AllowUserAgentScript script; ScriptState* scriptState = ScriptState::forWorld(frame, DOMWrapperWorld::privateScriptIsolatedWorld()); - if (!scriptState->contextIsValid()) + if (!scriptState) return false; ScriptState* scriptStateInUserScript = ScriptState::forMainWorld(frame); - if (!scriptState->contextIsValid()) + if (!scriptStateInUserScript) return false; ScriptState::Scope scope(scriptState); @@ -14038,10 +14038,10 @@ v8::HandleScope handleScope(toIsolate(frame)); ScriptForbiddenScope::AllowUserAgentScript script; ScriptState* scriptState = ScriptState::forWorld(frame, DOMWrapperWorld::privateScriptIsolatedWorld()); - if (!scriptState->contextIsValid()) + if (!scriptState) return false; ScriptState* scriptStateInUserScript = ScriptState::forMainWorld(frame); - if (!scriptState->contextIsValid()) + if (!scriptStateInUserScript) return false; ScriptState::Scope scope(scriptState); @@ -14068,10 +14068,10 @@ v8::HandleScope handleScope(toIsolate(frame)); ScriptForbiddenScope::AllowUserAgentScript script; ScriptState* scriptState = ScriptState::forWorld(frame, DOMWrapperWorld::privateScriptIsolatedWorld()); - if (!scriptState->contextIsValid()) + if (!scriptState) return false; ScriptState* scriptStateInUserScript = ScriptState::forMainWorld(frame); - if (!scriptState->contextIsValid()) + if (!scriptStateInUserScript) return false; ScriptState::Scope scope(scriptState); @@ -14102,10 +14102,10 @@ v8::HandleScope handleScope(toIsolate(frame)); ScriptForbiddenScope::AllowUserAgentScript script; ScriptState* scriptState = ScriptState::forWorld(frame, DOMWrapperWorld::privateScriptIsolatedWorld()); - if (!scriptState->contextIsValid()) + if (!scriptState) return false; ScriptState* scriptStateInUserScript = ScriptState::forMainWorld(frame); - if (!scriptState->contextIsValid()) + if (!scriptStateInUserScript) return false; ScriptState::Scope scope(scriptState); @@ -14135,10 +14135,10 @@ v8::HandleScope handleScope(toIsolate(frame)); ScriptForbiddenScope::AllowUserAgentScript script; ScriptState* scriptState = ScriptState::forWorld(frame, DOMWrapperWorld::privateScriptIsolatedWorld()); - if (!scriptState->contextIsValid()) + if (!scriptState) return false; ScriptState* scriptStateInUserScript = ScriptState::forMainWorld(frame); - if (!scriptState->contextIsValid()) + if (!scriptStateInUserScript) return false; ScriptState::Scope scope(scriptState); @@ -14166,10 +14166,10 @@ v8::HandleScope handleScope(toIsolate(frame)); ScriptForbiddenScope::AllowUserAgentScript script; ScriptState* scriptState = ScriptState::forWorld(frame, DOMWrapperWorld::privateScriptIsolatedWorld()); - if (!scriptState->contextIsValid()) + if (!scriptState) return false; ScriptState* scriptStateInUserScript = ScriptState::forMainWorld(frame); - if (!scriptState->contextIsValid()) + if (!scriptStateInUserScript) return false; ScriptState::Scope scope(scriptState); @@ -14197,10 +14197,10 @@ v8::HandleScope handleScope(toIsolate(frame)); ScriptForbiddenScope::AllowUserAgentScript script; ScriptState* scriptState = ScriptState::forWorld(frame, DOMWrapperWorld::privateScriptIsolatedWorld()); - if (!scriptState->contextIsValid()) + if (!scriptState) return false; ScriptState* scriptStateInUserScript = ScriptState::forMainWorld(frame); - if (!scriptState->contextIsValid()) + if (!scriptStateInUserScript) return false; ScriptState::Scope scope(scriptState); @@ -14219,10 +14219,10 @@ v8::HandleScope handleScope(toIsolate(frame)); ScriptForbiddenScope::AllowUserAgentScript script; ScriptState* scriptState = ScriptState::forWorld(frame, DOMWrapperWorld::privateScriptIsolatedWorld()); - if (!scriptState->contextIsValid()) + if (!scriptState) return false; ScriptState* scriptStateInUserScript = ScriptState::forMainWorld(frame); - if (!scriptState->contextIsValid()) + if (!scriptStateInUserScript) return false; ScriptState::Scope scope(scriptState); @@ -14250,10 +14250,10 @@ v8::HandleScope handleScope(toIsolate(frame)); ScriptForbiddenScope::AllowUserAgentScript script; ScriptState* scriptState = ScriptState::forWorld(frame, DOMWrapperWorld::privateScriptIsolatedWorld()); - if (!scriptState->contextIsValid()) + if (!scriptState) return false; ScriptState* scriptStateInUserScript = ScriptState::forMainWorld(frame); - if (!scriptState->contextIsValid()) + if (!scriptStateInUserScript) return false; ScriptState::Scope scope(scriptState); @@ -14272,10 +14272,10 @@ v8::HandleScope handleScope(toIsolate(frame)); ScriptForbiddenScope::AllowUserAgentScript script; ScriptState* scriptState = ScriptState::forWorld(frame, DOMWrapperWorld::privateScriptIsolatedWorld()); - if (!scriptState->contextIsValid()) + if (!scriptState) return false; ScriptState* scriptStateInUserScript = ScriptState::forMainWorld(frame); - if (!scriptState->contextIsValid()) + if (!scriptStateInUserScript) return false; ScriptState::Scope scope(scriptState); @@ -14301,10 +14301,10 @@ v8::HandleScope handleScope(toIsolate(frame)); ScriptForbiddenScope::AllowUserAgentScript script; ScriptState* scriptState = ScriptState::forWorld(frame, DOMWrapperWorld::privateScriptIsolatedWorld()); - if (!scriptState->contextIsValid()) + if (!scriptState) return false; ScriptState* scriptStateInUserScript = ScriptState::forMainWorld(frame); - if (!scriptState->contextIsValid()) + if (!scriptStateInUserScript) return false; ScriptState::Scope scope(scriptState); @@ -14323,10 +14323,10 @@ v8::HandleScope handleScope(toIsolate(frame)); ScriptForbiddenScope::AllowUserAgentScript script; ScriptState* scriptState = ScriptState::forWorld(frame, DOMWrapperWorld::privateScriptIsolatedWorld()); - if (!scriptState->contextIsValid()) + if (!scriptState) return false; ScriptState* scriptStateInUserScript = ScriptState::forMainWorld(frame); - if (!scriptState->contextIsValid()) + if (!scriptStateInUserScript) return false; ScriptState::Scope scope(scriptState); @@ -14354,10 +14354,10 @@ v8::HandleScope handleScope(toIsolate(frame)); ScriptForbiddenScope::AllowUserAgentScript script; ScriptState* scriptState = ScriptState::forWorld(frame, DOMWrapperWorld::privateScriptIsolatedWorld()); - if (!scriptState->contextIsValid()) + if (!scriptState) return false; ScriptState* scriptStateInUserScript = ScriptState::forMainWorld(frame); - if (!scriptState->contextIsValid()) + if (!scriptStateInUserScript) return false; ScriptState::Scope scope(scriptState); @@ -14376,10 +14376,10 @@ v8::HandleScope handleScope(toIsolate(frame)); ScriptForbiddenScope::AllowUserAgentScript script; ScriptState* scriptState = ScriptState::forWorld(frame, DOMWrapperWorld::privateScriptIsolatedWorld()); - if (!scriptState->contextIsValid()) + if (!scriptState) return false; ScriptState* scriptStateInUserScript = ScriptState::forMainWorld(frame); - if (!scriptState->contextIsValid()) + if (!scriptStateInUserScript) return false; ScriptState::Scope scope(scriptState); @@ -14407,10 +14407,10 @@ v8::HandleScope handleScope(toIsolate(frame)); ScriptForbiddenScope::AllowUserAgentScript script; ScriptState* scriptState = ScriptState::forWorld(frame, DOMWrapperWorld::privateScriptIsolatedWorld()); - if (!scriptState->contextIsValid()) + if (!scriptState) return false; ScriptState* scriptStateInUserScript = ScriptState::forMainWorld(frame); - if (!scriptState->contextIsValid()) + if (!scriptStateInUserScript) return false; ScriptState::Scope scope(scriptState);
diff --git a/third_party/WebKit/Source/core/clipboard/DataObjectTest.cpp b/third_party/WebKit/Source/core/clipboard/DataObjectTest.cpp index 920969a1..7944eb3a 100644 --- a/third_party/WebKit/Source/core/clipboard/DataObjectTest.cpp +++ b/third_party/WebKit/Source/core/clipboard/DataObjectTest.cpp
@@ -5,8 +5,7 @@ #include "core/clipboard/DataObject.h" #include "core/clipboard/DataObjectItem.h" -#include "public/platform/Platform.h" -#include "public/platform/WebUnitTestSupport.h" +#include "platform/testing/UnitTestHelpers.h" #include "testing/gtest/include/gtest/gtest.h" namespace blink { @@ -24,7 +23,7 @@ TEST_F(DataObjectTest, addItemWithFilenameAndNoTitle) { - String filePath = Platform::current()->unitTestSupport()->webKitRootDir(); + String filePath = testing::blinkRootDir(); filePath.append("/Source/core/clipboard/DataObjectTest.cpp"); m_dataObject->addFilename(filePath, String()); @@ -43,7 +42,7 @@ TEST_F(DataObjectTest, addItemWithFilenameAndTitle) { - String filePath = Platform::current()->unitTestSupport()->webKitRootDir(); + String filePath = testing::blinkRootDir(); filePath.append("/Source/core/clipboard/DataObjectTest.cpp"); m_dataObject->addFilename(filePath, "name.cpp");
diff --git a/third_party/WebKit/Source/core/core.gypi b/third_party/WebKit/Source/core/core.gypi index 0159e6e..aec4b53 100644 --- a/third_party/WebKit/Source/core/core.gypi +++ b/third_party/WebKit/Source/core/core.gypi
@@ -31,7 +31,6 @@ 'css/CSSViewportRule.idl', 'css/FontFace.idl', 'css/FontFaceSet.idl', - 'css/FontFaceSetForEachCallback.idl', 'css/FontFaceSetLoadEvent.idl', 'css/MediaList.idl', 'css/MediaQueryList.idl', @@ -43,6 +42,7 @@ 'css/cssom/KeywordValue.idl', 'css/cssom/LengthValue.idl', 'css/cssom/NumberValue.idl', + 'css/cssom/SimpleLength.idl', 'css/cssom/StyleValue.idl', 'dom/ArrayBuffer.idl', 'dom/ArrayBufferView.idl', @@ -1171,7 +1171,6 @@ 'css/FontFaceCache.h', 'css/FontFaceSet.cpp', 'css/FontFaceSet.h', - 'css/FontFaceSetForEachCallback.h', 'css/FontFaceSetLoadEvent.cpp', 'css/FontFaceSetLoadEvent.h', 'css/FontLoader.cpp', @@ -1247,6 +1246,8 @@ 'css/cssom/LengthValue.cpp', 'css/cssom/LengthValue.h', 'css/cssom/NumberValue.h', + 'css/cssom/SimpleLength.cpp', + 'css/cssom/SimpleLength.h', 'css/cssom/StyleValue.cpp', 'css/cssom/StyleValue.h', 'css/invalidation/InvalidationSet.cpp', @@ -2038,6 +2039,8 @@ 'paint/PaintPhase.h', 'paint/PaintPropertyTreeBuilder.cpp', 'paint/PaintPropertyTreeBuilder.h', + 'paint/PaintPropertyTreePrinter.cpp', + 'paint/PaintPropertyTreePrinter.h', 'paint/PaintTiming.cpp', 'paint/PaintTiming.h', 'paint/PartPainter.cpp', @@ -2881,6 +2884,7 @@ 'html/HTMLTrackElement.h', 'html/HTMLUListElement.cpp', 'html/HTMLUListElement.h', + 'html/HTMLUnknownElement.cpp', 'html/HTMLUnknownElement.h', 'html/HTMLVideoElement.cpp', 'html/HTMLVideoElement.h', @@ -3822,6 +3826,7 @@ 'css/CSSCalculationValueTest.cpp', 'css/CSSFontFaceTest.cpp', 'css/CSSSelectorTest.cpp', + 'css/CSSStyleSheetResourceTest.cpp', 'css/CSSTestHelper.cpp', 'css/CSSTestHelper.h', 'css/CSSValueTestHelper.h', @@ -3930,6 +3935,7 @@ 'input/EventHandlerTest.cpp', 'layout/ImageQualityControllerTest.cpp', 'layout/LayoutBlockTest.cpp', + 'layout/LayoutBoxTest.cpp', 'layout/LayoutInlineTest.cpp', 'layout/LayoutMultiColumnFlowThreadTest.cpp', 'layout/LayoutObjectTest.cpp',
diff --git a/third_party/WebKit/Source/core/css/CSSCrossfadeValue.h b/third_party/WebKit/Source/core/css/CSSCrossfadeValue.h index 1389fc6..8f93a01a 100644 --- a/third_party/WebKit/Source/core/css/CSSCrossfadeValue.h +++ b/third_party/WebKit/Source/core/css/CSSCrossfadeValue.h
@@ -26,6 +26,7 @@ #ifndef CSSCrossfadeValue_h #define CSSCrossfadeValue_h +#include "core/CoreExport.h" #include "core/css/CSSImageGeneratorValue.h" #include "core/css/CSSPrimitiveValue.h" #include "core/fetch/ImageResource.h" @@ -39,7 +40,7 @@ class CrossfadeSubimageObserverProxy; class LayoutObject; -class CSSCrossfadeValue final : public CSSImageGeneratorValue { +class CORE_EXPORT CSSCrossfadeValue final : public CSSImageGeneratorValue { friend class CrossfadeSubimageObserverProxy; WILL_BE_USING_PRE_FINALIZER(CSSCrossfadeValue, dispose); public:
diff --git a/third_party/WebKit/Source/core/css/CSSImageValue.h b/third_party/WebKit/Source/core/css/CSSImageValue.h index 7fec090..c1152a8 100644 --- a/third_party/WebKit/Source/core/css/CSSImageValue.h +++ b/third_party/WebKit/Source/core/css/CSSImageValue.h
@@ -21,6 +21,7 @@ #ifndef CSSImageValue_h #define CSSImageValue_h +#include "core/CoreExport.h" #include "core/css/CSSValue.h" #include "platform/CrossOriginAttributeValue.h" #include "platform/weborigin/Referrer.h" @@ -34,7 +35,7 @@ class StyleImage; class LayoutObject; -class CSSImageValue : public CSSValue { +class CORE_EXPORT CSSImageValue : public CSSValue { public: static PassRefPtrWillBeRawPtr<CSSImageValue> create(const KURL& url, StyleFetchedImage* image = 0) {
diff --git a/third_party/WebKit/Source/core/css/CSSPropertyMetadata.h b/third_party/WebKit/Source/core/css/CSSPropertyMetadata.h index 302b447b..7b6b0e4 100644 --- a/third_party/WebKit/Source/core/css/CSSPropertyMetadata.h +++ b/third_party/WebKit/Source/core/css/CSSPropertyMetadata.h
@@ -6,11 +6,12 @@ #define CSSPropertyMetadata_h #include "core/CSSPropertyNames.h" +#include "core/CoreExport.h" #include "wtf/Allocator.h" namespace blink { -class CSSPropertyMetadata { +class CORE_EXPORT CSSPropertyMetadata { STATIC_ONLY(CSSPropertyMetadata); public: static bool isEnabledProperty(CSSPropertyID);
diff --git a/third_party/WebKit/Source/core/css/CSSSelectorList.cpp b/third_party/WebKit/Source/core/css/CSSSelectorList.cpp index 351d398..114fb84 100644 --- a/third_party/WebKit/Source/core/css/CSSSelectorList.cpp +++ b/third_party/WebKit/Source/core/css/CSSSelectorList.cpp
@@ -30,6 +30,14 @@ #include "wtf/Partitions.h" #include "wtf/text/StringBuilder.h" +namespace { + // CSSSelector is one of the top types that consume renderer memory, + // so instead of using the |WTF_HEAP_PROFILER_TYPE_NAME| macro in the + // allocations below, pass this type name constant to allow profiling + // in official builds. + const char kCSSSelectorTypeName[] = "blink::CSSSelector"; +} + namespace blink { CSSSelectorList CSSSelectorList::copy() const @@ -37,7 +45,7 @@ CSSSelectorList list; unsigned length = this->length(); - list.m_selectorArray = reinterpret_cast<CSSSelector*>(WTF::Partitions::fastMalloc(sizeof(CSSSelector) * length, WTF_HEAP_PROFILER_TYPE_NAME(CSSSelector))); + list.m_selectorArray = reinterpret_cast<CSSSelector*>(WTF::Partitions::fastMalloc(sizeof(CSSSelector) * length, kCSSSelectorTypeName)); for (unsigned i = 0; i < length; ++i) new (&list.m_selectorArray[i]) CSSSelector(m_selectorArray[i]); @@ -54,7 +62,7 @@ ASSERT(flattenedSize); CSSSelectorList list; - list.m_selectorArray = reinterpret_cast<CSSSelector*>(WTF::Partitions::fastMalloc(sizeof(CSSSelector) * flattenedSize, WTF_HEAP_PROFILER_TYPE_NAME(CSSSelector))); + list.m_selectorArray = reinterpret_cast<CSSSelector*>(WTF::Partitions::fastMalloc(sizeof(CSSSelector) * flattenedSize, kCSSSelectorTypeName)); size_t arrayIndex = 0; for (size_t i = 0; i < selectorVector.size(); ++i) { CSSParserSelector* current = selectorVector[i].get();
diff --git a/third_party/WebKit/Source/core/css/CSSStyleSheetResourceTest.cpp b/third_party/WebKit/Source/core/css/CSSStyleSheetResourceTest.cpp new file mode 100644 index 0000000..4c16737 --- /dev/null +++ b/third_party/WebKit/Source/core/css/CSSStyleSheetResourceTest.cpp
@@ -0,0 +1,122 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "core/fetch/CSSStyleSheetResource.h" + +#include "core/css/CSSCrossfadeValue.h" +#include "core/css/CSSImageValue.h" +#include "core/css/CSSPrimitiveValue.h" +#include "core/css/CSSProperty.h" +#include "core/css/CSSSelectorList.h" +#include "core/css/CSSStyleSheet.h" +#include "core/css/StylePropertySet.h" +#include "core/css/StyleRule.h" +#include "core/css/StyleSheetContents.h" +#include "core/css/parser/CSSParserMode.h" +#include "core/css/parser/CSSParserSelector.h" +#include "core/dom/Document.h" +#include "core/fetch/FetchContext.h" +#include "core/fetch/FetchInitiatorTypeNames.h" +#include "core/fetch/FetchRequest.h" +#include "core/fetch/MemoryCache.h" +#include "core/fetch/ResourceFetcher.h" +#include "core/testing/DummyPageHolder.h" +#include "platform/heap/Handle.h" +#include "platform/network/ResourceRequest.h" +#include "platform/testing/URLTestHelpers.h" +#include "platform/testing/UnitTestHelpers.h" +#include "platform/weborigin/KURL.h" +#include "public/platform/Platform.h" +#include "public/platform/WebURLResponse.h" +#include "public/platform/WebUnitTestSupport.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "wtf/RefPtr.h" +#include "wtf/text/WTFString.h" + +namespace blink { + +class Document; + +namespace { + +class CSSStyleSheetResourceTest : public ::testing::Test { +protected: + CSSStyleSheetResourceTest() + { + m_originalMemoryCache = replaceMemoryCacheForTesting(MemoryCache::create()); + m_page = DummyPageHolder::create(); + document()->setURL(KURL(KURL(), "https://localhost/")); + } + + ~CSSStyleSheetResourceTest() override + { + replaceMemoryCacheForTesting(m_originalMemoryCache.release()); + } + + Document* document() { return &m_page->document(); } + + Persistent<MemoryCache> m_originalMemoryCache; + OwnPtr<DummyPageHolder> m_page; +}; + +TEST_F(CSSStyleSheetResourceTest, PruneCanCauseEviction) +{ + { + // We need this scope to remove all references. + KURL imageURL(KURL(), "https://localhost/image"); + KURL cssURL(KURL(), "https://localhost/style.css"); + + // We need to disable loading because we manually give a response to + // the image resource. + document()->fetcher()->setAutoLoadImages(false); + + ResourcePtr<CSSStyleSheetResource> cssResource = CSSStyleSheetResource::createForTest(ResourceRequest(cssURL), "utf-8"); + memoryCache()->add(cssResource.get()); + cssResource->responseReceived(ResourceResponse(cssURL, "style/css", 0, nullAtom, String()), nullptr); + cssResource->finish(); + + RefPtrWillBeRawPtr<StyleSheetContents> contents = StyleSheetContents::create(CSSParserContext(HTMLStandardMode, nullptr)); + RefPtrWillBeRawPtr<CSSStyleSheet> sheet = CSSStyleSheet::create(contents, document()); + EXPECT_TRUE(sheet); + RefPtrWillBeRawPtr<CSSCrossfadeValue> crossfade = CSSCrossfadeValue::create( + CSSImageValue::create(String("image"), imageURL), + CSSImageValue::create(String("image"), imageURL), + CSSPrimitiveValue::create(1.0, CSSPrimitiveValue::UnitType::Number)); + Vector<OwnPtr<CSSParserSelector>> selectors; + selectors.append(adoptPtr(new CSSParserSelector())); + selectors[0]->setMatch(CSSSelector::Id); + selectors[0]->setValue("foo"); + CSSProperty property(CSSPropertyBackground, crossfade); + contents->parserAppendRule( + StyleRule::create(CSSSelectorList::adoptSelectorVector(selectors), ImmutableStylePropertySet::create(&property, 1, HTMLStandardMode))); + + crossfade->loadSubimages(document()); + ResourcePtr<Resource> imageResource = memoryCache()->resourceForURL(imageURL, MemoryCache::defaultCacheIdentifier()); + ASSERT_TRUE(imageResource); + ResourceResponse imageResponse; + imageResponse.setURL(imageURL); + imageResponse.setHTTPHeaderField("cache-control", "no-store"); + imageResource->responseReceived(imageResponse, nullptr); + + contents->checkLoaded(); + cssResource->saveParsedStyleSheet(contents); + + memoryCache()->update(cssResource.get(), cssResource->size(), cssResource->size(), false); + memoryCache()->update(imageResource.get(), imageResource->size(), imageResource->size(), false); + if (!memoryCache()->isInSameLRUListForTest(cssResource.get(), imageResource.get())) { + // We assume that the LRU list is determined by |size / accessCount|. + for (size_t i = 0; i < cssResource->size() + 1; ++i) + memoryCache()->update(cssResource.get(), cssResource->size(), cssResource->size(), true); + for (size_t i = 0; i < imageResource->size() + 1; ++i) + memoryCache()->update(imageResource.get(), imageResource->size(), imageResource->size(), true); + } + ASSERT_TRUE(memoryCache()->isInSameLRUListForTest(cssResource.get(), imageResource.get())); + } + Heap::collectAllGarbage(); + // This operation should not lead to crash! + memoryCache()->pruneAll(); +} + +} // namespace +} // namespace blink
diff --git a/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp b/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp index 27c3863..0bb2a88 100644 --- a/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp +++ b/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp
@@ -1047,7 +1047,7 @@ list->append(CSSCustomIdentValue::create(item.key)); short number = propertyID == CSSPropertyCounterIncrement ? item.value.incrementValue() : item.value.resetValue(); - list->append(cssValuePool().createValue((double)number, CSSPrimitiveValue::UnitType::Number)); + list->append(cssValuePool().createValue((double)number, CSSPrimitiveValue::UnitType::Integer)); } if (!list->length())
diff --git a/third_party/WebKit/Source/core/css/FontFaceSet.h b/third_party/WebKit/Source/core/css/FontFaceSet.h index 61b0ebc6..dfcb27c5 100644 --- a/third_party/WebKit/Source/core/css/FontFaceSet.h +++ b/third_party/WebKit/Source/core/css/FontFaceSet.h
@@ -29,7 +29,6 @@ #include "bindings/core/v8/Iterable.h" #include "bindings/core/v8/ScriptPromise.h" #include "core/css/FontFace.h" -#include "core/css/FontFaceSetForEachCallback.h" #include "core/dom/ActiveDOMObject.h" #include "core/events/EventListener.h" #include "core/events/EventTarget.h"
diff --git a/third_party/WebKit/Source/core/css/FontFaceSetForEachCallback.h b/third_party/WebKit/Source/core/css/FontFaceSetForEachCallback.h deleted file mode 100644 index 1572b5e..0000000 --- a/third_party/WebKit/Source/core/css/FontFaceSetForEachCallback.h +++ /dev/null
@@ -1,47 +0,0 @@ -/* - * Copyright (C) 2013 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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. - */ - -#ifndef FontFaceSetForEachCallback_h -#define FontFaceSetForEachCallback_h - -#include "bindings/core/v8/ScriptValue.h" -#include "platform/heap/Handle.h" - -namespace blink { - -class FontFace; -class FontFaceSet; - -class FontFaceSetForEachCallback : public GarbageCollectedFinalized<FontFaceSetForEachCallback> { -public: - virtual ~FontFaceSetForEachCallback() { } - DEFINE_INLINE_VIRTUAL_TRACE() { } - virtual bool handleItem(ScriptValue thisValue, FontFace*, FontFace*, FontFaceSet*) = 0; - virtual bool handleItem(FontFace*, FontFace*, FontFaceSet*) = 0; -}; - -} // namespace blink - -#endif // FontFaceSetForEachCallback_h
diff --git a/third_party/WebKit/Source/core/css/FontFaceSetForEachCallback.idl b/third_party/WebKit/Source/core/css/FontFaceSetForEachCallback.idl deleted file mode 100644 index ac6c771..0000000 --- a/third_party/WebKit/Source/core/css/FontFaceSetForEachCallback.idl +++ /dev/null
@@ -1,36 +0,0 @@ -/* - * Copyright (C) 2013 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -// TODO(ksakamoto): Remove this interface when FontFaceSet is made Set-like. -// crbug.com/392075 -callback interface FontFaceSetForEachCallback { - [CallWith=ThisValue] boolean handleItem(FontFace fontFace, FontFace fontFaceAgain, FontFaceSet set); - boolean handleItem(FontFace fontFace, FontFace fontFaceAgain, FontFaceSet set); -};
diff --git a/third_party/WebKit/Source/core/css/MediaQueryEvaluator.cpp b/third_party/WebKit/Source/core/css/MediaQueryEvaluator.cpp index 69f2e988..99e42d0 100644 --- a/third_party/WebKit/Source/core/css/MediaQueryEvaluator.cpp +++ b/third_party/WebKit/Source/core/css/MediaQueryEvaluator.cpp
@@ -92,6 +92,11 @@ { } +DEFINE_TRACE(MediaQueryEvaluator) +{ + visitor->trace(m_mediaValues); +} + const String MediaQueryEvaluator::mediaType() const { // If a static mediaType was given by the constructor, we use it here.
diff --git a/third_party/WebKit/Source/core/css/MediaQueryEvaluator.h b/third_party/WebKit/Source/core/css/MediaQueryEvaluator.h index 93fc157..5ce10de 100644 --- a/third_party/WebKit/Source/core/css/MediaQueryEvaluator.h +++ b/third_party/WebKit/Source/core/css/MediaQueryEvaluator.h
@@ -53,8 +53,9 @@ // the device characteristics are not known. This can be used to prune the loading // of stylesheets to only those which are probable to match. -class CORE_EXPORT MediaQueryEvaluator { - WTF_MAKE_NONCOPYABLE(MediaQueryEvaluator); USING_FAST_MALLOC(MediaQueryEvaluator); +class CORE_EXPORT MediaQueryEvaluator final : public NoBaseWillBeGarbageCollectedFinalized<MediaQueryEvaluator> { + WTF_MAKE_NONCOPYABLE(MediaQueryEvaluator); + USING_FAST_MALLOC_WILL_BE_REMOVED(MediaQueryEvaluator); public: // Creates evaluator which evaluates only simple media queries // Evaluator returns true for "all", and returns value of \mediaFeatureResult @@ -87,12 +88,14 @@ // Evaluates media query subexpression, ie "and (media-feature: value)" part. bool eval(const MediaQueryExp*) const; + DECLARE_TRACE(); + private: const String mediaType() const; String m_mediaType; bool m_expectedResult; - RefPtrWillBePersistent<MediaValues> m_mediaValues; + RefPtrWillBeMember<MediaValues> m_mediaValues; }; } // namespace
diff --git a/third_party/WebKit/Source/core/css/MediaQueryMatcher.cpp b/third_party/WebKit/Source/core/css/MediaQueryMatcher.cpp index 7579d1f..16479c1d 100644 --- a/third_party/WebKit/Source/core/css/MediaQueryMatcher.cpp +++ b/third_party/WebKit/Source/core/css/MediaQueryMatcher.cpp
@@ -53,12 +53,12 @@ m_evaluator = nullptr; } -PassOwnPtr<MediaQueryEvaluator> MediaQueryMatcher::createEvaluator() const +PassOwnPtrWillBeRawPtr<MediaQueryEvaluator> MediaQueryMatcher::createEvaluator() const { if (!m_document || !m_document->frame()) return nullptr; - return adoptPtr(new MediaQueryEvaluator(m_document->frame())); + return adoptPtrWillBeNoop(new MediaQueryEvaluator(m_document->frame())); } bool MediaQueryMatcher::evaluate(const MediaQuerySet* media) @@ -147,6 +147,7 @@ { #if ENABLE(OILPAN) visitor->trace(m_document); + visitor->trace(m_evaluator); visitor->trace(m_mediaLists); visitor->trace(m_viewportListeners); #endif
diff --git a/third_party/WebKit/Source/core/css/MediaQueryMatcher.h b/third_party/WebKit/Source/core/css/MediaQueryMatcher.h index 81ec1ac..d46d354 100644 --- a/third_party/WebKit/Source/core/css/MediaQueryMatcher.h +++ b/third_party/WebKit/Source/core/css/MediaQueryMatcher.h
@@ -63,10 +63,10 @@ private: explicit MediaQueryMatcher(Document&); - PassOwnPtr<MediaQueryEvaluator> createEvaluator() const; + PassOwnPtrWillBeRawPtr<MediaQueryEvaluator> createEvaluator() const; RawPtrWillBeMember<Document> m_document; - OwnPtr<MediaQueryEvaluator> m_evaluator; + OwnPtrWillBeMember<MediaQueryEvaluator> m_evaluator; using MediaQueryListSet = WillBeHeapLinkedHashSet<RawPtrWillBeWeakMember<MediaQueryList>>; MediaQueryListSet m_mediaLists;
diff --git a/third_party/WebKit/Source/core/css/SelectorFilter.cpp b/third_party/WebKit/Source/core/css/SelectorFilter.cpp index 2b4c9800..140ebaf 100644 --- a/third_party/WebKit/Source/core/css/SelectorFilter.cpp +++ b/third_party/WebKit/Source/core/css/SelectorFilter.cpp
@@ -79,38 +79,17 @@ } } -void SelectorFilter::setupParentStack(Element& parent) +void SelectorFilter::pushParent(Element& parent) { - ASSERT(m_parentStack.isEmpty() == !m_ancestorIdentifierFilter); - // Kill whatever we stored before. - m_parentStack.shrink(0); - m_ancestorIdentifierFilter = adoptPtr(new BloomFilter<bloomFilterKeyBits>); - // Fast version if parent is a root element: - if (!parent.parentOrShadowHostNode()) { + ASSERT(parent.document().inStyleRecalc()); + ASSERT(parent.inActiveDocument()); + if (m_parentStack.isEmpty()) { + ASSERT(parent == parent.document().documentElement()); + ASSERT(!m_ancestorIdentifierFilter); + m_ancestorIdentifierFilter = adoptPtr(new IdentifierFilter); pushParentStackFrame(parent); return; } - // Otherwise climb up the tree. - WillBeHeapVector<RawPtrWillBeMember<Element>, 30> ancestors; - for (Element* ancestor = &parent; ancestor; ancestor = ancestor->parentOrShadowHostElement()) - ancestors.append(ancestor); - for (size_t n = ancestors.size(); n; --n) - pushParentStackFrame(*ancestors[n - 1]); -} - -void SelectorFilter::pushParent(Element& parent) -{ - const Element* parentsParent = parent.parentOrShadowHostElement(); - - // We are not always invoked consistently. For example, script execution can cause us to enter - // style recalc in the middle of tree building. We may also be invoked from somewhere within the tree. - // Reset the stack in this case, or if we see a new root element. - // Otherwise just push the new parent. - if (!parentsParent || m_parentStack.isEmpty()) { - setupParentStack(parent); - return; - } - ASSERT(m_ancestorIdentifierFilter); // We may get invoked for some random elements in some wacky cases during style resolve. // Pause maintaining the stack in this case. @@ -121,6 +100,8 @@ void SelectorFilter::popParent(Element& parent) { + ASSERT(parent.document().inStyleRecalc()); + ASSERT(parent.inActiveDocument()); // Note that we may get invoked for some random elements in some wacky cases during style resolve. // Pause maintaining the stack in this case. if (!parentStackIsConsistent(&parent))
diff --git a/third_party/WebKit/Source/core/css/SelectorFilter.h b/third_party/WebKit/Source/core/css/SelectorFilter.h index d99b8a0..3233c32 100644 --- a/third_party/WebKit/Source/core/css/SelectorFilter.h +++ b/third_party/WebKit/Source/core/css/SelectorFilter.h
@@ -66,13 +66,12 @@ private: void pushParentStackFrame(Element& parent); void popParentStackFrame(); - void setupParentStack(Element& parent); WillBeHeapVector<ParentStackFrame> m_parentStack; // With 100 unique strings in the filter, 2^12 slot table has false positive rate of ~0.2%. - static const unsigned bloomFilterKeyBits = 12; - OwnPtr<BloomFilter<bloomFilterKeyBits>> m_ancestorIdentifierFilter; + using IdentifierFilter = BloomFilter<12>; + OwnPtr<IdentifierFilter> m_ancestorIdentifierFilter; }; template <unsigned maximumIdentifierCount>
diff --git a/third_party/WebKit/Source/core/css/cssom/KeywordValue.h b/third_party/WebKit/Source/core/css/cssom/KeywordValue.h index 189c4ead..10b3d90 100644 --- a/third_party/WebKit/Source/core/css/cssom/KeywordValue.h +++ b/third_party/WebKit/Source/core/css/cssom/KeywordValue.h
@@ -30,12 +30,12 @@ String cssString() const override; PassRefPtrWillBeRawPtr<CSSValue> toCSSValue() const override; -protected: +private: KeywordValue(const String& keyword) : m_keywordValue(keywordValueFromString(keyword)) {} - static KeywordValueName keywordValueFromString(const String& keyword); - KeywordValueName m_keywordValue; + + static KeywordValueName keywordValueFromString(const String& keyword); }; }
diff --git a/third_party/WebKit/Source/core/css/cssom/LengthValue.cpp b/third_party/WebKit/Source/core/css/cssom/LengthValue.cpp index 77302ef..abd80f9e 100644 --- a/third_party/WebKit/Source/core/css/cssom/LengthValue.cpp +++ b/third_party/WebKit/Source/core/css/cssom/LengthValue.cpp
@@ -29,7 +29,6 @@ table.set(String("vmax"), LengthValue::Vmax); table.set(String("cm"), LengthValue::Cm); table.set(String("mm"), LengthValue::Mm); - table.set(String("q"), LengthValue::QUnit); table.set(String("in"), LengthValue::In); table.set(String("pc"), LengthValue::Pc); table.set(String("pt"), LengthValue::Pt); @@ -86,7 +85,9 @@ LengthValue::LengthUnit LengthValue::lengthUnitFromName(const String& str) { - return typeTable().get(str.lower()); + if (typeTable().contains(str.lower())) + return typeTable().get(str.lower()); + return LengthUnit::Count; } const String& LengthValue::lengthTypeToString(LengthValue::LengthUnit unit) @@ -103,7 +104,6 @@ DEFINE_STATIC_LOCAL(const String, VmaxStr, ("vmax")); DEFINE_STATIC_LOCAL(const String, CmStr, ("cm")); DEFINE_STATIC_LOCAL(const String, MmStr, ("mm")); - DEFINE_STATIC_LOCAL(const String, QStr, ("q")); DEFINE_STATIC_LOCAL(const String, InStr, ("in")); DEFINE_STATIC_LOCAL(const String, PcStr, ("pc")); DEFINE_STATIC_LOCAL(const String, PtStr, ("pt")); @@ -133,8 +133,6 @@ return CmStr; case Mm: return MmStr; - case QUnit: - return QStr; case In: return InStr; case Pc:
diff --git a/third_party/WebKit/Source/core/css/cssom/LengthValue.h b/third_party/WebKit/Source/core/css/cssom/LengthValue.h index b1377e7..65108ad 100644 --- a/third_party/WebKit/Source/core/css/cssom/LengthValue.h +++ b/third_party/WebKit/Source/core/css/cssom/LengthValue.h
@@ -27,7 +27,6 @@ Vmax, Cm, Mm, - QUnit, In, Pc, Pt, @@ -45,6 +44,9 @@ // static LengthValue* fromDictionary(const CalcDictionary&); protected: + // Length(const String& cssString) : StyleValue(cssString) {} + // Length(double value, LengthUnit type) {} + LengthValue() {} static LengthUnit lengthUnitFromName(const String&); static const String& lengthTypeToString(LengthUnit type); @@ -52,10 +54,6 @@ virtual PassRefPtrWillBeRawPtr<LengthValue> subtractInternal(const LengthValue* other, ExceptionState&); virtual PassRefPtrWillBeRawPtr<LengthValue> multiplyInternal(double, ExceptionState&); virtual PassRefPtrWillBeRawPtr<LengthValue> divideInternal(double, ExceptionState&); - - // Length(const String& cssString) : StyleValue(cssString) {} - // Length(double value, LengthUnit type) {} - LengthValue() {} }; } // namespace blink
diff --git a/third_party/WebKit/Source/core/css/cssom/LengthValue.idl b/third_party/WebKit/Source/core/css/cssom/LengthValue.idl index d2cbca3..0b68cb1 100644 --- a/third_party/WebKit/Source/core/css/cssom/LengthValue.idl +++ b/third_party/WebKit/Source/core/css/cssom/LengthValue.idl
@@ -3,7 +3,7 @@ // found in the LICENSE file. enum LengthType { - "px", "percent", "em", "ex", "ch", "rem", "vw", "vh", "vmin", "vmax", "cm", "mm", "q", "in", "pc", "pt" + "px", "percent", "em", "ex", "ch", "rem", "vw", "vh", "vmin", "vmax", "cm", "mm", "in", "pc", "pt" }; [
diff --git a/third_party/WebKit/Source/core/css/cssom/NumberValue.h b/third_party/WebKit/Source/core/css/cssom/NumberValue.h index 9773335..a651d77c 100644 --- a/third_party/WebKit/Source/core/css/cssom/NumberValue.h +++ b/third_party/WebKit/Source/core/css/cssom/NumberValue.h
@@ -36,7 +36,7 @@ } StyleValueType type() const override { return StyleValueType::NumberType; } -protected: +private: NumberValue(double value) : m_value(value) {} double m_value;
diff --git a/third_party/WebKit/Source/core/css/cssom/SimpleLength.cpp b/third_party/WebKit/Source/core/css/cssom/SimpleLength.cpp new file mode 100644 index 0000000..028ebb2 --- /dev/null +++ b/third_party/WebKit/Source/core/css/cssom/SimpleLength.cpp
@@ -0,0 +1,58 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "core/css/cssom/SimpleLength.h" + +#include "core/css/CSSPrimitiveValue.h" +#include "wtf/text/StringBuilder.h" + +namespace blink { + +String SimpleLength::cssString() const +{ + StringBuilder s; + s.appendNumber(m_value); + s.append(unit()); + return s.toString(); +} + +PassRefPtrWillBeRawPtr<CSSValue> SimpleLength::toCSSValue() const +{ + // TODO: Don't re-parse the unit. + return cssValuePool().createValue(m_value, CSSPrimitiveValue::fromName(unit())); +} + +PassRefPtrWillBeRawPtr<LengthValue> SimpleLength::addInternal(const LengthValue* other, ExceptionState& exceptionState) +{ + const SimpleLength* o = toSimpleLength(other); + if (m_unit == o->m_unit) + return create(m_value + o->value(), m_unit); + + // Different units resolve to a calc. + exceptionState.throwTypeError("Not implemented yet"); + return nullptr; +} + +PassRefPtrWillBeRawPtr<LengthValue> SimpleLength::subtractInternal(const LengthValue* other, ExceptionState& exceptionState) +{ + const SimpleLength* o = toSimpleLength(other); + if (m_unit == o->m_unit) + return create(m_value - o->value(), m_unit); + + // Different units resolve to a calc. + exceptionState.throwTypeError("Not implemented yet"); + return nullptr; +} + +PassRefPtrWillBeRawPtr<LengthValue> SimpleLength::multiplyInternal(double x, ExceptionState& exceptionState) +{ + return create(m_value * x, m_unit); +} + +PassRefPtrWillBeRawPtr<LengthValue> SimpleLength::divideInternal(double x, ExceptionState& exceptionState) +{ + return create(m_value / x, m_unit); +} + +} // namespace blink
diff --git a/third_party/WebKit/Source/core/css/cssom/SimpleLength.h b/third_party/WebKit/Source/core/css/cssom/SimpleLength.h new file mode 100644 index 0000000..86951ea --- /dev/null +++ b/third_party/WebKit/Source/core/css/cssom/SimpleLength.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 SimpleLength_h +#define SimpleLength_h + +#include "bindings/core/v8/ExceptionState.h" +#include "core/css/cssom/LengthValue.h" + +namespace blink { + +class CSSPrimitiveValue; + +class CORE_EXPORT SimpleLength : public LengthValue { + DEFINE_WRAPPERTYPEINFO(); +public: + static PassRefPtrWillBeRawPtr<SimpleLength> create(double value, const String& type, ExceptionState& exceptionState) + { + LengthUnit unit = LengthValue::lengthUnitFromName(type); + if (unit == LengthUnit::Count) { + exceptionState.throwTypeError("Invalid unit for SimpleLength."); + return nullptr; + } + return adoptRefWillBeNoop(new SimpleLength(value, unit)); + } + + static PassRefPtrWillBeRawPtr<SimpleLength> create(double value, LengthUnit type) + { + return adoptRefWillBeNoop(new SimpleLength(value, type)); + } + + double value() const { return m_value; } + String unit() const { return LengthValue::lengthTypeToString(m_unit); } + LengthUnit lengthUnit() const { return m_unit; } + + void setValue(double value) { m_value = value; } + + StyleValueType type() const override { return StyleValueType::SimpleLengthType; } + + String cssString() const override; + PassRefPtrWillBeRawPtr<CSSValue> toCSSValue() const override; + +protected: + virtual PassRefPtrWillBeRawPtr<LengthValue> addInternal(const LengthValue* other, ExceptionState&); + virtual PassRefPtrWillBeRawPtr<LengthValue> subtractInternal(const LengthValue* other, ExceptionState&); + virtual PassRefPtrWillBeRawPtr<LengthValue> multiplyInternal(double, ExceptionState&); + virtual PassRefPtrWillBeRawPtr<LengthValue> divideInternal(double, ExceptionState&); + +private: + SimpleLength(double value, LengthUnit unit) : LengthValue(), m_unit(unit), m_value(value) {} + + LengthUnit m_unit; + double m_value; +}; + +#define DEFINE_SIMPLE_LENGTH_TYPE_CASTS(argumentType) \ + DEFINE_TYPE_CASTS(SimpleLength, argumentType, value, \ + value->type() == LengthValue::StyleValueType::SimpleLengthType, \ + value.type() == LengthValue::StyleValueType::SimpleLengthType) + +DEFINE_SIMPLE_LENGTH_TYPE_CASTS(LengthValue); +DEFINE_SIMPLE_LENGTH_TYPE_CASTS(StyleValue); + +} // namespace blink + +#endif
diff --git a/third_party/WebKit/Source/core/css/cssom/SimpleLength.idl b/third_party/WebKit/Source/core/css/cssom/SimpleLength.idl new file mode 100644 index 0000000..07c0b49 --- /dev/null +++ b/third_party/WebKit/Source/core/css/cssom/SimpleLength.idl
@@ -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(double value, DOMString type), + RaisesException=Constructor, + RuntimeEnabled=CSSTypedOM +] interface SimpleLength : LengthValue { + [EnforceRange] attribute double value; + [ImplementedAs=unit] readonly attribute LengthType type; +};
diff --git a/third_party/WebKit/Source/core/css/parser/CSSParserSelector.h b/third_party/WebKit/Source/core/css/parser/CSSParserSelector.h index 47171cf2..82a2141 100644 --- a/third_party/WebKit/Source/core/css/parser/CSSParserSelector.h +++ b/third_party/WebKit/Source/core/css/parser/CSSParserSelector.h
@@ -21,11 +21,12 @@ #ifndef CSSParserSelector_h #define CSSParserSelector_h +#include "core/CoreExport.h" #include "core/css/CSSSelector.h" namespace blink { -class CSSParserSelector { +class CORE_EXPORT CSSParserSelector { WTF_MAKE_NONCOPYABLE(CSSParserSelector); USING_FAST_MALLOC(CSSParserSelector); public: CSSParserSelector();
diff --git a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp index 22a22b5..7ad29baa 100644 --- a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp +++ b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
@@ -870,12 +870,10 @@ // Methods for consuming non-shorthand properties starts here. static PassRefPtrWillBeRawPtr<CSSValue> consumeWillChange(CSSParserTokenRange& range) { - RefPtrWillBeRawPtr<CSSValueList> values = CSSValueList::createCommaSeparated(); - if (range.peek().id() == CSSValueAuto) { - // FIXME: This will be read back as an empty string instead of auto - return values.release(); - } + if (range.peek().id() == CSSValueAuto) + return consumeIdent(range); + RefPtrWillBeRawPtr<CSSValueList> values = CSSValueList::createCommaSeparated(); // Every comma-separated list of identifiers is a valid will-change value, // unless the list includes an explicitly disallowed identifier. while (true) { @@ -1228,8 +1226,7 @@ if (range.peek().id() == CSSValueNone) return consumeIdent(range); - // TODO(rwlbuis): should be space separated list. - RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createCommaSeparated(); + RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createSpaceSeparated(); do { RefPtrWillBeRawPtr<CSSCustomIdentValue> counterName = consumeCustomIdent(range); if (!counterName) @@ -1238,7 +1235,7 @@ if (RefPtrWillBeRawPtr<CSSPrimitiveValue> counterValue = consumeInteger(range)) i = clampTo<int>(counterValue->getDoubleValue()); list->append(CSSValuePair::create(counterName.release(), - cssValuePool().createValue(i, CSSPrimitiveValue::UnitType::Number), + cssValuePool().createValue(i, CSSPrimitiveValue::UnitType::Integer), CSSValuePair::DropIdenticalValues)); } while (!range.atEnd()); return list.release(); @@ -2358,7 +2355,7 @@ static PassRefPtrWillBeRawPtr<CSSValue> consumeCursor(CSSParserTokenRange& range, const CSSParserContext& context, bool inQuirksMode) { RefPtrWillBeRawPtr<CSSValueList> list = nullptr; - while (!range.atEnd()) { + while (true) { RefPtrWillBeRawPtr<CSSValue> image = nullptr; AtomicString uri(consumeUrl(range)); if (!uri.isNull()) { @@ -2399,17 +2396,19 @@ } RefPtrWillBeRawPtr<CSSValue> cursorType = nullptr; if (id == CSSValueHand) { - if (inQuirksMode) // Non-standard behavior - cursorType = cssValuePool().createIdentifierValue(CSSValuePointer); + if (!inQuirksMode) // Non-standard behavior + return nullptr; + cursorType = cssValuePool().createIdentifierValue(CSSValuePointer); range.consumeIncludingWhitespace(); } else if ((id >= CSSValueAuto && id <= CSSValueWebkitZoomOut) || id == CSSValueCopy || id == CSSValueNone) { cursorType = consumeIdent(range); + } else { + return nullptr; } if (!list) return cursorType.release(); - if (cursorType) - list->append(cursorType.release()); + list->append(cursorType.release()); return list.release(); } @@ -2876,6 +2875,22 @@ return values.release(); } +static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> consumePerspective(CSSParserTokenRange& range, CSSParserMode cssParserMode, CSSPropertyID unresolvedProperty) +{ + if (range.peek().id() == CSSValueNone) + return consumeIdent(range); + RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue = consumeLength(range, cssParserMode, ValueRangeAll); + if (!parsedValue && (unresolvedProperty == CSSPropertyAliasWebkitPerspective)) { + double perspective; + if (!consumeNumberRaw(range, perspective)) + return nullptr; + parsedValue = cssValuePool().createValue(perspective, CSSPrimitiveValue::UnitType::Pixels); + } + if (parsedValue && (parsedValue->isCalculated() || parsedValue->getDoubleValue() > 0)) + return parsedValue.release(); + return nullptr; +} + PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseSingleValue(CSSPropertyID unresolvedProperty) { CSSPropertyID property = resolveCSSPropertyID(unresolvedProperty); @@ -3121,6 +3136,8 @@ return consumeContent(m_range, m_context); case CSSPropertyListStyleImage: return consumeImage(m_range, m_context); + case CSSPropertyPerspective: + return consumePerspective(m_range, m_context.mode(), unresolvedProperty); default: return nullptr; } @@ -3449,25 +3466,27 @@ } } -static void consumeColumnWidthOrCount(CSSParserTokenRange& range, CSSParserMode cssParserMode, RefPtrWillBeRawPtr<CSSValue> &columnWidth, RefPtrWillBeRawPtr<CSSValue> &columnCount) +static bool consumeColumnWidthOrCount(CSSParserTokenRange& range, CSSParserMode cssParserMode, RefPtrWillBeRawPtr<CSSValue> &columnWidth, RefPtrWillBeRawPtr<CSSValue> &columnCount) { if (range.peek().id() == CSSValueAuto) { consumeIdent(range); - return; + return true; } if (!columnWidth) { if ((columnWidth = consumeColumnWidth(range))) - return; + return true; } if (!columnCount) columnCount = consumeColumnCount(range); + return columnCount; } bool CSSPropertyParser::consumeColumns(bool important) { RefPtrWillBeRawPtr<CSSValue> columnWidth = nullptr; RefPtrWillBeRawPtr<CSSValue> columnCount = nullptr; - consumeColumnWidthOrCount(m_range, m_context.mode(), columnWidth, columnCount); + if (!consumeColumnWidthOrCount(m_range, m_context.mode(), columnWidth, columnCount)) + return false; consumeColumnWidthOrCount(m_range, m_context.mode(), columnWidth, columnCount); if (!m_range.atEnd()) return false; @@ -3551,17 +3570,18 @@ return false; } } + if (index == 0) + return false; + if (flexGrow == unsetValue) + flexGrow = 1; + if (flexShrink == unsetValue) + flexShrink = 1; + if (!flexBasis) + flexBasis = cssValuePool().createValue(0, CSSPrimitiveValue::UnitType::Percentage); } + if (!m_range.atEnd()) return false; - - if (flexGrow == unsetValue) - flexGrow = 1; - if (flexShrink == unsetValue) - flexShrink = 1; - if (!flexBasis) - flexBasis = cssValuePool().createValue(0, CSSPrimitiveValue::UnitType::Percentage); - addProperty(CSSPropertyFlexGrow, cssValuePool().createValue(clampTo<float>(flexGrow), CSSPrimitiveValue::UnitType::Number), important); addProperty(CSSPropertyFlexShrink, cssValuePool().createValue(clampTo<float>(flexShrink), CSSPrimitiveValue::UnitType::Number), important); addProperty(CSSPropertyFlexBasis, flexBasis, important);
diff --git a/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp b/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp index 18cd6df..ddb4e9a 100644 --- a/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp +++ b/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp
@@ -530,19 +530,6 @@ validPrimitive = validUnit(value, FInteger); break; - case CSSPropertyPerspective: - if (id == CSSValueNone) { - validPrimitive = true; - } else if (validUnit(value, FLength) && (m_parsedCalculation || value->fValue > 0)) { - validPrimitive = true; - } else if (unresolvedProperty == CSSPropertyAliasWebkitPerspective && validUnit(value, FNumber) && value->fValue > 0) { - value->setUnit(CSSPrimitiveValue::UnitType::Pixels); - validPrimitive = true; - } else { - return false; - } - break; - case CSSPropertyJustifyContent: ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled()); parsedValue = parseContentDistributionOverflowPosition(); @@ -878,6 +865,7 @@ case CSSPropertyContent: case CSSPropertyListStyleImage: case CSSPropertyListStyle: + case CSSPropertyPerspective: validPrimitive = false; break; @@ -2547,7 +2535,7 @@ NamedGridAreaMap::iterator gridAreaIt = gridAreaMap.find(gridAreaName); if (gridAreaIt == gridAreaMap.end()) { - gridAreaMap.add(gridAreaName, GridCoordinate(GridSpan::definiteGridSpan(rowCount, rowCount + 1), GridSpan::definiteGridSpan(currentCol, lookAheadCol))); + gridAreaMap.add(gridAreaName, GridCoordinate(GridSpan::translatedDefiniteGridSpan(rowCount, rowCount + 1), GridSpan::translatedDefiniteGridSpan(currentCol, lookAheadCol))); } else { GridCoordinate& gridCoordinate = gridAreaIt->value; @@ -2564,7 +2552,7 @@ if (lookAheadCol != gridCoordinate.columns.resolvedFinalPosition()) return false; - gridCoordinate.rows = GridSpan::definiteGridSpan(gridCoordinate.rows.resolvedInitialPosition(), gridCoordinate.rows.resolvedFinalPosition() + 1); + gridCoordinate.rows = GridSpan::translatedDefiniteGridSpan(gridCoordinate.rows.resolvedInitialPosition(), gridCoordinate.rows.resolvedFinalPosition() + 1); } currentCol = lookAheadCol - 1; }
diff --git a/third_party/WebKit/Source/core/css/resolver/StyleBuilderCustom.cpp b/third_party/WebKit/Source/core/css/resolver/StyleBuilderCustom.cpp index 92b2c77..8bec77e 100644 --- a/third_party/WebKit/Source/core/css/resolver/StyleBuilderCustom.cpp +++ b/third_party/WebKit/Source/core/css/resolver/StyleBuilderCustom.cpp
@@ -648,20 +648,24 @@ void StyleBuilderFunctions::applyValueCSSPropertyWillChange(StyleResolverState& state, CSSValue* value) { - ASSERT(value->isValueList()); bool willChangeContents = false; bool willChangeScrollPosition = false; Vector<CSSPropertyID> willChangeProperties; - for (auto& willChangeValue : toCSSValueList(*value)) { - if (willChangeValue->isCustomIdentValue()) - willChangeProperties.append(toCSSCustomIdentValue(*willChangeValue).valueAsPropertyID()); - else if (toCSSPrimitiveValue(*willChangeValue).getValueID() == CSSValueContents) - willChangeContents = true; - else if (toCSSPrimitiveValue(*willChangeValue).getValueID() == CSSValueScrollPosition) - willChangeScrollPosition = true; - else - ASSERT_NOT_REACHED(); + if (value->isPrimitiveValue()) { + ASSERT(toCSSPrimitiveValue(value)->getValueID() == CSSValueAuto); + } else { + ASSERT(value->isValueList()); + for (auto& willChangeValue : toCSSValueList(*value)) { + if (willChangeValue->isCustomIdentValue()) + willChangeProperties.append(toCSSCustomIdentValue(*willChangeValue).valueAsPropertyID()); + else if (toCSSPrimitiveValue(*willChangeValue).getValueID() == CSSValueContents) + willChangeContents = true; + else if (toCSSPrimitiveValue(*willChangeValue).getValueID() == CSSValueScrollPosition) + willChangeScrollPosition = true; + else + ASSERT_NOT_REACHED(); + } } state.style()->setWillChangeContents(willChangeContents); state.style()->setWillChangeScrollPosition(willChangeScrollPosition);
diff --git a/third_party/WebKit/Source/core/css/resolver/StyleResolver.cpp b/third_party/WebKit/Source/core/css/resolver/StyleResolver.cpp index a3ced71c..ec2bb0e 100644 --- a/third_party/WebKit/Source/core/css/resolver/StyleResolver.cpp +++ b/third_party/WebKit/Source/core/css/resolver/StyleResolver.cpp
@@ -150,10 +150,10 @@ { FrameView* view = document.view(); if (view) { - m_medium = adoptPtr(new MediaQueryEvaluator(&view->frame())); + m_medium = adoptPtrWillBeNoop(new MediaQueryEvaluator(&view->frame())); m_printMediaType = equalIgnoringCase(view->mediaType(), MediaTypeNames::print); } else { - m_medium = adoptPtr(new MediaQueryEvaluator("all")); + m_medium = adoptPtrWillBeNoop(new MediaQueryEvaluator("all")); } initWatchedSelectorRules(); @@ -1538,6 +1538,7 @@ { #if ENABLE(OILPAN) visitor->trace(m_matchedPropertiesCache); + visitor->trace(m_medium); visitor->trace(m_viewportDependentMediaQueryResults); visitor->trace(m_selectorFilter); visitor->trace(m_viewportStyleResolver);
diff --git a/third_party/WebKit/Source/core/css/resolver/StyleResolver.h b/third_party/WebKit/Source/core/css/resolver/StyleResolver.h index 23c9593..4a8d1e3 100644 --- a/third_party/WebKit/Source/core/css/resolver/StyleResolver.h +++ b/third_party/WebKit/Source/core/css/resolver/StyleResolver.h
@@ -230,7 +230,7 @@ MatchedPropertiesCache m_matchedPropertiesCache; - OwnPtr<MediaQueryEvaluator> m_medium; + OwnPtrWillBeMember<MediaQueryEvaluator> m_medium; MediaQueryResultList m_viewportDependentMediaQueryResults; RawPtrWillBeMember<Document> m_document;
diff --git a/third_party/WebKit/Source/core/dom/ContainerNode.cpp b/third_party/WebKit/Source/core/dom/ContainerNode.cpp index 1e2fe05d..25dfd46 100644 --- a/third_party/WebKit/Source/core/dom/ContainerNode.cpp +++ b/third_party/WebKit/Source/core/dom/ContainerNode.cpp
@@ -1533,6 +1533,9 @@ if (node->isInsertionPoint()) return true; + if (isHTMLSlotElement(node)) + return true; + if (node->isElementNode() && toElement(node)->shadow()) return true;
diff --git a/third_party/WebKit/Source/core/dom/Document.cpp b/third_party/WebKit/Source/core/dom/Document.cpp index 56afe21..6d357f3 100644 --- a/third_party/WebKit/Source/core/dom/Document.cpp +++ b/third_party/WebKit/Source/core/dom/Document.cpp
@@ -2624,8 +2624,9 @@ return; } - // The call to dispatchWindowLoadEvent can detach the LocalDOMWindow and cause it (and its - // attached Document) to be destroyed. + // The call to dispatchWindowLoadEvent (from documentWasClosed()) can detach + // the LocalDOMWindow and cause it (and its attached Document) to be + // destroyed. RefPtrWillBeRawPtr<LocalDOMWindow> protectedWindow(this->domWindow()); m_loadEventProgress = LoadEventInProgress;
diff --git a/third_party/WebKit/Source/core/dom/Document.h b/third_party/WebKit/Source/core/dom/Document.h index 707c2e1..91b3c4e 100644 --- a/third_party/WebKit/Source/core/dom/Document.h +++ b/third_party/WebKit/Source/core/dom/Document.h
@@ -1141,11 +1141,6 @@ void loadEventDelayTimerFired(Timer<Document>*); void pluginLoadingTimerFired(Timer<Document>*); - // Note that dispatching a window load event may cause the LocalDOMWindow to be detached from - // the LocalFrame, so callers should take a reference to the LocalDOMWindow (which owns us) to - // prevent the Document from getting blown away from underneath them. - void dispatchWindowLoadEvent(); - void addListenerType(ListenerType listenerType) { m_listenerTypes |= listenerType; } void addMutationEventListenerTypeIfEnabled(ListenerType);
diff --git a/third_party/WebKit/Source/core/dom/DocumentLifecycle.cpp b/third_party/WebKit/Source/core/dom/DocumentLifecycle.cpp index f1287b0b..72e9e03 100644 --- a/third_party/WebKit/Source/core/dom/DocumentLifecycle.cpp +++ b/third_party/WebKit/Source/core/dom/DocumentLifecycle.cpp
@@ -212,9 +212,8 @@ if (RuntimeEnabledFeatures::slimmingPaintV2Enabled()) { if (nextState == InUpdatePaintProperties) return true; - } else { - if (nextState == InPaint && RuntimeEnabledFeatures::slimmingPaintSynchronizedPaintingEnabled()) - return true; + } else if (nextState == InPaint) { + return true; } break; case InUpdatePaintProperties: @@ -226,12 +225,10 @@ return true; break; case InPaint: - if (nextState == PaintClean && RuntimeEnabledFeatures::slimmingPaintSynchronizedPaintingEnabled()) + if (nextState == PaintClean) return true; break; case PaintClean: - if (!RuntimeEnabledFeatures::slimmingPaintSynchronizedPaintingEnabled()) - break; if (nextState == InStyleRecalc) return true; if (nextState == InPreLayout) @@ -262,7 +259,7 @@ || m_state == LayoutClean || m_state == CompositingClean || m_state == PaintInvalidationClean - || (m_state == PaintClean && RuntimeEnabledFeatures::slimmingPaintSynchronizedPaintingEnabled()); + || m_state == PaintClean; } #endif
diff --git a/third_party/WebKit/Source/core/dom/Element.cpp b/third_party/WebKit/Source/core/dom/Element.cpp index 316ab46..69043a7 100644 --- a/third_party/WebKit/Source/core/dom/Element.cpp +++ b/third_party/WebKit/Source/core/dom/Element.cpp
@@ -695,7 +695,7 @@ if (!element) return nullptr; - if (element->isInShadowTree() && !element->containingShadowRoot()->isOpen()) + if (element->isInShadowTree() && !element->containingShadowRoot()->isOpenOrV0()) return nullptr; return element; @@ -1220,6 +1220,10 @@ invalidateNodeListCachesInAncestors(&name, this); + // If there is currently no StyleResolver, we can't be sure that this attribute change won't affect style. + if (!document().styleResolver()) + setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonForTracing::fromAttribute(name)); + if (inDocument()) { if (AXObjectCache* cache = document().existingAXObjectCache()) cache->handleAttributeChanged(name, this);
diff --git a/third_party/WebKit/Source/core/dom/Node.cpp b/third_party/WebKit/Source/core/dom/Node.cpp index ea3cd12..ff35a956 100644 --- a/third_party/WebKit/Source/core/dom/Node.cpp +++ b/third_party/WebKit/Source/core/dom/Node.cpp
@@ -968,6 +968,38 @@ return isHTMLSlotElement(*this) || isActiveInsertionPoint(*this); } +bool Node::isInV1ShadowTree() const +{ + ShadowRoot* shadowRoot = containingShadowRoot(); + return shadowRoot && shadowRoot->isV1(); +} + +bool Node::isInV0ShadowTree() const +{ + ShadowRoot* shadowRoot = containingShadowRoot(); + return shadowRoot && !shadowRoot->isV1(); +} + +static ElementShadow* parentElementShadow(const Node& node) +{ + Element* parent = node.parentElement(); + if (!parent) + return nullptr; + return parent->shadow(); +} + +bool Node::isChildOfV1ShadowHost() const +{ + ElementShadow* parentShadow = parentElementShadow(*this); + return parentShadow && parentShadow->isV1(); +} + +bool Node::isChildOfV0ShadowHost() const +{ + ElementShadow* parentShadow = parentElementShadow(*this); + return parentShadow && !parentShadow->isV1(); +} + Element* Node::shadowHost() const { if (ShadowRoot* root = containingShadowRoot()) @@ -2201,7 +2233,7 @@ for (size_t i = 0; i < insertionPoints.size(); ++i) { InsertionPoint* insertionPoint = insertionPoints[i]; ASSERT(insertionPoint->containingShadowRoot()); - if (!insertionPoint->containingShadowRoot()->isOpen()) + if (!insertionPoint->containingShadowRoot()->isOpenOrV0()) break; filteredInsertionPoints.append(insertionPoint); } @@ -2211,11 +2243,16 @@ HTMLSlotElement* Node::assignedSlot() const { ASSERT(!needsDistributionRecalc()); - Element* parent = parentElement(); - if (!parent) - return nullptr; - if (ElementShadow* shadow = parent->shadow()) { - if (shadow->isV1() && shadow->isOpen()) + if (ElementShadow* shadow = parentElementShadow(*this)) + return shadow->assignedSlotFor(*this); + return nullptr; +} + +HTMLSlotElement* Node::assignedSlotForBinding() +{ + updateDistribution(); + if (ElementShadow* shadow = parentElementShadow(*this)) { + if (shadow->isV1() && shadow->isOpenOrV0()) return shadow->assignedSlotFor(*this); } return nullptr;
diff --git a/third_party/WebKit/Source/core/dom/Node.h b/third_party/WebKit/Source/core/dom/Node.h index d5b87bc..c4d75f7 100644 --- a/third_party/WebKit/Source/core/dom/Node.h +++ b/third_party/WebKit/Source/core/dom/Node.h
@@ -483,6 +483,11 @@ bool isInShadowTree() const { return getFlag(IsInShadowTreeFlag); } bool isInTreeScope() const { return getFlag(static_cast<NodeFlags>(InDocumentFlag | IsInShadowTreeFlag)); } + bool isInV1ShadowTree() const; + bool isInV0ShadowTree() const; + bool isChildOfV1ShadowHost() const; + bool isChildOfV0ShadowHost() const; + bool isDocumentTypeNode() const { return nodeType() == DOCUMENT_TYPE_NODE; } virtual bool childTypeAllowed(NodeType) const { return false; } unsigned countChildren() const; @@ -660,7 +665,7 @@ PassRefPtrWillBeRawPtr<StaticNodeList> getDestinationInsertionPoints(); HTMLSlotElement* assignedSlot() const; - HTMLSlotElement* assignedSlotForBinding() { updateDistribution(); return assignedSlot(); } + HTMLSlotElement* assignedSlotForBinding(); void setAlreadySpellChecked(bool flag) { setFlag(flag, AlreadySpellCheckedFlag); } bool isAlreadySpellChecked() { return getFlag(AlreadySpellCheckedFlag); }
diff --git a/third_party/WebKit/Source/core/dom/ScriptLoader.cpp b/third_party/WebKit/Source/core/dom/ScriptLoader.cpp index 8032539..e656de6 100644 --- a/third_party/WebKit/Source/core/dom/ScriptLoader.cpp +++ b/third_party/WebKit/Source/core/dom/ScriptLoader.cpp
@@ -259,7 +259,7 @@ LocalFrame* frame = m_element->document().frame(); if (frame) { ScriptState* scriptState = ScriptState::forMainWorld(frame); - if (scriptState->contextIsValid()) + if (scriptState) ScriptStreamer::startStreaming(m_pendingScript, PendingScript::Async, frame->settings(), scriptState, frame->frameScheduler()->loadingTaskRunner()); } contextDocument->scriptRunner()->queueScriptForExecution(this, ScriptRunner::ASYNC_EXECUTION); @@ -301,15 +301,13 @@ request.setDefer(defer); String integrityAttr = m_element->fastGetAttribute(HTMLNames::integrityAttr); - IntegrityMetadataSet metadataSet; if (!integrityAttr.isEmpty()) { + IntegrityMetadataSet metadataSet; SubresourceIntegrity::parseIntegrityAttribute(integrityAttr, metadataSet, elementDocument.get()); request.setIntegrityMetadata(metadataSet); } m_resource = ScriptResource::fetch(request, elementDocument->fetcher()); - if (m_resource && !integrityAttr.isEmpty()) - m_resource->setIntegrityMetadata(metadataSet); m_isExternalScript = true; }
diff --git a/third_party/WebKit/Source/core/dom/shadow/ComposedTreeTraversal.cpp b/third_party/WebKit/Source/core/dom/shadow/ComposedTreeTraversal.cpp index 4050ea18..a1c84831 100644 --- a/third_party/WebKit/Source/core/dom/shadow/ComposedTreeTraversal.cpp +++ b/third_party/WebKit/Source/core/dom/shadow/ComposedTreeTraversal.cpp
@@ -38,6 +38,11 @@ return node.isElementNode() ? toElement(node).shadow() : nullptr; } +static inline bool canBeDistributedToInsertionPoint(const Node& node) +{ + return node.isInV0ShadowTree() || node.isChildOfV0ShadowHost(); +} + Node* ComposedTreeTraversal::traverseChild(const Node& node, TraversalDirection direction) { ElementShadow* shadow = shadowFor(node); @@ -52,13 +57,23 @@ { if (!node) return nullptr; - if (node->isInShadowTree() && node->containingShadowRoot()->isV1()) - return v1ResolveDistributionStartingAt(*node, direction); - return v0ResolveDistributionStartingAt(*node, direction); + for (const Node* sibling = node; sibling; sibling = (direction == TraversalDirectionForward ? sibling->nextSibling() : sibling->previousSibling())) { + if (isHTMLSlotElement(*sibling)) { + const HTMLSlotElement& slot = toHTMLSlotElement(*sibling); + if (Node* found = (direction == TraversalDirectionForward ? slot.firstDistributedNode() : slot.lastDistributedNode())) + return found; + continue; + } + if (node->isInV0ShadowTree()) + return v0ResolveDistributionStartingAt(*sibling, direction); + return const_cast<Node*>(sibling); + } + return nullptr; } Node* ComposedTreeTraversal::v0ResolveDistributionStartingAt(const Node& node, TraversalDirection direction) { + ASSERT(!isHTMLSlotElement(node)); for (const Node* sibling = &node; sibling; sibling = (direction == TraversalDirectionForward ? sibling->nextSibling() : sibling->previousSibling())) { if (!isActiveInsertionPoint(*sibling)) return const_cast<Node*>(sibling); @@ -70,18 +85,6 @@ return nullptr; } -Node* ComposedTreeTraversal::v1ResolveDistributionStartingAt(const Node& node, TraversalDirection direction) -{ - for (const Node* sibling = &node; sibling; sibling = (direction == TraversalDirectionForward ? sibling->nextSibling() : sibling->previousSibling())) { - if (!isHTMLSlotElement(*sibling)) - return const_cast<Node*>(sibling); - const HTMLSlotElement& slot = toHTMLSlotElement(*sibling); - if (Node* found = (direction == TraversalDirectionForward ? slot.firstDistributedNode() : slot.lastDistributedNode())) - return found; - } - return nullptr; -} - static HTMLSlotElement* finalDestinationSlotFor(const Node& node) { HTMLSlotElement* slot = node.assignedSlot(); @@ -93,70 +96,53 @@ return slot; } -Node* ComposedTreeTraversal::traverseSiblings(const Node& node, TraversalDirection direction) -{ - Node* parent = node.parentNode(); - if (!parent) - return nullptr; - if (parent->isElementNode()) { - if (ElementShadow* shadow = toElement(parent)->shadow()) { - if (shadow->isV1()) { - return v1TraverseSiblings(node, direction); - } - } - } - return v0TraverseSiblings(node, direction); -} - // TODO(hayato): This may return a wrong result for a node which is not in a // document composed tree. See ComposedTreeTraversalTest's redistribution test for details. -Node* ComposedTreeTraversal::v0TraverseSiblings(const Node& node, TraversalDirection direction) +Node* ComposedTreeTraversal::traverseSiblings(const Node& node, TraversalDirection direction) { - if (!shadowWhereNodeCanBeDistributed(node)) - return traverseSiblingsOrShadowInsertionPointSiblings(node, direction); + if (node.isChildOfV1ShadowHost()) + return traverseSiblingsForV1HostChild(node, direction); + if (shadowWhereNodeCanBeDistributed(node)) + return traverseSiblingsForV0Distribution(node, direction); + + if (Node* found = resolveDistributionStartingAt(direction == TraversalDirectionForward ? node.nextSibling() : node.previousSibling(), direction)) + return found; + + if (!node.isInV0ShadowTree()) + return nullptr; + + // For v0 older shadow tree + if (node.parentNode() && node.parentNode()->isShadowRoot()) { + ShadowRoot* parentShadowRoot = toShadowRoot(node.parentNode()); + if (!parentShadowRoot->isYoungest()) { + HTMLShadowElement* assignedInsertionPoint = parentShadowRoot->shadowInsertionPointOfYoungerShadowRoot(); + ASSERT(assignedInsertionPoint); + return traverseSiblings(*assignedInsertionPoint, direction); + } + } + return nullptr; +} + +Node* ComposedTreeTraversal::traverseSiblingsForV1HostChild(const Node& node, TraversalDirection direction) +{ + HTMLSlotElement* slot = finalDestinationSlotFor(node); + if (!slot) + return nullptr; + if (Node* siblingInDistributedNodes = (direction == TraversalDirectionForward ? slot->distributedNodeNextTo(node) : slot->distributedNodePreviousTo(node))) + return siblingInDistributedNodes; + return traverseSiblings(*slot, direction); +} + +Node* ComposedTreeTraversal::traverseSiblingsForV0Distribution(const Node& node, TraversalDirection direction) +{ const InsertionPoint* finalDestination = resolveReprojection(&node); if (!finalDestination) return nullptr; if (Node* found = (direction == TraversalDirectionForward ? finalDestination->distributedNodeNextTo(&node) : finalDestination->distributedNodePreviousTo(&node))) return found; return traverseSiblings(*finalDestination, direction); -} -Node* ComposedTreeTraversal::v1TraverseSiblings(const Node& node, TraversalDirection direction) -{ - HTMLSlotElement* slot = finalDestinationSlotFor(node); - if (!slot) - return resolveDistributionStartingAt(direction == TraversalDirectionForward ? node.nextSibling() : node.previousSibling(), direction); - if (Node* siblingInDistributedNodes = (direction == TraversalDirectionForward ? slot->distributedNodeNextTo(node) : slot->distributedNodePreviousTo(node))) - return siblingInDistributedNodes; - return v1TraverseSiblings(*slot, direction); -} - -Node* ComposedTreeTraversal::traverseSiblingsOrShadowInsertionPointSiblings(const Node& node, TraversalDirection direction) -{ - if (Node* found = resolveDistributionStartingAt(direction == TraversalDirectionForward ? node.nextSibling() : node.previousSibling(), direction)) - return found; - - if (node.parentNode() && node.parentNode()->isShadowRoot()) { - ShadowRoot* parentShadowRoot = toShadowRoot(node.parentNode()); - if (!parentShadowRoot->isYoungest()) { - HTMLShadowElement* assignedInsertionPoint = parentShadowRoot->shadowInsertionPointOfYoungerShadowRoot(); - ASSERT(assignedInsertionPoint); - return traverseSiblingsOrShadowInsertionPointSiblings(*assignedInsertionPoint, direction); - } - } - return nullptr; -} - -static ElementShadow* parentElementShadow(const Node& node) -{ - Node* parent = node.parentNode(); - if (!parent) - return nullptr; - if (parent->isElementNode()) - return toElement(parent)->shadow(); - return nullptr; } ContainerNode* ComposedTreeTraversal::traverseParent(const Node& node, ParentTraversalDetails* details) @@ -165,43 +151,49 @@ if (node.isPseudoElement()) return node.parentOrShadowHostNode(); - ElementShadow* shadow = parentElementShadow(node); - if (shadow && shadow->isV1()) - return v1TraverseParent(node); - if (shadowWhereNodeCanBeDistributed(node)) - return v0TraverseParent(node, details); + if (node.isChildOfV1ShadowHost()) { + HTMLSlotElement* slot = finalDestinationSlotFor(node); + if (!slot) + return nullptr; + return traverseParent(*slot); + } + + Element* parent = node.parentElement(); + if (parent && isHTMLSlotElement(parent)) { + HTMLSlotElement& slot = toHTMLSlotElement(*parent); + if (!slot.getAssignedNodes().isEmpty()) + return nullptr; + return traverseParent(slot, details); + } + + if (canBeDistributedToInsertionPoint(node)) + return traverseParentForV0(node, details); + + ASSERT(!shadowWhereNodeCanBeDistributed(node)); return traverseParentOrHost(node); } -ContainerNode* ComposedTreeTraversal::v1TraverseParent(const Node& node) +ContainerNode* ComposedTreeTraversal::traverseParentForV0(const Node& node, ParentTraversalDetails* details) { - HTMLSlotElement* slot = finalDestinationSlotFor(node); - if (!slot) - return nullptr; - if (parentElementShadow(*slot)) { - // The node is distributed to the |slot|, however, |slot|, which is a - // child of a shadow host, is not assigned to any slots. + if (shadowWhereNodeCanBeDistributed(node)) { + if (const InsertionPoint* insertionPoint = resolveReprojection(&node)) { + if (details) + details->didTraverseInsertionPoint(insertionPoint); + // The node is distributed. But the distribution was stopped at this insertion point. + if (shadowWhereNodeCanBeDistributed(*insertionPoint)) + return nullptr; + return traverseParent(*insertionPoint); + } return nullptr; } - return traverseParentOrHost(*slot); + ContainerNode* parent = traverseParentOrHost(node); + if (isActiveInsertionPoint(*parent)) + return nullptr; + return parent; } -ContainerNode* ComposedTreeTraversal::v0TraverseParent(const Node& node, ParentTraversalDetails* details) +ContainerNode* ComposedTreeTraversal::traverseParentOrHost(const Node& node) { - if (const InsertionPoint* insertionPoint = resolveReprojection(&node)) { - if (details) - details->didTraverseInsertionPoint(insertionPoint); - // The node is distributed. But the distribution was stopped at this insertion point. - if (shadowWhereNodeCanBeDistributed(*insertionPoint)) - return nullptr; - return traverseParentOrHost(*insertionPoint); - } - return nullptr; -} - -inline ContainerNode* ComposedTreeTraversal::traverseParentOrHost(const Node& node) -{ - // TODO(hayato): Support fallback contents of slots. The parent can be a slot. ContainerNode* parent = node.parentNode(); if (!parent) return nullptr; @@ -211,10 +203,7 @@ ASSERT(!shadowRoot->shadowInsertionPointOfYoungerShadowRoot()); if (!shadowRoot->isYoungest()) return nullptr; - Element* host = shadowRoot->host(); - if (isActiveInsertionPoint(*host)) - return nullptr; - return host; + return shadowRoot->host(); } Node* ComposedTreeTraversal::childAt(const Node& node, unsigned index)
diff --git a/third_party/WebKit/Source/core/dom/shadow/ComposedTreeTraversal.h b/third_party/WebKit/Source/core/dom/shadow/ComposedTreeTraversal.h index 844f490..9a5e7cc 100644 --- a/third_party/WebKit/Source/core/dom/shadow/ComposedTreeTraversal.h +++ b/third_party/WebKit/Source/core/dom/shadow/ComposedTreeTraversal.h
@@ -140,7 +140,6 @@ } static Node* resolveDistributionStartingAt(const Node*, TraversalDirection); - static Node* v1ResolveDistributionStartingAt(const Node&, TraversalDirection); static Node* v0ResolveDistributionStartingAt(const Node&, TraversalDirection); static Node* traverseNext(const Node&); @@ -154,19 +153,16 @@ static ContainerNode* traverseParent(const Node&, ParentTraversalDetails* = 0); // TODO(hayato): Make ParentTraversalDetails be aware of slot elements too. - static ContainerNode* v1TraverseParent(const Node&); - static ContainerNode* v0TraverseParent(const Node&, ParentTraversalDetails* = 0); + static ContainerNode* traverseParentForV0(const Node&, ParentTraversalDetails* = 0); + static ContainerNode* traverseParentOrHost(const Node&); static Node* traverseNextSibling(const Node&); static Node* traversePreviousSibling(const Node&); static Node* traverseSiblings(const Node&, TraversalDirection); - static Node* v1TraverseSiblings(const Node&, TraversalDirection); - static Node* v0TraverseSiblings(const Node&, TraversalDirection); + static Node* traverseSiblingsForV1HostChild(const Node&, TraversalDirection); + static Node* traverseSiblingsForV0Distribution(const Node&, TraversalDirection); - static Node* traverseSiblingsOrShadowInsertionPointSiblings(const Node&, TraversalDirection); - - static ContainerNode* traverseParentOrHost(const Node&); static Node* traverseNextAncestorSibling(const Node&); static Node* traversePreviousAncestorSibling(const Node&); };
diff --git a/third_party/WebKit/Source/core/dom/shadow/ElementShadow.h b/third_party/WebKit/Source/core/dom/shadow/ElementShadow.h index 7a8d8b9..925156c4 100644 --- a/third_party/WebKit/Source/core/dom/shadow/ElementShadow.h +++ b/third_party/WebKit/Source/core/dom/shadow/ElementShadow.h
@@ -84,7 +84,7 @@ void didDistributeNode(const Node*, InsertionPoint*); bool isV1() const { return youngestShadowRoot().isV1(); }; - bool isOpen() const { return youngestShadowRoot().isOpen(); }; + bool isOpenOrV0() const { return youngestShadowRoot().isOpenOrV0(); }; DECLARE_TRACE();
diff --git a/third_party/WebKit/Source/core/dom/shadow/ShadowRoot.cpp b/third_party/WebKit/Source/core/dom/shadow/ShadowRoot.cpp index 3a4a3e9..b0703a6 100644 --- a/third_party/WebKit/Source/core/dom/shadow/ShadowRoot.cpp +++ b/third_party/WebKit/Source/core/dom/shadow/ShadowRoot.cpp
@@ -104,9 +104,9 @@ ShadowRoot* ShadowRoot::olderShadowRootForBindings() const { ShadowRoot* older = olderShadowRoot(); - while (older && !older->isOpen()) + while (older && !older->isOpenOrV0()) older = older->olderShadowRoot(); - ASSERT(!older || older->isOpen()); + ASSERT(!older || older->isOpenOrV0()); return older; }
diff --git a/third_party/WebKit/Source/core/dom/shadow/ShadowRoot.h b/third_party/WebKit/Source/core/dom/shadow/ShadowRoot.h index c8591f002..bc4572ad 100644 --- a/third_party/WebKit/Source/core/dom/shadow/ShadowRoot.h +++ b/third_party/WebKit/Source/core/dom/shadow/ShadowRoot.h
@@ -78,7 +78,9 @@ ShadowRoot* youngerShadowRoot() const { return prev(); } ShadowRoot* olderShadowRootForBindings() const; - bool isOpen() const { return type() == ShadowRootType::V0 || type() == ShadowRootType::Open; } + + bool isOpenOrV0() const { return type() == ShadowRootType::V0 || type() == ShadowRootType::Open; } + bool isV1() const { return type() == ShadowRootType::Open || type() == ShadowRootType::Closed; } bool isYoungest() const { return !youngerShadowRoot(); }
diff --git a/third_party/WebKit/Source/core/dom/shadow/SlotAssignment.cpp b/third_party/WebKit/Source/core/dom/shadow/SlotAssignment.cpp index 9699e4a..ae12fb7 100644 --- a/third_party/WebKit/Source/core/dom/shadow/SlotAssignment.cpp +++ b/third_party/WebKit/Source/core/dom/shadow/SlotAssignment.cpp
@@ -28,14 +28,17 @@ { m_assignment.clear(); - using Name2Slot = HashMap<AtomicString, HTMLSlotElement*>; + using Name2Slot = WillBeHeapHashMap<AtomicString, RefPtrWillBeMember<HTMLSlotElement>>; Name2Slot name2slot; HTMLSlotElement* defaultSlot = nullptr; + WillBeHeapVector<RefPtrWillBeMember<HTMLSlotElement>> slots; // TODO(hayato): Cache slots elements so that we do not have to travese the shadow tree. See ShadowRoot::descendantInsertionPoints() for (HTMLSlotElement& slot : Traversal<HTMLSlotElement>::descendantsOf(shadowRoot)) { slot.clearDistribution(); + slots.append(&slot); + AtomicString name = slot.fastGetAttribute(HTMLNames::nameAttr); if (name.isNull() || name.isEmpty()) { if (!defaultSlot) @@ -71,6 +74,10 @@ detachNotAssignedNode(child); } } + + // Update each slot's distribution in reverse tree order so that a child slot is visited before its parent slot. + for (auto slot = slots.rbegin(); slot != slots.rend(); ++slot) + (*slot)->updateDistributedNodesWithFallback(); } void SlotAssignment::assign(Node& hostChild, HTMLSlotElement& slot)
diff --git a/third_party/WebKit/Source/core/editing/CaretBase.cpp b/third_party/WebKit/Source/core/editing/CaretBase.cpp index 1ceb458c..24b7b49 100644 --- a/third_party/WebKit/Source/core/editing/CaretBase.cpp +++ b/third_party/WebKit/Source/core/editing/CaretBase.cpp
@@ -68,7 +68,7 @@ static void mapCaretRectToCaretPainter(LayoutObject* caretLayoutObject, LayoutBlock* caretPainter, LayoutRect& caretRect) { // FIXME: This shouldn't be called on un-rooted subtrees. - // FIXME: This should probably just use mapLocalToContainer. + // FIXME: This should probably just use mapLocalToAncestor. // Compute an offset between the caretLayoutObject and the caretPainter. ASSERT(caretLayoutObject->isDescendantOf(caretPainter)); @@ -137,7 +137,7 @@ LayoutRect inflatedRect = rect; inflatedRect.inflate(1); - // FIXME: We should use mapLocalToContainer() since we know we're not un-rooted. + // FIXME: We should use mapLocalToAncestor() since we know we're not un-rooted. mapCaretRectToCaretPainter(node->layoutObject(), caretPainter, inflatedRect); // FIXME: We should not allow paint invalidation out of paint invalidation state. crbug.com/457415
diff --git a/third_party/WebKit/Source/core/editing/VisibleUnits.cpp b/third_party/WebKit/Source/core/editing/VisibleUnits.cpp index f3c9222..1ea913e 100644 --- a/third_party/WebKit/Source/core/editing/VisibleUnits.cpp +++ b/third_party/WebKit/Source/core/editing/VisibleUnits.cpp
@@ -688,6 +688,8 @@ bool inTextSecurityMode = it.node() && it.node()->layoutObject() && it.node()->layoutObject()->style()->textSecurity() != TSNONE; // iterate to get chunks until the searchFunction returns a non-zero // value. + // TODO(xiaochengh): Iterative prepending has quadratic running time + // in the worst case. Should improve it to linear. if (!inTextSecurityMode) { it.prependTextTo(string); } else { @@ -697,6 +699,9 @@ iteratorString.fill('x', it.length()); string.prepend(iteratorString.data(), iteratorString.size()); } + // TODO(xiaochengh): The following line takes O(string.size()) time, + // which makes the while loop take quadratic time in the worst case. + // Should improve it in some way. next = searchFunction(string.data(), string.size(), string.size() - suffixLength, MayHaveMoreContext, needMoreContext); if (next) break; @@ -706,6 +711,7 @@ // The last search returned the beginning of the buffer and asked for // more context, but there is no earlier text. Force a search with // what's available. + // TODO(xiaochengh): Do we have to search the whole string? next = searchFunction(string.data(), string.size(), string.size() - suffixLength, DontHaveMoreContext, needMoreContext); ASSERT(!needMoreContext); } @@ -748,6 +754,8 @@ backwardsIterator.prependTextTo(characters); int length = characters.size(); int i = startOfLastWordBoundaryContext(characters.data(), length); + // TODO(xiaochengh): Iterative prepending has quadratic running + // time in the worst case. Should improve it to linear. string.prepend(characters.data() + i, length - i); prefixLength += length - i; if (i > 0) @@ -761,6 +769,7 @@ TextIteratorAlgorithm<Strategy> it(searchStart, searchEnd, TextIteratorEmitsCharactersBetweenAllVisiblePositions); const unsigned invalidOffset = static_cast<unsigned>(-1); unsigned next = invalidOffset; + unsigned offset = prefixLength; bool needMoreContext = false; while (!it.atEnd()) { // Keep asking the iterator for chunks until the search function @@ -776,15 +785,22 @@ iteratorString.fill('x', it.length()); string.append(iteratorString.data(), iteratorString.size()); } - next = searchFunction(string.data(), string.size(), prefixLength, MayHaveMoreContext, needMoreContext); + next = searchFunction(string.data(), string.size(), offset, MayHaveMoreContext, needMoreContext); if (next != string.size()) break; it.advance(); + if (!needMoreContext) { + // When the search does not need more context, skip all examined + // characters except the last one, in case it is a boundary. + offset = string.size(); + U16_BACK_1(string.data(), 0, offset); + } } if (needMoreContext) { // The last search returned the end of the buffer and asked for more // context, but there is no further text. Force a search with what's // available. + // TODO(xiaochengh): Do we still have to search the whole string? next = searchFunction(string.data(), string.size(), prefixLength, DontHaveMoreContext, needMoreContext); ASSERT(!needMoreContext); } @@ -818,6 +834,7 @@ static unsigned startWordBoundary(const UChar* characters, unsigned length, unsigned offset, BoundarySearchContextAvailability mayHaveMoreContext, bool& needMoreContext) { + TRACE_EVENT0("blink", "startWordBoundary"); ASSERT(offset); if (mayHaveMoreContext && !startOfLastWordBoundaryContext(characters, offset)) { needMoreContext = true;
diff --git a/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.cpp b/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.cpp index 150081b..dc49ff08 100644 --- a/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.cpp +++ b/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.cpp
@@ -479,6 +479,24 @@ chunkAndMarkAllMisspellingsAndBadGrammar(textCheckingOptions, fullParagraphToCheck); } +static EphemeralRange expandEndToSentenceBoundary(const EphemeralRange& range) +{ + ASSERT(range.isNotNull()); + const VisiblePosition& visibleEnd = createVisiblePosition(range.endPosition()); + ASSERT(visibleEnd.isNotNull()); + const Position& sentenceEnd = endOfSentence(visibleEnd).deepEquivalent(); + return EphemeralRange(range.startPosition(), sentenceEnd.isNotNull() ? sentenceEnd : range.endPosition()); +} + +static EphemeralRange expandRangeToSentenceBoundary(const EphemeralRange& range) +{ + ASSERT(range.isNotNull()); + const VisiblePosition& visibleStart = createVisiblePosition(range.startPosition()); + ASSERT(visibleStart.isNotNull()); + const Position& sentenceStart = startOfSentence(visibleStart).deepEquivalent(); + return expandEndToSentenceBoundary(EphemeralRange(sentenceStart.isNull() ? range.startPosition() : sentenceStart, range.endPosition())); +} + void SpellChecker::chunkAndMarkAllMisspellingsAndBadGrammar(Node* node) { TRACE_EVENT0("blink", "SpellChecker::chunkAndMarkAllMisspellingsAndBadGrammar"); @@ -493,40 +511,27 @@ { if (fullParagraphToCheck.isEmpty()) return; + const EphemeralRange& paragraphRange = fullParagraphToCheck.paragraphRange(); // Since the text may be quite big chunk it up and adjust to the sentence boundary. const int kChunkSize = 16 * 1024; - int start = fullParagraphToCheck.checkingStart(); - int end = fullParagraphToCheck.checkingEnd(); - start = std::min(start, end); - end = std::max(start, end); - const int kNumChunksToCheck = (end - start + kChunkSize - 1) / kChunkSize; - int currentChunkStart = start; - if (kNumChunksToCheck == 1) { - EphemeralRange checkRange = fullParagraphToCheck.checkingRange(); - markAllMisspellingsAndBadGrammarInRanges(textCheckingOptions, checkRange, checkRange, 0); - return; + CharacterIterator checkRangeIterator(fullParagraphToCheck.checkingRange(), TextIteratorEmitsObjectReplacementCharacter); + for (int requestNum = 0; !checkRangeIterator.atEnd(); requestNum++) { + EphemeralRange chunkRange = checkRangeIterator.calculateCharacterSubrange(0, kChunkSize); + EphemeralRange checkRange = requestNum ? expandEndToSentenceBoundary(chunkRange) : expandRangeToSentenceBoundary(chunkRange); + + RefPtrWillBeRawPtr<SpellCheckRequest> request = SpellCheckRequest::create(resolveTextCheckingTypeMask(textCheckingOptions), TextCheckingProcessBatch, checkRange, paragraphRange, requestNum); + if (request) + m_spellCheckRequester->requestCheckingFor(request); + + if (!checkRangeIterator.atEnd()) { + checkRangeIterator.advance(1); + // The layout should be already update due to the initialization of checkRangeIterator, + // so comparePositions can be directly called. + if (comparePositions(chunkRange.endPosition(), checkRange.endPosition()) < 0) + checkRangeIterator.advance(TextIterator::rangeLength(chunkRange.endPosition(), checkRange.endPosition())); + } } - - for (int iter = 0; iter < kNumChunksToCheck; ++iter) { - EphemeralRange checkRange = expandRangeToSentenceBoundary(fullParagraphToCheck.subrange(currentChunkStart, kChunkSize)); - int checkingLength = 0; - markAllMisspellingsAndBadGrammarInRanges(textCheckingOptions, checkRange, checkRange, iter, &checkingLength); - currentChunkStart += checkingLength; - } -} - -void SpellChecker::markAllMisspellingsAndBadGrammarInRanges(TextCheckingTypeMask textCheckingOptions, const EphemeralRange& checkRange, const EphemeralRange& paragraphRange, int requestNumber, int* checkingLength) -{ - TextCheckingParagraph sentenceToCheck(checkRange, paragraphRange); - if (checkingLength) - *checkingLength = sentenceToCheck.checkingLength(); - - RefPtrWillBeRawPtr<SpellCheckRequest> request = SpellCheckRequest::create(resolveTextCheckingTypeMask(textCheckingOptions), TextCheckingProcessBatch, checkRange, paragraphRange, requestNumber); - if (!request) - return; - - m_spellCheckRequester->requestCheckingFor(request); } void SpellChecker::markAndReplaceFor(PassRefPtrWillBeRawPtr<SpellCheckRequest> request, const Vector<TextCheckingResult>& results)
diff --git a/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.h b/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.h index f3138ab3..57ae728 100644 --- a/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.h +++ b/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.h
@@ -106,7 +106,6 @@ bool unifiedTextCheckerEnabled() const; void chunkAndMarkAllMisspellingsAndBadGrammar(TextCheckingTypeMask textCheckingOptions, const TextCheckingParagraph& fullParagraphToCheck); - void markAllMisspellingsAndBadGrammarInRanges(TextCheckingTypeMask textCheckingOptions, const EphemeralRange& checkingRange, const EphemeralRange& paragraphRange, int requestNumber, int* checkingLength = 0); RawPtrWillBeMember<LocalFrame> m_frame; const OwnPtrWillBeMember<SpellCheckRequester> m_spellCheckRequester;
diff --git a/third_party/WebKit/Source/core/editing/spellcheck/TextCheckingHelper.cpp b/third_party/WebKit/Source/core/editing/spellcheck/TextCheckingHelper.cpp index 719b31a..a992fd2 100644 --- a/third_party/WebKit/Source/core/editing/spellcheck/TextCheckingHelper.cpp +++ b/third_party/WebKit/Source/core/editing/spellcheck/TextCheckingHelper.cpp
@@ -95,21 +95,6 @@ } } -// TODO(yosin): We should move |expandRangeToSentenceBoundary()| to -// "SpellChcker.cpp" as static function, since there is only one call site in -// |SpellChecker::chunkAndMarkAllMisspellingsAndBadGrammar()|. -EphemeralRange expandRangeToSentenceBoundary(const EphemeralRange& range) -{ - ASSERT(range.isNotNull()); - const VisiblePosition& visibleStart = createVisiblePosition(range.startPosition()); - ASSERT(visibleStart.isNotNull()); - const Position& sentenceStart = startOfSentence(visibleStart).deepEquivalent(); - const VisiblePosition& visibleEnd = createVisiblePosition(range.endPosition()); - ASSERT(visibleEnd.isNotNull()); - const Position& sentenceEnd = endOfSentence(visibleEnd).deepEquivalent(); - return EphemeralRange(sentenceStart.isNull() ? range.startPosition() : sentenceStart, sentenceEnd.isNull() ? range.endPosition() : sentenceEnd); -} - static EphemeralRange expandToParagraphBoundary(const EphemeralRange& range) { return EphemeralRange(startOfParagraph(createVisiblePosition(range.startPosition())).deepEquivalent(), endOfParagraph(createVisiblePosition(range.endPosition())).deepEquivalent());
diff --git a/third_party/WebKit/Source/core/editing/spellcheck/TextCheckingHelper.h b/third_party/WebKit/Source/core/editing/spellcheck/TextCheckingHelper.h index 7eae542..5f778934 100644 --- a/third_party/WebKit/Source/core/editing/spellcheck/TextCheckingHelper.h +++ b/third_party/WebKit/Source/core/editing/spellcheck/TextCheckingHelper.h
@@ -104,7 +104,6 @@ }; void checkTextOfParagraph(TextCheckerClient&, const String&, TextCheckingTypeMask, Vector<TextCheckingResult>&); -EphemeralRange expandRangeToSentenceBoundary(const EphemeralRange&); bool unifiedTextCheckerEnabled(const LocalFrame*); } // namespace blink
diff --git a/third_party/WebKit/Source/core/events/TreeScopeEventContext.cpp b/third_party/WebKit/Source/core/events/TreeScopeEventContext.cpp index db2d8fb..288119e4d 100644 --- a/third_party/WebKit/Source/core/events/TreeScopeEventContext.cpp +++ b/third_party/WebKit/Source/core/events/TreeScopeEventContext.cpp
@@ -114,7 +114,7 @@ int TreeScopeEventContext::calculateTreeOrderAndSetNearestAncestorClosedTree(int orderNumber, TreeScopeEventContext* nearestAncestorClosedTreeScopeEventContext) { m_preOrder = orderNumber; - m_containingClosedShadowTree = (rootNode().isShadowRoot() && !toShadowRoot(rootNode()).isOpen()) ? this : nearestAncestorClosedTreeScopeEventContext; + m_containingClosedShadowTree = (rootNode().isShadowRoot() && !toShadowRoot(rootNode()).isOpenOrV0()) ? this : nearestAncestorClosedTreeScopeEventContext; for (size_t i = 0; i < m_children.size(); ++i) orderNumber = m_children[i]->calculateTreeOrderAndSetNearestAncestorClosedTree(orderNumber + 1, containingClosedShadowTree()); m_postOrder = orderNumber + 1;
diff --git a/third_party/WebKit/Source/core/fetch/CSSStyleSheetResource.cpp b/third_party/WebKit/Source/core/fetch/CSSStyleSheetResource.cpp index f1abd0c..53fc85d 100644 --- a/third_party/WebKit/Source/core/fetch/CSSStyleSheetResource.cpp +++ b/third_party/WebKit/Source/core/fetch/CSSStyleSheetResource.cpp
@@ -44,6 +44,11 @@ return toCSSStyleSheetResource(fetcher->requestResource(request, CSSStyleSheetResourceFactory())); } +ResourcePtr<CSSStyleSheetResource> CSSStyleSheetResource::createForTest(const ResourceRequest& request, const String& charset) +{ + return new CSSStyleSheetResource(request, charset); +} + CSSStyleSheetResource::CSSStyleSheetResource(const ResourceRequest& resourceRequest, const String& charset) : StyleSheetResource(resourceRequest, CSSStyleSheet, "text/css", charset) {
diff --git a/third_party/WebKit/Source/core/fetch/CSSStyleSheetResource.h b/third_party/WebKit/Source/core/fetch/CSSStyleSheetResource.h index eafa35d..411e7e10 100644 --- a/third_party/WebKit/Source/core/fetch/CSSStyleSheetResource.h +++ b/third_party/WebKit/Source/core/fetch/CSSStyleSheetResource.h
@@ -26,6 +26,7 @@ #ifndef CSSStyleSheetResource_h #define CSSStyleSheetResource_h +#include "core/CoreExport.h" #include "core/fetch/ResourcePtr.h" #include "core/fetch/StyleSheetResource.h" #include "platform/heap/Handle.h" @@ -38,11 +39,12 @@ class ResourceFetcher; class StyleSheetContents; -class CSSStyleSheetResource final : public StyleSheetResource { +class CORE_EXPORT CSSStyleSheetResource final : public StyleSheetResource { public: enum class MIMETypeCheck { Strict, Lax }; static ResourcePtr<CSSStyleSheetResource> fetch(FetchRequest&, ResourceFetcher*); + static ResourcePtr<CSSStyleSheetResource> createForTest(const ResourceRequest&, const String& charset); ~CSSStyleSheetResource() override; DECLARE_VIRTUAL_TRACE();
diff --git a/third_party/WebKit/Source/core/fetch/MemoryCache.cpp b/third_party/WebKit/Source/core/fetch/MemoryCache.cpp index 80ee6f7f8..024cbdc1 100644 --- a/third_party/WebKit/Source/core/fetch/MemoryCache.cpp +++ b/third_party/WebKit/Source/core/fetch/MemoryCache.cpp
@@ -347,7 +347,7 @@ } // Decoded data may reference other resources. Stop iterating if 'previous' somehow got // kicked out of cache during destroyDecodedData(). - if (previous && !contains(previous->m_resource.get())) + if (!previous || !previous->m_resource || !contains(previous->m_resource.get())) break; current = previous; } @@ -372,7 +372,7 @@ if (targetSize && m_deadSize <= targetSize) return; } - if (previous && !contains(previous->m_resource.get())) + if (!previous || !previous->m_resource || !contains(previous->m_resource.get())) break; current = previous; } @@ -791,6 +791,15 @@ } } +bool MemoryCache::isInSameLRUListForTest(const Resource* x, const Resource* y) +{ + MemoryCacheEntry* ex = getEntryForResource(x); + MemoryCacheEntry* ey = getEntryForResource(y); + ASSERT(ex); + ASSERT(ey); + return lruListFor(ex->m_accessCount, x->size()) == lruListFor(ey->m_accessCount, y->size()); +} + void MemoryCache::registerLiveResource(Resource& resource) { #if ENABLE(OILPAN)
diff --git a/third_party/WebKit/Source/core/fetch/MemoryCache.h b/third_party/WebKit/Source/core/fetch/MemoryCache.h index ad1cb6a65..06f426cc 100644 --- a/third_party/WebKit/Source/core/fetch/MemoryCache.h +++ b/third_party/WebKit/Source/core/fetch/MemoryCache.h
@@ -236,6 +236,7 @@ // Take memory usage snapshot for tracing. void onMemoryDump(WebMemoryDumpLevelOfDetail, WebProcessMemoryDump*); + bool isInSameLRUListForTest(const Resource*, const Resource*); private: enum PruneStrategy { // Automatically decide how much to prune.
diff --git a/third_party/WebKit/Source/core/fetch/ScriptResource.cpp b/third_party/WebKit/Source/core/fetch/ScriptResource.cpp index c4c35e6..fb4cfdd 100644 --- a/third_party/WebKit/Source/core/fetch/ScriptResource.cpp +++ b/third_party/WebKit/Source/core/fetch/ScriptResource.cpp
@@ -41,7 +41,10 @@ { ASSERT(request.resourceRequest().frameType() == WebURLRequest::FrameTypeNone); request.mutableResourceRequest().setRequestContext(WebURLRequest::RequestContextScript); - return toScriptResource(fetcher->requestResource(request, ScriptResourceFactory())); + ResourcePtr<ScriptResource> resource = toScriptResource(fetcher->requestResource(request, ScriptResourceFactory())); + if (resource && !request.integrityMetadata().isEmpty()) + resource->setIntegrityMetadata(request.integrityMetadata()); + return resource; } ScriptResource::ScriptResource(const ResourceRequest& resourceRequest, const String& charset)
diff --git a/third_party/WebKit/Source/core/fetch/StyleSheetResource.h b/third_party/WebKit/Source/core/fetch/StyleSheetResource.h index 0b9fb405..51c8567 100644 --- a/third_party/WebKit/Source/core/fetch/StyleSheetResource.h +++ b/third_party/WebKit/Source/core/fetch/StyleSheetResource.h
@@ -31,13 +31,14 @@ #ifndef StyleSheetResource_h #define StyleSheetResource_h +#include "core/CoreExport.h" #include "core/fetch/TextResource.h" namespace blink { class StyleSheetResourceClient; -class StyleSheetResource : public TextResource { +class CORE_EXPORT StyleSheetResource : public TextResource { public: using ClientType = StyleSheetResourceClient;
diff --git a/third_party/WebKit/Source/core/frame/FrameView.cpp b/third_party/WebKit/Source/core/frame/FrameView.cpp index 751d7fb..97525f35 100644 --- a/third_party/WebKit/Source/core/frame/FrameView.cpp +++ b/third_party/WebKit/Source/core/frame/FrameView.cpp
@@ -2040,7 +2040,7 @@ ASSERT(m_frame->view() == this); LayoutRect clipRect(LayoutPoint(), LayoutSize(visibleContentSize(scrollbarInclusion))); - layoutView()->mapToVisibleRectInContainerSpace(&layoutView()->containerForPaintInvalidation(), clipRect, nullptr); + layoutView()->mapToVisibleRectInAncestorSpace(&layoutView()->containerForPaintInvalidation(), clipRect, nullptr); return enclosingIntRect(clipRect); } @@ -2375,6 +2375,11 @@ // Updating layout can run script, which can tear down the FrameView. RefPtrWillBeRawPtr<FrameView> protector(this); + if (shouldThrottleRendering()) { + updateViewportIntersectionsForSubtree(); + return; + } + updateStyleAndLayoutIfNeededRecursive(); ASSERT(lifecycle().state() >= DocumentLifecycle::LayoutClean); @@ -2408,7 +2413,7 @@ if (RuntimeEnabledFeatures::slimmingPaintV2Enabled()) updatePaintProperties(); - if (RuntimeEnabledFeatures::slimmingPaintSynchronizedPaintingEnabled() && !m_frame->document()->printing()) + if (!m_frame->document()->printing()) synchronizedPaint(); if (RuntimeEnabledFeatures::frameTimingSupportEnabled()) @@ -2418,8 +2423,8 @@ pushPaintArtifactToCompositor(); ASSERT(!view->hasPendingSelection()); - ASSERT(lifecycle().state() == DocumentLifecycle::PaintInvalidationClean - || (RuntimeEnabledFeatures::slimmingPaintSynchronizedPaintingEnabled() && lifecycle().state() == DocumentLifecycle::PaintClean)); + ASSERT((m_frame->document()->printing() && lifecycle().state() == DocumentLifecycle::PaintInvalidationClean) + || lifecycle().state() == DocumentLifecycle::PaintClean); } } @@ -2428,6 +2433,8 @@ void FrameView::updatePaintProperties() { + TRACE_EVENT0("blink", "FrameView::updatePaintProperties"); + ASSERT(RuntimeEnabledFeatures::slimmingPaintV2Enabled()); forAllNonThrottledFrameViews([](FrameView& frameView) { frameView.lifecycle().advanceTo(DocumentLifecycle::InUpdatePaintProperties); }); @@ -2437,7 +2444,8 @@ void FrameView::synchronizedPaint() { - ASSERT(RuntimeEnabledFeatures::slimmingPaintSynchronizedPaintingEnabled()); + TRACE_EVENT0("blink", "FrameView::synchronizedPaint"); + ASSERT(frame() == page()->mainFrame() || (!frame().tree().parent()->isLocalFrame())); LayoutView* view = layoutView(); @@ -2486,6 +2494,8 @@ void FrameView::pushPaintArtifactToCompositor() { + TRACE_EVENT0("blink", "FrameView::pushPaintArtifactToCompositor"); + ASSERT(RuntimeEnabledFeatures::slimmingPaintV2Enabled()); LayoutView* view = layoutView();
diff --git a/third_party/WebKit/Source/core/frame/LocalFrame.cpp b/third_party/WebKit/Source/core/frame/LocalFrame.cpp index af21f1c7..eca2f18 100644 --- a/third_party/WebKit/Source/core/frame/LocalFrame.cpp +++ b/third_party/WebKit/Source/core/frame/LocalFrame.cpp
@@ -490,7 +490,6 @@ document()->setPrinting(printing); view()->adjustMediaTypeForPrinting(printing); - document()->styleResolverChanged(); if (shouldUsePrintingLayout()) { view()->forceLayoutForPagination(pageSize, originalPageSize, maximumShrinkRatio); } else {
diff --git a/third_party/WebKit/Source/core/frame/UseCounter.h b/third_party/WebKit/Source/core/frame/UseCounter.h index 97723e2..11ebf3c 100644 --- a/third_party/WebKit/Source/core/frame/UseCounter.h +++ b/third_party/WebKit/Source/core/frame/UseCounter.h
@@ -952,6 +952,9 @@ V8SVGSVGElement_Viewport_AttributeGetter = 1095, V8RegExpPrototypeStickyGetter = 1096, V8RegExpPrototypeToString = 1097, + V8InputDeviceCapabilities_FiresTouchEvents_AttributeGetter = 1098, + DataElement = 1099, + TimeElement = 1100, // Add new features immediately above this line. Don't change assigned // numbers of any item, and don't reuse removed slots.
diff --git a/third_party/WebKit/Source/core/html/HTMLInputElement.cpp b/third_party/WebKit/Source/core/html/HTMLInputElement.cpp index c28defb..03cba21d 100644 --- a/third_party/WebKit/Source/core/html/HTMLInputElement.cpp +++ b/third_party/WebKit/Source/core/html/HTMLInputElement.cpp
@@ -1481,11 +1481,7 @@ void HTMLInputElement::onSearch() { - // FIXME: Remove type check, and static_cast. - ASSERT(type() == InputTypeNames::search); - if (m_inputType) - static_cast<SearchInputType*>(m_inputType.get())->stopSearchEventTimer(); - dispatchEvent(Event::createBubble(EventTypeNames::search)); + m_inputType->dispatchSearchEvent(); } void HTMLInputElement::updateClearButtonVisibility()
diff --git a/third_party/WebKit/Source/core/html/HTMLKeygenElement.cpp b/third_party/WebKit/Source/core/html/HTMLKeygenElement.cpp index fab51b6..160e505 100644 --- a/third_party/WebKit/Source/core/html/HTMLKeygenElement.cpp +++ b/third_party/WebKit/Source/core/html/HTMLKeygenElement.cpp
@@ -34,6 +34,7 @@ #include "core/html/HTMLOptionElement.h" #include "core/html/HTMLSelectElement.h" #include "core/layout/LayoutBlockFlow.h" +#include "core/loader/FrameLoaderClient.h" #include "platform/text/PlatformLocale.h" #include "public/platform/Platform.h" #include "public/platform/WebLocalizedString.h" @@ -49,6 +50,8 @@ : HTMLFormControlElementWithState(keygenTag, document, form) { UseCounter::count(document, UseCounter::HTMLKeygenElement); + if (document.frame()) + document.frame()->loader().client()->didUseKeygen(); } PassRefPtrWillBeRawPtr<HTMLKeygenElement> HTMLKeygenElement::create(Document& document, HTMLFormElement* form)
diff --git a/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp b/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp index 65ec407..ecd1e121 100644 --- a/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp +++ b/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp
@@ -383,7 +383,7 @@ removeElementFromDocumentMap(this, &document()); // Destroying the player may cause a resource load to be canceled, - // which could result in Document::dispatchWindowLoadEvent() being + // which could result in LocalDOMWindow::dispatchWindowLoadEvent() being // called via ResourceFetch::didLoadResource() then // FrameLoader::checkCompleted(). To prevent load event dispatching during // object destruction, we use Document::incrementLoadEventDelayCount().
diff --git a/third_party/WebKit/Source/core/html/HTMLSelectElement.cpp b/third_party/WebKit/Source/core/html/HTMLSelectElement.cpp index fb8cc0d92..31751a6 100644 --- a/third_party/WebKit/Source/core/html/HTMLSelectElement.cpp +++ b/third_party/WebKit/Source/core/html/HTMLSelectElement.cpp
@@ -1256,9 +1256,12 @@ firstOption = option; } - if (!selectedOption && firstOption && !m_multiple && m_size <= 1) + if (!selectedOption && firstOption && !m_multiple && m_size <= 1) { firstOption->setSelectedState(true); + selectedOption = firstOption; + } + m_lastOnChangeOption = selectedOption; setOptionsChangedOnLayoutObject(); setNeedsValidityCheck(); }
diff --git a/third_party/WebKit/Source/core/html/HTMLShadowElement.cpp b/third_party/WebKit/Source/core/html/HTMLShadowElement.cpp index 1ec5c2c..c1d65e6 100644 --- a/third_party/WebKit/Source/core/html/HTMLShadowElement.cpp +++ b/third_party/WebKit/Source/core/html/HTMLShadowElement.cpp
@@ -59,10 +59,10 @@ updateDistribution(); ShadowRoot* older = containingRoot->olderShadowRoot(); - if (!older || !older->isOpen() || older->shadowInsertionPointOfYoungerShadowRoot() != this) + if (!older || !older->isOpenOrV0() || older->shadowInsertionPointOfYoungerShadowRoot() != this) return nullptr; - ASSERT(older->isOpen()); + ASSERT(older->isOpenOrV0()); return older; }
diff --git a/third_party/WebKit/Source/core/html/HTMLSlotElement.cpp b/third_party/WebKit/Source/core/html/HTMLSlotElement.cpp index cf907c2..a3f1e37 100644 --- a/third_party/WebKit/Source/core/html/HTMLSlotElement.cpp +++ b/third_party/WebKit/Source/core/html/HTMLSlotElement.cpp
@@ -31,6 +31,8 @@ #include "core/html/HTMLSlotElement.h" #include "core/HTMLNames.h" +#include "core/dom/NodeTraversal.h" +#include "core/dom/shadow/InsertionPoint.h" namespace blink { @@ -98,6 +100,21 @@ HTMLElement::detach(context); } +void HTMLSlotElement::updateDistributedNodesWithFallback() +{ + if (!m_distributedNodes.isEmpty()) + return; + for (auto& child : NodeTraversal::childrenOf(*this)) { + // Insertion points are not supported as slots fallback + if (isActiveInsertionPoint(child)) + continue; + if (isHTMLSlotElement(child)) + appendDistributedNodes(toHTMLSlotElement(child).getDistributedNodes()); + else + appendDistributedNode(child); + } +} + DEFINE_TRACE(HTMLSlotElement) { visitor->trace(m_assignedNodes);
diff --git a/third_party/WebKit/Source/core/html/HTMLSlotElement.h b/third_party/WebKit/Source/core/html/HTMLSlotElement.h index 66d3eba..a6e1ba9 100644 --- a/third_party/WebKit/Source/core/html/HTMLSlotElement.h +++ b/third_party/WebKit/Source/core/html/HTMLSlotElement.h
@@ -42,7 +42,6 @@ DECLARE_NODE_FACTORY(HTMLSlotElement); const WillBeHeapVector<RefPtrWillBeMember<Node>> getAssignedNodes() const { return m_assignedNodes; } - // TODO(hayato): Support fallback contents of slot elements const WillBeHeapVector<RefPtrWillBeMember<Node>> getDistributedNodes() const { return m_distributedNodes; } Node* firstDistributedNode() const { return m_distributedNodes.isEmpty() ? nullptr : m_distributedNodes.first().get(); } @@ -57,6 +56,8 @@ void appendDistributedNodes(const WillBeHeapVector<RefPtrWillBeMember<Node>>&); void clearDistribution(); + void updateDistributedNodesWithFallback(); + void attach(const AttachContext& = AttachContext()) override; void detach(const AttachContext& = AttachContext()) override;
diff --git a/third_party/WebKit/Source/core/html/HTMLUnknownElement.cpp b/third_party/WebKit/Source/core/html/HTMLUnknownElement.cpp new file mode 100644 index 0000000..8237054 --- /dev/null +++ b/third_party/WebKit/Source/core/html/HTMLUnknownElement.cpp
@@ -0,0 +1,20 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "core/html/HTMLUnknownElement.h" + +#include "core/frame/UseCounter.h" + +namespace blink { + +HTMLUnknownElement::HTMLUnknownElement(const QualifiedName& tagName, Document& document) + : HTMLElement(tagName, document) +{ + if (tagName.localName() == "data") + UseCounter::count(document, UseCounter::DataElement); + else if (tagName.localName() == "time") + UseCounter::count(document, UseCounter::TimeElement); +} + +} // namespace blink
diff --git a/third_party/WebKit/Source/core/html/HTMLUnknownElement.h b/third_party/WebKit/Source/core/html/HTMLUnknownElement.h index 8b46925..c9c1523 100644 --- a/third_party/WebKit/Source/core/html/HTMLUnknownElement.h +++ b/third_party/WebKit/Source/core/html/HTMLUnknownElement.h
@@ -43,8 +43,7 @@ } private: - HTMLUnknownElement(const QualifiedName& tagName, Document& document) - : HTMLElement(tagName, document) { } + HTMLUnknownElement(const QualifiedName&, Document&); bool isHTMLUnknownElement() const override { return true; } };
diff --git a/third_party/WebKit/Source/core/html/canvas/CanvasDrawListener.cpp b/third_party/WebKit/Source/core/html/canvas/CanvasDrawListener.cpp index d63ce55..1e68664 100644 --- a/third_party/WebKit/Source/core/html/canvas/CanvasDrawListener.cpp +++ b/third_party/WebKit/Source/core/html/canvas/CanvasDrawListener.cpp
@@ -4,8 +4,6 @@ #include "core/html/canvas/CanvasDrawListener.h" -#include "public/platform/WebSkImage.h" - namespace blink { CanvasDrawListener::~CanvasDrawListener() {} @@ -17,7 +15,7 @@ void CanvasDrawListener::sendNewFrame(const WTF::PassRefPtr<SkImage>& image) { - m_handler->sendNewFrame(WebSkImage(image)); + m_handler->sendNewFrame(image.get()); } void CanvasDrawListener::requestFrame()
diff --git a/third_party/WebKit/Source/core/html/forms/InputType.cpp b/third_party/WebKit/Source/core/html/forms/InputType.cpp index 4fe4acc..aae8efb 100644 --- a/third_party/WebKit/Source/core/html/forms/InputType.cpp +++ b/third_party/WebKit/Source/core/html/forms/InputType.cpp
@@ -558,6 +558,10 @@ return !equalIgnoringNullity(oldValue, newValue); } +void InputType::dispatchSearchEvent() +{ +} + void InputType::setValue(const String& sanitizedValue, bool valueChanged, TextFieldEventBehavior eventBehavior) { element().setValueInternal(sanitizedValue, eventBehavior);
diff --git a/third_party/WebKit/Source/core/html/forms/InputType.h b/third_party/WebKit/Source/core/html/forms/InputType.h index a05d67a..b059cbb 100644 --- a/third_party/WebKit/Source/core/html/forms/InputType.h +++ b/third_party/WebKit/Source/core/html/forms/InputType.h
@@ -212,6 +212,7 @@ bool hasCustomFocusLogic() const override; virtual bool shouldDispatchFormControlChangeEvent(String&, String&); + virtual void dispatchSearchEvent(); // For test purpose virtual ColorChooserClient* colorChooserClient();
diff --git a/third_party/WebKit/Source/core/html/forms/SearchInputType.cpp b/third_party/WebKit/Source/core/html/forms/SearchInputType.cpp index 948102533..3ee8ac6 100644 --- a/third_party/WebKit/Source/core/html/forms/SearchInputType.cpp +++ b/third_party/WebKit/Source/core/html/forms/SearchInputType.cpp
@@ -113,7 +113,7 @@ unsigned length = element().innerEditorValue().length(); if (!length) { - stopSearchEventTimer(); + m_searchEventTimer.stop(); element().document().postTask(BLINK_FROM_HERE, createSameThreadTask(&HTMLInputElement::onSearch, PassRefPtrWillBeRawPtr<HTMLInputElement>(&element()))); return; } @@ -123,9 +123,10 @@ m_searchEventTimer.startOneShot(max(0.2, 0.6 - 0.1 * length), BLINK_FROM_HERE); } -void SearchInputType::stopSearchEventTimer() +void SearchInputType::dispatchSearchEvent() { m_searchEventTimer.stop(); + element().dispatchEvent(Event::createBubble(EventTypeNames::search)); } void SearchInputType::searchEventTimerFired(Timer<SearchInputType>*)
diff --git a/third_party/WebKit/Source/core/html/forms/SearchInputType.h b/third_party/WebKit/Source/core/html/forms/SearchInputType.h index df0aefa..db36fe2 100644 --- a/third_party/WebKit/Source/core/html/forms/SearchInputType.h +++ b/third_party/WebKit/Source/core/html/forms/SearchInputType.h
@@ -40,8 +40,6 @@ public: static PassRefPtrWillBeRawPtr<InputType> create(HTMLInputElement&); - void stopSearchEventTimer(); - private: SearchInputType(HTMLInputElement&); void countUsage() override; @@ -54,6 +52,7 @@ bool supportsInputModeAttribute() const override; void updateView() override; const AtomicString& defaultAutocapitalize() const override; + void dispatchSearchEvent() override; void searchEventTimerFired(Timer<SearchInputType>*); bool searchEventsShouldBeDispatched() const;
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLPreloadScanner.cpp b/third_party/WebKit/Source/core/html/parser/HTMLPreloadScanner.cpp index 50f18fd..efff3e4 100644 --- a/third_party/WebKit/Source/core/html/parser/HTMLPreloadScanner.cpp +++ b/third_party/WebKit/Source/core/html/parser/HTMLPreloadScanner.cpp
@@ -34,7 +34,9 @@ #include "core/css/MediaValuesCached.h" #include "core/css/parser/SizesAttributeParser.h" #include "core/dom/Document.h" +#include "core/fetch/IntegrityMetadata.h" #include "core/frame/Settings.h" +#include "core/frame/SubresourceIntegrity.h" #include "core/html/CrossOriginAttribute.h" #include "core/html/HTMLImageElement.h" #include "core/html/HTMLMetaElement.h" @@ -202,6 +204,7 @@ request->setCrossOrigin(m_crossOrigin); request->setCharset(charset()); request->setDefer(m_defer); + request->setIntegrityMetadata(m_integrityMetadata); return request.release(); } @@ -218,6 +221,16 @@ setDefer(FetchRequest::LazyLoad); else if (match(attributeName, deferAttr)) setDefer(FetchRequest::LazyLoad); + // Note that only scripts need to have the integrity metadata set on + // preloads. This is because script resources fetches, and only script + // resource fetches, need to re-request resources if a cached version + // has different metadata (including empty) from the metadata on the + // request. See the comment before the call to + // mustRefetchDueToIntegrityMismatch() in + // Source/core/fetch/ResourceFetcher.cpp for a more complete + // explanation. + else if (match(attributeName, integrityAttr)) + SubresourceIntegrity::parseIntegrityAttribute(attributeValue, m_integrityMetadata); } template<typename NameType> @@ -402,6 +415,7 @@ RefPtrWillBeMember<MediaValues> m_mediaValues; bool m_referrerPolicySet; ReferrerPolicy m_referrerPolicy; + IntegrityMetadataSet m_integrityMetadata; }; TokenPreloadScanner::TokenPreloadScanner(const KURL& documentURL, PassOwnPtr<CachedDocumentParameters> documentParameters)
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLScriptRunner.cpp b/third_party/WebKit/Source/core/html/parser/HTMLScriptRunner.cpp index 81212fc..e1b14f28 100644 --- a/third_party/WebKit/Source/core/html/parser/HTMLScriptRunner.cpp +++ b/third_party/WebKit/Source/core/html/parser/HTMLScriptRunner.cpp
@@ -286,7 +286,7 @@ if (!m_parserBlockingScript.isReady()) { if (m_document->frame()) { ScriptState* scriptState = ScriptState::forMainWorld(m_document->frame()); - if (scriptState->contextIsValid()) + if (scriptState) ScriptStreamer::startStreaming(m_parserBlockingScript, PendingScript::ParsingBlocking, m_document->frame()->settings(), scriptState, m_document->loadingTaskRunner()); } @@ -302,7 +302,7 @@ if (m_document->frame() && !pendingScript.isReady()) { ScriptState* scriptState = ScriptState::forMainWorld(m_document->frame()); - if (scriptState->contextIsValid()) + if (scriptState) ScriptStreamer::startStreaming(pendingScript, PendingScript::Deferred, m_document->frame()->settings(), scriptState, m_document->loadingTaskRunner()); }
diff --git a/third_party/WebKit/Source/core/html/parser/PreloadRequest.cpp b/third_party/WebKit/Source/core/html/parser/PreloadRequest.cpp index d3453d2..27c92b9 100644 --- a/third_party/WebKit/Source/core/html/parser/PreloadRequest.cpp +++ b/third_party/WebKit/Source/core/html/parser/PreloadRequest.cpp
@@ -44,6 +44,7 @@ request.setDefer(m_defer); request.setResourceWidth(m_resourceWidth); request.clientHintsPreferences().updateFrom(m_clientHintsPreferences); + request.setIntegrityMetadata(m_integrityMetadata); return request; }
diff --git a/third_party/WebKit/Source/core/html/parser/PreloadRequest.h b/third_party/WebKit/Source/core/html/parser/PreloadRequest.h index 465e8ae..da2fa00 100644 --- a/third_party/WebKit/Source/core/html/parser/PreloadRequest.h +++ b/third_party/WebKit/Source/core/html/parser/PreloadRequest.h
@@ -7,6 +7,7 @@ #include "core/fetch/ClientHintsPreferences.h" #include "core/fetch/FetchRequest.h" +#include "core/fetch/IntegrityMetadata.h" #include "core/fetch/Resource.h" #include "platform/CrossOriginAttributeValue.h" #include "platform/weborigin/SecurityPolicy.h" @@ -51,6 +52,14 @@ bool isPreconnect() const { return m_requestType == RequestTypePreconnect; } const ClientHintsPreferences& preferences() const { return m_clientHintsPreferences; } ReferrerPolicy referrerPolicy() const { return m_referrerPolicy; } + void setIntegrityMetadata(const IntegrityMetadataSet& metadataSet) + { + m_integrityMetadata = metadataSet; + } + const IntegrityMetadataSet& integrityMetadata() const + { + return m_integrityMetadata; + } private: PreloadRequest(const String& initiatorName, @@ -92,6 +101,7 @@ ClientHintsPreferences m_clientHintsPreferences; RequestType m_requestType; ReferrerPolicy m_referrerPolicy; + IntegrityMetadataSet m_integrityMetadata; }; typedef Vector<OwnPtr<PreloadRequest>> PreloadRequestStream;
diff --git a/third_party/WebKit/Source/core/input/InputDeviceCapabilities.idl b/third_party/WebKit/Source/core/input/InputDeviceCapabilities.idl index 316b8de..6263af8 100644 --- a/third_party/WebKit/Source/core/input/InputDeviceCapabilities.idl +++ b/third_party/WebKit/Source/core/input/InputDeviceCapabilities.idl
@@ -18,5 +18,5 @@ // Whether this device dispatches touch events for movement. This is used to detect // mouse events which represent only an action that has already been handled by // touch event handlers. - readonly attribute boolean firesTouchEvents; + [Measure] readonly attribute boolean firesTouchEvents; };
diff --git a/third_party/WebKit/Source/core/inspector/DevToolsHost.cpp b/third_party/WebKit/Source/core/inspector/DevToolsHost.cpp index 4a1580a..5a295331 100644 --- a/third_party/WebKit/Source/core/inspector/DevToolsHost.cpp +++ b/third_party/WebKit/Source/core/inspector/DevToolsHost.cpp
@@ -219,6 +219,8 @@ { ASSERT(m_frontendFrame); ScriptState* frontendScriptState = ScriptState::forMainWorld(m_frontendFrame); + if (!frontendScriptState) + return; ScriptValue devtoolsApiObject = frontendScriptState->getFromGlobalObject("DevToolsAPI"); ASSERT(devtoolsApiObject.isObject());
diff --git a/third_party/WebKit/Source/core/inspector/InspectorAnimationAgent.cpp b/third_party/WebKit/Source/core/inspector/InspectorAnimationAgent.cpp index 13fd35c6..a066328 100644 --- a/third_party/WebKit/Source/core/inspector/InspectorAnimationAgent.cpp +++ b/third_party/WebKit/Source/core/inspector/InspectorAnimationAgent.cpp
@@ -387,6 +387,8 @@ } ScriptState* scriptState = ScriptState::forMainWorld(frame); + if (!scriptState) + return; InjectedScript injectedScript = m_injectedScriptManager->injectedScriptFor(scriptState); if (injectedScript.isEmpty()) return;
diff --git a/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.cpp b/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.cpp index 8aa5fe9..c5294c5 100644 --- a/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.cpp +++ b/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.cpp
@@ -1302,7 +1302,7 @@ if (Document* document = parentStyleSheet->ownerDocument()) frame = document->frame(); } - OwnPtr<MediaQueryEvaluator> mediaEvaluator = adoptPtr(new MediaQueryEvaluator(frame)); + OwnPtrWillBeRawPtr<MediaQueryEvaluator> mediaEvaluator = adoptPtrWillBeNoop(new MediaQueryEvaluator(frame)); InspectorStyleSheet* inspectorStyleSheet = parentStyleSheet ? m_cssStyleSheetToInspectorStyleSheet.get(parentStyleSheet) : nullptr; RefPtr<TypeBuilder::Array<TypeBuilder::CSS::MediaQuery> > mediaListArray = TypeBuilder::Array<TypeBuilder::CSS::MediaQuery>::create();
diff --git a/third_party/WebKit/Source/core/inspector/InspectorDOMAgent.cpp b/third_party/WebKit/Source/core/inspector/InspectorDOMAgent.cpp index df8fde2..4d4028fc 100644 --- a/third_party/WebKit/Source/core/inspector/InspectorDOMAgent.cpp +++ b/third_party/WebKit/Source/core/inspector/InspectorDOMAgent.cpp
@@ -2122,12 +2122,14 @@ if (!frame) return nullptr; - ScriptState* state = ScriptState::forMainWorld(frame); - InjectedScript injectedScript = m_injectedScriptManager->injectedScriptFor(state); + ScriptState* scriptState = ScriptState::forMainWorld(frame); + if (!scriptState) + return nullptr; + InjectedScript injectedScript = m_injectedScriptManager->injectedScriptFor(scriptState); if (injectedScript.isEmpty()) return nullptr; - ScriptValue scriptValue = nodeAsScriptValue(state, node); + ScriptValue scriptValue = nodeAsScriptValue(scriptState, node); return injectedScript.wrapObject(scriptValue, objectGroup); }
diff --git a/third_party/WebKit/Source/core/inspector/InspectorPageAgent.cpp b/third_party/WebKit/Source/core/inspector/InspectorPageAgent.cpp index 75872c3..f89af016 100644 --- a/third_party/WebKit/Source/core/inspector/InspectorPageAgent.cpp +++ b/third_party/WebKit/Source/core/inspector/InspectorPageAgent.cpp
@@ -126,7 +126,7 @@ static bool prepareResourceBuffer(Resource* cachedResource, bool* hasZeroSize) { *hasZeroSize = false; - if (!cachedResource) + if (!cachedResource || cachedResource->wasPurged()) return false; if (cachedResource->dataBufferingPolicy() == DoNotBufferData)
diff --git a/third_party/WebKit/Source/core/inspector/PageRuntimeAgent.cpp b/third_party/WebKit/Source/core/inspector/PageRuntimeAgent.cpp index c4e2e9fe..a224985 100644 --- a/third_party/WebKit/Source/core/inspector/PageRuntimeAgent.cpp +++ b/third_party/WebKit/Source/core/inspector/PageRuntimeAgent.cpp
@@ -121,7 +121,9 @@ ScriptState* PageRuntimeAgent::defaultScriptState() { - return ScriptState::forMainWorld(m_inspectedFrames->root()); + ScriptState* scriptState = ScriptState::forMainWorld(m_inspectedFrames->root()); + ASSERT(scriptState); + return scriptState; } void PageRuntimeAgent::muteConsole() @@ -144,8 +146,10 @@ // Ensure execution context is created. // If initializeMainWorld returns true, then is registered by didCreateScriptContext - if (!frame->script().initializeMainWorld()) - reportExecutionContext(ScriptState::forMainWorld(frame), true, "", frameId); + if (!frame->script().initializeMainWorld()) { + ScriptState* scriptState = ScriptState::forMainWorld(frame); + reportExecutionContext(scriptState, true, "", frameId); + } frame->script().collectIsolatedContexts(isolatedContexts); if (isolatedContexts.isEmpty()) continue;
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlock.cpp b/third_party/WebKit/Source/core/layout/LayoutBlock.cpp index 7daa88b77..dc2b6a0 100644 --- a/third_party/WebKit/Source/core/layout/LayoutBlock.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutBlock.cpp
@@ -1025,12 +1025,13 @@ bool hasRelativeLogicalHeight = child.hasRelativeLogicalHeight() || (child.isAnonymous() && this->hasRelativeLogicalHeight()) || child.stretchesToViewport(); - if (relayoutChildren || (hasRelativeLogicalHeight && !isLayoutView())) + if (relayoutChildren || (hasRelativeLogicalHeight && !isLayoutView())) { child.setChildNeedsLayout(MarkOnlyThis); - // If relayoutChildren is set and the child has percentage padding or an embedded content box, we also need to invalidate the childs pref widths. - if (relayoutChildren && child.needsPreferredWidthsRecalculation()) - child.setPreferredLogicalWidthsDirty(MarkOnlyThis); + // If the child has percentage padding or an embedded content box, we also need to invalidate the childs pref widths. + if (child.needsPreferredWidthsRecalculation()) + child.setPreferredLogicalWidthsDirty(MarkOnlyThis); + } } void LayoutBlock::simplifiedNormalFlowLayout()
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp index 859ad0c..328f1d33 100644 --- a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp
@@ -2176,20 +2176,20 @@ return LayoutPoint(point.x() + size().width() - child.layoutObject()->size().width() - 2 * xPositionForFloatIncludingMargin(child), point.y()); } -LayoutUnit LayoutBlockFlow::logicalLeftOffsetForPositioningFloat(LayoutUnit logicalTop, LayoutUnit fixedOffset, bool applyTextIndent, LayoutUnit* heightRemaining) const +LayoutUnit LayoutBlockFlow::logicalLeftOffsetForPositioningFloat(LayoutUnit logicalTop, LayoutUnit fixedOffset, LayoutUnit* heightRemaining) const { LayoutUnit offset = fixedOffset; if (m_floatingObjects && m_floatingObjects->hasLeftObjects()) offset = m_floatingObjects->logicalLeftOffsetForPositioningFloat(fixedOffset, logicalTop, heightRemaining); - return adjustLogicalLeftOffsetForLine(offset, applyTextIndent); + return adjustLogicalLeftOffsetForLine(offset, false); } -LayoutUnit LayoutBlockFlow::logicalRightOffsetForPositioningFloat(LayoutUnit logicalTop, LayoutUnit fixedOffset, bool applyTextIndent, LayoutUnit* heightRemaining) const +LayoutUnit LayoutBlockFlow::logicalRightOffsetForPositioningFloat(LayoutUnit logicalTop, LayoutUnit fixedOffset, LayoutUnit* heightRemaining) const { LayoutUnit offset = fixedOffset; if (m_floatingObjects && m_floatingObjects->hasRightObjects()) offset = m_floatingObjects->logicalRightOffsetForPositioningFloat(fixedOffset, logicalTop, heightRemaining); - return adjustLogicalRightOffsetForLine(offset, applyTextIndent); + return adjustLogicalRightOffsetForLine(offset, false); } LayoutUnit LayoutBlockFlow::adjustLogicalLeftOffsetForLine(LayoutUnit offsetFromFloats, bool applyTextIndent) const @@ -2228,10 +2228,10 @@ if (childBox->style()->floating() == LeftFloat) { LayoutUnit heightRemainingLeft = 1; LayoutUnit heightRemainingRight = 1; - floatLogicalLeft = logicalLeftOffsetForPositioningFloat(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft); - while (logicalRightOffsetForPositioningFloat(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight) - floatLogicalLeft < floatLogicalWidth) { + floatLogicalLeft = logicalLeftOffsetForPositioningFloat(logicalTopOffset, logicalLeftOffset, &heightRemainingLeft); + while (logicalRightOffsetForPositioningFloat(logicalTopOffset, logicalRightOffset, &heightRemainingRight) - floatLogicalLeft < floatLogicalWidth) { logicalTopOffset += std::min<LayoutUnit>(heightRemainingLeft, heightRemainingRight); - floatLogicalLeft = logicalLeftOffsetForPositioningFloat(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft); + floatLogicalLeft = logicalLeftOffsetForPositioningFloat(logicalTopOffset, logicalLeftOffset, &heightRemainingLeft); if (insideFlowThread) { // Have to re-evaluate all of our offsets, since they may have changed. logicalRightOffset = logicalRightOffsetForContent(); // Constant part of right offset. @@ -2243,10 +2243,10 @@ } else { LayoutUnit heightRemainingLeft = 1; LayoutUnit heightRemainingRight = 1; - floatLogicalLeft = logicalRightOffsetForPositioningFloat(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight); - while (floatLogicalLeft - logicalLeftOffsetForPositioningFloat(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft) < floatLogicalWidth) { + floatLogicalLeft = logicalRightOffsetForPositioningFloat(logicalTopOffset, logicalRightOffset, &heightRemainingRight); + while (floatLogicalLeft - logicalLeftOffsetForPositioningFloat(logicalTopOffset, logicalLeftOffset, &heightRemainingLeft) < floatLogicalWidth) { logicalTopOffset += std::min(heightRemainingLeft, heightRemainingRight); - floatLogicalLeft = logicalRightOffsetForPositioningFloat(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight); + floatLogicalLeft = logicalRightOffsetForPositioningFloat(logicalTopOffset, logicalRightOffset, &heightRemainingRight); if (insideFlowThread) { // Have to re-evaluate all of our offsets, since they may have changed. logicalRightOffset = logicalRightOffsetForContent(); // Constant part of right offset. @@ -2660,7 +2660,7 @@ return GapRects(); TransformState transformState(TransformState::ApplyTransformDirection, FloatPoint()); - mapLocalToContainer(paintInvalidationContainer, transformState, ApplyContainerFlip | UseTransforms); + mapLocalToAncestor(paintInvalidationContainer, transformState, ApplyContainerFlip | UseTransforms); LayoutPoint offsetFromPaintInvalidationContainer = roundedLayoutPoint(transformState.mappedPoint()); if (hasOverflowClip())
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.h b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.h index db5ae51..bc3c8ab 100644 --- a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.h +++ b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.h
@@ -363,8 +363,8 @@ LayoutUnit logicalRightFloatOffsetForLine(LayoutUnit logicalTop, LayoutUnit fixedOffset, LayoutUnit logicalHeight) const; LayoutUnit logicalLeftFloatOffsetForLine(LayoutUnit logicalTop, LayoutUnit fixedOffset, LayoutUnit logicalHeight) const; - LayoutUnit logicalRightOffsetForPositioningFloat(LayoutUnit logicalTop, LayoutUnit fixedOffset, bool applyTextIndent, LayoutUnit* heightRemaining) const; - LayoutUnit logicalLeftOffsetForPositioningFloat(LayoutUnit logicalTop, LayoutUnit fixedOffset, bool applyTextIndent, LayoutUnit* heightRemaining) const; + LayoutUnit logicalRightOffsetForPositioningFloat(LayoutUnit logicalTop, LayoutUnit fixedOffset, LayoutUnit* heightRemaining) const; + LayoutUnit logicalLeftOffsetForPositioningFloat(LayoutUnit logicalTop, LayoutUnit fixedOffset, LayoutUnit* heightRemaining) const; LayoutUnit adjustLogicalRightOffsetForLine(LayoutUnit offsetFromFloats, bool applyTextIndent) const; LayoutUnit adjustLogicalLeftOffsetForLine(LayoutUnit offsetFromFloats, bool applyTextIndent) const;
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlockFlowLine.cpp b/third_party/WebKit/Source/core/layout/LayoutBlockFlowLine.cpp index 987a7a8..96d0d132 100644 --- a/third_party/WebKit/Source/core/layout/LayoutBlockFlowLine.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutBlockFlowLine.cpp
@@ -445,9 +445,9 @@ #if OS(MACOSX) // FIXME: Having any font feature settings enabled can lead to selection gaps on // Chromium-mac. https://bugs.webkit.org/show_bug.cgi?id=113418 - bool canUseCachedWordMeasurements = layoutText->canUseSimpleFontCodePath() && !font.fontDescription().featureSettings(); + bool canUseCachedWordMeasurements = font.canShapeWordByWord() && !font.fontDescription().featureSettings(); #else - bool canUseCachedWordMeasurements = layoutText->canUseSimpleFontCodePath(); + bool canUseCachedWordMeasurements = font.canShapeWordByWord(); #endif if (canUseCachedWordMeasurements) { @@ -508,7 +508,7 @@ copyToVector(fallbackFonts, it->value.first); run->m_box->parent()->clearDescendantsHaveSameLineHeightAndBaseline(); } - if (!glyphOverflow.isZero()) { + if (!glyphOverflow.isApproximatelyZero()) { ASSERT(run->m_box->isText()); GlyphOverflowAndFallbackFontsMap::ValueType* it = textBoxDataMap.add(toInlineTextBox(run->m_box), std::make_pair(Vector<const SimpleFontData*>(), GlyphOverflow())).storedValue; it->value.second = glyphOverflow; @@ -1178,9 +1178,6 @@ const Font& font = text->style()->font(); TextRun run = constructTextRun(font, &trailingWhitespaceChar, 1, text->styleRef(), text->style()->direction()); - run.setCodePath(text->canUseSimpleFontCodePath() - ? TextRun::ForceSimple - : TextRun::ForceComplex); float spaceWidth = font.width(run); inlineMax -= LayoutUnit::fromFloatCeil(spaceWidth + font.fontDescription().wordSpacing()); if (inlineMin > inlineMax)
diff --git a/third_party/WebKit/Source/core/layout/LayoutBox.cpp b/third_party/WebKit/Source/core/layout/LayoutBox.cpp index e7dde710..b49bb5af 100644 --- a/third_party/WebKit/Source/core/layout/LayoutBox.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutBox.cpp
@@ -938,7 +938,7 @@ return flooredIntSize(layer()->scrollableArea()->scrollOffset()); } -void LayoutBox::applyCachedScrollOffsetForPaintInvalidation(LayoutRect& paintRect) const +void LayoutBox::mapScrollingContentsRectToBoxSpace(LayoutRect& rect) const { ASSERT(hasLayer()); ASSERT(hasOverflowClip()); @@ -950,23 +950,22 @@ else offset.setWidth(-offset.width()); } - paintRect.move(offset); + rect.move(offset); } -void LayoutBox::applyCachedClipAndScrollOffsetForPaintInvalidation(LayoutRect& paintRect) const +void LayoutBox::applyOverflowClip(LayoutRect& rect) const { ASSERT(hasLayer()); ASSERT(hasOverflowClip()); - applyCachedScrollOffsetForPaintInvalidation(paintRect); - flipForWritingMode(paintRect); + flipForWritingMode(rect); // size() is inaccurate if we're in the middle of a layout of this LayoutBox, so use the // layer's size instead. Even if the layer's size is wrong, the layer itself will issue paint invalidations // anyway if its size does change. LayoutRect clipRect(LayoutPoint(), LayoutSize(layer()->size())); - paintRect = intersection(paintRect, clipRect); - flipForWritingMode(paintRect); + rect = intersection(rect, clipRect); + flipForWritingMode(rect); } void LayoutBox::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const @@ -1222,13 +1221,11 @@ BoxPainter(*this).paint(paintInfo, paintOffset); } - void LayoutBox::paintBoxDecorationBackground(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) const { BoxPainter(*this).paintBoxDecorationBackground(paintInfo, paintOffset); } - bool LayoutBox::getBackgroundPaintedExtent(LayoutRect& paintedExtent) const { ASSERT(hasBackground()); @@ -1237,7 +1234,7 @@ // thus can't be handled by this function. ASSERT(!isLayoutView()); - LayoutRect backgroundRect(enclosingIntRect(borderBoxRect())); + LayoutRect backgroundRect(borderBoxRect()); Color backgroundColor = resolveColor(CSSPropertyBackgroundColor); if (backgroundColor.alpha()) { @@ -1453,7 +1450,7 @@ LayoutView* layoutView = view(); while (layoutView->frame()->ownerLayoutObject()) layoutView = layoutView->frame()->ownerLayoutObject()->view(); - mapToVisibleRectInContainerSpace(layoutView, rect, 0); + mapToVisibleRectInAncestorSpace(layoutView, rect, nullptr); return rect.intersects(LayoutRect(layoutView->frameView()->scrollableArea()->visibleContentRectDouble())); } @@ -1641,12 +1638,12 @@ return cb->adjustContentBoxLogicalHeightForBoxSizing(logicalHeightLength.value()); } -void LayoutBox::mapLocalToContainer(const LayoutBoxModelObject* paintInvalidationContainer, TransformState& transformState, MapCoordinatesFlags mode, bool* wasFixed, const PaintInvalidationState* paintInvalidationState) const +void LayoutBox::mapLocalToAncestor(const LayoutBoxModelObject* ancestor, TransformState& transformState, MapCoordinatesFlags mode, bool* wasFixed, const PaintInvalidationState* paintInvalidationState) const { - if (paintInvalidationContainer == this) + if (ancestor == this) return; - if (paintInvalidationState && paintInvalidationState->canMapToContainer(paintInvalidationContainer)) { + if (paintInvalidationState && paintInvalidationState->canMapToContainer(ancestor)) { LayoutSize offset = paintInvalidationState->paintOffset() + locationOffset(); if (style()->hasInFlowPosition() && layer()) offset += layer()->offsetForInFlowPosition(); @@ -1654,8 +1651,8 @@ return; } - bool containerSkipped; - LayoutObject* o = container(paintInvalidationContainer, &containerSkipped); + bool ancestorSkipped; + LayoutObject* o = container(ancestor, &ancestorSkipped); if (!o) return; @@ -1682,17 +1679,17 @@ transformState.move(containerOffset.width(), containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform); } - if (containerSkipped) { + if (ancestorSkipped) { // There can't be a transform between paintInvalidationContainer and o, because transforms create containers, so it should be safe // to just subtract the delta between the paintInvalidationContainer and o. - LayoutSize containerOffset = paintInvalidationContainer->offsetFromAncestorContainer(o); + LayoutSize containerOffset = ancestor->offsetFromAncestorContainer(o); transformState.move(-containerOffset.width(), -containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform); return; } mode &= ~ApplyContainerFlip; - o->mapLocalToContainer(paintInvalidationContainer, transformState, mode, wasFixed); + o->mapLocalToAncestor(ancestor, transformState, mode, wasFixed); } void LayoutBox::mapAbsoluteToLocalPoint(MapCoordinatesFlags mode, TransformState& transformState) const @@ -1883,11 +1880,11 @@ } LayoutRect r = visualOverflowRect(); - mapToVisibleRectInContainerSpace(paintInvalidationContainer, r, paintInvalidationState); + mapToVisibleRectInAncestorSpace(paintInvalidationContainer, r, paintInvalidationState); return r; } -void LayoutBox::mapToVisibleRectInContainerSpace(const LayoutBoxModelObject* paintInvalidationContainer, LayoutRect& rect, const PaintInvalidationState* paintInvalidationState) const +void LayoutBox::mapToVisibleRectInAncestorSpace(const LayoutBoxModelObject* ancestor, LayoutRect& rect, const PaintInvalidationState* paintInvalidationState) const { // The rect we compute at each step is shifted by our x/y offset in the parent container's coordinate space. // Only when we cross a writing mode boundary will we have to possibly flipForWritingMode (to convert into a more appropriate @@ -1906,7 +1903,7 @@ // included into the visual overflow for repaint, we wouldn't have this issue. inflatePaintInvalidationRectForReflectionAndFilter(rect); - if (paintInvalidationState && paintInvalidationState->canMapToContainer(paintInvalidationContainer) && position != FixedPosition) { + if (paintInvalidationState && paintInvalidationState->canMapToContainer(ancestor) && position != FixedPosition) { if (layer() && layer()->transform()) rect = LayoutRect(layer()->transform()->mapRect(pixelSnappedIntRect(rect))); @@ -1921,15 +1918,15 @@ return; } - if (paintInvalidationContainer == this) { - if (paintInvalidationContainer->style()->isFlippedBlocksWritingMode()) + if (ancestor == this) { + if (ancestor->style()->isFlippedBlocksWritingMode()) flipForWritingMode(rect); return; } bool containerSkipped; - LayoutObject* o = container(paintInvalidationContainer, &containerSkipped); - if (!o) + LayoutObject* container = this->container(ancestor, &containerSkipped); + if (!container) return; if (isWritingModeRoot()) @@ -1946,8 +1943,8 @@ topLeft.move(locationOffset()); } - if (position == AbsolutePosition && o->isInFlowPositioned() && o->isLayoutInline()) { - topLeft += toLayoutInline(o)->offsetForInFlowPositionedInline(*this); + if (position == AbsolutePosition && container->isInFlowPositioned() && container->isLayoutInline()) { + topLeft += toLayoutInline(container)->offsetForInFlowPositionedInline(*this); } else if (styleToUse.hasInFlowPosition() && layer()) { // Apply the relative position offset when invalidating a rectangle. The layer // is translated, but the layout box isn't, so we need to do this to get the @@ -1959,30 +1956,29 @@ // FIXME: We ignore the lightweight clipping rect that controls use, since if |o| is in mid-layout, // its controlClipRect will be wrong. For overflow clip we use the values cached by the layer. rect.setLocation(topLeft); - if (o->hasOverflowClip()) { - LayoutBox* containerBox = toLayoutBox(o); - if (o == paintInvalidationContainer) - containerBox->applyCachedScrollOffsetForPaintInvalidation(rect); - else - containerBox->applyCachedClipAndScrollOffsetForPaintInvalidation(rect); + if (container->hasOverflowClip()) { + LayoutBox* containerBox = toLayoutBox(container); + containerBox->mapScrollingContentsRectToBoxSpace(rect); + if (container != ancestor) + containerBox->applyOverflowClip(rect); if (rect.isEmpty()) return; } if (containerSkipped) { // If the paintInvalidationContainer is below o, then we need to map the rect into paintInvalidationContainer's coordinates. - LayoutSize containerOffset = paintInvalidationContainer->offsetFromAncestorContainer(o); + LayoutSize containerOffset = ancestor->offsetFromAncestorContainer(container); rect.move(-containerOffset); // If the paintInvalidationContainer is fixed, then the rect is already in its coordinates so doesn't need viewport-adjusting. - if (paintInvalidationContainer->style()->position() != FixedPosition && o->isLayoutView()) - toLayoutView(o)->adjustViewportConstrainedOffset(rect, LayoutView::viewportConstrainedPosition(position)); + if (ancestor->style()->position() != FixedPosition && container->isLayoutView()) + toLayoutView(container)->adjustViewportConstrainedOffset(rect, LayoutView::viewportConstrainedPosition(position)); return; } - if (o->isLayoutView()) - toLayoutView(o)->mapToVisibleRectInContainerSpace(paintInvalidationContainer, rect, LayoutView::viewportConstrainedPosition(position), paintInvalidationState); + if (container->isLayoutView()) + toLayoutView(container)->mapToVisibleRectInAncestorSpace(ancestor, rect, LayoutView::viewportConstrainedPosition(position), paintInvalidationState); else - o->mapToVisibleRectInContainerSpace(paintInvalidationContainer, rect, paintInvalidationState); + container->mapToVisibleRectInAncestorSpace(ancestor, rect, paintInvalidationState); } void LayoutBox::inflatePaintInvalidationRectForReflectionAndFilter(LayoutRect& paintInvalidationRect) const
diff --git a/third_party/WebKit/Source/core/layout/LayoutBox.h b/third_party/WebKit/Source/core/layout/LayoutBox.h index 31aefb61..bd08770 100644 --- a/third_party/WebKit/Source/core/layout/LayoutBox.h +++ b/third_party/WebKit/Source/core/layout/LayoutBox.h
@@ -599,7 +599,7 @@ bool hasForcedBreakAfter() const; LayoutRect clippedOverflowRectForPaintInvalidation(const LayoutBoxModelObject* paintInvalidationContainer, const PaintInvalidationState* = nullptr) const override; - void mapToVisibleRectInContainerSpace(const LayoutBoxModelObject* paintInvalidationContainer, LayoutRect&, const PaintInvalidationState*) const override; + void mapToVisibleRectInAncestorSpace(const LayoutBoxModelObject* ancestor, LayoutRect&, const PaintInvalidationState*) const override; virtual void invalidatePaintForOverhangingFloats(bool paintAllDescendants); LayoutUnit containingBlockLogicalHeightForGetComputedStyle() const; @@ -798,8 +798,8 @@ virtual void computeIntrinsicRatioInformation(FloatSize& /* intrinsicSize */, double& /* intrinsicRatio */) const { } IntSize scrolledContentOffset() const; - void applyCachedScrollOffsetForPaintInvalidation(LayoutRect& paintRect) const; - void applyCachedClipAndScrollOffsetForPaintInvalidation(LayoutRect& paintRect) const; + void mapScrollingContentsRectToBoxSpace(LayoutRect&) const; + void applyOverflowClip(LayoutRect&) const; virtual bool hasRelativeLogicalWidth() const; virtual bool hasRelativeLogicalHeight() const; @@ -844,7 +844,7 @@ bool canRenderBorderImage() const; - void mapLocalToContainer(const LayoutBoxModelObject* paintInvalidationContainer, TransformState&, MapCoordinatesFlags = ApplyContainerFlip, bool* wasFixed = nullptr, const PaintInvalidationState* = nullptr) const override; + void mapLocalToAncestor(const LayoutBoxModelObject* ancestor, TransformState&, MapCoordinatesFlags = ApplyContainerFlip, bool* wasFixed = nullptr, const PaintInvalidationState* = nullptr) const override; void mapAbsoluteToLocalPoint(MapCoordinatesFlags, TransformState&) const override; void clearPreviousPaintInvalidationRects() override;
diff --git a/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.cpp b/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.cpp index a2d6a782..4c941fc 100644 --- a/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.cpp
@@ -441,7 +441,7 @@ if (descendant.hasLayer()) { Vector<LayoutRect> layerOutlineRects; descendant.addOutlineRects(layerOutlineRects, LayoutPoint(), includeBlockOverflows); - descendant.localToContainerRects(layerOutlineRects, this, LayoutPoint(), additionalOffset); + descendant.localToAncestorRects(layerOutlineRects, this, LayoutPoint(), additionalOffset); rects.appendVector(layerOutlineRects); return; }
diff --git a/third_party/WebKit/Source/core/layout/LayoutBoxTest.cpp b/third_party/WebKit/Source/core/layout/LayoutBoxTest.cpp new file mode 100644 index 0000000..e15635d --- /dev/null +++ b/third_party/WebKit/Source/core/layout/LayoutBoxTest.cpp
@@ -0,0 +1,28 @@ +// 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 "core/layout/LayoutBox.h" + +#include "core/html/HTMLElement.h" +#include "core/layout/ImageQualityController.h" +#include "core/layout/LayoutTestHelper.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace blink { + +class LayoutBoxTest : public RenderingTest { +}; + +TEST_F(LayoutBoxTest, BackgroundObscuredInRect) +{ + setBodyInnerHTML("<style>.column { width: 295.4px; padding-left: 10.4px; } .white-background { background: red; position: relative; overflow: hidden; border-radius: 1px; }" + ".black-background { height: 100px; background: black; color: white; } </style>" + "<div class='column'> <div> <div id='target' class='white-background'> <div class='black-background'></div> </div> </div> </div>"); + Element* element = document().getElementById("target"); + ASSERT_TRUE(element); + ASSERT_TRUE(element->layoutObject()); + ASSERT_TRUE(element->layoutObject()->boxDecorationBackgroundIsKnownToBeObscured()); +} + +}
diff --git a/third_party/WebKit/Source/core/layout/LayoutFlowThread.cpp b/third_party/WebKit/Source/core/layout/LayoutFlowThread.cpp index b617d1ef..4f174e38 100644 --- a/third_party/WebKit/Source/core/layout/LayoutFlowThread.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutFlowThread.cpp
@@ -97,16 +97,16 @@ generateColumnSetIntervalTree(); } -void LayoutFlowThread::mapToVisibleRectInContainerSpace(const LayoutBoxModelObject* paintInvalidationContainer, LayoutRect& rect, const PaintInvalidationState* paintInvalidationState) const +void LayoutFlowThread::mapToVisibleRectInAncestorSpace(const LayoutBoxModelObject* ancestor, LayoutRect& rect, const PaintInvalidationState* paintInvalidationState) const { - ASSERT(paintInvalidationContainer != this); // A flow thread should never be an invalidation container. + ASSERT(ancestor != this); // A flow thread should never be an invalidation container. // |rect| is a layout rectangle, where the block direction coordinate is flipped for writing // mode. fragmentsBoundingBox(), on the other hand, works on physical rectangles, so we need to // flip the rectangle before and after calling it. flipForWritingMode(rect); rect = fragmentsBoundingBox(rect); flipForWritingMode(rect); - LayoutBlockFlow::mapToVisibleRectInContainerSpace(paintInvalidationContainer, rect, paintInvalidationState); + LayoutBlockFlow::mapToVisibleRectInAncestorSpace(ancestor, rect, paintInvalidationState); } void LayoutFlowThread::layout()
diff --git a/third_party/WebKit/Source/core/layout/LayoutFlowThread.h b/third_party/WebKit/Source/core/layout/LayoutFlowThread.h index e88ccc77..a88592d9 100644 --- a/third_party/WebKit/Source/core/layout/LayoutFlowThread.h +++ b/third_party/WebKit/Source/core/layout/LayoutFlowThread.h
@@ -82,7 +82,7 @@ void invalidateColumnSets(); bool hasValidColumnSetInfo() const { return !m_columnSetsInvalidated && !m_multiColumnSetList.isEmpty(); } - void mapToVisibleRectInContainerSpace(const LayoutBoxModelObject* paintInvalidationContainer, LayoutRect&, const PaintInvalidationState*) const override; + void mapToVisibleRectInAncestorSpace(const LayoutBoxModelObject* ancestor, LayoutRect&, const PaintInvalidationState*) const override; LayoutUnit pageLogicalHeightForOffset(LayoutUnit); LayoutUnit pageRemainingLogicalHeightForOffset(LayoutUnit, PageBoundaryRule);
diff --git a/third_party/WebKit/Source/core/layout/LayoutGeometryMap.cpp b/third_party/WebKit/Source/core/layout/LayoutGeometryMap.cpp index 2a865cd..9cb0abf 100644 --- a/third_party/WebKit/Source/core/layout/LayoutGeometryMap.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutGeometryMap.cpp
@@ -54,27 +54,27 @@ { } -void LayoutGeometryMap::mapToContainer(TransformState& transformState, const LayoutBoxModelObject* container) const +void LayoutGeometryMap::mapToAncestor(TransformState& transformState, const LayoutBoxModelObject* ancestor) const { // If the mapping includes something like columns, we have to go via layoutObjects. if (hasNonUniformStep()) { - m_mapping.last().m_layoutObject->mapLocalToContainer(container, transformState, ApplyContainerFlip | m_mapCoordinatesFlags); + m_mapping.last().m_layoutObject->mapLocalToAncestor(ancestor, transformState, ApplyContainerFlip | m_mapCoordinatesFlags); transformState.flatten(); return; } bool inFixed = false; #if ENABLE(ASSERT) - bool foundContainer = !container || (m_mapping.size() && m_mapping[0].m_layoutObject == container); + bool foundAncestor = !ancestor || (m_mapping.size() && m_mapping[0].m_layoutObject == ancestor); #endif for (int i = m_mapping.size() - 1; i >= 0; --i) { const LayoutGeometryMapStep& currentStep = m_mapping[i]; // If container is the root LayoutView (step 0) we want to apply its fixed position offset. - if (i > 0 && currentStep.m_layoutObject == container) { + if (i > 0 && currentStep.m_layoutObject == ancestor) { #if ENABLE(ASSERT) - foundContainer = true; + foundAncestor = true; #endif break; } @@ -91,7 +91,7 @@ if (!i) { // A null container indicates mapping through the root LayoutView, so including its transform (the page scale). - if (!container && currentStep.m_transform) + if (!ancestor && currentStep.m_transform) transformState.applyTransform(*currentStep.m_transform.get()); } else { TransformState::TransformAccumulation accumulate = currentStep.m_accumulatingTransform ? TransformState::AccumulateTransform : TransformState::FlattenTransform; @@ -107,7 +107,7 @@ } } - ASSERT(foundContainer); + ASSERT(foundAncestor); transformState.flatten(); } @@ -128,16 +128,16 @@ } #endif -FloatQuad LayoutGeometryMap::mapToContainer(const FloatRect& rect, const LayoutBoxModelObject* container) const +FloatQuad LayoutGeometryMap::mapToAncestor(const FloatRect& rect, const LayoutBoxModelObject* ancestor) const { FloatQuad result; - if (!hasFixedPositionStep() && !hasTransformStep() && !hasNonUniformStep() && (!container || (m_mapping.size() && container == m_mapping[0].m_layoutObject))) { + if (!hasFixedPositionStep() && !hasTransformStep() && !hasNonUniformStep() && (!ancestor || (m_mapping.size() && ancestor == m_mapping[0].m_layoutObject))) { result = rect; result.move(m_accumulatedOffset); } else { TransformState transformState(TransformState::ApplyTransformDirection, rect.center(), rect); - mapToContainer(transformState, container); + mapToAncestor(transformState, ancestor); result = transformState.lastPlanarQuad(); } @@ -145,7 +145,7 @@ if (m_mapping.size() > 0) { const LayoutObject* lastLayoutObject = m_mapping.last().m_layoutObject; - FloatRect layoutObjectMappedResult = lastLayoutObject->localToContainerQuad(rect, container, m_mapCoordinatesFlags).boundingBox(); + FloatRect layoutObjectMappedResult = lastLayoutObject->localToAncestorQuad(rect, ancestor, m_mapCoordinatesFlags).boundingBox(); // Inspector creates layoutObjects with negative width <https://bugs.webkit.org/show_bug.cgi?id=87194>. // Taking FloatQuad bounds avoids spurious assertions because of that.
diff --git a/third_party/WebKit/Source/core/layout/LayoutGeometryMap.h b/third_party/WebKit/Source/core/layout/LayoutGeometryMap.h index 4fe2cc5..78436b0 100644 --- a/third_party/WebKit/Source/core/layout/LayoutGeometryMap.h +++ b/third_party/WebKit/Source/core/layout/LayoutGeometryMap.h
@@ -55,13 +55,13 @@ FloatRect absoluteRect(const FloatRect& rect) const { - return mapToContainer(rect, 0).boundingBox(); + return mapToAncestor(rect, 0).boundingBox(); } - // Map to a container. Will assert that the container has been pushed onto this map. - // A null container maps through the LayoutView (including its scale transform, if any). - // If the container is the LayoutView, the scroll offset is applied, but not the scale. - FloatQuad mapToContainer(const FloatRect&, const LayoutBoxModelObject*) const; + // Map to an ancestor. Will assert that the ancestor has been pushed onto this map. + // A null ancestor maps through the LayoutView (including its scale transform, if any). + // If the ancestor is the LayoutView, the scroll offset is applied, but not the scale. + FloatQuad mapToAncestor(const FloatRect&, const LayoutBoxModelObject*) const; // Called by code walking the layout or layer trees. void pushMappingsToAncestor(const PaintLayer*, const PaintLayer* ancestorLayer); @@ -77,7 +77,7 @@ private: void popMappingsToAncestor(const LayoutBoxModelObject*); - void mapToContainer(TransformState&, const LayoutBoxModelObject* container = nullptr) const; + void mapToAncestor(TransformState&, const LayoutBoxModelObject* ancestor = nullptr) const; void stepInserted(const LayoutGeometryMapStep&); void stepRemoved(const LayoutGeometryMapStep&);
diff --git a/third_party/WebKit/Source/core/layout/LayoutGrid.cpp b/third_party/WebKit/Source/core/layout/LayoutGrid.cpp index 255e397..390a4410 100644 --- a/third_party/WebKit/Source/core/layout/LayoutGrid.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutGrid.cpp
@@ -209,7 +209,7 @@ const size_t endOfVaryingTrackIndex = (m_direction == ForColumns) ? m_grid.size() : m_grid[0].size(); for (; varyingTrackIndex < endOfVaryingTrackIndex; ++varyingTrackIndex) { if (checkEmptyCells(rowSpan, columnSpan)) { - OwnPtr<GridCoordinate> result = adoptPtr(new GridCoordinate(GridSpan::definiteGridSpan(m_rowIndex, m_rowIndex + rowSpan), GridSpan::definiteGridSpan(m_columnIndex, m_columnIndex + columnSpan))); + OwnPtr<GridCoordinate> result = adoptPtr(new GridCoordinate(GridSpan::translatedDefiniteGridSpan(m_rowIndex, m_rowIndex + rowSpan), GridSpan::translatedDefiniteGridSpan(m_columnIndex, m_columnIndex + columnSpan))); // Advance the iterator to avoid an infinite loop where we would return the same grid area over and over. ++varyingTrackIndex; return result.release(); @@ -536,7 +536,7 @@ // 4. Grow all Grid tracks having a fraction as the MaxTrackSizingFunction. double flexFraction = 0; if (hasDefiniteFreeSpace) { - flexFraction = findFlexFactorUnitSize(tracks, GridSpan::definiteGridSpan(0, tracks.size()), direction, initialFreeSpace); + flexFraction = findFlexFactorUnitSize(tracks, GridSpan::translatedDefiniteGridSpan(0, tracks.size()), direction, initialFreeSpace); } else { for (const auto& trackIndex : flexibleSizedTracksIndex) flexFraction = std::max(flexFraction, normalizedFlexFraction(tracks[trackIndex], gridTrackSize(direction, trackIndex).maxTrackBreadth().flex())); @@ -656,7 +656,9 @@ { bool isForColumns = direction == ForColumns; const Vector<GridTrackSize>& trackStyles = isForColumns ? style()->gridTemplateColumns() : style()->gridTemplateRows(); - const GridTrackSize& trackSize = (i >= trackStyles.size()) ? (isForColumns ? style()->gridAutoColumns() : style()->gridAutoRows()) : trackStyles[i]; + const GridTrackSize& autoTrackSize = isForColumns ? style()->gridAutoColumns() : style()->gridAutoRows(); + int translatedIndex = i + (isForColumns ? m_smallestColumnStart : m_smallestRowStart); + const GridTrackSize& trackSize = (translatedIndex < 0 || translatedIndex >= static_cast<int>(trackStyles.size())) ? autoTrackSize : trackStyles[translatedIndex]; GridLength minTrackBreadth = trackSize.minTrackBreadth(); GridLength maxTrackBreadth = trackSize.maxTrackBreadth(); @@ -1104,7 +1106,7 @@ void LayoutGrid::insertItemIntoGrid(LayoutBox& child, const GridCoordinate& coordinate) { - RELEASE_ASSERT(coordinate.rows.isDefinite() && coordinate.columns.isDefinite()); + RELEASE_ASSERT(coordinate.rows.isTranslatedDefinite() && coordinate.columns.isTranslatedDefinite()); ensureGridSize(coordinate.rows.resolvedFinalPosition(), coordinate.columns.resolvedFinalPosition()); for (const auto& row : coordinate.rows) { @@ -1132,9 +1134,15 @@ continue; GridCoordinate coordinate = cachedGridCoordinate(*child); - if (!coordinate.rows.isDefinite() || !coordinate.columns.isDefinite()) { + if (!coordinate.rows.isIndefinite()) + coordinate.rows.translate(abs(m_smallestRowStart)); + if (!coordinate.columns.isIndefinite()) + coordinate.columns.translate(abs(m_smallestColumnStart)); + m_gridItemCoordinate.set(child, coordinate); + + if (coordinate.rows.isIndefinite() || coordinate.columns.isIndefinite()) { GridSpan majorAxisPositions = (autoPlacementMajorAxisDirection() == ForColumns) ? coordinate.columns : coordinate.rows; - if (!majorAxisPositions.isDefinite()) + if (majorAxisPositions.isIndefinite()) autoMajorAxisAutoGridItems.append(child); else specifiedMajorAxisAutoGridItems.append(child); @@ -1157,7 +1165,7 @@ continue; GridCoordinate coordinate = cachedGridCoordinate(*child); - ASSERT(coordinate.rows.isDefinite() && coordinate.columns.isDefinite()); + ASSERT(coordinate.rows.isTranslatedDefinite() && coordinate.columns.isTranslatedDefinite()); } #endif } @@ -1166,6 +1174,8 @@ { OrderIteratorPopulator populator(m_orderIterator); + m_smallestRowStart = m_smallestColumnStart = 0; + size_t maximumRowIndex = std::max<size_t>(1, GridResolvedPosition::explicitGridRowCount(*style())); size_t maximumColumnIndex = std::max<size_t>(1, GridResolvedPosition::explicitGridColumnCount(*style())); @@ -1184,26 +1194,28 @@ m_gridItemCoordinate.set(child, GridCoordinate(rowPositions, columnPositions)); // |positions| is 0 if we need to run the auto-placement algorithm. - if (rowPositions.isDefinite()) { - maximumRowIndex = std::max<size_t>(maximumRowIndex, rowPositions.resolvedFinalPosition()); + if (!rowPositions.isIndefinite()) { + m_smallestRowStart = std::min(m_smallestRowStart, rowPositions.untranslatedResolvedInitialPosition()); + maximumRowIndex = std::max<int>(maximumRowIndex, rowPositions.untranslatedResolvedFinalPosition()); } else { // Grow the grid for items with a definite row span, getting the largest such span. size_t spanSize = GridResolvedPosition::spanSizeForAutoPlacedItem(*style(), *child, ForRows); - maximumRowIndex = std::max<size_t>(maximumRowIndex, spanSize); + maximumRowIndex = std::max(maximumRowIndex, spanSize); } - if (columnPositions.isDefinite()) { - maximumColumnIndex = std::max<size_t>(maximumColumnIndex, columnPositions.resolvedFinalPosition()); + if (!columnPositions.isIndefinite()) { + m_smallestColumnStart = std::min(m_smallestColumnStart, columnPositions.untranslatedResolvedInitialPosition()); + maximumColumnIndex = std::max<int>(maximumColumnIndex, columnPositions.untranslatedResolvedFinalPosition()); } else { // Grow the grid for items with a definite column span, getting the largest such span. size_t spanSize = GridResolvedPosition::spanSizeForAutoPlacedItem(*style(), *child, ForColumns); - maximumColumnIndex = std::max<size_t>(maximumColumnIndex, spanSize); + maximumColumnIndex = std::max(maximumColumnIndex, spanSize); } } - m_grid.grow(maximumRowIndex); + m_grid.grow(maximumRowIndex + abs(m_smallestRowStart)); for (auto& column : m_grid) - column.grow(maximumColumnIndex); + column.grow(maximumColumnIndex + abs(m_smallestColumnStart)); } PassOwnPtr<GridCoordinate> LayoutGrid::createEmptyGridAreaAtSpecifiedPositionsOutsideGrid(const LayoutBox& gridItem, GridTrackSizingDirection specifiedDirection, const GridSpan& specifiedPositions) const @@ -1211,7 +1223,7 @@ GridTrackSizingDirection crossDirection = specifiedDirection == ForColumns ? ForRows : ForColumns; const size_t endOfCrossDirection = crossDirection == ForColumns ? gridColumnCount() : gridRowCount(); size_t crossDirectionSpanSize = GridResolvedPosition::spanSizeForAutoPlacedItem(*style(), gridItem, crossDirection); - GridSpan crossDirectionPositions = GridSpan::definiteGridSpan(endOfCrossDirection, endOfCrossDirection + crossDirectionSpanSize); + GridSpan crossDirectionPositions = GridSpan::translatedDefiniteGridSpan(endOfCrossDirection, endOfCrossDirection + crossDirectionSpanSize); return adoptPtr(new GridCoordinate(specifiedDirection == ForColumns ? crossDirectionPositions : specifiedPositions, specifiedDirection == ForColumns ? specifiedPositions : crossDirectionPositions)); } @@ -1227,8 +1239,8 @@ for (const auto& autoGridItem : autoGridItems) { GridSpan majorAxisPositions = cachedGridSpan(*autoGridItem, autoPlacementMajorAxisDirection()); - ASSERT(majorAxisPositions.isDefinite()); - ASSERT(!cachedGridSpan(*autoGridItem, autoPlacementMinorAxisDirection()).isDefinite()); + ASSERT(majorAxisPositions.isTranslatedDefinite()); + ASSERT(!cachedGridSpan(*autoGridItem, autoPlacementMinorAxisDirection()).isTranslatedDefinite()); size_t minorAxisSpanSize = GridResolvedPosition::spanSizeForAutoPlacedItem(*style(), *autoGridItem, autoPlacementMinorAxisDirection()); unsigned majorAxisInitialPosition = majorAxisPositions.resolvedInitialPosition(); @@ -1264,7 +1276,7 @@ void LayoutGrid::placeAutoMajorAxisItemOnGrid(LayoutBox& gridItem, std::pair<size_t, size_t>& autoPlacementCursor) { GridSpan minorAxisPositions = cachedGridSpan(gridItem, autoPlacementMinorAxisDirection()); - ASSERT(!cachedGridSpan(gridItem, autoPlacementMajorAxisDirection()).isDefinite()); + ASSERT(!cachedGridSpan(gridItem, autoPlacementMajorAxisDirection()).isTranslatedDefinite()); size_t majorAxisSpanSize = GridResolvedPosition::spanSizeForAutoPlacedItem(*style(), gridItem, autoPlacementMajorAxisDirection()); const size_t endOfMajorAxis = (autoPlacementMajorAxisDirection() == ForColumns) ? gridColumnCount() : gridRowCount(); @@ -1272,7 +1284,7 @@ size_t minorAxisAutoPlacementCursor = autoPlacementMajorAxisDirection() == ForColumns ? autoPlacementCursor.first : autoPlacementCursor.second; OwnPtr<GridCoordinate> emptyGridArea; - if (minorAxisPositions.isDefinite()) { + if (minorAxisPositions.isTranslatedDefinite()) { // Move to the next track in major axis if initial position in minor axis is before auto-placement cursor. if (minorAxisPositions.resolvedInitialPosition() < minorAxisAutoPlacementCursor) majorAxisAutoPlacementCursor++; @@ -1308,7 +1320,7 @@ } if (!emptyGridArea) - emptyGridArea = createEmptyGridAreaAtSpecifiedPositionsOutsideGrid(gridItem, autoPlacementMinorAxisDirection(), GridSpan::definiteGridSpan(0, minorAxisSpanSize)); + emptyGridArea = createEmptyGridAreaAtSpecifiedPositionsOutsideGrid(gridItem, autoPlacementMinorAxisDirection(), GridSpan::translatedDefiniteGridSpan(0, minorAxisSpanSize)); } m_gridItemCoordinate.set(&gridItem, *emptyGridArea); @@ -1476,11 +1488,12 @@ ASSERT(child.isHorizontalWritingMode() == isHorizontalWritingMode()); GridSpan positions = GridResolvedPosition::resolveGridPositionsFromStyle(*style(), child, direction); - if (!positions.isDefinite()) { + if (positions.isIndefinite()) { offset = LayoutUnit(); breadth = (direction == ForColumns) ? clientLogicalWidth() : clientLogicalHeight(); return; } + positions.translate(direction == ForColumns ? m_smallestColumnStart : m_smallestRowStart); GridPosition startPosition = (direction == ForColumns) ? child.style()->gridColumnStart() : child.style()->gridRowStart(); GridPosition endPosition = (direction == ForColumns) ? child.style()->gridColumnEnd() : child.style()->gridRowEnd();
diff --git a/third_party/WebKit/Source/core/layout/LayoutGrid.h b/third_party/WebKit/Source/core/layout/LayoutGrid.h index c7885c8..a9a7705 100644 --- a/third_party/WebKit/Source/core/layout/LayoutGrid.h +++ b/third_party/WebKit/Source/core/layout/LayoutGrid.h
@@ -213,6 +213,9 @@ LayoutUnit m_minContentHeight { -1 }; LayoutUnit m_maxContentHeight { -1 }; + + int m_smallestRowStart; + int m_smallestColumnStart; }; DEFINE_LAYOUT_OBJECT_TYPE_CASTS(LayoutGrid, isLayoutGrid());
diff --git a/third_party/WebKit/Source/core/layout/LayoutInline.cpp b/third_party/WebKit/Source/core/layout/LayoutInline.cpp index 3f38d05..7ff082f 100644 --- a/third_party/WebKit/Source/core/layout/LayoutInline.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutInline.cpp
@@ -1056,7 +1056,7 @@ if (overflowRect.isEmpty()) return overflowRect; - mapToVisibleRectInContainerSpace(paintInvalidationContainer, overflowRect, paintInvalidationState); + mapToVisibleRectInAncestorSpace(paintInvalidationContainer, overflowRect, paintInvalidationState); return overflowRect; } @@ -1078,9 +1078,9 @@ return overflowRect; } -void LayoutInline::mapToVisibleRectInContainerSpace(const LayoutBoxModelObject* paintInvalidationContainer, LayoutRect& rect, const PaintInvalidationState* paintInvalidationState) const +void LayoutInline::mapToVisibleRectInAncestorSpace(const LayoutBoxModelObject* ancestor, LayoutRect& rect, const PaintInvalidationState* paintInvalidationState) const { - if (paintInvalidationState && paintInvalidationState->canMapToContainer(paintInvalidationContainer)) { + if (paintInvalidationState && paintInvalidationState->canMapToContainer(ancestor)) { if (style()->hasInFlowPosition() && layer()) rect.move(layer()->offsetForInFlowPosition()); rect.move(paintInvalidationState->paintOffset()); @@ -1089,12 +1089,12 @@ return; } - if (paintInvalidationContainer == this) + if (ancestor == this) return; - bool containerSkipped; - LayoutObject* o = container(paintInvalidationContainer, &containerSkipped); - if (!o) + bool ancestorSkipped; + LayoutObject* container = this->container(ancestor, &ancestorSkipped); + if (!container) return; LayoutPoint topLeft = rect.location(); @@ -1110,24 +1110,23 @@ // FIXME: We ignore the lightweight clipping rect that controls use, since if |o| is in mid-layout, // its controlClipRect will be wrong. For overflow clip we use the values cached by the layer. rect.setLocation(topLeft); - if (o->hasOverflowClip()) { - LayoutBox* containerBox = toLayoutBox(o); - if (o == paintInvalidationContainer) - containerBox->applyCachedScrollOffsetForPaintInvalidation(rect); - else - containerBox->applyCachedClipAndScrollOffsetForPaintInvalidation(rect); + if (container->hasOverflowClip()) { + LayoutBox* containerBox = toLayoutBox(container); + containerBox->mapScrollingContentsRectToBoxSpace(rect); + if (container != ancestor) + containerBox->applyOverflowClip(rect); if (rect.isEmpty()) return; } - if (containerSkipped) { + if (ancestorSkipped) { // If the paintInvalidationContainer is below o, then we need to map the rect into paintInvalidationContainer's coordinates. - LayoutSize containerOffset = paintInvalidationContainer->offsetFromAncestorContainer(o); + LayoutSize containerOffset = ancestor->offsetFromAncestorContainer(container); rect.move(-containerOffset); return; } - o->mapToVisibleRectInContainerSpace(paintInvalidationContainer, rect, paintInvalidationState); + container->mapToVisibleRectInAncestorSpace(ancestor, rect, paintInvalidationState); } LayoutSize LayoutInline::offsetFromContainer(const LayoutObject* container, const LayoutPoint& point, bool* offsetDependsOnPoint) const @@ -1155,12 +1154,12 @@ || style()->hasCompositorProxy() || style()->containsPaint() ? NormalPaintLayer : NoPaintLayer; } -void LayoutInline::mapLocalToContainer(const LayoutBoxModelObject* paintInvalidationContainer, TransformState& transformState, MapCoordinatesFlags mode, bool* wasFixed, const PaintInvalidationState* paintInvalidationState) const +void LayoutInline::mapLocalToAncestor(const LayoutBoxModelObject* ancestor, TransformState& transformState, MapCoordinatesFlags mode, bool* wasFixed, const PaintInvalidationState* paintInvalidationState) const { - if (paintInvalidationContainer == this) + if (ancestor == this) return; - if (paintInvalidationState && paintInvalidationState->canMapToContainer(paintInvalidationContainer)) { + if (paintInvalidationState && paintInvalidationState->canMapToContainer(ancestor)) { LayoutSize offset = paintInvalidationState->paintOffset(); if (style()->hasInFlowPosition() && layer()) offset += layer()->offsetForInFlowPosition(); @@ -1169,7 +1168,7 @@ } bool containerSkipped; - LayoutObject* o = container(paintInvalidationContainer, &containerSkipped); + LayoutObject* o = container(ancestor, &containerSkipped); if (!o) return; @@ -1195,12 +1194,12 @@ if (containerSkipped) { // There can't be a transform between paintInvalidationContainer and o, because transforms create containers, so it should be safe // to just subtract the delta between the paintInvalidationContainer and o. - LayoutSize containerOffset = paintInvalidationContainer->offsetFromAncestorContainer(o); + LayoutSize containerOffset = ancestor->offsetFromAncestorContainer(o); transformState.move(-containerOffset.width(), -containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform); return; } - o->mapLocalToContainer(paintInvalidationContainer, transformState, mode, wasFixed, paintInvalidationState); + o->mapLocalToAncestor(ancestor, transformState, mode, wasFixed, paintInvalidationState); } void LayoutInline::updateDragState(bool dragOn)
diff --git a/third_party/WebKit/Source/core/layout/LayoutInline.h b/third_party/WebKit/Source/core/layout/LayoutInline.h index 354505c..f4a4a8bb 100644 --- a/third_party/WebKit/Source/core/layout/LayoutInline.h +++ b/third_party/WebKit/Source/core/layout/LayoutInline.h
@@ -237,13 +237,13 @@ LayoutRect absoluteClippedOverflowRect() const override; LayoutRect clippedOverflowRectForPaintInvalidation(const LayoutBoxModelObject* paintInvalidationContainer, const PaintInvalidationState* = nullptr) const override; - void mapToVisibleRectInContainerSpace(const LayoutBoxModelObject* paintInvalidationContainer, LayoutRect&, const PaintInvalidationState*) const final; + void mapToVisibleRectInAncestorSpace(const LayoutBoxModelObject* ancestor, LayoutRect&, const PaintInvalidationState*) const final; // This method differs from clippedOverflowRectForPaintInvalidation in that it includes // the rects for culled inline boxes, which aren't necessary for paint invalidation. LayoutRect clippedOverflowRect(const LayoutBoxModelObject*, const PaintInvalidationState* = nullptr) const; - void mapLocalToContainer(const LayoutBoxModelObject* paintInvalidationContainer, TransformState&, MapCoordinatesFlags = ApplyContainerFlip, bool* wasFixed = 0, const PaintInvalidationState* = nullptr) const override; + void mapLocalToAncestor(const LayoutBoxModelObject* ancestor, TransformState&, MapCoordinatesFlags = ApplyContainerFlip, bool* wasFixed = 0, const PaintInvalidationState* = nullptr) const override; PositionWithAffinity positionForPoint(const LayoutPoint&) final;
diff --git a/third_party/WebKit/Source/core/layout/LayoutListMarker.cpp b/third_party/WebKit/Source/core/layout/LayoutListMarker.cpp index 44e0cf1..d5b22f9 100644 --- a/third_party/WebKit/Source/core/layout/LayoutListMarker.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutListMarker.cpp
@@ -448,7 +448,7 @@ RootInlineBox& root = inlineBoxWrapper()->root(); LayoutRect rect(0, root.selectionTop() - location().y(), size().width(), root.selectionHeight()); - mapToVisibleRectInContainerSpace(paintInvalidationContainer, rect, 0); + mapToVisibleRectInAncestorSpace(paintInvalidationContainer, rect, nullptr); // FIXME: groupedMapping() leaks the squashing abstraction. if (paintInvalidationContainer->layer()->groupedMapping()) PaintLayer::mapRectToPaintBackingCoordinates(paintInvalidationContainer, rect);
diff --git a/third_party/WebKit/Source/core/layout/LayoutObject.cpp b/third_party/WebKit/Source/core/layout/LayoutObject.cpp index 2f3fd7d..9da07a02 100644 --- a/third_party/WebKit/Source/core/layout/LayoutObject.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutObject.cpp
@@ -1031,7 +1031,7 @@ { Vector<LayoutRect> rects; const LayoutBoxModelObject* container = enclosingLayer()->layoutObject(); - addElementVisualOverflowRects(rects, LayoutPoint(localToContainerPoint(FloatPoint(), container))); + addElementVisualOverflowRects(rects, LayoutPoint(localToAncestorPoint(FloatPoint(), container))); return container->localToAbsoluteQuad(FloatQuad(FloatRect(unionRect(rects)))).enclosingBoundingBox(); } @@ -1587,30 +1587,29 @@ return LayoutRect(); } -void LayoutObject::mapToVisibleRectInContainerSpace(const LayoutBoxModelObject* paintInvalidationContainer, LayoutRect& rect, const PaintInvalidationState* paintInvalidationState) const +void LayoutObject::mapToVisibleRectInAncestorSpace(const LayoutBoxModelObject* ancestor, LayoutRect& rect, const PaintInvalidationState* paintInvalidationState) const { - if (paintInvalidationContainer == this) + if (ancestor == this) return; - if (paintInvalidationState && paintInvalidationState->canMapToContainer(paintInvalidationContainer)) { + if (paintInvalidationState && paintInvalidationState->canMapToContainer(ancestor)) { rect.move(paintInvalidationState->paintOffset()); if (paintInvalidationState->isClipped()) rect.intersect(paintInvalidationState->clipRect()); return; } - if (LayoutObject* o = parent()) { - if (o->hasOverflowClip()) { - LayoutBox* boxParent = toLayoutBox(o); - if (o == paintInvalidationContainer) - boxParent->applyCachedScrollOffsetForPaintInvalidation(rect); - else - boxParent->applyCachedClipAndScrollOffsetForPaintInvalidation(rect); + if (LayoutObject* parent = this->parent()) { + if (parent->hasOverflowClip()) { + LayoutBox* parentBox = toLayoutBox(parent); + parentBox->mapScrollingContentsRectToBoxSpace(rect); + if (parent != ancestor) + parentBox->applyOverflowClip(rect); if (rect.isEmpty()) return; } - o->mapToVisibleRectInContainerSpace(paintInvalidationContainer, rect, paintInvalidationState); + parent->mapToVisibleRectInAncestorSpace(ancestor, rect, paintInvalidationState); } } @@ -1798,7 +1797,8 @@ // Caret is painted in text color. || (isLayoutBlock() && toLayoutBlock(this)->hasCaret()) || (isSVG() && style()->svgStyle().isFillColorCurrentColor()) - || (isSVG() && style()->svgStyle().isStrokeColorCurrentColor())) + || (isSVG() && style()->svgStyle().isStrokeColorCurrentColor()) + || isListMarker()) diff.setNeedsPaintInvalidationObject(); } @@ -2144,7 +2144,7 @@ FloatPoint LayoutObject::localToAbsolute(const FloatPoint& localPoint, MapCoordinatesFlags mode) const { TransformState transformState(TransformState::ApplyTransformDirection, localPoint); - mapLocalToContainer(0, transformState, mode | ApplyContainerFlip); + mapLocalToAncestor(0, transformState, mode | ApplyContainerFlip); transformState.flatten(); return transformState.lastPlanarPoint(); @@ -2167,9 +2167,9 @@ return transformState.lastPlanarQuad(); } -void LayoutObject::mapLocalToContainer(const LayoutBoxModelObject* paintInvalidationContainer, TransformState& transformState, MapCoordinatesFlags mode, bool* wasFixed, const PaintInvalidationState* paintInvalidationState) const +void LayoutObject::mapLocalToAncestor(const LayoutBoxModelObject* ancestor, TransformState& transformState, MapCoordinatesFlags mode, bool* wasFixed, const PaintInvalidationState* paintInvalidationState) const { - if (paintInvalidationContainer == this) + if (ancestor == this) return; LayoutObject* o = parent(); @@ -2189,7 +2189,7 @@ if (o->hasOverflowClip()) transformState.move(-toLayoutBox(o)->scrolledContentOffset()); - o->mapLocalToContainer(paintInvalidationContainer, transformState, mode, wasFixed, paintInvalidationState); + o->mapLocalToAncestor(ancestor, transformState, mode, wasFixed, paintInvalidationState); } const LayoutObject* LayoutObject::pushMappingToContainer(const LayoutBoxModelObject* ancestorToStopAt, LayoutGeometryMap& geometryMap) const @@ -2237,32 +2237,32 @@ } } -FloatQuad LayoutObject::localToContainerQuad(const FloatQuad& localQuad, const LayoutBoxModelObject* paintInvalidationContainer, MapCoordinatesFlags mode, bool* wasFixed) const +FloatQuad LayoutObject::localToAncestorQuad(const FloatQuad& localQuad, const LayoutBoxModelObject* ancestor, MapCoordinatesFlags mode, bool* wasFixed) const { - // Track the point at the center of the quad's bounding box. As mapLocalToContainer() calls offsetFromContainer(), + // Track the point at the center of the quad's bounding box. As mapLocalToAncestor() calls offsetFromContainer(), // it will use that point as the reference point to decide which column's transform to apply in multiple-column blocks. TransformState transformState(TransformState::ApplyTransformDirection, localQuad.boundingBox().center(), localQuad); - mapLocalToContainer(paintInvalidationContainer, transformState, mode | ApplyContainerFlip | UseTransforms, wasFixed); + mapLocalToAncestor(ancestor, transformState, mode | ApplyContainerFlip | UseTransforms, wasFixed); transformState.flatten(); return transformState.lastPlanarQuad(); } -FloatPoint LayoutObject::localToContainerPoint(const FloatPoint& localPoint, const LayoutBoxModelObject* paintInvalidationContainer, MapCoordinatesFlags mode, bool* wasFixed, const PaintInvalidationState* paintInvalidationState) const +FloatPoint LayoutObject::localToAncestorPoint(const FloatPoint& localPoint, const LayoutBoxModelObject* ancestor, MapCoordinatesFlags mode, bool* wasFixed, const PaintInvalidationState* paintInvalidationState) const { TransformState transformState(TransformState::ApplyTransformDirection, localPoint); - mapLocalToContainer(paintInvalidationContainer, transformState, mode | ApplyContainerFlip | UseTransforms, wasFixed, paintInvalidationState); + mapLocalToAncestor(ancestor, transformState, mode | ApplyContainerFlip | UseTransforms, wasFixed, paintInvalidationState); transformState.flatten(); return transformState.lastPlanarPoint(); } -void LayoutObject::localToContainerRects(Vector<LayoutRect>& rects, const LayoutBoxModelObject* paintInvalidationContainer, const LayoutPoint& preOffset, const LayoutPoint& postOffset) const +void LayoutObject::localToAncestorRects(Vector<LayoutRect>& rects, const LayoutBoxModelObject* ancestor, const LayoutPoint& preOffset, const LayoutPoint& postOffset) const { for (size_t i = 0; i < rects.size(); ++i) { LayoutRect& rect = rects[i]; rect.moveBy(preOffset); - FloatQuad containerQuad = localToContainerQuad(FloatQuad(FloatRect(rect)), paintInvalidationContainer); + FloatQuad containerQuad = localToAncestorQuad(FloatQuad(FloatRect(rect)), ancestor); LayoutRect containerRect = LayoutRect(containerQuad.boundingBox()); if (containerRect.isEmpty()) { rects.remove(i--); @@ -2280,7 +2280,7 @@ if (backingLayer) *backingLayer = paintInvalidationContainer.layer(); - FloatPoint containerPoint = localToContainerPoint(FloatPoint(localPoint), &paintInvalidationContainer, TraverseDocumentBoundaries); + FloatPoint containerPoint = localToAncestorPoint(FloatPoint(localPoint), &paintInvalidationContainer, TraverseDocumentBoundaries); // A layoutObject can have no invalidation backing if it is from a detached frame, // or when forced compositing is disabled. @@ -2306,9 +2306,9 @@ return offset; } -LayoutSize LayoutObject::offsetFromAncestorContainer(const LayoutObject* container) const +LayoutSize LayoutObject::offsetFromAncestorContainer(const LayoutObject* ancestorContainer) const { - if (container == this) + if (ancestorContainer == this) return LayoutSize(); LayoutSize offset; @@ -2324,7 +2324,7 @@ offset += currentOffset; referencePoint.move(currentOffset); currContainer = nextContainer; - } while (currContainer != container); + } while (currContainer != ancestorContainer); return offset; }
diff --git a/third_party/WebKit/Source/core/layout/LayoutObject.h b/third_party/WebKit/Source/core/layout/LayoutObject.h index 9dc0b509..c6d38ab 100644 --- a/third_party/WebKit/Source/core/layout/LayoutObject.h +++ b/third_party/WebKit/Source/core/layout/LayoutObject.h
@@ -775,13 +775,12 @@ // It is also used for correctly sizing absolutely positioned elements // (point 3 above). // - // If |paintInvalidationContainer| and |paintInvalidationContainerSkipped| - // are not null, on return *paintInvalidationContainerSkipped is true if - // the layoutObject returned is an ancestor of |paintInvalidationContainer|. - LayoutObject* container(const LayoutBoxModelObject* paintInvalidationContainer = nullptr, bool* paintInvalidationContainerSkipped = nullptr) const; + // If |ancestor| and |ancestorSkipped| are not null, on return *ancestorSkipped + // is true if the layoutObject returned is an ancestor of |ancestor|. + LayoutObject* container(const LayoutBoxModelObject* ancestor = nullptr, bool* ancestorSkipped = nullptr) const; LayoutObject* containerCrossingFrameBoundaries() const; // Finds the container as if this object is fixed-position. - LayoutBlock* containerForFixedPosition(const LayoutBoxModelObject* paintInvalidationContainer = nullptr, bool* paintInvalidationContainerSkipped = nullptr) const; + LayoutBlock* containerForFixedPosition(const LayoutBoxModelObject* ancestor = nullptr, bool* ancestorSkipped = nullptr) const; // Finds the containing block as if this object is absolute-position. LayoutBlock* containingBlockForAbsolutePosition() const; @@ -941,15 +940,15 @@ // Convert a local quad to absolute coordinates, taking transforms into account. FloatQuad localToAbsoluteQuad(const FloatQuad& quad, MapCoordinatesFlags mode = 0, bool* wasFixed = nullptr) const { - return localToContainerQuad(quad, 0, mode, wasFixed); + return localToAncestorQuad(quad, nullptr, mode, wasFixed); } // Convert an absolute quad to local coordinates. FloatQuad absoluteToLocalQuad(const FloatQuad&, MapCoordinatesFlags mode = 0) const; // Convert a local quad into the coordinate system of container, taking transforms into account. - FloatQuad localToContainerQuad(const FloatQuad&, const LayoutBoxModelObject* paintInvalidationContainer, MapCoordinatesFlags = 0, bool* wasFixed = nullptr) const; - FloatPoint localToContainerPoint(const FloatPoint&, const LayoutBoxModelObject* paintInvalidationContainer, MapCoordinatesFlags = 0, bool* wasFixed = nullptr, const PaintInvalidationState* = nullptr) const; - void localToContainerRects(Vector<LayoutRect>&, const LayoutBoxModelObject* paintInvalidationContainer, const LayoutPoint& preOffset, const LayoutPoint& postOffset) const; + FloatQuad localToAncestorQuad(const FloatQuad&, const LayoutBoxModelObject* ancestor, MapCoordinatesFlags = 0, bool* wasFixed = nullptr) const; + FloatPoint localToAncestorPoint(const FloatPoint&, const LayoutBoxModelObject* ancestor, MapCoordinatesFlags = 0, bool* wasFixed = nullptr, const PaintInvalidationState* = nullptr) const; + void localToAncestorRects(Vector<LayoutRect>&, const LayoutBoxModelObject* ancestor, const LayoutPoint& preOffset, const LayoutPoint& postOffset) const; // Convert a local point into the coordinate system of backing coordinates. Also returns the backing layer if needed. FloatPoint localToInvalidationBackingPoint(const LayoutPoint&, PaintLayer** backingLayer = nullptr); @@ -1088,7 +1087,7 @@ // rect in the coordinate space of paintInvalidationContainer. If intermediate containers have clipping or // scrolling of any kind, it is applied; but overflow clipping is *not* applied for paintInvalidationContainer // itself. - virtual void mapToVisibleRectInContainerSpace(const LayoutBoxModelObject* paintInvalidationContainer, LayoutRect&, const PaintInvalidationState*) const; + virtual void mapToVisibleRectInAncestorSpace(const LayoutBoxModelObject* ancestor, LayoutRect&, const PaintInvalidationState*) const; // Return the offset to the column in which the specified point (in flow-thread coordinates) // lives. This is used to convert a flow-thread point to a visual point. @@ -1191,7 +1190,7 @@ // Map points and quads through elements, potentially via 3d transforms. You should never need to call these directly; use // localToAbsolute/absoluteToLocal methods instead. - virtual void mapLocalToContainer(const LayoutBoxModelObject* paintInvalidationContainer, TransformState&, MapCoordinatesFlags = ApplyContainerFlip, bool* wasFixed = nullptr, const PaintInvalidationState* = nullptr) const; + virtual void mapLocalToAncestor(const LayoutBoxModelObject* ancestor, TransformState&, MapCoordinatesFlags = ApplyContainerFlip, bool* wasFixed = nullptr, const PaintInvalidationState* = nullptr) const; virtual void mapAbsoluteToLocalPoint(MapCoordinatesFlags, TransformState&) const; // Pushes state onto LayoutGeometryMap about how to map coordinates from this layoutObject to its container, or ancestorToStopAt (whichever is encountered first).
diff --git a/third_party/WebKit/Source/core/layout/LayoutObjectTest.cpp b/third_party/WebKit/Source/core/layout/LayoutObjectTest.cpp index 67f50e0..81a246f 100644 --- a/third_party/WebKit/Source/core/layout/LayoutObjectTest.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutObjectTest.cpp
@@ -118,7 +118,7 @@ container->setScrollTop(50); LayoutRect rect(0, 60, 20, 20); - text->mapToVisibleRectInContainerSpace(container, rect, nullptr); + text->mapToVisibleRectInAncestorSpace(container, rect, nullptr); EXPECT_TRUE(rect == LayoutRect(0, 10, 20, 20)); }
diff --git a/third_party/WebKit/Source/core/layout/LayoutPart.cpp b/third_party/WebKit/Source/core/layout/LayoutPart.cpp index 91b0c1e..400584a 100644 --- a/third_party/WebKit/Source/core/layout/LayoutPart.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutPart.cpp
@@ -343,8 +343,13 @@ { if (widget() && widget()->isFrameView()) { FrameView* childFrameView = toFrameView(widget()); - PaintInvalidationState childViewPaintInvalidationState(*childFrameView->layoutView(), paintInvalidationState); - toFrameView(widget())->invalidateTreeIfNeeded(childViewPaintInvalidationState); + // |childFrameView| is in another document, which could be + // missing its LayoutView. TODO(jchaffraix): Ideally we should + // not need this code. + if (LayoutView* childLayoutView = childFrameView->layoutView()) { + PaintInvalidationState childViewPaintInvalidationState(*childLayoutView, paintInvalidationState); + childFrameView->invalidateTreeIfNeeded(childViewPaintInvalidationState); + } } LayoutReplaced::invalidatePaintOfSubtreesIfNeeded(paintInvalidationState);
diff --git a/third_party/WebKit/Source/core/layout/LayoutReplaced.cpp b/third_party/WebKit/Source/core/layout/LayoutReplaced.cpp index c2cac389..7621248 100644 --- a/third_party/WebKit/Source/core/layout/LayoutReplaced.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutReplaced.cpp
@@ -434,7 +434,7 @@ if (rect.isEmpty()) return rect; - mapToVisibleRectInContainerSpace(paintInvalidationContainer, rect, 0); + mapToVisibleRectInAncestorSpace(paintInvalidationContainer, rect, 0); // FIXME: groupedMapping() leaks the squashing abstraction. if (paintInvalidationContainer->layer()->groupedMapping()) PaintLayer::mapRectToPaintBackingCoordinates(paintInvalidationContainer, rect);
diff --git a/third_party/WebKit/Source/core/layout/LayoutTableCell.cpp b/third_party/WebKit/Source/core/layout/LayoutTableCell.cpp index cccc8fbb1..94c76ba 100644 --- a/third_party/WebKit/Source/core/layout/LayoutTableCell.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutTableCell.cpp
@@ -353,18 +353,18 @@ LayoutPoint location(std::max<LayoutUnit>(left, -visualOverflowRect().x()), std::max<LayoutUnit>(top, -visualOverflowRect().y())); LayoutRect r(-location.x(), -location.y(), location.x() + std::max(size().width() + right, visualOverflowRect().maxX()), location.y() + std::max(size().height() + bottom, visualOverflowRect().maxY())); - mapToVisibleRectInContainerSpace(paintInvalidationContainer, r, paintInvalidationState); + mapToVisibleRectInAncestorSpace(paintInvalidationContainer, r, paintInvalidationState); return r; } -void LayoutTableCell::mapToVisibleRectInContainerSpace(const LayoutBoxModelObject* paintInvalidationContainer, LayoutRect& r, const PaintInvalidationState* paintInvalidationState) const +void LayoutTableCell::mapToVisibleRectInAncestorSpace(const LayoutBoxModelObject* ancestor, LayoutRect& r, const PaintInvalidationState* paintInvalidationState) const { - if (paintInvalidationContainer == this) + if (ancestor == this) return; r.setY(r.y()); - if ((!paintInvalidationState || !paintInvalidationState->canMapToContainer(paintInvalidationContainer)) && parent()) + if ((!paintInvalidationState || !paintInvalidationState->canMapToContainer(ancestor)) && parent()) r.moveBy(-parentBox()->location()); // Rows are in the same coordinate space, so don't add their offset in. - LayoutBlockFlow::mapToVisibleRectInContainerSpace(paintInvalidationContainer, r, paintInvalidationState); + LayoutBlockFlow::mapToVisibleRectInAncestorSpace(ancestor, r, paintInvalidationState); } LayoutUnit LayoutTableCell::cellBaselinePosition() const @@ -1011,4 +1011,13 @@ return newCell; } +bool LayoutTableCell::backgroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect) const +{ + // If this object has layer, the area of collapsed borders should be transparent + // to expose the collapsed borders painted on the underlying layer. + if (hasLayer() && table()->collapseBorders()) + return false; + return LayoutBlockFlow::backgroundIsKnownToBeOpaqueInRect(localRect); +} + } // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/LayoutTableCell.h b/third_party/WebKit/Source/core/layout/LayoutTableCell.h index 5e4c6a44..0539af3 100644 --- a/third_party/WebKit/Source/core/layout/LayoutTableCell.h +++ b/third_party/WebKit/Source/core/layout/LayoutTableCell.h
@@ -270,6 +270,8 @@ const char* name() const override { return "LayoutTableCell"; } + bool backgroundIsKnownToBeOpaqueInRect(const LayoutRect&) const override; + protected: void styleDidChange(StyleDifference, const ComputedStyle* oldStyle) override; void computePreferredLogicalWidths() override; @@ -290,7 +292,7 @@ LayoutSize offsetFromContainer(const LayoutObject*, const LayoutPoint&, bool* offsetDependsOnPoint = nullptr) const override; LayoutRect clippedOverflowRectForPaintInvalidation(const LayoutBoxModelObject* paintInvalidationContainer, const PaintInvalidationState* = nullptr) const override; - void mapToVisibleRectInContainerSpace(const LayoutBoxModelObject* paintInvalidationContainer, LayoutRect&, const PaintInvalidationState*) const override; + void mapToVisibleRectInAncestorSpace(const LayoutBoxModelObject* ancestor, LayoutRect&, const PaintInvalidationState*) const override; int borderHalfLeft(bool outer) const; int borderHalfRight(bool outer) const;
diff --git a/third_party/WebKit/Source/core/layout/LayoutTableCellTest.cpp b/third_party/WebKit/Source/core/layout/LayoutTableCellTest.cpp index 9eb881e3..f676eaa 100644 --- a/third_party/WebKit/Source/core/layout/LayoutTableCellTest.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutTableCellTest.cpp
@@ -76,7 +76,7 @@ #endif -class LayoutTableCellTest : public RenderingTest { }; +using LayoutTableCellTest = RenderingTest; TEST_F(LayoutTableCellTest, ResetColspanIfTooBig) { @@ -110,6 +110,16 @@ ASSERT_EQ(cell->rowSpan(), 65534U); } +TEST_F(LayoutTableCellTest, BackgroundIsKnownToBeOpaqueWithLayerAndCollapsedBorder) +{ + setBodyInnerHTML("<table style='border-collapse: collapse'>" + "<td style='will-change: transform; background-color: blue'>Cell></td>" + "</table>"); + + LayoutTableCell* cell = toLayoutTableCell(document().body()->firstChild()->firstChild()->firstChild()->firstChild()->layoutObject()); + EXPECT_FALSE(cell->backgroundIsKnownToBeOpaqueInRect(LayoutRect(0, 0, 1, 1))); +} + } } // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/LayoutTableRow.cpp b/third_party/WebKit/Source/core/layout/LayoutTableRow.cpp index 6fb4eea9..0a13367 100644 --- a/third_party/WebKit/Source/core/layout/LayoutTableRow.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutTableRow.cpp
@@ -255,4 +255,13 @@ addVisualOverflow(cellVisualOverflowRect); } +bool LayoutTableRow::backgroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect) const +{ + // If this object has layer, the area of collapsed borders should be transparent + // to expose the collapsed borders painted on the underlying layer. + if (hasLayer() && table()->collapseBorders()) + return false; + return LayoutBox::backgroundIsKnownToBeOpaqueInRect(localRect); +} + } // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/LayoutTableRow.h b/third_party/WebKit/Source/core/layout/LayoutTableRow.h index ab41d03..753da75 100644 --- a/third_party/WebKit/Source/core/layout/LayoutTableRow.h +++ b/third_party/WebKit/Source/core/layout/LayoutTableRow.h
@@ -126,6 +126,8 @@ const char* name() const override { return "LayoutTableRow"; } + bool backgroundIsKnownToBeOpaqueInRect(const LayoutRect&) const override; + private: LayoutObjectChildList* virtualChildren() override { return children(); } const LayoutObjectChildList* virtualChildren() const override { return children(); }
diff --git a/third_party/WebKit/Source/core/layout/LayoutTableRowTest.cpp b/third_party/WebKit/Source/core/layout/LayoutTableRowTest.cpp index a7e8053..0b42225 100644 --- a/third_party/WebKit/Source/core/layout/LayoutTableRowTest.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutTableRowTest.cpp
@@ -25,19 +25,18 @@ #include "core/layout/LayoutTableRow.h" -#include "core/testing/DummyPageHolder.h" -#include "testing/gtest/include/gtest/gtest.h" +#include "core/layout/LayoutTestHelper.h" namespace blink { namespace { -class LayoutTableRowDeathTest : public testing::Test { +class LayoutTableRowDeathTest : public RenderingTest { protected: virtual void SetUp() { - m_pageHolder = DummyPageHolder::create(IntSize(800, 600)); - m_row = LayoutTableRow::createAnonymous(&m_pageHolder->document()); + RenderingTest::SetUp(); + m_row = LayoutTableRow::createAnonymous(&document()); } virtual void TearDown() @@ -45,7 +44,6 @@ m_row->destroy(); } - OwnPtr<DummyPageHolder> m_pageHolder; LayoutTableRow* m_row; }; @@ -78,6 +76,18 @@ #endif +using LayoutTableRowTest = RenderingTest; + +TEST_F(LayoutTableRowTest, BackgroundIsKnownToBeOpaqueWithLayerAndCollapsedBorder) +{ + setBodyInnerHTML("<table style='border-collapse: collapse'>" + "<tr style='will-change: transform; background-color: blue'><td>Cell</td></tr>" + "</table>"); + + LayoutTableRow* row = toLayoutTableRow(document().body()->firstChild()->firstChild()->firstChild()->layoutObject()); + EXPECT_FALSE(row->backgroundIsKnownToBeOpaqueInRect(LayoutRect(0, 0, 1, 1))); +} + } // anonymous namespace } // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/LayoutText.cpp b/third_party/WebKit/Source/core/layout/LayoutText.cpp index 7611a33..18333ce 100644 --- a/third_party/WebKit/Source/core/layout/LayoutText.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutText.cpp
@@ -727,7 +727,6 @@ TextRun run = constructTextRun(f, this, start, len, styleRef(), textDirection); run.setCharactersLength(textLength() - start); ASSERT(run.charactersLength() >= run.length()); - run.setCodePath(canUseSimpleFontCodePath() ? TextRun::ForceSimple : TextRun::ForceComplex); run.setTabSize(!style()->collapseWhiteSpace(), style()->tabSize()); run.setXPos(leadWidth + textWidthSoFar); @@ -792,7 +791,6 @@ if (stripFrontSpaces) { const UChar spaceChar = spaceCharacter; TextRun run = constructTextRun(font, &spaceChar, 1, styleRef(), direction); - run.setCodePath(canUseSimpleFontCodePath() ? TextRun::ForceSimple : TextRun::ForceComplex); float spaceWidth = font.width(run); floatMaxWidth -= spaceWidth; } else { @@ -1082,7 +1080,6 @@ } else { TextRun run = constructTextRun(f, this, i, 1, styleToUse, textDirection); run.setCharactersLength(len - i); - run.setCodePath(canUseSimpleFontCodePath() ? TextRun::ForceSimple : TextRun::ForceComplex); ASSERT(run.charactersLength() >= run.length()); run.setTabSize(!style()->collapseWhiteSpace(), style()->tabSize()); run.setXPos(leadWidth + currMaxWidth); @@ -1115,8 +1112,8 @@ GlyphOverflow glyphOverflow; glyphOverflow.setFromBounds(glyphBounds, f.fontMetrics().floatAscent(), f.fontMetrics().floatDescent(), m_maxWidth); // We shouldn't change our mind once we "know". - ASSERT(!m_knownToHaveNoOverflowAndNoFallbackFonts || (fallbackFonts.isEmpty() && glyphOverflow.isZero())); - m_knownToHaveNoOverflowAndNoFallbackFonts = fallbackFonts.isEmpty() && glyphOverflow.isZero(); + ASSERT(!m_knownToHaveNoOverflowAndNoFallbackFonts || (fallbackFonts.isEmpty() && glyphOverflow.isApproximatelyZero())); + m_knownToHaveNoOverflowAndNoFallbackFonts = fallbackFonts.isEmpty() && glyphOverflow.isApproximatelyZero(); clearPreferredLogicalWidthsDirty(); } @@ -1516,7 +1513,6 @@ run.setCharactersLength(textLength() - from); ASSERT(run.charactersLength() >= run.length()); - run.setCodePath(canUseSimpleFontCodePath() ? TextRun::ForceSimple : TextRun::ForceComplex); run.setTabSize(!style()->collapseWhiteSpace(), style()->tabSize()); run.setXPos(xPos.toFloat()); w = f.width(run, fallbackFonts, glyphBounds); @@ -1583,7 +1579,7 @@ return LayoutRect(); LayoutRect paintInvalidationRect(visualOverflowRect()); - mapToVisibleRectInContainerSpace(paintInvalidationContainer, paintInvalidationRect, paintInvalidationState); + mapToVisibleRectInAncestorSpace(paintInvalidationContainer, paintInvalidationRect, paintInvalidationState); return paintInvalidationRect; } @@ -1622,7 +1618,7 @@ rect.unite(LayoutRect(ellipsisRectForBox(box, startPos, endPos))); } - mapToVisibleRectInContainerSpace(paintInvalidationContainer, rect, 0); + mapToVisibleRectInAncestorSpace(paintInvalidationContainer, rect, 0); // FIXME: groupedMapping() leaks the squashing abstraction. if (paintInvalidationContainer->layer()->groupedMapping()) PaintLayer::mapRectToPaintBackingCoordinates(paintInvalidationContainer, rect);
diff --git a/third_party/WebKit/Source/core/layout/LayoutView.cpp b/third_party/WebKit/Source/core/layout/LayoutView.cpp index ca560fc..39fcf1c 100644 --- a/third_party/WebKit/Source/core/layout/LayoutView.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutView.cpp
@@ -314,11 +314,11 @@ return LayoutRect(documentRect()); } -void LayoutView::mapLocalToContainer(const LayoutBoxModelObject* paintInvalidationContainer, TransformState& transformState, MapCoordinatesFlags mode, bool* wasFixed, const PaintInvalidationState* paintInvalidationState) const +void LayoutView::mapLocalToAncestor(const LayoutBoxModelObject* ancestor, TransformState& transformState, MapCoordinatesFlags mode, bool* wasFixed, const PaintInvalidationState* paintInvalidationState) const { ASSERT_UNUSED(wasFixed, !wasFixed || *wasFixed == static_cast<bool>(mode & IsFixed)); - if (!paintInvalidationContainer && mode & UseTransforms && shouldUseTransformFromContainer(0)) { + if (!ancestor && mode & UseTransforms && shouldUseTransformFromContainer(0)) { TransformationMatrix t; getTransformFromContainer(0, LayoutSize(), t); transformState.applyTransform(t); @@ -332,7 +332,7 @@ mode &= ~IsFixed; } - if (paintInvalidationContainer == this) + if (ancestor == this) return; if (mode & TraverseDocumentBoundaries) { @@ -340,7 +340,7 @@ transformState.move(-frame()->view()->scrollOffset()); transformState.move(parentDocLayoutObject->contentBoxOffset()); - parentDocLayoutObject->mapLocalToContainer(paintInvalidationContainer, transformState, mode, wasFixed, paintInvalidationState); + parentDocLayoutObject->mapLocalToAncestor(ancestor, transformState, mode, wasFixed, paintInvalidationState); } } } @@ -458,12 +458,12 @@ compositor()->fullyInvalidatePaint(); } -void LayoutView::mapToVisibleRectInContainerSpace(const LayoutBoxModelObject* paintInvalidationContainer, LayoutRect& rect, const PaintInvalidationState* invalidationState) const +void LayoutView::mapToVisibleRectInAncestorSpace(const LayoutBoxModelObject* ancestor, LayoutRect& rect, const PaintInvalidationState* invalidationState) const { - mapToVisibleRectInContainerSpace(paintInvalidationContainer, rect, IsNotFixedPosition, invalidationState); + mapToVisibleRectInAncestorSpace(ancestor, rect, IsNotFixedPosition, invalidationState); } -void LayoutView::mapToVisibleRectInContainerSpace(const LayoutBoxModelObject* paintInvalidationContainer, LayoutRect& rect, ViewportConstrainedPosition viewportConstraint, const PaintInvalidationState* state) const +void LayoutView::mapToVisibleRectInAncestorSpace(const LayoutBoxModelObject* ancestor, LayoutRect& rect, ViewportConstrainedPosition viewportConstraint, const PaintInvalidationState* state) const { if (document().printing()) return; @@ -480,11 +480,11 @@ adjustViewportConstrainedOffset(rect, viewportConstraint); // Apply our transform if we have one (because of full page zooming). - if (!paintInvalidationContainer && layer() && layer()->transform()) + if (!ancestor && layer() && layer()->transform()) rect = layer()->transform()->mapRect(rect); - ASSERT(paintInvalidationContainer); - if (paintInvalidationContainer == this) + ASSERT(ancestor); + if (ancestor == this) return; Element* owner = document().ownerElement(); @@ -503,7 +503,7 @@ // Adjust for frame border. rect.move(obj->contentBoxOffset()); - obj->mapToVisibleRectInContainerSpace(paintInvalidationContainer, rect, 0); + obj->mapToVisibleRectInAncestorSpace(ancestor, rect, 0); } }
diff --git a/third_party/WebKit/Source/core/layout/LayoutView.h b/third_party/WebKit/Source/core/layout/LayoutView.h index 0a8e984..633bc93 100644 --- a/third_party/WebKit/Source/core/layout/LayoutView.h +++ b/third_party/WebKit/Source/core/layout/LayoutView.h
@@ -110,8 +110,8 @@ }; static ViewportConstrainedPosition viewportConstrainedPosition(EPosition position) { return position == FixedPosition ? IsFixedPosition : IsNotFixedPosition; } - void mapToVisibleRectInContainerSpace(const LayoutBoxModelObject* paintInvalidationContainer, LayoutRect&, ViewportConstrainedPosition, const PaintInvalidationState*) const; - void mapToVisibleRectInContainerSpace(const LayoutBoxModelObject* paintInvalidationContainer, LayoutRect&, const PaintInvalidationState*) const override; + void mapToVisibleRectInAncestorSpace(const LayoutBoxModelObject* ancestor, LayoutRect&, ViewportConstrainedPosition, const PaintInvalidationState*) const; + void mapToVisibleRectInAncestorSpace(const LayoutBoxModelObject* ancestor, LayoutRect&, const PaintInvalidationState*) const override; void adjustViewportConstrainedOffset(LayoutRect&, ViewportConstrainedPosition) const; void invalidatePaintForViewAndCompositedLayers(); @@ -211,7 +211,7 @@ void sendMediaPositionChangeNotifications(const IntRect& visibleRect); private: - void mapLocalToContainer(const LayoutBoxModelObject* paintInvalidationContainer, TransformState&, MapCoordinatesFlags = ApplyContainerFlip, bool* wasFixed = nullptr, const PaintInvalidationState* = nullptr) const override; + void mapLocalToAncestor(const LayoutBoxModelObject* ancestor, TransformState&, MapCoordinatesFlags = ApplyContainerFlip, bool* wasFixed = nullptr, const PaintInvalidationState* = nullptr) const override; const LayoutObject* pushMappingToContainer(const LayoutBoxModelObject* ancestorToStopAt, LayoutGeometryMap&) const override; void mapAbsoluteToLocalPoint(MapCoordinatesFlags, TransformState&) const override;
diff --git a/third_party/WebKit/Source/core/layout/PaintInvalidationState.cpp b/third_party/WebKit/Source/core/layout/PaintInvalidationState.cpp index 3f7e8c3..86d5be2 100644 --- a/third_party/WebKit/Source/core/layout/PaintInvalidationState.cpp +++ b/third_party/WebKit/Source/core/layout/PaintInvalidationState.cpp
@@ -30,7 +30,7 @@ } if (ownerPaintInvalidationState && ownerPaintInvalidationState->m_forcedSubtreeInvalidationWithinContainer) m_forcedSubtreeInvalidationWithinContainer = true; - FloatPoint point = layoutView.localToContainerPoint(FloatPoint(), &m_paintInvalidationContainer, TraverseDocumentBoundaries); + FloatPoint point = layoutView.localToAncestorPoint(FloatPoint(), &m_paintInvalidationContainer, TraverseDocumentBoundaries); m_paintOffset = LayoutSize(point.x(), point.y()); } m_clipRect = layoutView.viewRect(); @@ -62,7 +62,7 @@ } else { if (m_cachedOffsetsEnabled) { if (fixed) { - FloatPoint fixedOffset = layoutObject.localToContainerPoint(FloatPoint(), &m_paintInvalidationContainer, TraverseDocumentBoundaries); + FloatPoint fixedOffset = layoutObject.localToAncestorPoint(FloatPoint(), &m_paintInvalidationContainer, TraverseDocumentBoundaries); m_paintOffset = LayoutSize(fixedOffset.x(), fixedOffset.y()); } else { LayoutSize offset = layoutObject.isBox() && !layoutObject.isTableRow() ? toLayoutBox(layoutObject).locationOffset() : LayoutSize();
diff --git a/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.cpp b/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.cpp index 5f0e1c0..9c5dfc7 100644 --- a/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.cpp +++ b/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.cpp
@@ -853,7 +853,7 @@ } else { // The controls are in the same 2D space as the compositing container, so we can map them into the space of the container. TransformState transformState(TransformState::ApplyTransformDirection, FloatPoint()); - m_owningLayer.layoutObject()->mapLocalToContainer(compositingStackingContext->layoutObject(), transformState, ApplyContainerFlip); + m_owningLayer.layoutObject()->mapLocalToAncestor(compositingStackingContext->layoutObject(), transformState, ApplyContainerFlip); transformState.flatten(); hostLayerPosition = LayoutPoint(transformState.lastPlanarPoint()); if (PaintLayerScrollableArea* scrollableArea = compositingStackingContext->scrollableArea()) @@ -2278,7 +2278,7 @@ LayoutView* rootView = anchorLayoutObject->view(); while (rootView->frame()->ownerLayoutObject()) rootView = rootView->frame()->ownerLayoutObject()->view(); - anchorLayoutObject->mapToVisibleRectInContainerSpace(rootView, visibleContentRect, 0); + anchorLayoutObject->mapToVisibleRectInAncestorSpace(rootView, visibleContentRect, 0); visibleContentRect.intersect(LayoutRect(rootView->frameView()->visibleContentRect())); // Map the visible content rect from screen space to local graphics layer space.
diff --git a/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMappingTest.cpp b/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMappingTest.cpp index 82e9fb5..ac9d883 100644 --- a/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMappingTest.cpp +++ b/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMappingTest.cpp
@@ -17,8 +17,7 @@ public: CompositedLayerMappingTest() : RenderingTest(SingleChildFrameLoaderClient::create()) - , m_originalSlimmingPaintSynchronizedPaintingEnabled(RuntimeEnabledFeatures::slimmingPaintSynchronizedPaintingEnabled()) -{ } + { } protected: IntRect recomputeInterestRect(const GraphicsLayer* graphicsLayer) @@ -49,8 +48,6 @@ private: void SetUp() override { - RuntimeEnabledFeatures::setSlimmingPaintSynchronizedPaintingEnabled(true); - RenderingTest::SetUp(); enableCompositing(); GraphicsLayer::setDrawDebugRedFillForTesting(false); @@ -59,12 +56,8 @@ void TearDown() override { GraphicsLayer::setDrawDebugRedFillForTesting(true); - RuntimeEnabledFeatures::setSlimmingPaintSynchronizedPaintingEnabled(m_originalSlimmingPaintSynchronizedPaintingEnabled); - RenderingTest::TearDown(); } - - bool m_originalSlimmingPaintSynchronizedPaintingEnabled; }; #define EXPECT_RECT_EQ(expected, actual) \
diff --git a/third_party/WebKit/Source/core/layout/compositing/PaintLayerCompositor.cpp b/third_party/WebKit/Source/core/layout/compositing/PaintLayerCompositor.cpp index 722429f..99eded4 100644 --- a/third_party/WebKit/Source/core/layout/compositing/PaintLayerCompositor.cpp +++ b/third_party/WebKit/Source/core/layout/compositing/PaintLayerCompositor.cpp
@@ -876,13 +876,8 @@ { #if ENABLE(ASSERT) FrameView* view = m_layoutView.frameView(); - if (RuntimeEnabledFeatures::slimmingPaintSynchronizedPaintingEnabled()) { - ASSERT(lifecycle().state() == DocumentLifecycle::PaintClean - || (view && view->shouldThrottleRendering())); - } else { - ASSERT(lifecycle().state() == DocumentLifecycle::PaintInvalidationClean - || (view && view->shouldThrottleRendering())); - } + ASSERT(lifecycle().state() == DocumentLifecycle::PaintClean + || (view && view->shouldThrottleRendering())); #endif m_isTrackingPaintInvalidations = tracksPaintInvalidations;
diff --git a/third_party/WebKit/Source/core/layout/line/BreakingContextInlineHeaders.h b/third_party/WebKit/Source/core/layout/line/BreakingContextInlineHeaders.h index 9495aad..47fedc2 100644 --- a/third_party/WebKit/Source/core/layout/line/BreakingContextInlineHeaders.h +++ b/third_party/WebKit/Source/core/layout/line/BreakingContextInlineHeaders.h
@@ -535,7 +535,6 @@ return text.width(from, len, font, xPos, text.style()->direction(), fallbackFonts, glyphBounds); TextRun run = constructTextRun(font, text, from, len, text.styleRef()); - run.setCodePath(text.canUseSimpleFontCodePath() ? TextRun::ForceSimple : TextRun::ForceComplex); run.setTabSize(!collapseWhiteSpace, text.style()->tabSize()); run.setXPos(xPos); return font.width(run, fallbackFonts, glyphBounds); @@ -906,6 +905,10 @@ { bool checkForBreak = m_autoWrap; if (m_width.committedWidth() && !m_width.fitsOnLine() && m_lineBreak.object() && m_currWS == NOWRAP) { + if (m_width.fitsOnLine(0, ExcludeWhitespace)) { + m_width.commit(); + m_lineBreak.moveToStartOf(m_nextObject); + } checkForBreak = true; } else if (m_nextObject && m_current.object().isText() && m_nextObject.isText() && !m_nextObject.isBR() && (m_autoWrap || m_nextObject.style()->autoWrap())) { if (m_autoWrap && m_currentCharacterIsSpace) {
diff --git a/third_party/WebKit/Source/core/layout/line/GlyphOverflow.h b/third_party/WebKit/Source/core/layout/line/GlyphOverflow.h index 6b70e03..e301caf 100644 --- a/third_party/WebKit/Source/core/layout/line/GlyphOverflow.h +++ b/third_party/WebKit/Source/core/layout/line/GlyphOverflow.h
@@ -32,7 +32,6 @@ namespace blink { struct GlyphOverflow { - STACK_ALLOCATED(); GlyphOverflow() : left(0) , right(0) @@ -41,45 +40,31 @@ { } - bool isZero() const + bool isApproximatelyZero() const { - return !left && !right && !top && !bottom; - } - - // These helper functions are exposed to share logic with SVG which computes overflow - // in floating point (see: SVGTextLayoutEngine). - static float topOverflow(const FloatRect& bounds, float ascent) - { - return std::max(0.0f, -bounds.y() - ascent); - } - static float bottomOverflow(const FloatRect& bounds, float descent) - { - return std::max(0.0f, bounds.maxY() - descent); - } - static float leftOverflow(const FloatRect& bounds) - { - return std::max(0.0f, -bounds.x()); - } - static float rightOverflow(const FloatRect& bounds, float textWidth) - { - return std::max(0.0f, bounds.maxX() - textWidth); + // Overflow can be expensive so we try to avoid it. Small amounts of + // overflow is imperceptible and is typically masked by pixel snapping. + static const float kApproximatelyNoOverflow = 0.0625f; + return std::fabs(left) < kApproximatelyNoOverflow + && std::fabs(right) < kApproximatelyNoOverflow + && std::fabs(top) < kApproximatelyNoOverflow + && std::fabs(bottom) < kApproximatelyNoOverflow; } void setFromBounds(const FloatRect& bounds, float ascent, float descent, float textWidth) { - top = ceilf(topOverflow(bounds, ascent)); - bottom = ceilf(bottomOverflow(bounds, descent)); - left = ceilf(leftOverflow(bounds)); - right = ceilf(rightOverflow(bounds, textWidth)); + top = std::max(0.0f, -bounds.y() - ascent); + bottom = std::max(0.0f, bounds.maxY() - descent); + left = std::max(0.0f, -bounds.x()); + right = std::max(0.0f, bounds.maxX() - textWidth); } // Top and bottom are the amounts of glyph overflows exceeding the font metrics' ascent and descent, respectively. // Left and right are the amounts of glyph overflows exceeding the left and right edge of normal layout boundary, respectively. - // All fields are in absolute number of pixels rounded up to the nearest integer. - int left; - int right; - int top; - int bottom; + float left; + float right; + float top; + float bottom; }; } // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/line/InlineFlowBox.cpp b/third_party/WebKit/Source/core/layout/line/InlineFlowBox.cpp index bdf0cf96..886eac9 100644 --- a/third_party/WebKit/Source/core/layout/line/InlineFlowBox.cpp +++ b/third_party/WebKit/Source/core/layout/line/InlineFlowBox.cpp
@@ -820,20 +820,20 @@ GlyphOverflow* glyphOverflow = it == textBoxDataMap.end() ? nullptr : &it->value.second; bool isFlippedLine = style.isFlippedLinesWritingMode(); - int topGlyphEdge = glyphOverflow ? (isFlippedLine ? glyphOverflow->bottom : glyphOverflow->top) : 0; - int bottomGlyphEdge = glyphOverflow ? (isFlippedLine ? glyphOverflow->top : glyphOverflow->bottom) : 0; - int leftGlyphEdge = glyphOverflow ? glyphOverflow->left : 0; - int rightGlyphEdge = glyphOverflow ? glyphOverflow->right : 0; + float topGlyphEdge = glyphOverflow ? (isFlippedLine ? glyphOverflow->bottom : glyphOverflow->top) : 0; + float bottomGlyphEdge = glyphOverflow ? (isFlippedLine ? glyphOverflow->top : glyphOverflow->bottom) : 0; + float leftGlyphEdge = glyphOverflow ? glyphOverflow->left : 0; + float rightGlyphEdge = glyphOverflow ? glyphOverflow->right : 0; - int strokeOverflow = static_cast<int>(ceilf(style.textStrokeWidth() / 2.0f)); - int topGlyphOverflow = -strokeOverflow - topGlyphEdge; - int bottomGlyphOverflow = strokeOverflow + bottomGlyphEdge; - int leftGlyphOverflow = -strokeOverflow - leftGlyphEdge; - int rightGlyphOverflow = strokeOverflow + rightGlyphEdge; + float strokeOverflow = style.textStrokeWidth() / 2.0f; + float topGlyphOverflow = -strokeOverflow - topGlyphEdge; + float bottomGlyphOverflow = strokeOverflow + bottomGlyphEdge; + float leftGlyphOverflow = -strokeOverflow - leftGlyphEdge; + float rightGlyphOverflow = strokeOverflow + rightGlyphEdge; TextEmphasisPosition emphasisMarkPosition; if (style.textEmphasisMark() != TextEmphasisMarkNone && textBox->getEmphasisMarkPosition(style, emphasisMarkPosition)) { - int emphasisMarkHeight = style.font().emphasisMarkHeight(style.textEmphasisMarkString()); + float emphasisMarkHeight = style.font().emphasisMarkHeight(style.textEmphasisMarkString()); if ((emphasisMarkPosition == TextEmphasisPositionOver) == (!style.isFlippedLinesWritingMode())) topGlyphOverflow = std::min(topGlyphOverflow, -emphasisMarkHeight); else @@ -842,7 +842,7 @@ // If letter-spacing is negative, we should factor that into right layout overflow. Even in RTL, letter-spacing is // applied to the right, so this is not an issue with left overflow. - rightGlyphOverflow -= std::min(0, (int)style.font().fontDescription().letterSpacing()); + rightGlyphOverflow -= std::min(0.0f, style.font().fontDescription().letterSpacing()); LayoutRectOutsets textShadowLogicalOutsets; if (ShadowList* textShadow = style.textShadow()) @@ -860,10 +860,15 @@ LayoutUnit childOverflowLogicalLeft = std::min<LayoutUnit>(textShadowLogicalLeft + leftGlyphOverflow, leftGlyphOverflow); LayoutUnit childOverflowLogicalRight = std::max<LayoutUnit>(textShadowLogicalRight + rightGlyphOverflow, rightGlyphOverflow); - LayoutUnit logicalTopVisualOverflow = std::min(textBox->pixelSnappedLogicalTop() + childOverflowLogicalTop, logicalVisualOverflow.y()); - LayoutUnit logicalBottomVisualOverflow = std::max(textBox->pixelSnappedLogicalBottom() + childOverflowLogicalBottom, logicalVisualOverflow.maxY()); - LayoutUnit logicalLeftVisualOverflow = std::min(textBox->pixelSnappedLogicalLeft() + childOverflowLogicalLeft, logicalVisualOverflow.x()); - LayoutUnit logicalRightVisualOverflow = std::max(textBox->pixelSnappedLogicalRight() + childOverflowLogicalRight, logicalVisualOverflow.maxX()); + int enclosingLogicalTopWithOverflow = (textBox->logicalTop() + childOverflowLogicalTop).floor(); + int enclosingLogicalBottomWithOverflow = (textBox->logicalBottom() + childOverflowLogicalBottom).ceil(); + int enclosingLogicalLeftWithOverflow = (textBox->logicalLeft() + childOverflowLogicalLeft).floor(); + int enclosingLogicalRightWithOverflow = (textBox->logicalRight() + childOverflowLogicalRight).ceil(); + + LayoutUnit logicalTopVisualOverflow = std::min<LayoutUnit>(enclosingLogicalTopWithOverflow, logicalVisualOverflow.y()); + LayoutUnit logicalBottomVisualOverflow = std::max<LayoutUnit>(enclosingLogicalBottomWithOverflow, logicalVisualOverflow.maxY()); + LayoutUnit logicalLeftVisualOverflow = std::min<LayoutUnit>(enclosingLogicalLeftWithOverflow, logicalVisualOverflow.x()); + LayoutUnit logicalRightVisualOverflow = std::max<LayoutUnit>(enclosingLogicalRightWithOverflow, logicalVisualOverflow.maxX()); logicalVisualOverflow = LayoutRect(logicalLeftVisualOverflow, logicalTopVisualOverflow, logicalRightVisualOverflow - logicalLeftVisualOverflow, logicalBottomVisualOverflow - logicalTopVisualOverflow);
diff --git a/third_party/WebKit/Source/core/layout/line/InlineTextBox.cpp b/third_party/WebKit/Source/core/layout/line/InlineTextBox.cpp index c7aaf1063..4fcfc43 100644 --- a/third_party/WebKit/Source/core/layout/line/InlineTextBox.cpp +++ b/third_party/WebKit/Source/core/layout/line/InlineTextBox.cpp
@@ -587,7 +587,6 @@ TextRun run(string, textPos().toFloat(), expansion(), expansionBehavior(), direction(), dirOverride() || style.rtlOrdering() == VisualOrder); run.setTabSize(!style.collapseWhiteSpace(), style.tabSize()); - run.setCodePath(lineLayoutItem().canUseSimpleFontCodePath() ? TextRun::ForceSimple : TextRun::ForceComplex); run.setTextJustify(style.textJustify()); // Propagate the maximum length of the characters buffer to the TextRun, even when we're only processing a substring.
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGBlock.cpp b/third_party/WebKit/Source/core/layout/svg/LayoutSVGBlock.cpp index 013d5cf..67f0f27 100644 --- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGBlock.cpp +++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGBlock.cpp
@@ -81,9 +81,9 @@ SVGResourcesCache::clientStyleChanged(this, diff, styleRef()); } -void LayoutSVGBlock::mapLocalToContainer(const LayoutBoxModelObject* paintInvalidationContainer, TransformState& transformState, MapCoordinatesFlags, bool* wasFixed, const PaintInvalidationState* paintInvalidationState) const +void LayoutSVGBlock::mapLocalToAncestor(const LayoutBoxModelObject* ancestor, TransformState& transformState, MapCoordinatesFlags, bool* wasFixed, const PaintInvalidationState* paintInvalidationState) const { - SVGLayoutSupport::mapLocalToContainer(this, paintInvalidationContainer, transformState, wasFixed, paintInvalidationState); + SVGLayoutSupport::mapLocalToAncestor(this, ancestor, transformState, wasFixed, paintInvalidationState); } const LayoutObject* LayoutSVGBlock::pushMappingToContainer(const LayoutBoxModelObject* ancestorToStopAt, LayoutGeometryMap& geometryMap) const @@ -96,11 +96,11 @@ return SVGLayoutSupport::clippedOverflowRectForPaintInvalidation(*this, paintInvalidationContainer, paintInvalidationState); } -void LayoutSVGBlock::mapToVisibleRectInContainerSpace(const LayoutBoxModelObject* paintInvalidationContainer, LayoutRect& rect, const PaintInvalidationState* paintInvalidationState) const +void LayoutSVGBlock::mapToVisibleRectInAncestorSpace(const LayoutBoxModelObject* ancestor, LayoutRect& rect, const PaintInvalidationState* paintInvalidationState) const { FloatRect paintInvalidationRect(rect); const LayoutSVGRoot& svgRoot = SVGLayoutSupport::mapRectToSVGRootForPaintInvalidation(*this, paintInvalidationRect, rect); - svgRoot.mapToVisibleRectInContainerSpace(paintInvalidationContainer, rect, paintInvalidationState); + svgRoot.mapToVisibleRectInAncestorSpace(ancestor, rect, paintInvalidationState); } bool LayoutSVGBlock::nodeAtPoint(HitTestResult&, const HitTestLocation&, const LayoutPoint&, HitTestAction)
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGBlock.h b/third_party/WebKit/Source/core/layout/svg/LayoutSVGBlock.h index 665daf1..8eb17f4 100644 --- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGBlock.h +++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGBlock.h
@@ -32,7 +32,7 @@ LayoutRect clippedOverflowRectForPaintInvalidation(const LayoutBoxModelObject* paintInvalidationContainer, const PaintInvalidationState* = nullptr) const final; - void mapLocalToContainer(const LayoutBoxModelObject* paintInvalidationContainer, TransformState&, MapCoordinatesFlags = ApplyContainerFlip, bool* wasFixed = nullptr, const PaintInvalidationState* = nullptr) const final; + void mapLocalToAncestor(const LayoutBoxModelObject* ancestor, TransformState&, MapCoordinatesFlags = ApplyContainerFlip, bool* wasFixed = nullptr, const PaintInvalidationState* = nullptr) const final; const LayoutObject* pushMappingToContainer(const LayoutBoxModelObject* ancestorToStopAt, LayoutGeometryMap&) const final; AffineTransform localTransform() const final { return m_localTransform; } @@ -43,7 +43,7 @@ protected: void willBeDestroyed() override; - void mapToVisibleRectInContainerSpace(const LayoutBoxModelObject* paintInvalidationContainer, LayoutRect&, const PaintInvalidationState*) const final; + void mapToVisibleRectInAncestorSpace(const LayoutBoxModelObject* ancestor, LayoutRect&, const PaintInvalidationState*) const final; AffineTransform m_localTransform;
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGInline.cpp b/third_party/WebKit/Source/core/layout/svg/LayoutSVGInline.cpp index 4d11c671..b02c25e 100644 --- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGInline.cpp +++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGInline.cpp
@@ -88,9 +88,9 @@ return SVGLayoutSupport::clippedOverflowRectForPaintInvalidation(*this, paintInvalidationContainer, paintInvalidationState); } -void LayoutSVGInline::mapLocalToContainer(const LayoutBoxModelObject* paintInvalidationContainer, TransformState& transformState, MapCoordinatesFlags, bool* wasFixed, const PaintInvalidationState* paintInvalidationState) const +void LayoutSVGInline::mapLocalToAncestor(const LayoutBoxModelObject* ancestor, TransformState& transformState, MapCoordinatesFlags, bool* wasFixed, const PaintInvalidationState* paintInvalidationState) const { - SVGLayoutSupport::mapLocalToContainer(this, paintInvalidationContainer, transformState, wasFixed, paintInvalidationState); + SVGLayoutSupport::mapLocalToAncestor(this, ancestor, transformState, wasFixed, paintInvalidationState); } const LayoutObject* LayoutSVGInline::pushMappingToContainer(const LayoutBoxModelObject* ancestorToStopAt, LayoutGeometryMap& geometryMap) const
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGInline.h b/third_party/WebKit/Source/core/layout/svg/LayoutSVGInline.h index 2410ed9..5f6f6289 100644 --- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGInline.h +++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGInline.h
@@ -45,7 +45,7 @@ FloatRect paintInvalidationRectInLocalCoordinates() const final; LayoutRect clippedOverflowRectForPaintInvalidation(const LayoutBoxModelObject* paintInvalidationContainer, const PaintInvalidationState* = nullptr) const final; - void mapLocalToContainer(const LayoutBoxModelObject* paintInvalidationContainer, TransformState&, MapCoordinatesFlags = ApplyContainerFlip, bool* wasFixed = nullptr, const PaintInvalidationState* = nullptr) const final; + void mapLocalToAncestor(const LayoutBoxModelObject* ancestor, TransformState&, MapCoordinatesFlags = ApplyContainerFlip, bool* wasFixed = nullptr, const PaintInvalidationState* = nullptr) const final; const LayoutObject* pushMappingToContainer(const LayoutBoxModelObject* ancestorToStopAt, LayoutGeometryMap&) const final; void absoluteQuads(Vector<FloatQuad>&, bool* wasFixed) const final;
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGModelObject.cpp b/third_party/WebKit/Source/core/layout/svg/LayoutSVGModelObject.cpp index 8ef51a30..a2738d0 100644 --- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGModelObject.cpp +++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGModelObject.cpp
@@ -55,9 +55,9 @@ return SVGLayoutSupport::clippedOverflowRectForPaintInvalidation(*this, paintInvalidationContainer, paintInvalidationState); } -void LayoutSVGModelObject::mapLocalToContainer(const LayoutBoxModelObject* paintInvalidationContainer, TransformState& transformState, MapCoordinatesFlags, bool* wasFixed, const PaintInvalidationState* paintInvalidationState) const +void LayoutSVGModelObject::mapLocalToAncestor(const LayoutBoxModelObject* ancestor, TransformState& transformState, MapCoordinatesFlags, bool* wasFixed, const PaintInvalidationState* paintInvalidationState) const { - SVGLayoutSupport::mapLocalToContainer(this, paintInvalidationContainer, transformState, wasFixed, paintInvalidationState); + SVGLayoutSupport::mapLocalToAncestor(this, ancestor, transformState, wasFixed, paintInvalidationState); } const LayoutObject* LayoutSVGModelObject::pushMappingToContainer(const LayoutBoxModelObject* ancestorToStopAt, LayoutGeometryMap& geometryMap) const
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGModelObject.h b/third_party/WebKit/Source/core/layout/svg/LayoutSVGModelObject.h index 54fb62e..c20eea7 100644 --- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGModelObject.h +++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGModelObject.h
@@ -54,7 +54,7 @@ void absoluteRects(Vector<IntRect>&, const LayoutPoint& accumulatedOffset) const final; void absoluteQuads(Vector<FloatQuad>&, bool* wasFixed) const override; - void mapLocalToContainer(const LayoutBoxModelObject* paintInvalidationContainer, TransformState&, MapCoordinatesFlags = ApplyContainerFlip, bool* wasFixed = nullptr, const PaintInvalidationState* = nullptr) const final; + void mapLocalToAncestor(const LayoutBoxModelObject* ancestor, TransformState&, MapCoordinatesFlags = ApplyContainerFlip, bool* wasFixed = nullptr, const PaintInvalidationState* = nullptr) const final; const LayoutObject* pushMappingToContainer(const LayoutBoxModelObject* ancestorToStopAt, LayoutGeometryMap&) const final; void styleDidChange(StyleDifference, const ComputedStyle* oldStyle) override;
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGRoot.cpp b/third_party/WebKit/Source/core/layout/svg/LayoutSVGRoot.cpp index ab1d045..fbe5909 100644 --- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGRoot.cpp +++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGRoot.cpp
@@ -337,11 +337,11 @@ // Compute the paint invalidation rect in the parent coordinate space. LayoutRect rect(enclosingIntRect(paintInvalidationRect)); - LayoutReplaced::mapToVisibleRectInContainerSpace(paintInvalidationContainer, rect, paintInvalidationState); + LayoutReplaced::mapToVisibleRectInAncestorSpace(paintInvalidationContainer, rect, paintInvalidationState); return rect; } -void LayoutSVGRoot::mapToVisibleRectInContainerSpace(const LayoutBoxModelObject* paintInvalidationContainer, LayoutRect& rect, const PaintInvalidationState* paintInvalidationState) const +void LayoutSVGRoot::mapToVisibleRectInAncestorSpace(const LayoutBoxModelObject* ancestor, LayoutRect& rect, const PaintInvalidationState* paintInvalidationState) const { // Note that we don't apply the border-box transform here - it's assumed // that whoever called us has done that already. @@ -350,17 +350,17 @@ if (shouldApplyViewportClip()) rect.intersect(LayoutRect(pixelSnappedBorderBoxRect())); - LayoutReplaced::mapToVisibleRectInContainerSpace(paintInvalidationContainer, rect, paintInvalidationState); + LayoutReplaced::mapToVisibleRectInAncestorSpace(ancestor, rect, paintInvalidationState); } // This method expects local CSS box coordinates. // Callers with local SVG viewport coordinates should first apply the localToBorderBoxTransform // to convert from SVG viewport coordinates to local CSS box coordinates. -void LayoutSVGRoot::mapLocalToContainer(const LayoutBoxModelObject* paintInvalidationContainer, TransformState& transformState, MapCoordinatesFlags mode, bool* wasFixed, const PaintInvalidationState* paintInvalidationState) const +void LayoutSVGRoot::mapLocalToAncestor(const LayoutBoxModelObject* ancestor, TransformState& transformState, MapCoordinatesFlags mode, bool* wasFixed, const PaintInvalidationState* paintInvalidationState) const { ASSERT(mode & ~IsFixed); // We should have no fixed content in the SVG layout tree. - LayoutReplaced::mapLocalToContainer(paintInvalidationContainer, transformState, mode | ApplyContainerFlip, wasFixed, paintInvalidationState); + LayoutReplaced::mapLocalToAncestor(ancestor, transformState, mode | ApplyContainerFlip, wasFixed, paintInvalidationState); } const LayoutObject* LayoutSVGRoot::pushMappingToContainer(const LayoutBoxModelObject* ancestorToStopAt, LayoutGeometryMap& geometryMap) const
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGRoot.h b/third_party/WebKit/Source/core/layout/svg/LayoutSVGRoot.h index a87029d..df7b371 100644 --- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGRoot.h +++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGRoot.h
@@ -38,7 +38,7 @@ bool isEmbeddedThroughFrameContainingSVGDocument() const; void computeIntrinsicRatioInformation(FloatSize& intrinsicSize, double& intrinsicRatio) const override; - void mapToVisibleRectInContainerSpace(const LayoutBoxModelObject* paintInvalidationContainer, LayoutRect&, const PaintInvalidationState*) const override; + void mapToVisibleRectInAncestorSpace(const LayoutBoxModelObject* ancestor, LayoutRect&, const PaintInvalidationState*) const override; // If you have a LayoutSVGRoot, use firstChild or lastChild instead. void slowFirstChild() const = delete; @@ -103,7 +103,7 @@ LayoutRect clippedOverflowRectForPaintInvalidation(const LayoutBoxModelObject* paintInvalidationContainer, const PaintInvalidationState* = nullptr) const override; - void mapLocalToContainer(const LayoutBoxModelObject* paintInvalidationContainer, TransformState&, MapCoordinatesFlags = ApplyContainerFlip, bool* wasFixed = nullptr, const PaintInvalidationState* = nullptr) const override; + void mapLocalToAncestor(const LayoutBoxModelObject* ancestor, TransformState&, MapCoordinatesFlags = ApplyContainerFlip, bool* wasFixed = nullptr, const PaintInvalidationState* = nullptr) const override; const LayoutObject* pushMappingToContainer(const LayoutBoxModelObject* ancestorToStopAt, LayoutGeometryMap&) const override; bool canBeSelectionLeaf() const override { return false; }
diff --git a/third_party/WebKit/Source/core/layout/svg/SVGLayoutSupport.cpp b/third_party/WebKit/Source/core/layout/svg/SVGLayoutSupport.cpp index bddf227..32073042 100644 --- a/third_party/WebKit/Source/core/layout/svg/SVGLayoutSupport.cpp +++ b/third_party/WebKit/Source/core/layout/svg/SVGLayoutSupport.cpp
@@ -97,7 +97,7 @@ LayoutRect rect; const LayoutSVGRoot& svgRoot = mapRectToSVGRootForPaintInvalidation(object, paintInvalidationRect, rect, strokeWidthForHairlinePadding); - svgRoot.mapToVisibleRectInContainerSpace(paintInvalidationContainer, rect, paintInvalidationState); + svgRoot.mapToVisibleRectInAncestorSpace(paintInvalidationContainer, rect, paintInvalidationState); return rect; } @@ -120,11 +120,11 @@ return svgRoot; } -void SVGLayoutSupport::mapLocalToContainer(const LayoutObject* object, const LayoutBoxModelObject* paintInvalidationContainer, TransformState& transformState, bool* wasFixed, const PaintInvalidationState* paintInvalidationState) +void SVGLayoutSupport::mapLocalToAncestor(const LayoutObject* object, const LayoutBoxModelObject* ancestor, TransformState& transformState, bool* wasFixed, const PaintInvalidationState* paintInvalidationState) { transformState.applyTransform(object->localToParentTransform()); - if (paintInvalidationState && paintInvalidationState->canMapToContainer(paintInvalidationContainer)) { + if (paintInvalidationState && paintInvalidationState->canMapToContainer(ancestor)) { // |svgTransform| contains localToBorderBoxTransform mentioned below. transformState.applyTransform(paintInvalidationState->svgTransform()); transformState.move(paintInvalidationState->paintOffset()); @@ -135,12 +135,12 @@ // At the SVG/HTML boundary (aka LayoutSVGRoot), we apply the localToBorderBoxTransform // to map an element from SVG viewport coordinates to CSS box coordinates. - // LayoutSVGRoot's mapLocalToContainer method expects CSS box coordinates. + // LayoutSVGRoot's mapLocalToAncestor method expects CSS box coordinates. if (parent->isSVGRoot()) transformState.applyTransform(toLayoutSVGRoot(parent)->localToBorderBoxTransform()); MapCoordinatesFlags mode = UseTransforms; - parent->mapLocalToContainer(paintInvalidationContainer, transformState, mode, wasFixed, paintInvalidationState); + parent->mapLocalToAncestor(ancestor, transformState, mode, wasFixed, paintInvalidationState); } const LayoutObject* SVGLayoutSupport::pushMappingToContainer(const LayoutObject* object, const LayoutBoxModelObject* ancestorToStopAt, LayoutGeometryMap& geometryMap) @@ -151,7 +151,7 @@ // At the SVG/HTML boundary (aka LayoutSVGRoot), we apply the localToBorderBoxTransform // to map an element from SVG viewport coordinates to CSS box coordinates. - // LayoutSVGRoot's mapLocalToContainer method expects CSS box coordinates. + // LayoutSVGRoot's mapLocalToAncestor method expects CSS box coordinates. if (parent->isSVGRoot()) { TransformationMatrix matrix(object->localToParentTransform()); matrix.multiply(toLayoutSVGRoot(parent)->localToBorderBoxTransform());
diff --git a/third_party/WebKit/Source/core/layout/svg/SVGLayoutSupport.h b/third_party/WebKit/Source/core/layout/svg/SVGLayoutSupport.h index e553fd70..d5b8df4 100644 --- a/third_party/WebKit/Source/core/layout/svg/SVGLayoutSupport.h +++ b/third_party/WebKit/Source/core/layout/svg/SVGLayoutSupport.h
@@ -80,7 +80,7 @@ float strokeWidthForHairlinePadding = 0); static const LayoutSVGRoot& mapRectToSVGRootForPaintInvalidation(const LayoutObject&, const FloatRect& localPaintInvalidationRect, LayoutRect&, float strokeWidthForHairlinePadding = 0); - static void mapLocalToContainer(const LayoutObject*, const LayoutBoxModelObject* paintInvalidationContainer, TransformState&, bool* wasFixed = nullptr, const PaintInvalidationState* = nullptr); + static void mapLocalToAncestor(const LayoutObject*, const LayoutBoxModelObject* ancestor, TransformState&, bool* wasFixed = nullptr, const PaintInvalidationState* = nullptr); static const LayoutObject* pushMappingToContainer(const LayoutObject*, const LayoutBoxModelObject* ancestorToStopAt, LayoutGeometryMap&); // Shared between SVG layoutObjects and resources.
diff --git a/third_party/WebKit/Source/core/layout/svg/SVGTextFragment.h b/third_party/WebKit/Source/core/layout/svg/SVGTextFragment.h index b3ff267d..2951bb2 100644 --- a/third_party/WebKit/Source/core/layout/svg/SVGTextFragment.h +++ b/third_party/WebKit/Source/core/layout/svg/SVGTextFragment.h
@@ -20,6 +20,7 @@ #ifndef SVGTextFragment_h #define SVGTextFragment_h +#include "core/layout/line/GlyphOverflow.h" #include "platform/transforms/AffineTransform.h" #include "wtf/Allocator.h" @@ -56,10 +57,10 @@ FloatRect overflowBoundingBox(float baseline) const { FloatRect fragmentRect( - x - glyphOverflowLeft, - y - baseline - glyphOverflowTop, - width + glyphOverflowLeft + glyphOverflowRight, - height + glyphOverflowTop + glyphOverflowBottom); + x - glyphOverflow.left, + y - baseline - glyphOverflow.top, + width + glyphOverflow.left + glyphOverflow.right, + height + glyphOverflow.top + glyphOverflow.bottom); if (!isTransformed()) return fragmentRect; return buildNormalFragmentTransform().mapRect(fragmentRect); @@ -96,12 +97,7 @@ float width; float height; - // Top and bottom are the amounts of glyph overflows exceeding the font metrics' ascent and descent, respectively. - float glyphOverflowTop; - float glyphOverflowBottom; - // Left and right are the amounts of glyph overflows exceeding the left and right edge of normal layout boundary, respectively. - float glyphOverflowLeft; - float glyphOverflowRight; + GlyphOverflow glyphOverflow; // Includes rotation/glyph-orientation-(horizontal|vertical) transforms, as well as orientation related shifts // (see SVGTextLayoutEngine, which builds this transformation).
diff --git a/third_party/WebKit/Source/core/layout/svg/SVGTextLayoutEngine.cpp b/third_party/WebKit/Source/core/layout/svg/SVGTextLayoutEngine.cpp index 2958703..746e7d5 100644 --- a/third_party/WebKit/Source/core/layout/svg/SVGTextLayoutEngine.cpp +++ b/third_party/WebKit/Source/core/layout/svg/SVGTextLayoutEngine.cpp
@@ -19,7 +19,6 @@ #include "core/layout/svg/SVGTextLayoutEngine.h" -#include "core/layout/line/GlyphOverflow.h" #include "core/layout/svg/LayoutSVGInlineText.h" #include "core/layout/svg/LayoutSVGTextPath.h" #include "core/layout/svg/SVGTextChunkBuilder.h" @@ -110,7 +109,6 @@ m_dy = dy; } -// Computes the glyph overflow without integer clamping (see: GlyphOverflow.h). static void computeGlyphOverflow(SVGInlineTextBox* textBox, SVGTextFragment& textFragment) { LineLayoutSVGInlineText textLineLayout = LineLayoutSVGInlineText(textBox->lineLayoutItem()); @@ -124,11 +122,11 @@ float width = scaledFont.width(run, nullptr, &glyphOverflowBounds); float ascent = scaledFont.fontMetrics().floatAscent(); float descent = scaledFont.fontMetrics().floatDescent(); - - textFragment.glyphOverflowTop = GlyphOverflow::topOverflow(glyphOverflowBounds, ascent) / scalingFactor; - textFragment.glyphOverflowBottom = GlyphOverflow::bottomOverflow(glyphOverflowBounds, descent) / scalingFactor; - textFragment.glyphOverflowLeft = GlyphOverflow::leftOverflow(glyphOverflowBounds) / scalingFactor; - textFragment.glyphOverflowRight = GlyphOverflow::rightOverflow(glyphOverflowBounds, width) / scalingFactor; + textFragment.glyphOverflow.setFromBounds(glyphOverflowBounds, ascent, descent, width); + textFragment.glyphOverflow.top /= scalingFactor; + textFragment.glyphOverflow.left /= scalingFactor; + textFragment.glyphOverflow.right /= scalingFactor; + textFragment.glyphOverflow.bottom /= scalingFactor; } void SVGTextLayoutEngine::recordTextFragment(SVGInlineTextBox* textBox)
diff --git a/third_party/WebKit/Source/core/loader/FrameLoaderClient.h b/third_party/WebKit/Source/core/loader/FrameLoaderClient.h index e87eb48..3f85998 100644 --- a/third_party/WebKit/Source/core/loader/FrameLoaderClient.h +++ b/third_party/WebKit/Source/core/loader/FrameLoaderClient.h
@@ -197,6 +197,9 @@ // This callback is similar, but for plugins. virtual void didNotAllowPlugins() { } + // This callback notifies the client that the frame created a Keygen element. + virtual void didUseKeygen() { } + virtual WebCookieJar* cookieJar() const = 0; virtual void didChangeName(const String&) { }
diff --git a/third_party/WebKit/Source/core/loader/ImageLoader.cpp b/third_party/WebKit/Source/core/loader/ImageLoader.cpp index 29410d0..94ba386 100644 --- a/third_party/WebKit/Source/core/loader/ImageLoader.cpp +++ b/third_party/WebKit/Source/core/loader/ImageLoader.cpp
@@ -96,10 +96,12 @@ v8::HandleScope scope(isolate); // If we're invoked from C++ without a V8 context on the stack, we should // run the microtask in the context of the element's document's main world. - if (ScriptState::hasCurrentScriptState(isolate)) + if (ScriptState::hasCurrentScriptState(isolate)) { m_scriptState = ScriptState::current(isolate); - else + } else { m_scriptState = ScriptState::forMainWorld(loader->element()->document().frame()); + ASSERT(m_scriptState); + } } ~Task() override
diff --git a/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.cpp b/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.cpp index 52957ba..823e2782 100644 --- a/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.cpp +++ b/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.cpp
@@ -493,7 +493,7 @@ for (size_t i = 0; i < layerIter->value.size(); ++i) { LayoutRect rect = layerIter->value[i]; if (compositedLayer != curLayer) { - FloatQuad compositorQuad = geometryMap.mapToContainer(FloatRect(rect), compositedLayer->layoutObject()); + FloatQuad compositorQuad = geometryMap.mapToAncestor(FloatRect(rect), compositedLayer->layoutObject()); rect = LayoutRect(compositorQuad.boundingBox()); // If the enclosing composited layer itself is scrolled, we have to undo the subtraction // of its scroll offset since we want the offset relative to the scrolling content, not
diff --git a/third_party/WebKit/Source/core/paint/BlockFlowPainter.cpp b/third_party/WebKit/Source/core/paint/BlockFlowPainter.cpp index 136888c..6282469 100644 --- a/third_party/WebKit/Source/core/paint/BlockFlowPainter.cpp +++ b/third_party/WebKit/Source/core/paint/BlockFlowPainter.cpp
@@ -79,7 +79,7 @@ if (!m_layoutBlockFlow.hasLayer()) { LayoutRect localBounds(gapRectsBounds); m_layoutBlockFlow.flipForWritingMode(localBounds); - gapRectsBounds = LayoutRect(m_layoutBlockFlow.localToContainerQuad(FloatRect(localBounds), layer->layoutObject()).enclosingBoundingBox()); + gapRectsBounds = LayoutRect(m_layoutBlockFlow.localToAncestorQuad(FloatRect(localBounds), layer->layoutObject()).enclosingBoundingBox()); if (layer->layoutObject()->hasOverflowClip()) gapRectsBounds.move(layer->layoutBox()->scrolledContentOffset()); }
diff --git a/third_party/WebKit/Source/core/paint/BoxPainter.cpp b/third_party/WebKit/Source/core/paint/BoxPainter.cpp index faee7a6..a5e8c3a03 100644 --- a/third_party/WebKit/Source/core/paint/BoxPainter.cpp +++ b/third_party/WebKit/Source/core/paint/BoxPainter.cpp
@@ -156,9 +156,8 @@ // FIXME : It would be possible for the following occlusion culling test to be more aggressive // on layers with no repeat by testing whether the image covers the layout rect. // Testing that here would imply duplicating a lot of calculations that are currently done in - // LayoutBoxModelObject::paintFillLayerExtended. A more efficient solution might be to move - // the layer recursion into paintFillLayerExtended, or to compute the layer geometry here - // and pass it down. + // LayoutBoxModelObject::paintFillLayer. A more efficient solution might be to move the layer + // recursion into paintFillLayer, or to compute the layer geometry here and pass it down. // TODO(trchen): Need to check compositing mode as well. if (currentLayer->blendMode() != WebBlendModeNormal) @@ -204,18 +203,12 @@ context.beginLayer(); for (auto it = reversedPaintList.rbegin(); it != reversedPaintList.rend(); ++it) - paintFillLayer(paintInfo, c, **it, rect, bleedAvoidance, op, backgroundObject); + paintFillLayer(m_layoutBox, paintInfo, c, **it, rect, bleedAvoidance, 0, LayoutSize(), op, backgroundObject); if (shouldDrawBackgroundInSeparateBuffer) context.endLayer(); } -void BoxPainter::paintFillLayer(const PaintInfo& paintInfo, const Color& c, const FillLayer& fillLayer, const LayoutRect& rect, - BackgroundBleedAvoidance bleedAvoidance, SkXfermode::Mode op, const LayoutObject* backgroundObject) -{ - BoxPainter::paintFillLayerExtended(m_layoutBox, paintInfo, c, fillLayer, rect, bleedAvoidance, 0, LayoutSize(), op, backgroundObject); -} - void BoxPainter::applyBoxShadowForBackground(GraphicsContext& context, const LayoutObject& obj) { const ShadowList* shadowList = obj.style()->boxShadow(); @@ -285,7 +278,7 @@ return getBackgroundRoundedRect(obj, borderRect, box, boxSize.width(), boxSize.height(), includeLogicalLeftEdge, includeLogicalRightEdge); } -void BoxPainter::paintFillLayerExtended(const LayoutBoxModelObject& obj, const PaintInfo& paintInfo, const Color& color, const FillLayer& bgLayer, const LayoutRect& rect, BackgroundBleedAvoidance bleedAvoidance, const InlineFlowBox* box, const LayoutSize& boxSize, SkXfermode::Mode op, const LayoutObject* backgroundObject) +void BoxPainter::paintFillLayer(const LayoutBoxModelObject& obj, const PaintInfo& paintInfo, const Color& color, const FillLayer& bgLayer, const LayoutRect& rect, BackgroundBleedAvoidance bleedAvoidance, const InlineFlowBox* box, const LayoutSize& boxSize, SkXfermode::Mode op, const LayoutObject* backgroundObject) { GraphicsContext& context = paintInfo.context; if (rect.isEmpty())
diff --git a/third_party/WebKit/Source/core/paint/BoxPainter.h b/third_party/WebKit/Source/core/paint/BoxPainter.h index 438beca4..b2d3484 100644 --- a/third_party/WebKit/Source/core/paint/BoxPainter.h +++ b/third_party/WebKit/Source/core/paint/BoxPainter.h
@@ -37,7 +37,7 @@ void paintFillLayers(const PaintInfo&, const Color&, const FillLayer&, const LayoutRect&, BackgroundBleedAvoidance = BackgroundBleedNone, SkXfermode::Mode = SkXfermode::kSrcOver_Mode, const LayoutObject* backgroundObject = nullptr); void paintMaskImages(const PaintInfo&, const LayoutRect&); void paintBoxDecorationBackgroundWithRect(const PaintInfo&, const LayoutPoint&, const LayoutRect&); - static void paintFillLayerExtended(const LayoutBoxModelObject&, const PaintInfo&, const Color&, const FillLayer&, const LayoutRect&, BackgroundBleedAvoidance, const InlineFlowBox* = nullptr, const LayoutSize& = LayoutSize(), SkXfermode::Mode = SkXfermode::kSrcOver_Mode, const LayoutObject* backgroundObject = nullptr); + static void paintFillLayer(const LayoutBoxModelObject&, const PaintInfo&, const Color&, const FillLayer&, const LayoutRect&, BackgroundBleedAvoidance, const InlineFlowBox* = nullptr, const LayoutSize& = LayoutSize(), SkXfermode::Mode = SkXfermode::kSrcOver_Mode, const LayoutObject* backgroundObject = nullptr); static InterpolationQuality chooseInterpolationQuality(const LayoutObject&, Image*, const void*, const LayoutSize&); static bool paintNinePieceImage(const LayoutBoxModelObject&, GraphicsContext&, const LayoutRect&, const ComputedStyle&, const NinePieceImage&, SkXfermode::Mode = SkXfermode::kSrcOver_Mode); static void paintBorder(const LayoutBoxModelObject&, const PaintInfo&, const LayoutRect&, const ComputedStyle&, BackgroundBleedAvoidance = BackgroundBleedNone, bool includeLogicalLeftEdge = true, bool includeLogicalRightEdge = true); @@ -46,7 +46,6 @@ private: void paintBackground(const PaintInfo&, const LayoutRect&, const Color& backgroundColor, BackgroundBleedAvoidance = BackgroundBleedNone); - void paintFillLayer(const PaintInfo&, const Color&, const FillLayer&, const LayoutRect&, BackgroundBleedAvoidance, SkXfermode::Mode, const LayoutObject* backgroundObject = nullptr); static FloatRoundedRect backgroundRoundedRectAdjustedForBleedAvoidance(const LayoutObject&, const LayoutRect&, BackgroundBleedAvoidance, const InlineFlowBox*, const LayoutSize&, bool includeLogicalLeftEdge, bool includeLogicalRightEdge); static FloatRoundedRect getBackgroundRoundedRect(const LayoutObject&, const LayoutRect&, const InlineFlowBox*, LayoutUnit inlineBoxWidth, LayoutUnit inlineBoxHeight, bool includeLogicalLeftEdge, bool includeLogicalRightEdge);
diff --git a/third_party/WebKit/Source/core/paint/GridPainter.cpp b/third_party/WebKit/Source/core/paint/GridPainter.cpp index e51317c..c7af36f 100644 --- a/third_party/WebKit/Source/core/paint/GridPainter.cpp +++ b/third_party/WebKit/Source/core/paint/GridPainter.cpp
@@ -25,7 +25,7 @@ --endGridAreaIndex; // GridSpan stores lines' indexes (not tracks' indexes). - return GridSpan::definiteGridSpan(startGridAreaIndex, endGridAreaIndex + 1); + return GridSpan::translatedDefiniteGridSpan(startGridAreaIndex, endGridAreaIndex + 1); } class GridItemsSorter {
diff --git a/third_party/WebKit/Source/core/paint/InlineFlowBoxPainter.cpp b/third_party/WebKit/Source/core/paint/InlineFlowBoxPainter.cpp index 61fe7c32..b6074ef 100644 --- a/third_party/WebKit/Source/core/paint/InlineFlowBoxPainter.cpp +++ b/third_party/WebKit/Source/core/paint/InlineFlowBoxPainter.cpp
@@ -71,11 +71,11 @@ StyleImage* img = fillLayer.image(); bool hasFillImage = img && img->canRender(); if ((!hasFillImage && !m_inlineFlowBox.lineLayoutItem().style()->hasBorderRadius()) || (!m_inlineFlowBox.prevLineBox() && !m_inlineFlowBox.nextLineBox()) || !m_inlineFlowBox.parent()) { - BoxPainter::paintFillLayerExtended(*boxModel, paintInfo, c, fillLayer, rect, BackgroundBleedNone, &m_inlineFlowBox, rect.size(), op); + BoxPainter::paintFillLayer(*boxModel, paintInfo, c, fillLayer, rect, BackgroundBleedNone, &m_inlineFlowBox, rect.size(), op); } else if (m_inlineFlowBox.lineLayoutItem().style()->boxDecorationBreak() == DCLONE) { GraphicsContextStateSaver stateSaver(paintInfo.context); paintInfo.context.clip(pixelSnappedIntRect(rect)); - BoxPainter::paintFillLayerExtended(*boxModel, paintInfo, c, fillLayer, rect, BackgroundBleedNone, &m_inlineFlowBox, rect.size(), op); + BoxPainter::paintFillLayer(*boxModel, paintInfo, c, fillLayer, rect, BackgroundBleedNone, &m_inlineFlowBox, rect.size(), op); } else { // We have a fill image that spans multiple lines. // FIXME: frameSize ought to be the same as rect.size(). @@ -84,7 +84,7 @@ GraphicsContextStateSaver stateSaver(paintInfo.context); // TODO(chrishtr): this should likely be pixel-snapped. paintInfo.context.clip(pixelSnappedIntRect(rect)); - BoxPainter::paintFillLayerExtended(*boxModel, paintInfo, c, fillLayer, imageStripPaintRect, BackgroundBleedNone, &m_inlineFlowBox, rect.size(), op); + BoxPainter::paintFillLayer(*boxModel, paintInfo, c, fillLayer, imageStripPaintRect, BackgroundBleedNone, &m_inlineFlowBox, rect.size(), op); } }
diff --git a/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.cpp b/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.cpp index 68a33b3..d5970e1 100644 --- a/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.cpp +++ b/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.cpp
@@ -84,7 +84,7 @@ return; } - // The text clip phase already has a LayoutObjectDrawingRecorder. Text clips are initiated only in BoxPainter::paintLayerExtended, + // The text clip phase already has a LayoutObjectDrawingRecorder. Text clips are initiated only in BoxPainter::paintFillLayer, // which is already within a LayoutObjectDrawingRecorder. Optional<DrawingRecorder> drawingRecorder; if (paintInfo.phase != PaintPhaseTextClip) {
diff --git a/third_party/WebKit/Source/core/paint/ObjectPainter.cpp b/third_party/WebKit/Source/core/paint/ObjectPainter.cpp index 420ae626..8d5887e 100644 --- a/third_party/WebKit/Source/core/paint/ObjectPainter.cpp +++ b/third_party/WebKit/Source/core/paint/ObjectPainter.cpp
@@ -211,7 +211,7 @@ if (!m_layoutObject.isBox() && m_layoutObject.styleRef().isFlippedBlocksWritingMode()) { LayoutBlock* container = m_layoutObject.containingBlock(); if (container) { - m_layoutObject.localToContainerRects(outlineRects, container, -paintOffset, paintOffset); + m_layoutObject.localToAncestorRects(outlineRects, container, -paintOffset, paintOffset); if (outlineRects.isEmpty()) return; } @@ -295,9 +295,10 @@ length = y2 - y1; } - // FIXME: We really would like this check to be an ASSERT as we don't want to draw empty borders. However - // nothing guarantees that the following recursive calls to drawLineForBoxSide will have non-null dimensions. - if (!thickness || !length) + // We would like this check to be an ASSERT as we don't want to draw empty borders. However + // nothing guarantees that the following recursive calls to drawLineForBoxSide will have + // positive thickness and length. + if (length <= 0 || thickness <= 0) return; if (style == DOUBLE && thickness < 3) @@ -340,8 +341,7 @@ void ObjectPainter::drawDashedOrDottedBoxSide(GraphicsContext& graphicsContext, int x1, int y1, int x2, int y2, BoxSide side, Color color, int thickness, EBorderStyle style, bool antialias) { - if (thickness <= 0) - return; + ASSERT(thickness > 0); bool wasAntialiased = graphicsContext.shouldAntialias(); StrokeStyle oldStrokeStyle = graphicsContext.strokeStyle(); @@ -372,7 +372,7 @@ int length, BoxSide side, Color color, int thickness, int adjacentWidth1, int adjacentWidth2, bool antialias) { int thirdOfThickness = (thickness + 1) / 3; - ASSERT(thirdOfThickness); + ASSERT(thirdOfThickness > 0); if (!adjacentWidth1 && !adjacentWidth2) { StrokeStyle oldStrokeStyle = graphicsContext.strokeStyle();
diff --git a/third_party/WebKit/Source/core/paint/PaintControllerPaintTest.h b/third_party/WebKit/Source/core/paint/PaintControllerPaintTest.h index 5b3e03915..0d4e69e 100644 --- a/third_party/WebKit/Source/core/paint/PaintControllerPaintTest.h +++ b/third_party/WebKit/Source/core/paint/PaintControllerPaintTest.h
@@ -18,8 +18,7 @@ class PaintControllerPaintTestBase : public RenderingTest { public: PaintControllerPaintTestBase(bool enableSlimmingPaintV2) - : m_originalSlimmingPaintSynchronizedPaintingEnabled(RuntimeEnabledFeatures::slimmingPaintSynchronizedPaintingEnabled()) - , m_originalSlimmingPaintOffsetCachingEnabled(RuntimeEnabledFeatures::slimmingPaintOffsetCachingEnabled()) + : m_originalSlimmingPaintOffsetCachingEnabled(RuntimeEnabledFeatures::slimmingPaintOffsetCachingEnabled()) , m_originalSlimmingPaintV2Enabled(RuntimeEnabledFeatures::slimmingPaintV2Enabled()) , m_enableSlimmingPaintV2(enableSlimmingPaintV2) { } @@ -37,7 +36,6 @@ } void TearDown() override { - RuntimeEnabledFeatures::setSlimmingPaintSynchronizedPaintingEnabled(m_originalSlimmingPaintSynchronizedPaintingEnabled); RuntimeEnabledFeatures::setSlimmingPaintOffsetCachingEnabled(m_originalSlimmingPaintOffsetCachingEnabled); RuntimeEnabledFeatures::setSlimmingPaintV2Enabled(m_originalSlimmingPaintV2Enabled); GraphicsLayer::setDrawDebugRedFillForTesting(true); @@ -56,14 +54,12 @@ void updateLifecyclePhasesToPaintClean() { - ASSERT(RuntimeEnabledFeatures::slimmingPaintSynchronizedPaintingEnabled()); updateLifecyclePhasesBeforePaint(); document().view()->synchronizedPaint(); } bool paintWithoutCommit(const IntRect* interestRect = nullptr) { - ASSERT(RuntimeEnabledFeatures::slimmingPaintSynchronizedPaintingEnabled()); // Only root graphics layer is supported. document().view()->lifecycle().advanceTo(DocumentLifecycle::InPaint); if (!layoutView().layer()->graphicsLayerBacking()->paintWithoutCommit(interestRect)) { @@ -88,7 +84,6 @@ } private: - bool m_originalSlimmingPaintSynchronizedPaintingEnabled; bool m_originalSlimmingPaintOffsetCachingEnabled; bool m_originalSlimmingPaintV2Enabled; bool m_enableSlimmingPaintV2;
diff --git a/third_party/WebKit/Source/core/paint/PaintLayer.cpp b/third_party/WebKit/Source/core/paint/PaintLayer.cpp index 9c051c7..df982ee 100644 --- a/third_party/WebKit/Source/core/paint/PaintLayer.cpp +++ b/third_party/WebKit/Source/core/paint/PaintLayer.cpp
@@ -493,7 +493,7 @@ LayoutPoint PaintLayer::positionFromPaintInvalidationBacking(const LayoutObject* layoutObject, const LayoutBoxModelObject* paintInvalidationContainer, const PaintInvalidationState* paintInvalidationState) { - FloatPoint point = layoutObject->localToContainerPoint(FloatPoint(), paintInvalidationContainer, 0, 0, paintInvalidationState); + FloatPoint point = layoutObject->localToAncestorPoint(FloatPoint(), paintInvalidationContainer, 0, 0, paintInvalidationState); // FIXME: Eventually we are going to unify coordinates in GraphicsLayer space. if (paintInvalidationContainer && paintInvalidationContainer->layer()->groupedMapping()) @@ -516,7 +516,7 @@ // |paintInvalidationContainer| may have a local 2D transform on it, so take that into account when mapping into the space of the // transformed ancestor. - point = paintInvalidationContainer->localToContainerPoint(point, transformedAncestor); + point = paintInvalidationContainer->localToAncestorPoint(point, transformedAncestor); point.moveBy(-paintInvalidationLayer->groupedMapping()->squashingOffsetFromTransformedAncestor()); } @@ -535,7 +535,7 @@ // |paintInvalidationContainer| may have a local 2D transform on it, so take that into account when mapping into the space of the // transformed ancestor. - rect = LayoutRect(paintInvalidationContainer->localToContainerQuad(FloatRect(rect), transformedAncestor).boundingBox()); + rect = LayoutRect(paintInvalidationContainer->localToAncestorQuad(FloatRect(rect), transformedAncestor).boundingBox()); rect.moveBy(-paintInvalidationLayer->groupedMapping()->squashingOffsetFromTransformedAncestor()); } @@ -543,7 +543,7 @@ void PaintLayer::mapRectToPaintInvalidationBacking(const LayoutObject* layoutObject, const LayoutBoxModelObject* paintInvalidationContainer, LayoutRect& rect, const PaintInvalidationState* paintInvalidationState) { if (!paintInvalidationContainer->layer()->groupedMapping()) { - layoutObject->mapToVisibleRectInContainerSpace(paintInvalidationContainer, rect, paintInvalidationState); + layoutObject->mapToVisibleRectInAncestorSpace(paintInvalidationContainer, rect, paintInvalidationState); return; } @@ -551,7 +551,7 @@ // layer. This is because all layers that squash together need to issue paint invalidations w.r.t. a single container that is // an ancestor of all of them, in order to properly take into account any local transforms etc. // FIXME: remove this special-case code that works around the paint invalidation code structure. - layoutObject->mapToVisibleRectInContainerSpace(paintInvalidationContainer, rect, paintInvalidationState); + layoutObject->mapToVisibleRectInAncestorSpace(paintInvalidationContainer, rect, paintInvalidationState); mapRectToPaintBackingCoordinates(paintInvalidationContainer, rect); } @@ -875,7 +875,7 @@ TransformState transformState(TransformState::ApplyTransformDirection, FloatPoint()); // FIXME: add a test that checks flipped writing mode and ApplyContainerFlip are correct. - layoutObject()->mapLocalToContainer(properties.transformAncestor ? properties.transformAncestor->layoutObject() : 0, transformState, ApplyContainerFlip); + layoutObject()->mapLocalToAncestor(properties.transformAncestor ? properties.transformAncestor->layoutObject() : 0, transformState, ApplyContainerFlip); transformState.flatten(); return LayoutPoint(transformState.lastPlanarPoint()); }
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerClipper.cpp b/third_party/WebKit/Source/core/paint/PaintLayerClipper.cpp index 4cc750b6..dead1f23 100644 --- a/third_party/WebKit/Source/core/paint/PaintLayerClipper.cpp +++ b/third_party/WebKit/Source/core/paint/PaintLayerClipper.cpp
@@ -274,7 +274,7 @@ // This offset cannot use convertToLayerCoords, because sometimes our rootLayer may be across // some transformed layer boundary, for example, in the PaintLayerCompositor overlapMap, where // clipRects are needed in view space. - applyClipRects(context, m_layoutObject, roundedLayoutPoint(m_layoutObject.localToContainerPoint(FloatPoint(), context.rootLayer->layoutObject())), clipRects); + applyClipRects(context, m_layoutObject, roundedLayoutPoint(m_layoutObject.localToAncestorPoint(FloatPoint(), context.rootLayer->layoutObject())), clipRects); } }
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerPainterTest.cpp b/third_party/WebKit/Source/core/paint/PaintLayerPainterTest.cpp index 4a76309e..b19b119b 100644 --- a/third_party/WebKit/Source/core/paint/PaintLayerPainterTest.cpp +++ b/third_party/WebKit/Source/core/paint/PaintLayerPainterTest.cpp
@@ -22,8 +22,6 @@ TEST_P(PaintLayerPainterTest, CachedSubsequence) { - RuntimeEnabledFeatures::setSlimmingPaintSynchronizedPaintingEnabled(true); - setBodyInnerHTML( "<div id='container1' style='position: relative; z-index: 1; width: 200px; height: 200px; background-color: blue'>" " <div id='content1' style='position: absolute; width: 100px; height: 100px; background-color: red'></div>" @@ -87,8 +85,6 @@ TEST_P(PaintLayerPainterTest, CachedSubsequenceOnInterestRectChange) { - RuntimeEnabledFeatures::setSlimmingPaintSynchronizedPaintingEnabled(true); - setBodyInnerHTML( "<div id='container1' style='position: relative; z-index: 1; width: 200px; height: 200px; background-color: blue'>" " <div id='content1' style='position: absolute; width: 100px; height: 100px; background-color: green'></div>" @@ -183,8 +179,6 @@ TEST_P(PaintLayerPainterTest, CachedSubsequenceOnStyleChangeWithInterestRectClipping) { - RuntimeEnabledFeatures::setSlimmingPaintSynchronizedPaintingEnabled(true); - setBodyInnerHTML( "<div id='container1' style='position: relative; z-index: 1; width: 200px; height: 200px; background-color: blue'>" " <div id='content1' style='position: absolute; width: 100px; height: 100px; background-color: red'></div>"
diff --git a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.h b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.h index d7861495..cdfacad 100644 --- a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.h +++ b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.h
@@ -21,7 +21,6 @@ void buildPropertyTrees(FrameView& rootFrame); private: - void walk(FrameView&, const PaintPropertyTreeBuilderContext&); void walk(LayoutObject&, const PaintPropertyTreeBuilderContext&); };
diff --git a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilderTest.cpp b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilderTest.cpp index 347dcac0..2fce3a6 100644 --- a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilderTest.cpp +++ b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilderTest.cpp
@@ -7,6 +7,7 @@ #include "core/layout/LayoutView.h" #include "core/paint/ObjectPaintProperties.h" #include "platform/graphics/paint/TransformPaintPropertyNode.h" +#include "platform/testing/UnitTestHelpers.h" #include "platform/text/TextStream.h" #include "public/platform/Platform.h" #include "public/platform/WebUnitTestSupport.h" @@ -23,7 +24,7 @@ void loadTestData(const char* fileName) { - String fullPath(Platform::current()->unitTestSupport()->webKitRootDir()); + String fullPath = testing::blinkRootDir(); fullPath.append("/Source/core/paint/test_data/"); fullPath.append(fileName); WebData inputBuffer = Platform::current()->unitTestSupport()->readFromFile(fullPath);
diff --git a/third_party/WebKit/Source/core/paint/PaintPropertyTreePrinter.cpp b/third_party/WebKit/Source/core/paint/PaintPropertyTreePrinter.cpp new file mode 100644 index 0000000..98d539a5 --- /dev/null +++ b/third_party/WebKit/Source/core/paint/PaintPropertyTreePrinter.cpp
@@ -0,0 +1,164 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "core/paint/PaintPropertyTreePrinter.h" + +#include "core/frame/FrameView.h" +#include "core/layout/LayoutView.h" +#include "core/paint/ObjectPaintProperties.h" + +#ifndef NDEBUG + +namespace blink { +namespace { + +template <typename PaintPropertyTreeNode> +class PropertyTreePrinterTraits; + +template <typename PropertyTreeNode> +class PropertyTreePrinter { +public: + PropertyTreePrinter(const FrameView& frameView) + { + collectPropertyNodes(frameView); + } + + void show() + { + showAllPropertyNodes(nullptr); + } + + void addPropertyNode(const PropertyTreeNode* node, String debugInfo) + { + m_nodeToDebugString.set(node, debugInfo); + } + +private: + using Traits = PropertyTreePrinterTraits<PropertyTreeNode>; + + void collectPropertyNodes(const FrameView& frameView) + { + Traits::addFrameViewProperties(frameView, *this); + if (LayoutView* layoutView = frameView.layoutView()) + collectPropertyNodes(*layoutView); + } + + void collectPropertyNodes(const LayoutObject& object) + { + if (const ObjectPaintProperties* paintProperties = object.objectPaintProperties()) + Traits::addObjectPaintProperties(*paintProperties, *this); + for (LayoutObject* child = object.slowFirstChild(); child; child = child->nextSibling()) + collectPropertyNodes(*child); + } + + void showAllPropertyNodes(const PropertyTreeNode* node, unsigned indent = 0) + { + if (node) { + StringBuilder stringBuilder; + for (unsigned i = 0; i < indent; i++) + stringBuilder.append(' '); + if (m_nodeToDebugString.contains(node)) + stringBuilder.append(m_nodeToDebugString.get(node)); + Traits::printNodeAsString(node, stringBuilder); + fprintf(stderr, "%s\n", stringBuilder.toString().ascii().data()); + } + + for (const auto* childNode : m_nodeToDebugString.keys()) { + if (childNode->parent() == node) + showAllPropertyNodes(childNode, indent + 2); + } + } + + HashMap<const PropertyTreeNode*, String> m_nodeToDebugString; +}; + +template <> +class PropertyTreePrinterTraits<TransformPaintPropertyNode> { +public: + static void addFrameViewProperties(const FrameView& frameView, PropertyTreePrinter<TransformPaintPropertyNode>& printer) + { + if (const TransformPaintPropertyNode* preTranslation = frameView.preTranslation()) + printer.addPropertyNode(preTranslation, "PreTranslation"); + if (const TransformPaintPropertyNode* scrollTranslation = frameView.scrollTranslation()) + printer.addPropertyNode(scrollTranslation, "ScrollTranslation"); + } + + static void addObjectPaintProperties(const ObjectPaintProperties& paintProperties, PropertyTreePrinter<TransformPaintPropertyNode>& printer) + { + if (const TransformPaintPropertyNode* paintOffsetTranslation = paintProperties.paintOffsetTranslation()) + printer.addPropertyNode(paintOffsetTranslation, "PaintOffsetTranslation"); + if (const TransformPaintPropertyNode* transform = paintProperties.transform()) + printer.addPropertyNode(transform, "Transform"); + if (const TransformPaintPropertyNode* perspective = paintProperties.perspective()) + printer.addPropertyNode(perspective, "Perspective"); + if (const TransformPaintPropertyNode* scrollTranslation = paintProperties.scrollTranslation()) + printer.addPropertyNode(scrollTranslation, "ScrollTranslation"); + if (const TransformPaintPropertyNode* transformForLayerContents = paintProperties.transformForLayerContents()) + printer.addPropertyNode(transformForLayerContents, "TransformForLayerContents"); + } + + static void printNodeAsString(const TransformPaintPropertyNode* node, StringBuilder& stringBuilder) + { + stringBuilder.append(String::format(" %p ", node)); + stringBuilder.append("transform="); + + TransformationMatrix::DecomposedType decomposition; + if (!node->matrix().decompose(decomposition)) { + stringBuilder.append("degenerate"); + return; + } + + stringBuilder.append(String::format("translation=%f,%f,%f", decomposition.translateX, decomposition.translateY, decomposition.translateZ)); + if (node->matrix().isIdentityOrTranslation()) + return; + + stringBuilder.append(String::format(", scale=%f,%f,%f", decomposition.scaleX, decomposition.scaleY, decomposition.scaleZ)); + stringBuilder.append(String::format(", skew=%f,%f,%f", decomposition.skewXY, decomposition.skewXZ, decomposition.skewYZ)); + stringBuilder.append(String::format(", quaternion=%f,%f,%f,%f", decomposition.quaternionX, decomposition.quaternionY, decomposition.quaternionZ, decomposition.quaternionW)); + stringBuilder.append(String::format(", perspective=%f,%f,%f,%f", decomposition.perspectiveX, decomposition.perspectiveY, decomposition.perspectiveZ, decomposition.perspectiveW)); + } +}; + +template <> +class PropertyTreePrinterTraits<ClipPaintPropertyNode> { +public: + static void addFrameViewProperties(const FrameView& frameView, PropertyTreePrinter<ClipPaintPropertyNode>& printer) + { + if (const ClipPaintPropertyNode* contentClip = frameView.contentClip()) + printer.addPropertyNode(contentClip, "ContentClip"); + } + + static void addObjectPaintProperties(const ObjectPaintProperties& paintProperties, PropertyTreePrinter<ClipPaintPropertyNode>& printer) + { + if (const ClipPaintPropertyNode* overflowClip = paintProperties.overflowClip()) + printer.addPropertyNode(overflowClip, "OverflowClip"); + } + + static void printNodeAsString(const ClipPaintPropertyNode* node, StringBuilder& stringBuilder) + { + stringBuilder.append(String::format(" %p ", node)); + stringBuilder.append(String::format("localTransformSpace=%p ", node->localTransformSpace())); + stringBuilder.append(String::format("rect=%f,%f,%f,%f", + node->clipRect().rect().x(), node->clipRect().rect().y(), + node->clipRect().rect().width(), node->clipRect().rect().height())); + } +}; + +} // anonymous namespace + +void showTransformPropertyTree(const FrameView& rootFrame) +{ + ASSERT(RuntimeEnabledFeatures::slimmingPaintV2Enabled()); + PropertyTreePrinter<TransformPaintPropertyNode>(rootFrame).show(); +} + +void showClipPropertyTree(const FrameView& rootFrame) +{ + ASSERT(RuntimeEnabledFeatures::slimmingPaintV2Enabled()); + PropertyTreePrinter<ClipPaintPropertyNode>(rootFrame).show(); +} + +} // namespace blink + +#endif
diff --git a/third_party/WebKit/Source/core/paint/PaintPropertyTreePrinter.h b/third_party/WebKit/Source/core/paint/PaintPropertyTreePrinter.h new file mode 100644 index 0000000..12504c03 --- /dev/null +++ b/third_party/WebKit/Source/core/paint/PaintPropertyTreePrinter.h
@@ -0,0 +1,19 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PaintPropertyTreePrinter_h +#define PaintPropertyTreePrinter_h + +#ifndef NDEBUG +namespace blink { + +class FrameView; + +void showTransformPropertyTree(const FrameView& rootFrame); +void showClipPropertyTree(const FrameView& rootFrame); + +} // namespace blink +#endif + +#endif // PaintPropertyTreePrinter_h
diff --git a/third_party/WebKit/Source/core/paint/TableCellPainterTest.cpp b/third_party/WebKit/Source/core/paint/TableCellPainterTest.cpp index e8a2c19..023c77f 100644 --- a/third_party/WebKit/Source/core/paint/TableCellPainterTest.cpp +++ b/third_party/WebKit/Source/core/paint/TableCellPainterTest.cpp
@@ -11,8 +11,6 @@ TEST_F(TableCellPainterTest, TableCellBackgroundInterestRect) { - RuntimeEnabledFeatures::setSlimmingPaintSynchronizedPaintingEnabled(true); - setBodyInnerHTML( "<style>" " td { width: 200px; height: 200px; border: none; }"
diff --git a/third_party/WebKit/Source/core/paint/ViewPainter.cpp b/third_party/WebKit/Source/core/paint/ViewPainter.cpp index c1eb6d1..55aea28 100644 --- a/third_party/WebKit/Source/core/paint/ViewPainter.cpp +++ b/third_party/WebKit/Source/core/paint/ViewPainter.cpp
@@ -142,13 +142,13 @@ bool shouldPaintInViewportSpace = (*it)->attachment() == FixedBackgroundAttachment; if (shouldPaintInViewportSpace) { - BoxPainter::paintFillLayerExtended(m_layoutView, paintInfo, Color(), **it, LayoutRect(LayoutRect::infiniteIntRect()), BackgroundBleedNone); + BoxPainter::paintFillLayer(m_layoutView, paintInfo, Color(), **it, LayoutRect(LayoutRect::infiniteIntRect()), BackgroundBleedNone); } else { context.save(); // TODO(trchen): We should be able to handle 3D-transformed root // background with slimming paint by using transform display items. context.concatCTM(transform.toAffineTransform()); - BoxPainter::paintFillLayerExtended(m_layoutView, paintInfo, Color(), **it, LayoutRect(paintRect), BackgroundBleedNone); + BoxPainter::paintFillLayer(m_layoutView, paintInfo, Color(), **it, LayoutRect(paintRect), BackgroundBleedNone); context.restore(); } }
diff --git a/third_party/WebKit/Source/core/streams/ReadableStream.js b/third_party/WebKit/Source/core/streams/ReadableStream.js index 6f94c2b3..0e745b86 100644 --- a/third_party/WebKit/Source/core/streams/ReadableStream.js +++ b/third_party/WebKit/Source/core/streams/ReadableStream.js
@@ -400,7 +400,9 @@ try { chunkSize = strategySize(chunk); } catch (chunkSizeE) { - ErrorReadableStream(stream, chunkSizeE); + if (stream[readableStreamState] === STATE_READABLE) { + ErrorReadableStream(stream, chunkSizeE); + } throw chunkSizeE; } } @@ -408,7 +410,9 @@ try { EnqueueValueWithSize(stream, chunk, chunkSize); } catch (enqueueE) { - ErrorReadableStream(stream, enqueueE); + if (stream[readableStreamState] === STATE_READABLE) { + ErrorReadableStream(stream, enqueueE); + } throw enqueueE; } }
diff --git a/third_party/WebKit/Source/core/style/GridCoordinate.h b/third_party/WebKit/Source/core/style/GridCoordinate.h index bd1592f..fb1727ee 100644 --- a/third_party/WebKit/Source/core/style/GridCoordinate.h +++ b/third_party/WebKit/Source/core/style/GridCoordinate.h
@@ -41,7 +41,7 @@ namespace blink { // Recommended maximum size for both explicit and implicit grids. -const size_t kGridMaxTracks = 1000000; +const int kGridMaxTracks = 1000000; // A span in a single direction (either rows or columns). Note that |resolvedInitialPosition| // and |resolvedFinalPosition| are grid lines' indexes. @@ -50,9 +50,14 @@ USING_FAST_MALLOC(GridSpan); public: - static GridSpan definiteGridSpan(size_t resolvedInitialPosition, size_t resolvedFinalPosition) + static GridSpan untranslatedDefiniteGridSpan(int resolvedInitialPosition, int resolvedFinalPosition) { - return GridSpan(resolvedInitialPosition, resolvedFinalPosition, Definite); + return GridSpan(resolvedInitialPosition, resolvedFinalPosition, UntranslatedDefinite); + } + + static GridSpan translatedDefiniteGridSpan(size_t resolvedInitialPosition, size_t resolvedFinalPosition) + { + return GridSpan(resolvedInitialPosition, resolvedFinalPosition, TranslatedDefinite); } static GridSpan indefiniteGridSpan() @@ -67,21 +72,34 @@ size_t integerSpan() const { - ASSERT(isDefinite()); + ASSERT(isTranslatedDefinite()); ASSERT(m_resolvedFinalPosition > m_resolvedInitialPosition); return m_resolvedFinalPosition - m_resolvedInitialPosition; } + int untranslatedResolvedInitialPosition() const + { + ASSERT(m_type == UntranslatedDefinite); + return m_resolvedInitialPosition; + } + + int untranslatedResolvedFinalPosition() const + { + ASSERT(m_type == UntranslatedDefinite); + return m_resolvedFinalPosition; + } + size_t resolvedInitialPosition() const { - ASSERT(isDefinite()); + ASSERT(isTranslatedDefinite()); + ASSERT(m_resolvedInitialPosition >= 0); return m_resolvedInitialPosition; } size_t resolvedFinalPosition() const { - ASSERT(isDefinite()); - ASSERT(m_resolvedFinalPosition); + ASSERT(isTranslatedDefinite()); + ASSERT(m_resolvedFinalPosition > 0); return m_resolvedFinalPosition; } @@ -97,35 +115,66 @@ GridSpanIterator begin() const { - ASSERT(isDefinite()); + ASSERT(isTranslatedDefinite()); return m_resolvedInitialPosition; } GridSpanIterator end() const { - ASSERT(isDefinite()); + ASSERT(isTranslatedDefinite()); return m_resolvedFinalPosition; } - bool isDefinite() const + bool isTranslatedDefinite() const { - return m_type == Definite; + return m_type == TranslatedDefinite; + } + + bool isIndefinite() const + { + return m_type == Indefinite; + } + + void translate(size_t offset) + { + ASSERT(m_type == UntranslatedDefinite); + + m_type = TranslatedDefinite; + m_resolvedInitialPosition += offset; + m_resolvedFinalPosition += offset; + + ASSERT(m_resolvedInitialPosition >= 0); + ASSERT(m_resolvedFinalPosition > 0); } private: - enum GridSpanType {Definite, Indefinite}; + enum GridSpanType {UntranslatedDefinite, TranslatedDefinite, Indefinite}; - GridSpan(size_t resolvedInitialPosition, size_t resolvedFinalPosition, GridSpanType type) - : m_resolvedInitialPosition(std::min(resolvedInitialPosition, kGridMaxTracks - 1)) - , m_resolvedFinalPosition(std::min(resolvedFinalPosition, kGridMaxTracks)) - , m_type(type) + GridSpan(int resolvedInitialPosition, int resolvedFinalPosition, GridSpanType type) + : m_type(type) { +#if ENABLE(ASSERT) ASSERT(resolvedInitialPosition < resolvedFinalPosition); + if (type == TranslatedDefinite) { + ASSERT(resolvedInitialPosition >= 0); + ASSERT(resolvedFinalPosition > 0); + } +#endif + + if (resolvedInitialPosition >= 0) + m_resolvedInitialPosition = std::min(resolvedInitialPosition, kGridMaxTracks - 1); + else + m_resolvedInitialPosition = std::max(resolvedInitialPosition, -kGridMaxTracks); + + if (resolvedFinalPosition >= 0) + m_resolvedFinalPosition = std::min(resolvedFinalPosition, kGridMaxTracks); + else + m_resolvedFinalPosition = std::max(resolvedFinalPosition, -kGridMaxTracks + 1); } - size_t m_resolvedInitialPosition; - size_t m_resolvedFinalPosition; + int m_resolvedInitialPosition; + int m_resolvedFinalPosition; GridSpanType m_type; };
diff --git a/third_party/WebKit/Source/core/style/GridResolvedPosition.cpp b/third_party/WebKit/Source/core/style/GridResolvedPosition.cpp index e1ca27a..1f28d5a 100644 --- a/third_party/WebKit/Source/core/style/GridResolvedPosition.cpp +++ b/third_party/WebKit/Source/core/style/GridResolvedPosition.cpp
@@ -65,7 +65,7 @@ static GridSpan definiteGridSpanWithInitialNamedSpanAgainstOpposite(size_t resolvedOppositePosition, const GridPosition& position, const Vector<size_t>& gridLines) { if (resolvedOppositePosition == 0) - return GridSpan::definiteGridSpan(resolvedOppositePosition, resolvedOppositePosition + 1); + return GridSpan::untranslatedDefiniteGridSpan(resolvedOppositePosition, resolvedOppositePosition + 1); size_t firstLineBeforeOppositePositionIndex = 0; const size_t* firstLineBeforeOppositePosition = std::lower_bound(gridLines.begin(), gridLines.end(), resolvedOppositePosition); @@ -75,7 +75,7 @@ size_t resolvedGridLinePosition = gridLines[gridLineIndex]; if (resolvedGridLinePosition >= resolvedOppositePosition) resolvedGridLinePosition = resolvedOppositePosition - 1; - return GridSpan::definiteGridSpan(resolvedGridLinePosition, resolvedOppositePosition); + return GridSpan::untranslatedDefiniteGridSpan(resolvedGridLinePosition, resolvedOppositePosition); } static GridSpan definiteGridSpanWithFinalNamedSpanAgainstOpposite(size_t resolvedOppositePosition, const GridPosition& position, const Vector<size_t>& gridLines) @@ -90,7 +90,7 @@ if (resolvedGridLinePosition <= resolvedOppositePosition) resolvedGridLinePosition = resolvedOppositePosition + 1; - return GridSpan::definiteGridSpan(resolvedOppositePosition, resolvedGridLinePosition); + return GridSpan::untranslatedDefiniteGridSpan(resolvedOppositePosition, resolvedGridLinePosition); } static GridSpan definiteGridSpanWithNamedSpanAgainstOpposite(size_t resolvedOppositePosition, const GridPosition& position, GridPositionSide side, const Vector<size_t>& gridLines) @@ -115,8 +115,8 @@ // See http://lists.w3.org/Archives/Public/www-style/2013Jun/0394.html. if (it == gridLinesNames.end()) { if ((side == ColumnStartSide || side == RowStartSide) && resolvedOppositePosition) - return GridSpan::definiteGridSpan(resolvedOppositePosition - 1, resolvedOppositePosition); - return GridSpan::definiteGridSpan(resolvedOppositePosition, resolvedOppositePosition + 1); + return GridSpan::untranslatedDefiniteGridSpan(resolvedOppositePosition - 1, resolvedOppositePosition); + return GridSpan::untranslatedDefiniteGridSpan(resolvedOppositePosition, resolvedOppositePosition + 1); } return definiteGridSpanWithNamedSpanAgainstOpposite(resolvedOppositePosition, position, side, it->value); @@ -125,23 +125,18 @@ static GridSpan definiteGridSpanWithSpanAgainstOpposite(size_t resolvedOppositePosition, const GridPosition& position, GridPositionSide side) { size_t positionOffset = position.spanPosition(); - if (side == ColumnStartSide || side == RowStartSide) { - if (resolvedOppositePosition == 0) - return GridSpan::definiteGridSpan(resolvedOppositePosition, resolvedOppositePosition + 1); + if (side == ColumnStartSide || side == RowStartSide) + return GridSpan::untranslatedDefiniteGridSpan(resolvedOppositePosition - positionOffset, resolvedOppositePosition); - size_t initialResolvedPosition = std::max<int>(0, resolvedOppositePosition - positionOffset); - return GridSpan::definiteGridSpan(initialResolvedPosition, resolvedOppositePosition); - } - - return GridSpan::definiteGridSpan(resolvedOppositePosition, resolvedOppositePosition + positionOffset); + return GridSpan::untranslatedDefiniteGridSpan(resolvedOppositePosition, resolvedOppositePosition + positionOffset); } static GridSpan resolveGridPositionAgainstOppositePosition(const ComputedStyle& gridContainerStyle, size_t resolvedOppositePosition, const GridPosition& position, GridPositionSide side) { if (position.isAuto()) { - if ((side == ColumnStartSide || side == RowStartSide) && resolvedOppositePosition) - return GridSpan::definiteGridSpan(resolvedOppositePosition - 1, resolvedOppositePosition); - return GridSpan::definiteGridSpan(resolvedOppositePosition, resolvedOppositePosition + 1); + if (side == ColumnStartSide || side == RowStartSide) + return GridSpan::untranslatedDefiniteGridSpan(resolvedOppositePosition - 1, resolvedOppositePosition); + return GridSpan::untranslatedDefiniteGridSpan(resolvedOppositePosition, resolvedOppositePosition + 1); } ASSERT(position.isSpan()); @@ -174,12 +169,12 @@ size_t GridResolvedPosition::explicitGridColumnCount(const ComputedStyle& gridContainerStyle) { - return std::min(gridContainerStyle.gridTemplateColumns().size(), kGridMaxTracks); + return std::min<size_t>(gridContainerStyle.gridTemplateColumns().size(), kGridMaxTracks); } size_t GridResolvedPosition::explicitGridRowCount(const ComputedStyle& gridContainerStyle) { - return std::min(gridContainerStyle.gridTemplateRows().size(), kGridMaxTracks); + return std::min<size_t>(gridContainerStyle.gridTemplateRows().size(), kGridMaxTracks); } static size_t explicitGridSizeForSide(const ComputedStyle& gridContainerStyle, GridPositionSide side) @@ -208,7 +203,7 @@ return it->value[namedGridLineIndex]; } -static size_t resolveGridPositionFromStyle(const ComputedStyle& gridContainerStyle, const GridPosition& position, GridPositionSide side) +static int resolveGridPositionFromStyle(const ComputedStyle& gridContainerStyle, const GridPosition& position, GridPositionSide side) { switch (position.type()) { case ExplicitPosition: { @@ -224,10 +219,6 @@ size_t resolvedPosition = abs(position.integerPosition()) - 1; size_t endOfTrack = explicitGridSizeForSide(gridContainerStyle, side); - // Per http://lists.w3.org/Archives/Public/www-style/2013Mar/0589.html, we clamp negative value to the first line. - if (endOfTrack < resolvedPosition) - return 0; - return endOfTrack - resolvedPosition; } case NamedGridAreaPosition: @@ -280,25 +271,25 @@ if (initialPosition.shouldBeResolvedAgainstOppositePosition()) { // Infer the position from the final position ('auto / 1' or 'span 2 / 3' case). - size_t finalResolvedPosition = resolveGridPositionFromStyle(gridContainerStyle, finalPosition, finalSide); + int finalResolvedPosition = resolveGridPositionFromStyle(gridContainerStyle, finalPosition, finalSide); return resolveGridPositionAgainstOppositePosition(gridContainerStyle, finalResolvedPosition, initialPosition, initialSide); } if (finalPosition.shouldBeResolvedAgainstOppositePosition()) { // Infer our position from the initial position ('1 / auto' or '3 / span 2' case). - size_t initialResolvedPosition = resolveGridPositionFromStyle(gridContainerStyle, initialPosition, initialSide); + int initialResolvedPosition = resolveGridPositionFromStyle(gridContainerStyle, initialPosition, initialSide); return resolveGridPositionAgainstOppositePosition(gridContainerStyle, initialResolvedPosition, finalPosition, finalSide); } - size_t resolvedInitialPosition = resolveGridPositionFromStyle(gridContainerStyle, initialPosition, initialSide); - size_t resolvedFinalPosition = resolveGridPositionFromStyle(gridContainerStyle, finalPosition, finalSide); + int resolvedInitialPosition = resolveGridPositionFromStyle(gridContainerStyle, initialPosition, initialSide); + int resolvedFinalPosition = resolveGridPositionFromStyle(gridContainerStyle, finalPosition, finalSide); if (resolvedFinalPosition < resolvedInitialPosition) std::swap(resolvedFinalPosition, resolvedInitialPosition); else if (resolvedFinalPosition == resolvedInitialPosition) resolvedFinalPosition = resolvedInitialPosition + 1; - return GridSpan::definiteGridSpan(resolvedInitialPosition, resolvedFinalPosition); + return GridSpan::untranslatedDefiniteGridSpan(resolvedInitialPosition, resolvedFinalPosition); } } // namespace blink
diff --git a/third_party/WebKit/Source/core/svg/SVGSVGElement.cpp b/third_party/WebKit/Source/core/svg/SVGSVGElement.cpp index aa02b54..99a5b38 100644 --- a/third_party/WebKit/Source/core/svg/SVGSVGElement.cpp +++ b/third_party/WebKit/Source/core/svg/SVGSVGElement.cpp
@@ -747,7 +747,8 @@ { SVGGraphicsElement::finishParsingChildren(); - // The outermost SVGSVGElement SVGLoad event is fired through Document::dispatchWindowLoadEvent. + // The outermost SVGSVGElement SVGLoad event is fired through + // LocalDOMWindow::dispatchWindowLoadEvent. if (isOutermostSVGSVGElement()) return;
diff --git a/third_party/WebKit/Source/core/workers/WorkerGlobalScope.cpp b/third_party/WebKit/Source/core/workers/WorkerGlobalScope.cpp index 1605bbd4..621e0af 100644 --- a/third_party/WebKit/Source/core/workers/WorkerGlobalScope.cpp +++ b/third_party/WebKit/Source/core/workers/WorkerGlobalScope.cpp
@@ -74,7 +74,7 @@ : m_url(url) , m_userAgent(userAgent) , m_v8CacheOptions(V8CacheOptionsDefault) - , m_script(WorkerScriptController::create(this, thread->isolate())) + , m_script(WorkerOrWorkletScriptController::create(this, thread->isolate())) , m_thread(thread) , m_workerInspectorController(adoptRefWillBeNoop(new WorkerInspectorController(this))) , m_closing(false)
diff --git a/third_party/WebKit/Source/core/workers/WorkerGlobalScope.h b/third_party/WebKit/Source/core/workers/WorkerGlobalScope.h index b03f823..8ac3d677 100644 --- a/third_party/WebKit/Source/core/workers/WorkerGlobalScope.h +++ b/third_party/WebKit/Source/core/workers/WorkerGlobalScope.h
@@ -28,7 +28,7 @@ #define WorkerGlobalScope_h #include "bindings/core/v8/V8CacheOptions.h" -#include "bindings/core/v8/WorkerScriptController.h" +#include "bindings/core/v8/WorkerOrWorkletScriptController.h" #include "core/CoreExport.h" #include "core/dom/ExecutionContext.h" #include "core/events/EventListener.h" @@ -83,7 +83,7 @@ String userAgent() const final; void disableEval(const String& errorMessage) final; - WorkerScriptController* script() { return m_script.get(); } + WorkerOrWorkletScriptController* script() { return m_script.get(); } virtual void didEvaluateWorkerScript(); void dispose(); @@ -186,7 +186,7 @@ mutable UseCounter::CountBits m_deprecationWarningBits; - OwnPtrWillBeMember<WorkerScriptController> m_script; + OwnPtrWillBeMember<WorkerOrWorkletScriptController> m_script; WorkerThread* m_thread; RefPtrWillBeMember<WorkerInspectorController> m_workerInspectorController;
diff --git a/third_party/WebKit/Source/core/workers/WorkerThread.cpp b/third_party/WebKit/Source/core/workers/WorkerThread.cpp index 2ec784a..d9bf313 100644 --- a/third_party/WebKit/Source/core/workers/WorkerThread.cpp +++ b/third_party/WebKit/Source/core/workers/WorkerThread.cpp
@@ -71,7 +71,7 @@ { Microtask::performCheckpoint(m_workerThread->isolate()); if (WorkerGlobalScope* globalScope = m_workerThread->workerGlobalScope()) { - if (WorkerScriptController* scriptController = globalScope->script()) + if (WorkerOrWorkletScriptController* scriptController = globalScope->script()) scriptController->rejectedPromises()->processQueue(); if (globalScope->isClosing()) { m_workerThread->workerReportingProxy().workerGlobalScopeClosed(); @@ -300,7 +300,7 @@ // Notify proxy that a new WorkerGlobalScope has been created and started. m_workerReportingProxy.workerGlobalScopeStarted(m_workerGlobalScope.get()); - WorkerScriptController* script = m_workerGlobalScope->script(); + WorkerOrWorkletScriptController* script = m_workerGlobalScope->script(); if (!script->isExecutionForbidden()) script->initializeContextIfNeeded(); }
diff --git a/third_party/WebKit/Source/core/xml/DocumentXSLT.cpp b/third_party/WebKit/Source/core/xml/DocumentXSLT.cpp index 0dda1fb..9b5126b 100644 --- a/third_party/WebKit/Source/core/xml/DocumentXSLT.cpp +++ b/third_party/WebKit/Source/core/xml/DocumentXSLT.cpp
@@ -149,6 +149,8 @@ return true; ScriptState* scriptState = ScriptState::forMainWorld(document.frame()); + if (!scriptState) + return false; RefPtrWillBeRawPtr<DOMContentLoadedListener> listener = DOMContentLoadedListener::create(scriptState, pi); document.addEventListener(EventTypeNames::DOMContentLoaded, listener, false); ASSERT(!pi->eventListenerForXSLT());
diff --git a/third_party/WebKit/Source/devtools/devtools.gypi b/third_party/WebKit/Source/devtools/devtools.gypi index 7f17451..e0d3abc 100644 --- a/third_party/WebKit/Source/devtools/devtools.gypi +++ b/third_party/WebKit/Source/devtools/devtools.gypi
@@ -622,7 +622,6 @@ ], 'devtools_sources_js_files': [ 'front_end/sources/addSourceMapURLDialog.css', - 'front_end/sources/filteredItemSelectionDialog.css', 'front_end/sources/navigatorView.css', 'front_end/sources/revisionHistory.css', 'front_end/sources/serviceWorkersSidebar.css', @@ -639,13 +638,15 @@ 'front_end/sources/EventListenerBreakpointsSidebarPane.js', 'front_end/sources/FileBasedSearchResultsPane.js', 'front_end/sources/FilePathScoreFunction.js', - 'front_end/sources/FilteredItemSelectionDialog.js', + 'front_end/sources/FilteredUISourceCodeListDelegate.js', 'front_end/sources/InplaceFormatterEditorAction.js', 'front_end/sources/JavaScriptBreakpointsSidebarPane.js', 'front_end/sources/JavaScriptCompiler.js', + 'front_end/sources/JavaScriptOutlineDialog.js', 'front_end/sources/JavaScriptSourceFrame.js', 'front_end/sources/NavigatorView.js', 'front_end/sources/ObjectEventListenersSidebarPane.js', + 'front_end/sources/OpenResourceDialog.js', 'front_end/sources/RevisionHistoryView.js', 'front_end/sources/ScopeChainSidebarPane.js', 'front_end/sources/ScriptFormatter.js', @@ -699,11 +700,13 @@ ], 'devtools_ui_lazy_js_files': [ 'front_end/ui_lazy/dataGrid.css', + 'front_end/ui_lazy/filteredListWidget.css', 'front_end/ui_lazy/flameChart.css', 'front_end/ui_lazy/overviewGrid.css', 'front_end/ui_lazy/pieChart.css', 'front_end/ui_lazy/timelineGrid.css', 'front_end/ui_lazy/DataGrid.js', + 'front_end/ui_lazy/FilteredListWidget.js', 'front_end/ui_lazy/FlameChart.js', 'front_end/ui_lazy/OverviewGrid.js', 'front_end/ui_lazy/PieChart.js', @@ -789,11 +792,6 @@ 'front_end/Images/errorWave.png', 'front_end/Images/errorWave_2x.png', 'front_end/Images/fileSystem.png', - 'front_end/Images/ic_cloud_queue_black_18dp.svg', - 'front_end/Images/ic_drive_file_black_18dp.svg', - 'front_end/Images/ic_folder_black_18dp.svg', - 'front_end/Images/ic_folder_open_black_18dp.svg', - 'front_end/Images/ic_web_asset_black_18dp.svg', 'front_end/Images/forward.png', 'front_end/Images/frame.png', 'front_end/Images/graphLabelCalloutLeft.png',
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/ic_cloud_queue_black_18dp.svg b/third_party/WebKit/Source/devtools/front_end/Images/ic_cloud_queue_black_18dp.svg deleted file mode 100644 index 24216b67..0000000 --- a/third_party/WebKit/Source/devtools/front_end/Images/ic_cloud_queue_black_18dp.svg +++ /dev/null
@@ -1,4 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" width="18px" height="18px" viewBox="0 0 48 48" fill="#000000"> - <path d="M0 0h48v48H0z" fill="none"/> - <path d="M38.71 20.07C37.35 13.19 31.28 8 24 8c-5.78 0-10.79 3.28-13.3 8.07C4.69 16.72 0 21.81 0 28c0 6.63 5.37 12 12 12h26c5.52 0 10-4.48 10-10 0-5.28-4.11-9.56-9.29-9.93zM38 36H12c-4.42 0-8-3.58-8-8s3.58-8 8-8h1.42c1.31-4.61 5.54-8 10.58-8 6.08 0 11 4.92 11 11v1h3c3.31 0 6 2.69 6 6s-2.69 6-6 6z"/> -</svg>
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/ic_drive_file_black_18dp.svg b/third_party/WebKit/Source/devtools/front_end/Images/ic_drive_file_black_18dp.svg deleted file mode 100644 index d78ae9f7d..0000000 --- a/third_party/WebKit/Source/devtools/front_end/Images/ic_drive_file_black_18dp.svg +++ /dev/null
@@ -1,4 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" width="18px" height="18px" viewBox="0 0 18 18" fill="#000000"> - <path d="M4 1c-.55 0-.99.45-.99 1L3 16c0 .55.44 1 1 1h10c.55 0 1-.45 1-1V6l-5-5H4zm6 5V2l4 4h-4z"/> - <path d="M0 0h18v18H0z" fill="none"/> -</svg>
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/ic_folder_black_18dp.svg b/third_party/WebKit/Source/devtools/front_end/Images/ic_folder_black_18dp.svg deleted file mode 100644 index ea8458ef..0000000 --- a/third_party/WebKit/Source/devtools/front_end/Images/ic_folder_black_18dp.svg +++ /dev/null
@@ -1,4 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" width="18px" height="18px" viewBox="0 0 18 18" fill="#000000"> - <path d="M0 0h18v18H0z" fill="none"/> - <path d="M10 5L8 3H3c-.55 0-1 .45-1 1v10c0 .55.45 1 1 1h12c.55 0 1-.45 1-1V6c0-.55-.45-1-1-1h-5z"/> -</svg>
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/ic_folder_open_black_18dp.svg b/third_party/WebKit/Source/devtools/front_end/Images/ic_folder_open_black_18dp.svg deleted file mode 100644 index 01f37f90..0000000 --- a/third_party/WebKit/Source/devtools/front_end/Images/ic_folder_open_black_18dp.svg +++ /dev/null
@@ -1,4 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" width="18px" height="18px" viewBox="0 0 18 18" fill="#000000"> - <path d="M0 0h18v18H0z" fill="none"/> - <path d="M15 5h-5L8 3H3c-.55 0-1 .45-1 1v10c0 .55.45 1 1 1h12c.55 0 1-.45 1-1V6c0-.55-.45-1-1-1zm-1 8H4V7h10v6z"/> -</svg>
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/ic_web_asset_black_18dp.svg b/third_party/WebKit/Source/devtools/front_end/Images/ic_web_asset_black_18dp.svg deleted file mode 100644 index fba62d1..0000000 --- a/third_party/WebKit/Source/devtools/front_end/Images/ic_web_asset_black_18dp.svg +++ /dev/null
@@ -1,4 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" width="18px" height="18px" viewBox="0 0 48 48" fill="#000000"> - <path fill="#010101" d="M38 8H10c-2.22 0-4 1.8-4 4v24c0 2.2 1.78 4 4 4h28c2.2 0 4-1.8 4-4V12c0-2.2-1.78-4-4-4zm0 28H10V16h28v20z"/> - <path fill="none" d="M0 0h48v48H0z"/> -</svg>
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/src/optimize_png.hashes b/third_party/WebKit/Source/devtools/front_end/Images/src/optimize_png.hashes index 7368460..c32546c 100644 --- a/third_party/WebKit/Source/devtools/front_end/Images/src/optimize_png.hashes +++ b/third_party/WebKit/Source/devtools/front_end/Images/src/optimize_png.hashes
@@ -2,7 +2,7 @@ "breakpointConditional.svg": "4cf90210b2af2ed84db2f60b07bcde28", "errorWave.svg": "e183fa242a22ed4784a92f6becbc2c45", "settingsListRemove.svg": "ce9e7c5c5cdaef28e6ee51d9478d5485", - "toolbarButtonGlyphs.svg": "87c9b93462ddd0f20795f49178680357", + "toolbarButtonGlyphs.svg": "f1b787b943d8b2d46d8e7f74b0a86cd5", "breakpoint.svg": "69cd92d807259c022791112809b97799", "responsiveDesign.svg": "1d6e963f88e5e448a7cff85f75a0e6b0" } \ No newline at end of file
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/src/svg2png.hashes b/third_party/WebKit/Source/devtools/front_end/Images/src/svg2png.hashes index 7368460..c32546c 100644 --- a/third_party/WebKit/Source/devtools/front_end/Images/src/svg2png.hashes +++ b/third_party/WebKit/Source/devtools/front_end/Images/src/svg2png.hashes
@@ -2,7 +2,7 @@ "breakpointConditional.svg": "4cf90210b2af2ed84db2f60b07bcde28", "errorWave.svg": "e183fa242a22ed4784a92f6becbc2c45", "settingsListRemove.svg": "ce9e7c5c5cdaef28e6ee51d9478d5485", - "toolbarButtonGlyphs.svg": "87c9b93462ddd0f20795f49178680357", + "toolbarButtonGlyphs.svg": "f1b787b943d8b2d46d8e7f74b0a86cd5", "breakpoint.svg": "69cd92d807259c022791112809b97799", "responsiveDesign.svg": "1d6e963f88e5e448a7cff85f75a0e6b0" } \ No newline at end of file
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/src/toolbarButtonGlyphs.svg b/third_party/WebKit/Source/devtools/front_end/Images/src/toolbarButtonGlyphs.svg index 4b2e613..36c48f90 100644 --- a/third_party/WebKit/Source/devtools/front_end/Images/src/toolbarButtonGlyphs.svg +++ b/third_party/WebKit/Source/devtools/front_end/Images/src/toolbarButtonGlyphs.svg
@@ -21,13 +21,13 @@ rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><sodipodi:namedview showgrid="true" id="namedview3397" - inkscape:zoom="4" - inkscape:cx="219.35293" - inkscape:cy="83.683783" - inkscape:window-width="1920" - inkscape:window-height="1122" - inkscape:window-x="0" - inkscape:window-y="25" + inkscape:zoom="6.7102273" + inkscape:cx="176" + inkscape:cy="84.292174" + inkscape:window-width="2495" + inkscape:window-height="1576" + inkscape:window-x="65" + inkscape:window-y="24" inkscape:window-maximized="1" inkscape:current-layer="svg3395" inkscape:snap-global="false" @@ -744,34 +744,7 @@ style="fill:none;stroke:#000000;stroke-width:2" /><path d="m 46,128 7,0 0,8 -7,0 0,-8 z m 9,-2 -14,0 0,12 14,0 0,-12 z" id="path3753" - inkscape:connector-curvature="0" /><rect - height="6" - width="3" - x="73" - y="129" - id="rect3755" /><rect - height="6" - width="3" - x="77" - y="129" - id="rect3757" /><rect - height="6" - width="3" - x="81" - y="129" - id="rect3759" /><rect - height="10" - rx="1" - ry="1" - width="15" - x="71" - y="127" - id="rect3761" - style="fill:none;stroke:#000000;stroke-width:2;stroke-linejoin:round" /><path - d="m 86,129 c 3,0 3,0 3,3 0,3 0,3 -3,3" - id="path3763" - inkscape:connector-curvature="0" - style="fill:none;stroke:#000000;stroke-width:2" /><path + inkscape:connector-curvature="0" /><path d="m 227.25,107 c -0.7,0 -1.25,0.5 -1.25,1.25 l 0,7.5 c 0,0.7 0.5,1.25 1.25,1.25 l 3.5,0 c 0.7,0 1.25,-0.5 1.25,-1.25 l 0,-7.5 c 0,-0.7 -0.5,-1.25 -1.25,-1.25 l -3.5,0 z m -0.25,1 4,0 0,7 -4,0 0,-7 z m 2,7.25 c 0.4,0 0.75,0.3 0.75,0.75 0,0.4 -0.3,0.75 -0.75,0.75 -0.4,0 -0.75,-0.3 -0.75,-0.75 0,-0.4 0.3,-0.75 0.75,-0.75 z" id="path3765" inkscape:connector-curvature="0" /><path @@ -817,9 +790,6 @@ d="m 169.19838,130.1487 c 0.0551,-0.1128 0.15339,-0.22 0.2313,-0.3064 0.54584,-0.6074 1.38893,-1.1974 3.00529,-1.5702 l 0,-2.1715 c -1.29309,0.2523 -2.31462,0.6686 -3.304,1.5597 -0.33248,0.3832 -0.50543,0.6247 -0.514,1.1665 -0.007,0.443 0.17732,0.8863 0.58141,1.3219 z m 6.63093,3.1292 c -1.61635,-0.024 -3.10906,-0.2558 -4.62277,-0.764 -2.69382,-0.9037 -3.02857,-2.1697 -3.17032,-2.5931 -0.0958,1.6897 0.028,2.9573 0.0346,3.0648 0.092,1.5004 1.29179,2.6742 2.15751,3.1151 1.7796,0.9067 3.66137,1.3756 5.60099,1.4151 l 0,2.4842 3.25098,-4.6483 -3.25098,-4.6486 0,2.5748 z m -0.32327,-5.2959 c 1.61636,0.01 3.45286,0.3384 5.2454,1.1131 0.73528,0.3177 1.32751,0.7904 1.80821,1.3048 0.33152,-0.1523 0.80672,-0.7308 0.74126,-1.2923 -0.16163,-1.3879 -1.62637,-2.1912 -1.88014,-2.3045 -1.7704,-0.7908 -3.9751,-1.0356 -5.91473,-1.0589 l 0,-1.7442 -2.01317,2.8787 2.01317,2.8783 0,-1.775 z m 8.42363,1.8658 c -0.0824,0.6478 -0.82676,2.0349 -3.89784,2.9138 l 0,4.5247 c 1.13145,-0.3677 2.46495,-1.2956 3.17873,-2.1988 0.2911,-0.3677 0.46906,-0.875 0.57736,-1.242 0.33216,-1.1229 0.18604,-3.3136 0.14175,-3.9977 z" id="Rotate" sketch:type="MSShapeGroup" /><path - inkscape:connector-curvature="0" - d="M 233,88.08946 V 91 h 2.91054 L 244.1944,82.71614 241.28385,79.8056 233,88.08946 z m 13.76911,-7.9387 c 0.30785,-0.30785 0.30785,-0.79294 0,-1.10079 l -1.81908,-1.81909 c -0.30785,-0.30784 -0.79295,-0.30784 -1.10078,0 l -1.52058,1.52991 2.91054,2.91054 1.5299,-1.52057 z" - id="path4" /><path style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1.99999976;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.19999981;stroke-opacity:1;stroke-dasharray:none" d="m 107,33 8,0 0,6 -8,0 z" id="path3963" @@ -1080,4 +1050,51 @@ style="opacity:0.2" inkscape:connector-curvature="0" id="path4070" - d="m 307.37415,162.12363 -7.84375,0 0,-11.625 7.84375,0 0,11.625 z" /></svg> \ No newline at end of file + d="m 307.37415,162.12363 -7.84375,0 0,-11.625 7.84375,0 0,11.625 z" /><path + style="fill:none" + inkscape:connector-curvature="0" + d="m 166,147 h 18 v 18 h -18 z" + id="path3947" /><path + inkscape:connector-curvature="0" + d="M 181.51625,154.52625 C 181.00625,151.94625 178.73,150 176,150 c -2.1675,0 -4.04625,1.23 -4.9875,3.02625 C 168.75875,153.27 167,155.17875 167,157.5 c 0,2.48625 2.01375,4.5 4.5,4.5 h 9.75 c 2.07,0 3.75,-1.68 3.75,-3.75 0,-1.98 -1.54125,-3.585 -3.48375,-3.72375 z M 181.25,160.5 h -9.75 c -1.6575,0 -3,-1.3425 -3,-3 0,-1.6575 1.3425,-3 3,-3 h 0.5325 c 0.49125,-1.72875 2.0775,-3 3.9675,-3 2.28,0 4.125,1.845 4.125,4.125 V 156 h 1.125 c 1.24125,0 2.25,1.00875 2.25,2.25 0,1.24125 -1.00875,2.25 -2.25,2.25 z" + id="path3949" /><path + style="fill:none" + inkscape:connector-curvature="0" + d="m 230,148 h 18 v 18 h -18 z" + id="path3935" /><path + inkscape:connector-curvature="0" + d="m 246,152 h -5 l -2,-2 h -5 c -0.55,0 -1,0.45 -1,1 v 10 c 0,0.55 0.45,1 1,1 h 12 c 0.55,0 1,-0.45 1,-1 v -8 c 0,-0.55 -0.45,-1 -1,-1 z m -1,8 h -10 v -6 h 10 v 6 z" + id="path3937" /><path + style="fill:#010101" + inkscape:connector-curvature="0" + d="m 278,150 h -10.5 c -0.8325,0 -1.5,0.675 -1.5,1.5 v 9 c 0,0.825 0.6675,1.5 1.5,1.5 H 278 c 0.825,0 1.5,-0.675 1.5,-1.5 v -9 c 0,-0.825 -0.6675,-1.5 -1.5,-1.5 z m 0,10.5 H 267.5 V 153 H 278 v 7.5 z" + id="path3923" /><path + style="fill:none" + inkscape:connector-curvature="0" + d="m 262.97094,147.06757 h 18 v 18 h -18 z" + id="path3925" /><g + transform="matrix(0.72907174,0,0,0.72907174,327.22683,147.61664)" + style="stroke:#000000" + id="g4074"><path + inkscape:connector-curvature="0" + d="M 7.854,6.963 6.877,7.279 6.857,8.617 6.889,8.705 7.398,9.699 6.188,10.578 5.398,9.787 5.326,9.73 4.047,9.336 l -0.604,0.83 0.77,1.094 0.078,0.053 0.996,0.504 -0.463,1.424 -1.104,-0.176 -0.092,-0.004 -1.266,0.432 0,1.027 1.266,0.434 0.092,-0.004 1.104,-0.178 0.463,1.424 -0.996,0.506 -0.078,0.051 -0.77,1.094 0.604,0.83 1.279,-0.393 0.072,-0.059 0.789,-0.791 1.211,0.879 -0.51,0.996 -0.031,0.086 0.02,1.338 0.977,0.316 0.803,-1.068 0.025,-0.09 0.172,-1.104 1.498,0 0.172,1.104 0.025,0.09 0.803,1.068 0.977,-0.316 0.02,-1.338 -0.031,-0.086 -0.51,-0.996 1.211,-0.879 0.789,0.791 0.072,0.059 1.279,0.393 0.604,-0.83 -0.771,-1.094 -0.076,-0.051 -0.996,-0.506 0.461,-1.424 1.105,0.178 0.092,0.004 1.266,-0.434 0,-1.027 -1.266,-0.432 -0.092,0.004 -1.105,0.176 -0.461,-1.424 0.996,-0.504 0.076,-0.053 0.771,-1.094 L 15.159,9.336 13.88,9.731 13.808,9.788 13.019,10.579 11.808,9.7 12.318,8.706 12.349,8.618 12.329,7.28 11.352,6.964 10.549,8.034 10.524,8.122 10.352,9.227 8.854,9.227 8.682,8.121 8.656,8.03 7.854,6.963 m 1.748,3.398 a 3.621,3.645 0 0 1 3.621,3.645 3.621,3.645 0 0 1 -3.621,3.646 3.621,3.645 0 0 1 -3.619,-3.646 3.621,3.645 0 0 1 3.619,-3.645 z" + transform="translate(0.535,1.346)" + id="path4076" /><path + style="stroke-width:0.89899999" + inkscape:connector-curvature="0" + d="M 14.885,1.563 14.178,1.957 14.365,3.24 14.396,3.279 15.14,4.04 14.553,5.03 13.529,4.736 13.479,4.729 12.262,5.172 12.25,5.98 13.455,6.459 13.506,6.453 14.537,6.189 15.1,7.191 14.332,7.932 14.301,7.971 14.08,9.248 14.771,9.662 15.787,8.859 15.807,8.811 16.1,7.787 17.242,7.803 17.502,8.834 17.52,8.883 18.514,9.715 19.219,9.32 19.03,8.04 19,7.998 18.258,7.234 18.844,6.25 19.869,6.541 19.92,6.551 21.14,6.105 21.15,5.297 19.943,4.818 19.893,4.824 18.861,5.088 18.301,4.086 19.07,3.346 19.1,3.307 19.322,2.029 18.627,1.615 17.609,2.418 17.59,2.467 17.303,3.49 16.16,3.475 15.896,2.443 15.879,2.395 14.885,1.563 z m 1.814,2.138 a 1.938,1.938 0 0 1 1.938,1.938 1.938,1.938 0 0 1 -1.938,1.937 1.938,1.938 0 0 1 -1.937,-1.937 1.938,1.938 0 0 1 1.937,-1.938 z" + id="path4078" /></g><path + style="fill:none" + inkscape:connector-curvature="0" + d="m 71,124 h 18 v 18 H 71 z" + id="path4246" /><path + inkscape:connector-curvature="0" + d="m 82,129 -2,-2 h -5 c -0.55,0 -1,0.45 -1,1 v 10 c 0,0.55 0.45,1 1,1 h 12 c 0.55,0 1,-0.45 1,-1 v -8 c 0,-0.55 -0.45,-1 -1,-1 h -5 z" + id="path4248" /><path + inkscape:connector-curvature="0" + d="m 235,76 c -0.55,0 -0.99,0.45 -0.99,1 L 234,91 c 0,0.55 0.44,1 1,1 h 10 c 0.55,0 1,-0.45 1,-1 V 81 l -5,-5 h -6 z m 6,5 v -4 l 4,4 h -4 z" + id="path4365" /><path + style="fill:none" + inkscape:connector-curvature="0" + d="m 231,75 h 18 v 18 h -18 z" + id="path4367" /></svg> \ No newline at end of file
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/toolbarButtonGlyphs.png b/third_party/WebKit/Source/devtools/front_end/Images/toolbarButtonGlyphs.png index 37ac78a..6802f4f 100644 --- a/third_party/WebKit/Source/devtools/front_end/Images/toolbarButtonGlyphs.png +++ b/third_party/WebKit/Source/devtools/front_end/Images/toolbarButtonGlyphs.png Binary files differ
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/toolbarButtonGlyphs_2x.png b/third_party/WebKit/Source/devtools/front_end/Images/toolbarButtonGlyphs_2x.png index c06f0e9..86604ad 100644 --- a/third_party/WebKit/Source/devtools/front_end/Images/toolbarButtonGlyphs_2x.png +++ b/third_party/WebKit/Source/devtools/front_end/Images/toolbarButtonGlyphs_2x.png Binary files differ
diff --git a/third_party/WebKit/Source/devtools/front_end/bindings/FileSystemWorkspaceBinding.js b/third_party/WebKit/Source/devtools/front_end/bindings/FileSystemWorkspaceBinding.js index 62b1150c..3bad7db 100644 --- a/third_party/WebKit/Source/devtools/front_end/bindings/FileSystemWorkspaceBinding.js +++ b/third_party/WebKit/Source/devtools/front_end/bindings/FileSystemWorkspaceBinding.js
@@ -42,16 +42,6 @@ this._isolatedFileSystemManager.addEventListener(WebInspector.IsolatedFileSystemManager.Events.FileSystemFilesChanged, this._fileSystemFilesChanged, this); /** @type {!Map.<string, !WebInspector.FileSystemWorkspaceBinding.FileSystem>} */ this._boundFileSystems = new Map(); - - /** @type {!Object.<number, function(!Array.<string>)>} */ - this._callbacks = {}; - /** @type {!Object.<number, !WebInspector.Progress>} */ - this._progresses = {}; - - InspectorFrontendHost.events.addEventListener(InspectorFrontendHostAPI.Events.IndexingTotalWorkCalculated, this._onIndexingTotalWorkCalculated, this); - InspectorFrontendHost.events.addEventListener(InspectorFrontendHostAPI.Events.IndexingWorked, this._onIndexingWorked, this); - InspectorFrontendHost.events.addEventListener(InspectorFrontendHostAPI.Events.IndexingDone, this._onIndexingDone, this); - InspectorFrontendHost.events.addEventListener(InspectorFrontendHostAPI.Events.SearchCompleted, this._onSearchCompleted, this); } WebInspector.FileSystemWorkspaceBinding._styleSheetExtensions = new Set(["css", "scss", "sass", "less"]); @@ -60,8 +50,6 @@ WebInspector.FileSystemWorkspaceBinding._imageExtensions = WebInspector.IsolatedFileSystem.ImageExtensions; -WebInspector.FileSystemWorkspaceBinding._lastRequestId = 0; - /** * @param {string} fileSystemPath * @return {string} @@ -146,11 +134,10 @@ { var paths = /** @type {!Array<string>} */ (event.data); for (var path of paths) { - var normalizedPath = WebInspector.IsolatedFileSystem.normalizePath(path); for (var key of this._boundFileSystems.keys()) { - if (!normalizedPath.startsWith(key)) + if (!path.startsWith(key)) continue; - this._boundFileSystems.get(key)._fileChanged(normalizedPath.substr(key.length + 1)); + this._boundFileSystems.get(key)._fileChanged(path); } } }, @@ -164,105 +151,11 @@ return projectId; }, - /** - * @return {number} - */ - _nextId: function() - { - return ++WebInspector.FileSystemWorkspaceBinding._lastRequestId; - }, - - /** - * @param {function(!Array.<string>)} callback - * @return {number} - */ - registerCallback: function(callback) - { - var requestId = this._nextId(); - this._callbacks[requestId] = callback; - return requestId; - }, - - /** - * @param {!WebInspector.Progress} progress - * @return {number} - */ - registerProgress: function(progress) - { - var requestId = this._nextId(); - this._progresses[requestId] = progress; - return requestId; - }, - - /** - * @param {!WebInspector.Event} event - */ - _onIndexingTotalWorkCalculated: function(event) - { - var requestId = /** @type {number} */ (event.data["requestId"]); - var totalWork = /** @type {number} */ (event.data["totalWork"]); - - var progress = this._progresses[requestId]; - if (!progress) - return; - progress.setTotalWork(totalWork); - }, - - /** - * @param {!WebInspector.Event} event - */ - _onIndexingWorked: function(event) - { - var requestId = /** @type {number} */ (event.data["requestId"]); - var worked = /** @type {number} */ (event.data["worked"]); - - var progress = this._progresses[requestId]; - if (!progress) - return; - progress.worked(worked); - if (progress.isCanceled()) { - InspectorFrontendHost.stopIndexing(requestId); - this._onIndexingDone(event); - } - }, - - /** - * @param {!WebInspector.Event} event - */ - _onIndexingDone: function(event) - { - var requestId = /** @type {number} */ (event.data["requestId"]); - - var progress = this._progresses[requestId]; - if (!progress) - return; - progress.done(); - delete this._progresses[requestId]; - }, - - /** - * @param {!WebInspector.Event} event - */ - _onSearchCompleted: function(event) - { - var requestId = /** @type {number} */ (event.data["requestId"]); - var files = /** @type {!Array.<string>} */ (event.data["files"]); - - var callback = this._callbacks[requestId]; - if (!callback) - return; - callback.call(null, files); - delete this._callbacks[requestId]; - }, - dispose: function() { this._isolatedFileSystemManager.removeEventListener(WebInspector.IsolatedFileSystemManager.Events.FileSystemAdded, this._fileSystemAdded, this); this._isolatedFileSystemManager.removeEventListener(WebInspector.IsolatedFileSystemManager.Events.FileSystemRemoved, this._fileSystemRemoved, this); - InspectorFrontendHost.events.removeEventListener(InspectorFrontendHostAPI.Events.IndexingTotalWorkCalculated, this._onIndexingTotalWorkCalculated, this); - InspectorFrontendHost.events.removeEventListener(InspectorFrontendHostAPI.Events.IndexingWorked, this._onIndexingWorked, this); - InspectorFrontendHost.events.removeEventListener(InspectorFrontendHostAPI.Events.IndexingDone, this._onIndexingDone, this); - InspectorFrontendHost.events.removeEventListener(InspectorFrontendHostAPI.Events.SearchCompleted, this._onSearchCompleted, this); + this._isolatedFileSystemManager.dispose(); for (var fileSystem of this._boundFileSystems.values()) { fileSystem.dispose(); this._boundFileSystems.remove(fileSystem._fileSystem.path()); @@ -461,7 +354,7 @@ return; } var query = queriesToRun.shift(); - this._searchInPath(searchConfig.isRegex() ? "" : query, progress, innerCallback.bind(this)); + this._fileSystem.searchInPath(searchConfig.isRegex() ? "" : query, progress, innerCallback.bind(this)); } /** @@ -478,47 +371,12 @@ }, /** - * @param {string} query - * @param {!WebInspector.Progress} progress - * @param {function(!Array.<string>)} callback - */ - _searchInPath: function(query, progress, callback) - { - var requestId = this._fileSystemWorkspaceBinding.registerCallback(innerCallback); - InspectorFrontendHost.searchInPath(requestId, this._fileSystem.path(), query); - - /** - * @param {!Array.<string>} files - */ - function innerCallback(files) - { - /** - * @param {string} fullPath - * @return {string} - */ - function trimAndNormalizeFileSystemPath(fullPath) - { - fullPath = "file://" + fullPath; - if (WebInspector.isWin()) - fullPath = fullPath.replace(/\\/g, "/"); - return fullPath; - } - - files = files.map(trimAndNormalizeFileSystemPath); - progress.worked(1); - callback(files); - } - }, - - /** * @override * @param {!WebInspector.Progress} progress */ indexContent: function(progress) { - progress.setTotalWork(1); - var requestId = this._fileSystemWorkspaceBinding.registerProgress(progress); - InspectorFrontendHost.indexPath(requestId, this._fileSystem.path()); + this._fileSystem.indexContent(progress); }, /** @@ -623,7 +481,7 @@ */ remove: function() { - this._fileSystemWorkspaceBinding._isolatedFileSystemManager.removeFileSystem(this._fileSystem.path()); + this._fileSystemWorkspaceBinding._isolatedFileSystemManager.removeFileSystem(this._fileSystem); }, /**
diff --git a/third_party/WebKit/Source/devtools/front_end/bindings/NetworkProject.js b/third_party/WebKit/Source/devtools/front_end/bindings/NetworkProject.js index bc8b9842..14f23eb 100644 --- a/third_party/WebKit/Source/devtools/front_end/bindings/NetworkProject.js +++ b/third_party/WebKit/Source/devtools/front_end/bindings/NetworkProject.js
@@ -79,6 +79,7 @@ target[WebInspector.NetworkProject._networkProjectSymbol] = this; target.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.ResourceAdded, this._resourceAdded, this); + target.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.FrameWillNavigate, this._frameWillNavigate, this); target.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.MainFrameNavigated, this._mainFrameNavigated, this); var debuggerModel = WebInspector.DebuggerModel.fromTarget(target); @@ -368,6 +369,20 @@ /** * @param {!WebInspector.Event} event */ + _frameWillNavigate: function(event) + { + var frame = /** @type {!WebInspector.ResourceTreeFrame} */ (event.data); + var project = this._workspaceProject(frame, false); + for (var resource of frame.resources()) + project.removeUISourceCode(resource.url); + project = this._workspaceProject(frame, true); + for (var resource of frame.resources()) + project.removeUISourceCode(resource.url); + }, + + /** + * @param {!WebInspector.Event} event + */ _mainFrameNavigated: function(event) { this._reset();
diff --git a/third_party/WebKit/Source/devtools/front_end/inspectorStyle.css b/third_party/WebKit/Source/devtools/front_end/inspectorStyle.css index 4c5d894..c069c9f 100644 --- a/third_party/WebKit/Source/devtools/front_end/inspectorStyle.css +++ b/third_party/WebKit/Source/devtools/front_end/inspectorStyle.css
@@ -554,10 +554,6 @@ bottom: 0; } -.viewport-control-gap-element { - color: transparent; -} - .drawer-toolbar { margin-right: -6px; }
diff --git a/third_party/WebKit/Source/devtools/front_end/resources/serviceWorkersView.css b/third_party/WebKit/Source/devtools/front_end/resources/serviceWorkersView.css index 132e7537..07b77be 100644 --- a/third_party/WebKit/Source/devtools/front_end/resources/serviceWorkersView.css +++ b/third_party/WebKit/Source/devtools/front_end/resources/serviceWorkersView.css
@@ -134,10 +134,12 @@ flex: 1 1 0; overflow: hidden; padding: 8px; + text-overflow: ellipsis; } .service-workers-versions-table-row-content { flex: 2 2 0; + overflow: hidden; padding: 8px; text-overflow: ellipsis; }
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/ResourceTreeModel.js b/third_party/WebKit/Source/devtools/front_end/sdk/ResourceTreeModel.js index 8d46311..acf14dda 100644 --- a/third_party/WebKit/Source/devtools/front_end/sdk/ResourceTreeModel.js +++ b/third_party/WebKit/Source/devtools/front_end/sdk/ResourceTreeModel.js
@@ -58,6 +58,7 @@ FrameNavigated: "FrameNavigated", FrameDetached: "FrameDetached", FrameResized: "FrameResized", + FrameWillNavigate: "FrameWillNavigate", MainFrameNavigated: "MainFrameNavigated", ResourceAdded: "ResourceAdded", WillLoadCachedResources: "WillLoadCachedResources", @@ -270,6 +271,9 @@ frame = this._frameAttached(framePayload.id, framePayload.parentId || ""); console.assert(frame); } + + this.dispatchEventToListeners(WebInspector.ResourceTreeModel.EventTypes.FrameWillNavigate, frame); + this._removeSecurityOrigin(frame.securityOrigin); frame._navigate(framePayload); var addedOrigin = frame.securityOrigin; @@ -736,7 +740,7 @@ if (subtitle) { if (!this._name) return subtitle; - return this._name + "( " + subtitle + " )"; + return this._name + " (" + subtitle + ")"; } return WebInspector.UIString("<iframe>"); }
diff --git a/third_party/WebKit/Source/devtools/front_end/settings/SettingsScreen.js b/third_party/WebKit/Source/devtools/front_end/settings/SettingsScreen.js index 52994eea..1898953 100644 --- a/third_party/WebKit/Source/devtools/front_end/settings/SettingsScreen.js +++ b/third_party/WebKit/Source/devtools/front_end/settings/SettingsScreen.js
@@ -362,12 +362,12 @@ */ _removeFileSystemClicked: function(fileSystem) { - WebInspector.isolatedFileSystemManager.removeFileSystem(fileSystem.path()); + WebInspector.isolatedFileSystemManager.removeFileSystem(fileSystem); }, _addFileSystemClicked: function() { - WebInspector.isolatedFileSystemManager.addFileSystem(""); + WebInspector.isolatedFileSystemManager.addFileSystem(); }, _fileSystemAdded: function(event)
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/FilePathScoreFunction.js b/third_party/WebKit/Source/devtools/front_end/sources/FilePathScoreFunction.js index 121ede0..8d026a5 100644 --- a/third_party/WebKit/Source/devtools/front_end/sources/FilePathScoreFunction.js +++ b/third_party/WebKit/Source/devtools/front_end/sources/FilePathScoreFunction.js
@@ -42,25 +42,6 @@ this._fileNameIndex = 0; } -/** - * @param {string} query - * @return {!RegExp} - */ -WebInspector.FilePathScoreFunction.filterRegex = function(query) -{ - const toEscape = String.regexSpecialCharacters(); - var regexString = ""; - for (var i = 0; i < query.length; ++i) { - var c = query.charAt(i); - if (toEscape.indexOf(c) !== -1) - c = "\\" + c; - if (i) - regexString += "[^" + c + "]*"; - regexString += c; - } - return new RegExp(regexString, "i"); -} - WebInspector.FilePathScoreFunction.prototype = { /** * @param {string} data
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/FilteredItemSelectionDialog.js b/third_party/WebKit/Source/devtools/front_end/sources/FilteredItemSelectionDialog.js deleted file mode 100644 index 5afbfc7a..0000000 --- a/third_party/WebKit/Source/devtools/front_end/sources/FilteredItemSelectionDialog.js +++ /dev/null
@@ -1,987 +0,0 @@ -/* - * Copyright (C) 2012 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @constructor - * @extends {WebInspector.VBox} - * @implements {WebInspector.ViewportControl.Provider} - * @param {!WebInspector.SelectionDialogContentProvider} delegate - * @param {boolean} renderAsTwoRows - */ -WebInspector.FilteredItemSelectionDialog = function(delegate, renderAsTwoRows) -{ - WebInspector.VBox.call(this); - - this._renderAsTwoRows = renderAsTwoRows; - - this.element.classList.add("filtered-item-list-dialog"); - this.element.addEventListener("keydown", this._onKeyDown.bind(this), false); - this.registerRequiredCSS("sources/filteredItemSelectionDialog.css"); - - this._promptElement = this.element.createChild("div", "monospace filtered-dialog-input"); - this._promptElement.setAttribute("spellcheck", "false"); - this._prompt = new WebInspector.TextPrompt(this._autocomplete.bind(this)); - this._prompt.renderAsBlock(); - this._prompt.addEventListener(WebInspector.TextPrompt.Events.ItemAccepted, this._onAutocompleted, this); - var promptProxy = this._prompt.attach(this._promptElement); - promptProxy.addEventListener("input", this._onInput.bind(this), false); - promptProxy.classList.add("filtered-dialog-prompt-element"); - - this._filteredItems = []; - this._viewportControl = new WebInspector.ViewportControl(this); - this._itemElementsContainer = this._viewportControl.element; - this._itemElementsContainer.classList.add("container"); - this._itemElementsContainer.classList.add("monospace"); - this._itemElementsContainer.addEventListener("click", this._onClick.bind(this), false); - this.element.appendChild(this._itemElementsContainer); - - this.setDefaultFocusedElement(this._promptElement); - - this._delegate = delegate; - this._delegate.setRefreshCallback(this._itemsLoaded.bind(this)); - this._itemsLoaded(); - this._updateShowMatchingItems(); - this._viewportControl.refresh(); - this._prompt.autoCompleteSoon(true); - - this._dialog = new WebInspector.Dialog(); - this._dialog.setMaxSize(new Size(504, 600)); - this.show(this._dialog.element); - this._dialog.show(); -} - -WebInspector.FilteredItemSelectionDialog.prototype = { - /** - * @return {string} - */ - _value: function() - { - return this._prompt.userEnteredText().trim(); - }, - - willHide: function() - { - this._delegate.dispose(); - if (this._filterTimer) - clearTimeout(this._filterTimer); - }, - - /** - * @param {!Event} event - */ - _onEnter: function(event) - { - if (!this._delegate.itemCount()) - return; - event.preventDefault(); - var selectedIndex = this._shouldShowMatchingItems() && this._selectedIndexInFiltered < this._filteredItems.length ? this._filteredItems[this._selectedIndexInFiltered] : null; - this._delegate.selectItemWithQuery(selectedIndex, this._value()); - this._dialog.detach(); - }, - - _itemsLoaded: function() - { - - if (this._loadTimeout) - return; - this._loadTimeout = setTimeout(this._updateAfterItemsLoaded.bind(this), 0); - }, - - _updateAfterItemsLoaded: function() - { - delete this._loadTimeout; - this._filterItems(); - }, - - /** - * @param {number} index - * @return {!Element} - */ - _createItemElement: function(index) - { - var itemElement = createElement("div"); - itemElement.className = "filtered-item-list-dialog-item " + (this._renderAsTwoRows ? "two-rows" : "one-row"); - itemElement._titleElement = itemElement.createChild("div", "filtered-item-list-dialog-title"); - itemElement._subtitleElement = itemElement.createChild("div", "filtered-item-list-dialog-subtitle"); - itemElement._subtitleElement.textContent = "\u200B"; - itemElement._index = index; - this._delegate.renderItem(index, this._value(), itemElement._titleElement, itemElement._subtitleElement); - return itemElement; - }, - - /** - * @param {string} query - */ - setQuery: function(query) - { - this._prompt.setText(query); - this._prompt.autoCompleteSoon(true); - this._scheduleFilter(); - }, - - /** - * @param {!Element} proxyElement - * @param {string} query - * @param {number} cursorOffset - * @param {!Range} wordRange - * @param {boolean} force - * @param {function(!Array.<string>, number=)} completionsReadyCallback - */ - _autocomplete: function(proxyElement, query, cursorOffset, wordRange, force, completionsReadyCallback) - { - var completions = wordRange.startOffset === 0 ? [this._delegate.autocomplete(query)] : []; - completionsReadyCallback.call(null, completions); - this._autocompletedForTests(); - }, - - _autocompletedForTests: function() - { - // Sniffed in tests. - }, - - _filterItems: function() - { - delete this._filterTimer; - if (this._scoringTimer) { - clearTimeout(this._scoringTimer); - delete this._scoringTimer; - } - - var query = this._delegate.rewriteQuery(this._value()); - this._query = query; - var filterRegex = query ? WebInspector.FilePathScoreFunction.filterRegex(query) : null; - - var oldSelectedAbsoluteIndex = this._selectedIndexInFiltered ? this._filteredItems[this._selectedIndexInFiltered] : null; - var filteredItems = []; - this._selectedIndexInFiltered = 0; - - var bestScores = []; - var bestItems = []; - var bestItemsToCollect = 100; - var minBestScore = 0; - var overflowItems = []; - - scoreItems.call(this, 0); - - /** - * @param {number} a - * @param {number} b - * @return {number} - */ - function compareIntegers(a, b) - { - return b - a; - } - - /** - * @param {number} fromIndex - * @this {WebInspector.FilteredItemSelectionDialog} - */ - function scoreItems(fromIndex) - { - var maxWorkItems = 1000; - var workDone = 0; - for (var i = fromIndex; i < this._delegate.itemCount() && workDone < maxWorkItems; ++i) { - // Filter out non-matching items quickly. - if (filterRegex && !filterRegex.test(this._delegate.itemKeyAt(i))) - continue; - - // Score item. - var score = this._delegate.itemScoreAt(i, query); - if (query) - workDone++; - - // Find its index in the scores array (earlier elements have bigger scores). - if (score > minBestScore || bestScores.length < bestItemsToCollect) { - var index = insertionIndexForObjectInListSortedByFunction(score, bestScores, compareIntegers, true); - bestScores.splice(index, 0, score); - bestItems.splice(index, 0, i); - if (bestScores.length > bestItemsToCollect) { - // Best list is too large -> drop last elements. - overflowItems.push(bestItems.peekLast()); - bestScores.length = bestItemsToCollect; - bestItems.length = bestItemsToCollect; - } - minBestScore = bestScores.peekLast(); - } else - filteredItems.push(i); - } - - // Process everything in chunks. - if (i < this._delegate.itemCount()) { - this._scoringTimer = setTimeout(scoreItems.bind(this, i), 0); - return; - } - delete this._scoringTimer; - - this._filteredItems = bestItems.concat(overflowItems).concat(filteredItems); - for (var i = 0; i < this._filteredItems.length; ++i) { - if (this._filteredItems[i] === oldSelectedAbsoluteIndex) { - this._selectedIndexInFiltered = i; - break; - } - } - this._viewportControl.invalidate(); - if (!query) - this._selectedIndexInFiltered = 0; - this._updateSelection(this._selectedIndexInFiltered, false); - } - }, - - /** - * @return {boolean} - */ - _shouldShowMatchingItems: function() - { - return this._delegate.shouldShowMatchingItems(this._value()); - }, - - _onAutocompleted: function() - { - this._prompt.autoCompleteSoon(true); - this._onInput(); - }, - - _onInput: function() - { - this._updateShowMatchingItems(); - this._scheduleFilter(); - }, - - _updateShowMatchingItems: function() - { - var shouldShowMatchingItems = this._shouldShowMatchingItems(); - this._itemElementsContainer.classList.toggle("hidden", !shouldShowMatchingItems); - }, - - /** - * @return {number} - */ - _rowsPerViewport: function() - { - return Math.floor(this._viewportControl.element.clientHeight / this._rowHeight); - }, - - _onKeyDown: function(event) - { - var newSelectedIndex = this._selectedIndexInFiltered; - - switch (event.keyCode) { - case WebInspector.KeyboardShortcut.Keys.Down.code: - if (++newSelectedIndex >= this._filteredItems.length) - newSelectedIndex = this._filteredItems.length - 1; - this._updateSelection(newSelectedIndex, true); - event.consume(true); - break; - case WebInspector.KeyboardShortcut.Keys.Up.code: - if (--newSelectedIndex < 0) - newSelectedIndex = 0; - this._updateSelection(newSelectedIndex, false); - event.consume(true); - break; - case WebInspector.KeyboardShortcut.Keys.PageDown.code: - newSelectedIndex = Math.min(newSelectedIndex + this._rowsPerViewport(), this._filteredItems.length - 1); - this._updateSelection(newSelectedIndex, true); - event.consume(true); - break; - case WebInspector.KeyboardShortcut.Keys.PageUp.code: - newSelectedIndex = Math.max(newSelectedIndex - this._rowsPerViewport(), 0); - this._updateSelection(newSelectedIndex, false); - event.consume(true); - break; - case WebInspector.KeyboardShortcut.Keys.Enter.code: - this._onEnter(event); - break; - default: - } - }, - - _scheduleFilter: function() - { - if (this._filterTimer) - return; - this._filterTimer = setTimeout(this._filterItems.bind(this), 0); - }, - - /** - * @param {number} index - * @param {boolean} makeLast - */ - _updateSelection: function(index, makeLast) - { - if (!this._filteredItems.length) - return; - if (this._selectedElement) - this._selectedElement.classList.remove("selected"); - this._viewportControl.scrollItemIntoView(index, makeLast); - this._selectedIndexInFiltered = index; - this._selectedElement = this._viewportControl.renderedElementAt(index); - if (this._selectedElement) - this._selectedElement.classList.add("selected"); - }, - - _onClick: function(event) - { - var itemElement = event.target.enclosingNodeOrSelfWithClass("filtered-item-list-dialog-item"); - if (!itemElement) - return; - this._delegate.selectItemWithQuery(itemElement._index, this._value()); - this._dialog.detach(); - }, - - /** - * @override - * @return {number} - */ - itemCount: function() - { - return this._filteredItems.length; - }, - - /** - * @override - * @param {number} index - * @return {number} - */ - fastHeight: function(index) - { - if (!this._rowHeight) { - var delegateIndex = this._filteredItems[index]; - var element = this._createItemElement(delegateIndex); - this._rowHeight = WebInspector.measurePreferredSize(element, this._viewportControl.contentElement()).height; - } - return this._rowHeight; - }, - - /** - * @override - * @param {number} index - * @return {!WebInspector.ViewportElement} - */ - itemElement: function(index) - { - var delegateIndex = this._filteredItems[index]; - var element = this._createItemElement(delegateIndex); - return new WebInspector.StaticViewportElement(element); - }, - - /** - * @override - * @return {number} - */ - minimumRowHeight: function() - { - return this.fastHeight(0); - }, - - __proto__: WebInspector.VBox.prototype -} - -/** - * @constructor - * @param {!Array<string>} promptHistory - */ -WebInspector.SelectionDialogContentProvider = function(promptHistory) -{ - this._promptHistory = promptHistory; -} - -WebInspector.SelectionDialogContentProvider.prototype = { - /** - * @param {function():void} refreshCallback - */ - setRefreshCallback: function(refreshCallback) - { - this._refreshCallback = refreshCallback; - }, - - /** - * @param {string} query - * @return {boolean} - */ - shouldShowMatchingItems: function(query) - { - return true; - }, - - /** - * @return {number} - */ - itemCount: function() - { - return 0; - }, - - /** - * @param {number} itemIndex - * @return {string} - */ - itemKeyAt: function(itemIndex) - { - return ""; - }, - - /** - * @param {number} itemIndex - * @param {string} query - * @return {number} - */ - itemScoreAt: function(itemIndex, query) - { - return 1; - }, - - /** - * @param {number} itemIndex - * @param {string} query - * @param {!Element} titleElement - * @param {!Element} subtitleElement - */ - renderItem: function(itemIndex, query, titleElement, subtitleElement) - { - }, - - /** - * @param {!Element} element - * @param {string} query - * @return {boolean} - */ - highlightRanges: function(element, query) - { - if (!query) - return false; - - /** - * @param {string} text - * @param {string} query - * @return {?Array.<!WebInspector.SourceRange>} - */ - function rangesForMatch(text, query) - { - var opcodes = WebInspector.Diff.charDiff(query, text); - var offset = 0; - var ranges = []; - for (var i = 0; i < opcodes.length; ++i) { - var opcode = opcodes[i]; - if (opcode[0] === WebInspector.Diff.Operation.Equal) - ranges.push(new WebInspector.SourceRange(offset, opcode[1].length)); - else if (opcode[0] !== WebInspector.Diff.Operation.Insert) - return null; - offset += opcode[1].length; - } - return ranges; - } - - var text = element.textContent; - var ranges = rangesForMatch(text, query); - if (!ranges) - ranges = rangesForMatch(text.toUpperCase(), query.toUpperCase()); - if (ranges) { - WebInspector.highlightRangesWithStyleClass(element, ranges, "highlight"); - return true; - } - return false; - }, - - /** - * @param {number} itemIndex - * @param {string} promptValue - */ - selectItemWithQuery: function(itemIndex, promptValue) - { - this._promptHistory.push(promptValue); - if (this._promptHistory.length > 100) - this._promptHistory.shift(); - this.selectItem(itemIndex, promptValue); - }, - - /** - * @param {number} itemIndex - * @param {string} promptValue - */ - selectItem: function(itemIndex, promptValue) - { - }, - - refresh: function() - { - this._refreshCallback(); - }, - - /** - * @param {string} query - * @return {string} - */ - rewriteQuery: function(query) - { - return query; - }, - - /** - * @param {string} query - * @return {string} - */ - autocomplete: function(query) - { - for (var i = this._promptHistory.length - 1; i >= 0; i--) { - if (this._promptHistory[i] !== query && this._promptHistory[i].startsWith(query)) - return this._promptHistory[i]; - } - return query; - }, - - dispose: function() - { - } -} - -/** - * @constructor - * @extends {WebInspector.SelectionDialogContentProvider} - * @param {!WebInspector.UISourceCode} uiSourceCode - * @param {function(number, number)} selectItemCallback - */ -WebInspector.JavaScriptOutlineDialog = function(uiSourceCode, selectItemCallback) -{ - WebInspector.SelectionDialogContentProvider.call(this, []); - - this._functionItems = []; - this._selectItemCallback = selectItemCallback; - this._outlineWorker = new WorkerRuntime.Worker("script_formatter_worker"); - this._outlineWorker.onmessage = this._didBuildOutlineChunk.bind(this); - this._outlineWorker.postMessage({ method: "javaScriptOutline", params: { content: uiSourceCode.workingCopy() } }); -} - -/** - * @param {!WebInspector.UISourceCode} uiSourceCode - * @param {function(number, number)} selectItemCallback - */ -WebInspector.JavaScriptOutlineDialog.show = function(uiSourceCode, selectItemCallback) -{ - new WebInspector.FilteredItemSelectionDialog(new WebInspector.JavaScriptOutlineDialog(uiSourceCode, selectItemCallback), false); -} - -WebInspector.JavaScriptOutlineDialog.prototype = { - /** - * @param {!MessageEvent} event - */ - _didBuildOutlineChunk: function(event) - { - var data = /** @type {!WebInspector.JavaScriptOutlineDialog.MessageEventData} */ (event.data); - var chunk = data.chunk; - for (var i = 0; i < chunk.length; ++i) - this._functionItems.push(chunk[i]); - - if (data.isLastChunk) - this.dispose(); - - this.refresh(); - }, - - /** - * @override - * @return {number} - */ - itemCount: function() - { - return this._functionItems.length; - }, - - /** - * @override - * @param {number} itemIndex - * @return {string} - */ - itemKeyAt: function(itemIndex) - { - var item = this._functionItems[itemIndex]; - return item.name + (item.arguments ? item.arguments : ""); - }, - - /** - * @override - * @param {number} itemIndex - * @param {string} query - * @return {number} - */ - itemScoreAt: function(itemIndex, query) - { - var item = this._functionItems[itemIndex]; - return -item.line; - }, - - /** - * @override - * @param {number} itemIndex - * @param {string} query - * @param {!Element} titleElement - * @param {!Element} subtitleElement - */ - renderItem: function(itemIndex, query, titleElement, subtitleElement) - { - var item = this._functionItems[itemIndex]; - titleElement.textContent = item.name + (item.arguments ? item.arguments : ""); - this.highlightRanges(titleElement, query); - subtitleElement.textContent = ":" + (item.line + 1); - }, - - /** - * @override - * @param {?number} itemIndex - * @param {string} promptValue - */ - selectItem: function(itemIndex, promptValue) - { - if (itemIndex === null) - return; - var lineNumber = this._functionItems[itemIndex].line; - if (!isNaN(lineNumber) && lineNumber >= 0) - this._selectItemCallback(lineNumber, this._functionItems[itemIndex].column); - }, - - dispose: function() - { - if (this._outlineWorker) { - this._outlineWorker.terminate(); - delete this._outlineWorker; - } - }, - - __proto__: WebInspector.SelectionDialogContentProvider.prototype -} - -/** - * @constructor - * @extends {WebInspector.SelectionDialogContentProvider} - * @param {!Map.<!WebInspector.UISourceCode, number>=} defaultScores - * @param {!Array<string>=} history - */ -WebInspector.SelectUISourceCodeDialog = function(defaultScores, history) -{ - WebInspector.SelectionDialogContentProvider.call(this, history || []); - - this._populate(); - this._defaultScores = defaultScores; - this._scorer = new WebInspector.FilePathScoreFunction(""); - WebInspector.workspace.addEventListener(WebInspector.Workspace.Events.UISourceCodeAdded, this._uiSourceCodeAdded, this); - WebInspector.workspace.addEventListener(WebInspector.Workspace.Events.ProjectRemoved, this._projectRemoved, this); -} - -WebInspector.SelectUISourceCodeDialog.prototype = { - _projectRemoved: function(event) - { - var project = /** @type {!WebInspector.Project} */ (event.data); - this._populate(project); - this.refresh(); - }, - - /** - * @param {!WebInspector.Project=} skipProject - */ - _populate: function(skipProject) - { - /** @type {!Array.<!WebInspector.UISourceCode>} */ - this._uiSourceCodes = []; - var projects = WebInspector.workspace.projects().filter(this.filterProject.bind(this)); - for (var i = 0; i < projects.length; ++i) { - if (skipProject && projects[i] === skipProject) - continue; - this._uiSourceCodes = this._uiSourceCodes.concat(projects[i].uiSourceCodes()); - } - }, - - /** - * @param {?WebInspector.UISourceCode} uiSourceCode - * @param {number=} lineNumber - * @param {number=} columnNumber - */ - uiSourceCodeSelected: function(uiSourceCode, lineNumber, columnNumber) - { - // Overridden by subclasses - }, - - /** - * @param {!WebInspector.Project} project - * @return {boolean} - */ - filterProject: function(project) - { - return true; - // Overridden by subclasses - }, - - /** - * @override - * @return {number} - */ - itemCount: function() - { - return this._uiSourceCodes.length; - }, - - /** - * @override - * @param {number} itemIndex - * @return {string} - */ - itemKeyAt: function(itemIndex) - { - return this._uiSourceCodes[itemIndex].fullDisplayName(); - }, - - /** - * @override - * @param {number} itemIndex - * @param {string} query - * @return {number} - */ - itemScoreAt: function(itemIndex, query) - { - var uiSourceCode = this._uiSourceCodes[itemIndex]; - var score = this._defaultScores ? (this._defaultScores.get(uiSourceCode) || 0) : 0; - if (!query || query.length < 2) - return score; - - if (this._query !== query) { - this._query = query; - this._scorer = new WebInspector.FilePathScoreFunction(query); - } - - var path = uiSourceCode.fullDisplayName(); - return score + 10 * this._scorer.score(path, null); - }, - - /** - * @override - * @param {number} itemIndex - * @param {string} query - * @param {!Element} titleElement - * @param {!Element} subtitleElement - */ - renderItem: function(itemIndex, query, titleElement, subtitleElement) - { - query = this.rewriteQuery(query); - var uiSourceCode = this._uiSourceCodes[itemIndex]; - var fullDisplayName = uiSourceCode.fullDisplayName(); - var indexes = []; - var score = new WebInspector.FilePathScoreFunction(query).score(fullDisplayName, indexes); - var fileNameIndex = fullDisplayName.lastIndexOf("/"); - - titleElement.textContent = uiSourceCode.displayName() + (this._queryLineNumberAndColumnNumber || ""); - subtitleElement.textContent = fullDisplayName.trimEnd(100); - subtitleElement.title = fullDisplayName; - var ranges = []; - for (var i = 0; i < indexes.length; ++i) - ranges.push({offset: indexes[i], length: 1}); - - if (indexes[0] > fileNameIndex) { - for (var i = 0; i < ranges.length; ++i) - ranges[i].offset -= fileNameIndex + 1; - WebInspector.highlightRangesWithStyleClass(titleElement, ranges, "highlight"); - } else { - WebInspector.highlightRangesWithStyleClass(subtitleElement, ranges, "highlight"); - } - }, - - /** - * @override - * @param {?number} itemIndex - * @param {string} promptValue - */ - selectItem: function(itemIndex, promptValue) - { - var parsedExpression = promptValue.trim().match(/^([^:]*)(:\d+)?(:\d+)?$/); - if (!parsedExpression) - return; - - var lineNumber; - var columnNumber; - if (parsedExpression[2]) - lineNumber = parseInt(parsedExpression[2].substr(1), 10) - 1; - if (parsedExpression[3]) - columnNumber = parseInt(parsedExpression[3].substr(1), 10) - 1; - var uiSourceCode = itemIndex !== null ? this._uiSourceCodes[itemIndex] : null; - this.uiSourceCodeSelected(uiSourceCode, lineNumber, columnNumber); - }, - - /** - * @override - * @param {string} query - * @return {string} - */ - rewriteQuery: function(query) - { - if (!query) - return query; - query = query.trim(); - var lineNumberMatch = query.match(/^([^:]+)((?::[^:]*){0,2})$/); - this._queryLineNumberAndColumnNumber = lineNumberMatch ? lineNumberMatch[2] : ""; - return lineNumberMatch ? lineNumberMatch[1] : query; - }, - - /** - * @param {!WebInspector.Event} event - */ - _uiSourceCodeAdded: function(event) - { - var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.data); - if (!this.filterProject(uiSourceCode.project())) - return; - this._uiSourceCodes.push(uiSourceCode); - this.refresh(); - }, - - dispose: function() - { - WebInspector.workspace.removeEventListener(WebInspector.Workspace.Events.UISourceCodeAdded, this._uiSourceCodeAdded, this); - WebInspector.workspace.removeEventListener(WebInspector.Workspace.Events.ProjectRemoved, this._projectRemoved, this); - }, - - __proto__: WebInspector.SelectionDialogContentProvider.prototype -} - -/** - * @constructor - * @extends {WebInspector.SelectUISourceCodeDialog} - * @param {!WebInspector.SourcesView} sourcesView - * @param {!Map.<!WebInspector.UISourceCode, number>} defaultScores - * @param {!Array<string>} history - */ -WebInspector.OpenResourceDialog = function(sourcesView, defaultScores, history) -{ - WebInspector.SelectUISourceCodeDialog.call(this, defaultScores, history); - this._sourcesView = sourcesView; -} - -WebInspector.OpenResourceDialog.prototype = { - - /** - * @override - * @param {?WebInspector.UISourceCode} uiSourceCode - * @param {number=} lineNumber - * @param {number=} columnNumber - */ - uiSourceCodeSelected: function(uiSourceCode, lineNumber, columnNumber) - { - if (!uiSourceCode) - uiSourceCode = this._sourcesView.currentUISourceCode(); - if (!uiSourceCode) - return; - this._sourcesView.showSourceLocation(uiSourceCode, lineNumber, columnNumber); - }, - - /** - * @override - * @param {string} query - * @return {boolean} - */ - shouldShowMatchingItems: function(query) - { - return !query.startsWith(":"); - }, - - /** - * @override - * @param {!WebInspector.Project} project - * @return {boolean} - */ - filterProject: function(project) - { - return !WebInspector.Project.isServiceProject(project); - }, - - __proto__: WebInspector.SelectUISourceCodeDialog.prototype -} - -/** - * @param {!WebInspector.SourcesView} sourcesView - * @param {string} query - * @param {!Map.<!WebInspector.UISourceCode, number>} defaultScores - * @param {!Array<string>} history - */ -WebInspector.OpenResourceDialog.show = function(sourcesView, query, defaultScores, history) -{ - var filteredItemSelectionDialog = new WebInspector.FilteredItemSelectionDialog(new WebInspector.OpenResourceDialog(sourcesView, defaultScores, history), true); - filteredItemSelectionDialog.setQuery(query); -} - -/** - * @constructor - * @extends {WebInspector.SelectUISourceCodeDialog} - * @param {!Array.<string>} types - * @param {function(?WebInspector.UISourceCode)} callback - */ -WebInspector.SelectUISourceCodeForProjectTypesDialog = function(types, callback) -{ - this._types = types; - WebInspector.SelectUISourceCodeDialog.call(this); - this._callback = callback; -} - -WebInspector.SelectUISourceCodeForProjectTypesDialog.prototype = { - /** - * @override - * @param {?WebInspector.UISourceCode} uiSourceCode - * @param {number=} lineNumber - * @param {number=} columnNumber - */ - uiSourceCodeSelected: function(uiSourceCode, lineNumber, columnNumber) - { - this._callback(uiSourceCode); - }, - - /** - * @override - * @param {!WebInspector.Project} project - * @return {boolean} - */ - filterProject: function(project) - { - return this._types.indexOf(project.type()) !== -1; - }, - - __proto__: WebInspector.SelectUISourceCodeDialog.prototype -} - -/** - * @param {string} name - * @param {!Array.<string>} types - * @param {function(?WebInspector.UISourceCode)} callback - */ -WebInspector.SelectUISourceCodeForProjectTypesDialog.show = function(name, types, callback) -{ - var filteredItemSelectionDialog = new WebInspector.FilteredItemSelectionDialog(new WebInspector.SelectUISourceCodeForProjectTypesDialog(types, callback), true); - filteredItemSelectionDialog.setQuery(name); -} - -/** - * @typedef {{isLastChunk: boolean, chunk: !Array.<!{selectorText: string, lineNumber: number, columnNumber: number}>}} - */ -WebInspector.JavaScriptOutlineDialog.MessageEventData;
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/FilteredUISourceCodeListDelegate.js b/third_party/WebKit/Source/devtools/front_end/sources/FilteredUISourceCodeListDelegate.js new file mode 100644 index 0000000..11df86ef --- /dev/null +++ b/third_party/WebKit/Source/devtools/front_end/sources/FilteredUISourceCodeListDelegate.js
@@ -0,0 +1,195 @@ +/* + * 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. + */ + +/** + * @constructor + * @extends {WebInspector.FilteredListWidget.Delegate} + * @param {!Map.<!WebInspector.UISourceCode, number>=} defaultScores + * @param {!Array<string>=} history + */ +WebInspector.FilteredUISourceCodeListDelegate = function(defaultScores, history) +{ + WebInspector.FilteredListWidget.Delegate.call(this, history || []); + + this._populate(); + this._defaultScores = defaultScores; + this._scorer = new WebInspector.FilePathScoreFunction(""); + WebInspector.workspace.addEventListener(WebInspector.Workspace.Events.UISourceCodeAdded, this._uiSourceCodeAdded, this); + WebInspector.workspace.addEventListener(WebInspector.Workspace.Events.ProjectRemoved, this._projectRemoved, this); +} + +WebInspector.FilteredUISourceCodeListDelegate.prototype = { + _projectRemoved: function(event) + { + var project = /** @type {!WebInspector.Project} */ (event.data); + this._populate(project); + this.refresh(); + }, + + /** + * @param {!WebInspector.Project=} skipProject + */ + _populate: function(skipProject) + { + /** @type {!Array.<!WebInspector.UISourceCode>} */ + this._uiSourceCodes = []; + var projects = WebInspector.workspace.projects().filter(this.filterProject.bind(this)); + for (var i = 0; i < projects.length; ++i) { + if (skipProject && projects[i] === skipProject) + continue; + this._uiSourceCodes = this._uiSourceCodes.concat(projects[i].uiSourceCodes()); + } + }, + + /** + * @param {?WebInspector.UISourceCode} uiSourceCode + * @param {number=} lineNumber + * @param {number=} columnNumber + */ + uiSourceCodeSelected: function(uiSourceCode, lineNumber, columnNumber) + { + // Overridden by subclasses + }, + + /** + * @param {!WebInspector.Project} project + * @return {boolean} + */ + filterProject: function(project) + { + return true; + // Overridden by subclasses + }, + + /** + * @override + * @return {number} + */ + itemCount: function() + { + return this._uiSourceCodes.length; + }, + + /** + * @override + * @param {number} itemIndex + * @return {string} + */ + itemKeyAt: function(itemIndex) + { + return this._uiSourceCodes[itemIndex].fullDisplayName(); + }, + + /** + * @override + * @param {number} itemIndex + * @param {string} query + * @return {number} + */ + itemScoreAt: function(itemIndex, query) + { + var uiSourceCode = this._uiSourceCodes[itemIndex]; + var score = this._defaultScores ? (this._defaultScores.get(uiSourceCode) || 0) : 0; + if (!query || query.length < 2) + return score; + + if (this._query !== query) { + this._query = query; + this._scorer = new WebInspector.FilePathScoreFunction(query); + } + + var path = uiSourceCode.fullDisplayName(); + return score + 10 * this._scorer.score(path, null); + }, + + /** + * @override + * @param {number} itemIndex + * @param {string} query + * @param {!Element} titleElement + * @param {!Element} subtitleElement + */ + renderItem: function(itemIndex, query, titleElement, subtitleElement) + { + query = this.rewriteQuery(query); + var uiSourceCode = this._uiSourceCodes[itemIndex]; + var fullDisplayName = uiSourceCode.fullDisplayName(); + var indexes = []; + var score = new WebInspector.FilePathScoreFunction(query).score(fullDisplayName, indexes); + var fileNameIndex = fullDisplayName.lastIndexOf("/"); + + titleElement.textContent = uiSourceCode.displayName() + (this._queryLineNumberAndColumnNumber || ""); + subtitleElement.textContent = fullDisplayName.trimEnd(100); + subtitleElement.title = fullDisplayName; + var ranges = []; + for (var i = 0; i < indexes.length; ++i) + ranges.push({offset: indexes[i], length: 1}); + + if (indexes[0] > fileNameIndex) { + for (var i = 0; i < ranges.length; ++i) + ranges[i].offset -= fileNameIndex + 1; + WebInspector.highlightRangesWithStyleClass(titleElement, ranges, "highlight"); + } else { + WebInspector.highlightRangesWithStyleClass(subtitleElement, ranges, "highlight"); + } + }, + + /** + * @override + * @param {?number} itemIndex + * @param {string} promptValue + */ + selectItem: function(itemIndex, promptValue) + { + var parsedExpression = promptValue.trim().match(/^([^:]*)(:\d+)?(:\d+)?$/); + if (!parsedExpression) + return; + + var lineNumber; + var columnNumber; + if (parsedExpression[2]) + lineNumber = parseInt(parsedExpression[2].substr(1), 10) - 1; + if (parsedExpression[3]) + columnNumber = parseInt(parsedExpression[3].substr(1), 10) - 1; + var uiSourceCode = itemIndex !== null ? this._uiSourceCodes[itemIndex] : null; + this.uiSourceCodeSelected(uiSourceCode, lineNumber, columnNumber); + }, + + /** + * @override + * @param {string} query + * @return {string} + */ + rewriteQuery: function(query) + { + if (!query) + return query; + query = query.trim(); + var lineNumberMatch = query.match(/^([^:]+)((?::[^:]*){0,2})$/); + this._queryLineNumberAndColumnNumber = lineNumberMatch ? lineNumberMatch[2] : ""; + return lineNumberMatch ? lineNumberMatch[1] : query; + }, + + /** + * @param {!WebInspector.Event} event + */ + _uiSourceCodeAdded: function(event) + { + var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.data); + if (!this.filterProject(uiSourceCode.project())) + return; + this._uiSourceCodes.push(uiSourceCode); + this.refresh(); + }, + + dispose: function() + { + WebInspector.workspace.removeEventListener(WebInspector.Workspace.Events.UISourceCodeAdded, this._uiSourceCodeAdded, this); + WebInspector.workspace.removeEventListener(WebInspector.Workspace.Events.ProjectRemoved, this._projectRemoved, this); + }, + + __proto__: WebInspector.FilteredListWidget.Delegate.prototype +}
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/JavaScriptOutlineDialog.js b/third_party/WebKit/Source/devtools/front_end/sources/JavaScriptOutlineDialog.js new file mode 100644 index 0000000..0fc53ce --- /dev/null +++ b/third_party/WebKit/Source/devtools/front_end/sources/JavaScriptOutlineDialog.js
@@ -0,0 +1,125 @@ +/* + * 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. + */ + +/** + * @constructor + * @extends {WebInspector.FilteredListWidget.Delegate} + * @param {!WebInspector.UISourceCode} uiSourceCode + * @param {function(number, number)} selectItemCallback + */ +WebInspector.JavaScriptOutlineDialog = function(uiSourceCode, selectItemCallback) +{ + WebInspector.FilteredListWidget.Delegate.call(this, []); + + this._functionItems = []; + this._selectItemCallback = selectItemCallback; + this._outlineWorker = new WorkerRuntime.Worker("script_formatter_worker"); + this._outlineWorker.onmessage = this._didBuildOutlineChunk.bind(this); + this._outlineWorker.postMessage({ method: "javaScriptOutline", params: { content: uiSourceCode.workingCopy() } }); +} + +/** + * @param {!WebInspector.UISourceCode} uiSourceCode + * @param {function(number, number)} selectItemCallback + */ +WebInspector.JavaScriptOutlineDialog.show = function(uiSourceCode, selectItemCallback) +{ + new WebInspector.FilteredListWidget(new WebInspector.JavaScriptOutlineDialog(uiSourceCode, selectItemCallback), false).showAsDialog(); +} + +WebInspector.JavaScriptOutlineDialog.prototype = { + /** + * @param {!MessageEvent} event + */ + _didBuildOutlineChunk: function(event) + { + var data = /** @type {!WebInspector.JavaScriptOutlineDialog.MessageEventData} */ (event.data); + var chunk = data.chunk; + for (var i = 0; i < chunk.length; ++i) + this._functionItems.push(chunk[i]); + + if (data.isLastChunk) + this.dispose(); + + this.refresh(); + }, + + /** + * @override + * @return {number} + */ + itemCount: function() + { + return this._functionItems.length; + }, + + /** + * @override + * @param {number} itemIndex + * @return {string} + */ + itemKeyAt: function(itemIndex) + { + var item = this._functionItems[itemIndex]; + return item.name + (item.arguments ? item.arguments : ""); + }, + + /** + * @override + * @param {number} itemIndex + * @param {string} query + * @return {number} + */ + itemScoreAt: function(itemIndex, query) + { + var item = this._functionItems[itemIndex]; + return -item.line; + }, + + /** + * @override + * @param {number} itemIndex + * @param {string} query + * @param {!Element} titleElement + * @param {!Element} subtitleElement + */ + renderItem: function(itemIndex, query, titleElement, subtitleElement) + { + var item = this._functionItems[itemIndex]; + titleElement.textContent = item.name + (item.arguments ? item.arguments : ""); + this.highlightRanges(titleElement, query); + subtitleElement.textContent = ":" + (item.line + 1); + }, + + /** + * @override + * @param {?number} itemIndex + * @param {string} promptValue + */ + selectItem: function(itemIndex, promptValue) + { + if (itemIndex === null) + return; + var lineNumber = this._functionItems[itemIndex].line; + if (!isNaN(lineNumber) && lineNumber >= 0) + this._selectItemCallback(lineNumber, this._functionItems[itemIndex].column); + }, + + dispose: function() + { + if (this._outlineWorker) { + this._outlineWorker.terminate(); + delete this._outlineWorker; + } + }, + + __proto__: WebInspector.FilteredListWidget.Delegate.prototype +} + +/** + * @typedef {{isLastChunk: boolean, chunk: !Array.<!{selectorText: string, lineNumber: number, columnNumber: number}>}} + */ +WebInspector.JavaScriptOutlineDialog.MessageEventData;
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/NavigatorView.js b/third_party/WebKit/Source/devtools/front_end/sources/NavigatorView.js index ef57dd3..eedc0ef8 100644 --- a/third_party/WebKit/Source/devtools/front_end/sources/NavigatorView.js +++ b/third_party/WebKit/Source/devtools/front_end/sources/NavigatorView.js
@@ -29,12 +29,12 @@ /** * @constructor * @extends {WebInspector.VBox} + * @implements {WebInspector.TargetManager.Observer} */ WebInspector.NavigatorView = function() { WebInspector.VBox.call(this); - var scriptsOutlineElement = this.element.createChild("div", "navigator"); this._scriptsTree = new TreeOutlineInShadow(); this._scriptsTree.registerRequiredCSS("sources/navigatorView.css"); this._scriptsTree.setComparator(WebInspector.NavigatorView._treeElementsCompare); @@ -54,11 +54,17 @@ this.element.addEventListener("contextmenu", this.handleContextMenu.bind(this), false); - this._navigatorGroupingSetting = WebInspector.moduleSetting("navigatorGrouping"); - this._navigatorGroupingSetting.addChangeListener(this._groupingChanged.bind(this)); + this._navigatorGroupingByFrameSetting = WebInspector.moduleSetting("navigatorGroupByFrame"); + this._navigatorGroupingByFrameSetting.addChangeListener(this._groupingChanged.bind(this)); + this._navigatorGroupingByDomainSetting = WebInspector.moduleSetting("navigatorGroupByDomain"); + this._navigatorGroupingByDomainSetting.addChangeListener(this._groupingChanged.bind(this)); + this._navigatorGroupingByFolderSetting = WebInspector.moduleSetting("navigatorGroupByFolder"); + this._navigatorGroupingByFolderSetting.addChangeListener(this._groupingChanged.bind(this)); + this._initGrouping(); WebInspector.targetManager.addModelListener(WebInspector.ResourceTreeModel, WebInspector.ResourceTreeModel.EventTypes.FrameNavigated, this._frameNavigated, this); WebInspector.targetManager.addModelListener(WebInspector.ResourceTreeModel, WebInspector.ResourceTreeModel.EventTypes.FrameDetached, this._frameDetached, this); + WebInspector.targetManager.observeTargets(this); } WebInspector.NavigatorView.Events = { @@ -126,7 +132,7 @@ { function addFolder() { - WebInspector.isolatedFileSystemManager.addFileSystem(""); + WebInspector.isolatedFileSystemManager.addFileSystem(); } var addFolderLabel = WebInspector.UIString.capitalize("Add ^folder to ^workspace"); @@ -134,6 +140,9 @@ } WebInspector.NavigatorView.prototype = { + /** + * @param {!WebInspector.Workspace} workspace + */ setWorkspace: function(workspace) { this._workspace = workspace; @@ -161,21 +170,47 @@ /** * @param {!WebInspector.UISourceCode} uiSourceCode + * @return {?WebInspector.ResourceTreeFrame} + */ + _uiSourceCodeFrame: function(uiSourceCode) + { + var target = WebInspector.NetworkProject.targetForProject(uiSourceCode.project()); + if (!target) + return null; + return WebInspector.NetworkProject.frameForProject(uiSourceCode.project()) || target.resourceTreeModel.mainFrame; + }, + + /** + * @param {!WebInspector.UISourceCode} uiSourceCode */ _addUISourceCode: function(uiSourceCode) { if (!this.accept(uiSourceCode)) return; + var isFromSourceMap = uiSourceCode.contentType().isFromSourceMap(); var path; if (uiSourceCode.project().type() === WebInspector.projectTypes.FileSystem) path = WebInspector.FileSystemWorkspaceBinding.relativePath(uiSourceCode).slice(0, -1); else path = WebInspector.ParsedURL.splitURLIntoPathComponents(uiSourceCode.path()).slice(1, -1); - var folderNode = this._folderNode(uiSourceCode.project(), uiSourceCode.host(), path, isFromSourceMap); + + var project = uiSourceCode.project(); + var target = WebInspector.NetworkProject.targetForUISourceCode(uiSourceCode); + var frame = this._uiSourceCodeFrame(uiSourceCode); + + var folderNode = this._folderNode(uiSourceCode, project, target, frame, uiSourceCode.host(), path, isFromSourceMap); var uiSourceCodeNode = new WebInspector.NavigatorUISourceCodeTreeNode(this, uiSourceCode); this._uiSourceCodeNodes.set(uiSourceCode, uiSourceCodeNode); folderNode.appendChild(uiSourceCodeNode); + this.uiSourceCodeAdded(uiSourceCode); + }, + + /** + * @param {!WebInspector.UISourceCode} uiSourceCode + */ + uiSourceCodeAdded: function(uiSourceCode) + { }, /** @@ -214,29 +249,47 @@ /** * @param {!WebInspector.Project} project + * @param {?WebInspector.Target} target + * @param {?WebInspector.ResourceTreeFrame} frame + * @param {string} projectHost + * @param {string} path + * @return {string} + */ + _folderNodeId: function(project, target, frame, projectHost, path) + { + var targetId = target ? target.id() : ""; + var projectId = project.type() === WebInspector.projectTypes.FileSystem ? project.id() : ""; + var frameId = this._groupByFrame && frame ? frame.id : ""; + return targetId + ":" + projectId + ":" + frameId + ":" + projectHost + ":" + path; + }, + + /** + * @param {!WebInspector.UISourceCode} uiSourceCode + * @param {!WebInspector.Project} project + * @param {?WebInspector.Target} target + * @param {?WebInspector.ResourceTreeFrame} frame * @param {string} projectHost * @param {!Array<string>} path * @param {boolean} fromSourceMap * @return {!WebInspector.NavigatorTreeNode} */ - _folderNode: function(project, projectHost, path, fromSourceMap) + _folderNode: function(uiSourceCode, project, target, frame, projectHost, path, fromSourceMap) { if (project.type() === WebInspector.projectTypes.Snippets) return this._rootNode; - var target = WebInspector.NetworkProject.targetForProject(project); if (target && !this._groupByFolder && !fromSourceMap) - return this._domainNode(target, project, projectHost); + return this._domainNode(uiSourceCode, project, target, frame, projectHost); var folderPath = path.join("/"); - var folderId = project.id() + ":" + projectHost + ":" + folderPath; + var folderId = this._folderNodeId(project, target, frame, projectHost, folderPath); var folderNode = this._subfolderNodes.get(folderId); if (folderNode) return folderNode; if (!path.length) { if (target) - return this._domainNode(target, project, projectHost); + return this._domainNode(uiSourceCode, project, target, frame, projectHost); var fileSystemNode = this._rootNode.child(project.id()); if (!fileSystemNode) { fileSystemNode = new WebInspector.NavigatorGroupTreeNode(this, project, project.id(), WebInspector.NavigatorView.Types.FileSystem, project.displayName()); @@ -245,7 +298,7 @@ return fileSystemNode; } - var parentNode = this._folderNode(project, projectHost, path.slice(0, -1), fromSourceMap); + var parentNode = this._folderNode(uiSourceCode, project, target, frame, projectHost, path.slice(0, -1), fromSourceMap); var type = fromSourceMap ? WebInspector.NavigatorView.Types.SourceMapFolder : WebInspector.NavigatorView.Types.NetworkFolder; if (project.type() === WebInspector.projectTypes.FileSystem) type = WebInspector.NavigatorView.Types.FileSystemFolder; @@ -257,16 +310,17 @@ return folderNode; }, - /** - * @param {!WebInspector.Target} target + /** + * @param {!WebInspector.UISourceCode} uiSourceCode * @param {!WebInspector.Project} project + * @param {!WebInspector.Target} target + * @param {?WebInspector.ResourceTreeFrame} frame * @param {string} projectHost * @return {!WebInspector.NavigatorTreeNode} */ - _domainNode: function(target, project, projectHost) + _domainNode: function(uiSourceCode, project, target, frame, projectHost) { - var frame = WebInspector.NetworkProject.frameForProject(project); - var frameNode = this._frameNode(target, frame, project); + var frameNode = this._frameNode(project, target, frame); if (!this._groupByDomain) return frameNode; var domainNode = frameNode.child(projectHost); @@ -280,35 +334,35 @@ return domainNode; }, - /** + /** + * @param {!WebInspector.Project} project * @param {!WebInspector.Target} target * @param {?WebInspector.ResourceTreeFrame} frame - * @param {!WebInspector.Project} project * @return {!WebInspector.NavigatorTreeNode} */ - _frameNode: function(target, frame, project) + _frameNode: function(project, target, frame) { if (!this._groupByFrame || !frame) - return this._targetNode(target, project); + return this._targetNode(project, target); var frameNode = this._frameNodes.get(frame); if (frameNode) return frameNode; - frameNode = new WebInspector.NavigatorGroupTreeNode(this, project, project.id() + ":" + frame.id, WebInspector.NavigatorView.Types.Frame, frame.displayName()); + frameNode = new WebInspector.NavigatorGroupTreeNode(this, project, target.id() + ":" + frame.id, WebInspector.NavigatorView.Types.Frame, frame.displayName()); this._frameNodes.set(frame, frameNode); - this._frameNode(target, frame.parentFrame, project).appendChild(frameNode); + this._frameNode(project, target, frame.parentFrame).appendChild(frameNode); if (!frame.parentFrame) frameNode.treeNode()._boostOrder = true; return frameNode; }, - /** - * @param {!WebInspector.Target} target + /** * @param {!WebInspector.Project} project + * @param {!WebInspector.Target} target * @return {!WebInspector.NavigatorTreeNode} */ - _targetNode: function(target, project) + _targetNode: function(project, target) { if (target === WebInspector.targetManager.mainTarget()) return this._rootNode; @@ -384,16 +438,22 @@ if (!node) return; + var project = uiSourceCode.project(); + var target = WebInspector.NetworkProject.targetForUISourceCode(uiSourceCode); + var frame = this._uiSourceCodeFrame(uiSourceCode); + var parentNode = node.parent; - this._uiSourceCodeNodes.remove(uiSourceCode); + this._uiSourceCodeNodes.delete(uiSourceCode); parentNode.removeChild(node); node = parentNode; while (node) { parentNode = node.parent; - if (!parentNode || !node.isEmpty()) + if (!parentNode || !node.isEmpty() || !(node instanceof WebInspector.NavigatorFolderTreeNode)) break; - this._subfolderNodes.remove(uiSourceCode.project().id() + ":" + uiSourceCode.host() + ":" + node._folderPath); + + var folderId = this._folderNodeId(project, target, frame, uiSourceCode.host(), node._folderPath); + this._subfolderNodes.delete(folderId); parentNode.removeChild(node); node = parentNode; } @@ -614,10 +674,9 @@ _initGrouping: function() { - var value = this._navigatorGroupingSetting.get(); - this._groupByFrame = value.includes("frame"); - this._groupByDomain = value.includes("domain"); - this._groupByFolder = value.includes("folder"); + this._groupByFrame = this._navigatorGroupingByFrameSetting.get(); + this._groupByDomain = this._navigatorGroupingByDomainSetting.get(); + this._groupByFolder = this._groupByDomain && this._navigatorGroupingByFolderSetting.get(); }, /** @@ -629,6 +688,7 @@ var node = this._frameNodes.get(frame); if (!node) return; + node.treeNode().title = frame.displayName(); for (var child of frame.childFrames) this._discardFrame(child); @@ -651,95 +711,37 @@ var node = this._frameNodes.get(frame); if (!node) return; + if (node.parent) - node.parent.treeNode().removeChild(node.treeNode()); + node.parent.removeChild(node); this._frameNodes.delete(frame); for (var child of frame.childFrames) this._discardFrame(child); }, + /** + * @override + * @param {!WebInspector.Target} target + */ + targetAdded: function(target) + { + }, + + /** + * @override + * @param {!WebInspector.Target} target + */ + targetRemoved: function(target) + { + var targetNode = this._rootNode.child("target:" + target.id()); + if (targetNode) + this._rootNode.removeChild(targetNode); + }, + __proto__: WebInspector.VBox.prototype } /** - * @constructor - * @extends {WebInspector.NavigatorView} - */ -WebInspector.SourcesNavigatorView = function() -{ - WebInspector.NavigatorView.call(this); - WebInspector.targetManager.addEventListener(WebInspector.TargetManager.Events.InspectedURLChanged, this._inspectedURLChanged, this); -} - -WebInspector.SourcesNavigatorView.prototype = { - /** - * @override - * @param {!WebInspector.UISourceCode} uiSourceCode - * @return {boolean} - */ - accept: function(uiSourceCode) - { - if (!WebInspector.NavigatorView.prototype.accept(uiSourceCode)) - return false; - return uiSourceCode.project().type() !== WebInspector.projectTypes.ContentScripts && uiSourceCode.project().type() !== WebInspector.projectTypes.Snippets; - - }, - - /** - * @param {!WebInspector.Event} event - */ - _inspectedURLChanged: function(event) - { - var nodes = this._uiSourceCodeNodes.valuesArray(); - for (var i = 0; i < nodes.length; ++i) { - var uiSourceCode = nodes[i].uiSourceCode(); - var inspectedPageURL = WebInspector.targetManager.inspectedPageURL(); - if (inspectedPageURL && WebInspector.networkMapping.networkURL(uiSourceCode) === inspectedPageURL) - this.revealUISourceCode(uiSourceCode, true); - } - }, - - /** - * @override - * @param {!WebInspector.UISourceCode} uiSourceCode - */ - _addUISourceCode: function(uiSourceCode) - { - WebInspector.NavigatorView.prototype._addUISourceCode.call(this, uiSourceCode); - var inspectedPageURL = WebInspector.targetManager.inspectedPageURL(); - if (inspectedPageURL && WebInspector.networkMapping.networkURL(uiSourceCode) === inspectedPageURL) - this.revealUISourceCode(uiSourceCode, true); - }, - - __proto__: WebInspector.NavigatorView.prototype -} - -/** - * @constructor - * @extends {WebInspector.NavigatorView} - */ -WebInspector.ContentScriptsNavigatorView = function() -{ - WebInspector.NavigatorView.call(this); -} - -WebInspector.ContentScriptsNavigatorView.prototype = { - /** - * @override - * @param {!WebInspector.UISourceCode} uiSourceCode - * @return {boolean} - */ - accept: function(uiSourceCode) - { - if (!WebInspector.NavigatorView.prototype.accept(uiSourceCode)) - return false; - return uiSourceCode.project().type() === WebInspector.projectTypes.ContentScripts; - }, - - __proto__: WebInspector.NavigatorView.prototype -} - -/** * @param {!TreeElement} treeElement1 * @param {!TreeElement} treeElement2 * @return {number}
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/OpenResourceDialog.js b/third_party/WebKit/Source/devtools/front_end/sources/OpenResourceDialog.js new file mode 100644 index 0000000..fb136b0 --- /dev/null +++ b/third_party/WebKit/Source/devtools/front_end/sources/OpenResourceDialog.js
@@ -0,0 +1,121 @@ +/* + * 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. + */ + +/** + * @constructor + * @extends {WebInspector.FilteredUISourceCodeListDelegate} + * @param {!WebInspector.SourcesView} sourcesView + * @param {!Map.<!WebInspector.UISourceCode, number>} defaultScores + * @param {!Array<string>} history + */ +WebInspector.OpenResourceDialog = function(sourcesView, defaultScores, history) +{ + WebInspector.FilteredUISourceCodeListDelegate.call(this, defaultScores, history); + this._sourcesView = sourcesView; +} + +WebInspector.OpenResourceDialog.prototype = { + + /** + * @override + * @param {?WebInspector.UISourceCode} uiSourceCode + * @param {number=} lineNumber + * @param {number=} columnNumber + */ + uiSourceCodeSelected: function(uiSourceCode, lineNumber, columnNumber) + { + if (!uiSourceCode) + uiSourceCode = this._sourcesView.currentUISourceCode(); + if (!uiSourceCode) + return; + this._sourcesView.showSourceLocation(uiSourceCode, lineNumber, columnNumber); + }, + + /** + * @override + * @param {string} query + * @return {boolean} + */ + shouldShowMatchingItems: function(query) + { + return !query.startsWith(":"); + }, + + /** + * @override + * @param {!WebInspector.Project} project + * @return {boolean} + */ + filterProject: function(project) + { + return !WebInspector.Project.isServiceProject(project); + }, + + __proto__: WebInspector.FilteredUISourceCodeListDelegate.prototype +} + +/** + * @param {!WebInspector.SourcesView} sourcesView + * @param {string} query + * @param {!Map.<!WebInspector.UISourceCode, number>} defaultScores + * @param {!Array<string>} history + */ +WebInspector.OpenResourceDialog.show = function(sourcesView, query, defaultScores, history) +{ + var filteredItemSelectionDialog = new WebInspector.FilteredListWidget(new WebInspector.OpenResourceDialog(sourcesView, defaultScores, history), true); + filteredItemSelectionDialog.showAsDialog(); + filteredItemSelectionDialog.setQuery(query); +} + +/** + * @constructor + * @extends {WebInspector.FilteredUISourceCodeListDelegate} + * @param {!Array.<string>} types + * @param {function(?WebInspector.UISourceCode)} callback + */ +WebInspector.SelectUISourceCodeForProjectTypesDialog = function(types, callback) +{ + this._types = types; + WebInspector.FilteredUISourceCodeListDelegate.call(this); + this._callback = callback; +} + +WebInspector.SelectUISourceCodeForProjectTypesDialog.prototype = { + /** + * @override + * @param {?WebInspector.UISourceCode} uiSourceCode + * @param {number=} lineNumber + * @param {number=} columnNumber + */ + uiSourceCodeSelected: function(uiSourceCode, lineNumber, columnNumber) + { + this._callback(uiSourceCode); + }, + + /** + * @override + * @param {!WebInspector.Project} project + * @return {boolean} + */ + filterProject: function(project) + { + return this._types.indexOf(project.type()) !== -1; + }, + + __proto__: WebInspector.FilteredUISourceCodeListDelegate.prototype +} + +/** + * @param {string} name + * @param {!Array.<string>} types + * @param {function(?WebInspector.UISourceCode)} callback + */ +WebInspector.SelectUISourceCodeForProjectTypesDialog.show = function(name, types, callback) +{ + var filteredItemSelectionDialog = new WebInspector.FilteredListWidget(new WebInspector.SelectUISourceCodeForProjectTypesDialog(types, callback), true); + filteredItemSelectionDialog.showAsDialog(); + filteredItemSelectionDialog.setQuery(name); +}
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/SourcesNavigator.js b/third_party/WebKit/Source/devtools/front_end/sources/SourcesNavigator.js index 4f5997f..ed1ed886 100644 --- a/third_party/WebKit/Source/devtools/front_end/sources/SourcesNavigator.js +++ b/third_party/WebKit/Source/devtools/front_end/sources/SourcesNavigator.js
@@ -42,6 +42,13 @@ this._tabbedPaneController = new WebInspector.ExtensibleTabbedPaneController(this._tabbedPane, "navigator-view", this._navigatorViewCreated.bind(this)); /** @type {!Map.<string, ?WebInspector.NavigatorView>} */ this._navigatorViews = new Map(); + + var toolbar = new WebInspector.Toolbar(""); + var menuButton = new WebInspector.ToolbarMenuButton(this._populateMenu.bind(this), true); + menuButton.setTitle(WebInspector.UIString("More options")); + toolbar.appendToolbarItem(menuButton); + + this._tabbedPane.appendAfterTabStrip(toolbar.element); } WebInspector.SourcesNavigator.Events = { @@ -114,6 +121,21 @@ this.dispatchEventToListeners(WebInspector.SourcesNavigator.Events.SourceRenamed, event.data); }, + /** + * @param {!WebInspector.ContextMenu} contextMenu + */ + _populateMenu: function(contextMenu) + { + var groupByFrameSetting = WebInspector.moduleSetting("navigatorGroupByFrame"); + var groupByDomainSetting = WebInspector.moduleSetting("navigatorGroupByDomain"); + var groupByFolderSetting = WebInspector.moduleSetting("navigatorGroupByFolder"); + contextMenu.appendItemsAtLocation("navigatorMenu"); + contextMenu.appendSeparator(); + contextMenu.appendCheckboxItem(WebInspector.UIString("Group by frame"), () => groupByFrameSetting.set(!groupByFrameSetting.get()), groupByFrameSetting.get()); + contextMenu.appendCheckboxItem(WebInspector.UIString("Group by domain"), () => groupByDomainSetting.set(!groupByDomainSetting.get()), groupByDomainSetting.get()); + contextMenu.appendCheckboxItem(WebInspector.UIString("Group by folder"), () => groupByFolderSetting.set(!groupByFolderSetting.get()), groupByFolderSetting.get(), !groupByDomainSetting.get()); + }, + __proto__: WebInspector.Object.prototype } @@ -121,6 +143,82 @@ * @constructor * @extends {WebInspector.NavigatorView} */ +WebInspector.SourcesNavigatorView = function() +{ + WebInspector.NavigatorView.call(this); + WebInspector.targetManager.addEventListener(WebInspector.TargetManager.Events.InspectedURLChanged, this._inspectedURLChanged, this); +} + +WebInspector.SourcesNavigatorView.prototype = { + /** + * @override + * @param {!WebInspector.UISourceCode} uiSourceCode + * @return {boolean} + */ + accept: function(uiSourceCode) + { + if (!WebInspector.NavigatorView.prototype.accept(uiSourceCode)) + return false; + return uiSourceCode.project().type() !== WebInspector.projectTypes.ContentScripts && uiSourceCode.project().type() !== WebInspector.projectTypes.Snippets; + }, + + /** + * @param {!WebInspector.Event} event + */ + _inspectedURLChanged: function(event) + { + var nodes = this._uiSourceCodeNodes.valuesArray(); + for (var i = 0; i < nodes.length; ++i) { + var uiSourceCode = nodes[i].uiSourceCode(); + var inspectedPageURL = WebInspector.targetManager.inspectedPageURL(); + if (inspectedPageURL && WebInspector.networkMapping.networkURL(uiSourceCode) === inspectedPageURL) + this.revealUISourceCode(uiSourceCode, true); + } + }, + + /** + * @override + * @param {!WebInspector.UISourceCode} uiSourceCode + */ + uiSourceCodeAdded: function(uiSourceCode) + { + var inspectedPageURL = WebInspector.targetManager.inspectedPageURL(); + if (inspectedPageURL && WebInspector.networkMapping.networkURL(uiSourceCode) === inspectedPageURL) + this.revealUISourceCode(uiSourceCode, true); + }, + + __proto__: WebInspector.NavigatorView.prototype +} + +/** + * @constructor + * @extends {WebInspector.NavigatorView} + */ +WebInspector.ContentScriptsNavigatorView = function() +{ + WebInspector.NavigatorView.call(this); +} + +WebInspector.ContentScriptsNavigatorView.prototype = { + /** + * @override + * @param {!WebInspector.UISourceCode} uiSourceCode + * @return {boolean} + */ + accept: function(uiSourceCode) + { + if (!WebInspector.NavigatorView.prototype.accept(uiSourceCode)) + return false; + return uiSourceCode.project().type() === WebInspector.projectTypes.ContentScripts; + }, + + __proto__: WebInspector.NavigatorView.prototype +} + +/** + * @constructor + * @extends {WebInspector.NavigatorView} + */ WebInspector.SnippetsNavigatorView = function() { WebInspector.NavigatorView.call(this);
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/StyleSheetOutlineDialog.js b/third_party/WebKit/Source/devtools/front_end/sources/StyleSheetOutlineDialog.js index 45c04191..1c4281e 100644 --- a/third_party/WebKit/Source/devtools/front_end/sources/StyleSheetOutlineDialog.js +++ b/third_party/WebKit/Source/devtools/front_end/sources/StyleSheetOutlineDialog.js
@@ -28,13 +28,13 @@ /** * @constructor - * @extends {WebInspector.SelectionDialogContentProvider} + * @extends {WebInspector.FilteredListWidget.Delegate} * @param {!WebInspector.UISourceCode} uiSourceCode * @param {function(number, number)} selectItemCallback */ WebInspector.StyleSheetOutlineDialog = function(uiSourceCode, selectItemCallback) { - WebInspector.SelectionDialogContentProvider.call(this, []); + WebInspector.FilteredListWidget.Delegate.call(this, []); this._selectItemCallback = selectItemCallback; this._cssParser = new WebInspector.CSSParser(); this._cssParser.addEventListener(WebInspector.CSSParser.Events.RulesParsed, this.refresh.bind(this)); @@ -48,7 +48,7 @@ WebInspector.StyleSheetOutlineDialog.show = function(uiSourceCode, selectItemCallback) { WebInspector.StyleSheetOutlineDialog._instanceForTests = new WebInspector.StyleSheetOutlineDialog(uiSourceCode, selectItemCallback); - new WebInspector.FilteredItemSelectionDialog(WebInspector.StyleSheetOutlineDialog._instanceForTests, false); + new WebInspector.FilteredListWidget(WebInspector.StyleSheetOutlineDialog._instanceForTests, false).showAsDialog(); } WebInspector.StyleSheetOutlineDialog.prototype = { @@ -117,5 +117,5 @@ this._cssParser.dispose(); }, - __proto__: WebInspector.SelectionDialogContentProvider.prototype + __proto__: WebInspector.FilteredListWidget.Delegate.prototype }
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/module.json b/third_party/WebKit/Source/devtools/front_end/sources/module.json index c6c21df..878b5fc 100644 --- a/third_party/WebKit/Source/devtools/front_end/sources/module.json +++ b/third_party/WebKit/Source/devtools/front_end/sources/module.json
@@ -157,6 +157,11 @@ "actionId": "sources.search.toggle" }, { + "type": "context-menu-item", + "location": "navigatorMenu/navigate", + "actionId": "sources.go-to-source" + }, + { "type": "@WebInspector.Revealer", "contextTypes": ["WebInspector.UILocation"], "className": "WebInspector.SourcesPanel.UILocationRevealer" @@ -211,6 +216,7 @@ { "type": "@WebInspector.ActionDelegate", "actionId": "sources.go-to-source", + "title": "Go to file...", "className": "WebInspector.SourcesPanel.RevealingActionDelegate", "order": 100, "bindings": [ @@ -237,18 +243,21 @@ }, { "type": "setting", - "category": "Sources", - "title": "Group items by", - "settingName": "navigatorGrouping", - "settingType": "enum", - "defaultValue": "frame/domain/folder", - "options": [ - ["Frames", "frame"], - ["Frames and Domains", "frame/domain"], - ["Frames, Domains and Folders", "frame/domain/folder"], - ["Domains", "domain"], - ["Domains and Folders", "domain/folder"] - ] + "settingName": "navigatorGroupByFrame", + "settingType": "boolean", + "defaultValue": "true" + }, + { + "type": "setting", + "settingName": "navigatorGroupByDomain", + "settingType": "boolean", + "defaultValue": "true" + }, + { + "type": "setting", + "settingName": "navigatorGroupByFolder", + "settingType": "boolean", + "defaultValue": "true" }, { "type": "setting", @@ -345,9 +354,9 @@ ], "dependencies": [ "components", - "diff", "source_frame", "snippets", + "ui_lazy", "extensions" ], "scripts": [ @@ -359,9 +368,10 @@ "EditingLocationHistoryManager.js", "EventListenerBreakpointsSidebarPane.js", "FilePathScoreFunction.js", - "FilteredItemSelectionDialog.js", + "FilteredUISourceCodeListDelegate.js", "UISourceCodeFrame.js", "JavaScriptBreakpointsSidebarPane.js", + "JavaScriptOutlineDialog.js", "JavaScriptSourceFrame.js", "CSSSourceFrame.js", "NavigatorView.js", @@ -376,6 +386,7 @@ "ScriptFormatterEditorAction.js", "InplaceFormatterEditorAction.js", "ScriptFormatter.js", + "OpenResourceDialog.js", "SourcesView.js", "AdvancedSearchView.js", "FileBasedSearchResultsPane.js", @@ -388,7 +399,6 @@ ], "resources": [ "addSourceMapURLDialog.css", - "filteredItemSelectionDialog.css", "uiList.css", "navigatorView.css", "revisionHistory.css",
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/navigatorView.css b/third_party/WebKit/Source/devtools/front_end/sources/navigatorView.css index aa8f113..a00e6e3 100644 --- a/third_party/WebKit/Source/devtools/front_end/sources/navigatorView.css +++ b/third_party/WebKit/Source/devtools/front_end/sources/navigatorView.css
@@ -27,9 +27,22 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +.icon { + -webkit-mask-image: url(Images/toolbarButtonGlyphs.png); + -webkit-mask-size: 352px 168px; + width: 32px; + height: 24px; + margin: -3px -3px -3px -7px; +} + +@media (-webkit-min-device-pixel-ratio: 1.5) { +.icon { + -webkit-mask-image: url(Images/toolbarButtonGlyphs_2x.png); +} +} /* media */ + .navigator-file-tree-item .icon { - -webkit-mask-image: url(Images/ic_drive_file_black_18dp.svg); - -webkit-mask-size: 18px 18px; + -webkit-mask-position: -224px -72px; background: linear-gradient(45deg, hsl(0, 0%, 50%), hsl(0, 0%, 70%)); } @@ -46,17 +59,16 @@ } .navigator-folder-tree-item .icon { - -webkit-mask-image: url(Images/ic_folder_black_18dp.svg); - -webkit-mask-size: 18px 18px; + -webkit-mask-position: -64px -120px; background-color: #555; } .navigator-domain-tree-item .icon { - -webkit-mask-image: url(Images/ic_cloud_queue_black_18dp.svg); + -webkit-mask-position: -160px -144px; } .navigator-frame-tree-item .icon { - -webkit-mask-image: url(Images/ic_web_asset_black_18dp.svg); + -webkit-mask-position: -256px -144px; } .navigator-sm-folder-tree-item .icon, @@ -70,7 +82,7 @@ } .navigator-worker-tree-item .icon { - -webkit-mask-image: url(Images/serviceWorker.svg); + -webkit-mask-position: -320px -144px; } .navigator-sm-script-tree-item .icon, @@ -93,10 +105,3 @@ .navigator-sm-stylesheet-tree-item .tree-element-title { font-style: italic; } - -.icon { - width: 18px; - height: 18px; - margin-right: 4px; - margin-top: -1px; -}
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/SoftContextMenu.js b/third_party/WebKit/Source/devtools/front_end/ui/SoftContextMenu.js index 46f0e9f..33f8545 100644 --- a/third_party/WebKit/Source/devtools/front_end/ui/SoftContextMenu.js +++ b/third_party/WebKit/Source/devtools/front_end/ui/SoftContextMenu.js
@@ -134,6 +134,8 @@ return menuItemElement; } + if (!item.enabled) + menuItemElement.classList.add("soft-context-menu-disabled"); menuItemElement.createTextChild(item.label); menuItemElement.createChild("span", "soft-context-menu-shortcut").textContent = item.shortcut;
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/Toolbar.js b/third_party/WebKit/Source/devtools/front_end/ui/Toolbar.js index 98900e5..c68fa0c 100644 --- a/third_party/WebKit/Source/devtools/front_end/ui/Toolbar.js +++ b/third_party/WebKit/Source/devtools/front_end/ui/Toolbar.js
@@ -615,11 +615,13 @@ * @constructor * @extends {WebInspector.ToolbarButton} * @param {function(!WebInspector.ContextMenu)} contextMenuHandler + * @param {boolean=} useSoftMenu */ -WebInspector.ToolbarMenuButton = function(contextMenuHandler) +WebInspector.ToolbarMenuButton = function(contextMenuHandler, useSoftMenu) { WebInspector.ToolbarButton.call(this, "", "menu-toolbar-item"); this._contextMenuHandler = contextMenuHandler; + this._useSoftMenu = !!useSoftMenu; } WebInspector.ToolbarMenuButton.prototype = { @@ -630,7 +632,7 @@ _clicked: function(event) { var contextMenu = new WebInspector.ContextMenu(event, - false, + this._useSoftMenu, this.element.totalOffsetLeft(), this.element.totalOffsetTop() + this.element.offsetHeight); this._contextMenuHandler(contextMenu);
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/ViewportControl.js b/third_party/WebKit/Source/devtools/front_end/ui/ViewportControl.js index b9de04d..f1267fd 100644 --- a/third_party/WebKit/Source/devtools/front_end/ui/ViewportControl.js +++ b/third_party/WebKit/Source/devtools/front_end/ui/ViewportControl.js
@@ -36,13 +36,15 @@ { this.element = createElement("div"); this.element.style.overflow = "auto"; - this._topGapElement = this.element.createChild("div", "viewport-control-gap-element"); + this._topGapElement = this.element.createChild("div"); this._topGapElement.textContent = "."; this._topGapElement.style.height = "0px"; + this._topGapElement.style.color = "transparent"; this._contentElement = this.element.createChild("div"); - this._bottomGapElement = this.element.createChild("div", "viewport-control-gap-element"); + this._bottomGapElement = this.element.createChild("div"); this._bottomGapElement.textContent = "."; this._bottomGapElement.style.height = "0px"; + this._bottomGapElement.style.color = "transparent"; this._provider = provider; this.element.addEventListener("scroll", this._onScroll.bind(this), false);
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/softContextMenu.css b/third_party/WebKit/Source/devtools/front_end/ui/softContextMenu.css index 558a3f0..36740cb4 100644 --- a/third_party/WebKit/Source/devtools/front_end/ui/softContextMenu.css +++ b/third_party/WebKit/Source/devtools/front_end/ui/softContextMenu.css
@@ -29,6 +29,11 @@ white-space: nowrap; } +.soft-context-menu-disabled { + color: #999; + pointer-events: none; +} + .soft-context-menu-separator { height: 10px; margin: 0 1px;
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/toolbar.css b/third_party/WebKit/Source/devtools/front_end/ui/toolbar.css index 1f56cf5a..dc3babb 100644 --- a/third_party/WebKit/Source/devtools/front_end/ui/toolbar.css +++ b/third_party/WebKit/Source/devtools/front_end/ui/toolbar.css
@@ -293,10 +293,6 @@ -webkit-mask-position: -224px 0; } -.edit-toolbar-item.toolbar-glyph { - -webkit-mask-position: -224px -72px; -} - .record-toolbar-item.toolbar-glyph { -webkit-mask-position: -288px 0; } @@ -476,6 +472,18 @@ -webkit-mask-position: -288px -96px; } +.frame-toolbar-item.toolbar-glyph { + -webkit-mask-position: -256px -144px; +} + +.domain-toolbar-item.toolbar-glyph { + -webkit-mask-position: -160px -144px; +} + +.folder-toolbar-item.toolbar-glyph { + -webkit-mask-position: -224px -144px; +} + .toolbar-state-on .record-toolbar-item.toolbar-glyph, .toolbar-state-active .filter-toolbar-item.toolbar-glyph, .toolbar-state-active .block-toolbar-item.toolbar-glyph {
diff --git a/third_party/WebKit/Source/devtools/front_end/ui_lazy/FilteredListWidget.js b/third_party/WebKit/Source/devtools/front_end/ui_lazy/FilteredListWidget.js new file mode 100644 index 0000000..8001938e --- /dev/null +++ b/third_party/WebKit/Source/devtools/front_end/ui_lazy/FilteredListWidget.js
@@ -0,0 +1,563 @@ +/* + * 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. + */ + +/** + * @constructor + * @extends {WebInspector.VBox} + * @implements {WebInspector.ViewportControl.Provider} + * @param {!WebInspector.FilteredListWidget.Delegate} delegate + * @param {boolean} renderAsTwoRows + */ +WebInspector.FilteredListWidget = function(delegate, renderAsTwoRows) +{ + WebInspector.VBox.call(this, true); + + this._renderAsTwoRows = renderAsTwoRows; + + this.contentElement.classList.add("filtered-list-widget"); + this.contentElement.addEventListener("keydown", this._onKeyDown.bind(this), false); + this.registerRequiredCSS("ui_lazy/filteredListWidget.css"); + + this._promptElement = this.contentElement.createChild("div", "monospace filtered-list-widget-input"); + this._promptElement.setAttribute("spellcheck", "false"); + this._prompt = new WebInspector.TextPrompt(this._autocomplete.bind(this)); + this._prompt.renderAsBlock(); + this._prompt.addEventListener(WebInspector.TextPrompt.Events.ItemAccepted, this._onAutocompleted, this); + var promptProxy = this._prompt.attach(this._promptElement); + promptProxy.addEventListener("input", this._onInput.bind(this), false); + promptProxy.classList.add("filtered-list-widget-prompt-element"); + + this._filteredItems = []; + this._viewportControl = new WebInspector.ViewportControl(this); + this._itemElementsContainer = this._viewportControl.element; + this._itemElementsContainer.classList.add("container"); + this._itemElementsContainer.classList.add("monospace"); + this._itemElementsContainer.addEventListener("click", this._onClick.bind(this), false); + this.contentElement.appendChild(this._itemElementsContainer); + + this.setDefaultFocusedElement(this._promptElement); + + this._delegate = delegate; + this._delegate.setRefreshCallback(this._itemsLoaded.bind(this)); + this._itemsLoaded(); + this._updateShowMatchingItems(); + this._viewportControl.refresh(); + this._prompt.autoCompleteSoon(true); +} + +/** + * @param {string} query + * @return {!RegExp} + */ +WebInspector.FilteredListWidget.filterRegex = function(query) +{ + const toEscape = String.regexSpecialCharacters(); + var regexString = ""; + for (var i = 0; i < query.length; ++i) { + var c = query.charAt(i); + if (toEscape.indexOf(c) !== -1) + c = "\\" + c; + if (i) + regexString += "[^" + c + "]*"; + regexString += c; + } + return new RegExp(regexString, "i"); +} + +WebInspector.FilteredListWidget.prototype = { + showAsDialog: function() + { + this._dialog = new WebInspector.Dialog(); + this._dialog.setMaxSize(new Size(504, 600)); + this.show(this._dialog.element); + this._dialog.show(); + }, + + /** + * @return {string} + */ + _value: function() + { + return this._prompt.userEnteredText().trim(); + }, + + willHide: function() + { + this._delegate.dispose(); + if (this._filterTimer) + clearTimeout(this._filterTimer); + }, + + /** + * @param {!Event} event + */ + _onEnter: function(event) + { + if (!this._delegate.itemCount()) + return; + event.preventDefault(); + var selectedIndex = this._shouldShowMatchingItems() && this._selectedIndexInFiltered < this._filteredItems.length ? this._filteredItems[this._selectedIndexInFiltered] : null; + this._delegate.selectItemWithQuery(selectedIndex, this._value()); + if (this._dialog) + this._dialog.detach(); + }, + + _itemsLoaded: function() + { + + if (this._loadTimeout) + return; + this._loadTimeout = setTimeout(this._updateAfterItemsLoaded.bind(this), 0); + }, + + _updateAfterItemsLoaded: function() + { + delete this._loadTimeout; + this._filterItems(); + }, + + /** + * @param {number} index + * @return {!Element} + */ + _createItemElement: function(index) + { + var itemElement = createElement("div"); + itemElement.className = "filtered-list-widget-item " + (this._renderAsTwoRows ? "two-rows" : "one-row"); + itemElement._titleElement = itemElement.createChild("div", "filtered-list-widget-title"); + itemElement._subtitleElement = itemElement.createChild("div", "filtered-list-widget-subtitle"); + itemElement._subtitleElement.textContent = "\u200B"; + itemElement._index = index; + this._delegate.renderItem(index, this._value(), itemElement._titleElement, itemElement._subtitleElement); + return itemElement; + }, + + /** + * @param {string} query + */ + setQuery: function(query) + { + this._prompt.setText(query); + this._prompt.autoCompleteSoon(true); + this._scheduleFilter(); + }, + + /** + * @param {!Element} proxyElement + * @param {string} query + * @param {number} cursorOffset + * @param {!Range} wordRange + * @param {boolean} force + * @param {function(!Array.<string>, number=)} completionsReadyCallback + */ + _autocomplete: function(proxyElement, query, cursorOffset, wordRange, force, completionsReadyCallback) + { + var completions = wordRange.startOffset === 0 ? [this._delegate.autocomplete(query)] : []; + completionsReadyCallback.call(null, completions); + this._autocompletedForTests(); + }, + + _autocompletedForTests: function() + { + // Sniffed in tests. + }, + + _filterItems: function() + { + delete this._filterTimer; + if (this._scoringTimer) { + clearTimeout(this._scoringTimer); + delete this._scoringTimer; + } + + var query = this._delegate.rewriteQuery(this._value()); + this._query = query; + var filterRegex = query ? WebInspector.FilteredListWidget.filterRegex(query) : null; + + var oldSelectedAbsoluteIndex = this._selectedIndexInFiltered ? this._filteredItems[this._selectedIndexInFiltered] : null; + var filteredItems = []; + this._selectedIndexInFiltered = 0; + + var bestScores = []; + var bestItems = []; + var bestItemsToCollect = 100; + var minBestScore = 0; + var overflowItems = []; + + scoreItems.call(this, 0); + + /** + * @param {number} a + * @param {number} b + * @return {number} + */ + function compareIntegers(a, b) + { + return b - a; + } + + /** + * @param {number} fromIndex + * @this {WebInspector.FilteredListWidget} + */ + function scoreItems(fromIndex) + { + var maxWorkItems = 1000; + var workDone = 0; + for (var i = fromIndex; i < this._delegate.itemCount() && workDone < maxWorkItems; ++i) { + // Filter out non-matching items quickly. + if (filterRegex && !filterRegex.test(this._delegate.itemKeyAt(i))) + continue; + + // Score item. + var score = this._delegate.itemScoreAt(i, query); + if (query) + workDone++; + + // Find its index in the scores array (earlier elements have bigger scores). + if (score > minBestScore || bestScores.length < bestItemsToCollect) { + var index = insertionIndexForObjectInListSortedByFunction(score, bestScores, compareIntegers, true); + bestScores.splice(index, 0, score); + bestItems.splice(index, 0, i); + if (bestScores.length > bestItemsToCollect) { + // Best list is too large -> drop last elements. + overflowItems.push(bestItems.peekLast()); + bestScores.length = bestItemsToCollect; + bestItems.length = bestItemsToCollect; + } + minBestScore = bestScores.peekLast(); + } else + filteredItems.push(i); + } + + // Process everything in chunks. + if (i < this._delegate.itemCount()) { + this._scoringTimer = setTimeout(scoreItems.bind(this, i), 0); + return; + } + delete this._scoringTimer; + + this._filteredItems = bestItems.concat(overflowItems).concat(filteredItems); + for (var i = 0; i < this._filteredItems.length; ++i) { + if (this._filteredItems[i] === oldSelectedAbsoluteIndex) { + this._selectedIndexInFiltered = i; + break; + } + } + this._viewportControl.invalidate(); + if (!query) + this._selectedIndexInFiltered = 0; + this._updateSelection(this._selectedIndexInFiltered, false); + } + }, + + /** + * @return {boolean} + */ + _shouldShowMatchingItems: function() + { + return this._delegate.shouldShowMatchingItems(this._value()); + }, + + _onAutocompleted: function() + { + this._prompt.autoCompleteSoon(true); + this._onInput(); + }, + + _onInput: function() + { + this._updateShowMatchingItems(); + this._scheduleFilter(); + }, + + _updateShowMatchingItems: function() + { + var shouldShowMatchingItems = this._shouldShowMatchingItems(); + this._itemElementsContainer.classList.toggle("hidden", !shouldShowMatchingItems); + }, + + /** + * @return {number} + */ + _rowsPerViewport: function() + { + return Math.floor(this._viewportControl.element.clientHeight / this._rowHeight); + }, + + _onKeyDown: function(event) + { + var newSelectedIndex = this._selectedIndexInFiltered; + + switch (event.keyCode) { + case WebInspector.KeyboardShortcut.Keys.Down.code: + if (++newSelectedIndex >= this._filteredItems.length) + newSelectedIndex = this._filteredItems.length - 1; + this._updateSelection(newSelectedIndex, true); + event.consume(true); + break; + case WebInspector.KeyboardShortcut.Keys.Up.code: + if (--newSelectedIndex < 0) + newSelectedIndex = 0; + this._updateSelection(newSelectedIndex, false); + event.consume(true); + break; + case WebInspector.KeyboardShortcut.Keys.PageDown.code: + newSelectedIndex = Math.min(newSelectedIndex + this._rowsPerViewport(), this._filteredItems.length - 1); + this._updateSelection(newSelectedIndex, true); + event.consume(true); + break; + case WebInspector.KeyboardShortcut.Keys.PageUp.code: + newSelectedIndex = Math.max(newSelectedIndex - this._rowsPerViewport(), 0); + this._updateSelection(newSelectedIndex, false); + event.consume(true); + break; + case WebInspector.KeyboardShortcut.Keys.Enter.code: + this._onEnter(event); + break; + default: + } + }, + + _scheduleFilter: function() + { + if (this._filterTimer) + return; + this._filterTimer = setTimeout(this._filterItems.bind(this), 0); + }, + + /** + * @param {number} index + * @param {boolean} makeLast + */ + _updateSelection: function(index, makeLast) + { + if (!this._filteredItems.length) + return; + if (this._selectedElement) + this._selectedElement.classList.remove("selected"); + this._viewportControl.scrollItemIntoView(index, makeLast); + this._selectedIndexInFiltered = index; + this._selectedElement = this._viewportControl.renderedElementAt(index); + if (this._selectedElement) + this._selectedElement.classList.add("selected"); + }, + + _onClick: function(event) + { + var itemElement = event.target.enclosingNodeOrSelfWithClass("filtered-list-widget-item"); + if (!itemElement) + return; + this._delegate.selectItemWithQuery(itemElement._index, this._value()); + if (this._dialog) + this._dialog.detach(); + }, + + /** + * @override + * @return {number} + */ + itemCount: function() + { + return this._filteredItems.length; + }, + + /** + * @override + * @param {number} index + * @return {number} + */ + fastHeight: function(index) + { + if (!this._rowHeight) { + var delegateIndex = this._filteredItems[index]; + var element = this._createItemElement(delegateIndex); + this._rowHeight = WebInspector.measurePreferredSize(element, this._viewportControl.contentElement()).height; + } + return this._rowHeight; + }, + + /** + * @override + * @param {number} index + * @return {!WebInspector.ViewportElement} + */ + itemElement: function(index) + { + var delegateIndex = this._filteredItems[index]; + var element = this._createItemElement(delegateIndex); + return new WebInspector.StaticViewportElement(element); + }, + + /** + * @override + * @return {number} + */ + minimumRowHeight: function() + { + return this.fastHeight(0); + }, + + __proto__: WebInspector.VBox.prototype +} + +/** + * @constructor + * @param {!Array<string>} promptHistory + */ +WebInspector.FilteredListWidget.Delegate = function(promptHistory) +{ + this._promptHistory = promptHistory; +} + +WebInspector.FilteredListWidget.Delegate.prototype = { + /** + * @param {function():void} refreshCallback + */ + setRefreshCallback: function(refreshCallback) + { + this._refreshCallback = refreshCallback; + }, + + /** + * @param {string} query + * @return {boolean} + */ + shouldShowMatchingItems: function(query) + { + return true; + }, + + /** + * @return {number} + */ + itemCount: function() + { + return 0; + }, + + /** + * @param {number} itemIndex + * @return {string} + */ + itemKeyAt: function(itemIndex) + { + return ""; + }, + + /** + * @param {number} itemIndex + * @param {string} query + * @return {number} + */ + itemScoreAt: function(itemIndex, query) + { + return 1; + }, + + /** + * @param {number} itemIndex + * @param {string} query + * @param {!Element} titleElement + * @param {!Element} subtitleElement + */ + renderItem: function(itemIndex, query, titleElement, subtitleElement) + { + }, + + /** + * @param {!Element} element + * @param {string} query + * @return {boolean} + */ + highlightRanges: function(element, query) + { + if (!query) + return false; + + /** + * @param {string} text + * @param {string} query + * @return {?Array.<!WebInspector.SourceRange>} + */ + function rangesForMatch(text, query) + { + var opcodes = WebInspector.Diff.charDiff(query, text); + var offset = 0; + var ranges = []; + for (var i = 0; i < opcodes.length; ++i) { + var opcode = opcodes[i]; + if (opcode[0] === WebInspector.Diff.Operation.Equal) + ranges.push(new WebInspector.SourceRange(offset, opcode[1].length)); + else if (opcode[0] !== WebInspector.Diff.Operation.Insert) + return null; + offset += opcode[1].length; + } + return ranges; + } + + var text = element.textContent; + var ranges = rangesForMatch(text, query); + if (!ranges) + ranges = rangesForMatch(text.toUpperCase(), query.toUpperCase()); + if (ranges) { + WebInspector.highlightRangesWithStyleClass(element, ranges, "highlight"); + return true; + } + return false; + }, + + /** + * @param {number} itemIndex + * @param {string} promptValue + */ + selectItemWithQuery: function(itemIndex, promptValue) + { + this._promptHistory.push(promptValue); + if (this._promptHistory.length > 100) + this._promptHistory.shift(); + this.selectItem(itemIndex, promptValue); + }, + + /** + * @param {number} itemIndex + * @param {string} promptValue + */ + selectItem: function(itemIndex, promptValue) + { + }, + + refresh: function() + { + this._refreshCallback(); + }, + + /** + * @param {string} query + * @return {string} + */ + rewriteQuery: function(query) + { + return query; + }, + + /** + * @param {string} query + * @return {string} + */ + autocomplete: function(query) + { + for (var i = this._promptHistory.length - 1; i >= 0; i--) { + if (this._promptHistory[i] !== query && this._promptHistory[i].startsWith(query)) + return this._promptHistory[i]; + } + return query; + }, + + dispose: function() + { + } +}
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/filteredItemSelectionDialog.css b/third_party/WebKit/Source/devtools/front_end/ui_lazy/filteredListWidget.css similarity index 67% rename from third_party/WebKit/Source/devtools/front_end/sources/filteredItemSelectionDialog.css rename to third_party/WebKit/Source/devtools/front_end/ui_lazy/filteredListWidget.css index 928b597..8dcf450e 100644 --- a/third_party/WebKit/Source/devtools/front_end/sources/filteredItemSelectionDialog.css +++ b/third_party/WebKit/Source/devtools/front_end/ui_lazy/filteredListWidget.css
@@ -4,13 +4,13 @@ * found in the LICENSE file. */ -.filtered-item-list-dialog { +.filtered-list-widget { display: flex; flex-direction: column; flex: auto; } -.filtered-dialog-prompt-element { +.filtered-list-widget-prompt-element { flex: 0 0 36px; border: 0; box-shadow: rgba(140, 140, 140, 0.5) 0 4px 16px; @@ -20,20 +20,20 @@ font-size: inherit; } -.filtered-dialog-input { +.filtered-list-widget-input { white-space: pre; -webkit-user-modify: read-write-plaintext-only; height: 18px; margin-top: 10px; } -.filtered-item-list-dialog > div.container { +.filtered-list-widget > div.container { flex: auto; overflow-y: auto; background: white; } -.filtered-item-list-dialog-item { +.filtered-list-widget-item { padding: 6px; white-space: nowrap; text-overflow: ellipsis; @@ -41,32 +41,32 @@ color: rgb(95, 95, 95); } -.filtered-item-list-dialog-item.selected { +.filtered-list-widget-item.selected { background-color: #eee; } -.filtered-item-list-dialog-item span.highlight { +.filtered-list-widget-item span.highlight { color: #222; font-weight: bold; } -.filtered-item-list-dialog-item .filtered-item-list-dialog-title { +.filtered-list-widget-item .filtered-list-widget-title { flex: auto; overflow: hidden; text-overflow: ellipsis; } -.filtered-item-list-dialog-item .filtered-item-list-dialog-subtitle { +.filtered-list-widget-item .filtered-list-widget-subtitle { flex: none; overflow: hidden; text-overflow: ellipsis; color: rgb(155, 155, 155); } -.filtered-item-list-dialog-item.one-row { +.filtered-list-widget-item.one-row { display: flex; } -.filtered-item-list-dialog-item.two-rows { +.filtered-list-widget-item.two-rows { border-bottom: 1px solid rgb(235, 235, 235); }
diff --git a/third_party/WebKit/Source/devtools/front_end/ui_lazy/module.json b/third_party/WebKit/Source/devtools/front_end/ui_lazy/module.json index 3c22dd30..c25902c 100644 --- a/third_party/WebKit/Source/devtools/front_end/ui_lazy/module.json +++ b/third_party/WebKit/Source/devtools/front_end/ui_lazy/module.json
@@ -3,13 +3,15 @@ "platform", "common", "host", - "ui" + "ui", + "diff" ], "scripts": [ "DataGrid.js", "ViewportDataGrid.js", "SortableDataGrid.js", "ShowMoreDataGridNode.js", + "FilteredListWidget.js", "FlameChart.js", "OverviewGrid.js", "PieChart.js", @@ -18,6 +20,7 @@ ], "resources": [ "dataGrid.css", + "filteredListWidget.css", "flameChart.css", "overviewGrid.css", "pieChart.css",
diff --git a/third_party/WebKit/Source/devtools/front_end/workspace/FileSystemMapping.js b/third_party/WebKit/Source/devtools/front_end/workspace/FileSystemMapping.js index 83c8b03..f85b7060 100644 --- a/third_party/WebKit/Source/devtools/front_end/workspace/FileSystemMapping.js +++ b/third_party/WebKit/Source/devtools/front_end/workspace/FileSystemMapping.js
@@ -53,7 +53,7 @@ this._fileSystemMappings = {}; for (var fileSystemPath in savedMapping) { var savedFileSystemMappings = savedMapping[fileSystemPath]; - fileSystemPath = WebInspector.IsolatedFileSystem.normalizePath(fileSystemPath); + fileSystemPath = WebInspector.IsolatedFileSystemManager.normalizePath(fileSystemPath); this._fileSystemMappings[fileSystemPath] = []; var fileSystemMappings = this._fileSystemMappings[fileSystemPath];
diff --git a/third_party/WebKit/Source/devtools/front_end/workspace/IsolatedFileSystem.js b/third_party/WebKit/Source/devtools/front_end/workspace/IsolatedFileSystem.js index 78665c1..ec4c527 100644 --- a/third_party/WebKit/Source/devtools/front_end/workspace/IsolatedFileSystem.js +++ b/third_party/WebKit/Source/devtools/front_end/workspace/IsolatedFileSystem.js
@@ -32,12 +32,14 @@ * @constructor * @param {!WebInspector.IsolatedFileSystemManager} manager * @param {string} path + * @param {string} embedderPath * @param {!DOMFileSystem} domFileSystem */ -WebInspector.IsolatedFileSystem = function(manager, path, domFileSystem) +WebInspector.IsolatedFileSystem = function(manager, path, embedderPath, domFileSystem) { this._manager = manager; this._path = path; + this._embedderPath = embedderPath; this._domFileSystem = domFileSystem; this._excludedFoldersSetting = WebInspector.settings.createLocalSetting("workspaceExcludedFolders", {}); /** @type {!Set<string>} */ @@ -52,11 +54,12 @@ * @constructor * @param {!WebInspector.IsolatedFileSystemManager} manager * @param {string} path + * @param {string} embedderPath * @param {string} name * @param {string} rootURL * @return {!Promise<?WebInspector.IsolatedFileSystem>} */ -WebInspector.IsolatedFileSystem.create = function(manager, path, name, rootURL) +WebInspector.IsolatedFileSystem.create = function(manager, path, embedderPath, name, rootURL) { return new Promise(promiseBody); @@ -71,7 +74,7 @@ resolve(null); return; } - var fileSystem = new WebInspector.IsolatedFileSystem(manager, path, domFileSystem); + var fileSystem = new WebInspector.IsolatedFileSystem(manager, path, embedderPath, domFileSystem); fileSystem.requestFileContent(".devtools", onConfigAvailable); /** @@ -101,36 +104,6 @@ return WebInspector.UIString("File system error: %s", error.message); } -/** - * @param {string} fileSystemPath - * @return {string} - */ -WebInspector.IsolatedFileSystem.normalizePath = function(fileSystemPath) -{ - fileSystemPath = fileSystemPath.replace(/\\/g, "/"); - if (!fileSystemPath.startsWith("file://")) { - if (fileSystemPath.startsWith("/")) - fileSystemPath = "file://" + fileSystemPath; - else - fileSystemPath = "file:///" + fileSystemPath; - } - return fileSystemPath; -} - -/** - * @param {string} fileSystemPath - * @return {string} - */ -WebInspector.IsolatedFileSystem.denormalizePath = function(fileSystemPath) -{ - fileSystemPath = fileSystemPath.substring("file://".length); - if (WebInspector.isWin()) { - fileSystemPath = fileSystemPath.replace(/\//g, "\\"); - fileSystemPath = fileSystemPath.substring(1); - } - return fileSystemPath; -} - WebInspector.IsolatedFileSystem.prototype = { /** * @return {string} @@ -141,6 +114,14 @@ }, /** + * @return {string} + */ + embedderPath: function() + { + return this._embedderPath; + }, + + /** * @param {?Object} projectObject */ _initializeProject: function(projectObject) @@ -600,5 +581,37 @@ nonConfigurableExcludedFolders: function() { return this._nonConfigurableExcludedFolders; + }, + + + /** + * @param {string} query + * @param {!WebInspector.Progress} progress + * @param {function(!Array.<string>)} callback + */ + searchInPath: function(query, progress, callback) + { + var requestId = this._manager.registerCallback(innerCallback); + InspectorFrontendHost.searchInPath(requestId, this._embedderPath, query); + + /** + * @param {!Array.<string>} files + */ + function innerCallback(files) + { + files = files.map(embedderPath => WebInspector.IsolatedFileSystemManager.normalizePath(embedderPath)); + progress.worked(1); + callback(files); + } + }, + + /** + * @param {!WebInspector.Progress} progress + */ + indexContent: function(progress) + { + progress.setTotalWork(1); + var requestId = this._manager.registerProgress(progress); + InspectorFrontendHost.indexPath(requestId, this._embedderPath); } }
diff --git a/third_party/WebKit/Source/devtools/front_end/workspace/IsolatedFileSystemManager.js b/third_party/WebKit/Source/devtools/front_end/workspace/IsolatedFileSystemManager.js index 88b8dc25..837526e7 100644 --- a/third_party/WebKit/Source/devtools/front_end/workspace/IsolatedFileSystemManager.js +++ b/third_party/WebKit/Source/devtools/front_end/workspace/IsolatedFileSystemManager.js
@@ -36,11 +36,19 @@ { /** @type {!Object.<string, !WebInspector.IsolatedFileSystem>} */ this._fileSystems = {}; + /** @type {!Object.<number, function(!Array.<string>)>} */ + this._callbacks = {}; + /** @type {!Object.<number, !WebInspector.Progress>} */ + this._progresses = {}; InspectorFrontendHost.events.addEventListener(InspectorFrontendHostAPI.Events.FileSystemsLoaded, this._onFileSystemsLoaded, this); InspectorFrontendHost.events.addEventListener(InspectorFrontendHostAPI.Events.FileSystemRemoved, this._onFileSystemRemoved, this); InspectorFrontendHost.events.addEventListener(InspectorFrontendHostAPI.Events.FileSystemAdded, this._onFileSystemAdded, this); InspectorFrontendHost.events.addEventListener(InspectorFrontendHostAPI.Events.FileSystemFilesChanged, this._onFileSystemFilesChanged, this); + InspectorFrontendHost.events.addEventListener(InspectorFrontendHostAPI.Events.IndexingTotalWorkCalculated, this._onIndexingTotalWorkCalculated, this); + InspectorFrontendHost.events.addEventListener(InspectorFrontendHostAPI.Events.IndexingWorked, this._onIndexingWorked, this); + InspectorFrontendHost.events.addEventListener(InspectorFrontendHostAPI.Events.IndexingDone, this._onIndexingDone, this); + InspectorFrontendHost.events.addEventListener(InspectorFrontendHostAPI.Events.SearchCompleted, this._onSearchCompleted, this); this._initExcludePatterSetting(); } @@ -57,6 +65,24 @@ ExcludedFolderRemoved: "ExcludedFolderRemoved" } +WebInspector.IsolatedFileSystemManager._lastRequestId = 0; + +/** + * @param {string} fileSystemPath + * @return {string} + */ +WebInspector.IsolatedFileSystemManager.normalizePath = function(fileSystemPath) +{ + fileSystemPath = fileSystemPath.replace(/\\/g, "/"); + if (!fileSystemPath.startsWith("file://")) { + if (fileSystemPath.startsWith("/")) + fileSystemPath = "file://" + fileSystemPath; + else + fileSystemPath = "file:///" + fileSystemPath; + } + return fileSystemPath; +} + WebInspector.IsolatedFileSystemManager.prototype = { /** * @param {function()} callback @@ -67,21 +93,18 @@ InspectorFrontendHost.requestFileSystems(); }, - /** - * @param {string} fileSystemPath - */ - addFileSystem: function(fileSystemPath) + addFileSystem: function() { - InspectorFrontendHost.addFileSystem(WebInspector.IsolatedFileSystem.denormalizePath(fileSystemPath)); + InspectorFrontendHost.addFileSystem(""); }, /** - * @param {string} fileSystemPath + * @param {!WebInspector.IsolatedFileSystem} fileSystem */ - removeFileSystem: function(fileSystemPath) + removeFileSystem: function(fileSystem) { - InspectorFrontendHost.removeFileSystem(WebInspector.IsolatedFileSystem.denormalizePath(fileSystemPath)); + InspectorFrontendHost.removeFileSystem(fileSystem.embedderPath()); }, /** @@ -120,8 +143,9 @@ */ _innerAddFileSystem: function(fileSystem) { - var fileSystemPath = WebInspector.IsolatedFileSystem.normalizePath(fileSystem.fileSystemPath); - var promise = WebInspector.IsolatedFileSystem.create(this, fileSystemPath, fileSystem.fileSystemName, fileSystem.rootURL); + var embedderPath = fileSystem.fileSystemPath; + var fileSystemPath = WebInspector.IsolatedFileSystemManager.normalizePath(fileSystem.fileSystemPath); + var promise = WebInspector.IsolatedFileSystem.create(this, fileSystemPath, embedderPath, fileSystem.fileSystemName, fileSystem.rootURL); return promise.then(storeFileSystem.bind(this)); /** @@ -163,15 +187,17 @@ */ _onFileSystemFilesChanged: function(event) { - this.dispatchEventToListeners(WebInspector.IsolatedFileSystemManager.Events.FileSystemFilesChanged, event.data); + var embedderPaths = /** @type {!Array<string>} */ (event.data); + var paths = embedderPaths.map(embedderPath => WebInspector.IsolatedFileSystemManager.normalizePath(embedderPath)); + this.dispatchEventToListeners(WebInspector.IsolatedFileSystemManager.Events.FileSystemFilesChanged, paths); }, /** - * @param {string} fileSystemPath + * @param {string} embedderPath */ - _fileSystemRemoved: function(fileSystemPath) + _fileSystemRemoved: function(embedderPath) { - fileSystemPath = WebInspector.IsolatedFileSystem.normalizePath(fileSystemPath); + var fileSystemPath = WebInspector.IsolatedFileSystemManager.normalizePath(embedderPath); var isolatedFileSystem = this._fileSystems[fileSystemPath]; delete this._fileSystems[fileSystemPath]; if (isolatedFileSystem) { @@ -246,6 +272,97 @@ return this._workspaceFolderExcludePatternSetting; }, + /** + * @param {function(!Array.<string>)} callback + * @return {number} + */ + registerCallback: function(callback) + { + var requestId = ++WebInspector.IsolatedFileSystemManager._lastRequestId; + this._callbacks[requestId] = callback; + return requestId; + }, + + /** + * @param {!WebInspector.Progress} progress + * @return {number} + */ + registerProgress: function(progress) + { + var requestId = ++WebInspector.IsolatedFileSystemManager._lastRequestId; + this._progresses[requestId] = progress; + return requestId; + }, + + /** + * @param {!WebInspector.Event} event + */ + _onIndexingTotalWorkCalculated: function(event) + { + var requestId = /** @type {number} */ (event.data["requestId"]); + var totalWork = /** @type {number} */ (event.data["totalWork"]); + + var progress = this._progresses[requestId]; + if (!progress) + return; + progress.setTotalWork(totalWork); + }, + + /** + * @param {!WebInspector.Event} event + */ + _onIndexingWorked: function(event) + { + var requestId = /** @type {number} */ (event.data["requestId"]); + var worked = /** @type {number} */ (event.data["worked"]); + + var progress = this._progresses[requestId]; + if (!progress) + return; + progress.worked(worked); + if (progress.isCanceled()) { + InspectorFrontendHost.stopIndexing(requestId); + this._onIndexingDone(event); + } + }, + + /** + * @param {!WebInspector.Event} event + */ + _onIndexingDone: function(event) + { + var requestId = /** @type {number} */ (event.data["requestId"]); + + var progress = this._progresses[requestId]; + if (!progress) + return; + progress.done(); + delete this._progresses[requestId]; + }, + + /** + * @param {!WebInspector.Event} event + */ + _onSearchCompleted: function(event) + { + var requestId = /** @type {number} */ (event.data["requestId"]); + var files = /** @type {!Array.<string>} */ (event.data["files"]); + + var callback = this._callbacks[requestId]; + if (!callback) + return; + callback.call(null, files); + delete this._callbacks[requestId]; + }, + + dispose: function() + { + InspectorFrontendHost.events.removeEventListener(InspectorFrontendHostAPI.Events.IndexingTotalWorkCalculated, this._onIndexingTotalWorkCalculated, this); + InspectorFrontendHost.events.removeEventListener(InspectorFrontendHostAPI.Events.IndexingWorked, this._onIndexingWorked, this); + InspectorFrontendHost.events.removeEventListener(InspectorFrontendHostAPI.Events.IndexingDone, this._onIndexingDone, this); + InspectorFrontendHost.events.removeEventListener(InspectorFrontendHostAPI.Events.SearchCompleted, this._onSearchCompleted, this); + }, + __proto__: WebInspector.Object.prototype }
diff --git a/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerThreadTest.cpp b/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerThreadTest.cpp index 7a45991..3d16a97 100644 --- a/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerThreadTest.cpp +++ b/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerThreadTest.cpp
@@ -188,7 +188,7 @@ private: void executeScriptInWorker(WorkerThread* worker, WebWaitableEvent* waitEvent) { - WorkerScriptController* scriptController = worker->workerGlobalScope()->script(); + WorkerOrWorkletScriptController* scriptController = worker->workerGlobalScope()->script(); bool evaluateResult = scriptController->evaluate(ScriptSourceCode("var counter = 0; ++counter;")); ASSERT_UNUSED(evaluateResult, evaluateResult); waitEvent->signal();
diff --git a/third_party/WebKit/Source/modules/filesystem/DOMFileSystemBaseTest.cpp b/third_party/WebKit/Source/modules/filesystem/DOMFileSystemBaseTest.cpp index 608e2a68..d705c23 100644 --- a/third_party/WebKit/Source/modules/filesystem/DOMFileSystemBaseTest.cpp +++ b/third_party/WebKit/Source/modules/filesystem/DOMFileSystemBaseTest.cpp
@@ -5,8 +5,7 @@ #include "modules/filesystem/DOMFileSystemBase.h" #include "core/fileapi/File.h" -#include "public/platform/Platform.h" -#include "public/platform/WebUnitTestSupport.h" +#include "platform/testing/UnitTestHelpers.h" #include "testing/gtest/include/gtest/gtest.h" @@ -16,7 +15,7 @@ public: DOMFileSystemBaseTest() { - m_filePath = Platform::current()->unitTestSupport()->webKitRootDir(); + m_filePath = testing::blinkRootDir(); m_filePath.append("/Source/modules/filesystem/DOMFileSystemBaseTest.cpp"); getFileMetadata(m_filePath, m_fileMetadata); m_fileMetadata.platformPath = m_filePath;
diff --git a/third_party/WebKit/Source/modules/indexeddb/InspectorIndexedDBAgent.cpp b/third_party/WebKit/Source/modules/indexeddb/InspectorIndexedDBAgent.cpp index e1aef26be..6ea1d86 100644 --- a/third_party/WebKit/Source/modules/indexeddb/InspectorIndexedDBAgent.cpp +++ b/third_party/WebKit/Source/modules/indexeddb/InspectorIndexedDBAgent.cpp
@@ -674,6 +674,8 @@ return; ScriptState* scriptState = ScriptState::forMainWorld(frame); + if (!scriptState) + return; ScriptState::Scope scope(scriptState); TrackExceptionState exceptionState; IDBRequest* idbRequest = idbFactory->getDatabaseNames(scriptState, exceptionState); @@ -695,6 +697,8 @@ return; ScriptState* scriptState = ScriptState::forMainWorld(frame); + if (!scriptState) + return; ScriptState::Scope scope(scriptState); RefPtr<DatabaseLoader> databaseLoader = DatabaseLoader::create(scriptState, requestCallback); databaseLoader->start(idbFactory, document->securityOrigin(), databaseName); @@ -717,6 +721,8 @@ } ScriptState* scriptState = ScriptState::forMainWorld(frame); + if (!scriptState) + return; ScriptState::Scope scope(scriptState); RefPtr<DataLoader> dataLoader = DataLoader::create(scriptState, requestCallback, objectStoreName, indexName, idbKeyRange, skipCount, pageSize); dataLoader->start(idbFactory, document->securityOrigin(), databaseName); @@ -823,6 +829,8 @@ return; ScriptState* scriptState = ScriptState::forMainWorld(frame); + if (!scriptState) + return; ScriptState::Scope scope(scriptState); RefPtr<ClearObjectStore> clearObjectStore = ClearObjectStore::create(scriptState, objectStoreName, requestCallback); clearObjectStore->start(idbFactory, document->securityOrigin(), databaseName);
diff --git a/third_party/WebKit/Source/modules/mediacapturefromelement/AutoCanvasDrawListener.cpp b/third_party/WebKit/Source/modules/mediacapturefromelement/AutoCanvasDrawListener.cpp index b3cadfc..b4a1265 100644 --- a/third_party/WebKit/Source/modules/mediacapturefromelement/AutoCanvasDrawListener.cpp +++ b/third_party/WebKit/Source/modules/mediacapturefromelement/AutoCanvasDrawListener.cpp
@@ -4,8 +4,6 @@ #include "modules/mediacapturefromelement/AutoCanvasDrawListener.h" -#include "public/platform/WebSkImage.h" - namespace blink { // static
diff --git a/third_party/WebKit/Source/modules/mediacapturefromelement/OnRequestCanvasDrawListener.cpp b/third_party/WebKit/Source/modules/mediacapturefromelement/OnRequestCanvasDrawListener.cpp index 2a81d68..d04152d 100644 --- a/third_party/WebKit/Source/modules/mediacapturefromelement/OnRequestCanvasDrawListener.cpp +++ b/third_party/WebKit/Source/modules/mediacapturefromelement/OnRequestCanvasDrawListener.cpp
@@ -6,7 +6,6 @@ #include "platform/Task.h" #include "public/platform/Platform.h" -#include "public/platform/WebSkImage.h" #include "public/platform/WebTaskRunner.h" #include "public/platform/WebTraceLocation.h"
diff --git a/third_party/WebKit/Source/modules/mediacapturefromelement/TimedCanvasDrawListener.cpp b/third_party/WebKit/Source/modules/mediacapturefromelement/TimedCanvasDrawListener.cpp index 9234382..1206a61 100644 --- a/third_party/WebKit/Source/modules/mediacapturefromelement/TimedCanvasDrawListener.cpp +++ b/third_party/WebKit/Source/modules/mediacapturefromelement/TimedCanvasDrawListener.cpp
@@ -6,7 +6,6 @@ #include "platform/Task.h" #include "public/platform/Platform.h" -#include "public/platform/WebSkImage.h" #include "public/platform/WebTaskRunner.h" #include "public/platform/WebTraceLocation.h"
diff --git a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerGlobalScope.cpp b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerGlobalScope.cpp index 5b09a1e..a796bc4 100644 --- a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerGlobalScope.cpp +++ b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerGlobalScope.cpp
@@ -184,7 +184,7 @@ { m_eventNestingLevel++; bool result = WorkerGlobalScope::dispatchEventInternal(event.get()); - if (event->interfaceName() == EventNames::ErrorEvent && m_eventNestingLevel == 2 && !event->defaultPrevented()) + if (event->interfaceName() == EventNames::ErrorEvent && m_eventNestingLevel == 2) m_hadErrorInTopLevelEventHandler = true; m_eventNestingLevel--; return result;
diff --git a/third_party/WebKit/Source/modules/webaudio/AudioParamTimeline.cpp b/third_party/WebKit/Source/modules/webaudio/AudioParamTimeline.cpp index d19c002..2fad5535 100644 --- a/third_party/WebKit/Source/modules/webaudio/AudioParamTimeline.cpp +++ b/third_party/WebKit/Source/modules/webaudio/AudioParamTimeline.cpp
@@ -600,9 +600,8 @@ } currentFrame = fillToEndFrame; - - break; } + break; } case ParamEvent::SetValueCurve:
diff --git a/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.cpp b/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.cpp index 95cb0ca..a128374 100644 --- a/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.cpp +++ b/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.cpp
@@ -1406,79 +1406,22 @@ attribValue.value.uintValue[3] = value[3]; } -bool WebGL2RenderingContextBase::validateVertexAttribPointerTypeAndSize(GLenum type, GLint size) -{ - switch (type) { - case GL_BYTE: - case GL_UNSIGNED_BYTE: - case GL_SHORT: - case GL_UNSIGNED_SHORT: - case GL_INT: - case GL_UNSIGNED_INT: - case GL_FLOAT: - case GL_HALF_FLOAT: - if (size < 1 || size > 4) { - synthesizeGLError(GL_INVALID_VALUE, "vertexAttribPointer", "invalid size"); - return false; - } - return true; - case GL_INT_2_10_10_10_REV: - case GL_UNSIGNED_INT_2_10_10_10_REV: - if (size < 1 || size > 4) { - synthesizeGLError(GL_INVALID_VALUE, "vertexAttribPointer", "invalid size"); - return false; - } - if (size != 4) { - synthesizeGLError(GL_INVALID_OPERATION, "vertexAttribPointer", "size != 4"); - return false; - } - return true; - default: - synthesizeGLError(GL_INVALID_ENUM, "vertexAttribPointer", "invalid type"); - return false; - } -} - void WebGL2RenderingContextBase::vertexAttribIPointer(GLuint index, GLint size, GLenum type, GLsizei stride, long long offset) { if (isContextLost()) return; - - switch (type) { - case GL_BYTE: - case GL_UNSIGNED_BYTE: - case GL_SHORT: - case GL_UNSIGNED_SHORT: - case GL_INT: - case GL_UNSIGNED_INT: - break; - default: - synthesizeGLError(GL_INVALID_ENUM, "vertexAttribIPointer", "invalid type"); - return; - } if (index >= m_maxVertexAttribs) { synthesizeGLError(GL_INVALID_VALUE, "vertexAttribIPointer", "index out of range"); return; } - if (size < 1 || size > 4 || stride < 0 || stride > 255) { - synthesizeGLError(GL_INVALID_VALUE, "vertexAttribIPointer", "bad size or stride"); - return; - } if (!validateValueFitNonNegInt32("vertexAttribIPointer", "offset", offset)) return; if (!m_boundArrayBuffer) { synthesizeGLError(GL_INVALID_OPERATION, "vertexAttribIPointer", "no bound ARRAY_BUFFER"); return; } - unsigned typeSize = sizeInBytes(type); - ASSERT((typeSize & (typeSize - 1)) == 0); // Ensure that the value is POT. - if ((stride & (typeSize - 1)) || (static_cast<GLintptr>(offset) & (typeSize - 1))) { - synthesizeGLError(GL_INVALID_OPERATION, "vertexAttribIPointer", "stride or offset not valid for type"); - return; - } - GLsizei bytesPerElement = size * typeSize; - m_boundVertexArrayObject->setVertexAttribState(index, bytesPerElement, size, type, false, stride, static_cast<GLintptr>(offset), m_boundArrayBuffer); + m_boundVertexArrayObject->setArrayBufferForAttrib(index, m_boundArrayBuffer); webContext()->vertexAttribIPointer(index, size, type, stride, static_cast<GLintptr>(offset)); } @@ -1493,7 +1436,6 @@ return; } - m_boundVertexArrayObject->setVertexAttribDivisor(index, divisor); webContext()->vertexAttribDivisorANGLE(index, divisor); } @@ -1521,6 +1463,11 @@ if (!validateDrawInstanced("drawElementsInstanced", instanceCount)) return; + if (transformFeedbackActive() && !transformFeedbackPaused()) { + synthesizeGLError(GL_INVALID_OPERATION, "drawElementsInstanced", "transform feedback is active and not paused"); + return; + } + clearIfComposited(); handleTextureCompleteness("drawElementsInstanced", true); @@ -1534,6 +1481,11 @@ if (!validateDrawElements("drawRangeElements", mode, count, type, offset)) return; + if (transformFeedbackActive() && !transformFeedbackPaused()) { + synthesizeGLError(GL_INVALID_OPERATION, "drawRangeElements", "transform feedback is active and not paused"); + return; + } + clearIfComposited(); handleTextureCompleteness("drawRangeElements", true); @@ -2161,6 +2113,11 @@ return; } + if (transformFeedbackActive() && !transformFeedbackPaused()) { + synthesizeGLError(GL_INVALID_OPERATION, "bindTransformFeedback", "transform feedback is active and not paused"); + return; + } + m_transformFeedbackBinding = feedback; webContext()->bindTransformFeedback(target, objectOrZero(feedback)); @@ -2172,8 +2129,21 @@ { if (isContextLost()) return; + if (!validateTransformFeedbackPrimitiveMode("beginTransformFeedback", primitiveMode)) + return; + + if (transformFeedbackActive()) { + synthesizeGLError(GL_INVALID_OPERATION, "beginTransformFeedback", "transform feedback is active"); + return; + } webContext()->beginTransformFeedback(primitiveMode); + + // TODO(kbr): there are many more reasons BeginTransformFeedback may fail, the most + // problematic being "if any binding point used in transform feedback mode does not + // have a buffer object bound", and "if no binding points would be used". + // crbug.com/448164 + setTransformFeedbackActive(true); } void WebGL2RenderingContextBase::endTransformFeedback() @@ -2181,7 +2151,15 @@ if (isContextLost()) return; + if (!transformFeedbackActive()) { + synthesizeGLError(GL_INVALID_OPERATION, "endTransformFeedback", "transform feedback is not active"); + return; + } + webContext()->endTransformFeedback(); + + setTransformFeedbackPaused(false); + setTransformFeedbackActive(false); } void WebGL2RenderingContextBase::transformFeedbackVaryings(WebGLProgram* program, const Vector<String>& varyings, GLenum bufferMode) @@ -2252,7 +2230,14 @@ if (isContextLost()) return; + if (!transformFeedbackActive() || transformFeedbackPaused()) { + synthesizeGLError(GL_INVALID_OPERATION, "pauseTransformFeedback", "transform feedback is not active or is paused"); + return; + } + webContext()->pauseTransformFeedback(); + + setTransformFeedbackPaused(true); } void WebGL2RenderingContextBase::resumeTransformFeedback() @@ -2260,7 +2245,27 @@ if (isContextLost()) return; + if (!transformFeedbackActive() || !transformFeedbackPaused()) { + synthesizeGLError(GL_INVALID_OPERATION, "resumeTransformFeedback", "transform feedback is not active or is not paused"); + return; + } + webContext()->resumeTransformFeedback(); + + setTransformFeedbackPaused(false); +} + +bool WebGL2RenderingContextBase::validateTransformFeedbackPrimitiveMode(const char* functionName, GLenum primitiveMode) +{ + switch (primitiveMode) { + case GL_POINTS: + case GL_LINES: + case GL_TRIANGLES: + return true; + default: + synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid transform feedback primitive mode"); + return false; + } } void WebGL2RenderingContextBase::bindBufferBase(GLenum target, GLuint index, WebGLBuffer* buffer) @@ -2274,6 +2279,13 @@ buffer = 0; if (!validateAndUpdateBufferBindBaseTarget("bindBufferBase", target, index, buffer)) return; + + // ES 3.0.4 spec section 2.15.2 "Transform Feedback Primitive Capture" + if (target == GL_TRANSFORM_FEEDBACK_BUFFER && transformFeedbackActive()) { + synthesizeGLError(GL_INVALID_OPERATION, "bindBufferBase", "target is TRANSFORM_FEEDBACK_BUFFER and transform feedback is active"); + return; + } + webContext()->bindBufferBase(target, index, objectOrZero(buffer)); } @@ -2291,12 +2303,44 @@ return; } + // ES 3.0.4 spec section 2.15.2 "Transform Feedback Primitive Capture" + if (target == GL_TRANSFORM_FEEDBACK_BUFFER && transformFeedbackActive()) { + synthesizeGLError(GL_INVALID_OPERATION, "bindBufferRange", "target is TRANSFORM_FEEDBACK_BUFFER and transform feedback is active"); + return; + } + if (!validateAndUpdateBufferBindBaseTarget("bindBufferRange", target, index, buffer)) return; webContext()->bindBufferRange(target, index, objectOrZero(buffer), static_cast<GLintptr>(offset), static_cast<GLsizeiptr>(size)); } +bool WebGL2RenderingContextBase::transformFeedbackActive() const +{ + if (m_transformFeedbackBinding) + return m_transformFeedbackBinding->isActive(); + return false; +} + +bool WebGL2RenderingContextBase::transformFeedbackPaused() const +{ + if (m_transformFeedbackBinding) + return m_transformFeedbackBinding->isPaused(); + return false; +} + +void WebGL2RenderingContextBase::setTransformFeedbackActive(bool transformFeedbackActive) +{ + if (m_transformFeedbackBinding) + m_transformFeedbackBinding->setActive(transformFeedbackActive); +} + +void WebGL2RenderingContextBase::setTransformFeedbackPaused(bool transformFeedbackPaused) +{ + if (m_transformFeedbackBinding) + m_transformFeedbackBinding->setPaused(transformFeedbackPaused); +} + ScriptValue WebGL2RenderingContextBase::getIndexedParameter(ScriptState* scriptState, GLenum target, GLuint index) { if (isContextLost())
diff --git a/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.h b/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.h index e0b2e339..9370f58 100644 --- a/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.h +++ b/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.h
@@ -147,6 +147,7 @@ WebGLActiveInfo* getTransformFeedbackVarying(WebGLProgram*, GLuint); void pauseTransformFeedback(); void resumeTransformFeedback(); + bool validateTransformFeedbackPrimitiveMode(const char* functionName, GLenum primitiveMode); /* Uniform Buffer Objects and Transform Feedback Buffers */ void bindBufferBase(GLenum, GLuint, WebGLBuffer*); @@ -224,7 +225,6 @@ WebGLTexture* validateTextureBinding(const char* functionName, GLenum target, bool useSixEnumsForCubeMap) override; bool validateFramebufferTarget(GLenum target) override; bool validateReadPixelsFormatAndType(GLenum format, GLenum type) override; - bool validateVertexAttribPointerTypeAndSize(GLenum type, GLint size) override; DOMArrayBufferView::ViewType readPixelsExpectedArrayBufferViewType(GLenum type) override; WebGLFramebuffer* getFramebufferBinding(GLenum target) override; @@ -244,6 +244,11 @@ void resetUnpackParameters() override; void restoreUnpackParameters() override; + bool transformFeedbackActive() const override; + bool transformFeedbackPaused() const override; + void setTransformFeedbackActive(bool); + void setTransformFeedbackPaused(bool); + PersistentWillBeMember<WebGLFramebuffer> m_readFramebufferBinding; PersistentWillBeMember<WebGLTransformFeedback> m_transformFeedbackBinding; GLint m_maxArrayTextureLayers;
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp index ad83707..6eb6c9f 100644 --- a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp +++ b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
@@ -1412,34 +1412,6 @@ return isContextLost() ? 0 : drawingBuffer()->size().height(); } -unsigned WebGLRenderingContextBase::sizeInBytes(GLenum type) const -{ - switch (type) { - case GL_BYTE: - return sizeof(GLbyte); - case GL_UNSIGNED_BYTE: - return sizeof(GLubyte); - case GL_SHORT: - return sizeof(GLshort); - case GL_UNSIGNED_SHORT: - return sizeof(GLushort); - case GL_INT: - return sizeof(GLint); - case GL_UNSIGNED_INT: - return sizeof(GLuint); - case GL_FLOAT: - return sizeof(GLfloat); - case GL_HALF_FLOAT: - return sizeof(GLushort); - case GL_INT_2_10_10_10_REV: - return sizeof(GLint); - case GL_UNSIGNED_INT_2_10_10_10_REV: - return sizeof(GLuint); - } - ASSERT_NOT_REACHED(); - return 0; -} - void WebGLRenderingContextBase::activeTexture(GLenum texture) { if (isContextLost()) @@ -2278,9 +2250,6 @@ return; } - WebGLVertexArrayObjectBase::VertexAttribState* state = m_boundVertexArrayObject->getVertexAttribState(index); - state->enabled = false; - webContext()->disableVertexAttribArray(index); } @@ -2325,6 +2294,11 @@ if (!validateDrawElements("drawElements", mode, count, type, offset)) return; + if (transformFeedbackActive() && !transformFeedbackPaused()) { + synthesizeGLError(GL_INVALID_OPERATION, "drawElements", "transform feedback is active and not paused"); + return; + } + clearIfComposited(); handleTextureCompleteness("drawElements", true); @@ -2390,9 +2364,6 @@ return; } - WebGLVertexArrayObjectBase::VertexAttribState* state = m_boundVertexArrayObject->getVertexAttribState(index); - state->enabled = true; - webContext()->enableVertexAttribArray(index); } @@ -3498,27 +3469,38 @@ synthesizeGLError(GL_INVALID_VALUE, "getVertexAttrib", "index out of range"); return ScriptValue::createNull(scriptState); } - const WebGLVertexArrayObjectBase::VertexAttribState* state = m_boundVertexArrayObject->getVertexAttribState(index); if ((extensionEnabled(ANGLEInstancedArraysName) || isWebGL2OrHigher()) && pname == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE) - return WebGLAny(scriptState, state->divisor); + { + GLint value = 0; + webContext()->getVertexAttribiv(index, pname, &value); + return WebGLAny(scriptState, value); + } switch (pname) { case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING: - if (!state->bufferBinding || !state->bufferBinding->object()) - return ScriptValue::createNull(scriptState); - return WebGLAny(scriptState, state->bufferBinding.get()); + return WebGLAny(scriptState, m_boundVertexArrayObject->getArrayBufferForAttrib(index)); case GL_VERTEX_ATTRIB_ARRAY_ENABLED: - return WebGLAny(scriptState, state->enabled); case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED: - return WebGLAny(scriptState, state->normalized); + { + GLint value = 0; + webContext()->getVertexAttribiv(index, pname, &value); + return WebGLAny(scriptState, static_cast<bool>(value)); + } case GL_VERTEX_ATTRIB_ARRAY_SIZE: - return WebGLAny(scriptState, state->size); case GL_VERTEX_ATTRIB_ARRAY_STRIDE: - return WebGLAny(scriptState, state->originalStride); + { + GLint value = 0; + webContext()->getVertexAttribiv(index, pname, &value); + return WebGLAny(scriptState, value); + } case GL_VERTEX_ATTRIB_ARRAY_TYPE: - return WebGLAny(scriptState, state->type); + { + GLint value = 0; + webContext()->getVertexAttribiv(index, pname, &value); + return WebGLAny(scriptState, static_cast<GLenum>(value)); + } case GL_CURRENT_VERTEX_ATTRIB: { VertexAttribValue& attribValue = m_vertexAttribValue[index]; @@ -4448,7 +4430,7 @@ webContext()->framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, targetTexture, 0); webContext()->bindTexture(texture->getTarget(), texture->object()); if (functionType == TexImage2DByGPU) { - webContext()->copyTexImage2D(target, level, internalformat, 0, 0, canvas->width(), canvas->height(), 0); + webContext()->copyTexSubImage2D(target, level, 0, 0, 0, 0, canvas->width(), canvas->height()); } else if (functionType == TexSubImage2DByGPU) { webContext()->copyTexSubImage2D(target, level, xoffset, yoffset, 0, 0, canvas->width(), canvas->height()); } else if (functionType == TexSubImage3DByGPU) { @@ -4479,6 +4461,7 @@ return; } + texImage2DBase(target, level, internalformat, canvas->width(), canvas->height(), 0, format, type, 0); texImageCanvasByGPU(TexImage2DByGPU, texture, target, level, internalformat, type, 0, 0, 0, canvas); texture->setLevelInfo(target, level, internalformat, canvas->width(), canvas->height(), 1, type); } @@ -5066,6 +5049,12 @@ synthesizeGLError(GL_INVALID_OPERATION, "useProgram", "program not valid"); return; } + + if (transformFeedbackActive() && !transformFeedbackPaused()) { + synthesizeGLError(GL_INVALID_OPERATION, "useProgram", "transform feedback is active and not paused"); + return; + } + if (m_currentProgram != program) { if (m_currentProgram) m_currentProgram->onDetached(webContext()); @@ -5144,52 +5133,22 @@ vertexAttribfvImpl("vertexAttrib4fv", index, v.data(), v.size(), 4); } -bool WebGLRenderingContextBase::validateVertexAttribPointerTypeAndSize(GLenum type, GLint size) -{ - switch (type) { - case GL_BYTE: - case GL_UNSIGNED_BYTE: - case GL_SHORT: - case GL_UNSIGNED_SHORT: - case GL_FLOAT: - if (size < 1 || size > 4) { - synthesizeGLError(GL_INVALID_VALUE, "vertexAttribPointer", "bad size"); - return false; - } - return true; - default: - synthesizeGLError(GL_INVALID_ENUM, "vertexAttribPointer", "invalid type"); - return false; - } -} - void WebGLRenderingContextBase::vertexAttribPointer(ScriptState* scriptState, GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, long long offset) { - if (isContextLost() || !validateVertexAttribPointerTypeAndSize(type, size)) + if (isContextLost()) return; if (index >= m_maxVertexAttribs) { synthesizeGLError(GL_INVALID_VALUE, "vertexAttribPointer", "index out of range"); return; } - if (stride < 0 || stride > 255) { - synthesizeGLError(GL_INVALID_VALUE, "vertexAttribPointer", "bad stride"); - return; - } if (!validateValueFitNonNegInt32("vertexAttribPointer", "offset", offset)) return; if (!m_boundArrayBuffer) { synthesizeGLError(GL_INVALID_OPERATION, "vertexAttribPointer", "no bound ARRAY_BUFFER"); return; } - unsigned typeSize = sizeInBytes(type); - ASSERT((typeSize & (typeSize - 1)) == 0); // Ensure that the value is POT. - if ((stride & (typeSize - 1)) || (static_cast<GLintptr>(offset) & (typeSize - 1))) { - synthesizeGLError(GL_INVALID_OPERATION, "vertexAttribPointer", "stride or offset not valid for type"); - return; - } - GLsizei bytesPerElement = size * typeSize; - m_boundVertexArrayObject->setVertexAttribState(index, bytesPerElement, size, type, normalized, stride, static_cast<GLintptr>(offset), m_boundArrayBuffer); + m_boundVertexArrayObject->setArrayBufferForAttrib(index, m_boundArrayBuffer.get()); webContext()->vertexAttribPointer(index, size, type, normalized, stride, static_cast<GLintptr>(offset)); maybePreserveDefaultVAOObjectWrapper(scriptState); preserveObjectWrapper(scriptState, m_boundVertexArrayObject, "arraybuffer", index, m_boundArrayBuffer); @@ -5205,7 +5164,6 @@ return; } - m_boundVertexArrayObject->setVertexAttribDivisor(index, divisor); webContext()->vertexAttribDivisorANGLE(index, divisor); }
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h index 53bc5d0..26b1f063 100644 --- a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h +++ b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h
@@ -907,9 +907,6 @@ // are valid. Otherwise, generates appropriate error and returns false. bool validateReadPixelsFuncParameters(GLsizei width, GLsizei height, GLenum format, GLenum type, long long bufferSize); - // Helper function to check type and size of vertexAttribPointer. Return true if type and size are valid. Otherwise, generates appropriates error and return false. - virtual bool validateVertexAttribPointerTypeAndSize(GLenum type, GLint size); - virtual GLint getMaxTextureLevelForTarget(GLenum target); // Helper function to check input level for functions {copy}Tex{Sub}Image. @@ -1133,6 +1130,9 @@ // JavaScript). void maybePreserveDefaultVAOObjectWrapper(ScriptState*); + virtual bool transformFeedbackActive() const { return false; } + virtual bool transformFeedbackPaused() const { return false; } + friend class WebGLStateRestorer; friend class WebGLRenderingContextEvictionManager;
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLTransformFeedback.cpp b/third_party/WebKit/Source/modules/webgl/WebGLTransformFeedback.cpp index d460f7b..4f122f4 100644 --- a/third_party/WebKit/Source/modules/webgl/WebGLTransformFeedback.cpp +++ b/third_party/WebKit/Source/modules/webgl/WebGLTransformFeedback.cpp
@@ -22,6 +22,8 @@ WebGLTransformFeedback::WebGLTransformFeedback(WebGL2RenderingContextBase* ctx) : WebGLSharedPlatform3DObject(ctx) , m_target(0) + , m_active(false) + , m_paused(false) { setObject(ctx->webContext()->createTransformFeedback()); } @@ -40,4 +42,14 @@ m_target = target; } +void WebGLTransformFeedback::setActive(bool active) +{ + m_active = active; +} + +void WebGLTransformFeedback::setPaused(bool paused) +{ + m_paused = paused; +} + } // namespace blink
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLTransformFeedback.h b/third_party/WebKit/Source/modules/webgl/WebGLTransformFeedback.h index da427c7..452d886c 100644 --- a/third_party/WebKit/Source/modules/webgl/WebGLTransformFeedback.h +++ b/third_party/WebKit/Source/modules/webgl/WebGLTransformFeedback.h
@@ -24,6 +24,11 @@ bool hasEverBeenBound() const { return object() && m_target; } + bool isActive() const { return m_active; } + bool isPaused() const { return m_paused; } + void setActive(bool); + void setPaused(bool); + protected: explicit WebGLTransformFeedback(WebGL2RenderingContextBase*); @@ -33,6 +38,9 @@ bool isTransformFeedback() const override { return true; } GLenum m_target; + + bool m_active; + bool m_paused; }; } // namespace blink
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLVertexArrayObjectBase.cpp b/third_party/WebKit/Source/modules/webgl/WebGLVertexArrayObjectBase.cpp index 4d2e6bca..3bf1069 100644 --- a/third_party/WebKit/Source/modules/webgl/WebGLVertexArrayObjectBase.cpp +++ b/third_party/WebKit/Source/modules/webgl/WebGLVertexArrayObjectBase.cpp
@@ -16,7 +16,7 @@ , m_destructionInProgress(false) , m_boundElementArrayBuffer(nullptr) { - m_vertexAttribState.reserveCapacity(ctx->maxVertexAttribs()); + m_arrayBufferList.resize(ctx->maxVertexAttribs()); switch (m_type) { case VaoTypeDefault: @@ -43,10 +43,9 @@ if (m_boundElementArrayBuffer) m_boundElementArrayBuffer->onDetached(context3d); - for (size_t i = 0; i < m_vertexAttribState.size(); ++i) { - VertexAttribState* state = m_vertexAttribState[i].get(); - if (state->bufferBinding) - state->bufferBinding->onDetached(context3d); + for (size_t i = 0; i < m_arrayBufferList.size(); ++i) { + if (m_arrayBufferList[i]) + m_arrayBufferList[i]->onDetached(context3d); } } @@ -78,34 +77,20 @@ m_boundElementArrayBuffer = buffer; } -WebGLVertexArrayObjectBase::VertexAttribState* WebGLVertexArrayObjectBase::getVertexAttribState(size_t index) +WebGLBuffer* WebGLVertexArrayObjectBase::getArrayBufferForAttrib(size_t index) { ASSERT(index < context()->maxVertexAttribs()); - // Lazily create the vertex attribute states. - for (size_t i = m_vertexAttribState.size(); i <= index; i++) - m_vertexAttribState.append(new VertexAttribState); - return m_vertexAttribState[index].get(); + return m_arrayBufferList[index].get(); } -void WebGLVertexArrayObjectBase::setVertexAttribState( - GLuint index, GLsizei bytesPerElement, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLintptr offset, WebGLBuffer* buffer) +void WebGLVertexArrayObjectBase::setArrayBufferForAttrib(GLuint index, WebGLBuffer* buffer) { - GLsizei validatedStride = stride ? stride : bytesPerElement; - VertexAttribState* state = getVertexAttribState(index); - if (buffer) buffer->onAttached(); - if (state->bufferBinding) - state->bufferBinding->onDetached(context()->webContext()); + if (m_arrayBufferList[index]) + m_arrayBufferList[index]->onDetached(context()->webContext()); - state->bufferBinding = buffer; - state->bytesPerElement = bytesPerElement; - state->size = size; - state->type = type; - state->normalized = normalized; - state->stride = validatedStride; - state->originalStride = stride; - state->offset = offset; + m_arrayBufferList[index] = buffer; } void WebGLVertexArrayObjectBase::unbindBuffer(WebGLBuffer* buffer) @@ -115,30 +100,18 @@ m_boundElementArrayBuffer = nullptr; } - for (size_t i = 0; i < m_vertexAttribState.size(); ++i) { - VertexAttribState* state = m_vertexAttribState[i]; - if (state->bufferBinding == buffer) { - buffer->onDetached(context()->webContext()); - state->bufferBinding = nullptr; + for (size_t i = 0; i < m_arrayBufferList.size(); ++i) { + if (m_arrayBufferList[i] == buffer) { + m_arrayBufferList[i]->onDetached(context()->webContext()); + m_arrayBufferList[i] = nullptr; } } } -void WebGLVertexArrayObjectBase::setVertexAttribDivisor(GLuint index, GLuint divisor) -{ - VertexAttribState* state = getVertexAttribState(index); - state->divisor = divisor; -} - -DEFINE_TRACE(WebGLVertexArrayObjectBase::VertexAttribState) -{ - visitor->trace(bufferBinding); -} - DEFINE_TRACE(WebGLVertexArrayObjectBase) { visitor->trace(m_boundElementArrayBuffer); - visitor->trace(m_vertexAttribState); + visitor->trace(m_arrayBufferList); WebGLContextObject::trace(visitor); }
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLVertexArrayObjectBase.h b/third_party/WebKit/Source/modules/webgl/WebGLVertexArrayObjectBase.h index e9192af..ba6b1b2 100644 --- a/third_party/WebKit/Source/modules/webgl/WebGLVertexArrayObjectBase.h +++ b/third_party/WebKit/Source/modules/webgl/WebGLVertexArrayObjectBase.h
@@ -22,36 +22,6 @@ Platform3DObject object() const { return m_object; } - // Cached values for vertex attrib range checks - class VertexAttribState final : public GarbageCollected<VertexAttribState> { - public: - VertexAttribState() - : enabled(false) - , bytesPerElement(0) - , size(4) - , type(GL_FLOAT) - , normalized(false) - , stride(16) - , originalStride(0) - , offset(0) - , divisor(0) - { - } - - DECLARE_TRACE(); - - bool enabled; - Member<WebGLBuffer> bufferBinding; - GLsizei bytesPerElement; - GLint size; - GLenum type; - bool normalized; - GLsizei stride; - GLsizei originalStride; - GLintptr offset; - GLuint divisor; - }; - bool isDefaultObject() const { return m_type == VaoTypeDefault; } bool hasEverBeenBound() const { return object() && m_hasEverBeenBound; } @@ -60,10 +30,9 @@ WebGLBuffer* boundElementArrayBuffer() const { return m_boundElementArrayBuffer; } void setElementArrayBuffer(WebGLBuffer*); - VertexAttribState* getVertexAttribState(size_t); - void setVertexAttribState(GLuint, GLsizei, GLint, GLenum, GLboolean, GLsizei, GLintptr, WebGLBuffer*); + WebGLBuffer* getArrayBufferForAttrib(size_t); + void setArrayBufferForAttrib(GLuint, WebGLBuffer*); void unbindBuffer(WebGLBuffer*); - void setVertexAttribDivisor(GLuint index, GLuint divisor); DECLARE_VIRTUAL_TRACE(); @@ -81,7 +50,7 @@ bool m_hasEverBeenBound; bool m_destructionInProgress; Member<WebGLBuffer> m_boundElementArrayBuffer; - HeapVector<Member<VertexAttribState>> m_vertexAttribState; + HeapVector<Member<WebGLBuffer>> m_arrayBufferList; }; } // namespace blink
diff --git a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in index fac272d..d85f1cd 100644 --- a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in +++ b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in
@@ -169,7 +169,6 @@ SlimmingPaintV2 SlimmingPaintOffsetCaching implied_by=SlimmingPaintV2 SlimmingPaintStrictCullRectClipping -SlimmingPaintSynchronizedPainting implied_by=SlimmingPaintV2, status=stable SlimmingPaintUnderInvalidationChecking StackedCSSPropertyAnimations status=experimental StyleSharing status=stable
diff --git a/third_party/WebKit/Source/platform/blink_platform.gypi b/third_party/WebKit/Source/platform/blink_platform.gypi index bf8b597..b974e62 100644 --- a/third_party/WebKit/Source/platform/blink_platform.gypi +++ b/third_party/WebKit/Source/platform/blink_platform.gypi
@@ -335,7 +335,6 @@ 'exported/WebSocketHandshakeRequestInfo.cpp', 'exported/WebSocketHandshakeResponseInfo.cpp', 'exported/WebSourceInfo.cpp', - 'exported/WebSkImage.cpp', 'exported/WebSpeechSynthesisUtterance.cpp', 'exported/WebSpeechSynthesisVoice.cpp', 'exported/WebSpeechSynthesizerClientImpl.cpp', @@ -438,6 +437,8 @@ 'fonts/shaping/ShapeCache.h', 'fonts/shaping/ShapeResult.cpp', 'fonts/shaping/ShapeResult.h', + 'fonts/shaping/ShapeResultBuffer.cpp', + 'fonts/shaping/ShapeResultBuffer.h', 'fonts/shaping/ShapeResultInlineHeaders.h', 'fonts/shaping/ShapeResultTestInfo.cpp', 'fonts/shaping/ShapeResultTestInfo.h',
diff --git a/third_party/WebKit/Source/platform/exported/WebActiveGestureAnimation.h b/third_party/WebKit/Source/platform/exported/WebActiveGestureAnimation.h index 289c6aa8..4510ff8 100644 --- a/third_party/WebKit/Source/platform/exported/WebActiveGestureAnimation.h +++ b/third_party/WebKit/Source/platform/exported/WebActiveGestureAnimation.h
@@ -27,6 +27,7 @@ #define WebActiveGestureAnimation_h #include "platform/PlatformExport.h" +#include "wtf/Allocator.h" #include "wtf/Noncopyable.h" #include "wtf/OwnPtr.h" #include "wtf/PassOwnPtr.h" @@ -41,6 +42,7 @@ // to a target, again via a generic interface. It is assumed that animate() is called // on a more-or-less regular basis by the owner. class PLATFORM_EXPORT WebActiveGestureAnimation { + USING_FAST_MALLOC(WebActiveGestureAnimation); WTF_MAKE_NONCOPYABLE(WebActiveGestureAnimation); public: static PassOwnPtr<WebActiveGestureAnimation> createAtAnimationStart(PassOwnPtr<WebGestureCurve>, WebGestureCurveTarget*);
diff --git a/third_party/WebKit/Source/platform/exported/WebScrollbarImpl.h b/third_party/WebKit/Source/platform/exported/WebScrollbarImpl.h index 0815757..a72fb49 100644 --- a/third_party/WebKit/Source/platform/exported/WebScrollbarImpl.h +++ b/third_party/WebKit/Source/platform/exported/WebScrollbarImpl.h
@@ -28,11 +28,15 @@ #include "platform/PlatformExport.h" #include "platform/heap/Handle.h" #include "public/platform/WebScrollbar.h" +#include "wtf/Allocator.h" +#include "wtf/Noncopyable.h" namespace blink { class Scrollbar; class PLATFORM_EXPORT WebScrollbarImpl final : public WebScrollbar { + USING_FAST_MALLOC(WebScrollbarImpl); + WTF_MAKE_NONCOPYABLE(WebScrollbarImpl); public: static WebScrollbarImpl* create(Scrollbar* scrollbar) {
diff --git a/third_party/WebKit/Source/platform/exported/WebScrollbarThemeClientImpl.h b/third_party/WebKit/Source/platform/exported/WebScrollbarThemeClientImpl.h index 4edba3f..5c6a96f 100644 --- a/third_party/WebKit/Source/platform/exported/WebScrollbarThemeClientImpl.h +++ b/third_party/WebKit/Source/platform/exported/WebScrollbarThemeClientImpl.h
@@ -29,12 +29,14 @@ #include "platform/PlatformExport.h" #include "platform/scroll/ScrollbarThemeClient.h" #include "public/platform/WebScrollbar.h" +#include "wtf/Allocator.h" #include "wtf/Noncopyable.h" namespace blink { // Adapts a WebScrollbar to the ScrollbarThemeClient interface class PLATFORM_EXPORT WebScrollbarThemeClientImpl : public ScrollbarThemeClient { + DISALLOW_NEW(); WTF_MAKE_NONCOPYABLE(WebScrollbarThemeClientImpl); public: // Caller must retain ownership of this pointer and ensure that its lifetime
diff --git a/third_party/WebKit/Source/platform/exported/WebScrollbarThemeGeometryNative.h b/third_party/WebKit/Source/platform/exported/WebScrollbarThemeGeometryNative.h index 29f80f9..e5392c3 100644 --- a/third_party/WebKit/Source/platform/exported/WebScrollbarThemeGeometryNative.h +++ b/third_party/WebKit/Source/platform/exported/WebScrollbarThemeGeometryNative.h
@@ -29,6 +29,8 @@ #include "platform/PlatformExport.h" #include "public/platform/WebRect.h" #include "public/platform/WebScrollbarThemeGeometry.h" +#include "wtf/Allocator.h" +#include "wtf/Noncopyable.h" #include "wtf/PassOwnPtr.h" namespace blink { @@ -37,6 +39,8 @@ class WebScrollbar; class PLATFORM_EXPORT WebScrollbarThemeGeometryNative : public WebScrollbarThemeGeometry { + USING_FAST_MALLOC(WebScrollbarThemeGeometryNative); + WTF_MAKE_NONCOPYABLE(WebScrollbarThemeGeometryNative); public: static PassOwnPtr<WebScrollbarThemeGeometryNative> create(ScrollbarTheme&);
diff --git a/third_party/WebKit/Source/platform/exported/WebSkImage.cpp b/third_party/WebKit/Source/platform/exported/WebSkImage.cpp deleted file mode 100644 index d5b752f..0000000 --- a/third_party/WebKit/Source/platform/exported/WebSkImage.cpp +++ /dev/null
@@ -1,55 +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 "public/platform/WebSkImage.h" - -#include "wtf/PassRefPtr.h" - -namespace blink { - -WebSkImage::WebSkImage() -{ -} - -WebSkImage::WebSkImage(const WebSkImage& image) -{ - m_image = image.m_image; -} - -WebSkImage::~WebSkImage() -{ - m_image.reset(); -} - -int WebSkImage::width() const -{ - return m_image->width(); -} - -int WebSkImage::height() const -{ - return m_image->height(); -} - -bool WebSkImage::readPixels(const SkImageInfo& dstInfo, - void* dstPixels, - size_t dstRowBytes, - int srcX, - int srcY) const -{ - return m_image->readPixels(dstInfo, dstPixels, dstRowBytes, srcX, srcY); -} - -WebSkImage::WebSkImage(const PassRefPtr<SkImage>& image) - : m_image(image) -{ -} - -WebSkImage& WebSkImage::operator=(const WTF::PassRefPtr<SkImage>& image) -{ - m_image = image; - return *this; -} - -} // namespace blink
diff --git a/third_party/WebKit/Source/platform/exported/WebURLRequest.cpp b/third_party/WebKit/Source/platform/exported/WebURLRequest.cpp index fc29fd6e..7369ba5c 100644 --- a/third_party/WebKit/Source/platform/exported/WebURLRequest.cpp +++ b/third_party/WebKit/Source/platform/exported/WebURLRequest.cpp
@@ -36,6 +36,8 @@ #include "public/platform/WebHTTPHeaderVisitor.h" #include "public/platform/WebSecurityOrigin.h" #include "public/platform/WebURL.h" +#include "wtf/Allocator.h" +#include "wtf/Noncopyable.h" namespace blink { @@ -62,7 +64,8 @@ // The standard implementation of WebURLRequestPrivate, which maintains // ownership of a ResourceRequest instance. -class WebURLRequestPrivateImpl : public WebURLRequestPrivate { +class WebURLRequestPrivateImpl final : public WebURLRequestPrivate { + USING_FAST_MALLOC(WebURLRequestPrivate); public: WebURLRequestPrivateImpl() {
diff --git a/third_party/WebKit/Source/platform/exported/WebURLRequestPrivate.h b/third_party/WebKit/Source/platform/exported/WebURLRequestPrivate.h index c6261c572..3163a9b 100644 --- a/third_party/WebKit/Source/platform/exported/WebURLRequestPrivate.h +++ b/third_party/WebKit/Source/platform/exported/WebURLRequestPrivate.h
@@ -31,11 +31,14 @@ #ifndef WebURLRequestPrivate_h #define WebURLRequestPrivate_h +#include "wtf/Noncopyable.h" + namespace blink { class ResourceRequest; class WebURLRequestPrivate { + WTF_MAKE_NONCOPYABLE(WebURLRequestPrivate); public: WebURLRequestPrivate() : m_resourceRequest(0)
diff --git a/third_party/WebKit/Source/platform/exported/WebURLResponse.cpp b/third_party/WebKit/Source/platform/exported/WebURLResponse.cpp index 8d95476..d00ddd2 100644 --- a/third_party/WebKit/Source/platform/exported/WebURLResponse.cpp +++ b/third_party/WebKit/Source/platform/exported/WebURLResponse.cpp
@@ -38,6 +38,7 @@ #include "public/platform/WebString.h" #include "public/platform/WebURL.h" #include "public/platform/WebURLLoadTiming.h" +#include "wtf/Allocator.h" #include "wtf/RefPtr.h" namespace blink { @@ -65,7 +66,8 @@ // The standard implementation of WebURLResponsePrivate, which maintains // ownership of a ResourceResponse instance. -class WebURLResponsePrivateImpl : public WebURLResponsePrivate { +class WebURLResponsePrivateImpl final : public WebURLResponsePrivate { + USING_FAST_MALLOC(WebURLResponsePrivateImpl); public: WebURLResponsePrivateImpl() {
diff --git a/third_party/WebKit/Source/platform/exported/WebURLResponsePrivate.h b/third_party/WebKit/Source/platform/exported/WebURLResponsePrivate.h index 6a408f3..81cb5c06 100644 --- a/third_party/WebKit/Source/platform/exported/WebURLResponsePrivate.h +++ b/third_party/WebKit/Source/platform/exported/WebURLResponsePrivate.h
@@ -32,12 +32,14 @@ #define WebURLResponsePrivate_h #include "public/platform/WebString.h" +#include "wtf/Noncopyable.h" namespace blink { class ResourceResponse; class WebURLResponsePrivate { + WTF_MAKE_NONCOPYABLE(WebURLResponsePrivate); public: WebURLResponsePrivate() : m_resourceResponse(0) { }
diff --git a/third_party/WebKit/Source/platform/exported/WrappedResourceRequest.h b/third_party/WebKit/Source/platform/exported/WrappedResourceRequest.h index 901aeb0..a81d5f79 100644 --- a/third_party/WebKit/Source/platform/exported/WrappedResourceRequest.h +++ b/third_party/WebKit/Source/platform/exported/WrappedResourceRequest.h
@@ -33,6 +33,8 @@ #include "platform/exported/WebURLRequestPrivate.h" #include "public/platform/WebURLRequest.h" +#include "wtf/Allocator.h" +#include "wtf/Noncopyable.h" namespace blink { @@ -67,8 +69,11 @@ } private: - class Handle : public WebURLRequestPrivate { + class Handle final : public WebURLRequestPrivate { + DISALLOW_NEW(); public: + Handle() { } + virtual void dispose() { m_resourceRequest = 0; } };
diff --git a/third_party/WebKit/Source/platform/exported/WrappedResourceResponse.h b/third_party/WebKit/Source/platform/exported/WrappedResourceResponse.h index 355fefc..0f9c75a 100644 --- a/third_party/WebKit/Source/platform/exported/WrappedResourceResponse.h +++ b/third_party/WebKit/Source/platform/exported/WrappedResourceResponse.h
@@ -33,6 +33,7 @@ #include "platform/exported/WebURLResponsePrivate.h" #include "public/platform/WebURLResponse.h" +#include "wtf/Allocator.h" namespace blink { @@ -68,6 +69,7 @@ private: class Handle : public WebURLResponsePrivate { + DISALLOW_NEW(); public: virtual void dispose() { m_resourceResponse = 0; } };
diff --git a/third_party/WebKit/Source/platform/exported/linux/WebFontInfo.cpp b/third_party/WebKit/Source/platform/exported/linux/WebFontInfo.cpp index c186dbc..681c977 100644 --- a/third_party/WebKit/Source/platform/exported/linux/WebFontInfo.cpp +++ b/third_party/WebKit/Source/platform/exported/linux/WebFontInfo.cpp
@@ -31,6 +31,7 @@ #include "public/platform/linux/WebFontInfo.h" #include "public/platform/linux/WebFallbackFont.h" +#include "wtf/Allocator.h" #include "wtf/HashMap.h" #include "wtf/Noncopyable.h" #include "wtf/OwnPtr.h" @@ -45,6 +46,7 @@ namespace blink { class CachedFont { + DISALLOW_NEW_EXCEPT_PLACEMENT_NEW(); public: // Note: We pass the charset explicitly as callers // should not create CachedFont entries without knowing @@ -120,6 +122,7 @@ class CachedFontSet { WTF_MAKE_NONCOPYABLE(CachedFontSet); + USING_FAST_MALLOC(CachedFontSet); public: // CachedFontSet takes ownership of the passed FcFontSet. static PassOwnPtr<CachedFontSet> createForLocale(const char* locale) @@ -219,6 +222,8 @@ }; class FontSetCache { + WTF_MAKE_NONCOPYABLE(FontSetCache); + USING_FAST_MALLOC(FontSetCache); public: static FontSetCache& shared() { @@ -248,6 +253,8 @@ // FIXME: We may wish to add a way to prune the cache at a later time. private: + FontSetCache() { } + // FIXME: This shouldn't need to be AtomicString, but // currently HashTraits<const char*> isn't smart enough // to hash the string (only does pointer compares).
diff --git a/third_party/WebKit/Source/platform/fonts/Font.cpp b/third_party/WebKit/Source/platform/fonts/Font.cpp index 4a39f1d..17150794 100644 --- a/third_party/WebKit/Source/platform/fonts/Font.cpp +++ b/third_party/WebKit/Source/platform/fonts/Font.cpp
@@ -437,12 +437,6 @@ if (fontDescription().textRendering() == OptimizeLegibility || fontDescription().textRendering() == GeometricPrecision) return ComplexPath; - if (run.codePath() == TextRun::ForceComplex) - return ComplexPath; - - if (run.codePath() == TextRun::ForceSimple) - return SimplePath; - if (run.is8Bit()) return SimplePath;
diff --git a/third_party/WebKit/Source/platform/fonts/FontPlatformDataTest.cpp b/third_party/WebKit/Source/platform/fonts/FontPlatformDataTest.cpp index 7fe1929..c7ebf385 100644 --- a/third_party/WebKit/Source/platform/fonts/FontPlatformDataTest.cpp +++ b/third_party/WebKit/Source/platform/fonts/FontPlatformDataTest.cpp
@@ -32,14 +32,14 @@ #include "platform/fonts/TestFontSelector.h" #include "platform/fonts/TypesettingFeatures.h" -#include "public/platform/WebUnitTestSupport.h" +#include "platform/testing/UnitTestHelpers.h" #include "testing/gtest/include/gtest/gtest.h" namespace blink { static inline String fontPath(String relativePath) { - return Platform::current()->unitTestSupport()->webKitRootDir() + return testing::blinkRootDir() + String("/Source/platform/testing/data/") + relativePath; }
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/CachingWordShaper.cpp b/third_party/WebKit/Source/platform/fonts/shaping/CachingWordShaper.cpp index 5493f85..f89d9178 100644 --- a/third_party/WebKit/Source/platform/fonts/shaping/CachingWordShaper.cpp +++ b/third_party/WebKit/Source/platform/fonts/shaping/CachingWordShaper.cpp
@@ -29,6 +29,7 @@ #include "platform/fonts/shaping/CachingWordShapeIterator.h" #include "platform/fonts/shaping/HarfBuzzShaper.h" #include "platform/fonts/shaping/ShapeCache.h" +#include "platform/fonts/shaping/ShapeResultBuffer.h" #include "wtf/text/CharacterNames.h" namespace blink { @@ -60,17 +61,17 @@ static inline float shapeResultsForRun(ShapeCache* shapeCache, const Font* font, const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, - Vector<RefPtr<ShapeResult>>* results) + ShapeResultBuffer* resultsBuffer) { CachingWordShapeIterator iterator(shapeCache, run, font); RefPtr<ShapeResult> wordResult; float totalWidth = 0; while (iterator.next(&wordResult)) { if (wordResult) { - results->append(wordResult); totalWidth += wordResult->width(); if (fallbackFonts) wordResult->fallbackFonts(fallbackFonts); + resultsBuffer->appendResult(wordResult.release()); } } return totalWidth; @@ -78,42 +79,40 @@ int CachingWordShaper::offsetForPosition(const Font* font, const TextRun& run, float targetX) { - Vector<RefPtr<ShapeResult>> results; - shapeResultsForRun(m_shapeCache, font, run, nullptr, &results); + ShapeResultBuffer buffer; + shapeResultsForRun(m_shapeCache, font, run, nullptr, &buffer); - return ShapeResult::offsetForPosition(results, run, targetX); + return buffer.offsetForPosition(run, targetX); } float CachingWordShaper::fillGlyphBuffer(const Font* font, const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, GlyphBuffer* glyphBuffer, unsigned from, unsigned to) { - Vector<RefPtr<ShapeResult>> results; - shapeResultsForRun(m_shapeCache, font, run, fallbackFonts, &results); + ShapeResultBuffer buffer; + shapeResultsForRun(m_shapeCache, font, run, fallbackFonts, &buffer); - return ShapeResult::fillGlyphBuffer(results, glyphBuffer, run, from, to); + return buffer.fillGlyphBuffer(glyphBuffer, run, from, to); } float CachingWordShaper::fillGlyphBufferForTextEmphasis(const Font* font, const TextRun& run, const GlyphData* emphasisData, GlyphBuffer* glyphBuffer, unsigned from, unsigned to) { - Vector<RefPtr<ShapeResult>> results; - shapeResultsForRun(m_shapeCache, font, run, nullptr, &results); + ShapeResultBuffer buffer; + shapeResultsForRun(m_shapeCache, font, run, nullptr, &buffer); - return ShapeResult::fillGlyphBufferForTextEmphasis(results, glyphBuffer, - run, emphasisData, from, to); + return buffer.fillGlyphBufferForTextEmphasis(glyphBuffer, run, emphasisData, from, to); } FloatRect CachingWordShaper::selectionRect(const Font* font, const TextRun& run, const FloatPoint& point, int height, unsigned from, unsigned to) { - Vector<RefPtr<ShapeResult>> results; + ShapeResultBuffer buffer; float totalWidth = shapeResultsForRun(m_shapeCache, font, run, nullptr, - &results); + &buffer); - return ShapeResult::selectionRect(results, run.direction(), totalWidth, - point, height, from, to); + return buffer.selectionRect(run.direction(), totalWidth, point, height, from, to); } }; // namespace blink
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaper.cpp b/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaper.cpp index 0074064..0f9f2b3 100644 --- a/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaper.cpp +++ b/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaper.cpp
@@ -634,15 +634,19 @@ { ASSERT(numGlyphs > 0); OwnPtr<ShapeResult::RunInfo> run(std::move(runToInsert)); + ASSERT(numGlyphs == run->m_glyphData.size()); const SimpleFontData* currentFontData = run->m_fontData.get(); - hb_glyph_info_t* glyphInfos = hb_buffer_get_glyph_infos(harfBuzzBuffer, 0); - hb_glyph_position_t* glyphPositions = hb_buffer_get_glyph_positions(harfBuzzBuffer, 0); + const hb_glyph_info_t* glyphInfos = hb_buffer_get_glyph_infos(harfBuzzBuffer, 0); + const hb_glyph_position_t* glyphPositions = hb_buffer_get_glyph_positions(harfBuzzBuffer, 0); + const unsigned startCluster = HB_DIRECTION_IS_FORWARD(hb_buffer_get_direction(harfBuzzBuffer)) + ? glyphInfos[startGlyph].cluster : glyphInfos[startGlyph + numGlyphs - 1].cluster; float totalAdvance = 0.0f; FloatPoint glyphOrigin; float offsetX, offsetY; float* directionOffset = m_font->fontDescription().isVerticalAnyUpright() ? &offsetY : &offsetX; + bool hasVerticalOffsets = !HB_DIRECTION_IS_HORIZONTAL(run->m_direction); // HarfBuzz returns result in visual order, no need to flip for RTL. for (unsigned i = 0; i < numGlyphs; ++i) { @@ -662,12 +666,7 @@ // The characterIndex of one ShapeResult run is normalized to the run's // startIndex and length. TODO crbug.com/542703: Consider changing that // and instead pass the whole run to hb_buffer_t each time. - run->m_glyphData.resize(numGlyphs); - if (HB_DIRECTION_IS_FORWARD(hb_buffer_get_direction(harfBuzzBuffer))) { - run->m_glyphData[i].characterIndex = glyphInfos[startGlyph + i].cluster - glyphInfos[startGlyph].cluster; - } else { - run->m_glyphData[i].characterIndex = glyphInfos[startGlyph + i].cluster - glyphInfos[startGlyph + numGlyphs - 1].cluster; - } + run->m_glyphData[i].characterIndex = glyphInfos[startGlyph + i].cluster - startCluster; if (isClusterEnd) spacing += adjustSpacing(run.get(), i, currentCharacterIndex, *directionOffset, totalAdvance); @@ -682,6 +681,7 @@ run->setGlyphAndPositions(i, glyph, advance, offsetX, offsetY); totalAdvance += advance; + hasVerticalOffsets |= (offsetY != 0); FloatRect glyphBounds = currentFontData->boundsForGlyph(glyph); glyphBounds.move(glyphOrigin.x(), glyphOrigin.y()); @@ -691,6 +691,8 @@ run->m_width = std::max(0.0f, totalAdvance); result->m_width += run->m_width; result->m_numGlyphs += numGlyphs; + ASSERT(result->m_numGlyphs >= numGlyphs); // no overflow + result->m_hasVerticalOffsets |= hasVerticalOffsets; // The runs are stored in result->m_runs in visual order. For LTR, we place // the run to be inserted before the next run with a bigger character @@ -738,6 +740,7 @@ RefPtr<ShapeResult> result = ShapeResult::create(font, count, textRun.direction()); result->m_width = run->m_width; result->m_numGlyphs = count; + ASSERT(result->m_numGlyphs == count); // no overflow result->m_runs.append(run.release()); return result.release(); }
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/ShapeResult.cpp b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResult.cpp index b0cc8b9f..538bef5 100644 --- a/third_party/WebKit/Source/platform/fonts/shaping/ShapeResult.cpp +++ b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResult.cpp
@@ -32,9 +32,7 @@ #include "platform/fonts/shaping/ShapeResult.h" #include "platform/fonts/Font.h" -#include "platform/fonts/GlyphBuffer.h" #include "platform/fonts/shaping/ShapeResultInlineHeaders.h" -#include "platform/text/TextBreakIterator.h" namespace blink { @@ -49,22 +47,23 @@ float ShapeResult::RunInfo::xPositionForOffset(unsigned offset) const { ASSERT(offset <= m_numCharacters); + const unsigned numGlyphs = m_glyphData.size(); unsigned glyphIndex = 0; float position = 0; if (rtl()) { - while (glyphIndex < m_numGlyphs && m_glyphData[glyphIndex].characterIndex > offset) { + while (glyphIndex < numGlyphs && m_glyphData[glyphIndex].characterIndex > offset) { position += m_glyphData[glyphIndex].advance; ++glyphIndex; } // For RTL, we need to return the right side boundary of the character. // Add advance of glyphs which are part of the character. - while (glyphIndex < m_numGlyphs - 1 && m_glyphData[glyphIndex].characterIndex == m_glyphData[glyphIndex + 1].characterIndex) { + while (glyphIndex < numGlyphs - 1 && m_glyphData[glyphIndex].characterIndex == m_glyphData[glyphIndex + 1].characterIndex) { position += m_glyphData[glyphIndex].advance; ++glyphIndex; } position += m_glyphData[glyphIndex].advance; } else { - while (glyphIndex < m_numGlyphs && m_glyphData[glyphIndex].characterIndex < offset) { + while (glyphIndex < numGlyphs && m_glyphData[glyphIndex].characterIndex < offset) { position += m_glyphData[glyphIndex].advance; ++glyphIndex; } @@ -75,12 +74,13 @@ int ShapeResult::RunInfo::characterIndexForXPosition(float targetX) const { ASSERT(targetX <= m_width); + const unsigned numGlyphs = m_glyphData.size(); float currentX = 0; float currentAdvance = m_glyphData[0].advance; unsigned glyphIndex = 0; // Sum up advances that belong to the first character. - while (glyphIndex < m_numGlyphs - 1 && m_glyphData[glyphIndex].characterIndex == m_glyphData[glyphIndex + 1].characterIndex) + while (glyphIndex < numGlyphs - 1 && m_glyphData[glyphIndex].characterIndex == m_glyphData[glyphIndex + 1].characterIndex) currentAdvance += m_glyphData[++glyphIndex].advance; currentAdvance = currentAdvance / 2.0; if (targetX <= currentAdvance) @@ -88,11 +88,11 @@ currentX = currentAdvance; ++glyphIndex; - while (glyphIndex < m_numGlyphs) { + while (glyphIndex < numGlyphs) { unsigned prevCharacterIndex = m_glyphData[glyphIndex - 1].characterIndex; float prevAdvance = currentAdvance; currentAdvance = m_glyphData[glyphIndex].advance; - while (glyphIndex < m_numGlyphs - 1 && m_glyphData[glyphIndex].characterIndex == m_glyphData[glyphIndex + 1].characterIndex) + while (glyphIndex < numGlyphs - 1 && m_glyphData[glyphIndex].characterIndex == m_glyphData[glyphIndex + 1].characterIndex) currentAdvance += m_glyphData[++glyphIndex].advance; currentAdvance = currentAdvance / 2.0; float nextX = currentX + prevAdvance + currentAdvance; @@ -120,6 +120,7 @@ , m_numCharacters(numCharacters) , m_numGlyphs(0) , m_direction(direction) + , m_hasVerticalOffsets(0) { } @@ -127,294 +128,6 @@ { } -static inline void addGlyphToBuffer(GlyphBuffer* glyphBuffer, float advance, - hb_direction_t direction, const SimpleFontData* fontData, - const HarfBuzzRunGlyphData& glyphData) -{ - FloatPoint startOffset = HB_DIRECTION_IS_HORIZONTAL(direction) - ? FloatPoint(advance, 0) - : FloatPoint(0, advance); - glyphBuffer->add(glyphData.glyph, fontData, startOffset + glyphData.offset); -} - -template<TextDirection direction> -float ShapeResult::fillGlyphBufferForRun(GlyphBuffer* glyphBuffer, - const RunInfo* run, float initialAdvance, unsigned from, unsigned to, - unsigned runOffset) -{ - if (!run) - return 0; - float advanceSoFar = initialAdvance; - unsigned numGlyphs = run->m_numGlyphs; - for (unsigned i = 0; i < numGlyphs; ++i) { - const HarfBuzzRunGlyphData& glyphData = run->m_glyphData[i]; - uint16_t currentCharacterIndex = run->m_startIndex + - glyphData.characterIndex + runOffset; - if ((direction == RTL && currentCharacterIndex >= to) - || (direction == LTR && currentCharacterIndex < from)) { - advanceSoFar += glyphData.advance; - } else if ((direction == RTL && currentCharacterIndex >= from) - || (direction == LTR && currentCharacterIndex < to)) { - addGlyphToBuffer(glyphBuffer, advanceSoFar, run->m_direction, - run->m_fontData.get(), glyphData); - advanceSoFar += glyphData.advance; - } - } - return advanceSoFar - initialAdvance; -} - -static inline unsigned countGraphemesInCluster(const UChar* str, - unsigned strLength, uint16_t startIndex, uint16_t endIndex) -{ - if (startIndex > endIndex) { - uint16_t tempIndex = startIndex; - startIndex = endIndex; - endIndex = tempIndex; - } - uint16_t length = endIndex - startIndex; - ASSERT(static_cast<unsigned>(startIndex + length) <= strLength); - TextBreakIterator* cursorPosIterator = cursorMovementIterator(&str[startIndex], length); - - int cursorPos = cursorPosIterator->current(); - int numGraphemes = -1; - while (0 <= cursorPos) { - cursorPos = cursorPosIterator->next(); - numGraphemes++; - } - return std::max(0, numGraphemes); -} - -static inline void addEmphasisMark(GlyphBuffer* buffer, - const GlyphData* emphasisData, FloatPoint glyphCenter, - float midGlyphOffset) -{ - ASSERT(buffer); - ASSERT(emphasisData); - - const SimpleFontData* emphasisFontData = emphasisData->fontData; - ASSERT(emphasisFontData); - - bool isVertical = emphasisFontData->platformData().isVerticalAnyUpright() - && emphasisFontData->verticalData(); - - if (!isVertical) { - buffer->add(emphasisData->glyph, emphasisFontData, - midGlyphOffset - glyphCenter.x()); - } else { - buffer->add(emphasisData->glyph, emphasisFontData, - FloatPoint(-glyphCenter.x(), midGlyphOffset - glyphCenter.y())); - } -} - -float ShapeResult::fillGlyphBufferForTextEmphasisRun(GlyphBuffer* glyphBuffer, - const RunInfo* run, const TextRun& textRun, const GlyphData* emphasisData, - float initialAdvance, unsigned from, unsigned to, unsigned runOffset) -{ - if (!run) - return 0; - - unsigned graphemesInCluster = 1; - float clusterAdvance = 0; - - FloatPoint glyphCenter = emphasisData->fontData-> - boundsForGlyph(emphasisData->glyph).center(); - - TextDirection direction = textRun.direction(); - - // A "cluster" in this context means a cluster as it is used by HarfBuzz: - // The minimal group of characters and corresponding glyphs, that cannot be broken - // down further from a text shaping point of view. - // A cluster can contain multiple glyphs and grapheme clusters, with mutually - // overlapping boundaries. Below we count grapheme clusters per HarfBuzz clusters, - // then linearly split the sum of corresponding glyph advances by the number of - // grapheme clusters in order to find positions for emphasis mark drawing. - uint16_t clusterStart = static_cast<uint16_t>(direction == RTL - ? run->m_startIndex + run->m_numCharacters + runOffset - : run->glyphToCharacterIndex(0) + runOffset); - - float advanceSoFar = initialAdvance; - unsigned numGlyphs = run->m_numGlyphs; - for (unsigned i = 0; i < numGlyphs; ++i) { - const HarfBuzzRunGlyphData& glyphData = run->m_glyphData[i]; - uint16_t currentCharacterIndex = run->m_startIndex + glyphData.characterIndex + runOffset; - bool isRunEnd = (i + 1 == numGlyphs); - bool isClusterEnd = isRunEnd || (run->glyphToCharacterIndex(i + 1) + runOffset != currentCharacterIndex); - - if ((direction == RTL && currentCharacterIndex >= to) || (direction != RTL && currentCharacterIndex < from)) { - advanceSoFar += glyphData.advance; - direction == RTL ? --clusterStart : ++clusterStart; - continue; - } - - clusterAdvance += glyphData.advance; - - if (textRun.is8Bit()) { - float glyphAdvanceX = glyphData.advance; - if (Character::canReceiveTextEmphasis(textRun[currentCharacterIndex])) { - addEmphasisMark(glyphBuffer, emphasisData, glyphCenter, advanceSoFar + glyphAdvanceX / 2); - } - advanceSoFar += glyphAdvanceX; - } else if (isClusterEnd) { - uint16_t clusterEnd; - if (direction == RTL) - clusterEnd = currentCharacterIndex; - else - clusterEnd = static_cast<uint16_t>(isRunEnd ? run->m_startIndex + run->m_numCharacters + runOffset : run->glyphToCharacterIndex(i + 1) + runOffset); - - graphemesInCluster = countGraphemesInCluster(textRun.characters16(), textRun.charactersLength(), clusterStart, clusterEnd); - if (!graphemesInCluster || !clusterAdvance) - continue; - - float glyphAdvanceX = clusterAdvance / graphemesInCluster; - for (unsigned j = 0; j < graphemesInCluster; ++j) { - // Do not put emphasis marks on space, separator, and control characters. - if (Character::canReceiveTextEmphasis(textRun[currentCharacterIndex])) - addEmphasisMark(glyphBuffer, emphasisData, glyphCenter, advanceSoFar + glyphAdvanceX / 2); - advanceSoFar += glyphAdvanceX; - } - clusterStart = clusterEnd; - clusterAdvance = 0; - } - } - return advanceSoFar - initialAdvance; -} - -float ShapeResult::fillGlyphBuffer(Vector<RefPtr<ShapeResult>>& results, - GlyphBuffer* glyphBuffer, const TextRun& textRun, - unsigned from, unsigned to) -{ - float advance = 0; - if (textRun.rtl()) { - unsigned wordOffset = textRun.length(); - for (unsigned j = 0; j < results.size(); j++) { - unsigned resolvedIndex = results.size() - 1 - j; - RefPtr<ShapeResult>& wordResult = results[resolvedIndex]; - for (unsigned i = 0; i < wordResult->m_runs.size(); i++) { - advance += wordResult->fillGlyphBufferForRun<RTL>(glyphBuffer, - wordResult->m_runs[i].get(), advance, from, to, - wordOffset - wordResult->numCharacters()); - } - wordOffset -= wordResult->numCharacters(); - } - } else { - unsigned wordOffset = 0; - for (unsigned j = 0; j < results.size(); j++) { - RefPtr<ShapeResult>& wordResult = results[j]; - for (unsigned i = 0; i < wordResult->m_runs.size(); i++) { - advance += wordResult->fillGlyphBufferForRun<LTR>(glyphBuffer, - wordResult->m_runs[i].get(), advance, from, to, wordOffset); - } - wordOffset += wordResult->numCharacters(); - } - } - - return advance; -} - -float ShapeResult::fillGlyphBufferForTextEmphasis( - Vector<RefPtr<ShapeResult>>& results, GlyphBuffer* glyphBuffer, - const TextRun& textRun, const GlyphData* emphasisData, - unsigned from, unsigned to) -{ - float advance = 0; - unsigned wordOffset = textRun.rtl() ? textRun.length() : 0; - for (unsigned j = 0; j < results.size(); j++) { - unsigned resolvedIndex = textRun.rtl() ? results.size() - 1 - j : j; - RefPtr<ShapeResult>& wordResult = results[resolvedIndex]; - for (unsigned i = 0; i < wordResult->m_runs.size(); i++) { - unsigned resolvedOffset = wordOffset - - (textRun.rtl() ? wordResult->numCharacters() : 0); - advance += wordResult->fillGlyphBufferForTextEmphasisRun( - glyphBuffer, wordResult->m_runs[i].get(), textRun, emphasisData, - advance, from, to, resolvedOffset); - } - wordOffset += wordResult->numCharacters() * (textRun.rtl() ? -1 : 1); - } - - return advance; -} - -FloatRect ShapeResult::selectionRect(Vector<RefPtr<ShapeResult>>& results, - TextDirection direction, float totalWidth, const FloatPoint& point, - int height, unsigned absoluteFrom, unsigned absoluteTo) -{ - float currentX = 0; - float fromX = 0; - float toX = 0; - bool foundFromX = false; - bool foundToX = false; - - if (direction == RTL) - currentX = totalWidth; - - // The absoluteFrom and absoluteTo arguments represent the start/end offset - // for the entire run, from/to are continuously updated to be relative to - // the current word (ShapeResult instance). - int from = absoluteFrom; - int to = absoluteTo; - - unsigned totalNumCharacters = 0; - for (unsigned j = 0; j < results.size(); j++) { - RefPtr<ShapeResult> result = results[j]; - if (direction == RTL) { - // Convert logical offsets to visual offsets, because results are in - // logical order while runs are in visual order. - if (!foundFromX && from >= 0 && static_cast<unsigned>(from) < result->numCharacters()) - from = result->numCharacters() - from - 1; - if (!foundToX && to >= 0 && static_cast<unsigned>(to) < result->numCharacters()) - to = result->numCharacters() - to - 1; - currentX -= result->width(); - } - for (unsigned i = 0; i < result->m_runs.size(); i++) { - if (!result->m_runs[i]) - continue; - ASSERT((direction == RTL) == result->m_runs[i]->rtl()); - int numCharacters = result->m_runs[i]->m_numCharacters; - if (!foundFromX && from >= 0 && from < numCharacters) { - fromX = result->m_runs[i]->xPositionForVisualOffset(from) + currentX; - foundFromX = true; - } else { - from -= numCharacters; - } - - if (!foundToX && to >= 0 && to < numCharacters) { - toX = result->m_runs[i]->xPositionForVisualOffset(to) + currentX; - foundToX = true; - } else { - to -= numCharacters; - } - - if (foundFromX && foundToX) - break; - currentX += result->m_runs[i]->m_width; - } - if (direction == RTL) - currentX -= result->width(); - totalNumCharacters += result->numCharacters(); - } - - // The position in question might be just after the text. - if (!foundFromX && absoluteFrom == totalNumCharacters) { - fromX = direction == RTL ? 0 : totalWidth; - foundFromX = true; - } - if (!foundToX && absoluteTo == totalNumCharacters) { - toX = direction == RTL ? 0 : totalWidth; - foundToX = true; - } - if (!foundFromX) - fromX = 0; - if (!foundToX) - toX = direction == RTL ? 0 : totalWidth; - - // None of our runs is part of the selection, possibly invalid arguments. - if (!foundToX && !foundFromX) - fromX = toX = 0; - if (fromX < toX) - return FloatRect(point.x() + fromX, point.y(), toX - fromX, height); - return FloatRect(point.x() + toX, point.y(), fromX - toX, height); -} - size_t ShapeResult::byteSize() { size_t selfByteSize = sizeof(this); @@ -424,40 +137,7 @@ return selfByteSize; } -int ShapeResult::offsetForPosition(Vector<RefPtr<ShapeResult>>& results, - const TextRun& run, float targetX) -{ - unsigned totalOffset; - if (run.rtl()) { - totalOffset = run.length(); - for (unsigned i = results.size(); i; --i) { - const RefPtr<ShapeResult>& wordResult = results[i - 1]; - if (!wordResult) - continue; - totalOffset -= wordResult->numCharacters(); - if (targetX >= 0 && targetX <= wordResult->width()) { - int offsetForWord = wordResult->offsetForPosition(targetX); - return totalOffset + offsetForWord; - } - targetX -= wordResult->width(); - } - } else { - totalOffset = 0; - for (auto& wordResult : results) { - if (!wordResult) - continue; - int offsetForWord = wordResult->offsetForPosition(targetX); - ASSERT(offsetForWord >= 0); - totalOffset += offsetForWord; - if (targetX >= 0 && targetX <= wordResult->width()) - return totalOffset; - targetX -= wordResult->width(); - } - } - return totalOffset; -} - -int ShapeResult::offsetForPosition(float targetX) +int ShapeResult::offsetForPosition(float targetX) const { int charactersSoFar = 0; float currentX = 0;
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/ShapeResult.h b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResult.h index 9759fa5..ffd7cf3 100644 --- a/third_party/WebKit/Source/platform/fonts/shaping/ShapeResult.h +++ b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResult.h
@@ -31,20 +31,20 @@ #ifndef ShapeResult_h #define ShapeResult_h -#include "platform/geometry/FloatPoint.h" +#include "platform/PlatformExport.h" #include "platform/geometry/FloatRect.h" -#include "platform/text/TextRun.h" +#include "platform/text/TextDirection.h" #include "wtf/HashSet.h" #include "wtf/Noncopyable.h" #include "wtf/OwnPtr.h" +#include "wtf/RefCounted.h" #include "wtf/Vector.h" namespace blink { class Font; -class GlyphBuffer; class SimpleFontData; -class HarfBuzzShaper; +class TextRun; struct GlyphData; class PLATFORM_EXPORT ShapeResult : public RefCounted<ShapeResult> { @@ -59,25 +59,17 @@ const TextRun&, float positionOffset, unsigned count); ~ShapeResult(); - float width() { return m_width; } - FloatRect bounds() { return m_glyphBoundingBox; } + float width() const { return m_width; } + const FloatRect& bounds() const { return m_glyphBoundingBox; } unsigned numCharacters() const { return m_numCharacters; } void fallbackFonts(HashSet<const SimpleFontData*>*) const; - - static int offsetForPosition(Vector<RefPtr<ShapeResult>>&, - const TextRun&, float targetX); - static float fillGlyphBuffer(Vector<RefPtr<ShapeResult>>&, - GlyphBuffer*, const TextRun&, unsigned from, unsigned to); - static float fillGlyphBufferForTextEmphasis(Vector<RefPtr<ShapeResult>>&, - GlyphBuffer*, const TextRun&, const GlyphData* emphasisData, - unsigned from, unsigned to); - static FloatRect selectionRect(Vector<RefPtr<ShapeResult>>&, - TextDirection, float totalWidth, const FloatPoint&, int height, - unsigned from, unsigned to); + bool hasVerticalOffsets() const { return m_hasVerticalOffsets; } // For memory reporting. size_t byteSize(); + int offsetForPosition(float targetX) const; + protected: struct RunInfo; #if COMPILER(MSVC) @@ -86,29 +78,24 @@ ShapeResult(const Font*, unsigned numCharacters, TextDirection); - int offsetForPosition(float targetX); - template<TextDirection> - float fillGlyphBufferForRun(GlyphBuffer*, const RunInfo*, - float initialAdvance, unsigned from, unsigned to, unsigned runOffset); - - float fillGlyphBufferForTextEmphasisRun(GlyphBuffer*, const RunInfo*, - const TextRun&, const GlyphData*, float initialAdvance, - unsigned from, unsigned to, unsigned runOffset); - float m_width; FloatRect m_glyphBoundingBox; Vector<OwnPtr<RunInfo>> m_runs; RefPtr<SimpleFontData> m_primaryFont; unsigned m_numCharacters; - unsigned m_numGlyphs : 31; + unsigned m_numGlyphs : 30; // Overall direction for the TextRun, dictates which order each individual // sub run (represented by RunInfo structs in the m_runs vector) can have a // different text direction. unsigned m_direction : 1; + // Tracks whether any runs contain glyphs with a y-offset != 0. + unsigned m_hasVerticalOffsets : 1; + friend class HarfBuzzShaper; + friend class ShapeResultBuffer; }; } // namespace blink
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultBuffer.cpp b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultBuffer.cpp new file mode 100644 index 0000000..f59d2300 --- /dev/null +++ b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultBuffer.cpp
@@ -0,0 +1,373 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "platform/fonts/shaping/ShapeResultBuffer.h" + +#include "platform/fonts/Character.h" +#include "platform/fonts/GlyphBuffer.h" +#include "platform/fonts/SimpleFontData.h" +#include "platform/fonts/shaping/ShapeResultInlineHeaders.h" +#include "platform/geometry/FloatPoint.h" +#include "platform/text/TextBreakIterator.h" +#include "platform/text/TextDirection.h" + +namespace blink { + +namespace { + +inline void addGlyphToBuffer(GlyphBuffer* glyphBuffer, float advance, hb_direction_t direction, + const SimpleFontData* fontData, const HarfBuzzRunGlyphData& glyphData) +{ + FloatPoint startOffset = HB_DIRECTION_IS_HORIZONTAL(direction) + ? FloatPoint(advance, 0) + : FloatPoint(0, advance); + glyphBuffer->add(glyphData.glyph, fontData, startOffset + glyphData.offset); +} + +inline void addEmphasisMark(GlyphBuffer* buffer, + const GlyphData* emphasisData, FloatPoint glyphCenter, + float midGlyphOffset) +{ + ASSERT(buffer); + ASSERT(emphasisData); + + const SimpleFontData* emphasisFontData = emphasisData->fontData; + ASSERT(emphasisFontData); + + bool isVertical = emphasisFontData->platformData().isVerticalAnyUpright() + && emphasisFontData->verticalData(); + + if (!isVertical) { + buffer->add(emphasisData->glyph, emphasisFontData, + midGlyphOffset - glyphCenter.x()); + } else { + buffer->add(emphasisData->glyph, emphasisFontData, + FloatPoint(-glyphCenter.x(), midGlyphOffset - glyphCenter.y())); + } +} + +inline unsigned countGraphemesInCluster(const UChar* str, unsigned strLength, + uint16_t startIndex, uint16_t endIndex) +{ + if (startIndex > endIndex) { + uint16_t tempIndex = startIndex; + startIndex = endIndex; + endIndex = tempIndex; + } + uint16_t length = endIndex - startIndex; + ASSERT(static_cast<unsigned>(startIndex + length) <= strLength); + TextBreakIterator* cursorPosIterator = cursorMovementIterator(&str[startIndex], length); + + int cursorPos = cursorPosIterator->current(); + int numGraphemes = -1; + while (0 <= cursorPos) { + cursorPos = cursorPosIterator->next(); + numGraphemes++; + } + return std::max(0, numGraphemes); +} + +} // anonymous namespace + +template<TextDirection direction> +float ShapeResultBuffer::fillGlyphBufferForRun(GlyphBuffer* glyphBuffer, + const ShapeResult::RunInfo* run, float initialAdvance, unsigned from, unsigned to, + unsigned runOffset) +{ + if (!run) + return 0; + float advanceSoFar = initialAdvance; + const unsigned numGlyphs = run->m_glyphData.size(); + for (unsigned i = 0; i < numGlyphs; ++i) { + const HarfBuzzRunGlyphData& glyphData = run->m_glyphData[i]; + uint16_t currentCharacterIndex = run->m_startIndex + + glyphData.characterIndex + runOffset; + if ((direction == RTL && currentCharacterIndex >= to) + || (direction == LTR && currentCharacterIndex < from)) { + advanceSoFar += glyphData.advance; + } else if ((direction == RTL && currentCharacterIndex >= from) + || (direction == LTR && currentCharacterIndex < to)) { + addGlyphToBuffer(glyphBuffer, advanceSoFar, run->m_direction, + run->m_fontData.get(), glyphData); + advanceSoFar += glyphData.advance; + } + } + return advanceSoFar - initialAdvance; +} + +float ShapeResultBuffer::fillGlyphBufferForTextEmphasisRun(GlyphBuffer* glyphBuffer, + const ShapeResult::RunInfo* run, const TextRun& textRun, const GlyphData* emphasisData, + float initialAdvance, unsigned from, unsigned to, unsigned runOffset) +{ + if (!run) + return 0; + + unsigned graphemesInCluster = 1; + float clusterAdvance = 0; + + FloatPoint glyphCenter = emphasisData->fontData-> + boundsForGlyph(emphasisData->glyph).center(); + + TextDirection direction = textRun.direction(); + + // A "cluster" in this context means a cluster as it is used by HarfBuzz: + // The minimal group of characters and corresponding glyphs, that cannot be broken + // down further from a text shaping point of view. + // A cluster can contain multiple glyphs and grapheme clusters, with mutually + // overlapping boundaries. Below we count grapheme clusters per HarfBuzz clusters, + // then linearly split the sum of corresponding glyph advances by the number of + // grapheme clusters in order to find positions for emphasis mark drawing. + uint16_t clusterStart = static_cast<uint16_t>(direction == RTL + ? run->m_startIndex + run->m_numCharacters + runOffset + : run->glyphToCharacterIndex(0) + runOffset); + + float advanceSoFar = initialAdvance; + const unsigned numGlyphs = run->m_glyphData.size(); + for (unsigned i = 0; i < numGlyphs; ++i) { + const HarfBuzzRunGlyphData& glyphData = run->m_glyphData[i]; + uint16_t currentCharacterIndex = run->m_startIndex + glyphData.characterIndex + runOffset; + bool isRunEnd = (i + 1 == numGlyphs); + bool isClusterEnd = isRunEnd || (run->glyphToCharacterIndex(i + 1) + runOffset != currentCharacterIndex); + + if ((direction == RTL && currentCharacterIndex >= to) || (direction != RTL && currentCharacterIndex < from)) { + advanceSoFar += glyphData.advance; + direction == RTL ? --clusterStart : ++clusterStart; + continue; + } + + clusterAdvance += glyphData.advance; + + if (textRun.is8Bit()) { + float glyphAdvanceX = glyphData.advance; + if (Character::canReceiveTextEmphasis(textRun[currentCharacterIndex])) { + addEmphasisMark(glyphBuffer, emphasisData, glyphCenter, advanceSoFar + glyphAdvanceX / 2); + } + advanceSoFar += glyphAdvanceX; + } else if (isClusterEnd) { + uint16_t clusterEnd; + if (direction == RTL) + clusterEnd = currentCharacterIndex; + else + clusterEnd = static_cast<uint16_t>(isRunEnd ? run->m_startIndex + run->m_numCharacters + runOffset : run->glyphToCharacterIndex(i + 1) + runOffset); + + graphemesInCluster = countGraphemesInCluster(textRun.characters16(), textRun.charactersLength(), clusterStart, clusterEnd); + if (!graphemesInCluster || !clusterAdvance) + continue; + + float glyphAdvanceX = clusterAdvance / graphemesInCluster; + for (unsigned j = 0; j < graphemesInCluster; ++j) { + // Do not put emphasis marks on space, separator, and control characters. + if (Character::canReceiveTextEmphasis(textRun[currentCharacterIndex])) + addEmphasisMark(glyphBuffer, emphasisData, glyphCenter, advanceSoFar + glyphAdvanceX / 2); + advanceSoFar += glyphAdvanceX; + } + clusterStart = clusterEnd; + clusterAdvance = 0; + } + } + return advanceSoFar - initialAdvance; +} + +float ShapeResultBuffer::fillFastHorizontalGlyphBuffer(GlyphBuffer* glyphBuffer, + TextDirection dir) const +{ + ASSERT(!hasVerticalOffsets()); + + float advance = 0; + + for (unsigned i = 0; i < m_results.size(); ++i) { + const auto& wordResult = + isLeftToRightDirection(dir) ? m_results[i] : m_results[m_results.size() - 1 - i]; + ASSERT(!wordResult->hasVerticalOffsets()); + + for (const auto& run : wordResult->m_runs) { + ASSERT(run); + ASSERT(HB_DIRECTION_IS_HORIZONTAL(run->m_direction)); + + for (const auto& glyphData : run->m_glyphData) { + ASSERT(!glyphData.offset.height()); + + glyphBuffer->add(glyphData.glyph, run->m_fontData.get(), + advance + glyphData.offset.width()); + advance += glyphData.advance; + } + } + } + + ASSERT(!glyphBuffer->hasVerticalOffsets()); + + return advance; +} + +float ShapeResultBuffer::fillGlyphBuffer(GlyphBuffer* glyphBuffer, const TextRun& textRun, + unsigned from, unsigned to) const +{ + // Fast path: full run with no vertical offsets + if (!from && to == static_cast<unsigned>(textRun.length()) && !hasVerticalOffsets()) + return fillFastHorizontalGlyphBuffer(glyphBuffer, textRun.direction()); + + float advance = 0; + + if (textRun.rtl()) { + unsigned wordOffset = textRun.length(); + for (unsigned j = 0; j < m_results.size(); j++) { + unsigned resolvedIndex = m_results.size() - 1 - j; + const RefPtr<ShapeResult>& wordResult = m_results[resolvedIndex]; + for (unsigned i = 0; i < wordResult->m_runs.size(); i++) { + advance += fillGlyphBufferForRun<RTL>(glyphBuffer, + wordResult->m_runs[i].get(), advance, from, to, + wordOffset - wordResult->numCharacters()); + } + wordOffset -= wordResult->numCharacters(); + } + } else { + unsigned wordOffset = 0; + for (unsigned j = 0; j < m_results.size(); j++) { + const RefPtr<ShapeResult>& wordResult = m_results[j]; + for (unsigned i = 0; i < wordResult->m_runs.size(); i++) { + advance += fillGlyphBufferForRun<LTR>(glyphBuffer, + wordResult->m_runs[i].get(), advance, from, to, wordOffset); + } + wordOffset += wordResult->numCharacters(); + } + } + + return advance; +} + +float ShapeResultBuffer::fillGlyphBufferForTextEmphasis(GlyphBuffer* glyphBuffer, + const TextRun& textRun, const GlyphData* emphasisData, unsigned from, unsigned to) const +{ + float advance = 0; + unsigned wordOffset = textRun.rtl() ? textRun.length() : 0; + + for (unsigned j = 0; j < m_results.size(); j++) { + unsigned resolvedIndex = textRun.rtl() ? m_results.size() - 1 - j : j; + const RefPtr<ShapeResult>& wordResult = m_results[resolvedIndex]; + for (unsigned i = 0; i < wordResult->m_runs.size(); i++) { + unsigned resolvedOffset = wordOffset - + (textRun.rtl() ? wordResult->numCharacters() : 0); + advance += fillGlyphBufferForTextEmphasisRun( + glyphBuffer, wordResult->m_runs[i].get(), textRun, emphasisData, + advance, from, to, resolvedOffset); + } + wordOffset += wordResult->numCharacters() * (textRun.rtl() ? -1 : 1); + } + + return advance; +} + +FloatRect ShapeResultBuffer::selectionRect(TextDirection direction, float totalWidth, + const FloatPoint& point, int height, unsigned absoluteFrom, unsigned absoluteTo) const +{ + float currentX = 0; + float fromX = 0; + float toX = 0; + bool foundFromX = false; + bool foundToX = false; + + if (direction == RTL) + currentX = totalWidth; + + // The absoluteFrom and absoluteTo arguments represent the start/end offset + // for the entire run, from/to are continuously updated to be relative to + // the current word (ShapeResult instance). + int from = absoluteFrom; + int to = absoluteTo; + + unsigned totalNumCharacters = 0; + for (unsigned j = 0; j < m_results.size(); j++) { + const RefPtr<ShapeResult> result = m_results[j]; + if (direction == RTL) { + // Convert logical offsets to visual offsets, because results are in + // logical order while runs are in visual order. + if (!foundFromX && from >= 0 && static_cast<unsigned>(from) < result->numCharacters()) + from = result->numCharacters() - from - 1; + if (!foundToX && to >= 0 && static_cast<unsigned>(to) < result->numCharacters()) + to = result->numCharacters() - to - 1; + currentX -= result->width(); + } + for (unsigned i = 0; i < result->m_runs.size(); i++) { + if (!result->m_runs[i]) + continue; + ASSERT((direction == RTL) == result->m_runs[i]->rtl()); + int numCharacters = result->m_runs[i]->m_numCharacters; + if (!foundFromX && from >= 0 && from < numCharacters) { + fromX = result->m_runs[i]->xPositionForVisualOffset(from) + currentX; + foundFromX = true; + } else { + from -= numCharacters; + } + + if (!foundToX && to >= 0 && to < numCharacters) { + toX = result->m_runs[i]->xPositionForVisualOffset(to) + currentX; + foundToX = true; + } else { + to -= numCharacters; + } + + if (foundFromX && foundToX) + break; + currentX += result->m_runs[i]->m_width; + } + if (direction == RTL) + currentX -= result->width(); + totalNumCharacters += result->numCharacters(); + } + + // The position in question might be just after the text. + if (!foundFromX && absoluteFrom == totalNumCharacters) { + fromX = direction == RTL ? 0 : totalWidth; + foundFromX = true; + } + if (!foundToX && absoluteTo == totalNumCharacters) { + toX = direction == RTL ? 0 : totalWidth; + foundToX = true; + } + if (!foundFromX) + fromX = 0; + if (!foundToX) + toX = direction == RTL ? 0 : totalWidth; + + // None of our runs is part of the selection, possibly invalid arguments. + if (!foundToX && !foundFromX) + fromX = toX = 0; + if (fromX < toX) + return FloatRect(point.x() + fromX, point.y(), toX - fromX, height); + return FloatRect(point.x() + toX, point.y(), fromX - toX, height); +} + +int ShapeResultBuffer::offsetForPosition(const TextRun& run, float targetX) const +{ + unsigned totalOffset; + if (run.rtl()) { + totalOffset = run.length(); + for (unsigned i = m_results.size(); i; --i) { + const RefPtr<ShapeResult>& wordResult = m_results[i - 1]; + if (!wordResult) + continue; + totalOffset -= wordResult->numCharacters(); + if (targetX >= 0 && targetX <= wordResult->width()) { + int offsetForWord = wordResult->offsetForPosition(targetX); + return totalOffset + offsetForWord; + } + targetX -= wordResult->width(); + } + } else { + totalOffset = 0; + for (const auto& wordResult : m_results) { + if (!wordResult) + continue; + int offsetForWord = wordResult->offsetForPosition(targetX); + ASSERT(offsetForWord >= 0); + totalOffset += offsetForWord; + if (targetX >= 0 && targetX <= wordResult->width()) + return totalOffset; + targetX -= wordResult->width(); + } + } + return totalOffset; +} + +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultBuffer.h b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultBuffer.h new file mode 100644 index 0000000..a0394e4 --- /dev/null +++ b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultBuffer.h
@@ -0,0 +1,57 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ShapeResultBuffer_h +#define ShapeResultBuffer_h + +#include "platform/fonts/shaping/ShapeResult.h" +#include "wtf/Allocator.h" +#include "wtf/RefPtr.h" +#include "wtf/Vector.h" + +namespace blink { + +class GlyphBuffer; +class TextRun; + +class ShapeResultBuffer { + WTF_MAKE_NONCOPYABLE(ShapeResultBuffer); + STACK_ALLOCATED(); +public: + ShapeResultBuffer() + : m_hasVerticalOffsets(false) { } + + void appendResult(PassRefPtr<ShapeResult> result) + { + m_hasVerticalOffsets |= result->hasVerticalOffsets(); + m_results.append(result); + } + + bool hasVerticalOffsets() const { return m_hasVerticalOffsets; } + + float fillGlyphBuffer(GlyphBuffer*, const TextRun&, unsigned from, unsigned to) const; + float fillGlyphBufferForTextEmphasis(GlyphBuffer*, const TextRun&, + const GlyphData* emphasisData, unsigned from, unsigned to) const; + int offsetForPosition(const TextRun&, float targetX) const; + FloatRect selectionRect(TextDirection, float totalWidth, const FloatPoint&, int height, + unsigned from, unsigned to) const; + +private: + float fillFastHorizontalGlyphBuffer(GlyphBuffer*, TextDirection) const; + + template<TextDirection> + static float fillGlyphBufferForRun(GlyphBuffer*, const ShapeResult::RunInfo*, + float initialAdvance, unsigned from, unsigned to, unsigned runOffset); + static float fillGlyphBufferForTextEmphasisRun(GlyphBuffer*, const ShapeResult::RunInfo*, + const TextRun&, const GlyphData*, float initialAdvance, unsigned from, unsigned to, + unsigned runOffset); + + // Empirically, cases where we get more than 50 ShapeResults are extremely rare. + Vector<RefPtr<ShapeResult>, 64>m_results; + bool m_hasVerticalOffsets; +}; + +} // namespace blink + +#endif // ShapeResultBuffer_h
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultInlineHeaders.h b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultInlineHeaders.h index 3eb1169c..e4c2b53 100644 --- a/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultInlineHeaders.h +++ b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultInlineHeaders.h
@@ -60,10 +60,9 @@ RunInfo(const SimpleFontData* font, hb_direction_t dir, hb_script_t script, unsigned startIndex, unsigned numGlyphs, unsigned numCharacters) : m_fontData(const_cast<SimpleFontData*>(font)), m_direction(dir) - , m_script(script), m_startIndex(startIndex) - , m_numCharacters(numCharacters) , m_numGlyphs(numGlyphs), m_width(0.0f) + , m_script(script), m_glyphData(numGlyphs), m_startIndex(startIndex) + , m_numCharacters(numCharacters), m_width(0.0f) { - m_glyphData.resize(m_numGlyphs); } bool rtl() const { return HB_DIRECTION_IS_BACKWARD(m_direction); } @@ -95,7 +94,6 @@ Vector<HarfBuzzRunGlyphData> m_glyphData; unsigned m_startIndex; unsigned m_numCharacters; - unsigned m_numGlyphs; float m_width; };
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultTestInfo.cpp b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultTestInfo.cpp index 7cbd59c..185726d2 100644 --- a/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultTestInfo.cpp +++ b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultTestInfo.cpp
@@ -19,7 +19,7 @@ { if (runIndex < m_runs.size() && m_runs[runIndex]) { startIndex = m_runs[runIndex]->m_startIndex; - numGlyphs = m_runs[runIndex]->m_numGlyphs; + numGlyphs = m_runs[runIndex]->m_glyphData.size(); script = m_runs[runIndex]->m_script; return true; }
diff --git a/third_party/WebKit/Source/platform/graphics/BitmapImageTest.cpp b/third_party/WebKit/Source/platform/graphics/BitmapImageTest.cpp index fbd1cf81..495f351 100644 --- a/third_party/WebKit/Source/platform/graphics/BitmapImageTest.cpp +++ b/third_party/WebKit/Source/platform/graphics/BitmapImageTest.cpp
@@ -33,6 +33,7 @@ #include "platform/SharedBuffer.h" #include "platform/graphics/DeferredImageDecoder.h" #include "platform/graphics/ImageObserver.h" +#include "platform/testing/UnitTestHelpers.h" #include "public/platform/Platform.h" #include "public/platform/WebUnitTestSupport.h" #include "testing/gtest/include/gtest/gtest.h" @@ -63,7 +64,7 @@ static PassRefPtr<SharedBuffer> readFile(const char* fileName) { - String filePath = Platform::current()->unitTestSupport()->webKitRootDir(); + String filePath = testing::blinkRootDir(); filePath.append(fileName); return Platform::current()->unitTestSupport()->readFromFile(filePath); }
diff --git a/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridgeTest.cpp b/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridgeTest.cpp index 46b33fb1..e78cafac 100644 --- a/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridgeTest.cpp +++ b/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridgeTest.cpp
@@ -25,6 +25,7 @@ #include "platform/graphics/Canvas2DLayerBridge.h" #include "SkSurface.h" +#include "base/memory/scoped_ptr.h" #include "platform/graphics/ImageBuffer.h" #include "platform/graphics/UnacceleratedImageBufferSurface.h" #include "platform/graphics/test/MockWebGraphicsContext3D.h" @@ -65,7 +66,7 @@ MockWebGraphicsContext3DProvider(WebGraphicsContext3D* context3d) : m_context3d(context3d) { - RefPtr<SkGLContext> glContext = adoptRef(SkNullGLContext::Create(kNone_GrGLStandard)); + scoped_ptr<SkGLContext> glContext(SkNullGLContext::Create()); glContext->makeCurrent(); m_grContext = adoptRef(GrContext::Create(kOpenGL_GrBackend, reinterpret_cast<GrBackendContext>(glContext->gl()))); }
diff --git a/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp b/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp index 472a452..f55cd75 100644 --- a/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp +++ b/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp
@@ -305,8 +305,6 @@ IntRect GraphicsLayer::interestRect() { - if (!RuntimeEnabledFeatures::slimmingPaintSynchronizedPaintingEnabled()) - m_previousInterestRect = m_client->computeInterestRect(this, m_previousInterestRect); return m_previousInterestRect; } @@ -332,8 +330,7 @@ interestRect = &newInterestRect; } - if (RuntimeEnabledFeatures::slimmingPaintSynchronizedPaintingEnabled() - && !paintController().subsequenceCachingIsDisabled() + if (!paintController().subsequenceCachingIsDisabled() && !m_client->needsRepaint() && !paintController().cacheIsEmpty() && m_previousInterestRect == *interestRect) {
diff --git a/third_party/WebKit/Source/platform/graphics/ImageBuffer.cpp b/third_party/WebKit/Source/platform/graphics/ImageBuffer.cpp index a8385663..4f28973 100644 --- a/third_party/WebKit/Source/platform/graphics/ImageBuffer.cpp +++ b/third_party/WebKit/Source/platform/graphics/ImageBuffer.cpp
@@ -219,7 +219,7 @@ // The canvas is stored in a premultiplied format, so unpremultiply if necessary. // The canvas is stored in an inverted position, so the flip semantics are reversed. - context->copyTextureCHROMIUM(GL_TEXTURE_2D, sourceTexture, texture, internalFormat, destType, flipY ? GL_FALSE : GL_TRUE, GL_FALSE, premultiplyAlpha ? GL_FALSE : GL_TRUE); + context->copyTextureCHROMIUM(sourceTexture, texture, internalFormat, destType, flipY ? GL_FALSE : GL_TRUE, GL_FALSE, premultiplyAlpha ? GL_FALSE : GL_TRUE); context->deleteTexture(sourceTexture);
diff --git a/third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.cpp b/third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.cpp index 0a1fac0b..b45c0dc4 100644 --- a/third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.cpp +++ b/third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.cpp
@@ -306,7 +306,7 @@ m_context->discardFramebufferEXT(GL_FRAMEBUFFER, 3, attachments); } } else { - m_context->copyTextureCHROMIUM(GL_TEXTURE_2D, m_colorBuffer.textureId, frontColorBufferMailbox->textureInfo.textureId, GL_RGBA, GL_UNSIGNED_BYTE, GL_FALSE, GL_FALSE, GL_FALSE); + m_context->copyTextureCHROMIUM(m_colorBuffer.textureId, frontColorBufferMailbox->textureInfo.textureId, GL_RGBA, GL_UNSIGNED_BYTE, GL_FALSE, GL_FALSE, GL_FALSE); } restoreFramebufferBindings(); @@ -528,7 +528,7 @@ else if (m_actualAttributes.alpha && !m_actualAttributes.premultipliedAlpha && premultiplyAlpha) unpackPremultiplyAlphaNeeded = GL_TRUE; - context->copyTextureCHROMIUM(GL_TEXTURE_2D, sourceTexture, texture, internalFormat, destType, flipY, unpackPremultiplyAlphaNeeded, unpackUnpremultiplyAlphaNeeded); + context->copyTextureCHROMIUM(sourceTexture, texture, internalFormat, destType, flipY, unpackPremultiplyAlphaNeeded, unpackUnpremultiplyAlphaNeeded); context->deleteTexture(sourceTexture);
diff --git a/third_party/WebKit/Source/platform/graphics/paint/PaintController.h b/third_party/WebKit/Source/platform/graphics/paint/PaintController.h index 79b1cda..844f9d8 100644 --- a/third_party/WebKit/Source/platform/graphics/paint/PaintController.h +++ b/third_party/WebKit/Source/platform/graphics/paint/PaintController.h
@@ -168,12 +168,10 @@ bool clientHasCheckedPaintInvalidation(const DisplayItemClient& client) const { - ASSERT(RuntimeEnabledFeatures::slimmingPaintSynchronizedPaintingEnabled()); return m_clientsCheckedPaintInvalidation.contains(&client); } void setClientHasCheckedPaintInvalidation(const DisplayItemClient& client) { - ASSERT(RuntimeEnabledFeatures::slimmingPaintSynchronizedPaintingEnabled()); m_clientsCheckedPaintInvalidation.add(&client); }
diff --git a/third_party/WebKit/Source/platform/graphics/paint/PaintControllerTest.cpp b/third_party/WebKit/Source/platform/graphics/paint/PaintControllerTest.cpp index 7ac677e9..65a8fb6a 100644 --- a/third_party/WebKit/Source/platform/graphics/paint/PaintControllerTest.cpp +++ b/third_party/WebKit/Source/platform/graphics/paint/PaintControllerTest.cpp
@@ -20,7 +20,6 @@ public: PaintControllerTest() : m_paintController(PaintController::create()) - , m_originalSlimmingPaintSynchronizedPaintingEnabled(RuntimeEnabledFeatures::slimmingPaintSynchronizedPaintingEnabled()) , m_originalSlimmingPaintV2Enabled(RuntimeEnabledFeatures::slimmingPaintV2Enabled()) { } protected: @@ -29,12 +28,10 @@ private: void TearDown() override { - RuntimeEnabledFeatures::setSlimmingPaintSynchronizedPaintingEnabled(m_originalSlimmingPaintSynchronizedPaintingEnabled); RuntimeEnabledFeatures::setSlimmingPaintV2Enabled(m_originalSlimmingPaintV2Enabled); } OwnPtr<PaintController> m_paintController; - bool m_originalSlimmingPaintSynchronizedPaintingEnabled; bool m_originalSlimmingPaintV2Enabled; }; @@ -450,8 +447,6 @@ TEST_F(PaintControllerTest, CachedSubsequenceSwapOrder) { - RuntimeEnabledFeatures::setSlimmingPaintSynchronizedPaintingEnabled(true); - TestDisplayItemClient container1("container1"); TestDisplayItemClient content1("content1"); TestDisplayItemClient container2("container2"); @@ -542,8 +537,6 @@ TEST_F(PaintControllerTest, CachedNestedSubsequenceUpdate) { - RuntimeEnabledFeatures::setSlimmingPaintSynchronizedPaintingEnabled(true); - TestDisplayItemClient container1("container1"); TestDisplayItemClient content1("content1"); TestDisplayItemClient container2("container2");
diff --git a/third_party/WebKit/Source/platform/graphics/paint/SubsequenceRecorder.cpp b/third_party/WebKit/Source/platform/graphics/paint/SubsequenceRecorder.cpp index 2a498c4a..e046b9ec 100644 --- a/third_party/WebKit/Source/platform/graphics/paint/SubsequenceRecorder.cpp +++ b/third_party/WebKit/Source/platform/graphics/paint/SubsequenceRecorder.cpp
@@ -14,9 +14,6 @@ bool SubsequenceRecorder::useCachedSubsequenceIfPossible(GraphicsContext& context, const DisplayItemClient& client) { - if (!RuntimeEnabledFeatures::slimmingPaintSynchronizedPaintingEnabled()) - return false; - if (context.paintController().displayItemConstructionIsDisabled() || context.paintController().subsequenceCachingIsDisabled()) return false; @@ -40,9 +37,6 @@ , m_client(client) , m_beginSubsequenceIndex(0) { - if (!RuntimeEnabledFeatures::slimmingPaintSynchronizedPaintingEnabled()) - return; - if (m_paintController.displayItemConstructionIsDisabled()) return; @@ -52,9 +46,6 @@ SubsequenceRecorder::~SubsequenceRecorder() { - if (!RuntimeEnabledFeatures::slimmingPaintSynchronizedPaintingEnabled()) - return; - if (m_paintController.displayItemConstructionIsDisabled()) return;
diff --git a/third_party/WebKit/Source/platform/image-decoders/ImageDecoderTestHelpers.cpp b/third_party/WebKit/Source/platform/image-decoders/ImageDecoderTestHelpers.cpp index 7c79270f..1082494 100644 --- a/third_party/WebKit/Source/platform/image-decoders/ImageDecoderTestHelpers.cpp +++ b/third_party/WebKit/Source/platform/image-decoders/ImageDecoderTestHelpers.cpp
@@ -7,6 +7,7 @@ #include "platform/SharedBuffer.h" #include "platform/image-decoders/ImageDecoder.h" #include "platform/image-decoders/ImageFrame.h" +#include "platform/testing/UnitTestHelpers.h" #include "public/platform/Platform.h" #include "public/platform/WebUnitTestSupport.h" #include "testing/gtest/include/gtest/gtest.h" @@ -17,14 +18,14 @@ PassRefPtr<SharedBuffer> readFile(const char* fileName) { - String filePath = Platform::current()->unitTestSupport()->webKitRootDir(); + String filePath = testing::blinkRootDir(); filePath.append(fileName); return Platform::current()->unitTestSupport()->readFromFile(filePath); } PassRefPtr<SharedBuffer> readFile(const char* dir, const char* fileName) { - String filePath = Platform::current()->unitTestSupport()->webKitRootDir(); + String filePath = testing::blinkRootDir(); filePath.append("/"); filePath.append(dir); filePath.append("/");
diff --git a/third_party/WebKit/Source/platform/testing/DEPS b/third_party/WebKit/Source/platform/testing/DEPS new file mode 100644 index 0000000..ce5e389 --- /dev/null +++ b/third_party/WebKit/Source/platform/testing/DEPS
@@ -0,0 +1,6 @@ +include_rules = [ + # To whitelist base/ stuff Blink is allowed to include, we list up all + # directories and files instead of writing 'base/'. + "+base/files", + "+base/path_service.h", +]
diff --git a/third_party/WebKit/Source/platform/testing/URLTestHelpers.cpp b/third_party/WebKit/Source/platform/testing/URLTestHelpers.cpp index ccd6f1c1..4d69037 100644 --- a/third_party/WebKit/Source/platform/testing/URLTestHelpers.cpp +++ b/third_party/WebKit/Source/platform/testing/URLTestHelpers.cpp
@@ -30,6 +30,7 @@ #include "platform/testing/URLTestHelpers.h" +#include "platform/testing/UnitTestHelpers.h" #include "public/platform/Platform.h" #include "public/platform/WebURL.h" #include "public/platform/WebURLError.h" @@ -75,12 +76,12 @@ void registerMockedURLLoadWithCustomResponse(const WebURL& fullURL, const WebString& fileName, const WebString& relativeBaseDirectory, WebURLResponse response) { // Physical file path for the mock = <webkitRootDir> + relativeBaseDirectory + fileName. - std::string filePath = std::string(Platform::current()->unitTestSupport()->webKitRootDir().utf8().data()); + String filePath = testing::blinkRootDir(); filePath.append("/Source/web/tests/data/"); - filePath.append(std::string(relativeBaseDirectory.utf8().data())); - filePath.append(std::string(fileName.utf8().data())); + filePath.append(relativeBaseDirectory); + filePath.append(fileName); - Platform::current()->unitTestSupport()->registerMockedURL(fullURL, response, WebString::fromUTF8(filePath.c_str())); + Platform::current()->unitTestSupport()->registerMockedURL(fullURL, response, filePath); } } // namespace URLTestHelpers
diff --git a/third_party/WebKit/Source/platform/testing/UnitTestHelpers.cpp b/third_party/WebKit/Source/platform/testing/UnitTestHelpers.cpp index dcb8252..04524d8 100644 --- a/third_party/WebKit/Source/platform/testing/UnitTestHelpers.cpp +++ b/third_party/WebKit/Source/platform/testing/UnitTestHelpers.cpp
@@ -25,6 +25,9 @@ #include "platform/testing/UnitTestHelpers.h" +#include "base/files/file_path.h" +#include "base/files/file_util.h" +#include "base/path_service.h" #include "public/platform/Platform.h" #include "public/platform/WebTaskRunner.h" #include "public/platform/WebThread.h" @@ -48,5 +51,14 @@ Platform::current()->unitTestSupport()->enterRunLoop(); } +String blinkRootDir() +{ + base::FilePath path; + base::PathService::Get(base::DIR_SOURCE_ROOT, &path); + path = path.Append(FILE_PATH_LITERAL("third_party/WebKit")); + path = base::MakeAbsoluteFilePath(path); + return String::fromUTF8(path.MaybeAsASCII().c_str()); +} + } }
diff --git a/third_party/WebKit/Source/platform/testing/UnitTestHelpers.h b/third_party/WebKit/Source/platform/testing/UnitTestHelpers.h index 19767b2..d863b3f8 100644 --- a/third_party/WebKit/Source/platform/testing/UnitTestHelpers.h +++ b/third_party/WebKit/Source/platform/testing/UnitTestHelpers.h
@@ -26,11 +26,15 @@ #ifndef UnitTestHelpers_h #define UnitTestHelpers_h +#include "wtf/text/WTFString.h" + namespace blink { namespace testing { void runPendingTasks(); +String blinkRootDir(); + } // namespace testing } // namespace blink
diff --git a/third_party/WebKit/Source/platform/text/TextRun.cpp b/third_party/WebKit/Source/platform/text/TextRun.cpp index 2027356..1ade95b 100644 --- a/third_party/WebKit/Source/platform/text/TextRun.cpp +++ b/third_party/WebKit/Source/platform/text/TextRun.cpp
@@ -36,7 +36,7 @@ float float1; float float2; float float3; - uint32_t bitfields : 12; + uint32_t bitfields : 10; TabSize tabSize; };
diff --git a/third_party/WebKit/Source/platform/text/TextRun.h b/third_party/WebKit/Source/platform/text/TextRun.h index 8748aca..cc390f9 100644 --- a/third_party/WebKit/Source/platform/text/TextRun.h +++ b/third_party/WebKit/Source/platform/text/TextRun.h
@@ -71,7 +71,6 @@ , m_horizontalGlyphStretch(1) , m_expansion(expansion) , m_expansionBehavior(expansionBehavior) - , m_codePath(Auto) , m_is8Bit(true) , m_allowTabs(false) , m_direction(direction) @@ -91,7 +90,6 @@ , m_horizontalGlyphStretch(1) , m_expansion(expansion) , m_expansionBehavior(expansionBehavior) - , m_codePath(Auto) , m_is8Bit(false) , m_allowTabs(false) , m_direction(direction) @@ -111,7 +109,6 @@ , m_horizontalGlyphStretch(1) , m_expansion(expansion) , m_expansionBehavior(expansionBehavior) - , m_codePath(Auto) , m_allowTabs(false) , m_direction(direction) , m_directionalOverride(directionalOverride) @@ -139,7 +136,6 @@ , m_horizontalGlyphStretch(1) , m_expansion(expansion) , m_expansionBehavior(expansionBehavior) - , m_codePath(Auto) , m_allowTabs(false) , m_direction(direction) , m_directionalOverride(directionalOverride) @@ -210,13 +206,11 @@ bool rtl() const { return m_direction == RTL; } bool ltr() const { return m_direction == LTR; } bool directionalOverride() const { return m_directionalOverride; } - TextCodePath codePath() const { return static_cast<TextCodePath>(m_codePath); } bool spacingDisabled() const { return m_disableSpacing; } void disableSpacing() { m_disableSpacing = true; } void setDirection(TextDirection direction) { m_direction = direction; } void setDirectionalOverride(bool override) { m_directionalOverride = override; } - void setCodePath(TextCodePath codePath) { m_codePath = codePath; } void setTextJustify(TextJustify textJustify) { m_textJustify = static_cast<unsigned>(textJustify); } TextJustify textJustify() const { return static_cast<TextJustify>(m_textJustify); } @@ -237,7 +231,6 @@ float m_expansion; ExpansionBehavior m_expansionBehavior : 2; - unsigned m_codePath : 2; unsigned m_is8Bit : 1; unsigned m_allowTabs : 1; unsigned m_direction : 1;
diff --git a/third_party/WebKit/Source/platform/weborigin/KURL.cpp b/third_party/WebKit/Source/platform/weborigin/KURL.cpp index 22348951..9e10715 100644 --- a/third_party/WebKit/Source/platform/weborigin/KURL.cpp +++ b/third_party/WebKit/Source/platform/weborigin/KURL.cpp
@@ -93,6 +93,7 @@ namespace { class KURLCharsetConverter final : public url::CharsetConverter { + DISALLOW_NEW(); public: // The encoding parameter may be 0, but in this case the object must not be called. explicit KURLCharsetConverter(const WTF::TextEncoding* encoding)
diff --git a/third_party/WebKit/Source/platform/weborigin/KURL.h b/third_party/WebKit/Source/platform/weborigin/KURL.h index 14668c4..2a8fa80 100644 --- a/third_party/WebKit/Source/platform/weborigin/KURL.h +++ b/third_party/WebKit/Source/platform/weborigin/KURL.h
@@ -27,6 +27,7 @@ #define KURL_h #include "platform/PlatformExport.h" +#include "wtf/Allocator.h" #include "wtf/Forward.h" #include "wtf/HashTableDeletedValueType.h" #include "wtf/OwnPtr.h" @@ -45,6 +46,7 @@ enum ParsedURLStringTag { ParsedURLString }; class PLATFORM_EXPORT KURL { + USING_FAST_MALLOC(KURL); public: // This must be called during initialization (before we create // other threads).
diff --git a/third_party/WebKit/Source/platform/weborigin/KURLHash.h b/third_party/WebKit/Source/platform/weborigin/KURLHash.h index 3b5f543..7f43c77c 100644 --- a/third_party/WebKit/Source/platform/weborigin/KURLHash.h +++ b/third_party/WebKit/Source/platform/weborigin/KURLHash.h
@@ -27,6 +27,7 @@ #define KURLHash_h #include "platform/weborigin/KURL.h" +#include "wtf/Allocator.h" #include "wtf/text/StringHash.h" #include "wtf/text/WTFString.h" @@ -37,6 +38,7 @@ // KURLs. struct KURLHash { + STATIC_ONLY(KURLHash); static unsigned hash(const KURL& key) { return key.string().impl()->hash();
diff --git a/third_party/WebKit/Source/platform/weborigin/OriginAccessEntry.h b/third_party/WebKit/Source/platform/weborigin/OriginAccessEntry.h index 42a7827..d364702 100644 --- a/third_party/WebKit/Source/platform/weborigin/OriginAccessEntry.h +++ b/third_party/WebKit/Source/platform/weborigin/OriginAccessEntry.h
@@ -32,6 +32,7 @@ #define OriginAccessEntry_h #include "platform/PlatformExport.h" +#include "wtf/Allocator.h" #include "wtf/text/WTFString.h" namespace blink { @@ -39,6 +40,7 @@ class SecurityOrigin; class PLATFORM_EXPORT OriginAccessEntry { + USING_FAST_MALLOC(OriginAccessEntry); public: enum SubdomainSetting { // 'www.example.com' matches an OriginAccessEntry for 'example.com'
diff --git a/third_party/WebKit/Source/platform/weborigin/Referrer.h b/third_party/WebKit/Source/platform/weborigin/Referrer.h index b8d9572..c23d6163 100644 --- a/third_party/WebKit/Source/platform/weborigin/Referrer.h +++ b/third_party/WebKit/Source/platform/weborigin/Referrer.h
@@ -32,11 +32,13 @@ #define Referrer_h #include "platform/weborigin/ReferrerPolicy.h" +#include "wtf/Allocator.h" #include "wtf/text/WTFString.h" namespace blink { struct Referrer { + DISALLOW_NEW(); Referrer(const String& referrer, ReferrerPolicy referrerPolicy) : referrer(referrer), referrerPolicy(referrerPolicy) { } Referrer() : referrerPolicy(ReferrerPolicyDefault) { }
diff --git a/third_party/WebKit/Source/platform/weborigin/SchemeRegistry.h b/third_party/WebKit/Source/platform/weborigin/SchemeRegistry.h index f9533f6..153cf4a 100644 --- a/third_party/WebKit/Source/platform/weborigin/SchemeRegistry.h +++ b/third_party/WebKit/Source/platform/weborigin/SchemeRegistry.h
@@ -28,6 +28,7 @@ #define SchemeRegistry_h #include "platform/PlatformExport.h" +#include "wtf/Allocator.h" #include "wtf/HashMap.h" #include "wtf/HashSet.h" #include "wtf/text/StringHash.h" @@ -41,6 +42,7 @@ using URLSchemesMap = HashMap<String, T, CaseFoldingHash>; class PLATFORM_EXPORT SchemeRegistry { + STATIC_ONLY(SchemeRegistry); public: static void registerURLSchemeAsLocal(const String&); static bool shouldTreatURLSchemeAsLocal(const String&);
diff --git a/third_party/WebKit/Source/platform/weborigin/SecurityOrigin.h b/third_party/WebKit/Source/platform/weborigin/SecurityOrigin.h index b4a4a90..bf542df 100644 --- a/third_party/WebKit/Source/platform/weborigin/SecurityOrigin.h +++ b/third_party/WebKit/Source/platform/weborigin/SecurityOrigin.h
@@ -31,6 +31,7 @@ #include "base/gtest_prod_util.h" #include "platform/PlatformExport.h" +#include "wtf/Noncopyable.h" #include "wtf/ThreadSafeRefCounted.h" #include "wtf/text/WTFString.h" @@ -40,6 +41,7 @@ class SecurityOriginCache; class PLATFORM_EXPORT SecurityOrigin : public RefCounted<SecurityOrigin> { + WTF_MAKE_NONCOPYABLE(SecurityOrigin); public: static PassRefPtr<SecurityOrigin> create(const KURL&); static PassRefPtr<SecurityOrigin> createUnique();
diff --git a/third_party/WebKit/Source/platform/weborigin/SecurityOriginHash.h b/third_party/WebKit/Source/platform/weborigin/SecurityOriginHash.h index cffa0e7..7f697207 100644 --- a/third_party/WebKit/Source/platform/weborigin/SecurityOriginHash.h +++ b/third_party/WebKit/Source/platform/weborigin/SecurityOriginHash.h
@@ -31,11 +31,13 @@ #include "platform/weborigin/KURL.h" #include "platform/weborigin/SecurityOrigin.h" +#include "wtf/Allocator.h" #include "wtf/RefPtr.h" namespace blink { struct SecurityOriginHash { + STATIC_ONLY(SecurityOriginHash); static unsigned hash(SecurityOrigin* origin) { unsigned hashCodes[4] = {
diff --git a/third_party/WebKit/Source/platform/weborigin/SecurityPolicy.h b/third_party/WebKit/Source/platform/weborigin/SecurityPolicy.h index e7cc7de1..50282ef2 100644 --- a/third_party/WebKit/Source/platform/weborigin/SecurityPolicy.h +++ b/third_party/WebKit/Source/platform/weborigin/SecurityPolicy.h
@@ -32,6 +32,7 @@ #include "platform/PlatformExport.h" #include "platform/weborigin/Referrer.h" #include "platform/weborigin/ReferrerPolicy.h" +#include "wtf/Allocator.h" #include "wtf/text/WTFString.h" namespace blink { @@ -40,6 +41,7 @@ class SecurityOrigin; class PLATFORM_EXPORT SecurityPolicy { + STATIC_ONLY(SecurityPolicy); public: // This must be called during initialization (before we create // other threads).
diff --git a/third_party/WebKit/Source/web/AssociatedURLLoaderTest.cpp b/third_party/WebKit/Source/web/AssociatedURLLoaderTest.cpp index 30fc465f..009e1b3 100644 --- a/third_party/WebKit/Source/web/AssociatedURLLoaderTest.cpp +++ b/third_party/WebKit/Source/web/AssociatedURLLoaderTest.cpp
@@ -65,7 +65,7 @@ , m_didFail(false) { // Reuse one of the test files from WebFrameTest. - m_baseFilePath = Platform::current()->unitTestSupport()->webKitRootDir(); + m_baseFilePath = testing::blinkRootDir(); m_baseFilePath.append("/Source/web/tests/data/"); m_frameFilePath = m_baseFilePath; m_frameFilePath.append("iframes_test.html");
diff --git a/third_party/WebKit/Source/web/FrameLoaderClientImpl.cpp b/third_party/WebKit/Source/web/FrameLoaderClientImpl.cpp index caaf4e7..a954edf 100644 --- a/third_party/WebKit/Source/web/FrameLoaderClientImpl.cpp +++ b/third_party/WebKit/Source/web/FrameLoaderClientImpl.cpp
@@ -293,6 +293,12 @@ } +void FrameLoaderClientImpl::didUseKeygen() +{ + if (m_webFrame->contentSettingsClient()) + m_webFrame->contentSettingsClient()->didUseKeygen(); +} + bool FrameLoaderClientImpl::hasWebView() const { return m_webFrame->viewImpl();
diff --git a/third_party/WebKit/Source/web/FrameLoaderClientImpl.h b/third_party/WebKit/Source/web/FrameLoaderClientImpl.h index d57f3df..e65c5b29 100644 --- a/third_party/WebKit/Source/web/FrameLoaderClientImpl.h +++ b/third_party/WebKit/Source/web/FrameLoaderClientImpl.h
@@ -143,6 +143,7 @@ bool allowRunningInsecureContent(bool enabledPerSettings, SecurityOrigin*, const KURL&) override; void didNotAllowScript() override; void didNotAllowPlugins() override; + void didUseKeygen() override; WebCookieJar* cookieJar() const override; bool willCheckAndDispatchMessageEvent(SecurityOrigin* target, MessageEvent*, LocalFrame* sourceFrame) const override;
diff --git a/third_party/WebKit/Source/web/IndexedDBClientImpl.cpp b/third_party/WebKit/Source/web/IndexedDBClientImpl.cpp index 0b6feba..9069a510 100644 --- a/third_party/WebKit/Source/web/IndexedDBClientImpl.cpp +++ b/third_party/WebKit/Source/web/IndexedDBClientImpl.cpp
@@ -28,7 +28,7 @@ #include "web/IndexedDBClientImpl.h" -#include "bindings/core/v8/WorkerScriptController.h" +#include "bindings/core/v8/WorkerOrWorkletScriptController.h" #include "core/dom/Document.h" #include "core/workers/WorkerGlobalScope.h" #include "platform/weborigin/SecurityOrigin.h"
diff --git a/third_party/WebKit/Source/web/InspectorOverlay.cpp b/third_party/WebKit/Source/web/InspectorOverlay.cpp index 867198da..16d077dc 100644 --- a/third_party/WebKit/Source/web/InspectorOverlay.cpp +++ b/third_party/WebKit/Source/web/InspectorOverlay.cpp
@@ -497,7 +497,7 @@ loader.load(FrameLoadRequest(0, blankURL(), SubstituteData(data, "text/html", "UTF-8", KURL(), ForceSynchronousLoad))); v8::Isolate* isolate = toIsolate(frame.get()); ScriptState* scriptState = ScriptState::forMainWorld(frame.get()); - ASSERT(scriptState->contextIsValid()); + ASSERT(scriptState); ScriptState::Scope scope(scriptState); v8::Local<v8::Object> global = scriptState->context()->Global(); v8::Local<v8::Value> overlayHostObj = toV8(m_overlayHost.get(), global, isolate);
diff --git a/third_party/WebKit/Source/web/ServiceWorkerGlobalScopeProxy.cpp b/third_party/WebKit/Source/web/ServiceWorkerGlobalScopeProxy.cpp index 5c9baf6..dd12697 100644 --- a/third_party/WebKit/Source/web/ServiceWorkerGlobalScopeProxy.cpp +++ b/third_party/WebKit/Source/web/ServiceWorkerGlobalScopeProxy.cpp
@@ -30,7 +30,7 @@ #include "web/ServiceWorkerGlobalScopeProxy.h" -#include "bindings/core/v8/WorkerScriptController.h" +#include "bindings/core/v8/WorkerOrWorkletScriptController.h" #include "core/dom/CrossThreadTask.h" #include "core/dom/Document.h" #include "core/dom/ExecutionContext.h"
diff --git a/third_party/WebKit/Source/web/WebDevToolsFrontendImpl.cpp b/third_party/WebKit/Source/web/WebDevToolsFrontendImpl.cpp index 2f072e6d..14a2274 100644 --- a/third_party/WebKit/Source/web/WebDevToolsFrontendImpl.cpp +++ b/third_party/WebKit/Source/web/WebDevToolsFrontendImpl.cpp
@@ -69,6 +69,7 @@ if (m_webFrame == frame) { v8::Isolate* isolate = v8::Isolate::GetCurrent(); ScriptState* scriptState = ScriptState::forMainWorld(m_webFrame->frame()); + ASSERT(scriptState); ScriptState::Scope scope(scriptState); if (m_devtoolsHost)
diff --git a/third_party/WebKit/Source/web/WebFrameSerializerImpl.cpp b/third_party/WebKit/Source/web/WebFrameSerializerImpl.cpp index ce5e7a3..49240cb 100644 --- a/third_party/WebKit/Source/web/WebFrameSerializerImpl.cpp +++ b/third_party/WebKit/Source/web/WebFrameSerializerImpl.cpp
@@ -112,7 +112,6 @@ , haveSeenDocType(false) , haveAddedCharsetDeclaration(false) , skipMetaElement(nullptr) - , isInScriptOrStyleTag(false) , haveAddedXMLProcessingDirective(false) , haveAddedContentsBeforeEnd(false) { @@ -201,8 +200,6 @@ param->haveAddedContentsBeforeEnd = true; // Will search each META which has charset declaration, and skip them all // in PreActionBeforeSerializeOpenTag. - } else if (isHTMLScriptElement(*element) || isHTMLScriptElement(*element)) { - param->isInScriptOrStyleTag = true; } return result.toString(); @@ -221,9 +218,6 @@ // skipMetaElement is definitely META tag if it's not 0. if (param->skipMetaElement == element) { *needSkip = true; - } else if (isHTMLScriptElement(*element) || isHTMLScriptElement(*element)) { - ASSERT(param->isInScriptOrStyleTag); - param->isInScriptOrStyleTag = false; } return result;
diff --git a/third_party/WebKit/Source/web/WebFrameSerializerImpl.h b/third_party/WebKit/Source/web/WebFrameSerializerImpl.h index 0a403dd..49eb9059 100644 --- a/third_party/WebKit/Source/web/WebFrameSerializerImpl.h +++ b/third_party/WebKit/Source/web/WebFrameSerializerImpl.h
@@ -112,8 +112,6 @@ bool haveAddedCharsetDeclaration; // This meta element need to be skipped when serializing DOM. RawPtrWillBeMember<const Element> skipMetaElement; - // Flag indicates we are in script or style tag. - bool isInScriptOrStyleTag; bool haveAddedXMLProcessingDirective; // Flag indicates whether we have added additional contents before end tag. // This flag will be re-assigned in each call of function
diff --git a/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp b/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp index 1ec2a76..7fa14d64 100644 --- a/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp +++ b/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp
@@ -941,7 +941,7 @@ v8::Local<v8::Context> WebLocalFrameImpl::mainWorldScriptContext() const { ScriptState* scriptState = ScriptState::forMainWorld(frame()); - ASSERT(scriptState->contextIsValid()); + ASSERT(scriptState); return scriptState->context(); }
diff --git a/third_party/WebKit/Source/web/WebPagePopupImpl.cpp b/third_party/WebKit/Source/web/WebPagePopupImpl.cpp index 055c78e..541a2787 100644 --- a/third_party/WebKit/Source/web/WebPagePopupImpl.cpp +++ b/third_party/WebKit/Source/web/WebPagePopupImpl.cpp
@@ -408,7 +408,7 @@ { if (m_closing || !m_page || !m_page->mainFrame() || !toLocalFrame(m_page->mainFrame())->view()) return WebInputEventResult::NotHandled; - if (event.type == WebInputEvent::GestureTap && !isGestureEventInWindow(event)) { + if (event.type == WebInputEvent::GestureTap && !isViewportPointInWindow(event.x, event.y)) { cancel(); return WebInputEventResult::NotHandled; } @@ -418,7 +418,7 @@ void WebPagePopupImpl::handleMouseDown(LocalFrame& mainFrame, const WebMouseEvent& event) { - if (isMouseEventInWindow(event)) + if (isViewportPointInWindow(event.x, event.y)) PageWidgetEventHandler::handleMouseDown(mainFrame, event); else cancel(); @@ -426,20 +426,17 @@ WebInputEventResult WebPagePopupImpl::handleMouseWheel(LocalFrame& mainFrame, const WebMouseWheelEvent& event) { - if (isMouseEventInWindow(event)) + if (isViewportPointInWindow(event.x, event.y)) return PageWidgetEventHandler::handleMouseWheel(mainFrame, event); cancel(); return WebInputEventResult::NotHandled; } -bool WebPagePopupImpl::isMouseEventInWindow(const WebMouseEvent& event) +bool WebPagePopupImpl::isViewportPointInWindow(int x, int y) { - return IntRect(0, 0, m_windowRectInScreen.width, m_windowRectInScreen.height).contains(IntPoint(event.x, event.y)); -} - -bool WebPagePopupImpl::isGestureEventInWindow(const WebGestureEvent& event) -{ - return IntRect(0, 0, m_windowRectInScreen.width, m_windowRectInScreen.height).contains(IntPoint(event.x, event.y)); + WebRect pointInWindow(x, y, 0, 0); + widgetClient()->convertViewportToWindow(&pointInWindow); + return IntRect(0, 0, m_windowRectInScreen.width, m_windowRectInScreen.height).contains(IntPoint(pointInWindow.x, pointInWindow.y)); } WebInputEventResult WebPagePopupImpl::handleInputEvent(const WebInputEvent& event)
diff --git a/third_party/WebKit/Source/web/WebPagePopupImpl.h b/third_party/WebKit/Source/web/WebPagePopupImpl.h index 07886cd..8031c57 100644 --- a/third_party/WebKit/Source/web/WebPagePopupImpl.h +++ b/third_party/WebKit/Source/web/WebPagePopupImpl.h
@@ -91,8 +91,7 @@ void handleMouseDown(LocalFrame& mainFrame, const WebMouseEvent&) override; WebInputEventResult handleMouseWheel(LocalFrame& mainFrame, const WebMouseWheelEvent&) override; - bool isMouseEventInWindow(const WebMouseEvent&); - bool isGestureEventInWindow(const WebGestureEvent&); + bool isViewportPointInWindow(int x, int y); // PagePopup function AXObject* rootAXObject() override;
diff --git a/third_party/WebKit/Source/web/WebPluginContainerImpl.cpp b/third_party/WebKit/Source/web/WebPluginContainerImpl.cpp index 7589865..4b35fb5 100644 --- a/third_party/WebKit/Source/web/WebPluginContainerImpl.cpp +++ b/third_party/WebKit/Source/web/WebPluginContainerImpl.cpp
@@ -456,7 +456,7 @@ return v8::Local<v8::Object>(); ScriptState* scriptState = ScriptState::forMainWorld(frame); - if (!scriptState->contextIsValid()) + if (!scriptState) return v8::Local<v8::Object>(); v8::Local<v8::Value> v8value = toV8(m_element.get(), scriptState->context()->Global(), scriptState->isolate()); @@ -931,7 +931,7 @@ IntRect frameRectInOwnerElementSpace = box->absoluteToLocalQuad(FloatRect(frameRect()), UseTransforms).enclosingBoundingBox(); LayoutRect unclippedAbsoluteRect(frameRectInOwnerElementSpace); - box->mapToVisibleRectInContainerSpace(rootView, unclippedAbsoluteRect, nullptr); + box->mapToVisibleRectInAncestorSpace(rootView, unclippedAbsoluteRect, nullptr); // The frameRect is already in absolute space of the local frame to the plugin. windowRect = frameRect();
diff --git a/third_party/WebKit/Source/web/WebTextInputInfo.cpp b/third_party/WebKit/Source/web/WebTextInputInfo.cpp index 2c806f0..5aeea93 100644 --- a/third_party/WebKit/Source/web/WebTextInputInfo.cpp +++ b/third_party/WebKit/Source/web/WebTextInputInfo.cpp
@@ -36,6 +36,7 @@ { return type == other.type && value == other.value + && flags == other.flags && selectionStart == other.selectionStart && selectionEnd == other.selectionEnd && compositionStart == other.compositionStart
diff --git a/third_party/WebKit/Source/web/WebViewImpl.cpp b/third_party/WebKit/Source/web/WebViewImpl.cpp index a065625..7be5f100 100644 --- a/third_party/WebKit/Source/web/WebViewImpl.cpp +++ b/third_party/WebKit/Source/web/WebViewImpl.cpp
@@ -2003,16 +2003,14 @@ PageWidgetDelegate::updateAllLifecyclePhases(*m_page, *mainFrameImpl()->frame()); - if (RuntimeEnabledFeatures::slimmingPaintSynchronizedPaintingEnabled()) { - if (InspectorOverlay* overlay = inspectorOverlay()) { - overlay->updateAllLifecyclePhases(); - // TODO(chrishtr): integrate paint into the overlay's lifecycle. - if (overlay->pageOverlay() && overlay->pageOverlay()->graphicsLayer()) - overlay->pageOverlay()->graphicsLayer()->paint(nullptr); - } - if (m_pageColorOverlay) - m_pageColorOverlay->graphicsLayer()->paint(nullptr); + if (InspectorOverlay* overlay = inspectorOverlay()) { + overlay->updateAllLifecyclePhases(); + // TODO(chrishtr): integrate paint into the overlay's lifecycle. + if (overlay->pageOverlay() && overlay->pageOverlay()->graphicsLayer()) + overlay->pageOverlay()->graphicsLayer()->paint(nullptr); } + if (m_pageColorOverlay) + m_pageColorOverlay->graphicsLayer()->paint(nullptr); // TODO(chrishtr): link highlights don't currently paint themselves, it's still driven by cc. // Fix this.
diff --git a/third_party/WebKit/Source/web/tests/FrameThrottlingTest.cpp b/third_party/WebKit/Source/web/tests/FrameThrottlingTest.cpp index 825586c..beca4dd 100644 --- a/third_party/WebKit/Source/web/tests/FrameThrottlingTest.cpp +++ b/third_party/WebKit/Source/web/tests/FrameThrottlingTest.cpp
@@ -6,9 +6,12 @@ #include "core/dom/Element.h" #include "core/frame/FrameView.h" #include "core/html/HTMLIFrameElement.h" +#include "platform/testing/URLTestHelpers.h" #include "platform/testing/UnitTestHelpers.h" #include "public/web/WebHitTestResult.h" #include "testing/gtest/include/gtest/gtest.h" +#include "web/WebLocalFrameImpl.h" +#include "web/WebRemoteFrameImpl.h" #include "web/tests/sim/SimCompositor.h" #include "web/tests/sim/SimDisplayItemList.h" #include "web/tests/sim/SimRequest.h" @@ -150,10 +153,7 @@ frameElement->setAttribute(styleAttr, "transform: translateY(480px)"); compositeFrame(); EXPECT_TRUE(frameDocument->view()->canThrottleRendering()); - if (RuntimeEnabledFeatures::slimmingPaintSynchronizedPaintingEnabled()) - EXPECT_EQ(DocumentLifecycle::PaintClean, frameDocument->lifecycle().state()); - else - EXPECT_EQ(DocumentLifecycle::PaintInvalidationClean, frameDocument->lifecycle().state()); + EXPECT_EQ(DocumentLifecycle::PaintClean, frameDocument->lifecycle().state()); // Mutating the throttled frame followed by a beginFrame will not result in // a complete lifecycle update. @@ -251,4 +251,50 @@ EXPECT_EQ(50, divElement->clientWidth()); } +TEST(RemoteFrameThrottlingTest, ThrottledLocalRoot) +{ + FrameTestHelpers::TestWebViewClient viewClient; + WebViewImpl* webView = WebViewImpl::create(&viewClient); + webView->resize(WebSize(640, 480)); + + // Create a remote root frame with a local child frame. + FrameTestHelpers::TestWebRemoteFrameClient remoteClient; + webView->setMainFrame(remoteClient.frame()); + remoteClient.frame()->setReplicatedOrigin(WebSecurityOrigin::createUnique()); + + WebFrameOwnerProperties properties; + FrameTestHelpers::TestWebFrameClient localFrameClient; + WebRemoteFrame* rootFrame = webView->mainFrame()->toWebRemoteFrame(); + WebLocalFrame* localFrame = rootFrame->createLocalChild(WebTreeScopeType::Document, "", WebSandboxFlags::None, &localFrameClient, nullptr, properties); + + WebString baseURL("http://internal.test/"); + URLTestHelpers::registerMockedURLFromBaseURL(baseURL, "simple_div.html"); + FrameTestHelpers::loadFrame(localFrame, baseURL.utf8() + "simple_div.html"); + + FrameView* frameView = toWebLocalFrameImpl(localFrame)->frameView(); + EXPECT_TRUE(frameView->frame().isLocalRoot()); + + // Enable throttling for the child frame. + frameView->setFrameRect(IntRect(0, 480, frameView->width(), frameView->height())); + frameView->frame().securityContext()->setSecurityOrigin(SecurityOrigin::createUnique()); + frameView->updateAllLifecyclePhases(); + testing::runPendingTasks(); + EXPECT_TRUE(frameView->shouldThrottleRendering()); + + Document* frameDocument = frameView->frame().document(); + EXPECT_EQ(DocumentLifecycle::PaintClean, frameDocument->lifecycle().state()); + + // Mutate the local child frame contents. + auto* divElement = frameDocument->getElementById("div"); + divElement->setAttribute(styleAttr, "width: 50px"); + EXPECT_EQ(DocumentLifecycle::VisualUpdatePending, frameDocument->lifecycle().state()); + + // Update the lifecycle again. The frame's lifecycle should not advance + // because of throttling even though it is the local root. + frameView->updateAllLifecyclePhases(); + testing::runPendingTasks(); + EXPECT_EQ(DocumentLifecycle::VisualUpdatePending, frameDocument->lifecycle().state()); + webView->close(); +} + } // namespace blink
diff --git a/third_party/WebKit/Source/web/tests/LayoutGeometryMapTest.cpp b/third_party/WebKit/Source/web/tests/LayoutGeometryMapTest.cpp index dc80383..ae98a6e 100644 --- a/third_party/WebKit/Source/web/tests/LayoutGeometryMapTest.cpp +++ b/third_party/WebKit/Source/web/tests/LayoutGeometryMapTest.cpp
@@ -141,20 +141,20 @@ LayoutGeometryMap rgm; rgm.pushMappingsToAncestor(getLayoutBox(webView, "InitialDiv"), 0); FloatRect rect(0.0f, 0.0f, 1.0f, 2.0f); - EXPECT_EQ(FloatQuad(FloatRect(8.0f, 8.0f, 1.0f, 2.0f)), rgm.mapToContainer(rect, nullptr)); + EXPECT_EQ(FloatQuad(FloatRect(8.0f, 8.0f, 1.0f, 2.0f)), rgm.mapToAncestor(rect, nullptr)); rgm.popMappingsToAncestor(static_cast<PaintLayer*>(nullptr)); - EXPECT_EQ(FloatQuad(FloatRect(0.0f, 0.0f, 1.0f, 2.0f)), rgm.mapToContainer(rect, nullptr)); + EXPECT_EQ(FloatQuad(FloatRect(0.0f, 0.0f, 1.0f, 2.0f)), rgm.mapToAncestor(rect, nullptr)); rgm.pushMappingsToAncestor(getLayoutBox(webView, "InnerDiv"), 0); - EXPECT_EQ(FloatQuad(FloatRect(21.0f, 6.0f, 1.0f, 2.0f)), rgm.mapToContainer(rect, getLayoutBox(webView, "CenterDiv"))); + EXPECT_EQ(FloatQuad(FloatRect(21.0f, 6.0f, 1.0f, 2.0f)), rgm.mapToAncestor(rect, getLayoutBox(webView, "CenterDiv"))); rgm.pushMappingsToAncestor(getLayoutBox(webView, "OtherDiv"), getLayoutBox(webView, "InnerDiv")); - EXPECT_EQ(FloatQuad(FloatRect(22.0f, 12.0f, 1.0f, 2.0f)), rgm.mapToContainer(rect, getLayoutBox(webView, "CenterDiv"))); + EXPECT_EQ(FloatQuad(FloatRect(22.0f, 12.0f, 1.0f, 2.0f)), rgm.mapToAncestor(rect, getLayoutBox(webView, "CenterDiv"))); - EXPECT_EQ(FloatQuad(FloatRect(1.0f, 6.0f, 1.0f, 2.0f)), rgm.mapToContainer(rect, getLayoutBox(webView, "InnerDiv"))); + EXPECT_EQ(FloatQuad(FloatRect(1.0f, 6.0f, 1.0f, 2.0f)), rgm.mapToAncestor(rect, getLayoutBox(webView, "InnerDiv"))); - EXPECT_EQ(FloatQuad(FloatRect(50.0f, 44.0f, 1.0f, 2.0f)), rgm.mapToContainer(rect, nullptr)); + EXPECT_EQ(FloatQuad(FloatRect(50.0f, 44.0f, 1.0f, 2.0f)), rgm.mapToAncestor(rect, nullptr)); } // Fails on Windows due to crbug.com/391457. When run through the transform the @@ -177,27 +177,27 @@ const float scaleWidth = 2.0f; const float scaleHeight = 3.0f; FloatRect rect(0.0f, 0.0f, 15.0f, 25.0f); - EXPECT_EQ(FloatQuad(FloatRect(8.0f, 8.0f, 15.0f, 25.0f)), rgm.mapToContainer(rect, nullptr)); + EXPECT_EQ(FloatQuad(FloatRect(8.0f, 8.0f, 15.0f, 25.0f)), rgm.mapToAncestor(rect, nullptr)); rgm.popMappingsToAncestor(static_cast<PaintLayer*>(nullptr)); - EXPECT_EQ(FloatQuad(FloatRect(0.0f, 0.0f, 15.0f, 25.0f)).boundingBox(), rgm.mapToContainer(rect, nullptr).boundingBox()); + EXPECT_EQ(FloatQuad(FloatRect(0.0f, 0.0f, 15.0f, 25.0f)).boundingBox(), rgm.mapToAncestor(rect, nullptr).boundingBox()); rgm.pushMappingsToAncestor(getLayoutBox(webView, "InnerDiv"), 0); - EXPECT_EQ(FloatQuad(FloatRect(523.0f - rectWidth, 6.0f, 15.0f, 25.0f)).boundingBox(), rgm.mapToContainer(rect, getLayoutBox(webView, "CenterDiv")).boundingBox()); + EXPECT_EQ(FloatQuad(FloatRect(523.0f - rectWidth, 6.0f, 15.0f, 25.0f)).boundingBox(), rgm.mapToAncestor(rect, getLayoutBox(webView, "CenterDiv")).boundingBox()); rgm.pushMappingsToAncestor(getLayoutBox(webView, "OtherDiv"), getLayoutBox(webView, "InnerDiv")); - EXPECT_EQ(FloatQuad(FloatRect(522.0f - rectWidth, 12.0f, 15.0f, 25.0f)).boundingBox(), rgm.mapToContainer(rect, getLayoutBox(webView, "CenterDiv")).boundingBox()); + EXPECT_EQ(FloatQuad(FloatRect(522.0f - rectWidth, 12.0f, 15.0f, 25.0f)).boundingBox(), rgm.mapToAncestor(rect, getLayoutBox(webView, "CenterDiv")).boundingBox()); - EXPECT_EQ(FloatQuad(FloatRect(1.0f, 6.0f, 15.0f, 25.0f)).boundingBox(), rgm.mapToContainer(rect, getLayoutBox(webView, "InnerDiv")).boundingBox()); + EXPECT_EQ(FloatQuad(FloatRect(1.0f, 6.0f, 15.0f, 25.0f)).boundingBox(), rgm.mapToAncestor(rect, getLayoutBox(webView, "InnerDiv")).boundingBox()); - EXPECT_EQ(FloatQuad(FloatRect(821.0f - rectWidth * scaleWidth, 31.0f, 15.0f * scaleWidth, 25.0f * scaleHeight)).boundingBox(), rgm.mapToContainer(rect, nullptr).boundingBox()); + EXPECT_EQ(FloatQuad(FloatRect(821.0f - rectWidth * scaleWidth, 31.0f, 15.0f * scaleWidth, 25.0f * scaleHeight)).boundingBox(), rgm.mapToAncestor(rect, nullptr).boundingBox()); rect = FloatRect(10.0f, 25.0f, 15.0f, 25.0f); - EXPECT_EQ(FloatQuad(FloatRect(512.0f - rectWidth, 37.0f, 15.0f, 25.0f)).boundingBox(), rgm.mapToContainer(rect, getLayoutBox(webView, "CenterDiv")).boundingBox()); + EXPECT_EQ(FloatQuad(FloatRect(512.0f - rectWidth, 37.0f, 15.0f, 25.0f)).boundingBox(), rgm.mapToAncestor(rect, getLayoutBox(webView, "CenterDiv")).boundingBox()); - EXPECT_EQ(FloatQuad(FloatRect(11.0f, 31.0f, 15.0f, 25.0f)).boundingBox(), rgm.mapToContainer(rect, getLayoutBox(webView, "InnerDiv")).boundingBox()); + EXPECT_EQ(FloatQuad(FloatRect(11.0f, 31.0f, 15.0f, 25.0f)).boundingBox(), rgm.mapToAncestor(rect, getLayoutBox(webView, "InnerDiv")).boundingBox()); - EXPECT_EQ(FloatQuad(FloatRect(801.0f - rectWidth * scaleWidth, 106.0f, 15.0f * scaleWidth, 25.0f * scaleHeight)).boundingBox(), rgm.mapToContainer(rect, nullptr).boundingBox()); + EXPECT_EQ(FloatQuad(FloatRect(801.0f - rectWidth * scaleWidth, 106.0f, 15.0f * scaleWidth, 25.0f * scaleHeight)).boundingBox(), rgm.mapToAncestor(rect, nullptr).boundingBox()); } TEST_F(LayoutGeometryMapTest, FixedGeometryTest) @@ -211,23 +211,23 @@ LayoutGeometryMap rgm; rgm.pushMappingsToAncestor(getLayoutBox(webView, "InitialDiv"), 0); FloatRect rect(0.0f, 0.0f, 15.0f, 25.0f); - EXPECT_EQ(FloatQuad(FloatRect(8.0f, 8.0f, 15.0f, 25.0f)), rgm.mapToContainer(rect, nullptr)); + EXPECT_EQ(FloatQuad(FloatRect(8.0f, 8.0f, 15.0f, 25.0f)), rgm.mapToAncestor(rect, nullptr)); rgm.popMappingsToAncestor(static_cast<PaintLayer*>(nullptr)); - EXPECT_EQ(FloatQuad(FloatRect(0.0f, 0.0f, 15.0f, 25.0f)), rgm.mapToContainer(rect, nullptr)); + EXPECT_EQ(FloatQuad(FloatRect(0.0f, 0.0f, 15.0f, 25.0f)), rgm.mapToAncestor(rect, nullptr)); rgm.pushMappingsToAncestor(getLayoutBox(webView, "InnerDiv"), 0); - EXPECT_EQ(FloatQuad(FloatRect(20.0f, 14.0f, 15.0f, 25.0f)), rgm.mapToContainer(rect, nullptr)); + EXPECT_EQ(FloatQuad(FloatRect(20.0f, 14.0f, 15.0f, 25.0f)), rgm.mapToAncestor(rect, nullptr)); rgm.pushMappingsToAncestor(getLayoutBox(webView, "OtherDiv"), getLayoutBox(webView, "InnerDiv")); - EXPECT_EQ(FloatQuad(FloatRect(21.0f, 20.0f, 15.0f, 25.0f)), rgm.mapToContainer(rect, getLayoutContainer(webView, "CenterDiv"))); + EXPECT_EQ(FloatQuad(FloatRect(21.0f, 20.0f, 15.0f, 25.0f)), rgm.mapToAncestor(rect, getLayoutContainer(webView, "CenterDiv"))); rect = FloatRect(22.0f, 15.2f, 15.3f, 0.0f); - EXPECT_EQ(FloatQuad(FloatRect(43.0f, 35.2f, 15.3f, 0.0f)), rgm.mapToContainer(rect, getLayoutContainer(webView, "CenterDiv"))); + EXPECT_EQ(FloatQuad(FloatRect(43.0f, 35.2f, 15.3f, 0.0f)), rgm.mapToAncestor(rect, getLayoutContainer(webView, "CenterDiv"))); - EXPECT_EQ(FloatQuad(FloatRect(43.0f, 35.2f, 15.3f, 0.0f)), rgm.mapToContainer(rect, getLayoutContainer(webView, "InnerDiv"))); + EXPECT_EQ(FloatQuad(FloatRect(43.0f, 35.2f, 15.3f, 0.0f)), rgm.mapToAncestor(rect, getLayoutContainer(webView, "InnerDiv"))); - EXPECT_EQ(FloatQuad(FloatRect(43.0f, 35.2f, 15.3f, 0.0f)), rgm.mapToContainer(rect, nullptr)); + EXPECT_EQ(FloatQuad(FloatRect(43.0f, 35.2f, 15.3f, 0.0f)), rgm.mapToAncestor(rect, nullptr)); } TEST_F(LayoutGeometryMapTest, IframeTest) @@ -246,7 +246,7 @@ rgm.pushMappingsToAncestor(getFrameElement("test_frame", webView, "InitialDiv"), 0); FloatRect rect(0.0f, 0.0f, 1.0f, 2.0f); - EXPECT_EQ(FloatQuad(FloatRect(8.0f, 8.0f, 1.0f, 2.0f)), rgmNoFrame.mapToContainer(rect, nullptr)); + EXPECT_EQ(FloatQuad(FloatRect(8.0f, 8.0f, 1.0f, 2.0f)), rgmNoFrame.mapToAncestor(rect, nullptr)); // Our initial rect looks like: (0, 0, 1, 2) // p0_____ @@ -265,33 +265,33 @@ // That maximum x should likewise be p0.x + cos(30deg) = p0.x + 0.866. // And the maximum y should be p0.x + sin(30deg) + 2*cos(30deg) // = p0.y + 2.232. - EXPECT_NEAR(69.5244f, rectFromQuad(rgm.mapToContainer(rect, nullptr)).x(), 0.0001f); - EXPECT_NEAR(-44.0237, rectFromQuad(rgm.mapToContainer(rect, nullptr)).y(), 0.0001f); - EXPECT_NEAR(1.866, rectFromQuad(rgm.mapToContainer(rect, nullptr)).width(), 0.0001f); - EXPECT_NEAR(2.232, rectFromQuad(rgm.mapToContainer(rect, nullptr)).height(), 0.0001f); + EXPECT_NEAR(69.5244f, rectFromQuad(rgm.mapToAncestor(rect, nullptr)).x(), 0.0001f); + EXPECT_NEAR(-44.0237, rectFromQuad(rgm.mapToAncestor(rect, nullptr)).y(), 0.0001f); + EXPECT_NEAR(1.866, rectFromQuad(rgm.mapToAncestor(rect, nullptr)).width(), 0.0001f); + EXPECT_NEAR(2.232, rectFromQuad(rgm.mapToAncestor(rect, nullptr)).height(), 0.0001f); rgm.popMappingsToAncestor(static_cast<PaintLayer*>(nullptr)); rgmNoFrame.popMappingsToAncestor(static_cast<PaintLayer*>(nullptr)); rgm.pushMappingsToAncestor(getFrameElement("test_frame", webView, "InnerDiv"), 0); rgmNoFrame.pushMappingsToAncestor(getFrameElement("test_frame", webView, "InnerDiv"), 0); - EXPECT_EQ(FloatQuad(FloatRect(21.0f, 6.0f, 1.0f, 2.0f)), rgm.mapToContainer(rect, getFrameLayoutContainer("test_frame", webView, "CenterDiv"))); - EXPECT_EQ(FloatQuad(FloatRect(21.0f, 6.0f, 1.0f, 2.0f)), rgmNoFrame.mapToContainer(rect, getFrameLayoutContainer("test_frame", webView, "CenterDiv"))); + EXPECT_EQ(FloatQuad(FloatRect(21.0f, 6.0f, 1.0f, 2.0f)), rgm.mapToAncestor(rect, getFrameLayoutContainer("test_frame", webView, "CenterDiv"))); + EXPECT_EQ(FloatQuad(FloatRect(21.0f, 6.0f, 1.0f, 2.0f)), rgmNoFrame.mapToAncestor(rect, getFrameLayoutContainer("test_frame", webView, "CenterDiv"))); rgm.pushMappingsToAncestor(getFrameElement("test_frame", webView, "OtherDiv"), getFrameLayoutContainer("test_frame", webView, "InnerDiv")); rgmNoFrame.pushMappingsToAncestor(getFrameElement("test_frame", webView, "OtherDiv"), getFrameLayoutContainer("test_frame", webView, "InnerDiv")); - EXPECT_EQ(FloatQuad(FloatRect(22.0f, 12.0f, 1.0f, 2.0f)), rgm.mapToContainer(rect, getFrameLayoutContainer("test_frame", webView, "CenterDiv"))); - EXPECT_EQ(FloatQuad(FloatRect(22.0f, 12.0f, 1.0f, 2.0f)), rgmNoFrame.mapToContainer(rect, getFrameLayoutContainer("test_frame", webView, "CenterDiv"))); + EXPECT_EQ(FloatQuad(FloatRect(22.0f, 12.0f, 1.0f, 2.0f)), rgm.mapToAncestor(rect, getFrameLayoutContainer("test_frame", webView, "CenterDiv"))); + EXPECT_EQ(FloatQuad(FloatRect(22.0f, 12.0f, 1.0f, 2.0f)), rgmNoFrame.mapToAncestor(rect, getFrameLayoutContainer("test_frame", webView, "CenterDiv"))); - EXPECT_EQ(FloatQuad(FloatRect(1.0f, 6.0f, 1.0f, 2.0f)), rgm.mapToContainer(rect, getFrameLayoutContainer("test_frame", webView, "InnerDiv"))); - EXPECT_EQ(FloatQuad(FloatRect(1.0f, 6.0f, 1.0f, 2.0f)), rgmNoFrame.mapToContainer(rect, getFrameLayoutContainer("test_frame", webView, "InnerDiv"))); + EXPECT_EQ(FloatQuad(FloatRect(1.0f, 6.0f, 1.0f, 2.0f)), rgm.mapToAncestor(rect, getFrameLayoutContainer("test_frame", webView, "InnerDiv"))); + EXPECT_EQ(FloatQuad(FloatRect(1.0f, 6.0f, 1.0f, 2.0f)), rgmNoFrame.mapToAncestor(rect, getFrameLayoutContainer("test_frame", webView, "InnerDiv"))); - EXPECT_NEAR(87.8975f, rectFromQuad(rgm.mapToContainer(rect, nullptr)).x(), 0.0001f); - EXPECT_NEAR(8.1532f, rectFromQuad(rgm.mapToContainer(rect, nullptr)).y(), 0.0001f); - EXPECT_NEAR(1.866, rectFromQuad(rgm.mapToContainer(rect, nullptr)).width(), 0.0001f); - EXPECT_NEAR(2.232, rectFromQuad(rgm.mapToContainer(rect, nullptr)).height(), 0.0001f); + EXPECT_NEAR(87.8975f, rectFromQuad(rgm.mapToAncestor(rect, nullptr)).x(), 0.0001f); + EXPECT_NEAR(8.1532f, rectFromQuad(rgm.mapToAncestor(rect, nullptr)).y(), 0.0001f); + EXPECT_NEAR(1.866, rectFromQuad(rgm.mapToAncestor(rect, nullptr)).width(), 0.0001f); + EXPECT_NEAR(2.232, rectFromQuad(rgm.mapToAncestor(rect, nullptr)).height(), 0.0001f); - EXPECT_EQ(FloatQuad(FloatRect(50.0f, 44.0f, 1.0f, 2.0f)), rgmNoFrame.mapToContainer(rect, nullptr)); + EXPECT_EQ(FloatQuad(FloatRect(50.0f, 44.0f, 1.0f, 2.0f)), rgmNoFrame.mapToAncestor(rect, nullptr)); } TEST_F(LayoutGeometryMapTest, ColumnTest) @@ -315,27 +315,27 @@ FloatPoint point; FloatRect rect(0.0f, 0.0f, 5.0f, 3.0f); - EXPECT_EQ(FloatQuad(FloatRect(8.0f, 8.0f, 5.0f, 3.0f)), rgm.mapToContainer(rect, nullptr)); + EXPECT_EQ(FloatQuad(FloatRect(8.0f, 8.0f, 5.0f, 3.0f)), rgm.mapToAncestor(rect, nullptr)); rgm.popMappingsToAncestor(static_cast<PaintLayer*>(nullptr)); - EXPECT_EQ(FloatQuad(FloatRect(0.0f, 0.0f, 5.0f, 3.0f)), rgm.mapToContainer(rect, nullptr)); + EXPECT_EQ(FloatQuad(FloatRect(0.0f, 0.0f, 5.0f, 3.0f)), rgm.mapToAncestor(rect, nullptr)); rgm.pushMappingsToAncestor(getLayoutBox(webView, "Col1"), 0); - EXPECT_EQ(FloatQuad(FloatRect(8.0f, 8.0f, 5.0f, 3.0f)), rgm.mapToContainer(rect, nullptr)); + EXPECT_EQ(FloatQuad(FloatRect(8.0f, 8.0f, 5.0f, 3.0f)), rgm.mapToAncestor(rect, nullptr)); rgm.popMappingsToAncestor(static_cast<PaintLayer*>(nullptr)); rgm.pushMappingsToAncestor(getLayoutBox(webView, "Col2"), nullptr); - EXPECT_NEAR(8.0f + offset, rectFromQuad(rgm.mapToContainer(rect, nullptr)).x(), 0.1f); - EXPECT_NEAR(8.0f, rectFromQuad(rgm.mapToContainer(rect, nullptr)).y(), 0.1f); - EXPECT_EQ(5.0f, rectFromQuad(rgm.mapToContainer(rect, nullptr)).width()); - EXPECT_EQ(3.0f, rectFromQuad(rgm.mapToContainer(rect, nullptr)).height()); + EXPECT_NEAR(8.0f + offset, rectFromQuad(rgm.mapToAncestor(rect, nullptr)).x(), 0.1f); + EXPECT_NEAR(8.0f, rectFromQuad(rgm.mapToAncestor(rect, nullptr)).y(), 0.1f); + EXPECT_EQ(5.0f, rectFromQuad(rgm.mapToAncestor(rect, nullptr)).width()); + EXPECT_EQ(3.0f, rectFromQuad(rgm.mapToAncestor(rect, nullptr)).height()); rgm.popMappingsToAncestor(static_cast<PaintLayer*>(nullptr)); rgm.pushMappingsToAncestor(getLayoutBox(webView, "Col3"), nullptr); - EXPECT_NEAR(8.0f + offset * 2.0f, rectFromQuad(rgm.mapToContainer(rect, nullptr)).x(), 0.1f); - EXPECT_NEAR(8.0f, rectFromQuad(rgm.mapToContainer(rect, nullptr)).y(), 0.1f); - EXPECT_EQ(5.0f, rectFromQuad(rgm.mapToContainer(rect, nullptr)).width()); - EXPECT_EQ(3.0f, rectFromQuad(rgm.mapToContainer(rect, nullptr)).height()); + EXPECT_NEAR(8.0f + offset * 2.0f, rectFromQuad(rgm.mapToAncestor(rect, nullptr)).x(), 0.1f); + EXPECT_NEAR(8.0f, rectFromQuad(rgm.mapToAncestor(rect, nullptr)).y(), 0.1f); + EXPECT_EQ(5.0f, rectFromQuad(rgm.mapToAncestor(rect, nullptr)).width()); + EXPECT_EQ(3.0f, rectFromQuad(rgm.mapToAncestor(rect, nullptr)).height()); }
diff --git a/third_party/WebKit/Source/web/tests/MHTMLTest.cpp b/third_party/WebKit/Source/web/tests/MHTMLTest.cpp index 1c364e5b..091ebde 100644 --- a/third_party/WebKit/Source/web/tests/MHTMLTest.cpp +++ b/third_party/WebKit/Source/web/tests/MHTMLTest.cpp
@@ -36,6 +36,7 @@ #include "platform/SharedBuffer.h" #include "platform/mhtml/MHTMLArchive.h" #include "platform/testing/URLTestHelpers.h" +#include "platform/testing/UnitTestHelpers.h" #include "platform/weborigin/KURL.h" #include "public/platform/Platform.h" #include "public/platform/WebString.h" @@ -79,11 +80,11 @@ size_t m_index; }; -class MHTMLTest : public testing::Test { +class MHTMLTest : public ::testing::Test { public: MHTMLTest() { - m_filePath = Platform::current()->unitTestSupport()->webKitRootDir(); + m_filePath = testing::blinkRootDir(); m_filePath.append("/Source/web/tests/data/mhtml/"); }
diff --git a/third_party/WebKit/Source/web/tests/WebFrameTest.cpp b/third_party/WebKit/Source/web/tests/WebFrameTest.cpp index 7469a0ba..6d006af 100644 --- a/third_party/WebKit/Source/web/tests/WebFrameTest.cpp +++ b/third_party/WebKit/Source/web/tests/WebFrameTest.cpp
@@ -5718,7 +5718,7 @@ TEST_P(ParameterizedWebFrameTest, FirstPartyForCookiesForRedirect) { - WTF::String filePath = Platform::current()->unitTestSupport()->webKitRootDir(); + String filePath = testing::blinkRootDir(); filePath.append("/Source/web/tests/data/first_party.html"); WebURL testURL(toKURL("http://internal.test/first_party_redirect.html"));
diff --git a/third_party/WebKit/Source/web/tests/WebImageTest.cpp b/third_party/WebKit/Source/web/tests/WebImageTest.cpp index bfc173e1..142d49e 100644 --- a/third_party/WebKit/Source/web/tests/WebImageTest.cpp +++ b/third_party/WebKit/Source/web/tests/WebImageTest.cpp
@@ -31,6 +31,7 @@ #include "public/platform/WebImage.h" #include "platform/SharedBuffer.h" +#include "platform/testing/UnitTestHelpers.h" #include "public/platform/Platform.h" #include "public/platform/WebData.h" #include "public/platform/WebSize.h" @@ -41,7 +42,7 @@ static PassRefPtr<SharedBuffer> readFile(const char* fileName) { - String filePath = Platform::current()->unitTestSupport()->webKitRootDir(); + String filePath = testing::blinkRootDir(); filePath.append("/Source/web/tests/data/"); filePath.append(fileName);
diff --git a/third_party/WebKit/Source/web/tests/WebViewTest.cpp b/third_party/WebKit/Source/web/tests/WebViewTest.cpp index 642cb4f9..ff330cdf 100644 --- a/third_party/WebKit/Source/web/tests/WebViewTest.cpp +++ b/third_party/WebKit/Source/web/tests/WebViewTest.cpp
@@ -2472,28 +2472,32 @@ HTMLInputElement* inputElement = toHTMLInputElement(document->getElementById("input")); document->setFocusedElement(inputElement, FocusParams(SelectionBehaviorOnFocus::None, WebFocusTypeNone, nullptr)); webViewImpl->setFocus(true); - WebTextInputInfo info = webViewImpl->textInputInfo(); + WebTextInputInfo info1 = webViewImpl->textInputInfo(); EXPECT_EQ( WebTextInputFlagAutocompleteOff | WebTextInputFlagAutocorrectOff | WebTextInputFlagSpellcheckOff | WebTextInputFlagAutocapitalizeNone, - info.flags); + info1.flags); // (A.2) Verifies autocorrect/autocomplete/spellcheck flags are On and // autocapitalize is set to sentences. inputElement = toHTMLInputElement(document->getElementById("input2")); document->setFocusedElement(inputElement, FocusParams(SelectionBehaviorOnFocus::None, WebFocusTypeNone, nullptr)); webViewImpl->setFocus(true); - info = webViewImpl->textInputInfo(); + WebTextInputInfo info2 = webViewImpl->textInputInfo(); EXPECT_EQ( WebTextInputFlagAutocompleteOn | WebTextInputFlagAutocorrectOn | WebTextInputFlagSpellcheckOn | WebTextInputFlagAutocapitalizeSentences, - info.flags); + info2.flags); // (B) <textarea> Verifies the default text input flags are // WebTextInputFlagAutocapitalizeSentences. HTMLTextAreaElement* textAreaElement = toHTMLTextAreaElement(document->getElementById("textarea")); document->setFocusedElement(textAreaElement, FocusParams(SelectionBehaviorOnFocus::None, WebFocusTypeNone, nullptr)); webViewImpl->setFocus(true); - info = webViewImpl->textInputInfo(); - EXPECT_EQ(WebTextInputFlagAutocapitalizeSentences, info.flags); + WebTextInputInfo info3 = webViewImpl->textInputInfo(); + EXPECT_EQ(WebTextInputFlagAutocapitalizeSentences, info3.flags); + + // (C) Verifies the WebTextInputInfo's don't equal. + EXPECT_FALSE(info1.equals(info2)); + EXPECT_FALSE(info2.equals(info3)); // Free the webView before freeing the NonUserInputTextUpdateWebViewClient. m_webViewHelper.reset();
diff --git a/third_party/WebKit/Source/wtf/BitVector.cpp b/third_party/WebKit/Source/wtf/BitVector.cpp index 69f4c67..1ff094f 100644 --- a/third_party/WebKit/Source/wtf/BitVector.cpp +++ b/third_party/WebKit/Source/wtf/BitVector.cpp
@@ -77,7 +77,6 @@ // Because of the way BitVector stores the pointer, memory tools // will erroneously report a leak here. WTF_INTERNAL_LEAK_SANITIZER_DISABLED_SCOPE; - numBits = (numBits + bitsInPointer() - 1) & ~(bitsInPointer() - 1); numBits = (numBits + bitsInPointer() - 1) & ~(bitsInPointer() - static_cast<size_t>(1)); size_t size = sizeof(OutOfLineBits) + sizeof(uintptr_t) * (numBits / bitsInPointer()); void* allocation = Partitions::bufferMalloc(size, WTF_HEAP_PROFILER_TYPE_NAME(OutOfLineBits));
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/cpp.py b/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/cpp.py index 9bb42f3..6a5d2a0a 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/cpp.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/cpp.py
@@ -1717,7 +1717,7 @@ error: The function to call with any errors found. """ match_ref_or_own_ptr = '(?=\W|^)(Ref|Own)Ptr(WillBeRawPtr)?(?=\W)' - exceptions = '(?:&|\*|\*\s*=\s*0)$' + exceptions = '(?:&|\*|\*\s*=\s*(0|nullptr))$' bad_type_usage = search(match_ref_or_own_ptr, type_text) exception_usage = search(exceptions, type_text) if not bad_type_usage or exception_usage:
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/cpp_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/cpp_unittest.py index b76cf59..54838ad 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/cpp_unittest.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/cpp_unittest.py
@@ -3640,6 +3640,16 @@ '{\n' '}', '') + self.assert_pass_ptr_check( + 'int myFunction(RefPtr<Type1>* = nullptr)\n' + '{\n' + '}', + '') + self.assert_pass_ptr_check( + 'int myFunction(RefPtr<Type1>* = nullptr)\n' + '{\n' + '}', + '') def test_own_ptr_parameter_value(self): self.assert_pass_ptr_check(
diff --git a/third_party/WebKit/public/blink_headers.gypi b/third_party/WebKit/public/blink_headers.gypi index 3e05ce6..fdda320 100644 --- a/third_party/WebKit/public/blink_headers.gypi +++ b/third_party/WebKit/public/blink_headers.gypi
@@ -200,7 +200,6 @@ "platform/WebSelectionBound.h", "platform/WebSetSinkIdCallbacks.h", "platform/WebSize.h", - "platform/WebSkImage.h", "platform/WebSocketHandle.h", "platform/WebSocketHandleClient.h", "platform/WebSocketHandshakeRequestInfo.h",
diff --git a/third_party/WebKit/public/platform/WebCanvasCaptureHandler.h b/third_party/WebKit/public/platform/WebCanvasCaptureHandler.h index 421ab37b..9c48fe89 100644 --- a/third_party/WebKit/public/platform/WebCanvasCaptureHandler.h +++ b/third_party/WebKit/public/platform/WebCanvasCaptureHandler.h
@@ -6,17 +6,16 @@ #define WebCanvasCaptureHandler_h #include "WebCommon.h" -#include "public/platform/WebSkImage.h" + +class SkImage; namespace blink { -class WebSkImage; - // Platform interface of a CanvasCaptureHandler. class BLINK_PLATFORM_EXPORT WebCanvasCaptureHandler { public: virtual ~WebCanvasCaptureHandler() = default; - virtual void sendNewFrame(const WebSkImage& image) {} + virtual void sendNewFrame(const SkImage*) {} virtual bool needsNewFrame() const { return false; } };
diff --git a/third_party/WebKit/public/platform/WebGraphicsContext3D.h b/third_party/WebKit/public/platform/WebGraphicsContext3D.h index a542360..80cf755e 100644 --- a/third_party/WebKit/public/platform/WebGraphicsContext3D.h +++ b/third_party/WebKit/public/platform/WebGraphicsContext3D.h
@@ -391,10 +391,10 @@ virtual void bindUniformLocationCHROMIUM(WebGLId program, WGC3Dint location, const WGC3Dchar* uniform) { } // GL_CHROMIUM_copy_texture - virtual void copyTextureCHROMIUM(WGC3Denum target, WGC3Duint sourceId, + virtual void copyTextureCHROMIUM(WGC3Duint sourceId, WGC3Duint destId, WGC3Denum internalFormat, WGC3Denum destType, WGC3Dboolean unpackFlipY, WGC3Dboolean unpackPremultiplyAlpha, WGC3Dboolean unpackUnmultiplyAlpha) { } - virtual void copySubTextureCHROMIUM(WGC3Denum target, WGC3Duint sourceId, + virtual void copySubTextureCHROMIUM(WGC3Duint sourceId, WGC3Duint destId, WGC3Dint xoffset, WGC3Dint yoffset, WGC3Dint x, WGC3Dint y, WGC3Dsizei width, WGC3Dsizei height, WGC3Dboolean unpackFlipY, WGC3Dboolean unpackPremultiplyAlpha, WGC3Dboolean unpackUnmultiplyAlpha) { }
diff --git a/third_party/WebKit/public/platform/WebSkImage.h b/third_party/WebKit/public/platform/WebSkImage.h deleted file mode 100644 index b9e929e..0000000 --- a/third_party/WebKit/public/platform/WebSkImage.h +++ /dev/null
@@ -1,43 +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 WebSkImage_h -#define WebSkImage_h - -#include "WebPrivatePtr.h" -#include "third_party/skia/include/core/SkImage.h" - -#if INSIDE_BLINK -#include "wtf/Forward.h" -#endif - -namespace blink { - -// A container for an SkImage -class BLINK_PLATFORM_EXPORT WebSkImage { -public: - WebSkImage(); - WebSkImage(const WebSkImage&); - ~WebSkImage(); - - bool isNull() const { return m_image.isNull(); } - int width() const; - int height() const; - bool readPixels(const SkImageInfo& dstInfo, - void* dstPixels, - size_t dstRowBytes, - int srcX, - int srcY) const; - -#if INSIDE_BLINK - WebSkImage(const WTF::PassRefPtr<SkImage>&); - WebSkImage& operator=(const WTF::PassRefPtr<SkImage>&); -#endif -private: - WebPrivatePtr<SkImage> m_image; -}; - -} // namespace blink - -#endif // WebSkImage_h
diff --git a/third_party/WebKit/public/platform/WebUnitTestSupport.h b/third_party/WebKit/public/platform/WebUnitTestSupport.h index 2cdca224..85609d9 100644 --- a/third_party/WebKit/public/platform/WebUnitTestSupport.h +++ b/third_party/WebKit/public/platform/WebUnitTestSupport.h
@@ -56,9 +56,6 @@ // Set a delegate that allows callbacks for all WebURLLoaderClients to be intercepted. virtual void setLoaderDelegate(WebURLLoaderTestDelegate*) { } - // Returns the root directory of the WebKit code. - virtual WebString webKitRootDir() { return WebString(); } - // Constructs a WebLayerTreeView set up with reasonable defaults for // testing. virtual WebLayerTreeView* createLayerTreeViewForTesting() { return nullptr; }
diff --git a/third_party/WebKit/public/web/WebContentSettingsClient.h b/third_party/WebKit/public/web/WebContentSettingsClient.h index dc957e1f..3d285d2 100644 --- a/third_party/WebKit/public/web/WebContentSettingsClient.h +++ b/third_party/WebKit/public/web/WebContentSettingsClient.h
@@ -84,6 +84,9 @@ // Notifies the client that the frame would have executed script if script were enabled. virtual void didNotAllowScript() { } + // Notifies the client that the frame instantiated a keygen element. + virtual void didUseKeygen() { } + virtual ~WebContentSettingsClient() { } };
diff --git a/third_party/accessibility-audit/OWNERS b/third_party/accessibility-audit/OWNERS new file mode 100644 index 0000000..cd795ab --- /dev/null +++ b/third_party/accessibility-audit/OWNERS
@@ -0,0 +1 @@ +aboxhall@chromium.org \ No newline at end of file
diff --git a/third_party/accessibility-audit/README.chromium b/third_party/accessibility-audit/README.chromium index 8df33898..6cf4986 100644 --- a/third_party/accessibility-audit/README.chromium +++ b/third_party/accessibility-audit/README.chromium
@@ -2,7 +2,7 @@ Short Name: accessibility-audit URL: https://raw.githubusercontent.com/GoogleChrome/accessibility-developer-tools/master/dist/js/axs_testing.js Version: 0 -Revision: 3d4893b4ecd0eb8f4765e04479213d04b240f3e0 +Revision: 404ede0f2186682fbbef624141e76ec2b601317d License: Apache 2.0 License File: LICENSE Security Critical: no
diff --git a/third_party/accessibility-audit/axs_testing.js b/third_party/accessibility-audit/axs_testing.js index f0e6f4a..f075a05 100644 --- a/third_party/accessibility-audit/axs_testing.js +++ b/third_party/accessibility-audit/axs_testing.js
@@ -1,5 +1,5 @@ /* - * Copyright 2014 Google Inc. + * Copyright 2015 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,14 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. * - * Generated from http://github.com/GoogleChrome/accessibility-developer-tools/tree/3d4893b4ecd0eb8f4765e04479213d04b240f3e0 + * Generated from http://github.com/GoogleChrome/accessibility-developer-tools/tree/404ede0f2186682fbbef624141e76ec2b601317d * * See project README for build steps. */ - + // AUTO-GENERATED CONTENT BELOW: DO NOT EDIT! See above for details. -var COMPILED = !0, goog = goog || {}; +var fn = (function() { + var COMPILED = !0, goog = goog || {}; goog.global = this; goog.isDef = function(a) { return void 0 !== a; @@ -62,7 +63,7 @@ goog.forwardDeclare = function(a) { }; COMPILED || (goog.isProvided_ = function(a) { - return!goog.implicitNamespaces_[a] && goog.isDefAndNotNull(goog.getObjectByName(a)); + return !goog.implicitNamespaces_[a] && goog.isDefAndNotNull(goog.getObjectByName(a)); }, goog.implicitNamespaces_ = {}); goog.getObjectByName = function(a, b) { for (var c = a.split("."), d = b || goog.global, e;e = c.shift();) { @@ -153,14 +154,14 @@ var b = goog.global.document; if ("complete" == b.readyState) { if (/\bdeps.js$/.test(a)) { - return!1; + return !1; } throw Error('Cannot write "' + a + '" after document load'); } b.write('<script type="text/javascript" src="' + a + '">\x3c/script>'); - return!0; + return !0; } - return!1; + return !1; }, goog.writeScripts_ = function() { function a(e) { if (!(e in d.written)) { @@ -258,7 +259,7 @@ return a[goog.UID_PROPERTY_] || (a[goog.UID_PROPERTY_] = ++goog.uidCounter_); }; goog.hasUid = function(a) { - return!!a[goog.UID_PROPERTY_]; + return !!a[goog.UID_PROPERTY_]; }; goog.removeUid = function(a) { "removeAttribute" in a && a.removeAttribute(goog.UID_PROPERTY_); @@ -322,7 +323,7 @@ } }; goog.now = goog.TRUSTED_SITE && Date.now || function() { - return+new Date; + return +new Date; }; goog.globalEval = function(a) { if (goog.global.execScript) { @@ -421,24 +422,24 @@ var axs = {}; axs.browserUtils = {}; axs.browserUtils.matchSelector = function(a, b) { - return a.webkitMatchesSelector ? a.webkitMatchesSelector(b) : a.mozMatchesSelector ? a.mozMatchesSelector(b) : !1; + return a.matches ? a.matches(b) : a.webkitMatchesSelector ? a.webkitMatchesSelector(b) : a.mozMatchesSelector ? a.mozMatchesSelector(b) : a.msMatchesSelector ? a.msMatchesSelector(b) : !1; }; axs.constants = {}; axs.constants.ARIA_ROLES = {alert:{namefrom:["author"], parent:["region"]}, alertdialog:{namefrom:["author"], namerequired:!0, parent:["alert", "dialog"]}, application:{namefrom:["author"], namerequired:!0, parent:["landmark"]}, article:{namefrom:["author"], parent:["document", "region"]}, banner:{namefrom:["author"], parent:["landmark"]}, button:{childpresentational:!0, namefrom:["contents", "author"], namerequired:!0, parent:["command"], properties:["aria-expanded", "aria-pressed"]}, checkbox:{namefrom:["contents", -"author"], namerequired:!0, parent:["input"], requiredProperties:["aria-checked"], properties:["aria-checked"]}, columnheader:{namefrom:["contents", "author"], namerequired:!0, parent:["gridcell", "sectionhead", "widget"], properties:["aria-sort"]}, combobox:{mustcontain:["listbox", "textbox"], namefrom:["author"], namerequired:!0, parent:["select"], requiredProperties:["aria-expanded"], properties:["aria-expanded", "aria-autocomplete", "aria-required"]}, command:{"abstract":!0, namefrom:["author"], +"author"], namerequired:!0, parent:["input"], requiredProperties:["aria-checked"], properties:["aria-checked"]}, columnheader:{namefrom:["contents", "author"], namerequired:!0, parent:["gridcell", "sectionhead", "widget"], properties:["aria-sort"], scope:["row"]}, combobox:{mustcontain:["listbox", "textbox"], namefrom:["author"], namerequired:!0, parent:["select"], requiredProperties:["aria-expanded"], properties:["aria-expanded", "aria-autocomplete", "aria-required"]}, command:{"abstract":!0, namefrom:["author"], parent:["widget"]}, complementary:{namefrom:["author"], parent:["landmark"]}, composite:{"abstract":!0, childpresentational:!1, namefrom:["author"], parent:["widget"], properties:["aria-activedescendant"]}, contentinfo:{namefrom:["author"], parent:["landmark"]}, definition:{namefrom:["author"], parent:["section"]}, dialog:{namefrom:["author"], namerequired:!0, parent:["window"]}, directory:{namefrom:["contents", "author"], parent:["list"]}, document:{namefrom:[" author"], namerequired:!0, parent:["structure"], -properties:["aria-expanded"]}, form:{namefrom:["author"], parent:["landmark"]}, grid:{mustcontain:["row", "rowgroup"], namefrom:["author"], namerequired:!0, parent:["composite", "region"], properties:["aria-level", "aria-multiselectable", "aria-readonly"]}, gridcell:{namefrom:["contents", "author"], namerequired:!0, parent:["section", "widget"], properties:["aria-readonly", "aria-required", "aria-selected"]}, group:{namefrom:[" author"], parent:["section"], properties:["aria-activedescendant"]}, +properties:["aria-expanded"]}, form:{namefrom:["author"], parent:["landmark"]}, grid:{mustcontain:["row", "rowgroup"], namefrom:["author"], namerequired:!0, parent:["composite", "region"], properties:["aria-level", "aria-multiselectable", "aria-readonly"]}, gridcell:{namefrom:["contents", "author"], namerequired:!0, parent:["section", "widget"], properties:["aria-readonly", "aria-required", "aria-selected"], scope:["row"]}, group:{namefrom:[" author"], parent:["section"], properties:["aria-activedescendant"]}, heading:{namerequired:!0, parent:["sectionhead"], properties:["aria-level"]}, img:{childpresentational:!0, namefrom:["author"], namerequired:!0, parent:["section"]}, input:{"abstract":!0, namefrom:["author"], parent:["widget"]}, landmark:{"abstract":!0, namefrom:["contents", "author"], namerequired:!1, parent:["region"]}, link:{namefrom:["contents", "author"], namerequired:!0, parent:["command"], properties:["aria-expanded"]}, list:{mustcontain:["group", "listitem"], namefrom:["author"], parent:["region"]}, -listbox:{mustcontain:["option"], namefrom:["author"], namerequired:!0, parent:["list", "select"], properties:["aria-multiselectable", "aria-required"]}, listitem:{namefrom:["contents", "author"], namerequired:!0, parent:["section"], properties:["aria-level", "aria-posinset", "aria-setsize"]}, log:{namefrom:[" author"], namerequired:!0, parent:["region"]}, main:{namefrom:["author"], parent:["landmark"]}, marquee:{namerequired:!0, parent:["section"]}, math:{childpresentational:!0, namefrom:["author"], -parent:["section"]}, menu:{mustcontain:["group", "menuitemradio", "menuitem", "menuitemcheckbox"], namefrom:["author"], namerequired:!0, parent:["list", "select"]}, menubar:{namefrom:["author"], parent:["menu"]}, menuitem:{namefrom:["contents", "author"], namerequired:!0, parent:["command"]}, menuitemcheckbox:{namefrom:["contents", "author"], namerequired:!0, parent:["checkbox", "menuitem"]}, menuitemradio:{namefrom:["contents", "author"], namerequired:!0, parent:["menuitemcheckbox", "radio"]}, navigation:{namefrom:["author"], -parent:["landmark"]}, note:{namefrom:["author"], parent:["section"]}, option:{namefrom:["contents", "author"], namerequired:!0, parent:["input"], properties:["aria-checked", "aria-posinset", "aria-selected", "aria-setsize"]}, presentation:{parent:["structure"]}, progressbar:{childpresentational:!0, namefrom:["author"], namerequired:!0, parent:["range"]}, radio:{namefrom:["contents", "author"], namerequired:!0, parent:["checkbox", "option"]}, radiogroup:{mustcontain:["radio"], namefrom:["author"], -namerequired:!0, parent:["select"], properties:["aria-required"]}, range:{"abstract":!0, namefrom:["author"], parent:["widget"], properties:["aria-valuemax", "aria-valuemin", "aria-valuenow", "aria-valuetext"]}, region:{namefrom:[" author"], parent:["section"]}, roletype:{"abstract":!0, properties:"aria-atomic aria-busy aria-controls aria-describedby aria-disabled aria-dropeffect aria-flowto aria-grabbed aria-haspopup aria-hidden aria-invalid aria-label aria-labelledby aria-live aria-owns aria-relevant".split(" ")}, -row:{mustcontain:["columnheader", "gridcell", "rowheader"], namefrom:["contents", "author"], parent:["group", "widget"], properties:["aria-level", "aria-selected"]}, rowgroup:{mustcontain:["row"], namefrom:["contents", "author"], parent:["group"]}, rowheader:{namefrom:["contents", "author"], namerequired:!0, parent:["gridcell", "sectionhead", "widget"], properties:["aria-sort"]}, search:{namefrom:["author"], parent:["landmark"]}, section:{"abstract":!0, namefrom:["contents", "author"], parent:["structure"], -properties:["aria-expanded"]}, sectionhead:{"abstract":!0, namefrom:["contents", "author"], parent:["structure"], properties:["aria-expanded"]}, select:{"abstract":!0, namefrom:["author"], parent:["composite", "group", "input"]}, separator:{childpresentational:!0, namefrom:["author"], parent:["structure"], properties:["aria-expanded", "aria-orientation"]}, scrollbar:{childpresentational:!0, namefrom:["author"], namerequired:!1, parent:["input", "range"], requiredProperties:["aria-controls", "aria-orientation", -"aria-valuemax", "aria-valuemin", "aria-valuenow"], properties:["aria-controls", "aria-orientation", "aria-valuemax", "aria-valuemin", "aria-valuenow"]}, slider:{childpresentational:!0, namefrom:["author"], namerequired:!0, parent:["input", "range"], requiredProperties:["aria-valuemax", "aria-valuemin", "aria-valuenow"], properties:["aria-valuemax", "aria-valuemin", "aria-valuenow", "aria-orientation"]}, spinbutton:{namefrom:["author"], namerequired:!0, parent:["input", "range"], requiredProperties:["aria-valuemax", -"aria-valuemin", "aria-valuenow"], properties:["aria-valuemax", "aria-valuemin", "aria-valuenow", "aria-required"]}, status:{parent:["region"]}, structure:{"abstract":!0, parent:["roletype"]}, tab:{namefrom:["contents", "author"], parent:["sectionhead", "widget"], properties:["aria-selected"]}, tablist:{mustcontain:["tab"], namefrom:["author"], parent:["composite", "directory"], properties:["aria-level"]}, tabpanel:{namefrom:["author"], namerequired:!0, parent:["region"]}, textbox:{namefrom:["author"], -namerequired:!0, parent:["input"], properties:["aria-activedescendant", "aria-autocomplete", "aria-multiline", "aria-readonly", "aria-required"]}, timer:{namefrom:["author"], namerequired:!0, parent:["status"]}, toolbar:{namefrom:["author"], parent:["group"]}, tooltip:{namerequired:!0, parent:["section"]}, tree:{mustcontain:["group", "treeitem"], namefrom:["author"], namerequired:!0, parent:["select"], properties:["aria-multiselectable", "aria-required"]}, treegrid:{mustcontain:["row"], namefrom:["author"], -namerequired:!0, parent:["grid", "tree"]}, treeitem:{namefrom:["contents", "author"], namerequired:!0, parent:["listitem", "option"]}, widget:{"abstract":!0, parent:["roletype"]}, window:{"abstract":!0, namefrom:[" author"], parent:["roletype"], properties:["aria-expanded"]}}; +listbox:{mustcontain:["option"], namefrom:["author"], namerequired:!0, parent:["list", "select"], properties:["aria-multiselectable", "aria-required"]}, listitem:{namefrom:["contents", "author"], namerequired:!0, parent:["section"], properties:["aria-level", "aria-posinset", "aria-setsize"], scope:["list"]}, log:{namefrom:[" author"], namerequired:!0, parent:["region"]}, main:{namefrom:["author"], parent:["landmark"]}, marquee:{namerequired:!0, parent:["section"]}, math:{childpresentational:!0, namefrom:["author"], +parent:["section"]}, menu:{mustcontain:["group", "menuitemradio", "menuitem", "menuitemcheckbox"], namefrom:["author"], namerequired:!0, parent:["list", "select"]}, menubar:{namefrom:["author"], parent:["menu"]}, menuitem:{namefrom:["contents", "author"], namerequired:!0, parent:["command"], scope:["menu", "menubar"]}, menuitemcheckbox:{namefrom:["contents", "author"], namerequired:!0, parent:["checkbox", "menuitem"], scope:["menu", "menubar"]}, menuitemradio:{namefrom:["contents", "author"], namerequired:!0, +parent:["menuitemcheckbox", "radio"], scope:["menu", "menubar"]}, navigation:{namefrom:["author"], parent:["landmark"]}, note:{namefrom:["author"], parent:["section"]}, option:{namefrom:["contents", "author"], namerequired:!0, parent:["input"], properties:["aria-checked", "aria-posinset", "aria-selected", "aria-setsize"]}, presentation:{parent:["structure"]}, progressbar:{childpresentational:!0, namefrom:["author"], namerequired:!0, parent:["range"]}, radio:{namefrom:["contents", "author"], namerequired:!0, +parent:["checkbox", "option"]}, radiogroup:{mustcontain:["radio"], namefrom:["author"], namerequired:!0, parent:["select"], properties:["aria-required"]}, range:{"abstract":!0, namefrom:["author"], parent:["widget"], properties:["aria-valuemax", "aria-valuemin", "aria-valuenow", "aria-valuetext"]}, region:{namefrom:[" author"], parent:["section"]}, roletype:{"abstract":!0, properties:"aria-atomic aria-busy aria-controls aria-describedby aria-disabled aria-dropeffect aria-flowto aria-grabbed aria-haspopup aria-hidden aria-invalid aria-label aria-labelledby aria-live aria-owns aria-relevant".split(" ")}, +row:{mustcontain:["columnheader", "gridcell", "rowheader"], namefrom:["contents", "author"], parent:["group", "widget"], properties:["aria-level", "aria-selected"], scope:["grid", "rowgroup", "treegrid"]}, rowgroup:{mustcontain:["row"], namefrom:["contents", "author"], parent:["group"], scope:["grid"]}, rowheader:{namefrom:["contents", "author"], namerequired:!0, parent:["gridcell", "sectionhead", "widget"], properties:["aria-sort"], scope:["row"]}, search:{namefrom:["author"], parent:["landmark"]}, +section:{"abstract":!0, namefrom:["contents", "author"], parent:["structure"], properties:["aria-expanded"]}, sectionhead:{"abstract":!0, namefrom:["contents", "author"], parent:["structure"], properties:["aria-expanded"]}, select:{"abstract":!0, namefrom:["author"], parent:["composite", "group", "input"]}, separator:{childpresentational:!0, namefrom:["author"], parent:["structure"], properties:["aria-expanded", "aria-orientation"]}, scrollbar:{childpresentational:!0, namefrom:["author"], namerequired:!1, +parent:["input", "range"], requiredProperties:["aria-controls", "aria-orientation", "aria-valuemax", "aria-valuemin", "aria-valuenow"], properties:["aria-controls", "aria-orientation", "aria-valuemax", "aria-valuemin", "aria-valuenow"]}, slider:{childpresentational:!0, namefrom:["author"], namerequired:!0, parent:["input", "range"], requiredProperties:["aria-valuemax", "aria-valuemin", "aria-valuenow"], properties:["aria-valuemax", "aria-valuemin", "aria-valuenow", "aria-orientation"]}, spinbutton:{namefrom:["author"], +namerequired:!0, parent:["input", "range"], requiredProperties:["aria-valuemax", "aria-valuemin", "aria-valuenow"], properties:["aria-valuemax", "aria-valuemin", "aria-valuenow", "aria-required"]}, status:{parent:["region"]}, structure:{"abstract":!0, parent:["roletype"]}, tab:{namefrom:["contents", "author"], parent:["sectionhead", "widget"], properties:["aria-selected"], scope:["tablist"]}, tablist:{mustcontain:["tab"], namefrom:["author"], parent:["composite", "directory"], properties:["aria-level"]}, +tabpanel:{namefrom:["author"], namerequired:!0, parent:["region"]}, textbox:{namefrom:["author"], namerequired:!0, parent:["input"], properties:["aria-activedescendant", "aria-autocomplete", "aria-multiline", "aria-readonly", "aria-required"]}, timer:{namefrom:["author"], namerequired:!0, parent:["status"]}, toolbar:{namefrom:["author"], parent:["group"]}, tooltip:{namerequired:!0, parent:["section"]}, tree:{mustcontain:["group", "treeitem"], namefrom:["author"], namerequired:!0, parent:["select"], +properties:["aria-multiselectable", "aria-required"]}, treegrid:{mustcontain:["row"], namefrom:["author"], namerequired:!0, parent:["grid", "tree"]}, treeitem:{namefrom:["contents", "author"], namerequired:!0, parent:["listitem", "option"], scope:["group", "tree"]}, widget:{"abstract":!0, parent:["roletype"]}, window:{"abstract":!0, namefrom:[" author"], parent:["roletype"], properties:["aria-expanded"]}}; axs.constants.WIDGET_ROLES = {}; axs.constants.addAllParentRolesToSet_ = function(a, b) { if (a.parent) { @@ -480,7 +481,18 @@ multiline:{defaultValue:"false", type:"property", valueType:"boolean"}, multiselectable:{defaultValue:"false", type:"property", valueType:"boolean"}, orientation:{defaultValue:"vertical", type:"property", valueType:"token", values:["horizontal", "vertical"]}, owns:{type:"property", valueType:"idref_list"}, posinset:{type:"property", valueType:"integer"}, pressed:{defaultValue:"undefined", type:"state", valueType:"token", values:["true", "false", "mixed", "undefined"]}, readonly:{defaultValue:"false", type:"property", valueType:"boolean"}, relevant:{defaultValue:"additions text", type:"property", valueType:"token_list", values:["additions", "removals", "text", "all"]}, required:{defaultValue:"false", type:"property", valueType:"boolean"}, selected:{defaultValue:"undefined", type:"state", valueType:"token", values:["true", "false", "undefined"]}, setsize:{type:"property", valueType:"integer"}, sort:{defaultValue:"none", type:"property", valueType:"token", values:["ascending", "descending", "none", "other"]}, valuemax:{type:"property", valueType:"decimal"}, valuemin:{type:"property", valueType:"decimal"}, valuenow:{type:"property", valueType:"decimal"}, valuetext:{type:"property", valueType:"string"}}; -axs.constants.GLOBAL_PROPERTIES = "aria-atomic aria-busy aria-controls aria-describedby aria-disabled aria-dropeffect aria-flowto aria-grabbed aria-haspopup aria-hidden aria-invalid aria-label aria-labelledby aria-live aria-owns aria-relevant".split(" "); +(function() { + for (var a in axs.constants.ARIA_PROPERTIES) { + var b = axs.constants.ARIA_PROPERTIES[a]; + if (b.values) { + for (var c = {}, d = 0;d < b.values.length;d++) { + c[b.values[d]] = !0; + } + b.valuesSet = c; + } + } +})(); +axs.constants.GLOBAL_PROPERTIES = axs.constants.ARIA_ROLES.roletype.propertiesSet; axs.constants.NO_ROLE_NAME = " "; axs.constants.WIDGET_ROLE_TO_NAME = {alert:"aria_role_alert", alertdialog:"aria_role_alertdialog", button:"aria_role_button", checkbox:"aria_role_checkbox", columnheader:"aria_role_columnheader", combobox:"aria_role_combobox", dialog:"aria_role_dialog", grid:"aria_role_grid", gridcell:"aria_role_gridcell", link:"aria_role_link", listbox:"aria_role_listbox", log:"aria_role_log", marquee:"aria_role_marquee", menu:"aria_role_menu", menubar:"aria_role_menubar", menuitem:"aria_role_menuitem", menuitemcheckbox:"aria_role_menuitemcheckbox", menuitemradio:"aria_role_menuitemradio", option:axs.constants.NO_ROLE_NAME, progressbar:"aria_role_progressbar", radio:"aria_role_radio", radiogroup:"aria_role_radiogroup", rowheader:"aria_role_rowheader", scrollbar:"aria_role_scrollbar", slider:"aria_role_slider", spinbutton:"aria_role_spinbutton", status:"aria_role_status", tab:"aria_role_tab", tabpanel:"aria_role_tabpanel", textbox:"aria_role_textbox", timer:"aria_role_timer", toolbar:"aria_role_toolbar", tooltip:"aria_role_tooltip", treeitem:"aria_role_treeitem"}; @@ -494,80 +506,277 @@ axs.constants.TAG_TO_INFORMATION_TABLE_VERBOSE_MSG = {A:"tag_link", BUTTON:"tag_button", H1:"tag_h1", H2:"tag_h2", H3:"tag_h3", H4:"tag_h4", H5:"tag_h5", H6:"tag_h6", LI:"tag_li", OL:"tag_ol", SELECT:"tag_select", TEXTAREA:"tag_textarea", UL:"tag_ul", SECTION:"tag_section", NAV:"tag_nav", ARTICLE:"tag_article", ASIDE:"tag_aside", HGROUP:"tag_hgroup", HEADER:"tag_header", FOOTER:"tag_footer", TIME:"tag_time", MARK:"tag_mark"}; axs.constants.TAG_TO_INFORMATION_TABLE_BRIEF_MSG = {BUTTON:"tag_button", SELECT:"tag_select", TEXTAREA:"tag_textarea"}; axs.constants.MIXED_VALUES = {"true":!0, "false":!0, mixed:!0}; -(function() { - for (var a in axs.constants.ARIA_PROPERTIES) { - var b = axs.constants.ARIA_PROPERTIES[a]; - if (b.values) { - for (var c = {}, d = 0;d < b.values.length;d++) { - c[b.values[d]] = !0; - } - b.valuesSet = c; - } - } -})(); axs.constants.Severity = {INFO:"Info", WARNING:"Warning", SEVERE:"Severe"}; axs.constants.AuditResult = {PASS:"PASS", FAIL:"FAIL", NA:"NA"}; axs.constants.InlineElements = {TT:!0, I:!0, B:!0, BIG:!0, SMALL:!0, EM:!0, STRONG:!0, DFN:!0, CODE:!0, SAMP:!0, KBD:!0, VAR:!0, CITE:!0, ABBR:!0, ACRONYM:!0, A:!0, IMG:!0, OBJECT:!0, BR:!0, SCRIPT:!0, MAP:!0, Q:!0, SUB:!0, SUP:!0, SPAN:!0, BDO:!0, INPUT:!0, SELECT:!0, TEXTAREA:!0, LABEL:!0, BUTTON:!0}; -axs.utils = {}; -axs.utils.FOCUSABLE_ELEMENTS_SELECTOR = "input:not([type=hidden]):not([disabled]),select:not([disabled]),textarea:not([disabled]),button:not([disabled]),a[href],iframe,[tabindex]"; -axs.utils.Color = function(a, b, c, d) { +axs.constants.NATIVELY_DISABLEABLE = {BUTTON:!0, INPUT:!0, SELECT:!0, TEXTAREA:!0, FIELDSET:!0, OPTGROUP:!0, OPTION:!0}; +axs.constants.ARIA_TO_HTML_ATTRIBUTE = {"aria-checked":"checked", "aria-disabled":"disabled", "aria-hidden":"hidden", "aria-expanded":"open", "aria-valuemax":"max", "aria-valuemin":"min", "aria-readonly":"readonly", "aria-required":"required", "aria-selected":"selected", "aria-valuenow":"value"}; +axs.constants.TAG_TO_IMPLICIT_SEMANTIC_INFO = {A:[{role:"link", allowed:"button checkbox menuitem menuitemcheckbox menuitemradio tab treeitem".split(" "), selector:"a[href]"}], ADDRESS:[{role:"", allowed:["contentinfo", "presentation"]}], AREA:[{role:"link", selector:"area[href]"}], ARTICLE:[{role:"article", allowed:["presentation", "article", "document", "application", "main"]}], ASIDE:[{role:"complementary", allowed:["note", "complementary", "search", "presentation"]}], AUDIO:[{role:"", allowed:["application", +"presentation"]}], BASE:[{role:"", reserved:!0}], BODY:[{role:"document", allowed:["presentation"]}], BUTTON:[{role:"button", allowed:["link", "menuitem", "menuitemcheckbox", "menuitemradio", "radio"], selector:'button:not([aria-pressed]):not([type="menu"])'}, {role:"button", allowed:["button"], selector:"button[aria-pressed]"}, {role:"button", attributes:{"aria-haspopup":!0}, allowed:["link", "menuitem", "menuitemcheckbox", "menuitemradio", "radio"], selector:'button[type="menu"]'}], CAPTION:[{role:"", +allowed:["presentation"]}], COL:[{role:"", reserved:!0}], COLGROUP:[{role:"", reserved:!0}], DATALIST:[{role:"listbox", attributes:{"aria-multiselectable":!1}, allowed:["presentation"]}], DEL:[{role:"", allowed:["*"]}], DD:[{role:"", allowed:["presentation"]}], DT:[{role:"", allowed:["presentation"]}], DETAILS:[{role:"group", allowed:["group", "presentation"]}], DIALOG:[{role:"dialog", allowed:"dialog alert alertdialog application log marquee status".split(" "), selector:"dialog[open]"}, {role:"dialog", +attributes:{"aria-hidden":!0}, allowed:"dialog alert alertdialog application log marquee status".split(" "), selector:"dialog:not([open])"}], DIV:[{role:"", allowed:["*"]}], DL:[{role:"list", allowed:["presentation"]}], EMBED:[{role:"", allowed:["application", "document", "img", "presentation"]}], FIGURE:[{role:"", allowed:["*"]}], FOOTER:[{role:"", allowed:["contentinfo", "presentation"]}], FORM:[{role:"form", allowed:["presentation"]}], P:[{role:"", allowed:["*"]}], PRE:[{role:"", allowed:["*"]}], +BLOCKQUOTE:[{role:"", allowed:["*"]}], H1:[{role:"heading"}], H2:[{role:"heading"}], H3:[{role:"heading"}], H4:[{role:"heading"}], H5:[{role:"heading"}], H6:[{role:"heading"}], HEAD:[{role:"", reserved:!0}], HEADER:[{role:"", allowed:["banner", "presentation"]}], HR:[{role:"separator", allowed:["presentation"]}], HTML:[{role:"", reserved:!0}], IFRAME:[{role:"", allowed:["application", "document", "img", "presentation"], selector:"iframe:not([seamless])"}, {role:"", allowed:["application", "document", +"img", "presentation", "group"], selector:"iframe[seamless]"}], IMG:[{role:"presentation", reserved:!0, selector:'img[alt=""]'}, {role:"img", allowed:["*"], selector:'img[alt]:not([alt=""])'}], INPUT:[{role:"button", allowed:["link", "menuitem", "menuitemcheckbox", "menuitemradio", "radio"], selector:'input[type="button"]:not([aria-pressed])'}, {role:"button", allowed:["button"], selector:'input[type="button"][aria-pressed]'}, {role:"checkbox", allowed:["checkbox"], selector:'input[type="checkbox"]'}, +{role:"", selector:'input[type="color"]'}, {role:"", selector:'input[type="date"]'}, {role:"", selector:'input[type="datetime"]'}, {role:"textbox", selector:'input[type="email"]:not([list])'}, {role:"", selector:'input[type="file"]'}, {role:"", reserved:!0, selector:'input[type="hidden"]'}, {role:"button", allowed:["button"], selector:'input[type="image"][aria-pressed]'}, {role:"button", allowed:["link", "menuitem", "menuitemcheckbox", "menuitemradio", "radio"], selector:'input[type="image"]:not([aria-pressed])'}, +{role:"", selector:'input[type="month"]'}, {role:"", selector:'input[type="number"]'}, {role:"textbox", selector:'input[type="password"]'}, {role:"radio", allowed:["menuitemradio"], selector:'input[type="radio"]'}, {role:"slider", selector:'input[type="range"]'}, {role:"button", selector:'input[type="reset"]'}, {role:"combobox", selector:'input[type="search"][list]'}, {role:"textbox", selector:'input[type="search"]:not([list])'}, {role:"button", selector:'input[type="submit"]'}, {role:"combobox", +selector:'input[type="tel"][list]'}, {role:"textbox", selector:'input[type="tel"]:not([list])'}, {role:"combobox", selector:'input[type="text"][list]'}, {role:"textbox", selector:'input[type="text"]:not([list])'}, {role:"textbox", selector:"input:not([type])"}, {role:"", selector:'input[type="time"]'}, {role:"combobox", selector:'input[type="url"][list]'}, {role:"textbox", selector:'input[type="url"]:not([list])'}, {role:"", selector:'input[type="week"]'}], INS:[{role:"", allowed:["*"]}], KEYGEN:[{role:""}], +LABEL:[{role:"", allowed:["presentation"]}], LI:[{role:"listitem", allowed:"menuitem menuitemcheckbox menuitemradio option tab treeitem presentation".split(" "), selector:'ol:not([role="presentation"])>li, ul:not([role="presentation"])>li'}, {role:"listitem", allowed:"listitem menuitem menuitemcheckbox menuitemradio option tab treeitem presentation".split(" "), selector:'ol[role="presentation"]>li, ul[role="presentation"]>li'}], LINK:[{role:"link", reserved:!0, selector:"link[href]"}], MAIN:[{role:"", +allowed:["main", "presentation"]}], MAP:[{role:"", reserved:!0}], MATH:[{role:"", allowed:["presentation"]}], MENU:[{role:"toolbar", selector:'menu[type="toolbar"]'}], MENUITEM:[{role:"menuitem", selector:'menuitem[type="command"]'}, {role:"menuitemcheckbox", selector:'menuitem[type="checkbox"]'}, {role:"menuitemradio", selector:'menuitem[type="radio"]'}], META:[{role:"", reserved:!0}], METER:[{role:"progressbar", allowed:["presentation"]}], NAV:[{role:"navigation", allowed:["navigation", "presentation"]}], +NOSCRIPT:[{role:"", reserved:!0}], OBJECT:[{role:"", allowed:["application", "document", "img", "presentation"]}], OL:[{role:"list", allowed:"directory group listbox menu menubar tablist toolbar tree presentation".split(" ")}], OPTGROUP:[{role:"", allowed:["presentation"]}], OPTION:[{role:"option"}], OUTPUT:[{role:"status", allowed:["*"]}], PARAM:[{role:"", reserved:!0}], PICTURE:[{role:"", reserved:!0}], PROGRESS:[{role:"progressbar", allowed:["presentation"]}], SCRIPT:[{role:"", reserved:!0}], +SECTION:[{role:"region", allowed:"alert alertdialog application contentinfo dialog document log marquee search status presentation".split(" ")}], SELECT:[{role:"listbox"}], SOURCE:[{role:"", reserved:!0}], SPAN:[{role:"", allowed:["*"]}], STYLE:[{role:"", reserved:!0}], SVG:[{role:"", allowed:["application", "document", "img", "presentation"]}], SUMMARY:[{role:"", allowed:["presentation"]}], TABLE:[{role:"", allowed:["*"]}], TEMPLATE:[{role:"", reserved:!0}], TEXTAREA:[{role:"textbox"}], TBODY:[{role:"rowgroup", +allowed:["*"]}], THEAD:[{role:"rowgroup", allowed:["*"]}], TFOOT:[{role:"rowgroup", allowed:["*"]}], TITLE:[{role:"", reserved:!0}], TD:[{role:"", allowed:["*"]}], TH:[{role:"", allowed:["*"]}], TR:[{role:"", allowed:["*"]}], TRACK:[{role:"", reserved:!0}], UL:[{role:"list", allowed:"directory group listbox menu menubar tablist toolbar tree presentation".split(" ")}], VIDEO:[{role:"", allowed:["application", "presentation"]}]}; +axs.color = {}; +axs.color.Color = function(a, b, c, d) { this.red = a; this.green = b; this.blue = c; this.alpha = d; }; -axs.utils.calculateContrastRatio = function(a, b) { - if (!a || !b) { - return null; +axs.color.YCbCr = function(a) { + this.luma = this.z = a[0]; + this.Cb = this.x = a[1]; + this.Cr = this.y = a[2]; +}; +axs.color.YCbCr.prototype = {multiply:function(a) { + return new axs.color.YCbCr([this.luma * a, this.Cb * a, this.Cr * a]); +}, add:function(a) { + return new axs.color.YCbCr([this.luma + a.luma, this.Cb + a.Cb, this.Cr + a.Cr]); +}, subtract:function(a) { + return new axs.color.YCbCr([this.luma - a.luma, this.Cb - a.Cb, this.Cr - a.Cr]); +}}; +axs.color.calculateContrastRatio = function(a, b) { + 1 > a.alpha && (a = axs.color.flattenColors(a, b)); + var c = axs.color.calculateLuminance(a), d = axs.color.calculateLuminance(b); + return (Math.max(c, d) + .05) / (Math.min(c, d) + .05); +}; +axs.color.calculateLuminance = function(a) { + return axs.color.toYCbCr(a).luma; +}; +axs.color.luminanceRatio = function(a, b) { + return (Math.max(a, b) + .05) / (Math.min(a, b) + .05); +}; +axs.color.parseColor = function(a) { + if ("transparent" === a) { + return new axs.color.Color(0, 0, 0, 0); } - 1 > a.alpha && (a = axs.utils.flattenColors(a, b)); - var c = axs.utils.calculateLuminance(a), d = axs.utils.calculateLuminance(b); - return(Math.max(c, d) + .05) / (Math.min(c, d) + .05); + var b = a.match(/^rgb\((\d+), (\d+), (\d+)\)$/); + if (b) { + a = parseInt(b[1], 10); + var c = parseInt(b[2], 10), d = parseInt(b[3], 10); + return new axs.color.Color(a, c, d, 1); + } + return (b = a.match(/^rgba\((\d+), (\d+), (\d+), (\d*(\.\d+)?)\)/)) ? (a = parseInt(b[1], 10), c = parseInt(b[2], 10), d = parseInt(b[3], 10), b = parseFloat(b[4]), new axs.color.Color(a, c, d, b)) : null; }; -axs.utils.luminanceRatio = function(a, b) { - return(Math.max(a, b) + .05) / (Math.min(a, b) + .05); +axs.color.colorChannelToString = function(a) { + a = Math.round(a); + return 15 >= a ? "0" + a.toString(16) : a.toString(16); }; -axs.utils.parentElement = function(a) { +axs.color.colorToString = function(a) { + return 1 == a.alpha ? "#" + axs.color.colorChannelToString(a.red) + axs.color.colorChannelToString(a.green) + axs.color.colorChannelToString(a.blue) : "rgba(" + [a.red, a.green, a.blue, a.alpha].join() + ")"; +}; +axs.color.luminanceFromContrastRatio = function(a, b, c) { + return c ? (a + .05) * b - .05 : (a + .05) / b - .05; +}; +axs.color.translateColor = function(a, b) { + for (var c = b > a.luma ? axs.color.WHITE_YCC : axs.color.BLACK_YCC, d = c == axs.color.WHITE_YCC ? axs.color.YCC_CUBE_FACES_WHITE : axs.color.YCC_CUBE_FACES_BLACK, e = new axs.color.YCbCr([0, a.Cb, a.Cr]), f = new axs.color.YCbCr([1, a.Cb, a.Cr]), f = {a:e, b:f}, e = null, g = 0;g < d.length && !(e = axs.color.findIntersection(f, d[g]), 0 <= e.z && 1 >= e.z);g++) { + } + if (!e) { + throw "Couldn't find intersection with YCbCr color cube for Cb=" + a.Cb + ", Cr=" + a.Cr + "."; + } + if (e.x != a.x || e.y != a.y) { + throw "Intersection has wrong Cb/Cr values."; + } + if (Math.abs(c.luma - e.luma) < Math.abs(c.luma - b)) { + return c = [b, a.Cb, a.Cr], axs.color.fromYCbCrArray(c); + } + c = (b - e.luma) / (c.luma - e.luma); + c = [b, e.Cb - e.Cb * c, e.Cr - e.Cr * c]; + return axs.color.fromYCbCrArray(c); +}; +axs.color.suggestColors = function(a, b, c) { + var d = {}, e = axs.color.calculateLuminance(a), f = axs.color.calculateLuminance(b), g = f > e, h = axs.color.toYCbCr(b), k = axs.color.toYCbCr(a), m; + for (m in c) { + var l = c[m], n = axs.color.luminanceFromContrastRatio(e, l + .02, g); + if (1 >= n && 0 <= n) { + var p = axs.color.translateColor(h, n), l = axs.color.calculateContrastRatio(p, a), n = {}; + n.fg = axs.color.colorToString(p); + n.bg = axs.color.colorToString(a); + n.contrast = l.toFixed(2); + d[m] = n; + } else { + l = axs.color.luminanceFromContrastRatio(f, l + .02, !g), 1 >= l && 0 <= l && (p = axs.color.translateColor(k, l), l = axs.color.calculateContrastRatio(b, p), n = {}, n.bg = axs.color.colorToString(p), n.fg = axs.color.colorToString(b), n.contrast = l.toFixed(2), d[m] = n); + } + } + return d; +}; +axs.color.flattenColors = function(a, b) { + var c = a.alpha; + return new axs.color.Color((1 - c) * b.red + c * a.red, (1 - c) * b.green + c * a.green, (1 - c) * b.blue + c * a.blue, a.alpha + b.alpha * (1 - a.alpha)); +}; +axs.color.multiplyMatrixVector = function(a, b) { + var c = b[0], d = b[1], e = b[2]; + return [a[0][0] * c + a[0][1] * d + a[0][2] * e, a[1][0] * c + a[1][1] * d + a[1][2] * e, a[2][0] * c + a[2][1] * d + a[2][2] * e]; +}; +axs.color.toYCbCr = function(a) { + var b = a.red / 255, c = a.green / 255; + a = a.blue / 255; + b = .03928 >= b ? b / 12.92 : Math.pow((b + .055) / 1.055, 2.4); + c = .03928 >= c ? c / 12.92 : Math.pow((c + .055) / 1.055, 2.4); + a = .03928 >= a ? a / 12.92 : Math.pow((a + .055) / 1.055, 2.4); + return new axs.color.YCbCr(axs.color.multiplyMatrixVector(axs.color.YCC_MATRIX, [b, c, a])); +}; +axs.color.fromYCbCr = function(a) { + return axs.color.fromYCbCrArray([a.luma, a.Cb, a.Cr]); +}; +axs.color.fromYCbCrArray = function(a) { + var b = axs.color.multiplyMatrixVector(axs.color.INVERTED_YCC_MATRIX, a), c = b[0]; + a = b[1]; + b = b[2]; + c = .00303949 >= c ? 12.92 * c : 1.055 * Math.pow(c, 1 / 2.4) - .055; + a = .00303949 >= a ? 12.92 * a : 1.055 * Math.pow(a, 1 / 2.4) - .055; + b = .00303949 >= b ? 12.92 * b : 1.055 * Math.pow(b, 1 / 2.4) - .055; + c = Math.min(Math.max(Math.round(255 * c), 0), 255); + a = Math.min(Math.max(Math.round(255 * a), 0), 255); + b = Math.min(Math.max(Math.round(255 * b), 0), 255); + return new axs.color.Color(c, a, b, 1); +}; +axs.color.RGBToYCbCrMatrix = function(a, b) { + return [[a, 1 - a - b, b], [-a / (2 - 2 * b), (a + b - 1) / (2 - 2 * b), (1 - b) / (2 - 2 * b)], [(1 - a) / (2 - 2 * a), (a + b - 1) / (2 - 2 * a), -b / (2 - 2 * a)]]; +}; +axs.color.invert3x3Matrix = function(a) { + var b = a[0][0], c = a[0][1], d = a[0][2], e = a[1][0], f = a[1][1], g = a[1][2], h = a[2][0], k = a[2][1]; + a = a[2][2]; + return axs.color.scalarMultiplyMatrix([[f * a - g * k, d * k - c * a, c * g - d * f], [g * h - e * a, b * a - d * h, d * e - b * g], [e * k - f * h, h * c - b * k, b * f - c * e]], 1 / (b * (f * a - g * k) - c * (a * e - g * h) + d * (e * k - f * h))); +}; +axs.color.findIntersection = function(a, b) { + var c = [a.a.x - b.p0.x, a.a.y - b.p0.y, a.a.z - b.p0.z], d = axs.color.invert3x3Matrix([[a.a.x - a.b.x, b.p1.x - b.p0.x, b.p2.x - b.p0.x], [a.a.y - a.b.y, b.p1.y - b.p0.y, b.p2.y - b.p0.y], [a.a.z - a.b.z, b.p1.z - b.p0.z, b.p2.z - b.p0.z]]), c = axs.color.multiplyMatrixVector(d, c)[0]; + return a.a.add(a.b.subtract(a.a).multiply(c)); +}; +axs.color.scalarMultiplyMatrix = function(a, b) { + for (var c = [], d = 0;3 > d;d++) { + c[d] = axs.color.scalarMultiplyVector(a[d], b); + } + return c; +}; +axs.color.scalarMultiplyVector = function(a, b) { + for (var c = [], d = 0;d < a.length;d++) { + c[d] = a[d] * b; + } + return c; +}; +axs.color.kR = .2126; +axs.color.kB = .0722; +axs.color.YCC_MATRIX = axs.color.RGBToYCbCrMatrix(axs.color.kR, axs.color.kB); +axs.color.INVERTED_YCC_MATRIX = axs.color.invert3x3Matrix(axs.color.YCC_MATRIX); +axs.color.BLACK = new axs.color.Color(0, 0, 0, 1); +axs.color.BLACK_YCC = axs.color.toYCbCr(axs.color.BLACK); +axs.color.WHITE = new axs.color.Color(255, 255, 255, 1); +axs.color.WHITE_YCC = axs.color.toYCbCr(axs.color.WHITE); +axs.color.RED = new axs.color.Color(255, 0, 0, 1); +axs.color.RED_YCC = axs.color.toYCbCr(axs.color.RED); +axs.color.GREEN = new axs.color.Color(0, 255, 0, 1); +axs.color.GREEN_YCC = axs.color.toYCbCr(axs.color.GREEN); +axs.color.BLUE = new axs.color.Color(0, 0, 255, 1); +axs.color.BLUE_YCC = axs.color.toYCbCr(axs.color.BLUE); +axs.color.CYAN = new axs.color.Color(0, 255, 255, 1); +axs.color.CYAN_YCC = axs.color.toYCbCr(axs.color.CYAN); +axs.color.MAGENTA = new axs.color.Color(255, 0, 255, 1); +axs.color.MAGENTA_YCC = axs.color.toYCbCr(axs.color.MAGENTA); +axs.color.YELLOW = new axs.color.Color(255, 255, 0, 1); +axs.color.YELLOW_YCC = axs.color.toYCbCr(axs.color.YELLOW); +axs.color.YCC_CUBE_FACES_BLACK = [{p0:axs.color.BLACK_YCC, p1:axs.color.RED_YCC, p2:axs.color.GREEN_YCC}, {p0:axs.color.BLACK_YCC, p1:axs.color.GREEN_YCC, p2:axs.color.BLUE_YCC}, {p0:axs.color.BLACK_YCC, p1:axs.color.BLUE_YCC, p2:axs.color.RED_YCC}]; +axs.color.YCC_CUBE_FACES_WHITE = [{p0:axs.color.WHITE_YCC, p1:axs.color.CYAN_YCC, p2:axs.color.MAGENTA_YCC}, {p0:axs.color.WHITE_YCC, p1:axs.color.MAGENTA_YCC, p2:axs.color.YELLOW_YCC}, {p0:axs.color.WHITE_YCC, p1:axs.color.YELLOW_YCC, p2:axs.color.CYAN_YCC}]; +axs.dom = {}; +axs.dom.parentElement = function(a) { if (!a) { return null; } - if (a.nodeType == Node.DOCUMENT_FRAGMENT_NODE) { - return a.host; - } - var b = a.parentElement; - if (b) { - return b; - } - a = a.parentNode; + a = axs.dom.composedParentNode(a); if (!a) { return null; } switch(a.nodeType) { case Node.ELEMENT_NODE: return a; - case Node.DOCUMENT_FRAGMENT_NODE: - return a.host; default: - return null; + return axs.dom.parentElement(a); } }; -axs.utils.asElement = function(a) { +axs.dom.shadowHost = function(a) { + return "host" in a ? a.host : null; +}; +axs.dom.composedParentNode = function(a) { + if (!a) { + return null; + } + if (a.nodeType === Node.DOCUMENT_FRAGMENT_NODE) { + return axs.dom.shadowHost(a); + } + var b = a.parentNode; + if (!b) { + return null; + } + if (b.nodeType === Node.DOCUMENT_FRAGMENT_NODE) { + return axs.dom.shadowHost(b); + } + if (!b.shadowRoot) { + return b; + } + a = a.getDestinationInsertionPoints(); + return 0 < a.length ? axs.dom.composedParentNode(a[a.length - 1]) : null; +}; +axs.dom.asElement = function(a) { switch(a.nodeType) { case Node.COMMENT_NODE: - return null; + break; case Node.ELEMENT_NODE: - if ("script" == a.tagName.toLowerCase()) { - return null; + if ("script" == a.localName || "template" == a.localName) { + break; } - break; + return a; + case Node.DOCUMENT_FRAGMENT_NODE: + return a.host; case Node.TEXT_NODE: - a = axs.utils.parentElement(a); - break; + return axs.dom.parentElement(a); default: - return console.warn("Unhandled node type: ", a.nodeType), null; + console.warn("Unhandled node type: ", a.nodeType); } - return a; + return null; }; +axs.dom.composedTreeSearch = function(a, b, c, d) { + if (a === b) { + return !0; + } + if (a.nodeType == Node.ELEMENT_NODE) { + var e = a + } + var f = !1; + if (e && c.preorder && !c.preorder(e)) { + return f; + } + if (e) { + var g = e.shadowRoot || e.webkitShadowRoot; + if (g) { + return f = axs.dom.composedTreeSearch(g, b, c, g), e && c.postorder && !f && c.postorder(e), f; + } + } + if (e && "content" == e.localName) { + a = e.getDistributedNodes(); + for (g = 0;g < a.length && !f;g++) { + f = axs.dom.composedTreeSearch(a[g], b, c, d); + } + e && c.postorder && !f && c.postorder.call(null, e); + return f; + } + for (a = a.firstChild;null != a && !f;) { + f = axs.dom.composedTreeSearch(a, b, c, d), a = a.nextSibling; + } + e && c.postorder && !f && c.postorder.call(null, e); + return f; +}; +axs.utils = {}; +axs.utils.FOCUSABLE_ELEMENTS_SELECTOR = "input:not([type=hidden]):not([disabled]),select:not([disabled]),textarea:not([disabled]),button:not([disabled]),a[href],iframe,[tabindex]"; +axs.utils.LABELABLE_ELEMENTS_SELECTOR = "button,input:not([type=hidden]),keygen,meter,output,progress,select,textarea"; axs.utils.elementIsTransparent = function(a) { return "0" == a.style.opacity; }; @@ -577,32 +786,45 @@ return a.right - a.left && b ? !1 : !0; }; axs.utils.elementIsOutsideScrollArea = function(a) { - for (var b = axs.utils.parentElement(a), c = a.ownerDocument.defaultView;b != c.document.body;) { + for (var b = axs.dom.parentElement(a), c = a.ownerDocument.defaultView;b != c.document.body;) { if (axs.utils.isClippedBy(a, b)) { - return!0; + return !0; } if (axs.utils.canScrollTo(a, b) && !axs.utils.elementIsOutsideScrollArea(b)) { - return!1; + return !1; } - b = axs.utils.parentElement(b); + b = axs.dom.parentElement(b); } - return!axs.utils.canScrollTo(a, c.document.body); + return !axs.utils.canScrollTo(a, c.document.body); }; axs.utils.canScrollTo = function(a, b) { - var c = a.getBoundingClientRect(), d = b.getBoundingClientRect(), e = d.top, f = d.left, g = e - b.scrollTop, e = e - b.scrollTop + b.scrollHeight, h = f - b.scrollLeft + b.scrollWidth; - if (c.right < f - b.scrollLeft || c.bottom < g || c.left > h || c.top > e) { - return!1; + var c = a.getBoundingClientRect(), d = b.getBoundingClientRect(); + if (b == b.ownerDocument.body) { + var e = d.top, f = d.left + } else { + e = d.top - b.scrollTop, f = d.left - b.scrollLeft; } - f = a.ownerDocument.defaultView; - g = f.getComputedStyle(b); - return c.left > d.right || c.top > d.bottom ? "scroll" == g.overflow || "auto" == g.overflow || b instanceof f.HTMLBodyElement : !0; + var g = e + b.scrollHeight, h = f + b.scrollWidth; + if (c.right < f || c.bottom < e || c.left > h || c.top > g) { + return !1; + } + e = a.ownerDocument.defaultView; + f = e.getComputedStyle(b); + return c.left > d.right || c.top > d.bottom ? "scroll" == f.overflow || "auto" == f.overflow || b instanceof e.HTMLBodyElement : !0; }; axs.utils.isClippedBy = function(a, b) { var c = a.getBoundingClientRect(), d = b.getBoundingClientRect(), e = d.top - b.scrollTop, f = d.left - b.scrollLeft, g = a.ownerDocument.defaultView.getComputedStyle(b); - return(c.right < d.left || c.bottom < d.top || c.left > d.right || c.top > d.bottom) && "hidden" == g.overflow ? !0 : c.right < f || c.bottom < e ? "visible" != g.overflow : !1; + return (c.right < d.left || c.bottom < d.top || c.left > d.right || c.top > d.bottom) && "hidden" == g.overflow ? !0 : c.right < f || c.bottom < e ? "visible" != g.overflow : !1; }; axs.utils.isAncestor = function(a, b) { - return null == b ? !1 : b === a ? !0 : axs.utils.isAncestor(a, b.parentNode); + if (null == b) { + return !1; + } + if (b === a) { + return !0; + } + var c = axs.dom.composedParentNode(b); + return axs.utils.isAncestor(a, c); }; axs.utils.overlappingElements = function(a) { if (axs.utils.elementHasZeroArea(a)) { @@ -648,13 +870,13 @@ } if (c = b.match(/(\d+)pt/)) { if (b = parseInt(c[1], 10), a && 14 <= b || 18 <= b) { - return!0; + return !0; } } - return!1; + return !1; }; axs.utils.getBgColor = function(a, b) { - var c = axs.utils.parseColor(a.backgroundColor); + var c = axs.color.parseColor(a.backgroundColor); if (!c) { return null; } @@ -664,158 +886,38 @@ if (null == d) { return null; } - c = axs.utils.flattenColors(c, d); + c = axs.color.flattenColors(c, d); } return c; }; axs.utils.getParentBgColor = function(a) { var b = a; a = []; - for (var c = null;b = axs.utils.parentElement(b);) { + for (var c = null;b = axs.dom.parentElement(b);) { var d = window.getComputedStyle(b, null); if (d) { - var e = axs.utils.parseColor(d.backgroundColor); + var e = axs.color.parseColor(d.backgroundColor); if (e && (1 > d.opacity && (e.alpha *= d.opacity), 0 != e.alpha && (a.push(e), 1 == e.alpha))) { c = !0; break; } } } - c || a.push(new axs.utils.Color(255, 255, 255, 1)); + c || a.push(new axs.color.Color(255, 255, 255, 1)); for (b = a.pop();a.length;) { - c = a.pop(), b = axs.utils.flattenColors(c, b); + c = a.pop(), b = axs.color.flattenColors(c, b); } return b; }; axs.utils.getFgColor = function(a, b, c) { - var d = axs.utils.parseColor(a.color); + var d = axs.color.parseColor(a.color); if (!d) { return null; } - 1 > d.alpha && (d = axs.utils.flattenColors(d, c)); - 1 > a.opacity && (b = axs.utils.getParentBgColor(b), d.alpha *= a.opacity, d = axs.utils.flattenColors(d, b)); + 1 > d.alpha && (d = axs.color.flattenColors(d, c)); + 1 > a.opacity && (b = axs.utils.getParentBgColor(b), d.alpha *= a.opacity, d = axs.color.flattenColors(d, b)); return d; }; -axs.utils.parseColor = function(a) { - var b = a.match(/^rgb\((\d+), (\d+), (\d+)\)$/); - if (b) { - a = parseInt(b[1], 10); - var c = parseInt(b[2], 10), b = parseInt(b[3], 10), d; - return new axs.utils.Color(a, c, b, 1); - } - return(b = a.match(/^rgba\((\d+), (\d+), (\d+), (\d+(\.\d+)?)\)/)) ? (d = parseInt(b[4], 10), a = parseInt(b[1], 10), c = parseInt(b[2], 10), b = parseInt(b[3], 10), new axs.utils.Color(a, c, b, d)) : null; -}; -axs.utils.colorChannelToString = function(a) { - a = Math.round(a); - return 15 >= a ? "0" + a.toString(16) : a.toString(16); -}; -axs.utils.colorToString = function(a) { - return 1 == a.alpha ? "#" + axs.utils.colorChannelToString(a.red) + axs.utils.colorChannelToString(a.green) + axs.utils.colorChannelToString(a.blue) : "rgba(" + [a.red, a.green, a.blue, a.alpha].join() + ")"; -}; -axs.utils.luminanceFromContrastRatio = function(a, b, c) { - return c ? (a + .05) * b - .05 : (a + .05) / b - .05; -}; -axs.utils.translateColor = function(a, b) { - var c = a[0], c = (b - c) / ((c > b ? 0 : 1) - c); - return axs.utils.fromYCC([b, a[1] - a[1] * c, a[2] - a[2] * c]); -}; -axs.utils.suggestColors = function(a, b, c, d) { - if (!axs.utils.isLowContrast(c, d, !0)) { - return null; - } - var e = {}, f = axs.utils.calculateLuminance(a), g = axs.utils.calculateLuminance(b), h = axs.utils.isLargeFont(d) ? 3 : 4.5, k = axs.utils.isLargeFont(d) ? 4.5 : 7, m = g > f, l = axs.utils.luminanceFromContrastRatio(f, h + .02, m), n = axs.utils.luminanceFromContrastRatio(f, k + .02, m), q = axs.utils.toYCC(b); - if (axs.utils.isLowContrast(c, d, !1) && 1 >= l && 0 <= l) { - var p = axs.utils.translateColor(q, l), l = axs.utils.calculateContrastRatio(p, a); - axs.utils.calculateLuminance(p); - f = {}; - f.fg = axs.utils.colorToString(p); - f.bg = axs.utils.colorToString(a); - f.contrast = l.toFixed(2); - e.AA = f; - } - axs.utils.isLowContrast(c, d, !0) && 1 >= n && 0 <= n && (n = axs.utils.translateColor(q, n), l = axs.utils.calculateContrastRatio(n, a), f = {}, f.fg = axs.utils.colorToString(n), f.bg = axs.utils.colorToString(a), f.contrast = l.toFixed(2), e.AAA = f); - h = axs.utils.luminanceFromContrastRatio(g, h + .02, !m); - g = axs.utils.luminanceFromContrastRatio(g, k + .02, !m); - a = axs.utils.toYCC(a); - !("AA" in e) && axs.utils.isLowContrast(c, d, !1) && 1 >= h && 0 <= h && (k = axs.utils.translateColor(a, h), l = axs.utils.calculateContrastRatio(b, k), f = {}, f.bg = axs.utils.colorToString(k), f.fg = axs.utils.colorToString(b), f.contrast = l.toFixed(2), e.AA = f); - !("AAA" in e) && axs.utils.isLowContrast(c, d, !0) && 1 >= g && 0 <= g && (c = axs.utils.translateColor(a, g), l = axs.utils.calculateContrastRatio(b, c), f = {}, f.bg = axs.utils.colorToString(c), f.fg = axs.utils.colorToString(b), f.contrast = l.toFixed(2), e.AAA = f); - return e; -}; -axs.utils.flattenColors = function(a, b) { - var c = a.alpha; - return new axs.utils.Color((1 - c) * b.red + c * a.red, (1 - c) * b.green + c * a.green, (1 - c) * b.blue + c * a.blue, a.alpha + b.alpha * (1 - a.alpha)); -}; -axs.utils.calculateLuminance = function(a) { - return axs.utils.toYCC(a)[0]; -}; -axs.utils.RGBToYCCMatrix = function(a, b) { - return[[a, 1 - a - b, b], [-a / (2 - 2 * b), (a + b - 1) / (2 - 2 * b), (1 - b) / (2 - 2 * b)], [(1 - a) / (2 - 2 * a), (a + b - 1) / (2 - 2 * a), -b / (2 - 2 * a)]]; -}; -axs.utils.invert3x3Matrix = function(a) { - var b = a[0][0], c = a[0][1], d = a[0][2], e = a[1][0], f = a[1][1], g = a[1][2], h = a[2][0], k = a[2][1]; - a = a[2][2]; - return axs.utils.scalarMultiplyMatrix([[f * a - g * k, d * k - c * a, c * g - d * f], [g * h - e * a, b * a - d * h, d * e - b * g], [e * k - f * h, h * c - b * k, b * f - c * e]], 1 / (b * (f * a - g * k) - c * (a * e - g * h) + d * (e * k - f * h))); -}; -axs.utils.scalarMultiplyMatrix = function(a, b) { - for (var c = [[], [], []], d = 0;3 > d;d++) { - for (var e = 0;3 > e;e++) { - c[d][e] = a[d][e] * b; - } - } - return c; -}; -axs.utils.kR = .2126; -axs.utils.kB = .0722; -axs.utils.YCC_MATRIX = axs.utils.RGBToYCCMatrix(axs.utils.kR, axs.utils.kB); -axs.utils.INVERTED_YCC_MATRIX = axs.utils.invert3x3Matrix(axs.utils.YCC_MATRIX); -axs.utils.convertColor = function(a, b) { - var c = b[0], d = b[1], e = b[2]; - return[a[0][0] * c + a[0][1] * d + a[0][2] * e, a[1][0] * c + a[1][1] * d + a[1][2] * e, a[2][0] * c + a[2][1] * d + a[2][2] * e]; -}; -axs.utils.multiplyMatrices = function(a, b) { - for (var c = [[], [], []], d = 0;3 > d;d++) { - for (var e = 0;3 > e;e++) { - c[d][e] = a[d][0] * b[0][e] + a[d][1] * b[1][e] + a[d][2] * b[2][e]; - } - } - return c; -}; -axs.utils.toYCC = function(a) { - var b = a.red / 255, c = a.green / 255; - a = a.blue / 255; - b = .03928 >= b ? b / 12.92 : Math.pow((b + .055) / 1.055, 2.4); - c = .03928 >= c ? c / 12.92 : Math.pow((c + .055) / 1.055, 2.4); - a = .03928 >= a ? a / 12.92 : Math.pow((a + .055) / 1.055, 2.4); - return axs.utils.convertColor(axs.utils.YCC_MATRIX, [b, c, a]); -}; -axs.utils.fromYCC = function(a) { - var b = axs.utils.convertColor(axs.utils.INVERTED_YCC_MATRIX, a), c = b[0]; - a = b[1]; - b = b[2]; - c = .00303949 >= c ? 12.92 * c : 1.055 * Math.pow(c, 1 / 2.4) - .055; - a = .00303949 >= a ? 12.92 * a : 1.055 * Math.pow(a, 1 / 2.4) - .055; - b = .00303949 >= b ? 12.92 * b : 1.055 * Math.pow(b, 1 / 2.4) - .055; - c = Math.min(Math.max(Math.round(255 * c), 0), 255); - a = Math.min(Math.max(Math.round(255 * a), 0), 255); - b = Math.min(Math.max(Math.round(255 * b), 0), 255); - return new axs.utils.Color(c, a, b, 1); -}; -axs.utils.scalarMultiplyMatrix = function(a, b) { - for (var c = [[], [], []], d = 0;3 > d;d++) { - for (var e = 0;3 > e;e++) { - c[d][e] = a[d][e] * b; - } - } - return c; -}; -axs.utils.multiplyMatrices = function(a, b) { - for (var c = [[], [], []], d = 0;3 > d;d++) { - for (var e = 0;3 > e;e++) { - c[d][e] = a[d][0] * b[0][e] + a[d][1] * b[1][e] + a[d][2] * b[2][e]; - } - } - return c; -}; axs.utils.getContrastRatioForElement = function(a) { var b = window.getComputedStyle(a, null); return axs.utils.getContrastRatioForElementWithComputedStyle(b, a); @@ -829,16 +931,16 @@ return null; } var d = axs.utils.getFgColor(a, b, c); - return d ? axs.utils.calculateContrastRatio(d, c) : null; + return d ? axs.color.calculateContrastRatio(d, c) : null; }; axs.utils.isNativeTextElement = function(a) { var b = a.tagName.toLowerCase(); a = a.type ? a.type.toLowerCase() : ""; if ("textarea" == b) { - return!0; + return !0; } if ("input" != b) { - return!1; + return !1; } switch(a) { case "email": @@ -856,9 +958,9 @@ case "url": ; case "": - return!0; + return !0; default: - return!1; + return !1; } }; axs.utils.isLowContrast = function(a, b, c) { @@ -867,20 +969,37 @@ }; axs.utils.hasLabel = function(a) { var b = a.tagName.toLowerCase(), c = a.type ? a.type.toLowerCase() : ""; - if (a.hasAttribute("aria-label") || a.hasAttribute("title") || "img" == b && a.hasAttribute("alt") || "input" == b && "image" == c && a.hasAttribute("alt") || "input" == b && ("submit" == c || "reset" == c) || a.hasAttribute("aria-labelledby") || axs.utils.isNativeTextElement(a) && a.hasAttribute("placeholder") || a.hasAttribute("id") && 0 < document.querySelectorAll('label[for="' + a.id + '"]').length) { - return!0; + if (a.hasAttribute("aria-label") || a.hasAttribute("title") || "img" == b && a.hasAttribute("alt") || "input" == b && "image" == c && a.hasAttribute("alt") || "input" == b && ("submit" == c || "reset" == c) || a.hasAttribute("aria-labelledby") || a.hasAttribute("id") && 0 < document.querySelectorAll('label[for="' + a.id + '"]').length) { + return !0; } - for (b = axs.utils.parentElement(a);b;) { + for (b = axs.dom.parentElement(a);b;) { if ("label" == b.tagName.toLowerCase() && b.control == a) { - return!0; + return !0; } - b = axs.utils.parentElement(b); + b = axs.dom.parentElement(b); } - return!1; + return !1; +}; +axs.utils.isNativelyDisableable = function(a) { + return a.tagName.toUpperCase() in axs.constants.NATIVELY_DISABLEABLE; +}; +axs.utils.isElementDisabled = function(a) { + if (axs.browserUtils.matchSelector(a, "[aria-disabled=true], [aria-disabled=true] *")) { + return !0; + } + if (!axs.utils.isNativelyDisableable(a) || axs.browserUtils.matchSelector(a, "fieldset>legend:first-of-type *")) { + return !1; + } + for (;null !== a;a = axs.dom.parentElement(a)) { + if (axs.utils.isNativelyDisableable(a) && a.hasAttribute("disabled")) { + return !0; + } + } + return !1; }; axs.utils.isElementHidden = function(a) { if (!(a instanceof a.ownerDocument.defaultView.HTMLElement)) { - return!1; + return !1; } if (a.hasAttribute("chromevoxignoreariahidden")) { var b = !0 @@ -889,22 +1008,27 @@ return "none" == c.display || "hidden" == c.visibility ? !0 : a.hasAttribute("aria-hidden") && "true" == a.getAttribute("aria-hidden").toLowerCase() ? !b : !1; }; axs.utils.isElementOrAncestorHidden = function(a) { - return axs.utils.isElementHidden(a) ? !0 : axs.utils.parentElement(a) ? axs.utils.isElementOrAncestorHidden(axs.utils.parentElement(a)) : !1; + return axs.utils.isElementHidden(a) ? !0 : axs.dom.parentElement(a) ? axs.utils.isElementOrAncestorHidden(axs.dom.parentElement(a)) : !1; }; axs.utils.isInlineElement = function(a) { a = a.tagName.toUpperCase(); return axs.constants.InlineElements[a]; }; -axs.utils.getRoles = function(a) { - if (!a.hasAttribute("role")) { - return!1; +axs.utils.getRoles = function(a, b) { + if (!a || a.nodeType !== Node.ELEMENT_NODE || !a.hasAttribute("role") && !b) { + return null; } - a = a.getAttribute("role").split(" "); - for (var b = [], c = !0, d = 0;d < a.length;d++) { - var e = a[d]; - axs.constants.ARIA_ROLES[e] ? b.push({name:e, details:axs.constants.ARIA_ROLES[e], valid:!0}) : (b.push({name:e, valid:!1}), c = !1); + var c = a.getAttribute("role"); + !c && b && (c = axs.properties.getImplicitRole(a)); + if (!c) { + return null; } - return{roles:b, valid:c}; + for (var c = c.split(" "), d = {roles:[], valid:!1}, e = 0;e < c.length;e++) { + var f = c[e], g = axs.constants.ARIA_ROLES[f], f = {name:f}; + g && !g.abstract ? (f.details = g, d.applied || (d.applied = f), f.valid = d.valid = !0) : f.valid = !1; + d.roles.push(f); + } + return d; }; axs.utils.getAriaPropertyValue = function(a, b, c) { var d = a.replace(/^aria-/, ""), e = axs.constants.ARIA_PROPERTIES[d], d = {name:a, rawValue:b}; @@ -926,16 +1050,22 @@ } return d; case "integer": - ; - case "decimal": c = axs.utils.isValidNumber(b); if (!c.valid) { return d.valid = !1, d.reason = c.reason, d; } - Math.floor(c.value) != c.value ? (d.valid = !1, d.reason = "" + b + " is not a whole integer") : (d.valid = !0, d.value = c.value); + Math.floor(c.value) !== c.value ? (d.valid = !1, d.reason = "" + b + " is not a whole integer") : (d.valid = !0, d.value = c.value); return d; + case "decimal": + ; case "number": - c = axs.utils.isValidNumber(b), c.valid && (d.valid = !0, d.value = c.value); + c = axs.utils.isValidNumber(b); + d.valid = c.valid; + if (!c.valid) { + return d.reason = c.reason, d; + } + d.value = c.value; + return d; case "string": return d.valid = !0, d.value = b, d; case "token": @@ -975,12 +1105,15 @@ return 0 == a.length ? {valid:!0, idref:a} : b.ownerDocument.getElementById(a) ? {valid:!0, idref:a} : {valid:!1, idref:a, reason:'No element with ID "' + a + '"'}; }; axs.utils.isValidNumber = function(a) { - try { - var b = JSON.parse(a); - } catch (c) { - return{valid:!1, value:a, reason:'"' + a + '" is not a number'}; + var b = {valid:!1, value:a, reason:'"' + a + '" is not a number'}; + if (!a) { + return b; } - return "number" != typeof b ? {valid:!1, value:a, reason:'"' + a + '" is not a number'} : {valid:!0, value:b}; + if (/^0x/i.test(a)) { + return b.reason = '"' + a + '" is not a decimal number', b; + } + a *= 1; + return isFinite(a) ? {valid:!0, value:a} : b; }; axs.utils.isElementImplicitlyFocusable = function(a) { var b = a.ownerDocument.defaultView; @@ -1027,7 +1160,9 @@ } else { d = 1; } - return 1 == d ? axs.utils.getQuerySelectorText(a.parentNode) + " > " + b : axs.utils.getQuerySelectorText(a.parentNode) + " > " + b + ":nth-of-type(" + d + ")"; + if (1 == d) { + return axs.utils.getQuerySelectorText(a.parentNode) + " > " + b; + } } if (a.parentNode) { b = a.parentNode.children; @@ -1046,6 +1181,103 @@ } return ""; }; +axs.utils.getAriaIdReferrers = function(a, b) { + var c = function(a) { + var b = axs.constants.ARIA_PROPERTIES[a]; + if (b) { + if ("idref" === b.valueType) { + return "[aria-" + a + "='" + d + "']"; + } + if ("idref_list" === b.valueType) { + return "[aria-" + a + "~='" + d + "']"; + } + } + return ""; + }; + if (!a) { + return null; + } + var d = a.id; + if (!d) { + return null; + } + d = d.replace(/'/g, "\\'"); + if (b) { + var e = b.replace(/^aria-/, ""), f = c(e); + if (f) { + return a.ownerDocument.querySelectorAll(f); + } + } else { + var g = []; + for (e in axs.constants.ARIA_PROPERTIES) { + (f = c(e)) && g.push(f); + } + return a.ownerDocument.querySelectorAll(g.join(",")); + } + return null; +}; +axs.utils.getHtmlIdReferrers = function(a) { + if (!a) { + return null; + } + var b = a.id; + if (!b) { + return null; + } + var b = b.replace(/'/g, "\\'"), c = "[contextmenu='{id}'] [itemref~='{id}'] button[form='{id}'] button[menu='{id}'] fieldset[form='{id}'] input[form='{id}'] input[list='{id}'] keygen[form='{id}'] label[for='{id}'] label[form='{id}'] menuitem[command='{id}'] object[form='{id}'] output[for~='{id}'] output[form='{id}'] select[form='{id}'] td[headers~='{id}'] textarea[form='{id}'] tr[headers~='{id}']".split(" ").map(function(a) { + return a.replace("{id}", b); + }); + return a.ownerDocument.querySelectorAll(c.join(",")); +}; +axs.utils.getIdReferrers = function(a) { + var b = [], c = axs.utils.getHtmlIdReferrers(a); + c && (b = b.concat(Array.prototype.slice.call(c))); + (c = axs.utils.getAriaIdReferrers(a)) && (b = b.concat(Array.prototype.slice.call(c))); + return b; +}; +axs.utils.getIdReferents = function(a, b) { + var c = [], d = a.replace(/^aria-/, ""), d = axs.constants.ARIA_PROPERTIES[d]; + if (!d || !b.hasAttribute(a)) { + return c; + } + d = d.valueType; + if ("idref_list" === d || "idref" === d) { + for (var d = b.ownerDocument, e = b.getAttribute(a), e = e.split(/\s+/), f = 0, g = e.length;f < g;f++) { + var h = d.getElementById(e[f]); + h && (c[c.length] = h); + } + } + return c; +}; +axs.utils.getAriaPropertiesByValueType = function(a) { + var b = {}, c; + for (c in axs.constants.ARIA_PROPERTIES) { + var d = axs.constants.ARIA_PROPERTIES[c]; + d && 0 <= a.indexOf(d.valueType) && (b[c] = d); + } + return b; +}; +axs.utils.getSelectorForAriaProperties = function(a) { + a = Object.keys(a).map(function(a) { + return "[aria-" + a + "]"; + }); + a.sort(); + return a.join(","); +}; +axs.utils.findDescendantsWithRole = function(a, b) { + if (!a || !b) { + return []; + } + var c = axs.properties.getSelectorForRole(b); + if (c && (c = a.querySelectorAll(c))) { + c = Array.prototype.map.call(c, function(a) { + return a; + }); + } else { + return []; + } + return c; +}; axs.properties = {}; axs.properties.TEXT_CONTENT_XPATH = './/text()[normalize-space(.)!=""]/parent::*[name()!="script"]'; axs.properties.getFocusProperties = function(a) { @@ -1078,7 +1310,7 @@ var b = !0 } var c = window.getComputedStyle(a, null); - return "none" == c.display ? {property:"display: none", on:a} : "hidden" == c.visibility ? {property:"visibility: hidden", on:a} : a.hasAttribute("aria-hidden") && "true" == a.getAttribute("aria-hidden").toLowerCase() && !b ? {property:"aria-hidden", on:a} : axs.properties.getHiddenReason(axs.utils.parentElement(a)); + return "none" == c.display ? {property:"display: none", on:a} : "hidden" == c.visibility ? {property:"visibility: hidden", on:a} : a.hasAttribute("aria-hidden") && "true" == a.getAttribute("aria-hidden").toLowerCase() && !b ? {property:"aria-hidden", on:a} : axs.properties.getHiddenReason(axs.dom.parentElement(a)); }; axs.properties.getColorProperties = function(a) { var b = {}; @@ -1086,13 +1318,25 @@ return 0 == Object.keys(b).length ? null : b; }; axs.properties.hasDirectTextDescendant = function(a) { - for (var b = (a.nodeType == Node.DOCUMENT_NODE ? a : a.ownerDocument).evaluate(axs.properties.TEXT_CONTENT_XPATH, a, null, XPathResult.ANY_TYPE, null), c = !1, d = b.iterateNext();null != d;d = b.iterateNext()) { - if (d === a) { - c = !0; - break; + function b() { + for (var b = c.evaluate(axs.properties.TEXT_CONTENT_XPATH, a, null, XPathResult.ANY_TYPE, null), e = b.iterateNext();null != e;e = b.iterateNext()) { + if (e === a) { + return !0; + } } + return !1; } - return c; + var c; + c = a.nodeType == Node.DOCUMENT_NODE ? a : a.ownerDocument; + return c.evaluate ? b() : function() { + for (var b = c.createTreeWalker(a, NodeFilter.SHOW_TEXT, null, !1);b.nextNode();) { + var e = b.currentNode, f = e.parentNode.tagName.toLowerCase(); + if (e.nodeValue.trim() && "script" !== f && a !== e) { + return !0; + } + } + return !1; + }(); }; axs.properties.getContrastRatioProperties = function(a) { if (!axs.properties.hasDirectTextDescendant(a)) { @@ -1102,22 +1346,28 @@ if (!d) { return null; } - b.backgroundColor = axs.utils.colorToString(d); + b.backgroundColor = axs.color.colorToString(d); var e = axs.utils.getFgColor(c, a, d); - b.foregroundColor = axs.utils.colorToString(e); + b.foregroundColor = axs.color.colorToString(e); a = axs.utils.getContrastRatioForElementWithComputedStyle(c, a); if (!a) { return null; } b.value = a.toFixed(2); axs.utils.isLowContrast(a, c) && (b.alert = !0); - (c = axs.utils.suggestColors(d, e, a, c)) && Object.keys(c).length && (b.suggestedColors = c); + var f = axs.utils.isLargeFont(c) ? 3 : 4.5, c = axs.utils.isLargeFont(c) ? 4.5 : 7, g = {}; + f > a && (g.AA = f); + c > a && (g.AAA = c); + if (!Object.keys(g).length) { + return b; + } + (d = axs.color.suggestColors(d, e, g)) && Object.keys(d).length && (b.suggestedColors = d); return b; }; axs.properties.findTextAlternatives = function(a, b, c, d) { var e = c || !1; - c = axs.utils.asElement(a); - if (!c || !e && !d && axs.utils.isElementOrAncestorHidden(c)) { + c = axs.dom.asElement(a); + if (!c || !d && axs.utils.isElementOrAncestorHidden(c)) { return null; } if (a.nodeType == Node.TEXT_NODE) { @@ -1125,17 +1375,23 @@ } a = null; e || (a = axs.properties.getTextFromAriaLabelledby(c, b)); - c.hasAttribute("aria-label") && (d = {type:"text"}, d.text = c.getAttribute("aria-label"), d.lastWord = axs.properties.getLastWord(d.text), a ? d.unused = !0 : e && axs.utils.elementIsHtmlControl(c) || (a = d.text), b.ariaLabel = d); + if (c.hasAttribute("aria-label")) { + var f = {type:"text"}; + f.text = c.getAttribute("aria-label"); + f.lastWord = axs.properties.getLastWord(f.text); + a ? f.unused = !0 : e && axs.utils.elementIsHtmlControl(c) || (a = f.text); + b.ariaLabel = f; + } c.hasAttribute("role") && "presentation" == c.getAttribute("role") || (a = axs.properties.getTextFromHostLanguageAttributes(c, b, a, e)); if (e && axs.utils.elementIsHtmlControl(c)) { - d = c.ownerDocument.defaultView; - if (c instanceof d.HTMLInputElement) { - var f = c; - "text" == f.type && f.value && 0 < f.value.length && (b.controlValue = {text:f.value}); - "range" == f.type && (b.controlValue = {text:f.value}); + f = c.ownerDocument.defaultView; + if (c instanceof f.HTMLInputElement) { + var g = c; + "text" == g.type && g.value && 0 < g.value.length && (b.controlValue = {text:g.value}); + "range" == g.type && (b.controlValue = {text:g.value}); } - c instanceof d.HTMLSelectElement && (b.controlValue = {text:c.value}); - b.controlValue && (d = b.controlValue, a ? d.unused = !0 : a = d.text); + c instanceof f.HTMLSelectElement && (b.controlValue = {text:c.value}); + b.controlValue && (f = b.controlValue, a ? f.unused = !0 : a = f.text); } if (e && axs.utils.elementIsAriaWidget(c)) { e = c.getAttribute("role"); @@ -1144,43 +1400,39 @@ c.hasAttribute("aria-valuetext") ? b.controlValue = {text:c.getAttribute("aria-valuetext")} : c.hasAttribute("aria-valuenow") && (b.controlValue = {value:c.getAttribute("aria-valuenow"), text:"" + c.getAttribute("aria-valuenow")}); } if ("menu" == e) { - var g = c.querySelectorAll("[role=menuitemcheckbox], [role=menuitemradio]"); - d = []; - for (f = 0;f < g.length;f++) { - "true" == g[f].getAttribute("aria-checked") && d.push(g[f]); + for (var h = c.querySelectorAll("[role=menuitemcheckbox], [role=menuitemradio]"), f = [], g = 0;g < h.length;g++) { + "true" == h[g].getAttribute("aria-checked") && f.push(h[g]); } - if (0 < d.length) { - g = ""; - for (f = 0;f < d.length;f++) { - g += axs.properties.findTextAlternatives(d[f], {}, !0), f < d.length - 1 && (g += ", "); + if (0 < f.length) { + h = ""; + for (g = 0;g < f.length;g++) { + h += axs.properties.findTextAlternatives(f[g], {}, !0), g < f.length - 1 && (h += ", "); } - b.controlValue = {text:g}; + b.controlValue = {text:h}; } } if ("combobox" == e || "select" == e) { b.controlValue = {text:"TODO"}; } - b.controlValue && (d = b.controlValue, a ? d.unused = !0 : a = d.text); + b.controlValue && (f = b.controlValue, a ? f.unused = !0 : a = f.text); } - d = !0; - c.hasAttribute("role") && (e = c.getAttribute("role"), (e = axs.constants.ARIA_ROLES[e]) && (!e.namefrom || 0 > e.namefrom.indexOf("contents")) && (d = !1)); - (e = axs.properties.getTextFromDescendantContent(c)) && d && (d = {type:"text"}, d.text = e, d.lastWord = axs.properties.getLastWord(d.text), a ? d.unused = !0 : a = e, b.content = d); - c.hasAttribute("title") && (e = {type:"string", valid:!0}, e.text = c.getAttribute("title"), e.lastWord = axs.properties.getLastWord(e.lastWord), a ? e.unused = !0 : a = e.text, b.title = e); + f = !0; + c.hasAttribute("role") && (e = c.getAttribute("role"), (e = axs.constants.ARIA_ROLES[e]) && (!e.namefrom || 0 > e.namefrom.indexOf("contents")) && (f = !1)); + (d = axs.properties.getTextFromDescendantContent(c, d)) && f && (e = {type:"text"}, e.text = d, e.lastWord = axs.properties.getLastWord(e.text), a ? e.unused = !0 : a = d, b.content = e); + c.hasAttribute("title") && (d = {type:"string", valid:!0}, d.text = c.getAttribute("title"), d.lastWord = axs.properties.getLastWord(d.lastWord), a ? d.unused = !0 : a = d.text, b.title = d); return 0 == Object.keys(b).length && null == a ? null : a; }; -axs.properties.getTextFromDescendantContent = function(a) { - var b = a.childNodes; - a = []; - for (var c = 0;c < b.length;c++) { - var d = axs.properties.findTextAlternatives(b[c], {}, !0); - d && a.push(d.trim()); +axs.properties.getTextFromDescendantContent = function(a, b) { + for (var c = a.childNodes, d = [], e = 0;e < c.length;e++) { + var f = axs.properties.findTextAlternatives(c[e], {}, !0, b); + f && d.push(f.trim()); } - if (a.length) { - b = ""; - for (c = 0;c < a.length;c++) { - b = [b, a[c]].join(" ").trim(); + if (d.length) { + c = ""; + for (e = 0;e < d.length;e++) { + c = [c, d[e]].join(" ").trim(); } - return b; + return c; } return null; }; @@ -1193,22 +1445,18 @@ var k = {type:"element"}, m = d[h]; k.value = m; var l = document.getElementById(m); - l ? (k.valid = !0, k.text = axs.properties.findTextAlternatives(l, {}, !0), k.lastWord = axs.properties.getLastWord(k.text), f.push(l.textContent.trim()), k.element = l) : (k.valid = !1, e.valid = !1, k.errorMessage = {messageKey:"noElementWithId", args:[m]}); + l ? (k.valid = !0, k.text = axs.properties.findTextAlternatives(l, {}, !0, !0), k.lastWord = axs.properties.getLastWord(k.text), f.push(k.text), k.element = l) : (k.valid = !1, e.valid = !1, k.errorMessage = {messageKey:"noElementWithId", args:[m]}); g.push(k); } 0 < g.length && (g[g.length - 1].last = !0, e.values = g, e.text = f.join(" "), e.lastWord = axs.properties.getLastWord(e.text), c = e.text, b.ariaLabelledby = e); return c; }; axs.properties.getTextFromHostLanguageAttributes = function(a, b, c, d) { - if (axs.browserUtils.matchSelector(a, "img")) { - if (a.hasAttribute("alt")) { - var e = {type:"string", valid:!0}; - e.text = a.getAttribute("alt"); - c ? e.unused = !0 : c = e.text; - b.alt = e; - } else { - e = {valid:!1, errorMessage:"No alt value provided"}, b.alt = e, e = a.src, "string" == typeof e && (c = e.split("/").pop(), b.filename = {text:c}); - } + if (axs.browserUtils.matchSelector(a, "img") && a.hasAttribute("alt")) { + var e = {type:"string", valid:!0}; + e.text = a.getAttribute("alt"); + c ? e.unused = !0 : c = e.text; + b.alt = e; } if (axs.browserUtils.matchSelector(a, 'input:not([type="hidden"]):not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), video:not([disabled])') && !d) { if (a.hasAttribute("id")) { @@ -1221,7 +1469,7 @@ } 0 < f.length && (f[f.length - 1].last = !0, e.values = f, e.text = g.join(" "), e.lastWord = axs.properties.getLastWord(e.text), c ? e.unused = !0 : c = e.text, b.labelFor = e); } - d = axs.utils.parentElement(a); + d = axs.dom.parentElement(a); for (e = {};d;) { if ("label" == d.tagName.toLowerCase() && (f = d, f.control == a)) { e.type = "element"; @@ -1230,9 +1478,10 @@ e.element = f; break; } - d = axs.utils.parentElement(d); + d = axs.dom.parentElement(d); } e.text && (c ? e.unused = !0 : c = e.text, b.labelWrapped = e); + axs.browserUtils.matchSelector(a, 'input[type="image"]') && a.hasAttribute("alt") && (e = {type:"string", valid:!0}, e.text = a.getAttribute("alt"), c ? e.unused = !0 : c = e.text, b.alt = e); Object.keys(b).length || (b.noLabel = !0); } return c; @@ -1245,18 +1494,13 @@ return a.substring(b > c ? b : c); }; axs.properties.getTextProperties = function(a) { - var b = {}; - a = axs.properties.findTextAlternatives(a, b, !1, !0); - if (0 == Object.keys(b).length) { - if (!a) { - return null; - } - b.hasProperties = !1; - } else { - b.hasProperties = !0; + var b = {}, c = axs.properties.findTextAlternatives(a, b, !1, !0); + if (0 == Object.keys(b).length && ((a = axs.dom.asElement(a)) && axs.browserUtils.matchSelector(a, "img") && (b.alt = {valid:!1, errorMessage:"No alt value provided"}, a = a.src, "string" == typeof a && (c = a.split("/").pop(), b.filename = {text:c})), !c)) { + return null; } - b.computedText = a; - b.lastWord = axs.properties.getLastWord(a); + b.hasProperties = Boolean(Object.keys(b).length); + b.computedText = c; + b.lastWord = axs.properties.getLastWord(c); return b; }; axs.properties.getAriaProperties = function(a) { @@ -1289,11 +1533,11 @@ return 0 < Object.keys(b).length ? b : null; }; axs.properties.getGlobalAriaProperties = function(a) { - for (var b = {}, c = 0;c < axs.constants.GLOBAL_PROPERTIES.length;c++) { - var d = axs.constants.GLOBAL_PROPERTIES[c]; - if (a.hasAttribute(d)) { - var e = a.getAttribute(d); - b[d] = axs.utils.getAriaPropertyValue(d, e, a); + var b = {}, c; + for (c in axs.constants.GLOBAL_PROPERTIES) { + if (a.hasAttribute(c)) { + var d = a.getAttribute(c); + b[c] = axs.utils.getAriaPropertyValue(c, d, a); } } return b; @@ -1328,9 +1572,9 @@ return d; }; axs.properties.getAllProperties = function(a) { - var b = axs.utils.asElement(a); + var b = axs.dom.asElement(a); if (!b) { - return{}; + return {}; } var c = {}; c.ariaProperties = axs.properties.getAriaProperties(b); @@ -1340,6 +1584,80 @@ c.videoProperties = axs.properties.getVideoProperties(b); return c; }; +(function() { + function a(a) { + if (!a) { + return null; + } + var c = a.tagName; + if (!c) { + return null; + } + c = c.toUpperCase(); + c = axs.constants.TAG_TO_IMPLICIT_SEMANTIC_INFO[c]; + if (!c || !c.length) { + return null; + } + for (var d = null, e = 0, f = c.length;e < f;e++) { + var g = c[e]; + if (g.selector) { + if (axs.browserUtils.matchSelector(a, g.selector)) { + return g; + } + } else { + d = g; + } + } + return d; + } + axs.properties.getImplicitRole = function(b) { + return (b = a(b)) ? b.role : ""; + }; + axs.properties.canTakeAriaAttributes = function(b) { + return (b = a(b)) ? !b.reserved : !0; + }; +})(); +axs.properties.getNativelySupportedAttributes = function(a) { + var b = []; + if (!a) { + return b; + } + a = a.cloneNode(!1); + for (var c = Object.keys(axs.constants.ARIA_TO_HTML_ATTRIBUTE), d = 0;d < c.length;d++) { + var e = c[d]; + axs.constants.ARIA_TO_HTML_ATTRIBUTE[e] in a && (b[b.length] = e); + } + return b; +}; +(function() { + var a = {}; + axs.properties.getSelectorForRole = function(b) { + if (!b) { + return ""; + } + if (a[b] && a.hasOwnProperty(b)) { + return a[b]; + } + var c = ['[role="' + b + '"]']; + Object.keys(axs.constants.TAG_TO_IMPLICIT_SEMANTIC_INFO).forEach(function(a) { + var e = axs.constants.TAG_TO_IMPLICIT_SEMANTIC_INFO[a]; + if (e && e.length) { + for (var f = 0;f < e.length;f++) { + var g = e[f]; + if (g.role === b) { + if (g.selector) { + c[c.length] = g.selector; + } else { + c[c.length] = a; + break; + } + } + } + } + }); + return a[b] = c.join(","); + }; +})(); axs.AuditRule = function(a) { for (var b = !0, c = [], d = 0;d < axs.AuditRule.requiredFields.length;d++) { var e = axs.AuditRule.requiredFields[d]; @@ -1363,69 +1681,59 @@ a.push(b); }; axs.AuditRule.collectMatchingElements = function(a, b, c, d) { - if (a.nodeType == Node.ELEMENT_NODE) { - var e = a - } - e && b.call(null, e) && c.push(e); - if (e) { - var f = e.shadowRoot || e.webkitShadowRoot; - if (f) { - axs.AuditRule.collectMatchingElements(f, b, c, f); - return; - } - } - if (e && "content" == e.localName) { - for (e = e.getDistributedNodes(), a = 0;a < e.length;a++) { - axs.AuditRule.collectMatchingElements(e[a], b, c, d); - } - } else { - if (e && "shadow" == e.localName) { - a = e, d ? (d = d.olderShadowRoot || a.olderShadowRoot) && axs.AuditRule.collectMatchingElements(d, b, c, d) : console.warn("ShadowRoot not provided for", e); - } else { - for (e = a.firstChild;null != e;) { - axs.AuditRule.collectMatchingElements(e, b, c, d), e = e.nextSibling; + axs.dom.composedTreeSearch(a, null, {preorder:function(a) { + if (d) { + for (var f = 0;f < d.length;f++) { + if (axs.browserUtils.matchSelector(a, d[f])) { + return !1; + } } } - } + b(a) && c.push(a); + return !0; + }}); }; axs.AuditRule.prototype.run = function(a) { a = a || {}; - var b = "ignoreSelectors" in a ? a.ignoreSelectors : [], c = "maxResults" in a ? a.maxResults : null, d = []; - axs.AuditRule.collectMatchingElements("scope" in a ? a.scope : document, this.relevantElementMatcher_, d); - var e = []; - if (!d.length) { - return{result:axs.constants.AuditResult.NA}; + var b = "maxResults" in a ? a.maxResults : null, c = []; + axs.AuditRule.collectMatchingElements("scope" in a ? a.scope : document, this.relevantElementMatcher_, c, a.ignoreSelectors); + var d = []; + if (!c.length) { + return {result:axs.constants.AuditResult.NA}; } - for (a = 0;a < d.length && !(null != c && e.length >= c);a++) { - var f = d[a], g; - a: { - g = f; - for (var h = 0;h < b.length;h++) { - if (axs.browserUtils.matchSelector(g, b[h])) { - g = !0; - break a; - } - } - g = !1; - } - !g && this.test_(f) && this.addElement(e, f); + for (var e = 0;e < c.length && !(null != b && d.length >= b);e++) { + var f = c[e]; + this.test_(f, a.config) && this.addElement(d, f); } - b = {result:e.length ? axs.constants.AuditResult.FAIL : axs.constants.AuditResult.PASS, elements:e}; - a < d.length && (b.resultsTruncated = !0); - return b; + a = {result:d.length ? axs.constants.AuditResult.FAIL : axs.constants.AuditResult.PASS, elements:d}; + e < c.length && (a.resultsTruncated = !0); + return a; }; -axs.AuditRule.specs = {}; axs.AuditRules = {}; -axs.AuditRules.getRule = function(a) { - if (!axs.AuditRules.rules) { - axs.AuditRules.rules = {}; - for (var b in axs.AuditRule.specs) { - var c = axs.AuditRule.specs[b], d = new axs.AuditRule(c); - axs.AuditRules.rules[c.name] = d; +(function() { + var a = {}, b = {}; + axs.AuditRules.specs = {}; + axs.AuditRules.addRule = function(c) { + var d = new axs.AuditRule(c); + if (d.code in b) { + throw Error('Can not add audit rule with same code: "' + d.code + '"'); } - } - return axs.AuditRules.rules[a]; -}; + if (d.name in a) { + throw Error('Can not add audit rule with same name: "' + d.name + '"'); + } + a[d.name] = b[d.code] = d; + axs.AuditRules.specs[c.name] = c; + }; + axs.AuditRules.getRule = function(c) { + return a[c] || b[c] || null; + }; + axs.AuditRules.getRules = function(b) { + var d = Object.keys(a); + return b ? d : d.map(function(a) { + return this.getRule(a); + }, axs.AuditRules); + }; +})(); axs.AuditResults = function() { this.errors_ = []; this.warnings_ = []; @@ -1467,11 +1775,15 @@ }; goog.exportProperty(axs.AuditResults.prototype, "toString", axs.AuditResults.prototype.toString); axs.Audit = {}; -axs.AuditConfiguration = function() { +axs.AuditConfiguration = function(a) { + null == a && (a = {}); this.rules_ = {}; this.maxResults = this.auditRulesToIgnore = this.auditRulesToRun = this.scope = null; this.withConsoleApi = !1; this.showUnsupportedRulesWarning = !0; + for (var b in this) { + this.hasOwnProperty(b) && b in a && (this[b] = a[b]); + } goog.exportProperty(this, "scope", this.scope); goog.exportProperty(this, "auditRulesToRun", this.auditRulesToRun); goog.exportProperty(this, "auditRulesToIgnore", this.auditRulesToIgnore); @@ -1490,21 +1802,26 @@ this.rules_[a].severity = b; }, getSeverity:function(a) { return a in this.rules_ && "severity" in this.rules_[a] ? this.rules_[a].severity : null; +}, setRuleConfig:function(a, b) { + a in this.rules_ || (this.rules_[a] = {}); + this.rules_[a].config = b; +}, getRuleConfig:function(a) { + return a in this.rules_ && "config" in this.rules_[a] ? this.rules_[a].config : null; }}; goog.exportProperty(axs.AuditConfiguration.prototype, "ignoreSelectors", axs.AuditConfiguration.prototype.ignoreSelectors); goog.exportProperty(axs.AuditConfiguration.prototype, "getIgnoreSelectors", axs.AuditConfiguration.prototype.getIgnoreSelectors); axs.Audit.unsupportedRulesWarningShown = !1; axs.Audit.getRulesCannotRun = function(a) { - return a.withConsoleApi ? [] : Object.keys(axs.AuditRule.specs).filter(function(a) { - return axs.AuditRules.getRule(a).requiresConsoleAPI; + return a.withConsoleApi ? [] : axs.AuditRules.getRules().filter(function(a) { + return a.requiresConsoleAPI; }).map(function(a) { - return axs.AuditRules.getRule(a).code; + return a.code; }); }; axs.Audit.run = function(a) { a = a || new axs.AuditConfiguration; var b = a.withConsoleApi, c = [], d; - d = a.auditRulesToRun && 0 < a.auditRulesToRun.length ? a.auditRulesToRun : Object.keys(axs.AuditRule.specs); + d = a.auditRulesToRun && 0 < a.auditRulesToRun.length ? a.auditRulesToRun : axs.AuditRules.getRules(!0); if (a.auditRulesToIgnore) { for (var e = 0;e < a.auditRulesToIgnore.length;e++) { var f = a.auditRulesToIgnore[e]; @@ -1519,6 +1836,8 @@ if (0 < k.length || a.scope) { h.ignoreSelectors = k; } + k = a.getRuleConfig(g.name); + null != k && (h.config = k); a.scope && (h.scope = a.scope); a.maxResults && (h.maxResults = a.maxResults); h = g.run.call(g, h); @@ -1559,17 +1878,72 @@ return b; }; goog.exportSymbol("axs.Audit.accessibilityErrorMessage", axs.Audit.accessibilityErrorMessage); -axs.AuditRule.specs.audioWithoutControls = {name:"audioWithoutControls", heading:"Audio elements should have controls", url:"", severity:axs.constants.Severity.WARNING, relevantElementMatcher:function(a) { +axs.AuditRules.addRule({name:"ariaOnReservedElement", heading:"This element does not support ARIA roles, states and properties", url:"https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules#ax_aria_12", severity:axs.constants.Severity.WARNING, relevantElementMatcher:function(a) { + return !axs.properties.canTakeAriaAttributes(a); +}, test:function(a) { + return null !== axs.properties.getAriaProperties(a); +}, code:"AX_ARIA_12"}); +axs.AuditRules.addRule({name:"ariaOwnsDescendant", heading:"aria-owns should not be used if ownership is implicit in the DOM", url:"https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules#ax_aria_06", severity:axs.constants.Severity.WARNING, relevantElementMatcher:function(a) { + return axs.browserUtils.matchSelector(a, "[aria-owns]"); +}, test:function(a) { + return axs.utils.getIdReferents("aria-owns", a).some(function(b) { + return a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_CONTAINED_BY; + }); +}, code:"AX_ARIA_06"}); +axs.AuditRules.addRule({name:"ariaRoleNotScoped", heading:"Elements with ARIA roles must be in the correct scope", url:"https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules#ax_aria_09", severity:axs.constants.Severity.SEVERE, relevantElementMatcher:function(a) { + return axs.browserUtils.matchSelector(a, "[role]"); +}, test:function(a) { + var b = axs.utils.getRoles(a); + if (!b || !b.applied) { + return !1; + } + b = b.applied.details.scope; + if (!b || 0 === b.length) { + return !1; + } + for (var c = a;c = axs.dom.parentElement(c);) { + var d = axs.utils.getRoles(c, !0); + if (d && d.applied && 0 <= b.indexOf(d.applied.name)) { + return !1; + } + } + if (a = axs.utils.getAriaIdReferrers(a, "aria-owns")) { + for (c = 0;c < a.length;c++) { + if ((d = axs.utils.getRoles(a[c], !0)) && d.applied && 0 <= b.indexOf(d.applied.name)) { + return !1; + } + } + } + return !0; +}, code:"AX_ARIA_09"}); +axs.AuditRules.addRule({name:"audioWithoutControls", heading:"Audio elements should have controls", url:"https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules#ax_audio_01", severity:axs.constants.Severity.WARNING, relevantElementMatcher:function(a) { return axs.browserUtils.matchSelector(a, "audio[autoplay]"); }, test:function(a) { - return!a.querySelectorAll("[controls]").length && 3 < a.duration; -}, code:"AX_AUDIO_01"}; -axs.AuditRule.specs.badAriaAttributeValue = {name:"badAriaAttributeValue", heading:"ARIA state and property values must be valid", url:"", severity:axs.constants.Severity.SEVERE, relevantElementMatcher:function(a) { - var b = "", c; - for (c in axs.constants.ARIA_PROPERTIES) { - b += "[aria-" + c + "],"; - } - b = b.substring(0, b.length - 1); + return !a.querySelectorAll("[controls]").length && 3 < a.duration; +}, code:"AX_AUDIO_01"}); +(function() { + var a = /^aria\-/; + axs.AuditRules.addRule({name:"badAriaAttribute", heading:"This element has an invalid ARIA attribute", url:"https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules#ax_aria_11", severity:axs.constants.Severity.WARNING, relevantElementMatcher:function(b) { + b = b.attributes; + for (var c = 0, d = b.length;c < d;c++) { + if (a.test(b[c].name)) { + return !0; + } + } + return !1; + }, test:function(b) { + b = b.attributes; + for (var c = 0, d = b.length;c < d;c++) { + var e = b[c].name; + if (a.test(e) && (e = e.replace(a, ""), !axs.constants.ARIA_PROPERTIES.hasOwnProperty(e))) { + return !0; + } + } + return !1; + }, code:"AX_ARIA_11"}); +})(); +axs.AuditRules.addRule({name:"badAriaAttributeValue", heading:"ARIA state and property values must be valid", url:"https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules#ax_aria_04", severity:axs.constants.Severity.SEVERE, relevantElementMatcher:function(a) { + var b = axs.utils.getSelectorForAriaProperties(axs.constants.ARIA_PROPERTIES); return axs.browserUtils.matchSelector(a, b); }, test:function(a) { for (var b in axs.constants.ARIA_PROPERTIES) { @@ -1577,135 +1951,328 @@ if (a.hasAttribute(c)) { var d = a.getAttribute(c); if (!axs.utils.getAriaPropertyValue(c, d, a).valid) { - return!0; + return !0; } } } - return!1; -}, code:"AX_ARIA_04"}; -axs.AuditRule.specs.badAriaRole = {name:"badAriaRole", heading:"Elements with ARIA roles must use a valid, non-abstract ARIA role", url:"https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules#-ax_aria_01--elements-with-aria-roles-must-use-a-valid-non-abstract-aria-role", severity:axs.constants.Severity.SEVERE, relevantElementMatcher:function(a) { + return !1; +}, code:"AX_ARIA_04"}); +axs.AuditRules.addRule({name:"badAriaRole", heading:"Elements with ARIA roles must use a valid, non-abstract ARIA role", url:"https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules#ax_aria_01", severity:axs.constants.Severity.SEVERE, relevantElementMatcher:function(a) { return axs.browserUtils.matchSelector(a, "[role]"); }, test:function(a) { - return!axs.utils.getRoles(a).valid; -}, code:"AX_ARIA_01"}; -axs.AuditRule.specs.controlsWithoutLabel = {name:"controlsWithoutLabel", heading:"Controls and media elements should have labels", url:"https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules#-ax_text_01--controls-and-media-elements-should-have-labels", severity:axs.constants.Severity.SEVERE, relevantElementMatcher:function(a) { - if (!axs.browserUtils.matchSelector(a, 'input:not([type="hidden"]):not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), video:not([disabled])')) { - return!1; + return !axs.utils.getRoles(a).valid; +}, code:"AX_ARIA_01"}); +axs.AuditRules.addRule({name:"controlsWithoutLabel", heading:"Controls and media elements should have labels", url:"https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules#ax_text_01", severity:axs.constants.Severity.SEVERE, relevantElementMatcher:function(a) { + if (!axs.browserUtils.matchSelector(a, 'input:not([type="hidden"]):not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), video:not([disabled])') || "presentation" == a.getAttribute("role")) { + return !1; } if (0 <= a.tabIndex) { - return!0; + return !0; } - for (a = axs.utils.parentElement(a);null != a;a = axs.utils.parentElement(a)) { + for (a = axs.dom.parentElement(a);null != a;a = axs.dom.parentElement(a)) { if (axs.utils.elementIsAriaWidget(a)) { - return!1; + return !1; } } - return!0; + return !0; }, test:function(a) { - return axs.utils.isElementOrAncestorHidden(a) || "input" == a.tagName.toLowerCase() && "button" == a.type && a.value.length || "button" == a.tagName.toLowerCase() && a.textContent.replace(/^\s+|\s+$/g, "").length ? !1 : axs.utils.hasLabel(a) ? !1 : !0; -}, code:"AX_TEXT_01", ruleName:"Controls and media elements should have labels"}; -axs.AuditRule.specs.focusableElementNotVisibleAndNotAriaHidden = {name:"focusableElementNotVisibleAndNotAriaHidden", heading:"These elements are focusable but either invisible or obscured by another element", url:"https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules#-ax_focus_01--these-elements-are-focusable-but-either-invisible-or-obscured-by-another-element", severity:axs.constants.Severity.WARNING, relevantElementMatcher:function(a) { + if (axs.utils.isElementOrAncestorHidden(a) || "input" == a.tagName.toLowerCase() && "button" == a.type && a.value.length || "button" == a.tagName.toLowerCase() && a.textContent.replace(/^\s+|\s+$/g, "").length || axs.utils.hasLabel(a)) { + return !1; + } + a = axs.properties.findTextAlternatives(a, {}); + return null === a || "" === a.trim() ? !0 : !1; +}, code:"AX_TEXT_01", ruleName:"Controls and media elements should have labels"}); +axs.AuditRules.addRule({name:"duplicateId", heading:"Any ID referred to via an IDREF must be unique in the DOM", url:"https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules#ax_html_02", severity:axs.constants.Severity.SEVERE, relevantElementMatcher:function(a) { + return a.hasAttribute("id") ? axs.utils.getIdReferrers(a).some(function(a) { + return !axs.utils.isElementOrAncestorHidden(a); + }) : !1; +}, test:function(a) { + var b = "[id='" + a.id.replace(/'/g, "\\'") + "']"; + return 1 < a.ownerDocument.querySelectorAll(b).length; +}, code:"AX_HTML_02"}); +axs.AuditRules.addRule({name:"focusableElementNotVisibleAndNotAriaHidden", heading:"These elements are focusable but either invisible or obscured by another element", url:"https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules#ax_focus_01", severity:axs.constants.Severity.WARNING, relevantElementMatcher:function(a) { if (!axs.browserUtils.matchSelector(a, axs.utils.FOCUSABLE_ELEMENTS_SELECTOR)) { - return!1; + return !1; } if (0 <= a.tabIndex) { - return!0; + return !0; } - for (a = axs.utils.parentElement(a);null != a;a = axs.utils.parentElement(a)) { - if (axs.utils.elementIsAriaWidget(a)) { - return!1; + for (var b = axs.dom.parentElement(a);null != b;b = axs.dom.parentElement(b)) { + if (axs.utils.elementIsAriaWidget(b)) { + return !1; } } - return!0; + a = axs.properties.findTextAlternatives(a, {}); + return null === a || "" === a.trim() ? !1 : !0; }, test:function(a) { if (axs.utils.isElementOrAncestorHidden(a)) { - return!1; + return !1; } a.focus(); - return!axs.utils.elementIsVisible(a); -}, code:"AX_FOCUS_01"}; -axs.AuditRule.specs.imagesWithoutAltText = {name:"imagesWithoutAltText", heading:"Images should have an alt attribute", url:"https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules#-ax_text_02--images-should-have-an-alt-attribute-unless-they-have-an-aria-role-of-presentation", severity:axs.constants.Severity.WARNING, relevantElementMatcher:function(a) { + return !axs.utils.elementIsVisible(a); +}, code:"AX_FOCUS_01"}); +axs.AuditRules.addRule({name:"humanLangMissing", heading:"The web page should have the content's human language indicated in the markup", url:"https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules#ax_html_01", severity:axs.constants.Severity.WARNING, relevantElementMatcher:function(a) { + return a instanceof a.ownerDocument.defaultView.HTMLHtmlElement; +}, test:function(a) { + return a.lang ? !1 : !0; +}, code:"AX_HTML_01"}); +axs.AuditRules.addRule({name:"imagesWithoutAltText", heading:"Images should have a text alternative or presentational role", url:"https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules#ax_text_02", severity:axs.constants.Severity.WARNING, relevantElementMatcher:function(a) { return axs.browserUtils.matchSelector(a, "img") && !axs.utils.isElementOrAncestorHidden(a); }, test:function(a) { - return!a.hasAttribute("alt") && "presentation" != a.getAttribute("role"); -}, code:"AX_TEXT_02"}; -axs.AuditRule.specs.linkWithUnclearPurpose = {name:"linkWithUnclearPurpose", heading:"The purpose of each link should be clear from the link text", url:"", severity:axs.constants.Severity.WARNING, relevantElementMatcher:function(a) { - return axs.browserUtils.matchSelector(a, "a"); -}, test:function(a) { - return/^\s*click\s*here\s*[^a-z]?$/i.test(a.textContent); -}, code:"AX_TITLE_01"}; -axs.AuditRule.specs.lowContrastElements = {name:"lowContrastElements", heading:"Text elements should have a reasonable contrast ratio", url:"https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules#-ax_color_01--text-elements-should-have-a-reasonable-contrast-ratio", severity:axs.constants.Severity.WARNING, relevantElementMatcher:function(a) { - return axs.properties.hasDirectTextDescendant(a); + if (a.hasAttribute("alt") && "" == a.alt || "presentation" == a.getAttribute("role")) { + return !1; + } + var b = {}; + axs.properties.findTextAlternatives(a, b); + return 0 == Object.keys(b).length ? !0 : !1; +}, code:"AX_TEXT_02"}); +axs.AuditRules.addRule({name:"linkWithUnclearPurpose", heading:"The purpose of each link should be clear from the link text", url:"https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules#ax_text_04", severity:axs.constants.Severity.WARNING, relevantElementMatcher:function(a) { + return axs.browserUtils.matchSelector(a, "a[href]") && !axs.utils.isElementOrAncestorHidden(a); +}, test:function(a, b) { + for (var c = b || {}, d = c.blacklistPhrases || [], e = /\s+/, f = 0;f < d.length;f++) { + var g = "^\\s*" + d[f].trim().replace(e, "\\s*") + "s*[^a-z]$"; + if ((new RegExp(g, "i")).test(a.textContent)) { + return !0; + } + } + c = c.stopwords || "click tap go here learn more this page link about".split(" "); + d = axs.properties.findTextAlternatives(a, {}); + if (null === d || "" === d.trim()) { + return !0; + } + d = d.replace(/[^a-zA-Z ]/g, ""); + for (f = 0;f < c.length;f++) { + if (d = d.replace(new RegExp("\\b" + c[f] + "\\b", "ig"), ""), "" == d.trim()) { + return !0; + } + } + return !1; +}, code:"AX_TEXT_04"}); +axs.AuditRules.addRule({name:"lowContrastElements", heading:"Text elements should have a reasonable contrast ratio", url:"https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules#ax_color_01", severity:axs.constants.Severity.WARNING, relevantElementMatcher:function(a) { + return axs.properties.hasDirectTextDescendant(a) && !axs.utils.isElementDisabled(a); }, test:function(a) { var b = window.getComputedStyle(a, null); - return(a = axs.utils.getContrastRatioForElementWithComputedStyle(b, a)) && axs.utils.isLowContrast(a, b); -}, code:"AX_COLOR_01"}; -axs.AuditRule.specs.mainRoleOnInappropriateElement = {name:"mainRoleOnInappropriateElement", heading:"role=main should only appear on significant elements", url:"", severity:axs.constants.Severity.WARNING, relevantElementMatcher:function(a) { + return (a = axs.utils.getContrastRatioForElementWithComputedStyle(b, a)) && axs.utils.isLowContrast(a, b); +}, code:"AX_COLOR_01"}); +axs.AuditRules.addRule({name:"mainRoleOnInappropriateElement", heading:"role=main should only appear on significant elements", url:"https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules#ax_aria_05", severity:axs.constants.Severity.WARNING, relevantElementMatcher:function(a) { return axs.browserUtils.matchSelector(a, "[role~=main]"); }, test:function(a) { if (axs.utils.isInlineElement(a)) { - return!0; + return !0; } a = axs.properties.getTextFromDescendantContent(a); - return!a || 50 > a.length ? !0 : !1; -}, code:"AX_ARIA_04"}; -axs.AuditRule.specs.elementsWithMeaningfulBackgroundImage = {name:"elementsWithMeaningfulBackgroundImage", severity:axs.constants.Severity.WARNING, relevantElementMatcher:function(a) { - return!axs.utils.isElementOrAncestorHidden(a); -}, heading:"Meaningful images should not be used in element backgrounds", url:"https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules#-ax_image_01--meaningful-images-should-not-be-used-in-element-backgrounds", test:function(a) { + return !a || 50 > a.length ? !0 : !1; +}, code:"AX_ARIA_05"}); +axs.AuditRules.addRule({name:"elementsWithMeaningfulBackgroundImage", severity:axs.constants.Severity.WARNING, relevantElementMatcher:function(a) { + return !axs.utils.isElementOrAncestorHidden(a); +}, heading:"Meaningful images should not be used in element backgrounds", url:"https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules#ax_image_01", test:function(a) { if (a.textContent && 0 < a.textContent.length) { - return!1; + return !1; } a = window.getComputedStyle(a, null); var b = a.backgroundImage; if (!b || "undefined" === b || "none" === b || 0 != b.indexOf("url")) { - return!1; + return !1; } b = parseInt(a.width, 10); a = parseInt(a.height, 10); return 150 > b && 150 > a; -}, code:"AX_IMAGE_01"}; -axs.AuditRule.specs.nonExistentAriaLabelledbyElement = {name:"nonExistentAriaLabelledbyElement", heading:"aria-labelledby attributes should refer to an element which exists in the DOM", url:"https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules#-ax_aria_02--aria-labelledby-attributes-should-refer-to-an-element-which-exists-in-the-dom", severity:axs.constants.Severity.WARNING, relevantElementMatcher:function(a) { - return axs.browserUtils.matchSelector(a, "[aria-labelledby]"); +}, code:"AX_IMAGE_01"}); +axs.AuditRules.addRule({name:"multipleAriaOwners", heading:"An element's ID must not be present in more that one aria-owns attribute at any time", url:"https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules#ax_aria_07", severity:axs.constants.Severity.WARNING, relevantElementMatcher:function(a) { + return axs.browserUtils.matchSelector(a, "[aria-owns]"); }, test:function(a) { - a = a.getAttribute("aria-labelledby").split(/\s+/); - for (var b = 0;b < a.length;b++) { - if (!document.getElementById(a[b])) { - return!0; + return axs.utils.getIdReferents("aria-owns", a).some(function(a) { + return 1 < axs.utils.getAriaIdReferrers(a, "aria-owns").length; + }); +}, code:"AX_ARIA_07"}); +axs.AuditRules.addRule({name:"multipleLabelableElementsPerLabel", heading:"A label element may not have labelable descendants other than its labeled control.", url:"https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules#-ax_text_03--labels-should-only-contain-one-labelable-element", severity:axs.constants.Severity.SEVERE, relevantElementMatcher:function(a) { + return axs.browserUtils.matchSelector(a, "label"); +}, test:function(a) { + if (1 < a.querySelectorAll(axs.utils.LABELABLE_ELEMENTS_SELECTOR).length) { + return !0; + } +}, code:"AX_TEXT_03"}); +axs.AuditRules.addRule({name:"nonExistentAriaRelatedElement", heading:"ARIA attributes which refer to other elements by ID should refer to elements which exist in the DOM", url:"https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules#ax_aria_02", severity:axs.constants.Severity.SEVERE, relevantElementMatcher:function(a) { + var b = axs.utils.getAriaPropertiesByValueType(["idref", "idref_list"]), b = axs.utils.getSelectorForAriaProperties(b); + return axs.browserUtils.matchSelector(a, b); +}, test:function(a) { + for (var b = axs.utils.getAriaPropertiesByValueType(["idref", "idref_list"]), b = axs.utils.getSelectorForAriaProperties(b).split(","), c = 0, d = b.length;c < d;c++) { + var e = b[c]; + if (axs.browserUtils.matchSelector(a, e)) { + var e = e.match(/aria-[^\]]+/)[0], f = a.getAttribute(e); + if (!axs.utils.getAriaPropertyValue(e, f, a).valid) { + return !0; + } } } - return!1; -}, code:"AX_ARIA_02"}; -axs.AuditRule.specs.pageWithoutTitle = {name:"pageWithoutTitle", heading:"The web page should have a title that describes topic or purpose", url:"", severity:axs.constants.Severity.WARNING, relevantElementMatcher:function(a) { + return !1; +}, code:"AX_ARIA_02"}); +axs.AuditRules.addRule({name:"pageWithoutTitle", heading:"The web page should have a title that describes topic or purpose", url:"https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules#ax_title_01", severity:axs.constants.Severity.WARNING, relevantElementMatcher:function(a) { return "html" == a.tagName.toLowerCase(); }, test:function(a) { a = a.querySelector("head"); return a ? (a = a.querySelector("title")) ? !a.textContent : !0 : !0; -}, code:"AX_TITLE_01"}; -axs.AuditRule.specs.requiredAriaAttributeMissing = {name:"requiredAriaAttributeMissing", heading:"Elements with ARIA roles must have all required attributes for that role", url:"https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules#-ax_aria_03--elements-with-aria-roles-must-have-all-required-attributes-for-that-role", severity:axs.constants.Severity.SEVERE, relevantElementMatcher:function(a) { +}, code:"AX_TITLE_01"}); +axs.AuditRules.addRule({name:"requiredAriaAttributeMissing", heading:"Elements with ARIA roles must have all required attributes for that role", url:"https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules#ax_aria_03", severity:axs.constants.Severity.SEVERE, relevantElementMatcher:function(a) { return axs.browserUtils.matchSelector(a, "[role]"); }, test:function(a) { var b = axs.utils.getRoles(a); if (!b.valid) { - return!1; + return !1; } for (var c = 0;c < b.roles.length;c++) { var d = b.roles[c].details.requiredPropertiesSet, e; for (e in d) { - if (d = e.replace(/^aria-/, ""), !("defaultValue" in axs.constants.ARIA_PROPERTIES[d] || a.hasAttribute(e))) { - return!0; + if (d = e.replace(/^aria-/, ""), !("defaultValue" in axs.constants.ARIA_PROPERTIES[d] || a.hasAttribute(e)) && 0 > axs.properties.getNativelySupportedAttributes(a).indexOf(e)) { + return !0; } } } -}, code:"AX_ARIA_03"}; -axs.AuditRule.specs.unfocusableElementsWithOnClick = {name:"unfocusableElementsWithOnClick", heading:"Elements with onclick handlers must be focusable", url:"https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules#-ax_focus_02--elements-with-onclick-handlers-must-be-focusable", severity:axs.constants.Severity.WARNING, opt_requiresConsoleAPI:!0, relevantElementMatcher:function(a) { +}, code:"AX_ARIA_03"}); +(function() { + function a(a) { + a = axs.utils.getRoles(a); + if (!a || !a.applied) { + return []; + } + a = a.applied; + return a.valid ? a.details.mustcontain || [] : []; + } + axs.AuditRules.addRule({name:"requiredOwnedAriaRoleMissing", heading:"Elements with ARIA roles must ensure required owned elements are present", url:"https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules#ax_aria_08", severity:axs.constants.Severity.SEVERE, relevantElementMatcher:function(b) { + return axs.browserUtils.matchSelector(b, "[role]") ? 0 < a(b).length : !1; + }, test:function(b) { + if ("true" === b.getAttribute("aria-busy")) { + return !1; + } + for (var c = a(b), d = c.length - 1;0 <= d;d--) { + var e = axs.utils.findDescendantsWithRole(b, c[d]); + if (e && e.length) { + return !1; + } + } + b = axs.utils.getIdReferents("aria-owns", b); + for (d = b.length - 1;0 <= d;d--) { + if ((e = axs.utils.getRoles(b[d], !0)) && e.applied) { + for (var e = e.applied, f = c.length - 1;0 <= f;f--) { + if (e.name === c[f]) { + return !1; + } + } + } + } + return !0; + }, code:"AX_ARIA_08"}); +})(); +axs.AuditRules.addRule({name:"roleTooltipRequiresDescribedby", heading:"Elements with role=tooltip should have a corresponding element with aria-describedby", url:"https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules#ax_aria_02", severity:axs.constants.Severity.SEVERE, relevantElementMatcher:function(a) { + return axs.browserUtils.matchSelector(a, "[role=tooltip]") && !axs.utils.isElementOrAncestorHidden(a); +}, test:function(a) { + return 0 === axs.utils.getAriaIdReferrers(a, "aria-describedby").length; +}, code:"AX_TOOLTIP_01"}); +axs.AuditRules.addRule({name:"tabIndexGreaterThanZero", heading:"Avoid positive integer values for tabIndex", url:"https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules#ax_focus_03", severity:axs.constants.Severity.WARNING, relevantElementMatcher:function(a) { + return axs.browserUtils.matchSelector(a, "[tabindex]"); +}, test:function(a) { + if (0 < a.tabIndex) { + return !0; + } +}, code:"AX_FOCUS_03"}); +(function() { + axs.AuditRules.addRule({name:"tableHasAppropriateHeaders", heading:"Tables should have appropriate headers", url:"https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules#ax_table_01", severity:axs.constants.Severity.SEVERE, relevantElementMatcher:function(a) { + return axs.browserUtils.matchSelector(a, "table"); + }, test:function(a) { + if ("presentation" == a.getAttribute("role")) { + return 0 != a.querySelectorAll("th").length; + } + a = a.querySelectorAll("tr"); + var b; + a: { + b = a[0].children; + for (var c = 0;c < b.length;c++) { + if ("TH" != b[c].tagName) { + b = !0; + break a; + } + } + b = !1; + } + if (b) { + a: { + for (b = 0;b < a.length;b++) { + if ("TH" != a[b].children[0].tagName) { + b = !0; + break a; + } + } + b = !1; + } + } + if (b) { + a: { + b = a[0].children; + for (c = 1;c < b.length;c++) { + if ("TH" != b[c].tagName) { + b = !0; + break a; + } + } + for (c = 1;c < a.length;c++) { + if ("TH" != a[c].children[0].tagName) { + b = !0; + break a; + } + } + b = !1; + } + } + return b; + }, code:"AX_TABLE_01"}); +})(); +(function() { + axs.AuditRules.addRule({name:"uncontrolledTabpanel", heading:"A tabpanel should be related to a tab via aria-controls or aria-labelledby", url:"https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules#ax_aria_13", severity:axs.constants.Severity.WARNING, relevantElementMatcher:function(a) { + return axs.browserUtils.matchSelector(a, '[role="tabpanel"]'); + }, test:function(a) { + var b; + b = document.querySelectorAll('[role="tab"][aria-controls="' + a.id + '"]'); + (b = a.id && 1 === b.length) || (a.hasAttribute("aria-labelledby") ? (a = document.querySelectorAll("#" + a.getAttribute("aria-labelledby")), b = 1 === a.length && "tab" === a[0].getAttribute("role")) : b = !1); + return !b; + }, code:"AX_ARIA_13"}); +})(); +axs.AuditRules.addRule({name:"unfocusableElementsWithOnClick", heading:"Elements with onclick handlers must be focusable", url:"https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules#ax_focus_02", severity:axs.constants.Severity.WARNING, opt_requiresConsoleAPI:!0, relevantElementMatcher:function(a) { return a instanceof a.ownerDocument.defaultView.HTMLBodyElement || axs.utils.isElementOrAncestorHidden(a) ? !1 : "click" in getEventListeners(a) ? !0 : !1; }, test:function(a) { - return!a.hasAttribute("tabindex") && !axs.utils.isElementImplicitlyFocusable(a) && !a.disabled; -}, code:"AX_FOCUS_02"}; -axs.AuditRule.specs.videoWithoutCaptions = {name:"videoWithoutCaptions", heading:"Video elements should use <track> elements to provide captions", url:"https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules#-ax_video_01--video-elements-should-use-track-elements-to-provide-captions", severity:axs.constants.Severity.WARNING, relevantElementMatcher:function(a) { + return !a.hasAttribute("tabindex") && !axs.utils.isElementImplicitlyFocusable(a) && !a.disabled; +}, code:"AX_FOCUS_02"}); +(function() { + var a = /^aria\-/, b = axs.utils.getSelectorForAriaProperties(axs.constants.ARIA_PROPERTIES); + axs.AuditRules.addRule({name:"unsupportedAriaAttribute", heading:"This element has an unsupported ARIA attribute", url:"https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules#ax_aria_10", severity:axs.constants.Severity.SEVERE, relevantElementMatcher:function(a) { + return axs.browserUtils.matchSelector(a, b); + }, test:function(b) { + var d = axs.utils.getRoles(b, !0), d = d && d.applied ? d.applied.details.propertiesSet : axs.constants.GLOBAL_PROPERTIES; + b = b.attributes; + for (var e = 0, f = b.length;e < f;e++) { + var g = b[e].name; + if (a.test(g)) { + var h = g.replace(a, ""); + if (axs.constants.ARIA_PROPERTIES.hasOwnProperty(h) && !(g in d)) { + return !0; + } + } + } + return !1; + }, code:"AX_ARIA_10"}); +})(); +axs.AuditRules.addRule({name:"videoWithoutCaptions", heading:"Video elements should use <track> elements to provide captions", url:"https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules#ax_video_01", severity:axs.constants.Severity.WARNING, relevantElementMatcher:function(a) { return axs.browserUtils.matchSelector(a, "video"); }, test:function(a) { - return!a.querySelectorAll("track[kind=captions]").length; -}, code:"AX_VIDEO_01"}; + return !a.querySelectorAll("track[kind=captions]").length; +}, code:"AX_VIDEO_01"}); + return axs; +}); + +// Define AMD module if possible, export globals otherwise. +if (typeof define !== 'undefined' && define.amd) { + define([], fn); +} else { + var axs = fn.call(this); +}
diff --git a/third_party/crashpad/README.chromium b/third_party/crashpad/README.chromium index b18bb0fe..40eca9a5 100644 --- a/third_party/crashpad/README.chromium +++ b/third_party/crashpad/README.chromium
@@ -2,7 +2,7 @@ Short Name: crashpad URL: https://crashpad.chromium.org/ Version: unknown -Revision: b0394744cc41a846eb9a79ccc73cd2992790ed42 +Revision: 330adfb02984692135fc5989dbaff49adb3b757e License: Apache 2.0 License File: crashpad/LICENSE Security Critical: yes @@ -35,7 +35,4 @@ $ git am --3way --message-id -p4 /tmp/patchdir Local Modifications: -- Removed references to "base/basictypes.h" and replaced them with appropriate - headers. -- Updated usage of ScopedLaunchData to use explicit methods rather than the - implicit |operator T()| conversion. +None.
diff --git a/third_party/crashpad/crashpad/DEPS b/third_party/crashpad/crashpad/DEPS index ed993d7..902915c 100644 --- a/third_party/crashpad/crashpad/DEPS +++ b/third_party/crashpad/crashpad/DEPS
@@ -25,7 +25,7 @@ '01528c7244837168a1c80f06ff60fa5a9793c824', 'crashpad/third_party/mini_chromium/mini_chromium': Var('chromium_git') + '/chromium/mini_chromium@' + - '43f04e7299621f708801bf475c84d9f294826ff9', + 'a43fee120b10ed71df4e55a370948ca461d78232', 'buildtools': Var('chromium_git') + '/chromium/buildtools.git@' + 'c2f259809d5ede3275df5ea0842f0431990c4f98',
diff --git a/third_party/crashpad/crashpad/client/capture_context_mac.h b/third_party/crashpad/crashpad/client/capture_context_mac.h index 934266e9..74e440e 100644 --- a/third_party/crashpad/crashpad/client/capture_context_mac.h +++ b/third_party/crashpad/crashpad/client/capture_context_mac.h
@@ -16,7 +16,6 @@ #define CRASHPAD_CLIENT_CAPTURE_CONTEXT_MAC_H_ #include <mach/mach.h> -#include <stdint.h> #include "build/build_config.h"
diff --git a/third_party/crashpad/crashpad/client/crash_report_database_mac.mm b/third_party/crashpad/crashpad/client/crash_report_database_mac.mm index f36356c..80cc5cd 100644 --- a/third_party/crashpad/crashpad/client/crash_report_database_mac.mm +++ b/third_party/crashpad/crashpad/client/crash_report_database_mac.mm
@@ -17,7 +17,6 @@ #include <errno.h> #include <fcntl.h> #import <Foundation/Foundation.h> -#include <stddef.h> #include <stdio.h> #include <sys/stat.h> #include <sys/types.h> @@ -27,7 +26,6 @@ #include "base/logging.h" #include "base/mac/scoped_nsautorelease_pool.h" -#include "base/macros.h" #include "base/posix/eintr_wrapper.h" #include "base/scoped_generic.h" #include "base/strings/string_piece.h"
diff --git a/third_party/crashpad/crashpad/client/crash_report_database_test.cc b/third_party/crashpad/crashpad/client/crash_report_database_test.cc index 3517330..ca839f4 100644 --- a/third_party/crashpad/crashpad/client/crash_report_database_test.cc +++ b/third_party/crashpad/crashpad/client/crash_report_database_test.cc
@@ -14,7 +14,6 @@ #include "client/crash_report_database.h" -#include "base/macros.h" #include "build/build_config.h" #include "client/settings.h" #include "gtest/gtest.h"
diff --git a/third_party/crashpad/crashpad/client/crash_report_database_win.cc b/third_party/crashpad/crashpad/client/crash_report_database_win.cc index fa71796..d408b54 100644 --- a/third_party/crashpad/crashpad/client/crash_report_database_win.cc +++ b/third_party/crashpad/crashpad/client/crash_report_database_win.cc
@@ -14,16 +14,16 @@ #include "client/crash_report_database.h" -#include <stddef.h> +#include <windows.h> #include <stdint.h> #include <string.h> +#include <sys/types.h> #include <time.h> -#include <windows.h> +#include <wchar.h> #include <utility> #include "base/logging.h" -#include "base/macros.h" #include "base/numerics/safe_math.h" #include "base/strings/string16.h" #include "base/strings/stringprintf.h"
diff --git a/third_party/crashpad/crashpad/client/crashpad_client_mac.cc b/third_party/crashpad/crashpad/client/crashpad_client_mac.cc index e35b503..97f5504 100644 --- a/third_party/crashpad/crashpad/client/crashpad_client_mac.cc +++ b/third_party/crashpad/crashpad/client/crashpad_client_mac.cc
@@ -25,7 +25,6 @@ #include "base/logging.h" #include "base/mac/mach_logging.h" -#include "base/macros.h" #include "base/posix/eintr_wrapper.h" #include "base/strings/stringprintf.h" #include "util/mac/mac_util.h"
diff --git a/third_party/crashpad/crashpad/client/crashpad_client_win.cc b/third_party/crashpad/crashpad/client/crashpad_client_win.cc index b627796a..79412abc 100644 --- a/third_party/crashpad/crashpad/client/crashpad_client_win.cc +++ b/third_party/crashpad/crashpad/client/crashpad_client_win.cc
@@ -14,9 +14,9 @@ #include "client/crashpad_client.h" +#include <windows.h> #include <stdint.h> #include <string.h> -#include <windows.h> #include "base/atomicops.h" #include "base/logging.h" @@ -26,7 +26,6 @@ #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "base/synchronization/lock.h" -#include "build/build_config.h" #include "util/file/file_io.h" #include "util/win/command_line.h" #include "util/win/critical_section_with_debug_info.h"
diff --git a/third_party/crashpad/crashpad/client/crashpad_info.cc b/third_party/crashpad/crashpad/client/crashpad_info.cc index db71cc9..596f349 100644 --- a/third_party/crashpad/crashpad/client/crashpad_info.cc +++ b/third_party/crashpad/crashpad/client/crashpad_info.cc
@@ -14,7 +14,6 @@ #include "client/crashpad_info.h" -#include "build/build_config.h" #include "util/stdlib/cxx.h" #if defined(OS_MACOSX)
diff --git a/third_party/crashpad/crashpad/client/prune_crash_reports.h b/third_party/crashpad/crashpad/client/prune_crash_reports.h index fcef135..3f13991 100644 --- a/third_party/crashpad/crashpad/client/prune_crash_reports.h +++ b/third_party/crashpad/crashpad/client/prune_crash_reports.h
@@ -15,7 +15,6 @@ #ifndef CRASHPAD_CLIENT_PRUNE_CRASH_REPORTS_H_ #define CRASHPAD_CLIENT_PRUNE_CRASH_REPORTS_H_ -#include <stddef.h> #include <sys/types.h> #include <time.h>
diff --git a/third_party/crashpad/crashpad/client/prune_crash_reports_test.cc b/third_party/crashpad/crashpad/client/prune_crash_reports_test.cc index e72c59b..bb9ea8e 100644 --- a/third_party/crashpad/crashpad/client/prune_crash_reports_test.cc +++ b/third_party/crashpad/crashpad/client/prune_crash_reports_test.cc
@@ -14,14 +14,12 @@ #include "client/prune_crash_reports.h" -#include <stddef.h> #include <stdlib.h> #include <algorithm> #include <string> #include <vector> -#include "base/macros.h" #include "base/rand_util.h" #include "gmock/gmock.h" #include "gtest/gtest.h"
diff --git a/third_party/crashpad/crashpad/client/settings_test.cc b/third_party/crashpad/crashpad/client/settings_test.cc index ec1009e..08c24b4 100644 --- a/third_party/crashpad/crashpad/client/settings_test.cc +++ b/third_party/crashpad/crashpad/client/settings_test.cc
@@ -14,7 +14,6 @@ #include "client/settings.h" -#include "base/macros.h" #include "build/build_config.h" #include "gtest/gtest.h" #include "test/errors.h"
diff --git a/third_party/crashpad/crashpad/client/simple_string_dictionary.h b/third_party/crashpad/crashpad/client/simple_string_dictionary.h index f8cdd4a5..2fb19bb 100644 --- a/third_party/crashpad/crashpad/client/simple_string_dictionary.h +++ b/third_party/crashpad/crashpad/client/simple_string_dictionary.h
@@ -15,8 +15,8 @@ #ifndef CRASHPAD_CLIENT_SIMPLE_STRING_DICTIONARY_H_ #define CRASHPAD_CLIENT_SIMPLE_STRING_DICTIONARY_H_ -#include <stddef.h> #include <string.h> +#include <sys/types.h> #include "base/logging.h" #include "base/macros.h"
diff --git a/third_party/crashpad/crashpad/client/simple_string_dictionary_test.cc b/third_party/crashpad/crashpad/client/simple_string_dictionary_test.cc index c002fe3f..6396c2fe 100644 --- a/third_party/crashpad/crashpad/client/simple_string_dictionary_test.cc +++ b/third_party/crashpad/crashpad/client/simple_string_dictionary_test.cc
@@ -14,9 +14,6 @@ #include "client/simple_string_dictionary.h" -#include <stddef.h> -#include <string.h> - #include "base/logging.h" #include "gtest/gtest.h" #include "test/gtest_death_check.h"
diff --git a/third_party/crashpad/crashpad/client/simulate_crash_mac.cc b/third_party/crashpad/crashpad/client/simulate_crash_mac.cc index 8e1deb5..7e279015 100644 --- a/third_party/crashpad/crashpad/client/simulate_crash_mac.cc +++ b/third_party/crashpad/crashpad/client/simulate_crash_mac.cc
@@ -14,8 +14,8 @@ #include "client/simulate_crash_mac.h" -#include <stddef.h> #include <string.h> +#include <sys/types.h> #include "base/logging.h" #include "base/mac/mach_logging.h"
diff --git a/third_party/crashpad/crashpad/client/simulate_crash_mac_test.cc b/third_party/crashpad/crashpad/client/simulate_crash_mac_test.cc index 320a65e..87c5f84 100644 --- a/third_party/crashpad/crashpad/client/simulate_crash_mac_test.cc +++ b/third_party/crashpad/crashpad/client/simulate_crash_mac_test.cc
@@ -15,8 +15,8 @@ #include "client/simulate_crash.h" #include <mach/mach.h> -#include <stddef.h> #include <string.h> +#include <sys/types.h> #include "base/macros.h" #include "base/strings/stringprintf.h"
diff --git a/third_party/crashpad/crashpad/crashpad.gyp b/third_party/crashpad/crashpad/crashpad.gyp index fd2a2691..42fe0a2 100644 --- a/third_party/crashpad/crashpad/crashpad.gyp +++ b/third_party/crashpad/crashpad/crashpad.gyp
@@ -17,7 +17,6 @@ { 'target_name': 'All', 'type': 'none', - 'suppress_wildcard': 1, 'dependencies': [ 'client/client.gyp:*', 'client/client_test.gyp:*', @@ -37,6 +36,11 @@ 'doc/support/crashpad.doxy.h', 'package.h', ], + 'conditions': [ + ['OS!="mac" and OS!="win"', { + 'suppress_wildcard': 1, + }], + ], }, ], }
diff --git a/third_party/crashpad/crashpad/handler/crash_report_upload_thread.cc b/third_party/crashpad/crashpad/handler/crash_report_upload_thread.cc index c3c4f36..38ce029 100644 --- a/third_party/crashpad/crashpad/handler/crash_report_upload_thread.cc +++ b/third_party/crashpad/crashpad/handler/crash_report_upload_thread.cc
@@ -21,7 +21,6 @@ #include <vector> #include "base/logging.h" -#include "base/macros.h" #include "base/memory/scoped_ptr.h" #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" @@ -34,7 +33,6 @@ #include "util/net/http_multipart_builder.h" #include "util/net/http_transport.h" #include "util/stdlib/map_insert.h" -#include "util/thread/thread.h" namespace crashpad { @@ -138,78 +136,32 @@ } // namespace -namespace internal { - -class CrashReportUploadHelperThread final : public Thread { - public: - explicit CrashReportUploadHelperThread(CrashReportUploadThread* self) - : self_(self) {} - ~CrashReportUploadHelperThread() override {} - - void ThreadMain() override { - self_->ThreadMain(); - } - - private: - CrashReportUploadThread* self_; - - DISALLOW_COPY_AND_ASSIGN(CrashReportUploadHelperThread); -}; - -} // namespace internal - CrashReportUploadThread::CrashReportUploadThread(CrashReportDatabase* database, - const std::string& url) + const std::string& url, + bool rate_limit) : url_(url), + // Check for pending reports every 15 minutes, even in the absence of a + // signal from the handler thread. This allows for failed uploads to be + // retried periodically, and for pending reports written by other + // processes to be recognized. + thread_(15 * 60, this), database_(database), - semaphore_(0), - thread_(), - running_(false) { + rate_limit_(rate_limit) { } CrashReportUploadThread::~CrashReportUploadThread() { - DCHECK(!running_); - DCHECK(!thread_); } void CrashReportUploadThread::Start() { - DCHECK(!running_); - DCHECK(!thread_); - - running_ = true; - thread_.reset(new internal::CrashReportUploadHelperThread(this)); - thread_->Start(); + thread_.Start(0); } void CrashReportUploadThread::Stop() { - DCHECK(running_); - DCHECK(thread_); - - if (!running_) { - return; - } - - running_ = false; - semaphore_.Signal(); - - thread_->Join(); - thread_.reset(); + thread_.Stop(); } void CrashReportUploadThread::ReportPending() { - semaphore_.Signal(); -} - -void CrashReportUploadThread::ThreadMain() { - while (running_) { - ProcessPendingReports(); - - // Check for pending reports every 15 minutes, even in the absence of a - // signal from the handler thread. This allows for failed uploads to be - // retried periodically, and for pending reports written by other processes - // to be recognized. - semaphore_.TimedWait(15 * 60); - } + thread_.DoWorkNow(); } void CrashReportUploadThread::ProcessPendingReports() { @@ -227,7 +179,7 @@ // Respect Stop() being called after at least one attempt to process a // report. - if (!running_) { + if (!thread_.is_running()) { return; } } @@ -254,28 +206,30 @@ // // TODO(mark): Provide a proper rate-limiting strategy and allow for failed // upload attempts to be retried. - time_t last_upload_attempt_time; - if (settings->GetLastUploadAttemptTime(&last_upload_attempt_time)) { - time_t now = time(nullptr); - if (now >= last_upload_attempt_time) { - // If the most recent upload attempt occurred within the past hour, don’t - // attempt to upload the new report. If it happened longer ago, attempt to - // upload the report. - const int kUploadAttemptIntervalSeconds = 60 * 60; // 1 hour - if (now - last_upload_attempt_time < kUploadAttemptIntervalSeconds) { - database_->SkipReportUpload(report.uuid); - return; - } - } else { - // The most recent upload attempt purportedly occurred in the future. If - // it “happened” at least one day in the future, assume that the last - // upload attempt time is bogus, and attempt to upload the report. If the - // most recent upload time is in the future but within one day, accept it - // and don’t attempt to upload the report. - const int kBackwardsClockTolerance = 60 * 60 * 24; // 1 day - if (last_upload_attempt_time - now < kBackwardsClockTolerance) { - database_->SkipReportUpload(report.uuid); - return; + if (rate_limit_) { + time_t last_upload_attempt_time; + if (settings->GetLastUploadAttemptTime(&last_upload_attempt_time)) { + time_t now = time(nullptr); + if (now >= last_upload_attempt_time) { + // If the most recent upload attempt occurred within the past hour, + // don’t attempt to upload the new report. If it happened longer ago, + // attempt to upload the report. + const int kUploadAttemptIntervalSeconds = 60 * 60; // 1 hour + if (now - last_upload_attempt_time < kUploadAttemptIntervalSeconds) { + database_->SkipReportUpload(report.uuid); + return; + } + } else { + // The most recent upload attempt purportedly occurred in the future. If + // it “happened” at least one day in the future, assume that the last + // upload attempt time is bogus, and attempt to upload the report. If + // the most recent upload time is in the future but within one day, + // accept it and don’t attempt to upload the report. + const int kBackwardsClockTolerance = 60 * 60 * 24; // 1 day + if (last_upload_attempt_time - now < kBackwardsClockTolerance) { + database_->SkipReportUpload(report.uuid); + return; + } } } } @@ -378,4 +332,8 @@ return UploadResult::kSuccess; } +void CrashReportUploadThread::DoWork(const WorkerThread* thread) { + ProcessPendingReports(); +} + } // namespace crashpad
diff --git a/third_party/crashpad/crashpad/handler/crash_report_upload_thread.h b/third_party/crashpad/crashpad/handler/crash_report_upload_thread.h index f1bb75b6..05fb9fc 100644 --- a/third_party/crashpad/crashpad/handler/crash_report_upload_thread.h +++ b/third_party/crashpad/crashpad/handler/crash_report_upload_thread.h
@@ -17,16 +17,13 @@ #include <string> +#include "base/macros.h" #include "base/memory/scoped_ptr.h" #include "client/crash_report_database.h" -#include "util/synchronization/semaphore.h" +#include "util/thread/worker_thread.h" namespace crashpad { -namespace internal { -class CrashReportUploadHelperThread; -} // namespace internal - //! \brief A thread that processes pending crash reports in a //! CrashReportDatabase by uploading them or marking them as completed //! without upload, as desired. @@ -40,14 +37,17 @@ //! catches reports that are added without a ReportPending() signal being //! caught. This may happen if crash reports are added to the database by other //! processes. -class CrashReportUploadThread { +class CrashReportUploadThread : public WorkerThread::Delegate { public: //! \brief Constructs a new object. //! //! \param[in] database The database to upload crash reports from. //! \param[in] url The URL of the server to upload crash reports to. + //! \param[in] rate_limit Whether uploads should be throttled to a (currently + //! hardcoded) rate. CrashReportUploadThread(CrashReportDatabase* database, - const std::string& url); + const std::string& url, + bool rate_limit); ~CrashReportUploadThread(); //! \brief Starts a dedicated upload thread, which executes ThreadMain(). @@ -77,8 +77,6 @@ void ReportPending(); private: - friend internal::CrashReportUploadHelperThread; - //! \brief The result code from UploadReport(). enum class UploadResult { //! \brief The crash report was uploaded successfully. @@ -99,10 +97,6 @@ kRetry, }; - //! \brief Calls ProcessPendingReports() in response to ReportPending() having - //! been called on any thread, as well as periodically on a timer. - void ThreadMain(); - //! \brief Obtains all pending reports from the database, and calls //! ProcessPendingReport() to process each one. void ProcessPendingReports(); @@ -136,11 +130,17 @@ UploadResult UploadReport(const CrashReportDatabase::Report* report, std::string* response_body); + // WorkerThread::Delegate: + //! \brief Calls ProcessPendingReports() in response to ReportPending() having + //! been called on any thread, as well as periodically on a timer. + void DoWork(const WorkerThread* thread) override; + std::string url_; + WorkerThread thread_; CrashReportDatabase* database_; // weak - Semaphore semaphore_; // TODO(mark): Use a condition variable instead? - scoped_ptr<internal::CrashReportUploadHelperThread> thread_; - bool running_; + bool rate_limit_; + + DISALLOW_COPY_AND_ASSIGN(CrashReportUploadThread); }; } // namespace crashpad
diff --git a/third_party/crashpad/crashpad/handler/crashpad_handler.ad b/third_party/crashpad/crashpad/handler/crashpad_handler.ad index e7fd66b..41457734 100644 --- a/third_party/crashpad/crashpad/handler/crashpad_handler.ad +++ b/third_party/crashpad/crashpad/handler/crashpad_handler.ad
@@ -97,6 +97,16 @@ Either this option or *--mach-service*, but not both, is required. This option is only valid on OS X. +*--handshake-handle*='HANDLE':: +Perform the handshake with the initial client on the HANDLE at 'HANDLE'. Either +this option or *--pipe-name*, but not both, is required. This option is only +valid on Windows. ++ +When this option is present, the server creates a new named pipe at a random +name and informs its client of the name. The server waits for at least one +client to register, and exits when all clients have exited, after waiting for +any uploads in progress to complete. + *--mach-service*='SERVICE':: Check in with the bootstrap server under the name 'SERVICE'. Either this option or *--handshake-fd*, but not both, is required. This option is only valid on OS @@ -107,15 +117,10 @@ declared in a job’s +MachServices+ dictionary (see launchd.plist(5)). The service name may also be completely unknown to the system. -*--handshake-handle*='HANDLE':: -Perform the handshake with the initial client on the HANDLE at 'HANDLE'. Either -this option or *--pipe-name*, but not both, is required. This option is only -valid on Windows. -+ -When this option is present, the server creates a new named pipe at a random -name and informs its client of the name. The server waits for at least one -client to register, and exits when all clients have exited, after waiting for -any uploads in progress to complete. +*--no-rate-limit*:: +Do not rate limit the upload of crash reports. By default uploads are throttled +to one per hour. Using this option disables that behavior, and Crashpad will +attempt to upload all captured reports. *--pipe-name*='PIPE':: Listen on the given pipe name for connections from clients. 'PIPE' must be of
diff --git a/third_party/crashpad/crashpad/handler/handler.gyp b/third_party/crashpad/crashpad/handler/handler.gyp index e7f54c8..9a520a2 100644 --- a/third_party/crashpad/crashpad/handler/handler.gyp +++ b/third_party/crashpad/crashpad/handler/handler.gyp
@@ -38,12 +38,14 @@ 'sources': [ 'crash_report_upload_thread.cc', 'crash_report_upload_thread.h', + 'handler_main.cc', + 'handler_main.h', 'mac/crash_report_exception_handler.cc', 'mac/crash_report_exception_handler.h', 'mac/exception_handler_server.cc', 'mac/exception_handler_server.h', - 'handler_main.cc', - 'handler_main.h', + 'prune_crash_reports_thread.cc', + 'prune_crash_reports_thread.h', 'win/crash_report_exception_handler.cc', 'win/crash_report_exception_handler.h', ],
diff --git a/third_party/crashpad/crashpad/handler/handler_main.cc b/third_party/crashpad/crashpad/handler/handler_main.cc index 16b89d01..e022dac 100644 --- a/third_party/crashpad/crashpad/handler/handler_main.cc +++ b/third_party/crashpad/crashpad/handler/handler_main.cc
@@ -32,7 +32,9 @@ #include "build/build_config.h" #include "client/crash_report_database.h" #include "client/crashpad_client.h" +#include "client/prune_crash_reports.h" #include "handler/crash_report_upload_thread.h" +#include "handler/prune_crash_reports_thread.h" #include "tools/tool_support.h" #include "util/file/file_io.h" #include "util/stdlib/map_insert.h" @@ -72,11 +74,15 @@ #if defined(OS_MACOSX) " --handshake-fd=FD establish communication with the client over FD\n" " --mach-service=SERVICE register SERVICE with the bootstrap server\n" -" --reset-own-crash-exception-port-to-system-default\n" -" reset the server's exception handler to default\n" #elif defined(OS_WIN) " --handshake-handle=HANDLE\n" " create a new pipe and send its name via HANDLE\n" +#endif // OS_MACOSX +" --no-rate-limit don't rate limit crash uploads\n" +#if defined(OS_MACOSX) +" --reset-own-crash-exception-port-to-system-default\n" +" reset the server's exception handler to default\n" +#elif defined(OS_WIN) " --pipe-name=PIPE communicate with the client over PIPE\n" #endif // OS_MACOSX " --url=URL send crash reports to this Breakpad server URL,\n" @@ -127,9 +133,13 @@ #if defined(OS_MACOSX) kOptionHandshakeFD, kOptionMachService, - kOptionResetOwnCrashExceptionPortToSystemDefault, #elif defined(OS_WIN) kOptionHandshakeHandle, +#endif // OS_MACOSX + kOptionNoRateLimit, +#if defined(OS_MACOSX) + kOptionResetOwnCrashExceptionPortToSystemDefault, +#elif defined(OS_WIN) kOptionPipeName, #endif // OS_MACOSX kOptionURL, @@ -151,12 +161,14 @@ HANDLE handshake_handle; std::string pipe_name; #endif // OS_MACOSX + bool rate_limit; } options = {}; #if defined(OS_MACOSX) options.handshake_fd = -1; #elif defined(OS_WIN) options.handshake_handle = INVALID_HANDLE_VALUE; #endif + options.rate_limit = true; const option long_options[] = { {"annotation", required_argument, nullptr, kOptionAnnotation}, @@ -164,12 +176,16 @@ #if defined(OS_MACOSX) {"handshake-fd", required_argument, nullptr, kOptionHandshakeFD}, {"mach-service", required_argument, nullptr, kOptionMachService}, +#elif defined(OS_WIN) + {"handshake-handle", required_argument, nullptr, kOptionHandshakeHandle}, +#endif // OS_MACOSX + {"no-rate-limit", no_argument, nullptr, kOptionNoRateLimit}, +#if defined(OS_MACOSX) {"reset-own-crash-exception-port-to-system-default", no_argument, nullptr, kOptionResetOwnCrashExceptionPortToSystemDefault}, #elif defined(OS_WIN) - {"handshake-handle", required_argument, nullptr, kOptionHandshakeHandle}, {"pipe-name", required_argument, nullptr, kOptionPipeName}, #endif // OS_MACOSX {"url", required_argument, nullptr, kOptionURL}, @@ -213,10 +229,6 @@ options.mach_service = optarg; break; } - case kOptionResetOwnCrashExceptionPortToSystemDefault: { - options.reset_own_crash_exception_port_to_system_default = true; - break; - } #elif defined(OS_WIN) case kOptionHandshakeHandle: { // Use unsigned int, because the handle was presented by the client in @@ -230,6 +242,17 @@ } break; } +#endif // OS_MACOSX + case kOptionNoRateLimit: { + options.rate_limit = false; + break; + } +#if defined(OS_MACOSX) + case kOptionResetOwnCrashExceptionPortToSystemDefault: { + options.reset_own_crash_exception_port_to_system_default = true; + break; + } +#elif defined(OS_WIN) case kOptionPipeName: { options.pipe_name = optarg; break; @@ -370,15 +393,24 @@ return EXIT_FAILURE; } - CrashReportUploadThread upload_thread(database.get(), options.url); + // TODO(scottmg): options.rate_limit should be removed when we have a + // configurable database setting to control upload limiting. + // See https://crashpad.chromium.org/bug/23. + CrashReportUploadThread upload_thread( + database.get(), options.url, options.rate_limit); upload_thread.Start(); + PruneCrashReportThread prune_thread(database.get(), + PruneCondition::GetDefault()); + prune_thread.Start(); + CrashReportExceptionHandler exception_handler( database.get(), &upload_thread, &options.annotations); exception_handler_server.Run(&exception_handler); upload_thread.Stop(); + prune_thread.Stop(); return EXIT_SUCCESS; }
diff --git a/third_party/crashpad/crashpad/handler/mac/exception_handler_server.cc b/third_party/crashpad/crashpad/handler/mac/exception_handler_server.cc index 1a141ba..38a016e 100644 --- a/third_party/crashpad/crashpad/handler/mac/exception_handler_server.cc +++ b/third_party/crashpad/crashpad/handler/mac/exception_handler_server.cc
@@ -18,7 +18,6 @@ #include "base/logging.h" #include "base/mac/mach_logging.h" -#include "base/macros.h" #include "util/mach/composite_mach_message_server.h" #include "util/mach/mach_extensions.h" #include "util/mach/mach_message.h"
diff --git a/third_party/crashpad/crashpad/handler/prune_crash_reports_thread.cc b/third_party/crashpad/crashpad/handler/prune_crash_reports_thread.cc new file mode 100644 index 0000000..e6f3a8b --- /dev/null +++ b/third_party/crashpad/crashpad/handler/prune_crash_reports_thread.cc
@@ -0,0 +1,44 @@ +// Copyright 2016 The Crashpad Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "handler/prune_crash_reports_thread.h" + +#include <utility> + +#include "client/prune_crash_reports.h" + +namespace crashpad { + +PruneCrashReportThread::PruneCrashReportThread( + CrashReportDatabase* database, + scoped_ptr<PruneCondition> condition) + : thread_(60 * 60 * 24, this), + condition_(std::move(condition)), + database_(database) {} + +PruneCrashReportThread::~PruneCrashReportThread() {} + +void PruneCrashReportThread::Start() { + thread_.Start(60 * 10); +} + +void PruneCrashReportThread::Stop() { + thread_.Stop(); +} + +void PruneCrashReportThread::DoWork(const WorkerThread* thread) { + PruneCrashReportDatabase(database_, condition_.get()); +} + +} // namespace crashpad
diff --git a/third_party/crashpad/crashpad/handler/prune_crash_reports_thread.h b/third_party/crashpad/crashpad/handler/prune_crash_reports_thread.h new file mode 100644 index 0000000..fbdda52 --- /dev/null +++ b/third_party/crashpad/crashpad/handler/prune_crash_reports_thread.h
@@ -0,0 +1,75 @@ +// Copyright 2016 The Crashpad Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef CRASHPAD_HANDLER_PRUNE_CRASH_REPORTS_THREAD_H_ +#define CRASHPAD_HANDLER_PRUNE_CRASH_REPORTS_THREAD_H_ + +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" +#include "util/thread/worker_thread.h" + +namespace crashpad { + +class CrashReportDatabase; +class PruneCondition; + +//! \brief A thread that periodically prunes crash reports from the database +//! using the specified condition. +//! +//! After the thread is started, the database is pruned using the condition +//! every 24 hours. Upon calling Start(), the thread waits 10 minutes before +//! performing the initial prune operation. +class PruneCrashReportThread : public WorkerThread::Delegate { + public: + //! \brief Constructs a new object. + //! + //! \param[in] database The database to prune crash reports from. + //! \param[in] condition The condition used to evaluate crash reports for + //! pruning. + PruneCrashReportThread(CrashReportDatabase* database, + scoped_ptr<PruneCondition> condition); + ~PruneCrashReportThread(); + + //! \brief Starts a dedicated pruning thread. + //! + //! The thread waits before running the initial prune, so as to not interfere + //! with any startup-related IO performed by the client. + //! + //! This method may only be be called on a newly-constructed object or after + //! a call to Stop(). + void Start(); + + //! \brief Stops the pruning thread. + //! + //! This method must only be called after Start(). If Start() has been called, + //! this method must be called before destroying an object of this class. + //! + //! This method may be called from any thread other than the pruning thread. + //! It is expected to only be called from the same thread that called Start(). + void Stop(); + + private: + // WorkerThread::Delegate: + void DoWork(const WorkerThread* thread) override; + + WorkerThread thread_; + scoped_ptr<PruneCondition> condition_; + CrashReportDatabase* database_; // weak + + DISALLOW_COPY_AND_ASSIGN(PruneCrashReportThread); +}; + +} // namespace crashpad + +#endif // CRASHPAD_HANDLER_PRUNE_CRASH_REPORTS_THREAD_H_
diff --git a/third_party/crashpad/crashpad/handler/win/crashy_test_program.cc b/third_party/crashpad/crashpad/handler/win/crashy_test_program.cc index dd3c2b4..be03d4c 100644 --- a/third_party/crashpad/crashpad/handler/win/crashy_test_program.cc +++ b/third_party/crashpad/crashpad/handler/win/crashy_test_program.cc
@@ -12,9 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include <stddef.h> #include <stdint.h> #include <stdlib.h> +#include <sys/types.h> #include <windows.h> #include <winternl.h> @@ -22,11 +22,6 @@ #include <string> #include <vector> -// ntstatus.h conflicts with windows.h so define this locally. -#ifndef STATUS_NO_SUCH_FILE -#define STATUS_NO_SUCH_FILE static_cast<NTSTATUS>(0xC000000F) -#endif - #include "base/files/file_path.h" #include "base/logging.h" #include "base/macros.h" @@ -34,6 +29,11 @@ #include "util/win/critical_section_with_debug_info.h" #include "util/win/get_function.h" +// ntstatus.h conflicts with windows.h so define this locally. +#ifndef STATUS_NO_SUCH_FILE +#define STATUS_NO_SUCH_FILE static_cast<NTSTATUS>(0xC000000F) +#endif + namespace crashpad { namespace {
diff --git a/third_party/crashpad/crashpad/minidump/minidump_context_writer.cc b/third_party/crashpad/crashpad/minidump/minidump_context_writer.cc index 4df8a65d..114859e 100644 --- a/third_party/crashpad/crashpad/minidump/minidump_context_writer.cc +++ b/third_party/crashpad/crashpad/minidump/minidump_context_writer.cc
@@ -19,7 +19,6 @@ #include "base/compiler_specific.h" #include "base/logging.h" -#include "base/macros.h" #include "snapshot/cpu_context.h" #include "util/file/file_writer.h"
diff --git a/third_party/crashpad/crashpad/minidump/minidump_context_writer.h b/third_party/crashpad/crashpad/minidump/minidump_context_writer.h index d185371..10de6900 100644 --- a/third_party/crashpad/crashpad/minidump/minidump_context_writer.h +++ b/third_party/crashpad/crashpad/minidump/minidump_context_writer.h
@@ -15,7 +15,6 @@ #ifndef CRASHPAD_MINIDUMP_MINIDUMP_CONTEXT_WRITER_H_ #define CRASHPAD_MINIDUMP_MINIDUMP_CONTEXT_WRITER_H_ -#include <stddef.h> #include <sys/types.h> #include "base/macros.h"
diff --git a/third_party/crashpad/crashpad/minidump/minidump_crashpad_info_writer.h b/third_party/crashpad/crashpad/minidump/minidump_crashpad_info_writer.h index 23d5b0c..b83aeaa8 100644 --- a/third_party/crashpad/crashpad/minidump/minidump_crashpad_info_writer.h +++ b/third_party/crashpad/crashpad/minidump/minidump_crashpad_info_writer.h
@@ -15,7 +15,7 @@ #ifndef CRASHPAD_MINIDUMP_MINIDUMP_CRASHPAD_INFO_WRITER_H_ #define CRASHPAD_MINIDUMP_MINIDUMP_CRASHPAD_INFO_WRITER_H_ -#include <stddef.h> +#include <sys/types.h> #include <vector>
diff --git a/third_party/crashpad/crashpad/minidump/minidump_crashpad_info_writer_test.cc b/third_party/crashpad/crashpad/minidump/minidump_crashpad_info_writer_test.cc index 105e7fb..d5ff65ce 100644 --- a/third_party/crashpad/crashpad/minidump/minidump_crashpad_info_writer_test.cc +++ b/third_party/crashpad/crashpad/minidump/minidump_crashpad_info_writer_test.cc
@@ -16,7 +16,6 @@ #include <windows.h> #include <dbghelp.h> -#include <stdint.h> #include <map> #include <string>
diff --git a/third_party/crashpad/crashpad/minidump/minidump_exception_writer.cc b/third_party/crashpad/crashpad/minidump/minidump_exception_writer.cc index 1b94741f..c1181ad 100644 --- a/third_party/crashpad/crashpad/minidump/minidump_exception_writer.cc +++ b/third_party/crashpad/crashpad/minidump/minidump_exception_writer.cc
@@ -14,12 +14,9 @@ #include "minidump/minidump_exception_writer.h" -#include <sys/types.h> - #include <utility> #include "base/logging.h" -#include "base/macros.h" #include "base/numerics/safe_conversions.h" #include "minidump/minidump_context_writer.h" #include "snapshot/exception_snapshot.h"
diff --git a/third_party/crashpad/crashpad/minidump/minidump_exception_writer.h b/third_party/crashpad/crashpad/minidump/minidump_exception_writer.h index 07d13451..a81abfb2 100644 --- a/third_party/crashpad/crashpad/minidump/minidump_exception_writer.h +++ b/third_party/crashpad/crashpad/minidump/minidump_exception_writer.h
@@ -17,8 +17,8 @@ #include <windows.h> #include <dbghelp.h> -#include <stddef.h> #include <stdint.h> +#include <sys/types.h> #include <vector>
diff --git a/third_party/crashpad/crashpad/minidump/minidump_exception_writer_test.cc b/third_party/crashpad/crashpad/minidump/minidump_exception_writer_test.cc index dd43a89..68e501a 100644 --- a/third_party/crashpad/crashpad/minidump/minidump_exception_writer_test.cc +++ b/third_party/crashpad/crashpad/minidump/minidump_exception_writer_test.cc
@@ -14,17 +14,9 @@ #include "minidump/minidump_exception_writer.h" -#include <windows.h> -#include <dbghelp.h> -#include <stddef.h> -#include <stdint.h> -#include <sys/types.h> - #include <string> #include <utility> -#include <vector> -#include "base/macros.h" #include "gtest/gtest.h" #include "minidump/minidump_context.h" #include "minidump/minidump_context_writer.h"
diff --git a/third_party/crashpad/crashpad/minidump/minidump_file_writer.h b/third_party/crashpad/crashpad/minidump/minidump_file_writer.h index bdb47d8..5198148a 100644 --- a/third_party/crashpad/crashpad/minidump/minidump_file_writer.h +++ b/third_party/crashpad/crashpad/minidump/minidump_file_writer.h
@@ -17,7 +17,6 @@ #include <windows.h> #include <dbghelp.h> -#include <stddef.h> #include <sys/types.h> #include <set>
diff --git a/third_party/crashpad/crashpad/minidump/minidump_file_writer_test.cc b/third_party/crashpad/crashpad/minidump/minidump_file_writer_test.cc index f2e4679..2fb7d29 100644 --- a/third_party/crashpad/crashpad/minidump/minidump_file_writer_test.cc +++ b/third_party/crashpad/crashpad/minidump/minidump_file_writer_test.cc
@@ -14,9 +14,6 @@ #include "minidump/minidump_file_writer.h" -#include <windows.h> -#include <dbghelp.h> -#include <stddef.h> #include <stdint.h> #include <string.h>
diff --git a/third_party/crashpad/crashpad/minidump/minidump_handle_writer.h b/third_party/crashpad/crashpad/minidump/minidump_handle_writer.h index 5bd1135..f8eaeef 100644 --- a/third_party/crashpad/crashpad/minidump/minidump_handle_writer.h +++ b/third_party/crashpad/crashpad/minidump/minidump_handle_writer.h
@@ -17,13 +17,12 @@ #include <windows.h> #include <dbghelp.h> -#include <stddef.h> +#include <sys/types.h> #include <map> #include <string> #include <vector> -#include "base/macros.h" #include "minidump/minidump_stream_writer.h" #include "minidump/minidump_string_writer.h" #include "minidump/minidump_writable.h"
diff --git a/third_party/crashpad/crashpad/minidump/minidump_handle_writer_test.cc b/third_party/crashpad/crashpad/minidump/minidump_handle_writer_test.cc index 4dc1e3d..2a5445d 100644 --- a/third_party/crashpad/crashpad/minidump/minidump_handle_writer_test.cc +++ b/third_party/crashpad/crashpad/minidump/minidump_handle_writer_test.cc
@@ -14,8 +14,6 @@ #include "minidump/minidump_handle_writer.h" -#include <stddef.h> - #include <string> #include <utility>
diff --git a/third_party/crashpad/crashpad/minidump/minidump_memory_info_writer.h b/third_party/crashpad/crashpad/minidump/minidump_memory_info_writer.h index f05f042..ec66019 100644 --- a/third_party/crashpad/crashpad/minidump/minidump_memory_info_writer.h +++ b/third_party/crashpad/crashpad/minidump/minidump_memory_info_writer.h
@@ -17,8 +17,8 @@ #include <windows.h> #include <dbghelp.h> -#include <stddef.h> #include <stdint.h> +#include <sys/types.h> #include <vector>
diff --git a/third_party/crashpad/crashpad/minidump/minidump_memory_info_writer_test.cc b/third_party/crashpad/crashpad/minidump/minidump_memory_info_writer_test.cc index 6dc6e5a..f59cbb8 100644 --- a/third_party/crashpad/crashpad/minidump/minidump_memory_info_writer_test.cc +++ b/third_party/crashpad/crashpad/minidump/minidump_memory_info_writer_test.cc
@@ -14,8 +14,6 @@ #include "minidump/minidump_memory_info_writer.h" -#include <stddef.h> - #include <string> #include <utility>
diff --git a/third_party/crashpad/crashpad/minidump/minidump_memory_writer.cc b/third_party/crashpad/crashpad/minidump/minidump_memory_writer.cc index 4a5f87a..3528655 100644 --- a/third_party/crashpad/crashpad/minidump/minidump_memory_writer.cc +++ b/third_party/crashpad/crashpad/minidump/minidump_memory_writer.cc
@@ -18,7 +18,6 @@ #include "base/auto_reset.h" #include "base/logging.h" -#include "base/macros.h" #include "snapshot/memory_snapshot.h" #include "util/file/file_writer.h" #include "util/numeric/safe_assignment.h"
diff --git a/third_party/crashpad/crashpad/minidump/minidump_memory_writer.h b/third_party/crashpad/crashpad/minidump/minidump_memory_writer.h index 57aaeaf..e3e33e5c 100644 --- a/third_party/crashpad/crashpad/minidump/minidump_memory_writer.h +++ b/third_party/crashpad/crashpad/minidump/minidump_memory_writer.h
@@ -17,7 +17,6 @@ #include <windows.h> #include <dbghelp.h> -#include <stddef.h> #include <stdint.h> #include <sys/types.h>
diff --git a/third_party/crashpad/crashpad/minidump/minidump_memory_writer_test.cc b/third_party/crashpad/crashpad/minidump/minidump_memory_writer_test.cc index ea1442b..7194a49 100644 --- a/third_party/crashpad/crashpad/minidump/minidump_memory_writer_test.cc +++ b/third_party/crashpad/crashpad/minidump/minidump_memory_writer_test.cc
@@ -14,11 +14,6 @@ #include "minidump/minidump_memory_writer.h" -#include <windows.h> -#include <dbghelp.h> -#include <stddef.h> -#include <stdint.h> - #include <utility> #include "base/format_macros.h"
diff --git a/third_party/crashpad/crashpad/minidump/minidump_misc_info_writer.cc b/third_party/crashpad/crashpad/minidump/minidump_misc_info_writer.cc index 1cb50be..4d3b143 100644 --- a/third_party/crashpad/crashpad/minidump/minidump_misc_info_writer.cc +++ b/third_party/crashpad/crashpad/minidump/minidump_misc_info_writer.cc
@@ -17,7 +17,6 @@ #include <limits> #include "base/logging.h" -#include "base/macros.h" #include "base/numerics/safe_conversions.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h"
diff --git a/third_party/crashpad/crashpad/minidump/minidump_misc_info_writer.h b/third_party/crashpad/crashpad/minidump/minidump_misc_info_writer.h index 66997cb..a558fc3 100644 --- a/third_party/crashpad/crashpad/minidump/minidump_misc_info_writer.h +++ b/third_party/crashpad/crashpad/minidump/minidump_misc_info_writer.h
@@ -17,7 +17,6 @@ #include <windows.h> #include <dbghelp.h> -#include <stddef.h> #include <stdint.h> #include <sys/types.h> #include <time.h>
diff --git a/third_party/crashpad/crashpad/minidump/minidump_misc_info_writer_test.cc b/third_party/crashpad/crashpad/minidump/minidump_misc_info_writer_test.cc index f838ba57..2b5dbe4 100644 --- a/third_party/crashpad/crashpad/minidump/minidump_misc_info_writer_test.cc +++ b/third_party/crashpad/crashpad/minidump/minidump_misc_info_writer_test.cc
@@ -14,10 +14,6 @@ #include "minidump/minidump_misc_info_writer.h" -#include <windows.h> -#include <dbghelp.h> -#include <stddef.h> -#include <stdint.h> #include <string.h> #include <string>
diff --git a/third_party/crashpad/crashpad/minidump/minidump_module_crashpad_info_writer.cc b/third_party/crashpad/crashpad/minidump/minidump_module_crashpad_info_writer.cc index c4a09c33c..7e34157 100644 --- a/third_party/crashpad/crashpad/minidump/minidump_module_crashpad_info_writer.cc +++ b/third_party/crashpad/crashpad/minidump/minidump_module_crashpad_info_writer.cc
@@ -14,8 +14,6 @@ #include "minidump/minidump_module_crashpad_info_writer.h" -#include <sys/types.h> - #include <utility> #include "base/logging.h"
diff --git a/third_party/crashpad/crashpad/minidump/minidump_module_crashpad_info_writer.h b/third_party/crashpad/crashpad/minidump/minidump_module_crashpad_info_writer.h index f7ef387..0b25db6 100644 --- a/third_party/crashpad/crashpad/minidump/minidump_module_crashpad_info_writer.h +++ b/third_party/crashpad/crashpad/minidump/minidump_module_crashpad_info_writer.h
@@ -15,7 +15,6 @@ #ifndef CRASHPAD_MINIDUMP_MINIDUMP_MODULE_CRASHPAD_INFO_WRITER_H_ #define CRASHPAD_MINIDUMP_MINIDUMP_MODULE_CRASHPAD_INFO_WRITER_H_ -#include <stddef.h> #include <stdint.h> #include <sys/types.h>
diff --git a/third_party/crashpad/crashpad/minidump/minidump_module_crashpad_info_writer_test.cc b/third_party/crashpad/crashpad/minidump/minidump_module_crashpad_info_writer_test.cc index 701e761..07f44c1 100644 --- a/third_party/crashpad/crashpad/minidump/minidump_module_crashpad_info_writer_test.cc +++ b/third_party/crashpad/crashpad/minidump/minidump_module_crashpad_info_writer_test.cc
@@ -16,12 +16,9 @@ #include <windows.h> #include <dbghelp.h> -#include <stddef.h> -#include <stdint.h> #include <utility> -#include "base/macros.h" #include "gtest/gtest.h" #include "minidump/minidump_extensions.h" #include "minidump/minidump_simple_string_dictionary_writer.h"
diff --git a/third_party/crashpad/crashpad/minidump/minidump_module_writer.cc b/third_party/crashpad/crashpad/minidump/minidump_module_writer.cc index c3a0e83..05f837f 100644 --- a/third_party/crashpad/crashpad/minidump/minidump_module_writer.cc +++ b/third_party/crashpad/crashpad/minidump/minidump_module_writer.cc
@@ -14,8 +14,6 @@ #include "minidump/minidump_module_writer.h" -#include <sys/types.h> - #include <limits> #include <utility>
diff --git a/third_party/crashpad/crashpad/minidump/minidump_module_writer.h b/third_party/crashpad/crashpad/minidump/minidump_module_writer.h index c476a92f..0b047e3 100644 --- a/third_party/crashpad/crashpad/minidump/minidump_module_writer.h +++ b/third_party/crashpad/crashpad/minidump/minidump_module_writer.h
@@ -17,8 +17,8 @@ #include <windows.h> #include <dbghelp.h> -#include <stddef.h> #include <stdint.h> +#include <sys/types.h> #include <time.h> #include <string>
diff --git a/third_party/crashpad/crashpad/minidump/minidump_module_writer_test.cc b/third_party/crashpad/crashpad/minidump/minidump_module_writer_test.cc index 0d3f05d..aa5171e 100644 --- a/third_party/crashpad/crashpad/minidump/minidump_module_writer_test.cc +++ b/third_party/crashpad/crashpad/minidump/minidump_module_writer_test.cc
@@ -14,17 +14,11 @@ #include "minidump/minidump_module_writer.h" -#include <windows.h> -#include <dbghelp.h> -#include <stddef.h> -#include <stdint.h> #include <string.h> -#include <sys/types.h> #include <utility> #include "base/format_macros.h" -#include "base/macros.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "gtest/gtest.h"
diff --git a/third_party/crashpad/crashpad/minidump/minidump_rva_list_writer.h b/third_party/crashpad/crashpad/minidump/minidump_rva_list_writer.h index 6444db0..cb17ef2b 100644 --- a/third_party/crashpad/crashpad/minidump/minidump_rva_list_writer.h +++ b/third_party/crashpad/crashpad/minidump/minidump_rva_list_writer.h
@@ -15,7 +15,6 @@ #ifndef CRASHPAD_MINIDUMP_RVA_LIST_WRITER_H_ #define CRASHPAD_MINIDUMP_RVA_LIST_WRITER_H_ -#include <stddef.h> #include <stdint.h> #include <sys/types.h>
diff --git a/third_party/crashpad/crashpad/minidump/minidump_rva_list_writer_test.cc b/third_party/crashpad/crashpad/minidump/minidump_rva_list_writer_test.cc index 4963f298..fa18dc5 100644 --- a/third_party/crashpad/crashpad/minidump/minidump_rva_list_writer_test.cc +++ b/third_party/crashpad/crashpad/minidump/minidump_rva_list_writer_test.cc
@@ -14,13 +14,9 @@ #include "minidump/minidump_rva_list_writer.h" -#include <stddef.h> -#include <stdint.h> - #include <utility> #include "base/format_macros.h" -#include "base/macros.h" #include "base/strings/stringprintf.h" #include "gtest/gtest.h" #include "minidump/test/minidump_rva_list_test_util.h"
diff --git a/third_party/crashpad/crashpad/minidump/minidump_simple_string_dictionary_writer.h b/third_party/crashpad/crashpad/minidump/minidump_simple_string_dictionary_writer.h index d24dc9b..975f019 100644 --- a/third_party/crashpad/crashpad/minidump/minidump_simple_string_dictionary_writer.h +++ b/third_party/crashpad/crashpad/minidump/minidump_simple_string_dictionary_writer.h
@@ -15,7 +15,6 @@ #ifndef CRASHPAD_MINIDUMP_MINIDUMP_SIMPLE_STRING_DICTIONARY_WRITER_H_ #define CRASHPAD_MINIDUMP_MINIDUMP_SIMPLE_STRING_DICTIONARY_WRITER_H_ -#include <stddef.h> #include <sys/types.h> #include <map>
diff --git a/third_party/crashpad/crashpad/minidump/minidump_simple_string_dictionary_writer_test.cc b/third_party/crashpad/crashpad/minidump/minidump_simple_string_dictionary_writer_test.cc index bd02ed4..a5b83ac4 100644 --- a/third_party/crashpad/crashpad/minidump/minidump_simple_string_dictionary_writer_test.cc +++ b/third_party/crashpad/crashpad/minidump/minidump_simple_string_dictionary_writer_test.cc
@@ -14,7 +14,6 @@ #include "minidump/minidump_simple_string_dictionary_writer.h" -#include <stddef.h> #include <stdint.h> #include <map>
diff --git a/third_party/crashpad/crashpad/minidump/minidump_string_writer.cc b/third_party/crashpad/crashpad/minidump/minidump_string_writer.cc index bf40d256..5bf57dd 100644 --- a/third_party/crashpad/crashpad/minidump/minidump_string_writer.cc +++ b/third_party/crashpad/crashpad/minidump/minidump_string_writer.cc
@@ -14,8 +14,6 @@ #include "minidump/minidump_string_writer.h" -#include <sys/types.h> - #include <utility> #include "base/logging.h"
diff --git a/third_party/crashpad/crashpad/minidump/minidump_string_writer.h b/third_party/crashpad/crashpad/minidump/minidump_string_writer.h index ff2572dd..26fabf8 100644 --- a/third_party/crashpad/crashpad/minidump/minidump_string_writer.h +++ b/third_party/crashpad/crashpad/minidump/minidump_string_writer.h
@@ -17,7 +17,7 @@ #include <windows.h> #include <dbghelp.h> -#include <stddef.h> +#include <sys/types.h> #include <string> #include <vector>
diff --git a/third_party/crashpad/crashpad/minidump/minidump_string_writer_test.cc b/third_party/crashpad/crashpad/minidump/minidump_string_writer_test.cc index 454e362..0997321 100644 --- a/third_party/crashpad/crashpad/minidump/minidump_string_writer_test.cc +++ b/third_party/crashpad/crashpad/minidump/minidump_string_writer_test.cc
@@ -14,11 +14,6 @@ #include "minidump/minidump_string_writer.h" -#include <windows.h> -#include <dbghelp.h> -#include <stddef.h> -#include <sys/types.h> - #include <string> #include "base/compiler_specific.h"
diff --git a/third_party/crashpad/crashpad/minidump/minidump_system_info_writer.cc b/third_party/crashpad/crashpad/minidump/minidump_system_info_writer.cc index 102fdcf..066363c 100644 --- a/third_party/crashpad/crashpad/minidump/minidump_system_info_writer.cc +++ b/third_party/crashpad/crashpad/minidump/minidump_system_info_writer.cc
@@ -14,12 +14,9 @@ #include "minidump/minidump_system_info_writer.h" -#include <stdint.h> #include <string.h> -#include <sys/types.h> #include "base/logging.h" -#include "base/macros.h" #include "minidump/minidump_string_writer.h" #include "snapshot/system_snapshot.h" #include "util/file/file_writer.h"
diff --git a/third_party/crashpad/crashpad/minidump/minidump_system_info_writer.h b/third_party/crashpad/crashpad/minidump/minidump_system_info_writer.h index 2227df5..8ab2d8f 100644 --- a/third_party/crashpad/crashpad/minidump/minidump_system_info_writer.h +++ b/third_party/crashpad/crashpad/minidump/minidump_system_info_writer.h
@@ -17,8 +17,8 @@ #include <windows.h> #include <dbghelp.h> -#include <stddef.h> #include <stdint.h> +#include <sys/types.h> #include <string> #include <vector>
diff --git a/third_party/crashpad/crashpad/minidump/minidump_system_info_writer_test.cc b/third_party/crashpad/crashpad/minidump/minidump_system_info_writer_test.cc index bcecef0..08f36f65 100644 --- a/third_party/crashpad/crashpad/minidump/minidump_system_info_writer_test.cc +++ b/third_party/crashpad/crashpad/minidump/minidump_system_info_writer_test.cc
@@ -14,12 +14,7 @@ #include "minidump/minidump_system_info_writer.h" -#include <windows.h> -#include <dbghelp.h> -#include <stddef.h> -#include <stdint.h> #include <string.h> -#include <sys/types.h> #include <algorithm> #include <string>
diff --git a/third_party/crashpad/crashpad/minidump/minidump_thread_id_map_test.cc b/third_party/crashpad/crashpad/minidump/minidump_thread_id_map_test.cc index 3213342..2fee93c04 100644 --- a/third_party/crashpad/crashpad/minidump/minidump_thread_id_map_test.cc +++ b/third_party/crashpad/crashpad/minidump/minidump_thread_id_map_test.cc
@@ -14,8 +14,7 @@ #include "minidump/minidump_thread_id_map.h" -#include <stddef.h> -#include <stdint.h> +#include <sys/types.h> #include <vector>
diff --git a/third_party/crashpad/crashpad/minidump/minidump_thread_writer.cc b/third_party/crashpad/crashpad/minidump/minidump_thread_writer.cc index d41d2dd..cc4339e 100644 --- a/third_party/crashpad/crashpad/minidump/minidump_thread_writer.cc +++ b/third_party/crashpad/crashpad/minidump/minidump_thread_writer.cc
@@ -14,8 +14,6 @@ #include "minidump/minidump_thread_writer.h" -#include <sys/types.h> - #include <utility> #include "base/logging.h"
diff --git a/third_party/crashpad/crashpad/minidump/minidump_thread_writer.h b/third_party/crashpad/crashpad/minidump/minidump_thread_writer.h index 604f6440..fba5481 100644 --- a/third_party/crashpad/crashpad/minidump/minidump_thread_writer.h +++ b/third_party/crashpad/crashpad/minidump/minidump_thread_writer.h
@@ -17,8 +17,8 @@ #include <windows.h> #include <dbghelp.h> -#include <stddef.h> #include <stdint.h> +#include <sys/types.h> #include <vector>
diff --git a/third_party/crashpad/crashpad/minidump/minidump_thread_writer_test.cc b/third_party/crashpad/crashpad/minidump/minidump_thread_writer_test.cc index 89df530..86a5d936 100644 --- a/third_party/crashpad/crashpad/minidump/minidump_thread_writer_test.cc +++ b/third_party/crashpad/crashpad/minidump/minidump_thread_writer_test.cc
@@ -14,18 +14,11 @@ #include "minidump/minidump_thread_writer.h" -#include <windows.h> -#include <dbghelp.h> -#include <stddef.h> -#include <stdint.h> -#include <sys/types.h> - #include <string> #include <utility> #include "base/compiler_specific.h" #include "base/format_macros.h" -#include "base/macros.h" #include "base/strings/stringprintf.h" #include "gtest/gtest.h" #include "minidump/minidump_context_writer.h"
diff --git a/third_party/crashpad/crashpad/minidump/minidump_writable.cc b/third_party/crashpad/crashpad/minidump/minidump_writable.cc index 190984ee..8b73906 100644 --- a/third_party/crashpad/crashpad/minidump/minidump_writable.cc +++ b/third_party/crashpad/crashpad/minidump/minidump_writable.cc
@@ -19,7 +19,6 @@ #include <limits> #include "base/logging.h" -#include "base/macros.h" #include "util/file/file_writer.h" #include "util/numeric/safe_assignment.h"
diff --git a/third_party/crashpad/crashpad/minidump/minidump_writable.h b/third_party/crashpad/crashpad/minidump/minidump_writable.h index 8ca9db2d..9827375 100644 --- a/third_party/crashpad/crashpad/minidump/minidump_writable.h +++ b/third_party/crashpad/crashpad/minidump/minidump_writable.h
@@ -17,7 +17,6 @@ #include <windows.h> #include <dbghelp.h> -#include <stddef.h> #include <sys/types.h> #include <vector>
diff --git a/third_party/crashpad/crashpad/minidump/minidump_writable_test.cc b/third_party/crashpad/crashpad/minidump/minidump_writable_test.cc index 77b8000..be04e60 100644 --- a/third_party/crashpad/crashpad/minidump/minidump_writable_test.cc +++ b/third_party/crashpad/crashpad/minidump/minidump_writable_test.cc
@@ -14,8 +14,6 @@ #include "minidump/minidump_writable.h" -#include <stddef.h> - #include <string> #include <vector>
diff --git a/third_party/crashpad/crashpad/minidump/minidump_writer_util.h b/third_party/crashpad/crashpad/minidump/minidump_writer_util.h index afd28f62..7ebe3f3 100644 --- a/third_party/crashpad/crashpad/minidump/minidump_writer_util.h +++ b/third_party/crashpad/crashpad/minidump/minidump_writer_util.h
@@ -15,7 +15,6 @@ #ifndef CRASHPAD_MINIDUMP_MINIDUMP_WRITER_UTIL_H_ #define CRASHPAD_MINIDUMP_MINIDUMP_WRITER_UTIL_H_ -#include <stddef.h> #include <stdint.h> #include <sys/types.h> #include <time.h>
diff --git a/third_party/crashpad/crashpad/minidump/test/minidump_context_test_util.cc b/third_party/crashpad/crashpad/minidump/test/minidump_context_test_util.cc index 639fdc97..730c2b79 100644 --- a/third_party/crashpad/crashpad/minidump/test/minidump_context_test_util.cc +++ b/third_party/crashpad/crashpad/minidump/test/minidump_context_test_util.cc
@@ -14,8 +14,8 @@ #include "minidump/test/minidump_context_test_util.h" -#include <stddef.h> #include <string.h> +#include <sys/types.h> #include "base/format_macros.h" #include "base/macros.h"
diff --git a/third_party/crashpad/crashpad/minidump/test/minidump_memory_writer_test_util.h b/third_party/crashpad/crashpad/minidump/test/minidump_memory_writer_test_util.h index c020e97..5c56898 100644 --- a/third_party/crashpad/crashpad/minidump/test/minidump_memory_writer_test_util.h +++ b/third_party/crashpad/crashpad/minidump/test/minidump_memory_writer_test_util.h
@@ -19,8 +19,8 @@ #include <windows.h> #include <dbghelp.h> -#include <stddef.h> #include <stdint.h> +#include <sys/types.h> #include <string>
diff --git a/third_party/crashpad/crashpad/minidump/test/minidump_rva_list_test_util.h b/third_party/crashpad/crashpad/minidump/test/minidump_rva_list_test_util.h index 5ee9a33..4865d01 100644 --- a/third_party/crashpad/crashpad/minidump/test/minidump_rva_list_test_util.h +++ b/third_party/crashpad/crashpad/minidump/test/minidump_rva_list_test_util.h
@@ -15,7 +15,6 @@ #ifndef CRASHPAD_MINIDUMP_TEST_MINIDUMP_RVA_LIST_TEST_UTIL_H_ #define CRASHPAD_MINIDUMP_TEST_MINIDUMP_RVA_LIST_TEST_UTIL_H_ -#include <stddef.h> #include <sys/types.h> #include <string>
diff --git a/third_party/crashpad/crashpad/minidump/test/minidump_string_writer_test_util.cc b/third_party/crashpad/crashpad/minidump/test/minidump_string_writer_test_util.cc index c0e7ffa..d5c7354 100644 --- a/third_party/crashpad/crashpad/minidump/test/minidump_string_writer_test_util.cc +++ b/third_party/crashpad/crashpad/minidump/test/minidump_string_writer_test_util.cc
@@ -14,7 +14,7 @@ #include "minidump/test/minidump_string_writer_test_util.h" -#include <stddef.h> +#include <sys/types.h> #include "gtest/gtest.h" #include "minidump/minidump_extensions.h"
diff --git a/third_party/crashpad/crashpad/minidump/test/minidump_writable_test_util.h b/third_party/crashpad/crashpad/minidump/test/minidump_writable_test_util.h index ae3172c..ea3ec00 100644 --- a/third_party/crashpad/crashpad/minidump/test/minidump_writable_test_util.h +++ b/third_party/crashpad/crashpad/minidump/test/minidump_writable_test_util.h
@@ -17,7 +17,6 @@ #include <windows.h> #include <dbghelp.h> -#include <stddef.h> #include <stdint.h> #include <sys/types.h>
diff --git a/third_party/crashpad/crashpad/snapshot/cpu_context_test.cc b/third_party/crashpad/crashpad/snapshot/cpu_context_test.cc index 27134f9..808ba61 100644 --- a/third_party/crashpad/crashpad/snapshot/cpu_context_test.cc +++ b/third_party/crashpad/crashpad/snapshot/cpu_context_test.cc
@@ -14,9 +14,8 @@ #include "snapshot/cpu_context.h" -#include <stddef.h> -#include <stdint.h> #include <string.h> +#include <sys/types.h> #include "base/macros.h" #include "gtest/gtest.h"
diff --git a/third_party/crashpad/crashpad/snapshot/mac/cpu_context_mac.cc b/third_party/crashpad/crashpad/snapshot/mac/cpu_context_mac.cc index 8b08a0a..8dca246 100644 --- a/third_party/crashpad/crashpad/snapshot/mac/cpu_context_mac.cc +++ b/third_party/crashpad/crashpad/snapshot/mac/cpu_context_mac.cc
@@ -17,7 +17,6 @@ #include <string.h> #include "base/logging.h" -#include "build/build_config.h" namespace crashpad {
diff --git a/third_party/crashpad/crashpad/snapshot/mac/cpu_context_mac_test.cc b/third_party/crashpad/crashpad/snapshot/mac/cpu_context_mac_test.cc index 541056a8..844c9f6 100644 --- a/third_party/crashpad/crashpad/snapshot/mac/cpu_context_mac_test.cc +++ b/third_party/crashpad/crashpad/snapshot/mac/cpu_context_mac_test.cc
@@ -16,7 +16,6 @@ #include <mach/mach.h> -#include "build/build_config.h" #include "gtest/gtest.h" namespace crashpad {
diff --git a/third_party/crashpad/crashpad/snapshot/mac/exception_snapshot_mac.cc b/third_party/crashpad/crashpad/snapshot/mac/exception_snapshot_mac.cc index bd8ecce..b5725d38e 100644 --- a/third_party/crashpad/crashpad/snapshot/mac/exception_snapshot_mac.cc +++ b/third_party/crashpad/crashpad/snapshot/mac/exception_snapshot_mac.cc
@@ -16,7 +16,6 @@ #include "base/logging.h" #include "base/strings/stringprintf.h" -#include "build/build_config.h" #include "snapshot/mac/cpu_context_mac.h" #include "snapshot/mac/process_reader.h" #include "util/mach/exception_behaviors.h"
diff --git a/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_annotations_reader.cc b/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_annotations_reader.cc index 23caf87..b67a089 100644 --- a/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_annotations_reader.cc +++ b/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_annotations_reader.cc
@@ -16,7 +16,7 @@ #include <mach-o/loader.h> #include <mach/mach.h> -#include <stddef.h> +#include <sys/types.h> #include <utility>
diff --git a/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_annotations_reader_test.cc b/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_annotations_reader_test.cc index 4949fba..18b00a9 100644 --- a/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_annotations_reader_test.cc +++ b/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_annotations_reader_test.cc
@@ -17,9 +17,9 @@ #include <dlfcn.h> #include <mach/mach.h> #include <signal.h> -#include <stddef.h> #include <stdlib.h> #include <string.h> +#include <sys/types.h> #include <unistd.h> #include <map>
diff --git a/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_reader.cc b/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_reader.cc index f98a658..3e944f7 100644 --- a/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_reader.cc +++ b/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_reader.cc
@@ -23,7 +23,6 @@ #include <vector> #include "base/logging.h" -#include "base/macros.h" #include "base/strings/stringprintf.h" #include "client/crashpad_info.h" #include "snapshot/mac/mach_o_image_segment_reader.h"
diff --git a/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_reader.h b/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_reader.h index 7539fde..883a756 100644 --- a/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_reader.h +++ b/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_reader.h
@@ -16,8 +16,8 @@ #define CRASHPAD_SNAPSHOT_MAC_MACH_O_IMAGE_READER_H_ #include <mach/mach.h> -#include <stddef.h> #include <stdint.h> +#include <sys/types.h> #include <map> #include <string>
diff --git a/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_reader_test.cc b/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_reader_test.cc index 071e726c..b2e5fed 100644 --- a/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_reader_test.cc +++ b/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_reader_test.cc
@@ -22,7 +22,6 @@ #include <mach-o/ldsyms.h> #include <mach-o/loader.h> #include <mach-o/nlist.h> -#include <stddef.h> #include <stdint.h> #include "base/strings/stringprintf.h"
diff --git a/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_segment_reader.h b/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_segment_reader.h index 06f9207e..20f891d 100644 --- a/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_segment_reader.h +++ b/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_segment_reader.h
@@ -16,7 +16,6 @@ #define CRASHPAD_SNAPSHOT_MAC_MACH_O_IMAGE_SEGMENT_READER_H_ #include <mach/mach.h> -#include <stddef.h> #include <stdint.h> #include <sys/types.h>
diff --git a/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_segment_reader_test.cc b/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_segment_reader_test.cc index 8c99917..49eacb0 100644 --- a/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_segment_reader_test.cc +++ b/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_segment_reader_test.cc
@@ -15,7 +15,6 @@ #include "snapshot/mac/mach_o_image_segment_reader.h" #include <mach-o/loader.h> -#include <stddef.h> #include "base/macros.h" #include "base/strings/stringprintf.h"
diff --git a/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_symbol_table_reader.cc b/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_symbol_table_reader.cc index 4cf4ef12..49655b6 100644 --- a/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_symbol_table_reader.cc +++ b/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_symbol_table_reader.cc
@@ -16,11 +16,10 @@ #include <mach-o/loader.h> #include <mach-o/nlist.h> -#include <stddef.h> +#include <sys/types.h> #include <utility> -#include "base/macros.h" #include "base/memory/scoped_ptr.h" #include "base/strings/stringprintf.h" #include "util/mac/checked_mach_address_range.h"
diff --git a/third_party/crashpad/crashpad/snapshot/mac/memory_snapshot_mac.h b/third_party/crashpad/crashpad/snapshot/mac/memory_snapshot_mac.h index 9951dee2..dbb02ee 100644 --- a/third_party/crashpad/crashpad/snapshot/mac/memory_snapshot_mac.h +++ b/third_party/crashpad/crashpad/snapshot/mac/memory_snapshot_mac.h
@@ -15,7 +15,6 @@ #ifndef CRASHPAD_SNAPSHOT_MAC_MEMORY_SNAPSHOT_MAC_H_ #define CRASHPAD_SNAPSHOT_MAC_MEMORY_SNAPSHOT_MAC_H_ -#include <stddef.h> #include <stdint.h> #include <sys/types.h>
diff --git a/third_party/crashpad/crashpad/snapshot/mac/process_reader.cc b/third_party/crashpad/crashpad/snapshot/mac/process_reader.cc index 92b9d05..c7f674b 100644 --- a/third_party/crashpad/crashpad/snapshot/mac/process_reader.cc +++ b/third_party/crashpad/crashpad/snapshot/mac/process_reader.cc
@@ -25,7 +25,6 @@ #include "base/mac/scoped_mach_port.h" #include "base/mac/scoped_mach_vm.h" #include "base/strings/stringprintf.h" -#include "build/build_config.h" #include "snapshot/mac/mach_o_image_reader.h" #include "snapshot/mac/process_types.h" #include "util/misc/scoped_forbid_return.h"
diff --git a/third_party/crashpad/crashpad/snapshot/mac/process_reader.h b/third_party/crashpad/crashpad/snapshot/mac/process_reader.h index 5204e4c8..13c59da 100644 --- a/third_party/crashpad/crashpad/snapshot/mac/process_reader.h +++ b/third_party/crashpad/crashpad/snapshot/mac/process_reader.h
@@ -16,7 +16,6 @@ #define CRASHPAD_SNAPSHOT_MAC_PROCESS_READER_H_ #include <mach/mach.h> -#include <stddef.h> #include <stdint.h> #include <sys/time.h> #include <sys/types.h>
diff --git a/third_party/crashpad/crashpad/snapshot/mac/process_reader_test.cc b/third_party/crashpad/crashpad/snapshot/mac/process_reader_test.cc index 0c4778f..2cbf8ea 100644 --- a/third_party/crashpad/crashpad/snapshot/mac/process_reader_test.cc +++ b/third_party/crashpad/crashpad/snapshot/mac/process_reader_test.cc
@@ -19,8 +19,6 @@ #include <mach-o/dyld_images.h> #include <mach/mach.h> #include <OpenCL/opencl.h> -#include <stddef.h> -#include <stdint.h> #include <string.h> #include <sys/stat.h> @@ -30,7 +28,6 @@ #include "base/logging.h" #include "base/mac/scoped_mach_port.h" -#include "base/macros.h" #include "base/posix/eintr_wrapper.h" #include "base/strings/stringprintf.h" #include "build/build_config.h"
diff --git a/third_party/crashpad/crashpad/snapshot/mac/process_types.h b/third_party/crashpad/crashpad/snapshot/mac/process_types.h index 44e3385..a1039dd 100644 --- a/third_party/crashpad/crashpad/snapshot/mac/process_types.h +++ b/third_party/crashpad/crashpad/snapshot/mac/process_types.h
@@ -18,7 +18,6 @@ #include <mach/mach.h> #include <mach-o/dyld_images.h> #include <mach-o/loader.h> -#include <stddef.h> #include <stdint.h> #include <sys/types.h>
diff --git a/third_party/crashpad/crashpad/snapshot/mac/process_types/custom.cc b/third_party/crashpad/crashpad/snapshot/mac/process_types/custom.cc index 606743a..78bc302d 100644 --- a/third_party/crashpad/crashpad/snapshot/mac/process_types/custom.cc +++ b/third_party/crashpad/crashpad/snapshot/mac/process_types/custom.cc
@@ -14,8 +14,8 @@ #include "snapshot/mac/process_types.h" -#include <stddef.h> #include <string.h> +#include <sys/types.h> #include "base/logging.h" #include "snapshot/mac/process_types/internal.h"
diff --git a/third_party/crashpad/crashpad/snapshot/mac/process_types_test.cc b/third_party/crashpad/crashpad/snapshot/mac/process_types_test.cc index 3545576..d54ea3c 100644 --- a/third_party/crashpad/crashpad/snapshot/mac/process_types_test.cc +++ b/third_party/crashpad/crashpad/snapshot/mac/process_types_test.cc
@@ -16,8 +16,6 @@ #include <AvailabilityMacros.h> #include <mach/mach.h> -#include <stddef.h> -#include <stdint.h> #include <string.h> #include <vector>
diff --git a/third_party/crashpad/crashpad/snapshot/mac/system_snapshot_mac.cc b/third_party/crashpad/crashpad/snapshot/mac/system_snapshot_mac.cc index 7eddeb03..185372d 100644 --- a/third_party/crashpad/crashpad/snapshot/mac/system_snapshot_mac.cc +++ b/third_party/crashpad/crashpad/snapshot/mac/system_snapshot_mac.cc
@@ -14,15 +14,12 @@ #include "snapshot/mac/system_snapshot_mac.h" -#include <stddef.h> -#include <stdint.h> #include <sys/sysctl.h> #include <sys/types.h> #include <sys/utsname.h> #include <time.h> #include "base/logging.h" -#include "base/macros.h" #include "base/strings/stringprintf.h" #include "build/build_config.h" #include "snapshot/cpu_context.h"
diff --git a/third_party/crashpad/crashpad/snapshot/mac/system_snapshot_mac_test.cc b/third_party/crashpad/crashpad/snapshot/mac/system_snapshot_mac_test.cc index bc10a948..a02e94e0 100644 --- a/third_party/crashpad/crashpad/snapshot/mac/system_snapshot_mac_test.cc +++ b/third_party/crashpad/crashpad/snapshot/mac/system_snapshot_mac_test.cc
@@ -19,7 +19,6 @@ #include <string> -#include "base/macros.h" #include "build/build_config.h" #include "gtest/gtest.h" #include "snapshot/mac/process_reader.h"
diff --git a/third_party/crashpad/crashpad/snapshot/mac/thread_snapshot_mac.cc b/third_party/crashpad/crashpad/snapshot/mac/thread_snapshot_mac.cc index 03c3a24..b042f75 100644 --- a/third_party/crashpad/crashpad/snapshot/mac/thread_snapshot_mac.cc +++ b/third_party/crashpad/crashpad/snapshot/mac/thread_snapshot_mac.cc
@@ -15,7 +15,6 @@ #include "snapshot/mac/thread_snapshot_mac.h" #include "base/logging.h" -#include "build/build_config.h" #include "snapshot/mac/cpu_context_mac.h" #include "snapshot/mac/process_reader.h"
diff --git a/third_party/crashpad/crashpad/snapshot/memory_snapshot.h b/third_party/crashpad/crashpad/snapshot/memory_snapshot.h index b027522..47f8443 100644 --- a/third_party/crashpad/crashpad/snapshot/memory_snapshot.h +++ b/third_party/crashpad/crashpad/snapshot/memory_snapshot.h
@@ -15,7 +15,6 @@ #ifndef CRASHPAD_SNAPSHOT_MEMORY_SNAPSHOT_H_ #define CRASHPAD_SNAPSHOT_MEMORY_SNAPSHOT_H_ -#include <stddef.h> #include <stdint.h> #include <sys/types.h>
diff --git a/third_party/crashpad/crashpad/snapshot/minidump/process_snapshot_minidump_test.cc b/third_party/crashpad/crashpad/snapshot/minidump/process_snapshot_minidump_test.cc index 8ab727fe..07665ca 100644 --- a/third_party/crashpad/crashpad/snapshot/minidump/process_snapshot_minidump_test.cc +++ b/third_party/crashpad/crashpad/snapshot/minidump/process_snapshot_minidump_test.cc
@@ -16,7 +16,6 @@ #include <windows.h> #include <dbghelp.h> -#include <stdint.h> #include <string.h> #include "base/memory/scoped_ptr.h"
diff --git a/third_party/crashpad/crashpad/snapshot/test/test_cpu_context.cc b/third_party/crashpad/crashpad/snapshot/test/test_cpu_context.cc index 506274ed..a7506b8 100644 --- a/third_party/crashpad/crashpad/snapshot/test/test_cpu_context.cc +++ b/third_party/crashpad/crashpad/snapshot/test/test_cpu_context.cc
@@ -12,11 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include <stddef.h> +#include "snapshot/test/test_cpu_context.h" + #include <string.h> +#include <sys/types.h> #include "base/macros.h" -#include "snapshot/test/test_cpu_context.h" namespace crashpad { namespace test {
diff --git a/third_party/crashpad/crashpad/snapshot/test/test_memory_snapshot.h b/third_party/crashpad/crashpad/snapshot/test/test_memory_snapshot.h index 01d0c5d..80b45c66 100644 --- a/third_party/crashpad/crashpad/snapshot/test/test_memory_snapshot.h +++ b/third_party/crashpad/crashpad/snapshot/test/test_memory_snapshot.h
@@ -15,7 +15,6 @@ #ifndef CRASHPAD_SNAPSHOT_TEST_TEST_MEMORY_SNAPSHOT_H_ #define CRASHPAD_SNAPSHOT_TEST_TEST_MEMORY_SNAPSHOT_H_ -#include <stddef.h> #include <stdint.h> #include <sys/types.h>
diff --git a/third_party/crashpad/crashpad/snapshot/win/cpu_context_win.cc b/third_party/crashpad/crashpad/snapshot/win/cpu_context_win.cc index 62a27a0..2450ef2 100644 --- a/third_party/crashpad/crashpad/snapshot/win/cpu_context_win.cc +++ b/third_party/crashpad/crashpad/snapshot/win/cpu_context_win.cc
@@ -18,7 +18,6 @@ #include <string.h> #include "base/logging.h" -#include "build/build_config.h" #include "snapshot/cpu_context.h" namespace crashpad {
diff --git a/third_party/crashpad/crashpad/snapshot/win/exception_snapshot_win.cc b/third_party/crashpad/crashpad/snapshot/win/exception_snapshot_win.cc index e3d45c33..07b1c8ea 100644 --- a/third_party/crashpad/crashpad/snapshot/win/exception_snapshot_win.cc +++ b/third_party/crashpad/crashpad/snapshot/win/exception_snapshot_win.cc
@@ -14,7 +14,6 @@ #include "snapshot/win/exception_snapshot_win.h" -#include "build/build_config.h" #include "snapshot/win/cpu_context_win.h" #include "snapshot/win/process_reader_win.h" #include "util/win/nt_internals.h"
diff --git a/third_party/crashpad/crashpad/snapshot/win/exception_snapshot_win_test.cc b/third_party/crashpad/crashpad/snapshot/win/exception_snapshot_win_test.cc index 617b000..5c3b0609e 100644 --- a/third_party/crashpad/crashpad/snapshot/win/exception_snapshot_win_test.cc +++ b/third_party/crashpad/crashpad/snapshot/win/exception_snapshot_win_test.cc
@@ -14,15 +14,11 @@ #include "snapshot/win/exception_snapshot_win.h" -#include <stdint.h> - #include <string> #include "base/files/file_path.h" -#include "base/macros.h" #include "base/strings/string16.h" #include "base/strings/utf_string_conversions.h" -#include "build/build_config.h" #include "client/crashpad_client.h" #include "gtest/gtest.h" #include "snapshot/win/process_snapshot_win.h"
diff --git a/third_party/crashpad/crashpad/snapshot/win/memory_snapshot_win.h b/third_party/crashpad/crashpad/snapshot/win/memory_snapshot_win.h index 374e356cf..04d11842 100644 --- a/third_party/crashpad/crashpad/snapshot/win/memory_snapshot_win.h +++ b/third_party/crashpad/crashpad/snapshot/win/memory_snapshot_win.h
@@ -15,7 +15,6 @@ #ifndef CRASHPAD_SNAPSHOT_WIN_MEMORY_SNAPSHOT_WIN_H_ #define CRASHPAD_SNAPSHOT_WIN_MEMORY_SNAPSHOT_WIN_H_ -#include <stddef.h> #include <stdint.h> #include <sys/types.h>
diff --git a/third_party/crashpad/crashpad/snapshot/win/module_snapshot_win.h b/third_party/crashpad/crashpad/snapshot/win/module_snapshot_win.h index b682be426..99327de5 100644 --- a/third_party/crashpad/crashpad/snapshot/win/module_snapshot_win.h +++ b/third_party/crashpad/crashpad/snapshot/win/module_snapshot_win.h
@@ -17,7 +17,6 @@ #include <windows.h> #include <stdint.h> -#include <sys/types.h> #include <map> #include <string>
diff --git a/third_party/crashpad/crashpad/snapshot/win/pe_image_annotations_reader.cc b/third_party/crashpad/crashpad/snapshot/win/pe_image_annotations_reader.cc index 7698bfd..87de1e3 100644 --- a/third_party/crashpad/crashpad/snapshot/win/pe_image_annotations_reader.cc +++ b/third_party/crashpad/crashpad/snapshot/win/pe_image_annotations_reader.cc
@@ -14,8 +14,8 @@ #include "snapshot/win/pe_image_annotations_reader.h" -#include <stddef.h> #include <string.h> +#include <sys/types.h> #include "base/strings/utf_string_conversions.h" #include "client/simple_string_dictionary.h"
diff --git a/third_party/crashpad/crashpad/snapshot/win/pe_image_reader.cc b/third_party/crashpad/crashpad/snapshot/win/pe_image_reader.cc index 4effaad7..4ae745fc 100644 --- a/third_party/crashpad/crashpad/snapshot/win/pe_image_reader.cc +++ b/third_party/crashpad/crashpad/snapshot/win/pe_image_reader.cc
@@ -17,7 +17,6 @@ #include <string.h> #include "base/logging.h" -#include "base/macros.h" #include "base/memory/scoped_ptr.h" #include "client/crashpad_info.h" #include "snapshot/win/pe_image_resource_reader.h"
diff --git a/third_party/crashpad/crashpad/snapshot/win/pe_image_reader.h b/third_party/crashpad/crashpad/snapshot/win/pe_image_reader.h index c576774f..4e9516b 100644 --- a/third_party/crashpad/crashpad/snapshot/win/pe_image_reader.h +++ b/third_party/crashpad/crashpad/snapshot/win/pe_image_reader.h
@@ -16,8 +16,8 @@ #define CRASHPAD_SNAPSHOT_WIN_PE_IMAGE_READER_H_ #include <windows.h> -#include <stddef.h> #include <stdint.h> +#include <sys/types.h> #include <string>
diff --git a/third_party/crashpad/crashpad/snapshot/win/process_reader_win.cc b/third_party/crashpad/crashpad/snapshot/win/process_reader_win.cc index 7303dd8..91d236c 100644 --- a/third_party/crashpad/crashpad/snapshot/win/process_reader_win.cc +++ b/third_party/crashpad/crashpad/snapshot/win/process_reader_win.cc
@@ -20,7 +20,6 @@ #include "base/memory/scoped_ptr.h" #include "base/numerics/safe_conversions.h" #include "base/strings/stringprintf.h" -#include "build/build_config.h" #include "util/win/capture_context.h" #include "util/win/nt_internals.h" #include "util/win/ntstatus_logging.h"
diff --git a/third_party/crashpad/crashpad/snapshot/win/process_reader_win.h b/third_party/crashpad/crashpad/snapshot/win/process_reader_win.h index 7e6d70c5..e2f1b01 100644 --- a/third_party/crashpad/crashpad/snapshot/win/process_reader_win.h +++ b/third_party/crashpad/crashpad/snapshot/win/process_reader_win.h
@@ -16,7 +16,6 @@ #define CRASHPAD_SNAPSHOT_WIN_PROCESS_READER_WIN_H_ #include <windows.h> -#include <stdint.h> #include <sys/time.h> #include <vector>
diff --git a/third_party/crashpad/crashpad/snapshot/win/process_reader_win_test.cc b/third_party/crashpad/crashpad/snapshot/win/process_reader_win_test.cc index d1609e8..b9befc9a 100644 --- a/third_party/crashpad/crashpad/snapshot/win/process_reader_win_test.cc +++ b/third_party/crashpad/crashpad/snapshot/win/process_reader_win_test.cc
@@ -17,8 +17,6 @@ #include <windows.h> #include <string.h> -#include "base/macros.h" -#include "build/build_config.h" #include "gtest/gtest.h" #include "test/win/win_multiprocess.h" #include "util/synchronization/semaphore.h"
diff --git a/third_party/crashpad/crashpad/snapshot/win/process_snapshot_win.cc b/third_party/crashpad/crashpad/snapshot/win/process_snapshot_win.cc index b781b303..8c184c26 100644 --- a/third_party/crashpad/crashpad/snapshot/win/process_snapshot_win.cc +++ b/third_party/crashpad/crashpad/snapshot/win/process_snapshot_win.cc
@@ -17,7 +17,6 @@ #include <algorithm> #include "base/logging.h" -#include "base/macros.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "snapshot/win/memory_snapshot_win.h"
diff --git a/third_party/crashpad/crashpad/snapshot/win/process_snapshot_win.h b/third_party/crashpad/crashpad/snapshot/win/process_snapshot_win.h index 6a389ce..64e73da 100644 --- a/third_party/crashpad/crashpad/snapshot/win/process_snapshot_win.h +++ b/third_party/crashpad/crashpad/snapshot/win/process_snapshot_win.h
@@ -16,8 +16,8 @@ #define CRASHPAD_SNAPSHOT_WIN_PROCESS_SNAPSHOT_WIN_H_ #include <windows.h> -#include <stddef.h> #include <sys/time.h> +#include <sys/types.h> #include <map> #include <string>
diff --git a/third_party/crashpad/crashpad/snapshot/win/system_snapshot_win.cc b/third_party/crashpad/crashpad/snapshot/win/system_snapshot_win.cc index b3458246..28d692bd 100644 --- a/third_party/crashpad/crashpad/snapshot/win/system_snapshot_win.cc +++ b/third_party/crashpad/crashpad/snapshot/win/system_snapshot_win.cc
@@ -17,7 +17,6 @@ #include <windows.h> #include <intrin.h> #include <powrprof.h> -#include <stdint.h> #include <winnt.h> #include <algorithm>
diff --git a/third_party/crashpad/crashpad/snapshot/win/system_snapshot_win_test.cc b/third_party/crashpad/crashpad/snapshot/win/system_snapshot_win_test.cc index d02195c..d0caee7 100644 --- a/third_party/crashpad/crashpad/snapshot/win/system_snapshot_win_test.cc +++ b/third_party/crashpad/crashpad/snapshot/win/system_snapshot_win_test.cc
@@ -19,7 +19,6 @@ #include <string> -#include "base/macros.h" #include "build/build_config.h" #include "gtest/gtest.h" #include "snapshot/win/process_reader_win.h"
diff --git a/third_party/crashpad/crashpad/snapshot/win/thread_snapshot_win.cc b/third_party/crashpad/crashpad/snapshot/win/thread_snapshot_win.cc index 2239298..9c8c9ea 100644 --- a/third_party/crashpad/crashpad/snapshot/win/thread_snapshot_win.cc +++ b/third_party/crashpad/crashpad/snapshot/win/thread_snapshot_win.cc
@@ -17,7 +17,6 @@ #include <vector> #include "base/logging.h" -#include "build/build_config.h" #include "snapshot/win/cpu_context_win.h" #include "snapshot/win/process_reader_win.h"
diff --git a/third_party/crashpad/crashpad/test/multiprocess_exec_test_child.cc b/third_party/crashpad/crashpad/test/multiprocess_exec_test_child.cc index 84d44ab3..c796e4a3 100644 --- a/third_party/crashpad/crashpad/test/multiprocess_exec_test_child.cc +++ b/third_party/crashpad/crashpad/test/multiprocess_exec_test_child.cc
@@ -14,7 +14,6 @@ #include <errno.h> #include <limits.h> -#include <stddef.h> #include <stdio.h> #include <stdlib.h> #include <sys/types.h>
diff --git a/third_party/crashpad/crashpad/test/multiprocess_exec_win.cc b/third_party/crashpad/crashpad/test/multiprocess_exec_win.cc index 1db73795..3f7d2face 100644 --- a/third_party/crashpad/crashpad/test/multiprocess_exec_win.cc +++ b/third_party/crashpad/crashpad/test/multiprocess_exec_win.cc
@@ -14,7 +14,7 @@ #include "test/multiprocess_exec.h" -#include <stddef.h> +#include <sys/types.h> #include "base/logging.h" #include "base/strings/utf_string_conversions.h"
diff --git a/third_party/crashpad/crashpad/tools/crashpad_database_util.cc b/third_party/crashpad/crashpad/tools/crashpad_database_util.cc index dcb5496..3cd573a 100644 --- a/third_party/crashpad/crashpad/tools/crashpad_database_util.cc +++ b/third_party/crashpad/crashpad/tools/crashpad_database_util.cc
@@ -14,7 +14,6 @@ #include <errno.h> #include <getopt.h> -#include <stddef.h> #include <stdio.h> #include <stdlib.h> #include <string.h>
diff --git a/third_party/crashpad/crashpad/tools/mac/catch_exception_tool.cc b/third_party/crashpad/crashpad/tools/mac/catch_exception_tool.cc index e38dab5..afd738a 100644 --- a/third_party/crashpad/crashpad/tools/mac/catch_exception_tool.cc +++ b/third_party/crashpad/crashpad/tools/mac/catch_exception_tool.cc
@@ -14,9 +14,9 @@ #include <getopt.h> #include <libgen.h> -#include <stddef.h> #include <stdio.h> #include <string.h> +#include <sys/types.h> #include <unistd.h> #include <algorithm>
diff --git a/third_party/crashpad/crashpad/tools/mac/exception_port_tool.cc b/third_party/crashpad/crashpad/tools/mac/exception_port_tool.cc index 11603814..3faa00fe 100644 --- a/third_party/crashpad/crashpad/tools/mac/exception_port_tool.cc +++ b/third_party/crashpad/crashpad/tools/mac/exception_port_tool.cc
@@ -16,10 +16,10 @@ #include <getopt.h> #include <libgen.h> #include <mach/mach.h> -#include <stddef.h> #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <sys/types.h> #include <unistd.h> #include <string>
diff --git a/third_party/crashpad/crashpad/tools/tool_support.cc b/third_party/crashpad/crashpad/tools/tool_support.cc index 401cff3..5d3592bc 100644 --- a/third_party/crashpad/crashpad/tools/tool_support.cc +++ b/third_party/crashpad/crashpad/tools/tool_support.cc
@@ -20,7 +20,6 @@ #include "base/memory/scoped_ptr.h" #include "base/strings/utf_string_conversions.h" -#include "build/build_config.h" #include "package.h" namespace crashpad {
diff --git a/third_party/crashpad/crashpad/util/file/file_io.h b/third_party/crashpad/crashpad/util/file/file_io.h index ae920db8..55909415 100644 --- a/third_party/crashpad/crashpad/util/file/file_io.h +++ b/third_party/crashpad/crashpad/util/file/file_io.h
@@ -15,7 +15,6 @@ #ifndef CRASHPAD_UTIL_FILE_FILE_IO_H_ #define CRASHPAD_UTIL_FILE_FILE_IO_H_ -#include <stddef.h> #include <sys/types.h> #include "build/build_config.h"
diff --git a/third_party/crashpad/crashpad/util/file/file_io_posix.cc b/third_party/crashpad/crashpad/util/file/file_io_posix.cc index d6625f8..ce08a39 100644 --- a/third_party/crashpad/crashpad/util/file/file_io_posix.cc +++ b/third_party/crashpad/crashpad/util/file/file_io_posix.cc
@@ -15,7 +15,6 @@ #include "util/file/file_io.h" #include <fcntl.h> -#include <stddef.h> #include <sys/file.h> #include <unistd.h>
diff --git a/third_party/crashpad/crashpad/util/file/file_io_test.cc b/third_party/crashpad/crashpad/util/file/file_io_test.cc index 7dd763c..27ffd310 100644 --- a/third_party/crashpad/crashpad/util/file/file_io_test.cc +++ b/third_party/crashpad/crashpad/util/file/file_io_test.cc
@@ -14,8 +14,6 @@ #include "util/file/file_io.h" -#include <stddef.h> - #include "base/atomicops.h" #include "base/files/file_path.h" #include "base/macros.h"
diff --git a/third_party/crashpad/crashpad/util/file/file_io_win.cc b/third_party/crashpad/crashpad/util/file/file_io_win.cc index 7f48317..def2a5a 100644 --- a/third_party/crashpad/crashpad/util/file/file_io_win.cc +++ b/third_party/crashpad/crashpad/util/file/file_io_win.cc
@@ -14,8 +14,6 @@ #include "util/file/file_io.h" -#include <stddef.h> - #include "base/files/file_path.h" #include "base/logging.h" #include "base/numerics/safe_conversions.h"
diff --git a/third_party/crashpad/crashpad/util/file/file_reader.h b/third_party/crashpad/crashpad/util/file/file_reader.h index 27bd284..39225e54 100644 --- a/third_party/crashpad/crashpad/util/file/file_reader.h +++ b/third_party/crashpad/crashpad/util/file/file_reader.h
@@ -15,7 +15,6 @@ #ifndef CRASHPAD_UTIL_FILE_FILE_READER_H_ #define CRASHPAD_UTIL_FILE_FILE_READER_H_ -#include <stddef.h> #include <stdio.h> #include <sys/types.h>
diff --git a/third_party/crashpad/crashpad/util/file/file_writer.cc b/third_party/crashpad/crashpad/util/file/file_writer.cc index 62f896b..edbdb8d 100644 --- a/third_party/crashpad/crashpad/util/file/file_writer.cc +++ b/third_party/crashpad/crashpad/util/file/file_writer.cc
@@ -14,11 +14,11 @@ #include "util/file/file_writer.h" -#include <algorithm> - #include <limits.h> #include <string.h> +#include <algorithm> + #include "base/logging.h" #include "base/numerics/safe_conversions.h" #include "build/build_config.h"
diff --git a/third_party/crashpad/crashpad/util/file/file_writer.h b/third_party/crashpad/crashpad/util/file/file_writer.h index 0af8f87..ed261ec 100644 --- a/third_party/crashpad/crashpad/util/file/file_writer.h +++ b/third_party/crashpad/crashpad/util/file/file_writer.h
@@ -15,7 +15,6 @@ #ifndef CRASHPAD_UTIL_FILE_FILE_WRITER_H_ #define CRASHPAD_UTIL_FILE_FILE_WRITER_H_ -#include <stddef.h> #include <sys/types.h> #include <vector>
diff --git a/third_party/crashpad/crashpad/util/file/string_file.h b/third_party/crashpad/crashpad/util/file/string_file.h index 9c0d793..313310e 100644 --- a/third_party/crashpad/crashpad/util/file/string_file.h +++ b/third_party/crashpad/crashpad/util/file/string_file.h
@@ -15,7 +15,6 @@ #ifndef CRASHPAD_UTIL_FILE_STRING_FILE_H_ #define CRASHPAD_UTIL_FILE_STRING_FILE_H_ -#include <stddef.h> #include <sys/types.h> #include <string>
diff --git a/third_party/crashpad/crashpad/util/file/string_file_test.cc b/third_party/crashpad/crashpad/util/file/string_file_test.cc index a961aa0..1b154bb 100644 --- a/third_party/crashpad/crashpad/util/file/string_file_test.cc +++ b/third_party/crashpad/crashpad/util/file/string_file_test.cc
@@ -14,7 +14,6 @@ #include "util/file/string_file.h" -#include <stddef.h> #include <stdint.h> #include <string.h>
diff --git a/third_party/crashpad/crashpad/util/mac/checked_mach_address_range.h b/third_party/crashpad/crashpad/util/mac/checked_mach_address_range.h index e8b98cc..e64e3d1 100644 --- a/third_party/crashpad/crashpad/util/mac/checked_mach_address_range.h +++ b/third_party/crashpad/crashpad/util/mac/checked_mach_address_range.h
@@ -16,7 +16,6 @@ #define CRASHPAD_UTIL_MAC_CHECKED_MACH_ADDRESS_RANGE_H_ #include <mach/mach.h> -#include <stddef.h> #include "util/numeric/checked_address_range.h"
diff --git a/third_party/crashpad/crashpad/util/mac/checked_mach_address_range_test.cc b/third_party/crashpad/crashpad/util/mac/checked_mach_address_range_test.cc index 571fe2e..c012624 100644 --- a/third_party/crashpad/crashpad/util/mac/checked_mach_address_range_test.cc +++ b/third_party/crashpad/crashpad/util/mac/checked_mach_address_range_test.cc
@@ -15,7 +15,7 @@ #include "util/mac/checked_mach_address_range.h" #include <mach/mach.h> -#include <stddef.h> +#include <sys/types.h> #include <limits>
diff --git a/third_party/crashpad/crashpad/util/mac/launchd.h b/third_party/crashpad/crashpad/util/mac/launchd.h index d1ddbbb..2545075 100644 --- a/third_party/crashpad/crashpad/util/mac/launchd.h +++ b/third_party/crashpad/crashpad/util/mac/launchd.h
@@ -17,7 +17,7 @@ #include <CoreFoundation/CoreFoundation.h> #include <launch.h> -#include <stddef.h> +#include <sys/types.h> namespace crashpad {
diff --git a/third_party/crashpad/crashpad/util/mac/launchd_test.mm b/third_party/crashpad/crashpad/util/mac/launchd_test.mm index 7c86400..649e799d 100644 --- a/third_party/crashpad/crashpad/util/mac/launchd_test.mm +++ b/third_party/crashpad/crashpad/util/mac/launchd_test.mm
@@ -16,7 +16,6 @@ #import <Foundation/Foundation.h> #include <launch.h> -#include <stddef.h> #include <stdint.h> #include <string.h> @@ -63,8 +62,9 @@ NSNumber* integer_ns = integer_nses[index]; launch_data.reset(CFPropertyToLaunchData(integer_ns)); ASSERT_TRUE(launch_data.get()); - ASSERT_EQ(LAUNCH_DATA_INTEGER, LaunchDataGetType(launch_data)); - EXPECT_EQ([integer_ns longLongValue], LaunchDataGetInteger(launch_data)) + ASSERT_EQ(LAUNCH_DATA_INTEGER, LaunchDataGetType(launch_data.get())); + EXPECT_EQ([integer_ns longLongValue], + LaunchDataGetInteger(launch_data.get())) << "index " << index; } } @@ -92,9 +92,9 @@ NSNumber* double_ns = double_nses[index]; launch_data.reset(CFPropertyToLaunchData(double_ns)); ASSERT_TRUE(launch_data.get()); - ASSERT_EQ(LAUNCH_DATA_REAL, LaunchDataGetType(launch_data)); + ASSERT_EQ(LAUNCH_DATA_REAL, LaunchDataGetType(launch_data.get())); double expected_double_value = [double_ns doubleValue]; - double observed_double_value = LaunchDataGetReal(launch_data); + double observed_double_value = LaunchDataGetReal(launch_data.get()); bool expected_is_nan = std::isnan(expected_double_value); EXPECT_EQ(expected_is_nan, std::isnan(observed_double_value)); if (!expected_is_nan) { @@ -118,11 +118,11 @@ NSNumber* bool_ns = bool_nses[index]; launch_data.reset(CFPropertyToLaunchData(bool_ns)); ASSERT_TRUE(launch_data.get()); - ASSERT_EQ(LAUNCH_DATA_BOOL, LaunchDataGetType(launch_data)); + ASSERT_EQ(LAUNCH_DATA_BOOL, LaunchDataGetType(launch_data.get())); if ([bool_ns boolValue]) { - EXPECT_TRUE(LaunchDataGetBool(launch_data)); + EXPECT_TRUE(LaunchDataGetBool(launch_data.get())); } else { - EXPECT_FALSE(LaunchDataGetBool(launch_data)); + EXPECT_FALSE(LaunchDataGetBool(launch_data.get())); } } } @@ -142,8 +142,9 @@ NSString* string_ns = string_nses[index]; launch_data.reset(CFPropertyToLaunchData(string_ns)); ASSERT_TRUE(launch_data.get()); - ASSERT_EQ(LAUNCH_DATA_STRING, LaunchDataGetType(launch_data)); - EXPECT_STREQ([string_ns UTF8String], LaunchDataGetString(launch_data)); + ASSERT_EQ(LAUNCH_DATA_STRING, LaunchDataGetType(launch_data.get())); + EXPECT_STREQ([string_ns UTF8String], + LaunchDataGetString(launch_data.get())); } } } @@ -157,10 +158,11 @@ NSData* data_ns = [NSData dataWithBytes:data_c length:sizeof(data_c)]; launch_data.reset(CFPropertyToLaunchData(data_ns)); ASSERT_TRUE(launch_data.get()); - ASSERT_EQ(LAUNCH_DATA_OPAQUE, LaunchDataGetType(launch_data)); - EXPECT_EQ(sizeof(data_c), LaunchDataGetOpaqueSize(launch_data)); - EXPECT_EQ(0, - memcmp(LaunchDataGetOpaque(launch_data), data_c, sizeof(data_c))); + ASSERT_EQ(LAUNCH_DATA_OPAQUE, LaunchDataGetType(launch_data.get())); + EXPECT_EQ(sizeof(data_c), LaunchDataGetOpaqueSize(launch_data.get())); + EXPECT_EQ( + 0, + memcmp(LaunchDataGetOpaque(launch_data.get()), data_c, sizeof(data_c))); } } @@ -174,10 +176,11 @@ launch_data.reset(CFPropertyToLaunchData(dictionary_ns)); ASSERT_TRUE(launch_data.get()); - ASSERT_EQ(LAUNCH_DATA_DICTIONARY, LaunchDataGetType(launch_data)); - EXPECT_EQ([dictionary_ns count], LaunchDataDictGetCount(launch_data)); + ASSERT_EQ(LAUNCH_DATA_DICTIONARY, LaunchDataGetType(launch_data.get())); + EXPECT_EQ([dictionary_ns count], LaunchDataDictGetCount(launch_data.get())); - launch_data_t launch_lookup_data = LaunchDataDictLookup(launch_data, "key"); + launch_data_t launch_lookup_data = + LaunchDataDictLookup(launch_data.get(), "key"); ASSERT_TRUE(launch_lookup_data); ASSERT_EQ(LAUNCH_DATA_STRING, LaunchDataGetType(launch_lookup_data)); EXPECT_STREQ("value", LaunchDataGetString(launch_lookup_data)); @@ -192,15 +195,16 @@ launch_data.reset(CFPropertyToLaunchData(array_ns)); ASSERT_TRUE(launch_data.get()); - ASSERT_EQ(LAUNCH_DATA_ARRAY, LaunchDataGetType(launch_data)); - EXPECT_EQ([array_ns count], LaunchDataArrayGetCount(launch_data)); + ASSERT_EQ(LAUNCH_DATA_ARRAY, LaunchDataGetType(launch_data.get())); + EXPECT_EQ([array_ns count], LaunchDataArrayGetCount(launch_data.get())); - launch_data_t launch_lookup_data = LaunchDataArrayGetIndex(launch_data, 0); + launch_data_t launch_lookup_data = + LaunchDataArrayGetIndex(launch_data.get(), 0); ASSERT_TRUE(launch_lookup_data); ASSERT_EQ(LAUNCH_DATA_STRING, LaunchDataGetType(launch_lookup_data)); EXPECT_STREQ("element_1", LaunchDataGetString(launch_lookup_data)); - launch_lookup_data = LaunchDataArrayGetIndex(launch_data, 1); + launch_lookup_data = LaunchDataArrayGetIndex(launch_data.get(), 1); ASSERT_TRUE(launch_lookup_data); ASSERT_EQ(LAUNCH_DATA_STRING, LaunchDataGetType(launch_lookup_data)); EXPECT_STREQ("element_2", LaunchDataGetString(launch_lookup_data)); @@ -216,18 +220,18 @@ NSDate* date = [NSDate date]; launch_data.reset(CFPropertyToLaunchData(date)); - EXPECT_FALSE(launch_data); + EXPECT_FALSE(launch_data.get()); NSDictionary* date_dictionary = @{ @"key" : @"value", @"date" : date, }; launch_data.reset(CFPropertyToLaunchData(date_dictionary)); - EXPECT_FALSE(launch_data); + EXPECT_FALSE(launch_data.get()); NSArray* date_array = @[ @"string_1", date, @"string_2", ]; launch_data.reset(CFPropertyToLaunchData(date_array)); - EXPECT_FALSE(launch_data); + EXPECT_FALSE(launch_data.get()); } } @@ -247,24 +251,24 @@ launch_data.reset(CFPropertyToLaunchData(job_dictionary)); ASSERT_TRUE(launch_data.get()); - ASSERT_EQ(LAUNCH_DATA_DICTIONARY, LaunchDataGetType(launch_data)); - EXPECT_EQ(4u, LaunchDataDictGetCount(launch_data)); + ASSERT_EQ(LAUNCH_DATA_DICTIONARY, LaunchDataGetType(launch_data.get())); + EXPECT_EQ(4u, LaunchDataDictGetCount(launch_data.get())); launch_data_t launch_lookup_data = - LaunchDataDictLookup(launch_data, LAUNCH_JOBKEY_LABEL); + LaunchDataDictLookup(launch_data.get(), LAUNCH_JOBKEY_LABEL); ASSERT_TRUE(launch_lookup_data); ASSERT_EQ(LAUNCH_DATA_STRING, LaunchDataGetType(launch_lookup_data)); EXPECT_STREQ("com.example.job.rebooter", LaunchDataGetString(launch_lookup_data)); launch_lookup_data = - LaunchDataDictLookup(launch_data, LAUNCH_JOBKEY_ONDEMAND); + LaunchDataDictLookup(launch_data.get(), LAUNCH_JOBKEY_ONDEMAND); ASSERT_TRUE(launch_lookup_data); ASSERT_EQ(LAUNCH_DATA_BOOL, LaunchDataGetType(launch_lookup_data)); EXPECT_TRUE(LaunchDataGetBool(launch_lookup_data)); launch_lookup_data = - LaunchDataDictLookup(launch_data, LAUNCH_JOBKEY_PROGRAMARGUMENTS); + LaunchDataDictLookup(launch_data.get(), LAUNCH_JOBKEY_PROGRAMARGUMENTS); ASSERT_TRUE(launch_lookup_data); ASSERT_EQ(LAUNCH_DATA_ARRAY, LaunchDataGetType(launch_lookup_data)); EXPECT_EQ(3u, LaunchDataArrayGetCount(launch_lookup_data)); @@ -286,7 +290,7 @@ EXPECT_STREQ("/sbin/reboot", LaunchDataGetString(launch_sublookup_data)); launch_lookup_data = - LaunchDataDictLookup(launch_data, LAUNCH_JOBKEY_MACHSERVICES); + LaunchDataDictLookup(launch_data.get(), LAUNCH_JOBKEY_MACHSERVICES); ASSERT_TRUE(launch_lookup_data); ASSERT_EQ(LAUNCH_DATA_DICTIONARY, LaunchDataGetType(launch_lookup_data)); EXPECT_EQ(1u, LaunchDataDictGetCount(launch_lookup_data));
diff --git a/third_party/crashpad/crashpad/util/mac/mac_util.cc b/third_party/crashpad/crashpad/util/mac/mac_util.cc index a2e8651a..a792e51 100644 --- a/third_party/crashpad/crashpad/util/mac/mac_util.cc +++ b/third_party/crashpad/crashpad/util/mac/mac_util.cc
@@ -16,7 +16,6 @@ #include <CoreFoundation/CoreFoundation.h> #include <IOKit/IOKitLib.h> -#include <stddef.h> #include <string.h> #include <sys/types.h> #include <sys/utsname.h>
diff --git a/third_party/crashpad/crashpad/util/mac/xattr.cc b/third_party/crashpad/crashpad/util/mac/xattr.cc index bdd2f80..36dfda8 100644 --- a/third_party/crashpad/crashpad/util/mac/xattr.cc +++ b/third_party/crashpad/crashpad/util/mac/xattr.cc
@@ -15,11 +15,12 @@ #include "util/mac/xattr.h" #include <errno.h> -#include <stddef.h> #include <stdint.h> +#include <sys/types.h> #include <sys/xattr.h> #include "base/logging.h" +#include "base/macros.h" #include "base/numerics/safe_conversions.h" #include "base/strings/string_number_conversions.h" #include "base/strings/stringprintf.h"
diff --git a/third_party/crashpad/crashpad/util/mach/child_port_handshake.cc b/third_party/crashpad/crashpad/util/mach/child_port_handshake.cc index 74c6fc6..51aad90 100644 --- a/third_party/crashpad/crashpad/util/mach/child_port_handshake.cc +++ b/third_party/crashpad/crashpad/util/mach/child_port_handshake.cc
@@ -29,7 +29,6 @@ #include "base/logging.h" #include "base/mac/mach_logging.h" #include "base/mac/scoped_mach_port.h" -#include "base/macros.h" #include "base/posix/eintr_wrapper.h" #include "base/rand_util.h" #include "base/strings/stringprintf.h"
diff --git a/third_party/crashpad/crashpad/util/mach/child_port_handshake_test.cc b/third_party/crashpad/crashpad/util/mach/child_port_handshake_test.cc index fedf138..f77107b5 100644 --- a/third_party/crashpad/crashpad/util/mach/child_port_handshake_test.cc +++ b/third_party/crashpad/crashpad/util/mach/child_port_handshake_test.cc
@@ -15,7 +15,6 @@ #include "util/mach/child_port_handshake.h" #include "base/mac/scoped_mach_port.h" -#include "base/macros.h" #include "gtest/gtest.h" #include "test/multiprocess.h" #include "util/mach/child_port_types.h"
diff --git a/third_party/crashpad/crashpad/util/mach/child_port_server.cc b/third_party/crashpad/crashpad/util/mach/child_port_server.cc index 40aae8a..4fc723a 100644 --- a/third_party/crashpad/crashpad/util/mach/child_port_server.cc +++ b/third_party/crashpad/crashpad/util/mach/child_port_server.cc
@@ -15,7 +15,6 @@ #include "util/mach/child_port_server.h" #include "base/logging.h" -#include "base/macros.h" #include "util/mach/child_portServer.h" #include "util/mach/mach_message.h"
diff --git a/third_party/crashpad/crashpad/util/mach/child_port_server.h b/third_party/crashpad/crashpad/util/mach/child_port_server.h index 867238c1..b82e99a 100644 --- a/third_party/crashpad/crashpad/util/mach/child_port_server.h +++ b/third_party/crashpad/crashpad/util/mach/child_port_server.h
@@ -16,7 +16,6 @@ #define CRASHPAD_UTIL_MACH_CHILD_PORT_SERVER_H_ #include <mach/mach.h> -#include <stddef.h> #include <set>
diff --git a/third_party/crashpad/crashpad/util/mach/composite_mach_message_server.h b/third_party/crashpad/crashpad/util/mach/composite_mach_message_server.h index e386fce9..fe3446e 100644 --- a/third_party/crashpad/crashpad/util/mach/composite_mach_message_server.h +++ b/third_party/crashpad/crashpad/util/mach/composite_mach_message_server.h
@@ -16,7 +16,6 @@ #define CRASHPAD_UTIL_MACH_COMPOSITE_MACH_MESSAGE_SERVER_H_ #include <mach/mach.h> -#include <stddef.h> #include <map> #include <set>
diff --git a/third_party/crashpad/crashpad/util/mach/composite_mach_message_server_test.cc b/third_party/crashpad/crashpad/util/mach/composite_mach_message_server_test.cc index a4d713f..11984da 100644 --- a/third_party/crashpad/crashpad/util/mach/composite_mach_message_server_test.cc +++ b/third_party/crashpad/crashpad/util/mach/composite_mach_message_server_test.cc
@@ -14,9 +14,8 @@ #include "util/mach/composite_mach_message_server.h" -#include <stddef.h> +#include <sys/types.h> -#include "base/macros.h" #include "base/strings/stringprintf.h" #include "gtest/gtest.h" #include "test/gtest_death_check.h"
diff --git a/third_party/crashpad/crashpad/util/mach/exc_client_variants.cc b/third_party/crashpad/crashpad/util/mach/exc_client_variants.cc index 93f7005..e7945b22 100644 --- a/third_party/crashpad/crashpad/util/mach/exc_client_variants.cc +++ b/third_party/crashpad/crashpad/util/mach/exc_client_variants.cc
@@ -14,7 +14,7 @@ #include "util/mach/exc_client_variants.h" -#include <stddef.h> +#include <sys/types.h> #include <vector>
diff --git a/third_party/crashpad/crashpad/util/mach/exc_client_variants_test.cc b/third_party/crashpad/crashpad/util/mach/exc_client_variants_test.cc index 3de94d1..ca3101c 100644 --- a/third_party/crashpad/crashpad/util/mach/exc_client_variants_test.cc +++ b/third_party/crashpad/crashpad/util/mach/exc_client_variants_test.cc
@@ -16,8 +16,8 @@ #include <mach/mach.h> #include <pthread.h> -#include <stddef.h> #include <string.h> +#include <sys/types.h> #include "base/macros.h" #include "base/strings/stringprintf.h"
diff --git a/third_party/crashpad/crashpad/util/mach/exc_server_variants.cc b/third_party/crashpad/crashpad/util/mach/exc_server_variants.cc index 7b1f5324..209c45ef 100644 --- a/third_party/crashpad/crashpad/util/mach/exc_server_variants.cc +++ b/third_party/crashpad/crashpad/util/mach/exc_server_variants.cc
@@ -21,7 +21,6 @@ #include <vector> #include "base/logging.h" -#include "base/macros.h" #include "util/mac/mac_util.h" #include "util/mach/composite_mach_message_server.h" #include "util/mach/exc.h"
diff --git a/third_party/crashpad/crashpad/util/mach/exc_server_variants.h b/third_party/crashpad/crashpad/util/mach/exc_server_variants.h index 5cfc9c6..c80233c 100644 --- a/third_party/crashpad/crashpad/util/mach/exc_server_variants.h +++ b/third_party/crashpad/crashpad/util/mach/exc_server_variants.h
@@ -16,7 +16,6 @@ #define CRASHPAD_UTIL_MACH_EXC_SERVER_VARIANTS_H_ #include <mach/mach.h> -#include <stddef.h> #include <set>
diff --git a/third_party/crashpad/crashpad/util/mach/exc_server_variants_test.cc b/third_party/crashpad/crashpad/util/mach/exc_server_variants_test.cc index be3b3d04..1a24e69 100644 --- a/third_party/crashpad/crashpad/util/mach/exc_server_variants_test.cc +++ b/third_party/crashpad/crashpad/util/mach/exc_server_variants_test.cc
@@ -15,11 +15,10 @@ #include "util/mach/exc_server_variants.h" #include <mach/mach.h> -#include <stddef.h> #include <stdint.h> #include <string.h> +#include <sys/types.h> -#include "base/macros.h" #include "base/strings/stringprintf.h" #include "build/build_config.h" #include "gmock/gmock.h"
diff --git a/third_party/crashpad/crashpad/util/mach/exception_behaviors_test.cc b/third_party/crashpad/crashpad/util/mach/exception_behaviors_test.cc index 07ae297..a4a55e2 100644 --- a/third_party/crashpad/crashpad/util/mach/exception_behaviors_test.cc +++ b/third_party/crashpad/crashpad/util/mach/exception_behaviors_test.cc
@@ -14,7 +14,7 @@ #include "util/mach/exception_behaviors.h" -#include <stddef.h> +#include <sys/types.h> #include "base/macros.h" #include "base/strings/stringprintf.h"
diff --git a/third_party/crashpad/crashpad/util/mach/exception_ports.h b/third_party/crashpad/crashpad/util/mach/exception_ports.h index 86197ce..b2473d98 100644 --- a/third_party/crashpad/crashpad/util/mach/exception_ports.h +++ b/third_party/crashpad/crashpad/util/mach/exception_ports.h
@@ -16,7 +16,6 @@ #define CRASHPAD_UTIL_MACH_EXCEPTION_PORTS_H_ #include <mach/mach.h> -#include <stddef.h> #include <vector>
diff --git a/third_party/crashpad/crashpad/util/mach/exception_types_test.cc b/third_party/crashpad/crashpad/util/mach/exception_types_test.cc index 5d7314e..372b57f0 100644 --- a/third_party/crashpad/crashpad/util/mach/exception_types_test.cc +++ b/third_party/crashpad/crashpad/util/mach/exception_types_test.cc
@@ -16,7 +16,6 @@ #include <kern/exc_resource.h> #include <signal.h> -#include <stddef.h> #include <stdint.h> #include <sys/types.h> #include <unistd.h>
diff --git a/third_party/crashpad/crashpad/util/mach/mach_message.h b/third_party/crashpad/crashpad/util/mach/mach_message.h index d07996e..2fd8151 100644 --- a/third_party/crashpad/crashpad/util/mach/mach_message.h +++ b/third_party/crashpad/crashpad/util/mach/mach_message.h
@@ -16,7 +16,6 @@ #define CRASHPAD_UTIL_MACH_MACH_MESSAGE_H_ #include <mach/mach.h> -#include <stddef.h> #include <stdint.h> #include <sys/types.h>
diff --git a/third_party/crashpad/crashpad/util/mach/mach_message_server.cc b/third_party/crashpad/crashpad/util/mach/mach_message_server.cc index 131f7c1..0af1901 100644 --- a/third_party/crashpad/crashpad/util/mach/mach_message_server.cc +++ b/third_party/crashpad/crashpad/util/mach/mach_message_server.cc
@@ -21,7 +21,6 @@ #include "base/logging.h" #include "base/mac/mach_logging.h" #include "base/mac/scoped_mach_vm.h" -#include "base/macros.h" #include "util/mach/mach_message.h" namespace crashpad {
diff --git a/third_party/crashpad/crashpad/util/mach/mach_message_server.h b/third_party/crashpad/crashpad/util/mach/mach_message_server.h index 0f27019f..9793560 100644 --- a/third_party/crashpad/crashpad/util/mach/mach_message_server.h +++ b/third_party/crashpad/crashpad/util/mach/mach_message_server.h
@@ -16,7 +16,6 @@ #define CRASHPAD_UTIL_MACH_MACH_MESSAGE_SERVER_H_ #include <mach/mach.h> -#include <stddef.h> #include <set>
diff --git a/third_party/crashpad/crashpad/util/mach/mach_message_server_test.cc b/third_party/crashpad/crashpad/util/mach/mach_message_server_test.cc index 004cbf3..fc45e26 100644 --- a/third_party/crashpad/crashpad/util/mach/mach_message_server_test.cc +++ b/third_party/crashpad/crashpad/util/mach/mach_message_server_test.cc
@@ -15,9 +15,9 @@ #include "util/mach/mach_message_server.h" #include <mach/mach.h> -#include <stddef.h> #include <stdint.h> #include <string.h> +#include <sys/types.h> #include <set>
diff --git a/third_party/crashpad/crashpad/util/mach/mach_message_test.cc b/third_party/crashpad/crashpad/util/mach/mach_message_test.cc index 8f6db7af..3e64601 100644 --- a/third_party/crashpad/crashpad/util/mach/mach_message_test.cc +++ b/third_party/crashpad/crashpad/util/mach/mach_message_test.cc
@@ -14,7 +14,6 @@ #include "util/mach/mach_message.h" -#include <stdint.h> #include <unistd.h> #include "base/mac/scoped_mach_port.h"
diff --git a/third_party/crashpad/crashpad/util/mach/notify_server.cc b/third_party/crashpad/crashpad/util/mach/notify_server.cc index da1d2c81..9ac377d1 100644 --- a/third_party/crashpad/crashpad/util/mach/notify_server.cc +++ b/third_party/crashpad/crashpad/util/mach/notify_server.cc
@@ -15,7 +15,6 @@ #include "util/mach/notify_server.h" #include "base/logging.h" -#include "base/macros.h" #include "util/mach/mach_message.h" #include "util/mach/notifyServer.h"
diff --git a/third_party/crashpad/crashpad/util/mach/notify_server.h b/third_party/crashpad/crashpad/util/mach/notify_server.h index 3be0bcd..ad0a888 100644 --- a/third_party/crashpad/crashpad/util/mach/notify_server.h +++ b/third_party/crashpad/crashpad/util/mach/notify_server.h
@@ -16,7 +16,6 @@ #define CRASHPAD_UTIL_MACH_NOTIFY_SERVER_H_ #include <mach/mach.h> -#include <stddef.h> #include <set>
diff --git a/third_party/crashpad/crashpad/util/mach/notify_server_test.cc b/third_party/crashpad/crashpad/util/mach/notify_server_test.cc index 3659f8b..445e35b 100644 --- a/third_party/crashpad/crashpad/util/mach/notify_server_test.cc +++ b/third_party/crashpad/crashpad/util/mach/notify_server_test.cc
@@ -16,7 +16,6 @@ #include "base/compiler_specific.h" #include "base/mac/scoped_mach_port.h" -#include "base/macros.h" #include "gmock/gmock.h" #include "gtest/gtest.h" #include "test/mac/mach_errors.h"
diff --git a/third_party/crashpad/crashpad/util/mach/scoped_task_suspend_test.cc b/third_party/crashpad/crashpad/util/mach/scoped_task_suspend_test.cc index 0263b19..b53b83d 100644 --- a/third_party/crashpad/crashpad/util/mach/scoped_task_suspend_test.cc +++ b/third_party/crashpad/crashpad/util/mach/scoped_task_suspend_test.cc
@@ -16,7 +16,6 @@ #include <mach/mach.h> -#include "base/macros.h" #include "gtest/gtest.h" #include "test/mac/mach_errors.h" #include "test/mac/mach_multiprocess.h"
diff --git a/third_party/crashpad/crashpad/util/mach/symbolic_constants_mach.cc b/third_party/crashpad/crashpad/util/mach/symbolic_constants_mach.cc index 9ff1bc5..26cc564f 100644 --- a/third_party/crashpad/crashpad/util/mach/symbolic_constants_mach.cc +++ b/third_party/crashpad/crashpad/util/mach/symbolic_constants_mach.cc
@@ -14,8 +14,8 @@ #include "util/mach/symbolic_constants_mach.h" -#include <stddef.h> #include <string.h> +#include <sys/types.h> #include "base/macros.h" #include "base/strings/stringprintf.h"
diff --git a/third_party/crashpad/crashpad/util/mach/symbolic_constants_mach_test.cc b/third_party/crashpad/crashpad/util/mach/symbolic_constants_mach_test.cc index 6d36389..feb409b 100644 --- a/third_party/crashpad/crashpad/util/mach/symbolic_constants_mach_test.cc +++ b/third_party/crashpad/crashpad/util/mach/symbolic_constants_mach_test.cc
@@ -15,8 +15,8 @@ #include "util/mach/symbolic_constants_mach.h" #include <mach/mach.h> -#include <stddef.h> #include <string.h> +#include <sys/types.h> #include "base/macros.h" #include "base/strings/string_piece.h"
diff --git a/third_party/crashpad/crashpad/util/mach/task_memory.h b/third_party/crashpad/crashpad/util/mach/task_memory.h index 731ff97..086b0b99 100644 --- a/third_party/crashpad/crashpad/util/mach/task_memory.h +++ b/third_party/crashpad/crashpad/util/mach/task_memory.h
@@ -16,7 +16,7 @@ #define CRASHPAD_UTIL_MACH_TASK_MEMORY_H_ #include <mach/mach.h> -#include <stddef.h> +#include <sys/types.h> #include <string>
diff --git a/third_party/crashpad/crashpad/util/mach/task_memory_test.cc b/third_party/crashpad/crashpad/util/mach/task_memory_test.cc index 1ebe3e8..963bc4d 100644 --- a/third_party/crashpad/crashpad/util/mach/task_memory_test.cc +++ b/third_party/crashpad/crashpad/util/mach/task_memory_test.cc
@@ -15,7 +15,6 @@ #include "util/mach/task_memory.h" #include <mach/mach.h> -#include <stddef.h> #include <string.h> #include <algorithm> @@ -23,7 +22,6 @@ #include "base/mac/scoped_mach_port.h" #include "base/mac/scoped_mach_vm.h" -#include "base/macros.h" #include "base/memory/scoped_ptr.h" #include "gtest/gtest.h" #include "test/mac/mach_errors.h"
diff --git a/third_party/crashpad/crashpad/util/misc/clock_mac.cc b/third_party/crashpad/crashpad/util/misc/clock_mac.cc index a7b9fc1..bb52299e 100644 --- a/third_party/crashpad/crashpad/util/misc/clock_mac.cc +++ b/third_party/crashpad/crashpad/util/misc/clock_mac.cc
@@ -15,7 +15,6 @@ #include "util/misc/clock.h" #include <mach/mach_time.h> -#include <stdint.h> #include "base/mac/mach_logging.h"
diff --git a/third_party/crashpad/crashpad/util/misc/clock_posix.cc b/third_party/crashpad/crashpad/util/misc/clock_posix.cc index e7c0acf..2417109 100644 --- a/third_party/crashpad/crashpad/util/misc/clock_posix.cc +++ b/third_party/crashpad/crashpad/util/misc/clock_posix.cc
@@ -14,7 +14,6 @@ #include "util/misc/clock.h" -#include <stdint.h> #include <time.h> #include "base/logging.h"
diff --git a/third_party/crashpad/crashpad/util/misc/clock_test.cc b/third_party/crashpad/crashpad/util/misc/clock_test.cc index 4f81aa7..c6e2c02a 100644 --- a/third_party/crashpad/crashpad/util/misc/clock_test.cc +++ b/third_party/crashpad/crashpad/util/misc/clock_test.cc
@@ -14,15 +14,14 @@ #include "util/misc/clock.h" -#include <stddef.h> #include <stdint.h> +#include <sys/types.h> #include <algorithm> #include "base/logging.h" #include "base/macros.h" #include "base/strings/stringprintf.h" -#include "build/build_config.h" #include "gtest/gtest.h" namespace crashpad {
diff --git a/third_party/crashpad/crashpad/util/misc/clock_win.cc b/third_party/crashpad/crashpad/util/misc/clock_win.cc index b1f99d8..2de7ae7 100644 --- a/third_party/crashpad/crashpad/util/misc/clock_win.cc +++ b/third_party/crashpad/crashpad/util/misc/clock_win.cc
@@ -15,7 +15,6 @@ #include "util/misc/clock.h" #include <windows.h> -#include <stdint.h> #include <sys/types.h> namespace {
diff --git a/third_party/crashpad/crashpad/util/misc/random_string_test.cc b/third_party/crashpad/crashpad/util/misc/random_string_test.cc index 29bc61a..bb05a2bd 100644 --- a/third_party/crashpad/crashpad/util/misc/random_string_test.cc +++ b/third_party/crashpad/crashpad/util/misc/random_string_test.cc
@@ -14,7 +14,7 @@ #include "util/misc/random_string.h" -#include <stddef.h> +#include <sys/types.h> #include <set>
diff --git a/third_party/crashpad/crashpad/util/misc/uuid.cc b/third_party/crashpad/crashpad/util/misc/uuid.cc index e1c8556..9ef55a6 100644 --- a/third_party/crashpad/crashpad/util/misc/uuid.cc +++ b/third_party/crashpad/crashpad/util/misc/uuid.cc
@@ -26,7 +26,6 @@ #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "base/sys_byteorder.h" -#include "build/build_config.h" #include "util/stdlib/cxx.h" #if defined(OS_MACOSX)
diff --git a/third_party/crashpad/crashpad/util/misc/uuid_test.cc b/third_party/crashpad/crashpad/util/misc/uuid_test.cc index 86d198d..673cedc 100644 --- a/third_party/crashpad/crashpad/util/misc/uuid_test.cc +++ b/third_party/crashpad/crashpad/util/misc/uuid_test.cc
@@ -14,9 +14,8 @@ #include "util/misc/uuid.h" -#include <stddef.h> -#include <stdint.h> #include <string.h> +#include <sys/types.h> #include <string> @@ -24,7 +23,6 @@ #include "base/macros.h" #include "base/scoped_generic.h" #include "base/strings/stringprintf.h" -#include "build/build_config.h" #include "gtest/gtest.h" namespace crashpad {
diff --git a/third_party/crashpad/crashpad/util/net/http_body.h b/third_party/crashpad/crashpad/util/net/http_body.h index 698d898..4fca573c 100644 --- a/third_party/crashpad/crashpad/util/net/http_body.h +++ b/third_party/crashpad/crashpad/util/net/http_body.h
@@ -15,7 +15,6 @@ #ifndef CRASHPAD_UTIL_NET_HTTP_BODY_H_ #define CRASHPAD_UTIL_NET_HTTP_BODY_H_ -#include <stddef.h> #include <stdint.h> #include <sys/types.h>
diff --git a/third_party/crashpad/crashpad/util/net/http_body_test.cc b/third_party/crashpad/crashpad/util/net/http_body_test.cc index 3f4ad50..eb67f10 100644 --- a/third_party/crashpad/crashpad/util/net/http_body_test.cc +++ b/third_party/crashpad/crashpad/util/net/http_body_test.cc
@@ -14,8 +14,6 @@ #include "util/net/http_body.h" -#include <stddef.h> -#include <stdint.h> #include <string.h> #include "gtest/gtest.h"
diff --git a/third_party/crashpad/crashpad/util/net/http_body_test_util.h b/third_party/crashpad/crashpad/util/net/http_body_test_util.h index 98fa3d93..288fcca 100644 --- a/third_party/crashpad/crashpad/util/net/http_body_test_util.h +++ b/third_party/crashpad/crashpad/util/net/http_body_test_util.h
@@ -15,7 +15,6 @@ #ifndef CRASHPAD_UTIL_NET_HTTP_BODY_TEST_UTIL_H_ #define CRASHPAD_UTIL_NET_HTTP_BODY_TEST_UTIL_H_ -#include <stddef.h> #include <sys/types.h> #include <string>
diff --git a/third_party/crashpad/crashpad/util/net/http_multipart_builder.cc b/third_party/crashpad/crashpad/util/net/http_multipart_builder.cc index 90fae9cd..f4218569 100644 --- a/third_party/crashpad/crashpad/util/net/http_multipart_builder.cc +++ b/third_party/crashpad/crashpad/util/net/http_multipart_builder.cc
@@ -14,7 +14,7 @@ #include "util/net/http_multipart_builder.h" -#include <stddef.h> +#include <sys/types.h> #include <utility> #include <vector>
diff --git a/third_party/crashpad/crashpad/util/net/http_multipart_builder_test.cc b/third_party/crashpad/crashpad/util/net/http_multipart_builder_test.cc index 76fdec6..6670225 100644 --- a/third_party/crashpad/crashpad/util/net/http_multipart_builder_test.cc +++ b/third_party/crashpad/crashpad/util/net/http_multipart_builder_test.cc
@@ -14,7 +14,7 @@ #include "util/net/http_multipart_builder.h" -#include <stddef.h> +#include <sys/types.h> #include <vector>
diff --git a/third_party/crashpad/crashpad/util/net/http_transport_mac.mm b/third_party/crashpad/crashpad/util/net/http_transport_mac.mm index 3657a9a5..aad505d 100644 --- a/third_party/crashpad/crashpad/util/net/http_transport_mac.mm +++ b/third_party/crashpad/crashpad/util/net/http_transport_mac.mm
@@ -19,7 +19,6 @@ #include "base/mac/foundation_util.h" #import "base/mac/scoped_nsobject.h" -#include "base/macros.h" #include "base/strings/stringprintf.h" #include "base/strings/sys_string_conversions.h" #include "third_party/apple_cf/CFStreamAbstract.h"
diff --git a/third_party/crashpad/crashpad/util/net/http_transport_test.cc b/third_party/crashpad/crashpad/util/net/http_transport_test.cc index 09c8be07..d015a5a 100644 --- a/third_party/crashpad/crashpad/util/net/http_transport_test.cc +++ b/third_party/crashpad/crashpad/util/net/http_transport_test.cc
@@ -14,10 +14,10 @@ #include "util/net/http_transport.h" -#include <stddef.h> #include <stdint.h> #include <stdlib.h> #include <string.h> +#include <sys/types.h> #include <utility> #include <vector>
diff --git a/third_party/crashpad/crashpad/util/net/http_transport_win.cc b/third_party/crashpad/crashpad/util/net/http_transport_win.cc index 8adffbe..95308ca 100644 --- a/third_party/crashpad/crashpad/util/net/http_transport_win.cc +++ b/third_party/crashpad/crashpad/util/net/http_transport_win.cc
@@ -15,12 +15,11 @@ #include "util/net/http_transport.h" #include <windows.h> -#include <stddef.h> #include <stdint.h> +#include <sys/types.h> #include <winhttp.h> #include "base/logging.h" -#include "base/macros.h" #include "base/numerics/safe_conversions.h" #include "base/scoped_generic.h" #include "base/strings/stringprintf.h"
diff --git a/third_party/crashpad/crashpad/util/numeric/checked_address_range.cc b/third_party/crashpad/crashpad/util/numeric/checked_address_range.cc index bdd0f15..1d50696 100644 --- a/third_party/crashpad/crashpad/util/numeric/checked_address_range.cc +++ b/third_party/crashpad/crashpad/util/numeric/checked_address_range.cc
@@ -14,10 +14,7 @@ #include "util/numeric/checked_address_range.h" -#include <stddef.h> - #include "base/strings/stringprintf.h" -#include "build/build_config.h" #if defined(OS_MACOSX) #include <mach/mach.h>
diff --git a/third_party/crashpad/crashpad/util/numeric/checked_address_range_test.cc b/third_party/crashpad/crashpad/util/numeric/checked_address_range_test.cc index 22ed136..6b7e4c43 100644 --- a/third_party/crashpad/crashpad/util/numeric/checked_address_range_test.cc +++ b/third_party/crashpad/crashpad/util/numeric/checked_address_range_test.cc
@@ -14,8 +14,7 @@ #include "util/numeric/checked_address_range.h" -#include <stddef.h> -#include <stdint.h> +#include <sys/types.h> #include <limits>
diff --git a/third_party/crashpad/crashpad/util/numeric/checked_range_test.cc b/third_party/crashpad/crashpad/util/numeric/checked_range_test.cc index 1efceff..0b1ea32 100644 --- a/third_party/crashpad/crashpad/util/numeric/checked_range_test.cc +++ b/third_party/crashpad/crashpad/util/numeric/checked_range_test.cc
@@ -14,8 +14,8 @@ #include "util/numeric/checked_range.h" -#include <stddef.h> #include <stdint.h> +#include <sys/types.h> #include <limits>
diff --git a/third_party/crashpad/crashpad/util/numeric/int128_test.cc b/third_party/crashpad/crashpad/util/numeric/int128_test.cc index 24b4a790..c0ad74e 100644 --- a/third_party/crashpad/crashpad/util/numeric/int128_test.cc +++ b/third_party/crashpad/crashpad/util/numeric/int128_test.cc
@@ -14,10 +14,7 @@ #include "util/numeric/int128.h" -#include <stdint.h> - #include "base/macros.h" -#include "build/build_config.h" #include "gtest/gtest.h" namespace crashpad {
diff --git a/third_party/crashpad/crashpad/util/posix/process_info_mac.cc b/third_party/crashpad/crashpad/util/posix/process_info_mac.cc index 90a74cb8..17d205a 100644 --- a/third_party/crashpad/crashpad/util/posix/process_info_mac.cc +++ b/third_party/crashpad/crashpad/util/posix/process_info_mac.cc
@@ -14,12 +14,10 @@ #include "util/posix/process_info.h" -#include <stddef.h> #include <string.h> #include "base/logging.h" #include "base/mac/mach_logging.h" -#include "base/macros.h" namespace crashpad {
diff --git a/third_party/crashpad/crashpad/util/posix/process_info_test.cc b/third_party/crashpad/crashpad/util/posix/process_info_test.cc index a5a90be..dd0844b 100644 --- a/third_party/crashpad/crashpad/util/posix/process_info_test.cc +++ b/third_party/crashpad/crashpad/util/posix/process_info_test.cc
@@ -14,7 +14,6 @@ #include "util/posix/process_info.h" -#include <stddef.h> #include <time.h> #include <unistd.h>
diff --git a/third_party/crashpad/crashpad/util/posix/symbolic_constants_posix.cc b/third_party/crashpad/crashpad/util/posix/symbolic_constants_posix.cc index b8ea0d5..c952e82 100644 --- a/third_party/crashpad/crashpad/util/posix/symbolic_constants_posix.cc +++ b/third_party/crashpad/crashpad/util/posix/symbolic_constants_posix.cc
@@ -14,8 +14,8 @@ #include "util/posix/symbolic_constants_posix.h" -#include <stddef.h> #include <string.h> +#include <sys/types.h> #include <sys/signal.h> #include "base/macros.h"
diff --git a/third_party/crashpad/crashpad/util/posix/symbolic_constants_posix_test.cc b/third_party/crashpad/crashpad/util/posix/symbolic_constants_posix_test.cc index 6a157a7f..72e37bd 100644 --- a/third_party/crashpad/crashpad/util/posix/symbolic_constants_posix_test.cc +++ b/third_party/crashpad/crashpad/util/posix/symbolic_constants_posix_test.cc
@@ -14,8 +14,8 @@ #include "util/posix/symbolic_constants_posix.h" -#include <stddef.h> #include <sys/signal.h> +#include <sys/types.h> #include "base/macros.h" #include "base/strings/string_piece.h"
diff --git a/third_party/crashpad/crashpad/util/stdlib/aligned_allocator_test.cc b/third_party/crashpad/crashpad/util/stdlib/aligned_allocator_test.cc index ef5235d..fe3b9e6 100644 --- a/third_party/crashpad/crashpad/util/stdlib/aligned_allocator_test.cc +++ b/third_party/crashpad/crashpad/util/stdlib/aligned_allocator_test.cc
@@ -14,10 +14,8 @@ #include "util/stdlib/aligned_allocator.h" -#include <stddef.h> #include <stdint.h> -#include "build/build_config.h" #include "gtest/gtest.h" #if defined(OS_WIN)
diff --git a/third_party/crashpad/crashpad/util/stdlib/string_number_conversion_test.cc b/third_party/crashpad/crashpad/util/stdlib/string_number_conversion_test.cc index 081b922..6fe6f81 100644 --- a/third_party/crashpad/crashpad/util/stdlib/string_number_conversion_test.cc +++ b/third_party/crashpad/crashpad/util/stdlib/string_number_conversion_test.cc
@@ -14,7 +14,7 @@ #include "util/stdlib/string_number_conversion.h" -#include <stddef.h> +#include <sys/types.h> #include <limits>
diff --git a/third_party/crashpad/crashpad/util/stdlib/strlcpy.h b/third_party/crashpad/crashpad/util/stdlib/strlcpy.h index 6235ead..20e1a718 100644 --- a/third_party/crashpad/crashpad/util/stdlib/strlcpy.h +++ b/third_party/crashpad/crashpad/util/stdlib/strlcpy.h
@@ -15,8 +15,7 @@ #ifndef CRASHPAD_UTIL_STDLIB_STRLCPY_H_ #define CRASHPAD_UTIL_STDLIB_STRLCPY_H_ -#include <stddef.h> -#include <stdint.h> +#include <sys/types.h> #include "base/strings/string16.h"
diff --git a/third_party/crashpad/crashpad/util/stdlib/strlcpy_test.cc b/third_party/crashpad/crashpad/util/stdlib/strlcpy_test.cc index d666c048..cbc61c0 100644 --- a/third_party/crashpad/crashpad/util/stdlib/strlcpy_test.cc +++ b/third_party/crashpad/crashpad/util/stdlib/strlcpy_test.cc
@@ -14,7 +14,6 @@ #include "util/stdlib/strlcpy.h" -#include <stddef.h> #include <string.h> #include <algorithm>
diff --git a/third_party/crashpad/crashpad/util/stdlib/strnlen.cc b/third_party/crashpad/crashpad/util/stdlib/strnlen.cc index fccefdc..3016bf63 100644 --- a/third_party/crashpad/crashpad/util/stdlib/strnlen.cc +++ b/third_party/crashpad/crashpad/util/stdlib/strnlen.cc
@@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "build/build_config.h" #include "util/stdlib/strnlen.h" #if defined(OS_MACOSX) && MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_7
diff --git a/third_party/crashpad/crashpad/util/stdlib/strnlen.h b/third_party/crashpad/crashpad/util/stdlib/strnlen.h index 071f10d..e85d8c7 100644 --- a/third_party/crashpad/crashpad/util/stdlib/strnlen.h +++ b/third_party/crashpad/crashpad/util/stdlib/strnlen.h
@@ -15,8 +15,8 @@ #ifndef CRASHPAD_UTIL_STDLIB_STRNLEN_H_ #define CRASHPAD_UTIL_STDLIB_STRNLEN_H_ -#include <stddef.h> #include <string.h> +#include <sys/types.h> #include "build/build_config.h"
diff --git a/third_party/crashpad/crashpad/util/string/split_string.cc b/third_party/crashpad/crashpad/util/string/split_string.cc index 76e7fc8..25048b5 100644 --- a/third_party/crashpad/crashpad/util/string/split_string.cc +++ b/third_party/crashpad/crashpad/util/string/split_string.cc
@@ -12,10 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include <stddef.h> - #include "util/string/split_string.h" +#include <sys/types.h> + namespace crashpad { bool SplitString(const std::string& string,
diff --git a/third_party/crashpad/crashpad/util/synchronization/semaphore_posix.cc b/third_party/crashpad/crashpad/util/synchronization/semaphore_posix.cc index f596648..973f0a5d 100644 --- a/third_party/crashpad/crashpad/util/synchronization/semaphore_posix.cc +++ b/third_party/crashpad/crashpad/util/synchronization/semaphore_posix.cc
@@ -20,7 +20,6 @@ #include "base/logging.h" #include "base/posix/eintr_wrapper.h" -#include "build/build_config.h" namespace crashpad {
diff --git a/third_party/crashpad/crashpad/util/synchronization/semaphore_test.cc b/third_party/crashpad/crashpad/util/synchronization/semaphore_test.cc index 46e872d..5f0563a 100644 --- a/third_party/crashpad/crashpad/util/synchronization/semaphore_test.cc +++ b/third_party/crashpad/crashpad/util/synchronization/semaphore_test.cc
@@ -14,9 +14,8 @@ #include "util/synchronization/semaphore.h" -#include <stddef.h> +#include <sys/types.h> -#include "build/build_config.h" #include "gtest/gtest.h" #if defined(OS_POSIX)
diff --git a/third_party/crashpad/crashpad/util/thread/thread_log_messages.cc b/third_party/crashpad/crashpad/util/thread/thread_log_messages.cc index 8a70beda..7f67e45 100644 --- a/third_party/crashpad/crashpad/util/thread/thread_log_messages.cc +++ b/third_party/crashpad/crashpad/util/thread/thread_log_messages.cc
@@ -14,11 +14,10 @@ #include "util/thread/thread_log_messages.h" -#include <stddef.h> +#include <sys/types.h> #include "base/lazy_instance.h" #include "base/logging.h" -#include "base/macros.h" #include "base/threading/thread_local_storage.h" namespace crashpad {
diff --git a/third_party/crashpad/crashpad/util/thread/thread_log_messages_test.cc b/third_party/crashpad/crashpad/util/thread/thread_log_messages_test.cc index 3f32f33..df5735b5 100644 --- a/third_party/crashpad/crashpad/util/thread/thread_log_messages_test.cc +++ b/third_party/crashpad/crashpad/util/thread/thread_log_messages_test.cc
@@ -14,11 +14,10 @@ #include "util/thread/thread_log_messages.h" -#include <stddef.h> #include <string.h> +#include <sys/types.h> #include "base/logging.h" -#include "base/macros.h" #include "base/strings/stringprintf.h" #include "gtest/gtest.h" #include "util/thread/thread.h"
diff --git a/third_party/crashpad/crashpad/util/thread/worker_thread.cc b/third_party/crashpad/crashpad/util/thread/worker_thread.cc new file mode 100644 index 0000000..595ef8f --- /dev/null +++ b/third_party/crashpad/crashpad/util/thread/worker_thread.cc
@@ -0,0 +1,95 @@ +// Copyright 2015 The Crashpad Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "util/thread/worker_thread.h" + +#include "base/logging.h" +#include "util/synchronization/semaphore.h" +#include "util/thread/thread.h" + +namespace crashpad { + +namespace internal { + +class WorkerThreadImpl final : public Thread { + public: + WorkerThreadImpl(WorkerThread* self, double initial_work_delay) + : semaphore_(0), + initial_work_delay_(initial_work_delay), + self_(self) {} + ~WorkerThreadImpl() {} + + void ThreadMain() override { + if (initial_work_delay_ > 0) + semaphore_.TimedWait(initial_work_delay_); + + while (self_->running_) { + self_->delegate_->DoWork(self_); + semaphore_.TimedWait(self_->work_interval_); + } + } + + void SignalSemaphore() { + semaphore_.Signal(); + } + + private: + // TODO(mark): Use a condition variable instead? + Semaphore semaphore_; + double initial_work_delay_; + WorkerThread* self_; // Weak, owns this. +}; + +} // namespace internal + +WorkerThread::WorkerThread(double work_interval, + WorkerThread::Delegate* delegate) + : work_interval_(work_interval), + delegate_(delegate), + impl_(), + running_(false) {} + +WorkerThread::~WorkerThread() { + DCHECK(!running_); +} + +void WorkerThread::Start(double initial_work_delay) { + DCHECK(!impl_); + DCHECK(!running_); + + running_ = true; + impl_.reset(new internal::WorkerThreadImpl(this, initial_work_delay)); + impl_->Start(); +} + +void WorkerThread::Stop() { + DCHECK(running_); + DCHECK(impl_); + + if (!running_) + return; + + running_ = false; + + impl_->SignalSemaphore(); + impl_->Join(); + impl_.reset(); +} + +void WorkerThread::DoWorkNow() { + DCHECK(running_); + impl_->SignalSemaphore(); +} + +} // namespace crashpad
diff --git a/third_party/crashpad/crashpad/util/thread/worker_thread.h b/third_party/crashpad/crashpad/util/thread/worker_thread.h new file mode 100644 index 0000000..748c99f5 --- /dev/null +++ b/third_party/crashpad/crashpad/util/thread/worker_thread.h
@@ -0,0 +1,93 @@ +// Copyright 2015 The Crashpad Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef CRASHPAD_UTIL_THREAD_WORKER_THREAD_H_ +#define CRASHPAD_UTIL_THREAD_WORKER_THREAD_H_ + +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" + +namespace crashpad { + +namespace internal { +class WorkerThreadImpl; +} // namespace internal + +//! \brief A WorkerThread executes its Delegate's DoWork method repeatedly on a +//! dedicated thread at a set time interval. +class WorkerThread { + public: + //! \brief An interface for doing work on a WorkerThread. + class Delegate { + public: + //! \brief The work function executed by the WorkerThread every work + //! interval. + virtual void DoWork(const WorkerThread* thread) = 0; + + protected: + virtual ~Delegate() {} + }; + + //! \brief Creates a new WorkerThread that is not yet running. + //! + //! \param[in] work_interval The time interval in seconds at which the \a + //! delegate runs. The interval counts from the completion of + //! Delegate::DoWork() to the next invocation. + //! \param[in] delegate The work delegate to invoke every interval. + WorkerThread(double work_interval, Delegate* delegate); + ~WorkerThread(); + + //! \brief Starts the worker thread. + //! + //! This may not be called if the thread is_running(). + //! + //! \param[in] initial_work_delay The amount of time in seconds to wait + //! before invoking the \a delegate for the first time. Pass `0` for + //! no delay. + void Start(double initial_work_delay); + + //! \brief Stops the worker thread from running. + //! + //! This may only be called if the thread is_running(). + //! + //! If the work function is currently executing, this will not interrupt it. + //! This method stops any future work from occurring. This method is safe + //! to call from any thread with the exception of the worker thread itself, + //! as this joins the thread. + void Stop(); + + //! \brief Interrupts a \a work_interval to execute the work function + //! immediately. This invokes Delegate::DoWork() on the thread, without + //! waiting for the current \a work_interval to expire. After the + //! delegate is invoked, the WorkerThread will start waiting for a new + //! \a work_interval. + void DoWorkNow(); + + //! \return `true` if the thread is running, `false` if it is not. + bool is_running() const { return running_; } + + private: + friend class internal::WorkerThreadImpl; + + double work_interval_; + Delegate* delegate_; // weak + scoped_ptr<internal::WorkerThreadImpl> impl_; + bool running_; + + DISALLOW_COPY_AND_ASSIGN(WorkerThread); +}; + +} // namespace crashpad + +#endif // CRASHPAD_UTIL_THREAD_WORKER_THREAD_H_
diff --git a/third_party/crashpad/crashpad/util/thread/worker_thread_test.cc b/third_party/crashpad/crashpad/util/thread/worker_thread_test.cc new file mode 100644 index 0000000..24f0cb3 --- /dev/null +++ b/third_party/crashpad/crashpad/util/thread/worker_thread_test.cc
@@ -0,0 +1,137 @@ +// Copyright 2015 The Crashpad Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "util/thread/worker_thread.h" + +#include "gtest/gtest.h" +#include "util/misc/clock.h" +#include "util/synchronization/semaphore.h" + +namespace crashpad { +namespace test { +namespace { + +const uint64_t kNanosecondsPerSecond = static_cast<uint64_t>(1E9); + +class WorkDelegate : public WorkerThread::Delegate { + public: + WorkDelegate() {} + ~WorkDelegate() {} + + void DoWork(const WorkerThread* thread) override { + if (++work_count_ == waiting_for_count_) + semaphore_.Signal(); + } + + //! \brief Suspends the calling thread until the DoWork() has been called + //! the specified number of times. + void WaitForWorkCount(int times) { + waiting_for_count_ = times; + semaphore_.Wait(); + } + + int work_count() const { return work_count_; } + + private: + Semaphore semaphore_{0}; + int work_count_ = 0; + int waiting_for_count_ = -1; + + DISALLOW_COPY_AND_ASSIGN(WorkDelegate); +}; + +TEST(WorkerThread, DoWork) { + WorkDelegate delegate; + WorkerThread thread(0.05, &delegate); + + uint64_t start = ClockMonotonicNanoseconds(); + thread.Start(0); + EXPECT_TRUE(thread.is_running()); + + delegate.WaitForWorkCount(2); + thread.Stop(); + EXPECT_FALSE(thread.is_running()); + + EXPECT_GE(1 * kNanosecondsPerSecond, ClockMonotonicNanoseconds() - start); +} + +TEST(WorkerThread, StopBeforeDoWork) { + WorkDelegate delegate; + WorkerThread thread(1, &delegate); + + thread.Start(15); + thread.Stop(); + + EXPECT_EQ(0, delegate.work_count()); +} + +TEST(WorkerThread, Restart) { + WorkDelegate delegate; + WorkerThread thread(0.05, &delegate); + + thread.Start(0); + EXPECT_TRUE(thread.is_running()); + + delegate.WaitForWorkCount(1); + thread.Stop(); + ASSERT_FALSE(thread.is_running()); + + thread.Start(0); + delegate.WaitForWorkCount(2); + thread.Stop(); + ASSERT_FALSE(thread.is_running()); +} + +TEST(WorkerThread, DoWorkNow) { + WorkDelegate delegate; + WorkerThread thread(100, &delegate); + + thread.Start(0); + EXPECT_TRUE(thread.is_running()); + + uint64_t start = ClockMonotonicNanoseconds(); + + delegate.WaitForWorkCount(1); + EXPECT_EQ(1, delegate.work_count()); + + thread.DoWorkNow(); + delegate.WaitForWorkCount(2); + thread.Stop(); + EXPECT_EQ(2, delegate.work_count()); + + EXPECT_GE(100 * kNanosecondsPerSecond, ClockMonotonicNanoseconds() - start); +} + +TEST(WorkerThread, DoWorkNowAtStart) { + WorkDelegate delegate; + WorkerThread thread(100, &delegate); + + uint64_t start = ClockMonotonicNanoseconds(); + + thread.Start(100); + EXPECT_TRUE(thread.is_running()); + + thread.DoWorkNow(); + delegate.WaitForWorkCount(1); + EXPECT_EQ(1, delegate.work_count()); + + EXPECT_GE(100 * kNanosecondsPerSecond, ClockMonotonicNanoseconds() - start); + + thread.Stop(); + EXPECT_FALSE(thread.is_running()); +} + +} // namespace +} // namespace test +} // namespace crashpad
diff --git a/third_party/crashpad/crashpad/util/util.gyp b/third_party/crashpad/crashpad/util/util.gyp index 7ef9c4e..6d0090f4 100644 --- a/third_party/crashpad/crashpad/util/util.gyp +++ b/third_party/crashpad/crashpad/util/util.gyp
@@ -152,6 +152,8 @@ 'thread/thread_log_messages.h', 'thread/thread_posix.cc', 'thread/thread_win.cc', + 'thread/worker_thread.cc', + 'thread/worker_thread.h', 'win/address_types.h', 'win/capture_context.asm', 'win/capture_context.h',
diff --git a/third_party/crashpad/crashpad/util/util_test.gyp b/third_party/crashpad/crashpad/util/util_test.gyp index f5adc03..28dab4f7 100644 --- a/third_party/crashpad/crashpad/util/util_test.gyp +++ b/third_party/crashpad/crashpad/util/util_test.gyp
@@ -81,6 +81,7 @@ 'synchronization/semaphore_test.cc', 'thread/thread_log_messages_test.cc', 'thread/thread_test.cc', + 'thread/worker_thread_test.cc', 'win/capture_context_test.cc', 'win/command_line_test.cc', 'win/critical_section_with_debug_info_test.cc',
diff --git a/third_party/crashpad/crashpad/util/win/capture_context_test.cc b/third_party/crashpad/crashpad/util/win/capture_context_test.cc index 19f849f9..72b2587 100644 --- a/third_party/crashpad/crashpad/util/win/capture_context_test.cc +++ b/third_party/crashpad/crashpad/util/win/capture_context_test.cc
@@ -14,8 +14,8 @@ #include "util/win/capture_context.h" -#include <stddef.h> #include <stdint.h> +#include <sys/types.h> #include <algorithm>
diff --git a/third_party/crashpad/crashpad/util/win/command_line.cc b/third_party/crashpad/crashpad/util/win/command_line.cc index 90671b1..930c83c8 100644 --- a/third_party/crashpad/crashpad/util/win/command_line.cc +++ b/third_party/crashpad/crashpad/util/win/command_line.cc
@@ -12,10 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include <stddef.h> - #include "util/win/command_line.h" +#include <sys/types.h> + namespace crashpad { // Ref:
diff --git a/third_party/crashpad/crashpad/util/win/command_line_test.cc b/third_party/crashpad/crashpad/util/win/command_line_test.cc index 16f9a6b..2577d6d 100644 --- a/third_party/crashpad/crashpad/util/win/command_line_test.cc +++ b/third_party/crashpad/crashpad/util/win/command_line_test.cc
@@ -16,7 +16,7 @@ #include <windows.h> #include <shellapi.h> -#include <stddef.h> +#include <sys/types.h> #include "base/logging.h" #include "base/macros.h"
diff --git a/third_party/crashpad/crashpad/util/win/exception_handler_server.cc b/third_party/crashpad/crashpad/util/win/exception_handler_server.cc index 347dc50..39575df 100644 --- a/third_party/crashpad/crashpad/util/win/exception_handler_server.cc +++ b/third_party/crashpad/crashpad/util/win/exception_handler_server.cc
@@ -15,14 +15,13 @@ #include "util/win/exception_handler_server.h" #include <sddl.h> -#include <stddef.h> #include <stdint.h> #include <string.h> +#include <sys/types.h> #include <utility> #include "base/logging.h" -#include "base/macros.h" #include "base/numerics/safe_conversions.h" #include "base/rand_util.h" #include "base/strings/stringprintf.h"
diff --git a/third_party/crashpad/crashpad/util/win/exception_handler_server_test.cc b/third_party/crashpad/crashpad/util/win/exception_handler_server_test.cc index 1dbc64f9..c7f02574 100644 --- a/third_party/crashpad/crashpad/util/win/exception_handler_server_test.cc +++ b/third_party/crashpad/crashpad/util/win/exception_handler_server_test.cc
@@ -15,7 +15,7 @@ #include "util/win/exception_handler_server.h" #include <windows.h> -#include <stddef.h> +#include <sys/types.h> #include <string> #include <vector>
diff --git a/third_party/crashpad/crashpad/util/win/ntstatus_logging.cc b/third_party/crashpad/crashpad/util/win/ntstatus_logging.cc index 4460105..4c243cc 100644 --- a/third_party/crashpad/crashpad/util/win/ntstatus_logging.cc +++ b/third_party/crashpad/crashpad/util/win/ntstatus_logging.cc
@@ -16,7 +16,6 @@ #include <string> -#include "base/macros.h" #include "base/strings/stringprintf.h" namespace {
diff --git a/third_party/crashpad/crashpad/util/win/process_info.cc b/third_party/crashpad/crashpad/util/win/process_info.cc index a9a08a8..5628e04 100644 --- a/third_party/crashpad/crashpad/util/win/process_info.cc +++ b/third_party/crashpad/crashpad/util/win/process_info.cc
@@ -14,7 +14,6 @@ #include "util/win/process_info.h" -#include <stddef.h> #include <winternl.h> #include <algorithm>
diff --git a/third_party/crashpad/crashpad/util/win/process_info.h b/third_party/crashpad/crashpad/util/win/process_info.h index ec53513..0bb8d7356 100644 --- a/third_party/crashpad/crashpad/util/win/process_info.h +++ b/third_party/crashpad/crashpad/util/win/process_info.h
@@ -16,7 +16,6 @@ #define CRASHPAD_UTIL_WIN_PROCESS_INFO_H_ #include <windows.h> -#include <stdint.h> #include <sys/types.h> #include <string>
diff --git a/third_party/crashpad/crashpad/util/win/process_info_test.cc b/third_party/crashpad/crashpad/util/win/process_info_test.cc index 84c4ff3a..7f9b6dac 100644 --- a/third_party/crashpad/crashpad/util/win/process_info_test.cc +++ b/third_party/crashpad/crashpad/util/win/process_info_test.cc
@@ -16,7 +16,6 @@ #include <dbghelp.h> #include <intrin.h> -#include <stddef.h> #include <wchar.h> #include "base/files/file_path.h"
diff --git a/third_party/crashpad/crashpad/util/win/scoped_process_suspend_test.cc b/third_party/crashpad/crashpad/util/win/scoped_process_suspend_test.cc index 585be8ad..5b7813df 100644 --- a/third_party/crashpad/crashpad/util/win/scoped_process_suspend_test.cc +++ b/third_party/crashpad/crashpad/util/win/scoped_process_suspend_test.cc
@@ -19,7 +19,6 @@ #include <algorithm> #include <vector> -#include "base/macros.h" #include "gtest/gtest.h" #include "test/errors.h" #include "test/win/win_child_process.h"
diff --git a/third_party/crashpad/crashpad/util/win/time.cc b/third_party/crashpad/crashpad/util/win/time.cc index ad9f884..4c6fba1 100644 --- a/third_party/crashpad/crashpad/util/win/time.cc +++ b/third_party/crashpad/crashpad/util/win/time.cc
@@ -14,7 +14,6 @@ #include "util/win/time.h" -#include <inttypes.h> #include <stdint.h> #include "base/logging.h"
diff --git a/third_party/crashpad/update.py b/third_party/crashpad/update.py index e861519..cdf30697 100755 --- a/third_party/crashpad/update.py +++ b/third_party/crashpad/update.py
@@ -13,6 +13,9 @@ import textwrap +IS_WINDOWS = sys.platform.startswith('win') + + def SubprocessCheckCall0Or1(args): """Like subprocss.check_call(), but allows a return code of 1. @@ -20,7 +23,7 @@ code 1, and re-raises the subprocess.check_call() exception otherwise. """ try: - subprocess.check_call(args) + subprocess.check_call(args, shell=IS_WINDOWS) except subprocess.CalledProcessError, e: if e.returncode != 1: raise @@ -67,7 +70,8 @@ parsed = parser.parse_args(args) original_head = ( - subprocess.check_output(['git', 'rev-parse', 'HEAD']).rstrip()) + subprocess.check_output(['git', 'rev-parse', 'HEAD'], + shell=IS_WINDOWS).rstrip()) # Read the README, because that’s what it’s for. Extract some things from # it, and save it to be able to update it later. @@ -86,7 +90,8 @@ re.MULTILINE) revision_old = revision_match.group(1) - subprocess.check_call(['git', 'fetch', parsed.repository, parsed.fetch_ref]) + subprocess.check_call(['git', 'fetch', parsed.repository, parsed.fetch_ref], + shell=IS_WINDOWS) # Make sure that parsed.update_to is an ancestor of FETCH_HEAD, and # revision_old is an ancestor of parsed.update_to. This prevents the use of @@ -125,7 +130,7 @@ except: # ^C, signal, or something else. print >>sys.stderr, 'Aborting...' - subprocess.call(['git', 'cherry-pick', '--abort']) + subprocess.call(['git', 'cherry-pick', '--abort'], shell=IS_WINDOWS) raise # Get an abbreviated hash and subject line for each commit in the window, @@ -137,7 +142,8 @@ '--abbrev-commit', '--pretty=oneline', '--reverse', - update_range]).splitlines(False) + update_range], + shell=IS_WINDOWS).splitlines(False) if assisted_cherry_pick: # If the user had to help, count the number of cherry-picked commits, @@ -146,14 +152,14 @@ ['git', 'rev-list', '--count', original_head + '..HEAD'])) if cherry_picked_commits != len(log_lines): print >>sys.stderr, 'Something smells fishy, aborting anyway...' - subprocess.call(['git', 'cherry-pick', '--abort']) + subprocess.call(['git', 'cherry-pick', '--abort'], shell=IS_WINDOWS) raise Exception('not all commits were cherry-picked', len(log_lines), cherry_picked_commits) # Make a nice commit message. Start with the full commit hash. revision_new = subprocess.check_output( - ['git', 'rev-parse', parsed.update_to]).rstrip() + ['git', 'rev-parse', parsed.update_to], shell=IS_WINDOWS).rstrip() new_message = 'Update ' + project_name + ' to ' + revision_new + '\n\n' # Wrap everything to 72 characters, with a hanging indent. @@ -197,14 +203,16 @@ # This soft-reset causes all of the cherry-picks to show up as staged, # which will have the effect of squashing them along with the README update # when committed below. - subprocess.check_call(['git', 'reset', '--soft', original_head]) + subprocess.check_call(['git', 'reset', '--soft', original_head], + shell=IS_WINDOWS) # Write the new README. open(readme_path, 'wb').write(readme_content_new) # Commit everything. - subprocess.check_call(['git', 'add', readme_path]) - subprocess.check_call(['git', 'commit', '--message=' + new_message]) + subprocess.check_call(['git', 'add', readme_path], shell=IS_WINDOWS) + subprocess.check_call(['git', 'commit', '--message=' + new_message], + shell=IS_WINDOWS) if has_local_modifications: print >>sys.stderr, (
diff --git a/third_party/custom_tabs_client/BUILD.gn b/third_party/custom_tabs_client/BUILD.gn index 443424c1..cb553cf 100644 --- a/third_party/custom_tabs_client/BUILD.gn +++ b/third_party/custom_tabs_client/BUILD.gn
@@ -33,7 +33,7 @@ android_library("custom_tabs_support_lib") { DEPRECATED_java_in_dir = "src/customtabs/src" deps = [ - "//third_party/android_tools:android_support_annotations_javalib", + "//third_party/android_tools:android_support_v13_java", ] srcjar_deps = [ ":chrome_custom_tabs_service_aidl" ] }
diff --git a/third_party/custom_tabs_client/custom_tabs_client.gyp b/third_party/custom_tabs_client/custom_tabs_client.gyp index 20d15cf..1ac57c8 100644 --- a/third_party/custom_tabs_client/custom_tabs_client.gyp +++ b/third_party/custom_tabs_client/custom_tabs_client.gyp
@@ -41,7 +41,7 @@ }, 'dependencies': [ 'chrome_custom_tabs_service_aidl', - '../android_tools/android_tools.gyp:android_support_annotations_javalib', + '../android_tools/android_tools.gyp:android_support_v13_javalib', ], 'includes': [ '../../build/java.gypi' ], },
diff --git a/third_party/kasko/BUILD.gn b/third_party/kasko/BUILD.gn new file mode 100644 index 0000000..bedcb1d --- /dev/null +++ b/third_party/kasko/BUILD.gn
@@ -0,0 +1,55 @@ +# 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/sanitizers/sanitizers.gni") + +declare_args() { + # Enable the Kasko crash reporter. Enabled by default on syzyasan build. + enable_kasko = is_syzyasan + + # Enable the reporting of browser hangs with Kasko. + enable_kasko_hang_reports = false +} + +if (enable_kasko) { + assert(is_win, "Kasko only support Windows.") + assert(target_cpu == "x86", "Kasko only support 32 bits.") + assert(is_chrome_branded, + "The Kasko client is only initialized in Chrome-branded builds.") + + config("kasko_config") { + visibility = [ ":*" ] + defines = [ "KASKO" ] + if (enable_kasko_hang_reports) { + defines += [ "KASKO_HANG_REPORTS" ] + } + include_dirs = [ "//third_party/kasko/binaries/include" ] + lib_dirs = [ "//third_party/kasko/binaries" ] + libs = [ "kasko.dll.lib" ] + } + + copy("copy_kasko_dll") { + visibility = [ ":*" ] + sources = [ + "//third_party/kasko/binaries/kasko.dll", + "//third_party/kasko/binaries/kasko.dll.pdb", + ] + outputs = [ + "$root_out_dir/{{source_file_part}}", + ] + } + + group("kasko") { + if (enable_kasko) { + deps = [ + ":copy_kasko_dll", + ] + public_configs = [ ":kasko_config" ] + } + } +} else { + group("kasko") { + } +}
diff --git a/third_party/kasko/OWNERS b/third_party/kasko/OWNERS new file mode 100644 index 0000000..71dc7187 --- /dev/null +++ b/third_party/kasko/OWNERS
@@ -0,0 +1,3 @@ +chrisha@chromium.org +pmonette@chromium.org +siggi@chromium.org
diff --git a/third_party/libjingle/BUILD.gn b/third_party/libjingle/BUILD.gn index 5a2510a..d78a0a2 100644 --- a/third_party/libjingle/BUILD.gn +++ b/third_party/libjingle/BUILD.gn
@@ -287,7 +287,7 @@ ] configs += [ ":jingle_unexported_configs" ] public_configs = [ ":jingle_public_configs" ] - deps = [ + public_deps = [ ":libjingle_webrtc_common", ] }
diff --git a/third_party/libxml/BUILD.gn b/third_party/libxml/BUILD.gn index 5e633c04..70b66ab 100644 --- a/third_party/libxml/BUILD.gn +++ b/third_party/libxml/BUILD.gn
@@ -28,7 +28,8 @@ if (is_win) { cflags_c = [ "/wd4018", # Signed/unsigned mismatch in comparison. - "/wd4101", # Unreferenced local variable. + "/wd4267", # TODO(brucedawson): http://crbug.com/554200 fix C4267 + "/wd4311", # and C4311 warnings. ] } if (is_clang) {
diff --git a/third_party/libxslt/BUILD.gn b/third_party/libxslt/BUILD.gn index 3f27c5de5..6e8dcc9 100644 --- a/third_party/libxslt/BUILD.gn +++ b/third_party/libxslt/BUILD.gn
@@ -86,7 +86,13 @@ include_dirs = [ "linux" ] } else if (is_win) { include_dirs = [ "win32" ] - cflags += [ "/wd4267" ] # size_t to int. + cflags += [ + "/wd4267", # size_t to int. + + # TODO(brucedawson): http://crbug.com/554200 4311 is a VS + # 2015 64-bit warning for pointer truncation + "/wd4311", + ] } else if (is_mac) { include_dirs = [ "mac" ] }
diff --git a/third_party/libxslt/libxslt.gyp b/third_party/libxslt/libxslt.gyp index 19ea0b1..fc6ffc4 100644 --- a/third_party/libxslt/libxslt.gyp +++ b/third_party/libxslt/libxslt.gyp
@@ -109,8 +109,8 @@ 'msvs_disabled_warnings': [ # size_t to int conversion. 4267, - # TODO(brucedawson): http://crbug.com/554200 4311 is a VS - # 2015 64-bit warning for pointer truncation + # TODO(brucedawson): http://crbug.com/554200 4311 is a + # VS 2015 64-bit warning for pointer truncation 4311, ], 'variables': {
diff --git a/third_party/mesa/BUILD.gn b/third_party/mesa/BUILD.gn index 6ae815dd..a6fdb11 100644 --- a/third_party/mesa/BUILD.gn +++ b/third_party/mesa/BUILD.gn
@@ -141,6 +141,7 @@ "/wd4305", # Truncation from int to float. "/wd4334", # Result of 32-bit shift implicitly converted to 64 bits. "/wd4345", # POD-type default initializers. + "/wd4311", # Pointer truncation TODO(brucedawson): http://crbug.com/554200 ] } }
diff --git a/third_party/mojo/src/mojo/edk/embedder/entrypoints.cc b/third_party/mojo/src/mojo/edk/embedder/entrypoints.cc index cb24016..3d30deb 100644 --- a/third_party/mojo/src/mojo/edk/embedder/entrypoints.cc +++ b/third_party/mojo/src/mojo/edk/embedder/entrypoints.cc
@@ -9,6 +9,7 @@ #include "mojo/public/c/system/data_pipe.h" #include "mojo/public/c/system/functions.h" #include "mojo/public/c/system/message_pipe.h" +#include "mojo/public/c/system/wait_set.h" #include "third_party/mojo/src/mojo/edk/embedder/embedder_internal.h" #include "third_party/mojo/src/mojo/edk/system/core.h"
diff --git a/third_party/polymer/v1_0/extract_inline_scripts.sh b/third_party/polymer/v1_0/extract_inline_scripts.sh index 91fc6ea..e4c891f 100755 --- a/third_party/polymer/v1_0/extract_inline_scripts.sh +++ b/third_party/polymer/v1_0/extract_inline_scripts.sh
@@ -44,6 +44,7 @@ html_without_js="$dir/$name-extracted.html" extracted_js="$dir/$name-extracted.js" - crisper --source "$original_html_name" --html "$html_without_js" --js "$extracted_js" + crisper --script-in-head=false --source "$original_html_name" \ + --html "$html_without_js" --js "$extracted_js" mv "$html_without_js" "$original_html_name" done
diff --git a/third_party/re2/BUILD.gn b/third_party/re2/BUILD.gn index 3777b6d..b827d59 100644 --- a/third_party/re2/BUILD.gn +++ b/third_party/re2/BUILD.gn
@@ -61,17 +61,6 @@ configs += [ "//build/config/compiler:no_chromium_code" ] public_configs = [ ":re2_config" ] - deps = [ - "//base/third_party/dynamic_annotations", - ] - - if (is_win) { - cflags = [ - "/wd4018", # Signed/unsigned mismatch in comparison. - "/wd4722", # Destructor never terminates. - ] - } - # TODO(battre) If Dr. Memory is ever migrated to GN, a flag needs to be # added for this that adds a MEMORY_SANITIZER define. See re2.gyp. # if (is_drmemory) {
diff --git a/third_party/re2/re2.gyp b/third_party/re2/re2.gyp index 49b4fc17..c566156 100644 --- a/third_party/re2/re2.gyp +++ b/third_party/re2/re2.gyp
@@ -20,9 +20,6 @@ '<(DEPTH)', ], }, - 'dependencies': [ - '<(DEPTH)/base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations', - ], 'sources': [ 'src/re2/bitstate.cc', 'src/re2/compile.cc', @@ -73,9 +70,6 @@ 'src/util/valgrind.h', ], 'conditions': [ - ['OS=="win"', { - 'msvs_disabled_warnings': [ 4018, 4722, 4267 ], - }], ['build_for_tool=="drmemory"', { # Treat builds for Dr. Memory as builds for MSAN to prevent false # positives created by lazily initialized memory.
diff --git a/tools/android/BUILD.gn b/tools/android/BUILD.gn index 102072f8..012dc35 100644 --- a/tools/android/BUILD.gn +++ b/tools/android/BUILD.gn
@@ -68,3 +68,11 @@ "//tools/android/customtabs_benchmark:customtabs_benchmark_apk", ] } + +# GYP: //tools/android/android_tools.gyp:audio_focus_grabber +group("audio_focus_grabber") { + testonly = true + deps = [ + "//tools/android/audio_focus_grabber:audio_focus_grabber_apk", + ] +}
diff --git a/tools/android/android_tools.gyp b/tools/android/android_tools.gyp index 152636a5..b963b3f 100644 --- a/tools/android/android_tools.gyp +++ b/tools/android/android_tools.gyp
@@ -77,5 +77,13 @@ 'customtabs_benchmark/customtabs_benchmark.gyp:customtabs_benchmark_apk', ], }, + { + # GN: //tools/android:audio_focus_grabber + 'target_name': 'audio_focus_grabber', + 'type': 'none', + 'dependencies': [ + 'audio_focus_grabber/audio_focus_grabber.gyp:audio_focus_grabber_apk', + ], + }, ], }
diff --git a/tools/android/audio_focus_grabber/BUILD.gn b/tools/android/audio_focus_grabber/BUILD.gn new file mode 100644 index 0000000..94ea7511 --- /dev/null +++ b/tools/android/audio_focus_grabber/BUILD.gn
@@ -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. + +import("//build/config/android/rules.gni") + +# GYP: //tools/android/audio_focus_grabber/audio_focus_grabber.gyp:audio_focus_grabber_apk +android_apk("audio_focus_grabber_apk") { + testonly = true + android_manifest = "java/AndroidManifest.xml" + apk_name = "AudioFocusGrabber" + + deps = [ + ":audio_focus_grabber_apk_resources", + "//base:base_java", + "//third_party/android_tools:android_support_v13_java", + ] + + java_files = [ + "java/src/org/chromium/tools/audio_focus_grabber/AudioFocusGrabberActivity.java", + "java/src/org/chromium/tools/audio_focus_grabber/AudioFocusGrabberListenerService.java", + ] +} + +android_resources("audio_focus_grabber_apk_resources") { + testonly = true + resource_dirs = [ "java/res" ] + android_manifest = "java/AndroidManifest.xml" +}
diff --git a/tools/android/audio_focus_grabber/OWNERS b/tools/android/audio_focus_grabber/OWNERS new file mode 100644 index 0000000..5ad525b --- /dev/null +++ b/tools/android/audio_focus_grabber/OWNERS
@@ -0,0 +1 @@ +zqzhang@chromium.org
diff --git a/tools/android/audio_focus_grabber/README.md b/tools/android/audio_focus_grabber/README.md new file mode 100644 index 0000000..9640898f --- /dev/null +++ b/tools/android/audio_focus_grabber/README.md
@@ -0,0 +1,50 @@ +## AudioFocusGrabber: a Tool for Testing Audio Focus Handling in Apps + +A simple app used to test audio focus handling in apps, especially +MediaSession in Chrome. You can perform audio gain/abandon actions, in +order to simulate a short ping from an SMS or email, or permanent +audio focus gain from other media player apps. + +### Setup + +#### 1: Build and install the AudioFocusGrabber app + + ninja -C out/Debug audio_focus_grabber_apk + adb install -r out/Debug/apks/AudioFocusGrabber.apk + +#### 2: Simulate audio focus actions + +You can simulate audio focus actions using the UI, the notification +bar or through `adb` shell. There are three kinds of audio focus +actions, corresponding to: + +* `AudioManager.AUDIOFOCUS_GAIN` +* `AudioManager.AUDIOFOCUS_TRANSIENT` +* `AudioManager.AUDIOFOCUS_TRANSIENT_MAY_DUCK` + +##### 2.1: Controlling from the UI + +From the UI, there are three buttons for the three actions. Just click +it, and AudioFocusGrabber will perform the audio focus action, and play a ping +sound. + +However in this way, the app must be in background. + +##### 2.2: Controlling from the notification + +You can also start a notification from the UI, and then you can make +controls from the notification. + +In this way, the app must be in background or losed window focus. + +##### 2.3 Controlling from the `adb` shell + +From the `adb` shell, which you can do it even if the AudioFocusGrabber is not +in foreground. You may use the following three commands: + + adb shell am startservice -a AUDIO_FOCUS_GRABBER_GAIN + adb shell am startservice -a AUDIO_FOCUS_GRABBER_TRANSIENT_PAUSE + adb shell am startservice -a AUDIO_FOCUS_GRABBER_TRANSIENT_DUCK + +In this way, the app may be in the foreground, in the background or +losed window focus.
diff --git a/tools/android/audio_focus_grabber/audio_focus_grabber.gyp b/tools/android/audio_focus_grabber/audio_focus_grabber.gyp new file mode 100644 index 0000000..bad0432d --- /dev/null +++ b/tools/android/audio_focus_grabber/audio_focus_grabber.gyp
@@ -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. +{ + 'targets': [ + { + # GN: //tools/android/audio_focus_grabber:audio_focus_grabber_apk + 'target_name': 'audio_focus_grabber_apk', + 'type': 'none', + 'variables': { + 'apk_name': 'AudioFocusGrabber', + 'android_manifest_path': 'java/AndroidManifest.xml', + 'java_in_dir': 'java', + 'resource_dir': 'java/res', + }, + 'dependencies': [ + '../../../base/base.gyp:base_java', + '../../../third_party/android_tools/android_tools.gyp:android_support_v13_javalib' + ], + 'includes': [ '../../../build/java_apk.gypi' ], + }] +}
diff --git a/tools/android/audio_focus_grabber/java/AndroidManifest.xml b/tools/android/audio_focus_grabber/java/AndroidManifest.xml new file mode 100644 index 0000000..e83b915 --- /dev/null +++ b/tools/android/audio_focus_grabber/java/AndroidManifest.xml
@@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (c) 2016 The Chromium Authors. All rights reserved. Use of this + source code is governed by a BSD-style license that can be found in the + LICENSE file. +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="org.chromium.tools.audio_focus_grabber" > + + <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="23" /> + + <application + android:label="@string/app_name" > + + <activity + android:name="org.chromium.tools.audio_focus_grabber.AudioFocusGrabberActivity" + android:label="@string/app_name" > + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + + <service + android:name="org.chromium.tools.audio_focus_grabber.AudioFocusGrabberListenerService" + android:exported="true" > + <intent-filter> + <action android:name="AUDIO_FOCUS_GRABBER_GAIN" /> + <action android:name="AUDIO_FOCUS_GRABBER_TRANSIENT_PAUSE" /> + <action android:name="AUDIO_FOCUS_GRABBER_TRANSIENT_DUCK" /> + </intent-filter> + </service> + + </application> + +</manifest>
diff --git a/tools/android/audio_focus_grabber/java/res/drawable-hdpi/notification_icon.png b/tools/android/audio_focus_grabber/java/res/drawable-hdpi/notification_icon.png new file mode 100644 index 0000000..ca6ce5f --- /dev/null +++ b/tools/android/audio_focus_grabber/java/res/drawable-hdpi/notification_icon.png Binary files differ
diff --git a/tools/android/audio_focus_grabber/java/res/drawable-mdpi/notification_icon.png b/tools/android/audio_focus_grabber/java/res/drawable-mdpi/notification_icon.png new file mode 100644 index 0000000..82d17aa --- /dev/null +++ b/tools/android/audio_focus_grabber/java/res/drawable-mdpi/notification_icon.png Binary files differ
diff --git a/tools/android/audio_focus_grabber/java/res/drawable-xhdpi/notification_icon.png b/tools/android/audio_focus_grabber/java/res/drawable-xhdpi/notification_icon.png new file mode 100644 index 0000000..833485ec --- /dev/null +++ b/tools/android/audio_focus_grabber/java/res/drawable-xhdpi/notification_icon.png Binary files differ
diff --git a/tools/android/audio_focus_grabber/java/res/drawable-xxhdpi/notification_icon.png b/tools/android/audio_focus_grabber/java/res/drawable-xxhdpi/notification_icon.png new file mode 100644 index 0000000..9eaf5331 --- /dev/null +++ b/tools/android/audio_focus_grabber/java/res/drawable-xxhdpi/notification_icon.png Binary files differ
diff --git a/tools/android/audio_focus_grabber/java/res/drawable-xxxhdpi/notification_icon.png b/tools/android/audio_focus_grabber/java/res/drawable-xxxhdpi/notification_icon.png new file mode 100644 index 0000000..5c0f943 --- /dev/null +++ b/tools/android/audio_focus_grabber/java/res/drawable-xxxhdpi/notification_icon.png Binary files differ
diff --git a/tools/android/audio_focus_grabber/java/res/layout/audio_focus_grabber_activity.xml b/tools/android/audio_focus_grabber/java/res/layout/audio_focus_grabber_activity.xml new file mode 100644 index 0000000..101b2e6 --- /dev/null +++ b/tools/android/audio_focus_grabber/java/res/layout/audio_focus_grabber_activity.xml
@@ -0,0 +1,80 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + 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. +--> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_margin="20dp" > + + <TextView + android:id="@+id/message" + android:layout_gravity="center_horizontal|top" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_weight="1" + android:text="" /> + + <LinearLayout + android:orientation="horizontal" + android:layout_gravity="center_horizontal|bottom" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:layout_weight="0" + style="?android:attr/buttonBarStyle" > + + <Button + android:id="@+id/button_gain" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/button_gain_name" + android:onClick="onButtonClicked" + style="?android:attr/buttonBarButtonStyle" /> + <Button + android:id="@+id/button_transient_pause" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/button_transient_pause_name" + android:onClick="onButtonClicked" + style="?android:attr/buttonBarButtonStyle" /> + <Button + android:id="@+id/button_transient_duck" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/button_transient_duck_name" + android:onClick="onButtonClicked" + style="?android:attr/buttonBarButtonStyle" /> + + </LinearLayout> + + <LinearLayout + android:orientation="horizontal" + android:layout_gravity="center_horizontal|bottom" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:layout_weight="0" > + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/text_notification_prompt" /> + <Button + android:id="@+id/button_show_notification" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/button_show_notification_name" + android:onClick="onButtonClicked" /> + <Button + android:id="@+id/button_hide_notification" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/button_hide_notification_name" + android:onClick="onButtonClicked" /> + + </LinearLayout> + +</LinearLayout>
diff --git a/tools/android/audio_focus_grabber/java/res/layout/audio_focus_grabber_notification_bar.xml b/tools/android/audio_focus_grabber/java/res/layout/audio_focus_grabber_notification_bar.xml new file mode 100644 index 0000000..ec7ffd8 --- /dev/null +++ b/tools/android/audio_focus_grabber/java/res/layout/audio_focus_grabber_notification_bar.xml
@@ -0,0 +1,54 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + 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. +--> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:gravity="center_vertical" + android:orientation="vertical" + style="?android:attr/buttonBarStyle"> + + <TextView + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:text="@string/app_name" /> + + <LinearLayout + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:gravity="center_vertical" + android:orientation="horizontal" + style="?android:attr/buttonBarStyle"> + + <Button + android:id="@+id/notification_button_gain" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/button_gain_name" + style="?android:attr/buttonBarButtonStyle" /> + <Button + android:id="@+id/notification_button_transient_pause" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/button_transient_pause_name" + style="?android:attr/buttonBarButtonStyle" /> + <Button + android:id="@+id/notification_button_transient_duck" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/button_transient_duck_name" + style="?android:attr/buttonBarButtonStyle" /> + <Button + android:id="@+id/notification_button_hide" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/button_hide_notification_name" + style="?android:attr/buttonBarButtonStyle" /> + + </LinearLayout> + +</LinearLayout>
diff --git a/tools/android/audio_focus_grabber/java/res/raw/ping.mp3 b/tools/android/audio_focus_grabber/java/res/raw/ping.mp3 new file mode 100644 index 0000000..75b83ba --- /dev/null +++ b/tools/android/audio_focus_grabber/java/res/raw/ping.mp3 Binary files differ
diff --git a/tools/android/audio_focus_grabber/java/res/values/strings.xml b/tools/android/audio_focus_grabber/java/res/values/strings.xml new file mode 100644 index 0000000..222879c --- /dev/null +++ b/tools/android/audio_focus_grabber/java/res/values/strings.xml
@@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (c) 2016 The Chromium Authors. All rights reserved. Use of this + source code is governed by a BSD-style license that can be found in the + LICENSE file. +--> + +<resources> + <string name="app_name">AudioFocusGrabber</string> + <string name="button_gain_name">Gain</string> + <string name="button_transient_pause_name">Pause</string> + <string name="button_transient_duck_name">Duck</string> + <string name="button_hide_notification_name">Hide</string> + <string name="button_show_notification_name">Show</string> + <string name="text_notification_prompt">Notification Controller:</string> +</resources>
diff --git a/tools/android/audio_focus_grabber/java/src/org/chromium/tools/audio_focus_grabber/AudioFocusGrabberActivity.java b/tools/android/audio_focus_grabber/java/src/org/chromium/tools/audio_focus_grabber/AudioFocusGrabberActivity.java new file mode 100644 index 0000000..7030b8f --- /dev/null +++ b/tools/android/audio_focus_grabber/java/src/org/chromium/tools/audio_focus_grabber/AudioFocusGrabberActivity.java
@@ -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. + +package org.chromium.tools.audio_focus_grabber; + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; +import android.view.View; + +/** + * The main activity of AudioFocusGrabber. It starts the background service, + * and responds to UI button controls. + */ +public class AudioFocusGrabberActivity extends Activity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.audio_focus_grabber_activity); + } + + public void onButtonClicked(View view) { + Intent intent = new Intent(this, AudioFocusGrabberListenerService.class); + switch (view.getId()) { + case R.id.button_gain: + intent.setAction(AudioFocusGrabberListenerService.ACTION_GAIN); + break; + case R.id.button_transient_pause: + intent.setAction(AudioFocusGrabberListenerService.ACTION_TRANSIENT_PAUSE); + break; + case R.id.button_transient_duck: + intent.setAction(AudioFocusGrabberListenerService.ACTION_TRANSIENT_DUCK); + break; + case R.id.button_show_notification: + intent.setAction(AudioFocusGrabberListenerService.ACTION_SHOW_NOTIFICATION); + break; + case R.id.button_hide_notification: + intent.setAction(AudioFocusGrabberListenerService.ACTION_HIDE_NOTIFICATION); + break; + } + startService(intent); + } + +}
diff --git a/tools/android/audio_focus_grabber/java/src/org/chromium/tools/audio_focus_grabber/AudioFocusGrabberListenerService.java b/tools/android/audio_focus_grabber/java/src/org/chromium/tools/audio_focus_grabber/AudioFocusGrabberListenerService.java new file mode 100644 index 0000000..9981fd8 --- /dev/null +++ b/tools/android/audio_focus_grabber/java/src/org/chromium/tools/audio_focus_grabber/AudioFocusGrabberListenerService.java
@@ -0,0 +1,180 @@ +// 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.tools.audio_focus_grabber; + +import android.app.PendingIntent; +import android.app.Service; +import android.content.Context; +import android.content.Intent; +import android.media.AudioManager; +import android.media.MediaPlayer; +import android.os.IBinder; +import android.support.v4.app.NotificationCompat; +import android.support.v4.app.NotificationManagerCompat; +import android.widget.RemoteViews; + +import org.chromium.base.Log; + +/** + * The listener service, which listens to intents and perform audio focus actions. + */ +public class AudioFocusGrabberListenerService extends Service { + private static final String TAG = "AudioFocusGrabber"; + + public static final String ACTION_GAIN = "AUDIO_FOCUS_GRABBER_GAIN"; + public static final String ACTION_TRANSIENT_PAUSE = "AUDIO_FOCUS_GRABBER_TRANSIENT_PAUSE"; + public static final String ACTION_TRANSIENT_DUCK = "AUDIO_FOCUS_GRABBER_TRANSIENT_DUCK"; + public static final String ACTION_SHOW_NOTIFICATION = "AUDIO_FOCUS_GRABBER_SHOW_NOTIFICATION"; + public static final String ACTION_HIDE_NOTIFICATION = "AUDIO_FOCUS_GRABBER_HIDE_NOTIFICATION"; + + private static final int NOTIFICATION_ID = 1; + + AudioManager mAudioManager = null; + MediaPlayer mMediaPlayer = null; + boolean mIsDucking = false; + + @Override + public void onCreate() { + super.onCreate(); + mAudioManager = (AudioManager) getApplicationContext() + .getSystemService(Context.AUDIO_SERVICE); + } + + @Override + public void onDestroy() { + hideNotification(); + } + + @Override + public IBinder onBind(Intent intent) { + return null; + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + if (intent != null) { + Log.i(TAG, "received intent: " + intent.getAction()); + } else { + Log.i(TAG, "received null intent"); + return START_NOT_STICKY; + } + processIntent(intent); + return START_NOT_STICKY; + } + + void processIntent(Intent intent) { + if (mMediaPlayer != null) { + Log.i(TAG, "There's already a MediaPlayer playing," + + " stopping the existing player and abandon focus"); + releaseAndAbandonAudioFocus(); + } + String action = intent.getAction(); + if (ACTION_SHOW_NOTIFICATION.equals(action)) { + showNotification(); + } else if (ACTION_HIDE_NOTIFICATION.equals(action)) { + hideNotification(); + } else if (ACTION_GAIN.equals(action)) { + gainFocusAndPlay(AudioManager.AUDIOFOCUS_GAIN); + } else if (ACTION_TRANSIENT_PAUSE.equals(action)) { + gainFocusAndPlay(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT); + } else if (ACTION_TRANSIENT_DUCK.equals(action)) { + gainFocusAndPlay(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK); + } else { + assert false; + } + } + + + void gainFocusAndPlay(int focusType) { + int result = mAudioManager.requestAudioFocus( + mOnAudioFocusChangeListener, + AudioManager.STREAM_MUSIC, + focusType); + if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) { + playSound(); + } else { + Log.i(TAG, "cannot request audio focus"); + } + } + + void playSound() { + mMediaPlayer = MediaPlayer.create(getApplicationContext(), R.raw.ping); + mMediaPlayer.setOnCompletionListener(mOnCompletionListener); + mMediaPlayer.start(); + } + + void releaseAndAbandonAudioFocus() { + mMediaPlayer.release(); + mMediaPlayer = null; + mAudioManager.abandonAudioFocus(mOnAudioFocusChangeListener); + } + + MediaPlayer.OnCompletionListener mOnCompletionListener = + new MediaPlayer.OnCompletionListener() { + @Override + public void onCompletion(MediaPlayer mp) { + releaseAndAbandonAudioFocus(); + } + }; + + AudioManager.OnAudioFocusChangeListener mOnAudioFocusChangeListener = + new AudioManager.OnAudioFocusChangeListener() { + @Override + public void onAudioFocusChange(int focusChange) { + switch (focusChange) { + case AudioManager.AUDIOFOCUS_GAIN: + if (mIsDucking) { + mMediaPlayer.setVolume(1.0f, 1.0f); + mIsDucking = false; + } else { + mMediaPlayer.start(); + } + break; + case AudioManager.AUDIOFOCUS_LOSS: + mMediaPlayer.stop(); + mMediaPlayer.release(); + mMediaPlayer = null; + break; + case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT: + mMediaPlayer.pause(); + break; + case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: + mMediaPlayer.setVolume(0.1f, 0.1f); + mIsDucking = true; + break; + } + } + }; + + private void showNotification() { + RemoteViews view = new RemoteViews(this.getPackageName(), + R.layout.audio_focus_grabber_notification_bar); + view.setOnClickPendingIntent(R.id.notification_button_gain, + createPendingIntent(ACTION_GAIN)); + view.setOnClickPendingIntent(R.id.notification_button_transient_pause, + createPendingIntent(ACTION_TRANSIENT_PAUSE)); + view.setOnClickPendingIntent(R.id.notification_button_transient_duck, + createPendingIntent(ACTION_TRANSIENT_DUCK)); + view.setOnClickPendingIntent(R.id.notification_button_hide, + createPendingIntent(ACTION_HIDE_NOTIFICATION)); + + NotificationManagerCompat manager = NotificationManagerCompat.from(this); + NotificationCompat.Builder builder = new NotificationCompat.Builder(this) + .setContent(view) + .setSmallIcon(R.drawable.notification_icon); + manager.notify(NOTIFICATION_ID, builder.build()); + } + + private void hideNotification() { + NotificationManagerCompat manager = NotificationManagerCompat.from(this); + manager.cancel(NOTIFICATION_ID); + } + + private PendingIntent createPendingIntent(String action) { + Intent i = new Intent(this, AudioFocusGrabberListenerService.class); + i.setAction(action); + return PendingIntent.getService(this, 0, i, PendingIntent.FLAG_CANCEL_CURRENT); + } +}
diff --git a/tools/android/loading/OWNERS b/tools/android/loading/OWNERS new file mode 100644 index 0000000..3301555 --- /dev/null +++ b/tools/android/loading/OWNERS
@@ -0,0 +1,2 @@ +lizeb@chromium.org +pasko@chromium.org
diff --git a/tools/android/loading/log_parser.py b/tools/android/loading/log_parser.py new file mode 100644 index 0000000..e77fd4d --- /dev/null +++ b/tools/android/loading/log_parser.py
@@ -0,0 +1,215 @@ +# 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. + +"""Parses a JSON request log created by log_requests.py.""" + +import collections +import json +import operator +import urlparse + + +Timing = collections.namedtuple( + 'Timing', + ['connectEnd', 'connectStart', 'dnsEnd', 'dnsStart', 'proxyEnd', + 'proxyStart', 'receiveHeadersEnd', 'requestTime', 'sendEnd', 'sendStart', + 'serviceWorkerFetchEnd', 'serviceWorkerFetchReady', + 'serviceWorkerFetchStart', 'sslEnd', 'sslStart']) + + +class Resource(object): + """Describes a resource.""" + + def __init__(self, url, content_type): + """Creates an instance of Resource. + + Args: + url: URL of the resource + content_type: Content-Type of the resources. + """ + self.url = url + self.content_type = content_type + + def GetShortName(self): + """Returns either the hostname of the resource, or the filename, + or the end of the path. + """ + parsed = urlparse.urlparse(self.url) + path = parsed.path + if path != '' and path != '/': + last_path = parsed.path.split('/')[-1] + if len(last_path) < 10: + if len(path) < 10: + return path + else: + return parsed.path[-10:] + else: + return last_path + else: + return parsed.hostname + + def GetContentType(self): + mime = self.content_type + if mime == 'text/html': + return 'html' + elif mime == 'text/css': + return 'css' + elif mime in ('application/x-javascript', 'text/javascript', + 'application/javascript'): + return 'script' + elif mime == 'application/json': + return 'json' + elif mime == 'image/gif': + return 'gif_image' + elif mime.startswith('image/'): + return 'image' + else: + return 'other' + + @classmethod + def FromRequest(cls, request): + """Creates a Resource from an instance of RequestData.""" + return Resource(request.url, request.GetContentType()) + + def __Fields(self): + return (self.url, self.content_type) + + def __eq__(self, o): + return self.__Fields() == o.__Fields() + + def __hash__(self): + return hash(self.__Fields()) + + +class RequestData(object): + """Represents a request, as dumped by log_requests.py.""" + + def __init__(self, status, headers, request_headers, timestamp, timing, url, + served_from_cache, initiator): + self.status = status + self.headers = headers + self.request_headers = request_headers + self.timestamp = timestamp + self.timing = Timing(**timing) if timing else None + self.url = url + self.served_from_cache = served_from_cache + self.initiator = initiator + + def IsDataUrl(self): + return self.url.startswith('data:') + + def GetContentType(self): + content_type = self.headers['Content-Type'] + if ';' in content_type: + return content_type[:content_type.index(';')] + else: + return content_type + + @classmethod + def FromDict(cls, r): + """Creates a RequestData object from a dict.""" + return RequestData(r['status'], r['headers'], r['request_headers'], + r['timestamp'], r['timing'], r['url'], + r['served_from_cache'], r['initiator']) + + +def ParseJsonFile(filename): + """Converts a JSON file to a sequence of RequestData.""" + with open(filename) as f: + json_data = json.load(f) + return [RequestData.FromDict(r) for r in json_data] + + +def FilterRequests(requests): + """Filters a list of requests. + + Args: + requests: [RequestData, ...] + + Returns: + A list of requests that are not data URL, have a Content-Type, and are + not served from the cache. + """ + return [r for r in requests if not r.IsDataUrl() + and 'Content-Type' in r.headers and not r.served_from_cache] + + +def ResourceToRequestMap(requests): + """Returns a Resource -> Request map. + + A resource can be requested several times in a single page load. Keeps the + first request in this case. + + Args: + requests: [RequestData, ...] + + Returns: + [Resource, ...] + """ + # reversed(requests) because we want the first one to win. + return dict([(Resource.FromRequest(r), r) for r in reversed(requests)]) + + +def GetResources(requests): + """Returns an ordered list of resources from a list of requests. + + The same resource can be requested several time for a single page load. This + keeps only the first request. + + Args: + requests: [RequestData] + + Returns: + [Resource] + """ + resources = [] + known_resources = set() + for r in requests: + resource = Resource.FromRequest(r) + if r in known_resources: + continue + known_resources.add(resource) + resources.append(resource) + return resources + + +def ParseCacheControl(headers): + """Parses the "Cache-Control" header and returns a dict representing it. + + Args: + headers: (dict) Response headers. + + Returns: + {Directive: Value, ...} + """ + # TODO(lizeb): Handle the "Expires" header as well. + result = {} + cache_control = headers.get('Cache-Control', None) + if cache_control is None: + return result + directives = [s.strip() for s in cache_control.split(',')] + for directive in directives: + parts = [s.strip() for s in directive.split('=')] + if len(parts) == 1: + result[parts[0]] = True + else: + result[parts[0]] = parts[1] + return result + + +def MaxAge(request): + """Returns the max-age of a resource, or -1.""" + cache_control = ParseCacheControl(request.headers) + if (u'no-store' in cache_control + or u'no-cache' in cache_control + or len(cache_control) == 0): + return -1 + if 'max-age' in cache_control: + return int(cache_control['max-age']) + return -1 + + +def SortedByCompletion(requests): + """Returns the requests, sorted by completion time.""" + return sorted(requests, key=operator.attrgetter('timestamp'))
diff --git a/tools/android/loading/log_requests.py b/tools/android/loading/log_requests.py new file mode 100755 index 0000000..16a10d5 --- /dev/null +++ b/tools/android/loading/log_requests.py
@@ -0,0 +1,216 @@ +#! /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. + +"""Loads a URL on an Android device, logging all the requests made to do it +to a JSON file using DevTools. +""" + +import contextlib +import httplib +import json +import logging +import optparse +import os +import sys +import time + +file_dir = os.path.dirname(__file__) +sys.path.append(os.path.join(file_dir, '..', '..', '..', 'build', 'android')) +sys.path.append(os.path.join(file_dir, '..', '..', 'telemetry')) +sys.path.append(os.path.join(file_dir, '..', '..', 'chrome_proxy')) + +from pylib import constants +from pylib import flag_changer +from pylib.device import device_utils +from pylib.device import intent +from common import inspector_network +from telemetry.internal.backends.chrome_inspector import inspector_websocket +from telemetry.internal.backends.chrome_inspector import websocket + + +_PORT = 9222 # DevTools port number. + + +@contextlib.contextmanager +def FlagChanger(device, command_line_path, new_flags): + """Changes the flags in a context, restores them afterwards. + + Args: + device: Device to target, from DeviceUtils. + command_line_path: Full path to the command-line file. + new_flags: Flags to add. + """ + changer = flag_changer.FlagChanger(device, command_line_path) + changer.AddFlags(new_flags) + try: + yield + finally: + changer.Restore() + + +@contextlib.contextmanager +def ForwardPort(device, local, remote): + """Forwards a local port to a remote one on a device in a context.""" + device.adb.Forward(local, remote) + try: + yield + finally: + device.adb.ForwardRemove(local) + + +def _SetUpDevice(device, package_info): + """Enables root and closes Chrome on a device.""" + device.EnableRoot() + device.KillAll(package_info.package, quiet=True) + + +class AndroidRequestsLogger(object): + """Logs all the requests made to load a page on a device.""" + + def __init__(self, device): + self.device = device + self._please_stop = False + self._main_frame_id = None + + def _PageDataReceived(self, msg): + """Called when a Page event is received. + + Records the main frame, and stops the recording once it has finished + loading. + + Args: + msg: (dict) Message sent by DevTools. + """ + if 'params' not in msg: + return + params = msg['params'] + method = msg.get('method', None) + if method == 'Page.frameStartedLoading' and self._main_frame_id is None: + self._main_frame_id = params['frameId'] + elif (method == 'Page.frameStoppedLoading' + and params['frameId'] == self._main_frame_id): + self._please_stop = True + + def _LogPageLoadInternal(self, url, clear_cache): + """Returns the collection of requests made to load a given URL. + + Assumes that DevTools is available on http://localhost:_PORT. + + Args: + url: URL to load. + clear_cache: Whether to clear the HTTP cache. + + Returns: + [inspector_network.InspectorNetworkResponseData, ...] + """ + self._main_frame_id = None + self._please_stop = False + r = httplib.HTTPConnection('localhost', _PORT) + r.request('GET', '/json') + response = r.getresponse() + if response.status != 200: + logging.error('Cannot connect to the remote target.') + return None + json_response = json.loads(response.read()) + r.close() + websocket_url = json_response[0]['webSocketDebuggerUrl'] + ws = inspector_websocket.InspectorWebsocket() + ws.Connect(websocket_url) + inspector = inspector_network.InspectorNetwork(ws) + if clear_cache: + inspector.ClearCache() + ws.SyncRequest({'method': 'Page.enable'}) + ws.RegisterDomain('Page', self._PageDataReceived) + inspector.StartMonitoringNetwork() + ws.SendAndIgnoreResponse({'method': 'Page.navigate', + 'params': {'url': url}}) + while not self._please_stop: + try: + ws.DispatchNotifications() + except websocket.WebSocketTimeoutException as e: + logging.warning('Exception: ' + str(e)) + break + inspector.StopMonitoringNetwork() + return inspector.GetResponseData() + + def LogPageLoad(self, url, clear_cache): + """Returns the collection of requests made to load a given URL on a device. + + Args: + url: (str) URL to load on the device. + clear_cache: (bool) Whether to clear the HTTP cache. + + Returns: + See _LogPageLoadInternal(). + """ + package_info = constants.PACKAGE_INFO['chrome'] + command_line_path = '/data/local/chrome-command-line' + new_flags = ['--enable-test-events', '--remote-debugging-port=%d' % _PORT] + _SetUpDevice(self.device, package_info) + with FlagChanger(self.device, command_line_path, new_flags): + start_intent = intent.Intent( + package=package_info.package, activity=package_info.activity, + data='about:blank') + self.device.StartActivity(start_intent, blocking=True) + time.sleep(2) + with ForwardPort(self.device, 'tcp:%d' % _PORT, + 'localabstract:chrome_devtools_remote'): + return self._LogPageLoadInternal(url, clear_cache) + + +def _ResponseDataToJson(data): + """Converts a list of inspector_network.InspectorNetworkResponseData to JSON. + + Args: + data: as returned by _LogPageLoad() + + Returns: + A JSON file with the following format: + [request1, request2, ...], and a request is: + {'status': str, 'headers': dict, 'request_headers': dict, + 'timestamp': double, 'timing': dict, 'url': str, + 'served_from_cache': bool, 'initiator': str}) + """ + result = [] + for r in data: + result.append({'status': r.status, + 'headers': r.headers, + 'request_headers': r.request_headers, + 'timestamp': r.timestamp, + 'timing': r.timing, + 'url': r.url, + 'served_from_cache': r.served_from_cache, + 'initiator': r.initiator}) + return json.dumps(result) + + +def _CreateOptionParser(): + """Returns the option parser for this tool.""" + parser = optparse.OptionParser(description='Starts a browser on an Android ' + 'device, gathers the requests made to load a ' + 'page and dumps it to a JSON file.') + parser.add_option('--url', help='URL to load.', + default='https://www.google.com', metavar='URL') + parser.add_option('--output', help='Output file.', default='result.json') + parser.add_option('--no-clear-cache', help=('Do not clear the HTTP cache ' + 'before loading the URL.'), + default=True, action='store_false', dest='clear_cache') + return parser + + +def main(): + parser = _CreateOptionParser() + options, _ = parser.parse_args() + devices = device_utils.DeviceUtils.HealthyDevices() + device = devices[0] + request_logger = AndroidRequestsLogger(device) + response_data = request_logger.LogPageLoad(options.url, options.clear_cache) + json_data = _ResponseDataToJson(response_data) + with open(options.output, 'w') as f: + f.write(json_data) + + +if __name__ == '__main__': + main()
diff --git a/tools/android/loading/process_request_log.py b/tools/android/loading/process_request_log.py new file mode 100755 index 0000000..bbec0a8 --- /dev/null +++ b/tools/android/loading/process_request_log.py
@@ -0,0 +1,189 @@ +#! /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. + +"""Creates a Graphviz file visualizing the resource dependencies from a JSON +file dumped by log_requests.py. +""" + +import collections +import sys +import urlparse + +import log_parser +from log_parser import Resource + + +def _BuildResourceDependencyGraph(requests): + """Builds the graph of resource dependencies. + + Args: + requests: [RequestData, ...] + + Returns: + A tuple ([Resource], [(resource1, resource2, reason), ...]) + """ + resources = log_parser.GetResources(requests) + resources_from_url = {resource.url: resource for resource in resources} + requests_by_completion = log_parser.SortedByCompletion(requests) + deps = [] + for r in requests: + resource = Resource.FromRequest(r) + initiator = r.initiator + initiator_type = initiator['type'] + dep = None + if initiator_type == 'parser': + url = initiator['url'] + blocking_resource = resources_from_url.get(url, None) + if blocking_resource is None: + continue + dep = (blocking_resource, resource, 'parser') + elif initiator_type == 'script' and 'stackTrace' in initiator: + for frame in initiator['stackTrace']: + url = frame['url'] + blocking_resource = resources_from_url.get(url, None) + if blocking_resource is None: + continue + dep = (blocking_resource, resource, 'stack') + break + else: + # When the initiator is a script without a stackTrace, infer that it comes + # from the most recent script from the same hostname. + # TLD+1 might be better, but finding what is a TLD requires a database. + request_hostname = urlparse.urlparse(r.url).hostname + sorted_script_requests_from_hostname = [ + r for r in requests_by_completion + if (resource.GetContentType() in ('script', 'html', 'json') + and urlparse.urlparse(r.url).hostname == request_hostname)] + most_recent = None + # Linear search is bad, but this shouldn't matter here. + for request in sorted_script_requests_from_hostname: + if request.timestamp < r.timing.requestTime: + most_recent = request + else: + break + if most_recent is not None: + blocking = resources_from_url.get(most_recent.url, None) + if blocking is not None: + dep = (blocking, resource, 'script_inferred') + if dep is not None: + deps.append(dep) + return (resources, deps) + + +def PrefetchableResources(requests): + """Returns a list of resources that are discoverable without JS. + + Args: + requests: List of requests. + + Returns: + List of discoverable resources, with their initial request. + """ + resource_to_request = log_parser.ResourceToRequestMap(requests) + (_, all_deps) = _BuildResourceDependencyGraph(requests) + # Only keep "parser" arcs + deps = [(first, second) for (first, second, reason) in all_deps + if reason == 'parser'] + deps_per_resource = collections.defaultdict(list) + for (first, second) in deps: + deps_per_resource[first].append(second) + result = [] + visited = set() + to_visit = [deps[0][0]] + while len(to_visit) != 0: + r = to_visit.pop() + visited.add(r) + to_visit += deps_per_resource[r] + result.append(resource_to_request[r]) + return result + + +_CONTENT_TYPE_TO_COLOR = {'html': 'red', 'css': 'green', 'script': 'blue', + 'json': 'purple', 'gif_image': 'grey', + 'image': 'orange', 'other': 'white'} + + +def _ResourceGraphvizNode(resource, request, resource_to_index): + """Returns the node description for a given resource. + + Args: + resource: Resource. + request: RequestData associated with the resource. + resource_to_index: {Resource: int}. + + Returns: + A string describing the resource in graphviz format. + The resource is color-coded according to its content type, and its shape is + oval if its max-age is less than 300s (or if it's not cacheable). + """ + color = _CONTENT_TYPE_TO_COLOR[resource.GetContentType()] + max_age = log_parser.MaxAge(request) + shape = 'polygon' if max_age > 300 else 'oval' + return ('%d [label = "%s"; style = "filled"; fillcolor = %s; shape = %s];\n' + % (resource_to_index[resource], resource.GetShortName(), color, + shape)) + + +def _GraphvizFileFromDeps(resources, requests, deps, output_filename): + """Writes a graphviz file from a set of resource dependencies. + + Args: + resources: [Resource, ...] + requests: list of requests + deps: [(resource1, resource2, reason), ...] + output_filename: file to write the graph to. + """ + with open(output_filename, 'w') as f: + f.write("""digraph dependencies { + rankdir = LR; + """) + resource_to_request = log_parser.ResourceToRequestMap(requests) + resource_to_index = {r: i for (i, r) in enumerate(resources)} + resources_with_edges = set() + for (first, second, reason) in deps: + resources_with_edges.add(first) + resources_with_edges.add(second) + if len(resources_with_edges) != len(resources): + f.write("""subgraph cluster_orphans { + color=black; + label="Orphans"; +""") + for resource in resources: + if resource not in resources_with_edges: + request = resource_to_request[resource] + f.write(_ResourceGraphvizNode(resource, request, resource_to_index)) + f.write('}\n') + + f.write("""subgraph cluster_nodes { + color=invis; +""") + for resource in resources: + request = resource_to_request[resource] + print resource.url + if resource in resources_with_edges: + f.write(_ResourceGraphvizNode(resource, request, resource_to_index)) + for (first, second, reason) in deps: + arrow = '' + if reason == 'parser': + arrow = '[color = red]' + elif reason == 'stack': + arrow = '[color = blue]' + elif reason == 'script_inferred': + arrow = '[color = blue; style=dotted]' + f.write('%d -> %d %s;\n' % ( + resource_to_index[first], resource_to_index[second], arrow)) + f.write('}\n}\n') + + +def main(): + filename = sys.argv[1] + requests = log_parser.ParseJsonFile(filename) + requests = log_parser.FilterRequests(requests) + (resources, deps) = _BuildResourceDependencyGraph(requests) + _GraphvizFileFromDeps(resources, requests, deps, filename + '.dot') + + +if __name__ == '__main__': + main()
diff --git a/tools/battor_agent/BUILD.gn b/tools/battor_agent/BUILD.gn index 03c5594a..a0d401ac 100644 --- a/tools/battor_agent/BUILD.gn +++ b/tools/battor_agent/BUILD.gn
@@ -4,6 +4,9 @@ import("//testing/test.gni") +# Works only on desktop platforms. +assert(is_win || is_linux || is_mac) + executable("battor_agent") { sources = [ "battor_agent_bin.cc", @@ -35,15 +38,18 @@ test("battor_agent_unittests") { sources = [ + "battor_agent_unittest.cc", "battor_connection_impl_unittest.cc", ] deps = [ ":battor_agent_lib", "//base", "//base/test:run_all_unittests", + "//base/test:test_support", "//device/serial", "//device/serial:test_support", "//mojo/public/c/system:for_shared_library", + "//testing/gmock", "//testing/gtest", ] }
diff --git a/tools/battor_agent/battor_agent.cc b/tools/battor_agent/battor_agent.cc index bc2dca418..65289a63 100644 --- a/tools/battor_agent/battor_agent.cc +++ b/tools/battor_agent/battor_agent.cc
@@ -4,20 +4,53 @@ #include "tools/battor_agent/battor_agent.h" +#include "base/bind.h" +#include "base/thread_task_runner_handle.h" #include "tools/battor_agent/battor_connection_impl.h" +using std::vector; + namespace battor { +namespace { + +// The number of seconds that it takes a BattOr to reset. +const uint8_t kBattOrResetTimeSeconds = 2; + +// Returns true if the specified vector of bytes decodes to a message that is an +// ack for the specified control message type. +bool IsAckOfControlCommand(BattOrMessageType message_type, + BattOrControlMessageType control_message_type, + const vector<char>& msg) { + if (message_type != BATTOR_MESSAGE_TYPE_CONTROL_ACK) + return false; + + if (msg.size() != sizeof(BattOrControlMessageAck)) + return false; + + const BattOrControlMessageAck* ack = + reinterpret_cast<const BattOrControlMessageAck*>(msg.data()); + + if (ack->type != control_message_type) + return false; + + return true; +} + +} // namespace + BattOrAgent::BattOrAgent( - scoped_refptr<base::SingleThreadTaskRunner> file_thread_task_runner, - scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner, const std::string& path, - Listener* listener) - : listener_(listener), - connection_(new BattOrConnectionImpl(path, + Listener* listener, + scoped_refptr<base::SingleThreadTaskRunner> file_thread_task_runner, + scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner) + : connection_(new BattOrConnectionImpl(path, this, file_thread_task_runner, - ui_thread_task_runner)) { + ui_thread_task_runner)), + listener_(listener), + last_action_(Action::INVALID), + command_(Command::INVALID) { DCHECK(thread_checker_.CalledOnValidThread()); } @@ -28,39 +61,175 @@ void BattOrAgent::StartTracing() { DCHECK(thread_checker_.CalledOnValidThread()); - ConnectIfNeeded(); + command_ = Command::START_TRACING; + PerformAction(Action::REQUEST_CONNECTION); } -void BattOrAgent::DoStartTracing() { - DCHECK(thread_checker_.CalledOnValidThread()); - - // TODO(charliea): Tell the BattOr to start tracing. - listener_->OnStartTracingComplete(BATTOR_ERROR_NONE); -} - -void BattOrAgent::OnConnectionOpened(bool success) { - DCHECK(thread_checker_.CalledOnValidThread()); - - // TODO(charliea): Rewrite this in a way that allows for multiple tracing - // commands. - if (success) { - DoStartTracing(); - } else { - connection_.reset(); - listener_->OnStartTracingComplete(BATTOR_ERROR_CONNECTION_FAILED); - } -} - -void BattOrAgent::OnBytesSent(bool success) {} - -void BattOrAgent::OnBytesRead(bool success, - BattOrMessageType type, - scoped_ptr<std::vector<char>> bytes) {} - -void BattOrAgent::ConnectIfNeeded() { +void BattOrAgent::BeginConnect() { DCHECK(thread_checker_.CalledOnValidThread()); connection_->Open(); } +void BattOrAgent::OnConnectionOpened(bool success) { + if (!success) { + CompleteCommand(BATTOR_ERROR_CONNECTION_FAILED); + return; + } + + switch (command_) { + case Command::START_TRACING: + PerformAction(Action::SEND_RESET); + break; + case Command::INVALID: + NOTREACHED(); + } +} + +void BattOrAgent::OnBytesSent(bool success) { + DCHECK(thread_checker_.CalledOnValidThread()); + + if (!success) { + CompleteCommand(BATTOR_ERROR_SEND_ERROR); + return; + } + + switch (last_action_) { + case Action::SEND_RESET: + // Wait for the reset to happen before sending the init message. + PerformDelayedAction(Action::SEND_INIT, base::TimeDelta::FromSeconds( + kBattOrResetTimeSeconds)); + break; + case Action::SEND_INIT: + PerformAction(Action::READ_INIT_ACK); + break; + case Action::SEND_SET_GAIN: + PerformAction(Action::READ_SET_GAIN_ACK); + break; + case Action::SEND_START_TRACING: + PerformAction(Action::READ_START_TRACING_ACK); + break; + default: + CompleteCommand(BATTOR_ERROR_UNEXPECTED_MESSAGE); + } +} + +void BattOrAgent::OnBytesRead(bool success, + BattOrMessageType type, + scoped_ptr<vector<char>> bytes) { + if (!success) { + CompleteCommand(BATTOR_ERROR_RECEIVE_ERROR); + return; + } + + switch (last_action_) { + case Action::READ_INIT_ACK: + if (!IsAckOfControlCommand(type, BATTOR_CONTROL_MESSAGE_TYPE_INIT, + *bytes)) { + CompleteCommand(BATTOR_ERROR_UNEXPECTED_MESSAGE); + return; + } + + PerformAction(Action::SEND_SET_GAIN); + break; + + case Action::READ_SET_GAIN_ACK: + if (!IsAckOfControlCommand(type, BATTOR_CONTROL_MESSAGE_TYPE_SET_GAIN, + *bytes)) { + CompleteCommand(BATTOR_ERROR_UNEXPECTED_MESSAGE); + return; + } + + PerformAction(Action::SEND_START_TRACING); + break; + + case Action::READ_START_TRACING_ACK: + if (!IsAckOfControlCommand( + type, BATTOR_CONTROL_MESSAGE_TYPE_START_SAMPLING_SD, *bytes)) { + CompleteCommand(BATTOR_ERROR_UNEXPECTED_MESSAGE); + return; + } + + CompleteCommand(BATTOR_ERROR_NONE); + return; + + default: + CompleteCommand(BATTOR_ERROR_UNEXPECTED_MESSAGE); + } +} + +void BattOrAgent::PerformAction(Action action) { + DCHECK(thread_checker_.CalledOnValidThread()); + + last_action_ = action; + + switch (action) { + case Action::REQUEST_CONNECTION: + BeginConnect(); + break; + + case Action::SEND_RESET: + // Reset the BattOr to clear any preexisting state. After sending the + // reset signal, we need to wait for the reset to finish before issuing + // further commands. + SendControlMessage(BATTOR_CONTROL_MESSAGE_TYPE_RESET, 0, 0); + break; + case Action::SEND_INIT: + // After resetting the BattOr, we need to make sure to flush the serial + // stream. Strange data may have been written into it during the reset. + connection_->Flush(); + + SendControlMessage(BATTOR_CONTROL_MESSAGE_TYPE_INIT, 0, 0); + break; + case Action::READ_INIT_ACK: + connection_->ReadBytes(sizeof(BattOrControlMessageAck)); + break; + case Action::SEND_SET_GAIN: + // Set the BattOr's gain. Setting the gain tells the BattOr the range of + // power measurements that we expect to see. + SendControlMessage(BATTOR_CONTROL_MESSAGE_TYPE_SET_GAIN, BATTOR_GAIN_LOW, + 0); + break; + case Action::READ_SET_GAIN_ACK: + connection_->ReadBytes(sizeof(BattOrControlMessageAck)); + break; + case Action::SEND_START_TRACING: + SendControlMessage(BATTOR_CONTROL_MESSAGE_TYPE_START_SAMPLING_SD, 0, 0); + break; + case Action::READ_START_TRACING_ACK: + connection_->ReadBytes(sizeof(BattOrControlMessageAck)); + break; + case Action::INVALID: + NOTREACHED(); + } +} + +void BattOrAgent::PerformDelayedAction(Action action, base::TimeDelta delay) { + base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( + FROM_HERE, base::Bind(&BattOrAgent::PerformAction, AsWeakPtr(), action), + delay); +} + +void BattOrAgent::SendControlMessage(BattOrControlMessageType type, + uint16_t param1, + uint16_t param2) { + DCHECK(thread_checker_.CalledOnValidThread()); + + BattOrControlMessage msg{type, param1, param2}; + connection_->SendBytes(BATTOR_MESSAGE_TYPE_CONTROL, &msg, sizeof(msg)); +} + +void BattOrAgent::CompleteCommand(BattOrError error) { + switch (command_) { + case Command::START_TRACING: + listener_->OnStartTracingComplete(error); + break; + case Command::INVALID: + NOTREACHED(); + } + + last_action_ = Action::INVALID; + command_ = Command::INVALID; +} + } // namespace battor
diff --git a/tools/battor_agent/battor_agent.gyp b/tools/battor_agent/battor_agent.gyp index 8aae2b7..4055599 100644 --- a/tools/battor_agent/battor_agent.gyp +++ b/tools/battor_agent/battor_agent.gyp
@@ -52,11 +52,13 @@ '../../base/base.gyp:test_support_base', '../../device/serial/serial.gyp:device_serial', '../../device/serial/serial.gyp:device_serial_test_util', + '../../testing/gmock.gyp:gmock', '../../testing/gtest.gyp:gtest', '../../third_party/mojo/mojo_public.gyp:mojo_environment_standalone', '../../third_party/mojo/mojo_public.gyp:mojo_public', ], 'sources': [ + 'battor_agent_unittest.cc', 'battor_connection_impl_unittest.cc', ], },
diff --git a/tools/battor_agent/battor_agent.h b/tools/battor_agent/battor_agent.h index a008b6c..643c45d 100644 --- a/tools/battor_agent/battor_agent.h +++ b/tools/battor_agent/battor_agent.h
@@ -7,6 +7,7 @@ #include "base/macros.h" #include "base/memory/ref_counted.h" +#include "base/memory/weak_ptr.h" #include "base/threading/thread_checker.h" #include "tools/battor_agent/battor_connection.h" #include "tools/battor_agent/battor_error.h" @@ -27,7 +28,8 @@ // // This class is NOT thread safe, and must be interacted with only from the IO // thread. The IO thread must also have a running MessageLoop. -class BattOrAgent : public BattOrConnection::Listener { +class BattOrAgent : public BattOrConnection::Listener, + public base::SupportsWeakPtr<BattOrAgent> { public: // The listener interface that must be implemented in order to interact with // the BattOrAgent. @@ -37,10 +39,10 @@ }; BattOrAgent( - scoped_refptr<base::SingleThreadTaskRunner> file_thread_task_runner, - scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner, const std::string& path, - Listener* listener); + Listener* listener, + scoped_refptr<base::SingleThreadTaskRunner> file_thread_task_runner, + scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner); virtual ~BattOrAgent(); // Tells the BattOr to start tracing. @@ -50,26 +52,66 @@ // trace log. static bool SupportsExplicitClockSync() { return true; } - // BattOrConnection::Listener implementation. + // BattOrConnection::Listener implementations. void OnConnectionOpened(bool success) override; void OnBytesSent(bool success) override; void OnBytesRead(bool success, BattOrMessageType type, scoped_ptr<std::vector<char>> bytes) override; - private: - // Initializes the serial connection (if not done already). - // OnConnectionOpened() will be called once the connection is made. - void ConnectIfNeeded(); + protected: + // The connection that knows how to communicate with the BattOr in terms of + // protocol primitives. This is protected so that it can be replaced with a + // fake in testing. + scoped_ptr<BattOrConnection> connection_; - // StartTracing continuation called once the connection is initialized. - void DoStartTracing(); + private: + enum class Command { + INVALID, + START_TRACING, + }; + + enum class Action { + INVALID, + + // Actions required to connect to a BattOr. + REQUEST_CONNECTION, + + // Actions required for starting tracing. + SEND_RESET, + SEND_INIT, + READ_INIT_ACK, + SEND_SET_GAIN, + READ_SET_GAIN_ACK, + SEND_START_TRACING, + READ_START_TRACING_ACK, + }; + + // Performs an action. + void PerformAction(Action action); + // Performs an action after a delay. + void PerformDelayedAction(Action action, base::TimeDelta delay); + + // Requests a connection to the BattOr. + void BeginConnect(); + + // Sends a control message over the connection. + void SendControlMessage(BattOrControlMessageType type, + uint16_t param1, + uint16_t param2); + + // Completes the command with the specified error. + void CompleteCommand(BattOrError error); // The listener that handles the commands' results. It must outlive the agent. Listener* listener_; - // The serial connection to the BattOr. - scoped_ptr<BattOrConnection> connection_; + // The last action executed by the agent. This should only be updated in + // PerformAction(). + Action last_action_; + + // The tracing command currently being executed by the agent. + Command command_; // Checker to make sure that this is only ever called on the IO thread. base::ThreadChecker thread_checker_;
diff --git a/tools/battor_agent/battor_agent_bin.cc b/tools/battor_agent/battor_agent_bin.cc index c8a6eb2a..b8c9d27 100644 --- a/tools/battor_agent/battor_agent_bin.cc +++ b/tools/battor_agent/battor_agent_bin.cc
@@ -169,8 +169,8 @@ ExitFromThreadStartFailure(kUiThreadName); } - agent_.reset(new BattOrAgent(file_thread_.task_runner(), - ui_thread_.task_runner(), path, this)); + agent_.reset(new BattOrAgent(path, this, file_thread_.task_runner(), + ui_thread_.task_runner())); error_ = BATTOR_ERROR_NONE; done_.Signal(); }
diff --git a/tools/battor_agent/battor_agent_unittest.cc b/tools/battor_agent/battor_agent_unittest.cc new file mode 100644 index 0000000..41571196 --- /dev/null +++ b/tools/battor_agent/battor_agent_unittest.cc
@@ -0,0 +1,334 @@ +// 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 "tools/battor_agent/battor_agent.h" + +#include "base/test/test_simple_task_runner.h" +#include "base/thread_task_runner_handle.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "tools/battor_agent/battor_protocol_types.h" + +using namespace testing; + +namespace battor { + +namespace { + +BattOrControlMessageAck kInitAck{BATTOR_CONTROL_MESSAGE_TYPE_INIT, 0}; +BattOrControlMessageAck kSetGainAck{BATTOR_CONTROL_MESSAGE_TYPE_SET_GAIN, 0}; +BattOrControlMessageAck kStartTracingAck{ + BATTOR_CONTROL_MESSAGE_TYPE_START_SAMPLING_SD, 0}; + +// Creates a byte vector copy of the specified ack. +scoped_ptr<std::vector<char>> AckToCharVector(BattOrControlMessageAck ack) { + return scoped_ptr<std::vector<char>>( + new std::vector<char>(reinterpret_cast<char*>(&ack), + reinterpret_cast<char*>(&ack) + sizeof(ack))); +} + +MATCHER_P2( + BufferEq, + expected_buffer, + expected_buffer_size, + "Makes sure that the argument has the same contents as the buffer.") { + return memcmp(reinterpret_cast<const void*>(arg), + reinterpret_cast<const void*>(expected_buffer), + expected_buffer_size) == 0; +} + +class MockBattOrConnection : public BattOrConnection { + public: + MockBattOrConnection(BattOrConnection::Listener* listener) + : BattOrConnection(listener) {} + ~MockBattOrConnection() override {} + + MOCK_METHOD0(Open, void()); + MOCK_METHOD0(Close, void()); + MOCK_METHOD3(SendBytes, + void(BattOrMessageType type, + const void* buffer, + size_t bytes_to_send)); + MOCK_METHOD1(ReadBytes, void(size_t bytes_to_read)); + MOCK_METHOD0(Flush, void()); + + private: + DISALLOW_COPY_AND_ASSIGN(MockBattOrConnection); +}; + +} // namespace + +// TestableBattOrAgent uses a fake BattOrConnection to be testable. +class TestableBattOrAgent : public BattOrAgent { + public: + TestableBattOrAgent(BattOrAgent::Listener* listener) + : BattOrAgent("/dev/test", listener, nullptr, nullptr) { + connection_ = scoped_ptr<BattOrConnection>(new MockBattOrConnection(this)); + } + + MockBattOrConnection* GetConnection() { + return static_cast<MockBattOrConnection*>(connection_.get()); + } +}; + +// BattOrAgentTest provides a BattOrAgent and captures the results of its +// tracing commands. +class BattOrAgentTest : public testing::Test, public BattOrAgent::Listener { + public: + BattOrAgentTest() + : task_runner_(new base::TestSimpleTaskRunner()), + thread_task_runner_handle_(task_runner_) {} + + void OnStartTracingComplete(BattOrError error) override { + is_start_tracing_complete_ = true; + start_tracing_error_ = error; + } + + protected: + void SetUp() override { + agent_.reset(new TestableBattOrAgent(this)); + task_runner_->ClearPendingTasks(); + is_start_tracing_complete_ = false; + } + + // Possible states that the BattOrAgent can be in. + enum class BattOrAgentState { + CONNECTED, + RESET_SENT, + INIT_SENT, + INIT_ACKED, + SET_GAIN_SENT, + GAIN_ACKED, + START_TRACING_SENT, + START_TRACING_COMPLETE, + }; + + // Runs BattOrAgent::StartTracing until it reaches the specified state by + // feeding it the callbacks it needs to progress. + void RunStartTracingTo(BattOrAgentState end_state) { + GetAgent()->StartTracing(); + GetTaskRunner()->RunUntilIdle(); + + GetAgent()->OnConnectionOpened(true); + GetTaskRunner()->RunUntilIdle(); + + if (end_state == BattOrAgentState::CONNECTED) + return; + + GetAgent()->OnBytesSent(true); + GetTaskRunner()->RunUntilIdle(); + + if (end_state == BattOrAgentState::RESET_SENT) + return; + + GetAgent()->OnBytesSent(true); + GetTaskRunner()->RunUntilIdle(); + + if (end_state == BattOrAgentState::INIT_SENT) + return; + + GetAgent()->OnBytesRead(true, BATTOR_MESSAGE_TYPE_CONTROL_ACK, + AckToCharVector(kInitAck)); + GetTaskRunner()->RunUntilIdle(); + + if (end_state == BattOrAgentState::INIT_ACKED) + return; + + GetAgent()->OnBytesSent(true); + GetTaskRunner()->RunUntilIdle(); + + if (end_state == BattOrAgentState::SET_GAIN_SENT) + return; + + GetAgent()->OnBytesRead(true, BATTOR_MESSAGE_TYPE_CONTROL_ACK, + AckToCharVector(kSetGainAck)); + GetTaskRunner()->RunUntilIdle(); + + if (end_state == BattOrAgentState::GAIN_ACKED) + return; + + GetAgent()->OnBytesSent(true); + GetTaskRunner()->RunUntilIdle(); + + if (end_state == BattOrAgentState::START_TRACING_SENT) + return; + + // Make sure that we're actually forwarding to a state in the start tracing + // state machine. + DCHECK(end_state == BattOrAgentState::START_TRACING_COMPLETE); + + GetAgent()->OnBytesRead(true, BATTOR_MESSAGE_TYPE_CONTROL_ACK, + AckToCharVector(kStartTracingAck)); + GetTaskRunner()->RunUntilIdle(); + } + + TestableBattOrAgent* GetAgent() { return agent_.get(); } + + scoped_refptr<base::TestSimpleTaskRunner> GetTaskRunner() { + return task_runner_; + } + + BattOrError GetStartTracingError() { return start_tracing_error_; } + + bool IsStartTracingComplete() { return is_start_tracing_complete_; } + + private: + scoped_refptr<base::TestSimpleTaskRunner> task_runner_; + // Needed to support ThreadTaskRunnerHandle::Get() in code under test. + base::ThreadTaskRunnerHandle thread_task_runner_handle_; + + scoped_ptr<TestableBattOrAgent> agent_; + bool is_start_tracing_complete_; + + BattOrError start_tracing_error_; +}; + +TEST_F(BattOrAgentTest, StartTracing) { + testing::InSequence s; + EXPECT_CALL(*GetAgent()->GetConnection(), Open()); + + BattOrControlMessage reset_msg{BATTOR_CONTROL_MESSAGE_TYPE_RESET, 0, 0}; + EXPECT_CALL( + *GetAgent()->GetConnection(), + SendBytes(BATTOR_MESSAGE_TYPE_CONTROL, + BufferEq(&reset_msg, sizeof(reset_msg)), sizeof(reset_msg))); + + EXPECT_CALL(*GetAgent()->GetConnection(), Flush()); + BattOrControlMessage init_msg{BATTOR_CONTROL_MESSAGE_TYPE_INIT, 0, 0}; + EXPECT_CALL( + *GetAgent()->GetConnection(), + SendBytes(BATTOR_MESSAGE_TYPE_CONTROL, + BufferEq(&init_msg, sizeof(init_msg)), sizeof(init_msg))); + + EXPECT_CALL(*GetAgent()->GetConnection(), ReadBytes(sizeof(kInitAck))); + + BattOrControlMessage set_gain_msg{BATTOR_CONTROL_MESSAGE_TYPE_SET_GAIN, + BATTOR_GAIN_LOW, 0}; + EXPECT_CALL(*GetAgent()->GetConnection(), + SendBytes(BATTOR_MESSAGE_TYPE_CONTROL, + BufferEq(&set_gain_msg, sizeof(set_gain_msg)), + sizeof(set_gain_msg))); + + EXPECT_CALL(*GetAgent()->GetConnection(), ReadBytes(sizeof(kSetGainAck))); + + BattOrControlMessage start_tracing_msg{ + BATTOR_CONTROL_MESSAGE_TYPE_START_SAMPLING_SD, 0, 0}; + EXPECT_CALL(*GetAgent()->GetConnection(), + SendBytes(BATTOR_MESSAGE_TYPE_CONTROL, + BufferEq(&start_tracing_msg, sizeof(start_tracing_msg)), + sizeof(start_tracing_msg))); + + EXPECT_CALL(*GetAgent()->GetConnection(), + ReadBytes(sizeof(kStartTracingAck))); + + RunStartTracingTo(BattOrAgentState::START_TRACING_COMPLETE); + EXPECT_TRUE(IsStartTracingComplete()); + EXPECT_EQ(BATTOR_ERROR_NONE, GetStartTracingError()); +} + +TEST_F(BattOrAgentTest, StartTracingFailsWithoutConnection) { + GetAgent()->StartTracing(); + GetTaskRunner()->RunUntilIdle(); + + GetAgent()->OnConnectionOpened(false); + GetTaskRunner()->RunUntilIdle(); + + EXPECT_TRUE(IsStartTracingComplete()); + EXPECT_EQ(BATTOR_ERROR_CONNECTION_FAILED, GetStartTracingError()); +} + +TEST_F(BattOrAgentTest, StartTracingFailsIfResetSendFails) { + RunStartTracingTo(BattOrAgentState::CONNECTED); + GetAgent()->OnBytesSent(false); + GetTaskRunner()->RunUntilIdle(); + + EXPECT_TRUE(IsStartTracingComplete()); + EXPECT_EQ(BATTOR_ERROR_SEND_ERROR, GetStartTracingError()); +} + +TEST_F(BattOrAgentTest, StartTracingFailsIfInitSendFails) { + RunStartTracingTo(BattOrAgentState::RESET_SENT); + GetAgent()->OnBytesSent(false); + GetTaskRunner()->RunUntilIdle(); + + EXPECT_TRUE(IsStartTracingComplete()); + EXPECT_EQ(BATTOR_ERROR_SEND_ERROR, GetStartTracingError()); +} + +TEST_F(BattOrAgentTest, StartTracingFailsIfInitAckReadFails) { + RunStartTracingTo(BattOrAgentState::INIT_SENT); + GetAgent()->OnBytesRead(false, BATTOR_MESSAGE_TYPE_CONTROL_ACK, nullptr); + GetTaskRunner()->RunUntilIdle(); + + EXPECT_TRUE(IsStartTracingComplete()); + EXPECT_EQ(BATTOR_ERROR_RECEIVE_ERROR, GetStartTracingError()); +} + +TEST_F(BattOrAgentTest, StartTracingFailsIfInitWrongAckRead) { + RunStartTracingTo(BattOrAgentState::INIT_SENT); + GetAgent()->OnBytesRead(true, BATTOR_MESSAGE_TYPE_CONTROL_ACK, + AckToCharVector(kStartTracingAck)); + GetTaskRunner()->RunUntilIdle(); + + EXPECT_TRUE(IsStartTracingComplete()); + EXPECT_EQ(BATTOR_ERROR_UNEXPECTED_MESSAGE, GetStartTracingError()); +} + +TEST_F(BattOrAgentTest, StartTracingFailsIfSetGainSendFails) { + RunStartTracingTo(BattOrAgentState::RESET_SENT); + GetAgent()->OnBytesSent(false); + GetTaskRunner()->RunUntilIdle(); + + EXPECT_TRUE(IsStartTracingComplete()); + EXPECT_EQ(BATTOR_ERROR_SEND_ERROR, GetStartTracingError()); +} + +TEST_F(BattOrAgentTest, StartTracingFailsIfSetGainAckReadFails) { + RunStartTracingTo(BattOrAgentState::SET_GAIN_SENT); + GetAgent()->OnBytesRead(false, BATTOR_MESSAGE_TYPE_CONTROL_ACK, nullptr); + GetTaskRunner()->RunUntilIdle(); + + EXPECT_TRUE(IsStartTracingComplete()); + EXPECT_EQ(BATTOR_ERROR_RECEIVE_ERROR, GetStartTracingError()); +} + +TEST_F(BattOrAgentTest, StartTracingFailsIfSetGainWrongAckRead) { + RunStartTracingTo(BattOrAgentState::SET_GAIN_SENT); + GetAgent()->OnBytesRead(true, BATTOR_MESSAGE_TYPE_CONTROL_ACK, + AckToCharVector(kStartTracingAck)); + GetTaskRunner()->RunUntilIdle(); + + EXPECT_TRUE(IsStartTracingComplete()); + EXPECT_EQ(BATTOR_ERROR_UNEXPECTED_MESSAGE, GetStartTracingError()); +} + +TEST_F(BattOrAgentTest, StartTracingFailsIfStartTracingSendFails) { + RunStartTracingTo(BattOrAgentState::RESET_SENT); + GetAgent()->OnBytesSent(false); + GetTaskRunner()->RunUntilIdle(); + + EXPECT_TRUE(IsStartTracingComplete()); + EXPECT_EQ(BATTOR_ERROR_SEND_ERROR, GetStartTracingError()); +} + +TEST_F(BattOrAgentTest, StartTracingFailsIfStartTracingAckReadFails) { + RunStartTracingTo(BattOrAgentState::START_TRACING_SENT); + GetAgent()->OnBytesRead(false, BATTOR_MESSAGE_TYPE_CONTROL_ACK, nullptr); + GetTaskRunner()->RunUntilIdle(); + + EXPECT_TRUE(IsStartTracingComplete()); + EXPECT_EQ(BATTOR_ERROR_RECEIVE_ERROR, GetStartTracingError()); +} + +TEST_F(BattOrAgentTest, StartTracingFailsIfStartTracingWrongAckRead) { + RunStartTracingTo(BattOrAgentState::START_TRACING_SENT); + GetAgent()->OnBytesRead(true, BATTOR_MESSAGE_TYPE_CONTROL_ACK, + AckToCharVector(kInitAck)); + GetTaskRunner()->RunUntilIdle(); + + EXPECT_TRUE(IsStartTracingComplete()); + EXPECT_EQ(BATTOR_ERROR_UNEXPECTED_MESSAGE, GetStartTracingError()); +} + +} // namespace battor
diff --git a/tools/checklicenses/checklicenses.py b/tools/checklicenses/checklicenses.py index 28ae32ad..54482a39 100755 --- a/tools/checklicenses/checklicenses.py +++ b/tools/checklicenses/checklicenses.py
@@ -31,72 +31,73 @@ WHITELISTED_LICENSES = [ - 'Anti-Grain Geometry', - 'Apache (v2.0)', - 'Apache (v2.0) BSD (2 clause)', - 'Apache (v2.0) GPL (v2)', - 'Apple MIT', # https://fedoraproject.org/wiki/Licensing/Apple_MIT_License - 'APSL (v2)', 'APSL (v2) BSD (4 clause)', - 'BSD', - 'BSD (2 clause)', + 'APSL (v2)', + 'Anti-Grain Geometry', + 'Apache (v2.0) BSD (2 clause)', + 'Apache (v2.0) BSD-like', + 'Apache (v2.0) GPL (v2)', + 'Apache (v2.0)', + 'Apple MIT', # https://fedoraproject.org/wiki/Licensing/Apple_MIT_License 'BSD (2 clause) ISC', 'BSD (2 clause) MIT/X11 (BSD like)', - 'BSD (3 clause)', + 'BSD (2 clause)', 'BSD (3 clause) GPL (v2)', 'BSD (3 clause) ISC', 'BSD (3 clause) LGPL (v2 or later)', 'BSD (3 clause) LGPL (v2.1 or later)', 'BSD (3 clause) MIT/X11 (BSD like)', + 'BSD (3 clause)', 'BSD (4 clause)', + 'BSD', 'BSD-like', # TODO(phajdan.jr): Make licensecheck not print BSD-like twice. - 'BSD-like MIT/X11 (BSD like)', 'BSD MIT/X11 (BSD like)', + 'BSD-like MIT/X11 (BSD like)', 'BSL (v1.0)', - 'FreeType (BSD like)', 'FreeType (BSD like) with patent clause', - 'GPL (v2) LGPL (v2.1 or later)', + 'FreeType (BSD like)', 'GPL (v2 or later) with Bison parser exception', 'GPL (v2 or later) with libtool exception', + 'GPL (v2) LGPL (v2.1 or later)', 'GPL (v3 or later) with Bison parser exception', 'GPL with Bison parser exception', - 'Independent JPEG Group License', 'ISC', + 'Independent JPEG Group License', 'LGPL (unversioned/unknown version)', - 'LGPL (v2)', 'LGPL (v2 or later)', - 'LGPL (v2.1)', + 'LGPL (v2)', 'LGPL (v2.1 or later)', + 'LGPL (v2.1)', 'LGPL (v3 or later)', - 'MIT/X11 (BSD like)', 'MIT/X11 (BSD like) LGPL (v2.1 or later)', + 'MIT/X11 (BSD like)', 'MPL (v1.0) LGPL (v2 or later)', - 'MPL (v1.1)', 'MPL (v1.1) BSD (3 clause) GPL (v2) LGPL (v2.1 or later)', 'MPL (v1.1) BSD (3 clause) LGPL (v2.1 or later)', - 'MPL (v1.1) BSD-like', 'MPL (v1.1) BSD-like GPL (unversioned/unknown version)', 'MPL (v1.1) BSD-like GPL (v2) LGPL (v2.1 or later)', - 'MPL (v1.1) GPL (v2)', + 'MPL (v1.1) BSD-like', + 'MPL (v1.1) GPL (unversioned/unknown version)', 'MPL (v1.1) GPL (v2) LGPL (v2 or later)', 'MPL (v1.1) GPL (v2) LGPL (v2.1 or later)', - 'MPL (v1.1) GPL (unversioned/unknown version)', + 'MPL (v1.1) GPL (v2)', 'MPL (v1.1) LGPL (v2 or later)', 'MPL (v1.1) LGPL (v2.1 or later)', + 'MPL (v1.1)', 'MPL (v2.0)', 'Ms-PL', - 'Public domain', - 'Public domain BSD', 'Public domain BSD (3 clause)', + 'Public domain BSD', 'Public domain BSD-like', 'Public domain LGPL (v2.1 or later)', - 'libpng', - 'zlib/libpng', + 'Public domain', 'SGI Free Software License B', 'SunSoft (BSD like)', + 'libpng', + 'zlib/libpng', 'University of Illinois/NCSA Open Source License (BSD like)', ('University of Illinois/NCSA Open Source License (BSD like) ' 'MIT/X11 (BSD like)'),
diff --git a/tools/chrome_proxy/chrome_proxy_config.py b/tools/chrome_proxy/chrome_proxy_config.py new file mode 100644 index 0000000..35846e8c --- /dev/null +++ b/tools/chrome_proxy/chrome_proxy_config.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. + +import os +import sys + +sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir, 'perf')) + +from chrome_telemetry_build import chromium_config + +_top_level_dir = os.path.dirname(os.path.realpath(__file__)) + +CONFIG = chromium_config.ChromiumConfig( + top_level_dir=_top_level_dir, + benchmark_dirs=[os.path.join(_top_level_dir, 'integration_tests')])
diff --git a/tools/chrome_proxy/common/network_metrics.py b/tools/chrome_proxy/common/network_metrics.py index 10f70c5..1355dc9c 100644 --- a/tools/chrome_proxy/common/network_metrics.py +++ b/tools/chrome_proxy/common/network_metrics.py
@@ -7,11 +7,17 @@ import hashlib import io import logging +import os +import sys import zlib from common import inspector_network -from metrics import Metric from telemetry.timeline import model + +sys.path.append( + os.path.join(os.path.dirname(__file__), os.pardir, os.pardir, 'perf')) +from metrics import Metric + from telemetry.page import page_test # All network metrics are Chrome only for now. from telemetry.value import scalar
diff --git a/tools/chrome_proxy/integration_tests/chrome_proxy_benchmark.py b/tools/chrome_proxy/integration_tests/chrome_proxy_benchmark.py index dd4f3b6..759c94c 100644 --- a/tools/chrome_proxy/integration_tests/chrome_proxy_benchmark.py +++ b/tools/chrome_proxy/integration_tests/chrome_proxy_benchmark.py
@@ -71,6 +71,36 @@ return 'chrome_proxy_benchmark.bypass.bypass' +class ChromeProxyHTTPSBypass(ChromeProxyBenchmark): + tag = 'https_bypass' + test = measurements.ChromeProxyHTTPSBypass + page_set = pagesets.HTTPSBypassStorySet + + @classmethod + def Name(cls): + return 'chrome_proxy_benchmark.https_bypass.https_bypass' + + +class ChromeProxyHTML5Test(ChromeProxyBenchmark): + tag = 'html5test' + test = measurements.ChromeProxyHTML5Test + page_set = pagesets.HTML5TestStorySet + + @classmethod + def Name(cls): + return 'chrome_proxy_benchmark.html5test.html5test' + + +class ChromeProxyYouTube(ChromeProxyBenchmark): + tag = 'youtube' + test = measurements.ChromeProxyYouTube + page_set = pagesets.YouTubeStorySet + + @classmethod + def Name(cls): + return 'chrome_proxy_benchmark.youtube.youtube' + + class ChromeProxyCorsBypass(ChromeProxyBenchmark): tag = 'bypass' test = measurements.ChromeProxyCorsBypass
diff --git a/tools/chrome_proxy/integration_tests/chrome_proxy_measurements.py b/tools/chrome_proxy/integration_tests/chrome_proxy_measurements.py index 5261add..61ebe23 100644 --- a/tools/chrome_proxy/integration_tests/chrome_proxy_measurements.py +++ b/tools/chrome_proxy/integration_tests/chrome_proxy_measurements.py
@@ -62,6 +62,42 @@ self._metrics.AddResultsForBypass(tab, results) +class ChromeProxyHTTPSBypass(ChromeProxyValidation): + """Correctness measurement for bypass responses.""" + + def __init__(self): + super(ChromeProxyHTTPSBypass, self).__init__( + restart_after_each_page=True, + metrics=metrics.ChromeProxyMetric()) + + def AddResults(self, tab, results): + self._metrics.AddResultsForHTTPSBypass(tab, results) + + +class ChromeProxyYouTube(ChromeProxyValidation): + """Correctness measurement for youtube video playback.""" + + def __init__(self): + super(ChromeProxyYouTube, self).__init__( + restart_after_each_page=True, + metrics=metrics.ChromeProxyMetric()) + + def AddResults(self, tab, results): + self._metrics.AddResultsForYouTube(tab, results) + + +class ChromeProxyHTML5Test(ChromeProxyValidation): + """Correctness measurement for html5test page.""" + + def __init__(self): + super(ChromeProxyHTML5Test, self).__init__( + restart_after_each_page=True, + metrics=metrics.ChromeProxyMetric()) + + def AddResults(self, tab, results): + self._metrics.AddResultsForHTML5Test(tab, results) + + class ChromeProxyCorsBypass(ChromeProxyValidation): """Correctness measurement for bypass responses for CORS requests."""
diff --git a/tools/chrome_proxy/integration_tests/chrome_proxy_metrics.py b/tools/chrome_proxy/integration_tests/chrome_proxy_metrics.py index d7578d97..8ec7f81 100644 --- a/tools/chrome_proxy/integration_tests/chrome_proxy_metrics.py +++ b/tools/chrome_proxy/integration_tests/chrome_proxy_metrics.py
@@ -321,6 +321,42 @@ results.AddValue(scalar.ScalarValue( results.current_page, 'pass_through_size', 'bytes', pass_through_size)) + def AddResultsForHTTPSBypass(self, tab, results): + bypass_count = 0 + + for resp in self.IterResponses(tab): + # Only check https url's + if "https://" not in resp.response.url: + continue + + # If a Chrome Proxy Via appears fail the test + if resp.HasChromeProxyViaHeader(): + r = resp.response + raise ChromeProxyMetricException, ( + '%s: Should not have Via header (%s) (refer=%s, status=%d)' % ( + r.url, r.GetHeader('Via'), r.GetHeader('Referer'), r.status)) + bypass_count += 1 + + + if bypass_count == 0: + raise ChromeProxyMetricException, ( + 'Expected at least one https response was expected, but zero such ' + 'responses were received.') + + results.AddValue(scalar.ScalarValue( + results.current_page, 'bypass', 'count', bypass_count)) + + def AddResultsForHTML5Test(self, tab, results): + # Wait for the number of "points" of HTML5 compatibility to appear to verify + # the HTML5 elements have loaded successfully. + tab.WaitForJavaScriptExpression( + 'document.getElementsByClassName("pointsPanel")', 15) + + def AddResultsForYouTube(self, tab, results): + # Wait for the video to begin playing. + tab.WaitForJavaScriptExpression( + 'window.playerState == YT.PlayerState.PLAYING', 30) + def AddResultsForBypass(self, tab, results, url_pattern=""): bypass_count = 0 skipped_count = 0
diff --git a/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/html5test.py b/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/html5test.py new file mode 100644 index 0000000..00139cf --- /dev/null +++ b/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/html5test.py
@@ -0,0 +1,27 @@ +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +from telemetry.page import page as page_module +from telemetry import story + + +class HTML5TestPage(page_module.Page): + + def __init__(self, url, page_set): + super(HTML5TestPage, self).__init__(url=url, page_set=page_set) + + +class HTML5TestStorySet(story.StorySet): + + """ Chrome proxy test page for traffic over https. """ + + def __init__(self): + super(HTML5TestStorySet, self).__init__() + + urls_list = [ + 'http://html5test.com/', + ] + + for url in urls_list: + self.AddStory(HTML5TestPage(url, self))
diff --git a/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/https_bypass.py b/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/https_bypass.py new file mode 100644 index 0000000..69235d88 --- /dev/null +++ b/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/https_bypass.py
@@ -0,0 +1,27 @@ +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +from telemetry.page import page as page_module +from telemetry import story + + +class HTTPSBypassPage(page_module.Page): + + def __init__(self, url, page_set): + super(HTTPSBypassPage, self).__init__(url=url, page_set=page_set) + + +class HTTPSBypassStorySet(story.StorySet): + + """ Chrome proxy test page for traffic over https. """ + + def __init__(self): + super(HTTPSBypassStorySet, self).__init__() + + urls_list = [ + 'https://check.googlezip.net/test.html', + ] + + for url in urls_list: + self.AddStory(HTTPSBypassPage(url, self))
diff --git a/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/youtube.py b/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/youtube.py new file mode 100644 index 0000000..e4397bf --- /dev/null +++ b/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/youtube.py
@@ -0,0 +1,27 @@ +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +from telemetry.page import page as page_module +from telemetry import story + + +class YouTubePage(page_module.Page): + + def __init__(self, url, page_set): + super(YouTubePage, self).__init__(url=url, page_set=page_set) + + +class YouTubeStorySet(story.StorySet): + + """ Chrome proxy test site to verify YouTube functionality. """ + + def __init__(self): + super(YouTubeStorySet, self).__init__() + + urls_list = [ + 'http://data-saver-test.appspot.com/youtube', + ] + + for url in urls_list: + self.AddStory(YouTubePage(url, self))
diff --git a/tools/chrome_proxy/run_benchmark b/tools/chrome_proxy/run_benchmark index 7d5a3f7..e6bcbde 100755 --- a/tools/chrome_proxy/run_benchmark +++ b/tools/chrome_proxy/run_benchmark
@@ -7,14 +7,11 @@ import sys sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir, 'telemetry')) -sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir, 'perf')) from telemetry import benchmark_runner +import chrome_proxy_config + if __name__ == '__main__': - top_level_dir = os.path.dirname(os.path.realpath(__file__)) - config = benchmark_runner.ProjectConfig( - top_level_dir=top_level_dir, - benchmark_dirs=[os.path.join(top_level_dir, 'integration_tests')]) - sys.exit(benchmark_runner.main(config)) + sys.exit(benchmark_runner.main(chrome_proxy_config.CONFIG))
diff --git a/tools/chrome_proxy/run_livetests b/tools/chrome_proxy/run_livetests index 6c177719..e6bcbde 100755 --- a/tools/chrome_proxy/run_livetests +++ b/tools/chrome_proxy/run_livetests
@@ -7,14 +7,11 @@ import sys sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir, 'telemetry')) -sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir, 'perf')) from telemetry import benchmark_runner +import chrome_proxy_config + if __name__ == '__main__': - top_level_dir = os.path.dirname(os.path.realpath(__file__)) - config = benchmark_runner.ProjectConfig( - top_level_dir=top_level_dir, - benchmark_dirs=[os.path.join(top_level_dir, 'live_tests')]) - sys.exit(benchmark_runner.main(config)) + sys.exit(benchmark_runner.main(chrome_proxy_config.CONFIG))
diff --git a/tools/chrome_proxy/run_tests b/tools/chrome_proxy/run_tests index aff7dcd..027a323 100755 --- a/tools/chrome_proxy/run_tests +++ b/tools/chrome_proxy/run_tests
@@ -9,22 +9,14 @@ """ import os -import subprocess import sys +sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir, 'telemetry')) + +from telemetry.testing import unittest_runner + +import chrome_proxy_config + if __name__ == '__main__': - proxy_dir = os.path.dirname(os.path.realpath(__file__)) - perf_dir = os.path.realpath(os.path.join(proxy_dir, '..', 'perf')) - telemetry_dir = os.path.realpath(os.path.join(proxy_dir, '..', 'telemetry')) - - env = os.environ.copy() - if 'PYTHONPATH' in env: - env['PYTHONPATH'] = env['PYTHONPATH'] + os.pathsep + telemetry_dir - else: - env['PYTHONPATH'] = telemetry_dir - - path_to_run_tests = os.path.join(telemetry_dir, 'telemetry', 'testing', - 'run_tests.py') - argv = ['--top-level-dir', proxy_dir, '--path', perf_dir] + sys.argv[1:] - sys.exit(subprocess.call([sys.executable, path_to_run_tests] + argv, env=env)) + sys.exit(unittest_runner.Run(chrome_proxy_config.CONFIG))
diff --git a/tools/clang/scripts/update.py b/tools/clang/scripts/update.py index 46aa8be..f784c621 100755 --- a/tools/clang/scripts/update.py +++ b/tools/clang/scripts/update.py
@@ -102,6 +102,9 @@ sys.stdout.write('.' * (num_dots - dots_printed)) sys.stdout.flush() dots_printed = num_dots + if bytes_done != total_size: + raise urllib2.URLError("only got %d of %d bytes" % + (bytes_done, total_size)) print ' Done.' return except urllib2.URLError as e:
diff --git a/tools/gn/c_include_iterator_unittest.cc b/tools/gn/c_include_iterator_unittest.cc index 5adbb65..a4278b2 100644 --- a/tools/gn/c_include_iterator_unittest.cc +++ b/tools/gn/c_include_iterator_unittest.cc
@@ -15,8 +15,8 @@ int line, int begin_char, int end_char) { return range.begin().line_number() == line && range.end().line_number() == line && - range.begin().char_offset() == begin_char && - range.end().char_offset() == end_char; + range.begin().column_number() == begin_char && + range.end().column_number() == end_char; } } // namespace
diff --git a/tools/gn/docs/cookbook.md b/tools/gn/docs/cookbook.md index 3f9f1f4b..7bec8cb 100644 --- a/tools/gn/docs/cookbook.md +++ b/tools/gn/docs/cookbook.md
@@ -190,7 +190,7 @@ | `msan` (0/1) | `is_msan` (true/false) | `//build/config/sanitizers/sanitizers.gni` | | `SDKROOT` (Mac) | `sysroot` | `//build/config/sysroot.gni` | | `sysroot` | `sysroot` | `//build/config/sysroot.gni` | -| `target_arch` ("ia32"/"x64"/"arm"/"mipsel") | `target_arch` ("x86"/"x64"/"arm"/"mipsel") | (global) | +| `target_arch` ("ia32"/"x64"/"arm"/"mipsel") | `target_cpu` ("x86"/"x64"/"arm"/"mipsel") | (global) | | `toolkit_views` (0/1) | `toolkit_views` | `//build/config/ui.gni` | | `tsan` (0/1) | `is_tsan` (true/false) | `//build/config/sanitizers/sanitizers.gni` | | `windows_sdk_path` | `windows_sdk_path` | (internal to `//build/config/win/BUILD.gn`) |
diff --git a/tools/gn/err.cc b/tools/gn/err.cc index e10f001e..378fb7e5 100644 --- a/tools/gn/err.cc +++ b/tools/gn/err.cc
@@ -39,13 +39,13 @@ if (range.begin().line_number() < line_number) begin_char = 0; else - begin_char = range.begin().char_offset() - 1; + begin_char = range.begin().column_number() - 1; int end_char; if (range.end().line_number() > line_number) end_char = static_cast<int>(line->size()); // Ending is non-inclusive. else - end_char = range.end().char_offset() - 1; + end_char = range.end().column_number() - 1; CHECK(end_char >= begin_char); CHECK(begin_char >= 0 && begin_char <= static_cast<int>(line->size())); @@ -71,9 +71,9 @@ // Allow the marker to be one past the end of the line for marking the end. highlight.push_back(' '); - CHECK(location.char_offset() - 1 >= 0 && - location.char_offset() - 1 < static_cast<int>(highlight.size())); - highlight[location.char_offset() - 1] = '^'; + CHECK(location.column_number() - 1 >= 0 && + location.column_number() - 1 < static_cast<int>(highlight.size())); + highlight[location.column_number() - 1] = '^'; // Trim unused spaces from end of line. while (!highlight.empty() && highlight[highlight.size() - 1] == ' ')
diff --git a/tools/gn/function_rebase_path.cc b/tools/gn/function_rebase_path.cc index 6661d81..ef5ef40f 100644 --- a/tools/gn/function_rebase_path.cc +++ b/tools/gn/function_rebase_path.cc
@@ -144,7 +144,7 @@ " relative to the source root, so can't also generate source-absolute\n" " paths without more special-cases.\n" "\n" - "Arguments:\n" + "Arguments\n" "\n" " input\n" " A string or list of strings representing file or directory names\n" @@ -175,6 +175,12 @@ " names will be converted to be relative to the requested output\n" " System-absolute paths will be unchanged.\n" "\n" + " Whether an output path will end in a slash will match whether the\n" + " corresponding input path ends in a slash. It will return \".\" or\n" + " \"./\" (depending on whether the input ends in a slash) to avoid\n" + " returning empty strings. This means if you want a root path\n" + " (\"//\" or \"/\") not ending in a slash, you can add a dot (\"//.\").\n" + "\n" "Example\n" "\n" " # Convert a file in the current directory to be relative to the build\n"
diff --git a/tools/gn/header_checker.cc b/tools/gn/header_checker.cc index 05b624ca..ada9d70 100644 --- a/tools/gn/header_checker.cc +++ b/tools/gn/header_checker.cc
@@ -63,11 +63,11 @@ return LocationRange(Location(clone_input_file, range.begin().line_number(), - range.begin().char_offset(), + range.begin().column_number(), -1 /* TODO(scottmg) */), Location(clone_input_file, range.end().line_number(), - range.end().char_offset(), + range.end().column_number(), -1 /* TODO(scottmg) */)); }
diff --git a/tools/gn/input_conversion_unittest.cc b/tools/gn/input_conversion_unittest.cc index aff66674..2c4afea 100644 --- a/tools/gn/input_conversion_unittest.cc +++ b/tools/gn/input_conversion_unittest.cc
@@ -126,7 +126,7 @@ ASSERT_TRUE(a_origin); LocationRange a_range = a_origin->GetRange(); EXPECT_EQ(2, a_range.begin().line_number()); - EXPECT_EQ(6, a_range.begin().char_offset()); + EXPECT_EQ(6, a_range.begin().column_number()); const InputFile* a_file = a_range.begin().file(); EXPECT_EQ(input, a_file->contents());
diff --git a/tools/gn/location.cc b/tools/gn/location.cc index 59b99d6..49ca3ff 100644 --- a/tools/gn/location.cc +++ b/tools/gn/location.cc
@@ -13,23 +13,23 @@ Location::Location() : file_(nullptr), line_number_(-1), - char_offset_(-1) { + column_number_(-1) { } Location::Location(const InputFile* file, int line_number, - int char_offset, + int column_number, int byte) : file_(file), line_number_(line_number), - char_offset_(char_offset), + column_number_(column_number), byte_(byte) { } bool Location::operator==(const Location& other) const { return other.file_ == file_ && other.line_number_ == line_number_ && - other.char_offset_ == char_offset_; + other.column_number_ == column_number_; } bool Location::operator!=(const Location& other) const { @@ -38,11 +38,11 @@ bool Location::operator<(const Location& other) const { DCHECK(file_ == other.file_); - return std::tie(line_number_, char_offset_) < - std::tie(other.line_number_, other.char_offset_); + return std::tie(line_number_, column_number_) < + std::tie(other.line_number_, other.column_number_); } -std::string Location::Describe(bool include_char_offset) const { +std::string Location::Describe(bool include_column_number) const { if (!file_) return std::string(); @@ -54,9 +54,9 @@ ret += ":"; ret += base::IntToString(line_number_); - if (include_char_offset) { + if (include_column_number) { ret += ":"; - ret += base::IntToString(char_offset_); + ret += base::IntToString(column_number_); } return ret; }
diff --git a/tools/gn/location.h b/tools/gn/location.h index b56e73d..44d1a6f 100644 --- a/tools/gn/location.h +++ b/tools/gn/location.h
@@ -13,11 +13,11 @@ class Location { public: Location(); - Location(const InputFile* file, int line_number, int char_offset, int byte); + Location(const InputFile* file, int line_number, int column_number, int byte); const InputFile* file() const { return file_; } int line_number() const { return line_number_; } - int char_offset() const { return char_offset_; } + int column_number() const { return column_number_; } int byte() const { return byte_; } bool operator==(const Location& other) const; @@ -27,12 +27,12 @@ // Returns a string with the file, line, and (optionally) the character // offset for this location. If this location is null, returns an empty // string. - std::string Describe(bool include_char_offset) const; + std::string Describe(bool include_column_number) const; private: const InputFile* file_; // Null when unset. int line_number_; // -1 when unset. 1-based. - int char_offset_; // -1 when unset. 1-based. + int column_number_; // -1 when unset. 1-based. int byte_; // Index into the buffer, 0-based. };
diff --git a/tools/gn/parse_tree.cc b/tools/gn/parse_tree.cc index 2c55037..167531c 100644 --- a/tools/gn/parse_tree.cc +++ b/tools/gn/parse_tree.cc
@@ -256,7 +256,7 @@ void AccessorNode::SetNewLocation(int line_number) { Location old = base_.location(); base_.set_location( - Location(old.file(), line_number, old.char_offset(), old.byte())); + Location(old.file(), line_number, old.column_number(), old.byte())); } // BinaryOpNode --------------------------------------------------------------- @@ -483,7 +483,7 @@ void IdentifierNode::SetNewLocation(int line_number) { Location old = value_.location(); value_.set_location( - Location(old.file(), line_number, old.char_offset(), old.byte())); + Location(old.file(), line_number, old.column_number(), old.byte())); } // ListNode ------------------------------------------------------------------- @@ -742,7 +742,7 @@ void LiteralNode::SetNewLocation(int line_number) { Location old = value_.location(); value_.set_location( - Location(old.file(), line_number, old.char_offset(), old.byte())); + Location(old.file(), line_number, old.column_number(), old.byte())); } // UnaryOpNode ----------------------------------------------------------------
diff --git a/tools/gn/parse_tree_unittest.cc b/tools/gn/parse_tree_unittest.cc index b46114f..fba902a9 100644 --- a/tools/gn/parse_tree_unittest.cc +++ b/tools/gn/parse_tree_unittest.cc
@@ -94,7 +94,7 @@ // origin will point to the value assigned to the variable (in this case, the // "13" assigned to "b". EXPECT_EQ(3, err.location().line_number()); - EXPECT_EQ(7, err.location().char_offset()); + EXPECT_EQ(7, err.location().column_number()); } TEST(ParseTree, OriginForDereference) { @@ -111,7 +111,7 @@ // The origin for the "not a string" error message should be where the value // was dereferenced (the "a" on the second line). EXPECT_EQ(2, err.location().line_number()); - EXPECT_EQ(20, err.location().char_offset()); + EXPECT_EQ(20, err.location().column_number()); } TEST(ParseTree, SortRangeExtraction) {
diff --git a/tools/gn/parser.cc b/tools/gn/parser.cc index 79966b8..d3e2f0f 100644 --- a/tools/gn/parser.cc +++ b/tools/gn/parser.cc
@@ -62,7 +62,8 @@ " escape = `\\` ( \"$\" | `\"` | char ) .\n" " BracketExpansion = \"{\" ( identifier | ArrayAccess | ScopeAccess " ") \"}\" .\n" - " expansion = \"$\" ( identifier | BracketExpansion ) .\n" + " Hex = \"0x\" [0-9A-Fa-f][0-9A-Fa-f]\n" + " expansion = \"$\" ( identifier | BracketExpansion | Hex ) .\n" " char = /* any character except \"$\", `\"`, or newline " "*/ .\n" "\n" @@ -74,6 +75,9 @@ "\n" " All other backslashes represent themselves.\n" "\n" + " To insert an arbitrary byte value, use $0xFF. For example, to\n" + " insert a newline character: \"Line one$0x0ALine two\".\n" + "\n" "Punctuation\n" "\n" " The following character sequences represent punctuation:\n"
diff --git a/tools/gn/parser_unittest.cc b/tools/gn/parser_unittest.cc index 39b69b7..b6c2009 100644 --- a/tools/gn/parser_unittest.cc +++ b/tools/gn/parser_unittest.cc
@@ -68,7 +68,7 @@ } EXPECT_EQ(err_line, err.location().line_number()); - EXPECT_EQ(err_char, err.location().char_offset()); + EXPECT_EQ(err_char, err.location().column_number()); } // Expects the tokenizer or parser to identify an error at the given line and @@ -86,7 +86,7 @@ } EXPECT_EQ(err_line, err.location().line_number()); - EXPECT_EQ(err_char, err.location().char_offset()); + EXPECT_EQ(err_char, err.location().column_number()); } } // namespace
diff --git a/tools/gn/setup.cc b/tools/gn/setup.cc index 774d877..459b87b 100644 --- a/tools/gn/setup.cc +++ b/tools/gn/setup.cc
@@ -16,6 +16,7 @@ #include "base/process/launch.h" #include "base/strings/string_split.h" #include "base/strings/string_util.h" +#include "base/strings/sys_string_conversions.h" #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" #include "tools/gn/commands.h" @@ -149,7 +150,38 @@ } #if defined(OS_WIN) + +// Given the path to a batch file that runs Python, extracts the name of the +// executable actually implementing Python. Generally people write a batch file +// to put something named "python" on the path, which then just redirects to +// a python.exe somewhere else. This step decodes that setup. On failure, +// returns empty path. +base::FilePath PythonBatToExe(const base::FilePath& bat_path) { + // Note exciting double-quoting to allow spaces. The /c switch seems to check + // for quotes around the whole thing and then deletes them. If you want to + // quote the first argument in addition (to allow for spaces in the Python + // path, you need *another* set of quotes around that, likewise, we need + // two quotes at the end. + base::string16 command = L"cmd.exe /c \"\""; + command.append(bat_path.value()); + command.append(L"\" -c \"import sys; print sys.executable\"\""); + + std::string python_path; + if (base::GetAppOutput(command, &python_path)) { + base::TrimWhitespaceASCII(python_path, base::TRIM_ALL, &python_path); + + // Python uses the system multibyte code page for sys.executable. + base::FilePath exe_path(base::SysNativeMBToWide(python_path)); + + // Check for reasonable output, cmd may have output an error message. + if (base::PathExists(exe_path)) + return exe_path; + } + return base::FilePath(); +} + const base::char16 kPythonExeName[] = L"python.exe"; +const base::char16 kPythonBatName[] = L"python.bat"; base::FilePath FindWindowsPython() { base::char16 current_directory[MAX_PATH]; @@ -179,6 +211,15 @@ base::FilePath(component).Append(kPythonExeName); if (base::PathExists(candidate_exe)) return candidate_exe; + + // Also allow python.bat, but convert into the .exe. + base::FilePath candidate_bat = + base::FilePath(component).Append(kPythonBatName); + if (base::PathExists(candidate_bat)) { + base::FilePath python_exe = PythonBatToExe(candidate_bat); + if (!python_exe.empty()) + return python_exe; + } } return base::FilePath(); }
diff --git a/tools/gn/string_utils.cc b/tools/gn/string_utils.cc index 5ee12d9..83a98bde 100644 --- a/tools/gn/string_utils.cc +++ b/tools/gn/string_utils.cc
@@ -5,7 +5,9 @@ #include "tools/gn/string_utils.h" #include <stddef.h> +#include <cctype> +#include "base/strings/string_number_conversions.h" #include "tools/gn/err.h" #include "tools/gn/input_file.h" #include "tools/gn/parser.h" @@ -25,12 +27,13 @@ int int_offset = static_cast<int>(offset); Location begin_loc(token.location().file(), token.location().line_number(), - token.location().char_offset() + int_offset + 1, + token.location().column_number() + int_offset + 1, token.location().byte() + int_offset + 1); Location end_loc( token.location().file(), token.location().line_number(), - token.location().char_offset() + int_offset + 1 + static_cast<int>(size), + token.location().column_number() + int_offset + 1 + + static_cast<int>(size), token.location().byte() + int_offset + 1 + static_cast<int>(size)); return Err(LocationRange(begin_loc, end_loc), msg, help); } @@ -131,7 +134,7 @@ // Handles string interpolations: $identifier and ${expression} // -// |*i| is the index into |input| of the $. This will be updated to point to +// |*i| is the index into |input| after the $. This will be updated to point to // the last character consumed on success. The token is the original string // to blame on failure. // @@ -143,13 +146,7 @@ size_t* i, std::string* output, Err* err) { - size_t dollars_index = *i; - (*i)++; - if (*i == size) { - *err = ErrInsideStringToken(token, dollars_index, 1, "$ at end of string.", - "I was expecting an identifier or {...} after the $."); - return false; - } + size_t dollars_index = *i - 1; if (input[*i] == '{') { // Bracketed expression. @@ -203,6 +200,40 @@ end_offset, output, err); } +// Handles a hex literal: $0xFF +// +// |*i| is the index into |input| after the $. This will be updated to point to +// the last character consumed on success. The token is the original string +// to blame on failure. +// +// On failure, returns false and sets the error. On success, appends the +// char with the given hex value to |*output|. +bool AppendHexByte(Scope* scope, + const Token& token, + const char* input, size_t size, + size_t* i, + std::string* output, + Err* err) { + size_t dollars_index = *i - 1; + // "$0" is already known to exist. + if (*i + 3 >= size || input[*i + 1] != 'x' || !std::isxdigit(input[*i + 2]) || + !std::isxdigit(input[*i + 3])) { + *err = ErrInsideStringToken( + token, dollars_index, *i - dollars_index + 1, + "Invalid hex character. Hex values must look like 0xFF."); + return false; + } + int value = 0; + if (!base::HexStringToInt(base::StringPiece(&input[*i + 2], 2), &value)) { + *err = ErrInsideStringToken(token, dollars_index, *i - dollars_index + 1, + "Could not convert hex value."); + return false; + } + *i += 3; + output->push_back(value); + return true; +} + } // namespace bool ExpandStringLiteral(Scope* scope, @@ -235,7 +266,16 @@ } output.push_back(input[i]); } else if (input[i] == '$') { - if (!AppendStringInterpolation(scope, literal, input, size, &i, + i++; + if (i == size) { + *err = ErrInsideStringToken(literal, i - 1, 1, "$ at end of string.", + "I was expecting an identifier, 0xFF, or {...} after the $."); + return false; + } + if (input[i] == '0') { + if (!AppendHexByte(scope, literal, input, size, &i, &output, err)) + return false; + } else if (!AppendStringInterpolation(scope, literal, input, size, &i, &output, err)) return false; } else {
diff --git a/tools/gn/string_utils_unittest.cc b/tools/gn/string_utils_unittest.cc index 4e18eb5..d62e17e 100644 --- a/tools/gn/string_utils_unittest.cc +++ b/tools/gn/string_utils_unittest.cc
@@ -69,6 +69,10 @@ EXPECT_TRUE(CheckExpansionCase("$onescope", "{\n one = 1\n}", true)); EXPECT_TRUE(CheckExpansionCase("$onelist", "[1]", true)); + // Hex values + EXPECT_TRUE(CheckExpansionCase("$0x0AA", "\x0A""A", true)); + EXPECT_TRUE(CheckExpansionCase("$0x0a$0xfF", "\x0A\xFF", true)); + // Errors EXPECT_TRUE(CheckExpansionCase("hello #$", nullptr, false)); EXPECT_TRUE(CheckExpansionCase("hello #$%", nullptr, false)); @@ -76,6 +80,12 @@ EXPECT_TRUE(CheckExpansionCase("hello #${}", nullptr, false)); EXPECT_TRUE(CheckExpansionCase("hello #$nonexistant", nullptr, false)); EXPECT_TRUE(CheckExpansionCase("hello #${unterminated", nullptr, false)); + EXPECT_TRUE(CheckExpansionCase("hex truncated: $0", nullptr, false)); + EXPECT_TRUE(CheckExpansionCase("hex truncated: $0x", nullptr, false)); + EXPECT_TRUE(CheckExpansionCase("hex truncated: $0x0", nullptr, false)); + EXPECT_TRUE(CheckExpansionCase("hex with bad char: $0a", nullptr, false)); + EXPECT_TRUE(CheckExpansionCase("hex with bad char: $0x1z", nullptr, false)); + EXPECT_TRUE(CheckExpansionCase("hex with bad char: $0xz1", nullptr, false)); // Unknown backslash values aren't special. EXPECT_TRUE(CheckExpansionCase("\\", "\\", true));
diff --git a/tools/gn/target.cc b/tools/gn/target.cc index bec13c9..49a22fc 100644 --- a/tools/gn/target.cc +++ b/tools/gn/target.cc
@@ -554,10 +554,8 @@ CheckSourceGenerated(file); for (const SourceFile& file : inputs_) CheckSourceGenerated(file); - for (size_t i = 0; i < all_libs_.size(); i++) { - if (all_libs_[i].is_source_file()) - CheckSourceGenerated(all_libs_[i].source_file()); - } + // TODO(agrieve): Check all_libs_ here as well (those that are source files). + // http://crbug.com/571731 } void Target::CheckSourceGenerated(const SourceFile& source) const {
diff --git a/tools/gn/token.h b/tools/gn/token.h index 45b6e28ce..bf87283 100644 --- a/tools/gn/token.h +++ b/tools/gn/token.h
@@ -68,7 +68,7 @@ location_, Location(location_.file(), location_.line_number(), - location_.char_offset() + static_cast<int>(value_.size()), + location_.column_number() + static_cast<int>(value_.size()), location_.byte() + static_cast<int>(value_.size()))); }
diff --git a/tools/gn/tokenizer.cc b/tools/gn/tokenizer.cc index 4dd71d5..0568bec 100644 --- a/tools/gn/tokenizer.cc +++ b/tools/gn/tokenizer.cc
@@ -74,7 +74,7 @@ err_(err), cur_(0), line_number_(1), - char_in_line_(1) { + column_number_(1) { } Tokenizer::~Tokenizer() { @@ -126,7 +126,8 @@ (tokens_.empty() || tokens_.back().type() != Token::SUFFIX_COMMENT || tokens_.back().location().line_number() + 1 != location.line_number() || - tokens_.back().location().char_offset() != location.char_offset())) { + tokens_.back().location().column_number() != + location.column_number())) { type = Token::LINE_COMMENT; if (!at_end()) // Could be EOF. Advance(); // The current \n. @@ -374,16 +375,16 @@ DCHECK(cur_ < input_.size()); if (IsCurrentNewline()) { line_number_++; - char_in_line_ = 1; + column_number_ = 1; } else { - char_in_line_++; + column_number_++; } cur_++; } Location Tokenizer::GetCurrentLocation() const { return Location( - input_file_, line_number_, char_in_line_, static_cast<int>(cur_)); + input_file_, line_number_, column_number_, static_cast<int>(cur_)); } Err Tokenizer::GetErrorForInvalidToken(const Location& location) const {
diff --git a/tools/gn/tokenizer.h b/tools/gn/tokenizer.h index bf3285b9..9b6ef33c 100644 --- a/tools/gn/tokenizer.h +++ b/tools/gn/tokenizer.h
@@ -82,7 +82,7 @@ size_t cur_; // Byte offset into input buffer. int line_number_; - int char_in_line_; + int column_number_; DISALLOW_COPY_AND_ASSIGN(Tokenizer); };
diff --git a/tools/gritsettings/resource_ids b/tools/gritsettings/resource_ids index 93949e3..9324518c 100644 --- a/tools/gritsettings/resource_ids +++ b/tools/gritsettings/resource_ids
@@ -298,9 +298,6 @@ "includes": [30370], "structures": [30670], }, - "chrome/browser/devtools/device/webrtc/resources.grd": { - "includes": [30820], - }, "chrome/browser/resources/md_policy/policy_resources.grd": { "structures": [30900], },
diff --git a/tools/licenses.py b/tools/licenses.py index a7f64b8..2b91939 100755 --- a/tools/licenses.py +++ b/tools/licenses.py
@@ -47,6 +47,7 @@ os.path.join('third_party','gnu_binutils'), os.path.join('third_party','gold'), os.path.join('third_party','gperf'), + os.path.join('third_party','kasko'), os.path.join('third_party','lighttpd'), os.path.join('third_party','llvm'), os.path.join('third_party','llvm-build'),
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml index 991ceb2..888c1ff 100644 --- a/tools/metrics/actions/actions.xml +++ b/tools/metrics/actions/actions.xml
@@ -131,6 +131,13 @@ <description>Please enter the description of this user action.</description> </action> +<action name="AboutFlags_disable-smooth-scrolling"> + <owner>skobes@chromium.org</owner> + <description> + User flag to disable smooth scroll animations on wheel and keyboard input. + </description> +</action> + <action name="AboutFlags_disable-views-rect-based-targeting"> <owner>Please list the metric's owners. Add more owner tags as needed.</owner> <description>Please enter the description of this user action.</description> @@ -12342,12 +12349,21 @@ </description> </action> +<action name="Signin_Signin_FromUnknownAccessPoint"> + <owner>gogerald@chromium.org</owner> + <description> + Recorded on sign in start from access point + signin_metrics::AccessPoint::ACCESS_POINT_UNKNOWN. + </description> +</action> + <action name="Signin_Signin_FromUnspecifiedAccessPoint"> <owner>gogerald@chromium.org</owner> <description> Recorded on sign in start from access point signin_metrics::AccessPoint::ACCESS_POINT_UNSPECIFIED. </description> + <obsolete>Replaced by Signin_Signin_FromUnknownAccessPoint.</obsolete> </action> <action name="Signin_Signin_FromUserManager">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 2108a81..d1f2d78 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -367,6 +367,16 @@ </summary> </histogram> +<histogram name="AppBanners.MinutesFromFirstVisitToBannerShown" units="minutes"> + <owner>dominickn@chromium.org</owner> + <summary> + App banners promote an application related to the current website, and are + requested specifically through the current page's HTML. This stat tracks + the number of minutes between the first recorded visit to an origin and the + time when the banner is actually shown. + </summary> +</histogram> + <histogram name="AppBanners.UserResponse" enum="AppBannersUserResponse"> <owner>dominickn@chromium.org</owner> <summary> @@ -5041,7 +5051,7 @@ </histogram> <histogram - name="Compositing.RenderPass.AppendQuadData.CheckerboardedNeedsRasterContentArea" + name="Compositing.RenderPass.AppendQuadData.CheckerboardedNeedRasterContentArea" units="pixels/frame"> <owner>weiliangc@chromium.org</owner> <summary> @@ -26097,15 +26107,9 @@ <histogram name="Net.QuicSession.VerifyProofTime" units="milliseconds"> <owner>rtenneti@chromium.org</owner> <summary> - Time spent verifying the signature and certificate chain of a server. - </summary> -</histogram> - -<histogram name="Net.QuicSession.VerifyProofTime.google" units="milliseconds"> - <owner>rtenneti@chromium.org</owner> - <summary> - Time spent verifying the signature and certificate chain for www.google.com - server. + Time spent verifying the signature and certificate chain. This is logged + whenever QUIC verifies the certificate chain and signature during crypto + handshake. </summary> </histogram> @@ -42554,6 +42558,14 @@ </summary> </histogram> +<histogram name="Sdch3.FirstUseInterval" units="milliseconds"> + <owner>rdsmith@chromium.org</owner> + <summary> + The amount of time between creation/load of an SDCH dictionary and its first + use. + </summary> +</histogram> + <histogram name="Sdch3.Network_Decode_1st_To_2nd_c" units="milliseconds"> <owner>rdsmith@chromium.org</owner> <summary> @@ -42908,7 +42920,8 @@ <owner>rdsmith@chromium.org</owner> <summary> The amount of time from the last time an SDCH dictionary was used. Not - recorded on first dictionary use. + recorded on first dictionary use. First use is recorded as + Sdch3.FirstUseInterval. </summary> </histogram> @@ -47588,6 +47601,14 @@ </summary> </histogram> +<histogram name="Startup.SystemUptime" units="milliseconds"> + <owner>fdoray@chromium.org</owner> + <summary> + The time elapsed between system boot and Chrome browser process launch. This + is recorded just before the main message loop starts. + </summary> +</histogram> + <histogram name="Startup.Temperature" enum="StartupTemperature"> <owner>chrisha@chromium.org</owner> <summary> @@ -49596,6 +49617,11 @@ </summary> </histogram> +<histogram name="Tab.AndroidCrashUpload" enum="BooleanSuccess"> + <owner>hzl@google.com</owner> + <summary>Count of upload success/failures by crash type.</summary> +</histogram> + <histogram name="Tab.BackgroundLoadStatus" enum="TabBackgroundLoadStatus"> <owner>ppi@chromium.org</owner> <summary> @@ -56497,18 +56523,19 @@ </enum> <enum name="AudioSampleRate" type="int"> - <int value="0" label="k8000Hz"/> - <int value="1" label="k16000Hz"/> - <int value="2" label="k32000Hz"/> - <int value="3" label="k48000Hz"/> - <int value="4" label="k96000Hz"/> - <int value="5" label="k11025Hz"/> - <int value="6" label="k22050Hz"/> - <int value="7" label="k44100Hz"/> - <int value="8" label="k88200Hz"/> - <int value="9" label="k176400Hz"/> - <int value="10" label="k192000Hz"/> - <int value="11" label="k24000Hz"/> + <int value="0" label="8 kHz"/> + <int value="1" label="16 kHz"/> + <int value="2" label="32 kHz"/> + <int value="3" label="48 kHz"/> + <int value="4" label="96 kHz"/> + <int value="5" label="11.025 kHz"/> + <int value="6" label="22.05 kHz"/> + <int value="7" label="44.1 kHz"/> + <int value="8" label="88.2 kHz"/> + <int value="9" label="176.4 kHz"/> + <int value="10" label="192 kHz"/> + <int value="11" label="24 kHz"/> + <int value="12" label="384 kHz"/> </enum> <enum name="AudioThreadStatus" type="int"> @@ -57017,6 +57044,8 @@ <int value="100" label="BDH_EMPTY_OR_INVALID_FILTERS"/> <int value="101" label="WC_CONTENT_WITH_CERT_ERRORS_BAD_SECURITY_INFO"/> <int value="102" label="RFMF_RENDERER_FAKED_ITS_OWN_DEATH"/> + <int value="103" label="DWNLD_INVALID_SAVABLE_RESOURCE_LINKS_RESPONSE"/> + <int value="104" label="DWNLD_INVALID_SERIALIZE_AS_MHTML_RESPONSE"/> </enum> <enum name="BadMessageReasonExtensions" type="int"> @@ -64925,6 +64954,10 @@ <int value="1093" label="FormNameAccessForNonDescendantImageElement"/> <int value="1094" label="FormControlsCollectionNameAccessForImageElement"/> <int value="1095" label="V8SVGSVGElement_Viewport_AttributeGetter"/> + <int value="1096" label="V8RegExpPrototypeStickyGetter"/> + <int value="1097" label="V8RegExpPrototypeToString"/> + <int value="1098" + label="V8InputDeviceCapabilities_FiresTouchEvents_AttributeGetter"/> </enum> <enum name="FetchRequestMode" type="int"> @@ -68924,6 +68957,7 @@ <int value="-1972383451" label="disable-pinch"/> <int value="-1963402827" label="enable-topchrome-md"/> <int value="-1961648833" label="show_summary"/> + <int value="-1956349722" label="disable-smooth-scrolling"/> <int value="-1946595906" label="enable-push-api-background-mode"/> <int value="-1943507605" label="enable-new-video-renderer"/> <int value="-1941852572" label="floating-virtual-keyboard"/> @@ -76566,7 +76600,7 @@ <int value="14" label="Content area"/> <int value="15" label="Signin promo"/> <int value="16" label="Recent tabs"/> - <int value="17" label="Typed URL w/o specifying access point"/> + <int value="17" label="Typed URL with unknown access point"/> </enum> <enum name="SigninAccountReconcilorState" type="int"> @@ -76638,7 +76672,7 @@ <int value="1" label="Add secondary account"/> <int value="2" label="Reauthentication"/> <int value="3" label="Unlock profile"/> - <int value="4" label="Typed URL w/o specifying reason"/> + <int value="4" label="Typed URL with unknown reason"/> </enum> <enum name="SigninReauthStates" type="int"> @@ -78945,6 +78979,8 @@ <int value="20" label="kSwReporterPromptReason"/> <int value="21" label="kGoogleServicesUsername"/> <int value="22" label="kSwReporterPromptSeed"/> + <int value="23" label="kGoogleServicesAccountId"/> + <int value="24" label="kGoogleServicesLastAccountId"/> </enum> <enum name="TranslateError" type="int"> @@ -80383,6 +80419,14 @@ <affected-histogram name="PLT.StartToFinish_NormalLoad"/> </histogram_suffixes> +<histogram_suffixes name="AndroidCrashUploadTypes"> + <suffix name="Browser" label="Measures browser crash uploads."/> + <suffix name="GPU" label="Measures GPU crash uploads."/> + <suffix name="Other" label="Measures other crash uploads."/> + <suffix name="Renderer" label="Measures renderer crash uploads."/> + <affected-histogram name="Tab.AndroidCrashUpload"/> +</histogram_suffixes> + <histogram_suffixes name="AndroidGetAccountsTypes"> <suffix name="AccountManager" label="Using Android AccountManager API"/> <suffix name="GoogleAuthUtil" label="Using GoogleAuthUtil API"/> @@ -84727,6 +84771,15 @@ <affected-histogram name="Net.QuicSession.Connect"/> </histogram_suffixes> +<histogram_suffixes name="QuicSessionVerifyProofTime" separator="."> + <suffix name="" label="Verification time for a server."/> + <suffix name="google" label="Verification time for www.google.com server."/> + <suffix name="CachedServerConfig" + label="Verification time for a server when server config from cache is + used."/> + <affected-histogram name="Net.QuicSession.VerifyProofTime"/> +</histogram_suffixes> + <histogram_suffixes name="RemoteProcessWarmStartFast" separator=""> <suffix name="" label="Normal start."/> <suffix name="Fast" @@ -85392,6 +85445,7 @@ <affected-histogram name="Startup.LoadTime.ExeMainToDllMain"/> <affected-histogram name="Startup.LoadTime.ProcessCreateToDllMain"/> <affected-histogram name="Startup.LoadTime.ProcessCreateToExeMain"/> + <affected-histogram name="Startup.SystemUptime"/> </histogram_suffixes> <histogram_suffixes name="StartupTimeBombAlarm" separator=".">
diff --git a/tools/perf/BUILD.gn b/tools/perf/BUILD.gn new file mode 100644 index 0000000..1e978616 --- /dev/null +++ b/tools/perf/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. + +group("perf") { + deps = [ + "//tools/perf/chrome_telemetry_build:telemetry_chrome_test", + ] + + data = [ + "//tools/perf/", + + "//build/android/pylib/", + + # Field trial config + "//tools/variations/", + "//testing/variations/", + ] +}
diff --git a/tools/perf/benchmarks/benchmark_smoke_unittest.py b/tools/perf/benchmarks/benchmark_smoke_unittest.py index 10ccdba..3fa90291 100644 --- a/tools/perf/benchmarks/benchmark_smoke_unittest.py +++ b/tools/perf/benchmarks/benchmark_smoke_unittest.py
@@ -18,8 +18,6 @@ from telemetry.testing import options_for_unittests from telemetry.testing import progress_reporter -from benchmarks import blink_style -from benchmarks import dromaeo from benchmarks import image_decoding from benchmarks import indexeddb_perf from benchmarks import jetstream @@ -29,13 +27,10 @@ from benchmarks import octane from benchmarks import rasterize_and_record_micro from benchmarks import repaint -from benchmarks import service_worker from benchmarks import spaceport from benchmarks import speedometer from benchmarks import sunspider from benchmarks import text_selection -from benchmarks import v8 -from benchmarks import webrtc def SmokeTestGenerator(benchmark): @@ -100,11 +95,6 @@ _ANDROID_BLACK_LIST_MODULES = { kraken, # Takes 275 seconds on Android. sunspider, # Takes 163 seconds on Android. - service_worker, # crbug.com/574135 - v8, # crbug.com/574135 - blink_style, # crbug.com/574135 - dromaeo, # crbug.com/574135 - webrtc # crbug.com/574135 }
diff --git a/tools/perf/benchmarks/blink_perf.py b/tools/perf/benchmarks/blink_perf.py index 673c7f8a..dd8aa57 100644 --- a/tools/perf/benchmarks/blink_perf.py +++ b/tools/perf/benchmarks/blink_perf.py
@@ -112,19 +112,6 @@ print log -class _BlinkPerfFullFrameMeasurement(_BlinkPerfMeasurement): - def __init__(self): - super(_BlinkPerfFullFrameMeasurement, self).__init__() - self._blink_perf_js += '\nwindow.fullFrameMeasurement = true;' - - def CustomizeBrowserOptions(self, options): - super(_BlinkPerfFullFrameMeasurement, self).CustomizeBrowserOptions( - options) - # Full layout measurement needs content_shell with internals testing API. - assert 'content-shell' in options.browser_type - options.AppendExtraBrowserArgs(['--expose-internals-for-testing']) - - class _SharedPywebsocketPageState(shared_page_state.SharedPageState): """Runs a pywebsocket server.""" def __init__(self, test, finder_options, user_story_set): @@ -245,16 +232,6 @@ return cls.IsSvelte(possible_browser) # http://crbug.com/551950 -@benchmark.Enabled('content-shell') -class BlinkPerfLayoutFullLayout(BlinkPerfLayout): - tag = 'layout_full_frame' - test = _BlinkPerfFullFrameMeasurement - - @classmethod - def Name(cls): - return 'blink_perf.layout_full_frame' - - class BlinkPerfPaint(perf_benchmark.PerfBenchmark): tag = 'paint' test = _BlinkPerfMeasurement @@ -267,6 +244,10 @@ path = os.path.join(BLINK_PERF_BASE_DIR, 'Paint') return CreateStorySetFromPath(path, SKIPPED_FILE) + @classmethod + def ShouldDisable(cls, possible_browser): + return cls.IsSvelte(possible_browser) # http://crbug.com/574483 + @benchmark.Disabled('win', # crbug.com/488493 'android') # crbug.com/527156 @@ -296,16 +277,6 @@ return CreateStorySetFromPath(path, SKIPPED_FILE) -@benchmark.Enabled('content-shell') -class BlinkPerfSVGFullLayout(BlinkPerfSVG): - tag = 'svg_full_frame' - test = _BlinkPerfFullFrameMeasurement - - @classmethod - def Name(cls): - return 'blink_perf.svg_full_frame' - - class BlinkPerfShadowDOM(perf_benchmark.PerfBenchmark): tag = 'shadow_dom' test = _BlinkPerfMeasurement
diff --git a/tools/perf/benchmarks/page_cycler.py b/tools/perf/benchmarks/page_cycler.py index 5886df2..9d23cf6 100644 --- a/tools/perf/benchmarks/page_cycler.py +++ b/tools/perf/benchmarks/page_cycler.py
@@ -213,6 +213,7 @@ Designed to represent typical, not highly optimized or highly popular web sites. Runs against pages recorded in June, 2014. """ + options = {'pageset_repeat': 3} @classmethod def Name(cls):
diff --git a/tools/perf/benchmarks/smoothness.py b/tools/perf/benchmarks/smoothness.py index b7dc056..37c0e0a 100644 --- a/tools/perf/benchmarks/smoothness.py +++ b/tools/perf/benchmarks/smoothness.py
@@ -510,3 +510,7 @@ @classmethod def Name(cls): return 'smoothness.tough_webgl_ad_cases' + + @classmethod + def ShouldDisable(cls, possible_browser): + return cls.IsSvelte(possible_browser) # http://crbug.com/574485
diff --git a/tools/perf/benchmarks/start_with_url.py b/tools/perf/benchmarks/start_with_url.py index 01606b0..8fd4b63b 100644 --- a/tools/perf/benchmarks/start_with_url.py +++ b/tools/perf/benchmarks/start_with_url.py
@@ -20,7 +20,7 @@ class StartWithUrlColdTBM(startup2._StartupPerfBenchmark): """Measures time to start Chrome cold with startup URLs.""" - page_set = page_sets.StartupPagesPageSetTBM + page_set = page_sets.StartupPagesPageSet options = {'pageset_repeat': 5} def SetExtraBrowserOptions(self, options): @@ -38,7 +38,7 @@ class StartWithUrlWarmTBM(startup2._StartupPerfBenchmark): """Measures stimetime to start Chrome warm with startup URLs.""" - page_set = page_sets.StartupPagesPageSetTBM + page_set = page_sets.StartupPagesPageSet options = {'pageset_repeat': 11} @classmethod
diff --git a/tools/perf/benchmarks/startup.py b/tools/perf/benchmarks/startup.py index c2313a5..08ed081d 100644 --- a/tools/perf/benchmarks/startup.py +++ b/tools/perf/benchmarks/startup.py
@@ -37,6 +37,7 @@ @benchmark.Disabled('snowleopard') # crbug.com/336913 +@benchmark.Disabled('android') class StartupColdBlankPage(_StartupCold): """Measures cold startup time with a clean profile.""" tag = 'cold' @@ -47,6 +48,7 @@ return 'startup.cold.blank_page' +@benchmark.Disabled('android') class StartupWarmBlankPage(_StartupWarm): """Measures warm startup time with a clean profile.""" tag = 'warm'
diff --git a/tools/perf/benchmarks/startup2.py b/tools/perf/benchmarks/startup2.py index 3790c53..be0ac26d 100644 --- a/tools/perf/benchmarks/startup2.py +++ b/tools/perf/benchmarks/startup2.py
@@ -34,6 +34,7 @@ @benchmark.Disabled('snowleopard') # crbug.com/336913 +@benchmark.Disabled('android') class StartupColdBlankPage2(_StartupPerfBenchmark): """Measures cold startup time with a clean profile.""" @@ -49,6 +50,7 @@ super(StartupColdBlankPage2, self).SetExtraBrowserOptions(options) +@benchmark.Disabled('android') class StartupWarmBlankPage2(_StartupPerfBenchmark): """Measures warm startup time with a clean profile."""
diff --git a/tools/perf/core/telemetry_dependencies_unittest.py b/tools/perf/core/telemetry_dependencies_unittest.py index 27f1532..7d107eaf 100644 --- a/tools/perf/core/telemetry_dependencies_unittest.py +++ b/tools/perf/core/telemetry_dependencies_unittest.py
@@ -15,7 +15,6 @@ _TELEMETRY_DEPS = [ 'build/android/devil/', - 'build/android/pylib/', 'third_party/catapult/', 'tools/telemetry/']
diff --git a/tools/perf/core/trybot_command.py b/tools/perf/core/trybot_command.py index 532fb47..855d030f 100644 --- a/tools/perf/core/trybot_command.py +++ b/tools/perf/core/trybot_command.py
@@ -100,9 +100,9 @@ class Trybot(command_line.ArgParseCommand): - """Display help information about a command""" + """ Run telemetry perf benchmark on trybot """ - usage = 'benchmark_name --trybot=<botname> [<benchmark run options>]' + usage = 'botname benchmark_name [<benchmark run options>]' _builders = None def __init__(self): @@ -124,7 +124,8 @@ @classmethod def CreateParser(cls): parser = argparse.ArgumentParser( - 'Run telemetry benchmarks on trybot.', + ('Run telemetry benchmarks on trybot. You can add all the benchmark ' + 'options available except the --browser option'), formatter_class=argparse.RawTextHelpFormatter) return parser @@ -139,12 +140,16 @@ def AddCommandLineArgs(cls, parser, environment): del environment # unused available_bots = _GetTrybotList(cls._GetBuilderList()) - parser.add_argument('benchmark_name', type=str) parser.add_argument( - '--trybot', choices=available_bots, - help=('specify which bots to run telemetry benchmarks on. ' - ' Allowed values are:\n'+'\n'.join(available_bots)), - metavar='') + 'trybot', choices=available_bots, + help=('specify which bots to run telemetry benchmarks on. ' + ' Allowed values are:\n'+'\n'.join(available_bots)), + metavar='<trybot name>') + parser.add_argument( + 'benchmark_name', type=str, + help=('specify which benchmark to run. To see all available benchmarks,' + ' run `run_benchmark list`'), + metavar='<benchmark name>') def Run(self, options, extra_args=None): """Sends a tryjob to a perf trybot.
diff --git a/tools/perf/core/trybot_command_unittest.py b/tools/perf/core/trybot_command_unittest.py index 9fc56395..e47103d2 100644 --- a/tools/perf/core/trybot_command_unittest.py +++ b/tools/perf/core/trybot_command_unittest.py
@@ -89,8 +89,7 @@ ] parser = trybot_command.Trybot.CreateParser() trybot_command.Trybot.AddCommandLineArgs(parser, None) - trybot_action = [a for a in parser._actions if '--trybot' in - a.option_strings][0] + trybot_action = [a for a in parser._actions if a.dest == 'trybot'][0] self.assertEquals( expected_trybots_list, sorted(trybot_action.choices)) @@ -113,18 +112,14 @@ parser = trybot_command.Trybot.CreateParser() trybot_command.Trybot.AddCommandLineArgs(parser, None) - trybot_action = [a for a in parser._actions if '--trybot' in - a.option_strings][0] - self.assertEquals( - expected_trybots_list, - sorted(trybot_action.choices)) + trybot_action = [a for a in parser._actions if a.dest == 'trybot'][0] + self.assertEquals(expected_trybots_list, sorted(trybot_action.choices)) def testFindAllBrowserTypesNonTrybotBrowser(self): self._MockTryserverJson({}) parser = trybot_command.Trybot.CreateParser() trybot_command.Trybot.AddCommandLineArgs(parser, None) - trybot_action = [a for a in parser._actions if '--trybot' in - a.option_strings][0] + trybot_action = [a for a in parser._actions if a.dest == 'trybot'][0] self.assertEquals( ['all', 'all-android', 'all-linux', 'all-mac', 'all-win'], sorted(trybot_action.choices))
diff --git a/tools/perf/measurements/draw_properties.py b/tools/perf/measurements/draw_properties.py index b5c75cf..fb8bb43 100644 --- a/tools/perf/measurements/draw_properties.py +++ b/tools/perf/measurements/draw_properties.py
@@ -4,8 +4,7 @@ from telemetry.page import page_test from telemetry.timeline import model -from telemetry.timeline import tracing_category_filter -from telemetry.timeline import tracing_options +from telemetry.timeline import tracing_config from telemetry.value import scalar @@ -19,11 +18,11 @@ ]) def WillNavigateToPage(self, page, tab): - options = tracing_options.TracingOptions() - options.enable_chrome_trace = True - category_filter = tracing_category_filter.TracingCategoryFilter( + config = tracing_config.TracingConfig() + config.tracing_category_filter.AddDisabledByDefault( 'disabled-by-default-cc.debug.cdp-perf') - tab.browser.platform.tracing_controller.Start(options, category_filter) + config.tracing_options.enable_chrome_trace = True + tab.browser.platform.tracing_controller.Start(config) def ComputeAverageOfDurations(self, timeline_model, name): events = timeline_model.GetAllEventsOfName(name)
diff --git a/tools/perf/measurements/image_decoding.py b/tools/perf/measurements/image_decoding.py index 3e1bb35c..d19fec6c 100644 --- a/tools/perf/measurements/image_decoding.py +++ b/tools/perf/measurements/image_decoding.py
@@ -4,8 +4,7 @@ from telemetry.page import page_test from telemetry.timeline import model -from telemetry.timeline import tracing_category_filter -from telemetry.timeline import tracing_options +from telemetry.timeline import tracing_config from telemetry.value import scalar from metrics import power @@ -33,26 +32,19 @@ """) self._power_metric.Start(page, tab) - options = tracing_options.TracingOptions() - options.enable_chrome_trace = True + config = tracing_config.TracingConfig() # FIXME: Remove the timeline category when impl-side painting is on # everywhere. - category_filter = tracing_category_filter.TracingCategoryFilter( - 'disabled-by-default-devtools.timeline') - # FIXME: Remove webkit.console when blink.console lands in chromium and # the ref builds are updated. crbug.com/386847 # FIXME: Remove the devtools.timeline category when impl-side painting is # on everywhere. - categories = [ - 'blink', - 'devtools.timeline', - 'webkit.console', - 'blink.console' - ] - for c in categories: - category_filter.AddIncludedCategory(c) - tab.browser.platform.tracing_controller.Start(options, category_filter) + config.tracing_category_filter.AddDisabledByDefault( + 'disabled-by-default-devtools.timeline') + for c in [ 'blink', 'devtools.timeline', 'webkit.console', 'blink.console']: + config.tracing_category_filter.AddIncludedCategory(c) + config.tracing_options.enable_chrome_trace = True + tab.browser.platform.tracing_controller.Start(config) def StopBrowserAfterPage(self, browser, page): return not browser.tabs[0].ExecuteJavaScript("""
diff --git a/tools/perf/measurements/oilpan_gc_times.py b/tools/perf/measurements/oilpan_gc_times.py index 7fd5dcf..0bd37ba 100644 --- a/tools/perf/measurements/oilpan_gc_times.py +++ b/tools/perf/measurements/oilpan_gc_times.py
@@ -7,8 +7,7 @@ from telemetry.page import action_runner from telemetry.page import page_test from telemetry.timeline.model import TimelineModel -from telemetry.timeline import tracing_category_filter -from telemetry.timeline import tracing_options +from telemetry.timeline import tracing_config from telemetry.value import list_of_scalar_values from telemetry.value import scalar @@ -138,14 +137,11 @@ def WillNavigateToPage(self, page, tab): # FIXME: Remove webkit.console when blink.console lands in chromium and # the ref builds are updated. crbug.com/386847 - categories = ['webkit.console', 'blink.console', 'blink_gc'] - category_filter = tracing_category_filter.TracingCategoryFilter() - for c in categories: - category_filter.AddIncludedCategory(c) - options = tracing_options.TracingOptions() - options.enable_chrome_trace = True - tab.browser.platform.tracing_controller.Start(options, category_filter, - timeout=1000) + config = tracing_config.TracingConfig() + for c in ['webkit.console', 'blink.console', 'blink_gc']: + config.tracing_category_filter.AddIncludedCategory(c) + config.tracing_options.enable_chrome_trace = True + tab.browser.platform.tracing_controller.Start(config, timeout=1000) def ValidateAndMeasurePage(self, page, tab, results): timeline_data = tab.browser.platform.tracing_controller.Stop()
diff --git a/tools/perf/measurements/smoothness_unittest.py b/tools/perf/measurements/smoothness_unittest.py index 127be842..0bf1a91 100644 --- a/tools/perf/measurements/smoothness_unittest.py +++ b/tools/perf/measurements/smoothness_unittest.py
@@ -18,10 +18,9 @@ class FakeTracingController(object): def __init__(self): - self.category_filter = None - def Start(self, options, category_filter): - del options # unused - self.category_filter = category_filter + self.config = None + def Start(self, config): + self.config = config def IsChromeTracingSupported(self): return True @@ -95,7 +94,7 @@ ]) tracing_controller = tab.browser.platform.tracing_controller actual_synthetic_delay = ( - tracing_controller.category_filter.synthetic_delays) + tracing_controller.config.tracing_category_filter.synthetic_delays) if expected_synthetic_delay != actual_synthetic_delay: sys.stderr.write("Expected category filter: %s\n" %
diff --git a/tools/perf/measurements/task_execution_time.py b/tools/perf/measurements/task_execution_time.py index 8e4a6b6e..926cf4e 100644 --- a/tools/perf/measurements/task_execution_time.py +++ b/tools/perf/measurements/task_execution_time.py
@@ -4,8 +4,7 @@ from telemetry.page import page_test from telemetry.timeline.model import TimelineModel -from telemetry.timeline import tracing_category_filter -from telemetry.timeline import tracing_options +from telemetry.timeline import tracing_config from telemetry.util import statistics from telemetry.value import scalar @@ -42,16 +41,13 @@ self._results = None def WillNavigateToPage(self, page, tab): - category_filter = tracing_category_filter.TracingCategoryFilter() - + config = tracing_config.TracingConfig() for category in self._CATEGORIES: - category_filter.AddIncludedCategory(category) - - options = tracing_options.TracingOptions() - options.enable_chrome_trace = True + config.tracing_category_filter.AddIncludedCategory(category) + config.tracing_options.enable_chrome_trace = True tab.browser.platform.tracing_controller.Start( - options, category_filter, self._TIME_OUT_IN_SECONDS) + config, self._TIME_OUT_IN_SECONDS) def ValidateAndMeasurePage(self, page, tab, results): trace_data = tab.browser.platform.tracing_controller.Stop()
diff --git a/tools/perf/measurements/timeline_controller.py b/tools/perf/measurements/timeline_controller.py index 893f742..5f2b99e 100644 --- a/tools/perf/measurements/timeline_controller.py +++ b/tools/perf/measurements/timeline_controller.py
@@ -5,8 +5,7 @@ from telemetry.page import action_runner from telemetry.page import page_test from telemetry.timeline.model import TimelineModel -from telemetry.timeline import tracing_category_filter -from telemetry.timeline import tracing_options +from telemetry.timeline import tracing_config from telemetry.value import trace from telemetry.web_perf import smooth_gesture_util from telemetry.web_perf import timeline_interaction_record as tir_module @@ -34,13 +33,12 @@ self._renderer_process = None if not tab.browser.platform.tracing_controller.IsChromeTracingSupported(): raise Exception('Not supported') - category_filter = tracing_category_filter.TracingCategoryFilter( - filter_string=self.trace_categories) + config = tracing_config.TracingConfig() + config.tracing_category_filter.AddFilterString(self.trace_categories) for delay in page.GetSyntheticDelayCategories(): - category_filter.AddSyntheticDelay(delay) - options = tracing_options.TracingOptions() - options.enable_chrome_trace = True - tab.browser.platform.tracing_controller.Start(options, category_filter) + config.tracing_category_filter.AddSyntheticDelay(delay) + config.tracing_options.enable_chrome_trace = True + tab.browser.platform.tracing_controller.Start(config) def Start(self, tab): # Start the smooth marker for all actions.
diff --git a/tools/perf/measurements/v8_gc_times.py b/tools/perf/measurements/v8_gc_times.py index d8d1f0f..77d1820 100644 --- a/tools/perf/measurements/v8_gc_times.py +++ b/tools/perf/measurements/v8_gc_times.py
@@ -4,8 +4,7 @@ from telemetry.page import page_test from telemetry.timeline.model import TimelineModel -from telemetry.timeline import tracing_category_filter -from telemetry.timeline import tracing_options +from telemetry.timeline import tracing_config from telemetry.util import statistics from telemetry.value import scalar @@ -24,16 +23,12 @@ super(V8GCTimes, self).__init__() def WillNavigateToPage(self, page, tab): - category_filter = tracing_category_filter.TracingCategoryFilter() - + config = tracing_config.TracingConfig() for category in self._CATEGORIES: - category_filter.AddIncludedCategory(category) - - options = tracing_options.TracingOptions() - options.enable_chrome_trace = True - + config.tracing_category_filter.AddIncludedCategory(category) + config.tracing_options.enable_chrome_trace = True tab.browser.platform.tracing_controller.Start( - options, category_filter, self._TIME_OUT_IN_SECONDS) + config, self._TIME_OUT_IN_SECONDS) def ValidateAndMeasurePage(self, page, tab, results): trace_data = tab.browser.platform.tracing_controller.Stop()
diff --git a/tools/perf/metrics/power.py b/tools/perf/metrics/power.py index b0afedf..8cb0d2d 100644 --- a/tools/perf/metrics/power.py +++ b/tools/perf/metrics/power.py
@@ -37,13 +37,18 @@ self._starting_cpu_stats = None self._results = None self._MeasureQuiescentPower(quiescent_measurement_time_s) + # TODO(yolandyan): Remove this and the following info loggings after + # crbug/573302 is fixed + logging.info("PowerMetric created, not running") def _StopInternal(self): """Stop monitoring power if measurement is running. This function is idempotent.""" if not self._running: + logging.info("Attempting to stop non-running monitor") return self._running = False + logging.info("StopInternal: PowerMetric running") self._results = self._platform.StopMonitoringPower() if self._results: # StopMonitoringPower() can return None. self._results['cpu_stats'] = ( @@ -85,6 +90,7 @@ self._platform.StartMonitoringPower(self._browser) self._running = True + logging.info("Start: PowerMetric running") def Stop(self, _, tab): if (not self._platform.CanMonitorPower() or
diff --git a/tools/perf/page_sets/startup_pages.py b/tools/perf/page_sets/startup_pages.py index 5678b54d..0f49671 100644 --- a/tools/perf/page_sets/startup_pages.py +++ b/tools/perf/page_sets/startup_pages.py
@@ -20,44 +20,8 @@ class StartedPage(page_module.Page): - def __init__(self, url, startup_url, page_set): - super(StartedPage, self).__init__( - url=url, page_set=page_set, startup_url=startup_url) - self.archive_data_file = 'data/startup_pages.json' - - def RunNavigateSteps(self, action_runner): - action_runner.Wait(10) - - def RunPageInteractions(self, action_runner): - self.RunNavigateSteps(action_runner) - - -class StartupPagesPageSet(story.StorySet): - - """ Pages for testing starting Chrome with a URL. - Note that this file can't be used with record_wpr, since record_wpr requires - a true navigate step, which we do not want for startup testing. Instead use - record_wpr startup_pages_record to record data for this test. - """ - - def __init__(self): - super(StartupPagesPageSet, self).__init__( - archive_data_file='data/startup_pages.json', - cloud_storage_bucket=story.PARTNER_BUCKET) - - # Typical page. - self.AddStory(StartedPage('about:blank', 'about:blank', self)) - # Typical page. - self.AddStory(StartedPage('http://bbc.co.uk', 'http://bbc.co.uk', self)) - # Horribly complex page - stress test! - self.AddStory(StartedPage( - 'http://kapook.com', 'http://kapook.com', self)) - - -class StartedPageTBM(page_module.Page): - def __init__(self, url, page_set): - super(StartedPageTBM, self).__init__( + super(StartedPage, self).__init__( url=url, page_set=page_set, startup_url=url, shared_page_state_class=BrowserStartupSharedState) self.archive_data_file = 'data/startup_pages.json' @@ -73,7 +37,7 @@ self.RunNavigateSteps(action_runner) -class StartupPagesPageSetTBM(story.StorySet): +class StartupPagesPageSet(story.StorySet): """Pages for testing starting Chrome with a URL. Note that this file can't be used with record_wpr, since record_wpr requires @@ -81,13 +45,13 @@ record_wpr startup_pages_record to record data for this test.""" def __init__(self): - super(StartupPagesPageSetTBM, self).__init__( + super(StartupPagesPageSet, self).__init__( archive_data_file='data/startup_pages.json', cloud_storage_bucket=story.PARTNER_BUCKET) # Typical page. - self.AddStory(StartedPageTBM('about:blank', self)) + self.AddStory(StartedPage('about:blank', self)) # Typical page. - self.AddStory(StartedPageTBM('http://bbc.co.uk', self)) + self.AddStory(StartedPage('http://bbc.co.uk', self)) # Horribly complex page - stress test! - self.AddStory(StartedPageTBM('http://kapook.com', self)) + self.AddStory(StartedPage('http://kapook.com', self))
diff --git a/tools/perf/perf.isolate b/tools/perf/perf.isolate index 20cb796..234d724 100644 --- a/tools/perf/perf.isolate +++ b/tools/perf/perf.isolate
@@ -10,6 +10,7 @@ 'variables': { 'files': [ './', + '../../build/android/pylib/', # Field trial configs '../variations/', '../../testing/variations/',
diff --git a/tools/telemetry/BUILD.gn b/tools/telemetry/BUILD.gn index 674b8d0..5eb6b5bf 100644 --- a/tools/telemetry/BUILD.gn +++ b/tools/telemetry/BUILD.gn
@@ -6,7 +6,6 @@ # Generic telemetry deps data = [ "//build/android/devil/", - "//build/android/pylib/", "//third_party/catapult/", "//tools/telemetry/", ]
diff --git a/tools/telemetry/support/html_output/results-template.html b/tools/telemetry/support/html_output/results-template.html index 95da288..b27c080 100644 --- a/tools/telemetry/support/html_output/results-template.html +++ b/tools/telemetry/support/html_output/results-template.html
@@ -249,7 +249,7 @@ </head> <body onload="init()"> <div style="padding: 0 10px; white-space: nowrap;"> -Result <span id="time-memory" class="checkbox"><span class="checked">Time</span><span>Memory</span></span> +Result <span id="time-memory" class="checkbox"></span> Reference <span id="reference" class="checkbox"></span> Style <span id="scatter-line" class="checkbox"><span class="checked">Scatter</span><span>Line</span></span> <span class="checkbox"><span class="checked" id="undelete">Undelete</span></span><br> @@ -278,11 +278,6 @@ var PADDING_UNDER_GRAPH = 5; // px Indentation for nested children left-margins var INDENTATION = 40; -// Bit field enums for active test types -var MEMORY_TEST = 1 << 0; -var TIME_TEST = 1 << 1; -var NO_TESTS = 0; -var ALL_TESTS = MEMORY_TEST | TIME_TEST; function TestResult(metric, values, associatedRun, std, degreesOfFreedom) { if (values) { @@ -319,13 +314,13 @@ values = []; } - this.test = function () { return metric; } - this.values = function () { return values.map(function (value) { return metric.scalingFactor() * value; }); } - this.unscaledMean = function () { return Statistics.sum(values) / values.length; } - this.mean = function () { return metric.scalingFactor() * this.unscaledMean(); } - this.min = function () { return metric.scalingFactor() * Statistics.min(values); } - this.max = function () { return metric.scalingFactor() * Statistics.max(values); } - this.confidenceIntervalDelta = function () { + this.test = function() { return metric; } + this.values = function() { return values.map(function(value) { return metric.scalingFactor() * value; }); } + this.unscaledMean = function() { return Statistics.sum(values) / values.length; } + this.mean = function() { return metric.scalingFactor() * this.unscaledMean(); } + this.min = function() { return metric.scalingFactor() * Statistics.min(values); } + this.max = function() { return metric.scalingFactor() * Statistics.max(values); } + this.confidenceIntervalDelta = function() { if (std !== undefined) { return metric.scalingFactor() * Statistics.confidenceIntervalDeltaFromStd(0.95, values.length, std, degreesOfFreedom); @@ -333,26 +328,26 @@ return metric.scalingFactor() * Statistics.confidenceIntervalDelta(0.95, values.length, Statistics.sum(values), Statistics.squareSum(values)); } - this.confidenceIntervalDeltaRatio = function () { return this.confidenceIntervalDelta() / this.mean(); } + this.confidenceIntervalDeltaRatio = function() { return this.confidenceIntervalDelta() / this.mean(); } this.percentDifference = function(other) { if (other === undefined) { return undefined; } return (other.unscaledMean() - this.unscaledMean()) / this.unscaledMean(); } - this.isStatisticallySignificant = function (other) { + this.isStatisticallySignificant = function(other) { if (other === undefined) { return false; } var diff = Math.abs(other.mean() - this.mean()); return diff > this.confidenceIntervalDelta() && diff > other.confidenceIntervalDelta(); } - this.run = function () { return associatedRun; } + this.run = function() { return associatedRun; } } function TestRun(entry) { this.id = function() { return entry['buildTime'].replace(/[:.-]/g,''); } - this.label = function () { + this.label = function() { if (labelKey in localStorage) return localStorage[labelKey]; return entry['label']; @@ -395,9 +390,9 @@ } } - this.name = function () { return name + ':' + metric; } + this.name = function() { return name + ':' + metric; } this.isImportant = isImportant; - this.isMemoryTest = function () { + this.isMemoryTest = function() { return (unit == 'kb' || unit == 'KB' || unit == 'MB' || @@ -405,21 +400,21 @@ unit == 'count' || !metric.indexOf('V8.')); } - this.addResult = function (newResult) { + this.addResult = function(newResult) { testResults.push(newResult); cachedUnit = null; cachedScalingFactor = null; } - this.results = function () { return testResults; } + this.results = function() { return testResults; } this.scalingFactor = function() { computeScalingFactorIfNeeded(); return cachedScalingFactor; } - this.unit = function () { + this.unit = function() { computeScalingFactorIfNeeded(); return cachedUnit; } - this.biggerIsBetter = function () { + this.biggerIsBetter = function() { if (window.unitToBiggerIsBetter == undefined) { window.unitToBiggerIsBetter = {}; var units = JSON.parse(document.getElementById('units-json').textContent); @@ -536,7 +531,7 @@ attachLinePlots(test, section.children('.line-plots'), useLargeLinePlots); var tooltip = section.children('.tooltip'); - plotContainer.bind('plothover', function (event, position, item) { + plotContainer.bind('plothover', function(event, position, item) { if (item) { var postfix = item.series.id ? ' (' + item.series.id + ')' : ''; tooltip.html(item.datapoint[1].toPrecision(4) + postfix); @@ -546,10 +541,10 @@ } else tooltip.hide(); }); - plotContainer.mouseout(function () { + plotContainer.mouseout(function() { tooltip.hide(); }); - plotContainer.click(function (event) { + plotContainer.click(function(event) { event.preventDefault(); minIsZero = !minIsZero; attachPlot(test, plotContainer, minIsZero); @@ -592,7 +587,7 @@ xaxis: {min: -0.5, max: values.length - 0.5}, points: {show: (values.length < 2) ? true : false}}); } - $.plot(container.children().last(), [values.map(function (value, index) { return [index, value]; })], options); + $.plot(container.children().last(), [values.map(function(value, index) { return [index, value]; })], options); } if (!attachedPlot) container.children().remove(); @@ -652,23 +647,23 @@ function attachPlot(test, plotContainer, minIsZero) { var results = test.results(); - var values = results.reduce(function (values, result, index) { + var values = results.reduce(function(values, result, index) { var newValues = result.values(); - return newValues ? values.concat(newValues.map(function (value) { return [index, value]; })) : values; + return newValues ? values.concat(newValues.map(function(value) { return [index, value]; })) : values; }, []); var plotData = [$.extend(true, {}, subpointsPlotOptions, {data: values})]; - plotData.push({id: 'μ', data: results.map(function (result, index) { return [index, result.mean()]; }), color: plotColor}); + plotData.push({id: 'μ', data: results.map(function(result, index) { return [index, result.mean()]; }), color: plotColor}); - var overallMax = Statistics.max(results.map(function (result, index) { return result.max(); })); - var overallMin = Statistics.min(results.map(function (result, index) { return result.min(); })); + var overallMax = Statistics.max(results.map(function(result, index) { return result.max(); })); + var overallMin = Statistics.min(results.map(function(result, index) { return result.min(); })); var margin = (overallMax - overallMin) * 0.1; var currentPlotOptions = $.extend(true, {}, mainPlotOptions, {yaxis: { min: minIsZero ? 0 : overallMin - margin, max: minIsZero ? overallMax * 1.1 : overallMax + margin}}); currentPlotOptions.xaxis.max = results.length - 0.5; - currentPlotOptions.xaxis.ticks = results.map(function (result, index) { return [index, result.run().label()]; }); + currentPlotOptions.xaxis.ticks = results.map(function(result, index) { return [index, result.run().label()]; }); $.plot(plotContainer, plotData, currentPlotOptions); } @@ -695,39 +690,66 @@ }); } -function getTestTypes(tests) { - var testTypes = NO_TESTS; - for (testName in tests) { - if (tests[testName].isMemoryTest()) { - testTypes |= MEMORY_TEST; - } else { - testTypes |= TIME_TEST; - } - if (testTypes === ALL_TESTS) { - // Early out as soon as we've found all the test types. - break; - } - } - return testTypes; - } - -function areMemoryResultsIgnoredForTestTypes(testTypes) { - return testTypes !== MEMORY_TEST; +function TestTypeSelector(tests) { + this.recognizers = { + 'Time': function(test) { return test.isMemoryTest(); }, + 'Memory': function(test) { return !test.isMemoryTest(); } + }; + this.testTypeNames = this.generateUsedTestTypeNames(tests); + // Default to selecting the first test-type name in the list. + this.testTypeName = this.testTypeNames[0]; } -function setUpUIForTestTypes(testTypes) { - var withFirstTestTypeRemoved = testTypes & (testTypes-1); - if (withFirstTestTypeRemoved === NO_TESTS) { - // Hide button when there are zero or one test types. - document.getElementById('time-memory').style.display = 'none'; +TestTypeSelector.prototype = { + set testTypeName(testTypeName) { + this._testTypeName = testTypeName; + this.shouldShowTest = this.recognizers[testTypeName]; + }, + + generateUsedTestTypeNames: function(allTests) { + var testTypeNames = []; + + for (var recognizedTestName in this.recognizers) { + var recognizes = this.recognizers[recognizedTestName]; + for (var testName in allTests) { + var test = allTests[testName]; + if (recognizes(test)) { + testTypeNames.push(recognizedTestName); + break; + } + } + } + + if (testTypeNames.length === 0) { + // No test types we recognize, add 'No Results' with a dummy recognizer. + var noResults = 'No Results'; + this.recognizers[noResults] = function() { return false; }; + testTypeNames.push(noResults); + } else if (testTypeNames.length > 1) { + // We have more than one test type, so add 'All' with a recognizer that always succeeds. + var allResults = 'All'; + this.recognizers[allResults] = function() { return true; }; + testTypeNames.push(allResults); + } + + return testTypeNames; + }, + + buildButtonHTMLForUsedTestTypes: function() { + var selectedTestTypeName = this._testTypeName; + // Build spans for all recognised test names with the selected test highlighted. + return this.testTypeNames.map(function(testTypeName) { + var classAttribute = testTypeName === selectedTestTypeName ? ' class=checked' : ''; + return '<span' + classAttribute + '>' + testTypeName + '</span>'; + }).join(''); } -} +}; var topLevelRows; var allTableRows; -function createTable(tests, runs, shouldIgnoreMemory, referenceIndex, useLargeLinePlots) { - var resultHeaders = runs.map(function (run, index) { +function displayTable(tests, runs, testTypeSelector, referenceIndex, useLargeLinePlots) { + var resultHeaders = runs.map(function(run, index) { var header = '<th id="' + run.id() + '" ' + 'colspan=2 ' + 'title="' + run.description() + '">' + @@ -782,10 +804,9 @@ allTableRows = []; testNames.forEach(function(testName) { var test = tests[testName]; - if (test.isMemoryTest() === shouldIgnoreMemory) { - return; + if (testTypeSelector.shouldShowTest(test)) { + allTableRows.push(new TableRow(runs, test, referenceIndex, useLargeLinePlots)); } - allTableRows.push(new TableRow(runs, test, referenceIndex, useLargeLinePlots)); }); // Build a list of top level rows with attached children @@ -861,10 +882,10 @@ location.reload(); } }); - $('#labelEditor').click(function (event) { + $('#labelEditor').click(function(event) { event.stopPropagation(); }); - $('#labelEditor').mousedown(function (event) { + $('#labelEditor').mousedown(function(event) { event.stopPropagation(); }); $('#labelEditor').select(); @@ -1376,7 +1397,7 @@ var runs = []; var metrics = {}; var deletedRunsById = {}; - $.each(JSON.parse(document.getElementById('results-json').textContent), function (index, entry) { + $.each(JSON.parse(document.getElementById('results-json').textContent), function(index, entry) { var run = new TestRun(entry); if (run.isHidden()) { deletedRunsById[run.id()] = run; @@ -1408,36 +1429,35 @@ }); var useLargeLinePlots = false; - - var testTypes = getTestTypes(metrics); - - setUpUIForTestTypes(testTypes); - var shouldIgnoreMemory = areMemoryResultsIgnoredForTestTypes(testTypes); var referenceIndex = 0; - createTable(metrics, runs, shouldIgnoreMemory, referenceIndex, useLargeLinePlots); + var testTypeSelector = new TestTypeSelector(metrics); + var buttonHTML = testTypeSelector.buildButtonHTMLForUsedTestTypes(); + $('#time-memory').append(buttonHTML); - $('#time-memory').bind('change', function (event, checkedElement) { - shouldIgnoreMemory = checkedElement.textContent == 'Time'; - createTable(metrics, runs, shouldIgnoreMemory, referenceIndex, useLargeLinePlots); - }); - - $('#scatter-line').bind('change', function (event, checkedElement) { + $('#scatter-line').bind('change', function(event, checkedElement) { useLargeLinePlots = checkedElement.textContent == 'Line'; - createTable(metrics, runs, shouldIgnoreMemory, referenceIndex, useLargeLinePlots); + displayTable(metrics, runs, testTypeSelector, referenceIndex, useLargeLinePlots); }); - runs.map(function (run, index) { + runs.map(function(run, index) { $('#reference').append('<span value="' + index + '"' + (index == referenceIndex ? ' class="checked"' : '') + ' title="' + run.description() + '">' + run.label() + '</span>'); }) - $('#reference').bind('change', function (event, checkedElement) { - referenceIndex = parseInt(checkedElement.getAttribute('value')); - createTable(metrics, runs, shouldIgnoreMemory, referenceIndex, useLargeLinePlots); + $('#time-memory').bind('change', function(event, checkedElement) { + testTypeSelector.testTypeName = checkedElement.textContent; + displayTable(metrics, runs, testTypeSelector, referenceIndex, useLargeLinePlots); }); - $('.checkbox').each(function (index, checkbox) { - $(checkbox).children('span').click(function (event) { + $('#reference').bind('change', function(event, checkedElement) { + referenceIndex = parseInt(checkedElement.getAttribute('value')); + displayTable(metrics, runs, testTypeSelector, referenceIndex, useLargeLinePlots); + }); + + displayTable(metrics, runs, testTypeSelector, referenceIndex, useLargeLinePlots); + + $('.checkbox').each(function(index, checkbox) { + $(checkbox).children('span').click(function(event) { if ($(this).hasClass('checked')) return; $(checkbox).children('span').removeClass('checked'); @@ -1451,7 +1471,7 @@ if (runToUndelete) { $('#undelete').html('Undelete ' + runToUndelete.label()); $('#undelete').attr('title', runToUndelete.description()); - $('#undelete').click(function (event) { + $('#undelete').click(function(event) { runToUndelete.show(); undeleteManager.undeleteMostRecent(); location.reload();
diff --git a/tools/telemetry/telemetry.isolate b/tools/telemetry/telemetry.isolate index 44bea2c..aa9fc95 100644 --- a/tools/telemetry/telemetry.isolate +++ b/tools/telemetry/telemetry.isolate
@@ -6,7 +6,6 @@ ['OS=="android" or OS=="linux" or OS=="mac" or OS=="win"', { 'variables': { 'files': [ - '../../build/android/pylib/', '../../build/android/devil/', '../../third_party/catapult/', './',
diff --git a/tools/telemetry/telemetry/core/platform_unittest.py b/tools/telemetry/telemetry/core/platform_unittest.py index 9fa6305..6454d842 100644 --- a/tools/telemetry/telemetry/core/platform_unittest.py +++ b/tools/telemetry/telemetry/core/platform_unittest.py
@@ -13,6 +13,7 @@ class PlatformScreenshotTest(tab_test_case.TabTestCase): + @decorators.Disabled('win') # crbug.com/570955 def testScreenshotSupported(self): if self._platform.GetOSName() == 'android': self.assertTrue(self._platform.CanTakeScreenshot())
diff --git a/tools/telemetry/telemetry/core/tracing_controller.py b/tools/telemetry/telemetry/core/tracing_controller.py index 9fd796d7..8b35c10 100644 --- a/tools/telemetry/telemetry/core/tracing_controller.py +++ b/tools/telemetry/telemetry/core/tracing_controller.py
@@ -9,9 +9,11 @@ """Provides control of the tracing systems supported by telemetry.""" self._tracing_controller_backend = tracing_controller_backend - def Start(self, trace_options, category_filter, timeout=10): + def Start(self, tracing_config, timeout=10): """Starts tracing. + tracing config contains both tracing optoins and category filters. + trace_options specifies which tracing systems to activate. Category filter allows fine-tuning of the data that are collected by the selected tracing systems. @@ -26,8 +28,7 @@ your code fail gracefully when the data you require is not present in the resulting trace. """ - self._tracing_controller_backend.Start(trace_options, category_filter, - timeout) + self._tracing_controller_backend.Start(tracing_config, timeout) def Stop(self): """Stops tracing and returns a TraceValue."""
diff --git a/tools/telemetry/telemetry/core/tracing_controller_unittest.py b/tools/telemetry/telemetry/core/tracing_controller_unittest.py index cdf2664..2441bac 100644 --- a/tools/telemetry/telemetry/core/tracing_controller_unittest.py +++ b/tools/telemetry/telemetry/core/tracing_controller_unittest.py
@@ -7,18 +7,16 @@ from telemetry.testing import browser_test_case from telemetry.testing import tab_test_case from telemetry.timeline import model as model_module -from telemetry.timeline import tracing_category_filter -from telemetry.timeline import tracing_options +from telemetry.timeline import tracing_config class TracingControllerTest(tab_test_case.TabTestCase): def testModifiedConsoleTime(self): tracing_controller = self._tab.browser.platform.tracing_controller - category_filter = tracing_category_filter.TracingCategoryFilter() - options = tracing_options.TracingOptions() - options.enable_chrome_trace = True - tracing_controller.Start(options, category_filter) + config = tracing_config.TracingConfig() + config.tracing_options.enable_chrome_trace = True + tracing_controller.Start(config) self.Navigate('blank.html') self.assertEquals( self._tab.EvaluateJavaScript('document.location.pathname;'), @@ -39,17 +37,16 @@ # Check that subsequent tests will be able to use tracing normally. self.assertFalse(tracing_controller.is_tracing_running) - tracing_controller.Start(options, category_filter) + tracing_controller.Start(config) self.assertTrue(tracing_controller.is_tracing_running) tracing_controller.Stop() self.assertFalse(tracing_controller.is_tracing_running) def testExceptionRaisedInStopTracing(self): tracing_controller = self._tab.browser.platform.tracing_controller - category_filter = tracing_category_filter.TracingCategoryFilter() - options = tracing_options.TracingOptions() - options.enable_chrome_trace = True - tracing_controller.Start(options, category_filter) + config = tracing_config.TracingConfig() + config.tracing_options.enable_chrome_trace = True + tracing_controller.Start(config) self.Navigate('blank.html') self._tab.EvaluateJavaScript(""" @@ -64,10 +61,9 @@ def testGotTrace(self): tracing_controller = self._browser.platform.tracing_controller - options = tracing_options.TracingOptions() - options.enable_chrome_trace = True - tracing_controller.Start(options, - tracing_category_filter.TracingCategoryFilter()) + config = tracing_config.TracingConfig() + config.tracing_options.enable_chrome_trace = True + tracing_controller.Start(config) trace_data = tracing_controller.Stop() # Test that trace data is parsable @@ -76,12 +72,11 @@ def testStartAndStopTraceMultipleTimes(self): tracing_controller = self._browser.platform.tracing_controller - options = tracing_options.TracingOptions() - options.enable_chrome_trace = True - tracing_controller.Start(options, - tracing_category_filter.TracingCategoryFilter()) - self.assertFalse(tracing_controller.Start( - options, tracing_category_filter.TracingCategoryFilter())) + config = tracing_config.TracingConfig() + config.tracing_options.enable_chrome_trace = True + tracing_controller.Start(config) + self.assertFalse(tracing_controller.Start(config)) + trace_data = tracing_controller.Stop() # Test that trace data is parsable model_module.TimelineModel(trace_data) @@ -95,10 +90,9 @@ # Start tracing self.assertFalse(platform.tracing_controller.is_tracing_running) - trace_options = tracing_options.TracingOptions() - trace_options.enable_chrome_trace = True - category_filter = tracing_category_filter.TracingCategoryFilter() - platform.tracing_controller.Start(trace_options, category_filter) + config = tracing_config.TracingConfig() + config.tracing_options.enable_chrome_trace = True + platform.tracing_controller.Start(config) self.assertTrue(platform.tracing_controller.is_tracing_running) try: @@ -108,8 +102,7 @@ self._browser.tabs[0].WaitForDocumentReadyStateToBeInteractiveOrBetter() self.assertEquals(platform, self._browser.platform) # Calling start tracing again will return False - self.assertFalse(self._browser.platform.tracing_controller.Start( - trace_options, category_filter)) + self.assertFalse(self._browser.platform.tracing_controller.Start(config)) trace_data = self._browser.platform.tracing_controller.Stop() # Test that trace data is parsable
diff --git a/tools/telemetry/telemetry/internal/actions/action_runner_unittest.py b/tools/telemetry/telemetry/internal/actions/action_runner_unittest.py index 43f5194..da6bd90f 100644 --- a/tools/telemetry/telemetry/internal/actions/action_runner_unittest.py +++ b/tools/telemetry/telemetry/internal/actions/action_runner_unittest.py
@@ -10,8 +10,7 @@ from telemetry.testing import tab_test_case import mock from telemetry.timeline import model -from telemetry.timeline import tracing_category_filter -from telemetry.timeline import tracing_options +from telemetry.timeline import tracing_config from telemetry.web_perf import timeline_interaction_record as tir_module @@ -31,10 +30,10 @@ skip_waits=True) self.Navigate('interaction_enabled_page.html') action_runner.Wait(1) - options = tracing_options.TracingOptions() - options.enable_chrome_trace = True - self._browser.platform.tracing_controller.Start( - options, tracing_category_filter.CreateNoOverheadFilter()) + config = tracing_config.TracingConfig() + config.SetNoOverheadFilter() + config.tracing_options.enable_chrome_trace = True + self._browser.platform.tracing_controller.Start(config) with action_runner.CreateInteraction('InteractionName', **interaction_kwargs): pass
diff --git a/tools/telemetry/telemetry/internal/backends/chrome_inspector/tracing_backend_unittest.py b/tools/telemetry/telemetry/internal/backends/chrome_inspector/tracing_backend_unittest.py index b0352f8..97949be 100644 --- a/tools/telemetry/telemetry/internal/backends/chrome_inspector/tracing_backend_unittest.py +++ b/tools/telemetry/telemetry/internal/backends/chrome_inspector/tracing_backend_unittest.py
@@ -12,8 +12,7 @@ from telemetry.testing import simple_mock from telemetry.testing import tab_test_case from telemetry.timeline import model as model_module -from telemetry.timeline import tracing_category_filter -from telemetry.timeline import tracing_options +from telemetry.timeline import tracing_config class TracingBackendTest(tab_test_case.TabTestCase): @@ -46,11 +45,11 @@ self.assertRaises(Exception, self._browser.DumpMemory) # Start tracing with memory dumps enabled. - options = tracing_options.TracingOptions() - options.enable_chrome_trace = True - self._tracing_controller.Start( - options, tracing_category_filter.TracingCategoryFilter( - 'disabled-by-default-memory-infra')) + config = tracing_config.TracingConfig() + config.tracing_category_filter.AddDisabledByDefault( + 'disabled-by-default-memory-infra') + config.tracing_options.enable_chrome_trace = True + self._tracing_controller.Start(config) # Request several memory dumps in a row and test that they were all # successfully created with unique IDs. @@ -81,10 +80,9 @@ self.assertRaises(Exception, self._browser.DumpMemory) # Start tracing with memory dumps disabled. - options = tracing_options.TracingOptions() - options.enable_chrome_trace = True - self._tracing_controller.Start( - options, tracing_category_filter.TracingCategoryFilter()) + config = tracing_config.TracingConfig() + config.tracing_options.enable_chrome_trace = True + self._tracing_controller.Start(config) # Check that the method returns None if the dump was not successful. self.assertIsNone(self._browser.DumpMemory())
diff --git a/tools/telemetry/telemetry/internal/backends/remote/trybot_browser_finder.py b/tools/telemetry/telemetry/internal/backends/remote/trybot_browser_finder.py index aa1596e..14c17b0 100644 --- a/tools/telemetry/telemetry/internal/backends/remote/trybot_browser_finder.py +++ b/tools/telemetry/telemetry/internal/backends/remote/trybot_browser_finder.py
@@ -278,9 +278,15 @@ the bisect config, commits it, uploads the CL to rietveld, and runs a tryjob on the given bot. """ - logging.warning('PLEASE NOTE: Due to the schedule lab move, ' - 'try jobs might not work on Android perf bisect bots. ' - 'Please refer to crbug.com/568661') + print '\n**** WARNING ****' + print ('Running telemetry benchmark on trybot using --browser=trybot-... ' + 'is deprecated (see crbug.com/566605) and will be removed on ' + 'Jan 20th 2016. To run benchmark on trybot, use the ' + 'command `run_benchmark trybot ...` instead.') + user_input = raw_input( + "Enter 'c' to keep running the current command anyway: ") + if user_input != 'c': + return # First check if there are chromium changes to upload. status = self._AttemptTryjob(CHROMIUM_CONFIG_FILENAME) @@ -380,6 +386,5 @@ """Find all perf trybots on tryserver.chromium.perf.""" if not isinstance(device, trybot_device.TrybotDevice): return [] - return [PossibleTrybotBrowser(b, finder_options) for b in FindAllBrowserTypes(finder_options)]
diff --git a/tools/telemetry/telemetry/internal/backends/remote/trybot_browser_finder_unittest.py b/tools/telemetry/telemetry/internal/backends/remote/trybot_browser_finder_unittest.py index 999234a..1b0e12ce 100644 --- a/tools/telemetry/telemetry/internal/backends/remote/trybot_browser_finder_unittest.py +++ b/tools/telemetry/telemetry/internal/backends/remote/trybot_browser_finder_unittest.py
@@ -11,9 +11,6 @@ from telemetry.testing import simple_mock from telemetry.testing import system_stub -TRYBOT_OUTAGE_WARNING = ('PLEASE NOTE: Due to the schedule lab move, ' - 'try jobs might not work on Android perf bisect bots. ' - 'Please refer to crbug.com/568661\n') class TrybotBrowserFinderTest(unittest.TestCase): @@ -25,8 +22,10 @@ self._stubs = system_stub.Override(trybot_browser_finder, ['sys', 'open', 'os']) self._builder_list = "" + trybot_browser_finder.raw_input = lambda _: 'c' def tearDown(self): + trybot_browser_finder.raw_input = raw_input logging.getLogger().removeHandler(self.stream_handler) self.log_output.close() trybot_browser_finder.subprocess = self._real_subprocess @@ -253,7 +252,7 @@ (['git', 'rev-parse', '--abbrev-ref', 'HEAD'], (128, None, None)), )) browser.RunRemote() - self.assertEquals(TRYBOT_OUTAGE_WARNING + + self.assertEquals( 'Must be in a git repository to send changes to trybots.\n', self.log_output.getvalue()) @@ -269,7 +268,7 @@ )) browser.RunRemote() - self.assertEquals(TRYBOT_OUTAGE_WARNING + + self.assertEquals( 'Cannot send a try job with a dirty tree. Commit locally first.\n', self.log_output.getvalue()) @@ -290,7 +289,7 @@ )) browser.RunRemote() - self.assertEquals(TRYBOT_OUTAGE_WARNING + + self.assertEquals( ('No local changes found in chromium or blink trees. ' 'browser=trybot-android-nexus4 argument sends local changes to the ' 'perf trybot(s): ' @@ -312,7 +311,7 @@ )) browser.RunRemote() - self.assertEquals(TRYBOT_OUTAGE_WARNING + + self.assertEquals( ('Error creating branch telemetry-tryjob. ' 'Please delete it if it exists.\n' 'fatal: A branch named \'telemetry-try\' already exists.\n'),
diff --git a/tools/telemetry/telemetry/internal/browser/browser_unittest.py b/tools/telemetry/telemetry/internal/browser/browser_unittest.py index f56b257..80c0cd2 100644 --- a/tools/telemetry/telemetry/internal/browser/browser_unittest.py +++ b/tools/telemetry/telemetry/internal/browser/browser_unittest.py
@@ -18,8 +18,7 @@ from telemetry.internal.util import path from telemetry.testing import browser_test_case from telemetry.testing import options_for_unittests -from telemetry.timeline import tracing_category_filter -from telemetry.timeline import tracing_options +from telemetry.timeline import tracing_config import mock @@ -121,10 +120,9 @@ if not tracing_controller.IsChromeTracingSupported(): return self.assertFalse(tracing_controller.is_tracing_running) - options = tracing_options.TracingOptions() - options.enable_chrome_trace = True - category_filter = tracing_category_filter.TracingCategoryFilter() - tracing_controller.Start(options, category_filter) + config = tracing_config.TracingConfig() + config.tracing_options.enable_chrome_trace = True + tracing_controller.Start(config) self.assertTrue(tracing_controller.is_tracing_running) tracing_controller.Stop() self.assertFalse(tracing_controller.is_tracing_running)
diff --git a/tools/telemetry/telemetry/internal/browser/tab_unittest.py b/tools/telemetry/telemetry/internal/browser/tab_unittest.py index a82917f..0b01f575 100644 --- a/tools/telemetry/telemetry/internal/browser/tab_unittest.py +++ b/tools/telemetry/telemetry/internal/browser/tab_unittest.py
@@ -11,8 +11,7 @@ from telemetry.internal.image_processing import video from telemetry.testing import tab_test_case from telemetry.timeline import model -from telemetry.timeline import tracing_category_filter -from telemetry.timeline import tracing_options +from telemetry.timeline import tracing_config from telemetry.util import image_util from telemetry.util import rgba_color @@ -102,10 +101,10 @@ @decorators.Disabled('win') # crbug.com/570955 def testHighlight(self): self.assertEquals(self._tab.url, 'about:blank') - options = tracing_options.TracingOptions() - options.enable_chrome_trace = True - self._browser.platform.tracing_controller.Start( - options, tracing_category_filter.CreateNoOverheadFilter()) + config = tracing_config.TracingConfig() + config.SetNoOverheadFilter() + config.tracing_options.enable_chrome_trace = True + self._browser.platform.tracing_controller.Start(config) self._tab.Highlight(rgba_color.WEB_PAGE_TEST_ORANGE) self._tab.ClearHighlight(rgba_color.WEB_PAGE_TEST_ORANGE) trace_data = self._browser.platform.tracing_controller.Stop() @@ -134,10 +133,10 @@ third_tab.Navigate('about:blank') third_tab.WaitForDocumentReadyStateToBeInteractiveOrBetter() third_tab.Close() - options = tracing_options.TracingOptions() - options.enable_chrome_trace = True - self._browser.platform.tracing_controller.Start( - options, tracing_category_filter.CreateNoOverheadFilter()) + config = tracing_config.TracingConfig() + config.SetNoOverheadFilter() + config.tracing_options.enable_chrome_trace = True + self._browser.platform.tracing_controller.Start(config) first_tab.ExecuteJavaScript('console.time("first-tab-marker");') first_tab.ExecuteJavaScript('console.timeEnd("first-tab-marker");') second_tab.ExecuteJavaScript('console.time("second-tab-marker");')
diff --git a/tools/telemetry/telemetry/internal/platform/profiler/trace_profiler_unittest.py b/tools/telemetry/telemetry/internal/platform/profiler/trace_profiler_unittest.py index efacad7..7d844cfa 100644 --- a/tools/telemetry/telemetry/internal/platform/profiler/trace_profiler_unittest.py +++ b/tools/telemetry/telemetry/internal/platform/profiler/trace_profiler_unittest.py
@@ -7,12 +7,14 @@ import tempfile import zipfile +from telemetry import decorators from telemetry.internal.platform.profiler import trace_profiler from telemetry.testing import tab_test_case class TestTraceProfiler(tab_test_case.TabTestCase): + @decorators.Disabled('win') # crbug.com/570955 def testTraceProfiler(self): try: out_dir = tempfile.mkdtemp()
diff --git a/tools/telemetry/telemetry/internal/platform/tracing_agent/__init__.py b/tools/telemetry/telemetry/internal/platform/tracing_agent/__init__.py index 2301c80..85d82d6 100644 --- a/tools/telemetry/telemetry/internal/platform/tracing_agent/__init__.py +++ b/tools/telemetry/telemetry/internal/platform/tracing_agent/__init__.py
@@ -24,17 +24,19 @@ del platform_backend # unused return False - def Start(self, trace_options, category_filter, timeout): + def Start(self, config, timeout): """ Override to add tracing agent's custom logic to start tracing. Depending on trace_options and category_filter, the tracing agent may choose to start or not start tracing. Args: - trace_options: an instance of tracing_options.TracingOptions that - control which core tracing systems should be enabled. - category_filter: an instance of - tracing_category_filter.TracingCategoryFilter + config: tracing_config instance that contains trace_option and + category_filter + trace_options: an instance of tracing_options.TracingOptions that + control which core tracing systems should be enabled. + category_filter: an instance of + tracing_category_filter.TracingCategoryFilter timeout: number of seconds that this tracing agent should try to start tracing until time out.
diff --git a/tools/telemetry/telemetry/internal/platform/tracing_agent/chrome_tracing_agent.py b/tools/telemetry/telemetry/internal/platform/tracing_agent/chrome_tracing_agent.py index 47fe3b7..7ee1304 100644 --- a/tools/telemetry/telemetry/internal/platform/tracing_agent/chrome_tracing_agent.py +++ b/tools/telemetry/telemetry/internal/platform/tracing_agent/chrome_tracing_agent.py
@@ -13,7 +13,6 @@ from telemetry.internal.platform import tracing_agent from telemetry.internal.platform.tracing_agent import ( chrome_tracing_devtools_manager) -from telemetry.timeline import tracing_config _DESKTOP_OS_NAMES = ['linux', 'mac', 'win'] _STARTUP_TRACING_OS_NAMES = _DESKTOP_OS_NAMES + ['android'] @@ -67,7 +66,7 @@ self._CreateTraceConfigFile(config) return True - def _StartDevToolsTracing(self, trace_options, category_filter, timeout): + def _StartDevToolsTracing(self, config, timeout): if not chrome_tracing_devtools_manager.IsSupported(self._platform_backend): return False devtools_clients = (chrome_tracing_devtools_manager @@ -79,12 +78,13 @@ raise ChromeTracingStartedError( 'Tracing is already running on devtools at port %s on platform' 'backend %s.' % (client.remote_port, self._platform_backend)) - client.StartChromeTracing( - trace_options, category_filter.filter_string, timeout) + client.StartChromeTracing(config.tracing_options, + config.tracing_category_filter.filter_string, + timeout) return True - def Start(self, trace_options, category_filter, timeout): - if not trace_options.enable_chrome_trace: + def Start(self, config, timeout): + if not config.tracing_options.enable_chrome_trace: return False if self._trace_config: @@ -92,7 +92,7 @@ 'Tracing is already running on platform backend %s.' % self._platform_backend) - if (trace_options.enable_android_graphics_memtrack and + if (config.tracing_options.enable_android_graphics_memtrack and self._platform_backend.GetOSName() == 'android'): self._platform_backend.SetGraphicsMemoryTrackingEnabled(True) @@ -102,10 +102,8 @@ # this point to use it for enabling tracing upon browser startup. For the # latter, we invoke start tracing command through devtools for browsers that # are already started and tracked by chrome_tracing_devtools_manager. - config = tracing_config.TracingConfig(trace_options, category_filter) started_startup_tracing = self._StartStartupTracing(config) - started_devtools_tracing = self._StartDevToolsTracing( - trace_options, category_filter, timeout) + started_devtools_tracing = self._StartDevToolsTracing(config, timeout) if started_startup_tracing or started_devtools_tracing: self._trace_config = config return True @@ -147,7 +145,7 @@ def _CreateTraceConfigFileString(self, config): # See src/components/tracing/trace_config_file.h for the format - trace_config_str = config.GetTraceConfigJsonString() + trace_config_str = config.GetChromeTraceConfigJsonString() return '{"trace_config":' + trace_config_str + '}' def _CreateTraceConfigFile(self, config):
diff --git a/tools/telemetry/telemetry/internal/platform/tracing_agent/chrome_tracing_agent_unittest.py b/tools/telemetry/telemetry/internal/platform/tracing_agent/chrome_tracing_agent_unittest.py index 1138a6e..60ea43c 100644 --- a/tools/telemetry/telemetry/internal/platform/tracing_agent/chrome_tracing_agent_unittest.py +++ b/tools/telemetry/telemetry/internal/platform/tracing_agent/chrome_tracing_agent_unittest.py
@@ -10,9 +10,7 @@ from telemetry.internal.platform.tracing_agent import chrome_tracing_agent from telemetry.internal.platform.tracing_agent import ( chrome_tracing_devtools_manager) -from telemetry.timeline import tracing_category_filter from telemetry.timeline import tracing_config -from telemetry.timeline import tracing_options from devil.android import device_utils @@ -82,11 +80,11 @@ def StartTracing(self, platform_backend, enable_chrome_trace=True): assert chrome_tracing_agent.ChromeTracingAgent.IsSupported(platform_backend) agent = chrome_tracing_agent.ChromeTracingAgent(platform_backend) - trace_options = tracing_options.TracingOptions() - trace_options.enable_chrome_trace = enable_chrome_trace - category_filter = tracing_category_filter.TracingCategoryFilter('foo') + config = tracing_config.TracingConfig() + config.tracing_category_filter.AddIncludedCategory('foo') + config.tracing_options.enable_chrome_trace = enable_chrome_trace agent._platform_backend.tracing_controller_backend.is_tracing_running = True - agent.Start(trace_options, category_filter, 10) + agent.Start(config, 10) return agent def StopTracing(self, agent): @@ -231,9 +229,7 @@ agent = chrome_tracing_agent.ChromeTracingAgent(platform_backend) self.assertIsNone(agent.trace_config_file) - config = tracing_config.TracingConfig( - tracing_options.TracingOptions(), - tracing_category_filter.TracingCategoryFilter()) + config = tracing_config.TracingConfig() agent._CreateTraceConfigFile(config) self.assertIsNotNone(agent.trace_config_file) self.assertTrue(platform_backend.device.PathExists(agent.trace_config_file)) @@ -257,9 +253,7 @@ agent = chrome_tracing_agent.ChromeTracingAgent(platform_backend) self.assertIsNone(agent.trace_config_file) - config = tracing_config.TracingConfig( - tracing_options.TracingOptions(), - tracing_category_filter.TracingCategoryFilter()) + config = tracing_config.TracingConfig() agent._CreateTraceConfigFile(config) self.assertIsNotNone(agent.trace_config_file) self.assertTrue(os.path.exists(agent.trace_config_file))
diff --git a/tools/telemetry/telemetry/internal/platform/tracing_agent/display_tracing_agent.py b/tools/telemetry/telemetry/internal/platform/tracing_agent/display_tracing_agent.py index 963baf82..0fa523d 100644 --- a/tools/telemetry/telemetry/internal/platform/tracing_agent/display_tracing_agent.py +++ b/tools/telemetry/telemetry/internal/platform/tracing_agent/display_tracing_agent.py
@@ -14,9 +14,9 @@ def IsSupported(cls, platform_backend): return platform_backend.IsDisplayTracingSupported() - def Start(self, trace_options, category_filter, timeout): + def Start(self, config, timeout): del timeout # unused - if trace_options.enable_platform_display_trace: + if config.tracing_options.enable_platform_display_trace: self._platform_backend.StartDisplayTracing() return True
diff --git a/tools/telemetry/telemetry/internal/platform/tracing_agent/display_tracing_agent_unittest.py b/tools/telemetry/telemetry/internal/platform/tracing_agent/display_tracing_agent_unittest.py index 3360e02..088f8e9 100644 --- a/tools/telemetry/telemetry/internal/platform/tracing_agent/display_tracing_agent_unittest.py +++ b/tools/telemetry/telemetry/internal/platform/tracing_agent/display_tracing_agent_unittest.py
@@ -6,8 +6,7 @@ from telemetry.internal.platform import android_platform_backend from telemetry.internal.platform.tracing_agent import display_tracing_agent -from telemetry.timeline import tracing_category_filter -from telemetry.timeline import tracing_options +from telemetry.timeline import tracing_config # pylint: disable=super-init-not-called, abstract-method, unused-argument class FakeAndroidPlatformBackend( @@ -27,9 +26,8 @@ class DisplayTracingAgentTest(unittest.TestCase): def setUp(self): - self._trace_options = tracing_options.TracingOptions() - self._trace_options.enable_platform_display_trace = True - self._category_filter = tracing_category_filter.TracingCategoryFilter() + self._config = tracing_config.TracingConfig() + self._config.tracing_options.enable_platform_display_trace = True self._platform_backend = FakeAndroidPlatformBackend() self._agent = display_tracing_agent.DisplayTracingAgent( self._platform_backend) @@ -37,22 +35,22 @@ @mock.patch( 'devil.android.perf.surface_stats_collector.SurfaceStatsCollector') def testStartAndStopTracing(self, MockSurfaceStatsCollector): - self._agent.Start(self._trace_options, self._category_filter, 10) + self._agent.Start(self._config, 10) # Second start tracing will raise error. with self.assertRaises(AssertionError): - self._agent.Start(self._trace_options, self._category_filter, 10) + self._agent.Start(self._config, 10) self._platform_backend.surface_stats_collector.Stop.return_value = (0, []) self._agent.Stop(mock.MagicMock()) # Can start and stop tracing multiple times. - self._agent.Start(self._trace_options, self._category_filter, 10) + self._agent.Start(self._config, 10) self._platform_backend.surface_stats_collector.Stop.return_value = (0, []) self._agent.Stop(mock.MagicMock()) @mock.patch( 'devil.android.perf.surface_stats_collector.SurfaceStatsCollector') def testExceptionRaisedInStopTracing(self, MockSurfaceStatsCollector): - self._agent.Start(self._trace_options, self._category_filter, 10) + self._agent.Start(self._config, 10) self._platform_backend.surface_stats_collector.Stop.side_effect = Exception( 'Raise error when stopping tracing.') with self.assertRaises(Exception): @@ -60,7 +58,7 @@ # Tracing is stopped even if there is exception. And the agent can start # tracing again. - self._agent.Start(self._trace_options, self._category_filter, 10) + self._agent.Start(self._config, 10) self._platform_backend.surface_stats_collector.Stop.side_effect = None self._platform_backend.surface_stats_collector.Stop.return_value = (0, []) self._agent.Stop(mock.MagicMock())
diff --git a/tools/telemetry/telemetry/internal/platform/tracing_controller_backend.py b/tools/telemetry/telemetry/internal/platform/tracing_controller_backend.py index 6e2fff27..af530f4 100644 --- a/tools/telemetry/telemetry/internal/platform/tracing_controller_backend.py +++ b/tools/telemetry/telemetry/internal/platform/tracing_controller_backend.py
@@ -11,8 +11,7 @@ from telemetry.internal.platform import tracing_agent from telemetry.internal.platform.tracing_agent import chrome_tracing_agent from telemetry.timeline import trace_data as trace_data_module -from telemetry.timeline import tracing_category_filter -from telemetry.timeline import tracing_options +from telemetry.timeline import tracing_config def _IterAllTracingAgentClasses(): @@ -30,26 +29,21 @@ class TracingControllerBackend(object): def __init__(self, platform_backend): self._platform_backend = platform_backend - self._current_trace_options = None - self._current_category_filter = None self._current_chrome_tracing_agent = None + self._current_config = None self._supported_agents_classes = [ agent_classes for agent_classes in _IterAllTracingAgentClasses() if agent_classes.IsSupported(platform_backend)] self._active_agents_instances = [] - def Start(self, trace_options, category_filter, timeout): + def Start(self, config, timeout): if self.is_tracing_running: return False - assert isinstance(category_filter, - tracing_category_filter.TracingCategoryFilter) - assert isinstance(trace_options, - tracing_options.TracingOptions) + assert isinstance(config, tracing_config.TracingConfig) assert len(self._active_agents_instances) == 0 - self._current_trace_options = trace_options - self._current_category_filter = category_filter + self._current_config = config # Hack: chrome tracing agent may only depend on the number of alive chrome # devtools processes, rather platform (when startup tracing is not # supported), hence we add it to the list of supported agents here if it was @@ -63,7 +57,7 @@ for agent_class in self._supported_agents_classes: agent = agent_class(self._platform_backend) - if agent.Start(trace_options, category_filter, timeout): + if agent.Start(config, timeout): self._active_agents_instances.append(agent) def Stop(self): @@ -79,8 +73,7 @@ ''.join(traceback.format_exception(*sys.exc_info()))) self._active_agents_instances = [] - self._current_trace_options = None - self._current_category_filter = None + self._current_config = None if raised_execption_messages: raise TracingControllerStoppedError( @@ -95,12 +88,12 @@ @property def is_tracing_running(self): - return self._current_trace_options != None + return self._current_config != None def _GetActiveChromeTracingAgent(self): if not self.is_tracing_running: return None - if not self._current_trace_options.enable_chrome_trace: + if not self._current_config.tracing_options.enable_chrome_trace: return None for agent in self._active_agents_instances: if isinstance(agent, chrome_tracing_agent.ChromeTracingAgent):
diff --git a/tools/telemetry/telemetry/page/__init__.py b/tools/telemetry/telemetry/page/__init__.py index c635798..b715e66 100644 --- a/tools/telemetry/telemetry/page/__init__.py +++ b/tools/telemetry/telemetry/page/__init__.py
@@ -6,15 +6,14 @@ import os import urlparse -from telemetry import decorators from telemetry import story from catapult_base import cloud_storage -from telemetry.internal.util import path from telemetry.page import shared_page_state from telemetry.page import action_runner as action_runner_module class Page(story.Story): + def __init__(self, url, page_set=None, base_dir=None, name='', credentials_path=None, credentials_bucket=cloud_storage.PUBLIC_BUCKET, labels=None, @@ -84,7 +83,7 @@ shared_state.page_test.RunNavigateSteps(self, current_tab) shared_state.page_test.DidNavigateToPage(self, current_tab) action_runner = action_runner_module.ActionRunner( - current_tab, skip_waits=self.skip_waits) + current_tab, skip_waits=self.skip_waits) self.RunPageInteractions(action_runner) def RunNavigateSteps(self, action_runner): @@ -104,8 +103,8 @@ def AsDict(self): """Converts a page object to a dict suitable for JSON output.""" d = { - 'id': self._id, - 'url': self._url, + 'id': self._id, + 'url': self._url, } if self._name: d['name'] = self._name @@ -115,7 +114,6 @@ def story_set(self): return self._page_set - # TODO(nednguyen, aiolos): deprecate this property. @property def page_set(self): @@ -163,7 +161,7 @@ """Returns the path of the file, stripping the scheme and query string.""" assert self.is_file # Because ? is a valid character in a filename, - # we have to treat the url as a non-file by removing the scheme. + # we have to treat the URL as a non-file by removing the scheme. parsed_url = urlparse.urlparse(self.url[7:]) return os.path.normpath(os.path.join( self._base_dir, parsed_url.netloc + parsed_url.path)) @@ -176,7 +174,8 @@ def file_path_url(self): """Returns the file path, including the params, query, and fragment.""" assert self.is_file - file_path_url = os.path.normpath(os.path.join(self._base_dir, self.url[7:])) + file_path_url = os.path.normpath( + os.path.join(self._base_dir, self.url[7:])) # Preserve trailing slash or backslash. # It doesn't matter in a file path, but it does matter in a URL. if self.url.endswith('/'):
diff --git a/tools/telemetry/telemetry/page/action_runner.py b/tools/telemetry/telemetry/page/action_runner.py index e1875d6..aa11bdd 100644 --- a/tools/telemetry/telemetry/page/action_runner.py +++ b/tools/telemetry/telemetry/page/action_runner.py
@@ -106,7 +106,7 @@ def Navigate(self, url, script_to_evaluate_on_commit=None, timeout_in_seconds=60): - """Navigates to url. + """Navigates to |url|. If |script_to_evaluate_on_commit| is given, the script source string will be evaluated when the navigation is committed. This is after the context of @@ -125,7 +125,7 @@ self._tab.WaitForNavigate(timeout_in_seconds_seconds) time_left_in_seconds = (start_time + timeout_in_seconds_seconds - - time.time()) + - time.time()) time_left_in_seconds = max(0, time_left_in_seconds) self._tab.WaitForDocumentReadyStateToBeInteractiveOrBetter( time_left_in_seconds) @@ -461,11 +461,12 @@ overscroll=overscroll, repeat_count=repeat_count, speed_in_pixels_per_second=speed_in_pixels_per_second)) - def ScrollBounceElement(self, selector=None, text=None, element_function=None, - left_start_ratio=0.5, top_start_ratio=0.5, - direction='down', distance=100, - overscroll=10, repeat_count=10, - speed_in_pixels_per_second=400): + def ScrollBounceElement( + self, selector=None, text=None, element_function=None, + left_start_ratio=0.5, top_start_ratio=0.5, + direction='down', distance=100, + overscroll=10, repeat_count=10, + speed_in_pixels_per_second=400): """Perform scroll bounce gesture on the element. This gesture scrolls on the element by the number of pixels specified in @@ -489,7 +490,7 @@ 'up', 'down', 'upleft', 'upright', 'downleft', or 'downright' distance: The distance to scroll (in pixel). overscroll: The number of additional pixels to scroll back, in - addition to the givendistance. + addition to the given distance. repeat_count: How often we want to repeat the full gesture. speed_in_pixels_per_second: The speed of the gesture (in pixels/s). """ @@ -683,6 +684,7 @@ self._RunAction(RepaintContinuouslyAction( seconds=0 if self._skip_waits else seconds)) + class Interaction(object): def __init__(self, action_runner, label, flags): @@ -710,13 +712,15 @@ def Begin(self): assert not self._started self._started = True - self._action_runner.ExecuteJavaScript('console.time("%s");' % + self._action_runner.ExecuteJavaScript( + 'console.time("%s");' % timeline_interaction_record.GetJavaScriptMarker( - self._label, self._flags)) + self._label, self._flags)) def End(self): assert self._started self._started = False - self._action_runner.ExecuteJavaScript('console.timeEnd("%s");' % + self._action_runner.ExecuteJavaScript( + 'console.timeEnd("%s");' % timeline_interaction_record.GetJavaScriptMarker( - self._label, self._flags)) + self._label, self._flags))
diff --git a/tools/telemetry/telemetry/page/page_run_end_to_end_unittest.py b/tools/telemetry/telemetry/page/page_run_end_to_end_unittest.py index ef72b7f..eb3cd0b 100644 --- a/tools/telemetry/telemetry/page/page_run_end_to_end_unittest.py +++ b/tools/telemetry/telemetry/page/page_run_end_to_end_unittest.py
@@ -30,8 +30,6 @@ from telemetry.testing import system_stub -# pylint: disable=bad-super-call - SIMPLE_CREDENTIALS_STRING = """ { "test": { @@ -40,7 +38,10 @@ } } """ + + class DummyTest(page_test.PageTest): + def ValidateAndMeasurePage(self, *_): pass @@ -51,11 +52,15 @@ options.MergeDefaultValues(parser.get_default_values()) story_runner.ProcessCommandLineArgs(parser, options) + class EmptyMetadataForTest(benchmark.BenchmarkMetadata): + def __init__(self): super(EmptyMetadataForTest, self).__init__('') + class StubCredentialsBackend(object): + def __init__(self, login_return_value): self.did_get_login = False self.did_get_login_no_longer_needed = False @@ -143,6 +148,7 @@ 'file://blank.html', story_set, base_dir=util.GetUnittestDataDir())) class Test(page_test.PageTest): + def __init__(self, *args): super(Test, self).__init__( *args, needs_browser_restart_after_each_page=True) @@ -179,6 +185,7 @@ 'file://blank.html', story_set, base_dir=util.GetUnittestDataDir())) class Test(page_test.PageTest): + def __init__(self, *args, **kwargs): super(Test, self).__init__(*args, **kwargs) self.browser_starts = 0 @@ -205,16 +212,16 @@ self.CaptureFormattedException() credentials_backend = StubCredentialsBackend(login_return_value=False) did_run = self.runCredentialsTest(credentials_backend) - assert credentials_backend.did_get_login == True - assert credentials_backend.did_get_login_no_longer_needed == False - assert did_run == False + assert credentials_backend.did_get_login + assert not credentials_backend.did_get_login_no_longer_needed + assert not did_run self.assertFormattedExceptionIsEmpty() def testCredentialsWhenLoginSucceeds(self): credentials_backend = StubCredentialsBackend(login_return_value=True) did_run = self.runCredentialsTest(credentials_backend) - assert credentials_backend.did_get_login == True - assert credentials_backend.did_get_login_no_longer_needed == True + assert credentials_backend.did_get_login + assert credentials_backend.did_get_login_no_longer_needed assert did_run def runCredentialsTest(self, credentials_backend): @@ -224,14 +231,15 @@ try: with tempfile.NamedTemporaryFile(delete=False) as f: page = page_module.Page( - 'file://blank.html', story_set, base_dir=util.GetUnittestDataDir(), - credentials_path=f.name) + 'file://blank.html', story_set, base_dir=util.GetUnittestDataDir(), + credentials_path=f.name) page.credentials = "test" story_set.AddStory(page) f.write(SIMPLE_CREDENTIALS_STRING) class TestThatInstallsCredentialsBackend(page_test.PageTest): + def __init__(self, credentials_backend): super(TestThatInstallsCredentialsBackend, self).__init__() self._credentials_backend = credentials_backend @@ -272,7 +280,7 @@ # This is so we can check later that the test actually made it into this # function. Previously it was timing out before even getting here, which # should fail, but since it skipped all the asserts, it slipped by. - self.hasRun = True # pylint: disable=attribute-defined-outside-init + self.hasRun = True # pylint: disable=attribute-defined-outside-init test = TestUserAgent() options = options_for_unittests.GetCopy() @@ -293,6 +301,7 @@ story_set.AddStory(page) class TestOneTab(page_test.PageTest): + def DidStartBrowser(self, browser): browser.tabs.New() @@ -342,6 +351,7 @@ story_set.AddStory(page) class TestBeforeLaunch(page_test.PageTest): + def __init__(self): super(TestBeforeLaunch, self).__init__() self._did_call_will_start = False @@ -368,7 +378,9 @@ def testRunPageWithStartupUrl(self): num_times_browser_closed = [0] + class TestSharedState(shared_page_state.SharedPageState): + def _StopBrowser(self): super(TestSharedState, self)._StopBrowser() num_times_browser_closed[0] += 1 @@ -379,6 +391,7 @@ story_set.AddStory(page) class Measurement(page_test.PageTest): + def __init__(self): super(Measurement, self).__init__() @@ -408,6 +421,7 @@ story_set.AddStory(page) class Test(page_test.PageTest): + def __init__(self): super(Test, self).__init__() self.did_call_clean_up = False @@ -419,7 +433,6 @@ del platform # unused self.did_call_clean_up = True - test = Test() options = options_for_unittests.GetCopy() options.output_formats = ['none'] @@ -437,6 +450,7 @@ def CanRunOnBrowser(self, browser_info, page): del browser_info, page # unused return False + def ValidateAndMeasurePage(self, _): pass @@ -446,6 +460,7 @@ shared_page_state_class=UnrunnableSharedState)) class Test(page_test.PageTest): + def __init__(self, *args, **kwargs): super(Test, self).__init__(*args, **kwargs) self.will_navigate_to_page_called = False @@ -476,6 +491,7 @@ 'file://blank.html', story_set, base_dir=util.GetUnittestDataDir())) class Measurement(page_test.PageTest): + def ValidateAndMeasurePage(self, page, tab, results): pass @@ -501,6 +517,7 @@ def _RunPageTestThatRaisesAppCrashException(self, test, max_failures): class TestPage(page_module.Page): + def RunNavigateSteps(self, _): raise exceptions.AppCrashException @@ -515,18 +532,21 @@ SetUpStoryRunnerArguments(options) results = results_options.CreateResults(EmptyMetadataForTest(), options) story_runner.Run(test, story_set, options, results, - max_failures=max_failures) + max_failures=max_failures) return results def testSingleTabMeansCrashWillCauseFailureValue(self): self.CaptureFormattedException() + class SingleTabTest(page_test.PageTest): # Test is not multi-tab because it does not override TabForPage. + def ValidateAndMeasurePage(self, *_): pass test = SingleTabTest() - results = self._RunPageTestThatRaisesAppCrashException(test, max_failures=1) + results = self._RunPageTestThatRaisesAppCrashException( + test, max_failures=1) self.assertEquals([], GetSuccessfulPageRuns(results)) self.assertEquals(2, len(results.failures)) # max_failures + 1 self.assertFormattedExceptionIsEmpty() @@ -534,10 +554,13 @@ @decorators.Enabled('has tabs') def testMultipleTabsMeansCrashRaises(self): self.CaptureFormattedException() + class MultipleTabsTest(page_test.PageTest): # Test *is* multi-tab because it overrides TabForPage. + def TabForPage(self, page, browser): return browser.tabs.New() + def ValidateAndMeasurePage(self, *_): pass @@ -549,6 +572,7 @@ def testWebPageReplay(self): story_set = example_domain.ExampleDomainPageSet() body = [] + class TestWpr(page_test.PageTest): def ValidateAndMeasurePage(self, page, tab, results): del page, results # unused @@ -576,7 +600,9 @@ platform_screenshot_supported = [False] tab_screenshot_supported = [False] chrome_version_screen_shot = [None] + class FailingTestPage(page_module.Page): + def RunNavigateSteps(self, action_runner): action_runner.Navigate(self._url) platform_screenshot_supported[0] = ( @@ -614,7 +640,9 @@ def testNoProfilingFilesCreatedForPageByDefault(self): self.CaptureFormattedException() + class FailingTestPage(page_module.Page): + def RunNavigateSteps(self, action_runner): action_runner.Navigate(self._url) raise exceptions.AppCrashException @@ -635,6 +663,7 @@ class FakePageRunEndToEndTests(unittest.TestCase): + def setUp(self): self.options = fakes.CreateBrowserFinderOptions() self.options.output_formats = ['none'] @@ -645,6 +674,7 @@ self.options.browser_options.take_screenshot_for_failed_page = True class FailingTestPage(page_module.Page): + def RunNavigateSteps(self, action_runner): raise exceptions.AppCrashException @@ -670,6 +700,7 @@ self.options.browser_options.take_screenshot_for_failed_page = True class FailingTestPage(page_module.Page): + def RunNavigateSteps(self, action_runner): raise exceptions.AppCrashException story_set = story.StorySet() @@ -690,7 +721,7 @@ try: actual_screenshot_img = image_util.FromPngFile(screenshot_file_path) self.assertTrue(image_util.AreEqual( - image_util.FromBase64Png(expected_png_base64), - actual_screenshot_img)) + image_util.FromBase64Png(expected_png_base64), + actual_screenshot_img)) finally: # Must clean up screenshot file if exists. os.remove(screenshot_file_path)
diff --git a/tools/telemetry/telemetry/page/page_test_unittest.py b/tools/telemetry/telemetry/page/page_test_unittest.py index 80630c27..23bb5f38 100644 --- a/tools/telemetry/telemetry/page/page_test_unittest.py +++ b/tools/telemetry/telemetry/page/page_test_unittest.py
@@ -17,11 +17,13 @@ class PageTestThatFails(page_test.PageTest): + def ValidateAndMeasurePage(self, page, tab, results): raise page_test.Failure class PageTestForBlank(page_test.PageTest): + def ValidateAndMeasurePage(self, page, tab, results): contents = tab.EvaluateJavaScript('document.body.textContent') if contents.strip() != 'Hello world': @@ -30,6 +32,7 @@ class PageTestForReplay(page_test.PageTest): + def ValidateAndMeasurePage(self, page, tab, results): # Web Page Replay returns '404 Not found' if a page is not in the archive. contents = tab.EvaluateJavaScript('document.body.textContent') @@ -38,6 +41,7 @@ class PageTestQueryParams(page_test.PageTest): + def ValidateAndMeasurePage(self, page, tab, results): query = tab.EvaluateJavaScript('window.location.search') expected = '?foo=1' @@ -47,6 +51,7 @@ class PageTestWithAction(page_test.PageTest): + def __init__(self): super(PageTestWithAction, self).__init__() @@ -55,6 +60,7 @@ class PageWithAction(page_module.Page): + def __init__(self, url, story_set): super(PageWithAction, self).__init__(url, story_set, story_set.base_dir) self.run_test_action_called = False @@ -77,7 +83,8 @@ self.assertEquals(0, len(all_results.failures)) def testGotQueryParams(self): - story_set = self.CreateStorySetFromFileInUnittestDataDir('blank.html?foo=1') + story_set = self.CreateStorySetFromFileInUnittestDataDir( + 'blank.html?foo=1') measurement = PageTestQueryParams() all_results = self.RunMeasurement( measurement, story_set, options=self._options) @@ -111,10 +118,9 @@ # First record an archive with only www.google.com. self._options.browser_options.wpr_mode = wpr_modes.WPR_RECORD - # pylint: disable=protected-access story_set._wpr_archive_info = archive_info.WprArchiveInfo( - '', '', story_set.bucket, json.loads(archive_info_template % - (test_archive, google_url))) + '', '', story_set.bucket, json.loads( + archive_info_template % (test_archive, google_url))) story_set.pages = [page_module.Page(google_url, story_set)] all_results = self.RunMeasurement( measurement, story_set, options=self._options) @@ -123,19 +129,18 @@ # Now replay it and verify that google.com is found but foo.com is not. self._options.browser_options.wpr_mode = wpr_modes.WPR_REPLAY - # pylint: disable=protected-access story_set._wpr_archive_info = archive_info.WprArchiveInfo( - '', '', story_set.bucket, json.loads(archive_info_template % - (test_archive, foo_url))) + '', '', story_set.bucket, json.loads( + archive_info_template % + (test_archive, foo_url))) story_set.pages = [page_module.Page(foo_url, story_set)] all_results = self.RunMeasurement( measurement, story_set, options=self._options) self.assertEquals(1, len(all_results.failures)) - # pylint: disable=protected-access story_set._wpr_archive_info = archive_info.WprArchiveInfo( - '', '', story_set.bucket, json.loads(archive_info_template % - (test_archive, google_url))) + '', '', story_set.bucket, json.loads( + archive_info_template % (test_archive, google_url))) story_set.pages = [page_module.Page(google_url, story_set)] all_results = self.RunMeasurement( measurement, story_set, options=self._options) @@ -157,8 +162,10 @@ class MultiTabPageTestUnitTest(unittest.TestCase): + def testNoTabForPageReturnsFalse(self): class PageTestWithoutTabForPage(page_test.PageTest): + def ValidateAndMeasurePage(self, *_): pass test = PageTestWithoutTabForPage() @@ -166,8 +173,10 @@ def testHasTabForPageReturnsTrue(self): class PageTestWithTabForPage(page_test.PageTest): + def ValidateAndMeasurePage(self, *_): pass + def TabForPage(self, *_): pass test = PageTestWithTabForPage() @@ -175,10 +184,13 @@ def testHasTabForPageInAncestor(self): class PageTestWithTabForPage(page_test.PageTest): + def ValidateAndMeasurePage(self, *_): pass + def TabForPage(self, *_): pass + class PageTestWithTabForPageInParent(PageTestWithTabForPage): pass test = PageTestWithTabForPageInParent()
diff --git a/tools/telemetry/telemetry/page/page_unittest.py b/tools/telemetry/telemetry/page/page_unittest.py index 6270c6e9..7620465 100644 --- a/tools/telemetry/telemetry/page/page_unittest.py +++ b/tools/telemetry/telemetry/page/page_unittest.py
@@ -12,6 +12,7 @@ class TestPage(unittest.TestCase): + def assertPathEqual(self, path1, path2): self.assertEqual(os.path.normpath(path1), os.path.normpath(path2)) @@ -50,16 +51,16 @@ story_set.AddStory( page.Page('http://www.bar.com/', story_set, story_set.base_dir)) - pages = [story_set.stories[0], story_set.stories[1]] - pages.sort() + pages = sorted([story_set.stories[0], story_set.stories[1]]) self.assertEquals([story_set.stories[1], story_set.stories[0]], pages) def testGetUrlBaseDirAndFileForUrlBaseDir(self): base_dir = os.path.dirname(__file__) - file_path = os.path.join(os.path.dirname(base_dir), 'otherdir', 'file.html') + file_path = os.path.join( + os.path.dirname(base_dir), 'otherdir', 'file.html') story_set = story.StorySet(base_dir=base_dir, - serving_dirs=[os.path.join('..', 'somedir', '')]) + serving_dirs=[os.path.join('..', 'somedir', '')]) story_set.AddStory( page.Page('file://../otherdir/file.html', story_set, story_set.base_dir)) @@ -150,17 +151,17 @@ self.assertIn('id', nameless_dict) del nameless_dict['id'] self.assertEquals({ - 'url': 'http://example.com/', - }, nameless_dict) + 'url': 'http://example.com/', + }, nameless_dict) def testNamedPageAsDict(self): named_dict = page.Page('http://example.com/', name='Example').AsDict() self.assertIn('id', named_dict) del named_dict['id'] self.assertEquals({ - 'url': 'http://example.com/', - 'name': 'Example' - }, named_dict) + 'url': 'http://example.com/', + 'name': 'Example' + }, named_dict) def testIsLocal(self): p = page.Page('file://foo.html') @@ -177,6 +178,7 @@ class TestPageRun(unittest.TestCase): + def testFiveGarbageCollectionCallsByDefault(self): mock_shared_state = mock.Mock() p = page.Page('file://foo.html') @@ -187,16 +189,18 @@ mock.call.current_tab.CollectGarbage(), mock.call.current_tab.CollectGarbage(), mock.call.page_test.WillNavigateToPage( - p, mock_shared_state.current_tab), + p, mock_shared_state.current_tab), mock.call.page_test.RunNavigateSteps( - p, mock_shared_state.current_tab), + p, mock_shared_state.current_tab), mock.call.page_test.DidNavigateToPage( - p, mock_shared_state.current_tab)] + p, mock_shared_state.current_tab)] self.assertEquals(mock_shared_state.mock_calls, expected) def testNoGarbageCollectionCalls(self): mock_shared_state = mock.Mock() + class NonGarbageCollectPage(page.Page): + def __init__(self, url): super(NonGarbageCollectPage, self).__init__(url) self._collect_garbage_before_run = False @@ -204,9 +208,9 @@ p = NonGarbageCollectPage('file://foo.html') p.Run(mock_shared_state) expected = [mock.call.page_test.WillNavigateToPage( - p, mock_shared_state.current_tab), + p, mock_shared_state.current_tab), mock.call.page_test.RunNavigateSteps( - p, mock_shared_state.current_tab), + p, mock_shared_state.current_tab), mock.call.page_test.DidNavigateToPage( - p, mock_shared_state.current_tab)] + p, mock_shared_state.current_tab)] self.assertEquals(mock_shared_state.mock_calls, expected)
diff --git a/tools/telemetry/telemetry/page/shared_page_state.py b/tools/telemetry/telemetry/page/shared_page_state.py index 5d4b048..c32b72c5 100644 --- a/tools/telemetry/telemetry/page/shared_page_state.py +++ b/tools/telemetry/telemetry/page/shared_page_state.py
@@ -1,6 +1,7 @@ # Copyright 2014 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. + import logging import os import shutil @@ -36,6 +37,7 @@ profiler_class.CustomizeBrowserOptions(browser_options.browser_type, finder_options) + class SharedPageState(story.SharedState): """ This class contains all specific logic necessary to run a Chrome browser @@ -47,11 +49,11 @@ def __init__(self, test, finder_options, story_set): super(SharedPageState, self).__init__(test, finder_options, story_set) if isinstance(test, timeline_based_measurement.TimelineBasedMeasurement): - assert not finder_options.profiler, ('This is a Timeline Based ' - 'Measurement benchmark. You cannot run it with the --profiler flag. ' - 'If you need trace data, tracing is always enabled in Timeline Based ' - 'Measurement benchmarks and you can get the trace data by using ' - '--output-format=json.') + assert not finder_options.profiler, ( + 'This is a Timeline Based Measurement benchmark. You cannot run it ' + 'with the --profiler flag. If you need trace data, tracing is always ' + ' enabled in Timeline Based Measurement benchmarks and you can get ' + 'the trace data by using --output-format=json.') # This is to avoid the cyclic-import caused by timeline_based_page_test. from telemetry.web_perf import timeline_based_page_test self._test = timeline_based_page_test.TimelineBasedPageTest(test) @@ -61,6 +63,7 @@ # TODO(aiolos, nednguyen): Remove this logic of pulling out user_agent_type # from story_set once all page_set are converted to story_set # (crbug.com/439512). + def _IsPageSetInstance(s): # This is needed to avoid importing telemetry.page.page_set which will # cause cyclic import. @@ -103,12 +106,12 @@ finder_options.browser_options.browser_type = ( possible_browser.browser_type) - (enabled, msg) = decorators.IsEnabled(test, possible_browser) - if (not enabled and - not finder_options.run_disabled_tests): + enabled, msg = decorators.IsEnabled(test, possible_browser) + if not enabled and not finder_options.run_disabled_tests: logging.warning(msg) logging.warning('You are trying to run a disabled test.') - logging.warning('Pass --also-run-disabled-tests to squelch this message.') + logging.warning( + 'Pass --also-run-disabled-tests to squelch this message.') sys.exit(0) if possible_browser.IsRemote(): @@ -226,7 +229,6 @@ else: logging.warning('System info not supported') - def WillRunStory(self, page): if self._ShouldDownloadPregeneratedProfileArchive(): self._DownloadPregeneratedProfileArchive() @@ -262,7 +264,7 @@ # navigation has begun and RenderFrameHostManager::DidNavigateMainFrame() # will cancel the next navigation because it's pending. This manifests as # the first navigation in a PageSet freezing indefinitely because the - # navigation was silently cancelled when |self.browser.tabs[0]| was + # navigation was silently canceled when |self.browser.tabs[0]| was # committed. Only do this when we just started the browser, otherwise # there are cases where previous pages in a PageSet never complete # loading so we'll wait forever. @@ -402,23 +404,23 @@ finder_options.output_profile_path = saved_output_profile def _MigratePregeneratedProfile(self): - """Migrates the pregenerated profile by launching Chrome with it. + """Migrates the pre-generated profile by launching Chrome with it. On success, updates self._migrated_profile and self._finder_options.browser_options.profile_dir with the directory of the migrated profile. """ self._migrated_profile = tempfile.mkdtemp() - logging.info("Starting migration of pregenerated profile to %s", - self._migrated_profile) + logging.info("Starting migration of pre-generated profile to %s", + self._migrated_profile) pregenerated_profile = self._finder_options.browser_options.profile_dir possible_browser = self._FindBrowser(self._finder_options) self._MigrateProfile(self._finder_options, possible_browser, pregenerated_profile, self._migrated_profile) self._finder_options.browser_options.profile_dir = self._migrated_profile - logging.info("Finished migration of pregenerated profile to %s", - self._migrated_profile) + logging.info("Finished migration of pre-generated profile to %s", + self._migrated_profile) def GetPregeneratedProfileArchiveDir(self): return self._pregenerated_profile_archive_dir @@ -427,7 +429,7 @@ """ Benchmarks can set a pre-generated profile archive to indicate that when Chrome is launched, it should have a --user-data-dir set to the - pregenerated profile, rather than to an empty profile. + pre-generated profile, rather than to an empty profile. If the benchmark is invoked with the option --profile-dir=<dir>, that option overrides this value. @@ -443,8 +445,8 @@ # If profile dir is specified on command line, use that instead. if self._finder_options.browser_options.profile_dir: logging.warning("Profile directory specified on command line: %s, this" - "overrides the benchmark's default profile directory.", - self._finder_options.browser_options.profile_dir) + "overrides the benchmark's default profile directory.", + self._finder_options.browser_options.profile_dir) return False # If the browser is remote, a local download has no effect. @@ -464,14 +466,14 @@ try: cloud_storage.GetIfChanged(generated_profile_archive_path, - cloud_storage.PUBLIC_BUCKET) + cloud_storage.PUBLIC_BUCKET) except (cloud_storage.CredentialsError, cloud_storage.PermissionError) as e: if os.path.exists(generated_profile_archive_path): # If the profile directory archive exists, assume the user has their # own local copy simply warn. logging.warning('Could not download Profile archive: %s', - generated_profile_archive_path) + generated_profile_archive_path) else: # If the archive profile directory doesn't exist, this is fatal. logging.error('Can not run without required profile archive: %s. ' @@ -484,7 +486,7 @@ # Check to make sure the zip file exists. if not os.path.isfile(generated_profile_archive_path): raise Exception("Profile directory archive not downloaded: ", - generated_profile_archive_path) + generated_profile_archive_path) # The location to extract the profile into. extracted_profile_dir_path = ( @@ -503,10 +505,11 @@ # Run with freshly extracted profile directory. logging.info("Using profile archive directory: %s", - extracted_profile_dir_path) + extracted_profile_dir_path) self._finder_options.browser_options.profile_dir = ( extracted_profile_dir_path) + class SharedMobilePageState(SharedPageState): _device_type = 'mobile'
diff --git a/tools/telemetry/telemetry/page/shared_page_state_unittest.py b/tools/telemetry/telemetry/page/shared_page_state_unittest.py index fc4150a..c6b5e3e 100644 --- a/tools/telemetry/telemetry/page/shared_page_state_unittest.py +++ b/tools/telemetry/telemetry/page/shared_page_state_unittest.py
@@ -22,11 +22,13 @@ class DummyTest(page_test.PageTest): + def ValidateAndMeasurePage(self, *_): pass class FakeNetworkController(object): + def __init__(self): self.archive_path = None self.wpr_mode = None @@ -46,7 +48,6 @@ self.options.output_formats = ['none'] self.options.suppress_gtest_report = True - # pylint: disable=protected-access def TestUseLiveSitesFlag(self, expected_wpr_mode): with tempfile.NamedTemporaryFile() as f: run_state = shared_page_state.SharedPageState( @@ -115,4 +116,4 @@ for p in (google_page, example_page, gmail_page): shared_state.WillRunStory(p) self.assertEquals( - p.startup_url, self.options.browser_options.startup_url) + p.startup_url, self.options.browser_options.startup_url)
diff --git a/tools/telemetry/telemetry/timeline/tracing_category_filter.py b/tools/telemetry/telemetry/timeline/tracing_category_filter.py index 85f79f9..c417d13 100644 --- a/tools/telemetry/telemetry/timeline/tracing_category_filter.py +++ b/tools/telemetry/telemetry/timeline/tracing_category_filter.py
@@ -53,7 +53,9 @@ self._disabled_by_default_categories = set() self._synthetic_delays = set() self.contains_wildcards = False + self.AddFilterString(filter_string) + def AddFilterString(self, filter_string): if filter_string == None: return @@ -136,6 +138,10 @@ result[SYNTHETIC_DELAYS_PARAM] = list(self._synthetic_delays) return result + def AddDisabledByDefault(self, category): + assert category.startswith('disabled-by-default-') + self._disabled_by_default_categories.add(category) + def AddIncludedCategory(self, category_glob): """Explicitly enables anything matching category_glob.""" assert not category_glob.startswith('disabled-by-default-')
diff --git a/tools/telemetry/telemetry/timeline/tracing_config.py b/tools/telemetry/telemetry/timeline/tracing_config.py index e0d5208..6122ce4 100644 --- a/tools/telemetry/telemetry/timeline/tracing_config.py +++ b/tools/telemetry/telemetry/timeline/tracing_config.py
@@ -4,6 +4,8 @@ import json +from telemetry.timeline import tracing_category_filter +from telemetry.timeline import tracing_options class TracingConfig(object): """Tracing config is the configuration for Chrome tracing. @@ -11,9 +13,10 @@ This produces the trace config JSON string for Chrome tracing. For the details about the JSON string format, see base/trace_event/trace_config.h. """ - def __init__(self, tracing_options, tracing_category_filter): - self._tracing_options = tracing_options - self._tracing_category_filter = tracing_category_filter + def __init__(self): + self._tracing_options = tracing_options.TracingOptions() + self._tracing_category_filter = ( + tracing_category_filter.TracingCategoryFilter()) @property def tracing_options(self): @@ -23,8 +26,45 @@ def tracing_category_filter(self): return self._tracing_category_filter - def GetTraceConfigJsonString(self): + def GetChromeTraceConfigJsonString(self): result = {} result.update(self._tracing_options.GetDictForChromeTracing()) result.update(self._tracing_category_filter.GetDictForChromeTracing()) return json.dumps(result, sort_keys=True) + + def SetNoOverheadFilter(self): + """Sets a filter with the least overhead possible. + + This contains no sub-traces of thread tasks, so it's only useful for + capturing the cpu-time spent on threads (as well as needed benchmark + traces). + + FIXME: Remove webkit.console when blink.console lands in chromium and + the ref builds are updated. crbug.com/386847 + """ + categories = [ + "toplevel", + "benchmark", + "webkit.console", + "blink.console", + "trace_event_overhead" + ] + self._tracing_category_filter = ( + tracing_category_filter.TracingCategoryFilter( + filter_string=','.join(categories))) + + def SetMinimalOverheadFilter(self): + self._tracing_category_filter = ( + tracing_category_filter.TracingCategoryFilter(filter_string='')) + + def SetDebugOverheadFilter(self): + self._tracing_category_filter = ( + tracing_category_filter.TracingCategoryFilter( + filter_string='*,disabled-by-default-cc.debug')) + + def SetTracingCategoryFilter(self, cf): + if isinstance(cf, tracing_category_filter.TracingCategoryFilter): + self._tracing_category_filter = cf + else: + raise TypeError( + 'Must pass SetTracingCategoryFilter a TracingCategoryFilter instance')
diff --git a/tools/telemetry/telemetry/timeline/tracing_config_unittest.py b/tools/telemetry/telemetry/timeline/tracing_config_unittest.py index 5462f721..daf00a4 100644 --- a/tools/telemetry/telemetry/timeline/tracing_config_unittest.py +++ b/tools/telemetry/telemetry/timeline/tracing_config_unittest.py
@@ -11,10 +11,8 @@ class TracingConfigTests(unittest.TestCase): def testDefault(self): - options = tracing_options.TracingOptions() - category_filter = tracing_category_filter.TracingCategoryFilter() - config = tracing_config.TracingConfig(options, category_filter) - config_string = config.GetTraceConfigJsonString() + config = tracing_config.TracingConfig() + config_string = config.GetChromeTraceConfigJsonString() self.assertEquals( '{' '"record_mode": "record-as-much-as-possible"' @@ -22,13 +20,13 @@ config_string) def testBasic(self): - options = tracing_options.TracingOptions() - options.record_mode = tracing_options.RECORD_UNTIL_FULL - options.enable_systrace = True category_filter = tracing_category_filter.TracingCategoryFilter( 'x,-y,disabled-by-default-z,DELAY(7;foo)') - config = tracing_config.TracingConfig(options, category_filter) - config_string = config.GetTraceConfigJsonString() + config = tracing_config.TracingConfig() + config.SetTracingCategoryFilter(category_filter) + config.tracing_options.enable_systrace = True + config.tracing_options.record_mode = tracing_options.RECORD_UNTIL_FULL + config_string = config.GetChromeTraceConfigJsonString() self.assertEquals( '{' '"enable_systrace": true, '
diff --git a/tools/telemetry/telemetry/web_perf/smooth_gesture_util_unittest.py b/tools/telemetry/telemetry/web_perf/smooth_gesture_util_unittest.py index b2581ea..a324e41a9 100644 --- a/tools/telemetry/telemetry/web_perf/smooth_gesture_util_unittest.py +++ b/tools/telemetry/telemetry/web_perf/smooth_gesture_util_unittest.py
@@ -10,8 +10,7 @@ from telemetry.testing import page_test_test_case from telemetry.timeline import async_slice from telemetry.timeline import model as model_module -from telemetry.timeline import tracing_category_filter -from telemetry.timeline import tracing_options +from telemetry.timeline import tracing_config from telemetry.web_perf import smooth_gesture_util as sg_util from telemetry.web_perf import timeline_interaction_record as tir_module @@ -112,6 +111,7 @@ class SmoothGestureTest(page_test_test_case.PageTestTestCase): @decorators.Disabled('mac', # crbug.com/450171 + 'win', # crbug.com/570955 'chromeos') # crbug.com/483212 def testSmoothGestureAdjusted(self): ps = self.CreateEmptyPageSet() @@ -126,10 +126,9 @@ def WillNavigateToPage(self, page, tab): del page # unused - options = tracing_options.TracingOptions() - options.enable_chrome_trace = True - tab.browser.platform.tracing_controller.Start( - options, tracing_category_filter.TracingCategoryFilter()) + config = tracing_config.TracingConfig() + config.tracing_options.enable_chrome_trace = True + tab.browser.platform.tracing_controller.Start(config) def ValidateAndMeasurePage(self, page, tab, results): del page, results # unused
diff --git a/tools/telemetry/telemetry/web_perf/timeline_based_measurement.py b/tools/telemetry/telemetry/web_perf/timeline_based_measurement.py index 7f7bfdc9..a050ead 100644 --- a/tools/telemetry/telemetry/web_perf/timeline_based_measurement.py +++ b/tools/telemetry/telemetry/web_perf/timeline_based_measurement.py
@@ -7,7 +7,7 @@ from telemetry.timeline import model as model_module from telemetry.timeline import tracing_category_filter -from telemetry.timeline import tracing_options +from telemetry.timeline import tracing_config from telemetry.value import trace from telemetry.web_perf.metrics import timeline_based_metric from telemetry.web_perf.metrics import blob_timeline @@ -168,45 +168,48 @@ one of NO_OVERHEAD_LEVEL, MINIMAL_OVERHEAD_LEVEL or DEBUG_OVERHEAD_LEVEL. """ - self._category_filter = None + self._config = tracing_config.TracingConfig() + self._config.tracing_options.enable_chrome_trace = True + self._config.tracing_options.enable_platform_display_trace = True + if isinstance(overhead_level, tracing_category_filter.TracingCategoryFilter): - self._category_filter = overhead_level + self._config.SetTracingCategoryFilter(overhead_level) elif overhead_level in ALL_OVERHEAD_LEVELS: if overhead_level == NO_OVERHEAD_LEVEL: - self._category_filter = tracing_category_filter.CreateNoOverheadFilter() + self._config.SetNoOverheadFilter() elif overhead_level == MINIMAL_OVERHEAD_LEVEL: - self._category_filter = ( - tracing_category_filter.CreateMinimalOverheadFilter()) + self._config.SetMinimalOverheadFilter() else: - self._category_filter = ( - tracing_category_filter.CreateDebugOverheadFilter()) + self._config.SetDebugOverheadFilter() else: raise Exception("Overhead level must be a TracingCategoryFilter object" " or valid overhead level string." " Given overhead level: %s" % overhead_level) - self._tracing_options = tracing_options.TracingOptions() - self._tracing_options.enable_chrome_trace = True - self._tracing_options.enable_platform_display_trace = True self._timeline_based_metrics = _GetAllTimelineBasedMetrics() def ExtendTraceCategoryFilter(self, filters): for new_category_filter in filters: - self._category_filter.AddIncludedCategory(new_category_filter) + self._config.tracing_category_filter.AddIncludedCategory( + new_category_filter) @property def category_filter(self): - return self._category_filter + return self._config.tracing_category_filter + + @property + def config(self): + return self._config @property def tracing_options(self): - return self._tracing_options + return self._config.tracing_options @tracing_options.setter def tracing_options(self, value): - self._tracing_options = value + self._config.tracing_options = value def SetTimelineBasedMetrics(self, metrics): assert isinstance(metrics, collections.Iterable) @@ -255,8 +258,7 @@ """Configure and start tracing.""" if not platform.tracing_controller.IsChromeTracingSupported(): raise Exception('Not supported') - platform.tracing_controller.Start(self._tbm_options.tracing_options, - self._tbm_options.category_filter) + platform.tracing_controller.Start(self._tbm_options.config) def Measure(self, platform, results): """Collect all possible metrics and added them to results."""
diff --git a/tools/telemetry/third_party/webpagereplay/README.chromium b/tools/telemetry/third_party/webpagereplay/README.chromium index de63579..ac89ce1 100644 --- a/tools/telemetry/third_party/webpagereplay/README.chromium +++ b/tools/telemetry/third_party/webpagereplay/README.chromium
@@ -1,7 +1,7 @@ Name: chromite Short Name: webpagereplay URL: https://github.com/chromium/web-page-replay -Version: ac5d71a0938d98c82220398fbdc9036fdda1240f (commit hash) +Version: baa1ef964a0758e14871be0676899335149a3d78 (commit hash) License: BSD License File: NOT_SHIPPED Security Critical: no
diff --git a/tools/telemetry/third_party/webpagereplay/certutils.py b/tools/telemetry/third_party/webpagereplay/certutils.py index 33236e03..c64e4e0 100644 --- a/tools/telemetry/third_party/webpagereplay/certutils.py +++ b/tools/telemetry/third_party/webpagereplay/certutils.py
@@ -137,7 +137,7 @@ crypto.X509Extension('subjectKeyIdentifier', False, 'hash', subject=ca_cert), ]) - ca_cert.sign(key, 'sha1') + ca_cert.sign(key, 'sha256') key_str = _dump_privatekey(key) ca_cert_str = _dump_cert(ca_cert) return ca_cert_str, key_str @@ -243,7 +243,7 @@ req = crypto.X509Req() req.get_subject().CN = common_name req.set_pubkey(ca_cert.get_pubkey()) - req.sign(key, 'sha1') + req.sign(key, 'sha256') cert.gmtime_adj_notBefore(-60 * 60) cert.gmtime_adj_notAfter(60 * 60 * 24 * 30) @@ -251,6 +251,6 @@ cert.set_subject(req.get_subject()) cert.set_serial_number(int(time.time()*10000)) cert.set_pubkey(req.get_pubkey()) - cert.sign(key, 'sha1') + cert.sign(key, 'sha256') return _dump_cert(cert)
diff --git a/tools/telemetry/third_party/webpagereplay/exception_formatter.py b/tools/telemetry/third_party/webpagereplay/exception_formatter.py new file mode 100644 index 0000000..8ceb0d4 --- /dev/null +++ b/tools/telemetry/third_party/webpagereplay/exception_formatter.py
@@ -0,0 +1,96 @@ +# Copyright 2015 Google Inc. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import math +import os +import sys +import traceback + + +def PrintFormattedException(msg=None): + exception_class, exception, tb = sys.exc_info() + + def _GetFinalFrame(tb_level): + while tb_level.tb_next: + tb_level = tb_level.tb_next + return tb_level.tb_frame + + processed_tb = traceback.extract_tb(tb) + frame = _GetFinalFrame(tb) + exception_list = traceback.format_exception_only(exception_class, exception) + exception_string = '\n'.join(l.strip() for l in exception_list) + + if msg: + print >> sys.stderr + print >> sys.stderr, msg + + _PrintFormattedTrace(processed_tb, frame, exception_string) + +def PrintFormattedFrame(frame, exception_string=None): + _PrintFormattedTrace(traceback.extract_stack(frame), frame, exception_string) + + +def _PrintFormattedTrace(processed_tb, frame, exception_string=None): + """Prints an Exception in a more useful format than the default. + """ + print >> sys.stderr + + # Format the traceback. + base_dir = os.path.dirname(__file__) + print >> sys.stderr, 'Traceback (most recent call last):' + for filename, line, function, text in processed_tb: + filename = os.path.abspath(filename) + if filename.startswith(base_dir): + filename = filename[len(base_dir)+1:] + print >> sys.stderr, ' %s at %s:%d' % (function, filename, line) + print >> sys.stderr, ' %s' % text + + # Format the exception. + if exception_string: + print >> sys.stderr, exception_string + + # Format the locals. + local_variables = [(variable, value) for variable, value in + frame.f_locals.iteritems() if variable != 'self'] + print >> sys.stderr + print >> sys.stderr, 'Locals:' + if local_variables: + longest_variable = max(len(v) for v, _ in local_variables) + for variable, value in sorted(local_variables): + value = repr(value) + possibly_truncated_value = _AbbreviateMiddleOfString(value, ' ... ', 1024) + truncation_indication = '' + if len(possibly_truncated_value) != len(value): + truncation_indication = ' (truncated)' + print >> sys.stderr, ' %s: %s%s' % (variable.ljust(longest_variable + 1), + possibly_truncated_value, + truncation_indication) + else: + print >> sys.stderr, ' No locals!' + + print >> sys.stderr + sys.stderr.flush() + + +def _AbbreviateMiddleOfString(target, middle, max_length): + if max_length < 0: + raise ValueError('Must provide positive max_length') + if len(middle) > max_length: + raise ValueError('middle must not be greater than max_length') + + if len(target) <= max_length: + return target + half_length = (max_length - len(middle)) / 2. + return (target[:int(math.floor(half_length))] + middle + + target[-int(math.ceil(half_length)):])
diff --git a/tools/telemetry/third_party/webpagereplay/httparchive.py b/tools/telemetry/third_party/webpagereplay/httparchive.py index 1eda414..388fc66 100755 --- a/tools/telemetry/third_party/webpagereplay/httparchive.py +++ b/tools/telemetry/third_party/webpagereplay/httparchive.py
@@ -665,6 +665,8 @@ transient state of the transport layer. - user-agent: Changes with every Chrome version. - proxy-connection: Sent for proxy requests. + - x-chrome-variations, x-client-data: Unique to each Chrome binary. Used by + Google to collect statistics about Chrome's enabled features. Another variant to consider is dropping only the value from the header. However, this is particularly bad for the cookie header, because the @@ -682,6 +684,8 @@ if 'accept-encoding' in headers: accept_encoding = headers['accept-encoding'] accept_encoding = accept_encoding.replace('sdch', '') + # Strip lzma so Opera's requests matches archives recorded using Chrome. + accept_encoding = accept_encoding.replace('lzma', '') stripped_encodings = [e.strip() for e in accept_encoding.split(',')] accept_encoding = ','.join(filter(bool, stripped_encodings)) headers['accept-encoding'] = accept_encoding @@ -689,7 +693,7 @@ 'accept', 'accept-charset', 'accept-language', 'cache-control', 'connection', 'cookie', 'keep-alive', 'method', 'referer', 'scheme', 'url', 'version', 'user-agent', 'proxy-connection', - 'x-chrome-variations'] + 'x-chrome-variations', 'x-client-data'] return sorted([(k, v) for k, v in headers.items() if k.lower() not in undesirable_keys])
diff --git a/tools/telemetry/third_party/webpagereplay/httparchive_test.py b/tools/telemetry/third_party/webpagereplay/httparchive_test.py index b09c8028..bc94653 100755 --- a/tools/telemetry/third_party/webpagereplay/httparchive_test.py +++ b/tools/telemetry/third_party/webpagereplay/httparchive_test.py
@@ -80,6 +80,15 @@ self.assertEqual(request._TrimHeaders(header4), [('accept-encoding', 'gzip,deflate')]) + # Tests that 'lzma' gets stripped. + header5 = {'accept-encoding': 'gzip, deflate, lzma'} + self.assertEqual(request._TrimHeaders(header5), + [('accept-encoding', 'gzip,deflate')]) + + # Tests that x-client-data gets stripped. + header6 = {'x-client-data': 'testdata'} + self.assertEqual(request._TrimHeaders(header6), []) + def test_matches(self): headers = {} request1 = httparchive.ArchivedHttpRequest(
diff --git a/tools/telemetry/third_party/webpagereplay/httpclient.py b/tools/telemetry/third_party/webpagereplay/httpclient.py index c650dc4..9159a48 100644 --- a/tools/telemetry/third_party/webpagereplay/httpclient.py +++ b/tools/telemetry/third_party/webpagereplay/httpclient.py
@@ -343,9 +343,9 @@ except Exception, e: if retries: retries -= 1 - logging.warning('Retrying fetch %s: %s', request, e) + logging.warning('Retrying fetch %s: %s', request, repr(e)) continue - logging.critical('Could not fetch %s: %s', request, e) + logging.critical('Could not fetch %s: %s', request, repr(e)) return None
diff --git a/tools/telemetry/third_party/webpagereplay/replay.py b/tools/telemetry/third_party/webpagereplay/replay.py index bb40b51b..50762ce 100755 --- a/tools/telemetry/third_party/webpagereplay/replay.py +++ b/tools/telemetry/third_party/webpagereplay/replay.py
@@ -75,7 +75,11 @@ logging.critical('A logging method (e.g. "logging.warn(...)")' ' was called before logging was configured.') log_level = getattr(logging, log_level_name.upper()) - log_format = '%(asctime)s %(levelname)s %(message)s' + log_format = ( + '(%(levelname)s) %(asctime)s %(module)s.%(funcName)s:%(lineno)d ' + '%(message)s') + + logging.basicConfig(level=log_level, format=log_format) logger = logging.getLogger() if log_file_name:
diff --git a/tools/telemetry/third_party/webpagereplay/third_party/dns/name.py b/tools/telemetry/third_party/webpagereplay/third_party/dns/name.py index f239c9b..b54aa19 100644 --- a/tools/telemetry/third_party/webpagereplay/third_party/dns/name.py +++ b/tools/telemetry/third_party/webpagereplay/third_party/dns/name.py
@@ -176,7 +176,7 @@ def fullcompare(self, other): """Compare two names, returning a 3-tuple (relation, order, nlabels). - I{relation} describes the relation ship beween the names, + I{relation} describes the relation ship between the names, and is one of: dns.name.NAMERELN_NONE, dns.name.NAMERELN_SUPERDOMAIN, dns.name.NAMERELN_SUBDOMAIN, dns.name.NAMERELN_EQUAL, or dns.name.NAMERELN_COMMONANCESTOR
diff --git a/tools/telemetry/third_party/webpagereplay/trafficshaper_test.py b/tools/telemetry/third_party/webpagereplay/trafficshaper_test.py index 701a71a6..525446dd2 100755 --- a/tools/telemetry/third_party/webpagereplay/trafficshaper_test.py +++ b/tools/telemetry/third_party/webpagereplay/trafficshaper_test.py
@@ -67,7 +67,7 @@ It can respond with the number of bytes specified in the request. The request looks like: - request_data -> RESPONSE_SIZE_KEY num_reponse_bytes '\n' ANY_DATA + request_data -> RESPONSE_SIZE_KEY num_response_bytes '\n' ANY_DATA """ def handle(self):
diff --git a/ui/accelerated_widget_mac/BUILD.gn b/ui/accelerated_widget_mac/BUILD.gn index 5e6680e..69d2213e 100644 --- a/ui/accelerated_widget_mac/BUILD.gn +++ b/ui/accelerated_widget_mac/BUILD.gn
@@ -12,8 +12,6 @@ "display_link_mac.h", "io_surface_context.h", "io_surface_context.mm", - "surface_handle_types.cc", - "surface_handle_types.h", "window_resize_helper_mac.cc", "window_resize_helper_mac.h", ]
diff --git a/ui/accelerated_widget_mac/accelerated_widget_mac.gyp b/ui/accelerated_widget_mac/accelerated_widget_mac.gyp index 6dce667..a062ef7 100644 --- a/ui/accelerated_widget_mac/accelerated_widget_mac.gyp +++ b/ui/accelerated_widget_mac/accelerated_widget_mac.gyp
@@ -19,8 +19,6 @@ 'display_link_mac.h', 'io_surface_context.h', 'io_surface_context.mm', - 'surface_handle_types.cc', - 'surface_handle_types.h', 'window_resize_helper_mac.cc', 'window_resize_helper_mac.h', ],
diff --git a/ui/accelerated_widget_mac/accelerated_widget_mac.h b/ui/accelerated_widget_mac/accelerated_widget_mac.h index 6b514c8..696dc18 100644 --- a/ui/accelerated_widget_mac/accelerated_widget_mac.h +++ b/ui/accelerated_widget_mac/accelerated_widget_mac.h
@@ -12,7 +12,7 @@ #include "base/macros.h" #include "base/time/time.h" #include "ui/accelerated_widget_mac/accelerated_widget_mac_export.h" -#include "ui/accelerated_widget_mac/surface_handle_types.h" +#include "ui/base/cocoa/remote_layer_api.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" #include "ui/gfx/native_widget_types.h" @@ -20,7 +20,6 @@ #if defined(__OBJC__) #import <Cocoa/Cocoa.h> #import "base/mac/scoped_nsobject.h" -#include "ui/base/cocoa/remote_layer_api.h" #endif // __OBJC__ class SkCanvas;
diff --git a/ui/accelerated_widget_mac/surface_handle_types.cc b/ui/accelerated_widget_mac/surface_handle_types.cc deleted file mode 100644 index 35699629..0000000 --- a/ui/accelerated_widget_mac/surface_handle_types.cc +++ /dev/null
@@ -1,53 +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/accelerated_widget_mac/surface_handle_types.h" - -#include "base/logging.h" - -namespace ui { -namespace { - -// The type of the handle is stored in the upper 64 bits. -const uint64_t kTypeMask = 0xFFFFFFFFull << 32; - -const uint64_t kTypeIOSurface = 0x01010101ull << 32; -const uint64_t kTypeCAContext = 0x02020202ull << 32; - -// To make it a bit less likely that we'll just cast off the top bits of the -// handle to get the ID, XOR lower bits with a type-specific mask. -const uint32_t kXORMaskIOSurface = 0x01010101; -const uint32_t kXORMaskCAContext = 0x02020202; - -} // namespace - -SurfaceHandleType GetSurfaceHandleType(uint64_t surface_handle) { - switch(surface_handle & kTypeMask) { - case kTypeIOSurface: - return kSurfaceHandleTypeIOSurface; - case kTypeCAContext: - return kSurfaceHandleTypeCAContext; - } - return kSurfaceHandleTypeInvalid; -} - -IOSurfaceID IOSurfaceIDFromSurfaceHandle(uint64_t surface_handle) { - DCHECK_EQ(kSurfaceHandleTypeIOSurface, GetSurfaceHandleType(surface_handle)); - return static_cast<uint32_t>(surface_handle) ^ kXORMaskIOSurface; -} - -CAContextID CAContextIDFromSurfaceHandle(uint64_t surface_handle) { - DCHECK_EQ(kSurfaceHandleTypeCAContext, GetSurfaceHandleType(surface_handle)); - return static_cast<uint32_t>(surface_handle) ^ kXORMaskCAContext; -} - -uint64_t SurfaceHandleFromIOSurfaceID(IOSurfaceID io_surface_id) { - return kTypeIOSurface | (io_surface_id ^ kXORMaskIOSurface); -} - -uint64_t SurfaceHandleFromCAContextID(CAContextID ca_context_id) { - return kTypeCAContext | (ca_context_id ^ kXORMaskCAContext); -} - -} // namespace ui
diff --git a/ui/accelerated_widget_mac/surface_handle_types.h b/ui/accelerated_widget_mac/surface_handle_types.h deleted file mode 100644 index 23723e8..0000000 --- a/ui/accelerated_widget_mac/surface_handle_types.h +++ /dev/null
@@ -1,43 +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_ACCELERATED_WIDGET_MAC_SURFACE_HANDLE_TYPES_H_ -#define UI_ACCELERATED_WIDGET_MAC_SURFACE_HANDLE_TYPES_H_ - -#include <IOSurface/IOSurface.h> -#include <OpenGL/CGLIOSurface.h> -#include <stdint.h> - -#include "ui/accelerated_widget_mac/accelerated_widget_mac_export.h" -#include "ui/base/cocoa/remote_layer_api.h" - -namespace ui { - -// The surface handle passed between the GPU and browser process may refer to -// an IOSurface or a CAContext. These helper functions must be used to identify -// and translate between the types. -enum SurfaceHandleType { - kSurfaceHandleTypeInvalid, - kSurfaceHandleTypeIOSurface, - kSurfaceHandleTypeCAContext, -}; - -ACCELERATED_WIDGET_MAC_EXPORT -SurfaceHandleType GetSurfaceHandleType(uint64_t surface_handle); - -ACCELERATED_WIDGET_MAC_EXPORT -CAContextID CAContextIDFromSurfaceHandle(uint64_t surface_handle); - -ACCELERATED_WIDGET_MAC_EXPORT -IOSurfaceID IOSurfaceIDFromSurfaceHandle(uint64_t surface_handle); - -ACCELERATED_WIDGET_MAC_EXPORT -uint64_t SurfaceHandleFromIOSurfaceID(IOSurfaceID io_surface_id); - -ACCELERATED_WIDGET_MAC_EXPORT -uint64_t SurfaceHandleFromCAContextID(CAContextID ca_context_id); - -} // namespace ui - -#endif // UI_ACCELERATED_WIDGET_MAC_SURFACE_HANDLE_TYPES_H_
diff --git a/ui/android/java/src/org/chromium/ui/widget/ButtonCompat.java b/ui/android/java/src/org/chromium/ui/widget/ButtonCompat.java index 27ed3e3..c3092df 100644 --- a/ui/android/java/src/org/chromium/ui/widget/ButtonCompat.java +++ b/ui/android/java/src/org/chromium/ui/widget/ButtonCompat.java
@@ -5,6 +5,7 @@ package org.chromium.ui.widget; import android.animation.AnimatorInflater; +import android.animation.StateListAnimator; import android.annotation.TargetApi; import android.content.Context; import android.content.res.ColorStateList; @@ -74,23 +75,7 @@ getBackground().mutate(); setButtonColor(buttonColor); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - // Use the StateListAnimator from the Widget.Material.Button style to animate the - // elevation when the button is pressed. - TypedArray a = getContext().obtainStyledAttributes(null, - new int[]{android.R.attr.stateListAnimator}, 0, - android.R.style.Widget_Material_Button); - int stateListAnimatorId = a.getResourceId(0, 0); - a.recycle(); - // stateListAnimatorId could be 0 on custom or future builds of Android, or when using a - // framework like Xposed. Handle these cases gracefully by simply not using a - // StateListAnimator. - if (stateListAnimatorId != 0) { - setStateListAnimator(AnimatorInflater.loadStateListAnimator(getContext(), - stateListAnimatorId)); - } - } + setRaised(true); } /** @@ -107,6 +92,37 @@ } } + /** + * Sets whether the button is raised (has a shadow), or flat (has no shadow). + */ + public void setRaised(boolean raised) { + // All buttons are flat on pre-L devices. + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) return; + + if (raised) { + // Use the StateListAnimator from the Widget.Material.Button style to animate the + // elevation when the button is pressed. + TypedArray a = getContext().obtainStyledAttributes(null, + new int[]{android.R.attr.stateListAnimator}, 0, + android.R.style.Widget_Material_Button); + int stateListAnimatorId = a.getResourceId(0, 0); + a.recycle(); + + // stateListAnimatorId could be 0 on custom or future builds of Android, or when + // using a framework like Xposed. Handle these cases gracefully by simply not using + // a StateListAnimator. + StateListAnimator stateListAnimator = null; + if (stateListAnimatorId != 0) { + stateListAnimator = AnimatorInflater.loadStateListAnimator(getContext(), + stateListAnimatorId); + } + setStateListAnimator(stateListAnimator); + } else { + setElevation(0f); + setStateListAnimator(null); + } + } + @Override protected void drawableStateChanged() { super.drawableStateChanged();
diff --git a/ui/events/PRESUBMIT.py b/ui/events/PRESUBMIT.py index 182145b..ad7df12 100644 --- a/ui/events/PRESUBMIT.py +++ b/ui/events/PRESUBMIT.py
@@ -15,6 +15,6 @@ 'linux_chromium_chromeos_asan_rel_ng': set(['defaulttests']), }, 'tryserver.chromium.win': { - 'win_chromium_compile_dbg': set(['defaulttests']), + 'win_chromium_compile_dbg_ng': set(['defaulttests']), } }
diff --git a/ui/events/blink/input_handler_proxy.cc b/ui/events/blink/input_handler_proxy.cc index cd1f4ff..8ba8b03 100644 --- a/ui/events/blink/input_handler_proxy.cc +++ b/ui/events/blink/input_handler_proxy.cc
@@ -334,6 +334,16 @@ return DID_NOT_HANDLE; } +bool InputHandlerProxy::ShouldAnimate( + const blink::WebMouseWheelEvent& event) const { +#if defined(OS_MACOSX) + // Mac does not smooth scroll wheel events (crbug.com/574283). + return false; +#else + return smooth_scroll_enabled_ && !event.hasPreciseScrollingDeltas; +#endif +} + InputHandlerProxy::EventDisposition InputHandlerProxy::HandleMouseWheel( const WebMouseWheelEvent& wheel_event) { InputHandlerProxy::EventDisposition result = DID_NOT_HANDLE; @@ -357,7 +367,7 @@ // Wheel events with |canScroll| == false will not trigger scrolling, // only event handlers. Forward to the main thread. result = DID_NOT_HANDLE; - } else if (smooth_scroll_enabled_ && !wheel_event.hasPreciseScrollingDeltas) { + } else if (ShouldAnimate(wheel_event)) { cc::InputHandler::ScrollStatus scroll_status = input_handler_->ScrollAnimated(gfx::Point(wheel_event.x, wheel_event.y), scroll_delta);
diff --git a/ui/events/blink/input_handler_proxy.h b/ui/events/blink/input_handler_proxy.h index 79f3253e..e96b31bf 100644 --- a/ui/events/blink/input_handler_proxy.h +++ b/ui/events/blink/input_handler_proxy.h
@@ -131,6 +131,9 @@ const gfx::Point& causal_event_viewport_point, const cc::InputHandlerScrollResult& scroll_result); + // Whether to use a smooth scroll animation for this event. + bool ShouldAnimate(const blink::WebMouseWheelEvent& event) const; + scoped_ptr<blink::WebGestureCurve> fling_curve_; // Parameters for the active fling animation, stored in case we need to // transfer it out later.
diff --git a/ui/events/blink/input_handler_proxy_unittest.cc b/ui/events/blink/input_handler_proxy_unittest.cc index 6b778e01..d76d891c 100644 --- a/ui/events/blink/input_handler_proxy_unittest.cc +++ b/ui/events/blink/input_handler_proxy_unittest.cc
@@ -390,7 +390,12 @@ VERIFY_AND_RESET_MOCKS(); } +// Mac does not smooth scroll wheel events (crbug.com/574283). +#if !defined(OS_MACOSX) TEST_P(InputHandlerProxyTest, MouseWheelWithPreciseScrollingDeltas) { +#else +TEST_P(InputHandlerProxyTest, DISABLED_MouseWheelWithPreciseScrollingDeltas) { +#endif SetSmoothScrollEnabled(true); expected_disposition_ = InputHandlerProxy::DID_HANDLE; WebMouseWheelEvent wheel; @@ -418,7 +423,12 @@ VERIFY_AND_RESET_MOCKS(); } +// Mac does not smooth scroll wheel events (crbug.com/574283). +#if !defined(OS_MACOSX) TEST_P(InputHandlerProxyTest, MouseWheelScrollIgnored) { +#else +TEST_P(InputHandlerProxyTest, DISABLED_MouseWheelScrollIgnored) { +#endif SetSmoothScrollEnabled(true); expected_disposition_ = InputHandlerProxy::DROP_EVENT; WebMouseWheelEvent wheel;
diff --git a/ui/events/ozone/evdev/input_device_factory_evdev.cc b/ui/events/ozone/evdev/input_device_factory_evdev.cc index 728d7e8..16ccab2a 100644 --- a/ui/events/ozone/evdev/input_device_factory_evdev.cc +++ b/ui/events/ozone/evdev/input_device_factory_evdev.cc
@@ -95,7 +95,7 @@ params.id, params.cursor, params.gesture_property_provider, params.dispatcher)); return make_scoped_ptr(new EventReaderLibevdevCros( - fd, params.path, params.id, devinfo, gesture_interp.Pass())); + fd, params.path, params.id, devinfo, std::move(gesture_interp))); } #endif @@ -303,7 +303,7 @@ new std::vector<base::FilePath>); #if defined(USE_EVDEV_GESTURES) DumpTouchEventLog(converters_, gesture_property_provider_.get(), out_dir, - log_paths.Pass(), reply); + std::move(log_paths), reply); #else reply.Run(std::move(log_paths)); #endif
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 a5f3277e..74fc52c7 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
@@ -7,6 +7,7 @@ #include <errno.h> #include <libevdev/libevdev.h> #include <linux/input.h> +#include <utility> #include "base/message_loop/message_loop.h" #include "base/strings/string_util.h" @@ -42,7 +43,7 @@ has_mouse_(devinfo.HasMouse()), has_touchpad_(devinfo.HasTouchpad()), has_caps_lock_led_(devinfo.HasLedEvent(LED_CAPSL)), - delegate_(delegate.Pass()) { + delegate_(std::move(delegate)) { // This class assumes it does not deal with internal keyboards. CHECK(!has_keyboard_ || type() != INPUT_DEVICE_INTERNAL);
diff --git a/ui/events/platform/x11/BUILD.gn b/ui/events/platform/x11/BUILD.gn index b36e1442..e55afc7e 100644 --- a/ui/events/platform/x11/BUILD.gn +++ b/ui/events/platform/x11/BUILD.gn
@@ -2,6 +2,10 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import("//build/config/ui.gni") + +assert(use_x11) + component("x11") { output_name = "x11_events_platform"
diff --git a/ui/file_manager/video_player/js/media_controls.js b/ui/file_manager/video_player/js/media_controls.js index ed80db6..8138685 100644 --- a/ui/file_manager/video_player/js/media_controls.js +++ b/ui/file_manager/video_player/js/media_controls.js
@@ -246,6 +246,17 @@ MediaControls.PROGRESS_RANGE = 5000; /** + * 5 seconds should be skipped when left/right key is pressed on progress bar. + */ +MediaControls.PROGRESS_MAX_SECONDS_TO_SKIP = 5; + +/** + * 10% of duration should be skipped when the video is too short to skip 5 + * seconds. + */ +MediaControls.PROGRESS_MAX_RATIO_TO_SKIP = 0.1; + +/** * @param {HTMLElement=} opt_parent Parent container. */ MediaControls.prototype.initTimeControls = function(opt_parent) { @@ -272,6 +283,10 @@ function(event) { this.onProgressDrag_(); }.bind(this)); + this.progressSlider_.addEventListener('keydown', + this.onProgressKeyDownOrKeyPress_.bind(this)); + this.progressSlider_.addEventListener('keypress', + this.onProgressKeyDownOrKeyPress_.bind(this)); timeControls.appendChild(this.progressSlider_); }; @@ -325,6 +340,38 @@ }; /** + * Handles ArrowRight/ArrowLeft key on progress slider to skip forward/backword. + * @param {!Event} event + * @private + */ +MediaControls.prototype.onProgressKeyDownOrKeyPress_ = function(event) { + if (event.code !== 'ArrowRight' && event.code !== 'ArrowLeft') + return; + + event.preventDefault(); + + if (this.media_ && this.media_.duration > 0) { + // On left/right key for progress bar, min(5 seconds, 10% of video) should + // be skipped. + var secondsToSkip = Math.min( + MediaControls.PROGRESS_MAX_SECONDS_TO_SKIP, + this.media_.duration * MediaControls.PROGRESS_MAX_RATIO_TO_SKIP); + var stepsToSkip = MediaControls.PROGRESS_RANGE * + (secondsToSkip / this.media_.duration); + + if (event.code === 'ArrowRight') { + this.progressSlider_.value = Math.min( + this.progressSlider_.value + stepsToSkip, + this.progressSlider_.max); + } else { + this.progressSlider_.value = Math.max( + this.progressSlider_.value - stepsToSkip, 0); + } + this.onProgressChange_(this.progressSlider_.ratio); + } +}; + +/** * Handles 'seeking' state, which starts by dragging slider knob and finishes by * releasing it. While seeking, we pause the video when seeking starts and * resume the last play state when seeking ends. @@ -369,13 +416,20 @@ if (isNaN(current)) current = 0; - this.currentTime_.textContent = - MediaControls.formatTime_(current) + ' / ' + - MediaControls.formatTime_(duration); - // Keep the maximum space to prevent time label from moving while playing. - this.currentTimeSpacer_.textContent = - MediaControls.formatTime_(duration) + ' / ' + - MediaControls.formatTime_(duration); + if (isFinite(duration)) { + this.currentTime_.textContent = + MediaControls.formatTime_(current) + ' / ' + + MediaControls.formatTime_(duration); + // Keep the maximum space to prevent time label from moving while playing. + this.currentTimeSpacer_.textContent = + MediaControls.formatTime_(duration) + ' / ' + + MediaControls.formatTime_(duration); + } else { + // Media's duration can be positive infinity value when the media source is + // not known to be bounded yet. In such cases, we should hide duration. + this.currentTime_.textContent = MediaControls.formatTime_(current); + this.currentTimeSpacer_.textContent = MediaControls.formatTime_(current); + } }; /*
diff --git a/ui/file_manager/video_player/js/video_player.js b/ui/file_manager/video_player/js/video_player.js index a97ed24e..e34ff5e 100644 --- a/ui/file_manager/video_player/js/video_player.js +++ b/ui/file_manager/video_player/js/video_player.js
@@ -29,6 +29,7 @@ currentWindow.onRestored.addListener( this.onFullScreenChanged.bind(this, false)); document.addEventListener('keydown', function(e) { + this.inactivityWatcher_.kick(); switch (util.getKeyModifiers(e) + e.keyIdentifier) { // Handle debug shortcut keys. case 'Ctrl-Shift-U+0049': // Ctrl+Shift+I @@ -67,6 +68,9 @@ break; } }.wrap(this)); + document.addEventListener('keypress', function(e) { + this.inactivityWatcher_.kick(); + }.wrap(this)); // TODO(mtomasz): Simplify. crbug.com/254318. var clickInProgress = false;
diff --git a/ui/gfx/BUILD.gn b/ui/gfx/BUILD.gn index c40a4a39..c276eb9 100644 --- a/ui/gfx/BUILD.gn +++ b/ui/gfx/BUILD.gn
@@ -133,8 +133,8 @@ "linux_font_delegate.h", "mac/coordinate_conversion.h", "mac/coordinate_conversion.mm", - "mac/io_surface_manager.cc", - "mac/io_surface_manager.h", + "mac/io_surface.cc", + "mac/io_surface.h", "mac/nswindow_frame_controls.h", "mac/nswindow_frame_controls.mm", "mac/scoped_cocoa_disable_screen_updates.h", @@ -426,6 +426,8 @@ # GYP version: ui/gfx/gfx.gyp:aggregate_vector_icons action("aggregate_vector_icons") { script = "vector_icons/aggregate_vector_icons.py" + + # TODO(estade): move all platform-specific icons into their own directories. sources = [ "vector_icons/account_box.icon", "vector_icons/account_child_invert.icon", @@ -538,9 +540,23 @@ "vector_icons/warning.icon", "vector_icons/warning_badge.icon", "vector_icons/web.icon", + "vector_icons/window_control_back.1x.icon", + "vector_icons/window_control_back.icon", + "vector_icons/window_control_close.1x.icon", + "vector_icons/window_control_close.icon", + "vector_icons/window_control_left_snapped.1x.icon", + "vector_icons/window_control_maximize.1x.icon", + "vector_icons/window_control_maximize.icon", + "vector_icons/window_control_minimize.1x.icon", + "vector_icons/window_control_minimize.icon", + "vector_icons/window_control_restore.1x.icon", + "vector_icons/window_control_restore.icon", + "vector_icons/window_control_right_snapped.1x.icon", + "vector_icons/window_control_right_snapped.icon", "vector_icons/zoom_minus.icon", "vector_icons/zoom_plus.icon", ] + outputs = [ vector_icons_cc_file, vector_icons_h_file,
diff --git a/ui/gfx/canvas.cc b/ui/gfx/canvas.cc index f612a8e3..459a0e6 100644 --- a/ui/gfx/canvas.cc +++ b/ui/gfx/canvas.cc
@@ -394,8 +394,9 @@ const ImageSkiaRep& image_rep = image.GetRepresentation(image_scale_); if (image_rep.is_null()) return; + bool remove_image_scale = true; DrawImageIntHelper(image_rep, src_x, src_y, src_w, src_h, dest_x, dest_y, - dest_w, dest_h, filter, paint, false); + dest_w, dest_h, filter, paint, remove_image_scale); } void Canvas::DrawImageIntInPixel(const ImageSkiaRep& image_rep, @@ -409,8 +410,11 @@ int src_y = 0; int src_w = image_rep.pixel_width(); int src_h = image_rep.pixel_height(); + // Don't remove image scale here, this function is used to draw the + // (already scaled) |image_rep| at a 1:1 scale with the canvas. + bool remove_image_scale = false; DrawImageIntHelper(image_rep, src_x, src_y, src_w, src_h, dest_x, dest_y, - dest_w, dest_h, filter, paint, true); + dest_w, dest_h, filter, paint, remove_image_scale); } void Canvas::DrawImageInPath(const ImageSkia& image, @@ -534,7 +538,7 @@ int dest_h, bool filter, const SkPaint& paint, - bool pixel) { + bool remove_image_scale) { DLOG_ASSERT(src_x + src_w < std::numeric_limits<int16_t>::max() && src_y + src_h < std::numeric_limits<int16_t>::max()); if (src_w <= 0 || src_h <= 0) { @@ -553,17 +557,6 @@ SkIntToScalar(dest_x + dest_w), SkIntToScalar(dest_y + dest_h) }; - if (src_w == dest_w && src_h == dest_h && - user_scale_x == 1.0f && user_scale_y == 1.0f && - image_rep.scale() == 1.0f && !pixel) { - // Workaround for apparent bug in Skia that causes image to occasionally - // shift. - SkIRect src_rect = { src_x, src_y, src_x + src_w, src_y + src_h }; - const SkBitmap& bitmap = image_rep.sk_bitmap(); - canvas_->drawBitmapRect(bitmap, src_rect, dest_rect, &paint); - return; - } - // Make a bitmap shader that contains the bitmap we want to draw. This is // basically what SkCanvas.drawBitmap does internally, but it gives us // more control over quality and will use the mipmap in the source image if @@ -575,10 +568,8 @@ shader_scale.postTranslate(SkIntToScalar(dest_x), SkIntToScalar(dest_y)); skia::RefPtr<SkShader> shader = CreateImageRepShaderForScale( - image_rep, - SkShader::kRepeat_TileMode, - shader_scale, - pixel ? 1.0f : image_rep.scale()); + image_rep, SkShader::kRepeat_TileMode, shader_scale, + remove_image_scale ? image_rep.scale() : 1.f); // Set up our paint to use the shader & release our reference (now just owned // by the paint).
diff --git a/ui/gfx/canvas.h b/ui/gfx/canvas.h index d1d031c..311cf38 100644 --- a/ui/gfx/canvas.h +++ b/ui/gfx/canvas.h
@@ -418,9 +418,9 @@ bool IntersectsClipRectInt(int x, int y, int w, int h); bool IntersectsClipRect(const Rect& rect); - // Helper for the DrawImageInt functions declared above. The |pixel| - // parameter if true indicates that the bounds and the image are to - // be assumed to be in pixels, i.e. no scaling needs to be performed. + // Helper for the DrawImageInt functions declared above. The + // |remove_image_scale| parameter indicates if the scale of the |image_rep| + // should be removed when drawing the image, to avoid double-scaling it. void DrawImageIntHelper(const ImageSkiaRep& image_rep, int src_x, int src_y, @@ -432,7 +432,7 @@ int dest_h, bool filter, const SkPaint& paint, - bool pixel); + bool remove_image_scale); // The device scale factor at which drawing on this canvas occurs. // An additional scale can be applied via Canvas::Scale(). However,
diff --git a/ui/gfx/gfx.gyp b/ui/gfx/gfx.gyp index 307ad04..d9e8078 100644 --- a/ui/gfx/gfx.gyp +++ b/ui/gfx/gfx.gyp
@@ -123,10 +123,10 @@ 'animation/throb_animation.h', 'animation/tween.cc', 'animation/tween.h', - 'break_list.h', 'blit.cc', 'blit.h', 'break_list.h', + 'break_list.h', 'buffer_format_util.cc', 'buffer_format_util.h', 'canvas.cc', @@ -217,8 +217,8 @@ 'linux_font_delegate.h', 'mac/coordinate_conversion.h', 'mac/coordinate_conversion.mm', - 'mac/io_surface_manager.cc', - 'mac/io_surface_manager.h', + 'mac/io_surface.cc', + 'mac/io_surface.h', 'mac/nswindow_frame_controls.h', 'mac/nswindow_frame_controls.mm', 'mac/scoped_cocoa_disable_screen_updates.h', @@ -525,8 +525,8 @@ 'test/fontconfig_util_linux.h', 'test/gfx_util.cc', 'test/gfx_util.h', - 'test/test_screen.h', 'test/test_screen.cc', + 'test/test_screen.h', 'test/ui_cocoa_test_helper.h', 'test/ui_cocoa_test_helper.mm', ],
diff --git a/ui/gfx/gpu_memory_buffer.cc b/ui/gfx/gpu_memory_buffer.cc index f70badb..4bad70e 100644 --- a/ui/gfx/gpu_memory_buffer.cc +++ b/ui/gfx/gpu_memory_buffer.cc
@@ -20,4 +20,6 @@ : type(EMPTY_BUFFER), id(0), handle(base::SharedMemory::NULLHandle()) { } +GpuMemoryBufferHandle::~GpuMemoryBufferHandle() {} + } // namespace gfx
diff --git a/ui/gfx/gpu_memory_buffer.h b/ui/gfx/gpu_memory_buffer.h index 6b769c8..ee1de2bd 100644 --- a/ui/gfx/gpu_memory_buffer.h +++ b/ui/gfx/gpu_memory_buffer.h
@@ -18,6 +18,8 @@ #if defined(USE_OZONE) #include "ui/gfx/native_pixmap_handle_ozone.h" +#elif defined(OS_MACOSX) +#include "ui/gfx/mac/io_surface.h" #endif extern "C" typedef struct _ClientBuffer* ClientBuffer; @@ -37,6 +39,7 @@ struct GFX_EXPORT GpuMemoryBufferHandle { GpuMemoryBufferHandle(); + ~GpuMemoryBufferHandle(); bool is_null() const { return type == EMPTY_BUFFER; } GpuMemoryBufferType type; GpuMemoryBufferId id; @@ -45,6 +48,8 @@ int32_t stride; #if defined(USE_OZONE) NativePixmapHandle native_pixmap_handle; +#elif defined(OS_MACOSX) + ScopedRefCountedIOSurfaceMachPort mach_port; #endif };
diff --git a/ui/gfx/ipc/gfx_param_traits.cc b/ui/gfx/ipc/gfx_param_traits.cc index 2eeefbf..a49e1da9 100644 --- a/ui/gfx/ipc/gfx_param_traits.cc +++ b/ui/gfx/ipc/gfx_param_traits.cc
@@ -16,6 +16,10 @@ #include "ui/gfx/geometry/scroll_offset.h" #include "ui/gfx/range/range.h" +#if defined(OS_MACOSX) +#include "ipc/mach_port_mac.h" +#endif + namespace { struct SkBitmap_Data { @@ -340,6 +344,33 @@ l->append(")"); } +#if defined(OS_MACOSX) && !defined(OS_IOS) +void ParamTraits<gfx::ScopedRefCountedIOSurfaceMachPort>::Write( + Message* m, + const param_type p) { + MachPortMac mach_port_mac(p.get()); + ParamTraits<MachPortMac>::Write(m, mach_port_mac); +} + +bool ParamTraits<gfx::ScopedRefCountedIOSurfaceMachPort>::Read( + const Message* m, + base::PickleIterator* iter, + param_type* r) { + MachPortMac mach_port_mac; + if (!ParamTraits<MachPortMac>::Read(m, iter, &mach_port_mac)) + return false; + r->reset(mach_port_mac.get_mach_port()); + return true; +} + +void ParamTraits<gfx::ScopedRefCountedIOSurfaceMachPort>::Log( + const param_type& p, + std::string* l) { + l->append("IOSurface Mach send right: "); + LogParam(p.get(), l); +} +#endif // defined(OS_MACOSX) && !defined(OS_IOS) + } // namespace IPC // Generate param traits write methods.
diff --git a/ui/gfx/ipc/gfx_param_traits.h b/ui/gfx/ipc/gfx_param_traits.h index 337505a..b7280ef0 100644 --- a/ui/gfx/ipc/gfx_param_traits.h +++ b/ui/gfx/ipc/gfx_param_traits.h
@@ -13,6 +13,10 @@ #include "ui/gfx/ipc/gfx_ipc_export.h" #include "ui/gfx/ipc/gfx_param_traits_macros.h" +#if defined(OS_MACOSX) && !defined(OS_IOS) +#include "ui/gfx/mac/io_surface.h" +#endif + class SkBitmap; namespace gfx { @@ -131,6 +135,20 @@ static void Log(const param_type& p, std::string* l); }; +#if defined(OS_MACOSX) && !defined(OS_IOS) +template <> +struct GFX_IPC_EXPORT ParamTraits<gfx::ScopedRefCountedIOSurfaceMachPort> { + typedef gfx::ScopedRefCountedIOSurfaceMachPort param_type; + static void Write(Message* m, const param_type p); + // Note: Read() passes ownership of the Mach send right from the IPC message + // to the ScopedRefCountedIOSurfaceMachPort. Therefore, Read() may only be + // called once for a given message, otherwise the singular right will be + // managed and released by two objects. + static bool Read(const Message* m, base::PickleIterator* iter, param_type* r); + static void Log(const param_type& p, std::string* l); +}; +#endif // defined(OS_MACOSX) && !defined(OS_IOS) + } // namespace IPC #endif // UI_GFX_IPC_GFX_PARAM_TRAITS_H_
diff --git a/ui/gfx/mac/io_surface_manager.cc b/ui/gfx/mac/io_surface.cc similarity index 84% rename from ui/gfx/mac/io_surface_manager.cc rename to ui/gfx/mac/io_surface.cc index 9e3e9cf..8c748bc 100644 --- a/ui/gfx/mac/io_surface_manager.cc +++ b/ui/gfx/mac/io_surface.cc
@@ -2,21 +2,19 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ui/gfx/mac/io_surface_manager.h" +#include "ui/gfx/mac/io_surface.h" -#include <IOSurface/IOSurface.h> #include <stddef.h> #include <stdint.h> #include "base/logging.h" -#include "base/mac/scoped_cftyperef.h" +#include "base/mac/mach_logging.h" #include "base/macros.h" #include "ui/gfx/buffer_format_util.h" namespace gfx { -namespace { -IOSurfaceManager* g_instance = NULL; +namespace { void AddIntegerValue(CFMutableDictionaryRef dictionary, const CFStringRef key, @@ -89,21 +87,28 @@ } // namespace +namespace internal { + // static -IOSurfaceManager* IOSurfaceManager::GetInstance() { - DCHECK(g_instance); - return g_instance; +mach_port_t IOSurfaceMachPortTraits::Retain(mach_port_t port) { + kern_return_t kr = + mach_port_mod_refs(mach_task_self(), port, MACH_PORT_RIGHT_SEND, 1); + MACH_LOG_IF(ERROR, kr != KERN_SUCCESS, kr) + << "IOSurfaceMachPortTraits::Retain mach_port_mod_refs"; + return port; } // static -void IOSurfaceManager::SetInstance(IOSurfaceManager* instance) { - DCHECK(!g_instance || !instance); - g_instance = instance; +void IOSurfaceMachPortTraits::Release(mach_port_t port) { + kern_return_t kr = + mach_port_mod_refs(mach_task_self(), port, MACH_PORT_RIGHT_SEND, -1); + MACH_LOG_IF(ERROR, kr != KERN_SUCCESS, kr) + << "IOSurfaceMachPortTraits::Release mach_port_mod_refs"; } -// static -IOSurfaceRef IOSurfaceManager::CreateIOSurface(const gfx::Size& size, - gfx::BufferFormat format) { +} // namespace internal + +IOSurfaceRef CreateIOSurface(const gfx::Size& size, gfx::BufferFormat format) { size_t num_planes = gfx::NumberOfPlanesForBufferFormat(format); base::ScopedCFTypeRef<CFMutableArrayRef> planes(CFArrayCreateMutable( kCFAllocatorDefault, num_planes, &kCFTypeArrayCallBacks)); @@ -146,4 +151,4 @@ return IOSurfaceCreate(properties); } -} // namespace content +} // namespace gfx
diff --git a/ui/gfx/mac/io_surface.h b/ui/gfx/mac/io_surface.h new file mode 100644 index 0000000..4c24fe46 --- /dev/null +++ b/ui/gfx/mac/io_surface.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 UI_GFX_MAC_IO_SURFACE_H_ +#define UI_GFX_MAC_IO_SURFACE_H_ + +#include <IOSurface/IOSurface.h> +#include <mach/mach.h> + +#include "base/mac/scoped_cftyperef.h" +#include "ui/gfx/buffer_types.h" +#include "ui/gfx/generic_shared_memory_id.h" +#include "ui/gfx/geometry/size.h" +#include "ui/gfx/gfx_export.h" + +namespace gfx { + +namespace internal { + +struct IOSurfaceMachPortTraits { + GFX_EXPORT static mach_port_t InvalidValue() { return MACH_PORT_NULL; } + GFX_EXPORT static mach_port_t Retain(mach_port_t); + GFX_EXPORT static void Release(mach_port_t); +}; + +} // namespace internal + +using IOSurfaceId = GenericSharedMemoryId; + +// Helper function to create an IOSurface with a specified size and format. +GFX_EXPORT IOSurfaceRef CreateIOSurface(const Size& size, BufferFormat format); + +// A scoper for handling Mach port names that are send rights for IOSurfaces. +// This scoper is both copyable and assignable, which will increase the kernel +// reference count of the right. On destruction, the reference count is +// decremented. +using ScopedRefCountedIOSurfaceMachPort = + base::ScopedTypeRef<mach_port_t, internal::IOSurfaceMachPortTraits>; + +} // namespace gfx + +#endif // UI_GFX_MAC_IO_SURFACE_H_
diff --git a/ui/gfx/mac/io_surface_manager.h b/ui/gfx/mac/io_surface_manager.h deleted file mode 100644 index 130214c..0000000 --- a/ui/gfx/mac/io_surface_manager.h +++ /dev/null
@@ -1,50 +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 CONTENT_COMMON_MAC_IO_SURFACE_MANAGER_H_ -#define CONTENT_COMMON_MAC_IO_SURFACE_MANAGER_H_ - -#include <IOSurface/IOSurface.h> - -#include "ui/gfx/buffer_types.h" -#include "ui/gfx/generic_shared_memory_id.h" -#include "ui/gfx/geometry/size.h" -#include "ui/gfx/gfx_export.h" - -namespace gfx { - -using IOSurfaceId = GenericSharedMemoryId; - -// This interface provides a mechanism for different processes to securely -// share IOSurfaces. A process can register an IOSurface for use in another -// process and the client ID provided with registration determines the process -// that can acquire a reference to the IOSurface. -class GFX_EXPORT IOSurfaceManager { - public: - static IOSurfaceManager* GetInstance(); - static void SetInstance(IOSurfaceManager* instance); - - // Helper function to create an IOSurface with a specified size and format. - static IOSurfaceRef CreateIOSurface(const Size& size, BufferFormat format); - - // Register an IO surface for use in another process. - virtual bool RegisterIOSurface(IOSurfaceId io_surface_id, - int client_id, - IOSurfaceRef io_surface) = 0; - - // Unregister an IO surface previously registered for use in another - // process. - virtual void UnregisterIOSurface(IOSurfaceId io_surface_id, - int client_id) = 0; - - // Acquire IO surface reference for a registered IO surface. - virtual IOSurfaceRef AcquireIOSurface(IOSurfaceId io_surface_id) = 0; - - protected: - virtual ~IOSurfaceManager() {} -}; - -} // namespace content - -#endif // CONTENT_COMMON_MAC_IO_SURFACE_MANAGER_H_
diff --git a/ui/gfx/text_elider.cc b/ui/gfx/text_elider.cc index 82baf44..4b7a7f9f 100644 --- a/ui/gfx/text_elider.cc +++ b/ui/gfx/text_elider.cc
@@ -41,7 +41,7 @@ namespace { -#if defined(OS_ANDROID) && !defined(USE_AURA) || defined(OS_IOS) +#if defined(OS_ANDROID) || defined(OS_IOS) // The returned string will have at least one character besides the ellipsis // on either side of '@'; if that's impossible, a single ellipsis is returned. // If possible, only the username is elided. Otherwise, the domain is elided @@ -196,7 +196,22 @@ const FontList& font_list, float available_pixel_width, ElideBehavior behavior) { -#if defined(OS_ANDROID) && !defined(USE_AURA) || defined(OS_IOS) +#if !defined(OS_ANDROID) && !defined(OS_IOS) + DCHECK_NE(behavior, FADE_TAIL); + scoped_ptr<RenderText> render_text(RenderText::CreateInstance()); + render_text->SetCursorEnabled(false); + // TODO(bshe): 5000 is out dated. We should remove it. See crbug.com/551660. + // Do not bother accurately sizing strings over 5000 characters here, for + // performance purposes. This matches the behavior of Canvas::SizeStringFloat. + render_text->set_truncate_length(5000); + render_text->SetFontList(font_list); + available_pixel_width = std::ceil(available_pixel_width); + render_text->SetDisplayRect( + gfx::ToEnclosingRect(gfx::RectF(gfx::SizeF(available_pixel_width, 1)))); + render_text->SetElideBehavior(behavior); + render_text->SetText(text); + return render_text->GetDisplayText(); +#else DCHECK_NE(behavior, FADE_TAIL); if (text.empty() || behavior == FADE_TAIL || behavior == NO_ELIDE || GetStringWidthF(text, font_list) <= available_pixel_width) { @@ -240,21 +255,6 @@ } return cut; -#else - DCHECK_NE(behavior, FADE_TAIL); - scoped_ptr<RenderText> render_text(RenderText::CreateInstance()); - render_text->SetCursorEnabled(false); - // TODO(bshe): 5000 is out dated. We should remove it. See crbug.com/551660. - // Do not bother accurately sizing strings over 5000 characters here, for - // performance purposes. This matches the behavior of Canvas::SizeStringFloat. - render_text->set_truncate_length(5000); - render_text->SetFontList(font_list); - available_pixel_width = std::ceil(available_pixel_width); - render_text->SetDisplayRect( - gfx::ToEnclosingRect(gfx::RectF(gfx::SizeF(available_pixel_width, 1)))); - render_text->SetElideBehavior(behavior); - render_text->SetText(text); - return render_text->GetDisplayText(); #endif }
diff --git a/ui/gfx/vector_icons/window_control_back.1x.icon b/ui/gfx/vector_icons/window_control_back.1x.icon new file mode 100644 index 0000000..6080f41 --- /dev/null +++ b/ui/gfx/vector_icons/window_control_back.1x.icon
@@ -0,0 +1,18 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +CANVAS_DIMENSIONS, 12, +MOVE_TO, 4.92f, 5, +H_LINE_TO, 11, +R_V_LINE_TO, 2, +H_LINE_TO, 4.92f, +LINE_TO, 8, 9.75f, +LINE_TO, 6.6f, 11, +LINE_TO, 1, 6, +R_LINE_TO, 0.7f, -0.62f, +LINE_TO, 6.6f, 1, +LINE_TO, 8, 2.25f, +LINE_TO, 4.92f, 5, +CLOSE, +END
diff --git a/ui/gfx/vector_icons/window_control_back.icon b/ui/gfx/vector_icons/window_control_back.icon new file mode 100644 index 0000000..4363674 --- /dev/null +++ b/ui/gfx/vector_icons/window_control_back.icon
@@ -0,0 +1,19 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +CANVAS_DIMENSIONS, 24, +MOVE_TO, 6.83f, 10, +H_LINE_TO, 23, +R_V_LINE_TO, 3, +H_LINE_TO, 6.83f, +LINE_TO, 15, 20.96f, +LINE_TO, 12.86f, 23, +LINE_TO, 4.93f, 15.25f, +LINE_TO, 1, 11.5f, +R_LINE_TO, 5, -4.77f, +LINE_TO, 12.86f, 0, +LINE_TO, 15, 2.05f, +LINE_TO, 6.83f, 10, +CLOSE, +END
diff --git a/ui/gfx/vector_icons/window_control_close.1x.icon b/ui/gfx/vector_icons/window_control_close.1x.icon new file mode 100644 index 0000000..94d36a0f --- /dev/null +++ b/ui/gfx/vector_icons/window_control_close.1x.icon
@@ -0,0 +1,20 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +CANVAS_DIMENSIONS, 12, +MOVE_TO, 6, 4.59f, +LINE_TO, 2.46f, 1.05f, +LINE_TO, 1.05f, 2.46f, +LINE_TO, 4.59f, 6, +LINE_TO, 1.05f, 9.54f, +R_LINE_TO, 1.41f, 1.41f, +LINE_TO, 6, 7.41f, +R_LINE_TO, 3.54f, 3.54f, +R_LINE_TO, 1.41f, -1.41f, +LINE_TO, 7.41f, 6, +R_LINE_TO, 3.54f, -3.54f, +LINE_TO, 9.54f, 1.05f, +LINE_TO, 6, 4.59f, +CLOSE, +END
diff --git a/ui/gfx/vector_icons/window_control_close.icon b/ui/gfx/vector_icons/window_control_close.icon new file mode 100644 index 0000000..1e6fb80 --- /dev/null +++ b/ui/gfx/vector_icons/window_control_close.icon
@@ -0,0 +1,20 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +CANVAS_DIMENSIONS, 24, +MOVE_TO, 23, 3.22f, +LINE_TO, 20.78f, 1, +LINE_TO, 12, 9.78f, +LINE_TO, 3.22f, 1, +LINE_TO, 1, 3.22f, +LINE_TO, 9.78f, 12, +LINE_TO, 1, 20.78f, +LINE_TO, 3.22f, 23, +LINE_TO, 12, 14.22f, +LINE_TO, 20.78f, 23, +LINE_TO, 23, 20.78f, +LINE_TO, 14.22f, 12, +LINE_TO, 23, 3.22f, +CLOSE, +END
diff --git a/ui/gfx/vector_icons/window_control_left_snapped.1x.icon b/ui/gfx/vector_icons/window_control_left_snapped.1x.icon new file mode 100644 index 0000000..0899d308 --- /dev/null +++ b/ui/gfx/vector_icons/window_control_left_snapped.1x.icon
@@ -0,0 +1,15 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +CANVAS_DIMENSIONS, 12, +MOVE_TO, 1, 6, +R_LINE_TO, 5.6f, 5, +LINE_TO, 8, 9.75f, +LINE_TO, 3.8f, 6, +LINE_TO, 8, 2.25f, +LINE_TO, 6.6f, 1, +LINE_TO, 1.7f, 5.38f, +LINE_TO, 1, 6, +CLOSE, +END
diff --git a/ui/gfx/vector_icons/window_control_left_snapped.icon b/ui/gfx/vector_icons/window_control_left_snapped.icon new file mode 100644 index 0000000..f764dc7 --- /dev/null +++ b/ui/gfx/vector_icons/window_control_left_snapped.icon
@@ -0,0 +1,16 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +CANVAS_DIMENSIONS, 24, +MOVE_TO, 15, 2.05f, +LINE_TO, 5.29f, 11.5f, +LINE_TO, 15, 20.96f, +LINE_TO, 12.86f, 23, +LINE_TO, 4.93f, 15.25f, +LINE_TO, 1, 11.5f, +R_LINE_TO, 5, -4.77f, +LINE_TO, 12.86f, 0, +LINE_TO, 15, 2.05f, +CLOSE, +END
diff --git a/ui/gfx/vector_icons/window_control_maximize.1x.icon b/ui/gfx/vector_icons/window_control_maximize.1x.icon new file mode 100644 index 0000000..f1c56bb --- /dev/null +++ b/ui/gfx/vector_icons/window_control_maximize.1x.icon
@@ -0,0 +1,18 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +CANVAS_DIMENSIONS, 12, +MOVE_TO, 11, 1, +R_V_LINE_TO, 10, +H_LINE_TO, 1, +V_LINE_TO, 1, +R_H_LINE_TO, 10, +CLOSE, +MOVE_TO, 9, 9, +H_LINE_TO, 3, +V_LINE_TO, 3, +R_H_LINE_TO, 6, +R_V_LINE_TO, 6, +CLOSE, +END
diff --git a/ui/gfx/vector_icons/window_control_maximize.icon b/ui/gfx/vector_icons/window_control_maximize.icon new file mode 100644 index 0000000..c186d5f --- /dev/null +++ b/ui/gfx/vector_icons/window_control_maximize.icon
@@ -0,0 +1,18 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +CANVAS_DIMENSIONS, 24, +MOVE_TO, 23, 1, +R_V_LINE_TO, 22, +H_LINE_TO, 1, +V_LINE_TO, 1, +R_H_LINE_TO, 22, +CLOSE, +R_MOVE_TO, -3, 19, +H_LINE_TO, 4, +V_LINE_TO, 4, +R_H_LINE_TO, 16, +R_V_LINE_TO, 16, +CLOSE, +END
diff --git a/ui/gfx/vector_icons/window_control_minimize.1x.icon b/ui/gfx/vector_icons/window_control_minimize.1x.icon new file mode 100644 index 0000000..da77c268 --- /dev/null +++ b/ui/gfx/vector_icons/window_control_minimize.1x.icon
@@ -0,0 +1,11 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +CANVAS_DIMENSIONS, 12, +MOVE_TO, 1, 9, +R_H_LINE_TO, 10, +R_V_LINE_TO, 2, +H_LINE_TO, 1, +CLOSE, +END
diff --git a/ui/gfx/vector_icons/window_control_minimize.icon b/ui/gfx/vector_icons/window_control_minimize.icon new file mode 100644 index 0000000..98629c7 --- /dev/null +++ b/ui/gfx/vector_icons/window_control_minimize.icon
@@ -0,0 +1,11 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +CANVAS_DIMENSIONS, 24, +MOVE_TO, 1, 20, +R_H_LINE_TO, 22, +R_V_LINE_TO, 3, +H_LINE_TO, 1, +CLOSE, +END
diff --git a/ui/gfx/vector_icons/window_control_restore.1x.icon b/ui/gfx/vector_icons/window_control_restore.1x.icon new file mode 100644 index 0000000..99449dd --- /dev/null +++ b/ui/gfx/vector_icons/window_control_restore.1x.icon
@@ -0,0 +1,26 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +CANVAS_DIMENSIONS, 12, +MOVE_TO, 11, 8, +H_LINE_TO, 4, +V_LINE_TO, 1, +R_H_LINE_TO, 7, +R_V_LINE_TO, 7, +CLOSE, +MOVE_TO, 6, 6, +V_LINE_TO, 3, +R_H_LINE_TO, 3, +R_V_LINE_TO, 3, +H_LINE_TO, 6, +CLOSE, +MOVE_TO, 3, 3, +H_LINE_TO, 1, +R_V_LINE_TO, 8, +R_H_LINE_TO, 8, +V_LINE_TO, 9, +H_LINE_TO, 3, +V_LINE_TO, 3, +CLOSE, +END
diff --git a/ui/gfx/vector_icons/window_control_restore.icon b/ui/gfx/vector_icons/window_control_restore.icon new file mode 100644 index 0000000..f511b4c --- /dev/null +++ b/ui/gfx/vector_icons/window_control_restore.icon
@@ -0,0 +1,26 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +CANVAS_DIMENSIONS, 24, +MOVE_TO, 23, 16, +H_LINE_TO, 8, +V_LINE_TO, 1, +R_H_LINE_TO, 15, +R_V_LINE_TO, 15, +CLOSE, +R_MOVE_TO, -12, -3, +V_LINE_TO, 4, +R_H_LINE_TO, 9, +R_V_LINE_TO, 9, +R_H_LINE_TO, -9, +CLOSE, +MOVE_TO, 4, 8, +H_LINE_TO, 1, +R_V_LINE_TO, 15, +R_H_LINE_TO, 15, +R_V_LINE_TO, -3, +H_LINE_TO, 4, +V_LINE_TO, 8, +CLOSE, +END
diff --git a/ui/gfx/vector_icons/window_control_right_snapped.1x.icon b/ui/gfx/vector_icons/window_control_right_snapped.1x.icon new file mode 100644 index 0000000..448e72c --- /dev/null +++ b/ui/gfx/vector_icons/window_control_right_snapped.1x.icon
@@ -0,0 +1,15 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +CANVAS_DIMENSIONS, 12, +MOVE_TO, 11, 6, +R_LINE_TO, -5.6f, 5, +LINE_TO, 4, 9.75f, +LINE_TO, 8.2f, 6, +LINE_TO, 4, 2.25f, +LINE_TO, 5.4f, 1, +R_LINE_TO, 4.9f, 4.38f, +LINE_TO, 11, 6, +CLOSE, +END
diff --git a/ui/gfx/vector_icons/window_control_right_snapped.icon b/ui/gfx/vector_icons/window_control_right_snapped.icon new file mode 100644 index 0000000..f446d371 --- /dev/null +++ b/ui/gfx/vector_icons/window_control_right_snapped.icon
@@ -0,0 +1,16 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +CANVAS_DIMENSIONS, 24, +MOVE_TO, 9, 2.05f, +R_LINE_TO, 9.71f, 9.46f, +LINE_TO, 9, 20.96f, +LINE_TO, 11.14f, 23, +R_LINE_TO, 7.93f, -7.75f, +LINE_TO, 23, 11.5f, +R_LINE_TO, -5, -4.77f, +LINE_TO, 11.14f, 0, +LINE_TO, 9, 2.05f, +CLOSE, +END
diff --git a/ui/gfx/x/BUILD.gn b/ui/gfx/x/BUILD.gn index 26938627..6ffba24 100644 --- a/ui/gfx/x/BUILD.gn +++ b/ui/gfx/x/BUILD.gn
@@ -2,6 +2,10 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import("//build/config/ui.gni") + +assert(use_x11) + # GYP version: //ui/gfx/x/gfx_x11.gyp:gfx_x11 component("x") { output_name = "gfx_x11"
diff --git a/ui/gl/gl_image_io_surface_unittest.cc b/ui/gl/gl_image_io_surface_unittest.cc index 8936ada..487366f 100644 --- a/ui/gl/gl_image_io_surface_unittest.cc +++ b/ui/gl/gl_image_io_surface_unittest.cc
@@ -7,7 +7,7 @@ #include "testing/gtest/include/gtest/gtest.h" #include "ui/gfx/buffer_format_util.h" -#include "ui/gfx/mac/io_surface_manager.h" +#include "ui/gfx/mac/io_surface.h" #include "ui/gl/gl_image_io_surface.h" #include "ui/gl/test/gl_image_test_template.h" @@ -21,8 +21,7 @@ const uint8_t color[4]) const { scoped_refptr<GLImageIOSurface> image(new GLImageIOSurface( size, GLImageIOSurface::GetInternalFormatForTesting(format))); - IOSurfaceRef surface_ref = - gfx::IOSurfaceManager::CreateIOSurface(size, format); + IOSurfaceRef surface_ref = gfx::CreateIOSurface(size, format); IOReturn status = IOSurfaceLock(surface_ref, 0, nullptr); EXPECT_NE(status, kIOReturnCannotLock); for (size_t plane = 0; plane < NumberOfPlanesForBufferFormat(format);
diff --git a/ui/gl/gl_surface.cc b/ui/gl/gl_surface.cc index c5346908..22495365 100644 --- a/ui/gl/gl_surface.cc +++ b/ui/gl/gl_surface.cc
@@ -219,6 +219,10 @@ return false; } +bool GLSurface::FlipsVertically() const { + return false; +} + GLSurface* GLSurface::GetCurrent() { return current_surface_.Pointer()->Get(); } @@ -379,6 +383,10 @@ return surface_->IsSurfaceless(); } +bool GLSurfaceAdapter::FlipsVertically() const { + return surface_->FlipsVertically(); +} + GLSurfaceAdapter::~GLSurfaceAdapter() {} } // namespace gfx
diff --git a/ui/gl/gl_surface.h b/ui/gl/gl_surface.h index e4f3265..066435a 100644 --- a/ui/gl/gl_surface.h +++ b/ui/gl/gl_surface.h
@@ -181,6 +181,8 @@ virtual bool IsSurfaceless() const; + virtual bool FlipsVertically() const; + // Create a GL surface that renders directly to a view. static scoped_refptr<GLSurface> CreateViewGLSurface( gfx::AcceleratedWidget window); @@ -267,6 +269,7 @@ const Rect& bounds_rect, const RectF& crop_rect) override; bool IsSurfaceless() const override; + bool FlipsVertically() const override; GLSurface* surface() const { return surface_.get(); }
diff --git a/ui/gl/gl_surface_egl.cc b/ui/gl/gl_surface_egl.cc index f378cfd..5dd8637f 100644 --- a/ui/gl/gl_surface_egl.cc +++ b/ui/gl/gl_surface_egl.cc
@@ -84,6 +84,14 @@ #define EGL_X11_VISUAL_ID_ANGLE 0x33A3 #endif /* EGL_ANGLE_x11_visual */ +#ifndef EGL_ANGLE_surface_orientation +#define EGL_ANGLE_surface_orientation +#define EGL_OPTIMAL_SURFACE_ORIENTATION_ANGLE 0x33A7 +#define EGL_SURFACE_ORIENTATION_ANGLE 0x33A8 +#define EGL_SURFACE_ORIENTATION_INVERT_X_ANGLE 0x0001 +#define EGL_SURFACE_ORIENTATION_INVERT_Y_ANGLE 0x0002 +#endif /* EGL_ANGLE_surface_orientation */ + using ui::GetLastEGLErrorString; namespace gfx { @@ -107,6 +115,7 @@ bool g_egl_sync_control_supported = false; bool g_egl_window_fixed_size_supported = false; bool g_egl_surfaceless_context_supported = false; +bool g_egl_surface_orientation_supported = false; class EGLSyncControlVSyncProvider : public gfx::SyncControlVSyncProvider { @@ -364,6 +373,8 @@ HasEGLExtension("EGL_CHROMIUM_sync_control"); g_egl_window_fixed_size_supported = HasEGLExtension("EGL_ANGLE_window_fixed_size"); + g_egl_surface_orientation_supported = + HasEGLExtension("EGL_ANGLE_surface_orientation"); // TODO(oetuaho@nvidia.com): Surfaceless is disabled on Android as a temporary // workaround, since code written for Android WebView takes different paths @@ -492,6 +503,7 @@ surface_(NULL), supports_post_sub_buffer_(false), alpha_(true), + flips_vertically_(false), swap_interval_(1) { #if defined(OS_ANDROID) if (window) @@ -543,6 +555,18 @@ egl_window_attributes.push_back(EGL_TRUE); } + if (g_egl_surface_orientation_supported) { + EGLint attrib; + eglGetConfigAttrib(GetDisplay(), GetConfig(), + EGL_OPTIMAL_SURFACE_ORIENTATION_ANGLE, &attrib); + flips_vertically_ = (attrib == EGL_SURFACE_ORIENTATION_INVERT_Y_ANGLE); + } + + if (flips_vertically_) { + egl_window_attributes.push_back(EGL_SURFACE_ORIENTATION_ANGLE); + egl_window_attributes.push_back(EGL_SURFACE_ORIENTATION_INVERT_Y_ANGLE); + } + egl_window_attributes.push_back(EGL_NONE); // Create a surface for the native window. surface_ = eglCreateWindowSurface( @@ -704,6 +728,10 @@ return supports_post_sub_buffer_; } +bool NativeViewGLSurfaceEGL::FlipsVertically() const { + return flips_vertically_; +} + gfx::SwapResult NativeViewGLSurfaceEGL::PostSubBuffer(int x, int y, int width, @@ -713,6 +741,12 @@ DVLOG(1) << "Failed to commit pending overlay planes."; return gfx::SwapResult::SWAP_FAILED; } + if (flips_vertically_) { + // With EGL_SURFACE_ORIENTATION_INVERT_Y_ANGLE the contents are rendered + // inverted, but the PostSubBuffer rectangle is still measured from the + // bottom left. + y = GetSize().height() - y - height; + } if (!eglPostSubBufferNV(GetDisplay(), surface_, x, y, width, height)) { DVLOG(1) << "eglPostSubBufferNV failed with error " << GetLastEGLErrorString();
diff --git a/ui/gl/gl_surface_egl.h b/ui/gl/gl_surface_egl.h index 232016d8..1c99faeb 100644 --- a/ui/gl/gl_surface_egl.h +++ b/ui/gl/gl_surface_egl.h
@@ -100,6 +100,7 @@ gl::GLImage* image, const Rect& bounds_rect, const RectF& crop_rect) override; + bool FlipsVertically() const override; // Create a NativeViewGLSurfaceEGL with an externally provided VSyncProvider. // Takes ownership of the VSyncProvider. @@ -125,6 +126,7 @@ EGLSurface surface_; bool supports_post_sub_buffer_; bool alpha_; + bool flips_vertically_; scoped_ptr<VSyncProvider> vsync_provider_;
diff --git a/ui/login/account_picker/user_pod_row.js b/ui/login/account_picker/user_pod_row.js index 35f39fd..8672327 100644 --- a/ui/login/account_picker/user_pod_row.js +++ b/ui/login/account_picker/user_pod_row.js
@@ -976,6 +976,23 @@ }, /** + * Gets the elements used for statistics display. + * @type {Object.<string, !HTMLDivElement>} + */ + get statsMapElements() { + return { + 'BrowsingHistory': + this.querySelector('.action-box-remove-user-warning-history'), + 'Passwords': + this.querySelector('.action-box-remove-user-warning-passwords'), + 'Bookmarks': + this.querySelector('.action-box-remove-user-warning-bookmarks'), + 'Settings': + this.querySelector('.action-box-remove-user-warning-settings') + } + }, + + /** * Updates the user pod element. */ update: function() { @@ -1404,7 +1421,6 @@ this.actionBoxMenu.classList.add('menu-moved-up'); this.actionBoxAreaElement.classList.add('menu-moved-up'); } - chrome.send('logRemoveUserWarningShown'); }, /** @@ -1418,32 +1434,16 @@ // Show extra statistics information for desktop users var message; - if (this.user.isDesktopUser) { - this.classList.remove('has-errors'); - var isSyncedUser = this.user.emailAddress !== ""; - if (!this.user.isProfileLoaded) { - message = loadTimeData.getString( - isSyncedUser ? 'removeUserWarningTextSyncNoStats' : - 'removeUserWarningTextNonSyncNoStats'); - this.updateRemoveWarningDialogSetMessage_(this.user.profilePath, - message); - } else { - message = loadTimeData.getString( - isSyncedUser ? 'removeUserWarningTextSyncCalculating' : - 'removeUserWarningTextNonSyncCalculating'); - substitute = loadTimeData.getString( - 'removeUserWarningTextCalculating'); - this.updateRemoveWarningDialogSetMessage_(this.user.profilePath, - message, substitute); - } - + if (this.user.isLegacySupervisedUser) { + this.moveActionMenuUpIfNeeded_(); + } else { + this.RemoveWarningDialogSetMessage_(true, false); // set a global handler for the callback window.updateRemoveWarningDialog = this.updateRemoveWarningDialog_.bind(this); chrome.send('removeUserWarningLoadStats', [this.user.profilePath]); } - - this.moveActionMenuUpIfNeeded_(); + chrome.send('logRemoveUserWarningShown'); }, /** @@ -1454,45 +1454,57 @@ updateRemoveWarningDialog_: function(profilePath, profileStats) { if (profilePath !== this.user.profilePath) return; - // Converting profileStats into id attribute by an object. - var stats_id_map = { - 'BrowsingHistory': 'action-box-remove-user-warning-history', - 'Passwords': 'action-box-remove-user-warning-passwords', - 'Bookmarks': 'action-box-remove-user-warning-bookmarks', - 'Settings': 'action-box-remove-user-warning-settings', - } - // Load individual statistics - var num_stats_loaded = 0; - var total_count = 0; - var failed = false; + + var stats_elements = this.statsMapElements; + // Update individual statistics + var hasErrors = false; for (var key in profileStats) { - if (stats_id_map.hasOwnProperty(key)) { + if (stats_elements.hasOwnProperty(key)) { if (profileStats[key].success) { - var count = profileStats[key].count; - this.querySelector("." + stats_id_map[key]).textContent = count; - total_count += count; - } else { - failed = true; - this.querySelector("." + stats_id_map[key]).textContent = ''; + this.user.statistics[key] = profileStats[key]; + } else if (!this.user.statistics[key].success) { + hasErrors = true; + stats_elements[key].textContent = ''; } + } + } + + this.RemoveWarningDialogSetMessage_(false, hasErrors); + }, + + /** + * Set the new message in the dialog. + * @param {boolean} Whether this is the first output, that requires setting + * a in-progress message. + * @param {boolean} Whether any actual query to the statistics have failed. + * Should be true only if there is an error and the corresponding statistic + * is also unavailable in ProfileInfoCache. + */ + RemoveWarningDialogSetMessage_: function(isInitial, hasErrors) { + var stats_elements = this.statsMapElements; + var total_count = 0; + var num_stats_loaded = 0; + for (var key in stats_elements) { + if (this.user.statistics[key].success) { + var count = this.user.statistics[key].count; + stats_elements[key].textContent = count; + total_count += count; num_stats_loaded++; } } // this.classList is used for selecting the appropriate dialog. - this.classList.toggle('has-errors', failed); - if (total_count > 0) { + if (total_count) this.classList.remove('has-no-stats'); - } + var is_synced_user = this.user.emailAddress !== ""; // Write total number if all statistics are loaded. - if (num_stats_loaded === Object.keys(stats_id_map).length) { - if (total_count === 0) { + if (num_stats_loaded === Object.keys(stats_elements).length) { + if (!total_count) { this.classList.add('has-no-stats'); - var isSyncedUser = this.user.emailAddress !== ""; var message = loadTimeData.getString( - isSyncedUser ? 'removeUserWarningTextSyncNoStats' : - 'removeUserWarningTextNonSyncNoStats'); + is_synced_user ? 'removeUserWarningTextSyncNoStats' : + 'removeUserWarningTextNonSyncNoStats'); this.updateRemoveWarningDialogSetMessage_(this.user.profilePath, message); } else { @@ -1500,14 +1512,28 @@ this.updateRemoveWarningDialogSetMessage_.bind(this); chrome.send('getRemoveWarningDialogMessage',[{ profilePath: this.user.profilePath, - isSyncedUser: this.user.emailAddress !== "", - hasErrors: failed, + isSyncedUser: is_synced_user, + hasErrors: hasErrors, totalCount: total_count }]); } + } else if (isInitial) { + if (!this.user.isProfileLoaded) { + message = loadTimeData.getString( + is_synced_user ? 'removeUserWarningTextSyncNoStats' : + 'removeUserWarningTextNonSyncNoStats'); + this.updateRemoveWarningDialogSetMessage_(this.user.profilePath, + message); + } else { + message = loadTimeData.getString( + is_synced_user ? 'removeUserWarningTextSyncCalculating' : + 'removeUserWarningTextNonSyncCalculating'); + substitute = loadTimeData.getString( + 'removeUserWarningTextCalculating'); + this.updateRemoveWarningDialogSetMessage_(this.user.profilePath, + message, substitute); + } } - - this.moveActionMenuUpIfNeeded_(); }, /** @@ -1524,8 +1550,7 @@ // Add localized messages where $1 will be replaced with // <span class="total-count"></span>. var element = this.querySelector('.action-box-remove-user-warning-text'); - while (element.firstChild) - element.removeChild(element.firstChild); + element.textContent = ''; messageParts = message.split('$1'); var numParts = messageParts.length; @@ -1538,6 +1563,7 @@ element.appendChild(elementToAdd); } } + this.moveActionMenuUpIfNeeded_(); }, /** @@ -2077,7 +2103,8 @@ this.classList.toggle('legacy-supervised', isLegacySupervisedUser); this.classList.toggle('child', isChildUser); this.classList.toggle('synced', isSyncedUser); - this.classList.toggle('has-no-stats', !isProfileLoaded); + this.classList.toggle('has-no-stats', + !isProfileLoaded && !this.user.statistics.length); if (this.isAuthTypeUserClick) this.passwordLabelElement.textContent = this.authValue;
diff --git a/ui/message_center/BUILD.gn b/ui/message_center/BUILD.gn index de11882..bda992c 100644 --- a/ui/message_center/BUILD.gn +++ b/ui/message_center/BUILD.gn
@@ -9,31 +9,33 @@ component("message_center") { deps = [ "//base", - "//base:i18n", - "//base/third_party/dynamic_annotations", - "//components/url_formatter", - "//skia", - "//ui/accessibility", "//ui/base", - "//ui/events", - "//ui/gfx", - "//ui/gfx/geometry", - "//ui/native_theme", - "//ui/resources", - "//ui/strings", "//url", ] - configs += [ - "//build/config:precompiled_headers", - - # TODO(jschuh): crbug.com/167187 fix size_t to int truncations. - "//build/config/compiler:no_size_t_to_int_warning", - ] - defines = [ "MESSAGE_CENTER_IMPLEMENTATION" ] if (enable_notifications && !is_android) { + deps += [ + "//base:i18n", + "//base/third_party/dynamic_annotations", + "//components/url_formatter", + "//skia", + "//ui/accessibility", + "//ui/events", + "//ui/gfx", + "//ui/gfx/geometry", + "//ui/native_theme", + "//ui/resources", + "//ui/strings", + ] + + configs += [ + "//build/config:precompiled_headers", + + # TODO(jschuh): crbug.com/167187 fix size_t to int truncations. + "//build/config/compiler:no_size_t_to_int_warning", + ] sources = [ "cocoa/notification_controller.h", "cocoa/notification_controller.mm", @@ -153,28 +155,30 @@ } } -static_library("test_support") { +source_set("test_support") { testonly = true - sources = [ - "fake_message_center.cc", - "fake_message_center.h", - "fake_message_center_tray_delegate.cc", - "fake_message_center_tray_delegate.h", - "fake_notifier_settings_provider.cc", - "fake_notifier_settings_provider.h", - ] + + if (enable_notifications && !is_android) { + sources = [ + "fake_message_center.cc", + "fake_message_center.h", + "fake_message_center_tray_delegate.cc", + "fake_message_center_tray_delegate.h", + "fake_notifier_settings_provider.cc", + "fake_notifier_settings_provider.h", + ] + deps = [ + "//base", + "//base/test:test_support", + "//skia", + "//ui/gfx", + "//ui/gfx/geometry", + ] + } public_deps = [ ":message_center", ] - - deps = [ - "//base", - "//base/test:test_support", - "//skia", - "//ui/gfx", - "//ui/gfx/geometry", - ] } test("message_center_unittests") {
diff --git a/ui/ozone/BUILD.gn b/ui/ozone/BUILD.gn index 32746189..e6881de 100644 --- a/ui/ozone/BUILD.gn +++ b/ui/ozone/BUILD.gn
@@ -72,8 +72,6 @@ "common/gpu/ozone_gpu_messages.h", "common/native_display_delegate_ozone.cc", "common/native_display_delegate_ozone.h", - "common/stub_client_native_pixmap_factory.cc", - "common/stub_client_native_pixmap_factory.h", "common/stub_overlay_manager.cc", "common/stub_overlay_manager.h", "public/cursor_factory_ozone.cc", @@ -115,6 +113,8 @@ component("ozone") { sources = [ + "common/stub_client_native_pixmap_factory.cc", + "common/stub_client_native_pixmap_factory.h", "platform_selection.cc", "platform_selection.h", "public/client_native_pixmap_factory.cc",
diff --git a/ui/ozone/common/egl_util.h b/ui/ozone/common/egl_util.h index 5cdfa428..8e20387 100644 --- a/ui/ozone/common/egl_util.h +++ b/ui/ozone/common/egl_util.h
@@ -5,15 +5,18 @@ #ifndef UI_OZONE_COMMON_EGL_UTIL_H_ #define UI_OZONE_COMMON_EGL_UTIL_H_ +#include "ui/ozone/ozone_base_export.h" #include "ui/ozone/public/surface_factory_ozone.h" namespace ui { +OZONE_BASE_EXPORT bool LoadDefaultEGLGLES2Bindings( SurfaceFactoryOzone::AddGLLibraryCallback add_gl_library, SurfaceFactoryOzone::SetGLGetProcAddressProcCallback set_gl_get_proc_address); +OZONE_BASE_EXPORT bool LoadEGLGLES2Bindings( SurfaceFactoryOzone::AddGLLibraryCallback add_gl_library, SurfaceFactoryOzone::SetGLGetProcAddressProcCallback
diff --git a/ui/ozone/common/native_display_delegate_ozone.h b/ui/ozone/common/native_display_delegate_ozone.h index 6def01f..8c5a8cb 100644 --- a/ui/ozone/common/native_display_delegate_ozone.h +++ b/ui/ozone/common/native_display_delegate_ozone.h
@@ -10,10 +10,12 @@ #include "base/macros.h" #include "base/memory/scoped_vector.h" #include "ui/display/types/native_display_delegate.h" +#include "ui/ozone/ozone_base_export.h" namespace ui { -class NativeDisplayDelegateOzone : public NativeDisplayDelegate { +class OZONE_BASE_EXPORT NativeDisplayDelegateOzone + : public NativeDisplayDelegate { public: NativeDisplayDelegateOzone(); ~NativeDisplayDelegateOzone() override;
diff --git a/ui/ozone/common/stub_overlay_manager.h b/ui/ozone/common/stub_overlay_manager.h index 54fa3a36..3d42c2b 100644 --- a/ui/ozone/common/stub_overlay_manager.h +++ b/ui/ozone/common/stub_overlay_manager.h
@@ -6,11 +6,12 @@ #define UI_OZONE_COMMON_STUB_OVERLAY_MANAGER_H_ #include "base/macros.h" +#include "ui/ozone/ozone_base_export.h" #include "ui/ozone/public/overlay_manager_ozone.h" namespace ui { -class StubOverlayManager : public OverlayManagerOzone { +class OZONE_BASE_EXPORT StubOverlayManager : public OverlayManagerOzone { public: StubOverlayManager(); ~StubOverlayManager() override;
diff --git a/ui/ozone/platform/drm/BUILD.gn b/ui/ozone/platform/drm/BUILD.gn index f41e3ad3..26dfa60 100644 --- a/ui/ozone/platform/drm/BUILD.gn +++ b/ui/ozone/platform/drm/BUILD.gn
@@ -82,6 +82,8 @@ "host/channel_observer.h", "host/drm_cursor.cc", "host/drm_cursor.h", + "host/drm_cursor_core.cc", + "host/drm_cursor_core.h", "host/drm_device_handle.cc", "host/drm_device_handle.h", "host/drm_display_host.cc",
diff --git a/ui/ozone/platform/drm/gbm.gypi b/ui/ozone/platform/drm/gbm.gypi index 7cc797c..a73909c 100644 --- a/ui/ozone/platform/drm/gbm.gypi +++ b/ui/ozone/platform/drm/gbm.gypi
@@ -109,6 +109,8 @@ 'host/channel_observer.h', 'host/drm_cursor.cc', 'host/drm_cursor.h', + 'host/drm_cursor_core.cc', + 'host/drm_cursor_core.h', 'host/drm_device_handle.cc', 'host/drm_device_handle.h', 'host/drm_display_host.cc',
diff --git a/ui/ozone/platform/drm/host/drm_cursor.cc b/ui/ozone/platform/drm/host/drm_cursor.cc index ad0e0b23..31c5b9f 100644 --- a/ui/ozone/platform/drm/host/drm_cursor.cc +++ b/ui/ozone/platform/drm/host/drm_cursor.cc
@@ -11,7 +11,6 @@ #include "ui/gfx/geometry/point_conversions.h" #include "ui/gfx/geometry/point_f.h" #include "ui/ozone/common/gpu/ozone_gpu_messages.h" -#include "ui/ozone/platform/drm/host/drm_window_host.h" #include "ui/ozone/platform/drm/host/drm_window_host_manager.h" #if defined(OS_CHROMEOS) @@ -21,182 +20,109 @@ namespace ui { DrmCursor::DrmCursor(DrmWindowHostManager* window_manager) - : window_manager_(window_manager) { -} + : ipc_(&lock_), core_(new DrmCursorCore(&ipc_, window_manager)) {} DrmCursor::~DrmCursor() { } void DrmCursor::SetCursor(gfx::AcceleratedWidget window, PlatformCursor platform_cursor) { - DCHECK(ui_task_runner_->BelongsToCurrentThread()); + TRACE_EVENT0("drmcursor", "DrmCursor::SetCursor"); + DCHECK(thread_checker_.CalledOnValidThread()); DCHECK_NE(window, gfx::kNullAcceleratedWidget); scoped_refptr<BitmapCursorOzone> bitmap = BitmapCursorFactoryOzone::GetBitmapCursor(platform_cursor); - base::AutoLock lock(state_.lock); - if (state_.window != window || state_.bitmap == bitmap) - return; - - state_.bitmap = bitmap; - - SendCursorShowLocked(); + base::AutoLock lock(lock_); + core_->SetCursor(window, bitmap); } void DrmCursor::OnWindowAdded(gfx::AcceleratedWidget window, const gfx::Rect& bounds_in_screen, const gfx::Rect& cursor_confined_bounds) { -#if DCHECK_IS_ON() - if (!ui_task_runner_) - ui_task_runner_ = base::ThreadTaskRunnerHandle::Get(); -#endif - DCHECK(ui_task_runner_->BelongsToCurrentThread()); - base::AutoLock lock(state_.lock); + TRACE_EVENT0("drmcursor", "DrmCursor::OnWindowAdded"); + DCHECK(thread_checker_.CalledOnValidThread()); + base::AutoLock lock(lock_); - if (state_.window == gfx::kNullAcceleratedWidget) { - // First window added & cursor is not placed. Place it. - state_.window = window; - state_.display_bounds_in_screen = bounds_in_screen; - state_.confined_bounds = cursor_confined_bounds; - SetCursorLocationLocked(gfx::PointF(cursor_confined_bounds.CenterPoint())); - } + core_->OnWindowAdded(window, bounds_in_screen, cursor_confined_bounds); } void DrmCursor::OnWindowRemoved(gfx::AcceleratedWidget window) { - DCHECK(ui_task_runner_->BelongsToCurrentThread()); - base::AutoLock lock(state_.lock); - - if (state_.window == window) { - // Try to find a new location for the cursor. - DrmWindowHost* dest_window = window_manager_->GetPrimaryWindow(); - - if (dest_window) { - state_.window = dest_window->GetAcceleratedWidget(); - state_.display_bounds_in_screen = dest_window->GetBounds(); - state_.confined_bounds = dest_window->GetCursorConfinedBounds(); - SetCursorLocationLocked( - gfx::PointF(state_.confined_bounds.CenterPoint())); - SendCursorShowLocked(); - } else { - state_.window = gfx::kNullAcceleratedWidget; - state_.display_bounds_in_screen = gfx::Rect(); - state_.confined_bounds = gfx::Rect(); - state_.location = gfx::PointF(); - } - } + TRACE_EVENT0("drmcursor", "DrmCursor::OnWindowRemoved"); + DCHECK(thread_checker_.CalledOnValidThread()); + base::AutoLock lock(lock_); + core_->OnWindowRemoved(window); } void DrmCursor::CommitBoundsChange( gfx::AcceleratedWidget window, const gfx::Rect& new_display_bounds_in_screen, const gfx::Rect& new_confined_bounds) { - DCHECK(ui_task_runner_->BelongsToCurrentThread()); - base::AutoLock lock(state_.lock); - if (state_.window == window) { - state_.display_bounds_in_screen = new_display_bounds_in_screen; - state_.confined_bounds = new_confined_bounds; - SetCursorLocationLocked(state_.location); - SendCursorShowLocked(); - } + TRACE_EVENT0("drmcursor", "DrmCursor::CommitBoundsChange"); + DCHECK(thread_checker_.CalledOnValidThread()); + base::AutoLock lock(lock_); + core_->CommitBoundsChange(window, new_display_bounds_in_screen, + new_confined_bounds); } void DrmCursor::MoveCursorTo(gfx::AcceleratedWidget window, const gfx::PointF& location) { - DCHECK(ui_task_runner_->BelongsToCurrentThread()); - base::AutoLock lock(state_.lock); - gfx::AcceleratedWidget old_window = state_.window; - - if (window != old_window) { - // When moving between displays, hide the cursor on the old display - // prior to showing it on the new display. - if (old_window != gfx::kNullAcceleratedWidget) - SendCursorHideLocked(); - - DrmWindowHost* drm_window_host = window_manager_->GetWindow(window); - state_.display_bounds_in_screen = drm_window_host->GetBounds(); - state_.confined_bounds = drm_window_host->GetCursorConfinedBounds(); - state_.window = window; - } - - SetCursorLocationLocked(location); - - if (window != old_window) - SendCursorShowLocked(); - else - SendCursorMoveLocked(); + TRACE_EVENT0("drmcursor", "DrmCursor::MoveCursorTo (window)"); + DCHECK(thread_checker_.CalledOnValidThread()); + base::AutoLock lock(lock_); + core_->MoveCursorTo(window, location); } void DrmCursor::MoveCursorTo(const gfx::PointF& screen_location) { - base::AutoLock lock(state_.lock); - - // TODO(spang): Moving between windows doesn't work here, but - // is not needed for current uses. - - SetCursorLocationLocked(screen_location - - state_.display_bounds_in_screen.OffsetFromOrigin()); - - SendCursorMoveLocked(); + TRACE_EVENT0("drmcursor", "DrmCursor::MoveCursorTo"); + DCHECK(thread_checker_.CalledOnValidThread()); + base::AutoLock lock(lock_); + core_->MoveCursorTo(screen_location); } void DrmCursor::MoveCursor(const gfx::Vector2dF& delta) { - base::AutoLock lock(state_.lock); - if (state_.window == gfx::kNullAcceleratedWidget) - return; - - gfx::Point location; -#if defined(OS_CHROMEOS) - gfx::Vector2dF transformed_delta = delta; - ui::CursorController::GetInstance()->ApplyCursorConfigForWindow( - state_.window, &transformed_delta); - SetCursorLocationLocked(state_.location + transformed_delta); -#else - SetCursorLocationLocked(state_.location + delta); -#endif - - SendCursorMoveLocked(); + TRACE_EVENT0("drmcursor", "DrmCursor::MoveCursor"); + base::AutoLock lock(lock_); + core_->MoveCursor(delta); } bool DrmCursor::IsCursorVisible() { - base::AutoLock lock(state_.lock); - return state_.bitmap; + base::AutoLock lock(lock_); + return core_->IsCursorVisible(); } gfx::PointF DrmCursor::GetLocation() { - base::AutoLock lock(state_.lock); - return state_.location + state_.display_bounds_in_screen.OffsetFromOrigin(); + base::AutoLock lock(lock_); + return core_->GetLocation(); } gfx::Rect DrmCursor::GetCursorConfinedBounds() { - base::AutoLock lock(state_.lock); - return state_.confined_bounds + - state_.display_bounds_in_screen.OffsetFromOrigin(); + base::AutoLock lock(lock_); + return core_->GetCursorConfinedBounds(); } void DrmCursor::OnChannelEstablished( int host_id, scoped_refptr<base::SingleThreadTaskRunner> send_runner, const base::Callback<void(IPC::Message*)>& send_callback) { -#if DCHECK_IS_ON() - if (!ui_task_runner_) - ui_task_runner_ = base::ThreadTaskRunnerHandle::Get(); -#endif - DCHECK(ui_task_runner_->BelongsToCurrentThread()); - base::AutoLock lock(state_.lock); - state_.host_id = host_id; - state_.send_runner = send_runner; - state_.send_callback = send_callback; + TRACE_EVENT0("drmcursor", "DrmCursor::OnChannelEstablished"); + DCHECK(thread_checker_.CalledOnValidThread()); + base::AutoLock lock(lock_); + ipc_.host_id = host_id; + ipc_.send_runner = send_runner; + ipc_.send_callback = send_callback; // Initial set for this GPU process will happen after the window // initializes, in CommitBoundsChange(). } void DrmCursor::OnChannelDestroyed(int host_id) { - DCHECK(ui_task_runner_->BelongsToCurrentThread()); - base::AutoLock lock(state_.lock); - if (state_.host_id == host_id) { - state_.host_id = -1; - state_.send_runner = NULL; - state_.send_callback.Reset(); + DCHECK(thread_checker_.CalledOnValidThread()); + base::AutoLock lock(lock_); + if (ipc_.host_id == host_id) { + ipc_.host_id = -1; + ipc_.send_runner = NULL; + ipc_.send_callback.Reset(); } } @@ -204,70 +130,37 @@ return false; } -void DrmCursor::SetCursorLocationLocked(const gfx::PointF& location) { - state_.lock.AssertAcquired(); - - gfx::PointF clamped_location = location; - clamped_location.SetToMax(gfx::PointF(state_.confined_bounds.origin())); - // Right and bottom edges are exclusive. - clamped_location.SetToMin(gfx::PointF(state_.confined_bounds.right() - 1, - state_.confined_bounds.bottom() - 1)); - - state_.location = clamped_location; +bool DrmCursor::CursorIPC::IsConnectedLocked() { + return !send_callback.is_null(); } -gfx::Point DrmCursor::GetBitmapLocationLocked() { - return gfx::ToFlooredPoint(state_.location) - - state_.bitmap->hotspot().OffsetFromOrigin(); +void DrmCursor::CursorIPC::CursorSet(gfx::AcceleratedWidget window, + const std::vector<SkBitmap>& bitmaps, + gfx::Point point, + int frame_delay_ms) { + SendLocked(new OzoneGpuMsg_CursorSet(window, bitmaps, point, frame_delay_ms)); } -bool DrmCursor::IsConnectedLocked() { - return !state_.send_callback.is_null(); +void DrmCursor::CursorIPC::Move(gfx::AcceleratedWidget window, + gfx::Point point) { + SendLocked(new OzoneGpuMsg_CursorMove(window, point)); } -void DrmCursor::SendCursorShowLocked() { - DCHECK(ui_task_runner_->BelongsToCurrentThread()); - if (!state_.bitmap) { - SendCursorHideLocked(); - return; - } - SendLocked(new OzoneGpuMsg_CursorSet(state_.window, state_.bitmap->bitmaps(), - GetBitmapLocationLocked(), - state_.bitmap->frame_delay_ms())); -} - -void DrmCursor::SendCursorHideLocked() { - DCHECK(ui_task_runner_->BelongsToCurrentThread()); - SendLocked(new OzoneGpuMsg_CursorSet(state_.window, std::vector<SkBitmap>(), - gfx::Point(), 0)); -} - -void DrmCursor::SendCursorMoveLocked() { - if (!state_.bitmap) - return; - SendLocked( - new OzoneGpuMsg_CursorMove(state_.window, GetBitmapLocationLocked())); -} - -void DrmCursor::SendLocked(IPC::Message* message) { - state_.lock.AssertAcquired(); +void DrmCursor::CursorIPC::SendLocked(IPC::Message* message) { + lock->AssertAcquired(); if (IsConnectedLocked() && - state_.send_runner->PostTask(FROM_HERE, - base::Bind(state_.send_callback, message))) + send_runner->PostTask(FROM_HERE, base::Bind(send_callback, message))) return; - // Drop disconnected updates. DrmWindowHost will call CommitBoundsChange() - // when - // we connect to initialize the cursor location. + // Drop disconnected updates. DrmWindowHost will call + // CommitBoundsChange() when we connect to initialize the cursor + // location. delete message; } -DrmCursor::CursorState::CursorState() - : window(gfx::kNullAcceleratedWidget), host_id(-1) { -} +DrmCursor::CursorIPC::CursorIPC(base::Lock* lock) : host_id(-1), lock(lock) {} -DrmCursor::CursorState::~CursorState() { -} +DrmCursor::CursorIPC::~CursorIPC() {} } // namespace ui
diff --git a/ui/ozone/platform/drm/host/drm_cursor.h b/ui/ozone/platform/drm/host/drm_cursor.h index 2fba1443..2766365 100644 --- a/ui/ozone/platform/drm/host/drm_cursor.h +++ b/ui/ozone/platform/drm/host/drm_cursor.h
@@ -5,15 +5,20 @@ #ifndef UI_OZONE_PLATFORM_DRM_HOST_DRM_CURSOR_H_ #define UI_OZONE_PLATFORM_DRM_HOST_DRM_CURSOR_H_ +#include <memory> + #include "base/callback.h" #include "base/logging.h" +#include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/synchronization/lock.h" +#include "base/threading/thread_checker.h" #include "ui/base/cursor/cursor.h" #include "ui/events/ozone/evdev/cursor_delegate_evdev.h" #include "ui/gfx/geometry/point_f.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/native_widget_types.h" +#include "ui/ozone/platform/drm/host/drm_cursor_core.h" #include "ui/ozone/public/gpu_platform_support_host.h" namespace gfx { @@ -23,10 +28,7 @@ } namespace ui { - -class BitmapCursorOzone; class BitmapCursorFactoryOzone; -class DrmGpuPlatformSupportHost; class DrmWindowHostManager; class DrmCursor : public CursorDelegateEvdev { @@ -66,54 +68,41 @@ bool OnMessageReceived(const IPC::Message& message); private: - // Set the location (clamps to cursor bounds). - void SetCursorLocationLocked(const gfx::PointF& location); + // An IPC-based implementation of the DrmCursorProxy that ships + // messages to the GPU process. + class CursorIPC : public DrmCursorProxy { + public: + explicit CursorIPC(base::Lock* lock); + ~CursorIPC(); - // The location of the bitmap (the cursor location is the hotspot location). - gfx::Point GetBitmapLocationLocked(); + bool IsConnectedLocked(); + void SendLocked(IPC::Message* message); - // IPC-related functions. - bool IsConnectedLocked(); - void SendCursorShowLocked(); - void SendCursorHideLocked(); - void SendCursorMoveLocked(); - void SendLocked(IPC::Message* message); - - DrmWindowHostManager* window_manager_; // Not owned. - - // Task runner for main thread. - scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_; - - struct CursorState { - CursorState(); - ~CursorState(); - - // The current cursor bitmap (immutable). - scoped_refptr<BitmapCursorOzone> bitmap; - - // The window under the cursor. - gfx::AcceleratedWidget window; - - // The location of the cursor within the window. - gfx::PointF location; - - // The bounds of the display under the cursor. - gfx::Rect display_bounds_in_screen; - - // The bounds that the cursor is confined to in |window|. - gfx::Rect confined_bounds; + // DrmCursorProxy implementation. + void CursorSet(gfx::AcceleratedWidget window, + const std::vector<SkBitmap>& bitmaps, + gfx::Point point, + int frame_delay_ms) override; + void Move(gfx::AcceleratedWidget window, gfx::Point point) override; int host_id; // Callback for IPC updates. base::Callback<void(IPC::Message*)> send_callback; scoped_refptr<base::SingleThreadTaskRunner> send_runner; - - // The mutex synchronizing this object. - base::Lock lock; + base::Lock* lock; }; - CursorState state_; + // The mutex synchronizing this object. + base::Lock lock_; + + // Enforce our threading constraints. + base::ThreadChecker thread_checker_; + + CursorIPC ipc_; + std::unique_ptr<DrmCursorCore> core_; + + DISALLOW_COPY_AND_ASSIGN(DrmCursor); }; } // namespace ui
diff --git a/ui/ozone/platform/drm/host/drm_cursor_core.cc b/ui/ozone/platform/drm/host/drm_cursor_core.cc new file mode 100644 index 0000000..9535d6a2 --- /dev/null +++ b/ui/ozone/platform/drm/host/drm_cursor_core.cc
@@ -0,0 +1,171 @@ +// 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/drm/host/drm_cursor_core.h" + +#include "ui/events/ozone/chromeos/cursor_controller.h" +#include "ui/gfx/geometry/point_conversions.h" +#include "ui/ozone/platform/drm/host/drm_window_host.h" +#include "ui/ozone/platform/drm/host/drm_window_host_manager.h" + +namespace ui { + +DrmCursorCore::DrmCursorCore(DrmCursorProxy* proxy, + DrmWindowHostManager* window_manager) + : window_(gfx::kNullAcceleratedWidget), + window_manager_(window_manager), + proxy_(proxy) {} + +DrmCursorCore::~DrmCursorCore() {} + +gfx::Point DrmCursorCore::GetBitmapLocationLocked() { + return gfx::ToFlooredPoint(location_) - bitmap_->hotspot().OffsetFromOrigin(); +} + +void DrmCursorCore::SetCursor(gfx::AcceleratedWidget window, + scoped_refptr<BitmapCursorOzone> bitmap) { + if (window_ != window || bitmap_ == bitmap) + return; + + bitmap_ = bitmap; + + SendCursorShow(); +} + +void DrmCursorCore::OnWindowAdded(gfx::AcceleratedWidget window, + const gfx::Rect& bounds_in_screen, + const gfx::Rect& cursor_confined_bounds) { + if (window_ == gfx::kNullAcceleratedWidget) { + // First window added & cursor is not placed. Place it. + window_ = window; + display_bounds_in_screen_ = bounds_in_screen; + confined_bounds_ = cursor_confined_bounds; + SetCursorLocation(gfx::PointF(cursor_confined_bounds.CenterPoint())); + } +} + +void DrmCursorCore::OnWindowRemoved(gfx::AcceleratedWidget window) { + if (window_ == window) { + // Try to find a new location for the cursor. + DrmWindowHost* dest_window = window_manager_->GetPrimaryWindow(); + + if (dest_window) { + window_ = dest_window->GetAcceleratedWidget(); + display_bounds_in_screen_ = dest_window->GetBounds(); + confined_bounds_ = dest_window->GetCursorConfinedBounds(); + SetCursorLocation(gfx::PointF(confined_bounds_.CenterPoint())); + SendCursorShow(); + } else { + window_ = gfx::kNullAcceleratedWidget; + display_bounds_in_screen_ = gfx::Rect(); + confined_bounds_ = gfx::Rect(); + location_ = gfx::PointF(); + } + } +} + +void DrmCursorCore::CommitBoundsChange( + gfx::AcceleratedWidget window, + const gfx::Rect& new_display_bounds_in_screen, + const gfx::Rect& new_confined_bounds) { + if (window_ == window) { + display_bounds_in_screen_ = new_display_bounds_in_screen; + confined_bounds_ = new_confined_bounds; + SetCursorLocation(location_); + SendCursorShow(); + } +} + +void DrmCursorCore::MoveCursorTo(gfx::AcceleratedWidget window, + const gfx::PointF& location) { + gfx::AcceleratedWidget old_window = window_; + + if (window != old_window) { + // When moving between displays, hide the cursor on the old display + // prior to showing it on the new display. + if (old_window != gfx::kNullAcceleratedWidget) + SendCursorHide(); + + // TODO(rjk): pass this in? + DrmWindowHost* drm_window_host = window_manager_->GetWindow(window); + display_bounds_in_screen_ = drm_window_host->GetBounds(); + confined_bounds_ = drm_window_host->GetCursorConfinedBounds(); + window_ = window; + } + + SetCursorLocation(location_); + if (window != old_window) + SendCursorShow(); + else + SendCursorMove(); +} + +void DrmCursorCore::MoveCursorTo(const gfx::PointF& screen_location) { + // TODO(spang): Moving between windows doesn't work here, but + // is not needed for current uses. + SetCursorLocation(screen_location - + display_bounds_in_screen_.OffsetFromOrigin()); + + SendCursorMove(); +} + +void DrmCursorCore::MoveCursor(const gfx::Vector2dF& delta) { + if (window_ == gfx::kNullAcceleratedWidget) + return; + + gfx::Point location; +#if defined(OS_CHROMEOS) + gfx::Vector2dF transformed_delta = delta; + ui::CursorController::GetInstance()->ApplyCursorConfigForWindow( + window_, &transformed_delta); + SetCursorLocation(location_ + transformed_delta); +#else + SetCursorLocation(location_ + delta); +#endif + SendCursorMove(); +} + +bool DrmCursorCore::IsCursorVisible() { + return bitmap_; +} + +gfx::PointF DrmCursorCore::GetLocation() { + return location_ + display_bounds_in_screen_.OffsetFromOrigin(); +} + +gfx::Rect DrmCursorCore::GetCursorConfinedBounds() { + return confined_bounds_ + display_bounds_in_screen_.OffsetFromOrigin(); +} + +void DrmCursorCore::SetCursorLocation(const gfx::PointF& location) { + gfx::PointF clamped_location = location; + clamped_location.SetToMax(gfx::PointF(confined_bounds_.origin())); + // Right and bottom edges are exclusive. + clamped_location.SetToMin( + gfx::PointF(confined_bounds_.right() - 1, confined_bounds_.bottom() - 1)); + + location_ = clamped_location; +} + +void DrmCursorCore::SendCursorShow() { + if (!bitmap_) { + SendCursorHide(); + return; + } + proxy_->CursorSet(window_, bitmap_->bitmaps(), GetBitmapLocationLocked(), + bitmap_->frame_delay_ms()); +} + +void DrmCursorCore::SendCursorHide() { + proxy_->CursorSet(window_, std::vector<SkBitmap>(), gfx::Point(), 0); +} + +void DrmCursorCore::SendCursorMove() { + if (!bitmap_) + return; + + proxy_->Move(window_, GetBitmapLocationLocked()); +} + +} // namespace ui
diff --git a/ui/ozone/platform/drm/host/drm_cursor_core.h b/ui/ozone/platform/drm/host/drm_cursor_core.h new file mode 100644 index 0000000..3dc7bce --- /dev/null +++ b/ui/ozone/platform/drm/host/drm_cursor_core.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 UI_OZONE_PLATFORM_DRM_HOST_DRM_CURSOR_CORE_H_ +#define UI_OZONE_PLATFORM_DRM_HOST_DRM_CURSOR_CORE_H_ + +#include <vector> + +#include "base/macros.h" +#include "base/memory/ref_counted.h" +#include "ui/base/cursor/ozone/bitmap_cursor_factory_ozone.h" +#include "ui/gfx/geometry/point_f.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/gfx/native_widget_types.h" + +namespace ui { +class BitmapCursorOzone; +class DrmWindowHostManager; + +// DrmCursorCore manages all cursor state but is dependent on an injected +// proxy for how it communicates state changes to other threads or +// processes. The proxy implementation must satisfy DrmCursorProxy. +class DrmCursorProxy { + public: + // Sets the cursor |bitmaps| on |window| at |point| with |frame_delay_ms|. + virtual void CursorSet(gfx::AcceleratedWidget window, + const std::vector<SkBitmap>& bitmaps, + gfx::Point point, + int frame_delay_ms) = 0; + // Moves the cursor in |window| to |point| + virtual void Move(gfx::AcceleratedWidget window, gfx::Point point) = 0; +}; + +// DrmCursorCore manages all cursor state and semantics. +class DrmCursorCore { + public: + DrmCursorCore(DrmCursorProxy* proxy, DrmWindowHostManager* window_manager); + ~DrmCursorCore(); + + // Change the cursor over the specifed window. + void SetCursor(gfx::AcceleratedWidget window, + scoped_refptr<BitmapCursorOzone> platform_cursor); + + // Handle window lifecycle. + void OnWindowAdded(gfx::AcceleratedWidget window, + const gfx::Rect& bounds_in_screen, + const gfx::Rect& cursor_confined_bounds); + void OnWindowRemoved(gfx::AcceleratedWidget window); + + // Handle window bounds changes. + void CommitBoundsChange(gfx::AcceleratedWidget window, + const gfx::Rect& new_display_bounds_in_screen, + const gfx::Rect& new_confined_bounds); + + // CursorDelegateEvdev: + void MoveCursorTo(gfx::AcceleratedWidget window, const gfx::PointF& location); + void MoveCursorTo(const gfx::PointF& screen_location); + void MoveCursor(const gfx::Vector2dF& delta); + bool IsCursorVisible(); + gfx::PointF GetLocation(); + gfx::Rect GetCursorConfinedBounds(); + + private: + void SetCursorLocation(const gfx::PointF& location); + void SendCursorShow(); + void SendCursorHide(); + void SendCursorMove(); + + // The location of the bitmap (the cursor location is the hotspot location). + gfx::Point GetBitmapLocationLocked(); + + // The current cursor bitmap (immutable). + scoped_refptr<BitmapCursorOzone> bitmap_; + + // The window under the cursor. + gfx::AcceleratedWidget window_; + + // The location of the cursor within the window. + gfx::PointF location_; + + // The bounds of the display under the cursor. + gfx::Rect display_bounds_in_screen_; + + // The bounds that the cursor is confined to in |window|. + gfx::Rect confined_bounds_; + + DrmWindowHostManager* window_manager_; // Not owned. + + // Lifetime managed by the caller. + DrmCursorProxy* proxy_; + + DISALLOW_COPY_AND_ASSIGN(DrmCursorCore); +}; + +} // namespace ui + +#endif // UI_OZONE_PLATFORM_DRM_HOST_DRM_CURSOR_H_
diff --git a/ui/ozone/platform/egltest/client_native_pixmap_factory_egltest.cc b/ui/ozone/platform/egltest/client_native_pixmap_factory_egltest.cc index d6fe65ed..9e551f80 100644 --- a/ui/ozone/platform/egltest/client_native_pixmap_factory_egltest.cc +++ b/ui/ozone/platform/egltest/client_native_pixmap_factory_egltest.cc
@@ -4,7 +4,7 @@ #include "ui/ozone/platform/egltest/client_native_pixmap_factory_egltest.h" -#include "ui/ozone/common/stub_client_native_pixmap_factory.h" +#include "ui/ozone/common/stub_client_native_pixmap_factory.h" // nogncheck namespace ui {
diff --git a/ui/ozone/platform/headless/client_native_pixmap_factory_headless.cc b/ui/ozone/platform/headless/client_native_pixmap_factory_headless.cc index 1f409eb..f1e875d 100644 --- a/ui/ozone/platform/headless/client_native_pixmap_factory_headless.cc +++ b/ui/ozone/platform/headless/client_native_pixmap_factory_headless.cc
@@ -4,7 +4,7 @@ #include "ui/ozone/platform/headless/client_native_pixmap_factory_headless.h" -#include "ui/ozone/common/stub_client_native_pixmap_factory.h" +#include "ui/ozone/common/stub_client_native_pixmap_factory.h" // nogncheck namespace ui {
diff --git a/ui/ozone/public/input_controller.h b/ui/ozone/public/input_controller.h index e7fdaf7..398fbbe 100644 --- a/ui/ozone/public/input_controller.h +++ b/ui/ozone/public/input_controller.h
@@ -13,7 +13,7 @@ #include "base/files/file_path.h" #include "base/macros.h" #include "base/memory/scoped_ptr.h" -#include "ui/ozone/ozone_export.h" +#include "ui/ozone/ozone_base_export.h" namespace base { class TimeDelta; @@ -28,7 +28,7 @@ // The object provides methods for the preference page to configure input // devices w.r.t. the user setting. On ChromeOS, this replaces the inputcontrol // script that is originally located at /opt/google/chrome/. -class OZONE_EXPORT InputController { +class OZONE_BASE_EXPORT InputController { public: typedef base::Callback<void(scoped_ptr<std::string>)> GetTouchDeviceStatusReply; @@ -91,7 +91,7 @@ }; // Create an input controller that does nothing. -OZONE_EXPORT scoped_ptr<InputController> CreateStubInputController(); +OZONE_BASE_EXPORT scoped_ptr<InputController> CreateStubInputController(); } // namespace ui
diff --git a/ui/ozone/public/ozone_switches.h b/ui/ozone/public/ozone_switches.h index 88c848b0..099b858c1 100644 --- a/ui/ozone/public/ozone_switches.h +++ b/ui/ozone/public/ozone_switches.h
@@ -6,19 +6,19 @@ #define UI_OZONE_PUBLIC_OZONE_SWITCHES_H_ #include "base/compiler_specific.h" -#include "ui/ozone/ozone_export.h" +#include "ui/ozone/ozone_base_export.h" namespace switches { -OZONE_EXPORT extern const char kOzonePlatform[]; +OZONE_BASE_EXPORT extern const char kOzonePlatform[]; -OZONE_EXPORT extern const char kOzoneDumpFile[]; +OZONE_BASE_EXPORT extern const char kOzoneDumpFile[]; -OZONE_EXPORT extern const char kOzoneTestSingleOverlaySupport[]; +OZONE_BASE_EXPORT extern const char kOzoneTestSingleOverlaySupport[]; -OZONE_EXPORT extern const char kOzoneInitialDisplayBounds[]; +OZONE_BASE_EXPORT extern const char kOzoneInitialDisplayBounds[]; -OZONE_EXPORT extern const char kOzoneInitialDisplayPhysicalSizeMm[]; +OZONE_BASE_EXPORT extern const char kOzoneInitialDisplayPhysicalSizeMm[]; } // namespace switches
diff --git a/ui/platform_window/x11/BUILD.gn b/ui/platform_window/x11/BUILD.gn index 9f734ae..4775aa7 100644 --- a/ui/platform_window/x11/BUILD.gn +++ b/ui/platform_window/x11/BUILD.gn
@@ -2,6 +2,10 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import("//build/config/ui.gni") + +assert(use_x11) + component("x11") { output_name = "x11_window"
diff --git a/ui/touch_selection/longpress_drag_selector.cc b/ui/touch_selection/longpress_drag_selector.cc index b84c90da..fdc3221 100644 --- a/ui/touch_selection/longpress_drag_selector.cc +++ b/ui/touch_selection/longpress_drag_selector.cc
@@ -108,7 +108,7 @@ } bool LongPressDragSelector::IsActive() const { - return state_ != INACTIVE && state_ != LONGPRESS_PENDING; + return state_ == DRAG_PENDING || state_ == DRAGGING; } void LongPressDragSelector::OnLongPressEvent(base::TimeTicks event_time, @@ -126,6 +126,10 @@ } } +void LongPressDragSelector::OnScrollBeginEvent() { + SetState(INACTIVE); +} + void LongPressDragSelector::OnSelectionActivated() { if (state_ == SELECTION_PENDING) SetState(DRAG_PENDING);
diff --git a/ui/touch_selection/longpress_drag_selector.h b/ui/touch_selection/longpress_drag_selector.h index f6e84ec..4ebdd675 100644 --- a/ui/touch_selection/longpress_drag_selector.h +++ b/ui/touch_selection/longpress_drag_selector.h
@@ -40,6 +40,9 @@ void OnLongPressEvent(base::TimeTicks event_time, const gfx::PointF& position); + // Called when a scroll is going to happen to cancel longpress-drag gesture. + void OnScrollBeginEvent(); + // Called when the active selection changes. void OnSelectionActivated(); void OnSelectionDeactivated();
diff --git a/ui/touch_selection/longpress_drag_selector_unittest.cc b/ui/touch_selection/longpress_drag_selector_unittest.cc index 88594395..badb2697 100644 --- a/ui/touch_selection/longpress_drag_selector_unittest.cc +++ b/ui/touch_selection/longpress_drag_selector_unittest.cc
@@ -87,12 +87,13 @@ gfx::PointF selection_start(0, 10); gfx::PointF selection_end(10, 10); selector.OnLongPressEvent(event.GetEventTime(), gfx::PointF()); - EXPECT_TRUE(GetAndResetActiveStateChanged()); + EXPECT_FALSE(GetAndResetActiveStateChanged()); // Motion should not be consumed until a selection is detected. EXPECT_FALSE(selector.WillHandleTouchEvent(event.MovePoint(0, 0, 0))); SetSelection(selection_start, selection_end); selector.OnSelectionActivated(); + EXPECT_TRUE(GetAndResetActiveStateChanged()); EXPECT_FALSE(IsDragging()); // Initiate drag motion. Note that the first move event after activation is @@ -133,9 +134,10 @@ gfx::PointF selection_start(0, 10); gfx::PointF selection_end(10, 10); selector.OnLongPressEvent(event.GetEventTime(), gfx::PointF()); - EXPECT_TRUE(GetAndResetActiveStateChanged()); + EXPECT_FALSE(GetAndResetActiveStateChanged()); SetSelection(selection_start, selection_end); selector.OnSelectionActivated(); + EXPECT_TRUE(GetAndResetActiveStateChanged()); EXPECT_FALSE(IsDragging()); // Initiate drag motion. @@ -248,10 +250,9 @@ EXPECT_FALSE(selector.WillHandleTouchEvent(event.PressPoint(0, 0))); EXPECT_FALSE(GetAndResetActiveStateChanged()); - // Trigger a longpress. This will notify the client that detection is active, - // but until there's a longpress no drag selection should occur. + // Trigger a longpress. selector.OnLongPressEvent(event.GetEventTime(), gfx::PointF()); - EXPECT_TRUE(GetAndResetActiveStateChanged()); + EXPECT_FALSE(GetAndResetActiveStateChanged()); EXPECT_FALSE(IsDragging()); // Touch movement should not initiate selection drag, as there is no active @@ -263,7 +264,6 @@ EXPECT_EQ(gfx::PointF(), DragPosition()); EXPECT_FALSE(selector.WillHandleTouchEvent(event.ReleasePoint())); - EXPECT_TRUE(GetAndResetActiveStateChanged()); } TEST_F(LongPressDragSelectorTest, NoDragMotion) { @@ -276,11 +276,12 @@ // Activate a longpress-triggered selection. selector.OnLongPressEvent(event.GetEventTime(), gfx::PointF()); - EXPECT_TRUE(GetAndResetActiveStateChanged()); + EXPECT_FALSE(GetAndResetActiveStateChanged()); gfx::PointF selection_start(0, 10); gfx::PointF selection_end(10, 10); SetSelection(selection_start, selection_end); selector.OnSelectionActivated(); + EXPECT_TRUE(GetAndResetActiveStateChanged()); EXPECT_FALSE(IsDragging()); // Touch movement within the slop region should not initiate selection drag. @@ -304,11 +305,12 @@ // Activate a longpress-triggered selection. selector.OnLongPressEvent(event.GetEventTime(), gfx::PointF()); - EXPECT_TRUE(GetAndResetActiveStateChanged()); + EXPECT_FALSE(GetAndResetActiveStateChanged()); gfx::PointF selection_start(0, 10); gfx::PointF selection_end(10, 10); SetSelection(selection_start, selection_end); selector.OnSelectionActivated(); + EXPECT_TRUE(GetAndResetActiveStateChanged()); EXPECT_FALSE(IsDragging()); // Start a drag selection. @@ -342,9 +344,10 @@ gfx::PointF selection_start(0, 10); gfx::PointF selection_end(10, 10); selector.OnLongPressEvent(event.GetEventTime(), gfx::PointF()); - EXPECT_TRUE(GetAndResetActiveStateChanged()); + EXPECT_FALSE(GetAndResetActiveStateChanged()); SetSelection(selection_start, selection_end); selector.OnSelectionActivated(); + EXPECT_TRUE(GetAndResetActiveStateChanged()); EXPECT_FALSE(IsDragging()); // Initiate drag motion. @@ -364,4 +367,31 @@ EXPECT_TRUE(GetAndResetActiveStateChanged()); } +TEST_F(LongPressDragSelectorTest, ScrollAfterLongPress) { + LongPressDragSelector selector(this); + MockMotionEvent event; + gfx::PointF touch_point(0, 0); + + // Start a touch sequence. + EXPECT_FALSE(selector.WillHandleTouchEvent( + event.PressPoint(touch_point.x(), touch_point.y()))); + + // Long-press and hold down. + selector.OnLongPressEvent(event.GetEventTime(), touch_point); + + // Scroll the page. This should cancel long-press drag gesture. + touch_point.Offset(0, 2 * kSlop); + EXPECT_FALSE(selector.WillHandleTouchEvent( + event.MovePoint(0, touch_point.x(), touch_point.y()))); + selector.OnScrollBeginEvent(); + + // Now if the selection is activated, because long-press drag gesture was + // canceled, active state of the long-press selector should not change. + selector.OnSelectionActivated(); + EXPECT_FALSE(GetAndResetActiveStateChanged()); + + // Release the touch sequence. + selector.WillHandleTouchEvent(event.ReleasePoint()); +} + } // namespace ui
diff --git a/ui/touch_selection/touch_selection_controller.cc b/ui/touch_selection/touch_selection_controller.cc index 3baf946..8ea8246 100644 --- a/ui/touch_selection/touch_selection_controller.cc +++ b/ui/touch_selection/touch_selection_controller.cc
@@ -241,6 +241,24 @@ return false; } +void TouchSelectionController::OnScrollBeginEvent() { + // When there is an active selection, if the user performs a long-press that + // does not trigger a new selection (e.g. a long-press on an empty area) and + // then scrolls, the scroll will move the selection. In this case we will + // think incorrectly that the selection change was due to the long-press and + // will activate touch selection and start long-press drag gesture (see + // ActivateInsertionIfNecessary()). To prevent this, we need to reset the + // state of touch selection controller and long-press drag selector. + // TODO(mohsen): Remove this workaround when we have enough information about + // the cause of a selection change (see https://crbug.com/571897). + longpress_drag_selector_.OnScrollBeginEvent(); + response_pending_input_event_ = INPUT_EVENT_TYPE_NONE; + if (active_status_ == INACTIVE) { + activate_insertion_automatically_ = false; + activate_selection_automatically_ = false; + } +} + void TouchSelectionController::AllowShowingFromCurrentSelection() { if (active_status_ != INACTIVE) return;
diff --git a/ui/touch_selection/touch_selection_controller.h b/ui/touch_selection/touch_selection_controller.h index f4f0bdf..56f4eb4f 100644 --- a/ui/touch_selection/touch_selection_controller.h +++ b/ui/touch_selection/touch_selection_controller.h
@@ -102,6 +102,10 @@ bool WillHandleLongPressEvent(base::TimeTicks event_time, const gfx::PointF& location); + // To be called before forwarding a gesture scroll begin event to prevent + // long-press drag. + void OnScrollBeginEvent(); + // Allow showing the selection handles from the most recent selection bounds // update (if valid), or a future valid bounds update. void AllowShowingFromCurrentSelection();
diff --git a/ui/touch_selection/touch_selection_controller_unittest.cc b/ui/touch_selection/touch_selection_controller_unittest.cc index d1d4062..8b363cb0 100644 --- a/ui/touch_selection/touch_selection_controller_unittest.cc +++ b/ui/touch_selection/touch_selection_controller_unittest.cc
@@ -1275,6 +1275,46 @@ EXPECT_TRUE(test_controller.GetEndVisible()); } +// When there is a selection on the page and long-press drag is performed +// somewhere that has nothing to select, long-press drag selector should not get +// activated so the page can scroll. +TEST_F(TouchSelectionControllerTest, LongPressDragScroll) { + EnableLongPressDragSelection(); + TouchSelectionControllerTestApi test_controller(&controller()); + + gfx::RectF start_rect(10, 0, 0, 10); + gfx::RectF end_rect(20, 0, 0, 10); + gfx::PointF touch_point(0, 0); + bool visible = true; + MockMotionEvent event; + + // Pre-select something. + ChangeSelection(start_rect, visible, end_rect, visible); + EXPECT_THAT(GetAndResetEvents(), ElementsAre(SELECTION_ESTABLISHED)); + + // Start the touch sequence and perform the long-press out of the existing + // selection. + EXPECT_FALSE(controller().WillHandleTouchEvent( + event.PressPoint(touch_point.x(), touch_point.y()))); + OnLongPressEvent(); + + // Drag down. Selection controller should not consume the touch-move event. + touch_point.Offset(0, 2 * kDefaulTapSlop); + EXPECT_FALSE(controller().WillHandleTouchEvent( + event.MovePoint(0, touch_point.x(), touch_point.y()))); + + // Begin page scroll and update the selection. Selection handles should not be + // shown which means long-press drag selector is not activated. + controller().OnScrollBeginEvent(); + start_rect.Offset(0, 2 * kDefaulTapSlop); + end_rect.Offset(0, 2 * kDefaulTapSlop); + ChangeSelection(start_rect, visible, end_rect, visible); + EXPECT_THAT(GetAndResetEvents(), IsEmpty()); + + // Release the touch sequence. + EXPECT_FALSE(controller().WillHandleTouchEvent(event.ReleasePoint())); +} + TEST_F(TouchSelectionControllerTest, RectBetweenBounds) { gfx::RectF start_rect(5, 5, 0, 10); gfx::RectF end_rect(50, 5, 0, 10);
diff --git a/ui/views/animation/ink_drop_animation_controller_factory_unittest.cc b/ui/views/animation/ink_drop_animation_controller_factory_unittest.cc index eb32904..1743c59 100644 --- a/ui/views/animation/ink_drop_animation_controller_factory_unittest.cc +++ b/ui/views/animation/ink_drop_animation_controller_factory_unittest.cc
@@ -2,13 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef UI_VIEWS_ANIMATION_INK_DROP_ANIMATION_CONTROLLER_FACTORY_UNITTEST_H_ -#define UI_VIEWS_ANIMATION_INK_DROP_ANIMATION_CONTROLLER_FACTORY_UNITTEST_H_ - #include "base/macros.h" #include "base/memory/scoped_ptr.h" #include "testing/gtest/include/gtest/gtest.h" +#include "ui/base/resource/material_design/material_design_controller.h" #include "ui/base/test/material_design_controller_test_api.h" +#include "ui/compositor/scoped_animation_duration_scale_mode.h" #include "ui/views/animation/ink_drop_animation_controller.h" #include "ui/views/animation/ink_drop_animation_controller_factory.h" #include "ui/views/animation/ink_drop_host.h" @@ -17,23 +16,11 @@ namespace views { -// Macro that will execute |test_code| against all derivatives of the -// InkDropAnimationController returned by the InkDropAnimationControllerFactory. -// TODO(bruthig): Refactor these tests to use TEST_P and -// INSTANTIATE_TEST_CASE_P. -#define TEST_ALL_INK_DROPS(test_name, test_code) \ - TEST_F(InkDropAnimationControllerFactoryTest, test_name) \ - test_code TEST_F(MDInkDropAnimationControllerFactoryTest, test_name) test_code - -// Test fixture to test the non material design InkDropAnimationController. -class InkDropAnimationControllerFactoryTest : public testing::Test { +class InkDropAnimationControllerFactoryTest + : public testing::TestWithParam<ui::MaterialDesignController::Mode> { public: - InkDropAnimationControllerFactoryTest() {} - ~InkDropAnimationControllerFactoryTest() override {} - - // testing::Test: - void SetUp() override; - void TearDown() override; + InkDropAnimationControllerFactoryTest(); + ~InkDropAnimationControllerFactoryTest(); protected: // A dummy InkDropHost required to create an InkDropAnimationController. @@ -44,130 +31,102 @@ scoped_ptr<InkDropAnimationController> ink_drop_animation_controller_; private: + scoped_ptr<ui::ScopedAnimationDurationScaleMode> zero_duration_mode_; + DISALLOW_COPY_AND_ASSIGN(InkDropAnimationControllerFactoryTest); }; -void InkDropAnimationControllerFactoryTest::SetUp() { +InkDropAnimationControllerFactoryTest::InkDropAnimationControllerFactoryTest() + : ink_drop_animation_controller_(nullptr) { // Any call by a previous test to MaterialDesignController::GetMode() will // initialize and cache the mode. This ensures that these tests will run from // a non-initialized state. ui::test::MaterialDesignControllerTestAPI::UninitializeMode(); - - ink_drop_animation_controller_ = + ui::test::MaterialDesignControllerTestAPI::SetMode(GetParam()); + ink_drop_animation_controller_.reset( InkDropAnimationControllerFactory::CreateInkDropAnimationController( - &test_ink_drop_host_); + &test_ink_drop_host_) + .release()); + ink_drop_animation_controller_->SetInkDropSize(gfx::Size(10, 10), 4, + gfx::Size(8, 8), 2); + + zero_duration_mode_.reset(new ui::ScopedAnimationDurationScaleMode( + ui::ScopedAnimationDurationScaleMode::ZERO_DURATION)); } -void InkDropAnimationControllerFactoryTest::TearDown() { +InkDropAnimationControllerFactoryTest:: + ~InkDropAnimationControllerFactoryTest() { ui::test::MaterialDesignControllerTestAPI::UninitializeMode(); } -// Test fixture to test the material design InkDropAnimationController. -class MDInkDropAnimationControllerFactoryTest - : public InkDropAnimationControllerFactoryTest { - public: - MDInkDropAnimationControllerFactoryTest() {} +// Note: First argument is optional and intentionally left blank. +// (it's a prefix for the generated test cases) +INSTANTIATE_TEST_CASE_P( + , + InkDropAnimationControllerFactoryTest, + testing::Values(ui::MaterialDesignController::NON_MATERIAL, + ui::MaterialDesignController::MATERIAL_NORMAL)); - // InkDropAnimationControllerFactoryTest: - void SetUp() override; - - private: - DISALLOW_COPY_AND_ASSIGN(MDInkDropAnimationControllerFactoryTest); -}; - -void MDInkDropAnimationControllerFactoryTest::SetUp() { - ui::test::MaterialDesignControllerTestAPI::SetMode( - ui::MaterialDesignController::MATERIAL_NORMAL); - InkDropAnimationControllerFactoryTest::SetUp(); +TEST_P(InkDropAnimationControllerFactoryTest, + VerifyAllInkDropLayersRemovedAfterDestruction) { + ink_drop_animation_controller_->AnimateToState(InkDropState::ACTION_PENDING); + ink_drop_animation_controller_.reset(); + EXPECT_EQ(0, test_ink_drop_host_.num_ink_drop_layers()); } -TEST_ALL_INK_DROPS(VerifyAllInkDropLayersRemovedAfterDestruction, - { - ink_drop_animation_controller_->AnimateToState( - InkDropState::ACTION_PENDING); - ink_drop_animation_controller_.reset(); - EXPECT_EQ(0, test_ink_drop_host_.num_ink_drop_layers()); - }) +TEST_P(InkDropAnimationControllerFactoryTest, StateIsHiddenInitially) { + EXPECT_EQ(InkDropState::HIDDEN, + ink_drop_animation_controller_->GetInkDropState()); +} -TEST_ALL_INK_DROPS(StateIsHiddenInitially, - { - EXPECT_EQ( - InkDropState::HIDDEN, - ink_drop_animation_controller_->GetInkDropState()); - }) +TEST_P(InkDropAnimationControllerFactoryTest, TypicalQuickAction) { + ink_drop_animation_controller_->AnimateToState(InkDropState::ACTION_PENDING); + ink_drop_animation_controller_->AnimateToState(InkDropState::QUICK_ACTION); + EXPECT_EQ(InkDropState::HIDDEN, + ink_drop_animation_controller_->GetInkDropState()); +} -TEST_ALL_INK_DROPS(TypicalQuickAction, - { - ink_drop_animation_controller_->AnimateToState( - InkDropState::ACTION_PENDING); - ink_drop_animation_controller_->AnimateToState( - InkDropState::QUICK_ACTION); - EXPECT_EQ( - InkDropState::HIDDEN, - ink_drop_animation_controller_->GetInkDropState()); - }) +TEST_P(InkDropAnimationControllerFactoryTest, CancelQuickAction) { + ink_drop_animation_controller_->AnimateToState(InkDropState::ACTION_PENDING); + ink_drop_animation_controller_->AnimateToState(InkDropState::HIDDEN); + EXPECT_EQ(InkDropState::HIDDEN, + ink_drop_animation_controller_->GetInkDropState()); +} -TEST_ALL_INK_DROPS(CancelQuickAction, - { - ink_drop_animation_controller_->AnimateToState( - InkDropState::ACTION_PENDING); - ink_drop_animation_controller_->AnimateToState( - InkDropState::HIDDEN); - EXPECT_EQ( - InkDropState::HIDDEN, - ink_drop_animation_controller_->GetInkDropState()); - }) +TEST_P(InkDropAnimationControllerFactoryTest, TypicalSlowAction) { + ink_drop_animation_controller_->AnimateToState(InkDropState::ACTION_PENDING); + ink_drop_animation_controller_->AnimateToState( + InkDropState::SLOW_ACTION_PENDING); + ink_drop_animation_controller_->AnimateToState(InkDropState::SLOW_ACTION); + EXPECT_EQ(InkDropState::HIDDEN, + ink_drop_animation_controller_->GetInkDropState()); +} -TEST_ALL_INK_DROPS(TypicalSlowAction, - { - ink_drop_animation_controller_->AnimateToState( - InkDropState::ACTION_PENDING); - ink_drop_animation_controller_->AnimateToState( - InkDropState::SLOW_ACTION_PENDING); - ink_drop_animation_controller_->AnimateToState( - InkDropState::SLOW_ACTION); - EXPECT_EQ( - InkDropState::HIDDEN, - ink_drop_animation_controller_->GetInkDropState()); - }) +TEST_P(InkDropAnimationControllerFactoryTest, CancelSlowAction) { + ink_drop_animation_controller_->AnimateToState(InkDropState::ACTION_PENDING); + ink_drop_animation_controller_->AnimateToState( + InkDropState::SLOW_ACTION_PENDING); + ink_drop_animation_controller_->AnimateToState(InkDropState::HIDDEN); + EXPECT_EQ(InkDropState::HIDDEN, + ink_drop_animation_controller_->GetInkDropState()); +} -TEST_ALL_INK_DROPS(CancelSlowAction, - { - ink_drop_animation_controller_->AnimateToState( - InkDropState::ACTION_PENDING); - ink_drop_animation_controller_->AnimateToState( - InkDropState::SLOW_ACTION_PENDING); - ink_drop_animation_controller_->AnimateToState( - InkDropState::HIDDEN); - EXPECT_EQ( - InkDropState::HIDDEN, - ink_drop_animation_controller_->GetInkDropState()); - }) +TEST_P(InkDropAnimationControllerFactoryTest, TypicalQuickActivated) { + ink_drop_animation_controller_->AnimateToState(InkDropState::ACTION_PENDING); + ink_drop_animation_controller_->AnimateToState(InkDropState::ACTIVATED); + ink_drop_animation_controller_->AnimateToState(InkDropState::DEACTIVATED); + EXPECT_EQ(InkDropState::HIDDEN, + ink_drop_animation_controller_->GetInkDropState()); +} -TEST_ALL_INK_DROPS( - TypicalQuickActivated, - { - ink_drop_animation_controller_->AnimateToState( - InkDropState::ACTION_PENDING); - ink_drop_animation_controller_->AnimateToState(InkDropState::ACTIVATED); - ink_drop_animation_controller_->AnimateToState(InkDropState::DEACTIVATED); - EXPECT_EQ(InkDropState::HIDDEN, - ink_drop_animation_controller_->GetInkDropState()); - }) - -TEST_ALL_INK_DROPS( - TypicalSlowActivated, - { - ink_drop_animation_controller_->AnimateToState( - InkDropState::ACTION_PENDING); - ink_drop_animation_controller_->AnimateToState( - InkDropState::SLOW_ACTION_PENDING); - ink_drop_animation_controller_->AnimateToState(InkDropState::ACTIVATED); - ink_drop_animation_controller_->AnimateToState(InkDropState::DEACTIVATED); - EXPECT_EQ(InkDropState::HIDDEN, - ink_drop_animation_controller_->GetInkDropState()); - }) +TEST_P(InkDropAnimationControllerFactoryTest, TypicalSlowActivated) { + ink_drop_animation_controller_->AnimateToState(InkDropState::ACTION_PENDING); + ink_drop_animation_controller_->AnimateToState( + InkDropState::SLOW_ACTION_PENDING); + ink_drop_animation_controller_->AnimateToState(InkDropState::ACTIVATED); + ink_drop_animation_controller_->AnimateToState(InkDropState::DEACTIVATED); + EXPECT_EQ(InkDropState::HIDDEN, + ink_drop_animation_controller_->GetInkDropState()); +} } // namespace views - -#endif // UI_VIEWS_ANIMATION_INK_DROP_ANIMATION_CONTROLLER_FACTORY_UNITTEST_H_
diff --git a/ui/views/cocoa/bridged_content_view.mm b/ui/views/cocoa/bridged_content_view.mm index 2167561..2dd3851 100644 --- a/ui/views/cocoa/bridged_content_view.mm +++ b/ui/views/cocoa/bridged_content_view.mm
@@ -122,7 +122,8 @@ } - (void)clearView { - hostedView_ = NULL; + textInputClient_ = nullptr; + hostedView_ = nullptr; [cursorTrackingArea_.get() clearOwner]; [self removeTrackingArea:cursorTrackingArea_.get()]; } @@ -329,8 +330,10 @@ } - (NSTextInputContext*)inputContext { - if (!hostedView_) - return [super inputContext]; + // If the textInputClient_ does not exist, return nil since this view does not + // conform to NSTextInputClient protocol. + if (!textInputClient_) + return nil; // If a menu is active, and -[NSView interpretKeyEvents:] asks for the // input context, return nil. This ensures the action message is sent to @@ -339,7 +342,17 @@ if (menuController && menuController->owner() == hostedView_->GetWidget()) return nil; - return [super inputContext]; + // When not in an editable mode, or while entering passwords + // (http://crbug.com/23219), we don't want to show IME candidate windows. + // Returning nil prevents this view from getting messages defined as part of + // the NSTextInputClient protocol. + switch (textInputClient_->GetTextInputType()) { + case ui::TEXT_INPUT_TYPE_NONE: + case ui::TEXT_INPUT_TYPE_PASSWORD: + return nil; + default: + return [super inputContext]; + } } // NSResponder implementation.
diff --git a/ui/views/cocoa/bridged_native_widget_unittest.mm b/ui/views/cocoa/bridged_native_widget_unittest.mm index b1a43ec..56f911c 100644 --- a/ui/views/cocoa/bridged_native_widget_unittest.mm +++ b/ui/views/cocoa/bridged_native_widget_unittest.mm
@@ -145,8 +145,13 @@ BridgedNativeWidgetTest(); ~BridgedNativeWidgetTest() override; - // Install a textfield in the view hierarchy and make it the text input - // client. + // Install a textfield with input type |text_input_type| in the view hierarchy + // and make it the text input client. + void InstallTextField(const std::string& text, + ui::TextInputType text_input_type); + + // Install a textfield with input type ui::TEXT_INPUT_TYPE_TEXT in the view + // hierarchy and make it the text input client. void InstallTextField(const std::string& text); // Returns the current text as std::string. @@ -172,9 +177,13 @@ BridgedNativeWidgetTest::~BridgedNativeWidgetTest() { } -void BridgedNativeWidgetTest::InstallTextField(const std::string& text) { +void BridgedNativeWidgetTest::InstallTextField( + const std::string& text, + ui::TextInputType text_input_type) { Textfield* textfield = new Textfield(); textfield->SetText(ASCIIToUTF16(text)); + textfield->SetTextInputType(text_input_type); + view_->RemoveAllChildViews(true); view_->AddChildView(textfield); // Request focus so the InputMethod can dispatch events to the RootView, and @@ -185,6 +194,10 @@ [ns_view_ setTextInputClient:textfield]; } +void BridgedNativeWidgetTest::InstallTextField(const std::string& text) { + InstallTextField(text, ui::TEXT_INPUT_TYPE_TEXT); +} + std::string BridgedNativeWidgetTest::GetText() { NSRange range = NSMakeRange(0, NSUIntegerMax); NSAttributedString* text = @@ -349,6 +362,20 @@ widget_.reset(); } +// Ensure a nil NSTextInputContext is returned when the ui::TextInputClient is +// not editable, a password field, or unset. +TEST_F(BridgedNativeWidgetTest, InputContext) { + const std::string test_string = "test_str"; + InstallTextField(test_string, ui::TEXT_INPUT_TYPE_PASSWORD); + EXPECT_FALSE([ns_view_ inputContext]); + InstallTextField(test_string, ui::TEXT_INPUT_TYPE_TEXT); + EXPECT_TRUE([ns_view_ inputContext]); + [ns_view_ setTextInputClient:nil]; + EXPECT_FALSE([ns_view_ inputContext]); + InstallTextField(test_string, ui::TEXT_INPUT_TYPE_NONE); + EXPECT_FALSE([ns_view_ inputContext]); +} + // Test getting complete string using text input protocol. TEST_F(BridgedNativeWidgetTest, TextInput_GetCompleteString) { const std::string kTestString = "foo bar baz";
diff --git a/ui/views/controls/menu/menu_controller.cc b/ui/views/controls/menu/menu_controller.cc index cae826f..3e279d9 100644 --- a/ui/views/controls/menu/menu_controller.cc +++ b/ui/views/controls/menu/menu_controller.cc
@@ -865,7 +865,7 @@ ui::KeyboardCode key_code) { if (exit_type() == MenuController::EXIT_ALL || exit_type() == MenuController::EXIT_DESTROYED) { - TerminateNestedMessageLoop(); + TerminateNestedMessageLoopIfNecessary(); return ui::POST_DISPATCH_PERFORM_DEFAULT; } @@ -874,8 +874,7 @@ else OnKeyDown(key_code); - if (exit_type() != MenuController::EXIT_NONE) - TerminateNestedMessageLoop(); + TerminateNestedMessageLoopIfNecessary(); return ui::POST_DISPATCH_NONE; } @@ -2406,16 +2405,16 @@ // the next native message. We quite the nested message loop as soon as // possible to avoid having deleted views classes (such as widgets and // rootviews) on the stack when the nested message loop stops. - // - // It's safe to invoke QuitNestedMessageLoop() multiple times, it only effects - // the current loop. - bool quit_now = exit_type_ != EXIT_NONE && message_loop_depth_; - if (quit_now) - TerminateNestedMessageLoop(); + TerminateNestedMessageLoopIfNecessary(); } -void MenuController::TerminateNestedMessageLoop() { - message_loop_->QuitNow(); +bool MenuController::TerminateNestedMessageLoopIfNecessary() { + // It is necessary to check both |async_run_| and |message_loop_depth_| + // because the topmost async menu could be nested in a sync parent menu. + bool quit_now = !async_run_ && exit_type_ != EXIT_NONE && message_loop_depth_; + if (quit_now) + message_loop_->QuitNow(); + return quit_now; } MenuItemView* MenuController::ExitMenuRun() { @@ -2485,10 +2484,8 @@ // Set exit_all_, which makes sure all nested loops exit immediately. if (exit_type_ != EXIT_DESTROYED) SetExitType(EXIT_ALL); - } else if (exit_type_ != EXIT_NONE && message_loop_depth_) { - // If we're closing all menus, also mark the next topmost menu - // message loop for termination, so that we'll unwind fully. - TerminateNestedMessageLoop(); + } else { + TerminateNestedMessageLoopIfNecessary(); } }
diff --git a/ui/views/controls/menu/menu_controller.h b/ui/views/controls/menu/menu_controller.h index b550ad7..c04fb57d 100644 --- a/ui/views/controls/menu/menu_controller.h +++ b/ui/views/controls/menu/menu_controller.h
@@ -539,8 +539,9 @@ // Sets exit type. Calling this can terminate the active nested message-loop. void SetExitType(ExitType type); - // Terminates the current nested message-loop. - void TerminateNestedMessageLoop(); + // Terminates the current nested message-loop, if there is any. Returns |true| + // if any message loop is terminated. + bool TerminateNestedMessageLoopIfNecessary(); // Performs the teardown of the menu launched by Run(). The selected item is // returned.
diff --git a/ui/views/controls/menu/menu_controller_unittest.cc b/ui/views/controls/menu/menu_controller_unittest.cc index f611988..32dcccb 100644 --- a/ui/views/controls/menu/menu_controller_unittest.cc +++ b/ui/views/controls/menu/menu_controller_unittest.cc
@@ -15,9 +15,14 @@ #include "ui/views/controls/menu/menu_controller_delegate.h" #include "ui/views/controls/menu/menu_delegate.h" #include "ui/views/controls/menu/menu_item_view.h" +#include "ui/views/controls/menu/menu_message_loop.h" #include "ui/views/controls/menu/submenu_view.h" #include "ui/views/test/views_test_base.h" +#if defined(OS_WIN) +#include "ui/views/widget/desktop_aura/desktop_dispatcher_client.h" +#endif + #if defined(USE_AURA) #include "ui/aura/scoped_window_targeter.h" #include "ui/aura/window.h" @@ -124,6 +129,52 @@ DISALLOW_COPY_AND_ASSIGN(TestEventHandler); }; +// A wrapper around MenuMessageLoop that can be used to track whether a message +// loop is running or not. +class TestMenuMessageLoop : public MenuMessageLoop { + public: + explicit TestMenuMessageLoop(scoped_ptr<MenuMessageLoop> original); + ~TestMenuMessageLoop() override; + + bool is_running() const { return is_running_; } + + private: + // MenuMessageLoop: + void Run(MenuController* controller, + Widget* owner, + bool nested_menu) override; + void QuitNow() override; + void ClearOwner() override; + + scoped_ptr<MenuMessageLoop> original_; + bool is_running_; + + DISALLOW_COPY_AND_ASSIGN(TestMenuMessageLoop); +}; + +TestMenuMessageLoop::TestMenuMessageLoop(scoped_ptr<MenuMessageLoop> original) + : original_(std::move(original)) { + DCHECK(original_); +} + +TestMenuMessageLoop::~TestMenuMessageLoop() {} + +void TestMenuMessageLoop::Run(MenuController* controller, + Widget* owner, + bool nested_menu) { + is_running_ = true; + original_->Run(controller, owner, nested_menu); +} + +void TestMenuMessageLoop::QuitNow() { + is_running_ = false; + original_->QuitNow(); +} + +void TestMenuMessageLoop::ClearOwner() { + original_->ClearOwner(); +} + } // namespace class TestMenuItemViewShown : public MenuItemView { @@ -191,6 +242,55 @@ } #endif // defined(OS_LINUX) && defined(USE_X11) + void TestAsynchronousNestedExitAll() { + ASSERT_TRUE(test_message_loop_->is_running()); + + scoped_ptr<TestMenuControllerDelegate> nested_delegate( + new TestMenuControllerDelegate()); + + menu_controller()->AddNestedDelegate(nested_delegate.get()); + menu_controller()->SetAsyncRun(true); + + int mouse_event_flags = 0; + MenuItemView* run_result = menu_controller()->Run( + owner(), nullptr, menu_item(), gfx::Rect(), MENU_ANCHOR_TOPLEFT, false, + false, &mouse_event_flags); + EXPECT_EQ(run_result, nullptr); + + // Exit all menus and check that the parent menu's message loop is + // terminated. + menu_controller()->Cancel(MenuController::EXIT_ALL); + EXPECT_EQ(MenuController::EXIT_ALL, menu_controller()->exit_type()); + EXPECT_FALSE(test_message_loop_->is_running()); + } + + void TestAsynchronousNestedExitOutermost() { + ASSERT_TRUE(test_message_loop_->is_running()); + + scoped_ptr<TestMenuControllerDelegate> nested_delegate( + new TestMenuControllerDelegate()); + + menu_controller()->AddNestedDelegate(nested_delegate.get()); + menu_controller()->SetAsyncRun(true); + + int mouse_event_flags = 0; + MenuItemView* run_result = menu_controller()->Run( + owner(), nullptr, menu_item(), gfx::Rect(), MENU_ANCHOR_TOPLEFT, false, + false, &mouse_event_flags); + EXPECT_EQ(run_result, nullptr); + + // Exit the nested menu and check that the parent menu's message loop is + // still running. + menu_controller()->Cancel(MenuController::EXIT_OUTERMOST); + EXPECT_EQ(MenuController::EXIT_NONE, menu_controller()->exit_type()); + EXPECT_TRUE(test_message_loop_->is_running()); + + // Now, exit the parent menu and check that its message loop is terminated. + menu_controller()->Cancel(MenuController::EXIT_OUTERMOST); + EXPECT_EQ(MenuController::EXIT_OUTERMOST, menu_controller()->exit_type()); + EXPECT_FALSE(test_message_loop_->is_running()); + } + protected: void SetPendingStateItem(MenuItemView* item) { menu_controller_->pending_state_.item = item; @@ -252,13 +352,21 @@ } void RunMenu() { + menu_controller_->message_loop_depth_++; menu_controller_->RunMessageLoop(false); + menu_controller_->message_loop_depth_--; } void Accept(MenuItemView* item, int event_flags) { menu_controller_->Accept(item, event_flags); } + void InstallTestMenuMessageLoop() { + test_message_loop_ = + new TestMenuMessageLoop(std::move(menu_controller_->message_loop_)); + menu_controller_->message_loop_.reset(test_message_loop_); + } + Widget* owner() { return owner_.get(); } ui::test::EventGenerator* event_generator() { return event_generator_.get(); } TestMenuItemViewShown* menu_item() { return menu_item_.get(); } @@ -283,6 +391,12 @@ new ui::test::EventGenerator(GetContext(), owner_->GetNativeWindow())); owner_->Show(); +#if defined(OS_WIN) + dispatcher_client_.reset(new DesktopDispatcherClient); + aura::client::SetDispatcherClient(owner_->GetNativeView()->GetRootWindow(), + dispatcher_client_.get()); +#endif + SetupMenuItem(); SetupMenuController(); @@ -308,12 +422,17 @@ menu_item_->SetController(menu_controller_); } +#if defined(OS_WIN) + scoped_ptr<aura::client::DispatcherClient> dispatcher_client_; +#endif + scoped_ptr<Widget> owner_; scoped_ptr<ui::test::EventGenerator> event_generator_; scoped_ptr<TestMenuItemViewShown> menu_item_; scoped_ptr<TestMenuControllerDelegate> menu_controller_delegate_; scoped_ptr<MenuDelegate> menu_delegate_; MenuController* menu_controller_; + TestMenuMessageLoop* test_message_loop_; DISALLOW_COPY_AND_ASSIGN(MenuControllerTest); }; @@ -602,5 +721,31 @@ EXPECT_EQ(MenuController::EXIT_ALL, controller->exit_type()); } +// Tests that if you exit all menus when an asynchrnous menu is nested within a +// synchronous menu, the message loop for the parent menu finishes running. +TEST_F(MenuControllerTest, AsynchronousNestedExitAll) { + InstallTestMenuMessageLoop(); + + base::MessageLoopForUI::current()->PostTask( + FROM_HERE, base::Bind(&MenuControllerTest::TestAsynchronousNestedExitAll, + base::Unretained(this))); + + RunMenu(); +} + +// Tests that if you exit the nested menu when an asynchrnous menu is nested +// within a synchronous menu, the message loop for the parent menu remains +// running. +TEST_F(MenuControllerTest, AsynchronousNestedExitOutermost) { + InstallTestMenuMessageLoop(); + + base::MessageLoopForUI::current()->PostTask( + FROM_HERE, + base::Bind(&MenuControllerTest::TestAsynchronousNestedExitOutermost, + base::Unretained(this))); + + RunMenu(); +} + } // namespace test } // namespace views
diff --git a/ui/views/controls/menu/menu_event_dispatcher.cc b/ui/views/controls/menu/menu_event_dispatcher.cc index 2211c02..9b7c231 100644 --- a/ui/views/controls/menu/menu_event_dispatcher.cc +++ b/ui/views/controls/menu/menu_event_dispatcher.cc
@@ -79,8 +79,7 @@ } } - if (menu_controller_->exit_type() != MenuController::EXIT_NONE) - menu_controller_->TerminateNestedMessageLoop(); + menu_controller_->TerminateNestedMessageLoopIfNecessary(); return should_perform_default ? ui::POST_DISPATCH_PERFORM_DEFAULT : ui::POST_DISPATCH_NONE;
diff --git a/ui/views/controls/menu/menu_key_event_handler.cc b/ui/views/controls/menu/menu_key_event_handler.cc index 204153f5d..fc110b5 100644 --- a/ui/views/controls/menu/menu_key_event_handler.cc +++ b/ui/views/controls/menu/menu_key_event_handler.cc
@@ -41,7 +41,7 @@ // not quit till the action's base::RunLoop ends. IDC_BOOKMARK_BAR_OPEN_ALL // sometimes opens a modal dialog. The modal dialog starts a base::RunLoop // and keeps the base::RunLoop running for the duration of its lifetime. - menu_controller->TerminateNestedMessageLoop(); + menu_controller->TerminateNestedMessageLoopIfNecessary(); return; } @@ -58,9 +58,7 @@ } } - if (menu_controller->exit_type() != MenuController::EXIT_NONE) { - menu_controller->TerminateNestedMessageLoop(); - } else { + if (!menu_controller->TerminateNestedMessageLoopIfNecessary()) { ui::Accelerator accelerator(*event); ViewsDelegate::ProcessMenuAcceleratorResult result = ViewsDelegate::GetInstance()->ProcessAcceleratorWhileMenuShowing(
diff --git a/ui/views/controls/menu/menu_message_pump_dispatcher_win.cc b/ui/views/controls/menu/menu_message_pump_dispatcher_win.cc index b7f5b37..fedb10e 100644 --- a/ui/views/controls/menu/menu_message_pump_dispatcher_win.cc +++ b/ui/views/controls/menu/menu_message_pump_dispatcher_win.cc
@@ -23,12 +23,9 @@ uint32_t MenuMessagePumpDispatcher::Dispatch(const MSG& msg) { DCHECK(menu_controller_->IsBlockingRun()); - bool should_quit = false; bool should_perform_default = true; - if (menu_controller_->exit_type() == MenuController::EXIT_ALL || - menu_controller_->exit_type() == MenuController::EXIT_DESTROYED) { - should_quit = true; - } else { + if (menu_controller_->exit_type() != MenuController::EXIT_ALL && + menu_controller_->exit_type() != MenuController::EXIT_DESTROYED) { // NOTE: we don't get WM_ACTIVATE or anything else interesting in here. switch (msg.message) { case WM_CONTEXTMENU: { @@ -71,7 +68,6 @@ case WM_SYSKEYDOWN: // Exit immediately on system keys. menu_controller_->Cancel(MenuController::EXIT_ALL); - should_quit = true; should_perform_default = false; break; @@ -80,8 +76,7 @@ } } - if (should_quit || menu_controller_->exit_type() != MenuController::EXIT_NONE) - menu_controller_->TerminateNestedMessageLoop(); + menu_controller_->TerminateNestedMessageLoopIfNecessary(); return should_perform_default ? POST_DISPATCH_PERFORM_DEFAULT : POST_DISPATCH_NONE; }
diff --git a/ui/views/mus/window_manager_connection.cc b/ui/views/mus/window_manager_connection.cc index d4bceb6..6fa8370 100644 --- a/ui/views/mus/window_manager_connection.cc +++ b/ui/views/mus/window_manager_connection.cc
@@ -122,8 +122,8 @@ mus::WindowTreeConnection::Create( this, std::move(window_tree_client_request), mus::WindowTreeConnection::CreateType::WAIT_FOR_EMBED); - DCHECK(window_tree_connection->GetRoot()); - return window_tree_connection->GetRoot(); + DCHECK_EQ(1u, window_tree_connection->GetRoots().size()); + return *window_tree_connection->GetRoots().begin(); } WindowManagerConnection::WindowManagerConnection(mojo::ApplicationImpl* app)
diff --git a/ui/views/view.cc b/ui/views/view.cc index fc2d03ec..375cff4 100644 --- a/ui/views/view.cc +++ b/ui/views/view.cc
@@ -1769,6 +1769,14 @@ } } +void View::SchedulePaintOnParent() { + if (parent_) { + // Translate the requested paint rect to the parent's coordinate system + // then pass this notification up to the parent. + parent_->SchedulePaintInRect(ConvertRectToParent(GetLocalBounds())); + } +} + // Tree operations ------------------------------------------------------------- void View::DoRemoveChildView(View* view, @@ -2082,6 +2090,12 @@ Widget* widget = GetWidget(); if (widget) widget->UpdateRootLayers(); + + // Before having its own Layer, this View may have painted in to a Layer owned + // by an ancestor View. Scheduling a paint on the parent View will erase this + // View's painting effects on the ancestor View's Layer. + // (See crbug.com/551492) + SchedulePaintOnParent(); } void View::UpdateParentLayers() {
diff --git a/ui/views/view.h b/ui/views/view.h index a6248de..12ed0f10 100644 --- a/ui/views/view.h +++ b/ui/views/view.h
@@ -1223,6 +1223,7 @@ friend class internal::PostEventDispatchHandler; friend class internal::RootView; friend class FocusManager; + friend class ViewLayerTest; friend class Widget; // Painting ----------------------------------------------------------------- @@ -1239,6 +1240,9 @@ // new bounds. void SchedulePaintBoundsChanged(SchedulePaintType type); + // Schedules a paint on the parent View if it exists. + void SchedulePaintOnParent(); + // Tree operations ----------------------------------------------------------- // Removes |view| from the hierarchy tree. If |update_focus_cycle| is true,
diff --git a/ui/views/view_unittest.cc b/ui/views/view_unittest.cc index 4ea748e..68675c0 100644 --- a/ui/views/view_unittest.cc +++ b/ui/views/view_unittest.cc
@@ -3596,6 +3596,10 @@ Widget* widget() { return widget_; } + protected: + // Accessors to View internals. + void SchedulePaintOnParent(View* view) { view->SchedulePaintOnParent(); } + private: Widget* widget_; }; @@ -3988,6 +3992,50 @@ EXPECT_TRUE(content_view->painted()); } +TEST_F(ViewLayerTest, NoCrashWhenParentlessViewSchedulesPaintOnParent) { + TestView v; + SchedulePaintOnParent(&v); +} + +TEST_F(ViewLayerTest, ScheduledRectsInParentAfterSchedulingPaint) { + TestView parent_view; + parent_view.SetBounds(10, 10, 100, 100); + + TestView* child_view = new TestView; + child_view->SetBounds(5, 6, 10, 20); + parent_view.AddChildView(child_view); + + parent_view.scheduled_paint_rects_.clear(); + SchedulePaintOnParent(child_view); + ASSERT_EQ(1U, parent_view.scheduled_paint_rects_.size()); + EXPECT_EQ(gfx::Rect(5, 6, 10, 20), + parent_view.scheduled_paint_rects_.front()); +} + +TEST_F(ViewLayerTest, ParentPaintWhenSwitchingPaintToLayerFromFalseToTrue) { + TestView parent_view; + parent_view.SetBounds(10, 11, 12, 13); + + TestView* child_view = new TestView; + parent_view.AddChildView(child_view); + + parent_view.scheduled_paint_rects_.clear(); + child_view->SetPaintToLayer(true); + EXPECT_EQ(1U, parent_view.scheduled_paint_rects_.size()); +} + +TEST_F(ViewLayerTest, NoParentPaintWhenSwitchingPaintToLayerFromTrueToTrue) { + TestView parent_view; + parent_view.SetBounds(10, 11, 12, 13); + + TestView* child_view = new TestView; + child_view->SetPaintToLayer(true); + parent_view.AddChildView(child_view); + + parent_view.scheduled_paint_rects_.clear(); + EXPECT_EQ(0U, parent_view.scheduled_paint_rects_.size()); +} + // Tests that the visibility of child layers are updated correctly when a View's // visibility changes. TEST_F(ViewLayerTest, VisibilityChildLayers) {
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc index d3aafd9d..f7495f0a 100644 --- a/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc +++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc
@@ -1116,6 +1116,10 @@ window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_NORMAL"); break; } + // An in-activatable window should not interact with the system wm. + if (!activatable_) + swa.override_redirect = True; + if (swa.override_redirect) attribute_mask |= CWOverrideRedirect;
diff --git a/ui/views/widget/widget.cc b/ui/views/widget/widget.cc index aaa9320..04c9011b 100644 --- a/ui/views/widget/widget.cc +++ b/ui/views/widget/widget.cc
@@ -1449,9 +1449,16 @@ } } else { if (bounds.IsEmpty()) { - // No initial bounds supplied, so size the window to its content and - // center over its parent. - native_widget_->CenterWindow(non_client_view_->GetPreferredSize()); + if (bounds.origin().IsOrigin()) { + // No initial bounds supplied, so size the window to its content and + // center over its parent. + native_widget_->CenterWindow(non_client_view_->GetPreferredSize()); + } else { + // Use the preferred size and the supplied origin. + gfx::Rect preferred_bounds(bounds); + preferred_bounds.set_size(non_client_view_->GetPreferredSize()); + SetBoundsConstrained(preferred_bounds); + } } else { // Use the supplied initial bounds. SetBoundsConstrained(bounds);
diff --git a/ui/webui/resources/js/load_time_data.js b/ui/webui/resources/js/load_time_data.js index 42f29fa..4075b62 100644 --- a/ui/webui/resources/js/load_time_data.js +++ b/ui/webui/resources/js/load_time_data.js
@@ -10,7 +10,7 @@ * that must be displayed right away). */ -var loadTimeData; +/** @type {!LoadTimeData} */ var loadTimeData; // Expose this type globally as a temporary work around until // https://github.com/google/closure-compiler/issues/544 is fixed. @@ -78,8 +78,8 @@ * Returns a formatted localized string where $1 to $9 are replaced by the * second to the tenth argument. * @param {string} id The ID of the string we want. - * @param {...string} var_args The extra values to include in the formatted - * output. + * @param {...(string|number)} var_args The extra values to include in the + * formatted output. * @return {string} The formatted string. */ getStringF: function(id, var_args) {
diff --git a/url/BUILD.gn b/url/BUILD.gn index 2f3678c..5c5b3ba 100644 --- a/url/BUILD.gn +++ b/url/BUILD.gn
@@ -72,6 +72,13 @@ } if (is_android) { + android_library("url_java") { + DEPRECATED_java_in_dir = "android/java/src" + deps = [ + "//base:base_java", + ] + } + generate_jni("url_jni_headers") { sources = [ "android/java/src/org/chromium/url/IDNStringUtil.java", @@ -98,6 +105,7 @@ ] deps = [ + ":url_java", ":url_jni_headers", "//base", "//base/third_party/dynamic_annotations",