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.

1071 lines
34 KiB

  1. #include "lsmem.h"
  2. #include "lstxtglf.h"
  3. #include "lstxtmap.h"
  4. #include "txtils.h"
  5. #include "txtln.h"
  6. #include "txtobj.h"
  7. #include "zqfromza.h"
  8. typedef struct
  9. {
  10. long cWhite;
  11. long duMaxWhite;
  12. long duTotalWhite;
  13. long cContinuous;
  14. long duMaxContinuous;
  15. long duMinContinuous;
  16. long cDiscrete;
  17. long duMaxDiscrete;
  18. } EXPG;
  19. typedef struct
  20. {
  21. long cExpginfo;
  22. EXPG* pexpg;
  23. long cResidual;
  24. } EXPGINFO;
  25. #define priorSpace 1
  26. #define priorMax 8
  27. #define cDiscreteMax 25
  28. #define min(a,b) ((a) > (b) ? (b) : (a))
  29. #define max(a,b) ((a) < (b) ? (b) : (a))
  30. static LSERR CollectGlyphExpInfo(const LSGRCHNK* plsgrchnk, LSTFLOW lstflow, LSDEVICE lsdev,
  31. long itxtobjFirst, long iwchFirst, long itxtobjLast, long iwchLast,
  32. long* rgdu, long* rgduGind, EXPGINFO* pexpginfo);
  33. static LSERR ApplyPriorGlyphExp(const LSGRCHNK* plsgrchnk, LSTFLOW lstflow, LSDEVICE lsdev,
  34. long itxtobjFirst, long iwchFirst, long itxtobjLast, long iwchLast,
  35. long prior, long duToDistribute, EXPG* pexpg, long* rgdu, long* rgduGind,
  36. long* rgduRight, long* rgduGright, long* pduDistributed);
  37. LSERR static ApplyDiscrete(const LSGRCHNK* plsgrchnk, LSTFLOW lstflow, LSDEVICE lsdev,
  38. long itxtobjFirst, long iwchFirst, long itxtobjLast, long iwchLast,
  39. long prior, long duToDistribute, long cDiscrete,
  40. long* rgduGind, long* rgduGright, long* pduDistributed);
  41. static void ApplyOneEachContinuous(const LSGRCHNK* plsgrchnk, long itxtobjFirst, long iwchFirst,
  42. long itxtobjLast, long iwchLast, long prior, long duToDistribute, long cContinuous,
  43. long* rgduGind, long* rgduGright, long* pduDistributed);
  44. static void ApplyFullWhiteContinuous(const LSGRCHNK* plsgrchnk, long itxtobjFirst, long iwchFirst, long itxtobjLast, long iwchLast,
  45. long prior,
  46. long* rgdu, long* rgduGind, long* rgduRight, long* rgduGright, long* pduDistributed);
  47. static void ApplyPropWhiteContinuous(const LSGRCHNK* plsgrchnk, BOOL fWhiteOnly,
  48. long itxtobjFirst, long iwchFirst, long itxtobjLast, long iwchLast, long prior,
  49. long duToDistribute, long duTotalMin,
  50. long* rgdu, long* rgduGind, long* rgduRight, long* rgduGright, long* pduDistributed);
  51. static void ApplyResidualGlyphExp(const LSGRCHNK* plsgrchnk, long itxtobjFirst,
  52. long iwchFirst, long itxtobjLast, long iwchLim, long duToDistribute,
  53. long cResidual, long* rgduGind, long* rgduGright, long* pduDistributed);
  54. static void FixExpt(const LSGRCHNK* plsgrchnk, long itxtobjFirst, long iwchVeryFirst,
  55. long itxtobjLast, long iwchLast, long* rgduGright);
  56. static void CalcExpandChanges(long cWhole, long duDenom, long duRest, long duLocal, long duMax,
  57. long* pduChange, long* pduAddCurrent);
  58. static void ApplyGlyphExpandChanges(long ind, long* rgduGind, long* rgduGright, long* pduDistributed, long duChange);
  59. /* A P P L Y G L Y P H E X P A N D */
  60. /*----------------------------------------------------------------------------
  61. %%Function: ApplyGlyphExpand
  62. %%Contact: sergeyge
  63. Applies glyph expansion
  64. First collects information about expansion opportunities
  65. Then applies expansion according to priorities
  66. If it is not sufficient, applies risidual expansion
  67. ----------------------------------------------------------------------------*/
  68. LSERR ApplyGlyphExpand(const LSGRCHNK* plsgrchnk, LSTFLOW lstflow, LSDEVICE lsdev,
  69. long itxtobjFirst, long iwchFirst, long itxtobjLast, long iwchLast,
  70. long duToDistribute, long* rgdu, long* rgduGind, long* rgduRight, long* rgduGright,
  71. BOOL* pfFullyJustified)
  72. {
  73. LSERR lserr;
  74. PILSOBJ pilsobj;
  75. EXPGINFO expginfo;
  76. EXPG rgexpg[priorMax];
  77. long duDistributed;
  78. long i;
  79. pilsobj = ((PTXTOBJ)plsgrchnk->plschnk[0].pdobj)->plnobj->pilsobj;
  80. expginfo.pexpg = rgexpg;
  81. expginfo.cExpginfo = priorMax;
  82. lserr = CollectGlyphExpInfo(plsgrchnk, lstflow, lsdev,
  83. itxtobjFirst, iwchFirst, itxtobjLast, iwchLast, rgdu, rgduGind, &expginfo);
  84. if (lserr != lserrNone) return lserr;
  85. for (i = 0; i < priorMax && duToDistribute > 0; i++)
  86. {
  87. lserr = ApplyPriorGlyphExp(plsgrchnk, lstflow, lsdev, itxtobjFirst, iwchFirst, itxtobjLast, iwchLast,
  88. i + 1, duToDistribute, &expginfo.pexpg[i], rgdu, rgduGind, rgduRight, rgduGright,
  89. &duDistributed);
  90. if (lserr != lserrNone) return lserr;
  91. Assert(duDistributed <= duToDistribute);
  92. duToDistribute -= duDistributed;
  93. }
  94. FixExpt(plsgrchnk, itxtobjFirst, iwchFirst, itxtobjLast, iwchLast, rgduGright);
  95. if (duToDistribute > 0 && expginfo.cResidual > 0)
  96. {
  97. ApplyResidualGlyphExp(plsgrchnk, itxtobjFirst, iwchFirst, itxtobjLast, iwchLast, duToDistribute,
  98. expginfo.cResidual, rgduGind, rgduGright, &duDistributed);
  99. Assert(duDistributed == duToDistribute);
  100. duToDistribute = 0;
  101. }
  102. *pfFullyJustified = (duToDistribute == 0);
  103. return lserrNone;
  104. }
  105. /* C O L L E C T G L Y P H E X P I N F O */
  106. /*----------------------------------------------------------------------------
  107. %%Function: CollectGlyphExpInfo
  108. %%Contact: sergeyge
  109. Collects expansion information and agreagated values for
  110. the expansion algorithm.
  111. Spaces from character-based runs contribute as expansion opportunities
  112. of exptAddWhiteSpace type with prior==priorSpace and duMax==lsexpinfInfinity
  113. ----------------------------------------------------------------------------*/
  114. static LSERR CollectGlyphExpInfo(const LSGRCHNK* plsgrchnk, LSTFLOW lstflow, LSDEVICE lsdev,
  115. long itxtobjFirst, long iwchVeryFirst, long itxtobjLast, long iwchLast,
  116. long* rgdu, long* rgduGind, EXPGINFO* pexpginfo)
  117. {
  118. LSERR lserr;
  119. PILSOBJ pilsobj;
  120. PLNOBJ plnobj;
  121. PTXTOBJ ptxtobj;
  122. PTXTOBJ ptxtobjLast;
  123. PLSRUN plsrun;
  124. LSEXPINFO* plsexpinf;
  125. EXPTYPE* pexpt;
  126. long itxtobj;
  127. long iwchFirst;
  128. long iwchLim;
  129. long igindFirst;
  130. long igindLim;
  131. long igind;
  132. long iwSpace;
  133. memset(pexpginfo->pexpg, 0, sizeof(EXPG) * pexpginfo->cExpginfo);
  134. pexpginfo->cResidual = 0;
  135. ptxtobjLast = (PTXTOBJ)plsgrchnk->plschnk[max(0, itxtobjLast)].pdobj;
  136. plnobj = ptxtobjLast->plnobj;
  137. pilsobj = plnobj->pilsobj;
  138. itxtobj = itxtobjFirst;
  139. plsexpinf = pilsobj->plsexpinf;
  140. pexpt = plnobj->pexpt;
  141. while (itxtobj <= itxtobjLast)
  142. {
  143. ptxtobj = (PTXTOBJ)plsgrchnk->plschnk[itxtobj].pdobj;
  144. if (ptxtobj->txtf & txtfGlyphBased)
  145. {
  146. iwchFirst = iwchVeryFirst;
  147. if (itxtobj > itxtobjFirst)
  148. iwchFirst = ptxtobj->iwchFirst;
  149. Assert(iwchFirst < ptxtobj->iwchLim);
  150. igindFirst = IgindFirstFromIwch(ptxtobj, iwchFirst);
  151. plsrun = plsgrchnk->plschnk[itxtobj].plsrun;
  152. while ((!(ptxtobj->txtf & txtfLastShaping)) && itxtobj < itxtobjLast )
  153. {
  154. itxtobj++;
  155. ptxtobj = (PTXTOBJ)plsgrchnk->plschnk[itxtobj].pdobj;
  156. Assert (ptxtobj->txtf & txtfGlyphBased);
  157. Assert(ptxtobj->igindFirst == ((PTXTOBJ)plsgrchnk->plschnk[itxtobj-1].pdobj)->igindLim);
  158. Assert(ptxtobj->iwchFirst == ((PTXTOBJ)plsgrchnk->plschnk[itxtobj-1].pdobj)->iwchLim);
  159. }
  160. iwchLim = ptxtobj->iwchLim;
  161. igindLim = ptxtobj->igindLim;
  162. Assert(itxtobj <= itxtobjLast);
  163. if (itxtobj == itxtobjLast)
  164. {
  165. iwchLim = iwchLast + 1;
  166. Assert(IgindLastFromIwch(ptxtobjLast, iwchLast) + 1 <= igindLim);
  167. igindLim = IgindLastFromIwch(ptxtobjLast, iwchLast);
  168. while (!FIgindFirstInContext(pilsobj, igindLim) && rgduGind[igindLim] == 0)
  169. igindLim--;
  170. Assert(igindLim >= ptxtobj->igindFirst);
  171. igindLim++;
  172. }
  173. lserr = (*pilsobj->plscbk->pfnGetGlyphExpansionInfo)(pilsobj->pols, plsrun, lsdev,
  174. &pilsobj->pwchOrig[iwchFirst], &plnobj->pgmap[iwchFirst], iwchLim - iwchFirst,
  175. &plnobj->pgind[igindFirst], &plnobj->pgprop[igindFirst], igindLim - igindFirst,
  176. lstflow, itxtobj == itxtobjLast, &pexpt[igindFirst], &plsexpinf[igindFirst]);
  177. if (lserr != lserrNone) return lserr;
  178. for (igind = igindFirst; igind < igindLim; igind++)
  179. {
  180. Assert(plsexpinf[igind].prior < priorMax);
  181. if (plsexpinf[igind].prior > 0)
  182. {
  183. switch (pexpt[igind])
  184. {
  185. case exptAddWhiteSpace:
  186. Assert(plsexpinf[igind].duMax > 0);
  187. if (rgduGind[igind] > 0)
  188. {
  189. pexpginfo->pexpg[plsexpinf[igind].prior - 1].duMaxWhite += plsexpinf[igind].duMax;
  190. pexpginfo->pexpg[plsexpinf[igind].prior - 1].duTotalWhite += rgduGind[igind];
  191. pexpginfo->pexpg[plsexpinf[igind].prior - 1].cWhite++;
  192. }
  193. break;
  194. case exptAddInkContinuous:
  195. Assert(plsexpinf[igind].duMax > 0);
  196. Assert(plsexpinf[igind].u.AddInkContinuous.duMin > 0);
  197. pexpginfo->pexpg[plsexpinf[igind].prior - 1].duMaxContinuous += plsexpinf[igind].duMax;
  198. pexpginfo->pexpg[plsexpinf[igind].prior - 1].duMinContinuous +=
  199. plsexpinf[igind].u.AddInkContinuous.duMin;
  200. pexpginfo->pexpg[plsexpinf[igind].prior - 1].cContinuous++;
  201. break;
  202. case exptAddInkDiscrete:
  203. Assert(plsexpinf[igind].duMax > 0);
  204. pexpginfo->pexpg[plsexpinf[igind].prior - 1].duMaxDiscrete += plsexpinf[igind].duMax;
  205. pexpginfo->pexpg[plsexpinf[igind].prior - 1].cDiscrete++;
  206. break;
  207. }
  208. }
  209. if (plsexpinf[igind].fCanBeUsedForResidual)
  210. pexpginfo->cResidual++;
  211. }
  212. }
  213. else
  214. {
  215. if (ptxtobj->txtkind == txtkindRegular)
  216. {
  217. iwchFirst = iwchVeryFirst;
  218. if (itxtobj > itxtobjFirst)
  219. iwchFirst = ptxtobj->iwchFirst;
  220. iwchLim = iwchLast + 1;
  221. if (itxtobj < itxtobjLast)
  222. iwchLim = ptxtobj->iwchLim;
  223. for (iwSpace = ptxtobj->u.reg.iwSpacesFirst; iwSpace < ptxtobj->u.reg.iwSpacesLim &&
  224. pilsobj->pwSpaces[iwSpace] < iwchFirst; iwSpace++);
  225. for (; iwSpace < ptxtobj->u.reg.iwSpacesLim &&
  226. pilsobj->pwSpaces[iwSpace] < iwchLim; iwSpace++)
  227. {
  228. pexpginfo->pexpg[priorSpace - 1].duMaxWhite += lsexpinfInfinity;
  229. pexpginfo->pexpg[priorSpace - 1].duTotalWhite += rgdu[pilsobj->pwSpaces[iwSpace]];
  230. pexpginfo->pexpg[priorSpace - 1].cWhite++;
  231. }
  232. }
  233. }
  234. itxtobj++;
  235. }
  236. return lserrNone;
  237. }
  238. /* A P P L Y P R I O R G L Y P H E X P A N D */
  239. /*----------------------------------------------------------------------------
  240. %%Function: ApplyPriorGlyphExpand
  241. %%Contact: sergeyge
  242. Applies glyph expansion for particular priority
  243. Startegy:
  244. 1. Apply Discrete expansion
  245. 2. If the rest to distribute is bigger than the sum of maximus for other distribution types
  246. use these maximums for distribution
  247. else if sum of mimimums is less than the rest to distribute
  248. distribute proportionally to this minimums (width of character for AddWhiteSpace type)
  249. else
  250. increase AddContinuous opportrunities by minimum one by one while possible,
  251. distribute the rest in White opportunities proportionally
  252. ---------------------------------------------------------------------------*/
  253. static LSERR ApplyPriorGlyphExp(const LSGRCHNK* plsgrchnk, LSTFLOW lstflow, LSDEVICE lsdev,
  254. long itxtobjFirst, long iwchFirst, long itxtobjLast, long iwchLast,
  255. long prior, long duToDistribute, EXPG* pexpg, long* rgdu, long* rgduGind,
  256. long* rgduRight, long* rgduGright, long* pduDistributed)
  257. {
  258. LSERR lserr;
  259. PILSOBJ pilsobj;
  260. long duCovered;
  261. const BOOL fWhiteOnly = fTrue;
  262. *pduDistributed = 0;
  263. pilsobj = ((PTXTOBJ)plsgrchnk->plschnk[0].pdobj)->plnobj->pilsobj;
  264. Assert(duToDistribute > 0);
  265. if (pexpg->cDiscrete > 0)
  266. {
  267. lserr = ApplyDiscrete(plsgrchnk, lstflow, lsdev, itxtobjFirst, iwchFirst, itxtobjLast, iwchLast,
  268. prior, duToDistribute, pexpg->cDiscrete,
  269. rgduGind, rgduGright, &duCovered);
  270. if (lserr != lserrNone) return lserr;
  271. Assert(duCovered <= duToDistribute);
  272. duToDistribute -= duCovered;
  273. *pduDistributed += duCovered;
  274. }
  275. if (duToDistribute > 0 && pexpg->cWhite + pexpg->cContinuous > 0 )
  276. {
  277. if (pexpg->duMaxWhite + pexpg->duMaxContinuous <= duToDistribute)
  278. {
  279. ApplyFullWhiteContinuous(plsgrchnk, itxtobjFirst, iwchFirst, itxtobjLast, iwchLast,
  280. prior, rgdu, rgduGind, rgduRight, rgduGright, &duCovered);
  281. Assert(duCovered == pexpg->duMaxWhite + pexpg->duMaxContinuous);
  282. duToDistribute -= duCovered;
  283. *pduDistributed += duCovered;
  284. }
  285. else if (pexpg->duTotalWhite + pexpg->duMinContinuous <= duToDistribute)
  286. {
  287. Assert(pexpg->duMaxWhite + pexpg->duMaxContinuous > duToDistribute);
  288. ApplyPropWhiteContinuous(plsgrchnk, !fWhiteOnly,
  289. itxtobjFirst, iwchFirst, itxtobjLast, iwchLast,
  290. prior, duToDistribute, pexpg->duTotalWhite + pexpg->duMinContinuous,
  291. rgdu, rgduGind, rgduRight, rgduGright, &duCovered);
  292. duToDistribute -= duCovered;
  293. *pduDistributed += duCovered;
  294. }
  295. else
  296. {
  297. Assert(pexpg->duTotalWhite + pexpg->duMinContinuous > duToDistribute);
  298. if (pexpg->cContinuous > 0)
  299. {
  300. ApplyOneEachContinuous(plsgrchnk, itxtobjFirst, iwchFirst, itxtobjLast, iwchLast,
  301. prior, duToDistribute, pexpg->cContinuous,
  302. rgduGind, rgduGright, &duCovered);
  303. duToDistribute -= duCovered;
  304. *pduDistributed += duCovered;
  305. }
  306. if (pexpg->cWhite > 0 && duToDistribute > 0)
  307. {
  308. ApplyPropWhiteContinuous(plsgrchnk, fWhiteOnly,
  309. itxtobjFirst, iwchFirst, itxtobjLast, iwchLast,
  310. prior, duToDistribute, pexpg->duTotalWhite,
  311. rgdu, rgduGind, rgduRight, rgduGright, &duCovered);
  312. duToDistribute -= duCovered;
  313. *pduDistributed += duCovered;
  314. }
  315. }
  316. }
  317. return lserrNone;
  318. }
  319. /* A P P L Y D I S C R E T E */
  320. /*----------------------------------------------------------------------------
  321. %%Function: ApplyDiscrete
  322. %%Contact: sergeyge
  323. Applies disctrete glyph expansion for particular priority
  324. Goes ones from first to last glyph on this priority level, and chooses maximum
  325. discrete opportunity which still fits.
  326. ---------------------------------------------------------------------------*/
  327. LSERR static ApplyDiscrete(const LSGRCHNK* plsgrchnk, LSTFLOW lstflow, LSDEVICE lsdev,
  328. long itxtobjFirst, long iwchVeryFirst, long itxtobjLast, long iwchLast,
  329. long prior, long duToDistribute, long cDiscrete,
  330. long* rgduGind, long* rgduGright, long* pduDistributed)
  331. {
  332. LSERR lserr;
  333. PILSOBJ pilsobj;
  334. PLNOBJ plnobj;
  335. PTXTOBJ ptxtobj;
  336. PTXTOBJ ptxtobjLast;
  337. PLSRUN plsrun;
  338. LSEXPINFO* plsexpinf;
  339. EXPTYPE* pexpt;
  340. long itxtobj;
  341. long iwchFirst;
  342. long iwchLim;
  343. long igindFirst;
  344. long igindLim;
  345. long igind;
  346. long rgduDiscrete[cDiscreteMax];
  347. long* pduDiscrete;
  348. long cwidths;
  349. int i;
  350. *pduDistributed = 0;
  351. ptxtobjLast = (PTXTOBJ)plsgrchnk->plschnk[max(0, itxtobjLast)].pdobj;
  352. plnobj = ptxtobjLast->plnobj;
  353. pilsobj = plnobj->pilsobj;
  354. itxtobj = itxtobjFirst;
  355. plsexpinf = pilsobj->plsexpinf;
  356. pexpt = plnobj->pexpt;
  357. for (itxtobj = itxtobjLast; itxtobj >= itxtobjFirst && cDiscrete > 0 && duToDistribute > 0; itxtobj--)
  358. {
  359. ptxtobj = (PTXTOBJ)plsgrchnk->plschnk[itxtobj].pdobj;
  360. if (ptxtobj->txtf & txtfGlyphBased)
  361. {
  362. iwchFirst = iwchVeryFirst;
  363. if (itxtobj > itxtobjFirst)
  364. iwchFirst = ptxtobj->iwchFirst;
  365. Assert(iwchFirst < ptxtobj->iwchLim);
  366. igindFirst = IgindFirstFromIwch(ptxtobj, iwchFirst);
  367. iwchLim = ptxtobj->iwchLim;
  368. igindLim = ptxtobj->igindLim;
  369. Assert(itxtobj <= itxtobjLast);
  370. if (itxtobj == itxtobjLast)
  371. {
  372. iwchLim = iwchLast + 1;
  373. Assert(IgindLastFromIwch(ptxtobjLast, iwchLast) + 1 <= igindLim);
  374. igindLim = IgindLastFromIwch(ptxtobjLast, iwchLast) + 1;
  375. }
  376. plsrun = plsgrchnk->plschnk[itxtobj].plsrun;
  377. for (igind = igindLim - 1; igind >= igindFirst && cDiscrete > 0 && duToDistribute > 0; igind--)
  378. {
  379. if (pexpt[igind] == exptAddInkDiscrete && plsexpinf[igind].prior == prior)
  380. {
  381. cDiscrete--;
  382. if (duToDistribute > plsexpinf[igind].duMax)
  383. {
  384. ApplyGlyphExpandChanges(igind, rgduGind, rgduGright, pduDistributed, plsexpinf[igind].duMax);
  385. duToDistribute -= plsexpinf[igind].duMax;
  386. }
  387. else
  388. {
  389. pduDiscrete = rgduDiscrete;
  390. cwidths = plsexpinf[igind].u.AddInkDiscrete.cwidths - 1;
  391. if (cwidths > cDiscreteMax)
  392. {
  393. pduDiscrete = (*pilsobj->plscbk->pfnNewPtr)(pilsobj->pols, sizeof(long) * cwidths);
  394. if (pduDiscrete == NULL) return lserrOutOfMemory;
  395. }
  396. lserr = (pilsobj->plscbk->pfnGetGlyphExpansionInkInfo)(pilsobj->pols, plsrun, lsdev,
  397. plnobj->pgind[igind], plnobj->pgprop[igind], lstflow, cwidths, pduDiscrete);
  398. if (lserr != lserrNone)
  399. {
  400. if (pduDiscrete != rgduDiscrete)
  401. (*pilsobj->plscbk->pfnDisposePtr)(pilsobj->pols, pduDiscrete);
  402. return lserr;
  403. }
  404. #ifdef DEBUG
  405. for (i = 0; i < cwidths - 1; i++)
  406. Assert(pduDiscrete[i] <= pduDiscrete[i+1]);
  407. #endif
  408. for (i = cwidths - 1; i >= 0 && pduDiscrete[i] > duToDistribute; i--);
  409. if (i >= 0)
  410. {
  411. Assert(pduDiscrete[i] <= duToDistribute);
  412. ApplyGlyphExpandChanges(igind, rgduGind, rgduGright, pduDistributed, pduDiscrete[i]);
  413. duToDistribute -= pduDiscrete[i];
  414. }
  415. if (pduDiscrete != rgduDiscrete)
  416. (*pilsobj->plscbk->pfnDisposePtr)(pilsobj->pols, pduDiscrete);
  417. }
  418. }
  419. }
  420. }
  421. }
  422. return lserrNone;
  423. }
  424. /* A P P L Y O N E E A C H C O N T I N U O U S */
  425. /*----------------------------------------------------------------------------
  426. %%Function: ApplyOneEachContinuous
  427. %%Contact: sergeyge
  428. Applies glyph expansion for particular priority
  429. Goes ones from first to last glyph on this priority level, and adds minimum
  430. to each glyph with AddIncContinuous exapnsion type, if this minimum still fits
  431. ---------------------------------------------------------------------------*/
  432. static void ApplyOneEachContinuous(const LSGRCHNK* plsgrchnk, long itxtobjFirst, long iwchVeryFirst,
  433. long itxtobjLast, long iwchLast, long prior, long duToDistribute, long cContinuous,
  434. long* rgduGind, long* rgduGright, long* pduDistributed)
  435. {
  436. PILSOBJ pilsobj;
  437. PLNOBJ plnobj;
  438. PTXTOBJ ptxtobj;
  439. PTXTOBJ ptxtobjLast;
  440. LSEXPINFO* plsexpinf;
  441. EXPTYPE* pexpt;
  442. long itxtobj;
  443. long iwchFirst;
  444. long iwchLim;
  445. long igindFirst;
  446. long igindLim;
  447. long igind;
  448. *pduDistributed = 0;
  449. ptxtobjLast = (PTXTOBJ)plsgrchnk->plschnk[max(0, itxtobjLast)].pdobj;
  450. plnobj = ptxtobjLast->plnobj;
  451. pilsobj = plnobj->pilsobj;
  452. itxtobj = itxtobjFirst;
  453. plsexpinf = pilsobj->plsexpinf;
  454. pexpt = plnobj->pexpt;
  455. for (itxtobj = itxtobjLast; itxtobj >= itxtobjFirst && cContinuous > 0 && duToDistribute > 0; itxtobj--)
  456. {
  457. ptxtobj = (PTXTOBJ)plsgrchnk->plschnk[itxtobj].pdobj;
  458. if (ptxtobj->txtf & txtfGlyphBased)
  459. {
  460. iwchFirst = iwchVeryFirst;
  461. if (itxtobj > itxtobjFirst)
  462. iwchFirst = ptxtobj->iwchFirst;
  463. Assert(iwchFirst < ptxtobj->iwchLim);
  464. igindFirst = IgindFirstFromIwch(ptxtobj, iwchFirst);
  465. iwchLim = ptxtobj->iwchLim;
  466. igindLim = ptxtobj->igindLim;
  467. Assert(itxtobj <= itxtobjLast);
  468. if (itxtobj == itxtobjLast)
  469. {
  470. iwchLim = iwchLast + 1;
  471. Assert(IgindLastFromIwch(ptxtobjLast, iwchLast) + 1 <= igindLim);
  472. igindLim = IgindLastFromIwch(ptxtobjLast, iwchLast) + 1;
  473. }
  474. for (igind = igindLim - 1; igind >= igindFirst && cContinuous> 0 && duToDistribute > 0; igind--)
  475. {
  476. if (pexpt[igind] == exptAddInkContinuous && plsexpinf[igind].prior == prior)
  477. {
  478. cContinuous--;
  479. if (duToDistribute > plsexpinf[igind].u.AddInkContinuous.duMin)
  480. {
  481. ApplyGlyphExpandChanges(igind, rgduGind, rgduGright, pduDistributed, plsexpinf[igind].u.AddInkContinuous.duMin);
  482. duToDistribute -= plsexpinf[igind].u.AddInkContinuous.duMin;
  483. }
  484. }
  485. }
  486. }
  487. }
  488. }
  489. /* A P P L Y F U L L W H I T E C O N T I N U O U S */
  490. /*----------------------------------------------------------------------------
  491. %%Function: ApplyFullWhiteContinuous
  492. %%Contact: sergeyge
  493. Applies glyph expansion for particular priority
  494. Goes ones from first to last glyph on this priority level, and adds maximum
  495. to each glyph with AddIncContinuous or AddWhiteSpace exapnsion type
  496. ---------------------------------------------------------------------------*/
  497. static void ApplyFullWhiteContinuous(const LSGRCHNK* plsgrchnk,
  498. long itxtobjFirst, long iwchVeryFirst, long itxtobjLast, long iwchLast,
  499. long prior,
  500. long* rgdu, long* rgduGind, long* rgduRight, long* rgduGright, long* pduDistributed)
  501. {
  502. PILSOBJ pilsobj;
  503. PLNOBJ plnobj;
  504. PTXTOBJ ptxtobj;
  505. PTXTOBJ ptxtobjLast;
  506. LSEXPINFO* plsexpinf;
  507. EXPTYPE* pexpt;
  508. long itxtobj;
  509. long iwchFirst;
  510. long iwchLim;
  511. long igindFirst;
  512. long igindLim;
  513. long igind;
  514. long iwSpace;
  515. *pduDistributed = 0;
  516. ptxtobjLast = (PTXTOBJ)plsgrchnk->plschnk[max(0, itxtobjLast)].pdobj;
  517. plnobj = ptxtobjLast->plnobj;
  518. pilsobj = plnobj->pilsobj;
  519. itxtobj = itxtobjFirst;
  520. plsexpinf = pilsobj->plsexpinf;
  521. pexpt = plnobj->pexpt;
  522. for (itxtobj = itxtobjFirst; itxtobj <= itxtobjLast; itxtobj++)
  523. {
  524. ptxtobj = (PTXTOBJ)plsgrchnk->plschnk[itxtobj].pdobj;
  525. if (ptxtobj->txtf & txtfGlyphBased)
  526. {
  527. iwchFirst = iwchVeryFirst;
  528. if (itxtobj > itxtobjFirst)
  529. iwchFirst = ptxtobj->iwchFirst;
  530. Assert(iwchFirst < ptxtobj->iwchLim);
  531. igindFirst = IgindFirstFromIwch(ptxtobj, iwchFirst);
  532. iwchLim = ptxtobj->iwchLim;
  533. igindLim = ptxtobj->igindLim;
  534. Assert(itxtobj <= itxtobjLast);
  535. if (itxtobj == itxtobjLast)
  536. {
  537. iwchLim = iwchLast + 1;
  538. Assert(IgindLastFromIwch(ptxtobjLast, iwchLast) + 1 <= igindLim);
  539. igindLim = IgindLastFromIwch(ptxtobjLast, iwchLast) + 1;
  540. }
  541. for (igind = igindFirst; igind < igindLim; igind++)
  542. {
  543. if (plsexpinf[igind].prior == prior &&
  544. (pexpt[igind] == exptAddWhiteSpace || pexpt[igind] == exptAddInkContinuous))
  545. {
  546. ApplyGlyphExpandChanges(igind, rgduGind, rgduGright, pduDistributed, plsexpinf[igind].duMax);
  547. }
  548. }
  549. }
  550. else
  551. {
  552. if (ptxtobj->txtkind == txtkindRegular && prior == priorSpace)
  553. {
  554. iwchFirst = iwchVeryFirst;
  555. if (itxtobj > itxtobjFirst)
  556. iwchFirst = ptxtobj->iwchFirst;
  557. iwchLim = iwchLast + 1;
  558. if (itxtobj < itxtobjLast)
  559. iwchLim = ptxtobj->iwchLim;
  560. for (iwSpace = ptxtobj->u.reg.iwSpacesFirst; iwSpace < ptxtobj->u.reg.iwSpacesLim &&
  561. pilsobj->pwSpaces[iwSpace] < iwchFirst; iwSpace++);
  562. for (; iwSpace < ptxtobj->u.reg.iwSpacesLim &&
  563. pilsobj->pwSpaces[iwSpace] < iwchLim; iwSpace++)
  564. {
  565. Assert(fFalse);
  566. ApplyGlyphExpandChanges(pilsobj->pwSpaces[iwSpace], rgdu, rgduRight, pduDistributed, lsexpinfInfinity);
  567. }
  568. }
  569. }
  570. }
  571. }
  572. /* A P P L Y P R O P W H I T E C O N T I N U O U S */
  573. /*----------------------------------------------------------------------------
  574. %%Function: ApplyPropWhiteContinuous
  575. %%Contact: sergeyge
  576. Applies glyph expansion for particular priority
  577. Goes ones from first to last glyph on this priority level, and increases width
  578. for each glyph with AddIncContinuous or AddWhiteSpace exapnsion type
  579. proportionally to its minimum (for InkCont) or width of character (for WhiteSpace).
  580. ---------------------------------------------------------------------------*/
  581. static void ApplyPropWhiteContinuous(const LSGRCHNK* plsgrchnk, BOOL fWhiteOnly,
  582. long itxtobjFirst, long iwchVeryFirst, long itxtobjLast, long iwchLast, long prior,
  583. long duToDistribute, long duDenom,
  584. long* rgdu, long* rgduGind, long* rgduRight, long* rgduGright, long* pduDistributed)
  585. {
  586. PILSOBJ pilsobj;
  587. PLNOBJ plnobj;
  588. PTXTOBJ ptxtobj;
  589. PTXTOBJ ptxtobjLast;
  590. LSEXPINFO* plsexpinf;
  591. EXPTYPE* pexpt;
  592. long itxtobj;
  593. long iwchFirst;
  594. long iwchLim;
  595. long igindFirst;
  596. long igindLim;
  597. long igind;
  598. long cWhole;
  599. long duAddCurrent;
  600. long duDebt;
  601. long duRest;
  602. long duChange;
  603. long iwch;
  604. long iwSpace;
  605. long duDebtSaved;
  606. *pduDistributed = 0;
  607. ptxtobjLast = (PTXTOBJ)plsgrchnk->plschnk[max(0, itxtobjLast)].pdobj;
  608. plnobj = ptxtobjLast->plnobj;
  609. pilsobj = plnobj->pilsobj;
  610. plsexpinf = pilsobj->plsexpinf;
  611. pexpt = plnobj->pexpt;
  612. cWhole = duToDistribute / duDenom;
  613. duRest = duToDistribute - cWhole * duDenom;
  614. duAddCurrent = 0;
  615. duDebt = 0;
  616. for (itxtobj = itxtobjFirst; itxtobj <= itxtobjLast; itxtobj++)
  617. {
  618. ptxtobj = (PTXTOBJ)plsgrchnk->plschnk[itxtobj].pdobj;
  619. if (ptxtobj->txtf & txtfGlyphBased)
  620. {
  621. iwchFirst = iwchVeryFirst;
  622. if (itxtobj > itxtobjFirst)
  623. iwchFirst = ptxtobj->iwchFirst;
  624. Assert(iwchFirst < ptxtobj->iwchLim);
  625. igindFirst = IgindFirstFromIwch(ptxtobj, iwchFirst);
  626. iwchLim = ptxtobj->iwchLim;
  627. igindLim = ptxtobj->igindLim;
  628. Assert(itxtobj <= itxtobjLast);
  629. if (itxtobj == itxtobjLast)
  630. {
  631. iwchLim = iwchLast + 1;
  632. Assert(IgindLastFromIwch(ptxtobjLast, iwchLast) + 1 <= igindLim);
  633. igindLim = IgindLastFromIwch(ptxtobjLast, iwchLast) + 1;
  634. }
  635. for (igind = igindFirst; igind < igindLim; igind++)
  636. {
  637. if (plsexpinf[igind].prior == prior)
  638. {
  639. if (pexpt[igind] == exptAddWhiteSpace)
  640. {
  641. Assert(rgduGright[igind] == 0 || pexpt[igind] == exptAddInkDiscrete);
  642. CalcExpandChanges(cWhole, duDenom, duRest,
  643. rgduGind[igind], plsexpinf[igind].duMax, &duChange, &duAddCurrent);
  644. if (duChange > 0)
  645. ApplyGlyphExpandChanges(igind, rgduGind, rgduGright, pduDistributed, duChange);
  646. }
  647. else if (pexpt[igind] == exptAddInkContinuous && !fWhiteOnly)
  648. {
  649. Assert(rgduGright[igind] == 0 || pexpt[igind] == exptAddInkDiscrete);
  650. CalcExpandChanges(cWhole, duDenom, duRest, plsexpinf[igind].u.AddInkContinuous.duMin,
  651. plsexpinf[igind].duMax, &duChange, &duAddCurrent);
  652. if (duChange > 0)
  653. ApplyGlyphExpandChanges(igind, rgduGind, rgduGright, pduDistributed, duChange);
  654. }
  655. }
  656. }
  657. }
  658. else
  659. {
  660. if (ptxtobj->txtkind == txtkindRegular && prior == priorSpace)
  661. {
  662. iwchFirst = iwchVeryFirst;
  663. if (itxtobj > itxtobjFirst)
  664. iwchFirst = ptxtobj->iwchFirst;
  665. iwchLim = iwchLast + 1;
  666. if (itxtobj < itxtobjLast)
  667. iwchLim = ptxtobj->iwchLim;
  668. for (iwSpace = ptxtobj->u.reg.iwSpacesFirst; iwSpace < ptxtobj->u.reg.iwSpacesLim &&
  669. pilsobj->pwSpaces[iwSpace] < iwchFirst; iwSpace++);
  670. for (; iwSpace < ptxtobj->u.reg.iwSpacesLim &&
  671. pilsobj->pwSpaces[iwSpace] < iwchLim; iwSpace++)
  672. {
  673. iwch = pilsobj->pwSpaces[iwSpace];
  674. CalcExpandChanges(cWhole, duDenom, duRest, rgdu[iwch], lsexpinfInfinity,
  675. &duChange, &duAddCurrent);
  676. if (duChange > 0)
  677. ApplyGlyphExpandChanges(iwch, rgdu, rgduRight, pduDistributed, duChange);
  678. }
  679. }
  680. }
  681. }
  682. duDebt = duToDistribute - *pduDistributed;
  683. Assert(duDebt >= 0);
  684. /* If not everything distributed, distribute it somehow not violating Min/Max boundaries */
  685. duDebtSaved = 0;
  686. while (duDebt > 0 && duDebt != duDebtSaved)
  687. {
  688. duDebtSaved = duDebt;
  689. for (itxtobj = itxtobjLast; itxtobj >= itxtobjFirst && duDebt > 0; itxtobj--)
  690. {
  691. ptxtobj = (PTXTOBJ)plsgrchnk->plschnk[itxtobj].pdobj;
  692. if (ptxtobj->txtf & txtfGlyphBased)
  693. {
  694. iwchFirst = iwchVeryFirst;
  695. if (itxtobj > itxtobjFirst)
  696. iwchFirst = ptxtobj->iwchFirst;
  697. Assert(iwchFirst < ptxtobj->iwchLim);
  698. igindFirst = IgindFirstFromIwch(ptxtobj, iwchFirst);
  699. iwchLim = ptxtobj->iwchLim;
  700. igindLim = ptxtobj->igindLim;
  701. Assert(itxtobj <= itxtobjLast);
  702. if (itxtobj == itxtobjLast)
  703. {
  704. iwchLim = iwchLast + 1;
  705. Assert(IgindLastFromIwch(ptxtobjLast, iwchLast) + 1 <= igindLim);
  706. igindLim = IgindLastFromIwch(ptxtobjLast, iwchLast) + 1;
  707. }
  708. for (igind = igindLim - 1; igind >= igindFirst && duDebt > 0; igind--)
  709. {
  710. if (plsexpinf[igind].prior == prior && rgduGright[igind] < plsexpinf[igind].duMax)
  711. {
  712. if (pexpt[igind] == exptAddWhiteSpace)
  713. {
  714. duChange = min(rgduGind[igind] - rgduGright[igind], min(duDebt, plsexpinf[igind].duMax - rgduGright[igind]));
  715. ApplyGlyphExpandChanges(igind, rgduGind, rgduGright, pduDistributed, duChange);
  716. duDebt -= duChange;
  717. }
  718. else if (pexpt[igind] == exptAddInkContinuous && !fWhiteOnly)
  719. {
  720. Assert(rgduGright[igind] > 0);
  721. duChange = min(plsexpinf[igind].u.AddInkContinuous.duMin, min(duDebt, plsexpinf[igind].duMax - rgduGright[igind]));
  722. ApplyGlyphExpandChanges(igind, rgduGind, rgduGright, pduDistributed, duChange);
  723. duDebt -= duChange;
  724. }
  725. }
  726. }
  727. }
  728. else
  729. {
  730. if (ptxtobj->txtkind == txtkindRegular && prior == priorSpace)
  731. {
  732. iwchFirst = iwchVeryFirst;
  733. if (itxtobj > itxtobjFirst)
  734. iwchFirst = ptxtobj->iwchFirst;
  735. iwchLim = iwchLast + 1;
  736. if (itxtobj < itxtobjLast)
  737. iwchLim = ptxtobj->iwchLim;
  738. for (iwSpace = ptxtobj->u.reg.iwSpacesLim - 1; iwSpace >= ptxtobj->u.reg.iwSpacesFirst &&
  739. pilsobj->pwSpaces[iwSpace] >= iwchLim; iwSpace--);
  740. for (; iwSpace >= ptxtobj->u.reg.iwSpacesFirst &&
  741. pilsobj->pwSpaces[iwSpace] >= iwchFirst && duDebt > 0; iwSpace--)
  742. {
  743. iwch = pilsobj->pwSpaces[iwSpace];
  744. duChange = min(rgdu[iwch] - rgduRight[iwch], duDebt);
  745. ApplyGlyphExpandChanges(iwch, rgdu, rgduRight, pduDistributed, duChange);
  746. duDebt -= duChange;
  747. }
  748. }
  749. }
  750. }
  751. Assert(duDebt == duToDistribute - *pduDistributed);
  752. }
  753. }
  754. /* A P P L Y R E S I D U A L G L Y P H E X P */
  755. /*----------------------------------------------------------------------------
  756. %%Function: ApplyResidualGlyphExp
  757. %%Contact: sergeyge
  758. Distributes equally between all risidual opportunities
  759. ---------------------------------------------------------------------------*/
  760. static void ApplyResidualGlyphExp(const LSGRCHNK* plsgrchnk, long itxtobjFirst,
  761. long iwchVeryFirst, long itxtobjLast, long iwchLast, long duToDistribute,
  762. long cResidual, long* rgduGind, long* rgduGright, long* pduDistributed)
  763. {
  764. PILSOBJ pilsobj;
  765. PTXTOBJ ptxtobj;
  766. PTXTOBJ ptxtobjLast;
  767. LSEXPINFO* plsexpinf;
  768. long itxtobj;
  769. long iwchFirst;
  770. long iwchLim;
  771. long igindFirst;
  772. long igindLim;
  773. long igind;
  774. long cUsed;
  775. long duAdd;
  776. long cBound;
  777. *pduDistributed = 0;
  778. if (cResidual == 0)
  779. return;
  780. ptxtobjLast = (PTXTOBJ)plsgrchnk->plschnk[max(0, itxtobjLast)].pdobj;
  781. pilsobj = ptxtobjLast->plnobj->pilsobj;
  782. itxtobj = itxtobjFirst;
  783. plsexpinf = pilsobj->plsexpinf;
  784. duAdd = duToDistribute / cResidual;
  785. cBound = duToDistribute - duAdd * cResidual;
  786. cUsed = 0;
  787. for (itxtobj = itxtobjFirst; itxtobj <= itxtobjLast; itxtobj++)
  788. {
  789. ptxtobj = (PTXTOBJ)plsgrchnk->plschnk[itxtobj].pdobj;
  790. if (ptxtobj->txtf & txtfGlyphBased)
  791. {
  792. iwchFirst = iwchVeryFirst;
  793. if (itxtobj > itxtobjFirst)
  794. iwchFirst = ptxtobj->iwchFirst;
  795. Assert(iwchFirst < ptxtobj->iwchLim);
  796. igindFirst = IgindFirstFromIwch(ptxtobj, iwchFirst);
  797. iwchLim = ptxtobj->iwchLim;
  798. igindLim = ptxtobj->igindLim;
  799. Assert(itxtobj <= itxtobjLast);
  800. if (itxtobj == itxtobjLast)
  801. {
  802. iwchLim = iwchLast + 1;
  803. Assert(IgindLastFromIwch(ptxtobjLast, iwchLast) + 1 <= igindLim);
  804. igindLim = IgindLastFromIwch(ptxtobjLast, iwchLast) + 1;
  805. }
  806. for (igind = igindFirst; igind < igindLim; igind++)
  807. {
  808. if (plsexpinf[igind].fCanBeUsedForResidual)
  809. {
  810. if (cUsed < cBound)
  811. ApplyGlyphExpandChanges(igind, rgduGind, rgduGright, pduDistributed, duAdd + 1);
  812. else
  813. ApplyGlyphExpandChanges(igind, rgduGind, rgduGright, pduDistributed, duAdd);
  814. cUsed++;
  815. }
  816. }
  817. }
  818. }
  819. Assert(duToDistribute == *pduDistributed);
  820. }
  821. /* F I X E X P T */
  822. /*----------------------------------------------------------------------------
  823. %%Function: FixExpt
  824. %%Contact: sergeyge
  825. Zeroes expt for the glyphs which were not changed,
  826. so correct distribution type is passed to client at display time
  827. ---------------------------------------------------------------------------*/
  828. static void FixExpt(const LSGRCHNK* plsgrchnk, long itxtobjFirst, long iwchVeryFirst,
  829. long itxtobjLast, long iwchLast, long* rgduGright)
  830. {
  831. PTXTOBJ ptxtobj;
  832. PTXTOBJ ptxtobjLast;
  833. EXPTYPE* pexpt;
  834. long itxtobj;
  835. long iwchFirst;
  836. long iwchLim;
  837. long igindFirst;
  838. long igindLim;
  839. long igind;
  840. ptxtobjLast = (PTXTOBJ)plsgrchnk->plschnk[max(0, itxtobjLast)].pdobj;
  841. pexpt = ptxtobjLast->plnobj->pexpt;
  842. itxtobj = itxtobjFirst;
  843. for (itxtobj = itxtobjFirst; itxtobj <= itxtobjLast; itxtobj++)
  844. {
  845. ptxtobj = (PTXTOBJ)plsgrchnk->plschnk[itxtobj].pdobj;
  846. if (ptxtobj->txtf & txtfGlyphBased)
  847. {
  848. iwchFirst = iwchVeryFirst;
  849. if (itxtobj > itxtobjFirst)
  850. iwchFirst = ptxtobj->iwchFirst;
  851. Assert(iwchFirst < ptxtobj->iwchLim);
  852. igindFirst = IgindFirstFromIwch(ptxtobj, iwchFirst);
  853. iwchLim = ptxtobj->iwchLim;
  854. igindLim = ptxtobj->igindLim;
  855. Assert(itxtobj <= itxtobjLast);
  856. if (itxtobj == itxtobjLast)
  857. {
  858. iwchLim = iwchLast + 1;
  859. Assert(IgindLastFromIwch(ptxtobjLast, iwchLast) + 1 <= igindLim);
  860. igindLim = IgindLastFromIwch(ptxtobjLast, iwchLast) + 1;
  861. }
  862. for (igind = igindFirst; igind < igindLim; igind++)
  863. {
  864. if (rgduGright[igind] == 0)
  865. {
  866. pexpt[igind] = 0;
  867. }
  868. }
  869. }
  870. }
  871. }
  872. /* C A L C E X P A N D C H A N G E S */
  873. /*----------------------------------------------------------------------------
  874. %%Function: CalcExpandChanges
  875. %%Contact: sergeyge
  876. Arithmetics for proportional distribution
  877. ---------------------------------------------------------------------------*/
  878. static void CalcExpandChanges(long cWhole, long duDenom, long duRest, long duLocal, long duMax,
  879. long* pduChange, long* pduAddCurrent)
  880. {
  881. /* REVIEW sergeyge: is __int64 necessary to avoid overflow??? */
  882. __int64 temp;
  883. temp = Mul64 (duRest, duLocal) + *pduAddCurrent;
  884. Assert(duDenom > 0);
  885. Assert(Div64 (temp, duDenom) < 0x7FFFFFFF);
  886. *pduChange = (long) Div64 (temp, duDenom);
  887. Assert( temp - Mul64(*pduChange, duDenom) < 0x7FFFFFFF);
  888. *pduAddCurrent = (long)(temp - Mul64(*pduChange, duDenom));
  889. *pduChange += (cWhole * duLocal);
  890. if (*pduChange > duMax)
  891. {
  892. *pduChange = duMax;
  893. }
  894. }
  895. /* A P P L Y G L Y P H E X P A N D C H A N G E S */
  896. /*----------------------------------------------------------------------------
  897. %%Function: ApplyGlyphExpandChanges
  898. %%Contact: sergeyge
  899. ---------------------------------------------------------------------------*/
  900. static void ApplyGlyphExpandChanges(long ind, long* rgduGind, long* rgduGright, long* pduDistributed, long duChange)
  901. {
  902. rgduGind[ind] += duChange;
  903. rgduGright[ind] += duChange;
  904. *pduDistributed += duChange;
  905. }