summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.h
blob: 80d9eb33bf0eb81a64852e2678affa388cd96bb5 (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
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
// Copyright 2017 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 NGInlineBoxState_h
#define NGInlineBoxState_h

#include "third_party/blink/renderer/core/layout/ng/geometry/ng_logical_size.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_line_height_metrics.h"
#include "third_party/blink/renderer/core/style/computed_style_constants.h"
#include "third_party/blink/renderer/platform/fonts/font_baseline.h"
#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"

namespace blink {

class LayoutObject;
class NGInlineItem;
struct NGInlineItemResult;
class ShapeResultView;

// Fragments that require the layout position/size of ancestor are packed in
// this struct.
struct NGPendingPositions {
  unsigned fragment_start;
  unsigned fragment_end;
  NGLineHeightMetrics metrics;
  EVerticalAlign vertical_align;
};

// Represents the current box while NGInlineLayoutAlgorithm performs layout.
// Used 1) to cache common values for a box, and 2) to layout children that
// require ancestor position or size.
// This is a transient object only while building line boxes in a block.
struct NGInlineBoxState {
  DISALLOW_NEW();

 public:
  unsigned fragment_start = 0;
  const NGInlineItem* item = nullptr;
  const ComputedStyle* style = nullptr;

  // The united metrics for the current box. This includes all objects in this
  // box, including descendants, and adjusted by placement properties such as
  // 'vertical-align'.
  NGLineHeightMetrics metrics;

  // The metrics of the font for this box. This includes leadings as specified
  // by the 'line-height' property.
  NGLineHeightMetrics text_metrics;

  // The distance between the text-top and the baseline for this box. The
  // text-top does not include leadings.
  LayoutUnit text_top;

  // The height of the text fragments.
  LayoutUnit text_height;

  // These values are to create a box fragment. Set only when needs_box_fragment
  // is set.
  bool has_start_edge = false;
  bool has_end_edge = false;
  LayoutUnit margin_inline_start;
  LayoutUnit margin_inline_end;
  NGLineBoxStrut borders;
  NGLineBoxStrut padding;

  Vector<NGPendingPositions> pending_descendants;
  bool include_used_fonts = false;
  bool needs_box_fragment = 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.
  // The computed metrics is included into the line height of the current box.
  void ComputeTextMetrics(const ComputedStyle& style,
                          FontBaseline baseline_type);
  void EnsureTextMetrics(const ComputedStyle&, FontBaseline);
  void ResetTextMetrics();

  void AccumulateUsedFonts(const ShapeResultView*, FontBaseline);

  // 'text-top' offset for 'vertical-align'.
  LayoutUnit TextTop(FontBaseline baseline_type) const;

  // Create a box fragment for this box.
  void SetNeedsBoxFragment();

  // Returns if the text style can be added without open-tag.
  // Text with different font or vertical-align needs to be wrapped with an
  // inline box.
  bool CanAddTextOfStyle(const ComputedStyle&) const;

#if DCHECK_IS_ON()
  void CheckSame(const NGInlineBoxState&) const;
#endif
};

// Represents the inline tree structure. This class provides:
// 1) Allow access to fragments belonging to the current box.
// 2) Performs layout when the positin/size of a box was computed.
// 3) Cache common values for a box.
class CORE_EXPORT NGInlineLayoutStateStack {
  STACK_ALLOCATED();

 public:
  // The box state for the line box.
  NGInlineBoxState& LineBoxState() { return stack_.front(); }

  void SetIsEmptyLine(bool is_empty_line) { is_empty_line_ = is_empty_line; }

  // Initialize the box state stack for a new line.
  // @return The initial box state for the line.
  NGInlineBoxState* OnBeginPlaceItems(const ComputedStyle*, FontBaseline, bool);

  // Push a box state stack.
  NGInlineBoxState* OnOpenTag(const NGInlineItem&,
                              const NGInlineItemResult&,
                              const NGLineBoxFragmentBuilder::ChildList&);
  NGInlineBoxState* OnOpenTag(const ComputedStyle&,
                              const NGLineBoxFragmentBuilder::ChildList&);

  // Pop a box state stack.
  NGInlineBoxState* OnCloseTag(NGLineBoxFragmentBuilder::ChildList*,
                               NGInlineBoxState*,
                               FontBaseline,
                               bool has_end_edge = true);

  // Compute all the pending positioning at the end of a line.
  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*);

  // Update start/end of the first BoxData found at |index|.
  //
  // If inline fragmentation is found, a new BoxData is added.
  //
  // Returns the index to process next. It should be given to the next call to
  // this function.
  unsigned UpdateBoxDataFragmentRange(NGLineBoxFragmentBuilder::ChildList*,
                                      unsigned index);

  // Update edges of inline fragmented boxes.
  void UpdateFragmentedBoxDataEdges();

  // Compute inline positions of fragments and boxes.
  LayoutUnit ComputeInlinePositions(NGLineBoxFragmentBuilder::ChildList*);

  // Create box fragments. This function turns a flat list of children into
  // a box tree.
  void CreateBoxFragments(NGLineBoxFragmentBuilder::ChildList*);

#if DCHECK_IS_ON()
  void CheckSame(const NGInlineLayoutStateStack&) const;
#endif

 private:
  // End of a box state, either explicitly by close tag, or implicitly at the
  // end of a line.
  void EndBoxState(NGInlineBoxState*,
                   NGLineBoxFragmentBuilder::ChildList*,
                   FontBaseline);

  void AddBoxFragmentPlaceholder(NGInlineBoxState*,
                                 NGLineBoxFragmentBuilder::ChildList*,
                                 FontBaseline);

  enum PositionPending { kPositionNotPending, kPositionPending };

  // Compute vertical position for the 'vertical-align' property.
  // The timing to apply varies by values; some values apply at the layout of
  // the box was computed. Other values apply when the layout of the parent or
  // the line box was computed.
  // https://www.w3.org/TR/CSS22/visudet.html#propdef-vertical-align
  // https://www.w3.org/TR/css-inline-3/#propdef-vertical-align
  PositionPending ApplyBaselineShift(NGInlineBoxState*,
                                     NGLineBoxFragmentBuilder::ChildList*,
                                     FontBaseline);

  // Compute the metrics for when 'vertical-align' is 'top' and 'bottom' from
  // |pending_descendants|.
  NGLineHeightMetrics MetricsForTopAndBottomAlign(
      const NGInlineBoxState&,
      const NGLineBoxFragmentBuilder::ChildList&) const;

  // Data for a box fragment. See AddBoxFragmentPlaceholder().
  // This is a transient object only while building a line box.
  struct BoxData {
    BoxData(unsigned start,
            unsigned end,
            const NGInlineItem* item,
            NGLogicalSize size)
        : fragment_start(start), fragment_end(end), item(item), size(size) {}

    BoxData(const BoxData& other, unsigned start, unsigned end)
        : fragment_start(start),
          fragment_end(end),
          item(other.item),
          size(other.size),
          offset(other.offset) {}

    // The range of child fragments this box contains.
    unsigned fragment_start;
    unsigned fragment_end;

    const NGInlineItem* item;
    NGLogicalSize size;

    bool has_line_left_edge = false;
    bool has_line_right_edge = false;
    NGLineBoxStrut padding;
    // |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 parent_box_data_index = 0;
    unsigned fragmented_box_data_index = 0;

    void UpdateFragmentEdges(Vector<BoxData, 4>& list);

    scoped_refptr<NGLayoutResult> CreateBoxFragment(
        NGLineBoxFragmentBuilder::ChildList*);
  };

  Vector<NGInlineBoxState, 4> stack_;
  Vector<BoxData, 4> box_data_list_;

  bool is_empty_line_ = false;
};

}  // namespace blink

#endif  // NGInlineBoxState_h