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.

717 lines
22 KiB

  1. /**************************************************************************\
  2. *
  3. * Copyright (c) 1998 Microsoft Corporation
  4. *
  5. * Abstract:
  6. *
  7. * Engine solid fill routines.
  8. *
  9. * Revision History:
  10. *
  11. * 12/11/1998 andrewgo
  12. * Created it.
  13. *
  14. \**************************************************************************/
  15. #include "precomp.hpp"
  16. /**************************************************************************\
  17. *
  18. * Function Description:
  19. *
  20. * Outputs a single span within a raster as a solid color.
  21. * Is called by the rasterizer.
  22. *
  23. * Arguments:
  24. *
  25. * [IN] y - the Y value of the raster being output
  26. * [IN] leftEdge - the DDA class of the left edge
  27. * [IN] rightEdge - the DDA class of the right edge
  28. *
  29. * Return Value:
  30. *
  31. * GpStatus - Ok
  32. *
  33. * Created:
  34. *
  35. * 12/15/1998 DCurtis
  36. *
  37. \**************************************************************************/
  38. GpStatus
  39. DpOutputSolidColorSpan::OutputSpan(
  40. INT y,
  41. INT xMin,
  42. INT xMax // xMax is exclusive
  43. )
  44. {
  45. INT width = xMax - xMin;
  46. FillMemoryInt32(Scan->NextBuffer(xMin, y, width), width, Argb);
  47. return Ok;
  48. }
  49. /**************************************************************************\
  50. *
  51. * Function Description:
  52. *
  53. * Fills a path. This distributes to the individual brush fill method.
  54. *
  55. * Arguments:
  56. *
  57. * [IN] context - the context (matrix and clipping)
  58. * [IN] surface - the surface to fill
  59. * [IN] drawBounds - the surface bounds
  60. * [IN] path - the path to fill
  61. * [IN] brush - the brush to use
  62. *
  63. * Return Value:
  64. *
  65. * GpStatus - Ok or failure status
  66. *
  67. * Created:
  68. *
  69. * 01/21/1999 ikkof
  70. *
  71. \**************************************************************************/
  72. GpStatus
  73. DpDriver::FillPath(
  74. DpContext *context,
  75. DpBitmap *surface,
  76. const GpRect *drawBounds,
  77. const DpPath *path,
  78. const DpBrush *brush
  79. )
  80. {
  81. GpStatus status = GenericError;
  82. const GpBrush *gpBrush = GpBrush::GetBrush(brush);
  83. BOOL noTransparentPixels = (!context->AntiAliasMode) && (gpBrush->IsOpaque());
  84. DpScanBuffer scan(
  85. surface->Scan,
  86. this,
  87. context,
  88. surface,
  89. noTransparentPixels);
  90. if (scan.IsValid())
  91. {
  92. if (brush->Type == BrushTypeSolidColor)
  93. {
  94. GpColor color(brush->SolidColor.GetValue());
  95. DpOutputSolidColorSpan output(color.GetPremultipliedValue(), &scan);
  96. status = RasterizePath(path,
  97. &context->WorldToDevice,
  98. path->GetFillMode(),
  99. context->AntiAliasMode,
  100. FALSE,
  101. &output,
  102. &context->VisibleClip,
  103. drawBounds);
  104. }
  105. else
  106. {
  107. // If there is a shrinking world to device transform when using
  108. // a path gradient, then scale the brush and the path to be
  109. // in device units. This eliminates the need to create potentially
  110. // very large gradients or textures.
  111. // Only handle positive scale because some of our driver rectangle
  112. // filling code can't handle negative rects. Doing ABS preserves
  113. // the sign of the input world coordinate rectangles/path.
  114. REAL scaleX = REALABS(context->WorldToDevice.GetM11());
  115. REAL scaleY = REALABS(context->WorldToDevice.GetM22());
  116. DpOutputSpan * output = NULL;
  117. if (brush->Type == BrushTypePathGradient &&
  118. context->WorldToDevice.IsTranslateScale() &&
  119. REALABS(scaleX) > REAL_EPSILON &&
  120. REALABS(scaleY) > REAL_EPSILON &&
  121. (REALABS(scaleX) < 1.0f || REALABS(scaleY) < 1.0f))
  122. {
  123. // I don't like the following hack for magically getting
  124. // a GpBrush from a DpBrush, but DpOutputSpan already does this...
  125. GpBrush * gpbrush = GpBrush::GetBrush( (DpBrush *)(brush));
  126. GpPathGradient *scaledBrush = (GpPathGradient*)(gpbrush->Clone());
  127. if (scaledBrush == NULL)
  128. {
  129. return OutOfMemory;
  130. }
  131. // Scale the cloned brush's path and bounding rect into
  132. // device units.
  133. scaledBrush->ScalePath(scaleX,scaleY);
  134. REAL mOrig[6];
  135. context->WorldToDevice.GetMatrix(mOrig);
  136. context->WorldToDevice.Scale(1.0f/scaleX, 1.0f/scaleY);
  137. output = DpOutputSpan::Create(scaledBrush->GetDeviceBrush(), &scan, context, drawBounds);
  138. if (output != NULL)
  139. {
  140. GpPath *scalePath = ((GpPath*)path)->Clone();
  141. if (scalePath != NULL)
  142. {
  143. GpMatrix scaleMatrix (scaleX, 0.0f, 0.0f, scaleY, 0.0f, 0.0f);
  144. scalePath->Transform(&scaleMatrix);
  145. status = RasterizePath(scalePath,
  146. &context->WorldToDevice,
  147. path->GetFillMode(),
  148. context->AntiAliasMode,
  149. FALSE,
  150. output,
  151. &context->VisibleClip,
  152. drawBounds);
  153. delete scalePath;
  154. }
  155. else
  156. {
  157. status = OutOfMemory;
  158. }
  159. delete output;
  160. }
  161. else
  162. {
  163. status = OutOfMemory;
  164. }
  165. delete scaledBrush;
  166. context->WorldToDevice.SetMatrix(mOrig);
  167. }
  168. else
  169. {
  170. output = DpOutputSpan::Create(brush, &scan, context, drawBounds);
  171. if (output != NULL)
  172. {
  173. status = RasterizePath(path,
  174. &context->WorldToDevice,
  175. path->GetFillMode(),
  176. context->AntiAliasMode,
  177. FALSE,
  178. output,
  179. &context->VisibleClip,
  180. drawBounds);
  181. delete output;
  182. }
  183. }
  184. }
  185. }
  186. return status;
  187. }
  188. /**************************************************************************\
  189. *
  190. * Function Description:
  191. *
  192. * Draws a path. This distributes to the individual pen draw method.
  193. *
  194. * Arguments:
  195. *
  196. * [IN] context - the context (matrix and clipping)
  197. * [IN] surface - the surface to draw to
  198. * [IN] drawBounds - the surface bounds
  199. * [IN] path - the path to stroke
  200. * [IN] pen - the pen to use
  201. *
  202. * Return Value:
  203. *
  204. * GpStatus - Ok or failure status
  205. *
  206. * Created:
  207. *
  208. * 01/06/1999 ikkof
  209. *
  210. \**************************************************************************/
  211. GpStatus
  212. DpDriver::StrokePath(
  213. DpContext *context,
  214. DpBitmap *surface,
  215. const GpRect *drawBounds,
  216. const DpPath *path,
  217. const DpPen *pen
  218. )
  219. {
  220. GpStatus status = GenericError;
  221. const DpBrush *brush = pen->Brush;
  222. REAL dpiX = (context->GetDpiX() > 0)
  223. ? (context->GetDpiX())
  224. : (Globals::DesktopDpiX);
  225. BOOL isOnePixelWide = pen->IsOnePixelWide(&context->WorldToDevice, dpiX) &&
  226. pen->IsCenterNoAnchor();
  227. BOOL isOnePixelWideOpaque = isOnePixelWide &&
  228. (brush->Type == BrushTypeSolidColor) &&
  229. (brush->SolidColor.IsOpaque()) &&
  230. !(context->AntiAliasMode);
  231. BOOL isOnePixelWideSolid = isOnePixelWide &&
  232. pen->IsSimple();
  233. // We have a special fast-path for doing single-pixel-wide,
  234. // solid color, opaque, aliased lines:
  235. // !!! [asecchia] RAID 239905.
  236. // The single pixel wide optimized code has significant rounding problems
  237. // that are particularly problematic on bezier curves.
  238. // Bezier curves tend to be enumerated in a particular way that causes
  239. // the SolidStrokePathOnePixel code to enumerate the line segments backward
  240. // hitting badly tested end point conditions, though the problem seems
  241. // to be pervasive.
  242. // The general rasterizer does not have these problems but is about
  243. // 30% slower for single pixel solid lines.
  244. // Turn on the optimization only for polylines until this is fixed.
  245. if (isOnePixelWideOpaque && isOnePixelWideSolid && !path->HasCurve())
  246. {
  247. return SolidStrokePathOnePixel(
  248. context,
  249. surface,
  250. drawBounds,
  251. path,
  252. pen,
  253. TRUE
  254. );
  255. }
  256. const DpPath* widenedPath;
  257. const DpPath* allocatedPath;
  258. GpMatrix *transform;
  259. GpMatrix identityTransform;
  260. if (isOnePixelWideSolid)
  261. {
  262. // Our RasterizePath code can directly draw a one-pixel-wide solid
  263. // line directly:
  264. widenedPath = path;
  265. allocatedPath = NULL;
  266. transform = &context->WorldToDevice;
  267. }
  268. else
  269. {
  270. // We have to widen the path before we can give it to the
  271. // rasterizer. Generate new path now:
  272. REAL dpiX = context->GetDpiX();
  273. REAL dpiY = context->GetDpiY();
  274. if ((dpiX <= 0) || (dpiY <= 0))
  275. {
  276. dpiX = Globals::DesktopDpiX;
  277. dpiY = Globals::DesktopDpiY;
  278. }
  279. widenedPath = path->GetFlattenedPath(
  280. isOnePixelWideOpaque ? NULL : &context->WorldToDevice,
  281. isOnePixelWideOpaque ? Flattened : Widened,
  282. pen
  283. );
  284. allocatedPath = widenedPath;
  285. transform = &identityTransform;
  286. if (!widenedPath)
  287. return OutOfMemory;
  288. // If this line is aliased, opaque and dashed, dash it now and pass the
  289. // dashed path to the single pixel stroking code.
  290. if (isOnePixelWideOpaque && pen->DashStyle != DashStyleSolid)
  291. {
  292. DpPath *dashPath = NULL;
  293. dashPath = ((GpPath*)widenedPath)->CreateDashedPath(pen,
  294. NULL,
  295. dpiX,
  296. dpiY,
  297. 1.0f,
  298. FALSE /* don't need caps in 1 px wide case */);
  299. if (!dashPath)
  300. {
  301. delete widenedPath;
  302. return OutOfMemory;
  303. }
  304. Status status = SolidStrokePathOnePixel(context,
  305. surface,
  306. drawBounds,
  307. dashPath,
  308. pen,
  309. FALSE);
  310. delete dashPath;
  311. delete widenedPath;
  312. return status;
  313. }
  314. }
  315. const GpBrush *gpBrush = GpBrush::GetBrush(brush);
  316. BOOL noTransparentPixels = (!context->AntiAliasMode) && (gpBrush->IsOpaque());
  317. DpScanBuffer scan(surface->Scan, this, context, surface, noTransparentPixels);
  318. if (scan.IsValid())
  319. {
  320. if (brush->Type == BrushTypeSolidColor)
  321. {
  322. GpColor color(brush->SolidColor.GetValue());
  323. DpOutputSolidColorSpan output(color.GetPremultipliedValue(), &scan);
  324. status = RasterizePath(widenedPath,
  325. transform,
  326. widenedPath->GetFillMode(),
  327. context->AntiAliasMode,
  328. isOnePixelWideSolid,
  329. &output,
  330. &context->VisibleClip,
  331. drawBounds);
  332. }
  333. else
  334. {
  335. DpOutputSpan * output = DpOutputSpan::Create(brush, &scan, context,
  336. drawBounds);
  337. if (output != NULL)
  338. {
  339. status = RasterizePath(widenedPath,
  340. transform,
  341. widenedPath->GetFillMode(),
  342. context->AntiAliasMode,
  343. isOnePixelWideSolid,
  344. output,
  345. &context->VisibleClip,
  346. drawBounds);
  347. delete output;
  348. }
  349. }
  350. }
  351. if (allocatedPath)
  352. {
  353. delete allocatedPath;
  354. }
  355. return status;
  356. }
  357. /**************************************************************************\
  358. *
  359. * Function Description:
  360. *
  361. * Fills a region. This distributes to the individual brush fill method.
  362. *
  363. * Arguments:
  364. *
  365. * [IN] context - the context (matrix and clipping)
  366. * [IN] surface - the surface to fill
  367. * [IN] drawBounds - the surface bounds
  368. * [IN] region - the region to fill
  369. * [IN] brush - the brush to use
  370. *
  371. * Return Value:
  372. *
  373. * GpStatus - Ok or failure status
  374. *
  375. * Created:
  376. *
  377. * 02/25/1999 DCurtis
  378. *
  379. \**************************************************************************/
  380. GpStatus
  381. DpDriver::FillRegion(
  382. DpContext *context,
  383. DpBitmap *surface,
  384. const GpRect *drawBounds,
  385. const DpRegion *region,
  386. const DpBrush *brush
  387. )
  388. {
  389. GpStatus status = GenericError;
  390. const GpBrush *gpBrush = GpBrush::GetBrush(brush);
  391. DpScanBuffer scan(
  392. surface->Scan,
  393. this,
  394. context,
  395. surface,
  396. gpBrush->IsOpaque());
  397. if (scan.IsValid())
  398. {
  399. DpOutputSpan * output = DpOutputSpan::Create(brush, &scan,
  400. context, drawBounds);
  401. if (output != NULL)
  402. {
  403. DpClipRegion * clipRegion = &(context->VisibleClip);
  404. GpRect clipBounds;
  405. GpRect * clipBoundsPointer = NULL;
  406. DpRegion::Visibility visibility;
  407. visibility = clipRegion->GetRectVisibility(
  408. drawBounds->X,
  409. drawBounds->Y,
  410. drawBounds->X + drawBounds->Width,
  411. drawBounds->Y + drawBounds->Height);
  412. switch (visibility)
  413. {
  414. default: // Need to clip
  415. clipRegion->GetBounds(&clipBounds);
  416. clipBoundsPointer = &clipBounds;
  417. clipRegion->InitClipping(output, drawBounds->Y);
  418. status = region->Fill(clipRegion, clipBoundsPointer);
  419. break;
  420. case DpRegion::TotallyVisible: // No clipping needed
  421. status = region->Fill(output, clipBoundsPointer);
  422. break;
  423. case DpRegion::Invisible:
  424. status = Ok;
  425. break;
  426. }
  427. delete output;
  428. clipRegion->EndClipping();
  429. }
  430. }
  431. return status;
  432. }
  433. GpStatus
  434. DpDriver::MoveBits(
  435. DpContext *context,
  436. DpBitmap *surface,
  437. const GpRect *drawBounds,
  438. const GpRect *dstRect,
  439. const GpPoint *srcPoint
  440. )
  441. {
  442. return(GenericError);
  443. }
  444. GpStatus
  445. DpDriver::Lock(
  446. DpBitmap *surface,
  447. const GpRect *drawBounds,
  448. INT *stride, // [OUT] - Returned stride
  449. VOID **bits // [OUT] - Returned pointer to bits
  450. )
  451. {
  452. return(Ok);
  453. }
  454. VOID
  455. DpDriver::Unlock(
  456. DpBitmap *surface
  457. )
  458. {
  459. }
  460. /**************************************************************************\
  461. *
  462. * Function Description:
  463. *
  464. * Engine version of routine to fill rectangles.
  465. * This is not limited to filling solid color.
  466. *
  467. * Arguments:
  468. *
  469. * [IN] - DDI parameters.
  470. *
  471. * Return Value:
  472. *
  473. * TRUE if successful.
  474. *
  475. * History:
  476. *
  477. * 01/13/1999 ikkof
  478. * Created it.
  479. *
  480. \**************************************************************************/
  481. // !!![andrewgo] What is this doing in a file called "solidfill.cpp"?
  482. GpStatus
  483. DpDriver::FillRects(
  484. DpContext *context,
  485. DpBitmap *surface,
  486. const GpRect *drawBounds,
  487. INT numRects,
  488. const GpRectF *rects,
  489. const DpBrush *brush
  490. )
  491. {
  492. GpStatus status = Ok;
  493. GpBrushType type = brush->Type;
  494. const GpBrush *gpBrush = GpBrush::GetBrush(brush);
  495. DpScanBuffer scan(
  496. surface->Scan,
  497. this,
  498. context,
  499. surface,
  500. gpBrush->IsOpaque());
  501. if(!scan.IsValid())
  502. {
  503. return(GenericError);
  504. }
  505. DpOutputSpan * output = DpOutputSpan::Create(brush, &scan,
  506. context, drawBounds);
  507. if(output == NULL)
  508. return(GenericError);
  509. DpRegion::Visibility visibility = DpRegion::TotallyVisible;
  510. DpClipRegion * clipRegion = NULL;
  511. if (context->VisibleClip.GetRectVisibility(
  512. drawBounds->X, drawBounds->Y,
  513. drawBounds->GetRight(), drawBounds->GetBottom()) !=
  514. DpRegion::TotallyVisible)
  515. {
  516. clipRegion = &(context->VisibleClip);
  517. clipRegion->InitClipping(output, drawBounds->Y);
  518. }
  519. GpMatrix *worldToDevice = &context->WorldToDevice;
  520. const GpRectF * rect = rects;
  521. INT y;
  522. for (INT i = numRects; i != 0; i--, rect++)
  523. {
  524. // We have to check for empty rectangles in world space (because
  525. // after the transform they might have flipped):
  526. if ((rect->Width > 0) && (rect->Height > 0))
  527. {
  528. GpPointF points[4];
  529. points[0].X = rect->X;
  530. points[0].Y = rect->Y;
  531. points[1].X = rect->X + rect->Width;
  532. points[1].Y = rect->Y + rect->Height;
  533. // FillRects only ever gets called when a scaling transform:
  534. // !!![ericvan] printing code calls this to render the brush onto a rectangle,
  535. // but the transform in effect may not be TranslateScale
  536. // !!![andrewgo] Yeah but then isn't the printer case completely
  537. // broken when there is an arbitrary transform?!?
  538. ASSERT(context->IsPrinter ||
  539. worldToDevice->IsTranslateScale());
  540. worldToDevice->Transform(points, 2);
  541. INT left;
  542. INT right;
  543. // convert to INT the same way the GDI+ rasterizer does
  544. // so we get the same rounding error in both places.
  545. if (points[0].X <= points[1].X)
  546. {
  547. left = RasterizerCeiling(points[0].X);
  548. right = RasterizerCeiling(points[1].X); // exclusive
  549. }
  550. else
  551. {
  552. left = RasterizerCeiling(points[1].X);
  553. right = RasterizerCeiling(points[0].X); // exclusive
  554. }
  555. // Since right is exclusive, we don't draw anything
  556. // if left >= right.
  557. INT width = right - left;
  558. INT top;
  559. INT bottom;
  560. if (points[0].Y <= points[1].Y)
  561. {
  562. top = RasterizerCeiling(points[0].Y);
  563. bottom = RasterizerCeiling(points[1].Y); // exclusive
  564. }
  565. else
  566. {
  567. top = RasterizerCeiling(points[1].Y);
  568. bottom = RasterizerCeiling(points[0].Y); // exclusive
  569. }
  570. // Since bottom is exclusive, we don't draw anything
  571. // if top >= bottom.
  572. if ((width > 0) && (top < bottom))
  573. {
  574. GpRect clippedRect;
  575. if(clipRegion)
  576. {
  577. visibility =
  578. clipRegion->GetRectVisibility(
  579. left, top,
  580. right, bottom, &clippedRect);
  581. }
  582. switch (visibility)
  583. {
  584. case DpRegion::ClippedVisible:
  585. left = clippedRect.X;
  586. top = clippedRect.Y;
  587. right = clippedRect.GetRight();
  588. bottom = clippedRect.GetBottom();
  589. width = right - left;
  590. // FALLTHRU
  591. case DpRegion::TotallyVisible:
  592. for (y = top; y < bottom; y++)
  593. {
  594. output->OutputSpan(y, left, right);
  595. }
  596. break;
  597. case DpRegion::PartiallyVisible:
  598. for (y = top; y < bottom; y++)
  599. {
  600. clipRegion->OutputSpan(y, left, right);
  601. }
  602. break;
  603. case DpRegion::Invisible:
  604. break;
  605. }
  606. }
  607. }
  608. }
  609. if (clipRegion != NULL)
  610. {
  611. clipRegion->EndClipping();
  612. }
  613. delete output;
  614. return status;
  615. }