Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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