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.

1168 lines
37 KiB

  1. /****************************************************************************
  2. Unit Cache; Implementation
  3. *****************************************************************************
  4. Module Prefix: Ca
  5. ****************************************************************************/
  6. #include "headers.c"
  7. #pragma hdrstop
  8. #include "cache.h" /* own interface */
  9. /*********************** Exported Data **************************************/
  10. /*********************** Private Data ***************************************/
  11. /*--- Gdi cache ---*/
  12. typedef struct
  13. {
  14. HPEN handle;
  15. LOGPEN logPen;
  16. Boolean stockObject;
  17. } Pen, far * PenLPtr;
  18. typedef struct
  19. {
  20. HBRUSH handle;
  21. LOGBRUSH logBrush;
  22. Boolean stockObject;
  23. } Brush, far * BrushLPtr;
  24. typedef struct
  25. {
  26. Handle metafile; // metafile handle
  27. Rect prevClipRect; // last cliprect before SaveDC()
  28. Rect curClipRect; // last clipping rectangle
  29. Boolean forceNewClipRect; // always emit new clipping rectangle?
  30. HPEN nulPen; // frequently used pens
  31. HPEN whitePen;
  32. HPEN blackPen;
  33. HBRUSH nulBrush; // frequently used brushes
  34. HBRUSH whiteBrush;
  35. HBRUSH blackBrush;
  36. Boolean stockFont; // current font selection
  37. HFONT curFont;
  38. LOGFONT curLogFont;
  39. Brush curBrush; // current pen and brush selections
  40. Pen curPen;
  41. Pen nextPen; // cached frame(pen)
  42. CaPrimitive nextPrim; // cached primitive
  43. Boolean samePrim;
  44. Handle polyHandle;
  45. Integer numPoints;
  46. Integer maxPoints;
  47. Point far * pointList;
  48. Word iniROP2; // initial value for ROP2 mode
  49. Word iniTextAlign; // initial value for text alignment
  50. Word iniBkMode;
  51. RGBColor iniTxColor;
  52. RGBColor iniBkColor;
  53. Word curROP2; // current ROP codes setting
  54. Word curBkMode; // current background mode
  55. RGBColor curBkColor; // current background color
  56. Word curStretchMode; // current stretchblt mode
  57. RGBColor curTextColor; // last text color
  58. Word curTextAlign; // last text alignment value
  59. short curCharExtra; // last char extra value
  60. Fixed spExtra; // last space extra value
  61. Point txNumer; // last text scaling
  62. Point txDenom; // factors
  63. Boolean restorePen; // do any attribs need to be re-issued
  64. Boolean restoreBrush; // after RestoreDC() call?
  65. Boolean restoreFont;
  66. Boolean restoreCharExtra;
  67. Boolean restoreStretchMode;
  68. } GdiCache;
  69. private GdiCache gdiCache;
  70. /*********************** Private Function Definitions ***********************/
  71. #define /* void */ NewPolygon( /* void */ ) \
  72. /* start a new polygon definition */ \
  73. gdiCache.numPoints = 0
  74. private void AddPolyPt( Point pt );
  75. /* Add a point to the polygon buffer */
  76. private void SelectCachedPen( void );
  77. /* select the currently cached Pen into the metafile */
  78. /*********************** Function Implementation ****************************/
  79. void CaInit( Handle metafile )
  80. /*=========*/
  81. /* initialize the gdi cache module */
  82. {
  83. /* save off the metafile handle into global structure */
  84. gdiCache.metafile = metafile;
  85. /* make sure that text and background colors will be set */
  86. gdiCache.curTextColor =
  87. gdiCache.curBkColor = RGB( 12, 34, 56 );
  88. /* get handles to some stock pen objects */
  89. gdiCache.nulPen = GetStockObject( NULL_PEN );
  90. gdiCache.whitePen = CreatePen( PS_INSIDEFRAME, 1, RGB( 255, 255, 255 ) );
  91. gdiCache.blackPen = CreatePen( PS_INSIDEFRAME, 1, RGB( 0, 0, 0 ) );
  92. /* get handles to some stock brush objects */
  93. gdiCache.nulBrush = GetStockObject( NULL_BRUSH );
  94. gdiCache.whiteBrush = GetStockObject( WHITE_BRUSH );
  95. gdiCache.blackBrush = GetStockObject( BLACK_BRUSH );
  96. /* allocate space for the polygon buffer */
  97. gdiCache.numPoints = 0;
  98. gdiCache.maxPoints = 16;
  99. gdiCache.polyHandle = GlobalAlloc( GHND, gdiCache.maxPoints * sizeof( Point ) );
  100. if (gdiCache.polyHandle == NULL)
  101. {
  102. ErSetGlobalError( ErMemoryFull);
  103. }
  104. else
  105. {
  106. /* get a pointer address for the memory block */
  107. gdiCache.pointList = (Point far *)GlobalLock( gdiCache.polyHandle );
  108. }
  109. /* mark the primitive cache as empty */
  110. gdiCache.nextPrim.type = CaEmpty;
  111. /* the current primitive isn't being repeated */
  112. gdiCache.samePrim = FALSE;
  113. /* turn off forcing of a new clipping rectangle */
  114. gdiCache.forceNewClipRect = FALSE;
  115. } /* CaInit */
  116. void CaFini( void )
  117. /*=========*/
  118. /* close down the cache module */
  119. {
  120. /* delete the current font selection if non-NULL and non-stock */
  121. if ((gdiCache.curFont != NULL) && !gdiCache.stockFont)
  122. {
  123. /* free the font object */
  124. DeleteObject( gdiCache.curFont );
  125. }
  126. /* remove the current brush selection if non-NULL and not a stock brush */
  127. if ((gdiCache.curBrush.handle != NULL) && !gdiCache.curBrush.stockObject)
  128. {
  129. /* see if the current brush has a DIB - if so, delete it */
  130. if (gdiCache.curBrush.logBrush.lbStyle == BS_DIBPATTERN)
  131. {
  132. /* free the DIB memory used for brush */
  133. GlobalFree( (HANDLE) gdiCache.curBrush.logBrush.lbHatch );
  134. }
  135. /* delte the brush object */
  136. DeleteObject( gdiCache.curBrush.handle );
  137. }
  138. /* remove the current pen selection if non-NULL and not a stock pen */
  139. if ((gdiCache.curPen.handle != NULL) && !gdiCache.curPen.stockObject)
  140. {
  141. DeleteObject( gdiCache.curPen.handle );
  142. }
  143. /* Remove other pens created at initialization time */
  144. DeleteObject( gdiCache.whitePen );
  145. DeleteObject( gdiCache.blackPen );
  146. /* deallocate the polygon buffer */
  147. GlobalUnlock( gdiCache.polyHandle );
  148. GlobalFree( gdiCache.polyHandle );
  149. } /* CaFini */
  150. void CaSetMetafileDefaults( void )
  151. /*========================*/
  152. /* Set up any defaults that will be used throughout the metafile context */
  153. {
  154. /* set up some metafile defaults */
  155. gdiCache.iniTextAlign = TA_LEFT | TA_BASELINE | TA_NOUPDATECP;
  156. gdiCache.iniROP2 = R2_COPYPEN;
  157. gdiCache.iniBkMode = TRANSPARENT;
  158. gdiCache.iniTxColor = RGB( 0, 0, 0 );
  159. gdiCache.iniBkColor = RGB( 255, 255, 255 );
  160. /* Put the records into the metafile */
  161. CaSetROP2( gdiCache.iniROP2 );
  162. CaSetTextAlign( gdiCache.iniTextAlign );
  163. CaSetBkMode( gdiCache.iniBkMode );
  164. CaSetTextColor( gdiCache.iniTxColor );
  165. CaSetBkColor( gdiCache.iniBkColor );
  166. } /* CaSetMetafileDefaults */
  167. void CaSamePrimitive( Boolean same )
  168. /*==================*/
  169. /* indicate whether next primitive is the same or new */
  170. {
  171. gdiCache.samePrim = same;
  172. } /* CaSamePrimitive */
  173. void CaMergePen( Word verb )
  174. /*=============*/
  175. /* indicate that next pen should be merged with previous logical pen */
  176. {
  177. if (gdiCache.nextPen.handle != NULL)
  178. {
  179. /* check to see if this is a NULL pen - the merge can happen */
  180. if (gdiCache.samePrim && verb == GdiFrame &&
  181. gdiCache.nextPen.handle == gdiCache.nulPen)
  182. {
  183. /* remove the cached pen - don't delte the pen object */
  184. gdiCache.nextPen.handle = NULL;
  185. }
  186. else
  187. {
  188. /* if not removing a null pen, then flush the cache. This will most
  189. often result in a line segment being flushed. */
  190. CaFlushCache();
  191. }
  192. }
  193. } /* CaMergePen */
  194. Word CaGetCachedPrimitive( void )
  195. /*=======================*/
  196. /* return the current cached primitive type */
  197. {
  198. return gdiCache.nextPrim.type;
  199. } /* CaGetCachedPrimitive */
  200. void CaCachePrimitive( CaPrimitiveLPtr primLPtr )
  201. /*===================*/
  202. /* Cache the primitive passed down. This includes the current pen and brush. */
  203. {
  204. /* not another line segment and/or not continuous - flush cache */
  205. CaFlushCache();
  206. /* save off the new primitive */
  207. gdiCache.nextPrim = *primLPtr;
  208. /* check if we need to copy over the polygon list, also */
  209. if ((gdiCache.nextPrim.type == CaPolygon) ||
  210. (gdiCache.nextPrim.type == CaPolyLine))
  211. {
  212. /* create new polygon */
  213. NewPolygon();
  214. /* add the polygon to the polygon buffer */
  215. while (gdiCache.nextPrim.a.poly.numPoints--)
  216. {
  217. AddPolyPt( *gdiCache.nextPrim.a.poly.pointList++);
  218. }
  219. }
  220. } /* CaCachePrimitive */
  221. void CaFlushCache( void )
  222. /*===============*/
  223. /* Flush the current primitive stored in the cache */
  224. {
  225. /* if the cache is empty, then just return - nothing to do */
  226. if (gdiCache.nextPrim.type == CaEmpty)
  227. {
  228. return;
  229. }
  230. /* select all cached attributes */
  231. CaFlushAttributes();
  232. /* emit any cached primitive, if necessary */
  233. switch (gdiCache.nextPrim.type)
  234. {
  235. case CaLine:
  236. {
  237. Rect clip;
  238. Point delta;
  239. Point offset;
  240. /* determine the length in both directions */
  241. delta.x = gdiCache.nextPrim.a.line.end.x - gdiCache.nextPrim.a.line.start.x;
  242. delta.y = gdiCache.nextPrim.a.line.end.y - gdiCache.nextPrim.a.line.start.y;
  243. /* set clipRect extents based upon current point position */
  244. clip.left = min( gdiCache.nextPrim.a.line.start.x, gdiCache.nextPrim.a.line.end.x );
  245. clip.top = min( gdiCache.nextPrim.a.line.start.y, gdiCache.nextPrim.a.line.end.y );
  246. clip.right = max( gdiCache.nextPrim.a.line.start.x, gdiCache.nextPrim.a.line.end.x );
  247. clip.bottom = max( gdiCache.nextPrim.a.line.start.y, gdiCache.nextPrim.a.line.end.y );
  248. /* extend clip rectangle for down-right pen stylus hang */
  249. clip.right += gdiCache.nextPrim.a.line.pnSize.x;
  250. clip.bottom += gdiCache.nextPrim.a.line.pnSize.y;
  251. /* determine the new starting and ending points */
  252. gdiCache.nextPrim.a.line.start.x -= delta.x;
  253. gdiCache.nextPrim.a.line.start.y -= delta.y;
  254. gdiCache.nextPrim.a.line.end.x += delta.x;
  255. gdiCache.nextPrim.a.line.end.y += delta.y;
  256. /* ajust the clipping rect for vertical line penSize roundoff? */
  257. if (delta.x == 0)
  258. {
  259. /* vertical line - expand clip in x dimension */
  260. clip.left--;
  261. }
  262. /* are we are adjusting pen by 1/2 metafile unit - roundoff error? */
  263. else if (gdiCache.nextPrim.a.line.pnSize.x & 0x01)
  264. {
  265. /* adjust clipping rectangle to clip the rounding error */
  266. clip.right--;
  267. }
  268. /* ajust the clipping rect for horizontal line penSize roundoff? */
  269. if (delta.y == 0)
  270. {
  271. /* horizontal line - extend clip in y dimension */
  272. clip.top--;
  273. }
  274. /* are we are adjusting pen by 1/2 metafile unit - roundoff error? */
  275. else if (gdiCache.nextPrim.a.line.pnSize.y & 0x01)
  276. {
  277. /* adjust clipping rectangle to clip the rounding error */
  278. clip.bottom--;
  279. }
  280. /* cut the size of the pen dimensions in half for offsets */
  281. offset.x = gdiCache.nextPrim.a.line.pnSize.x / 2;
  282. offset.y = gdiCache.nextPrim.a.line.pnSize.y / 2;
  283. /* set the new clipping rectangle */
  284. SaveDC( gdiCache.metafile );
  285. IntersectClipRect( gdiCache.metafile,
  286. clip.left, clip.top, clip.right, clip.bottom );
  287. /* move to the first point and draw to second (with padding) */
  288. // MoveTo is replaced by MoveToEx in win32
  289. #ifdef WIN32
  290. MoveToEx( gdiCache.metafile,
  291. gdiCache.nextPrim.a.line.start.x + offset.x,
  292. gdiCache.nextPrim.a.line.start.y + offset.y, NULL );
  293. #else
  294. MoveTo( gdiCache.metafile,
  295. gdiCache.nextPrim.a.line.start.x + offset.x,
  296. gdiCache.nextPrim.a.line.start.y + offset.y );
  297. #endif
  298. LineTo( gdiCache.metafile,
  299. gdiCache.nextPrim.a.line.end.x + offset.x,
  300. gdiCache.nextPrim.a.line.end.y + offset.y );
  301. /* restore the previous clipping rectangle */
  302. RestoreDC( gdiCache.metafile, -1 );
  303. break;
  304. }
  305. case CaRectangle:
  306. {
  307. if (gdiCache.curPen.handle == gdiCache.nulPen)
  308. {
  309. Point poly[5];
  310. /* set up the bounding coodinates */
  311. poly[0].x = poly[3].x = gdiCache.nextPrim.a.rect.bbox.left;
  312. poly[0].y = poly[1].y = gdiCache.nextPrim.a.rect.bbox.top;
  313. poly[1].x = poly[2].x = gdiCache.nextPrim.a.rect.bbox.right;
  314. poly[2].y = poly[3].y = gdiCache.nextPrim.a.rect.bbox.bottom;
  315. poly[4] = poly[0];
  316. /* perform call to render rectangle */
  317. Polygon( gdiCache.metafile, poly, 5 );
  318. }
  319. else
  320. {
  321. Rectangle( gdiCache.metafile,
  322. gdiCache.nextPrim.a.rect.bbox.left, gdiCache.nextPrim.a.rect.bbox.top,
  323. gdiCache.nextPrim.a.rect.bbox.right, gdiCache.nextPrim.a.rect.bbox.bottom );
  324. }
  325. break;
  326. }
  327. case CaRoundRect:
  328. {
  329. RoundRect( gdiCache.metafile,
  330. gdiCache.nextPrim.a.rect.bbox.left, gdiCache.nextPrim.a.rect.bbox.top,
  331. gdiCache.nextPrim.a.rect.bbox.right, gdiCache.nextPrim.a.rect.bbox.bottom,
  332. gdiCache.nextPrim.a.rect.oval.x, gdiCache.nextPrim.a.rect.oval.y );
  333. break;
  334. }
  335. case CaEllipse:
  336. {
  337. Ellipse( gdiCache.metafile,
  338. gdiCache.nextPrim.a.rect.bbox.left, gdiCache.nextPrim.a.rect.bbox.top,
  339. gdiCache.nextPrim.a.rect.bbox.right, gdiCache.nextPrim.a.rect.bbox.bottom );
  340. break;
  341. }
  342. case CaArc:
  343. {
  344. Arc( gdiCache.metafile,
  345. gdiCache.nextPrim.a.arc.bbox.left, gdiCache.nextPrim.a.arc.bbox.top,
  346. gdiCache.nextPrim.a.arc.bbox.right, gdiCache.nextPrim.a.arc.bbox.bottom,
  347. gdiCache.nextPrim.a.arc.start.x, gdiCache.nextPrim.a.arc.start.y,
  348. gdiCache.nextPrim.a.arc.end.x, gdiCache.nextPrim.a.arc.end.y );
  349. break;
  350. }
  351. case CaPie:
  352. {
  353. Pie( gdiCache.metafile,
  354. gdiCache.nextPrim.a.arc.bbox.left, gdiCache.nextPrim.a.arc.bbox.top,
  355. gdiCache.nextPrim.a.arc.bbox.right, gdiCache.nextPrim.a.arc.bbox.bottom,
  356. gdiCache.nextPrim.a.arc.start.x, gdiCache.nextPrim.a.arc.start.y,
  357. gdiCache.nextPrim.a.arc.end.x, gdiCache.nextPrim.a.arc.end.y );
  358. break;
  359. }
  360. case CaPolygon:
  361. case CaPolyLine:
  362. {
  363. Point offset;
  364. Integer i;
  365. /* see if centering of the pen is required */
  366. if (gdiCache.curPen.handle == gdiCache.nulPen)
  367. {
  368. /* no - just filling the object without frame */
  369. offset.x = offset.y = 0;
  370. }
  371. else
  372. {
  373. /* transform all points to correct for down-right pen
  374. rendering in QuickDraw and make for a GDI centered pen */
  375. offset.x = gdiCache.nextPrim.a.poly.pnSize.x / 2;
  376. offset.y = gdiCache.nextPrim.a.poly.pnSize.y / 2;
  377. }
  378. /* transform end point for all points in the polygon */
  379. for (i = 0; i < gdiCache.numPoints; i++)
  380. {
  381. /* increment each coordinate pair off half of the pen size */
  382. gdiCache.pointList[i].x += offset.x;
  383. gdiCache.pointList[i].y += offset.y;
  384. }
  385. /* call the appropriate GDI routine based upon the type */
  386. if (gdiCache.nextPrim.type == CaPolygon)
  387. {
  388. Polygon( gdiCache.metafile,
  389. gdiCache.pointList,
  390. gdiCache.numPoints );
  391. }
  392. else
  393. {
  394. Polyline( gdiCache.metafile,
  395. gdiCache.pointList,
  396. gdiCache.numPoints );
  397. }
  398. break;
  399. }
  400. }
  401. /* mark the primitive cache as empty */
  402. gdiCache.nextPrim.type = CaEmpty;
  403. } /* CaFlushCache */
  404. void CaFlushAttributes( void )
  405. /*====================*/
  406. /* flush any pending attribute elements */
  407. {
  408. /* select the cached pen - the routine will determine if one exits */
  409. SelectCachedPen();
  410. } /* CaFlushAttributes */
  411. void CaCreatePenIndirect( LOGPEN far * newLogPen )
  412. /*======================*/
  413. /* create a new pen */
  414. {
  415. PenLPtr compare;
  416. Boolean different;
  417. /* determine which pen to compare against */
  418. compare = (gdiCache.nextPen.handle != NULL) ? &gdiCache.nextPen :
  419. &gdiCache.curPen;
  420. /* compare the two pens */
  421. different = ((newLogPen->lopnStyle != compare->logPen.lopnStyle) ||
  422. (newLogPen->lopnColor != compare->logPen.lopnColor) ||
  423. (newLogPen->lopnWidth.x != compare->logPen.lopnWidth.x));
  424. /* if the pens are different ... */
  425. if (different)
  426. {
  427. /* if there is a cached pen ... */
  428. if (gdiCache.nextPen.handle != NULL)
  429. {
  430. /* flush the cached primitive - there is a change of pens */
  431. CaFlushCache();
  432. /* check to see if the new pen is changed by next selection */
  433. different = ((newLogPen->lopnStyle != gdiCache.curPen.logPen.lopnStyle) ||
  434. (newLogPen->lopnColor != gdiCache.curPen.logPen.lopnColor) ||
  435. (newLogPen->lopnWidth.x != gdiCache.curPen.logPen.lopnWidth.x));
  436. }
  437. }
  438. /* if the pen has changed from the current setting, cache the next pen */
  439. if (different || gdiCache.curPen.handle == NULL)
  440. {
  441. /* if there is a pending line or polyline, the flush the cache */
  442. if (gdiCache.nextPrim.type == CaLine || gdiCache.nextPrim.type == CaPolyLine)
  443. {
  444. CaFlushCache();
  445. }
  446. /* assign the new pen attributes */
  447. gdiCache.nextPen.logPen = *newLogPen;
  448. /* currently not using a stock pen object */
  449. gdiCache.nextPen.stockObject = FALSE;
  450. /* check for any pre-defined pen objects */
  451. if (gdiCache.nextPen.logPen.lopnStyle == PS_NULL)
  452. {
  453. /* and use them if possible */
  454. gdiCache.nextPen.handle = gdiCache.nulPen;
  455. gdiCache.nextPen.stockObject = TRUE;
  456. }
  457. else if (gdiCache.nextPen.logPen.lopnWidth.x == 1)
  458. {
  459. if (newLogPen->lopnColor == RGB( 0, 0, 0 ))
  460. {
  461. gdiCache.nextPen.handle = gdiCache.blackPen;
  462. gdiCache.nextPen.stockObject = TRUE;
  463. }
  464. else if (gdiCache.nextPen.logPen.lopnColor == RGB( 255, 255, 255 ))
  465. {
  466. gdiCache.nextPen.handle = gdiCache.whitePen;
  467. gdiCache.nextPen.stockObject = TRUE;
  468. }
  469. }
  470. if (!gdiCache.nextPen.stockObject)
  471. {
  472. /* otherwise, create a new pen */
  473. gdiCache.nextPen.handle = CreatePenIndirect( &gdiCache.nextPen.logPen );
  474. }
  475. }
  476. else
  477. {
  478. /* copy the current setting back into the next pen setting */
  479. gdiCache.nextPen = gdiCache.curPen;
  480. }
  481. /* check if cache was invalidated */
  482. if (gdiCache.restorePen && (gdiCache.curPen.handle != NULL))
  483. {
  484. /* if pen was invalidated by RestoreDC(), reselect it */
  485. SelectObject( gdiCache.metafile, gdiCache.curPen.handle );
  486. }
  487. /* all is ok with cache now */
  488. gdiCache.restorePen = FALSE;
  489. } /* CaCreatePenIndirect */
  490. void CaCreateBrushIndirect( LOGBRUSH far * newLogBrush )
  491. /*========================*/
  492. /* Create a new logical brush using structure passed in */
  493. {
  494. /* assume that the DIB patterns are different */
  495. Boolean differentDIB = TRUE;
  496. /* check if we are comparing two DIB patterned brushes */
  497. if ((newLogBrush->lbStyle == BS_DIBPATTERN) &&
  498. (gdiCache.curBrush.logBrush.lbStyle == BS_DIBPATTERN))
  499. {
  500. Word nextSize = (Word)GlobalSize( (HANDLE) newLogBrush->lbHatch ) / 2;
  501. Word currSize = (Word)GlobalSize( (HANDLE) gdiCache.curBrush.logBrush.lbHatch ) / 2;
  502. /* make sure that the sizes are the same */
  503. if (nextSize == currSize)
  504. {
  505. Word far * nextDIBPattern = (Word far *)GlobalLock( (HANDLE) newLogBrush->lbHatch );
  506. Word far * currDIBPattern = (Word far *)GlobalLock( (HANDLE) gdiCache.curBrush.logBrush.lbHatch );
  507. /* assume that the DIBs are the same so far */
  508. differentDIB = FALSE;
  509. /* compare all the bytes in the two brush patterns */
  510. while (currSize--)
  511. {
  512. /* are they the same ? */
  513. if (*nextDIBPattern++ != *currDIBPattern++)
  514. {
  515. /* if not, flag the difference and break from the loop */
  516. differentDIB = TRUE;
  517. break;
  518. }
  519. }
  520. /* Unlock the data blocks */
  521. GlobalUnlock( (HANDLE) newLogBrush->lbHatch );
  522. GlobalUnlock( (HANDLE) gdiCache.curBrush.logBrush.lbHatch );
  523. /* see if these did compare exactly */
  524. if (!differentDIB)
  525. {
  526. /* if so, free the new DIB brush - it's no longer needed */
  527. GlobalFree( (HANDLE) newLogBrush->lbHatch );
  528. }
  529. }
  530. }
  531. /* see if we are requesting a new brush */
  532. if (differentDIB &&
  533. (newLogBrush->lbStyle != gdiCache.curBrush.logBrush.lbStyle ||
  534. newLogBrush->lbColor != gdiCache.curBrush.logBrush.lbColor ||
  535. newLogBrush->lbHatch != gdiCache.curBrush.logBrush.lbHatch ||
  536. gdiCache.curBrush.handle == NULL))
  537. {
  538. HBRUSH brushHandle = NULL;
  539. Boolean stockBrush;
  540. /* flush the primitive cache if changing brush selection */
  541. CaFlushCache();
  542. /* if current brush has a DIB, make sure to free memory */
  543. if (gdiCache.curBrush.logBrush.lbStyle == BS_DIBPATTERN)
  544. {
  545. /* free the memory */
  546. GlobalFree( (HANDLE) gdiCache.curBrush.logBrush.lbHatch );
  547. }
  548. /* copy over the new structure */
  549. gdiCache.curBrush.logBrush = *newLogBrush;
  550. /* We currently aren't using a stock brush */
  551. stockBrush = FALSE;
  552. /* use stock objects if possible */
  553. if (gdiCache.curBrush.logBrush.lbStyle == BS_HOLLOW)
  554. {
  555. /* use null (hollow) brush */
  556. brushHandle = gdiCache.nulBrush;
  557. stockBrush = TRUE;
  558. }
  559. /* check for some standard solid colored brushes */
  560. else if (gdiCache.curBrush.logBrush.lbStyle == BS_SOLID)
  561. {
  562. if (gdiCache.curBrush.logBrush.lbColor == RGB( 0, 0, 0) )
  563. {
  564. /* use solid black brush */
  565. brushHandle = gdiCache.blackBrush;
  566. stockBrush = TRUE;
  567. }
  568. else if (gdiCache.curBrush.logBrush.lbColor == RGB( 255, 255, 255 ))
  569. {
  570. /* use solid white brush */
  571. brushHandle = gdiCache.whiteBrush;
  572. stockBrush = TRUE;
  573. }
  574. }
  575. /* if unable to find a stock brush, then create a new one */
  576. if (!stockBrush)
  577. {
  578. /* otherwise, create new brush using logbrush structure */
  579. brushHandle = CreateBrushIndirect( &gdiCache.curBrush.logBrush );
  580. }
  581. /* select the new brush */
  582. SelectObject( gdiCache.metafile, brushHandle );
  583. /* if this isn't the first brush selection and not a stock brush */
  584. if (gdiCache.curBrush.handle != NULL && !gdiCache.curBrush.stockObject)
  585. {
  586. /* delete the previous brush object */
  587. DeleteObject( gdiCache.curBrush.handle );
  588. }
  589. /* save brush handle in current cache variable */
  590. gdiCache.curBrush.handle = brushHandle;
  591. gdiCache.curBrush.stockObject = stockBrush;
  592. }
  593. else if (gdiCache.restoreBrush)
  594. {
  595. /* if brush was invalidated by RestoreDC(), reselect it */
  596. SelectObject( gdiCache.metafile, gdiCache.curBrush.handle );
  597. }
  598. /* all is ok with cache now */
  599. gdiCache.restoreBrush = FALSE;
  600. } /* CaCreateBrushIndirect */
  601. void CaCreateFontIndirect( LOGFONT far * newLogFont )
  602. /*=======================*/
  603. /* create the logical font passed as paramter */
  604. {
  605. /* make sure we are requesting a new font */
  606. if (newLogFont->lfHeight != gdiCache.curLogFont.lfHeight ||
  607. newLogFont->lfWeight != gdiCache.curLogFont.lfWeight ||
  608. newLogFont->lfEscapement != gdiCache.curLogFont.lfEscapement ||
  609. newLogFont->lfOrientation != gdiCache.curLogFont.lfOrientation ||
  610. newLogFont->lfItalic != gdiCache.curLogFont.lfItalic ||
  611. newLogFont->lfUnderline != gdiCache.curLogFont.lfUnderline ||
  612. newLogFont->lfPitchAndFamily != gdiCache.curLogFont.lfPitchAndFamily ||
  613. lstrcmp( newLogFont->lfFaceName, gdiCache.curLogFont.lfFaceName ) != 0 ||
  614. gdiCache.curFont == NULL)
  615. {
  616. HFONT fontHandle;
  617. Boolean stockFont;
  618. /* flush the primitive cache if changing font attributes */
  619. CaFlushCache();
  620. /* assign the new pen attributes */
  621. gdiCache.curLogFont = *newLogFont;
  622. /* currently not using a stock font object */
  623. stockFont = FALSE;
  624. /* check for any pre-defined pen objects */
  625. if (newLogFont->lfFaceName == NULL)
  626. {
  627. fontHandle = GetStockObject( SYSTEM_FONT );
  628. stockFont = TRUE;
  629. }
  630. else
  631. {
  632. /* otherwise, create a new pen */
  633. fontHandle = CreateFontIndirect( &gdiCache.curLogFont );
  634. }
  635. /* select the new font */
  636. SelectObject( gdiCache.metafile, fontHandle );
  637. /* if this isn't the first font selection and not a stock font */
  638. if (gdiCache.curFont != NULL && !gdiCache.stockFont)
  639. {
  640. /* delete the previous font object */
  641. DeleteObject( gdiCache.curFont );
  642. }
  643. /* save font handle in current cache variable */
  644. gdiCache.curFont = fontHandle;
  645. gdiCache.stockFont = stockFont;
  646. }
  647. else if (gdiCache.restoreFont)
  648. {
  649. /* if pen was invalidated by RestoreDC(), reselect it */
  650. SelectObject( gdiCache.metafile, gdiCache.curFont );
  651. }
  652. /* all is ok with cache now */
  653. gdiCache.restoreFont = FALSE;
  654. } /* CaCreateFontIndirect */
  655. void CaSetBkMode( Word mode )
  656. /*==============*/
  657. /* set the backgound transfer mode */
  658. {
  659. if (gdiCache.curBkMode != mode)
  660. {
  661. /* flush the primitive cache if changing mode */
  662. CaFlushCache();
  663. /* set the background mode and save in global cache */
  664. SetBkMode( gdiCache.metafile, mode );
  665. gdiCache.curBkMode = mode;
  666. }
  667. /* no need to worry about restoring BkMode, since this is set
  668. before the initial SaveDC() is issued and is restored after each
  669. RestoreDC() call back to the metafile default. */
  670. } /* CaSetBkMode */
  671. void CaSetROP2( Word ROP2Code )
  672. /*============*/
  673. /* set the transfer ROP mode according to ROP2Code */
  674. {
  675. /* check for change in ROP code */
  676. if (gdiCache.curROP2 != ROP2Code)
  677. {
  678. /* flush the primitive cache if changing ROP mode */
  679. CaFlushCache();
  680. /* set the ROP code and save in global cache variable */
  681. SetROP2( gdiCache.metafile, ROP2Code );
  682. gdiCache.curROP2 = ROP2Code;
  683. }
  684. /* no need to worry about restoring ROP code, since this is set
  685. before the initial SaveDC() is issued and is restored after each
  686. RestoreDC() call back to the metafile default. */
  687. } /* CaSetROP2 */
  688. void CaSetStretchBltMode( Word mode )
  689. /*======================*/
  690. /* stretch blt mode - how to preserve scanlines using StretchDIBits() */
  691. {
  692. if (gdiCache.curStretchMode != mode)
  693. {
  694. /* flush the primitive cache if changing mode */
  695. CaFlushCache();
  696. /* set the stretch blt mode and save in global cache variable */
  697. SetStretchBltMode( gdiCache.metafile, mode );
  698. gdiCache.curStretchMode = mode;
  699. }
  700. else if (gdiCache.restoreStretchMode)
  701. {
  702. /* if stretch blt mode was invalidated by RestoreDC(), re-issue */
  703. SetStretchBltMode( gdiCache.metafile, gdiCache.curStretchMode );
  704. }
  705. /* all is ok with cache now */
  706. gdiCache.restoreStretchMode = FALSE;
  707. } /* CaSetStretchBltMode */
  708. void CaSetTextAlign( Word txtAlign )
  709. /*=================*/
  710. /* set text alignment according to parameter */
  711. {
  712. if (gdiCache.curTextAlign != txtAlign)
  713. {
  714. /* flush the primitive cache if changing text alignment */
  715. CaFlushCache();
  716. /* Set the text color and save in cache */
  717. SetTextAlign( gdiCache.metafile, txtAlign );
  718. gdiCache.curTextAlign = txtAlign;
  719. }
  720. /* no need to worry about restoring text align, since this is set
  721. before the initial SaveDC() is issued and is restored after each
  722. RestoreDC() call back to the metafile default. */
  723. } /* CaSetTextAlign */
  724. void CaSetTextColor( RGBColor txtColor )
  725. /*=================*/
  726. /* set the text color if different from current setting */
  727. {
  728. if (gdiCache.curTextColor != txtColor)
  729. {
  730. /* flush the primitive cache if changing text color */
  731. CaFlushCache();
  732. /* Set the text color and save in cache */
  733. SetTextColor( gdiCache.metafile, txtColor );
  734. gdiCache.curTextColor = txtColor;
  735. }
  736. /* no need to worry about restoring text color, since this is set
  737. before the initial SaveDC() is issued and is restored after each
  738. RestoreDC() call back to the metafile default. */
  739. } /* CaSetTextColor */
  740. void CaSetTextCharacterExtra( Integer chExtra )
  741. /*==========================*/
  742. /* set the character extra spacing */
  743. {
  744. if (gdiCache.curCharExtra != chExtra)
  745. {
  746. /* flush the primitive cache if changing text char extra */
  747. CaFlushCache();
  748. /* set the char extra and same state in the cache */
  749. SetTextCharacterExtra( gdiCache.metafile, chExtra );
  750. gdiCache.curCharExtra = (WORD) chExtra;
  751. }
  752. else if (gdiCache.restoreCharExtra)
  753. {
  754. /* if text char extra was invalidated by RestoreDC(), re-issue */
  755. SetTextCharacterExtra( gdiCache.metafile, gdiCache.curCharExtra );
  756. }
  757. /* all is ok with cache now */
  758. gdiCache.restoreCharExtra = FALSE;
  759. } /* CaSetTextCharacterExtra */
  760. void CaSetBkColor( RGBColor bkColor )
  761. /*===============*/
  762. /* set background color if different from current setting */
  763. {
  764. if (gdiCache.curBkColor != bkColor)
  765. {
  766. /* flush the primitive cache if changing background color */
  767. CaFlushCache();
  768. /* Set the background color and save in cache */
  769. SetBkColor( gdiCache.metafile, bkColor );
  770. gdiCache.curBkColor = bkColor;
  771. }
  772. /* no need to worry about restoring background color, since this is set
  773. before the initial SaveDC() is issued and is restored after each
  774. RestoreDC() call back to the metafile default. */
  775. } /* CaSetBkColor */
  776. Boolean CaIntersectClipRect( Rect rect )
  777. /*=========================*/
  778. /* Create new clipping rectangle - return FALSE if drawing is disabled */
  779. {
  780. Rect combinedRect;
  781. /* See if the clipping rectangle is empty, indicating that no drawing
  782. should occur into the metafile */
  783. if (Height( rect ) == 0 || Width( rect ) == 0)
  784. {
  785. /* indicate that drawing is disabled */
  786. return FALSE;
  787. }
  788. /* don't do anything if rectangle hasn't changed */
  789. if (!EqualRect( &rect, &gdiCache.curClipRect ) || gdiCache.forceNewClipRect)
  790. {
  791. /* flush the primitive cache if changing clip region */
  792. CaFlushCache();
  793. /* is new clip rect is completely enclosed by current cliprect? */
  794. IntersectRect( &combinedRect, &rect, &gdiCache.curClipRect );
  795. /* check for equality of intersection and new cliprect */
  796. if (!EqualRect( &combinedRect, &rect ) || gdiCache.forceNewClipRect)
  797. {
  798. /* must be called just to be able to change clipping rectangle */
  799. CaRestoreDC();
  800. CaSaveDC();
  801. }
  802. /* set the new clipping rectangle */
  803. IntersectClipRect( gdiCache.metafile,
  804. rect.left, rect.top, rect.right, rect.bottom );
  805. /* save the current clip rectangle, since it has changed */
  806. gdiCache.curClipRect = rect;
  807. /* turn off forcing of the clipping rectangle */
  808. gdiCache.forceNewClipRect = FALSE;
  809. }
  810. /* return TRUE - drawing is enabled */
  811. return TRUE;
  812. } /* GdiIntersectClipRect */
  813. void CaSetClipRect( Rect rect )
  814. /*================*/
  815. /* set the current cliprectangle to be equal to rect */
  816. {
  817. gdiCache.curClipRect = rect;
  818. } /* CaSetClipRect */
  819. Rect far * CaGetClipRect( void )
  820. /*=====================*/
  821. /* get the current cliprectangle */
  822. {
  823. return &gdiCache.curClipRect;
  824. } /* CaGetClipRect */
  825. void CaNonRectangularClip( void )
  826. /*=======================*/
  827. /* notify cache that a non-rectangular clipping region was set */
  828. {
  829. gdiCache.forceNewClipRect = TRUE;
  830. } /* CaNonRectangularClip */
  831. void CaSaveDC( void )
  832. /*===========*/
  833. /* save the current device context - used to set up clipping rects */
  834. {
  835. /* the previous clipping rectangle is saved off */
  836. gdiCache.prevClipRect = gdiCache.curClipRect;
  837. /* issue call to GDI */
  838. SaveDC( gdiCache.metafile );
  839. }
  840. void CaRestoreDC( void )
  841. /*==============*/
  842. /* restore the device context and invalidate cached attributes */
  843. {
  844. /* restore previous clipping rectangle */
  845. gdiCache.curClipRect = gdiCache.prevClipRect;
  846. /* invalidate all of the cached attributes and objects */
  847. gdiCache.restorePen =
  848. gdiCache.restoreBrush =
  849. gdiCache.restoreFont =
  850. gdiCache.restoreCharExtra = TRUE;
  851. /* reset metafile defaults */
  852. gdiCache.curROP2 = gdiCache.iniROP2;
  853. gdiCache.curTextAlign = gdiCache.iniTextAlign;
  854. gdiCache.curBkMode = gdiCache.iniBkMode;
  855. gdiCache.curTextColor = gdiCache.iniTxColor;
  856. gdiCache.curBkColor = gdiCache.iniBkColor;
  857. /* issue call to GDI */
  858. RestoreDC( gdiCache.metafile, -1 );
  859. }
  860. /******************************* Private Routines ***************************/
  861. private void AddPolyPt( Point pt )
  862. /*--------------------*/
  863. /* Add a point to the polygon buffer */
  864. {
  865. HANDLE tmpHandle;
  866. /* make sure that we haven't reached maximum size */
  867. if ((gdiCache.numPoints + 1) >= gdiCache.maxPoints)
  868. {
  869. /* expand the number of points that can be cached by 10 */
  870. gdiCache.maxPoints += 16;
  871. /* unlock to prepare for re-allocation */
  872. GlobalUnlock( gdiCache.polyHandle);
  873. /* re-allocate the memory handle by the given amount */
  874. /* save current ptr so it can be freed if GlobalReAlloc fails */
  875. tmpHandle = GlobalReAlloc(
  876. gdiCache.polyHandle,
  877. gdiCache.maxPoints * sizeof( Point ),
  878. GMEM_MOVEABLE);
  879. /* make sure that the re-allocation succeeded */
  880. if (tmpHandle == NULL)
  881. {
  882. /* if not, free the old memory, flag global error and exit from here */
  883. GlobalFree(gdiCache.polyHandle);
  884. gdiCache.polyHandle = NULL;
  885. ErSetGlobalError( ErMemoryFull );
  886. return;
  887. }
  888. gdiCache.polyHandle = tmpHandle;
  889. /* lock the memory handle to get a pointer address */
  890. gdiCache.pointList = (Point far *)GlobalLock( gdiCache.polyHandle );
  891. }
  892. /* insert the new point and increment the number of points in the buffer */
  893. gdiCache.pointList[gdiCache.numPoints++] = pt;
  894. } /* AddPolyPt */
  895. private void SelectCachedPen( void )
  896. /*--------------------------*/
  897. /* select the currently cached Pen into the metafile */
  898. {
  899. /* make sure that there is some new pen to select */
  900. if (gdiCache.nextPen.handle != NULL)
  901. {
  902. /* make sure that the pens are different */
  903. if (gdiCache.nextPen.handle != gdiCache.curPen.handle)
  904. {
  905. /* select the new pen */
  906. SelectObject( gdiCache.metafile, gdiCache.nextPen.handle);
  907. /* if this isn't the first pen selection and not a stock pen */
  908. if (gdiCache.curPen.handle != NULL && !gdiCache.curPen.stockObject)
  909. {
  910. /* delete the previous pen selection */
  911. DeleteObject( gdiCache.curPen.handle );
  912. }
  913. /* save pen handle in current cache variable */
  914. gdiCache.curPen = gdiCache.nextPen;
  915. }
  916. /* reset the cache pen to indicate no pre-existing cached pen */
  917. gdiCache.nextPen.handle = NULL;
  918. }
  919. } /* SelectCachedPen */