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.

1742 lines
53 KiB

  1. /***************************************************************************
  2. * ELSEPAN.C - ElseWare PANOSE(tm) 1.0 Font Mapper routines.
  3. *
  4. * $keywords: elsepan.c 1.5 19-Jul-93 11:15:09 AM$
  5. *
  6. * Copyright (C) 1991-93 ElseWare Corporation. All rights reserved.
  7. ***************************************************************************/
  8. #define ELSE_MAPPER_CORE
  9. #include <windows.h>
  10. #include "elsepan.h"
  11. /* Sanity check: this is the poor man's way to make sure the mapstate
  12. * we get is valid. We init this value during startup and check it upon
  13. * entry to every API routine.
  14. *
  15. * Note it is a good idea to modify SANITY_VALUE every time you make a
  16. * significant change to the software just in case the mapper ends up
  17. * in an environment where there may be multiple copies of it running,
  18. * or if client software tries to save the mapstate (which is a no-no: it
  19. * should use the API to get and set the exposed mapstate variables).
  20. */
  21. #ifndef NOELSEWEIGHTS
  22. #define SANITY_VALUE 0xD0CACA12L
  23. #else
  24. #define SANITY_VALUE 0xD0CACA13L
  25. #endif
  26. #define M_SANE(lpMapState) \
  27. (((lpMapState) != NULL) && ((lpMapState)->ulSanity == SANITY_VALUE))
  28. #define M_lpjOFFS(lpDB, lOffs) (((EW_LPBYTE)(lpDB)) + (lOffs))
  29. #ifndef M_ELSEMEMCPY
  30. #define ELSELOCALMEMCPY
  31. #define M_ELSEMEMCPY(dst, src, len) s_lpPANMemCpy((dst), (src), (len))
  32. LOCAL EW_LPBYTE EW_NEAR EW_PASCAL s_lpPANMemCpy
  33. ELSEARGS (( EW_LPBYTE lpDst, EW_LPBYTE lpSrc, EW_USHORT unLen ));
  34. #endif
  35. LOCAL EW_LPPIND_MEM EW_NEAR EW_PASCAL s_lpPANGetIndRec
  36. ELSEARGS (( EW_LPPDICT_MEM lpPDB, EW_LPBYTE EW_FAR *lplpPanWant,
  37. EW_LPBYTE EW_FAR *lplpPanThis ));
  38. LOCAL EW_BOOL EW_NEAR EW_PASCAL s_bPANGetPenaltyC0
  39. ELSEARGS (( EW_LPPIND_MEM lpPanIndRec, EW_LPPTBL_C0_MEM lpPC0,
  40. EW_LPUSHORT lpunMatch, EW_USHORT unTblSize, EW_USHORT unAttrA,
  41. EW_USHORT unAttrB ));
  42. LOCAL EW_USHORT EW_NEAR EW_PASCAL s_unPANGetPenaltyC1
  43. ELSEARGS (( EW_USHORT unAttrA, EW_USHORT unAttrB ));
  44. LOCAL EW_BOOL EW_NEAR EW_PASCAL s_bPANGetPenaltyC2
  45. ELSEARGS (( EW_LPPIND_MEM lpPanIndRec, EW_LPBYTE lpPTbl,
  46. EW_LPUSHORT lpunMatch, EW_USHORT unTblSize,
  47. EW_USHORT unAttrA, EW_USHORT unAttrB ));
  48. LOCAL EW_USHORT EW_NEAR EW_PASCAL s_unPANGetPenaltyC4
  49. ELSEARGS (( EW_LPPTBL_C4_MEM lpPC4, EW_USHORT unAttrA,
  50. EW_USHORT unAttrB ));
  51. LOCAL EW_LPBYTE EW_NEAR EW_PASCAL s_lpPANGetWeights
  52. ELSEARGS (( EW_LPMAPSTATE lpMapState, EW_LPPDICT_MEM lpPDB,
  53. EW_LPPIND_MEM lpPanIndRec ));
  54. LOCAL EW_BOOL EW_NEAR EW_PASCAL s_bPANMatchDigits
  55. ELSEARGS (( EW_LPPDICT_MEM lpPDB, EW_LPUSHORT lpunMatchTotal,
  56. EW_LPPIND_MEM lpPanIndRec, EW_LPPTBL_MEM lpPTblRec, EW_USHORT unWt,
  57. EW_USHORT unAttrA, EW_USHORT unAttrB ));
  58. /***************************************************************************
  59. * FUNCTION: nPANMapInit
  60. *
  61. * PURPOSE: Initialize the font mapper. Fill in the default settings.
  62. *
  63. * RETURNS: Return the size of the map-state struct if successful, or
  64. * the negative size if the passed in struct was too small.
  65. * The function returns zero if it failed to initialize.
  66. ***************************************************************************/
  67. EW_SHORT EW_FAR EW_PASCAL nPANMapInit( EW_LPMAPSTATE lpMapState,
  68. EW_USHORT unSizeMapState)
  69. {
  70. EW_USHORT i;
  71. EW_LPPDICT_MEM lpPDB;
  72. EW_LPBYTE lpPanDef;
  73. EW_LPBYTE lpjWtA;
  74. EW_LPBYTE lpjWtB;
  75. //
  76. // Simple version check: make sure we got the right size struct.
  77. //
  78. if( unSizeMapState < sizeof( EW_MAPSTATE ) )
  79. {
  80. if( unSizeMapState >= sizeof( EW_ULONG ) )
  81. {
  82. lpMapState->ulSanity = 0L;
  83. }
  84. return( -(EW_SHORT) sizeof( EW_MAPSTATE ) );
  85. }
  86. lpMapState->ulSanity = 0L;
  87. //
  88. // Attempt to allocate the penalty database. We keep the handle
  89. // until the mapper is disabled.
  90. //
  91. if( !( lpMapState->ulhPan1Data = M_lAllocPAN1DATA( ) ) )
  92. {
  93. goto errout0;
  94. }
  95. //
  96. // Make sure the penalty database is the right version and
  97. // in the right byte ordering.
  98. //
  99. if( !( lpPDB = M_lLockPAN1DATA( lpMapState->ulhPan1Data ) ) )
  100. {
  101. goto errout1;
  102. }
  103. if( ( lpPDB->unVersion != PANOSE_PENALTY_VERS ) ||
  104. ( lpPDB->unByteOrder != PTBL_BYTE_ORDER ) )
  105. {
  106. goto errout2;
  107. }
  108. M_bUnlockPAN1DATA( lpMapState->ulhPan1Data );
  109. //
  110. // Fill in defaults.
  111. //
  112. lpMapState->unThreshold = ELSEDEFTHRESHOLD;
  113. lpMapState->unRelaxThresholdCount = 0;
  114. lpMapState->bUseDef = TRUE;
  115. //
  116. // Initial default font is the PANOSE number for Courier.
  117. //
  118. lpPanDef = lpMapState->ajPanDef;
  119. lpPanDef[PAN_IND_FAMILY] = FAMILY_LATTEXT;
  120. lpPanDef[PAN_IND_SERIF] = SERIF_THIN;
  121. lpPanDef[PAN_IND_WEIGHT] = WEIGHT_THIN;
  122. lpPanDef[PAN_IND_PROPORTION] = PROPORTION_MONOSPACE;
  123. lpPanDef[PAN_IND_CONTRAST] = CONTRAST_NONE;
  124. lpPanDef[PAN_IND_STROKE] = STROKE_GRADVERT;
  125. lpPanDef[PAN_IND_ARMSTYLE] = ARM_STRAIGHTSGLSERIF;
  126. lpPanDef[PAN_IND_LTRFORM] = LTRFORM_NORMCONTACT;
  127. lpPanDef[PAN_IND_MIDLINE] = MIDLINE_STDSERIFED;
  128. lpPanDef[PAN_IND_XHEIGHT] = XHEIGHT_CONSTLARGE;
  129. #ifndef NOELSEWEIGHTS
  130. //
  131. // Initialize the custom weights array.
  132. //
  133. for( i = 0, lpjWtA = lpMapState->ajWtRefA,
  134. lpjWtB = lpMapState->ajWtRefB;
  135. i < MAX_CUSTOM_WEIGHTS;
  136. ++i, *lpjWtA++ = PANOSE_ANY, *lpjWtB++ = PANOSE_ANY)
  137. ;
  138. #endif
  139. //
  140. // This value is checked by all other functions, in an attempt
  141. // to safeguard against a mapstate that we didn't initialize.
  142. //
  143. lpMapState->ulSanity = SANITY_VALUE;
  144. //
  145. // Normal return.
  146. //
  147. return( sizeof( EW_MAPSTATE ) );
  148. errout2:
  149. M_bUnlockPAN1DATA(lpMapState->ulhPan1Data);
  150. errout1:
  151. M_bFreePAN1DATA(lpMapState->ulhPan1Data);
  152. errout0:
  153. return( 0 );
  154. }
  155. /***************************************************************************
  156. * FUNCTION: bPANMapClose
  157. *
  158. * PURPOSE: Free the penalty database and close the font mapper. Also
  159. * clear the sanity value so we will not service any more calls
  160. * on this mapstate.
  161. *
  162. * RETURNS: The function returns TRUE if the penalty database is
  163. * successfully freed.
  164. ***************************************************************************/
  165. EW_BOOL EW_FAR EW_PASCAL bPANMapClose( EW_LPMAPSTATE lpMapState )
  166. {
  167. if( M_SANE( lpMapState ) )
  168. {
  169. lpMapState->ulSanity = 0L;
  170. return( M_bFreePAN1DATA( lpMapState->ulhPan1Data ) );
  171. }
  172. return( FALSE );
  173. }
  174. #ifndef NOELSEPICKFONTS
  175. /***************************************************************************
  176. * FUNCTION: nPANGetMapDefault
  177. *
  178. * PURPOSE: Fill in the passed-in PANOSE number structure with the
  179. * default font.
  180. *
  181. * RETURNS: Return 0 if the default number was not copied (passed-in
  182. * structure too small), or NUM_PAN_DIGITS if it was.
  183. ***************************************************************************/
  184. EW_SHORT EW_FAR EW_PASCAL nPANGetMapDefault( EW_LPMAPSTATE lpMapState,
  185. EW_LPBYTE lpPanDef,
  186. EW_USHORT unSizePanDef)
  187. {
  188. //
  189. // Sanity checks.
  190. //
  191. if( !M_SANE( lpMapState ) || ( unSizePanDef < SIZE_PAN1_NUM ) )
  192. {
  193. return( 0 );
  194. }
  195. //
  196. // Copy the number.
  197. //
  198. M_ELSEMEMCPY( lpPanDef, lpMapState->ajPanDef, SIZE_PAN1_NUM );
  199. return( NUM_PAN_DIGITS );
  200. }
  201. /***************************************************************************
  202. * FUNCTION: nPANSetMapDefault
  203. *
  204. * PURPOSE: Make the passed-in PANOSE number the new default font. There
  205. * is no sanity checking on the number.
  206. *
  207. * RETURNS: Return 0 if the default number was not copied (passed-in
  208. * structure too small), or NUM_PAN_DIGITS if it was.
  209. ***************************************************************************/
  210. EW_SHORT EW_FAR EW_PASCAL nPANSetMapDefault( EW_LPMAPSTATE lpMapState,
  211. EW_LPBYTE lpPanDef,
  212. EW_USHORT unSizePanDef)
  213. {
  214. //
  215. // Sanity checks.
  216. //
  217. if( !M_SANE( lpMapState ) || ( unSizePanDef < SIZE_PAN1_NUM ) )
  218. {
  219. return( 0 );
  220. }
  221. //
  222. // Copy the number.
  223. //
  224. M_ELSEMEMCPY( lpMapState->ajPanDef, lpPanDef, SIZE_PAN1_NUM );
  225. return( NUM_PAN_DIGITS );
  226. }
  227. /***************************************************************************
  228. * FUNCTION: bPANEnableMapDefault
  229. *
  230. * PURPOSE: Enable/disable usage of the default font.
  231. *
  232. * RETURNS: Return the previous usage state, or FALSE in the event of
  233. * an error.
  234. ***************************************************************************/
  235. EW_BOOL EW_FAR EW_PASCAL bPANEnableMapDefault( EW_LPMAPSTATE lpMapState,
  236. EW_BOOL bEnable)
  237. {
  238. if( M_SANE( lpMapState ) )
  239. {
  240. EW_BOOL bPrev = lpMapState->bUseDef;
  241. lpMapState->bUseDef = bEnable;
  242. return( bPrev );
  243. }
  244. else
  245. {
  246. return( FALSE );
  247. }
  248. }
  249. /***************************************************************************
  250. * FUNCTION: bPANIsDefaultEnabled
  251. *
  252. * PURPOSE: This function gets the state of using the default font.
  253. *
  254. * RETURNS: Return TRUE if usage of the default font is enabled, and
  255. * FALSE if it is not or an error occurred.
  256. ***************************************************************************/
  257. EW_BOOL EW_FAR EW_PASCAL bPANIsDefaultEnabled( EW_LPMAPSTATE lpMapState )
  258. {
  259. return( M_SANE( lpMapState ) && lpMapState->bUseDef );
  260. }
  261. #endif /* ifndef NOELSEPICKFONTS */
  262. #ifndef NOELSETHRESHOLD
  263. /***************************************************************************
  264. * FUNCTION: unPANGetMapThreshold
  265. *
  266. * PURPOSE: This function gets the state of using threshold checking
  267. * in the mapper.
  268. *
  269. * RETURNS: Return the match threshold, or zero if an error occurred.
  270. ***************************************************************************/
  271. EW_USHORT EW_FAR EW_PASCAL unPANGetMapThreshold( EW_LPMAPSTATE lpMapState )
  272. {
  273. return( M_SANE( lpMapState ) ? lpMapState->unThreshold : 0 );
  274. }
  275. /***************************************************************************
  276. * FUNCTION: bPANSetMapThreshold
  277. *
  278. * PURPOSE: Change the match threshold.
  279. *
  280. * RETURNS: Return TRUE if the threshold is changed, FALSE if it is
  281. * equal to the match error value and therefore rejected, or
  282. * an error occurred.
  283. ***************************************************************************/
  284. EW_BOOL EW_FAR EW_PASCAL bPANSetMapThreshold( EW_LPMAPSTATE lpMapState,
  285. EW_USHORT unThreshold)
  286. {
  287. //
  288. // Cannot set a threshold equal to the error value.
  289. //
  290. if( !M_SANE( lpMapState ) || ( unThreshold == PAN_MATCH_ERROR ) )
  291. {
  292. return( FALSE );
  293. }
  294. //
  295. // Set new threshold.
  296. //
  297. lpMapState->unThreshold = unThreshold;
  298. return( TRUE );
  299. }
  300. /***************************************************************************
  301. * FUNCTION: bPANIsThresholdRelaxed
  302. *
  303. * PURPOSE: This function gets the state of using the threshold in
  304. * mapping.
  305. *
  306. * RETURNS: Return TRUE if the match threshold is relaxed, or FALSE if
  307. * it is not or an error occurred.
  308. ***************************************************************************/
  309. EW_BOOL EW_FAR EW_PASCAL bPANIsThresholdRelaxed( EW_LPMAPSTATE lpMapState )
  310. {
  311. return( M_SANE( lpMapState ) &&( lpMapState->unRelaxThresholdCount > 0 ) );
  312. }
  313. /***************************************************************************
  314. * FUNCTION: vPANRelaxThreshold
  315. *
  316. * PURPOSE: Temporarily relax the threshold variable so every font
  317. * except the erroneous ones will return a match value.
  318. *
  319. * RETURNS: Nothing.
  320. ***************************************************************************/
  321. EW_VOID EW_FAR EW_PASCAL vPANRelaxThreshold( EW_LPMAPSTATE lpMapState )
  322. {
  323. if( M_SANE( lpMapState ) )
  324. {
  325. ++lpMapState->unRelaxThresholdCount;
  326. }
  327. }
  328. /***************************************************************************
  329. * FUNCTION: bPANRestoreThreshold
  330. *
  331. * PURPOSE: Restore mapping within a threshold.
  332. *
  333. * RETURNS: Return TRUE if the threshold is back in effect or an error
  334. * occurred, FALSE if someone else has relaxed it too so it
  335. * still is relaxed. We return TRUE on error in the event someone
  336. * rights a 'for' loop restoring until TRUE is returned.
  337. ***************************************************************************/
  338. EW_BOOL EW_FAR EW_PASCAL bPANRestoreThreshold( EW_LPMAPSTATE lpMapState )
  339. {
  340. if( M_SANE( lpMapState ) &&( lpMapState->unRelaxThresholdCount > 0 ) )
  341. {
  342. return( --lpMapState->unRelaxThresholdCount == 0 );
  343. }
  344. else
  345. {
  346. return( TRUE );
  347. }
  348. }
  349. #endif /* ifndef NOELSETHRESHOLD */
  350. #ifndef NOELSEWEIGHTS
  351. /***************************************************************************
  352. * FUNCTION: bPANGetMapWeights
  353. *
  354. * PURPOSE: Retrieve the mapper weight values for the passed-in family
  355. * digits pair. The variable *lpbIsCustom is set if custom
  356. * mapper weights have been set by the caller.
  357. *
  358. * The weights array is an array of 10 bytes corresponding to
  359. * the 10 PANOSE digits. The first weight is ignored (and usually
  360. * set to zero) because we never actually assess a weighted
  361. * penalty on the family digit. We include it so the index
  362. * constants may be used to access the values in the weights
  363. * array.
  364. *
  365. * RETURNS: Return TRUE if mapper weights were retrieved/available (it is
  366. * legal for the caller to pass in NULL for lpjWts), or FALSE
  367. * if none exist.
  368. ***************************************************************************/
  369. EW_BOOL EW_FAR EW_PASCAL bPANGetMapWeights( EW_LPMAPSTATE lpMapState,
  370. EW_BYTE jFamilyA,
  371. EW_BYTE jFamilyB,
  372. EW_LPBYTE lpjWts,
  373. EW_LPBOOL lpbIsCustom)
  374. {
  375. EW_USHORT i;
  376. EW_BOOL bFound = FALSE;
  377. EW_LPPDICT_MEM lpPDB;
  378. EW_LPPIND_MEM lpPanIndRec;
  379. EW_LPBYTE lpjWtA;
  380. EW_LPBYTE lpjWtB;
  381. //
  382. // Sanity test on the family digits.
  383. //
  384. if( !M_SANE( lpMapState ) ||
  385. ( jFamilyA <= PANOSE_NOFIT ) ||( jFamilyA > MAX_PAN1_FAMILY ) ||
  386. ( jFamilyB <= PANOSE_NOFIT ) ||( jFamilyB > MAX_PAN1_FAMILY ) )
  387. {
  388. return( FALSE );
  389. }
  390. //
  391. // Search for custom weights.
  392. //
  393. for( i = 0, lpjWtA = lpMapState->ajWtRefA, lpjWtB = lpMapState->ajWtRefB;
  394. !bFound && ( i < MAX_CUSTOM_WEIGHTS ) && *lpjWtA;
  395. ++i, ++lpjWtA, ++lpjWtB)
  396. {
  397. //
  398. // If custom weights are found then set *lpbIsCustom to
  399. // TRUE, copy the weights, and return success.
  400. //
  401. if( ( (*lpjWtA == jFamilyA ) &&( *lpjWtB == jFamilyB ) ) ||
  402. ( (*lpjWtA == jFamilyB ) &&( *lpjWtB == jFamilyA ) ) )
  403. {
  404. if( lpjWts )
  405. {
  406. M_ELSEMEMCPY( lpjWts,
  407. &lpMapState->ajCustomWt[SIZE_PAN1_NUM * i],
  408. SIZE_PAN1_NUM );
  409. }
  410. if( lpbIsCustom )
  411. {
  412. *lpbIsCustom = TRUE;
  413. }
  414. bFound = TRUE;
  415. }
  416. }
  417. //
  418. // No custom weights available. Search the penalty database
  419. // for default weights.
  420. //
  421. if( !bFound && ( lpPDB = M_lLockPAN1DATA( lpMapState->ulhPan1Data ) ) )
  422. {
  423. for( i = 0, lpPanIndRec = lpPDB->pind;
  424. !bFound && ( i < lpPDB->unNumDicts );
  425. ++i, ++lpPanIndRec )
  426. {
  427. if( ( (lpPanIndRec->jFamilyA == jFamilyA ) &&
  428. ( lpPanIndRec->jFamilyB == jFamilyB ) ) ||
  429. ( (lpPanIndRec->jFamilyA == jFamilyB ) &&
  430. ( lpPanIndRec->jFamilyB == jFamilyA ) ) )
  431. {
  432. if( lpPanIndRec->unOffsWts )
  433. {
  434. if( lpjWts )
  435. {
  436. M_ELSEMEMCPY( lpjWts,
  437. M_lpjOFFS( lpPDB, lpPanIndRec->unOffsWts ),
  438. SIZE_PAN1_NUM );
  439. }
  440. if( lpbIsCustom )
  441. {
  442. *lpbIsCustom = FALSE;
  443. }
  444. bFound = TRUE;
  445. }
  446. }
  447. }
  448. M_bUnlockPAN1DATA( lpMapState->ulhPan1Data );
  449. }
  450. //
  451. // Return the result of the search.
  452. //
  453. return( bFound );
  454. }
  455. /***************************************************************************
  456. * FUNCTION: bPANSetMapWeights
  457. *
  458. * PURPOSE: Set the mapper weight values for the passed-in family
  459. * digits pair.
  460. *
  461. * The weights array is an array of 10 bytes corresponding to
  462. * the 10 PANOSE digits. The first weight is ignored (and usually
  463. * set to zero) because we never actually assess a weighted
  464. * penalty on the family digit. We include it so the index
  465. * constants may be used to access the values in the weights
  466. * array.
  467. *
  468. * RETURNS: Return TRUE if mapper weights were set, or FALSE if this
  469. * family pair is not supported by the mapper or there is no
  470. * more room for custom mapper weights.
  471. ***************************************************************************/
  472. EW_BOOL EW_FAR EW_PASCAL bPANSetMapWeights( EW_LPMAPSTATE lpMapState,
  473. EW_BYTE jFamilyA,
  474. EW_BYTE jFamilyB,
  475. EW_LPBYTE lpjWts )
  476. {
  477. EW_USHORT i;
  478. EW_BOOL bFound;
  479. EW_LPPDICT_MEM lpPDB;
  480. EW_LPPIND_MEM lpPanIndRec;
  481. EW_LPBYTE lpjWtA;
  482. EW_LPBYTE lpjWtB;
  483. EW_LPBYTE lpjWtFam;
  484. //
  485. // Sanity test on the family digits.
  486. //
  487. if( !M_SANE( lpMapState ) || !lpjWts ||
  488. ( jFamilyA <= PANOSE_NOFIT ) ||( jFamilyA > MAX_PAN1_FAMILY ) ||
  489. ( jFamilyB <= PANOSE_NOFIT ) ||( jFamilyB > MAX_PAN1_FAMILY ) )
  490. {
  491. return( FALSE );
  492. }
  493. //
  494. // First make sure this family pair exists in the penalty
  495. // database (it does not make sense to store penalties for
  496. // a family pair we'll never map against).
  497. //
  498. if( lpPDB = M_lLockPAN1DATA( lpMapState->ulhPan1Data ) )
  499. {
  500. for( i = 0, bFound = FALSE, lpPanIndRec = lpPDB->pind;
  501. i < lpPDB->unNumDicts; ++i, ++lpPanIndRec)
  502. {
  503. if( ( (lpPanIndRec->jFamilyA == jFamilyA ) &&
  504. ( lpPanIndRec->jFamilyB == jFamilyB ) ) ||
  505. ( (lpPanIndRec->jFamilyA == jFamilyB ) &&
  506. ( lpPanIndRec->jFamilyB == jFamilyA ) ) )
  507. {
  508. bFound = TRUE;
  509. break;
  510. }
  511. }
  512. M_bUnlockPAN1DATA( lpMapState->ulhPan1Data );
  513. if( !bFound )
  514. {
  515. return( FALSE );
  516. }
  517. }
  518. else
  519. {
  520. return( FALSE );
  521. }
  522. //
  523. // Search for an existing entry.
  524. //
  525. for( i = 0, lpjWtA = lpMapState->ajWtRefA, lpjWtB = lpMapState->ajWtRefB;
  526. ( i < MAX_CUSTOM_WEIGHTS ) && *lpjWtA;
  527. ++i, ++lpjWtA, ++lpjWtB)
  528. {
  529. if( ( (*lpjWtA == jFamilyA ) &&( *lpjWtB == jFamilyB ) ) ||
  530. ( (*lpjWtA == jFamilyB ) &&( *lpjWtB == jFamilyA ) ) )
  531. {
  532. break;
  533. }
  534. }
  535. //
  536. // Abort if the weights were not found and there are no free slots.
  537. //
  538. if( i >= MAX_CUSTOM_WEIGHTS )
  539. {
  540. return( FALSE );
  541. }
  542. //
  543. // We either found the previous weights or have a free slot,
  544. // in both cases copy the passed-in weights. For aesthetics,
  545. // preserve zero for the family weight( it is not used ).
  546. //
  547. *lpjWtA = jFamilyA;
  548. *lpjWtB = jFamilyB;
  549. M_ELSEMEMCPY( lpjWtFam = &lpMapState->ajCustomWt[SIZE_PAN1_NUM * i],
  550. lpjWts, SIZE_PAN1_NUM);
  551. *lpjWtFam = 0;
  552. //
  553. // Return success.
  554. //
  555. return( TRUE );
  556. }
  557. /***************************************************************************
  558. * FUNCTION: bPANClearMapWeights
  559. *
  560. * PURPOSE: Locate the custom mapper weights for the passed-in family
  561. * digit pair and clear them, thus causing the mapper to revert
  562. * back to using the default weights.
  563. *
  564. * RETURNS: Return TRUE if custom mapper weights were located and cleared,
  565. * FALSE if there are no custom weights for the passed-in family
  566. * digit pair.
  567. ***************************************************************************/
  568. EW_BOOL EW_FAR EW_PASCAL bPANClearMapWeights( EW_LPMAPSTATE lpMapState,
  569. EW_BYTE jFamilyA,
  570. EW_BYTE jFamilyB )
  571. {
  572. EW_USHORT i;
  573. EW_USHORT j;
  574. EW_LPBYTE lpjWtA;
  575. EW_LPBYTE lpjWtB;
  576. //
  577. // Sanity test on the family digits.
  578. //
  579. if( !M_SANE( lpMapState ) ||
  580. ( jFamilyA <= PANOSE_NOFIT ) ||( jFamilyA > MAX_PAN1_FAMILY ) ||
  581. ( jFamilyB <= PANOSE_NOFIT ) ||( jFamilyB > MAX_PAN1_FAMILY ) )
  582. {
  583. return( FALSE );
  584. }
  585. //
  586. // Search for custom weights.
  587. //
  588. for( i = 0, lpjWtA = lpMapState->ajWtRefA, lpjWtB = lpMapState->ajWtRefB;
  589. ( i < MAX_CUSTOM_WEIGHTS ) && *lpjWtA;
  590. ++i, ++lpjWtA, ++lpjWtB)
  591. {
  592. //
  593. // If custom weights are found then overwrite them by
  594. // shifting other weights forward in the array.
  595. //
  596. if( ( (*lpjWtA == jFamilyA ) &&( *lpjWtB == jFamilyB ) ) ||
  597. ( (*lpjWtA == jFamilyB ) &&( *lpjWtB == jFamilyA ) ) )
  598. {
  599. for( j = i + 1, ++lpjWtA, ++lpjWtB;
  600. ( j < MAX_CUSTOM_WEIGHTS ) && *lpjWtA;
  601. ++j, ++lpjWtA, ++lpjWtB)
  602. {
  603. lpjWtA[-1] = *lpjWtA;
  604. lpjWtB[-1] = *lpjWtB;
  605. }
  606. lpjWtA[-1] = PANOSE_ANY;
  607. lpjWtB[-1] = PANOSE_ANY;
  608. if( i < ( j - 1 ) )
  609. {
  610. M_ELSEMEMCPY( &lpMapState->ajCustomWt[SIZE_PAN1_NUM * i],
  611. &lpMapState->ajCustomWt[SIZE_PAN1_NUM * (i + 1)],
  612. ( SIZE_PAN1_NUM * (j - i - 1 ) ) );
  613. }
  614. return( TRUE );
  615. }
  616. }
  617. //
  618. // Custom weights matching this family digit pair were not
  619. // found, return failure.
  620. //
  621. return( FALSE );
  622. }
  623. #endif /* ifndef NOELSEWEIGHTS */
  624. /***************************************************************************
  625. * FUNCTION: unPANMatchFonts
  626. *
  627. * PURPOSE: Match two PANOSE numbers.
  628. *
  629. * RETURNS: Return a match value if the fonts are successfully compared
  630. * and are within range of the threshold, otherwise return
  631. * PAN_MATCH_ERROR if there is an error or the fonts are out
  632. * of range.
  633. ***************************************************************************/
  634. EW_USHORT EW_FAR EW_PASCAL unPANMatchFonts( EW_LPMAPSTATE lpMapState,
  635. EW_LPBYTE lpPanWant,
  636. EW_ULONG ulSizeWant,
  637. EW_LPBYTE lpPanThis,
  638. EW_ULONG ulSizeThis,
  639. EW_BYTE jMapToFamily )
  640. {
  641. EW_USHORT unMatch = PAN_MATCH_ERROR;
  642. EW_USHORT unThreshold;
  643. EW_USHORT i;
  644. EW_USHORT j;
  645. EW_LPPDICT_MEM lpPDB;
  646. EW_LPPIND_MEM lpPanIndRec;
  647. EW_LPPTBL_MEM lpPTblRec;
  648. EW_LPBYTE lpjWts;
  649. EW_LPATOB_MEM lpAtoBHead;
  650. EW_LPATOB_ITEM_MEM lpAtoB;
  651. //
  652. // Sanity check on the PANOSE numbers. Both numbers must be
  653. // valid PANOSE 1.0 numbers, and the 'this'( compared-to )
  654. // number must match the map-to family.
  655. //
  656. if( !M_SANE( lpMapState ) ||
  657. ( ulSizeWant != SIZE_PAN1_NUM ) || ( ulSizeThis != SIZE_PAN1_NUM ) ||
  658. ( lpPanWant[PAN_IND_FAMILY] <= PANOSE_NOFIT ) ||
  659. ( lpPanWant[PAN_IND_FAMILY] > MAX_PAN1_FAMILY ) ||
  660. ( lpPanThis[PAN_IND_FAMILY] <= PANOSE_NOFIT ) ||
  661. ( lpPanThis[PAN_IND_FAMILY] > MAX_PAN1_FAMILY ) ||
  662. ( lpPanThis[PAN_IND_FAMILY] != jMapToFamily ) )
  663. {
  664. goto backout0;
  665. }
  666. //
  667. // Lock the penalty database.
  668. //
  669. if( !(lpPDB = M_lLockPAN1DATA( lpMapState->ulhPan1Data ) ) )
  670. {
  671. goto backout0;
  672. }
  673. //
  674. // Locate the index entry that points to the dictionary containing
  675. // the penalty tables for this PANOSE number.
  676. // This routine may flip what lpPanWant and lpPanThis point to so
  677. // we can guarantee the 'FamilyA' from the penalty tables is always
  678. // associated with lpPanWant and 'FamilyB' is associated with
  679. // lpPanThis.
  680. //
  681. // Optimization for unsupported families: If we do not support this
  682. // family, but the numbers are identical, then return an 'exact match'
  683. // value of zero. Otherwise return the usual match error value.
  684. //
  685. if( !(lpPanIndRec = s_lpPANGetIndRec(lpPDB, &lpPanWant, &lpPanThis ) ) )
  686. {
  687. for( i = 0; ( i < NUM_PAN_DIGITS ) && ( *lpPanWant == *lpPanThis ) &&
  688. ( *lpPanWant != PANOSE_NOFIT );
  689. ++i, ++lpPanWant, ++lpPanThis)
  690. ;
  691. if( i >= NUM_PAN_DIGITS )
  692. {
  693. unMatch = 0;
  694. }
  695. goto backout1;
  696. }
  697. //
  698. // Get the array of mapper weights -- this could be a custom array
  699. // supplied by the user, or the default array from the penalty
  700. // database.
  701. //
  702. if( !( lpjWts = s_lpPANGetWeights( lpMapState, lpPDB, lpPanIndRec ) ) )
  703. {
  704. goto backout1;
  705. }
  706. //
  707. // If we are NOT supposed to do threshold testing then just set
  708. // it to the maximum integer.
  709. //
  710. if( lpMapState->unRelaxThresholdCount > 0 )
  711. {
  712. unThreshold = ELSEMAXSHORT;
  713. }
  714. else
  715. {
  716. unThreshold = lpMapState->unThreshold;
  717. }
  718. //
  719. // Index the penalty table array.
  720. //
  721. lpPTblRec = (EW_LPPTBL_MEM) M_lpjOFFS( lpPDB, lpPanIndRec->unOffsPTbl );
  722. //
  723. // There are two flavors of walking the digits:
  724. //
  725. // 1. For cross-family matching, we walk an array of indices mapping
  726. // digits from one family to the digits of another.
  727. // 2. For normal( same family ) matching, we directly walk the digits.
  728. //
  729. // Test for an a-to-b array( cross-family matching ).
  730. //
  731. if( lpPanIndRec->unOffsAtoB )
  732. {
  733. //
  734. // This is a cross-family mapping, get the a-to-b array head.
  735. //
  736. lpAtoBHead = (EW_LPATOB_MEM) M_lpjOFFS( lpPDB, lpPanIndRec->unOffsAtoB );
  737. //
  738. // Walk the a-to-b array.
  739. //
  740. for( i = unMatch = 0, j = lpAtoBHead->unNumAtoB,
  741. lpAtoB = lpAtoBHead->AtoBItem;
  742. i < j;
  743. ++i, ++lpPTblRec, ++lpjWts, ++lpAtoB)
  744. {
  745. //
  746. // Compare the two digits. Abort if the test fails or the
  747. // accumulated match value is greater than the threshold.
  748. //
  749. if( !s_bPANMatchDigits( lpPDB, &unMatch, lpPanIndRec,
  750. lpPTblRec, *lpjWts, lpPanWant[lpAtoB->jAttrA],
  751. lpPanThis[lpAtoB->jAttrB]) ||
  752. ( unMatch > unThreshold ) )
  753. {
  754. unMatch = PAN_MATCH_ERROR;
  755. goto backout1;
  756. }
  757. }
  758. }
  759. else
  760. {
  761. //
  762. // Normal match: comparing PANOSE numbers from the same
  763. // families. Walk the digits accumulating the match result.
  764. //
  765. for( i = unMatch = 0, ++lpPanWant, ++lpPanThis;
  766. i <( NUM_PAN_DIGITS - 1 );
  767. ++i, ++lpPTblRec, ++lpjWts, ++lpPanWant, ++lpPanThis )
  768. {
  769. //
  770. // Compare the two digits. Abort if the test fails or the
  771. // accumulated match value is greater than the threshold.
  772. //
  773. if( !s_bPANMatchDigits( lpPDB, &unMatch, lpPanIndRec,
  774. lpPTblRec, *lpjWts, *lpPanWant, *lpPanThis) ||
  775. ( unMatch > unThreshold ) )
  776. {
  777. unMatch = PAN_MATCH_ERROR;
  778. goto backout1;
  779. }
  780. }
  781. }
  782. //
  783. // Return the match value. If it was out of range or an error
  784. // occurred, then it will equal PAN_MATCH_ERROR.
  785. //
  786. backout1:
  787. M_bUnlockPAN1DATA( lpMapState->ulhPan1Data );
  788. backout0:
  789. return( unMatch );
  790. }
  791. #ifndef NOELSEPICKFONTS
  792. /***************************************************************************
  793. * FUNCTION: unPANPickFonts
  794. *
  795. * PURPOSE: Walk an array of fonts ordering them by the closest to the
  796. * requested font. If no font is within range of the threshold
  797. * then look for the closest to the default font. If still
  798. * no font is found then just pick the first font in the list.
  799. *
  800. * Implementation note: This proc assumes PANOSE 1.0 numbers.
  801. * A future version of this proc will accept intermixed PANOSE
  802. * 1.0 and 2.0 numbers, and will call a callback routine to
  803. * supply each record, instead of presuming it can walk an
  804. * array of fixed-length records.
  805. *
  806. * RETURNS: Return the number of fonts found to match the requested
  807. * font, or zero if unNumInds == 0 or an error ocurred.
  808. *
  809. * If no close match was found but the default font is enabled,
  810. * then one is returned and *lpMatchValues == PAN_MATCH_ERROR.
  811. *
  812. * If no suitable match was found and the default font is
  813. * disabled, then zero is returned.
  814. ***************************************************************************/
  815. EW_USHORT EW_FAR EW_PASCAL unPANPickFonts( EW_LPMAPSTATE lpMapState,
  816. EW_LPUSHORT lpIndsBest,
  817. EW_LPUSHORT lpMatchValues,
  818. EW_LPBYTE lpPanWant,
  819. EW_USHORT unNumInds,
  820. EW_LPBYTE lpPanFirst,
  821. EW_USHORT unNumAvail,
  822. EW_SHORT nRecSize,
  823. EW_BYTE jMapToFamily )
  824. {
  825. EW_USHORT i;
  826. EW_USHORT j;
  827. EW_USHORT k;
  828. EW_USHORT unNumFound = 0;
  829. EW_USHORT unMatchValue;
  830. EW_USHORT unSavedThreshold;
  831. EW_LPUSHORT lpMatches;
  832. EW_LPUSHORT lpInds;
  833. EW_LPBYTE lpPanThis;
  834. //
  835. // Sanity check.
  836. //
  837. if( !M_SANE( lpMapState ) || ( unNumInds == 0 ) || ( unNumAvail == 0 ) ||
  838. ( (nRecSize < 0 ) &&( nRecSize > -(EW_SHORT )SIZE_PAN1_NUM) ) ||
  839. ( (nRecSize > 0 ) &&( nRecSize < (EW_SHORT )SIZE_PAN1_NUM) ) )
  840. {
  841. return( 0 );
  842. }
  843. //
  844. // This routine implements a 'quit early' algorithm by modifying
  845. // the threshold to the worst acceptable value in the list (once
  846. // the list is full). This has the effect of causing matchfonts
  847. // to abort & return PAN_MATCH_ERROR whenever a penalty exceeds
  848. // the threshold.
  849. //
  850. unSavedThreshold = lpMapState->unThreshold;
  851. //
  852. // Walk the PANOSE numbers ordering them from best to worst
  853. // match. Walk the array with a byte pointer, advancing by
  854. // the passed-in record size.
  855. //
  856. for( i = 0, lpPanThis = lpPanFirst; i < unNumAvail;
  857. ++i, lpPanThis += nRecSize)
  858. {
  859. //
  860. // Get the match value.
  861. //
  862. if( ( unMatchValue = unPANMatchFonts( lpMapState,
  863. lpPanWant, SIZE_PAN1_NUM, lpPanThis, SIZE_PAN1_NUM,
  864. jMapToFamily ) ) != PAN_MATCH_ERROR )
  865. {
  866. //
  867. // Find the slot in the array where this match value
  868. // should reside.
  869. //
  870. for( j = 0, lpMatches = lpMatchValues;
  871. ( j < unNumFound ) &&( *lpMatches < unMatchValue );
  872. ++j, ++lpMatches)
  873. ;
  874. //
  875. // If this match value is better than one of the matches
  876. // already in the array, then insert it. Notice that
  877. // until the array is full everything goes in it. After
  878. // that, we shuffle less close matches off the end.
  879. //
  880. if( j < unNumInds )
  881. {
  882. if( unNumFound < unNumInds )
  883. {
  884. ++unNumFound;
  885. }
  886. for( lpInds = &lpIndsBest[k = unNumFound - 1],
  887. lpMatches = &lpMatchValues[k];
  888. k > j;
  889. lpInds[0] = lpInds[-1], lpMatches[0] = lpMatches[-1],
  890. --k, --lpInds, --lpMatches)
  891. ;
  892. *lpInds = i;
  893. *lpMatches = unMatchValue;
  894. //
  895. // If the list is full, then set the threshold equal
  896. // to the last match value in the list. The matchfonts
  897. // routine will abort & return PAN_MATCH_ERROR on any
  898. // match greater than this value.
  899. //
  900. // Also, if the last value in the list is zero (exact
  901. // match), then exit the loop because the list will
  902. // not change.
  903. //
  904. if( unNumFound == unNumInds )
  905. {
  906. if( (k = lpMatchValues[unNumFound - 1] ) == 0)
  907. {
  908. break;
  909. }
  910. lpMapState->unThreshold = k;
  911. }
  912. }
  913. }
  914. }
  915. //
  916. // If no acceptable match was found, then attempt to find a match
  917. // for the default font. We temporarily step off the threshold
  918. // so we will definitely find something. At this point, we do
  919. // not care if the default is not within the threshold, we just
  920. // want to find it.
  921. //
  922. if( !unNumFound && lpMapState->bUseDef )
  923. {
  924. lpMapState->unThreshold = ELSEMAXSHORT;
  925. for( i = 0, lpPanThis = lpPanFirst; i < unNumAvail;
  926. ++i, lpPanThis += nRecSize)
  927. {
  928. if( ( unMatchValue = unPANMatchFonts( lpMapState,
  929. lpMapState->ajPanDef, SIZE_PAN1_NUM, lpPanThis, SIZE_PAN1_NUM,
  930. lpMapState->ajPanDef[PAN_IND_FAMILY] ) ) != PAN_MATCH_ERROR )
  931. {
  932. if( unNumFound == 0 )
  933. {
  934. *lpIndsBest = i;
  935. lpMapState->unThreshold = *lpMatchValues = unMatchValue;
  936. ++unNumFound;
  937. }
  938. else if( unMatchValue < *lpMatchValues )
  939. {
  940. *lpIndsBest = i;
  941. lpMapState->unThreshold = *lpMatchValues = unMatchValue;
  942. }
  943. }
  944. }
  945. //
  946. // We flag this match with the error so the caller can
  947. // determine that the default font was substituted.
  948. //
  949. if( unNumFound > 0 )
  950. {
  951. *lpMatchValues = PAN_MATCH_ERROR;
  952. }
  953. }
  954. //
  955. // Restore the threshold.
  956. //
  957. lpMapState->unThreshold = unSavedThreshold;
  958. //
  959. // If still no match is found then just pick the first font.
  960. //
  961. if( !unNumFound )
  962. {
  963. *lpIndsBest = 0;
  964. *lpMatchValues = PAN_MATCH_ERROR;
  965. ++unNumFound;
  966. }
  967. //
  968. // Return the number of fonts found. It will be zero if we
  969. // encountered an error or couldn't find a suitable match.
  970. //
  971. return( unNumFound );
  972. }
  973. #endif /* ifndef NOELSEPICKFONTS */
  974. /***************************************************************************
  975. * FUNCTION: vPANMakeDummy
  976. *
  977. * PURPOSE: Build a dummy PANOSE number with all attributes set to
  978. * PANOSE_NOFIT.
  979. *
  980. * RETURNS: Nothing.
  981. ***************************************************************************/
  982. EW_VOID EW_FAR EW_PASCAL vPANMakeDummy( EW_LPBYTE lpPanThis,
  983. EW_USHORT unSize )
  984. {
  985. EW_USHORT i;
  986. EW_USHORT j;
  987. unSize /= sizeof( EW_BYTE );
  988. for( i = j = 0; (i < NUM_PAN_DIGITS ) &&( j < unSize );
  989. ++i, j += sizeof( EW_BYTE ), *lpPanThis++ = PANOSE_NOFIT)
  990. ;
  991. }
  992. /***************************************************************************/
  993. /************************** LOCAL SERVICE ROUTINES *************************/
  994. /***************************************************************************/
  995. /***************************************************************************
  996. * FUNCTION: s_lpPANGetIndRec
  997. *
  998. * PURPOSE: Search the header of the database looking for a dictionary
  999. * of penalty tables designed for this family pair.
  1000. *
  1001. * There is a similar search for the index rec in the routine
  1002. * bPANGetMapWeights. If you make a change here, also check in
  1003. * that routine.
  1004. *
  1005. * RETURNS: Return the pointer to the index record if a match is found,
  1006. * or NULL if one is not.
  1007. ***************************************************************************/
  1008. LOCAL EW_LPPIND_MEM EW_NEAR EW_PASCAL s_lpPANGetIndRec(
  1009. EW_LPPDICT_MEM lpPDB,
  1010. EW_LPBYTE EW_FAR *lplpPanWant,
  1011. EW_LPBYTE EW_FAR *lplpPanThis )
  1012. {
  1013. EW_USHORT i;
  1014. EW_BYTE jFamilyA =( *lplpPanWant )[PAN_IND_FAMILY];
  1015. EW_BYTE jFamilyB =( *lplpPanThis )[PAN_IND_FAMILY];
  1016. EW_LPBYTE lpPanSwitch;
  1017. EW_LPPIND_MEM lpPanIndRec;
  1018. //
  1019. // Walk the index array in the penalty database looking for
  1020. // a matching family pair.
  1021. //
  1022. for( i = 0, lpPanIndRec = lpPDB->pind; i < lpPDB->unNumDicts;
  1023. ++i, ++lpPanIndRec)
  1024. {
  1025. if( ( lpPanIndRec->jFamilyA == jFamilyA ) &&
  1026. ( lpPanIndRec->jFamilyB == jFamilyB ) )
  1027. {
  1028. //
  1029. // Straight match. Return the index.
  1030. //
  1031. return( lpPanIndRec );
  1032. }
  1033. else if( ( lpPanIndRec->jFamilyA == jFamilyB ) &&
  1034. ( lpPanIndRec->jFamilyB == jFamilyA ) )
  1035. {
  1036. //
  1037. // There is a match but the families are swapped. Swap
  1038. // the PANOSE numbers to match the order in the penalty
  1039. // database in the event it contains tables that are
  1040. // order-dependent (this can happen with cross-family
  1041. // mapping, C0-style/uncompressed/non-symmetric tables).
  1042. //
  1043. lpPanSwitch = *lplpPanWant;
  1044. *lplpPanWant = *lplpPanThis;
  1045. *lplpPanThis = lpPanSwitch;
  1046. return( lpPanIndRec );
  1047. }
  1048. }
  1049. //
  1050. // No match found, return an error.
  1051. //
  1052. return( NULL );
  1053. }
  1054. /***************************************************************************
  1055. * FUNCTION: s_bPANGetPenaltyC0
  1056. *
  1057. * PURPOSE: Compute the penalty between two PANOSE digits using 'C0'
  1058. * compression, where the entire table is provided (except
  1059. * the any and no-fit rows and columns).
  1060. *
  1061. * RETURNS: Return TRUE if the computed index is within range, and
  1062. * *lpunMatch is filled in with the penalty value, FALSE if
  1063. * it is out of range.
  1064. ***************************************************************************/
  1065. LOCAL EW_BOOL EW_NEAR EW_PASCAL s_bPANGetPenaltyC0( EW_LPPIND_MEM lpPanIndRec,
  1066. EW_LPPTBL_C0_MEM lpPC0,
  1067. EW_LPUSHORT lpunMatch,
  1068. EW_USHORT unTblSize,
  1069. EW_USHORT unAttrA,
  1070. EW_USHORT unAttrB )
  1071. {
  1072. EW_USHORT unInd;
  1073. //
  1074. // Make sure each value is within range. Notice this may
  1075. // be a non-square table.
  1076. //
  1077. if( ( unAttrA > lpPC0->jARangeLast ) ||( unAttrB > lpPC0->jBRangeLast ) )
  1078. {
  1079. *lpunMatch = lpPanIndRec->jDefNoFitPenalty;
  1080. return( FALSE );
  1081. }
  1082. //
  1083. // Compute the table index.
  1084. //
  1085. if( ( unInd = ( (unAttrA - 2 ) *(lpPC0->jBRangeLast - 1 ) )
  1086. + unAttrB - 2) >= unTblSize )
  1087. {
  1088. *lpunMatch = lpPanIndRec->jDefNoFitPenalty;
  1089. return( FALSE );
  1090. }
  1091. //
  1092. // Get the penalty.
  1093. //
  1094. *lpunMatch = lpPC0->jPenalties[unInd];
  1095. return( TRUE );
  1096. }
  1097. /***************************************************************************
  1098. * FUNCTION: s_unPANGetPenaltyC1
  1099. *
  1100. * PURPOSE: Compute the penalty between two PANOSE digits using 'C1'
  1101. * compression, which is a perfectly symmetrical table around
  1102. * the diagonal. Two digits on the diagonal are an exact match.
  1103. * A difference of 1 yields a penalty of 1, a difference of 2
  1104. * yields a penalty of 2, and so on.
  1105. *
  1106. * It is assumed the caller handled any, no-fit, and exact
  1107. * matches.
  1108. *
  1109. * RETURNS: Return the penalty from the table, the function cannot fail.
  1110. ***************************************************************************/
  1111. LOCAL EW_USHORT EW_NEAR EW_PASCAL s_unPANGetPenaltyC1( EW_USHORT unAttrA,
  1112. EW_USHORT unAttrB )
  1113. {
  1114. EW_SHORT nDiff;
  1115. //
  1116. // Compute the penalty, which is simply the absolute value
  1117. // of the difference between the two numbers.
  1118. //
  1119. if( ( nDiff = (EW_SHORT) unAttrA - (EW_SHORT) unAttrB ) < 0 )
  1120. {
  1121. nDiff = -nDiff;
  1122. }
  1123. return( nDiff );
  1124. }
  1125. /***************************************************************************
  1126. * FUNCTION: s_bPANGetPenaltyC2
  1127. *
  1128. * PURPOSE: Compute the penalty between two PANOSE digits using 'C2'
  1129. * compression, which is a table symmetrical about the
  1130. * diagonal, but not a smooth range from low to high, so the
  1131. * lower left corner of the table is provided. The unAttrA
  1132. * digit references the row and unAttrB references the column.
  1133. *
  1134. * It is assumed the caller handled any, no-fit, and exact
  1135. * matches.
  1136. *
  1137. * RETURNS: Return TRUE if the computed index is within range, and
  1138. * *lpunMatch is filled in with the penalty value, FALSE if
  1139. * it is out of range.
  1140. ***************************************************************************/
  1141. LOCAL EW_BOOL EW_NEAR EW_PASCAL s_bPANGetPenaltyC2( EW_LPPIND_MEM lpPanIndRec,
  1142. EW_LPBYTE lpPTbl,
  1143. EW_LPUSHORT lpunMatch,
  1144. EW_USHORT unTblSize,
  1145. EW_USHORT unAttrA,
  1146. EW_USHORT unAttrB )
  1147. {
  1148. EW_USHORT unSwap;
  1149. EW_SHORT nInd;
  1150. //
  1151. // The formula we use assumes the lower left half of the
  1152. // penalty table, which means row > column. The table is
  1153. // symmetric about the diagonal, so if row < column we can
  1154. // just switch their values.
  1155. //
  1156. if( unAttrA < unAttrB )
  1157. {
  1158. unSwap = unAttrA;
  1159. unAttrA = unAttrB;
  1160. unAttrB = unSwap;
  1161. }
  1162. //
  1163. // The table is missing the any, no-fit, and exact match
  1164. // penalties as those are handled separately. Since the
  1165. // table is triangular shaped, we use the additive series
  1166. // to compute the row:
  1167. //
  1168. // n + ... + 3 + 2 + 1 == 1/2 * n *( n + 1 )
  1169. //
  1170. // Substituting n for row - 3, the first possible row, and
  1171. // adding the column offset, we get the following formula:
  1172. //
  1173. // ( 1/2 * (row - 3 ) *( row - 2 ) ) +( col - 2 )
  1174. //
  1175. // We know that row >= 3 and col >= 2 as we catch the other
  1176. // cases above.
  1177. //
  1178. if( ( nInd = M_ELSEMULDIV( unAttrA - 3, unAttrA - 2, 2 ) +
  1179. (EW_SHORT) unAttrB - 2) >= (EW_SHORT) unTblSize )
  1180. {
  1181. *lpunMatch = lpPanIndRec->jDefNoFitPenalty;
  1182. return( FALSE );
  1183. }
  1184. *lpunMatch = lpPTbl[nInd];
  1185. return( TRUE );
  1186. }
  1187. /***************************************************************************
  1188. * FUNCTION: s_unPANGetPenaltyC4
  1189. *
  1190. * PURPOSE: Compute the penalty between two PANOSE digits using 'C4'
  1191. * compression, which is almost identical to 'C1' compression
  1192. * except a start and increment value are supplied.
  1193. *
  1194. * It is assumed the caller handled any, no-fit, and exact
  1195. * matches.
  1196. *
  1197. * RETURNS: Return the penalty from the table, the function cannot fail.
  1198. ***************************************************************************/
  1199. LOCAL EW_USHORT EW_NEAR EW_PASCAL s_unPANGetPenaltyC4( EW_LPPTBL_C4_MEM lpPC4,
  1200. EW_USHORT unAttrA,
  1201. EW_USHORT unAttrB )
  1202. {
  1203. EW_SHORT nDiff;
  1204. //
  1205. // First compute the absolute value of the difference
  1206. // between the two numbers.
  1207. //
  1208. if( (nDiff = (EW_SHORT )unAttrA -( EW_SHORT )unAttrB) < 0)
  1209. {
  1210. nDiff = -nDiff;
  1211. }
  1212. //
  1213. // Then scale by the increment and start values.
  1214. //
  1215. if( nDiff > 0 )
  1216. {
  1217. nDiff = ( ( nDiff - 1 ) *(EW_SHORT) lpPC4->jIncrement ) +
  1218. (EW_SHORT) lpPC4->jStart;
  1219. }
  1220. return( nDiff );
  1221. }
  1222. /***************************************************************************
  1223. * FUNCTION: s_lpPANGetWeights
  1224. *
  1225. * PURPOSE: Check the mapstate record for a set of user-supplied custom
  1226. * weights. If none are present, then use the default weights
  1227. * from the mapping table.
  1228. *
  1229. * RETURNS: Return the pointer to the array of weight values.
  1230. ***************************************************************************/
  1231. LOCAL EW_LPBYTE EW_NEAR EW_PASCAL s_lpPANGetWeights( EW_LPMAPSTATE lpMapState,
  1232. EW_LPPDICT_MEM lpPDB,
  1233. EW_LPPIND_MEM lpPanIndRec )
  1234. {
  1235. EW_USHORT i;
  1236. EW_LPBYTE lpjWtA;
  1237. EW_LPBYTE lpjWtB;
  1238. EW_BYTE jFamilyA = lpPanIndRec->jFamilyA;
  1239. EW_BYTE jFamilyB = lpPanIndRec->jFamilyB;
  1240. #ifndef NOELSEWEIGHTS
  1241. //
  1242. // Search for custom weights.
  1243. //
  1244. for( i = 0, lpjWtA = lpMapState->ajWtRefA, lpjWtB = lpMapState->ajWtRefB;
  1245. ( i < MAX_CUSTOM_WEIGHTS ) && *lpjWtA;
  1246. ++i, ++lpjWtA, ++lpjWtB )
  1247. {
  1248. //
  1249. // If custom weights are found then return a pointer into
  1250. // the mapstate struct. We store a weight value for the family
  1251. // digit but do not use it. The pointer points to the first
  1252. // digit after the family digit.
  1253. //
  1254. if( ( (*lpjWtA == jFamilyA ) &&( *lpjWtB == jFamilyB ) ) ||
  1255. ( (*lpjWtA == jFamilyB ) &&( *lpjWtB == jFamilyA ) ) )
  1256. {
  1257. return( &lpMapState->ajCustomWt[ ( SIZE_PAN1_NUM * i ) + 1] );
  1258. }
  1259. }
  1260. #endif
  1261. //
  1262. // If no custom weights were found then return the default
  1263. // weight from the penalty database.
  1264. //
  1265. if( lpPanIndRec->unOffsWts )
  1266. {
  1267. return( M_lpjOFFS(lpPDB, lpPanIndRec->unOffsWts + 1 ) );
  1268. }
  1269. else
  1270. {
  1271. return( NULL );
  1272. }
  1273. }
  1274. /***************************************************************************
  1275. * FUNCTION: s_bPANMatchDigits
  1276. *
  1277. * PURPOSE: Compute the match value between two PANOSE digits and add
  1278. * it to the passed in match total.
  1279. *
  1280. * RETURNS: Return TRUE if the match value is computed and added to
  1281. * *lpunMatchTotal. If an error occurs, return FALSE and
  1282. * set *lpunMatchTotal to the value PAN_MATCH_ERROR.
  1283. ***************************************************************************/
  1284. LOCAL EW_BOOL EW_NEAR EW_PASCAL s_bPANMatchDigits( EW_LPPDICT_MEM lpPDB,
  1285. EW_LPUSHORT lpunMatchTotal,
  1286. EW_LPPIND_MEM lpPanIndRec,
  1287. EW_LPPTBL_MEM lpPTblRec,
  1288. EW_USHORT unWt,
  1289. EW_USHORT unAttrA,
  1290. EW_USHORT unAttrB )
  1291. {
  1292. EW_USHORT unLast = lpPTblRec->jRangeLast;
  1293. EW_USHORT unMatch;
  1294. //
  1295. // First make sure the digit values are not out of range.
  1296. //
  1297. if( (unAttrA > unLast ) ||( unAttrB > unLast ) )
  1298. {
  1299. goto errout;
  1300. }
  1301. //
  1302. // Special case no-fit, any, or exact matches.
  1303. //
  1304. if( ( unAttrA == PANOSE_NOFIT ) || ( unAttrB == PANOSE_NOFIT ) )
  1305. {
  1306. if( lpPTblRec->jCompress != PAN_COMPRESS_C3 )
  1307. {
  1308. *lpunMatchTotal += lpPanIndRec->jDefNoFitPenalty * unWt;
  1309. return( TRUE );
  1310. }
  1311. }
  1312. else if( ( unAttrA == PANOSE_ANY ) || ( unAttrB == PANOSE_ANY ) )
  1313. {
  1314. *lpunMatchTotal += lpPanIndRec->jDefAnyPenalty * unWt;
  1315. return( TRUE );
  1316. }
  1317. else if( (unAttrA == unAttrB ) &&
  1318. ( lpPTblRec->jCompress != PAN_COMPRESS_C0 ) )
  1319. {
  1320. *lpunMatchTotal += lpPanIndRec->jDefMatchPenalty * unWt;
  1321. return( TRUE );
  1322. }
  1323. //
  1324. // Compute the penalty depending on the kind of compression
  1325. // used for the table.
  1326. //
  1327. switch( lpPTblRec->jCompress )
  1328. {
  1329. case PAN_COMPRESS_C0:
  1330. if( !lpPTblRec->unOffsTbl || !lpPTblRec->unTblSize
  1331. || !s_bPANGetPenaltyC0( lpPanIndRec,
  1332. (EW_LPPTBL_C0_MEM) M_lpjOFFS( lpPDB, lpPTblRec->unOffsTbl ),
  1333. &unMatch, lpPTblRec->unTblSize, unAttrA, unAttrB ) )
  1334. {
  1335. goto errout;
  1336. }
  1337. *lpunMatchTotal += unMatch * unWt;
  1338. break;
  1339. case PAN_COMPRESS_C1:
  1340. *lpunMatchTotal += s_unPANGetPenaltyC1( unAttrA, unAttrB ) * unWt;
  1341. break;
  1342. case PAN_COMPRESS_C2:
  1343. if( !lpPTblRec->unOffsTbl || !lpPTblRec->unTblSize ||
  1344. !s_bPANGetPenaltyC2( lpPanIndRec,
  1345. M_lpjOFFS( lpPDB, lpPTblRec->unOffsTbl ), &unMatch,
  1346. lpPTblRec->unTblSize, unAttrA, unAttrB ) )
  1347. {
  1348. goto errout;
  1349. }
  1350. *lpunMatchTotal += unMatch * unWt;
  1351. break;
  1352. case PAN_COMPRESS_C3:
  1353. if( !lpPTblRec->unOffsTbl || !lpPTblRec->unTblSize )
  1354. {
  1355. goto errout;
  1356. }
  1357. if( ( unAttrA == PANOSE_NOFIT ) || ( unAttrB == PANOSE_NOFIT ) )
  1358. {
  1359. unMatch = *M_lpjOFFS( lpPDB, lpPTblRec->unOffsTbl );
  1360. }
  1361. else if( !s_bPANGetPenaltyC2( lpPanIndRec,
  1362. M_lpjOFFS( lpPDB, lpPTblRec->unOffsTbl + 1 ), &unMatch,
  1363. (EW_USHORT) ( lpPTblRec->unTblSize - 1 ),
  1364. unAttrA, unAttrB ) )
  1365. {
  1366. goto errout;
  1367. }
  1368. *lpunMatchTotal += unMatch * unWt;
  1369. break;
  1370. case PAN_COMPRESS_C4:
  1371. if( !lpPTblRec->unOffsTbl || !lpPTblRec->unTblSize )
  1372. {
  1373. goto errout;
  1374. }
  1375. *lpunMatchTotal += s_unPANGetPenaltyC4(
  1376. (EW_LPPTBL_C4_MEM) M_lpjOFFS( lpPDB, lpPTblRec->unOffsTbl ),
  1377. unAttrA, unAttrB) * unWt;
  1378. break;
  1379. }
  1380. //
  1381. // Match computed, successful return.
  1382. //
  1383. return( TRUE );
  1384. //
  1385. // An error occurred, return FALSE.
  1386. //
  1387. errout:
  1388. *lpunMatchTotal = PAN_MATCH_ERROR;
  1389. return( FALSE );
  1390. }
  1391. /***************************************************************************
  1392. * FUNCTION: s_lpPANMemCpy
  1393. *
  1394. * PURPOSE: Perform a memcpy operation.
  1395. *
  1396. * RETURNS: The function returns lpDst.
  1397. ***************************************************************************/
  1398. #ifdef ELSELOCALMEMCPY
  1399. LOCAL EW_LPBYTE EW_NEAR EW_PASCAL s_lpPANMemCpy( EW_LPBYTE lpDst,
  1400. EW_LPBYTE lpSrc,
  1401. EW_USHORT unLen)
  1402. {
  1403. EW_LPBYTE lpRet = lpDst;
  1404. EW_USHORT i;
  1405. for( i = 0; i < unLen; ++i, *lpDst++ = *lpSrc++ )
  1406. ;
  1407. return( lpRet );
  1408. }
  1409. #endif
  1410. /***************************************************************************
  1411. * Revision log:
  1412. *
  1413. * 31-Jan-93 msd PANOSE 1.0 mapper: 10-digit PANOSE.
  1414. * 2-Feb-93 msd Removed huge pointer stuff.
  1415. * 3-Feb-93 msd Removed ctrl-z at EOF. Added 'unused' pragmas.
  1416. * 3-Feb-93 msd Fixed bug caused by vcs check-in.
  1417. * 14-Feb-93 msd Removed extra restore-threshold call in pickfonts.
  1418. * 15-Feb-93 msd For extra security, bumped the sanity value from
  1419. * word to a long.
  1420. ***************************************************************************/
  1421. /*
  1422. * $lgb$
  1423. * 1.0 17-Feb-93 msd New module created because of vcs problems.
  1424. * 1.1 17-Feb-93 msd Small doc change.
  1425. * 1.2 18-Feb-93 msd Added penalty table byte-ordering check, and C4 ptbl compression( new version of ptbl ). Modified internal routines so 'unused' pragmas are not necessary. Use EW_FAR.
  1426. * 1.3 23-Feb-93 msd On close session, kill the sanity value so subsequent mapper calls will fail.
  1427. * 1.4 25-Feb-93 msd Modified the default font search logic in pickfonts -- search by the default font's family, not by the requested family. Also use M_ELSEMEMCPY() in a few more places.
  1428. * 1.5 19-Jul-93 msd Added compilation flags to selectively disable mapper routines.
  1429. * $lge$
  1430. */