/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is mozilla.org code. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either of the GNU General Public License Version 2 or later (the "GPL"), * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #ifdef NGLAYOUT_DDRAW #define INITGUID #endif #include "nsDrawingSurfaceWin.h" #include "prmem.h" #include "nsCRT.h" //#define GFX_DEBUG #ifdef GFX_DEBUG #define BREAK_TO_DEBUGGER DebugBreak() #else #define BREAK_TO_DEBUGGER #endif #ifdef GFX_DEBUG #define VERIFY(exp) ((exp) ? 0: (GetLastError(), BREAK_TO_DEBUGGER)) #else // !_DEBUG #define VERIFY(exp) (exp) #endif // !_DEBUG static NS_DEFINE_IID(kIDrawingSurfaceIID, NS_IDRAWING_SURFACE_IID); static NS_DEFINE_IID(kIDrawingSurfaceWinIID, NS_IDRAWING_SURFACE_WIN_IID); #ifdef NGLAYOUT_DDRAW IDirectDraw *nsDrawingSurfaceWin::mDDraw = NULL; IDirectDraw2 *nsDrawingSurfaceWin::mDDraw2 = NULL; nsresult nsDrawingSurfaceWin::mDDrawResult = NS_OK; #endif nsDrawingSurfaceWin :: nsDrawingSurfaceWin() { mDC = NULL; mOrigBitmap = nsnull; mSelectedBitmap = nsnull; mKillDC = PR_FALSE; mBitmapInfo = nsnull; mDIBits = nsnull; mLockedBitmap = nsnull; mWidth = mHeight = 0; mLockOffset = mLockHeight = 0; mLockFlags = 0; #ifdef NGLAYOUT_DDRAW CreateDDraw(); mSurface = NULL; mSurfLockCnt = 0; #endif } nsDrawingSurfaceWin :: ~nsDrawingSurfaceWin() { if ((nsnull != mDC) && (nsnull != mOrigBitmap)) { HBITMAP tbits = (HBITMAP)::SelectObject(mDC, mOrigBitmap); if (nsnull != tbits) VERIFY(::DeleteObject(tbits)); mOrigBitmap = nsnull; } if (nsnull != mBitmapInfo) { PR_Free(mBitmapInfo); mBitmapInfo = nsnull; } if ((nsnull != mDIBits) && (nsnull == mSelectedBitmap)) PR_Free(mDIBits); mDIBits = nsnull; mSelectedBitmap = nsnull; #ifdef NGLAYOUT_DDRAW if (NULL != mSurface) { if (NULL != mDC) { mSurface->ReleaseDC(mDC); mDC = NULL; } NS_RELEASE(mSurface); mSurface = NULL; } else #endif { if (NULL != mDC) { if (PR_TRUE == mKillDC) ::DeleteDC(mDC); mDC = NULL; } } } NS_IMETHODIMP nsDrawingSurfaceWin :: QueryInterface(REFNSIID aIID, void** aInstancePtr) { if (nsnull == aInstancePtr) return NS_ERROR_NULL_POINTER; if (aIID.Equals(kIDrawingSurfaceIID)) { nsIDrawingSurface* tmp = this; *aInstancePtr = (void*) tmp; NS_ADDREF_THIS(); return NS_OK; } if (aIID.Equals(kIDrawingSurfaceWinIID)) { nsIDrawingSurfaceWin* tmp = this; *aInstancePtr = (void*) tmp; NS_ADDREF_THIS(); return NS_OK; } static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); if (aIID.Equals(kISupportsIID)) { nsIDrawingSurface* tmp = this; nsISupports* tmp2 = tmp; *aInstancePtr = (void*) tmp2; NS_ADDREF_THIS(); return NS_OK; } return NS_NOINTERFACE; } NS_IMPL_ADDREF(nsDrawingSurfaceWin) NS_IMPL_RELEASE(nsDrawingSurfaceWin) NS_IMETHODIMP nsDrawingSurfaceWin :: Lock(PRInt32 aX, PRInt32 aY, PRUint32 aWidth, PRUint32 aHeight, void **aBits, PRInt32 *aStride, PRInt32 *aWidthBytes, PRUint32 aFlags) { #ifdef NGLAYOUT_DDRAW if (mSurfLockCnt == 0) { RECT srect; DWORD lockflags = 0; srect.left = aX; srect.top = aY; srect.right = aX + aWidth; srect.bottom = aY + aHeight; if (aFlags & NS_LOCK_SURFACE_READ_ONLY) lockflags |= DDLOCK_READONLY; if (aFlags & NS_LOCK_SURFACE_WRITE_ONLY) lockflags |= DDLOCK_WRITEONLY; if (PR_TRUE == LockSurface(mSurface, &mSurfDesc, &mBitmap, &srect, lockflags, &mPixFormat)) mSurfLockCnt++; } else { NS_ASSERTION(0, "nested lock attempt"); return NS_ERROR_FAILURE; } if (mSurfLockCnt == 0) #endif { if (nsnull == mLockedBitmap) { if (nsnull == mSelectedBitmap) { HBITMAP tbits = ::CreateCompatibleBitmap(mDC, 2, 2); if ( tbits != nsnull ) { mLockedBitmap = (HBITMAP)::SelectObject(mDC, tbits); // if the SelectObject fails, or there was no bitmap returned from this DC if ( mLockedBitmap != nsnull ) { ::GetObject(mLockedBitmap, sizeof(BITMAP), &mBitmap); // Always use at least 24-bit bitmaps regardless of the device context. // See bug 228399 for more information. if (mBitmap.bmBitsPixel < 24) mBitmap.bmBitsPixel = 24; // Note the width of the DIB-bits rows. DIB rows are DWORD-aligned, // the original bitmap's rows may not have been DWORD-aligned. mBitmap.bmWidthBytes = RASWIDTH(mBitmap.bmWidth, mBitmap.bmBitsPixel); if (aY < 0 || aY + aHeight > mBitmap.bmHeight) { ::DeleteObject(tbits); return NS_ERROR_FAILURE; } // GetDIBits always seems to interpret the scanlines as bottom-to-top. mLockHeight = (PRInt32)aHeight; mLockOffset = mBitmap.bmHeight - (aY + aHeight); mBitmapInfo = CreateBitmapInfo(mBitmap.bmWidth, mBitmap.bmHeight, mBitmap.bmBitsPixel, (void **)&mDIBits); if ( mBitmapInfo != nsnull ) { if (!(aFlags & NS_LOCK_SURFACE_WRITE_ONLY)) ::GetDIBits(mDC, mLockedBitmap, mLockOffset, mLockHeight, mDIBits, mBitmapInfo, DIB_RGB_COLORS); mBitmap.bmBits = mDIBits; } else { ::DeleteObject(tbits); return NS_ERROR_FAILURE; } } else { ::DeleteObject(tbits); return NS_ERROR_FAILURE; } } else { return NS_ERROR_FAILURE; } } else { if (!(aFlags & NS_LOCK_SURFACE_WRITE_ONLY)) ::GdiFlush(); mLockedBitmap = mSelectedBitmap; mBitmap.bmBits = mDIBits + mBitmap.bmWidthBytes * aY; } } else { NS_ASSERTION(0, "nested lock attempt"); return NS_ERROR_FAILURE; } } *aBits = (PRUint8 *)mBitmap.bmBits + (aX * (mBitmap.bmBitsPixel >> 3)); *aStride = mBitmap.bmWidthBytes; *aWidthBytes = aWidth * (mBitmap.bmBitsPixel >> 3); mLockFlags = aFlags; return NS_OK; } NS_IMETHODIMP nsDrawingSurfaceWin :: Unlock(void) { #ifdef NGLAYOUT_DDRAW NS_ASSERTION(!(mDC != nsnull), "attempt to unlock with dc"); if (nsnull == mDC) { mSurfLockCnt--; NS_ASSERTION(!(mSurfLockCnt != 0), "nested surface locks"); if (mSurfLockCnt == 0) mSurface->Unlock(mSurfDesc.lpSurface); } else #endif { if (nsnull != mLockedBitmap) { if (nsnull == mSelectedBitmap) { HBITMAP tbits; if (!(mLockFlags & NS_LOCK_SURFACE_READ_ONLY)) ::SetDIBits(mDC, mLockedBitmap, mLockOffset, mLockHeight, mDIBits, mBitmapInfo, DIB_RGB_COLORS); tbits = (HBITMAP)::SelectObject(mDC, mLockedBitmap); ::DeleteObject(tbits); if (nsnull != mBitmapInfo) { PR_Free(mBitmapInfo); mBitmapInfo = nsnull; } if (nsnull != mDIBits) { PR_Free(mDIBits); mDIBits = nsnull; } } mLockedBitmap = nsnull; } } return NS_OK; } NS_IMETHODIMP nsDrawingSurfaceWin :: GetDimensions(PRUint32 *aWidth, PRUint32 *aHeight) { *aWidth = mWidth; *aHeight = mHeight; return NS_OK; } NS_IMETHODIMP nsDrawingSurfaceWin :: IsOffscreen(PRBool *aOffScreen) { *aOffScreen = mKillDC; return NS_OK; } NS_IMETHODIMP nsDrawingSurfaceWin :: IsPixelAddressable(PRBool *aAddressable) { #ifdef NGLAYOUT_DDRAW if (nsnull != mSurface) *aAddressable = PR_TRUE; else #endif if (nsnull != mSelectedBitmap) *aAddressable = PR_TRUE; else *aAddressable = PR_FALSE; return NS_OK; } NS_IMETHODIMP nsDrawingSurfaceWin :: GetPixelFormat(nsPixelFormat *aFormat) { *aFormat = mPixFormat; return NS_OK; } NS_IMETHODIMP nsDrawingSurfaceWin :: Init(HDC aDC) { mDC = aDC; mTechnology = ::GetDeviceCaps(mDC, TECHNOLOGY); return NS_OK; } NS_IMETHODIMP nsDrawingSurfaceWin :: Init(HDC aDC, PRUint32 aWidth, PRUint32 aHeight, PRUint32 aFlags) { NS_ASSERTION(!(aDC == nsnull), "null DC"); #if defined(MOZ_SVG) && defined(SVG_FORCE_PIXEL_ACCESS_SURFACES) // force pixel access on all surfaces. Improves gdi+ performance aFlags |= NS_CREATEDRAWINGSURFACE_FOR_PIXEL_ACCESS; #endif #ifdef NGLAYOUT_DDRAW if (aFlags & NS_CREATEDRAWINGSURFACE_FOR_PIXEL_ACCESS) { LPDIRECTDRAWSURFACE ddsurf = nsnull; if ((NULL != mDDraw2) && (aWidth > 0) && (aHeight > 0)) { DDSURFACEDESC ddsd; ddsd.dwSize = sizeof(ddsd); ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | ((aFlags & NS_CREATEDRAWINGSURFACE_FOR_PIXEL_ACCESS) ? DDSCAPS_SYSTEMMEMORY : 0); ddsd.dwWidth = aWidth; ddsd.dwHeight = aHeight; mDDraw2->CreateSurface(&ddsd, &ddsurf, NULL); } if (NULL != ddsurf) mSurface = ddsurf; else { mDC = ::CreateCompatibleDC(aDC); mKillDC = PR_TRUE; } } else #endif { mDC = ::CreateCompatibleDC(aDC); mTechnology = ::GetDeviceCaps(mDC, TECHNOLOGY); mKillDC = PR_TRUE; } #ifdef NGLAYOUT_DDRAW if (nsnull == mSurface) #endif { HBITMAP tbits = nsnull; if (aWidth > 0 && aHeight > 0) { if ((aFlags & NS_CREATEDRAWINGSURFACE_FOR_PIXEL_ACCESS) == 0) tbits = ::CreateCompatibleBitmap(aDC, aWidth, aHeight); // Create a DIB if we need Pixel Access, or if DDB creation failed if (nsnull == tbits) { void *bits; BITMAPINFO *binfo; int depth; depth = ::GetDeviceCaps(aDC, BITSPIXEL); // Always use at least 24-bit bitmaps regardless of the device context. // See bug 228399 for more information. if (depth < 24) depth = 24; binfo = CreateBitmapInfo(aWidth, aHeight, depth); if (nsnull == binfo) return NS_ERROR_FAILURE; mSelectedBitmap = tbits = ::CreateDIBSection(aDC, binfo, DIB_RGB_COLORS, &bits, NULL, 0); if (NULL == mSelectedBitmap) return NS_ERROR_FAILURE; mBitmapInfo = binfo; mDIBits = (PRUint8 *)bits; mBitmap.bmWidthBytes = RASWIDTH(aWidth, depth); mBitmap.bmBitsPixel = depth; } } else { //we do this to make sure that the memory DC knows what the //bitmap format of the original DC was. this way, later //operations to create bitmaps from the memory DC will create //bitmaps with the correct properties. tbits = ::CreateCompatibleBitmap(aDC, 2, 2); } mOrigBitmap = (HBITMAP)::SelectObject(mDC, tbits); } mWidth = aWidth; mHeight = aHeight; return NS_OK; } NS_IMETHODIMP nsDrawingSurfaceWin :: GetDC(HDC *aDC) { #ifdef NGLAYOUT_DDRAW if (nsnull != mSurface) { if (0 == mSurfLockCnt) mSurface->GetDC(&mDC); mSurfLockCnt++; } #endif *aDC = mDC; return NS_OK; } NS_IMETHODIMP nsDrawingSurfaceWin::GetTECHNOLOGY(PRInt32 *aTechnology) { *aTechnology = mTechnology; return NS_OK; } NS_IMETHODIMP nsDrawingSurfaceWin :: ReleaseDC(void) { #ifdef NGLAYOUT_DDRAW if (nsnull != mSurface) { --mSurfLockCnt; if ((nsnull != mDC) && (mSurfLockCnt == 0)) { mSurface->ReleaseDC(mDC); mDC = nsnull; } } #endif return NS_OK; } NS_IMETHODIMP nsDrawingSurfaceWin :: IsReleaseDCDestructive(PRBool *aDestructive) { #ifdef NGLAYOUT_DDRAW if (nsnull != mSurface) *aDestructive = PR_TRUE; else #endif *aDestructive = PR_FALSE; return NS_OK; } BITMAPINFO * nsDrawingSurfaceWin :: CreateBitmapInfo(PRInt32 aWidth, PRInt32 aHeight, PRInt32 aDepth, void **aBits) { NS_ASSERTION(aDepth == 24 || aDepth == 32, "Unsupported bitmap depth"); PRInt32 palsize, imagesize, spanbytes, allocsize; PRUint8 *colortable; DWORD bicomp, masks[3]; BITMAPINFO *rv = nsnull; switch (aDepth) { case 24: palsize = 0; allocsize = 0; bicomp = BI_RGB; mPixFormat.mRedZeroMask = 0xff; mPixFormat.mGreenZeroMask = 0xff; mPixFormat.mBlueZeroMask = 0xff; mPixFormat.mAlphaZeroMask = 0; mPixFormat.mRedMask = 0xff0000; mPixFormat.mGreenMask = 0xff00; mPixFormat.mBlueMask = 0xff; mPixFormat.mAlphaMask = 0; mPixFormat.mRedCount = 8; mPixFormat.mGreenCount = 8; mPixFormat.mBlueCount = 8; mPixFormat.mAlphaCount = 0; mPixFormat.mRedShift = 16; mPixFormat.mGreenShift = 8; mPixFormat.mBlueShift = 0; mPixFormat.mAlphaShift = 0; break; case 32: palsize = 0; allocsize = 3; bicomp = BI_BITFIELDS; masks[0] = 0xff0000; masks[1] = 0x00ff00; masks[2] = 0x0000ff; mPixFormat.mRedZeroMask = 0xff; mPixFormat.mGreenZeroMask = 0xff; mPixFormat.mBlueZeroMask = 0xff; mPixFormat.mAlphaZeroMask = 0xff; mPixFormat.mRedMask = masks[0]; mPixFormat.mGreenMask = masks[1]; mPixFormat.mBlueMask = masks[2]; mPixFormat.mAlphaMask = 0xff000000; mPixFormat.mRedCount = 8; mPixFormat.mGreenCount = 8; mPixFormat.mBlueCount = 8; mPixFormat.mAlphaCount = 8; mPixFormat.mRedShift = 16; mPixFormat.mGreenShift = 8; mPixFormat.mBlueShift = 0; mPixFormat.mAlphaShift = 24; break; default: palsize = -1; break; } if (palsize >= 0) { spanbytes = RASWIDTH(aWidth, aDepth); imagesize = spanbytes * aHeight; rv = (BITMAPINFO *)PR_Malloc(sizeof(BITMAPINFOHEADER) + (sizeof(RGBQUAD) * allocsize)); if (nsnull != rv) { rv->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); rv->bmiHeader.biWidth = aWidth; rv->bmiHeader.biHeight = -aHeight; rv->bmiHeader.biPlanes = 1; rv->bmiHeader.biBitCount = (unsigned short)aDepth; rv->bmiHeader.biCompression = bicomp; rv->bmiHeader.biSizeImage = imagesize; rv->bmiHeader.biXPelsPerMeter = 0; rv->bmiHeader.biYPelsPerMeter = 0; rv->bmiHeader.biClrUsed = palsize; rv->bmiHeader.biClrImportant = palsize; // set the color table in the info header colortable = (PRUint8 *)rv + sizeof(BITMAPINFOHEADER); if ((aDepth == 16) || (aDepth == 32)) memcpy(colortable, masks, sizeof(DWORD) * allocsize); else memset(colortable, 0, sizeof(RGBQUAD) * palsize); if (nsnull != aBits) { *aBits = PR_Malloc(imagesize); if ( nsnull == *aBits ) { PR_Free(rv); rv = nsnull; } } } } return rv; } #ifdef NGLAYOUT_DDRAW PRBool nsDrawingSurfaceWin :: LockSurface(IDirectDrawSurface *aSurface, DDSURFACEDESC *aDesc, BITMAP *aBitmap, RECT *aRect, DWORD aLockFlags, nsPixelFormat *aPixFormat) { if (nsnull != aSurface) { aDesc->dwSize = sizeof(DDSURFACEDESC); if (DD_OK == aSurface->Lock(aRect, aDesc, DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR | aLockFlags, NULL)) { if ((aDesc->ddpfPixelFormat.dwFlags & (DDPF_ALPHA | DDPF_PALETTEINDEXED1 | DDPF_PALETTEINDEXED2 | DDPF_PALETTEINDEXED4 | DDPF_PALETTEINDEXEDTO8 | DDPF_YUV | DDPF_ZBUFFER)) || (aDesc->ddpfPixelFormat.dwRGBBitCount < 8)) { //this is a surface that we can't, or don't want to handle. aSurface->Unlock(aDesc->lpSurface); return PR_FALSE; } aBitmap->bmType = 0; aBitmap->bmWidth = aDesc->dwWidth; aBitmap->bmHeight = aDesc->dwHeight; aBitmap->bmWidthBytes = aDesc->lPitch; aBitmap->bmPlanes = 1; aBitmap->bmBitsPixel = (PRUint16)aDesc->ddpfPixelFormat.dwRGBBitCount; aBitmap->bmBits = aDesc->lpSurface; if ((nsnull != aPixFormat) && (aBitmap->bmBitsPixel > 8)) { DWORD btemp, shiftcnt; btemp = aDesc->ddpfPixelFormat.dwRBitMask; aPixFormat->mRedMask = btemp; shiftcnt = 32; if (!(btemp & 0xffff)) { aPixFormat->mRedShift = 16; btemp >>= 16; shiftcnt = 16; } else if (!(btemp & 0xff)) { aPixFormat->mRedShift = 8; btemp >>= 8; shiftcnt = 24; } else { aPixFormat->mRedShift = 0; shiftcnt = 32; } while (!(btemp & 1) && shiftcnt--) { btemp >>= 1; aPixFormat->mRedShift++; } aPixFormat->mRedZeroMask = btemp; aPixFormat->mRedCount = 0; while ((btemp & 1) && shiftcnt--) { btemp >>= 1; aPixFormat->mRedCount++; } btemp = aDesc->ddpfPixelFormat.dwGBitMask; aPixFormat->mGreenMask = btemp; shiftcnt = 32; if (!(btemp & 0xffff)) { aPixFormat->mGreenShift = 16; btemp >>= 16; shiftcnt = 16; } else if (!(btemp & 0xff)) { aPixFormat->mGreenShift = 8; btemp >>= 8; shiftcnt = 24; } else { aPixFormat->mGreenShift = 0; shiftcnt = 32; } while (!(btemp & 1) && shiftcnt--) { btemp >>= 1; aPixFormat->mGreenShift++; } aPixFormat->mGreenZeroMask = btemp; aPixFormat->mGreenCount = 0; while ((btemp & 1) && shiftcnt--) { btemp >>= 1; aPixFormat->mGreenCount++; } btemp = aDesc->ddpfPixelFormat.dwBBitMask; aPixFormat->mBlueMask = btemp; shiftcnt = 32; if (!(btemp & 0xffff)) { aPixFormat->mBlueShift = 16; btemp >>= 16; shiftcnt = 16; } else if (!(btemp & 0xff)) { aPixFormat->mBlueShift = 8; btemp >>= 8; shiftcnt = 24; } else { aPixFormat->mBlueShift = 0; shiftcnt = 32; } while (!(btemp & 1) && shiftcnt--) { btemp >>= 1; aPixFormat->mBlueShift++; } aPixFormat->mBlueZeroMask = btemp; aPixFormat->mBlueCount = 0; while ((btemp & 1) && shiftcnt--) { btemp >>= 1; aPixFormat->mBlueCount++; } aPixFormat->mAlphaCount = (PRUint8)aDesc->ddpfPixelFormat.dwAlphaBitDepth; if (aPixFormat->mAlphaCount > 0) { btemp = aDesc->ddpfPixelFormat.dwRGBAlphaBitMask; aPixFormat->mAlphaMask = btemp; shiftcnt = 32; if (!(btemp & 0xffff)) { aPixFormat->mAlphaShift = 16; btemp >>= 16; shiftcnt = 16; } else if (!(btemp & 0xff)) { aPixFormat->mAlphaShift = 8; btemp >>= 8; shiftcnt = 24; } else { aPixFormat->mAlphaShift = 0; shiftcnt = 32; } while (!(btemp & 1) && shiftcnt--) { btemp >>= 1; aPixFormat->mAlphaShift++; } aPixFormat->mAlphaZeroMask = btemp; } else { aPixFormat->mAlphaMask = 0; aPixFormat->mAlphaShift = 0; aPixFormat->mAlphaZeroMask = 0; } } return PR_TRUE; } else return PR_FALSE; } else return PR_FALSE; } nsresult nsDrawingSurfaceWin :: CreateDDraw() { if ((mDDraw2 == NULL) && (mDDrawResult == NS_OK)) { CoInitialize(NULL); mDDrawResult = DirectDrawCreate(NULL, &mDDraw, NULL); if (mDDrawResult == NS_OK) mDDrawResult = mDDraw->QueryInterface(IID_IDirectDraw2, (LPVOID *)&mDDraw2); if (mDDrawResult == NS_OK) { mDDraw2->SetCooperativeLevel(NULL, DDSCL_NORMAL); #ifdef NS_DEBUG printf("using DirectDraw (%08X)\n", mDDraw2); DDSCAPS ddscaps; DWORD totalmem, freemem; ddscaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY; nsresult res = mDDraw2->GetAvailableVidMem(&ddscaps, &totalmem, &freemem); if (NS_SUCCEEDED(res)) { printf("total video memory: %d\n", totalmem); printf("free video memory: %d\n", freemem); } else { printf("GetAvailableVidMem() returned %08x: %s\n", res, (res == DDERR_NODIRECTDRAWHW) ? "no hardware ddraw driver available" : "unknown error code"); } #endif } } return mDDrawResult; } nsresult nsDrawingSurfaceWin :: GetDDraw(IDirectDraw2 **aDDraw) { CreateDDraw(); if (NULL != mDDraw2) { NS_ADDREF(mDDraw2); *aDDraw = mDDraw2; } else *aDDraw = NULL; return NS_OK; } #endif