/src/mozilla-central/layout/xul/nsLeafBoxFrame.cpp
Line | Count | Source (jump to first uncovered line) |
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 | | // Eric Vaughan |
9 | | // Netscape Communications |
10 | | // |
11 | | // See documentation in associated header file |
12 | | // |
13 | | |
14 | | #include "nsLeafBoxFrame.h" |
15 | | #include "nsBoxFrame.h" |
16 | | #include "nsCOMPtr.h" |
17 | | #include "nsGkAtoms.h" |
18 | | #include "nsPresContext.h" |
19 | | #include "mozilla/ComputedStyle.h" |
20 | | #include "nsIContent.h" |
21 | | #include "nsNameSpaceManager.h" |
22 | | #include "nsBoxLayoutState.h" |
23 | | #include "nsWidgetsCID.h" |
24 | | #include "nsViewManager.h" |
25 | | #include "nsContainerFrame.h" |
26 | | #include "nsDisplayList.h" |
27 | | #include <algorithm> |
28 | | |
29 | | using namespace mozilla; |
30 | | |
31 | | // |
32 | | // NS_NewLeafBoxFrame |
33 | | // |
34 | | // Creates a new Toolbar frame and returns it |
35 | | // |
36 | | nsIFrame* |
37 | | NS_NewLeafBoxFrame (nsIPresShell* aPresShell, ComputedStyle* aStyle) |
38 | 0 | { |
39 | 0 | return new (aPresShell) nsLeafBoxFrame(aStyle); |
40 | 0 | } |
41 | | |
42 | | NS_IMPL_FRAMEARENA_HELPERS(nsLeafBoxFrame) |
43 | | |
44 | | /** |
45 | | * Initialize us. This is a good time to get the alignment of the box |
46 | | */ |
47 | | void |
48 | | nsLeafBoxFrame::Init(nsIContent* aContent, |
49 | | nsContainerFrame* aParent, |
50 | | nsIFrame* aPrevInFlow) |
51 | 0 | { |
52 | 0 | nsLeafFrame::Init(aContent, aParent, aPrevInFlow); |
53 | 0 |
|
54 | 0 | if (GetStateBits() & NS_FRAME_FONT_INFLATION_CONTAINER) { |
55 | 0 | AddStateBits(NS_FRAME_FONT_INFLATION_FLOW_ROOT); |
56 | 0 | } |
57 | 0 |
|
58 | 0 | UpdateMouseThrough(); |
59 | 0 | } |
60 | | |
61 | | nsresult |
62 | | nsLeafBoxFrame::AttributeChanged(int32_t aNameSpaceID, |
63 | | nsAtom* aAttribute, |
64 | | int32_t aModType) |
65 | 0 | { |
66 | 0 | nsresult rv = nsLeafFrame::AttributeChanged(aNameSpaceID, aAttribute, |
67 | 0 | aModType); |
68 | 0 |
|
69 | 0 | if (aAttribute == nsGkAtoms::mousethrough) |
70 | 0 | UpdateMouseThrough(); |
71 | 0 |
|
72 | 0 | return rv; |
73 | 0 | } |
74 | | |
75 | | void nsLeafBoxFrame::UpdateMouseThrough() |
76 | | { |
77 | | static Element::AttrValuesArray strings[] = |
78 | | {&nsGkAtoms::never, &nsGkAtoms::always, nullptr}; |
79 | | switch (mContent->AsElement()->FindAttrValueIn(kNameSpaceID_None, |
80 | | nsGkAtoms::mousethrough, |
81 | | strings, eCaseMatters)) { |
82 | | case 0: AddStateBits(NS_FRAME_MOUSE_THROUGH_NEVER); break; |
83 | | case 1: AddStateBits(NS_FRAME_MOUSE_THROUGH_ALWAYS); break; |
84 | | case 2: { |
85 | | RemoveStateBits(NS_FRAME_MOUSE_THROUGH_ALWAYS); |
86 | | RemoveStateBits(NS_FRAME_MOUSE_THROUGH_NEVER); |
87 | | break; |
88 | | } |
89 | | } |
90 | | } |
91 | | |
92 | | void |
93 | | nsLeafBoxFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, |
94 | | const nsDisplayListSet& aLists) |
95 | 0 | { |
96 | 0 | // REVIEW: GetFrameForPoint used to not report events for the background |
97 | 0 | // layer, whereas this code will put an event receiver for this frame in the |
98 | 0 | // BlockBorderBackground() list. But I don't see any need to preserve |
99 | 0 | // that anomalous behaviour. The important thing I'm preserving is that |
100 | 0 | // leaf boxes continue to receive events in the foreground layer. |
101 | 0 | DisplayBorderBackgroundOutline(aBuilder, aLists); |
102 | 0 |
|
103 | 0 | if (!aBuilder->IsForEventDelivery() || !IsVisibleForPainting(aBuilder)) |
104 | 0 | return; |
105 | 0 | |
106 | 0 | aLists.Content()->AppendToTop( |
107 | 0 | MakeDisplayItem<nsDisplayEventReceiver>(aBuilder, this)); |
108 | 0 | } |
109 | | |
110 | | /* virtual */ nscoord |
111 | | nsLeafBoxFrame::GetMinISize(gfxContext *aRenderingContext) |
112 | 0 | { |
113 | 0 | nscoord result; |
114 | 0 | DISPLAY_MIN_INLINE_SIZE(this, result); |
115 | 0 | nsBoxLayoutState state(PresContext(), aRenderingContext); |
116 | 0 |
|
117 | 0 | WritingMode wm = GetWritingMode(); |
118 | 0 | LogicalSize minSize(wm, GetXULMinSize(state)); |
119 | 0 |
|
120 | 0 | // GetXULMinSize returns border-box size, and we want to return content |
121 | 0 | // inline-size. Since Reflow uses the reflow state's border and padding, we |
122 | 0 | // actually just want to subtract what GetXULMinSize added, which is the |
123 | 0 | // result of GetXULBorderAndPadding. |
124 | 0 | nsMargin bp; |
125 | 0 | GetXULBorderAndPadding(bp); |
126 | 0 |
|
127 | 0 | result = minSize.ISize(wm) - LogicalMargin(wm, bp).IStartEnd(wm); |
128 | 0 |
|
129 | 0 | return result; |
130 | 0 | } |
131 | | |
132 | | /* virtual */ nscoord |
133 | | nsLeafBoxFrame::GetPrefISize(gfxContext *aRenderingContext) |
134 | 0 | { |
135 | 0 | nscoord result; |
136 | 0 | DISPLAY_PREF_INLINE_SIZE(this, result); |
137 | 0 | nsBoxLayoutState state(PresContext(), aRenderingContext); |
138 | 0 |
|
139 | 0 | WritingMode wm = GetWritingMode(); |
140 | 0 | LogicalSize prefSize(wm, GetXULPrefSize(state)); |
141 | 0 |
|
142 | 0 | // GetXULPrefSize returns border-box size, and we want to return content |
143 | 0 | // inline-size. Since Reflow uses the reflow state's border and padding, we |
144 | 0 | // actually just want to subtract what GetXULPrefSize added, which is the |
145 | 0 | // result of GetXULBorderAndPadding. |
146 | 0 | nsMargin bp; |
147 | 0 | GetXULBorderAndPadding(bp); |
148 | 0 |
|
149 | 0 | result = prefSize.ISize(wm) - LogicalMargin(wm, bp).IStartEnd(wm); |
150 | 0 |
|
151 | 0 | return result; |
152 | 0 | } |
153 | | |
154 | | nscoord |
155 | | nsLeafBoxFrame::GetIntrinsicISize() |
156 | 0 | { |
157 | 0 | // No intrinsic width |
158 | 0 | return 0; |
159 | 0 | } |
160 | | |
161 | | LogicalSize |
162 | | nsLeafBoxFrame::ComputeAutoSize(gfxContext* aRenderingContext, |
163 | | WritingMode aWM, |
164 | | const LogicalSize& aCBSize, |
165 | | nscoord aAvailableISize, |
166 | | const LogicalSize& aMargin, |
167 | | const LogicalSize& aBorder, |
168 | | const LogicalSize& aPadding, |
169 | | ComputeSizeFlags aFlags) |
170 | 0 | { |
171 | 0 | // Important: NOT calling our direct superclass here! |
172 | 0 | return nsFrame::ComputeAutoSize(aRenderingContext, aWM, |
173 | 0 | aCBSize, aAvailableISize, |
174 | 0 | aMargin, aBorder, aPadding, aFlags); |
175 | 0 | } |
176 | | |
177 | | void |
178 | | nsLeafBoxFrame::Reflow(nsPresContext* aPresContext, |
179 | | ReflowOutput& aDesiredSize, |
180 | | const ReflowInput& aReflowInput, |
181 | | nsReflowStatus& aStatus) |
182 | 0 | { |
183 | 0 | // This is mostly a copy of nsBoxFrame::Reflow(). |
184 | 0 | // We aren't able to share an implementation because of the frame |
185 | 0 | // class hierarchy. If you make changes here, please keep |
186 | 0 | // nsBoxFrame::Reflow in sync. |
187 | 0 |
|
188 | 0 | MarkInReflow(); |
189 | 0 | DO_GLOBAL_REFLOW_COUNT("nsLeafBoxFrame"); |
190 | 0 | DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus); |
191 | 0 | MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!"); |
192 | 0 |
|
193 | 0 | NS_ASSERTION(aReflowInput.ComputedWidth() >=0 && |
194 | 0 | aReflowInput.ComputedHeight() >= 0, "Computed Size < 0"); |
195 | 0 |
|
196 | | #ifdef DO_NOISY_REFLOW |
197 | | printf("\n-------------Starting LeafBoxFrame Reflow ----------------------------\n"); |
198 | | printf("%p ** nsLBF::Reflow %d R: ", this, myCounter++); |
199 | | switch (aReflowInput.reason) { |
200 | | case eReflowReason_Initial: |
201 | | printf("Ini");break; |
202 | | case eReflowReason_Incremental: |
203 | | printf("Inc");break; |
204 | | case eReflowReason_Resize: |
205 | | printf("Rsz");break; |
206 | | case eReflowReason_StyleChange: |
207 | | printf("Sty");break; |
208 | | case eReflowReason_Dirty: |
209 | | printf("Drt "); |
210 | | break; |
211 | | default:printf("<unknown>%d", aReflowInput.reason);break; |
212 | | } |
213 | | |
214 | | printSize("AW", aReflowInput.AvailableWidth()); |
215 | | printSize("AH", aReflowInput.AvailableHeight()); |
216 | | printSize("CW", aReflowInput.ComputedWidth()); |
217 | | printSize("CH", aReflowInput.ComputedHeight()); |
218 | | |
219 | | printf(" *\n"); |
220 | | |
221 | | #endif |
222 | |
|
223 | 0 | // create the layout state |
224 | 0 | nsBoxLayoutState state(aPresContext, aReflowInput.mRenderingContext); |
225 | 0 |
|
226 | 0 | nsSize computedSize(aReflowInput.ComputedWidth(),aReflowInput.ComputedHeight()); |
227 | 0 |
|
228 | 0 | nsMargin m; |
229 | 0 | m = aReflowInput.ComputedPhysicalBorderPadding(); |
230 | 0 |
|
231 | 0 | //GetXULBorderAndPadding(m); |
232 | 0 |
|
233 | 0 | // this happens sometimes. So lets handle it gracefully. |
234 | 0 | if (aReflowInput.ComputedHeight() == 0) { |
235 | 0 | nsSize minSize = GetXULMinSize(state); |
236 | 0 | computedSize.height = minSize.height - m.top - m.bottom; |
237 | 0 | } |
238 | 0 |
|
239 | 0 | nsSize prefSize(0,0); |
240 | 0 |
|
241 | 0 | // if we are told to layout intrinic then get our preferred size. |
242 | 0 | if (computedSize.width == NS_INTRINSICSIZE || computedSize.height == NS_INTRINSICSIZE) { |
243 | 0 | prefSize = GetXULPrefSize(state); |
244 | 0 | nsSize minSize = GetXULMinSize(state); |
245 | 0 | nsSize maxSize = GetXULMaxSize(state); |
246 | 0 | prefSize = BoundsCheck(minSize, prefSize, maxSize); |
247 | 0 | } |
248 | 0 |
|
249 | 0 | // get our desiredSize |
250 | 0 | if (aReflowInput.ComputedWidth() == NS_INTRINSICSIZE) { |
251 | 0 | computedSize.width = prefSize.width; |
252 | 0 | } else { |
253 | 0 | computedSize.width += m.left + m.right; |
254 | 0 | } |
255 | 0 |
|
256 | 0 | if (aReflowInput.ComputedHeight() == NS_INTRINSICSIZE) { |
257 | 0 | computedSize.height = prefSize.height; |
258 | 0 | } else { |
259 | 0 | computedSize.height += m.top + m.bottom; |
260 | 0 | } |
261 | 0 |
|
262 | 0 | // handle reflow state min and max sizes |
263 | 0 | // XXXbz the width handling here seems to be wrong, since |
264 | 0 | // mComputedMin/MaxWidth is a content-box size, whole |
265 | 0 | // computedSize.width is a border-box size... |
266 | 0 | if (computedSize.width > aReflowInput.ComputedMaxWidth()) |
267 | 0 | computedSize.width = aReflowInput.ComputedMaxWidth(); |
268 | 0 |
|
269 | 0 | if (computedSize.width < aReflowInput.ComputedMinWidth()) |
270 | 0 | computedSize.width = aReflowInput.ComputedMinWidth(); |
271 | 0 |
|
272 | 0 | // Now adjust computedSize.height for our min and max computed |
273 | 0 | // height. The only problem is that those are content-box sizes, |
274 | 0 | // while computedSize.height is a border-box size. So subtract off |
275 | 0 | // m.TopBottom() before adjusting, then readd it. |
276 | 0 | computedSize.height = std::max(0, computedSize.height - m.TopBottom()); |
277 | 0 | computedSize.height = NS_CSS_MINMAX(computedSize.height, |
278 | 0 | aReflowInput.ComputedMinHeight(), |
279 | 0 | aReflowInput.ComputedMaxHeight()); |
280 | 0 | computedSize.height += m.TopBottom(); |
281 | 0 |
|
282 | 0 | nsRect r(mRect.x, mRect.y, computedSize.width, computedSize.height); |
283 | 0 |
|
284 | 0 | SetXULBounds(state, r); |
285 | 0 |
|
286 | 0 | // layout our children |
287 | 0 | XULLayout(state); |
288 | 0 |
|
289 | 0 | // ok our child could have gotten bigger. So lets get its bounds |
290 | 0 | aDesiredSize.Width() = mRect.width; |
291 | 0 | aDesiredSize.Height() = mRect.height; |
292 | 0 | aDesiredSize.SetBlockStartAscent(GetXULBoxAscent(state)); |
293 | 0 |
|
294 | 0 | // the overflow rect is set in SetXULBounds() above |
295 | 0 | aDesiredSize.mOverflowAreas = GetOverflowAreas(); |
296 | 0 |
|
297 | | #ifdef DO_NOISY_REFLOW |
298 | | { |
299 | | printf("%p ** nsLBF(done) W:%d H:%d ", this, aDesiredSize.Width(), aDesiredSize.Height()); |
300 | | |
301 | | if (maxElementWidth) { |
302 | | printf("MW:%d\n", *maxElementWidth); |
303 | | } else { |
304 | | printf("MW:?\n"); |
305 | | } |
306 | | |
307 | | } |
308 | | #endif |
309 | | } |
310 | | |
311 | | #ifdef DEBUG_FRAME_DUMP |
312 | | nsresult |
313 | | nsLeafBoxFrame::GetFrameName(nsAString& aResult) const |
314 | | { |
315 | | return MakeFrameName(NS_LITERAL_STRING("LeafBox"), aResult); |
316 | | } |
317 | | #endif |
318 | | |
319 | | nsresult |
320 | | nsLeafBoxFrame::CharacterDataChanged(const CharacterDataChangeInfo& aInfo) |
321 | 0 | { |
322 | 0 | MarkIntrinsicISizesDirty(); |
323 | 0 | return nsLeafFrame::CharacterDataChanged(aInfo); |
324 | 0 | } |
325 | | |
326 | | /* virtual */ nsSize |
327 | | nsLeafBoxFrame::GetXULPrefSize(nsBoxLayoutState& aState) |
328 | 0 | { |
329 | 0 | return nsBox::GetXULPrefSize(aState); |
330 | 0 | } |
331 | | |
332 | | /* virtual */ nsSize |
333 | | nsLeafBoxFrame::GetXULMinSize(nsBoxLayoutState& aState) |
334 | 0 | { |
335 | 0 | return nsBox::GetXULMinSize(aState); |
336 | 0 | } |
337 | | |
338 | | /* virtual */ nsSize |
339 | | nsLeafBoxFrame::GetXULMaxSize(nsBoxLayoutState& aState) |
340 | 0 | { |
341 | 0 | return nsBox::GetXULMaxSize(aState); |
342 | 0 | } |
343 | | |
344 | | /* virtual */ nscoord |
345 | | nsLeafBoxFrame::GetXULFlex() |
346 | 0 | { |
347 | 0 | return nsBox::GetXULFlex(); |
348 | 0 | } |
349 | | |
350 | | /* virtual */ nscoord |
351 | | nsLeafBoxFrame::GetXULBoxAscent(nsBoxLayoutState& aState) |
352 | 0 | { |
353 | 0 | return nsBox::GetXULBoxAscent(aState); |
354 | 0 | } |
355 | | |
356 | | /* virtual */ void |
357 | | nsLeafBoxFrame::MarkIntrinsicISizesDirty() |
358 | 0 | { |
359 | 0 | // Don't call base class method, since everything it does is within an |
360 | 0 | // IsXULBoxWrapped check. |
361 | 0 | } |
362 | | |
363 | | NS_IMETHODIMP |
364 | | nsLeafBoxFrame::DoXULLayout(nsBoxLayoutState& aState) |
365 | 0 | { |
366 | 0 | return nsBox::DoXULLayout(aState); |
367 | 0 | } |