diff --git a/DEPS b/DEPS
index a945a12..efd816c 100644
--- a/DEPS
+++ b/DEPS
@@ -78,7 +78,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': 'c431872866ad9df805408af459fb8c0cbf553068',
+  'v8_revision': 'a94bf1a84ab7876bc11a7a7307b77c20d96f58bc',
   # 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.
@@ -639,7 +639,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'd458ada06171a85af00367251a4ed55db7fe2018',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '9106fb6d23603d47bb8f3d63b45c278ff138d119', # commit position 20628
+    Var('webrtc_git') + '/src.git' + '@' + 'da04916bb9ffd832bc239050699bdedfd5efeb53', # commit position 20628
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 6a9a566e1..d96cef4 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -3009,14 +3009,6 @@
      SINGLE_VALUE_TYPE(ash::switches::kAshForceEnableStylusTools)},
 #endif  // defined(OS_CHROMEOS)
 
-#if defined(OS_ANDROID)
-    {"enable-midi-manager-dynamic-instantiation",
-     flag_descriptions::kEnableMidiManagerDynamicInstantiationName,
-     flag_descriptions::kEnableMidiManagerDynamicInstantiationDescription,
-     kOsAll,
-     FEATURE_VALUE_TYPE(midi::features::kMidiManagerDynamicInstantiation)},
-#endif  // defined(OS_ANDROID)
-
 #if defined(OS_WIN)
     {"new-usb-backend", flag_descriptions::kNewUsbBackendName,
      flag_descriptions::kNewUsbBackendDescription, kOsWin,
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index ae28b0b..1f81de4 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -1848,11 +1848,6 @@
 const char kEnableExpandedAutofillCreditCardPopupLayoutDescription[] =
     "If enabled, displays autofill credit card popup using expanded layout.";
 
-const char kEnableMidiManagerDynamicInstantiationName[] =
-    "MIDIManager dynamic instantiation for Web MIDI.";
-const char kEnableMidiManagerDynamicInstantiationDescription[] =
-    "Enable MIDIManager dynamic instantiation for Web MIDI.";
-
 const char kEnableNtpAssetDownloadSuggestionsName[] =
     "Show asset downloads on the New Tab page";
 const char kEnableNtpAssetDownloadSuggestionsDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index d9b08af4..2a471056 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -1141,9 +1141,6 @@
 extern const char kEnableNtpForeignSessionsSuggestionsName[];
 extern const char kEnableNtpForeignSessionsSuggestionsDescription[];
 
-extern const char kEnableMidiManagerDynamicInstantiationName[];
-extern const char kEnableMidiManagerDynamicInstantiationDescription[];
-
 extern const char kEnableNtpOfflinePageDownloadSuggestionsName[];
 extern const char kEnableNtpOfflinePageDownloadSuggestionsDescription[];
 
diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn
index 68c7c0f..a64a0cc 100644
--- a/content/renderer/BUILD.gn
+++ b/content/renderer/BUILD.gn
@@ -914,9 +914,7 @@
       "//jingle:jingle_glue",
       "//third_party/libvpx",
       "//third_party/opus",
-      "//third_party/webrtc/api:libjingle_api_deprecated_headers",
       "//third_party/webrtc/api:libjingle_logging_api",
-      "//third_party/webrtc/api:libjingle_peerconnection",
       "//third_party/webrtc/api:libjingle_peerconnection_api",
       "//third_party/webrtc/api:optional",
       "//third_party/webrtc/api:peerconnection_and_implicit_call_api",
@@ -946,6 +944,8 @@
       "//third_party/webrtc/modules/video_coding:webrtc_h264",
       "//third_party/webrtc/p2p:libstunprober",
       "//third_party/webrtc/p2p:rtc_p2p",
+      "//third_party/webrtc/pc:libjingle_peerconnection",
+      "//third_party/webrtc/pc:peerconnection",
       "//third_party/webrtc/pc:rtc_pc",
       "//third_party/webrtc/pc:rtc_pc_base",
       "//third_party/webrtc/rtc_base:rtc_base",
diff --git a/content/renderer/media/webrtc/media_stream_video_webrtc_sink.cc b/content/renderer/media/webrtc/media_stream_video_webrtc_sink.cc
index 4af35d7..a661434 100644
--- a/content/renderer/media/webrtc/media_stream_video_webrtc_sink.cc
+++ b/content/renderer/media/webrtc/media_stream_video_webrtc_sink.cc
@@ -23,7 +23,7 @@
 #include "content/renderer/media/webrtc/peer_connection_dependency_factory.h"
 #include "media/base/limits.h"
 #include "third_party/webrtc/api/videosourceproxy.h"
-#include "third_party/webrtc/api/videotracksource.h"
+#include "third_party/webrtc/pc/videotracksource.h"
 
 namespace content {
 
diff --git a/content/renderer/media/webrtc/webrtc_audio_sink.h b/content/renderer/media/webrtc/webrtc_audio_sink.h
index 00e3af7..d9a1de5 100644
--- a/content/renderer/media/webrtc/webrtc_audio_sink.h
+++ b/content/renderer/media/webrtc/webrtc_audio_sink.h
@@ -20,7 +20,7 @@
 #include "content/renderer/media/media_stream_audio_processor.h"
 #include "media/base/audio_parameters.h"
 #include "media/base/audio_push_fifo.h"
-#include "third_party/webrtc/api/mediastreamtrack.h"
+#include "third_party/webrtc/pc/mediastreamtrack.h"
 
 namespace content {
 
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index f92337c3..c79bfffe 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -397,12 +397,12 @@
     ]
 
     deps += [
-      "//third_party/webrtc/api:libjingle_peerconnection",
       "//third_party/webrtc/api:libjingle_peerconnection_api",
       "//third_party/webrtc/api:peerconnection_and_implicit_call_api",
       "//third_party/webrtc/api:rtc_stats_api",
       "//third_party/webrtc/media:rtc_media_base",
       "//third_party/webrtc/modules/video_capture",
+      "//third_party/webrtc/pc:libjingle_peerconnection",
       "//third_party/webrtc/rtc_base:rtc_base_approved",
       "//third_party/webrtc/stats:rtc_stats",
       "//third_party/webrtc_overrides:init_webrtc",
@@ -1859,7 +1859,6 @@
       "//services/device/public/interfaces",
       "//third_party/libyuv",
       "//third_party/opus",
-      "//third_party/webrtc/api:libjingle_peerconnection",
       "//third_party/webrtc/api:libjingle_peerconnection_api",
       "//third_party/webrtc/api:peerconnection_and_implicit_call_api",
       "//third_party/webrtc/api:rtc_stats_api",
@@ -1869,6 +1868,7 @@
       "//third_party/webrtc/media:rtc_media",
       "//third_party/webrtc/modules/desktop_capture:primitives",
       "//third_party/webrtc/modules/video_capture",
+      "//third_party/webrtc/pc:libjingle_peerconnection",
       "//third_party/webrtc/rtc_base:rtc_base",
       "//third_party/webrtc/stats:rtc_stats_test_utils",
       "//third_party/webrtc_overrides",
diff --git a/gpu/command_buffer/service/texture_manager.cc b/gpu/command_buffer/service/texture_manager.cc
index 437e0b9..8a2c00c 100644
--- a/gpu/command_buffer/service/texture_manager.cc
+++ b/gpu/command_buffer/service/texture_manager.cc
@@ -9,6 +9,7 @@
 
 #include <algorithm>
 #include <set>
+#include <tuple>
 #include <utility>
 
 #include "base/bits.h"
@@ -283,21 +284,16 @@
   }
 
  private:
-  // TODO(zmo): once std::tuple is allowed, switch over to that.
-  struct FormatType {
-    GLenum internal_format;
-    GLenum format;
-    GLenum type;
-  };
-
+  // FormatType is a tuple of <internal_format, format, type>
+  typedef std::tuple<GLenum, GLenum, GLenum> FormatType;
   struct FormatTypeCompare {
     bool operator() (const FormatType& lhs, const FormatType& rhs) const {
-      return (lhs.internal_format < rhs.internal_format ||
-              ((lhs.internal_format == rhs.internal_format) &&
-               (lhs.format < rhs.format)) ||
-              ((lhs.internal_format == rhs.internal_format) &&
-               (lhs.format == rhs.format) &&
-               (lhs.type < rhs.type)));
+      return (std::get<0>(lhs) < std::get<0>(rhs) ||
+              ((std::get<0>(lhs) == std::get<0>(rhs)) &&
+               (std::get<1>(lhs) < std::get<1>(rhs))) ||
+              ((std::get<0>(lhs) == std::get<0>(rhs)) &&
+               (std::get<1>(lhs) == std::get<1>(rhs)) &&
+               (std::get<2>(lhs) < std::get<2>(rhs))));
     }
   };
 
diff --git a/ios/web/public/test/fakes/test_web_state.h b/ios/web/public/test/fakes/test_web_state.h
index ff54ce2..b6c7253 100644
--- a/ios/web/public/test/fakes/test_web_state.h
+++ b/ios/web/public/test/fakes/test_web_state.h
@@ -82,6 +82,7 @@
   void DidChangeVisibleSecurityState() override {}
   bool HasOpener() const override;
   void SetHasOpener(bool has_opener) override;
+  bool CanTakeSnapshot() const override;
   void TakeSnapshot(const SnapshotCallback& callback,
                     CGSize target_size) const override;
   base::WeakPtr<WebState> AsWeakPtr() override;
diff --git a/ios/web/public/test/fakes/test_web_state.mm b/ios/web/public/test/fakes/test_web_state.mm
index 260cd46f..f212f82 100644
--- a/ios/web/public/test/fakes/test_web_state.mm
+++ b/ios/web/public/test/fakes/test_web_state.mm
@@ -312,6 +312,10 @@
   has_opener_ = has_opener;
 }
 
+bool TestWebState::CanTakeSnapshot() const {
+  return view_ != nil;
+}
+
 void TestWebState::TakeSnapshot(const SnapshotCallback& callback,
                                 CGSize target_size) const {
   callback.Run(gfx::Image([[UIImage alloc] init]));
diff --git a/ios/web/public/web_state/web_state.h b/ios/web/public/web_state/web_state.h
index ddc9bbf..a2859a25 100644
--- a/ios/web/public/web_state/web_state.h
+++ b/ios/web/public/web_state/web_state.h
@@ -297,6 +297,11 @@
   // Callback used to handle snapshots. The parameter is the snapshot image.
   typedef base::Callback<void(const gfx::Image&)> SnapshotCallback;
 
+  // Returns whether there is a view available to generate a snapshot. If
+  // this returns false, then TakeSnapshot will takes a snapshot of an empty
+  // view.
+  virtual bool CanTakeSnapshot() const = 0;
+
   // Takes a snapshot of this WebState with |target_size|. |callback| is
   // asynchronously invoked after performing the snapshot.
   virtual void TakeSnapshot(const SnapshotCallback& callback,
diff --git a/ios/web/web_state/web_state_impl.h b/ios/web/web_state/web_state_impl.h
index db916fa8..dd4f877 100644
--- a/ios/web/web_state/web_state_impl.h
+++ b/ios/web/web_state/web_state_impl.h
@@ -229,6 +229,7 @@
       mojo::ScopedMessagePipeHandle interface_pipe) override;
   bool HasOpener() const override;
   void SetHasOpener(bool has_opener) override;
+  bool CanTakeSnapshot() const override;
   void TakeSnapshot(const SnapshotCallback& callback,
                     CGSize target_size) const override;
   base::WeakPtr<WebState> AsWeakPtr() override;
diff --git a/ios/web/web_state/web_state_impl.mm b/ios/web/web_state/web_state_impl.mm
index 2e142de0..0e8f669 100644
--- a/ios/web/web_state/web_state_impl.mm
+++ b/ios/web/web_state/web_state_impl.mm
@@ -713,6 +713,10 @@
   created_with_opener_ = has_opener;
 }
 
+bool WebStateImpl::CanTakeSnapshot() const {
+  return [web_controller_ canUseViewForGeneratingOverlayPlaceholderView];
+}
+
 void WebStateImpl::TakeSnapshot(const SnapshotCallback& callback,
                                 CGSize target_size) const {
   UIView* view = [web_controller_ view];
diff --git a/ios/web/web_state/web_state_impl_unittest.mm b/ios/web/web_state/web_state_impl_unittest.mm
index fef4bc4..82ba30f 100644
--- a/ios/web/web_state/web_state_impl_unittest.mm
+++ b/ios/web/web_state/web_state_impl_unittest.mm
@@ -826,4 +826,27 @@
   EXPECT_FALSE(observer->update_favicon_url_candidates_info());
 }
 
+// Tests that taking a snapshot after disabling web usage or adding an overlay
+// will force the creation of the WebState's view.
+TEST_F(WebStateImplTest, CanTakeSnapshot) {
+  // The view is lazily created, so taking a snapshot is not possible initially.
+  ASSERT_FALSE(web_state_->CanTakeSnapshot());
+
+  // Enabling overlay does not create the creation of the View.
+  [web_state_->GetWebController() setOverlayPreviewMode:YES];
+  EXPECT_FALSE(web_state_->CanTakeSnapshot());
+
+  // Loading the page will create the view (and add the placeholder overlay).
+  [web_state_->GetWebController() loadCurrentURLIfNecessary];
+  EXPECT_TRUE(web_state_->CanTakeSnapshot());
+
+  // Disabling the overlay will remove the view.
+  [web_state_->GetWebController() setOverlayPreviewMode:NO];
+  EXPECT_FALSE(web_state_->CanTakeSnapshot());
+
+  // Loading the page will create the view again.
+  [web_state_->GetWebController() loadCurrentURLIfNecessary];
+  EXPECT_TRUE(web_state_->CanTakeSnapshot());
+}
+
 }  // namespace web
