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.

1939 lines
58 KiB

  1. #include <limits.h>
  2. #include "lsmem.h" /* memset() */
  3. #include "break.h"
  4. #include "dnutils.h"
  5. #include "iobj.h"
  6. #include "iobjln.h"
  7. #include "lsc.h"
  8. #include "lschp.h"
  9. #include "lscrline.h"
  10. #include "lsdevres.h"
  11. #include "lskysr.h"
  12. #include "lsffi.h"
  13. #include "lsidefs.h"
  14. #include "lsline.h"
  15. #include "lsfetch.h"
  16. #include "lstext.h"
  17. #include "prepdisp.h"
  18. #include "tlpr.h"
  19. #include "qheap.h"
  20. #include "sublutil.h"
  21. #include "zqfromza.h"
  22. #include "lscfmtfl.h"
  23. #include "limqmem.h"
  24. #include "ntiman.h"
  25. typedef struct
  26. {
  27. long urLeft;
  28. BOOL fAutoDecimalTab;
  29. long durAutoDecimalTab;
  30. LSCP cpFirstVis;
  31. BOOL fAutonumber;
  32. BOOL fStopped;
  33. BOOL fYsrChangeAfter;
  34. WCHAR wchYsr; /* we need memory to keep wchYsr for kysrChangeAfter */
  35. } LINEGEOMETRY;
  36. static LSERR CreateLineCore(PLSC, /* IN: ptr to line services context */
  37. LSCP, /* IN: starting cp in line */
  38. long, /* IN: column width in twips */
  39. const BREAKREC*, /* IN: previous line's break records */
  40. DWORD, /* IN: number of previous line's break records */
  41. DWORD, /* IN: size of the array of current line's break records */
  42. BREAKREC*, /* OUT: current line's break records */
  43. DWORD*, /* OUT: actual number of current line's break records */
  44. LSLINFO*, /* OUT: visible line info to fill in */
  45. PLSLINE*, /* OUT: ptr to line opaque to client */
  46. BOOL*); /* OUT fSuccessful: false means insufficient fetch */
  47. static BOOL FRoundingOK(void);
  48. static LSERR CannotCreateLine(PLSLINE*, /* IN: ponter to a line structure to be deleted */
  49. LSERR); /* IN: code of an error */
  50. static LSERR ErrReleasePreFetchedRun (PLSC, /* IN: ptr to line services context */
  51. PLSRUN, /* IN: ponter to a run structure to be deleted */
  52. LSERR); /* IN: code of an error */
  53. static LSERR EndFormatting(PLSC, /* IN: ptr to line services context */
  54. enum endres, /* IN: type of line ending to put in lslinfo */
  55. LSCP, /* IN: cpLim to put in lslinfo */
  56. LSDCP, /* IN: dcpDepend to put in lslinfo*/
  57. LSLINFO*); /* OUT: lslinfo to fill in, output of LsCreateLine*/
  58. static LSERR FiniFormatGeneralCase (
  59. PLSC, /* IN: ptr to line services context */
  60. const BREAKREC*,/* IN: input array of break records */
  61. DWORD, /* IN: number of records in input array */
  62. DWORD, /* IN: size of the output array */
  63. BREAKREC*, /* OUT: output array of break records */
  64. DWORD*, /* OUT:actual number of records in array*/
  65. LSLINFO*, /* OUT: lslinfo to fill in, output of LsCreateLine*/
  66. BOOL*); /* OUT fSuccessful: false means insufficient fetch */
  67. static LSERR FiniEndLine(PLSC, /* IN: ptr to line services context */
  68. ENDRES, /* IN: how the line ended */
  69. LSCP /* IN: cpLim of a line as a result of breaking,
  70. can be changed in this procedure*/,
  71. LSDCP, /* IN: dcpDepend (amount of characters after breaking point
  72. that has participated in breaking decision)
  73. can be changed in this procedure */
  74. LSLINFO*); /* OUT: lslinfo to fill in, output of LsCreateLine*/
  75. static LSERR FetchUntilVisible(
  76. PLSC, /* IN: ptr to line services context */
  77. LSPAP*, /* IN/OUT current lspap before and after */
  78. LSCP*, /* IN/OUT current cp before and after */
  79. LSFRUN*, /* IN/OUT current lsfrun before and after */
  80. PLSCHP, /* IN/OUT current lschp before and after */
  81. BOOL*, /* OUT fStopped: procedure stopped fetching because has not been allowed
  82. to go across paragraph boundaries (result CheckPara Boundaries) */
  83. BOOL*); /* OUT fNewPara: procedure crossed paragraph boundaries */
  84. static LSERR InitTextParams(PLSC, /* IN: ptr to line services context */
  85. LSCP, /* IN: cp to start fetch */
  86. long, /* IN: duaColumn */
  87. LSFRUN*, /* OUT: lsfrun of the first run */
  88. PLSCHP, /* OUT: lsfrun of the first run */
  89. LINEGEOMETRY*); /* OUT: set of flags and parameters about a line */
  90. static LSERR FiniAuto(PLSC , /* IN: ptr to line services context */
  91. BOOL , /* IN: fAutonumber */
  92. BOOL , /* IN: fAutoDecimalTab */
  93. PLSFRUN , /* IN: first run of the main text */
  94. long, /* IN: durAutoDecimalTab */
  95. const BREAKREC*, /* IN: input array of break records */
  96. DWORD, /* IN: number of records in input array */
  97. DWORD, /* IN: size of the output array */
  98. BREAKREC*, /* OUT: output array of break records */
  99. DWORD*, /* OUT:actual number of records in array*/
  100. LSLINFO*, /* OUT: lslinfo to fill in, output of LsCreateLine*/
  101. BOOL*); /* OUT fSuccessful: false means insufficient fetch */
  102. static LSERR InitCurLine(PLSC plsc, /* IN: ptr to line services context */
  103. LSCP cpFirst); /* IN: first cp in al line */
  104. static LSERR RemoveLineObjects(PLSLINE plsline); /* IN: ponter to a line structure */
  105. static LSERR GetYsrChangeAfterRun(
  106. PLSC plsc, /* IN: ptr to line services context */
  107. LSCP cp, /* IN: cp to start fetch */
  108. BOOL* pfYsrChangeAfter, /* OUT: is it hyphenation of the previous line */
  109. PLSFRUN plsfrun, /* OUT: lsfrun of modified first run */
  110. PLSCHP plschp, /* OUT: lschp of modified first run */
  111. LINEGEOMETRY*); /* OUT: to put wchYsr */
  112. static LSERR FillTextParams(
  113. PLSC plsc, /* IN: ptr to line services context */
  114. LSCP cp, /* IN: cp to start fetch */
  115. long duaCol, /* IN: duaColumn */
  116. PLSPAP plspap, /* IN: paragraph properties */
  117. BOOL fFirstLineInPara, /* IN: flag fFirstLineInPara */
  118. BOOL fStopped, /* IN: flag fStopped */
  119. LINEGEOMETRY*); /* OUT: set of flags and parameters about a line */
  120. static LSERR FiniChangeAfter(
  121. PLSC plsc, /* IN: ptr to line services context */
  122. LSFRUN* plsfrun, /* IN: lsfrun of modified first run */
  123. const BREAKREC*, /* IN: input array of break records */
  124. DWORD, /* IN: number of records in input array */
  125. DWORD, /* IN: size of the output array */
  126. BREAKREC*, /* OUT: output array of break records */
  127. DWORD*, /* OUT:actual number of records in array*/
  128. LSLINFO*, /* OUT: lslinfo to fill in, output of LsCreateLine*/
  129. BOOL*); /* OUT fSuccessful: false means insufficient fetch */
  130. /* L I M R G */
  131. /*----------------------------------------------------------------------------
  132. %%Function: LimRg
  133. %%Contact: lenoxb
  134. Returns # of elements in an array.
  135. ----------------------------------------------------------------------------*/
  136. #define LimRg(rg) (sizeof(rg)/sizeof((rg)[0]))
  137. #define fFmiAdvancedFormatting (fFmiPunctStartLine | fFmiHangingPunct)
  138. #define FBreakJustSimple(lsbrj) (lsbrj == lsbrjBreakJustify || lsbrj == lsbrjBreakThenSqueeze)
  139. #define FAdvancedTypographyEnabled(plsc, cbreakrec) \
  140. (FNominalToIdealBecauseOfParagraphProperties(plsc->grpfManager, \
  141. plsc->lsadjustcontext.lskj) || \
  142. !FBreakJustSimple((plsc)->lsadjustcontext.lsbrj) ||\
  143. cbreakrec != 0 \
  144. )
  145. #define fFmiSpecialSpaceBreaking (fFmiWrapTrailingSpaces | fFmiWrapAllSpaces)
  146. #define fFmiQuickBreakProhibited (fFmiSpecialSpaceBreaking | fFmiDoHyphenation)
  147. /* F T R Y Q U I C K B R E A K */
  148. /*----------------------------------------------------------------------------
  149. %%Macro: FTryQuickBreak
  150. %%Contact: igorzv
  151. "Returns" fTrue when the formatter flags indicate that it it may be
  152. possible to use QuickBreakText() instead of the more expensive
  153. BreakGeneralCase().
  154. ----------------------------------------------------------------------------*/
  155. #define FTryQuickBreak(plsc) ((((plsc)->grpfManager & fFmiQuickBreakProhibited) == 0) && \
  156. ((plsc)->lMarginIncreaseCoefficient == LONG_MIN) \
  157. )
  158. #define GetMainSubline(plsc) \
  159. (Assert(FWorkWithCurrentLine(plsc)),\
  160. &((plsc)->plslineCur->lssubl))
  161. #define FPapInconsistent(plspap) \
  162. ((((plspap)->lsbrj == lsbrjBreakJustify || \
  163. (plspap)->lsbrj == lsbrjBreakWithCompJustify) \
  164. && (plspap)->uaRightBreak < uLsInfiniteRM \
  165. && (plspap)->uaRightBreak != (plspap)->uaRightJustify) \
  166. || ((plspap)->lsbrj == lsbrjBreakThenExpand \
  167. && (plspap)->uaRightBreak < (plspap)->uaRightJustify) \
  168. || ((plspap)->lsbrj == lsbrjBreakThenSqueeze \
  169. && (plspap)->uaRightBreak > (plspap)->uaRightJustify) \
  170. || ((plspap)->lsbrj != lsbrjBreakWithCompJustify \
  171. && (plspap)->grpf & fFmiHangingPunct) \
  172. || ((plspap)->lsbrj == lsbrjBreakWithCompJustify \
  173. && (plspap)->lskj == lskjFullGlyphs))
  174. /* ---------------------------------------------------------------------- */
  175. /* L S C R E A T E L I N E */
  176. /*----------------------------------------------------------------------------
  177. %%Function: LsCreateLine
  178. %%Contact: igorzv
  179. Parameters:
  180. plsc - (IN) ptr to line services context
  181. cpFirst - (IN) starting cp in line
  182. duaColumn - (IN) column width in twips
  183. pbreakrecPrev - (IN) previous line's break records
  184. breakrecMacPrev - (IN) number of previous line's break records
  185. breakrecMaxCurrent- (IN) size of the array of current line's break records
  186. pbreakrecCurrent- (OUT) current line's break records
  187. pbreakrecMacCurrent-(OUT) actual number of current line's break records
  188. plsinfo - (OUT) visible line info to fill in
  189. pplsline - (OUT) ptr to line opaque to client
  190. An exported LineServices API.
  191. ----------------------------------------------------------------------------*/
  192. LSERR WINAPI LsCreateLine(PLSC plsc,
  193. LSCP cpFirst,
  194. long duaColumn,
  195. const BREAKREC* pbreakrecPrev,
  196. DWORD breakrecMacPrev,
  197. DWORD breakrecMaxCurrent,
  198. BREAKREC* pbreakrecCurrent,
  199. DWORD* pbreakrecMacCurrent,
  200. LSLINFO* plslinfo,
  201. PLSLINE* pplsline)
  202. {
  203. LSERR lserr;
  204. BOOL fSuccessful;
  205. /* Check parameters and enviroment */
  206. Assert(FRoundingOK());
  207. if (plslinfo == NULL || pplsline == NULL || pbreakrecMacCurrent == NULL)
  208. return lserrNullOutputParameter;
  209. *pplsline = NULL;
  210. *pbreakrecMacCurrent = 0; /* it's very important to initialize number of break records
  211. because for example quick break doesn't work with break records */
  212. if (!FIsLSC(plsc))
  213. return lserrInvalidContext;
  214. if (plsc->lsstate != LsStateFree)
  215. return lserrContextInUse;
  216. Assert(FIsLsContextValid(plsc));
  217. if (pbreakrecPrev == NULL && breakrecMacPrev != 0)
  218. return lserrInvalidParameter;
  219. if (pbreakrecCurrent == NULL && breakrecMaxCurrent != 0)
  220. return lserrInvalidParameter;
  221. if (duaColumn < 0)
  222. return lserrInvalidParameter;
  223. if (duaColumn > uLsInfiniteRM)
  224. duaColumn = uLsInfiniteRM;
  225. /* if we have current line we must prepare it for display before creating of new line */
  226. /* can change context. We've delayed this untill last moment because of optimisation reasons */
  227. if (plsc->plslineCur != NULL)
  228. {
  229. lserr = PrepareLineForDisplayProc(plsc->plslineCur);
  230. if (lserr != lserrNone)
  231. return lserr;
  232. plsc->plslineCur = NULL;
  233. }
  234. plsc->lMarginIncreaseCoefficient = LONG_MIN;
  235. do /* loop allowing change of exceeded right margin if it's not sufficient */
  236. {
  237. lserr = CreateLineCore(plsc, cpFirst, duaColumn, pbreakrecPrev, breakrecMacPrev,
  238. breakrecMaxCurrent, pbreakrecCurrent, pbreakrecMacCurrent,
  239. plslinfo, pplsline, &fSuccessful);
  240. if (lserr != lserrNone)
  241. return lserr;
  242. if (!fSuccessful)
  243. { /* coefficient has not been sufficient before so increase it */
  244. if (plsc->lMarginIncreaseCoefficient == LONG_MIN)
  245. plsc->lMarginIncreaseCoefficient = 1;
  246. else
  247. {
  248. if (plsc->lMarginIncreaseCoefficient >= uLsInfiniteRM / 2 )
  249. plsc->lMarginIncreaseCoefficient = uLsInfiniteRM;
  250. else
  251. plsc->lMarginIncreaseCoefficient *= 2;
  252. }
  253. }
  254. }
  255. while (!fSuccessful);
  256. #ifdef DEBUG
  257. #ifdef LSTEST_GETMINDUR
  258. /* Test LsGetMinDurBreaks () */
  259. if ((lserr == lserrNone) && (plslinfo->endr != endrNormal) &&
  260. (plslinfo->endr != endrHyphenated) && (! (plsc->grpfManager & fFmiDoHyphenation)) )
  261. {
  262. /* Line was ended with hard break / stopped */
  263. long durMinInclTrail;
  264. long durMinExclTrail;
  265. lserr = LsGetMinDurBreaks ( plsc, *pplsline, &durMinInclTrail,
  266. &durMinExclTrail );
  267. };
  268. #endif /* LSTEST_GETMINDUR */
  269. #endif /* DEBUG */
  270. return lserr;
  271. }
  272. /* ---------------------------------------------------------------------- */
  273. /* C R E A T E L I N E C O R E*/
  274. /*----------------------------------------------------------------------------
  275. %%Function: CreateLineCore
  276. %%Contact: igorzv
  277. Parameters:
  278. plsc - (IN) ptr to line services context
  279. cpFirst - (IN) starting cp in line
  280. duaColumn - (IN) column width in twips
  281. pbreakrecPrev - (IN) previous line's break records
  282. breakrecMacPrev - (IN) number of previous line's break records
  283. breakrecMaxCurrent- (IN) size of the array of current line's break records
  284. pbreakrecCurrent- (OUT) current line's break records
  285. pbreakrecMacCurrent-(OUT) actual number of current line's break records
  286. plsinfo - (OUT) visible line info to fill in
  287. pplsline - (OUT) ptr to line opaque to client
  288. pfSuccessful - (OUT) fSuccessful: false means insufficient fetch
  289. Internal procedure organized to handle error in choosing extended right margin
  290. ----------------------------------------------------------------------------*/
  291. static LSERR CreateLineCore(PLSC plsc,
  292. LSCP cpFirst,
  293. long duaColumn,
  294. const BREAKREC* pbreakrecPrev,
  295. DWORD breakrecMacPrev,
  296. DWORD breakrecMaxCurrent,
  297. BREAKREC* pbreakrecCurrent,
  298. DWORD* pbreakrecMacCurrent,
  299. LSLINFO* plslinfo,
  300. PLSLINE* pplsline,
  301. BOOL* pfSuccessful)
  302. {
  303. PLSLINE plsline;
  304. LINEGEOMETRY lgeom;
  305. LSCHP lschp;
  306. LSERR lserr;
  307. BOOL fGeneral = fFalse;
  308. BOOL fHardStop;
  309. BOOL fSuccessfulQuickBreak;
  310. LSCP cpLimLine;
  311. LSDCP dcpDepend = 0;
  312. LSFRUN lsfrun;
  313. long urFinalPen;
  314. long urColumnMaxIncreased;
  315. ENDRES endr = endrNormal;
  316. /*Initialization; */
  317. *pfSuccessful = fTrue;
  318. lsfrun.plschp = &lschp; /* we use the same area for lschips */
  319. /* because we pasing pointer to const nobody can change it */
  320. plsline= PvNewQuick(plsc->pqhLines, cbRep(struct lsline, rgplnobj, plsc->lsiobjcontext.iobjMac));
  321. if (plsline == NULL)
  322. return lserrOutOfMemory;
  323. plsc->lsstate = LsStateFormatting; /* We start here forwating line. After this momemt we must
  324. free context before return. We do this either in CannotCreateLine (error)
  325. or EndFormatting (success) */
  326. plsc->plslineCur = plsline;
  327. *pplsline = plsline;
  328. lserr = InitCurLine (plsc, cpFirst);
  329. if (lserr != lserrNone)
  330. return CannotCreateLine(pplsline, lserr);
  331. /* check initial value of flags */
  332. Assert(FAllSimpleText(plsc));
  333. Assert(!FNonRealDnodeEncounted(plsc));
  334. Assert(!FNonZeroDvpPosEncounted(plsc));
  335. Assert(AggregatedDisplayFlags(plsc) == 0);
  336. Assert(!FNominalToIdealEncounted(plsc));
  337. Assert(!FForeignObjectEncounted(plsc));
  338. Assert(!FTabEncounted(plsc));
  339. Assert(!FNonLeftTabEncounted(plsc));
  340. Assert(!FSubmittedSublineEncounted(plsc));
  341. Assert(!FAutodecimalTabPresent(plsc));
  342. plsc->cLinesActive += 1;
  343. lserr = InitTextParams(plsc, cpFirst, duaColumn, &lsfrun, &lschp, &lgeom);
  344. if (lserr != lserrNone)
  345. return CannotCreateLine(pplsline,lserr);
  346. /* prepare starting set for formatting */
  347. InitFormattingContext(plsc, lgeom.urLeft, lgeom.cpFirstVis);
  348. /* REVIEW comments */
  349. if (lgeom.fStopped)
  350. {
  351. plsc->lsstate = LsStateBreaking; /* we now in a stage of breaking */
  352. lserr = FiniEndLine(plsc, endrStopped, lgeom.cpFirstVis, 0, plslinfo);
  353. if (lserr != lserrNone)
  354. return CannotCreateLine(pplsline,lserr);
  355. else
  356. return lserrNone;
  357. }
  358. /* change first character because of hyphenation */
  359. if (lgeom.fYsrChangeAfter)
  360. {
  361. Assert(!(lgeom.fAutonumber) || (lgeom.fAutoDecimalTab));
  362. lserr = FiniChangeAfter(plsc, &lsfrun, pbreakrecPrev,
  363. breakrecMacPrev, breakrecMaxCurrent,
  364. pbreakrecCurrent, pbreakrecMacCurrent, plslinfo, pfSuccessful);
  365. if (lserr != lserrNone || !*pfSuccessful)
  366. return CannotCreateLine(pplsline, lserr);
  367. else
  368. return lserrNone;
  369. }
  370. /* important note to understand code flow : The situation below can happened
  371. only for first line in a paragraph, the situation above never can happened
  372. for such line. */
  373. /* if autonumbering or auto-decimal tab */
  374. if ((lgeom.fAutonumber) || (lgeom.fAutoDecimalTab))
  375. {
  376. Assert(!lgeom.fYsrChangeAfter);
  377. TurnOffAllSimpleText(plsc);
  378. /* we will release plsrun in FiniAuto */
  379. lserr = FiniAuto(plsc, lgeom.fAutonumber, lgeom.fAutoDecimalTab, &lsfrun,
  380. lgeom.durAutoDecimalTab, pbreakrecPrev,
  381. breakrecMacPrev, breakrecMaxCurrent,
  382. pbreakrecCurrent, pbreakrecMacCurrent, plslinfo, pfSuccessful);
  383. if (lserr != lserrNone || !*pfSuccessful)
  384. return CannotCreateLine(pplsline, lserr);
  385. else
  386. return lserrNone;
  387. }
  388. if (FAdvancedTypographyEnabled(plsc, breakrecMacPrev ))
  389. {
  390. /* we should release run here, in general procedure we will fetch it again */
  391. if (!plsc->fDontReleaseRuns)
  392. {
  393. lserr = plsc->lscbk.pfnReleaseRun(plsc->pols, lsfrun.plsrun);
  394. if (lserr != lserrNone)
  395. return CannotCreateLine(pplsline,lserr);
  396. }
  397. lserr = FiniFormatGeneralCase(plsc, pbreakrecPrev,
  398. breakrecMacPrev, breakrecMaxCurrent,
  399. pbreakrecCurrent, pbreakrecMacCurrent, plslinfo, pfSuccessful);
  400. if (lserr != lserrNone || !*pfSuccessful)
  401. return CannotCreateLine(pplsline,lserr);
  402. else
  403. return lserrNone;
  404. }
  405. /* it is possible that width of column is negative: in such scase we'll
  406. use another right margin*/
  407. if (plsc->urRightMarginBreak <= 0 && plsc->lMarginIncreaseCoefficient == LONG_MIN)
  408. plsc->lMarginIncreaseCoefficient = 1;
  409. if (plsc->lMarginIncreaseCoefficient != LONG_MIN)
  410. {
  411. urColumnMaxIncreased = RightMarginIncreasing(plsc, plsc->urRightMarginBreak);
  412. }
  413. else
  414. {
  415. urColumnMaxIncreased = plsc->urRightMarginBreak;
  416. }
  417. lserr = QuickFormatting(plsc, &lsfrun, urColumnMaxIncreased,
  418. &fGeneral, &fHardStop, &cpLimLine, &urFinalPen);
  419. if (lserr != lserrNone)
  420. return CannotCreateLine(pplsline,lserr);
  421. if (fGeneral)
  422. {
  423. lserr = FiniFormatGeneralCase(plsc, pbreakrecPrev,
  424. breakrecMacPrev, breakrecMaxCurrent,
  425. pbreakrecCurrent, pbreakrecMacCurrent,
  426. plslinfo, pfSuccessful);
  427. if (lserr != lserrNone || !*pfSuccessful)
  428. return CannotCreateLine(pplsline, lserr);
  429. else
  430. return lserrNone;
  431. }
  432. plsc->lsstate = LsStateBreaking; /* we now in a stage of breaking */
  433. if (FTryQuickBreak(plsc))
  434. {
  435. lserr = BreakQuickCase(plsc, fHardStop, &dcpDepend, &cpLimLine,
  436. &fSuccessfulQuickBreak, &endr);
  437. if (lserr != lserrNone)
  438. return CannotCreateLine(pplsline,lserr);
  439. }
  440. else
  441. {
  442. fSuccessfulQuickBreak = fFalse;
  443. }
  444. if (fSuccessfulQuickBreak)
  445. {
  446. if (endr == endrNormal || endr == endrAltEndPara ||
  447. (endr == endrEndPara && !plsc->fLimSplat))
  448. {
  449. lserr = EndFormatting(plsc, endr, cpLimLine,
  450. dcpDepend, plslinfo);
  451. if (lserr != lserrNone)
  452. return CannotCreateLine(pplsline,lserr);
  453. else
  454. return lserrNone;
  455. }
  456. else /* there is splat that is handled in FiniEndLine */
  457. {
  458. lserr = FiniEndLine(plsc, endr, cpLimLine, dcpDepend, plslinfo);
  459. if (lserr != lserrNone)
  460. return CannotCreateLine(pplsline, lserr);
  461. else
  462. return lserrNone;
  463. }
  464. }
  465. else
  466. {
  467. /* here we should use BreakGeneralCase */
  468. lserr = BreakGeneralCase(plsc, fHardStop, breakrecMaxCurrent,
  469. pbreakrecCurrent, pbreakrecMacCurrent,&dcpDepend,
  470. &cpLimLine, &endr, pfSuccessful);
  471. if (lserr != lserrNone || !*pfSuccessful)
  472. return CannotCreateLine(pplsline,lserr);
  473. lserr = FiniEndLine(plsc, endr, cpLimLine, dcpDepend, plslinfo);
  474. if (lserr != lserrNone)
  475. return CannotCreateLine(pplsline, lserr);
  476. else
  477. return lserrNone;
  478. }
  479. } /* end LsCreateLine */
  480. /* ---------------------------------------------------------------------- */
  481. /* F I N I F O R M A T G E N E R A L C A S E*/
  482. /*----------------------------------------------------------------------------
  483. %%Function: FiniFormatGeneralCase
  484. %%Contact: igorzv
  485. Parameters:
  486. plsc - (IN) ptr to line services context
  487. pbreakrecPrev - (IN) previous line's break records
  488. breakrecMacPrev - (IN) number of previous line's break records
  489. breakrecMaxCurrent- (IN) size of the array of current line's break records
  490. pbreakrecCurrent- (OUT) current line's break records
  491. pbreakrecMacCurrent-(OUT) actual number of current line's break records
  492. plsinfo - (OUT) visible line info to fill in
  493. pfSuccessful - (OUT) fSuccessful: false means insufficient fetch
  494. Formatting and breaking in a case when "quick formatting" is prohibit
  495. ----------------------------------------------------------------------------*/
  496. static LSERR FiniFormatGeneralCase (PLSC plsc,
  497. const BREAKREC* pbreakrecPrev,
  498. DWORD breakrecMacPrev,
  499. DWORD breakrecMaxCurrent,
  500. BREAKREC* pbreakrecCurrent,
  501. DWORD* pbreakrecMacCurrent,
  502. LSLINFO* plslinfo, BOOL* pfSuccessful)
  503. {
  504. long urColumnMaxIncreased;
  505. FMTRES fmtres;
  506. LSERR lserr;
  507. LSCP cpLimLine;
  508. LSDCP dcpDepend;
  509. PLSDNODE plsdnFirst, plsdnLast;
  510. long urFinal;
  511. ENDRES endr;
  512. Assert(FIsLSC(plsc));
  513. Assert(FFormattingAllowed(plsc));
  514. Assert(plslinfo != NULL);
  515. *pfSuccessful = fTrue;
  516. if (plsc->lMarginIncreaseCoefficient == LONG_MIN) /* we are here for the first time */
  517. {
  518. /* increase right margin for nominal to ideal and compression */
  519. if (!FBreakJustSimple(plsc->lsadjustcontext.lsbrj))
  520. plsc->lMarginIncreaseCoefficient = 2;
  521. else
  522. plsc->lMarginIncreaseCoefficient = 1;
  523. }
  524. urColumnMaxIncreased = RightMarginIncreasing(plsc, plsc->urRightMarginBreak);
  525. if (FNominalToIdealBecauseOfParagraphProperties(plsc->grpfManager,
  526. plsc->lsadjustcontext.lskj))
  527. TurnOnNominalToIdealEncounted(plsc);
  528. if (breakrecMacPrev != 0)
  529. lserr = FetchAppendEscResumeCore(plsc, urColumnMaxIncreased, NULL, 0,
  530. pbreakrecPrev, breakrecMacPrev,
  531. &fmtres, &cpLimLine, &plsdnFirst,
  532. &plsdnLast, &urFinal);
  533. else
  534. lserr = FetchAppendEscCore(plsc, urColumnMaxIncreased, NULL, 0,
  535. &fmtres, &cpLimLine, &plsdnFirst,
  536. &plsdnLast, &urFinal);
  537. if (lserr != lserrNone)
  538. return lserr;
  539. /* fetch append esc can be stopped because of tab */
  540. /* so we have loop for tabs here */
  541. while (fmtres == fmtrTab)
  542. {
  543. lserr = HandleTab(plsc);
  544. if (lserr != lserrNone)
  545. return lserr;
  546. if (FBreakthroughLine(plsc))
  547. {
  548. urColumnMaxIncreased = RightMarginIncreasing(plsc, plsc->urRightMarginBreak);
  549. }
  550. lserr = FetchAppendEscCore(plsc, urColumnMaxIncreased, NULL, 0,
  551. &fmtres, &cpLimLine, &plsdnFirst,
  552. &plsdnLast, &urFinal);
  553. if (lserr != lserrNone)
  554. return lserr;
  555. }
  556. Assert(fmtres == fmtrStopped || fmtres == fmtrExceededMargin);
  557. /* skip back pen dnodes */
  558. while (plsdnLast != NULL && FIsDnodePen(plsdnLast))
  559. {
  560. plsdnLast = plsdnLast->plsdnPrev;
  561. }
  562. /* close last border */
  563. if (FDnodeHasBorder(plsdnLast) && !FIsDnodeCloseBorder(plsdnLast))
  564. {
  565. lserr = CloseCurrentBorder(plsc);
  566. if (lserr != lserrNone)
  567. return lserr;
  568. }
  569. if (fmtres == fmtrExceededMargin
  570. && (urFinal <= plsc->urRightMarginBreak /* it's important for truncation to have <= here */
  571. || plsdnLast == NULL || FIsNotInContent(plsdnLast) /* this can happen if in nominal
  572. to ideal (dcpMaxContext) we deleted everything
  573. in content, but starting point
  574. of content is already behind right margin */
  575. )
  576. )
  577. {
  578. /* return unsuccessful */
  579. *pfSuccessful = fFalse;
  580. return lserrNone;
  581. }
  582. else
  583. {
  584. plsc->lsstate = LsStateBreaking; /* we now in a stage of breaking */
  585. lserr = BreakGeneralCase(plsc, (fmtres == fmtrStopped), breakrecMaxCurrent,
  586. pbreakrecCurrent, pbreakrecMacCurrent,
  587. &dcpDepend, &cpLimLine, &endr, pfSuccessful);
  588. if (lserr != lserrNone || !*pfSuccessful)
  589. return lserr;
  590. /* because, we work with increased margin we can resolve pending tab only after break */
  591. /* we use here that after breaking decision we set state after break point*/
  592. lserr = HandleTab(plsc);
  593. if (lserr != lserrNone)
  594. return lserr;
  595. return FiniEndLine(plsc, endr, cpLimLine, dcpDepend, plslinfo);
  596. }
  597. }
  598. /* ---------------------------------------------------------------------- */
  599. /* F I N I E N D L I N E */
  600. /*----------------------------------------------------------------------------
  601. %%Function: FiniEndLine
  602. %%Contact: igorzv
  603. Parameters:
  604. plsc - (IN) ptr to line services context
  605. endr - (IN) how the line ended
  606. cpLimLine - (IN) cpLim of a line as a result of breaking,
  607. can be changed in this procedure
  608. dcpDepend - (IN) amount of characters after breaking point
  609. that has participated in breaking decision,
  610. can be changed in this procedure
  611. plsinfo - (OUT) visible line info to fill in
  612. Handles splat, calculates heights, special effects
  613. ----------------------------------------------------------------------------*/
  614. static LSERR FiniEndLine(PLSC plsc, ENDRES endr, LSCP cpLimLine,
  615. LSDCP dcpDepend, LSLINFO* plslinfo)
  616. {
  617. LSLINFO* plslinfoState;
  618. OBJDIM objdim;
  619. LSERR lserr;
  620. PLSLINE plsline;
  621. BOOL fEmpty;
  622. ENDRES endrOld;
  623. Assert(FIsLSC(plsc));
  624. Assert(plslinfo != NULL);
  625. plsline = plsc->plslineCur;
  626. plslinfoState = &(plsline->lslinfo);
  627. endrOld = endr;
  628. if (endr == endrEndPara && plsc->fLimSplat)
  629. {
  630. endr = endrEndParaSection;
  631. cpLimLine++;
  632. }
  633. /* handling splat */
  634. if (endr == endrEndColumn || endr == endrEndSection ||
  635. endr == endrEndParaSection|| endr == endrEndPage)
  636. {
  637. if (plsc->grpfManager & fFmiVisiSplats)
  638. {
  639. switch (endr)
  640. {
  641. case endrEndColumn: plsline->kspl = ksplColumnBreak; break;
  642. case endrEndSection: plsline->kspl = ksplSectionBreak; break;
  643. case endrEndParaSection: plsline->kspl = ksplSectionBreak; break;
  644. case endrEndPage: plsline->kspl = ksplPageBreak; break;
  645. }
  646. }
  647. lserr = FIsSublineEmpty(GetMainSubline(plsc), &fEmpty);
  648. if (lserr != lserrNone)
  649. return lserr;
  650. if (!fEmpty && (plsc->grpfManager & fFmiAllowSplatLine))
  651. {
  652. cpLimLine--;
  653. dcpDepend++;
  654. plsline->kspl = ksplNone;
  655. if (endrOld == endrEndPara)
  656. {
  657. endr = endrEndPara;
  658. }
  659. else
  660. {
  661. endr = endrNormal;
  662. }
  663. }
  664. }
  665. /* Height calculation; */
  666. lserr = GetObjDimSublineCore(GetMainSubline(plsc), &objdim);
  667. if (lserr != lserrNone)
  668. return lserr;
  669. plslinfoState->dvrAscent = objdim.heightsRef.dvAscent;
  670. plslinfoState->dvpAscent = objdim.heightsPres.dvAscent;
  671. plslinfoState->dvrDescent = objdim.heightsRef.dvDescent;
  672. plslinfoState->dvpDescent = objdim.heightsPres.dvDescent;
  673. plslinfoState->dvpMultiLineHeight = objdim.heightsPres.dvMultiLineHeight;
  674. plslinfoState->dvrMultiLineHeight = objdim.heightsRef.dvMultiLineHeight;
  675. /* calculation plslinfoState->EffectsFlags*/
  676. if (plslinfoState->EffectsFlags) /* some run with special effects happend during formating */
  677. {
  678. lserr = GetSpecialEffectsSublineCore(GetMainSubline(plsc),
  679. &plsc->lsiobjcontext, &plslinfoState->EffectsFlags);
  680. if (lserr != lserrNone)
  681. return lserr;
  682. }
  683. return EndFormatting(plsc, endr, cpLimLine, dcpDepend, plslinfo);
  684. }
  685. /* ---------------------------------------------------------------------- */
  686. /* F I N I A U T O */
  687. /*----------------------------------------------------------------------------
  688. %%Function: FiniAuto
  689. %%Contact: igorzv
  690. Parameters:
  691. plsc - (IN) ptr to line services context
  692. fAutonumber - (IN) does this line containes autonimber
  693. fAutoDecimaltab - (IN) does this line containes autodecimal tab
  694. plsfrunMainText - (IN) first run of main text
  695. durAutoDecimalTab- (IN) tab stop for autodecimal tab
  696. pbreakrecPrev - (IN) previous line's break records
  697. breakrecMacPrev - (IN) number of previous line's break records
  698. breakrecMaxCurrent- (IN) size of the array of current line's break records
  699. pbreakrecCurrent- (OUT) current line's break records
  700. pbreakrecMacCurrent-(OUT) actual number of current line's break records
  701. plsinfo - (OUT) visible line info to fill in
  702. pfSuccessful - (OUT) fSuccessful: false means insufficient fetch
  703. Completes CreateLine logic for autonumbering and auto-decimal tab
  704. ----------------------------------------------------------------------------*/
  705. static LSERR FiniAuto(
  706. PLSC plsc,
  707. BOOL fAutonumber,
  708. BOOL fAutoDecimalTab,
  709. PLSFRUN plsfrunMainText,
  710. long durAutoDecimalTab,
  711. const BREAKREC* pbreakrecPrev,
  712. DWORD breakrecMacPrev,
  713. DWORD breakrecMaxCurrent,
  714. BREAKREC* pbreakrecCurrent,
  715. DWORD* pbreakrecMacCurrent,
  716. LSLINFO* plslinfo, BOOL* pfSuccessful)
  717. {
  718. LSERR lserr;
  719. if (plsc->lMarginIncreaseCoefficient == LONG_MIN)
  720. plsc->lMarginIncreaseCoefficient = 1;
  721. if (fAutonumber) /*autonumbering */
  722. {
  723. lserr = FormatAnm(plsc, plsfrunMainText);
  724. if (lserr != lserrNone)
  725. {
  726. return ErrReleasePreFetchedRun(plsc, plsfrunMainText->plsrun, lserr);
  727. }
  728. }
  729. if (fAutoDecimalTab)
  730. {
  731. lserr = InitializeAutoDecTab(plsc, durAutoDecimalTab);
  732. if (lserr != lserrNone)
  733. {
  734. return ErrReleasePreFetchedRun(plsc, plsfrunMainText->plsrun, lserr);
  735. }
  736. }
  737. /* we should release run here, in general procedure we will fetch it again */
  738. if (!plsc->fDontReleaseRuns)
  739. {
  740. lserr = plsc->lscbk.pfnReleaseRun(plsc->pols, plsfrunMainText->plsrun);
  741. if (lserr != lserrNone)
  742. return lserr;
  743. }
  744. return FiniFormatGeneralCase(plsc, pbreakrecPrev,
  745. breakrecMacPrev, breakrecMaxCurrent,
  746. pbreakrecCurrent, pbreakrecMacCurrent, plslinfo, pfSuccessful);
  747. }
  748. /* F I N I C H A N G E A F T E R */
  749. /*----------------------------------------------------------------------------
  750. %%Function: FiniChangeAfter
  751. %%Contact: igorzv
  752. Parameters:
  753. plsc - (IN) ptr to line services context
  754. plsfrun, - (IN) lsfrun of modified first run
  755. pbreakrecPrev - (IN) previous line's break records
  756. breakrecMacPrev - (IN) number of previous line's break records
  757. breakrecMaxCurrent- (IN) size of the array of current line's break records
  758. pbreakrecCurrent- (OUT) current line's break records
  759. pbreakrecMacCurrent-(OUT) actual number of current line's break records
  760. plsinfo - (OUT) visible line info to fill in
  761. pfSuccessful - (OUT) fSuccessful: false means insufficient fetch
  762. Completes CreateLine logic for change after because of hyphenation
  763. ----------------------------------------------------------------------------*/
  764. static LSERR FiniChangeAfter(PLSC plsc, LSFRUN* plsfrun, const BREAKREC* pbreakrecPrev,
  765. DWORD breakrecMacPrev,
  766. DWORD breakrecMaxCurrent,
  767. BREAKREC* pbreakrecCurrent,
  768. DWORD* pbreakrecMacCurrent,
  769. LSLINFO* plslinfo, BOOL* pfSuccessful)
  770. {
  771. LSERR lserr;
  772. FMTRES fmtres;
  773. lserr = ProcessOneRun(plsc, plsc->urRightMarginBreak, plsfrun, NULL, 0, &fmtres);
  774. if (lserr != lserrNone)
  775. return lserr;
  776. return FiniFormatGeneralCase(plsc, pbreakrecPrev,
  777. breakrecMacPrev, breakrecMaxCurrent,
  778. pbreakrecCurrent, pbreakrecMacCurrent, plslinfo, pfSuccessful);
  779. }
  780. /* ---------------------------------------------------------------------- */
  781. /* E N D F O R M A T T I N G*/
  782. /*----------------------------------------------------------------------------
  783. %%Function: EndFormatting
  784. %%Contact: igorzv
  785. Parameters:
  786. plsc - (IN) ptr to line services context
  787. endres - (IN) how line ends
  788. cpLimLine - (IN) cpLim of a line as a result of breaking,
  789. can be changed in this procedure
  790. dcpDepend - (IN) amount of characters after breaking point
  791. that has participated in breaking decision,
  792. can be changed in this procedure
  793. plsinfo - (OUT) visible line info to fill in
  794. Filles in lslinfo
  795. ----------------------------------------------------------------------------*/
  796. static LSERR EndFormatting (PLSC plsc, enum endres endr,
  797. LSCP cpLimLine, LSDCP dcpDepend, LSLINFO* plslinfo)
  798. {
  799. PLSLINE plsline = plsc->plslineCur;
  800. LSLINFO* plslinfoContext = &(plsline->lslinfo);
  801. Assert(FIsLSC(plsc));
  802. Assert(plslinfo != NULL);
  803. plslinfoContext->cpLim = cpLimLine;
  804. plslinfoContext->dcpDepend = dcpDepend;
  805. plslinfoContext->endr = endr;
  806. *plslinfo = *plslinfoContext;
  807. plsc->lsstate = LsStateFree; /* we always return through this procedure (in a case of success )
  808. so we free context here */
  809. return lserrNone;
  810. }
  811. /*----------------------------------------------------------------------------
  812. /* L S M O D I F Y L I N E H E I G H T */
  813. /*----------------------------------------------------------------------------
  814. %%Function: LsModifyLineHeight
  815. %%Contact: igorzv
  816. Parameters:
  817. plsc - (IN) ptr to line services context
  818. psline - (IN) ptr to a line to be modified
  819. dvpAbove - (IN) dvpAbove to set in plsline
  820. dvpAscent - (IN) dvpAscent to set in plsline
  821. dvpDescent - (IN) dvpDescent to set in plsline
  822. dvpBelow - (IN) dvpBelow to set in plsline
  823. An exported LineServices API.
  824. Modifies heights in a plsline structure
  825. ----------------------------------------------------------------------------*/
  826. LSERR WINAPI LsModifyLineHeight(PLSC plsc,
  827. PLSLINE plsline,
  828. long dvpAbove,
  829. long dvpAscent,
  830. long dvpDescent,
  831. long dvpBelow)
  832. {
  833. if (!FIsLSC(plsc))
  834. return lserrInvalidContext;
  835. if (!FIsLSLINE(plsline))
  836. return lserrInvalidLine;
  837. if (plsline->lssubl.plsc != plsc)
  838. return lserrMismatchLineContext;
  839. if (plsc->lsstate != LsStateFree)
  840. return lserrContextInUse;
  841. plsline->dvpAbove = dvpAbove;
  842. plsline->lslinfo.dvpAscent = dvpAscent;
  843. plsline->lslinfo.dvpDescent = dvpDescent;
  844. plsline->dvpBelow = dvpBelow;
  845. return lserrNone;
  846. }
  847. /*----------------------------------------------------------------------------
  848. /* L S D E S T R O Y L I N E */
  849. /*----------------------------------------------------------------------------
  850. %%Function: LsDestroyLine
  851. %%Contact: igorzv
  852. Parameters:
  853. plsc - (IN) ptr to line services context
  854. psline - (IN) ptr to a line to be deleted
  855. An exported LineServices API.
  856. Removed plsline structure , dnode list, line objects structures
  857. ----------------------------------------------------------------------------*/
  858. LSERR WINAPI LsDestroyLine(PLSC plsc, /* IN: ptr to line services context */
  859. PLSLINE plsline) /* IN: ptr to line -- opaque to client */
  860. {
  861. POLS pols;
  862. LSERR lserrNew, lserr = lserrNone;
  863. if (!FIsLSC(plsc))
  864. return lserrInvalidContext;
  865. if (!FIsLSLINE(plsline))
  866. return lserrInvalidLine;
  867. if (plsline->lssubl.plsc != plsc)
  868. return lserrMismatchLineContext;
  869. if (plsc->lsstate != LsStateFree)
  870. return lserrContextInUse;
  871. Assert(FIsLsContextValid(plsc));
  872. Assert(plsc->cLinesActive > 0);
  873. plsc->lsstate = LsStateDestroyingLine;
  874. pols = plsc->pols;
  875. /* optimization */
  876. /* we use here that text doesn't have pinfosubl and DestroyDobj is actually empty for text */
  877. if (!plsc->fDontReleaseRuns || !plsline->fAllSimpleText)
  878. {
  879. lserrNew = DestroyDnodeList(&plsc->lscbk, plsc->pols, &plsc->lsiobjcontext,
  880. plsline->lssubl.plsdnFirst, plsc->fDontReleaseRuns);
  881. if (lserrNew != lserrNone && lserr == lserrNone)
  882. lserr = lserrNew;
  883. }
  884. if (plsline == plsc->plslineCur)
  885. plsc->plslineCur = NULL;
  886. lserrNew = RemoveLineObjects(plsline);
  887. if (lserrNew != lserrNone && lserr == lserrNone)
  888. lserr = lserrNew;
  889. /* flush heap of dnodes */
  890. if (plsline->pqhAllDNodes != NULL)
  891. FlushQuickHeap(plsline->pqhAllDNodes);
  892. if (plsc->pqhAllDNodesRecycled != NULL)
  893. DestroyQuickHeap(plsc->pqhAllDNodesRecycled);
  894. /* recycle quick heap of dnodes */
  895. plsc->pqhAllDNodesRecycled = plsline->pqhAllDNodes;
  896. plsline->tag = tagInvalid;
  897. DisposeQuickPv(plsc->pqhLines, plsline,
  898. cbRep(struct lsline, rgplnobj, plsc->lsiobjcontext.iobjMac));
  899. plsc->cLinesActive -= 1;
  900. plsc->lsstate = LsStateFree;
  901. return lserr;
  902. }
  903. /* ---------------------------------------------------------------------- */
  904. /* L S G E T L I N E D U R */
  905. /*----------------------------------------------------------------------------
  906. %%Function: LsGetLineDur
  907. %%Contact: igorzv
  908. Parameters:
  909. plsc - (IN) LS context
  910. plsline - (IN) ptr to a line
  911. pdurInclTrail - (OUT) dur of line incl. trailing area
  912. pdurExclTrail - (OUT) dur of line excl. trailing area
  913. ----------------------------------------------------------------------------*/
  914. LSERR WINAPI LsGetLineDur (PLSC plsc, PLSLINE plsline,
  915. long* pdurInclTrail, long* pdurExclTrail)
  916. {
  917. LSERR lserr;
  918. if (!FIsLSC(plsc))
  919. return lserrInvalidContext;
  920. if (!FIsLSLINE(plsline))
  921. return lserrInvalidLine;
  922. if (plsline->lssubl.plsc != plsc)
  923. return lserrMismatchLineContext;
  924. if (plsc->lsstate != LsStateFree)
  925. return lserrContextInUse;
  926. Assert(FIsLsContextValid(plsc));
  927. Assert(plsc->cLinesActive > 0);
  928. /* check that the line is active */
  929. if (plsline != plsc->plslineCur)
  930. return lserrLineIsNotActive;
  931. /* set breaking state */
  932. plsc->lsstate = LsStateBreaking;
  933. lserr = GetLineDurCore(plsc, pdurInclTrail, pdurExclTrail);
  934. plsc->lsstate = LsStateFree;
  935. return lserr;
  936. }
  937. /* ---------------------------------------------------------------------- */
  938. /* L S G E T M I N D U R B R E A K S */
  939. /*----------------------------------------------------------------------------
  940. %%Function: LsGetMinDurBreaks
  941. %%Contact: igorzv
  942. Parameters:
  943. plsc - (IN) LS context
  944. plsline - (IN) ptr to a line
  945. pdurMinInclTrail - (OUT) min dur between breaks including trailing area
  946. pdurMinExclTrail - (OUT) min dur between breaks excluding trailing area
  947. ----------------------------------------------------------------------------*/
  948. LSERR WINAPI LsGetMinDurBreaks (PLSC plsc, PLSLINE plsline,
  949. long* pdurMinInclTrail, long* pdurMinExclTrail)
  950. {
  951. LSERR lserr;
  952. if (!FIsLSC(plsc))
  953. return lserrInvalidContext;
  954. if (!FIsLSLINE(plsline))
  955. return lserrInvalidLine;
  956. if (plsline->lssubl.plsc != plsc)
  957. return lserrMismatchLineContext;
  958. if (plsc->lsstate != LsStateFree)
  959. return lserrContextInUse;
  960. Assert(FIsLsContextValid(plsc));
  961. Assert(plsc->cLinesActive > 0);
  962. /* check that the line is active */
  963. if (plsline != plsc->plslineCur)
  964. return lserrLineIsNotActive;
  965. /* set breaking state */
  966. plsc->lsstate = LsStateBreaking;
  967. lserr = GetMinDurBreaksCore(plsc, pdurMinInclTrail, pdurMinExclTrail);
  968. plsc->lsstate = LsStateFree;
  969. return lserr;
  970. }
  971. /*----------------------------------------------------------------------*/
  972. #define grpfTextMask ( \
  973. fFmiVisiCondHyphens | \
  974. fFmiVisiParaMarks | \
  975. fFmiVisiSpaces | \
  976. fFmiVisiTabs | \
  977. fFmiVisiBreaks | \
  978. fFmiDoHyphenation | \
  979. fFmiWrapTrailingSpaces | \
  980. fFmiWrapAllSpaces | \
  981. fFmiPunctStartLine | \
  982. fFmiHangingPunct | \
  983. fFmiApplyBreakingRules | \
  984. fFmiFCheckTruncateBefore | \
  985. fFmiDrawInCharCodes | \
  986. fFmiSpacesInfluenceHeight | \
  987. fFmiIndentChangesHyphenZone | \
  988. fFmiNoPunctAfterAutoNumber | \
  989. fFmiTreatHyphenAsRegular \
  990. )
  991. /*----------------------------------------------------------------------------*/
  992. /* I N I T T E X T P A R A M S */
  993. /*----------------------------------------------------------------------------
  994. %%Function: InitTextParams
  995. %%Contact: igorzv
  996. Parameters:
  997. plsc - (IN) ptr to line services context
  998. cp, - (IN) cp to start fetch
  999. duaCol - (IN) duaColumn
  1000. plsfrun - (IN) lsfrun of the first run
  1001. plschp - (OUT) lsfrun of the first run
  1002. plgeom - (OUT) set of flags and parameters about a line
  1003. LsCreateLine calls this function at the beginning of the line in order
  1004. to skip over vanished text, fetch an LSPAP, and invoke the text APIs
  1005. SetTextLineParams().
  1006. ----------------------------------------------------------------------------*/
  1007. static LSERR InitTextParams(PLSC plsc, LSCP cp, long duaCol,
  1008. LSFRUN* plsfrun, PLSCHP plschp, LINEGEOMETRY* plgeom)
  1009. {
  1010. LSERR lserr;
  1011. LSPAP lspap;
  1012. POLS pols = plsc->pols;
  1013. BOOL fFirstLineInPara;
  1014. BOOL fHidden;
  1015. BOOL fStopped = fFalse;
  1016. BOOL fNoLinesParaBefore;
  1017. BOOL fNewPara;
  1018. plsfrun->lpwchRun = NULL;
  1019. plsfrun->plsrun = NULL;
  1020. plsfrun->cwchRun = 0;
  1021. plgeom->fYsrChangeAfter = fFalse;
  1022. Assert(cp >= 0);
  1023. lserr = plsc->lscbk.pfnFetchPap(pols, cp, &lspap);
  1024. if (lserr != lserrNone)
  1025. return lserr;
  1026. if (FPapInconsistent(&lspap))
  1027. return lserrInvalidPap;
  1028. /* N.B. lspap.cpFirstContent may be negative, which indicates
  1029. * "no content in this paragraph".
  1030. */
  1031. fNoLinesParaBefore = lspap.cpFirstContent < 0 || cp <= lspap.cpFirstContent;
  1032. if (!fNoLinesParaBefore && (lspap.grpf & fFmiDoHyphenation))
  1033. {
  1034. lserr = GetYsrChangeAfterRun(plsc, cp, &plgeom->fYsrChangeAfter, plsfrun, plschp, plgeom);
  1035. if (lserr != lserrNone)
  1036. return lserr;
  1037. if (plgeom->fYsrChangeAfter)
  1038. {
  1039. fFirstLineInPara = fFalse;
  1040. fStopped = fFalse;
  1041. lserr = FillTextParams(plsc, cp, duaCol, &lspap, fFirstLineInPara,
  1042. fStopped, plgeom);
  1043. if (lserr != lserrNone)
  1044. return ErrReleasePreFetchedRun(plsc, plsfrun->plsrun, lserr);
  1045. else
  1046. return lserrNone;
  1047. }
  1048. }
  1049. lserr = plsc->lscbk.pfnFetchRun(pols, cp,&plsfrun->lpwchRun, &plsfrun->cwchRun,
  1050. &fHidden, plschp, &plsfrun->plsrun);
  1051. if (lserr != lserrNone)
  1052. return lserr;
  1053. if (fHidden) /* vanished text */
  1054. {
  1055. lserr = FetchUntilVisible(plsc, &lspap, &cp, plsfrun, plschp,
  1056. &fStopped, &fNewPara);
  1057. if (lserr != lserrNone)
  1058. return lserr;
  1059. if (fNewPara)
  1060. fNoLinesParaBefore = fTrue;
  1061. }
  1062. fFirstLineInPara = fNoLinesParaBefore && FBetween(lspap.cpFirstContent, 0, cp);
  1063. lserr = FillTextParams(plsc, cp, duaCol, &lspap, fFirstLineInPara,
  1064. fStopped, plgeom);
  1065. if (lserr != lserrNone)
  1066. return ErrReleasePreFetchedRun(plsc, plsfrun->plsrun, lserr);
  1067. else
  1068. return lserrNone;
  1069. }
  1070. /*----------------------------------------------------------------------------*/
  1071. /* G E T Y S R C H A N G E A F T E R R U N */
  1072. /*----------------------------------------------------------------------------
  1073. %%Function: GetYsrChangeAfterRun
  1074. %%Contact: igorzv
  1075. Parameters:
  1076. plsc - (IN) ptr to line services context
  1077. cp, - (IN) cp to start fetch
  1078. pfYsrChangeAfter (OUT) is it hyphenation of the previous line
  1079. plsfrun, (OUT) lsfrun of modified first run
  1080. plschp (OUT) lschp of modified first run
  1081. plsgeom (OUT) to put wchYsr
  1082. InitTextParams calls this procedure if there is a possibility
  1083. for previous line to be hyphenated.
  1084. If previous line has been hyphenated with ysr change after procedure returns
  1085. modified first run for a line
  1086. ----------------------------------------------------------------------------*/
  1087. static LSERR GetYsrChangeAfterRun(PLSC plsc, LSCP cp, BOOL* pfYsrChangeAfter,
  1088. PLSFRUN plsfrun, PLSCHP plschp, LINEGEOMETRY* plgeom)
  1089. {
  1090. LSFRUN lsfrunPrev;
  1091. LSCHP lschpPrev;
  1092. BOOL fHidden;
  1093. LSERR lserr;
  1094. lsfrunPrev.plschp = &lschpPrev;
  1095. *pfYsrChangeAfter = fFalse;
  1096. /* Fetch run at cp-1 to handle ysrChangeAfter from previous line.
  1097. */
  1098. lserr = plsc->lscbk.pfnFetchRun(plsc->pols, cp-1, &lsfrunPrev.lpwchRun,
  1099. &lsfrunPrev.cwchRun, &fHidden,
  1100. &lschpPrev, &lsfrunPrev.plsrun);
  1101. if (lserr != lserrNone)
  1102. return lserr;
  1103. /* previous run is hyphenated text */
  1104. if (!fHidden && ((lsfrunPrev.plschp)->idObj == idObjTextChp)
  1105. && (lsfrunPrev.plschp)->fHyphen)
  1106. {
  1107. DWORD kysr;
  1108. WCHAR wchYsr;
  1109. Assert(lsfrunPrev.cwchRun == 1);
  1110. lserr = plsc->lscbk.pfnGetHyphenInfo(plsc->pols, lsfrunPrev.plsrun, &kysr, &wchYsr);
  1111. if (lserr != lserrNone)
  1112. return ErrReleasePreFetchedRun(plsc, lsfrunPrev.plsrun, lserr);
  1113. if ((kysr == kysrChangeAfter) &&
  1114. (wchYsr != 0))
  1115. {
  1116. lserr = plsc->lscbk.pfnFetchRun(plsc->pols, cp, &plsfrun->lpwchRun,
  1117. &plsfrun->cwchRun, &fHidden,
  1118. plschp, &plsfrun->plsrun);
  1119. if (lserr != lserrNone)
  1120. return ErrReleasePreFetchedRun(plsc, lsfrunPrev.plsrun, lserr);
  1121. if (!fHidden)
  1122. {
  1123. Assert((plsfrun->plschp)->idObj == idObjTextChp);
  1124. plgeom->wchYsr = wchYsr;
  1125. /* Synthesize a 1-byte run */
  1126. plsfrun->lpwchRun = &plgeom->wchYsr; /* here is the only reason to keep wchrChar in lgeom
  1127. we cann't use local memory to keep it */
  1128. plsfrun->cwchRun = 1;
  1129. plschp->fHyphen = kysrNil;
  1130. *pfYsrChangeAfter = fTrue;
  1131. }
  1132. else
  1133. {
  1134. if (!plsc->fDontReleaseRuns)
  1135. {
  1136. lserr = plsc->lscbk.pfnReleaseRun(plsc->pols, plsfrun->plsrun);
  1137. if (lserr != lserrNone)
  1138. return ErrReleasePreFetchedRun(plsc, lsfrunPrev.plsrun, lserr);
  1139. }
  1140. }
  1141. }
  1142. }
  1143. /* Release run from previous line */
  1144. if (!plsc->fDontReleaseRuns)
  1145. {
  1146. lserr = plsc->lscbk.pfnReleaseRun(plsc->pols, lsfrunPrev.plsrun);
  1147. if (lserr != lserrNone)
  1148. return ErrReleasePreFetchedRun(plsc, plsfrun->plsrun, lserr);
  1149. }
  1150. return lserrNone;
  1151. }
  1152. /*----------------------------------------------------------------------------*/
  1153. /* F I L L T E X T P A R A M S */
  1154. /*----------------------------------------------------------------------------
  1155. %%Function: FillTextParamsTextParams
  1156. %%Contact: igorzv
  1157. Parameters:
  1158. plsc - (IN) ptr to line services context
  1159. cp, - (IN) cp to start fetch
  1160. duaCol - (IN) duaColumn
  1161. plspap - (IN) paragraph properties
  1162. fFirstLineInPara- (IN) flag fFirstLineInPara
  1163. fStopped - (IN) flag fStopped
  1164. plgeom - (OUT) set of flags and parameters about a line
  1165. LsCreateLine calls this function at the beginning of the line in order
  1166. to skip over vanished text, fetch an LSPAP, and invoke the text APIs
  1167. SetTextLineParams().
  1168. ----------------------------------------------------------------------------*/
  1169. static LSERR FillTextParams(PLSC plsc, LSCP cp, long duaCol, PLSPAP plspap,
  1170. BOOL fFirstLineInPara, BOOL fStopped, LINEGEOMETRY* plgeom)
  1171. {
  1172. LSERR lserr;
  1173. TLPR tlpr;
  1174. DWORD iobjText;
  1175. PILSOBJ pilsobjText;
  1176. PLNOBJ plnobjText;
  1177. long uaLeft;
  1178. PLSLINE plsline = plsc->plslineCur;
  1179. long duaColumnMaxBreak;
  1180. long duaColumnMaxJustify;
  1181. long urLeft;
  1182. /* Copy information from lspap to context current line and local for LsCreateLine structure lgeom */
  1183. uaLeft = plspap->uaLeft;
  1184. if (fFirstLineInPara)
  1185. uaLeft += plspap->duaIndent;
  1186. urLeft = UrFromUa(LstflowFromSubline(GetMainSubline(plsc)),
  1187. &plsc->lsdocinf.lsdevres, uaLeft);
  1188. /* line */
  1189. plsline->lslinfo.fFirstLineInPara = fFirstLineInPara;
  1190. plsline->lslinfo.cpFirstVis = cp;
  1191. plsline->lssubl.lstflow = plspap->lstflow;
  1192. if (duaCol != uLsInfiniteRM && plspap->uaRightBreak < uLsInfiniteRM
  1193. && plspap->uaRightJustify < uLsInfiniteRM)
  1194. {
  1195. duaColumnMaxBreak = duaCol - plspap->uaRightBreak;
  1196. duaColumnMaxJustify = duaCol - plspap->uaRightJustify;
  1197. }
  1198. else{
  1199. if (duaCol == uLsInfiniteRM)
  1200. {
  1201. duaColumnMaxBreak = uLsInfiniteRM;
  1202. duaColumnMaxJustify = uLsInfiniteRM;
  1203. }
  1204. else
  1205. {
  1206. if (plspap->uaRightBreak >= uLsInfiniteRM)
  1207. duaColumnMaxBreak = uLsInfiniteRM;
  1208. else
  1209. duaColumnMaxBreak = duaCol - plspap->uaRightBreak;
  1210. if (plspap->uaRightJustify >= uLsInfiniteRM)
  1211. duaColumnMaxJustify = uLsInfiniteRM;
  1212. else
  1213. duaColumnMaxJustify = duaCol - plspap->uaRightJustify;
  1214. }
  1215. }
  1216. /* fill in context for adjustment */
  1217. SetLineLineContainsAutoNumber(plsc, (plspap->grpf & fFmiAnm) && fFirstLineInPara);
  1218. SetUnderlineTrailSpacesRM(plsc, plspap->grpf & fFmiUnderlineTrailSpacesRM);
  1219. SetForgetLastTabAlignment(plsc, plspap->grpf & fFmiForgetLastTabAlignment);
  1220. plsc->lsadjustcontext.lskj = plspap->lskj;
  1221. plsc->lsadjustcontext.lskalign = plspap->lskal;
  1222. plsc->lsadjustcontext.lsbrj = plspap->lsbrj;
  1223. plsc->lsadjustcontext.urLeftIndent = urLeft;
  1224. plsc->lsadjustcontext.urStartAutonumberingText =0;
  1225. plsc->lsadjustcontext.urStartMainText = urLeft; /* autonumber can change it later */
  1226. if (duaColumnMaxJustify != uLsInfiniteRM)
  1227. {
  1228. plsc->lsadjustcontext.urRightMarginJustify = UrFromUa(
  1229. LstflowFromSubline(GetMainSubline(plsc)),
  1230. &(plsc->lsdocinf.lsdevres), duaColumnMaxJustify);
  1231. }
  1232. else
  1233. {
  1234. plsc->lsadjustcontext.urRightMarginJustify = uLsInfiniteRM;
  1235. }
  1236. if (duaColumnMaxBreak != uLsInfiniteRM)
  1237. {
  1238. plsc->urRightMarginBreak = UrFromUa(LstflowFromSubline(GetMainSubline(plsc)),
  1239. &(plsc->lsdocinf.lsdevres), duaColumnMaxBreak);
  1240. }
  1241. else
  1242. {
  1243. plsc->urRightMarginBreak = uLsInfiniteRM;
  1244. }
  1245. plsc->fIgnoreSplatBreak = plspap->grpf & fFmiIgnoreSplatBreak;
  1246. plsc->grpfManager = plspap->grpf;
  1247. plsc->fLimSplat = plspap->grpf & fFmiLimSplat;
  1248. plsc->urHangingTab = UrFromUa(LstflowFromSubline(GetMainSubline(plsc)),
  1249. &(plsc->lsdocinf.lsdevres), plspap->uaLeft);
  1250. /* snap grid */
  1251. if (plspap->lskj == lskjSnapGrid)
  1252. {
  1253. if (duaCol != uLsInfiniteRM)
  1254. {
  1255. plsc->lsgridcontext.urColumn = UrFromUa(
  1256. LstflowFromSubline(GetMainSubline(plsc)),
  1257. &(plsc->lsdocinf.lsdevres), duaCol);
  1258. }
  1259. else
  1260. {
  1261. plsc->lsgridcontext.urColumn = uLsInfiniteRM;
  1262. }
  1263. }
  1264. /* lgeom */
  1265. plgeom->cpFirstVis = cp;
  1266. plgeom->urLeft = urLeft;
  1267. plgeom->fAutonumber = (plspap->grpf & fFmiAnm) && fFirstLineInPara;
  1268. if (plspap->grpf & fFmiAutoDecimalTab)
  1269. {
  1270. plgeom->fAutoDecimalTab = fTrue;
  1271. plgeom->durAutoDecimalTab = UrFromUa(LstflowFromSubline(GetMainSubline(plsc)),
  1272. &(plsc->lsdocinf.lsdevres), plspap->duaAutoDecimalTab);
  1273. }
  1274. else
  1275. {
  1276. plgeom->fAutoDecimalTab = fFalse;
  1277. plgeom->durAutoDecimalTab = LONG_MIN;
  1278. }
  1279. plgeom->fStopped = fStopped;
  1280. /* prepare tlpr for text */
  1281. tlpr.grpfText = (plspap->grpf & grpfTextMask);
  1282. tlpr.fSnapGrid = (plspap->lskj == lskjSnapGrid);
  1283. tlpr.duaHyphenationZone = plspap->duaHyphenationZone;
  1284. tlpr.lskeop = plspap->lskeop;
  1285. /* we know that here is the first place we need plnobjText and we are creating it */
  1286. iobjText = IobjTextFromLsc(&(plsc->lsiobjcontext));
  1287. Assert( PlnobjFromLsline(plsline,iobjText) == NULL);
  1288. pilsobjText = PilsobjFromLsc(&(plsc->lsiobjcontext), iobjText);
  1289. lserr = CreateLNObjText(pilsobjText, &(plsline->rgplnobj[iobjText]));
  1290. if (lserr != lserrNone)
  1291. return lserr;
  1292. plnobjText = PlnobjFromLsline(plsline, iobjText);
  1293. lserr = SetTextLineParams(plnobjText, &tlpr);
  1294. if (lserr != lserrNone)
  1295. return lserr;
  1296. return lserrNone;
  1297. }
  1298. /*----------------------------------------------------------------------------
  1299. /* F E T C H U N T I L V I S I B L E */
  1300. /*----------------------------------------------------------------------------
  1301. %%Function: FetchUntilVisible
  1302. %%Contact: igorzv
  1303. Parameters:
  1304. plsc - (IN) ptr to line services context
  1305. plspap - (IN/OUT) current lspap before and after
  1306. pcp - (IN/OUT) current cp before and after
  1307. plsfrun - (IN/OUT) current lsfrun before and after
  1308. plschp - (IN/OUT) current lschp before and after
  1309. pfStopped - (OUT) fStopped: procedure stopped fetching because has not been allowed
  1310. to go across paragraph boundaries (result CheckPara Boundaries)
  1311. pfNewPara - (OUT) fNewPara: procedure crossed paragraph boundaries
  1312. Releases the supplied PLSRUN, if any, and fetches runs, starting at
  1313. the supplied cp, until a non-vanished run is fetched. As paragraph
  1314. boundaries are crossed, the LSPAP is updated.
  1315. ----------------------------------------------------------------------------*/
  1316. static LSERR FetchUntilVisible(PLSC plsc, LSPAP* plspap, LSCP* pcp,
  1317. LSFRUN* plsfrun, PLSCHP plschp,
  1318. BOOL* pfStopped, BOOL* pfNewPara)
  1319. {
  1320. LSERR lserr;
  1321. LSCP dcpPrevRun = plsfrun->cwchRun;
  1322. BOOL fHidden;
  1323. *pfStopped = fFalse;
  1324. *pfNewPara = fFalse;
  1325. /* we assume here that this finction is called only after hidden run has been fetched
  1326. and such run is passed as an input parameter */
  1327. do
  1328. {
  1329. const PLSRUN plsrunT = plsfrun->plsrun;
  1330. *pcp += dcpPrevRun;
  1331. lserr = plsc->lscbk.pfnCheckParaBoundaries(plsc->pols, *pcp - dcpPrevRun, *pcp, pfStopped);
  1332. if (lserr != lserrNone)
  1333. return ErrReleasePreFetchedRun(plsc, plsrunT, lserr);
  1334. if (*pfStopped)
  1335. return lserrNone;
  1336. lserr = plsc->lscbk.pfnFetchPap(plsc->pols, *pcp, plspap);
  1337. if (lserr != lserrNone)
  1338. return ErrReleasePreFetchedRun(plsc, plsrunT, lserr);
  1339. if (FPapInconsistent(plspap))
  1340. return ErrReleasePreFetchedRun(plsc, plsrunT, lserrInvalidPap);
  1341. if ((*pcp - dcpPrevRun) < plspap->cpFirst)
  1342. *pfNewPara = fTrue;
  1343. plsfrun->plsrun = NULL;
  1344. if (plsrunT != NULL && !plsc->fDontReleaseRuns)
  1345. {
  1346. lserr = plsc->lscbk.pfnReleaseRun(plsc->pols, plsrunT);
  1347. if (lserr != lserrNone)
  1348. return lserr;
  1349. }
  1350. lserr = plsc->lscbk.pfnFetchRun(plsc->pols, *pcp,
  1351. &plsfrun->lpwchRun,
  1352. &plsfrun->cwchRun,
  1353. &fHidden,
  1354. plschp,
  1355. &plsfrun->plsrun);
  1356. if (lserr != lserrNone)
  1357. return lserr;
  1358. dcpPrevRun = plsfrun->cwchRun;
  1359. }
  1360. while (fHidden);
  1361. return lserrNone;
  1362. }
  1363. /* I N I T C U R L I N E */
  1364. /*----------------------------------------------------------------------------
  1365. %%Function: InitCurLine
  1366. %%Contact: igorzv
  1367. Parameters:
  1368. plsc - (IN) ptr to line services context
  1369. cpFirst - (IN) starting cp for a line
  1370. Set default value in lsline
  1371. ----------------------------------------------------------------------------*/
  1372. static LSERR InitCurLine(PLSC plsc, LSCP cpFirst)
  1373. {
  1374. PLSLINE plsline = plsc->plslineCur;
  1375. memset(plsline, 0, cbRep(struct lsline, rgplnobj, plsc->lsiobjcontext.iobjMac));
  1376. plsline->tag = tagLSLINE;
  1377. plsline->lssubl.tag = tagLSSUBL;
  1378. plsline->lssubl.plsc = plsc;
  1379. plsline->lssubl.cpFirst = cpFirst;
  1380. /* reuse quick heap for dnodes if it possible */
  1381. if (plsc->pqhAllDNodesRecycled != NULL)
  1382. {
  1383. plsline->pqhAllDNodes = plsc->pqhAllDNodesRecycled;
  1384. plsc->pqhAllDNodesRecycled = NULL;
  1385. }
  1386. else
  1387. {
  1388. plsline->pqhAllDNodes = CreateQuickHeap(plsc, limAllDNodes,
  1389. sizeof (struct lsdnode), fTrue);
  1390. if (plsline->pqhAllDNodes == NULL )
  1391. return lserrOutOfMemory;
  1392. }
  1393. plsline->lssubl.fDupInvalid = fTrue;
  1394. plsline->lssubl.fContiguous = fTrue;
  1395. plsline->lssubl.plschunkcontext = &(plsc->lschunkcontextStorage);
  1396. plsline->lssubl.fMain = fTrue;
  1397. TurnOnAllSimpleText(plsc);
  1398. plsline->lslinfo.nDepthFormatLineMax = 1;
  1399. TurnOffLineCompressed(plsc);
  1400. TurnOffNominalToIdealEncounted(plsc);
  1401. TurnOffForeignObjectEncounted(plsc);
  1402. TurnOffTabEncounted(plsc);
  1403. TurnOffNonLeftTabEncounted(plsc);
  1404. TurnOffSubmittedSublineEncounted(plsc);
  1405. TurnOffAutodecimalTabPresent(plsc);
  1406. plsc->fHyphenated = fFalse;
  1407. plsc->fAdvanceBack = fFalse;
  1408. /* we use memset to set default value, below we check that after memset we really have
  1409. correct defaults */
  1410. Assert(plsline->lssubl.plsdnFirst == NULL);
  1411. Assert(plsline->lssubl.urColumnMax == 0);
  1412. Assert(plsline->lssubl.cpLim == 0);
  1413. Assert(plsline->lssubl.plsdnLast == NULL);
  1414. Assert(plsline->lssubl.urCur == 0);
  1415. Assert(plsline->lssubl.vrCur == 0);
  1416. Assert(plsline->lssubl.fAcceptedForDisplay == fFalse);
  1417. Assert(plsline->lssubl.fRightMarginExceeded == fFalse);
  1418. Assert(plsline->lssubl.plsdnUpTemp == NULL);
  1419. Assert(plsline->lssubl.pbrkcontext == NULL);
  1420. Assert(plsline->lslinfo.dvpAscent == 0); /* lslinfo */
  1421. Assert(plsline->lslinfo.dvrAscent == 0);
  1422. Assert(plsline->lslinfo.dvpDescent == 0);
  1423. Assert(plsline->lslinfo.dvrDescent == 0);
  1424. Assert(plsline->lslinfo.dvpMultiLineHeight == 0);
  1425. Assert(plsline->lslinfo.dvrMultiLineHeight == 0);
  1426. Assert(plsline->lslinfo.dvpAscentAutoNumber == 0);
  1427. Assert(plsline->lslinfo.dvrAscentAutoNumber == 0);
  1428. Assert(plsline->lslinfo.dvpDescentAutoNumber == 0);
  1429. Assert(plsline->lslinfo.dvrDescentAutoNumber == 0);
  1430. Assert(plsline->lslinfo.cpLim == 0);
  1431. Assert(plsline->lslinfo.dcpDepend == 0);
  1432. Assert(plsline->lslinfo.cpFirstVis == 0);
  1433. Assert(plsline->lslinfo.endr == endrNormal);
  1434. Assert(plsline->lslinfo.fAdvanced == fFalse);
  1435. Assert(plsline->lslinfo.vaAdvance == 0);
  1436. Assert(plsline->lslinfo.fFirstLineInPara == fFalse);
  1437. Assert(plsline->lslinfo.EffectsFlags == 0);
  1438. Assert(plsline->lslinfo.fTabInMarginExLine == fFalse);
  1439. Assert(plsline->lslinfo.fForcedBreak == fFalse);
  1440. Assert(plsline->upStartAutonumberingText == 0);
  1441. Assert(plsline->upLimAutonumberingText == 0);
  1442. Assert(plsline->upStartMainText == 0);
  1443. Assert(plsline->upLimLine == 0);
  1444. Assert(plsline->dvpAbove == 0);
  1445. Assert(plsline->dvpBelow == 0);
  1446. Assert(plsline->upRightMarginJustify == 0);
  1447. Assert(plsline->upLimUnderline == 0);
  1448. Assert(plsline->kspl == ksplNone);
  1449. Assert(!plsline->fCollectVisual);
  1450. Assert(!plsline->fNonRealDnodeEncounted);
  1451. Assert(!plsline->fNonZeroDvpPosEncounted);
  1452. Assert(plsline->AggregatedDisplayFlags == 0);
  1453. Assert(plsline->pad == 0);
  1454. #ifdef DEBUG
  1455. {
  1456. DWORD i;
  1457. for (i=0; i < plsc->lsiobjcontext.iobjMac; i++)
  1458. {
  1459. Assert(plsline->rgplnobj[i] == NULL);
  1460. }
  1461. }
  1462. #endif
  1463. return lserrNone;
  1464. }
  1465. /*----------------------------------------------------------------------------
  1466. /* C A N N O T C R E A T E L I N E */
  1467. /*----------------------------------------------------------------------------
  1468. %%Function: CannotCreateLine
  1469. %%Contact: igorzv
  1470. Parameters:
  1471. pplsline - (IN) ponter to a line structure to be deleted
  1472. lserr - (IN) code of an error
  1473. Called when LsCreateLine needs to return for an error condition.
  1474. ----------------------------------------------------------------------------*/
  1475. static LSERR CannotCreateLine(PLSLINE* pplsline, LSERR lserr)
  1476. {
  1477. LSERR lserrIgnore;
  1478. PLSLINE plsline = *pplsline;
  1479. PLSC plsc = plsline->lssubl.plsc;
  1480. plsc->plslineCur = NULL;
  1481. plsc->lsstate = LsStateFree; /* we need free context to destroy line */
  1482. lserrIgnore = LsDestroyLine(plsc, plsline);
  1483. *pplsline = NULL;
  1484. return lserr;
  1485. }
  1486. /*----------------------------------------------------------------------------
  1487. /* E R R R E L E A S E P R E F E T C H E D R U N */
  1488. /*----------------------------------------------------------------------------
  1489. %%Function: ErrReleasePreFetchedRun
  1490. %%Contact: igorzv
  1491. Parameters:
  1492. plsc - (IN) ptr to line services context
  1493. plsrun - (IN) ponter to a run structure to be deleted
  1494. lserr - (IN) code of an error
  1495. Called in a error situation when fist run of main text has been prefetched .
  1496. ----------------------------------------------------------------------------*/
  1497. static LSERR ErrReleasePreFetchedRun(PLSC plsc, PLSRUN plsrun, LSERR lserr)
  1498. {
  1499. LSERR lserrIgnore;
  1500. if (!plsc->fDontReleaseRuns)
  1501. lserrIgnore = plsc->lscbk.pfnReleaseRun(plsc->pols, plsrun);
  1502. return lserr;
  1503. }
  1504. /* R E M O V E L I N E O B J E C T S */
  1505. /*----------------------------------------------------------------------------
  1506. %%Function: RemoveLineObjects
  1507. %%Contact: igorzv
  1508. Parameter:
  1509. plsc - (IN) ponter to a line structure
  1510. Removes a line context of installed objects from an line.
  1511. ----------------------------------------------------------------------------*/
  1512. LSERR RemoveLineObjects(PLSLINE plsline)
  1513. {
  1514. DWORD iobjMac;
  1515. PLSC plsc;
  1516. LSERR lserr, lserrFinal = lserrNone;
  1517. DWORD iobj;
  1518. PLNOBJ plnobj;
  1519. Assert(FIsLSLINE(plsline));
  1520. plsc = plsline->lssubl.plsc;
  1521. Assert(FIsLSC(plsc));
  1522. Assert(plsc->lsstate == LsStateDestroyingLine);
  1523. iobjMac = plsc->lsiobjcontext.iobjMac;
  1524. for (iobj = 0; iobj < iobjMac; iobj++)
  1525. {
  1526. plnobj = plsline->rgplnobj[iobj];
  1527. if (plnobj != NULL)
  1528. {
  1529. lserr = plsc->lsiobjcontext.rgobj[iobj].lsim.pfnDestroyLNObj(plnobj);
  1530. plsline->rgplnobj[iobj] = NULL;
  1531. if (lserr != lserrNone)
  1532. lserrFinal = lserr;
  1533. }
  1534. }
  1535. return lserrFinal;
  1536. }
  1537. #ifdef DEBUG
  1538. /* F R O U N D I N G O K */
  1539. /*----------------------------------------------------------------------------
  1540. %%Function: FRoundingOK
  1541. %%Contact: lenoxb
  1542. Checks for correctness of rounding algorithm in converting absolute to
  1543. device units, to agree with Word 6.0.
  1544. Checks that:
  1545. 0.5 rounds up to 1.0,
  1546. 1.4 rounds down to 1.4,
  1547. -0.5 rounds down to -1.0, and
  1548. -1.4 rounds up to -1.0.
  1549. ----------------------------------------------------------------------------*/
  1550. static BOOL FRoundingOK(void)
  1551. {
  1552. LSDEVRES devresT;
  1553. Assert((czaUnitInch % 10) == 0);
  1554. devresT.dxpInch = czaUnitInch / 10;
  1555. if (UpFromUa(lstflowDefault, &devresT, 5) != 1)
  1556. return fFalse;
  1557. if (UpFromUa(lstflowDefault, &devresT, 14) != 1)
  1558. return fFalse;
  1559. if (UpFromUa(lstflowDefault, &devresT, -5) != -1)
  1560. return fFalse;
  1561. if (UpFromUa(lstflowDefault, &devresT, -14) != -1)
  1562. return fFalse;
  1563. return fTrue;
  1564. }
  1565. #endif /* DEBUG */