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.

645 lines
16 KiB

  1. /**************************************************************************\
  2. *
  3. * Copyright (c) 2000 Microsoft Corporation
  4. *
  5. * Abstract:
  6. *
  7. * Contains ClearType scan operations
  8. *
  9. * Revision History:
  10. *
  11. * 07/19/2000 mleonov
  12. * Created it.
  13. * 01/11/2001 mleonov
  14. * Reengineered ClearType architecture to allow variable length scan records
  15. *
  16. \**************************************************************************/
  17. #include "precomp.hpp"
  18. static inline VOID
  19. SetupGammaTables(ULONG ulGamma, const BYTE ** gamma, const BYTE ** gammaInv)
  20. {
  21. static BYTE const * const gammaTables[] =
  22. {
  23. Globals::TextContrastTableIdentity, Globals::TextContrastTableIdentity,
  24. Globals::TextContrastTablesDir[0], Globals::TextContrastTablesInv[0],
  25. Globals::TextContrastTablesDir[1], Globals::TextContrastTablesInv[1],
  26. Globals::TextContrastTablesDir[2], Globals::TextContrastTablesInv[2],
  27. Globals::TextContrastTablesDir[3], Globals::TextContrastTablesInv[3],
  28. Globals::TextContrastTablesDir[4], Globals::TextContrastTablesInv[4],
  29. Globals::TextContrastTablesDir[5], Globals::TextContrastTablesInv[5],
  30. Globals::TextContrastTablesDir[6], Globals::TextContrastTablesInv[6],
  31. Globals::TextContrastTablesDir[7], Globals::TextContrastTablesInv[7],
  32. Globals::TextContrastTablesDir[8], Globals::TextContrastTablesInv[8],
  33. Globals::TextContrastTablesDir[9], Globals::TextContrastTablesInv[9],
  34. Globals::TextContrastTablesDir[10], Globals::TextContrastTablesInv[10],
  35. Globals::TextContrastTablesDir[11], Globals::TextContrastTablesInv[11]
  36. };
  37. if (ulGamma > 12)
  38. {
  39. ASSERT(FALSE);
  40. ulGamma = 12;
  41. }
  42. *gamma = gammaTables[2 * ulGamma];
  43. *gammaInv = gammaTables[2 * ulGamma + 1];
  44. } // SetupGammaTables
  45. static __forceinline BYTE
  46. BlendOneChannel(BYTE alphaCT, BYTE alphaBrush, BYTE foreground, BYTE background, const BYTE * gamma, const BYTE * gammaInv)
  47. {
  48. ASSERT(0 <= alphaCT && alphaCT <= CT_SAMPLE_F);
  49. if (alphaCT == 0)
  50. return background;
  51. foreground = gamma[foreground];
  52. background = gamma[background];
  53. ULONG ulongRet = ULONG(0.5 + background + ((double)alphaBrush * (foreground - background) * alphaCT) / (255 * CT_SAMPLE_F));
  54. ASSERT(ulongRet <= 255);
  55. BYTE ret = (BYTE)ulongRet;
  56. ret = gammaInv[ret];
  57. return ret;
  58. } // BlendOneChannel
  59. namespace
  60. {
  61. class ClearTypeSolidBlend
  62. {
  63. const ARGB ArgbF;
  64. const BYTE * ClearTypeBits;
  65. public:
  66. ClearTypeSolidBlend(const ScanOperation::OtherParams * otherParams)
  67. : ClearTypeBits(otherParams->CTBuffer), ArgbF(otherParams->SolidColor)
  68. {}
  69. // always call IsCompletelyTransparent in the beginning of RMW operation
  70. bool IsCompletelyTransparent() const
  71. {
  72. return GetAlpha() == 0;
  73. }
  74. BYTE GetCT() const
  75. {
  76. return *ClearTypeBits;
  77. }
  78. ARGB GetARGB() const
  79. {
  80. return ArgbF;
  81. }
  82. BYTE GetAlpha() const
  83. {
  84. return (BYTE)GpColor::GetAlphaARGB(ArgbF);
  85. }
  86. BYTE GetRed() const
  87. {
  88. return (BYTE)GpColor::GetRedARGB(ArgbF);
  89. }
  90. BYTE GetGreen() const
  91. {
  92. return (BYTE)GpColor::GetGreenARGB(ArgbF);
  93. }
  94. BYTE GetBlue() const
  95. {
  96. return (BYTE)GpColor::GetBlueARGB(ArgbF);
  97. }
  98. bool IsOpaque() const
  99. {
  100. return GetCT() == CT_LOOKUP - 1 && GetAlpha() == 255;
  101. }
  102. bool IsTransparent() const
  103. {
  104. // we took care of zero GetAlpha() in IsCompletelyTransparent()
  105. return GetCT() == 0;
  106. }
  107. bool IsTranslucent() const
  108. {
  109. return !IsTransparent() && !IsOpaque();
  110. }
  111. void operator++()
  112. {
  113. ++ClearTypeBits;
  114. }
  115. }; // class ClearTypeSolidBlend
  116. class ClearTypeCARGBBlend
  117. {
  118. const ARGB * ArgbBrushBits;
  119. const BYTE * ClearTypeBits;
  120. public:
  121. ClearTypeCARGBBlend(const ScanOperation::OtherParams * otherParams)
  122. : ClearTypeBits(otherParams->CTBuffer),
  123. ArgbBrushBits(static_cast<const ARGB*>(otherParams->BlendingScan))
  124. {}
  125. bool IsCompletelyTransparent() const
  126. {
  127. return false;
  128. }
  129. BYTE GetCT() const
  130. {
  131. return *ClearTypeBits;
  132. }
  133. ARGB GetARGB() const
  134. {
  135. return *ArgbBrushBits;
  136. }
  137. BYTE GetAlpha() const
  138. {
  139. return (BYTE)GpColor::GetAlphaARGB(*ArgbBrushBits);
  140. }
  141. BYTE GetRed() const
  142. {
  143. return (BYTE)GpColor::GetRedARGB(*ArgbBrushBits);
  144. }
  145. BYTE GetGreen() const
  146. {
  147. return (BYTE)GpColor::GetGreenARGB(*ArgbBrushBits);
  148. }
  149. BYTE GetBlue() const
  150. {
  151. return (BYTE)GpColor::GetBlueARGB(*ArgbBrushBits);
  152. }
  153. bool IsOpaque() const
  154. {
  155. return GetCT() == CT_LOOKUP - 1 && GetAlpha() == 255;
  156. }
  157. bool IsTransparent() const
  158. {
  159. return GetCT() == 0 || GetAlpha() == 0;
  160. }
  161. bool IsTranslucent() const
  162. {
  163. return !IsTransparent() && !IsOpaque();
  164. }
  165. void operator++()
  166. {
  167. ++ClearTypeBits;
  168. ++ArgbBrushBits;
  169. }
  170. }; // class ClearTypeCARGBBlend
  171. } // namespace
  172. template <class BLENDTYPE>
  173. static VOID ClearTypeBlend(
  174. VOID *dst,
  175. const VOID *src,
  176. INT count,
  177. const ScanOperation::OtherParams *otherParams,
  178. BLENDTYPE & bl
  179. )
  180. {
  181. if (bl.IsCompletelyTransparent())
  182. return;
  183. DEFINE_POINTERS(ARGB, ARGB)
  184. ASSERT(count > 0);
  185. ULONG gammaValue = otherParams->TextContrast;
  186. const BYTE * gamma, * gammaInv;
  187. SetupGammaTables(gammaValue, &gamma, &gammaInv);
  188. do {
  189. if (bl.IsTransparent())
  190. ; // fully transparent case, nothing to do
  191. else if (bl.IsOpaque())
  192. { // fully opaque case, copy the foreground color
  193. *d = bl.GetARGB();
  194. }
  195. else
  196. {
  197. const BYTE blendIndex = bl.GetCT();
  198. ASSERT(0 <= blendIndex && blendIndex <= CT_LOOKUP - 1);
  199. const Globals::F_RGB blend = Globals::gaOutTable[blendIndex];
  200. const ARGB source = *s;
  201. const BYTE alphaBrush = bl.GetAlpha();
  202. const BYTE dstRed = BlendOneChannel(
  203. blend.kR,
  204. alphaBrush,
  205. bl.GetRed(),
  206. (BYTE)GpColor::GetRedARGB(source),
  207. gamma,
  208. gammaInv);
  209. const BYTE dstGre = BlendOneChannel(
  210. blend.kG,
  211. alphaBrush,
  212. bl.GetGreen(),
  213. (BYTE)GpColor::GetGreenARGB(source),
  214. gamma,
  215. gammaInv);
  216. const BYTE dstBlu = BlendOneChannel(
  217. blend.kB,
  218. alphaBrush,
  219. bl.GetBlue(),
  220. (BYTE)GpColor::GetBlueARGB(source),
  221. gamma,
  222. gammaInv);
  223. *d = GpColor::MakeARGB(255, dstRed, dstGre, dstBlu);
  224. }
  225. ++bl;
  226. ++s;
  227. ++d;
  228. } while (--count);
  229. } // ClearTypeBlend
  230. VOID FASTCALL
  231. ScanOperation::CTBlendCARGB(
  232. VOID *dst,
  233. const VOID *src,
  234. INT count,
  235. const OtherParams *otherParams
  236. )
  237. {
  238. ClearTypeCARGBBlend bl(otherParams);
  239. ClearTypeBlend(dst, src, count, otherParams, bl);
  240. } // ScanOperation::CTBlendCARGB
  241. VOID FASTCALL
  242. ScanOperation::CTBlendSolid(
  243. VOID *dst,
  244. const VOID *src,
  245. INT count,
  246. const OtherParams *otherParams
  247. )
  248. {
  249. ClearTypeSolidBlend bl(otherParams);
  250. ClearTypeBlend(dst, src, count, otherParams, bl);
  251. } // ScanOperation::CTBlendSolid
  252. template <class BLENDTYPE>
  253. static VOID
  254. CTReadRMW16(
  255. VOID *dst,
  256. const VOID *src,
  257. INT count,
  258. const ScanOperation::OtherParams *otherParams,
  259. BLENDTYPE & bl
  260. )
  261. {
  262. if (bl.IsCompletelyTransparent())
  263. return;
  264. DEFINE_POINTERS(UINT16, UINT16)
  265. // We want to get dword alignment for our copies, so handle the
  266. // initial partial dword, if there is one:
  267. if (((ULONG_PTR) s) & 0x2)
  268. {
  269. if (bl.IsTranslucent())
  270. {
  271. *(d) = *(s);
  272. }
  273. d++;
  274. s++;
  275. ++bl;
  276. count--;
  277. }
  278. // Now go through the aligned dword loop:
  279. while ((count -= 2) >= 0)
  280. {
  281. if (bl.IsTranslucent())
  282. {
  283. ++bl;
  284. if (bl.IsTranslucent())
  285. {
  286. // Both pixels have partial alpha, so do a dword read:
  287. *((UNALIGNED UINT32*) d) = *((UINT32*) s);
  288. }
  289. else
  290. {
  291. // Only the first pixel has partial alpha, so do a word read:
  292. *(d) = *(s);
  293. }
  294. }
  295. else
  296. {
  297. ++bl;
  298. if (bl.IsTranslucent())
  299. {
  300. // Only the second pixel has partial alpha, so do a word read:
  301. *(d + 1) = *(s + 1);
  302. }
  303. }
  304. d += 2;
  305. s += 2;
  306. ++bl;
  307. }
  308. // Handle the end alignment:
  309. if (count & 1)
  310. {
  311. if (bl.IsTranslucent())
  312. {
  313. *(d) = *(s);
  314. }
  315. }
  316. } // CTReadRMW16
  317. VOID FASTCALL ScanOperation::ReadRMW_16_CT_CARGB(
  318. VOID *dst,
  319. const VOID *src,
  320. INT count,
  321. const OtherParams *otherParams
  322. )
  323. {
  324. ClearTypeCARGBBlend bl(otherParams);
  325. CTReadRMW16(dst, src, count, otherParams, bl);
  326. } // ScanOperation::ReadRMW_16_CT_CARGB
  327. VOID FASTCALL ScanOperation::ReadRMW_16_CT_Solid(
  328. VOID *dst,
  329. const VOID *src,
  330. INT count,
  331. const OtherParams *otherParams
  332. )
  333. {
  334. ClearTypeSolidBlend bl(otherParams);
  335. CTReadRMW16(dst, src, count, otherParams, bl);
  336. } // ScanOperation::ReadRMW_16_CT_Solid
  337. template <class BLENDTYPE>
  338. static VOID
  339. CTReadRMW24(
  340. VOID *dst,
  341. const VOID *src,
  342. INT count,
  343. const ScanOperation::OtherParams *otherParams,
  344. BLENDTYPE & bl
  345. )
  346. {
  347. if (bl.IsCompletelyTransparent())
  348. return;
  349. DEFINE_POINTERS(BYTE, BYTE)
  350. ULONG_PTR srcToDstDelta = (ULONG_PTR) d - (ULONG_PTR) s;
  351. // Handle the initial partial read:
  352. INT initialAlignment = (INT) ((ULONG_PTR) s & 3);
  353. if (initialAlignment)
  354. {
  355. if (bl.IsTranslucent())
  356. {
  357. UINT32 *alignedSrc = (UINT32*) ((ULONG_PTR) s & ~3);
  358. DWORD dwBuffer[2];
  359. // Get pointer to start of pixel inside dwBuffer
  360. BYTE *pByte = (BYTE*) dwBuffer + initialAlignment;
  361. // Copy first aligned DWORDS from the source
  362. dwBuffer[0] = *alignedSrc;
  363. // Copy next one only if pixel is split between 2 aligned DWORDS
  364. if (initialAlignment >= 2)
  365. dwBuffer[1] = *(alignedSrc + 1);
  366. // Copy 4 bytes to the destination
  367. // This will cause an extra byte to have garbage in the
  368. // destination buffer, but will be overwritten if next pixel
  369. // is used.
  370. *((DWORD*) d) = *((UNALIGNED DWORD*) pByte);
  371. }
  372. ++bl;
  373. s += 3;
  374. if (--count == 0)
  375. return;
  376. }
  377. while (TRUE)
  378. {
  379. // Find the first pixel to copy
  380. while (!bl.IsTranslucent())
  381. {
  382. ++bl;
  383. s += 3;
  384. if (--count == 0)
  385. {
  386. return;
  387. }
  388. }
  389. UINT32 *startSrc = (UINT32*) ((ULONG_PTR) (s) & ~3);
  390. // Now find the first "don't copy" pixel after that:
  391. while (bl.IsTranslucent())
  392. {
  393. ++bl;
  394. s += 3;
  395. if (--count == 0)
  396. {
  397. break;
  398. }
  399. }
  400. // 'endSrc' is inclusive of the last pixel's last byte:
  401. UINT32 *endSrc = (UINT32*) ((ULONG_PTR) (s + 2) & ~3);
  402. UNALIGNED UINT32 *dstPtr = (UNALIGNED UINT32*) ((ULONG_PTR) startSrc + srcToDstDelta);
  403. while (startSrc <= endSrc)
  404. {
  405. *dstPtr++ = *startSrc++;
  406. }
  407. if (count == 0)
  408. return;
  409. }
  410. } // CTReadRMW24
  411. VOID FASTCALL ScanOperation::ReadRMW_24_CT_CARGB(
  412. VOID *dst,
  413. const VOID *src,
  414. INT count,
  415. const OtherParams *otherParams
  416. )
  417. {
  418. ClearTypeCARGBBlend bl(otherParams);
  419. CTReadRMW24(dst, src, count, otherParams, bl);
  420. } // ScanOperation::ReadRMW_24_CT_CARGB
  421. VOID FASTCALL ScanOperation::ReadRMW_24_CT_Solid(
  422. VOID *dst,
  423. const VOID *src,
  424. INT count,
  425. const OtherParams *otherParams
  426. )
  427. {
  428. ClearTypeSolidBlend bl(otherParams);
  429. CTReadRMW24(dst, src, count, otherParams, bl);
  430. } // ScanOperation::ReadRMW_24_CT_Solid
  431. template <class BLENDTYPE>
  432. static VOID
  433. CTWriteRMW16(
  434. VOID *dst,
  435. const VOID *src,
  436. INT count,
  437. const ScanOperation::OtherParams *otherParams,
  438. BLENDTYPE & bl
  439. )
  440. {
  441. if (bl.IsCompletelyTransparent())
  442. return;
  443. DEFINE_POINTERS(UINT16, UINT16)
  444. // We want to get dword alignment for our copies, so handle the
  445. // initial partial dword, if there is one:
  446. if (((ULONG_PTR) d) & 0x2)
  447. {
  448. if (!bl.IsTransparent())
  449. {
  450. *(d) = *(s);
  451. }
  452. d++;
  453. s++;
  454. ++bl;
  455. count--;
  456. }
  457. // Now go through the aligned dword loop:
  458. while ((count -= 2) >= 0)
  459. {
  460. if (!bl.IsTransparent())
  461. {
  462. ++bl;
  463. if (!bl.IsTransparent())
  464. {
  465. // Both pixels have partial bl, so do a dword read:
  466. *((UINT32*) d) = *((UNALIGNED UINT32*) s);
  467. }
  468. else
  469. {
  470. // Only the first pixel has partial bl, so do a word read:
  471. *(d) = *(s);
  472. }
  473. }
  474. else
  475. {
  476. ++bl;
  477. if (!bl.IsTransparent())
  478. {
  479. // Only the second pixel has partial bl, so do a word read:
  480. *(d + 1) = *(s + 1);
  481. }
  482. }
  483. d += 2;
  484. s += 2;
  485. ++bl;
  486. }
  487. // Handle the end alignment:
  488. if (count & 1)
  489. {
  490. if (!bl.IsTransparent())
  491. {
  492. *(d) = *(s);
  493. }
  494. }
  495. } // CTWriteRMW16
  496. VOID FASTCALL ScanOperation::WriteRMW_16_CT_CARGB(
  497. VOID *dst,
  498. const VOID *src,
  499. INT count,
  500. const OtherParams *otherParams
  501. )
  502. {
  503. ClearTypeCARGBBlend bl(otherParams);
  504. CTWriteRMW16(dst, src, count, otherParams, bl);
  505. } // ScanOperation::WriteRMW_16_CT_CARGB
  506. VOID FASTCALL ScanOperation::WriteRMW_16_CT_Solid(
  507. VOID *dst,
  508. const VOID *src,
  509. INT count,
  510. const OtherParams *otherParams
  511. )
  512. {
  513. ClearTypeSolidBlend bl(otherParams);
  514. CTWriteRMW16(dst, src, count, otherParams, bl);
  515. } // ScanOperation::WriteRMW_16_CT_Solid
  516. template <class BLENDTYPE>
  517. static VOID
  518. CTWriteRMW24(
  519. VOID *dst,
  520. const VOID *src,
  521. INT count,
  522. const ScanOperation::OtherParams *otherParams,
  523. BLENDTYPE & bl
  524. )
  525. {
  526. DEFINE_POINTERS(BYTE, BYTE)
  527. ASSERT(count>0);
  528. do {
  529. if (!bl.IsTransparent())
  530. {
  531. // Doing byte per byte writes are much faster than finding
  532. // runs and doing DWORD copies.
  533. *(d) = *(s);
  534. *(d + 1) = *(s + 1);
  535. *(d + 2) = *(s + 2);
  536. }
  537. d += 3;
  538. s += 3;
  539. ++bl;
  540. } while (--count != 0);
  541. } // CTWriteRMW24
  542. VOID FASTCALL ScanOperation::WriteRMW_24_CT_CARGB(
  543. VOID *dst,
  544. const VOID *src,
  545. INT count,
  546. const OtherParams *otherParams
  547. )
  548. {
  549. ClearTypeCARGBBlend bl(otherParams);
  550. CTWriteRMW24(dst, src, count, otherParams, bl);
  551. } // ScanOperation::WriteRMW_24_CT_CARGB
  552. VOID FASTCALL ScanOperation::WriteRMW_24_CT_Solid(
  553. VOID *dst,
  554. const VOID *src,
  555. INT count,
  556. const OtherParams *otherParams
  557. )
  558. {
  559. ClearTypeSolidBlend bl(otherParams);
  560. CTWriteRMW24(dst, src, count, otherParams, bl);
  561. } // ScanOperation::WriteRMW_24_CT_CARGB