1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_NG_PHYSICAL_FRAGMENT_H_
6 #define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_NG_PHYSICAL_FRAGMENT_H_
7 
8 #include "base/memory/scoped_refptr.h"
9 #include "third_party/blink/renderer/core/core_export.h"
10 #include "third_party/blink/renderer/core/editing/forward.h"
11 #include "third_party/blink/renderer/core/layout/geometry/physical_offset.h"
12 #include "third_party/blink/renderer/core/layout/geometry/physical_rect.h"
13 #include "third_party/blink/renderer/core/layout/geometry/physical_size.h"
14 #include "third_party/blink/renderer/core/layout/layout_box.h"
15 #include "third_party/blink/renderer/core/layout/ng/ng_style_variant.h"
16 #include "third_party/blink/renderer/platform/graphics/touch_action.h"
17 #include "third_party/blink/renderer/platform/wtf/ref_counted.h"
18 
19 #include <unicode/ubidi.h>
20 
21 namespace blink {
22 
23 class ComputedStyle;
24 class FragmentData;
25 class Node;
26 class NGFragmentBuilder;
27 class NGInlineItem;
28 class NGPhysicalFragment;
29 class PaintLayer;
30 struct LogicalRect;
31 
32 struct CORE_EXPORT NGPhysicalFragmentTraits {
33   static void Destruct(const NGPhysicalFragment*);
34 };
35 
36 // The NGPhysicalFragment contains the output geometry from layout. The
37 // fragment stores all of its information in the physical coordinate system for
38 // use by paint, hit-testing etc.
39 //
40 // The fragment keeps a pointer back to the LayoutObject which generated it.
41 // Once we have transitioned fully to LayoutNG it should be a const pointer
42 // such that paint/hit-testing/etc don't modify it.
43 //
44 // Layout code should only access geometry information through the
45 // NGFragment wrapper classes which transforms information into the logical
46 // coordinate system.
47 class CORE_EXPORT NGPhysicalFragment
48     : public RefCounted<const NGPhysicalFragment, NGPhysicalFragmentTraits> {
49  public:
50   enum NGFragmentType {
51     kFragmentBox = 0,
52     kFragmentText = 1,
53     kFragmentLineBox = 2,
54     // When adding new values, make sure the bit size of |type_| is large
55     // enough to store.
56   };
57   enum NGBoxType {
58     kNormalBox,
59     kInlineBox,
60     // A multi-column container creates column boxes as its children, which
61     // content is flowed into. https://www.w3.org/TR/css-multicol-1/#column-box
62     kColumnBox,
63     kAtomicInline,
64     kFloating,
65     kOutOfFlowPositioned,
66     kBlockFlowRoot,
67     kRenderedLegend,
68     // When adding new values, make sure the bit size of |sub_type_| is large
69     // enough to store.
70 
71     // Also, add after kMinimumFormattingContextRoot if the box type is a
72     // formatting context root, or before otherwise. See
73     // IsFormattingContextRoot().
74     kMinimumFormattingContextRoot = kAtomicInline
75   };
76 
77   ~NGPhysicalFragment();
78 
Type()79   NGFragmentType Type() const { return static_cast<NGFragmentType>(type_); }
IsContainer()80   bool IsContainer() const {
81     return Type() == NGFragmentType::kFragmentBox ||
82            Type() == NGFragmentType::kFragmentLineBox;
83   }
IsBox()84   bool IsBox() const { return Type() == NGFragmentType::kFragmentBox; }
IsText()85   bool IsText() const { return Type() == NGFragmentType::kFragmentText; }
IsLineBox()86   bool IsLineBox() const { return Type() == NGFragmentType::kFragmentLineBox; }
87 
88   // Returns the box type of this fragment.
BoxType()89   NGBoxType BoxType() const {
90     DCHECK(IsBox());
91     return static_cast<NGBoxType>(sub_type_);
92   }
93   // True if this is an inline box; e.g., <span>. Atomic inlines such as
94   // replaced elements or inline block are not included.
IsInlineBox()95   bool IsInlineBox() const {
96     return IsBox() && BoxType() == NGBoxType::kInlineBox;
97   }
IsColumnBox()98   bool IsColumnBox() const {
99     return IsBox() && BoxType() == NGBoxType::kColumnBox;
100   }
IsFragmentainerBox()101   bool IsFragmentainerBox() const { return IsColumnBox(); }
IsColumnSpanAll()102   bool IsColumnSpanAll() const {
103     if (const auto* box = DynamicTo<LayoutBox>(GetLayoutObject()))
104       return box->IsColumnSpanAll();
105     return false;
106   }
107   // An atomic inline is represented as a kFragmentBox, such as inline block and
108   // replaced elements.
IsAtomicInline()109   bool IsAtomicInline() const {
110     return IsBox() && BoxType() == NGBoxType::kAtomicInline;
111   }
112   // True if this fragment is in-flow in an inline formatting context.
IsInline()113   bool IsInline() const {
114     return IsText() || IsInlineBox() || IsAtomicInline();
115   }
IsFloating()116   bool IsFloating() const {
117     return IsBox() && BoxType() == NGBoxType::kFloating;
118   }
IsOutOfFlowPositioned()119   bool IsOutOfFlowPositioned() const {
120     return IsBox() && BoxType() == NGBoxType::kOutOfFlowPositioned;
121   }
IsFloatingOrOutOfFlowPositioned()122   bool IsFloatingOrOutOfFlowPositioned() const {
123     return IsFloating() || IsOutOfFlowPositioned();
124   }
125   // Return true if this is the legend child of a fieldset that gets special
126   // treatment (i.e. placed over the block-start border).
IsRenderedLegend()127   bool IsRenderedLegend() const {
128     return IsBox() && BoxType() == NGBoxType::kRenderedLegend;
129   }
IsMathMLFraction()130   bool IsMathMLFraction() const { return IsBox() && is_math_fraction_; }
131 
IsMathMLOperator()132   bool IsMathMLOperator() const { return IsBox() && is_math_operator_; }
133 
134   // Return true if this fragment corresponds directly to an entry in the CSS
135   // box tree [1]. Note that anonymous blocks also exist in the CSS box
136   // tree. Returns false otherwise, i.e. if the fragment is generated by the
137   // layout engine to contain fragments from CSS boxes (a line or a generated
138   // fragmentainer [2], in other words). The main signification of this is
139   // whether we can use the LayoutObject associated with this fragment for all
140   // purposes.
141   //
142   // [1] https://www.w3.org/TR/css-display-3/#box-tree
143   // [2] https://www.w3.org/TR/css-break-3/#fragmentation-container
IsCSSBox()144   bool IsCSSBox() const { return !IsLineBox() && !IsFragmentainerBox(); }
145 
146   bool IsBlockFlow() const;
IsAnonymousBlock()147   bool IsAnonymousBlock() const {
148     return IsCSSBox() && layout_object_->IsAnonymousBlock();
149   }
IsListMarker()150   bool IsListMarker() const {
151     return IsCSSBox() && layout_object_->IsLayoutNGOutsideListMarker();
152   }
IsRubyRun()153   bool IsRubyRun() const { return layout_object_->IsRubyRun(); }
154 
155   // Return true if this fragment is for LayoutNGRubyRun, LayoutNGRubyText, or
156   // LayoutNGRubyBase. They are handled specially in scrollable overflow
157   // computation.
IsRubyBox()158   bool IsRubyBox() const {
159     return layout_object_->IsRubyRun() || layout_object_->IsRubyText() ||
160            layout_object_->IsRubyBase();
161   }
162 
IsTableNGPart()163   bool IsTableNGPart() const { return is_table_ng_part_; }
164 
IsTable()165   bool IsTable() const { return IsBox() && layout_object_->IsTable(); }
166 
IsTableNGRow()167   bool IsTableNGRow() const {
168     return IsTableNGPart() && layout_object_->IsTableRow();
169   }
170 
IsTableNGSection()171   bool IsTableNGSection() const {
172     return IsTableNGPart() && layout_object_->IsTableSection();
173   }
174 
IsTableNGCell()175   bool IsTableNGCell() const {
176     return IsTableNGPart() && layout_object_->IsTableCell() &&
177            !layout_object_->IsTableCellLegacy();
178   }
179 
180   bool IsTextControlPlaceholder() const;
181 
182   // Return true if this fragment is a container established by a fieldset
183   // element. Such a fragment contains an optional rendered legend fragment and
184   // an optional fieldset contents wrapper fragment (which holds everything
185   // inside the fieldset except the rendered legend).
IsFieldsetContainer()186   bool IsFieldsetContainer() const { return is_fieldset_container_; }
187 
188   // Returns whether the fragment is legacy layout root.
IsLegacyLayoutRoot()189   bool IsLegacyLayoutRoot() const { return is_legacy_layout_root_; }
190 
191   // Returns whether the fragment should be atomically painted.
IsPaintedAtomically()192   bool IsPaintedAtomically() const { return is_painted_atomically_; }
193 
194   // Returns whether the fragment is a table part with collapsed borders.
HasCollapsedBorders()195   bool HasCollapsedBorders() const { return has_collapsed_borders_; }
196 
IsFormattingContextRoot()197   bool IsFormattingContextRoot() const {
198     return (IsBox() && BoxType() >= NGBoxType::kMinimumFormattingContextRoot) ||
199            IsLegacyLayoutRoot();
200   }
201 
202   // |Offset()| is reliable only when this fragment was placed by LayoutNG
203   // parent. When the parent is not LayoutNG, the parent may move the
204   // |LayoutObject| after this fragment was placed. See comments in
205   // |LayoutNGBlockFlow::UpdateBlockLayout()| and crbug.com/788590
206   bool IsPlacedByLayoutNG() const;
207 
208   // The accessors in this class shouldn't be used by layout code directly,
209   // instead should be accessed by the NGFragmentBase classes. These accessors
210   // exist for paint, hit-testing, etc.
211 
212   // Returns the border-box size.
Size()213   PhysicalSize Size() const { return size_; }
214 
215   // Returns the rect in the local coordinate of this fragment; i.e., offset is
216   // (0, 0).
LocalRect()217   PhysicalRect LocalRect() const { return {{}, size_}; }
218 
StyleVariant()219   NGStyleVariant StyleVariant() const {
220     return static_cast<NGStyleVariant>(style_variant_);
221   }
UsesFirstLineStyle()222   bool UsesFirstLineStyle() const {
223     return StyleVariant() == NGStyleVariant::kFirstLine;
224   }
225 
226   // Returns the style for this fragment.
227   //
228   // For a line box, this returns the style of the containing block. This mostly
229   // represents the style for the line box, except 1) |style.Direction()| maybe
230   // incorrect, use |BaseDirection()| instead, and 2) margin/border/padding,
231   // background etc. do not apply to the line box.
Style()232   const ComputedStyle& Style() const {
233     return layout_object_->EffectiveStyle(StyleVariant());
234   }
235 
GetDocument()236   const Document& GetDocument() const {
237     DCHECK(layout_object_);
238     return layout_object_->GetDocument();
239   }
GetNode()240   Node* GetNode() const {
241     return IsCSSBox() ? layout_object_->GetNode() : nullptr;
242   }
GeneratingNode()243   Node* GeneratingNode() const {
244     return IsCSSBox() ? layout_object_->GeneratingNode() : nullptr;
245   }
246   // The node to return when hit-testing on this fragment. This can be different
247   // from GetNode() when this fragment is content of a pseudo node.
NodeForHitTest()248   Node* NodeForHitTest() const { return layout_object_->NodeForHitTest(); }
249 
NonPseudoNode()250   Node* NonPseudoNode() const {
251     return IsCSSBox() ? layout_object_->NonPseudoNode() : nullptr;
252   }
253 
IsInSelfHitTestingPhase(HitTestAction action)254   bool IsInSelfHitTestingPhase(HitTestAction action) const {
255     if (const auto* box = DynamicTo<LayoutBox>(GetLayoutObject()))
256       return box->IsInSelfHitTestingPhase(action);
257     if (IsInlineBox())
258       return action == kHitTestForeground;
259     // Assuming this is some sort of container, e.g. a fragmentainer (they don't
260     // have a LayoutObject associated).
261     return action == kHitTestBlockBackground ||
262            action == kHitTestChildBlockBackground;
263   }
264 
265   // Whether there is a PaintLayer associated with the fragment.
HasLayer()266   bool HasLayer() const { return IsCSSBox() && layout_object_->HasLayer(); }
267 
268   // The PaintLayer associated with the fragment.
Layer()269   PaintLayer* Layer() const {
270     if (!HasLayer())
271       return nullptr;
272     return To<LayoutBoxModelObject>(layout_object_)->Layer();
273   }
274 
275   // Whether this object has a self-painting |Layer()|.
HasSelfPaintingLayer()276   bool HasSelfPaintingLayer() const {
277     return HasLayer() &&
278            To<LayoutBoxModelObject>(layout_object_)->HasSelfPaintingLayer();
279   }
280 
281   // True if overflow != 'visible', except for certain boxes that do not allow
282   // overflow clip; i.e., AllowOverflowClip() returns false.
HasNonVisibleOverflow()283   bool HasNonVisibleOverflow() const {
284     return IsCSSBox() && layout_object_->HasNonVisibleOverflow();
285   }
286 
287   // True if this is considered a scroll-container. See
288   // ComputedStyle::IsScrollContainer() for details.
IsScrollContainer()289   bool IsScrollContainer() const {
290     return IsCSSBox() && layout_object_->IsScrollContainer();
291   }
292 
293   // Return true if the given object is the effective root scroller in its
294   // Document. See |effective root scroller| in page/scrolling/README.md.
295   // Note: a root scroller always establishes a PaintLayer.
296   // This bit is updated in
297   // RootScrollerController::RecomputeEffectiveRootScroller in the LayoutClean
298   // document lifecycle phase.
IsEffectiveRootScroller()299   bool IsEffectiveRootScroller() const {
300     return IsCSSBox() && layout_object_->IsEffectiveRootScroller();
301   }
302 
ShouldApplyLayoutContainment()303   bool ShouldApplyLayoutContainment() const {
304     return IsCSSBox() && layout_object_->ShouldApplyLayoutContainment();
305   }
306 
ShouldClipOverflowAlongEitherAxis()307   bool ShouldClipOverflowAlongEitherAxis() const {
308     return IsCSSBox() && layout_object_->ShouldClipOverflowAlongEitherAxis();
309   }
310 
ShouldClipOverflowAlongBothAxis()311   bool ShouldClipOverflowAlongBothAxis() const {
312     return IsCSSBox() && layout_object_->ShouldClipOverflowAlongBothAxis();
313   }
314 
IsFragmentationContextRoot()315   bool IsFragmentationContextRoot() const {
316     // We have no bit that tells us whether this is a fragmentation context
317     // root, so some additional checking is necessary here, to make sure that
318     // we're actually establishing one. We check that we're not a custom layout
319     // box, as specifying columns on such a box has no effect. Note that
320     // specifying columns together with a display value of e.g. 'flex', 'grid'
321     // or 'table' also has no effect, but we don't need to check for that here,
322     // since such display types don't create a block flow (block container).
323     return IsCSSBox() && Style().SpecifiesColumns() && IsBlockFlow() &&
324            !layout_object_->IsLayoutNGCustom();
325   }
326 
327   // Return whether we can traverse this fragment and its children directly, for
328   // painting, hit-testing and other layout read operations. If false is
329   // returned, we need to traverse the layout object tree instead.
CanTraverse()330   bool CanTraverse() const {
331     return layout_object_->CanTraversePhysicalFragments();
332   }
333 
334   // This fragment is hidden for paint purpose, but exists for querying layout
335   // information. Used for `text-overflow: ellipsis`.
IsHiddenForPaint()336   bool IsHiddenForPaint() const { return is_hidden_for_paint_; }
337 
338   // Return true if this fragment is monolithic, as far as block fragmentation
339   // is concerned.
IsMonolithic()340   bool IsMonolithic() const {
341     const LayoutObject* layout_object = GetLayoutObject();
342     if (!layout_object || !IsBox() || !layout_object->IsBox())
343       return false;
344     return To<LayoutBox>(layout_object)->GetNGPaginationBreakability() ==
345            LayoutBox::kForbidBreaks;
346   }
347 
348   // GetLayoutObject should only be used when necessary for compatibility
349   // with LegacyLayout.
350   //
351   // For a line box, |layout_object_| has its containing block but this function
352   // returns |nullptr| for the historical reasons. TODO(kojii): We may change
353   // this in future. Use |IsLineBox()| instead of testing this is |nullptr|.
GetLayoutObject()354   const LayoutObject* GetLayoutObject() const {
355     return IsCSSBox() ? layout_object_ : nullptr;
356   }
357   // TODO(kojii): We should not have mutable version at all, the use of this
358   // function should be eliminiated over time.
GetMutableLayoutObject()359   LayoutObject* GetMutableLayoutObject() const {
360     return IsCSSBox() ? layout_object_ : nullptr;
361   }
362   // Similar to |GetLayoutObject|, but returns the |LayoutObject| of its
363   // container for |!IsCSSBox()| fragments instead of |nullptr|.
GetSelfOrContainerLayoutObject()364   const LayoutObject* GetSelfOrContainerLayoutObject() const {
365     return layout_object_;
366   }
367 
368   const FragmentData* GetFragmentData() const;
369 
370   // |NGPhysicalFragment| may live longer than the corresponding |LayoutObject|.
371   // Though |NGPhysicalFragment| is immutable, |layout_object_| is cleared to
372   // |nullptr| when it was destroyed to avoid reading destroyed objects.
IsLayoutObjectDestroyedOrMoved()373   bool IsLayoutObjectDestroyedOrMoved() const { return !layout_object_; }
LayoutObjectWillBeDestroyed()374   void LayoutObjectWillBeDestroyed() const {
375     const_cast<NGPhysicalFragment*>(this)->layout_object_ = nullptr;
376   }
377 
378   // Returns the latest generation of the post-layout fragment. Returns
379   // |nullptr| if |this| is the one.
380   //
381   // When subtree relayout occurs at the relayout boundary, its containing block
382   // may keep the reference to old generations of this fragment. Callers can
383   // check if there were newer generations.
384   const NGPhysicalFragment* PostLayout() const;
385 
386   // Specifies the type of scrollable overflow computation.
387   enum TextHeightType {
388     // Apply text fragment size as is.
389     kNormalHeight,
390     // Adjust text fragment size for 'em' height, and skip to unite
391     // container's bounding box. This type is useful for ruby annotation.
392     kEmHeight
393   };
394   // Scrollable overflow. including contents, in the local coordinate.
395   PhysicalRect ScrollableOverflow(const NGPhysicalBoxFragment& container,
396                                   TextHeightType height_type) const;
397 
398   // ScrollableOverflow(), with transforms applied wrt container if needed.
399   // This does not include any offsets from the parent (including relpos).
400   PhysicalRect ScrollableOverflowForPropagation(
401       const NGPhysicalBoxFragment& container,
402       TextHeightType height_type) const;
403   void AdjustScrollableOverflowForPropagation(
404       const NGPhysicalBoxFragment& container,
405       TextHeightType height_type,
406       PhysicalRect* overflow) const;
407 
408   // The allowed touch action is the union of the effective touch action
409   // (from style) and blocking touch event handlers.
410   TouchAction EffectiveAllowedTouchAction() const;
411 
412   // Returns if this fragment is inside a non-passive wheel event handler.
413   bool InsideBlockingWheelEventHandler() const;
414 
415   // Returns the bidi level of a text or atomic inline fragment.
416   UBiDiLevel BidiLevel() const;
417 
418   // Returns the resolved direction of a text or atomic inline fragment. Not to
419   // be confused with the CSS 'direction' property.
420   TextDirection ResolvedDirection() const;
421 
422   // Helper functions to convert between |PhysicalRect| and |LogicalRect| of a
423   // child.
424   LogicalRect ConvertChildToLogical(const PhysicalRect& physical_rect) const;
425   PhysicalRect ConvertChildToPhysical(const LogicalRect& logical_rect) const;
426 
427   // Utility functions for caret painting. Note that carets are painted as part
428   // of the containing block's foreground.
429   bool ShouldPaintCursorCaret() const;
430   bool ShouldPaintDragCaret() const;
ShouldPaintCarets()431   bool ShouldPaintCarets() const {
432     return ShouldPaintCursorCaret() || ShouldPaintDragCaret();
433   }
434 
435   String ToString() const;
436 
437   void CheckType() const;
438   void CheckCanUpdateInkOverflow() const;
439 
440   enum DumpFlag {
441     DumpHeaderText = 0x1,
442     DumpSubtree = 0x2,
443     DumpIndentation = 0x4,
444     DumpType = 0x8,
445     DumpOffset = 0x10,
446     DumpSize = 0x20,
447     DumpTextOffsets = 0x40,
448     DumpSelfPainting = 0x80,
449     DumpNodeName = 0x100,
450     DumpItems = 0x200,
451     DumpAll = -1
452   };
453   typedef int DumpFlags;
454 
455   String DumpFragmentTree(DumpFlags,
456                           base::Optional<PhysicalOffset> = base::nullopt,
457                           unsigned indent = 2) const;
458 
459 #if DCHECK_IS_ON()
460   void ShowFragmentTree() const;
461 #endif
462 
463  protected:
464   NGPhysicalFragment(NGFragmentBuilder*,
465                      NGFragmentType type,
466                      unsigned sub_type);
467 
468   NGPhysicalFragment(LayoutObject* layout_object,
469                      NGStyleVariant,
470                      PhysicalSize size,
471                      NGFragmentType type,
472                      unsigned sub_type);
473 
474   NGPhysicalFragment(const NGPhysicalFragment& other);
475 
476   const ComputedStyle& SlowEffectiveStyle() const;
477 
478   const Vector<NGInlineItem>& InlineItemsOfContainingBlock() const;
479 
480   // The following bitfields are only to be used by NGPhysicalContainerFragment
481   // (it's defined here to save memory, since that class has no bitfields).
482   unsigned has_floating_descendants_for_paint_ : 1;
483   unsigned has_adjoining_object_descendants_ : 1;
484   unsigned depends_on_percentage_block_size_ : 1;
485 
486   // The following bitfields are only to be used by NGPhysicalLineBoxFragment
487   // (it's defined here to save memory, since that class has no bitfields).
488   unsigned has_propagated_descendants_ : 1;
489   unsigned has_hanging_ : 1;
490 
491   // The following bitfields are only to be used by NGPhysicalBoxFragment
492   // (it's defined here to save memory, since that class has no bitfields).
493   unsigned is_inline_formatting_context_ : 1;
494   unsigned has_fragment_items_ : 1;
495   unsigned include_border_top_ : 1;
496   unsigned include_border_right_ : 1;
497   unsigned include_border_bottom_ : 1;
498   unsigned include_border_left_ : 1;
499   unsigned has_layout_overflow_ : 1;
500   unsigned has_borders_ : 1;
501   unsigned has_padding_ : 1;
502   unsigned has_inflow_bounds_ : 1;
503   unsigned has_rare_data_ : 1;
504   unsigned is_first_for_node_ : 1;
505 
506   LayoutObject* layout_object_;
507   const PhysicalSize size_;
508 
509   const unsigned type_ : 2;           // NGFragmentType
510   const unsigned sub_type_ : 3;       // NGBoxType, NGTextType, or NGLineBoxType
511   const unsigned style_variant_ : 2;  // NGStyleVariant
512   const unsigned is_hidden_for_paint_ : 1;
513   unsigned is_math_fraction_ : 1;
514   unsigned is_math_operator_ : 1;
515   // base (line box) or resolve (text) direction
516   unsigned base_or_resolved_direction_ : 1;  // TextDirection
517   unsigned may_have_descendant_above_block_start_ : 1;
518 
519   // The following are only used by NGPhysicalBoxFragment but are initialized
520   // for all types to allow methods using them to be inlined.
521   unsigned is_fieldset_container_ : 1;
522   unsigned is_table_ng_part_ : 1;
523   unsigned is_legacy_layout_root_ : 1;
524   unsigned is_painted_atomically_ : 1;
525   unsigned has_collapsed_borders_ : 1;
526   unsigned has_baseline_ : 1;
527   unsigned has_last_baseline_ : 1;
528 
529   // The following bitfields are only to be used by NGPhysicalTextFragment
530   // (it's defined here to save memory, since that class has no bitfields).
531   mutable unsigned ink_overflow_computed_ : 1;
532 
533   // Note: We've used 32-bit bit field. If you need more bits, please think to
534   // share bit fields, or put them before layout_object_ to fill the gap after
535   // RefCounted on 64-bit systems.
536 
537  private:
538   friend struct NGPhysicalFragmentTraits;
539   void Destroy() const;
540 };
541 
542 // Used for return value of traversing fragment tree.
543 struct CORE_EXPORT NGPhysicalFragmentWithOffset {
544   DISALLOW_NEW();
545 
546   scoped_refptr<const NGPhysicalFragment> fragment;
547   PhysicalOffset offset_to_container_box;
548 
549   PhysicalRect RectInContainerBox() const;
550 };
551 
552 CORE_EXPORT std::ostream& operator<<(std::ostream&, const NGPhysicalFragment*);
553 CORE_EXPORT std::ostream& operator<<(std::ostream&, const NGPhysicalFragment&);
554 
555 #if !DCHECK_IS_ON()
CheckType()556 inline void NGPhysicalFragment::CheckType() const {}
CheckCanUpdateInkOverflow()557 inline void NGPhysicalFragment::CheckCanUpdateInkOverflow() const {}
558 #endif
559 
560 }  // namespace blink
561 
562 #endif  // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_NG_PHYSICAL_FRAGMENT_H_
563