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