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.

1486 lines
34 KiB

  1. #include "lsmem.h"
  2. #include <limits.h>
  3. #include "lstxtscl.h"
  4. #include "lstxtmap.h"
  5. #include "lsdntext.h"
  6. #include "zqfromza.h"
  7. #include "txtils.h"
  8. #include "txtln.h"
  9. #include "txtobj.h"
  10. static void ApplyWysiGlyphs(const LSGRCHNK* plsgrchnk, LSTFLOW lstflow, long itxtobjStart,
  11. long durSumStart, long dupSumStart, BOOL fContinueWysiStart,
  12. long* pitxtobjLim, long* pdurSum, long* pdupSum);
  13. static void CopyRefToPresForScaleCharSides(const LSGRCHNK* plsgrchnk, BOOL* pfLeftSideAffected, BOOL* pfGlyphDetected);
  14. static void CopyRefToPresForScaleGlyphSides(const LSGRCHNK* plsgrchnk);
  15. #define min(a,b) ((a) > (b) ? (b) : (a))
  16. #define max(a,b) ((a) < (b) ? (b) : (a))
  17. #define abs(a) ((a) < 0 ? (-a) : (a))
  18. #define SetMagicConstant() (lstflow & fUVertical) ? \
  19. (MagicConstant = pilsobj->MagicConstantY, durRightMax = pilsobj->durRightMaxY) : \
  20. (MagicConstant = pilsobj->MagicConstantX, durRightMax = pilsobj->durRightMaxX)
  21. #define UpFromUrFast(ur) ( ((ur) * MagicConstant + (1 << 20)) >> 21)
  22. #define FAdjustable(ptxtobj) (!((ptxtobj)->txtf & txtfSkipAtWysi) && \
  23. ((ptxtobj)->iwchLim - (ptxtobj)->iwchFirst > 0))
  24. /* A P P L Y W Y S I */
  25. /*----------------------------------------------------------------------------
  26. %%Function: ApplyWysi
  27. %%Contact: sergeyge
  28. WYSIWYG algorithm for exact positioning of characters without wiggling
  29. ----------------------------------------------------------------------------*/
  30. void ApplyWysi(const LSGRCHNK* plsgrchnk, LSTFLOW lstflow)
  31. {
  32. PLNOBJ plnobj;
  33. PILSOBJ pilsobj;
  34. PTXTOBJ ptxtobj;
  35. long* rgdur;
  36. long* rgdup;
  37. long iwch;
  38. long itxtobj;
  39. long iwchPrev = 0;
  40. long iwchLim;
  41. BOOL fContinueWysi;
  42. BOOL fContinueAveraging;
  43. long durSum = 0;
  44. long dupSum = 0;
  45. long dupErrLast = 0;
  46. long dupPrevChar = 0;
  47. long MagicConstant;
  48. long durRightMax;
  49. long dupIdeal;
  50. long dupReal;
  51. long dupErrNew;
  52. long dupAdjust;
  53. long wCarry;
  54. long itxtobjNew;
  55. long durSumNew;
  56. long dupSumNew;
  57. Assert (plsgrchnk->clsgrchnk > 0);
  58. ptxtobj = (PTXTOBJ)plsgrchnk->plschnk[0].pdobj;
  59. plnobj = ptxtobj->plnobj;
  60. pilsobj = plnobj->pilsobj;
  61. if (pilsobj->fPresEqualRef)
  62. return;
  63. SetMagicConstant();
  64. rgdur = pilsobj->pdur;
  65. rgdup = plnobj->pdup;
  66. fContinueWysi = fFalse;
  67. fContinueAveraging = fFalse;
  68. itxtobj = 0;
  69. while(itxtobj < (long)plsgrchnk->clsgrchnk)
  70. {
  71. ptxtobj = (PTXTOBJ) plsgrchnk->plschnk[itxtobj].pdobj;
  72. Assert(ptxtobj->txtkind != txtkindTab);
  73. if (ptxtobj->txtf & txtfGlyphBased)
  74. {
  75. ApplyWysiGlyphs(plsgrchnk, lstflow, itxtobj, durSum, dupSum, fContinueWysi,
  76. &itxtobjNew, &durSumNew, &dupSumNew);
  77. itxtobj = itxtobjNew;
  78. durSum = durSumNew;
  79. dupSum = dupSumNew;
  80. fContinueAveraging = fFalse;
  81. fContinueWysi = fTrue;
  82. }
  83. else
  84. {
  85. if (FAdjustable(ptxtobj))
  86. {
  87. fContinueAveraging = fContinueAveraging && !(plsgrchnk->pcont[itxtobj] & fcontNonTextBefore);
  88. iwch = ptxtobj->iwchFirst;
  89. iwchLim = ptxtobj->iwchLim;
  90. while (iwch < iwchLim)
  91. {
  92. if (!fContinueAveraging)
  93. {
  94. fContinueAveraging = fTrue;
  95. if (!fContinueWysi)
  96. {
  97. fContinueWysi = fTrue;
  98. durSum = rgdur[iwch];
  99. if (durSum <= durRightMax)
  100. {
  101. dupIdeal = UpFromUrFast(durSum);
  102. dupErrLast = rgdup[iwch] - dupIdeal;
  103. rgdup[iwch] = dupIdeal;
  104. dupPrevChar = dupIdeal;
  105. iwchPrev = iwch;
  106. dupSum = dupIdeal;
  107. Assert(dupSum >= 0);
  108. }
  109. else
  110. {
  111. rgdup[iwch] = UpFromUr(lstflow, &pilsobj->lsdevres, durSum);
  112. dupSum = rgdup[iwch];
  113. /* Nothing else is set here because inside following while loop, first IF
  114. will be FALSE and loop will be terminated
  115. */
  116. }
  117. iwch++;
  118. }
  119. else
  120. {
  121. durSum += rgdur[iwch];
  122. if (durSum <= durRightMax)
  123. {
  124. dupIdeal = UpFromUrFast(durSum) - dupSum;
  125. dupErrLast = rgdup[iwch] - dupIdeal;
  126. rgdup[iwch] = dupIdeal;
  127. dupPrevChar = dupIdeal;
  128. iwchPrev = iwch;
  129. dupSum += dupIdeal;
  130. Assert(dupSum >= 0);
  131. iwch++;
  132. }
  133. else
  134. {
  135. durSum -= rgdur[iwch];
  136. /* Small triangle. Strictly speaking we could change nothing here
  137. but it is cleaner to keep invariants in order.
  138. Nothing else is set here because inside following while loop, first IF will
  139. be FALSE and loop will be terminated.
  140. */
  141. }
  142. }
  143. }
  144. while(iwch < iwchLim /* && fContinueWysi --replaced by break*/)
  145. {
  146. durSum += rgdur[iwch];
  147. if (durSum <= durRightMax)
  148. {
  149. /* here David Bangs algorithm starts */
  150. dupIdeal = UpFromUrFast(durSum) - dupSum;
  151. Assert(dupIdeal >= 0);
  152. dupReal = rgdup[iwch];
  153. dupErrNew = dupReal - dupIdeal;
  154. dupAdjust = dupErrNew - dupErrLast;
  155. if (dupAdjust != 0)
  156. {
  157. wCarry = dupAdjust & 1;
  158. if (dupAdjust > 0)
  159. {
  160. dupAdjust >>= 1;
  161. if (dupErrLast < -dupErrNew)
  162. dupAdjust += wCarry;
  163. dupAdjust = min(dupPrevChar /*-1*/, dupAdjust);
  164. }
  165. else
  166. {
  167. dupAdjust >>= 1;
  168. if (dupErrNew < -dupErrLast)
  169. dupAdjust += wCarry;
  170. dupAdjust = max(/*1*/ - dupIdeal, dupAdjust);
  171. }
  172. }
  173. rgdup[iwchPrev] -= dupAdjust;
  174. dupIdeal += dupAdjust;
  175. rgdup[iwch] = dupIdeal;
  176. dupSum += (dupIdeal - dupAdjust);
  177. dupErrLast = dupReal - dupIdeal;
  178. iwchPrev = iwch;
  179. dupPrevChar = dupIdeal;
  180. /* here David Bangs algorithm stops */
  181. iwch++;
  182. }
  183. else
  184. {
  185. fContinueWysi = fFalse;
  186. fContinueAveraging = fFalse;
  187. break;
  188. }
  189. }
  190. }
  191. }
  192. else
  193. {
  194. fContinueAveraging = fFalse;
  195. }
  196. itxtobj++;
  197. }
  198. }
  199. return;
  200. }
  201. /* S C A L E S P A C E S */
  202. /*----------------------------------------------------------------------------
  203. %%Function: ScaleSpaces
  204. %%Contact: sergeyge
  205. Scales down widths of spaces
  206. ----------------------------------------------------------------------------*/
  207. void ScaleSpaces(const LSGRCHNK* plsgrchnk, LSTFLOW lstflow, long itxtobjLast, long iwchLast)
  208. {
  209. PTXTOBJ ptxtobj;
  210. PILSOBJ pilsobj;
  211. PLNOBJ plnobj;
  212. long* rgdur;
  213. long* rgdup;
  214. long* rgwSpaces;
  215. long iwSpacesLim;
  216. long iwchLim;
  217. long itxtobj;
  218. long MagicConstant;
  219. long durRightMax;
  220. long dupSpace;
  221. long i;
  222. Assert (plsgrchnk->clsgrchnk > 0);
  223. plnobj = ((PTXTOBJ)(plsgrchnk->plschnk[0].pdobj))->plnobj;
  224. pilsobj = plnobj->pilsobj;
  225. rgdur = pilsobj->pdur;
  226. rgdup = plnobj->pdup;
  227. rgwSpaces = pilsobj->pwSpaces;
  228. Assert(!pilsobj->fPresEqualRef);
  229. Assert(!pilsobj->fNotSimpleText);
  230. SetMagicConstant();
  231. for (itxtobj = 0; itxtobj <= itxtobjLast; itxtobj++)
  232. {
  233. ptxtobj = (PTXTOBJ) plsgrchnk->plschnk[itxtobj].pdobj;
  234. Assert(!(ptxtobj->txtf & txtfGlyphBased));
  235. if (ptxtobj->txtkind == txtkindRegular)
  236. {
  237. iwSpacesLim = ptxtobj->u.reg.iwSpacesLim;
  238. iwchLim = iwchLast + 1;
  239. if (itxtobj < itxtobjLast)
  240. iwchLim = ptxtobj->iwchLim;
  241. while (iwSpacesLim > ptxtobj->u.reg.iwSpacesFirst && rgwSpaces[iwSpacesLim-1] >= iwchLim)
  242. {
  243. iwSpacesLim--;
  244. }
  245. for(i = ptxtobj->u.reg.iwSpacesFirst; i < iwSpacesLim; i++)
  246. {
  247. if (rgdur[rgwSpaces[i]] < durRightMax)
  248. {
  249. dupSpace = UpFromUrFast(rgdur[rgwSpaces[i]]);
  250. }
  251. else
  252. {
  253. dupSpace = UpFromUr(lstflow, &pilsobj->lsdevres, rgdur[rgwSpaces[i]]);
  254. }
  255. Assert(dupSpace >= 0);
  256. rgdup[rgwSpaces[i]] = dupSpace;
  257. }
  258. }
  259. }
  260. return;
  261. }
  262. /* S C A L E C H A R S I D E S */
  263. /*----------------------------------------------------------------------------
  264. %%Function: ScaleCharSides
  265. %%Contact: sergeyge
  266. Scales down changes applied to characters
  267. ----------------------------------------------------------------------------*/
  268. void ScaleCharSides(const LSGRCHNK* plsgrchnk, LSTFLOW lstflow, BOOL* pfLeftSideAffected, BOOL* pfGlyphDetected)
  269. {
  270. PLNOBJ plnobj;
  271. PILSOBJ pilsobj;
  272. PTXTOBJ ptxtobj;
  273. long* rgdur;
  274. long* rgdup;
  275. long* rgdurRight;
  276. long* rgdurLeft;
  277. long i;
  278. long itxtobj;
  279. long iLim;
  280. long durTemp = 0;
  281. long dupTemp = 0;
  282. long MagicConstant;
  283. long durRightMax;
  284. Assert (plsgrchnk->clsgrchnk > 0);
  285. *pfLeftSideAffected = fFalse;
  286. *pfGlyphDetected = fFalse;
  287. ptxtobj = (PTXTOBJ)plsgrchnk->plschnk[0].pdobj;
  288. plnobj = ptxtobj->plnobj;
  289. pilsobj = plnobj->pilsobj;
  290. if (pilsobj->fPresEqualRef)
  291. {
  292. CopyRefToPresForScaleCharSides(plsgrchnk, pfLeftSideAffected, pfGlyphDetected);
  293. return;
  294. }
  295. SetMagicConstant();
  296. for (itxtobj = 0; itxtobj < (long)plsgrchnk->clsgrchnk; itxtobj++)
  297. {
  298. ptxtobj = (PTXTOBJ) plsgrchnk->plschnk[itxtobj].pdobj;
  299. Assert(ptxtobj->txtkind != txtkindTab);
  300. if (ptxtobj->txtf & txtfGlyphBased)
  301. {
  302. *pfGlyphDetected = fTrue;
  303. }
  304. else
  305. {
  306. if (FAdjustable(ptxtobj))
  307. {
  308. rgdur = pilsobj->pdur;
  309. rgdup = plnobj->pdup;
  310. rgdurRight = pilsobj->pdurRight;
  311. rgdurLeft = pilsobj->pdurLeft;
  312. i = ptxtobj->iwchFirst;
  313. iLim = ptxtobj->iwchLim;
  314. while(i < iLim)
  315. {
  316. durTemp = rgdurRight[i] + rgdurLeft[i];
  317. *pfLeftSideAffected = *pfLeftSideAffected || (rgdurLeft[i] != 0);
  318. if (durTemp != 0)
  319. {
  320. if (abs(durTemp) <= durRightMax)
  321. {
  322. dupTemp = UpFromUrFast(durTemp);
  323. }
  324. else
  325. {
  326. dupTemp = UpFromUr(lstflow, &pilsobj->lsdevres, durTemp);
  327. }
  328. rgdup[i] += dupTemp;
  329. }
  330. i++;
  331. }
  332. }
  333. }
  334. }
  335. return;
  336. }
  337. /* S C A L E G L Y P H S I D E S */
  338. /*----------------------------------------------------------------------------
  339. %%Function: ScaleGlyphSides
  340. %%Contact: sergeyge
  341. Scales down changes applied to glyphs
  342. ----------------------------------------------------------------------------*/
  343. void ScaleGlyphSides(const LSGRCHNK* plsgrchnk, LSTFLOW lstflow)
  344. {
  345. PLNOBJ plnobj;
  346. PILSOBJ pilsobj;
  347. PTXTOBJ ptxtobj;
  348. long* rgdur;
  349. long* rgdup;
  350. long* rgdurRight;
  351. long i;
  352. long itxtobj;
  353. long iLim;
  354. long durTemp = 0;
  355. long dupTemp = 0;
  356. long MagicConstant;
  357. long durRightMax;
  358. Assert (plsgrchnk->clsgrchnk > 0);
  359. ptxtobj = (PTXTOBJ)plsgrchnk->plschnk[0].pdobj;
  360. plnobj = ptxtobj->plnobj;
  361. pilsobj = plnobj->pilsobj;
  362. if (pilsobj->fPresEqualRef)
  363. {
  364. CopyRefToPresForScaleGlyphSides(plsgrchnk);
  365. return;
  366. }
  367. SetMagicConstant();
  368. for (itxtobj = 0; itxtobj < (long)plsgrchnk->clsgrchnk; itxtobj++)
  369. {
  370. ptxtobj = (PTXTOBJ) plsgrchnk->plschnk[itxtobj].pdobj;
  371. Assert(ptxtobj->txtkind != txtkindTab);
  372. if (ptxtobj->txtf & txtfGlyphBased)
  373. {
  374. Assert (FAdjustable(ptxtobj));
  375. rgdur = pilsobj->pdurGind;
  376. rgdup = plnobj->pdupGind;
  377. rgdurRight = pilsobj->pduGright;
  378. i = ptxtobj->igindFirst;
  379. iLim = ptxtobj->igindLim;
  380. while(i < iLim)
  381. {
  382. durTemp = rgdurRight[i];
  383. if (durTemp != 0)
  384. {
  385. if (abs(durTemp) <= durRightMax)
  386. {
  387. dupTemp = UpFromUrFast(durTemp);
  388. }
  389. else
  390. {
  391. dupTemp = UpFromUr(lstflow, &pilsobj->lsdevres, durTemp);
  392. }
  393. rgdup[i] += dupTemp;
  394. rgdurRight[i] = dupTemp;
  395. }
  396. i++;
  397. }
  398. }
  399. }
  400. return;
  401. }
  402. /* U P D A T E G L Y P H O F F S E T S */
  403. /*----------------------------------------------------------------------------
  404. %%Function: UpdateGlyphOffsets
  405. %%Contact: sergeyge
  406. Adjusts offsets of glyphs which are attached to the glyph with changed width
  407. ----------------------------------------------------------------------------*/
  408. void UpdateGlyphOffsets(const LSGRCHNK* plsgrchnk)
  409. {
  410. PLNOBJ plnobj;
  411. PILSOBJ pilsobj;
  412. PTXTOBJ ptxtobj;
  413. long* rgduRight;
  414. long* rgdup;
  415. long igind;
  416. long itxtobj;
  417. long dupTemp = 0;
  418. Assert (plsgrchnk->clsgrchnk > 0);
  419. ptxtobj = (PTXTOBJ)plsgrchnk->plschnk[0].pdobj;
  420. plnobj = ptxtobj->plnobj;
  421. pilsobj = plnobj->pilsobj;
  422. rgduRight = pilsobj->pduGright;
  423. rgdup = plnobj->pdupGind;
  424. for (itxtobj = 0; itxtobj < (long)plsgrchnk->clsgrchnk; itxtobj++)
  425. {
  426. ptxtobj = (PTXTOBJ) plsgrchnk->plschnk[itxtobj].pdobj;
  427. Assert(ptxtobj->txtkind != txtkindTab);
  428. if (ptxtobj->txtf & txtfGlyphBased)
  429. {
  430. igind = ptxtobj->igindFirst;
  431. while(igind < ptxtobj->igindLim)
  432. {
  433. dupTemp = rgduRight[igind];
  434. if (dupTemp != 0)
  435. {
  436. while(!FIgindLastInContext(pilsobj, igind) && rgdup[igind + 1] == 0)
  437. {
  438. igind++;
  439. plnobj->pgoffs[igind].du -= dupTemp;
  440. }
  441. }
  442. igind++;
  443. }
  444. memset(&rgduRight[ptxtobj->igindFirst], 0, sizeof(long)*(ptxtobj->igindLim - ptxtobj->igindFirst));
  445. }
  446. }
  447. }
  448. /* S E T B E F O R E J U S T C O P Y */
  449. /*----------------------------------------------------------------------------
  450. %%Function: SetBeforeJustCopy
  451. %%Contact: sergeyge
  452. Fills pdupBeforeJust output array
  453. ----------------------------------------------------------------------------*/
  454. void SetBeforeJustCopy(const LSGRCHNK* plsgrchnk)
  455. {
  456. PLNOBJ plnobj;
  457. PILSOBJ pilsobj;
  458. PTXTOBJ ptxtobj;
  459. long itxtobj;
  460. long igindFirst;
  461. long igindLim;
  462. ptxtobj = (PTXTOBJ)plsgrchnk->plschnk[0].pdobj;
  463. plnobj = ptxtobj->plnobj;
  464. pilsobj = plnobj->pilsobj;
  465. for (itxtobj = 0; itxtobj < (long)plsgrchnk->clsgrchnk; itxtobj++)
  466. {
  467. ptxtobj = (PTXTOBJ) plsgrchnk->plschnk[itxtobj].pdobj;
  468. Assert(ptxtobj->txtkind != txtkindTab);
  469. if (ptxtobj->txtf & txtfGlyphBased)
  470. {
  471. igindFirst = ptxtobj->igindFirst;
  472. igindLim = ptxtobj->igindLim;
  473. memcpy(&plnobj->pdupBeforeJust[igindFirst], &plnobj->pdupGind[igindFirst], sizeof(long)*(igindLim - igindFirst));
  474. }
  475. }
  476. }
  477. /* S C A L E E X T N O N T E X T */
  478. /*----------------------------------------------------------------------------
  479. %%Function: ScaleExtNonText
  480. %%Contact: sergeyge
  481. Scales down change which is
  482. to be applyed by manager to non-text objects
  483. ----------------------------------------------------------------------------*/
  484. void ScaleExtNonText(PILSOBJ pilsobj, LSTFLOW lstflow, long durExtNonText, long* pdupExtNonText)
  485. {
  486. long MagicConstant;
  487. long durRightMax;
  488. if (pilsobj->fPresEqualRef)
  489. *pdupExtNonText = durExtNonText;
  490. else
  491. {
  492. SetMagicConstant();
  493. *pdupExtNonText = 0;
  494. Assert(durExtNonText >= 0);
  495. if (durExtNonText > 0)
  496. {
  497. if (durExtNonText <= durRightMax)
  498. {
  499. *pdupExtNonText = UpFromUrFast(durExtNonText);
  500. }
  501. else
  502. {
  503. *pdupExtNonText = UpFromUr(lstflow, &pilsobj->lsdevres, durExtNonText);
  504. }
  505. }
  506. }
  507. return;
  508. }
  509. /* G E T D U P L A S T C H A R */
  510. /*----------------------------------------------------------------------------
  511. %%Function: GetDupLastChar
  512. %%Contact: sergeyge
  513. ----------------------------------------------------------------------------*/
  514. void GetDupLastChar(const LSGRCHNK* plsgrchnk, long iwchLast, long* pdupHangingChar)
  515. {
  516. *pdupHangingChar = ((PTXTOBJ)plsgrchnk->plschnk[0].pdobj)->plnobj->pdup[iwchLast];
  517. }
  518. /* F I L L D U P P E N */
  519. /*----------------------------------------------------------------------------
  520. %%Function: FillDupPen
  521. %%Contact: sergeyge
  522. In the case when some characters were changed on the left side,
  523. prepares array of widths which is used at display time
  524. ----------------------------------------------------------------------------*/
  525. LSERR FillDupPen(const LSGRCHNK* plsgrchnk, LSTFLOW lstflow, long itxtobjLast, long iwchLast)
  526. {
  527. PLNOBJ plnobj;
  528. PILSOBJ pilsobj;
  529. PTXTOBJ ptxtobj;
  530. long* rgdup;
  531. long* rgdupPen;
  532. long* rgdurLeft;
  533. long iwch;
  534. long iwchLocLim;
  535. long iwchLim;
  536. long itxtobj;
  537. long MagicConstant;
  538. long durRightMax;
  539. long durLeft;
  540. long dupLeft;
  541. Assert (plsgrchnk->clsgrchnk > 0);
  542. ptxtobj = (PTXTOBJ)plsgrchnk->plschnk[0].pdobj;
  543. plnobj = ptxtobj->plnobj;
  544. pilsobj = plnobj->pilsobj;
  545. if (plnobj->pdupPenAlloc == NULL)
  546. {
  547. plnobj->pdupPenAlloc = (*pilsobj->plscbk->pfnNewPtr)(pilsobj->pols, sizeof(long) * pilsobj->wchMax);
  548. if (plnobj->pdupPenAlloc == NULL)
  549. return lserrOutOfMemory;
  550. memset(plnobj->pdupPenAlloc, 0, sizeof(long) * pilsobj->wchMax);
  551. }
  552. if (plnobj->pdupPen == plnobj->pdup)
  553. {
  554. plnobj->pdupPen = plnobj->pdupPenAlloc;
  555. memcpy(plnobj->pdupPen, plnobj->pdup, sizeof(long) * pilsobj->wchMac);
  556. }
  557. rgdurLeft = pilsobj->pdurLeft;
  558. rgdup = plnobj->pdup;
  559. rgdupPen = plnobj->pdupPen;
  560. SetMagicConstant();
  561. for (itxtobj = 0; itxtobj <= itxtobjLast; itxtobj++)
  562. {
  563. ptxtobj = (PTXTOBJ) plsgrchnk->plschnk[itxtobj].pdobj;
  564. /* Left chopping is impossible for glyph-based runs;
  565. no additional data structures are introduced for glyphs for
  566. this case.
  567. */
  568. if (!(ptxtobj->txtf & txtfGlyphBased) )
  569. {
  570. Assert(ptxtobj->txtkind != txtkindTab);
  571. iwch = ptxtobj->iwchFirst;
  572. iwchLocLim = iwchLast + 1;
  573. if (itxtobj < itxtobjLast)
  574. iwchLocLim = ptxtobj->iwchLim;
  575. Assert(iwchLocLim <= ptxtobj->iwchLim);
  576. if (iwch < iwchLocLim)
  577. {
  578. rgdupPen[iwch] = rgdup[iwch];
  579. durLeft = rgdurLeft[iwch];
  580. if (durLeft != 0)
  581. {
  582. if (pilsobj->fPresEqualRef)
  583. dupLeft = durLeft;
  584. else
  585. {
  586. if (abs(durLeft) <= durRightMax)
  587. {
  588. dupLeft = UpFromUrFast(durLeft);
  589. }
  590. else
  591. {
  592. dupLeft = UpFromUr(lstflow, &pilsobj->lsdevres, durLeft);
  593. }
  594. }
  595. ptxtobj->dupBefore = -dupLeft;
  596. rgdupPen[iwch] -= dupLeft;
  597. }
  598. iwch++;
  599. }
  600. while (iwch < iwchLocLim)
  601. {
  602. rgdupPen[iwch] = rgdup[iwch];
  603. durLeft = rgdurLeft[iwch];
  604. if (durLeft != 0)
  605. {
  606. if (pilsobj->fPresEqualRef)
  607. dupLeft = durLeft;
  608. else
  609. {
  610. if (abs(durLeft) <= durRightMax)
  611. {
  612. dupLeft = UpFromUrFast(durLeft);
  613. }
  614. else
  615. {
  616. dupLeft = UpFromUr(lstflow, &pilsobj->lsdevres, durLeft);
  617. }
  618. }
  619. rgdupPen[iwch-1] += dupLeft;
  620. rgdupPen[iwch] -= dupLeft;
  621. }
  622. iwch++;
  623. }
  624. iwchLim = ptxtobj->iwchLim;
  625. Assert(iwch == iwchLocLim);
  626. for (; iwch < iwchLim; iwch++)
  627. {
  628. rgdupPen[iwch] = rgdup[iwch];
  629. }
  630. }
  631. }
  632. Assert(itxtobj == itxtobjLast + 1);
  633. for (; itxtobj < (long)plsgrchnk->clsgrchnk; itxtobj++)
  634. {
  635. ptxtobj = (PTXTOBJ) plsgrchnk->plschnk[itxtobj].pdobj;
  636. if (!(ptxtobj->txtf & txtfGlyphBased))
  637. {
  638. for (iwch = ptxtobj->iwchFirst; iwch < ptxtobj->iwchLim; iwch++)
  639. {
  640. rgdupPen[iwch] = rgdup[iwch];
  641. }
  642. }
  643. }
  644. return lserrNone;
  645. }
  646. /* F I N A L A D J U S T M E N T O N P R E S */
  647. /*----------------------------------------------------------------------------
  648. %%Function: FinalAdjustmentOnPres
  649. %%Contact: sergeyge
  650. Sets dup's to DNODE's
  651. Implements emergency procedures to fit on presentation device
  652. ----------------------------------------------------------------------------*/
  653. LSERR FinalAdjustmentOnPres(const LSGRCHNK* plsgrchnk, long itxtobjLast, long iwchLast,
  654. long dupAvailable, BOOL fFullyScaled, BOOL fForcedBreak, BOOL fSuppressTrailingSpaces,
  655. long* pdupText, long* pdupTail)
  656. {
  657. LSERR lserr;
  658. PLNOBJ plnobj;
  659. PILSOBJ pilsobj;
  660. PTXTOBJ ptxtobj;
  661. PTXTOBJ ptxtobjLast;
  662. long* rgdup;
  663. long iFirst;
  664. long iLim;
  665. long iMinLim;
  666. long dupTotal;
  667. long dupToDistribute;
  668. long dupAdd;
  669. long dupChange;
  670. long itxtobj;
  671. long i;
  672. long iTemp;
  673. long dupToDistributePrev;
  674. Assert (plsgrchnk->clsgrchnk > 0);
  675. Assert (itxtobjLast < (long)plsgrchnk->clsgrchnk);
  676. ptxtobjLast = (PTXTOBJ)plsgrchnk->plschnk[max(0, itxtobjLast)].pdobj;
  677. plnobj = ptxtobjLast->plnobj;
  678. pilsobj = plnobj->pilsobj;
  679. *pdupText = 0;
  680. *pdupTail = 0;
  681. for (itxtobj=0; itxtobj < (long)plsgrchnk->clsgrchnk; itxtobj++)
  682. {
  683. ptxtobj = (PTXTOBJ)plsgrchnk->plschnk[itxtobj].pdobj;
  684. dupTotal = 0;
  685. if (ptxtobj->txtf & txtfGlyphBased)
  686. {
  687. iFirst = ptxtobj->igindFirst;
  688. iLim = ptxtobj->igindLim;
  689. iMinLim = iLim;
  690. if (itxtobj == itxtobjLast)
  691. iMinLim = IgindLastFromIwch(ptxtobjLast, iwchLast) + 1;
  692. else if (itxtobj > itxtobjLast)
  693. iMinLim = iFirst;
  694. rgdup = plnobj->pdupGind;
  695. }
  696. else
  697. {
  698. iFirst = ptxtobj->iwchFirst;
  699. iLim = ptxtobj->iwchLim;
  700. iMinLim = iLim;
  701. if (itxtobj == itxtobjLast)
  702. iMinLim = iwchLast + 1;
  703. else if (itxtobj > itxtobjLast)
  704. iMinLim = iFirst;
  705. rgdup = plnobj->pdup;
  706. }
  707. for (i = iFirst; i < iMinLim; i++)
  708. {
  709. dupTotal += rgdup[i];
  710. }
  711. Assert(i >= iMinLim);
  712. /* Take care of trailing area, taking into account fSuppressTrailingSpaces bit */
  713. if (fSuppressTrailingSpaces)
  714. {
  715. for (; i < iLim; i++)
  716. {
  717. rgdup[i] = 0;
  718. }
  719. }
  720. else
  721. {
  722. for (; i < iLim; i++)
  723. {
  724. dupTotal += rgdup[i];
  725. *pdupTail += rgdup[i];
  726. }
  727. }
  728. *pdupText += dupTotal;
  729. lserr = LsdnSetTextDup(plnobj->pilsobj->plsc, ptxtobj->plsdnUpNode, dupTotal);
  730. if (lserr != lserrNone) return lserr;
  731. }
  732. if (itxtobjLast < 0)
  733. return lserrNone;
  734. dupToDistribute = dupAvailable - (*pdupText - *pdupTail);
  735. /* fFinalAdjustNeeded==fTrue, if there were spaces on the line. If there were no spaces,
  736. justification is not needed
  737. */
  738. if ( (!fForcedBreak && dupToDistribute < 0 && -dupToDistribute < *pdupText) ||
  739. (dupToDistribute > 0 && fFullyScaled))
  740. {
  741. dupAdd = 0;
  742. if (dupToDistribute > 0)
  743. {
  744. dupAdd = 1;
  745. }
  746. else if (dupToDistribute < 0)
  747. {
  748. dupAdd = -1;
  749. }
  750. dupToDistributePrev = 0;
  751. while (dupToDistribute != 0 && dupToDistributePrev != dupToDistribute)
  752. {
  753. dupToDistributePrev = dupToDistribute;
  754. for (itxtobj = itxtobjLast; itxtobj >= 0 && dupToDistribute != 0; itxtobj--)
  755. {
  756. ptxtobj = (PTXTOBJ)plsgrchnk->plschnk[itxtobj].pdobj;
  757. dupChange = 0;
  758. /* REVIEW sergeyge: iwchLast-1 is used because we want correct alignment for the
  759. last character. Is it correct?
  760. */
  761. if (ptxtobj->txtf & txtfGlyphBased)
  762. {
  763. rgdup = plnobj->pdupGind;
  764. if (itxtobj == itxtobjLast)
  765. i = IgindLastFromIwch(ptxtobjLast, iwchLast);
  766. else
  767. {
  768. Assert(itxtobj < itxtobjLast);
  769. i = ptxtobj->igindLim - 1;
  770. }
  771. for (; i >= ptxtobj->igindFirst && dupToDistribute != 0; i--)
  772. {
  773. if (rgdup[i] > 1)
  774. {
  775. rgdup[i] += dupAdd;
  776. iTemp = i;
  777. while(!FIgindLastInContext(pilsobj, iTemp) && rgdup[iTemp + 1] == 0)
  778. {
  779. iTemp++;
  780. plnobj->pgoffs[iTemp].du -= dupAdd;
  781. }
  782. dupToDistribute -= dupAdd;
  783. dupChange += dupAdd;
  784. }
  785. }
  786. }
  787. else
  788. {
  789. rgdup = plnobj->pdup;
  790. i = iwchLast;
  791. if (itxtobj < itxtobjLast)
  792. i = ptxtobj->iwchLim - 1;
  793. for (; i >= ptxtobj->iwchFirst && dupToDistribute != 0; i--)
  794. {
  795. if (rgdup[i] > 1)
  796. {
  797. rgdup[i] += dupAdd;
  798. dupToDistribute -= dupAdd;
  799. dupChange += dupAdd;
  800. }
  801. }
  802. }
  803. lserr = LsdnModifyTextDup(ptxtobj->plnobj->pilsobj->plsc, ptxtobj->plsdnUpNode, dupChange);
  804. if (lserr != lserrNone) return lserr;
  805. *pdupText += dupChange;
  806. }
  807. }
  808. }
  809. return lserrNone;
  810. }
  811. /* Internal Procedures Implementation */
  812. /* A P P L Y W Y S I G L Y P H S */
  813. /*----------------------------------------------------------------------------
  814. %%Function: ApplyWysiGlyphs
  815. %%Contact: sergeyge
  816. WYSIWYG algorithm for exact positioning of glyphs without wiggling
  817. ----------------------------------------------------------------------------*/
  818. static void ApplyWysiGlyphs(const LSGRCHNK* plsgrchnk, LSTFLOW lstflow, long itxtobjStart,
  819. long durSumStart, long dupSumStart, BOOL fContinueWysiStart,
  820. long* pitxtobjLim, long* pdurSum, long* pdupSum)
  821. {
  822. PLNOBJ plnobj;
  823. PILSOBJ pilsobj;
  824. PTXTOBJ ptxtobj;
  825. long* rgdur;
  826. long* rgdup;
  827. long igind;
  828. long itxtobj;
  829. long igindPrev = 0;
  830. long igindLim;
  831. BOOL fContinueWysi;
  832. BOOL fContinueAveraging;
  833. long durSum;
  834. long dupSum;
  835. long dupErrLast = 0;
  836. long dupPrevChar = 0;
  837. long MagicConstant;
  838. long durRightMax;
  839. long dupIdeal;
  840. long dupReal;
  841. long dupErrNew;
  842. long dupAdjust;
  843. long wCarry;
  844. ptxtobj = (PTXTOBJ)plsgrchnk->plschnk[0].pdobj;
  845. plnobj = ptxtobj->plnobj;
  846. pilsobj = plnobj->pilsobj;
  847. SetMagicConstant();
  848. rgdur = pilsobj->pdurGind;
  849. rgdup = plnobj->pdupGind;
  850. fContinueAveraging = fFalse;
  851. durSum = durSumStart;
  852. dupSum = dupSumStart;
  853. fContinueWysi = fContinueWysiStart;
  854. itxtobj = itxtobjStart;
  855. while(itxtobj < (long)plsgrchnk->clsgrchnk)
  856. {
  857. ptxtobj = (PTXTOBJ) plsgrchnk->plschnk[itxtobj].pdobj;
  858. Assert(ptxtobj->txtkind != txtkindTab);
  859. if (ptxtobj->txtf & txtfGlyphBased)
  860. {
  861. Assert(FAdjustable(ptxtobj));
  862. fContinueAveraging = fContinueAveraging && !(plsgrchnk->pcont[itxtobj] & fcontNonTextBefore);
  863. igind = ptxtobj->igindFirst;
  864. igindLim = ptxtobj->igindLim;
  865. while (igind < igindLim)
  866. {
  867. if (!fContinueAveraging)
  868. {
  869. fContinueAveraging = fTrue;
  870. if (!fContinueWysi)
  871. {
  872. fContinueWysi = fTrue;
  873. durSum = rgdur[igind];
  874. if (durSum <= durRightMax)
  875. {
  876. dupIdeal = UpFromUrFast(durSum);
  877. dupErrLast = rgdup[igind] - dupIdeal;
  878. rgdup[igind] = dupIdeal;
  879. dupPrevChar = dupIdeal;
  880. igindPrev = igind;
  881. dupSum = dupIdeal;
  882. Assert(dupSum >= 0);
  883. while(!FIgindLastInContext(pilsobj, igind) && rgdup[igind + 1] == 0)
  884. {
  885. igind++;
  886. plnobj->pgoffs[igind].du += dupErrLast;
  887. }
  888. }
  889. else
  890. {
  891. dupIdeal = UpFromUr(lstflow, &pilsobj->lsdevres, durSum);
  892. dupErrLast = rgdup[igind] - dupIdeal;
  893. rgdup[igind] = dupIdeal;
  894. dupSum = dupIdeal;
  895. /* Nothing else is set here because inside following while loop, first IF
  896. will be FALSE and loop will be terminated
  897. */
  898. while(!FIgindLastInContext(pilsobj, igind) && rgdup[igind + 1] == 0)
  899. {
  900. igind++;
  901. plnobj->pgoffs[igind].du += dupErrLast;
  902. }
  903. }
  904. igind++;
  905. }
  906. else
  907. {
  908. durSum += rgdur[igind];
  909. if (durSum <= durRightMax)
  910. {
  911. dupIdeal = UpFromUrFast(durSum) - dupSum;
  912. dupErrLast = rgdup[igind] - dupIdeal;
  913. rgdup[igind] = dupIdeal;
  914. dupPrevChar = dupIdeal;
  915. igindPrev = igind;
  916. dupSum += dupIdeal;
  917. Assert(dupSum >= 0);
  918. while(!FIgindLastInContext(pilsobj, igind) && rgdup[igind + 1] == 0)
  919. {
  920. igind++;
  921. plnobj->pgoffs[igind].du += dupErrLast;
  922. }
  923. igind++;
  924. }
  925. else
  926. {
  927. durSum -= rgdur[igind];
  928. /* Small triangle. Strictly speaking we could change nothing here
  929. but it is cleaner to keep invariants in order.
  930. Nothing else is set here because inside following while loop, first IF will
  931. be FALSE and loop will be terminated.
  932. */
  933. }
  934. }
  935. }
  936. while(igind < igindLim /* && fContinueWysi --replaced by break*/)
  937. {
  938. durSum += rgdur[igind];
  939. if (durSum <= durRightMax)
  940. {
  941. /* here David Bangs algorithm starts */
  942. dupIdeal = UpFromUrFast(durSum) - dupSum;
  943. Assert(dupIdeal >= 0);
  944. dupReal = rgdup[igind];
  945. dupErrNew = dupReal - dupIdeal;
  946. dupAdjust = dupErrNew - dupErrLast;
  947. if (dupAdjust != 0)
  948. {
  949. wCarry = dupAdjust & 1;
  950. if (dupAdjust > 0)
  951. {
  952. dupAdjust >>= 1;
  953. if (dupErrLast < -dupErrNew)
  954. dupAdjust += wCarry;
  955. dupAdjust = min(dupPrevChar /*-1*/, dupAdjust);
  956. }
  957. else
  958. {
  959. dupAdjust >>= 1;
  960. if (dupErrNew < -dupErrLast)
  961. dupAdjust += wCarry;
  962. dupAdjust = max(/*1*/ - dupIdeal, dupAdjust);
  963. }
  964. }
  965. rgdup[igindPrev] -= dupAdjust;
  966. while(!FIgindLastInContext(pilsobj, igindPrev) && rgdup[igindPrev + 1] == 0)
  967. {
  968. igindPrev++;
  969. plnobj->pgoffs[igindPrev].du += dupAdjust;
  970. }
  971. dupIdeal += dupAdjust;
  972. rgdup[igind] = dupIdeal;
  973. dupSum += (dupIdeal - dupAdjust);
  974. dupErrLast = dupReal - dupIdeal;
  975. igindPrev = igind;
  976. while(!FIgindLastInContext(pilsobj, igind) && rgdup[igind + 1] == 0)
  977. {
  978. igind++;
  979. plnobj->pgoffs[igind].du += dupErrLast;
  980. }
  981. dupPrevChar = dupIdeal;
  982. /* here David Bangs algorithm stops */
  983. igind++;
  984. }
  985. else
  986. {
  987. fContinueWysi = fFalse;
  988. fContinueAveraging = fFalse;
  989. break;
  990. }
  991. }
  992. }
  993. itxtobj++;
  994. }
  995. else
  996. {
  997. break;
  998. }
  999. }
  1000. *pitxtobjLim = itxtobj;
  1001. *pdurSum = durSum;
  1002. *pdupSum = dupSum;
  1003. return;
  1004. }
  1005. /* C O P Y R E F T O P R E S F O R S C A L E C H A R S I D E S */
  1006. /*----------------------------------------------------------------------------
  1007. %%Function: CopyRefToPresForScaleCharSides
  1008. %%Contact: sergeyge
  1009. ----------------------------------------------------------------------------*/
  1010. static void CopyRefToPresForScaleCharSides(const LSGRCHNK* plsgrchnk, BOOL* pfLeftSideAffected, BOOL* pfGlyphDetected)
  1011. {
  1012. PLNOBJ plnobj;
  1013. PILSOBJ pilsobj;
  1014. PTXTOBJ ptxtobj;
  1015. long itxtobj;
  1016. long iFirst;
  1017. long iLim;
  1018. long i;
  1019. ptxtobj = (PTXTOBJ)plsgrchnk->plschnk[0].pdobj;
  1020. plnobj = ptxtobj->plnobj;
  1021. pilsobj = plnobj->pilsobj;
  1022. *pfLeftSideAffected = fFalse;
  1023. *pfGlyphDetected = fFalse;
  1024. for (itxtobj = 0; itxtobj < (long)plsgrchnk->clsgrchnk; itxtobj++)
  1025. {
  1026. ptxtobj = (PTXTOBJ) plsgrchnk->plschnk[itxtobj].pdobj;
  1027. Assert(ptxtobj->txtkind != txtkindTab);
  1028. if (ptxtobj->txtf & txtfGlyphBased)
  1029. {
  1030. Assert (FAdjustable(ptxtobj));
  1031. *pfGlyphDetected = fTrue;
  1032. }
  1033. else
  1034. {
  1035. if(FAdjustable(ptxtobj))
  1036. {
  1037. iFirst = ptxtobj->iwchFirst;
  1038. iLim = ptxtobj->iwchLim;
  1039. memcpy(&plnobj->pdup[iFirst], &pilsobj->pdur[iFirst], sizeof(long)*(iLim - iFirst));
  1040. for (i = iFirst; i < iLim && !*pfLeftSideAffected; i++)
  1041. {
  1042. *pfLeftSideAffected = (pilsobj->pdurLeft[i] != 0);
  1043. }
  1044. }
  1045. }
  1046. }
  1047. }
  1048. /* C O P Y R E F T O P R E S F O R S C A L E G L Y P H S I D E S */
  1049. /*----------------------------------------------------------------------------
  1050. %%Function: CopyRefToPresForScaleGlyphSides
  1051. %%Contact: sergeyge
  1052. ----------------------------------------------------------------------------*/
  1053. static void CopyRefToPresForScaleGlyphSides(const LSGRCHNK* plsgrchnk)
  1054. {
  1055. PLNOBJ plnobj;
  1056. PILSOBJ pilsobj;
  1057. PTXTOBJ ptxtobj;
  1058. long itxtobj;
  1059. long iFirst;
  1060. long iLim;
  1061. ptxtobj = (PTXTOBJ)plsgrchnk->plschnk[0].pdobj;
  1062. plnobj = ptxtobj->plnobj;
  1063. pilsobj = plnobj->pilsobj;
  1064. for (itxtobj = 0; itxtobj < (long)plsgrchnk->clsgrchnk; itxtobj++)
  1065. {
  1066. ptxtobj = (PTXTOBJ) plsgrchnk->plschnk[itxtobj].pdobj;
  1067. Assert(ptxtobj->txtkind != txtkindTab);
  1068. if (ptxtobj->txtf & txtfGlyphBased)
  1069. {
  1070. Assert (FAdjustable(ptxtobj));
  1071. iFirst = ptxtobj->igindFirst;
  1072. iLim = ptxtobj->igindLim;
  1073. memcpy(&plnobj->pdupGind[iFirst], &pilsobj->pdurGind[iFirst], sizeof(long)*(iLim - iFirst));
  1074. }
  1075. }
  1076. }
  1077. #ifdef FUTURE
  1078. /* NOT USED IN LS 3.0 */
  1079. /* A P P L Y N O N E X A C T W Y S I */
  1080. /*----------------------------------------------------------------------------
  1081. %%Function: ApplyNonExactWysi
  1082. %%Contact: sergeyge
  1083. Alternative WYSIWYG algorithm of characters without wiggling
  1084. sacrifices exact positioning somewhat in attempt to improve
  1085. character spacing
  1086. ----------------------------------------------------------------------------*/
  1087. #define dupBigError 2
  1088. void ApplyNonExactWysi(const LSGRCHNK* plsgrchnk, LSTFLOW lstflow)
  1089. {
  1090. PLNOBJ plnobj;
  1091. PILSOBJ pilsobj;
  1092. PTXTOBJ ptxtobj;
  1093. long* rgdur;
  1094. long* rgdup;
  1095. WCHAR* rgwch;
  1096. long iwch;
  1097. long itxtobj;
  1098. long iwchPrev = 0;
  1099. long iwchLim;
  1100. BOOL fContinueWysi;
  1101. BOOL fContinueAveraging;
  1102. long durSum = 0;
  1103. long dupSum = 0;
  1104. long dupErrLast = 0;
  1105. long MagicConstant;
  1106. long durRightMax;
  1107. long dupIdeal;
  1108. long dupAdjust;
  1109. BOOL fInSpaces;
  1110. Assert (plsgrchnk->clsgrchnk > 0);
  1111. ptxtobj = (PTXTOBJ)plsgrchnk->plschnk[0].pdobj;
  1112. plnobj = ptxtobj->plnobj;
  1113. pilsobj = plnobj->pilsobj;
  1114. if (pilsobj->fPresEqualRef)
  1115. return;
  1116. SetMagicConstant();
  1117. rgdur = pilsobj->pdur;
  1118. rgdup = plnobj->pdup;
  1119. rgwch = pilsobj->pwchOrig;
  1120. fContinueWysi = fFalse;
  1121. fContinueAveraging = fFalse;
  1122. itxtobj = 0;
  1123. while(itxtobj < (long)plsgrchnk->clsgrchnk)
  1124. {
  1125. ptxtobj = (PTXTOBJ) plsgrchnk->plschnk[itxtobj].pdobj;
  1126. Assert(ptxtobj->txtkind != txtkindTab);
  1127. Assert(!(ptxtobj->txtf & txtfGlyphBased));
  1128. if (FAdjustable(ptxtobj))
  1129. {
  1130. fInSpaces = ptxtobj->txtkind == txtkindSpecSpace || ptxtobj->txtkind == txtkindNonBreakSpace;
  1131. fContinueAveraging = fContinueAveraging && !(plsgrchnk->pcont[itxtobj] & fcontNonTextBefore);
  1132. iwch = ptxtobj->iwchFirst;
  1133. iwchLim = ptxtobj->iwchLim;
  1134. while (iwch < iwchLim)
  1135. {
  1136. if (!fContinueAveraging)
  1137. {
  1138. fContinueAveraging = fTrue;
  1139. if (!fContinueWysi)
  1140. {
  1141. fContinueWysi = fTrue;
  1142. durSum = rgdur[iwch];
  1143. if (durSum <= durRightMax)
  1144. {
  1145. dupIdeal = UpFromUrFast(durSum);
  1146. if (dupIdeal < 0)
  1147. dupIdeal = 0;
  1148. dupErrLast = rgdup[iwch] - dupIdeal;
  1149. iwchPrev = iwch;
  1150. if (dupErrLast > dupBigError && rgdup[iwch] > 0)
  1151. {
  1152. rgdup[iwch]--;
  1153. }
  1154. else if (dupErrLast < -dupBigError)
  1155. {
  1156. rgdup[iwch]++;
  1157. }
  1158. dupSum = rgdup[iwch];
  1159. Assert(dupSum >= 0);
  1160. }
  1161. else
  1162. {
  1163. rgdup[iwch] = UpFromUr(lstflow, &pilsobj->lsdevres, durSum);
  1164. dupSum = rgdup[iwch];
  1165. /* Nothing else is set here because inside following while loop, first IF
  1166. will be FALSE and loop will be terminated
  1167. */
  1168. }
  1169. iwch++;
  1170. }
  1171. else
  1172. {
  1173. durSum += rgdur[iwch];
  1174. if (durSum <= durRightMax)
  1175. {
  1176. dupIdeal = UpFromUrFast(durSum) - dupSum;
  1177. dupErrLast = rgdup[iwch] - dupIdeal;
  1178. iwchPrev = iwch;
  1179. if (dupErrLast > dupBigError && rgdup[iwch] > 0)
  1180. {
  1181. rgdup[iwch]--;
  1182. }
  1183. else if (dupErrLast < -dupBigError)
  1184. {
  1185. rgdup[iwch]++;
  1186. }
  1187. dupSum += rgdup[iwch];
  1188. iwch++;
  1189. }
  1190. else
  1191. {
  1192. durSum -= rgdur[iwch];
  1193. /* Small triangle. Strictly speaking we could change nothing here
  1194. but it is cleaner to keep invariants in order.
  1195. Nothing else is set here because inside following while loop, first IF will
  1196. be FALSE and loop will be terminated.
  1197. */
  1198. }
  1199. }
  1200. }
  1201. while(iwch < iwchLim /* && fContinueWysi --replaced by break*/)
  1202. {
  1203. durSum += rgdur[iwch];
  1204. if (durSum <= durRightMax)
  1205. {
  1206. /* here modified David Bangs algorithm starts */
  1207. dupIdeal = UpFromUrFast(durSum) - dupSum;
  1208. Assert(dupIdeal >= 0);
  1209. dupErrLast = rgdup[iwch] - dupIdeal;
  1210. if (dupErrLast != 0 && (rgwch[iwch] == pilsobj->wchSpace || fInSpaces))
  1211. {
  1212. if (dupErrLast > 0)
  1213. {
  1214. dupAdjust = min(rgdup[iwch] >> 1, dupErrLast);
  1215. rgdup[iwch] -= dupAdjust;
  1216. }
  1217. else
  1218. {
  1219. Assert(dupErrLast < 0);
  1220. rgdup[iwch] -= dupErrLast;
  1221. }
  1222. }
  1223. else if (dupErrLast > dupBigError)
  1224. {
  1225. dupAdjust = (dupErrLast - 1) >> 1;
  1226. rgdup[iwchPrev] -= dupAdjust;
  1227. dupSum -= dupAdjust;
  1228. rgdup[iwch] -= dupAdjust;
  1229. }
  1230. else if (dupErrLast < -dupBigError)
  1231. {
  1232. dupAdjust = -((-dupErrLast - 1) >> 1);
  1233. rgdup[iwchPrev] -= dupAdjust;
  1234. dupSum -= dupAdjust;
  1235. rgdup[iwch] -= dupAdjust;
  1236. }
  1237. dupSum += rgdup[iwch];
  1238. iwchPrev = iwch;
  1239. /* here modified David Bangs algorithm stops */
  1240. iwch++;
  1241. }
  1242. else
  1243. {
  1244. fContinueWysi = fFalse;
  1245. fContinueAveraging = fFalse;
  1246. break;
  1247. }
  1248. }
  1249. }
  1250. }
  1251. else
  1252. {
  1253. fContinueAveraging = fFalse;
  1254. }
  1255. itxtobj++;
  1256. }
  1257. return;
  1258. }
  1259. #endif /* FUTURE */