1 /*
2 * Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public License
15 * along with this library; see the file COPYING.LIB. If not, write to
16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 *
19 */
20
21 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_LINE_INLINE_FLOW_BOX_H_
22 #define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_LINE_INLINE_FLOW_BOX_H_
23
24 #include <memory>
25 #include "third_party/blink/renderer/core/layout/line/inline_box.h"
26 #include "third_party/blink/renderer/core/layout/overflow_model.h"
27 #include "third_party/blink/renderer/core/style/shadow_data.h"
28
29 namespace blink {
30
31 class HitTestResult;
32 class InlineTextBox;
33 class LineBoxList;
34 class SimpleFontData;
35 class VerticalPositionCache;
36
37 struct GlyphOverflow;
38
39 typedef HashMap<const InlineTextBox*,
40 std::pair<Vector<const SimpleFontData*>, GlyphOverflow>>
41 GlyphOverflowAndFallbackFontsMap;
42
43 class InlineFlowBox : public InlineBox {
44 public:
InlineFlowBox(LineLayoutItem line_layout_item)45 InlineFlowBox(LineLayoutItem line_layout_item)
46 : InlineBox(line_layout_item),
47 first_child_(nullptr),
48 last_child_(nullptr),
49 prev_line_box_(nullptr),
50 next_line_box_(nullptr),
51 include_logical_left_edge_(false),
52 include_logical_right_edge_(false),
53 descendants_have_same_line_height_and_baseline_(true),
54 baseline_type_(kAlphabeticBaseline),
55 has_annotations_before_(false),
56 has_annotations_after_(false),
57 line_break_bidi_status_eor_(WTF::unicode::kLeftToRight),
58 line_break_bidi_status_last_strong_(WTF::unicode::kLeftToRight),
59 line_break_bidi_status_last_(WTF::unicode::kLeftToRight),
60 is_first_after_page_break_(false)
61 #if DCHECK_IS_ON()
62 ,
63 has_bad_child_list_(false)
64 #endif
65 {
66 // Internet Explorer and Firefox always create a marker for list items, even
67 // when the list-style-type is none. We do not make a marker in the
68 // list-style-type: none case, since it is wasteful to do so.
69 // However, in order to match other browsers we have to pretend like an
70 // invisible marker exists. The side effect of having an invisible marker
71 // is that the quirks mode behavior of shrinking lines with no text children
72 // must not apply. This change also means that gaps will exist between image
73 // bullet list items. Even when the list bullet is an image, the line is
74 // still considered to be immune from the quirk.
75 has_text_children_ =
76 line_layout_item.StyleRef().Display() == EDisplay::kListItem;
77 has_text_descendants_ = has_text_children_;
78 }
79
80 #if DCHECK_IS_ON()
81 ~InlineFlowBox() override;
82
83 void DumpLineTreeAndMark(StringBuilder&,
84 const InlineBox* = nullptr,
85 const char* = nullptr,
86 const InlineBox* = nullptr,
87 const char* = nullptr,
88 const LayoutObject* = nullptr,
89 int = 0) const override;
90 #endif
91 const char* BoxName() const override;
92
PrevForSameLayoutObject()93 InlineFlowBox* PrevForSameLayoutObject() const { return prev_line_box_; }
NextForSameLayoutObject()94 InlineFlowBox* NextForSameLayoutObject() const { return next_line_box_; }
SetNextForSameLayoutObject(InlineFlowBox * n)95 void SetNextForSameLayoutObject(InlineFlowBox* n) { next_line_box_ = n; }
SetPreviousForSameLayoutObject(InlineFlowBox * p)96 void SetPreviousForSameLayoutObject(InlineFlowBox* p) { prev_line_box_ = p; }
97
FirstChild()98 InlineBox* FirstChild() const { return first_child_; }
LastChild()99 InlineBox* LastChild() const { return last_child_; }
100
IsLeaf()101 bool IsLeaf() const final { return false; }
102
103 InlineBox* FirstLeafChild() const;
104 InlineBox* LastLeafChild() const;
105
106 DISABLE_CFI_PERF
SetConstructed()107 void SetConstructed() final {
108 InlineBox::SetConstructed();
109 for (InlineBox* child = FirstChild(); child; child = child->NextOnLine())
110 child->SetConstructed();
111 }
112
113 void AddToLine(InlineBox* child);
114 void DeleteLine() final;
115 void ExtractLine() final;
116 void AttachLine() final;
117 void Move(const LayoutSize&) override;
118
119 virtual void ExtractLineBoxFromLayoutObject();
120 virtual void AttachLineBoxToLayoutObject();
121 virtual void RemoveLineBoxFromLayoutObject();
122
123 void ClearTruncation() override;
124
125 LayoutRect FrameRect() const;
126
127 void Paint(const PaintInfo&,
128 const LayoutPoint&,
129 LayoutUnit line_top,
130 LayoutUnit line_bottom) const override;
131 bool NodeAtPoint(HitTestResult&,
132 const HitTestLocation&,
133 const PhysicalOffset& accumulated_offset,
134 LayoutUnit line_top,
135 LayoutUnit line_bottom) override;
136
137 bool BoxShadowCanBeAppliedToBackground(const FillLayer&) const;
138
139 virtual LineBoxList* LineBoxes() const;
140
141 // logicalLeft = left in a horizontal line and top in a vertical line.
MarginBorderPaddingLogicalLeft()142 LayoutUnit MarginBorderPaddingLogicalLeft() const {
143 return MarginLogicalLeft() + BorderLogicalLeft() + PaddingLogicalLeft();
144 }
MarginBorderPaddingLogicalRight()145 LayoutUnit MarginBorderPaddingLogicalRight() const {
146 return MarginLogicalRight() + BorderLogicalRight() + PaddingLogicalRight();
147 }
MarginLogicalLeft()148 LayoutUnit MarginLogicalLeft() const {
149 if (!IncludeLogicalLeftEdge())
150 return LayoutUnit();
151 return IsHorizontal() ? BoxModelObject().MarginLeft()
152 : BoxModelObject().MarginTop();
153 }
MarginLogicalRight()154 LayoutUnit MarginLogicalRight() const {
155 if (!IncludeLogicalRightEdge())
156 return LayoutUnit();
157 return IsHorizontal() ? BoxModelObject().MarginRight()
158 : BoxModelObject().MarginBottom();
159 }
MarginLogicalWidth()160 LayoutUnit MarginLogicalWidth() const {
161 return MarginLogicalLeft() + MarginLogicalRight();
162 }
BorderLogicalLeft()163 LayoutUnit BorderLogicalLeft() const {
164 if (!IncludeLogicalLeftEdge())
165 return LayoutUnit();
166 return LayoutUnit(
167 IsHorizontal()
168 ? GetLineLayoutItem().Style(IsFirstLineStyle())->BorderLeftWidth()
169 : GetLineLayoutItem().Style(IsFirstLineStyle())->BorderTopWidth());
170 }
BorderLogicalRight()171 LayoutUnit BorderLogicalRight() const {
172 if (!IncludeLogicalRightEdge())
173 return LayoutUnit();
174 return LayoutUnit(
175 IsHorizontal()
176 ? GetLineLayoutItem().Style(IsFirstLineStyle())->BorderRightWidth()
177 : GetLineLayoutItem()
178 .Style(IsFirstLineStyle())
179 ->BorderBottomWidth());
180 }
PaddingLogicalLeft()181 int PaddingLogicalLeft() const {
182 if (!IncludeLogicalLeftEdge())
183 return 0;
184 return (IsHorizontal() ? BoxModelObject().PaddingLeft()
185 : BoxModelObject().PaddingTop())
186 .ToInt();
187 }
PaddingLogicalRight()188 int PaddingLogicalRight() const {
189 if (!IncludeLogicalRightEdge())
190 return 0;
191 return (IsHorizontal() ? BoxModelObject().PaddingRight()
192 : BoxModelObject().PaddingBottom())
193 .ToInt();
194 }
195
IncludeLogicalLeftEdge()196 bool IncludeLogicalLeftEdge() const { return include_logical_left_edge_; }
IncludeLogicalRightEdge()197 bool IncludeLogicalRightEdge() const { return include_logical_right_edge_; }
SetEdges(bool include_left,bool include_right)198 void SetEdges(bool include_left, bool include_right) {
199 include_logical_left_edge_ = include_left;
200 include_logical_right_edge_ = include_right;
201 }
202
203 // Helper functions used during line construction and placement.
204 void DetermineSpacingForFlowBoxes(
205 bool last_line,
206 bool is_logically_last_run_wrapped,
207 LineLayoutItem logically_last_run_layout_object);
208 LayoutUnit GetFlowSpacingLogicalWidth();
209 LayoutUnit PlaceBoxesInInlineDirection(LayoutUnit logical_left,
210 bool& needs_word_spacing);
211
212 void ComputeLogicalBoxHeights(RootInlineBox*,
213 LayoutUnit& max_position_top,
214 LayoutUnit& max_position_bottom,
215 LayoutUnit& max_ascent,
216 LayoutUnit& max_descent,
217 bool& set_max_ascent,
218 bool& set_max_descent,
219 bool no_quirks_mode,
220 GlyphOverflowAndFallbackFontsMap&,
221 FontBaseline,
222 VerticalPositionCache&);
223 void AdjustMaxAscentAndDescent(LayoutUnit& max_ascent,
224 LayoutUnit& max_descent,
225 int max_position_top,
226 int max_position_bottom);
227 void PlaceBoxesInBlockDirection(LayoutUnit logical_top,
228 LayoutUnit max_height,
229 LayoutUnit max_ascent,
230 bool no_quirks_mode,
231 LayoutUnit& line_top,
232 LayoutUnit& line_bottom,
233 LayoutUnit& selection_bottom,
234 bool& set_line_top,
235 LayoutUnit& line_top_including_margins,
236 LayoutUnit& line_bottom_including_margins,
237 bool& has_annotations_before,
238 bool& has_annotations_after,
239 FontBaseline);
240 void FlipLinesInBlockDirection(LayoutUnit line_top, LayoutUnit line_bottom);
241 FontBaseline DominantBaseline() const;
242
243 LayoutUnit ComputeOverAnnotationAdjustment(LayoutUnit allowed_position) const;
244 LayoutUnit ComputeUnderAnnotationAdjustment(
245 LayoutUnit allowed_position) const;
246
247 // Computes all layout overflow, plus visual overflow not due to replaced
248 // children. Visual overflow due to replaced children is computed during
249 // the RecalcVisualOverflow tree walk. Other visual overflow is computed
250 // during layout for performance reasons.
251 void ComputeOverflow(LayoutUnit line_top,
252 LayoutUnit line_bottom,
253 GlyphOverflowAndFallbackFontsMap&);
254 // Adds visual flow to the current visual overflow for replaced children.
255 void AddReplacedChildrenVisualOverflow(LayoutUnit line_top,
256 LayoutUnit line_bottom);
257
258 void RemoveChild(InlineBox* child, MarkLineBoxes);
259
IsSelected()260 bool IsSelected() const override { return false; }
261
262 bool CanAccommodateEllipsis(bool ltr,
263 LayoutUnit block_edge,
264 LayoutUnit ellipsis_width) const final;
265 LayoutUnit PlaceEllipsisBox(bool ltr,
266 LayoutUnit block_left_edge,
267 LayoutUnit block_right_edge,
268 LayoutUnit ellipsis_width,
269 LayoutUnit& truncated_width,
270 InlineBox**,
271 LayoutUnit logical_left_offset) override;
272
HasTextChildren()273 bool HasTextChildren() const { return has_text_children_; }
HasTextDescendants()274 bool HasTextDescendants() const { return has_text_descendants_; }
SetHasTextDescendants()275 void SetHasTextDescendants() { has_text_descendants_ = true; }
276
277 void SetHasBadChildList();
278
279 // Line visual and layout overflow are in the coordinate space of the block.
280 // This means that they aren't purely physical directions. For horizontal-tb
281 // and vertical-lr they will match physical directions, but for vertical-rl,
282 // the left/right respectively are flipped when compared to their physical
283 // counterparts. For example minX is on the left in vertical-lr, but it is on
284 // the right in vertical-rl.
LayoutOverflowRect(LayoutUnit line_top,LayoutUnit line_bottom)285 LayoutRect LayoutOverflowRect(LayoutUnit line_top,
286 LayoutUnit line_bottom) const {
287 return LayoutOverflowIsSet()
288 ? overflow_->layout_overflow->LayoutOverflowRect()
289 : FrameRectIncludingLineHeight(line_top, line_bottom);
290 }
LogicalTopLayoutOverflow(LayoutUnit line_top)291 LayoutUnit LogicalTopLayoutOverflow(LayoutUnit line_top) const {
292 if (LayoutOverflowIsSet()) {
293 return IsHorizontal()
294 ? overflow_->layout_overflow->LayoutOverflowRect().Y()
295 : overflow_->layout_overflow->LayoutOverflowRect().X();
296 }
297 return line_top;
298 }
LogicalBottomLayoutOverflow(LayoutUnit line_bottom)299 LayoutUnit LogicalBottomLayoutOverflow(LayoutUnit line_bottom) const {
300 if (LayoutOverflowIsSet()) {
301 return IsHorizontal()
302 ? overflow_->layout_overflow->LayoutOverflowRect().MaxY()
303 : overflow_->layout_overflow->LayoutOverflowRect().MaxX();
304 }
305 return line_bottom;
306 }
LogicalLayoutOverflowRect(LayoutUnit line_top,LayoutUnit line_bottom)307 LayoutRect LogicalLayoutOverflowRect(LayoutUnit line_top,
308 LayoutUnit line_bottom) const {
309 LayoutRect result = LayoutOverflowRect(line_top, line_bottom);
310 if (!GetLineLayoutItem().IsHorizontalWritingMode())
311 result = result.TransposedRect();
312 return result;
313 }
314
VisualOverflowRect(LayoutUnit line_top,LayoutUnit line_bottom)315 LayoutRect VisualOverflowRect(LayoutUnit line_top,
316 LayoutUnit line_bottom) const {
317 return VisualOverflowIsSet()
318 ? overflow_->visual_overflow->VisualOverflowRect()
319 : FrameRectIncludingLineHeight(line_top, line_bottom);
320 }
PhysicalVisualOverflowRect(LayoutUnit line_top,LayoutUnit line_bottom)321 PhysicalRect PhysicalVisualOverflowRect(LayoutUnit line_top,
322 LayoutUnit line_bottom) const {
323 LayoutRect rect = VisualOverflowRect(line_top, line_bottom);
324 FlipForWritingMode(rect);
325 return PhysicalRect(rect);
326 }
LogicalLeftVisualOverflow()327 LayoutUnit LogicalLeftVisualOverflow() const {
328 return VisualOverflowIsSet()
329 ? (IsHorizontal()
330 ? overflow_->visual_overflow->VisualOverflowRect().X()
331 : overflow_->visual_overflow->VisualOverflowRect().Y())
332 : LogicalLeft();
333 }
LogicalRightVisualOverflow()334 LayoutUnit LogicalRightVisualOverflow() const {
335 return VisualOverflowIsSet()
336 ? (IsHorizontal()
337 ? overflow_->visual_overflow->VisualOverflowRect().MaxX()
338 : overflow_->visual_overflow->VisualOverflowRect().MaxY())
339 : static_cast<LayoutUnit>(LogicalRight().Ceil());
340 }
LogicalTopVisualOverflow(LayoutUnit line_top)341 LayoutUnit LogicalTopVisualOverflow(LayoutUnit line_top) const {
342 if (VisualOverflowIsSet()) {
343 return IsHorizontal()
344 ? overflow_->visual_overflow->VisualOverflowRect().Y()
345 : overflow_->visual_overflow->VisualOverflowRect().X();
346 }
347 return line_top;
348 }
LogicalBottomVisualOverflow(LayoutUnit line_bottom)349 LayoutUnit LogicalBottomVisualOverflow(LayoutUnit line_bottom) const {
350 if (VisualOverflowIsSet()) {
351 return IsHorizontal()
352 ? overflow_->visual_overflow->VisualOverflowRect().MaxY()
353 : overflow_->visual_overflow->VisualOverflowRect().MaxX();
354 }
355 return line_bottom;
356 }
LogicalVisualOverflowRect(LayoutUnit line_top,LayoutUnit line_bottom)357 LayoutRect LogicalVisualOverflowRect(LayoutUnit line_top,
358 LayoutUnit line_bottom) const {
359 LayoutRect result = VisualOverflowRect(line_top, line_bottom);
360 if (!GetLineLayoutItem().IsHorizontalWritingMode())
361 result = result.TransposedRect();
362 return result;
363 }
364
FrameRectIncludingLineHeight(LayoutUnit line_top,LayoutUnit line_bottom)365 LayoutRect FrameRectIncludingLineHeight(LayoutUnit line_top,
366 LayoutUnit line_bottom) const {
367 if (IsHorizontal())
368 return LayoutRect(X(), line_top, LogicalWidth(), line_bottom - line_top);
369 return LayoutRect(line_top, Y(), line_bottom - line_top, LogicalWidth());
370 }
371
LogicalFrameRectIncludingLineHeight(LayoutUnit line_top,LayoutUnit line_bottom)372 LayoutRect LogicalFrameRectIncludingLineHeight(LayoutUnit line_top,
373 LayoutUnit line_bottom) const {
374 return LayoutRect(LogicalLeft(), line_top, LogicalWidth(),
375 line_bottom - line_top);
376 }
377
DescendantsHaveSameLineHeightAndBaseline()378 bool DescendantsHaveSameLineHeightAndBaseline() const {
379 return descendants_have_same_line_height_and_baseline_;
380 }
ClearDescendantsHaveSameLineHeightAndBaseline()381 void ClearDescendantsHaveSameLineHeightAndBaseline() {
382 descendants_have_same_line_height_and_baseline_ = false;
383 if (Parent() && Parent()->DescendantsHaveSameLineHeightAndBaseline())
384 Parent()->ClearDescendantsHaveSameLineHeightAndBaseline();
385 }
386
IsFirstAfterPageBreak()387 bool IsFirstAfterPageBreak() const { return is_first_after_page_break_; }
SetIsFirstAfterPageBreak(bool is_first_after_page_break)388 void SetIsFirstAfterPageBreak(bool is_first_after_page_break) {
389 is_first_after_page_break_ = is_first_after_page_break;
390 }
391
392 bool OverrideVisualOverflowFromLogicalRect(
393 const LayoutRect& logical_visual_overflow,
394 LayoutUnit line_top,
395 LayoutUnit line_bottom);
396
397 void OverrideLayoutOverflowFromLogicalRect(
398 const LayoutRect& logical_layout_overflow,
399 LayoutUnit line_top,
400 LayoutUnit line_bottom);
401
402 LayoutUnit FarthestPositionForUnderline(LineLayoutItem decorating_box,
403 FontVerticalPositionType,
404 FontBaseline,
405 LayoutUnit current) const;
406
407 private:
LayoutOverflowIsSet()408 inline bool LayoutOverflowIsSet() const {
409 return overflow_ && overflow_->layout_overflow;
410 }
VisualOverflowIsSet()411 inline bool VisualOverflowIsSet() const {
412 return overflow_ && overflow_->visual_overflow;
413 }
414 void PlaceBoxRangeInInlineDirection(InlineBox* first_child,
415 InlineBox* last_child,
416 LayoutUnit& logical_left,
417 LayoutUnit& min_logical_left,
418 LayoutUnit& max_logical_right,
419 bool& needs_word_spacing);
BeginPlacingBoxRangesInInlineDirection(LayoutUnit logical_left)420 void BeginPlacingBoxRangesInInlineDirection(LayoutUnit logical_left) {
421 SetLogicalLeft(logical_left);
422 }
EndPlacingBoxRangesInInlineDirection(LayoutUnit logical_left,LayoutUnit logical_right,LayoutUnit min_logical_left,LayoutUnit max_logical_right)423 void EndPlacingBoxRangesInInlineDirection(LayoutUnit logical_left,
424 LayoutUnit logical_right,
425 LayoutUnit min_logical_left,
426 LayoutUnit max_logical_right) {
427 SetLogicalWidth(logical_right - logical_left);
428 if (KnownToHaveNoOverflow() &&
429 (min_logical_left < logical_left || max_logical_right > logical_right))
430 ClearKnownToHaveNoOverflow();
431 }
432
433 void AddBoxShadowVisualOverflow(LayoutRect& logical_visual_overflow);
434 void AddBorderOutsetVisualOverflow(LayoutRect& logical_visual_overflow);
435 void AddOutlineVisualOverflow(LayoutRect& logical_visual_overflow);
436 void AddTextBoxVisualOverflow(InlineTextBox*,
437 GlyphOverflowAndFallbackFontsMap&,
438 LayoutRect& logical_visual_overflow);
439 void AddReplacedChildLayoutOverflow(const InlineBox*,
440 LayoutRect& logical_layout_overflow);
441 bool HasEmphasisMarkBefore(const InlineTextBox*) const;
442 bool HasEmphasisMarkOver(const InlineTextBox*) const;
443 bool HasEmphasisMarkUnder(const InlineTextBox*) const;
444
445 void SetLayoutOverflow(const LayoutRect&, const LayoutRect&);
446 void SetVisualOverflow(const LayoutRect&, const LayoutRect&);
447
448 void SetLayoutOverflowFromLogicalRect(
449 const LayoutRect& logical_layout_overflow,
450 LayoutUnit line_top,
451 LayoutUnit line_bottom);
452 void SetVisualOverflowFromLogicalRect(
453 const LayoutRect& logical_visual_overflow,
454 LayoutUnit line_top,
455 LayoutUnit line_bottom);
456
457 protected:
458 std::unique_ptr<SimpleOverflowModel> overflow_;
459
IsInlineFlowBox()460 bool IsInlineFlowBox() const final { return true; }
461
462 InlineBox* first_child_;
463 InlineBox* last_child_;
464
465 // The next/previous box that also uses our LayoutObject.
466 // RootInlineBox, a subclass of this class, uses these fields for
467 // next/previous RootInlineBox.
468 InlineFlowBox* prev_line_box_;
469 InlineFlowBox* next_line_box_;
470
471 private:
472 unsigned include_logical_left_edge_ : 1;
473 unsigned include_logical_right_edge_ : 1;
474 unsigned has_text_children_ : 1;
475 unsigned has_text_descendants_ : 1;
476 unsigned descendants_have_same_line_height_and_baseline_ : 1;
477
478 protected:
479 // The following members are only used by RootInlineBox but moved here to keep
480 // the bits packed.
481
482 // Whether or not this line uses alphabetic or ideographic baselines by
483 // default.
484 unsigned baseline_type_ : 1; // FontBaseline
485
486 // If the line contains any ruby runs, then this will be true.
487 unsigned has_annotations_before_ : 1;
488 unsigned has_annotations_after_ : 1;
489
490 unsigned line_break_bidi_status_eor_ : 5; // WTF::unicode::Direction
491 unsigned line_break_bidi_status_last_strong_ : 5; // WTF::unicode::Direction
492 unsigned line_break_bidi_status_last_ : 5; // WTF::unicode::Direction
493
494 unsigned is_first_after_page_break_ : 1;
495
496 // End of RootInlineBox-specific members.
497
498 #if DCHECK_IS_ON()
499 private:
500 unsigned has_bad_child_list_ : 1;
501 #endif
502 };
503
504 DEFINE_INLINE_BOX_TYPE_CASTS(InlineFlowBox);
505
SetHasBadChildList()506 inline void InlineFlowBox::SetHasBadChildList() {
507 #if DCHECK_IS_ON()
508 has_bad_child_list_ = true;
509 #endif
510 }
511
512 } // namespace blink
513
514 #endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_LINE_INLINE_FLOW_BOX_H_
515