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/. */
7 #ifndef nsIFrameInlines_h___
8 #define nsIFrameInlines_h___
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"
18 bool nsIFrame::IsSVGGeometryFrameOrSubclass() const {
19 return IsSVGGeometryFrame() || IsSVGImageFrame();
22 bool nsIFrame::IsFlexItem() const {
23 return GetParent() && GetParent()->IsFlexContainerFrame() &&
24 !HasAnyStateBits(NS_FRAME_OUT_OF_FLOW
);
27 bool nsIFrame::IsGridItem() const {
28 return GetParent() && GetParent()->IsGridContainerFrame() &&
29 !HasAnyStateBits(NS_FRAME_OUT_OF_FLOW
);
32 bool nsIFrame::IsFlexOrGridContainer() const {
33 return IsFlexContainerFrame() || IsGridContainerFrame();
36 bool nsIFrame::IsFlexOrGridItem() const {
37 return !HasAnyStateBits(NS_FRAME_OUT_OF_FLOW
) && GetParent() &&
38 GetParent()->IsFlexOrGridContainer();
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
);
48 bool nsIFrame::IsTableCaption() const {
49 return StyleDisplay()->mDisplay
== mozilla::StyleDisplay::TableCaption
&&
50 GetParent()->Style()->GetPseudoType() ==
51 mozilla::PseudoStyleType::tableWrapper
;
54 bool nsIFrame::IsFloating() const {
55 return HasAnyStateBits(NS_FRAME_OUT_OF_FLOW
) &&
56 StyleDisplay()->IsFloating(this);
59 bool nsIFrame::IsAbsPosContainingBlock() const {
60 return StyleDisplay()->IsAbsPosContainingBlock(this);
63 bool nsIFrame::IsFixedPosContainingBlock() const {
64 return StyleDisplay()->IsFixedPosContainingBlock(this);
67 bool nsIFrame::IsRelativelyPositioned() const {
68 return StyleDisplay()->IsRelativelyPositioned(this);
71 bool nsIFrame::IsStickyPositioned() const {
72 return StyleDisplay()->IsStickyPositioned(this);
75 bool nsIFrame::IsAbsolutelyPositioned(
76 const nsStyleDisplay
* aStyleDisplay
) const {
77 return HasAnyStateBits(NS_FRAME_OUT_OF_FLOW
) &&
78 StyleDisplayWithOptionalParam(aStyleDisplay
)
79 ->IsAbsolutelyPositioned(this);
82 inline bool nsIFrame::IsTrueOverflowContainer() const {
83 return HasAnyStateBits(NS_FRAME_IS_OVERFLOW_CONTAINER
) &&
84 !IsAbsolutelyPositioned();
85 // XXXfr This check isn't quite correct, because it doesn't handle cases
86 // where the out-of-flow has overflow.. but that's rare.
87 // We'll need to revisit the way abspos continuations are handled later
88 // for various reasons, this detail is one of them. See bug 154892
91 bool nsIFrame::IsBlockOutside() const {
92 return StyleDisplay()->IsBlockOutside(this);
95 bool nsIFrame::IsInlineOutside() const {
96 return StyleDisplay()->IsInlineOutside(this);
99 bool nsIFrame::IsColumnSpan() const {
100 return IsBlockOutside() && StyleColumn()->IsColumnSpanStyle();
103 bool nsIFrame::IsColumnSpanInMulticolSubtree() const {
104 return IsColumnSpan() &&
105 (HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR
) ||
106 // A frame other than inline and block won't have
107 // NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR. We instead test its parent.
108 (GetParent() && GetParent()->Style()->GetPseudoType() ==
109 mozilla::PseudoStyleType::columnSpanWrapper
));
112 mozilla::StyleDisplay
nsIFrame::GetDisplay() const {
113 return StyleDisplay()->GetDisplay(this);
116 nscoord
nsIFrame::SynthesizeBaselineBOffsetFromMarginBox(
117 mozilla::WritingMode aWM
, BaselineSharingGroup aGroup
) const {
118 MOZ_ASSERT(!aWM
.IsOrthogonalTo(GetWritingMode()));
119 auto margin
= GetLogicalUsedMargin(aWM
);
120 if (aGroup
== BaselineSharingGroup::First
) {
121 if (aWM
.IsAlphabeticalBaseline()) {
122 // First baseline for inverted-line content is the block-start margin
123 // edge, as the frame is in effect "flipped" for alignment purposes.
124 return MOZ_UNLIKELY(aWM
.IsLineInverted()) ? -margin
.BStart(aWM
)
125 : BSize(aWM
) + margin
.BEnd(aWM
);
127 nscoord marginBoxCenter
= (BSize(aWM
) + margin
.BStartEnd(aWM
)) / 2;
128 return marginBoxCenter
- margin
.BStart(aWM
);
130 MOZ_ASSERT(aGroup
== BaselineSharingGroup::Last
);
131 if (aWM
.IsAlphabeticalBaseline()) {
132 // Last baseline for inverted-line content is the block-start margin edge,
133 // as the frame is in effect "flipped" for alignment purposes.
134 return MOZ_UNLIKELY(aWM
.IsLineInverted()) ? BSize(aWM
) + margin
.BStart(aWM
)
137 // Round up for central baseline offset, to be consistent with ::First.
138 nscoord marginBoxSize
= BSize(aWM
) + margin
.BStartEnd(aWM
);
139 nscoord marginBoxCenter
= (marginBoxSize
/ 2) + (marginBoxSize
% 2);
140 return marginBoxCenter
- margin
.BEnd(aWM
);
143 nscoord
nsIFrame::SynthesizeBaselineBOffsetFromBorderBox(
144 mozilla::WritingMode aWM
, BaselineSharingGroup aGroup
) const {
145 nscoord borderBoxSize
= MOZ_UNLIKELY(aWM
.IsOrthogonalTo(GetWritingMode()))
148 if (aGroup
== BaselineSharingGroup::First
) {
149 return MOZ_LIKELY(aWM
.IsAlphabeticalBaseline()) ? borderBoxSize
152 MOZ_ASSERT(aGroup
== BaselineSharingGroup::Last
);
153 // Round up for central baseline offset, to be consistent with ::First.
154 auto borderBoxCenter
= (borderBoxSize
/ 2) + (borderBoxSize
% 2);
155 return MOZ_LIKELY(aWM
.IsAlphabeticalBaseline()) ? 0 : borderBoxCenter
;
158 nscoord
nsIFrame::SynthesizeBaselineBOffsetFromContentBox(
159 mozilla::WritingMode aWM
, BaselineSharingGroup aGroup
) const {
160 mozilla::WritingMode wm
= GetWritingMode();
161 MOZ_ASSERT(!aWM
.IsOrthogonalTo(wm
));
162 const auto bp
= GetLogicalUsedBorderAndPadding(wm
)
163 .ApplySkipSides(GetLogicalSkipSides())
166 if (MOZ_UNLIKELY(aWM
.IsCentralBaseline())) {
167 nscoord contentBoxBSize
= BSize(aWM
) - bp
.BStartEnd(aWM
);
168 if (aGroup
== BaselineSharingGroup::First
) {
169 return contentBoxBSize
/ 2 + bp
.BStart(aWM
);
171 // Return the same center position as for ::First, but as offset from end:
172 nscoord halfContentBoxBSize
= (contentBoxBSize
/ 2) + (contentBoxBSize
% 2);
173 return halfContentBoxBSize
+ bp
.BEnd(aWM
);
175 if (aGroup
== BaselineSharingGroup::First
) {
176 // First baseline for inverted-line content is the block-start content
177 // edge, as the frame is in effect "flipped" for alignment purposes.
178 return MOZ_UNLIKELY(aWM
.IsLineInverted()) ? bp
.BStart(aWM
)
179 : BSize(aWM
) - bp
.BEnd(aWM
);
181 // Last baseline for inverted-line content is the block-start content edge,
182 // as the frame is in effect "flipped" for alignment purposes.
183 return MOZ_UNLIKELY(aWM
.IsLineInverted()) ? BSize(aWM
) - bp
.BStart(aWM
)
187 nscoord
nsIFrame::BaselineBOffset(mozilla::WritingMode aWM
,
188 BaselineSharingGroup aBaselineGroup
,
189 AlignmentContext aAlignmentContext
) const {
190 MOZ_ASSERT(!aWM
.IsOrthogonalTo(GetWritingMode()));
192 if (GetNaturalBaselineBOffset(aWM
, aBaselineGroup
, &baseline
)) {
195 if (aAlignmentContext
== AlignmentContext::Inline
) {
196 return SynthesizeBaselineBOffsetFromMarginBox(aWM
, aBaselineGroup
);
198 if (aAlignmentContext
== AlignmentContext::Table
) {
199 return SynthesizeBaselineBOffsetFromContentBox(aWM
, aBaselineGroup
);
201 return SynthesizeBaselineBOffsetFromBorderBox(aWM
, aBaselineGroup
);
204 void nsIFrame::PropagateWritingModeToSelfAndAncestors(
205 mozilla::WritingMode aWM
) {
206 MOZ_ASSERT(IsCanvasFrame());
207 for (auto f
= this; f
; f
= f
->GetParent()) {
208 f
->mWritingMode
= aWM
;
212 nsContainerFrame
* nsIFrame::GetInFlowParent() const {
213 if (HasAnyStateBits(NS_FRAME_OUT_OF_FLOW
)) {
215 FirstContinuation()->GetProperty(nsIFrame::PlaceholderFrameProperty());
216 return ph
->GetParent();
222 // We generally want to follow the style tree for preserve-3d, jumping through
223 // display: contents.
225 // There are various fun mismatches between the flattened tree and the frame
226 // tree which makes this non-trivial to do looking at the frame tree state:
228 // - Anon boxes. You'd have to step through them, because you generally want to
231 // - IB-splits, which produce a frame tree where frames for the block inside
232 // the inline are not children of any frame from the inline.
234 // - display: contents, which makes DOM ancestors not have frames even when a
237 // See GetFlattenedTreeParentElementForStyle for the difference between it and
238 // plain GetFlattenedTreeParentElement.
239 nsIFrame
* nsIFrame::GetClosestFlattenedTreeAncestorPrimaryFrame() const {
243 mozilla::dom::Element
* parent
=
244 mContent
->GetFlattenedTreeParentElementForStyle();
246 if (nsIFrame
* frame
= parent
->GetPrimaryFrame()) {
249 // NOTE(emilio): This should be an assert except we have code in tree which
250 // violates invariants like the <frameset> frame construction code.
251 if (MOZ_UNLIKELY(!parent
->IsDisplayContents())) {
254 parent
= parent
->GetFlattenedTreeParentElementForStyle();
259 nsPoint
nsIFrame::GetNormalPosition(bool* aHasProperty
) const {
260 nsPoint
* normalPosition
= GetProperty(NormalPositionProperty());
261 if (normalPosition
) {
263 *aHasProperty
= true;
265 return *normalPosition
;
268 *aHasProperty
= false;
270 return GetPosition();
273 mozilla::LogicalPoint
nsIFrame::GetLogicalNormalPosition(
274 mozilla::WritingMode aWritingMode
, const nsSize
& aContainerSize
) const {
275 // Subtract the size of this frame from the container size to get
276 // the correct position in rtl frames where the origin is on the
277 // right instead of the left
278 return mozilla::LogicalPoint(aWritingMode
, GetNormalPosition(),
279 aContainerSize
- mRect
.Size());