diff --git a/net/quic/chromium/quic_chromium_client_stream.cc b/net/quic/chromium/quic_chromium_client_stream.cc
index 1b1c90e..a084fe5c 100644
--- a/net/quic/chromium/quic_chromium_client_stream.cc
+++ b/net/quic/chromium/quic_chromium_client_stream.cc
@@ -73,6 +73,13 @@
   ResetAndReturn(&read_body_callback_).Run(rv);
 }
 
+void QuicChromiumClientStream::Handle::OnCanWrite() {
+  if (!write_callback_)
+    return;
+
+  base::ResetAndReturn(&write_callback_).Run(OK);
+}
+
 void QuicChromiumClientStream::Handle::OnClose() {
   if (stream_)
     SaveState();
@@ -144,7 +151,12 @@
     const CompletionCallback& callback) {
   if (!stream_)
     return ERR_CONNECTION_CLOSED;
-  return stream_->WriteStreamData(data, fin, callback);
+
+  if (stream_->WriteStreamData(data, fin))
+    return OK;
+
+  write_callback_ = callback;
+  return ERR_IO_PENDING;
 }
 
 int QuicChromiumClientStream::Handle::WritevStreamData(
@@ -154,7 +166,12 @@
     const CompletionCallback& callback) {
   if (!stream_)
     return ERR_CONNECTION_CLOSED;
-  return stream_->WritevStreamData(buffers, lengths, fin, callback);
+
+  if (stream_->WritevStreamData(buffers, lengths, fin))
+    return OK;
+
+  write_callback_ = callback;
+  return ERR_IO_PENDING;
 }
 
 int QuicChromiumClientStream::Handle::Read(IOBuffer* buf, int buf_len) {
@@ -386,9 +403,8 @@
 void QuicChromiumClientStream::OnCanWrite() {
   QuicStream::OnCanWrite();
 
-  if (!HasBufferedData() && !write_callback_.is_null()) {
-    base::ResetAndReturn(&write_callback_).Run(OK);
-  }
+  if (!HasBufferedData() && handle_)
+    handle_->OnCanWrite();
 }
 
 size_t QuicChromiumClientStream::WriteHeaders(
@@ -415,27 +431,18 @@
                                : kV3HighestPriority;
 }
 
-int QuicChromiumClientStream::WriteStreamData(
-    QuicStringPiece data,
-    bool fin,
-    const CompletionCallback& callback) {
-  // We should not have data buffered.
+bool QuicChromiumClientStream::WriteStreamData(QuicStringPiece data, bool fin) {
+  // Must not be called when data is buffered.
   DCHECK(!HasBufferedData());
   // Writes the data, or buffers it.
   WriteOrBufferData(data, fin, nullptr);
-  if (!HasBufferedData()) {
-    return OK;
-  }
-
-  write_callback_ = callback;
-  return ERR_IO_PENDING;
+  return !HasBufferedData();  // Was all data written?
 }
 
-int QuicChromiumClientStream::WritevStreamData(
+bool QuicChromiumClientStream::WritevStreamData(
     const std::vector<scoped_refptr<IOBuffer>>& buffers,
     const std::vector<int>& lengths,
-    bool fin,
-    const CompletionCallback& callback) {
+    bool fin) {
   // Must not be called when data is buffered.
   DCHECK(!HasBufferedData());
   // Writes the data, or buffers it.
@@ -444,12 +451,7 @@
     QuicStringPiece string_data(buffers[i]->data(), lengths[i]);
     WriteOrBufferData(string_data, is_fin, nullptr);
   }
-  if (!HasBufferedData()) {
-    return OK;
-  }
-
-  write_callback_ = callback;
-  return ERR_IO_PENDING;
+  return !HasBufferedData();  // Was all data written?
 }
 
 std::unique_ptr<QuicChromiumClientStream::Handle>
diff --git a/net/quic/chromium/quic_chromium_client_stream.h b/net/quic/chromium/quic_chromium_client_stream.h
index 14901d8edc..e512b457 100644
--- a/net/quic/chromium/quic_chromium_client_stream.h
+++ b/net/quic/chromium/quic_chromium_client_stream.h
@@ -157,6 +157,7 @@
     void OnTrailingHeadersAvailable(const SpdyHeaderBlock& headers,
                                     size_t frame_len);
     void OnDataAvailable();
+    void OnCanWrite();
     void OnClose();
     void OnError(int error);
 
@@ -166,13 +167,19 @@
     QuicChromiumClientStream* stream_;  // Unowned.
     Delegate* delegate_;                // Owns this.
 
+    // Callback to be invoked when ReadHeaders completes asynchronously.
     CompletionCallback read_headers_callback_;
     SpdyHeaderBlock* read_headers_buffer_;
 
+    // Callback to be invoked when ReadBody completes asynchronously.
     CompletionCallback read_body_callback_;
     IOBuffer* read_body_buffer_;
     int read_body_buffer_len_;
 
+    // Callback to be invoked when WriteStreamData or WritevStreamData completes
+    // asynchronously.
+    CompletionCallback write_callback_;
+
     QuicStreamId id_;
     QuicErrorCode connection_error_;
     QuicRstStreamErrorCode stream_error_;
@@ -217,15 +224,15 @@
   // of client-side streams should be able to set the priority.
   using QuicSpdyStream::SetPriority;
 
-  int WriteStreamData(QuicStringPiece data,
-                      bool fin,
-                      const CompletionCallback& callback);
+  // Writes |data| to the peer and closes the write side if |fin| is true.
+  // Returns true if the data have been fully written. If the data was not fully
+  // written, returns false and OnCanWrite() will be invoked later.
+  bool WriteStreamData(QuicStringPiece data, bool fin);
   // Same as WriteStreamData except it writes data from a vector of IOBuffers,
   // with the length of each buffer at the corresponding index in |lengths|.
-  int WritevStreamData(const std::vector<scoped_refptr<IOBuffer>>& buffers,
-                       const std::vector<int>& lengths,
-                       bool fin,
-                       const CompletionCallback& callback);
+  bool WritevStreamData(const std::vector<scoped_refptr<IOBuffer>>& buffers,
+                        const std::vector<int>& lengths,
+                        bool fin);
 
   // Creates a new Handle for this stream and sets |delegate| on the handle.
   // Must only be called once.
@@ -274,10 +281,6 @@
   // True when initial headers have been sent.
   bool initial_headers_sent_;
 
-  // Callback to be invoked when WriteStreamData or WritevStreamData completes
-  // asynchronously.
-  CompletionCallback write_callback_;
-
   QuicClientSessionBase* session_;
 
   // Set to false if this stream to not be migrated during connection migration.
diff --git a/net/quic/chromium/quic_chromium_client_stream_test.cc b/net/quic/chromium/quic_chromium_client_stream_test.cc
index aba5b919..0623610f 100644
--- a/net/quic/chromium/quic_chromium_client_stream_test.cc
+++ b/net/quic/chromium/quic_chromium_client_stream_test.cc
@@ -641,7 +641,7 @@
   EXPECT_CALL(session_, WritevData(stream_, stream_->id(), _, _, _, _))
       .WillOnce(Return(QuicConsumedData(kDataLen, true)));
   TestCompletionCallback callback;
-  EXPECT_EQ(OK, stream_->WriteStreamData(QuicStringPiece(kData1, kDataLen),
+  EXPECT_EQ(OK, handle_->WriteStreamData(QuicStringPiece(kData1, kDataLen),
                                          true, callback.callback()));
 }
 
@@ -657,7 +657,7 @@
       .WillOnce(Return(QuicConsumedData(0, false)));
   TestCompletionCallback callback;
   EXPECT_EQ(ERR_IO_PENDING,
-            stream_->WriteStreamData(QuicStringPiece(kData1, kDataLen), true,
+            handle_->WriteStreamData(QuicStringPiece(kData1, kDataLen), true,
                                      callback.callback()));
   ASSERT_FALSE(callback.have_result());
 
@@ -682,7 +682,7 @@
       .WillOnce(Return(QuicConsumedData(buf2->size(), true)));
   TestCompletionCallback callback;
   EXPECT_EQ(
-      OK, stream_->WritevStreamData({buf1, buf2}, {buf1->size(), buf2->size()},
+      OK, handle_->WritevStreamData({buf1, buf2}, {buf1->size(), buf2->size()},
                                     true, callback.callback()));
 }
 
@@ -702,7 +702,7 @@
       .WillOnce(Return(QuicConsumedData(0, false)));
   TestCompletionCallback callback;
   EXPECT_EQ(ERR_IO_PENDING,
-            stream_->WritevStreamData({buf1.get(), buf2.get()},
+            handle_->WritevStreamData({buf1.get(), buf2.get()},
                                       {buf1->size(), buf2->size()}, true,
                                       callback.callback()));
   ASSERT_FALSE(callback.have_result());
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 553ca7d2..1d2c0df7 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -859,6 +859,7 @@
 crbug.com/635619 virtual/layout_ng/fast/block/float/canvas-with-floats-marked-for-layout.html [ Crash ]
 crbug.com/635619 virtual/layout_ng/fast/block/float/centered-float-avoidance-complexity.html [ Failure ]
 crbug.com/635619 virtual/layout_ng/fast/block/float/checkbox-and-radio-avoid-floats.html [ Failure ]
+crbug.com/635619 virtual/layout_ng/fast/block/float/clamped-right-float.html [ Failure ]
 crbug.com/635619 virtual/layout_ng/fast/block/float/clear-element-too-wide-for-containing-block.html [ Failure ]
 crbug.com/635619 virtual/layout_ng/fast/block/float/clear-intruding-floats-when-moving-to-inline-parent-3.html [ Crash Failure ]
 crbug.com/635619 virtual/layout_ng/fast/block/float/clear-to-fit.html [ Failure ]
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 4d27613..64cdfd1 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
@@ -7,6 +7,8 @@
 #include "core/layout/ng/inline/ng_inline_node.h"
 #include "core/layout/ng/inline/ng_line_box_fragment_builder.h"
 #include "core/layout/ng/inline/ng_text_fragment_builder.h"
+#include "core/layout/ng/ng_fragment_builder.h"
+#include "core/layout/ng/ng_layout_result.h"
 #include "core/style/ComputedStyle.h"
 
 namespace blink {
@@ -36,6 +38,16 @@
   }
 }
 
+void NGInlineBoxState::SetNeedsBoxFragment(
+    LayoutUnit position,
+    LayoutUnit borders_paddings_block_start,
+    LayoutUnit borders_paddings_block_height) {
+  needs_box_fragment = true;
+  line_left_position = position;
+  this->borders_paddings_block_start = borders_paddings_block_start;
+  this->borders_paddings_block_height = borders_paddings_block_height;
+}
+
 NGInlineBoxState* NGInlineLayoutStateStack::OnBeginPlaceItems(
     const ComputedStyle* line_style,
     FontBaseline baseline_type) {
@@ -67,13 +79,12 @@
 
 NGInlineBoxState* NGInlineLayoutStateStack::OnOpenTag(
     const NGInlineItem& item,
-    NGLineBoxFragmentBuilder* line_box,
-    NGTextFragmentBuilder* text_builder) {
+    NGLineBoxFragmentBuilder* line_box) {
   stack_.resize(stack_.size() + 1);
   NGInlineBoxState* box = &stack_.back();
   box->fragment_start = line_box->Children().size();
+  box->item = &item;
   box->style = item.Style();
-  text_builder->SetDirection(box->style->Direction());
   return box;
 }
 
@@ -81,8 +92,9 @@
     const NGInlineItem& item,
     NGLineBoxFragmentBuilder* line_box,
     NGInlineBoxState* box,
-    FontBaseline baseline_type) {
-  EndBoxState(box, line_box, baseline_type);
+    FontBaseline baseline_type,
+    LayoutUnit position) {
+  EndBoxState(box, line_box, baseline_type, position);
   // TODO(kojii): When the algorithm restarts from a break token, the stack may
   // underflow. We need either synthesize a missing box state, or push all
   // parents on initialize.
@@ -92,19 +104,27 @@
 
 void NGInlineLayoutStateStack::OnEndPlaceItems(
     NGLineBoxFragmentBuilder* line_box,
-    FontBaseline baseline_type) {
+    FontBaseline baseline_type,
+    LayoutUnit position) {
   for (auto it = stack_.rbegin(); it != stack_.rend(); ++it) {
     NGInlineBoxState* box = &(*it);
-    EndBoxState(box, line_box, baseline_type);
+    EndBoxState(box, line_box, baseline_type, position);
   }
 
+  if (!box_placeholders_.IsEmpty())
+    CreateBoxFragments(line_box);
+
   DCHECK(!LineBoxState().metrics.IsEmpty());
   line_box->SetMetrics(LineBoxState().metrics);
 }
 
 void NGInlineLayoutStateStack::EndBoxState(NGInlineBoxState* box,
                                            NGLineBoxFragmentBuilder* line_box,
-                                           FontBaseline baseline_type) {
+                                           FontBaseline baseline_type,
+                                           LayoutUnit position) {
+  if (box->needs_box_fragment)
+    AddBoxFragmentPlaceholder(box, line_box, baseline_type, position);
+
   PositionPending position_pending =
       ApplyBaselineShift(box, line_box, baseline_type);
 
@@ -114,6 +134,106 @@
   }
 }
 
+// Crete a placeholder for a box fragment.
+// We keep a flat list of fragments because it is more suitable for operations
+// such as ApplyBaselineShift. Later, CreateBoxFragments() creates box fragments
+// from placeholders.
+void NGInlineLayoutStateStack::AddBoxFragmentPlaceholder(
+    NGInlineBoxState* box,
+    NGLineBoxFragmentBuilder* line_box,
+    FontBaseline baseline_type,
+    LayoutUnit position) {
+  if (box->fragment_start == line_box->Children().size()) {
+    // Don't create a placeholder if the inline box is empty.
+    // Whether to create this box or not affects layout when the line contains
+    // only this box, since this box participates the line height.
+    // TODO(kojii): Testing indicates that we should create a box if it has
+    // borders, but not for backgrounds. But creating such a RootInlineBox needs
+    // additional code. The plan is to enable such line box when NG paint is
+    // enabled.
+    return;
+  }
+
+  // The inline box should have the height of the font metrics without the
+  // line-height property. Compute from style because |box->metrics| includes
+  // the line-height property.
+  DCHECK(box->style);
+  const ComputedStyle& style = *box->style;
+  NGLineHeightMetrics metrics(style, baseline_type);
+
+  // Extend the block direction of the box by borders and paddings. Inline
+  // direction is already included into positions in NGLineBreaker.
+  NGLogicalRect bounds(
+      box->line_left_position,
+      -metrics.ascent - box->borders_paddings_block_start,
+      position - box->line_left_position,
+      metrics.LineHeight() + box->borders_paddings_block_height);
+
+  // 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->Children().size();
+  box_placeholders_.push_back(BoxFragmentPlaceholder{
+      box->fragment_start, fragment_end, box->item, bounds.size});
+  line_box->AddChild(nullptr, bounds.offset);
+}
+
+// Create box fragments and construct a tree from the placeholders.
+void NGInlineLayoutStateStack::CreateBoxFragments(
+    NGLineBoxFragmentBuilder* line_box) {
+  DCHECK(!box_placeholders_.IsEmpty());
+
+  Vector<RefPtr<NGPhysicalFragment>> children =
+      std::move(line_box->MutableChildren());
+  Vector<NGLogicalOffset> offsets = std::move(line_box->MutableOffsets());
+  DCHECK(line_box->Children().IsEmpty() && line_box->Offsets().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_) {
+    NGFragmentBuilder box(NGPhysicalFragment::kFragmentBox,
+                          placeholder.item->GetLayoutObject());
+    const NGLogicalOffset& box_offset = offsets[placeholder.fragment_end];
+    for (unsigned i = placeholder.fragment_start; i < placeholder.fragment_end;
+         i++) {
+      if (RefPtr<NGPhysicalFragment>& child = children[i]) {
+        box.AddChild(std::move(child), offsets[i] - box_offset);
+        DCHECK(!children[i]);
+      }
+    }
+
+    box.SetWritingMode(line_box->WritingMode());
+    box.SetDirection(placeholder.item->Direction());
+    box.SetSize(placeholder.size);
+    // TODO(kojii): Overflow size should be computed from children.
+    box.SetOverflowSize(placeholder.size);
+    RefPtr<NGLayoutResult> layout_result = box.ToBoxFragment();
+    DCHECK(!children[placeholder.fragment_end]);
+    children[placeholder.fragment_end] =
+        std::move(layout_result->MutablePhysicalFragment());
+  }
+  box_placeholders_.clear();
+
+  // Add the list to line_box by skipping null fragments; i.e., fragments added
+  // to box children.
+  for (unsigned i = 0; i < children.size(); i++) {
+    if (children[i])
+      line_box->AddChild(children[i], offsets[i]);
+  }
+}
+
 NGInlineLayoutStateStack::PositionPending
 NGInlineLayoutStateStack::ApplyBaselineShift(NGInlineBoxState* box,
                                              NGLineBoxFragmentBuilder* line_box,
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 96106ab..5fcc396 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
@@ -6,6 +6,7 @@
 #define NGInlineBoxState_h
 
 #include "core/CoreExport.h"
+#include "core/layout/ng/geometry/ng_logical_size.h"
 #include "core/layout/ng/inline/ng_line_height_metrics.h"
 #include "core/style/ComputedStyleConstants.h"
 #include "platform/LayoutUnit.h"
@@ -16,7 +17,6 @@
 
 class NGInlineItem;
 class NGLineBoxFragmentBuilder;
-class NGTextFragmentBuilder;
 
 // Fragments that require the layout position/size of ancestor are packed in
 // this struct.
@@ -32,12 +32,21 @@
 // require ancestor position or size.
 struct NGInlineBoxState {
   unsigned fragment_start;
+  const NGInlineItem* item;
   const ComputedStyle* style;
   NGLineHeightMetrics metrics;
   NGLineHeightMetrics text_metrics;
   LayoutUnit text_top;
+
+  // These values are to create a box fragment. Set only when needs_box_fragment
+  // is set.
+  LayoutUnit line_left_position;
+  LayoutUnit borders_paddings_block_start;
+  LayoutUnit borders_paddings_block_height;
+
   Vector<NGPendingPositions> pending_descendants;
   bool include_used_fonts = false;
+  bool needs_box_fragment = false;
 
   // Compute text metrics for a box. All text in a box share the same metrics.
   void ComputeTextMetrics(const ComputedStyle& style, FontBaseline);
@@ -45,6 +54,11 @@
                            unsigned start,
                            unsigned end,
                            FontBaseline);
+
+  // Create a box fragment for this box.
+  void SetNeedsBoxFragment(LayoutUnit line_left_position,
+                           LayoutUnit borders_paddings_block_start,
+                           LayoutUnit borders_paddings_block_height);
 };
 
 // Represents the inline tree structure. This class provides:
@@ -61,23 +75,33 @@
   NGInlineBoxState* OnBeginPlaceItems(const ComputedStyle*, FontBaseline);
 
   // Push a box state stack.
-  NGInlineBoxState* OnOpenTag(const NGInlineItem&,
-                              NGLineBoxFragmentBuilder*,
-                              NGTextFragmentBuilder*);
+  NGInlineBoxState* OnOpenTag(const NGInlineItem&, NGLineBoxFragmentBuilder*);
 
   // Pop a box state stack.
   NGInlineBoxState* OnCloseTag(const NGInlineItem&,
                                NGLineBoxFragmentBuilder*,
                                NGInlineBoxState*,
-                               FontBaseline);
+                               FontBaseline,
+                               LayoutUnit position);
 
   // Compute all the pending positioning at the end of a line.
-  void OnEndPlaceItems(NGLineBoxFragmentBuilder*, FontBaseline);
+  void OnEndPlaceItems(NGLineBoxFragmentBuilder*,
+                       FontBaseline,
+                       LayoutUnit position);
 
  private:
   // End of a box state, either explicitly by close tag, or implicitly at the
   // end of a line.
-  void EndBoxState(NGInlineBoxState*, NGLineBoxFragmentBuilder*, FontBaseline);
+  void EndBoxState(NGInlineBoxState*,
+                   NGLineBoxFragmentBuilder*,
+                   FontBaseline,
+                   LayoutUnit position);
+
+  void AddBoxFragmentPlaceholder(NGInlineBoxState*,
+                                 NGLineBoxFragmentBuilder*,
+                                 FontBaseline,
+                                 LayoutUnit position);
+  void CreateBoxFragments(NGLineBoxFragmentBuilder*);
 
   enum PositionPending { kPositionNotPending, kPositionPending };
 
@@ -91,7 +115,16 @@
                                      NGLineBoxFragmentBuilder*,
                                      FontBaseline);
 
+  // Data for a box fragment placeholder. See AddBoxFragmentPlaceholder().
+  struct BoxFragmentPlaceholder {
+    unsigned fragment_start;
+    unsigned fragment_end;
+    const NGInlineItem* item;
+    NGLogicalSize size;
+  };
+
   Vector<NGInlineBoxState, 4> stack_;
+  Vector<BoxFragmentPlaceholder, 4> box_placeholders_;
 };
 
 }  // namespace blink
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 95c075b..f9b7422 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
@@ -222,6 +222,7 @@
   NGLineHeightMetrics line_metrics_with_leading = line_metrics;
   line_metrics_with_leading.AddLeading(line_style.ComputedLineHeightAsFixed());
   NGLineBoxFragmentBuilder line_box(Node());