diff --git a/ios/web/web_state/web_state_unittest.mm b/ios/web/web_state/web_state_unittest.mm
index 729a5c5..88aa1cd6 100644
--- a/ios/web/web_state/web_state_unittest.mm
+++ b/ios/web/web_state/web_state_unittest.mm
@@ -141,6 +141,28 @@
   ASSERT_FALSE(navigation_manager->GetLastCommittedItem());
 }
 
+// Tests that taking a snapshot after disabling web usage or adding an overlay
+// will force the creation of the WebState's view.
+TEST_F(WebStateTest, CanTakeSnapshot) {
+  // The test fixture forces the creation of the view, so it is initially
+  // possible to take a snapshot.
+  ASSERT_TRUE(web_state()->CanTakeSnapshot());
+
+  // Taking snapshot after disabling web usage will cause a reload.
+  web_state()->SetWebUsageEnabled(false);
+  EXPECT_FALSE(web_state()->CanTakeSnapshot());
+
+  // Even after re-enabling web usage, taking a snapshot will create the
+  // WebState's view as it is lazily created.
+  web_state()->SetWebUsageEnabled(true);
+  EXPECT_FALSE(web_state()->CanTakeSnapshot());
+
+  // After re-creating the view, it is possible to take a snapshot without
+  // reloading.
+  web_state()->GetView();
+  EXPECT_TRUE(web_state()->CanTakeSnapshot());
+}
+
 // Tests that the snapshot method returns an image of a rendered html page.
 TEST_F(WebStateTest, Snapshot) {
   LoadHtml(
diff --git a/media/blink/watch_time_reporter.cc b/media/blink/watch_time_reporter.cc
index 070034d..cddcb77 100644
--- a/media/blink/watch_time_reporter.cc
+++ b/media/blink/watch_time_reporter.cc
@@ -18,18 +18,23 @@
   return false;
 }
 
-WatchTimeReporter::WatchTimeReporter(mojom::PlaybackPropertiesPtr properties,
-                                     GetMediaTimeCB get_media_time_cb,
-                                     mojom::MediaMetricsProvider* provider)
+WatchTimeReporter::WatchTimeReporter(
+    mojom::PlaybackPropertiesPtr properties,
+    GetMediaTimeCB get_media_time_cb,
+    mojom::MediaMetricsProvider* provider,
+    scoped_refptr<base::SequencedTaskRunner> task_runner)
     : WatchTimeReporter(std::move(properties),
                         false /* is_background */,
                         std::move(get_media_time_cb),
-                        provider) {}
+                        provider,
+                        task_runner) {}
 
-WatchTimeReporter::WatchTimeReporter(mojom::PlaybackPropertiesPtr properties,
-                                     bool is_background,
-                                     GetMediaTimeCB get_media_time_cb,
-                                     mojom::MediaMetricsProvider* provider)
+WatchTimeReporter::WatchTimeReporter(
+    mojom::PlaybackPropertiesPtr properties,
+    bool is_background,
+    GetMediaTimeCB get_media_time_cb,
+    mojom::MediaMetricsProvider* provider,
+    scoped_refptr<base::SequencedTaskRunner> task_runner)
     : properties_(std::move(properties)),
       is_background_(is_background),
       get_media_time_cb_(std::move(get_media_time_cb)) {
@@ -53,7 +58,9 @@
   prop_copy->is_background = true;
   background_reporter_.reset(
       new WatchTimeReporter(std::move(prop_copy), true /* is_background */,
-                            get_media_time_cb_, provider));
+                            get_media_time_cb_, provider, task_runner));
+
+  reporting_timer_.SetTaskRunner(task_runner);
 }
 
 WatchTimeReporter::~WatchTimeReporter() {
diff --git a/media/blink/watch_time_reporter.h b/media/blink/watch_time_reporter.h
index 1a37ceb..cf1a2472 100644
--- a/media/blink/watch_time_reporter.h
+++ b/media/blink/watch_time_reporter.h
@@ -74,7 +74,8 @@
   // the elapsed media time instead?
   WatchTimeReporter(mojom::PlaybackPropertiesPtr properties,
                     GetMediaTimeCB get_media_time_cb,
-                    mojom::MediaMetricsProvider* provider);
+                    mojom::MediaMetricsProvider* provider,
+                    scoped_refptr<base::SequencedTaskRunner> task_runner);
   ~WatchTimeReporter() override;
 
   // These methods are used to ensure that watch time is only reported for media
@@ -144,7 +145,8 @@
   WatchTimeReporter(mojom::PlaybackPropertiesPtr properties,
                     bool is_background,
                     GetMediaTimeCB get_media_time_cb,
-                    mojom::MediaMetricsProvider* provider);
+                    mojom::MediaMetricsProvider* provider,
+                    scoped_refptr<base::SequencedTaskRunner> task_runner);
 
   // base::PowerObserver implementation.
   //
diff --git a/media/blink/watch_time_reporter_unittest.cc b/media/blink/watch_time_reporter_unittest.cc
index f241221..89f9d96 100644
--- a/media/blink/watch_time_reporter_unittest.cc
+++ b/media/blink/watch_time_reporter_unittest.cc
@@ -17,6 +17,7 @@
 #include "mojo/public/cpp/bindings/strong_binding.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/WebKit/public/platform/scheduler/test/renderer_scheduler_test_support.h"
 
 namespace media {
 
@@ -227,7 +228,8 @@
                                        is_encrypted, false, initial_video_size),
         base::Bind(&WatchTimeReporterTest::GetCurrentMediaTime,
                    base::Unretained(this)),
-        &fake_metrics_provider_));
+        &fake_metrics_provider_,
+        blink::scheduler::GetSequencedTaskRunnerForTesting()));
 
     // Setup the reporting interval to be immediate to avoid spinning real time
     // within the unit test.
diff --git a/media/blink/webmediaplayer_impl.cc b/media/blink/webmediaplayer_impl.cc
index ba96ebc..f1dffad 100644
--- a/media/blink/webmediaplayer_impl.cc
+++ b/media/blink/webmediaplayer_impl.cc
@@ -296,6 +296,9 @@
 
   if (observer_)
     observer_->SetClient(this);
+
+  memory_usage_reporting_timer_.SetTaskRunner(
+      frame_->GetTaskRunner(blink::TaskType::kUnthrottled));
 }
 
 WebMediaPlayerImpl::~WebMediaPlayerImpl() {
@@ -2567,7 +2570,8 @@
           pipeline_metadata_.natural_size),
       base::BindRepeating(&WebMediaPlayerImpl::GetCurrentTimeInternal,
                           base::Unretained(this)),
-      media_metrics_provider_.get()));
+      media_metrics_provider_.get(),
+      frame_->GetTaskRunner(blink::TaskType::kUnthrottled)));
   watch_time_reporter_->OnVolumeChange(volume_);
 
   if (delegate_->IsFrameHidden())
diff --git a/media/gpu/v4l2/v4l2_video_decode_accelerator.cc b/media/gpu/v4l2/v4l2_video_decode_accelerator.cc
index 63a3d54..8b145b7 100644
--- a/media/gpu/v4l2/v4l2_video_decode_accelerator.cc
+++ b/media/gpu/v4l2/v4l2_video_decode_accelerator.cc
@@ -1023,32 +1023,20 @@
   // Recycle buffers.
   Dequeue();
 
-  // Check and see if we have format info yet.
-  struct v4l2_format format;
-  gfx::Size visible_size;
-  bool again = false;
-  if (!GetFormatInfo(&format, &visible_size, &again))
-    return false;
-
   *endpos = size;
 
-  if (again) {
-    // Need more stream to decode format, return true and schedule next buffer.
+  // If an initial resolution change event is not done yet, a driver probably
+  // needs more stream to decode format.
+  // Return true and schedule next buffer without changing status to kDecoding.
+  // If the initial resolution change is done and coded size is known, we may
+  // still have to wait for AssignPictureBuffers() and output buffers to be
+  // allocated.
+  if (coded_size_.IsEmpty() || output_buffer_map_.empty()) {
     return true;
   }
 
-  // Run this initialization only on first startup.
-  if (output_buffer_map_.empty()) {
-    DVLOGF(4) << "running initialization";
-    // Success! Setup our parameters.
-    if (!CreateBuffersForFormat(format, visible_size))
-      return false;
-    // We are waiting for AssignPictureBuffers. Do not set the state to
-    // kDecoding.
-  } else {
-    decoder_state_ = kDecoding;
-    ScheduleDecodeBufferTaskIfNeeded();
-  }
+  decoder_state_ = kDecoding;
+  ScheduleDecodeBufferTaskIfNeeded();
   return true;
 }
 
@@ -1185,6 +1173,25 @@
   bool resolution_change_pending = false;
   if (event_pending)
     resolution_change_pending = DequeueResolutionChangeEvent();
+
+  if (!resolution_change_pending && coded_size_.IsEmpty()) {
+    // Some platforms do not send an initial resolution change event.
+    // To work around this, we need to keep checking if the initial resolution
+    // is known already by explicitly querying the format after each decode,
+    // regardless of whether we received an event.
+    // This needs to be done on initial resolution change,
+    // i.e. when coded_size_.IsEmpty().
+
+    // Try GetFormatInfo to check if an initial resolution change can be done.
+    struct v4l2_format format;
+    gfx::Size visible_size;
+    bool again;
+    if (GetFormatInfo(&format, &visible_size, &again) && !again) {
+      resolution_change_pending = true;
+      DequeueResolutionChangeEvent();
+    }
+  }
+
   Dequeue();
   Enqueue();
 
@@ -1582,14 +1589,7 @@
   DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread());
   TRACE_EVENT0("Video Decoder", "V4L2VDA::FlushTask");
 
