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