summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h
blob: c14ef2b3644af0fbef50071e88291dd673823130 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_INLINE_NODE_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_INLINE_NODE_H_

#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/layout/layout_block_flow.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_data.h"
#include "third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h"
#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
#include "third_party/blink/renderer/platform/wtf/casting.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"

namespace blink {

class NGBlockBreakToken;
class NGConstraintSpace;
class NGInlineChildLayoutContext;
class NGInlineNodeLegacy;
class NGLayoutResult;
class NGOffsetMapping;
struct NGInlineItemsData;

// Represents an anonymous block box to be laid out, that contains consecutive
// inline nodes and their descendants.
class CORE_EXPORT NGInlineNode : public NGLayoutInputNode {
 public:
  NGInlineNode(LayoutBlockFlow*);

  LayoutBlockFlow* GetLayoutBlockFlow() const {
    return To<LayoutBlockFlow>(box_);
  }
  NGLayoutInputNode NextSibling() { return nullptr; }

  // True in quirks mode or limited-quirks mode, which require line-height
  // quirks.
  // https://quirks.spec.whatwg.org/#the-line-height-calculation-quirk
  bool InLineHeightQuirksMode() const {
    return GetDocument().InLineHeightQuirksMode();
  }

  scoped_refptr<const NGLayoutResult> Layout(
      const NGConstraintSpace&,
      const NGBreakToken*,
      NGInlineChildLayoutContext* context);

  // Computes the value of min-content and max-content for this anonymous block
  // box. min-content is the inline size when lines wrap at every break
  // opportunity, and max-content is when lines do not wrap at all.
  MinMaxSizesResult ComputeMinMaxSizes(WritingMode container_writing_mode,
                                       const MinMaxSizesInput&,
                                       const NGConstraintSpace* = nullptr);

  // Instruct to re-compute |PrepareLayout| on the next layout.
  void InvalidatePrepareLayoutForTest() {
    LayoutBlockFlow* block_flow = GetLayoutBlockFlow();
    block_flow->ResetNGInlineNodeData();
    DCHECK(!IsPrepareLayoutFinished());
    // There shouldn't be paint fragment if NGInlineNodeData does not exist.
    block_flow->SetPaintFragment(nullptr, nullptr);
  }

  const NGInlineItemsData& ItemsData(bool is_first_line) const {
    return Data().ItemsData(is_first_line);
  }

  // There's a special intrinsic size measure quirk for images that are direct
  // children of table cells that have auto inline-size: When measuring
  // intrinsic min/max inline sizes, we pretend that it's not possible to break
  // between images, or between text and images. Note that this only applies
  // when measuring. During actual layout, on the other hand, standard breaking
  // rules are to be followed.
  // See https://quirks.spec.whatwg.org/#the-table-cell-width-calculation-quirk
  bool IsStickyImagesQuirkForContentSize() const;

  // Returns the text content to use for content sizing. This is normally the
  // same as |items_data.text_content|, except when sticky images quirk is
  // needed.
  static String TextContentForStickyImagesQuirk(const NGInlineItemsData&);

  // Clear associated fragments for LayoutObjects.
  // They are associated when NGPaintFragment is constructed, but when clearing,
  // NGInlineItem provides easier and faster logic.
  static void ClearAssociatedFragments(const NGPhysicalFragment& fragment,
                                       const NGBlockBreakToken* break_token);

  // Returns true if we don't need to collect inline items after replacing
  // |layout_text| after deleting replacing subtext from |offset| to |length|
  // |new_text| is new text of |layout_text|.
  // This is optimized version of |PrepareLayout()|.
  static bool SetTextWithOffset(LayoutText* layout_text,
                                scoped_refptr<StringImpl> new_text,
                                unsigned offset,
                                unsigned length);

  // Returns the DOM to text content offset mapping of this block. If it is not
  // computed before, compute and store it in NGInlineNodeData.
  // This funciton must be called with clean layout.
  const NGOffsetMapping* ComputeOffsetMappingIfNeeded();

