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

1479 lines
38 KiB

  1. /*
  2. * @doc INTERNAL
  3. *
  4. * @module FRUNPTR.C -- FormatRunPtr methods |
  5. *
  6. * common code to handle character and paragraph format runs
  7. *
  8. * Original Authors: <nl>
  9. * Original RichEdit 1.0 code: David R. Fulmer <nl>
  10. * Christian Fortini <nl>
  11. * Murray Sargent <nl>
  12. *
  13. * History:
  14. * 6/25/95 alexgo convert to use Auto-Doc and simplified backing
  15. * store model
  16. *
  17. * @devnote
  18. * BOR and EOR mean Beginning Of Run and End Of Run, respectively
  19. *
  20. * Copyright (c) 1995-1999, Microsoft Corporation. All rights reserved.
  21. */
  22. #include "_common.h"
  23. #include "_edit.h"
  24. #include "_frunptr.h"
  25. #include "_rtext.h"
  26. #include "_font.h"
  27. ASSERTDATA
  28. //
  29. // Invariant stuff
  30. //
  31. #define DEBUG_CLASSNAME CFormatRunPtr
  32. #include "_invar.h"
  33. #ifdef DEBUG
  34. /*
  35. * CFormatRunPtr::Invariant
  36. *
  37. * @mfunc Invariant for format run pointers
  38. *
  39. * @rdesc BOOL
  40. */
  41. BOOL CFormatRunPtr::Invariant() const
  42. {
  43. if(IsValid())
  44. {
  45. CFormatRun *prun = GetRun(0);
  46. if(prun && _iRun)
  47. {
  48. Assert(prun->_cch > 0);
  49. }
  50. }
  51. else
  52. {
  53. Assert(_ich == 0);
  54. }
  55. return CRunPtrBase::Invariant();
  56. }
  57. #endif
  58. /*
  59. * CFormatRunPtr::InitRuns(ich, cch, iFormat, ppfrs)
  60. *
  61. * @mfunc
  62. * Setup this format run ptr for rich-text operation, namely,
  63. * allocate CArray<lt>CFormatRun<gt> if not allocated, assign it to this
  64. * run ptr's _pRuns, add initial run if no runs are present, and store
  65. * initial cch and ich
  66. *
  67. * @rdesc
  68. * TRUE if succeeds
  69. */
  70. BOOL CFormatRunPtr::InitRuns(
  71. LONG ich, //@parm # chars in initial run
  72. LONG cch, //@parm char offset in initial run
  73. CFormatRuns **ppfrs) //@parm ptr to CFormatRuns ptr
  74. {
  75. TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CFormatRunPtr::InitRuns");
  76. _TEST_INVARIANT_
  77. AssertSz( ppfrs,
  78. "FRP::InitRuns: illegal ptr to runs");
  79. AssertSz( !IsValid(),
  80. "FRP::InitRuns: ptr already valid");
  81. if(!*ppfrs) // Allocate format runs
  82. {
  83. _pRuns = (CRunArray *) new CFormatRuns();
  84. if(!_pRuns)
  85. goto NoRAM;
  86. *ppfrs = (CFormatRuns *)_pRuns;
  87. }
  88. else // Format runs already alloc'd
  89. _pRuns = (CRunArray *)*ppfrs; // Cache ptr to runs
  90. if(!Count()) // No runs yet, so add one
  91. {
  92. CFormatRun *pRun= Add(1, NULL);
  93. if(!pRun)
  94. goto NoRAM;
  95. #ifdef DEBUG
  96. PvSet(*(void**)_pRuns);
  97. #endif
  98. _ich = ich;
  99. ZeroMemory(pRun, sizeof(*pRun));
  100. pRun->_cch = cch; // Define its _cch
  101. pRun->_iFormat = -1; // and _iFormat
  102. }
  103. else
  104. BindToCp(ich); // Format runs are in place
  105. return TRUE;
  106. NoRAM:
  107. TRACEERRSZSC("CFormatRunPtr::InitRuns: Out Of RAM", E_OUTOFMEMORY);
  108. return FALSE;
  109. }
  110. /*
  111. * CFormatRunPtr::Delete(cch, pf, cchMove)
  112. *
  113. * @mfunc
  114. * Delete/modify runs starting at this run ptr up to cch chars. <nl>
  115. * There are 7 possibilities: <nl>
  116. * 1. cch comes out of this run with count left over, i.e.,
  117. * cch <lt>= (*this)->_cch - _ich && (*this)->_cch > cch
  118. * (simple: no runs deleted/merged, just subtract cch) <nl>
  119. * 2. cch comes out of this run and empties run and doc
  120. * (simple: no runs left to delete/merge) <nl>
  121. * 3. cch comes out of this run and empties run, which is last
  122. * (need to delete run, no merge possibility) <nl>
  123. * 4. cch comes out of this run and empties run, which is first
  124. * (need to delete run, no merge possibility) <nl>
  125. * 5. cch exceeds count available in this run and this run is last
  126. * (simple: treat as 3.) <nl>
  127. * 6. cch comes out of this run and empties run with runs before
  128. * and after (need to delete run; merge possibility) <nl>
  129. * 7. cch comes partly out of this run and partly out of later run(s)
  130. * (may need to delete and merge) <nl>
  131. *
  132. * @comm
  133. * PARAFORMATs have two special cases that use the cchMove argument set
  134. * up in CRchTxtPtr::ReplaceRange().
  135. */
  136. void CFormatRunPtr::Delete(
  137. LONG cch, //@parm # chars to modify format runs for
  138. IFormatCache *pf, //@parm IFormatCache ptr for ReleaseFormat
  139. LONG cchMove) //@parm cch to move between runs (always 0 for CF)
  140. {
  141. TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CFormatRunPtr::Delete");
  142. _TEST_INVARIANT_
  143. // We should not have any boundary cases for empty or NULL pointers.
  144. // (i.e. if there's no text, then nobody should be calling delete).
  145. Assert(IsValid());
  146. LONG cchEnd = 0; // Probably unnecessary: see below
  147. LONG cRun = 1;
  148. BOOL fLast = (_iRun == Count() - 1);
  149. LONG ifmtEnd, ifmtStart;
  150. CFormatRun * pRun = Elem(_iRun);
  151. CFormatRun * pRunRp;
  152. LONG cchChunk = pRun->_cch - _ich;
  153. CFormatRunPtr rp(*this); // Clone this run ptr
  154. CBiDiLevel levelStart = {0,0};
  155. CBiDiLevel levelEnd = {0,0};
  156. rp.AdjustBackward(); // If at BOR, move to prev EOR
  157. ifmtStart = rp.GetRun(0)->_iFormat; // to get start format
  158. levelStart = rp.GetRun(0)->_level; // and level
  159. rp = *this; // In case RpAdjustCp() backed up
  160. // Process deletes confined to this run first, since their logic tends to
  161. // clutter up other cases
  162. AssertSz(cch >= 0, "FRP::Delete: cch < 0");
  163. if(fLast) // Handle oversized cch on last
  164. cch = min(cch, cchChunk); // run here
  165. if(cch <= cchChunk) // cch comes out of this run
  166. {
  167. pRun->_cch -= cch;
  168. Assert(pRun->_cch >= 0);
  169. if(cchMove) // If nonzero here, we are
  170. { // deleting EOP at end of run
  171. rp.AdjustForward(); // Adjust rp to beginning of
  172. goto move; // next run and go move cchMove
  173. } // chars back into this run
  174. if(pRun->_cch) // Something left in run: done
  175. return;
  176. // Note: _ich = 0
  177. if(!_iRun || fLast) // This run is either first
  178. { // or last
  179. AdjustBackward(); // If last, go to prev EOR
  180. if(_ich) // This run is empty so delete
  181. cRun++; // Compensate for cRun-- coming up
  182. ifmtStart = -2; // No runs eligible for merging
  183. } // so use unmatchable ifmtStart
  184. rp.NextRun(); // Set up to get next _iFormat
  185. }
  186. else
  187. {
  188. rp.Move(cch); // Move clone to end of delete
  189. pRunRp = rp.GetRun(0);
  190. cRun = rp._iRun - _iRun // If at EOR, then need to add
  191. + (rp._ich == pRunRp->_cch); // one more run to delete
  192. pRun->_cch = _ich; // Shorten this run to _ich chars
  193. pRunRp->_cch -= rp._ich; // Shorten last run by rp._ich
  194. rp._ich = 0;
  195. Assert(pRunRp->_cch >= 0);
  196. AssertSz(cRun > 0, "FRP: bogus runptr");
  197. if(!_iRun) // First run?
  198. ifmtStart = -2; // Then we cannot merge runs so
  199. } // set to unmergable format
  200. ifmtEnd = -3; // Default invalid format at end
  201. if(rp.IsValid())
  202. {
  203. // FUTURE (murrays): probably rp is always valid here now and
  204. // pRun->_cch is nonzero
  205. pRun = rp.GetRun(0);
  206. if (pRun->_cch) // run not empty
  207. {
  208. ifmtEnd = pRun->_iFormat; // Remember end format and count
  209. levelEnd = pRun->_level;
  210. cchEnd = pRun->_cch; // in case of merge
  211. }
  212. else if(rp._iRun != rp.Count() - 1) // run not last
  213. {
  214. pRun = rp.GetRun(1);
  215. ifmtEnd = pRun->_iFormat; // Remember end format and count
  216. levelEnd = pRun->_level;
  217. cchEnd = pRun->_cch; // in case of merge
  218. }
  219. }
  220. rp = *this; // Default to delete this run
  221. if(_ich) // There are chars in this run
  222. {
  223. if(cchMove + _ich == 0) // Need to combine all chars of
  224. { // this run with run after del,
  225. pf->AddRef(ifmtEnd); // so setup merge below using
  226. ifmtStart = ifmtEnd; // ifmtEnd. This run then takes
  227. pf->Release(GetRun(0)->_iFormat);
  228. GetRun(0)->_iFormat = ifmtEnd; // place of run after del.
  229. GetRun(0)->_level = levelEnd;
  230. cchMove = 0; // cchMove all accounted for
  231. }
  232. rp.NextRun(); // Don't delete this run; start
  233. cRun--; // with next one
  234. }
  235. AdjustBackward(); // If !_ich, go to prev EOR
  236. if(ifmtEnd >=0 && // Same formats: merge runs
  237. ifmtEnd == ifmtStart &&
  238. levelStart == levelEnd)
  239. {
  240. GetRun(0)->_cch += cchEnd; // Add last-run cch to this one's
  241. Assert(GetRun(0)->_cch >= 0);
  242. cRun++; // Setup to eat last run
  243. }
  244. if(cRun > 0) // There are run(s) to delete
  245. {
  246. rp.Remove(cRun, pf);
  247. if(!Count()) // If no more runs, keep this rp
  248. _ich = _iRun = 0; // valid by pointing at cp = 0
  249. }
  250. move:
  251. if(cchMove) // Need to move some cch between
  252. { // this run and next (See
  253. GetRun(0)->_cch += cchMove; // CRchTxtPtr::ReplaceRange())
  254. rp.GetRun(0)->_cch -= cchMove;
  255. Assert(GetRun(0)->_cch >= 0);
  256. Assert(rp.GetRun(0)->_cch >= 0);
  257. Assert(_iRun < rp._iRun);
  258. if(!rp.GetRun(0)->_cch) // If all chars moved out of rp's
  259. rp.Remove(1, pf); // run, delete it
  260. if(cchMove < 0) // Moved -cchMove chars from this
  261. { // run to next
  262. if(!GetRun(0)->_cch)
  263. Remove(1, pf);
  264. else
  265. _iRun++; // Keep this run ptr in sync with
  266. _ich = -cchMove; // cp (can't use NextRun() due
  267. } // to Invariants)
  268. }
  269. AdjustForward(); // Don't leave ptr at EOR unless
  270. } // there are no more runs
  271. /*
  272. * CFormatRunPtr::InsertFormat(cch, ifmt, pf)
  273. *
  274. * @mfunc
  275. * Insert cch chars with format ifmt into format runs starting at
  276. * this run ptr
  277. *
  278. * @rdesc
  279. * count of characters added
  280. *
  281. * @devnote
  282. * It is the caller's responsibility to ensure that we are in the
  283. * "normal" or "empty" state. A format run pointer doesn't know about
  284. * CTxtStory, so it can't create the run array without outside help.
  285. */
  286. LONG CFormatRunPtr::InsertFormat(
  287. LONG cch, //@parm # chars to insert
  288. LONG ifmt, //@parm format to use
  289. IFormatCache *pf) //@parm pointer to IFormatCache to AddRefFormat
  290. {
  291. TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CFormatRunPtr::InsertFormat");
  292. LONG cRun;
  293. CFormatRun *pRun;
  294. CFormatRun *pRunPrev;
  295. LONG cchRun; // Current-run length,
  296. LONG ich; // offset, and
  297. LONG iFormat; // format
  298. _TEST_INVARIANT_
  299. Assert(_pRuns);
  300. if(!IsValid())
  301. {
  302. // Empty run case (occurs when inserting after all text is deleted)
  303. pRun = Add(1, NULL);
  304. goto StoreNewRunData; // (located at end of function)
  305. }
  306. // Go to previous run if at a boundary case
  307. AdjustBackward();
  308. pRun = Elem(_iRun); // Try other cases
  309. cchRun = pRun->_cch;
  310. iFormat = pRun->_iFormat;
  311. ich = _ich;
  312. // Same run case. Note that there is an additional boundary case; if we
  313. // are the _end_ of one run, then the next run may have the necessary
  314. // format.
  315. if(ifmt == iFormat) // IP already has correct fmt
  316. {
  317. pRun->_cch += cch;
  318. _ich += cch; // Inc offset to keep in sync
  319. return cch;
  320. }
  321. if(_ich == pRun->_cch && _iRun < _pRuns->Count() - 1)
  322. {
  323. AdjustForward();
  324. pRun = Elem(_iRun);
  325. Assert(pRun);
  326. if(pRun->_iFormat == ifmt)
  327. {
  328. pRun->_cch += cch;
  329. _ich += cch;
  330. return cch;
  331. }
  332. AdjustBackward();
  333. }
  334. // Prior run case (needed when formatting change occurs on line break
  335. // and caret is at beginning of new line)
  336. if(!ich && _iRun > 0 ) // IP at start of run
  337. {
  338. pRunPrev = GetPtr(pRun, -1);
  339. if( ifmt == pRunPrev->_iFormat) // Prev run has same format:
  340. { // add count to prev run and
  341. pRunPrev->_cch += cch;
  342. return cch;
  343. }
  344. }
  345. // Create new run[s] cases. There is a special case for a format
  346. // run of zero length: just re-use it.
  347. if(!pRun->_cch)
  348. {
  349. // This assert has been toned down to ignore a plain text control
  350. // being forced into IME Rich Composition.
  351. AssertSz( /* FALSE */ pRun->_iFormat == -1 && Count() == 1,
  352. "CFormatRunPtr::InsertFormat: 0-length run");
  353. pf->Release(pRun->_iFormat);
  354. }
  355. else // Need to create 1 or 2 new
  356. { // runs for insertion
  357. cRun = 1; // Default 1 new run
  358. if(ich && ich < cchRun) // Not at beginning or end of
  359. cRun++; // run, so need two new runs
  360. // The following insert call adds one or two runs at the current
  361. // position. If the new run is inserted at the beginning or end
  362. // of the current run, the latter needs no change; however, if
  363. // the new run splits the current run in two, both pieces have
  364. // to be updated (cRun == 2 case).
  365. pRun = Insert(cRun); // Insert cRun run(s)
  366. if(!pRun) // Out of RAM. Can't insert
  367. { // new format, but can keep
  368. _ich += cch; // run ptr and format runs
  369. GetRun(0)->_cch += cch; // valid. Note: doesn't
  370. return cch; // signal any error; no access
  371. } // to _ped->_fErrSpace
  372. if(ich) // Not at beginning of run,
  373. {
  374. pRunPrev = pRun; // Previous run is current run
  375. IncPtr(pRun); // New run is next run
  376. VALIDATE_PTR(pRun);
  377. pRun->_cch = cch; // Keep NextRun() invariant happy
  378. NextRun(); // Point this runptr at it too
  379. if(cRun == 2) // Are splitting current run
  380. { // _iFormat's are already set
  381. AssertSz(pRunPrev->_iFormat == iFormat,
  382. "CFormatRunPtr::InsertFormat: bad format inserted");
  383. pRunPrev->_cch = ich; // Divide up original cch
  384. GetPtr(pRun, 1)->_cch // accordingly
  385. = cchRun - ich;
  386. pf->AddRef(iFormat); // Addref iFormat for extra run
  387. }
  388. }
  389. }
  390. StoreNewRunData:
  391. pf->AddRef(ifmt); // Addref ifmt
  392. ZeroMemory(pRun, sizeof(*pRun));
  393. pRun->_iFormat = ifmt; // Store insert format and count
  394. pRun->_cch = cch; // of new run
  395. _ich = cch; // cp goes at end of insertion
  396. return cch;
  397. }
  398. /*
  399. * CFormatRunPtr::MergeRuns(iRun, pf)
  400. *
  401. * @mfunc
  402. * Merge adjacent runs that have the same format between this run
  403. * <md CFormatRunPtr::_iRun> and that for <p iRun>
  404. *
  405. * @comm
  406. * Changes this run ptr
  407. */
  408. void CFormatRunPtr::MergeRuns(
  409. LONG iRun, //@parm last run to check (can preceed or follow
  410. // <md CFormatRunPtr::_iRun>)
  411. IFormatCache *pf) //@parm pointer to IFormatCache to ReleaseFormat
  412. {
  413. TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CFormatRunPtr::MergeRuns");
  414. LONG cch;
  415. LONG cRuns = iRun - _iRun;
  416. LONG iDirection = 1; // Default going forward
  417. CFormatRun *pRun;
  418. _TEST_INVARIANT_
  419. if(cRuns < 0)
  420. {
  421. cRuns = -cRuns;
  422. iDirection = -1;
  423. }
  424. if(!IsValid()) // Allow starting run to be
  425. { // invalid
  426. Assert(FALSE); // I think this is old...
  427. ChgRun(iDirection);
  428. }
  429. while(cRuns--)
  430. {
  431. if(!GetRun(0)->_cch && !_iRun && _iRun < Count() - 1)
  432. {
  433. if(iDirection > 0)
  434. PrevRun();
  435. Remove(1, pf);
  436. continue;
  437. }
  438. pRun = GetRun(0); // Save the current run
  439. if(!ChgRun(iDirection)) // Go to next (or prev) run
  440. return; // No more runs to check
  441. if(pRun->SameFormat(GetRun(0)))
  442. { // Like formatted runs
  443. if(iDirection > 0) // Point at the first of the
  444. PrevRun(); // two runs
  445. cch = GetRun(0)->_cch; // Save its count
  446. Remove(1, pf); // Remove it
  447. GetRun(0)->_cch += cch; // Add its count to the other's,
  448. } // i.e., they're merged
  449. }
  450. }
  451. /*
  452. * CFormatRunPtr::Remove(cRun, flag, pf)
  453. *
  454. * @mfunc
  455. * Remove cRun runs starting at _iRun
  456. */
  457. void CFormatRunPtr::Remove(
  458. LONG cRun,
  459. IFormatCache *pf)
  460. {
  461. CFormatRun *pRun = GetRun(0); // Point at run(s) to delete
  462. for(LONG j = 0; j < cRun; j++, IncPtr(pRun))
  463. pf->Release(pRun->_iFormat); // Decrement run reference count
  464. CRunPtr<CFormatRun>::Remove(cRun);
  465. }
  466. /*
  467. * CFormatRunPtr::SetFormat(ifmt, cch, pf, pLevel)
  468. *
  469. * @mfunc
  470. * Set format for up to cch chars of this run to ifmt, splitting run
  471. * as needed, and returning the character count actually processed
  472. *
  473. * @rdesc
  474. * character count of run chunk processed, CP_INFINITE on failure
  475. * this points at next run
  476. *
  477. * Comments:
  478. * Changes this run ptr. cch must be >= 0.
  479. *
  480. * Note 1) for the first run in a series, _ich may not = 0, and 2) cch
  481. * may be <lt>, =, or <gt> the count remaining in the run. The algorithm
  482. * doesn't split runs when the format doesn't change.
  483. */
  484. LONG CFormatRunPtr::SetFormat(
  485. LONG ifmt, //@parm format index to use
  486. LONG cch, //@parm character count of remaining format range
  487. IFormatCache * pf, //@parm pointer to IFormatCache to
  488. CBiDiLevel* pLevel) //@parm pointer to BiDi level structure
  489. {
  490. TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CFormatRunPtr::SetFormat");
  491. // AddRefFormat/ReleaseFormat
  492. LONG cchChunk;
  493. LONG iFormat;
  494. CFormatRun * pRun;
  495. CFormatRun * pChgRun; // run that was reformatted
  496. CBiDiLevel level;
  497. _TEST_INVARIANT_
  498. if(!IsValid())
  499. return 0;
  500. pRun = GetRun(0); // pRun points at current run in
  501. cchChunk = pRun->_cch - _ich; // this function
  502. iFormat = pRun->_iFormat;
  503. level = pRun->_level;
  504. pChgRun = pRun;
  505. AssertSz(cch, "Have to have characters to format!");
  506. AssertSz(pRun->_cch, "uh-oh, empty format run detected");
  507. if(ifmt != iFormat || (pLevel && level != *pLevel)) // New and current formats differ
  508. {
  509. AssertSz(cchChunk, "Caller did not call AdjustForward");
  510. if(_ich) // Not at either end of run: need
  511. { // to split into two runs of
  512. if(!(pRun = Insert(1))) // counts _ich and _pRun->_cch
  513. { // - _ich, respectively
  514. return CP_INFINITE; // Out of RAM: do nothing; just
  515. } // keep current format
  516. pRun->_cch = _ich;
  517. pRun->_iFormat = iFormat; // New run has same format
  518. pRun->_level = level; // and same level
  519. pf->AddRef(iFormat); // Increment format ref count
  520. NextRun(); // Go to second (original) run
  521. IncPtr(pRun); // Point pRun at current run
  522. pRun->_cch = cchChunk; // Note: IncPtr is a bit more
  523. pChgRun = pRun;
  524. } // efficient than GetRun, but
  525. // trickier to code right
  526. if(cch < cchChunk) // cch doesn't cover whole run:
  527. { // need to split into two runs
  528. if(!(pRun = Insert(1)))
  529. {
  530. // Out of RAM, so formatting's wrong, oh well. We actually
  531. // "processed" all of the characters, so return that (though
  532. // the tail end formatting isn't split out right)
  533. return cch;
  534. }
  535. pRun->_cch = cch; // New run gets the cch
  536. pRun->_iFormat = ifmt; // and the new format
  537. pChgRun = pRun;
  538. IncPtr(pRun); // Point pRun at current run
  539. pRun->_cch = cchChunk - cch; // Set leftover count
  540. }
  541. else // cch as big or bigger than
  542. { // current run
  543. pf->Release(iFormat); // Free run's current format
  544. pRun->_iFormat = ifmt; // Change it to new format
  545. pChgRun = pRun;
  546. } // May get merged later
  547. pf->AddRef(ifmt); // Increment new format ref count
  548. }
  549. else if(!cchChunk)
  550. {
  551. pRun->_cch += cch; // Add cch to end of current run
  552. cchChunk = cch; // Report that all cch are done
  553. IncPtr(pRun);
  554. pRun->_cch -= cch; // Remove count from next run
  555. if(!pRun->_cch) // Next run is now empty, so
  556. { // remove it
  557. _iRun++;
  558. Remove(1, pf);
  559. _iRun--; // Backup to start run
  560. }
  561. }
  562. // Record embedding level to changed run
  563. if (pLevel)
  564. pChgRun->_level = *pLevel;
  565. cch = min(cch, cchChunk);
  566. Move(cch);
  567. AdjustForward();
  568. return cch;
  569. }
  570. /*
  571. * CFormatRunPtr::GetFormat()
  572. *
  573. * @mfunc
  574. * return format index at current run pointer position
  575. *
  576. * @rdesc
  577. * current format index
  578. */
  579. short CFormatRunPtr::GetFormat() const
  580. {
  581. TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CFormatRunPtr::GetFormat");
  582. _TEST_INVARIANT_
  583. return IsValid() ? GetRun(0)->_iFormat : -1;
  584. }
  585. /*
  586. * CFormatRunPtr::SplitFormat(IFormatCache*)
  587. *
  588. * @mfunc
  589. * Split a format run
  590. *
  591. * @rdesc
  592. * If succeeded the run pointer moves to the next splitted run
  593. */
  594. void CFormatRunPtr::SplitFormat(IFormatCache* pf)
  595. {
  596. if (!_ich || _ich == GetRun(0)->_cch)
  597. return;
  598. CFormatRun* pRun = GetRun(0);
  599. LONG iFormat = pRun->_iFormat;
  600. LONG cch = pRun->_cch - _ich;
  601. CBiDiLevel level = pRun->_level;
  602. if (pRun = Insert(1))
  603. {
  604. pRun->_cch = _ich;
  605. pRun->_iFormat = iFormat;
  606. pRun->_level = level;
  607. pf->AddRef(iFormat);
  608. NextRun();
  609. IncPtr(pRun);
  610. pRun->_cch = cch;
  611. }
  612. }
  613. /*
  614. * CFormatRunPtr::SetLevel(level)
  615. *
  616. * @mfunc
  617. * Set run's embedding level
  618. */
  619. void CFormatRunPtr::SetLevel (CBiDiLevel& level)
  620. {
  621. if (!IsValid())
  622. {
  623. Assert(FALSE);
  624. return;
  625. }
  626. CFormatRun* pRun = GetRun(0);
  627. if (pRun)
  628. pRun->_level = level;
  629. }
  630. BYTE CFormatRunPtr::GetLevel (CBiDiLevel* pLevel)
  631. {
  632. CFormatRun* pRun;
  633. if (!IsValid() || !(pRun = GetRun(0)))
  634. {
  635. Assert(FALSE);
  636. if (pLevel)
  637. {
  638. pLevel->_value = 0;
  639. pLevel->_fStart = FALSE;
  640. }
  641. return 0;
  642. }
  643. if (pLevel)
  644. *pLevel = pRun->_level;
  645. return pRun->_level._value;
  646. }
  647. /*
  648. * CFormatRunPtr::AdjustFormatting(cch, pf)
  649. *
  650. * @mfunc
  651. * Use the same format index for the cch chars at this run ptr
  652. * as that immediately preceeding it (if on run edge).
  653. *
  654. * @devnote
  655. * This runptr ends up pointing at what was the preceeding run,
  656. * since the current run has been moved into the preceeding run.
  657. *
  658. * FUTURE: might be better to take the cch equal to chars in
  659. * the following run.
  660. */
  661. void CFormatRunPtr::AdjustFormatting(
  662. LONG cch, //@parm Count of chars to extend formatting
  663. IFormatCache *pf) //@parm Format cache ptr for AddRef/Release
  664. {
  665. if(!IsValid())
  666. return; // Nothing to merge
  667. CFormatRunPtr rp(*this);
  668. CBiDiLevel level;
  669. // Move this run ptr to end of
  670. AdjustBackward(); // preceeding run (if at run edge)
  671. rp.AdjustForward(); // (merge may delete run at entry)
  672. if(_iRun != rp._iRun) // On a format edge: copy previous
  673. { // format index over
  674. GetLevel(&level);
  675. rp.SetFormat(GetFormat(), cch, pf, &level); // Format cch chars at this
  676. rp.MergeRuns(_iRun, pf); // runptr
  677. }
  678. }
  679. ///////////////////////////// CCFRunPtr ///////////////////////////////
  680. CCFRunPtr::CCFRunPtr(const CRchTxtPtr &rtp)
  681. : CFormatRunPtr(rtp._rpCF)
  682. {
  683. _ped = rtp.GetPed();
  684. }
  685. CCFRunPtr::CCFRunPtr(const CFormatRunPtr &rp, CTxtEdit *ped)
  686. : CFormatRunPtr(rp)
  687. {
  688. _ped = ped;
  689. }
  690. /*
  691. * CCFRunPtr::IsMask(dwMask, MaskOp)
  692. *
  693. * @mfunc
  694. * return TRUE according to the mask operation MaskOp operating on
  695. * _dwEffects.
  696. *
  697. * @rdesc
  698. * TRUE if bits in CCharFormat::dwEffects correspond to those in dwMask
  699. */
  700. BOOL CCFRunPtr::IsMask(
  701. DWORD dwMask, //@parm Bit mask to use on dwEffects
  702. MASKOP MaskOp) //@parm Logic operation for bits
  703. {
  704. DWORD dwEffects = _ped->GetCharFormat(GetFormat())->_dwEffects;
  705. if(MaskOp == MO_EXACT) // Bit masks must be identical
  706. return dwEffects == dwMask;
  707. dwEffects &= dwMask;
  708. if(MaskOp == MO_OR) // TRUE if one or more effect bits
  709. return dwEffects != 0; // identified by mask are on
  710. if(MaskOp == MO_AND) // TRUE if all effect bits
  711. return dwEffects == dwMask; // identified by mask are on
  712. AssertSz(FALSE, "CCFRunPtr::IsMask: illegal mask operation");
  713. return FALSE;
  714. }
  715. /*
  716. * CCFRunPtr::IsInHidden()
  717. *
  718. * @mfunc
  719. * return TRUE if CCharFormat for this run ptr has CFE_HIDDEN bit set
  720. *
  721. * @rdesc
  722. * TRUE if CCharFormat for this run ptr has CFE_HIDDEN bit set
  723. */
  724. BOOL CCFRunPtr::IsInHidden()
  725. {
  726. if (!IsValid())
  727. return FALSE; // No format run, not hidden
  728. AdjustForward();
  729. BOOL fHidden = IsHidden();
  730. if(_ich)
  731. return fHidden;
  732. AdjustBackward();
  733. return fHidden && IsHidden();
  734. }
  735. /*
  736. * CCFRunPtr::FindUnhidden()
  737. *
  738. * @mfunc
  739. * Find nearest expanded CF going forward. If none, find nearest going
  740. * backward. If none, go to start of document
  741. *
  742. * @rdesc
  743. * cch to nearest expanded CF as explained in function description
  744. *
  745. * @devnote
  746. * changes this run ptr
  747. */
  748. LONG CCFRunPtr::FindUnhidden()
  749. {
  750. LONG cch = FindUnhiddenForward();
  751. if(IsHidden())
  752. cch = FindUnhiddenBackward();
  753. return cch;
  754. }
  755. /*
  756. * CCFRunPtr::FindUnhiddenForward()
  757. *
  758. * @mfunc
  759. * Find nearest expanded CF going forward. If none, go to EOD
  760. *
  761. * @rdesc
  762. * cch to nearest expanded CF going forward
  763. *
  764. * @devnote
  765. * changes this run ptr
  766. */
  767. LONG CCFRunPtr::FindUnhiddenForward()
  768. {
  769. LONG cch = 0;
  770. AdjustForward();
  771. while(IsHidden())
  772. {
  773. cch += GetCchLeft();
  774. if(!NextRun())
  775. break;
  776. }
  777. return cch;
  778. }
  779. /*
  780. * CCFRunPtr::MatchFormatSignature
  781. *
  782. * @mfunc
  783. * Match the current format's font signature with the script (index to codepage).
  784. * It takes care single-codepage fonts which implicitly supports ASCII range.
  785. *
  786. * @rdesc
  787. * return how font matched
  788. */
  789. inline int CCFRunPtr::MatchFormatSignature (
  790. const CCharFormat* pCF,
  791. int iCharRep,
  792. int iMatchCurrent,
  793. QWORD * pqwFontSig)
  794. {
  795. QWORD qwFontSig = 0;
  796. if (GetFontSignatureFromFace(pCF->_iFont, &qwFontSig) != 0)
  797. {
  798. if (pqwFontSig)
  799. *pqwFontSig = qwFontSig;
  800. if (iMatchCurrent & MATCH_ASCII && fc().GetInfoFlags(pCF->_iFont).fNonBiDiAscii)
  801. return MATCH_ASCII;
  802. if (FontSigFromCharRep(iCharRep) & ~FASCII & qwFontSig)
  803. return MATCH_FONT_SIG;
  804. }
  805. return 0;
  806. }
  807. /*
  808. * CCFRunPtr::GetPreferredFontInfo(iCharRep, &iCharRepRet, &iFont, &yHeight, &bPitchAndFamily,
  809. * iFormat, iMatchCurrent, piFormatOut )
  810. *
  811. * @mfunc
  812. * Find the preferred font for the given code page around the range.
  813. *
  814. * @rdesc
  815. * boolean true if suitable font found, false otherwise.
  816. */
  817. bool CCFRunPtr::GetPreferredFontInfo(
  818. BYTE iCharRep,
  819. BYTE & iCharRepRet,
  820. SHORT& iFont,
  821. SHORT& yHeight, // return in twips
  822. BYTE& bPitchAndFamily,
  823. int iFormat,
  824. int iMatchCurrent,
  825. int *piFormatOut)
  826. {
  827. int i;
  828. bool fr = false;
  829. static int const MAX_FONTSEARCH = 256;
  830. const CCharFormat *pCF;
  831. const CCharFormat *pCFCurrent;
  832. const CCharFormat *pCFPrevious = NULL;
  833. int iMatch = 0; // how signature match?
  834. QWORD qwFontSigCurrent = 0;
  835. SHORT yNewHeight = 0;
  836. bool fUseUIFont = _ped->fUseUIFont() || _ped->Get10Mode();
  837. Assert(!(iMatchCurrent & MATCH_ASCII) || iCharRep == ANSI_INDEX);
  838. if(_ped->fUseUIFont())
  839. pCFCurrent = _ped->GetCharFormat(-1); // Plain text or UI font specified
  840. else
  841. pCFCurrent = _ped->GetCharFormat(iFormat != -1 ? iFormat : GetFormat());
  842. if (iMatchCurrent == GET_HEIGHT_ONLY) // Just do the font autosizing.
  843. {
  844. fr = true;
  845. pCF = NULL;
  846. goto DO_SIZE;
  847. }
  848. if ((iMatchCurrent & MATCH_FONT_SIG) &&
  849. (iMatch = MatchFormatSignature(pCFCurrent, iCharRep, iMatchCurrent, &qwFontSigCurrent)) != 0)
  850. {
  851. pCF = pCFCurrent; // Setup to use it
  852. }
  853. else
  854. {
  855. int iFormatOut;
  856. // Try searching backwards
  857. if (IsValid()) // If doc has CF runs
  858. AdjustBackward();
  859. i = MAX_FONTSEARCH; // Don't be searching for years
  860. iFormatOut = GetFormat();
  861. pCF = _ped->GetCharFormat(iFormatOut);
  862. while (i--)
  863. {
  864. if(iCharRep == pCF->_iCharRep) // Equal charset ids?
  865. {
  866. pCFPrevious = pCF;
  867. break;
  868. }
  869. if (!PrevRun()) // Done searching?
  870. break;
  871. iFormatOut = GetFormat();
  872. pCF = _ped->GetCharFormat(iFormatOut);
  873. }
  874. pCF = pCFPrevious;
  875. if (piFormatOut && pCF)
  876. {
  877. *piFormatOut = iFormatOut;
  878. return true; // Done since we only ask for the format.
  879. }
  880. }
  881. // Try match charset if requested
  882. if(!pCF && iMatchCurrent == MATCH_CURRENT_CHARSET)
  883. {
  884. CCcs* pccs = _ped->GetCcs(pCFCurrent, W32->GetYPerInchScreenDC());
  885. if (pccs)
  886. {
  887. if(pccs->BestCharRep(iCharRep, DEFAULT_INDEX, MATCH_CURRENT_CHARSET) != DEFAULT_INDEX)
  888. pCF = pCFCurrent; // Current font can do it
  889. pccs->Release();
  890. }
  891. }
  892. // Try default document format
  893. if (!pCF)
  894. {
  895. pCF = _ped->GetCharFormat(-1);
  896. if(iCharRep != pCF->_iCharRep) // Diff charset ids?
  897. pCF = NULL;
  898. }
  899. DO_SIZE:
  900. yHeight = pCFCurrent->_yHeight; // Assume current height
  901. if (!pCF)
  902. {
  903. // Default to table if no match.
  904. fr = W32->GetPreferredFontInfo(
  905. iCharRep, fUseUIFont, iFont, (BYTE&)yNewHeight, bPitchAndFamily );
  906. if (!_ped->_fAutoFontSizeAdjust && iCharRep == THAI_INDEX)
  907. // Kick in font size adjusting in first bind to Thai.
  908. _ped->_fAutoFontSizeAdjust = TRUE;
  909. }
  910. if (pCF)
  911. {
  912. // Found previous or current font
  913. iFont = pCF->_iFont;
  914. bPitchAndFamily = pCF->_bPitchAndFamily;
  915. if (pCF == pCFCurrent && (iMatchCurrent & MATCH_FONT_SIG) &&
  916. (IsFECharRep(pCF->_iCharRep) && W32->IsFECodePageFont(qwFontSigCurrent) ||
  917. iMatch == MATCH_ASCII && iCharRep == ANSI_INDEX))
  918. {
  919. // The current font matches the requested signature.
  920. // If it's a East Asia or ASCII font, we leave the charset intact.
  921. iCharRepRet = pCF->_iCharRep;
  922. return true;
  923. }
  924. }
  925. if (_ped->_fAutoFontSizeAdjust && iFont != pCFCurrent->_iFont)
  926. {
  927. if (IsValid())
  928. {
  929. // If the last run format is available. We will scale the size relative to it.
  930. AdjustBackward();
  931. if (GetIch() > 0)
  932. {
  933. pCFCurrent = _ped->GetCharFormat(GetFormat());
  934. yHeight = pCFCurrent->_yHeight;
  935. }
  936. AdjustForward();
  937. }
  938. if (iFont != pCFCurrent->_iFont)
  939. {
  940. // Scale the height relative to the preceding format
  941. if (pCF)
  942. yNewHeight = GetFontLegitimateSize(iFont, fUseUIFont, iCharRep);
  943. if (yNewHeight)
  944. {
  945. // Get legitimate size of current font
  946. SHORT yDefHeight = GetFontLegitimateSize(pCFCurrent->_iFont,
  947. fUseUIFont, pCFCurrent->_iCharRep);
  948. // Calculate the new height relative to the current height
  949. if (yDefHeight)
  950. {
  951. if (fUseUIFont)
  952. {
  953. // For UIFont, we only convert from one preferred size to another preferred size.
  954. if (pCFCurrent->_yHeight / TWIPS_PER_POINT == yDefHeight)
  955. yHeight = yNewHeight * TWIPS_PER_POINT;
  956. }
  957. else
  958. yHeight = (SHORT)MulDiv(pCFCurrent->_yHeight, yNewHeight, yDefHeight);
  959. }
  960. }
  961. }
  962. }
  963. if (!yHeight)
  964. yHeight = (SHORT)MulDiv(pCFCurrent->_yHeight, yNewHeight, 10);
  965. return pCF || fr;
  966. }
  967. /*
  968. * CCFRunPtr::FindUnhiddenBackward()
  969. *
  970. * @mfunc
  971. * Find nearest expanded CF going backward. If none, go to BOD
  972. *
  973. * @rdesc
  974. * cch to nearest expanded CF going backward
  975. *
  976. * @devnote
  977. * changes this run ptr
  978. */
  979. LONG CCFRunPtr::FindUnhiddenBackward()
  980. {
  981. LONG cch = 0;
  982. AdjustBackward();
  983. while(IsHidden())
  984. {
  985. cch -= GetIch();
  986. if(!_iRun)
  987. break;
  988. _ich = 0;
  989. AdjustBackward();
  990. }
  991. return cch;
  992. }
  993. ///////////////////////////// CPFRunPtr ///////////////////////////////
  994. CPFRunPtr::CPFRunPtr(const CRchTxtPtr &rtp)
  995. : CFormatRunPtr(rtp._rpPF)
  996. {
  997. _ped = rtp.GetPed();
  998. }
  999. /*
  1000. * CPFRunPtr::FindHeading(cch, lHeading)
  1001. *
  1002. * @mfunc
  1003. * Find heading with number lHeading (e.g., = 1 for Heading 1) or above
  1004. * in a range starting at this PFrun pointer. If successful, this run
  1005. * ptr points at the matching run; else it remains unchanged.
  1006. *
  1007. * @rdesc
  1008. * cch to matching heading or tomBackward if not found
  1009. *
  1010. * @devnote
  1011. * changes this run ptr
  1012. */
  1013. LONG CPFRunPtr::FindHeading(
  1014. LONG cch, //@parm Max cch to move
  1015. LONG& lHeading) //@parm Lowest lHeading to match
  1016. {
  1017. LONG cchSave = cch;
  1018. LONG ichSave = _ich;
  1019. LONG iRunSave = _iRun;
  1020. LONG OutlineLevel;
  1021. Assert((unsigned)lHeading <= NHSTYLES);
  1022. if(!IsValid())
  1023. return tomBackward;
  1024. while(TRUE)
  1025. {
  1026. OutlineLevel = GetOutlineLevel();
  1027. if (!(OutlineLevel & 1) &&
  1028. (!lHeading || (lHeading - 1)*2 >= OutlineLevel))
  1029. {
  1030. lHeading = OutlineLevel/2 + 1; // Return heading # found
  1031. return cchSave - cch; // Return how far away it was
  1032. }
  1033. if(cch >= 0)
  1034. {
  1035. cch -= GetCchLeft();
  1036. if(cch <= 0 || !NextRun())
  1037. break;
  1038. }
  1039. else
  1040. {
  1041. cch += GetIch();
  1042. if(cch > 0 || !_iRun)
  1043. break;
  1044. AdjustBackward();
  1045. }
  1046. }
  1047. _ich = ichSave;
  1048. _iRun = iRunSave;
  1049. return tomBackward; // Didn't find desired heading
  1050. }
  1051. /*
  1052. * CPFRunPtr::FindRowEnd(TableLevel)
  1053. *
  1054. * @mfunc
  1055. * Advance this ptr just past table-row terminator that matches
  1056. * the passed-in table level
  1057. *
  1058. * @rdesc
  1059. * TRUE if matching table row end is found
  1060. *
  1061. * @devnote
  1062. * changes this run ptr only if TableLevel is found within cch chars
  1063. */
  1064. BOOL CPFRunPtr::FindRowEnd(
  1065. LONG TableLevel) //@parm Table level to match
  1066. {
  1067. LONG ichSave = _ich;
  1068. LONG iRunSave = _iRun;
  1069. Assert(IsValid());
  1070. do
  1071. {
  1072. if(IsTableRowDelimiter() && GetPF()->_bTableLevel == (BYTE)TableLevel)
  1073. {
  1074. NextRun(); // Bypass delimiter
  1075. return TRUE;
  1076. }
  1077. } while(NextRun());
  1078. _ich = ichSave; // Restore run ptr indices
  1079. _iRun = iRunSave;
  1080. return FALSE; // Didn't find desired heading
  1081. }
  1082. /*
  1083. * CPFRunPtr::IsCollapsed()
  1084. *
  1085. * @mfunc
  1086. * return TRUE if CParaFormat for this run ptr has PFE_COLLAPSED bit set
  1087. *
  1088. * @rdesc
  1089. * TRUE if CParaFormat for this run ptr has PFE_COLLAPSED bit set
  1090. */
  1091. BOOL CPFRunPtr::IsCollapsed()
  1092. {
  1093. return (_ped->GetParaFormat(GetFormat())->_wEffects & PFE_COLLAPSED) != 0;
  1094. }
  1095. /*
  1096. * CPFRunPtr::IsTableRowDelimiter()
  1097. *
  1098. * @mfunc
  1099. * return TRUE if CParaFormat for this run ptr has PFE_TABLEROWDELIMITER bit set
  1100. *
  1101. * @rdesc
  1102. * TRUE if CParaFormat for this run ptr has PFE_TABLEROWDELIMITER bit set
  1103. */
  1104. BOOL CPFRunPtr::IsTableRowDelimiter()
  1105. {
  1106. return (_ped->GetParaFormat(GetFormat())->_wEffects & PFE_TABLEROWDELIMITER) != 0;
  1107. }
  1108. /*
  1109. * CPFRunPtr::InTable()
  1110. *
  1111. * @mfunc
  1112. * return TRUE if CParaFormat for this run ptr has PFE_TABLE bit set
  1113. *
  1114. * @rdesc
  1115. * TRUE if CParaFormat for this run ptr has PFE_TABLE bit set
  1116. */
  1117. BOOL CPFRunPtr::InTable()
  1118. {
  1119. return (_ped->GetParaFormat(GetFormat())->_wEffects & PFE_TABLE) != 0;
  1120. }
  1121. /*
  1122. * CPFRunPtr::FindExpanded()
  1123. *
  1124. * @mfunc
  1125. * Find nearest expanded PF going forward. If none, find nearest going
  1126. * backward. If none, go to start of document
  1127. *
  1128. * @rdesc
  1129. * cch to nearest expanded PF as explained in function description
  1130. *
  1131. * @devnote
  1132. * Moves this run ptr the amount returned (cch)
  1133. */
  1134. LONG CPFRunPtr::FindExpanded()
  1135. {
  1136. LONG cch, cchRun;
  1137. for(cch = 0; IsCollapsed(); cch += cchRun) // Try to find expanded PF
  1138. { // run going forward
  1139. cchRun = GetCchLeft();
  1140. if(!NextRun()) // Aren't any
  1141. {
  1142. Move(-cch); // Go back to starting point
  1143. return FindExpandedBackward(); // Try to find expanded PF
  1144. } // run going backward
  1145. }
  1146. return cch;
  1147. }
  1148. /*
  1149. * CPFRunPtr::FindExpandedForward()
  1150. *
  1151. * @mfunc
  1152. * Find nearest expanded PF going forward. If none, go to EOD
  1153. *
  1154. * @rdesc
  1155. * cch to nearest expanded PF going forward
  1156. *
  1157. * @devnote
  1158. * advances this run ptr the amount returned (cch)
  1159. */
  1160. LONG CPFRunPtr::FindExpandedForward()
  1161. {
  1162. LONG cch = 0;
  1163. while(IsCollapsed())
  1164. {
  1165. LONG cchLeft = GetCchLeft();
  1166. _ich += cchLeft; // Update _ich in case
  1167. cch += cchLeft; // if(!NextRun()) breaks
  1168. if(!NextRun())
  1169. break;
  1170. }
  1171. return cch;
  1172. }
  1173. /*
  1174. * CPFRunPtr::FindExpandedBackward()
  1175. *
  1176. * @mfunc
  1177. * Find nearest expanded PF going backward. If none, go to BOD
  1178. *
  1179. * @rdesc
  1180. * cch to nearest expanded PF going backward
  1181. *
  1182. * @devnote
  1183. * Moves this run ptr the amount returned (cch)
  1184. */
  1185. LONG CPFRunPtr::FindExpandedBackward()
  1186. {
  1187. LONG cch = 0;
  1188. while(IsCollapsed())
  1189. {
  1190. cch -= GetIch();
  1191. _ich = 0;
  1192. if(!_iRun)
  1193. break;
  1194. AdjustBackward();
  1195. }
  1196. return cch;
  1197. }
  1198. /*
  1199. * CPFRunPtr::GetOutlineLevel()
  1200. *
  1201. * @mfunc
  1202. * Find outline level this rp is pointing at
  1203. *
  1204. * @rdesc
  1205. * Outline level this rp is pointing at
  1206. */
  1207. LONG CPFRunPtr::GetOutlineLevel()
  1208. {
  1209. const CParaFormat *pPF = _ped->GetParaFormat(GetFormat());
  1210. LONG OutlineLevel = pPF->_bOutlineLevel;
  1211. AssertSz(IsHeadingStyle(pPF->_sStyle) ^ (OutlineLevel & 1),
  1212. "CPFRunPtr::GetOutlineLevel: sStyle/bOutlineLevel mismatch");
  1213. return OutlineLevel;
  1214. }
  1215. /*
  1216. * CPFRunPtr::GetStyle()
  1217. *
  1218. * @mfunc
  1219. * Find style this rp is pointing at
  1220. *
  1221. * @rdesc
  1222. * Style this rp is pointing at
  1223. */
  1224. LONG CPFRunPtr::GetStyle()
  1225. {
  1226. const CParaFormat *pPF = _ped->GetParaFormat(GetFormat());
  1227. LONG Style = pPF->_sStyle;
  1228. AssertSz(IsHeadingStyle(Style) ^ (pPF->_bOutlineLevel & 1),
  1229. "CPFRunPtr::GetStyle: sStyle/bOutlineLevel mismatch");
  1230. return Style;
  1231. }
  1232. /*
  1233. * CPFRunPtr::ResolveRowStartPF()
  1234. *
  1235. * @mfunc
  1236. * Resolve table row start PF corresponding to the current table row
  1237. * end. Assumes that all table rows contained in the current row are
  1238. * resolved, which should be the case for nested tables in RTF.
  1239. *
  1240. * @rdesc
  1241. * TRUE iff success
  1242. */
  1243. BOOL CPFRunPtr::ResolveRowStartPF()
  1244. {
  1245. AdjustBackward();
  1246. LONG iFormat = GetFormat();
  1247. Assert(IsTableRowDelimiter());
  1248. const CParaFormat *pPF = NULL;
  1249. while(PrevRun())
  1250. {
  1251. pPF = _ped->GetParaFormat(GetFormat());
  1252. if((pPF->_wEffects & PFE_TABLEROWDELIMITER) && pPF->_iTabs == -1)
  1253. break;
  1254. }
  1255. Assert(IsTableRowDelimiter());
  1256. Assert(pPF->_iTabs == -1);
  1257. CFormatRun* pRun = GetRun(0);
  1258. IParaFormatCache *pf = GetParaFormatCache();
  1259. pf->Release(pRun->_iFormat);
  1260. pf->AddRef(iFormat);
  1261. pRun->_iFormat = iFormat;
  1262. return TRUE;
  1263. }
  1264. /*
  1265. * CPFRunPtr::GetMinTableLevel(cch)
  1266. *
  1267. * @mfunc
  1268. * Get the lowest table level in the range of cch chars from this
  1269. * run ptr. This is the lesser of the level ending at the range
  1270. * cpMost and that starting at cpMin. Leave this run ptr at cpMin.
  1271. *
  1272. * @rdesc
  1273. * Lowest table level in the cch chars from this run ptr
  1274. */
  1275. LONG CPFRunPtr::GetMinTableLevel(
  1276. LONG cch) //@parm cch to check for table level
  1277. {
  1278. if(cch > 0)
  1279. AdjustBackward();
  1280. const CParaFormat *pPF = GetPF();
  1281. LONG Level = pPF->_bTableLevel; // Default: level at active end
  1282. if(cch)
  1283. {
  1284. Move(-cch); // Go find table level at other
  1285. pPF = GetPF(); // end of range
  1286. if(pPF->_bTableLevel < Level)
  1287. Level = pPF->_bTableLevel;
  1288. if(cch < 0) // Range active end at cpMin
  1289. Move(cch); // Start at cpMin
  1290. }
  1291. AssertSz(Level >= 0, "CPFRunPtr::GetMinTableLevel: invalid table level");
  1292. return Level;
  1293. }
  1294. /*
  1295. * CPFRunPtr::GetTableLevel()
  1296. *
  1297. * @mfunc
  1298. * Get table level this run ptr is at
  1299. *
  1300. * @rdesc
  1301. * Table level this run ptr is at
  1302. */
  1303. LONG CPFRunPtr::GetTableLevel()
  1304. {
  1305. const CParaFormat *pPF = _ped->GetParaFormat(GetFormat());
  1306. AssertSz(!(pPF->_wEffects & PFE_TABLE) || pPF->_bTableLevel > 0,
  1307. "CPFRunPtr::GetTableLevel: invalid table level");
  1308. return pPF->_bTableLevel;
  1309. }