Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

808 lines
22 KiB

  1. /**************************************************************************\
  2. *
  3. * Copyright (c) 1998 Microsoft Corporation
  4. *
  5. * Abstract:
  6. *
  7. * Device bitmap APIs and internals.
  8. *
  9. * Revision History:
  10. *
  11. * 12/02/1998 andrewgo
  12. * Created it.
  13. *
  14. \**************************************************************************/
  15. #include "precomp.hpp"
  16. #include "compatibleDIB.hpp"
  17. /**************************************************************************\
  18. *
  19. * Function Description:
  20. *
  21. * Temporary function to see if the bitmap is a standard format type
  22. * (5-5-5, 5-6-5, 24bpp or 32bpp).
  23. *
  24. * Notes:
  25. *
  26. * Code which calls this assumes that there are no standard formats which
  27. * support alpha.
  28. *
  29. * History:
  30. *
  31. * 12/04/1998 andrewgo
  32. * Created it.
  33. *
  34. \**************************************************************************/
  35. BOOL
  36. DpBitmap::StandardFormat(
  37. VOID
  38. )
  39. {
  40. INT BitsPerPixel = GetPixelFormatSize(PixelFormat);
  41. BOOL standardFormat = FALSE;
  42. if ((RedMask == 0x00ff0000) &&
  43. (GreenMask == 0x0000ff00) &&
  44. (BlueMask == 0x000000ff))
  45. {
  46. if (BitsPerPixel == 24)
  47. {
  48. standardFormat = TRUE;
  49. }
  50. else if (BitsPerPixel == 32)
  51. {
  52. standardFormat = TRUE;
  53. }
  54. }
  55. else if ((RedMask == 0x00007c00) &&
  56. (GreenMask == 0x000003e0) &&
  57. (BlueMask == 0x0000001f) &&
  58. (BitsPerPixel == 16))
  59. {
  60. standardFormat = TRUE;
  61. }
  62. else if ((RedMask == 0x0000f800) &&
  63. (GreenMask == 0x000007e0) &&
  64. (BlueMask == 0x0000001f) &&
  65. (BitsPerPixel == 16))
  66. {
  67. standardFormat = TRUE;
  68. }
  69. return(standardFormat);
  70. }
  71. /**************************************************************************\
  72. *
  73. * Function Description:
  74. *
  75. * This function computes the PixelFormatID corresponding to a particular
  76. * combination of bit depth and color channel masks in the DpBitmap.
  77. *
  78. * Notes:
  79. *
  80. * Code which calls this assumes that there are no standard formats which
  81. * support alpha.
  82. *
  83. * History:
  84. *
  85. * 05/17/2000 asecchia
  86. * Created it.
  87. *
  88. \**************************************************************************/
  89. PixelFormatID DpBitmap::GetPixelFormatFromBitDepth(INT bits)
  90. {
  91. switch(bits)
  92. {
  93. // !!! [asecchia] not sure if we support these indexed modes
  94. // from this codepath.
  95. case 1:
  96. return PixelFormat1bppIndexed;
  97. case 4:
  98. return PixelFormat4bppIndexed;
  99. case 8:
  100. return PixelFormat8bppIndexed;
  101. case 16:
  102. if (RedMask == 0x00007c00)
  103. {
  104. return PixelFormat16bppRGB555;
  105. }
  106. if (RedMask == 0x0000f800)
  107. {
  108. return PixelFormat16bppRGB565;
  109. }
  110. break;
  111. case 24:
  112. if (RedMask == 0x00ff0000)
  113. {
  114. return PixelFormat24bppRGB;
  115. }
  116. if (RedMask == 0x000000ff)
  117. {
  118. return PIXFMT_24BPP_BGR;
  119. }
  120. break;
  121. case 32:
  122. if (RedMask == 0x00ff0000)
  123. {
  124. return PixelFormat32bppRGB;
  125. }
  126. break;
  127. }
  128. WARNING(("Unsupported pixel format"));
  129. return PixelFormatUndefined;
  130. }
  131. /**************************************************************************\
  132. *
  133. * Function Description:
  134. *
  135. * Initializes a bitmap for drawing on via the GDI routines.
  136. *
  137. * Arguments:
  138. *
  139. * [IN] device - Identifies the device
  140. * [IN] width - Bitmap width
  141. * [IN] height - Bitmap height
  142. * [OUT] driver - Driver interface to be used
  143. *
  144. * History:
  145. *
  146. * 12/06/1998 andrewgo
  147. * Created it.
  148. *
  149. \**************************************************************************/
  150. VOID
  151. DpBitmap::InitializeForGdiBitmap(
  152. GpDevice *device,
  153. INT width,
  154. INT height
  155. )
  156. {
  157. SurfaceTransparency = TransparencyNoAlpha;
  158. // !!![andrewgo] Disable this assert until MetaFiles stop calling
  159. // with a zero dimension surface
  160. //
  161. // ASSERTMSG((width > 0) && (height > 0), ("Dimensions must be positive"));
  162. Width = width;
  163. Height = height;
  164. NumBytes = 0;
  165. Uniqueness = (DWORD)GpObject::GenerateUniqueness();
  166. PixelFormat = ExtractPixelFormatFromHDC(device->DeviceHdc);
  167. Scan = device->ScanGdi;
  168. SetValid(TRUE);
  169. Bits = NULL;
  170. Delta = 0;
  171. DdrawSurface7 = NULL;
  172. Type = GDI;
  173. }
  174. /**************************************************************************\
  175. *
  176. * Function Description:
  177. *
  178. * Initializes a bitmap for drawing on via the DCI routines, if possible.
  179. *
  180. * Arguments:
  181. *
  182. * [IN] device - Identifies the device
  183. * [IN] width - Bitmap width
  184. * [IN] height - Bitmap height
  185. * [OUT] driver - Driver interface to be used
  186. *
  187. * History:
  188. *
  189. * 12/06/1998 andrewgo
  190. * Created it.
  191. *
  192. \**************************************************************************/
  193. VOID
  194. DpBitmap::InitializeForGdiScreen(
  195. GpDevice *device,
  196. INT width,
  197. INT height
  198. )
  199. {
  200. InitializeForGdiBitmap(device, width, height);
  201. // Even if GDI bitmaps change to support alpha, the screen doesn't.
  202. SurfaceTransparency = TransparencyNoAlpha;
  203. ASSERT(!IsAlphaPixelFormat(PixelFormat));
  204. if(device->pdds != NULL)
  205. {
  206. DdrawSurface7 = device->pdds;
  207. DdrawSurface7->AddRef();
  208. }
  209. Scan = device->ScanDci;
  210. }
  211. /**************************************************************************\
  212. *
  213. * Function Description:
  214. *
  215. * Initializes a bitmap for drawing on via D3D/DD access.
  216. *
  217. * Arguments:
  218. *
  219. * [IN] device - Identifies the device
  220. * [IN] width - Bitmap width
  221. * [IN] height - Bitmap height
  222. * [OUT] driver - Driver interface to be used
  223. *
  224. * Return Value:
  225. *
  226. * A GpStatus value indicating success or failure.
  227. *
  228. * History:
  229. *
  230. * 09/28/1999 bhouse
  231. * Created it.
  232. *
  233. \**************************************************************************/
  234. BOOL
  235. DpBitmap::InitializeForD3D(
  236. HDC hdc,
  237. INT *width,
  238. INT *height,
  239. DpDriver **driver
  240. )
  241. {
  242. HRESULT ddVal;
  243. HDC hdcDevice;
  244. DDSURFACEDESC2 ddsd;
  245. if(!InitializeDirectDrawGlobals())
  246. return FALSE;
  247. IDirectDrawSurface7 * surface;
  248. ddVal = Globals::DirectDraw->GetSurfaceFromDC(hdc, &surface);
  249. if(ddVal != DD_OK)
  250. return(FALSE);
  251. return InitializeForD3D(surface, width, height, driver);
  252. }
  253. /**************************************************************************\
  254. *
  255. * Function Description:
  256. *
  257. * Initializes a bitmap for drawing on via D3D/DD access.
  258. *
  259. * Arguments:
  260. *
  261. * [IN] device - Identifies the device
  262. * [IN] width - Bitmap width
  263. * [IN] height - Bitmap height
  264. * [OUT] driver - Driver interface to be used
  265. *
  266. * Return Value:
  267. *
  268. * A GpStatus value indicating success or failure.
  269. *
  270. * History:
  271. *
  272. * 09/28/1999 bhouse
  273. * Created it.
  274. *
  275. \**************************************************************************/
  276. BOOL
  277. DpBitmap::InitializeForD3D(
  278. IDirectDrawSurface7 * surface,
  279. INT *width,
  280. INT *height,
  281. DpDriver **driver
  282. )
  283. {
  284. HRESULT ddVal;
  285. HDC hdcDevice;
  286. DDSURFACEDESC2 ddsd;
  287. GpDevice * device = Globals::DeviceList->FindD3DDevice(surface);
  288. if(device == NULL || device->pd3d == NULL)
  289. return FALSE;
  290. DdrawSurface7 = surface;
  291. ddsd.dwSize = sizeof(ddsd);
  292. ddVal = DdrawSurface7->GetSurfaceDesc(&ddsd);
  293. if (ddVal == DD_OK)
  294. {
  295. // Initialize bitmap class stuff:
  296. Bits = NULL;
  297. Delta = ddsd.lPitch;
  298. Width = ddsd.dwWidth;
  299. Height = ddsd.dwHeight;
  300. // AlphaMask is initialized to zero because we don't use it -
  301. // non-alpha format.
  302. AlphaMask = 0x00000000;
  303. RedMask = ddsd.ddpfPixelFormat.dwRBitMask;
  304. GreenMask = ddsd.ddpfPixelFormat.dwGBitMask;
  305. BlueMask = ddsd.ddpfPixelFormat.dwBBitMask;
  306. PixelFormat = GetPixelFormatFromBitDepth(ddsd.ddpfPixelFormat.dwRGBBitCount);
  307. if (StandardFormat())
  308. {
  309. // Our standard formats don't have alpha.
  310. SurfaceTransparency = TransparencyNoAlpha;
  311. *driver = Globals::D3DDriver;
  312. Scan = &Globals::DesktopDevice->ScanEngine;
  313. NumBytes = 0;
  314. Uniqueness = (DWORD)GpObject::GenerateUniqueness();
  315. Type = D3D;
  316. SetValid(TRUE);
  317. // Return some stuff:
  318. *width = Width;
  319. *height = Height;
  320. // Grab a reference:
  321. DdrawSurface7->AddRef();
  322. return(TRUE);
  323. }
  324. }
  325. return(FALSE);
  326. }
  327. /**************************************************************************\
  328. *
  329. * Function Description:
  330. *
  331. * Initializes a bitmap for drawing on via printer routines, if possible.
  332. *
  333. * Return Value:
  334. *
  335. * A GpStatus value indicating success or failure.
  336. *
  337. * History:
  338. *
  339. * 12/06/1998 andrewgo
  340. * Created it.
  341. *
  342. \**************************************************************************/
  343. BOOL
  344. DpBitmap::InitializeForPrinter(
  345. GpPrinterDevice *device,
  346. INT width,
  347. INT height
  348. )
  349. {
  350. InitializeForGdiBitmap(device, width, height);
  351. // Even if GDI bitmaps change to support alpha, printers don't.
  352. SurfaceTransparency = TransparencyNoAlpha;
  353. ASSERT(!IsAlphaPixelFormat(PixelFormat));
  354. Scan = &device->ScanPrint;
  355. return TRUE;
  356. }
  357. /**************************************************************************\
  358. *
  359. * Function Description:
  360. *
  361. * Initializes a bitmap for drawing on via direct access to the
  362. * DIBsection bits.
  363. *
  364. * Return Value:
  365. *
  366. * A GpStatus value indicating success or failure.
  367. *
  368. * History:
  369. *
  370. * 12/06/1998 andrewgo
  371. * Created it.
  372. *
  373. \**************************************************************************/
  374. BOOL
  375. DpBitmap::InitializeForDibsection(
  376. HDC hdc,
  377. HBITMAP hbitmap, // [IN] Bitmap handle, needed for determing
  378. // if bitmap is really top-down or not
  379. GpDevice *device, // [IN] Identifies the device
  380. DIBSECTION *dib, // [IN] Structure describing the bitmap
  381. INT *width, // [OUT] Bitmap width
  382. INT *height, // [OUT] Bitmap height
  383. DpDriver **driver // [OUT] Driver interface to be used
  384. )
  385. {
  386. BOOL isTopDown;
  387. // On NT5, drivers have the option of supporting GetDC with DirectDraw
  388. // surfaces in such a way that the surfaces are not Locked when GDI
  389. // does the GetDC on them. This means that there may be no user-mode
  390. // mapping of the underlying surface. So we have to check here for
  391. // that case, because we obviously cannot render directly to those
  392. // surfaces via software:
  393. // NOTE: if the surface is actually a DDraw surface, this check is not
  394. // actually enough. It is up to the driver to return a pointer here and
  395. // on occasion it simply returns its KM address. I.e. it will return a
  396. // non-NULL pointer that we can't access.
  397. // See the DDraw special case below.
  398. // This has been verified on a number of video drivers on Windows 2000
  399. // and Windows XP. (for instance, the inbox win2k permedia driver).
  400. if (dib->dsBm.bmBits == NULL)
  401. {
  402. return(FALSE);
  403. }
  404. LONG scans = abs(dib->dsBm.bmHeight);
  405. LONG widthInBytes = dib->dsBm.bmWidthBytes;
  406. // For backwards compatibility with Get/SetBitmapBits, GDI does
  407. // not accurately report the bitmap pitch in bmWidthBytes. It
  408. // always computes bmWidthBytes assuming WORD-aligned scanlines
  409. // regardless of the platform.
  410. //
  411. // Therefore, if the platform is WinNT, which uses DWORD-aligned
  412. // scanlines, adjust the bmWidthBytes value.
  413. if (Globals::IsNt)
  414. {
  415. widthInBytes = (widthInBytes + 3) & ~3;
  416. }
  417. DWORD* topDown = (DWORD*) dib->dsBm.bmBits;
  418. DWORD* bottomUp = (DWORD*) ((ULONG_PTR) topDown + (scans - 1) * widthInBytes);
  419. if (Globals::IsNt)
  420. {
  421. // Unfortunately, on NT there is no simple means of determining
  422. // whether the DIB-section or DDraw surface is bottom-up or
  423. // top-down. (NT should really set biHeight as Win9x does, but
  424. // unfortunately this is a bug that due to compatibility with
  425. // older versions of NT, will never be fixed.)
  426. //
  427. // At least we know that DirectDraw surfaces will always be
  428. // top-down, and we can recognize DDraw surfaces by the fact
  429. // that they have biSizeImage set to 0. (Note that we can't let
  430. // this fall into the SetBitmapBits case because NT5 doesn't
  431. // permit SetBitmapBits calls on DDraw surface handles.)
  432. if (dib->dsBmih.biSizeImage == 0)
  433. {
  434. // This is a DirectDraw surface.
  435. // Currently we don't support direct rendering on DDraw surfaces
  436. // that are not backed by a system memory DIB Section so we simply
  437. // fail here and drop into the GDI fallback code if we detect
  438. // this condition.
  439. isTopDown = TRUE;
  440. if(!InitializeDirectDrawGlobals() ||
  441. (Globals::GetDdrawSurfaceFromDcFunction == NULL))
  442. {
  443. // If we can't talk to the DDraw surface, we simply fall back
  444. // to our GDI rendering codepath.
  445. return FALSE;
  446. }
  447. HDC driverHdc;
  448. LPDIRECTDRAWSURFACE pDDS = NULL;
  449. HRESULT hr = Globals::GetDdrawSurfaceFromDcFunction(
  450. hdc,
  451. &pDDS,
  452. &driverHdc
  453. );
  454. if (FAILED(hr) || (pDDS == NULL))
  455. {
  456. // Bail out if we can't get a DirectDraw Surface object.
  457. return FALSE;
  458. }
  459. // Lock the surface so we can see what the user mode bits pointer
  460. // is. If it's the same as the one in dib->dsBm.bmBits, then
  461. // the DDraw surface is backed by a DIB section and we can continue
  462. // to treat this bitmap as a DIB. Otherwise we must fall back
  463. // to GDI.
  464. DDSURFACEDESC2 DDSD;
  465. DDSD.dwSize = sizeof(DDSURFACEDESC);
  466. hr = pDDS->Lock(
  467. NULL,
  468. (LPDDSURFACEDESC)&DDSD,
  469. DDLOCK_WAIT,
  470. NULL
  471. );
  472. if (FAILED(hr))
  473. {
  474. pDDS->Release();
  475. return FALSE;
  476. }
  477. // Get the correct pitch from the DDSD. Note this may not be the
  478. // same as the pitch in the dib info structure.
  479. widthInBytes = DDSD.lPitch;
  480. // If the lpSurface is not the same as the dib->dsBm.bmBits then
  481. // this is not a DIB backed DDraw surface, so we (currently) have
  482. // no way of drawing on it besides our GDI fallback codepath.
  483. // Fail this call and release resources so that we can pick up
  484. // the StretchBlt fallback case.
  485. if(DDSD.lpSurface != dib->dsBm.bmBits)
  486. {
  487. pDDS->Unlock(NULL);
  488. pDDS->Release();
  489. return FALSE;
  490. }
  491. pDDS->Unlock(NULL);
  492. pDDS->Release();
  493. // We're set: this is a DIB backed DDraw surface so we can continue
  494. // to treat it as a DIB - now that we have the correct pitch.
  495. }
  496. else
  497. {
  498. // When it's not a DDraw surface, we have to go through a
  499. // somewhat more indirect method to figure out where pixel
  500. // (0, 0) is in memory.
  501. //
  502. // We use SetBitmapBits instead of something like SetPixel
  503. // or PatBlt because those would need to use the 'hdc'
  504. // given to us by the application, which might have a
  505. // transform set that maps (0, 0) to something other than
  506. // the top-left pixel of the bitmap.
  507. DWORD top = *topDown;
  508. DWORD bottom = *bottomUp;
  509. DWORD setBits = 0x000000ff;
  510. // Our SetBitmapBits call will set the top-left dword of
  511. // the bitmap to 0x000000ff. If it's a top-down bitmap,
  512. // that will have modified the value at address 'topDown':
  513. *topDown = 0;
  514. LONG bytes = SetBitmapBits(hbitmap, sizeof(setBits), &setBits);
  515. isTopDown = (*topDown != 0);
  516. // The scanlines are guaranteed to be DWORD aligned, so there
  517. // really is at least a DWORD that we can directly access via
  518. // the pointer. However, if the bitmap dimensions are such
  519. // that there is less than a DWORD of active data per scanline
  520. // (for example, a 3x3 8bpp bitmap or a 1x1 16bpp bitmap),
  521. // SetBitmapBits may use less than a DWORD of data.
  522. ASSERT(bytes > 0);
  523. // Restore the bitmap portions that we may have modified:
  524. *topDown = top;
  525. *bottomUp = bottom;
  526. }
  527. }
  528. else
  529. {
  530. // On Win9x, we can simply look at the sign of 'biHeight' to
  531. // determine whether the surface is top-down or bottom-up:
  532. isTopDown = (dib->dsBmih.biHeight < 0);
  533. }
  534. // Fill in our bitmap fields:
  535. if (isTopDown)
  536. {
  537. Bits = (BYTE*) topDown;
  538. Delta = widthInBytes;
  539. }
  540. else
  541. {
  542. Bits = (BYTE*) bottomUp;
  543. Delta = -widthInBytes;
  544. }
  545. Width = dib->dsBm.bmWidth;
  546. Height = dib->dsBm.bmHeight;
  547. // Note that this code doesn't handle palettes!
  548. if (dib->dsBmih.biCompression == BI_BITFIELDS)
  549. {
  550. RedMask = dib->dsBitfields[0];
  551. GreenMask = dib->dsBitfields[1];
  552. BlueMask = dib->dsBitfields[2];
  553. }
  554. else
  555. {
  556. if((dib->dsBmih.biCompression == BI_RGB) &&
  557. (dib->dsBm.bmBitsPixel == 16))
  558. {
  559. // According to MSDN, 16bpp BI_RGB implies 555 format.
  560. RedMask = 0x00007c00;
  561. GreenMask = 0x000003e0;
  562. BlueMask = 0x0000001F;
  563. }
  564. else
  565. {
  566. RedMask = 0x00ff0000;
  567. GreenMask = 0x0000ff00;
  568. BlueMask = 0x000000ff;
  569. }
  570. }
  571. // DibSections don't have alpha, but we don't want to leave this
  572. // field uninitialized because we peek at it occasionally.
  573. AlphaMask = 0x00000000;
  574. PixelFormat = GetPixelFormatFromBitDepth(dib->dsBm.bmBitsPixel);
  575. // if we are here and the bits per pel is 8, this is a DIB
  576. // with halftone colortable
  577. if ((dib->dsBm.bmBitsPixel == 8) || StandardFormat())
  578. {
  579. // Our standard formats don't have alpha.
  580. SurfaceTransparency = TransparencyNoAlpha;
  581. *driver = Globals::EngineDriver;
  582. Scan = &device->ScanEngine;
  583. NumBytes = 0;
  584. Uniqueness = (DWORD)GpObject::GenerateUniqueness();
  585. Type = GDIDIBSECTION;
  586. SetValid(TRUE);
  587. // Return some stuff:
  588. *width = Width;
  589. *height = Height;
  590. return(TRUE);
  591. }
  592. return(FALSE);
  593. }
  594. /**************************************************************************\
  595. *
  596. * Function Description:
  597. *
  598. * Initializes a GDI+ bitmap for drawing on via GpBitmap.Lock/UnlockBits.
  599. *
  600. * Arguments:
  601. *
  602. * [IN] bitmap - Specifies the target GpBitmap
  603. *
  604. * Return Value:
  605. *
  606. * TRUE is successful, FALSE otherwise.
  607. *
  608. * History:
  609. *
  610. * 09/22/1999 gilmanw
  611. * Created it based on DpBitmap::InitializeForGdiBitmap.
  612. *
  613. \**************************************************************************/
  614. VOID
  615. DpBitmap::InitializeForGdipBitmap(
  616. INT width,
  617. INT height,
  618. ImageInfo * imageInfo,
  619. EpScanBitmap * scanBitmap,
  620. BOOL isDisplay
  621. )
  622. {
  623. Width = width;
  624. Height = height;
  625. NumBytes = 0;
  626. Uniqueness = (DWORD)GpObject::GenerateUniqueness();
  627. AlphaMask = 0xff000000;
  628. RedMask = 0x00ff0000;
  629. GreenMask = 0x0000ff00;
  630. BlueMask = 0x000000ff;
  631. SetValid(TRUE);
  632. Bits = NULL;
  633. Delta = 0;
  634. Type = GPBITMAP;
  635. Scan = scanBitmap;
  636. PaletteTable = NULL;
  637. PixelFormat = imageInfo->PixelFormat;
  638. // GetTransparencyHint is called from DrvDrawImage
  639. // bitmap->GetTransparencyHint(&SurfaceTransparency);
  640. IsDisplay = isDisplay;
  641. DpiX = (REAL)imageInfo->Xdpi;
  642. DpiY = (REAL)imageInfo->Ydpi;
  643. }
  644. /**************************************************************************\
  645. *
  646. * Function Description:
  647. *
  648. * Bitmap destructor
  649. *
  650. \**************************************************************************/
  651. DpBitmap::~DpBitmap()
  652. {
  653. if (PaletteTable != NULL)
  654. GpFree(PaletteTable);
  655. if (DdrawSurface7 != NULL)
  656. DdrawSurface7->Release();
  657. SetValid(FALSE); // so we don't use a deleted object
  658. }
  659. /**************************************************************************\
  660. *
  661. * Function Description:
  662. *
  663. * Flush any rendering pending to this surface
  664. *
  665. \**************************************************************************/
  666. VOID
  667. DpBitmap::Flush(
  668. GpFlushIntention intention
  669. )
  670. {
  671. Scan->Flush();
  672. }