Back to index

lightning-sunbird  0.9+nobinonly
nsDeviceContextWin.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 
00038 #include "nsDeviceContextWin.h"
00039 #include "nsRenderingContextWin.h"
00040 #include "nsDeviceContextSpecWin.h"
00041 #include "nsIServiceManager.h"
00042 #include "nsCOMPtr.h"
00043 #include "nsIScreenManager.h"
00044 #include "nsIScreen.h"
00045 #include "nsGfxCIID.h"
00046 #include "nsReadableUtils.h"
00047 
00048 #include "nsString.h"
00049 
00050 #if defined(DEBUG_rods) && defined(MOZ_LAYOUTDEBUG)
00051 #include "nsIDebugObject.h"
00052 #endif
00053 
00054 #define DOC_TITLE_LENGTH      64
00055 
00056 #include "prlog.h"
00057 #ifdef PR_LOGGING 
00058 PRLogModuleInfo * kGfxPrintingLogMod = PR_NewLogModule("printing-gfx");
00059 #define PR_PL(_p1)  PR_LOG(kGfxPrintingLogMod, PR_LOG_DEBUG, _p1)
00060 #else
00061 #define PR_PL(_p1)
00062 #endif
00063 
00064 nsDeviceContextWin :: nsDeviceContextWin()
00065   : DeviceContextImpl()
00066 {
00067   mSurface = NULL;
00068   mPaletteInfo.isPaletteDevice = PR_FALSE;
00069   mPaletteInfo.sizePalette = 0;
00070   mPaletteInfo.numReserved = 0;
00071   mPaletteInfo.palette = NULL;
00072   mDC = NULL;
00073   mPixelScale = 1.0f;
00074   mWidth = -1;
00075   mHeight = -1;
00076   mSpec = nsnull;
00077   mCachedClientRect = PR_FALSE;
00078   mCachedFullRect = PR_FALSE;
00079 }
00080 
00081 nsDeviceContextWin :: ~nsDeviceContextWin()
00082 {
00083   nsDrawingSurfaceWin *surf = (nsDrawingSurfaceWin *)mSurface;
00084 
00085   NS_IF_RELEASE(surf);    //this clears the surf pointer...
00086   mSurface = nsnull;
00087 
00088   if (NULL != mPaletteInfo.palette)
00089     ::DeleteObject((HPALETTE)mPaletteInfo.palette);
00090 
00091   if (NULL != mDC)
00092   {
00093     ::DeleteDC(mDC);
00094     mDC = NULL;
00095   }
00096 
00097   NS_IF_RELEASE(mSpec);
00098 }
00099 
00100 NS_IMETHODIMP nsDeviceContextWin :: Init(nsNativeWidget aWidget)
00101 {
00102   mWidget = aWidget;
00103 
00104   HWND  hwnd = (HWND)aWidget;
00105   HDC   hdc = ::GetDC(hwnd);
00106 
00107   CommonInit(hdc);
00108 
00109   ::ReleaseDC(hwnd, hdc);
00110 
00111   return NS_OK;
00112 }
00113 
00114 //local method...
00115 
00116 nsresult nsDeviceContextWin :: Init(nsNativeDeviceContext aContext, nsIDeviceContext *aOrigContext)
00117 {
00118   float origscale, newscale;
00119   float t2d, a2d;
00120 
00121   mDC = (HDC)aContext;
00122 
00123   CommonInit(mDC);
00124 
00125 
00126   newscale = TwipsToDevUnits();
00127   origscale = aOrigContext->TwipsToDevUnits();
00128 
00129   mPixelScale = newscale / origscale;
00130 
00131   t2d = aOrigContext->TwipsToDevUnits();
00132   a2d = aOrigContext->AppUnitsToDevUnits();
00133 
00134   mAppUnitsToDevUnits = (a2d / t2d) * mTwipsToPixels;
00135   mDevUnitsToAppUnits = 1.0f / mAppUnitsToDevUnits;
00136 
00137   return NS_OK;
00138 }
00139 
00140 void nsDeviceContextWin :: CommonInit(HDC aDC)
00141 {
00142   int   rasterCaps = ::GetDeviceCaps(aDC, RASTERCAPS);
00143 
00144   mDepth = (PRUint32)::GetDeviceCaps(aDC, BITSPIXEL);
00145   mPaletteInfo.isPaletteDevice = RC_PALETTE == (rasterCaps & RC_PALETTE);
00146   mPaletteInfo.sizePalette = (PRUint16)::GetDeviceCaps(aDC, SIZEPALETTE);
00147   mPaletteInfo.numReserved = (PRUint16)::GetDeviceCaps(aDC, NUMRESERVED);
00148 
00149   mWidth = ::GetDeviceCaps(aDC, HORZRES);
00150   mHeight = ::GetDeviceCaps(aDC, VERTRES);
00151 
00152   mPixelsToTwips = (float)NSIntPointsToTwips(72) / ((float)::GetDeviceCaps(aDC, LOGPIXELSY));
00153   if (::GetDeviceCaps(aDC, TECHNOLOGY) == DT_RASDISPLAY)
00154   {
00155     // Ensure that, for screens, pixels-to-twips is an integer
00156     mPixelsToTwips = NSToIntRound(mPixelsToTwips);
00157 
00158     // init the screen manager and compute our client rect based on the
00159     // screen objects. We'll save the result 
00160     nsresult ignore;
00161     mScreenManager = do_GetService("@mozilla.org/gfx/screenmanager;1", &ignore);   
00162   } // if this dc is not a print device
00163   mTwipsToPixels = 1.0 / mPixelsToTwips;
00164 
00165   DeviceContextImpl::CommonInit();
00166 }
00167 
00168 
00169 void
00170 nsDeviceContextWin :: ComputeClientRectUsingScreen ( nsRect* outRect )
00171 {
00172   // we always need to recompute the clientRect
00173   // because the window may have moved onto a different screen. In the single
00174   // monitor case, we only need to do the computation if we haven't done it
00175   // once already, and remember that we have because we're assured it won't change.
00176   nsCOMPtr<nsIScreen> screen;
00177   FindScreen ( getter_AddRefs(screen) );
00178   if ( screen ) {
00179     PRInt32 x, y, width, height;
00180     screen->GetAvailRect ( &x, &y, &width, &height );
00181   
00182     // convert to device units
00183     outRect->y = NSToIntRound(y * mDevUnitsToAppUnits);
00184     outRect->x = NSToIntRound(x * mDevUnitsToAppUnits);
00185     outRect->width = NSToIntRound(width * mDevUnitsToAppUnits);
00186     outRect->height = NSToIntRound(height * mDevUnitsToAppUnits);
00187 
00188     mCachedClientRect = PR_TRUE;
00189     mClientRect = *outRect;
00190   }
00191 
00192 } // ComputeClientRectUsingScreen
00193 
00194 
00195 void
00196 nsDeviceContextWin :: ComputeFullAreaUsingScreen ( nsRect* outRect )
00197 {
00198   // if we have more than one screen, we always need to recompute the clientRect
00199   // because the window may have moved onto a different screen. In the single
00200   // monitor case, we only need to do the computation if we haven't done it
00201   // once already, and remember that we have because we're assured it won't change.
00202   nsCOMPtr<nsIScreen> screen;
00203   FindScreen ( getter_AddRefs(screen) );
00204   if ( screen ) {
00205     PRInt32 x, y, width, height;
00206     screen->GetRect ( &x, &y, &width, &height );
00207   
00208     // convert to device units
00209     outRect->y = NSToIntRound(y * mDevUnitsToAppUnits);
00210     outRect->x = NSToIntRound(x * mDevUnitsToAppUnits);
00211     outRect->width = NSToIntRound(width * mDevUnitsToAppUnits);
00212     outRect->height = NSToIntRound(height * mDevUnitsToAppUnits);
00213 
00214     mWidth = width;
00215     mHeight = height;
00216     mCachedFullRect = PR_TRUE;
00217   }
00218  
00219 } // ComputeFullRectUsingScreen
00220 
00221 
00222 //
00223 // FindScreen
00224 //
00225 // Determines which screen intersects the largest area of the given surface.
00226 //
00227 void
00228 nsDeviceContextWin :: FindScreen ( nsIScreen** outScreen )
00229 {
00230   // now then, if we have more than one screen, we need to find which screen this
00231   // window is on.
00232   HWND window = NS_REINTERPRET_CAST(HWND, mWidget);
00233   if ( window ) {
00234     RECT globalPosition;
00235     ::GetWindowRect ( window, &globalPosition ); 
00236     if ( mScreenManager )
00237       mScreenManager->ScreenForRect ( globalPosition.left, globalPosition.top, 
00238                                        globalPosition.right - globalPosition.left,
00239                                        globalPosition.bottom - globalPosition.top, outScreen );
00240   }
00241 
00242 } // FindScreen
00243 
00244 
00245 static NS_DEFINE_CID(kRCCID,NS_RENDERING_CONTEXT_CID);
00246 
00247 NS_IMETHODIMP nsDeviceContextWin :: CreateRenderingContext(nsIRenderingContext *&aContext)
00248 {
00249 #ifdef NS_PRINT_PREVIEW
00250   // Defer to Alt when there is one
00251   if (mAltDC && ((mUseAltDC & kUseAltDCFor_CREATERC_PAINT) || (mUseAltDC & kUseAltDCFor_CREATERC_REFLOW))) {
00252     return mAltDC->CreateRenderingContext(aContext);
00253   }
00254 #endif
00255 
00256   nsIRenderingContext *pContext;
00257   nsresult             rv;
00258   nsDrawingSurfaceWin  *surf;
00259 
00260   rv = CallCreateInstance(kRCCID, &pContext);
00261 
00262   if ( (NS_SUCCEEDED(rv)) && (nsnull != pContext))
00263   {
00264     surf = new nsDrawingSurfaceWin();
00265 
00266     if (nsnull != surf)
00267     {
00268       rv = surf->Init(mDC);
00269 
00270       if (NS_OK == rv)
00271         rv = pContext->Init(this, surf);
00272     }
00273     else
00274       rv = NS_ERROR_OUT_OF_MEMORY;
00275   }
00276   else
00277     rv = NS_ERROR_OUT_OF_MEMORY;
00278 
00279   if (NS_OK != rv)
00280   {
00281     NS_IF_RELEASE(pContext);
00282   }
00283 
00284   aContext = pContext;
00285 
00286   return rv;
00287 }
00288 
00289 NS_IMETHODIMP nsDeviceContextWin :: SupportsNativeWidgets(PRBool &aSupportsWidgets)
00290 {
00291   if (nsnull == mDC)
00292     aSupportsWidgets = PR_TRUE;
00293   else
00294     aSupportsWidgets = PR_FALSE;
00295 
00296   return NS_OK;
00297 }
00298 
00299 NS_IMETHODIMP nsDeviceContextWin :: GetCanonicalPixelScale(float &aScale) const
00300 {
00301   aScale = mPixelScale;
00302   return NS_OK;
00303 }
00304 
00305 NS_IMETHODIMP nsDeviceContextWin :: SetCanonicalPixelScale(float aScale)
00306 {
00307   DeviceContextImpl::SetCanonicalPixelScale(aScale);
00308   mPixelScale = aScale;
00309   return NS_OK;
00310 }
00311 
00312 
00313 NS_IMETHODIMP nsDeviceContextWin :: GetScrollBarDimensions(float &aWidth, float &aHeight) const
00314 {
00315   float scale;
00316   GetCanonicalPixelScale(scale);
00317 
00318   aWidth  = ::GetSystemMetrics(SM_CXVSCROLL) * mDevUnitsToAppUnits * scale;
00319   aHeight = ::GetSystemMetrics(SM_CXHSCROLL) * mDevUnitsToAppUnits * scale;
00320 
00321   return NS_OK;
00322 }
00323 
00324 nsresult nsDeviceContextWin::CopyLogFontToNSFont(HDC* aHDC, const LOGFONT* ptrLogFont,
00325                                                  nsFont* aFont, PRBool aIsWide) const
00326 {
00327   PRUnichar name[LF_FACESIZE];
00328   name[0] = 0;
00329   if (aIsWide)
00330     memcpy(name, ptrLogFont->lfFaceName, LF_FACESIZE*2);
00331   else {
00332     MultiByteToWideChar(CP_ACP, 0, ptrLogFont->lfFaceName,
00333       strlen(ptrLogFont->lfFaceName) + 1, name, sizeof(name)/sizeof(name[0]));
00334   }
00335   aFont->name = name;
00336 
00337   // Do Style
00338   aFont->style = NS_FONT_STYLE_NORMAL;
00339   if (ptrLogFont->lfItalic)
00340   {
00341     aFont->style = NS_FONT_STYLE_ITALIC;
00342   }
00343   // XXX What about oblique?
00344 
00345   aFont->variant = NS_FONT_VARIANT_NORMAL;
00346 
00347   // Do Weight
00348   aFont->weight = (ptrLogFont->lfWeight == FW_BOLD ? 
00349             NS_FONT_WEIGHT_BOLD : NS_FONT_WEIGHT_NORMAL);
00350 
00351   // Do decorations
00352   aFont->decorations = NS_FONT_DECORATION_NONE;
00353   if (ptrLogFont->lfUnderline)
00354   {
00355     aFont->decorations |= NS_FONT_DECORATION_UNDERLINE;
00356   }
00357   if (ptrLogFont->lfStrikeOut)
00358   {
00359     aFont->decorations |= NS_FONT_DECORATION_LINE_THROUGH;
00360   }
00361 
00362   // Do Point Size
00363   //
00364   // The lfHeight is in pixel and it needs to be adjusted for the
00365   // device it will be "displayed" on
00366   // Screens and Printers will differe in DPI
00367   //
00368   // So this accounts for the difference in the DeviceContexts
00369   // The mPixelScale will be a "1" for the screen and could be
00370   // any value when going to a printer, for example mPixleScale is
00371   // 6.25 when going to a 600dpi printer.
00372   // round, but take into account whether it is negative
00373   float pixelHeight = -ptrLogFont->lfHeight;
00374   if (pixelHeight < 0) {
00375     HFONT hFont = ::CreateFontIndirect(ptrLogFont);
00376     if (!hFont)
00377       return NS_ERROR_OUT_OF_MEMORY;
00378     HGDIOBJ hObject = ::SelectObject(*aHDC, hFont);
00379     TEXTMETRIC tm;
00380     ::GetTextMetrics(*aHDC, &tm);
00381     ::SelectObject(*aHDC, hObject);
00382     ::DeleteObject(hFont);
00383     pixelHeight = tm.tmAscent;
00384   }
00385 
00386   float pointSize = pixelHeight * mPixelScale * 72 / ::GetDeviceCaps(*aHDC, LOGPIXELSY);
00387 
00388   // we have problem on Simplified Chinese system because the system report
00389   // the default font size is 8. but if we use 8, the text display very
00390   // Ugly. force it to be at 9 on that system (cp936), but leave other sizes alone.
00391   if ((pointSize < 9) && 
00392       (936 == ::GetACP())) 
00393     pointSize = 9;
00394 
00395   aFont->size = NSFloatPointsToTwips(pointSize);
00396   return NS_OK;
00397 }
00398 
00399 nsresult nsDeviceContextWin :: GetSysFontInfo(HDC aHDC, nsSystemFontID anID, nsFont* aFont) const
00400 {
00401   HGDIOBJ hGDI;
00402 
00403   LOGFONT logFont;
00404   LOGFONT* ptrLogFont = NULL;
00405 
00406 #ifdef WINCE
00407   hGDI = ::GetStockObject(SYSTEM_FONT);
00408   if (hGDI == NULL)
00409     return NS_ERROR_UNEXPECTED;
00410   
00411   if (::GetObject(hGDI, sizeof(logFont), &logFont) > 0)
00412     ptrLogFont = &logFont;
00413 #else
00414 
00415   NONCLIENTMETRICS ncm;
00416 
00417   BOOL status;
00418   if (anID == eSystemFont_Icon) 
00419   {
00420     status = ::SystemParametersInfo(SPI_GETICONTITLELOGFONT,
00421                                   sizeof(logFont),
00422                                   (PVOID)&logFont,
00423                                   0);
00424   }
00425   else
00426   {
00427     ncm.cbSize = sizeof(NONCLIENTMETRICS);
00428     status = ::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 
00429                                      sizeof(ncm),  
00430                                      (PVOID)&ncm, 
00431                                      0);
00432   }
00433 
00434   if (!status)
00435   {
00436     return NS_ERROR_FAILURE;
00437   }
00438 
00439   switch (anID)
00440   {
00441     // Caption in CSS is NOT the same as Caption on Windows
00442     //case eSystemFont_Caption: 
00443     //  ptrLogFont = &ncm.lfCaptionFont;
00444     //  break;
00445 
00446     case eSystemFont_Icon: 
00447       ptrLogFont = &logFont;
00448       break;
00449 
00450     case eSystemFont_Menu: 
00451       ptrLogFont = &ncm.lfMenuFont;
00452       break;
00453 
00454     case eSystemFont_MessageBox: 
00455       ptrLogFont = &ncm.lfMessageFont;
00456       break;
00457 
00458     case eSystemFont_SmallCaption: 
00459       ptrLogFont = &ncm.lfSmCaptionFont;
00460       break;
00461 
00462     case eSystemFont_StatusBar: 
00463     case eSystemFont_Tooltips: 
00464       ptrLogFont = &ncm.lfStatusFont;
00465       break;
00466 
00467     case eSystemFont_Widget:
00468 
00469     case eSystemFont_Window:      // css3
00470     case eSystemFont_Document:
00471     case eSystemFont_Workspace:
00472     case eSystemFont_Desktop:
00473     case eSystemFont_Info:
00474     case eSystemFont_Dialog:
00475     case eSystemFont_Button:
00476     case eSystemFont_PullDownMenu:
00477     case eSystemFont_List:
00478     case eSystemFont_Field:
00479     case eSystemFont_Caption: 
00480       hGDI = ::GetStockObject(DEFAULT_GUI_FONT);
00481       if (hGDI != NULL)
00482       {
00483         if (::GetObject(hGDI, sizeof(logFont), &logFont) > 0)
00484         { 
00485           ptrLogFont = &logFont;
00486         }
00487       }
00488       break;
00489   } // switch 
00490 
00491 #endif // WINCE
00492 
00493   if (nsnull == ptrLogFont)
00494   {
00495     return NS_ERROR_FAILURE;
00496   }
00497 
00498   aFont->systemFont = PR_TRUE;
00499 
00500   return CopyLogFontToNSFont(&aHDC, ptrLogFont, aFont);
00501 }
00502 
00503 NS_IMETHODIMP nsDeviceContextWin :: GetSystemFont(nsSystemFontID anID, nsFont *aFont) const
00504 {
00505   nsresult status = NS_OK;
00506 
00507   switch (anID) {
00508     case eSystemFont_Caption: 
00509     case eSystemFont_Icon: 
00510     case eSystemFont_Menu: 
00511     case eSystemFont_MessageBox: 
00512     case eSystemFont_SmallCaption: 
00513     case eSystemFont_StatusBar: 
00514     case eSystemFont_Tooltips: 
00515     case eSystemFont_Widget:
00516 
00517     case eSystemFont_Window:      // css3
00518     case eSystemFont_Document:
00519     case eSystemFont_Workspace:
00520     case eSystemFont_Desktop:
00521     case eSystemFont_Info:
00522     case eSystemFont_Dialog:
00523     case eSystemFont_Button:
00524     case eSystemFont_PullDownMenu:
00525     case eSystemFont_List:
00526     case eSystemFont_Field:
00527     {
00528       HWND  hwnd;
00529       HDC   tdc;
00530 
00531       if (nsnull == mDC)
00532       {
00533         hwnd = (HWND)mWidget;
00534         tdc = ::GetDC(hwnd);
00535       }
00536       else
00537         tdc = mDC;
00538 
00539       status = GetSysFontInfo(tdc, anID, aFont);
00540 
00541       if (nsnull == mDC)
00542         ::ReleaseDC(hwnd, tdc);
00543 
00544       break;
00545     }
00546   }
00547 
00548   return status;
00549 }
00550 
00551 NS_IMETHODIMP nsDeviceContextWin :: GetDrawingSurface(nsIRenderingContext &aContext, nsIDrawingSurface* &aSurface)
00552 {
00553   if (NULL == mSurface) {
00554     nsRect empty(0,0,0,0); // CreateDrawingSurface(null,...) used width=0,height=0
00555     aContext.CreateDrawingSurface(empty, 0, mSurface);
00556   }
00557 
00558   aSurface = mSurface;
00559   return NS_OK;
00560 }
00561 
00562 int CALLBACK fontcallback(ENUMLOGFONT FAR *lpelf, NEWTEXTMETRIC FAR *lpntm,
00563                           int FontType, LPARAM lParam)  
00564 {
00565   if (NULL != lpelf)
00566     *((PRBool *)lParam) = PR_TRUE;
00567 
00568   return 0;
00569 }
00570 
00571 NS_IMETHODIMP nsDeviceContextWin :: CheckFontExistence(const nsString& aFontName)
00572 {
00573   HWND    hwnd = (HWND)mWidget;
00574   HDC     hdc = ::GetDC(hwnd);
00575   PRBool  isthere = PR_FALSE;
00576 
00577   LOGFONT logFont;
00578   logFont.lfCharSet = DEFAULT_CHARSET;
00579   logFont.lfPitchAndFamily = 0;
00580   int outlen = WideCharToMultiByte(CP_ACP, 0, aFontName.get(), aFontName.Length() + 1,
00581                                    logFont.lfFaceName, sizeof(logFont.lfFaceName), nsnull, nsnull);
00582 
00583   // somehow the WideCharToMultiByte failed, let's try the old code
00584   if(0 == outlen)
00585     aFontName.ToCString(logFont.lfFaceName, LF_FACESIZE);
00586 
00587   ::EnumFontFamiliesEx(hdc, &logFont, (FONTENUMPROC)fontcallback, (LPARAM)&isthere, 0);
00588 
00589   ::ReleaseDC(hwnd, hdc);
00590 
00591   if (PR_TRUE == isthere)
00592     return NS_OK;
00593   else
00594     return NS_ERROR_FAILURE;
00595 }
00596 
00597 NS_IMETHODIMP nsDeviceContextWin::GetDepth(PRUint32& aDepth)
00598 {
00599   aDepth = mDepth;
00600   return NS_OK;
00601 }
00602 
00603 
00604 NS_IMETHODIMP nsDeviceContextWin::GetPaletteInfo(nsPaletteInfo& aPaletteInfo)
00605 {
00606   aPaletteInfo.isPaletteDevice = mPaletteInfo.isPaletteDevice;
00607   aPaletteInfo.sizePalette = mPaletteInfo.sizePalette;
00608   aPaletteInfo.numReserved = mPaletteInfo.numReserved;
00609 
00610   if (NULL == mPaletteInfo.palette) {
00611 #ifndef WINCE
00612     HWND    hwnd = (HWND)mWidget;
00613     HDC     hdc = ::GetDC(hwnd);
00614     mPaletteInfo.palette = ::CreateHalftonePalette(hdc);  
00615     ::ReleaseDC(hwnd, hdc);                                                     
00616 #else
00617     mPaletteInfo.palette = (HPALETTE) GetStockObject(DEFAULT_PALETTE);
00618 #endif
00619   }
00620 
00621   aPaletteInfo.palette = mPaletteInfo.palette;
00622                                          
00623   return NS_OK;
00624 }
00625 
00626 NS_IMETHODIMP nsDeviceContextWin :: GetDeviceSurfaceDimensions(PRInt32 &aWidth, PRInt32 &aHeight)
00627 {
00628 #ifdef NS_PRINT_PREVIEW
00629   // Defer to Alt when there is one
00630   if (mAltDC && (mUseAltDC & kUseAltDCFor_SURFACE_DIM)) {
00631     return mAltDC->GetDeviceSurfaceDimensions(aWidth, aHeight);
00632   }
00633 #endif
00634 
00635   if ( mSpec )
00636   {
00637     // we have a printer device
00638     aWidth = NSToIntRound(mWidth * mDevUnitsToAppUnits);
00639     aHeight = NSToIntRound(mHeight * mDevUnitsToAppUnits);
00640   } 
00641   else 
00642   {
00643     nsRect area;
00644     ComputeFullAreaUsingScreen ( &area );
00645     aWidth = area.width;
00646     aHeight = area.height;
00647   }
00648 
00649   return NS_OK;
00650 }
00651 
00652 
00653 NS_IMETHODIMP nsDeviceContextWin :: GetRect(nsRect &aRect)
00654 {
00655   if ( mSpec )
00656   {
00657     // we have a printer device
00658     aRect.x = 0;
00659     aRect.y = 0;
00660     aRect.width = NSToIntRound(mWidth * mDevUnitsToAppUnits);
00661     aRect.height = NSToIntRound(mHeight * mDevUnitsToAppUnits);
00662   }
00663   else
00664     ComputeFullAreaUsingScreen ( &aRect );
00665 
00666   return NS_OK;
00667 }
00668 
00669 
00670 NS_IMETHODIMP nsDeviceContextWin :: GetClientRect(nsRect &aRect)
00671 {
00672   if ( mSpec )
00673   {
00674     // we have a printer device
00675     aRect.x = 0;
00676     aRect.y = 0;
00677     aRect.width = NSToIntRound(mWidth * mDevUnitsToAppUnits);
00678     aRect.height = NSToIntRound(mHeight * mDevUnitsToAppUnits);
00679   }
00680   else
00681     ComputeClientRectUsingScreen ( &aRect );
00682 
00683   return NS_OK;
00684 }
00685 
00686 BOOL CALLBACK abortproc( HDC hdc, int iError )
00687 {
00688   return TRUE;
00689 } 
00690  
00691 NS_IMETHODIMP nsDeviceContextWin :: GetDeviceContextFor(nsIDeviceContextSpec *aDevice,
00692                                                         nsIDeviceContext *&aContext)
00693 {
00694   nsDeviceContextWin* devConWin = new nsDeviceContextWin(); //ref count 0 
00695   if (devConWin != nsnull) {
00696     // this will ref count it
00697     nsresult rv = devConWin->QueryInterface(NS_GET_IID(nsIDeviceContext), (void**)&aContext);
00698     NS_ASSERTION(NS_SUCCEEDED(rv), "This has to support nsIDeviceContext");
00699   } else {
00700     return NS_ERROR_OUT_OF_MEMORY;
00701   }
00702 
00703   devConWin->mSpec = aDevice;
00704   NS_ADDREF(aDevice);
00705  
00706   char*   devicename;
00707   char*   drivername;
00708 
00709   nsDeviceContextSpecWin* devSpecWin = NS_STATIC_CAST(nsDeviceContextSpecWin*, aDevice);
00710   devSpecWin->GetDeviceName(devicename); // sets pointer do not free
00711   devSpecWin->GetDriverName(drivername); // sets pointer do not free
00712 
00713   HDC dc = NULL;
00714   LPDEVMODE devmode;
00715   devSpecWin->GetDevMode(devmode);
00716   NS_ASSERTION(devmode, "DevMode can't be NULL here");
00717   if (devmode) {
00718     dc = ::CreateDC(drivername, devicename, NULL, devmode);
00719   }
00720 
00721   return devConWin->Init(dc, this); // take ownership of the DC
00722 }
00723 
00724 #if defined(DEBUG_rods) || defined(DEBUG_dcone)
00725 static void DisplayLastError()
00726 {
00727   LPVOID lpMsgBuf;
00728   DWORD errCode = GetLastError();
00729 
00730   FormatMessage( 
00731       FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
00732       NULL,
00733       GetLastError(),
00734       MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
00735       (LPTSTR) &lpMsgBuf,
00736       0,
00737       NULL 
00738   );
00739 
00740   // Display the string.
00741   MessageBox( NULL, (const char *)lpMsgBuf, "GetLastError", MB_OK|MB_ICONINFORMATION );
00742 }
00743 #define DISPLAY_LAST_ERROR DisplayLastError();
00744 #else
00745 #define DISPLAY_LAST_ERROR 
00746 #endif
00747 
00748 
00749 NS_IMETHODIMP nsDeviceContextWin :: BeginDocument(PRUnichar * aTitle, PRUnichar* aPrintToFileName, PRInt32 aStartPage, PRInt32 aEndPage)
00750 {
00751   nsresult rv = NS_ERROR_GFX_PRINTER_STARTDOC;
00752 
00753   if (NULL != mDC) {
00754     DOCINFO docinfo;
00755 
00756     nsString titleStr;
00757     titleStr = aTitle;
00758     if (titleStr.Length() > DOC_TITLE_LENGTH) {
00759       titleStr.SetLength(DOC_TITLE_LENGTH-3);
00760       titleStr.AppendLiteral("...");
00761     }
00762     char *title = GetACPString(titleStr);
00763 
00764     char* docName = nsnull;
00765     nsAutoString str(aPrintToFileName);
00766     if (!str.IsEmpty()) {
00767       docName = ToNewCString(str);
00768     }
00769     docinfo.cbSize = sizeof(docinfo);
00770     docinfo.lpszDocName = title != nsnull?title:"Mozilla Document";
00771 
00772 #ifdef DEBUG_rods
00773     docinfo.lpszOutput = "\\p.ps";
00774 
00775 #ifdef MOZ_LAYOUTDEBUG
00776     // This is for overriding the above when doing the runtime checking
00777     char * tempFileName = nsnull;
00778     nsCOMPtr<nsIDebugObject>debugObj = do_GetService("@mozilla.org/debug/debugobject;1");
00779     if (debugObj) {
00780       PRBool isDoingTests;
00781       if (NS_SUCCEEDED(debugObj->GetDoRuntimeTests(&isDoingTests)) && isDoingTests) {
00782         PRUnichar * name;
00783         debugObj->GetPrintFileName(&name);
00784         if (name) {
00785           if (*name) {
00786             nsCString cStrName;
00787             cStrName.AssignWithConversion(name);
00788             tempFileName = ToNewCString(cStrName);
00789           }
00790           nsMemory::Free(name);
00791         }
00792         docinfo.lpszOutput = tempFileName;
00793       }
00794     }
00795 #endif
00796 
00797 #else
00798     docinfo.lpszOutput = docName;
00799 #endif
00800 
00801     docinfo.lpszDatatype = NULL;
00802     docinfo.fwType = 0;
00803 
00804     if (::StartDoc(mDC, &docinfo) > 0) {
00805       rv = NS_OK;
00806     } else {
00807       DISPLAY_LAST_ERROR
00808       rv = NS_ERROR_GFX_PRINTER_STARTDOC;
00809       PR_PL(("nsDeviceContextWin::BeginDocument - StartDoc Error!\n"));
00810     }
00811 
00812     if (title != nsnull) delete [] title;
00813     if (docName != nsnull) nsMemory::Free(docName);
00814 
00815 #if defined(DEBUG_rods) && defined(MOZ_LAYOUTDEBUG)
00816     if (tempFileName) {
00817       nsMemory::Free(tempFileName);
00818     }
00819 #endif
00820   }
00821 
00822   return rv;
00823 }
00824 
00825 NS_IMETHODIMP nsDeviceContextWin :: EndDocument(void)
00826 {
00827   if (NULL != mDC)
00828   {
00829     if (::EndDoc(mDC) > 0) {
00830       return NS_OK;
00831     } else {
00832       DISPLAY_LAST_ERROR
00833       PR_PL(("nsDeviceContextWin::EndDocument - EndDoc Error!\n"));
00834       return NS_ERROR_GFX_PRINTER_ENDDOC;
00835     }
00836   }
00837 
00838   return NS_OK;
00839 }
00840 
00841 NS_IMETHODIMP nsDeviceContextWin :: AbortDocument(void)
00842 {
00843   if (NULL != mDC)
00844   {
00845     if (::AbortDoc(mDC) > 0) {
00846       return NS_OK;
00847     } else {
00848       DISPLAY_LAST_ERROR
00849       PR_PL(("nsDeviceContextWin::AbortDocument - AbortDoc Error!\n"));
00850       return NS_ERROR_ABORT;
00851     }
00852   }
00853 
00854   return NS_OK;
00855 }
00856 
00857 NS_IMETHODIMP nsDeviceContextWin :: BeginPage(void)
00858 {
00859   if (NULL != mDC)
00860   {
00861     if (::StartPage(mDC) > 0)
00862       return NS_OK;
00863     else {
00864       DISPLAY_LAST_ERROR
00865       PR_PL(("nsDeviceContextWin::BeginPage - StartPage Error!\n"));
00866       return NS_ERROR_GFX_PRINTER_STARTPAGE;
00867     }
00868   }
00869 
00870   return NS_OK;
00871 }
00872 
00873 NS_IMETHODIMP nsDeviceContextWin :: EndPage(void)
00874 {
00875   if (NULL != mDC)
00876   {
00877     if (::EndPage(mDC) > 0) {
00878       return NS_OK;
00879     } else {
00880       DISPLAY_LAST_ERROR
00881       PR_PL(("nsDeviceContextWin::EndPage - EndPage Error!\n"));
00882       return NS_ERROR_GFX_PRINTER_ENDPAGE;
00883     }
00884   }
00885 
00886   return NS_OK;
00887 }
00888 
00889 char*
00890 nsDeviceContextWin :: GetACPString(const nsAString& aStr)
00891 {
00892    int acplen = aStr.Length() * 2 + 1;
00893    char * acp = new char[acplen];
00894    if(acp)
00895    {
00896       int outlen = ::WideCharToMultiByte( CP_ACP, 0, 
00897                       PromiseFlatString(aStr).get(), aStr.Length(),
00898                       acp, acplen, NULL, NULL);
00899       if ( outlen > 0)
00900          acp[outlen] = '\0';  // null terminate
00901    }
00902    return acp;
00903 }