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.

1445 lines
41 KiB

  1. /*++
  2. Copyright (c) 1990-2003 Microsoft Corporation
  3. Module Name:
  4. textout.c
  5. Abstract:
  6. This module contains the DrvTextOut entry point. This is the main routine
  7. called by the NT graphics engine in order to get text rendered on the
  8. target device. This implementation handles both drawing device paths that
  9. represent the glyphs of the STROBJ (the line of text to output), as well
  10. as outputing bitmaps that represent the glyphs on devices that can
  11. handle raster output.
  12. Author:
  13. Written by AP on 8/17/92.
  14. 15-Nov-1993 Mon 19:43:58 updated
  15. clean up / fixed / add debugging information
  16. [Environment:]
  17. GDI Device Driver - Plotter.
  18. [Notes:]
  19. Revision History:
  20. --*/
  21. #include "precomp.h"
  22. #pragma hdrstop
  23. #define DBG_PLOTFILENAME DbgTextOut
  24. #define DBG_GETGLYPHMODE 0x00000001
  25. #define DBG_TEXTOUT 0x00000002
  26. #define DBG_TEXTOUT1 0x00000004
  27. #define DBG_TEXTOUT2 0x00000008
  28. #define DBG_DRAWLINE 0x00000010
  29. #define DBG_TRUETYPE 0x00000020
  30. #define DBG_TRUETYPE1 0x00000040
  31. #define DBG_TRUETYPE2 0x00000080
  32. #define DBG_BMPFONT 0x00000100
  33. #define DBG_BMPTEXTCLR 0x00000200
  34. #define DBG_DEFCHARINC 0x00000400
  35. #define DBG_SET_FONTTYPE 0x20000000
  36. #define DBG_SHOWRASFONT 0x40000000
  37. #define DBG_NO_RASTER_FONT 0x80000000
  38. DEFINE_DBGVAR(0);
  39. extern PALENTRY HTPal[];
  40. DWORD
  41. DrvGetGlyphMode(
  42. DHPDEV dhpdev,
  43. FONTOBJ *pfo
  44. )
  45. /*++
  46. Routine Description:
  47. Asks the driver what sort of font information should be cached for a
  48. particular font. For remote printer devices, this determines the format
  49. that gets spooled. For local devices, this determines what GDI stores in
  50. its font cache. This call will be made for each particular font
  51. realization.
  52. Arguments:
  53. dhpdev - Pointer to our PDEV
  54. pfo - Pointer to the font object
  55. Return Value:
  56. DWORD as FO_xxxx
  57. Author:
  58. 27-Jan-1994 Thu 12:51:59 created
  59. 10-Mar-1994 Thu 00:36:30 updated
  60. Re-write, so we will pre-examine the Font type, source and its
  61. technology together with PDEV setting to let engine know which type of
  62. the font output we are interested in the DrvTextOut(). Currently this
  63. is broken in GDI which caused a GP in winsrv. (this is why a
  64. DBG_SET_FONTTYPE switch is on by default)
  65. Revision History:
  66. --*/
  67. {
  68. #define pPDev ((PPDEV)dhpdev)
  69. PIFIMETRICS pifi;
  70. DWORD FOType;
  71. PLOTDBG(DBG_GETGLYPHMODE, ("DrvGetGlyphMode: Type=%08lx, cxMax=%ld",
  72. pfo->flFontType, pfo->cxMax));
  73. //
  74. // If we cannot get the IFI metrics for the passed FONTOBJ, only
  75. // ask for PATHS.
  76. //
  77. if (!(pifi = FONTOBJ_pifi(pfo))) {
  78. PLOTERR(("DrvGetGlyphMode: FONTOBJ_pifi()=NULL, return FO_PATHOBJ"));
  79. return(FO_PATHOBJ);
  80. }
  81. FOType = FO_PATHOBJ;
  82. //
  83. // If its a bitmap font, ask for BITS
  84. //
  85. if (pifi->flInfo & FM_INFO_TECH_BITMAP) {
  86. PLOTDBG(DBG_GETGLYPHMODE, ("DrvGetGlyphMode: BITMAP FONT, return FO_GLYPHBITS"));
  87. FOType = FO_GLYPHBITS;
  88. } else if (pifi->flInfo & FM_INFO_TECH_STROKE) {
  89. PLOTDBG(DBG_GETGLYPHMODE, ("DrvGetGlyphMode: STROKE (Vector) FONT, return FO_PATHOBJ"));
  90. } else if (pifi->flInfo & FM_INFO_RETURNS_BITMAPS) {
  91. //
  92. // Now make a decision on whether to ask for glyphbits or paths.
  93. // This decision is based on the target device being raster, that
  94. // bitmap fonts are okay to use, and that the threshold for doing
  95. // raster fonts versus paths is met.
  96. //
  97. DWORD cxBMFontMax = (DWORD)pPDev->pPlotGPC->RasterXDPI;
  98. if (pPDev->PlotDM.dm.dmPrintQuality == DMRES_HIGH) {
  99. cxBMFontMax <<= 3;
  100. } else {
  101. cxBMFontMax >>= 2;
  102. }
  103. PLOTDBG(DBG_GETGLYPHMODE,
  104. ("DrvGetGlyphMode: Font CAN return BITMAP, cxBMFontMax=%ld",
  105. cxBMFontMax));
  106. #if DBG
  107. if ((!(DBG_PLOTFILENAME & DBG_NO_RASTER_FONT)) &&
  108. (IS_RASTER(pPDev)) &&
  109. (!NO_BMP_FONT(pPDev)) &&
  110. (pfo->cxMax <= cxBMFontMax)) {
  111. #else
  112. if ((IS_RASTER(pPDev)) &&
  113. (!NO_BMP_FONT(pPDev)) &&
  114. (pfo->cxMax <= cxBMFontMax)) {
  115. #endif
  116. PLOTDBG(DBG_GETGLYPHMODE, ("DrvGetGlyphMode: Convert to BITMAP FONT, FO_GLYPHBITS"));
  117. FOType = FO_GLYPHBITS;
  118. } else {
  119. PLOTDBG(DBG_GETGLYPHMODE, ("DrvGetGlyphMode: Return as FO_PATHOBJ"));
  120. }
  121. } else if (pifi->flInfo & FM_INFO_RETURNS_OUTLINES) {
  122. PLOTDBG(DBG_GETGLYPHMODE, ("DrvGetGlyphMode: Font CAN return OUTLINES"));
  123. } else if (pifi->flInfo & FM_INFO_RETURNS_STROKES) {
  124. PLOTDBG(DBG_GETGLYPHMODE, ("DrvGetGlyphMode: Font CAN return STROKES"));
  125. }
  126. #if DBG
  127. if (DBG_PLOTFILENAME & DBG_SET_FONTTYPE) {
  128. if ((FOType == FO_GLYPHBITS) &&
  129. (!(pfo->flFontType & FO_TYPE_RASTER))) {
  130. PLOTWARN(("DrvGetGlyphMode: Set FontType to RASTER"));
  131. pfo->flFontType &= ~(FO_TYPE_TRUETYPE | FO_TYPE_DEVICE);
  132. pfo->flFontType |= FO_TYPE_RASTER;
  133. }
  134. }
  135. #endif
  136. return(FOType);
  137. #undef pPDev
  138. }
  139. BOOL
  140. BitmapTextOut(
  141. PPDEV pPDev,
  142. STROBJ *pstro,
  143. FONTOBJ *pfo,
  144. PRECTL pClipRect,
  145. LPDWORD pOHTFlags,
  146. DWORD Rop3
  147. )
  148. /*++
  149. Routine Description:
  150. This routine outputs the passed STROBJ with bitmaps that represent
  151. each of the glyphs, rather than converting the glyphs to paths that
  152. will be filled in the target device.
  153. Arguments:
  154. pPDev - Pointer to our PDEV
  155. pstro - We pass a string object to be drawn
  156. pfo - Pointer to the FONTOBJ
  157. pClipRect - Current enumerated clipping rectangle
  158. pOHTFlags - Pointer to the current OutputHTBitmap() flags
  159. Rop3 - Rop3 to be used in the device
  160. Return Value:
  161. TRUE/FALSE
  162. Author:
  163. 18-Feb-1994 Fri 12:41:57 updated
  164. change that so if pfo=NULL then the font already in BITMAP format
  165. 14-Feb-1994 Mon 18:16:25 create
  166. Revision History:
  167. --*/
  168. {
  169. GLYPHPOS *pgp;
  170. GLYPHBITS *pgb;
  171. SURFOBJ soGlyph;
  172. POINTL ptlCur;
  173. SIZEL sizlInc;
  174. RECTL rclSrc;
  175. RECTL rclDst;
  176. BOOL MoreGlyphs;
  177. BOOL Ok;
  178. BOOL FirstCh;
  179. ULONG cGlyphs;
  180. //
  181. // The public fields of SURFOBJ is what will be used by OutputHTBitmap
  182. // instead of actually creating a SURFOBJ from the graphics engine. This
  183. // is a safe thing to do, since only we look at these fields.
  184. //
  185. ZeroMemory(&soGlyph, sizeof(SURFOBJ));
  186. soGlyph.dhsurf = (DHSURF)'PLOT';
  187. soGlyph.hsurf = (HSURF)'TEXT';
  188. soGlyph.dhpdev = (DHPDEV)pPDev;
  189. soGlyph.iBitmapFormat = BMF_1BPP;
  190. soGlyph.iType = STYPE_BITMAP;
  191. soGlyph.fjBitmap = BMF_TOPDOWN;
  192. //
  193. // We will now enumerate each of the glyphs in the STROBJ such that
  194. // we can image them. If the STROBJ has a non NULL pgp field, this means
  195. // that the GLYPH definitions are already available, and no enumeration
  196. // is required. If not, we will make a sequence of calls to STROBJ_bEnum
  197. // (an engine helper) to enumerate the glyphs. The actual imaging code
  198. // is the same, regardless of the stat of STROBJ->pgp
  199. //
  200. if (pstro->pgp) {
  201. pgp = pstro->pgp;
  202. MoreGlyphs = FALSE;
  203. cGlyphs = pstro->cGlyphs;
  204. PLOTDBG(DBG_BMPFONT, ("BitmapTextOut: Character info already there (%ld glyphs)", cGlyphs));
  205. } else {
  206. STROBJ_vEnumStart(pstro);
  207. MoreGlyphs = TRUE;
  208. PLOTDBG(DBG_BMPFONT, ("BitmapTextOut: STROBJ enub"));
  209. }
  210. //
  211. // Now straring drawing the glyphs, if we have MoreGlyphs = TRUE then we
  212. // will initially do a STROBJ_bEnum first to initialize enumeration of
  213. // the glyphs
  214. //
  215. Ok = TRUE;
  216. Rop3 &= 0xFF;
  217. sizlInc.cx =
  218. sizlInc.cy = 0;
  219. FirstCh = TRUE;
  220. do {
  221. //
  222. // Verify the job is not aborting, if it is break out now.
  223. //
  224. if (PLOT_CANCEL_JOB(pPDev)) {
  225. break;
  226. }
  227. //
  228. // Check to see if we need to do an enumeration and start it if
  229. // it is required.
  230. //
  231. if (MoreGlyphs) {
  232. MoreGlyphs = STROBJ_bEnum(pstro, &cGlyphs, &pgp);
  233. if (MoreGlyphs == DDI_ERROR) {
  234. PLOTERR(("DrvTextOut: STROBJ_bEnum()=DDI_ERROR"));
  235. return(FALSE);
  236. }
  237. }
  238. PLOTDBG(DBG_BMPFONT,
  239. ("BitmapTextOut: New batch of cGlyphs=%d", cGlyphs));
  240. //
  241. // Get the first character position
  242. //
  243. if ((FirstCh) && (cGlyphs)) {
  244. ptlCur = pgp->ptl;
  245. FirstCh = FALSE;
  246. }
  247. //
  248. // Start sending each bitmap to the device
  249. //
  250. for ( ; (Ok) && (cGlyphs--); pgp++) {
  251. GLYPHDATA gd;
  252. GLYPHDATA *pgd;
  253. if (PLOT_CANCEL_JOB(pPDev)) {
  254. break;
  255. }
  256. if (pfo) {
  257. //
  258. // This is true type font, so query the bitmap
  259. //
  260. pgd = &gd;
  261. if (FONTOBJ_cGetGlyphs(pfo,
  262. FO_GLYPHBITS,
  263. 1,
  264. &(pgp->hg),
  265. (LPVOID)&pgd) != 1) {
  266. PLOTERR(("BitmapTextOut: FONTOBJ_cGetGlyphs() FAILED"));
  267. return(FALSE);
  268. }
  269. pgb = pgd->gdf.pgb;
  270. } else {
  271. //
  272. // For bitmap font, we already have the bitmap
  273. //
  274. pgb = pgp->pgdf->pgb;
  275. }
  276. //
  277. // Get the size of the bitmap
  278. //
  279. soGlyph.sizlBitmap = pgb->sizlBitmap;
  280. //
  281. // Compute new destination position for the text, based on the
  282. // passed accelerators.
  283. //
  284. if (pstro->ulCharInc) {
  285. sizlInc.cx =
  286. sizlInc.cy = (LONG)pstro->ulCharInc;
  287. } else if (pstro->flAccel & SO_CHAR_INC_EQUAL_BM_BASE) {
  288. sizlInc = soGlyph.sizlBitmap;
  289. } else {
  290. ptlCur = pgp->ptl;
  291. }
  292. if (!(pstro->flAccel & SO_HORIZONTAL)) {
  293. sizlInc.cx = 0;
  294. }
  295. if (!(pstro->flAccel & SO_VERTICAL)) {
  296. sizlInc.cy = 0;
  297. }
  298. if (pstro->flAccel & SO_REVERSED) {
  299. sizlInc.cx = -sizlInc.cx;
  300. sizlInc.cy = -sizlInc.cy;
  301. }
  302. //
  303. // The pgp->ptl informs us where to position the glyph origin in
  304. // the device surface, and pgb->ptlOrigin informs us of the
  305. // relationship between character origin and bitmap origin. For
  306. // example, if (2,-24) is passed in as the character origin, then
  307. // we would need to reposition rclDst.left right 2 pixels and
  308. // rclDst.top up 24 pixels.
  309. //
  310. rclDst.left = ptlCur.x + pgb->ptlOrigin.x;
  311. rclDst.top = ptlCur.y + pgb->ptlOrigin.y;
  312. rclDst.right = rclDst.left + soGlyph.sizlBitmap.cx;
  313. rclDst.bottom = rclDst.top + soGlyph.sizlBitmap.cy;
  314. ptlCur.x += sizlInc.cx;
  315. ptlCur.y += sizlInc.cy;
  316. //
  317. // NOTE: If the bitmap size is 1x1 and the value of the glyphdata
  318. // is 0 (background only) then we skip this glyph. This is
  319. // GDI's way of telling us we have an empty glyph (like a
  320. // space).
  321. if ((soGlyph.sizlBitmap.cx == 1) &&
  322. (soGlyph.sizlBitmap.cy == 1) &&
  323. ((pgb->aj[0] & 0x80) == 0x0)) {
  324. PLOTDBG(DBG_BMPFONT,
  325. ("BitmapTextOut: Getting (1x1)=0 bitmap, SKIP it"));
  326. soGlyph.sizlBitmap.cx =
  327. soGlyph.sizlBitmap.cy = 0;
  328. } else {
  329. rclSrc = rclDst;
  330. PLOTDBG(DBG_BMPFONT, ("BitmapTextOut: pgp=%08lx, pgb=%08lx, ptl=(%ld, %ld) Inc=(%ld, %ld)",
  331. pgp, pgb, pgp->ptl.x, pgp->ptl.y,
  332. sizlInc.cx, sizlInc.cy));
  333. PLOTDBG(DBG_BMPFONT, ("BitmapTextOut: Bmp=%ld x %ld, pgb->ptlOrigin=[%ld, %ld]",
  334. soGlyph.sizlBitmap.cx,
  335. soGlyph.sizlBitmap.cy,
  336. pgb->ptlOrigin.x, pgb->ptlOrigin.y));
  337. PLOTDBG(DBG_BMPFONT, ("BitmapTextOut: rclDst=(%ld, %ld)-(%ld, %ld)",
  338. rclDst.left, rclDst.top, rclDst.right, rclDst.bottom));
  339. }
  340. //
  341. // Now verify that we have a glyph to send, and that the glyphs
  342. // destination position in the target device, lies inside
  343. // the clipping region.
  344. //
  345. if ((soGlyph.sizlBitmap.cx) &&
  346. (soGlyph.sizlBitmap.cy) &&
  347. (IntersectRECTL(&rclDst, pClipRect))) {
  348. //
  349. // We will pass the internal version of soGlyph without making
  350. // a temp. copy.
  351. //
  352. soGlyph.pvBits =
  353. soGlyph.pvScan0 = (LPVOID)pgb->aj;
  354. soGlyph.lDelta = (LONG)((soGlyph.sizlBitmap.cx + 7) >> 3);
  355. soGlyph.cjBits = (LONG)(soGlyph.lDelta *
  356. soGlyph.sizlBitmap.cy);
  357. rclSrc.left = rclDst.left - rclSrc.left;
  358. rclSrc.top = rclDst.top - rclSrc.top;
  359. rclSrc.right = rclSrc.left + (rclDst.right - rclDst.left);
  360. rclSrc.bottom = rclSrc.top + (rclDst.bottom - rclDst.top);
  361. PLOTDBG(DBG_BMPFONT, ("BitmapTextOut: rclSrc=(%ld, %ld)-(%ld, %ld)",
  362. rclSrc.left, rclSrc.top, rclSrc.right, rclSrc.bottom));
  363. #if DBG
  364. if (DBG_PLOTFILENAME & DBG_SHOWRASFONT) {
  365. LPBYTE pbSrc;
  366. LPBYTE pbCur;
  367. UINT x;
  368. UINT y;
  369. UINT Size;
  370. BYTE bData;
  371. BYTE Mask;
  372. BYTE Buf[128];
  373. DBGP(("================================================="));
  374. DBGP(("BitmapTextOut: Size=%ld x %ld, Origin=(%ld, %ld), Clip=(%ld, %ld)-(%ld, %ld)",
  375. soGlyph.sizlBitmap.cx, soGlyph.sizlBitmap.cy,
  376. pgb->ptlOrigin.x, pgb->ptlOrigin.y,
  377. rclSrc.left, rclSrc.top,
  378. rclSrc.right, rclSrc.bottom));
  379. pbSrc = soGlyph.pvScan0;
  380. for (y = 0; y < (UINT)soGlyph.sizlBitmap.cy; y++) {
  381. pbCur = pbSrc;
  382. pbSrc += soGlyph.lDelta;
  383. Mask = 0x0;
  384. Size = 0;
  385. for (x = 0;
  386. x < (UINT)soGlyph.sizlBitmap.cx && Size < sizeof(Buf);
  387. x++)
  388. {
  389. if (!(Mask >>= 1)) {
  390. Mask = 0x80;
  391. bData = *pbCur++;
  392. }
  393. if ((y >= (UINT)rclSrc.top) &&
  394. (y < (UINT)rclSrc.bottom) &&
  395. (x >= (UINT)rclSrc.left) &&
  396. (x < (UINT)rclSrc.right)) {
  397. Buf[Size++] = (BYTE)((bData & Mask) ? 219 :
  398. 177);
  399. } else {
  400. Buf[Size++] = (BYTE)((bData & Mask) ? 178 :
  401. 176);
  402. }
  403. }
  404. if (Size < sizeof(Buf))
  405. {
  406. Buf[Size] = '\0';
  407. }
  408. else
  409. {
  410. Buf[sizeof(Buf) - 1] = '\0';
  411. }
  412. DBGP((Buf));
  413. }
  414. }
  415. #endif
  416. //
  417. // Now output the bitmap that represents the glyph
  418. //
  419. Ok = OutputHTBitmap(pPDev, // pPDev
  420. &soGlyph, // psoHT
  421. NULL, // pco
  422. (PPOINTL)&rclDst, // pptlDst
  423. &rclSrc, // prclSrc
  424. Rop3, // Rop3
  425. pOHTFlags); // pOHTFlags
  426. }
  427. }
  428. } while ((Ok) && (MoreGlyphs));
  429. return(Ok);
  430. }
  431. BOOL
  432. OutlineTextOut(
  433. PPDEV pPDev,
  434. STROBJ *pstro,
  435. FONTOBJ *pfo,
  436. PRECTL pClipRect,
  437. BRUSHOBJ *pboBrush,
  438. POINTL *pptlBrushOrg,
  439. DWORD OutlineFlags,
  440. ROP4 Rop4
  441. )
  442. /*++
  443. Routine Description:
  444. This routine outputs the passed STROBJ by outputing a path that
  445. represents each glyph to the target device.
  446. Arguments:
  447. pPDev - Pointer to our PDEV
  448. pstro - We pass a string object to be drawn
  449. pfo - Pointer to the FONTOBJ
  450. pClipRect - Current enumerated clipping rectangle
  451. pboBrush - Brush object to be used for the text
  452. pptlBrushOrg - Brush origin alignment
  453. OutlineFlags - specified how to do outline font from FPOLY_xxxx flags
  454. Rop4 - Rop4 to be used
  455. Return Value:
  456. TRUE/FALSE
  457. Author:
  458. 18-Feb-1994 Fri 12:41:17 updated
  459. Adding the OutlineFlags to specified how to do fill/stroke
  460. 27-Jan-1994 Thu 13:10:34 updated
  461. re-write, style update, and arrange codes
  462. 25-Jan-1994 Wed 16:30:08 modified
  463. Added FONTOBJ as a parameter and now we only FILL truetype fonts,
  464. all others are stroked
  465. 18-Dec-1993 Sat 10:38:08 created
  466. Change style
  467. [t-kenl] Mar 14, 93 taken from DrvTextOut()
  468. Revision History:
  469. --*/
  470. {
  471. GLYPHPOS *pgp;
  472. PATHOBJ *ppo;
  473. RECTFX rectfxBound;
  474. RECTFX rclfxClip;
  475. POINTL ptlCur;
  476. SIZEL sizlInc;
  477. BOOL MoreGlyphs;
  478. BOOL Ok;
  479. BOOL FirstCh;
  480. ULONG cGlyphs;
  481. //
  482. // We will enumerate each of the glyphs in the passed STROBJ and use
  483. // the core polygon routine (DoPolygon) to draw each of them as a path.
  484. // If the STROBJ has a non NULL pgp field, then all the data is already
  485. // available on each gpyph. If not, we need to make a sequence of calls
  486. // to the engine helper function STROBJ_bEnum in order to enumerate the
  487. // glyphs. We will use the same code to output the data in both cases.
  488. //
  489. if (pClipRect) {
  490. rclfxClip.xLeft = LTOFX(pClipRect->left);
  491. rclfxClip.yTop = LTOFX(pClipRect->top);
  492. rclfxClip.xRight = LTOFX(pClipRect->right);
  493. rclfxClip.yBottom = LTOFX(pClipRect->bottom);
  494. }
  495. if (pstro->pgp) {
  496. pgp = pstro->pgp;
  497. MoreGlyphs = FALSE;
  498. cGlyphs = pstro->cGlyphs;
  499. PLOTDBG(DBG_TRUETYPE, ("OutlineTextOut: Character info already there (%ld glyphs)", cGlyphs));
  500. } else {
  501. STROBJ_vEnumStart(pstro);
  502. MoreGlyphs = TRUE;
  503. PLOTDBG(DBG_TRUETYPE, ("OutlineTextOut: STROBJ enub"));
  504. }
  505. //
  506. // Now start drawing the glyphs, if we have MoreGlyphs = TRUE then we
  507. // will do a STROBJ_bEnum first, in order to load up the Glyph data.
  508. //
  509. // Check the fill flags and set the flag appropriately out of the DEVMODE.
  510. // We will ONLY fill TrueType fonts, all other types (vector) will only be
  511. // stroked.
  512. //
  513. Ok = TRUE;
  514. sizlInc.cx =
  515. sizlInc.cy = 0;
  516. FirstCh = TRUE;
  517. do {
  518. //
  519. // Check to see if the job is being aborted, and exit out if such
  520. // is the case.
  521. //
  522. if (PLOT_CANCEL_JOB(pPDev)) {
  523. break;
  524. }
  525. //
  526. // We need to enum for more glyph data so do it now.
  527. //
  528. if (MoreGlyphs) {
  529. MoreGlyphs = STROBJ_bEnum(pstro, &cGlyphs, &pgp);
  530. if (MoreGlyphs == DDI_ERROR) {
  531. PLOTERR(("DrvTextOut: STROBJ_bEnum()=DDI_ERROR"));
  532. return(FALSE);
  533. }
  534. }
  535. PLOTDBG(DBG_TRUETYPE1,
  536. ("OutlineTextOut: New batch of cGlyphs=%d", cGlyphs));
  537. //
  538. // Stroke each glyph in this batch, then check if there are more.
  539. // Getting the first character position
  540. //
  541. if ((FirstCh) && (cGlyphs)) {
  542. ptlCur = pgp->ptl;
  543. FirstCh = FALSE;
  544. }
  545. for ( ; (Ok) && (cGlyphs--); pgp++) {
  546. #ifdef USERMODE_DRIVER
  547. GLYPHDATA gd;
  548. GLYPHDATA *pgd;
  549. #endif // USERMODE_DRIVER
  550. if (PLOT_CANCEL_JOB(pPDev)) {
  551. break;
  552. }
  553. //
  554. // Set up to enumerate path
  555. //
  556. #ifdef USERMODE_DRIVER
  557. pgd = &gd;
  558. if (FONTOBJ_cGetGlyphs(pfo,
  559. FO_PATHOBJ,
  560. 1,
  561. &(pgp->hg),
  562. (LPVOID)&pgd) != 1) {
  563. PLOTRIP(("OutlineTextOut: FONTOBJ_cGetGlyphs() FAILED"));
  564. return(FALSE);
  565. }
  566. ppo = pgd->gdf.ppo;
  567. #else
  568. ppo = pgp->pgdf->ppo;
  569. #endif // USERMODE_DRIVER
  570. //
  571. // If the clip rect is not null then verify the glyph actually lies
  572. // within the clipping rect then OUTPUT!!!
  573. //
  574. if (pstro->ulCharInc) {
  575. PLOTDBG(DBG_DEFCHARINC, ("OutlineTextOut: CharInc=(%ld, %ld)->(%ld, %ld), [%ld]",
  576. ptlCur.x, ptlCur.y,
  577. ptlCur.x + pstro->ulCharInc, ptlCur.y,
  578. pstro->ulCharInc));
  579. sizlInc.cx =
  580. sizlInc.cy = (LONG)pstro->ulCharInc;
  581. //
  582. // Check the text Accelators and adjust accordingly.
  583. //
  584. if (!(pstro->flAccel & SO_HORIZONTAL)) {
  585. sizlInc.cx = 0;
  586. }
  587. if (!(pstro->flAccel & SO_VERTICAL)) {
  588. sizlInc.cy = 0;
  589. }
  590. if (pstro->flAccel & SO_REVERSED) {
  591. sizlInc.cx = -sizlInc.cx;
  592. sizlInc.cy = -sizlInc.cy;
  593. }
  594. ptlCur.x += sizlInc.cx;
  595. ptlCur.y += sizlInc.cy;
  596. } else {
  597. ptlCur = pgp->ptl;
  598. }
  599. if (pClipRect) {
  600. //
  601. // Create a rect in correct device space and compare to the
  602. // clip rect
  603. //
  604. PATHOBJ_vGetBounds(ppo, &rectfxBound);
  605. //
  606. // Since the glyph positioning is based on the glyph origin
  607. // transform now to device space, in order to check if the
  608. // glyph lies inside the current clipping region.
  609. //
  610. rectfxBound.xLeft += LTOFX(ptlCur.x);
  611. rectfxBound.yTop += LTOFX(ptlCur.y);
  612. rectfxBound.xRight += LTOFX(ptlCur.x);
  613. rectfxBound.yBottom += LTOFX(ptlCur.y);
  614. if ((rectfxBound.xLeft > rclfxClip.xRight) ||
  615. (rectfxBound.xRight < rclfxClip.xLeft) ||
  616. (rectfxBound.yTop > rclfxClip.yBottom) ||
  617. (rectfxBound.yBottom < rclfxClip.yTop)) {
  618. PLOTDBG(DBG_TRUETYPE1, ("OutlineTextOut: Outside of CLIP, skipping glyph ..."));
  619. continue;
  620. }
  621. }
  622. //
  623. // Utilize the core path building function, taking advantage of
  624. // its ability to offset the passed PATH by a specific amount.
  625. //
  626. if (!(Ok = DoPolygon(pPDev,
  627. &ptlCur,
  628. NULL,
  629. ppo,
  630. pptlBrushOrg,
  631. pboBrush,
  632. pboBrush,
  633. Rop4,
  634. NULL,
  635. OutlineFlags))) {
  636. PLOTERR(("OutlineTextOut: Failed in DoPolygon(Options=%08lx)",
  637. OutlineFlags));
  638. //
  639. // If we failed to draw it, then try just stroking it, since
  640. // that won't depend on any polygon constraints used in the
  641. // target device, and failing DrvStrokePath, won't make the
  642. // Text output get broken down to any simpler format.
  643. //
  644. if ((OutlineFlags & FPOLY_MASK) != FPOLY_STROKE) {
  645. //
  646. // If we failed then just stroke it
  647. //
  648. PLOTERR(("OutlineTextOut: Now TRY DoPolygon(FPOLY_STROKE)"));
  649. Ok = DoPolygon(pPDev,
  650. &ptlCur,
  651. NULL,
  652. ppo,
  653. pptlBrushOrg,
  654. NULL,
  655. pboBrush,
  656. Rop4,
  657. NULL,
  658. FPOLY_STROKE);
  659. }
  660. }
  661. //
  662. // Go to next position
  663. ptlCur.x += sizlInc.cx;
  664. ptlCur.y += sizlInc.cy;
  665. }
  666. } while ((Ok) && (MoreGlyphs));
  667. return(TRUE);
  668. }
  669. BOOL
  670. DrvTextOut(
  671. SURFOBJ *pso,
  672. STROBJ *pstro,
  673. FONTOBJ *pfo,
  674. CLIPOBJ *pco,
  675. RECTL *prclExtra,
  676. RECTL *prclOpaque,
  677. BRUSHOBJ *pboFore,
  678. BRUSHOBJ *pboOpaque,
  679. POINTL *pptlBrushOrg,
  680. MIX mix
  681. )
  682. /*++
  683. Routine Description:
  684. The Graphics Engine will call this routine to render a set of glyphs at
  685. specified positions. This function will review the passed data, and
  686. image the glyph either as a path to be filled or stroked, or as a bitmap.
  687. Arguments:
  688. pso - pointer to our surface object
  689. pstro - pointer to the string object
  690. pfo - pointer to the font object
  691. pco - clipping object
  692. prclExtra - pointer to array of rectangles to be merge with glyphs
  693. prclOpaque - Pointer to a rectangle to be fill with pboOpaque brush
  694. pboFore - pointer to the brush object for the foreground color
  695. pboOpqaue - pointer to the brush object for the opaque rectangle
  696. pptlBrushOrg- Pointer to the brush alignment
  697. mix - Two Rop2 mode
  698. Return Value:
  699. TRUE/FALSE
  700. Author:
  701. 23-Jan-1994 Thu 2:59:31 created
  702. 27-Jan-1994 Thu 12:56:11 updated
  703. Style, re-write, commented
  704. 10-Mar-1994 Thu 00:30:38 updated
  705. 1. Make sure we not fill the stroke type of font
  706. 2. Move rclOpqaue and rclExtra process out from the do loop, so that
  707. when it in the RTL mode for the font it will be correctly processed
  708. and it will also save output data size by not switching in/out
  709. RTL/HPGL2 mode just try to do the prclOpaque/prclExtra
  710. 3. Process FO_TYPE correctly for all type of fonts (outline, truetype,
  711. bitmap, vector, stroke and others)
  712. 11-Mar-1994 Fri 19:24:56 updated
  713. Bug# 10276, the clipping window is set for the raster font and clear
  714. clipping window is done before the exit to HPGL2 mode, this causes
  715. all raster font after the first clip is not visible to end of the
  716. page. Now changed it so we only do clipping window when the font is
  717. NOT RASTER.
  718. Revision History:
  719. --*/
  720. {
  721. #define pDrvHTInfo ((PDRVHTINFO)(pPDev->pvDrvHTData))
  722. PPDEV pPDev;
  723. PRECTL pCurClipRect;
  724. HTENUMRCL EnumRects;
  725. DWORD RTLPalDW[2];
  726. DWORD rgbText;
  727. DWORD OHTFlags;
  728. DWORD OutlineFlags;
  729. BOOL DoRasterFont;
  730. BOOL bMore;
  731. BOOL bDoClipWindow;
  732. BOOL Ok;
  733. DWORD BMFontRop3;
  734. ROP4 Rop4;
  735. //
  736. // Transform the MIX to ROP4
  737. //
  738. Rop4 = MixToRop4(mix);
  739. PLOTDBG(DBG_TEXTOUT, ("DrvTextOut: prclOpaque = %08lx", prclOpaque));
  740. PLOTDBG(DBG_TEXTOUT, (" prclExtra = %08lx", prclExtra));
  741. PLOTDBG(DBG_TEXTOUT, (" pstro->flAccel = %08lx", pstro->flAccel));
  742. PLOTDBG(DBG_TEXTOUT, (" pstro->ulCharInc = %ld", pstro->ulCharInc));
  743. PLOTDBG(DBG_TEXTOUT, (" pfo->cxMax = %ld", pfo->cxMax));
  744. PLOTDBG(DBG_TEXTOUT, (" FontType = %08lx", pfo->flFontType));
  745. PLOTDBG(DBG_TEXTOUT, (" MIX = %04lx (Rop=%04lx)", mix, Rop4));
  746. if (!(pPDev = SURFOBJ_GETPDEV(pso))) {
  747. PLOTERR(("DoTextOut: Invalid pPDev in pso"));
  748. return(FALSE);
  749. }
  750. if (pPDev->PlotDM.Flags & PDMF_PLOT_ON_THE_FLY) {
  751. PLOTWARN(("DoTextOut: POSTER Mode IGNORE All Texts"));
  752. return(TRUE);
  753. }
  754. //
  755. // Since we dont support device fonts, make sure we are not getting one
  756. // now.
  757. //
  758. if (pfo->flFontType & FO_TYPE_DEVICE) {
  759. PLOTASSERT(1, "DrvTextOut: Getting DEVICE font (%08lx)",
  760. !(pfo->flFontType & FO_TYPE_DEVICE ), pfo->flFontType);
  761. return(FALSE);
  762. }
  763. if (DoRasterFont = (BOOL)(pfo->flFontType & FO_TYPE_RASTER)) {
  764. PLOTDBG(DBG_TEXTOUT1, ("DrvTextOut: We got the BITMAP Font from GDI"));
  765. //
  766. // Make pfo = NULL so later we will not try to do FONTOBJ_cGetGlyph in
  767. // BitmapTextOut
  768. //
  769. #ifndef USERMODE_DRIVER
  770. pfo = NULL;
  771. #endif // !USERMODE_DRIVER
  772. } else {
  773. PIFIMETRICS pifi;
  774. //
  775. // Try to find out if we need to fill the font, or just stroke it.
  776. //
  777. if ((pifi = FONTOBJ_pifi(pfo)) &&
  778. (pifi->flInfo & FM_INFO_RETURNS_STROKES)) {
  779. PLOTDBG(DBG_TEXTOUT1, ("DrvTextOut() Font can only do STROKE"));
  780. OutlineFlags = FPOLY_STROKE;
  781. } else {
  782. PLOTDBG(DBG_TEXTOUT1, ("DrvTextOut() Font We can do FILL, User Said=%hs",
  783. (pPDev->PlotDM.Flags & PDMF_FILL_TRUETYPE) ? "FILL" : "STROKE"));
  784. OutlineFlags = (pPDev->PlotDM.Flags & PDMF_FILL_TRUETYPE) ?
  785. (DWORD)FPOLY_FILL : (DWORD)FPOLY_STROKE;
  786. }
  787. }
  788. //
  789. // Check if we need to opaque the area
  790. //
  791. if (prclOpaque) {
  792. PLOTDBG(DBG_TEXTOUT2, ("prclOpaque=(%ld, %ld) - (%ld, %ld)",
  793. prclOpaque->left, prclOpaque->top,
  794. prclOpaque->right, prclOpaque->bottom));
  795. if (!DrvBitBlt(pso, // Target
  796. NULL, // Source
  797. NULL, // Mask Obj
  798. pco, // Clip Obj
  799. NULL, // XlateOBj
  800. prclOpaque, // Dest Rect Ptr
  801. NULL, // Source Pointl
  802. NULL, // Mask Pointl
  803. pboOpaque, // Brush Obj
  804. pptlBrushOrg, // Brush Origin
  805. 0xF0F0)) { // ROP4 (PATCOPY)
  806. PLOTERR(("DrvTextOut: DrvBitBltBit(pboOpqaue) FAILED!"));
  807. return(FALSE);
  808. }
  809. }
  810. //
  811. // We will do prclExtra only if it is not NULL, this simulates the
  812. // underline or strikeout effects.
  813. //
  814. if (prclExtra) {
  815. //
  816. // The prclExtra terminated only if all points in rectangle coordinate
  817. // are all set to zeros
  818. //
  819. while ((prclExtra->left) ||
  820. (prclExtra->top) ||
  821. (prclExtra->right) ||
  822. (prclExtra->bottom)) {
  823. PLOTDBG(DBG_TEXTOUT2, ("prclExtra=(%ld, %ld) - (%ld, %ld)",
  824. prclExtra->left, prclExtra->top,
  825. prclExtra->right, prclExtra->bottom));
  826. if (!DrvBitBlt(pso, // Target
  827. NULL, // Source
  828. NULL, // Mask Obj
  829. pco, // Clip Obj
  830. NULL, // XlateOBj
  831. prclExtra, // Dest Rect Ptr
  832. NULL, // Source Pointl
  833. NULL, // Mask Pointl
  834. pboFore, // Brush Obj
  835. pptlBrushOrg, // Brush Origin
  836. Rop4)) { // ROP4
  837. PLOTERR(("DrvTextOut: DrvBitBltBit(pboFore) FAILED!"));
  838. return(FALSE);
  839. }
  840. //
  841. // Now try next EXTRA rectangle
  842. //
  843. ++prclExtra;
  844. }
  845. }
  846. //
  847. // If we are using Raster Font then the mode will be set as following
  848. //
  849. if (DoRasterFont) {
  850. RTLPalDW[0] = pDrvHTInfo->RTLPal[0].dw;
  851. RTLPalDW[1] = pDrvHTInfo->RTLPal[1].dw;
  852. //
  853. // Get the color to use.
  854. //
  855. if (!GetColor(pPDev,
  856. pboFore,
  857. &(pDrvHTInfo->RTLPal[1].dw),
  858. NULL,
  859. Rop4)) {
  860. PLOTERR(("DrvTextOut: Get Raster Font Text Color failed! use BLACK"));
  861. rgbText = 0x0;
  862. }
  863. if (pDrvHTInfo->RTLPal[1].dw == 0xFFFFFF) {
  864. //
  865. // White Text, our white is 1 and 0=black, so do:"not S and D"
  866. //
  867. PLOTDBG(DBG_BMPTEXTCLR, ("DrvTextOut: Doing WHITE TEXT (0xEEEE)"));
  868. pDrvHTInfo->RTLPal[0].dw = 0x0;
  869. OHTFlags = 0;
  870. BMFontRop3 = 0xEE; // S | D
  871. } else {
  872. pDrvHTInfo->RTLPal[0].dw = 0xFFFFFF;
  873. OHTFlags = OHTF_SET_TR1;
  874. BMFontRop3 = 0xCC; // S
  875. }
  876. PLOTDBG(DBG_BMPTEXTCLR,
  877. ("DrvTextOut: BG=%02x:%02x:%02x, FG=%02x:%02x:%02x, Rop3=%04lx",
  878. (DWORD)pDrvHTInfo->RTLPal[0].Pal.R,
  879. (DWORD)pDrvHTInfo->RTLPal[0].Pal.G,
  880. (DWORD)pDrvHTInfo->RTLPal[0].Pal.B,
  881. (DWORD)pDrvHTInfo->RTLPal[1].Pal.R,
  882. (DWORD)pDrvHTInfo->RTLPal[1].Pal.G,
  883. (DWORD)pDrvHTInfo->RTLPal[1].Pal.B,
  884. BMFontRop3));
  885. //
  886. // We do not need clip window command in RTL mode
  887. //
  888. bDoClipWindow = FALSE;
  889. } else {
  890. bDoClipWindow = TRUE;
  891. }
  892. bMore = FALSE;
  893. Ok = TRUE;
  894. EnumRects.c = 1;
  895. if ((!pco) || (pco->iDComplexity == DC_TRIVIAL)) {
  896. //
  897. // The whole output destination rectangle is visible
  898. //
  899. PLOTDBG(DBG_TEXTOUT, ("DrvTextOut: pco=%hs",
  900. (pco) ? "DC_TRIVIAL" : "NULL"));
  901. EnumRects.rcl[0] = pstro->rclBkGround;
  902. bDoClipWindow = FALSE;
  903. } else if (pco->iDComplexity == DC_RECT) {
  904. //
  905. // The visible area is one rectangle intersect with the destinaiton
  906. //
  907. PLOTDBG(DBG_TEXTOUT, ("DrvTextOut: pco=DC_RECT"));
  908. EnumRects.rcl[0] = pco->rclBounds;
  909. } else {
  910. //
  911. // We have complex clipping region to be computed, call engine to start
  912. // enumerating the rectangles and set More = TRUE so we can get the
  913. // first batch of rectangles.
  914. //
  915. PLOTDBG(DBG_TEXTOUT, ("DrvTextOut: pco=DC_COMPLEX, EnumRects now"));
  916. CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_ANY, 0);
  917. bMore = TRUE;
  918. }
  919. do {
  920. //
  921. // If More is true then we need to get next batch of rectangles. In
  922. // this mode, we have a set of rectangles that represents the
  923. // clipping region in the target device. Since none of the devices
  924. // we handle can acommodate a complex clipping path, we enumerate the
  925. // cliping path (CLIPOBJ) as rectangles and image the entire STROBJ
  926. // through these rectangles, trying to determine as quickly as possible
  927. // when a glyph does not lie in the current clipping rect.
  928. //
  929. if (bMore) {
  930. bMore = CLIPOBJ_bEnum(pco, sizeof(EnumRects), (ULONG *)&EnumRects);
  931. }
  932. //
  933. // prcl will point to the first enumerated rectangle, which may just
  934. // be the RECT of the clipping area if its DC_RECT.
  935. //
  936. pCurClipRect = (PRECTL)&EnumRects.rcl[0];
  937. while ((Ok) && bMore != DDI_ERROR && (EnumRects.c--)) {
  938. PLOTDBG(DBG_TEXTOUT, ("DrvTextOut: Clip=(%ld, %ld)-(%ld, %ld) %ld x %ld, Bound=(%ld, %d)-(%ld, %ld), %ld x %ld",
  939. pCurClipRect->left, pCurClipRect->top,
  940. pCurClipRect->right, pCurClipRect->bottom,
  941. pCurClipRect->right - pCurClipRect->left,
  942. pCurClipRect->bottom - pCurClipRect->top,
  943. pstro->rclBkGround.left, pstro->rclBkGround.top,
  944. pstro->rclBkGround.right, pstro->rclBkGround.bottom,
  945. pstro->rclBkGround.right - pstro->rclBkGround.left,
  946. pstro->rclBkGround.bottom - pstro->rclBkGround.top));
  947. //
  948. // If we will output the STROBJ as bitmaps that represent the
  949. // glyphs of the STROBJ, do it now.
  950. //
  951. if (DoRasterFont) {
  952. if (!(Ok = BitmapTextOut(pPDev,
  953. pstro,
  954. pfo,
  955. pCurClipRect,
  956. &OHTFlags,
  957. BMFontRop3))) {
  958. PLOTERR(("DrvTextOut: BitmapTypeTextOut() FAILED"));
  959. break;
  960. }
  961. } else {
  962. //
  963. // If we have a clip window, set it now, this will allow
  964. // the target device to do any clipping
  965. //
  966. if (bDoClipWindow) {
  967. SetClipWindow(pPDev, pCurClipRect);
  968. }
  969. if (!(Ok = OutlineTextOut(pPDev,
  970. pstro,
  971. pfo,
  972. pCurClipRect,
  973. pboFore,
  974. pptlBrushOrg,
  975. OutlineFlags,
  976. Rop4))) {
  977. PLOTERR(("DrvTextOut: TrueTypeTextOut() FAILED!"));
  978. break;
  979. }
  980. }
  981. //
  982. // Goto next clip rectangle
  983. //
  984. pCurClipRect++;
  985. }
  986. } while ((Ok) && (bMore == TRUE));
  987. if (DoRasterFont) {
  988. pDrvHTInfo->RTLPal[0].dw = RTLPalDW[0];
  989. pDrvHTInfo->RTLPal[1].dw = RTLPalDW[1];
  990. if (OHTFlags & OHTF_MASK) {
  991. OHTFlags |= OHTF_EXIT_TO_HPGL2;
  992. OutputHTBitmap(pPDev, NULL, NULL, NULL, NULL, 0xAA, &OHTFlags);
  993. }
  994. }
  995. //
  996. // If we had set a clip window now is the time to clear it after exit from
  997. // RTL Mode
  998. //
  999. if (bDoClipWindow) {
  1000. ClearClipWindow(pPDev);
  1001. }
  1002. return(Ok);
  1003. #undef pDrvHTInfo
  1004. }