Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/layout/generic/CSSAlignUtils.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
/* Utility code for performing CSS Box Alignment */
8
9
#include "CSSAlignUtils.h"
10
#include "ReflowInput.h"
11
12
namespace mozilla {
13
14
static nscoord
15
SpaceToFill(WritingMode aWM, const LogicalSize& aSize, nscoord aMargin,
16
            LogicalAxis aAxis, nscoord aCBSize)
17
0
{
18
0
  nscoord size = aSize.Size(aAxis, aWM);
19
0
  return aCBSize - (size + aMargin);
20
0
}
21
22
nscoord
23
CSSAlignUtils::AlignJustifySelf(uint8_t aAlignment, LogicalAxis aAxis,
24
                                AlignJustifyFlags aFlags,
25
                                nscoord aBaselineAdjust, nscoord aCBSize,
26
                                const ReflowInput& aRI,
27
                                const LogicalSize& aChildSize)
28
0
{
29
0
  MOZ_ASSERT(aAlignment != NS_STYLE_ALIGN_AUTO,
30
0
             "auto values should have resolved already");
31
0
  MOZ_ASSERT(aAlignment != NS_STYLE_ALIGN_LEFT &&
32
0
             aAlignment != NS_STYLE_ALIGN_RIGHT,
33
0
             "caller should map that to the corresponding START/END");
34
0
35
0
  // Promote aFlags to convenience bools:
36
0
  const bool isOverflowSafe = !!(aFlags & AlignJustifyFlags::eOverflowSafe);
37
0
  const bool isSameSide = !!(aFlags & AlignJustifyFlags::eSameSide);
38
0
39
0
  // Map some alignment values to 'start' / 'end'.
40
0
  switch (aAlignment) {
41
0
    case NS_STYLE_ALIGN_SELF_START: // align/justify-self: self-start
42
0
      aAlignment = MOZ_LIKELY(isSameSide) ? NS_STYLE_ALIGN_START
43
0
                                          : NS_STYLE_ALIGN_END;
44
0
      break;
45
0
    case NS_STYLE_ALIGN_SELF_END: // align/justify-self: self-end
46
0
      aAlignment = MOZ_LIKELY(isSameSide) ? NS_STYLE_ALIGN_END
47
0
                                          : NS_STYLE_ALIGN_START;
48
0
      break;
49
0
    // flex-start/flex-end are the same as start/end, in most contexts.
50
0
    // (They have special behavior in flex containers, so flex containers
51
0
    // should map them to some other value before calling this method.)
52
0
    case NS_STYLE_ALIGN_FLEX_START:
53
0
      aAlignment = NS_STYLE_ALIGN_START;
54
0
      break;
55
0
    case NS_STYLE_ALIGN_FLEX_END:
56
0
      aAlignment = NS_STYLE_ALIGN_END;
57
0
      break;
58
0
  }
59
0
60
0
  // XXX try to condense this code a bit by adding the necessary convenience
61
0
  // methods? (bug 1209710)
62
0
63
0
  // Get the item's margin corresponding to the container's start/end side.
64
0
  const LogicalMargin margin = aRI.ComputedLogicalMargin();
65
0
  WritingMode wm = aRI.GetWritingMode();
66
0
  nscoord marginStart, marginEnd;
67
0
  if (aAxis == eLogicalAxisBlock) {
68
0
    if (MOZ_LIKELY(isSameSide)) {
69
0
      marginStart = margin.BStart(wm);
70
0
      marginEnd = margin.BEnd(wm);
71
0
    } else {
72
0
      marginStart = margin.BEnd(wm);
73
0
      marginEnd = margin.BStart(wm);
74
0
    }
75
0
  } else {
76
0
    if (MOZ_LIKELY(isSameSide)) {
77
0
      marginStart = margin.IStart(wm);
78
0
      marginEnd = margin.IEnd(wm);
79
0
    } else {
80
0
      marginStart = margin.IEnd(wm);
81
0
      marginEnd = margin.IStart(wm);
82
0
    }
83
0
  }
84
0
85
0
  const auto& styleMargin = aRI.mStyleMargin->mMargin;
86
0
  bool hasAutoMarginStart;
87
0
  bool hasAutoMarginEnd;
88
0
  if (aFlags & AlignJustifyFlags::eIgnoreAutoMargins) {
89
0
    // (Note: ReflowInput will have treated "auto" margins as 0, so we
90
0
    // don't need to do anything special to avoid expanding them.)
91
0
    hasAutoMarginStart = hasAutoMarginEnd = false;
92
0
  } else if (aAxis == eLogicalAxisBlock) {
93
0
    hasAutoMarginStart = styleMargin.GetBStartUnit(wm) == eStyleUnit_Auto;
94
0
    hasAutoMarginEnd = styleMargin.GetBEndUnit(wm) == eStyleUnit_Auto;
95
0
  } else { /* aAxis == eLogicalAxisInline */
96
0
    hasAutoMarginStart = styleMargin.GetIStartUnit(wm) == eStyleUnit_Auto;
97
0
    hasAutoMarginEnd = styleMargin.GetIEndUnit(wm) == eStyleUnit_Auto;
98
0
  }
99
0
100
0
  // https://drafts.csswg.org/css-align-3/#overflow-values
101
0
  // This implements <overflow-position> = 'safe'.
102
0
  // And auto-margins: https://drafts.csswg.org/css-grid/#auto-margins
103
0
  if ((MOZ_UNLIKELY(isOverflowSafe) && aAlignment != NS_STYLE_ALIGN_START) ||
104
0
      hasAutoMarginStart || hasAutoMarginEnd) {
105
0
    nscoord space = SpaceToFill(wm, aChildSize, marginStart + marginEnd,
106
0
                                aAxis, aCBSize);
107
0
    // XXX we might want to include == 0 here as an optimization -
108
0
    // I need to see what the baseline/last baseline code looks like first.
109
0
    if (space < 0) {
110
0
      // "Overflowing elements ignore their auto margins and overflow
111
0
      // in the end directions"
112
0
      aAlignment = NS_STYLE_ALIGN_START;
113
0
    } else if (hasAutoMarginEnd) {
114
0
      aAlignment = hasAutoMarginStart ? NS_STYLE_ALIGN_CENTER
115
0
                                      : (isSameSide ? NS_STYLE_ALIGN_START
116
0
                                                    : NS_STYLE_ALIGN_END);
117
0
    } else if (hasAutoMarginStart) {
118
0
      aAlignment = isSameSide ? NS_STYLE_ALIGN_END : NS_STYLE_ALIGN_START;
119
0
    }
120
0
  }
121
0
122
0
  // Determine the offset for the child frame (its border-box) which will
123
0
  // achieve the requested alignment.
124
0
  nscoord offset = 0;
125
0
  switch (aAlignment) {
126
0
    case NS_STYLE_ALIGN_BASELINE:
127
0
    case NS_STYLE_ALIGN_LAST_BASELINE:
128
0
      if (MOZ_LIKELY(isSameSide == (aAlignment == NS_STYLE_ALIGN_BASELINE))) {
129
0
        offset = marginStart + aBaselineAdjust;
130
0
      } else {
131
0
        nscoord size = aChildSize.Size(aAxis, wm);
132
0
        offset = aCBSize - (size + marginEnd) - aBaselineAdjust;
133
0
      }
134
0
      break;
135
0
    case NS_STYLE_ALIGN_STRETCH:
136
0
      MOZ_FALLTHROUGH; // ComputeSize() deals with it
137
0
    case NS_STYLE_ALIGN_START:
138
0
      offset = marginStart;
139
0
      break;
140
0
    case NS_STYLE_ALIGN_END: {
141
0
      nscoord size = aChildSize.Size(aAxis, wm);
142
0
      offset = aCBSize - (size + marginEnd);
143
0
      break;
144
0
    }
145
0
    case NS_STYLE_ALIGN_CENTER: {
146
0
      nscoord size = aChildSize.Size(aAxis, wm);
147
0
      offset = (aCBSize - size + marginStart - marginEnd) / 2;
148
0
      break;
149
0
    }
150
0
    default:
151
0
      MOZ_ASSERT_UNREACHABLE("unknown align-/justify-self value");
152
0
  }
153
0
154
0
  return offset;
155
0
}
156
157
} // namespace mozilla