Windows NT 4.0 source code leak
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.

488 lines
14 KiB

4 years ago
  1. /******************************Module*Header*******************************\
  2. * Module Name: font.c
  3. *
  4. * Font and text handling for the OpenGL-based 3D Text screen saver.
  5. *
  6. * Created: 12-24-94 -by- Marc Fortier [marcfo]
  7. *
  8. * Copyright (c) 1994 Microsoft Corporation
  9. \**************************************************************************/
  10. #include <nt.h>
  11. #include <ntrtl.h>
  12. #include <nturtl.h>
  13. #include <windows.h>
  14. #include <commdlg.h>
  15. #include <ptypes32.h>
  16. #include <pwin32.h>
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include <memory.h>
  20. #include <float.h> // for FLT_MAX
  21. #include <GL/gl.h>
  22. #include "sscommon.h"
  23. #include "sstext3d.h"
  24. #ifndef UNICODE
  25. // Support dbcs characters (this is a patch)
  26. #define SS_DBCS_SUPPORT 1
  27. #endif
  28. static LISTENTRY* FindExtendedLUTEntry( TCHAR c, WglFontContext *pwfc );
  29. static BOOL UpdateReducedFontList( TCHAR c, LISTENTRY *ple,
  30. WglFontContext *pwfc );
  31. #ifdef SS_DBCS_SUPPORT
  32. static BOOL UpdateReducedFontListDBCS( DWORD c, LISTENTRY *ple,
  33. WglFontContext *pwfc );
  34. #endif
  35. static void DeleteExtendedLUTTableEntries( WglFontContext *pwfc );
  36. static void DeleteDirectLUTTableEntries( WglFontContext *pwfc );
  37. static void DeleteLUTEntry( LISTENTRY *ple );
  38. /******************************Public*Routine******************************\
  39. * CreateWglFontContext
  40. *
  41. * Create a WglFontContext.
  42. *
  43. * Initializes the look-up-table memory for characters.
  44. * The first half of this table is a direct look-up, using the char value.
  45. * The second half is used for unicode chars that are >256, and must be
  46. * searched sequentially.
  47. *
  48. \**************************************************************************/
  49. WglFontContext *
  50. CreateWglFontContext( HDC hdc, int type, float fExtrusion,
  51. float fChordalDeviation )
  52. {
  53. WglFontContext *pwfc;
  54. pwfc = (WglFontContext *) LocalAlloc( LMEM_FIXED, sizeof(WglFontContext) );
  55. if( !pwfc ) {
  56. SS_ALLOC_FAILURE( "CreateWglFontContext" );
  57. return NULL;
  58. }
  59. pwfc->hdc = hdc;
  60. pwfc->type = type;
  61. pwfc->extrusion = fExtrusion;
  62. pwfc->chordalDeviation = fChordalDeviation;
  63. pwfc->listLUT = (LISTENTRY*) LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT,
  64. SIZE_LIST_LUT * sizeof(LISTENTRY) );
  65. if( !pwfc->listLUT ) {
  66. LocalFree( pwfc );
  67. SS_ALLOC_FAILURE( "CreateWglFontContext" );
  68. return NULL;
  69. }
  70. pwfc->LUTIndex = 0;
  71. return pwfc;
  72. }
  73. /******************************Public*Routine******************************\
  74. * DeleteWglFontContext
  75. *
  76. * Delete a WglFontContext.
  77. *
  78. \**************************************************************************/
  79. void
  80. DeleteWglFontContext( WglFontContext *pwfc )
  81. {
  82. if( !pwfc )
  83. return;
  84. // Delete the extended lut table entries
  85. DeleteExtendedLUTTableEntries( pwfc );
  86. // Delete the direct lut table entries
  87. DeleteDirectLUTTableEntries( pwfc );
  88. if( pwfc->listLUT )
  89. LocalFree( pwfc->listLUT );
  90. LocalFree( pwfc );
  91. }
  92. /******************************Public*Routine******************************\
  93. * DeleteExtendedLUTTablEntries
  94. *
  95. \**************************************************************************/
  96. static void
  97. DeleteExtendedLUTTableEntries( WglFontContext *pwfc )
  98. {
  99. int i;
  100. LISTENTRY *ple = pwfc->listLUT + MAX_DIRECT_LUT;
  101. for( i = 0; i < pwfc->LUTIndex; i ++, ple++ )
  102. DeleteLUTEntry( ple );
  103. pwfc->LUTIndex = 0;
  104. }
  105. /******************************Public*Routine******************************\
  106. * DeleteDirectLUTTablEntries
  107. *
  108. \**************************************************************************/
  109. static void
  110. DeleteDirectLUTTableEntries( WglFontContext *pwfc )
  111. {
  112. int i;
  113. LISTENTRY *ple = pwfc->listLUT;
  114. for( i = 0; i < MAX_DIRECT_LUT; i ++, ple++ )
  115. DeleteLUTEntry( ple );
  116. }
  117. /******************************Public*Routine******************************\
  118. * DeleteLUTEntry
  119. *
  120. \**************************************************************************/
  121. static void
  122. DeleteLUTEntry( LISTENTRY *ple )
  123. {
  124. if( ple->listNum ) {
  125. glDeleteLists( ple->listNum, 1 );
  126. ple->listNum = 0;
  127. }
  128. if( ple->lpgmf ) {
  129. LocalFree( ple->lpgmf );
  130. ple->lpgmf = NULL;
  131. }
  132. ple->glyph = 0;
  133. }
  134. /**************************************************************************\
  135. * ConvertStringToList
  136. *
  137. * - Translate the string into display list numbers
  138. * - If no entry in the list table, update the table
  139. *
  140. \**************************************************************************/
  141. void
  142. ConvertStringToList( LPTSTR pszSrc, USHORT *usDst, WglFontContext *pwfc )
  143. {
  144. int strLen;
  145. LISTENTRY *ple;
  146. TCHAR c;
  147. TUCHAR cindex; // use unsigned TCHAR for table indexing
  148. #ifdef SS_DBCS_SUPPORT
  149. BOOL bIsLeadByte;
  150. #endif
  151. if( !pwfc )
  152. return;
  153. /* Go thru the string, making sure every char has a display list
  154. * Copy the display list # into usDst
  155. */
  156. strLen = lstrlen( pszSrc );
  157. if( strLen > TEXT_BUF_SIZE )
  158. strLen = TEXT_BUF_SIZE;
  159. /* Check for possible overflow with the extended LUT section, and
  160. * invalidate the extended LUT if so
  161. */
  162. if( pwfc->LUTIndex ) {
  163. int roomLeft; // spaces left in extended lut table
  164. roomLeft = SIZE_LIST_LUT - (pwfc->LUTIndex + MAX_DIRECT_LUT +1);
  165. if( roomLeft < strLen ) {
  166. /* If none of the characters in this string have entries in the
  167. * table, we'll run out of room. Assume the worst, invalidate
  168. * the whole table, and start over again.
  169. */
  170. DeleteExtendedLUTTableEntries( pwfc );
  171. }
  172. }
  173. for( ; strLen; strLen--, pszSrc++ ) {
  174. c = *pszSrc;
  175. cindex = (TUCHAR) c;
  176. // see if char already has cmd list entry - if not, create it
  177. #ifdef SS_DBCS_SUPPORT
  178. bIsLeadByte = IsDBCSLeadByte(cindex);
  179. if( !bIsLeadByte && (cindex < MAX_DIRECT_LUT) ) { // direct LUT
  180. #else
  181. if( cindex < MAX_DIRECT_LUT ) { // direct LUT entry
  182. #endif
  183. ple = &pwfc->listLUT[cindex];
  184. if( !ple->listNum ) {
  185. // have to create new cmd list for this glyph
  186. if( ! UpdateReducedFontList( c, ple, pwfc ) ) {
  187. DeleteLUTEntry( ple );
  188. continue;
  189. }
  190. }
  191. } else { // extended LUT entry
  192. #ifdef SS_DBCS_SUPPORT
  193. DWORD dwChar;
  194. if( bIsLeadByte ) {
  195. // Iterate over the lead byte
  196. pszSrc++;
  197. strLen--;
  198. c = *pszSrc;
  199. // Setup the double byte word so that :
  200. // High byte is the lead byte
  201. // Low byte is the next byte in the byte stream (this byte
  202. // will be used to access the extended lut table)
  203. dwChar = (DWORD) ( (cindex << 8) | ((TUCHAR) c) );
  204. } else
  205. dwChar = (DWORD) (TUCHAR) c;
  206. if( !(ple = FindExtendedLUTEntry( c, pwfc )) ) {
  207. ple = &pwfc->listLUT[pwfc->LUTIndex+MAX_DIRECT_LUT];
  208. if( ! UpdateReducedFontListDBCS( dwChar, ple, pwfc ) ) {
  209. DeleteLUTEntry( ple );
  210. continue;
  211. }
  212. ple->glyph = c;
  213. pwfc->LUTIndex++;
  214. }
  215. #else
  216. if( !(ple = FindExtendedLUTEntry( c, pwfc )) ) {
  217. ple = &pwfc->listLUT[pwfc->LUTIndex+MAX_DIRECT_LUT];
  218. if( ! UpdateReducedFontList( c, ple, pwfc ) ) {
  219. DeleteLUTEntry( ple );
  220. continue;
  221. }
  222. ple->glyph = c;
  223. pwfc->LUTIndex++;
  224. }
  225. #endif
  226. }
  227. *usDst++ = ple->listNum;
  228. }
  229. // zero terminate
  230. *usDst = 0;
  231. }
  232. /******************************Public*Routine******************************\
  233. * UpdateReducedFontList
  234. *
  235. * Calls wglUseFontOutlines() to create a command list for the supplied
  236. * character.
  237. *
  238. * Allocates memory for the characters glyphmetrics as well
  239. *
  240. \**************************************************************************/
  241. static BOOL
  242. UpdateReducedFontList( TCHAR c, LISTENTRY *ple, WglFontContext *pwfc )
  243. {
  244. ple->lpgmf = (LPGLYPHMETRICSFLOAT) LocalAlloc( LMEM_FIXED,
  245. sizeof( GLYPHMETRICSFLOAT ) );
  246. if( !ple->lpgmf ) {
  247. SS_ALLOC_FAILURE( "UpdateReducedFontList" );
  248. return FAILURE;
  249. }
  250. // get next list # for this glyph.
  251. ple->listNum = (USHORT) glGenLists( 1 );
  252. if( !ple->listNum ) {
  253. SS_WARNING( "glGenLists failed\n" );
  254. return FAILURE;
  255. }
  256. if( !wglUseFontOutlines(pwfc->hdc, (TUCHAR) c, 1, ple->listNum,
  257. pwfc->chordalDeviation,
  258. pwfc->extrusion,
  259. pwfc->type, ple->lpgmf) ) {
  260. SS_WARNING( "wglUseFontOutlines failed\n" );
  261. return FAILURE;
  262. }
  263. return SUCCESS;
  264. }
  265. #ifdef SS_DBCS_SUPPORT
  266. // Modified version of UpdateReducedFontList that handles dbcs characters.
  267. // This is a *patch* (as is all the SS_DBCS_SUPPORT stuff) to handle dbcs
  268. // characters without jeopardizing SUR release stability. Later, the functions
  269. // can be consolidated.
  270. static BOOL
  271. UpdateReducedFontListDBCS( DWORD c, LISTENTRY *ple, WglFontContext *pwfc )
  272. {
  273. ple->lpgmf = (LPGLYPHMETRICSFLOAT) LocalAlloc( LMEM_FIXED,
  274. sizeof( GLYPHMETRICSFLOAT ) );
  275. if( !ple->lpgmf ) {
  276. SS_ALLOC_FAILURE( "UpdateReducedFontList" );
  277. return FAILURE;
  278. }
  279. // get next list # for this glyph.
  280. ple->listNum = (USHORT) glGenLists( 1 );
  281. if( !ple->listNum ) {
  282. SS_WARNING( "glGenLists failed\n" );
  283. return FAILURE;
  284. }
  285. if( !wglUseFontOutlines(pwfc->hdc, c, 1, ple->listNum,
  286. pwfc->chordalDeviation,
  287. pwfc->extrusion,
  288. pwfc->type, ple->lpgmf) ) {
  289. SS_WARNING( "wglUseFontOutlines failed\n" );
  290. return FAILURE;
  291. }
  292. return SUCCESS;
  293. }
  294. #endif
  295. /******************************Public*Routine******************************\
  296. * FindExtendedLUTEntry
  297. *
  298. * Searches through the extended character LUT, and returns ptr to the
  299. * char's info if found, otherwise NULL.
  300. *
  301. \**************************************************************************/
  302. static LISTENTRY*
  303. FindExtendedLUTEntry( TCHAR c, WglFontContext *pwfc )
  304. {
  305. int i;
  306. LISTENTRY *ple = pwfc->listLUT + MAX_DIRECT_LUT;
  307. for( i = 0; i < pwfc->LUTIndex; i ++, ple++ ) {
  308. if( ple->glyph == c )
  309. return ple;
  310. }
  311. return NULL;
  312. }
  313. /******************************Public*Routine******************************\
  314. * DrawString
  315. *
  316. * Draws string by calling cmd list for each char.
  317. *
  318. \**************************************************************************/
  319. void
  320. DrawString( USHORT *string,
  321. int strLen,
  322. WglFontContext *pwfc )
  323. {
  324. if( !pwfc )
  325. return;
  326. glCallLists(strLen, GL_UNSIGNED_SHORT, (GLushort *) string);
  327. }
  328. /******************************Public*Routine******************************\
  329. * GetStringExtent
  330. *
  331. * Calculate a string's origin and extent in world coordinates.
  332. *
  333. * The origin is determined by the first character's location, and thereafter
  334. * each char's location is determined by adding the previous char's cellInc
  335. * values.
  336. *
  337. * This will work for all string orientations.
  338. *
  339. \**************************************************************************/
  340. int
  341. GetStringExtent( LPTSTR szString,
  342. POINTFLOAT *extent,
  343. POINTFLOAT *origin,
  344. WglFontContext *pwfc )
  345. {
  346. int len, strLen;
  347. TCHAR *c;
  348. TUCHAR cindex;
  349. LPGLYPHMETRICSFLOAT lpgmf;
  350. POINTFLOAT cellOrigin = {0.0f, 0.0f};
  351. POINTFLOAT extentOrigin = {FLT_MAX, -FLT_MAX};
  352. POINTFLOAT extentLowerRight = {-FLT_MAX, FLT_MAX};
  353. POINTFLOAT boxOrigin, boxLowerRight;
  354. LISTENTRY *listLUT, *ple;
  355. #ifdef SS_DBCS_SUPPORT
  356. BOOL bIsLeadByte;
  357. #endif
  358. if( !pwfc )
  359. return 0;
  360. listLUT = pwfc->listLUT;
  361. extent->x = extent->y = 0.0f;
  362. origin->x = origin->y = 0.0f;
  363. len = strLen = lstrlen( szString );
  364. if( !len )
  365. return 0; // otherwise extents will be calc'd erroneously
  366. c = szString;
  367. for( ; strLen; strLen--, c++ ) {
  368. cindex = (TUCHAR) *c;
  369. #ifdef SS_DBCS_SUPPORT
  370. if( bIsLeadByte = IsDBCSLeadByte(cindex) ) {
  371. // iterate over lead byte
  372. c++;
  373. strLen--;
  374. cindex = (TUCHAR) *c;
  375. }
  376. if( !bIsLeadByte && (cindex < MAX_DIRECT_LUT) )
  377. #else
  378. if( cindex < MAX_DIRECT_LUT )
  379. #endif
  380. ple = &listLUT[cindex];
  381. else
  382. ple = FindExtendedLUTEntry( *c, pwfc );
  383. lpgmf = ple->lpgmf;
  384. if( !lpgmf )
  385. // Memory must be running low, but keep going
  386. continue;
  387. // calc global position of this char's BlackBox (this is
  388. // 'upper left')
  389. boxOrigin.x = cellOrigin.x + lpgmf->gmfptGlyphOrigin.x;
  390. boxOrigin.y = cellOrigin.y + lpgmf->gmfptGlyphOrigin.y;
  391. // calc lower right position
  392. boxLowerRight.x = boxOrigin.x + lpgmf->gmfBlackBoxX;
  393. boxLowerRight.y = boxOrigin.y - lpgmf->gmfBlackBoxY;
  394. // compare against the current bounding box
  395. if( boxOrigin.x < extentOrigin.x )
  396. extentOrigin.x = boxOrigin.x;
  397. if( boxOrigin.y > extentOrigin.y )
  398. extentOrigin.y = boxOrigin.y;
  399. if( boxLowerRight.x > extentLowerRight.x )
  400. extentLowerRight.x = boxLowerRight.x;
  401. if( boxLowerRight.y < extentLowerRight.y )
  402. extentLowerRight.y = boxLowerRight.y;
  403. // set global position of next cell
  404. cellOrigin.x = cellOrigin.x + lpgmf->gmfCellIncX;
  405. cellOrigin.y = cellOrigin.y + lpgmf->gmfCellIncY;
  406. }
  407. // Check for possible total lack of glyphmetric info
  408. if( extentOrigin.x == FLT_MAX ) {
  409. // Can assume if this value is still maxed out that all glyphmetric
  410. // info was NULL
  411. origin->x = origin->y = 0.0f;
  412. extent->x = extent->y = 0.0f;
  413. return 0;
  414. }
  415. *origin = extentOrigin;
  416. extent->x = extentLowerRight.x - extentOrigin.x;
  417. extent->y = extentOrigin.y - extentLowerRight.y;
  418. return len;
  419. }