-  // Flush outstanding buffers.
-  if (decoder_state_ == kInitialized) {
-    // There's nothing in the pipe, so return done immediately.
-    VLOGF(2) << "returning flush";
-    child_task_runner_->PostTask(FROM_HERE,
-                                 base::Bind(&Client::NotifyFlushDone, client_));
-    return;
-  } else if (decoder_state_ == kError) {
+  if (decoder_state_ == kError) {
     VLOGF(2) << "early out: kError state";
     return;
   }
diff --git a/media/midi/midi_service.cc b/media/midi/midi_service.cc
index 7427330b..6ecd858 100644
--- a/media/midi/midi_service.cc
+++ b/media/midi/midi_service.cc
@@ -13,20 +13,6 @@
 
 namespace midi {
 
-namespace {
-
-// TODO(toyoshim): Support on all platforms. See https://crbug.com/672793.
-bool IsDynamicInstantiationEnabled() {
-#if defined(OS_ANDROID)
-  return base::FeatureList::IsEnabled(
-      features::kMidiManagerDynamicInstantiation);
-#else
-  return true;
-#endif
-}
-
-}  // namespace
-
 std::unique_ptr<MidiManager> MidiService::ManagerFactory::Create(
     MidiService* service) {
   return std::unique_ptr<MidiManager>(MidiManager::Create(service));
@@ -45,8 +31,7 @@
 }
 
 MidiService::MidiService(void)
-    : MidiService(std::make_unique<ManagerFactory>(),
-                  IsDynamicInstantiationEnabled()) {}
+    : MidiService(std::make_unique<ManagerFactory>(), true) {}
 
 // TODO(toyoshim): Stop enforcing to disable dynamic instantiation mode for
 // testing once the mode is enabled by default.
diff --git a/media/midi/midi_switches.cc b/media/midi/midi_switches.cc
index 1dc448d..08df596 100644
--- a/media/midi/midi_switches.cc
+++ b/media/midi/midi_switches.cc
@@ -8,11 +8,6 @@
 namespace midi {
 namespace features {
 
-#if defined(OS_ANDROID)
-const base::Feature kMidiManagerDynamicInstantiation{
-    "MidiManagerDynamicInstantiation", base::FEATURE_ENABLED_BY_DEFAULT};
-#endif
-
 #if defined(OS_WIN)
 const base::Feature kMidiManagerWinrt{"MidiManagerWinrt",
                                       base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/media/midi/midi_switches.h b/media/midi/midi_switches.h
index 9b377a1d..1c0dbb1d 100644
--- a/media/midi/midi_switches.h
+++ b/media/midi/midi_switches.h
@@ -14,10 +14,6 @@
 namespace midi {
 namespace features {
 
-#if defined(OS_ANDROID)
-MIDI_EXPORT extern const base::Feature kMidiManagerDynamicInstantiation;
-#endif
-
 #if defined(OS_WIN)
 MIDI_EXPORT extern const base::Feature kMidiManagerWinrt;
 #endif
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 91b1439..e04368b 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -1855,37 +1855,6 @@
             ]
         }
     ],
-    "MidiManagerDynamicInstantiation": [
-        {
-            "platforms": [
-                "chromeos",
-                "linux",
-                "mac",
-                "win"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled",
-                    "enable_features": [
-                        "MidiManagerDynamicInstantiation"
-                    ]
-                }
-            ]
-        },
-        {
-            "platforms": [
-                "android"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled_WithFullSupport",
-                    "enable_features": [
-                        "MidiManagerDynamicInstantiation"
-                    ]
-                }
-            ]
-        }
-    ],
     "MojoCdm": [
         {
             "platforms": [
diff --git a/third_party/WebKit/Source/bindings/core/v8/UseCounterCallback.cpp b/third_party/WebKit/Source/bindings/core/v8/UseCounterCallback.cpp
index c3bf8fd2..21d8ef7 100644
--- a/third_party/WebKit/Source/bindings/core/v8/UseCounterCallback.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/UseCounterCallback.cpp
@@ -142,6 +142,9 @@
     case v8::Isolate::kIndexAccessor:
       blink_feature = WebFeature::kV8IndexAccessor;
       break;
+    case v8::Isolate::kDeoptimizerDisableSpeculation:
+      blink_feature = WebFeature::kV8DeoptimizerDisableSpeculation;
+      break;
     default:
       // This can happen if V8 has added counters that this version of Blink
       // does not know about. It's harmless.
diff --git a/third_party/WebKit/Source/core/css/cssom/InlineStylePropertyMap.cpp b/third_party/WebKit/Source/core/css/cssom/InlineStylePropertyMap.cpp
index 86536ef..3baba84 100644
--- a/third_party/WebKit/Source/core/css/cssom/InlineStylePropertyMap.cpp
+++ b/third_party/WebKit/Source/core/css/cssom/InlineStylePropertyMap.cpp
@@ -22,7 +22,7 @@
 
 void InlineStylePropertyMap::SetProperty(CSSPropertyID property_id,
                                          const CSSValue* value) {
-  owner_element_->SetInlineStyleProperty(property_id, value);
+  owner_element_->SetInlineStyleProperty(property_id, *value);
 }
 
 void InlineStylePropertyMap::RemoveProperty(CSSPropertyID property_id) {
diff --git a/third_party/WebKit/Source/core/dom/Element.cpp b/third_party/WebKit/Source/core/dom/Element.cpp
index a357a5a..24dd166 100644
--- a/third_party/WebKit/Source/core/dom/Element.cpp
+++ b/third_party/WebKit/Source/core/dom/Element.cpp
@@ -4484,7 +4484,7 @@
 void Element::SetInlineStyleProperty(CSSPropertyID property_id,
                                      CSSValueID identifier,
                                      bool important) {
-  SetInlineStyleProperty(property_id, CSSIdentifierValue::Create(identifier),
+  SetInlineStyleProperty(property_id, *CSSIdentifierValue::Create(identifier),
                          important);
 }
 
@@ -4492,15 +4492,15 @@
                                      double value,
                                      CSSPrimitiveValue::UnitType unit,
                                      bool important) {
-  SetInlineStyleProperty(property_id, CSSPrimitiveValue::Create(value, unit),
+  SetInlineStyleProperty(property_id, *CSSPrimitiveValue::Create(value, unit),
                          important);
 }
 
 void Element::SetInlineStyleProperty(CSSPropertyID property_id,
-                                     const CSSValue* value,
+                                     const CSSValue& value,
                                      bool important) {
   DCHECK(IsStyledElement());
-  EnsureMutableInlineStyle().SetProperty(property_id, *value, important);
+  EnsureMutableInlineStyle().SetProperty(property_id, value, important);
   InlineStyleChanged();
 }
 
diff --git a/third_party/WebKit/Source/core/dom/Element.h b/third_party/WebKit/Source/core/dom/Element.h
index 86df572..8ae54acd 100644
--- a/third_party/WebKit/Source/core/dom/Element.h
+++ b/third_party/WebKit/Source/core/dom/Element.h
@@ -370,9 +370,8 @@
                               double value,
                               CSSPrimitiveValue::UnitType,
                               bool important = false);
-  // TODO(sashab): Make this take a const CSSValue&.
   void SetInlineStyleProperty(CSSPropertyID,
-                              const CSSValue*,
+                              const CSSValue&,
                               bool important = false);
   bool SetInlineStyleProperty(CSSPropertyID,
                               const String& value,
diff --git a/third_party/WebKit/Source/core/layout/LayoutInlineTest.cpp b/third_party/WebKit/Source/core/layout/LayoutInlineTest.cpp
index 6ecc8f1d..5ccd7c63 100644
--- a/third_party/WebKit/Source/core/layout/LayoutInlineTest.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutInlineTest.cpp
@@ -54,11 +54,8 @@
   EXPECT_EQ(
       LayoutRect(LayoutPoint(745, 0), LayoutSize(39, 26)),
       ToLayoutInline(GetLayoutObjectByElementId("rtl1"))->LinesBoundingBox());
-  // TODO(layout-dev): LayoutNG should have same LayoutRect of legacy.
-  // See http://crbug.com/785687
   EXPECT_EQ(
-      LayoutNGEnabled() ? LayoutRect(LayoutPoint(745, 0), LayoutSize(65, 13))
-                        : LayoutRect(LayoutPoint(641, 0), LayoutSize(143, 13)),
+      LayoutRect(LayoutPoint(641, 0), LayoutSize(143, 13)),
       ToLayoutInline(GetLayoutObjectByElementId("rtl2"))->LinesBoundingBox());
   EXPECT_EQ(LayoutRect(LayoutPoint(0, 0), LayoutSize(26, 39)),
             ToLayoutInline(GetLayoutObjectByElementId("vertical"))
diff --git a/third_party/WebKit/Source/core/layout/line/InlineFlowBox.cpp b/third_party/WebKit/Source/core/layout/line/InlineFlowBox.cpp
index 757064f2..75833f9 100644
--- a/third_party/WebKit/Source/core/layout/line/InlineFlowBox.cpp
+++ b/third_party/WebKit/Source/core/layout/line/InlineFlowBox.cpp
@@ -98,28 +98,49 @@
       text_box->GetLineLayoutItem().StyleRef(IsFirstLineStyle());
   if (!text_box->GetEmphasisMarkPosition(style, emphasis_mark_position))
     return false;
-  LineLogicalSide side = style.GetTextEmphasisLineLogicalSide();
-  if (IsHorizontal() || !style.IsFlippedLinesWritingMode())
-    return side == LineLogicalSide::kOver;
-  return side == LineLogicalSide::kUnder;
+  if (IsHorizontal()) {
+    return emphasis_mark_position == TextEmphasisPosition::kOverRight ||
+           emphasis_mark_position == TextEmphasisPosition::kOverLeft;
+  }
+  if (style.IsFlippedLinesWritingMode()) {
+    return emphasis_mark_position == TextEmphasisPosition::kOverLeft ||
+           emphasis_mark_position == TextEmphasisPosition::kUnderLeft;
+  }
+  if (style.IsFlippedBlocksWritingMode()) {
+    return emphasis_mark_position == TextEmphasisPosition::kOverRight ||
+           emphasis_mark_position == TextEmphasisPosition::kUnderRight;
+  }
+  return false;
 }
 
 inline bool InlineFlowBox::HasEmphasisMarkOver(
     const InlineTextBox* text_box) const {
-  const auto& style =
-      text_box->GetLineLayoutItem().StyleRef(IsFirstLineStyle());
   TextEmphasisPosition emphasis_mark_position;
-  return text_box->GetEmphasisMarkPosition(style, emphasis_mark_position) &&
-         style.GetTextEmphasisLineLogicalSide() == LineLogicalSide::kOver;
+  if (!text_box->GetEmphasisMarkPosition(
+          text_box->GetLineLayoutItem().StyleRef(IsFirstLineStyle()),
+          emphasis_mark_position))
+    return false;
+
+  return IsHorizontal()
+             ? emphasis_mark_position == TextEmphasisPosition::kOverRight ||
+                   emphasis_mark_position == TextEmphasisPosition::kOverLeft
+             : emphasis_mark_position == TextEmphasisPosition::kOverRight ||
+                   emphasis_mark_position == TextEmphasisPosition::kUnderRight;
 }
 
 inline bool InlineFlowBox::HasEmphasisMarkUnder(
     const InlineTextBox* text_box) const {
-  const auto& style =
-      text_box->GetLineLayoutItem().StyleRef(IsFirstLineStyle());
   TextEmphasisPosition emphasis_mark_position;
-  return text_box->GetEmphasisMarkPosition(style, emphasis_mark_position) &&
-         style.GetTextEmphasisLineLogicalSide() == LineLogicalSide::kUnder;
+  if (!text_box->GetEmphasisMarkPosition(
+          text_box->GetLineLayoutItem().StyleRef(IsFirstLineStyle()),
+          emphasis_mark_position))
+    return false;
+
+  return IsHorizontal()
+             ? emphasis_mark_position == TextEmphasisPosition::kUnderRight ||
+                   emphasis_mark_position == TextEmphasisPosition::kUnderLeft
+             : emphasis_mark_position == TextEmphasisPosition::kOverLeft ||
+                   emphasis_mark_position == TextEmphasisPosition::kUnderLeft;
 }
 
 void InlineFlowBox::AddToLine(InlineBox* child) {
diff --git a/third_party/WebKit/Source/core/layout/line/InlineTextBox.cpp b/third_party/WebKit/Source/core/layout/line/InlineTextBox.cpp
index cb4312d..8171902b 100644
--- a/third_party/WebKit/Source/core/layout/line/InlineTextBox.cpp
+++ b/third_party/WebKit/Source/core/layout/line/InlineTextBox.cpp
@@ -518,7 +518,12 @@
 
   emphasis_position = style.GetTextEmphasisPosition();
   // Ruby text is always over, so it cannot suppress emphasis marks under.
-  if (style.GetTextEmphasisLineLogicalSide() != LineLogicalSide::kOver)
+  if ((IsHorizontal() &&
+       (emphasis_position == TextEmphasisPosition::kUnderRight ||
+        emphasis_position == TextEmphasisPosition::kUnderLeft)) ||
+      (!IsHorizontal() &&
+       (emphasis_position == TextEmphasisPosition::kOverLeft ||
+        emphasis_position == TextEmphasisPosition::kUnderLeft)))
     return true;
 
   LineLayoutBox containing_block = GetLineLayoutItem().ContainingBlock();
diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_box_state.cc b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_box_state.cc
index c35f21a..3d099ac 100644
--- a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_box_state.cc
+++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_box_state.cc
@@ -85,14 +85,18 @@
       else
         box.metrics = NGLineHeightMetrics();
       if (box.needs_box_fragment) {
-        box.line_left_position = LayoutUnit();
-        // Existing box states are wrapped boxes, and hence no left edges.
-        box.border_edges.line_left = false;
+        // Existing box states are wrapped before they were closed, and hence
+        // they do not have start edges.
+        box.has_start_edge = false;
+        box.margin_inline_start = LayoutUnit();
+        box.margin_border_padding_inline_start = LayoutUnit();
       }
       DCHECK(box.pending_descendants.IsEmpty());
     }
   }
 
+  DCHECK(box_data_list_.IsEmpty());
+
   // Initialize the box state for the line box.
   NGInlineBoxState& line_box = LineBoxState();
   line_box.style = line_style;
@@ -108,18 +112,24 @@
 NGInlineBoxState* NGInlineLayoutStateStack::OnOpenTag(
     const NGInlineItem& item,
     const NGInlineItemResult& item_result,
-    const NGLineBoxFragmentBuilder::ChildList& line_box,
-    LayoutUnit position) {
+    const NGLineBoxFragmentBuilder::ChildList& line_box) {
   DCHECK(item.Style());
   NGInlineBoxState* box = OnOpenTag(*item.Style(), line_box);
   box->item = &item;
 
   // Compute box properties regardless of needs_box_fragment since close tag may
   // also set needs_box_fragment.
-  box->line_left_position =
-      position + item_result.margins.LineLeft(item.Style()->Direction());
-  box->borders_paddings_block_start = item_result.borders_paddings_block_start;
-  box->borders_paddings_block_end = item_result.borders_paddings_block_end;
+  box->has_start_edge = item_result.has_edge;
+  if (box->has_start_edge) {
+    box->margin_inline_start = item_result.margins.inline_start;
+    // The open tag item has the start margin+border+padding in |inline_size|.
+    box->margin_border_padding_inline_start = item_result.inline_size;
+  } else {
+    DCHECK_EQ(item_result.margins.inline_start, LayoutUnit());
+    DCHECK_EQ(item_result.inline_size, LayoutUnit());
+  }
+  box->border_padding_block_start = item_result.borders_paddings_block_start;
+  box->border_padding_block_end = item_result.borders_paddings_block_end;
   return box;
 }
 
@@ -147,16 +157,11 @@
 
 void NGInlineLayoutStateStack::OnEndPlaceItems(
     NGLineBoxFragmentBuilder::ChildList* line_box,
-    FontBaseline baseline_type,
-    LayoutUnit position) {
+    FontBaseline baseline_type) {
   for (auto it = stack_.rbegin(); it != stack_.rend(); ++it) {
     NGInlineBoxState* box = &(*it);
-    box->line_right_position = position;
     EndBoxState(box, line_box, baseline_type);
   }
-
-  if (!box_placeholders_.IsEmpty())
-    CreateBoxFragments(line_box);
 }
 
 void NGInlineLayoutStateStack::EndBoxState(
@@ -180,28 +185,22 @@
   if (!needs_box_fragment) {
     DCHECK(item);
     needs_box_fragment = true;
-    // We have left edge on open tag, and if the box is not a continuation.
-    // TODO(kojii): Needs review when we change SplitInlines().
-    bool has_line_left_edge = item->Style()->IsLeftToRightDirection()
-                                  ? item->HasStartEdge()
-                                  : item->HasEndEdge();
-    border_edges = {true, false, true, has_line_left_edge};
   }
 }
 
 void NGInlineBoxState::SetLineRightForBoxFragment(
     const NGInlineItem& item,
-    const NGInlineItemResult& item_result,
-    LayoutUnit position) {
+    const NGInlineItemResult& item_result) {
   DCHECK(needs_box_fragment);
-  line_right_position =
-      position - item_result.margins.LineRight(item.Style()->Direction());
-  // We have right edge on close tag, and if the box does not have a
-  // continuation.
-  // TODO(kojii): Needs review when we change SplitInlines().
-  border_edges.line_right = item.Style()->IsLeftToRightDirection()
-                                ? item.HasEndEdge()
-                                : item.HasStartEdge();
+  has_end_edge = item_result.has_edge;
+  if (has_end_edge) {
+    margin_inline_end = item_result.margins.inline_end;
+    // The close tag item has the end margin+border+padding in |inline_size|.
+    margin_border_padding_inline_end = item_result.inline_size;
+  } else {
+    DCHECK_EQ(item_result.margins.inline_end, LayoutUnit());
+    DCHECK_EQ(item_result.inline_size, LayoutUnit());
+  }
 }
 
 // Crete a placeholder for a box fragment.
@@ -213,8 +212,8 @@
     NGLineBoxFragmentBuilder::ChildList* line_box,
     FontBaseline baseline_type) {
   DCHECK(box->needs_box_fragment);
-  LayoutUnit inline_size = box->line_right_position - box->line_left_position;
-  if (box->fragment_start == line_box->size() &&
+  unsigned fragment_end = line_box->size();
+  if (box->fragment_start == fragment_end &&
       !box->needs_box_fragment_when_empty) {
     // Don't create a box if the inline box is "empty".
     // Inline boxes with inline margins/borders/paddings are not "empty",
@@ -233,71 +232,227 @@
 
   // Extend the block direction of the box by borders and paddings. Inline
   // direction is already included into positions in NGLineBreaker.
-  NGLogicalOffset offset(box->line_left_position,
-                         -metrics.ascent - box->borders_paddings_block_start);
-  NGLogicalSize size(inline_size, metrics.LineHeight() +
-                                      box->borders_paddings_block_start +
-                                      box->borders_paddings_block_end);
-
-  // The start is marked only in BoxFragmentPlaceholder, while end is marked
-  // in both BoxFragmentPlaceholder and the list itself.
-  // With a list of 4 text fragments:
-  // |  0  |  1  |  2  |  3  |
-  // |text0|text1|text2|text3|
-  // By adding a BoxFragmentPlaceholder(2,4) (end is exclusive), it becomes:
-  // |  0  |  1  |  2  |  3  |  4  |
-  // |text0|text1|text2|text3|null |
-  // The "null" is added to the list to compute baseline shift of the box
-  // separately from text fragments.
-  unsigned fragment_end = line_box->size();
+  NGLogicalOffset offset(LayoutUnit(),
+                         -metrics.ascent - box->border_padding_block_start);
+  NGLogicalSize size(LayoutUnit(), metrics.LineHeight() +
+                                       box->border_padding_block_start +
+                                       box->border_padding_block_end);
   DCHECK(box->item);
-  box_placeholders_.push_back(BoxFragmentPlaceholder{
-      box->fragment_start, fragment_end, box->item, size, box->border_edges});
-  line_box->AddChild(nullptr, offset);
+  box_data_list_.push_back(
+      BoxData{box->fragment_start, fragment_end, box->item, size});
+  BoxData& box_data = box_data_list_.back();
+  if (box->has_start_edge) {
+    box_data.has_line_left_edge = true;
+    box_data.margin_line_left = box->margin_inline_start;
+    box_data.margin_border_padding_line_left =
+        box->margin_border_padding_inline_start;
+  }
+  if (box->has_end_edge) {
+    box_data.has_line_right_edge = true;
+    box_data.margin_line_right = box->margin_inline_end;
+    box_data.margin_border_padding_line_right =
+        box->margin_border_padding_inline_end;
+  }
+  if (IsRtl(style.Direction())) {
+    std::swap(box_data.has_line_left_edge, box_data.has_line_right_edge);
+    std::swap(box_data.margin_line_left, box_data.margin_line_right);
+    std::swap(box_data.margin_border_padding_line_left,
+              box_data.margin_border_padding_line_right);
+  }
+
+  if (fragment_end > box->fragment_start) {
+    // The start is marked only in BoxData, while end is marked
+    // in both BoxData and the list itself.
+    // With a list of 4 text fragments:
+    // |  0  |  1  |  2  |  3  |
+    // |text0|text1|text2|text3|
+    // By adding a BoxData(2,4) (end is exclusive), it becomes:
+    // |  0  |  1  |  2  |  3  |  4  |
+    // |text0|text1|text2|text3|null |
+    // The "null" is added to the list to compute baseline shift of the box
+    // separately from text fragments.
+    line_box->AddChild(offset);
+  } else {
+    // Do not defer creating a box fragment if this is an empty inline box.
+    // An empty box fragment is still flat that we do not have to defer.
+    // Also, placeholders cannot be reordred if empty.
+    scoped_refptr<NGLayoutResult> layout_result =
+        box_data.CreateBoxFragment(line_box);
+    offset.inline_offset += box_data.margin_line_left;
+    line_box->AddChild(layout_result, offset, box_data.size.inline_size, 0);
+    box_data_list_.pop_back();
+  }
 }
 
-// Create box fragments and construct a tree from the placeholders.
-void NGInlineLayoutStateStack::CreateBoxFragments(
+void NGInlineLayoutStateStack::PrepareForReorder(
     NGLineBoxFragmentBuilder::ChildList* line_box) {
-  DCHECK(!box_placeholders_.IsEmpty());
-
-  // At this point, children is a list of text fragments and box placeholders.
-  // |  0  |  1  |  2  |  3  |  4  |  5  |
-  // |text0|text1|text2|text3|null1|text5|
-  // When there is a BoxFragmentPlaceholder(2,4), this loop creates a box
-  // fragment with text2 and text3 as its children and changes the list to:
-  // |  0  |  1  |  2  |  3  |  4  |  5  |
-  // |text0|text1|null |null | box |text5|
-  for (const BoxFragmentPlaceholder& placeholder : box_placeholders_) {
-    const ComputedStyle* style = placeholder.item->Style();
-    // Because children are already in the visual order, use LTR for the
-    // fragment builder so that it should not transform the coordinates for RTL.
-    NGFragmentBuilder box(placeholder.item->GetLayoutObject(), style,
-                          style->GetWritingMode(), TextDirection::kLtr);
-    const NGLogicalOffset& box_offset =
-        (*line_box)[placeholder.fragment_end].offset;
-    for (unsigned i = placeholder.fragment_start; i < placeholder.fragment_end;
-         i++) {
+  // Set indexes of BoxData to the children of the line box.
+  unsigned box_data_index = 0;
+  for (const auto& box_data : box_data_list_) {
+    box_data_index++;
+    for (unsigned i = box_data.fragment_start; i < box_data.fragment_end; i++) {
       NGLineBoxFragmentBuilder::Child& child = (*line_box)[i];
-      if (child.layout_result) {
-        box.AddChild(std::move(child.layout_result), child.offset - box_offset);
-        DCHECK(!child.layout_result);
-      } else if (child.fragment) {
-        box.AddChild(std::move(child.fragment), child.offset - box_offset);
-        DCHECK(!child.fragment);
+      if (!child.box_data_index)
+        child.box_data_index = box_data_index;
+    }
+  }
+
+  // When boxes are nested, placeholders have indexes to which box it should be
+  // added. Copy them to BoxData.
+  for (auto& box_data : box_data_list_) {
+    const NGLineBoxFragmentBuilder::Child& placeholder =
+        (*line_box)[box_data.fragment_end];
+    DCHECK(!placeholder.HasFragment());
+    box_data.offset = placeholder.offset;
+    box_data.box_data_index = placeholder.box_data_index;
+  }
+}
+
+void NGInlineLayoutStateStack::UpdateAfterReorder(
+    NGLineBoxFragmentBuilder::ChildList* line_box) {
+  // Compute start/end of boxes from the children of the line box.
+  for (auto& box_data : box_data_list_)
+    box_data.fragment_start = box_data.fragment_end = 0;
+  for (unsigned i = 0; i < line_box->size(); i++) {
+    const auto& child = (*line_box)[i];
+    if (!child.HasFragment())
+      continue;
+    if (unsigned box_data_index = child.box_data_index) {
+      BoxData& box_data = box_data_list_[box_data_index - 1];
+      if (!box_data.fragment_end)
+        box_data.fragment_start = i;
+      box_data.fragment_end = i + 1;
+    }
+  }
+
+  // Extend start/end of boxes when they are nested.
+  for (auto& box_data : box_data_list_) {
+    if (box_data.box_data_index) {
+      BoxData& parent_box_data = box_data_list_[box_data.box_data_index - 1];
+      if (!parent_box_data.fragment_end) {
+        parent_box_data.fragment_start = box_data.fragment_start;
+        parent_box_data.fragment_end = box_data.fragment_end;
+      } else {
+        parent_box_data.fragment_start =
+            std::min(box_data.fragment_start, parent_box_data.fragment_start);
+        parent_box_data.fragment_end =
+            std::max(box_data.fragment_end, parent_box_data.fragment_end);
       }
     }
-
-    // Inline boxes have block start/end borders, even when its containing block
-    // was fragmented. Fragmenting a line box in block direction is not
-    // supported today.
-    box.SetBorderEdges(placeholder.border_edges);
-    box.SetInlineSize(placeholder.size.inline_size);
-    box.SetBlockSize(placeholder.size.block_size);
-    DCHECK(!(*line_box)[placeholder.fragment_end].HasFragment());
-    (*line_box)[placeholder.fragment_end].layout_result = box.ToBoxFragment();
   }
-  box_placeholders_.clear();
+
+#if DCHECK_IS_ON()
+  // Check all BoxData have ranges.
+  for (const auto& box_data : box_data_list_) {
+    DCHECK_NE(box_data.fragment_end, 0u);
+    DCHECK_GT(box_data.fragment_end, box_data.fragment_start);
+  }
+#endif
+}
+
+LayoutUnit NGInlineLayoutStateStack::ComputeInlinePositions(
+    NGLineBoxFragmentBuilder::ChildList* line_box) {
+  // At this point, children are in the visual order, and they have their
+  // origins at (0, 0). Accumulate inline offset from left to right.
+  LayoutUnit position;
+  for (auto& child : *line_box) {
+    child.offset.inline_offset += position;
+    // Box margins/boders/paddings will be processed later.
+    // TODO(kojii): we could optimize this if the reordering did not occur.
+    if (!child.HasFragment())
+      continue;
+    position += child.inline_size;
+  }
+
+  if (box_data_list_.IsEmpty())
+    return position;
+
+  // Create box fragments.
+  for (auto& box_data : box_data_list_) {
+    unsigned start = box_data.fragment_start;
+    unsigned end = box_data.fragment_end;
+    DCHECK_GT(end, start);
+    NGLineBoxFragmentBuilder::Child& start_child = (*line_box)[start];
+    LayoutUnit line_left_offset = start_child.offset.inline_offset;
+    LayoutUnit line_right_offset = end < line_box->size()
+                                       ? (*line_box)[end].offset.inline_offset
+                                       : position;
+    box_data.offset.inline_offset = line_left_offset;
+    box_data.size.inline_size = line_right_offset - line_left_offset;
+
+    scoped_refptr<NGLayoutResult> box_fragment =
+        box_data.CreateBoxFragment(line_box);
+    NGLogicalOffset offset(line_left_offset + box_data.margin_line_left,
+                           box_data.offset.block_offset);
+    if (!start_child.HasFragment()) {
+      start_child.layout_result = std::move(box_fragment);
+      start_child.offset = offset;
+    } else {
+      // In most cases, |start_child| is moved to the children of the box, and
+      // is empty. It's not empty when it's out-of-flow. Insert in such case.
+      line_box->InsertChild(start, std::move(box_fragment), offset,
+                            LayoutUnit(), 0);
+    }
+
+    // Out-of-flow fragments are left in (start + 1, end). Move them by the left
+    // margin/border/padding.
+    if (box_data.margin_border_padding_line_left) {
+      line_box->MoveInInlineDirection(box_data.margin_border_padding_line_left,
+                                      start + 1, end);
+    }
+    // Move the rest of children by the inline size the box consumes.
+    LayoutUnit margin_border_padding =
+        box_data.margin_border_padding_line_left +
+        box_data.margin_border_padding_line_right;
+    if (margin_border_padding) {
+      line_box->MoveInInlineDirection(margin_border_padding, end,
+                                      line_box->size());
+      position += margin_border_padding;
+    }
+  }
+
+  box_data_list_.clear();
+
+  return position;
+}
+
+scoped_refptr<NGLayoutResult>
+NGInlineLayoutStateStack::BoxData::CreateBoxFragment(
+    NGLineBoxFragmentBuilder::ChildList* line_box) {
+  DCHECK(item);
+  DCHECK(item->Style());
+  const ComputedStyle& style = *item->Style();
+  // Because children are already in the visual order, use LTR for the
+  // fragment builder so that it should not transform the coordinates for RTL.
+  NGFragmentBuilder box(item->GetLayoutObject(), &style, style.GetWritingMode(),
+                        TextDirection::kLtr);
+
+  // Inline boxes have block start/end borders, even when its containing block
+  // was fragmented. Fragmenting a line box in block direction is not
+  // supported today.
+  box.SetBorderEdges({true, has_line_right_edge, true, has_line_left_edge});
+  LayoutUnit border_padding_line_left =
+      margin_border_padding_line_left - margin_line_left;
+  LayoutUnit border_padding_line_right =
+      margin_border_padding_line_right - margin_line_right;
+  offset.inline_offset -= border_padding_line_left;
+  size.inline_size += border_padding_line_left + border_padding_line_right;
+  box.SetInlineSize(size.inline_size);
+  box.SetBlockSize(size.block_size);
+
+  for (unsigned i = fragment_start; i < fragment_end; i++) {
+    NGLineBoxFragmentBuilder::Child& child = (*line_box)[i];
+    if (child.layout_result) {
+      box.AddChild(std::move(child.layout_result), child.offset - offset);
+    } else if (child.fragment) {
+      box.AddChild(std::move(child.fragment), child.offset - offset);
+    }
+    // Leave out-of-flow fragments. They need to be at the top level so that
+    // NGInlineLayoutAlgorithm can handle them later.
+    DCHECK(!child.HasInFlowFragment());
+  }
+
+  return box.ToBoxFragment();
 }
 
 NGInlineLayoutStateStack::PositionPending
diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_box_state.h b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_box_state.h
index 4f317802..fa37027 100644
--- a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_box_state.h
+++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_box_state.h
@@ -56,17 +56,27 @@
 
   // These values are to create a box fragment. Set only when needs_box_fragment
   // is set.
-  LayoutUnit line_left_position;
-  LayoutUnit line_right_position;
-  LayoutUnit borders_paddings_block_start;
-  LayoutUnit borders_paddings_block_end;
-  NGBorderEdges border_edges;
+  bool has_start_edge = false;
+  bool has_end_edge = false;
+  // |CreateBoxFragment()| needs margin, border+padding, and the sum of them.
+  LayoutUnit margin_inline_start;
+  LayoutUnit margin_inline_end;
+  LayoutUnit margin_border_padding_inline_start;
+  LayoutUnit margin_border_padding_inline_end;
+  LayoutUnit border_padding_block_start;
+  LayoutUnit border_padding_block_end;
 
   Vector<NGPendingPositions> pending_descendants;
   bool include_used_fonts = false;
   bool needs_box_fragment = false;
   bool needs_box_fragment_when_empty = false;
 
+  // True if this box has a metrics, including pending ones. Pending metrics
+  // will be activated in |EndBoxState()|.
+  bool HasMetrics() const {
+    return !metrics.IsEmpty() || !pending_descendants.IsEmpty();
+  }
+
   // Compute text metrics for a box. All text in a box share the same
   // metrics.  When line_height_quirk is set, text metrics won't
   // influence box height until ActivateTextMetrics() is called.
@@ -83,8 +93,7 @@
   // Create a box fragment for this box.
   void SetNeedsBoxFragment(bool when_empty);
   void SetLineRightForBoxFragment(const NGInlineItem&,
-                                  const NGInlineItemResult&,
-                                  LayoutUnit position);
+                                  const NGInlineItemResult&);
 
   // Returns if the text style can be added without open-tag.
   // Text with different font or vertical-align needs to be wrapped with an
@@ -108,8 +117,7 @@
   // Push a box state stack.
   NGInlineBoxState* OnOpenTag(const NGInlineItem&,
                               const NGInlineItemResult&,
-                              const NGLineBoxFragmentBuilder::ChildList&,
-                              LayoutUnit position);
+                              const NGLineBoxFragmentBuilder::ChildList&);
   NGInlineBoxState* OnOpenTag(const ComputedStyle&,
                               const NGLineBoxFragmentBuilder::ChildList&);
 
@@ -119,12 +127,26 @@
                                FontBaseline);
 
   // Compute all the pending positioning at the end of a line.
-  void OnEndPlaceItems(NGLineBoxFragmentBuilder::ChildList*,
-                       FontBaseline,
-                       LayoutUnit position);
+  void OnEndPlaceItems(NGLineBoxFragmentBuilder::ChildList*, FontBaseline);
 
   LayoutObject* ContainingLayoutObjectForAbsolutePositionObjects() const;
 
+  bool HasBoxFragments() const { return !box_data_list_.IsEmpty(); }
+
+  // This class keeps indexes to fragments in the line box, and that only
+  // appending is allowed. Call this function to move all such data to the line
+  // box, so that outside of this class can reorder fragments in the line box.
+  void PrepareForReorder(NGLineBoxFragmentBuilder::ChildList*);
+
+  // When reordering was complete, call this function to re-construct the box
+  // data from the line box. Callers must call |PrepareForReorder()| before
+  // reordering.
+  void UpdateAfterReorder(NGLineBoxFragmentBuilder::ChildList*);
+
+  // Compute inline positions of fragments. Also creates box fragments if
+  // needed.
+  LayoutUnit ComputeInlinePositions(NGLineBoxFragmentBuilder::ChildList*);
+
  private:
   // End of a box state, either explicitly by close tag, or implicitly at the
   // end of a line.
@@ -135,7 +157,6 @@
   void AddBoxFragmentPlaceholder(NGInlineBoxState*,
                                  NGLineBoxFragmentBuilder::ChildList*,
                                  FontBaseline);
-  void CreateBoxFragments(NGLineBoxFragmentBuilder::ChildList*);
 
   enum PositionPending { kPositionNotPending, kPositionPending };
 
@@ -149,18 +170,31 @@
                                      NGLineBoxFragmentBuilder::ChildList*,
                                      FontBaseline);
 
-  // Data for a box fragment placeholder. See AddBoxFragmentPlaceholder().
+  // Data for a box fragment. See AddBoxFragmentPlaceholder().
   // This is a transient object only while building a line box.
-  struct BoxFragmentPlaceholder {
+  struct BoxData {
     unsigned fragment_start;
     unsigned fragment_end;
     const NGInlineItem* item;
     NGLogicalSize size;
-    NGBorderEdges border_edges;
+
+    bool has_line_left_edge = false;
+    bool has_line_right_edge = false;
+    // |CreateBoxFragment()| needs margin, border+padding, and the sum of them.
+    LayoutUnit margin_line_left;
+    LayoutUnit margin_line_right;
+    LayoutUnit margin_border_padding_line_left;
+    LayoutUnit margin_border_padding_line_right;
+
+    NGLogicalOffset offset;
+    unsigned box_data_index = 0;
+
+    scoped_refptr<NGLayoutResult> CreateBoxFragment(
+        NGLineBoxFragmentBuilder::ChildList*);
   };
 
   Vector<NGInlineBoxState, 4> stack_;
-  Vector<BoxFragmentPlaceholder, 4> box_placeholders_;
+  Vector<BoxData, 4> box_data_list_;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_item_result.h b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_item_result.h
index 3d702239..149c68e 100644
--- a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_item_result.h
+++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_item_result.h
@@ -60,6 +60,9 @@
   // by default.
   int expansion = 0;
 
+  // Has start/end edge for open/close tags.
+  bool has_edge = false;
+
   // Create a box when the box is empty, for open/close tags.
   bool needs_box_when_empty = false;
 
diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm.cc b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm.cc
index 3771b93..d0b2f4b 100644
--- a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm.cc
+++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm.cc
@@ -70,60 +70,6 @@
 
 void NGInlineLayoutAlgorithm::CreateLine(NGLineInfo* line_info,
                                          NGExclusionSpace* exclusion_space) {
-  if (Node().IsBidiEnabled())
-    BidiReorder(&line_info->Results());
-
-  PlaceItems(line_info, *exclusion_space);
-}
-
-void NGInlineLayoutAlgorithm::BidiReorder(NGInlineItemResults* line_items) {
-  // TODO(kojii): UAX#9 L1 is not supported yet. Supporting L1 may change
-  // embedding levels of parts of runs, which requires to split items.
-  // http://unicode.org/reports/tr9/#L1
-  // BidiResolver does not support L1 crbug.com/316409.
-
-  // Create a list of chunk indices in the visual order.
-  // ICU |ubidi_getVisualMap()| works for a run of characters. Since we can
-  // handle the direction of each run, we use |ubidi_reorderVisual()| to reorder
-  // runs instead of characters.
-  Vector<UBiDiLevel, 32> levels;
-  levels.ReserveInitialCapacity(line_items->size());
-  for (const auto& item_result : *line_items)
-    levels.push_back(item_result.item->BidiLevelForReorder());
-  Vector<int32_t, 32> indices_in_visual_order(line_items->size());
-  NGBidiParagraph::IndicesInVisualOrder(levels, &indices_in_visual_order);
-
-  // Reorder to the visual order.
-  NGInlineItemResults line_items_in_visual_order(line_items->size());
-  for (unsigned visual_index = 0; visual_index < indices_in_visual_order.size();
-       visual_index++) {
-    unsigned logical_index = indices_in_visual_order[visual_index];
-    line_items_in_visual_order[visual_index] =
-        std::move((*line_items)[logical_index]);
-  }
-
-  // Keep Open before Close in the visual order.
-  HashMap<LayoutObject*, unsigned> first_index;
-  for (unsigned i = 0; i < line_items_in_visual_order.size(); i++) {
-    NGInlineItemResult& item_result = line_items_in_visual_order[i];
-    const NGInlineItem& item = *item_result.item;
-    if (item.Type() != NGInlineItem::kOpenTag &&
-        item.Type() != NGInlineItem::kCloseTag) {
-      continue;
-    }
-    auto result = first_index.insert(item.GetLayoutObject(), i);
-    if (!result.is_new_entry && item.Type() == NGInlineItem::kOpenTag) {
-      std::swap(line_items_in_visual_order[i],
-                line_items_in_visual_order[result.stored_value->value]);
-    }
-  }
-
-  line_items->swap(line_items_in_visual_order);
-}
-
-void NGInlineLayoutAlgorithm::PlaceItems(
-    NGLineInfo* line_info,
-    const NGExclusionSpace& exclusion_space) {
   NGInlineItemResults* line_items = &line_info->Results();
   line_box_.clear();
 
@@ -151,11 +97,10 @@
 
   // Place items from line-left to line-right along with the baseline.
   // Items are already bidi-reordered to the visual order.
-  LayoutUnit position;
 
   if (IsRtl(line_info->BaseDirection()) && line_info->LineEndShapeResult()) {
     PlaceGeneratedContent(std::move(line_info->LineEndShapeResult()),
-                          std::move(line_info->LineEndStyle()), &position, box,
+                          std::move(line_info->LineEndStyle()), box,
                           &text_builder);
   }
 
@@ -176,7 +121,7 @@
                                    baseline_type_);
         }
       } else {
-        if (quirks_mode_ && line_box_.IsEmpty())
+        if (quirks_mode_ && !box->HasMetrics())
           box->ActivateTextMetrics();
         DCHECK(!item.TextShapeResult());  // kControl or unit tests.
       }
@@ -186,9 +131,10 @@
           text_builder.ToTextFragment(item_result.item_index,
                                       item_result.start_offset,
                                       item_result.end_offset);
-      line_box_.AddChild(std::move(text_fragment), {position, box->text_top});
+      line_box_.AddChild(std::move(text_fragment), box->text_top,
+                         item_result.inline_size, item.BidiLevel());
     } else if (item.Type() == NGInlineItem::kOpenTag) {
-      box = box_states_->OnOpenTag(item, item_result, line_box_, position);
+      box = box_states_->OnOpenTag(item, item_result, line_box_);
       // Compute text metrics for all inline boxes since even empty inlines
       // influence the line height.
       // https://drafts.csswg.org/css2/visudet.html#line-height
@@ -198,39 +144,33 @@
       if (ShouldCreateBoxFragment(item, item_result))
         box->SetNeedsBoxFragment(item_result.needs_box_when_empty);
     } else if (item.Type() == NGInlineItem::kCloseTag) {
-      position += item_result.inline_size;
       if (box->needs_box_fragment || item_result.needs_box_when_empty) {
         if (item_result.needs_box_when_empty)
           box->SetNeedsBoxFragment(true);
-        box->SetLineRightForBoxFragment(item, item_result, position);
+        box->SetLineRightForBoxFragment(item, item_result);
         if (quirks_mode_)
           box->ActivateTextMetrics();
       }
       box = box_states_->OnCloseTag(&line_box_, box, baseline_type_);
-      continue;
     } else if (item.Type() == NGInlineItem::kAtomicInline) {
-      box = PlaceAtomicInline(item, &item_result, *line_info, position);
+      box = PlaceAtomicInline(item, &item_result, *line_info);
     } else if (item.Type() == NGInlineItem::kListMarker) {
       list_marker_index = line_box_.size();
       PlaceListMarker(item, &item_result, *line_info);
       DCHECK_GT(line_box_.size(), list_marker_index.value());
     } else if (item.Type() == NGInlineItem::kOutOfFlowPositioned) {
-      NGBlockNode node(ToLayoutBox(item.GetLayoutObject()));
-      container_builder_.AddInlineOutOfFlowChildCandidate(
-          node, NGLogicalOffset(position, LayoutUnit()),
-          line_info->BaseDirection(),
-          box_states_->ContainingLayoutObjectForAbsolutePositionObjects());
-      continue;
-    } else {
-      continue;
+      line_box_.AddChild(
+          item.GetLayoutObject(),
+          box_states_->ContainingLayoutObjectForAbsolutePositionObjects(),
+          item.BidiLevel());
+    } else if (item.Type() == NGInlineItem::kBidiControl) {
+      line_box_.AddChild(item.BidiLevel());
     }
-
-    position += item_result.inline_size;
   }
 
   if (line_info->LineEndShapeResult()) {
     PlaceGeneratedContent(std::move(line_info->LineEndShapeResult()),
-                          std::move(line_info->LineEndStyle()), &position, box,
+                          std::move(line_info->LineEndStyle()), box,
                           &text_builder);
   }
 
@@ -238,7 +178,40 @@
     return;  // The line was empty.
   }
 
-  box_states_->OnEndPlaceItems(&line_box_, baseline_type_, position);
+  box_states_->OnEndPlaceItems(&line_box_, baseline_type_);
+
+  // TODO(kojii): For LTR, we can optimize ComputeInlinePositions() to compute
+  // without PrepareForReorder() and UpdateAfterReorder() even when
+  // HasBoxFragments(). We do this to share the logic between LTR and RTL, and
+  // to get more coverage for RTL, but when we're more stabilized, we could have
+  // optimized code path for LTR.
+  box_states_->PrepareForReorder(&line_box_);
+  BidiReorder();
+  box_states_->UpdateAfterReorder(&line_box_);
+  LayoutUnit inline_size = box_states_->ComputeInlinePositions(&line_box_);
+
+  // Handle out-of-flow positioned objects. They need inline offsets for their
+  // static positions.
+  bool has_fragments = false;
+  for (auto& child : line_box_) {
+    if (child.out_of_flow_positioned_box) {
+      NGBlockNode node(ToLayoutBox(child.out_of_flow_positioned_box));
+      container_builder_.AddInlineOutOfFlowChildCandidate(
+          node, NGLogicalOffset(child.offset.inline_offset, LayoutUnit()),
+          line_info->BaseDirection(), child.out_of_flow_containing_box);
+      child.out_of_flow_positioned_box = child.out_of_flow_containing_box =
+          nullptr;
+    } else if (!has_fragments) {
+      has_fragments = child.HasFragment();
+    }
+  }
+
+  if (!has_fragments) {
+    // If we have out-of-flow objects but nothing else, we don't have line box
+    // metrics nor BFC offset. Exit early.
+    return;
+  }
+
   const NGLineHeightMetrics& line_box_metrics =
       box_states_->LineBoxState().metrics;
   DCHECK(!line_box_metrics.IsEmpty());
@@ -255,7 +228,7 @@
 
   // Negative margins can make the position negative, but the inline size is
   // always positive or 0.
-  LayoutUnit inline_size = position.ClampNegativeToZero();
+  inline_size = inline_size.ClampNegativeToZero();
 
   // Other 'text-align' values than 'justify' move line boxes as a whole, but
   // indivisual items do not change their relative position to the line box.
@@ -281,20 +254,17 @@
 void NGInlineLayoutAlgorithm::PlaceGeneratedContent(
     scoped_refptr<const ShapeResult> shape_result,
     scoped_refptr<const ComputedStyle> style,
-    LayoutUnit* position,
     NGInlineBoxState* box,
     NGTextFragmentBuilder* text_builder) {
   if (box->CanAddTextOfStyle(*style)) {
-    PlaceText(std::move(shape_result), std::move(style), position, box,
-              text_builder);
+    PlaceText(std::move(shape_result), std::move(style), 0, box, text_builder);
   } else {
     scoped_refptr<ComputedStyle> text_style =
         ComputedStyle::CreateAnonymousStyleWithDisplay(*style,
                                                        EDisplay::kInline);
     NGInlineBoxState* box = box_states_->OnOpenTag(*text_style, line_box_);
     box->ComputeTextMetrics(*text_style, baseline_type_, false);
-    PlaceText(std::move(shape_result), std::move(style), position, box,
-              text_builder);
+    PlaceText(std::move(shape_result), std::move(style), 0, box, text_builder);
     box_states_->OnCloseTag(&line_box_, box, baseline_type_);
   }
 }
@@ -302,7 +272,7 @@
 void NGInlineLayoutAlgorithm::PlaceText(
     scoped_refptr<const ShapeResult> shape_result,
     scoped_refptr<const ComputedStyle> style,
-    LayoutUnit* position,
+    UBiDiLevel bidi_level,
     NGInlineBoxState* box,
     NGTextFragmentBuilder* text_builder) {
   unsigned start_offset = shape_result->StartIndexForResult();
@@ -313,38 +283,37 @@
   scoped_refptr<NGPhysicalTextFragment> text_fragment =
       text_builder->ToTextFragment(std::numeric_limits<unsigned>::max(),
                                    start_offset, end_offset);
-  line_box_.AddChild(std::move(text_fragment), {*position, box->text_top});
-  *position += inline_size;
+  line_box_.AddChild(std::move(text_fragment), box->text_top, inline_size,
+                     bidi_level);
 }
 
 NGInlineBoxState* NGInlineLayoutAlgorithm::PlaceAtomicInline(
     const NGInlineItem& item,
     NGInlineItemResult* item_result,
-    const NGLineInfo& line_info,
-    LayoutUnit position) {
+    const NGLineInfo& line_info) {
   DCHECK(item_result->layout_result);
 
   // The input |position| is the line-left edge of the margin box.
   // Adjust it to the border box by adding the line-left margin.
-  const ComputedStyle& style = *item.Style();
-  position += item_result->margins.LineLeft(style.Direction());
+  // const ComputedStyle& style = *item.Style();
+  // position += item_result->margins.LineLeft(style.Direction());
 
-  NGInlineBoxState* box =
-      box_states_->OnOpenTag(item, *item_result, line_box_, position);
-
-  PlaceLayoutResult(item_result, position, box);
-
+  item_result->has_edge = true;
+  NGInlineBoxState* box = box_states_->OnOpenTag(item, *item_result, line_box_);
+  PlaceLayoutResult(item_result, box, box->margin_inline_start);
   return box_states_->OnCloseTag(&line_box_, box, baseline_type_);
 }
 
 // Place a NGLayoutResult into the line box.
 void NGInlineLayoutAlgorithm::PlaceLayoutResult(NGInlineItemResult* item_result,
-                                                LayoutUnit position,
-                                                NGInlineBoxState* box) {
+                                                NGInlineBoxState* box,
+                                                LayoutUnit inline_offset) {
   DCHECK(item_result->layout_result);
   DCHECK(item_result->layout_result->PhysicalFragment());
-  DCHECK(item_result->item->Style());
-  const ComputedStyle& style = *item_result->item->Style();
+  DCHECK(item_result->item);
+  const NGInlineItem& item = *item_result->item;
+  DCHECK(item.Style());
+  const ComputedStyle& style = *item.Style();
   NGBoxFragment fragment(
       ConstraintSpace().GetWritingMode(),
       ToNGPhysicalBoxFragment(*item_result->layout_result->PhysicalFragment()));
@@ -366,12 +335,14 @@
         text_builder.ToTextFragment(item_result->item_index,
                                     item_result->start_offset,
                                     item_result->end_offset);
-    line_box_.AddChild(std::move(text_fragment), {position, line_top});
+    line_box_.AddChild(std::move(text_fragment), line_top, LayoutUnit(),
+                       item.BidiLevel());
     // We need the box fragment as well to compute VisualRect() correctly.
   }
 
   line_box_.AddChild(std::move(item_result->layout_result),
-                     {position, line_top});
+                     NGLogicalOffset{inline_offset, line_top},
+                     item_result->inline_size, item.BidiLevel());
 }
 
 // Place a list marker.
@@ -387,7 +358,7 @@
   DCHECK(item_result->layout_result->PhysicalFragment());
 
   // The inline position is adjusted later, when we knew the line width.
-  PlaceLayoutResult(item_result, LayoutUnit(), nullptr);
+  PlaceLayoutResult(item_result, nullptr);
 }
 
 // Justify the line. This changes the size of items by adding spacing.
