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.

1189 lines
36 KiB

  1. #include "lsmem.h"
  2. #include <limits.h>
  3. #include "lstxtfmt.h"
  4. #include "lsstring.h"
  5. #include "lstxtffi.h"
  6. #include "lsdnfin.h"
  7. #include "lsdnfinp.h"
  8. #include "lsdntext.h"
  9. #include "zqfromza.h"
  10. #include "txtobj.h"
  11. #include "lskysr.h"
  12. #include "lschp.h"
  13. #include "fmti.h"
  14. #include "objdim.h"
  15. #include "txtils.h"
  16. #include "txtln.h"
  17. #include "txtobj.h"
  18. #include "txtconst.h"
  19. #define cwchLocalMax 120
  20. /* Internal Functions Prototypes */
  21. static LSERR FormatRegularCharacters(PLNOBJ plnobj, PCFMTIN pfmtin, FMTRES* pfmtr);
  22. static LSERR CreateFillTextDobj(PLNOBJ plnobj, long txtkind, PCFMTIN pfmtin, BOOL fIgnoreGlyphs,
  23. TXTOBJ** ppdobjText);
  24. static LSERR GetTextDobj(PLNOBJ plnobj, TXTOBJ** ppdobjText);
  25. static LSERR FillRealFmtOut(PILSOBJ pilsobj, LSDCP dcp, long dur, TXTOBJ* pdobjText, PCFMTIN pfmtin,
  26. BOOL fIgnoreHeights);
  27. static LSERR AppendTrailingSpaces(PLNOBJ plnobj, TXTOBJ* pdobjText, WCHAR* rgwchGlobal,
  28. long iwchGlobal, long cwchGlobal,
  29. long* iwchGlobalNew, long* pddur);
  30. static LSERR FormatStartEmptyDobj(PLNOBJ plnobj, PCFMTIN pfmtin, long txtkind, DWORD fTxtVisi,
  31. WCHAR wchVisi, FMTRES* pfmtr);
  32. static LSERR FormatStartTab(PLNOBJ plnobj, PCFMTIN pfmtin, FMTRES* pfmtr);
  33. static LSERR FormatStartOneRegularChar(PLNOBJ plnobj, PCFMTIN pfmtin, long txtkind, FMTRES* pfmtr);
  34. static LSERR FormatStartToReplace(PLNOBJ plnobj, PCFMTIN pfmtin, FMTRES* pfmtr);
  35. static LSERR FormatStartEol(PLNOBJ plnobj, PCFMTIN pfmtin, WCHAR wch, STOPRES stopr, FMTRES* pfmtr);
  36. static LSERR FormatStartDelete(PLNOBJ plnobj, LSDCP dcp, FMTRES* pfmtr);
  37. static LSERR FormatStartSplat(PLNOBJ plnobj, PCFMTIN pfmtin, STOPRES stopr, FMTRES* pfmtr);
  38. static LSERR FormatStartBorderedSpaces(PLNOBJ plnobj, PCFMTIN pfmtin, FMTRES* pfmtr);
  39. static LSERR FormatSpecial(PLNOBJ plnobj, WCHAR wchRef, WCHAR wchPres, BOOL fVisible,
  40. long txtkind, PCFMTIN pfmtin, FMTRES* pfmtr);
  41. static STOPRES StoprHardBreak(CLABEL clab);
  42. static CLABEL ClabFromChar(PILSOBJ pilsobj, WCHAR wch);
  43. /* Export Functions Implementation */
  44. /* L S T X T F M T */
  45. /*----------------------------------------------------------------------------
  46. %%Function: LsTxtFmt
  47. %%Contact: sergeyge
  48. The top-level function of the text formatter.
  49. It checks for the first character and state
  50. and redirects the program flow accordingly.
  51. ----------------------------------------------------------------------------*/
  52. LSERR WINAPI FmtText(PLNOBJ plnobj, PCFMTIN pfmtin, FMTRES* pfmtr)
  53. {
  54. LSERR lserr;
  55. PILSOBJ pilsobj;
  56. WCHAR wchFirst;
  57. CLABEL clab;
  58. BOOL fInChildList;
  59. pilsobj = plnobj->pilsobj;
  60. wchFirst = pfmtin->lsfrun.lpwchRun[0];
  61. clab = pilsobj->rgbSwitch[wchFirst & 0x00FF]; /* REVIEW sergeyge */
  62. if (clab != clabRegular)
  63. {
  64. clab = ClabFromChar(pilsobj, wchFirst);
  65. }
  66. /* check for the YSR-character */
  67. if (pfmtin->lsfrun.plschp->fHyphen && clab == clabRegular)
  68. {
  69. return FormatStartOneRegularChar(plnobj, pfmtin, txtkindYsrChar, pfmtr);
  70. }
  71. else
  72. {
  73. switch (clab)
  74. {
  75. case clabRegular:
  76. return FormatRegularCharacters(plnobj, pfmtin, pfmtr);
  77. case clabSpace:
  78. if (pfmtin->lsfrun.plschp->fBorder)
  79. return FormatStartBorderedSpaces(plnobj, pfmtin, pfmtr);
  80. else
  81. return FormatRegularCharacters(plnobj, pfmtin, pfmtr);
  82. case clabEOP1:
  83. switch (pilsobj->lskeop)
  84. {
  85. case lskeopEndPara1:
  86. return FormatStartEol(plnobj, pfmtin, pilsobj->wchVisiEndPara, stoprEndPara, pfmtr);
  87. case lskeopEndPara12:
  88. return FormatStartDelete(plnobj, 1, pfmtr);
  89. default:
  90. return FormatStartOneRegularChar(plnobj, pfmtin, txtkindRegular, pfmtr);
  91. }
  92. case clabEOP2:
  93. switch (pilsobj->lskeop)
  94. {
  95. case lskeopEndPara2:
  96. case lskeopEndPara12:
  97. return FormatStartEol(plnobj, pfmtin, pilsobj->wchVisiEndPara, stoprEndPara, pfmtr);
  98. default:
  99. return FormatStartOneRegularChar(plnobj, pfmtin, txtkindRegular, pfmtr);
  100. }
  101. break;
  102. case clabAltEOP:
  103. switch (pilsobj->lskeop)
  104. {
  105. case lskeopEndParaAlt:
  106. return FormatStartEol(plnobj, pfmtin, pilsobj->wchVisiAltEndPara, stoprAltEndPara, pfmtr);
  107. default:
  108. return FormatStartOneRegularChar(plnobj, pfmtin, txtkindRegular, pfmtr);
  109. }
  110. case clabEndLineInPara:
  111. return FormatStartEol(plnobj, pfmtin, pilsobj->wchVisiEndLineInPara, stoprSoftCR, pfmtr);
  112. case clabTab:
  113. return FormatStartTab(plnobj, pfmtin, pfmtr);
  114. case clabNull:
  115. if (pilsobj->grpf & fTxtVisiSpaces)
  116. return FormatSpecial(plnobj, wchFirst, pilsobj->wchVisiNull, fTrue, txtkindRegular, pfmtin, pfmtr);
  117. else
  118. return FormatSpecial(plnobj, wchFirst, wchFirst, fFalse, txtkindRegular, pfmtin, pfmtr);
  119. case clabNonReqHyphen:
  120. return FormatStartEmptyDobj(plnobj, pfmtin, txtkindNonReqHyphen, fTxtVisiCondHyphens,
  121. pilsobj->wchVisiNonReqHyphen, pfmtr);
  122. case clabNonBreakHyphen:
  123. if (pilsobj->grpf & fTxtVisiCondHyphens)
  124. return FormatSpecial(plnobj, pilsobj->wchHyphen, pilsobj->wchVisiNonBreakHyphen, fTrue, txtkindNonBreakHyphen, pfmtin, pfmtr);
  125. else
  126. return FormatSpecial(plnobj, pilsobj->wchHyphen, pilsobj->wchHyphen, fFalse, txtkindNonBreakHyphen, pfmtin, pfmtr);
  127. case clabNonBreakSpace:
  128. if (pilsobj->grpf & fTxtVisiSpaces)
  129. return FormatSpecial(plnobj, pilsobj->wchSpace, pilsobj->wchVisiNonBreakSpace, fTrue, txtkindNonBreakSpace, pfmtin, pfmtr);
  130. else
  131. return FormatSpecial(plnobj, pilsobj->wchSpace, pilsobj->wchSpace, fFalse, txtkindNonBreakSpace, pfmtin, pfmtr);
  132. case clabHardHyphen:
  133. if (pilsobj->grpf & fTxtTreatHyphenAsRegular)
  134. return FormatSpecial(plnobj, wchFirst, wchFirst, fFalse, txtkindRegular, pfmtin, pfmtr);
  135. else
  136. return FormatSpecial(plnobj, wchFirst, wchFirst, fFalse, txtkindHardHyphen, pfmtin, pfmtr);
  137. case clabSectionBreak:
  138. case clabColumnBreak:
  139. case clabPageBreak:
  140. lserr = LsdnFInChildList(pilsobj->plsc, pfmtin->plsdnTop, &fInChildList);
  141. if (lserr != lserrNone) return lserr;
  142. if (fInChildList)
  143. return FormatStartDelete(plnobj, 1, pfmtr);
  144. else
  145. return FormatStartSplat(plnobj, pfmtin, StoprHardBreak(clab), pfmtr);
  146. case clabEmSpace:
  147. if (pilsobj->grpf & fTxtVisiSpaces)
  148. return FormatSpecial(plnobj, wchFirst, pilsobj->wchVisiEmSpace, fTrue, txtkindSpecSpace, pfmtin, pfmtr);
  149. else
  150. return FormatSpecial(plnobj, wchFirst, wchFirst, fFalse, txtkindSpecSpace, pfmtin, pfmtr);
  151. case clabEnSpace:
  152. if (pilsobj->grpf & fTxtVisiSpaces)
  153. return FormatSpecial(plnobj, wchFirst, pilsobj->wchVisiEnSpace, fTrue, txtkindSpecSpace, pfmtin, pfmtr);
  154. else
  155. return FormatSpecial(plnobj, wchFirst, wchFirst, fFalse, txtkindSpecSpace, pfmtin, pfmtr);
  156. case clabNarrowSpace:
  157. if (pilsobj->grpf & fTxtVisiSpaces)
  158. return FormatSpecial(plnobj, wchFirst, pilsobj->wchVisiNarrowSpace, fTrue, txtkindSpecSpace, pfmtin, pfmtr);
  159. else
  160. return FormatSpecial(plnobj, wchFirst, wchFirst, fFalse, txtkindSpecSpace, pfmtin, pfmtr);
  161. case clabOptBreak:
  162. return FormatStartEmptyDobj(plnobj, pfmtin, txtkindOptBreak, fTxtVisiBreaks,
  163. pilsobj->wchVisiOptBreak, pfmtr);
  164. case clabNonBreak:
  165. return FormatStartEmptyDobj(plnobj, pfmtin, txtkindOptNonBreak, fTxtVisiBreaks,
  166. pilsobj->wchVisiNoBreak, pfmtr);
  167. case clabFESpace:
  168. if (pilsobj->grpf & fTxtVisiSpaces)
  169. return FormatSpecial(plnobj, wchFirst, pilsobj->wchVisiFESpace, fTrue, txtkindSpecSpace, pfmtin, pfmtr);
  170. else
  171. return FormatSpecial(plnobj, wchFirst, wchFirst, fFalse, txtkindSpecSpace, pfmtin, pfmtr);
  172. case clabJoiner:
  173. case clabNonJoiner:
  174. return FormatStartOneRegularChar(plnobj, pfmtin, txtkindRegular, pfmtr);
  175. case clabToReplace: /* backslash in FE Word */
  176. return FormatStartToReplace(plnobj, pfmtin, pfmtr);
  177. }
  178. }
  179. return lserrNone;
  180. }
  181. /* L S D E S T R O Y T X T D O B J*/
  182. /*----------------------------------------------------------------------------
  183. %%Function: LsDestroyTxtDObj
  184. %%Contact: sergeyge
  185. DestroyDObj method of the text handler.
  186. ----------------------------------------------------------------------------*/
  187. LSERR WINAPI DestroyDObjText(PDOBJ pdobj)
  188. {
  189. Unreferenced(pdobj);
  190. return lserrNone;
  191. }
  192. /* L S S U B L I N E F I N I S H E D T E X T */
  193. /*----------------------------------------------------------------------------
  194. %%Function: LsSublineFinishedText
  195. %%Contact: sergeyge
  196. Notification from Manager about finishing the subline
  197. ----------------------------------------------------------------------------*/
  198. LSERR LsSublineFinishedText(PLNOBJ plnobj)
  199. {
  200. Assert(plnobj->pilsobj->wchMac + 2 <= plnobj->pilsobj->wchMax);
  201. return IncreaseWchMacBy2(plnobj);
  202. }
  203. /* Internal Functions Implementation */
  204. /* F O R M A T R E G U L A R C H A R A C T E R S */
  205. /*----------------------------------------------------------------------------
  206. %%Function: FormatRegularCharacters
  207. %%Contact: sergeyge
  208. Formats run starting with the regular character.
  209. Ends as soon as any special character is encountered or
  210. right margin is achieved or
  211. all characters are processed.
  212. ----------------------------------------------------------------------------*/
  213. static LSERR FormatRegularCharacters(PLNOBJ plnobj, PCFMTIN pfmtin, FMTRES* pfmtr)
  214. {
  215. LSERR lserr;
  216. PILSOBJ pilsobj;
  217. long cwchGlobal;
  218. long iwchGlobal;
  219. long iwchLocal;
  220. long cwchLocal;
  221. long iwSpaces;
  222. long cwchMax;
  223. LSCP cpFirst;
  224. long durWidthExceed;
  225. WCHAR* rgwchGlobal;
  226. WCHAR* rgwchLocal;
  227. long rgwSpaces[cwchLocalMax];
  228. TXTOBJ* pdobjText;
  229. long durWidth;
  230. long ddur;
  231. BOOL fTerminateLoops;
  232. long dur;
  233. CLABEL clab;
  234. CLABEL* rgbSwitch;
  235. WCHAR wchSpace;
  236. long iwchGlobalNew;
  237. BOOL fInSpaces = fFalse;
  238. int i;
  239. int idur;
  240. pilsobj = plnobj->pilsobj;
  241. lserr = CreateFillTextDobj(plnobj, txtkindRegular, pfmtin, fFalse, &pdobjText);
  242. if (lserr != lserrNone) return lserr;
  243. rgbSwitch = pilsobj->rgbSwitch;
  244. wchSpace = pilsobj->wchSpace;
  245. rgwchGlobal = (WCHAR*)pfmtin->lsfrun.lpwchRun;
  246. cwchGlobal = (long)pfmtin->lsfrun.cwchRun;
  247. iwchGlobal = 0;
  248. fTerminateLoops = fFalse;
  249. durWidthExceed = pfmtin->lsfgi.urColumnMax - pfmtin->lsfgi.urPen;
  250. cpFirst = pfmtin->lsfgi.cpFirst;
  251. dur = 0;
  252. while (iwchGlobal < cwchGlobal && !fTerminateLoops)
  253. {
  254. rgwchLocal = &rgwchGlobal[iwchGlobal];
  255. cwchMax = cwchGlobal - iwchGlobal;
  256. if (cwchMax > cwchLocalMax)
  257. cwchMax = cwchLocalMax;
  258. lserr = GetWidths(plnobj, pfmtin->lsfrun.plsrun, pdobjText->iwchLim, rgwchLocal,
  259. cpFirst, cwchMax, durWidthExceed, pfmtin->lsfgi.lstflow, &cwchLocal, &durWidth);
  260. if (lserr != lserrNone) return lserr;
  261. iwchLocal = 0;
  262. iwSpaces = 0;
  263. while (iwchLocal < cwchLocal /*&& !fTerminateLoops*/)
  264. {
  265. if (rgbSwitch[rgwchLocal[iwchLocal] & 0x00FF] == clabRegular)
  266. iwchLocal++;
  267. else if (rgwchLocal[iwchLocal] == wchSpace)
  268. {
  269. if (!pfmtin->lsfrun.plschp->fBorder)
  270. {
  271. rgwSpaces[iwSpaces] = iwchLocal;
  272. iwchLocal++;
  273. iwSpaces++;
  274. }
  275. else
  276. {
  277. fTerminateLoops = fTrue;
  278. durWidth = 0;
  279. for (i = 0, idur = pdobjText->iwchLim; i < iwchLocal; i++, idur++)
  280. durWidth += pilsobj->pdur[idur];
  281. break; /* This break is equivalent to the check commented out in the loop condition */
  282. }
  283. }
  284. else
  285. {
  286. clab = ClabFromChar(pilsobj, rgwchLocal[iwchLocal]);
  287. if (clab == clabRegular)
  288. {
  289. iwchLocal++;
  290. }
  291. else
  292. {
  293. /* Terminate loops (and processing of run) for any special character */
  294. fTerminateLoops = fTrue;
  295. durWidth = 0;
  296. for (i = 0, idur = pdobjText->iwchLim; i < iwchLocal; i++, idur++)
  297. durWidth += pilsobj->pdur[idur];
  298. break; /* This break is equivalent to the check commented out in the loop condition */
  299. }
  300. }
  301. }
  302. if (iwchLocal != 0)
  303. {
  304. fInSpaces = fFalse;
  305. lserr = FormatString(plnobj, pdobjText, rgwchLocal, iwchLocal, rgwSpaces, iwSpaces, durWidth);
  306. if (lserr != lserrNone) return lserr;
  307. iwchGlobal += iwchLocal;
  308. durWidthExceed -= durWidth;
  309. Assert(dur < uLsInfiniteRM); /* We can be sure of it because dur is 0 during first iteration,
  310. and we check for uLsInfiniteRM in the TrailingSpaces logic */
  311. Assert(durWidth < uLsInfiniteRM);
  312. dur += durWidth;
  313. cpFirst += iwchLocal;
  314. if (cwchLocal == iwchLocal && durWidthExceed < 0)
  315. {
  316. if (rgwchLocal[cwchLocal-1] == wchSpace)
  317. {
  318. fInSpaces = fTrue;
  319. if (iwchGlobal < cwchGlobal && pilsobj->wchSpace == rgwchGlobal[iwchGlobal])
  320. {
  321. lserr = AppendTrailingSpaces(plnobj, pdobjText, rgwchGlobal,
  322. (DWORD)iwchGlobal, cwchGlobal, &iwchGlobalNew, &ddur);
  323. if (lserr != lserrNone) return lserr;
  324. if (iwchGlobalNew != iwchGlobal)
  325. {
  326. cpFirst += (iwchGlobalNew - iwchGlobal);
  327. iwchGlobal = iwchGlobalNew;
  328. Assert (ddur <= uLsInfiniteRM - dur);
  329. if (ddur > uLsInfiniteRM - dur)
  330. return lserrTooLongParagraph;
  331. dur += ddur;
  332. }
  333. }
  334. }
  335. else
  336. fTerminateLoops = fTrue;
  337. }
  338. } /* if iwchLocal != 0 */
  339. } /* while iwchGlobal < cwchGlobal && !fTerminateLoops */
  340. Assert(iwchGlobal == pdobjText->iwchLim - pdobjText->iwchFirst);
  341. Assert(iwchGlobal > 0);
  342. lserr = FillRegularPresWidths(plnobj, pfmtin->lsfrun.plsrun, pfmtin->lsfgi.lstflow, pdobjText);
  343. if (lserr != lserrNone) return lserr;
  344. if ((pilsobj->grpf & fTxtVisiSpaces) && pfmtin->lsfgi.cpFirst >= 0)
  345. {
  346. FixSpaces(plnobj, pdobjText, pilsobj->wchVisiSpace);
  347. }
  348. *pfmtr = fmtrCompletedRun;
  349. if (durWidthExceed < 0 && !fInSpaces)
  350. {
  351. *pfmtr = fmtrExceededMargin;
  352. }
  353. lserr = FillRealFmtOut(pilsobj, iwchGlobal, dur, pdobjText, pfmtin,
  354. iwchGlobal == pdobjText->u.reg.iwSpacesLim - pdobjText->u.reg.iwSpacesFirst);
  355. return lserr;
  356. }
  357. /* C R E A T E F I L L T E X T D O B J */
  358. /*----------------------------------------------------------------------------
  359. %%Function: CreateFillTextDobj
  360. %%Contact: sergeyge
  361. Requests pointer to the new text DObj and then fills common memebers
  362. ----------------------------------------------------------------------------*/
  363. static LSERR CreateFillTextDobj(PLNOBJ plnobj, long txtkind, PCFMTIN pfmtin, BOOL fIgnoreGlyphs,
  364. TXTOBJ** ppdobjText)
  365. {
  366. LSERR lserr;
  367. PILSOBJ pilsobj;
  368. pilsobj = plnobj->pilsobj;
  369. lserr = GetTextDobj(plnobj, ppdobjText);
  370. if (lserr != lserrNone) return lserr;
  371. (*ppdobjText)->txtkind = (BYTE)txtkind;
  372. (*ppdobjText)->plnobj = plnobj;
  373. (*ppdobjText)->plsdnUpNode = pfmtin->plsdnTop;
  374. if (pfmtin->lstxmPres.fMonospaced)
  375. (*ppdobjText)->txtf |= txtfMonospaced;
  376. (*ppdobjText)->iwchFirst = pilsobj->wchMac;
  377. (*ppdobjText)->iwchLim = pilsobj->wchMac;
  378. if (txtkind == txtkindRegular)
  379. {
  380. (*ppdobjText)->u.reg.iwSpacesFirst = pilsobj->wSpacesMac;
  381. (*ppdobjText)->u.reg.iwSpacesLim = pilsobj->wSpacesMac;
  382. }
  383. if (!fIgnoreGlyphs && pfmtin->lsfrun.plschp->fGlyphBased)
  384. (*ppdobjText)->txtf |= txtfGlyphBased;
  385. return lserrNone;
  386. }
  387. /* G E T T E X T D O B J */
  388. /*----------------------------------------------------------------------------
  389. %%Function: GetTextDobj
  390. %%Contact: sergeyge
  391. Produces pointer of the first unoccupied DObj from the preallocated chunk.
  392. If nothing is left, allocates next piece and includes it in the linked list.
  393. ----------------------------------------------------------------------------*/
  394. static LSERR GetTextDobj(PLNOBJ plnobj, TXTOBJ** ppdobjText)
  395. {
  396. PILSOBJ pilsobj;
  397. TXTOBJ* ptxtobj;
  398. pilsobj = plnobj->pilsobj;
  399. if (pilsobj->txtobjMac < txtobjMaxM)
  400. {
  401. *ppdobjText = &plnobj->ptxtobj[pilsobj->txtobjMac];
  402. pilsobj->txtobjMac++;
  403. }
  404. else
  405. {
  406. /* if nothing is left in the active piece, there are still two possibilities:
  407. either there is next preallocated (during the formatting of the previous lines piece
  408. or next piece should be allocated
  409. */
  410. if ( *(TXTOBJ**)(plnobj->ptxtobj + txtobjMaxM) == NULL)
  411. {
  412. ptxtobj = (*pilsobj->plscbk->pfnNewPtr)(pilsobj->pols, sizeof(TXTOBJ) * txtobjMaxM + sizeof(TXTOBJ**));
  413. if (ptxtobj == NULL)
  414. {
  415. return lserrOutOfMemory;
  416. }
  417. *(TXTOBJ**)(ptxtobj + txtobjMaxM) = NULL;
  418. *(TXTOBJ**)(plnobj->ptxtobj + txtobjMaxM) = ptxtobj;
  419. plnobj->ptxtobj = ptxtobj;
  420. }
  421. else
  422. {
  423. plnobj->ptxtobj = *(TXTOBJ**)(plnobj->ptxtobj + txtobjMaxM);
  424. }
  425. *ppdobjText = plnobj->ptxtobj;
  426. pilsobj->txtobjMac = 1;
  427. }
  428. memset(*ppdobjText, 0, sizeof(**ppdobjText));
  429. return lserrNone;
  430. }
  431. /* F I L L R E A L F M T O U T */
  432. /*----------------------------------------------------------------------------
  433. %%Function: FillRealFmtOut
  434. %%Contact: sergeyge
  435. Sets dup in dobj and
  436. calls to LsdnFinishSimpleRegular for the regular case (real upper node)
  437. ----------------------------------------------------------------------------*/
  438. static LSERR FillRealFmtOut(PILSOBJ pilsobj, LSDCP lsdcp, long dur, TXTOBJ* pdobjText, PCFMTIN pfmtin,
  439. BOOL fSpacesOnly)
  440. {
  441. LSERR lserr;
  442. OBJDIM objdim;
  443. objdim.dur = dur;
  444. objdim.heightsPres.dvAscent = pfmtin->lstxmPres.dvAscent;
  445. objdim.heightsRef.dvAscent = pfmtin->lstxmRef.dvAscent;
  446. objdim.heightsPres.dvDescent = pfmtin->lstxmPres.dvDescent;
  447. objdim.heightsRef.dvDescent = pfmtin->lstxmRef.dvDescent;
  448. objdim.heightsPres.dvMultiLineHeight = pfmtin->lstxmPres.dvMultiLineHeight;
  449. objdim.heightsRef.dvMultiLineHeight = pfmtin->lstxmRef.dvMultiLineHeight;
  450. if (fSpacesOnly)
  451. {
  452. if (!(pilsobj->grpf & fTxtSpacesInfluenceHeight))
  453. {
  454. objdim.heightsRef.dvMultiLineHeight = dvHeightIgnore;
  455. objdim.heightsPres.dvMultiLineHeight = dvHeightIgnore;
  456. }
  457. }
  458. /* It is ugly to set part of FetchedWidth state here, but it is absolutely needed
  459. to fix bug 546. iwchFetchedWidthFirst was introduced to fix this bug
  460. */
  461. if (lsdcp < pfmtin->lsfrun.cwchRun)
  462. pilsobj->wchFetchedWidthFirst = pfmtin->lsfrun.lpwchRun[lsdcp];
  463. else
  464. FlushStringState(pilsobj); /* Next char is not available---it is risky to use optimization */
  465. lserr = LsdnFinishRegular(pilsobj->plsc, lsdcp,
  466. pfmtin->lsfrun.plsrun, pfmtin->lsfrun.plschp, (PDOBJ)pdobjText, &objdim);
  467. return lserr;
  468. }
  469. /* A P P E N D T R A I L I N G S P A C E S */
  470. /*----------------------------------------------------------------------------
  471. %%Function: AppendTrailingSpaces
  472. %%Contact: sergeyge
  473. Trailing spaces logic.
  474. ----------------------------------------------------------------------------*/
  475. static LSERR AppendTrailingSpaces(PLNOBJ plnobj, TXTOBJ* pdobjText, WCHAR* rgwchGlobal,
  476. long iwchGlobal, long cwchGlobal,
  477. long* iwchGlobalNew, long* pddur)
  478. {
  479. LSERR lserr;
  480. PILSOBJ pilsobj;
  481. long iNumOfSpaces;
  482. long durSpace;
  483. pilsobj = plnobj->pilsobj;
  484. Assert(iwchGlobal < cwchGlobal && pilsobj->wchSpace == rgwchGlobal[iwchGlobal]);
  485. iNumOfSpaces = 1;
  486. iwchGlobal++;
  487. while (iwchGlobal < cwchGlobal && pilsobj->wchSpace == rgwchGlobal[iwchGlobal])
  488. {
  489. iNumOfSpaces++;
  490. iwchGlobal++;
  491. }
  492. *iwchGlobalNew = iwchGlobal;
  493. Assert(pilsobj->pwchOrig[pdobjText->iwchLim - 1] == pilsobj->wchSpace);
  494. durSpace = pilsobj->pdur[pdobjText->iwchLim - 1];
  495. Assert (iNumOfSpaces > 0);
  496. Assert(durSpace <= uLsInfiniteRM / iNumOfSpaces);
  497. if (durSpace > uLsInfiniteRM / iNumOfSpaces)
  498. return lserrTooLongParagraph;
  499. *pddur = durSpace * iNumOfSpaces;
  500. /* Calls function of the string module level */
  501. lserr = AddSpaces(plnobj, pdobjText, durSpace, iNumOfSpaces);
  502. return lserr;
  503. }
  504. /* F O R M A T S T A R T E M P T Y D O B J */
  505. /*----------------------------------------------------------------------------
  506. %%Function: FormatStartEmptyDobj
  507. %%Contact: sergeyge
  508. NonReqHyphen/OptionalBreak/OptionalNonBreak logic
  509. ----------------------------------------------------------------------------*/
  510. static LSERR FormatStartEmptyDobj(PLNOBJ plnobj, PCFMTIN pfmtin, long txtkind, DWORD fTxtVisi,
  511. WCHAR wchVisi, FMTRES* pfmtr)
  512. {
  513. LSERR lserr;
  514. PILSOBJ pilsobj;
  515. TXTOBJ* pdobjText;
  516. PLSRUN plsrun;
  517. long dup;
  518. /* long durOut = 0; */
  519. pilsobj = plnobj->pilsobj;
  520. plsrun = pfmtin->lsfrun.plsrun;
  521. lserr = CreateFillTextDobj(plnobj, txtkind, pfmtin, fTrue, &pdobjText);
  522. if (lserr != lserrNone) return lserr;
  523. pdobjText->txtf |= txtfSkipAtNti;
  524. pilsobj->fDifficultForAdjust = fTrue;
  525. if (pilsobj->grpf & fTxtVisi)
  526. {
  527. Assert(pilsobj->fDisplay);
  528. /* Imitate formatting for 1-char string without writing in the string level structures */
  529. /* lserr = GetOneCharDur(pilsobj, plsrun, pilsobj->wchHyphen, pfmtin->lsfgi.lstflow, &durOut);
  530. if (lserr != lserrNone) return lserr;
  531. */
  532. pdobjText->txtf |= txtfSkipAtWysi;
  533. pdobjText->txtf |= txtfVisi;
  534. lserr = GetVisiCharDup(pilsobj, plsrun, wchVisi, pfmtin->lsfgi.lstflow, &dup);
  535. if (lserr != lserrNone) return lserr;
  536. /* Restore this code instead of current one if Word wants to keep differences in breaking
  537. lserr = AddCharacterWithWidth(plnobj, pdobjText, pilsobj->wchHyphen, durOut, wchVisi, dup);
  538. if (lserr != lserrNone) return lserr;
  539. lserr = FillRealFmtOut(pilsobj, 1, durOut, pdobjText, pfmtin, fFalse);
  540. if (lserr != lserrNone) return lserr;
  541. */
  542. lserr = AddCharacterWithWidth(plnobj, pdobjText, pilsobj->wchHyphen, 0, wchVisi, dup);
  543. if (lserr != lserrNone) return lserr;
  544. lserr = FillRealFmtOut(pilsobj, 1, 0, pdobjText, pfmtin, fTrue);
  545. if (lserr != lserrNone) return lserr;
  546. }
  547. else
  548. {
  549. lserr = FillRealFmtOut(pilsobj, 1, 0, pdobjText, pfmtin, fTrue);
  550. if (lserr != lserrNone) return lserr;
  551. FlushStringState(pilsobj); /* Position of fetched widths is not correct any longer */
  552. }
  553. *pfmtr = fmtrCompletedRun;
  554. return lserrNone;
  555. }
  556. /* F O R M A T S T A R T T A B */
  557. /*----------------------------------------------------------------------------
  558. %%Function: FormatStartTab
  559. %%Contact: sergeyge
  560. Tab logic
  561. ----------------------------------------------------------------------------*/
  562. static LSERR FormatStartTab(PLNOBJ plnobj, PCFMTIN pfmtin, FMTRES* pfmtr)
  563. {
  564. LSERR lserr;
  565. PILSOBJ pilsobj;
  566. PTXTOBJ pdobjText;
  567. int durJunk;
  568. long cJunk;
  569. pilsobj = plnobj->pilsobj;
  570. lserr = CreateFillTextDobj(plnobj, txtkindTab, pfmtin, fTrue, &pdobjText);
  571. if (lserr != lserrNone) return lserr;
  572. pdobjText->u.tab.wchTabLeader = pilsobj->wchSpace;
  573. if (pilsobj->grpf & fTxtVisiTabs)
  574. {
  575. Assert(pilsobj->fDisplay);
  576. pdobjText->txtf |= txtfVisi;
  577. /* REVIEW sergeyge: Next call is made to show Visi Tab correctly in WORD
  578. it should be moved to the WAL */
  579. (*pilsobj->plscbk->pfnGetRunCharWidths)(pilsobj->pols, pfmtin->lsfrun.plsrun,
  580. lsdevPres, &pilsobj->wchVisiTab, 1, LONG_MAX, pfmtin->lsfgi.lstflow,
  581. &durJunk, (long*)&durJunk, &cJunk);
  582. pdobjText->u.tab.wch = pilsobj->wchVisiTab;
  583. }
  584. else
  585. {
  586. pdobjText->u.tab.wch = pfmtin->lsfrun.lpwchRun[0];
  587. }
  588. lserr = AddCharacterWithWidth(plnobj, pdobjText, pfmtin->lsfrun.lpwchRun[0], 0,
  589. pfmtin->lsfrun.lpwchRun[0], 0);
  590. if (lserr != lserrNone) return lserr;
  591. lserr = FillRealFmtOut(pilsobj, 1, 0, pdobjText, pfmtin, fTrue);
  592. if (lserr != lserrNone) return lserr;
  593. *pfmtr = fmtrTab;
  594. return lserrNone;
  595. }
  596. /* F O R M A T S T A R T B O R D E R E D S P A C E S */
  597. /*----------------------------------------------------------------------------
  598. %%Function: FormatStartBorderedSpaces
  599. %%Contact: sergeyge
  600. Formatting od the spaces within bordered run
  601. ----------------------------------------------------------------------------*/
  602. static LSERR FormatStartBorderedSpaces(PLNOBJ plnobj, PCFMTIN pfmtin, FMTRES* pfmtr)
  603. {
  604. LSERR lserr;
  605. PILSOBJ pilsobj;
  606. TXTOBJ* pdobjText;
  607. long durSpace;
  608. DWORD iNumOfSpaces;
  609. pilsobj = plnobj->pilsobj;
  610. lserr = CreateFillTextDobj(plnobj, txtkindRegular, pfmtin, fFalse, &pdobjText);
  611. if (lserr != lserrNone) return lserr;
  612. Assert(pfmtin->lsfrun.lpwchRun[0] == pilsobj->wchSpace);
  613. /* fill additional information for txtkindYsrChar text DObj */
  614. lserr = GetOneCharDur(pilsobj, pfmtin->lsfrun.plsrun, pilsobj->wchSpace, pfmtin->lsfgi.lstflow, &durSpace);
  615. if (lserr != lserrNone) return lserr;
  616. iNumOfSpaces = 0;
  617. while (pilsobj->wchSpace == pfmtin->lsfrun.lpwchRun[iNumOfSpaces] && iNumOfSpaces < pfmtin->lsfrun.cwchRun)
  618. {
  619. iNumOfSpaces++;
  620. }
  621. /* Calls functions of the string module level */
  622. lserr = AddSpaces(plnobj, pdobjText, durSpace, iNumOfSpaces);
  623. if (lserr != lserrNone) return lserr;
  624. lserr = FillRegularPresWidths(plnobj, pfmtin->lsfrun.plsrun, pfmtin->lsfgi.lstflow, pdobjText);
  625. if (lserr != lserrNone) return lserr;
  626. if ((pilsobj->grpf & fTxtVisiSpaces) && pfmtin->lsfgi.cpFirst >= 0)
  627. {
  628. FixSpaces(plnobj, pdobjText, pilsobj->wchVisiSpace);
  629. }
  630. *pfmtr = fmtrCompletedRun;
  631. lserr = FillRealFmtOut(pilsobj, iNumOfSpaces, durSpace * iNumOfSpaces, pdobjText, pfmtin, fTrue);
  632. if (lserr != lserrNone) return lserr;
  633. return lserrNone;
  634. }
  635. /* F O R M A T S T A R T O N E R E G U L A R C H A R */
  636. /*----------------------------------------------------------------------------
  637. %%Function: FormatStartOneRegularChar
  638. %%Contact: sergeyge
  639. YSR/(NonSignificant for this paragraph EOP) character logic.
  640. ----------------------------------------------------------------------------*/
  641. static LSERR FormatStartOneRegularChar(PLNOBJ plnobj, PCFMTIN pfmtin, long txtkind, FMTRES* pfmtr)
  642. {
  643. LSERR lserr;
  644. PILSOBJ pilsobj;
  645. TXTOBJ* pdobjText;
  646. long durOut;
  647. long dupOut;
  648. WCHAR wch;
  649. pilsobj = plnobj->pilsobj;
  650. lserr = CreateFillTextDobj(plnobj, txtkind, pfmtin, fFalse, &pdobjText);
  651. if (lserr != lserrNone) return lserr;
  652. wch = pfmtin->lsfrun.lpwchRun[0];
  653. /* fill additional information for txtkindYsrChar text DObj */
  654. lserr = GetOneCharDur(pilsobj, pfmtin->lsfrun.plsrun, wch, pfmtin->lsfgi.lstflow, &durOut);
  655. if (lserr != lserrNone) return lserr;
  656. lserr = GetOneCharDup(pilsobj, pfmtin->lsfrun.plsrun, wch, pfmtin->lsfgi.lstflow, durOut, &dupOut);
  657. if (lserr != lserrNone) return lserr;
  658. Assert(durOut < uLsInfiniteRM);
  659. lserr = AddCharacterWithWidth(plnobj, pdobjText, wch, durOut, wch, dupOut);
  660. *pfmtr = fmtrCompletedRun;
  661. if (durOut > pfmtin->lsfgi.urColumnMax - pfmtin->lsfgi.urPen)
  662. {
  663. *pfmtr = fmtrExceededMargin;
  664. }
  665. lserr = FillRealFmtOut(pilsobj, 1, durOut, pdobjText, pfmtin, fFalse);
  666. if (lserr != lserrNone) return lserr;
  667. return lserrNone;
  668. }
  669. /* F O R M A T S T A R T T O R E P L A C E */
  670. /*----------------------------------------------------------------------------
  671. %%Function: FormatStartToReplace
  672. %%Contact: sergeyge
  673. Implements replacement of one char code ("\") by another (Yen)
  674. ----------------------------------------------------------------------------*/
  675. static LSERR FormatStartToReplace(PLNOBJ plnobj, PCFMTIN pfmtin, FMTRES* pfmtr)
  676. {
  677. LSERR lserr;
  678. PILSOBJ pilsobj;
  679. TXTOBJ* pdobjText;
  680. WCHAR wch;
  681. long durOut;
  682. long dupOut;
  683. pilsobj = plnobj->pilsobj;
  684. lserr = CreateFillTextDobj(plnobj, txtkindRegular, pfmtin, fFalse, &pdobjText);
  685. if (lserr != lserrNone) return lserr;
  686. /* fill additional information for txtkindYsrChar text DObj */
  687. if (pfmtin->lsfrun.plschp->fCheckForReplaceChar)
  688. wch = pilsobj->wchReplace;
  689. else
  690. wch = pfmtin->lsfrun.lpwchRun[0];
  691. lserr = GetOneCharDur(pilsobj, pfmtin->lsfrun.plsrun, wch, pfmtin->lsfgi.lstflow, &durOut);
  692. if (lserr != lserrNone) return lserr;
  693. lserr = GetOneCharDup(pilsobj, pfmtin->lsfrun.plsrun, wch, pfmtin->lsfgi.lstflow, durOut, &dupOut);
  694. if (lserr != lserrNone) return lserr;
  695. Assert(durOut < uLsInfiniteRM);
  696. lserr = AddCharacterWithWidth(plnobj, pdobjText, wch, durOut, wch, dupOut);
  697. *pfmtr = fmtrCompletedRun;
  698. if (durOut > pfmtin->lsfgi.urColumnMax - pfmtin->lsfgi.urPen)
  699. {
  700. *pfmtr = fmtrExceededMargin;
  701. }
  702. lserr = FillRealFmtOut(pilsobj, 1, durOut, pdobjText, pfmtin, fFalse);
  703. if (lserr != lserrNone) return lserr;
  704. return lserrNone;
  705. }
  706. /* F O R M A T S T A R T E O L */
  707. /*----------------------------------------------------------------------------
  708. %%Function: FormatStartEop
  709. %%Contact: sergeyge
  710. EOP/SoftCR logic.
  711. ----------------------------------------------------------------------------*/
  712. static LSERR FormatStartEol(PLNOBJ plnobj, PCFMTIN pfmtin, WCHAR wchVisiEnd, STOPRES stopr, FMTRES* pfmtr)
  713. {
  714. LSERR lserr;
  715. PILSOBJ pilsobj;
  716. PLSRUN plsrun;
  717. TXTOBJ* pdobjText;
  718. WCHAR wchAdd;
  719. long dupWch;
  720. long durWch;
  721. BOOL fInChildList;
  722. OBJDIM objdim;
  723. pilsobj = plnobj->pilsobj;
  724. plsrun = pfmtin->lsfrun.plsrun;
  725. lserr = LsdnFInChildList(pilsobj->plsc, pfmtin->plsdnTop, &fInChildList);
  726. Assert(lserr == lserrNone);
  727. if (fInChildList)
  728. return FormatStartOneRegularChar(plnobj, pfmtin, txtkindRegular, pfmtr);
  729. *pfmtr = fmtrStopped;
  730. /* CreateFillTextDobj section starts */
  731. lserr = GetTextDobj(plnobj, &pdobjText);
  732. if (lserr != lserrNone) return lserr;
  733. pdobjText->txtkind = txtkindEOL;
  734. pdobjText->plnobj = plnobj;
  735. pdobjText->plsdnUpNode = pfmtin->plsdnTop;
  736. pdobjText->iwchFirst = pilsobj->wchMac;
  737. /* CreateFillTextDobj section ends */
  738. pdobjText->txtf |= txtfSkipAtNti;
  739. if (pilsobj->grpf & fTxtVisiParaMarks)
  740. wchAdd = wchVisiEnd;
  741. else
  742. wchAdd = pilsobj->wchSpace;
  743. if (pilsobj->fDisplay)
  744. {
  745. lserr = GetVisiCharDup(pilsobj, plsrun, wchVisiEnd, pfmtin->lsfgi.lstflow, &dupWch);
  746. if (lserr != lserrNone) return lserr;
  747. durWch = UrFromUp(pfmtin->lsfgi.lstflow, &pilsobj->lsdevres, dupWch);
  748. plnobj->pwch[pilsobj->wchMac] = wchAdd;
  749. plnobj->pdup[pilsobj->wchMac] = dupWch;
  750. }
  751. else
  752. {
  753. durWch = 1;
  754. }
  755. Assert(durWch < uLsInfiniteRM);
  756. pilsobj->pwchOrig[pilsobj->wchMac] = wchAdd;
  757. pilsobj->pdur[pilsobj->wchMac] = durWch;
  758. /* AddCharacterWithWidth section starts---parts of it were moved up */
  759. /* We do not check for sufficient space in allocated arrays becayse anyway we allocate for 2 additional
  760. characters due to possible changes at hyphenation time
  761. */
  762. pilsobj->dcpFetchedWidth = 0;
  763. pilsobj->wchMac++;
  764. pdobjText->iwchLim = pilsobj->wchMac;
  765. Assert(pdobjText->iwchLim == pdobjText->iwchFirst + 1);
  766. /* AddCharacterWithWidth section ends */
  767. /* FillRealFmtOut section starts */
  768. objdim.dur = durWch;
  769. objdim.heightsPres.dvAscent = pfmtin->lstxmPres.dvAscent;
  770. objdim.heightsRef.dvAscent = pfmtin->lstxmRef.dvAscent;
  771. objdim.heightsPres.dvDescent = pfmtin->lstxmPres.dvDescent;
  772. objdim.heightsRef.dvDescent = pfmtin->lstxmRef.dvDescent;
  773. objdim.heightsPres.dvMultiLineHeight = pfmtin->lstxmPres.dvMultiLineHeight;
  774. objdim.heightsRef.dvMultiLineHeight = pfmtin->lstxmRef.dvMultiLineHeight;
  775. if (!(pilsobj->grpf & fTxtSpacesInfluenceHeight))
  776. {
  777. objdim.heightsRef.dvMultiLineHeight = dvHeightIgnore;
  778. objdim.heightsPres.dvMultiLineHeight = dvHeightIgnore;
  779. }
  780. lserr = LsdnSetStopr(pilsobj->plsc, pfmtin->plsdnTop, stopr);
  781. Assert(lserr == lserrNone);
  782. lserr = LsdnFinishRegular(pilsobj->plsc, 1,
  783. pfmtin->lsfrun.plsrun, pfmtin->lsfrun.plschp, (PDOBJ)pdobjText, &objdim);
  784. return lserr;
  785. }
  786. /* F O R M A T S T A R T D E L E T E */
  787. /*----------------------------------------------------------------------------
  788. %%Function: FormatStartDelete
  789. %%Contact: sergeyge
  790. Formatting by Delete upper dnode
  791. ----------------------------------------------------------------------------*/
  792. static LSERR FormatStartDelete(PLNOBJ plnobj, LSDCP dcp, FMTRES* pfmtr)
  793. {
  794. PILSOBJ pilsobj;
  795. pilsobj = plnobj->pilsobj;
  796. FlushStringState(pilsobj); /* Position of fetched widths is not correct any longer */
  797. *pfmtr = fmtrCompletedRun;
  798. return LsdnFinishDelete(pilsobj->plsc, dcp);
  799. }
  800. /* F O R M A T S T A R T S P L A T */
  801. /*----------------------------------------------------------------------------
  802. %%Function: FormatStartSplat
  803. %%Contact: sergeyge
  804. Splat formatting logic
  805. ----------------------------------------------------------------------------*/
  806. static LSERR FormatStartSplat(PLNOBJ plnobj, PCFMTIN pfmtin, STOPRES stopr, FMTRES* pfmtr)
  807. {
  808. *pfmtr = fmtrStopped;
  809. LsdnSetStopr(plnobj->pilsobj->plsc, pfmtin->plsdnTop, stopr);
  810. return FillRealFmtOut(plnobj->pilsobj, 1, 0, NULL, pfmtin, fTrue);
  811. }
  812. /* F O R M A T S P E C I A L */
  813. /*----------------------------------------------------------------------------
  814. %%Function: FormatSpecial
  815. %%Contact: sergeyge
  816. Formatting of the special characters (not NonReqHyphen, not Tab)
  817. Uses wchRef for formatting on reference device, wchPres--on preview device
  818. ----------------------------------------------------------------------------*/
  819. static LSERR FormatSpecial(PLNOBJ plnobj, WCHAR wchRef, WCHAR wchPres, BOOL fVisible, long txtkind,
  820. PCFMTIN pfmtin, FMTRES* pfmtr)
  821. {
  822. LSERR lserr;
  823. PILSOBJ pilsobj;
  824. PTXTOBJ pdobjText;
  825. PLSRUN plsrun;
  826. long dur;
  827. long dup;
  828. long durGlobal;
  829. long cwchRun;
  830. const WCHAR* pwchRun;
  831. long iNumOfChars;
  832. long durWidth;
  833. long i;
  834. pilsobj = plnobj->pilsobj;
  835. plsrun = pfmtin->lsfrun.plsrun;
  836. lserr = CreateFillTextDobj(plnobj, txtkind, pfmtin, fTrue, &pdobjText);
  837. if (lserr != lserrNone) return lserr;
  838. durWidth = pfmtin->lsfgi.urColumnMax - pfmtin->lsfgi.urPen;
  839. /* Imitate formatting for 1-char string without writing in the string level structures */
  840. lserr = GetOneCharDur(pilsobj, plsrun, wchRef, pfmtin->lsfgi.lstflow, &dur);
  841. if (lserr != lserrNone) return lserr;
  842. /* Calculate presentation width */
  843. Assert(wchPres == wchRef || fVisible);
  844. if (fVisible)
  845. {
  846. long dupOrig;
  847. pilsobj->fDifficultForAdjust = fTrue;
  848. lserr = GetVisiCharDup(pilsobj, plsrun, wchPres, pfmtin->lsfgi.lstflow, &dup);
  849. if (lserr != lserrNone) return lserr;
  850. lserr = GetOneCharDup(pilsobj, plsrun, wchPres, pfmtin->lsfgi.lstflow, dur, &dupOrig);
  851. if (lserr != lserrNone) return lserr;
  852. if (dup != dupOrig)
  853. pdobjText->txtf |= txtfSkipAtWysi;
  854. }
  855. else
  856. {
  857. lserr = GetOneCharDup(pilsobj, plsrun, wchPres, pfmtin->lsfgi.lstflow, dur, &dup);
  858. if (lserr != lserrNone) return lserr;
  859. }
  860. cwchRun = (long)pfmtin->lsfrun.cwchRun;
  861. pwchRun = pfmtin->lsfrun.lpwchRun;
  862. /* check if there are a few identical characters and calculate their number -- we can format them all at once */
  863. for (iNumOfChars = 1; iNumOfChars < cwchRun && pwchRun[0] == pwchRun[iNumOfChars]; iNumOfChars++);
  864. durGlobal = 0;
  865. Assert(iNumOfChars > 0);
  866. Assert (dur <= uLsInfiniteRM / iNumOfChars);
  867. if (dur > uLsInfiniteRM / iNumOfChars)
  868. return lserrTooLongParagraph;
  869. /* Don't forget to write at least one char even if pen was positioned behind right margin */
  870. lserr = AddCharacterWithWidth(plnobj, pdobjText, wchRef, dur, wchPres, dup);
  871. if (lserr != lserrNone) return lserr;
  872. durWidth -= dur;
  873. durGlobal += dur;
  874. for (i = 1; i < iNumOfChars && (durWidth >= 0 || txtkind == txtkindSpecSpace); i++)
  875. {
  876. lserr = AddCharacterWithWidth(plnobj, pdobjText, wchRef, dur, wchPres, dup);
  877. if (lserr != lserrNone) return lserr;
  878. durWidth -= dur;
  879. durGlobal += dur;
  880. }
  881. iNumOfChars = i;
  882. *pfmtr = fmtrCompletedRun;
  883. if (durWidth < 0 && txtkind != txtkindSpecSpace) /* Don't stop formatting while in spaces */
  884. *pfmtr = fmtrExceededMargin;
  885. if (fVisible)
  886. pdobjText->txtf |= txtfVisi;
  887. lserr = FillRealFmtOut(pilsobj, iNumOfChars, durGlobal, pdobjText, pfmtin,
  888. txtkind == txtkindSpecSpace);
  889. if (lserr != lserrNone) return lserr;
  890. return lserrNone;
  891. }
  892. /* F M T R H A R D B R E A K */
  893. /*----------------------------------------------------------------------------
  894. %%Function: FmtrHardBreak
  895. %%Contact: sergeyge
  896. Calculates fmtr based on clab for the hard breaks.
  897. ----------------------------------------------------------------------------*/
  898. static STOPRES StoprHardBreak(CLABEL clab)
  899. {
  900. switch (clab)
  901. {
  902. case clabSectionBreak:
  903. return stoprEndSection;
  904. case clabPageBreak:
  905. return stoprEndPage;
  906. case clabColumnBreak:
  907. return stoprEndColumn;
  908. default:
  909. NotReached();
  910. return 0;
  911. }
  912. }
  913. /* C L A B F R O M C H A R */
  914. /*----------------------------------------------------------------------------
  915. %%Function: ClabFromChar
  916. %%Contact: sergeyge
  917. Calculates clab for wch
  918. ----------------------------------------------------------------------------*/
  919. static CLABEL ClabFromChar(PILSOBJ pilsobj, WCHAR wch) /* REVIEW sergeyge - the whole procedure can be fixed */
  920. {
  921. DWORD i;
  922. if (wch < 0x00FF)
  923. {
  924. return (CLABEL)(pilsobj->rgbSwitch[wch] & fSpecMask);
  925. }
  926. else
  927. {
  928. if (pilsobj->rgbSwitch[wch & 0x00FF] & clabSuspicious)
  929. {
  930. /*
  931. REVIEW sergeyge (elik) It does not make sense to make bin search while
  932. there are two wide special characters only. It would make sense to switch
  933. to binary search as soon as this number is more than 4.
  934. */
  935. for (i=0; i < pilsobj->cwchSpec && wch != pilsobj->rgwchSpec[i]; i++);
  936. if (i == pilsobj->cwchSpec)
  937. {
  938. return clabRegular;
  939. }
  940. else
  941. {
  942. return pilsobj->rgbKind[i];
  943. }
  944. }
  945. else
  946. {
  947. return clabRegular;
  948. }
  949. }
  950. }