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 #ifndef nsIFrameInlines_h___
8 #define nsIFrameInlines_h___
9
10 #include "mozilla/dom/ElementInlines.h"
11 #include "nsContainerFrame.h"
12 #include "nsLayoutUtils.h"
13 #include "nsPlaceholderFrame.h"
14 #include "nsStyleStructInlines.h"
15 #include "nsCSSAnonBoxes.h"
16 #include "nsFrameManager.h"
17
IsSVGGeometryFrameOrSubclass()18 bool nsIFrame::IsSVGGeometryFrameOrSubclass() const {
19 return IsSVGGeometryFrame() || IsSVGImageFrame();
20 }
21
IsFlexItem()22 bool nsIFrame::IsFlexItem() const {
23 return GetParent() && GetParent()->IsFlexContainerFrame() &&
24 !HasAnyStateBits(NS_FRAME_OUT_OF_FLOW);
25 }
26
IsGridItem()27 bool nsIFrame::IsGridItem() const {
28 return GetParent() && GetParent()->IsGridContainerFrame() &&
29 !HasAnyStateBits(NS_FRAME_OUT_OF_FLOW);
30 }
31
IsFlexOrGridContainer()32 bool nsIFrame::IsFlexOrGridContainer() const {
33 return IsFlexContainerFrame() || IsGridContainerFrame();
34 }
35
IsFlexOrGridItem()36 bool nsIFrame::IsFlexOrGridItem() const {
37 return !HasAnyStateBits(NS_FRAME_OUT_OF_FLOW) && GetParent() &&
38 GetParent()->IsFlexOrGridContainer();
39 }
40
IsMasonry(mozilla::LogicalAxis aAxis)41 bool nsIFrame::IsMasonry(mozilla::LogicalAxis aAxis) const {
42 MOZ_DIAGNOSTIC_ASSERT(IsGridContainerFrame());
43 return HasAnyStateBits(aAxis == mozilla::eLogicalAxisBlock
44 ? NS_STATE_GRID_IS_ROW_MASONRY
45 : NS_STATE_GRID_IS_COL_MASONRY);
46 }
47
IsTableCaption()48 bool nsIFrame::IsTableCaption() const {
49 return StyleDisplay()->mDisplay == mozilla::StyleDisplay::TableCaption &&
50 GetParent()->Style()->GetPseudoType() ==
51 mozilla::PseudoStyleType::tableWrapper;
52 }
53
IsFloating()54 bool nsIFrame::IsFloating() const {
55 return HasAnyStateBits(NS_FRAME_OUT_OF_FLOW) &&
56 StyleDisplay()->IsFloating(this);
57 }
58
IsAbsPosContainingBlock()59 bool nsIFrame::IsAbsPosContainingBlock() const {
60 return StyleDisplay()->IsAbsPosContainingBlock(this);
61 }
62
IsFixedPosContainingBlock()63 bool nsIFrame::IsFixedPosContainingBlock() const {
64 return StyleDisplay()->IsFixedPosContainingBlock(this);
65 }
66
IsRelativelyOrStickyPositioned()67 bool nsIFrame::IsRelativelyOrStickyPositioned() const {
68 return StyleDisplay()->IsRelativelyOrStickyPositioned(this);
69 }
70
IsRelativelyPositioned()71 bool nsIFrame::IsRelativelyPositioned() const {
72 return StyleDisplay()->IsRelativelyPositioned(this);
73 }
74
IsStickyPositioned()75 bool nsIFrame::IsStickyPositioned() const {
76 return StyleDisplay()->IsStickyPositioned(this);
77 }
78
IsAbsolutelyPositioned(const nsStyleDisplay * aStyleDisplay)79 bool nsIFrame::IsAbsolutelyPositioned(
80 const nsStyleDisplay* aStyleDisplay) const {
81 return HasAnyStateBits(NS_FRAME_OUT_OF_FLOW) &&
82 StyleDisplayWithOptionalParam(aStyleDisplay)
83 ->IsAbsolutelyPositioned(this);
84 }
85
IsTrueOverflowContainer()86 inline bool nsIFrame::IsTrueOverflowContainer() const {
87 return HasAnyStateBits(NS_FRAME_IS_OVERFLOW_CONTAINER) &&
88 !IsAbsolutelyPositioned();
89 // XXXfr This check isn't quite correct, because it doesn't handle cases
90 // where the out-of-flow has overflow.. but that's rare.
91 // We'll need to revisit the way abspos continuations are handled later
92 // for various reasons, this detail is one of them. See bug 154892
93 }
94
IsBlockOutside()95 bool nsIFrame::IsBlockOutside() const {
96 return StyleDisplay()->IsBlockOutside(this);
97 }
98
IsInlineOutside()99 bool nsIFrame::IsInlineOutside() const {
100 return StyleDisplay()->IsInlineOutside(this);
101 }
102
IsColumnSpan()103 bool nsIFrame::IsColumnSpan() const {
104 return IsBlockOutside() && StyleColumn()->IsColumnSpanStyle();
105 }
106
IsColumnSpanInMulticolSubtree()107 bool nsIFrame::IsColumnSpanInMulticolSubtree() const {
108 return IsColumnSpan() &&
109 (HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR) ||
110 // A frame other than inline and block won't have
111 // NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR. We instead test its parent.
112 (GetParent() && GetParent()->Style()->GetPseudoType() ==
113 mozilla::PseudoStyleType::columnSpanWrapper));
114 }
115
GetDisplay()116 mozilla::StyleDisplay nsIFrame::GetDisplay() const {
117 return StyleDisplay()->GetDisplay(this);
118 }
119
SynthesizeBaselineBOffsetFromMarginBox(mozilla::WritingMode aWM,BaselineSharingGroup aGroup)120 nscoord nsIFrame::SynthesizeBaselineBOffsetFromMarginBox(
121 mozilla::WritingMode aWM, BaselineSharingGroup aGroup) const {
122 MOZ_ASSERT(!aWM.IsOrthogonalTo(GetWritingMode()));
123 auto margin = GetLogicalUsedMargin(aWM);
124 if (aGroup == BaselineSharingGroup::First) {
125 if (aWM.IsAlphabeticalBaseline()) {
126 // First baseline for inverted-line content is the block-start margin
127 // edge, as the frame is in effect "flipped" for alignment purposes.
128 return MOZ_UNLIKELY(aWM.IsLineInverted()) ? -margin.BStart(aWM)
129 : BSize(aWM) + margin.BEnd(aWM);
130 }
131 nscoord marginBoxCenter = (BSize(aWM) + margin.BStartEnd(aWM)) / 2;
132 return marginBoxCenter - margin.BStart(aWM);
133 }
134 MOZ_ASSERT(aGroup == BaselineSharingGroup::Last);
135 if (aWM.IsAlphabeticalBaseline()) {
136 // Last baseline for inverted-line content is the block-start margin edge,
137 // as the frame is in effect "flipped" for alignment purposes.
138 return MOZ_UNLIKELY(aWM.IsLineInverted()) ? BSize(aWM) + margin.BStart(aWM)
139 : -margin.BEnd(aWM);
140 }
141 // Round up for central baseline offset, to be consistent with ::First.
142 nscoord marginBoxSize = BSize(aWM) + margin.BStartEnd(aWM);
143 nscoord marginBoxCenter = (marginBoxSize / 2) + (marginBoxSize % 2);
144 return marginBoxCenter - margin.BEnd(aWM);
145 }
146
SynthesizeBaselineBOffsetFromBorderBox(mozilla::WritingMode aWM,BaselineSharingGroup aGroup)147 nscoord nsIFrame::SynthesizeBaselineBOffsetFromBorderBox(
148 mozilla::WritingMode aWM, BaselineSharingGroup aGroup) const {
149 nscoord borderBoxSize = MOZ_UNLIKELY(aWM.IsOrthogonalTo(GetWritingMode()))
150 ? ISize(aWM)
151 : BSize(aWM);
152 if (aGroup == BaselineSharingGroup::First) {
153 return MOZ_LIKELY(aWM.IsAlphabeticalBaseline()) ? borderBoxSize
154 : borderBoxSize / 2;
155 }
156 MOZ_ASSERT(aGroup == BaselineSharingGroup::Last);
157 // Round up for central baseline offset, to be consistent with ::First.
158 auto borderBoxCenter = (borderBoxSize / 2) + (borderBoxSize % 2);
159 return MOZ_LIKELY(aWM.IsAlphabeticalBaseline()) ? 0 : borderBoxCenter;
160 }
161
SynthesizeBaselineBOffsetFromContentBox(mozilla::WritingMode aWM,BaselineSharingGroup aGroup)162 nscoord nsIFrame::SynthesizeBaselineBOffsetFromContentBox(
163 mozilla::WritingMode aWM, BaselineSharingGroup aGroup) const {
164 mozilla::WritingMode wm = GetWritingMode();
165 MOZ_ASSERT(!aWM.IsOrthogonalTo(wm));
166 const auto bp = GetLogicalUsedBorderAndPadding(wm)
167 .ApplySkipSides(GetLogicalSkipSides())
168 .ConvertTo(aWM, wm);
169
170 if (MOZ_UNLIKELY(aWM.IsCentralBaseline())) {
171 nscoord contentBoxBSize = BSize(aWM) - bp.BStartEnd(aWM);
172 if (aGroup == BaselineSharingGroup::First) {
173 return contentBoxBSize / 2 + bp.BStart(aWM);
174 }
175 // Return the same center position as for ::First, but as offset from end:
176 nscoord halfContentBoxBSize = (contentBoxBSize / 2) + (contentBoxBSize % 2);
177 return halfContentBoxBSize + bp.BEnd(aWM);
178 }
179 if (aGroup == BaselineSharingGroup::First) {
180 // First baseline for inverted-line content is the block-start content
181 // edge, as the frame is in effect "flipped" for alignment purposes.
182 return MOZ_UNLIKELY(aWM.IsLineInverted()) ? bp.BStart(aWM)
183 : BSize(aWM) - bp.BEnd(aWM);
184 }
185 // Last baseline for inverted-line content is the block-start content edge,
186 // as the frame is in effect "flipped" for alignment purposes.
187 return MOZ_UNLIKELY(aWM.IsLineInverted()) ? BSize(aWM) - bp.BStart(aWM)
188 : bp.BEnd(aWM);
189 }
190
BaselineBOffset(mozilla::WritingMode aWM,BaselineSharingGroup aBaselineGroup,AlignmentContext aAlignmentContext)191 nscoord nsIFrame::BaselineBOffset(mozilla::WritingMode aWM,
192 BaselineSharingGroup aBaselineGroup,
193 AlignmentContext aAlignmentContext) const {
194 MOZ_ASSERT(!aWM.IsOrthogonalTo(GetWritingMode()));
195 nscoord baseline;
196 if (GetNaturalBaselineBOffset(aWM, aBaselineGroup, &baseline)) {
197 return baseline;
198 }
199 if (aAlignmentContext == AlignmentContext::Inline) {
200 return SynthesizeBaselineBOffsetFromMarginBox(aWM, aBaselineGroup);
201 }
202 if (aAlignmentContext == AlignmentContext::Table) {
203 return SynthesizeBaselineBOffsetFromContentBox(aWM, aBaselineGroup);
204 }
205 return SynthesizeBaselineBOffsetFromBorderBox(aWM, aBaselineGroup);
206 }
207
PropagateWritingModeToSelfAndAncestors(mozilla::WritingMode aWM)208 void nsIFrame::PropagateWritingModeToSelfAndAncestors(
209 mozilla::WritingMode aWM) {
210 MOZ_ASSERT(IsCanvasFrame());
211 for (auto f = this; f; f = f->GetParent()) {
212 f->mWritingMode = aWM;
213 }
214 }
215
GetInFlowParent()216 nsContainerFrame* nsIFrame::GetInFlowParent() const {
217 if (HasAnyStateBits(NS_FRAME_OUT_OF_FLOW)) {
218 nsIFrame* ph =
219 FirstContinuation()->GetProperty(nsIFrame::PlaceholderFrameProperty());
220 return ph->GetParent();
221 }
222
223 return GetParent();
224 }
225
226 // We generally want to follow the style tree for preserve-3d, jumping through
227 // display: contents.
228 //
229 // There are various fun mismatches between the flattened tree and the frame
230 // tree which makes this non-trivial to do looking at the frame tree state:
231 //
232 // - Anon boxes. You'd have to step through them, because you generally want to
233 // ignore them.
234 //
235 // - IB-splits, which produce a frame tree where frames for the block inside
236 // the inline are not children of any frame from the inline.
237 //
238 // - display: contents, which makes DOM ancestors not have frames even when a
239 // descendant does.
240 //
241 // See GetFlattenedTreeParentElementForStyle for the difference between it and
242 // plain GetFlattenedTreeParentElement.
GetClosestFlattenedTreeAncestorPrimaryFrame()243 nsIFrame* nsIFrame::GetClosestFlattenedTreeAncestorPrimaryFrame() const {
244 if (!mContent) {
245 return nullptr;
246 }
247 mozilla::dom::Element* parent =
248 mContent->GetFlattenedTreeParentElementForStyle();
249 while (parent) {
250 if (nsIFrame* frame = parent->GetPrimaryFrame()) {
251 return frame;
252 }
253 // NOTE(emilio): This should be an assert except we have code in tree which
254 // violates invariants like the <frameset> frame construction code.
255 if (MOZ_UNLIKELY(!parent->IsDisplayContents())) {
256 return nullptr;
257 }
258 parent = parent->GetFlattenedTreeParentElementForStyle();
259 }
260 return nullptr;
261 }
262
GetNormalPosition(bool * aHasProperty)263 nsPoint nsIFrame::GetNormalPosition(bool* aHasProperty) const {
264 bool hasProperty;
265 nsPoint normalPosition = GetProperty(NormalPositionProperty(), &hasProperty);
266 if (aHasProperty) {
267 *aHasProperty = hasProperty;
268 }
269 return hasProperty ? normalPosition : GetPosition();
270 }
271
GetLogicalNormalPosition(mozilla::WritingMode aWritingMode,const nsSize & aContainerSize)272 mozilla::LogicalPoint nsIFrame::GetLogicalNormalPosition(
273 mozilla::WritingMode aWritingMode, const nsSize& aContainerSize) const {
274 // Subtract the size of this frame from the container size to get
275 // the correct position in rtl frames where the origin is on the
276 // right instead of the left
277 return mozilla::LogicalPoint(aWritingMode, GetNormalPosition(),
278 aContainerSize - mRect.Size());
279 }
280
281 #endif
282