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 "nsFrame.h" 40 #include "nsGkAtoms.h" 41 42 nsIFrame* NS_NewPlaceholderFrame(nsIPresShell* aPresShell, 43 nsStyleContext* aContext, 44 nsFrameState aTypeBits); 45 46 #define PLACEHOLDER_TYPE_MASK \ 47 (PLACEHOLDER_FOR_FLOAT | PLACEHOLDER_FOR_ABSPOS | PLACEHOLDER_FOR_FIXEDPOS | \ 48 PLACEHOLDER_FOR_POPUP | PLACEHOLDER_FOR_TOPLAYER) 49 50 /** 51 * Implementation of a frame that's used as a placeholder for a frame that 52 * has been moved out of the flow. 53 */ 54 class nsPlaceholderFrame final : public nsFrame { 55 public: 56 NS_DECL_FRAMEARENA_HELPERS(nsPlaceholderFrame) 57 #ifdef DEBUG 58 NS_DECL_QUERYFRAME 59 #endif 60 61 /** 62 * Create a new placeholder frame. aTypeBit must be one of the 63 * PLACEHOLDER_FOR_* constants above. 64 */ 65 friend nsIFrame* NS_NewPlaceholderFrame(nsIPresShell* aPresShell, 66 nsStyleContext* aContext, 67 nsFrameState aTypeBits); nsPlaceholderFrame(nsStyleContext * aContext,nsFrameState aTypeBits)68 nsPlaceholderFrame(nsStyleContext* aContext, nsFrameState aTypeBits) 69 : nsFrame(aContext, kClassID), mOutOfFlowFrame(nullptr) { 70 MOZ_ASSERT( 71 aTypeBits == PLACEHOLDER_FOR_FLOAT || 72 aTypeBits == PLACEHOLDER_FOR_ABSPOS || 73 aTypeBits == PLACEHOLDER_FOR_FIXEDPOS || 74 aTypeBits == PLACEHOLDER_FOR_POPUP || 75 aTypeBits == (PLACEHOLDER_FOR_TOPLAYER | PLACEHOLDER_FOR_ABSPOS) || 76 aTypeBits == (PLACEHOLDER_FOR_TOPLAYER | PLACEHOLDER_FOR_FIXEDPOS), 77 "Unexpected type bit"); 78 AddStateBits(aTypeBits); 79 } 80 81 // Get/Set the associated out of flow frame GetOutOfFlowFrame()82 nsIFrame* GetOutOfFlowFrame() const { return mOutOfFlowFrame; } SetOutOfFlowFrame(nsIFrame * aFrame)83 void SetOutOfFlowFrame(nsIFrame* aFrame) { 84 NS_ASSERTION(!aFrame || !aFrame->GetPrevContinuation(), 85 "OOF must be first continuation"); 86 mOutOfFlowFrame = aFrame; 87 } 88 89 // nsIFrame overrides 90 // We need to override GetXULMinSize and GetXULPrefSize because XUL uses 91 // placeholders not within lines. 92 virtual void AddInlineMinISize(gfxContext* aRenderingContext, 93 InlineMinISizeData* aData) override; 94 virtual void AddInlinePrefISize(gfxContext* aRenderingContext, 95 InlinePrefISizeData* aData) override; 96 virtual nsSize GetXULMinSize(nsBoxLayoutState& aBoxLayoutState) override; 97 virtual nsSize GetXULPrefSize(nsBoxLayoutState& aBoxLayoutState) override; 98 virtual nsSize GetXULMaxSize(nsBoxLayoutState& aBoxLayoutState) override; 99 100 virtual void Reflow(nsPresContext* aPresContext, ReflowOutput& aDesiredSize, 101 const ReflowInput& aReflowInput, 102 nsReflowStatus& aStatus) override; 103 104 virtual void DestroyFrom(nsIFrame* aDestructRoot, 105 PostDestroyData& aPostDestroyData) override; 106 107 #if defined(DEBUG) || (defined(MOZ_REFLOW_PERF_DSP) && defined(MOZ_REFLOW_PERF)) 108 virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder, 109 const nsDisplayListSet& aLists) override; 110 #endif // DEBUG || (MOZ_REFLOW_PERF_DSP && MOZ_REFLOW_PERF) 111 112 #ifdef DEBUG_FRAME_DUMP 113 void List(FILE* out = stderr, const char* aPrefix = "", 114 uint32_t aFlags = 0) const override; 115 virtual nsresult GetFrameName(nsAString& aResult) const override; 116 #endif // DEBUG 117 IsEmpty()118 virtual bool IsEmpty() override { return true; } IsSelfEmpty()119 virtual bool IsSelfEmpty() override { return true; } 120 121 virtual bool CanContinueTextRun() const override; 122 SetLineIsEmptySoFar(bool aValue)123 void SetLineIsEmptySoFar(bool aValue) { 124 AddOrRemoveStateBits(PLACEHOLDER_LINE_IS_EMPTY_SO_FAR, aValue); 125 AddStateBits(PLACEHOLDER_HAVE_LINE_IS_EMPTY_SO_FAR); 126 } GetLineIsEmptySoFar(bool * aResult)127 bool GetLineIsEmptySoFar(bool* aResult) const { 128 bool haveValue = HasAnyStateBits(PLACEHOLDER_HAVE_LINE_IS_EMPTY_SO_FAR); 129 if (haveValue) { 130 *aResult = HasAnyStateBits(PLACEHOLDER_LINE_IS_EMPTY_SO_FAR); 131 } 132 return haveValue; 133 } ForgetLineIsEmptySoFar()134 void ForgetLineIsEmptySoFar() { 135 RemoveStateBits(PLACEHOLDER_HAVE_LINE_IS_EMPTY_SO_FAR); 136 } 137 138 #ifdef ACCESSIBILITY AccessibleType()139 virtual mozilla::a11y::AccType AccessibleType() override { 140 nsIFrame* realFrame = GetRealFrameForPlaceholder(this); 141 return realFrame ? realFrame->AccessibleType() : nsFrame::AccessibleType(); 142 } 143 #endif 144 145 nsStyleContext* GetParentStyleContextForOutOfFlow( 146 nsIFrame** aProviderFrame) const; 147 148 // Like GetParentStyleContextForOutOfFlow, but ignores display:contents bits. 149 nsStyleContext* GetLayoutParentStyleForOutOfFlow( 150 nsIFrame** aProviderFrame) const; 151 RenumberFrameAndDescendants(int32_t * aOrdinal,int32_t aDepth,int32_t aIncrement,bool aForCounting)152 bool RenumberFrameAndDescendants(int32_t* aOrdinal, int32_t aDepth, 153 int32_t aIncrement, 154 bool aForCounting) override { 155 return mOutOfFlowFrame->RenumberFrameAndDescendants( 156 aOrdinal, aDepth, aIncrement, aForCounting); 157 } 158 159 /** 160 * @return the out-of-flow for aFrame if aFrame is a placeholder; otherwise 161 * aFrame 162 */ GetRealFrameFor(nsIFrame * aFrame)163 static nsIFrame* GetRealFrameFor(nsIFrame* aFrame) { 164 NS_PRECONDITION(aFrame, "Must have a frame to work with"); 165 if (aFrame->IsPlaceholderFrame()) { 166 return GetRealFrameForPlaceholder(aFrame); 167 } 168 return aFrame; 169 } 170 171 /** 172 * @return the out-of-flow for aFrame, which is known to be a placeholder 173 */ GetRealFrameForPlaceholder(nsIFrame * aFrame)174 static nsIFrame* GetRealFrameForPlaceholder(nsIFrame* aFrame) { 175 NS_PRECONDITION(aFrame->IsPlaceholderFrame(), 176 "Must have placeholder frame as input"); 177 nsIFrame* outOfFlow = 178 static_cast<nsPlaceholderFrame*>(aFrame)->GetOutOfFlowFrame(); 179 NS_ASSERTION(outOfFlow, "Null out-of-flow for placeholder?"); 180 return outOfFlow; 181 } 182 183 protected: 184 nsIFrame* mOutOfFlowFrame; 185 }; 186 187 #endif /* nsPlaceholderFrame_h___ */ 188