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.

1717 lines
53 KiB

  1. #include "lsmem.h"
  2. #include <limits.h>
  3. #include "lstxtjst.h"
  4. #include "lstxtwrd.h"
  5. #include "lstxtcmp.h"
  6. #include "lstxtglf.h"
  7. #include "lstxtscl.h"
  8. #include "lstxtmap.h"
  9. #include "lsdnset.h"
  10. #include "lsdntext.h"
  11. #include "locchnk.h"
  12. #include "posichnk.h"
  13. #include "objdim.h"
  14. #include "lstxtffi.h"
  15. #include "txtils.h"
  16. #include "txtln.h"
  17. #include "txtobj.h"
  18. #define min(a,b) ((a) > (b) ? (b) : (a))
  19. #define max(a,b) ((a) < (b) ? (b) : (a))
  20. static void GetFirstPosAfterStartSpaces(const LSGRCHNK* plsgrchnk, long itxtobjLast, long iwchLim,
  21. long* pitxtobjAfterStartSpaces, long* piwchAfterStartSpaces, BOOL* pfFirstOnLineAfter);
  22. static LSERR HandleSimpleTextWysi(LSKJUST lskjust, const LSGRCHNK* plsgrchnk, long durToDistribute,
  23. long dupAvailable, LSTFLOW lstflow, long itxtobjAfterStartSpaces, long iwchAfterStartSpaces,
  24. long itxtobjLast, long iwchLast, BOOL fExactSync,
  25. BOOL fForcedBreak, BOOL fSuppressTrailingSpaces,
  26. long* pdupText, long* pdupTail);
  27. static LSERR HandleSimpleTextPres(LSKJUST lskjust, const LSGRCHNK* plsgrchnk,
  28. long dupAvailable, long itxtobjAfterStartSpaces, long iwchAfterStartSpaces,
  29. long itxtobjLast, long iwchLast, BOOL fForcedBreak, BOOL fSuppressTrailingSpaces,
  30. long* pdupText, long* pdupTail);
  31. static LSERR HandleGeneralSpacesExactSync(LSKJUST lskjust, const LSGRCHNK* plsgrchnk, long durToDistribute,
  32. long dupAvailable, LSTFLOW lstflow, long itxtobjAfterStartSpaces, long iwchAfterStartSpaces,
  33. long itxtobjLast, long iwchLast, BOOL fForcedBreak, BOOL fSuppressTrailingSpaces,
  34. long* pdupText, long* pdupTail);
  35. static LSERR HandleGeneralSpacesPres(LSKJUST lskjust, const LSGRCHNK* plsgrchnk, long dupAvailable,
  36. LSTFLOW lstflow, long itxtobjAfterStartSpaces, long iwchAfterStartSpaces,
  37. long itxtobjLast, long iwchLast, BOOL fForcedBreak, BOOL fSuppressTrailingSpaces,
  38. long* pdupText, long* pdupTail);
  39. static LSERR HandleTablesBased(LSKJUST lskjust, const LSGRCHNK* plsgrchnk,
  40. long durToDistribute, long dupAvailable, LSTFLOW lstflow,
  41. long itxtobjAfterStartSpaces, long iwchAfterStartSpaces, BOOL fFirstOnLineAfter,
  42. long itxtobjLast, long iwchLast, long cNonText, BOOL fLastObjectIsText,
  43. BOOL fForcedBreak, BOOL fSuppressTrailingSpaces,
  44. long* pdupText, long* pdupTail, long* pdupExtNonText);
  45. static LSERR HandleFullGlyphsExactSync(const LSGRCHNK* plsgrchnk,
  46. long durToDistribute, long dupAvailable, LSTFLOW lstflow,
  47. long itxtobjAfterStartSpaces, long iwchAfterStartSpaces,
  48. long itxtobjLast, long iwchLast, BOOL fForcedBreak, BOOL fSuppressTrailingSpaces,
  49. long* pdupText, long* pdupTail);
  50. static LSERR HandleFullGlyphsPres(const LSGRCHNK* plsgrchnk, long dupAvailable,
  51. LSTFLOW lstflow, long itxtobjAfterStartSpaces, long iwchAfterStartSpaces,
  52. long itxtobjLast, long iwchLast, BOOL fForcedBreak, BOOL fSuppressTrailingSpaces,
  53. long* pdupText, long* pdupTail);
  54. /* A D J U S T T E X T */
  55. /*----------------------------------------------------------------------------
  56. %%Function: AdjustText
  57. %%Contact: sergeyge
  58. The top-level text handler function of
  59. the PrepLineForDisplay time---calculation of the presentation widths
  60. It calculates justification area (from first non-space to last non-space),
  61. checks for the type of justification and WYSIWYG algorythm
  62. and redirects the program flow accordingly.
  63. ----------------------------------------------------------------------------*/
  64. LSERR AdjustText(LSKJUST lskjust, long durColumnMax, long durTotal, long dupAvailable,
  65. const LSGRCHNK* plsgrchnk, PCPOSICHNK pposichnkBeforeTrailing, LSTFLOW lstflow,
  66. BOOL fCompress, DWORD cNonText, BOOL fSuppressWiggle, BOOL fExactSync,
  67. BOOL fForcedBreak, BOOL fSuppressTrailingSpaces,
  68. long* pdupText, long* pdupTail,long* pdupExtNonTextObjects, DWORD* pcExtNonTextObjects)
  69. {
  70. PILSOBJ pilsobj;
  71. long itxtobjAfterStartSpaces;
  72. long itxtobjLast;
  73. PTXTOBJ ptxtobjLast;
  74. long iwchAfterStartSpaces;
  75. long iwchLast;
  76. long clsgrchnk;
  77. long durToDistribute;
  78. BOOL fFirstOnLineAfter;
  79. BOOL fLastObjectIsText;
  80. LSDCP dcp;
  81. *pdupText = 0;
  82. *pdupTail = 0;
  83. *pdupExtNonTextObjects = 0;
  84. *pcExtNonTextObjects = 0;
  85. clsgrchnk = (long)plsgrchnk->clsgrchnk;
  86. if (clsgrchnk == 0)
  87. {
  88. Assert(cNonText > 0);
  89. if (lskjust == lskjFullScaled || lskjust == lskjFullInterLetterAligned)
  90. {
  91. *pcExtNonTextObjects = cNonText - 1;
  92. *pdupExtNonTextObjects = dupAvailable;
  93. }
  94. return lserrNone;
  95. }
  96. pilsobj = ((PTXTOBJ)plsgrchnk->plschnk[0].pdobj)->plnobj->pilsobj;
  97. Assert (pilsobj->fDisplay);
  98. if (pilsobj->fPresEqualRef)
  99. {
  100. fExactSync = fFalse;
  101. fSuppressWiggle = fFalse;
  102. }
  103. itxtobjLast = pposichnkBeforeTrailing->ichnk;
  104. dcp = pposichnkBeforeTrailing->dcp;
  105. Assert(itxtobjLast >= 0);
  106. Assert(itxtobjLast < clsgrchnk || (itxtobjLast == clsgrchnk && dcp == 0));
  107. if (dcp == 0 && itxtobjLast > 0)
  108. {
  109. itxtobjLast--;
  110. dcp = plsgrchnk->plschnk[itxtobjLast].dcp;
  111. }
  112. ptxtobjLast = (PTXTOBJ)plsgrchnk->plschnk[itxtobjLast].pdobj;
  113. if (ptxtobjLast->iwchLim > ptxtobjLast->iwchFirst)
  114. iwchLast = ptxtobjLast->iwchFirst + dcp - 1;
  115. else
  116. iwchLast = ptxtobjLast->iwchLim - 1;
  117. /* In the case of AutoHyphenation, dcp reported by manager is not equal to the real number of characters---
  118. it should be fixed. Notice that in the case of "delete before" hyphenation type,
  119. situation is totally wrong because deleted character was replaced by space and collected by manager as trailing space.
  120. */
  121. if (ptxtobjLast == ptxtobjLast->plnobj->pdobjHyphen)
  122. {
  123. iwchLast = ptxtobjLast->iwchLim - 1;
  124. }
  125. Assert(iwchLast >= ptxtobjLast->iwchFirst - 1);
  126. Assert(iwchLast <= ptxtobjLast->iwchLim - 1);
  127. GetFirstPosAfterStartSpaces(plsgrchnk, itxtobjLast, iwchLast + 1,
  128. &itxtobjAfterStartSpaces, &iwchAfterStartSpaces, &fFirstOnLineAfter);
  129. durToDistribute = durColumnMax - durTotal;
  130. if (!pilsobj->fNotSimpleText)
  131. {
  132. if (durToDistribute < 0)
  133. fSuppressWiggle = fFalse;
  134. if (fExactSync || fSuppressWiggle)
  135. {
  136. return HandleSimpleTextWysi(lskjust, plsgrchnk, durToDistribute, dupAvailable, lstflow,
  137. itxtobjAfterStartSpaces, iwchAfterStartSpaces, itxtobjLast, iwchLast, fExactSync,
  138. fForcedBreak, fSuppressTrailingSpaces,
  139. pdupText, pdupTail);
  140. }
  141. // else if (fSupressWiggle) /* add later */
  142. else
  143. {
  144. return HandleSimpleTextPres(lskjust, plsgrchnk, dupAvailable,
  145. itxtobjAfterStartSpaces, iwchAfterStartSpaces, itxtobjLast, iwchLast,
  146. fForcedBreak, fSuppressTrailingSpaces,
  147. pdupText, pdupTail);
  148. }
  149. }
  150. else
  151. {
  152. long itxtobjFirstInLastTextChunk;
  153. for(itxtobjFirstInLastTextChunk = clsgrchnk; itxtobjFirstInLastTextChunk > 0 &&
  154. !(plsgrchnk->pcont[itxtobjFirstInLastTextChunk - 1] & fcontNonTextAfter); itxtobjFirstInLastTextChunk--);
  155. fLastObjectIsText = fTrue;
  156. if (itxtobjLast < itxtobjFirstInLastTextChunk ||
  157. itxtobjLast == itxtobjFirstInLastTextChunk && iwchLast < ((PTXTOBJ)plsgrchnk->plschnk[itxtobjFirstInLastTextChunk].pdobj)->iwchFirst )
  158. {
  159. /* REVIEW sergeyge: check this logic */
  160. if (cNonText > 0)
  161. cNonText--;
  162. fLastObjectIsText = fFalse;
  163. }
  164. *pcExtNonTextObjects = cNonText;
  165. if (fCompress || lskjust == lskjFullInterLetterAligned || lskjust == lskjFullScaled || pilsobj->fSnapGrid)
  166. {
  167. return HandleTablesBased(lskjust, plsgrchnk, durToDistribute, dupAvailable, lstflow,
  168. itxtobjAfterStartSpaces, iwchAfterStartSpaces, fFirstOnLineAfter,
  169. itxtobjLast, iwchLast, cNonText, fLastObjectIsText,
  170. fForcedBreak, fSuppressTrailingSpaces,
  171. pdupText, pdupTail, pdupExtNonTextObjects);
  172. }
  173. else if (lskjust == lskjFullGlyphs)
  174. {
  175. if (fExactSync || fSuppressWiggle)
  176. {
  177. return HandleFullGlyphsExactSync(plsgrchnk, durToDistribute, dupAvailable, lstflow,
  178. itxtobjAfterStartSpaces, iwchAfterStartSpaces, itxtobjLast, iwchLast,
  179. fForcedBreak, fSuppressTrailingSpaces,
  180. pdupText, pdupTail);
  181. }
  182. else
  183. {
  184. return HandleFullGlyphsPres(plsgrchnk, dupAvailable, lstflow,
  185. itxtobjAfterStartSpaces, iwchAfterStartSpaces, itxtobjLast, iwchLast,
  186. fForcedBreak, fSuppressTrailingSpaces,
  187. pdupText, pdupTail);
  188. }
  189. }
  190. else
  191. {
  192. if (plsgrchnk->clsgrchnk == 0)
  193. return lserrNone;
  194. Assert(fCompress == fFalse);
  195. Assert(lskjust == lskjNone || lskjust == lskjFullInterWord);
  196. if (fExactSync || fSuppressWiggle)
  197. {
  198. return HandleGeneralSpacesExactSync(lskjust, plsgrchnk, durToDistribute, dupAvailable, lstflow,
  199. itxtobjAfterStartSpaces, iwchAfterStartSpaces, itxtobjLast, iwchLast,
  200. fForcedBreak, fSuppressTrailingSpaces,
  201. pdupText, pdupTail);
  202. }
  203. else
  204. {
  205. return HandleGeneralSpacesPres(lskjust, plsgrchnk, dupAvailable, lstflow,
  206. itxtobjAfterStartSpaces, iwchAfterStartSpaces, itxtobjLast, iwchLast,
  207. fForcedBreak, fSuppressTrailingSpaces,
  208. pdupText, pdupTail);
  209. }
  210. }
  211. }
  212. }
  213. /* C A N C O M P R E S S T E X T */
  214. /*----------------------------------------------------------------------------
  215. %%Function: CanCompressText
  216. %%Contact: sergeyge
  217. Procedure checks if there is enough compression opportunities on the line
  218. to squeeze in needed amount (durToCompress).
  219. Trailing spaces are already subtracted by the manager.
  220. This procedure takes care of the hanging punctuation
  221. and possible changes if this break opportunity will be realized
  222. At the end it helps Word to solve backward compatibility issues
  223. ----------------------------------------------------------------------------*/
  224. LSERR CanCompressText(const LSGRCHNK* plsgrchnk, PCPOSICHNK pposichnkBeforeTrailing, LSTFLOW lstflow,
  225. long durToCompress, BOOL* pfCanCompress, BOOL* pfActualCompress, long* pdurNonSufficient)
  226. {
  227. LSERR lserr;
  228. PILSOBJ pilsobj;
  229. long clschnk;
  230. long itxtobjFirstInLastTextChunk; /* if GroupChunk ends with foreign object it is equal to cchnk */
  231. long itxtobjLast;
  232. PTXTOBJ ptxtobjLast;
  233. long iwchLast;
  234. long iwchLastTemp;
  235. long iwchAfterStartSpaces;
  236. long itxtobjAfterStartSpaces;
  237. long durCompressTotal;
  238. BOOL fHangingPunct;
  239. BOOL fChangeBackLastChar;
  240. long ibrkinf;
  241. BREAKINFO* pbrkinf = NULL;
  242. BOOL fFirstOnLineAfter;
  243. long durCompLastRight;
  244. long durCompLastLeft;
  245. long durChangeComp;
  246. BOOL fCancelHangingPunct;
  247. MWCLS mwclsLast;
  248. LSCP cpLim;
  249. LSCP cpLastAdjustable;
  250. LSDCP dcp;
  251. *pfCanCompress = fFalse;
  252. *pfActualCompress = fTrue;
  253. clschnk = (long)plsgrchnk->clsgrchnk;
  254. if (clschnk == 0)
  255. {
  256. *pfCanCompress = (durToCompress <=0 );
  257. *pfActualCompress = fFalse;
  258. return lserrNone;
  259. }
  260. Assert(clschnk > 0);
  261. pilsobj = ((PTXTOBJ)plsgrchnk->plschnk[clschnk-1].pdobj)->plnobj->pilsobj;
  262. itxtobjLast = pposichnkBeforeTrailing->ichnk;
  263. dcp = pposichnkBeforeTrailing->dcp;
  264. Assert(itxtobjLast >= 0);
  265. Assert(itxtobjLast < clschnk || (itxtobjLast == clschnk && dcp == 0));
  266. if (dcp == 0 && itxtobjLast > 0)
  267. {
  268. itxtobjLast--;
  269. dcp = plsgrchnk->plschnk[itxtobjLast].dcp;
  270. }
  271. ptxtobjLast = (PTXTOBJ)plsgrchnk->plschnk[itxtobjLast].pdobj;
  272. if (ptxtobjLast->iwchLim > ptxtobjLast->iwchFirst)
  273. iwchLast = ptxtobjLast->iwchFirst + dcp - 1;
  274. else
  275. iwchLast = ptxtobjLast->iwchLim - 1;
  276. Assert(iwchLast <= ptxtobjLast->iwchLim - 1);
  277. Assert(iwchLast >= ptxtobjLast->iwchFirst - 1);
  278. GetFirstPosAfterStartSpaces(plsgrchnk, itxtobjLast, iwchLast + 1,
  279. &itxtobjAfterStartSpaces, &iwchAfterStartSpaces, &fFirstOnLineAfter);
  280. if (iwchAfterStartSpaces > iwchLast)
  281. {
  282. *pfCanCompress = (durToCompress <=0 );
  283. *pfActualCompress = fFalse;
  284. return lserrNone;
  285. }
  286. for(itxtobjFirstInLastTextChunk = clschnk; itxtobjFirstInLastTextChunk > 0 && !(plsgrchnk->pcont[itxtobjFirstInLastTextChunk - 1] & fcontNonTextAfter); itxtobjFirstInLastTextChunk--);
  287. fHangingPunct = fFalse;
  288. if ((pilsobj->grpf & fTxtHangingPunct) &&
  289. (itxtobjLast > itxtobjFirstInLastTextChunk ||
  290. itxtobjLast == itxtobjFirstInLastTextChunk && iwchLast >= ((PTXTOBJ)plsgrchnk->plschnk[itxtobjFirstInLastTextChunk].pdobj)->iwchFirst) &&
  291. !(ptxtobjLast->txtf & txtfGlyphBased))
  292. {
  293. lserr = (*pilsobj->plscbk->pfnFHangingPunct)(pilsobj->pols, plsgrchnk->plschnk[itxtobjLast].plsrun,
  294. (BYTE)pilsobj->ptxtinf[iwchLast].mwcls, pilsobj->pwchOrig[iwchLast], &fHangingPunct);
  295. if (lserr != lserrNone) return lserr;
  296. }
  297. /* Compression information should be collected under assumption that all chars have correct widths;
  298. Correct width of HangingPunct should be subtructed as well
  299. */
  300. iwchLastTemp = iwchLast;
  301. fChangeBackLastChar = fFalse;
  302. for (ibrkinf = 0; ibrkinf < (long)pilsobj->breakinfMac &&
  303. (pilsobj->pbreakinf[ibrkinf].pdobj != (PDOBJ)ptxtobjLast ||
  304. ((long)pilsobj->pbreakinf[ibrkinf].dcp != iwchLast + 1 - ptxtobjLast->iwchFirst &&
  305. ptxtobjLast->txtkind != txtkindNonReqHyphen && ptxtobjLast->txtkind != txtkindOptBreak));
  306. ibrkinf++);
  307. if (ibrkinf < (long)pilsobj->breakinfMac)
  308. {
  309. pbrkinf = &pilsobj->pbreakinf[ibrkinf];
  310. Assert(pbrkinf->brkt != brktHyphen);
  311. if (pbrkinf->brkt == brktNormal && pbrkinf->u.normal.durFix != 0)
  312. {
  313. /* Now manager makes correct calculation */
  314. // durToCompress += pbrkinf->u.normal.durFix;
  315. Assert(pilsobj->pdurRight[iwchLast] == - pbrkinf->u.normal.durFix);
  316. pilsobj->pdur[iwchLast] += pbrkinf->u.normal.durFix;
  317. pilsobj->pdurRight[iwchLast] = 0;
  318. fChangeBackLastChar = fTrue;
  319. }
  320. else if (pbrkinf->brkt == brktNonReq)
  321. {
  322. Assert(iwchLast + 1 == ptxtobjLast->iwchLim);
  323. /* Now manager makes correct calculation */
  324. // durToCompress += pbrkinf->u.nonreq.ddurTotal;
  325. fHangingPunct = fFalse; /* hanging punct does not make sence in this case */
  326. if (pbrkinf->u.nonreq.dwchYsr >= 1)
  327. {
  328. if (pbrkinf->u.nonreq.wchPrev != 0)
  329. {
  330. iwchLastTemp--;
  331. if (pbrkinf->u.nonreq.wchPrevPrev != 0)
  332. {
  333. iwchLastTemp--;
  334. }
  335. }
  336. }
  337. }
  338. }
  339. *pfActualCompress = (durToCompress > 0);
  340. if (fHangingPunct)
  341. {
  342. pilsobj->ptxtinf[iwchLast].fHangingPunct = fTrue;
  343. durToCompress -= pilsobj->pdur[iwchLast];
  344. iwchLastTemp--;
  345. }
  346. durCompressTotal = 0;
  347. if (!pilsobj->fSnapGrid)
  348. {
  349. lserr = FetchCompressInfo(plsgrchnk, fFirstOnLineAfter, lstflow,
  350. itxtobjAfterStartSpaces, iwchAfterStartSpaces, itxtobjLast, iwchLastTemp + 1,
  351. durToCompress, &durCompressTotal);
  352. if (lserr != lserrNone) return lserr;
  353. }
  354. /* Next piece is added to provide mechanism for the backword compatibility with Word */
  355. durCompLastRight = 0;
  356. durCompLastLeft = 0;
  357. if (!(((PTXTOBJ)(plsgrchnk->plschnk[itxtobjLast].pdobj))->txtf & txtfGlyphBased) &&
  358. !pilsobj->fSnapGrid)
  359. {
  360. GetCompLastCharInfo(pilsobj, iwchLast, &mwclsLast, &durCompLastRight, &durCompLastLeft);
  361. /* First 3 lines of the following condition mean:
  362. Is Last Significant Character On The Line Text?
  363. */
  364. if (itxtobjFirstInLastTextChunk < (long)clschnk &&
  365. (itxtobjLast > itxtobjFirstInLastTextChunk ||
  366. itxtobjLast == itxtobjFirstInLastTextChunk && iwchLast >= ((PTXTOBJ)plsgrchnk->plschnk[itxtobjFirstInLastTextChunk].pdobj)->iwchFirst) &&
  367. (durCompLastRight > 0 || durCompLastLeft > 0 || fHangingPunct))
  368. {
  369. cpLim = plsgrchnk->plschnk[clschnk-1].cpFirst + plsgrchnk->plschnk[clschnk-1].dcp;
  370. cpLastAdjustable = plsgrchnk->plschnk[itxtobjLast].cpFirst +
  371. iwchLast - ((PTXTOBJ)plsgrchnk->plschnk[itxtobjLast].pdobj)->iwchFirst;
  372. durChangeComp = 0;
  373. if (fHangingPunct)
  374. {
  375. lserr = (*pilsobj->plscbk->pfnFCancelHangingPunct)(pilsobj->pols, cpLim, cpLastAdjustable,
  376. pilsobj->pwchOrig[iwchLast], mwclsLast, &fCancelHangingPunct);
  377. if (lserr != lserrNone) return lserr;
  378. if (fCancelHangingPunct)
  379. {
  380. lserr = FetchCompressInfo(plsgrchnk, fFirstOnLineAfter, lstflow,
  381. itxtobjAfterStartSpaces, iwchAfterStartSpaces, itxtobjLast, iwchLast + 1,
  382. LONG_MAX, &durCompressTotal);
  383. if (lserr != lserrNone) return lserr;
  384. durToCompress += pilsobj->pdur[iwchLast];
  385. GetCompLastCharInfo(pilsobj, iwchLast, &mwclsLast, &durCompLastRight, &durCompLastLeft);
  386. if ((durCompLastRight + durCompLastLeft) > 0)
  387. {
  388. lserr = (*pilsobj->plscbk->pfnModifyCompAtLastChar)(pilsobj->pols, cpLim, cpLastAdjustable,
  389. pilsobj->pwchOrig[iwchLast], mwclsLast,
  390. durCompLastRight, durCompLastLeft, &durChangeComp);
  391. if (lserr != lserrNone) return lserr;
  392. }
  393. Assert(durChangeComp >= 0);
  394. Assert(durChangeComp == 0 || (durCompLastRight + durCompLastLeft) > 0);
  395. }
  396. }
  397. else
  398. {
  399. lserr = (*pilsobj->plscbk->pfnModifyCompAtLastChar)(pilsobj->pols, cpLim, cpLastAdjustable,
  400. pilsobj->pwchOrig[iwchLast], mwclsLast, durCompLastRight, durCompLastLeft, &durChangeComp);
  401. if (lserr != lserrNone) return lserr;
  402. Assert(durChangeComp >= 0);
  403. Assert(durChangeComp == 0 || (durCompLastRight + durCompLastLeft) > 0);
  404. }
  405. durCompressTotal -= durChangeComp;
  406. }
  407. /* End of the piece is added to provide mechanizm for the backword compatibility with Word */
  408. }
  409. /* Restore width changed before the call to FetchCompressInfo */
  410. if (fChangeBackLastChar)
  411. {
  412. pilsobj->pdur[iwchLast] -= pbrkinf->u.normal.durFix;
  413. pilsobj->pdurRight[iwchLast] = - pbrkinf->u.normal.durFix;
  414. }
  415. if (!pilsobj->fSnapGrid)
  416. *pfCanCompress = (durToCompress <= durCompressTotal);
  417. else
  418. *pfCanCompress = (fHangingPunct && durToCompress <= 0);
  419. *pdurNonSufficient = durToCompress - durCompressTotal;
  420. return lserrNone;
  421. }
  422. /* D I S T R I B U T E I N T E X T */
  423. /*----------------------------------------------------------------------------
  424. %%Function: DistributeInText
  425. %%Contact: sergeyge
  426. Distributes given amount in text chunk equally
  427. between all participating characters
  428. ----------------------------------------------------------------------------*/
  429. LSERR DistributeInText(const LSGRCHNK* plsgrchnk, LSTFLOW lstflow, DWORD cNonText,
  430. long durToDistribute, long* pdurNonTextObjects)
  431. {
  432. LSERR lserr;
  433. PILSOBJ pilsobj;
  434. DWORD clschnk;
  435. long* rgdur;
  436. long iFirst;
  437. long iLim;
  438. PTXTOBJ ptxtobj;
  439. long itxtobj;
  440. long i;
  441. long durTxtobj;
  442. OBJDIM objdim;
  443. Unreferenced(lstflow);
  444. clschnk = plsgrchnk->clsgrchnk;
  445. Assert(clschnk + cNonText > 0);
  446. if (clschnk == 0)
  447. {
  448. *pdurNonTextObjects = durToDistribute;
  449. return lserrNone;
  450. }
  451. pilsobj = ((PTXTOBJ)plsgrchnk->plschnk[0].pdobj)->plnobj->pilsobj;
  452. /* REVIEW sergeyge:Very ugly but still better than anything else?
  453. Problem case is latin Rubi---NTI was not called and so additional arrays were not allocated
  454. Original solution---scaling everything down---is not an option becuse than we lose all
  455. left sided changes in the Rubi subline for Japanese case
  456. */
  457. pilsobj->fNotSimpleText = fTrue;
  458. if (pilsobj->pdurRight == NULL)
  459. {
  460. pilsobj->pdurRight = (*pilsobj->plscbk->pfnNewPtr)(pilsobj->pols, sizeof(long) * pilsobj->wchMax );
  461. Assert (pilsobj->pdurLeft == NULL);
  462. Assert (pilsobj->ptxtinf == NULL);
  463. pilsobj->pdurLeft = (*pilsobj->plscbk->pfnNewPtr)(pilsobj->pols, sizeof(long) * pilsobj->wchMax );
  464. pilsobj->ptxtinf = (*pilsobj->plscbk->pfnNewPtr)(pilsobj->pols, sizeof(TXTINF) * pilsobj->wchMax );
  465. if (pilsobj->pdurRight == NULL || pilsobj->pdurLeft == NULL || pilsobj->ptxtinf == NULL)
  466. {
  467. return lserrOutOfMemory;
  468. }
  469. memset(pilsobj->pdurRight, 0, sizeof(long) * pilsobj->wchMax );
  470. memset(pilsobj->pdurLeft, 0, sizeof(long) * pilsobj->wchMax );
  471. memset(pilsobj->ptxtinf, 0, sizeof(TXTINF) * pilsobj->wchMax);
  472. }
  473. ApplyDistribution(plsgrchnk, cNonText, durToDistribute, pdurNonTextObjects);
  474. for (itxtobj = 0; itxtobj < (long)clschnk; itxtobj++)
  475. {
  476. ptxtobj = (PTXTOBJ)plsgrchnk->plschnk[itxtobj].pdobj;
  477. if (ptxtobj->txtf & txtfGlyphBased)
  478. {
  479. iFirst = ptxtobj->igindFirst;
  480. iLim = ptxtobj->igindLim;
  481. rgdur = pilsobj->pdurGind;
  482. }
  483. else
  484. {
  485. iFirst = ptxtobj->iwchFirst;
  486. iLim = ptxtobj->iwchLim;
  487. rgdur = pilsobj->pdur;
  488. }
  489. durTxtobj = 0;
  490. for (i = iFirst; i < iLim; i++)
  491. {
  492. durTxtobj += rgdur[i];
  493. }
  494. lserr = LsdnGetObjDim(pilsobj->plsc, ptxtobj->plsdnUpNode, &objdim);
  495. if (lserr != lserrNone) return lserr;
  496. objdim.dur = durTxtobj;
  497. lserr = LsdnResetObjDim(pilsobj->plsc, ptxtobj->plsdnUpNode, &objdim);
  498. if (lserr != lserrNone) return lserr;
  499. }
  500. return lserrNone;
  501. }
  502. /* G E T T R A I L I N F O T E X T */
  503. /*----------------------------------------------------------------------------
  504. %%Function: GetTrailInfoText
  505. %%Contact: sergeyge
  506. Calculates number of spaces at the end of dobj (assuming that it ends at dcp)
  507. and the width of the trailing area
  508. ----------------------------------------------------------------------------*/
  509. void GetTrailInfoText(PDOBJ pdobj, LSDCP dcp, DWORD* pcNumOfTrailSpaces, long* pdurTrailing)
  510. {
  511. PILSOBJ pilsobj;
  512. PTXTOBJ ptxtobj;
  513. long iwch;
  514. Assert(dcp > 0);
  515. ptxtobj = (PTXTOBJ)pdobj;
  516. pilsobj = ptxtobj->plnobj->pilsobj;
  517. *pcNumOfTrailSpaces = 0;
  518. *pdurTrailing = 0;
  519. if (ptxtobj->txtkind == txtkindEOL)
  520. {
  521. Assert(dcp == 1);
  522. *pcNumOfTrailSpaces = 1;
  523. *pdurTrailing = ptxtobj->plnobj->pilsobj->pdur[ptxtobj->iwchFirst];
  524. }
  525. else if (!(pilsobj->grpf & fTxtWrapAllSpaces))
  526. {
  527. if (ptxtobj->txtkind == txtkindRegular)
  528. {
  529. Assert(ptxtobj->iwchLim >= ptxtobj->iwchFirst + (long)dcp);
  530. if (!(ptxtobj->txtf & txtfGlyphBased))
  531. {
  532. for (iwch = ptxtobj->iwchFirst + dcp - 1;
  533. iwch >= ptxtobj->iwchFirst && pilsobj->pwchOrig[iwch] == pilsobj->wchSpace; iwch--)
  534. {
  535. (*pcNumOfTrailSpaces)++;
  536. *pdurTrailing += pilsobj->pdur[iwch];
  537. }
  538. }
  539. else
  540. {
  541. long igindFirst = 0;
  542. long iwchFirst = 0;
  543. long igindLast;
  544. long igind;
  545. Assert(FIwchLastInContext(pilsobj, ptxtobj->iwchFirst + dcp - 1));
  546. igindLast = IgindLastFromIwch(ptxtobj, ptxtobj->iwchFirst + dcp - 1);
  547. for (iwch = ptxtobj->iwchFirst + dcp - 1;
  548. iwch >= ptxtobj->iwchFirst && pilsobj->pwchOrig[iwch] == pilsobj->wchSpace; iwch--);
  549. if (iwch < ptxtobj->iwchFirst)
  550. {
  551. iwchFirst = ptxtobj->iwchFirst;
  552. igindFirst = ptxtobj->igindFirst;
  553. }
  554. else
  555. {
  556. iwchFirst = IwchLastFromIwch(ptxtobj, iwch) + 1;
  557. igindFirst = IgindLastFromIwch(ptxtobj, iwch) + 1;
  558. }
  559. *pcNumOfTrailSpaces = ptxtobj->iwchFirst + dcp - iwchFirst;
  560. Assert(igindLast < ptxtobj->igindLim);
  561. for (igind = igindFirst; igind <= igindLast; igind++)
  562. *pdurTrailing += pilsobj->pdurGind[igind];
  563. }
  564. }
  565. else if (ptxtobj->txtkind == txtkindSpecSpace)
  566. {
  567. *pcNumOfTrailSpaces = dcp;
  568. *pdurTrailing = 0;
  569. for (iwch = ptxtobj->iwchFirst + dcp - 1; iwch >= ptxtobj->iwchFirst; iwch--)
  570. *pdurTrailing += pilsobj->pdur[iwch];
  571. }
  572. }
  573. }
  574. /* F S U S P E C T D E V I C E D I F F E R E N T */
  575. /*----------------------------------------------------------------------------
  576. %%Function: FSuspectDeviceDifferent
  577. %%Contact: sergeyge
  578. Returns TRUE if Visi character or NonReqHyphen-like character might be present
  579. on the line, and therefore fast prep-for-displaying is impossible in the case
  580. when fPresEqualRef is TRUE
  581. ----------------------------------------------------------------------------*/
  582. BOOL FSuspectDeviceDifferent(PLNOBJ plnobj)
  583. {
  584. return (plnobj->pilsobj->fDifficultForAdjust);
  585. }
  586. /* F Q U I C K S C A L I N G */
  587. /*----------------------------------------------------------------------------
  588. %%Function: FQuickScaling
  589. %%Contact: sergeyge
  590. Checks if fast scaling is possible in the case when fPresEqualRef is FALSE
  591. ----------------------------------------------------------------------------*/
  592. BOOL FQuickScaling(PLNOBJ plnobj, BOOL fVertical, long durTotal)
  593. {
  594. PILSOBJ pilsobj;
  595. long durMax;
  596. pilsobj = plnobj->pilsobj;
  597. durMax = pilsobj->durRightMaxX;
  598. if (fVertical)
  599. durMax = pilsobj->durRightMaxY;
  600. return (durTotal < durMax && !pilsobj->fDifficultForAdjust && plnobj->ptxtobjFirst == plnobj->ptxtobj);
  601. }
  602. #define UpFromUrFast(ur) ( ((ur) * MagicConstant + (1 << 20)) >> 21)
  603. /* Q U I C K A D J U S T E X A C T */
  604. /*----------------------------------------------------------------------------
  605. %%Function: AdjustText
  606. %%Contact: sergeyge
  607. Fast scaling: does not check for width restrictions and for Visi situations,
  608. assumes that there is only text on the line.
  609. ----------------------------------------------------------------------------*/
  610. void QuickAdjustExact(PDOBJ* rgpdobj, DWORD cdobj, DWORD cNumOfTrailSpaces, BOOL fVertical,
  611. long* pdupText, long* pdupTrail)
  612. {
  613. LSERR lserr;
  614. PILSOBJ pilsobj;
  615. PLNOBJ plnobj;
  616. PTXTOBJ ptxtobj;
  617. long* rgdur;
  618. long* rgdup;
  619. long durSum;
  620. long dupSum;
  621. long dupErrLast;
  622. long dupPrevChar;
  623. long MagicConstant;
  624. long dupIdeal;
  625. long dupReal;
  626. long dupErrNew;
  627. long dupAdjust;
  628. long wCarry;
  629. long iwchPrev;
  630. long iwch;
  631. long itxtobj;
  632. long dupTotal;
  633. Assert(cdobj > 0);
  634. plnobj = ((PTXTOBJ)rgpdobj[0])->plnobj;
  635. pilsobj = plnobj->pilsobj;
  636. Assert(!pilsobj->fDifficultForAdjust);
  637. rgdur = pilsobj->pdur;
  638. rgdup = plnobj->pdup;
  639. if (fVertical)
  640. MagicConstant = pilsobj->MagicConstantY;
  641. else
  642. MagicConstant = pilsobj->MagicConstantX;
  643. itxtobj = 0;
  644. durSum = 0;
  645. dupPrevChar = 0;
  646. /* Pretty dirty; we make sure that for the first iteration dupAdjust will be 0 */
  647. iwchPrev = ((PTXTOBJ)rgpdobj[0])->iwchFirst;
  648. dupErrLast = rgdup[iwchPrev] - UpFromUrFast(rgdur[iwchPrev]);
  649. dupSum = 0;
  650. for(itxtobj = 0; itxtobj < (long)cdobj; itxtobj++)
  651. {
  652. ptxtobj = (PTXTOBJ) rgpdobj[itxtobj];
  653. Assert(ptxtobj->txtkind != txtkindTab);
  654. Assert(!(ptxtobj->txtf & txtfGlyphBased));
  655. for(iwch = ptxtobj->iwchFirst; iwch < ptxtobj->iwchLim; iwch++)
  656. {
  657. durSum += rgdur[iwch];
  658. /* here David Bangs algorithm starts */
  659. dupIdeal = UpFromUrFast(durSum) - dupSum;
  660. Assert(dupIdeal >= 0);
  661. dupReal = rgdup[iwch];
  662. dupErrNew = dupReal - dupIdeal;
  663. dupAdjust = dupErrNew - dupErrLast;
  664. Assert(iwch > ((PTXTOBJ)rgpdobj[0])->iwchFirst || dupAdjust == 0);
  665. if (dupAdjust != 0)
  666. {
  667. wCarry = dupAdjust & 1;
  668. if (dupAdjust > 0)
  669. {
  670. dupAdjust >>= 1;
  671. if (dupErrLast < -dupErrNew)
  672. dupAdjust += wCarry;
  673. dupAdjust = min(dupPrevChar /*-1*/, dupAdjust);
  674. }
  675. else
  676. {
  677. dupAdjust >>= 1;
  678. if (dupErrNew < -dupErrLast)
  679. dupAdjust += wCarry;
  680. dupAdjust = max(/*1*/ - dupIdeal, dupAdjust);
  681. }
  682. rgdup[iwchPrev] -= dupAdjust;
  683. dupIdeal += dupAdjust;
  684. }
  685. rgdup[iwch] = dupIdeal;
  686. dupSum += (dupIdeal - dupAdjust);
  687. dupErrLast = dupReal - dupIdeal;
  688. iwchPrev = iwch;
  689. dupPrevChar = dupIdeal;
  690. /* here David Bangs algorithm stops */
  691. }
  692. }
  693. *pdupText = 0;
  694. *pdupTrail = 0;
  695. for (itxtobj=0; itxtobj < (long)cdobj - 1; itxtobj++)
  696. {
  697. ptxtobj = (PTXTOBJ) rgpdobj[itxtobj];
  698. dupTotal = 0;
  699. for(iwch = ptxtobj->iwchFirst; iwch < ptxtobj->iwchLim; iwch++)
  700. dupTotal += rgdup[iwch];
  701. *pdupText += dupTotal;
  702. lserr = LsdnSetTextDup(plnobj->pilsobj->plsc, ptxtobj->plsdnUpNode, dupTotal);
  703. Assert(lserr == lserrNone);
  704. }
  705. Assert(itxtobj == (long)cdobj - 1);
  706. ptxtobj = (PTXTOBJ) rgpdobj[itxtobj];
  707. Assert(ptxtobj->txtkind == txtkindEOL && cNumOfTrailSpaces == 1||
  708. ptxtobj->iwchLim - ptxtobj->iwchFirst > (long)cNumOfTrailSpaces);
  709. dupTotal = 0;
  710. for (iwch = ptxtobj->iwchLim - 1; iwch > ptxtobj->iwchLim - (long)cNumOfTrailSpaces - 1; iwch--)
  711. {
  712. dupTotal += rgdup[iwch];
  713. *pdupTrail += rgdup[iwch];
  714. }
  715. Assert(iwch == ptxtobj->iwchLim - (long)cNumOfTrailSpaces - 1);
  716. for (; iwch >= ptxtobj->iwchFirst; iwch--)
  717. {
  718. dupTotal += rgdup[iwch];
  719. }
  720. *pdupText += dupTotal;
  721. lserr = LsdnSetTextDup(plnobj->pilsobj->plsc, ptxtobj->plsdnUpNode, dupTotal);
  722. Assert(lserr == lserrNone);
  723. return;
  724. }
  725. /* Internal functions implementation */
  726. /* G E T F I R S T P O S A F T E R S T A R T S P A C E S */
  727. /*----------------------------------------------------------------------------
  728. %%Function: GetFirstPosAfterStartSpaces
  729. %%Contact: sergeyge
  730. Reports index of the first char after leading spaces
  731. ----------------------------------------------------------------------------*/
  732. static void GetFirstPosAfterStartSpaces(const LSGRCHNK* plsgrchnk, long itxtobjLast, long iwchLim,
  733. long* pitxtobjAfterStartSpaces, long* piwchAfterStartSpaces, BOOL* pfFirstOnLineAfter)
  734. {
  735. PILSOBJ pilsobj;
  736. PLNOBJ plnobj;
  737. long iwch;
  738. BOOL fInStartSpace;
  739. long itxtobj;
  740. PTXTOBJ ptxtobj;
  741. long iwchLimInDobj;
  742. PLSCHNK rglschnk;
  743. Assert(plsgrchnk->clsgrchnk > 0);
  744. rglschnk = plsgrchnk->plschnk;
  745. plnobj = ((PTXTOBJ)rglschnk[0].pdobj)->plnobj;
  746. pilsobj = plnobj->pilsobj;
  747. itxtobj = 0;
  748. ptxtobj = (PTXTOBJ)rglschnk[0].pdobj;
  749. iwch = 0;
  750. *pitxtobjAfterStartSpaces = 0;
  751. *piwchAfterStartSpaces = ptxtobj->iwchFirst;
  752. *pfFirstOnLineAfter = !(plsgrchnk->pcont[0] & fcontNonTextBefore);
  753. fInStartSpace = *pfFirstOnLineAfter;
  754. while (fInStartSpace && itxtobj <= itxtobjLast)
  755. {
  756. ptxtobj = (PTXTOBJ)rglschnk[itxtobj].pdobj;
  757. iwchLimInDobj = iwchLim;
  758. if (itxtobj < itxtobjLast)
  759. iwchLimInDobj = ptxtobj->iwchLim;
  760. if (plsgrchnk->pcont[itxtobj] & fcontNonTextBefore)
  761. {
  762. *pfFirstOnLineAfter = fFalse;
  763. *pitxtobjAfterStartSpaces = itxtobj;
  764. *piwchAfterStartSpaces = ptxtobj->iwchFirst;
  765. fInStartSpace = fFalse;
  766. }
  767. else if (ptxtobj->txtkind == txtkindRegular)
  768. {
  769. for (iwch = ptxtobj->iwchFirst; iwch < iwchLimInDobj &&
  770. pilsobj->pwchOrig[iwch] == pilsobj->wchSpace; iwch++);
  771. if ((ptxtobj->txtf & txtfGlyphBased) && iwch < iwchLimInDobj)
  772. {
  773. for(; !FIwchFirstInContext(pilsobj, iwch); iwch--);
  774. Assert(iwch >= ptxtobj->iwchFirst);
  775. }
  776. if (iwch < iwchLimInDobj)
  777. {
  778. *pitxtobjAfterStartSpaces = itxtobj;
  779. *piwchAfterStartSpaces = iwch;
  780. fInStartSpace = fFalse;
  781. }
  782. }
  783. /* REVIEW: sergeyge---should something be changed in the following check? */
  784. else if (ptxtobj->txtkind != txtkindEOL
  785. // && ptxtobj->txtkind != txtkindSpecSpace
  786. )
  787. {
  788. *pitxtobjAfterStartSpaces = itxtobj;
  789. *piwchAfterStartSpaces = ptxtobj->iwchFirst;
  790. fInStartSpace = fFalse;
  791. }
  792. itxtobj++;
  793. iwch = iwchLimInDobj;
  794. }
  795. if (fInStartSpace)
  796. {
  797. *pitxtobjAfterStartSpaces = itxtobj;
  798. *piwchAfterStartSpaces = iwchLim;
  799. }
  800. return;
  801. }
  802. /* H A N D L E S I M P L E T E X T W Y S I */
  803. /*----------------------------------------------------------------------------
  804. %%Function: HandleSimpleTextWysi
  805. %%Contact: sergeyge
  806. Implements Latin-like justification in spaces (if needed)
  807. on the reference device and WYSIWYG algorithm for the exact positioning
  808. under assumption that there were no NominalToIdeal modifications
  809. (except for Latin kerning) on the line.
  810. Startegy:
  811. Distribute in spaces if needed
  812. Scale down width of spaces from the reference device to the presentation one
  813. Apply WYSIWYG algorithm
  814. ----------------------------------------------------------------------------*/
  815. static LSERR HandleSimpleTextWysi(LSKJUST lskjust, const LSGRCHNK* plsgrchnk, long durToDistribute,
  816. long dupAvailable, LSTFLOW lstflow, long itxtobjAfterStartSpaces, long iwchAfterStartSpaces,
  817. long itxtobjLast, long iwchLast, BOOL fExactSync, BOOL fForcedBreak, BOOL fSuppressTrailingSpaces,
  818. long* pdupText, long* pdupTail)
  819. {
  820. PTXTOBJ ptxtobj;
  821. BOOL fFullyJustified;
  822. fFullyJustified = fFalse;
  823. if (itxtobjLast > itxtobjAfterStartSpaces || (itxtobjLast == itxtobjAfterStartSpaces && iwchLast >= iwchAfterStartSpaces))
  824. {
  825. ptxtobj = (PTXTOBJ)plsgrchnk->plschnk[0].pdobj;
  826. if (lskjust != lskjNone && durToDistribute > 0)
  827. {
  828. FullPositiveSpaceJustification(plsgrchnk, itxtobjAfterStartSpaces, iwchAfterStartSpaces,
  829. itxtobjLast, iwchLast, ptxtobj->plnobj->pilsobj->pdur, NULL,
  830. durToDistribute, &fFullyJustified);
  831. ScaleSpaces(plsgrchnk, lstflow, itxtobjLast, iwchLast);
  832. }
  833. else if (!fForcedBreak && durToDistribute < 0)
  834. {
  835. fFullyJustified = fTrue;
  836. NegativeSpaceJustification(plsgrchnk, itxtobjAfterStartSpaces, iwchAfterStartSpaces,
  837. itxtobjLast, iwchLast, ptxtobj->plnobj->pilsobj->pdur, NULL,
  838. -durToDistribute);
  839. ScaleSpaces(plsgrchnk, lstflow, itxtobjLast, iwchLast);
  840. }
  841. }
  842. Unreferenced(fExactSync);
  843. /* if (fExactSync)*/
  844. ApplyWysi(plsgrchnk, lstflow);
  845. /* else
  846. ApplyNonExactWysi(plsgrchnk, lstflow);
  847. */
  848. return FinalAdjustmentOnPres(plsgrchnk, itxtobjLast, iwchLast, dupAvailable,
  849. fFullyJustified, fForcedBreak, fSuppressTrailingSpaces,
  850. pdupText, pdupTail);
  851. }
  852. /* H A N D L E S I M P L E T E X T P R E S */
  853. /*----------------------------------------------------------------------------
  854. %%Function: HandleSimpleTextPres
  855. %%Contact: sergeyge
  856. Implements Latin-like justification in spaces (if needed)
  857. on the presentation device
  858. under assumption that there were no NominalToIdeal modifications
  859. (except for Latin kerning) on the line.
  860. ----------------------------------------------------------------------------*/
  861. static LSERR HandleSimpleTextPres(LSKJUST lskjust, const LSGRCHNK* plsgrchnk,
  862. long dupAvailable, long itxtobjAfterStartSpaces, long iwchAfterStartSpaces,
  863. long itxtobjLast, long iwchLast, BOOL fForcedBreak, BOOL fSuppressTrailingSpaces,
  864. long* pdupText, long* pdupTail)
  865. {
  866. PTXTOBJ ptxtobj;
  867. BOOL fFullyJustified;
  868. long* rgdup;
  869. long itxtobj;
  870. long iwchLim;
  871. long iwch;
  872. long dupTotal;
  873. long dupToDistribute;
  874. if (itxtobjLast > itxtobjAfterStartSpaces || (itxtobjLast == itxtobjAfterStartSpaces && iwchLast >= iwchAfterStartSpaces))
  875. {
  876. ptxtobj = (PTXTOBJ)plsgrchnk->plschnk[0].pdobj;
  877. rgdup = ptxtobj->plnobj->pdup;
  878. dupTotal = 0;
  879. /* REVIEW sergeyge: should we think about eliminating this loop for online view? */
  880. for (itxtobj=0; itxtobj <= itxtobjLast; itxtobj++)
  881. {
  882. ptxtobj = (PTXTOBJ)plsgrchnk->plschnk[itxtobj].pdobj;
  883. iwchLim = iwchLast + 1;
  884. if (itxtobj < itxtobjLast)
  885. iwchLim = ptxtobj->iwchLim;
  886. for (iwch = ptxtobj->iwchFirst; iwch < iwchLim; iwch++)
  887. {
  888. dupTotal += rgdup[iwch];
  889. }
  890. }
  891. dupToDistribute = dupAvailable - dupTotal;
  892. if (lskjust != lskjNone && dupToDistribute > 0)
  893. {
  894. FullPositiveSpaceJustification(plsgrchnk, itxtobjAfterStartSpaces, iwchAfterStartSpaces,
  895. itxtobjLast, iwchLast, rgdup, NULL,
  896. dupToDistribute, &fFullyJustified);
  897. }
  898. else if (!fForcedBreak && dupToDistribute < 0)
  899. {
  900. NegativeSpaceJustification(plsgrchnk, itxtobjAfterStartSpaces, iwchAfterStartSpaces,
  901. itxtobjLast, iwchLast, rgdup, NULL,
  902. -dupToDistribute);
  903. }
  904. }
  905. return FinalAdjustmentOnPres(plsgrchnk, itxtobjLast, iwchLast, dupAvailable,
  906. fFalse, fForcedBreak, fSuppressTrailingSpaces,
  907. pdupText, pdupTail);
  908. }
  909. /* H A N D L E G E N E R A L S P A C E S E X A C T S Y N C */
  910. /*----------------------------------------------------------------------------
  911. %%Function: HandleGeneralSpacesExactSync
  912. %%Contact: sergeyge
  913. Implements Latin-like justification in spaces (if needed)
  914. on the reference device and WYSIWYG algorithm for the exact positioning
  915. in the general case
  916. Startegy:
  917. Distribute in spaces if needed
  918. Scale down changes applied to characters during NTI and distribution
  919. If glyphs were detected on the line,
  920. scale down changes apllied to glyphs during NTI
  921. and adjust offsets
  922. Apply WYSIWYG algorithm
  923. If some characters were changed on the left side
  924. prepare additional width array for the display time
  925. ----------------------------------------------------------------------------*/
  926. static LSERR HandleGeneralSpacesExactSync(LSKJUST lskjust, const LSGRCHNK* plsgrchnk, long durToDistribute,
  927. long dupAvailable, LSTFLOW lstflow, long itxtobjAfterStartSpaces, long iwchAfterStartSpaces,
  928. long itxtobjLast, long iwchLast, BOOL fForcedBreak, BOOL fSuppressTrailingSpaces,
  929. long* pdupText, long* pdupTail)
  930. {
  931. LSERR lserr;
  932. PLNOBJ plnobj;
  933. PILSOBJ pilsobj;
  934. PTXTOBJ ptxtobj;
  935. BOOL fFullyJustified = fFalse;
  936. BOOL fLeftSideAffected = fFalse;
  937. BOOL fGlyphDetected = fFalse;
  938. plnobj = ((PTXTOBJ) plsgrchnk->plschnk[0].pdobj)->plnobj;
  939. pilsobj = plnobj->pilsobj;
  940. if (itxtobjLast > itxtobjAfterStartSpaces || (itxtobjLast == itxtobjAfterStartSpaces && iwchLast >= iwchAfterStartSpaces))
  941. {
  942. ptxtobj = (PTXTOBJ)plsgrchnk->plschnk[0].pdobj;
  943. if (lskjust != lskjNone && durToDistribute > 0)
  944. {
  945. FullPositiveSpaceJustification(plsgrchnk, itxtobjAfterStartSpaces, iwchAfterStartSpaces,
  946. itxtobjLast, iwchLast, pilsobj->pdur, pilsobj->pdurGind,
  947. durToDistribute, &fFullyJustified);
  948. }
  949. else if (!fForcedBreak && durToDistribute < 0)
  950. {
  951. fFullyJustified = fTrue;
  952. NegativeSpaceJustification(plsgrchnk, itxtobjAfterStartSpaces, iwchAfterStartSpaces,
  953. itxtobjLast, iwchLast, pilsobj->pdur, pilsobj->pdurGind,
  954. -durToDistribute);
  955. }
  956. }
  957. ScaleCharSides(plsgrchnk, lstflow, &fLeftSideAffected, &fGlyphDetected);
  958. if (fGlyphDetected)
  959. {
  960. ScaleGlyphSides(plsgrchnk, lstflow);
  961. UpdateGlyphOffsets(plsgrchnk);
  962. SetBeforeJustCopy(plsgrchnk);
  963. }
  964. ApplyWysi(plsgrchnk, lstflow);
  965. lserr = FinalAdjustmentOnPres(plsgrchnk, itxtobjLast, iwchLast, dupAvailable,
  966. fFullyJustified, fForcedBreak, fSuppressTrailingSpaces,
  967. pdupText, pdupTail);
  968. if (lserr != lserrNone) return lserr;
  969. /* If pdupPen is already used, don't forget to copy pdup there---ScaleSides could change it */
  970. if (fLeftSideAffected || plnobj->pdup != plnobj->pdupPen)
  971. {
  972. lserr = FillDupPen(plsgrchnk, lstflow, itxtobjLast, iwchLast);
  973. if (lserr != lserrNone) return lserr;
  974. }
  975. return lserrNone;
  976. }
  977. /* H A N D L E G E N E R A L S P A C E S P R E S */
  978. /*----------------------------------------------------------------------------
  979. %%Function: HandleGeneralSpacesPres
  980. %%Contact: sergeyge
  981. Implements Latin-like justification in spaces (if needed)
  982. directly on the presentation device in the general case
  983. Startegy:
  984. Scale down changes applied to characters during NTI
  985. If glyphs were detected on the line,
  986. scale down changes apllied to glyphs during NTI
  987. and adjust glyph offsets
  988. Distribute in spaces if needed
  989. If glyphs were detected on the line,
  990. adjust glyph offsets
  991. If some characters were changed on the left side
  992. prepare additional width array for the display time
  993. ----------------------------------------------------------------------------*/
  994. static LSERR HandleGeneralSpacesPres(LSKJUST lskjust, const LSGRCHNK* plsgrchnk, long dupAvailable,
  995. LSTFLOW lstflow, long itxtobjAfterStartSpaces, long iwchAfterStartSpaces,
  996. long itxtobjLast, long iwchLast, BOOL fForcedBreak, BOOL fSuppressTrailingSpaces,
  997. long* pdupText, long* pdupTail)
  998. {
  999. LSERR lserr;
  1000. PLNOBJ plnobj;
  1001. PTXTOBJ ptxtobj;
  1002. PTXTOBJ ptxtobjLast;
  1003. long* rgdup;
  1004. BOOL fFullyJustified;
  1005. long itxtobj;
  1006. long iwchLastInDobj;
  1007. long iFirst;
  1008. long iLim;
  1009. long i;
  1010. long dupTotal;
  1011. long dupToDistribute;
  1012. BOOL fLeftSideAffected = fFalse;
  1013. BOOL fGlyphDetected = fFalse;
  1014. ptxtobjLast = (PTXTOBJ)plsgrchnk->plschnk[max(0, itxtobjLast)].pdobj;
  1015. plnobj = ptxtobjLast->plnobj;
  1016. ScaleCharSides(plsgrchnk, lstflow, &fLeftSideAffected, &fGlyphDetected);
  1017. if (fGlyphDetected)
  1018. {
  1019. ScaleGlyphSides(plsgrchnk, lstflow);
  1020. UpdateGlyphOffsets(plsgrchnk);
  1021. SetBeforeJustCopy(plsgrchnk);
  1022. }
  1023. if (itxtobjLast > itxtobjAfterStartSpaces || (itxtobjLast == itxtobjAfterStartSpaces && iwchLast >= iwchAfterStartSpaces))
  1024. {
  1025. ptxtobj = (PTXTOBJ)plsgrchnk->plschnk[0].pdobj;
  1026. dupTotal = 0;
  1027. for (itxtobj=0; itxtobj <= itxtobjLast; itxtobj++)
  1028. {
  1029. ptxtobj = (PTXTOBJ)plsgrchnk->plschnk[itxtobj].pdobj;
  1030. if (ptxtobj->txtf & txtfGlyphBased)
  1031. {
  1032. iFirst = ptxtobj->igindFirst;
  1033. iwchLastInDobj = iwchLast;
  1034. if (itxtobj < itxtobjLast)
  1035. iwchLastInDobj = ptxtobj->iwchLim - 1;
  1036. iLim = IgindLastFromIwch(ptxtobj, iwchLastInDobj) + 1;
  1037. rgdup = plnobj->pdupGind;
  1038. }
  1039. else
  1040. {
  1041. iFirst = ptxtobj->iwchFirst;
  1042. iLim = iwchLast + 1;
  1043. if (itxtobj < itxtobjLast)
  1044. iLim = ptxtobj->iwchLim;
  1045. rgdup = plnobj->pdup;
  1046. }
  1047. for (i =iFirst; i < iLim; i++)
  1048. {
  1049. dupTotal += rgdup[i];
  1050. }
  1051. }
  1052. dupToDistribute = dupAvailable - dupTotal;
  1053. if (lskjust != lskjNone && dupToDistribute > 0)
  1054. {
  1055. FullPositiveSpaceJustification(plsgrchnk, itxtobjAfterStartSpaces, iwchAfterStartSpaces,
  1056. itxtobjLast, iwchLast, plnobj->pdup, plnobj->pdupGind,
  1057. dupToDistribute, &fFullyJustified);
  1058. }
  1059. else if (!fForcedBreak && dupToDistribute < 0)
  1060. {
  1061. NegativeSpaceJustification(plsgrchnk, itxtobjAfterStartSpaces, iwchAfterStartSpaces,
  1062. itxtobjLast, iwchLast, plnobj->pdup, plnobj->pdupGind,
  1063. -dupToDistribute);
  1064. }
  1065. if (fGlyphDetected)
  1066. {
  1067. UpdateGlyphOffsets(plsgrchnk);
  1068. }
  1069. }
  1070. lserr = FinalAdjustmentOnPres(plsgrchnk, itxtobjLast, iwchLast, dupAvailable,
  1071. fFalse, fForcedBreak, fSuppressTrailingSpaces,
  1072. pdupText, pdupTail);
  1073. if (lserr != lserrNone) return lserr;
  1074. /* If pdupPen is already used, don't forget to copy pdup there---ScaleSides could change it */
  1075. if (fLeftSideAffected || plnobj->pdup != plnobj->pdupPen)
  1076. {
  1077. lserr = FillDupPen(plsgrchnk, lstflow, itxtobjLast, iwchLast);
  1078. if (lserr != lserrNone) return lserr;
  1079. }
  1080. return lserrNone;
  1081. }
  1082. /* H A N D L E T A B L E B A S E D */
  1083. /*----------------------------------------------------------------------------
  1084. %%Function: HandleTableBased
  1085. %%Contact: sergeyge
  1086. Implements FE-like justification or compression
  1087. on the reference device and WYSIWYG algorithm for the exact positioning
  1088. Startegy:
  1089. Apply needed type of justification or compression
  1090. Scale down changes applied to characters during NTI and justification
  1091. If glyphs were detected on the line,
  1092. scale down changes apllied to glyphs during NTI
  1093. and adjust offsets
  1094. Apply WYSIWYG algorithm
  1095. If some characters were changed on the left side
  1096. prepare additional width array for the display time
  1097. ----------------------------------------------------------------------------*/
  1098. static LSERR HandleTablesBased(LSKJUST lskjust, const LSGRCHNK* plsgrchnk,
  1099. long durToDistribute, long dupAvailable, LSTFLOW lstflow,
  1100. long itxtobjAfterStartSpaces, long iwchAfterStartSpaces, BOOL fFirstOnLineAfter,
  1101. long itxtobjLast, long iwchLast, long cNonText, BOOL fLastObjectIsText,
  1102. BOOL fForcedBreak, BOOL fSuppressTrailingSpaces,
  1103. long* pdupText, long* pdupTail, long* pdupExtNonText)
  1104. {
  1105. LSERR lserr;
  1106. PILSOBJ pilsobj = NULL;
  1107. PLNOBJ plnobj;
  1108. long durExtNonText = 0;
  1109. DWORD clschnk;
  1110. MWCLS mwclsLast;
  1111. long durCompLastLeft = 0;
  1112. long durCompLastRight = 0;
  1113. long durHangingChar;
  1114. long dupHangingChar = 0;
  1115. BOOL fHangingUsed = fFalse;
  1116. long durCompressTotal;
  1117. long iwchLastTemp;
  1118. BOOL fScaledExp;
  1119. BOOL fFullyJustified = fFalse;
  1120. BOOL fLeftSideAffected = fFalse;
  1121. BOOL fGlyphDetected = fFalse;
  1122. Assert(lskjust == lskjFullInterLetterAligned ||
  1123. lskjust == lskjFullScaled ||
  1124. lskjust == lskjNone);
  1125. *pdupExtNonText = 0;
  1126. clschnk = plsgrchnk->clsgrchnk;
  1127. Assert(clschnk > 0);
  1128. plnobj = ((PTXTOBJ) plsgrchnk->plschnk[0].pdobj)->plnobj;
  1129. pilsobj = plnobj->pilsobj;
  1130. if (itxtobjLast > itxtobjAfterStartSpaces || (itxtobjLast == itxtobjAfterStartSpaces && iwchLast >= iwchAfterStartSpaces))
  1131. {
  1132. Assert(clschnk > 0);
  1133. if (pilsobj->fSnapGrid)
  1134. {
  1135. if (durToDistribute < 0)
  1136. {
  1137. Assert(-durToDistribute <= pilsobj->pdur[iwchLast]);
  1138. fHangingUsed = fTrue;
  1139. }
  1140. }
  1141. else if (durToDistribute < 0)
  1142. {
  1143. fFullyJustified = fTrue;
  1144. lserr = FetchCompressInfo(plsgrchnk, fFirstOnLineAfter, lstflow,
  1145. itxtobjAfterStartSpaces, iwchAfterStartSpaces, itxtobjLast, iwchLast + 1,
  1146. LONG_MAX, &durCompressTotal);
  1147. if (lserr != lserrNone) return lserr;
  1148. if (fLastObjectIsText && !(((PTXTOBJ) plsgrchnk->plschnk[0].pdobj)->txtf & txtfGlyphBased))
  1149. GetCompLastCharInfo(pilsobj, iwchLast, &mwclsLast, &durCompLastRight, &durCompLastLeft);
  1150. if (pilsobj->ptxtinf[iwchLast].fHangingPunct)
  1151. {
  1152. Assert(lskjust == lskjNone || lskjust == lskjFullInterLetterAligned || lskjust == lskjFullScaled);
  1153. Assert(fLastObjectIsText);
  1154. if (durCompLastRight >= -durToDistribute)
  1155. {
  1156. Assert(durCompLastRight > 0);
  1157. CompressLastCharRight(pilsobj, iwchLast, durCompLastRight);
  1158. if (lskjust != lskjNone)
  1159. {
  1160. fScaledExp = (lskjust != lskjFullInterLetterAligned);
  1161. lserr = ApplyExpand(plsgrchnk, lstflow, fScaledExp,
  1162. itxtobjAfterStartSpaces, iwchAfterStartSpaces, itxtobjLast, iwchLast, cNonText,
  1163. durCompLastRight + durToDistribute, &durExtNonText, &fFullyJustified);
  1164. if (lserr != lserrNone) return lserr;
  1165. }
  1166. }
  1167. else if (durCompressTotal - durCompLastRight >= -durToDistribute)
  1168. {
  1169. lserr = ApplyCompress(plsgrchnk, lstflow, itxtobjAfterStartSpaces, iwchAfterStartSpaces,
  1170. itxtobjLast, iwchLast, -durToDistribute);
  1171. if (lserr != lserrNone) return lserr;
  1172. }
  1173. else if (durCompressTotal >= -durToDistribute)
  1174. {
  1175. if (durCompLastRight > 0)
  1176. CompressLastCharRight(pilsobj, iwchLast, durCompLastRight);
  1177. lserr = ApplyCompress(plsgrchnk, lstflow, itxtobjAfterStartSpaces, iwchAfterStartSpaces,
  1178. itxtobjLast, iwchLast + 1, -durToDistribute - durCompLastRight);
  1179. if (lserr != lserrNone) return lserr;
  1180. }
  1181. else
  1182. {
  1183. durHangingChar = pilsobj->pdur[iwchLast];
  1184. /* Order of operations is important here because dur of the hanging
  1185. punctuation gets chnaged in the next lines of code and
  1186. durHangingChar is used in ApplyCompress/ApplyExpand calls below!!!
  1187. */
  1188. if (durCompLastRight > 0)
  1189. CompressLastCharRight(pilsobj, iwchLast, durCompLastRight);
  1190. fHangingUsed = fTrue;
  1191. if (durHangingChar + durToDistribute >= 0)
  1192. {
  1193. fScaledExp = (lskjust != lskjFullInterLetterAligned);
  1194. lserr = ApplyExpand(plsgrchnk, lstflow, fScaledExp,
  1195. itxtobjAfterStartSpaces, iwchAfterStartSpaces, itxtobjLast, iwchLast,
  1196. cNonText, durHangingChar + durToDistribute, &durExtNonText, &fFullyJustified);
  1197. if (lserr != lserrNone) return lserr;
  1198. }
  1199. else
  1200. {
  1201. lserr = ApplyCompress(plsgrchnk, lstflow,
  1202. itxtobjAfterStartSpaces, iwchAfterStartSpaces, itxtobjLast, iwchLast,
  1203. -durToDistribute - durHangingChar);
  1204. if (lserr != lserrNone) return lserr;
  1205. }
  1206. }
  1207. }
  1208. else
  1209. {
  1210. if (durCompLastRight >= -durToDistribute)
  1211. {
  1212. Assert(!(((PTXTOBJ) plsgrchnk->plschnk[0].pdobj)->txtf & txtfGlyphBased));
  1213. CompressLastCharRight(pilsobj, iwchLast, -durToDistribute);
  1214. }
  1215. else
  1216. {
  1217. if (durCompLastRight > 0)
  1218. {
  1219. Assert(!(((PTXTOBJ) plsgrchnk->plschnk[0].pdobj)->txtf & txtfGlyphBased));
  1220. CompressLastCharRight(pilsobj, iwchLast, durCompLastRight);
  1221. }
  1222. lserr = ApplyCompress(plsgrchnk, lstflow, itxtobjAfterStartSpaces, iwchAfterStartSpaces,
  1223. itxtobjLast, iwchLast + 1, -durToDistribute - durCompLastRight);
  1224. if (lserr != lserrNone) return lserr;
  1225. }
  1226. }
  1227. }
  1228. else
  1229. {
  1230. /* Assert (durToDistribute >= 0 || iwchLast == iwchAfterStartSpaces);---Unfortunately it might be not true
  1231. for the second line of Warichu, because durTotal for it is scaled up value of dup of the first line
  1232. */
  1233. if (lskjust != lskjNone && durToDistribute > 0)
  1234. {
  1235. Assert(lskjust == lskjFullScaled || lskjust == lskjFullInterLetterAligned);
  1236. iwchLastTemp = iwchLast;
  1237. if (!fLastObjectIsText)
  1238. iwchLastTemp++;
  1239. lserr = ApplyExpand(plsgrchnk, lstflow, lskjust == lskjFullScaled,
  1240. itxtobjAfterStartSpaces, iwchAfterStartSpaces, itxtobjLast, iwchLastTemp,
  1241. cNonText, durToDistribute, &durExtNonText, &fFullyJustified);
  1242. if (lserr != lserrNone) return lserr;
  1243. }
  1244. }
  1245. }
  1246. else if (cNonText != 0 && lskjust != lskjNone && durToDistribute > 0)
  1247. {
  1248. durExtNonText = durToDistribute;
  1249. }
  1250. ScaleExtNonText(pilsobj, lstflow, durExtNonText, pdupExtNonText);
  1251. ScaleCharSides(plsgrchnk, lstflow, &fLeftSideAffected, &fGlyphDetected);
  1252. if (fGlyphDetected)
  1253. {
  1254. ScaleGlyphSides(plsgrchnk, lstflow);
  1255. UpdateGlyphOffsets(plsgrchnk);
  1256. SetBeforeJustCopy(plsgrchnk);
  1257. }
  1258. ApplyWysi(plsgrchnk, lstflow);
  1259. if (fHangingUsed)
  1260. GetDupLastChar(plsgrchnk, iwchLast, &dupHangingChar);
  1261. lserr = FinalAdjustmentOnPres(plsgrchnk, itxtobjLast, iwchLast,
  1262. dupAvailable + dupHangingChar - *pdupExtNonText,
  1263. fFullyJustified, fForcedBreak, fSuppressTrailingSpaces,
  1264. pdupText, pdupTail);
  1265. if (lserr != lserrNone) return lserr;
  1266. /* If pdupPen is already used, don't forget to copy pdup there---ScaleSides could change it */
  1267. if (fLeftSideAffected || plnobj->pdup != plnobj->pdupPen)
  1268. {
  1269. lserr = FillDupPen(plsgrchnk, lstflow, itxtobjLast, iwchLast);
  1270. if (lserr != lserrNone) return lserr;
  1271. }
  1272. return lserrNone;
  1273. }
  1274. /* H A N D L E F U L L G L Y P H S E X A C T S Y N C */
  1275. /*----------------------------------------------------------------------------
  1276. %%Function: HandleFullGlyphsExactSync
  1277. %%Contact: sergeyge
  1278. Implements glyph-based justification
  1279. on the reference device and WYSIWYG algorithm
  1280. for the exact positioning
  1281. Startegy:
  1282. Apply glyph-based justification if needed
  1283. Scale down changes applied to characters during NTI and justification
  1284. If glyphs were detected on the line,
  1285. scale down changes apllied to glyphs during NTI
  1286. and adjust offsets
  1287. Apply WYSIWYG algorithm
  1288. If some characters were changed on the left side
  1289. prepare additional width array for the display time
  1290. ----------------------------------------------------------------------------*/
  1291. static LSERR HandleFullGlyphsExactSync(const LSGRCHNK* plsgrchnk,
  1292. long durToDistribute, long dupAvailable, LSTFLOW lstflow,
  1293. long itxtobjAfterStartSpaces, long iwchAfterStartSpaces,
  1294. long itxtobjLast, long iwchLast, BOOL fForcedBreak, BOOL fSuppressTrailingSpaces,
  1295. long* pdupText, long* pdupTail)
  1296. {
  1297. LSERR lserr;
  1298. PILSOBJ pilsobj;
  1299. PLNOBJ plnobj;
  1300. BOOL fFullyJustified = fFalse;
  1301. BOOL fLeftSideAffected = fFalse;
  1302. BOOL fGlyphDetected = fFalse;
  1303. plnobj = ((PTXTOBJ) plsgrchnk->plschnk[0].pdobj)->plnobj;
  1304. pilsobj = plnobj->pilsobj;
  1305. ScaleGlyphSides(plsgrchnk, lstflow);
  1306. UpdateGlyphOffsets(plsgrchnk);
  1307. SetBeforeJustCopy(plsgrchnk);
  1308. if (itxtobjLast > itxtobjAfterStartSpaces || (itxtobjLast == itxtobjAfterStartSpaces && iwchLast >= iwchAfterStartSpaces))
  1309. {
  1310. lserr = ApplyGlyphExpand(plsgrchnk, lstflow, lsdevReference,
  1311. itxtobjAfterStartSpaces, iwchAfterStartSpaces, itxtobjLast, iwchLast,
  1312. durToDistribute, pilsobj->pdur, pilsobj->pdurGind, pilsobj->pdurRight, pilsobj->pduGright,
  1313. &fFullyJustified);
  1314. if (lserr != lserrNone) return lserr;
  1315. }
  1316. ScaleCharSides(plsgrchnk, lstflow, &fLeftSideAffected, &fGlyphDetected);
  1317. if (fGlyphDetected)
  1318. {
  1319. ScaleGlyphSides(plsgrchnk, lstflow);
  1320. UpdateGlyphOffsets(plsgrchnk);
  1321. }
  1322. ApplyWysi(plsgrchnk, lstflow);
  1323. lserr = FinalAdjustmentOnPres(plsgrchnk, itxtobjLast, iwchLast, dupAvailable,
  1324. fFullyJustified, fForcedBreak, fSuppressTrailingSpaces,
  1325. pdupText, pdupTail);
  1326. if (lserr != lserrNone) return lserr;
  1327. /* If pdupPen is already used, don't forget to copy pdup there---ScaleSides could change it */
  1328. if (fLeftSideAffected || plnobj->pdup != plnobj->pdupPen)
  1329. {
  1330. lserr = FillDupPen(plsgrchnk, lstflow, itxtobjLast, iwchLast);
  1331. if (lserr != lserrNone) return lserr;
  1332. }
  1333. return lserrNone;
  1334. }
  1335. /* H A N D L E F U L L G L Y P H S P R E S */
  1336. /*----------------------------------------------------------------------------
  1337. %%Function: HandleFullGlyphsPres
  1338. %%Contact: sergeyge
  1339. Implements glyph-based justification
  1340. directly on the presentation device
  1341. Startegy:
  1342. Scale down changes applied to characters during NTI
  1343. If glyphs were detected on the line,
  1344. scale down changes apllied to glyphs during NTI
  1345. and adjust offsets
  1346. Apply glyph-based justification if needed
  1347. If glyphs were detected on the line,
  1348. adjust offsets
  1349. If some characters were changed on the left side
  1350. prepare additional width array for the display time
  1351. ----------------------------------------------------------------------------*/
  1352. static LSERR HandleFullGlyphsPres(const LSGRCHNK* plsgrchnk,
  1353. long dupAvailable, LSTFLOW lstflow,
  1354. long itxtobjAfterStartSpaces, long iwchAfterStartSpaces,
  1355. long itxtobjLast, long iwchLast, BOOL fForcedBreak, BOOL fSuppressTrailingSpaces,
  1356. long* pdupText, long* pdupTail)
  1357. {
  1358. LSERR lserr;
  1359. PILSOBJ pilsobj;
  1360. PLNOBJ plnobj;
  1361. PTXTOBJ ptxtobj;
  1362. PTXTOBJ ptxtobjLast;
  1363. long* rgdup;
  1364. long itxtobj;
  1365. long iwchLastInDobj;
  1366. long iFirst;
  1367. long iLim;
  1368. long i;
  1369. long dupTotal;
  1370. long dupToDistribute;
  1371. BOOL fFullyJustified = fFalse;
  1372. BOOL fLeftSideAffected = fFalse;
  1373. BOOL fGlyphDetected = fFalse;
  1374. ptxtobjLast = (PTXTOBJ)plsgrchnk->plschnk[max(0, itxtobjLast)].pdobj;
  1375. plnobj = ptxtobjLast->plnobj;
  1376. pilsobj = plnobj->pilsobj;
  1377. ScaleCharSides(plsgrchnk, lstflow, &fLeftSideAffected, &fGlyphDetected);
  1378. if (fGlyphDetected)
  1379. {
  1380. ScaleGlyphSides(plsgrchnk, lstflow);
  1381. UpdateGlyphOffsets(plsgrchnk);
  1382. SetBeforeJustCopy(plsgrchnk);
  1383. }
  1384. if (itxtobjLast > itxtobjAfterStartSpaces || (itxtobjLast == itxtobjAfterStartSpaces && iwchLast >= iwchAfterStartSpaces))
  1385. {
  1386. rgdup = plnobj->pdup;
  1387. dupTotal = 0;
  1388. for (itxtobj=0; itxtobj <= itxtobjLast; itxtobj++)
  1389. {
  1390. ptxtobj = (PTXTOBJ)plsgrchnk->plschnk[itxtobj].pdobj;
  1391. if (ptxtobj->txtf & txtfGlyphBased)
  1392. {
  1393. iFirst = ptxtobj->igindFirst;
  1394. iwchLastInDobj = iwchLast;
  1395. if (itxtobj < itxtobjLast)
  1396. iwchLastInDobj = ptxtobj->iwchLim - 1;
  1397. iLim = IgindLastFromIwch(ptxtobj, iwchLastInDobj) + 1;
  1398. rgdup = plnobj->pdupGind;
  1399. }
  1400. else
  1401. {
  1402. iFirst = ptxtobj->iwchFirst;
  1403. iLim = iwchLast + 1;
  1404. if (itxtobj < itxtobjLast)
  1405. iLim = ptxtobj->iwchLim;
  1406. rgdup = plnobj->pdup;
  1407. }
  1408. for (i =iFirst; i < iLim; i++)
  1409. {
  1410. dupTotal += rgdup[i];
  1411. }
  1412. }
  1413. dupToDistribute = dupAvailable - dupTotal;
  1414. lserr = ApplyGlyphExpand(plsgrchnk, lstflow, lsdevPres,
  1415. itxtobjAfterStartSpaces, iwchAfterStartSpaces, itxtobjLast, iwchLast,
  1416. dupToDistribute, plnobj->pdup, plnobj->pdupGind, pilsobj->pdurRight, pilsobj->pduGright,
  1417. &fFullyJustified);
  1418. if (lserr != lserrNone) return lserr;
  1419. if (fGlyphDetected)
  1420. {
  1421. UpdateGlyphOffsets(plsgrchnk);
  1422. }
  1423. }
  1424. lserr = FinalAdjustmentOnPres(plsgrchnk, itxtobjLast, iwchLast, dupAvailable,
  1425. fFalse, fForcedBreak, fSuppressTrailingSpaces,
  1426. pdupText, pdupTail);
  1427. if (lserr != lserrNone) return lserr;
  1428. /* If pdupPen is already used, don't forget to copy pdup there---ScaleSides could change it */
  1429. if (fLeftSideAffected || plnobj->pdup != plnobj->pdupPen)
  1430. {
  1431. lserr = FillDupPen(plsgrchnk, lstflow, itxtobjLast, iwchLast);
  1432. if (lserr != lserrNone) return lserr;
  1433. }
  1434. return lserrNone;
  1435. }