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.

2006 lines
58 KiB

  1. /*++
  2. Copyright (c) 1985 - 1999, Microsoft Corporation
  3. Module Name:
  4. misc.c
  5. Abstract:
  6. This file implements the NT console server font routines.
  7. Author:
  8. Therese Stowell (thereses) 22-Jan-1991
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. #if DBG && defined(DEBUG_PRINT)
  14. #error yo!
  15. ULONG gDebugFlag;
  16. #endif
  17. ULONG NumberOfMouseButtons;
  18. PFONT_INFO FontInfo;
  19. ULONG FontInfoLength;
  20. ULONG NumberOfFonts;
  21. WCHAR DefaultFaceName[LF_FACESIZE];
  22. COORD DefaultFontSize;
  23. BYTE DefaultFontFamily;
  24. ULONG DefaultFontIndex = 0;
  25. typedef struct _FONTENUMDC {
  26. HDC hDC;
  27. BOOL bFindFaces;
  28. BOOL bFarEastOK;
  29. SHORT TTPointSize;
  30. } FONTENUMDC, *PFONTENUMDC;
  31. /*
  32. * Custom CP for glyph translations
  33. */
  34. CPTABLEINFO GlyphCP;
  35. USHORT GlyphTable[256];
  36. #define FONT_BUFFER_SIZE 12
  37. #define CHAR_NULL ((char)0)
  38. /*
  39. * Initial default fonts and face names
  40. */
  41. PFACENODE gpFaceNames;
  42. NTSTATUS
  43. GetMouseButtons(
  44. PULONG NumButtons
  45. )
  46. {
  47. *NumButtons = NumberOfMouseButtons;
  48. return STATUS_SUCCESS;
  49. }
  50. VOID
  51. InitializeMouseButtons( VOID )
  52. {
  53. NumberOfMouseButtons = GetSystemMetrics(SM_CMOUSEBUTTONS);
  54. }
  55. PFACENODE AddFaceNode(PFACENODE *ppStart, LPWSTR pwsz) {
  56. PFACENODE pNew;
  57. PFACENODE *ppTmp;
  58. int cb;
  59. /*
  60. * Is it already here?
  61. */
  62. for (ppTmp = ppStart; *ppTmp; ppTmp = &((*ppTmp)->pNext)) {
  63. if (wcscmp(((*ppTmp)->awch), pwsz) == 0) {
  64. // already there !
  65. return *ppTmp;
  66. }
  67. }
  68. cb = (wcslen(pwsz) + 1) * sizeof(WCHAR);
  69. pNew = ConsoleHeapAlloc(FONT_TAG, sizeof(FACENODE) + cb);
  70. if (pNew == NULL) {
  71. return NULL;
  72. }
  73. pNew->pNext = NULL;
  74. pNew->dwFlag = 0;
  75. wcscpy(pNew->awch, pwsz);
  76. *ppTmp = pNew;
  77. return pNew;
  78. }
  79. VOID
  80. InitializeFonts( VOID )
  81. {
  82. WCHAR FontName[CONSOLE_MAX_FONT_NAME_LENGTH];
  83. int i;
  84. static CONST LPWSTR FontList[] = {L"woafont",
  85. L"ega80woa.fon",
  86. L"ega40woa.fon",
  87. L"cga80woa.fon",
  88. L"cga40woa.fon"};
  89. //
  90. // Read software.ini to get the values for "woafont",
  91. // "ega80woa.fon", "ega40woa.fon", "cga80woa.fon", and
  92. // "cga40woa.fon", respectively, to pass to AddFontResource.
  93. //
  94. // If any of the entries are empty or non-existent,
  95. // GetPrivateProfileString will return a NULL (empty) string.
  96. // If such is the case, the call to AddPermanentFontResource will
  97. // simply fail.
  98. //
  99. OpenProfileUserMapping();
  100. for (i = 0; i < NELEM(FontList); i++) {
  101. GetPrivateProfileString(L"386enh", FontList[i], L"",
  102. FontName, NELEM(FontName), L"system.ini");
  103. GdiAddFontResourceW(FontName, AFRW_ADD_LOCAL_FONT,NULL);
  104. }
  105. CloseProfileUserMapping();
  106. }
  107. /***************************************************************************\
  108. * FontEnum
  109. *
  110. * This routine is called exactly once by GDI for each font in the system,
  111. * and is used to store the FONT_INFO structure.
  112. \***************************************************************************/
  113. int CALLBACK
  114. FontEnum(
  115. LPENUMLOGFONTW lpLogFont,
  116. LPNEWTEXTMETRICW lpTextMetric,
  117. int nFontType,
  118. LPARAM lParam
  119. )
  120. {
  121. PFONTENUMDC pfed = (PFONTENUMDC)lParam;
  122. HDC hDC = pfed->hDC;
  123. BOOL bFindFaces = pfed->bFindFaces;
  124. HFONT hFont;
  125. TEXTMETRICW tmi;
  126. LONG nFont;
  127. LONG nFontNew;
  128. COORD SizeToShow;
  129. COORD SizeActual;
  130. COORD SizeWant;
  131. BYTE tmFamily;
  132. SIZE Size;
  133. LPWSTR pwszFace = lpLogFont->elfLogFont.lfFaceName;
  134. PFACENODE pFN;
  135. DBGFONTS((" FontEnum \"%ls\" (%d,%d) weight 0x%lx(%d) -- %s\n",
  136. pwszFace,
  137. lpLogFont->elfLogFont.lfWidth, lpLogFont->elfLogFont.lfHeight,
  138. lpLogFont->elfLogFont.lfWeight, lpLogFont->elfLogFont.lfWeight,
  139. bFindFaces ? "Finding Faces" : "Creating Fonts"));
  140. //
  141. // reject variable width and italic fonts, also tt fonts with neg ac
  142. //
  143. if
  144. (
  145. !(lpLogFont->elfLogFont.lfPitchAndFamily & FIXED_PITCH) ||
  146. (lpLogFont->elfLogFont.lfItalic) ||
  147. !(lpTextMetric->ntmFlags & NTM_NONNEGATIVE_AC)
  148. )
  149. {
  150. if (!IsAvailableTTFont(pwszFace))
  151. {
  152. DBGFONTS((" REJECT face (variable pitch, italic, or neg a&c)\n"));
  153. return bFindFaces ? TRUE : FALSE; // unsuitable font
  154. }
  155. }
  156. if (nFontType == TRUETYPE_FONTTYPE) {
  157. lpLogFont->elfLogFont.lfHeight = pfed->TTPointSize;
  158. lpLogFont->elfLogFont.lfWidth = 0;
  159. lpLogFont->elfLogFont.lfWeight = FW_NORMAL;
  160. }
  161. /*
  162. * reject TT fonts for whoom family is not modern, that is do not use
  163. * FF_DONTCARE // may be surprised unpleasantly
  164. * FF_DECORATIVE // likely to be symbol fonts
  165. * FF_SCRIPT // cursive, inappropriate for console
  166. * FF_SWISS OR FF_ROMAN // variable pitch
  167. */
  168. if ((nFontType == TRUETYPE_FONTTYPE) &&
  169. ((lpLogFont->elfLogFont.lfPitchAndFamily & 0xf0) != FF_MODERN)) {
  170. DBGFONTS((" REJECT face (TT but not FF_MODERN)\n"));
  171. return bFindFaces ? TRUE : FALSE; // unsuitable font
  172. }
  173. /*
  174. * reject non-TT fonts that aren't OEM
  175. */
  176. if ((nFontType != TRUETYPE_FONTTYPE) &&
  177. #if defined(FE_SB)
  178. (!CONSOLE_IS_DBCS_ENABLED() ||
  179. !IS_ANY_DBCS_CHARSET(lpLogFont->elfLogFont.lfCharSet)) &&
  180. #endif
  181. (lpLogFont->elfLogFont.lfCharSet != OEM_CHARSET)) {
  182. DBGFONTS((" REJECT face (not TT nor OEM)\n"));
  183. return bFindFaces ? TRUE : FALSE; // unsuitable font
  184. }
  185. /*
  186. * reject non-TT fonts that are virtical font
  187. */
  188. if ((nFontType != TRUETYPE_FONTTYPE) &&
  189. (pwszFace[0] == L'@')) {
  190. DBGFONTS((" REJECT face (not TT and TATEGAKI)\n"));
  191. return bFindFaces ? TRUE : FALSE; // unsuitable font
  192. }
  193. /*
  194. * reject non-TT fonts that aren't Terminal
  195. */
  196. if (CONSOLE_IS_DBCS_ENABLED() &&
  197. (nFontType != TRUETYPE_FONTTYPE) &&
  198. (wcscmp(pwszFace, L"Terminal") != 0)) {
  199. DBGFONTS((" REJECT face (not TT nor Terminal)\n"));
  200. return bFindFaces ? TRUE : FALSE; // unsuitable font
  201. }
  202. /*
  203. * reject Far East TT fonts that aren't Far East charset.
  204. */
  205. if (IsAvailableTTFont(pwszFace) &&
  206. !IS_ANY_DBCS_CHARSET(lpLogFont->elfLogFont.lfCharSet) &&
  207. !IsAvailableTTFontCP(pwszFace,0)
  208. ) {
  209. DBGFONTS((" REJECT face (Far East TT and not Far East charset)\n"));
  210. return TRUE; // should be enumerate next charset.
  211. }
  212. /*
  213. * Add or find the facename
  214. */
  215. pFN = AddFaceNode(&gpFaceNames, pwszFace);
  216. if (pFN == NULL) {
  217. return FALSE;
  218. }
  219. if (bFindFaces) {
  220. if (nFontType == TRUETYPE_FONTTYPE) {
  221. DBGFONTS(("NEW TT FACE %ls\n", pwszFace));
  222. pFN->dwFlag |= EF_TTFONT;
  223. } else if (nFontType == RASTER_FONTTYPE) {
  224. DBGFONTS(("NEW OEM FACE %ls\n",pwszFace));
  225. pFN->dwFlag |= EF_OEMFONT;
  226. }
  227. return 0;
  228. }
  229. if (IS_BOLD(lpLogFont->elfLogFont.lfWeight)) {
  230. DBGFONTS2((" A bold font (weight %d)\n", lpLogFont->elfLogFont.lfWeight));
  231. // return 0;
  232. }
  233. /* get font info */
  234. SizeWant.Y = (SHORT)lpLogFont->elfLogFont.lfHeight;
  235. SizeWant.X = (SHORT)lpLogFont->elfLogFont.lfWidth;
  236. CreateBoldFont:
  237. lpLogFont->elfLogFont.lfQuality = DEFAULT_QUALITY;
  238. hFont = CreateFontIndirectW(&lpLogFont->elfLogFont);
  239. if (!hFont) {
  240. DBGFONTS((" REJECT font (can't create)\n"));
  241. RIPMSG0(RIP_WARNING, "FontEnum: CreateFontIndirectW returned NULL hFont.");
  242. return 0; // same font in other sizes may still be suitable
  243. }
  244. DBGFONTS2((" hFont = %lx\n", hFont));
  245. //
  246. // for reasons unbeknownst to me, removing this code causes GDI
  247. // to yack, claiming that the font is owned by another process.
  248. //
  249. SelectObject(hDC,hFont);
  250. if (!GetTextMetricsW(hDC, &tmi)) {
  251. tmi = *((LPTEXTMETRICW)lpTextMetric);
  252. }
  253. if (GetTextExtentPoint32W(hDC, L"0", 1, &Size)) {
  254. SizeActual.X = (SHORT)Size.cx;
  255. } else {
  256. SizeActual.X = (SHORT)(tmi.tmMaxCharWidth);
  257. }
  258. SizeActual.Y = (SHORT)(tmi.tmHeight + tmi.tmExternalLeading);
  259. DBGFONTS2((" actual size %d,%d\n", SizeActual.X, SizeActual.Y));
  260. tmFamily = tmi.tmPitchAndFamily;
  261. if (TM_IS_TT_FONT(tmFamily) && (SizeWant.Y >= 0)) {
  262. SizeToShow = SizeWant;
  263. if (SizeWant.X == 0) {
  264. // Asking for zero width height gets a default aspect-ratio width
  265. // It's better to show that width rather than 0.
  266. SizeToShow.X = SizeActual.X;
  267. }
  268. } else {
  269. SizeToShow = SizeActual;
  270. }
  271. DBGFONTS2((" SizeToShow = (%d,%d), SizeActual = (%d,%d)\n",
  272. SizeToShow.X, SizeToShow.Y, SizeActual.X, SizeActual.Y));
  273. // there's a GDI bug - this assert fails occasionally
  274. //ASSERT (tmi.tmw.tmMaxCharWidth == lpTextMetric->tmMaxCharWidth);
  275. /*
  276. * NOW, determine whether this font entry has already been cached
  277. * LATER : it may be possible to do this before creating the font, if
  278. * we can trust the dimensions & other info from lpTextMetric.
  279. * Sort by size:
  280. * 1) By pixelheight (negative Y values)
  281. * 2) By height (as shown)
  282. * 3) By width (as shown)
  283. */
  284. for (nFont = 0; nFont < (LONG)NumberOfFonts; ++nFont) {
  285. COORD SizeShown;
  286. if (FontInfo[nFont].hFont == NULL) {
  287. DBGFONTS(("! Font %x has a NULL hFont\n", nFont));
  288. continue;
  289. }
  290. if (FontInfo[nFont].SizeWant.X > 0) {
  291. SizeShown.X = FontInfo[nFont].SizeWant.X;
  292. } else {
  293. SizeShown.X = FontInfo[nFont].Size.X;
  294. }
  295. if (FontInfo[nFont].SizeWant.Y > 0) {
  296. // This is a font specified by cell height.
  297. SizeShown.Y = FontInfo[nFont].SizeWant.Y;
  298. } else {
  299. SizeShown.Y = FontInfo[nFont].Size.Y;
  300. if (FontInfo[nFont].SizeWant.Y < 0) {
  301. // This is a TT font specified by character height.
  302. if (SizeWant.Y < 0 && SizeWant.Y > FontInfo[nFont].SizeWant.Y) {
  303. // Requested pixelheight is smaller than this one.
  304. DBGFONTS(("INSERT %d pt at %x, before %d pt\n",
  305. -SizeWant.Y, nFont, -FontInfo[nFont].SizeWant.Y));
  306. nFontNew = nFont;
  307. goto InsertNewFont;
  308. }
  309. }
  310. }
  311. // DBGFONTS((" SizeShown(%x) = (%d,%d)\n",nFont,SizeShown.X,SizeShown.Y));
  312. if (SIZE_EQUAL(SizeShown, SizeToShow) &&
  313. FontInfo[nFont].Family == tmFamily &&
  314. FontInfo[nFont].Weight == tmi.tmWeight &&
  315. wcscmp(FontInfo[nFont].FaceName, pwszFace) == 0) {
  316. /*
  317. * Already have this font
  318. */
  319. DBGFONTS2((" Already have the font\n"));
  320. DeleteObject(hFont);
  321. pfed->bFarEastOK = TRUE;
  322. return TRUE;
  323. }
  324. if ((SizeToShow.Y < SizeShown.Y) ||
  325. (SizeToShow.Y == SizeShown.Y && SizeToShow.X < SizeShown.X)) {
  326. /*
  327. * This new font is smaller than nFont
  328. */
  329. DBGFONTS(("INSERT at %x, SizeToShow = (%d,%d)\n", nFont,
  330. SizeToShow.X,SizeToShow.Y));
  331. nFontNew = nFont;
  332. goto InsertNewFont;
  333. }
  334. }
  335. /*
  336. * The font we are adding should be appended to the list,
  337. * since it is bigger (or equal) to the last one.
  338. */
  339. nFontNew = (LONG)NumberOfFonts;
  340. InsertNewFont: // at nFontNew
  341. // ASSERT ((lpTextMetric->tmPitchAndFamily & 1) == 0);
  342. /* If we have to grow our font table, do it */
  343. if (NumberOfFonts == FontInfoLength) {
  344. PFONT_INFO Temp;
  345. FontInfoLength += FONT_INCREMENT;
  346. Temp = ConsoleHeapReAlloc(FONT_TAG, FontInfo, sizeof(FONT_INFO) * FontInfoLength);
  347. if (Temp == NULL) {
  348. RIPMSG0(RIP_WARNING, "FontEnum: failed to allocate PFONT_INFO");
  349. FontInfoLength -= FONT_INCREMENT;
  350. return FALSE;
  351. }
  352. FontInfo = Temp;
  353. }
  354. if (nFontNew < (LONG)NumberOfFonts) {
  355. RtlMoveMemory(&FontInfo[nFontNew+1],
  356. &FontInfo[nFontNew],
  357. sizeof(FONT_INFO)*(NumberOfFonts - nFontNew));
  358. //
  359. // Fix up DefaultFontIndex if nFontNew less than DefaultFontIndex.
  360. //
  361. if (nFontNew < (LONG)DefaultFontIndex &&
  362. DefaultFontIndex+1 < NumberOfFonts) {
  363. DefaultFontIndex++;
  364. }
  365. }
  366. /*
  367. * Store the font info
  368. */
  369. FontInfo[nFontNew].hFont = hFont;
  370. FontInfo[nFontNew].Family = tmFamily;
  371. FontInfo[nFontNew].Size = SizeActual;
  372. if (TM_IS_TT_FONT(tmFamily)) {
  373. FontInfo[nFontNew].SizeWant = SizeWant;
  374. } else {
  375. FontInfo[nFontNew].SizeWant.X = 0;
  376. FontInfo[nFontNew].SizeWant.Y = 0;
  377. }
  378. FontInfo[nFontNew].Weight = tmi.tmWeight;
  379. FontInfo[nFont].FaceName = pFN->awch;
  380. #if defined(FE_SB)
  381. FontInfo[nFontNew].tmCharSet = tmi.tmCharSet;
  382. #endif
  383. ++NumberOfFonts;
  384. if (nFontType == TRUETYPE_FONTTYPE && !IS_BOLD(FontInfo[nFontNew].Weight)) {
  385. lpLogFont->elfLogFont.lfWeight = FW_BOLD;
  386. goto CreateBoldFont;
  387. }
  388. pfed->bFarEastOK = TRUE; // and continue enumeration
  389. return TRUE;
  390. }
  391. BOOL
  392. DoFontEnum(
  393. HDC hDC,
  394. LPWSTR pwszFace,
  395. SHORT TTPointSize)
  396. {
  397. BOOL bDeleteDC = FALSE;
  398. BOOL bFindFaces = (pwszFace == NULL);
  399. FONTENUMDC fed;
  400. LOGFONTW LogFont;
  401. DBGFONTS(("DoFontEnum \"%ls\"\n", pwszFace));
  402. if (hDC == NULL) {
  403. hDC = CreateDCW(L"DISPLAY", NULL, NULL, NULL);
  404. bDeleteDC = TRUE;
  405. }
  406. fed.hDC = hDC;
  407. fed.bFindFaces = bFindFaces;
  408. fed.bFarEastOK = FALSE;
  409. fed.TTPointSize = TTPointSize;
  410. RtlZeroMemory(&LogFont, sizeof(LOGFONT));
  411. LogFont.lfCharSet = DEFAULT_CHARSET;
  412. if (pwszFace) {
  413. wcscpy(LogFont.lfFaceName, pwszFace);
  414. }
  415. /*
  416. * EnumFontFamiliesEx function enumerates one font in every face in
  417. * every character set.
  418. */
  419. EnumFontFamiliesExW(hDC, &LogFont, (FONTENUMPROC)FontEnum, (LPARAM)&fed, 0);
  420. if (bDeleteDC) {
  421. DeleteDC(hDC);
  422. }
  423. return fed.bFarEastOK;
  424. }
  425. NTSTATUS
  426. EnumerateFonts(
  427. DWORD Flags)
  428. {
  429. TEXTMETRIC tmi;
  430. HDC hDC;
  431. PFACENODE pFN;
  432. ULONG ulOldEnumFilter;
  433. DWORD FontIndex;
  434. DWORD dwFontType = 0;
  435. DBGFONTS(("EnumerateFonts %lx\n", Flags));
  436. dwFontType = (EF_TTFONT|EF_OEMFONT|EF_DEFFACE) & Flags;
  437. if (FontInfo == NULL) {
  438. //
  439. // Allocate memory for the font array.
  440. //
  441. NumberOfFonts = 0;
  442. FontInfo = ConsoleHeapAlloc(FONT_TAG, sizeof(FONT_INFO) * INITIAL_FONTS);
  443. if (FontInfo == NULL) {
  444. return STATUS_NO_MEMORY;
  445. }
  446. FontInfoLength = INITIAL_FONTS;
  447. }
  448. hDC = CreateDCW(L"DISPLAY",NULL,NULL,NULL);
  449. // Before enumeration, turn off font enumeration filters.
  450. ulOldEnumFilter = SetFontEnumeration(0);
  451. // restore all the other flags
  452. SetFontEnumeration(ulOldEnumFilter & ~FE_FILTER_TRUETYPE);
  453. if (Flags & EF_DEFFACE) {
  454. SelectObject(hDC,GetStockObject(OEM_FIXED_FONT));
  455. if (GetTextMetricsW(hDC, &tmi)) {
  456. DefaultFontSize.X = (SHORT)(tmi.tmMaxCharWidth);
  457. DefaultFontSize.Y = (SHORT)(tmi.tmHeight+tmi.tmExternalLeading);
  458. DefaultFontFamily = tmi.tmPitchAndFamily;
  459. #if defined(FE_SB)
  460. if (IS_ANY_DBCS_CHARSET(tmi.tmCharSet))
  461. DefaultFontSize.X /= 2;
  462. #endif
  463. }
  464. GetTextFaceW(hDC, LF_FACESIZE, DefaultFaceName);
  465. #if defined(FE_SB)
  466. DBGFONTS(("Default (OEM) Font %ls (%d,%d) CharSet 0x%02X\n", DefaultFaceName,
  467. DefaultFontSize.X, DefaultFontSize.Y,
  468. tmi.tmCharSet));
  469. #else
  470. DBGFONTS(("Default (OEM) Font %ls (%d,%d)\n", DefaultFaceName,
  471. DefaultFontSize.X, DefaultFontSize.Y));
  472. #endif
  473. // Make sure we are going to enumerate the OEM face.
  474. pFN = AddFaceNode(&gpFaceNames, DefaultFaceName);
  475. if (pFN) {
  476. pFN->dwFlag |= EF_DEFFACE | EF_OEMFONT;
  477. }
  478. }
  479. // Use DoFontEnum to get all fonts from the system. Our FontEnum
  480. // proc puts just the ones we want into an array
  481. //
  482. for (pFN = gpFaceNames; pFN; pFN = pFN->pNext) {
  483. DBGFONTS(("\"%ls\" is %s%s%s%s%s%s\n", pFN->awch,
  484. pFN->dwFlag & EF_NEW ? "NEW " : " ",
  485. pFN->dwFlag & EF_OLD ? "OLD " : " ",
  486. pFN->dwFlag & EF_ENUMERATED ? "ENUMERATED " : " ",
  487. pFN->dwFlag & EF_OEMFONT ? "OEMFONT " : " ",
  488. pFN->dwFlag & EF_TTFONT ? "TTFONT " : " ",
  489. pFN->dwFlag & EF_DEFFACE ? "DEFFACE " : " "));
  490. if ((pFN->dwFlag & dwFontType) == 0) {
  491. // not the kind of face we want
  492. continue;
  493. }
  494. if (pFN->dwFlag & EF_ENUMERATED) {
  495. // we already enumerated this face
  496. continue;
  497. }
  498. DoFontEnum(hDC, pFN->awch, DefaultFontSize.Y);
  499. pFN->dwFlag |= EF_ENUMERATED;
  500. }
  501. // After enumerating fonts, restore the font enumeration filter.
  502. SetFontEnumeration(ulOldEnumFilter);
  503. DeleteDC(hDC);
  504. // Make sure the default font is set correctly
  505. if (NumberOfFonts > 0 && DefaultFontSize.X == 0 && DefaultFontSize.Y == 0) {
  506. DefaultFontSize.X = FontInfo[0].Size.X;
  507. DefaultFontSize.Y = FontInfo[0].Size.Y;
  508. DefaultFontFamily = FontInfo[0].Family;
  509. }
  510. for (FontIndex = 0; FontIndex < NumberOfFonts; FontIndex++) {
  511. if (FontInfo[FontIndex].Size.X == DefaultFontSize.X &&
  512. FontInfo[FontIndex].Size.Y == DefaultFontSize.Y &&
  513. FontInfo[FontIndex].Family == DefaultFontFamily) {
  514. #if defined(FE_SB)
  515. if (CONSOLE_IS_DBCS_ENABLED() &&
  516. !IS_ANY_DBCS_CHARSET(FontInfo[FontIndex].tmCharSet))
  517. {
  518. continue ;
  519. }
  520. #endif
  521. break;
  522. }
  523. }
  524. ASSERT(FontIndex < NumberOfFonts);
  525. if (FontIndex < NumberOfFonts) {
  526. DefaultFontIndex = FontIndex;
  527. } else {
  528. DefaultFontIndex = 0;
  529. }
  530. DBGFONTS(("EnumerateFonts : DefaultFontIndex = %ld\n", DefaultFontIndex));
  531. return STATUS_SUCCESS;
  532. }
  533. /*
  534. * Get the font index for a new font
  535. * If necessary, attempt to create the font.
  536. * Always return a valid FontIndex (even if not correct)
  537. * Family: Find/Create a font with of this Family
  538. * 0 - don't care
  539. * pwszFace: Find/Create a font with this face name.
  540. * NULL or L"" - use DefaultFaceName
  541. * Size: Must match SizeWant or actual Size.
  542. */
  543. int
  544. FindCreateFont(
  545. DWORD Family,
  546. LPWSTR pwszFace,
  547. COORD Size,
  548. LONG Weight,
  549. UINT CodePage)
  550. {
  551. #define NOT_CREATED_NOR_FOUND -1
  552. #define CREATED_BUT_NOT_FOUND -2
  553. int i;
  554. int FontIndex = NOT_CREATED_NOR_FOUND;
  555. int BestMatch = NOT_CREATED_NOR_FOUND;
  556. BOOL bFontOK;
  557. WCHAR AltFaceName[LF_FACESIZE];
  558. COORD AltFontSize;
  559. BYTE AltFontFamily;
  560. ULONG AltFontIndex = 0;
  561. LPWSTR pwszAltFace = NULL;
  562. BYTE CharSet = CodePageToCharSet(CodePage);
  563. DBGFONTS(("FindCreateFont Family=%x %ls (%d,%d) %d %d %x\n",
  564. Family, pwszFace, Size.X, Size.Y, Weight, CodePage, CharSet));
  565. if (CONSOLE_IS_DBCS_ENABLED() &&
  566. !IS_ANY_DBCS_CHARSET(CharSet))
  567. {
  568. MakeAltRasterFont(CodePage, FontInfo[DefaultFontIndex].Size,
  569. &AltFontSize, &AltFontFamily, &AltFontIndex, AltFaceName);
  570. if (pwszFace == NULL || *pwszFace == L'\0') {
  571. pwszFace = AltFaceName;
  572. }
  573. if (Size.Y == 0) {
  574. Size.X = AltFontSize.X;
  575. Size.Y = AltFontSize.Y;
  576. }
  577. }
  578. else {
  579. if (pwszFace == NULL || *pwszFace == L'\0') {
  580. pwszFace = DefaultFaceName;
  581. }
  582. if (Size.Y == 0) {
  583. Size.X = DefaultFontSize.X;
  584. Size.Y = DefaultFontSize.Y;
  585. }
  586. }
  587. if (IsAvailableTTFont(pwszFace)) {
  588. pwszAltFace = GetAltFaceName(pwszFace);
  589. }
  590. else {
  591. pwszAltFace = pwszFace;
  592. }
  593. /*
  594. * Try to find the exact font
  595. */
  596. TryFindExactFont:
  597. for (i=0; i < (int)NumberOfFonts; i++) {
  598. /*
  599. * If looking for a particular Family, skip non-matches
  600. */
  601. if ((Family != 0) &&
  602. ((BYTE)Family != FontInfo[i].Family)) {
  603. continue;
  604. }
  605. /*
  606. * Skip non-matching sizes
  607. */
  608. if ((FontInfo[i].SizeWant.Y != Size.Y) &&
  609. !SIZE_EQUAL(FontInfo[i].Size, Size)) {
  610. continue;
  611. }
  612. /*
  613. * Skip non-matching weights
  614. */
  615. if ((Weight != 0) && (Weight != FontInfo[i].Weight)) {
  616. continue;
  617. }
  618. #if defined(FE_SB)
  619. if (!TM_IS_TT_FONT(FontInfo[i].Family) &&
  620. FontInfo[i].tmCharSet != CharSet) {
  621. continue;
  622. }
  623. #endif
  624. /*
  625. * Size (and maybe Family) match.
  626. * If we don't care about the name, or if it matches, use this font.
  627. * Else if name doesn't match and it is a raster font, consider it.
  628. */
  629. if ((pwszFace == NULL) || (pwszFace[0] == L'\0') ||
  630. wcscmp(FontInfo[i].FaceName, pwszFace) == 0 ||
  631. wcscmp(FontInfo[i].FaceName, pwszAltFace) == 0
  632. ) {
  633. FontIndex = i;
  634. goto FoundFont;
  635. } else if (!TM_IS_TT_FONT(FontInfo[i].Family)) {
  636. BestMatch = i;
  637. }
  638. }
  639. /*
  640. * Didn't find the exact font, so try to create it
  641. */
  642. if (FontIndex == NOT_CREATED_NOR_FOUND) {
  643. ULONG ulOldEnumFilter;
  644. ulOldEnumFilter = SetFontEnumeration(0);
  645. // restore all the other flags
  646. SetFontEnumeration(ulOldEnumFilter & ~FE_FILTER_TRUETYPE);
  647. if (Size.Y < 0) {
  648. Size.Y = -Size.Y;
  649. }
  650. bFontOK = DoFontEnum(NULL, pwszFace, Size.Y);
  651. SetFontEnumeration(ulOldEnumFilter);
  652. if (bFontOK) {
  653. DBGFONTS(("FindCreateFont created font!\n"));
  654. FontIndex = CREATED_BUT_NOT_FOUND;
  655. goto TryFindExactFont;
  656. } else {
  657. DBGFONTS(("FindCreateFont failed to create font!\n"));
  658. }
  659. }
  660. /*
  661. * Failed to find exact match, but we have a close Raster Font
  662. * fit - only the name doesn't match.
  663. */
  664. if (BestMatch >= 0) {
  665. FontIndex = BestMatch;
  666. goto FoundFont;
  667. }
  668. /*
  669. * Failed to find exact match, even after enumeration, so now try
  670. * to find a font of same family and same size or bigger
  671. */
  672. for (i=0; i < (int)NumberOfFonts; i++) {
  673. #if defined(FE_SB)
  674. if (CONSOLE_IS_DBCS_ENABLED()) {
  675. if ((Family != 0) &&
  676. ((BYTE)Family != FontInfo[i].Family)) {
  677. continue;
  678. }
  679. if (!TM_IS_TT_FONT(FontInfo[i].Family) &&
  680. FontInfo[i].tmCharSet != CharSet) {
  681. continue;
  682. }
  683. }
  684. else {
  685. #endif
  686. if ((BYTE)Family != FontInfo[i].Family) {
  687. continue;
  688. }
  689. #if defined(FE_SB)
  690. }
  691. #endif
  692. if (FontInfo[i].Size.Y >= Size.Y &&
  693. FontInfo[i].Size.X >= Size.X) {
  694. // Same family, size >= desired.
  695. FontIndex = i;
  696. break;
  697. }
  698. }
  699. if (FontIndex < 0) {
  700. DBGFONTS(("FindCreateFont defaults!\n"));
  701. #if defined(FE_SB)
  702. if (CONSOLE_IS_DBCS_ENABLED() &&
  703. !IsAvailableFarEastCodePage(CodePage))
  704. {
  705. FontIndex = AltFontIndex;
  706. }
  707. else
  708. #endif
  709. FontIndex = DefaultFontIndex;
  710. }
  711. FoundFont:
  712. DBGFONTS(("FindCreateFont returns %x : %ls (%d,%d)\n", FontIndex,
  713. FontInfo[FontIndex].FaceName,
  714. FontInfo[FontIndex].Size.X, FontInfo[FontIndex].Size.Y));
  715. return FontIndex;
  716. #undef NOT_CREATED_NOR_FOUND
  717. #undef CREATED_BUT_NOT_FOUND
  718. }
  719. NTSTATUS
  720. FindTextBufferFontInfo(
  721. IN PSCREEN_INFORMATION ScreenInfo,
  722. IN UINT CodePage,
  723. OUT PTEXT_BUFFER_FONT_INFO TextFontInfo
  724. )
  725. /*++
  726. Routine Description:
  727. This routine find a font information which correspond to code page value.
  728. Arguments:
  729. Return Value:
  730. --*/
  731. {
  732. PTEXT_BUFFER_FONT_INFO CurrentFont;
  733. CurrentFont = ScreenInfo->BufferInfo.TextInfo.ListOfTextBufferFont;
  734. while (CurrentFont != NULL) {
  735. if (CurrentFont->FontCodePage == CodePage) {
  736. *TextFontInfo = *CurrentFont;
  737. return STATUS_SUCCESS;
  738. }
  739. CurrentFont = CurrentFont->NextTextBufferFont;
  740. }
  741. return STATUS_UNSUCCESSFUL;
  742. }
  743. NTSTATUS
  744. StoreTextBufferFontInfo(
  745. IN PSCREEN_INFORMATION ScreenInfo,
  746. IN ULONG FontIndex,
  747. IN COORD FontSize,
  748. IN BYTE FontFamily,
  749. IN LONG FontWeight,
  750. IN LPWSTR FaceName,
  751. IN UINT CodePage
  752. )
  753. /*++
  754. Routine Description:
  755. This routine store a font information in CurrentTextBufferFont and ListOfTextBufferFont.
  756. If specified code page does not exist in ListOfTextBufferFont, then create new list.
  757. Arguments:
  758. Return Value:
  759. --*/
  760. {
  761. PTEXT_BUFFER_FONT_INFO CurrentFont, PrevFont;
  762. CurrentFont = ScreenInfo->BufferInfo.TextInfo.ListOfTextBufferFont;
  763. while (CurrentFont != NULL) {
  764. if (CurrentFont->FontCodePage == CodePage) {
  765. CurrentFont->FontNumber = FontIndex;
  766. CurrentFont->FontSize = FontSize;
  767. CurrentFont->Family = FontFamily;
  768. CurrentFont->Weight = FontWeight;
  769. // CurrentFont->FontCodePage = CodePage; // Redundant
  770. wcscpy(CurrentFont->FaceName, FaceName);
  771. break;
  772. }
  773. PrevFont = CurrentFont;
  774. CurrentFont = CurrentFont->NextTextBufferFont;
  775. }
  776. if (CurrentFont == NULL) {
  777. CurrentFont = ConsoleHeapAlloc(FONT_TAG, sizeof(TEXT_BUFFER_FONT_INFO));
  778. if (CurrentFont == NULL) {
  779. return STATUS_NO_MEMORY;
  780. }
  781. CurrentFont->NextTextBufferFont = NULL;
  782. CurrentFont->FontNumber = FontIndex;
  783. CurrentFont->FontSize = FontSize;
  784. CurrentFont->Family = FontFamily;
  785. CurrentFont->Weight = FontWeight;
  786. CurrentFont->FontCodePage = CodePage;
  787. wcscpy(CurrentFont->FaceName, FaceName);
  788. if (ScreenInfo->BufferInfo.TextInfo.ListOfTextBufferFont == NULL) {
  789. ScreenInfo->BufferInfo.TextInfo.ListOfTextBufferFont = CurrentFont;
  790. }
  791. else {
  792. PrevFont->NextTextBufferFont = CurrentFont;
  793. }
  794. }
  795. ScreenInfo->BufferInfo.TextInfo.CurrentTextBufferFont = *CurrentFont;
  796. ScreenInfo->BufferInfo.TextInfo.CurrentTextBufferFont.NextTextBufferFont = NULL;
  797. return STATUS_SUCCESS;
  798. }
  799. NTSTATUS
  800. RemoveTextBufferFontInfo(
  801. IN PSCREEN_INFORMATION ScreenInfo
  802. )
  803. /*++
  804. Routine Description:
  805. This routine all remove a font information in ListOfTextBufferFont.
  806. Arguments:
  807. Return Value:
  808. --*/
  809. {
  810. PTEXT_BUFFER_FONT_INFO CurrentFont;
  811. CurrentFont = ScreenInfo->BufferInfo.TextInfo.ListOfTextBufferFont;
  812. while (CurrentFont != NULL) {
  813. PTEXT_BUFFER_FONT_INFO NextFont;
  814. NextFont = CurrentFont->NextTextBufferFont;
  815. ConsoleHeapFree(CurrentFont);
  816. CurrentFont = NextFont;
  817. }
  818. ScreenInfo->BufferInfo.TextInfo.ListOfTextBufferFont = NULL;
  819. return STATUS_SUCCESS;
  820. }
  821. NTSTATUS
  822. GetNumFonts(
  823. OUT PULONG NumFonts
  824. )
  825. {
  826. *NumFonts = NumberOfFonts;
  827. return STATUS_SUCCESS;
  828. }
  829. NTSTATUS
  830. GetAvailableFonts(
  831. IN PSCREEN_INFORMATION ScreenInfo,
  832. IN BOOLEAN MaximumWindow,
  833. OUT PVOID Buffer,
  834. IN OUT PULONG NumFonts
  835. )
  836. {
  837. PCONSOLE_FONT_INFO BufPtr;
  838. ULONG i;
  839. COORD WindowSize;
  840. WINDOW_LIMITS WindowLimits;
  841. //
  842. // if the buffer is too small to return all the fonts, return
  843. // the number that will fit.
  844. //
  845. *NumFonts = (*NumFonts > NumberOfFonts) ? NumberOfFonts : *NumFonts;
  846. //
  847. // convert font size in pixels to font size in rows/columns
  848. //
  849. BufPtr = (PCONSOLE_FONT_INFO)Buffer;
  850. if (MaximumWindow) {
  851. GetWindowLimits(ScreenInfo, &WindowLimits);
  852. WindowSize = WindowLimits.MaximumWindowSize;
  853. }
  854. else {
  855. WindowSize.X = (SHORT)CONSOLE_WINDOW_SIZE_X(ScreenInfo);
  856. WindowSize.Y = (SHORT)CONSOLE_WINDOW_SIZE_Y(ScreenInfo);
  857. }
  858. for (i=0;i<*NumFonts;i++,BufPtr++) {
  859. BufPtr->nFont = i;
  860. BufPtr->dwFontSize.X = WindowSize.X * SCR_FONTSIZE(ScreenInfo).X / FontInfo[i].Size.X;
  861. BufPtr->dwFontSize.Y = WindowSize.Y * SCR_FONTSIZE(ScreenInfo).Y / FontInfo[i].Size.Y;
  862. }
  863. return STATUS_SUCCESS;
  864. }
  865. NTSTATUS
  866. GetFontSize(
  867. IN DWORD FontIndex,
  868. OUT PCOORD FontSize
  869. )
  870. {
  871. if (FontIndex >= NumberOfFonts)
  872. return STATUS_INVALID_PARAMETER;
  873. *FontSize = FontInfo[FontIndex].Size;
  874. return STATUS_SUCCESS;
  875. }
  876. NTSTATUS
  877. GetCurrentFont(
  878. IN PSCREEN_INFORMATION ScreenInfo,
  879. IN BOOLEAN MaximumWindow,
  880. OUT PULONG FontIndex,
  881. OUT PCOORD FontSize
  882. )
  883. {
  884. COORD WindowSize;
  885. WINDOW_LIMITS WindowLimits;
  886. if (MaximumWindow) {
  887. GetWindowLimits(ScreenInfo, &WindowLimits);
  888. WindowSize = WindowLimits.MaximumWindowSize;
  889. }
  890. else {
  891. WindowSize.X = (SHORT)CONSOLE_WINDOW_SIZE_X(ScreenInfo);
  892. WindowSize.Y = (SHORT)CONSOLE_WINDOW_SIZE_Y(ScreenInfo);
  893. }
  894. *FontIndex = SCR_FONTNUMBER(ScreenInfo);
  895. *FontSize = WindowSize;
  896. return STATUS_SUCCESS;
  897. }
  898. NTSTATUS
  899. SetScreenBufferFont(
  900. IN PSCREEN_INFORMATION ScreenInfo,
  901. IN ULONG FontIndex,
  902. IN UINT CodePage
  903. )
  904. {
  905. COORD FontSize;
  906. WINDOW_LIMITS WindowLimits;
  907. NTSTATUS Status;
  908. ULONG ulFlagPrev;
  909. DBGFONTS(("SetScreenBufferFont %lx %x\n", ScreenInfo, FontIndex));
  910. if (ScreenInfo == NULL) {
  911. /* If shutdown occurs with font dlg up */
  912. return STATUS_SUCCESS;
  913. }
  914. /*
  915. * Don't try to set the font if we're not in text mode
  916. */
  917. if (!(ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER)) {
  918. return STATUS_UNSUCCESSFUL;
  919. }
  920. Status = GetFontSize(FontIndex, &FontSize);
  921. if (!NT_SUCCESS(Status)) {
  922. return((ULONG) Status);
  923. }
  924. ulFlagPrev = ScreenInfo->Flags;
  925. if (TM_IS_TT_FONT(FontInfo[FontIndex].Family)) {
  926. ScreenInfo->Flags &= ~CONSOLE_OEMFONT_DISPLAY;
  927. } else {
  928. ScreenInfo->Flags |= CONSOLE_OEMFONT_DISPLAY;
  929. }
  930. /*
  931. * Convert from UnicodeOem to Unicode or vice-versa if necessary
  932. */
  933. if ((ulFlagPrev & CONSOLE_OEMFONT_DISPLAY) != (ScreenInfo->Flags & CONSOLE_OEMFONT_DISPLAY)) {
  934. if (ulFlagPrev & CONSOLE_OEMFONT_DISPLAY) {
  935. /*
  936. * Must convert from UnicodeOem to real Unicode
  937. */
  938. DBGCHARS(("SetScreenBufferFont converts UnicodeOem to Unicode\n"));
  939. FalseUnicodeToRealUnicode(
  940. ScreenInfo->BufferInfo.TextInfo.TextRows,
  941. ScreenInfo->ScreenBufferSize.X * ScreenInfo->ScreenBufferSize.Y,
  942. ScreenInfo->Console->OutputCP);
  943. } else {
  944. /*
  945. * Must convert from real Unicode to UnicodeOem
  946. */
  947. DBGCHARS(("SetScreenBufferFont converts Unicode to UnicodeOem\n"));
  948. RealUnicodeToFalseUnicode(
  949. ScreenInfo->BufferInfo.TextInfo.TextRows,
  950. ScreenInfo->ScreenBufferSize.X * ScreenInfo->ScreenBufferSize.Y,
  951. ScreenInfo->Console->OutputCP);
  952. }
  953. }
  954. /*
  955. * Store font properties
  956. */
  957. Status = StoreTextBufferFontInfo(ScreenInfo,
  958. FontIndex,
  959. FontSize,
  960. FontInfo[FontIndex].Family,
  961. FontInfo[FontIndex].Weight,
  962. FontInfo[FontIndex].FaceName,
  963. CodePage);
  964. if (!NT_SUCCESS(Status)) {
  965. return((ULONG) Status);
  966. }
  967. //
  968. // set font
  969. //
  970. Status = SetFont(ScreenInfo);
  971. if (!NT_SUCCESS(Status)) {
  972. return((ULONG) Status);
  973. }
  974. //
  975. // if window is growing, make sure it's not bigger than the screen.
  976. //
  977. GetWindowLimits(ScreenInfo, &WindowLimits);
  978. if (WindowLimits.MaximumWindowSize.X < CONSOLE_WINDOW_SIZE_X(ScreenInfo)) {
  979. ScreenInfo->Window.Right -= CONSOLE_WINDOW_SIZE_X(ScreenInfo) - WindowLimits.MaximumWindowSize.X;
  980. ScreenInfo->WindowMaximizedX = (ScreenInfo->Window.Left == 0 &&
  981. (SHORT)(ScreenInfo->Window.Right+1) == ScreenInfo->ScreenBufferSize.X);
  982. }
  983. if (WindowLimits.MaximumWindowSize.Y < CONSOLE_WINDOW_SIZE_Y(ScreenInfo)) {
  984. ScreenInfo->Window.Bottom -= CONSOLE_WINDOW_SIZE_Y(ScreenInfo) - WindowLimits.MaximumWindowSize.Y;
  985. if (ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y > ScreenInfo->Window.Bottom) {
  986. ScreenInfo->Window.Top += ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y - ScreenInfo->Window.Bottom;
  987. ScreenInfo->Window.Bottom += ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y - ScreenInfo->Window.Bottom;
  988. }
  989. ScreenInfo->WindowMaximizedY = (ScreenInfo->Window.Top == 0 &&
  990. (SHORT)(ScreenInfo->Window.Bottom+1) == ScreenInfo->ScreenBufferSize.Y);
  991. }
  992. if (WindowLimits.MinimumWindowSize.X > CONSOLE_WINDOW_SIZE_X(ScreenInfo)) {
  993. if (WindowLimits.MinimumWindowSize.X > ScreenInfo->ScreenBufferSize.X) {
  994. COORD NewBufferSize;
  995. NewBufferSize.X = WindowLimits.MinimumWindowSize.X;
  996. NewBufferSize.Y = ScreenInfo->ScreenBufferSize.Y;
  997. ResizeScreenBuffer(ScreenInfo,
  998. NewBufferSize,
  999. FALSE
  1000. );
  1001. }
  1002. if ((ScreenInfo->Window.Left+WindowLimits.MinimumWindowSize.X) > ScreenInfo->ScreenBufferSize.X) {
  1003. ScreenInfo->Window.Left = 0;
  1004. ScreenInfo->Window.Right = WindowLimits.MinimumWindowSize.X-1;
  1005. } else {
  1006. ScreenInfo->Window.Right = ScreenInfo->Window.Left+WindowLimits.MinimumWindowSize.X-1;
  1007. }
  1008. ScreenInfo->WindowMaximizedX = (ScreenInfo->Window.Left == 0 &&
  1009. (SHORT)(ScreenInfo->Window.Right+1) == ScreenInfo->ScreenBufferSize.X);
  1010. }
  1011. SetLineChar(ScreenInfo);
  1012. {
  1013. COORD WindowedWindowSize;
  1014. WindowedWindowSize.X = CONSOLE_WINDOW_SIZE_X(ScreenInfo);
  1015. WindowedWindowSize.Y = CONSOLE_WINDOW_SIZE_Y(ScreenInfo);
  1016. #if defined(FE_IME)
  1017. if (CONSOLE_IS_DBCS_OUTPUTCP(ScreenInfo->Console))
  1018. {
  1019. PCONVERSIONAREA_INFORMATION ConvAreaInfo;
  1020. ConvAreaInfo = ScreenInfo->Console->ConsoleIme.ConvAreaRoot;
  1021. while (ConvAreaInfo) {
  1022. Status = StoreTextBufferFontInfo(ConvAreaInfo->ScreenBuffer,
  1023. SCR_FONTNUMBER(ScreenInfo),
  1024. SCR_FONTSIZE(ScreenInfo),
  1025. SCR_FAMILY(ScreenInfo),
  1026. SCR_FONTWEIGHT(ScreenInfo),
  1027. SCR_FACENAME(ScreenInfo),
  1028. SCR_FONTCODEPAGE(ScreenInfo));
  1029. if (!NT_SUCCESS(Status)) {
  1030. return((ULONG) Status);
  1031. }
  1032. ConvAreaInfo->ScreenBuffer->Window = ScreenInfo->Window;
  1033. ConvAreaInfo->ScreenBuffer->BufferInfo.TextInfo.ModeIndex = ScreenInfo->BufferInfo.TextInfo.ModeIndex;
  1034. ConvAreaInfo = ConvAreaInfo->ConvAreaNext;
  1035. }
  1036. }
  1037. #endif // FE_IME
  1038. }
  1039. //
  1040. // resize window. this will take care of the scroll bars too.
  1041. //
  1042. if (ACTIVE_SCREEN_BUFFER(ScreenInfo)) {
  1043. SetWindowSize(ScreenInfo);
  1044. }
  1045. //
  1046. // adjust cursor size.
  1047. //
  1048. SetCursorInformation(ScreenInfo,
  1049. ScreenInfo->BufferInfo.TextInfo.CursorSize,
  1050. (BOOLEAN)ScreenInfo->BufferInfo.TextInfo.CursorVisible
  1051. );
  1052. WriteToScreen(ScreenInfo,
  1053. &ScreenInfo->Window);
  1054. return STATUS_SUCCESS;
  1055. }
  1056. NTSTATUS
  1057. SetFont(
  1058. IN OUT PSCREEN_INFORMATION ScreenInfo
  1059. )
  1060. {
  1061. if (ACTIVE_SCREEN_BUFFER(ScreenInfo)) {
  1062. int FontIndex = FindCreateFont(SCR_FAMILY(ScreenInfo),
  1063. SCR_FACENAME(ScreenInfo),
  1064. SCR_FONTSIZE(ScreenInfo),
  1065. SCR_FONTWEIGHT(ScreenInfo),
  1066. SCR_FONTCODEPAGE(ScreenInfo));
  1067. if (SelectObject(ScreenInfo->Console->hDC,FontInfo[FontIndex].hFont)==0)
  1068. return STATUS_INVALID_PARAMETER;
  1069. if ((DWORD)FontIndex != SCR_FONTNUMBER(ScreenInfo)) {
  1070. NTSTATUS Status;
  1071. Status = StoreTextBufferFontInfo(ScreenInfo,
  1072. FontIndex,
  1073. FontInfo[FontIndex].Size,
  1074. FontInfo[FontIndex].Family,
  1075. FontInfo[FontIndex].Weight,
  1076. FontInfo[FontIndex].FaceName,
  1077. ScreenInfo->Console->OutputCP);
  1078. if (!NT_SUCCESS(Status)) {
  1079. return((ULONG) Status);
  1080. }
  1081. }
  1082. // hack to get text realized into DC. this is to force the
  1083. // attribute cache to get flushed to the server side, since
  1084. // we select the font with a client side DC and call ExtTextOut
  1085. // with a server side DC.
  1086. // we then need to reset the text color, since the incorrect
  1087. // client side color has been flushed to the server.
  1088. {
  1089. TEXTMETRIC tmi;
  1090. GetTextMetricsW( ScreenInfo->Console->hDC, &tmi);
  1091. ASSERT ((tmi.tmPitchAndFamily & 1) == 0);
  1092. ScreenInfo->Console->LastAttributes = ScreenInfo->Attributes;
  1093. SetTextColor(ScreenInfo->Console->hDC,ConvertAttrToRGB(ScreenInfo->Console, LOBYTE(ScreenInfo->Attributes)));
  1094. SetBkColor(ScreenInfo->Console->hDC,ConvertAttrToRGB(ScreenInfo->Console, LOBYTE(ScreenInfo->Attributes >> 4)));
  1095. }
  1096. }
  1097. return STATUS_SUCCESS;
  1098. }
  1099. int
  1100. ConvertToOem(
  1101. IN UINT Codepage,
  1102. IN LPWSTR Source,
  1103. IN int SourceLength, // in chars
  1104. OUT LPSTR Target,
  1105. IN int TargetLength // in chars
  1106. )
  1107. {
  1108. DBGCHARS(("ConvertToOem U->%d %.*ls\n", Codepage,
  1109. SourceLength > 10 ? 10 : SourceLength, Source));
  1110. if (Codepage == OEMCP) {
  1111. ULONG Length;
  1112. NTSTATUS Status;
  1113. Status = RtlUnicodeToOemN(Target,
  1114. TargetLength,
  1115. &Length,
  1116. Source,
  1117. SourceLength * sizeof(WCHAR)
  1118. );
  1119. if (!NT_SUCCESS(Status)) {
  1120. return 0;
  1121. } else {
  1122. return Length;
  1123. }
  1124. } else {
  1125. return WideCharToMultiByte(Codepage,
  1126. 0,
  1127. Source,
  1128. SourceLength,
  1129. Target,
  1130. TargetLength,
  1131. NULL,
  1132. NULL);
  1133. }
  1134. }
  1135. int
  1136. ConvertInputToUnicode(
  1137. IN UINT Codepage,
  1138. IN LPSTR Source,
  1139. IN int SourceLength, // in chars
  1140. OUT LPWSTR Target,
  1141. IN int TargetLength // in chars
  1142. )
  1143. /*
  1144. data in the output buffer is the true unicode value
  1145. */
  1146. {
  1147. DBGCHARS(("ConvertInputToUnicode %d->U %.*s\n", Codepage,
  1148. SourceLength > 10 ? 10 : SourceLength, Source));
  1149. if (Codepage == OEMCP) {
  1150. ULONG Length;
  1151. NTSTATUS Status;
  1152. Status = RtlOemToUnicodeN(Target,
  1153. TargetLength * sizeof(WCHAR),
  1154. &Length,
  1155. Source,
  1156. SourceLength
  1157. );
  1158. if (!NT_SUCCESS(Status)) {
  1159. return 0;
  1160. } else {
  1161. return Length / sizeof(WCHAR);
  1162. }
  1163. } else {
  1164. return MultiByteToWideChar(Codepage,
  1165. 0,
  1166. Source,
  1167. SourceLength,
  1168. Target,
  1169. TargetLength);
  1170. }
  1171. }
  1172. int
  1173. ConvertOutputToUnicode(
  1174. IN UINT Codepage,
  1175. IN LPSTR Source,
  1176. IN int SourceLength, // in chars
  1177. OUT LPWSTR Target,
  1178. IN int TargetLength // in chars
  1179. )
  1180. /*
  1181. output data is always translated via the ansi codepage
  1182. so glyph translation works.
  1183. */
  1184. {
  1185. NTSTATUS Status;
  1186. ULONG Length;
  1187. CHAR StackBuffer[STACK_BUFFER_SIZE];
  1188. LPSTR pszT;
  1189. DBGCHARS(("ConvertOutputToUnicode %d->U %.*s\n", Codepage,
  1190. SourceLength > 10 ? 10 : SourceLength, Source));
  1191. if (Codepage == OEMCP) {
  1192. Status = RtlCustomCPToUnicodeN(&GlyphCP,
  1193. Target,
  1194. TargetLength * sizeof(WCHAR),
  1195. &Length,
  1196. Source,
  1197. SourceLength
  1198. );
  1199. if (!NT_SUCCESS(Status)) {
  1200. return 0;
  1201. } else {
  1202. return Length / sizeof(WCHAR);
  1203. }
  1204. }
  1205. if (TargetLength > STACK_BUFFER_SIZE) {
  1206. pszT = ConsoleHeapAlloc(TMP_TAG, SourceLength);
  1207. if (pszT == NULL) {
  1208. return 0;
  1209. }
  1210. } else {
  1211. pszT = StackBuffer;
  1212. }
  1213. RtlCopyMemory(pszT, Source, SourceLength);
  1214. Length = MultiByteToWideChar(Codepage, MB_USEGLYPHCHARS,
  1215. pszT, SourceLength, Target, TargetLength);
  1216. if (pszT != StackBuffer) {
  1217. ConsoleHeapFree(pszT);
  1218. }
  1219. return Length;
  1220. }
  1221. #if defined(FE_SB)
  1222. WCHAR
  1223. SB_CharToWcharGlyph(
  1224. IN UINT Codepage,
  1225. IN char Ch)
  1226. #else
  1227. WCHAR
  1228. CharToWcharGlyph(
  1229. IN UINT Codepage,
  1230. IN char Ch)
  1231. #endif
  1232. {
  1233. WCHAR wch = UNICODE_NULL;
  1234. if (Codepage == OEMCP) {
  1235. RtlCustomCPToUnicodeN(&GlyphCP, &wch, sizeof(wch), NULL, &Ch, sizeof(Ch));
  1236. } else {
  1237. MultiByteToWideChar(Codepage, MB_USEGLYPHCHARS, &Ch, 1, &wch, 1);
  1238. }
  1239. #ifdef DEBUG_PRINT
  1240. if (Ch > 0x7F) {
  1241. DBGCHARS(("CharToWcharGlyph %d 0x%02x -> 0x%04x\n",Codepage,(UCHAR)Ch,wch));
  1242. }
  1243. #endif
  1244. return wch;
  1245. }
  1246. #if defined(FE_SB)
  1247. WCHAR
  1248. SB_CharToWchar(
  1249. IN UINT Codepage,
  1250. IN char Ch)
  1251. #else
  1252. WCHAR
  1253. CharToWchar(
  1254. IN UINT Codepage,
  1255. IN char Ch)
  1256. #endif
  1257. {
  1258. WCHAR wch = UNICODE_NULL;
  1259. if (Codepage == OEMCP) {
  1260. RtlOemToUnicodeN(&wch, sizeof(wch), NULL, &Ch, sizeof(Ch));
  1261. } else {
  1262. MultiByteToWideChar(Codepage, 0, &Ch, 1, &wch, 1);
  1263. }
  1264. #ifdef DEBUG_PRINT
  1265. if (Ch > 0x7F) {
  1266. DBGCHARS(("CharToWchar %d 0x%02x -> 0x%04x\n",Codepage,(UCHAR)Ch,wch));
  1267. }
  1268. #endif
  1269. return wch;
  1270. }
  1271. char
  1272. WcharToChar(
  1273. IN UINT Codepage,
  1274. IN WCHAR Wchar)
  1275. {
  1276. char ch = CHAR_NULL;
  1277. if (Codepage == OEMCP) {
  1278. RtlUnicodeToOemN(&ch, sizeof(ch), NULL, &Wchar, sizeof(Wchar));
  1279. } else {
  1280. WideCharToMultiByte(Codepage, 0, &Wchar, 1, &ch, 1, NULL, NULL);
  1281. }
  1282. #ifdef DEBUG_PRINT
  1283. if (Wchar > 0x007F) {
  1284. DBGCHARS(("WcharToChar %d 0x%04x -> 0x%02x\n",Codepage,Wchar,(UCHAR)ch));
  1285. }
  1286. #endif
  1287. return ch;
  1288. }
  1289. int
  1290. ConvertOutputToOem(
  1291. IN UINT Codepage,
  1292. IN LPWSTR Source,
  1293. IN int SourceLength, // in chars
  1294. OUT LPSTR Target,
  1295. IN int TargetLength // in chars
  1296. )
  1297. /*
  1298. Converts SourceLength Unicode characters from Source into
  1299. not more than TargetLength Codepage characters at Target.
  1300. Returns the number characters put in Target. (0 if failure)
  1301. */
  1302. {
  1303. if (Codepage == OEMCP) {
  1304. NTSTATUS Status;
  1305. ULONG Length;
  1306. // Can do this in place
  1307. Status = RtlUnicodeToOemN(Target,
  1308. TargetLength,
  1309. &Length,
  1310. Source,
  1311. SourceLength * sizeof(WCHAR)
  1312. );
  1313. if (NT_SUCCESS(Status)) {
  1314. return Length;
  1315. } else {
  1316. return 0;
  1317. }
  1318. } else {
  1319. ASSERT (Source != (LPWSTR)Target);
  1320. #ifdef SOURCE_EQ_TARGET
  1321. LPSTR pszDestTmp;
  1322. CHAR StackBuffer[STACK_BUFFER_SIZE];
  1323. DBGCHARS(("ConvertOutputToOem U->%d %.*ls\n", Codepage,
  1324. SourceLength > 10 ? 10 : SourceLength, Source));
  1325. if (TargetLength > STACK_BUFFER_SIZE) {
  1326. pszDestTmp = ConsoleHeapAlloc(TMP_TAG, TargetLength);
  1327. if (pszDestTmp == NULL) {
  1328. return 0;
  1329. }
  1330. } else {
  1331. pszDestTmp = StackBuffer;
  1332. }
  1333. TargetLength = WideCharToMultiByte(Codepage, 0,
  1334. Source, SourceLength,
  1335. pszDestTmp, TargetLength, NULL, NULL);
  1336. RtlCopyMemory(Target, pszDestTmp, TargetLength);
  1337. if (pszDestTmp != StackBuffer) {
  1338. ConsoleHeapFree(pszDestTmp);
  1339. }
  1340. return TargetLength;
  1341. #else
  1342. DBGCHARS(("ConvertOutputToOem U->%d %.*ls\n", Codepage,
  1343. SourceLength > 10 ? 10 : SourceLength, Source));
  1344. return WideCharToMultiByte(Codepage, 0,
  1345. Source, SourceLength, Target, TargetLength, NULL, NULL);
  1346. #endif
  1347. }
  1348. }
  1349. NTSTATUS
  1350. RealUnicodeToFalseUnicode(
  1351. IN OUT LPWSTR Source,
  1352. IN int SourceLength, // in chars
  1353. IN UINT Codepage
  1354. )
  1355. /*
  1356. this routine converts a unicode string into the correct characters
  1357. for an OEM (cp 437) font. this code is needed because the gdi glyph
  1358. mapper converts unicode to ansi using codepage 1252 to index
  1359. font. this is how the data is stored internally.
  1360. */
  1361. {
  1362. NTSTATUS Status;
  1363. LPSTR Temp;
  1364. ULONG TempLength;
  1365. ULONG Length;
  1366. CHAR StackBuffer[STACK_BUFFER_SIZE];
  1367. BOOL NormalChars;
  1368. int i;
  1369. DBGCHARS(("RealUnicodeToFalseUnicode U->%d:ACP->U %.*ls\n", Codepage,
  1370. SourceLength > 10 ? 10 : SourceLength, Source));
  1371. #if defined(FE_SB)
  1372. if (OEMCP == WINDOWSCP && Codepage == WINDOWSCP)
  1373. return STATUS_SUCCESS;
  1374. if (SourceLength == 0 )
  1375. return STATUS_SUCCESS;
  1376. #endif
  1377. NormalChars = TRUE;
  1378. for (i=0;i<SourceLength;i++) {
  1379. if (Source[i] > 0x7f) {
  1380. NormalChars = FALSE;
  1381. break;
  1382. }
  1383. }
  1384. if (NormalChars) {
  1385. return STATUS_SUCCESS;
  1386. }
  1387. TempLength = SourceLength;
  1388. if (TempLength > STACK_BUFFER_SIZE) {
  1389. Temp = ConsoleHeapAlloc(TMP_TAG, TempLength);
  1390. if (Temp == NULL) {
  1391. return STATUS_NO_MEMORY;
  1392. }
  1393. } else {
  1394. Temp = StackBuffer;
  1395. }
  1396. if (Codepage == OEMCP) {
  1397. Status = RtlUnicodeToOemN(Temp,
  1398. TempLength,
  1399. &Length,
  1400. Source,
  1401. SourceLength * sizeof(WCHAR)
  1402. );
  1403. } else {
  1404. Status = WideCharToMultiByte(Codepage,
  1405. 0,
  1406. Source,
  1407. SourceLength,
  1408. Temp,
  1409. TempLength,
  1410. NULL,
  1411. NULL);
  1412. }
  1413. if (!NT_SUCCESS(Status)) {
  1414. if (TempLength > STACK_BUFFER_SIZE) {
  1415. ConsoleHeapFree(Temp);
  1416. }
  1417. return Status;
  1418. }
  1419. if (CONSOLE_IS_DBCS_ENABLED()) {
  1420. MultiByteToWideChar(USACP,
  1421. 0,
  1422. Temp,
  1423. TempLength,
  1424. Source,
  1425. SourceLength
  1426. );
  1427. } else {
  1428. Status = RtlMultiByteToUnicodeN(Source,
  1429. SourceLength * sizeof(WCHAR),
  1430. &Length,
  1431. Temp,
  1432. TempLength
  1433. );
  1434. }
  1435. if (TempLength > STACK_BUFFER_SIZE) {
  1436. ConsoleHeapFree(Temp);
  1437. }
  1438. if (!NT_SUCCESS(Status)) {
  1439. return Status;
  1440. } else {
  1441. return STATUS_SUCCESS;
  1442. }
  1443. }
  1444. NTSTATUS
  1445. FalseUnicodeToRealUnicode(
  1446. IN OUT LPWSTR Source,
  1447. IN int SourceLength, // in chars
  1448. IN UINT Codepage
  1449. )
  1450. /*
  1451. this routine converts a unicode string from the internally stored
  1452. unicode characters into the real unicode characters.
  1453. */
  1454. {
  1455. NTSTATUS Status;
  1456. LPSTR Temp;
  1457. ULONG TempLength;
  1458. ULONG Length;
  1459. CHAR StackBuffer[STACK_BUFFER_SIZE];
  1460. BOOL NormalChars;
  1461. int i;
  1462. DBGCHARS(("UnicodeAnsiToUnicodeAnsi U->ACP:%d->U %.*ls\n", Codepage,
  1463. SourceLength > 10 ? 10 : SourceLength, Source));
  1464. #if defined(FE_SB)
  1465. if (OEMCP == WINDOWSCP && Codepage == WINDOWSCP)
  1466. return STATUS_SUCCESS;
  1467. if (SourceLength == 0 )
  1468. return STATUS_SUCCESS;
  1469. #endif
  1470. NormalChars = TRUE;
  1471. /*
  1472. * Test for characters < 0x20 or >= 0x7F. If none are found, we don't have
  1473. * any conversion to do!
  1474. */
  1475. for (i=0;i<SourceLength;i++) {
  1476. if ((USHORT)(Source[i] - 0x20) > 0x5e) {
  1477. NormalChars = FALSE;
  1478. break;
  1479. }
  1480. }
  1481. if (NormalChars) {
  1482. return STATUS_SUCCESS;
  1483. }
  1484. TempLength = SourceLength;
  1485. if (TempLength > STACK_BUFFER_SIZE) {
  1486. Temp = ConsoleHeapAlloc(TMP_TAG, TempLength);
  1487. if (Temp == NULL) {
  1488. return STATUS_NO_MEMORY;
  1489. }
  1490. } else {
  1491. Temp = StackBuffer;
  1492. }
  1493. if (CONSOLE_IS_DBCS_ENABLED()) {
  1494. Status = WideCharToMultiByte(USACP,
  1495. 0,
  1496. Source,
  1497. SourceLength,
  1498. Temp,
  1499. TempLength,
  1500. NULL,
  1501. NULL);
  1502. } else {
  1503. Status = RtlUnicodeToMultiByteN(Temp,
  1504. TempLength,
  1505. &Length,
  1506. Source,
  1507. SourceLength * sizeof(WCHAR)
  1508. );
  1509. }
  1510. if (!NT_SUCCESS(Status)) {
  1511. if (TempLength > STACK_BUFFER_SIZE) {
  1512. ConsoleHeapFree(Temp);
  1513. }
  1514. return Status;
  1515. }
  1516. if (Codepage == OEMCP) {
  1517. Status = RtlCustomCPToUnicodeN(&GlyphCP,
  1518. Source,
  1519. SourceLength * sizeof(WCHAR),
  1520. &Length,
  1521. Temp,
  1522. TempLength
  1523. );
  1524. } else {
  1525. Status = MultiByteToWideChar(Codepage,
  1526. MB_USEGLYPHCHARS,
  1527. Temp,
  1528. TempLength*sizeof(WCHAR),
  1529. Source,
  1530. SourceLength);
  1531. }
  1532. #if defined(FE_SB)
  1533. if (SourceLength > STACK_BUFFER_SIZE) {
  1534. ConsoleHeapFree(Temp);
  1535. }
  1536. #else
  1537. if (TempLength > STACK_BUFFER_SIZE) {
  1538. ConsoleHeapFree(Temp);
  1539. }
  1540. #endif
  1541. if (!NT_SUCCESS(Status)) {
  1542. return Status;
  1543. } else {
  1544. return STATUS_SUCCESS;
  1545. }
  1546. }
  1547. BOOL InitializeCustomCP() {
  1548. PPEB pPeb;
  1549. pPeb = NtCurrentPeb();
  1550. if ((pPeb == NULL) || (pPeb->OemCodePageData == NULL)) {
  1551. return FALSE;
  1552. }
  1553. /*
  1554. * Fill in the CPTABLEINFO struct
  1555. */
  1556. RtlInitCodePageTable(pPeb->OemCodePageData, &GlyphCP);
  1557. /*
  1558. * Make a copy of the MultiByteToWideChar table
  1559. */
  1560. RtlCopyMemory(GlyphTable, GlyphCP.MultiByteTable, 256 * sizeof(USHORT));
  1561. /*
  1562. * Modify the first 0x20 bytes so that they are glyphs.
  1563. */
  1564. MultiByteToWideChar(CP_OEMCP, MB_USEGLYPHCHARS,
  1565. "\x20\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"
  1566. "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F",
  1567. 0x20, GlyphTable, 0x20);
  1568. MultiByteToWideChar(CP_OEMCP, MB_USEGLYPHCHARS,
  1569. "\x7f", 1, &GlyphTable[0x7f], 1);
  1570. /*
  1571. * Point the Custom CP at the glyph table
  1572. */
  1573. GlyphCP.MultiByteTable = GlyphTable;
  1574. #if defined(FE_SB) && defined(i386)
  1575. if (ISNECPC98(gdwMachineId)) {
  1576. InitializeNEC_OS2_CP();
  1577. }
  1578. #endif
  1579. return TRUE;
  1580. }
  1581. #if defined(FE_SB)
  1582. VOID
  1583. SetConsoleCPInfo(
  1584. IN PCONSOLE_INFORMATION Console,
  1585. IN BOOL Output
  1586. )
  1587. {
  1588. if (Output) {
  1589. if (! GetCPInfo(Console->OutputCP,
  1590. &Console->OutputCPInfo)) {
  1591. Console->OutputCPInfo.LeadByte[0] = 0;
  1592. }
  1593. }
  1594. else {
  1595. if (! GetCPInfo(Console->CP,
  1596. &Console->CPInfo)) {
  1597. Console->CPInfo.LeadByte[0] = 0;
  1598. }
  1599. }
  1600. }
  1601. BOOL
  1602. CheckBisectStringW(
  1603. IN PSCREEN_INFORMATION ScreenInfo,
  1604. IN DWORD CodePage,
  1605. IN PWCHAR Buffer,
  1606. IN DWORD NumWords,
  1607. IN DWORD NumBytes
  1608. )
  1609. /*++
  1610. Routine Description:
  1611. This routine check bisected on Unicode string end.
  1612. Arguments:
  1613. ScreenInfo - Pointer to screen information structure.
  1614. CodePage - Value of code page.
  1615. Buffer - Pointer to Unicode string buffer.
  1616. NumWords - Number of Unicode string.
  1617. NumBytes - Number of bisect position by byte counts.
  1618. Return Value:
  1619. TRUE - Bisected character.
  1620. FALSE - Correctly.
  1621. --*/
  1622. {
  1623. while(NumWords && NumBytes) {
  1624. if (IsConsoleFullWidth(ScreenInfo->Console->hDC,CodePage,*Buffer)) {
  1625. if (NumBytes < 2)
  1626. return TRUE;
  1627. else {
  1628. NumWords--;
  1629. NumBytes -= 2;
  1630. Buffer++;
  1631. }
  1632. }
  1633. else {
  1634. NumWords--;
  1635. NumBytes--;
  1636. Buffer++;
  1637. }
  1638. }
  1639. return FALSE;
  1640. }
  1641. BOOL
  1642. CheckBisectProcessW(
  1643. IN PSCREEN_INFORMATION ScreenInfo,
  1644. IN DWORD CodePage,
  1645. IN PWCHAR Buffer,
  1646. IN DWORD NumWords,
  1647. IN DWORD NumBytes,
  1648. IN SHORT OriginalXPosition,
  1649. IN BOOL Echo
  1650. )
  1651. /*++
  1652. Routine Description:
  1653. This routine check bisected on Unicode string end.
  1654. Arguments:
  1655. ScreenInfo - Pointer to screen information structure.
  1656. CodePage - Value of code page.
  1657. Buffer - Pointer to Unicode string buffer.
  1658. NumWords - Number of Unicode string.
  1659. NumBytes - Number of bisect position by byte counts.
  1660. Echo - TRUE if called by Read (echoing characters)
  1661. Return Value:
  1662. TRUE - Bisected character.
  1663. FALSE - Correctly.
  1664. --*/
  1665. {
  1666. WCHAR Char;
  1667. ULONG TabSize;
  1668. if (ScreenInfo->OutputMode & ENABLE_PROCESSED_OUTPUT) {
  1669. while(NumWords && NumBytes) {
  1670. Char = *Buffer;
  1671. if (Char >= (WCHAR)' ') {
  1672. if (IsConsoleFullWidth(ScreenInfo->Console->hDC,CodePage,Char)) {
  1673. if (NumBytes < 2)
  1674. return TRUE;
  1675. else {
  1676. NumWords--;
  1677. NumBytes -= 2;
  1678. Buffer++;
  1679. OriginalXPosition += 2;
  1680. }
  1681. }
  1682. else {
  1683. NumWords--;
  1684. NumBytes--;
  1685. Buffer++;
  1686. OriginalXPosition++;
  1687. }
  1688. }
  1689. else {
  1690. NumWords--;
  1691. Buffer++;
  1692. switch (Char) {
  1693. case UNICODE_BELL:
  1694. if (Echo)
  1695. goto CtrlChar;
  1696. break;
  1697. case UNICODE_BACKSPACE:
  1698. case UNICODE_LINEFEED:
  1699. case UNICODE_CARRIAGERETURN:
  1700. break;
  1701. case UNICODE_TAB:
  1702. TabSize = NUMBER_OF_SPACES_IN_TAB(OriginalXPosition);
  1703. OriginalXPosition = (SHORT)(OriginalXPosition + TabSize);
  1704. if (NumBytes < TabSize)
  1705. return TRUE;
  1706. NumBytes -= TabSize;
  1707. break;
  1708. default:
  1709. if (Echo) {
  1710. CtrlChar:
  1711. if (NumBytes < 2)
  1712. return TRUE;
  1713. NumBytes -= 2;
  1714. OriginalXPosition += 2;
  1715. } else {
  1716. NumBytes--;
  1717. OriginalXPosition++;
  1718. }
  1719. }
  1720. }
  1721. }
  1722. return FALSE;
  1723. }
  1724. else {
  1725. return CheckBisectStringW(ScreenInfo,
  1726. CodePage,
  1727. Buffer,
  1728. NumWords,
  1729. NumBytes);
  1730. }
  1731. }
  1732. #endif // FE_SB