1 : /* -*- Mode: C++; tab-width: 8; 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 Communicator client 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 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either of the GNU General Public License Version 2 or later (the "GPL"),
26 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : //
39 : // Eric Vaughan
40 : // Netscape Communications
41 : //
42 : // See documentation in associated header file
43 : //
44 :
45 : #include "nsLeafBoxFrame.h"
46 : #include "nsBoxFrame.h"
47 : #include "nsCOMPtr.h"
48 : #include "nsGkAtoms.h"
49 : #include "nsPresContext.h"
50 : #include "nsStyleContext.h"
51 : #include "nsIContent.h"
52 : #include "nsINameSpaceManager.h"
53 : #include "nsBoxLayoutState.h"
54 : #include "nsWidgetsCID.h"
55 : #include "nsIViewManager.h"
56 : #include "nsContainerFrame.h"
57 : #include "nsDisplayList.h"
58 :
59 : //
60 : // NS_NewLeafBoxFrame
61 : //
62 : // Creates a new Toolbar frame and returns it
63 : //
64 : nsIFrame*
65 0 : NS_NewLeafBoxFrame (nsIPresShell* aPresShell, nsStyleContext* aContext)
66 : {
67 0 : return new (aPresShell) nsLeafBoxFrame(aPresShell, aContext);
68 : }
69 :
70 0 : NS_IMPL_FRAMEARENA_HELPERS(nsLeafBoxFrame)
71 :
72 0 : nsLeafBoxFrame::nsLeafBoxFrame(nsIPresShell* aShell, nsStyleContext* aContext)
73 0 : : nsLeafFrame(aContext)
74 : {
75 0 : }
76 :
77 : #ifdef DEBUG_LAYOUT
78 : void
79 : nsLeafBoxFrame::GetBoxName(nsAutoString& aName)
80 : {
81 : GetFrameName(aName);
82 : }
83 : #endif
84 :
85 :
86 : /**
87 : * Initialize us. This is a good time to get the alignment of the box
88 : */
89 : NS_IMETHODIMP
90 0 : nsLeafBoxFrame::Init(
91 : nsIContent* aContent,
92 : nsIFrame* aParent,
93 : nsIFrame* aPrevInFlow)
94 : {
95 0 : nsresult rv = nsLeafFrame::Init(aContent, aParent, aPrevInFlow);
96 0 : NS_ENSURE_SUCCESS(rv, rv);
97 :
98 0 : UpdateMouseThrough();
99 :
100 0 : return rv;
101 : }
102 :
103 : NS_IMETHODIMP
104 0 : nsLeafBoxFrame::AttributeChanged(PRInt32 aNameSpaceID,
105 : nsIAtom* aAttribute,
106 : PRInt32 aModType)
107 : {
108 : nsresult rv = nsLeafFrame::AttributeChanged(aNameSpaceID, aAttribute,
109 0 : aModType);
110 :
111 0 : if (aAttribute == nsGkAtoms::mousethrough)
112 0 : UpdateMouseThrough();
113 :
114 0 : return rv;
115 : }
116 :
117 0 : void nsLeafBoxFrame::UpdateMouseThrough()
118 : {
119 0 : if (mContent) {
120 : static nsIContent::AttrValuesArray strings[] =
121 : {&nsGkAtoms::never, &nsGkAtoms::always, nsnull};
122 0 : switch (mContent->FindAttrValueIn(kNameSpaceID_None,
123 : nsGkAtoms::mousethrough,
124 0 : strings, eCaseMatters)) {
125 0 : case 0: AddStateBits(NS_FRAME_MOUSE_THROUGH_NEVER); break;
126 0 : case 1: AddStateBits(NS_FRAME_MOUSE_THROUGH_ALWAYS); break;
127 : case 2: {
128 0 : RemoveStateBits(NS_FRAME_MOUSE_THROUGH_ALWAYS);
129 0 : RemoveStateBits(NS_FRAME_MOUSE_THROUGH_NEVER);
130 0 : break;
131 : }
132 : }
133 : }
134 0 : }
135 :
136 : NS_IMETHODIMP
137 0 : nsLeafBoxFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
138 : const nsRect& aDirtyRect,
139 : const nsDisplayListSet& aLists)
140 : {
141 : // REVIEW: GetFrameForPoint used to not report events for the background
142 : // layer, whereas this code will put an event receiver for this frame in the
143 : // BlockBorderBackground() list. But I don't see any need to preserve
144 : // that anomalous behaviour. The important thing I'm preserving is that
145 : // leaf boxes continue to receive events in the foreground layer.
146 0 : nsresult rv = DisplayBorderBackgroundOutline(aBuilder, aLists);
147 0 : NS_ENSURE_SUCCESS(rv, rv);
148 :
149 0 : if (!aBuilder->IsForEventDelivery() || !IsVisibleForPainting(aBuilder))
150 0 : return NS_OK;
151 :
152 : return aLists.Content()->AppendNewToTop(new (aBuilder)
153 0 : nsDisplayEventReceiver(aBuilder, this));
154 : }
155 :
156 : /* virtual */ nscoord
157 0 : nsLeafBoxFrame::GetMinWidth(nsRenderingContext *aRenderingContext)
158 : {
159 : nscoord result;
160 0 : DISPLAY_MIN_WIDTH(this, result);
161 0 : nsBoxLayoutState state(PresContext(), aRenderingContext);
162 0 : nsSize minSize = GetMinSize(state);
163 :
164 : // GetMinSize returns border-box width, and we want to return content
165 : // width. Since Reflow uses the reflow state's border and padding, we
166 : // actually just want to subtract what GetMinSize added, which is the
167 : // result of GetBorderAndPadding.
168 0 : nsMargin bp;
169 0 : GetBorderAndPadding(bp);
170 :
171 0 : result = minSize.width - bp.LeftRight();
172 :
173 0 : return result;
174 : }
175 :
176 : /* virtual */ nscoord
177 0 : nsLeafBoxFrame::GetPrefWidth(nsRenderingContext *aRenderingContext)
178 : {
179 : nscoord result;
180 0 : DISPLAY_PREF_WIDTH(this, result);
181 0 : nsBoxLayoutState state(PresContext(), aRenderingContext);
182 0 : nsSize prefSize = GetPrefSize(state);
183 :
184 : // GetPrefSize returns border-box width, and we want to return content
185 : // width. Since Reflow uses the reflow state's border and padding, we
186 : // actually just want to subtract what GetPrefSize added, which is the
187 : // result of GetBorderAndPadding.
188 0 : nsMargin bp;
189 0 : GetBorderAndPadding(bp);
190 :
191 0 : result = prefSize.width - bp.LeftRight();
192 :
193 0 : return result;
194 : }
195 :
196 : nscoord
197 0 : nsLeafBoxFrame::GetIntrinsicWidth()
198 : {
199 : // No intrinsic width
200 0 : return 0;
201 : }
202 :
203 : nsSize
204 0 : nsLeafBoxFrame::ComputeAutoSize(nsRenderingContext *aRenderingContext,
205 : nsSize aCBSize, nscoord aAvailableWidth,
206 : nsSize aMargin, nsSize aBorder,
207 : nsSize aPadding, bool aShrinkWrap)
208 : {
209 : // Important: NOT calling our direct superclass here!
210 : return nsFrame::ComputeAutoSize(aRenderingContext, aCBSize, aAvailableWidth,
211 0 : aMargin, aBorder, aPadding, aShrinkWrap);
212 : }
213 :
214 : NS_IMETHODIMP
215 0 : nsLeafBoxFrame::Reflow(nsPresContext* aPresContext,
216 : nsHTMLReflowMetrics& aDesiredSize,
217 : const nsHTMLReflowState& aReflowState,
218 : nsReflowStatus& aStatus)
219 : {
220 : // This is mostly a copy of nsBoxFrame::Reflow().
221 : // We aren't able to share an implementation because of the frame
222 : // class hierarchy. If you make changes here, please keep
223 : // nsBoxFrame::Reflow in sync.
224 :
225 0 : DO_GLOBAL_REFLOW_COUNT("nsLeafBoxFrame");
226 0 : DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
227 :
228 0 : NS_ASSERTION(aReflowState.ComputedWidth() >=0 &&
229 : aReflowState.ComputedHeight() >= 0, "Computed Size < 0");
230 :
231 : #ifdef DO_NOISY_REFLOW
232 : printf("\n-------------Starting LeafBoxFrame Reflow ----------------------------\n");
233 : printf("%p ** nsLBF::Reflow %d R: ", this, myCounter++);
234 : switch (aReflowState.reason) {
235 : case eReflowReason_Initial:
236 : printf("Ini");break;
237 : case eReflowReason_Incremental:
238 : printf("Inc");break;
239 : case eReflowReason_Resize:
240 : printf("Rsz");break;
241 : case eReflowReason_StyleChange:
242 : printf("Sty");break;
243 : case eReflowReason_Dirty:
244 : printf("Drt ");
245 : break;
246 : default:printf("<unknown>%d", aReflowState.reason);break;
247 : }
248 :
249 : printSize("AW", aReflowState.availableWidth);
250 : printSize("AH", aReflowState.availableHeight);
251 : printSize("CW", aReflowState.ComputedWidth());
252 : printSize("CH", aReflowState.ComputedHeight());
253 :
254 : printf(" *\n");
255 :
256 : #endif
257 :
258 0 : aStatus = NS_FRAME_COMPLETE;
259 :
260 : // create the layout state
261 0 : nsBoxLayoutState state(aPresContext, aReflowState.rendContext);
262 :
263 0 : nsSize computedSize(aReflowState.ComputedWidth(),aReflowState.ComputedHeight());
264 :
265 0 : nsMargin m;
266 0 : m = aReflowState.mComputedBorderPadding;
267 :
268 : //GetBorderAndPadding(m);
269 :
270 : // this happens sometimes. So lets handle it gracefully.
271 0 : if (aReflowState.ComputedHeight() == 0) {
272 0 : nsSize minSize = GetMinSize(state);
273 0 : computedSize.height = minSize.height - m.top - m.bottom;
274 : }
275 :
276 0 : nsSize prefSize(0,0);
277 :
278 : // if we are told to layout intrinic then get our preferred size.
279 0 : if (computedSize.width == NS_INTRINSICSIZE || computedSize.height == NS_INTRINSICSIZE) {
280 0 : prefSize = GetPrefSize(state);
281 0 : nsSize minSize = GetMinSize(state);
282 0 : nsSize maxSize = GetMaxSize(state);
283 0 : prefSize = BoundsCheck(minSize, prefSize, maxSize);
284 : }
285 :
286 : // get our desiredSize
287 0 : if (aReflowState.ComputedWidth() == NS_INTRINSICSIZE) {
288 0 : computedSize.width = prefSize.width;
289 : } else {
290 0 : computedSize.width += m.left + m.right;
291 : }
292 :
293 0 : if (aReflowState.ComputedHeight() == NS_INTRINSICSIZE) {
294 0 : computedSize.height = prefSize.height;
295 : } else {
296 0 : computedSize.height += m.top + m.bottom;
297 : }
298 :
299 : // handle reflow state min and max sizes
300 :
301 0 : if (computedSize.width > aReflowState.mComputedMaxWidth)
302 0 : computedSize.width = aReflowState.mComputedMaxWidth;
303 :
304 0 : if (computedSize.height > aReflowState.mComputedMaxHeight)
305 0 : computedSize.height = aReflowState.mComputedMaxHeight;
306 :
307 0 : if (computedSize.width < aReflowState.mComputedMinWidth)
308 0 : computedSize.width = aReflowState.mComputedMinWidth;
309 :
310 0 : if (computedSize.height < aReflowState.mComputedMinHeight)
311 0 : computedSize.height = aReflowState.mComputedMinHeight;
312 :
313 0 : nsRect r(mRect.x, mRect.y, computedSize.width, computedSize.height);
314 :
315 0 : SetBounds(state, r);
316 :
317 : // layout our children
318 0 : Layout(state);
319 :
320 : // ok our child could have gotten bigger. So lets get its bounds
321 0 : aDesiredSize.width = mRect.width;
322 0 : aDesiredSize.height = mRect.height;
323 0 : aDesiredSize.ascent = GetBoxAscent(state);
324 :
325 : // the overflow rect is set in SetBounds() above
326 0 : aDesiredSize.mOverflowAreas = GetOverflowAreas();
327 :
328 : #ifdef DO_NOISY_REFLOW
329 : {
330 : printf("%p ** nsLBF(done) W:%d H:%d ", this, aDesiredSize.width, aDesiredSize.height);
331 :
332 : if (maxElementWidth) {
333 : printf("MW:%d\n", *maxElementWidth);
334 : } else {
335 : printf("MW:?\n");
336 : }
337 :
338 : }
339 : #endif
340 :
341 0 : return NS_OK;
342 : }
343 :
344 : #ifdef DEBUG
345 : NS_IMETHODIMP
346 0 : nsLeafBoxFrame::GetFrameName(nsAString& aResult) const
347 : {
348 0 : return MakeFrameName(NS_LITERAL_STRING("LeafBox"), aResult);
349 : }
350 : #endif
351 :
352 : nsIAtom*
353 0 : nsLeafBoxFrame::GetType() const
354 : {
355 0 : return nsGkAtoms::leafBoxFrame;
356 : }
357 :
358 : NS_IMETHODIMP
359 0 : nsLeafBoxFrame::CharacterDataChanged(CharacterDataChangeInfo* aInfo)
360 : {
361 0 : MarkIntrinsicWidthsDirty();
362 0 : return nsLeafFrame::CharacterDataChanged(aInfo);
363 : }
364 :
365 : /* virtual */ nsSize
366 0 : nsLeafBoxFrame::GetPrefSize(nsBoxLayoutState& aState)
367 : {
368 0 : return nsBox::GetPrefSize(aState);
369 : }
370 :
371 : /* virtual */ nsSize
372 0 : nsLeafBoxFrame::GetMinSize(nsBoxLayoutState& aState)
373 : {
374 0 : return nsBox::GetMinSize(aState);
375 : }
376 :
377 : /* virtual */ nsSize
378 0 : nsLeafBoxFrame::GetMaxSize(nsBoxLayoutState& aState)
379 : {
380 0 : return nsBox::GetMaxSize(aState);
381 : }
382 :
383 : /* virtual */ nscoord
384 0 : nsLeafBoxFrame::GetFlex(nsBoxLayoutState& aState)
385 : {
386 0 : return nsBox::GetFlex(aState);
387 : }
388 :
389 : /* virtual */ nscoord
390 0 : nsLeafBoxFrame::GetBoxAscent(nsBoxLayoutState& aState)
391 : {
392 0 : return nsBox::GetBoxAscent(aState);
393 : }
394 :
395 : /* virtual */ void
396 0 : nsLeafBoxFrame::MarkIntrinsicWidthsDirty()
397 : {
398 : // Don't call base class method, since everything it does is within an
399 : // IsBoxWrapped check.
400 0 : }
401 :
402 : NS_IMETHODIMP
403 0 : nsLeafBoxFrame::DoLayout(nsBoxLayoutState& aState)
404 : {
405 0 : return nsBox::DoLayout(aState);
406 : }
|