Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(590)

Side by Side Diff: third_party/WebKit/Source/core/layout/ng/inline/ng_inline_box_state.cc

Issue 2803433002: [LayoutNG] Initial support for the 'vertical-align' property (Closed)
Patch Set: Move all On*() to NGInlineLayoutStateStack Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2017 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 #include "core/layout/ng/inline/ng_inline_box_state.h"
6
7 #include "core/layout/ng/inline/ng_inline_node.h"
8 #include "core/layout/ng/inline/ng_line_box_fragment_builder.h"
9 #include "core/layout/ng/inline/ng_text_fragment_builder.h"
10 #include "core/style/ComputedStyle.h"
11
12 namespace blink {
13
14 void NGInlineBoxState::ComputeTextMetrics(const NGLayoutInlineItem& item,
15 FontBaseline baseline_type) {
16 const ComputedStyle& style = *item.Style();
17 text_metrics = NGLineHeightMetrics(style, baseline_type);
18 text_top = -text_metrics.ascent;
19 text_metrics.AddLeading(style.ComputedLineHeightAsFixed());
20 metrics.Unite(text_metrics);
21
22 include_used_fonts = style.LineHeight().IsNegative();
23 }
24
25 NGInlineBoxState* NGInlineLayoutStateStack::OnBeginPlaceItems(
26 const ComputedStyle* line_style) {
27 if (stack_.IsEmpty()) {
28 // For the first line, push a box state for the line itself.
29 stack_.Resize(1);
30 NGInlineBoxState* box = &stack_.back();
31 box->fragment_start = 0;
32 box->style = line_style;
33 return box;
34 }
35
36 // For the following lines, clear states that are not shared across lines.
37 for (auto& box : stack_) {
38 box.fragment_start = 0;
39 box.metrics = NGLineHeightMetrics();
40 DCHECK(box.pending_descendants.IsEmpty());
41 }
42 return &stack_.back();
43 }
44
45 NGInlineBoxState* NGInlineLayoutStateStack::OnOpenTag(
46 const NGLayoutInlineItem& item,
47 NGLineBoxFragmentBuilder* line_box,
48 NGTextFragmentBuilder* text_builder) {
49 stack_.Resize(stack_.size() + 1);
50 NGInlineBoxState* box = &stack_.back();
51 box->fragment_start = line_box->Children().size();
52 box->style = item.Style();
53 text_builder->SetDirection(box->style->Direction());
54 return box;
55 }
56
57 NGInlineBoxState* NGInlineLayoutStateStack::OnCloseTag(
58 const NGLayoutInlineItem& item,
59 NGLineBoxFragmentBuilder* line_box,
60 NGInlineBoxState* box) {
61 EndBoxState(box, line_box);
62 // TODO(kojii): When the algorithm restarts from a break token, the stack may
63 // underflow. We need either synthesize a missing box state, or push all
64 // parents on initialize.
65 stack_.pop_back();
66 return &stack_.back();
67 }
68
69 void NGInlineLayoutStateStack::OnEndPlaceItems(
70 NGLineBoxFragmentBuilder* line_box) {
71 for (auto it = stack_.rbegin(); it != stack_.rend(); ++it) {
72 NGInlineBoxState* box = &(*it);
73 EndBoxState(box, line_box);
74 }
75 line_box->UniteMetrics(stack_.front().metrics);
76 }
77
78 void NGInlineLayoutStateStack::EndBoxState(NGInlineBoxState* box,
79 NGLineBoxFragmentBuilder* line_box) {
80 ApplyBaselineShift(box, line_box);
81
82 // Unite the metrics to the parent box.
83 if (box != stack_.begin()) {
84 box[-1].metrics.Unite(box->metrics);
85 }
86 }
87
88 void NGInlineLayoutStateStack::ApplyBaselineShift(
89 NGInlineBoxState* box,
90 NGLineBoxFragmentBuilder* line_box) {
91 // Compute descendants that depend on the layout size of this box if any.
92 LayoutUnit baseline_shift;
93 if (!box->pending_descendants.IsEmpty()) {
94 for (const auto& child : box->pending_descendants) {
95 switch (child.vertical_align) {
96 case EVerticalAlign::kTextTop:
97 case EVerticalAlign::kTop:
98 baseline_shift = child.metrics.ascent - box->metrics.ascent;
99 break;
100 case EVerticalAlign::kTextBottom:
101 case EVerticalAlign::kBottom:
102 baseline_shift = box->metrics.descent - child.metrics.descent;
103 break;
104 default:
105 NOTREACHED();
106 continue;
107 }
108 line_box->MoveChildrenInBlockDirection(
109 baseline_shift, child.fragment_start, child.fragment_end);
110 }
111 box->pending_descendants.Clear();
112 }
113
114 const ComputedStyle& style = *box->style;
115 EVerticalAlign vertical_align = style.VerticalAlign();
116 if (vertical_align == EVerticalAlign::kBaseline)
117 return;
118
119 // 'vertical-align' aplies only to inline-level elements.
120 if (box == stack_.begin())
121 return;
122
123 // Check if there are any fragments to move.
124 unsigned fragment_end = line_box->Children().size();
125 if (box->fragment_start == fragment_end)
126 return;
127
128 switch (vertical_align) {
129 case EVerticalAlign::kSub:
130 baseline_shift = style.ComputedFontSizeAsFixed() / 5 + 1;
131 break;
132 case EVerticalAlign::kSuper:
133 baseline_shift = -(style.ComputedFontSizeAsFixed() / 3 + 1);
134 break;
135 case EVerticalAlign::kLength: {
136 // 'Percentages: refer to the 'line-height' of the element itself'.
137 // https://www.w3.org/TR/CSS22/visudet.html#propdef-vertical-align
138 const Length& length = style.GetVerticalAlignLength();
139 LayoutUnit line_height = length.IsPercentOrCalc()
140 ? style.ComputedLineHeightAsFixed()
141 : box->text_metrics.LineHeight();
142 baseline_shift = -ValueForLength(length, line_height);
143 break;
144 }
145 case EVerticalAlign::kMiddle:
146 baseline_shift = (box->metrics.ascent - box->metrics.descent) / 2;
147 if (const SimpleFontData* font_data = style.GetFont().PrimaryFont()) {
148 baseline_shift -= LayoutUnit::FromFloatRound(
149 font_data->GetFontMetrics().XHeight() / 2);
150 }
151 break;
152 case EVerticalAlign::kBaselineMiddle:
153 baseline_shift = (box->metrics.ascent - box->metrics.descent) / 2;
154 break;
155 case EVerticalAlign::kTop:
156 case EVerticalAlign::kBottom:
157 // 'top' and 'bottom' require the layout size of the line box.
158 stack_.front().pending_descendants.push_back(NGPendingPositions{
159 box->fragment_start, fragment_end, box->metrics, vertical_align});
160 return;
161 default:
162 // Other values require the layout size of the parent box.
163 SECURITY_CHECK(box != stack_.begin());
164 box[-1].pending_descendants.push_back(NGPendingPositions{
165 box->fragment_start, fragment_end, box->metrics, vertical_align});
166 return;
167 }
168 box->metrics.Move(baseline_shift);
169 line_box->MoveChildrenInBlockDirection(baseline_shift, box->fragment_start,
170 fragment_end);
171 }
172
173 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698