Disable idle encoding for layout tests

This CL disables idle encoding in CanvasAsyncBlobCreator for layout tests.
The current timeout deadlines make it possible to wait more than 6 seconds
for the idle encoding to finish, which results in layout tests timeout.

This change also modifies the way slack time before idle task deadline
is calculated, trying to allow idle encoding proceed if we have enough
time to encode a smaller image row.

Bug: 860706
Change-Id: I7fdebcb84cc5ae7840a34126a0b9f1a6c0037f9e
Reviewed-on: https://chromium-review.googlesource.com/1142136
Reviewed-by: Justin Novosad <junov@chromium.org>
Commit-Queue: Mohammad Reza Zakerinasab <zakerinasab@chromium.org>
Cr-Commit-Position: refs/heads/master@{#576871}
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index c970037..1ae8e7d 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -4644,23 +4644,6 @@
 # Sheriff 2018-7-13
 crbug.com/863599 [ Linux Debug ] external/wpt/requestidlecallback/callback-iframe.html [ Pass Timeout ]
 
-#crbug.com/860706
-crbug.com/860706 fast/canvas/color-space/canvas-colorManaged-convertToBlob-roundtrip.html [ Pass Timeout Failure ]
-crbug.com/860706 virtual/gpu/fast/canvas/color-space/canvas-colorManaged-convertToBlob-roundtrip.html [ Pass Timeout Failure ]
-crbug.com/860706 [ Linux Mac ] css3/filters/effect-blur-hw.html [ Timeout Pass ]
-crbug.com/860706 [ Linux Mac ] css3/filters/filter-repaint-composited-fallback-crash.html [ Timeout Pass ]
-crbug.com/860706 [ Linux Mac ] virtual/gpu/fast/canvas/canvas-blending-gradient-over-image.html [ Timeout Pass ]
-crbug.com/860706 [ Linux Mac ] virtual/gpu/fast/canvas/color-space/canvas-createImageBitmap-p3.html [ Timeout Pass ]
-crbug.com/860706 [ Linux Mac ] virtual/gpu-rasterization/images/color-profile-mask-image-svg.html [ Timeout Pass ]
-crbug.com/860706 [ Linux Mac ] virtual/gpu/fast/canvas/canvas-blend-image.html [ Timeout Pass ]
-crbug.com/860706 [ Mac ] virtual/gpu/fast/canvas/canvas-blending-gradient-over-pattern.html [ Timeout Pass ]
-crbug.com/860706 [ Mac ] virtual/gpu/fast/canvas/canvas-blending-pattern-over-image.html [ Timeout Pass ]
-crbug.com/860706 [ Mac ] virtual/gpu/fast/canvas/canvas-blending-image-over-image.html [ Timeout Pass ]
-crbug.com/860706 [ Mac ] virtual/gpu/fast/canvas/color-space/canvas-createImageBitmap-rec2020.html [ Timeout Pass ]
-crbug.com/860706 [ Mac ] virtual/gpu/fast/canvas/canvas-blending-color-over-pattern.html [ Timeout Pass ]
-crbug.com/860706 [ Mac ] virtual/gpu/fast/canvas/canvas-blending-pattern-over-pattern.html [ Timeout Pass ]
-crbug.com/860706 [ Mac ] virtual/gpu/fast/canvas/canvas-shadow-source-in.html [ Timeout Pass ]
-
 crbug.com/864887 [ Linux ] fast/scroll-snap/snaps-after-scrollbar-scrolling.html [ Failure Pass ]
 crbug.com/864888 [ Mac ] editing/selection/offset-from-point-complex-scripts.html [ Failure Pass ]
 crbug.com/864891 [ Mac ] virtual/scroll_customization/fast/scroll-behavior/scroll-customization/scroll-customization-property.html [ Timeout Pass ]
diff --git a/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.cc b/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.cc
index f0dc7b1..5f8b5e90 100644
--- a/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.cc
+++ b/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.cc
@@ -30,8 +30,11 @@
 
 namespace {
 
-// a small slack period between deadline and current time for safety
-constexpr TimeDelta kSlackBeforeDeadline = TimeDelta::FromMilliseconds(1);
+// small slack period between deadline and current time for safety
+constexpr TimeDelta kCreateBlobSlackBeforeDeadline =
+    TimeDelta::FromMilliseconds(1);
+constexpr TimeDelta kEncodeRowSlackBeforeDeadline =
+    TimeDelta::FromMicroseconds(100);
 
 /* The value is based on user statistics on Nov 2017. */
 #if (defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN))
@@ -53,8 +56,19 @@
 const double kIdleTaskCompleteTimeoutDelayMs = 9000.0;
 #endif
 
-bool IsDeadlineNearOrPassed(TimeTicks deadline) {
-  return CurrentTimeTicks() >= deadline - kSlackBeforeDeadline;
+bool IsCreateBlobDeadlineNearOrPassed(TimeTicks deadline) {
+  return CurrentTimeTicks() >= deadline - kCreateBlobSlackBeforeDeadline;
+}
+
+bool IsEncodeRowDeadlineNearOrPassed(TimeTicks deadline, size_t image_width) {
+  // Rough estimate of the row encoding time in micro seconds. We will consider
+  // a slack time later to not pass the idle task deadline.
+  int row_encode_time_us = 1000 * (kIdleTaskCompleteTimeoutDelayMs / 4000.0) *
+                           (image_width / 4000.0);
+  TimeDelta row_encode_time_delta =
+      TimeDelta::FromMicroseconds(row_encode_time_us);
+  return CurrentTimeTicks() >=
+         deadline - row_encode_time_delta - kEncodeRowSlackBeforeDeadline;
 }
 
 String ConvertMimeTypeEnumToString(ImageEncoder::MimeType mime_type_enum) {
@@ -184,6 +198,7 @@
     ExecutionContext* context,
     ScriptPromiseResolver* resolver)
     : fail_encoder_initialization_for_test_(false),
+      enforce_idle_encoding_for_test_(false),
       image_(image),
       context_(context),
       encode_options_(options),
@@ -328,7 +343,8 @@
   std::unique_ptr<ImageDataBuffer> buffer = ImageDataBuffer::Create(src_data_);
   if (!buffer)
     return false;
-  return buffer->EncodeImage("image/webp", quality, &encoded_image_);
+  return buffer->EncodeImage(ConvertMimeTypeEnumToString(mime_type_), quality,
+                             &encoded_image_);
 }
 
 void CanvasAsyncBlobCreator::ScheduleAsyncBlobCreation(const double& quality) {
@@ -339,7 +355,17 @@
                              WrapPersistent(this)));
     return;
   }
