michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /* michael@0: * rendering object for the point that anchors out-of-flow rendering michael@0: * objects such as floats and absolutely positioned elements michael@0: */ michael@0: michael@0: /* michael@0: * Destruction of a placeholder and its out-of-flow must observe the michael@0: * following constraints: michael@0: * michael@0: * - The mapping from the out-of-flow to the placeholder must be michael@0: * removed from the frame manager before the placeholder is destroyed. michael@0: * - The mapping from the out-of-flow to the placeholder must be michael@0: * removed from the frame manager before the out-of-flow is destroyed. michael@0: * - The placeholder must be removed from the frame tree, or have the michael@0: * mapping from it to its out-of-flow cleared, before the out-of-flow michael@0: * is destroyed (so that the placeholder will not point to a destroyed michael@0: * frame while it's in the frame tree). michael@0: * michael@0: * Furthermore, some code assumes that placeholders point to something michael@0: * useful, so placeholders without an associated out-of-flow should not michael@0: * remain in the tree. michael@0: * michael@0: * The placeholder's Destroy() implementation handles the destruction of michael@0: * the placeholder and its out-of-flow. To avoid crashes, frame removal michael@0: * and destruction code that works with placeholders must not assume michael@0: * that the placeholder points to its out-of-flow. michael@0: */ michael@0: michael@0: #ifndef nsPlaceholderFrame_h___ michael@0: #define nsPlaceholderFrame_h___ michael@0: michael@0: #include "mozilla/Attributes.h" michael@0: #include "nsFrame.h" michael@0: #include "nsGkAtoms.h" michael@0: michael@0: nsIFrame* NS_NewPlaceholderFrame(nsIPresShell* aPresShell, michael@0: nsStyleContext* aContext, michael@0: nsFrameState aTypeBit); michael@0: michael@0: #define PLACEHOLDER_TYPE_MASK (PLACEHOLDER_FOR_FLOAT | \ michael@0: PLACEHOLDER_FOR_ABSPOS | \ michael@0: PLACEHOLDER_FOR_FIXEDPOS | \ michael@0: PLACEHOLDER_FOR_POPUP) michael@0: michael@0: /** michael@0: * Implementation of a frame that's used as a placeholder for a frame that michael@0: * has been moved out of the flow. michael@0: */ michael@0: class nsPlaceholderFrame MOZ_FINAL : public nsFrame { michael@0: public: michael@0: NS_DECL_FRAMEARENA_HELPERS michael@0: #ifdef DEBUG michael@0: NS_DECL_QUERYFRAME_TARGET(nsPlaceholderFrame) michael@0: NS_DECL_QUERYFRAME michael@0: #endif michael@0: michael@0: /** michael@0: * Create a new placeholder frame. aTypeBit must be one of the michael@0: * PLACEHOLDER_FOR_* constants above. michael@0: */ michael@0: friend nsIFrame* NS_NewPlaceholderFrame(nsIPresShell* aPresShell, michael@0: nsStyleContext* aContext, michael@0: nsFrameState aTypeBit); michael@0: nsPlaceholderFrame(nsStyleContext* aContext, nsFrameState aTypeBit) michael@0: : nsFrame(aContext) michael@0: { michael@0: NS_PRECONDITION(aTypeBit == PLACEHOLDER_FOR_FLOAT || michael@0: aTypeBit == PLACEHOLDER_FOR_ABSPOS || michael@0: aTypeBit == PLACEHOLDER_FOR_FIXEDPOS || michael@0: aTypeBit == PLACEHOLDER_FOR_POPUP, michael@0: "Unexpected type bit"); michael@0: AddStateBits(aTypeBit); michael@0: } michael@0: michael@0: // Get/Set the associated out of flow frame michael@0: nsIFrame* GetOutOfFlowFrame() const { return mOutOfFlowFrame; } michael@0: void SetOutOfFlowFrame(nsIFrame* aFrame) { michael@0: NS_ASSERTION(!aFrame || !aFrame->GetPrevContinuation(), michael@0: "OOF must be first continuation"); michael@0: mOutOfFlowFrame = aFrame; michael@0: } michael@0: michael@0: // nsIFrame overrides michael@0: // We need to override GetMinSize and GetPrefSize because XUL uses michael@0: // placeholders not within lines. michael@0: virtual void AddInlineMinWidth(nsRenderingContext* aRenderingContext, michael@0: InlineMinWidthData* aData) MOZ_OVERRIDE; michael@0: virtual void AddInlinePrefWidth(nsRenderingContext* aRenderingContext, michael@0: InlinePrefWidthData* aData) MOZ_OVERRIDE; michael@0: virtual nsSize GetMinSize(nsBoxLayoutState& aBoxLayoutState) MOZ_OVERRIDE; michael@0: virtual nsSize GetPrefSize(nsBoxLayoutState& aBoxLayoutState) MOZ_OVERRIDE; michael@0: virtual nsSize GetMaxSize(nsBoxLayoutState& aBoxLayoutState) MOZ_OVERRIDE; michael@0: michael@0: virtual nsresult Reflow(nsPresContext* aPresContext, michael@0: nsHTMLReflowMetrics& aDesiredSize, michael@0: const nsHTMLReflowState& aReflowState, michael@0: nsReflowStatus& aStatus) MOZ_OVERRIDE; michael@0: michael@0: virtual void DestroyFrom(nsIFrame* aDestructRoot) MOZ_OVERRIDE; michael@0: michael@0: #if defined(DEBUG) || (defined(MOZ_REFLOW_PERF_DSP) && defined(MOZ_REFLOW_PERF)) michael@0: virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder, michael@0: const nsRect& aDirtyRect, michael@0: const nsDisplayListSet& aLists) MOZ_OVERRIDE; michael@0: #endif // DEBUG || (MOZ_REFLOW_PERF_DSP && MOZ_REFLOW_PERF) michael@0: michael@0: #ifdef DEBUG_FRAME_DUMP michael@0: void List(FILE* out = stderr, const char* aPrefix = "", uint32_t aFlags = 0) const MOZ_OVERRIDE; michael@0: virtual nsresult GetFrameName(nsAString& aResult) const MOZ_OVERRIDE; michael@0: #endif // DEBUG michael@0: michael@0: /** michael@0: * Get the "type" of the frame michael@0: * michael@0: * @see nsGkAtoms::placeholderFrame michael@0: */ michael@0: virtual nsIAtom* GetType() const MOZ_OVERRIDE; michael@0: michael@0: virtual bool IsEmpty() MOZ_OVERRIDE { return true; } michael@0: virtual bool IsSelfEmpty() MOZ_OVERRIDE { return true; } michael@0: michael@0: virtual bool CanContinueTextRun() const MOZ_OVERRIDE; michael@0: michael@0: #ifdef ACCESSIBILITY michael@0: virtual mozilla::a11y::AccType AccessibleType() MOZ_OVERRIDE michael@0: { michael@0: nsIFrame* realFrame = GetRealFrameForPlaceholder(this); michael@0: return realFrame ? realFrame->AccessibleType() : michael@0: nsFrame::AccessibleType(); michael@0: } michael@0: #endif michael@0: michael@0: virtual nsIFrame* GetParentStyleContextFrame() const MOZ_OVERRIDE; michael@0: michael@0: /** michael@0: * @return the out-of-flow for aFrame if aFrame is a placeholder; otherwise michael@0: * aFrame michael@0: */ michael@0: static nsIFrame* GetRealFrameFor(nsIFrame* aFrame) { michael@0: NS_PRECONDITION(aFrame, "Must have a frame to work with"); michael@0: if (aFrame->GetType() == nsGkAtoms::placeholderFrame) { michael@0: return GetRealFrameForPlaceholder(aFrame); michael@0: } michael@0: return aFrame; michael@0: } michael@0: michael@0: /** michael@0: * @return the out-of-flow for aFrame, which is known to be a placeholder michael@0: */ michael@0: static nsIFrame* GetRealFrameForPlaceholder(nsIFrame* aFrame) { michael@0: NS_PRECONDITION(aFrame->GetType() == nsGkAtoms::placeholderFrame, michael@0: "Must have placeholder frame as input"); michael@0: nsIFrame* outOfFlow = michael@0: static_cast(aFrame)->GetOutOfFlowFrame(); michael@0: NS_ASSERTION(outOfFlow, "Null out-of-flow for placeholder?"); michael@0: return outOfFlow; michael@0: } michael@0: michael@0: protected: michael@0: nsIFrame* mOutOfFlowFrame; michael@0: }; michael@0: michael@0: #endif /* nsPlaceholderFrame_h___ */