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.

3032 lines
98 KiB

  1. #include "precomp.h"
  2. //
  3. // FH.CPP
  4. // Font Handling
  5. //
  6. // Copyright(c) Microsoft 1997-
  7. //
  8. #define MLZ_FILE_ZONE ZONE_CORE
  9. //
  10. // Table of problem fonts
  11. //
  12. const TCHAR c_szIBMHex[] = "r_ibmhex";
  13. const LPCTSTR c_aszProblemFonts[] =
  14. {
  15. c_szIBMHex,
  16. };
  17. #define CFONTS_PROBLEM (sizeof(c_aszProblemFonts) / sizeof(c_aszProblemFonts[0]))
  18. //
  19. // FH_Init()
  20. //
  21. // This routine allocates a structure for the local font list, then fills
  22. // it in. It returns the number of local fonts in the list, or zero if
  23. // something went wrong
  24. //
  25. UINT FH_Init(void)
  26. {
  27. UINT cFonts = 0;
  28. DebugEntry(FH_Init);
  29. //
  30. // Create the font array and the font index array
  31. //
  32. g_fhFonts = new FHLOCALFONTS;
  33. if (!g_fhFonts)
  34. {
  35. ERROR_OUT(("FH_Init: couldn't allocate g_fhFonts local list"));
  36. DC_QUIT;
  37. }
  38. ZeroMemory(g_fhFonts, sizeof(FHLOCALFONTS));
  39. SET_STAMP(g_fhFonts, FHLOCALFONTS);
  40. //
  41. // Now we consider the fonts individually, and store all acceptable
  42. // ones in the local font list.
  43. //
  44. FHConsiderAllLocalFonts();
  45. cFonts = g_fhFonts->fhNumFonts;
  46. if (cFonts)
  47. {
  48. FHSortAndIndexLocalFonts();
  49. }
  50. else
  51. {
  52. WARNING_OUT(( "No fonts found - this seems unlikely"));
  53. }
  54. DC_EXIT_POINT:
  55. DebugExitDWORD(FH_Init, cFonts);
  56. return(cFonts);
  57. }
  58. //
  59. // FH_Term()
  60. //
  61. void FH_Term(void)
  62. {
  63. DebugEntry(FH_Term);
  64. if (g_fhFonts)
  65. {
  66. delete g_fhFonts;
  67. g_fhFonts = NULL;
  68. }
  69. DebugExitVOID(FH_Term);
  70. }
  71. //
  72. // FH_ReceivedPacket - see fh.h
  73. //
  74. void ASShare::FH_ReceivedPacket
  75. (
  76. ASPerson * pasPerson,
  77. PS20DATAPACKET pPacket
  78. )
  79. {
  80. PFHPACKET pFontsPacket;
  81. UINT iLocal;
  82. UINT iRemote;
  83. LPNETWORKFONT pRemoteFont;
  84. POEREMOTEFONT pLocalFont;
  85. UINT cbSize;
  86. DebugEntry(ASShare::FH_ReceivedPacket);
  87. ValidatePerson(pasPerson);
  88. pFontsPacket = (PFHPACKET)pPacket;
  89. //
  90. // If the number we received isn't the same as before, we need to
  91. // possibly free the previous font block, and then allocate a new one.
  92. //
  93. // Once we're in a share with this person, every new joiner will cause
  94. // existing members to resend their local fonts, usually the same size.
  95. // So we can optimize and not realloc in that case.
  96. //
  97. if (pFontsPacket->cFonts != pasPerson->oecFonts)
  98. {
  99. if (pasPerson->poeFontInfo)
  100. {
  101. delete[] pasPerson->poeFontInfo;
  102. pasPerson->poeFontInfo = NULL;
  103. pasPerson->oecFonts = 0;
  104. }
  105. else
  106. {
  107. ASSERT(!pasPerson->oecFonts);
  108. }
  109. //
  110. // Allocate a new block
  111. //
  112. pasPerson->poeFontInfo = new OEREMOTEFONT[pFontsPacket->cFonts];
  113. if (!pasPerson->poeFontInfo)
  114. {
  115. ERROR_OUT(("Couldn't allocate %d fonts for FH packet from [%d]",
  116. pasPerson->mcsID));
  117. DC_QUIT;
  118. }
  119. ZeroMemory(pasPerson->poeFontInfo, pFontsPacket->cFonts * sizeof(OEREMOTEFONT));
  120. pasPerson->oecFonts = pFontsPacket->cFonts;
  121. }
  122. TRACE_OUT(("Received %d remote fonts in packet from person [%d]",
  123. pasPerson->oecFonts, pasPerson->mcsID));
  124. //
  125. // Consider each remote font. The multibyte fields of the NETWORKFONT
  126. // structure are flipped as they are read; otherwise we would have to
  127. // duplicate the logic about which fields are present in which version.
  128. //
  129. //
  130. // The size of each font is in the packet.
  131. //
  132. cbSize = pFontsPacket->cbFontSize;
  133. pRemoteFont = pFontsPacket->aFonts;
  134. pLocalFont = pasPerson->poeFontInfo;
  135. for (iRemote = 0; iRemote < pasPerson->oecFonts; iRemote++, pLocalFont++)
  136. {
  137. //
  138. // Copy the fields we store directly.
  139. //
  140. pLocalFont->rfFontFlags = pRemoteFont->nfFontFlags;
  141. pLocalFont->rfAveWidth = pRemoteFont->nfAveWidth;
  142. pLocalFont->rfAveHeight = pRemoteFont->nfAveHeight;
  143. pLocalFont->rfAspectX = pRemoteFont->nfAspectX;
  144. pLocalFont->rfAspectY = pRemoteFont->nfAspectY;
  145. //
  146. // And the R2.0 field(s)...
  147. //
  148. if (m_oeCombinedOrderCaps.capsfFonts & CAPS_FONT_CODEPAGE)
  149. {
  150. pLocalFont->rfCodePage = pRemoteFont->nfCodePage;
  151. }
  152. //
  153. // And the other R2.0 field(s)...
  154. //
  155. if (m_oeCombinedOrderCaps.capsfFonts & CAPS_FONT_R20_SIGNATURE)
  156. {
  157. pLocalFont->rfSigFats = pRemoteFont->nfSigFats;
  158. pLocalFont->rfSigThins = pRemoteFont->nfSigThins;
  159. pLocalFont->rfSigSymbol = pRemoteFont->nfSigSymbol;
  160. }
  161. if (m_oeCombinedOrderCaps.capsfFonts & CAPS_FONT_EM_HEIGHT)
  162. {
  163. pLocalFont->rfMaxAscent = pRemoteFont->nfMaxAscent;
  164. TRACE_OUT(( "maxAscent %hd", pLocalFont->rfMaxAscent));
  165. }
  166. //
  167. // Set up an initial remote to local handle mapping, by scanning
  168. // for the first local font with the remote font's facename.
  169. //
  170. // We first set a default match value, in case we dont find a true
  171. // match - this value should never be referenced since we never get
  172. // sent fonts that we can't match (because we sent details of our
  173. // fonts to remote systems, and they should be using the same, or a
  174. // compatible, font matching algorithm.
  175. //
  176. // The mapping we obtain here is to the first local font that has
  177. // the remote font's facename, which is probably not the correct
  178. // font (ie there are probably multiple fonts with the same
  179. // facename). This initial mapping will be updated when we do the
  180. // full matching for all remote fonts. (See FHConsiderRemoteFonts
  181. // for details), but is sufficient, as all we will use it for until
  182. // then, is to obtain the facename.
  183. //
  184. // This approach means that we do not have to store the remote
  185. // facename, which is a useful saving on remote font details space.
  186. //
  187. // SFR5279: cannot default to zero because that means we give a
  188. // name to fonts that do not in fact match at all, causing us to
  189. // always waste effort in FHConsiderRemoteFonts and sometimes to
  190. // wrongly match two fonts that do not really match at all.
  191. //
  192. pLocalFont->rfLocalHandle= NO_FONT_MATCH;
  193. for (iLocal = 0; iLocal < g_fhFonts->fhNumFonts; iLocal++)
  194. {
  195. if (!lstrcmp(g_fhFonts->afhFonts[iLocal].Details.nfFaceName,
  196. pRemoteFont->nfFaceName))
  197. {
  198. pLocalFont->rfLocalHandle = (TSHR_UINT16)iLocal;
  199. break;
  200. }
  201. }
  202. //
  203. // Advance to the next remote font.
  204. //
  205. pRemoteFont = (LPNETWORKFONT)((LPBYTE)pRemoteFont + cbSize);
  206. }
  207. DC_EXIT_POINT:
  208. //
  209. // We have a new set of fonts, so determine the common list.
  210. //
  211. FH_DetermineFontSupport();
  212. DebugExitVOID(ASShare::FH_ReceivedPacket);
  213. }
  214. //
  215. // FH_SendLocalFontInfo()
  216. //
  217. void ASShare::FH_SendLocalFontInfo(void)
  218. {
  219. PFHPACKET pFontPacket = NULL;
  220. LPBYTE pNetworkFonts;
  221. UINT pktSize;
  222. UINT iFont;
  223. BOOL fSendFont;
  224. UINT cDummyFonts = 0;
  225. #ifdef _DEBUG
  226. UINT sentSize;
  227. #endif // _DEBUG
  228. DebugEntry(ASShare::FH_SendLocalFontInfo);
  229. ASSERT(!m_fhLocalInfoSent);
  230. //
  231. //
  232. // Look at the combined capability flags to see whether the remote(s)
  233. // can cope with our preferred font structure (R20) or a slightly
  234. // older one (R11) or only the original flavor (pre R11).
  235. //
  236. //
  237. if (!(m_oeCombinedOrderCaps.capsfFonts & CAPS_FONT_R20_TEST_FLAGS))
  238. {
  239. WARNING_OUT(("Remotes in share don't support CAPS_FONT_R20"));
  240. m_fhLocalInfoSent = TRUE;
  241. DC_QUIT;
  242. }
  243. pktSize = sizeof(FHPACKET) + (g_fhFonts->fhNumFonts - 1) * sizeof(NETWORKFONT);
  244. pFontPacket = (PFHPACKET)SC_AllocPkt(PROT_STR_MISC, g_s20BroadcastID, pktSize);
  245. if (!pFontPacket)
  246. {
  247. WARNING_OUT(("Failed to alloc FH packet, size %u", pktSize));
  248. DC_QUIT;
  249. }
  250. //
  251. // Packet successfully allocated. Fill in the data and send it.
  252. //
  253. pFontPacket->header.data.dataType = DT_FH;
  254. pFontPacket->cbFontSize = sizeof(NETWORKFONT);
  255. //
  256. // Copy the fonts we want to send into the network packet.
  257. //
  258. pNetworkFonts = (LPBYTE)pFontPacket->aFonts;
  259. cDummyFonts = 0;
  260. for (iFont = 0 ; iFont < g_fhFonts->fhNumFonts ; iFont++)
  261. {
  262. //
  263. // Assume we will send this font.
  264. //
  265. fSendFont = TRUE;
  266. //
  267. // Check whether font is ANSI charset or font CodePage capability
  268. // is supported. If neither, skip on to next local font.
  269. //
  270. TRACE_OUT(( "TEST CP set OK: font[%u] CodePage[%hu]", iFont,
  271. g_fhFonts->afhFonts[iFont].Details.nfCodePage));
  272. if ((g_fhFonts->afhFonts[iFont].Details.nfCodePage != ANSI_CHARSET) &&
  273. (!(m_oeCombinedOrderCaps.capsfFonts & CAPS_FONT_CODEPAGE)) )
  274. {
  275. TRACE_OUT(( "Dont send font[%u] CodePage[%hu]", iFont,
  276. g_fhFonts->afhFonts[iFont].Details.nfCodePage));
  277. fSendFont = FALSE;
  278. }
  279. if (fSendFont)
  280. {
  281. //
  282. // We want to send this entry so copy across as much of the
  283. // stored details as the protocol level requires.
  284. // We then mask the flags and advance to the next location in
  285. // the packet.
  286. //
  287. memcpy(pNetworkFonts,
  288. &g_fhFonts->afhFonts[iFont].Details,
  289. sizeof(NETWORKFONT));
  290. ((LPNETWORKFONT)pNetworkFonts)->nfFontFlags &= ~NF_LOCAL;
  291. }
  292. else
  293. {
  294. //
  295. // If we determine that we do not want to send the current
  296. // font then we fill the corresponding entry in the network
  297. // packet with zeros. This ensures that an index into our
  298. // local font table is also an index into the network packet,
  299. // so no conversion is required. Setting the whole entry to
  300. // zero gives the font a NULL facename and zero size, which
  301. // will never match a real font.
  302. //
  303. ZeroMemory(pNetworkFonts, sizeof(NETWORKFONT));
  304. cDummyFonts++;
  305. }
  306. //
  307. // Move to the next entry in the font packet.
  308. //
  309. pNetworkFonts += sizeof(NETWORKFONT);
  310. }
  311. //
  312. // Note that at the end of this loop, we may not have sent any fonts,
  313. // eg where the remote system does not support the font CodePage
  314. // capability and we do not have any true ANSI fonts. We send the
  315. // packet anyway, so the remote system sees that we have no fonts to
  316. // match.
  317. //
  318. //
  319. // Only now do we know the number of fonts we actually put in the
  320. // packet.
  321. //
  322. pFontPacket->cFonts = (TSHR_UINT16)g_fhFonts->fhNumFonts;
  323. //
  324. // Send the fonts packet on the MISC stream. It has no dependency on
  325. // any updates and we want it to get across quickly.
  326. //
  327. if (m_scfViewSelf)
  328. FH_ReceivedPacket(m_pasLocal, &(pFontPacket->header));
  329. #ifdef _DEBUG
  330. sentSize =
  331. #endif // _DEBUG
  332. DCS_CompressAndSendPacket(PROT_STR_MISC, g_s20BroadcastID,
  333. &(pFontPacket->header), pktSize);
  334. TRACE_OUT(("FH packet size: %08d, sent %08d", pktSize, sentSize));
  335. TRACE_OUT(( "Sent font packet with %u fonts (inc %u dummies)",
  336. g_fhFonts->fhNumFonts,
  337. cDummyFonts));
  338. //
  339. // Set the flag that indicates that we have successfully sent the
  340. // font info.
  341. //
  342. m_fhLocalInfoSent = TRUE;
  343. //
  344. // The font info has been sent, so this may mean we can enable text
  345. // orders.
  346. //
  347. FHMaybeEnableText();
  348. DC_EXIT_POINT:
  349. DebugExitVOID(ASShare::FH_SendLocalFontInfo);
  350. }
  351. //
  352. // FUNCTION: FH_GetMaxHeightFromLocalHandle
  353. //
  354. // DESCRIPTION:
  355. //
  356. // Given an FH font handle (ie a handle originating from the locally
  357. // supported font structure which was sent to the remote machine at the
  358. // start of the call) this function returns the MaxBaseLineExt value stored
  359. // with the LOCALFONT details
  360. //
  361. // PARAMETERS:
  362. //
  363. // fontHandle - font handle being queried.
  364. //
  365. // RETURNS: max font height
  366. //
  367. //
  368. UINT FH_GetMaxHeightFromLocalHandle(UINT fontHandle)
  369. {
  370. UINT rc;
  371. DebugEntry(FH_GetMaxHeightFromLocalHandle);
  372. //
  373. // First check that the font handle is valid.
  374. //
  375. if (fontHandle >= g_fhFonts->fhNumFonts)
  376. {
  377. ERROR_OUT(( "Invalid font handle %u", fontHandle));
  378. fontHandle = 0;
  379. }
  380. //
  381. // Return the max font height
  382. //
  383. rc = g_fhFonts->afhFonts[fontHandle].lMaxBaselineExt;
  384. DebugExitDWORD(FH_GetMaxHeightFromLocalHandle, rc);
  385. return(rc);
  386. }
  387. //
  388. // FUNCTION: FH_GetFontFlagsFromLocalHandle
  389. //
  390. // DESCRIPTION:
  391. //
  392. // Given an FH font handle (ie a handle originating from the locally
  393. // supported font structure which was sent to the remote machine at the
  394. // start of the call) this function returns the FontFlags value stored with
  395. // the LOCALFONT details
  396. //
  397. // PARAMETERS:
  398. //
  399. // fontHandle - font handle being queried.
  400. //
  401. // RETURNS: font flags
  402. //
  403. //
  404. UINT FH_GetFontFlagsFromLocalHandle(UINT fontHandle)
  405. {
  406. UINT rc;
  407. DebugEntry(FH_GetFontFlagsFromLocalHandle);
  408. //
  409. // First check that the font handle is valid.
  410. //
  411. if (fontHandle >= g_fhFonts->fhNumFonts)
  412. {
  413. ERROR_OUT(( "Invalid font handle %u", fontHandle));
  414. fontHandle = 0;
  415. }
  416. //
  417. // Return the font flags.
  418. //
  419. rc = g_fhFonts->afhFonts[fontHandle].Details.nfFontFlags;
  420. DebugExitDWORD(FH_GetFontFlagsFromLocalHandle, rc);
  421. return(rc);
  422. }
  423. //
  424. // FUNCTION: FH_GetCodePageFromLocalHandle
  425. //
  426. // DESCRIPTION:
  427. //
  428. // Given an FH font handle (ie a handle originating from the locally
  429. // supported font structure which was sent to the remote machine at the
  430. // start of the call) this function returns the CodePage value stored with
  431. // the LOCALFONT details
  432. //
  433. // PARAMETERS:
  434. //
  435. // fontHandle - font handle being queried.
  436. //
  437. // RETURNS: char set
  438. //
  439. //
  440. UINT FH_GetCodePageFromLocalHandle(UINT fontHandle)
  441. {
  442. UINT rc = 0;
  443. DebugEntry(FH_GetCodePageFromLocalHandle);
  444. //
  445. // First check that the font handle is valid.
  446. //
  447. if (fontHandle >= g_fhFonts->fhNumFonts)
  448. {
  449. ERROR_OUT(( "Invalid font handle %u", fontHandle));
  450. fontHandle = 0;
  451. }
  452. //
  453. // Return the char set.
  454. //
  455. rc = g_fhFonts->afhFonts[fontHandle].Details.nfCodePage;
  456. DebugExitDWORD(FH_GetCodePageFromLocalHandle, rc);
  457. return(rc);
  458. }
  459. //
  460. // FH_ConvertAnyFontIDToLocal()
  461. //
  462. // DESCRIPTION:
  463. // Converts any font name ID fields in the passed order from remote font
  464. // face name IDs to local font facename IDs.
  465. //
  466. void ASShare::FH_ConvertAnyFontIDToLocal
  467. (
  468. LPCOM_ORDER pOrder,
  469. ASPerson * pasPerson
  470. )
  471. {
  472. LPCOMMON_TEXTORDER pCommon = NULL;
  473. DebugEntry(ASShare::FH_ConvertAnyFontIDToLocal);
  474. ValidatePerson(pasPerson);
  475. //
  476. // Get a pointer to the structure which is common to both TextOut and
  477. // ExtTextOut
  478. //
  479. if (TEXTFIELD(pOrder)->type == LOWORD(ORD_TEXTOUT))
  480. {
  481. pCommon = &TEXTFIELD(pOrder)->common;
  482. }
  483. else if (EXTTEXTFIELD(pOrder)->type == LOWORD(ORD_EXTTEXTOUT))
  484. {
  485. pCommon = &EXTTEXTFIELD(pOrder)->common;
  486. }
  487. else
  488. {
  489. ERROR_OUT(( "Order type not TextOut or ExtTextOut."));
  490. DC_QUIT;
  491. }
  492. TRACE_OUT(( "fonthandle IN %lu", pCommon->FontIndex));
  493. pCommon->FontIndex = FHGetLocalFontHandle(pCommon->FontIndex, pasPerson);
  494. TRACE_OUT(( "fonthandle OUT %lu", pCommon->FontIndex));
  495. DC_EXIT_POINT:
  496. DebugExitVOID(ASShare::FH_ConvertAnyFontIDToLocal);
  497. }
  498. //
  499. // FH_GetFaceNameFromLocalHandle - see fh.h
  500. //
  501. LPSTR FH_GetFaceNameFromLocalHandle(UINT fontHandle, LPUINT pFaceNameLength)
  502. {
  503. LPSTR pFontName = NULL;
  504. DebugEntry(FH_GetFaceNameFromLocalHandle);
  505. //
  506. // First check that the font handle is valid.
  507. //
  508. if (fontHandle >= g_fhFonts->fhNumFonts)
  509. {
  510. ERROR_OUT(( "Invalid font handle %u", fontHandle));
  511. fontHandle = 0;
  512. }
  513. //
  514. // Now get the facename
  515. //
  516. *pFaceNameLength = lstrlen(g_fhFonts->afhFonts[fontHandle].RealName);
  517. pFontName = g_fhFonts->afhFonts[fontHandle].RealName;
  518. DebugExitVOID(FH_GetFaceNameFromLocalHandle);
  519. return(pFontName);
  520. }
  521. //
  522. // FH_DetermineFontSupport()
  523. //
  524. void ASShare::FH_DetermineFontSupport(void)
  525. {
  526. UINT cCommonFonts;
  527. UINT iLocal;
  528. ASPerson * pasPerson;
  529. DebugEntry(ASShare::FH_DetermineFontSupport);
  530. //
  531. // First mark all local fonts as supported.
  532. //
  533. cCommonFonts = g_fhFonts->fhNumFonts;
  534. for (iLocal = 0; iLocal < g_fhFonts->fhNumFonts; iLocal++)
  535. {
  536. g_fhFonts->afhFonts[iLocal].SupportCode = FH_SC_EXACT_MATCH;
  537. }
  538. //
  539. // Work through all remote people (but not us)
  540. //
  541. ValidatePerson(m_pasLocal);
  542. for (pasPerson = m_pasLocal->pasNext;
  543. (cCommonFonts > 0) && (pasPerson != NULL);
  544. pasPerson = pasPerson->pasNext)
  545. {
  546. ValidatePerson(pasPerson);
  547. if (pasPerson->oecFonts)
  548. {
  549. cCommonFonts = FHConsiderRemoteFonts(cCommonFonts, pasPerson);
  550. }
  551. else
  552. {
  553. //
  554. // We do not have valid fonts for this person, so must not
  555. // send any text orders at all.
  556. //
  557. TRACE_OUT(( "Pending FONT INFO from person [%d]", pasPerson->mcsID));
  558. cCommonFonts = 0;
  559. }
  560. }
  561. //
  562. // We have determined the common supported fonts, and may be able to
  563. // enable text orders now.
  564. //
  565. FHMaybeEnableText();
  566. DebugExitVOID(ASShare::FH_DetermineFontSupport);
  567. }
  568. //
  569. // FH_CreateAndSelectFont()
  570. //
  571. BOOL FH_CreateAndSelectFont(HDC surface,
  572. HFONT* pHNewFont,
  573. HFONT* pHOldFont,
  574. LPSTR fontName,
  575. UINT codepage,
  576. UINT fontMaxHeight,
  577. UINT fontHeight,
  578. UINT fontWidth,
  579. UINT fontWeight,
  580. UINT fontFlags)
  581. {
  582. BOOL rc;
  583. BYTE italic;
  584. BYTE underline;
  585. BYTE strikeout;
  586. BYTE pitch;
  587. BYTE charset;
  588. BYTE precis;
  589. DebugEntry(FH_CreateAndSelectFont);
  590. //
  591. // Set the return code to indicate failure (FALSE). We will change this
  592. // later if we successfully create the font.
  593. //
  594. rc = FALSE;
  595. //
  596. // Massage the data passed which describes the font into the correct
  597. // arrangement to pass on a create font call. Then create a font.
  598. //
  599. //
  600. // If a facename passed is the null string then we are supposed to use
  601. // the system font.
  602. //
  603. if (fontName[0] == 0)
  604. {
  605. WARNING_OUT(( "Using system font"));
  606. *pHNewFont = GetStockFont(SYSTEM_FONT);
  607. }
  608. else
  609. {
  610. //
  611. // Determine the italic, underline, strikeout and pitch values from
  612. // the packed flags.
  613. //
  614. italic = (BYTE)(fontFlags & NF_ITALIC);
  615. underline = (BYTE)(fontFlags & NF_UNDERLINE);
  616. strikeout = (BYTE)(fontFlags & NF_STRIKEOUT);
  617. if (fontFlags & NF_FIXED_PITCH)
  618. {
  619. pitch = FF_DONTCARE | FIXED_PITCH;
  620. }
  621. else
  622. {
  623. pitch = FF_DONTCARE | VARIABLE_PITCH;
  624. }
  625. //
  626. // Check whether this is a TrueType font. This is important, as
  627. // the Windows Font mapper is biased towards non-TrueType, and it
  628. // is easy to do the subsequent decoding with a non-TrueType font.
  629. //
  630. // Note that the Windows headers do not define a name for the
  631. // required value (which is 0x04 in the manuals), so we use the
  632. // value used in the TextMetrics (which has the same value).
  633. //
  634. if (fontFlags & NF_TRUE_TYPE)
  635. {
  636. pitch |= TMPF_TRUETYPE;
  637. precis = OUT_TT_ONLY_PRECIS;
  638. }
  639. else
  640. {
  641. precis = OUT_RASTER_PRECIS;
  642. }
  643. //
  644. // The height we are passed is the character height, not the cell
  645. // height. To indicate this to Windows we need to pass it in as a
  646. // negative value.
  647. //
  648. TRACE_OUT(( "CreateFont cx(%u) cy(%u) wt(%u) pitch(%u) name:%s",
  649. fontWidth,
  650. fontHeight,
  651. fontWeight,
  652. pitch,
  653. fontName ));
  654. //
  655. // Use the misleadingly named codepage value to calculate what
  656. // charset to ask Windows for.
  657. //
  658. if (codepage == NF_CP_WIN_ANSI)
  659. {
  660. charset = ANSI_CHARSET;
  661. }
  662. else if (codepage == NF_CP_WIN_OEM)
  663. {
  664. charset = OEM_CHARSET;
  665. }
  666. else if (codepage == NF_CP_WIN_SYMBOL)
  667. {
  668. charset = SYMBOL_CHARSET;
  669. }
  670. else
  671. {
  672. //
  673. // We have to trust our luck to Windows by specifying default
  674. // (meaning don't care).
  675. //
  676. charset = DEFAULT_CHARSET;
  677. }
  678. *pHNewFont = CreateFont(-(int)fontHeight,
  679. fontWidth,
  680. 0, // escapement
  681. 0, // orientation
  682. fontWeight,
  683. italic,
  684. underline,
  685. strikeout,
  686. charset,
  687. precis,
  688. CLIP_DEFAULT_PRECIS,
  689. DEFAULT_QUALITY,
  690. pitch,
  691. fontName);
  692. if (*pHNewFont == NULL)
  693. {
  694. WARNING_OUT(( "Failed to create font %s", fontName));
  695. DC_QUIT;
  696. }
  697. }
  698. //
  699. // Now we have created the font we need to select it into the HDC
  700. // which was passed to us.
  701. //
  702. *pHOldFont = SelectFont(surface, *pHNewFont);
  703. if (*pHOldFont == NULL)
  704. {
  705. ERROR_OUT(( "Failed to select font %s", fontName));
  706. DeleteFont(*pHNewFont);
  707. *pHNewFont = NULL;
  708. DC_QUIT;
  709. }
  710. TRACE_OUT(( "Select new font: %p Old font: %", *pHNewFont,
  711. *pHOldFont));
  712. //
  713. // We have successfully created and selected the font.
  714. //
  715. rc = TRUE;
  716. DC_EXIT_POINT:
  717. DebugExitDWORD(FH_CreateAndSelectFont, rc);
  718. return(rc);
  719. }
  720. //
  721. // FHAddFontToLocalTable
  722. //
  723. // Adds the given font into the local font table, along with any renaming
  724. // and approximate matches.
  725. //
  726. //
  727. void FHAddFontToLocalTable( LPSTR faceName,
  728. TSHR_UINT16 fontFlags,
  729. TSHR_UINT16 codePage,
  730. TSHR_UINT16 maxHeight,
  731. TSHR_UINT16 aveHeight,
  732. TSHR_UINT16 aveWidth,
  733. TSHR_UINT16 aspectX,
  734. TSHR_UINT16 aspectY,
  735. TSHR_UINT16 maxAscent)
  736. {
  737. TSHR_INT16 fatSig;
  738. TSHR_INT16 thinSig;
  739. TSHR_INT16 symbolSig;
  740. FHWIDTHTABLE wTable;
  741. TSHR_UINT16 height;
  742. TSHR_UINT16 width;
  743. TSHR_UINT16 weight;
  744. LOCALFONT thisFont;
  745. TSHR_UINT16 fIndex;
  746. //
  747. // SFRFONT: place marker.
  748. // Here would be the best place to adjust codepage; for example suppose
  749. // we find that CodePage 950 (Chinese) is so different on all platforms
  750. // that we just should not send text orders in this codepage, we can
  751. // set codePage=NF_CP_UNKNOWN and it will be discarded.
  752. //
  753. //
  754. // SFRFONT: no point hanging on to details of fonts with unknown
  755. // code pages; we cannot risk matching them.
  756. //
  757. if (codePage == NF_CP_UNKNOWN)
  758. {
  759. TRACE_OUT(( "unknown CP: discard"));
  760. DC_QUIT;
  761. }
  762. //
  763. // Check we still have room for more fonts.
  764. //
  765. if (g_fhFonts->fhNumFonts >= FH_MAX_FONTS)
  766. {
  767. //
  768. // We are already at our maximum number of fonts.
  769. //
  770. DC_QUIT;
  771. }
  772. //
  773. // Zero the fields where we store facenames to allow bytewise matches.
  774. //
  775. ZeroMemory(thisFont.Details.nfFaceName, FH_FACESIZE);
  776. ZeroMemory(thisFont.RealName, FH_FACESIZE);
  777. //
  778. // Store the easy bits!
  779. //
  780. thisFont.Details.nfFontFlags = fontFlags;
  781. thisFont.Details.nfAveWidth = aveWidth;
  782. thisFont.Details.nfAveHeight = aveHeight;
  783. thisFont.Details.nfAspectX = aspectX;
  784. thisFont.Details.nfAspectY = aspectY;
  785. thisFont.Details.nfCodePage = codePage;
  786. thisFont.lMaxBaselineExt = maxHeight;
  787. //
  788. // Store the real name, for use when we want to create an instance of
  789. // this font.
  790. //
  791. lstrcpy (thisFont.RealName, faceName);
  792. //
  793. // Fill in the wire-format facename.
  794. //
  795. // NB - This has a machine-specific prefix, but for NT the prefix is an
  796. // empty string, so we can just use a strcpy without worrying about the
  797. // issues of adding a prefix.
  798. //
  799. lstrcpy (thisFont.Details.nfFaceName, faceName);
  800. //
  801. // Make sure the signatures are zero for now.
  802. //
  803. thisFont.Details.nfSigFats = 0;
  804. thisFont.Details.nfSigThins = 0;
  805. thisFont.Details.nfSigSymbol = 0;
  806. //
  807. // Now calculate the signature and maxAscent for this font
  808. //
  809. weight = 0; // use default weight
  810. if ((fontFlags & NF_FIXED_SIZE) != 0)
  811. {
  812. //
  813. // Fixed size font: use actual font size for signatures/maxAscent
  814. //
  815. height = thisFont.lMaxBaselineExt;
  816. width = thisFont.Details.nfAveWidth;
  817. thisFont.Details.nfMaxAscent = maxAscent;
  818. }
  819. else
  820. {
  821. //
  822. // Scalable font: use default height/width for signatures/maxAscent
  823. //
  824. height = NF_METRICS_HEIGHT;
  825. width = NF_METRICS_WIDTH;
  826. thisFont.Details.nfMaxAscent = NF_METRICS_HEIGHT;
  827. }
  828. //
  829. // Initialise signature fields to zero (== NF_NO_SIGNATURE). They will
  830. // be overwritten assuming we get a font width table OK.
  831. //
  832. fatSig = 0;
  833. thinSig = 0;
  834. symbolSig = 0;
  835. //
  836. // FHGenerateFontWidthTable also gives us a proper maxAscent value for
  837. // scalable fonts (i.e. based on its own rendition of the font)
  838. //
  839. if (FHGenerateFontWidthTable(&wTable,
  840. &thisFont,
  841. height,
  842. width,
  843. weight,
  844. thisFont.Details.nfFontFlags,
  845. &maxAscent))
  846. {
  847. //
  848. // If this is a scalable font, use the updated maxAscent value that
  849. // FHGenerateFontWidthTable has given us.
  850. //
  851. if (0 == (thisFont.Details.nfFontFlags & NF_FIXED_SIZE))
  852. {
  853. thisFont.Details.nfMaxAscent = maxAscent;
  854. TRACE_OUT(( "Set maxAscent = %d", thisFont.Details.nfMaxAscent));
  855. }
  856. //
  857. // We have all the raw data we need. Calculate the signatures.
  858. //
  859. FHCalculateSignatures(&wTable, &fatSig, &thinSig, &symbolSig);
  860. }
  861. //
  862. // Store the signatures. If the call to FHGenerateFontWidthTable
  863. // fails, the signatures are zero.
  864. //
  865. thisFont.Details.nfSigFats = (BYTE)fatSig;
  866. thisFont.Details.nfSigThins = (BYTE)thinSig;
  867. thisFont.Details.nfSigSymbol = (TSHR_UINT16)symbolSig;
  868. TRACE_OUT(( "Font %hu signatures: (x%.4hx%.2hx%.2hx)",
  869. g_fhFonts->fhNumFonts,
  870. thisFont.Details.nfSigSymbol,
  871. (TSHR_UINT16)(thisFont.Details.nfSigThins),
  872. (TSHR_UINT16)(thisFont.Details.nfSigFats)));
  873. //
  874. // We can now copy the details to the end of the local table.
  875. //
  876. memcpy((void *)&g_fhFonts->afhFonts[g_fhFonts->fhNumFonts],
  877. (void *)&thisFont,
  878. sizeof(LOCALFONT));
  879. //
  880. // Count this font.
  881. //
  882. TRACE_OUT(( "Added record %s",
  883. g_fhFonts->afhFonts[g_fhFonts->fhNumFonts].Details.nfFaceName));
  884. g_fhFonts->fhNumFonts++;
  885. TRACE_OUT(( "g_fhFonts->fhNumFonts now %u", g_fhFonts->fhNumFonts));
  886. DC_EXIT_POINT:
  887. DebugExitVOID(FHAddFontToLocalTable);
  888. }
  889. //
  890. // FHConsiderRemoteFonts
  891. //
  892. // Considers the remote fonts for a single remote person.
  893. //
  894. // Takes the existing number of supported fonts, and returns the number
  895. // that are still common after considering this person.
  896. //
  897. UINT ASShare::FHConsiderRemoteFonts
  898. (
  899. UINT cCanSend,
  900. ASPerson * pasPerson
  901. )
  902. {
  903. UINT iLocal;
  904. UINT iRemote;
  905. UINT cCanReceive=0;
  906. BOOL fCanReceive, fOnlyAscii;
  907. UINT sendSupportCode;
  908. UINT bestSupportSoFar;
  909. DebugEntry(ASShare::FHConsiderRemoteFonts);
  910. ValidatePerson(pasPerson);
  911. //
  912. // Consider each of the still valid local fonts, and see if the remote
  913. // person also supports them.
  914. //
  915. //
  916. // SFR5396: LOOP ONE
  917. //
  918. // Look through all the LOCAL fonts, for ones where we find a match in
  919. // the remote font table. These are fonts we can SEND, and for which
  920. // we must set g_fhFonts->afhFonts[].Supported.
  921. //
  922. // We also set the rfLocalHandle for remote fonts that we can receive
  923. // if we encounter them in this search. We complete the search for
  924. // remote fonts that we can receive in LOOP TWO.
  925. //
  926. // Things we check in this loop: - we may already know there is no
  927. // match for this local name
  928. // so drop out quickly. - otherwise check through EVERY REMOTE
  929. // font looking for the
  930. // best possible match. (If we find an EXACT match, leave the
  931. // inner loop early)
  932. //
  933. //
  934. for (iLocal=0;
  935. (cCanSend > 0) && (iLocal < g_fhFonts->fhNumFonts);
  936. iLocal++)
  937. {
  938. if (g_fhFonts->afhFonts[iLocal].SupportCode != FH_SC_NO_MATCH)
  939. {
  940. //
  941. //
  942. // This font is still valid so check it with all the remote
  943. // fonts for this person.
  944. //
  945. // Things we check in this loop:
  946. // - do the face names match? if no - try next remote font.
  947. // - the pitch: if one is FIXED pitch and one isn't try next
  948. // - the codepages: are the local/remote the same? This
  949. // determines whether we send only ASCII chars.
  950. // - scalability: possible combinations are:
  951. // local fixed/remote scalable (can send/not rcv)
  952. // local scalable/remote scalable (can send and rcv)
  953. // local fixed/remote fixed, sizes match (send & rcv)
  954. // local scalable/remote fixed (cannot send/can rcv)
  955. // for this last case, keep trying the remote fonts.
  956. //
  957. // In "back level" calls to Pre-R11 boxes we stop here but
  958. // force the matches to be approximate. Otherwise check
  959. //
  960. // - aspect ratios (if present): must match or try the
  961. // next remote font.
  962. // - signatures: these are used to finally decide whether
  963. // the fonts are exact matches; good enough to treat as
  964. // approximate matches or such poor matches that the
  965. // font is not supported (cannot be sent).
  966. //
  967. //
  968. //
  969. // Handy SHORTHAND macroes.
  970. //
  971. #define REMOTEFONT pasPerson->poeFontInfo[iRemote]
  972. #define LOCALFT g_fhFonts->afhFonts[iLocal]
  973. #define LOCALDETS LOCALFT.Details
  974. //
  975. // Initially assume that the fonts do not match, but that
  976. // if they do they will match across the whole codepage
  977. // (not just the ascii set).
  978. //
  979. sendSupportCode = FH_SC_NO_MATCH;
  980. bestSupportSoFar = FH_SC_NO_MATCH;
  981. fOnlyAscii = FALSE;
  982. //
  983. //
  984. // Loop through all the remote fonts looking to see which, if
  985. // any, offers the best possible match. Initially,
  986. // sendSupportCode is set to NO_MATCH; as we go through each
  987. // iteration we see if we can improve on the current setting
  988. // of sendSupportCode. We leave the loop as soon as we find
  989. // an EXACT_MATCH ('cos we are not going to do any better than
  990. // that!) or when we run out of remote fonts. The best match
  991. // found so far is kept in bestSupportSoFar.
  992. //
  993. //
  994. for (iRemote = 0;
  995. (iRemote < pasPerson->oecFonts)
  996. && (sendSupportCode != FH_SC_EXACT_MATCH);
  997. iRemote++)
  998. {
  999. //
  1000. // If the remote font is already flagged as having no
  1001. // possible match then skip out now. (We set this field
  1002. // during the initial processing of the remote font).
  1003. //
  1004. if (REMOTEFONT.rfLocalHandle==NO_FONT_MATCH)
  1005. {
  1006. continue; // SFR5279
  1007. }
  1008. //
  1009. // Check the face names...
  1010. //
  1011. if (lstrcmp(LOCALDETS.nfFaceName,
  1012. g_fhFonts->afhFonts[REMOTEFONT.rfLocalHandle].Details.nfFaceName))
  1013. {
  1014. continue;
  1015. }
  1016. TRACE_OUT(( "Matched Remote Face Name %s",
  1017. g_fhFonts->afhFonts[REMOTEFONT.rfLocalHandle]
  1018. .Details.nfFaceName));
  1019. //
  1020. // Check the pitch...
  1021. //
  1022. if( (LOCALDETS.nfFontFlags & NF_FIXED_PITCH)!=
  1023. (REMOTEFONT.rfFontFlags & NF_FIXED_PITCH) )
  1024. {
  1025. TRACE_OUT(( "Different Pitch %x %x",
  1026. LOCALDETS.nfFontFlags,
  1027. REMOTEFONT.rfFontFlags));
  1028. continue;
  1029. }
  1030. //
  1031. //
  1032. // If both systems support the font CodePage capability
  1033. // (indicated by the remote capability flags - which are
  1034. // the union of remote and local by now), check that the
  1035. // CodePages and CodePage flags match, and if not,
  1036. // restrict ourselves to sending the ASCII subset.
  1037. //
  1038. // If we support the font CodePage capability but remote
  1039. // system does not, then restrict ourselves to sending the
  1040. // ASCII subset.
  1041. //
  1042. // If we do not support the font CodePage capability, then
  1043. // we assume that the remote is only sending ANSI CodePage,
  1044. // either because it doesn't know about the font CodePage
  1045. // capability or because it can see that we don't support
  1046. // it. Therefore, we do not need to check the CodePage.
  1047. // BUT: restrict ourselves to ASCII only.
  1048. //
  1049. //
  1050. if (!(m_pasLocal->cpcCaps.orders.capsfFonts & CAPS_FONT_CODEPAGE))
  1051. {
  1052. //
  1053. // We do not support codepage checking.
  1054. //
  1055. TRACE_OUT(( "not checking CP"));
  1056. fOnlyAscii = TRUE;
  1057. }
  1058. if ((m_oeCombinedOrderCaps.capsfFonts & CAPS_FONT_CODEPAGE)
  1059. && (LOCALDETS.nfCodePage != REMOTEFONT.rfCodePage) )
  1060. {
  1061. TRACE_OUT(( "Different CPs %hu %hu",
  1062. LOCALDETS.nfCodePage,
  1063. REMOTEFONT.rfCodePage));
  1064. //
  1065. //
  1066. // Assume that all codepages include ASCII.
  1067. //
  1068. //
  1069. fOnlyAscii = TRUE;
  1070. }
  1071. //
  1072. //
  1073. // If we support codepage, but the remote does not then
  1074. // the remote will only be sending us ANSI chars. Make sure
  1075. // that we send only ASCII subset.
  1076. //
  1077. //
  1078. if ((m_pasLocal->cpcCaps.orders.capsfFonts & CAPS_FONT_CODEPAGE) &&
  1079. !(m_oeCombinedOrderCaps.capsfFonts & CAPS_FONT_CODEPAGE))
  1080. {
  1081. TRACE_OUT(( "Only ASCII"));
  1082. fOnlyAscii = TRUE;
  1083. }
  1084. //
  1085. //
  1086. // The face names and CodePages match and the fonts are of
  1087. // the same type of pitch (ie both are fixed pitch or both
  1088. // are variable pitch).
  1089. //
  1090. //
  1091. if ((REMOTEFONT.rfFontFlags & NF_FIXED_SIZE) == 0)
  1092. {
  1093. //
  1094. //
  1095. // The remote font is scalable, so we can send any font
  1096. // (with this facename) to the remote system, even if
  1097. // the local font is fixed sized. Set sendSupportCode
  1098. // to FH_SC_EXACT_MATCH now - we will change this to
  1099. // FH_SC_APPROX_MATCH later if other fields differ.
  1100. //
  1101. //
  1102. TRACE_OUT((
  1103. "Person [%d] Can SEND: remote SCALABLE %s (remote)%u to (local)%u",
  1104. pasPerson->mcsID,
  1105. LOCALDETS.nfFaceName,
  1106. iRemote, iLocal));
  1107. sendSupportCode = FH_SC_EXACT_MATCH;
  1108. //
  1109. //
  1110. // SFR5396: it is true that we can SEND this font
  1111. // because the remote version of the font is scalable.
  1112. // That does not mean that we can necessarily receive
  1113. // the font... unless ours is scalable too.
  1114. //
  1115. //
  1116. if ((LOCALDETS.nfFontFlags & NF_FIXED_SIZE)==0)
  1117. {
  1118. TRACE_OUT((
  1119. "Person [%d] Can RECEIVE remote font %u as local %u",
  1120. pasPerson->mcsID, iRemote, iLocal));
  1121. REMOTEFONT.rfLocalHandle = (TSHR_UINT16)iLocal;
  1122. }
  1123. }
  1124. else if (LOCALDETS.nfFontFlags & NF_FIXED_SIZE)
  1125. {
  1126. //
  1127. //
  1128. // The remote font is fixed size and so is the local
  1129. // one, so check if the sizes match exactly.
  1130. //
  1131. //
  1132. if ((LOCALDETS.nfAveWidth == REMOTEFONT.rfAveWidth) &&
  1133. (LOCALDETS.nfAveHeight == REMOTEFONT.rfAveHeight))
  1134. {
  1135. //
  1136. //
  1137. // Our fixed size local font is the same as the
  1138. // fixed size font at the remote. We set
  1139. // sendSupportCode to FH_SC_EXACT_MATCH now - we
  1140. // will change this to FH_SC_APPROX_MATCH later if
  1141. // other fields differ.
  1142. //
  1143. //
  1144. TRACE_OUT(("Person [%d] Matched remote fixed font %s %u to %u",
  1145. pasPerson->mcsID,
  1146. LOCALDETS.nfFaceName,
  1147. iRemote, iLocal));
  1148. sendSupportCode = FH_SC_EXACT_MATCH;
  1149. REMOTEFONT.rfLocalHandle = (TSHR_UINT16)iLocal;
  1150. }
  1151. else
  1152. {
  1153. TRACE_OUT(( "rejected %s ave width/heights "
  1154. "local/remote width %d/%d height %d/%d",
  1155. LOCALDETS.nfFaceName,
  1156. LOCALDETS.nfAveWidth,
  1157. REMOTEFONT.rfAveWidth,
  1158. LOCALDETS.nfAveHeight,
  1159. REMOTEFONT.rfAveHeight));
  1160. }
  1161. }
  1162. else
  1163. {
  1164. TRACE_OUT((
  1165. "Can only RECEIVE %s %u Remote is fixed, but local %u not",
  1166. LOCALDETS.nfFaceName,
  1167. iRemote,
  1168. iLocal));
  1169. //
  1170. //
  1171. // SFR5396: while we cannot SEND this font because our
  1172. // local version is scalable, but the remote's is
  1173. // fixed - we can still receive the font in an order.
  1174. //
  1175. //
  1176. REMOTEFONT.rfLocalHandle = (TSHR_UINT16)iLocal;
  1177. }
  1178. //
  1179. //
  1180. // If we have have set the send support code to indicate
  1181. // that we have matched we now consider any R1.1 info if it
  1182. // is present. As a result of this we may adjust the send
  1183. // support code (from indicating an exact match) to
  1184. // indicate either an approximate match or no match at all.
  1185. //
  1186. //
  1187. if (!pasPerson->oecFonts)
  1188. {
  1189. //
  1190. //
  1191. // The remote system did not send us any R11 font
  1192. // info. In this case we assume all font matches are
  1193. // approximate and restrict ourselves to the ascii
  1194. // subset.
  1195. //
  1196. //
  1197. if (sendSupportCode != FH_SC_NO_MATCH)
  1198. {
  1199. TRACE_OUT(( "No R11 so approx match only"));
  1200. sendSupportCode = FH_SC_APPROX_ASCII_MATCH;
  1201. }
  1202. }
  1203. else if (sendSupportCode != FH_SC_NO_MATCH)
  1204. {
  1205. //
  1206. //
  1207. // The remote system did send us R11 font info and
  1208. // the font is flagged as matching.
  1209. //
  1210. //
  1211. if ((m_oeCombinedOrderCaps.capsfFonts
  1212. & CAPS_FONT_R20_SIGNATURE)!=0)
  1213. {
  1214. //
  1215. //
  1216. // Check the signatures.
  1217. //
  1218. //
  1219. TRACE_OUT((
  1220. "Person [%d] local %d (remote %d) signatures (x%.4hx%.2hx%.2hx v x%.4hx%.2hx%.2hx)",
  1221. pasPerson->mcsID,
  1222. iLocal,
  1223. iRemote,
  1224. LOCALDETS.nfSigSymbol,
  1225. (TSHR_UINT16)(LOCALDETS.nfSigThins),
  1226. (TSHR_UINT16)(LOCALDETS.nfSigFats),
  1227. REMOTEFONT.rfSigSymbol,
  1228. (TSHR_UINT16)(REMOTEFONT.rfSigThins),
  1229. (TSHR_UINT16)(REMOTEFONT.rfSigFats)));
  1230. if ((LOCALDETS.nfSigFats != REMOTEFONT.rfSigFats) ||
  1231. (LOCALDETS.nfSigThins != REMOTEFONT.rfSigThins) ||
  1232. (LOCALDETS.nfSigSymbol != REMOTEFONT.rfSigSymbol) ||
  1233. (REMOTEFONT.rfSigSymbol == NF_NO_SIGNATURE))
  1234. {
  1235. //
  1236. // Decide what to do from the signatures.
  1237. //
  1238. if (REMOTEFONT.rfSigSymbol == NF_NO_SIGNATURE)
  1239. {
  1240. TRACE_OUT(("NO match: remote no signature"));
  1241. sendSupportCode = FH_SC_APPROX_ASCII_MATCH;
  1242. }
  1243. else if ((LOCALDETS.nfSigFats == REMOTEFONT.rfSigFats)
  1244. && (LOCALDETS.nfSigThins == REMOTEFONT.rfSigThins))
  1245. {
  1246. TRACE_OUT(( "our ASCII sigs match"));
  1247. sendSupportCode = FH_SC_EXACT_ASCII_MATCH;
  1248. }
  1249. else
  1250. {
  1251. //
  1252. // NOTE:
  1253. // We could use the "closeness" of the fat
  1254. // and thin signatures to help us decide
  1255. // whether to use approximate matching or
  1256. // not. But currently we don't.
  1257. //
  1258. TRACE_OUT(( "Sig mismatch: APPROX_ASC"));
  1259. sendSupportCode = FH_SC_APPROX_ASCII_MATCH;
  1260. }
  1261. }
  1262. else
  1263. {
  1264. //
  1265. //
  1266. // All signatures match exactly.
  1267. // Leave SendSupportCode as FH_SC_EXACT_MATCH
  1268. //
  1269. //
  1270. TRACE_OUT(("EXACT MATCH: Signatures match exactly"));
  1271. }
  1272. }
  1273. else
  1274. {
  1275. //
  1276. // Not using signatures. Do we care?
  1277. //
  1278. sendSupportCode = FH_SC_APPROX_MATCH;
  1279. TRACE_OUT(( "APPROX MATCH: no sigs"));
  1280. }
  1281. //
  1282. //
  1283. // Check the aspect ratio - but only if we do not
  1284. // already know that this font does not match.
  1285. //
  1286. //
  1287. if ( (sendSupportCode!=FH_SC_NO_MATCH) &&
  1288. ( (!(m_oeCombinedOrderCaps.capsfFonts
  1289. & CAPS_FONT_ASPECT))
  1290. || (LOCALDETS.nfAspectX != REMOTEFONT.rfAspectX)
  1291. || (LOCALDETS.nfAspectY != REMOTEFONT.rfAspectY) ))
  1292. {
  1293. //
  1294. //
  1295. // Either no aspect ratio was supplied or the
  1296. // aspect ratio differed.
  1297. //
  1298. //
  1299. if (sendSupportCode == FH_SC_EXACT_MATCH)
  1300. {
  1301. //
  1302. // Force delta-X text orders for mismatched
  1303. // aspect ratio. Note we tested above to
  1304. // see whether supportCode == EXACT because if
  1305. // we have already "downgraded" support then
  1306. // we do not need to change it here
  1307. //
  1308. sendSupportCode = FH_SC_APPROX_MATCH;
  1309. TRACE_OUT(( "AR mismatch: APPROX_MATCH"));
  1310. }
  1311. else if (sendSupportCode == FH_SC_EXACT_ASCII_MATCH)
  1312. {
  1313. //
  1314. // Same again but for ASCII only.
  1315. //
  1316. sendSupportCode = FH_SC_APPROX_ASCII_MATCH;
  1317. TRACE_OUT(( "AR mismatch: APPROX_ASCII_MATCH"));
  1318. }
  1319. }
  1320. }
  1321. if (sendSupportCode != FH_SC_NO_MATCH)
  1322. {
  1323. //
  1324. //
  1325. // Is this a better match than any we have seen
  1326. // before?
  1327. //
  1328. //
  1329. switch (sendSupportCode)
  1330. {
  1331. case FH_SC_EXACT_MATCH:
  1332. case FH_SC_APPROX_MATCH:
  1333. //
  1334. //
  1335. // Note that we do not have to worry about
  1336. // overwriting a bestSupportSoFar of EXACT
  1337. // with APPROX because we leave the loop when
  1338. // we get an exact match.
  1339. //
  1340. //
  1341. bestSupportSoFar = sendSupportCode;
  1342. break;
  1343. case FH_SC_EXACT_ASCII_MATCH:
  1344. //
  1345. //
  1346. // An approximate match over the whole 255
  1347. // code points is better than an exact one
  1348. // over just the ascii-s. Debatable, but that
  1349. // is what I have decided.
  1350. //
  1351. //
  1352. if (bestSupportSoFar != FH_SC_APPROX_MATCH)
  1353. {
  1354. bestSupportSoFar = FH_SC_EXACT_ASCII_MATCH;
  1355. }
  1356. break;
  1357. case FH_SC_APPROX_ASCII_MATCH:
  1358. //
  1359. //
  1360. // An approximate match over just the ascii-s
  1361. // is better than nothing at all!
  1362. //
  1363. //
  1364. if (bestSupportSoFar == FH_SC_NO_MATCH)
  1365. {
  1366. bestSupportSoFar = FH_SC_APPROX_ASCII_MATCH;
  1367. }
  1368. break;
  1369. default:
  1370. ERROR_OUT(("invalid support code"));
  1371. break;
  1372. }
  1373. }
  1374. }
  1375. sendSupportCode = bestSupportSoFar;
  1376. //
  1377. // If we matched the remote font, we have already updated
  1378. // its local handle to
  1379. // the matched local font. While the local handle was already
  1380. // set up, it was only set up to the first local font with the
  1381. // same facename, rather than the correct font.
  1382. //
  1383. // If we did not match the remote font, mark it as not
  1384. // supported, and decrement the common font count.
  1385. //
  1386. if (sendSupportCode != FH_SC_NO_MATCH)
  1387. {
  1388. TRACE_OUT(( "Local font %d/%s can be SENT (code=%u)",
  1389. iLocal,
  1390. LOCALDETS.nfFaceName,
  1391. sendSupportCode));
  1392. if (fOnlyAscii)
  1393. {
  1394. if (sendSupportCode == FH_SC_EXACT_MATCH)
  1395. {
  1396. sendSupportCode = FH_SC_EXACT_ASCII_MATCH;
  1397. TRACE_OUT(( "Adjust %d/%s to EXACT_ASC (code=%u)",
  1398. iLocal,
  1399. LOCALDETS.nfFaceName,
  1400. sendSupportCode));
  1401. }
  1402. else
  1403. {
  1404. TRACE_OUT(( "Adjust %d/%s to APPROX_ASC (code=%u)",
  1405. iLocal,
  1406. LOCALDETS.nfFaceName,
  1407. sendSupportCode));
  1408. sendSupportCode = FH_SC_APPROX_ASCII_MATCH;
  1409. }
  1410. }
  1411. }
  1412. else
  1413. {
  1414. TRACE_OUT(( "Local font %d/%s cannot be SENT",
  1415. iLocal,LOCALDETS.nfFaceName));
  1416. cCanSend--;
  1417. }
  1418. LOCALFT.SupportCode &= sendSupportCode;
  1419. }
  1420. else
  1421. {
  1422. TRACE_OUT(( "Cannot SEND %d/%s",iLocal,LOCALDETS.nfFaceName));
  1423. }
  1424. }
  1425. //
  1426. //
  1427. // SFR5396: LOOP TWO
  1428. //
  1429. // Loop through all the remote fonts, looking for ones where we have
  1430. // a locally matching font. These are fonts that we can RECEIVE in
  1431. // orders, and for which we need to map the remote font handle to the
  1432. // local font handle. This means setting REMOTEFONT.rfLocalHandle.
  1433. //
  1434. // By the time we reach here, REMOTEFONT.rfLocalHandle is already set
  1435. // to:
  1436. // - NO_FONT_MATCH (in FH_ProcessRemoteFonts)
  1437. // or the index in the local table of a definite match found in LOOP1
  1438. // or the index of the first entry in the local table with the
  1439. // same face name as the remote font (set in FH_ProcessRemoteFonts)
  1440. //
  1441. // so - we can begin our search in the local table from
  1442. // REMOTEFONT.rfLocalHandle.
  1443. //
  1444. //
  1445. for (iRemote = 0;
  1446. (iRemote < pasPerson->oecFonts);
  1447. iRemote++)
  1448. {
  1449. iLocal = REMOTEFONT.rfLocalHandle;
  1450. if (iLocal == NO_FONT_MATCH)
  1451. {
  1452. //
  1453. // We have no fonts whatsoever that match this font name
  1454. // Go round again... try the next REMOTE font.
  1455. //
  1456. continue;
  1457. }
  1458. TRACE_OUT(( "Can we receive %s?",
  1459. g_fhFonts->afhFonts[REMOTEFONT.rfLocalHandle].Details.nfFaceName));
  1460. for (fCanReceive = FALSE;
  1461. (iLocal < g_fhFonts->fhNumFonts) && (!fCanReceive);
  1462. iLocal++)
  1463. {
  1464. //
  1465. // Check the face names...
  1466. //
  1467. if (lstrcmp(LOCALDETS.nfFaceName,
  1468. g_fhFonts->afhFonts[REMOTEFONT.rfLocalHandle].Details.nfFaceName))
  1469. {
  1470. //
  1471. // Try the next LOCAL font.
  1472. //
  1473. continue;
  1474. }
  1475. //
  1476. // Check the pitch...
  1477. //
  1478. if((LOCALDETS.nfFontFlags & NF_FIXED_PITCH)!=
  1479. (REMOTEFONT.rfFontFlags & NF_FIXED_PITCH))
  1480. {
  1481. //
  1482. // Different pitches, try the next local font.
  1483. //
  1484. TRACE_OUT(( "Pitch mismatch"));
  1485. continue;
  1486. }
  1487. //
  1488. //
  1489. // The face names match and the fonts are of
  1490. // the same type of pitch (ie both are fixed pitch or both
  1491. // are variable pitch).
  1492. //
  1493. //
  1494. if ((REMOTEFONT.rfFontFlags & NF_FIXED_SIZE) == 0)
  1495. {
  1496. if ((LOCALDETS.nfFontFlags & NF_FIXED_SIZE)==0)
  1497. {
  1498. //
  1499. //
  1500. // The remote font is scalable. Ours is also
  1501. // scalable then we can receive the font.
  1502. //
  1503. // We do not need to look at any more LOCAL fonts.
  1504. //
  1505. //
  1506. fCanReceive = TRUE;
  1507. }
  1508. }
  1509. else if (LOCALDETS.nfFontFlags & NF_FIXED_SIZE)
  1510. {
  1511. //
  1512. //
  1513. // The remote font is fixed size and so is the local
  1514. // one, so check if the sizes match exactly.
  1515. //
  1516. //
  1517. if ((LOCALDETS.nfAveWidth == REMOTEFONT.rfAveWidth) &&
  1518. (LOCALDETS.nfAveHeight == REMOTEFONT.rfAveHeight))
  1519. {
  1520. //
  1521. //
  1522. // Our fixed size local font is the same as the
  1523. // fixed size font at the remote.
  1524. //
  1525. // We do not need to look at any more LOCAL fonts.
  1526. //
  1527. //
  1528. fCanReceive = TRUE;
  1529. }
  1530. else
  1531. {
  1532. TRACE_OUT(( "different fixed sizes"));
  1533. }
  1534. }
  1535. else
  1536. {
  1537. //
  1538. //
  1539. // The remote is FIXED but the LOCAL is scalable. We
  1540. // can receive orders for text of this type (but not send)
  1541. //
  1542. // We do not need to look at any more LOCAL fonts.
  1543. //
  1544. //
  1545. fCanReceive = TRUE;
  1546. }
  1547. if (fCanReceive)
  1548. {
  1549. TRACE_OUT(("Person [%d] Can RECEIVE remote font %s %u as %u",
  1550. pasPerson->mcsID,
  1551. LOCALDETS.nfFaceName,
  1552. iRemote, iLocal));
  1553. REMOTEFONT.rfLocalHandle = (TSHR_UINT16)iLocal;
  1554. cCanReceive++;
  1555. }
  1556. }
  1557. }
  1558. TRACE_OUT(("Person [%d] Can SEND %d fonts", pasPerson->mcsID, cCanSend));
  1559. TRACE_OUT(("Person [%d] Can RECEIVE %d fonts", pasPerson->mcsID, cCanReceive));
  1560. DebugExitDWORD(ASShare::FHConsiderRemoteFonts, cCanSend);
  1561. return(cCanSend);
  1562. }
  1563. //
  1564. // FHMaybeEnableText
  1565. //
  1566. // Enables or disables sending of text orders
  1567. //
  1568. void ASShare::FHMaybeEnableText(void)
  1569. {
  1570. BOOL fEnableText = FALSE;
  1571. ASPerson * pasPerson;
  1572. DebugEntry(ASShare::FHMaybeEnableText);
  1573. //
  1574. // To enable sending text orders we must have sent out our own packet
  1575. // of fonts, and there must be no outstanding remote packets required.
  1576. //
  1577. if (m_fhLocalInfoSent)
  1578. {
  1579. //
  1580. // Assume we can enable text orders.
  1581. //
  1582. fEnableText = TRUE;
  1583. //
  1584. // The local info was sent, so check remote dudes (not us)
  1585. //
  1586. ValidatePerson(m_pasLocal);
  1587. for (pasPerson = m_pasLocal->pasNext; pasPerson != NULL; pasPerson = pasPerson->pasNext)
  1588. {
  1589. ValidatePerson(pasPerson);
  1590. if (!pasPerson->oecFonts)
  1591. {
  1592. //
  1593. // We have found a font packet that we have not yet
  1594. // received, so must disable sending text, and can break
  1595. // out of the search.
  1596. //
  1597. TRACE_OUT(( "No font packet yet from person [%d]", pasPerson->mcsID));
  1598. fEnableText = FALSE;
  1599. break;
  1600. }
  1601. }
  1602. }
  1603. else
  1604. {
  1605. TRACE_OUT(( "Local font info not yet sent"));
  1606. }
  1607. OE_EnableText(fEnableText);
  1608. if (g_asCanHost)
  1609. {
  1610. //
  1611. // Pass on new font data to the other tasks.
  1612. //
  1613. if (fEnableText)
  1614. {
  1615. OE_NEW_FONTS newFontData;
  1616. //
  1617. // Copy the data from the Share Core.
  1618. //
  1619. newFontData.fontCaps = m_oeCombinedOrderCaps.capsfFonts;
  1620. newFontData.countFonts = (WORD)g_fhFonts->fhNumFonts;
  1621. newFontData.fontData = g_fhFonts->afhFonts;
  1622. newFontData.fontIndex = g_fhFonts->afhFontIndex;
  1623. TRACE_OUT(( "Sending %d Fonts", g_fhFonts->fhNumFonts));
  1624. //
  1625. // Notify display driver of new fonts
  1626. //
  1627. OSI_FunctionRequest(OE_ESC_NEW_FONTS,
  1628. (LPOSI_ESCAPE_HEADER)&newFontData,
  1629. sizeof(newFontData));
  1630. }
  1631. }
  1632. DebugExitVOID(ASShare::FHMaybeEnableText);
  1633. }
  1634. //
  1635. // FHGetLocalFontHandle
  1636. //
  1637. // Translate a remote font handle/local ID pair to a local font handle.
  1638. //
  1639. UINT ASShare::FHGetLocalFontHandle
  1640. (
  1641. UINT remotefont,
  1642. ASPerson * pasPerson
  1643. )
  1644. {
  1645. DebugEntry(ASShare::FHGetLocalFontHandle);
  1646. ValidatePerson(pasPerson);
  1647. if (!pasPerson->oecFonts)
  1648. {
  1649. WARNING_OUT(("Order packet from [%d] but no fonts", pasPerson->mcsID));
  1650. }
  1651. if (remotefont == DUMMY_FONT_ID)
  1652. {
  1653. //
  1654. // The dummy font ID has been supplied for the remote font Id.
  1655. // Substitute the first valid local font Id.
  1656. //
  1657. for (remotefont = 0;
  1658. remotefont < pasPerson->oecFonts;
  1659. remotefont++)
  1660. {
  1661. if (pasPerson->poeFontInfo[remotefont].rfLocalHandle !=
  1662. NO_FONT_MATCH)
  1663. {
  1664. break;
  1665. }
  1666. }
  1667. }
  1668. if (remotefont >= pasPerson->oecFonts)
  1669. {
  1670. //
  1671. // The remote font is invalid.
  1672. // There is no error value, we simply return the valid but
  1673. // incorrect value 0.
  1674. //
  1675. TRACE_OUT(("Person [%d] Invalid font handle %u",
  1676. pasPerson->mcsID, remotefont));
  1677. return(0);
  1678. }
  1679. DebugExitVOID(ASShare::FHGetLocalFontHandle);
  1680. return(pasPerson->poeFontInfo[remotefont].rfLocalHandle);
  1681. }
  1682. //
  1683. //
  1684. // FUNCTION: FHCalculateSignatures
  1685. //
  1686. // DESCRIPTION:
  1687. //
  1688. // Given a width table, calculates the three font signatures that are
  1689. // included in the R2.0 NETWORKFONT structure.
  1690. //
  1691. // PARAMETERS:
  1692. //
  1693. // pTable - pointer to width table
  1694. // pSigFats, pSigThins, pSigSymbol - return the three signatures
  1695. //
  1696. // RETURNS:
  1697. //
  1698. // None
  1699. //
  1700. //
  1701. void FHCalculateSignatures(PFHWIDTHTABLE pTable,
  1702. LPTSHR_INT16 pSigFats,
  1703. LPTSHR_INT16 pSigThins,
  1704. LPTSHR_INT16 pSigSymbol)
  1705. {
  1706. UINT charI = 0;
  1707. UINT fatSig = 0;
  1708. UINT thinSig = 0;
  1709. UINT symbolSig = 0;
  1710. DebugEntry(FHCalculateSignatures);
  1711. ASSERT((pTable != NULL));
  1712. ASSERT((pSigFats != NULL));
  1713. ASSERT((pSigThins != NULL));
  1714. ASSERT((pSigSymbol != NULL));
  1715. //
  1716. // nfSigFats the sum of the widths (in pels) of the chars
  1717. // 0-9,@-Z,$,%,&. divided by two: the fat chars
  1718. // nfSigThins the sum of the widths (in pels) of the chars
  1719. // 0x20->0x7F EXCLUDING those summed in nfSigFats.
  1720. // Again - divided by two. The thin chars.
  1721. // nfSigSymbol The sum of the widths (in pels) of the chars
  1722. // x80->xFF.
  1723. //
  1724. //
  1725. // Loop for 0-9, some punctuation, A-Z. Then add $,% and &. i.e. mainly
  1726. // fat characters.
  1727. //
  1728. for (charI= NF_ASCII_ZERO; charI<NF_ASCII_Z ; charI++ )
  1729. {
  1730. fatSig += pTable->charWidths[charI];
  1731. }
  1732. fatSig += pTable->charWidths[NF_ASCII_DOLLAR] +
  1733. pTable->charWidths[NF_ASCII_PERCENT] +
  1734. pTable->charWidths[NF_ASCII_AMPERSAND];
  1735. //
  1736. // thin sig covers the rest of the "ascii" characters (x20->7F) not
  1737. // already included in fatSig.
  1738. //
  1739. for (charI= NF_ASCII_FIRST; charI<NF_ASCII_LAST ; charI++ )
  1740. {
  1741. thinSig += pTable->charWidths[charI];
  1742. }
  1743. thinSig -= fatSig;
  1744. //
  1745. // symbolSig covers the "non-ascii" characters (x0->1F, 80->FF)
  1746. //
  1747. for (charI= 0x00; charI<(NF_ASCII_FIRST-1) ; charI++ )
  1748. {
  1749. symbolSig += pTable->charWidths[charI];
  1750. }
  1751. for (charI= NF_ASCII_LAST+1; charI<0xFF ; charI++ )
  1752. {
  1753. symbolSig += pTable->charWidths[charI];
  1754. }
  1755. TRACE_OUT(( "Signatures: symbol %#lx thin %#lx fat %#lx",
  1756. symbolSig, thinSig, fatSig));
  1757. //
  1758. // Halve the fat and thin sigs so that they fit into one byte each.
  1759. //
  1760. fatSig /= 2;
  1761. thinSig /= 2;
  1762. if ( (((TSHR_UINT16)symbolSig)==0)
  1763. && (((BYTE)fatSig)==0) && (((BYTE)thinSig)==0))
  1764. {
  1765. //
  1766. // Worry about the faint possibility that all three sums could add
  1767. // up to a value of zero when truncated.
  1768. //
  1769. symbolSig=1;
  1770. }
  1771. //
  1772. // Fill in return pointers.
  1773. //
  1774. *pSigFats = (TSHR_INT16)fatSig;
  1775. *pSigThins = (TSHR_INT16)thinSig;
  1776. *pSigSymbol = (TSHR_INT16)symbolSig;
  1777. DebugExitVOID(FHCalculateSignatures);
  1778. }
  1779. //
  1780. // FHEachFontFamily
  1781. //
  1782. // This callback is called for each font family. We use it to build up a
  1783. // list of all the family names.
  1784. //
  1785. //
  1786. // Although wingdi.h defines the first two parameters for an ENUMFONTPROC
  1787. // as LOGFONT and TEXTMETRIC (thereby disagreeing with MSDN), tests show
  1788. // that the structures are actually as defined in MSDN (i.e. we get valid
  1789. // information when accessing the extended fields)
  1790. //
  1791. int CALLBACK FHEachFontFamily
  1792. (
  1793. const ENUMLOGFONT FAR * enumlogFont,
  1794. const NEWTEXTMETRIC FAR * TextMetric,
  1795. int FontType,
  1796. LPARAM lParam
  1797. )
  1798. {
  1799. LPFHFAMILIES lpFamilies = (LPFHFAMILIES)lParam;
  1800. DebugEntry(FHEachFontFamily);
  1801. ASSERT(!IsBadWritePtr(lpFamilies, sizeof(*lpFamilies)));
  1802. if (lpFamilies->fhcFamilies == FH_MAX_FONTS)
  1803. {
  1804. //
  1805. // We cannot support any more font families so stop enumerating.
  1806. //
  1807. WARNING_OUT(( "Can only handle %u families", FH_MAX_FONTS));
  1808. return(FALSE); // Stop the enumeration
  1809. }
  1810. TRACE_OUT(("FHEachFontFamily: %s", enumlogFont->elfLogFont.lfFaceName));
  1811. ASSERT(lstrlen(enumlogFont->elfLogFont.lfFaceName) < FH_FACESIZE);
  1812. lstrcpy(lpFamilies->afhFamilies[lpFamilies->fhcFamilies].szFontName,
  1813. enumlogFont->elfLogFont.lfFaceName);
  1814. lpFamilies->fhcFamilies++;
  1815. DebugExitBOOL(FHEachFontFamily, TRUE);
  1816. return(TRUE); // Continue enumerating
  1817. }
  1818. //
  1819. // FHEachFont
  1820. //
  1821. // This callback is called for each font. It gathers and stores the font
  1822. // details.
  1823. //
  1824. //
  1825. //
  1826. // Although wingdi.h defines the first two parameters for an ENUMFONTPROC
  1827. // as LOGFONT and TEXTMETRIC (thereby disagreeing with MSDN), tests show
  1828. // that the structures are actually as defined in MSDN (i.e. we get valid
  1829. // information when accessing the extended fields)
  1830. //
  1831. int CALLBACK FHEachFont(const ENUMLOGFONT FAR * enumlogFont,
  1832. const NEWTEXTMETRIC FAR * TextMetric,
  1833. int FontType,
  1834. LPARAM lParam)
  1835. {
  1836. HDC hdc = (HDC)lParam;
  1837. TSHR_UINT16 fontflags = 0;
  1838. TSHR_UINT16 CodePage = 0;
  1839. HFONT hfont;
  1840. HFONT holdfont = NULL;
  1841. TEXTMETRIC tm;
  1842. BOOL fAcceptFont;
  1843. int rc;
  1844. DebugEntry(FHEachFont);
  1845. TRACE_OUT(( "Family name: %s", enumlogFont->elfLogFont.lfFaceName));
  1846. TRACE_OUT(( "Full name: %s", enumlogFont->elfFullName));
  1847. if (g_fhFonts->fhNumFonts >= FH_MAX_FONTS)
  1848. {
  1849. //
  1850. // We cannot support any more fonts so stop enumerating.
  1851. //
  1852. WARNING_OUT(( "Can only handle %u fonts", FH_MAX_FONTS));
  1853. rc = 0;
  1854. DC_QUIT; // Stop the enumeration
  1855. }
  1856. //
  1857. // We want to continue...
  1858. //
  1859. rc = 1;
  1860. //
  1861. // Don't bother with this if it's a bold/italic variant.
  1862. //
  1863. // NOTE:
  1864. // The elfFullName field is only valid for TrueType fonts on Win95. For
  1865. // non TrueType fonts, assume that the full name and face name are the
  1866. // same.
  1867. //
  1868. if (!g_asWin95 || (FontType & TRUETYPE_FONTTYPE))
  1869. {
  1870. if (lstrcmp(enumlogFont->elfLogFont.lfFaceName, (LPCSTR)enumlogFont->elfFullName))
  1871. {
  1872. TRACE_OUT(( "Discarding variant: %s", enumlogFont->elfFullName));
  1873. DC_QUIT; // Jump out, but don't stop enumerating!
  1874. }
  1875. }
  1876. //
  1877. // We now accumulate information on all local fonts in all CodePages.
  1878. // This relies on the subsequent sending of local fonts and matching of
  1879. // remote fonts taking into account the CodePage capabilities of the
  1880. // systems.
  1881. //
  1882. //
  1883. // On this pass we copy the details into our structure.
  1884. //
  1885. if (FontType & TRUETYPE_FONTTYPE)
  1886. {
  1887. //
  1888. // This is a truetype font, which we simply accept without double
  1889. // checking its metrics. (Metric double checking to exclude
  1890. // duplicates is of most relevance to fixed size fonts, which are
  1891. // explicitly optimised for one screen size)
  1892. //
  1893. fAcceptFont = TRUE;
  1894. //
  1895. // Indicate TrueType (this will go in the NETWORKFONT structure
  1896. // (i.e. over the wire)
  1897. //
  1898. fontflags |= NF_TRUE_TYPE;
  1899. //
  1900. // Signal that we did not call CreateFont for this font.
  1901. //
  1902. hfont = NULL;
  1903. }
  1904. else
  1905. {
  1906. //
  1907. // We create a font from the logical description, and select it so
  1908. // that we can query its metrics.
  1909. //
  1910. // The point of this is that it allows us to identify fonts where
  1911. // the logical font description is not a unique description of this
  1912. // font, and hence if we cannot get to this font via a logical font
  1913. // description, we cannot get to it at all.
  1914. //
  1915. // If we cannot get to it, then we cannot claim to support it.
  1916. //
  1917. // This selection operation is SLOW - of the order of a couple of
  1918. // seconds in some extreme cases (for example where the font is
  1919. // stored on a network drive, and pageing has to take place) and
  1920. // when you can have hundreds of fonts this can add up to a
  1921. // considerable time.
  1922. //
  1923. // Hence we only do the selection for non truetype fonts because
  1924. // these are the fonts where it is easy to get multiple fonts of
  1925. // the same logical description, though designed for different
  1926. // display drivers.
  1927. //
  1928. //
  1929. // Create a font from the logical font, so we can see what font
  1930. // Windows actually choses.
  1931. //
  1932. hfont = CreateFontIndirect(&enumlogFont->elfLogFont);
  1933. holdfont = SelectFont(hdc, hfont);
  1934. //
  1935. // Find the metrics of the font that Windows has actually selected.
  1936. //
  1937. GetTextMetrics(hdc, &tm);
  1938. //
  1939. // Double check the aspect ratios - enumerate returns all fonts,
  1940. // but it is possible to have fonts that are never matched by
  1941. // Windows due to duplications.
  1942. //
  1943. fAcceptFont = ((tm.tmDigitizedAspectX == TextMetric->tmDigitizedAspectX)
  1944. && (tm.tmDigitizedAspectY == TextMetric->tmDigitizedAspectY));
  1945. }
  1946. //
  1947. // Trace out the full text metrics for debugging.
  1948. //
  1949. if (fAcceptFont)
  1950. {
  1951. //
  1952. // This font is accepted.
  1953. //
  1954. //
  1955. // Determine the font flags settings.
  1956. //
  1957. if ((TextMetric->tmPitchAndFamily & TMPF_FIXED_PITCH) == 0)
  1958. {
  1959. //
  1960. // Setting the TMPF_FIXED_PITCH bit in the text metrics is used
  1961. // to indicate that the font is NOT fixed pitch. What a
  1962. // wonderfully named bit (see Microsoft CD for explanation).
  1963. //
  1964. fontflags |= NF_FIXED_PITCH;
  1965. }
  1966. if ((FontType & RASTER_FONTTYPE) ||
  1967. (FontType & TRUETYPE_FONTTYPE) == 0)
  1968. {
  1969. //
  1970. // This is a raster font, but not a truetype font so it must be
  1971. // of fixed size.
  1972. //
  1973. fontflags |= NF_FIXED_SIZE;
  1974. }
  1975. //
  1976. // Get the font CodePage. SFRFONT: must map from CharSet to
  1977. // Codepage. For now we only support ANSI and OEM charsets. This
  1978. // will need to change to support e.g BiDi/Arabic
  1979. //
  1980. CodePage = TextMetric->tmCharSet;
  1981. if (CodePage == ANSI_CHARSET)
  1982. {
  1983. TRACE_OUT(( "ANSI codepage"));
  1984. CodePage = NF_CP_WIN_ANSI;
  1985. }
  1986. else if (CodePage == OEM_CHARSET)
  1987. {
  1988. TRACE_OUT(( "OEM codepage"));
  1989. CodePage = NF_CP_WIN_OEM;
  1990. }
  1991. else if (CodePage == SYMBOL_CHARSET)
  1992. {
  1993. TRACE_OUT(("Symbol codepage"));
  1994. CodePage = NF_CP_WIN_SYMBOL;
  1995. }
  1996. else
  1997. {
  1998. TRACE_OUT(( "Charset %hu, unknown codepage", CodePage));
  1999. CodePage = NF_CP_UNKNOWN;
  2000. }
  2001. //
  2002. //
  2003. // SFRFONT: We have replaced the "old" checksum which was based on
  2004. // the actual bits making up the font to one based on the widths of
  2005. // characters in the font. The intention is that we use this to
  2006. // ensure that the actual characters in the local font and in the
  2007. // remote font which matches it are all the same width as each
  2008. // other.
  2009. //
  2010. // We calculate this sum for all fonts (not just non-truetype as
  2011. // before) because in cross platform calls with approximate font
  2012. // matching it applies to fonts of all types.
  2013. //
  2014. //
  2015. //
  2016. //
  2017. // There is considerable confusion caused by the terminology for
  2018. // fonts characteristics. The protocol uses two values MAXHEIGHT
  2019. // and AVEHEIGHT. In fact neither of these names is accurate
  2020. // (MAXHEIGHT is not the maximum height of a char; and AVEHEIGHT is
  2021. // not the average height of all chars).
  2022. //
  2023. // SFRFONT: we have added maxAscent to the protocol. This is the
  2024. // height of a capital letter (such as eM!) PLUS any internal
  2025. // leading. This value allows remote boxes to find the baseline -
  2026. // the point at which the bottommost pel of a letter with no
  2027. // descenders (e.g. capital M) is to be drawn. This is needed
  2028. // because not all boxes in the call follow the windows convention
  2029. // of specifying the start of text as being the top-left corner of
  2030. // the first character cell. maxAscent == tmAscent in the
  2031. // TextMetric.
  2032. //
  2033. //
  2034. FHAddFontToLocalTable((LPSTR)enumlogFont->elfLogFont.lfFaceName,
  2035. (TSHR_UINT16)fontflags,
  2036. (TSHR_UINT16)CodePage,
  2037. (TSHR_UINT16)TextMetric->tmHeight,
  2038. (TSHR_UINT16)(TextMetric->tmHeight -
  2039. TextMetric->tmInternalLeading),
  2040. (TSHR_UINT16)TextMetric->tmAveCharWidth,
  2041. (TSHR_UINT16)TextMetric->tmDigitizedAspectX,
  2042. (TSHR_UINT16)TextMetric->tmDigitizedAspectY,
  2043. (TSHR_UINT16)TextMetric->tmAscent);
  2044. }
  2045. else
  2046. {
  2047. //
  2048. // Windows returns a different font when we use this logical font
  2049. // description - presumably because of duplicate fonts. We
  2050. // therfore must not claim to support this particular font.
  2051. //
  2052. TRACE_OUT(( "Discarding hidden font %s",
  2053. enumlogFont->elfLogFont.lfFaceName));
  2054. }
  2055. if (hfont)
  2056. {
  2057. //
  2058. // We called CreateFont in processing this font, so now delete it
  2059. // to clean up.
  2060. //
  2061. SelectFont(hdc, holdfont);
  2062. //
  2063. // We have finished with the font so delete it.
  2064. //
  2065. DeleteFont(hfont);
  2066. }
  2067. DC_EXIT_POINT:
  2068. DebugExitDWORD(FHEachFont, rc);
  2069. return(rc);
  2070. }
  2071. //
  2072. // FHConsiderAllLocalFonts
  2073. //
  2074. // Considers the details of each of the fonts on the local system, and if
  2075. // acceptable adds them to the local font list.
  2076. //
  2077. //
  2078. void FHConsiderAllLocalFonts(void)
  2079. {
  2080. HDC hdcDesktop;
  2081. UINT i;
  2082. UINT iFont;
  2083. LPFONTNAME newFontList;
  2084. LPFHFAMILIES lpFamilies = NULL;
  2085. DebugEntry(FHConsiderAllLocalFonts);
  2086. g_fhFonts->fhNumFonts = 0;
  2087. //
  2088. // We can't enumerate all the fonts directly; we have to enumerate the
  2089. // family names, then the fonts within each family.
  2090. //
  2091. // This alloc assumes the worst case memory-wise (i.e. each
  2092. // family contains a single font) and therefore we will usually
  2093. // allocate more memory than we need. We use LocalReAlloc later to fix
  2094. // this.
  2095. //
  2096. lpFamilies = new FHFAMILIES;
  2097. if (!lpFamilies)
  2098. {
  2099. ERROR_OUT(("Failed to alloc FHFAMILIES"));
  2100. DC_QUIT;
  2101. }
  2102. SET_STAMP(lpFamilies, FHFAMILIES);
  2103. hdcDesktop = GetWindowDC(HWND_DESKTOP);
  2104. //
  2105. // Find all the font family names.
  2106. //
  2107. lpFamilies->fhcFamilies = 0;
  2108. EnumFontFamilies(hdcDesktop, NULL,(FONTENUMPROC)FHEachFontFamily,
  2109. (LPARAM)lpFamilies);
  2110. TRACE_OUT(("Found %d font families ", lpFamilies->fhcFamilies));
  2111. //
  2112. // Now enumerate each font for each family
  2113. //
  2114. for (i = 0; i < lpFamilies->fhcFamilies; i++)
  2115. {
  2116. TRACE_OUT(("ASSesion::FHConsiderAllLocalFonts - EnumFontFamilies %s",
  2117. lpFamilies->afhFamilies[i].szFontName));
  2118. for (iFont = 0; iFont < CFONTS_PROBLEM; iFont++)
  2119. {
  2120. if (!lstrcmpi(lpFamilies->afhFamilies[i].szFontName, c_aszProblemFonts[iFont]))
  2121. {
  2122. WARNING_OUT(("Found problem font %s",
  2123. lpFamilies->afhFamilies[i].szFontName));
  2124. break;
  2125. }
  2126. }
  2127. if (iFont == CFONTS_PROBLEM)
  2128. {
  2129. //
  2130. // Not in the problem list, go ahead.
  2131. //
  2132. EnumFontFamilies(hdcDesktop, lpFamilies->afhFamilies[i].szFontName,
  2133. (FONTENUMPROC)FHEachFont,
  2134. (LPARAM)hdcDesktop);
  2135. }
  2136. else
  2137. {
  2138. WARNING_OUT(("Skipping problem font %s",
  2139. lpFamilies->afhFamilies[i].szFontName));
  2140. }
  2141. }
  2142. ReleaseDC(HWND_DESKTOP, hdcDesktop);
  2143. DC_EXIT_POINT:
  2144. //
  2145. // Having considered all the fonts, we can now free the list of family
  2146. // names.
  2147. //
  2148. if (lpFamilies)
  2149. {
  2150. delete lpFamilies;
  2151. }
  2152. DebugExitVOID(FHConsiderAllLocalFonts);
  2153. }
  2154. //
  2155. // FHGenerateFontWidthTable
  2156. //
  2157. BOOL FHGenerateFontWidthTable(PFHWIDTHTABLE pTable,
  2158. LPLOCALFONT pFontInfo,
  2159. UINT fontHeight,
  2160. UINT fontWidth,
  2161. UINT fontWeight,
  2162. UINT fontFlags,
  2163. LPTSHR_UINT16 pMaxAscent)
  2164. {
  2165. HFONT hNewFont;
  2166. HFONT hOldFont;
  2167. BOOL gdiRC;
  2168. UINT i;
  2169. HDC cachedDC;
  2170. BOOL localRC;
  2171. BOOL functionRC;
  2172. TEXTMETRIC textmetrics;
  2173. int width;
  2174. UINT aFontSizes[256];
  2175. DebugEntry(FHGenerateFontWidthTable);
  2176. //
  2177. // Set the return value to FALSE (unsuccessful). We will set it to
  2178. // TRUE later if the function succeeds.
  2179. //
  2180. functionRC = FALSE;
  2181. //
  2182. // Set the old font handle to NULL. If this is not NULL at the exit
  2183. // point of this function then we will select it back into the cachedDC
  2184. // device context.
  2185. //
  2186. hOldFont = NULL;
  2187. //
  2188. // Set the new font handle to NULL. If this is not NULL at the exit
  2189. // point of this function then the new font will be deleted.
  2190. //
  2191. hNewFont = NULL;
  2192. //
  2193. // Get a cached DC with which to do the query.
  2194. //
  2195. cachedDC = GetDC(HWND_DESKTOP);
  2196. if (cachedDC == NULL)
  2197. {
  2198. WARNING_OUT(( "Failed to get DC"));
  2199. DC_QUIT;
  2200. }
  2201. //
  2202. // Get all the info we need from the local font table.
  2203. //
  2204. localRC = FH_CreateAndSelectFont(cachedDC,
  2205. &hNewFont,
  2206. &hOldFont,
  2207. pFontInfo->RealName,
  2208. pFontInfo->Details.nfCodePage,
  2209. pFontInfo->lMaxBaselineExt,
  2210. fontHeight,
  2211. fontWidth,
  2212. fontWeight,
  2213. fontFlags);
  2214. if (localRC == FALSE)
  2215. {
  2216. ERROR_OUT(( "Failed to create/select font %s, %u, %u",
  2217. pFontInfo->RealName,
  2218. fontHeight,
  2219. fontWidth));
  2220. DC_QUIT;
  2221. }
  2222. //
  2223. // Determine if the current font is a truetype font.
  2224. //
  2225. GetTextMetrics(cachedDC, &textmetrics);
  2226. if (textmetrics.tmPitchAndFamily & TMPF_TRUETYPE)
  2227. {
  2228. //
  2229. // Truetype fonts are ABC spaced.
  2230. //
  2231. ABC abc[256];
  2232. TRACE_OUT(("TrueType font %s, first char %d last char %d",
  2233. pFontInfo->RealName, (UINT)(WORD)textmetrics.tmFirstChar,
  2234. (UINT)(WORD)textmetrics.tmLastChar));
  2235. //
  2236. // Get all widths in one call - faster than getting them separately
  2237. //
  2238. GetCharABCWidths(cachedDC, 0, 255, abc);
  2239. for (i = 0; i < 256; i++)
  2240. {
  2241. width = abc[i].abcA + abc[i].abcB + abc[i].abcC;
  2242. if ((width < 0) || (width > 255))
  2243. {
  2244. //
  2245. // Width is outside the range we can cope with, so quit.
  2246. //
  2247. TRACE_OUT(( "Width %d is outside range", width));
  2248. DC_QUIT;
  2249. }
  2250. pTable->charWidths[i] = (BYTE)width;
  2251. }
  2252. }
  2253. else
  2254. {
  2255. TRACE_OUT(( "Non-truetype font"));
  2256. //
  2257. // Check if the font is fixed or variable pitch - note that a clear
  2258. // bit indicates FIXED, not the reverse which you might expect!
  2259. //
  2260. if ((textmetrics.tmPitchAndFamily & TMPF_FIXED_PITCH) == 0)
  2261. {
  2262. //
  2263. // No need to call GetCharWidth for a fixed width font (and
  2264. // more to the point it can return us bad values if we do)
  2265. //
  2266. for (i = 0; i < 256; i++)
  2267. {
  2268. aFontSizes[i] = textmetrics.tmAveCharWidth;
  2269. }
  2270. }
  2271. else
  2272. {
  2273. //
  2274. // Query the width of each character in the font.
  2275. //
  2276. ZeroMemory(aFontSizes, sizeof(aFontSizes));
  2277. gdiRC = GetCharWidth(cachedDC,
  2278. 0,
  2279. 255,
  2280. (LPINT)aFontSizes);
  2281. if (gdiRC == FALSE)
  2282. {
  2283. ERROR_OUT(( "Failed to get char widths for %s, %u, %u",
  2284. pFontInfo->RealName,
  2285. fontHeight,
  2286. fontWidth));
  2287. DC_QUIT;
  2288. }
  2289. }
  2290. //
  2291. // Now copy the widths into the width table.
  2292. // We must adjust the widths to take account of any overhang
  2293. // between characters.
  2294. //
  2295. for (i = 0; i < 256; i++)
  2296. {
  2297. width = aFontSizes[i] - textmetrics.tmOverhang;
  2298. if ((width < 0) || (width > 255))
  2299. {
  2300. TRACE_OUT(( "Width %d is outside range", width));
  2301. DC_QUIT;
  2302. }
  2303. pTable->charWidths[i] = (BYTE)width;
  2304. }
  2305. }
  2306. //
  2307. // The font table has been successfully generated.
  2308. //
  2309. functionRC = TRUE;
  2310. TRACE_OUT(( "Generated font table for: %s", pFontInfo->RealName));
  2311. //
  2312. // Return the maxAscent value, as we have easy access to it here. This
  2313. // saves us having to create the font again later to find it.
  2314. //
  2315. TRACE_OUT(( "Updating maxAscent %hu -> %hu",
  2316. *pMaxAscent,
  2317. (TSHR_UINT16)textmetrics.tmAscent));
  2318. *pMaxAscent = (TSHR_UINT16)textmetrics.tmAscent;
  2319. DC_EXIT_POINT:
  2320. if (hOldFont != NULL)
  2321. {
  2322. SelectFont(cachedDC, hOldFont);
  2323. }
  2324. if (hNewFont != NULL)
  2325. {
  2326. DeleteFont(hNewFont);
  2327. }
  2328. if (cachedDC != NULL)
  2329. {
  2330. ReleaseDC(HWND_DESKTOP, cachedDC);
  2331. }
  2332. DebugExitDWORD(FHGenerateFontWidthTable, functionRC);
  2333. return(functionRC);
  2334. }
  2335. //
  2336. // Define a macro to simplify the following code. This returns the first
  2337. // character in the name of the font at position i in the local table.
  2338. //
  2339. //
  2340. // nfFaceName is an array of CHARs, which are SIGNED. We need to treat them
  2341. // as UNSIGNED values, they are indeces from 0 to 255 into the font hash
  2342. // table.
  2343. //
  2344. #define LF_FIRSTCHAR(i) (BYTE)g_fhFonts->afhFonts[i].Details.nfFaceName[0]
  2345. //
  2346. // Name: FHSortAndIndexLocalFonts
  2347. //
  2348. // Purpose: Sorts local font table by font name and generates an index for
  2349. // quicker searching in the display driver.
  2350. //
  2351. // Returns: None.
  2352. //
  2353. // Params: None.
  2354. //
  2355. //
  2356. void FHSortAndIndexLocalFonts(void)
  2357. {
  2358. TSHR_UINT16 thisIndexEntry;
  2359. TSHR_UINT16 fontTablePos;
  2360. DebugEntry(FHSortAndIndexLocalFonts);
  2361. //
  2362. // Check there are actually some fonts to sort/index
  2363. //
  2364. if (0 == g_fhFonts->fhNumFonts)
  2365. {
  2366. WARNING_OUT(( "No fonts to sort/index"));
  2367. DC_QUIT;
  2368. }
  2369. //
  2370. // Use qsort to do the sort. We sort on the font name, ascending.
  2371. // Therefore we must use STRCMP and not lstrcmp. The latter sorts
  2372. // by 'word' method, where upper case sorts before lower case. But
  2373. // our NT driver has no access to a similar routine. And this code +
  2374. // driver code must be in ssync for the driver to successfully search
  2375. // the sorted font table.
  2376. //
  2377. FH_qsort(g_fhFonts->afhFonts, g_fhFonts->fhNumFonts, sizeof(LOCALFONT));
  2378. TRACE_OUT(( "Sorted local font list"));
  2379. //
  2380. // Now generate the index. Each element i in the g_fhFonts->afhFontIndex
  2381. // array must indicate the first entry in the local font table
  2382. // beginning with character i. If there are no fonts beginning with
  2383. // character i, then the element is set to USHRT_MAX (i.e. a large
  2384. // value).
  2385. //
  2386. //
  2387. // First clear the index table to unused entries.
  2388. //
  2389. for (thisIndexEntry = 0;
  2390. thisIndexEntry < FH_LOCAL_INDEX_SIZE;
  2391. thisIndexEntry++)
  2392. {
  2393. g_fhFonts->afhFontIndex[thisIndexEntry] = USHRT_MAX;
  2394. }
  2395. //
  2396. // Now fill in the useful information.
  2397. //
  2398. // This for loop steps through the index array, using the first
  2399. // character of the first font in the local table as its start point.
  2400. // Since the font table is alphabetically sorted, this will correspond
  2401. // to the first index entry that needs filling in.
  2402. //
  2403. // The terminating condition for this loop may seem a little odd, but
  2404. // works because fontTablePos will always reach a value of g_fhFonts->fhNumFonts
  2405. // before thisIndexEntry gets to the last index element.
  2406. //
  2407. fontTablePos = 0;
  2408. for (thisIndexEntry = LF_FIRSTCHAR(0);
  2409. fontTablePos < g_fhFonts->fhNumFonts;
  2410. thisIndexEntry++)
  2411. {
  2412. //
  2413. // Don't do anything until we get to the index element
  2414. // corresponding to the first character in the font pointed to by
  2415. // fontTablePos. (We'll be there straight away on the first pass)
  2416. //
  2417. if (thisIndexEntry == LF_FIRSTCHAR(fontTablePos))
  2418. {
  2419. //
  2420. // We've found the first font table entry starting with
  2421. // character thisIndexEntry, so enter it in the index.
  2422. //
  2423. g_fhFonts->afhFontIndex[thisIndexEntry] = fontTablePos;
  2424. //
  2425. // Now zip past the rest of the local font table entries that
  2426. // start with this character, also checking that we haven't got
  2427. // to the end of the font table.
  2428. //
  2429. // If the latter happens, it means we've finished and the check
  2430. // in the for statement will ensure that we exit the loop.
  2431. //
  2432. while ((LF_FIRSTCHAR(fontTablePos) == thisIndexEntry) &&
  2433. (fontTablePos < g_fhFonts->fhNumFonts))
  2434. {
  2435. fontTablePos++;
  2436. }
  2437. }
  2438. }
  2439. TRACE_OUT(( "Built local font table index"));
  2440. DC_EXIT_POINT:
  2441. DebugExitVOID(FHSortAndIndexLocalFonts);
  2442. }
  2443. //
  2444. // FHComp()
  2445. // This is a wrapper around strcmp(), which becomes an inline function in
  2446. // retail. It also handles the casting of the LPVOIDs.
  2447. //
  2448. //
  2449. // Compare item 1, item 2
  2450. //
  2451. int FHComp
  2452. (
  2453. LPVOID lpFont1,
  2454. LPVOID lpFont2
  2455. )
  2456. {
  2457. return(strcmp(((LPLOCALFONT)lpFont1)->Details.nfFaceName,
  2458. ((LPLOCALFONT)lpFont2)->Details.nfFaceName));
  2459. }
  2460. //
  2461. // FH_qsort(base, num, wid) - quicksort function for sorting arrays
  2462. //
  2463. // Purpose:
  2464. // quicksort the array of elements
  2465. // side effects: sorts in place
  2466. //
  2467. // Entry:
  2468. // char *base = pointer to base of array
  2469. // unsigned num = number of elements in the array
  2470. // unsigned width = width in bytes of each array element
  2471. //
  2472. // Exit:
  2473. // returns void
  2474. //
  2475. // Exceptions:
  2476. //
  2477. // sort the array between lo and hi (inclusive)
  2478. void FH_qsort
  2479. (
  2480. LPVOID base,
  2481. UINT num,
  2482. UINT width
  2483. )
  2484. {
  2485. LPSTR lo;
  2486. LPSTR hi;
  2487. LPSTR mid;
  2488. LPSTR loguy;
  2489. LPSTR higuy;
  2490. UINT size;
  2491. char *lostk[30], *histk[30];
  2492. int stkptr; // stack for saving sub-array to be processed
  2493. // Note: the number of stack entries required is no more than
  2494. // 1 + log2(size), so 30 is sufficient for any array
  2495. ASSERT(width);
  2496. if (num < 2)
  2497. return; // nothing to do
  2498. stkptr = 0; // initialize stack
  2499. lo = (LPSTR)base;
  2500. hi = (LPSTR)base + width * (num-1); // initialize limits
  2501. // this entry point is for pseudo-recursion calling: setting
  2502. // lo and hi and jumping to here is like recursion, but stkptr is
  2503. // prserved, locals aren't, so we preserve stuff on the stack
  2504. recurse:
  2505. size = (UINT)(hi - lo) / width + 1; // number of el's to sort
  2506. // below a certain size, it is faster to use a O(n^2) sorting method
  2507. if (size <= CUTOFF)
  2508. {
  2509. shortsort(lo, hi, width);
  2510. }
  2511. else
  2512. {
  2513. // First we pick a partititioning element. The efficiency of the
  2514. // algorithm demands that we find one that is approximately the
  2515. // median of the values, but also that we select one fast. Using
  2516. // the first one produces bad performace if the array is already
  2517. // sorted, so we use the middle one, which would require a very
  2518. // weirdly arranged array for worst case performance. Testing shows
  2519. // that a median-of-three algorithm does not, in general, increase
  2520. // performance.
  2521. mid = lo + (size / 2) * width; // find middle element
  2522. swap(mid, lo, width); // swap it to beginning of array
  2523. // We now wish to partition the array into three pieces, one
  2524. // consisiting of elements <= partition element, one of elements
  2525. // equal to the parition element, and one of element >= to it. This
  2526. // is done below; comments indicate conditions established at every
  2527. // step.
  2528. loguy = lo;
  2529. higuy = hi + width;
  2530. // Note that higuy decreases and loguy increases on every iteration,
  2531. // so loop must terminate.
  2532. for (;;) {
  2533. // lo <= loguy < hi, lo < higuy <= hi + 1,
  2534. // A[i] <= A[lo] for lo <= i <= loguy,
  2535. // A[i] >= A[lo] for higuy <= i <= hi
  2536. do
  2537. {
  2538. loguy += width;
  2539. }
  2540. while ((loguy <= hi) && (FHComp(loguy, lo) <= 0));
  2541. // lo < loguy <= hi+1, A[i] <= A[lo] for lo <= i < loguy,
  2542. // either loguy > hi or A[loguy] > A[lo]
  2543. do
  2544. {
  2545. higuy -= width;
  2546. }
  2547. while ((higuy > lo) && (FHComp(higuy, lo) >= 0));
  2548. // lo-1 <= higuy <= hi, A[i] >= A[lo] for higuy < i <= hi,
  2549. // either higuy <= lo or A[higuy] < A[lo]
  2550. if (higuy < loguy)
  2551. break;
  2552. // if loguy > hi or higuy <= lo, then we would have exited, so
  2553. // A[loguy] > A[lo], A[higuy] < A[lo],
  2554. // loguy < hi, highy > lo
  2555. swap(loguy, higuy, width);
  2556. // A[loguy] < A[lo], A[higuy] > A[lo]; so condition at top
  2557. // of loop is re-established
  2558. }
  2559. // A[i] >= A[lo] for higuy < i <= hi,
  2560. // A[i] <= A[lo] for lo <= i < loguy,
  2561. // higuy < loguy, lo <= higuy <= hi
  2562. // implying:
  2563. // A[i] >= A[lo] for loguy <= i <= hi,
  2564. // A[i] <= A[lo] for lo <= i <= higuy,
  2565. // A[i] = A[lo] for higuy < i < loguy
  2566. swap(lo, higuy, width); // put partition element in place
  2567. // OK, now we have the following:
  2568. // A[i] >= A[higuy] for loguy <= i <= hi,
  2569. // A[i] <= A[higuy] for lo <= i < higuy
  2570. // A[i] = A[lo] for higuy <= i < loguy
  2571. // We've finished the partition, now we want to sort the subarrays
  2572. // [lo, higuy-1] and [loguy, hi].
  2573. // We do the smaller one first to minimize stack usage.
  2574. // We only sort arrays of length 2 or more.
  2575. if ( higuy - 1 - lo >= hi - loguy ) {
  2576. if (lo + width < higuy) {
  2577. lostk[stkptr] = lo;
  2578. histk[stkptr] = higuy - width;
  2579. ++stkptr;
  2580. } // save big recursion for later
  2581. if (loguy < hi) {
  2582. lo = loguy;
  2583. goto recurse; // do small recursion
  2584. }
  2585. }
  2586. else {
  2587. if (loguy < hi) {
  2588. lostk[stkptr] = loguy;
  2589. histk[stkptr] = hi;
  2590. ++stkptr; // save big recursion for later
  2591. }
  2592. if (lo + width < higuy) {
  2593. hi = higuy - width;
  2594. goto recurse; // do small recursion
  2595. }
  2596. }
  2597. }
  2598. // We have sorted the array, except for any pending sorts on the stack.
  2599. // Check if there are any, and do them.
  2600. --stkptr;
  2601. if (stkptr >= 0) {
  2602. lo = lostk[stkptr];
  2603. hi = histk[stkptr];
  2604. goto recurse; // pop subarray from stack
  2605. }
  2606. else
  2607. return; // all subarrays done
  2608. }
  2609. //
  2610. // shortsort(hi, lo, width) - insertion sort for sorting short arrays
  2611. //
  2612. // Purpose:
  2613. // sorts the sub-array of elements between lo and hi (inclusive)
  2614. // side effects: sorts in place
  2615. // assumes that lo < hi
  2616. //
  2617. // Entry:
  2618. // char *lo = pointer to low element to sort
  2619. // char *hi = pointer to high element to sort
  2620. // unsigned width = width in bytes of each array element
  2621. //
  2622. // Exit:
  2623. // returns void
  2624. //
  2625. // Exceptions:
  2626. //
  2627. void shortsort
  2628. (
  2629. char *lo,
  2630. char *hi,
  2631. unsigned int width
  2632. )
  2633. {
  2634. char *p, *max;
  2635. // Note: in assertions below, i and j are alway inside original bound of
  2636. // array to sort.
  2637. while (hi > lo) {
  2638. // A[i] <= A[j] for i <= j, j > hi
  2639. max = lo;
  2640. for (p = lo+width; p <= hi; p += width) {
  2641. // A[i] <= A[max] for lo <= i < p
  2642. if (FHComp(p, max) > 0)
  2643. {
  2644. max = p;
  2645. }
  2646. // A[i] <= A[max] for lo <= i <= p
  2647. }
  2648. // A[i] <= A[max] for lo <= i <= hi
  2649. swap(max, hi, width);
  2650. // A[i] <= A[hi] for i <= hi, so A[i] <= A[j] for i <= j, j >= hi
  2651. hi -= width;
  2652. // A[i] <= A[j] for i <= j, j > hi, loop top condition established
  2653. }
  2654. // A[i] <= A[j] for i <= j, j > lo, which implies A[i] <= A[j] for i < j,
  2655. // so array is sorted
  2656. }
  2657. //
  2658. // swap(a, b, width) - swap two elements
  2659. //
  2660. // Purpose:
  2661. // swaps the two array elements of size width
  2662. //
  2663. // Entry:
  2664. // char *a, *b = pointer to two elements to swap
  2665. // unsigned width = width in bytes of each array element
  2666. //
  2667. // Exit:
  2668. // returns void
  2669. //
  2670. // Exceptions:
  2671. //
  2672. void swap (
  2673. char *a,
  2674. char *b,
  2675. unsigned int width
  2676. )
  2677. {
  2678. char tmp;
  2679. if ( a != b )
  2680. // Do the swap one character at a time to avoid potential alignment
  2681. // problems.
  2682. while ( width-- ) {
  2683. tmp = *a;
  2684. *a++ = *b;
  2685. *b++ = tmp;
  2686. }
  2687. }