Back to index

lightning-sunbird  0.9+nobinonly
nsFormControlFrame.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
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.org 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 #include "nsCOMPtr.h"
00038 #include "nsFormControlFrame.h"
00039 #include "nsHTMLParts.h"
00040 #include "nsGenericHTMLElement.h"
00041 #include "nsIRenderingContext.h"
00042 #include "nsIPresShell.h"
00043 #include "nsPresContext.h"
00044 #include "nsLeafFrame.h"
00045 #include "nsCSSRendering.h"
00046 #include "nsIView.h"
00047 #include "nsIViewManager.h"
00048 #include "nsCoord.h"
00049 #include "nsWidgetsCID.h"
00050 #include "nsViewsCID.h"
00051 #include "nsIComponentManager.h"
00052 #include "nsGUIEvent.h"
00053 #include "nsIFontMetrics.h"
00054 #include "nsIFormControl.h"
00055 #include "nsIDeviceContext.h"
00056 #include "nsHTMLAtoms.h"
00057 #include "nsIButton.h"  // remove this when GetCID is pure virtual
00058 #include "nsICheckButton.h"  //remove this
00059 #include "nsITextWidget.h"  //remove this
00060 #include "nsISupports.h"
00061 #include "nsStyleConsts.h"
00062 #include "nsUnitConversion.h"
00063 #include "nsIContent.h"
00064 #include "nsINameSpaceManager.h"
00065 #include "nsIDOMHTMLInputElement.h"
00066 #include "nsIDOMHTMLLabelElement.h"
00067 #include "nsIDOMHTMLTextAreaElement.h"
00068 #include "nsIDOMHTMLLegendElement.h"
00069 #include "nsIDOMHTMLButtonElement.h"
00070 #include "nsIEventStateManager.h"
00071 #include "nsIScrollableView.h"
00072 #include "nsILookAndFeel.h"
00073 
00074 #ifdef DEBUG_evaughan
00075 //#define DEBUG_rods
00076 #endif
00077 
00078 #ifdef DEBUG_rods
00079 //#define FCF_NOISY
00080 #endif
00081 
00082 #ifdef FCF_NOISY
00083 #define REFLOW_DEBUG_MSG(_msg1) printf((_msg1))
00084 #define REFLOW_DEBUG_MSG2(_msg1, _msg2) printf((_msg1), (_msg2))
00085 #define REFLOW_DEBUG_MSG3(_msg1, _msg2, _msg3) printf((_msg1), (_msg2), (_msg3))
00086 #define REFLOW_DEBUG_MSG4(_msg1, _msg2, _msg3, _msg4) printf((_msg1), (_msg2), (_msg3), (_msg4))
00087 
00088 #define IF_REFLOW_DEBUG_MSG(_bool, _msg1) if ((_bool)) printf((_msg1))
00089 #define IF_REFLOW_DEBUG_MSG2(_bool, _msg1, _msg2) if ((_bool)) printf((_msg1), (_msg2))
00090 #define IF_REFLOW_DEBUG_MSG3(_bool, _msg1, _msg2, _msg3) if ((_bool)) printf((_msg1), (_msg2), (_msg3))
00091 #define IF_REFLOW_DEBUG_MSG4(_bool, _msg1, _msg2, _msg3, _msg4) if ((_bool)) printf((_msg1), (_msg2), (_msg3), (_msg4))
00092 
00093 #else //-------------
00094 #define REFLOW_DEBUG_MSG(_msg) 
00095 #define REFLOW_DEBUG_MSG2(_msg1, _msg2) 
00096 #define REFLOW_DEBUG_MSG3(_msg1, _msg2, _msg3) 
00097 #define REFLOW_DEBUG_MSG4(_msg1, _msg2, _msg3, _msg4) 
00098 
00099 #define IF_REFLOW_DEBUG_MSG(_bool, _msg) 
00100 #define IF_REFLOW_DEBUG_MSG2(_bool, _msg1, _msg2) 
00101 #define IF_REFLOW_DEBUG_MSG3(_bool, _msg1, _msg2, _msg3) 
00102 #define IF_REFLOW_DEBUG_MSG4(_bool, _msg1, _msg2, _msg3, _msg4) 
00103 #endif
00104 
00105 const PRInt32 kSizeNotSet = -1;
00106 
00107 nsFormControlFrame::nsFormControlFrame()
00108   : nsLeafFrame()
00109 {
00110   mDidInit        = PR_FALSE;
00111   mSuggestedWidth = NS_FORMSIZE_NOTSET;
00112   mSuggestedHeight = NS_FORMSIZE_NOTSET;
00113   mPresContext    = nsnull;
00114 
00115   // Reflow Optimization
00116   mCacheSize.width             = kSizeNotSet;
00117   mCacheSize.height            = kSizeNotSet;
00118   mCachedMaxElementWidth       = kSizeNotSet;
00119 }
00120 
00121 nsFormControlFrame::~nsFormControlFrame()
00122 {
00123 }
00124 
00125 NS_IMETHODIMP
00126 nsFormControlFrame::Destroy(nsPresContext *aPresContext)
00127 {
00128   // XXXldb Do we really need to do this?  Shouldn't only those frames
00129   // that use it do it?
00130   nsFormControlFrame::RegUnRegAccessKey(aPresContext, NS_STATIC_CAST(nsIFrame*, this), PR_FALSE);
00131   return nsLeafFrame::Destroy(aPresContext);
00132 }
00133 
00134 // Frames are not refcounted, no need to AddRef
00135 NS_IMETHODIMP
00136 nsFormControlFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr)
00137 {
00138   NS_PRECONDITION(0 != aInstancePtr, "null ptr");
00139   if (NULL == aInstancePtr) {
00140     return NS_ERROR_NULL_POINTER;
00141   }
00142   if (aIID.Equals(NS_GET_IID(nsIFormControlFrame))) {
00143     *aInstancePtr = (void*) ((nsIFormControlFrame*) this);
00144     return NS_OK;
00145   }
00146   return nsLeafFrame::QueryInterface(aIID, aInstancePtr);
00147 }
00148 
00149 void nsFormControlFrame::SetupCachedSizes(nsSize& aCacheSize,
00150                                           nscoord& aCachedAscent,
00151                                           nscoord& aCachedMaxElementWidth,
00152                                           nsHTMLReflowMetrics& aDesiredSize)
00153 {
00154   aCacheSize.width  = aDesiredSize.width;
00155   aCacheSize.height = aDesiredSize.height;
00156   aCachedAscent = aDesiredSize.ascent;
00157   if (aDesiredSize.mComputeMEW) {
00158     aCachedMaxElementWidth  = aDesiredSize.mMaxElementWidth;
00159   }
00160 }
00161 
00162 #if 0 // Testing out changes
00163 //------------------------------------------------------------
00164 void nsFormControlFrame::SkipResizeReflow(nsSize& aCacheSize,
00165                                           nscoord& aCachedMaxElementWidth,
00166                                           nsSize& aCachedAvailableSize,
00167                                           nsHTMLReflowMetrics& aDesiredSize,
00168                                           const nsHTMLReflowState& aReflowState,
00169                                           nsReflowStatus& aStatus,
00170                                           PRBool& aBailOnWidth,
00171                                           PRBool& aBailOnHeight)
00172 {
00173 
00174   if (aReflowState.reason == eReflowReason_Incremental ||
00175       aReflowState.reason == eReflowReason_Dirty) {
00176     aBailOnHeight = PR_FALSE;
00177     aBailOnWidth  = PR_FALSE;
00178 
00179   } else if (eReflowReason_Initial == aReflowState.reason) {
00180     aBailOnHeight = PR_FALSE;
00181     aBailOnWidth  = PR_FALSE;
00182 
00183   } else {
00184 
00185     nscoord width;
00186     if (NS_UNCONSTRAINEDSIZE == aReflowState.mComputedWidth) {
00187       if (aReflowState.availableWidth == NS_UNCONSTRAINEDSIZE) {
00188         width = NS_UNCONSTRAINEDSIZE;
00189         aBailOnWidth = aCacheSize.width != kSizeNotSet;
00190         IF_REFLOW_DEBUG_MSG2(aBailOnWidth, "-------------- #1 Bailing on aCachedAvailableSize.width %d != kSizeNotSet\n", aCachedAvailableSize.width);
00191       } else {
00192         //width = aReflowState.availableWidth - aReflowState.mComputedBorderPadding.left -
00193         //        aReflowState.mComputedBorderPadding.right;
00194         aBailOnWidth = aCacheSize.width <= aReflowState.availableWidth && aCacheSize.width != kSizeNotSet;
00195 
00196         if (aBailOnWidth) {
00197           REFLOW_DEBUG_MSG3("-------------- #2 Bailing on aCachedSize.width %d <= (AW - BP) %d\n", aCachedAvailableSize.width, width );
00198         } else {
00199           //aBailOnWidth = width <= (aCacheSize.width - aReflowState.mComputedBorderPadding.left - aReflowState.mComputedBorderPadding.right) &&
00200           //               aCachedAvailableSize.width == kSizeNotSet;
00201           //if (aBailOnWidth) {
00202           //  REFLOW_DEBUG_MSG3("-------------- #2.2 Bailing on width %d <= aCachedSize.width %d\n", width, (aCacheSize.width - aReflowState.mComputedBorderPadding.left - aReflowState.mComputedBorderPadding.right));
00203           //}        
00204         }
00205       }
00206     } else {
00207       width = aReflowState.mComputedWidth;
00208       aBailOnWidth = width == (aCacheSize.width - aReflowState.mComputedBorderPadding.left - aReflowState.mComputedBorderPadding.right);
00209       IF_REFLOW_DEBUG_MSG3(aBailOnWidth, "-------------- #3 Bailing on aCachedAvailableSize.width %d == aReflowState.mComputedWidth %d\n", aCachedAvailableSize.width, width );
00210     }
00211     
00212     nscoord height;
00213     if (NS_UNCONSTRAINEDSIZE == aReflowState.mComputedHeight) {
00214       if (aReflowState.availableHeight == NS_UNCONSTRAINEDSIZE) {
00215         height = NS_UNCONSTRAINEDSIZE;
00216         aBailOnHeight = aCacheSize.height != kSizeNotSet;
00217         if (aBailOnHeight) {
00218           IF_REFLOW_DEBUG_MSG2(aBailOnHeight, "-------------- #1 Bailing on aCachedAvailableSize.height %d != kSizeNotSet\n", aCachedAvailableSize.height);
00219         }
00220       } else {
00221         height = aReflowState.availableHeight - aReflowState.mComputedBorderPadding.left -
00222                 aReflowState.mComputedBorderPadding.right;
00223         aBailOnHeight = aCachedAvailableSize.height <= height && aCachedAvailableSize.height != kSizeNotSet;
00224         if (aBailOnHeight) {
00225           REFLOW_DEBUG_MSG3("-------------- #2 Bailing on aCachedAvailableSize.height %d <= height %d\n", aCachedAvailableSize.height, height );
00226         } else {
00227           aBailOnHeight = height <= (aCacheSize.height - aReflowState.mComputedBorderPadding.left - aReflowState.mComputedBorderPadding.right) &&
00228                          aCachedAvailableSize.height == kSizeNotSet;
00229           if (aBailOnHeight) {
00230             REFLOW_DEBUG_MSG3("-------------- #2.2 Bailing on height %d <= aCachedSize.height %d\n", height, (aCacheSize.height - aReflowState.mComputedBorderPadding.left - aReflowState.mComputedBorderPadding.right));
00231           }        
00232         }
00233       }
00234     } else {
00235       height = aReflowState.mComputedHeight;
00236         aBailOnHeight = height == (aCacheSize.height - aReflowState.mComputedBorderPadding.left - aReflowState.mComputedBorderPadding.right);
00237         IF_REFLOW_DEBUG_MSG3(aBailOnHeight, "-------------- #3 Bailing on aCachedAvailableSize.height %d == aReflowState.mComputedHeight %d\n", aCachedAvailableSize.height, height );
00238     }
00239 
00240     if (aBailOnWidth || aBailOnHeight) {
00241       aDesiredSize.width  = aCacheSize.width;
00242       aDesiredSize.height = aCacheSize.height;
00243 
00244       if (aDesiredSize.mComputeMEW) {
00245         aDesiredSize.mMaxElementWidth  = aCachedMaxElementWidth;
00246       }
00247       aDesiredSize.ascent = aDesiredSize.height;
00248       aDesiredSize.descent = 0;
00249     }
00250   }
00251 }
00252 #else
00253 //------------------------------------------------------------
00254 void nsFormControlFrame::SkipResizeReflow(nsSize& aCacheSize,
00255                                           nscoord& aCachedAscent,
00256                                           nscoord& aCachedMaxElementWidth,
00257                                           nsSize& aCachedAvailableSize,
00258                                           nsHTMLReflowMetrics& aDesiredSize,
00259                                           const nsHTMLReflowState& aReflowState,
00260                                           nsReflowStatus& aStatus,
00261                                           PRBool& aBailOnWidth,
00262                                           PRBool& aBailOnHeight)
00263 {
00264 
00265   if (aReflowState.reason == eReflowReason_Incremental ||
00266 #ifdef IBMBIDI
00267       aReflowState.reason == eReflowReason_StyleChange ||
00268 #endif
00269       aReflowState.reason == eReflowReason_Dirty) {
00270     aBailOnHeight = PR_FALSE;
00271     aBailOnWidth  = PR_FALSE;
00272 
00273   } else if (eReflowReason_Initial == aReflowState.reason) {
00274     aBailOnHeight = PR_FALSE;
00275     aBailOnWidth  = PR_FALSE;
00276 
00277   } else {
00278 
00279     nscoord width;
00280     if (NS_UNCONSTRAINEDSIZE == aReflowState.mComputedWidth) {
00281       if (aReflowState.availableWidth == NS_UNCONSTRAINEDSIZE) {
00282         width = NS_UNCONSTRAINEDSIZE;
00283         aBailOnWidth = aCacheSize.width != kSizeNotSet;
00284 #ifdef FCF_NOISY
00285         if (aBailOnWidth) {
00286           printf("-------------- #1 Bailing on aCachedAvailableSize.width %d != kSizeNotSet\n", aCachedAvailableSize.width);
00287         }
00288 #endif
00289       } else {
00290         width = aReflowState.availableWidth - aReflowState.mComputedBorderPadding.left -
00291                 aReflowState.mComputedBorderPadding.right;
00292         aBailOnWidth = aCachedAvailableSize.width <= width && aCachedAvailableSize.width != kSizeNotSet;
00293 #ifdef FCF_NOISY
00294         if (aBailOnWidth) {
00295           printf("-------------- #2 Bailing on aCachedAvailableSize.width %d <= width %d\n", aCachedAvailableSize.width, width );
00296         } else {
00297           aBailOnWidth = width <= (aCacheSize.width - aReflowState.mComputedBorderPadding.left - aReflowState.mComputedBorderPadding.right) &&
00298                          aCachedAvailableSize.width == kSizeNotSet;
00299           if (aBailOnWidth) {
00300             printf("-------------- #2.2 Bailing on width %d <= aCachedAvailableSize.width %d\n",(aCacheSize.width - aReflowState.mComputedBorderPadding.left - aReflowState.mComputedBorderPadding.right), width );
00301           }        
00302         }
00303 #endif
00304       }
00305     } else {
00306       width = aReflowState.mComputedWidth;
00307       //if (aCachedAvailableSize.width == kSizeNotSet) {
00308       //  //aBailOnWidth = aCachedAvailableSize.width == aCacheSize.width;
00309         aBailOnWidth = PR_FALSE;
00310       //} else {
00311         aBailOnWidth = width == (aCacheSize.width - aReflowState.mComputedBorderPadding.left - aReflowState.mComputedBorderPadding.right);
00312       //}
00313 #ifdef FCF_NOISY
00314       if (aBailOnWidth) {
00315         printf("-------------- #3 Bailing on aCachedAvailableSize.width %d == aReflowState.mComputedWidth %d\n", aCachedAvailableSize.width, width );
00316       }
00317 #endif
00318     }
00319     
00320     nscoord height;
00321     if (NS_UNCONSTRAINEDSIZE == aReflowState.mComputedHeight) {
00322       if (aReflowState.availableHeight == NS_UNCONSTRAINEDSIZE) {
00323         height = NS_UNCONSTRAINEDSIZE;
00324         aBailOnHeight = aCacheSize.height != kSizeNotSet;
00325 #ifdef FCF_NOISY
00326         if (aBailOnHeight) {
00327           printf("-------------- #1 Bailing on aCachedAvailableSize.height %d != kSizeNotSet\n", aCachedAvailableSize.height);
00328         }
00329 #endif
00330       } else {
00331         height = aReflowState.availableHeight - aReflowState.mComputedBorderPadding.left -
00332                 aReflowState.mComputedBorderPadding.right;
00333         aBailOnHeight = aCachedAvailableSize.height <= height && aCachedAvailableSize.height != kSizeNotSet;
00334 #ifdef FCF_NOISY
00335         if (aBailOnHeight) {
00336           printf("-------------- #2 Bailing on aCachedAvailableSize.height %d <= height %d\n", aCachedAvailableSize.height, height );
00337         } else {
00338           aBailOnHeight = height <= (aCacheSize.height - aReflowState.mComputedBorderPadding.left - aReflowState.mComputedBorderPadding.right) &&
00339                          aCachedAvailableSize.height == kSizeNotSet;
00340           if (aBailOnHeight) {
00341             printf("-------------- #2.2 Bailing on height %d <= aCachedAvailableSize.height %d\n",(aCacheSize.height - aReflowState.mComputedBorderPadding.left - aReflowState.mComputedBorderPadding.right), height );
00342           }        
00343         }
00344 #endif
00345       }
00346     } else {
00347       height = aReflowState.mComputedHeight;
00348       //if (aCachedAvailableSize.height == kSizeNotSet) {
00349       //  //aBailOnHeight = aCachedAvailableSize.height == aCacheSize.height;
00350         aBailOnHeight = PR_FALSE;
00351       //} else {
00352         aBailOnHeight = height == (aCacheSize.height - aReflowState.mComputedBorderPadding.left - aReflowState.mComputedBorderPadding.right);
00353       //}
00354 #ifdef FCF_NOISY
00355       if (aBailOnHeight) {
00356         printf("-------------- #3 Bailing on aCachedAvailableSize.height %d == aReflowState.mComputedHeight %d\n", aCachedAvailableSize.height, height );
00357       }
00358 #endif
00359     }
00360 
00361     if (aBailOnWidth || aBailOnHeight) {
00362       aDesiredSize.width  = aCacheSize.width;
00363       aDesiredSize.height = aCacheSize.height;
00364       aDesiredSize.ascent = aCachedAscent;
00365       aDesiredSize.descent = aDesiredSize.height - aDesiredSize.ascent;
00366 
00367       if (aDesiredSize.mComputeMEW) {
00368         aDesiredSize.mMaxElementWidth = aCachedMaxElementWidth;
00369       }
00370     }
00371   }
00372 }
00373 #endif
00374 
00375 nscoord 
00376 nsFormControlFrame::GetScrollbarWidth(float aPixToTwip)
00377 {
00378    return NSIntPixelsToTwips(19, aPixToTwip);  // XXX this is windows
00379 }
00380 
00381 void 
00382 nsFormControlFrame::SetClickPoint(nscoord aX, nscoord aY)
00383 {
00384   mLastClickPoint.x = aX;
00385   mLastClickPoint.y = aY;
00386 }
00387 
00388 // XXX it would be cool if form element used our rendering sw, then
00389 // they could be blended, and bordered, and so on...
00390 NS_METHOD
00391 nsFormControlFrame::Paint(nsPresContext*      aPresContext,
00392                           nsIRenderingContext& aRenderingContext,
00393                           const nsRect&        aDirtyRect,
00394                           nsFramePaintLayer    aWhichLayer,
00395                           PRUint32             aFlags)
00396 {
00397   PRBool isVisible;
00398   if (NS_SUCCEEDED(IsVisibleForPainting(aPresContext, aRenderingContext, PR_TRUE, &isVisible)) && !isVisible) {
00399     return NS_OK;
00400   }
00401 
00402   nsresult rv = NS_OK;
00403   if (aWhichLayer == NS_FRAME_PAINT_LAYER_FOREGROUND) {
00404     rv = nsLeafFrame::Paint(aPresContext, aRenderingContext, aDirtyRect,
00405                             NS_FRAME_PAINT_LAYER_BACKGROUND);
00406     if (NS_FAILED(rv))
00407       return rv;
00408     // draw selection borders when appropriate
00409     rv = nsFrame::Paint(aPresContext, aRenderingContext, aDirtyRect,
00410                             NS_FRAME_PAINT_LAYER_BACKGROUND);
00411     if (NS_FAILED(rv))
00412       return rv;
00413 
00414     rv = nsLeafFrame::Paint(aPresContext, aRenderingContext, aDirtyRect,
00415                             NS_FRAME_PAINT_LAYER_FLOATS);
00416     if (NS_FAILED(rv))
00417       return rv;
00418     // draw selection borders when appropriate
00419     rv = nsFrame::Paint(aPresContext, aRenderingContext, aDirtyRect,
00420                             NS_FRAME_PAINT_LAYER_FLOATS);
00421     if (NS_FAILED(rv))
00422       return rv;
00423 
00424     rv = nsLeafFrame::Paint(aPresContext, aRenderingContext, aDirtyRect,
00425                             NS_FRAME_PAINT_LAYER_FOREGROUND);
00426     if (NS_FAILED(rv))
00427       return rv;
00428     // draw selection borders when appropriate
00429     rv = nsFrame::Paint(aPresContext, aRenderingContext, aDirtyRect,
00430                             NS_FRAME_PAINT_LAYER_FOREGROUND);
00431   }
00432   return rv;
00433 }
00434 
00435 NS_IMETHODIMP
00436 nsFormControlFrame::GetFrameForPoint(const nsPoint& aPoint,
00437                                      nsFramePaintLayer aWhichLayer,
00438                                      nsIFrame** aFrame)
00439 {
00440   nsresult rv = NS_ERROR_FAILURE;
00441   if (aWhichLayer == NS_FRAME_PAINT_LAYER_FOREGROUND) {
00442     rv = nsLeafFrame::GetFrameForPoint(aPoint,
00443                                       NS_FRAME_PAINT_LAYER_FOREGROUND, aFrame);
00444     if (NS_SUCCEEDED(rv))
00445       return NS_OK;
00446     rv = nsLeafFrame::GetFrameForPoint(aPoint,
00447                                        NS_FRAME_PAINT_LAYER_FLOATS, aFrame);
00448     if (NS_SUCCEEDED(rv))
00449       return NS_OK;
00450     rv = nsLeafFrame::GetFrameForPoint(aPoint,
00451                                       NS_FRAME_PAINT_LAYER_BACKGROUND, aFrame);
00452   }
00453   return rv;
00454 }
00455 
00456 void 
00457 nsFormControlFrame::GetDesiredSize(nsPresContext*          aPresContext,
00458                                    const nsHTMLReflowState& aReflowState,
00459                                    nsHTMLReflowMetrics&     aDesiredLayoutSize,
00460                                    nsSize&                  aDesiredWidgetSize)
00461 {
00462   // get the css size and let the frame use or override it
00463   nsSize styleSize;
00464   GetStyleSize(aPresContext, aReflowState, styleSize);
00465 
00466   // subclasses should always override this method, but if not and no css, make it small
00467   aDesiredLayoutSize.width  = (styleSize.width  > CSS_NOTSET) ? styleSize.width  : 144;
00468   aDesiredLayoutSize.height = (styleSize.height > CSS_NOTSET) ? styleSize.height : 144;
00469   aDesiredLayoutSize.ascent = aDesiredLayoutSize.height;
00470   aDesiredLayoutSize.descent = 0;
00471   if (aDesiredLayoutSize.mComputeMEW) {
00472     aDesiredLayoutSize.SetMEWToActualWidth(aReflowState.mStylePosition->mWidth.GetUnit());
00473   }
00474   aDesiredWidgetSize.width  = aDesiredLayoutSize.width;
00475   aDesiredWidgetSize.height = aDesiredLayoutSize.height;
00476 }
00477 
00478 void 
00479 nsFormControlFrame::GetDesiredSize(nsPresContext* aPresContext,
00480                              const nsHTMLReflowState& aReflowState,
00481                              nsHTMLReflowMetrics& aDesiredSize)
00482 {
00483   nsSize ignore;
00484   GetDesiredSize(aPresContext, aReflowState, aDesiredSize, ignore);
00485 }
00486 
00487 NS_IMETHODIMP
00488 nsFormControlFrame::DidReflow(nsPresContext*           aPresContext,
00489                               const nsHTMLReflowState*  aReflowState,
00490                               nsDidReflowStatus         aStatus)
00491 {
00492   nsresult rv = nsLeafFrame::DidReflow(aPresContext, aReflowState, aStatus);
00493 
00494 
00495   // The view is created hidden; once we have reflowed it and it has been
00496   // positioned then we show it.
00497   if (NS_FRAME_REFLOW_FINISHED == aStatus) {
00498     nsIView* view = GetView();
00499     if (view) {
00500       nsViewVisibility newVis = GetStyleVisibility()->IsVisible()
00501                                   ? nsViewVisibility_kShow
00502                                   : nsViewVisibility_kHide;
00503       // only change if different.
00504       if (newVis != view->GetVisibility()) {
00505         nsIViewManager* vm = view->GetViewManager();
00506         if (vm) {
00507           vm->SetViewVisibility(view, newVis);
00508         }
00509       }
00510     }
00511   }
00512   
00513   return rv;
00514 }
00515 
00516 NS_IMETHODIMP
00517 nsFormControlFrame::SetInitialChildList(nsPresContext* aPresContext,
00518                                         nsIAtom*        aListName,
00519                                         nsIFrame*       aChildList)
00520 {
00521   return NS_OK;
00522 }
00523 
00524 NS_METHOD
00525 nsFormControlFrame::Reflow(nsPresContext*          aPresContext,
00526                            nsHTMLReflowMetrics&     aDesiredSize,
00527                            const nsHTMLReflowState& aReflowState,
00528                            nsReflowStatus&          aStatus)
00529 {
00530   DO_GLOBAL_REFLOW_COUNT("nsFormControlFrame", aReflowState.reason);
00531   DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
00532 
00533   if (!mDidInit) {
00534     mPresContext = aPresContext;
00535     InitializeControl(aPresContext);
00536     mDidInit = PR_TRUE;
00537   }
00538 
00539 #if 0
00540   nsresult skiprv = SkipResizeReflow(mCacheSize, mCachedMaxElementWidth, aPresContext, 
00541                                      aDesiredSize, aReflowState, aStatus);
00542   if (NS_SUCCEEDED(skiprv)) {
00543     return skiprv;
00544   }
00545 #endif
00546 
00547   nsresult rv = nsLeafFrame::Reflow(aPresContext, aDesiredSize, aReflowState, aStatus);
00548 
00549   aStatus = NS_FRAME_COMPLETE;
00550   SetupCachedSizes(mCacheSize, mCachedAscent, mCachedMaxElementWidth, aDesiredSize);
00551   NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
00552   aDesiredSize.mOverflowArea = nsRect(0, 0, aDesiredSize.width, aDesiredSize.height);
00553   FinishAndStoreOverflow(&aDesiredSize);
00554   return rv;
00555 }
00556 
00557 
00558 nsWidgetInitData* 
00559 nsFormControlFrame::GetWidgetInitData(nsPresContext* aPresContext)
00560 {
00561   return nsnull;
00562 }
00563 
00564 
00565 nsresult
00566 nsFormControlFrame::RegUnRegAccessKey(nsPresContext* aPresContext, nsIFrame * aFrame, PRBool aDoReg)
00567 {
00568   NS_ASSERTION(aPresContext, "aPresContext is NULL in RegUnRegAccessKey!");
00569   NS_ENSURE_ARG_POINTER(aFrame);
00570 
00571   nsAutoString accessKey;
00572 
00573   nsIContent* content = aFrame->GetContent();
00574   content->GetAttr(kNameSpaceID_None, nsHTMLAtoms::accesskey, accessKey);
00575   if (!accessKey.IsEmpty()) {
00576     nsIEventStateManager *stateManager = aPresContext->EventStateManager();
00577     if (aDoReg) {
00578       return stateManager->RegisterAccessKey(content, (PRUint32)accessKey.First());
00579     } else {
00580       return stateManager->UnregisterAccessKey(content, (PRUint32)accessKey.First());
00581     }
00582   }
00583   return NS_ERROR_FAILURE;
00584 }
00585 
00586 void 
00587 nsFormControlFrame::InitializeControl(nsPresContext* aPresContext)
00588 {
00589   RegUnRegAccessKey(aPresContext, NS_STATIC_CAST(nsIFrame*, this), PR_TRUE);
00590 }
00591 
00592 void 
00593 nsFormControlFrame::SetFocus(PRBool aOn, PRBool aRepaint)
00594 {
00595 }
00596 
00597 void
00598 nsFormControlFrame::ScrollIntoView(nsPresContext* aPresContext)
00599 {
00600   if (aPresContext) {
00601     nsIPresShell *presShell = aPresContext->GetPresShell();
00602     if (presShell) {
00603       presShell->ScrollFrameIntoView(this,
00604                    NS_PRESSHELL_SCROLL_IF_NOT_VISIBLE,NS_PRESSHELL_SCROLL_IF_NOT_VISIBLE);
00605     }
00606   }
00607 }
00608 
00609 /*
00610  * FIXME: this ::GetIID() method has no meaning in life and should be
00611  * removed.
00612  * Pierre Phaneuf <pp@ludusdesign.com>
00613  */
00614 const nsIID&
00615 nsFormControlFrame::GetIID()
00616 {
00617   return NS_GET_IID(nsIButton);
00618 }
00619   
00620 const nsIID&
00621 nsFormControlFrame::GetCID()
00622 {
00623   static NS_DEFINE_IID(kButtonCID, NS_BUTTON_CID);
00624   return kButtonCID;
00625 }
00626 
00627 NS_IMETHODIMP
00628 nsFormControlFrame::GetMaxLength(PRInt32* aSize)
00629 {
00630   *aSize = -1;
00631 
00632   nsGenericHTMLElement *content = nsGenericHTMLElement::FromContent(mContent);
00633   if (content) {
00634     const nsAttrValue* attr = content->GetParsedAttr(nsHTMLAtoms::maxlength);
00635     if (attr && attr->Type() == nsAttrValue::eInteger) {
00636       *aSize = attr->GetIntegerValue();
00637 
00638       return NS_CONTENT_ATTR_HAS_VALUE;
00639     }
00640   }
00641   return NS_CONTENT_ATTR_NOT_THERE;
00642 }
00643 
00644 nsresult
00645 nsFormControlFrame::GetSizeFromContent(PRInt32* aSize) const
00646 {
00647   *aSize = -1;
00648 
00649   nsGenericHTMLElement *content = nsGenericHTMLElement::FromContent(mContent);
00650   if (content) {
00651     const nsAttrValue* attr = content->GetParsedAttr(nsHTMLAtoms::size);
00652     if (attr && attr->Type() == nsAttrValue::eInteger) {
00653       *aSize = attr->GetIntegerValue();
00654 
00655       return NS_CONTENT_ATTR_HAS_VALUE;
00656     }
00657   }
00658   return NS_CONTENT_ATTR_NOT_THERE;
00659 }
00660 
00661 NS_IMETHODIMP_(PRInt32)
00662 nsFormControlFrame::GetFormControlType() const
00663 {
00664   return nsFormControlHelper::GetType(mContent);
00665 }
00666 
00667 NS_IMETHODIMP
00668 nsFormControlFrame::GetName(nsAString* aResult)
00669 {
00670   return nsFormControlHelper::GetName(mContent, aResult);
00671 }
00672 
00673 
00674 NS_IMETHODIMP
00675 nsFormControlFrame::GetValue(nsAString* aResult)
00676 {
00677   return nsFormControlHelper::GetValueAttr(mContent, aResult);
00678 }
00679 
00680 
00681 NS_METHOD
00682 nsFormControlFrame::HandleEvent(nsPresContext* aPresContext, 
00683                                           nsGUIEvent* aEvent,
00684                                           nsEventStatus* aEventStatus)
00685 {
00686   NS_ENSURE_ARG_POINTER(aEventStatus);
00687   if (nsEventStatus_eConsumeNoDefault == *aEventStatus) {
00688     return NS_OK;
00689   }
00690 
00691   // Check for user-input:none style
00692   const nsStyleUserInterface* uiStyle = GetStyleUserInterface();
00693   if (uiStyle->mUserInput == NS_STYLE_USER_INPUT_NONE || uiStyle->mUserInput == NS_STYLE_USER_INPUT_DISABLED)
00694     return nsFrame::HandleEvent(aPresContext, aEvent, aEventStatus);
00695 
00696   // if not native then use the NS_MOUSE_LEFT_CLICK to see if pressed
00697   // unfortunately native widgets don't seem to handle this right. 
00698   // so use the old code for native stuff. -EDV
00699   switch (aEvent->message) {
00700           case NS_KEY_DOWN:
00701            if (NS_KEY_EVENT == aEvent->eventStructType) {
00702              nsKeyEvent* keyEvent = (nsKeyEvent*)aEvent;
00703              if (NS_VK_RETURN == keyEvent->keyCode) {
00704                EnterPressed(aPresContext);
00705              }
00706            }
00707            break;
00708   }
00709 
00710   *aEventStatus = nsEventStatus_eConsumeDoDefault;
00711   return NS_OK;
00712 }
00713 
00714 void 
00715 nsFormControlFrame::GetStyleSize(nsPresContext* aPresContext,
00716                                  const nsHTMLReflowState& aReflowState,
00717                                  nsSize& aSize)
00718 {
00719   if (aReflowState.mComputedWidth != NS_INTRINSICSIZE) {
00720     aSize.width = aReflowState.mComputedWidth;
00721   }
00722   else {
00723     aSize.width = CSS_NOTSET;
00724   }
00725   if (aReflowState.mComputedHeight != NS_INTRINSICSIZE) {
00726     aSize.height = aReflowState.mComputedHeight;
00727   }
00728   else {
00729     aSize.height = CSS_NOTSET;
00730   }
00731 }
00732 
00733 NS_IMETHODIMP
00734 nsFormControlFrame::GetFormContent(nsIContent*& aContent) const
00735 {
00736   aContent = GetContent();
00737   NS_IF_ADDREF(aContent);
00738   return NS_OK;
00739 }
00740 
00741 nsresult
00742 nsFormControlFrame::GetDefaultCheckState(PRBool *aState)
00743 {
00744   nsresult res = NS_OK;
00745   nsCOMPtr<nsIDOMHTMLInputElement> inputElement = do_QueryInterface(mContent);
00746   if (inputElement) {
00747     res = inputElement->GetDefaultChecked(aState);
00748   }
00749        return res;
00750 }
00751 
00752 nsresult
00753 nsFormControlFrame::SetDefaultCheckState(PRBool aState)
00754 {
00755        nsresult res = NS_OK;
00756   nsCOMPtr<nsIDOMHTMLInputElement> inputElement = do_QueryInterface(mContent);
00757   if (inputElement) {
00758     res = inputElement->SetDefaultChecked(aState);
00759   }
00760        return res;
00761 }
00762 
00763 nsresult
00764 nsFormControlFrame::GetCurrentCheckState(PRBool *aState)
00765 {
00766        nsresult res = NS_OK;
00767   nsCOMPtr<nsIDOMHTMLInputElement> inputElement = do_QueryInterface(mContent);
00768   if (inputElement) {
00769     res = inputElement->GetChecked(aState);
00770   }
00771        return res;
00772 }
00773 
00774 nsresult
00775 nsFormControlFrame::SetCurrentCheckState(PRBool aState)
00776 {
00777        nsresult res = NS_OK;
00778   nsCOMPtr<nsIDOMHTMLInputElement> inputElement = do_QueryInterface(mContent);
00779   if (inputElement) {
00780     inputElement->SetChecked(aState); 
00781   }
00782        return res;
00783 }
00784 
00785 NS_IMETHODIMP
00786 nsFormControlFrame::SetProperty(nsPresContext* aPresContext, nsIAtom* aName, const nsAString& aValue)
00787 {
00788   return NS_OK;
00789 }
00790 
00791 NS_IMETHODIMP
00792 nsFormControlFrame::GetProperty(nsIAtom* aName, nsAString& aValue)
00793 {
00794   aValue.Truncate();
00795   return NS_OK;
00796 }
00797 
00798 NS_IMETHODIMP
00799 nsFormControlFrame::SetSuggestedSize(nscoord aWidth, nscoord aHeight)
00800 {
00801   mSuggestedWidth = aWidth;
00802   mSuggestedHeight = aHeight;
00803   return NS_OK;
00804 }
00805 
00806 nsresult 
00807 nsFormControlFrame::GetScreenHeight(nsPresContext* aPresContext,
00808                                     nscoord& aHeight)
00809 {
00810   nsRect screen;
00811 
00812   nsIDeviceContext *context = aPresContext->DeviceContext();
00813   PRBool dropdownCanOverlapOSBar = PR_FALSE;
00814   nsILookAndFeel *lookAndFeel = aPresContext->LookAndFeel();
00815   lookAndFeel->GetMetric(nsILookAndFeel::eMetric_MenusCanOverlapOSBar,
00816                          dropdownCanOverlapOSBar);
00817   if ( dropdownCanOverlapOSBar )
00818     context->GetRect ( screen );
00819   else
00820     context->GetClientRect(screen);
00821       
00822   float devUnits;
00823   devUnits = context->DevUnitsToAppUnits();
00824   aHeight = NSToIntRound(float(screen.height) / devUnits );
00825   return NS_OK;
00826 }
00827 
00828 // Calculate a frame's position in screen coordinates
00829 nsresult
00830 nsFormControlFrame::GetAbsoluteFramePosition(nsPresContext* aPresContext,
00831                                              nsIFrame *aFrame, 
00832                                              nsRect& aAbsoluteTwipsRect, 
00833                                              nsRect& aAbsolutePixelRect)
00834 {
00835   nsresult rv = NS_OK;
00836  
00837   aAbsoluteTwipsRect = aFrame->GetRect();
00838   // zero these out, 
00839   // because the GetOffsetFromView figures them out
00840   // XXXbz why do we need to do this, really?  Will we ever fail to
00841   // get a containing view?
00842   aAbsoluteTwipsRect.x = 0;
00843   aAbsoluteTwipsRect.y = 0;
00844 
00845   // Get conversions between twips and pixels
00846   float t2p;
00847   float p2t;
00848   t2p = aPresContext->TwipsToPixels();
00849   p2t = aPresContext->PixelsToTwips();
00850 
00851   // Start with frame's offset from it it's containing view
00852   nsIView *view = nsnull;
00853   nsPoint frameOffset;
00854   rv = aFrame->GetOffsetFromView(frameOffset, &view);
00855 
00856   if (NS_SUCCEEDED(rv) && view) {
00857     aAbsoluteTwipsRect.MoveTo(frameOffset);
00858 
00859     nsIWidget* widget;
00860     // Walk up the views, looking for a widget
00861     do { 
00862       // add in the offset of the view from its parent.
00863       aAbsoluteTwipsRect += view->GetPosition();
00864 
00865       widget = view->GetWidget();
00866       if (widget) {
00867         // account for space above and to the left of the view origin.
00868         // the widget is aligned with view's bounds, not its origin
00869         
00870         nsRect bounds = view->GetBounds();
00871         aAbsoluteTwipsRect.x -= bounds.x;
00872         aAbsoluteTwipsRect.y -= bounds.y;
00873 
00874         // Add in the absolute offset of the widget.
00875         nsRect absBounds;
00876         nsRect zeroRect;
00877         // XXX a twip version of this would be really nice here!
00878         widget->WidgetToScreen(zeroRect, absBounds);
00879           // Convert widget coordinates to twips   
00880         aAbsoluteTwipsRect.x += NSIntPixelsToTwips(absBounds.x, p2t);
00881         aAbsoluteTwipsRect.y += NSIntPixelsToTwips(absBounds.y, p2t);   
00882         break;
00883       }
00884 
00885       view = view->GetParent();
00886     } while (view);
00887   }
00888   
00889   // convert to pixel coordinates
00890   if (NS_SUCCEEDED(rv)) {
00891     aAbsolutePixelRect.x = NSTwipsToIntPixels(aAbsoluteTwipsRect.x, t2p);
00892     aAbsolutePixelRect.y = NSTwipsToIntPixels(aAbsoluteTwipsRect.y, t2p);
00893 
00894     aAbsolutePixelRect.width = NSTwipsToIntPixels(aAbsoluteTwipsRect.width, t2p);
00895     aAbsolutePixelRect.height = NSTwipsToIntPixels(aAbsoluteTwipsRect.height, t2p);
00896   }
00897 
00898   return rv;
00899 }