Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1854 lines
54 KiB

  1. #include "lsidefs.h"
  2. #include "dninfo.h"
  3. #include "dnutils.h"
  4. #include "fmti.h"
  5. #include "getfmtst.h"
  6. #include "iobj.h"
  7. #include "iobjln.h"
  8. #include "lsc.h"
  9. #include "lsdnode.h"
  10. #include "lsfetch.h"
  11. #include "lsfrun.h"
  12. #include "lsline.h"
  13. #include "lsesc.h"
  14. #include "lstext.h"
  15. #include "ntiman.h"
  16. #include "qheap.h"
  17. #include "setfmtst.h"
  18. #include "tabutils.h"
  19. #include "zqfromza.h"
  20. #include "lssubl.h"
  21. #include "autonum.h"
  22. #include "lscfmtfl.h"
  23. #include <limits.h>
  24. #include "lsmem.h" /* memset() */
  25. /* L I M R G */
  26. /*----------------------------------------------------------------------------
  27. %%Function: LimRg
  28. %%Contact: igorzv
  29. Returns # of elements in an array.
  30. ----------------------------------------------------------------------------*/
  31. #define LimRg(rg) (sizeof(rg)/sizeof((rg)[0]))
  32. /* A S S E R T V A L I D F M T R E S */
  33. /*----------------------------------------------------------------------------
  34. %%Macro: AssertValidFmtres
  35. %%Contact: lenoxb
  36. Verifies that fmtrCk has a legal value.
  37. ----------------------------------------------------------------------------*/
  38. #define AssertValidFmtres(fmtrCk) \
  39. Assert( \
  40. (fmtrCk) == fmtrCompletedRun || \
  41. (fmtrCk) == fmtrExceededMargin || \
  42. (fmtrCk) == fmtrTab || \
  43. (fmtrCk) == fmtrStopped \
  44. );
  45. /* S E T T O M A X */
  46. /*----------------------------------------------------------------------------
  47. %%Macro: SetToMax
  48. %%Contact: lenoxb
  49. Sets "a" to the maximum of "a" and "b".
  50. ----------------------------------------------------------------------------*/
  51. #define SetToMax(a,b) if ((a) < (b)) (a) = (b); else
  52. /* S E T H E I G H T T O M A X */
  53. /*----------------------------------------------------------------------------
  54. %%Macro: SetHeightToMax
  55. %%Contact: igorzv
  56. Sets the line height elements of an LSLINFO structure to the maximum
  57. of their current value, and the height of an arbitrary object.
  58. (plslinfo)->dvrMultiLineHeight == dvHeightIgnore is sign not
  59. to take into account this dnode
  60. ----------------------------------------------------------------------------*/
  61. #define SetHeightToMax(plslinfo,pobjdim) \
  62. {\
  63. if ((pobjdim)->heightsRef.dvMultiLineHeight != dvHeightIgnore)\
  64. {\
  65. SetToMax((plslinfo)->dvrAscent, (pobjdim)->heightsRef.dvAscent);\
  66. SetToMax((plslinfo)->dvpAscent, (pobjdim)->heightsPres.dvAscent);\
  67. SetToMax((plslinfo)->dvrDescent, (pobjdim)->heightsRef.dvDescent);\
  68. SetToMax((plslinfo)->dvpDescent, (pobjdim)->heightsPres.dvDescent);\
  69. SetToMax((plslinfo)->dvpMultiLineHeight, (pobjdim)->heightsPres.dvMultiLineHeight);\
  70. SetToMax((plslinfo)->dvrMultiLineHeight, (pobjdim)->heightsRef.dvMultiLineHeight);\
  71. }\
  72. }
  73. #define PlnobjFromLsc(plsc,iobj) ((Assert(FIsLSC(plsc)), PlnobjFromLsline((plsc)->plslineCur,iobj)))
  74. #define CreateLNObjInLsc(plsc, iobj) ((PLsimFromLsc(&((plsc)->lsiobjcontext),iobj))->pfnCreateLNObj\
  75. (PilsobjFromLsc(&((plsc)->lsiobjcontext),iobj), \
  76. &((plsc)->plslineCur->rgplnobj[iobj])))
  77. /* This macros created to avoid code duplication */
  78. #define FRunIsNotSimple(plschp, fHidden) \
  79. (((plschp)->idObj != idObjTextChp) || \
  80. ((fHidden)) || \
  81. ((plschp)->fBorder) || \
  82. FApplyNominalToIdeal(plschp))
  83. #define CreateDnode(plsc, plsdnNew) \
  84. (plsdnNew) = PvNewQuick(GetPqhAllDNodes(plsc), sizeof *(plsdnNew));\
  85. if ((plsdnNew) == NULL)\
  86. return lserrOutOfMemory;\
  87. (plsdnNew)->tag = tagLSDNODE;\
  88. (plsdnNew)->plsdnPrev = GetCurrentDnode(plsc);\
  89. (plsdnNew)->plsdnNext = NULL;\
  90. (plsdnNew)->plssubl = GetCurrentSubline(plsc);\
  91. /* we don't connect dnode list with this dnode untill handler calls*/ \
  92. /*Finish API, but we put correct pointer to previous in this dnode,*/ \
  93. /*so we can easily link list in Finish routines */\
  94. (plsdnNew)->cpFirst = GetCurrentCpLim(plsc); \
  95. /* flush all flags, bellow check that result is what we expect */ \
  96. *((DWORD *) ((&(plsdnNew)->dcp)+1)) = 0;\
  97. Assert((plsdnNew)->klsdn == klsdnReal);\
  98. Assert((plsdnNew)->fRigidDup == fFalse);\
  99. Assert((plsdnNew)->fAdvancedPen == fFalse);\
  100. Assert((plsdnNew)->fTab == fFalse);\
  101. Assert((plsdnNew)->icaltbd == 0);\
  102. Assert((plsdnNew)->fBorderNode == fFalse);\
  103. Assert((plsdnNew)->fOpenBorder == fFalse);\
  104. Assert((plsdnNew)->fEndOfSection == fFalse); \
  105. Assert((plsdnNew)->fEndOfColumn == fFalse); \
  106. Assert((plsdnNew)->fEndOfPage == fFalse); \
  107. Assert((plsdnNew)->fEndOfPara == fFalse); \
  108. Assert((plsdnNew)->fAltEndOfPara == fFalse); \
  109. Assert((plsdnNew)->fSoftCR == fFalse); \
  110. Assert((plsdnNew)->fInsideBorder == fFalse); \
  111. Assert((plsdnNew)->fAutoDecTab == fFalse); \
  112. Assert((plsdnNew)->fTabForAutonumber == fFalse);
  113. #define FillRealPart(plsdnNew, plsfrunOfDnode)\
  114. /* we don't initialize here variables that will be set in FiniSimpleRegular */ \
  115. (plsdnNew)->u.real.pinfosubl = NULL;\
  116. /* next two assignement we do to use DestroyDnodeList in the case of error */ \
  117. (plsdnNew)->u.real.plsrun = (plsfrunOfDnode)->plsrun;\
  118. (plsdnNew)->u.real.pdobj = NULL;\
  119. /* we put amount of characters to dcp to check it in LsdnFinishSimpleByOneChar */ \
  120. (plsdnNew)->dcp = (plsfrunOfDnode)->cwchRun; \
  121. (plsdnNew)->cpLimOriginal = (plsdnNew)->cpFirst + (plsdnNew)->dcp;
  122. #define CreateRealDnode(plsc,plsdnNew, plsrun)\
  123. CreateDnode((plsc), (plsdnNew));\
  124. FillRealPart((plsdnNew), (plsrun));
  125. #define CreatePenDnode(plsc,plsdnNew)\
  126. CreateDnode((plsc), (plsdnNew));\
  127. (plsdnNew)->dcp = 0;\
  128. (plsdnNew)->cpLimOriginal = (plsdnNew)->cpFirst;\
  129. (plsdnNew)->u.pen.dur = 0;\
  130. (plsdnNew)->u.pen.dup = 0;\
  131. (plsdnNew)->u.pen.dvr = 0;\
  132. (plsdnNew)->u.pen.dvp = 0;\
  133. (plsdnNew)->klsdn = klsdnPenBorder;
  134. #define CreateBorderDnode(plsc,plsdnNew, durBorder, dupBorder)\
  135. CreateDnode((plsc), (plsdnNew));\
  136. (plsdnNew)->dcp = 0;\
  137. (plsdnNew)->cpLimOriginal = (plsdnNew)->cpFirst;\
  138. (plsdnNew)->u.pen.dur = (durBorder);\
  139. (plsdnNew)->u.pen.dup = (dupBorder);\
  140. (plsdnNew)->u.pen.dvr = 0;\
  141. (plsdnNew)->u.pen.dvp = 0;\
  142. (plsdnNew)->klsdn = klsdnPenBorder; \
  143. (plsdnNew)->fBorderNode = fTrue; \
  144. TurnOnNonRealDnodeEncounted(plsc);
  145. #define FNeedToCutPossibleContextViolation(plsc, plsdn) \
  146. (FIsDnodeReal(plsdn) && \
  147. ((plsdn)->u.real.lschp.dcpMaxContext > 1) && \
  148. (IdObjFromDnode(plsdn) == IobjTextFromLsc(&((plsc)->lsiobjcontext))) \
  149. )
  150. /* ------------------------------------------------------------------ */
  151. static LSERR CheckNewPara(PLSC, LSCP, LSCP, BOOL*);
  152. static BOOL FLimitRunEsc(LSFRUN*, const LSESC*, DWORD);
  153. static LSERR CreateInitialPen(PLSC plsc, long dur);
  154. static LSERR UndoLastDnode(PLSC); /* IN: ls context */
  155. static LSERR OpenBorder(PLSC plsc, PLSRUN plsrun);
  156. static LSERR HandleSplat(PLSC plsc, FMTRES* pfmtres);
  157. static LSERR ErrReleaseRunToFormat (PLSC, /* IN: ptr to line services context */
  158. PLSRUN, /* IN: ponter to a run structure to be deleted */
  159. LSERR); /* IN: code of an error */
  160. /* ---------------------------------------------------------------------- */
  161. /* F E T C H A P P E N D E S C R E S U M E C O R E */
  162. /*----------------------------------------------------------------------------
  163. %%Function: FetchAppendEscResumeCore
  164. %%Contact: igorzv
  165. Parameters:
  166. plsc - (IN) ptr to line services context
  167. urColumnMax - (IN) right margin where to stop
  168. plsesc - (IN) escape characters
  169. clsesc - (IN) # of escape characters
  170. rgbreakrec - (IN) input array of break records
  171. cbreakrec, (IN) number of records in input array
  172. pfmtres - (OUT) result of last formatter
  173. pcpLim - (OUT) where we stop fetching
  174. pplsdnFirst - (OUT) first dnode that was created
  175. pplsdnLast - (OUT) last dnode that was created
  176. pur - (OUT) pen position after procedure
  177. If cbreakrec > 0 fetches run with cpFirst from first break record.
  178. After that if rigth msrgin is not exceeded cals FetchAppendEscCore
  179. ----------------------------------------------------------------------------*/
  180. LSERR FetchAppendEscResumeCore(PLSC plsc, long urColumnMax, const LSESC* plsesc,
  181. DWORD clsesc, const BREAKREC* rgbreakrec,
  182. DWORD cbreakrec, FMTRES* pfmtres, LSCP* pcpLim,
  183. PLSDNODE* pplsdnFirst, PLSDNODE* pplsdnLast,
  184. long* pur)
  185. {
  186. LSFRUN lsfrun;
  187. LSCHP lschp; /* local memory to store lschp */
  188. BOOL fHidden;
  189. FMTRES fmtresResume;
  190. LSERR lserr;
  191. PLSDNODE* pplsdnFirstStore; /* where to find plsdnFirst */
  192. Assert(FIsLSC(plsc));
  193. Assert(FFormattingAllowed(plsc));
  194. Assert(!(rgbreakrec == NULL && cbreakrec != 0));
  195. Assert(GetCurrentDnode(plsc) == NULL); /* it should be begining of a subline */
  196. if (cbreakrec > 0)
  197. {
  198. /*Initialization; */
  199. lsfrun.plschp = &lschp;
  200. pplsdnFirstStore = GetWhereToPutLink(plsc, GetCurrentDnode(plsc));
  201. /* fetch run that starts object to resume */
  202. lserr = plsc->lscbk.pfnFetchRun(plsc->pols, rgbreakrec[0].cpFirst,
  203. &lsfrun.lpwchRun, &lsfrun.cwchRun,
  204. &fHidden, &lschp, &lsfrun.plsrun);
  205. if (lserr != lserrNone)
  206. return lserr;
  207. if (lsfrun.cwchRun <= 0 || fHidden || lsfrun.plschp->idObj != rgbreakrec[0].idobj)
  208. {
  209. lserr = lserrInvalidBreakRecord;
  210. if (!plsc->fDontReleaseRuns)
  211. {
  212. plsc->lscbk.pfnReleaseRun(plsc->pols, lsfrun.plsrun);
  213. }
  214. return lserr;
  215. }
  216. /* zero amount of characters before dispatching to an object */
  217. lsfrun.cwchRun = 0;
  218. lserr = ProcessOneRun(plsc, urColumnMax, &lsfrun, rgbreakrec,
  219. cbreakrec,&fmtresResume);
  220. if (lserr != lserrNone)
  221. return lserr;
  222. /* we know that resumed object is not text, so only two fmtres are possible
  223. and we don't consider others */
  224. Assert(fmtresResume == fmtrCompletedRun || fmtresResume == fmtrExceededMargin);
  225. if (fmtresResume == fmtrCompletedRun)
  226. {
  227. lserr = FetchAppendEscCore(plsc, urColumnMax, plsesc, clsesc, pfmtres, pcpLim,
  228. pplsdnFirst, pplsdnLast, pur);
  229. if (lserr != lserrNone)
  230. return lserr;
  231. /* special handling of empty dnode list as an result of FetchAppendEscCore */
  232. if (*pplsdnFirst == NULL)
  233. {
  234. *pplsdnLast = GetCurrentDnode(plsc); /* this assigning is correct even when
  235. resumed object produces empty list
  236. of dnodes because it starts subline */
  237. *pfmtres = fmtresResume;
  238. }
  239. /* rewrite first dnode */
  240. *pplsdnFirst = *pplsdnFirstStore;
  241. }
  242. else /* stop fetching here */
  243. {
  244. /* Prepare output */
  245. *pfmtres = fmtresResume;
  246. *pcpLim = GetCurrentCpLim(plsc);
  247. *pplsdnFirst = *pplsdnFirstStore;
  248. *pplsdnLast = GetCurrentDnode(plsc);
  249. *pur = GetCurrentUr(plsc);
  250. }
  251. Assert((*pplsdnFirst == NULL) == (*pplsdnLast == NULL));
  252. Assert((*pplsdnLast == NULL) || ((*pplsdnLast)->plsdnNext == NULL));
  253. return lserrNone;
  254. }
  255. else /* no breakrecords */
  256. {
  257. return FetchAppendEscCore(plsc, urColumnMax, plsesc, clsesc, pfmtres, pcpLim,
  258. pplsdnFirst, pplsdnLast, pur);
  259. }
  260. }
  261. /* ---------------------------------------------------------------------- */
  262. /* F E T C H A P P E N D E S C C O R E */
  263. /*----------------------------------------------------------------------------
  264. %%Function: FetchAppendEscCore
  265. %%Contact: igorzv
  266. Parameters:
  267. plsc - (IN) ptr to line services context
  268. urColumnMax - (IN) right margin where to stop
  269. plsesc - (IN) escape characters
  270. clsesc - (IN) # of escape characters
  271. pfmtres - (OUT) result of last formatter
  272. pcpLim - (OUT) where we stop fetching
  273. pplsdnFirst - (OUT) first dnode that was created
  274. pplsdnLast - (OUT) last dnode that was created
  275. pur - (OUT) pen position after procedure
  276. Loop: fetch run, dispatch it to object handler until escape character
  277. or terminal fmtres.
  278. ----------------------------------------------------------------------------*/
  279. LSERR FetchAppendEscCore(PLSC plsc, long urColumnMax, const LSESC* plsesc,
  280. DWORD clsesc, FMTRES* pfmtres, LSCP* pcpLim,
  281. PLSDNODE* pplsdnFirst, PLSDNODE* pplsdnLast,
  282. long* pur)
  283. {
  284. BOOL fDone = fFalse;
  285. LSFRUN lsfrun;
  286. LSCHP lschp; /* local memory to store lschp */
  287. FMTRES fmtres;
  288. BOOL fHidden;
  289. LSCP cpLimOfCutRun = (LSCP)(-1); /* cpLim of run that was cuted according with Esc character
  290. is not valid in other cases
  291. we use it to check that whole such run was handled by formater */
  292. LSCP cpPrev = (LSCP)(-1); /* cp of previous run valid only after first iteration */
  293. LSERR lserr;
  294. PLSDNODE* pplsdnFirstStore; /* where to find plsdnFirst */
  295. Assert(FIsLSC(plsc));
  296. Assert(FFormattingAllowed(plsc));
  297. /*Initialization; */
  298. lsfrun.plschp = &lschp;
  299. fmtres = fmtrCompletedRun; /* it will be output if return right away with esc character */
  300. pplsdnFirstStore = GetWhereToPutLink(plsc, GetCurrentDnode(plsc));
  301. while (!fDone)
  302. {
  303. cpPrev = GetCurrentCpLim(plsc);
  304. /* FetchRun */
  305. lserr = plsc->lscbk.pfnFetchRun(plsc->pols, GetCurrentCpLim(plsc),
  306. &lsfrun.lpwchRun, &lsfrun.cwchRun,
  307. &fHidden, &lschp, &lsfrun.plsrun);
  308. if (lserr != lserrNone)
  309. return lserr;
  310. if (lsfrun.cwchRun <= 0)
  311. {
  312. lserr = lserrInvalidDcpFetched;
  313. if (!plsc->fDontReleaseRuns)
  314. {
  315. plsc->lscbk.pfnReleaseRun(plsc->pols, lsfrun.plsrun);
  316. }
  317. return lserr;
  318. }
  319. if (fHidden)
  320. {
  321. AdvanceCurrentCpLim(plsc, lsfrun.cwchRun);
  322. if (lsfrun.plsrun != NULL && !plsc->fDontReleaseRuns) /* we have not used this plsrun */
  323. {
  324. lserr = plsc->lscbk.pfnReleaseRun(plsc->pols, lsfrun.plsrun);
  325. if (lserr != lserrNone)
  326. return lserr;
  327. }
  328. /* Handle vanish end of paragraph; */
  329. /* There is situation in Word (see bug 118) when after fetching hidden text
  330. paragraph boundaries can be changed. So we have to call CheckNewPara
  331. every time after hidden text */
  332. lserr = CheckNewPara(plsc, cpPrev, GetCurrentCpLim(plsc), &fDone);
  333. if (lserr != lserrNone)
  334. return lserr;
  335. if (fDone)
  336. {
  337. /* it will eventually force stop formatting so we should apply
  338. nominal to ideal here */
  339. if (FNominalToIdealEncounted(plsc))
  340. {
  341. lserr = ApplyNominalToIdeal(PlschunkcontextFromSubline(GetCurrentSubline(plsc)),
  342. &plsc->lsiobjcontext,
  343. plsc->grpfManager, plsc->lsadjustcontext.lskj,
  344. FIsSubLineMain(GetCurrentSubline(plsc)),
  345. FLineContainsAutoNumber(plsc),
  346. GetCurrentDnode(plsc));
  347. if (lserr != lserrNone)
  348. return lserr;
  349. }
  350. fmtres = fmtrStopped;
  351. }
  352. }
  353. else
  354. {
  355. /* Check Esc character; */
  356. if (clsesc > 0 && FLimitRunEsc(&lsfrun, plsesc, clsesc))
  357. {
  358. cpLimOfCutRun = (LSCP) (GetCurrentCpLim(plsc) + lsfrun.cwchRun);
  359. fDone = (lsfrun.cwchRun == 0);
  360. }
  361. if (!fDone)
  362. {
  363. lserr = ProcessOneRun(plsc, urColumnMax, &lsfrun, NULL, 0, &fmtres);
  364. if (lserr != lserrNone)
  365. return lserr;
  366. /*Check fmtres: Are formating done?; */
  367. switch (fmtres)
  368. {
  369. case fmtrCompletedRun:
  370. fDone = (GetCurrentCpLim(plsc) == cpLimOfCutRun); /* is true only if we cuted because */
  371. Assert(!fDone || clsesc > 0); /* of esc character and formater handled such*/
  372. break; /* run completely */
  373. case fmtrExceededMargin:
  374. fDone = fTrue;
  375. break;
  376. case fmtrTab:
  377. fDone = fTrue;
  378. break;
  379. case fmtrStopped:
  380. fDone = fTrue;
  381. break;
  382. default:
  383. NotReached();
  384. }
  385. }
  386. else /* after limiting run by esc characters it was empty */
  387. {
  388. if (lsfrun.plsrun != NULL && !plsc->fDontReleaseRuns) /* we have not used this plsrun */
  389. {
  390. lserr = plsc->lscbk.pfnReleaseRun(plsc->pols, lsfrun.plsrun);
  391. if (lserr != lserrNone)
  392. return lserr;
  393. fmtres = fmtrCompletedRun;
  394. }
  395. }
  396. } /* if/else hidden */
  397. }
  398. /* Prepare output */
  399. *pfmtres = fmtres;
  400. *pcpLim = GetCurrentCpLim(plsc);
  401. *pplsdnFirst = *pplsdnFirstStore;
  402. if (*pplsdnFirst != NULL)
  403. *pplsdnLast = GetCurrentDnode(plsc);
  404. else
  405. *pplsdnLast = NULL;
  406. *pur = GetCurrentUr(plsc);
  407. Assert((*pplsdnFirst == NULL) == (*pplsdnLast == NULL));
  408. Assert((*pplsdnLast == NULL) || ((*pplsdnLast)->plsdnNext == NULL));
  409. return lserrNone;
  410. }
  411. /* ---------------------------------------------------------------------- */
  412. /* P R O C E S S O N E R U N */
  413. /*----------------------------------------------------------------------------
  414. %%Function: ProcessOneRun
  415. %%Contact: igorzv
  416. Parameters:
  417. plsc - (IN) ptr to line services context
  418. urColumnMax - (IN) right margin where to stop
  419. plsfrun - (IN) given run
  420. rgbreakrec - (IN) input array of break records
  421. cbreakrec, (IN) number of records in input array
  422. pfmtres - (OUT) result of formatting
  423. 1) If run it's not a text run applies nominal to ideal to previous text chunk.
  424. To have correct pen position before dispatching to an foreign object.
  425. 2) Get text metrics and dispatches run to an handler.
  426. 3) If fmtres is terminal applies nominal to ideal to the last chunk.
  427. ----------------------------------------------------------------------------*/
  428. LSERR ProcessOneRun (PLSC plsc, long urColumnMax, const LSFRUN* plsfrun,
  429. const BREAKREC* rgbreakrec,
  430. DWORD cbreakrec, FMTRES* pfmtres)
  431. {
  432. DWORD iobj;
  433. LSIMETHODS* plsim;
  434. PLNOBJ plnobj;
  435. struct fmtin fmti;
  436. LSERR lserr;
  437. PLSDNODE plsdnNew;
  438. PLSDNODE plsdnToFinishOld; /* we should restore it after every formater */
  439. PLSSUBL plssublOld;
  440. PLSDNODE plsdnNomimalToIdeal;
  441. PLSDNODE* pplsdnToStoreNext;
  442. PLSDNODE plsdnNext;
  443. PLSDNODE plsdnCurrent;
  444. PLSDNODE plsdnLast;
  445. BOOL fInterruptBorder;
  446. BOOL fInsideBorderUp = fFalse;
  447. BOOL fBordered = fFalse;
  448. Assert(FIsLSC(plsc));
  449. Assert(!(rgbreakrec == NULL && cbreakrec != 0));
  450. plsdnToFinishOld = GetDnodeToFinish(plsc);
  451. plssublOld = GetCurrentSubline(plsc);
  452. plsdnCurrent = GetCurrentDnode(plsc);
  453. pplsdnToStoreNext = GetWhereToPutLink(plsc, plsdnCurrent);
  454. if (plsdnToFinishOld != NULL)
  455. fInsideBorderUp = plsdnToFinishOld->fInsideBorder;
  456. if (plsfrun->plschp->idObj == idObjTextChp)
  457. iobj = IobjTextFromLsc(&plsc->lsiobjcontext);
  458. else
  459. iobj = plsfrun->plschp->idObj;
  460. Assert (FIobjValid(&plsc->lsiobjcontext, iobj)); /* Reject other out of range ids */
  461. if (!FIobjValid(&plsc->lsiobjcontext, iobj)) /* for both debug and ship builds. */
  462. return ErrReleaseRunToFormat(plsc, plsfrun->plsrun, lserrInvalidObjectIdFetched);
  463. /* here we are catching for situatuion when client adding text dnode to a chunk to
  464. which nominal to ideal has been applied, such situation will lead later to applying nominal
  465. to ideal twice to the same dnode, and this text doesn't like */
  466. AssertImplies(iobj == IobjTextFromLsc(&plsc->lsiobjcontext),
  467. !FNTIAppliedToLastChunk(PlschunkcontextFromSubline(plssublOld)));
  468. if (iobj == IobjTextFromLsc(&plsc->lsiobjcontext) &&
  469. FNTIAppliedToLastChunk(PlschunkcontextFromSubline(plssublOld)))
  470. return ErrReleaseRunToFormat(plsc, plsfrun->plsrun, lserrFormattingFunctionDisabled);
  471. plsim = PLsimFromLsc(&plsc->lsiobjcontext, iobj);
  472. if (iobj != IobjTextFromLsc(&plsc->lsiobjcontext))
  473. {
  474. TurnOffAllSimpleText(plsc); /* not text */
  475. TurnOnForeignObjectEncounted(plsc);
  476. if (FNominalToIdealEncounted(plsc))
  477. {
  478. lserr = ApplyNominalToIdeal(PlschunkcontextFromSubline(plssublOld), &plsc->lsiobjcontext,
  479. plsc->grpfManager, plsc->lsadjustcontext.lskj,
  480. FIsSubLineMain(plssublOld), FLineContainsAutoNumber(plsc),
  481. plsdnCurrent);
  482. if (lserr != lserrNone)
  483. return ErrReleaseRunToFormat(plsc, plsfrun->plsrun, lserr);
  484. /* we should recalculate plsdnCurrent because nominal to ideal can destroy last dnode */
  485. plsdnCurrent = GetCurrentDnode(plsc);
  486. pplsdnToStoreNext = GetWhereToPutLink(plsc, plsdnCurrent);
  487. }
  488. }
  489. FlushNTIAppliedToLastChunk(PlschunkcontextFromSubline(plssublOld));
  490. /* creating border dnodes */
  491. /* skip back pen dnodes */
  492. while (plsdnCurrent != NULL && FIsDnodePen(plsdnCurrent))
  493. {
  494. plsdnCurrent = plsdnCurrent->plsdnPrev;
  495. }
  496. if (FDnodeHasBorder(plsdnCurrent) &&
  497. !(FIsDnodeBorder(plsdnCurrent) && !FIsDnodeOpenBorder(plsdnCurrent))) /* previous dnode has unclosed border */
  498. /* condition in if looks superfluous but it works correctly even if dnodes deleting
  499. happend during formatting */
  500. {
  501. if (plsfrun->plschp->fBorder)
  502. {
  503. /* check that client wants to border runs together */
  504. lserr = plsc->lscbk.pfnFInterruptBorder(plsc->pols, plsdnCurrent->u.real.plsrun,
  505. plsfrun->plsrun, &fInterruptBorder);
  506. if (lserr != lserrNone)
  507. return ErrReleaseRunToFormat(plsc, plsfrun->plsrun, lserr);
  508. if (fInterruptBorder)
  509. {
  510. /* close previous border and open new one */
  511. lserr = CloseCurrentBorder(plsc);
  512. if (lserr != lserrNone)
  513. return ErrReleaseRunToFormat(plsc, plsfrun->plsrun, lserr);
  514. lserr = OpenBorder(plsc, plsfrun->plsrun);
  515. if (lserr != lserrNone)
  516. return ErrReleaseRunToFormat(plsc, plsfrun->plsrun, lserr);
  517. }
  518. fBordered = fTrue;
  519. }
  520. else
  521. {
  522. lserr = CloseCurrentBorder(plsc);
  523. if (lserr != lserrNone)
  524. return ErrReleaseRunToFormat(plsc, plsfrun->plsrun, lserr);
  525. }
  526. }
  527. else
  528. {
  529. if (plsfrun->plschp->fBorder)
  530. {
  531. if (fInsideBorderUp)
  532. {
  533. /* border is open on upper level: turn off border flag */
  534. ((PLSCHP) (plsfrun->plschp))->fBorder = fFalse;
  535. }
  536. else
  537. {
  538. lserr = OpenBorder(plsc, plsfrun->plsrun);
  539. if (lserr != lserrNone)
  540. return ErrReleaseRunToFormat(plsc, plsfrun->plsrun, lserr);
  541. fBordered = fTrue;
  542. }
  543. }
  544. }
  545. /* we always create real dnode and change it for pen if needed in Finish method */
  546. CreateRealDnode(plsc, plsdnNew, plsfrun);
  547. plsdnNew->fInsideBorder = fInsideBorderUp || fBordered;
  548. /* initialization of fmti */
  549. fmti.lsfgi.fFirstOnLine = FIsFirstOnLine(plsdnNew) && FIsSubLineMain(plssublOld);
  550. fmti.lsfgi.cpFirst = GetCurrentCpLim(plsc);
  551. fmti.lsfgi.urPen = GetCurrentUr(plsc);
  552. fmti.lsfgi.vrPen = GetCurrentVr(plsc);
  553. fmti.lsfgi.urColumnMax = urColumnMax;
  554. fmti.lsfgi.lstflow = plssublOld->lstflow;
  555. fmti.lsfrun = *plsfrun;
  556. fmti.plsdnTop = plsdnNew;
  557. lserr = plsc->lscbk.pfnGetRunTextMetrics(plsc->pols, fmti.lsfrun.plsrun,
  558. lsdevReference, fmti.lsfgi.lstflow, &fmti.lstxmRef);
  559. if (lserr != lserrNone)
  560. {
  561. DestroyDnodeList (&plsc->lscbk, plsc->pols, &plsc->lsiobjcontext,
  562. plsdnNew, plsc->fDontReleaseRuns);
  563. return lserr;
  564. }
  565. if (plsc->lsdocinf.fPresEqualRef)
  566. fmti.lstxmPres = fmti.lstxmRef;
  567. else
  568. {
  569. lserr = plsc->lscbk.pfnGetRunTextMetrics(plsc->pols, fmti.lsfrun.plsrun,
  570. lsdevPres, fmti.lsfgi.lstflow,
  571. &fmti.lstxmPres);
  572. if (lserr != lserrNone)
  573. {
  574. DestroyDnodeList (&plsc->lscbk, plsc->pols, &plsc->lsiobjcontext,
  575. plsdnNew, plsc->fDontReleaseRuns);
  576. return lserr;
  577. }
  578. }
  579. plnobj = PlnobjFromLsc(plsc, iobj);
  580. if (plnobj == NULL)
  581. {
  582. lserr = CreateLNObjInLsc(plsc, iobj);
  583. if (lserr != lserrNone)
  584. {
  585. DestroyDnodeList (&plsc->lscbk, plsc->pols, &plsc->lsiobjcontext,
  586. plsdnNew, plsc->fDontReleaseRuns);
  587. return lserr;
  588. }
  589. plnobj = PlnobjFromLsc(plsc, iobj);
  590. }
  591. /* set dnode to finish */
  592. SetDnodeToFinish(plsc, plsdnNew);
  593. /* set current subline to NULL */
  594. SetCurrentSubline(plsc, NULL);
  595. if (cbreakrec == 0)
  596. {
  597. lserr = plsim->pfnFmt(plnobj, &fmti, pfmtres);
  598. }
  599. else{
  600. if (plsim->pfnFmtResume == NULL)
  601. return lserrInvalidBreakRecord;
  602. lserr = plsim->pfnFmtResume(plnobj, rgbreakrec, cbreakrec, &fmti, pfmtres);
  603. }
  604. if (lserr != lserrNone)
  605. {
  606. if (plsc->lslistcontext.plsdnToFinish != NULL) /* dnode hasn't added to list */
  607. DestroyDnodeList (&plsc->lscbk, plsc->pols, &plsc->lsiobjcontext,
  608. plsdnNew, plsc->fDontReleaseRuns);
  609. /* we should restore dnode to finish and current subline to properly handle
  610. error on upper level */
  611. SetCurrentSubline(plsc, plssublOld);
  612. SetDnodeToFinish(plsc, plsdnToFinishOld);
  613. return lserr;
  614. }
  615. AssertValidFmtres(*pfmtres);
  616. if (GetCurrentSubline(plsc) != NULL || GetDnodeToFinish(plsc) != NULL)
  617. {
  618. /* we should restore dnode to finish and current subline to properly handle
  619. error on upper level */
  620. SetCurrentSubline(plsc, plssublOld);
  621. SetDnodeToFinish(plsc, plsdnToFinishOld);
  622. return lserrUnfinishedDnode;
  623. }
  624. /* restore dnode to finish and current subline */
  625. SetCurrentSubline(plsc, plssublOld);
  626. SetDnodeToFinish(plsc, plsdnToFinishOld);
  627. /* to avoid all problems with deleteing dnodes we don't use plsdnNew */
  628. plsdnLast = GetCurrentDnodeSubl(plssublOld);
  629. /* case of tab */
  630. if (*pfmtres == fmtrTab)
  631. {
  632. plsdnLast->fTab = fTrue;
  633. /* caller later can skip this tab so we prepare zero values */
  634. Assert(FIsDnodeReal(plsdnLast));
  635. Assert(IdObjFromDnode(plsdnLast) == IobjTextFromLsc(&plsc->lsiobjcontext));
  636. TurnOffAllSimpleText(plsc); /* not text */
  637. }
  638. /* case of splat */
  639. if (*pfmtres == fmtrStopped && plsdnLast != NULL && FIsDnodeSplat(plsdnLast))
  640. {
  641. lserr = HandleSplat(plsc, pfmtres);
  642. if (lserr != lserrNone)
  643. return lserr;
  644. /* Handle splat can delete plsdnLast */
  645. plsdnLast = GetCurrentDnodeSubl(plssublOld);
  646. }
  647. /* in a case of exceeded margin or hard break or tab (so all values of fmtres but fmtrCompletedRun) */
  648. /* we need apply nominal to ideal to have correct lenght */
  649. if (*pfmtres != fmtrCompletedRun && plsdnLast != NULL && FNominalToIdealEncounted(plsc))
  650. {
  651. if (*pfmtres == fmtrTab || FIsDnodeSplat(plsdnLast))
  652. plsdnNomimalToIdeal = plsdnLast->plsdnPrev;
  653. else
  654. plsdnNomimalToIdeal = plsdnLast;
  655. lserr = ApplyNominalToIdeal(PlschunkcontextFromSubline(plssublOld), &plsc->lsiobjcontext,
  656. plsc->grpfManager, plsc->lsadjustcontext.lskj,
  657. FIsSubLineMain(plssublOld), FLineContainsAutoNumber(plsc),
  658. plsdnNomimalToIdeal);
  659. if (lserr != lserrNone)
  660. return lserr;
  661. /* ApplyNominalToIdeal can delete plsdnLast */
  662. plsdnLast = GetCurrentDnodeSubl(plssublOld);
  663. /* if we run nominal to ideal because of tab chunk of text to which
  664. nominal to ideal is applied is not last chunk */
  665. if (*pfmtres == fmtrTab || FIsDnodeSplat(plsdnLast))
  666. FlushNTIAppliedToLastChunk(PlschunkcontextFromSubline(plssublOld));
  667. /* in a case of exceeded right margin we should extract dcpMaxContext characters
  668. because after fetching further result of nominal to ideal can be different for these
  669. characters: examples ligatures or kerning */
  670. if (*pfmtres == fmtrExceededMargin &&
  671. FNeedToCutPossibleContextViolation(plsc, plsdnLast))
  672. {
  673. lserr = CutPossibleContextViolation(PlschunkcontextFromSubline(plssublOld),
  674. plsdnLast);
  675. if (lserr != lserrNone)
  676. return lserr;
  677. /* such procedure also can delete plsdnLast */
  678. plsdnLast = GetCurrentDnodeSubl(plssublOld);
  679. }
  680. }
  681. if (iobj != IobjTextFromLsc(&plsc->lsiobjcontext))
  682. /* only in this case there is a possibility to apply width modification
  683. to preceding character */
  684. {
  685. /* we are actually applying width modification to preceding character if first
  686. dnode produced by formating is non text */
  687. /* we can't relly on plsdnLast here because of such Finish methods as
  688. FinishByOneCharacter and FinishBySubline */
  689. /* we still rely here on pplsdnToStoreNext in other words we assume that
  690. plsdnCurrent (the current dnode in the begining of our procedure ) has not been
  691. deleted during nominal to ideal. To prove this we use that nominal to ideal has been
  692. already applied to plsdnCurrent*/
  693. plsdnNext = *pplsdnToStoreNext;
  694. Assert(plsdnNext == NULL || FIsLSDNODE(plsdnNext));
  695. if (FNominalToIdealEncounted(plsc) &&
  696. plsdnNext != NULL &&
  697. FIsDnodeReal(plsdnNext) &&
  698. IdObjFromDnode(plsdnNext) != IobjTextFromLsc(&plsc->lsiobjcontext)
  699. )
  700. {
  701. lserr = ApplyModWidthToPrecedingChar(PlschunkcontextFromSubline(plssublOld),
  702. &plsc->lsiobjcontext, plsc->grpfManager,
  703. plsc->lsadjustcontext.lskj, plsdnNext);
  704. if (lserr != lserrNone)
  705. return lserr;
  706. }
  707. }
  708. return lserrNone;
  709. }
  710. /* ---------------------------------------------------------------------- */
  711. /* Q U I C K F O R M A T T I N G */
  712. /*----------------------------------------------------------------------------
  713. %%Function: QuickFormatting
  714. %%Contact: igorzv
  715. Parameters:
  716. plsc - (IN) ptr to line services context
  717. plsfrun - (IN) given run
  718. urColumnMax - (IN) right margin where to stop
  719. pfGeneral - (OUT) quick formatting was stopped: we should use general formatting
  720. pfHardStop - (OUT) formatting ended with hard break
  721. pcpLim - (OUT) cpLim after procedure
  722. pur - (OUT) pen position after procedure
  723. Works only with text runs without nominal to ideal and without tabs.
  724. Stops if condition below is broken.
  725. ----------------------------------------------------------------------------*/
  726. LSERR QuickFormatting(PLSC plsc, LSFRUN* plsfrun, long urColumnMax,
  727. BOOL* pfGeneral, BOOL* pfHardStop,
  728. LSCP* pcpLim, long* pur)
  729. {
  730. struct fmtin fmti;
  731. LSLINFO* plslinfoText;
  732. DWORD iobjText;
  733. PLNOBJ plnobjText;
  734. PLSLINE plsline;
  735. BOOL fHidden;
  736. const POLS pols = plsc->pols;
  737. BOOL fGeneral;
  738. FMTRES fmtres = fmtrCompletedRun;
  739. LSERR lserr;
  740. PLSDNODE plsdnNew;
  741. PLSSUBL plssubl;
  742. iobjText = IobjTextFromLsc(&(plsc->lsiobjcontext));
  743. plnobjText = PlnobjFromLsc(plsc, iobjText);
  744. plssubl = GetCurrentSubline(plsc);
  745. fmti.lsfrun = *plsfrun;
  746. fmti.lsfgi.fFirstOnLine = TRUE;
  747. fmti.lsfgi.cpFirst = GetCurrentCpLim(plsc);
  748. fmti.lsfgi.vrPen = GetCurrentVr(plsc);
  749. fmti.lsfgi.urPen = GetCurrentUr(plsc);
  750. fmti.lsfgi.lstflow = plssubl->lstflow;
  751. fmti.lsfgi.urColumnMax = urColumnMax;
  752. plsline = plsc->plslineCur;
  753. plslinfoText = &(plsline->lslinfo);
  754. fGeneral = fFalse;
  755. fHidden = fFalse; /* in InitTextParams we already skipped all vanished text */
  756. for (;;) /* "break" exits quick-format loop */
  757. {
  758. /* Run has been alreary fetched */
  759. /*we don't want to handle here vanished text, foreign object, nominal to ideal */
  760. if ( FRunIsNotSimple(fmti.lsfrun.plschp, fHidden))
  761. {
  762. /* we should release run here, in general procedure we will fetch it again */
  763. if (!plsc->fDontReleaseRuns)
  764. {
  765. lserr = plsc->lscbk.pfnReleaseRun(plsc->pols, fmti.lsfrun.plsrun);
  766. if (lserr != lserrNone)
  767. return lserr;
  768. }
  769. fGeneral = fTrue;
  770. break;
  771. }
  772. /*Create dnode for text; */
  773. CreateRealDnode(plsc, plsdnNew, &fmti.lsfrun);
  774. SetDnodeToFinish(plsc, plsdnNew);
  775. /* prepare fmtin */
  776. fmti.plsdnTop = plsdnNew;
  777. lserr = plsc->lscbk.pfnGetRunTextMetrics(pols, fmti.lsfrun.plsrun,
  778. lsdevReference, fmti.lsfgi.lstflow, &fmti.lstxmRef);
  779. if (lserr != lserrNone)
  780. {
  781. DestroyDnodeList (&plsc->lscbk, plsc->pols, &plsc->lsiobjcontext,
  782. plsdnNew, plsc->fDontReleaseRuns);
  783. return lserr;
  784. }
  785. if (plsc->lsdocinf.fPresEqualRef)
  786. {
  787. fmti.lstxmPres = fmti.lstxmRef;
  788. }
  789. else
  790. {
  791. lserr = plsc->lscbk.pfnGetRunTextMetrics(pols, fmti.lsfrun.plsrun,
  792. lsdevPres, fmti.lsfgi.lstflow,
  793. &fmti.lstxmPres);
  794. if (lserr != lserrNone)
  795. {
  796. DestroyDnodeList (&plsc->lscbk, plsc->pols, &plsc->lsiobjcontext,
  797. plsdnNew, plsc->fDontReleaseRuns);
  798. return lserr;
  799. }
  800. }
  801. SetCurrentSubline(plsc, NULL);
  802. lserr = FmtText(plnobjText, &fmti, &fmtres);
  803. if (lserr != lserrNone)
  804. {
  805. if (plsc->lslistcontext.plsdnToFinish != NULL) /* dnode hasn't added to list */
  806. DestroyDnodeList (&plsc->lscbk, plsc->pols, &plsc->lsiobjcontext,
  807. plsdnNew, plsc->fDontReleaseRuns);
  808. return lserr;
  809. }
  810. /* restore current subline */
  811. SetCurrentSubline(plsc, plssubl);
  812. if (fmtres == fmtrTab ) /* tab: we quite from quick loop deleting this dnode
  813. because we will append it again in FormatGeneralCase */
  814. {
  815. lserr = UndoLastDnode(plsc); /* dnode is already in list */
  816. if (lserr != lserrNone)
  817. return lserr;
  818. fGeneral = fTrue;
  819. break;
  820. }
  821. AssertValidFmtres(fmtres);
  822. SetHeightToMax(plslinfoText, &(plsdnNew->u.real.objdim));
  823. if (FIsDnodeSplat(plsdnNew))
  824. {
  825. lserr = HandleSplat(plsc, &fmtres);
  826. if (lserr != lserrNone)
  827. return lserr;
  828. }
  829. if (fmtres != fmtrCompletedRun)
  830. {
  831. /* after break we should check that final heights is not zero */
  832. /* otherwise we take heights from last run */
  833. /* so we will have correct line height after quick break */
  834. if (plslinfoText->dvrAscent == 0 && plslinfoText->dvrDescent == 0)
  835. {
  836. plslinfoText->dvrAscent = fmti.lstxmRef.dvAscent;
  837. plslinfoText->dvpAscent = fmti.lstxmPres.dvAscent;
  838. plslinfoText->dvrDescent = fmti.lstxmRef.dvDescent;
  839. plslinfoText->dvpDescent = fmti.lstxmPres.dvDescent;
  840. plslinfoText->dvpMultiLineHeight = dvHeightIgnore;
  841. plslinfoText->dvrMultiLineHeight = dvHeightIgnore;
  842. }
  843. break;
  844. }
  845. /* prepare next iteration; */
  846. fmti.lsfgi.fFirstOnLine = fFalse;
  847. fmti.lsfgi.urPen = GetCurrentUr(plsc);
  848. fmti.lsfgi.cpFirst = GetCurrentCpLim(plsc);
  849. lserr = plsc->lscbk.pfnFetchRun(pols, fmti.lsfgi.cpFirst,
  850. &fmti.lsfrun.lpwchRun,
  851. &fmti.lsfrun.cwchRun,
  852. &fHidden, (LSCHP *)fmti.lsfrun.plschp,
  853. &fmti.lsfrun.plsrun);
  854. if (lserr != lserrNone)
  855. return lserr;
  856. Assert(fmti.lsfrun.cwchRun > 0);
  857. } /* for (;;) */
  858. /* prepare output */
  859. *pfGeneral = fGeneral;
  860. *pfHardStop = (fmtres == fmtrStopped);
  861. *pcpLim = GetCurrentCpLim(plsc);
  862. *pur = GetCurrentUr(plsc);
  863. return lserrNone;
  864. }
  865. /* C H E C K N E W P A R A */
  866. /*----------------------------------------------------------------------------
  867. %%Function: CheckNewPara
  868. %%Contact: igorzv
  869. Parameters:
  870. plsc - (IN) ptr to line services context
  871. cpPrev - (IN) cp in old paragraph
  872. cpThis - (IN) cp in new paragraph
  873. pfQuit - (OUT) stop formatting because new paragraph is not compatible with old
  874. Handles leaping from paragraph to paragraph (due to vanished text) on
  875. behalf of FetchAppendEscCore(). If the new paragraph is compatible
  876. with the old one, FetchPap is called and text is informed of the
  877. new para end parameters.
  878. ----------------------------------------------------------------------------*/
  879. static LSERR CheckNewPara(PLSC plsc, LSCP cpPrev, LSCP cpThis, BOOL* pfQuit)
  880. {
  881. LSERR lserr;
  882. BOOL fHazard;
  883. LSPAP lspap;
  884. DWORD iobjText;
  885. PLNOBJ plnobjText;
  886. *pfQuit = fTrue;
  887. Assert(cpThis >= 0 && cpThis > cpPrev);
  888. lserr = plsc->lscbk.pfnCheckParaBoundaries(plsc->pols, cpPrev, cpThis, &fHazard);
  889. if (lserr != lserrNone)
  890. return lserr;
  891. if (!fHazard)
  892. {
  893. lserr = plsc->lscbk.pfnFetchPap(plsc->pols, cpThis, &lspap);
  894. if (lserr != lserrNone)
  895. return lserr;
  896. /* we don't know are we really in a new paragraph or not */
  897. /* so we have to modify information about end of paragraph */
  898. /* always as would we are in a new paragraph */
  899. iobjText = IobjTextFromLsc(&plsc->lsiobjcontext);
  900. plnobjText = PlnobjFromLsc(plsc, iobjText);
  901. lserr = ModifyTextLineEnding(plnobjText, lspap.lskeop);
  902. if (lserr != lserrNone)
  903. return lserr;
  904. SetCpInPara(plsc->lstabscontext, cpThis);
  905. plsc->fLimSplat = lspap.grpf & fFmiLimSplat;
  906. plsc->fIgnoreSplatBreak = lspap.grpf & fFmiIgnoreSplatBreak;
  907. /* we don't invalidate tabs info and other paragraph properties
  908. /* that we stored in context */
  909. *pfQuit = fFalse;
  910. }
  911. return lserr;
  912. }
  913. /* F L I M I T R U N E S C */
  914. /*----------------------------------------------------------------------------
  915. %%Function: FLimitRunEsc
  916. %%Contact: igorzv
  917. Parameters:
  918. plsfrun - (IN) run to cut
  919. plsesc - (IN) set of esc characters
  920. iescLim - (IN) number of esc characters
  921. On behalf of LsFetchAppendEscCore(), this routine limits a run when
  922. an escape character is present.
  923. ----------------------------------------------------------------------------*/
  924. static BOOL FLimitRunEsc(LSFRUN* plsfrun, const LSESC* plsesc, DWORD iescLim)
  925. {
  926. DWORD iesc;
  927. DWORD ich;
  928. const LPCWSTR pwch = plsfrun->lpwchRun;
  929. const DWORD ichLim = plsfrun->cwchRun;
  930. Assert(iescLim > 0); /* optimization -- test before calling */
  931. for (ich=0; ich<ichLim; ich++)
  932. {
  933. for (iesc=0; iesc<iescLim; iesc++)
  934. {
  935. if (FBetween(pwch[ich], plsesc[iesc].wchFirst, plsesc[iesc].wchLast))
  936. {
  937. plsfrun->cwchRun = ich;
  938. return fTrue;
  939. }
  940. }
  941. }
  942. return fFalse;
  943. }
  944. /* F O R M A T A N M */
  945. /*----------------------------------------------------------------------------
  946. %%Function: FormatAnm
  947. %%Contact: igorzv
  948. Parameters:
  949. plsc - (IN) ptr to line services context
  950. plsfrunMainText - (IN) first run of the main text
  951. Formats and allignes bullets and numbering
  952. ----------------------------------------------------------------------------*/
  953. LSERR FormatAnm(PLSC plsc, PLSFRUN plsfrunMainText)
  954. {
  955. long duaSpaceAnm;
  956. long duaWidthAnm;
  957. LSKALIGN lskalignAnm;
  958. WCHAR wchAdd;
  959. BOOL fWord95Model;
  960. LSERR lserr;
  961. LSFRUN lsfrun;
  962. LSCHP lschp; /* local memory to store lschp */
  963. FMTRES fmtres;
  964. long durUsed;
  965. long urOriginal;
  966. long durAfter = 0;
  967. long durBefore = 0;
  968. LSCP cpLimOriginal;
  969. OBJDIM* pobjdimAnm;
  970. PLSDNODE plsdnAllignmentTab;
  971. BOOL fInterruptBorder;
  972. LSCHP lschpAdd; /* lschp for character added after autonumber */
  973. PLSRUN plsrunAdd; /* plsrun for character added after autonumber */
  974. Assert(FIsLSC(plsc));
  975. Assert(FFormattingAllowed(plsc));
  976. /*Initialization; */
  977. lsfrun.plschp = &lschp;
  978. cpLimOriginal = GetCurrentCpLim(plsc);
  979. urOriginal = GetCurrentUr(plsc);
  980. SetCurrentCpLim(plsc, cpFirstAnm);
  981. /* get autonumbering information */
  982. lserr = plsc->lscbk.pfnGetAutoNumberInfo(plsc->pols, &lskalignAnm, &lschp, &lsfrun.plsrun,
  983. &wchAdd, &lschpAdd, &plsrunAdd,
  984. &fWord95Model, &duaSpaceAnm, &duaWidthAnm);
  985. if (lserr != lserrNone)
  986. return lserr;
  987. Assert(!memcmp(&lschp, &lschpAdd, sizeof(lschpAdd)));
  988. lsfrun.cwchRun = 0 ; /* we dont use characters in formating autonumbering object */
  989. lsfrun.lpwchRun = NULL;
  990. /* put idobj of autonumber to lschp */
  991. lschp.idObj = (WORD) IobjAutonumFromLsc(&plsc->lsiobjcontext);
  992. /* remove underlining and some other bits from chp */
  993. /* we don't underline it as a whole */
  994. lschp.fUnderline = fFalse;
  995. lschp.fStrike = fFalse;
  996. lschp.fShade = fFalse;
  997. lschp.EffectsFlags = 0;
  998. lserr = ProcessOneRun(plsc, uLsInfiniteRM, &lsfrun, NULL,
  999. 0, &fmtres);
  1000. if (lserr != lserrNone)
  1001. return lserr;
  1002. Assert(fmtres == fmtrCompletedRun);
  1003. Assert(GetCurrentDnode(plsc) != NULL);
  1004. /* store heights of autonumber */
  1005. Assert(FIsDnodeReal(GetCurrentDnode(plsc)));
  1006. pobjdimAnm = &(GetCurrentDnode(plsc)->u.real.objdim);
  1007. plsc->plslineCur->lslinfo.dvpAscentAutoNumber = pobjdimAnm->heightsPres.dvAscent;
  1008. plsc->plslineCur->lslinfo.dvrAscentAutoNumber = pobjdimAnm->heightsRef.dvAscent;
  1009. plsc->plslineCur->lslinfo.dvpDescentAutoNumber = pobjdimAnm->heightsPres.dvDescent;
  1010. plsc->plslineCur->lslinfo.dvrDescentAutoNumber = pobjdimAnm->heightsRef.dvDescent;
  1011. if (wchAdd != 0) /* fill in lsfrun with a run of one character */
  1012. {
  1013. lsfrun.plschp = &lschpAdd;
  1014. lsfrun.plsrun = plsrunAdd;
  1015. lsfrun.lpwchRun = &wchAdd;
  1016. lsfrun.cwchRun = 1;
  1017. lserr = ProcessOneRun(plsc, uLsInfiniteRM, &lsfrun, NULL,
  1018. 0, &fmtres);
  1019. if (lserr != lserrNone)
  1020. return lserr;
  1021. Assert(fmtres == fmtrCompletedRun || fmtres == fmtrTab);
  1022. }
  1023. plsdnAllignmentTab = GetCurrentDnode(plsc); /* in the case when added character is not tab this
  1024. value will not be used */
  1025. if (lsfrun.plschp->fBorder)
  1026. {
  1027. if (plsfrunMainText->plschp->fBorder)
  1028. {
  1029. /* check that client wants to border runs together */
  1030. lserr = plsc->lscbk.pfnFInterruptBorder(plsc->pols,
  1031. lsfrun.plsrun, plsfrunMainText->plsrun, &fInterruptBorder);
  1032. if (lserr != lserrNone)
  1033. return lserr;
  1034. if (fInterruptBorder)
  1035. {
  1036. /* we should close border before allignment */
  1037. lserr = CloseCurrentBorder(plsc);
  1038. if (lserr != lserrNone)
  1039. return lserr;
  1040. }
  1041. }
  1042. else
  1043. {
  1044. /* we should close border before allignment */
  1045. lserr = CloseCurrentBorder(plsc);
  1046. if (lserr != lserrNone)
  1047. return lserr;
  1048. }
  1049. }
  1050. durUsed = GetCurrentUr(plsc) - urOriginal;
  1051. if (fWord95Model)
  1052. {
  1053. Assert(wchAdd != 0);
  1054. Assert(fmtres == fmtrTab);
  1055. AllignAutonum95(UrFromUa(LstflowFromSubline(GetCurrentSubline(plsc)),
  1056. &(plsc->lsdocinf.lsdevres), duaSpaceAnm),
  1057. UrFromUa(LstflowFromSubline(GetCurrentSubline(plsc)),
  1058. &(plsc->lsdocinf.lsdevres), duaWidthAnm),
  1059. lskalignAnm, durUsed, plsdnAllignmentTab,
  1060. &durBefore, &durAfter);
  1061. }
  1062. else
  1063. {
  1064. lserr = AllignAutonum(&(plsc->lstabscontext), lskalignAnm,
  1065. (wchAdd != 0 && fmtres == fmtrTab),
  1066. plsdnAllignmentTab, GetCurrentUr(plsc),
  1067. durUsed, &durBefore, &durAfter);
  1068. if (lserr != lserrNone)
  1069. return lserr;
  1070. /* if there is no allignment after then durAfter should be zero */
  1071. Assert(!((durAfter != 0) && (!(wchAdd != 0 && fmtres == fmtrTab))));
  1072. }
  1073. /* change geometry because of durBefore */
  1074. plsc->lsadjustcontext.urStartAutonumberingText =
  1075. plsc->lsadjustcontext.urLeftIndent + durBefore;
  1076. AdvanceCurrentUr(plsc, durBefore);
  1077. /* change geometry because of durAfter */
  1078. AdvanceCurrentUr(plsc, durAfter);
  1079. plsc->lsadjustcontext.urStartMainText = GetCurrentUr(plsc);
  1080. /* restore cpLim */
  1081. SetCurrentCpLim(plsc, cpLimOriginal);
  1082. return lserrNone;
  1083. }
  1084. #define iobjAutoDecimalTab (idObjTextChp-1)
  1085. /* I N I T I A L I Z E A U T O D E C T A B */
  1086. /*----------------------------------------------------------------------------
  1087. %%Function: InitializeAutoDecTab
  1088. %%Contact: igorzv
  1089. Parameters:
  1090. plsc - (IN) ptr to line services context
  1091. durAutoDecimalTab - (IN) auto decimal tab offset
  1092. Creates tab stop record and dnode for "auto-decimal tab"
  1093. ----------------------------------------------------------------------------*/
  1094. LSERR InitializeAutoDecTab(PLSC plsc, long durAutoDecimalTab)
  1095. {
  1096. PLSDNODE plsdnTab;
  1097. LSERR lserr;
  1098. LSKTAB lsktab;
  1099. BOOL fBreakThroughTab;
  1100. LSCP cpLimOriginal;
  1101. if (durAutoDecimalTab > GetCurrentUr(plsc))
  1102. {
  1103. cpLimOriginal = GetCurrentCpLim(plsc);
  1104. SetCurrentCpLim(plsc, LONG_MIN + 1);
  1105. lserr = InitTabsContextForAutoDecimalTab(&plsc->lstabscontext, durAutoDecimalTab);
  1106. if (lserr != lserrNone)
  1107. return lserrNone;
  1108. CreateDnode(plsc, plsdnTab);
  1109. *(GetWhereToPutLink(plsc, plsdnTab->plsdnPrev)) = plsdnTab;
  1110. SetCurrentDnode(plsc, plsdnTab);
  1111. /* fill in this dnode */
  1112. memset(&plsdnTab->u.real.objdim, 0, sizeof(OBJDIM));
  1113. memset(&plsdnTab->u.real.lschp, 0, sizeof(LSCHP));
  1114. plsdnTab->u.real.lschp.idObj = (WORD) IobjTextFromLsc(&plsc->lsiobjcontext);
  1115. plsdnTab->fTab = fTrue;
  1116. plsdnTab->fAutoDecTab = fTrue;
  1117. plsdnTab->cpLimOriginal = cpLimOriginal; /* it's important to display to put correct value here */
  1118. plsdnTab->dcp = 0;
  1119. /* If PrepareLineToDisplay is not called, this dnode will not convert to pen and will destroyed
  1120. as real dnode. So we need to put NULL to plsrun, pdobj, pinfosubl*/
  1121. plsdnTab->u.real.plsrun = NULL;
  1122. plsdnTab->u.real.pdobj = NULL;
  1123. plsdnTab->u.real.pinfosubl = NULL;
  1124. lserr = GetCurTabInfoCore(&plsc->lstabscontext, plsdnTab, GetCurrentUr(plsc),
  1125. fFalse, &lsktab, &fBreakThroughTab);
  1126. if (lserr != lserrNone)
  1127. return lserr;
  1128. TurnOnTabEncounted(plsc);
  1129. if (lsktab != lsktLeft)
  1130. TurnOnNonLeftTabEncounted(plsc);
  1131. /* restore cpLim */
  1132. SetCurrentCpLim(plsc, cpLimOriginal);
  1133. TurnOnAutodecimalTabPresent(plsc);
  1134. }
  1135. return lserrNone;
  1136. }
  1137. /* H A N D L E T A B */
  1138. /*----------------------------------------------------------------------------
  1139. %%Function: HandleTab
  1140. %%Contact: igorzv
  1141. Parameters:
  1142. plsc - (IN) ptr to line services context
  1143. Wraper around calls to tabutils module.
  1144. ----------------------------------------------------------------------------*/
  1145. LSERR HandleTab(PLSC plsc)
  1146. {
  1147. LSKTAB lsktab;
  1148. LSERR lserr;
  1149. BOOL fBreakThroughTab;
  1150. long durPendingTab;
  1151. long urNewMargin;
  1152. /* if we are not on a stage of a formatting this procedure resolve previous tab if any */
  1153. /* before tab calculation we should resolve pending tab */
  1154. lserr = ResolvePrevTabCore(&plsc->lstabscontext, GetCurrentDnode(plsc),
  1155. GetCurrentUr(plsc), &durPendingTab);
  1156. if (lserr != lserrNone)
  1157. return lserr;
  1158. /* move current pen position */
  1159. Assert(durPendingTab >= 0);
  1160. AdvanceCurrentUr(plsc, durPendingTab);
  1161. if (FFormattingAllowed(plsc))
  1162. {
  1163. /* in this case we are called only after tab */
  1164. Assert(GetCurrentDnode(plsc)->fTab);
  1165. lserr = GetCurTabInfoCore(&plsc->lstabscontext, GetCurrentDnode(plsc), GetCurrentUr(plsc),
  1166. fFalse, &lsktab, &fBreakThroughTab);
  1167. if (lserr != lserrNone)
  1168. return lserr;
  1169. TurnOnTabEncounted(plsc);
  1170. if (lsktab != lsktLeft)
  1171. TurnOnNonLeftTabEncounted(plsc);
  1172. /* move current pen position */
  1173. AdvanceCurrentUr(plsc, DurFromDnode(GetCurrentDnode(plsc)));
  1174. if (fBreakThroughTab)
  1175. {
  1176. lserr = GetMarginAfterBreakThroughTab(&plsc->lstabscontext, GetCurrentDnode(plsc),
  1177. &urNewMargin);
  1178. if (lserr != lserrNone)
  1179. return lserr;
  1180. SetBreakthroughLine(plsc, urNewMargin);
  1181. }
  1182. }
  1183. return lserrNone;
  1184. }
  1185. #define idObjSplat idObjTextChp - 2
  1186. /* H A N D L E S P L A T */
  1187. /*----------------------------------------------------------------------------
  1188. %%Function: HandleSplat
  1189. %%Contact: igorzv
  1190. Parameters:
  1191. plsc - (IN) ptr to line services context
  1192. pfmtres - (OUT) fmtres of the splat dnode, procedure can change it
  1193. in the case of fIgnoreSplatBreak to either fmtrCompletedRun
  1194. or fmtrStopped
  1195. Markes dnode for splat, deletes it in a case of fIgnoreSplatBreak
  1196. ----------------------------------------------------------------------------*/
  1197. LSERR HandleSplat(PLSC plsc, FMTRES* pfmtres)
  1198. {
  1199. PLSDNODE plsdn;
  1200. LSCP cpAfterSplat;
  1201. BOOL fQuit;
  1202. LSERR lserr;
  1203. plsdn = GetCurrentDnode(plsc);
  1204. cpAfterSplat = GetCurrentCpLim(plsc);
  1205. if (plsc->fIgnoreSplatBreak)
  1206. {
  1207. lserr = CheckNewPara(plsc, cpAfterSplat - 1, cpAfterSplat, &fQuit);
  1208. if (lserr != lserrNone)
  1209. return lserr;
  1210. if (fQuit)
  1211. {
  1212. /* despite plsc->fIgnoreSplatBreak we should stop formatting here */
  1213. *pfmtres = fmtrStopped;
  1214. }
  1215. else
  1216. {
  1217. *pfmtres = fmtrCompletedRun;
  1218. }
  1219. /* delete splat dnode */
  1220. /* break link */
  1221. *(GetWhereToPutLink(plsc, plsdn->plsdnPrev)) = NULL;
  1222. /* restore current dnode, don't change cpLim and geometry */
  1223. SetCurrentDnode(plsc, plsdn->plsdnPrev);
  1224. Assert(plsdn->plsdnNext == NULL);
  1225. lserr = DestroyDnodeList (&plsc->lscbk, plsc->pols, &plsc->lsiobjcontext,
  1226. plsdn, plsc->fDontReleaseRuns);
  1227. if (lserr != lserrNone)
  1228. return lserr;
  1229. }
  1230. else
  1231. {
  1232. /* set special idobj that will solve all chunk group chunk problems */
  1233. Assert(FIsDnodeReal(plsdn));
  1234. plsdn->u.real.lschp.idObj = idObjSplat;
  1235. TurnOffAllSimpleText(plsc); /* not simple text */
  1236. }
  1237. return lserrNone;
  1238. }
  1239. /* C R E A T E S U B L I N E C O R E */
  1240. /*----------------------------------------------------------------------------
  1241. %%Function: CreateSublineCore
  1242. %%Contact: igorzv
  1243. Parameters:
  1244. plsc - (IN) ptr to line services context
  1245. cpFirst - (IN) first cp of a subline
  1246. urColumnMax - (IN) max possible width of a subline
  1247. lstflow - (IN) text flow of a subline
  1248. fContiguos - (IN) if TRUE such line has the same coordinate system as main line
  1249. and is allowed to have tabs
  1250. Allocates, initializes subline structure. Sets subline as current.
  1251. ----------------------------------------------------------------------------*/
  1252. LSERR CreateSublineCore(PLSC plsc, LSCP cpFirst, long urColumnMax,
  1253. LSTFLOW lstflow, BOOL fContiguous)
  1254. {
  1255. PLSSUBL plssubl;
  1256. LSERR lserr;
  1257. Assert(FIsLSC(plsc));
  1258. Assert(FFormattingAllowed(plsc) || FBreakingAllowed(plsc));
  1259. Assert(GetCurrentSubline(plsc) == NULL);
  1260. plssubl = plsc->lscbk.pfnNewPtr(plsc->pols,
  1261. sizeof(LSSUBL));
  1262. if (plssubl == NULL)
  1263. return lserrOutOfMemory;
  1264. /* fill in structure */
  1265. plssubl->tag = tagLSSUBL;
  1266. plssubl->plsc = plsc;
  1267. plssubl->cpFirst = cpFirst;
  1268. plssubl->lstflow = lstflow;
  1269. plssubl->urColumnMax = urColumnMax;
  1270. plssubl->cpLim = cpFirst;
  1271. plssubl->plsdnFirst = NULL;
  1272. plssubl->plsdnLast = NULL;
  1273. plssubl->fMain = fFalse;
  1274. plssubl->plsdnUpTemp = NULL;
  1275. plssubl->fAcceptedForDisplay = fFalse;
  1276. plssubl->fRightMarginExceeded = fFalse;
  1277. if (fContiguous)
  1278. {
  1279. Assert(FFormattingAllowed(plsc));
  1280. Assert(SublineFromDnode(GetDnodeToFinish(plsc))->fContiguous);
  1281. plssubl->urCur = GetCurrentUrSubl(SublineFromDnode(GetDnodeToFinish(plsc)));
  1282. plssubl->vrCur = GetCurrentVrSubl(SublineFromDnode(GetDnodeToFinish(plsc)));
  1283. }
  1284. else
  1285. {
  1286. plssubl->urCur = 0;
  1287. plssubl->vrCur = 0;
  1288. }
  1289. plssubl->fContiguous = (BYTE) fContiguous;
  1290. plssubl->fDupInvalid = fTrue;
  1291. plssubl->plschunkcontext = plsc->lscbk.pfnNewPtr(plsc->pols,
  1292. sizeof(LSCHUNKCONTEXT));
  1293. if (plssubl->plschunkcontext == NULL)
  1294. return lserrOutOfMemory;
  1295. lserr = AllocChunkArrays(plssubl->plschunkcontext, &plsc->lscbk, plsc->pols,
  1296. &plsc->lsiobjcontext);
  1297. if (lserr != lserrNone)
  1298. return lserr;
  1299. InitSublineChunkContext(plssubl->plschunkcontext, plssubl->urCur, plssubl->vrCur);
  1300. /* allocate break context */
  1301. plssubl->pbrkcontext = plsc->lscbk.pfnNewPtr(plsc->pols,
  1302. sizeof(BRKCONTEXT));
  1303. if (plssubl->pbrkcontext == NULL)
  1304. return lserrOutOfMemory;
  1305. /* set flags */
  1306. plssubl->pbrkcontext->fBreakPrevValid = fFalse;
  1307. plssubl->pbrkcontext->fBreakNextValid = fFalse;
  1308. plssubl->pbrkcontext->fBreakForceValid = fFalse;
  1309. /* set this subline as current */
  1310. SetCurrentSubline(plsc, plssubl);
  1311. IncreaseFormatDepth(plsc);
  1312. return lserrNone;
  1313. }
  1314. /* F I N I S H S U B L I N E C O R E */
  1315. /*----------------------------------------------------------------------------
  1316. %%Function: FinishSublineCore
  1317. %%Contact: igorzv
  1318. Parameters:
  1319. plssubl - (IN) subline to finish
  1320. Applies nominal to ideal to the last chunk of text, flushes current subline
  1321. ----------------------------------------------------------------------------*/
  1322. LSERR FinishSublineCore(
  1323. PLSSUBL plssubl) /* IN: subline to finish */
  1324. {
  1325. PLSC plsc;
  1326. LSERR lserr;
  1327. PLSDNODE plsdn;
  1328. Assert(FIsLSSUBL(plssubl));
  1329. plsc = plssubl->plsc;
  1330. Assert(plssubl == GetCurrentSubline(plsc));
  1331. /* apply nominal to ideal to the last chunk of text */
  1332. if (FNominalToIdealEncounted(plsc))
  1333. {
  1334. lserr = ApplyNominalToIdeal(PlschunkcontextFromSubline(plssubl), &plsc->lsiobjcontext,
  1335. plsc->grpfManager, plsc->lsadjustcontext.lskj,
  1336. FIsSubLineMain(plssubl), FLineContainsAutoNumber(plsc),
  1337. GetCurrentDnodeSubl(plssubl));
  1338. if (lserr != lserrNone)
  1339. return lserr;
  1340. }
  1341. /* skip back pen dnodes */
  1342. plsdn = plssubl->plsdnLast;
  1343. while (plsdn != NULL && FIsDnodePen(plsdn))
  1344. {
  1345. plsdn = plsdn->plsdnPrev;
  1346. }
  1347. /* close last border */
  1348. if (FDnodeHasBorder(plsdn) && !FIsDnodeCloseBorder(plsdn))
  1349. {
  1350. lserr = CloseCurrentBorder(plsc);
  1351. if (lserr != lserrNone)
  1352. return lserr;
  1353. }
  1354. /* set boundaries for display */
  1355. SetCpLimDisplaySubl(plssubl, GetCurrentCpLimSubl(plssubl));
  1356. SetLastDnodeDisplaySubl(plssubl, GetCurrentDnodeSubl(plssubl));
  1357. /* flush current subline */
  1358. SetCurrentSubline(plsc, NULL);
  1359. DecreaseFormatDepth(plsc);
  1360. lserr = LsSublineFinishedText(PlnobjFromLsc(plsc, IobjTextFromLsc(&((plsc)->lsiobjcontext))));
  1361. if (lserr != lserrNone)
  1362. return lserr;
  1363. return lserrNone;
  1364. }
  1365. /* U N D O L A S T D N O D E */
  1366. /*----------------------------------------------------------------------------
  1367. %%Function: UndoLastDnode
  1368. %%Contact: igorzv
  1369. Parameters:
  1370. plsc - (IN) ptr to line services context
  1371. Restores set before last dnode and deletes it.
  1372. ----------------------------------------------------------------------------*/
  1373. static LSERR UndoLastDnode(PLSC plsc)
  1374. {
  1375. PLSDNODE plsdn = GetCurrentDnode(plsc);
  1376. long cpDecrease;
  1377. Assert(FIsLSDNODE(plsdn));
  1378. /* break link */
  1379. *(GetWhereToPutLink(plsc, plsdn->plsdnPrev)) = NULL;
  1380. /* restore state */
  1381. cpDecrease = plsdn->dcp;
  1382. AdvanceCurrentCpLim(plsc, -cpDecrease);
  1383. SetCurrentDnode(plsc, plsdn->plsdnPrev);
  1384. AdvanceCurrentUr(plsc, -DurFromDnode(plsdn));
  1385. AdvanceCurrentVr(plsc, -DvrFromDnode(plsdn));
  1386. Assert(plsdn->plsdnNext == NULL);
  1387. return DestroyDnodeList (&plsc->lscbk, plsc->pols, &plsc->lsiobjcontext,
  1388. plsdn, plsc->fDontReleaseRuns);
  1389. }
  1390. /* O P E N B O R D E R */
  1391. /*----------------------------------------------------------------------------
  1392. %%Function: OpenBorder
  1393. %%Contact: igorzv
  1394. Parameters:
  1395. plsc - (IN) ptr to line services context
  1396. plsrun - (IN) run with border information
  1397. Creates border dnode
  1398. ----------------------------------------------------------------------------*/
  1399. static LSERR OpenBorder(PLSC plsc, PLSRUN plsrun)
  1400. {
  1401. PLSDNODE plsdnCurrent;
  1402. PLSDNODE* pplsdnToStoreNext;
  1403. long durBorder, dupBorder;
  1404. PLSDNODE plsdnBorder;
  1405. LSERR lserr;
  1406. plsdnCurrent = GetCurrentDnode(plsc);
  1407. pplsdnToStoreNext = GetWhereToPutLink(plsc, plsdnCurrent);
  1408. lserr = plsc->lscbk.pfnGetBorderInfo(plsc->pols, plsrun, GetCurrentLstflow(plsc),
  1409. &durBorder, &dupBorder);
  1410. if (lserr != lserrNone)
  1411. return lserr;
  1412. CreateBorderDnode(plsc, plsdnBorder, durBorder, dupBorder);
  1413. plsdnBorder->fOpenBorder = fTrue;
  1414. /* maintain list and state */
  1415. *pplsdnToStoreNext = plsdnBorder;
  1416. SetCurrentDnode(plsc, plsdnBorder);
  1417. AdvanceCurrentUr(plsc, durBorder);
  1418. TurnOffAllSimpleText(plsc); /* not simple text */
  1419. return lserrNone;
  1420. }
  1421. /* C L O S E C U R R E N T B O R D E R */
  1422. /*----------------------------------------------------------------------------
  1423. %%Function: CloseCurrentBorder
  1424. %%Contact: igorzv
  1425. Parameters:
  1426. plsc - (IN) ptr to line services context
  1427. Creates border dnode
  1428. ----------------------------------------------------------------------------*/
  1429. LSERR CloseCurrentBorder(PLSC plsc)
  1430. {
  1431. PLSDNODE plsdnCurrent;
  1432. PLSDNODE* pplsdnToStoreNext;
  1433. long durBorder, dupBorder;
  1434. PLSDNODE plsdnBorder;
  1435. LSERR lserr;
  1436. PLSDNODE plsdn;
  1437. plsdnCurrent = GetCurrentDnode(plsc);
  1438. pplsdnToStoreNext = GetWhereToPutLink(plsc, plsdnCurrent);
  1439. /* find open border */
  1440. plsdn = plsdnCurrent;
  1441. Assert(FIsLSDNODE(plsdn));
  1442. while (! FIsDnodeBorder(plsdn))
  1443. {
  1444. plsdn = plsdn->plsdnPrev;
  1445. Assert(FIsLSDNODE(plsdn));
  1446. }
  1447. Assert(plsdn->fOpenBorder);
  1448. if (plsdn != plsdnCurrent)
  1449. {
  1450. durBorder = plsdn->u.pen.dur;
  1451. dupBorder = plsdn->u.pen.dup;
  1452. CreateBorderDnode(plsc, plsdnBorder, durBorder, dupBorder);
  1453. /* maintain list and state */
  1454. *pplsdnToStoreNext = plsdnBorder;
  1455. SetCurrentDnode(plsc, plsdnBorder);
  1456. AdvanceCurrentUr(plsc, durBorder);
  1457. }
  1458. else
  1459. {
  1460. /* we have empty list between borders */
  1461. lserr = UndoLastDnode(plsc);
  1462. if (lserr != lserrNone)
  1463. return lserrNone;
  1464. }
  1465. return lserrNone;
  1466. }
  1467. long RightMarginIncreasing(PLSC plsc, long urColumnMax)
  1468. {
  1469. long Coeff = plsc->lMarginIncreaseCoefficient;
  1470. long urInch;
  1471. long One32rd;
  1472. if (urColumnMax <= 0)
  1473. {
  1474. /* such strange formula for non positive margin is to have on
  1475. the first iteration 1 inch and 8 inches on the second*/
  1476. urInch = UrFromUa(LstflowFromSubline(GetCurrentSubline(plsc)),
  1477. &(plsc)->lsdocinf.lsdevres, 1440);
  1478. if (Coeff == uLsInfiniteRM || (Coeff >= uLsInfiniteRM / (7 * urInch)))
  1479. return uLsInfiniteRM;
  1480. else
  1481. return (7*Coeff - 6)* urInch;
  1482. }
  1483. else
  1484. {
  1485. if (urColumnMax <= 32)
  1486. One32rd = 1;
  1487. else
  1488. One32rd = urColumnMax >> 5;
  1489. if (Coeff == uLsInfiniteRM || (Coeff >= (uLsInfiniteRM - urColumnMax)/One32rd))
  1490. return uLsInfiniteRM;
  1491. else
  1492. return urColumnMax + (Coeff * One32rd);
  1493. }
  1494. }
  1495. /*----------------------------------------------------------------------------
  1496. /* E R R R E L E A S E R U N T O F O R M A T */
  1497. /*----------------------------------------------------------------------------
  1498. %%Function: ErrReleaseRunToFormat
  1499. %%Contact: igorzv
  1500. Parameters:
  1501. plsc - (IN) ptr to line services context
  1502. plsrun - (IN) ponter to a run structure to be deleted
  1503. lserr - (IN) code of an error
  1504. Called in a error situation when run has not been formatted yet .
  1505. ----------------------------------------------------------------------------*/
  1506. static LSERR ErrReleaseRunToFormat(PLSC plsc, PLSRUN plsrun, LSERR lserr)
  1507. {
  1508. LSERR lserrIgnore;
  1509. if (!plsc->fDontReleaseRuns)
  1510. lserrIgnore = plsc->lscbk.pfnReleaseRun(plsc->pols, plsrun);
  1511. return lserr;
  1512. }