summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/core/layout/grid_baseline_alignment.h
blob: 64a97f6c621a605ee56238940fbe5155747b70df (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
// Copyright (c) 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_GRID_BASELINE_ALIGNMENT_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_GRID_BASELINE_ALIGNMENT_H_

#include "third_party/blink/renderer/core/layout/grid_layout_utils.h"
#include "third_party/blink/renderer/core/layout/layout_box.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"

namespace blink {

// These classes are used to implement the Baseline Alignment logic, as
// described in the CSS Box Alignment specification.
// https://drafts.csswg.org/css-align/#baseline-terms

// A baseline-sharing group is composed of boxes that participate in
// baseline alignment together. This is possible only if they:
//
//   * Share an alignment context along an axis perpendicular to their
//   baseline alignment axis.
//   * Have compatible baseline alignment preferences (i.e., the baselines
//   that want to align are on the same side of the alignment context).
//
// Once the BaselineGroup is instantiated, defined by a
// 'block-direction' (WritingMode) and a 'baseline-preference'
// (first/last baseline), it's ready to collect the items that will
// participate in the Baseline Alignment logic.
//
// The 'Update' method is used to store an item (if not already
// present) and update the max_ascent and max_descent associated to
// this baseline-sharing group.
class BaselineGroup {
  DISALLOW_NEW();

 public:
  void Update(const LayoutBox&, LayoutUnit ascent, LayoutUnit descent);
  LayoutUnit MaxAscent() const { return max_ascent_; }
  LayoutUnit MaxDescent() const { return max_descent_; }
  int size() const { return items_.size(); }

 private:
  friend class BaselineContext;
  BaselineGroup(WritingMode block_flow, ItemPosition child_preference);

  // Determines whether a baseline-sharing group is compatible with an
  // item, based on its 'block-flow' and 'baseline-preference'
  bool IsCompatible(WritingMode, ItemPosition) const;

  // Determines whether the baseline-sharing group's associated
  // block-flow is opposite (LR vs RL) to particular item's
  // writing-mode.
  bool IsOppositeBlockFlow(WritingMode block_flow) const;

  // Determines whether the baseline-sharing group's associated
  // block-flow is orthogonal (vertical vs horizontal) to particular
  // item's writing-mode.
  bool IsOrthogonalBlockFlow(WritingMode block_flow) const;

  WritingMode block_flow_;
  ItemPosition preference_;
  LayoutUnit max_ascent_;
  LayoutUnit max_descent_;
  HashSet<const LayoutBox*> items_;
};

// Boxes share an alignment context along a particular axis when they
// are:
//
//  * table cells in the same row, along the table's row (inline) axis
//  * table cells in the same column, along the table's column (block)
//  axis
//  * grid items in the same row, along the grid's row (inline) axis
//  * grid items in the same column, along the grid's colum (block) axis
//  * flex items in the same flex line, along the flex container's main
//  axis
//
// A Baseline alignment-context may handle several baseline-sharing
// groups. In order to create an instance, we need to pass the
// required data to define the first baseline-sharing group; a
// Baseline Context must have at least one baseline-sharing group.
//
// By adding new items to a Baseline Context, the baseline-sharing
// groups it handles are automatically updated, if there is one that
// is compatible with such item. Otherwise, a new baseline-sharing
// group is created, compatible with the new item.
class BaselineContext {
  USING_FAST_MALLOC(BaselineContext);

 public:
  BaselineContext(const LayoutBox& child,
                  ItemPosition preference,
                  LayoutUnit ascent,
                  LayoutUnit descent);
  Vector<BaselineGroup>& SharedGroups() { return shared_groups_; }
  const BaselineGroup& GetSharedGroup(const LayoutBox& child,
                                      ItemPosition preference) const;

  // Updates the baseline-sharing group compatible with the item.
  // We pass the item's baseline-preference to avoid dependencies with
  // the LayoutGrid class, which is the one managing the alignment
  // behavior of the Grid Items.
  void UpdateSharedGroup(const LayoutBox& child,
                         ItemPosition preference,
                         LayoutUnit ascent,
                         LayoutUnit descent);

 private:
  // Returns the baseline-sharing group compatible with an item.
  // We pass the item's baseline-preference to avoid dependencies with
  // the LayoutGrid class, which is the one managing the alignment
  // behavior of the Grid Items.
  // TODO Properly implement baseline-group compatibility
  // See https://github.com/w3c/csswg-drafts/issues/721
  BaselineGroup& FindCompatibleSharedGroup(const LayoutBox& child,
                                           ItemPosition preference);

  Vector<BaselineGroup> shared_groups_;
};

static inline bool IsBaselinePosition(ItemPosition position) {
  return position == ItemPosition::kBaseline ||
         position == ItemPosition::kLastBaseline;
}

// This is the class that implements the Baseline Alignment logic,
// using internally the BaselineContext and BaselineGroupd classes
// (described above).
//
// The first phase is to collect the items that will participate in
// baseline alignment together. During this phase the required
// baseline- sharing groups will be created for each Baseline
// alignment-context shared by the items participating in the baseline
// alignment.
//
// Additionally, the baseline-sharing groups' offsets, max-ascend and
// max-descent will be computed and stored. This class also computes
// the baseline offset for a particular item, based on the max-ascent
// for its associated baseline-sharing group.
class GridBaselineAlignment {
  DISALLOW_NEW();

 public:
  // Collects the items participating in baseline alignment and
  // updates the corresponding baseline-sharing group of the Baseline
  // Context the items belongs to.
  // All the baseline offsets are updated accordingly based on the
  // added item.
  void UpdateBaselineAlignmentContext(ItemPosition,
                                      unsigned shared_context,
                                      const LayoutBox&,
                                      GridAxis);

  // Returns the baseline offset of a particular item, based on the
  // max-ascent for its associated baseline-sharing group
  LayoutUnit BaselineOffsetForChild(ItemPosition,
                                    unsigned shared_context,
                                    const LayoutBox&,
                                    GridAxis) const;

  // Sets the Grid Container's writing-mode so that we can avoid the
  // dependecy of the LayoutGrid class for determining whether a grid
  // item is orthogonal or not.
  void SetBlockFlow(WritingMode block_flow) { block_flow_ = block_flow; }

  // Clearing the Baseline Alignment context and their internal
  // classes and data structures.
  void Clear(GridAxis);

 private:
  const BaselineGroup& GetBaselineGroupForChild(ItemPosition,
                                                unsigned shared_context,
                                                const LayoutBox&,
                                                GridAxis) const;
  LayoutUnit MarginOverForChild(const LayoutBox&, GridAxis) const;
  LayoutUnit MarginUnderForChild(const LayoutBox&, GridAxis) const;
  LayoutUnit LogicalAscentForChild(const LayoutBox&, GridAxis) const;
  LayoutUnit AscentForChild(const LayoutBox&, GridAxis) const;
  LayoutUnit DescentForChild(const LayoutBox&, LayoutUnit, GridAxis) const;
  bool IsDescentBaselineForChild(const LayoutBox&, GridAxis) const;
  bool IsHorizontalBaselineAxis(GridAxis) const;
  bool IsOrthogonalChildForBaseline(const LayoutBox&) const;
  bool IsParallelToBaselineAxisForChild(const LayoutBox&, GridAxis) const;

  typedef HashMap<unsigned,
                  std::unique_ptr<BaselineContext>,
                  DefaultHash<unsigned>::Hash,
                  WTF::UnsignedWithZeroKeyHashTraits<unsigned>>
      BaselineContextsMap;

  // Grid Container's WritingMode, used to determine grid item's orthogonality.
  WritingMode block_flow_;
  BaselineContextsMap row_axis_alignment_context_;
  BaselineContextsMap col_axis_alignment_context_;
};

}  // namespace blink

#endif  // BaselineContext_h