Back to index

lightning-sunbird  0.9+nobinonly
nsLeafBoxFrame.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is Mozilla Communicator client code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 //
00039 // Eric Vaughan
00040 // Netscape Communications
00041 //
00042 // See documentation in associated header file
00043 //
00044 
00045 #include "nsLeafBoxFrame.h"
00046 #include "nsBoxFrame.h"
00047 #include "nsCOMPtr.h"
00048 #include "nsIDeviceContext.h"
00049 #include "nsIFontMetrics.h"
00050 #include "nsHTMLAtoms.h"
00051 #include "nsXULAtoms.h"
00052 #include "nsPresContext.h"
00053 #include "nsIRenderingContext.h"
00054 #include "nsStyleContext.h"
00055 #include "nsIContent.h"
00056 #include "nsINameSpaceManager.h"
00057 #include "nsBoxLayoutState.h"
00058 #include "nsWidgetsCID.h"
00059 #include "nsIViewManager.h"
00060 #include "nsHTMLContainerFrame.h"
00061 
00062 static NS_DEFINE_IID(kWidgetCID, NS_CHILD_CID);
00063 
00064 //
00065 // NS_NewToolbarFrame
00066 //
00067 // Creates a new Toolbar frame and returns it in |aNewFrame|
00068 //
00069 nsresult
00070 NS_NewLeafBoxFrame ( nsIPresShell* aPresShell, nsIFrame** aNewFrame )
00071 {
00072   NS_PRECONDITION(aNewFrame, "null OUT ptr");
00073   if (nsnull == aNewFrame) {
00074     return NS_ERROR_NULL_POINTER;
00075   }
00076   nsLeafBoxFrame* it = new (aPresShell) nsLeafBoxFrame(aPresShell);
00077   if (nsnull == it)
00078     return NS_ERROR_OUT_OF_MEMORY;
00079 
00080   // it->SetFlags(aFlags);
00081   *aNewFrame = it;
00082   return NS_OK;
00083   
00084 } // NS_NewTextFrame
00085 
00086 nsLeafBoxFrame::nsLeafBoxFrame(nsIPresShell* aShell)
00087     : mMouseThrough(unset)
00088 {
00089     mState |= NS_FRAME_IS_BOX;
00090 }
00091 
00092 #ifdef DEBUG_LAYOUT
00093 void
00094 nsLeafBoxFrame::GetBoxName(nsAutoString& aName)
00095 {
00096    GetFrameName(aName);
00097 }
00098 #endif
00099 
00100 
00104 NS_IMETHODIMP
00105 nsLeafBoxFrame::Init(nsPresContext*  aPresContext,
00106               nsIContent*      aContent,
00107               nsIFrame*        aParent,
00108               nsStyleContext*  aContext,
00109               nsIFrame*        aPrevInFlow)
00110 {
00111   nsresult  rv = nsLeafFrame::Init(aPresContext, aContent, aParent, aContext, aPrevInFlow);
00112   NS_ENSURE_SUCCESS(rv, rv);
00113 
00114    // see if we need a widget
00115   if (aParent && aParent->IsBoxFrame()) {
00116     PRBool needsWidget = PR_FALSE;
00117     aParent->ChildrenMustHaveWidgets(needsWidget);
00118     if (needsWidget) {
00119         rv = nsHTMLContainerFrame::CreateViewForFrame(this, nsnull, PR_TRUE); 
00120         NS_ENSURE_SUCCESS(rv, rv);
00121 
00122         nsIView* view = GetView();
00123         if (!view->HasWidget())
00124            view->CreateWidget(kWidgetCID);   
00125     }
00126   }
00127   
00128   mMouseThrough = unset;
00129 
00130   UpdateMouseThrough();
00131 
00132   return rv;
00133 }
00134 
00135 NS_IMETHODIMP
00136 nsLeafBoxFrame::AttributeChanged(nsIContent* aChild,
00137                                  PRInt32 aNameSpaceID,
00138                                  nsIAtom* aAttribute,
00139                                  PRInt32 aModType)
00140 {
00141   nsresult rv = nsLeafFrame::AttributeChanged(aChild, aNameSpaceID,
00142                                               aAttribute, aModType);
00143 
00144   if (aAttribute == nsXULAtoms::mousethrough) 
00145     UpdateMouseThrough();
00146 
00147   return rv;
00148 }
00149 
00150 void nsLeafBoxFrame::UpdateMouseThrough()
00151 {
00152   if (mContent) {
00153     nsAutoString value;
00154     if (NS_CONTENT_ATTR_HAS_VALUE == mContent->GetAttr(kNameSpaceID_None, nsXULAtoms::mousethrough, value)) {
00155         if (value.EqualsLiteral("never"))
00156           mMouseThrough = never;
00157         else if (value.EqualsLiteral("always"))
00158           mMouseThrough = always;
00159       
00160     }
00161   }
00162 }
00163 
00164 NS_IMETHODIMP
00165 nsLeafBoxFrame::GetMouseThrough(PRBool& aMouseThrough)
00166 {
00167   switch (mMouseThrough)
00168   {
00169     case always:
00170       aMouseThrough = PR_TRUE;
00171       return NS_OK;
00172     case never:
00173       aMouseThrough = PR_FALSE;      
00174       return NS_OK;
00175     case unset:
00176     {
00177       if (mParent && mParent->IsBoxFrame())
00178         return mParent->GetMouseThrough(aMouseThrough);
00179       else {
00180         aMouseThrough = PR_FALSE;      
00181         return NS_OK;
00182       }
00183     }
00184   }
00185 
00186   return NS_ERROR_FAILURE;
00187 }
00188 
00189 NS_IMETHODIMP  
00190 nsLeafBoxFrame::GetFrameForPoint(const nsPoint& aPoint, 
00191                              nsFramePaintLayer aWhichLayer,    
00192                              nsIFrame**     aFrame)
00193 {   
00194   if ((aWhichLayer != NS_FRAME_PAINT_LAYER_FOREGROUND))
00195     return NS_ERROR_FAILURE;
00196 
00197   if (!mRect.Contains(aPoint))
00198     return NS_ERROR_FAILURE;
00199 
00200   *aFrame = this;
00201   return NS_OK;
00202 }
00203 
00204 NS_IMETHODIMP
00205 nsLeafBoxFrame::DidReflow(nsPresContext*           aPresContext,
00206                           const nsHTMLReflowState*  aReflowState,
00207                           nsDidReflowStatus         aStatus)
00208 {
00209   PRBool isDirty = mState & NS_FRAME_IS_DIRTY;
00210   PRBool hasDirtyChildren = mState & NS_FRAME_HAS_DIRTY_CHILDREN;
00211   nsresult rv = nsFrame::DidReflow(aPresContext, aReflowState, aStatus);
00212   if (isDirty)
00213     mState |= NS_FRAME_IS_DIRTY;
00214 
00215   if (hasDirtyChildren)
00216     mState |= NS_FRAME_HAS_DIRTY_CHILDREN;
00217 
00218   return rv;
00219 
00220 }
00221 
00222 
00223 NS_IMETHODIMP
00224 nsLeafBoxFrame::Reflow(nsPresContext*   aPresContext,
00225                      nsHTMLReflowMetrics&     aDesiredSize,
00226                      const nsHTMLReflowState& aReflowState,
00227                      nsReflowStatus&          aStatus)
00228 {
00229   // This is mostly a copy of nsBoxFrame::Reflow().
00230   // We aren't able to share an implementation because of the frame
00231   // class hierarchy.  If you make changes here, please keep
00232   // nsBoxFrame::Reflow in sync.
00233 
00234   DO_GLOBAL_REFLOW_COUNT("nsLeafBoxFrame", aReflowState.reason);
00235   DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
00236 
00237   NS_ASSERTION(aReflowState.mComputedWidth >=0 && aReflowState.mComputedHeight >= 0, "Computed Size < 0");
00238 
00239 #ifdef DO_NOISY_REFLOW
00240   printf("\n-------------Starting LeafBoxFrame Reflow ----------------------------\n");
00241   printf("%p ** nsLBF::Reflow %d R: ", this, myCounter++);
00242   switch (aReflowState.reason) {
00243     case eReflowReason_Initial:
00244       printf("Ini");break;
00245     case eReflowReason_Incremental:
00246       printf("Inc");break;
00247     case eReflowReason_Resize:
00248       printf("Rsz");break;
00249     case eReflowReason_StyleChange:
00250       printf("Sty");break;
00251     case eReflowReason_Dirty:
00252       printf("Drt ");
00253       break;
00254     default:printf("<unknown>%d", aReflowState.reason);break;
00255   }
00256   
00257   printSize("AW", aReflowState.availableWidth);
00258   printSize("AH", aReflowState.availableHeight);
00259   printSize("CW", aReflowState.mComputedWidth);
00260   printSize("CH", aReflowState.mComputedHeight);
00261 
00262   printf(" *\n");
00263 
00264 #endif
00265 
00266   aStatus = NS_FRAME_COMPLETE;
00267 
00268   // create the layout state
00269   nsBoxLayoutState state(aPresContext, aReflowState, aDesiredSize);
00270 
00271   // coelesce reflows if we are root.
00272   state.HandleReflow(this);
00273   
00274   nsSize computedSize(aReflowState.mComputedWidth,aReflowState.mComputedHeight);
00275 
00276   nsMargin m;
00277   m = aReflowState.mComputedBorderPadding;
00278 
00279   //GetBorderAndPadding(m);
00280 
00281   // this happens sometimes. So lets handle it gracefully.
00282   if (aReflowState.mComputedHeight == 0) {
00283     nsSize minSize(0,0);
00284     GetMinSize(state, minSize);
00285     computedSize.height = minSize.height - m.top - m.bottom;
00286   }
00287 
00288   nsSize prefSize(0,0);
00289 
00290   // if we are told to layout intrinic then get our preferred size.
00291   if (computedSize.width == NS_INTRINSICSIZE || computedSize.height == NS_INTRINSICSIZE) {
00292      nsSize minSize(0,0);
00293      nsSize maxSize(0,0);
00294      GetPrefSize(state, prefSize);
00295      GetMinSize(state,  minSize);
00296      GetMaxSize(state,  maxSize);
00297      BoundsCheck(minSize, prefSize, maxSize);
00298   }
00299 
00300   // get our desiredSize
00301   if (aReflowState.mComputedWidth == NS_INTRINSICSIZE) {
00302     computedSize.width = prefSize.width;
00303   } else {
00304     computedSize.width += m.left + m.right;
00305   }
00306 
00307   if (aReflowState.mComputedHeight == NS_INTRINSICSIZE) {
00308     computedSize.height = prefSize.height;
00309   } else {
00310     computedSize.height += m.top + m.bottom;
00311   }
00312 
00313   // handle reflow state min and max sizes
00314 
00315   if (computedSize.width > aReflowState.mComputedMaxWidth)
00316     computedSize.width = aReflowState.mComputedMaxWidth;
00317 
00318   if (computedSize.height > aReflowState.mComputedMaxHeight)
00319     computedSize.height = aReflowState.mComputedMaxHeight;
00320 
00321   if (computedSize.width < aReflowState.mComputedMinWidth)
00322     computedSize.width = aReflowState.mComputedMinWidth;
00323 
00324   if (computedSize.height < aReflowState.mComputedMinHeight)
00325     computedSize.height = aReflowState.mComputedMinHeight;
00326 
00327   nsRect r(mRect.x, mRect.y, computedSize.width, computedSize.height);
00328 
00329   SetBounds(state, r);
00330  
00331   // layout our children
00332   Layout(state);
00333   
00334   // ok our child could have gotten bigger. So lets get its bounds
00335   
00336   // get the ascent
00337   nscoord ascent = mRect.height;
00338 
00339   // Only call GetAscent when not doing Initial reflow while in PP
00340   // or when it is Initial reflow while in PP and a chrome doc
00341   // If called again with initial reflow it crashes because the 
00342   // frames are fully constructed (I think).
00343   PRBool isChrome;
00344   PRBool isInitialPP = nsBoxFrame::IsInitialReflowForPrintPreview(state, isChrome);
00345   if (!isInitialPP || (isInitialPP && isChrome)) {
00346     GetAscent(state, ascent);
00347   }
00348 
00349   aDesiredSize.width  = mRect.width;
00350   aDesiredSize.height = mRect.height;
00351   aDesiredSize.ascent = ascent;
00352   aDesiredSize.descent = 0;
00353 
00354   // NS_FRAME_OUTSIDE_CHILDREN is set in SetBounds() above
00355   if (mState & NS_FRAME_OUTSIDE_CHILDREN) {
00356     nsRect* overflowArea = GetOverflowAreaProperty();
00357     NS_ASSERTION(overflowArea, "Failed to set overflow area property");
00358     aDesiredSize.mOverflowArea = *overflowArea;
00359   }
00360 
00361   // max sure the max element size reflects
00362   // our min width
00363   nscoord* maxElementWidth = state.GetMaxElementWidth();
00364   if (maxElementWidth)
00365   {
00366      nsSize minSize(0,0);
00367      GetMinSize(state,  minSize);
00368 
00369      if (mRect.width > minSize.width) {
00370        if (aReflowState.mComputedWidth == NS_INTRINSICSIZE) {
00371          *maxElementWidth = minSize.width;
00372        } else {
00373          *maxElementWidth = mRect.width;
00374        }
00375      } else {
00376         *maxElementWidth = mRect.width;
00377      }
00378   }
00379 #ifdef DO_NOISY_REFLOW
00380   {
00381     printf("%p ** nsLBF(done) W:%d H:%d  ", this, aDesiredSize.width, aDesiredSize.height);
00382 
00383     if (maxElementWidth) {
00384       printf("MW:%d\n", *maxElementWidth); 
00385     } else {
00386       printf("MW:?\n"); 
00387     }
00388 
00389   }
00390 #endif
00391 
00392   return NS_OK;
00393 }
00394 
00395 #ifdef DEBUG
00396 NS_IMETHODIMP
00397 nsLeafBoxFrame::GetFrameName(nsAString& aResult) const
00398 {
00399   return MakeFrameName(NS_LITERAL_STRING("LeafBox"), aResult);
00400 }
00401 #endif
00402 
00403 NS_IMETHODIMP_(nsrefcnt) 
00404 nsLeafBoxFrame::AddRef(void)
00405 {
00406   return NS_OK;
00407 }
00408 
00409 NS_IMETHODIMP_(nsrefcnt)
00410 nsLeafBoxFrame::Release(void)
00411 {
00412     return NS_OK;
00413 }
00414 
00415 NS_IMETHODIMP
00416 nsLeafBoxFrame::CharacterDataChanged(nsPresContext* aPresContext,
00417                                      nsIContent*     aChild,
00418                                      PRBool          aAppend)
00419 {
00420   NeedsRecalc();
00421   return nsLeafFrame::CharacterDataChanged(aPresContext, aChild, aAppend);
00422 }
00423 
00424 NS_IMETHODIMP
00425 nsLeafBoxFrame::GetPrefSize(nsBoxLayoutState& aState, nsSize& aSize)
00426 {
00427     return nsBox::GetPrefSize(aState, aSize);
00428 }
00429 
00430 NS_IMETHODIMP
00431 nsLeafBoxFrame::GetMinSize(nsBoxLayoutState& aState, nsSize& aSize)
00432 {
00433     return nsBox::GetMinSize(aState, aSize);
00434 }
00435 
00436 NS_IMETHODIMP
00437 nsLeafBoxFrame::GetMaxSize(nsBoxLayoutState& aState, nsSize& aSize)
00438 {
00439     return nsBox::GetMaxSize(aState, aSize);
00440 }
00441 
00442 NS_IMETHODIMP
00443 nsLeafBoxFrame::GetFlex(nsBoxLayoutState& aState, nscoord& aFlex)
00444 {
00445     return nsBox::GetFlex(aState, aFlex);
00446 }
00447 
00448 NS_IMETHODIMP
00449 nsLeafBoxFrame::GetAscent(nsBoxLayoutState& aState, nscoord& aAscent)
00450 {
00451     return nsBox::GetAscent(aState, aAscent);
00452 }
00453 
00454 NS_IMETHODIMP
00455 nsLeafBoxFrame::NeedsRecalc()
00456 {
00457     return nsBox::NeedsRecalc();
00458 }
00459 
00460 NS_IMETHODIMP
00461 nsLeafBoxFrame::DoLayout(nsBoxLayoutState& aState)
00462 {
00463     return nsBox::DoLayout(aState);
00464 }
00465 
00466 PRBool
00467 nsLeafBoxFrame::HasStyleChange()
00468 {
00469     return nsBox::HasStyleChange();
00470 }
00471 
00472 void
00473 nsLeafBoxFrame::SetStyleChangeFlag(PRBool aDirty)
00474 {
00475     nsBox::SetStyleChangeFlag(aDirty);
00476 }
00477 
00478 PRBool
00479 nsLeafBoxFrame::GetWasCollapsed(nsBoxLayoutState& aState)
00480 {
00481     return nsBox::GetWasCollapsed(aState);
00482 }
00483 
00484 void
00485 nsLeafBoxFrame::SetWasCollapsed(nsBoxLayoutState& aState, PRBool aWas)
00486 {
00487     nsBox::SetWasCollapsed(aState, aWas);
00488 }
00489 
00490 NS_INTERFACE_MAP_BEGIN(nsLeafBoxFrame)
00491   NS_INTERFACE_MAP_ENTRY(nsIBox)
00492 #ifdef NS_DEBUG
00493   NS_INTERFACE_MAP_ENTRY(nsIFrameDebug)
00494 #endif
00495   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIBox)
00496 NS_INTERFACE_MAP_END_INHERITING(nsLeafFrame)