Back to index

lightning-sunbird  0.9+nobinonly
nsNativeThemeMac.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  * Mike Pinkerton (pinkerton@netscape.com).
00019  * Portions created by the Initial Developer are Copyright (C) 2001
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 #include <Gestalt.h>
00039 #include "nsNativeThemeMac.h"
00040 #include "nsRenderingContextMac.h"
00041 #include "nsDeviceContextMac.h"
00042 #include "nsRect.h"
00043 #include "nsSize.h"
00044 #include "nsTransform2D.h"
00045 #include "nsThemeConstants.h"
00046 #include "nsIPresShell.h"
00047 #include "nsPresContext.h"
00048 #include "nsIContent.h"
00049 #include "nsIDocument.h"
00050 #include "nsIFrame.h"
00051 #include "nsIAtom.h"
00052 #include "nsIEventStateManager.h"
00053 #include "nsINameSpaceManager.h"
00054 #include "nsPresContext.h"
00055 #include "nsILookAndFeel.h"
00056 #include "nsRegionPool.h"
00057 #include "nsGfxUtils.h"
00058 #include "nsUnicharUtils.h"
00059 
00060 static PRBool sInitializedBorders = PR_FALSE;
00061 
00062 static void 
00063 ConvertGeckoToNativeRect(const nsRect& aSrc, Rect& aDst) 
00064 {
00065   aDst.top = aSrc.y;
00066   aDst.bottom = aSrc.y + aSrc.height;
00067   aDst.left = aSrc.x;
00068   aDst.right = aSrc.x + aSrc.width;
00069 }
00070 
00071 //
00072 // DoNothing
00073 //
00074 // An eraseProc for drawing theme buttons so that we don't erase over anything
00075 // that might be drawn before us in the background layer. Does absolutely
00076 // nothing.
00077 //
00078 static pascal void
00079 DoNothing(const Rect *bounds, UInt32 eraseData, SInt16 depth, Boolean isColorDev)
00080 {
00081   // be gentle, erase nothing.
00082 }
00083 
00084 
00085 #ifdef XP_MAC
00086 #pragma mark -
00087 #endif
00088 
00089          
00090 NS_IMPL_ISUPPORTS1(nsNativeThemeMac, nsITheme)
00091 
00092 nsNativeThemeMac::nsNativeThemeMac()
00093   : mEraseProc(nsnull)
00094 {
00095   mEraseProc = NewThemeEraseUPP(DoNothing);
00096   if (!sInitializedBorders) {
00097     sInitializedBorders = PR_TRUE;
00098     sTextfieldBorderSize.left = sTextfieldBorderSize.top = 2;
00099     sTextfieldBorderSize.right = sTextfieldBorderSize.bottom = 2;
00100     sTextfieldBGTransparent = PR_FALSE;
00101     sListboxBGTransparent = PR_TRUE;
00102     sTextfieldDisabledBGColorID = nsILookAndFeel::eColor__moz_field;
00103   }
00104 
00105   mMenuActiveAtom = do_GetAtom("_moz-menuactive");
00106 }
00107 
00108 nsNativeThemeMac::~nsNativeThemeMac()
00109 {
00110   if ( mEraseProc )
00111     ::DisposeThemeEraseUPP(mEraseProc);
00112 }
00113 
00114 #ifdef XP_MAC
00115 #pragma mark -
00116 #endif
00117 
00118 
00119 void
00120 nsNativeThemeMac::DrawCheckboxRadio ( ThemeButtonKind inKind, const Rect& inBoxRect, PRBool inChecked,
00121                                        PRBool inDisabled, PRInt32 inState )
00122 {
00123   ThemeButtonDrawInfo info;
00124   if ( inDisabled )
00125     info.state = kThemeStateInactive;
00126   else
00127     info.state = ((inState & NS_EVENT_STATE_ACTIVE) && (inState & NS_EVENT_STATE_HOVER)) ?
00128                      kThemeStatePressed : kThemeStateActive;
00129   info.value = inChecked ? kThemeButtonOn : kThemeButtonOff;
00130   info.adornment = (inState & NS_EVENT_STATE_FOCUS) ? kThemeAdornmentFocus : kThemeAdornmentNone;
00131   
00132   ::DrawThemeButton ( &inBoxRect, inKind, &info, nsnull, nsnull, nsnull, 0L );
00133 }
00134 
00135 
00136 void
00137 nsNativeThemeMac::DrawCheckbox ( const Rect& inBoxRect, PRBool inChecked, PRBool inDisabled, PRInt32 inState )
00138 {
00139   DrawCheckboxRadio(kThemeCheckBox, inBoxRect, inChecked, inDisabled, inState);
00140 }
00141 
00142 void
00143 nsNativeThemeMac::DrawSmallCheckbox ( const Rect& inBoxRect, PRBool inChecked, PRBool inDisabled, PRInt32 inState )
00144 {
00145   DrawCheckboxRadio(kThemeSmallCheckBox, inBoxRect, inChecked, inDisabled, inState);
00146 }
00147 
00148 void
00149 nsNativeThemeMac::DrawRadio ( const Rect& inBoxRect, PRBool inChecked, PRBool inDisabled, PRInt32 inState )
00150 {
00151   DrawCheckboxRadio(kThemeRadioButton, inBoxRect, inChecked, inDisabled, inState);
00152 }
00153 
00154 void
00155 nsNativeThemeMac::DrawSmallRadio ( const Rect& inBoxRect, PRBool inChecked, PRBool inDisabled, PRInt32 inState )
00156 {
00157   DrawCheckboxRadio(kThemeSmallRadioButton, inBoxRect, inChecked, inDisabled, inState);
00158 }
00159 
00160 void
00161 nsNativeThemeMac::DrawButton ( ThemeButtonKind inKind, const Rect& inBoxRect, PRBool inIsDefault, 
00162                                   PRBool inDisabled, ThemeButtonValue inValue, ThemeButtonAdornment inAdornment,
00163                                   PRInt32 inState )
00164 {
00165   ThemeButtonDrawInfo info;
00166 
00167   info.value = inValue;
00168   info.adornment = inAdornment;
00169 
00170   if ( inDisabled )
00171     info.state = kThemeStateUnavailableInactive;
00172   else {
00173     info.state = ((inState & NS_EVENT_STATE_ACTIVE) && (inState & NS_EVENT_STATE_HOVER)) ? 
00174                     kThemeStatePressed : kThemeStateActive;
00175     if ( inState & NS_EVENT_STATE_FOCUS ) {
00176       // There is a bug in OS 10.2.x-10.3.x where if we are in a CG context and
00177       // draw the focus ring with DrawThemeButton(), there are ugly lines all
00178       // through the button.  This may get fixed in a dot-release, but until it
00179       // does, we can't draw the focus ring.
00180       if (inKind != kThemePushButton || nsRenderingContextMac::OnTigerOrLater())
00181         info.adornment = kThemeAdornmentFocus;
00182     }
00183     if ( inIsDefault )
00184       info.adornment |= kThemeAdornmentDefault;
00185   }
00186   ::DrawThemeButton ( &inBoxRect, inKind, &info, nsnull, mEraseProc, nsnull, 0L );
00187 }
00188 
00189 
00190 void
00191 nsNativeThemeMac::DrawToolbar ( const Rect& inBoxRect )
00192 {
00193 #if 0
00194   const PRInt32 kThemeBrushToolbarBackground = 52;    // from 3.4.1 headers
00195   ::SetThemeBackground(kThemeBrushToolbarBackground, 24, true);
00196   ::EraseRect(&inBoxRect);
00197   ::SetThemeBackground(kThemeBrushWhite, 24, true);
00198 printf("told to draw at %ld %ld w %ld h %ld\n", inBoxRect.left, inBoxRect.top, inBoxRect.right-inBoxRect.left,
00199         inBoxRect.bottom - inBoxRect.top);
00200 #endif
00201   ThemeDrawState drawState = kThemeStateActive;
00202   ::DrawThemeWindowHeader(&inBoxRect, drawState);
00203 }
00204 
00205 
00206 void
00207 nsNativeThemeMac::DrawEditText ( const Rect& inBoxRect, PRBool inIsDisabled )
00208 {
00209   Pattern whitePat;
00210   ::BackColor(whiteColor);
00211   ::BackPat(GetQDGlobalsWhite(&whitePat));
00212   ::EraseRect(&inBoxRect);
00213   
00214   ThemeDrawState drawState = inIsDisabled ? kThemeStateDisabled : kThemeStateActive;
00215   ::DrawThemeEditTextFrame(&inBoxRect, drawState);
00216 }
00217 
00218 
00219 void
00220 nsNativeThemeMac::DrawListBox ( const Rect& inBoxRect, PRBool inIsDisabled )
00221 {
00222   Pattern whitePat;
00223   ::BackColor(whiteColor);
00224   ::BackPat(GetQDGlobalsWhite(&whitePat));
00225   ::EraseRect(&inBoxRect);
00226   
00227   ThemeDrawState drawState = inIsDisabled ? kThemeStateDisabled : kThemeStateActive;
00228   ::DrawThemeListBoxFrame(&inBoxRect, drawState);
00229 }
00230 
00231 
00232 void
00233 nsNativeThemeMac::DrawProgress ( const Rect& inBoxRect, PRBool inIsDisabled, PRBool inIsIndeterminate, 
00234                                   PRBool inIsHorizontal, PRInt32 inValue )
00235 {
00236   ThemeTrackDrawInfo info;
00237   static SInt32 sPhase = 0;
00238   
00239   info.kind = inIsIndeterminate ? kThemeMediumIndeterminateBar: kThemeMediumProgressBar;
00240   info.bounds = inBoxRect;
00241   info.min = 0;
00242   info.max = 100;
00243   info.value = inValue;
00244   info.attributes = inIsHorizontal ? kThemeTrackHorizontal : 0L;
00245   info.enableState = inIsDisabled ? kThemeTrackDisabled : kThemeTrackActive;
00246   info.trackInfo.progress.phase = sPhase++;       // animate for the next time we're called
00247   
00248   ::DrawThemeTrack(&info, nsnull, nsnull, 0L);
00249 }
00250 
00251 
00252 void
00253 nsNativeThemeMac::DrawTabPanel ( const Rect& inBoxRect, PRBool inIsDisabled )
00254 {
00255   ThemeDrawState drawState = inIsDisabled ? kThemeStateDisabled : kThemeStateActive;
00256   ::DrawThemeTabPane(&inBoxRect, drawState);
00257 }
00258 
00259 
00260 void
00261 nsNativeThemeMac::DrawSeparator ( const Rect& inBoxRect, PRBool inIsDisabled )
00262 {
00263   ThemeDrawState drawState = inIsDisabled ? kThemeStateDisabled : kThemeStateActive;
00264   ::DrawThemeSeparator(&inBoxRect, drawState);
00265 }
00266 
00267 
00268 void
00269 nsNativeThemeMac::DrawTab ( const Rect& inBoxRect, PRBool inIsDisabled, PRBool inIsFrontmost, 
00270                               PRBool inIsHorizontal, PRBool inTabBottom, PRInt32 inState )
00271 {
00272   ThemeTabStyle style = 0L;
00273   if ( inIsFrontmost ) {
00274     if ( inIsDisabled ) 
00275       style = kThemeTabFrontInactive;
00276     else
00277       style = kThemeTabFront;
00278   }
00279   else {
00280     if ( inIsDisabled )
00281       style = kThemeTabNonFrontInactive;
00282     else if ( (inState & NS_EVENT_STATE_ACTIVE) && (inState & NS_EVENT_STATE_HOVER) )
00283       style = kThemeTabNonFrontPressed;
00284     else
00285       style = kThemeTabNonFront;  
00286   }
00287 
00288   ThemeTabDirection direction = inTabBottom ? kThemeTabSouth : kThemeTabNorth; // don't yet support vertical tabs
00289   ::DrawThemeTab(&inBoxRect, style, direction, nsnull, 0L);
00290 }
00291 
00292 void
00293 nsNativeThemeMac::DrawMenu ( const Rect& inBoxRect, PRBool inIsDisabled )
00294 {
00295   ::EraseRect(&inBoxRect);
00296   ThemeMenuType menuType = inIsDisabled ? kThemeMenuTypeInactive : kThemeMenuTypePopUp;
00297   ::DrawThemeMenuBackground(&inBoxRect, menuType);
00298 }
00299 
00300 void
00301 nsNativeThemeMac::DrawMenuItem ( const Rect& inBoxRect, ThemeMenuItemType itemType, PRBool inIsDisabled,
00302                                    PRBool inHover)
00303 {
00304   ThemeMenuState menuItemState;
00305   if (inIsDisabled)
00306     menuItemState = kThemeMenuDisabled;
00307   else if (inHover)
00308     menuItemState = kThemeMenuSelected;
00309   else
00310     menuItemState = kThemeMenuActive;
00311 
00312   // XXXmano: pass the right menu rect!
00313   ::DrawThemeMenuItem(&inBoxRect, &inBoxRect, inBoxRect.top,
00314                       inBoxRect.bottom, menuItemState, itemType, NULL, 0);
00315 }
00316 
00317 NS_IMETHODIMP
00318 nsNativeThemeMac::DrawWidgetBackground(nsIRenderingContext* aContext, nsIFrame* aFrame,
00319                                         PRUint8 aWidgetType, const nsRect& aRect, const nsRect& aClipRect)
00320 {
00321   // setup to draw into the correct port
00322   nsIDrawingSurface* surf;
00323   aContext->GetDrawingSurface(&surf);
00324   nsDrawingSurfaceMac* macSurface = (nsDrawingSurfaceMac*)surf;
00325   CGrafPtr port = nsnull;
00326   NS_ASSERTION(macSurface,"no surface!!!\n");
00327   if ( macSurface )
00328     macSurface->GetGrafPtr(&port);
00329   else
00330     return NS_ERROR_FAILURE;      // we won't get far w/out something to draw into
00331   StPortSetter temp(port);
00332 
00333   // save off the old clip rgn for later restoration. however, we're currently
00334   // not using the cliprect because aqua likes to draw shadows and stuff outside
00335   // the bounds we give it, and clipping to the exact rect looks horrible.
00336   StRegionFromPool oldClip;
00337   ::GetClip(oldClip);
00338 
00339   // transform rect coordinates to correct coord system
00340   nsTransform2D* transformMatrix;
00341   aContext->GetCurrentTransform(transformMatrix);
00342   nsRect transRect(aRect), transClipRect(aClipRect);
00343   Rect macRect;
00344   transformMatrix->TransformCoord(&transRect.x, &transRect.y, &transRect.width, &transRect.height);
00345   ConvertGeckoToNativeRect(transRect, macRect);
00346 #ifdef CLIP_DRAWING
00347   Rect clipRect;
00348   transformMatrix->TransformCoord(&transClipRect.x, &transClipRect.y, &transClipRect.width, &transClipRect.height);
00349   ConvertGeckoToNativeRect(transClipRect, clipRect);
00350   ::ClipRect(&clipRect);
00351 #endif
00352 
00353   PRInt32 eventState = GetContentState(aFrame, aWidgetType);
00354 
00355   switch ( aWidgetType ) {
00356   
00357     case NS_THEME_DIALOG:
00358       ::SetThemeBackground(kThemeBrushDialogBackgroundActive, 24, true);
00359       ::EraseRect(&macRect);
00360       ::SetThemeBackground(kThemeBrushWhite, 24, true);
00361       break;
00362 
00363     case NS_THEME_MENUPOPUP:
00364       ::SetThemeBackground(kThemeBrushDialogBackgroundActive, 24, true);
00365       DrawMenu(macRect, IsDisabled(aFrame));
00366       ::SetThemeBackground(kThemeBrushWhite, 24, true);
00367       break;
00368 
00369     case NS_THEME_MENUITEM:
00370       ::SetThemeBackground(kThemeBrushDialogBackgroundActive, 24, true);
00371       DrawMenuItem(macRect, kThemeMenuItemPlain, IsDisabled(aFrame), CheckBooleanAttr(aFrame, mMenuActiveAtom));
00372       ::SetThemeBackground(kThemeBrushWhite, 24, true);
00373       break;
00374 
00375     case NS_THEME_TOOLTIP:
00376     {
00377       RGBColor yellow = {65535,65535,45000};
00378       ::RGBBackColor(&yellow);
00379       ::EraseRect(&macRect);
00380       ::SetThemeBackground(kThemeBrushWhite, 24, true);
00381       break;
00382     }
00383 
00384     case NS_THEME_CHECKBOX:
00385       DrawCheckbox ( macRect, IsChecked(aFrame), IsDisabled(aFrame), eventState );
00386       break;    
00387     case NS_THEME_RADIO:
00388       DrawRadio ( macRect, IsSelected(aFrame), IsDisabled(aFrame), eventState );
00389       break;
00390     case NS_THEME_CHECKBOX_SMALL:
00391       if (transRect.height == 15) {
00392        // draw at 14x16, see comment in GetMinimumWidgetSize
00393         ++macRect.bottom;
00394       }
00395       DrawSmallCheckbox ( macRect, IsChecked(aFrame), IsDisabled(aFrame), eventState );
00396       break;
00397     case NS_THEME_RADIO_SMALL:
00398       if (transRect.height == 14) {
00399         // draw at 14x15, see comment in GetMinimumWidgetSize
00400         ++macRect.bottom;
00401       }
00402       DrawSmallRadio ( macRect, IsSelected(aFrame), IsDisabled(aFrame), eventState );
00403       break;
00404     case NS_THEME_BUTTON:
00405     case NS_THEME_BUTTON_SMALL:
00406       DrawButton ( kThemePushButton, macRect, IsDefaultButton(aFrame), IsDisabled(aFrame), 
00407                     kThemeButtonOn, kThemeAdornmentNone, eventState );
00408       break;      
00409     case NS_THEME_BUTTON_BEVEL:
00410       DrawButton ( kThemeMediumBevelButton, macRect, IsDefaultButton(aFrame), IsDisabled(aFrame), 
00411                     kThemeButtonOff, kThemeAdornmentNone, eventState );
00412       break;
00413     case NS_THEME_TOOLBAR_BUTTON:
00414       DrawButton ( kThemePushButton, macRect, IsDefaultButton(aFrame), IsDisabled(aFrame),
00415                     kThemeButtonOn, kThemeAdornmentNone, eventState );
00416       break;
00417     case NS_THEME_TOOLBAR_SEPARATOR:
00418       DrawSeparator ( macRect, IsDisabled(aFrame) );
00419       break;
00420       
00421     case NS_THEME_TOOLBAR:
00422     case NS_THEME_TOOLBOX:
00423     case NS_THEME_STATUSBAR:
00424       DrawToolbar ( macRect );
00425       break;
00426       
00427     case NS_THEME_DROPDOWN:
00428       DrawButton ( kThemePopupButton, macRect, IsDefaultButton(aFrame), IsDisabled(aFrame), 
00429                     kThemeButtonOn, kThemeAdornmentNone, eventState );
00430       break;
00431     case NS_THEME_DROPDOWN_BUTTON:
00432       // do nothing, this is covered by the DROPDOWN case
00433       break;
00434 
00435     case NS_THEME_TEXTFIELD:
00436       DrawEditText ( macRect, (IsDisabled(aFrame) || IsReadOnly(aFrame)) );
00437       break;
00438       
00439     case NS_THEME_PROGRESSBAR:
00440       DrawProgress ( macRect, IsDisabled(aFrame), IsIndeterminateProgress(aFrame), PR_TRUE, GetProgressValue(aFrame) );
00441       break;
00442     case NS_THEME_PROGRESSBAR_VERTICAL:
00443       DrawProgress ( macRect, IsDisabled(aFrame), IsIndeterminateProgress(aFrame), PR_FALSE, GetProgressValue(aFrame) );
00444       break;
00445     case NS_THEME_PROGRESSBAR_CHUNK:
00446     case NS_THEME_PROGRESSBAR_CHUNK_VERTICAL:
00447       // do nothing, covered by the progress bar cases above
00448       break;
00449 
00450     case NS_THEME_TREEVIEW_TWISTY:
00451       DrawButton ( kThemeDisclosureButton, macRect, PR_FALSE, IsDisabled(aFrame), 
00452                     kThemeDisclosureRight, kThemeAdornmentNone, eventState );
00453       break;
00454     case NS_THEME_TREEVIEW_TWISTY_OPEN:
00455       DrawButton ( kThemeDisclosureButton, macRect, PR_FALSE, IsDisabled(aFrame), 
00456                     kThemeDisclosureDown, kThemeAdornmentNone, eventState );
00457       break;
00458     case NS_THEME_TREEVIEW_HEADER_CELL:
00459     {
00460       TreeSortDirection sortDirection = GetTreeSortDirection(aFrame);
00461       DrawButton ( kThemeListHeaderButton, macRect, PR_FALSE, IsDisabled(aFrame), 
00462                     sortDirection == eTreeSortDirection_Natural ? kThemeButtonOff : kThemeButtonOn,
00463                     sortDirection == eTreeSortDirection_Descending ?
00464                     kThemeAdornmentHeaderButtonSortUp : kThemeAdornmentNone, eventState );      
00465       break;
00466     }
00467     case NS_THEME_TREEVIEW_TREEITEM:
00468     case NS_THEME_TREEVIEW:
00469       ::SetThemeBackground(kThemeBrushWhite, 24, true);
00470       ::EraseRect ( &macRect );
00471       break;
00472     case NS_THEME_TREEVIEW_HEADER:
00473       // do nothing, taken care of by individual header cells
00474     case NS_THEME_TREEVIEW_HEADER_SORTARROW:
00475       // do nothing, taken care of by treeview header
00476     case NS_THEME_TREEVIEW_LINE:
00477       // do nothing, these lines don't exist on macos
00478       break;
00479     case NS_THEME_SCROLLBAR_GRIPPER_HORIZONTAL:
00480     case NS_THEME_SCROLLBAR_GRIPPER_VERTICAL: 
00481     case NS_THEME_SCROLLBAR_THUMB_VERTICAL:
00482     case NS_THEME_SCROLLBAR_THUMB_HORIZONTAL:
00483     case NS_THEME_SCROLLBAR_BUTTON_UP:
00484     case NS_THEME_SCROLLBAR_BUTTON_DOWN:
00485     case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL:
00486     case NS_THEME_SCROLLBAR_TRACK_VERTICAL:
00487     case NS_THEME_SCROLLBAR_BUTTON_LEFT:
00488     case NS_THEME_SCROLLBAR_BUTTON_RIGHT:
00489       // Scrollbars are now native on mac, via nsNativeScrollbarFrame.
00490       // So, this should never be called.
00491       break;
00492     
00493     case NS_THEME_LISTBOX:
00494       DrawListBox(macRect, IsDisabled(aFrame));
00495       break;
00496     
00497     case NS_THEME_TAB:
00498       DrawTab(macRect, IsDisabled(aFrame), IsSelectedTab(aFrame), PR_TRUE, IsBottomTab(aFrame), eventState);
00499       break;      
00500     case NS_THEME_TAB_PANELS:
00501       DrawTabPanel(macRect, IsDisabled(aFrame));
00502       break;
00503   }
00504 
00505   ::SetClip(oldClip);
00506   
00507   return NS_OK;
00508 }
00509 
00510 
00511 #ifdef XP_MAC
00512 #pragma mark -
00513 #endif
00514 
00515 
00516 NS_IMETHODIMP
00517 nsNativeThemeMac::GetWidgetBorder(nsIDeviceContext* aContext, 
00518                                   nsIFrame* aFrame,
00519                                   PRUint8 aWidgetType,
00520                                   nsMargin* aResult)
00521 {
00522   aResult->SizeTo(0,0,0,0);
00523       
00524   // XXX we should probably cache some of these metrics
00525   
00526   switch ( aWidgetType ) {
00527   
00528     case NS_THEME_BUTTON:
00529       aResult->SizeTo(kAquaPushButtonEndcaps, kAquaPushButtonTopBottom, 
00530                           kAquaPushButtonEndcaps, kAquaPushButtonTopBottom);
00531       break;
00532 
00533     case NS_THEME_BUTTON_SMALL:
00534       aResult->SizeTo(kAquaSmallPushButtonEndcaps, kAquaPushButtonTopBottom,
00535                       kAquaSmallPushButtonEndcaps, kAquaPushButtonTopBottom);
00536       break;
00537 
00538     case NS_THEME_TOOLBAR_BUTTON:
00539       //aResult->SizeTo(5,5,5,5);    // 5px around the button in aqua
00540       break;
00541 
00542     case NS_THEME_DROPDOWN:
00543       aResult->SizeTo(kAquaDropdownLeftEndcap, kAquaPushButtonTopBottom, 
00544                         kAquaDropwdonRightEndcap, kAquaPushButtonTopBottom);
00545       break;
00546     
00547     case NS_THEME_TEXTFIELD:
00548     {
00549       aResult->SizeTo(2, 2, 2, 2);
00550       break;
00551     }
00552 
00553     case NS_THEME_LISTBOX:
00554     {
00555       SInt32 frameOutset = 0;
00556       ::GetThemeMetric(kThemeMetricListBoxFrameOutset, &frameOutset);
00557       aResult->SizeTo(frameOutset, frameOutset, frameOutset, frameOutset);
00558       break;
00559     }
00560       
00561   }
00562   
00563   return NS_OK;
00564 }
00565 
00566 PRBool
00567 nsNativeThemeMac::GetWidgetPadding(nsIDeviceContext* aContext, 
00568                                    nsIFrame* aFrame,
00569                                    PRUint8 aWidgetType,
00570                                    nsMargin* aResult)
00571 {
00572   return PR_FALSE;
00573 }
00574 
00575 NS_IMETHODIMP
00576 nsNativeThemeMac::GetMinimumWidgetSize(nsIRenderingContext* aContext, nsIFrame* aFrame,
00577                                        PRUint8 aWidgetType, nsSize* aResult, PRBool* aIsOverridable)
00578 {
00579   // XXX we should probably cache some of these metrics
00580   aResult->SizeTo(0,0);
00581   *aIsOverridable = PR_TRUE;
00582   
00583   switch ( aWidgetType ) {
00584   
00585     case NS_THEME_BUTTON:
00586     {
00587       SInt32 buttonHeight = 0;
00588       ::GetThemeMetric(kThemeMetricPushButtonHeight, &buttonHeight);
00589       aResult->SizeTo(kAquaPushButtonEndcaps*2, buttonHeight);
00590       break;
00591     }
00592       
00593     case NS_THEME_BUTTON_SMALL:
00594     {
00595       SInt32 buttonHeight = 0;
00596       ::GetThemeMetric(kThemeMetricSmallPushButtonHeight, &buttonHeight);
00597       aResult->SizeTo(kAquaSmallPushButtonEndcaps*2, buttonHeight);
00598       break;
00599     }
00600 
00601     case NS_THEME_CHECKBOX:
00602     {
00603       SInt32 boxHeight = 0, boxWidth = 0;
00604       ::GetThemeMetric(kThemeMetricCheckBoxWidth, &boxWidth);
00605       ::GetThemeMetric(kThemeMetricCheckBoxHeight, &boxHeight);
00606       aResult->SizeTo(boxWidth, boxHeight);
00607       *aIsOverridable = PR_FALSE;
00608       break;
00609     }
00610     
00611     case NS_THEME_RADIO:
00612     {
00613       SInt32 radioHeight = 0, radioWidth = 0;
00614       ::GetThemeMetric(kThemeMetricRadioButtonWidth, &radioWidth);
00615       ::GetThemeMetric(kThemeMetricRadioButtonHeight, &radioHeight);
00616       aResult->SizeTo(radioWidth, radioHeight);
00617       *aIsOverridable = PR_FALSE;
00618       break;
00619     }
00620 
00621     case NS_THEME_CHECKBOX_SMALL:
00622     {
00623       // Appearance manager (and the Aqua HIG) will tell us that a small
00624       // checkbox is 14x16.  This includes a transparent row at the bottom
00625       // of the image.  In order to allow the baseline for text to be aligned
00626       // with the bottom of the checkbox, we report the size as 14x15, but
00627       // we'll always tell appearance manager to draw it at 14x16.  This
00628       // will result in Gecko aligning text with the real bottom of the
00629       // checkbox.
00630 
00631       aResult->SizeTo(14, 15);
00632       *aIsOverridable = PR_FALSE;
00633       break;
00634     }
00635 
00636     case NS_THEME_RADIO_SMALL:
00637     {
00638       // Same as above, but appearance manager reports 14x15, and we
00639       // tell gecko 14x14.
00640 
00641       aResult->SizeTo(14, 14);
00642       *aIsOverridable = PR_FALSE;
00643       break;
00644     }
00645 
00646     case NS_THEME_DROPDOWN:
00647     {
00648       SInt32 popupHeight = 0;
00649       ::GetThemeMetric(kThemeMetricPopupButtonHeight, &popupHeight);
00650       aResult->SizeTo(0, popupHeight);
00651       break;
00652     }
00653     
00654     case NS_THEME_DROPDOWN_BUTTON:
00655       // the drawing for this is done by the dropdown, so just make this
00656       // zero sized.
00657       aResult->SizeTo(0,0);
00658       break;
00659       
00660     case NS_THEME_TEXTFIELD:
00661     {
00662       // at minimum, we should be tall enough for 9pt text.
00663       // I'm using hardcoded values here because the appearance manager
00664       // values for the frame size are incorrect.
00665       aResult->SizeTo(0, (2 + 2) /* top */ + 9 + (1 + 1) /* bottom */ );
00666       break;
00667     }
00668       
00669     case NS_THEME_PROGRESSBAR:
00670     {
00671       SInt32 barHeight = 0;
00672       ::GetThemeMetric(kThemeMetricNormalProgressBarThickness, &barHeight);
00673       aResult->SizeTo(0, barHeight);
00674       break;
00675     }
00676 
00677     case NS_THEME_TREEVIEW_TWISTY:
00678     case NS_THEME_TREEVIEW_TWISTY_OPEN:   
00679     {
00680       SInt32 twistyHeight = 0, twistyWidth = 0;
00681       ::GetThemeMetric(kThemeMetricDisclosureButtonWidth, &twistyWidth);
00682       ::GetThemeMetric(kThemeMetricDisclosureButtonHeight, &twistyHeight);
00683       aResult->SizeTo(twistyWidth, twistyHeight);
00684       *aIsOverridable = PR_FALSE;
00685       break;
00686     }
00687     
00688     case NS_THEME_TREEVIEW_HEADER:
00689     case NS_THEME_TREEVIEW_HEADER_CELL:
00690     {
00691       SInt32 headerHeight = 0;
00692       ::GetThemeMetric(kThemeMetricListHeaderHeight, &headerHeight);
00693       aResult->SizeTo(0, headerHeight);
00694       break;
00695     }
00696       
00697     case NS_THEME_SCROLLBAR:
00698     case NS_THEME_SCROLLBAR_BUTTON_UP:
00699     case NS_THEME_SCROLLBAR_BUTTON_DOWN:
00700     case NS_THEME_SCROLLBAR_BUTTON_LEFT:
00701     case NS_THEME_SCROLLBAR_BUTTON_RIGHT:
00702     case NS_THEME_SCROLLBAR_THUMB_HORIZONTAL:
00703     case NS_THEME_SCROLLBAR_THUMB_VERTICAL:
00704     case NS_THEME_SCROLLBAR_GRIPPER_HORIZONTAL:
00705     case NS_THEME_SCROLLBAR_GRIPPER_VERTICAL:
00706     case NS_THEME_SCROLLBAR_TRACK_VERTICAL:
00707     case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL:
00708     {
00709       // yeah, i know i'm cheating a little here, but i figure that it
00710       // really doesn't matter if the scrollbar is vertical or horizontal
00711       // and the width metric is a really good metric for every piece
00712       // of the scrollbar.
00713       SInt32 scrollbarWidth = 0;
00714       ::GetThemeMetric(kThemeMetricScrollBarWidth, &scrollbarWidth);
00715       aResult->SizeTo(scrollbarWidth, scrollbarWidth);
00716       *aIsOverridable = PR_FALSE;
00717       break;
00718     }
00719 
00720   }
00721 
00722   return NS_OK;
00723 }
00724 
00725 
00726 NS_IMETHODIMP
00727 nsNativeThemeMac::WidgetStateChanged(nsIFrame* aFrame, PRUint8 aWidgetType, 
00728                                      nsIAtom* aAttribute, PRBool* aShouldRepaint)
00729 {
00730   // Some widget types just never change state.
00731   switch ( aWidgetType ) {
00732     case NS_THEME_TOOLBOX:
00733     case NS_THEME_TOOLBAR:
00734     case NS_THEME_TOOLBAR_BUTTON:
00735     case NS_THEME_SCROLLBAR_TRACK_VERTICAL: 
00736     case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL:
00737     case NS_THEME_STATUSBAR:
00738     case NS_THEME_STATUSBAR_PANEL:
00739     case NS_THEME_STATUSBAR_RESIZER_PANEL:
00740     case NS_THEME_PROGRESSBAR_CHUNK:
00741     case NS_THEME_PROGRESSBAR_CHUNK_VERTICAL:
00742     case NS_THEME_PROGRESSBAR:
00743     case NS_THEME_PROGRESSBAR_VERTICAL:
00744     case NS_THEME_TOOLTIP:
00745     case NS_THEME_TAB_PANELS:
00746     case NS_THEME_TAB_PANEL:
00747     case NS_THEME_TEXTFIELD:
00748     case NS_THEME_DIALOG:
00749     case NS_THEME_MENUPOPUP:
00750       *aShouldRepaint = PR_FALSE;
00751       return NS_OK;
00752   }
00753 
00754   // XXXdwh Not sure what can really be done here.  Can at least guess for
00755   // specific widgets that they're highly unlikely to have certain states.
00756   // For example, a toolbar doesn't care about any states.
00757   if (!aAttribute) {
00758     // Hover/focus/active changed.  Always repaint.
00759     *aShouldRepaint = PR_TRUE;
00760   }
00761   else {
00762     // Check the attribute to see if it's relevant.  
00763     // disabled, checked, dlgtype, default, etc.
00764     *aShouldRepaint = PR_FALSE;
00765     if (aAttribute == mDisabledAtom || aAttribute == mCheckedAtom ||
00766         aAttribute == mSelectedAtom || aAttribute == mMenuActiveAtom ||
00767         aAttribute == mSortDirectionAtom)
00768       *aShouldRepaint = PR_TRUE;
00769   }
00770 
00771   return NS_OK;
00772 }
00773 
00774 
00775 NS_IMETHODIMP
00776 nsNativeThemeMac::ThemeChanged()
00777 {
00778   // what do we do here?
00779   return NS_OK;
00780 }
00781 
00782 
00783 PRBool 
00784 nsNativeThemeMac::ThemeSupportsWidget(nsPresContext* aPresContext, nsIFrame* aFrame,
00785                                       PRUint8 aWidgetType)
00786 {
00787 #ifndef MOZ_WIDGET_COCOA
00788   // Only support HTML widgets for Cocoa
00789   if (aFrame && aFrame->GetContent()->IsContentOfType(nsIContent::eHTML))
00790     return PR_FALSE;
00791 #endif
00792 
00793   if (aPresContext && !aPresContext->PresShell()->IsThemeSupportEnabled())
00794     return PR_FALSE;
00795 
00796   PRBool retVal = PR_FALSE;
00797   
00798   switch ( aWidgetType ) {
00799     case NS_THEME_DIALOG:
00800     case NS_THEME_WINDOW:
00801     case NS_THEME_MENUPOPUP:
00802     case NS_THEME_MENUITEM:
00803     case NS_THEME_TOOLTIP:
00804     
00805     case NS_THEME_CHECKBOX:
00806     case NS_THEME_CHECKBOX_SMALL:
00807     case NS_THEME_CHECKBOX_CONTAINER:
00808     case NS_THEME_RADIO:
00809     case NS_THEME_RADIO_SMALL:
00810     case NS_THEME_RADIO_CONTAINER:
00811     case NS_THEME_BUTTON:
00812     case NS_THEME_BUTTON_SMALL:
00813     case NS_THEME_BUTTON_BEVEL:
00814     case NS_THEME_TOOLBAR:
00815     case NS_THEME_STATUSBAR:
00816     case NS_THEME_TEXTFIELD:
00817     //case NS_THEME_TOOLBOX:
00818     //case NS_THEME_TOOLBAR_BUTTON:
00819     case NS_THEME_PROGRESSBAR:
00820     case NS_THEME_PROGRESSBAR_VERTICAL:
00821     case NS_THEME_PROGRESSBAR_CHUNK:
00822     case NS_THEME_PROGRESSBAR_CHUNK_VERTICAL:
00823     case NS_THEME_TOOLBAR_SEPARATOR:
00824     
00825     case NS_THEME_TAB_PANELS:
00826     case NS_THEME_TAB:
00827     case NS_THEME_TAB_LEFT_EDGE:
00828     case NS_THEME_TAB_RIGHT_EDGE:
00829     
00830     case NS_THEME_TREEVIEW_TWISTY:
00831     case NS_THEME_TREEVIEW_TWISTY_OPEN:
00832     case NS_THEME_TREEVIEW:
00833     case NS_THEME_TREEVIEW_HEADER:
00834     case NS_THEME_TREEVIEW_HEADER_CELL:
00835     case NS_THEME_TREEVIEW_HEADER_SORTARROW:
00836     case NS_THEME_TREEVIEW_TREEITEM:
00837     case NS_THEME_TREEVIEW_LINE:
00838     
00839     case NS_THEME_SCROLLBAR:
00840     case NS_THEME_SCROLLBAR_BUTTON_UP:
00841     case NS_THEME_SCROLLBAR_BUTTON_DOWN:
00842     case NS_THEME_SCROLLBAR_BUTTON_LEFT:
00843     case NS_THEME_SCROLLBAR_BUTTON_RIGHT:
00844     case NS_THEME_SCROLLBAR_THUMB_HORIZONTAL:
00845     case NS_THEME_SCROLLBAR_THUMB_VERTICAL:
00846     case NS_THEME_SCROLLBAR_GRIPPER_HORIZONTAL:
00847     case NS_THEME_SCROLLBAR_GRIPPER_VERTICAL:
00848     case NS_THEME_SCROLLBAR_TRACK_VERTICAL:
00849     case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL:
00850       retVal = PR_TRUE;
00851       break;
00852 
00853     case NS_THEME_LISTBOX:
00854     case NS_THEME_DROPDOWN:
00855     case NS_THEME_DROPDOWN_BUTTON:
00856     case NS_THEME_DROPDOWN_TEXT:
00857       // Support listboxes and dropdowns regardless of styling,
00858       // since non-themed ones look totally wrong.
00859       return PR_TRUE;
00860   }
00861 
00862   return retVal ? !IsWidgetStyled(aPresContext, aFrame, aWidgetType) : PR_FALSE;
00863 }
00864 
00865 
00866 PRBool
00867 nsNativeThemeMac::WidgetIsContainer(PRUint8 aWidgetType)
00868 {
00869   // XXXdwh At some point flesh all of this out.
00870   switch ( aWidgetType ) {
00871    case NS_THEME_DROPDOWN_BUTTON:
00872    case NS_THEME_RADIO:
00873    case NS_THEME_CHECKBOX:
00874    case NS_THEME_PROGRESSBAR:
00875     return PR_FALSE;
00876     break;
00877   }
00878   return PR_TRUE;
00879 }