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.

2974 lines
89 KiB

  1. /**************************************************************************\
  2. *
  3. * Copyright (c) 1998 Microsoft Corporation
  4. *
  5. * Module Name:
  6. *
  7. * GradientFill.cpp
  8. *
  9. * Abstract:
  10. *
  11. * gradient fill routines.
  12. *
  13. * Revision History:
  14. *
  15. * 01/21/1999 ikkof
  16. * Created it.
  17. *
  18. \**************************************************************************/
  19. #include "precomp.hpp"
  20. #define CLAMP_COLOR_CHANNEL(a, b) \
  21. if(a < 0) \
  22. { \
  23. a = 0; \
  24. } \
  25. if(a > b) \
  26. { \
  27. a = b; \
  28. }
  29. // 10bit inverse gamma 2.2 look up table.
  30. static const BYTE TenBitInvGamma2_2 [] = {
  31. 0, 11, 15, 18, 21, 23, 25, 26,
  32. 28, 30, 31, 32, 34, 35, 36, 37,
  33. 39, 40, 41, 42, 43, 44, 45, 45,
  34. 46, 47, 48, 49, 50, 50, 51, 52,
  35. 53, 54, 54, 55, 56, 56, 57, 58,
  36. 58, 59, 60, 60, 61, 62, 62, 63,
  37. 63, 64, 65, 65, 66, 66, 67, 68,
  38. 68, 69, 69, 70, 70, 71, 71, 72,
  39. 72, 73, 73, 74, 74, 75, 75, 76,
  40. 76, 77, 77, 78, 78, 79, 79, 80,
  41. 80, 81, 81, 81, 82, 82, 83, 83,
  42. 84, 84, 84, 85, 85, 86, 86, 87,
  43. 87, 87, 88, 88, 89, 89, 89, 90,
  44. 90, 91, 91, 91, 92, 92, 93, 93,
  45. 93, 94, 94, 94, 95, 95, 96, 96,
  46. 96, 97, 97, 97, 98, 98, 98, 99,
  47. 99, 99, 100, 100, 101, 101, 101, 102,
  48. 102, 102, 103, 103, 103, 104, 104, 104,
  49. 105, 105, 105, 106, 106, 106, 107, 107,
  50. 107, 108, 108, 108, 108, 109, 109, 109,
  51. 110, 110, 110, 111, 111, 111, 112, 112,
  52. 112, 112, 113, 113, 113, 114, 114, 114,
  53. 115, 115, 115, 115, 116, 116, 116, 117,
  54. 117, 117, 117, 118, 118, 118, 119, 119,
  55. 119, 119, 120, 120, 120, 121, 121, 121,
  56. 121, 122, 122, 122, 123, 123, 123, 123,
  57. 124, 124, 124, 124, 125, 125, 125, 125,
  58. 126, 126, 126, 127, 127, 127, 127, 128,
  59. 128, 128, 128, 129, 129, 129, 129, 130,
  60. 130, 130, 130, 131, 131, 131, 131, 132,
  61. 132, 132, 132, 133, 133, 133, 133, 134,
  62. 134, 134, 134, 135, 135, 135, 135, 136,
  63. 136, 136, 136, 137, 137, 137, 137, 138,
  64. 138, 138, 138, 138, 139, 139, 139, 139,
  65. 140, 140, 140, 140, 141, 141, 141, 141,
  66. 142, 142, 142, 142, 142, 143, 143, 143,
  67. 143, 144, 144, 144, 144, 144, 145, 145,
  68. 145, 145, 146, 146, 146, 146, 146, 147,
  69. 147, 147, 147, 148, 148, 148, 148, 148,
  70. 149, 149, 149, 149, 149, 150, 150, 150,
  71. 150, 151, 151, 151, 151, 151, 152, 152,
  72. 152, 152, 152, 153, 153, 153, 153, 154,
  73. 154, 154, 154, 154, 155, 155, 155, 155,
  74. 155, 156, 156, 156, 156, 156, 157, 157,
  75. 157, 157, 157, 158, 158, 158, 158, 158,
  76. 159, 159, 159, 159, 159, 160, 160, 160,
  77. 160, 160, 161, 161, 161, 161, 161, 162,
  78. 162, 162, 162, 162, 163, 163, 163, 163,
  79. 163, 164, 164, 164, 164, 164, 165, 165,
  80. 165, 165, 165, 165, 166, 166, 166, 166,
  81. 166, 167, 167, 167, 167, 167, 168, 168,
  82. 168, 168, 168, 168, 169, 169, 169, 169,
  83. 169, 170, 170, 170, 170, 170, 171, 171,
  84. 171, 171, 171, 171, 172, 172, 172, 172,
  85. 172, 173, 173, 173, 173, 173, 173, 174,
  86. 174, 174, 174, 174, 174, 175, 175, 175,
  87. 175, 175, 176, 176, 176, 176, 176, 176,
  88. 177, 177, 177, 177, 177, 177, 178, 178,
  89. 178, 178, 178, 179, 179, 179, 179, 179,
  90. 179, 180, 180, 180, 180, 180, 180, 181,
  91. 181, 181, 181, 181, 181, 182, 182, 182,
  92. 182, 182, 182, 183, 183, 183, 183, 183,
  93. 183, 184, 184, 184, 184, 184, 185, 185,
  94. 185, 185, 185, 185, 186, 186, 186, 186,
  95. 186, 186, 186, 187, 187, 187, 187, 187,
  96. 187, 188, 188, 188, 188, 188, 188, 189,
  97. 189, 189, 189, 189, 189, 190, 190, 190,
  98. 190, 190, 190, 191, 191, 191, 191, 191,
  99. 191, 192, 192, 192, 192, 192, 192, 192,
  100. 193, 193, 193, 193, 193, 193, 194, 194,
  101. 194, 194, 194, 194, 195, 195, 195, 195,
  102. 195, 195, 195, 196, 196, 196, 196, 196,
  103. 196, 197, 197, 197, 197, 197, 197, 197,
  104. 198, 198, 198, 198, 198, 198, 199, 199,
  105. 199, 199, 199, 199, 199, 200, 200, 200,
  106. 200, 200, 200, 201, 201, 201, 201, 201,
  107. 201, 201, 202, 202, 202, 202, 202, 202,
  108. 202, 203, 203, 203, 203, 203, 203, 204,
  109. 204, 204, 204, 204, 204, 204, 205, 205,
  110. 205, 205, 205, 205, 205, 206, 206, 206,
  111. 206, 206, 206, 206, 207, 207, 207, 207,
  112. 207, 207, 207, 208, 208, 208, 208, 208,
  113. 208, 209, 209, 209, 209, 209, 209, 209,
  114. 210, 210, 210, 210, 210, 210, 210, 211,
  115. 211, 211, 211, 211, 211, 211, 212, 212,
  116. 212, 212, 212, 212, 212, 213, 213, 213,
  117. 213, 213, 213, 213, 213, 214, 214, 214,
  118. 214, 214, 214, 214, 215, 215, 215, 215,
  119. 215, 215, 215, 216, 216, 216, 216, 216,
  120. 216, 216, 217, 217, 217, 217, 217, 217,
  121. 217, 218, 218, 218, 218, 218, 218, 218,
  122. 218, 219, 219, 219, 219, 219, 219, 219,
  123. 220, 220, 220, 220, 220, 220, 220, 221,
  124. 221, 221, 221, 221, 221, 221, 221, 222,
  125. 222, 222, 222, 222, 222, 222, 223, 223,
  126. 223, 223, 223, 223, 223, 223, 224, 224,
  127. 224, 224, 224, 224, 224, 225, 225, 225,
  128. 225, 225, 225, 225, 225, 226, 226, 226,
  129. 226, 226, 226, 226, 226, 227, 227, 227,
  130. 227, 227, 227, 227, 228, 228, 228, 228,
  131. 228, 228, 228, 228, 229, 229, 229, 229,
  132. 229, 229, 229, 229, 230, 230, 230, 230,
  133. 230, 230, 230, 230, 231, 231, 231, 231,
  134. 231, 231, 231, 232, 232, 232, 232, 232,
  135. 232, 232, 232, 233, 233, 233, 233, 233,
  136. 233, 233, 233, 234, 234, 234, 234, 234,
  137. 234, 234, 234, 235, 235, 235, 235, 235,
  138. 235, 235, 235, 236, 236, 236, 236, 236,
  139. 236, 236, 236, 237, 237, 237, 237, 237,
  140. 237, 237, 237, 238, 238, 238, 238, 238,
  141. 238, 238, 238, 238, 239, 239, 239, 239,
  142. 239, 239, 239, 239, 240, 240, 240, 240,
  143. 240, 240, 240, 240, 241, 241, 241, 241,
  144. 241, 241, 241, 241, 242, 242, 242, 242,
  145. 242, 242, 242, 242, 243, 243, 243, 243,
  146. 243, 243, 243, 243, 243, 244, 244, 244,
  147. 244, 244, 244, 244, 244, 245, 245, 245,
  148. 245, 245, 245, 245, 245, 245, 246, 246,
  149. 246, 246, 246, 246, 246, 246, 247, 247,
  150. 247, 247, 247, 247, 247, 247, 248, 248,
  151. 248, 248, 248, 248, 248, 248, 248, 249,
  152. 249, 249, 249, 249, 249, 249, 249, 249,
  153. 250, 250, 250, 250, 250, 250, 250, 250,
  154. 251, 251, 251, 251, 251, 251, 251, 251,
  155. 251, 252, 252, 252, 252, 252, 252, 252,
  156. 252, 252, 253, 253, 253, 253, 253, 253,
  157. 253, 253, 254, 254, 254, 254, 254, 254,
  158. 254, 254, 254, 255, 255, 255, 255, 255
  159. };
  160. // 8bit to float gamma 2.2 LUT.
  161. static const REAL Gamma2_2LUT[] = {
  162. 0.000000000f, 0.001294648f, 0.005948641f, 0.014515050f,
  163. 0.027332777f, 0.044656614f, 0.066693657f, 0.093619749f,
  164. 0.125588466f, 0.162736625f, 0.205187917f, 0.253055448f,
  165. 0.306443578f, 0.365449320f, 0.430163406f, 0.500671134f,
  166. 0.577053056f, 0.659385527f, 0.747741173f, 0.842189273f,
  167. 0.942796093f, 1.049625159f, 1.162737505f, 1.282191881f,
  168. 1.408044937f, 1.540351382f, 1.679164133f, 1.824534436f,
  169. 1.976511986f, 2.135145025f, 2.300480434f, 2.472563819f,
  170. 2.651439585f, 2.837151004f, 3.029740281f, 3.229248608f,
  171. 3.435716220f, 3.649182441f, 3.869685731f, 4.097263727f,
  172. 4.331953283f, 4.573790502f, 4.822810773f, 5.079048802f,
  173. 5.342538638f, 5.613313704f, 5.891406820f, 6.176850227f,
  174. 6.469675611f, 6.769914121f, 7.077596394f, 7.392752570f,
  175. 7.715412307f, 8.045604807f, 8.383358822f, 8.728702674f,
  176. 9.081664270f, 9.442271111f, 9.810550312f, 10.18652861f,
  177. 10.57023236f, 10.96168759f, 11.36091997f, 11.76795482f,
  178. 12.18281716f, 12.60553168f, 13.03612276f, 13.47461451f,
  179. 13.92103071f, 14.37539488f, 14.83773026f, 15.30805982f,
  180. 15.78640628f, 16.27279209f, 16.76723947f, 17.26977037f,
  181. 17.78040653f, 18.29916946f, 18.82608041f, 19.36116046f,
  182. 19.90443044f, 20.45591098f, 21.01562250f, 21.58358523f,
  183. 22.15981921f, 22.74434425f, 23.33718001f, 23.93834596f,
  184. 24.54786138f, 25.16574537f, 25.79201687f, 26.42669465f,
  185. 27.06979729f, 27.72134324f, 28.38135078f, 29.04983802f,
  186. 29.72682293f, 30.41232332f, 31.10635686f, 31.80894107f,
  187. 32.52009334f, 33.23983090f, 33.96817086f, 34.70513018f,
  188. 35.45072570f, 36.20497412f, 36.96789203f, 37.73949586f,
  189. 38.51980195f, 39.30882651f, 40.10658561f, 40.91309523f,
  190. 41.72837123f, 42.55242933f, 43.38528517f, 44.22695426f,
  191. 45.07745202f, 45.93679373f, 46.80499461f, 47.68206973f,
  192. 48.56803410f, 49.46290260f, 50.36669002f, 51.27941105f,
  193. 52.20108030f, 53.13171227f, 54.07132136f, 55.01992190f,
  194. 55.97752811f, 56.94415413f, 57.91981400f, 58.90452170f,
  195. 59.89829110f, 60.90113599f, 61.91307008f, 62.93410700f,
  196. 63.96426029f, 65.00354342f, 66.05196978f, 67.10955268f,
  197. 68.17630535f, 69.25224094f, 70.33737253f, 71.43171314f,
  198. 72.53527570f, 73.64807306f, 74.77011803f, 75.90142331f,
  199. 77.04200157f, 78.19186538f, 79.35102726f, 80.51949965f,
  200. 81.69729494f, 82.88442544f, 84.08090341f, 85.28674102f,
  201. 86.50195041f, 87.72654363f, 88.96053269f, 90.20392952f,
  202. 91.45674601f, 92.71899397f, 93.99068516f, 95.27183128f,
  203. 96.56244399f, 97.86253485f, 99.17211542f, 100.4911972f,
  204. 101.8197915f, 103.1579098f, 104.5055633f, 105.8627634f,
  205. 107.2295212f, 108.6058479f, 109.9917545f, 111.3872522f,
  206. 112.7923519f, 114.2070647f, 115.6314012f, 117.0653726f,
  207. 118.5089894f, 119.9622626f, 121.4252027f, 122.8978204f,
  208. 124.3801265f, 125.8721313f, 127.3738455f, 128.8852796f,
  209. 130.4064438f, 131.9373487f, 133.4780046f, 135.0284217f,
  210. 136.5886104f, 138.1585808f, 139.7383431f, 141.3279074f,
  211. 142.9272838f, 144.5364824f, 146.1555131f, 147.7843860f,
  212. 149.4231109f, 151.0716977f, 152.7301563f, 154.3984965f,
  213. 156.0767280f, 157.7648605f, 159.4629038f, 161.1708675f,
  214. 162.8887612f, 164.6165945f, 166.3543769f, 168.1021179f,
  215. 169.8598270f, 171.6275137f, 173.4051873f, 175.1928571f,
  216. 176.9905325f, 178.7982229f, 180.6159374f, 182.4436852f,
  217. 184.2814757f, 186.1293178f, 187.9872208f, 189.8551937f,
  218. 191.7332455f, 193.6213854f, 195.5196223f, 197.4279651f,
  219. 199.3464228f, 201.2750043f, 203.2137184f, 205.1625740f,
  220. 207.1215799f, 209.0907449f, 211.0700776f, 213.0595868f,
  221. 215.0592813f, 217.0691695f, 219.0892603f, 221.1195621f,
  222. 223.1600835f, 225.2108331f, 227.2718194f, 229.3430508f,
  223. 231.4245359f, 233.5162830f, 235.6183005f, 237.7305968f,
  224. 239.8531803f, 241.9860592f, 244.1292419f, 246.2827366f,
  225. 248.4465516f, 250.6206950f, 252.8051751f, 255.0000000f,
  226. };
  227. /**************************************************************************\
  228. *
  229. * Function Description:
  230. *
  231. * Arguments:
  232. *
  233. * Created:
  234. *
  235. * 04/26/1999 ikkof
  236. *
  237. \**************************************************************************/
  238. DpOutputSpan *
  239. DpOutputSpan::Create(
  240. const DpBrush * dpBrush,
  241. DpScanBuffer * scan,
  242. DpContext *context,
  243. const GpRect *drawBounds
  244. )
  245. {
  246. const GpBrush * brush = GpBrush::GetBrush( (DpBrush *)(dpBrush));
  247. if(brush)
  248. {
  249. return ((GpBrush*) brush)->CreateOutputSpan(scan, context, drawBounds);
  250. }
  251. else
  252. return NULL;
  253. }
  254. /**************************************************************************\
  255. *
  256. * Function Description:
  257. *
  258. * Gradient brush constructor.
  259. *
  260. * Arguments:
  261. *
  262. * Created:
  263. *
  264. * 04/26/1999 ikkof
  265. *
  266. \**************************************************************************/
  267. DpOutputGradientSpan::DpOutputGradientSpan(
  268. const GpElementaryBrush *brush,
  269. DpScanBuffer * scan,
  270. DpContext* context
  271. )
  272. {
  273. Scan = scan;
  274. CompositingMode = context->CompositingMode;
  275. Brush = brush;
  276. BrushType = brush->GetBrushType();
  277. brush->GetRect(BrushRect);
  278. WrapMode = brush->GetWrapMode();
  279. // Incorporate the brush's transform into the graphics context's
  280. // current transform:
  281. GpMatrix xForm;
  282. brush->GetTransform(&xForm);
  283. WorldToDevice = context->WorldToDevice;
  284. WorldToDevice.Prepend(xForm);
  285. // !!![andrewgo] garbage is left in DeviceToWorld if not invertible
  286. if(WorldToDevice.IsInvertible())
  287. {
  288. DeviceToWorld = WorldToDevice;
  289. DeviceToWorld.Invert();
  290. }
  291. InitDefaultColorArrays(brush);
  292. }
  293. /**************************************************************************\
  294. *
  295. * Function Description:
  296. *
  297. * Converts the input value by using the blend factors and
  298. * blend positions.
  299. *
  300. \**************************************************************************/
  301. REAL
  302. slowAdjustValue(
  303. REAL x, INT count,
  304. REAL falloff,
  305. REAL* blendFactors,
  306. REAL* blendPositions
  307. )
  308. {
  309. REAL value = x;
  310. if(count == 1 && falloff != 1 && falloff > 0)
  311. {
  312. if((x >= 0.0f) && (x <= 1.0f))
  313. value = (REAL) pow(x, falloff);
  314. }
  315. else if(count >= 2 && blendFactors && blendPositions)
  316. {
  317. // This has to be an 'equality' test, because the
  318. // DpOutputLinearGradientSpan fast-path samples only
  319. // discretely, and it starts at exactly 0.0 and ends
  320. // exactly at 1.0. We don't actually have to incorporate
  321. // an epsilon in that case because it always gives us
  322. // exactly 0.0 and 1.0 for the start and end.
  323. if((x >= 0.0f) && (x <= 1.0f))
  324. {
  325. INT index = 1;
  326. // Look for the interval.
  327. while( ((x-blendPositions[index]) > REAL_EPSILON) &&
  328. (index < count) )
  329. {
  330. index++;
  331. }
  332. // Interpolate.
  333. if(index < count)
  334. {
  335. REAL d = blendPositions[index] - blendPositions[index - 1];
  336. if(d > 0)
  337. {
  338. REAL t = (x - blendPositions[index - 1])/d;
  339. value = blendFactors[index - 1]
  340. + t*(blendFactors[index] - blendFactors[index - 1]);
  341. }
  342. else
  343. value = (blendFactors[index - 1] + blendFactors[index])/2;
  344. }
  345. }
  346. }
  347. return value;
  348. }
  349. // We make this routine inline because it's nice and small and very
  350. // frequently we don't even have to call 'slowAdjustValue'.
  351. inline
  352. REAL
  353. adjustValue(
  354. REAL x, INT count,
  355. REAL falloff,
  356. REAL* blendFactors,
  357. REAL* blendPositions
  358. )
  359. {
  360. REAL value = x;
  361. if(count != 1 || falloff != 1)
  362. {
  363. value = slowAdjustValue(x, count, falloff, blendFactors, blendPositions);
  364. }
  365. return value;
  366. }
  367. /**************************************************************************\
  368. *
  369. * Function Description:
  370. *
  371. * GammaLinearizeAndPremultiply
  372. *
  373. * This function takes non-premultiplied ARGB input and emits a
  374. * Gamma converted (2.2) output 128bit floating point premultiplied
  375. * color value
  376. *
  377. * Arguments:
  378. *
  379. * [IN] ARGB - input premultiplied floating point color value
  380. * [IN] gammaCorrect - turn on gamma correction logic
  381. * [OUT] color - output color value. 128bit float color. premultiplied
  382. *
  383. * 10/31/2000 asecchia
  384. * Created
  385. *
  386. \**************************************************************************/
  387. VOID GammaLinearizeAndPremultiply(
  388. ARGB argb, // Non-premultiplied input.
  389. BOOL gammaCorrect,
  390. GpFColor128 *color // pre-multiplied output.
  391. )
  392. {
  393. // Alpha (opacity) shouldn't be gamma corrected.
  394. color->a = (REAL)GpColor::GetAlphaARGB(argb);
  395. // Alpha zero...
  396. if(REALABS((color->a)) < REAL_EPSILON)
  397. {
  398. color->r = 0.0f;
  399. color->g = 0.0f;
  400. color->b = 0.0f;
  401. // we're done.
  402. return;
  403. }
  404. if(gammaCorrect)
  405. {
  406. // use the gamma 2.2 lookup table to convert r, g, b.
  407. color->r = Gamma2_2LUT[GpColor::GetRedARGB(argb)];
  408. color->g = Gamma2_2LUT[GpColor::GetGreenARGB(argb)];
  409. color->b = Gamma2_2LUT[GpColor::GetBlueARGB(argb)];
  410. }
  411. else
  412. {
  413. color->r = (REAL)GpColor::GetRedARGB(argb);
  414. color->g = (REAL)GpColor::GetGreenARGB(argb);
  415. color->b = (REAL)GpColor::GetBlueARGB(argb);
  416. }
  417. // Alpha != 255
  418. if(REALABS((color->a)-255.0f) >= REAL_EPSILON)
  419. {
  420. // Do the premultiplication.
  421. color->r *= (color->a)/255.0f;
  422. color->g *= (color->a)/255.0f;
  423. color->b *= (color->a)/255.0f;
  424. }
  425. }
  426. /**************************************************************************\
  427. *
  428. * Function Description:
  429. *
  430. * GammaUnlinearizePremultiplied128.
  431. *
  432. * This function takes a 128bit floating point premultiplied color and
  433. * performs the inverse gamma correction step.
  434. *
  435. * First the color value is unpremultiplied - then the r,g,b channels are
  436. * scaled into the range 0-1023 and rounded so that they match our 10bit
  437. * gamma lookup table. We pass it through the 1/2.2 gamma LUT and
  438. * premultiply the output.
  439. *
  440. * Arguments:
  441. *
  442. * [IN] color - input premultiplied floating point color value
  443. *
  444. * Return:
  445. *
  446. * ARGB - output premultiplied 32bpp integer color (gamma corrected).
  447. *
  448. * 10/31/2000 asecchia
  449. * Created
  450. *
  451. \**************************************************************************/
  452. ARGB GammaUnlinearizePremultiplied128(
  453. const GpFColor128 &color
  454. )
  455. {
  456. // Do the gamma conversion thing. Ten bits is enough.
  457. INT iA, iR, iG, iB;
  458. // First unpremultiply. Don't do gamma conversion on the alpha channel.
  459. iA = GpRound(color.a);
  460. // make sure we're passed a valid input alpha channel.
  461. ASSERT(iA >= 0);
  462. ASSERT(iA <= 255);
  463. // full transparency.
  464. if(iA == 0)
  465. {
  466. iR = iG = iB = 0;
  467. }
  468. else
  469. {
  470. // full opacity.
  471. if(iA == 255)
  472. {
  473. // Simply scale the color channels to 0-1023
  474. iR = GpRound(color.r*(1023.0f/255.0f));
  475. iG = GpRound(color.g*(1023.0f/255.0f));
  476. iB = GpRound(color.b*(1023.0f/255.0f));
  477. }
  478. else
  479. {
  480. // Alpha Divide. Note that alpha already has a factor of 255 and
  481. // so do all the color channels. Therefore when we divide the
  482. // color channel by color.a, we implicitly cancel out the 255
  483. // factor and all that's left is to scale up to 10bit --- hence
  484. // the scale factor of 1023/a
  485. REAL scale = 1023.0f/color.a;
  486. iR = GpRound(color.r*scale);
  487. iG = GpRound(color.g*scale);
  488. iB = GpRound(color.b*scale);
  489. }
  490. }
  491. // must be well formed color value otherwise we will AV accessing our
  492. // gamma conversion table.
  493. ASSERT(iB >= 0);
  494. ASSERT(iB <= 1023);
  495. ASSERT(iG >= 0);
  496. ASSERT(iG <= 1023);
  497. ASSERT(iR >= 0);
  498. ASSERT(iR <= 1023);
  499. // Apply Gamma using our 10bit inverse 2.2 power function table.
  500. GpColorConverter colorConv;
  501. colorConv.Channel.b = TenBitInvGamma2_2[iB];
  502. colorConv.Channel.g = TenBitInvGamma2_2[iG];
  503. colorConv.Channel.r = TenBitInvGamma2_2[iR];
  504. colorConv.Channel.a = static_cast<BYTE>(iA); // alpha is already linear.
  505. // Premultiply.
  506. return GpColor::ConvertToPremultiplied(colorConv.argb);
  507. }
  508. VOID
  509. interpolatePresetColors(
  510. GpFColor128 *colorOut,
  511. REAL x,
  512. INT count,
  513. ARGB* presetColors,
  514. REAL* blendPositions,
  515. BOOL gammaCorrect
  516. )
  517. {
  518. REAL value = x;
  519. if(count > 1 && presetColors && blendPositions)
  520. {
  521. if(x >= 0 && x <= 1)
  522. {
  523. INT index = 1;
  524. // Look for the interval.
  525. while(blendPositions[index] < x && index < count)
  526. {
  527. index++;
  528. }
  529. // Interpolate.
  530. if(index < count)
  531. {
  532. GpFColor128 color[2];
  533. GammaLinearizeAndPremultiply(
  534. presetColors[index-1],
  535. gammaCorrect,
  536. &color[0]
  537. );
  538. GammaLinearizeAndPremultiply(
  539. presetColors[index],
  540. gammaCorrect,
  541. &color[1]
  542. );
  543. REAL d = blendPositions[index] - blendPositions[index - 1];
  544. if(d > 0)
  545. {
  546. REAL t = (x - blendPositions[index - 1])/d;
  547. colorOut->a = t*(color[1].a - color[0].a) + color[0].a;
  548. colorOut->r = t*(color[1].r - color[0].r) + color[0].r;
  549. colorOut->g = t*(color[1].g - color[0].g) + color[0].g;
  550. colorOut->b = t*(color[1].b - color[0].b) + color[0].b;
  551. }
  552. else
  553. {
  554. colorOut->a = (color[0].a + color[1].a)/2.0f;
  555. colorOut->r = (color[0].r + color[1].r)/2.0f;
  556. colorOut->g = (color[0].g + color[1].g)/2.0f;
  557. colorOut->b = (color[0].b + color[1].b)/2.0f;
  558. }
  559. }
  560. else // index == count
  561. {
  562. //!!! This case should not be happening if
  563. // the blendPositions array is properly set.
  564. // That means:
  565. // blendPositions array is monotonically
  566. // increasing and
  567. // blendPositions[0] = 0
  568. // blendPositions[count - 1] = 1.
  569. GammaLinearizeAndPremultiply(
  570. presetColors[count-1],
  571. gammaCorrect,
  572. colorOut
  573. );
  574. }
  575. }
  576. else if(x <= 0)
  577. {
  578. GammaLinearizeAndPremultiply(
  579. presetColors[0],
  580. gammaCorrect,
  581. colorOut
  582. );
  583. }
  584. else // x >= 1
  585. {
  586. GammaLinearizeAndPremultiply(
  587. presetColors[count-1],
  588. gammaCorrect,
  589. colorOut
  590. );
  591. }
  592. }
  593. }
  594. DpTriangleData::DpTriangleData(
  595. VOID
  596. )
  597. {
  598. SetValid(FALSE);
  599. IsPolygonMode = FALSE;
  600. GammaCorrect = FALSE;
  601. Index[0] = 0;
  602. Index[1] = 1;
  603. Index[2] = 2;
  604. GpMemset(&X[0], 0, 3*sizeof(REAL));
  605. GpMemset(&Y[0], 0, 3*sizeof(REAL));
  606. GpMemset(Color, 0, 3*sizeof(GpFColor128));
  607. Xmin = Xmax = 0;
  608. GpMemset(&M[0], 0, 3*sizeof(REAL));
  609. GpMemset(&DeltaY[0], 0, 3*sizeof(REAL));
  610. Falloff0 = 1;
  611. Falloff1 = 1;
  612. Falloff2 = 1;
  613. BlendCount0 = 1;
  614. BlendCount1 = 1;
  615. BlendCount2 = 1;
  616. BlendFactors0 = NULL;
  617. BlendFactors1 = NULL;
  618. BlendFactors2 = NULL;
  619. BlendPositions0 = NULL;
  620. BlendPositions1 = NULL;
  621. BlendPositions2 = NULL;
  622. XSpan[0] = 0.0f;
  623. XSpan[1] = 0.0f;
  624. }
  625. VOID
  626. DpTriangleData::SetTriangle(
  627. GpPointF& pt0,
  628. GpPointF& pt1,
  629. GpPointF& pt2,
  630. GpColor& color0,
  631. GpColor& color1,
  632. GpColor& color2,
  633. BOOL isPolygonMode,
  634. BOOL gammaCorrect
  635. )
  636. {
  637. IsPolygonMode = isPolygonMode;
  638. GammaCorrect = gammaCorrect;
  639. // !!! [asecchia] Windows db #203480
  640. // We're filtering the input points here because the rest of the
  641. // gradient code is sloppy about handling the comparison between
  642. // floating point coordinates. Basically no attempt is made to
  643. // handle rounding error and therefore we can get random off-by-one
  644. // scanline rendering errors based on coordinate differences
  645. // on the order of FLT_EPSILON in size.
  646. // Effectively we're applying a noise filter here by rounding to
  647. // 4 bits of fractional precision. This was chosen to match our
  648. // rasterizer rounding precision because we're in device space
  649. // already.
  650. X[0] = TOREAL(GpRealToFix4(pt0.X)) / 16.0f;
  651. Y[0] = TOREAL(GpRealToFix4(pt0.Y)) / 16.0f;
  652. X[1] = TOREAL(GpRealToFix4(pt1.X)) / 16.0f;
  653. Y[1] = TOREAL(GpRealToFix4(pt1.Y)) / 16.0f;
  654. X[2] = TOREAL(GpRealToFix4(pt2.X)) / 16.0f;
  655. Y[2] = TOREAL(GpRealToFix4(pt2.Y)) / 16.0f;
  656. GammaLinearizeAndPremultiply(
  657. color0.GetValue(),
  658. GammaCorrect,
  659. &Color[0]
  660. );
  661. GammaLinearizeAndPremultiply(
  662. color1.GetValue(),
  663. GammaCorrect,
  664. &Color[1]
  665. );
  666. GammaLinearizeAndPremultiply(
  667. color2.GetValue(),
  668. GammaCorrect,
  669. &Color[2]
  670. );
  671. Xmin = Xmax = X[0];
  672. Xmin = min(Xmin, X[1]);
  673. Xmax = max(Xmax, X[1]);
  674. Xmin = min(Xmin, X[2]);
  675. Xmax = max(Xmax, X[2]);
  676. INT i, j;
  677. // Sort the points according to the ascending y order.
  678. for(i = 0; i < 2; i++)
  679. {
  680. for(j = i; j < 3; j++)
  681. {
  682. if((Y[j] < Y[i]) ||
  683. ( (Y[j] == Y[i]) && (X[j] < X[i]) ))
  684. {
  685. REAL temp;
  686. INT tempColor;
  687. INT tempIndex;
  688. tempIndex = Index[i];
  689. Index[i] = Index[j];
  690. Index[j] = tempIndex;
  691. temp = X[i];
  692. X[i] = X[j];
  693. X[j] = temp;
  694. temp = Y[i];
  695. Y[i] = Y[j];
  696. Y[j] = temp;
  697. }
  698. }
  699. }
  700. // Calculate the gradients if possible.
  701. if(Y[0] != Y[1])
  702. {
  703. // P0->P2
  704. DeltaY[0] = TOREAL(1.0)/(Y[1] - Y[0]);
  705. M[0] = (X[1] - X[0])*DeltaY[0];
  706. }
  707. if(Y[1] != Y[2])
  708. {
  709. // P2->P1
  710. DeltaY[1] = TOREAL(1.0)/(Y[1] - Y[2]);
  711. M[1] = (X[1] - X[2])*DeltaY[1];
  712. }
  713. if(Y[2] != Y[0])
  714. {
  715. // P0->P2
  716. DeltaY[2] = TOREAL(1.0)/(Y[2] - Y[0]);
  717. M[2] = (X[2] - X[0])*DeltaY[2];
  718. }
  719. SetValid(TRUE);
  720. }
  721. /**************************************************************************\
  722. *
  723. * Function Description:
  724. *
  725. * Get the x span and st array values for this triangle for the scanline
  726. * specified by y.
  727. * NOTE: This must be called after SetXSpan for a particular value of y.
  728. *
  729. * Return Value:
  730. *
  731. * TRUE if retrieved successfully
  732. *
  733. * Created: peterost
  734. *
  735. \**************************************************************************/
  736. BOOL
  737. DpTriangleData::GetXSpan(REAL y, REAL xmin, REAL xmax, REAL* x, GpPointF* s)
  738. {
  739. // If SetXSpan did it's job correctly, we shouldn't need to do all this
  740. // stuff. In fact we shouldn't even need to pass all these parameters.
  741. // We simply retrieve the values for the span.
  742. if(!IsValid() || y < Y[0] || y >= Y[2] || xmin > Xmax ||
  743. xmax < Xmin || XSpan[0] == XSpan[1])
  744. {
  745. return FALSE;
  746. }
  747. // Retrieve the span coordinates.
  748. x[0] = XSpan[0];
  749. x[1] = XSpan[1];
  750. s[0].X = STGradient[0].X;
  751. s[0].Y = STGradient[0].Y;
  752. s[1].X = STGradient[1].X;
  753. s[1].Y = STGradient[1].Y;
  754. return TRUE;
  755. }
  756. /**************************************************************************\
  757. *
  758. * Function Description:
  759. *
  760. * Set the x span and st array values for this triangle for the scanline
  761. * specified by y.
  762. * NOTE: This must be called before GetXSpan for a particular value of y.
  763. *
  764. * Return Value:
  765. *
  766. * TRUE if set successfully
  767. *
  768. * Created: peterost (factored out of GetXSpan created by ikkof)
  769. *
  770. \**************************************************************************/
  771. BOOL
  772. DpTriangleData::SetXSpan(REAL y, REAL xmin, REAL xmax, REAL* x)
  773. {
  774. if(!IsValid() || y < Y[0] || y >= Y[2] || xmin > Xmax || xmax < Xmin)
  775. return FALSE;
  776. REAL xSpan[2], dy;
  777. REAL s1[2], t1[2];
  778. if(y < Y[1]) // Y[0] <= y < Y[1]
  779. {
  780. dy = y - Y[0];
  781. // P0->P1
  782. xSpan[0] = X[0] + M[0]*dy;
  783. s1[0] = DeltaY[0]*dy;
  784. t1[0] = 0;
  785. // P0->P2
  786. xSpan[1] = X[0] + M[2]*dy;
  787. s1[1] = 0;
  788. t1[1] = DeltaY[2]*dy;
  789. }
  790. else // Y[1] <= y < Y[2]
  791. {
  792. // P2->P1
  793. dy = y - Y[2];
  794. xSpan[0] = X[2] + M[1]*dy;
  795. s1[0] = DeltaY[1]*dy;
  796. t1[0] = 1 - s1[0];
  797. // P0->P2
  798. dy = y - Y[0];
  799. xSpan[1] = X[0] + M[2]*dy;
  800. s1[1] = 0;
  801. t1[1] = DeltaY[2]*dy;;
  802. }
  803. if(xSpan[0] == xSpan[1])
  804. {
  805. XSpan[0] = xSpan[0];
  806. XSpan[1] = xSpan[1];
  807. return FALSE;
  808. }
  809. // We must convert to the st values of the original
  810. // triangle.
  811. INT sIndex = 1, tIndex = 2;
  812. for(INT i = 0; i < 3; i++)
  813. {
  814. if(Index[i] == 1)
  815. sIndex = i;
  816. if(Index[i] == 2)
  817. tIndex = i;
  818. }
  819. REAL s[2], t[2];
  820. switch(sIndex)
  821. {
  822. case 0:
  823. s[0] = 1 - s1[0] - t1[0];
  824. s[1] = 1 - s1[1] - t1[1];
  825. break;
  826. case 1:
  827. s[0] = s1[0];
  828. s[1] = s1[1];
  829. break;
  830. case 2:
  831. s[0] = t1[0];
  832. s[1] = t1[1];
  833. break;
  834. }
  835. switch(tIndex)
  836. {
  837. case 0:
  838. t[0] = 1 - s1[0] - t1[0];
  839. t[1] = 1 - s1[1] - t1[1];
  840. break;
  841. case 1:
  842. t[0] = s1[0];
  843. t[1] = s1[1];
  844. break;
  845. case 2:
  846. t[0] = t1[0];
  847. t[1] = t1[1];
  848. break;
  849. }
  850. INT k0, k1;
  851. if(xSpan[0] < xSpan[1])
  852. {
  853. k0 = 0;
  854. k1 = 1;
  855. }
  856. else
  857. {
  858. k0 = 1;
  859. k1 = 0;
  860. }
  861. XSpan[k0] = xSpan[0];
  862. XSpan[k1] = xSpan[1];
  863. STGradient[k0].X = s[0];
  864. STGradient[k1].X = s[1];
  865. STGradient[k0].Y = t[0];
  866. STGradient[k1].Y = t[1];
  867. x[0] = XSpan[0];
  868. x[1] = XSpan[1];
  869. return TRUE;
  870. }
  871. GpStatus
  872. DpTriangleData::OutputSpan(
  873. ARGB* buffer,
  874. INT compositingMode,
  875. INT y,
  876. INT &xMin,
  877. INT &xMax // xMax is exclusive
  878. )
  879. {
  880. PointF st[2];
  881. REAL xSpan[2];
  882. // First grab the span for this y coordinate.
  883. // Note that GetXSpan returns the xSpan coordinates and the (s, t) texture
  884. // coordinates and that both are unclipped. We have to infer the clipping
  885. // based on the difference between the xSpan coordinates and the
  886. // input xMin and xMax coordinates and explicitly apply clipping to the
  887. // texture space coordinates (s, t).
  888. //
  889. // ( Texture mapping and gradient filling are mathematically similar
  890. // problems so we use 'texture space' and 'texture coordinates'
  891. // to refer to the gradient interpolation. In this way, gradient fills
  892. // can be thought of as procedurally-defined textures. )
  893. if(!GetXSpan((REAL) y, (REAL) xMin, (REAL) xMax, xSpan, st))
  894. {
  895. return Ok;
  896. }
  897. // SetXSpan ensures a correct ordering of the xSpan coordinates.
  898. // We rely on this, so we must ASSERT it.
  899. ASSERT(xSpan[0] <= xSpan[1]);
  900. // Round using our rasterizer rounding rules.
  901. // This is not strictly true, though, our rasterizer uses GpFix4Ceiling
  902. // See RasterizerCeiling
  903. INT xLeft = GpFix4Round(GpRealToFix4(xSpan[0]));
  904. INT xRight = GpFix4Round(GpRealToFix4(xSpan[1]));
  905. // Clip the x values.
  906. xLeft = max(xLeft, xMin);
  907. xRight = min(xRight, xMax); // remember, xMax is exclusive.
  908. // We're done. No pixels to emit.
  909. if(xLeft >= xRight)
  910. {
  911. return Ok;
  912. }
  913. // Now compute the per pixel interpolation increments for the
  914. // texture (s, t) coordinates.
  915. // Here are our actual interpolation coordinates.
  916. // Start them off at the left-hand edge of the span.
  917. REAL s = st[0].X;
  918. REAL t = st[0].Y;
  919. // Left clipping.
  920. // This is the amount to clip off the left edge of the span to reach
  921. // the left-most pixel.
  922. REAL clipLength = (REAL)xLeft - xSpan[0];
  923. if(REALABS(clipLength) > REAL_EPSILON)
  924. {
  925. ASSERT((xSpan[1]-xSpan[0]) != 0.0f);
  926. // Compute the proportion of the span that we're clipping off.
  927. // This is in the range [0,1]
  928. REAL u = clipLength/(xSpan[1]-xSpan[0]);
  929. // Apply the proportion to texture space and then add to the left
  930. // texture coordinate.
  931. s += u*(st[1].X-st[0].X);
  932. t += u*(st[1].Y-st[0].Y);
  933. }
  934. // Temporaries to store the right-hand texture endpoint for the span.
  935. REAL s_right = st[1].X;
  936. REAL t_right = st[1].Y;
  937. // Right clipping.
  938. // This is the amount to clip off the right edge of the span to reach
  939. // the right-most pixel.
  940. clipLength = xSpan[1] - xRight;
  941. if(REALABS(clipLength) > REAL_EPSILON)
  942. {
  943. ASSERT((xSpan[1]-xSpan[0]) != 0.0f);
  944. // Compute the proportion of the span that we're clipping off.
  945. // This is in the range [0,1]
  946. REAL u = clipLength/(xSpan[1]-xSpan[0]);
  947. // Apply the proportion to texture space and then subtract from the
  948. // right texture coordinate.
  949. s_right -= u*(st[1].X-st[0].X);
  950. t_right -= u*(st[1].Y-st[0].Y);
  951. }
  952. // Divide each texture coordinate interval by the number of pixels we're
  953. // emitting. Note that xRight != xLeft. Also note that SetXSpan ensures a
  954. // correct ordering of the xSpan coordinates. This gives us a set of
  955. // per pixel delta values for the (s, t) coordinates.
  956. // The next pixels texture coordinate is computed according
  957. // to the following formula:
  958. // (s', t') <-- (s, t) + (ds, dt)
  959. ASSERT(xRight > xLeft);
  960. REAL ds = (s_right - s)/(xRight - xLeft);
  961. REAL dt = (t_right - t)/(xRight - xLeft);
  962. GpFColor128 colorOut;
  963. buffer += (xLeft - xMin);
  964. for(INT x = xLeft; x < xRight; x++, buffer++)
  965. {
  966. if(!(UsesPresetColors && BlendPositions0 && BlendCount0 > 1))
  967. {
  968. if(BlendCount0 == 1 && Falloff0 == 1
  969. && BlendCount1 == 1 && Falloff1 == 1
  970. && BlendCount2 == 1 && Falloff2 == 1)
  971. {
  972. colorOut.a = Color[0].a + s*(Color[1].a - Color[0].a) + t*(Color[2].a - Color[0].a);
  973. colorOut.r = Color[0].r + s*(Color[1].r - Color[0].r) + t*(Color[2].r - Color[0].r);
  974. colorOut.g = Color[0].g + s*(Color[1].g - Color[0].g) + t*(Color[2].g - Color[0].g);
  975. colorOut.b = Color[0].b + s*(Color[1].b - Color[0].b) + t*(Color[2].b - Color[0].b);
  976. }
  977. else
  978. {
  979. REAL u1, s1, t1;
  980. u1 = ::adjustValue(1 - s - t, BlendCount0, Falloff0,
  981. BlendFactors0, BlendPositions0);
  982. s1 = ::adjustValue(s, BlendCount1, Falloff1,
  983. BlendFactors1, BlendPositions1);
  984. t1 = ::adjustValue(t, BlendCount2, Falloff2,
  985. BlendFactors2, BlendPositions2);
  986. REAL sum;
  987. if(!IsPolygonMode)
  988. {
  989. sum = u1 + s1 + t1;
  990. u1 = u1/sum;
  991. s1 = s1/sum;
  992. t1 = t1/sum;
  993. }
  994. else
  995. {
  996. // If it is the polygon gradient, treat u1 differently.
  997. // This gives the similar behavior as RadialGradient.
  998. sum = s1 + t1;
  999. if(sum != 0)
  1000. {
  1001. sum = (1 - u1)/sum;
  1002. s1 *= sum;
  1003. t1 *= sum;
  1004. }
  1005. }
  1006. colorOut.a = Color[0].a + s1*(Color[1].a - Color[0].a) + t1*(Color[2].a - Color[0].a);
  1007. colorOut.r = Color[0].r + s1*(Color[1].r - Color[0].r) + t1*(Color[2].r - Color[0].r);
  1008. colorOut.g = Color[0].g + s1*(Color[1].g - Color[0].g) + t1*(Color[2].g - Color[0].g);
  1009. colorOut.b = Color[0].b + s1*(Color[1].b - Color[0].b) + t1*(Color[2].b - Color[0].b);
  1010. }
  1011. }
  1012. else
  1013. {
  1014. interpolatePresetColors(
  1015. &colorOut,
  1016. 1 - s - t,
  1017. BlendCount0,
  1018. PresetColors,
  1019. BlendPositions0,
  1020. GammaCorrect
  1021. );
  1022. }
  1023. s += ds;
  1024. t += dt;
  1025. if((REALABS(colorOut.a) >= REAL_EPSILON) ||
  1026. compositingMode == CompositingModeSourceCopy)
  1027. {
  1028. GpColorConverter colorConv;
  1029. // Make sure the colorOut is properly premultiplied.
  1030. CLAMP_COLOR_CHANNEL(colorOut.a, 255.0f)
  1031. CLAMP_COLOR_CHANNEL(colorOut.r, colorOut.a);
  1032. CLAMP_COLOR_CHANNEL(colorOut.g, colorOut.a);
  1033. CLAMP_COLOR_CHANNEL(colorOut.b, colorOut.a);
  1034. if(GammaCorrect)
  1035. {
  1036. colorConv.argb = GammaUnlinearizePremultiplied128(colorOut);
  1037. }
  1038. else
  1039. {
  1040. colorConv.Channel.a = static_cast<BYTE>(GpRound(colorOut.a));
  1041. colorConv.Channel.r = static_cast<BYTE>(GpRound(colorOut.r));
  1042. colorConv.Channel.g = static_cast<BYTE>(GpRound(colorOut.g));
  1043. colorConv.Channel.b = static_cast<BYTE>(GpRound(colorOut.b));
  1044. }
  1045. // Clamp to the alpha channel for the premultiplied alpha blender.
  1046. *buffer = colorConv.argb;
  1047. }
  1048. else
  1049. {
  1050. *buffer = 0; // case of CompositingModeSourceOver && alpha = 0
  1051. }
  1052. }
  1053. return Ok;
  1054. }
  1055. /**************************************************************************\
  1056. *
  1057. * Function Description:
  1058. *
  1059. * Outputs a single span within a raster with a gradient brush.
  1060. * Is called by the rasterizer.
  1061. *
  1062. * Arguments:
  1063. *
  1064. * [IN] y - the Y value of the raster being output
  1065. * [IN] leftEdge - the DDA class of the left edge
  1066. * [IN] rightEdge - the DDA class of the right edge
  1067. *
  1068. * Return Value:
  1069. *
  1070. * GpStatus - Ok
  1071. *
  1072. * Created:
  1073. *
  1074. * 01/21/1999 ikkof
  1075. *
  1076. \**************************************************************************/
  1077. GpStatus
  1078. DpOutputGradientSpan::OutputSpan(
  1079. INT y,
  1080. INT xMin,
  1081. INT xMax // xMax is exclusive
  1082. )
  1083. {
  1084. ARGB argb;
  1085. INT width = xMax - xMin;
  1086. if(width <= 0)
  1087. return Ok;
  1088. ARGB * buffer = Scan->NextBuffer(xMin, y, width);
  1089. GpPointF pt1, pt2;
  1090. pt1.X = (REAL) xMin;
  1091. pt1.Y = pt2.Y = (REAL) y;
  1092. pt2.X = (REAL)xMax;
  1093. DeviceToWorld.Transform(&pt1);
  1094. DeviceToWorld.Transform(&pt2);
  1095. REAL u1, v1, u2, v2, du, dv;
  1096. u1 = (pt1.X - BrushRect.X)/BrushRect.Width;
  1097. v1 = (pt1.Y - BrushRect.Y)/BrushRect.Height;
  1098. u2 = (pt2.X - BrushRect.X)/BrushRect.Width;
  1099. v2 = (pt2.Y - BrushRect.Y)/BrushRect.Height;
  1100. du = (u2 - u1)/width;
  1101. dv = (v2 - v1)/width;
  1102. INT i;
  1103. REAL u0 = u1, v0 = v1;
  1104. REAL u, v;
  1105. REAL delta = min(BrushRect.Width, BrushRect.Height)/2;
  1106. if(REALABS(delta) < REAL_EPSILON)
  1107. {
  1108. delta = 1.0f;
  1109. }
  1110. REAL deltaInv = 1.0f/delta;
  1111. for(i = 0; i < width; i++, buffer++)
  1112. {
  1113. u = u0;
  1114. v = v0;
  1115. REAL alpha = 0, red = 0, green = 0, blue = 0;
  1116. // If this is the outside of the rectangle in Clamp mode,
  1117. // don't draw anything.
  1118. if(WrapMode == WrapModeClamp)
  1119. {
  1120. if(u < 0 || u > 1 || v < 0 || v > 1)
  1121. {
  1122. *buffer = 0;
  1123. goto NextUV;
  1124. }
  1125. }
  1126. // Remap the v-coordinate in Tile mode.
  1127. if(WrapMode == WrapModeTile || WrapMode == WrapModeTileFlipX)
  1128. {
  1129. // Get the fractional part of v.
  1130. v = GpModF(v, 1);
  1131. }
  1132. else if(WrapMode == WrapModeTileFlipY || WrapMode == WrapModeTileFlipXY)
  1133. {
  1134. INT nV;
  1135. nV = GpFloor(v);
  1136. v = GpModF(v, 1);
  1137. if(nV & 1)
  1138. v = 1 - v; // flip.
  1139. }
  1140. // Remap the u-coordinate in Tile mode.
  1141. if(WrapMode == WrapModeTile || WrapMode == WrapModeTileFlipY)
  1142. {
  1143. // Get the fractional part of u.
  1144. u = GpModF(u, 1);
  1145. }
  1146. else if(WrapMode == WrapModeTileFlipX || WrapMode == WrapModeTileFlipXY)
  1147. {
  1148. INT nU;
  1149. nU = GpFloor(u);
  1150. u = GpModF(u, 1);
  1151. if(nU & 1)
  1152. u = 1 - u; // flip.
  1153. }
  1154. if(/*BrushType == BrushRectGrad ||*/ BrushType == BrushTypeLinearGradient)
  1155. {
  1156. const GpRectGradient* rectGrad = static_cast<const GpRectGradient*> (Brush);
  1157. if(!(rectGrad->HasPresetColors() &&
  1158. rectGrad->DeviceBrush.PresetColors &&
  1159. rectGrad->DeviceBrush.BlendPositions[0] &&
  1160. rectGrad->DeviceBrush.BlendCounts[0] > 1))
  1161. {
  1162. u = ::adjustValue(
  1163. u,
  1164. rectGrad->DeviceBrush.BlendCounts[0],
  1165. rectGrad->DeviceBrush.Falloffs[0],
  1166. rectGrad->DeviceBrush.BlendFactors[0],
  1167. rectGrad->DeviceBrush.BlendPositions[0]
  1168. );
  1169. v = ::adjustValue(
  1170. v,
  1171. rectGrad->DeviceBrush.BlendCounts[1],
  1172. rectGrad->DeviceBrush.Falloffs[1],
  1173. rectGrad->DeviceBrush.BlendFactors[1],
  1174. rectGrad->DeviceBrush.BlendPositions[1]
  1175. );
  1176. REAL c[4];
  1177. c[0] = (1 - u)*(1 - v);
  1178. c[1] = u*(1 - v);
  1179. c[2] = (1 - u)*v;
  1180. c[3] = u*v;
  1181. // We must interpolate alpha.
  1182. alpha = c[0]*A[0] + c[1]*A[1]
  1183. + c[2]*A[2] + c[3]*A[3];
  1184. red = c[0]*R[0] + c[1]*R[1]
  1185. + c[2]*R[2] + c[3]*R[3];
  1186. green = c[0]*G[0] + c[1]*G[1]
  1187. + c[2]*G[2] + c[3]*G[3];
  1188. blue = c[0]*B[0] + c[1]*B[1]
  1189. + c[2]*B[2] + c[3]*B[3];
  1190. }
  1191. else
  1192. {
  1193. GpFColor128 color;
  1194. interpolatePresetColors(
  1195. &color,
  1196. u,
  1197. rectGrad->DeviceBrush.BlendCounts[0],
  1198. rectGrad->DeviceBrush.PresetColors,
  1199. rectGrad->DeviceBrush.BlendPositions[0],
  1200. FALSE
  1201. );
  1202. alpha = color.a;
  1203. red = color.r;
  1204. green = color.g;
  1205. blue = color.b;
  1206. }
  1207. }
  1208. if(alpha != 0 || CompositingMode == CompositingModeSourceCopy)
  1209. {
  1210. CLAMP_COLOR_CHANNEL(alpha, 255.0f);
  1211. CLAMP_COLOR_CHANNEL(red, alpha);
  1212. CLAMP_COLOR_CHANNEL(green, alpha);
  1213. CLAMP_COLOR_CHANNEL(blue, alpha);
  1214. *buffer = GpColor::MakeARGB(
  1215. static_cast<BYTE>(GpRound(alpha)),
  1216. static_cast<BYTE>(GpRound(red)),
  1217. static_cast<BYTE>(GpRound(green)),
  1218. static_cast<BYTE>(GpRound(blue)));
  1219. }
  1220. else
  1221. {
  1222. *buffer = 0; // case of CompositingModeSourceOver && alpha = 0
  1223. }
  1224. NextUV:
  1225. u0 += du;
  1226. v0 += dv;
  1227. }
  1228. return Ok;
  1229. }
  1230. /**************************************************************************\
  1231. *
  1232. * Function Description:
  1233. *
  1234. * Constructor for One Dimentional Gradient.
  1235. *
  1236. * Arguments:
  1237. *
  1238. * [IN] brush - brush
  1239. * [IN] scan - the scan buffer
  1240. * [IN] context - the context
  1241. * [IN] isHorizontal - TRUE if this is the horizontal gradient.
  1242. * Also TRUE for more complicated one-D gradient like
  1243. * Radial Gradient.
  1244. * [IN] isVertical - TRUE if this is the vertical gradient.
  1245. *
  1246. * Return Value:
  1247. *
  1248. * NONE
  1249. *
  1250. * Created:
  1251. *
  1252. * 12/21/1999 ikkof
  1253. *
  1254. \**************************************************************************/
  1255. DpOutputOneDGradientSpan::DpOutputOneDGradientSpan(
  1256. const GpElementaryBrush *brush,
  1257. DpScanBuffer * scan,
  1258. DpContext* context,
  1259. BOOL isHorizontal,
  1260. BOOL isVertical
  1261. ) : DpOutputGradientSpan(brush, scan, context)
  1262. {
  1263. FPUStateSaver::AssertMode();
  1264. Initialize();
  1265. GpStatus status = AllocateOneDData(isHorizontal, isVertical);
  1266. if(status == Ok)
  1267. {
  1268. if(BrushType == BrushTypeLinearGradient)
  1269. {
  1270. SetupRectGradientOneDData();
  1271. }
  1272. }
  1273. if(status == Ok)
  1274. SetValid(TRUE);
  1275. }
  1276. GpStatus
  1277. DpOutputOneDGradientSpan::AllocateOneDData(
  1278. BOOL isHorizontal,
  1279. BOOL isVertical
  1280. )
  1281. {
  1282. if(!isHorizontal && !isVertical)
  1283. return InvalidParameter;
  1284. IsHorizontal = isHorizontal;
  1285. IsVertical = isVertical;
  1286. GpPointF axis[4];
  1287. axis[0].X = 0;
  1288. axis[0].Y = 0;
  1289. axis[1].X = BrushRect.Width;
  1290. axis[1].Y = 0;
  1291. axis[2].X = BrushRect.Width;
  1292. axis[2].Y = BrushRect.Height;
  1293. axis[3].X = 0;
  1294. axis[3].Y = BrushRect.Height;
  1295. WorldToDevice.VectorTransform(&axis[0], 4);
  1296. // Calculate the sum of the diagonals as the largest possible distance
  1297. // of interest and use this to size the OneD array of colors. This gets us
  1298. // to within 1 bit of the "true" gradient values for each A,R,G,B channel.
  1299. REAL d1 = REALSQRT(distance_squared(axis[0], axis[2]));
  1300. REAL d2 = REALSQRT(distance_squared(axis[1], axis[3]));
  1301. OneDDataMultiplier = max(1, GpCeiling(d1+d2));
  1302. OneDDataCount = OneDDataMultiplier + 2;
  1303. GpStatus status = Ok;
  1304. OneDData = (ARGB*) GpMalloc(OneDDataCount*sizeof(ARGB));
  1305. if(!OneDData)
  1306. status = OutOfMemory;
  1307. return status;
  1308. }
  1309. DpOutputOneDGradientSpan::~DpOutputOneDGradientSpan()
  1310. {
  1311. if(OneDData)
  1312. GpFree(OneDData);
  1313. }
  1314. VOID
  1315. DpOutputOneDGradientSpan::SetupRectGradientOneDData(
  1316. )
  1317. {
  1318. REAL u, u0, du;
  1319. u0 = 0;
  1320. du = 1.0f/OneDDataMultiplier;
  1321. ARGB* buffer = OneDData;
  1322. ASSERT(buffer);
  1323. if(!buffer)
  1324. return;
  1325. for(INT i = 0; i < OneDDataCount; i++, buffer++)
  1326. {
  1327. u = u0;
  1328. const GpRectGradient* rectGrad = static_cast<const GpRectGradient*> (Brush);
  1329. REAL alpha = 0, red = 0, green = 0, blue = 0;
  1330. if(!(rectGrad->HasPresetColors() &&
  1331. rectGrad->DeviceBrush.PresetColors &&
  1332. rectGrad->DeviceBrush.BlendPositions[0] &&
  1333. rectGrad->DeviceBrush.BlendCounts[0] > 1))
  1334. {
  1335. INT index, i0, i1;
  1336. REAL a0, r0, g0, b0, a1, r1, g1, b1;
  1337. if(IsHorizontal)
  1338. {
  1339. index = 0;
  1340. i0 = 0;
  1341. i1 = 1;
  1342. }
  1343. else
  1344. {
  1345. index = 1;
  1346. i0 = 0;
  1347. i1 = 2;
  1348. }
  1349. a0 = A[i0];
  1350. r0 = R[i0];
  1351. g0 = G[i0];
  1352. b0 = B[i0];
  1353. a1 = A[i1];
  1354. r1 = R[i1];
  1355. g1 = G[i1];
  1356. b1 = B[i1];
  1357. u = ::adjustValue(
  1358. u0,
  1359. rectGrad->DeviceBrush.BlendCounts[index],
  1360. rectGrad->DeviceBrush.Falloffs[index],
  1361. rectGrad->DeviceBrush.BlendFactors[index],
  1362. rectGrad->DeviceBrush.BlendPositions[index]
  1363. );
  1364. REAL c[2];
  1365. c[0] = (1 - u);
  1366. c[1] = u;
  1367. // We must interpolate alpha.
  1368. alpha = c[0]*a0 + c[1]*a1;
  1369. red = c[0]*r0 + c[1]*r1;
  1370. green = c[0]*g0 + c[1]*g1;
  1371. blue = c[0]*b0 + c[1]*b1;
  1372. }
  1373. else
  1374. {
  1375. GpFColor128 color;
  1376. interpolatePresetColors(
  1377. &color,
  1378. u0,
  1379. rectGrad->DeviceBrush.BlendCounts[0],
  1380. rectGrad->DeviceBrush.PresetColors,
  1381. rectGrad->DeviceBrush.BlendPositions[0],
  1382. FALSE
  1383. );
  1384. alpha = color.a;
  1385. red = color.r;
  1386. green = color.g;
  1387. blue = color.b;
  1388. }
  1389. if(alpha != 0 || CompositingMode == CompositingModeSourceCopy)
  1390. {
  1391. CLAMP_COLOR_CHANNEL(alpha, 255.0f);
  1392. CLAMP_COLOR_CHANNEL(red, alpha);
  1393. CLAMP_COLOR_CHANNEL(green, alpha);
  1394. CLAMP_COLOR_CHANNEL(blue, alpha);
  1395. *buffer = GpColor::MakeARGB(
  1396. static_cast<BYTE>(GpRound(alpha)),
  1397. static_cast<BYTE>(GpRound(red)),
  1398. static_cast<BYTE>(GpRound(green)),
  1399. static_cast<BYTE>(GpRound(blue)));
  1400. }
  1401. else
  1402. {
  1403. *buffer = 0; // case of CompositingModeSourceOver && alpha = 0
  1404. }
  1405. u0 += du;
  1406. }
  1407. }
  1408. VOID
  1409. DpOutputOneDGradientSpan::SetupRadialGradientOneDData()
  1410. {
  1411. ASSERT(FALSE);
  1412. }
  1413. /**************************************************************************\
  1414. *
  1415. * Function Description:
  1416. *
  1417. * Outputs a single span within a raster with a gradient brush.
  1418. * Is called by the rasterizer.
  1419. *
  1420. * Arguments:
  1421. *
  1422. * [IN] y - the Y value of the raster being output
  1423. * [IN] leftEdge - the DDA class of the left edge
  1424. * [IN] rightEdge - the DDA class of the right edge
  1425. *
  1426. * Return Value:
  1427. *
  1428. * GpStatus - Ok
  1429. *
  1430. * Created:
  1431. *
  1432. * 01/21/1999 ikkof
  1433. *
  1434. \**************************************************************************/
  1435. GpStatus
  1436. DpOutputOneDGradientSpan::OutputSpan(
  1437. INT y,
  1438. INT xMin,
  1439. INT xMax // xMax is exclusive
  1440. )
  1441. {
  1442. ARGB argb;
  1443. INT width = xMax - xMin;
  1444. if(width <= 0 || !OneDData)
  1445. return Ok;
  1446. ARGB * buffer = Scan->NextBuffer(xMin, y, width);
  1447. GpPointF pt1, pt2;
  1448. pt1.X = (REAL) xMin;
  1449. pt1.Y = pt2.Y = (REAL) y;
  1450. pt2.X = (REAL)xMax;
  1451. DeviceToWorld.Transform(&pt1);
  1452. DeviceToWorld.Transform(&pt2);
  1453. REAL u1, v1, u2, v2;
  1454. u1 = (pt1.X - BrushRect.X)/BrushRect.Width;
  1455. v1 = (pt1.Y - BrushRect.Y)/BrushRect.Height;
  1456. u2 = (pt2.X - BrushRect.X)/BrushRect.Width;
  1457. v2 = (pt2.Y - BrushRect.Y)/BrushRect.Height;
  1458. INT u1Major, u2Major, v1Major, v2Major;
  1459. INT u1Minor, u2Minor, v1Minor, v2Minor;
  1460. u1Major = GpFloor(u1);
  1461. u2Major = GpFloor(u2);
  1462. u1Minor = GpRound(OneDDataMultiplier*(u1 - u1Major));
  1463. u2Minor = GpRound(OneDDataMultiplier*(u2 - u2Major));
  1464. v1Major = GpFloor(v1);
  1465. v2Major = GpFloor(v2);
  1466. v1Minor = GpRound(OneDDataMultiplier*(v1 - v1Major));
  1467. v2Minor = GpRound(OneDDataMultiplier*(v2 - v2Major));
  1468. INT du, dv;
  1469. du = GpRound((u2 - u1)*OneDDataMultiplier/width);
  1470. dv = GpRound((v2 - v1)*OneDDataMultiplier/width);
  1471. INT i;
  1472. INT uMajor, uMinor, vMajor, vMinor;
  1473. uMajor = u1Major;
  1474. uMinor = u1Minor;
  1475. vMajor = v1Major;
  1476. vMinor = v1Minor;
  1477. if(BrushType == BrushTypeLinearGradient)
  1478. {
  1479. for(i = 0; i < width; i++, buffer++)
  1480. {
  1481. if(IsHorizontal)
  1482. {
  1483. if((WrapMode == WrapModeTileFlipX || WrapMode == WrapModeTileFlipXY)
  1484. && (uMajor & 0x01) != 0)
  1485. *buffer = OneDData[OneDDataMultiplier - uMinor];
  1486. else
  1487. *buffer = OneDData[uMinor];
  1488. }
  1489. else if(IsVertical)
  1490. {
  1491. if((WrapMode == WrapModeTileFlipY || WrapMode == WrapModeTileFlipXY)
  1492. && (vMajor & 0x01) != 0)
  1493. *buffer = OneDData[OneDDataMultiplier - vMinor];
  1494. else
  1495. *buffer = OneDData[vMinor];
  1496. }
  1497. if(WrapMode == WrapModeClamp)
  1498. {
  1499. if(uMajor != 0 || vMajor != 0)
  1500. *buffer = 0;
  1501. }
  1502. uMinor += du;
  1503. while(uMinor >= OneDDataMultiplier)
  1504. {
  1505. uMajor++;
  1506. uMinor -= OneDDataMultiplier;
  1507. }
  1508. while(uMinor < 0)
  1509. {
  1510. uMajor--;
  1511. uMinor += OneDDataMultiplier;
  1512. }
  1513. vMinor += dv;
  1514. while(vMinor >= OneDDataMultiplier)
  1515. {
  1516. vMajor++;
  1517. vMinor -= OneDDataMultiplier;
  1518. }
  1519. while(vMinor < 0)
  1520. {
  1521. vMajor--;
  1522. vMinor += OneDDataMultiplier;
  1523. }
  1524. }
  1525. }
  1526. return Ok;
  1527. }
  1528. /**************************************************************************\
  1529. *
  1530. * Function Description:
  1531. *
  1532. * Constructor for linear gradient.
  1533. *
  1534. * Arguments:
  1535. *
  1536. * [IN] brush - brush
  1537. * [IN] scan - the scan buffer
  1538. * [IN] context - the context
  1539. *
  1540. * Return Value:
  1541. *
  1542. * NONE
  1543. *
  1544. * Created:
  1545. *
  1546. * 1/13/2000 andrewgo
  1547. *
  1548. \**************************************************************************/
  1549. DpOutputLinearGradientSpan::DpOutputLinearGradientSpan(
  1550. const GpElementaryBrush *brush,
  1551. DpScanBuffer * scan,
  1552. DpContext* context
  1553. ) : DpOutputGradientSpan(brush, scan, context)
  1554. {
  1555. SetValid(FALSE);
  1556. const GpRectGradient* gradient = static_cast<const GpRectGradient*>(brush);
  1557. // Copy some brush attributes to locals for speed:
  1558. GpRectF brushRect;
  1559. gradient->GetRect(brushRect);
  1560. BOOL doPresetColor = (gradient->HasPresetColors());
  1561. BOOL doAdjustValue = (gradient->DeviceBrush.BlendCounts[0] != 1) ||
  1562. (gradient->DeviceBrush.Falloffs[0] != 1);
  1563. // For now we just assume 32 pixels in the texture. In the future,
  1564. // we can change this to be inherited from the API.
  1565. UINT numberOfIntervalBits = 5;
  1566. UINT numberOfTexels = 32;
  1567. // If we're doing a fancy blend with multiple color points.
  1568. if(doPresetColor || doAdjustValue)
  1569. {
  1570. // Office specifies simple blends with 2-3 blend factors. If it's a
  1571. // simple blend, 32 texels is enough, but if it's complicated lets
  1572. // use more texels. Use in the range of the width + height, with a
  1573. // cap of 512. Using too many texels can result in overflow errors
  1574. // when calculating M11, M21 and Dx, and is wasted memory and
  1575. // processing power.
  1576. if(gradient->DeviceBrush.BlendCounts[0] > 3)
  1577. {
  1578. REAL widthHeight = brushRect.Width + brushRect.Height;
  1579. if (widthHeight > 512)
  1580. {
  1581. numberOfTexels = 512;
  1582. numberOfIntervalBits = 9;
  1583. }
  1584. else if (widthHeight > 128)
  1585. {
  1586. numberOfTexels = 128;
  1587. numberOfIntervalBits = 7;
  1588. }
  1589. }
  1590. }
  1591. const UINT halfNumberOfTexels = numberOfTexels / 2;
  1592. // The number of texels has to be a power of two:
  1593. ASSERT((numberOfTexels & (numberOfTexels - 1)) == 0);
  1594. // Remember the size:
  1595. IntervalMask = numberOfTexels - 1;
  1596. NumberOfIntervalBits = numberOfIntervalBits;
  1597. // We want to create a transform that takes us from any point in the
  1598. // device-space brush parallelogram to normalized texture coordinates.
  1599. // We're a bit tricky here and do the divide by 2 to handle TileFlipX:
  1600. REAL normalizedSize = (REAL)(numberOfTexels * (1 << ONEDNUMFRACTIONALBITS));
  1601. GpRectF normalizedRect(
  1602. 0.0f, 0.0f,
  1603. normalizedSize / 2,
  1604. normalizedSize / 2
  1605. );
  1606. GpMatrix normalizeBrushRect;
  1607. if (normalizeBrushRect.InferAffineMatrix(brushRect, normalizedRect) == Ok)
  1608. {
  1609. DeviceToNormalized = WorldToDevice;
  1610. DeviceToNormalized.Prepend(normalizeBrushRect);
  1611. if (DeviceToNormalized.Invert() == Ok)
  1612. {
  1613. // Convert the transform to fixed point units:
  1614. M11 = GpRound(DeviceToNormalized.GetM11());
  1615. M21 = GpRound(DeviceToNormalized.GetM21());
  1616. Dx = GpRoundSat(DeviceToNormalized.GetDx());
  1617. // For every pixel that we step one to the right in device space,
  1618. // we need to know the corresponding x-increment in texture (err,
  1619. // I mean gradient) space. Take a (1, 0) device vector, pop-it
  1620. // through the device-to-normalized transform, and you get this
  1621. // as the xIncrement result:
  1622. XIncrement = M11;
  1623. ULONG i;
  1624. GpFColor128 color;
  1625. REAL w;
  1626. // should we perform gamma correction to gamma 2.2
  1627. BOOL doGammaConversion = brush->GetGammaCorrection();
  1628. // Store our real converted color channels.
  1629. GpFColor128 A, B;
  1630. // Convert the end colors to premultiplied form,
  1631. // Convert the end color components to REALs,
  1632. // ... and pre-gamma convert to 2.2 if necessary.
  1633. GammaLinearizeAndPremultiply(
  1634. gradient->DeviceBrush.Colors[0].GetValue(),
  1635. doGammaConversion,
  1636. &A
  1637. );
  1638. GammaLinearizeAndPremultiply(
  1639. gradient->DeviceBrush.Colors[1].GetValue(),
  1640. doGammaConversion,
  1641. &B
  1642. );
  1643. // Okay, now we simply have to load the texture:
  1644. ULONGLONG *startTexelArgb = &StartTexelArgb[0];
  1645. ULONGLONG *endTexelArgb = &EndTexelArgb[0];
  1646. AGRB64TEXEL *startTexelAgrb = &StartTexelAgrb[0];
  1647. AGRB64TEXEL *endTexelAgrb = &EndTexelAgrb[0];
  1648. REAL wIncrement = 1.0f / halfNumberOfTexels;
  1649. // Note that we're looping through ONEDREALTEXTUREWIDTH + 1
  1650. // elements!
  1651. for (w = 0, i = 0;
  1652. i <= halfNumberOfTexels;
  1653. w += wIncrement, i++)
  1654. {
  1655. // We sample the specified interpolators at our fixed
  1656. // frequency:
  1657. if (doPresetColor)
  1658. {
  1659. interpolatePresetColors(
  1660. &color, w,
  1661. gradient->DeviceBrush.BlendCounts[0],
  1662. gradient->DeviceBrush.PresetColors,
  1663. gradient->DeviceBrush.BlendPositions[0],
  1664. doGammaConversion
  1665. );
  1666. }
  1667. else
  1668. {
  1669. REAL multB = w;
  1670. if (doAdjustValue)
  1671. {
  1672. multB = slowAdjustValue(w,
  1673. gradient->DeviceBrush.BlendCounts[0],
  1674. gradient->DeviceBrush.Falloffs[0],
  1675. gradient->DeviceBrush.BlendFactors[0],
  1676. gradient->DeviceBrush.BlendPositions[0]);
  1677. // !!![andrewgo] This can produce out-of-range numbers
  1678. }
  1679. REAL multA = 1.0f - multB;
  1680. color.a = (A.a * multA) + (B.a * multB);
  1681. color.r = (A.r * multA) + (B.r * multB);
  1682. color.g = (A.g * multA) + (B.g * multB);
  1683. color.b = (A.b * multA) + (B.b * multB);
  1684. }
  1685. // Note that we're actually touching ONEDREALTEXTUREWIDTH + 1
  1686. // elements in the array here!
  1687. if(doGammaConversion)
  1688. {
  1689. GpColorConverter colorConv;
  1690. colorConv.argb = GammaUnlinearizePremultiplied128(color);
  1691. startTexelAgrb[i].A00aa00gg =
  1692. (colorConv.Channel.a << 16) | colorConv.Channel.g;
  1693. startTexelAgrb[i].A00rr00bb =
  1694. (colorConv.Channel.r << 16) | colorConv.Channel.b;
  1695. }
  1696. else
  1697. {
  1698. startTexelAgrb[i].A00aa00gg =
  1699. (GpRound(color.a) << 16) | GpRound(color.g);
  1700. startTexelAgrb[i].A00rr00bb =
  1701. (GpRound(color.r) << 16) | GpRound(color.b);
  1702. }
  1703. ASSERT((startTexelAgrb[i].A00aa00gg & 0xff00ff00) == 0);
  1704. ASSERT((startTexelAgrb[i].A00rr00bb & 0xff00ff00) == 0);
  1705. }
  1706. // Replicate the interval start colors to the end colors (note
  1707. // again that we actually reference ONEDREALTEXTUREWIDTH + 1
  1708. // elements):
  1709. for (i = 0; i < halfNumberOfTexels; i++)
  1710. {
  1711. endTexelArgb[i] = startTexelArgb[i + 1];
  1712. }
  1713. // Here's why we've only filled up half the texture so far.
  1714. // If FlipX is set, we make the second half an inverted
  1715. // copy of the first; if not, we make it a straight copy:
  1716. if ((gradient->GetWrapMode() != WrapModeTileFlipX) &&
  1717. (gradient->GetWrapMode() != WrapModeTileFlipXY))
  1718. {
  1719. memcpy(&startTexelArgb[halfNumberOfTexels],
  1720. &startTexelArgb[0],
  1721. halfNumberOfTexels * sizeof(startTexelArgb[0]));
  1722. memcpy(&endTexelArgb[halfNumberOfTexels],
  1723. &endTexelArgb[0],
  1724. halfNumberOfTexels * sizeof(endTexelArgb[0]));
  1725. }
  1726. else
  1727. {
  1728. for (i = 0; i < halfNumberOfTexels; i++)
  1729. {
  1730. startTexelArgb[halfNumberOfTexels + i]
  1731. = endTexelArgb[halfNumberOfTexels - i - 1];
  1732. endTexelArgb[halfNumberOfTexels + i]
  1733. = startTexelArgb[halfNumberOfTexels - i - 1];
  1734. }
  1735. }
  1736. // We're done! We're set!
  1737. SetValid(TRUE);
  1738. }
  1739. }
  1740. }
  1741. /**************************************************************************\
  1742. *
  1743. * Function Description:
  1744. *
  1745. * Constructor for MMX linear gradient.
  1746. *
  1747. * Arguments:
  1748. *
  1749. * [IN] brush - brush
  1750. * [IN] scan - the scan buffer
  1751. * [IN] context - the context
  1752. *
  1753. * Return Value:
  1754. *
  1755. * NONE
  1756. *
  1757. * Created:
  1758. *
  1759. * 1/13/2000 andrewgo
  1760. *
  1761. \**************************************************************************/
  1762. DpOutputLinearGradientSpan_MMX::DpOutputLinearGradientSpan_MMX(
  1763. const GpElementaryBrush *brush,
  1764. DpScanBuffer * scan,
  1765. DpContext* context
  1766. ) : DpOutputLinearGradientSpan(brush, scan, context)
  1767. {
  1768. ASSERT(OSInfo::HasMMX);
  1769. // Here we do some additional stuff for our MMX routine, beyond
  1770. // what the base constructor did.
  1771. #if defined(_X86_)
  1772. UINT32 numberOfTexels = IntervalMask + 1;
  1773. ULONGLONG *startTexelArgb = &StartTexelArgb[0];
  1774. ULONGLONG *endTexelArgb = &EndTexelArgb[0];
  1775. static ULONGLONG OneHalf8dot8 = 0x0080008000800080;
  1776. // The C constructor creates the colors in AGRB order, but we
  1777. // want them in ARGB order, so swap R and G for every pixel:
  1778. USHORT *p = reinterpret_cast<USHORT*>(startTexelArgb);
  1779. for (UINT i = 0; i < numberOfTexels; i++, p += 4)
  1780. {
  1781. USHORT tmp = *(p + 1);
  1782. *(p + 1) = *(p + 2);
  1783. *(p + 2) = tmp;
  1784. }
  1785. p = reinterpret_cast<USHORT*>(endTexelArgb);
  1786. for (UINT i = 0; i < numberOfTexels; i++, p += 4)
  1787. {
  1788. USHORT tmp = *(p + 1);
  1789. *(p + 1) = *(p + 2);
  1790. *(p + 2) = tmp;
  1791. }
  1792. // Make some more adjustments for our MMX routine:
  1793. //
  1794. // EndTexelArgb[i] -= StartTexelArgb[i]
  1795. // StartTexelArgb[i] = 256 * StartTexelArgb[i] + OneHalf
  1796. _asm
  1797. {
  1798. mov ecx, numberOfTexels
  1799. mov esi, startTexelArgb
  1800. mov edi, endTexelArgb
  1801. MoreTexels:
  1802. movq mm0, [esi]
  1803. movq mm1, [edi]
  1804. psubw mm1, mm0
  1805. psllw mm0, 8
  1806. paddw mm0, OneHalf8dot8
  1807. movq [esi], mm0
  1808. movq [edi], mm1
  1809. add esi, 8
  1810. add edi, 8
  1811. dec ecx
  1812. jnz MoreTexels
  1813. emms
  1814. }
  1815. #endif
  1816. }
  1817. /**************************************************************************\
  1818. *
  1819. * Function Description:
  1820. *
  1821. * Outputs a single span within a raster with a gradient brush.
  1822. * Uses linear interpolation from a small one dimensional texture
  1823. * that effectively creates a piecewise-linear approximation to
  1824. * the blend curve.
  1825. *
  1826. * Arguments:
  1827. *
  1828. * [IN] y - the Y value of the raster being output
  1829. * [IN] leftEdge - the DDA class of the left edge
  1830. * [IN] rightEdge - the DDA class of the right edge
  1831. *
  1832. * Return Value:
  1833. *
  1834. * GpStatus - Ok
  1835. *
  1836. * Created:
  1837. *
  1838. * 1/13/2000 andrewgo
  1839. *
  1840. \**************************************************************************/
  1841. GpStatus
  1842. DpOutputLinearGradientSpan::OutputSpan(
  1843. INT y,
  1844. INT xMin,
  1845. INT xMax // xMax is exclusive
  1846. )
  1847. {
  1848. ASSERT((BrushType == BrushTypeLinearGradient) /*|| (BrushType == BrushRectGrad)*/);
  1849. ASSERT(xMax > xMin);
  1850. // Copy some class stuff to local variables for faster access in
  1851. // our inner loop:
  1852. INT32 xIncrement = XIncrement;
  1853. AGRB64TEXEL *startTexels = &StartTexelAgrb[0];
  1854. AGRB64TEXEL *endTexels = &EndTexelAgrb[0];
  1855. UINT32 count = xMax - xMin;
  1856. ARGB *buffer = Scan->NextBuffer(xMin, y, count);
  1857. UINT32 intervalMask = IntervalMask;
  1858. // Given our start point in device space, figure out the corresponding
  1859. // texture pixel. Note that this is expressed as a fixed-point number
  1860. // with FRACTIONBITS bits of fractional precision:
  1861. INT32 xTexture = (xMin * M11) + (y * M21) + Dx;
  1862. do {
  1863. // We want to linearly interpolate between two pixels,
  1864. // A and B (where A is the floor pixel, B the ceiling pixel).
  1865. // 'multA' is the fraction of pixel A that we want, and
  1866. // 'multB' is the fraction of pixel B that we want:
  1867. UINT32 multB = ONEDGETFRACTIONAL8BITS(xTexture);
  1868. UINT32 multA = 256 - multB;
  1869. // We could actually do a big lookup table right off of 'xTexture'
  1870. // for however many bits of precision we wanted to do. But that
  1871. // would be too much work in the setup.
  1872. UINT32 iTexture = ONEDGETINTEGERBITS(xTexture) & intervalMask;
  1873. AGRB64TEXEL *startTexel = &startTexels[iTexture];
  1874. AGRB64TEXEL *endTexel = &endTexels[iTexture];
  1875. // Note that we can gamma correct the texels so that we don't
  1876. // have to do gamma correction here. The addition of constants
  1877. // here are to accomplish rounding:
  1878. UINT32 rrrrbbbb = (startTexel->A00rr00bb * multA)
  1879. + (endTexel->A00rr00bb * multB)
  1880. + 0x00800080;
  1881. UINT32 aaaagggg = (startTexel->A00aa00gg * multA)
  1882. + (endTexel->A00aa00gg * multB)
  1883. + 0x00800080;
  1884. *buffer = (aaaagggg & 0xff00ff00) + ((rrrrbbbb & 0xff00ff00) >> 8);
  1885. buffer++;
  1886. xTexture += xIncrement;
  1887. } while (--count != 0);
  1888. return Ok;
  1889. }
  1890. /**************************************************************************\
  1891. *
  1892. * Function Description:
  1893. *
  1894. * Outputs a single span within a raster with a gradient brush.
  1895. *
  1896. * Created:
  1897. *
  1898. * 03/16/2000 andrewgo
  1899. *
  1900. \**************************************************************************/
  1901. GpStatus
  1902. DpOutputLinearGradientSpan_MMX::OutputSpan(
  1903. INT y,
  1904. INT xMin,
  1905. INT xMax // xMax is exclusive
  1906. )
  1907. {
  1908. ASSERT((BrushType == BrushTypeLinearGradient) /*|| (BrushType == BrushRectGrad)*/);
  1909. #if defined(_X86_)
  1910. ASSERT(xMax > xMin);
  1911. // Copy some class stuff to local variables for faster access in
  1912. // our inner loop:
  1913. INT32 xIncrement = XIncrement;
  1914. AGRB64TEXEL *startTexels = &StartTexelAgrb[0];
  1915. AGRB64TEXEL *endTexels = &EndTexelAgrb[0];
  1916. UINT32 count = xMax - xMin;
  1917. ARGB *buffer = Scan->NextBuffer(xMin, y, count);
  1918. // Given our start point in device space, figure out the corresponding
  1919. // texture pixel. Note that this is expressed as a fixed-point number
  1920. // with FRACTIONBITS bits of fractional precision:
  1921. INT32 xTexture = (xMin * M11) + (y * M21) + Dx;
  1922. // Scale up the interval count to the MSB so that we don't have to do
  1923. // a mask in the inner loop, which assumes 16.16 for the fixed point
  1924. // representation.
  1925. UINT32 downshiftAmount = 32 - NumberOfIntervalBits;
  1926. UINT32 upshiftAmount = 16 - NumberOfIntervalBits;
  1927. UINT32 intervalCounter = xTexture << upshiftAmount;
  1928. UINT32 intervalIncrement = xIncrement << upshiftAmount;
  1929. // Prepare for the three stages:
  1930. // stage1: QWORD align the destination
  1931. // stage2: process 2 pixels at a time
  1932. // stage3: process the last pixel if present
  1933. UINT32 stage1_count = 0, stage2_count = 0, stage3_count = 0;
  1934. if (count > 0)
  1935. {
  1936. // If destination is not QWORD aligned, process the first pixel
  1937. // in stage 1.
  1938. if (((UINT_PTR) buffer) & 0x4)
  1939. {
  1940. stage1_count = 1;
  1941. count--;
  1942. }
  1943. stage2_count = count >> 1;
  1944. stage3_count = count - 2 * stage2_count;
  1945. _asm
  1946. {
  1947. // eax = pointer to interval-start array
  1948. // ebx = pointer to interval-end array
  1949. // ecx = shift count
  1950. // edx = scratch
  1951. // esi = count
  1952. // edi = destination
  1953. // mm0 = interval counter
  1954. // mm1 = interval incrementer
  1955. // mm2 = fractional counter
  1956. // mm3 = fractional incrementer
  1957. // mm4 = temp
  1958. // mm5 = temp
  1959. dec stage1_count
  1960. mov eax, startTexels
  1961. mov ebx, endTexels
  1962. mov ecx, downshiftAmount
  1963. mov esi, stage2_count
  1964. mov edi, buffer
  1965. movd mm0, intervalCounter
  1966. movd mm1, intervalIncrement
  1967. movd mm2, xTexture // 0 | 0 | 0 | 0 || x | x | mult | lo
  1968. movd mm3, xIncrement
  1969. punpcklwd mm2, mm2 // 0 | x | 0 | x || mult | lo | mult | lo
  1970. punpcklwd mm3, mm3
  1971. punpckldq mm2, mm2 // mult | lo | mult | lo || mult | lo | mult | lo
  1972. punpckldq mm3, mm3
  1973. // This preparation normally happens inside the loop:
  1974. movq mm4, mm2 // mult | x | mult | x || mult | x | mult | x
  1975. movd edx, mm0
  1976. jnz pre_stage2_loop // the flags for this are set in the "dec stage1_count" above
  1977. // stage1_loop:
  1978. psrlw mm4, 8 // 0 | mult | 0 | mult || 0 | mult | 0 | mult
  1979. shr edx, cl
  1980. pmullw mm4, [ebx + edx*8]
  1981. paddd mm0, mm1 // interval counter += interval increment
  1982. add edi, 4 // buffer++
  1983. paddw mm4, [eax + edx*8]
  1984. movd edx, mm0 // Prepare for next iteration
  1985. paddw mm2, mm3 // fractional counter += fractional increment
  1986. psrlw mm4, 8 // 0 | a | 0 | r || 0 | g | 0 | b
  1987. packuswb mm4, mm4 // a | r | g | b || a | r | g | b
  1988. movd [edi - 4], mm4
  1989. movq mm4, mm2 // Prepare for next iteration
  1990. pre_stage2_loop:
  1991. cmp esi, 0
  1992. jz stage3_loop // Do we need to execute the stage2_loop?
  1993. stage2_loop:
  1994. psrlw mm4, 8 // 0 | mult | 0 | mult || 0 | mult | 0 | mult
  1995. shr edx, cl
  1996. paddd mm0, mm1 // interval counter += interval increment
  1997. pmullw mm4, [ebx + edx*8]
  1998. add edi, 8 // buffer++
  1999. paddw mm2, mm3 // fractional counter += fractional increment
  2000. paddw mm4, [eax + edx*8]
  2001. movd edx, mm0 // Prepare for next iteration
  2002. shr edx, cl
  2003. movq mm5, mm2 // Prepare for next iteration
  2004. psrlw mm5, 8 // 0 | mult | 0 | mult || 0 | mult | 0 | mult
  2005. psrlw mm4, 8 // 0 | a | 0 | r || 0 | g | 0 | b
  2006. paddd mm0, mm1 // interval counter += interval increment
  2007. pmullw mm5, [ebx + edx*8]
  2008. dec esi // count--
  2009. paddw mm5, [eax + edx*8]
  2010. movd edx, mm0 // Prepare for next iteration
  2011. paddw mm2, mm3 // fractional counter += fractional increment
  2012. psrlw mm5, 8 // 0 | a | 0 | r || 0 | g | 0 | b
  2013. packuswb mm4, mm5
  2014. movq [edi - 8], mm4
  2015. movq mm4, mm2 // Prepare for next iteration
  2016. jnz stage2_loop
  2017. stage3_loop:
  2018. dec stage3_count
  2019. jnz skip_stage3_loop
  2020. psrlw mm4, 8 // 0 | mult | 0 | mult || 0 | mult | 0 | mult
  2021. shr edx, cl
  2022. pmullw mm4, [ebx + edx*8]
  2023. paddd mm0, mm1 // interval counter += interval increment
  2024. paddw mm4, [eax + edx*8]
  2025. movd edx, mm0 // Prepare for next iteration
  2026. paddw mm2, mm3 // fractional counter += fractional increment
  2027. psrlw mm4, 8 // 0 | a | 0 | r || 0 | g | 0 | b
  2028. packuswb mm4, mm4 // a | r | g | b || a | r | g | b
  2029. movd [edi], mm4
  2030. skip_stage3_loop:
  2031. emms
  2032. }
  2033. }
  2034. #endif
  2035. return(Ok);
  2036. }
  2037. DpOutputPathGradientSpan::DpOutputPathGradientSpan(
  2038. const GpElementaryBrush *brush,
  2039. DpScanBuffer * scan,
  2040. DpContext* context
  2041. ) : DpOutputGradientSpan(brush, scan, context)
  2042. {
  2043. SetValid(FALSE);
  2044. const GpPathGradient* pathBrush
  2045. = static_cast<const GpPathGradient*> (brush);
  2046. if(pathBrush->DeviceBrush.Path)
  2047. pathBrush->Flatten(&WorldToDevice);
  2048. Count = pathBrush->GetNumberOfPoints();
  2049. PointF pt0, pt1, pt2;
  2050. pathBrush->GetCenterPoint(&pt0);
  2051. WorldToDevice.Transform(&pt0);
  2052. GpColor c0, c1, c2;
  2053. pathBrush->GetCenterColor(&c0);
  2054. Triangles = (DpTriangleData**) GpMalloc(Count*sizeof(DpTriangleData*));
  2055. BOOL isPolygonMode = TRUE;
  2056. if(Triangles)
  2057. {
  2058. GpMemset(Triangles, 0, Count*sizeof(DpTriangleData*));
  2059. INT j;
  2060. for(INT i = 0; i < Count; i++)
  2061. {
  2062. if(i < Count - 1)
  2063. j = i + 1;
  2064. else
  2065. j = 0;
  2066. pathBrush->GetPoint(&pt1, i);
  2067. pathBrush->GetPoint(&pt2, j);
  2068. if(pt1.X != pt2.X || pt1.Y != pt2.Y)
  2069. {
  2070. DpTriangleData* tri = new DpTriangleData();
  2071. pathBrush->GetSurroundColor(&c1, i);
  2072. pathBrush->GetSurroundColor(&c2, j);
  2073. // Transform points if they have not been flattened,
  2074. // since OutputSpan gets span data as Device units and
  2075. // the BLTransform must be in the same coordinate space.
  2076. if (pathBrush->FlattenPoints.GetCount() == 0)
  2077. {
  2078. WorldToDevice.Transform(&pt1);
  2079. WorldToDevice.Transform(&pt2);
  2080. }
  2081. tri->SetTriangle(
  2082. pt0, pt1, pt2,
  2083. c0, c1, c2,
  2084. isPolygonMode,
  2085. brush->GetGammaCorrection()
  2086. );
  2087. // Set the blend factors.
  2088. tri->Falloff0 = pathBrush->DeviceBrush.Falloffs[0];
  2089. tri->Falloff1 = 1;
  2090. tri->Falloff2 = 1;
  2091. tri->BlendCount0 = pathBrush->DeviceBrush.BlendCounts[0];
  2092. tri->BlendCount1 = 1;
  2093. tri->BlendCount2 = 1;
  2094. tri->BlendFactors0 = pathBrush->DeviceBrush.BlendFactors[0];
  2095. tri->BlendFactors1 = NULL;
  2096. tri->BlendFactors2 = NULL;
  2097. tri->BlendPositions0 = pathBrush->DeviceBrush.BlendPositions[0];
  2098. tri->BlendPositions1 = NULL;
  2099. tri->BlendPositions2 = NULL;
  2100. tri->PresetColors = pathBrush->DeviceBrush.PresetColors;
  2101. tri->UsesPresetColors = pathBrush->DeviceBrush.UsesPresetColors;
  2102. Triangles[i] = tri;
  2103. }
  2104. else
  2105. Triangles[i] = NULL;
  2106. }
  2107. SetValid(TRUE);
  2108. }
  2109. else
  2110. SetValid(FALSE);
  2111. }
  2112. DpOutputPathGradientSpan::~DpOutputPathGradientSpan(
  2113. VOID
  2114. )
  2115. {
  2116. FreeData();
  2117. }
  2118. VOID
  2119. DpOutputPathGradientSpan::FreeData()
  2120. {
  2121. if(Triangles) {
  2122. for(INT i = 0; i < Count; i++)
  2123. {
  2124. DpTriangleData* tri = Triangles[i];
  2125. delete tri;
  2126. Triangles[i] = NULL;
  2127. }
  2128. GpFree(Triangles);
  2129. Triangles = NULL;
  2130. }
  2131. SetValid(FALSE);
  2132. }
  2133. /**************************************************************************\
  2134. *
  2135. * Function Description:
  2136. *
  2137. * Outputs a single span within a raster with a polygon gradient brush.
  2138. * Is called by the rasterizer.
  2139. *
  2140. * Arguments:
  2141. *
  2142. * [IN] y - the Y value of the raster being output
  2143. * [IN] leftEdge - the DDA class of the left edge
  2144. * [IN] rightEdge - the DDA class of the right edge
  2145. *
  2146. * Return Value:
  2147. *
  2148. * GpStatus - Ok
  2149. *
  2150. * Created:
  2151. *
  2152. * 03/24/1999 ikkof
  2153. *
  2154. \**************************************************************************/
  2155. GpStatus
  2156. DpOutputPathGradientSpan::OutputSpan(
  2157. INT y,
  2158. INT xMin,
  2159. INT xMax // xMax is exclusive
  2160. )
  2161. {
  2162. if(!IsValid())
  2163. return Ok;
  2164. INT xxMin = xMax, xxMax = xMin;
  2165. INT iFirst = 0x7FFFFFFF, iLast = 0;
  2166. for(INT i = 0; i < Count; i++)
  2167. {
  2168. DpTriangleData* triangle = Triangles[i];
  2169. REAL xx[2];
  2170. if(triangle &&
  2171. triangle->SetXSpan((REAL) y, (REAL) xMin, (REAL) xMax, xx))
  2172. {
  2173. xxMin = min(xxMin, GpFloor(xx[0]));
  2174. xxMax = max(xxMax, GpRound(xx[1]));
  2175. iFirst = min(iFirst, i);
  2176. iLast = i;
  2177. }
  2178. }
  2179. // Don't attempt to fill outside the specified x bounds
  2180. xxMin = max(xxMin, xMin);
  2181. xxMax = min(xxMax, xMax);
  2182. INT width = xxMax - xxMin; // Right exclusive when filling
  2183. // No triangles intersect this scan line, so exit
  2184. if (width <= 0)
  2185. return Ok;
  2186. ARGB * buffer = Scan->NextBuffer(xxMin, y, width);
  2187. GpMemset(buffer, 0, width*sizeof(ARGB));
  2188. for(INT i = iFirst; i <= iLast; i++)
  2189. {
  2190. DpTriangleData* triangle = Triangles[i];
  2191. if(triangle)
  2192. triangle->OutputSpan(buffer, CompositingMode,
  2193. y, xxMin, xxMax);
  2194. }
  2195. return Ok;
  2196. }
  2197. DpOutputOneDPathGradientSpan::DpOutputOneDPathGradientSpan(
  2198. const GpElementaryBrush *brush,
  2199. DpScanBuffer * scan,
  2200. DpContext* context,
  2201. BOOL isHorizontal,
  2202. BOOL isVertical
  2203. ) : DpOutputOneDGradientSpan(
  2204. brush,
  2205. scan,
  2206. context,
  2207. isHorizontal,
  2208. isVertical)
  2209. {
  2210. if(!IsValid())
  2211. return;
  2212. SetupPathGradientOneDData(brush->GetGammaCorrection());
  2213. const GpPathGradient* pathBrush
  2214. = static_cast<const GpPathGradient*> (brush);
  2215. if(pathBrush->DeviceBrush.Path)
  2216. pathBrush->Flatten(&WorldToDevice);
  2217. Count = pathBrush->GetNumberOfPoints();
  2218. PointF pt0, pt1, pt2;
  2219. pathBrush->GetCenterPoint(&pt0);
  2220. WorldToDevice.Transform(&pt0);
  2221. // Round center point to nearest 1/16 of a pixel, since
  2222. // this is the rasterizer resolution. This eliminates
  2223. // precision errors that can affect bilinear transforms.
  2224. pt0.X = FIX4TOREAL(GpRealToFix4(pt0.X));
  2225. pt0.Y = FIX4TOREAL(GpRealToFix4(pt0.Y));
  2226. REAL xScale = pathBrush->DeviceBrush.FocusScaleX;
  2227. REAL yScale = pathBrush->DeviceBrush.FocusScaleY;
  2228. REAL inflation;
  2229. pathBrush->GetInflationFactor(&inflation);
  2230. // If we have falloff values, then there are twice the number of
  2231. // transforms. If we are inflating the gradient outwards, then
  2232. // there are additional transforms also.
  2233. INT infCount;
  2234. INT blCount = Count;
  2235. if (xScale != 0 || yScale != 0)
  2236. {
  2237. Count *= 2;
  2238. infCount = Count;
  2239. }
  2240. else
  2241. {
  2242. infCount = blCount;
  2243. }
  2244. if (inflation > 1.0f)
  2245. {
  2246. Count += blCount;
  2247. }
  2248. BLTransforms = new GpBilinearTransform[Count];
  2249. GpPointF points[4];
  2250. GpRectF rect(0, 0, 1, 1);
  2251. if(BLTransforms)
  2252. {
  2253. INT j;
  2254. for(INT i = 0; i < blCount; i++)
  2255. {
  2256. if(i < blCount - 1)
  2257. j = i + 1;
  2258. else
  2259. j = 0;
  2260. pathBrush->GetPoint(&pt1, i);
  2261. pathBrush->GetPoint(&pt2, j);
  2262. if(pt1.X != pt2.X || pt1.Y != pt2.Y)
  2263. {
  2264. // Transform points if they have not been flattened,
  2265. // since OutputSpan gets span data as Device units and
  2266. // the BLTransform must be in the same coordinate space.
  2267. if (pathBrush->FlattenPoints.GetCount() == 0)
  2268. {
  2269. WorldToDevice.Transform(&pt1);
  2270. WorldToDevice.Transform(&pt2);
  2271. }
  2272. // Round points to nearest 1/16 of a pixel, since
  2273. // this is the rasterizer resolution. This eliminates
  2274. // precision errors that can affect bilinear transforms.
  2275. pt1.X = FIX4TOREAL(GpRealToFix4(pt1.X));
  2276. pt1.Y = FIX4TOREAL(GpRealToFix4(pt1.Y));
  2277. pt2.X = FIX4TOREAL(GpRealToFix4(pt2.X));
  2278. pt2.Y = FIX4TOREAL(GpRealToFix4(pt2.Y));
  2279. points[1] = pt1;
  2280. points[3] = pt2;
  2281. if (inflation > 1.0f)
  2282. {
  2283. // Create a quadralateral extension of the gradient away
  2284. // from the outer edge, and set the fixed value to 1.0, so
  2285. // this entire quadralateral will be filled with the edge
  2286. // color. This is useful in some printing cases.
  2287. points[0].X = pt0.X + inflation*(pt1.X - pt0.X);
  2288. points[0].Y = pt0.Y + inflation*(pt1.Y - pt0.Y);
  2289. points[2].X = pt0.X + inflation*(pt2.X - pt0.X);
  2290. points[2].Y = pt0.Y + inflation*(pt2.Y - pt0.Y);
  2291. GpPointF centerPoints[4];
  2292. GpRectF centerRect(0, 0, 1, 1);
  2293. centerPoints[0] = points[0];
  2294. centerPoints[1] = pt1;
  2295. centerPoints[2] = points[2];
  2296. centerPoints[3] = pt2;
  2297. BLTransforms[infCount+i].SetBilinearTransform(centerRect, &centerPoints[0], 4, 1.0f);
  2298. }
  2299. if(xScale == 0 && yScale == 0)
  2300. {
  2301. points[0] = pt0;
  2302. points[2] = pt0;
  2303. }
  2304. else
  2305. {
  2306. // Set up an outer quadralateral for the gradient, plus an
  2307. // inner triangle for the single center gradient color.
  2308. points[0].X = pt0.X + xScale*(pt1.X - pt0.X);
  2309. points[0].Y = pt0.Y + yScale*(pt1.Y - pt0.Y);
  2310. points[2].X = pt0.X + xScale*(pt2.X - pt0.X);
  2311. points[2].Y = pt0.Y + yScale*(pt2.Y - pt0.Y);
  2312. GpPointF centerPoints[4];
  2313. GpRectF centerRect(0, 0, 1, 1);
  2314. centerPoints[0] = pt0;
  2315. centerPoints[1] = points[0];
  2316. centerPoints[2] = pt0;
  2317. centerPoints[3] = points[2];
  2318. // Set the fixed value to use for the inner triangular
  2319. // to 0, so that the inner gradient color will be used to
  2320. // fill this region.
  2321. BLTransforms[blCount+i].SetBilinearTransform(centerRect, &centerPoints[0], 4, 0.0f);
  2322. }
  2323. BLTransforms[i].SetBilinearTransform(rect, &points[0], 4);
  2324. }
  2325. }
  2326. SetValid(TRUE);
  2327. }
  2328. else
  2329. SetValid(FALSE);
  2330. }
  2331. VOID
  2332. DpOutputOneDPathGradientSpan::SetupPathGradientOneDData(
  2333. BOOL gammaCorrect
  2334. )
  2335. {
  2336. REAL u, u0, du;
  2337. u0 = 0;
  2338. du = 1.0f/OneDDataMultiplier;
  2339. ARGB* buffer = OneDData;
  2340. ASSERT(buffer);
  2341. if(!buffer)
  2342. return;
  2343. const GpPathGradient* pathBrush
  2344. = static_cast<const GpPathGradient*> (Brush);
  2345. GpColor c0, c1;
  2346. pathBrush->GetCenterColor(&c0);
  2347. pathBrush->GetSurroundColor(&c1, 0);
  2348. GpFColor128 color[2];
  2349. GammaLinearizeAndPremultiply(
  2350. c0.GetValue(),
  2351. gammaCorrect,
  2352. &color[0]
  2353. );
  2354. GammaLinearizeAndPremultiply(
  2355. c1.GetValue(),
  2356. gammaCorrect,
  2357. &color[1]
  2358. );
  2359. for(INT i = 0; i < OneDDataCount; i++, buffer++)
  2360. {
  2361. u = u0;
  2362. REAL w = u;
  2363. GpFColor128 colorOut;
  2364. if(!(pathBrush->HasPresetColors() &&
  2365. pathBrush->DeviceBrush.PresetColors &&
  2366. pathBrush->DeviceBrush.BlendPositions[0] &&
  2367. pathBrush->DeviceBrush.BlendCounts[0] > 1))
  2368. {
  2369. w = ::adjustValue(
  2370. w,
  2371. pathBrush->DeviceBrush.BlendCounts[0],
  2372. pathBrush->DeviceBrush.Falloffs[0],
  2373. pathBrush->DeviceBrush.BlendFactors[0],
  2374. pathBrush->DeviceBrush.BlendPositions[0]
  2375. );
  2376. colorOut.a = color[0].a + w*(color[1].a - color[0].a);
  2377. colorOut.r = color[0].r + w*(color[1].r - color[0].r);
  2378. colorOut.g = color[0].g + w*(color[1].g - color[0].g);
  2379. colorOut.b = color[0].b + w*(color[1].b - color[0].b);
  2380. }
  2381. else
  2382. {
  2383. interpolatePresetColors(
  2384. &colorOut,
  2385. w,
  2386. pathBrush->DeviceBrush.BlendCounts[0],
  2387. pathBrush->DeviceBrush.PresetColors,
  2388. pathBrush->DeviceBrush.BlendPositions[0],
  2389. gammaCorrect
  2390. );
  2391. }
  2392. if( (REALABS(colorOut.a) >= REAL_EPSILON) ||
  2393. (CompositingMode == CompositingModeSourceCopy) )
  2394. {
  2395. GpColorConverter colorConv;
  2396. // Make sure the colorOut is properly premultiplied.
  2397. CLAMP_COLOR_CHANNEL(colorOut.a, 255.0f)
  2398. CLAMP_COLOR_CHANNEL(colorOut.r, colorOut.a);
  2399. CLAMP_COLOR_CHANNEL(colorOut.g, colorOut.a);
  2400. CLAMP_COLOR_CHANNEL(colorOut.b, colorOut.a);
  2401. if(gammaCorrect)
  2402. {
  2403. colorConv.argb = GammaUnlinearizePremultiplied128(colorOut);
  2404. }
  2405. else
  2406. {
  2407. colorConv.Channel.a = static_cast<BYTE>(GpRound(colorOut.a));
  2408. colorConv.Channel.r = static_cast<BYTE>(GpRound(colorOut.r));
  2409. colorConv.Channel.g = static_cast<BYTE>(GpRound(colorOut.g));
  2410. colorConv.Channel.b = static_cast<BYTE>(GpRound(colorOut.b));
  2411. }
  2412. // Clamp to the alpha channel for the premultiplied alpha blender.
  2413. *buffer = colorConv.argb;
  2414. }
  2415. else
  2416. {
  2417. *buffer = 0; // case of CompositingModeSourceOver && alpha = 0
  2418. }
  2419. u0 += du;
  2420. }
  2421. }
  2422. GpStatus
  2423. DpOutputOneDPathGradientSpan::OutputSpan(
  2424. INT y,
  2425. INT xMin,
  2426. INT xMax // xMax is exclusive
  2427. )
  2428. {
  2429. FPUStateSaver::AssertMode();
  2430. if(!IsValid())
  2431. {
  2432. return Ok;
  2433. }
  2434. INT width = xMax - xMin;
  2435. ARGB * buffer = Scan->NextBuffer(xMin, y, width);
  2436. GpMemset(buffer, 0, width*sizeof(ARGB));
  2437. REAL* u = (REAL*) GpMalloc(2*width*sizeof(REAL));
  2438. REAL* v = u + width;
  2439. if(u == NULL)
  2440. {
  2441. GpFree(u);
  2442. return OutOfMemory;
  2443. }
  2444. for(INT i = 0; i < Count; i++)
  2445. {
  2446. INT pairCount;
  2447. INT xSpans[4];
  2448. pairCount = BLTransforms[i].GetSourceParameterArrays(
  2449. u, v, &xSpans[0], y, xMin, xMax);
  2450. if(pairCount > 0)
  2451. {
  2452. REAL* u1 = u;
  2453. for(INT k = 0; k < pairCount; k++)
  2454. {
  2455. ARGB* buffer1 = buffer + xSpans[2*k] - xMin;
  2456. INT width = xSpans[2*k + 1] - xSpans[2*k];
  2457. for(INT j = 0; j < width; j++)
  2458. {
  2459. REAL u2 = *u1;
  2460. if(u2 < 0)
  2461. u2 = 0;
  2462. *buffer1++ = OneDData[GpRound(OneDDataMultiplier*u2)];
  2463. u1++;
  2464. }
  2465. u1 = u + width;
  2466. }
  2467. }
  2468. }
  2469. GpFree(u);
  2470. return Ok;
  2471. }
  2472. #undef CLAMP_COLOR_CHANNEL