@@ -722,4 +693,37 @@
   unpositioned_floats_.clear();
 }
 
+void NGInlineLayoutAlgorithm::BidiReorder() {
+  // TODO(kojii): UAX#9 L1 is not supported yet. Supporting L1 may change
+  // embedding levels of parts of runs, which requires to split items.
+  // http://unicode.org/reports/tr9/#L1
+  // BidiResolver does not support L1 crbug.com/316409.
+
+  // Create a list of chunk indices in the visual order.
+  // ICU |ubidi_getVisualMap()| works for a run of characters. Since we can
+  // handle the direction of each run, we use |ubidi_reorderVisual()| to reorder
+  // runs instead of characters.
+  NGLineBoxFragmentBuilder::ChildList logical_items;
+  Vector<UBiDiLevel, 32> levels;
+  logical_items.ReserveInitialCapacity(line_box_.size());
+  levels.ReserveInitialCapacity(line_box_.size());
+  for (auto& item : line_box_) {
+    if (!item.HasFragment() && !item.HasBidiLevel())
+      continue;
+    levels.push_back(item.bidi_level);
+    logical_items.AddChild(std::move(item));
+    DCHECK(!item.HasInFlowFragment());
+  }
+
+  Vector<int32_t, 32> indices_in_visual_order(levels.size());
+  NGBidiParagraph::IndicesInVisualOrder(levels, &indices_in_visual_order);
+
+  // Reorder to the visual order.
+  line_box_.resize(0);
+  for (unsigned logical_index : indices_in_visual_order) {
+    line_box_.AddChild(std::move(logical_items[logical_index]));
+    DCHECK(!logical_items[logical_index].HasInFlowFragment());
+  }
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm.h b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm.h
index 5c6c5b35..3abeb89 100644
--- a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm.h
+++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm.h
@@ -52,26 +52,23 @@
 
   bool IsHorizontalWritingMode() const { return is_horizontal_writing_mode_; }
 
-  void BidiReorder(NGInlineItemResults*);
+  void BidiReorder();
 
-  void PlaceItems(NGLineInfo*, const NGExclusionSpace&);
   void PlaceText(scoped_refptr<const ShapeResult>,
                  scoped_refptr<const ComputedStyle>,
-                 LayoutUnit* position,
+                 UBiDiLevel bidi_level,
                  NGInlineBoxState*,
                  NGTextFragmentBuilder*);
   void PlaceGeneratedContent(scoped_refptr<const ShapeResult>,
                              scoped_refptr<const ComputedStyle>,
-                             LayoutUnit* position,
                              NGInlineBoxState*,
                              NGTextFragmentBuilder*);
   NGInlineBoxState* PlaceAtomicInline(const NGInlineItem&,
                                       NGInlineItemResult*,
-                                      const NGLineInfo&,
-                                      LayoutUnit position);
+                                      const NGLineInfo&);
   void PlaceLayoutResult(NGInlineItemResult*,
-                         LayoutUnit position,
-                         NGInlineBoxState*);
+                         NGInlineBoxState*,
+                         LayoutUnit inline_offset = LayoutUnit());
   void PlaceListMarker(const NGInlineItem&,
                        NGInlineItemResult*,
                        const NGLineInfo&);
diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_line_box_fragment_builder.cc b/third_party/WebKit/Source/core/layout/ng/inline/ng_line_box_fragment_builder.cc
index 9fc764d3..18d22098e 100644
--- a/third_party/WebKit/Source/core/layout/ng/inline/ng_line_box_fragment_builder.cc
+++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_line_box_fragment_builder.cc
@@ -55,22 +55,22 @@
                        : fragment.get();
 }
 
-void NGLineBoxFragmentBuilder::ChildList::AddChild(
+void NGLineBoxFragmentBuilder::ChildList::InsertChild(
+    unsigned index,
     scoped_refptr<NGLayoutResult> layout_result,
-    const NGLogicalOffset& child_offset) {
-  children_.push_back(Child{std::move(layout_result), nullptr, child_offset});
+    const NGLogicalOffset& offset,
+    LayoutUnit inline_size,
+    UBiDiLevel bidi_level) {
+  children_.insert(
+      index, Child{std::move(layout_result), offset, inline_size, bidi_level});
 }
 
-void NGLineBoxFragmentBuilder::ChildList::AddChild(
-    scoped_refptr<NGPhysicalFragment> fragment,
-    const NGLogicalOffset& child_offset) {
-  children_.push_back(Child{nullptr, std::move(fragment), child_offset});
-}
-
-void NGLineBoxFragmentBuilder::ChildList::AddChild(
-    std::nullptr_t,
-    const NGLogicalOffset& child_offset) {
-  children_.push_back(Child{nullptr, nullptr, child_offset});
+void NGLineBoxFragmentBuilder::ChildList::MoveInInlineDirection(
+    LayoutUnit delta,
+    unsigned start,
+    unsigned end) {
+  for (unsigned index = start; index < end; index++)
+    children_[index].offset.inline_offset += delta;
 }
 
 void NGLineBoxFragmentBuilder::ChildList::MoveInBlockDirection(
diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_line_box_fragment_builder.h b/third_party/WebKit/Source/core/layout/ng/inline/ng_line_box_fragment_builder.h
index ac5958e..8fb6e88 100644
--- a/third_party/WebKit/Source/core/layout/ng/inline/ng_line_box_fragment_builder.h
+++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_line_box_fragment_builder.h
@@ -50,9 +50,53 @@
 
     scoped_refptr<NGLayoutResult> layout_result;
     scoped_refptr<NGPhysicalFragment> fragment;
+    LayoutObject* out_of_flow_positioned_box = nullptr;
+    LayoutObject* out_of_flow_containing_box = nullptr;
     NGLogicalOffset offset;
+    LayoutUnit inline_size;
+    unsigned box_data_index = 0;
+    UBiDiLevel bidi_level = 0xff;
 
-    bool HasFragment() const { return layout_result || fragment; }
+    // Empty constructor needed for |resize()|.
+    Child() {}
+    // Create a placeholder. A placeholder does not have a fragment nor a bidi
+    // level.
+    Child(NGLogicalOffset offset) : offset(offset) {}
+    // Crete a bidi control. A bidi control does not have a fragment, but has
+    // bidi level and affects bidi reordering.
+    Child(UBiDiLevel bidi_level) : bidi_level(bidi_level) {}
+    // Create an in-flow |NGLayoutResult|.
+    Child(scoped_refptr<NGLayoutResult> layout_result,
+          NGLogicalOffset offset,
+          LayoutUnit inline_size,
+          UBiDiLevel bidi_level)
+        : layout_result(std::move(layout_result)),
+          offset(offset),
+          inline_size(inline_size),
+          bidi_level(bidi_level) {}
+    // Create an in-flow |NGPhysicalFragment|.
+    Child(scoped_refptr<NGPhysicalFragment> fragment,
+          LayoutUnit block_offset,
+          LayoutUnit inline_size,
+          UBiDiLevel bidi_level)
+        : fragment(std::move(fragment)),
+          offset({LayoutUnit(), block_offset}),
+          inline_size(inline_size),
+          bidi_level(bidi_level) {}
+    // Create an out-of-flow positioned object.
+    Child(LayoutObject* out_of_flow_positioned_box,
+          LayoutObject* out_of_flow_containing_box,
+          UBiDiLevel bidi_level)
+        : out_of_flow_positioned_box(out_of_flow_positioned_box),
+          out_of_flow_containing_box(out_of_flow_containing_box),
+          bidi_level(bidi_level) {}
+
+    bool HasInFlowFragment() const { return layout_result || fragment; }
+    bool HasOutOfFlowFragment() const { return out_of_flow_positioned_box; }
+    bool HasFragment() const {
+      return HasInFlowFragment() || HasOutOfFlowFragment();
+    }
+    bool HasBidiLevel() const { return bidi_level != 0xff; }
     const NGPhysicalFragment* PhysicalFragment() const;
   };
 
@@ -76,6 +120,7 @@
       children_.ReserveInitialCapacity(capacity);
     }
     void clear() { children_.clear(); }
+    void resize(size_t size) { children_.resize(size); }
 
     using iterator = Vector<Child, 16>::iterator;
     iterator begin() { return children_.begin(); }
@@ -84,13 +129,18 @@
     const_iterator begin() const { return children_.begin(); }
     const_iterator end() const { return children_.end(); }
 
-    void AddChild(scoped_refptr<NGLayoutResult>, const NGLogicalOffset&);
-    void AddChild(scoped_refptr<NGPhysicalFragment>, const NGLogicalOffset&);
-    // nullptr child is a placeholder until enclosing inline boxes are closed
-    // and we know the final box structure and their positions. This variant
-    // helps to avoid needing static_cast when adding a nullptr.
-    void AddChild(std::nullptr_t, const NGLogicalOffset&);
+    // Add a child. Accepts all constructor arguments for |Child|.
+    template <class... Args>
+    void AddChild(Args&&... args) {
+      children_.push_back(Child(std::forward<Args>(args)...));
+    }
+    void InsertChild(unsigned,
+                     scoped_refptr<NGLayoutResult>,
+                     const NGLogicalOffset&,
+                     LayoutUnit inline_size,
+                     UBiDiLevel);
 
+    void MoveInInlineDirection(LayoutUnit, unsigned start, unsigned end);
     void MoveInBlockDirection(LayoutUnit);
     void MoveInBlockDirection(LayoutUnit, unsigned start, unsigned end);
 
diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_line_breaker.cc b/third_party/WebKit/Source/core/layout/ng/inline/ng_line_breaker.cc
index 02eaa68..a7ed885 100644
--- a/third_party/WebKit/Source/core/layout/ng/inline/ng_line_breaker.cc
+++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_line_breaker.cc
@@ -571,15 +571,16 @@
   DCHECK(item.Style());
   const ComputedStyle& style = *item.Style();
   item_result->needs_box_when_empty = false;
+  item_result->has_edge = item.HasStartEdge();
   if (style.HasBorder() || style.HasPadding() ||
-      (style.HasMargin() && item.HasStartEdge())) {
+      (style.HasMargin() && item_result->has_edge)) {
     NGBoxStrut borders = ComputeBorders(constraint_space_, style);
     NGBoxStrut paddings = ComputePadding(constraint_space_, style);
     item_result->borders_paddings_block_start =
         borders.block_start + paddings.block_start;
     item_result->borders_paddings_block_end =
         borders.block_end + paddings.block_end;
-    if (item.HasStartEdge()) {
+    if (item_result->has_edge) {
       item_result->margins =
           ComputeMarginsForContainer(constraint_space_, style);
       item_result->inline_size = item_result->margins.inline_start +
@@ -611,7 +612,8 @@
   NGInlineItemResult* item_result = &item_results->back();
 
   item_result->needs_box_when_empty = false;
-  if (item.HasEndEdge()) {
+  item_result->has_edge = item.HasEndEdge();
+  if (item_result->has_edge) {
     DCHECK(item.Style());
     const ComputedStyle& style = *item.Style();
     item_result->margins = ComputeMarginsForContainer(constraint_space_, style);
diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_physical_text_fragment.cc b/third_party/WebKit/Source/core/layout/ng/inline/ng_physical_text_fragment.cc
index 7a6be610..2c5566e 100644
--- a/third_party/WebKit/Source/core/layout/ng/inline/ng_physical_text_fragment.cc
+++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_physical_text_fragment.cc
@@ -14,47 +14,36 @@
   if (!shape_result_)
     return {};
 
-  // Glyph bounds is in logical coordinate, origin at the alphabetic baseline.
-  LayoutRect visual_rect = EnclosingLayoutRect(shape_result_->Bounds());
+  // TODO(kojii): Copying InlineTextBox logic from
+  // InlineFlowBox::ComputeOverflow().
+  //
+  // InlineFlowBox::ComputeOverflow() computes GlpyhOverflow first
+  // (ComputeGlyphOverflow) then AddTextBoxVisualOverflow(). We probably don't
+  // have to keep these two steps separated.
+
+  // Glyph bounds is in logical coordinate, origin at the baseline.
+  FloatRect visual_float_rect = shape_result_->Bounds();
 
   // Make the origin at the logical top of this fragment.
+  // ShapeResult::Bounds() is in logical coordinate with alphabetic baseline.
   const ComputedStyle& style = Style();
-  const Font& font = style.GetFont();
-  const SimpleFontData* font_data = font.PrimaryFont();
-  if (font_data) {
-    visual_rect.SetY(visual_rect.Y() + font_data->GetFontMetrics().FixedAscent(
-                                           kAlphabeticBaseline));
-  }
+  const SimpleFontData* font_data = style.GetFont().PrimaryFont();
+  visual_float_rect.SetY(
+      visual_float_rect.Y() +
+      font_data->GetFontMetrics().FixedAscent(kAlphabeticBaseline));
 
+  // TODO(kojii): Copying from AddTextBoxVisualOverflow()
   if (float stroke_width = style.TextStrokeWidth()) {
-    visual_rect.Inflate(LayoutUnit::FromFloatCeil(stroke_width / 2.0f));
+    visual_float_rect.Inflate(stroke_width / 2.0f);
   }
 
-  if (style.GetTextEmphasisMark() != TextEmphasisMark::kNone) {
-    LayoutUnit emphasis_mark_height =
-        LayoutUnit(font.EmphasisMarkHeight(style.TextEmphasisMarkString()));
-    DCHECK_GT(emphasis_mark_height, LayoutUnit());
-    if (style.GetTextEmphasisLineLogicalSide() == LineLogicalSide::kOver) {
-      visual_rect.ShiftYEdgeTo(
-          std::min(visual_rect.Y(), -emphasis_mark_height));
-    } else {
-      LayoutUnit logical_height =
-          style.IsHorizontalWritingMode() ? Size().height : Size().width;
-      visual_rect.ShiftMaxYEdgeTo(
-          std::max(visual_rect.MaxY(), logical_height + emphasis_mark_height));
-    }
-  }
+  // TODO(kojii): Implement emphasis marks.
 
   if (ShadowList* text_shadow = style.TextShadow()) {
-    LayoutRectOutsets text_shadow_logical_outsets =
-        LayoutRectOutsets(text_shadow->RectOutsetsIncludingOriginal())
-            .LineOrientationOutsets(style.GetWritingMode());
-    text_shadow_logical_outsets.ClampNegativeToZero();
-    visual_rect.Expand(text_shadow_logical_outsets);
+    // TODO(kojii): Implement text shadow.
   }
 
-  visual_rect = LayoutRect(EnclosingIntRect(visual_rect));
-
+  LayoutRect visual_rect = EnclosingLayoutRect(visual_float_rect);
   switch (LineOrientation()) {
     case NGLineOrientation::kHorizontal:
       return NGPhysicalOffsetRect(visual_rect);
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_fragment_builder.cc b/third_party/WebKit/Source/core/layout/ng/ng_fragment_builder.cc
index dbfac9ad..9e8b81a 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_fragment_builder.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_fragment_builder.cc
@@ -275,20 +275,53 @@
               inline_container_fragments->at(key);
           if (!value.start_fragment) {
             value.start_fragment = descendant.fragment;
-            value.start_fragment_offset = descendant.offset_to_container_box;
+            value.start_fragment_union_rect.offset =
+                descendant.offset_to_container_box;
+            value.start_fragment_union_rect =
+                NGPhysicalOffsetRect(descendant.offset_to_container_box,
+                                     value.start_fragment->Size());
             value.start_linebox_fragment = linebox;
             value.start_linebox_offset = offsets_.at(i);
           }
-          value.end_fragment = descendant.fragment;
-          value.end_fragment_offset = descendant.offset_to_container_box;
-          value.end_linebox_fragment = linebox;
-          value.end_linebox_offset = offsets_.at(i);
+          if (!value.end_fragment || value.end_linebox_fragment != linebox) {
+            value.end_fragment = descendant.fragment;
+            value.end_fragment_union_rect = NGPhysicalOffsetRect(
+                descendant.offset_to_container_box, value.end_fragment->Size());
+            value.end_linebox_fragment = linebox;
+            value.end_linebox_offset = offsets_.at(i);
+          }
+          // Extend the union size
+          if (value.start_linebox_fragment == linebox) {
+            // std::max because initial box might have larger extent than its
+            // descendants.
+            value.start_fragment_union_rect.size.width =
+                std::max(descendant.offset_to_container_box.left +
+                             descendant.fragment->Size().width -
+                             value.start_fragment_union_rect.offset.left,
+                         value.start_fragment_union_rect.size.width);
+            value.start_fragment_union_rect.size.height =
+                std::max(descendant.offset_to_container_box.top +
+                             descendant.fragment->Size().height -
+                             value.start_fragment_union_rect.offset.top,
+                         value.start_fragment_union_rect.size.width);
+          }
+          if (value.end_linebox_fragment == linebox) {
+            value.end_fragment_union_rect.size.width =
+                std::max(descendant.offset_to_container_box.left +
+                             descendant.fragment->Size().width -
+                             value.start_fragment_union_rect.offset.left,
+                         value.end_fragment_union_rect.size.width);
+            value.end_fragment_union_rect.size.height =
+                std::max(descendant.offset_to_container_box.top +
+                             descendant.fragment->Size().height -
+                             value.start_fragment_union_rect.offset.top,
+                         value.end_fragment_union_rect.size.height);
+          }
           inline_container_fragments->Set(key, value);
         }
       }
     }
   }
-  // TODO(atotic) need to implement correct RTL handling.
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_fragment_builder.h b/third_party/WebKit/Source/core/layout/ng/ng_fragment_builder.h
index ff57900a8..d386a684 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_fragment_builder.h
+++ b/third_party/WebKit/Source/core/layout/ng/ng_fragment_builder.h
@@ -6,6 +6,7 @@
 #define NGFragmentBuilder_h
 
 #include "core/layout/ng/geometry/ng_border_edges.h"
+#include "core/layout/ng/geometry/ng_physical_offset_rect.h"
 #include "core/layout/ng/geometry/ng_physical_rect.h"
 #include "core/layout/ng/inline/ng_baseline.h"
 #include "core/layout/ng/ng_break_token.h"
@@ -14,7 +15,6 @@
 #include "core/layout/ng/ng_out_of_flow_positioned_descendant.h"
 #include "platform/heap/Handle.h"
 #include "platform/wtf/Allocator.h"
-
 namespace blink {
 
 class NGPhysicalFragment;
@@ -111,21 +111,22 @@
   // Inline containing block geometry is defined by two fragments:
   // start and end. FragmentPair holds the information needed to compute
   // inline containing block geometry wrt enclosing container block.
-  //
-  // start_fragment is the start fragment of inline containing block.
-  // start_fragment_offset is offset wrt start_linebox_fragment
-  // start_linebox_offset is offset of linebox from inline-cb
-  // end_fragment/linebox are complementary properties for end fragment.
   struct FragmentPair {
     DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
+    // Linebox that contains start_fragment.
     const NGPhysicalLineBoxFragment* start_linebox_fragment;
+    // Offset of start_linebox from containing block.
     NGLogicalOffset start_linebox_offset;
+    // Start fragment of inline containing block.
     const NGPhysicalFragment* start_fragment;
-    NGPhysicalOffset start_fragment_offset;
+    // Start fragment rect combined with rectangles of all fragments
+    // generated by same Element as start_fragment.
+    NGPhysicalOffsetRect start_fragment_union_rect;
+    // end_** variables are end fragment counterparts to start fragment.
     const NGPhysicalLineBoxFragment* end_linebox_fragment;
     NGLogicalOffset end_linebox_offset;
     const NGPhysicalFragment* end_fragment;
-    NGPhysicalOffset end_fragment_offset;
+    NGPhysicalOffsetRect end_fragment_union_rect;
   };
 
   void ComputeInlineContainerFragments(
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_out_of_flow_layout_part.cc b/third_party/WebKit/Source/core/layout/ng/ng_out_of_flow_layout_part.cc
index 79b80a6..8d5a538 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_out_of_flow_layout_part.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_out_of_flow_layout_part.cc
@@ -164,9 +164,10 @@
         default_containing_block_.style->Direction();
     // Step 1
     NGLogicalOffset start_fragment_logical_offset =
-        block_info.value.start_fragment_offset.ConvertToLogical(
+        block_info.value.start_fragment_union_rect.offset.ConvertToLogical(
             container_writing_mode, container_direction,
-            start_linebox_fragment->Size(), start_fragment->Size());
+            start_linebox_fragment->Size(),
+            block_info.value.start_fragment_union_rect.size);
     // Text fragments do not include inline-cb borders and padding.
     if (start_fragment->IsText()) {
       start_fragment_logical_offset -= inline_cb_borders.StartOffset();
@@ -186,9 +187,10 @@
         block_info.value.end_linebox_fragment;
     const NGPhysicalFragment* end_fragment = block_info.value.end_fragment;
     NGLogicalOffset end_fragment_logical_offset =
-        block_info.value.end_fragment_offset.ConvertToLogical(
+        block_info.value.end_fragment_union_rect.offset.ConvertToLogical(
             container_writing_mode, container_direction,
-            end_linebox_fragment->Size(), end_fragment->Size());
+            end_linebox_fragment->Size(),
+            block_info.value.end_fragment_union_rect.size);
     // Text fragments do not include inline-cb borders and padding.
     if (end_fragment->IsText()) {
       end_fragment_logical_offset += NGLogicalOffset(
@@ -198,7 +200,8 @@
     }
     NGLogicalOffset end_fragment_bottom_right =
         end_fragment_logical_offset +
-        end_fragment->Size().ConvertToLogical(container_writing_mode);
+        block_info.value.end_fragment_union_rect.size.ConvertToLogical(
+            container_writing_mode);
     NGPhysicalOffset end_fragment_physical_offset =
         end_fragment_bottom_right.ConvertToPhysical(
             container_writing_mode, container_direction,
@@ -249,8 +252,9 @@
     NGLogicalOffset default_container_offset;
     if (RuntimeEnabledFeatures::LayoutNGPaintFragmentsEnabled()) {
       // NGPaint offset is wrt parent fragment.
-      default_container_offset = start_fragment_logical_offset -
+      default_container_offset = start_fragment_logical_offset_wrt_box -
                                  default_containing_block_.content_offset;
+      default_container_offset += inline_cb_borders.StartOffset();
     } else {
       // Legacy offset is wrt inline container.
       default_container_offset =
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_out_of_flow_layout_part.h b/third_party/WebKit/Source/core/layout/ng/ng_out_of_flow_layout_part.h
index aecc67dbd..e30cde11 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_out_of_flow_layout_part.h
+++ b/third_party/WebKit/Source/core/layout/ng/ng_out_of_flow_layout_part.h
@@ -57,7 +57,8 @@
     NGLogicalOffset content_offset;
     // Physical content offset wrt border box.
     NGPhysicalOffset content_physical_offset;
-    // Logical offset wrt default containing block.
+    // Logical offset of container padding box
+    // wrt default containing block padding box.
     NGLogicalOffset default_container_offset;
   };
 
diff --git a/third_party/WebKit/Source/core/style/ComputedStyle.cpp b/third_party/WebKit/Source/core/style/ComputedStyle.cpp
index 28c47d91..3b563d7e 100644
--- a/third_party/WebKit/Source/core/style/ComputedStyle.cpp
+++ b/third_party/WebKit/Source/core/style/ComputedStyle.cpp
@@ -1359,26 +1359,6 @@
   return g_null_atom;
 }
 
-LineLogicalSide ComputedStyle::GetTextEmphasisLineLogicalSide() const {
-  TextEmphasisPosition position = GetTextEmphasisPosition();
-  if (IsHorizontalWritingMode()) {
-    return position == TextEmphasisPosition::kOverRight ||
-                   position == TextEmphasisPosition::kOverLeft
-               ? LineLogicalSide::kOver
-               : LineLogicalSide::kUnder;
-  }
-  if (GetWritingMode() != WritingMode::kSidewaysLr) {
-    return position == TextEmphasisPosition::kOverRight ||
-                   position == TextEmphasisPosition::kUnderRight
-               ? LineLogicalSide::kOver
-               : LineLogicalSide::kUnder;
-  }
-  return position == TextEmphasisPosition::kOverLeft ||
-                 position == TextEmphasisPosition::kUnderLeft
-             ? LineLogicalSide::kOver
-             : LineLogicalSide::kUnder;
-}
-
 CSSAnimationData& ComputedStyle::AccessAnimations() {
   if (!AnimationsInternal())
     SetAnimationsInternal(CSSAnimationData::Create());
diff --git a/third_party/WebKit/Source/core/style/ComputedStyle.h b/third_party/WebKit/Source/core/style/ComputedStyle.h
index 900753764..397c0252 100644
--- a/third_party/WebKit/Source/core/style/ComputedStyle.h
+++ b/third_party/WebKit/Source/core/style/ComputedStyle.h
@@ -876,7 +876,6 @@
     SetTextEmphasisMarkInternal(mark);
   }
   const AtomicString& TextEmphasisMarkString() const;
-  LineLogicalSide GetTextEmphasisLineLogicalSide() const;
 
   // -webkit-text-emphasis-color (aka -epub-text-emphasis-color)
   void SetTextEmphasisColor(const StyleColor& color) {
diff --git a/third_party/WebKit/Source/core/style/ComputedStyleConstants.h b/third_party/WebKit/Source/core/style/ComputedStyleConstants.h
index 262126d..6473388 100644
--- a/third_party/WebKit/Source/core/style/ComputedStyleConstants.h
+++ b/third_party/WebKit/Source/core/style/ComputedStyleConstants.h
@@ -253,11 +253,6 @@
   kUnderLeft,
 };
 
-enum class LineLogicalSide {
-  kOver,
-  kUnder,
-};
-
 }  // namespace blink
 
 #endif  // ComputedStyleConstants_h
diff --git a/third_party/WebKit/public/platform/web_feature.mojom b/third_party/WebKit/public/platform/web_feature.mojom
index a4d7f0e..38dd4dd 100644
--- a/third_party/WebKit/public/platform/web_feature.mojom
+++ b/third_party/WebKit/public/platform/web_feature.mojom
@@ -1783,6 +1783,7 @@
   kFileAccessedSessionStorage = 2274,
   kFileAccessedSharedWorker = 2275,
   kV8MediaKeys_GetStatusForPolicy_Method = 2276,
+  kV8DeoptimizerDisableSpeculation = 2277,
 
   // Add new features immediately above this line. Don't change assigned
   // numbers of any item, and don't reuse removed slots.
diff --git a/third_party/webrtc_overrides/BUILD.gn b/third_party/webrtc_overrides/BUILD.gn
index 7c938eb..8a4f25213 100644
--- a/third_party/webrtc_overrides/BUILD.gn
+++ b/third_party/webrtc_overrides/BUILD.gn
@@ -121,11 +121,11 @@
     ":webrtc",
     "//third_party/libsrtp",
     "//third_party/usrsctp",
-    "//third_party/webrtc/api:libjingle_peerconnection",
     "//third_party/webrtc/media:rtc_media",
     "//third_party/webrtc/media:rtc_media_base",
     "//third_party/webrtc/modules/media_file",
     "//third_party/webrtc/modules/video_capture",
+    "//third_party/webrtc/pc:libjingle_peerconnection",
     "//third_party/webrtc/pc:rtc_pc",
     "//third_party/webrtc/system_wrappers",
     "//third_party/webrtc/voice_engine",
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 6a88bbe..7c219c5 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -17280,6 +17280,7 @@
   <int value="2274" label="FileAccessedSessionStorage"/>
   <int value="2275" label="FileAccessedSharedWorker"/>
   <int value="2276" label="V8MediaKeys_GetStatusForPolicy_Method"/>
+  <int value="2277" label="V8DeoptimizerDisableSpeculation"/>
 </enum>
 
 <enum name="FeedbackSource">
diff --git a/ui/message_center/views/toast_contents_view.cc b/ui/message_center/views/toast_contents_view.cc
index e3d5604..1517157 100644
--- a/ui/message_center/views/toast_contents_view.cc
+++ b/ui/message_center/views/toast_contents_view.cc
@@ -191,9 +191,15 @@
     collection_->IncrementDeferCounter();
   fade_animation_->Stop();
 
-  closing_animation_ = (is_closing_ ? fade_animation_.get() : NULL);
-  fade_animation_->Reset(1);
-  fade_animation_->Hide();
+  closing_animation_ = (is_closing_ ? fade_animation_.get() : nullptr);
+  if (GetWidget()->GetLayer()->opacity() > 0.0) {
+    fade_animation_->Reset(1);
+    fade_animation_->Hide();
+  } else {
+    // If the layer is already transparent, do not trigger animation again.
+    // It happens when the toast is removed by touch gesture.
+    OnBoundsAnimationEndedOrCancelled(fade_animation_.get());
+  }
 }
 
 void ToastContentsView::OnBoundsAnimationEndedOrCancelled(