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.

2743 lines
85 KiB

  1. #include "lsidefs.h"
  2. #include "break.h"
  3. #include "brko.h"
  4. #include "chnutils.h"
  5. #include "dninfo.h"
  6. #include "dnutils.h"
  7. #include "getfmtst.h"
  8. #include "iobj.h"
  9. #include "iobjln.h"
  10. #include "locchnk.h"
  11. #include "lsc.h"
  12. #include "lsdnode.h"
  13. #include "lsline.h"
  14. #include "lstext.h"
  15. #include "plocchnk.h"
  16. #include "posichnk.h"
  17. #include "setfmtst.h"
  18. #include "posinln.h"
  19. #include "lscfmtfl.h"
  20. #include "lsmem.h" /* memset() */
  21. #include "limits.h"
  22. static LSERR TruncateCore(
  23. PLSSUBL, /* IN: subline where to find truncation point */
  24. long, /* IN: urColumnMax */
  25. POSINLINE*, /* OUT:position of truncation point */
  26. BOOL*); /* OUT:fAllLineAfterRightMargin */
  27. static LSERR FindNextBreakCore(
  28. long, /* IN: urColumnMax */
  29. POSINLINE*, /* IN: start break search */
  30. BOOL, /* IN: to apply rules for first character to
  31. the first character of this subline */
  32. BOOL, /* IN: fStopped */
  33. BRKOUT*, /* OUT: breaking information */
  34. POSINLINE*, /* OUT: position of break */
  35. BRKKIND*); /* OUT: how dnode was broken */
  36. static LSERR FindPrevBreakCore(
  37. long, /* IN: urColumnMax */
  38. POSINLINE*, /* IN: start break search */
  39. BOOL, /* IN: to apply rules for first character to
  40. the first character of this subline */
  41. BRKOUT*, /* OUT: breaking information */
  42. POSINLINE*, /* OUT: position of break */
  43. BRKKIND*); /* OUT: how dnode was broken */
  44. static LSERR ForceBreakCore(
  45. long, /* IN: urColumnMax */
  46. POSINLINE*, /* IN: where to do force break */
  47. BOOL, /* IN: fStopped */
  48. BOOL, /* IN: to apply rules for first character to
  49. the first character of this subline */
  50. BOOL, /* IN: fAllLineAfterRightMargin */
  51. BRKOUT*, /* OUT: breaking information */
  52. POSINLINE*, /* OUT: position of break */
  53. BRKKIND*); /* OUT: how dnode was broken */
  54. static LSERR SetBreakCore(
  55. POSINLINE*, /* IN: where to do break */
  56. OBJDIM*, /* IN: objdim of break dnode */
  57. BRKKIND, /* IN: how break was found */
  58. BOOL, /* IN fHardStop */
  59. BOOL, /* IN: fGlueEop */
  60. DWORD, /* IN: size of the output array */
  61. BREAKREC*, /* OUT: output array of break records */
  62. DWORD*, /* OUT:actual number of records in array*/
  63. LSCP*, /* OUT: cpLim */
  64. LSDCP*, /* OUT dcpDepend */
  65. ENDRES*, /* OUT: endr */
  66. BOOL*); /* OUT fSuccessful: false means insufficient fetch */
  67. static void GetPosInLineTruncateFromCp(
  68. PLSSUBL, /* IN: subline */
  69. LSCP, /* IN: cp of a position */
  70. BOOL, /* direction of snaping */
  71. POSINLINE* ); /* OUT: position in a subline */
  72. static LSERR BreakTabPenSplat(
  73. PLOCCHNK, /* IN: chunk contains tab or pen */
  74. BOOL, /* IN: we are searching next break*/
  75. BOOL, /* IN: breakthrough tab */
  76. BOOL, /* IN: splat */
  77. BRKCOND, /* IN: condition of boundary break */
  78. OBJDIM*, /* IN: to fill in objdim of break */
  79. BRKOUT*); /* OUT: breaking information */
  80. static LSERR ForceBreakTabPenSplat(
  81. PLOCCHNK, /* IN: chunk contains tab or pen */
  82. OBJDIM*, /* IN: to fill in objdim of break */
  83. BRKOUT*); /* OUT: breaking information */
  84. static void FindFirstDnodeContainsRightMargin(
  85. long urColumnMax, /* IN: position of right margin */
  86. POSINLINE* pposinlineTruncate); /* OUT: first dnode contains right margin */
  87. static void ApplyBordersForTruncation(POSINLINE* pposinlineTruncate, /* IN, OUT: position of truncation point */
  88. long* purColumnMaxTruncate, /* IN, OUT: position of right margin */
  89. BOOL* pfTruncationFound); /* OUT: this procedure can find truncation itself */
  90. static LSERR MoveClosingBorderAfterBreak(PLSSUBL plssubl, /* IN subline */
  91. BOOL fChangeList, /* IN: do we need to change dnode list
  92. and change pplsdnBreak, or only to recalculate durBreak */
  93. PLSDNODE* pplsdnBreak, /* IN, OUT: break dnode */
  94. long* purBreak); /* IN, OUT: position after break */
  95. static void RemoveBorderDnodeFromList(PLSDNODE plsdnBorder); /*IN: border dnode */
  96. static LSERR MoveBreakAfterPreviousDnode(
  97. PLSCHUNKCONTEXT plschunkcontext, /* chunk context */
  98. BRKOUT* pbrkout, /* IN,OUT brkout which can be changed */
  99. OBJDIM* pobjdimPrev, /* suggested objdim for the dnode in previous chunk
  100. if NULL take objdim of dnode */
  101. BRKKIND*); /* OUT: how dnode was broken */
  102. #define FCompressionFlagsAreOn(plsc) \
  103. ((plsc)->lsadjustcontext.lsbrj == lsbrjBreakWithCompJustify)
  104. #define FCompressionPossible(plsc, fAllLineAfterRightMargin) \
  105. (FCompressionFlagsAreOn(plsc) && \
  106. !FBreakthroughLine(plsc) && \
  107. !fAllLineAfterRightMargin)
  108. #define GoPrevPosInLine(pposinline, fEndOfContent) \
  109. if (((pposinline)->plsdn->plsdnPrev != NULL ) \
  110. && !FIsNotInContent((pposinline)->plsdn->plsdnPrev)) \
  111. {\
  112. (pposinline)->plsdn = (pposinline)->plsdn->plsdnPrev; \
  113. Assert(FIsLSDNODE((pposinline)->plsdn)); \
  114. (pposinline)->dcp = (pposinline)->plsdn->dcp;\
  115. (pposinline)->pointStart.u -= DurFromDnode((pposinline)->plsdn); \
  116. (pposinline)->pointStart.v -= DvrFromDnode((pposinline)->plsdn); \
  117. (fEndOfContent) = fFalse; \
  118. }\
  119. else\
  120. {\
  121. (fEndOfContent) = fTrue; \
  122. }
  123. #define GoNextPosInLine(pposinline) \
  124. (pposinline)->pointStart.u += DurFromDnode((pposinline)->plsdn);\
  125. (pposinline)->pointStart.v += DvrFromDnode((pposinline)->plsdn);\
  126. (pposinline)->plsdn = (pposinline)->plsdn->plsdnNext;\
  127. Assert(FIsLSDNODE((pposinline)->plsdn));\
  128. (pposinline)->dcp = 0;\
  129. #define GetCpLimFromPosInLine(posinline) \
  130. (((posinline).plsdn->dcp == (posinline).dcp) ? \
  131. ((posinline).plsdn->cpLimOriginal) : \
  132. ((posinline).plsdn->cpFirst + (posinline).dcp ))
  133. #define IsItTextDnode(plsdn, plsc) \
  134. ((plsdn) == NULL) ? fFalse : \
  135. (IdObjFromDnode(plsdn) == IobjTextFromLsc(&plsc->lsiobjcontext))
  136. #define ResolvePosInChunk(plschunkcontext, posichnk, pposinline) \
  137. (pposinline)->dcp = (posichnk).dcp; \
  138. LocDnodeFromChunk((plschunkcontext), (posichnk).ichnk, \
  139. &((pposinline)->plsdn),&((pposinline)->pointStart));
  140. #define GetCpFromPosInChunk(plschunkcontext, posichnk) \
  141. ((DnodeFromChunk(plschunkcontext, (posichnk).ichnk))->cpFirst + (posichnk).dcp)
  142. /* last two lines turn off check for lines ended with hard break and sublines ended
  143. by esc character */
  144. #define GetBrkpos(plsdn, dcpBreak) \
  145. ((FIsFirstOnLine(plsdn)) && ((dcpBreak) == 0) ? brkposBeforeFirstDnode :\
  146. ((((plsdn)->plsdnNext == NULL) \
  147. || (FIsDnodeCloseBorder((plsdn)->plsdnNext) && (plsdn)->plsdnNext->plsdnNext == NULL) \
  148. ) \
  149. && ((dcpBreak) == (plsdn)->dcp) \
  150. ) ? brkposAfterLastDnode : \
  151. brkposInside\
  152. )
  153. #define EndrFromBreakDnode(plsdnBreak)\
  154. (plsdnBreak == NULL) ? endrStopped : \
  155. (plsdnBreak->fEndOfPara) ? endrEndPara : \
  156. (plsdnBreak->fAltEndOfPara) ? endrAltEndPara : \
  157. (plsdnBreak->fSoftCR) ? endrSoftCR : \
  158. (plsdnBreak->fEndOfColumn) ? endrEndColumn : \
  159. (plsdnBreak->fEndOfSection) ? endrEndSection : \
  160. (plsdnBreak->fEndOfPage) ? endrEndPage : \
  161. endrStopped
  162. /* ---------------------------------------------------------------------- */
  163. /* B R E A K G E N E R A L C A S E */
  164. /*----------------------------------------------------------------------------
  165. %%Function: BreakGeneralCase
  166. %%Contact: igorzv
  167. Parameters:
  168. plsc - (IN) ptr to line services context
  169. fHardStop - (IN) is formatting sopped because of hard break or special situation
  170. breakrecMaxCurrent- (IN) size of the array of current line's break records
  171. pbreakrecCurrent- (OUT) current line's break records
  172. pbreakrecMacCurrent-(OUT) actual number of current line's break records
  173. pdcpDepend - (OUT) dcpDepend
  174. pCpLimLine - (OUT) cpLimLine
  175. pendr - (OUT) how the line ended
  176. pfSuccessful - (OUT) fSuccessful: false means insufficient fetch
  177. Main procedure of breaking
  178. Breaking can be unsuccessful if we didn't fetch enough
  179. ----------------------------------------------------------------------------*/
  180. LSERR BreakGeneralCase(PLSC plsc, BOOL fHardStop, DWORD breakrecMaxCurrent,
  181. BREAKREC* pbreakrecCurrent, DWORD* pbreakrecMacCurrent,
  182. LSDCP* pdcpDepend, LSCP* pcpLimLine, ENDRES* pendr,
  183. BOOL* pfSuccessful)
  184. {
  185. LSERR lserr;
  186. POSINLINE posinlineTruncate; /* position of truncation point */
  187. POSINLINE posinlineBreak; /* position of break point */
  188. BRKOUT brkout;
  189. GRCHUNKEXT grchnkextCompression;
  190. BOOL fCanCompress;
  191. long durToCompress;
  192. BOOL fLineCompressed;
  193. long durExtra;
  194. BOOL fEndOfContent;
  195. BOOL fAllLineAfterRightMargin;
  196. BRKKIND brkkindDnodeBreak;
  197. LSDCP dcpOld;
  198. PLSDNODE plsdnLastNotBorder;
  199. Assert(FBreakingAllowed(plsc));
  200. *pfSuccessful = fTrue;
  201. /* set flag how line was ended */ /*REVIEW*/
  202. if (!fHardStop)
  203. GetCurrentSubline(plsc)->fRightMarginExceeded = fTrue;
  204. if (GetCurrentDnode(plsc) == NULL) /* it can happend with fmtrStopped */
  205. {
  206. *pdcpDepend = 0;
  207. *pcpLimLine = GetCurrentCpLim(plsc);
  208. *pendr = endrStopped;
  209. return lserrNone;
  210. }
  211. if (fHardStop && (GetCurrentUr(plsc) <= plsc->urRightMarginBreak))
  212. /* we have hard break before right margin or there is no content in a line,
  213. so break is found */
  214. {
  215. posinlineBreak.plssubl = GetCurrentSubline(plsc);
  216. GetCurrentPoint(plsc, posinlineBreak.pointStart);
  217. posinlineBreak.plsdn = GetCurrentDnode(plsc);
  218. GetPointBeforeDnodeFromPointAfter(posinlineBreak.plsdn, &(posinlineBreak.pointStart));
  219. posinlineBreak.dcp = posinlineBreak.plsdn->dcp;
  220. /* skip back closing border after hard break */
  221. while (FIsDnodeBorder(posinlineBreak.plsdn))
  222. {
  223. GoPrevPosInLine(&posinlineBreak, fEndOfContent);
  224. Assert(!fEndOfContent);
  225. }
  226. brkout.objdim = posinlineBreak.plsdn->u.real.objdim;
  227. return SetBreakCore(&posinlineBreak, &brkout.objdim, brkkindImposedAfter,
  228. fHardStop, fTrue, breakrecMaxCurrent, pbreakrecCurrent,
  229. pbreakrecMacCurrent, pcpLimLine,
  230. pdcpDepend, pendr, pfSuccessful);
  231. }
  232. Assert(GetCurrentDnode(plsc) != NULL); /* case of empty list - end of section in the begining
  233. of a line should be handled in previous if */
  234. lserr = TruncateCore(GetCurrentSubline(plsc), plsc->urRightMarginBreak,
  235. &posinlineTruncate, &fAllLineAfterRightMargin);
  236. if (lserr != lserrNone)
  237. {
  238. return lserr;
  239. }
  240. Assert(!FIsNotInContent(posinlineTruncate.plsdn));
  241. if (FCompressionPossible(plsc, fAllLineAfterRightMargin))
  242. {
  243. lserr = FindNextBreakCore(plsc->urRightMarginBreak, &posinlineTruncate, fTrue,
  244. fHardStop, &brkout, &posinlineBreak, &brkkindDnodeBreak);
  245. if (lserr != lserrNone)
  246. {
  247. return lserr;
  248. }
  249. InitGroupChunkExt(PlschunkcontextFromSubline(GetCurrentSubline(plsc)),
  250. IobjTextFromLsc(&plsc->lsiobjcontext), &grchnkextCompression);
  251. if (!brkout.fSuccessful)
  252. {
  253. /* we can't find break and if we still can compress the amount that is over right
  254. margin we should fetch more */
  255. plsdnLastNotBorder = LastDnodeFromChunk(PlschunkcontextFromSubline(GetCurrentSubline(plsc)));
  256. Assert(!FIsDnodeBorder(plsdnLastNotBorder));
  257. /* last dnode from chunk which was collected in FindNextBreak will give us last not border dnode,
  258. we should store it before we change chunk context */
  259. lserr = CollectPreviousTextGroupChunk(GetCurrentDnode(plsc), CollectSublinesForCompression,
  260. FAllSimpleText(plsc),
  261. &grchnkextCompression);
  262. if (lserr != lserrNone)
  263. return lserr;
  264. durToCompress = GetCurrentUr(plsc) - plsc->urRightMarginBreak
  265. - grchnkextCompression.durTrailing;
  266. if ((brkout.brkcond == brkcondPlease || brkout.brkcond == brkcondCan)
  267. && FIsDnodeReal(plsdnLastNotBorder)
  268. )
  269. {
  270. /* In such case if we fetch more break may be possible after last dnode with also
  271. possible dur. So in our optimization check we are taking min from two durs */
  272. if (brkout.objdim.dur < DurFromDnode(plsdnLastNotBorder))
  273. {
  274. durToCompress -= (DurFromDnode(plsdnLastNotBorder) - brkout.objdim.dur);
  275. }
  276. }
  277. if (FDnodeHasBorder(grchnkextCompression.plsdnStartTrailing)
  278. && !grchnkextCompression.fClosingBorderStartsTrailing)
  279. {
  280. /* we should reserve room for closing border */
  281. /* if border is not exactly before trailing area it was counted as a part of durTrailing
  282. so we should add it again */
  283. durToCompress += DurBorderFromDnodeInside(grchnkextCompression.plsdnStartTrailing);
  284. }
  285. lserr = CanCompressText(&(grchnkextCompression.lsgrchnk),
  286. &(grchnkextCompression.posichnkBeforeTrailing),
  287. LstflowFromSubline(GetCurrentSubline(plsc)),
  288. durToCompress, &fCanCompress,
  289. &fLineCompressed, &durExtra);
  290. if (lserr != lserrNone)
  291. return lserr;
  292. if (fCanCompress)
  293. {
  294. /* increase right margin and fetch more */
  295. *pfSuccessful = fFalse;
  296. return lserrNone;
  297. }
  298. }
  299. else
  300. {
  301. /* temporary change dcp in break dnode */
  302. dcpOld = posinlineBreak.plsdn->dcp;
  303. posinlineBreak.plsdn->dcp = posinlineBreak.dcp;
  304. lserr = CollectPreviousTextGroupChunk(posinlineBreak.plsdn, CollectSublinesForCompression,
  305. FAllSimpleText(plsc),
  306. &grchnkextCompression);
  307. if (lserr != lserrNone)
  308. return lserr;
  309. durToCompress = posinlineBreak.pointStart.u + brkout.objdim.dur
  310. - plsc->urRightMarginBreak
  311. - grchnkextCompression.durTrailing;
  312. if (posinlineBreak.plsdn->plsdnNext != NULL &&
  313. FIsDnodeCloseBorder(posinlineBreak.plsdn->plsdnNext))
  314. {
  315. /* closing border after dnode is a part of collected group chunk
  316. so can participate in durTrailing see also calculation below */
  317. durToCompress += DurFromDnode(posinlineBreak.plsdn->plsdnNext);
  318. }
  319. if (FDnodeHasBorder(grchnkextCompression.plsdnStartTrailing)
  320. && !grchnkextCompression.fClosingBorderStartsTrailing)
  321. {
  322. /* we should reserve room for closing border */
  323. /* if closing border is right after non trailing area we already counted it */
  324. durToCompress += DurBorderFromDnodeInside(grchnkextCompression.plsdnStartTrailing);
  325. }
  326. /* restore dcp in break dnode */
  327. posinlineBreak.plsdn->dcp = dcpOld;
  328. lserr = CanCompressText(&(grchnkextCompression.lsgrchnk),
  329. &(grchnkextCompression.posichnkBeforeTrailing),
  330. LstflowFromSubline(GetCurrentSubline(plsc)),
  331. durToCompress, &fCanCompress, &fLineCompressed, &durExtra);
  332. if (lserr != lserrNone)
  333. return lserr;
  334. if (fCanCompress)
  335. {
  336. SetLineCompressed(plsc, fLineCompressed);
  337. return SetBreakCore(&posinlineBreak, &brkout.objdim, brkkindDnodeBreak,
  338. fHardStop, fTrue, breakrecMaxCurrent, pbreakrecCurrent,
  339. pbreakrecMacCurrent, pcpLimLine,
  340. pdcpDepend, pendr, pfSuccessful);
  341. }
  342. }
  343. } /* FCompressionPossible */
  344. if (!fAllLineAfterRightMargin)
  345. /* opposite is possible if we have left indent or auto number bigger then right margin */
  346. /* then we go to the force break */
  347. {
  348. lserr = FindPrevBreakCore(plsc->urRightMarginBreak, &posinlineTruncate, fTrue,
  349. &brkout, &posinlineBreak, &brkkindDnodeBreak);
  350. if (lserr != lserrNone)
  351. {
  352. return lserr;
  353. }
  354. if (brkout.fSuccessful)
  355. {
  356. return SetBreakCore(&posinlineBreak, &brkout.objdim, brkkindDnodeBreak,
  357. fHardStop, fTrue, breakrecMaxCurrent, pbreakrecCurrent,
  358. pbreakrecMacCurrent, pcpLimLine,
  359. pdcpDepend, pendr, pfSuccessful);
  360. }
  361. }
  362. /* handling line without break opportunity ( force break ) */
  363. plsc->plslineCur->lslinfo.fForcedBreak = fTrue;
  364. lserr = ForceBreakCore (plsc->urRightMarginBreak, &posinlineTruncate,
  365. fHardStop, fTrue, fAllLineAfterRightMargin,
  366. &brkout, &posinlineBreak, &brkkindDnodeBreak);
  367. if (lserr != lserrNone)
  368. {
  369. return lserr;
  370. }
  371. /* not successful return means insufficient fetch */
  372. if (!brkout.fSuccessful)
  373. {
  374. *pfSuccessful = fFalse;
  375. return lserrNone;
  376. }
  377. return SetBreakCore(&posinlineBreak, &brkout.objdim, brkkindDnodeBreak,
  378. fHardStop, fTrue, breakrecMaxCurrent, pbreakrecCurrent,
  379. pbreakrecMacCurrent, pcpLimLine,
  380. pdcpDepend, pendr, pfSuccessful);
  381. }
  382. /* ---------------------------------------------------------------------- */
  383. /* T R U N C A T E C O R E */
  384. /*----------------------------------------------------------------------------
  385. %%Function: TruncateCore
  386. %%Contact: igorzv
  387. Parameters:
  388. plssubl - (IN) subline where to find truncation point
  389. urColumnMax - (IN) position of right margin
  390. pposinlineTruncate - (OUT) position of truncation point
  391. pfAllLineAfterRightMargin(OUT) because of left indent or autonumber all line is
  392. after right margin
  393. Find dnode that exceeds right margin and then asked it's handler to find
  394. truncation point
  395. ----------------------------------------------------------------------------*/
  396. LSERR TruncateCore(PLSSUBL plssubl, long urColumnMax,
  397. POSINLINE* pposinlineTruncate, BOOL* pfAllLineAfterRightMargin)
  398. {
  399. LSERR lserr;
  400. DWORD idObj;
  401. POINTUV point;
  402. POSICHNK posichnk;
  403. PLSCHUNKCONTEXT plschunkcontext;
  404. LOCCHNK* plocchnk;
  405. PLSC plsc = plssubl->plsc;
  406. PLSSUBL plssublOld;
  407. long urColumnMaxTruncate;
  408. BOOL fEndOfContent;
  409. BOOL fTruncationFound = fFalse;
  410. Assert(FBreakingAllowed(plsc));
  411. Assert((pposinlineTruncate != NULL) );
  412. plschunkcontext = PlschunkcontextFromSubline(plssubl);
  413. plocchnk = &(plschunkcontext->locchnkCurrent);
  414. GetCurrentPointSubl(plssubl, point);
  415. /* length of the subline should be larger then lenght of the column */
  416. Assert(point.u >= urColumnMax);
  417. pposinlineTruncate->plssubl = plssubl;
  418. pposinlineTruncate->pointStart = point;
  419. pposinlineTruncate->plsdn = GetCurrentDnodeSubl(plssubl);
  420. GetPointBeforeDnodeFromPointAfter(pposinlineTruncate->plsdn, &(pposinlineTruncate->pointStart));
  421. pposinlineTruncate->dcp = 0;
  422. /* find dnode contains right margin */
  423. if (!plsc->fAdvanceBack)
  424. {
  425. fEndOfContent = fFalse;
  426. while ((pposinlineTruncate->pointStart.u > urColumnMax)
  427. && !fEndOfContent)
  428. {
  429. GoPrevPosInLine(pposinlineTruncate, fEndOfContent);
  430. }
  431. }
  432. else
  433. {
  434. /* in this case there is possible to have more then one dnode that contains right margin*/
  435. /* so we call more comprehensive procedure to find exactly the first one */
  436. FindFirstDnodeContainsRightMargin(urColumnMax, pposinlineTruncate);
  437. }
  438. *pfAllLineAfterRightMargin = fFalse;
  439. if (pposinlineTruncate->pointStart.u > urColumnMax)
  440. {
  441. *pfAllLineAfterRightMargin = fTrue;
  442. }
  443. urColumnMaxTruncate = urColumnMax;
  444. if (FDnodeHasBorder(pposinlineTruncate->plsdn))
  445. {
  446. ApplyBordersForTruncation(pposinlineTruncate, &urColumnMaxTruncate,
  447. &fTruncationFound);
  448. }
  449. if (!fTruncationFound)
  450. {
  451. /* if pen or tab or we don't find dnode that starts before right margin return immediately */
  452. /* last case possible if we have left indent or auto number bigger then right margin */
  453. if (FIsDnodePen(pposinlineTruncate->plsdn) || pposinlineTruncate->plsdn->fTab ||
  454. FIsDnodeSplat(pposinlineTruncate->plsdn) ||
  455. pposinlineTruncate->pointStart.u > urColumnMaxTruncate)
  456. {
  457. return lserrNone;
  458. }
  459. SetUrColumnMaxForChunks(plschunkcontext, urColumnMaxTruncate);
  460. lserr = CollectChunkAround(plschunkcontext, pposinlineTruncate->plsdn,
  461. pposinlineTruncate->plssubl->lstflow,
  462. &pposinlineTruncate->pointStart);
  463. if (lserr != lserrNone)
  464. return lserr;
  465. idObj = IdObjFromChnk(plocchnk);
  466. /* we allow object handler to formate subline,
  467. so we restore current subline after calling him */
  468. plssublOld = GetCurrentSubline(plsc);
  469. SetCurrentSubline(plsc, NULL);
  470. lserr = PLsimFromLsc(&plsc->lsiobjcontext, idObj)->pfnTruncateChunk(
  471. plocchnk, &posichnk);
  472. if (lserr != lserrNone)
  473. return lserr;
  474. SetCurrentSubline(plsc, plssublOld);
  475. ResolvePosInChunk(plschunkcontext, posichnk, pposinlineTruncate);
  476. /* if text sets truncation point before him, then move it after previous dnode */
  477. if (pposinlineTruncate->dcp == 0)
  478. {
  479. /* we allow this only for text */
  480. if (idObj == IobjTextFromLsc(&plsc->lsiobjcontext))
  481. {
  482. do
  483. {
  484. GoPrevPosInLine(pposinlineTruncate, fEndOfContent);
  485. Assert(!fEndOfContent);
  486. /* such situation cann't occurs on the boundary of chunck */
  487. }
  488. while (FIsDnodeBorder(pposinlineTruncate->plsdn));
  489. }
  490. else
  491. {
  492. return lserrWrongTruncationPoint;
  493. }
  494. }
  495. }
  496. return lserrNone;
  497. }
  498. /* ---------------------------------------------------------------------- */
  499. /* A P P L Y B O R D E R S F O R T R U N C A T I O N */
  500. /*----------------------------------------------------------------------------
  501. %%Function: ApplyBordersForTruncation
  502. %%Contact: igorzv
  503. Parameters:
  504. pposinlineTruncate - (IN, OUT) position of truncation point
  505. purColumnMax - (IN, OUT) position of right margin
  506. pfTruncationFound - (OUT) this procedure can find truncation itself
  507. Change right margin because of border and find dnode to call truncation method.
  508. ----------------------------------------------------------------------------*/
  509. static void ApplyBordersForTruncation(POSINLINE* pposinlineTruncate,
  510. long* purColumnMaxTruncate, BOOL* pfTruncationFound)
  511. {
  512. long durBorder;
  513. BOOL fEndOfContent = fFalse;
  514. PLSDNODE plsdn;
  515. *pfTruncationFound = fFalse;
  516. /* go back until open border or autonumber */
  517. if (FIsDnodeOpenBorder(pposinlineTruncate->plsdn))
  518. {
  519. /* move after border */
  520. durBorder = pposinlineTruncate->plsdn->u.pen.dur;
  521. GoNextPosInLine(pposinlineTruncate);
  522. Assert(!FIsDnodeBorder(pposinlineTruncate->plsdn));
  523. /* we should not have empty list between borders */
  524. }
  525. else
  526. {
  527. while (!FIsDnodeOpenBorder(pposinlineTruncate->plsdn->plsdnPrev) && !fEndOfContent)
  528. {
  529. GoPrevPosInLine(pposinlineTruncate, fEndOfContent);
  530. }
  531. if (!fEndOfContent) /* we stopped on opening border */
  532. {
  533. Assert(pposinlineTruncate->plsdn->plsdnPrev);
  534. durBorder = pposinlineTruncate->plsdn->plsdnPrev->u.pen.dur;
  535. }
  536. else
  537. {
  538. /* we stopped because of autonumber */
  539. /* now we only need to take width of border from border dnode which located before
  540. autonumber */
  541. plsdn = pposinlineTruncate->plsdn->plsdnPrev;
  542. while (!FIsDnodeOpenBorder(plsdn))
  543. {
  544. plsdn = plsdn->plsdnPrev;
  545. Assert(FIsLSDNODE(plsdn));
  546. }
  547. durBorder = plsdn->u.pen.dur;
  548. }
  549. }
  550. /* do we have enough room to put both opening and closing border */
  551. if (pposinlineTruncate->pointStart.u + durBorder <= *purColumnMaxTruncate)
  552. {
  553. /* if yes decrease margin and find new truncation dnode */
  554. *purColumnMaxTruncate -= durBorder;
  555. while (pposinlineTruncate->pointStart.u + DurFromDnode(pposinlineTruncate->plsdn)
  556. <= *purColumnMaxTruncate)
  557. {
  558. GoNextPosInLine(pposinlineTruncate);
  559. Assert(!FIsDnodeBorder(pposinlineTruncate->plsdn));
  560. /* this assert can be proved using the fact that end of closing border is beyond
  561. original right margin */
  562. }
  563. }
  564. else
  565. {
  566. /* set truncation as the first character of this dnode */
  567. *pfTruncationFound = fTrue;
  568. pposinlineTruncate->dcp = 1;
  569. }
  570. }
  571. /* ---------------------------------------------------------------------- */
  572. /* F I N D P R E V B R E A K C O R E */
  573. /*----------------------------------------------------------------------------
  574. %%Function: FindPrevBreakCore
  575. %%Contact: igorzv
  576. Parameters:
  577. urColumnMax - (IN) width of column
  578. pposinlineTruncate - (IN) position of truncation point
  579. fFirstSubline - (IN) to apply rules for first character to the first character of
  580. this subline
  581. pbrkout - (OUT)breaking information
  582. pposinlineBreak - (OUT)position of breaking point
  583. pbrkkindDnodeBreak - (OUT) how break was found
  584. Going backword try to find first break opportunity before truncation point
  585. ----------------------------------------------------------------------------*/
  586. LSERR FindPrevBreakCore( long urColumnMax,
  587. POSINLINE* pposinlineTruncate, BOOL fFirstSubline,
  588. BRKOUT* pbrkout, POSINLINE* pposinlineBreak,
  589. BRKKIND* pbrkkindDnodeBreak)
  590. {
  591. LSERR lserr;
  592. DWORD idObj;
  593. POSICHNK posichnk;
  594. BOOL fFound;
  595. PLSDNODE plsdn;
  596. PLSCHUNKCONTEXT plschunkcontext;
  597. LOCCHNK* plocchnk;
  598. BRKCOND brkcond;
  599. PLSC plsc = pposinlineTruncate->plssubl->plsc;
  600. POINTUV pointChunkStart;
  601. PLSSUBL plssublOld;
  602. Assert(FBreakingAllowed(plsc));
  603. Assert(FIsLSDNODE(pposinlineTruncate->plsdn));
  604. Assert(pposinlineBreak != NULL);
  605. *pbrkkindDnodeBreak = brkkindPrev;
  606. plschunkcontext = PlschunkcontextFromSubline(pposinlineTruncate->plssubl);
  607. plocchnk = &(plschunkcontext->locchnkCurrent);
  608. SetUrColumnMaxForChunks(plschunkcontext, urColumnMax);
  609. Assert(!FIsDnodeBorder(pposinlineTruncate->plsdn));
  610. lserr = CollectChunkAround(plschunkcontext, pposinlineTruncate->plsdn,
  611. pposinlineTruncate->plssubl->lstflow,
  612. &pposinlineTruncate->pointStart);
  613. if (lserr != lserrNone)
  614. return lserr;
  615. /* set fFirstOnLine */
  616. ApplyFFirstSublineToChunk(plschunkcontext, fFirstSubline);
  617. SetPosInChunk(plschunkcontext, pposinlineTruncate->plsdn, pposinlineTruncate->dcp, &posichnk);
  618. fFound = fTrue;
  619. /* for the chunk around truncation point we allow to make break after if it's text and
  620. don't allow otherwise.
  621. REVIEW:Such decision simplifyes code but produces some problems
  622. (with objects known so far more theoretical then practical).
  623. There are two bad cases: non-text after text which (non-text) prohibites to break before
  624. and text which allowes to break*/
  625. idObj = IdObjFromChnk(plocchnk);
  626. if (idObj == IobjTextFromLsc(&plsc->lsiobjcontext))
  627. brkcond = brkcondCan;
  628. else
  629. brkcond = brkcondNever;
  630. while (fFound)
  631. {
  632. Assert(NumberOfDnodesInChunk(plocchnk) != 0);
  633. plsdn = plschunkcontext->pplsdnChunk[0];
  634. GetPointChunkStart(plocchnk, pointChunkStart);
  635. if (FIsDnodePen(plsdn) || plsdn->fTab || FIsDnodeSplat(plsdn))
  636. {
  637. Assert(NumberOfDnodesInChunk(plocchnk) == 1);
  638. /* only advance pen is allowed here */
  639. Assert(!FIsDnodePen(plsdn) || plsdn->fAdvancedPen);
  640. /* for the case of a pen we are passing garbage as an objdim
  641. here assuming that it never be used */
  642. lserr = BreakTabPenSplat(plocchnk, fFalse, FBreakthroughLine(plsc),
  643. FIsDnodeSplat(plsdn), brkcond,
  644. &(plsdn->u.real.objdim), pbrkout);
  645. if (lserr != lserrNone)
  646. return lserr;
  647. }
  648. else
  649. {
  650. idObj = IdObjFromDnode(plsdn);
  651. /* we allow object handler to formate subline,
  652. so we restore current subline after calling him */
  653. plssublOld = GetCurrentSubline(plsc);
  654. SetCurrentSubline(plsc, NULL);
  655. lserr = PLsimFromLsc(&plsc->lsiobjcontext, idObj)->pfnFindPrevBreakChunk(plocchnk,
  656. &posichnk, brkcond, pbrkout);
  657. if (lserr != lserrNone)
  658. return lserr;
  659. SetCurrentSubline(plsc, plssublOld);
  660. } /* non tab */
  661. if (pbrkout->fSuccessful) break;
  662. /* prepare next iteration */
  663. lserr = CollectPreviousChunk(plschunkcontext, &fFound);
  664. if (lserr != lserrNone)
  665. return lserr;
  666. if (fFound)
  667. {
  668. posichnk.ichnk = ichnkOutside;
  669. /* posichnk.dcp is invalid */
  670. /* prepare brkcond for next iteration */
  671. brkcond = pbrkout->brkcond;
  672. }
  673. } /* while */
  674. if (pbrkout->fSuccessful)
  675. {
  676. pposinlineBreak->plssubl = pposinlineTruncate->plssubl;
  677. if (pbrkout->posichnk.dcp == 0 && FIsDnodeReal(plschunkcontext->pplsdnChunk[0]))
  678. /* break before dnode */
  679. {
  680. lserr = MoveBreakAfterPreviousDnode(plschunkcontext, pbrkout, NULL, pbrkkindDnodeBreak);
  681. /* this procedure can change chunkcontext */
  682. if (lserr != lserrNone)
  683. return lserr;
  684. }
  685. ResolvePosInChunk(plschunkcontext, (pbrkout->posichnk), pposinlineBreak);
  686. }
  687. return lserrNone;
  688. }
  689. /* ---------------------------------------------------------------------- */
  690. /* F I N D N E X T B R E A K C O R E */
  691. /*----------------------------------------------------------------------------
  692. %%Function: FindNextBreakCore
  693. %%Contact: igorzv
  694. Parameters:
  695. urColumnMax - (IN) width of column
  696. pposinlineTruncate - (IN) position of truncation point
  697. fFirstSubline - (IN) to apply rules for first character to the first character of
  698. this subline
  699. fStopped - (IN) formatting has been stopped by client
  700. pbrkout - (OUT) breaking information
  701. pposinlineBreak - (OUT) position of breaking point
  702. pbrkkindDnodeBreak - (OUT) how break was found
  703. Going forward try to find first break opportunity after truncation point
  704. ----------------------------------------------------------------------------*/
  705. LSERR FindNextBreakCore( long urColumnMax,
  706. POSINLINE* pposinlineTruncate, BOOL fFirstSubline, BOOL fStopped,
  707. BRKOUT* pbrkout, POSINLINE* pposinlineBreak, BRKKIND* pbrkkindDnodeBreak)
  708. {
  709. LSERR lserr;
  710. DWORD idObj;
  711. POSICHNK posichnk;
  712. BOOL fFound;
  713. PLSDNODE plsdn;
  714. PLSCHUNKCONTEXT plschunkcontext;
  715. LOCCHNK* plocchnk;
  716. BRKCOND brkcond;
  717. PLSC plsc = pposinlineTruncate->plssubl->plsc;
  718. POINTUV pointChunkStart;
  719. PLSSUBL plssublOld;
  720. OBJDIM objdimPrevious;
  721. Assert(FBreakingAllowed(plsc));
  722. Assert(FIsLSDNODE(pposinlineTruncate->plsdn));
  723. Assert(pposinlineBreak != NULL);
  724. *pbrkkindDnodeBreak = brkkindNext;
  725. plschunkcontext = PlschunkcontextFromSubline(pposinlineTruncate->plssubl);
  726. plocchnk = &(plschunkcontext->locchnkCurrent);
  727. SetUrColumnMaxForChunks(plschunkcontext, urColumnMax); /* will be used by LsdnCheckAvailableSpace */
  728. Assert(!FIsDnodeBorder(pposinlineTruncate->plsdn));
  729. lserr = CollectChunkAround(plschunkcontext, pposinlineTruncate->plsdn,
  730. pposinlineTruncate->plssubl->lstflow,
  731. &pposinlineTruncate->pointStart);
  732. if (lserr != lserrNone)
  733. return lserr;
  734. /* set fFirstOnLine */
  735. ApplyFFirstSublineToChunk(plschunkcontext, fFirstSubline);
  736. SetPosInChunk(plschunkcontext, pposinlineTruncate->plsdn,
  737. pposinlineTruncate->dcp, &posichnk);
  738. fFound = fTrue;
  739. /* for the chunk around truncation point we prohibite to make break before */
  740. brkcond = brkcondNever;
  741. while (fFound)
  742. {
  743. Assert(NumberOfDnodesInChunk(plocchnk) != 0);
  744. plsdn = plschunkcontext->pplsdnChunk[0];
  745. GetPointChunkStart(plocchnk, pointChunkStart);
  746. if (FIsDnodePen(plsdn) || plsdn->fTab || FIsDnodeSplat(plsdn))
  747. {
  748. Assert(NumberOfDnodesInChunk(plocchnk) == 1);
  749. /* only advance pen is allowed here */
  750. Assert(!FIsDnodePen(plsdn) || plsdn->fAdvancedPen);
  751. /* for the case of a pen we are passing garbage as an objdim
  752. here assuming that it never be used */
  753. lserr = BreakTabPenSplat(plocchnk, fTrue, FBreakthroughLine(plsc),
  754. FIsDnodeSplat(plsdn), brkcond,
  755. &(plsdn->u.real.objdim), pbrkout);
  756. if (lserr != lserrNone)
  757. return lserr;
  758. }
  759. else
  760. {
  761. idObj = IdObjFromChnk(plocchnk);
  762. /* we allow object handler to formate subline,
  763. so we restore current subline after calling him */
  764. plssublOld = GetCurrentSubline(plsc);
  765. SetCurrentSubline(plsc, NULL);
  766. lserr = PLsimFromLsc(&plsc->lsiobjcontext, idObj)->pfnFindNextBreakChunk(plocchnk,
  767. &posichnk, brkcond, pbrkout);
  768. if (lserr != lserrNone)
  769. return lserr;
  770. SetCurrentSubline(plsc, plssublOld);
  771. /* We ignore returned objdim in a case of brkcondNever. We don't expect
  772. object to set correct one */
  773. if (!pbrkout->fSuccessful && pbrkout->brkcond == brkcondNever)
  774. pbrkout->objdim = (LastDnodeFromChunk(plschunkcontext))->u.real.objdim;
  775. } /* non tab */
  776. if (pbrkout->fSuccessful) break;
  777. lserr = CollectNextChunk(plschunkcontext, &fFound);
  778. if (lserr != lserrNone)
  779. return lserr;
  780. if (fFound)
  781. {
  782. posichnk.ichnk = ichnkOutside;
  783. /* posichnk.dcp is invalid */
  784. /* prepare brkcond for next iteration */
  785. brkcond = pbrkout->brkcond;
  786. /* we save objdim and trailing info for the case when next object
  787. returns break before and we actually will set break in current object. */
  788. objdimPrevious = pbrkout->objdim;
  789. }
  790. }
  791. /* we cannot find break but formatting has been stopped by client */
  792. if (fStopped && !pbrkout->fSuccessful)
  793. {
  794. /* set break after last dnode */
  795. PosInChunkAfterChunk(plocchnk, pbrkout->posichnk);
  796. pbrkout->objdim =
  797. (LastDnodeFromChunk(plschunkcontext))->u.real.objdim;
  798. /* We should use last dnode in chunk here to be sure not to get closing border.
  799. In the case of pen it's garbage, we assume that will not be used */
  800. pbrkout->fSuccessful = fTrue;
  801. }
  802. if (pbrkout->fSuccessful)
  803. {
  804. pposinlineBreak->plssubl = pposinlineTruncate->plssubl;
  805. if (pbrkout->posichnk.dcp == 0 && FIsDnodeReal(plschunkcontext->pplsdnChunk[0]))
  806. /* break before dnode */
  807. {
  808. lserr = MoveBreakAfterPreviousDnode(plschunkcontext, pbrkout, &objdimPrevious, pbrkkindDnodeBreak);
  809. /* this procedure can change chunkcontext */
  810. if (lserr != lserrNone)
  811. return lserr;
  812. /* REVIEW: Is it possible to have garbage in objdimPrevious (somebody break brkcond */
  813. }
  814. ResolvePosInChunk(plschunkcontext, (pbrkout->posichnk), pposinlineBreak);
  815. }
  816. else
  817. {
  818. }
  819. return lserrNone;
  820. }
  821. /* ---------------------------------------------------------------------- */
  822. /* F O R C E B R E A K C O R E */
  823. /*----------------------------------------------------------------------------
  824. %%Function: ForceBreakCore
  825. %%Contact: igorzv
  826. Parameters:
  827. urColumnMax - (IN) width of column
  828. pposinlineTruncate - (IN) position of truncation point
  829. fStopped - (IN) formatting ended with hard break
  830. fFirstSubline - (IN) to apply rules for first character to the first character of
  831. this subline
  832. fAllLineAfterRightMargin(IN) lead to pass chunk otside in force break methods.
  833. pbrkout - (OUT)breaking information
  834. pposinlineBreak - (OUT)position of breaking point
  835. pbrkkindDnodeBreak - (OUT) how break was found
  836. Invokes force break of chunk around truncation point
  837. ----------------------------------------------------------------------------*/
  838. LSERR ForceBreakCore(
  839. long urColumnMax,
  840. POSINLINE* pposinlineTruncate,
  841. BOOL fStopped, BOOL fFirstSubline,
  842. BOOL fAllLineAfterRightMargin,
  843. BRKOUT* pbrkout,
  844. POSINLINE* pposinlineBreak, BRKKIND* pbrkkindDnodeBreak)
  845. {
  846. LSERR lserr;
  847. DWORD idObj;
  848. POSICHNK posichnk;
  849. LSCHUNKCONTEXT* plschunkcontext;
  850. LOCCHNK* plocchnk;
  851. PLSC plsc = pposinlineTruncate->plssubl->plsc;
  852. PLSSUBL plssublOld;
  853. Assert(FBreakingAllowed(plsc));
  854. Assert(FIsLSDNODE(pposinlineTruncate->plsdn));
  855. Assert(pposinlineBreak != NULL);
  856. *pbrkkindDnodeBreak = brkkindForce;
  857. plschunkcontext = PlschunkcontextFromSubline(pposinlineTruncate->plssubl);
  858. plocchnk = &(plschunkcontext->locchnkCurrent);
  859. if (plsc->grpfManager & fFmiForceBreakAsNext &&
  860. FIsSubLineMain(pposinlineTruncate->plssubl))
  861. /* find next break opportunity, client will scroll */
  862. {
  863. lserr = FindNextBreakCore(urColumnMax, pposinlineTruncate, fFirstSubline,
  864. fStopped, pbrkout, pposinlineBreak, pbrkkindDnodeBreak);
  865. if (lserr != lserrNone)
  866. return lserr;
  867. if (!pbrkout->fSuccessful)
  868. {
  869. /* increase right margin and fetch more */
  870. return lserrNone;
  871. }
  872. }
  873. else
  874. /* use force break method */
  875. {
  876. SetUrColumnMaxForChunks(plschunkcontext, urColumnMax);
  877. Assert(!FIsDnodeBorder(pposinlineTruncate->plsdn));
  878. lserr = CollectChunkAround(plschunkcontext, pposinlineTruncate->plsdn,
  879. pposinlineTruncate->plssubl->lstflow,
  880. &pposinlineTruncate->pointStart);
  881. if (lserr != lserrNone)
  882. {
  883. return lserr;
  884. }
  885. /* set fFirstOnLine */
  886. ApplyFFirstSublineToChunk(plschunkcontext, fFirstSubline);
  887. if (!fAllLineAfterRightMargin)
  888. {
  889. SetPosInChunk(plschunkcontext, pposinlineTruncate->plsdn,
  890. pposinlineTruncate->dcp, &posichnk);
  891. }
  892. else /* all chunk already behind right margin */
  893. {
  894. posichnk.ichnk = ichnkOutside;
  895. /* posichnk.dcp is invalid */
  896. }
  897. if (FIsDnodePen(pposinlineTruncate->plsdn) ||
  898. pposinlineTruncate->plsdn->fTab || FIsDnodeSplat(pposinlineTruncate->plsdn))
  899. {
  900. Assert(NumberOfDnodesInChunk(plocchnk) == 1);
  901. /* only advance pen is allowed here */
  902. Assert(!FIsDnodePen(pposinlineTruncate->plsdn) ||
  903. pposinlineTruncate->plsdn->fAdvancedPen);
  904. /* for the case of a pen we are passing garbage as an objdim
  905. here assuming that it never be used */
  906. lserr = ForceBreakTabPenSplat(plocchnk,
  907. &(pposinlineTruncate->plsdn->u.real.objdim),
  908. pbrkout);
  909. if (lserr != lserrNone)
  910. return lserr;
  911. }
  912. else
  913. {
  914. idObj = IdObjFromChnk(plocchnk);
  915. /* we allow object handler to formate subline,
  916. so we restore current subline after calling him */
  917. plssublOld = GetCurrentSubline(plsc);
  918. SetCurrentSubline(plsc, NULL);
  919. lserr = PLsimFromLsc(&plsc->lsiobjcontext, idObj)->pfnForceBreakChunk(plocchnk, &posichnk, pbrkout);
  920. if (lserr != lserrNone)
  921. {
  922. return lserr;
  923. }
  924. SetCurrentSubline(plsc, plssublOld);
  925. }
  926. Assert(pbrkout->fSuccessful);
  927. pposinlineBreak->plssubl = pposinlineTruncate->plssubl;
  928. if (pbrkout->posichnk.dcp == 0 && FIsDnodeReal(plschunkcontext->pplsdnChunk[0]))
  929. /* break before dnode */
  930. {
  931. lserr = MoveBreakAfterPreviousDnode(plschunkcontext, pbrkout, NULL, pbrkkindDnodeBreak);
  932. /* this procedure can change chunkcontext */
  933. if (lserr != lserrNone)
  934. return lserr;
  935. }
  936. ResolvePosInChunk(plschunkcontext, (pbrkout->posichnk), pposinlineBreak);
  937. }
  938. return lserrNone;
  939. }
  940. /* ---------------------------------------------------------------------- */
  941. /* M O V E B R E A K A F T E R P R E V I O U S D N O D E */
  942. /*----------------------------------------------------------------------------
  943. %%Function: MoveBreakAfterPreviousDnode
  944. %%Contact: igorzv
  945. Parameters:
  946. plschunkcontext - (IN) chunk context
  947. pbrkout - (IN,OUT) brkout which can be changed
  948. pobjdimPrev - (IN) suggested objdim for the dnode in previous chunk,
  949. if NULL take objdim of dnode
  950. pbrkkind - (IN, OUT) how dnode was broken
  951. ----------------------------------------------------------------------------*/
  952. static LSERR MoveBreakAfterPreviousDnode(
  953. PLSCHUNKCONTEXT plschunkcontext,
  954. BRKOUT* pbrkout,
  955. OBJDIM* pobjdimPrev,
  956. BRKKIND* pbrkkind )
  957. {
  958. LOCCHNK* plocchnk;
  959. LSERR lserr;
  960. BOOL fFound;
  961. Assert(pbrkout->posichnk.dcp == 0);
  962. Assert(FIsDnodeReal(plschunkcontext->pplsdnChunk[0]));
  963. /* because we do all operations on chunks we skip borders */
  964. plocchnk = &(plschunkcontext->locchnkCurrent);
  965. /* if break was set before chunk reset it after previous chunk */
  966. if (pbrkout->posichnk.ichnk == 0)
  967. {
  968. lserr = CollectPreviousChunk(plschunkcontext, &fFound);
  969. if (lserr != lserrNone)
  970. return lserr;
  971. if (fFound)
  972. {
  973. pbrkout->posichnk.ichnk = plocchnk->clschnk - 1;
  974. pbrkout->posichnk.dcp = plschunkcontext->pplsdnChunk[plocchnk->clschnk - 1]->dcp;
  975. if (pobjdimPrev != NULL)
  976. {
  977. pbrkout->objdim = *pobjdimPrev;
  978. }
  979. else
  980. {
  981. pbrkout->objdim = plschunkcontext->pplsdnChunk[plocchnk->clschnk - 1]
  982. ->u.real.objdim; /* if it's pen then objdim is garbage which doesn't matter */
  983. *pbrkkind = brkkindImposedAfter; /* geometry has not prepared by object */
  984. }
  985. }
  986. }
  987. else
  988. { /* just break after previous chunk element */
  989. pbrkout->posichnk.ichnk --;
  990. pbrkout->posichnk.dcp = plschunkcontext->pplsdnChunk[pbrkout->posichnk.ichnk]->dcp;
  991. pbrkout->objdim = plschunkcontext->pplsdnChunk[pbrkout->posichnk.ichnk]
  992. ->u.real.objdim;
  993. *pbrkkind = brkkindImposedAfter; /* geometry has not prepared by object */
  994. }
  995. return lserrNone;
  996. }
  997. /* ---------------------------------------------------------------------- */
  998. /* B R E A K T A B P E N S P L A T*/
  999. /*----------------------------------------------------------------------------
  1000. %%Function: BreakTabPenSplat
  1001. %%Contact: igorzv
  1002. Parameters:
  1003. plocchnk - (IN) chunk contains tab or pen
  1004. fFindNext - (IN) is this functions used for next break
  1005. fBreakThroughTab - (IN) there is a situation of breakthrough tab
  1006. fSplat - (IN) we are breaking splat
  1007. brkcond - (IN) condition of boundary break
  1008. pobjdim (IN) to fill in objdim of break
  1009. pbrkout - (OUT)breaking information
  1010. ----------------------------------------------------------------------------*/
  1011. static LSERR BreakTabPenSplat(PLOCCHNK plocchnk, BOOL fFindNext, BOOL fBreakThroughTab,
  1012. BOOL fSplat, BRKCOND brkcond, OBJDIM* pobjdim, BRKOUT* pbrkout)
  1013. {
  1014. Assert(NumberOfDnodesInChunk(plocchnk) == 1);
  1015. if (fSplat)
  1016. {
  1017. pbrkout->fSuccessful = fTrue;
  1018. PosInChunkAfterChunk(plocchnk, pbrkout->posichnk);
  1019. pbrkout->objdim = *pobjdim;
  1020. return lserrNone;
  1021. }
  1022. if (GetFFirstOnLineChunk(plocchnk) ||
  1023. (fFindNext && brkcond == brkcondNever) ||
  1024. fBreakThroughTab)
  1025. {
  1026. pbrkout->fSuccessful = fFalse;
  1027. pbrkout->brkcond = brkcondCan;
  1028. pbrkout->objdim = *pobjdim;
  1029. return lserrNone;
  1030. }
  1031. else
  1032. {
  1033. pbrkout->fSuccessful = fTrue;
  1034. pbrkout->posichnk.ichnk = 0;
  1035. pbrkout->posichnk.dcp = 0;
  1036. memset(&(pbrkout->objdim), 0, sizeof(pbrkout->objdim));
  1037. return lserrNone;
  1038. }
  1039. }
  1040. /* ---------------------------------------------------------------------- */
  1041. /* F O R C E B R E A K T A B P E N S P L A T*/
  1042. /*----------------------------------------------------------------------------
  1043. %%Function: ForceBreakTabPenSplat
  1044. %%Contact: igorzv
  1045. Parameters:
  1046. plocchnk - (IN) chunk contains tab or pen
  1047. pobjdim (IN) to fill in objdim of break
  1048. pbrkout - (OUT)breaking information
  1049. Returns break after chunk
  1050. ----------------------------------------------------------------------------*/
  1051. static LSERR ForceBreakTabPenSplat(PLOCCHNK plocchnk,
  1052. OBJDIM* pobjdim, BRKOUT* pbrkout)
  1053. {
  1054. Assert(NumberOfDnodesInChunk(plocchnk) == 1);
  1055. pbrkout->fSuccessful = fTrue;
  1056. PosInChunkAfterChunk(plocchnk, pbrkout->posichnk);
  1057. pbrkout->objdim = *pobjdim;
  1058. return lserrNone;
  1059. }
  1060. /* ---------------------------------------------------------------------- */
  1061. /* S E T B R E A K C O R E */
  1062. /*----------------------------------------------------------------------------
  1063. %%Function: SetBreakCore
  1064. %%Contact: igorzv
  1065. Parameters:
  1066. pposinlineBreak - (IN) position of breaking point
  1067. pobjdim - (IN) objdim of a breaking dnode
  1068. brkkind - (IN) how break was found
  1069. fStopped - (IN) formatting ends with hard break
  1070. fGlueEop - (IN) if break after dnode check EOP after it
  1071. breakrecMaxCurrent - (IN) size of the array of current line's break records
  1072. pbreakrecCurrent - (OUT) current line's break records
  1073. pbreakrecMacCurrent - (OUT) actual number of current line's break records
  1074. pcpLimLine - (OUT) cpLim of line to fill in
  1075. pdcpDepend - (OUT) amount of characters after break that was formated to
  1076. make breaking decision
  1077. pendr - (OUT) how line ends
  1078. pfSuccessful - (OUT) fSuccessful: false means insufficient fetch
  1079. Fill in break info
  1080. Change pfmtres in the case when hard break that we have because of excedeed margin
  1081. doesn't fit
  1082. If dcpBreak == 0 set break after previous dnode
  1083. Call handler of break dnode to notice him about break
  1084. Set current context after break point
  1085. ----------------------------------------------------------------------------*/
  1086. static LSERR SetBreakCore(
  1087. POSINLINE* pposinlineBreak, OBJDIM* pobjdim, BRKKIND brkkind,
  1088. BOOL fHardStop, BOOL fGlueEop, DWORD breakrecMaxCurrent,
  1089. BREAKREC* pbreakrecCurrent, DWORD* pbreakrecMacCurrent,
  1090. LSCP* pcpLimLine, LSDCP* pdcpDepend, ENDRES* pendr,
  1091. BOOL* pfSuccessful)
  1092. {
  1093. DWORD idObj;
  1094. PLSDNODE plsdnToChange;
  1095. LSERR lserr;
  1096. LSDCP dcpBreak;
  1097. POINTUV pointBeforeDnode;
  1098. long urBreak;
  1099. long vrBreak;
  1100. PLSSUBL plssubl = pposinlineBreak->plssubl;
  1101. PLSC plsc = plssubl->plsc;
  1102. PLSDNODE plsdnBreak;
  1103. PLSSUBL plssublOld;
  1104. BOOL fCrackDnode = fFalse;
  1105. PLSDNODE plsdn;
  1106. long urAdd;
  1107. plsdnBreak = pposinlineBreak->plsdn;
  1108. dcpBreak = pposinlineBreak->dcp;
  1109. pointBeforeDnode = pposinlineBreak->pointStart;
  1110. Assert(!FIsDnodeBorder(plsdnBreak)); /* border will be added later */
  1111. AssertImplies(FIsFirstOnLine(plsdnBreak), dcpBreak != 0); /*to avoid infinitive loop */
  1112. plsdnToChange = plsdnBreak;
  1113. if (plsdnToChange->dcp != dcpBreak)
  1114. /* if break is not after dnode than change cpLimOriginal */
  1115. {
  1116. plsdnToChange->cpLimOriginal = plsdnToChange->cpFirst + dcpBreak;
  1117. plsdnToChange->dcp = dcpBreak;
  1118. fCrackDnode = fTrue;
  1119. }
  1120. if (FIsDnodeReal(plsdnToChange))
  1121. SetDnodeObjdimFmt(plsdnToChange, *pobjdim);
  1122. /* set state after break point */
  1123. urBreak = pointBeforeDnode.u + DurFromDnode(plsdnBreak);
  1124. vrBreak = pointBeforeDnode.v + DvrFromDnode(plsdnBreak);
  1125. if (FIsDnodeReal(plsdnBreak) && !plsdnBreak->fTab && !FIsDnodeSplat(plsdnBreak)) /* call set break of break dnode */
  1126. {
  1127. idObj = IdObjFromDnode(plsdnBreak);
  1128. /* we allow object handler to formate subline,
  1129. so we restore current subline after calling him */
  1130. plssublOld = GetCurrentSubline(plsc);
  1131. SetCurrentSubline(plsc, NULL);
  1132. lserr = PLsimFromLsc(&plsc->lsiobjcontext, idObj)->pfnSetBreak(
  1133. plsdnBreak->u.real.pdobj, brkkind, breakrecMaxCurrent, pbreakrecCurrent,
  1134. pbreakrecMacCurrent);
  1135. if (lserr != lserrNone)
  1136. return lserr;
  1137. SetCurrentSubline(plsc, plssublOld);
  1138. }
  1139. /* if break after dnode and after it we have end of paragraph or spalt then we
  1140. should set break after end of paragraph */
  1141. if (fGlueEop && !fCrackDnode)
  1142. {
  1143. plsdn = plsdnBreak->plsdnNext;
  1144. urAdd = 0;
  1145. /* skip borders */
  1146. while(plsdn != NULL && FIsDnodeBorder(plsdn))
  1147. {
  1148. urAdd += DurFromDnode(plsdn);
  1149. plsdn = plsdn->plsdnNext;
  1150. }
  1151. if (plsdn == NULL && !fHardStop)
  1152. {
  1153. /* nothing has been fetched after break dnode which is not hard break */
  1154. /* increase right margin and fetch more */
  1155. *pfSuccessful = fFalse;
  1156. return lserrNone;
  1157. }
  1158. AssertImplies(plsdn == NULL, fHardStop);
  1159. /* next dnode EOP */
  1160. if (plsdn != NULL && (FIsDnodeEndPara(plsdn) || FIsDnodeAltEndPara(plsdn)
  1161. || FIsDnodeSplat(plsdn)))
  1162. {
  1163. plsdnBreak = plsdn;
  1164. urBreak += urAdd;
  1165. urBreak += DurFromDnode(plsdn);
  1166. }
  1167. }
  1168. /* move closing border */
  1169. if (FBorderEncounted(plsc))
  1170. {
  1171. lserr = MoveClosingBorderAfterBreak(plssubl, fTrue, &plsdnBreak, &urBreak);
  1172. if (lserr != lserrNone)
  1173. return lserr;
  1174. }
  1175. /* below we handle situation of hard break that has stopped formatting */
  1176. /* and if such dnode actually doesn't fit
  1177. we need to change final fmtres (can happened because of exceeded margin for formatting) */
  1178. /* it's important to execute this check after moving border, because afterward border will
  1179. never be next to hard break dnode */
  1180. if (plsdnBreak != GetCurrentDnodeSubl(plssubl) || fCrackDnode)
  1181. {
  1182. fHardStop = fFalse;
  1183. }
  1184. /* prepare output */
  1185. if (fHardStop)
  1186. {
  1187. /* in such case we should include hidden text after last dnode to a line */
  1188. *pcpLimLine = GetCurrentCpLimSubl(plssubl);
  1189. *pendr = EndrFromBreakDnode(plsdnBreak);
  1190. }
  1191. else
  1192. {
  1193. *pcpLimLine = (plsdnBreak)->cpLimOriginal;
  1194. *pendr = endrNormal;
  1195. }
  1196. if (plsc->fHyphenated) /* REVIEW why in context */
  1197. {
  1198. Assert(*pendr == endrNormal);
  1199. *pendr = endrHyphenated;
  1200. }
  1201. *pdcpDepend = GetCurrentCpLimSubl(plssubl) - *pcpLimLine;
  1202. /* set position of break in a subline */
  1203. SetCurrentCpLimSubl(plssubl, *pcpLimLine);
  1204. SetCurrentDnodeSubl(plssubl, plsdnBreak);
  1205. SetCurrentUrSubl(plssubl, urBreak);
  1206. SetCurrentVrSubl(plssubl, vrBreak);
  1207. /* set boundaries for display */
  1208. if (FIsDnodeSplat(plsdnBreak))
  1209. {
  1210. SetCpLimDisplaySubl(plssubl, GetCurrentCpLimSubl(plssubl) - 1);
  1211. SetLastDnodeDisplaySubl(plssubl, GetCurrentDnodeSubl(plssubl)->plsdnPrev);
  1212. }
  1213. else
  1214. {
  1215. SetCpLimDisplaySubl(plssubl, GetCurrentCpLimSubl(plssubl));
  1216. SetLastDnodeDisplaySubl(plssubl, GetCurrentDnodeSubl(plssubl));
  1217. }
  1218. return lserrNone;
  1219. }
  1220. /* ---------------------------------------------------------------------- */
  1221. /* M O V E C L O S I N G B O R D E R A F T E R B R E A K */
  1222. /*----------------------------------------------------------------------------
  1223. %%Function: MoveClosingBorderAfterBreak
  1224. %%Contact: igorzv
  1225. Parameters:
  1226. plsc - (IN) subline
  1227. fChangeList - (IN) do we need to change dnode list
  1228. and change pplsdnBreak, or only to recalculate durBreak
  1229. pplsdnBreak - (IN,OUT) break dnode
  1230. purBreak - (IN, OUT) position after break
  1231. This procedure puts closing border into correct place,
  1232. takes into account trailing space logic.
  1233. ----------------------------------------------------------------------------*/
  1234. LSERR MoveClosingBorderAfterBreak(PLSSUBL plssubl, BOOL fChangeList, PLSDNODE* pplsdnBreak,
  1235. long* purBreak)
  1236. {
  1237. PLSDNODE plsdnBorder, plsdnBeforeBorder;
  1238. long durBorder;
  1239. PLSDNODE plsdnLastClosingBorder = NULL;
  1240. LSERR lserr;
  1241. PLSDNODE plsdnNext, plsdnPrev;
  1242. PLSC plsc = plssubl->plsc;
  1243. BOOL fBreakReached;
  1244. BOOL fClosingBorderInsideBreak = fFalse;
  1245. Assert(!FIsDnodePen(*pplsdnBreak));
  1246. /* find dnode to insert border after, plus delete all borders which starts
  1247. inside trailing area*/
  1248. plsdnBeforeBorder = GetCurrentDnodeSubl(plssubl);
  1249. fBreakReached = (plsdnBeforeBorder == *pplsdnBreak);
  1250. while (!fBreakReached
  1251. ||
  1252. (plsdnBeforeBorder != NULL
  1253. && (!FIsDnodeReal(plsdnBeforeBorder)
  1254. || (FSpacesOnly(plsdnBeforeBorder, IobjTextFromLsc(&plsc->lsiobjcontext)))
  1255. )
  1256. )
  1257. )
  1258. {
  1259. /* pens can be only advanced so there is an object before REVIEW*/
  1260. /* we skip borders in trailing area */
  1261. plsdnPrev = plsdnBeforeBorder->plsdnPrev;
  1262. if (FIsDnodeBorder(plsdnBeforeBorder))
  1263. {
  1264. if (FIsDnodeOpenBorder(plsdnBeforeBorder))
  1265. {
  1266. /* delete such dnode and correspondent closing border */
  1267. /* decrease position of break */
  1268. if (fBreakReached)
  1269. *purBreak -= DurFromDnode(plsdnBeforeBorder);
  1270. if (fChangeList)
  1271. {
  1272. RemoveBorderDnodeFromList(plsdnBeforeBorder);
  1273. lserr = DestroyDnodeList (&plsc->lscbk, plsc->pols, &plsc->lsiobjcontext,
  1274. plsdnBeforeBorder, plsc->fDontReleaseRuns);
  1275. if (lserr != lserrNone)
  1276. return lserr;
  1277. }
  1278. if (plsdnLastClosingBorder != NULL)
  1279. {
  1280. /* decrease position of break */
  1281. if (fClosingBorderInsideBreak)
  1282. *purBreak -= DurFromDnode(plsdnLastClosingBorder);
  1283. if (fChangeList)
  1284. {
  1285. RemoveBorderDnodeFromList(plsdnLastClosingBorder);
  1286. lserr = DestroyDnodeList (&plsc->lscbk, plsc->pols, &plsc->lsiobjcontext,
  1287. plsdnLastClosingBorder, plsc->fDontReleaseRuns);
  1288. if (lserr != lserrNone)
  1289. return lserr;
  1290. }
  1291. plsdnLastClosingBorder = NULL;
  1292. }
  1293. }
  1294. else /* closing border */
  1295. {
  1296. plsdnLastClosingBorder = plsdnBeforeBorder;
  1297. fClosingBorderInsideBreak = fBreakReached;
  1298. }
  1299. }
  1300. plsdnBeforeBorder = plsdnPrev;
  1301. if (plsdnBeforeBorder == *pplsdnBreak)
  1302. fBreakReached = fTrue;
  1303. }
  1304. if (plsdnBeforeBorder != NULL && FDnodeHasBorder(plsdnBeforeBorder))
  1305. /* otherwise we don't need to move border */
  1306. {
  1307. /* set closing border */
  1308. plsdnBorder = plsdnLastClosingBorder;
  1309. Assert(FIsLSDNODE(plsdnBorder));
  1310. Assert(FIsDnodeBorder(plsdnBorder));
  1311. Assert(!plsdnBorder->fOpenBorder);
  1312. if (fChangeList)
  1313. {
  1314. if (plsdnBeforeBorder->plsdnNext != plsdnBorder) /* otherwise nothing to move */
  1315. {
  1316. /* break link with closing border in the old place */
  1317. RemoveBorderDnodeFromList(plsdnBorder);
  1318. /* insert closing border into it new place */
  1319. plsdnNext = plsdnBeforeBorder->plsdnNext;
  1320. plsdnBeforeBorder->plsdnNext = plsdnBorder;
  1321. plsdnBorder->plsdnPrev = plsdnBeforeBorder;
  1322. plsdnBorder->plsdnNext = plsdnNext;
  1323. if (plsdnNext != NULL)
  1324. plsdnNext->plsdnPrev = plsdnBorder;
  1325. plsdnBorder->fBorderMovedFromTrailingArea = fTrue;
  1326. }
  1327. /* change cp in border dnode */
  1328. plsdnBorder->cpFirst = plsdnBeforeBorder->cpLimOriginal;
  1329. plsdnBorder->cpLimOriginal = plsdnBorder->cpFirst;
  1330. }
  1331. /* increase widths of the line */
  1332. if (!fClosingBorderInsideBreak)
  1333. {
  1334. durBorder = plsdnBorder->u.pen.dur;
  1335. *purBreak += durBorder;
  1336. }
  1337. /* if we add closing border right after breaking dnode than consider border
  1338. as new breaking dnode */
  1339. if (plsdnBeforeBorder == *pplsdnBreak && fChangeList)
  1340. {
  1341. *pplsdnBreak = plsdnBorder;
  1342. }
  1343. }
  1344. return lserrNone;
  1345. }
  1346. /* ---------------------------------------------------------------------- */
  1347. /* R E M O V E B O R D E R D N O D E F R O M L I S T */
  1348. /*----------------------------------------------------------------------------
  1349. %%Function: RemoveBorderDnodeFromList
  1350. %%Contact: igorzv
  1351. Parameters:
  1352. plsdnBorder - (IN) border dnode to remove
  1353. This procedure removes border dnode from the list of dnodes.
  1354. ----------------------------------------------------------------------------*/
  1355. static void RemoveBorderDnodeFromList(PLSDNODE plsdnBorder)
  1356. {
  1357. PLSDNODE plsdnPrev;
  1358. PLSDNODE plsdnNext;
  1359. plsdnPrev = plsdnBorder->plsdnPrev;
  1360. plsdnNext = plsdnBorder->plsdnNext;
  1361. if (plsdnPrev != NULL)
  1362. {
  1363. plsdnPrev->plsdnNext = plsdnNext;
  1364. }
  1365. else
  1366. {
  1367. /* border was the first so change first dnode of subline */
  1368. (SublineFromDnode(plsdnBorder))->plsdnFirst = plsdnNext;
  1369. }
  1370. if (plsdnNext != NULL)
  1371. {
  1372. plsdnNext->plsdnPrev = plsdnPrev;
  1373. }
  1374. else
  1375. /* if border was the last then set new last dnode of subline */
  1376. {
  1377. SetCurrentDnodeSubl(SublineFromDnode(plsdnBorder), plsdnPrev);
  1378. }
  1379. plsdnBorder->plsdnNext = NULL;
  1380. plsdnBorder->plsdnPrev = NULL;
  1381. InvalidateChunk(PlschunkcontextFromSubline(SublineFromDnode(plsdnBorder)));
  1382. }
  1383. /* ---------------------------------------------------------------------- */
  1384. /* B R E A K Q U I C K C A S E */
  1385. /*----------------------------------------------------------------------------
  1386. %%Function: BreakQuickCase
  1387. %%Contact: igorzv
  1388. Parameters:
  1389. plsc - (IN) LineServices context
  1390. fHardStop - (IN) formatting ended with hard break
  1391. pdcpDepend - (OUT) amount of characters after cpLim that was formated to find break
  1392. pcpLim - (OUT) cpLim of line
  1393. pfSuccessful - (OUT) can we find break through quick break
  1394. pendr - (OUT) how line ended
  1395. This quick procedure works if we have only text in a line.
  1396. We try to find break just in the last dnode
  1397. ----------------------------------------------------------------------------*/
  1398. LSERR BreakQuickCase(PLSC plsc, BOOL fHardStop, LSDCP* pdcpDepend,
  1399. LSCP* pcpLim, BOOL* pfSuccessful, ENDRES* pendr)
  1400. {
  1401. LSDCP dcpBreak;
  1402. PLSDNODE plsdnBreak = GetCurrentDnode(plsc);
  1403. LSERR lserr;
  1404. *pfSuccessful = fFalse;
  1405. if (!fHardStop)
  1406. {
  1407. OBJDIM objdimBreak;
  1408. lserr = QuickBreakText(plsdnBreak->u.real.pdobj, pfSuccessful, &dcpBreak, &objdimBreak );
  1409. if (lserr != lserrNone)
  1410. return lserr;
  1411. if (*pfSuccessful)
  1412. { /* we found break */
  1413. AdvanceCurrentUr(plsc, objdimBreak.dur - plsdnBreak->u.real.objdim.dur);
  1414. SetDnodeObjdimFmt(plsdnBreak, objdimBreak);
  1415. plsdnBreak->dcp = dcpBreak;
  1416. Assert(dcpBreak > 0); /* we don't allow Quickbreak to break before him */
  1417. /* in the case of QuickBreak cpLim is always equal to cpFirst + dcp,
  1418. because otherwise is possible only with glyphs */
  1419. plsdnBreak->cpLimOriginal = plsdnBreak->cpFirst + dcpBreak;
  1420. *pcpLim = plsdnBreak->cpLimOriginal;
  1421. *pdcpDepend = GetCurrentCpLim(plsc) - *pcpLim;
  1422. *pendr = endrNormal;
  1423. SetCurrentCpLim(plsc, *pcpLim);
  1424. /* set boundaries for display */
  1425. SetCpLimDisplay(plsc, *pcpLim);
  1426. SetLastDnodeDisplay(plsc, plsdnBreak);
  1427. }
  1428. }
  1429. else /* hard break */
  1430. {
  1431. *pfSuccessful = fTrue;
  1432. *pcpLim = GetCurrentCpLim(plsc);
  1433. *pdcpDepend = 0;
  1434. /* plsdnBreak can be NULL because of deleting splat */
  1435. *pendr = EndrFromBreakDnode(plsdnBreak);
  1436. /* set boundaries for display */
  1437. if (plsdnBreak != NULL && FIsDnodeSplat(plsdnBreak))
  1438. {
  1439. SetCpLimDisplay(plsc, *pcpLim - 1);
  1440. SetLastDnodeDisplay(plsc, plsdnBreak->plsdnPrev);
  1441. }
  1442. else
  1443. {
  1444. SetCpLimDisplay(plsc, *pcpLim);
  1445. SetLastDnodeDisplay(plsc, plsdnBreak);
  1446. }
  1447. }
  1448. return lserrNone;
  1449. }
  1450. /* ---------------------------------------------------------------------- */
  1451. /* T R U N C A T E S U B L I N E C O R E */
  1452. /*----------------------------------------------------------------------------
  1453. %%Function: TruncateSublineCore
  1454. %%Contact: igorzv
  1455. Parameters:
  1456. plssubl - (IN) subline context
  1457. urColumnMax - (IN) urColumnMax
  1458. pcpTruncate - (OUT) cpTruncate
  1459. ----------------------------------------------------------------------------*/
  1460. LSERR TruncateSublineCore(PLSSUBL plssubl, long urColumnMax, LSCP* pcpTruncate)
  1461. {
  1462. LSERR lserr;
  1463. POSINLINE posinlineTruncate;
  1464. BOOL fAllLineAfterRightMargin;
  1465. Assert(FIsLSSUBL(plssubl));
  1466. lserr = TruncateCore(plssubl, urColumnMax, &posinlineTruncate, &fAllLineAfterRightMargin);
  1467. Assert(!fAllLineAfterRightMargin);
  1468. if (lserr != lserrNone)
  1469. return lserr;
  1470. *pcpTruncate = GetCpLimFromPosInLine(posinlineTruncate) - 1;
  1471. return lserrNone;
  1472. }
  1473. /* ---------------------------------------------------------------------- */
  1474. /* F I N D P R E V B R E A K S U B L I N E C O R E */
  1475. /*----------------------------------------------------------------------------
  1476. %%Function: FindPrevBreakSublineCore
  1477. %%Contact: igorzv
  1478. Parameters:
  1479. plssubl - (IN) subline context
  1480. fFirstSubline - (IN) to apply rules for first character to the first character of
  1481. this subline
  1482. cpTruncate - (IN) truncation cp
  1483. urColumnMax - (IN) urColumnMax
  1484. pfSuccessful - (OUT) do we find break?
  1485. pcpBreak - (OUT) cp of break
  1486. pobdimBreakSubline - (OUT) objdimSub up to break
  1487. pbrkpos - (OUT) Before/Inside/After
  1488. ----------------------------------------------------------------------------*/
  1489. LSERR FindPrevBreakSublineCore(PLSSUBL plssubl, BOOL fFirstSubline, LSCP cpTruncate,
  1490. long urColumnMax, BOOL* pfSuccessful,
  1491. LSCP* pcpBreak, POBJDIM pobdimBreakSubline, BRKPOS* pbrkpos)
  1492. {
  1493. LSERR lserr;
  1494. POSINLINE posinlineTruncate;
  1495. BRKOUT brkout;
  1496. PLSDNODE plsdnBreak;
  1497. LSDCP dcpDnodeOld;
  1498. OBJDIM objdimDnodeOld;
  1499. PLSDNODE plsdnToChange;
  1500. Assert(FIsLSSUBL(plssubl));
  1501. if (plssubl->plsdnFirst == NULL)
  1502. {
  1503. *pfSuccessful = fFalse;
  1504. return lserrNone;
  1505. }
  1506. if (cpTruncate < plssubl->plsdnFirst->cpFirst)
  1507. {
  1508. *pfSuccessful = fFalse;
  1509. return lserrNone;
  1510. }
  1511. GetPosInLineTruncateFromCp(plssubl, cpTruncate, fTrue, &posinlineTruncate);
  1512. lserr = FindPrevBreakCore(urColumnMax, &posinlineTruncate, fFirstSubline,
  1513. &brkout, &(plssubl->pbrkcontext->posinlineBreakPrev),
  1514. &(plssubl->pbrkcontext->brkkindForPrev));
  1515. if (lserr != lserrNone)
  1516. return lserr;
  1517. *pfSuccessful = brkout.fSuccessful;
  1518. if (*pfSuccessful)
  1519. {
  1520. *pcpBreak = GetCpLimFromPosInLine(plssubl->pbrkcontext->posinlineBreakPrev);
  1521. plssubl->pbrkcontext->objdimBreakPrev = brkout.objdim;
  1522. plssubl->pbrkcontext->fBreakPrevValid = fTrue;
  1523. plsdnBreak = plssubl->pbrkcontext->posinlineBreakPrev.plsdn;
  1524. *pbrkpos = GetBrkpos(plsdnBreak,
  1525. plssubl->pbrkcontext->posinlineBreakPrev.dcp);
  1526. /* we temporary change dnode to calculate objdim from the begining of subline */
  1527. plsdnToChange = plsdnBreak; /* later plsdnBreak can be changed because of borders */
  1528. dcpDnodeOld = plsdnToChange->dcp;
  1529. objdimDnodeOld = plsdnToChange->u.real.objdim;
  1530. plsdnToChange->dcp = plssubl->pbrkcontext->posinlineBreakPrev.dcp;
  1531. SetDnodeObjdimFmt(plsdnToChange, brkout.objdim);
  1532. lserr = FindListDims(plssubl->plsdnFirst, plsdnBreak, pobdimBreakSubline);
  1533. if (lserr != lserrNone)
  1534. return lserr;
  1535. /* recalculate durBreak taking into account possible changes because of borders */
  1536. if (FBorderEncounted(plssubl->plsc))
  1537. {
  1538. lserr = MoveClosingBorderAfterBreak(plssubl, fFalse, &plsdnBreak,
  1539. &(pobdimBreakSubline->dur));
  1540. if (lserr != lserrNone)
  1541. return lserr;
  1542. }
  1543. /*restore dnode */
  1544. plsdnToChange->dcp = dcpDnodeOld ;
  1545. SetDnodeObjdimFmt(plsdnToChange, objdimDnodeOld);
  1546. }
  1547. return lserrNone;
  1548. }
  1549. /* ---------------------------------------------------------------------- */
  1550. /* F I N D N E X T B R E A K S U B L I N E C O R E */
  1551. /*----------------------------------------------------------------------------
  1552. %%Function: FindNextBreakSublineCore
  1553. %%Contact: igorzv
  1554. Parameters:
  1555. plssubl - (IN) subline context
  1556. fFirstSubline - (IN) to apply rules for first character to the first character of
  1557. this subline
  1558. cpTruncate - (IN) truncation cp
  1559. urColumnMax - (IN) urColumnMax
  1560. pfSuccessful - (OUT) do we find break?
  1561. pcpBreak - (OUT) cp of break
  1562. pobdimBreakSubline - (OUT) objdimSub up to break
  1563. pbrkpos - (OUT) Before/Inside/After
  1564. ----------------------------------------------------------------------------*/
  1565. LSERR FindNextBreakSublineCore(PLSSUBL plssubl, BOOL fFirstSubline, LSCP cpTruncate,
  1566. long urColumnMax, BOOL* pfSuccessful,
  1567. LSCP* pcpBreak, POBJDIM pobdimBreakSubline, BRKPOS* pbrkpos)
  1568. {
  1569. LSERR lserr;
  1570. POSINLINE posinlineTruncate;
  1571. BRKOUT brkout;
  1572. PLSDNODE plsdnBreak;
  1573. LSDCP dcpDnodeOld;
  1574. OBJDIM objdimDnodeOld;
  1575. PLSDNODE plsdnToChange;
  1576. Assert(FIsLSSUBL(plssubl));
  1577. if (plssubl->plsdnFirst == NULL)
  1578. {
  1579. *pfSuccessful = fFalse;
  1580. return lserrNone;
  1581. }
  1582. if (cpTruncate >= plssubl->plsdnLast->cpLimOriginal)
  1583. {
  1584. *pfSuccessful = fFalse;
  1585. return lserrNone;
  1586. }
  1587. GetPosInLineTruncateFromCp(plssubl, cpTruncate, fFalse, &posinlineTruncate);
  1588. lserr = FindNextBreakCore(urColumnMax, &posinlineTruncate, fFirstSubline, fFalse,
  1589. &brkout, &(plssubl->pbrkcontext->posinlineBreakNext),
  1590. &(plssubl->pbrkcontext->brkkindForNext));
  1591. if (lserr != lserrNone)
  1592. return lserr;
  1593. *pfSuccessful = brkout.fSuccessful;
  1594. if (*pfSuccessful)
  1595. {
  1596. *pcpBreak = GetCpLimFromPosInLine(plssubl->pbrkcontext->posinlineBreakNext);
  1597. plssubl->pbrkcontext->objdimBreakNext = brkout.objdim;
  1598. plssubl->pbrkcontext->fBreakNextValid = fTrue;
  1599. plsdnBreak = plssubl->pbrkcontext->posinlineBreakNext.plsdn;
  1600. *pbrkpos = GetBrkpos(plsdnBreak,
  1601. plssubl->pbrkcontext->posinlineBreakNext.dcp);
  1602. /* we temporary change dnode to calculate objdim from the begining of subline */
  1603. plsdnToChange = plsdnBreak; /* later plsdnBreak can be changed because of borders */
  1604. dcpDnodeOld = plsdnToChange->dcp;
  1605. objdimDnodeOld = plsdnToChange->u.real.objdim;
  1606. plsdnToChange->dcp = plssubl->pbrkcontext->posinlineBreakNext.dcp;
  1607. SetDnodeObjdimFmt(plsdnToChange, brkout.objdim);
  1608. lserr = FindListDims(plssubl->plsdnFirst, plsdnBreak, pobdimBreakSubline);
  1609. if (lserr != lserrNone)
  1610. return lserr;
  1611. /* recalculate durBreak taking into account possible changes because of borders */
  1612. if (FBorderEncounted(plssubl->plsc))
  1613. {
  1614. lserr = MoveClosingBorderAfterBreak(plssubl, fFalse,
  1615. &plsdnBreak, &(pobdimBreakSubline->dur));
  1616. if (lserr != lserrNone)
  1617. return lserr;
  1618. }
  1619. /*restore dnode */
  1620. plsdnToChange->dcp = dcpDnodeOld ;
  1621. SetDnodeObjdimFmt(plsdnToChange, objdimDnodeOld);
  1622. }
  1623. return lserrNone;
  1624. }
  1625. /* ---------------------------------------------------------------------- */
  1626. /* F O R C E B R E A K S U B L I N E C O R E */
  1627. /*----------------------------------------------------------------------------
  1628. %%Function: ForceBreakSublineCore
  1629. %%Contact: igorzv
  1630. Parameters:
  1631. plssubl - (IN) subline context
  1632. fFirstSubline - (IN) to apply rules for first character to the first character of
  1633. this subline
  1634. cpTruncate - (IN) truncation cp
  1635. urColumnMax - (IN) urColumnMax
  1636. pcpBreak - (OUT) cp of break
  1637. pobdimBreakSubline - (OUT) objdimSub up to break
  1638. pbkrpos - (OUT) Before/Inside/After
  1639. ----------------------------------------------------------------------------*/
  1640. LSERR ForceBreakSublineCore(PLSSUBL plssubl, BOOL fFirstSubline, LSCP cpTruncate,
  1641. long urColumnMax, LSCP* pcpBreak,
  1642. POBJDIM pobdimBreakSubline, BRKPOS* pbrkpos)
  1643. {
  1644. LSERR lserr;
  1645. BRKOUT brkout;
  1646. LSDCP dcpDnodeOld;
  1647. PLSDNODE plsdnBreak;
  1648. OBJDIM objdimDnodeOld;
  1649. POSINLINE posinlineTruncate;
  1650. PLSDNODE plsdnToChange;
  1651. Assert(FIsLSSUBL(plssubl));
  1652. if (plssubl->plsdnFirst == NULL)
  1653. return lserrCpOutsideSubline;
  1654. if (cpTruncate < plssubl->plsdnFirst->cpFirst)
  1655. cpTruncate = plssubl->plsdnFirst->cpFirst;
  1656. GetPosInLineTruncateFromCp(plssubl, cpTruncate, fTrue, &posinlineTruncate);
  1657. lserr = ForceBreakCore(urColumnMax, &posinlineTruncate,
  1658. fFalse, fFirstSubline, fFalse, &brkout,
  1659. &(plssubl->pbrkcontext->posinlineBreakForce),
  1660. &(plssubl->pbrkcontext->brkkindForForce));
  1661. if (lserr != lserrNone)
  1662. return lserr;
  1663. Assert(brkout.fSuccessful); /* force break should be successful for not a main line */
  1664. *pcpBreak = GetCpLimFromPosInLine(plssubl->pbrkcontext->posinlineBreakForce);
  1665. plssubl->pbrkcontext->objdimBreakForce = brkout.objdim;
  1666. plssubl->pbrkcontext->fBreakForceValid = fTrue;
  1667. plsdnBreak = plssubl->pbrkcontext->posinlineBreakForce.plsdn;
  1668. *pbrkpos = GetBrkpos(plsdnBreak,
  1669. plssubl->pbrkcontext->posinlineBreakForce.dcp);
  1670. /* we temporary change dnode to calculate objdim from the begining of subline */
  1671. plsdnToChange = plsdnBreak; /* later plsdnBreak can be changed because of borders */
  1672. dcpDnodeOld = plsdnToChange->dcp;
  1673. objdimDnodeOld = plsdnToChange->u.real.objdim;
  1674. plsdnToChange->dcp = plssubl->pbrkcontext->posinlineBreakForce.dcp;
  1675. SetDnodeObjdimFmt(plsdnToChange, brkout.objdim);
  1676. lserr = FindListDims(plssubl->plsdnFirst, plsdnBreak, pobdimBreakSubline);
  1677. if (lserr != lserrNone)
  1678. return lserr;
  1679. /* recalculate durBreak taking into account possible changes because of borders */
  1680. if (FBorderEncounted(plssubl->plsc))
  1681. {
  1682. lserr = MoveClosingBorderAfterBreak(plssubl, fFalse,
  1683. &plsdnBreak, &(pobdimBreakSubline->dur));
  1684. if (lserr != lserrNone)
  1685. return lserr;
  1686. }
  1687. /*restore dnode */
  1688. plsdnToChange->dcp = dcpDnodeOld ;
  1689. SetDnodeObjdimFmt(plsdnToChange, objdimDnodeOld);
  1690. return lserrNone;
  1691. }
  1692. /* ---------------------------------------------------------------------- */
  1693. /* S E T B R E A K S U B L I N E C O R E */
  1694. /*----------------------------------------------------------------------------
  1695. %%Function: SetBreakSublineCore
  1696. %%Contact: igorzv
  1697. Parameters:
  1698. plssubl - (IN) subline context
  1699. brkkind, - (IN) Prev/Next/Force/Imposed
  1700. breakrecMaxCurrent - (IN) size of the array of current line's break records
  1701. pbreakrecCurrent - (OUT) current line's break records
  1702. pbreakrecMacCurrent - (OUT) actual number of current line's break records
  1703. ----------------------------------------------------------------------------*/
  1704. LSERR SetBreakSublineCore(PLSSUBL plssubl, BRKKIND brkkind, DWORD breakrecMaxCurrent,
  1705. BREAKREC* pbreakrecCurrent, DWORD* pbreakrecMacCurrent)
  1706. {
  1707. POSINLINE* pposinline;
  1708. LSCP cpLim;
  1709. LSDCP dcpDepend;
  1710. OBJDIM* pobjdim;
  1711. POSINLINE posinlineImposedAfter;
  1712. BRKKIND brkkindDnode;
  1713. BOOL fEndOfContent;
  1714. ENDRES endr;
  1715. BOOL fSuccessful;
  1716. Assert(FIsLSSUBL(plssubl));
  1717. /* invalidate chunkcontext, otherwise we will have wrong result of optimization there */
  1718. InvalidateChunk(plssubl->plschunkcontext);
  1719. switch (brkkind)
  1720. {
  1721. case brkkindPrev:
  1722. if (!plssubl->pbrkcontext->fBreakPrevValid)
  1723. return lserrWrongBreak;
  1724. pposinline = &(plssubl->pbrkcontext->posinlineBreakPrev);
  1725. pobjdim = &(plssubl->pbrkcontext->objdimBreakPrev);
  1726. brkkindDnode = plssubl->pbrkcontext->brkkindForPrev;
  1727. break;
  1728. case brkkindNext:
  1729. if (!plssubl->pbrkcontext->fBreakNextValid)
  1730. return lserrWrongBreak;
  1731. pposinline = &(plssubl->pbrkcontext->posinlineBreakNext);
  1732. pobjdim = &(plssubl->pbrkcontext->objdimBreakNext);
  1733. brkkindDnode = plssubl->pbrkcontext->brkkindForNext;
  1734. break;
  1735. case brkkindForce:
  1736. if (!plssubl->pbrkcontext->fBreakForceValid)
  1737. return lserrWrongBreak;
  1738. pposinline = &(plssubl->pbrkcontext->posinlineBreakForce);
  1739. pobjdim = &(plssubl->pbrkcontext->objdimBreakForce);
  1740. brkkindDnode = plssubl->pbrkcontext->brkkindForForce;
  1741. break;
  1742. case brkkindImposedAfter:
  1743. /* subline is empty: nothing to do */
  1744. if (plssubl->plsdnFirst == NULL)
  1745. return lserrNone;
  1746. posinlineImposedAfter.plssubl = plssubl;
  1747. posinlineImposedAfter.plsdn = GetCurrentDnodeSubl(plssubl);
  1748. GetCurrentPointSubl(plssubl, posinlineImposedAfter.pointStart);
  1749. GetPointBeforeDnodeFromPointAfter(posinlineImposedAfter.plsdn,
  1750. &(posinlineImposedAfter.pointStart));
  1751. posinlineImposedAfter.dcp = GetCurrentDnodeSubl(plssubl)->dcp;
  1752. while (FIsDnodeBorder(posinlineImposedAfter.plsdn))
  1753. {
  1754. GoPrevPosInLine(&posinlineImposedAfter, fEndOfContent);
  1755. Assert(!fEndOfContent);
  1756. }
  1757. pposinline = &posinlineImposedAfter;
  1758. /* for the case of a pen we are passing garbage as an objdim,
  1759. assuming that it will never be used */
  1760. pobjdim = &(posinlineImposedAfter.plsdn->u.real.objdim);
  1761. brkkindDnode = brkkindImposedAfter;
  1762. break;
  1763. default:
  1764. return lserrWrongBreak;
  1765. }
  1766. return SetBreakCore(pposinline, pobjdim, brkkindDnode, fFalse, fFalse, breakrecMaxCurrent,
  1767. pbreakrecCurrent, pbreakrecMacCurrent,
  1768. &cpLim, &dcpDepend, &endr, &fSuccessful);
  1769. }
  1770. /* ---------------------------------------------------------------------- */
  1771. /* S Q U E E Z E S U B L I N E C O R E */
  1772. /*----------------------------------------------------------------------------
  1773. %%Function: SqueezeSublineCore
  1774. %%Contact: igorzv
  1775. Parameters:
  1776. plssubl - (IN) subline context
  1777. durTarget - (IN) desirable width
  1778. pfSuceessful- (OUT) do we achieve the goal
  1779. pdurExtra - (OUT) if nof successful, how much we fail
  1780. ----------------------------------------------------------------------------*/
  1781. LSERR WINAPI SqueezeSublineCore(PLSSUBL plssubl, long durTarget,
  1782. BOOL* pfSuccessful, long* pdurExtra)
  1783. {
  1784. GRCHUNKEXT grchnkextCompression;
  1785. PLSC plsc;
  1786. long durToCompress;
  1787. BOOL fLineCompressed;
  1788. LSERR lserr;
  1789. Assert(FIsLSSUBL(plssubl));
  1790. plsc = plssubl->plsc;
  1791. durToCompress = GetCurrentUrSubl(plssubl) - durTarget;
  1792. InitGroupChunkExt(PlschunkcontextFromSubline(plssubl),
  1793. IobjTextFromLsc(&plsc->lsiobjcontext), &grchnkextCompression);
  1794. if (durToCompress > 0)
  1795. {
  1796. lserr = CollectPreviousTextGroupChunk(GetCurrentDnodeSubl(plssubl), CollectSublinesForCompression,
  1797. fFalse, /* simple text */
  1798. &grchnkextCompression);
  1799. if (lserr != lserrNone)
  1800. return lserr;
  1801. durToCompress -= grchnkextCompression.durTrailing;
  1802. if (FDnodeHasBorder(grchnkextCompression.plsdnStartTrailing))
  1803. {
  1804. /* we should reserve room for closing border */
  1805. durToCompress += DurBorderFromDnodeInside(grchnkextCompression.plsdnStartTrailing);
  1806. }
  1807. lserr = CanCompressText(&(grchnkextCompression.lsgrchnk),
  1808. &(grchnkextCompression.posichnkBeforeTrailing),
  1809. LstflowFromSubline(plssubl),
  1810. durToCompress, pfSuccessful,
  1811. &fLineCompressed, pdurExtra);
  1812. if (lserr != lserrNone)
  1813. return lserr;
  1814. }
  1815. else
  1816. {
  1817. *pdurExtra = 0;
  1818. *pfSuccessful = fTrue;
  1819. }
  1820. return lserrNone;
  1821. }
  1822. /* ---------------------------------------------------------------------- */
  1823. /* G E T P O S I N L I N E T R U N C A T E F R O M C P */
  1824. /*----------------------------------------------------------------------------
  1825. %%Function: GetPosInLineTruncateFromCp
  1826. %%Contact: igorzv
  1827. Parameters:
  1828. plssubl - (IN) subline context
  1829. cp - (IN) cp of position
  1830. pposinline - (OUT) position in a subline
  1831. ----------------------------------------------------------------------------*/
  1832. void GetPosInLineTruncateFromCp(
  1833. PLSSUBL plssubl, /* IN: subline */
  1834. LSCP cp, /* IN: cp of a position */
  1835. BOOL fSnapPrev, /* IN: direction of snapping hidden cp */
  1836. POSINLINE* pposinline) /* OUT: position in a subline */
  1837. {
  1838. PLSDNODE plsdn;
  1839. BOOL fSuccessful = fFalse;
  1840. BOOL fLastReached = fFalse;
  1841. BOOL fPassed = fFalse;
  1842. LSDCP dcp;
  1843. Assert(FIsLSSUBL(plssubl));
  1844. pposinline->plssubl = plssubl;
  1845. pposinline->pointStart.u = 0;
  1846. pposinline->pointStart.v = 0;
  1847. plsdn = plssubl->plsdnFirst;
  1848. while(!fSuccessful && !fLastReached &&!fPassed)
  1849. {
  1850. Assert(plsdn != NULL);
  1851. Assert(FIsLSDNODE(plsdn));
  1852. if (plsdn == plssubl->plsdnLast)
  1853. fLastReached = fTrue;
  1854. if (plsdn->cpFirst > cp) /* our cp is not inside any dnode */
  1855. {
  1856. fPassed = fTrue;
  1857. }
  1858. else
  1859. {
  1860. if (cp < plsdn->cpLimOriginal)
  1861. {
  1862. fSuccessful = fTrue;
  1863. pposinline->plsdn = plsdn;
  1864. dcp = cp - plsdn->cpFirst + 1;
  1865. if (dcp <= plsdn->dcp) /* such calculations are because of a case of ligature */
  1866. pposinline->dcp = dcp; /* across hiden text, in such case cpLimOriginal */
  1867. else /* is not equal to cpFirst + dcp */
  1868. pposinline->dcp = plsdn->dcp; /* such calculation doesn't guarantee exact cp, */
  1869. } /* but at least in the same ligature */
  1870. else
  1871. {
  1872. if (!fLastReached)
  1873. {
  1874. pposinline->pointStart.u += DurFromDnode(plsdn);
  1875. pposinline->pointStart.v += DvrFromDnode(plsdn);
  1876. plsdn = plsdn->plsdnNext;
  1877. }
  1878. }
  1879. }
  1880. }
  1881. if (!fSuccessful)
  1882. {
  1883. if (fSnapPrev)
  1884. {
  1885. /* snap to previous dnode */
  1886. if (fPassed)
  1887. {
  1888. Assert(plsdn != NULL); /* we don't allow caller to pass cp before first dnode */
  1889. plsdn = plsdn->plsdnPrev;
  1890. /* skip borders */
  1891. while(FIsDnodeBorder(plsdn))
  1892. {
  1893. plsdn = plsdn->plsdnPrev;
  1894. }
  1895. Assert(plsdn != NULL);
  1896. pposinline->plsdn = plsdn;
  1897. pposinline->dcp = plsdn->dcp;
  1898. pposinline->pointStart.u -= DurFromDnode(plsdn);
  1899. pposinline->pointStart.v -= DvrFromDnode(plsdn);
  1900. }
  1901. else
  1902. {
  1903. Assert(fLastReached);
  1904. /* skip borders */
  1905. while(FIsDnodeBorder(plsdn))
  1906. {
  1907. plsdn = plsdn->plsdnPrev;
  1908. }
  1909. Assert(plsdn != NULL);
  1910. pposinline->plsdn = plsdn;
  1911. pposinline->dcp = plsdn->dcp;
  1912. }
  1913. }
  1914. else
  1915. {
  1916. /* snap to current dnode */
  1917. if (fPassed)
  1918. {
  1919. /* skip borders */
  1920. while(FIsDnodeBorder(plsdn))
  1921. {
  1922. plsdn = plsdn->plsdnNext;
  1923. }
  1924. Assert(plsdn != NULL);
  1925. pposinline->plsdn = plsdn;
  1926. pposinline->dcp = 1;
  1927. }
  1928. else
  1929. {
  1930. Assert(fLastReached);
  1931. /* we don't allow caller to pass cp after last dnode */
  1932. NotReached();
  1933. }
  1934. }
  1935. }
  1936. }
  1937. /* ---------------------------------------------------------------------- */
  1938. /* F I N D F I R S T D N O D E C O N T A I N S R I G H T M A R G I N */
  1939. /*----------------------------------------------------------------------------
  1940. %%Function: FindFirstDnodeContainsRightMargin
  1941. %%Contact: igorzv
  1942. Parameters:
  1943. urColumnMax - (IN) right margin
  1944. pposinline - (IN,OUT) position in a subline: before position in the end,
  1945. after first position contains right margin
  1946. ----------------------------------------------------------------------------*/
  1947. static void FindFirstDnodeContainsRightMargin(long urColumnMax, POSINLINE* pposinlineTruncate)
  1948. {
  1949. POSINLINE posinline;
  1950. BOOL fOutside;
  1951. BOOL fFound = fFalse;
  1952. BOOL fEndOfContent;
  1953. posinline = *pposinlineTruncate;
  1954. // we know that last done ends after right margin
  1955. Assert(posinline.pointStart.u + DurFromDnode(posinline.plsdn) > urColumnMax);
  1956. fOutside = fTrue;
  1957. fEndOfContent = fFalse;
  1958. do
  1959. {
  1960. if (posinline.pointStart.u <= urColumnMax)
  1961. {
  1962. if (fOutside)
  1963. {
  1964. fFound = fTrue;
  1965. *pposinlineTruncate = posinline;
  1966. }
  1967. fOutside = fFalse;
  1968. }
  1969. else
  1970. {
  1971. fOutside = fTrue;
  1972. }
  1973. GoPrevPosInLine(&posinline, fEndOfContent);
  1974. } while (!fEndOfContent);
  1975. if (!fFound)
  1976. {
  1977. *pposinlineTruncate = posinline; // we cann't right dnode and return fisrt dnode to report situation
  1978. }
  1979. }
  1980. /* ---------------------------------------------------------------------- */
  1981. /* G E T L I N E D U R C O R E */
  1982. /*----------------------------------------------------------------------------
  1983. %%Function: GetLineDurCore
  1984. %%Contact: igorzv
  1985. Parameters:
  1986. plsc - (IN) LS context
  1987. pdurInclTrail - (OUT) dur of line incl. trailing area
  1988. pdurExclTrail - (OUT) dur of line excl. trailing area
  1989. ----------------------------------------------------------------------------*/
  1990. LSERR GetLineDurCore (PLSC plsc, long* pdurInclTrail, long* pdurExclTrail)
  1991. {
  1992. PLSDNODE plsdn;
  1993. LSERR lserr;
  1994. long durTrail;
  1995. LSDCP dcpTrail;
  1996. PLSDNODE plsdnStartTrail;
  1997. LSDCP dcpStartTrailingText;
  1998. int cDnodesTrailing;
  1999. PLSDNODE plsdnTrailingObject;
  2000. LSDCP dcpTrailingObject;
  2001. BOOL fClosingBorderStartsTrailing;
  2002. plsdn = GetCurrentDnode(plsc);
  2003. *pdurInclTrail = GetCurrentUr(plsc);
  2004. *pdurExclTrail = *pdurInclTrail;
  2005. if (plsdn != NULL && !FIsNotInContent(plsdn))
  2006. {
  2007. lserr = GetTrailingInfoForTextGroupChunk(plsdn, plsdn->dcp,
  2008. IobjTextFromLsc(&plsc->lsiobjcontext),
  2009. &durTrail, &dcpTrail, &plsdnStartTrail,
  2010. &dcpStartTrailingText, &cDnodesTrailing, &plsdnTrailingObject,
  2011. &dcpTrailingObject, &fClosingBorderStartsTrailing);
  2012. if (lserr != lserrNone)
  2013. return lserr;
  2014. *pdurExclTrail = *pdurInclTrail - durTrail;
  2015. }
  2016. return lserrNone;
  2017. }
  2018. /* ---------------------------------------------------------------------- */
  2019. /* G E T M I N D U R B R E A K S C O R E */
  2020. /*----------------------------------------------------------------------------
  2021. %%Function: GetMinDurBreaksCore
  2022. %%Contact: igorzv
  2023. Parameters:
  2024. plsc - (IN) LS context
  2025. pdurMinInclTrail - (OUT) min dur between breaks including trailing area
  2026. pdurMinExclTrail - (OUT) min dur between breaks excluding trailing area
  2027. ----------------------------------------------------------------------------*/
  2028. LSERR GetMinDurBreaksCore (PLSC plsc, long* pdurMinInclTrail, long* pdurMinExclTrail)
  2029. {
  2030. LSERR lserr;
  2031. PLSCHUNKCONTEXT plschunkcontext;
  2032. LOCCHNK* plocchnk;
  2033. POINTUV point;
  2034. long durTrail;
  2035. DWORD cchTrail;
  2036. POSINLINE posinline;
  2037. POSINLINE posinlineBreak;
  2038. BRKOUT brkout;
  2039. long urBreakInclTrail = 0;
  2040. long urBreakExclTrail = 0;
  2041. long urBreakInclTrailPrev;
  2042. long urBreakExclTrailPrev;
  2043. BOOL fEndOfContent = fFalse;
  2044. BRKKIND brkkind;
  2045. PLSDNODE plsdnStartTrail;
  2046. LSDCP dcpStartTrailingText;
  2047. int cDnodesTrailing;
  2048. PLSDNODE plsdnTrailingObject;
  2049. LSDCP dcpTrailingObject;
  2050. BOOL fClosingBorderStartsTrailing;
  2051. plschunkcontext = PlschunkcontextFromSubline(GetCurrentSubline(plsc));
  2052. plocchnk = &(plschunkcontext->locchnkCurrent);
  2053. *pdurMinInclTrail = 0;
  2054. *pdurMinExclTrail = 0;
  2055. GetCurrentPoint(plsc, point);
  2056. posinline.plssubl = GetCurrentSubline(plsc);
  2057. posinline.pointStart = point;
  2058. posinline.plsdn = GetCurrentDnode(plsc);
  2059. urBreakInclTrail = GetCurrentUr(plsc);
  2060. urBreakExclTrail = urBreakInclTrail;
  2061. /* REVIEW rewrite without code duplication and some probably superflous lines */
  2062. /* don't forget about problem of dnode which submitted subline for trailing and skiping trailing
  2063. area( tailing area in subline and dcp in parent dnode */
  2064. if (posinline.plsdn != NULL && !FIsNotInContent(posinline.plsdn))
  2065. {
  2066. GetPointBeforeDnodeFromPointAfter(posinline.plsdn, &(posinline.pointStart));
  2067. posinline.dcp = posinline.plsdn->dcp;
  2068. lserr = GetTrailingInfoForTextGroupChunk(posinline.plsdn, posinline.dcp,
  2069. IobjTextFromLsc(&plsc->lsiobjcontext),
  2070. &durTrail, &cchTrail, &plsdnStartTrail,
  2071. &dcpStartTrailingText, &cDnodesTrailing,
  2072. &plsdnTrailingObject, &dcpTrailingObject, &fClosingBorderStartsTrailing);
  2073. if (lserr != lserrNone)
  2074. return lserr;
  2075. urBreakExclTrail = urBreakInclTrail - durTrail;
  2076. /* move before trailing area */
  2077. while (posinline.plsdn != plsdnTrailingObject)
  2078. {
  2079. Assert(!fEndOfContent);
  2080. GoPrevPosInLine(&posinline, fEndOfContent);
  2081. }
  2082. posinline.dcp = dcpTrailingObject;
  2083. if (posinline.dcp == 0) /* move break before previous dnode */
  2084. {
  2085. do
  2086. {
  2087. GoPrevPosInLine(&posinline, fEndOfContent);
  2088. /* we allow to put break before the first dnode but stop loop here */
  2089. }
  2090. while (!fEndOfContent && FIsDnodeBorder(posinline.plsdn) );
  2091. }
  2092. }
  2093. else
  2094. {
  2095. fEndOfContent = fTrue;
  2096. }
  2097. if (fEndOfContent)
  2098. {
  2099. *pdurMinInclTrail = urBreakInclTrail;
  2100. *pdurMinExclTrail = urBreakExclTrail;
  2101. }
  2102. while(!fEndOfContent)
  2103. {
  2104. /* find previous break */
  2105. lserr = FindPrevBreakCore(urBreakInclTrail, &posinline, fTrue,
  2106. &brkout, &posinlineBreak, &brkkind);
  2107. if (lserr != lserrNone)
  2108. return lserr;
  2109. if (brkout.fSuccessful)
  2110. {
  2111. urBreakInclTrailPrev = posinlineBreak.pointStart.u + brkout.objdim.dur;
  2112. lserr = GetTrailingInfoForTextGroupChunk(posinlineBreak.plsdn,
  2113. posinlineBreak.dcp,
  2114. IobjTextFromLsc(&plsc->lsiobjcontext),
  2115. &durTrail, &cchTrail, &plsdnStartTrail,
  2116. &dcpStartTrailingText, &cDnodesTrailing,
  2117. &plsdnTrailingObject, &dcpTrailingObject, &fClosingBorderStartsTrailing);
  2118. if (lserr != lserrNone)
  2119. return lserr;
  2120. urBreakExclTrailPrev = urBreakInclTrailPrev - durTrail;
  2121. /* commands bellow prepare posinline for the next iteration */
  2122. if (posinlineBreak.plsdn->cpFirst > posinline.plsdn->cpFirst
  2123. || (posinlineBreak.plsdn == posinline.plsdn &&
  2124. posinlineBreak.dcp >= posinline.dcp
  2125. )
  2126. )
  2127. {
  2128. /* we are trying to avoid an infinite loop */
  2129. if (posinline.dcp != 0) posinline.dcp--;
  2130. /* posinline.dcp can be equal to 0 here in the case pen,
  2131. code bellow under if (posinline.dcp == 0) will help us to avoid infinite loop in such case*/
  2132. }
  2133. else
  2134. {
  2135. posinline = posinlineBreak;
  2136. /* move before trailing area */
  2137. while (posinline.plsdn != plsdnTrailingObject)
  2138. {
  2139. Assert(!fEndOfContent);
  2140. GoPrevPosInLine(&posinline, fEndOfContent);
  2141. }
  2142. posinline.dcp = dcpTrailingObject;
  2143. }
  2144. if (posinline.dcp == 0) /* move break before previous dnode */
  2145. {
  2146. do
  2147. {
  2148. GoPrevPosInLine(&posinline, fEndOfContent);
  2149. /* we allow to put break before the first dnode but stop loop here */
  2150. }
  2151. while (!fEndOfContent && FIsDnodeBorder(posinline.plsdn) );
  2152. }
  2153. }
  2154. else
  2155. {
  2156. urBreakInclTrailPrev = 0;
  2157. urBreakExclTrailPrev = 0;
  2158. fEndOfContent = fTrue;
  2159. }
  2160. /* calculate current value of the maximum distance between two break opportunites */
  2161. if (urBreakInclTrail - urBreakInclTrailPrev > *pdurMinInclTrail)
  2162. *pdurMinInclTrail = urBreakInclTrail - urBreakInclTrailPrev;
  2163. if (urBreakExclTrail - urBreakInclTrailPrev > *pdurMinExclTrail)
  2164. *pdurMinExclTrail = urBreakExclTrail - urBreakInclTrailPrev;
  2165. /* prepare next iteration */
  2166. urBreakInclTrail = urBreakInclTrailPrev;
  2167. urBreakExclTrail = urBreakExclTrailPrev;
  2168. }
  2169. return lserrNone;
  2170. }
  2171. /* F C A N B E F O R E N E X T C H U N K C O R E */
  2172. /*----------------------------------------------------------------------------
  2173. %%Function: FCanBreakBeforeNextChunkCore
  2174. %%Contact: igorzv
  2175. Parameters:
  2176. plsc - (IN) ptr to line services context
  2177. plsdn - (IN) Last DNODE of the current chunk
  2178. pfCanBreakBeforeNextChun-(OUT) Can break before next chunk ?
  2179. Called by text during find previous break when it's going to set break after last text dnode.
  2180. Procedure forwards this question to the next after text object
  2181. ----------------------------------------------------------------------------*/
  2182. LSERR FCanBreakBeforeNextChunkCore(PLSC plsc, PLSDNODE plsdn, BOOL* pfCanBreakBeforeNextChunk)
  2183. {
  2184. LSERR lserr;
  2185. PLSCHUNKCONTEXT plschunkcontextOld;
  2186. PLSCHUNKCONTEXT plschunkcontextNew;
  2187. BOOL fFound;
  2188. PLSDNODE plsdnInChunk;
  2189. DWORD idObj;
  2190. POSICHNK posichnk;
  2191. BRKCOND brkcond;
  2192. PLSSUBL plssublOld;
  2193. BRKOUT brkout;
  2194. plschunkcontextOld = PlschunkcontextFromSubline(SublineFromDnode(plsdn));
  2195. /* plsdnode should be the last dnode of the current chunk */
  2196. Assert(plsdn == LastDnodeFromChunk(plschunkcontextOld));
  2197. lserr = DuplicateChunkContext(plschunkcontextOld, &plschunkcontextNew);
  2198. if (lserr != lserrNone)
  2199. return lserr;
  2200. lserr = CollectNextChunk(plschunkcontextNew, &fFound);
  2201. if (lserr != lserrNone)
  2202. return lserr;
  2203. if (fFound)
  2204. {
  2205. plsdnInChunk = plschunkcontextNew->pplsdnChunk[0];
  2206. if (FIsDnodePen(plsdnInChunk) || plsdnInChunk->fTab || FIsDnodeSplat(plsdnInChunk))
  2207. {
  2208. *pfCanBreakBeforeNextChunk = fTrue;
  2209. }
  2210. else
  2211. {
  2212. idObj = IdObjFromDnode(plsdnInChunk);
  2213. /* we allow object handler to formate subline,
  2214. so we restore current subline after calling him */
  2215. plssublOld = GetCurrentSubline(plsc);
  2216. SetCurrentSubline(plsc, NULL);
  2217. /* we set truncation point to the first cp in chunk */
  2218. posichnk.ichnk = 0;
  2219. posichnk.dcp = 1;
  2220. brkcond = brkcondCan;
  2221. lserr = PLsimFromLsc(
  2222. &plsc->lsiobjcontext, idObj)->pfnFindPrevBreakChunk(&(plschunkcontextNew->locchnkCurrent),
  2223. &posichnk, brkcond, &brkout);
  2224. if (lserr != lserrNone)
  2225. return lserr;
  2226. SetCurrentSubline(plsc, plssublOld);
  2227. if (!brkout.fSuccessful && brkout.brkcond == brkcondNever)
  2228. *pfCanBreakBeforeNextChunk = fFalse;
  2229. else
  2230. *pfCanBreakBeforeNextChunk = fTrue;
  2231. }
  2232. }
  2233. else
  2234. {
  2235. /* it cann't happen on a main subline */
  2236. Assert(!FIsSubLineMain(SublineFromDnode(plsdn)));
  2237. *pfCanBreakBeforeNextChunk = fTrue;
  2238. }
  2239. DestroyChunkContext(plschunkcontextNew);
  2240. return lserrNone;
  2241. }