Source code of Windows XP (NT5)
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.

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