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
21 KiB

  1. /**************************************************************************\
  2. *
  3. * Copyright (c) 1999-2000 Microsoft Corporation
  4. *
  5. * Abstract:
  6. *
  7. * Contains all the 32-bit scan-buffer routines for the default supported
  8. * bitmap formats.
  9. *
  10. * Revision History:
  11. *
  12. * 12/08/1998 andrewgo
  13. * Created it.
  14. *
  15. \**************************************************************************/
  16. #include "precomp.hpp"
  17. /**************************************************************************\
  18. *
  19. * Function Description:
  20. *
  21. * Scan class helper function that SrcOver alpha blends two ARGB buffers.
  22. *
  23. * Arguments:
  24. *
  25. * [IN] driver - Driver interface
  26. * [IN] context - Drawing context
  27. * [IN] surface - Destination surface
  28. * [OUT] nextBuffer - Points to a EpScan:: type function to return
  29. * the next buffer
  30. * [IN] scanType - The type of scan.
  31. * [IN] pixFmtGeneral - the input pixel format for the color data,
  32. * in the "Blend" and "CT" scan types.
  33. * [IN] pixFmtOpaque - the input pixel format for the color data,
  34. * in the "Opaque" scan type.
  35. * [IN] solidColor - the solid fill color for "*SolidFill" scan types.
  36. *
  37. * Return Value:
  38. *
  39. * FALSE if all the necessary buffers couldn't be created
  40. *
  41. * History:
  42. *
  43. * 12/04/1998 andrewgo
  44. * Created it.
  45. *
  46. \**************************************************************************/
  47. BOOL
  48. EpScanEngine::Start(
  49. DpDriver *driver,
  50. DpContext *context,
  51. DpBitmap *surface,
  52. NEXTBUFFERFUNCTION *nextBuffer,
  53. EpScanType scanType,
  54. PixelFormatID pixFmtGeneral,
  55. PixelFormatID pixFmtOpaque,
  56. ARGB solidColor
  57. )
  58. {
  59. // Inherit initialization
  60. EpScan::Start(
  61. driver,
  62. context,
  63. surface,
  64. nextBuffer,
  65. scanType,
  66. pixFmtGeneral,
  67. pixFmtOpaque,
  68. solidColor
  69. );
  70. // DIBSection destinations don't have an alpha channel
  71. ASSERT(surface->SurfaceTransparency == TransparencyNoAlpha);
  72. Surface = surface;
  73. if(surface->Type == DpBitmap::D3D)
  74. {
  75. DDSURFACEDESC2 ddsd;
  76. memset(&ddsd, 0, sizeof(ddsd));
  77. ddsd.dwSize = sizeof(ddsd);
  78. HRESULT err;
  79. err = Surface->DdrawSurface7->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL);
  80. if(err != DD_OK)
  81. return(FALSE);
  82. Surface->Bits = ddsd.lpSurface;
  83. Surface->Delta = ddsd.lPitch;
  84. }
  85. Dst = NULL;
  86. Stride = surface->Delta;
  87. Bits = (BYTE*) surface->Bits;
  88. PixelSize = GetPixelFormatSize(surface->PixelFormat) >> 3;
  89. // [agodfrey] This Scan class is only designed for use with formats
  90. // which are supported natively, so it ignores the DIBSection and
  91. // corresponding PixelFormatID returned by GetScanBuffers.
  92. PixelFormatID dstFormat = surface->PixelFormat;
  93. ASSERTMSG(dstFormat != PIXFMT_UNDEFINED,(("Unexpected surface format")));
  94. *nextBuffer = (NEXTBUFFERFUNCTION) EpScanEngine::NextBuffer;
  95. if (!driver->Device->GetScanBuffers(
  96. surface->Width,
  97. NULL,
  98. NULL,
  99. NULL,
  100. Buffers)
  101. )
  102. {
  103. return NULL;
  104. }
  105. // initialize the AlphaBlenders.
  106. BlenderConfig[0].Initialize(
  107. dstFormat,
  108. context,
  109. context->Palette,
  110. Buffers,
  111. TRUE,
  112. FALSE,
  113. solidColor
  114. );
  115. BlenderConfig[1].Initialize(
  116. dstFormat,
  117. context,
  118. context->Palette,
  119. Buffers,
  120. TRUE,
  121. FALSE,
  122. solidColor
  123. );
  124. return TRUE;
  125. }
  126. /**************************************************************************\
  127. *
  128. * Function Description:
  129. *
  130. * Flushes the previous buffer (if there was), and returns the
  131. * next buffer for doing a SrcOver blend.
  132. *
  133. * Arguments:
  134. *
  135. * [IN] x - Destination pixel coordinate in destination surface
  136. * [IN] y - ""
  137. * [IN] width - Number of pixels needed for the next buffer (can be 0)
  138. * [IN] updateWidth - Number of pixels to update in the current buffer
  139. *
  140. * Return Value:
  141. *
  142. * Points to the resulting scan buffer
  143. *
  144. * History:
  145. *
  146. * 12/04/1998 andrewgo
  147. * Created it.
  148. *
  149. \**************************************************************************/
  150. VOID *EpScanEngine::NextBuffer(
  151. INT x,
  152. INT y,
  153. INT newWidth,
  154. INT updateWidth,
  155. INT blenderNum
  156. )
  157. {
  158. if (updateWidth != 0)
  159. {
  160. // Make sure we're not drawing outside the bounds of the surface.
  161. // If these ASSERTs are triggered, the clipping code is broken.
  162. // This class absolutely must have input clipped to the surface
  163. // bounds otherwise we will AV writing on bad memory, or corrupt some
  164. // other data structure.
  165. ASSERT( CurrentX >= 0 );
  166. ASSERT( CurrentY >= 0 );
  167. ASSERT( CurrentX + updateWidth <= Surface->Width );
  168. ASSERT( CurrentY < Surface->Height );
  169. // Handle the previous scanline segment.
  170. BlenderConfig[LastBlenderNum].AlphaBlender.Blend(
  171. Dst,
  172. Buffers[3],
  173. updateWidth,
  174. CurrentX - DitherOriginX,
  175. CurrentY - DitherOriginY,
  176. static_cast<BYTE *>(Buffers[4])
  177. );
  178. }
  179. // Now move on to processing this scanline segment.
  180. // The actual blend will be done on the next call through this routine
  181. // when we know the width and the bits have been set into the buffer
  182. // we're returning.
  183. LastBlenderNum = blenderNum;
  184. // Remember the x and y for the brush offset (halftone & dither).
  185. CurrentX = x;
  186. CurrentY = y;
  187. // Calculate the destination for the scan:
  188. Dst = Bits + (y * Stride) + (x * PixelSize);
  189. return (Buffers[3]);
  190. }
  191. /**************************************************************************\
  192. *
  193. * Function Description:
  194. *
  195. * Denotes the end of the use of the scan buffer.
  196. *
  197. * Arguments:
  198. *
  199. * NONE
  200. *
  201. * Return Value:
  202. *
  203. * NONE
  204. *
  205. * History:
  206. *
  207. * 12/04/1998 andrewgo
  208. * Created it.
  209. *
  210. \**************************************************************************/
  211. VOID
  212. EpScanEngine::End(
  213. INT updateWidth
  214. )
  215. {
  216. // Flush the last scan:
  217. NextBuffer(0, 0, 0, updateWidth, 0);
  218. if(Surface->Type == DpBitmap::D3D)
  219. {
  220. Surface->DdrawSurface7->Unlock(NULL);
  221. Surface->Bits = NULL;
  222. Surface->Delta = 0;
  223. }
  224. }
  225. /**************************************************************************\
  226. *
  227. * Function Description:
  228. *
  229. * Scan class helper function that SrcOver alpha blends two ARGB buffers.
  230. *
  231. * Arguments:
  232. *
  233. * [IN] driver - Driver interface
  234. * [IN] context - Drawing context
  235. * [IN] surface - Destination surface
  236. * [OUT] nextBuffer - Points to a EpScan:: type function to return
  237. * the next buffer
  238. * [IN] scanType - The type of scan.
  239. * [IN] pixFmtGeneral - the input pixel format for the color data,
  240. * in the "Blend" and "CT" scan types.
  241. * [IN] pixFmtOpaque - the input pixel format for the color data,
  242. * in the "Opaque" scan type.
  243. * [IN] solidColor - the solid fill color for "*SolidFill" scan types.
  244. *
  245. * Return Value:
  246. *
  247. * FALSE if all the necessary buffers couldn't be created
  248. *
  249. * History:
  250. *
  251. * 09/22/1999 gilmanw
  252. * Created it using EpScanEngine as a template
  253. *
  254. \**************************************************************************/
  255. BOOL
  256. EpScanBitmap::Start(
  257. DpDriver *driver,
  258. DpContext *context,
  259. DpBitmap *surface,
  260. NEXTBUFFERFUNCTION *nextBuffer,
  261. EpScanType scanType,
  262. PixelFormatID pixFmtGeneral,
  263. PixelFormatID pixFmtOpaque,
  264. ARGB solidColor
  265. )
  266. {
  267. // Inherit initialization
  268. EpScan::Start(
  269. driver,
  270. context,
  271. surface,
  272. nextBuffer,
  273. scanType,
  274. pixFmtGeneral,
  275. pixFmtOpaque,
  276. solidColor
  277. );
  278. GpStatus status;
  279. BOOL writeOnly = FALSE;
  280. GpCompositingMode compositingMode = context->CompositingMode;
  281. Surface = surface;
  282. if (scanType == EpScanTypeOpaque)
  283. {
  284. writeOnly = TRUE;
  285. }
  286. else
  287. {
  288. // Work out if this operation will write transparent pixels (alpha != 1)
  289. // into the surface for the first time.
  290. switch (surface->SurfaceTransparency)
  291. {
  292. case TransparencyUnknown:
  293. case TransparencyNoAlpha:
  294. break;
  295. case TransparencyOpaque:
  296. // If the surface contains only opaque pixels, the SourceOver
  297. // operation will produce only opaque pixels. So for SourceOver,
  298. // a transition from TransparencyOpaque to TransparencyUnknown is
  299. // impossible.
  300. if ( (scanType == EpScanTypeBlend)
  301. && (compositingMode == CompositingModeSourceOver))
  302. {
  303. break;
  304. }
  305. // Else, fall through:
  306. case TransparencySimple:
  307. // !!![agodfrey]: Theoretically, if the destination pixel format
  308. // is 1555, we could set it to 'TransparencySimple' here.
  309. surface->SurfaceTransparency = TransparencyUnknown;
  310. Bitmap->SetTransparencyHint(surface->SurfaceTransparency);
  311. break;
  312. default:
  313. RIP(("Unrecognized surface transparency"));
  314. break;
  315. }
  316. }
  317. // Pick the appropriate blending function based on the format of the
  318. // bitmap.
  319. ASSERTMSG(Bitmap != NULL, ("EpScanBitmap not initialized"));
  320. PixelFormatID dstFormat;
  321. if (FAILED(Bitmap->GetPixelFormatID(&dstFormat)))
  322. return FALSE;
  323. switch (dstFormat)
  324. {
  325. case PIXFMT_16BPP_RGB555:
  326. case PIXFMT_16BPP_RGB565:
  327. case PIXFMT_24BPP_RGB:
  328. case PIXFMT_32BPP_RGB:
  329. case PIXFMT_32BPP_ARGB:
  330. case PIXFMT_24BPP_BGR:
  331. case PIXFMT_32BPP_PARGB:
  332. // Since we're doing just one lock of the whole image, we have
  333. // to allow read-modify-write since only a portion of the bitmap
  334. // may be written.
  335. BitmapLockFlags = (IMGLOCK_WRITE | IMGLOCK_READ);
  336. *nextBuffer = (NEXTBUFFERFUNCTION) EpScanBitmap::NextBufferNative;
  337. EndFunc = (SCANENDFUNCTION) EpScanBitmap::EndNative;
  338. status = Bitmap->LockBits(NULL, BitmapLockFlags,
  339. dstFormat, &LockedBitmapData);
  340. if (status == Ok)
  341. {
  342. CurrentScan = NULL;
  343. PixelSize = GetPixelFormatSize(dstFormat) >> 3;
  344. break;
  345. }
  346. // else fall into the generic case and use 32bpp ARGB
  347. default:
  348. // When locking a scanline at a time and the mode is SourceCopy,
  349. // the read is unnecessary.
  350. if (writeOnly)
  351. {
  352. BitmapLockFlags = IMGLOCK_WRITE;
  353. }
  354. else
  355. {
  356. BitmapLockFlags = (IMGLOCK_WRITE | IMGLOCK_READ);
  357. }
  358. dstFormat = PIXFMT_32BPP_ARGB;
  359. *nextBuffer = (NEXTBUFFERFUNCTION) EpScanBitmap::NextBuffer32ARGB;
  360. EndFunc = (SCANENDFUNCTION) EpScanBitmap::End32ARGB;
  361. break;
  362. }
  363. // Allocate the temporary buffers.
  364. // Buffers[3] will be given to the caller to be used to pass scans to us.
  365. // Buffers[4] will be used for ClearType data.
  366. if (Buffers[0] == NULL)
  367. {
  368. Size bitmapSize;
  369. status = Bitmap->GetSize(&bitmapSize);
  370. if (status == Ok)
  371. {
  372. Width = bitmapSize.Width;
  373. Height = bitmapSize.Height;
  374. Buffers[0] = GpMalloc(sizeof(ARGB64) * bitmapSize.Width * 5);
  375. if (Buffers[0])
  376. {
  377. int i;
  378. for (i=1;i<5;i++)
  379. {
  380. Buffers[i] = static_cast<BYTE *>(Buffers[i-1]) +
  381. sizeof(ARGB64) * bitmapSize.Width;
  382. }
  383. }
  384. else
  385. {
  386. ONCE(WARNING(("(once) Buffer allocation failed")));
  387. return FALSE;
  388. }
  389. }
  390. else
  391. {
  392. ONCE(WARNING(("(once) GetSize failed")));
  393. return FALSE;
  394. }
  395. }
  396. // initialize the AlphaBlenders.
  397. BlenderConfig[0].Initialize(
  398. dstFormat,
  399. context,
  400. context->Palette,
  401. Buffers,
  402. TRUE,
  403. FALSE,
  404. solidColor
  405. );
  406. BlenderConfig[1].Initialize(
  407. dstFormat,
  408. context,
  409. context->Palette,
  410. Buffers,
  411. TRUE,
  412. FALSE,
  413. solidColor
  414. );
  415. return TRUE;
  416. }
  417. /**************************************************************************\
  418. *
  419. * Function Description:
  420. *
  421. * NextBuffer function used when we have low-level functions that match
  422. * native format of the GpBitmap and we can read/write directly into the
  423. * bitmap bits.
  424. *
  425. * Flushes the previous buffer (if there was), and returns the
  426. * next buffer for doing a SrcOver blend.
  427. *
  428. * Arguments:
  429. *
  430. * [IN] x - Destination pixel coordinate in destination surface
  431. * [IN] y - ""
  432. * [IN] width - Number of pixels needed for the next buffer (can be 0)
  433. * [IN] updateWidth - Number of pixels to update in the current buffer
  434. *
  435. * Return Value:
  436. *
  437. * Points to the resulting scan buffer
  438. *
  439. * History:
  440. *
  441. * 09/22/1999 gilmanw
  442. * Created it using EpScanEngine as a template
  443. *
  444. \**************************************************************************/
  445. VOID *EpScanBitmap::NextBufferNative(
  446. INT x,
  447. INT y,
  448. INT newWidth,
  449. INT updateWidth,
  450. INT blenderNum
  451. )
  452. {
  453. // Flush the previous buffer:
  454. if ((updateWidth != 0) && (CurrentScan != NULL))
  455. {
  456. ASSERTMSG(Buffers[0] != NULL, ("no buffers"));
  457. ASSERTMSG(updateWidth <= Width, ("updateWidth too big"));
  458. // Handle the previous scanline segment.
  459. BlenderConfig[LastBlenderNum].AlphaBlender.Blend(
  460. CurrentScan,
  461. Buffers[3],
  462. updateWidth,
  463. CurrentX - DitherOriginX,
  464. CurrentY - DitherOriginY,
  465. static_cast<BYTE *>(Buffers[4])
  466. );
  467. }
  468. // Now move on to processing this scanline segment.
  469. // The actual blend will be done on the next call through this routine
  470. // when we know the width and the bits have been set into the buffer
  471. // we're returning.
  472. LastBlenderNum = blenderNum;
  473. // Remember the x and y for the brush offset (halftone & dither).
  474. CurrentX = x;
  475. CurrentY = y;
  476. // Get the next destination scan:
  477. CurrentScan = NULL;
  478. // Check that surface clipping has been done properly.
  479. if((y >= 0) && (y < Height) && (x >= 0) && (x < Width))
  480. {
  481. // Clip against the right edge of the bitmap. newWidth is an upper
  482. // bound only - not guaranteed to be clipped.
  483. if (newWidth > (Width - x))
  484. {
  485. newWidth = Width - x;
  486. }
  487. if (newWidth > 0)
  488. {
  489. CurrentScan = static_cast<VOID *>
  490. (static_cast<BYTE *>(LockedBitmapData.Scan0)
  491. + (y * LockedBitmapData.Stride)
  492. + (x * PixelSize));
  493. }
  494. }
  495. else
  496. {
  497. // If we hit this, we're hosed. The OutputSpan routines in the
  498. // DpOutputSpan classes are built assuming correct clipping (at least
  499. // to the data buffer) and hence, if we hit this assert, we're going
  500. // to crash horibly later writing all over memory when we start writing
  501. // outside of the bounds of the destination allocation.
  502. // if you're here, someone broke clipping or the dpi computation.
  503. ASSERTMSG(!((y >= 0) && (y < Height) && (x >= 0) && (x < Width)),
  504. (("EpScanBitmap::NextBufferNative: x, y out of bounds")));
  505. }
  506. return (Buffers[3]);
  507. }
  508. /**************************************************************************\
  509. *
  510. * Function Description:
  511. *
  512. * Generic NextBuffer function that accesses GpBitmap bits
  513. * via GpBitmap::Lock/UnlockBits for each scan.
  514. *
  515. * Flushes the previous buffer (if there was), and returns the
  516. * next buffer for doing a SrcOver blend.
  517. *
  518. * Arguments:
  519. *
  520. * [IN] x - Destination pixel coordinate in destination surface
  521. * [IN] y - ""
  522. * [IN] width - Number of pixels needed for the next buffer (can be 0)
  523. * [IN] updateWidth - Number of pixels to update in the current buffer
  524. *
  525. * Return Value:
  526. *
  527. * Points to the resulting scan buffer
  528. *
  529. * History:
  530. *
  531. * 09/22/1999 gilmanw
  532. * Created it using EpScanEngine as a template
  533. *
  534. \**************************************************************************/
  535. VOID *EpScanBitmap::NextBuffer32ARGB(
  536. INT x,
  537. INT y,
  538. INT newWidth,
  539. INT updateWidth,
  540. INT blenderNum
  541. )
  542. {
  543. // Flush the previous buffer:
  544. if (updateWidth != 0 && BitmapLocked)
  545. {
  546. ASSERTMSG(Buffers[0] != NULL, ("no buffers"));
  547. ASSERTMSG(LockedBitmapData.Scan0 != NULL, ("no previous buffer"));
  548. // Handle the previous scanline segment.
  549. BlenderConfig[LastBlenderNum].AlphaBlender.Blend(
  550. LockedBitmapData.Scan0,
  551. Buffers[3],
  552. updateWidth,
  553. CurrentX - DitherOriginX,
  554. CurrentY - DitherOriginY,
  555. static_cast<BYTE *>(Buffers[4])
  556. );
  557. Bitmap->UnlockBits(&LockedBitmapData);
  558. BitmapLocked = FALSE;
  559. }
  560. else if (BitmapLocked)
  561. {
  562. EpScanBitmap::Flush();
  563. }
  564. // Now move on to processing this scanline segment.
  565. // The actual blend will be done on the next call through this routine
  566. // when we know the width and the bits have been set into the buffer
  567. // we're returning.
  568. LastBlenderNum = blenderNum;
  569. // Remember the x and y for the brush offset (halftone & dither).
  570. CurrentX = x;
  571. CurrentY = y;
  572. // Lock the next destination:
  573. // Check that surface clipping has been done properly.
  574. if((y >= 0) && (y < Height) && (x >= 0) && (x < Width))
  575. {
  576. // Clip against the right edge of the bitmap. newWidth is an upper
  577. // bound only - not guaranteed to be clipped. LockBits needs it
  578. // to be clipped.
  579. if (newWidth > (Width - x))
  580. {
  581. newWidth = Width - x;
  582. }
  583. if (newWidth > 0)
  584. {
  585. GpRect nextRect(x, y, newWidth, 1);
  586. GpStatus status = Bitmap->LockBits(
  587. &nextRect,
  588. BitmapLockFlags,
  589. PixelFormat32bppARGB,
  590. &LockedBitmapData
  591. );
  592. if (status == Ok)
  593. BitmapLocked = TRUE;
  594. }
  595. }
  596. else
  597. {
  598. // If we hit this, we're hosed. The OutputSpan routines in the
  599. // DpOutputSpan classes are built assuming correct clipping (at least
  600. // to the data buffer) and hence, if we hit this assert, we're going
  601. // to crash horibly later writing all over memory when we start writing
  602. // outside of the bounds of the destination allocation.
  603. // if you're here, someone broke clipping or the dpi computation.
  604. ASSERTMSG(!((y >= 0) && (y < Height) && (x >= 0) && (x < Width)),
  605. (("EpScanBitmap::NextBufferNative: x, y out of bounds")));
  606. }
  607. return (Buffers[3]);
  608. }
  609. /**************************************************************************\
  610. *
  611. * Function Description:
  612. *
  613. * Denotes the end of the use of the scan buffer.
  614. *
  615. * Arguments:
  616. *
  617. * NONE
  618. *
  619. * Return Value:
  620. *
  621. * NONE
  622. *
  623. * History:
  624. *
  625. * 09/22/1999 gilmanw
  626. * Created it using EpScanEngine as a template
  627. *
  628. \**************************************************************************/
  629. VOID
  630. EpScanBitmap::End32ARGB(
  631. INT updateWidth
  632. )
  633. {
  634. // Flush the last scan:
  635. EpScanBitmap::NextBuffer32ARGB(0, 0, 0, updateWidth, 0);
  636. }
  637. VOID
  638. EpScanBitmap::EndNative(
  639. INT updateWidth
  640. )
  641. {
  642. // Flush the last scan and release bitmap access:
  643. EpScanBitmap::NextBufferNative(0, 0, 0, updateWidth, 0);
  644. Bitmap->UnlockBits(&LockedBitmapData);
  645. }
  646. VOID
  647. EpScanBitmap::End(
  648. INT updateWidth
  649. )
  650. {
  651. (this->*EndFunc)(updateWidth);
  652. // Lock/UnlockBitmap has to be very aggressive about setting
  653. // TransparancyUnknown in the GpBitmap since the caller could be
  654. // doing anything to the alpha channel. However, the EpScanBitmap
  655. // knows what it is doing, so the surface->SurfaceTransparency is
  656. // more accurate.
  657. Bitmap->SetTransparencyHint(Surface->SurfaceTransparency);
  658. }
  659. /**************************************************************************\
  660. *
  661. * Function Description:
  662. *
  663. * Flush any batched rendering and optionally wait for rendering to finish.
  664. *
  665. * Return Value:
  666. *
  667. * NONE
  668. *
  669. * History:
  670. *
  671. * 09/22/1999 gilmanw
  672. * Created it using EpScanEngine as a template
  673. *
  674. \**************************************************************************/
  675. VOID EpScanBitmap::Flush()
  676. {
  677. if (BitmapLocked && Bitmap)
  678. {
  679. Bitmap->UnlockBits(&LockedBitmapData);
  680. BitmapLocked = FALSE;
  681. }
  682. }