-  if (mime_type_ == ImageEncoder::kMimeTypeWebp) {
+  // Webp encoder does not support progressive encoding. We also don't use idle
+  // encoding for layout tests, since the idle task start and completition
+  // deadlines (6.7s or 13s) bypass the layout test running deadline (6s)
+  // and result in timeouts on different tests. We use
+  // enforce_idle_encoding_for_test_ to test idle encoding in unit tests.
+  bool use_idle_encoding =
+      (mime_type_ != ImageEncoder::kMimeTypeWebp) &&
+      (enforce_idle_encoding_for_test_ ||
+       !RuntimeEnabledFeatures::NoIdleEncodingForLayoutTestsEnabled());
+
+  if (!use_idle_encoding) {
     if (!IsMainThread()) {
       DCHECK(function_type_ == kHTMLCanvasConvertToBlobPromise ||
              function_type_ == kOffscreenCanvasConvertToBlobPromise);
@@ -416,7 +442,7 @@
   }
 
   for (int y = num_rows_completed_; y < src_data_.height(); ++y) {
-    if (IsDeadlineNearOrPassed(deadline)) {
+    if (IsEncodeRowDeadlineNearOrPassed(deadline, src_data_.width())) {
       num_rows_completed_ = y;
       Platform::Current()->CurrentThread()->Scheduler()->PostIdleTask(
           FROM_HERE, WTF::Bind(&CanvasAsyncBlobCreator::IdleEncodeRows,
@@ -436,7 +462,7 @@
   TimeDelta elapsed_time =
       WTF::CurrentTimeTicks() - schedule_idle_task_start_time_;
   RecordElapsedTimeHistogram(kCompleteEncodingDelay, mime_type_, elapsed_time);
-  if (IsDeadlineNearOrPassed(deadline)) {
+  if (IsCreateBlobDeadlineNearOrPassed(deadline)) {
     context_->GetTaskRunner(TaskType::kCanvasBlobSerialization)
         ->PostTask(FROM_HERE,
                    WTF::Bind(&CanvasAsyncBlobCreator::CreateBlobAndReturnResult,
@@ -514,8 +540,6 @@
 
 void CanvasAsyncBlobCreator::EncodeImageOnEncoderThread(double quality) {
   DCHECK(!IsMainThread());
-  DCHECK(mime_type_ == ImageEncoder::kMimeTypeWebp);
-
   if (!EncodeImage(quality)) {
     PostCrossThreadTask(
         *parent_frame_task_runner_, FROM_HERE,
diff --git a/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.h b/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.h
index 3b2875d..4e7f119 100644
--- a/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.h
+++ b/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.h
@@ -110,6 +110,7 @@
  protected:
   IdleTaskStatus idle_task_status_;
   bool fail_encoder_initialization_for_test_;
+  bool enforce_idle_encoding_for_test_;
 
  private:
   friend class CanvasAsyncBlobCreatorTest;
diff --git a/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator_test.cc b/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator_test.cc
index e3b5269..13d6a52 100644
--- a/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator_test.cc
+++ b/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator_test.cc
@@ -35,6 +35,7 @@
             nullptr) {
     if (fail_encoder_initialization)
       fail_encoder_initialization_for_test_ = true;
+    enforce_idle_encoding_for_test_ = true;
   }
 
   CanvasAsyncBlobCreator::IdleTaskStatus GetIdleTaskStatus() {
@@ -177,7 +178,7 @@
   EXPECT_CALL(*(AsyncBlobCreator()),
               SignalTaskSwitchInStartTimeoutEventForTesting());
 
-  AsyncBlobCreator()->ScheduleAsyncBlobCreation(true);
+  AsyncBlobCreator()->ScheduleAsyncBlobCreation(1.0);
   test::EnterRunLoop();
 
   testing::Mock::VerifyAndClearExpectations(AsyncBlobCreator());
@@ -195,7 +196,7 @@
   EXPECT_CALL(*(AsyncBlobCreator()),
               SignalTaskSwitchInCompleteTimeoutEventForTesting());
 
-  AsyncBlobCreator()->ScheduleAsyncBlobCreation(true);
+  AsyncBlobCreator()->ScheduleAsyncBlobCreation(1.0);
   test::EnterRunLoop();
 
   testing::Mock::VerifyAndClearExpectations(AsyncBlobCreator());
@@ -209,7 +210,7 @@
   // the idle task status.
   PrepareMockCanvasAsyncBlobCreatorFail();
 
-  AsyncBlobCreator()->ScheduleAsyncBlobCreation(true);
+  AsyncBlobCreator()->ScheduleAsyncBlobCreation(1.0);
   test::EnterRunLoop();
 
   EXPECT_EQ(IdleTaskStatus::kIdleTaskFailed,
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index 933a133..aa77f93 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -840,6 +840,10 @@
       name: "NewRemotePlaybackPipeline",
     },
     {
+      name: "NoIdleEncodingForLayoutTests",
+      status: "test",
+    },
+    {
       name: "NotificationConstructor",
       status: "stable",
     },