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 
IsRelativelyPositioned()67 bool nsIFrame::IsRelativelyPositioned() const {
68   return StyleDisplay()->IsRelativelyPositioned(this);
69 }
70 
IsStickyPositioned()71 bool nsIFrame::IsStickyPositioned() const {
72   return StyleDisplay()->IsStickyPositioned(this);
73 }
74 
IsAbsolutelyPositioned(const nsStyleDisplay * aStyleDisplay)75 bool nsIFrame::IsAbsolutelyPositioned(
76     const nsStyleDisplay* aStyleDisplay) const {
77   return HasAnyStateBits(NS_FRAME_OUT_OF_FLOW) &&
78          StyleDisplayWithOptionalParam(aStyleDisplay)
79              ->IsAbsolutelyPositioned(this);
80 }
81 
IsTrueOverflowContainer()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
89 }
90 
IsBlockOutside()91 bool nsIFrame::IsBlockOutside() const {
92   return StyleDisplay()->IsBlockOutside(this);
93 }
94 
IsInlineOutside()95 bool nsIFrame::IsInlineOutside() const {
96   return StyleDisplay()->IsInlineOutside(this);
97 }
98 
IsColumnSpan()99 bool nsIFrame::IsColumnSpan() const {
100   return IsBlockOutside() && StyleColumn()->IsColumnSpanStyle();
101 }
102 
IsColumnSpanInMulticolSubtree()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));
110 }
111 
GetDisplay()112 mozilla::StyleDisplay nsIFrame::GetDisplay() const {
113   return StyleDisplay()->GetDisplay(this);
114 }
115 
SynthesizeBaselineBOffsetFromMarginBox(mozilla::WritingMode aWM,BaselineSharingGroup aGroup)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);
126     }
127     nscoord marginBoxCenter = (BSize(aWM) + margin.BStartEnd(aWM)) / 2;
128     return marginBoxCenter - margin.BStart(aWM);
129   }
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)
135                                               : -margin.BEnd(aWM);
136   }
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);
141 }
142 
SynthesizeBaselineBOffsetFromBorderBox(mozilla::WritingMode aWM,BaselineSharingGroup aGroup)143 nscoord nsIFrame::SynthesizeBaselineBOffsetFromBorderBox(
144     mozilla::WritingMode aWM, BaselineSharingGroup aGroup) const {
145   nscoord borderBoxSize = MOZ_UNLIKELY(aWM.IsOrthogonalTo(GetWritingMode()))
146                               ? ISize(aWM)
147                               : BSize(aWM);
148   if (aGroup == BaselineSharingGroup::First) {
149     return MOZ_LIKELY(aWM.IsAlphabeticalBaseline()) ? borderBoxSize
150                                                     : borderBoxSize / 2;
151   }
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;
156 }
157 
SynthesizeBaselineBOffsetFromContentBox(mozilla::WritingMode aWM,BaselineSharingGroup aGroup)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())
164                       .ConvertTo(aWM, wm);
165 
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);
170     }
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);
174   }
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);
180   }
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)
184                                             : bp.BEnd(aWM);
185 }
186 
BaselineBOffset(mozilla::WritingMode aWM,BaselineSharingGroup aBaselineGroup,AlignmentContext aAlignmentContext)187 nscoord nsIFrame::BaselineBOffset(mozilla::WritingMode aWM,
188                                   BaselineSharingGroup aBaselineGroup,
189                                   AlignmentContext aAlignmentContext) const {
190   MOZ_ASSERT(!aWM.IsOrthogonalTo(GetWritingMode()));
191   nscoord baseline;
192   if (GetNaturalBaselineBOffset(aWM, aBaselineGroup, &baseline)) {
193     return baseline;
194   }
195   if (aAlignmentContext == AlignmentContext::Inline) {
196     return SynthesizeBaselineBOffsetFromMarginBox(aWM, aBaselineGroup);
197   }
198   if (aAlignmentContext == AlignmentContext::Table) {
199     return SynthesizeBaselineBOffsetFromContentBox(aWM, aBaselineGroup);
200   }
201   return SynthesizeBaselineBOffsetFromBorderBox(aWM, aBaselineGroup);
202 }
203 
PropagateWritingModeToSelfAndAncestors(mozilla::WritingMode aWM)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;
209   }
210 }
211 
GetInFlowParent()212 nsContainerFrame* nsIFrame::GetInFlowParent() const {
213   if (HasAnyStateBits(NS_FRAME_OUT_OF_FLOW)) {
214     nsIFrame* ph =
215         FirstContinuation()->GetProperty(nsIFrame::PlaceholderFrameProperty());
216     return ph->GetParent();
217   }
218 
219   return GetParent();
220 }
221 
222 // We generally want to follow the style tree for preserve-3d, jumping through
223 // display: contents.
224 //
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:
227 //
228 //  - Anon boxes. You'd have to step through them, because you generally want to
229 //    ignore them.
230 //
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.
233 //
234 //  - display: contents, which makes DOM ancestors not have frames even when a
235 //    descendant does.
236 //
237 // See GetFlattenedTreeParentElementForStyle for the difference between it and
238 // plain GetFlattenedTreeParentElement.
GetClosestFlattenedTreeAncestorPrimaryFrame()239 nsIFrame* nsIFrame::GetClosestFlattenedTreeAncestorPrimaryFrame() const {
240   if (!mContent) {
241     return nullptr;
242   }
243   mozilla::dom::Element* parent =
244       mContent->GetFlattenedTreeParentElementForStyle();
245   while (parent) {
246     if (nsIFrame* frame = parent->GetPrimaryFrame()) {
247       return frame;
248     }
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())) {
252       return nullptr;
253     }
254     parent = parent->GetFlattenedTreeParentElementForStyle();
255   }
256   return nullptr;
257 }
258 
GetNormalPosition(bool * aHasProperty)259 nsPoint nsIFrame::GetNormalPosition(bool* aHasProperty) const {
260   nsPoint* normalPosition = GetProperty(NormalPositionProperty());
261   if (normalPosition) {
262     if (aHasProperty) {
263       *aHasProperty = true;
264     }
265     return *normalPosition;
266   }
267   if (aHasProperty) {
268     *aHasProperty = false;
269   }
270   return GetPosition();
271 }
272 
GetLogicalNormalPosition(mozilla::WritingMode aWritingMode,const nsSize & aContainerSize)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());
280 }
281 
282 #endif
283