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