diff --git a/AUTHORS b/AUTHORS index 712cbde..233d94eb 100644 --- a/AUTHORS +++ b/AUTHORS
@@ -671,6 +671,7 @@ Sujae Jo <sujae33.jo@gmail.com> Sujith S S <sujiths.s@samsung.com> Sungguk Lim <limasdf@gmail.com> +Sunghoon Kim <shoon.kim@lge.com> Sungmann Cho <sungmann.cho@gmail.com> Sungmann Cho <sungmann.cho@navercorp.com> Sunitha Srivatsa <srivats@amazon.com>
diff --git a/DEPS b/DEPS index ab1b1e2e..923ce45 100644 --- a/DEPS +++ b/DEPS
@@ -44,7 +44,7 @@ # 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': 'ffd7660a65e8470bf7df9141d281d75dcb359c45', + 'v8_revision': '783b1c5d041c3c612c5193a45937c060a32cc0d0', # 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. @@ -96,7 +96,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling catapult # and whatever else without interference from each other. - 'catapult_revision': '95b3e83b284d07b44518378ad795f15287249b19', + 'catapult_revision': '201f910a0958c2c25481dc011616aada3df330d9', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libFuzzer # and whatever else without interference from each other. @@ -228,7 +228,7 @@ Var('chromium_git') + '/native_client/src/third_party/scons-2.0.1.git' + '@' + '1c1550e17fc26355d08627fbdec13d8291227067', 'src/third_party/webrtc': - Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + '1638114289eca6e17cc412205c2970b2f6c98280', # commit position 16045 + Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + 'cda50c31ad6f31dfaa8568f6e23037dabb6b19e5', # commit position 16087 'src/third_party/openmax_dl': Var('chromium_git') + '/external/webrtc/deps/third_party/openmax.git' + '@' + Var('openmax_dl_revision'),
diff --git a/chrome/android/java/res/drawable-hdpi/ntp_signin_promo_card_bottom.9.png b/chrome/android/java/res/drawable-hdpi/ntp_signin_promo_card_bottom.9.png deleted file mode 100644 index ea17ae5..0000000 --- a/chrome/android/java/res/drawable-hdpi/ntp_signin_promo_card_bottom.9.png +++ /dev/null Binary files differ
diff --git a/chrome/android/java/res/drawable-mdpi/ntp_signin_promo_card_bottom.9.png b/chrome/android/java/res/drawable-mdpi/ntp_signin_promo_card_bottom.9.png deleted file mode 100644 index 191f356..0000000 --- a/chrome/android/java/res/drawable-mdpi/ntp_signin_promo_card_bottom.9.png +++ /dev/null Binary files differ
diff --git a/chrome/android/java/res/drawable-xhdpi/ntp_signin_promo_card_bottom.9.png b/chrome/android/java/res/drawable-xhdpi/ntp_signin_promo_card_bottom.9.png deleted file mode 100644 index 566a5cc..0000000 --- a/chrome/android/java/res/drawable-xhdpi/ntp_signin_promo_card_bottom.9.png +++ /dev/null Binary files differ
diff --git a/chrome/android/java/res/drawable-xxhdpi/ntp_signin_promo_card_bottom.9.png b/chrome/android/java/res/drawable-xxhdpi/ntp_signin_promo_card_bottom.9.png deleted file mode 100644 index 05c5152..0000000 --- a/chrome/android/java/res/drawable-xxhdpi/ntp_signin_promo_card_bottom.9.png +++ /dev/null Binary files differ
diff --git a/chrome/android/java/res/drawable-xxxhdpi/ntp_signin_promo_card_bottom.9.png b/chrome/android/java/res/drawable-xxxhdpi/ntp_signin_promo_card_bottom.9.png deleted file mode 100644 index 9bef7de..0000000 --- a/chrome/android/java/res/drawable-xxxhdpi/ntp_signin_promo_card_bottom.9.png +++ /dev/null Binary files differ
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/ui/MediaImageManager.java b/chrome/android/java/src/org/chromium/chrome/browser/media/ui/MediaImageManager.java index bd45b9d..444be22d 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/media/ui/MediaImageManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/media/ui/MediaImageManager.java
@@ -80,7 +80,7 @@ // The last image src for download, used for avoiding fetching the same src when artwork is set // multiple times but the same src is chosen. // - // Will be reset when initiating a new download request, and set to |null| when download failed. + // Will be reset when initiating a new download request. private String mLastImageSrc; /** @@ -134,7 +134,9 @@ mCallback = callback; MediaImage image = selectImage(images); if (image == null) { - onDownloadFailed(); + mLastImageSrc = null; + mCallback.onImageDownloaded(null); + clearRequests(); return; } @@ -178,12 +180,8 @@ bestScore = newScore; } } - if (bestBitmap != null) { - mCallback.onImageDownloaded(bestBitmap); - clearRequests(); - } else { - onDownloadFailed(); - } + mCallback.onImageDownloaded(bestBitmap); + clearRequests(); } /** @@ -210,12 +208,6 @@ mCallback = null; } - private void onDownloadFailed() { - mLastImageSrc = null; - mCallback.onImageDownloaded(null); - clearRequests(); - } - private double getImageScore(MediaImage image) { if (image == null) return 0; if (image.getSizes().isEmpty()) return DEFAULT_IMAGE_SIZE_SCORE;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/CardViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/CardViewHolder.java index e29abda9..41b37ca 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/CardViewHolder.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/CardViewHolder.java
@@ -171,8 +171,13 @@ int abovePosition = getAdapterPosition() - 1; boolean hasCardAbove = abovePosition >= 0 && isCard(adapter.getItemViewType(abovePosition)); int belowPosition = getAdapterPosition() + 1; - boolean hasCardBelow = belowPosition < adapter.getItemCount() - && isCard(adapter.getItemViewType(belowPosition)); + boolean hasCardBelow = false; + if (belowPosition < adapter.getItemCount()) { + // The PROMO card has an empty margin and will not be right against the preceding card, + // so we don't consider it a card from the point of view of the preceding one. + @ItemViewType int belowViewType = adapter.getItemViewType(belowPosition); + hasCardBelow = isCard(belowViewType) && belowViewType != ItemViewType.PROMO; + } getParams().bottomMargin = hasCardBelow ? -mCards9PatchAdjustment : 0;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SignInPromo.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SignInPromo.java index 15a6ffe..0a31854 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SignInPromo.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SignInPromo.java
@@ -8,7 +8,6 @@ import android.support.annotation.DrawableRes; import android.support.annotation.Nullable; import android.support.annotation.StringRes; -import android.support.v7.widget.RecyclerView; import org.chromium.base.Callback; import org.chromium.base.ContextUtils; @@ -176,46 +175,21 @@ * View Holder for {@link SignInPromo}. */ public static class ViewHolder extends StatusCardViewHolder { - private final int mSeparationSpaceSize; public ViewHolder(NewTabPageRecyclerView parent, NewTabPageManager newTabPageManager, UiConfig config) { super(parent, newTabPageManager, config); - mSeparationSpaceSize = parent.getResources().getDimensionPixelSize( + getParams().topMargin = parent.getResources().getDimensionPixelSize( R.dimen.ntp_sign_in_promo_margin_top); } @DrawableRes @Override protected int selectBackground(boolean hasCardAbove, boolean hasCardBelow) { - assert !hasCardBelow; - if (hasCardAbove) return R.drawable.ntp_signin_promo_card_bottom; return R.drawable.ntp_signin_promo_card_single; } @Override - public void updateLayoutParams() { - super.updateLayoutParams(); - - if (getAdapterPosition() == RecyclerView.NO_POSITION) return; - - int precedingPosition = getAdapterPosition() - 1; - if (precedingPosition < 0) return; // Invalid adapter position, just do nothing. - - @ItemViewType - int precedingCardType = - getRecyclerView().getAdapter().getItemViewType(precedingPosition); - - // The sign in promo should stick to the articles of the preceding section, but have - // some space otherwise. - if (precedingCardType != ItemViewType.SNIPPET) { - getParams().topMargin = mSeparationSpaceSize; - } else { - getParams().topMargin = 0; - } - } - - @Override public boolean isDismissable() { return true; }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/media/ui/MediaImageManagerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/media/ui/MediaImageManagerTest.java index 372dd01..ce176cf 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/media/ui/MediaImageManagerTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/media/ui/MediaImageManagerTest.java
@@ -120,6 +120,30 @@ } @Test + public void testDownloadSameImageTwiceButFailed() { + // First download. + mBitmaps.clear(); + mOriginalImageSizes.clear(); + + mMediaImageManager.downloadImage(mImages, mCallback); + mMediaImageManager.onFinishDownloadImage( + REQUEST_ID_1, 404, IMAGE_URL_1, mBitmaps, mOriginalImageSizes); + + // Second download. + mMediaImageManager.downloadImage(mImages, mCallback); + // The second download request will never be initiated and the callback + // will be ignored. + mMediaImageManager.onFinishDownloadImage( + REQUEST_ID_1, 200, IMAGE_URL_1, mBitmaps, mOriginalImageSizes); + + verify(mWebContents, times(1)) + .downloadImage(eq(IMAGE_URL_1), eq(false), + eq(MediaImageManager.MAX_BITMAP_SIZE_FOR_DOWNLOAD), eq(false), + eq(mMediaImageManager)); + verify(mCallback, times(1)).onImageDownloaded(isNull(Bitmap.class)); + } + + @Test public void testDownloadDifferentImagesTwice() { // First download. mMediaImageManager.downloadImage(mImages, mCallback);
diff --git a/chrome/browser/budget_service/budget_database.cc b/chrome/browser/budget_service/budget_database.cc index 28e3f7eb..662c2b94 100644 --- a/chrome/browser/budget_service/budget_database.cc +++ b/chrome/browser/budget_service/budget_database.cc
@@ -27,8 +27,13 @@ const char kDatabaseUMAName[] = "BudgetManager"; // The default amount of time during which a budget will be valid. -// This is 4 days = 96 hours. -constexpr double kBudgetDurationInHours = 96; +constexpr int kBudgetDurationInDays = 4; + +// The amount of budget that a maximally engaged site should receive per hour. +// For context, silent push messages cost 2 each, so this allows 6 silent push +// messages a day for a fully engaged site. See budget_manager.cc for costs of +// various actions. +constexpr double kMaximumHourlyBudget = 12.0 / 24.0; } // namespace @@ -164,8 +169,6 @@ predictions.push_back(std::move(prediction)); } - DCHECK_EQ(0, total); - callback.Run(blink::mojom::BudgetServiceErrorType::NONE, std::move(predictions)); } @@ -304,35 +307,36 @@ } void BudgetDatabase::AddEngagementBudget(const url::Origin& origin) { - // Get the current SES score, which we'll use to set a new budget. - SiteEngagementService* service = SiteEngagementService::Get(profile_); - double score = service->GetScore(origin.GetURL()); - - // By default we award the "full" award. Then that ratio is decreased if - // there have been other awards recently. - double ratio = 1.0; - - // Calculate how much budget should be awarded. If there is no entry in the - // cache then we award a full amount. + // Calculate how much budget should be awarded. The award depends on the + // time elapsed since the last award and the SES score. + // By default, give the origin kBudgetDurationInDays worth of budget, but + // reduce that if budget has already been given during that period. + base::TimeDelta elapsed = base::TimeDelta::FromDays(kBudgetDurationInDays); if (IsCached(origin)) { - base::TimeDelta elapsed = - clock_->Now() - budget_map_[origin].last_engagement_award; - int elapsed_hours = elapsed.InHours(); + elapsed = clock_->Now() - budget_map_[origin].last_engagement_award; // Don't give engagement awards for periods less than an hour. - if (elapsed_hours < 1) + if (elapsed.InHours() < 1) return; - if (elapsed_hours < kBudgetDurationInHours) - ratio = elapsed_hours / kBudgetDurationInHours; + // Cap elapsed time to the budget duration. + if (elapsed.InDays() > kBudgetDurationInDays) + elapsed = base::TimeDelta::FromDays(kBudgetDurationInDays); } + // Get the current SES score, and calculate the hourly budget for that score. + SiteEngagementService* service = SiteEngagementService::Get(profile_); + double hourly_budget = kMaximumHourlyBudget * + service->GetScore(origin.GetURL()) / + service->GetMaxPoints(); + // Update the last_engagement_award to the current time. If the origin wasn't // already in the map, this adds a new entry for it. budget_map_[origin].last_engagement_award = clock_->Now(); // Add a new chunk of budget for the origin at the default expiration time. base::Time expiration = - clock_->Now() + base::TimeDelta::FromHours(kBudgetDurationInHours); - budget_map_[origin].chunks.emplace_back(ratio * score, expiration); + clock_->Now() + base::TimeDelta::FromDays(kBudgetDurationInDays); + budget_map_[origin].chunks.emplace_back(elapsed.InHours() * hourly_budget, + expiration); // Any time we award engagement budget, which is done at most once an hour // whenever any budget action is taken, record the budget. @@ -355,10 +359,10 @@ cleanup_iter = chunks.erase(cleanup_iter); // If the entire budget is empty now AND there have been no engagements - // in the last kBudgetDurationInHours hours, remove this from the cache. + // in the last kBudgetDurationInDays days, remove this from the cache. if (chunks.empty() && budget_map_[origin].last_engagement_award < - clock_->Now() - base::TimeDelta::FromHours(kBudgetDurationInHours)) { + clock_->Now() - base::TimeDelta::FromDays(kBudgetDurationInDays)) { budget_map_.erase(origin); return true; }
diff --git a/chrome/browser/budget_service/budget_database_unittest.cc b/chrome/browser/budget_service/budget_database_unittest.cc index d25c93f..1f942b78 100644 --- a/chrome/browser/budget_service/budget_database_unittest.cc +++ b/chrome/browser/budget_service/budget_database_unittest.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/budget_service/budget_database.h" +#include <math.h> #include <vector> #include "base/memory/ptr_util.h" @@ -12,6 +13,7 @@ #include "base/test/simple_test_clock.h" #include "base/threading/thread_task_runner_handle.h" #include "chrome/browser/budget_service/budget.pb.h" +#include "chrome/browser/engagement/site_engagement_score.h" #include "chrome/browser/engagement/site_engagement_service.h" #include "chrome/test/base/testing_profile.h" #include "components/leveldb_proto/proto_database.h" @@ -24,8 +26,11 @@ namespace { -const double kDefaultExpirationInHours = 96; -const double kDefaultEngagement = 30.0; +// These values mirror the defaults in budget_database.cc +const double kDefaultExpirationInDays = 4; +const double kMaxDailyBudget = 12; + +const double kEngagement = 25; const char kTestOrigin[] = "https://example.com"; @@ -114,16 +119,20 @@ TEST_F(BudgetDatabaseTest, AddEngagementBudgetTest) { base::SimpleTestClock* clock = SetClockForTesting(); base::Time expiration_time = - clock->Now() + base::TimeDelta::FromHours(kDefaultExpirationInHours); + clock->Now() + base::TimeDelta::FromDays(kDefaultExpirationInDays); // Set the default site engagement. - SetSiteEngagementScore(kDefaultEngagement); + SetSiteEngagementScore(kEngagement); - // The budget should include a full share of the engagement. + // The budget should include kDefaultExpirationInDays days worth of + // engagement. + double daily_budget = + kMaxDailyBudget * (kEngagement / SiteEngagementScore::kMaxPoints); GetBudgetDetails(); ASSERT_TRUE(success_); ASSERT_EQ(2U, prediction_.size()); - ASSERT_EQ(kDefaultEngagement, prediction_[0]->budget_at); + ASSERT_DOUBLE_EQ(daily_budget * kDefaultExpirationInDays, + prediction_[0]->budget_at); ASSERT_EQ(0, prediction_[1]->budget_at); ASSERT_EQ(expiration_time.ToDoubleT(), prediction_[1]->time); @@ -134,12 +143,11 @@ // The budget should now have 1 full share plus 1 daily budget. ASSERT_TRUE(success_); ASSERT_EQ(3U, prediction_.size()); - double daily_budget = kDefaultEngagement * 24 / kDefaultExpirationInHours; - ASSERT_DOUBLE_EQ(kDefaultEngagement + daily_budget, + ASSERT_DOUBLE_EQ(daily_budget * (kDefaultExpirationInDays + 1), prediction_[0]->budget_at); ASSERT_DOUBLE_EQ(daily_budget, prediction_[1]->budget_at); ASSERT_EQ(expiration_time.ToDoubleT(), prediction_[1]->time); - ASSERT_EQ(0, prediction_[2]->budget_at); + ASSERT_DOUBLE_EQ(0, prediction_[2]->budget_at); ASSERT_EQ((expiration_time + base::TimeDelta::FromDays(1)).ToDoubleT(), prediction_[2]->time); @@ -151,7 +159,7 @@ // The budget should be the same as before the attempted add. ASSERT_TRUE(success_); ASSERT_EQ(3U, prediction_.size()); - ASSERT_DOUBLE_EQ(kDefaultEngagement + daily_budget, + ASSERT_DOUBLE_EQ(daily_budget * (kDefaultExpirationInDays + 1), prediction_[0]->budget_at); } @@ -159,7 +167,7 @@ base::SimpleTestClock* clock = SetClockForTesting(); // Set the default site engagement. - SetSiteEngagementScore(kDefaultEngagement); + SetSiteEngagementScore(kEngagement); // Intialize the budget with several chunks. GetBudgetDetails(); @@ -168,15 +176,16 @@ clock->Advance(base::TimeDelta::FromDays(1)); GetBudgetDetails(); - // Spend an amount of budget less than kDefaultEngagement. + // Spend an amount of budget less than the daily budget. ASSERT_TRUE(SpendBudget(1)); GetBudgetDetails(); - // There should still be three chunks of budget of size kDefaultEngagement-1, - // kDefaultEngagement, and kDefaultEngagement. + // There should still be three chunks of budget of size daily_budget-1, + // daily_budget, and kDefaultExpirationInDays * daily_budget. + double daily_budget = + kMaxDailyBudget * (kEngagement / SiteEngagementScore::kMaxPoints); ASSERT_EQ(4U, prediction_.size()); - double daily_budget = kDefaultEngagement * 24 / kDefaultExpirationInHours; - ASSERT_DOUBLE_EQ(kDefaultEngagement + 2 * daily_budget - 1, + ASSERT_DOUBLE_EQ((2 + kDefaultExpirationInDays) * daily_budget - 1, prediction_[0]->budget_at); ASSERT_DOUBLE_EQ(daily_budget * 2, prediction_[1]->budget_at); ASSERT_DOUBLE_EQ(daily_budget, prediction_[2]->budget_at); @@ -184,22 +193,22 @@ // Now spend enough that it will use up the rest of the first chunk and all of // the second chunk, but not all of the third chunk. - ASSERT_TRUE(SpendBudget(kDefaultEngagement + daily_budget)); + ASSERT_TRUE(SpendBudget((1 + kDefaultExpirationInDays) * daily_budget)); GetBudgetDetails(); ASSERT_EQ(2U, prediction_.size()); ASSERT_DOUBLE_EQ(daily_budget - 1, prediction_[0]->budget_at); // Validate that the code returns false if SpendBudget tries to spend more // budget than the origin has. - EXPECT_FALSE(SpendBudget(kDefaultEngagement)); + EXPECT_FALSE(SpendBudget(kEngagement)); GetBudgetDetails(); ASSERT_EQ(2U, prediction_.size()); ASSERT_DOUBLE_EQ(daily_budget - 1, prediction_[0]->budget_at); // Advance time until the last remaining chunk should be expired, then query // for the full engagement worth of budget. - clock->Advance(base::TimeDelta::FromHours(kDefaultExpirationInHours + 1)); - EXPECT_TRUE(SpendBudget(kDefaultEngagement)); + clock->Advance(base::TimeDelta::FromDays(kDefaultExpirationInDays + 1)); + EXPECT_TRUE(SpendBudget(daily_budget * kDefaultExpirationInDays)); } // There are times when a device's clock could move backwards in time, either @@ -210,7 +219,7 @@ base::SimpleTestClock* clock = SetClockForTesting(); // Set the default site engagement. - SetSiteEngagementScore(kDefaultEngagement); + SetSiteEngagementScore(kEngagement); // Initialize the budget with two chunks. GetBudgetDetails(); @@ -241,17 +250,17 @@ base::SimpleTestClock* clock = SetClockForTesting(); // Set the default site engagement. - SetSiteEngagementScore(kDefaultEngagement); + SetSiteEngagementScore(kEngagement); // Initialize the budget with some interesting chunks: 30 budget (full // engagement), 15 budget (half of the engagement), 0 budget (less than an // hour), and then after the first two expire, another 30 budget. GetBudgetDetails(); - clock->Advance(base::TimeDelta::FromHours(kDefaultExpirationInHours / 2)); + clock->Advance(base::TimeDelta::FromDays(kDefaultExpirationInDays / 2)); GetBudgetDetails(); clock->Advance(base::TimeDelta::FromMinutes(59)); GetBudgetDetails(); - clock->Advance(base::TimeDelta::FromHours(kDefaultExpirationInHours + 1)); + clock->Advance(base::TimeDelta::FromDays(kDefaultExpirationInDays + 1)); GetBudgetDetails(); // The BackgroundBudget UMA is recorded when budget is added to the origin. @@ -259,20 +268,25 @@ std::vector<base::Bucket> buckets = GetHistogramTester()->GetAllSamples("PushMessaging.BackgroundBudget"); ASSERT_EQ(2U, buckets.size()); - // First bucket is for full engagement, which should have 2 entries. - EXPECT_EQ(kDefaultEngagement, buckets[0].min); + // First bucket is for full award, which should have 2 entries. + double full_award = kMaxDailyBudget * kEngagement / + SiteEngagementScore::kMaxPoints * + kDefaultExpirationInDays; + EXPECT_EQ(floor(full_award), buckets[0].min); EXPECT_EQ(2, buckets[0].count); - // Second bucket is for 1.5 * engagement, which should have 1 entry. - EXPECT_EQ(kDefaultEngagement * 1.5, buckets[1].min); + // Second bucket is for 1.5 * award, which should have 1 entry. + EXPECT_EQ(floor(full_award * 1.5), buckets[1].min); EXPECT_EQ(1, buckets[1].count); } TEST_F(BudgetDatabaseTest, CheckEngagementHistograms) { base::SimpleTestClock* clock = SetClockForTesting(); - // Set the engagement to twice the cost of an action. + // Manipulate the engagement so that the budget is twice the cost of an + // action. double cost = 2; - double engagement = cost * 2; + double engagement = 2 * cost * SiteEngagementScore::kMaxPoints / + kDefaultExpirationInDays / kMaxDailyBudget; SetSiteEngagementScore(engagement); // Get the budget, which will award a chunk of budget equal to engagement. @@ -299,17 +313,17 @@ std::vector<base::Bucket> no_budget_buckets = GetHistogramTester()->GetAllSamples("PushMessaging.SESForNoBudgetOrigin"); ASSERT_EQ(2U, no_budget_buckets.size()); - EXPECT_EQ(engagement, no_budget_buckets[0].min); + EXPECT_EQ(floor(engagement), no_budget_buckets[0].min); EXPECT_EQ(1, no_budget_buckets[0].count); - EXPECT_EQ(engagement * 2, no_budget_buckets[1].min); + EXPECT_EQ(floor(engagement * 2), no_budget_buckets[1].min); EXPECT_EQ(1, no_budget_buckets[1].count); std::vector<base::Bucket> low_budget_buckets = GetHistogramTester()->GetAllSamples( "PushMessaging.SESForLowBudgetOrigin"); ASSERT_EQ(2U, low_budget_buckets.size()); - EXPECT_EQ(engagement, low_budget_buckets[0].min); + EXPECT_EQ(floor(engagement), low_budget_buckets[0].min); EXPECT_EQ(1, low_budget_buckets[0].count); - EXPECT_EQ(engagement * 2, low_budget_buckets[1].min); + EXPECT_EQ(floor(engagement * 2), low_budget_buckets[1].min); EXPECT_EQ(1, low_budget_buckets[1].count); }
diff --git a/chrome/browser/budget_service/budget_manager_browsertest.cc b/chrome/browser/budget_service/budget_manager_browsertest.cc index aef3cd4..299abe21 100644 --- a/chrome/browser/budget_service/budget_manager_browsertest.cc +++ b/chrome/browser/budget_service/budget_manager_browsertest.cc
@@ -8,6 +8,7 @@ #include "build/build_config.h" #include "chrome/browser/budget_service/budget_manager.h" #include "chrome/browser/budget_service/budget_manager_factory.h" +#include "chrome/browser/engagement/site_engagement_service.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" @@ -19,6 +20,7 @@ #include "content/public/test/browser_test_utils.h" #include "net/test/embedded_test_server/embedded_test_server.h" #include "third_party/WebKit/public/platform/modules/budget_service/budget_service.mojom.h" +#include "url/gurl.h" #include "url/origin.h" namespace { @@ -55,6 +57,12 @@ InProcessBrowserTest::SetUpCommandLine(command_line); } + void SetSiteEngagementScore(double score) { + SiteEngagementService* service = + SiteEngagementService::Get(browser()->profile()); + service->ResetScoreForURL(https_server_->GetURL(kTestURL), score); + } + bool RunScript(const std::string& script, std::string* result) { content::WebContents* web_contents = browser()->tab_strip_model()->GetActiveWebContents(); @@ -94,20 +102,22 @@ IN_PROC_BROWSER_TEST_F(BudgetManagerBrowserTest, BudgetInDocument) { std::string script_result; - // The page will have been loaded once, which gives a budget of 3. + SetSiteEngagementScore(5); + + // Site Engagement score of 5 gives a budget of 2. ASSERT_TRUE(RunScript("documentGetBudget()", &script_result)); - ASSERT_EQ("ok - budget returned value of 3", script_result); + EXPECT_EQ("ok - budget returned value of 2", script_result); ASSERT_TRUE(RunScript("documentReserveBudget()", &script_result)); - ASSERT_EQ("ok - reserved budget", script_result); + EXPECT_EQ("ok - reserved budget", script_result); - // After reserving budget, the new budget should be at 1. + // After reserving budget, the new budget should be at 0. ASSERT_TRUE(RunScript("documentGetBudget()", &script_result)); - ASSERT_EQ("ok - budget returned value of 1", script_result); + EXPECT_EQ("ok - budget returned value of 0", script_result); // A second reserve should fail because there is not enough budget. ASSERT_TRUE(RunScript("documentReserveBudget()", &script_result)); - ASSERT_EQ("failed - not able to reserve budget", script_result); + EXPECT_EQ("failed - not able to reserve budget", script_result); // Consume should succeed because there is an existing reservation. ConsumeReservation(); @@ -125,29 +135,29 @@ ASSERT_EQ("ok - service worker registered", script_result); LoadTestPage(); // Reload to become controlled. + SetSiteEngagementScore(12); ASSERT_TRUE(RunScript("isControlled()", &script_result)); ASSERT_EQ("true - is controlled", script_result); - // The page will have been loaded twice and a service worker was registered, - // which gives a budget of 4.5. + // Site engagement score of 12 gives a budget of 5. ASSERT_TRUE(RunScript("workerGetBudget()", &script_result)); - ASSERT_EQ("ok - budget returned value of 4.5", script_result); + EXPECT_EQ("ok - budget returned value of 5", script_result); - // With a budget of 4.5, two reservations should succeed. + // With a budget of 5, two reservations should succeed. ASSERT_TRUE(RunScript("workerReserveBudget()", &script_result)); - ASSERT_EQ("ok - reserved budget", script_result); + EXPECT_EQ("ok - reserved budget", script_result); ASSERT_TRUE(RunScript("workerReserveBudget()", &script_result)); - ASSERT_EQ("ok - reserved budget", script_result); + EXPECT_EQ("ok - reserved budget", script_result); - // After reserving budget, the new budget should be at 0.5. + // After reserving budget, the new budget should be at 1. ASSERT_TRUE(RunScript("workerGetBudget()", &script_result)); - ASSERT_EQ("ok - budget returned value of 0.5", script_result); + EXPECT_EQ("ok - budget returned value of 1", script_result); // A second reserve should fail because there is not enough budget. ASSERT_TRUE(RunScript("workerReserveBudget()", &script_result)); - ASSERT_EQ("failed - not able to reserve budget", script_result); + EXPECT_EQ("failed - not able to reserve budget", script_result); // Two consumes should succeed because there are existing reservations. ConsumeReservation();
diff --git a/chrome/browser/budget_service/budget_manager_unittest.cc b/chrome/browser/budget_service/budget_manager_unittest.cc index 43b48f105..ab0802f 100644 --- a/chrome/browser/budget_service/budget_manager_unittest.cc +++ b/chrome/browser/budget_service/budget_manager_unittest.cc
@@ -115,15 +115,15 @@ }; TEST_F(BudgetManagerTest, GetBudgetConsumedOverTime) { - // Set initial SES. The first time we try to spend budget, the - // engagement award will be granted which is 48.0. + // Set initial SES. The first time we try to spend budget, the engagement + // award will be granted which is 23.04. (kTestSES * maxDaily / maxSES) SetSiteEngagementScore(kTestSES); const blink::mojom::BudgetOperationType type = blink::mojom::BudgetOperationType::SILENT_PUSH; - // Spend for 24 silent push messages. This should consume all the original + // Spend for 11 silent push messages. This should consume all the original // budget grant. - for (int i = 0; i < 24; i++) { + for (int i = 0; i < 11; i++) { ASSERT_TRUE(GetBudget()); ASSERT_TRUE(ReserveBudget(type)); } @@ -132,8 +132,8 @@ ASSERT_TRUE(GetBudget()); ASSERT_FALSE(ReserveBudget(type)); - // Try to consume for the 24 messages reserved. - for (int i = 0; i < 24; i++) + // Try to consume for the 11 messages reserved. + for (int i = 0; i < 11; i++) ASSERT_TRUE(ConsumeBudget(type)); // The next consume should fail, since there is no reservation or budget @@ -148,9 +148,9 @@ // 1 failed reserve call. EXPECT_EQ(0, buckets[0].min); EXPECT_EQ(1, buckets[0].count); - // 24 successful reserve calls. + // 11 successful reserve calls. EXPECT_EQ(1, buckets[1].min); - EXPECT_EQ(24, buckets[1].count); + EXPECT_EQ(11, buckets[1].count); // Check that the UMA recorded for the GetBudget calls matches the operations // that were executed. @@ -159,7 +159,7 @@ int num_samples = 0; for (const base::Bucket& bucket : buckets) num_samples += bucket.count; - EXPECT_EQ(25, num_samples); + EXPECT_EQ(12, num_samples); } TEST_F(BudgetManagerTest, TestInsecureOrigin) {
diff --git a/chrome/browser/push_messaging/push_messaging_browsertest.cc b/chrome/browser/push_messaging/push_messaging_browsertest.cc index 13b3c100..90a6a56 100644 --- a/chrome/browser/push_messaging/push_messaging_browsertest.cc +++ b/chrome/browser/push_messaging/push_messaging_browsertest.cc
@@ -1240,9 +1240,10 @@ content::WebContents* web_contents = GetBrowser()->tab_strip_model()->GetActiveWebContents(); - // Set the site engagement score for the site. Setting it to 4 means it should - // have enough budget for two non-shown notification, which cost 2 each. - SetSiteEngagementScore(web_contents->GetURL(), 4.0); + // Set the site engagement score for the site. Setting it to 10 means it + // should have a budget of 4, enough for two non-shown notification, which + // cost 2 each. + SetSiteEngagementScore(web_contents->GetURL(), 10.0); // If the site is visible in an active tab, we should not force a notification // to be shown. Try it twice, since we allow one mistake per 10 push events.
diff --git a/chrome/test/data/webrtc/peerconnection_getstats.js b/chrome/test/data/webrtc/peerconnection_getstats.js index 300ae02..6054a5c 100644 --- a/chrome/test/data/webrtc/peerconnection_getstats.js +++ b/chrome/test/data/webrtc/peerconnection_getstats.js
@@ -21,6 +21,9 @@ associateStatsId: 'string', isRemote: 'boolean', mediaType: 'string', + trackId: 'string', + // TODO(hbos): As soon as |mediaTrackId| has been renamed to |trackId|, remove + // this line. crbug.com/657854 mediaTrackId: 'string', transportId: 'string', codecId: 'string', @@ -93,6 +96,8 @@ var kRTCPeerConnectionStats = new RTCStats_(null, { dataChannelsOpened: 'number', dataChannelsClosed: 'number', + dataChannelsRequested: 'number', + dataChannelsAccepted: 'number', }); gStatsWhitelist.set('peer-connection', kRTCPeerConnectionStats); @@ -117,6 +122,9 @@ remoteSource: 'boolean', ended: 'boolean', detached: 'boolean', + kind: 'string', + // TODO(hbos): As soon as |ssrcIds| has been removed, remove this line. + // crbug.com/659137 ssrcIds: 'sequence_string', frameWidth: 'number', frameHeight: 'number', @@ -160,6 +168,9 @@ bytesSent: 'number', bytesReceived: 'number', rtcpTransportStatsId: 'string', + dtlsState: 'string', + // TODO(hbos): As soon as |activeConnection| has been replaced by |dtlsState|, + // remove this line. crbug.com/653873 activeConnection: 'boolean', selectedCandidatePairId: 'string', localCertificateId: 'string',
diff --git a/components/ntp_snippets_strings.grdp b/components/ntp_snippets_strings.grdp index c3cfde7..e9e2ef5 100644 --- a/components/ntp_snippets_strings.grdp +++ b/components/ntp_snippets_strings.grdp
@@ -5,8 +5,8 @@ <message name="IDS_SNIPPETS_DISABLED_SIGNED_OUT_INSTRUCTIONS" desc="Body of the card explaining the status of the content suggestions on the New Tab Page, when the user is signed out." formatter_data="android_java"> To get personalized content suggested by Google, sign in to Chrome. </message> - <message name="IDS_SNIPPETS_DISABLED_GENERIC_PROMPT" desc="Title of the card explaining what action the user can take to get content suggestions on the New Tab Page." formatter_data="android_java"> - Get suggested content + <message name="IDS_SNIPPETS_DISABLED_GENERIC_PROMPT" desc="Title of the card explaining what action the user can take to get personalized content suggestions on the New Tab Page." formatter_data="android_java"> + Get personalized content </message> <message name="IDS_NTP_STATUS_CARD_TITLE_NO_SUGGESTIONS" desc="On the New Tab Page, title of the status card explaining that there is no new content available in the section." formatter_data="android_java"> That’s all for now
diff --git a/components/os_crypt/libsecret_util_linux.cc b/components/os_crypt/libsecret_util_linux.cc index 611b0fed..b14bbb2e 100644 --- a/components/os_crypt/libsecret_util_linux.cc +++ b/components/os_crypt/libsecret_util_linux.cc
@@ -19,7 +19,7 @@ // create, to explain its existence. const char kExplanationMessage[] = "Because of quirks in the gnome libsecret API, Chrome needs to store a " - "dummy entry to quarantee that this keyring was properly unlocked. More " + "dummy entry to guarantee that this keyring was properly unlocked. More " "details at http://crbug.com/660005."; } // namespace
diff --git a/net/disk_cache/backend_unittest.cc b/net/disk_cache/backend_unittest.cc index e92dd9b..2f401c8c 100644 --- a/net/disk_cache/backend_unittest.cc +++ b/net/disk_cache/backend_unittest.cc
@@ -126,6 +126,7 @@ void BackendDoomRecent(); void BackendDoomBetween(); void BackendCalculateSizeOfAllEntries(); + void BackendCalculateSizeOfEntriesBetween(); void BackendTransaction(const std::string& name, int num_entries, bool load); void BackendRecoverInsert(); void BackendRecoverRemove(); @@ -1872,6 +1873,70 @@ BackendCalculateSizeOfAllEntries(); } +void DiskCacheBackendTest::BackendCalculateSizeOfEntriesBetween() { + InitCache(); + + EXPECT_EQ(0, CalculateSizeOfEntriesBetween(base::Time(), base::Time::Max())); + + Time start = Time::Now(); + + disk_cache::Entry* entry; + ASSERT_THAT(CreateEntry("first", &entry), IsOk()); + entry->Close(); + FlushQueueForTest(); + + AddDelay(); + Time middle = Time::Now(); + AddDelay(); + + ASSERT_THAT(CreateEntry("second", &entry), IsOk()); + entry->Close(); + ASSERT_THAT(CreateEntry("third_entry", &entry), IsOk()); + entry->Close(); + FlushQueueForTest(); + + AddDelay(); + Time end = Time::Now(); + + int size_1 = GetEntryMetadataSize("first"); + int size_2 = GetEntryMetadataSize("second"); + int size_3 = GetEntryMetadataSize("third_entry"); + + ASSERT_EQ(3, cache_->GetEntryCount()); + ASSERT_EQ(CalculateSizeOfAllEntries(), + CalculateSizeOfEntriesBetween(base::Time(), base::Time::Max())); + + int start_end = CalculateSizeOfEntriesBetween(start, end); + ASSERT_EQ(CalculateSizeOfAllEntries(), start_end); + ASSERT_EQ(size_1 + size_2 + size_3, start_end); + + ASSERT_EQ(size_1, CalculateSizeOfEntriesBetween(start, middle)); + ASSERT_EQ(size_2 + size_3, CalculateSizeOfEntriesBetween(middle, end)); + + // After dooming the entries, the size should be back to zero. + ASSERT_THAT(DoomAllEntries(), IsOk()); + EXPECT_EQ(0, CalculateSizeOfEntriesBetween(base::Time(), base::Time::Max())); +} + +TEST_F(DiskCacheBackendTest, CalculateSizeOfEntriesBetween) { + InitCache(); + ASSERT_EQ(net::ERR_NOT_IMPLEMENTED, + CalculateSizeOfEntriesBetween(base::Time(), base::Time::Max())); +} + +TEST_F(DiskCacheBackendTest, MemoryOnlyCalculateSizeOfEntriesBetween) { + SetMemoryOnlyMode(); + BackendCalculateSizeOfEntriesBetween(); +} + +TEST_F(DiskCacheBackendTest, SimpleCacheCalculateSizeOfEntriesBetween) { + // Use net::APP_CACHE to make size estimations deterministic via + // non-optimistic writes. + SetCacheType(net::APP_CACHE); + SetSimpleCacheMode(); + BackendCalculateSizeOfEntriesBetween(); +} + void DiskCacheBackendTest::BackendTransaction(const std::string& name, int num_entries, bool load) { success_ = false;
diff --git a/net/disk_cache/cache_creator.cc b/net/disk_cache/disk_cache.cc similarity index 87% rename from net/disk_cache/cache_creator.cc rename to net/disk_cache/disk_cache.cc index f0146deb..81676eb 100644 --- a/net/disk_cache/cache_creator.cc +++ b/net/disk_cache/disk_cache.cc
@@ -88,8 +88,7 @@ net_log_(net_log) { } -CacheCreator::~CacheCreator() { -} +CacheCreator::~CacheCreator() {} int CacheCreator::Run() { #if defined(OS_ANDROID) @@ -101,14 +100,14 @@ (backend_type_ == net::CACHE_BACKEND_DEFAULT && kSimpleBackendIsDefault)) { disk_cache::SimpleBackendImpl* simple_cache = - new disk_cache::SimpleBackendImpl( - path_, max_bytes_, type_, thread_, net_log_); + new disk_cache::SimpleBackendImpl(path_, max_bytes_, type_, thread_, + net_log_); created_cache_.reset(simple_cache); return simple_cache->Init( base::Bind(&CacheCreator::OnIOComplete, base::Unretained(this))); } - // Avoid references to blockfile functions on Android to reduce binary size. +// Avoid references to blockfile functions on Android to reduce binary size. #if defined(OS_ANDROID) return net::ERR_FAILED; #else @@ -176,17 +175,16 @@ return *backend ? net::OK : net::ERR_FAILED; } DCHECK(thread.get()); - CacheCreator* creator = new CacheCreator(path, - force, - max_bytes, - type, - backend_type, - kNone, - thread, - net_log, - backend, - callback); + CacheCreator* creator = + new CacheCreator(path, force, max_bytes, type, backend_type, kNone, + thread, net_log, backend, callback); return creator->Run(); } +int Backend::CalculateSizeOfEntriesBetween(base::Time initial_time, + base::Time end_time, + const CompletionCallback& callback) { + return net::ERR_NOT_IMPLEMENTED; +} + } // namespace disk_cache
diff --git a/net/disk_cache/disk_cache.h b/net/disk_cache/disk_cache.h index f71bc819..0992406 100644 --- a/net/disk_cache/disk_cache.h +++ b/net/disk_cache/disk_cache.h
@@ -19,6 +19,7 @@ #include "base/time/time.h" #include "net/base/cache_type.h" #include "net/base/completion_callback.h" +#include "net/base/net_errors.h" #include "net/base/net_export.h" namespace base { @@ -149,8 +150,19 @@ // Calculate the total size of the cache. The return value is the size in // bytes or a net error code. If this method returns ERR_IO_PENDING, // the |callback| will be invoked when the operation completes. - virtual int CalculateSizeOfAllEntries( - const CompletionCallback& callback) = 0; + virtual int CalculateSizeOfAllEntries(const CompletionCallback& callback) = 0; + + // Calculate the size of all cache entries accessed between |initial_time| and + // |end_time|. + // The return value is the size in bytes or a net error code. The default + // implementation returns ERR_NOT_IMPLEMENTED and should only be overwritten + // if there is an efficient way for the backend to determine the size for a + // subset of the cache without reading the whole cache from disk. + // If this method returns ERR_IO_PENDING, the |callback| will be invoked when + // the operation completes. + virtual int CalculateSizeOfEntriesBetween(base::Time initial_time, + base::Time end_time, + const CompletionCallback& callback); // Returns an iterator which will enumerate all entries of the cache in an // undefined order.
diff --git a/net/disk_cache/disk_cache_test_base.cc b/net/disk_cache/disk_cache_test_base.cc index 84ba9c6..030c7bd 100644 --- a/net/disk_cache/disk_cache_test_base.cc +++ b/net/disk_cache/disk_cache_test_base.cc
@@ -179,6 +179,15 @@ return cb.GetResult(rv); } +int DiskCacheTestWithCache::CalculateSizeOfEntriesBetween( + const base::Time initial_time, + const base::Time end_time) { + net::TestCompletionCallback cb; + int rv = cache_->CalculateSizeOfEntriesBetween(initial_time, end_time, + cb.callback()); + return cb.GetResult(rv); +} + std::unique_ptr<DiskCacheTestWithCache::TestIterator> DiskCacheTestWithCache::CreateIterator() { return std::unique_ptr<TestIterator>(
diff --git a/net/disk_cache/disk_cache_test_base.h b/net/disk_cache/disk_cache_test_base.h index 9dde5bf..b9564f93 100644 --- a/net/disk_cache/disk_cache_test_base.h +++ b/net/disk_cache/disk_cache_test_base.h
@@ -138,6 +138,8 @@ int DoomEntriesBetween(const base::Time initial_time, const base::Time end_time); int CalculateSizeOfAllEntries(); + int CalculateSizeOfEntriesBetween(const base::Time initial_time, + const base::Time end_time); int DoomEntriesSince(const base::Time initial_time); std::unique_ptr<TestIterator> CreateIterator(); void FlushQueueForTest();
diff --git a/net/disk_cache/memory/mem_backend_impl.cc b/net/disk_cache/memory/mem_backend_impl.cc index ad9dfed..7ded277 100644 --- a/net/disk_cache/memory/mem_backend_impl.cc +++ b/net/disk_cache/memory/mem_backend_impl.cc
@@ -181,7 +181,6 @@ const CompletionCallback& callback) { if (end_time.is_null()) end_time = Time::Max(); - DCHECK_GE(end_time, initial_time); base::LinkNode<MemEntryImpl>* node = lru_list_.head(); @@ -206,6 +205,26 @@ return current_size_; } +int MemBackendImpl::CalculateSizeOfEntriesBetween( + base::Time initial_time, + base::Time end_time, + const CompletionCallback& callback) { + if (end_time.is_null()) + end_time = Time::Max(); + DCHECK_GE(end_time, initial_time); + + int size = 0; + base::LinkNode<MemEntryImpl>* node = lru_list_.head(); + while (node != lru_list_.end() && node->value()->GetLastUsed() < initial_time) + node = node->next(); + while (node != lru_list_.end() && node->value()->GetLastUsed() < end_time) { + MemEntryImpl* entry = node->value(); + size += entry->GetStorageSize(); + node = node->next(); + } + return size; +} + class MemBackendImpl::MemIterator final : public Backend::Iterator { public: explicit MemIterator(base::WeakPtr<MemBackendImpl> backend)
diff --git a/net/disk_cache/memory/mem_backend_impl.h b/net/disk_cache/memory/mem_backend_impl.h index 30417c6..024da855 100644 --- a/net/disk_cache/memory/mem_backend_impl.h +++ b/net/disk_cache/memory/mem_backend_impl.h
@@ -91,6 +91,10 @@ int DoomEntriesSince(base::Time initial_time, const CompletionCallback& callback) override; int CalculateSizeOfAllEntries(const CompletionCallback& callback) override; + int CalculateSizeOfEntriesBetween( + base::Time initial_time, + base::Time end_time, + const CompletionCallback& callback) override; std::unique_ptr<Iterator> CreateIterator() override; void GetStats(base::StringPairs* stats) override {} void OnExternalCacheHit(const std::string& key) override;
diff --git a/net/disk_cache/simple/simple_backend_impl.cc b/net/disk_cache/simple/simple_backend_impl.cc index 30fade47..e5645e35 100644 --- a/net/disk_cache/simple/simple_backend_impl.cc +++ b/net/disk_cache/simple/simple_backend_impl.cc
@@ -458,6 +458,15 @@ &SimpleBackendImpl::IndexReadyForSizeCalculation, AsWeakPtr(), callback)); } +int SimpleBackendImpl::CalculateSizeOfEntriesBetween( + base::Time initial_time, + base::Time end_time, + const CompletionCallback& callback) { + return index_->ExecuteWhenReady( + base::Bind(&SimpleBackendImpl::IndexReadyForSizeBetweenCalculation, + AsWeakPtr(), initial_time, end_time, callback)); +} + class SimpleBackendImpl::SimpleIterator final : public Iterator { public: explicit SimpleIterator(base::WeakPtr<SimpleBackendImpl> backend) @@ -573,6 +582,18 @@ callback.Run(result); } +void SimpleBackendImpl::IndexReadyForSizeBetweenCalculation( + base::Time initial_time, + base::Time end_time, + const CompletionCallback& callback, + int result) { + if (result == net::OK) { + result = + static_cast<int>(index_->GetCacheSizeBetween(initial_time, end_time)); + } + callback.Run(result); +} + // static SimpleBackendImpl::DiskStatResult SimpleBackendImpl::InitCacheStructureOnDisk( const base::FilePath& path,
diff --git a/net/disk_cache/simple/simple_backend_impl.h b/net/disk_cache/simple/simple_backend_impl.h index 3516847..a0b4b9c4 100644 --- a/net/disk_cache/simple/simple_backend_impl.h +++ b/net/disk_cache/simple/simple_backend_impl.h
@@ -110,6 +110,10 @@ int DoomEntriesSince(base::Time initial_time, const CompletionCallback& callback) override; int CalculateSizeOfAllEntries(const CompletionCallback& callback) override; + int CalculateSizeOfEntriesBetween( + base::Time initial_time, + base::Time end_time, + const CompletionCallback& callback) override; std::unique_ptr<Iterator> CreateIterator() override; void GetStats(base::StringPairs* stats) override; void OnExternalCacheHit(const std::string& key) override; @@ -148,6 +152,13 @@ void IndexReadyForSizeCalculation(const CompletionCallback& callback, int result); + // Calculates the size all cache entries between |initial_time| and + // |end_time|. Invoked when the index is ready. + void IndexReadyForSizeBetweenCalculation(base::Time initial_time, + base::Time end_time, + const CompletionCallback& callback, + int result); + // Try to create the directory if it doesn't exist. This must run on the IO // thread. static DiskStatResult InitCacheStructureOnDisk(
diff --git a/net/disk_cache/simple/simple_index.cc b/net/disk_cache/simple/simple_index.cc index e68e746..a654faf37 100644 --- a/net/disk_cache/simple/simple_index.cc +++ b/net/disk_cache/simple/simple_index.cc
@@ -220,16 +220,14 @@ end_time = base::Time::Max(); else end_time += EntryMetadata::GetUpperEpsilonForTimeComparisons(); - const base::Time extended_end_time = - end_time.is_null() ? base::Time::Max() : end_time; - DCHECK(extended_end_time >= initial_time); + DCHECK(end_time >= initial_time); + std::unique_ptr<HashList> ret_hashes(new HashList()); - for (EntrySet::iterator it = entries_set_.begin(), end = entries_set_.end(); - it != end; ++it) { - EntryMetadata& metadata = it->second; + for (const auto& entry : entries_set_) { + const EntryMetadata& metadata = entry.second; base::Time entry_time = metadata.GetLastUsedTime(); - if (initial_time <= entry_time && entry_time < extended_end_time) - ret_hashes->push_back(it->first); + if (initial_time <= entry_time && entry_time < end_time) + ret_hashes->push_back(entry.first); } return ret_hashes; } @@ -248,6 +246,28 @@ return cache_size_; } +uint64_t SimpleIndex::GetCacheSizeBetween(base::Time initial_time, + base::Time end_time) const { + DCHECK_EQ(true, initialized_); + + if (!initial_time.is_null()) + initial_time -= EntryMetadata::GetLowerEpsilonForTimeComparisons(); + if (end_time.is_null()) + end_time = base::Time::Max(); + else + end_time += EntryMetadata::GetUpperEpsilonForTimeComparisons(); + + DCHECK(end_time >= initial_time); + uint64_t size = 0; + for (const auto& entry : entries_set_) { + const EntryMetadata& metadata = entry.second; + base::Time entry_time = metadata.GetLastUsedTime(); + if (initial_time <= entry_time && entry_time < end_time) + size += metadata.GetEntrySize(); + } + return size; +} + void SimpleIndex::Insert(uint64_t entry_hash) { DCHECK(io_thread_checker_.CalledOnValidThread()); // Upon insert we don't know yet the size of the entry.
diff --git a/net/disk_cache/simple/simple_index.h b/net/disk_cache/simple/simple_index.h index fee2a1e9..1adb0ecc 100644 --- a/net/disk_cache/simple/simple_index.h +++ b/net/disk_cache/simple/simple_index.h
@@ -155,6 +155,12 @@ // index has been initialized. uint64_t GetCacheSize() const; + // Returns the size of the cache entries accessed between |initial_time| and + // |end_time| in bytes. Can only be called after the index has been + // initialized. + uint64_t GetCacheSizeBetween(const base::Time initial_time, + const base::Time end_time) const; + // Returns whether the index has been initialized yet. bool initialized() const { return initialized_; }
diff --git a/net/net.gypi b/net/net.gypi index 34d13133..1dda9716 100644 --- a/net/net.gypi +++ b/net/net.gypi
@@ -545,11 +545,11 @@ 'disk_cache/blockfile/trace.h', 'disk_cache/blockfile/webfonts_histogram.cc', 'disk_cache/blockfile/webfonts_histogram.h', - 'disk_cache/cache_creator.cc', 'disk_cache/cache_util.cc', 'disk_cache/cache_util.h', 'disk_cache/cache_util_posix.cc', 'disk_cache/cache_util_win.cc', + 'disk_cache/disk_cache.cc', 'disk_cache/disk_cache.h', 'disk_cache/memory/mem_backend_impl.cc', 'disk_cache/memory/mem_backend_impl.h',
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations index e6973754..2499915 100644 --- a/third_party/WebKit/LayoutTests/TestExpectations +++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -1215,8 +1215,6 @@ crbug.com/619539 [ Win ] http/tests/workers/terminate-during-sync-operation-file.html [ Pass Timeout ] crbug.com/619539 [ Win ] virtual/mojo-loading/http/tests/workers/terminate-during-sync-operation-file.html [ Pass Timeout ] -crbug.com/649159 imported/wpt/shadow-dom/slotchange-event.html [ Failure ] - # These are the failing tests because Chrome hasn't implemented according to the spec. crbug.com/645988 imported/wpt/uievents/order-of-events/focus-events/focus-manual.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/accessibility/misspellings.html b/third_party/WebKit/LayoutTests/accessibility/misspellings.html index 14618b4f..3c75643b 100644 --- a/third_party/WebKit/LayoutTests/accessibility/misspellings.html +++ b/third_party/WebKit/LayoutTests/accessibility/misspellings.html
@@ -13,100 +13,124 @@ <textarea id="textarea" spellcheck="true"></textarea> <script> - if (window.internals) - internals.setSpellCheckingEnabled(true); + if (window.internals) + internals.setSpellCheckingEnabled(true); + if (window.testRunner) + testRunner.setMockSpellCheckerEnabled(true); + + const tests = []; + + tests.push({ + testObject: async_test('Misspellings should be reported in content editables.'), + action: () => { + document.getElementById('editable').focus(); + document.execCommand('InsertText', false, 'Foo baz chello there.'); + assert_equals(document.getElementById('editable').childNodes.length, 1); + }, + verification: () => { + var axEditable = accessibilityController.accessibleElementById('editable'); + var axStaticText = axEditable.childAtIndex(0); + + assert_equals(axStaticText.misspellingsCount, 3); + assert_equals(axStaticText.misspellingAtIndex(0), 'Foo'); + assert_equals(axStaticText.misspellingAtIndex(1), 'baz'); + assert_equals(axStaticText.misspellingAtIndex(2), 'chello'); + }, + cleanup: () => document.getElementById('editable').style.display = 'none' + }); + + tests.push({ + testObject: async_test('Misspellings should be reported in static text when design mode is on.'), + action: () => { + document.designMode = 'on'; + // Trigger spell checking on originally static text. + window.getSelection().collapse(document.getElementById('paragraph'), 0); + }, + verification: () => { + var axParagraph = accessibilityController.accessibleElementById('paragraph'); + var axStaticText = axParagraph.childAtIndex(0); + + assert_equals(axStaticText.misspellingsCount, 2); + assert_equals(axStaticText.misspellingAtIndex(0), 'adaasj'); + assert_equals(axStaticText.misspellingAtIndex(1), 'sdklj'); + }, + cleanup: () => { + document.designMode = 'off'; + document.getElementById('paragraph').style.display = 'none'; + } + }); + + tests.push({ + testObject: async_test('Misspellings should be reported in single-line text fields.'), + action: () => { + document.getElementById('input').focus(); + document.execCommand('InsertText', false, 'contentEditable '); + }, + verification: () => { + var axInput = accessibilityController.accessibleElementById('input'); + // If input's shadow DOM changes, this logic might need to be modified. + assert_equals(axInput.childrenCount, 1); + var axDiv = axInput.childAtIndex(0); + assert_equals(axDiv.childrenCount, 1); + var axStaticText = axDiv.childAtIndex(0); + + assert_equals(axStaticText.misspellingsCount, 1); + assert_equals(axStaticText.misspellingAtIndex(0), 'contentEditable'); + }, + cleanup: () => document.getElementById('input').style.display = 'none' + }); + + tests.push({ + testObject: async_test('Misspellings should be reported in textareas.'), + action: () => { + document.getElementById('textarea').focus(); + document.execCommand('InsertText', false, 'contentEditable '); + }, + verification: () => { + var axTextarea = accessibilityController.accessibleElementById('textarea'); + // If textarea's shadow DOM changes, this logic might need to be modified. + assert_equals(axTextarea.childrenCount, 1); + var axDiv = axTextarea.childAtIndex(0); + assert_equals(axDiv.childrenCount, 1); + var axStaticText = axDiv.childAtIndex(0); + + assert_equals(axStaticText.misspellingsCount, 1); + assert_equals(axStaticText.misspellingAtIndex(0), 'contentEditable'); + }, + cleanup: () => document.getElementById('textarea').style.display = 'none' + }); + + function runTestIfAny() { + const currentTest = tests.shift(); + if (!currentTest) + return; + + const testObject = currentTest.testObject; + if (window.testRunner) { + testRunner.setSpellCheckResolvedCallback(() => { + testObject.step(() => { + currentTest.verification(); + testObject.done(); + }); + }); + } + testObject.cleanup = currentTest.cleanup; + + currentTest.action(); + + // Force idle time spell checker to run. if (window.testRunner) - testRunner.setMockSpellCheckerEnabled(true); + testRunner.runIdleTasks(() => {}); + } - async_test(function(t) - { - document.getElementById('editable').focus(); - document.execCommand('InsertText', false, 'Foo baz chello there.'); - assert_equals(document.getElementById('editable').childNodes.length, 1); + add_result_callback(testObject => { + setTimeout(() => { + if (window.testRunner) + testRunner.removeSpellCheckResolvedCallback(); + testObject.cleanup(); + runTestIfAny(); + }, 0); + }); - step_timeout(function() - { - var axEditable = accessibilityController.accessibleElementById('editable'); - var axStaticText = axEditable.childAtIndex(0); - - assert_equals(axStaticText.misspellingsCount, 3); - assert_equals(axStaticText.misspellingAtIndex(0), 'Foo'); - assert_equals(axStaticText.misspellingAtIndex(1), 'baz'); - assert_equals(axStaticText.misspellingAtIndex(2), 'chello'); - - document.getElementById('editable').style.display = "none";; - t.done(); - }, 50); - }, 'Misspellings should be reported in content editables.'); - - async_test(function(t) - { - step_timeout(function() { - document.designMode = 'on'; - // Trigger spell checking on originally static text. - window.getSelection().collapse(document.getElementById('paragraph'), 0); - - step_timeout(function() - { - var axParagraph = accessibilityController.accessibleElementById('paragraph'); - var axStaticText = axParagraph.childAtIndex(0); - - assert_equals(axStaticText.misspellingsCount, 2); - assert_equals(axStaticText.misspellingAtIndex(0), 'adaasj'); - assert_equals(axStaticText.misspellingAtIndex(1), 'sdklj'); - - document.designMode = 'off'; - document.getElementById('paragraph').style.display = "none";; - t.done(); - }, 50); - }, 100); - }, 'Misspellings should be reported in static text when design mode is on.'); - - async_test(function(t) - { - step_timeout(function() { - document.getElementById('input').focus(); - document.execCommand('InsertText', false, 'contentEditable '); - - step_timeout(function() - { - var axInput = accessibilityController.accessibleElementById('input'); - // If input's shadow DOM changes, this logic might need to be modified. - assert_equals(axInput.childrenCount, 1); - var axDiv = axInput.childAtIndex(0); - assert_equals(axDiv.childrenCount, 1); - var axStaticText = axDiv.childAtIndex(0); - - assert_equals(axStaticText.misspellingsCount, 1); - assert_equals(axStaticText.misspellingAtIndex(0), 'contentEditable'); - - document.getElementById('input').style.display = "none";; - t.done(); - }, 50); - }, 200); - }, 'Misspellings should be reported in single-line text fields.'); - - async_test(function(t) - { - step_timeout(function() { - document.getElementById('textarea').focus(); - document.execCommand('InsertText', false, 'contentEditable '); - - step_timeout(function() - { - var axTextarea = accessibilityController.accessibleElementById('textarea'); - // If textarea's shadow DOM changes, this logic might need to be modified. - assert_equals(axTextarea.childrenCount, 1); - var axDiv = axTextarea.childAtIndex(0); - assert_equals(axDiv.childrenCount, 1); - var axStaticText = axDiv.childAtIndex(0); - - assert_equals(axStaticText.misspellingsCount, 1); - assert_equals(axStaticText.misspellingAtIndex(0), 'contentEditable'); - - document.getElementById('textarea').style.display = "none";; - t.done(); - }, 50); - }, 300); - }, 'Misspellings should be reported in textareas.'); + runTestIfAny(); </script>
diff --git a/third_party/WebKit/LayoutTests/fast/css/background-image-url-setproperty.html b/third_party/WebKit/LayoutTests/fast/css/background-image-url-setproperty.html new file mode 100644 index 0000000..d3b5790 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/css/background-image-url-setproperty.html
@@ -0,0 +1,17 @@ +<!DOCTYPE html> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> +<script> + var doc = document.implementation.createHTMLDocument(""); + doc.head.innerHTML = "<style>span { background: url(fail) }</style>"; + var rule = doc.head.firstChild.sheet.cssRules[0]; + + test(() => { + assert_equals(rule.style.background, 'url("fail")'); + }, "Check initial background url."); + + test(() => { + rule.style.setProperty("background", "url(pass)"); + assert_equals(rule.style.background, 'url("pass")'); + }, "Setting background to a relative url should change its value."); +</script>
diff --git a/third_party/WebKit/LayoutTests/fast/dom/geometry-interfaces-dom-rect.html b/third_party/WebKit/LayoutTests/fast/dom/geometry-interfaces-dom-rect.html index 611e2b7..78e9871a 100644 --- a/third_party/WebKit/LayoutTests/fast/dom/geometry-interfaces-dom-rect.html +++ b/third_party/WebKit/LayoutTests/fast/dom/geometry-interfaces-dom-rect.html
@@ -57,6 +57,35 @@ }, 'DOMRect setter'); test(() => { + var rect = DOMRect.fromRect({x: 10, y: 20, width: 80, height: 50}); + assert_dom_rect_equals(rect, [10, 20, 80, 50, 20, 90, 70, 10]); +}, 'DOMRect.fromRect({x: 10, y: 20, width: 80, height: 50}) should create a DOMRect'); + +test(() => { + var rect = DOMRect.fromRect(); + assert_dom_rect_equals(rect, [0, 0, 0, 0, 0, 0, 0, 0]); +}, 'DOMRect.fromRect({x: 0, y: 0, width: 0, height: 0}) should create a DOMRect'); + +test(() => { + var rect = DOMRect.fromRect({x: 10, y: 20, width: 80, height: 50}); + rect.x = 30; + assert_dom_rect_equals(rect, [30, 20, 80, 50, 20, 110, 70, 30]); + rect.y = -10; + assert_dom_rect_equals(rect, [30, -10, 80, 50, -10, 110, 40, 30]); + rect.width = 20; + assert_dom_rect_equals(rect, [30, -10, 20, 50, -10, 50, 40, 30]); + rect.height = 40; + assert_dom_rect_equals(rect, [30, -10, 20, 40, -10, 50, 30, 30]); +}, 'DOMRect.fromRect({x: 10, y: 20, width: 80, height: 50}) should create a DOMRect and the values can be changed'); + +test(() => { + var rect1 = DOMRect.fromRect(); + var rect2 = DOMRect.fromRect(); + assert_false(rect1 == rect2); + assert_dom_rect_equals(rect1, rect2); +}, 'DOMRect.fromRect() should create a new DOMRect'); + +test(() => { var rect = new DOMRectReadOnly(); assert_dom_rect_equals(rect, [0, 0, 0, 0, 0, 0, 0, 0]); }, 'DOMRectReadOnly constructor without parameter'); @@ -94,4 +123,29 @@ assert_object_equals(rect.toJSON(), {x: 10, y: 20, width: 80, height: 50, top: 20, right: 90, bottom: 70, left: 10}); }, 'DOMRectReadOnly toJSON'); +test(() => { + var rect = DOMRectReadOnly.fromRect({x: 10, y: 20, width: 80, height: 50}); + assert_dom_rect_equals(rect, [10, 20, 80, 50, 20, 90, 70, 10]); +}, 'DOMRectReadOnly.fromRect({x: 10, y: 20, width: 80, height: 50}) should create a DOMRectReadOnly'); + +test(() => { + var rect = DOMRectReadOnly.fromRect(); + assert_dom_rect_equals(rect, [0, 0, 0, 0, 0, 0, 0, 0]); +}, 'DOMRectReadOnly.fromRect({x: 0, y: 0, width: 0, height: 0}) should create a DOMRectReadOnly'); + +test(() => { + var rect1 = DOMRectReadOnly.fromRect(); + var rect2 = DOMRectReadOnly.fromRect(); + assert_false(rect1 == rect2); + assert_dom_rect_equals(rect1, rect2); +}, 'DOMRectReadOnly.fromRect() should create a new DOMRectReadOnly'); + +test(() => { + var rect = DOMRectReadOnly.fromRect(); + assert_readonly(rect, 'x'); + assert_readonly(rect, 'y'); + assert_readonly(rect, 'width'); + assert_readonly(rect, 'height'); +}, "DOMRectReadOnly.fromRect() should create DOMRectReadOnly"); + </script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/budget/budget-service-mock.js b/third_party/WebKit/LayoutTests/http/tests/budget/budget-service-mock.js index 9e1f966..60ceac0 100644 --- a/third_party/WebKit/LayoutTests/http/tests/budget/budget-service-mock.js +++ b/third_party/WebKit/LayoutTests/http/tests/budget/budget-service-mock.js
@@ -5,7 +5,7 @@ "use strict"; const TEST_BUDGET_COST = 1.2; -const TEST_BUDGET_AT = 2.3; +const TEST_BUDGET_AT = 2; const TEST_BUDGET_TIME = new Date().getTime(); let budgetServiceMock = loadMojoModules(
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 363b2f07..6260f407 100644 --- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt +++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
@@ -1160,6 +1160,7 @@ setter x setter y interface DOMRectReadOnly + static method fromRect attribute @@toStringTag getter bottom getter height
diff --git a/third_party/WebKit/Source/bindings/core/v8/BUILD.gn b/third_party/WebKit/Source/bindings/core/v8/BUILD.gn index 1a45ad61..d3b5986 100644 --- a/third_party/WebKit/Source/bindings/core/v8/BUILD.gn +++ b/third_party/WebKit/Source/bindings/core/v8/BUILD.gn
@@ -33,6 +33,8 @@ "$blink_core_output_dir/dom/DOMPointInit.h", "$blink_core_output_dir/dom/DOMQuadInit.cpp", "$blink_core_output_dir/dom/DOMQuadInit.h", + "$blink_core_output_dir/dom/DOMRectInit.cpp", + "$blink_core_output_dir/dom/DOMRectInit.h", "$blink_core_output_dir/dom/ElementCreationOptions.cpp", "$blink_core_output_dir/dom/ElementCreationOptions.h", "$blink_core_output_dir/dom/ElementDefinitionOptions.cpp",
diff --git a/third_party/WebKit/Source/core/core_idl_files.gni b/third_party/WebKit/Source/core/core_idl_files.gni index d4cd26be..e2ee147 100644 --- a/third_party/WebKit/Source/core/core_idl_files.gni +++ b/third_party/WebKit/Source/core/core_idl_files.gni
@@ -514,6 +514,7 @@ "dom/DOMMatrixInit.idl", "dom/DOMPointInit.idl", "dom/DOMQuadInit.idl", + "dom/DOMRectInit.idl", "dom/ElementCreationOptions.idl", "dom/ElementDefinitionOptions.idl", "dom/ElementRegistrationOptions.idl",
diff --git a/third_party/WebKit/Source/core/css/CSSImageValue.cpp b/third_party/WebKit/Source/core/css/CSSImageValue.cpp index 2c338c8..c119d1b6 100644 --- a/third_party/WebKit/Source/core/css/CSSImageValue.cpp +++ b/third_party/WebKit/Source/core/css/CSSImageValue.cpp
@@ -102,6 +102,8 @@ } bool CSSImageValue::equals(const CSSImageValue& other) const { + if (m_absoluteURL.isEmpty() && other.m_absoluteURL.isEmpty()) + return m_relativeURL == other.m_relativeURL; return m_absoluteURL == other.m_absoluteURL; }
diff --git a/third_party/WebKit/Source/core/dom/DOMRect.cpp b/third_party/WebKit/Source/core/dom/DOMRect.cpp index 26c811ae..002018a 100644 --- a/third_party/WebKit/Source/core/dom/DOMRect.cpp +++ b/third_party/WebKit/Source/core/dom/DOMRect.cpp
@@ -4,12 +4,18 @@ #include "core/dom/DOMRect.h" +#include "core/dom/DOMRectInit.h" + namespace blink { DOMRect* DOMRect::create(double x, double y, double width, double height) { return new DOMRect(x, y, width, height); } +DOMRect* DOMRect::fromRect(const DOMRectInit& other) { + return new DOMRect(other.x(), other.y(), other.width(), other.height()); +} + DOMRect::DOMRect(double x, double y, double width, double height) : DOMRectReadOnly(x, y, width, height) {}
diff --git a/third_party/WebKit/Source/core/dom/DOMRect.h b/third_party/WebKit/Source/core/dom/DOMRect.h index 89746a79..b3d66dd0 100644 --- a/third_party/WebKit/Source/core/dom/DOMRect.h +++ b/third_party/WebKit/Source/core/dom/DOMRect.h
@@ -11,6 +11,9 @@ namespace blink { +class DOMRect; +class DOMRectInit; + class CORE_EXPORT DOMRect final : public DOMRectReadOnly { DEFINE_WRAPPERTYPEINFO(); @@ -19,6 +22,7 @@ double y = 0, double width = 0, double height = 0); + static DOMRect* fromRect(const DOMRectInit&); void setX(double x) { m_x = x; } void setY(double y) { m_y = y; }
diff --git a/third_party/WebKit/Source/core/dom/DOMRect.idl b/third_party/WebKit/Source/core/dom/DOMRect.idl index 293066b8..782cc41 100644 --- a/third_party/WebKit/Source/core/dom/DOMRect.idl +++ b/third_party/WebKit/Source/core/dom/DOMRect.idl
@@ -12,6 +12,8 @@ // FIXME: Exposed=(Window,Worker) RuntimeEnabled=GeometryInterfaces, ] interface DOMRect : DOMRectReadOnly { + [NewObject] static DOMRect fromRect(optional DOMRectInit other); + inherit attribute unrestricted double x; inherit attribute unrestricted double y; inherit attribute unrestricted double width;
diff --git a/third_party/WebKit/Source/core/dom/DOMRectInit.idl b/third_party/WebKit/Source/core/dom/DOMRectInit.idl new file mode 100644 index 0000000..2bcc9f3 --- /dev/null +++ b/third_party/WebKit/Source/core/dom/DOMRectInit.idl
@@ -0,0 +1,12 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// https://drafts.fxtf.org/geometry/#dictdef-domrectinit + +dictionary DOMRectInit { + unrestricted double x = 0; + unrestricted double y = 0; + unrestricted double width = 0; + unrestricted double height = 0; +};
diff --git a/third_party/WebKit/Source/core/dom/DOMRectReadOnly.cpp b/third_party/WebKit/Source/core/dom/DOMRectReadOnly.cpp index 3b09920..6b6e515 100644 --- a/third_party/WebKit/Source/core/dom/DOMRectReadOnly.cpp +++ b/third_party/WebKit/Source/core/dom/DOMRectReadOnly.cpp
@@ -6,6 +6,7 @@ #include "bindings/core/v8/ScriptValue.h" #include "bindings/core/v8/V8ObjectBuilder.h" +#include "core/dom/DOMRectInit.h" namespace blink { @@ -29,6 +30,10 @@ return result.scriptValue(); } +DOMRectReadOnly* DOMRectReadOnly::fromRect(const DOMRectInit& other) { + return new DOMRectReadOnly(other.x(), other.y(), other.width(), other.height()); +} + DOMRectReadOnly::DOMRectReadOnly(double x, double y, double width,
diff --git a/third_party/WebKit/Source/core/dom/DOMRectReadOnly.h b/third_party/WebKit/Source/core/dom/DOMRectReadOnly.h index 1a14e254..957dfc9 100644 --- a/third_party/WebKit/Source/core/dom/DOMRectReadOnly.h +++ b/third_party/WebKit/Source/core/dom/DOMRectReadOnly.h
@@ -11,6 +11,7 @@ namespace blink { +class DOMRectInit; class ScriptValue; class ScriptState; @@ -23,6 +24,7 @@ double y, double width, double height); + static DOMRectReadOnly* fromRect(const DOMRectInit&); double x() const { return m_x; } double y() const { return m_y; }
diff --git a/third_party/WebKit/Source/core/dom/DOMRectReadOnly.idl b/third_party/WebKit/Source/core/dom/DOMRectReadOnly.idl index f1cecfda..859ecb6 100644 --- a/third_party/WebKit/Source/core/dom/DOMRectReadOnly.idl +++ b/third_party/WebKit/Source/core/dom/DOMRectReadOnly.idl
@@ -10,6 +10,8 @@ // FIXME: Exposed=(Window,Worker) RuntimeEnabled=GeometryInterfaces, ] interface DOMRectReadOnly { + [NewObject] static DOMRectReadOnly fromRect(optional DOMRectInit other); + readonly attribute unrestricted double x; readonly attribute unrestricted double y; readonly attribute unrestricted double width;
diff --git a/third_party/WebKit/Source/core/dom/Document.cpp b/third_party/WebKit/Source/core/dom/Document.cpp index ed4d6b5..c6fc0601 100644 --- a/third_party/WebKit/Source/core/dom/Document.cpp +++ b/third_party/WebKit/Source/core/dom/Document.cpp
@@ -2450,6 +2450,8 @@ if (registrationContext()) registrationContext()->documentWasDetached(); + MutationObserver::cleanSlotChangeList(*this); + m_hoverNode = nullptr; m_activeHoverElement = nullptr; m_autofocusElement = nullptr;
diff --git a/third_party/WebKit/Source/core/dom/MutationObserver.cpp b/third_party/WebKit/Source/core/dom/MutationObserver.cpp index 9bf8da6..a25ae14 100644 --- a/third_party/WebKit/Source/core/dom/MutationObserver.cpp +++ b/third_party/WebKit/Source/core/dom/MutationObserver.cpp
@@ -37,6 +37,7 @@ #include "core/dom/MutationObserverRegistration.h" #include "core/dom/MutationRecord.h" #include "core/dom/Node.h" +#include "core/html/HTMLSlotElement.h" #include "core/inspector/InspectorInstrumentation.h" #include <algorithm> @@ -171,16 +172,45 @@ return activeObservers; } +using SlotChangeList = HeapVector<Member<HTMLSlotElement>>; + +// TODO(hayato): We should have a SlotChangeList for each unit of related +// similar-origin browsing context. +// https://html.spec.whatwg.org/multipage/browsers.html#unit-of-related-similar-origin-browsing-contexts +static SlotChangeList& activeSlotChangeList() { + DEFINE_STATIC_LOCAL(SlotChangeList, slotChangeList, (new SlotChangeList)); + return slotChangeList; +} + static MutationObserverSet& suspendedMutationObservers() { DEFINE_STATIC_LOCAL(MutationObserverSet, suspendedObservers, (new MutationObserverSet)); return suspendedObservers; } -static void activateObserver(MutationObserver* observer) { - if (activeMutationObservers().isEmpty()) +static void ensureEnqueueMicrotask() { + if (activeMutationObservers().isEmpty() && activeSlotChangeList().isEmpty()) Microtask::enqueueMicrotask(WTF::bind(&MutationObserver::deliverMutations)); +} +void MutationObserver::enqueueSlotChange(HTMLSlotElement& slot) { + DCHECK(isMainThread()); + ensureEnqueueMicrotask(); + activeSlotChangeList().push_back(&slot); +} + +void MutationObserver::cleanSlotChangeList(Document& document) { + SlotChangeList kept; + kept.reserveCapacity(activeSlotChangeList().size()); + for (auto& slot : activeSlotChangeList()) { + if (slot->document() != document) + kept.push_back(slot); + } + activeSlotChangeList().swap(kept); +} + +static void activateObserver(MutationObserver* observer) { + ensureEnqueueMicrotask(); activeMutationObservers().add(observer); } @@ -257,10 +287,19 @@ } void MutationObserver::deliverMutations() { + // These steps are defined in DOM Standard's "notify mutation observers". + // https://dom.spec.whatwg.org/#notify-mutation-observers DCHECK(isMainThread()); + MutationObserverVector observers; copyToVector(activeMutationObservers(), observers); activeMutationObservers().clear(); + + SlotChangeList slots; + slots.swap(activeSlotChangeList()); + for (const auto& slot : slots) + slot->clearSlotChangeEventEnqueued(); + std::sort(observers.begin(), observers.end(), ObserverLessThan()); for (const auto& observer : observers) { if (observer->shouldBeSuspended()) @@ -268,6 +307,8 @@ else observer->deliver(); } + for (const auto& slot : slots) + slot->dispatchSlotChangeEvent(); } DEFINE_TRACE(MutationObserver) {
diff --git a/third_party/WebKit/Source/core/dom/MutationObserver.h b/third_party/WebKit/Source/core/dom/MutationObserver.h index 6b35d73..7c7e8c2 100644 --- a/third_party/WebKit/Source/core/dom/MutationObserver.h +++ b/third_party/WebKit/Source/core/dom/MutationObserver.h
@@ -40,7 +40,9 @@ namespace blink { +class Document; class ExceptionState; +class HTMLSlotElement; class MutationCallback; class MutationObserver; class MutationObserverInit; @@ -81,6 +83,8 @@ static MutationObserver* create(MutationCallback*); static void resumeSuspendedObservers(); static void deliverMutations(); + static void enqueueSlotChange(HTMLSlotElement&); + static void cleanSlotChangeList(Document&); ~MutationObserver();
diff --git a/third_party/WebKit/Source/core/fileapi/FileReaderLoader.cpp b/third_party/WebKit/Source/core/fileapi/FileReaderLoader.cpp index a1e899c..10bec70 100644 --- a/third_party/WebKit/Source/core/fileapi/FileReaderLoader.cpp +++ b/third_party/WebKit/Source/core/fileapi/FileReaderLoader.cpp
@@ -118,12 +118,14 @@ CHECK(!m_loader); if (m_client) { DCHECK(!m_loader); - m_loader = ThreadableLoader::create(*executionContext, this, options, - resourceLoaderOptions); + m_loader = ThreadableLoader::create( + *executionContext, this, options, resourceLoaderOptions, + ThreadableLoader::ClientSpec::kFileReaderLoader); m_loader->start(request); } else { ThreadableLoader::loadResourceSynchronously( - *executionContext, request, *this, options, resourceLoaderOptions); + *executionContext, request, *this, options, resourceLoaderOptions, + ThreadableLoader::ClientSpec::kFileReaderLoader); } }
diff --git a/third_party/WebKit/Source/core/html/HTMLSlotElement.cpp b/third_party/WebKit/Source/core/html/HTMLSlotElement.cpp index 42ce6cf..3f28c62 100644 --- a/third_party/WebKit/Source/core/html/HTMLSlotElement.cpp +++ b/third_party/WebKit/Source/core/html/HTMLSlotElement.cpp
@@ -149,7 +149,6 @@ } void HTMLSlotElement::dispatchSlotChangeEvent() { - m_slotchangeEventEnqueued = false; Event* event = Event::createBubble(EventTypeNames::slotchange); event->setTarget(this); dispatchScopedEvent(event); @@ -331,8 +330,7 @@ void HTMLSlotElement::enqueueSlotChangeEvent() { if (m_slotchangeEventEnqueued) return; - Microtask::enqueueMicrotask(WTF::bind( - &HTMLSlotElement::dispatchSlotChangeEvent, wrapPersistent(this))); + MutationObserver::enqueueSlotChange(*this); m_slotchangeEventEnqueued = true; }
diff --git a/third_party/WebKit/Source/core/html/HTMLSlotElement.h b/third_party/WebKit/Source/core/html/HTMLSlotElement.h index 609f822..babaa81f 100644 --- a/third_party/WebKit/Source/core/html/HTMLSlotElement.h +++ b/third_party/WebKit/Source/core/html/HTMLSlotElement.h
@@ -93,6 +93,8 @@ bool supportsDistribution() const { return isInV1ShadowTree(); } void didSlotChange(SlotChangeType); + void dispatchSlotChangeEvent(); + void clearSlotChangeEventEnqueued() { m_slotchangeEventEnqueued = false; } static AtomicString normalizeSlotName(const AtomicString&); @@ -106,7 +108,6 @@ void willRecalcStyle(StyleRecalcChange) final; void enqueueSlotChangeEvent(); - void dispatchSlotChangeEvent(); HeapVector<Member<Node>> m_assignedNodes; HeapVector<Member<Node>> m_distributedNodes;
diff --git a/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.cpp b/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.cpp index f40059a..cd542a6 100644 --- a/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.cpp +++ b/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.cpp
@@ -58,6 +58,7 @@ #include "wtf/Assertions.h" #include "wtf/PtrUtil.h" #include "wtf/WeakPtr.h" +#include "wtf/debug/Alias.h" #include <memory> namespace blink { @@ -119,6 +120,67 @@ } } +// TODO(yhirano): Remove these when https://crbug.com/667254 is fixed. +void NEVER_INLINE crashWithBlobBytesConsumer() { + const char* name = __func__; + WTF::debug::alias(&name); + CRASH(); +} + +void NEVER_INLINE crashWithEventSource() { + const char* name = __func__; + WTF::debug::alias(&name); + CRASH(); +} + +void NEVER_INLINE crashWithFetchManager() { + const char* name = __func__; + WTF::debug::alias(&name); + CRASH(); +} + +void NEVER_INLINE crashWithFileReaderLoader() { + const char* name = __func__; + WTF::debug::alias(&name); + CRASH(); +} + +void NEVER_INLINE crashWithMainThreadLoaderHolder() { + const char* name = __func__; + WTF::debug::alias(&name); + CRASH(); +} + +void NEVER_INLINE crashWithNotificationImageLoader() { + const char* name = __func__; + WTF::debug::alias(&name); + CRASH(); +} + +void NEVER_INLINE crashWithWebAssociatedURLLoader() { + const char* name = __func__; + WTF::debug::alias(&name); + CRASH(); +} + +void NEVER_INLINE crashWithWorkerScriptLoader() { + const char* name = __func__; + WTF::debug::alias(&name); + CRASH(); +} + +void NEVER_INLINE crashWithXHR() { + const char* name = __func__; + WTF::debug::alias(&name); + CRASH(); +} + +void NEVER_INLINE crashWithTesting() { + const char* name = __func__; + WTF::debug::alias(&name); + CRASH(); +} + } // namespace // Max number of CORS redirects handled in DocumentThreadableLoader. Same number @@ -133,9 +195,10 @@ const ResourceRequest& request, ThreadableLoaderClient& client, const ThreadableLoaderOptions& options, - const ResourceLoaderOptions& resourceLoaderOptions) { + const ResourceLoaderOptions& resourceLoaderOptions, + ClientSpec clientSpec) { (new DocumentThreadableLoader(document, &client, LoadSynchronously, options, - resourceLoaderOptions)) + resourceLoaderOptions, clientSpec)) ->start(request); } @@ -143,9 +206,11 @@ Document& document, ThreadableLoaderClient* client, const ThreadableLoaderOptions& options, - const ResourceLoaderOptions& resourceLoaderOptions) { + const ResourceLoaderOptions& resourceLoaderOptions, + ClientSpec clientSpec) { return new DocumentThreadableLoader(document, client, LoadAsynchronously, - options, resourceLoaderOptions); + options, resourceLoaderOptions, + clientSpec); } DocumentThreadableLoader::DocumentThreadableLoader( @@ -153,8 +218,10 @@ ThreadableLoaderClient* client, BlockingBehavior blockingBehavior, const ThreadableLoaderOptions& options, - const ResourceLoaderOptions& resourceLoaderOptions) + const ResourceLoaderOptions& resourceLoaderOptions, + ClientSpec clientSpec) : m_client(client), + m_clientSpec(clientSpec), m_document(&document), m_options(options), m_resourceLoaderOptions(resourceLoaderOptions), @@ -413,7 +480,42 @@ } DocumentThreadableLoader::~DocumentThreadableLoader() { - CHECK(!m_client); + if (m_client) { + auto clientSpec = m_clientSpec; + WTF::debug::alias(&clientSpec); + switch (m_clientSpec) { + case ClientSpec::kBlobBytesConsumer: + crashWithBlobBytesConsumer(); + break; + case ClientSpec::kEventSource: + crashWithEventSource(); + break; + case ClientSpec::kFetchManager: + crashWithFetchManager(); + break; + case ClientSpec::kFileReaderLoader: + crashWithFileReaderLoader(); + break; + case ClientSpec::kMainThreadLoaderHolder: + crashWithMainThreadLoaderHolder(); + break; + case ClientSpec::kNotificationImageLoader: + crashWithNotificationImageLoader(); + break; + case ClientSpec::kWebAssociatedURLLoader: + crashWithWebAssociatedURLLoader(); + break; + case ClientSpec::kWorkerScriptLoader: + crashWithWorkerScriptLoader(); + break; + case ClientSpec::kXHR: + crashWithXHR(); + break; + case ClientSpec::kTesting: + crashWithTesting(); + break; + } + } DCHECK(!m_resource); }
diff --git a/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.h b/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.h index bf1fb5c..0cfdf4a7 100644 --- a/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.h +++ b/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.h
@@ -62,11 +62,13 @@ const ResourceRequest&, ThreadableLoaderClient&, const ThreadableLoaderOptions&, - const ResourceLoaderOptions&); + const ResourceLoaderOptions&, + ThreadableLoader::ClientSpec); static DocumentThreadableLoader* create(Document&, ThreadableLoaderClient*, const ThreadableLoaderOptions&, - const ResourceLoaderOptions&); + const ResourceLoaderOptions&, + ThreadableLoader::ClientSpec); ~DocumentThreadableLoader() override; void start(const ResourceRequest&) override; @@ -85,7 +87,8 @@ ThreadableLoaderClient*, BlockingBehavior, const ThreadableLoaderOptions&, - const ResourceLoaderOptions&); + const ResourceLoaderOptions&, + ClientSpec); void clear(); @@ -185,6 +188,7 @@ Document& document() const; ThreadableLoaderClient* m_client; + const ClientSpec m_clientSpec; Member<Document> m_document; const ThreadableLoaderOptions m_options;
diff --git a/third_party/WebKit/Source/core/loader/ThreadableLoader.cpp b/third_party/WebKit/Source/core/loader/ThreadableLoader.cpp index 11cedc5..1fee35a7 100644 --- a/third_party/WebKit/Source/core/loader/ThreadableLoader.cpp +++ b/third_party/WebKit/Source/core/loader/ThreadableLoader.cpp
@@ -42,7 +42,8 @@ ExecutionContext& context, ThreadableLoaderClient* client, const ThreadableLoaderOptions& options, - const ResourceLoaderOptions& resourceLoaderOptions) { + const ResourceLoaderOptions& resourceLoaderOptions, + ClientSpec clientSpec) { DCHECK(client); if (context.isWorkerGlobalScope()) { @@ -51,7 +52,7 @@ } return DocumentThreadableLoader::create(toDocument(context), client, options, - resourceLoaderOptions); + resourceLoaderOptions, clientSpec); } void ThreadableLoader::loadResourceSynchronously( @@ -59,7 +60,8 @@ const ResourceRequest& request, ThreadableLoaderClient& client, const ThreadableLoaderOptions& options, - const ResourceLoaderOptions& resourceLoaderOptions) { + const ResourceLoaderOptions& resourceLoaderOptions, + ClientSpec clientSpec) { if (context.isWorkerGlobalScope()) { WorkerThreadableLoader::loadResourceSynchronously( toWorkerGlobalScope(context), request, client, options, @@ -68,7 +70,8 @@ } DocumentThreadableLoader::loadResourceSynchronously( - toDocument(context), request, client, options, resourceLoaderOptions); + toDocument(context), request, client, options, resourceLoaderOptions, + clientSpec); } } // namespace blink
diff --git a/third_party/WebKit/Source/core/loader/ThreadableLoader.h b/third_party/WebKit/Source/core/loader/ThreadableLoader.h index 9e8c56c..39618fe 100644 --- a/third_party/WebKit/Source/core/loader/ThreadableLoader.h +++ b/third_party/WebKit/Source/core/loader/ThreadableLoader.h
@@ -131,11 +131,26 @@ WTF_MAKE_NONCOPYABLE(ThreadableLoader); public: + // TODO(yhirano): Remove this enum once https://crbug.com/667254 is fixed. + enum class ClientSpec { + kBlobBytesConsumer, + kEventSource, + kFetchManager, + kFileReaderLoader, + kMainThreadLoaderHolder, + kNotificationImageLoader, + kWebAssociatedURLLoader, + kWorkerScriptLoader, + kXHR, + kTesting, + }; + static void loadResourceSynchronously(ExecutionContext&, const ResourceRequest&, ThreadableLoaderClient&, const ThreadableLoaderOptions&, - const ResourceLoaderOptions&); + const ResourceLoaderOptions&, + ClientSpec); // This method never returns nullptr. // @@ -171,7 +186,8 @@ static ThreadableLoader* create(ExecutionContext&, ThreadableLoaderClient*, const ThreadableLoaderOptions&, - const ResourceLoaderOptions&); + const ResourceLoaderOptions&, + ClientSpec); // The methods on the ThreadableLoaderClient passed on create() call // may be called synchronous to start() call.
diff --git a/third_party/WebKit/Source/core/loader/ThreadableLoaderTest.cpp b/third_party/WebKit/Source/core/loader/ThreadableLoaderTest.cpp index de7b728..41ebcca 100644 --- a/third_party/WebKit/Source/core/loader/ThreadableLoaderTest.cpp +++ b/third_party/WebKit/Source/core/loader/ThreadableLoaderTest.cpp
@@ -128,8 +128,9 @@ ThreadableLoaderOptions options; options.crossOriginRequestPolicy = crossOriginRequestPolicy; ResourceLoaderOptions resourceLoaderOptions; - m_loader = DocumentThreadableLoader::create(document(), client, options, - resourceLoaderOptions); + m_loader = DocumentThreadableLoader::create( + document(), client, options, resourceLoaderOptions, + ThreadableLoader::ClientSpec::kTesting); } void startLoader(const ResourceRequest& request) override { @@ -300,7 +301,8 @@ DCHECK(m_workerThread->globalScope()->isWorkerGlobalScope()); m_loader = ThreadableLoader::create(*m_workerThread->globalScope(), client, - options, resourceLoaderOptions); + options, resourceLoaderOptions, + ThreadableLoader::ClientSpec::kTesting); DCHECK(m_loader); event->signal(); }
diff --git a/third_party/WebKit/Source/core/loader/WorkerThreadableLoader.cpp b/third_party/WebKit/Source/core/loader/WorkerThreadableLoader.cpp index f54172d4..f0e49d8 100644 --- a/third_party/WebKit/Source/core/loader/WorkerThreadableLoader.cpp +++ b/third_party/WebKit/Source/core/loader/WorkerThreadableLoader.cpp
@@ -671,8 +671,9 @@ resourceLoaderOptions.requestInitiatorContext = WorkerContext; // TODO(yhirano): Remove this CHECK once https://crbug.com/667254 is fixed. CHECK(!m_mainThreadLoader); - m_mainThreadLoader = DocumentThreadableLoader::create(document, this, options, - resourceLoaderOptions); + m_mainThreadLoader = DocumentThreadableLoader::create( + document, this, options, resourceLoaderOptions, + ThreadableLoader::ClientSpec::kMainThreadLoaderHolder); m_mainThreadLoader->start(ResourceRequest(request.get())); }
diff --git a/third_party/WebKit/Source/core/workers/WorkerScriptLoader.cpp b/third_party/WebKit/Source/core/workers/WorkerScriptLoader.cpp index 64d6f9b..5fe8c88 100644 --- a/third_party/WebKit/Source/core/workers/WorkerScriptLoader.cpp +++ b/third_party/WebKit/Source/core/workers/WorkerScriptLoader.cpp
@@ -112,8 +112,9 @@ m_needToCancel = true; // TODO(yhirano): Remove this CHECK once https://crbug.com/667254 is fixed. CHECK(!m_threadableLoader); - m_threadableLoader = ThreadableLoader::create(executionContext, this, options, - resourceLoaderOptions); + m_threadableLoader = ThreadableLoader::create( + executionContext, this, options, resourceLoaderOptions, + ThreadableLoader::ClientSpec::kWorkerScriptLoader); m_threadableLoader->start(request); if (m_failed) notifyFinished();
diff --git a/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.cpp b/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.cpp index 74da603..438a1786 100644 --- a/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.cpp +++ b/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.cpp
@@ -1046,7 +1046,8 @@ CHECK(!m_loader); DCHECK(m_sendFlag); m_loader = ThreadableLoader::create(executionContext, this, options, - resourceLoaderOptions); + resourceLoaderOptions, + ThreadableLoader::ClientSpec::kXHR); m_loader->start(request); return; @@ -1056,8 +1057,9 @@ CHECK(!m_loader); // Use count for XHR synchronous requests. UseCounter::count(&executionContext, UseCounter::XMLHttpRequestSynchronous); - ThreadableLoader::loadResourceSynchronously(executionContext, request, *this, - options, resourceLoaderOptions); + ThreadableLoader::loadResourceSynchronously( + executionContext, request, *this, options, resourceLoaderOptions, + ThreadableLoader::ClientSpec::kXHR); throwForLoadFailureIfNeeded(exceptionState, String()); }
diff --git a/third_party/WebKit/Source/modules/budget/BudgetService.cpp b/third_party/WebKit/Source/modules/budget/BudgetService.cpp index 5308d86..1def709 100644 --- a/third_party/WebKit/Source/modules/budget/BudgetService.cpp +++ b/third_party/WebKit/Source/modules/budget/BudgetService.cpp
@@ -114,9 +114,12 @@ // Copy the chunks into the budget array. HeapVector<Member<BudgetState>> budget(expectations.size()); - for (size_t i = 0; i < expectations.size(); i++) - budget[i] = - new BudgetState(expectations[i]->budget_at, expectations[i]->time); + for (size_t i = 0; i < expectations.size(); i++) { + // Return the largest integer less than the budget, so it's easier for + // developer to reason about budget. + budget[i] = new BudgetState(floor(expectations[i]->budget_at), + expectations[i]->time); + } resolver->resolve(budget); }
diff --git a/third_party/WebKit/Source/modules/eventsource/EventSource.cpp b/third_party/WebKit/Source/modules/eventsource/EventSource.cpp index d9eb5be..f8be89b6 100644 --- a/third_party/WebKit/Source/modules/eventsource/EventSource.cpp +++ b/third_party/WebKit/Source/modules/eventsource/EventSource.cpp
@@ -177,8 +177,9 @@ CHECK(!m_loader); // InspectorInstrumentation::documentThreadableLoaderStartedLoadingForClient // will be called synchronously. - m_loader = ThreadableLoader::create(executionContext, this, options, - resourceLoaderOptions); + m_loader = ThreadableLoader::create( + executionContext, this, options, resourceLoaderOptions, + ThreadableLoader::ClientSpec::kEventSource); m_loader->start(request); }
diff --git a/third_party/WebKit/Source/modules/fetch/BlobBytesConsumer.cpp b/third_party/WebKit/Source/modules/fetch/BlobBytesConsumer.cpp index 1ddf1a9..86b65b0 100644 --- a/third_party/WebKit/Source/modules/fetch/BlobBytesConsumer.cpp +++ b/third_party/WebKit/Source/modules/fetch/BlobBytesConsumer.cpp
@@ -278,8 +278,9 @@ ResourceLoaderOptions resourceLoaderOptions; resourceLoaderOptions.dataBufferingPolicy = DoNotBufferData; - return ThreadableLoader::create(*getExecutionContext(), this, options, - resourceLoaderOptions); + return ThreadableLoader::create( + *getExecutionContext(), this, options, resourceLoaderOptions, + ThreadableLoader::ClientSpec::kBlobBytesConsumer); } void BlobBytesConsumer::close() {
diff --git a/third_party/WebKit/Source/modules/fetch/FetchManager.cpp b/third_party/WebKit/Source/modules/fetch/FetchManager.cpp index fb8396e..a14ed48 100644 --- a/third_party/WebKit/Source/modules/fetch/FetchManager.cpp +++ b/third_party/WebKit/Source/modules/fetch/FetchManager.cpp
@@ -840,9 +840,9 @@ InspectorInstrumentation::willStartFetch(m_executionContext, this); // TODO(yhirano): Remove this CHECK once https://crbug.com/667254 is fixed. CHECK(!m_loader); - m_loader = - ThreadableLoader::create(*m_executionContext, this, - threadableLoaderOptions, resourceLoaderOptions); + m_loader = ThreadableLoader::create( + *m_executionContext, this, threadableLoaderOptions, resourceLoaderOptions, + ThreadableLoader::ClientSpec::kFetchManager); m_loader->start(request); } @@ -873,9 +873,9 @@ threadableLoaderOptions.crossOriginRequestPolicy = AllowCrossOriginRequests; InspectorInstrumentation::willStartFetch(m_executionContext, this); - m_loader = - ThreadableLoader::create(*m_executionContext, this, - threadableLoaderOptions, resourceLoaderOptions); + m_loader = ThreadableLoader::create( + *m_executionContext, this, threadableLoaderOptions, resourceLoaderOptions, + ThreadableLoader::ClientSpec::kFetchManager); m_loader->start(request); }
diff --git a/third_party/WebKit/Source/modules/notifications/NotificationImageLoader.cpp b/third_party/WebKit/Source/modules/notifications/NotificationImageLoader.cpp index 9cec819..09f3c76 100644 --- a/third_party/WebKit/Source/modules/notifications/NotificationImageLoader.cpp +++ b/third_party/WebKit/Source/modules/notifications/NotificationImageLoader.cpp
@@ -123,7 +123,8 @@ // TODO(yhirano): Remove this CHECK once https://crbug.com/667254 is fixed. CHECK(!m_threadableLoader); m_threadableLoader = ThreadableLoader::create( - *executionContext, this, threadableLoaderOptions, resourceLoaderOptions); + *executionContext, this, threadableLoaderOptions, resourceLoaderOptions, + ThreadableLoader::ClientSpec::kNotificationImageLoader); m_threadableLoader->start(resourceRequest); }
diff --git a/third_party/WebKit/Source/platform/BUILD.gn b/third_party/WebKit/Source/platform/BUILD.gn index b567a242..41a435f 100644 --- a/third_party/WebKit/Source/platform/BUILD.gn +++ b/third_party/WebKit/Source/platform/BUILD.gn
@@ -1208,6 +1208,8 @@ "scheduler/base/work_queue_sets.cc", "scheduler/base/work_queue_sets.h", "scheduler/child/compositor_worker_scheduler.cc", + "scheduler/child/idle_canceled_delayed_task_sweeper.cc", + "scheduler/child/idle_canceled_delayed_task_sweeper.h", "scheduler/child/idle_helper.cc", "scheduler/child/idle_helper.h", "scheduler/child/scheduler_helper.cc", @@ -1785,6 +1787,7 @@ "scheduler/base/time_domain_unittest.cc", "scheduler/base/work_queue_sets_unittest.cc", "scheduler/base/work_queue_unittest.cc", + "scheduler/child/idle_canceled_delayed_task_sweeper_unittest.cc", "scheduler/child/idle_helper_unittest.cc", "scheduler/child/scheduler_helper_unittest.cc", "scheduler/child/scheduler_tqm_delegate_impl_unittest.cc",
diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_queue_impl.cc b/third_party/WebKit/Source/platform/scheduler/base/task_queue_impl.cc index e3a3b584..a0bc142 100644 --- a/third_party/WebKit/Source/platform/scheduler/base/task_queue_impl.cc +++ b/third_party/WebKit/Source/platform/scheduler/base/task_queue_impl.cc
@@ -814,6 +814,28 @@ return base::MakeUnique<QueueEnabledVoterImpl>(this); } +void TaskQueueImpl::SweepCanceledDelayedTasks(base::TimeTicks now) { + if (main_thread_only().delayed_incoming_queue.empty()) + return; + + base::TimeTicks first_task_runtime = + main_thread_only().delayed_incoming_queue.top().delayed_run_time; + + // TODO(alexclarke): Let this remove all tasks once the DoWork refactor has + // landed. + std::priority_queue<Task> remaining_tasks; + while (!main_thread_only().delayed_incoming_queue.empty()) { + if (!main_thread_only().delayed_incoming_queue.top().task.IsCancelled() || + main_thread_only().delayed_incoming_queue.top().delayed_run_time == + first_task_runtime) { + remaining_tasks.push(std::move( + const_cast<Task&>(main_thread_only().delayed_incoming_queue.top()))); + } + main_thread_only().delayed_incoming_queue.pop(); + } + main_thread_only().delayed_incoming_queue = std::move(remaining_tasks); +} + } // namespace internal } // namespace scheduler } // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_queue_impl.h b/third_party/WebKit/Source/platform/scheduler/base/task_queue_impl.h index f293c5c..6f85115 100644 --- a/third_party/WebKit/Source/platform/scheduler/base/task_queue_impl.h +++ b/third_party/WebKit/Source/platform/scheduler/base/task_queue_impl.h
@@ -212,6 +212,9 @@ bool enabled_; }; + // Iterates over |delayed_incoming_queue| removing canceled tasks. + void SweepCanceledDelayedTasks(base::TimeTicks now); + private: friend class WorkQueue; friend class WorkQueueTest;
diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.cc b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.cc index 74a311b1..cbfc90c 100644 --- a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.cc +++ b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.cc
@@ -494,5 +494,15 @@ return !selector_.EnabledWorkQueuesEmpty(); } +void TaskQueueManager::SweepCanceledDelayedTasks() { + std::map<TimeDomain*, base::TimeTicks> time_domain_now; + for (const scoped_refptr<internal::TaskQueueImpl>& queue : queues_) { + TimeDomain* time_domain = queue->GetTimeDomain(); + if (time_domain_now.find(time_domain) == time_domain_now.end()) + time_domain_now.insert(std::make_pair(time_domain, time_domain->Now())); + queue->SweepCanceledDelayedTasks(time_domain_now[time_domain]); + } +} + } // namespace scheduler } // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.h b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.h index 0fbfa7e..53b9560 100644 --- a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.h +++ b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.h
@@ -140,6 +140,9 @@ // Returns true if there is a task that could be executed immediately. bool HasImmediateWorkForTesting() const; + // Removes all canceled delayed tasks. + void SweepCanceledDelayedTasks(); + private: friend class LazyNow; friend class internal::TaskQueueImpl;
diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_unittest.cc b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_unittest.cc index 97ef5e95..e16b5c6 100644 --- a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_unittest.cc +++ b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_unittest.cc
@@ -2162,5 +2162,43 @@ voter.reset(); } +TEST_F(TaskQueueManagerTest, SweepCanceledDelayedTasks) { + Initialize(1u); + + CancelableTask task1(now_src_.get()); + CancelableTask task2(now_src_.get()); + CancelableTask task3(now_src_.get()); + CancelableTask task4(now_src_.get()); + base::TimeDelta delay1(base::TimeDelta::FromSeconds(5)); + base::TimeDelta delay2(base::TimeDelta::FromSeconds(10)); + base::TimeDelta delay3(base::TimeDelta::FromSeconds(15)); + base::TimeDelta delay4(base::TimeDelta::FromSeconds(30)); + std::vector<base::TimeTicks> run_times; + runners_[0]->PostDelayedTask( + FROM_HERE, base::Bind(&CancelableTask::RecordTimeTask, + task1.weak_factory_.GetWeakPtr(), &run_times), + delay1); + runners_[0]->PostDelayedTask( + FROM_HERE, base::Bind(&CancelableTask::RecordTimeTask, + task2.weak_factory_.GetWeakPtr(), &run_times), + delay2); + runners_[0]->PostDelayedTask( + FROM_HERE, base::Bind(&CancelableTask::RecordTimeTask, + task3.weak_factory_.GetWeakPtr(), &run_times), + delay3); + runners_[0]->PostDelayedTask( + FROM_HERE, base::Bind(&CancelableTask::RecordTimeTask, + task4.weak_factory_.GetWeakPtr(), &run_times), + delay4); + + EXPECT_EQ(4u, runners_[0]->GetNumberOfPendingTasks()); + task2.weak_factory_.InvalidateWeakPtrs(); + task3.weak_factory_.InvalidateWeakPtrs(); + EXPECT_EQ(4u, runners_[0]->GetNumberOfPendingTasks()); + + manager_->SweepCanceledDelayedTasks(); + EXPECT_EQ(2u, runners_[0]->GetNumberOfPendingTasks()); +} + } // namespace scheduler } // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/child/compositor_worker_scheduler.cc b/third_party/WebKit/Source/platform/scheduler/child/compositor_worker_scheduler.cc index 4a8d07cf..d064d35b5 100644 --- a/third_party/WebKit/Source/platform/scheduler/child/compositor_worker_scheduler.cc +++ b/third_party/WebKit/Source/platform/scheduler/child/compositor_worker_scheduler.cc
@@ -175,5 +175,9 @@ void CompositorWorkerScheduler::DidProcessIdleTask() {} +base::TimeTicks CompositorWorkerScheduler::NowTicks() { + return base::TimeTicks::Now(); +} + } // namespace scheduler } // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/child/idle_canceled_delayed_task_sweeper.cc b/third_party/WebKit/Source/platform/scheduler/child/idle_canceled_delayed_task_sweeper.cc new file mode 100644 index 0000000..ed969fb --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/child/idle_canceled_delayed_task_sweeper.cc
@@ -0,0 +1,42 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "platform/scheduler/child/idle_canceled_delayed_task_sweeper.h" + +#include "base/bind.h" + +namespace blink { +namespace scheduler { + +namespace { +const int kDelayedTaskSweepIntervalSeconds = 30; +} + +IdleCanceledDelayedTaskSweeper::IdleCanceledDelayedTaskSweeper( + const char* tracing_category, + SchedulerHelper* scheduler_helper, + scoped_refptr<SingleThreadIdleTaskRunner> idle_task_runner) + : tracing_category_(tracing_category), + scheduler_helper_(scheduler_helper), + idle_task_runner_(idle_task_runner), + weak_factory_(this) { + PostIdleTask(); +} + +void IdleCanceledDelayedTaskSweeper::PostIdleTask() { + idle_task_runner_->PostDelayedIdleTask( + FROM_HERE, base::TimeDelta::FromSeconds(kDelayedTaskSweepIntervalSeconds), + base::Bind(&IdleCanceledDelayedTaskSweeper::SweepIdleTask, + weak_factory_.GetWeakPtr())); +} + +void IdleCanceledDelayedTaskSweeper::SweepIdleTask(base::TimeTicks deadline) { + TRACE_EVENT0(tracing_category_, + "IdleCanceledDelayedTaskSweeper::SweepIdleTask"); + scheduler_helper_->SweepCanceledDelayedTasks(); + PostIdleTask(); +} + +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/child/idle_canceled_delayed_task_sweeper.h b/third_party/WebKit/Source/platform/scheduler/child/idle_canceled_delayed_task_sweeper.h new file mode 100644 index 0000000..7482b147 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/child/idle_canceled_delayed_task_sweeper.h
@@ -0,0 +1,39 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_CHILD_IDLE_CANCELED_DELAYED_TASK_SWEEPER_H_ +#define THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_CHILD_IDLE_CANCELED_DELAYED_TASK_SWEEPER_H_ + +#include "base/macros.h" +#include "platform/scheduler/child/scheduler_helper.h" +#include "public/platform/scheduler/child/single_thread_idle_task_runner.h" + +namespace blink { +namespace scheduler { + +// This class periodically sweeps away canceled delayed tasks, which helps +// reduce memory consumption. +class BLINK_PLATFORM_EXPORT IdleCanceledDelayedTaskSweeper { + public: + IdleCanceledDelayedTaskSweeper( + const char* tracing_category, + SchedulerHelper* scheduler_helper, + scoped_refptr<SingleThreadIdleTaskRunner> idle_task_runner); + + private: + void PostIdleTask(); + void SweepIdleTask(base::TimeTicks deadline); + + const char* tracing_category_; // NOT OWNED + SchedulerHelper* scheduler_helper_; // NOT OWNED + scoped_refptr<SingleThreadIdleTaskRunner> idle_task_runner_; + base::WeakPtrFactory<IdleCanceledDelayedTaskSweeper> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(IdleCanceledDelayedTaskSweeper); +}; + +} // namespace scheduler +} // namespace blink + +#endif // THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_CHILD_IDLE_CANCELED_DELAYED_TASK_SWEEPER_H_
diff --git a/third_party/WebKit/Source/platform/scheduler/child/idle_canceled_delayed_task_sweeper_unittest.cc b/third_party/WebKit/Source/platform/scheduler/child/idle_canceled_delayed_task_sweeper_unittest.cc new file mode 100644 index 0000000..c9802db3 --- /dev/null +++ b/third_party/WebKit/Source/platform/scheduler/child/idle_canceled_delayed_task_sweeper_unittest.cc
@@ -0,0 +1,137 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "platform/scheduler/child/idle_canceled_delayed_task_sweeper.h" + +#include "base/memory/ptr_util.h" +#include "base/test/simple_test_tick_clock.h" +#include "cc/test/ordered_simple_task_runner.h" +#include "public/platform/scheduler/base/task_queue.h" +#include "platform/scheduler/base/lazy_now.h" +#include "platform/scheduler/base/test_time_source.h" +#include "platform/scheduler/child/idle_helper.h" +#include "platform/scheduler/child/scheduler_helper.h" +#include "platform/scheduler/child/scheduler_tqm_delegate_for_test.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace blink { +namespace scheduler { + +class TestClass { + public: + TestClass() : weak_factory_(this) {} + + void NopTask() {} + + base::WeakPtrFactory<TestClass> weak_factory_; +}; + +class IdleCanceledDelayedTaskSweeperTest : public testing::Test, + public IdleHelper::Delegate { + public: + IdleCanceledDelayedTaskSweeperTest() + : clock_(new base::SimpleTestTickClock()), + mock_task_runner_(new cc::OrderedSimpleTaskRunner(clock_.get(), true)), + delegate_(SchedulerTqmDelegateForTest::Create( + mock_task_runner_, + base::WrapUnique(new TestTimeSource(clock_.get())))), + scheduler_helper_(new SchedulerHelper( + delegate_, + "test.scheduler", + TRACE_DISABLED_BY_DEFAULT("test.scheduler"), + TRACE_DISABLED_BY_DEFAULT("test.scheduler.dbg"))), + idle_helper_( + new IdleHelper(scheduler_helper_.get(), + this, + "test.scheduler", + TRACE_DISABLED_BY_DEFAULT("test.scheduler"), + TRACE_DISABLED_BY_DEFAULT("test.scheduler.dbg"), + base::TimeDelta::FromSeconds(30))), + idle_canceled_delayed_taks_sweeper_( + new IdleCanceledDelayedTaskSweeper("test", + scheduler_helper_.get(), + idle_helper_->IdleTaskRunner())), + default_task_runner_(scheduler_helper_->DefaultTaskRunner()) { + clock_->Advance(base::TimeDelta::FromMicroseconds(5000)); + } + + ~IdleCanceledDelayedTaskSweeperTest() override {} + + void TearDown() override { + // Check that all tests stop posting tasks. + mock_task_runner_->SetAutoAdvanceNowToPendingTasks(true); + while (mock_task_runner_->RunUntilIdle()) { + } + } + + // IdleHelper::Delegate implementation: + bool CanEnterLongIdlePeriod( + base::TimeTicks now, + base::TimeDelta* next_long_idle_period_delay_out) override { + return true; + } + void IsNotQuiescent() override {} + void OnIdlePeriodStarted() override {} + void OnIdlePeriodEnded() override {} + + protected: + std::unique_ptr<base::SimpleTestTickClock> clock_; + scoped_refptr<cc::OrderedSimpleTaskRunner> mock_task_runner_; + + scoped_refptr<SchedulerTqmDelegateForTest> delegate_; + std::unique_ptr<SchedulerHelper> scheduler_helper_; + std::unique_ptr<IdleHelper> idle_helper_; + std::unique_ptr<IdleCanceledDelayedTaskSweeper> + idle_canceled_delayed_taks_sweeper_; + scoped_refptr<TaskQueue> default_task_runner_; + + DISALLOW_COPY_AND_ASSIGN(IdleCanceledDelayedTaskSweeperTest); +}; + +TEST_F(IdleCanceledDelayedTaskSweeperTest, TestSweep) { + TestClass class1; + TestClass class2; + + // Post one task we won't cancel. + default_task_runner_->PostDelayedTask( + FROM_HERE, + base::Bind(&TestClass::NopTask, class1.weak_factory_.GetWeakPtr()), + base::TimeDelta::FromSeconds(100)); + + // And a bunch we will. + default_task_runner_->PostDelayedTask( + FROM_HERE, + base::Bind(&TestClass::NopTask, class2.weak_factory_.GetWeakPtr()), + base::TimeDelta::FromSeconds(101)); + + default_task_runner_->PostDelayedTask( + FROM_HERE, + base::Bind(&TestClass::NopTask, class2.weak_factory_.GetWeakPtr()), + base::TimeDelta::FromSeconds(102)); + + default_task_runner_->PostDelayedTask( + FROM_HERE, + base::Bind(&TestClass::NopTask, class2.weak_factory_.GetWeakPtr()), + base::TimeDelta::FromSeconds(103)); + + default_task_runner_->PostDelayedTask( + FROM_HERE, + base::Bind(&TestClass::NopTask, class2.weak_factory_.GetWeakPtr()), + base::TimeDelta::FromSeconds(104)); + + // Cancel the last four tasks. + class2.weak_factory_.InvalidateWeakPtrs(); + + // Give the IdleCanceledDelayedTaskSweeper a chance to run but don't let + // the first non canceled delayed task run. This is important because the + // canceled tasks would get removed by TaskQueueImpl::WakeUpForDelayedWork. + clock_->Advance(base::TimeDelta::FromSeconds(40)); + idle_helper_->EnableLongIdlePeriod(); + mock_task_runner_->RunForPeriod(base::TimeDelta::FromSeconds(40)); + + EXPECT_EQ(1u, default_task_runner_->GetNumberOfPendingTasks()); +} + +} // namespace scheduler +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/child/idle_helper.cc b/third_party/WebKit/Source/platform/scheduler/child/idle_helper.cc index e093552..07a8e08a 100644 --- a/third_party/WebKit/Source/platform/scheduler/child/idle_helper.cc +++ b/third_party/WebKit/Source/platform/scheduler/child/idle_helper.cc
@@ -174,6 +174,9 @@ helper_->CheckOnValidThread(); DCHECK(IsInIdlePeriod(new_state)); + // Allow any ready delayed idle tasks to run. + idle_task_runner_->EnqueueReadyDelayedIdleTasks(); + base::TimeDelta idle_period_duration(idle_period_deadline - now); if (idle_period_duration < base::TimeDelta::FromMilliseconds(kMinimumIdlePeriodDurationMillis)) { @@ -321,6 +324,10 @@ } } +base::TimeTicks IdleHelper::NowTicks() { + return helper_->scheduler_tqm_delegate()->NowTicks(); +} + // static bool IdleHelper::IsInIdlePeriod(IdlePeriodState state) { return state != IdlePeriodState::NOT_IN_IDLE_PERIOD;
diff --git a/third_party/WebKit/Source/platform/scheduler/child/idle_helper.h b/third_party/WebKit/Source/platform/scheduler/child/idle_helper.h index 5f0ccd7..602f1b2e 100644 --- a/third_party/WebKit/Source/platform/scheduler/child/idle_helper.h +++ b/third_party/WebKit/Source/platform/scheduler/child/idle_helper.h
@@ -138,6 +138,7 @@ void OnIdleTaskPosted() override; base::TimeTicks WillProcessIdleTask() override; void DidProcessIdleTask() override; + base::TimeTicks NowTicks() override; // base::MessageLoop::TaskObserver implementation: void WillProcessTask(const base::PendingTask& pending_task) override; @@ -150,6 +151,8 @@ friend class BaseIdleHelperTest; friend class IdleHelperTest; + const scoped_refptr<TaskQueue>& idle_queue() const { return idle_queue_; } + class State { public: State(SchedulerHelper* helper,
diff --git a/third_party/WebKit/Source/platform/scheduler/child/idle_helper_unittest.cc b/third_party/WebKit/Source/platform/scheduler/child/idle_helper_unittest.cc index f7ea8c15e..9826020 100644 --- a/third_party/WebKit/Source/platform/scheduler/child/idle_helper_unittest.cc +++ b/third_party/WebKit/Source/platform/scheduler/child/idle_helper_unittest.cc
@@ -166,7 +166,7 @@ ~IdleHelperForTest() override {} - // SchedulerHelperDelegate implementation: + // IdleHelper::Delegate implementation: MOCK_METHOD2(CanEnterLongIdlePeriod, bool(base::TimeTicks now, base::TimeDelta* next_long_idle_period_delay_out)); @@ -284,6 +284,10 @@ idle_helper_->SchedulerIdlePeriodState())); } + const scoped_refptr<TaskQueue>& idle_queue() const { + return idle_helper_->idle_queue_; + } + std::unique_ptr<base::SimpleTestTickClock> clock_; // Only one of mock_task_runner_ or message_loop_ will be set. scoped_refptr<cc::OrderedSimpleTaskRunner> mock_task_runner_; @@ -1080,5 +1084,39 @@ EXPECT_EQ(0, run_count); } +TEST_F(IdleHelperTest, TestPostDelayedIdleTask) { + int run_count = 0; + base::TimeTicks expected_deadline = + clock_->NowTicks() + base::TimeDelta::FromMilliseconds(2300); + base::TimeTicks deadline_in_task; + + // Posting a delayed idle task should not post anything on the underlying + // task queue until the delay is up. + idle_task_runner_->PostDelayedIdleTask( + FROM_HERE, base::TimeDelta::FromMilliseconds(200), + base::Bind(&IdleTestTask, &run_count, &deadline_in_task)); + EXPECT_EQ(0u, idle_queue()->GetNumberOfPendingTasks()); + + clock_->Advance(base::TimeDelta::FromMilliseconds(100)); + + // It shouldn't run until the delay is over even though we went idle. + idle_helper_->StartIdlePeriod( + IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, clock_->NowTicks(), + expected_deadline); + EXPECT_EQ(0u, idle_queue()->GetNumberOfPendingTasks()); + RunUntilIdle(); + EXPECT_EQ(0, run_count); + + clock_->Advance(base::TimeDelta::FromMilliseconds(100)); + idle_helper_->StartIdlePeriod( + IdleHelper::IdlePeriodState::IN_SHORT_IDLE_PERIOD, clock_->NowTicks(), + expected_deadline); + EXPECT_EQ(1u, idle_queue()->GetNumberOfPendingTasks()); + RunUntilIdle(); + + EXPECT_EQ(1, run_count); + EXPECT_EQ(expected_deadline, deadline_in_task); +} + } // namespace scheduler } // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/child/scheduler_helper.cc b/third_party/WebKit/Source/platform/scheduler/child/scheduler_helper.cc index 5870d2f..f33bffa 100644 --- a/third_party/WebKit/Source/platform/scheduler/child/scheduler_helper.cc +++ b/third_party/WebKit/Source/platform/scheduler/child/scheduler_helper.cc
@@ -129,6 +129,12 @@ task_queue_manager_->SetObserver(this); } +void SchedulerHelper::SweepCanceledDelayedTasks() { + CheckOnValidThread(); + DCHECK(task_queue_manager_); + task_queue_manager_->SweepCanceledDelayedTasks(); +} + RealTimeDomain* SchedulerHelper::real_time_domain() const { CheckOnValidThread(); DCHECK(task_queue_manager_);
diff --git a/third_party/WebKit/Source/platform/scheduler/child/scheduler_helper.h b/third_party/WebKit/Source/platform/scheduler/child/scheduler_helper.h index 220ab7a..3a62d523 100644 --- a/third_party/WebKit/Source/platform/scheduler/child/scheduler_helper.h +++ b/third_party/WebKit/Source/platform/scheduler/child/scheduler_helper.h
@@ -86,6 +86,9 @@ // Note |observer| is expected to outlive the SchedulerHelper. void SetObserver(Observer* observer); + // Remove all canceled delayed tasks. + void SweepCanceledDelayedTasks(); + // Accessor methods. RealTimeDomain* real_time_domain() const; void RegisterTimeDomain(TimeDomain* time_domain);
diff --git a/third_party/WebKit/Source/platform/scheduler/child/single_thread_idle_task_runner.cc b/third_party/WebKit/Source/platform/scheduler/child/single_thread_idle_task_runner.cc index b6df36b6..2ffc75b 100644 --- a/third_party/WebKit/Source/platform/scheduler/child/single_thread_idle_task_runner.cc +++ b/third_party/WebKit/Source/platform/scheduler/child/single_thread_idle_task_runner.cc
@@ -44,6 +44,17 @@ weak_scheduler_ptr_, idle_task)); } +void SingleThreadIdleTaskRunner::PostDelayedIdleTask( + const tracked_objects::Location& from_here, + const base::TimeDelta delay, + const IdleTask& idle_task) { + base::TimeTicks first_run_time = delegate_->NowTicks() + delay; + delayed_idle_tasks_.insert(std::make_pair( + first_run_time, + std::make_pair(from_here, base::Bind(&SingleThreadIdleTaskRunner::RunTask, + weak_scheduler_ptr_, idle_task)))); +} + void SingleThreadIdleTaskRunner::PostNonNestableIdleTask( const tracked_objects::Location& from_here, const IdleTask& idle_task) { @@ -53,6 +64,20 @@ weak_scheduler_ptr_, idle_task)); } +void SingleThreadIdleTaskRunner::EnqueueReadyDelayedIdleTasks() { + if (delayed_idle_tasks_.empty()) + return; + + base::TimeTicks now = delegate_->NowTicks(); + while (!delayed_idle_tasks_.empty() && + delayed_idle_tasks_.begin()->first <= now) { + idle_priority_task_runner_->PostTask( + delayed_idle_tasks_.begin()->second.first, + std::move(delayed_idle_tasks_.begin()->second.second)); + delayed_idle_tasks_.erase(delayed_idle_tasks_.begin()); + } +} + void SingleThreadIdleTaskRunner::RunTask(IdleTask idle_task) { base::TimeTicks deadline = delegate_->WillProcessIdleTask(); TRACE_EVENT1(tracing_category_, "SingleThreadIdleTaskRunner::RunTask",
diff --git a/third_party/WebKit/Source/platform/scheduler/child/worker_scheduler_impl.cc b/third_party/WebKit/Source/platform/scheduler/child/worker_scheduler_impl.cc index 636c10fe..192502a3 100644 --- a/third_party/WebKit/Source/platform/scheduler/child/worker_scheduler_impl.cc +++ b/third_party/WebKit/Source/platform/scheduler/child/worker_scheduler_impl.cc
@@ -24,7 +24,10 @@ "worker.scheduler", TRACE_DISABLED_BY_DEFAULT("worker.scheduler"), "WorkerSchedulerIdlePeriod", - base::TimeDelta::FromMilliseconds(300)) { + base::TimeDelta::FromMilliseconds(300)), + idle_canceled_delayed_task_sweeper_("worker.scheduler", + &helper_, + idle_helper_.IdleTaskRunner()) { initialized_ = false; TRACE_EVENT_OBJECT_CREATED_WITH_ID( TRACE_DISABLED_BY_DEFAULT("worker.scheduler"), "WorkerScheduler", this);
diff --git a/third_party/WebKit/Source/platform/scheduler/child/worker_scheduler_impl.h b/third_party/WebKit/Source/platform/scheduler/child/worker_scheduler_impl.h index a561b05..b6cf8d614 100644 --- a/third_party/WebKit/Source/platform/scheduler/child/worker_scheduler_impl.h +++ b/third_party/WebKit/Source/platform/scheduler/child/worker_scheduler_impl.h
@@ -6,6 +6,7 @@ #define THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_CHILD_WORKER_SCHEDULER_IMPL_H_ #include "base/macros.h" +#include "platform/scheduler/child/idle_canceled_delayed_task_sweeper.h" #include "platform/scheduler/child/idle_helper.h" #include "platform/scheduler/child/scheduler_helper.h" #include "public/platform/scheduler/child/worker_scheduler.h" @@ -50,6 +51,7 @@ SchedulerHelper helper_; IdleHelper idle_helper_; + IdleCanceledDelayedTaskSweeper idle_canceled_delayed_task_sweeper_; bool initialized_; DISALLOW_COPY_AND_ASSIGN(WorkerSchedulerImpl);
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc index 72652c8..130d539 100644 --- a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc +++ b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc
@@ -93,6 +93,9 @@ TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "RendererSchedulerIdlePeriod", base::TimeDelta()), + idle_canceled_delayed_task_sweeper_("renderer.scheduler", + &helper_, + idle_helper_.IdleTaskRunner()), render_widget_scheduler_signals_(this), control_task_runner_(helper_.ControlTaskRunner()), compositor_task_runner_(
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.h b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.h index fe9be1f..a401289 100644 --- a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.h +++ b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.h
@@ -14,6 +14,7 @@ #include "platform/scheduler/base/pollable_thread_safe_flag.h" #include "platform/scheduler/base/queueing_time_estimator.h" #include "platform/scheduler/base/thread_load_tracker.h" +#include "platform/scheduler/child/idle_canceled_delayed_task_sweeper.h" #include "platform/scheduler/child/idle_helper.h" #include "platform/scheduler/child/scheduler_helper.h" #include "platform/scheduler/renderer/deadline_task_runner.h" @@ -376,6 +377,7 @@ SchedulerHelper helper_; IdleHelper idle_helper_; + IdleCanceledDelayedTaskSweeper idle_canceled_delayed_task_sweeper_; std::unique_ptr<TaskQueueThrottler> task_queue_throttler_; RenderWidgetSignals render_widget_scheduler_signals_;
diff --git a/third_party/WebKit/Source/web/WebAssociatedURLLoaderImpl.cpp b/third_party/WebKit/Source/web/WebAssociatedURLLoaderImpl.cpp index 9254db0..a2afce29 100644 --- a/third_party/WebKit/Source/web/WebAssociatedURLLoaderImpl.cpp +++ b/third_party/WebKit/Source/web/WebAssociatedURLLoaderImpl.cpp
@@ -413,7 +413,8 @@ // TODO(yhirano): Remove this CHECK once https://crbug.com/667254 is fixed. CHECK(!m_loader); m_loader = DocumentThreadableLoader::create( - *document, m_clientAdapter.get(), options, resourceLoaderOptions); + *document, m_clientAdapter.get(), options, resourceLoaderOptions, + ThreadableLoader::ClientSpec::kWebAssociatedURLLoader); m_loader->start(webcoreRequest); }
diff --git a/third_party/WebKit/Source/web/tests/WebFrameTest.cpp b/third_party/WebKit/Source/web/tests/WebFrameTest.cpp index 6665c81..e280ce9 100644 --- a/third_party/WebKit/Source/web/tests/WebFrameTest.cpp +++ b/third_party/WebKit/Source/web/tests/WebFrameTest.cpp
@@ -9371,14 +9371,16 @@ options.crossOriginRequestPolicy = UseAccessControl; ResourceLoaderOptions resourceLoaderOptions; DocumentThreadableLoader::loadResourceSynchronously( - *frame->document(), request, client, options, resourceLoaderOptions); + *frame->document(), request, client, options, resourceLoaderOptions, + ThreadableLoader::ClientSpec::kTesting); EXPECT_TRUE(client.failed()); client.reset(); // Try to load the request with cross origin access. Should succeed. options.crossOriginRequestPolicy = AllowCrossOriginRequests; DocumentThreadableLoader::loadResourceSynchronously( - *frame->document(), request, client, options, resourceLoaderOptions); + *frame->document(), request, client, options, resourceLoaderOptions, + ThreadableLoader::ClientSpec::kTesting); EXPECT_FALSE(client.failed()); }
diff --git a/third_party/WebKit/public/platform/scheduler/child/compositor_worker_scheduler.h b/third_party/WebKit/public/platform/scheduler/child/compositor_worker_scheduler.h index 2a17690..e7418031 100644 --- a/third_party/WebKit/public/platform/scheduler/child/compositor_worker_scheduler.h +++ b/third_party/WebKit/public/platform/scheduler/child/compositor_worker_scheduler.h
@@ -42,6 +42,7 @@ void OnIdleTaskPosted() override; base::TimeTicks WillProcessIdleTask() override; void DidProcessIdleTask() override; + base::TimeTicks NowTicks() override; private: base::Thread* thread_;
diff --git a/third_party/WebKit/public/platform/scheduler/child/single_thread_idle_task_runner.h b/third_party/WebKit/public/platform/scheduler/child/single_thread_idle_task_runner.h index 3362c69b..4fd615d 100644 --- a/third_party/WebKit/public/platform/scheduler/child/single_thread_idle_task_runner.h +++ b/third_party/WebKit/public/platform/scheduler/child/single_thread_idle_task_runner.h
@@ -5,6 +5,8 @@ #ifndef THIRD_PARTY_WEBKIT_PUBLIC_PLATFORM_SCHEDULER_CHILD_SINGLE_THREAD_IDLE_TASK_RUNNER_H_ #define THIRD_PARTY_WEBKIT_PUBLIC_PLATFORM_SCHEDULER_CHILD_SINGLE_THREAD_IDLE_TASK_RUNNER_H_ +#include <map> + #include "base/bind.h" #include "base/callback.h" #include "base/macros.h" @@ -22,6 +24,7 @@ namespace blink { namespace scheduler { +class IdleHelper; // A SingleThreadIdleTaskRunner is a task runner for running idle tasks. Idle // tasks have an unbound argument which is bound to a deadline @@ -50,6 +53,9 @@ // Signals that an idle task has finished being run. virtual void DidProcessIdleTask() = 0; + // Returns the current time. + virtual base::TimeTicks NowTicks() = 0; + private: DISALLOW_COPY_AND_ASSIGN(Delegate); }; @@ -64,6 +70,13 @@ virtual void PostIdleTask(const tracked_objects::Location& from_here, const IdleTask& idle_task); + // |idle_task| is eligible to run after the next time an idle period starts + // after |delay|. Note this has after wakeup semantics, i.e. unless something + // else wakes the CPU up, this won't run. + virtual void PostDelayedIdleTask(const tracked_objects::Location& from_here, + const base::TimeDelta delay, + const IdleTask& idle_task); + virtual void PostNonNestableIdleTask( const tracked_objects::Location& from_here, const IdleTask& idle_task); @@ -77,10 +90,17 @@ private: friend class base::RefCountedThreadSafe<SingleThreadIdleTaskRunner>; + friend class IdleHelper; void RunTask(IdleTask idle_task); + void EnqueueReadyDelayedIdleTasks(); + + using DelayedIdleTask = + std::pair<const tracked_objects::Location, base::Closure>; + scoped_refptr<base::SingleThreadTaskRunner> idle_priority_task_runner_; + std::multimap<base::TimeTicks, DelayedIdleTask> delayed_idle_tasks_; Delegate* delegate_; // NOT OWNED const char* tracing_category_; base::trace_event::BlameContext* blame_context_; // Not owned.
diff --git a/third_party/openh264/BUILD.gn b/third_party/openh264/BUILD.gn index ad6c8a6..4301abd 100644 --- a/third_party/openh264/BUILD.gn +++ b/third_party/openh264/BUILD.gn
@@ -3,6 +3,7 @@ # found in the LICENSE file. import("//third_party/openh264/openh264_args.gni") +import("//third_party/openh264/openh264_sources.gni") # Config shared by all openh264 targets. config("config") { @@ -28,58 +29,8 @@ } source_set("common") { - sources = [ - "src/codec/common/inc/WelsCircleQueue.h", - "src/codec/common/inc/WelsList.h", - "src/codec/common/inc/WelsLock.h", - "src/codec/common/inc/WelsTask.h", - "src/codec/common/inc/WelsTaskThread.h", - "src/codec/common/inc/WelsThread.h", - "src/codec/common/inc/WelsThreadLib.h", - "src/codec/common/inc/WelsThreadPool.h", - "src/codec/common/inc/copy_mb.h", - "src/codec/common/inc/cpu.h", - "src/codec/common/inc/cpu_core.h", - "src/codec/common/inc/crt_util_safe_x.h", - "src/codec/common/inc/deblocking_common.h", - "src/codec/common/inc/expand_pic.h", - "src/codec/common/inc/golomb_common.h", - "src/codec/common/inc/intra_pred_common.h", - "src/codec/common/inc/ls_defines.h", - "src/codec/common/inc/macros.h", - "src/codec/common/inc/mc.h", - "src/codec/common/inc/measure_time.h", - "src/codec/common/inc/memory_align.h", - "src/codec/common/inc/sad_common.h", - "src/codec/common/inc/typedefs.h", - "src/codec/common/inc/utils.h", - "src/codec/common/inc/version.h", - "src/codec/common/inc/welsCodecTrace.h", - "src/codec/common/inc/wels_common_defs.h", - "src/codec/common/inc/wels_const_common.h", - "src/codec/common/src/WelsTaskThread.cpp", - "src/codec/common/src/WelsThread.cpp", - "src/codec/common/src/WelsThreadLib.cpp", - "src/codec/common/src/WelsThreadPool.cpp", - "src/codec/common/src/common_tables.cpp", - "src/codec/common/src/copy_mb.cpp", - "src/codec/common/src/cpu.cpp", - "src/codec/common/src/crt_util_safe_x.cpp", - "src/codec/common/src/deblocking_common.cpp", - "src/codec/common/src/expand_pic.cpp", - "src/codec/common/src/intra_pred_common.cpp", - "src/codec/common/src/mc.cpp", - "src/codec/common/src/memory_align.cpp", - "src/codec/common/src/sad_common.cpp", - "src/codec/common/src/utils.cpp", - "src/codec/common/src/welsCodecTrace.cpp", - ] - - include_dirs = [ - "src/codec/api/svc", - "src/codec/common/inc", - "src/codec/common/src", - ] + sources = openh264_common_sources + include_dirs = openh264_common_include_dirs configs -= [ "//build/config/compiler:chromium_code" ] configs += [ "//build/config/compiler:no_chromium_code" ] @@ -97,60 +48,8 @@ } source_set("processing") { - sources = [ - "src/codec/processing/interface/IWelsVP.h", - "src/codec/processing/src/adaptivequantization/AdaptiveQuantization.cpp", - "src/codec/processing/src/adaptivequantization/AdaptiveQuantization.h", - "src/codec/processing/src/backgrounddetection/BackgroundDetection.cpp", - "src/codec/processing/src/backgrounddetection/BackgroundDetection.h", - "src/codec/processing/src/common/WelsFrameWork.cpp", - "src/codec/processing/src/common/WelsFrameWork.h", - "src/codec/processing/src/common/WelsFrameWorkEx.cpp", - "src/codec/processing/src/common/common.h", - "src/codec/processing/src/common/memory.cpp", - "src/codec/processing/src/common/memory.h", - "src/codec/processing/src/common/resource.h", - "src/codec/processing/src/common/typedef.h", - "src/codec/processing/src/common/util.h", - "src/codec/processing/src/complexityanalysis/ComplexityAnalysis.cpp", - "src/codec/processing/src/complexityanalysis/ComplexityAnalysis.h", - "src/codec/processing/src/denoise/denoise.cpp", - "src/codec/processing/src/denoise/denoise.h", - "src/codec/processing/src/denoise/denoise_filter.cpp", - "src/codec/processing/src/downsample/downsample.cpp", - "src/codec/processing/src/downsample/downsample.h", - "src/codec/processing/src/downsample/downsamplefuncs.cpp", - "src/codec/processing/src/imagerotate/imagerotate.cpp", - "src/codec/processing/src/imagerotate/imagerotate.h", - "src/codec/processing/src/imagerotate/imagerotatefuncs.cpp", - "src/codec/processing/src/scenechangedetection/SceneChangeDetection.cpp", - "src/codec/processing/src/scenechangedetection/SceneChangeDetection.h", - "src/codec/processing/src/scrolldetection/ScrollDetection.cpp", - "src/codec/processing/src/scrolldetection/ScrollDetection.h", - "src/codec/processing/src/scrolldetection/ScrollDetectionFuncs.cpp", - "src/codec/processing/src/scrolldetection/ScrollDetectionFuncs.h", - "src/codec/processing/src/vaacalc/vaacalcfuncs.cpp", - "src/codec/processing/src/vaacalc/vaacalculation.cpp", - "src/codec/processing/src/vaacalc/vaacalculation.h", - ] - - include_dirs = [ - "src/codec/api/svc", - "src/codec/common/inc", - "src/codec/common/src", - "src/codec/processing/interface", - "src/codec/processing/interface/", - "src/codec/processing/src/adaptivequantization", - "src/codec/processing/src/backgrounddetection", - "src/codec/processing/src/common", - "src/codec/processing/src/complexityanalysis", - "src/codec/processing/src/denoise", - "src/codec/processing/src/downsample", - "src/codec/processing/src/imagerotate", - "src/codec/processing/src/scenechangedetection", - "src/codec/processing/src/scrolldetection", - "src/codec/processing/src/vaacalc", - ] + sources = openh264_processing_sources + include_dirs = openh264_processing_include_dirs configs -= [ "//build/config/compiler:chromium_code" ] configs += [ "//build/config/compiler:no_chromium_code" ] @@ -161,103 +60,8 @@ } source_set("encoder") { - sources = [ - "src/codec/encoder/core/inc/as264_common.h", - "src/codec/encoder/core/inc/au_set.h", - "src/codec/encoder/core/inc/deblocking.h", - "src/codec/encoder/core/inc/decode_mb_aux.h", - "src/codec/encoder/core/inc/dq_map.h", - "src/codec/encoder/core/inc/encode_mb_aux.h", - "src/codec/encoder/core/inc/encoder.h", - "src/codec/encoder/core/inc/encoder_context.h", - "src/codec/encoder/core/inc/extern.h", - "src/codec/encoder/core/inc/get_intra_predictor.h", - "src/codec/encoder/core/inc/mb_cache.h", - "src/codec/encoder/core/inc/md.h", - "src/codec/encoder/core/inc/mt_defs.h", - "src/codec/encoder/core/inc/mv_pred.h", - "src/codec/encoder/core/inc/nal_encap.h", - "src/codec/encoder/core/inc/param_svc.h", - "src/codec/encoder/core/inc/parameter_sets.h", - "src/codec/encoder/core/inc/paraset_strategy.h", - "src/codec/encoder/core/inc/picture.h", - "src/codec/encoder/core/inc/picture_handle.h", - "src/codec/encoder/core/inc/rc.h", - "src/codec/encoder/core/inc/ref_list_mgr_svc.h", - "src/codec/encoder/core/inc/sample.h", - "src/codec/encoder/core/inc/set_mb_syn_cabac.h", - "src/codec/encoder/core/inc/set_mb_syn_cavlc.h", - "src/codec/encoder/core/inc/slice.h", - "src/codec/encoder/core/inc/slice_multi_threading.h", - "src/codec/encoder/core/inc/stat.h", - "src/codec/encoder/core/inc/svc_base_layer_md.h", - "src/codec/encoder/core/inc/svc_enc_frame.h", - "src/codec/encoder/core/inc/svc_enc_golomb.h", - "src/codec/encoder/core/inc/svc_enc_macroblock.h", - "src/codec/encoder/core/inc/svc_enc_slice_segment.h", - "src/codec/encoder/core/inc/svc_encode_mb.h", - "src/codec/encoder/core/inc/svc_encode_slice.h", - "src/codec/encoder/core/inc/svc_mode_decision.h", - "src/codec/encoder/core/inc/svc_motion_estimate.h", - "src/codec/encoder/core/inc/svc_set_mb_syn.h", - "src/codec/encoder/core/inc/svc_set_mb_syn_cavlc.h", - "src/codec/encoder/core/inc/vlc_encoder.h", - "src/codec/encoder/core/inc/wels_common_basis.h", - "src/codec/encoder/core/inc/wels_const.h", - "src/codec/encoder/core/inc/wels_func_ptr_def.h", - "src/codec/encoder/core/inc/wels_preprocess.h", - "src/codec/encoder/core/inc/wels_task_base.h", - "src/codec/encoder/core/inc/wels_task_encoder.h", - "src/codec/encoder/core/inc/wels_task_management.h", - "src/codec/encoder/core/inc/wels_transpose_matrix.h", - "src/codec/encoder/core/src/au_set.cpp", - "src/codec/encoder/core/src/deblocking.cpp", - "src/codec/encoder/core/src/decode_mb_aux.cpp", - "src/codec/encoder/core/src/encode_mb_aux.cpp", - "src/codec/encoder/core/src/encoder.cpp", - "src/codec/encoder/core/src/encoder_data_tables.cpp", - "src/codec/encoder/core/src/encoder_ext.cpp", - "src/codec/encoder/core/src/get_intra_predictor.cpp", - "src/codec/encoder/core/src/md.cpp", - "src/codec/encoder/core/src/mv_pred.cpp", - "src/codec/encoder/core/src/nal_encap.cpp", - "src/codec/encoder/core/src/paraset_strategy.cpp", - "src/codec/encoder/core/src/picture_handle.cpp", - "src/codec/encoder/core/src/ratectl.cpp", - "src/codec/encoder/core/src/ref_list_mgr_svc.cpp", - "src/codec/encoder/core/src/sample.cpp", - "src/codec/encoder/core/src/set_mb_syn_cabac.cpp", - "src/codec/encoder/core/src/set_mb_syn_cavlc.cpp", - "src/codec/encoder/core/src/slice_multi_threading.cpp", - "src/codec/encoder/core/src/svc_base_layer_md.cpp", - "src/codec/encoder/core/src/svc_enc_slice_segment.cpp", - "src/codec/encoder/core/src/svc_encode_mb.cpp", - "src/codec/encoder/core/src/svc_encode_slice.cpp", - "src/codec/encoder/core/src/svc_mode_decision.cpp", - "src/codec/encoder/core/src/svc_motion_estimate.cpp", - "src/codec/encoder/core/src/svc_set_mb_syn_cabac.cpp", - "src/codec/encoder/core/src/svc_set_mb_syn_cavlc.cpp", - "src/codec/encoder/core/src/wels_preprocess.cpp", - "src/codec/encoder/core/src/wels_task_base.cpp", - "src/codec/encoder/core/src/wels_task_encoder.cpp", - "src/codec/encoder/core/src/wels_task_management.cpp", - "src/codec/encoder/plus/inc/welsEncoderExt.h", - "src/codec/encoder/plus/src/welsEncoderExt.cpp", - - # Note: Purposefully excluded: 'src/codec/encoder/plus/src/DllEntry.cpp', - # This file is not built by the OpenH264 original build files. - ] - - include_dirs = [ - "src/codec/api/svc", - "src/codec/common/inc", - "src/codec/common/src", - "src/codec/encoder/core/inc", - "src/codec/encoder/core/src", - "src/codec/encoder/plus/inc", - "src/codec/encoder/plus/src", - "src/codec/processing/interface", - ] + sources = openh264_encoder_sources + include_dirs = openh264_encoder_include_dirs configs -= [ "//build/config/compiler:chromium_code" ] configs += [ "//build/config/compiler:no_chromium_code" ]
diff --git a/third_party/openh264/openh264_sources.gni b/third_party/openh264/openh264_sources.gni new file mode 100644 index 0000000..6f8c4f5 --- /dev/null +++ b/third_party/openh264/openh264_sources.gni
@@ -0,0 +1,289 @@ +# Common +openh264_common_include_dirs = [ + "//third_party/openh264/src/codec/api/svc", + "//third_party/openh264/src/codec/common/inc", + "//third_party/openh264/src/codec/common/src", +] + +openh264_common_sources = [ + "//third_party/openh264/src/codec/common/inc/WelsCircleQueue.h", + "//third_party/openh264/src/codec/common/inc/WelsList.h", + "//third_party/openh264/src/codec/common/inc/WelsLock.h", + "//third_party/openh264/src/codec/common/inc/WelsTask.h", + "//third_party/openh264/src/codec/common/inc/WelsTaskThread.h", + "//third_party/openh264/src/codec/common/inc/WelsThread.h", + "//third_party/openh264/src/codec/common/inc/WelsThreadLib.h", + "//third_party/openh264/src/codec/common/inc/WelsThreadPool.h", + "//third_party/openh264/src/codec/common/inc/copy_mb.h", + "//third_party/openh264/src/codec/common/inc/cpu.h", + "//third_party/openh264/src/codec/common/inc/cpu_core.h", + "//third_party/openh264/src/codec/common/inc/crt_util_safe_x.h", + "//third_party/openh264/src/codec/common/inc/deblocking_common.h", + "//third_party/openh264/src/codec/common/inc/expand_pic.h", + "//third_party/openh264/src/codec/common/inc/golomb_common.h", + "//third_party/openh264/src/codec/common/inc/intra_pred_common.h", + "//third_party/openh264/src/codec/common/inc/ls_defines.h", + "//third_party/openh264/src/codec/common/inc/macros.h", + "//third_party/openh264/src/codec/common/inc/mc.h", + "//third_party/openh264/src/codec/common/inc/measure_time.h", + "//third_party/openh264/src/codec/common/inc/memory_align.h", + "//third_party/openh264/src/codec/common/inc/sad_common.h", + "//third_party/openh264/src/codec/common/inc/typedefs.h", + "//third_party/openh264/src/codec/common/inc/utils.h", + "//third_party/openh264/src/codec/common/inc/version.h", + "//third_party/openh264/src/codec/common/inc/welsCodecTrace.h", + "//third_party/openh264/src/codec/common/inc/wels_common_defs.h", + "//third_party/openh264/src/codec/common/inc/wels_const_common.h", + "//third_party/openh264/src/codec/common/src/WelsTaskThread.cpp", + "//third_party/openh264/src/codec/common/src/WelsThread.cpp", + "//third_party/openh264/src/codec/common/src/WelsThreadLib.cpp", + "//third_party/openh264/src/codec/common/src/WelsThreadPool.cpp", + "//third_party/openh264/src/codec/common/src/common_tables.cpp", + "//third_party/openh264/src/codec/common/src/copy_mb.cpp", + "//third_party/openh264/src/codec/common/src/cpu.cpp", + "//third_party/openh264/src/codec/common/src/crt_util_safe_x.cpp", + "//third_party/openh264/src/codec/common/src/deblocking_common.cpp", + "//third_party/openh264/src/codec/common/src/expand_pic.cpp", + "//third_party/openh264/src/codec/common/src/intra_pred_common.cpp", + "//third_party/openh264/src/codec/common/src/mc.cpp", + "//third_party/openh264/src/codec/common/src/memory_align.cpp", + "//third_party/openh264/src/codec/common/src/sad_common.cpp", + "//third_party/openh264/src/codec/common/src/utils.cpp", + "//third_party/openh264/src/codec/common/src/welsCodecTrace.cpp", +] + +openh264_common_sources_asm_x86 = [ + "//third_party/openh264/src/codec/common/x86/asm_inc.asm", + "//third_party/openh264/src/codec/common/x86/cpuid.asm", + "//third_party/openh264/src/codec/common/x86/dct.asm", + "//third_party/openh264/src/codec/common/x86/deblock.asm", + "//third_party/openh264/src/codec/common/x86/expand_picture.asm", + "//third_party/openh264/src/codec/common/x86/intra_pred_com.asm", + "//third_party/openh264/src/codec/common/x86/mb_copy.asm", + "//third_party/openh264/src/codec/common/x86/mc_chroma.asm", + "//third_party/openh264/src/codec/common/x86/mc_luma.asm", + "//third_party/openh264/src/codec/common/x86/satd_sad.asm", + "//third_party/openh264/src/codec/common/x86/vaa.asm", +] + +openh264_common_sources_asm_arm = [ + "//third_party/openh264/src/codec/common/arm/arm_arch_common_macro.S", + "//third_party/openh264/src/codec/common/arm/copy_mb_neon.S", + "//third_party/openh264/src/codec/common/arm/deblocking_neon.S", + "//third_party/openh264/src/codec/common/arm/intra_pred_common_neo.S", + "//third_party/openh264/src/codec/common/arm/mc_neon.S", +] + +openh264_common_sources_asm_arm64 = [ + "//third_party/openh264/src/codec/common/arm64/arm_arch64_common_macro.S", + "//third_party/openh264/src/codec/common/arm64/copy_mb_aarch64_neon.S", + "//third_party/openh264/src/codec/common/arm64/deblocking_aarch64_neon.S", + "//third_party/openh264/src/codec/common/arm64/expand_picture_aarch64_neon.S", + "//third_party/openh264/src/codec/common/arm64/intra_pred_common_aarch64_neon.S", + "//third_party/openh264/src/codec/common/arm64/mc_aarch64_neon.S", +] + +# Processing +openh264_processing_include_dirs = [ + "//third_party/openh264/src/codec/api/svc", + "//third_party/openh264/src/codec/common/inc", + "//third_party/openh264/src/codec/common/src", + "//third_party/openh264/src/codec/common/x86", + "//third_party/openh264/src/codec/processing/interface", + "//third_party/openh264/src/codec/processing/src/adaptivequantization", + "//third_party/openh264/src/codec/processing/src/backgrounddetection", + "//third_party/openh264/src/codec/processing/src/common", + "//third_party/openh264/src/codec/processing/src/complexityanalysis", + "//third_party/openh264/src/codec/processing/src/denoise", + "//third_party/openh264/src/codec/processing/src/downsample", + "//third_party/openh264/src/codec/processing/src/imagerotate", + "//third_party/openh264/src/codec/processing/src/scenechangedetection", + "//third_party/openh264/src/codec/processing/src/scrolldetection", + "//third_party/openh264/src/codec/processing/src/vaacalc", +] + +openh264_processing_sources = [ + "//third_party/openh264/src/codec/processing/interface/IWelsVP.h", + "//third_party/openh264/src/codec/processing/src/adaptivequantization/AdaptiveQuantization.cpp", + "//third_party/openh264/src/codec/processing/src/adaptivequantization/AdaptiveQuantization.h", + "//third_party/openh264/src/codec/processing/src/backgrounddetection/BackgroundDetection.cpp", + "//third_party/openh264/src/codec/processing/src/backgrounddetection/BackgroundDetection.h", + "//third_party/openh264/src/codec/processing/src/common/WelsFrameWork.cpp", + "//third_party/openh264/src/codec/processing/src/common/WelsFrameWork.h", + "//third_party/openh264/src/codec/processing/src/common/WelsFrameWorkEx.cpp", + "//third_party/openh264/src/codec/processing/src/common/common.h", + "//third_party/openh264/src/codec/processing/src/common/memory.cpp", + "//third_party/openh264/src/codec/processing/src/common/memory.h", + "//third_party/openh264/src/codec/processing/src/common/resource.h", + "//third_party/openh264/src/codec/processing/src/common/typedef.h", + "//third_party/openh264/src/codec/processing/src/common/util.h", + "//third_party/openh264/src/codec/processing/src/complexityanalysis/ComplexityAnalysis.cpp", + "//third_party/openh264/src/codec/processing/src/complexityanalysis/ComplexityAnalysis.h", + "//third_party/openh264/src/codec/processing/src/denoise/denoise.cpp", + "//third_party/openh264/src/codec/processing/src/denoise/denoise.h", + "//third_party/openh264/src/codec/processing/src/denoise/denoise_filter.cpp", + "//third_party/openh264/src/codec/processing/src/downsample/downsample.cpp", + "//third_party/openh264/src/codec/processing/src/downsample/downsample.h", + "//third_party/openh264/src/codec/processing/src/downsample/downsamplefuncs.cpp", + "//third_party/openh264/src/codec/processing/src/imagerotate/imagerotate.cpp", + "//third_party/openh264/src/codec/processing/src/imagerotate/imagerotate.h", + "//third_party/openh264/src/codec/processing/src/imagerotate/imagerotatefuncs.cpp", + "//third_party/openh264/src/codec/processing/src/scenechangedetection/SceneChangeDetection.cpp", + "//third_party/openh264/src/codec/processing/src/scenechangedetection/SceneChangeDetection.h", + "//third_party/openh264/src/codec/processing/src/scrolldetection/ScrollDetection.cpp", + "//third_party/openh264/src/codec/processing/src/scrolldetection/ScrollDetection.h", + "//third_party/openh264/src/codec/processing/src/scrolldetection/ScrollDetectionFuncs.cpp", + "//third_party/openh264/src/codec/processing/src/scrolldetection/ScrollDetectionFuncs.h", + "//third_party/openh264/src/codec/processing/src/vaacalc/vaacalcfuncs.cpp", + "//third_party/openh264/src/codec/processing/src/vaacalc/vaacalculation.cpp", + "//third_party/openh264/src/codec/processing/src/vaacalc/vaacalculation.h", +] + +openh264_processing_sources_asm_x86 = [ + "//third_party/openh264/src/codec/processing/src/x86/denoisefilter.asm", + "//third_party/openh264/src/codec/processing/src/x86/downsample_bilinear.asm", + "//third_party/openh264/src/codec/processing/src/x86/vaa.asm", +] + +openh264_processing_sources_asm_arm = [ + "//third_party/openh264/src/codec/processing/src/arm/adaptive_quantization.S", + "//third_party/openh264/src/codec/processing/src/arm/down_sample_neon.S", + "//third_party/openh264/src/codec/processing/src/arm/pixel_sad_neon.S", + "//third_party/openh264/src/codec/processing/src/arm/vaa_calc_neon.S", +] + +openh264_processing_sources_asm_arm64 = [ + "//third_party/openh264/src/codec/processing/src/arm64/adaptive_quantization_aarch64_neon.S", + "//third_party/openh264/src/codec/processing/src/arm64/down_sample_aarch64_neon.S", + "//third_party/openh264/src/codec/processing/src/arm64/pixel_sad_aarch64_neon.S", + "//third_party/openh264/src/codec/processing/src/arm64/vaa_calc_aarch64_neon.S", +] + +# Encoder +openh264_encoder_include_dirs = [ + "//third_party/openh264/src/codec/api/svc", + "//third_party/openh264/src/codec/common/inc", + "//third_party/openh264/src/codec/common/src", + "//third_party/openh264/src/codec/common/x86", + "//third_party/openh264/src/codec/encoder/core/inc", + "//third_party/openh264/src/codec/encoder/core/src", + "//third_party/openh264/src/codec/encoder/plus/inc", + "//third_party/openh264/src/codec/encoder/plus/src", + "//third_party/openh264/src/codec/processing/interface", +] + +openh264_encoder_sources = [ + "//third_party/openh264/src/codec/encoder/core/inc/as264_common.h", + "//third_party/openh264/src/codec/encoder/core/inc/au_set.h", + "//third_party/openh264/src/codec/encoder/core/inc/deblocking.h", + "//third_party/openh264/src/codec/encoder/core/inc/decode_mb_aux.h", + "//third_party/openh264/src/codec/encoder/core/inc/dq_map.h", + "//third_party/openh264/src/codec/encoder/core/inc/encode_mb_aux.h", + "//third_party/openh264/src/codec/encoder/core/inc/encoder.h", + "//third_party/openh264/src/codec/encoder/core/inc/encoder_context.h", + "//third_party/openh264/src/codec/encoder/core/inc/extern.h", + "//third_party/openh264/src/codec/encoder/core/inc/get_intra_predictor.h", + "//third_party/openh264/src/codec/encoder/core/inc/mb_cache.h", + "//third_party/openh264/src/codec/encoder/core/inc/md.h", + "//third_party/openh264/src/codec/encoder/core/inc/mt_defs.h", + "//third_party/openh264/src/codec/encoder/core/inc/mv_pred.h", + "//third_party/openh264/src/codec/encoder/core/inc/nal_encap.h", + "//third_party/openh264/src/codec/encoder/core/inc/param_svc.h", + "//third_party/openh264/src/codec/encoder/core/inc/parameter_sets.h", + "//third_party/openh264/src/codec/encoder/core/inc/paraset_strategy.h", + "//third_party/openh264/src/codec/encoder/core/inc/picture.h", + "//third_party/openh264/src/codec/encoder/core/inc/picture_handle.h", + "//third_party/openh264/src/codec/encoder/core/inc/rc.h", + "//third_party/openh264/src/codec/encoder/core/inc/ref_list_mgr_svc.h", + "//third_party/openh264/src/codec/encoder/core/inc/sample.h", + "//third_party/openh264/src/codec/encoder/core/inc/set_mb_syn_cabac.h", + "//third_party/openh264/src/codec/encoder/core/inc/set_mb_syn_cavlc.h", + "//third_party/openh264/src/codec/encoder/core/inc/slice.h", + "//third_party/openh264/src/codec/encoder/core/inc/slice_multi_threading.h", + "//third_party/openh264/src/codec/encoder/core/inc/stat.h", + "//third_party/openh264/src/codec/encoder/core/inc/svc_base_layer_md.h", + "//third_party/openh264/src/codec/encoder/core/inc/svc_enc_frame.h", + "//third_party/openh264/src/codec/encoder/core/inc/svc_enc_golomb.h", + "//third_party/openh264/src/codec/encoder/core/inc/svc_enc_macroblock.h", + "//third_party/openh264/src/codec/encoder/core/inc/svc_enc_slice_segment.h", + "//third_party/openh264/src/codec/encoder/core/inc/svc_encode_mb.h", + "//third_party/openh264/src/codec/encoder/core/inc/svc_encode_slice.h", + "//third_party/openh264/src/codec/encoder/core/inc/svc_mode_decision.h", + "//third_party/openh264/src/codec/encoder/core/inc/svc_motion_estimate.h", + "//third_party/openh264/src/codec/encoder/core/inc/svc_set_mb_syn.h", + "//third_party/openh264/src/codec/encoder/core/inc/svc_set_mb_syn_cavlc.h", + "//third_party/openh264/src/codec/encoder/core/inc/vlc_encoder.h", + "//third_party/openh264/src/codec/encoder/core/inc/wels_common_basis.h", + "//third_party/openh264/src/codec/encoder/core/inc/wels_const.h", + "//third_party/openh264/src/codec/encoder/core/inc/wels_func_ptr_def.h", + "//third_party/openh264/src/codec/encoder/core/inc/wels_preprocess.h", + "//third_party/openh264/src/codec/encoder/core/inc/wels_task_base.h", + "//third_party/openh264/src/codec/encoder/core/inc/wels_task_encoder.h", + "//third_party/openh264/src/codec/encoder/core/inc/wels_task_management.h", + "//third_party/openh264/src/codec/encoder/core/inc/wels_transpose_matrix.h", + "//third_party/openh264/src/codec/encoder/core/src/au_set.cpp", + "//third_party/openh264/src/codec/encoder/core/src/deblocking.cpp", + "//third_party/openh264/src/codec/encoder/core/src/decode_mb_aux.cpp", + "//third_party/openh264/src/codec/encoder/core/src/encode_mb_aux.cpp", + "//third_party/openh264/src/codec/encoder/core/src/encoder.cpp", + "//third_party/openh264/src/codec/encoder/core/src/encoder_data_tables.cpp", + "//third_party/openh264/src/codec/encoder/core/src/encoder_ext.cpp", + "//third_party/openh264/src/codec/encoder/core/src/get_intra_predictor.cpp", + "//third_party/openh264/src/codec/encoder/core/src/md.cpp", + "//third_party/openh264/src/codec/encoder/core/src/mv_pred.cpp", + "//third_party/openh264/src/codec/encoder/core/src/nal_encap.cpp", + "//third_party/openh264/src/codec/encoder/core/src/paraset_strategy.cpp", + "//third_party/openh264/src/codec/encoder/core/src/picture_handle.cpp", + "//third_party/openh264/src/codec/encoder/core/src/ratectl.cpp", + "//third_party/openh264/src/codec/encoder/core/src/ref_list_mgr_svc.cpp", + "//third_party/openh264/src/codec/encoder/core/src/sample.cpp", + "//third_party/openh264/src/codec/encoder/core/src/set_mb_syn_cabac.cpp", + "//third_party/openh264/src/codec/encoder/core/src/set_mb_syn_cavlc.cpp", + "//third_party/openh264/src/codec/encoder/core/src/slice_multi_threading.cpp", + "//third_party/openh264/src/codec/encoder/core/src/svc_base_layer_md.cpp", + "//third_party/openh264/src/codec/encoder/core/src/svc_enc_slice_segment.cpp", + "//third_party/openh264/src/codec/encoder/core/src/svc_encode_mb.cpp", + "//third_party/openh264/src/codec/encoder/core/src/svc_encode_slice.cpp", + "//third_party/openh264/src/codec/encoder/core/src/svc_mode_decision.cpp", + "//third_party/openh264/src/codec/encoder/core/src/svc_motion_estimate.cpp", + "//third_party/openh264/src/codec/encoder/core/src/svc_set_mb_syn_cabac.cpp", + "//third_party/openh264/src/codec/encoder/core/src/svc_set_mb_syn_cavlc.cpp", + "//third_party/openh264/src/codec/encoder/core/src/wels_preprocess.cpp", + "//third_party/openh264/src/codec/encoder/core/src/wels_task_base.cpp", + "//third_party/openh264/src/codec/encoder/core/src/wels_task_encoder.cpp", + "//third_party/openh264/src/codec/encoder/core/src/wels_task_management.cpp", + "//third_party/openh264/src/codec/encoder/plus/inc/welsEncoderExt.h", + "//third_party/openh264/src/codec/encoder/plus/src/welsEncoderExt.cpp", + + # Note: Purposefully excluded: 'src/codec/encoder/plus/src/DllEntry.cpp', + # This file is not built by the OpenH264 original build files. +] + +openh264_encoder_sources_asm_x86 = [ + "//third_party/openh264/src/codec/encoder/core/x86/coeff.asm", + "//third_party/openh264/src/codec/encoder/core/x86/dct.asm", + "//third_party/openh264/src/codec/encoder/core/x86/intra_pred.asm", + "//third_party/openh264/src/codec/encoder/core/x86/matrix_transpose.asm", + "//third_party/openh264/src/codec/encoder/core/x86/memzero.asm", + "//third_party/openh264/src/codec/encoder/core/x86/quant.asm", + "//third_party/openh264/src/codec/encoder/core/x86/sample_sc.asm", + "//third_party/openh264/src/codec/encoder/core/x86/score.asm", +] + +openh264_encoder_sources_asm_arm = [ + "//third_party/openh264/src/codec/encoder/core/arm/intra_pred_neon.S", + "//third_party/openh264/src/codec/encoder/core/arm/intra_pred_sad_3_opt_neon.S", + "//third_party/openh264/src/codec/encoder/core/arm/memory_neon.S", + "//third_party/openh264/src/codec/encoder/core/arm/pixel_neon.S", + "//third_party/openh264/src/codec/encoder/core/arm/reconstruct_neon.S", + "//third_party/openh264/src/codec/encoder/core/arm/svc_motion_estimation.S", +] + +openh264_encoder_sources_asm_arm64 = [ + "//third_party/openh264/src/codec/encoder/core/arm64/intra_pred_aarch64_neon.S", + "//third_party/openh264/src/codec/encoder/core/arm64/intra_pred_sad_3_opt_aarch64_neon.S", + "//third_party/openh264/src/codec/encoder/core/arm64/memory_aarch64_neon.S", + "//third_party/openh264/src/codec/encoder/core/arm64/pixel_aarch64_neon.S", + "//third_party/openh264/src/codec/encoder/core/arm64/reconstruct_aarch64_neon.S", + "//third_party/openh264/src/codec/encoder/core/arm64/svc_motion_estimation_aarch64_neon.S", +]
diff --git a/ui/file_manager/file_manager/foreground/js/file_transfer_controller.js b/ui/file_manager/file_manager/foreground/js/file_transfer_controller.js index 35ecd10..cb390ca 100644 --- a/ui/file_manager/file_manager/foreground/js/file_transfer_controller.js +++ b/ui/file_manager/file_manager/foreground/js/file_transfer_controller.js
@@ -673,7 +673,7 @@ var imagePromise = this.thumbnailModel_.get([entry]).then(function(metadata) { return new Promise(function(fulfill, reject) { var loader = new ThumbnailLoader( - entry, ThumbnailLoader.LoaderType.IMAGE, metadata[0]); + entry, ThumbnailLoader.LoaderType.CANVAS, metadata[0]); loader.loadDetachedImage(function(result) { if (result) fulfill(loader.getImage());
diff --git a/ui/file_manager/file_manager/foreground/js/thumbnail_loader.js b/ui/file_manager/file_manager/foreground/js/thumbnail_loader.js index a5a090a..65d012f 100644 --- a/ui/file_manager/file_manager/foreground/js/thumbnail_loader.js +++ b/ui/file_manager/file_manager/foreground/js/thumbnail_loader.js
@@ -324,6 +324,46 @@ }; /** + * Renders an Image to canvas applying an image transformation. + * @param {Image} image Original image. Can be an unattached one to an elment. + * @param {number} width width of the original image + * @param {number} height height of the original image + * @param {{scaleX:number, scaleY:number, rotate90: number}} transform + * Transform. + * @param {!Object} canvas + */ +ThumbnailLoader.prototype.renderImageToCanvasWithTransform_ = function( + image, width, height, transform, canvas) { + var scaleX = transform.scaleX; + var scaleY = transform.scaleY; + var rotate90 = transform.rotate90; + + assert(scaleX === 1 || scaleX === -1); + assert(scaleY === 1 || scaleY === -1); + assert(rotate90 === 0 || rotate90 === 1); + + var context = canvas.getContext('2d'); + + canvas.width = rotate90 === 1 ? height : width; + canvas.height = rotate90 === 1 ? width : height; + + // Scale transformation should be applied before rotate transformation. + // i.e. When matrices for scale and rotate are A and B, transformation matrix + // should be BA. + + // Rotate 90 degree at center. + if (rotate90 === 1) { + context.translate(height, 0); + context.rotate(Math.PI / 2); + } + + // Flip X and Y. + context.translate(scaleX === -1 ? width : 0, scaleY === -1 ? height : 0); + context.scale(scaleX, scaleY); + context.drawImage(image, 0, 0); +}; + +/** * Applies transform to data url. * * @param {{scaleX:number, scaleY:number, rotate90: number}} transform @@ -338,13 +378,6 @@ ThumbnailLoader.prototype.applyTransformToDataUrl_ = function( transform, dataUrl, width, height) { var image = new Image(); - var scaleX = this.transform_.scaleX; - var scaleY = this.transform_.scaleY; - var rotate90 = this.transform_.rotate90; - - assert(scaleX === 1 || scaleX === -1); - assert(scaleY === 1 || scaleY === -1); - assert(rotate90 === 0 || rotate90 === 1); return new Promise(function(resolve, reject) { // Decode image for transformation. @@ -352,27 +385,9 @@ image.onerror = reject; image.src = dataUrl; }).then(function() { - // Apply transform. Scale transformation should be applied before rotate - // transformation. i.e. When matrices for scale and rotate are A and B, - // transformation matrix should be BA. var canvas = document.createElement('canvas'); - var context = canvas.getContext('2d'); - - canvas.width = rotate90 === 1 ? height : width; - canvas.height = rotate90 === 1 ? width : height; - - // Rotate 90 degree at center. - if (rotate90 === 1) { - context.translate(height, 0); - context.rotate(Math.PI / 2); - } - - // Flip X and Y. - context.translate(scaleX === -1 ? width : 0, scaleY === -1 ? height : 0); - context.scale(scaleX, scaleY); - - context.drawImage(image, 0, 0); - + this.renderImageToCanvasWithTransform_( + image, width, height, this.transform_, canvas); return { data: canvas.toDataURL('image/png'), width: canvas.width, @@ -473,6 +488,8 @@ this.canvas_ = document.createElement('canvas'); // Copy the image to a canvas if the canvas is outdated. + // At this point, image transformation is not applied because we attach style + // attribute to an img element in attachImage() instead. if (!this.canvasUpToDate_) { this.canvas_.width = this.image_.width; this.canvas_.height = this.image_.height; @@ -521,14 +538,22 @@ /** * Gets the loaded image. - * TODO(mtomasz): Apply transformations. * * @return {Image|HTMLCanvasElement} Either image or a canvas object. */ ThumbnailLoader.prototype.getImage = function() { this.renderMedia_(); - return this.loaderType_ === ThumbnailLoader.LoaderType.CANVAS ? this.canvas_ : - this.image_; + if (this.loaderType_ === ThumbnailLoader.LoaderType.IMAGE) + // TODO(yamaguchi): Fix image orientation in case of detached image loaded + // in IMAGE mode. Either apply transformation here or return + // this.transform_ as well. + return this.image_; + if (this.transform_) { + this.renderImageToCanvasWithTransform_( + this.image_, this.image_.width, this.image_.height, + this.transform_, this.canvas_); + } + return this.canvas_; }; /**
diff --git a/ui/file_manager/file_manager/foreground/js/thumbnail_loader_unittest.js b/ui/file_manager/file_manager/foreground/js/thumbnail_loader_unittest.js index 75129e461..f972dd1 100644 --- a/ui/file_manager/file_manager/foreground/js/thumbnail_loader_unittest.js +++ b/ui/file_manager/file_manager/foreground/js/thumbnail_loader_unittest.js
@@ -168,3 +168,40 @@ assertEquals(externalThumbnailDataUrl, result.data); }), callback); } + +function testLoadDetachedFromExifInCavnasModeThumbnailRotate(callback) { + ImageLoaderClient.getInstance = function() { + return { + load: function(url, callback, opt_option) { + // Assert that data url is passed. + assertTrue(/^data:/i.test(url)); + callback({status: 'success', data: url, width: 64, height: 32}); + } + }; + }; + + var metadata = { + thumbnail: { + url: generateSampleImageDataUrl(64, 32), + transform: { + rotate90: 1, + scaleX: 1, + scaleY: -1, + } + } + }; + + var fileSystem = new MockFileSystem('volume-id'); + var entry = new MockEntry(fileSystem, '/Test1.jpg'); + var thumbnailLoader = + new ThumbnailLoader(entry, ThumbnailLoader.LoaderType.CANVAS, metadata); + + reportPromise( + new Promise(function(resolve, reject) { + thumbnailLoader.loadDetachedImage(resolve); + }).then(function() { + var image = thumbnailLoader.getImage(); + assertEquals(32, image.width); + assertEquals(64, image.height); + }), callback); +}
diff --git a/ui/file_manager/gallery/js/gallery_item.js b/ui/file_manager/gallery/js/gallery_item.js index 53c12eb..6829538b 100644 --- a/ui/file_manager/gallery/js/gallery_item.js +++ b/ui/file_manager/gallery/js/gallery_item.js
@@ -440,3 +440,27 @@ this.entry_ = entry; }.bind(this)); }; + +/** + * The threshold size of an image in pixels, which we always use thumbnail + * image for slide-in animation above this. This is a hack to avoid an UI + * unresponsiveness when switching between images. + * @type {number} + * @const + */ +GalleryItem.HEAVY_RENDERING_THRESHOLD_PIXELS = 4000 * 3000; + +/** + * Whether the image requires long rendering time. + * + * @return {boolean} + */ +GalleryItem.prototype.requireLongRenderingTime = function() { + // Check for undefined values. + if (!this.metadataItem_ || + !this.metadataItem_.imageHeight || !this.metadataItem_.imageWidth) + return false; + var numPixels = this.metadataItem_.imageHeight * + this.metadataItem_.imageWidth; + return numPixels > GalleryItem.HEAVY_RENDERING_THRESHOLD_PIXELS; +};
diff --git a/ui/file_manager/gallery/js/image_editor/image_view.js b/ui/file_manager/gallery/js/image_editor/image_view.js index 0ee887f..f97c899 100644 --- a/ui/file_manager/gallery/js/image_editor/image_view.js +++ b/ui/file_manager/gallery/js/image_editor/image_view.js
@@ -138,7 +138,7 @@ * @return {ImageView.LoadTarget} Load target. */ ImageView.getLoadTarget = function(item, effect) { - if (item.contentImage) + if (item.contentImage && !item.requireLongRenderingTime()) return ImageView.LoadTarget.CACHED_MAIN_IMAGE; // Only show thumbnails if there is no effect or the effect is Slide or