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