  // Get |NGOffsetMapping| for the |layout_block_flow|. |layout_block_flow|
  // should be laid out. This function works for both new and legacy layout.
  static const NGOffsetMapping* GetOffsetMapping(
      LayoutBlockFlow* layout_block_flow);

  bool IsBidiEnabled() const { return Data().is_bidi_enabled_; }
  TextDirection BaseDirection() const { return Data().BaseDirection(); }

  bool IsEmptyInline() { return EnsureData().is_empty_inline_; }

  bool IsBlockLevel() { return EnsureData().is_block_level_; }

  // @return if this node can contain the "first formatted line".
  // https://www.w3.org/TR/CSS22/selector.html#first-formatted-line
  bool CanContainFirstFormattedLine() const {
    DCHECK(GetLayoutBlockFlow());
    return GetLayoutBlockFlow()->CanContainFirstFormattedLine();
  }

  bool UseFirstLineStyle() const;
  void CheckConsistency() const;

  String ToString() const;

  struct FloatingObject {
    DISALLOW_NEW();

    void Trace(Visitor* visitor) {}

    const ComputedStyle& float_style;
    const ComputedStyle& style;
    LayoutUnit float_inline_max_size_with_margin;
  };

 protected:
  bool IsPrepareLayoutFinished() const;

  // Prepare inline and text content for layout. Must be called before
  // calling the Layout method.
  void PrepareLayoutIfNeeded();
  void PrepareLayout(std::unique_ptr<NGInlineNodeData> previous_data);

  void CollectInlines(NGInlineNodeData*,
                      NGInlineNodeData* previous_data = nullptr);
  void SegmentText(NGInlineNodeData*);
  void SegmentScriptRuns(NGInlineNodeData*);
  void SegmentFontOrientation(NGInlineNodeData*);
  void SegmentBidiRuns(NGInlineNodeData*);
  void ShapeText(NGInlineItemsData*,
                 const String* previous_text = nullptr,
                 const Vector<NGInlineItem>* previous_items = nullptr);
  void ShapeTextForFirstLineIfNeeded(NGInlineNodeData*);
  void AssociateItemsWithInlines(NGInlineNodeData*);

  NGInlineNodeData* MutableData() {
    return To<LayoutBlockFlow>(box_)->GetNGInlineNodeData();
  }
  const NGInlineNodeData& Data() const {
    DCHECK(IsPrepareLayoutFinished() &&
           !GetLayoutBlockFlow()->NeedsCollectInlines());
    return *To<LayoutBlockFlow>(box_)->GetNGInlineNodeData();
  }
  // Same as |Data()| but can access even when |NeedsCollectInlines()| is set.
  const NGInlineNodeData& MaybeDirtyData() const {
    DCHECK(IsPrepareLayoutFinished());
    return *To<LayoutBlockFlow>(box_)->GetNGInlineNodeData();
  }
  const NGInlineNodeData& EnsureData();

  static void ComputeOffsetMapping(LayoutBlockFlow* layout_block_flow,
                                   NGInlineNodeData* data);

  friend class NGLineBreakerTest;
  friend class NGInlineNodeLegacy;
};

inline bool NGInlineNode::IsStickyImagesQuirkForContentSize() const {
  if (UNLIKELY(GetDocument().InQuirksMode())) {
    const ComputedStyle& style = Style();
    if (UNLIKELY(style.Display() == EDisplay::kTableCell &&
                 style.LogicalWidth().IsIntrinsicOrAuto()))
      return true;
  }
  return false;
}

template <>
struct DowncastTraits<NGInlineNode> {
  static bool AllowFrom(const NGLayoutInputNode& node) {
    return node.IsInline();
  }
};

}  // namespace blink

WTF_ALLOW_MOVE_INIT_AND_COMPARE_WITH_MEM_FUNCTIONS(
    blink::NGInlineNode::FloatingObject)

#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_INLINE_NODE_H_