summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.cc
blob: 9c556e3468bc2b9415ee963939b88373530f7bed (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
// 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.

#include "third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.h"

#include "third_party/blink/renderer/core/layout/ng/ng_block_break_token.h"
#include "third_party/blink/renderer/core/layout/ng/ng_box_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/ng_constraint_space.h"
#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"

namespace blink {

// Return the total amount of block space spent on a node by fragments
// preceding this one (but not including this one).
LayoutUnit PreviouslyUsedBlockSpace(const NGConstraintSpace& constraint_space,
                                    const NGPhysicalFragment& fragment) {
  if (!fragment.IsBox())
    return LayoutUnit();
  const NGPhysicalBoxFragment& box_fragment =
      To<NGPhysicalBoxFragment>(fragment);
  const auto* break_token = To<NGBlockBreakToken>(box_fragment.BreakToken());
  if (!break_token)
    return LayoutUnit();
  NGBoxFragment logical_fragment(constraint_space.GetWritingMode(),
                                 constraint_space.Direction(), box_fragment);
  return break_token->UsedBlockSize() - logical_fragment.BlockSize();
}

// At a class A break point [1], the break value with the highest precedence
// wins. If the two values have the same precedence (e.g. "left" and "right"),
// the value specified on a latter object wins.
//
// [1] https://drafts.csswg.org/css-break/#possible-breaks
inline int FragmentainerBreakPrecedence(EBreakBetween break_value) {
  // "auto" has the lowest priority.
  // "avoid*" values win over "auto".
  // "avoid-page" wins over "avoid-column".
  // "avoid" wins over "avoid-page".
  // Forced break values win over "avoid".
  // Any forced page break value wins over "column" forced break.
  // More specific break values (left, right, recto, verso) wins over generic
  // "page" values.

  switch (break_value) {
    default:
      NOTREACHED();
      FALLTHROUGH;
    case EBreakBetween::kAuto:
      return 0;
    case EBreakBetween::kAvoidColumn:
      return 1;
    case EBreakBetween::kAvoidPage:
      return 2;
    case EBreakBetween::kAvoid:
      return 3;
    case EBreakBetween::kColumn:
      return 4;
    case EBreakBetween::kPage:
      return 5;
    case EBreakBetween::kLeft:
    case EBreakBetween::kRight:
    case EBreakBetween::kRecto:
    case EBreakBetween::kVerso:
      return 6;
  }
}

EBreakBetween JoinFragmentainerBreakValues(EBreakBetween first_value,
                                           EBreakBetween second_value) {
  if (FragmentainerBreakPrecedence(second_value) >=
      FragmentainerBreakPrecedence(first_value))
    return second_value;
  return first_value;
}

bool IsForcedBreakValue(const NGConstraintSpace& constraint_space,
                        EBreakBetween break_value) {
  if (break_value == EBreakBetween::kColumn)
    return constraint_space.BlockFragmentationType() == kFragmentColumn;
  if (break_value == EBreakBetween::kLeft ||
      break_value == EBreakBetween::kPage ||
      break_value == EBreakBetween::kRecto ||
      break_value == EBreakBetween::kRight ||
      break_value == EBreakBetween::kVerso)
    return constraint_space.BlockFragmentationType() == kFragmentPage;
  return false;
}

bool ShouldIgnoreBlockStartMargin(const NGConstraintSpace& constraint_space,
                                  NGLayoutInputNode child,
                                  const NGBreakToken* child_break_token) {
  // Always ignore margins if we're not at the start of the child.
  auto* child_block_break_token =
      DynamicTo<NGBlockBreakToken>(child_break_token);
  if (child_block_break_token && !child_block_break_token->IsBreakBefore())
    return true;

  // If we're not fragmented or have been explicitly instructed to honor
  // margins, don't ignore them.
  if (!constraint_space.HasBlockFragmentation() ||
      constraint_space.HasSeparateLeadingFragmentainerMargins())
    return false;

  // Only ignore margins if we're at the start of the fragmentainer.
  if (constraint_space.FragmentainerBlockSize() !=
      constraint_space.FragmentainerSpaceAtBfcStart())
    return false;

  // Otherwise, only ignore in-flow margins.
  return !child.IsFloating() && !child.IsOutOfFlowPositioned();
}

}  // namespace blink