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 /* 8 * rendering object for the point that anchors out-of-flow rendering 9 * objects such as floats and absolutely positioned elements 10 */ 11 12 /* 13 * Destruction of a placeholder and its out-of-flow must observe the 14 * following constraints: 15 * 16 * - The mapping from the out-of-flow to the placeholder must be 17 * removed from the frame manager before the placeholder is destroyed. 18 * - The mapping from the out-of-flow to the placeholder must be 19 * removed from the frame manager before the out-of-flow is destroyed. 20 * - The placeholder must be removed from the frame tree, or have the 21 * mapping from it to its out-of-flow cleared, before the out-of-flow 22 * is destroyed (so that the placeholder will not point to a destroyed 23 * frame while it's in the frame tree). 24 * 25 * Furthermore, some code assumes that placeholders point to something 26 * useful, so placeholders without an associated out-of-flow should not 27 * remain in the tree. 28 * 29 * The placeholder's Destroy() implementation handles the destruction of 30 * the placeholder and its out-of-flow. To avoid crashes, frame removal 31 * and destruction code that works with placeholders must not assume 32 * that the placeholder points to its out-of-flow. 33 */ 34 35 #ifndef nsPlaceholderFrame_h___ 36 #define nsPlaceholderFrame_h___ 37 38 #include "mozilla/Attributes.h" 39 #include "nsIFrame.h" 40 #include "nsGkAtoms.h" 41 42 namespace mozilla { 43 class PresShell; 44 } // namespace mozilla 45 46 class nsPlaceholderFrame; 47 nsPlaceholderFrame* NS_NewPlaceholderFrame(mozilla::PresShell* aPresShell, 48 mozilla::ComputedStyle* aStyle, 49 nsFrameState aTypeBits); 50 51 #define PLACEHOLDER_TYPE_MASK \ 52 (PLACEHOLDER_FOR_FLOAT | PLACEHOLDER_FOR_ABSPOS | PLACEHOLDER_FOR_FIXEDPOS | \ 53 PLACEHOLDER_FOR_POPUP | PLACEHOLDER_FOR_TOPLAYER) 54 55 /** 56 * Implementation of a frame that's used as a placeholder for a frame that 57 * has been moved out of the flow. 58 */ 59 class nsPlaceholderFrame final : public nsIFrame { 60 public: 61 NS_DECL_FRAMEARENA_HELPERS(nsPlaceholderFrame) 62 #ifdef DEBUG 63 NS_DECL_QUERYFRAME 64 #endif 65 66 /** 67 * Create a new placeholder frame. aTypeBit must be one of the 68 * PLACEHOLDER_FOR_* constants above. 69 */ 70 friend nsPlaceholderFrame* NS_NewPlaceholderFrame( 71 mozilla::PresShell* aPresShell, ComputedStyle* aStyle, 72 nsFrameState aTypeBits); 73 nsPlaceholderFrame(ComputedStyle * aStyle,nsPresContext * aPresContext,nsFrameState aTypeBits)74 nsPlaceholderFrame(ComputedStyle* aStyle, nsPresContext* aPresContext, 75 nsFrameState aTypeBits) 76 : nsIFrame(aStyle, aPresContext, kClassID), mOutOfFlowFrame(nullptr) { 77 MOZ_ASSERT( 78 aTypeBits == PLACEHOLDER_FOR_FLOAT || 79 aTypeBits == PLACEHOLDER_FOR_ABSPOS || 80 aTypeBits == PLACEHOLDER_FOR_FIXEDPOS || 81 aTypeBits == PLACEHOLDER_FOR_POPUP || 82 aTypeBits == (PLACEHOLDER_FOR_TOPLAYER | PLACEHOLDER_FOR_ABSPOS) || 83 aTypeBits == (PLACEHOLDER_FOR_TOPLAYER | PLACEHOLDER_FOR_FIXEDPOS), 84 "Unexpected type bit"); 85 AddStateBits(aTypeBits); 86 } 87 88 // Get/Set the associated out of flow frame GetOutOfFlowFrame()89 nsIFrame* GetOutOfFlowFrame() const { return mOutOfFlowFrame; } SetOutOfFlowFrame(nsIFrame * aFrame)90 void SetOutOfFlowFrame(nsIFrame* aFrame) { 91 NS_ASSERTION(!aFrame || !aFrame->GetPrevContinuation(), 92 "OOF must be first continuation"); 93 mOutOfFlowFrame = aFrame; 94 } 95 96 // nsIFrame overrides 97 // We need to override GetXULMinSize and GetXULPrefSize because XUL uses 98 // placeholders not within lines. 99 virtual void AddInlineMinISize(gfxContext* aRenderingContext, 100 InlineMinISizeData* aData) override; 101 virtual void AddInlinePrefISize(gfxContext* aRenderingContext, 102 InlinePrefISizeData* aData) override; 103 virtual nsSize GetXULMinSize(nsBoxLayoutState& aBoxLayoutState) override; 104 virtual nsSize GetXULPrefSize(nsBoxLayoutState& aBoxLayoutState) override; 105 virtual nsSize GetXULMaxSize(nsBoxLayoutState& aBoxLayoutState) override; 106 107 virtual void Reflow(nsPresContext* aPresContext, ReflowOutput& aDesiredSize, 108 const ReflowInput& aReflowInput, 109 nsReflowStatus& aStatus) override; 110 111 virtual void DestroyFrom(nsIFrame* aDestructRoot, 112 PostDestroyData& aPostDestroyData) override; 113 114 #if defined(DEBUG) || (defined(MOZ_REFLOW_PERF_DSP) && defined(MOZ_REFLOW_PERF)) 115 virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder, 116 const nsDisplayListSet& aLists) override; 117 #endif // DEBUG || (MOZ_REFLOW_PERF_DSP && MOZ_REFLOW_PERF) 118 119 #ifdef DEBUG_FRAME_DUMP 120 void List(FILE* out = stderr, const char* aPrefix = "", 121 ListFlags aFlags = ListFlags()) const override; 122 virtual nsresult GetFrameName(nsAString& aResult) const override; 123 #endif // DEBUG 124 IsEmpty()125 virtual bool IsEmpty() override { return true; } IsSelfEmpty()126 virtual bool IsSelfEmpty() override { return true; } 127 128 virtual bool CanContinueTextRun() const override; 129 SetLineIsEmptySoFar(bool aValue)130 void SetLineIsEmptySoFar(bool aValue) { 131 AddOrRemoveStateBits(PLACEHOLDER_LINE_IS_EMPTY_SO_FAR, aValue); 132 AddStateBits(PLACEHOLDER_HAVE_LINE_IS_EMPTY_SO_FAR); 133 } GetLineIsEmptySoFar(bool * aResult)134 bool GetLineIsEmptySoFar(bool* aResult) const { 135 bool haveValue = HasAnyStateBits(PLACEHOLDER_HAVE_LINE_IS_EMPTY_SO_FAR); 136 if (haveValue) { 137 *aResult = HasAnyStateBits(PLACEHOLDER_LINE_IS_EMPTY_SO_FAR); 138 } 139 return haveValue; 140 } ForgetLineIsEmptySoFar()141 void ForgetLineIsEmptySoFar() { 142 RemoveStateBits(PLACEHOLDER_HAVE_LINE_IS_EMPTY_SO_FAR); 143 } 144 145 #ifdef ACCESSIBILITY AccessibleType()146 virtual mozilla::a11y::AccType AccessibleType() override { 147 nsIFrame* realFrame = GetRealFrameForPlaceholder(this); 148 return realFrame ? realFrame->AccessibleType() : nsIFrame::AccessibleType(); 149 } 150 #endif 151 152 ComputedStyle* GetParentComputedStyleForOutOfFlow( 153 nsIFrame** aProviderFrame) const; 154 155 // Like GetParentComputedStyleForOutOfFlow, but ignores display:contents bits. 156 ComputedStyle* GetLayoutParentStyleForOutOfFlow( 157 nsIFrame** aProviderFrame) const; 158 RenumberFrameAndDescendants(int32_t * aOrdinal,int32_t aDepth,int32_t aIncrement,bool aForCounting)159 bool RenumberFrameAndDescendants(int32_t* aOrdinal, int32_t aDepth, 160 int32_t aIncrement, 161 bool aForCounting) override { 162 return mOutOfFlowFrame->RenumberFrameAndDescendants( 163 aOrdinal, aDepth, aIncrement, aForCounting); 164 } 165 166 /** 167 * @return the out-of-flow for aFrame if aFrame is a placeholder; otherwise 168 * aFrame 169 */ GetRealFrameFor(nsIFrame * aFrame)170 static nsIFrame* GetRealFrameFor(nsIFrame* aFrame) { 171 MOZ_ASSERT(aFrame, "Must have a frame to work with"); 172 if (aFrame->IsPlaceholderFrame()) { 173 return GetRealFrameForPlaceholder(aFrame); 174 } 175 return aFrame; 176 } 177 178 /** 179 * @return the out-of-flow for aFrame, which is known to be a placeholder 180 */ GetRealFrameForPlaceholder(nsIFrame * aFrame)181 static nsIFrame* GetRealFrameForPlaceholder(nsIFrame* aFrame) { 182 MOZ_ASSERT(aFrame->IsPlaceholderFrame(), 183 "Must have placeholder frame as input"); 184 nsIFrame* outOfFlow = 185 static_cast<nsPlaceholderFrame*>(aFrame)->GetOutOfFlowFrame(); 186 NS_ASSERTION(outOfFlow, "Null out-of-flow for placeholder?"); 187 return outOfFlow; 188 } 189 190 protected: 191 nsIFrame* mOutOfFlowFrame; 192 }; 193 194 #endif /* nsPlaceholderFrame_h___ */ 195