summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.h
blob: 626ad129d8742907e5194f05fe141a1947cf32c0 (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
// 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/layout_unit.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"

namespace blink {

class NGInlineItem;
struct NGInlineItemResult;
class ShapeResult;

// 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 {
  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;
  NGBoxStrut padding;
  // |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.
  // 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 AccumulateUsedFonts(const ShapeResult*, FontBaseline);

  // Create a box fragment for this box.
  void SetNeedsBoxFragment();
  void SetLineRightForBoxFragment(const NGInlineItem&,
                                  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
  // inline box.
  bool CanAddTextOfStyle(const ComputedStyle&) const;
};

// 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 {
 public:
  // The box state for the line box.
  NGInlineBoxState& LineBoxState() { return stack_.front(); }

  // 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);

  // 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*);

  // 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*);

 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);

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

    bool has_line_left_edge = false;
    bool has_line_right_edge = false;
    NGBoxStrut 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 box_data_index = 0;

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

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

}  // namespace blink

#endif  // NGInlineBoxState_h