+  line_box.SetWritingMode(ConstraintSpace().WritingMode());
 
   // Compute heights of all inline items by placing the dominant baseline at 0.
   // The baseline is adjusted after the height of the line box is computed.
@@ -253,13 +254,26 @@
                                       item_result.end_offset);
       line_box.AddChild(std::move(text_fragment), {position, box->text_top});
     } else if (item.Type() == NGInlineItem::kOpenTag) {
-      box = box_states_.OnOpenTag(item, &line_box, &text_builder);
+      box = box_states_.OnOpenTag(item, &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
       box->ComputeTextMetrics(*item.Style(), baseline_type_);
+      text_builder.SetDirection(box->style->Direction());
+      // TODO(kojii): We may need more conditions to create box fragments.
+      if (item.Style()->HasBoxDecorationBackground()) {
+        // TODO(kojii): These are once computed in NGLineBreaker. Should copy to
+        // NGInlineItemResult to reuse here.
+        NGBoxStrut borders = ComputeBorders(*constraint_space_, *item.Style());
+        NGBoxStrut paddings = ComputePadding(*constraint_space_, *item.Style());
+        // TODO(kojii): Set paint edges.
+        box->SetNeedsBoxFragment(position,
+                                 borders.block_start + paddings.block_start,
+                                 borders.BlockSum() + paddings.BlockSum());
+      }
     } else if (item.Type() == NGInlineItem::kCloseTag) {
-      box = box_states_.OnCloseTag(item, &line_box, box, baseline_type_);
+      box = box_states_.OnCloseTag(item, &line_box, box, baseline_type_,
+                                   position);
     } else if (item.Type() == NGInlineItem::kAtomicInline) {
       box = PlaceAtomicInline(item, &item_result, position, &line_box,
                               &text_builder);
@@ -286,7 +300,7 @@
     return true;  // The line was empty.
   }
 
-  box_states_.OnEndPlaceItems(&line_box, baseline_type_);
+  box_states_.OnEndPlaceItems(&line_box, baseline_type_, position);
 
   // The baselines are always placed at pixel boundaries. Not doing so results
   // in incorrect layout of text decorations, most notably underlines.
@@ -342,7 +356,7 @@
     NGTextFragmentBuilder* text_builder) {
   DCHECK(item_result->layout_result);
 
-  NGInlineBoxState* box = box_states_.OnOpenTag(item, line_box, text_builder);
+  NGInlineBoxState* box = box_states_.OnOpenTag(item, line_box);
 
   // For replaced elements, inline-block elements, and inline-table elements,
   // the height is the height of their margin box.
@@ -371,6 +385,7 @@
   // TODO(kojii): Try to eliminate the wrapping text fragment and use the
   // |fragment| directly. Currently |CopyFragmentDataToLayoutBlockFlow|
   // requires a text fragment.
+  text_builder->SetDirection(item.Style()->Direction());
   text_builder->SetSize({fragment.InlineSize(), block_size});
   LayoutUnit line_top = item_result->margins.block_start - metrics.ascent;
   RefPtr<NGPhysicalTextFragment> text_fragment = text_builder->ToTextFragment(
@@ -378,7 +393,8 @@
       item_result->end_offset);
   line_box->AddChild(std::move(text_fragment), {position, line_top});
 
-  return box_states_.OnCloseTag(item, line_box, box, baseline_type_);
+  return box_states_.OnCloseTag(item, line_box, box, baseline_type_,
+                                LayoutUnit(0));
 }
 
 void NGInlineLayoutAlgorithm::FindNextLayoutOpportunity() {
diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_node.cc b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_node.cc
index 734d6ec..31440806 100644
--- a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_node.cc
+++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_node.cc
@@ -33,28 +33,120 @@
 
 namespace {
 
-// Set the geometry to InlineFlowBox by computing the union of children.
-void PlaceInlineFlowBoxes(InlineFlowBox* flow_box) {
+struct FragmentPosition {
+  NGLogicalOffset offset;
+  LayoutUnit inline_size;
+};
+
+// Create BidiRuns from a list of NGPhysicalFragment.
+// Produce a FragmentPosition map to place InlineBoxes.
+void CreateBidiRuns(BidiRunList<BidiRun>* bidi_runs,
+                    const Vector<RefPtr<NGPhysicalFragment>>& children,
+                    const NGConstraintSpace& constraint_space,
+                    NGLogicalOffset parent_offset,
+                    const Vector<NGInlineItem>& items,
+                    const Vector<unsigned, 32>& text_offsets,
+                    Vector<FragmentPosition, 32>* positions_for_bidi_runs_out,
+                    HashMap<LineLayoutItem, FragmentPosition>* positions_out) {
+  for (const auto& child : children) {
+    if (child->Type() == NGPhysicalFragment::kFragmentText) {
+      const auto* physical_fragment = ToNGPhysicalTextFragment(child.Get());
+      const NGInlineItem& item = items[physical_fragment->ItemIndex()];
+      BidiRun* run;
+      if (item.Type() == NGInlineItem::kText ||
+          item.Type() == NGInlineItem::kControl) {
+        LayoutObject* layout_object = item.GetLayoutObject();
+        DCHECK(layout_object->IsText());
+        unsigned text_offset = text_offsets[physical_fragment->ItemIndex()];
+        run = new BidiRun(physical_fragment->StartOffset() - text_offset,
+                          physical_fragment->EndOffset() - text_offset,
+                          item.BidiLevel(), LineLayoutItem(layout_object));
+        layout_object->ClearNeedsLayout();
+      } else if (item.Type() == NGInlineItem::kAtomicInline) {
+        LayoutObject* layout_object = item.GetLayoutObject();
+        DCHECK(layout_object->IsAtomicInlineLevel());
+        run =
+            new BidiRun(0, 1, item.BidiLevel(), LineLayoutItem(layout_object));
+      } else {
+        continue;
+      }
+      bidi_runs->AddRun(run);
+      NGTextFragment fragment(constraint_space.WritingMode(),
+                              physical_fragment);
+      // Store text fragments in a vector in the same order as BidiRunList.
+      // One LayoutText may produce multiple text fragments that they can't
+      // be set to a map.
+      positions_for_bidi_runs_out->push_back(FragmentPosition{
+          fragment.Offset() + parent_offset, fragment.InlineSize()});
+    } else {
+      DCHECK_EQ(child->Type(), NGPhysicalFragment::kFragmentBox);
+      NGPhysicalBoxFragment* physical_fragment =
+          ToNGPhysicalBoxFragment(child.Get());
+      NGBoxFragment fragment(constraint_space.WritingMode(), physical_fragment);
+      NGLogicalOffset child_offset = fragment.Offset() + parent_offset;
+      CreateBidiRuns(bidi_runs, physical_fragment->Children(), constraint_space,
+                     child_offset, items, text_offsets,
+                     positions_for_bidi_runs_out, positions_out);
+      // Store box fragments in a map by LineLayoutItem.
+      positions_out->Set(LineLayoutItem(child->GetLayoutObject()),
+                         FragmentPosition{child_offset, fragment.InlineSize()});
+    }
+  }
+}
+
+// Set the geometry to InlineBoxes by using the FragmentPosition map.
+// When the map doesn't provide positions; i.e., when InlineFlowBox doesn't have
+// corresponding box fragment, compute the union of children.
+unsigned PlaceInlineBoxChildren(
+    InlineFlowBox* parent,
+    const Vector<FragmentPosition, 32>& positions_for_bidi_runs,
+    const HashMap<LineLayoutItem, FragmentPosition>& positions,
+    unsigned text_index = 0,
+    bool set_parent_position_from_children = false) {
   LayoutUnit logical_left = LayoutUnit::Max();
   LayoutUnit logical_right = LayoutUnit::Min();
   LayoutUnit logical_top = LayoutUnit::Max();
-  for (InlineBox* curr = flow_box->FirstChild(); curr;
-       curr = curr->NextOnLine()) {
-    if (curr->GetLineLayoutItem().IsLayoutInline()) {
-      InlineFlowBox* flow = ToInlineFlowBox(curr);
-      PlaceInlineFlowBoxes(flow);
+  for (InlineBox* inline_box = parent->FirstChild(); inline_box;
+       inline_box = inline_box->NextOnLine()) {
+    if (inline_box->IsInlineFlowBox()) {
+      const auto& iter = positions.find(inline_box->GetLineLayoutItem());
+      if (iter != positions.end()) {
+        const FragmentPosition& position = iter->value;
+        inline_box->SetLogicalLeft(position.offset.inline_offset);
+        inline_box->SetLogicalTop(position.offset.block_offset);
+        inline_box->SetLogicalWidth(position.inline_size);
+      }
+
+      text_index = PlaceInlineBoxChildren(ToInlineFlowBox(inline_box),
+                                          positions_for_bidi_runs, positions,
+                                          text_index, iter == positions.end());
+    } else {
+      const FragmentPosition& position = positions_for_bidi_runs[text_index++];
+      inline_box->SetLogicalLeft(position.offset.inline_offset);
+      inline_box->SetLogicalTop(position.offset.block_offset);
+      inline_box->SetLogicalWidth(position.inline_size);
+      if (inline_box->GetLineLayoutItem().IsBox()) {
+        LineLayoutBox box(inline_box->GetLineLayoutItem());
+        box.SetLocation(inline_box->Location());
+      }
     }
-    logical_left = std::min(curr->LogicalLeft(), logical_left);
-    logical_right = std::max(curr->LogicalRight(), logical_right);
-    logical_top = std::min(curr->LogicalTop(), logical_top);
+
+    if (set_parent_position_from_children) {
+      logical_left = std::min(inline_box->LogicalLeft(), logical_left);
+      logical_right = std::max(inline_box->LogicalRight(), logical_right);
+      logical_top = std::min(inline_box->LogicalTop(), logical_top);
+    }
   }
-  if (logical_left == LayoutUnit::Max())
-    return;
-  logical_left -= flow_box->MarginBorderPaddingLogicalLeft();
-  logical_right += flow_box->MarginBorderPaddingLogicalRight();
-  flow_box->SetLogicalLeft(logical_left);
-  flow_box->SetLogicalWidth(logical_right - logical_left);
-  flow_box->SetLogicalTop(logical_top);
+
+  if (set_parent_position_from_children && logical_left != LayoutUnit::Max()) {
+    logical_left -= parent->MarginBorderPaddingLogicalLeft();
+    logical_right += parent->MarginBorderPaddingLogicalRight();
+    parent->SetLogicalLeft(logical_left);
+    parent->SetLogicalWidth(logical_right - logical_left);
+    parent->SetLogicalTop(logical_top);
+  }
+
+  return text_index;
 }
 
 }  // namespace
@@ -324,8 +416,8 @@
           ? FontBaseline::kAlphabeticBaseline
           : FontBaseline::kIdeographicBaseline;
 
-  Vector<const NGPhysicalFragment*, 32> fragments_for_bidi_runs;
-  fragments_for_bidi_runs.ReserveInitialCapacity(items.size());
+  Vector<FragmentPosition, 32> positions_for_bidi_runs;
+  HashMap<LineLayoutItem, FragmentPosition> positions;
   BidiRunList<BidiRun> bidi_runs;
   LineInfo line_info;
   NGPhysicalBoxFragment* box_fragment =
@@ -333,31 +425,11 @@
   for (const auto& container_child : box_fragment->Children()) {
     NGPhysicalLineBoxFragment* physical_line_box =
         ToNGPhysicalLineBoxFragment(container_child.Get());
+
     // Create a BidiRunList for this line.
-    for (const auto& line_child : physical_line_box->Children()) {
-      const auto* text_fragment = ToNGPhysicalTextFragment(line_child.Get());
-      const NGInlineItem& item = items[text_fragment->ItemIndex()];
-      BidiRun* run;
-      if (item.Type() == NGInlineItem::kText ||
-          item.Type() == NGInlineItem::kControl) {
-        LayoutObject* layout_object = item.GetLayoutObject();
-        DCHECK(layout_object->IsText());
-        unsigned text_offset = text_offsets[text_fragment->ItemIndex()];
-        run = new BidiRun(text_fragment->StartOffset() - text_offset,
-                          text_fragment->EndOffset() - text_offset,
-                          item.BidiLevel(), LineLayoutItem(layout_object));
-        layout_object->ClearNeedsLayout();
-      } else if (item.Type() == NGInlineItem::kAtomicInline) {
-        LayoutObject* layout_object = item.GetLayoutObject();
-        DCHECK(layout_object->IsAtomicInlineLevel());
-        run =
-            new BidiRun(0, 1, item.BidiLevel(), LineLayoutItem(layout_object));
-      } else {
-        continue;
-      }
-      bidi_runs.AddRun(run);
-      fragments_for_bidi_runs.push_back(text_fragment);
-    }
+    CreateBidiRuns(&bidi_runs, physical_line_box->Children(), constraint_space,
+                   NGLogicalOffset(), items, text_offsets,
+                   &positions_for_bidi_runs, &positions);
     // TODO(kojii): bidi needs to find the logical last run.
     bidi_runs.SetLogicallyLastRun(bidi_runs.LastRun());
 
@@ -369,27 +441,7 @@
         block_flow->ConstructLine(bidi_runs, line_info);
 
     // Copy fragments data to InlineBoxes.
-    DCHECK_EQ(fragments_for_bidi_runs.size(), bidi_runs.RunCount());
-    BidiRun* run = bidi_runs.FirstRun();
-    for (auto* physical_fragment : fragments_for_bidi_runs) {
-      DCHECK(run);
-      NGTextFragment fragment(constraint_space.WritingMode(),
-                              ToNGPhysicalTextFragment(physical_fragment));
-      InlineBox* inline_box = run->box_;
-      inline_box->SetLogicalWidth(fragment.InlineSize());
-      inline_box->SetLogicalLeft(fragment.InlineOffset());
-      inline_box->SetLogicalTop(fragment.BlockOffset());
-      if (inline_box->GetLineLayoutItem().IsBox()) {
-        LineLayoutBox box(inline_box->GetLineLayoutItem());
-        box.SetLocation(inline_box->Location());
-      }
-      run = run->Next();
-    }
-    DCHECK(!run);
-
-    // InlineTextBox and InlineBox are placed, but when ConstructLine() created
-    // InlineFlowBox, they needed to be placed as well.
-    PlaceInlineFlowBoxes(root_line_box);
+    PlaceInlineBoxChildren(root_line_box, positions_for_bidi_runs, positions);
 
     // Copy to RootInlineBox.
     NGLineBoxFragment line_box(constraint_space.WritingMode(),
@@ -405,7 +457,8 @@
         line_top, baseline + max_with_leading.descent);
 
     bidi_runs.DeleteRuns();
-    fragments_for_bidi_runs.clear();
+    positions_for_bidi_runs.clear();
+    positions.clear();
   }
 }
 
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 8c1b2b5..b7da848 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
@@ -14,7 +14,15 @@
 namespace blink {
 
 NGLineBoxFragmentBuilder::NGLineBoxFragmentBuilder(NGInlineNode* node)
-    : direction_(TextDirection::kLtr), node_(node) {}
+    : writing_mode_(kHorizontalTopBottom),
+      direction_(TextDirection::kLtr),
+      node_(node) {}
+
+NGLineBoxFragmentBuilder& NGLineBoxFragmentBuilder::SetWritingMode(
+    NGWritingMode writing_mode) {
+  writing_mode_ = writing_mode;
+  return *this;
+}
 
 NGLineBoxFragmentBuilder& NGLineBoxFragmentBuilder::SetDirection(
     TextDirection direction) {
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 f4e4da8..aa09de1 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
@@ -22,6 +22,9 @@
  public:
   explicit NGLineBoxFragmentBuilder(NGInlineNode*);
 
+  NGLineBoxFragmentBuilder& SetWritingMode(NGWritingMode);
+  NGWritingMode WritingMode() const { return writing_mode_; }
+
   NGLineBoxFragmentBuilder& SetDirection(TextDirection);
 
   NGLineBoxFragmentBuilder& SetInlineSize(LayoutUnit);
@@ -36,6 +39,9 @@
   const Vector<RefPtr<NGPhysicalFragment>>& Children() const {
     return children_;
   }
+  Vector<RefPtr<NGPhysicalFragment>>& MutableChildren() { return children_; }
+  const Vector<NGLogicalOffset>& Offsets() const { return offsets_; }
+  Vector<NGLogicalOffset>& MutableOffsets() { return offsets_; }
 
   void SetMetrics(const NGLineHeightMetrics&);
   const NGLineHeightMetrics& Metrics() const { return metrics_; }
@@ -48,6 +54,7 @@
   RefPtr<NGPhysicalLineBoxFragment> ToLineBoxFragment();
 
  private:
+  NGWritingMode writing_mode_;
   TextDirection direction_;
 
   Persistent<NGInlineNode> node_;
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_fragment.cc b/third_party/WebKit/Source/core/layout/ng/ng_fragment.cc
index e9b12536..b1f8d45 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_fragment.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_fragment.cc
@@ -37,6 +37,10 @@
              : physical_fragment_->Offset().left;
 }
 
+NGLogicalOffset NGFragment::Offset() const {
+  return NGLogicalOffset(InlineOffset(), BlockOffset());
+}
+
 NGPhysicalFragment::NGFragmentType NGFragment::Type() const {
   return physical_fragment_->Type();
 }
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_fragment.h b/third_party/WebKit/Source/core/layout/ng/ng_fragment.h
index 87d0ed3e..4c43104f 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_fragment.h
+++ b/third_party/WebKit/Source/core/layout/ng/ng_fragment.h
@@ -6,6 +6,7 @@
 #define NGFragment_h
 
 #include "core/CoreExport.h"
+#include "core/layout/ng/geometry/ng_logical_offset.h"
 #include "core/layout/ng/ng_physical_fragment.h"
 #include "core/layout/ng/ng_writing_mode.h"
 #include "platform/LayoutUnit.h"
@@ -31,6 +32,7 @@
   // Returns the offset relative to the parent fragment's content-box.
   LayoutUnit InlineOffset() const;
   LayoutUnit BlockOffset() const;
+  NGLogicalOffset Offset() const;
 
   NGPhysicalFragment::NGFragmentType Type() const;
 
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 b8739da..baed4d6 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
@@ -22,8 +22,16 @@
       writing_mode_(kHorizontalTopBottom),
       direction_(TextDirection::kLtr),
       node_(node),
-      did_break_(false) {
-}
+      layout_object_(node->GetLayoutObject()),
+      did_break_(false) {}
+
+NGFragmentBuilder::NGFragmentBuilder(NGPhysicalFragment::NGFragmentType type,
+                                     LayoutObject* layout_object)
+    : type_(type),
+      writing_mode_(kHorizontalTopBottom),
+      direction_(TextDirection::kLtr),
+      layout_object_(layout_object),
+      did_break_(false) {}
 
 NGFragmentBuilder& NGFragmentBuilder::SetWritingMode(
     NGWritingMode writing_mode) {
@@ -85,8 +93,10 @@
   switch (child->Type()) {
     case NGPhysicalBoxFragment::kFragmentBox:
       // Update if we have fragmented in this flow.
-      did_break_ |= !child->BreakToken()->IsFinished();
-      child_break_tokens_.push_back(child->BreakToken());
+      if (child->BreakToken()) {
+        did_break_ |= !child->BreakToken()->IsFinished();
+        child_break_tokens_.push_back(child->BreakToken());
+      }
       break;
     case NGPhysicalBoxFragment::kFragmentLineBox:
       // NGInlineNode produces multiple line boxes in an anonymous box. Only
@@ -193,16 +203,18 @@
   }
 
   RefPtr<NGBreakToken> break_token;
-  if (last_inline_break_token_) {
-    DCHECK(!last_inline_break_token_->IsFinished());
-    child_break_tokens_.push_back(std::move(last_inline_break_token_));
-    did_break_ = true;
-  }
-  if (did_break_) {
-    break_token = NGBlockBreakToken::Create(node_.Get(), used_block_size_,
-                                            child_break_tokens_);
-  } else {
-    break_token = NGBlockBreakToken::Create(node_.Get());
+  if (node_) {
+    if (last_inline_break_token_) {
+      DCHECK(!last_inline_break_token_->IsFinished());
+      child_break_tokens_.push_back(std::move(last_inline_break_token_));
+      did_break_ = true;
+    }
+    if (did_break_) {
+      break_token = NGBlockBreakToken::Create(node_.Get(), used_block_size_,
+                                              child_break_tokens_);
+    } else {
+      break_token = NGBlockBreakToken::Create(node_.Get());
+    }
   }
 
   for (auto& positioned_float : positioned_floats_) {
@@ -214,9 +226,9 @@
   }
 
   RefPtr<NGPhysicalBoxFragment> fragment = AdoptRef(new NGPhysicalBoxFragment(
-      node_->GetLayoutObject(), physical_size,
-      overflow_.ConvertToPhysical(writing_mode_), children_, positioned_floats_,
-      bfc_offset_, end_margin_strut_, std::move(break_token)));
+      layout_object_, physical_size, overflow_.ConvertToPhysical(writing_mode_),
+      children_, positioned_floats_, bfc_offset_, end_margin_strut_,
+      std::move(break_token)));
 
   return AdoptRef(
       new NGLayoutResult(std::move(fragment), out_of_flow_descendants_,
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 d10584c..24f44a3 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
@@ -24,6 +24,10 @@
  public:
   NGFragmentBuilder(NGPhysicalFragment::NGFragmentType, NGLayoutInputNode*);
 
+  // Build a fragment for LayoutObject without NGLayoutInputNode. LayoutInline
+  // has NGInlineItem but does not have corresponding NGLayoutInputNode.
+  NGFragmentBuilder(NGPhysicalFragment::NGFragmentType, LayoutObject*);
+
   using WeakBoxList = PersistentHeapLinkedHashSet<WeakMember<NGBlockNode>>;
 
   NGFragmentBuilder& SetWritingMode(NGWritingMode);
@@ -149,6 +153,7 @@
   TextDirection direction_;
 
   Persistent<NGLayoutInputNode> node_;
+  LayoutObject* layout_object_;
 
   NGLogicalSize size_;
   NGLogicalSize overflow_;
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_layout_result.h b/third_party/WebKit/Source/core/layout/ng/ng_layout_result.h
index 0ac755a..77d7be6a 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_layout_result.h
+++ b/third_party/WebKit/Source/core/layout/ng/ng_layout_result.h
@@ -28,6 +28,9 @@
   RefPtr<NGPhysicalFragment> PhysicalFragment() const {
     return physical_fragment_;
   }
+  RefPtr<NGPhysicalFragment>& MutablePhysicalFragment() {
+    return physical_fragment_;
+  }
 
   const HeapLinkedHashSet<WeakMember<NGBlockNode>>& OutOfFlowDescendants()
       const {