1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Mats Palmgren <matspal@gmail.com>
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either of the GNU General Public License Version 2 or later (the "GPL"),
27 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 : * in which case the provisions of the GPL or the LGPL are applicable instead
29 : * of those above. If you wish to allow use of your version of this file only
30 : * under the terms of either the GPL or the LGPL, and not to allow others to
31 : * use your version of this file under the terms of the MPL, indicate your
32 : * decision by deleting the provisions above and replace them with the notice
33 : * and other provisions required by the GPL or the LGPL. If you do not delete
34 : * the provisions above, a recipient may use your version of this file under
35 : * the terms of any one of the MPL, the GPL or the LGPL.
36 : *
37 : * ***** END LICENSE BLOCK ***** */
38 :
39 : /*
40 : * rendering object for the point that anchors out-of-flow rendering
41 : * objects such as floats and absolutely positioned elements
42 : */
43 :
44 : #include "nsLayoutUtils.h"
45 : #include "nsPlaceholderFrame.h"
46 : #include "nsLineLayout.h"
47 : #include "nsIContent.h"
48 : #include "nsPresContext.h"
49 : #include "nsRenderingContext.h"
50 : #include "nsGkAtoms.h"
51 : #include "nsFrameManager.h"
52 : #include "nsDisplayList.h"
53 :
54 : nsIFrame*
55 0 : NS_NewPlaceholderFrame(nsIPresShell* aPresShell, nsStyleContext* aContext,
56 : nsFrameState aTypeBit)
57 : {
58 0 : return new (aPresShell) nsPlaceholderFrame(aContext, aTypeBit);
59 : }
60 :
61 0 : NS_IMPL_FRAMEARENA_HELPERS(nsPlaceholderFrame)
62 :
63 0 : nsPlaceholderFrame::~nsPlaceholderFrame()
64 : {
65 0 : }
66 :
67 : /* virtual */ nscoord
68 0 : nsPlaceholderFrame::GetMinWidth(nsRenderingContext *aRenderingContext)
69 : {
70 0 : nscoord result = 0;
71 0 : DISPLAY_MIN_WIDTH(this, result);
72 0 : return result;
73 : }
74 :
75 : /* virtual */ nscoord
76 0 : nsPlaceholderFrame::GetPrefWidth(nsRenderingContext *aRenderingContext)
77 : {
78 0 : nscoord result = 0;
79 0 : DISPLAY_PREF_WIDTH(this, result);
80 0 : return result;
81 : }
82 :
83 : /* virtual */ nsSize
84 0 : nsPlaceholderFrame::GetMinSize(nsBoxLayoutState& aBoxLayoutState)
85 : {
86 0 : nsSize size(0, 0);
87 0 : DISPLAY_MIN_SIZE(this, size);
88 : return size;
89 : }
90 :
91 : /* virtual */ nsSize
92 0 : nsPlaceholderFrame::GetPrefSize(nsBoxLayoutState& aBoxLayoutState)
93 : {
94 0 : nsSize size(0, 0);
95 0 : DISPLAY_PREF_SIZE(this, size);
96 : return size;
97 : }
98 :
99 : /* virtual */ nsSize
100 0 : nsPlaceholderFrame::GetMaxSize(nsBoxLayoutState& aBoxLayoutState)
101 : {
102 0 : nsSize size(NS_INTRINSICSIZE, NS_INTRINSICSIZE);
103 0 : DISPLAY_MAX_SIZE(this, size);
104 : return size;
105 : }
106 :
107 : /* virtual */ void
108 0 : nsPlaceholderFrame::AddInlineMinWidth(nsRenderingContext *aRenderingContext,
109 : nsIFrame::InlineMinWidthData *aData)
110 : {
111 : // Override AddInlineMinWith so that *nothing* happens. In
112 : // particular, we don't want to zero out |aData->trailingWhitespace|,
113 : // since nsLineLayout skips placeholders when trimming trailing
114 : // whitespace, and we don't want to set aData->skipWhitespace to
115 : // false.
116 :
117 : // ...but push floats onto the list
118 0 : if (mOutOfFlowFrame->GetStyleDisplay()->mFloats != NS_STYLE_FLOAT_NONE)
119 0 : aData->floats.AppendElement(mOutOfFlowFrame);
120 0 : }
121 :
122 : /* virtual */ void
123 0 : nsPlaceholderFrame::AddInlinePrefWidth(nsRenderingContext *aRenderingContext,
124 : nsIFrame::InlinePrefWidthData *aData)
125 : {
126 : // Override AddInlinePrefWith so that *nothing* happens. In
127 : // particular, we don't want to zero out |aData->trailingWhitespace|,
128 : // since nsLineLayout skips placeholders when trimming trailing
129 : // whitespace, and we don't want to set aData->skipWhitespace to
130 : // false.
131 :
132 : // ...but push floats onto the list
133 0 : if (mOutOfFlowFrame->GetStyleDisplay()->mFloats != NS_STYLE_FLOAT_NONE)
134 0 : aData->floats.AppendElement(mOutOfFlowFrame);
135 0 : }
136 :
137 : NS_IMETHODIMP
138 0 : nsPlaceholderFrame::Reflow(nsPresContext* aPresContext,
139 : nsHTMLReflowMetrics& aDesiredSize,
140 : const nsHTMLReflowState& aReflowState,
141 : nsReflowStatus& aStatus)
142 : {
143 0 : DO_GLOBAL_REFLOW_COUNT("nsPlaceholderFrame");
144 0 : DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
145 0 : aDesiredSize.width = 0;
146 0 : aDesiredSize.height = 0;
147 :
148 0 : aStatus = NS_FRAME_COMPLETE;
149 0 : NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
150 0 : return NS_OK;
151 : }
152 :
153 : void
154 0 : nsPlaceholderFrame::DestroyFrom(nsIFrame* aDestructRoot)
155 : {
156 0 : nsIPresShell* shell = PresContext()->GetPresShell();
157 0 : nsIFrame* oof = mOutOfFlowFrame;
158 0 : if (oof) {
159 : // Unregister out-of-flow frame
160 0 : shell->FrameManager()->UnregisterPlaceholderFrame(this);
161 0 : mOutOfFlowFrame = nsnull;
162 : // If aDestructRoot is not an ancestor of the out-of-flow frame,
163 : // then call RemoveFrame on it here.
164 : // Also destroy it here if it's a popup frame. (Bug 96291)
165 0 : if (shell->FrameManager() &&
166 0 : ((GetStateBits() & PLACEHOLDER_FOR_POPUP) ||
167 0 : !nsLayoutUtils::IsProperAncestorFrame(aDestructRoot, oof))) {
168 0 : ChildListID listId = nsLayoutUtils::GetChildListNameFor(oof);
169 0 : shell->FrameManager()->RemoveFrame(listId, oof);
170 : }
171 : // else oof will be destroyed by its parent
172 : }
173 :
174 0 : nsFrame::DestroyFrom(aDestructRoot);
175 0 : }
176 :
177 : nsIAtom*
178 0 : nsPlaceholderFrame::GetType() const
179 : {
180 0 : return nsGkAtoms::placeholderFrame;
181 : }
182 :
183 : /* virtual */ bool
184 0 : nsPlaceholderFrame::CanContinueTextRun() const
185 : {
186 0 : if (!mOutOfFlowFrame) {
187 0 : return false;
188 : }
189 : // first-letter frames can continue text runs, and placeholders for floated
190 : // first-letter frames can too
191 0 : return mOutOfFlowFrame->CanContinueTextRun();
192 : }
193 :
194 : nsIFrame*
195 0 : nsPlaceholderFrame::GetParentStyleContextFrame() const
196 : {
197 0 : NS_PRECONDITION(GetParent(), "How can we not have a parent here?");
198 :
199 : // Lie about our pseudo so we can step out of all anon boxes and
200 : // pseudo-elements. The other option would be to reimplement the
201 : // {ib} split gunk here.
202 0 : return CorrectStyleParentFrame(GetParent(), nsGkAtoms::placeholderFrame);
203 : }
204 :
205 :
206 : #ifdef DEBUG
207 : static void
208 0 : PaintDebugPlaceholder(nsIFrame* aFrame, nsRenderingContext* aCtx,
209 : const nsRect& aDirtyRect, nsPoint aPt)
210 : {
211 0 : aCtx->SetColor(NS_RGB(0, 255, 255));
212 0 : nscoord x = nsPresContext::CSSPixelsToAppUnits(-5);
213 : aCtx->FillRect(aPt.x + x, aPt.y,
214 0 : nsPresContext::CSSPixelsToAppUnits(13), nsPresContext::CSSPixelsToAppUnits(3));
215 0 : nscoord y = nsPresContext::CSSPixelsToAppUnits(-10);
216 : aCtx->FillRect(aPt.x, aPt.y + y,
217 0 : nsPresContext::CSSPixelsToAppUnits(3), nsPresContext::CSSPixelsToAppUnits(10));
218 0 : }
219 : #endif // DEBUG
220 :
221 : #if defined(DEBUG) || (defined(MOZ_REFLOW_PERF_DSP) && defined(MOZ_REFLOW_PERF))
222 :
223 : NS_IMETHODIMP
224 0 : nsPlaceholderFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
225 : const nsRect& aDirtyRect,
226 : const nsDisplayListSet& aLists)
227 : {
228 0 : DO_GLOBAL_REFLOW_COUNT_DSP("nsPlaceholderFrame");
229 :
230 : #ifdef DEBUG
231 0 : if (!GetShowFrameBorders())
232 0 : return NS_OK;
233 :
234 : return aLists.Outlines()->AppendNewToTop(new (aBuilder)
235 : nsDisplayGeneric(aBuilder, this, PaintDebugPlaceholder, "DebugPlaceholder",
236 0 : nsDisplayItem::TYPE_DEBUG_PLACEHOLDER));
237 : #else // DEBUG
238 : return NS_OK;
239 : #endif // DEBUG
240 : }
241 : #endif // DEBUG || (MOZ_REFLOW_PERF_DSP && MOZ_REFLOW_PERF)
242 :
243 : #ifdef DEBUG
244 : NS_IMETHODIMP
245 0 : nsPlaceholderFrame::GetFrameName(nsAString& aResult) const
246 : {
247 0 : return MakeFrameName(NS_LITERAL_STRING("Placeholder"), aResult);
248 : }
249 :
250 : NS_IMETHODIMP
251 0 : nsPlaceholderFrame::List(FILE* out, PRInt32 aIndent) const
252 : {
253 0 : IndentBy(out, aIndent);
254 0 : ListTag(out);
255 : #ifdef DEBUG_waterson
256 : fprintf(out, " [parent=%p]", static_cast<void*>(mParent));
257 : #endif
258 0 : if (HasView()) {
259 0 : fprintf(out, " [view=%p]", (void*)GetView());
260 : }
261 0 : fprintf(out, " {%d,%d,%d,%d}", mRect.x, mRect.y, mRect.width, mRect.height);
262 0 : if (0 != mState) {
263 0 : fprintf(out, " [state=%016llx]", (unsigned long long)mState);
264 : }
265 0 : nsIFrame* prevInFlow = GetPrevInFlow();
266 0 : nsIFrame* nextInFlow = GetNextInFlow();
267 0 : if (nsnull != prevInFlow) {
268 0 : fprintf(out, " prev-in-flow=%p", static_cast<void*>(prevInFlow));
269 : }
270 0 : if (nsnull != nextInFlow) {
271 0 : fprintf(out, " next-in-flow=%p", static_cast<void*>(nextInFlow));
272 : }
273 0 : if (nsnull != mContent) {
274 0 : fprintf(out, " [content=%p]", static_cast<void*>(mContent));
275 : }
276 0 : if (nsnull != mStyleContext) {
277 0 : fprintf(out, " [sc=%p]", static_cast<void*>(mStyleContext));
278 : }
279 0 : if (mOutOfFlowFrame) {
280 0 : fprintf(out, " outOfFlowFrame=");
281 0 : nsFrame::ListTag(out, mOutOfFlowFrame);
282 : }
283 0 : fputs("\n", out);
284 0 : return NS_OK;
285 : }
286 : #endif
|