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

725 lines
23 KiB

  1. #include <limits.h>
  2. #include "lsmem.h"
  3. #include "lstxtbr1.h"
  4. #include "lstxtbrs.h"
  5. #include "lstxtmap.h"
  6. #include "lsdntext.h"
  7. #include "brko.h"
  8. #include "locchnk.h"
  9. #include "locchnk.h"
  10. #include "posichnk.h"
  11. #include "objdim.h"
  12. #include "lstxtffi.h"
  13. #include "txtils.h"
  14. #include "txtln.h"
  15. #include "txtobj.h"
  16. static void TruncateGlyphBased(PTXTOBJ ptxtobj, long itxtobj, long urTotal, long urColumnMax,
  17. PPOSICHNK pposichnk);
  18. /* Export Functions Implementation */
  19. /* Q U I C K B R E A K T E X T */
  20. /*----------------------------------------------------------------------------
  21. %%Function: QuickBreakText
  22. %%Contact: sergeyge
  23. Breaks the line if it is easy to do, namely:
  24. -- break-character is space
  25. -- previous character is not space
  26. ----------------------------------------------------------------------------*/
  27. LSERR QuickBreakText(PDOBJ pdobj, BOOL* pfSuccessful, LSDCP* pdcpBreak, POBJDIM pobjdim)
  28. {
  29. LSERR lserr;
  30. PILSOBJ pilsobj;
  31. PTXTOBJ ptxtobj;
  32. long iwchSpace;
  33. long dur;
  34. *pfSuccessful = fFalse;
  35. ptxtobj = (PTXTOBJ)pdobj;
  36. pilsobj = ptxtobj->plnobj->pilsobj;
  37. Assert(!(pilsobj->grpf & fTxtDoHyphenation));
  38. Assert(!(pilsobj->grpf & fTxtWrapTrailingSpaces));
  39. Assert(!(pilsobj->grpf & fTxtWrapAllSpaces));
  40. Assert(!(ptxtobj->txtf & txtfGlyphBased));
  41. if (ptxtobj->txtkind == txtkindRegular)
  42. {
  43. if (!(pilsobj->grpf & fTxtApplyBreakingRules))
  44. {
  45. if (ptxtobj->u.reg.iwSpacesLim > ptxtobj->u.reg.iwSpacesFirst)
  46. {
  47. iwchSpace = pilsobj->pwSpaces[ptxtobj->u.reg.iwSpacesLim - 1];
  48. Assert(iwchSpace < ptxtobj->iwchLim - 1); /* formatting never stops at space */
  49. if (iwchSpace + 1 - ptxtobj->iwchFirst > ptxtobj->u.reg.iwSpacesLim - ptxtobj->u.reg.iwSpacesFirst)
  50. {
  51. *pfSuccessful = fTrue;
  52. *pdcpBreak = iwchSpace - ptxtobj->iwchFirst + 1;
  53. lserr = CalcPartWidths(ptxtobj, *pdcpBreak, pobjdim, &dur);
  54. Assert(lserr == lserrNone);
  55. pobjdim->dur = dur;
  56. Assert(*pdcpBreak > 1);
  57. ptxtobj->iwchLim = iwchSpace + 1;
  58. }
  59. }
  60. }
  61. else
  62. {
  63. LSCP cpFirst;
  64. PLSRUN plsrun;
  65. long iwchFirst;
  66. long iwchCur;
  67. long iwchInSpace;
  68. BRKCLS brkclsFollowingCache;
  69. BRKCLS brkclsLeading;
  70. BRKCLS brkclsFollowing;
  71. Assert(pilsobj->pwchOrig[ptxtobj->iwchLim - 1] != pilsobj->wchSpace);
  72. lserr = LsdnGetCpFirst(pilsobj->plsc, ptxtobj->plsdnUpNode, &cpFirst);
  73. Assert(lserr == lserrNone);
  74. lserr = LsdnGetPlsrun(pilsobj->plsc, ptxtobj->plsdnUpNode, &plsrun);
  75. Assert(lserr == lserrNone);
  76. iwchFirst = ptxtobj->iwchFirst;
  77. if (ptxtobj->u.reg.iwSpacesLim > ptxtobj->u.reg.iwSpacesFirst)
  78. iwchFirst = pilsobj->pwSpaces[ptxtobj->u.reg.iwSpacesLim - 1] + 1;
  79. iwchCur = ptxtobj->iwchLim - 1;
  80. lserr =(*pilsobj->plscbk->pfnGetBreakingClasses)(pilsobj->pols, plsrun,
  81. cpFirst + (iwchCur - ptxtobj->iwchFirst),
  82. pilsobj->pwchOrig[iwchCur], &brkclsLeading, &brkclsFollowingCache);
  83. if (lserr != lserrNone) return lserr;
  84. Assert(brkclsLeading < pilsobj->cBreakingClasses && brkclsFollowingCache < pilsobj->cBreakingClasses);
  85. iwchCur--;
  86. while (!*pfSuccessful && iwchCur >= iwchFirst)
  87. {
  88. brkclsFollowing = brkclsFollowingCache;
  89. lserr =(*pilsobj->plscbk->pfnGetBreakingClasses)(pilsobj->pols, plsrun,
  90. cpFirst + (iwchCur - ptxtobj->iwchFirst),
  91. pilsobj->pwchOrig[iwchCur], &brkclsLeading, &brkclsFollowingCache);
  92. if (lserr != lserrNone) return lserr;
  93. Assert(brkclsLeading < pilsobj->cBreakingClasses && brkclsFollowingCache < pilsobj->cBreakingClasses);
  94. *pfSuccessful = FCanBreak(pilsobj, brkclsLeading, brkclsFollowing);
  95. iwchCur --;
  96. }
  97. if (!*pfSuccessful && iwchFirst > ptxtobj->iwchFirst)
  98. {
  99. Assert(pilsobj->pwchOrig[iwchCur] == pilsobj->wchSpace);
  100. iwchCur--;
  101. for (iwchInSpace = iwchCur; iwchInSpace >= ptxtobj->iwchFirst &&
  102. pilsobj->pwchOrig[iwchInSpace] == pilsobj->wchSpace; iwchInSpace--);
  103. if (iwchInSpace >= ptxtobj->iwchFirst)
  104. {
  105. brkclsFollowing = brkclsFollowingCache;
  106. lserr =(*pilsobj->plscbk->pfnGetBreakingClasses)(pilsobj->pols, plsrun,
  107. cpFirst + (iwchInSpace - ptxtobj->iwchFirst),
  108. pilsobj->pwchOrig[iwchInSpace], &brkclsLeading, &brkclsFollowingCache);
  109. if (lserr != lserrNone) return lserr;
  110. Assert(brkclsLeading < pilsobj->cBreakingClasses && brkclsFollowingCache < pilsobj->cBreakingClasses);
  111. *pfSuccessful = FCanBreakAcrossSpaces(pilsobj, brkclsLeading, brkclsFollowing);
  112. }
  113. }
  114. if (*pfSuccessful)
  115. {
  116. *pdcpBreak = iwchCur + 1 - ptxtobj->iwchFirst + 1;
  117. lserr = CalcPartWidths(ptxtobj, *pdcpBreak, pobjdim, &dur);
  118. Assert(lserr == lserrNone);
  119. pobjdim->dur = dur;
  120. Assert(*pdcpBreak >= 1);
  121. ptxtobj->iwchLim = iwchCur + 2;
  122. }
  123. }
  124. }
  125. return lserrNone;
  126. }
  127. /* S E T B R E A K T E X T */
  128. /*----------------------------------------------------------------------------
  129. %%Function:SetBreakText
  130. %%Contact: sergeyge
  131. ----------------------------------------------------------------------------*/
  132. LSERR WINAPI SetBreakText(PDOBJ pdobj, BRKKIND brkkind, DWORD nBreakRec, BREAKREC* rgBreakRec, DWORD* pnActual)
  133. {
  134. LSERR lserr;
  135. PLNOBJ plnobj;
  136. PILSOBJ pilsobj;
  137. PTXTOBJ ptxtobj;
  138. long iwchLim;
  139. long ibrkinf;
  140. BREAKINFO* pbrkinf;
  141. BOOL fInChildList;
  142. Unreferenced(nBreakRec);
  143. Unreferenced(rgBreakRec);
  144. *pnActual = 0;
  145. ptxtobj = (PTXTOBJ) pdobj;
  146. plnobj = ptxtobj->plnobj;
  147. pilsobj = plnobj->pilsobj;
  148. for (ibrkinf = 0; ibrkinf < (long)pilsobj->breakinfMac &&
  149. (pilsobj->pbreakinf[ibrkinf].pdobj != pdobj || pilsobj->pbreakinf[ibrkinf].brkkind != brkkind);
  150. ibrkinf++ );
  151. if (ibrkinf < (long)pilsobj->breakinfMac)
  152. {
  153. pbrkinf = &pilsobj->pbreakinf[ibrkinf];
  154. switch (pbrkinf->brkt)
  155. {
  156. case brktNormal:
  157. iwchLim = ptxtobj->iwchFirst + pbrkinf->dcp;
  158. if (iwchLim < ptxtobj->iwchLim)
  159. ptxtobj->iwchLim = iwchLim;
  160. ptxtobj->igindLim = pbrkinf->u.normal.igindLim;
  161. if (pbrkinf->u.normal.durFix != 0)
  162. {
  163. Assert(!(ptxtobj->txtf & txtfGlyphBased));
  164. pilsobj->pdur[ptxtobj->iwchLim - 1] += pbrkinf->u.normal.durFix;
  165. Assert (pilsobj->pdurRight != NULL);
  166. pilsobj->pdurRight[ptxtobj->iwchLim - 1] = 0;
  167. }
  168. break;
  169. case brktHyphen:
  170. iwchLim = pbrkinf->u.hyphen.iwchLim;
  171. ptxtobj->iwchLim = iwchLim;
  172. plnobj->pdobjHyphen = ptxtobj;
  173. plnobj->dwchYsr = pbrkinf->u.hyphen.dwchYsr;
  174. pilsobj->pwchOrig[iwchLim - 1] = pilsobj->wchHyphen;
  175. plnobj->pwch[iwchLim - 1] = pilsobj->wchHyphen;
  176. if (pbrkinf->u.hyphen.gindHyphen != 0)
  177. {
  178. ptxtobj->igindLim = pbrkinf->u.hyphen.igindHyphen + 1;
  179. plnobj->pgind[pbrkinf->u.hyphen.igindHyphen] = pbrkinf->u.hyphen.gindHyphen;
  180. pilsobj->pdurGind[pbrkinf->u.hyphen.igindHyphen] = pbrkinf->u.hyphen.durHyphen;
  181. plnobj->pdupGind[pbrkinf->u.hyphen.igindHyphen] = pbrkinf->u.hyphen.dupHyphen;
  182. if (pilsobj->pduGright != NULL)
  183. pilsobj->pduGright[pbrkinf->u.hyphen.igindHyphen] = 0;
  184. /* REVIEW sergeyge: It would be nice to move this activity to lstxtmap module */
  185. plnobj->pgmap[iwchLim - 1] = (WORD)(pbrkinf->u.hyphen.igindHyphen -
  186. (ptxtobj->igindFirst - plnobj->pgmap[ptxtobj->iwchFirst]));
  187. pilsobj->ptxtinf[iwchLim - 1].fOneToOne = fTrue;
  188. pilsobj->ptxtinf[iwchLim - 1].fFirstInContext = fTrue;
  189. pilsobj->ptxtinf[iwchLim - 1].fLastInContext = fTrue;
  190. pilsobj->pginf[pbrkinf->u.hyphen.igindHyphen] = ginffOneToOne |
  191. ginffFirstInContext | ginffLastInContext;
  192. }
  193. else
  194. {
  195. pilsobj->pdur[iwchLim - 1] = pbrkinf->u.hyphen.durHyphen;
  196. plnobj->pdup[iwchLim - 1] = pbrkinf->u.hyphen.dupHyphen;
  197. if (pilsobj->pdurRight != NULL)
  198. pilsobj->pdurRight[iwchLim - 1] = 0;
  199. if (pilsobj->pdurLeft != NULL)
  200. pilsobj->pdurLeft[iwchLim - 1] = 0;
  201. }
  202. if (pbrkinf->u.hyphen.wchPrev != 0)
  203. {
  204. pilsobj->pwchOrig[iwchLim - 2] = pbrkinf->u.hyphen.wchPrev;
  205. plnobj->pwch[iwchLim - 2] = pbrkinf->u.hyphen.wchPrev;
  206. if (pbrkinf->u.hyphen.gindPrev != 0)
  207. {
  208. plnobj->pgind[pbrkinf->u.hyphen.igindPrev] = pbrkinf->u.hyphen.gindPrev;
  209. pilsobj->pdurGind[pbrkinf->u.hyphen.igindPrev] = pbrkinf->u.hyphen.durPrev;
  210. plnobj->pdupGind[pbrkinf->u.hyphen.igindPrev] = pbrkinf->u.hyphen.dupPrev;
  211. if (pilsobj->pduGright != NULL)
  212. pilsobj->pduGright[pbrkinf->u.hyphen.igindPrev] = 0;
  213. /* REVIEW sergeyge: It would be nice to move this activity to lstxtmap module */
  214. /* If Prev glyph is added the following activity is required;
  215. If it is just replaced, we assign the same values,because ProcessYsr
  216. would not allow replace not OneToOne character
  217. */
  218. plnobj->pgmap[iwchLim - 2] = (WORD)(pbrkinf->u.hyphen.igindPrev -
  219. (ptxtobj->igindFirst - plnobj->pgmap[ptxtobj->iwchFirst]));
  220. pilsobj->ptxtinf[iwchLim - 2].fOneToOne = fTrue;
  221. pilsobj->ptxtinf[iwchLim - 2].fFirstInContext = fTrue;
  222. pilsobj->ptxtinf[iwchLim - 2].fLastInContext = fTrue;
  223. pilsobj->pginf[pbrkinf->u.hyphen.igindPrev] = ginffOneToOne |
  224. ginffFirstInContext | ginffLastInContext;
  225. }
  226. else
  227. {
  228. pilsobj->pdur[iwchLim - 2] = pbrkinf->u.hyphen.durPrev;
  229. plnobj->pdup[iwchLim - 2] = pbrkinf->u.hyphen.dupPrev;
  230. if (pilsobj->pdurRight != NULL)
  231. pilsobj->pdurRight[iwchLim - 2] = 0;
  232. if (pilsobj->pdurLeft != NULL)
  233. pilsobj->pdurLeft[iwchLim - 2] = 0;
  234. }
  235. }
  236. if (pbrkinf->u.hyphen.wchPrevPrev != 0)
  237. {
  238. pilsobj->pwchOrig[iwchLim - 3] = pbrkinf->u.hyphen.wchPrevPrev;
  239. plnobj->pwch[iwchLim - 3] = pbrkinf->u.hyphen.wchPrevPrev;
  240. if (pbrkinf->u.hyphen.gindPrevPrev != 0)
  241. {
  242. plnobj->pgind[pbrkinf->u.hyphen.igindPrevPrev] = pbrkinf->u.hyphen.gindPrevPrev;
  243. pilsobj->pdurGind[pbrkinf->u.hyphen.igindPrevPrev] = pbrkinf->u.hyphen.durPrevPrev;
  244. plnobj->pdupGind[pbrkinf->u.hyphen.igindPrevPrev] = pbrkinf->u.hyphen.dupPrevPrev;
  245. if (pilsobj->pduGright != NULL)
  246. pilsobj->pduGright[pbrkinf->u.hyphen.igindPrevPrev] = 0;
  247. }
  248. else
  249. {
  250. pilsobj->pdur[iwchLim - 3] = pbrkinf->u.hyphen.durPrevPrev;
  251. plnobj->pdup[iwchLim - 3] = pbrkinf->u.hyphen.dupPrevPrev;
  252. if (pilsobj->pdurRight != NULL)
  253. pilsobj->pdurRight[iwchLim - 3] = 0;
  254. if (pilsobj->pdurLeft != NULL)
  255. pilsobj->pdurLeft[iwchLim - 3] = 0;
  256. }
  257. }
  258. if (pbrkinf->u.hyphen.ddurDnodePrev != 0)
  259. {
  260. lserr = LsdnResetWidthInPreviousDnodes(pilsobj->plsc, ptxtobj->plsdnUpNode,
  261. pbrkinf->u.hyphen.ddurDnodePrev, 0);
  262. if (lserr != lserrNone) return lserr;
  263. }
  264. lserr = LsdnSetHyphenated(pilsobj->plsc);
  265. if (lserr != lserrNone) return lserr;
  266. break;
  267. case brktNonReq:
  268. Assert(pbrkinf->dcp == 1);
  269. iwchLim = pbrkinf->u.nonreq.iwchLim;
  270. ptxtobj->iwchLim = iwchLim;
  271. Assert(iwchLim == ptxtobj->iwchFirst + pbrkinf->u.nonreq.dwchYsr);
  272. plnobj->pdobjHyphen = ptxtobj;
  273. plnobj->dwchYsr = pbrkinf->u.nonreq.dwchYsr;
  274. Assert(ptxtobj->iwchLim == iwchLim);
  275. pilsobj->pwchOrig[iwchLim - 1] = pilsobj->wchHyphen;
  276. plnobj->pwch[iwchLim - 1] = pbrkinf->u.nonreq.wchHyphenPres;
  277. pilsobj->pdur[iwchLim - 1] = pbrkinf->u.nonreq.durHyphen;
  278. plnobj->pdup[iwchLim - 1] = pbrkinf->u.nonreq.dupHyphen;
  279. if (pilsobj->pdurRight != NULL)
  280. pilsobj->pdurRight[iwchLim - 1] = 0;
  281. if (pilsobj->pdurLeft != NULL)
  282. pilsobj->pdurLeft[iwchLim - 1] = 0;
  283. if (pbrkinf->u.nonreq.wchPrev != 0)
  284. {
  285. pilsobj->pwchOrig[iwchLim - 2] = pbrkinf->u.nonreq.wchPrev;
  286. plnobj->pwch[iwchLim - 2] = pbrkinf->u.nonreq.wchPrev;
  287. if (pbrkinf->u.nonreq.gindPrev != 0)
  288. {
  289. plnobj->pgind[pbrkinf->u.nonreq.igindPrev] = pbrkinf->u.nonreq.gindPrev;
  290. pilsobj->pdurGind[pbrkinf->u.nonreq.igindPrev] = pbrkinf->u.nonreq.durPrev;
  291. plnobj->pdupGind[pbrkinf->u.nonreq.igindPrev] = pbrkinf->u.nonreq.dupPrev;
  292. if (pilsobj->pduGright != NULL)
  293. pilsobj->pduGright[pbrkinf->u.nonreq.igindPrev] = 0;
  294. }
  295. else
  296. {
  297. pilsobj->pdur[iwchLim - 2] = pbrkinf->u.nonreq.durPrev;
  298. plnobj->pdup[iwchLim - 2] = pbrkinf->u.nonreq.dupPrev;
  299. if (pilsobj->pdurRight != NULL)
  300. pilsobj->pdurRight[iwchLim - 2] = 0;
  301. if (pilsobj->pdurLeft != NULL)
  302. pilsobj->pdurLeft[iwchLim - 2] = 0;
  303. }
  304. }
  305. if (pbrkinf->u.nonreq.wchPrevPrev != 0)
  306. {
  307. pilsobj->pwchOrig[iwchLim - 3] = pbrkinf->u.nonreq.wchPrevPrev;
  308. plnobj->pwch[iwchLim - 3] = pbrkinf->u.nonreq.wchPrevPrev;
  309. if (pbrkinf->u.nonreq.gindPrevPrev != 0)
  310. {
  311. plnobj->pgind[pbrkinf->u.nonreq.igindPrevPrev] = pbrkinf->u.nonreq.gindPrevPrev;
  312. pilsobj->pdurGind[pbrkinf->u.nonreq.igindPrevPrev] = pbrkinf->u.nonreq.durPrevPrev;
  313. plnobj->pdupGind[pbrkinf->u.nonreq.igindPrevPrev] = pbrkinf->u.nonreq.dupPrevPrev;
  314. if (pilsobj->pduGright != NULL)
  315. pilsobj->pduGright[pbrkinf->u.nonreq.igindPrevPrev] = 0;
  316. }
  317. else
  318. {
  319. pilsobj->pdur[iwchLim - 3] = pbrkinf->u.nonreq.durPrevPrev;
  320. plnobj->pdup[iwchLim - 3] = pbrkinf->u.nonreq.dupPrevPrev;
  321. if (pilsobj->pdurRight != NULL)
  322. pilsobj->pdurRight[iwchLim - 3] = 0;
  323. if (pilsobj->pdurLeft != NULL)
  324. pilsobj->pdurLeft[iwchLim - 3] = 0;
  325. }
  326. }
  327. if (pbrkinf->u.nonreq.ddurDnodePrev != 0 || pbrkinf->u.nonreq.ddurDnodePrevPrev != 0)
  328. {
  329. lserr = LsdnResetWidthInPreviousDnodes(pilsobj->plsc, ptxtobj->plsdnUpNode,
  330. pbrkinf->u.nonreq.ddurDnodePrev, pbrkinf->u.nonreq.ddurDnodePrevPrev);
  331. if (lserr != lserrNone) return lserr;
  332. }
  333. lserr = LsdnFInChildList(pilsobj->plsc, ptxtobj->plsdnUpNode, &fInChildList);
  334. Assert(lserr == lserrNone);
  335. if (!fInChildList)
  336. {
  337. lserr = LsdnSetHyphenated(pilsobj->plsc);
  338. Assert(lserr == lserrNone);
  339. }
  340. break;
  341. case brktOptBreak:
  342. break;
  343. default:
  344. NotReached();
  345. }
  346. }
  347. else
  348. {
  349. /* REVIEW sergeyge: we should return to the discussion of brkkind later.
  350. At the moment manager passes brkkindNext if during NextBreak object retrurned break
  351. with dcp == 0 and break was snapped to the previous DNODE inside chunk
  352. */
  353. // Assert(ptxtobj->iwchLim == ptxtobj->iwchFirst || ptxtobj->txtkind == txtkindEOL ||
  354. // brkkind == brkkindImposedAfter);
  355. }
  356. return lserrNone;
  357. }
  358. /* F O R C E B R E A K T E X T */
  359. /*----------------------------------------------------------------------------
  360. %%Function: ForceBreakText
  361. %%Contact: sergeyge
  362. Force break method.
  363. Breaks behind all characters in dobj, if they fit in line, or
  364. dobj consists of one character which is the first on the line,
  365. Breaks before the last character otherwise.
  366. ----------------------------------------------------------------------------*/
  367. LSERR WINAPI ForceBreakText(PCLOCCHNK plocchnk, PCPOSICHNK pposichnk, PBRKOUT ptbo)
  368. {
  369. LSERR lserr;
  370. PILSOBJ pilsobj;
  371. PTXTOBJ ptxtobjLast;
  372. long itxtobjLast;
  373. long dcpLast;
  374. OBJDIM objdim;
  375. BREAKINFO* pbrkinf;
  376. long igindLim;
  377. pilsobj = ((PTXTOBJ)plocchnk->plschnk[0].pdobj)->plnobj->pilsobj;
  378. memset(ptbo, 0, sizeof(*ptbo));
  379. ptbo->fSuccessful = fTrue;
  380. igindLim = 0;
  381. /* Outside means before for ForceBreak */
  382. if (pposichnk->ichnk == ichnkOutside)
  383. {
  384. itxtobjLast = 0;
  385. ptxtobjLast = (PTXTOBJ)plocchnk->plschnk[itxtobjLast].pdobj;
  386. dcpLast = 1;
  387. }
  388. else
  389. {
  390. itxtobjLast = pposichnk->ichnk;
  391. ptxtobjLast = (PTXTOBJ)plocchnk->plschnk[itxtobjLast].pdobj;
  392. Assert(ptxtobjLast->iwchFirst + pposichnk->dcp > 0);
  393. Assert(pposichnk->dcp > 0);
  394. dcpLast = pposichnk->dcp;
  395. if (pilsobj->fTruncatedBefore)
  396. {
  397. BOOL fInChildList;
  398. lserr = LsdnFInChildList(pilsobj->plsc, ptxtobjLast->plsdnUpNode, &fInChildList);
  399. Assert(lserr == lserrNone);
  400. if (!fInChildList)
  401. {
  402. dcpLast++;
  403. Assert(ptxtobjLast->iwchLim + 1 >= ptxtobjLast->iwchFirst + dcpLast);
  404. /* possible because if truncation returned dcp == 0, manager has reset it to previous dnode */
  405. if (ptxtobjLast->iwchLim + 1 == ptxtobjLast->iwchFirst + dcpLast)
  406. {
  407. itxtobjLast++;
  408. Assert(itxtobjLast < (long)plocchnk->clschnk);
  409. ptxtobjLast = (PTXTOBJ)plocchnk->plschnk[itxtobjLast].pdobj;
  410. dcpLast = 1;
  411. }
  412. }
  413. }
  414. }
  415. ptbo->posichnk.ichnk = itxtobjLast;
  416. lserr = LsdnGetObjDim(pilsobj->plsc, ptxtobjLast->plsdnUpNode, &ptbo->objdim);
  417. if (lserr != lserrNone) return lserr;
  418. if (plocchnk->lsfgi.fFirstOnLine && itxtobjLast == 0 && ptxtobjLast->iwchLim == ptxtobjLast->iwchFirst)
  419. {
  420. Assert(!(ptxtobjLast->txtf & txtfGlyphBased));
  421. ptbo->posichnk.dcp = 1;
  422. }
  423. else
  424. {
  425. if (ptxtobjLast->txtf & txtfGlyphBased)
  426. {
  427. Assert(ptxtobjLast->iwchLim > ptxtobjLast->iwchFirst);
  428. if (!plocchnk->lsfgi.fFirstOnLine || itxtobjLast > 0 || dcpLast > 1)
  429. {
  430. ptbo->posichnk.dcp = 0;
  431. if (dcpLast > 1)
  432. ptbo->posichnk.dcp = DcpAfterContextFromDcp(ptxtobjLast, dcpLast - 1);
  433. }
  434. else
  435. ptbo->posichnk.dcp = DcpAfterContextFromDcp(ptxtobjLast, 1);
  436. igindLim = IgindFirstFromIwch(ptxtobjLast, ptxtobjLast->iwchFirst + ptbo->posichnk.dcp);
  437. lserr = CalcPartWidthsGlyphs(ptxtobjLast, ptbo->posichnk.dcp, &objdim, &ptbo->objdim.dur);
  438. if (lserr != lserrNone) return lserr;
  439. }
  440. else
  441. {
  442. if (!plocchnk->lsfgi.fFirstOnLine || itxtobjLast > 0 || dcpLast > 1)
  443. {
  444. ptbo->posichnk.dcp = dcpLast - 1;
  445. lserr = CalcPartWidths(ptxtobjLast, ptbo->posichnk.dcp, &objdim, &ptbo->objdim.dur);
  446. if (lserr != lserrNone) return lserr;
  447. }
  448. else
  449. {
  450. if (ptxtobjLast->iwchLim > ptxtobjLast->iwchFirst)
  451. {
  452. lserr = CalcPartWidths(ptxtobjLast, 1, &objdim, &ptbo->objdim.dur);
  453. }
  454. else
  455. {
  456. ptbo->objdim.dur = 0;
  457. }
  458. ptbo->posichnk.dcp = 1;
  459. }
  460. }
  461. }
  462. /* Don't check that Heights of this dobj should be ignored, since in normal case, if there were spaces
  463. there was also break */
  464. lserr = GetPbrkinf(pilsobj, (PDOBJ)ptxtobjLast, brkkindForce, &pbrkinf);
  465. if (lserr != lserrNone) return lserr;
  466. pbrkinf->pdobj = (PDOBJ)ptxtobjLast;
  467. pbrkinf->brkkind = brkkindForce;
  468. pbrkinf->dcp = ptbo->posichnk.dcp;
  469. pbrkinf->u.normal.igindLim = igindLim;
  470. Assert(pbrkinf->brkt == brktNormal);
  471. Assert(pbrkinf->u.normal.durFix == 0);
  472. return lserrNone;
  473. }
  474. /* T R U N C A T E T E X T */
  475. /*----------------------------------------------------------------------------
  476. %%Function: TruncateText
  477. %%Contact: sergeyge
  478. Truncates text chunk
  479. ----------------------------------------------------------------------------*/
  480. LSERR WINAPI TruncateText(PCLOCCHNK plocchnk, PPOSICHNK pposichnk)
  481. {
  482. LSERR lserr;
  483. PILSOBJ pilsobj;
  484. PTXTOBJ ptxtobj = NULL;
  485. long itxtobj;
  486. long iwchCur;
  487. long iwchFirst;
  488. long* pdur;
  489. long urColumnMax;
  490. long urTotal;
  491. OBJDIM objdim;
  492. BOOL fTruncateBefore;
  493. pilsobj = ((PTXTOBJ)plocchnk->plschnk[0].pdobj)->plnobj->pilsobj;
  494. urColumnMax = plocchnk->lsfgi.urColumnMax;
  495. Assert(plocchnk->ppointUvLoc[0].u <= urColumnMax);
  496. for (itxtobj = plocchnk->clschnk - 1; plocchnk->ppointUvLoc[itxtobj].u > urColumnMax; itxtobj--);
  497. ptxtobj = (PTXTOBJ)plocchnk->plschnk[itxtobj].pdobj;
  498. lserr = LsdnGetObjDim(pilsobj->plsc, ptxtobj->plsdnUpNode, &objdim);
  499. if (lserr != lserrNone) return lserr;
  500. urTotal = plocchnk->ppointUvLoc[itxtobj].u + objdim.dur;
  501. Assert(urTotal > urColumnMax);
  502. if (ptxtobj->txtf & txtfGlyphBased)
  503. {
  504. TruncateGlyphBased(ptxtobj, itxtobj, urTotal, urColumnMax, pposichnk);
  505. return lserrNone;
  506. }
  507. iwchCur = ptxtobj->iwchLim;
  508. iwchFirst = ptxtobj->iwchFirst;
  509. pdur = pilsobj->pdur;
  510. while (urTotal > urColumnMax)
  511. {
  512. iwchCur--;
  513. urTotal -= pdur[iwchCur];
  514. }
  515. Assert(iwchCur >= iwchFirst);
  516. /* REVIEW sergeyge--- extremely ugly condition,
  517. and still slightly incompatible with Word.
  518. To make it more compatible txtkind should be checked against
  519. OptBreak, OptNonBreak, NonReqHyphen
  520. If we won't check it for OptBreak,..., we will have different break point for the Visi case
  521. Before fix for bug 227 we checked also that prev char is not space, but now it is not important.
  522. */
  523. if ((pilsobj->grpf & fTxtFCheckTruncateBefore) && iwchCur > 0 &&
  524. /* We enforce that there is no funny logic if EOL is truncation point */
  525. ptxtobj->txtkind != txtkindEOL &&
  526. !(iwchCur == iwchFirst && itxtobj > 0 &&
  527. ((PTXTOBJ)plocchnk->plschnk[itxtobj-1].pdobj)->txtkind != txtkindRegular &&
  528. ((PTXTOBJ)plocchnk->plschnk[itxtobj-1].pdobj)->txtkind != txtkindHardHyphen &&
  529. ((PTXTOBJ)plocchnk->plschnk[itxtobj-1].pdobj)->txtkind != txtkindYsrChar)
  530. )
  531. {
  532. BOOL fInChildList;
  533. lserr = LsdnFInChildList(pilsobj->plsc, ptxtobj->plsdnUpNode, &fInChildList);
  534. Assert(lserr == lserrNone);
  535. if (!fInChildList)
  536. {
  537. PLSRUN plsrunCur = plocchnk->plschnk[itxtobj].plsrun;
  538. LSCP cpCur = plocchnk->plschnk[itxtobj].cpFirst + (iwchCur - iwchFirst);
  539. long durCur = 0;
  540. PLSRUN plsrunPrev = NULL;
  541. WCHAR wchPrev = 0;
  542. LSCP cpPrev = -1;
  543. long durPrev = 0;
  544. if (iwchCur > iwchFirst)
  545. {
  546. plsrunPrev = plsrunCur;
  547. wchPrev = pilsobj->pwchOrig[iwchCur - 1];
  548. durPrev = pilsobj->pdur[iwchCur - 1];
  549. cpPrev = cpCur - 1;
  550. }
  551. else if (itxtobj > 0)
  552. {
  553. PTXTOBJ ptxtobjPrev = (PTXTOBJ)plocchnk->plschnk[itxtobj - 1].pdobj;
  554. long iwchPrev = ptxtobjPrev->iwchLim - 1;
  555. plsrunPrev= plocchnk->plschnk[itxtobj - 1].plsrun;
  556. wchPrev = pilsobj->pwchOrig[iwchPrev];
  557. durPrev = pilsobj->pdur[iwchPrev];
  558. cpPrev = plocchnk->plschnk[itxtobj-1].cpFirst + (iwchPrev - ptxtobjPrev->iwchFirst);
  559. }
  560. /* REVIEW sergeyge: dangerous change to fix bug 399. It looks correct, but might trigger some other
  561. incompatibility.
  562. */
  563. durCur = pilsobj->pdur[iwchCur];
  564. if (pilsobj->pdurRight != NULL)
  565. durCur -= pilsobj->pdurRight[iwchCur];
  566. lserr = (*pilsobj->plscbk->pfnFTruncateBefore)(pilsobj->pols,
  567. plsrunCur, cpCur, pilsobj->pwchOrig[iwchCur], durCur,
  568. plsrunPrev, cpPrev, wchPrev, durPrev,
  569. urTotal + durCur - urColumnMax, &fTruncateBefore);
  570. if (lserr != lserrNone) return lserr;
  571. if (fTruncateBefore && iwchCur > 0 && pdur[iwchCur-1] > 0)
  572. {
  573. iwchCur--;
  574. pilsobj->fTruncatedBefore = fTrue;
  575. }
  576. }
  577. }
  578. pposichnk->ichnk = itxtobj;
  579. pposichnk->dcp = iwchCur - iwchFirst + 1;
  580. return lserrNone;
  581. }
  582. /* internal functions implementation */
  583. static void TruncateGlyphBased(PTXTOBJ ptxtobj, long itxtobj, long urTotal, long urColumnMax,
  584. PPOSICHNK pposichnk)
  585. {
  586. PILSOBJ pilsobj;
  587. long iwchFirst;
  588. long iwchCur;
  589. long igindCur;
  590. long igindFirst;
  591. long* pdurGind;
  592. pilsobj= ptxtobj->plnobj->pilsobj;
  593. iwchFirst = ptxtobj->iwchFirst;
  594. igindCur = ptxtobj->igindLim;
  595. igindFirst = ptxtobj->igindFirst;
  596. pdurGind = pilsobj->pdurGind;
  597. while (urTotal > urColumnMax)
  598. {
  599. igindCur--;
  600. urTotal -= pdurGind[igindCur];
  601. }
  602. Assert(igindCur >= igindFirst);
  603. iwchCur = IwchFirstFromIgind(ptxtobj, igindCur);
  604. pposichnk->ichnk = itxtobj;
  605. pposichnk->dcp = iwchCur - iwchFirst + 1;
  606. }