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.

2607 lines
67 KiB

  1. /*
  2. * @doc INTERNAL
  3. *
  4. * @module OLS.CPP -- COls LineServices object class
  5. *
  6. * Authors:
  7. * Murray Sargent: initial coding up to nonLS RichEdit functionality
  8. * (with lots of help from RickSa's ols code)
  9. * Keith Curtis and Worachai Chaoweeraprasit: complex script support,
  10. * etc.
  11. *
  12. * @todo
  13. * 1) Fix table selection
  14. * 2) What are we to do with RTL tables? Word has a very different model
  15. * 3) What we should give for LSCHP.dcpMaxContext
  16. *
  17. * Copyright (c) 1997-1999 Microsoft Corporation. All rights reserved.
  18. */
  19. #include "_common.h"
  20. #include "_edit.h"
  21. #include "_font.h"
  22. #include "_render.h"
  23. #include "_osdc.h"
  24. #include "_dfreeze.h"
  25. #include "_tomfmt.h"
  26. #include "_ols.h"
  27. #include "_clasfyc.h"
  28. #include "_uspi.h"
  29. #include "_txtbrk.h"
  30. #include "lskysr.h"
  31. #ifdef LINESERVICES
  32. ASSERTDATA
  33. // Guess at the number of characters on the line
  34. const int cchLineHint = 66;
  35. #define OBJID_OLE 0
  36. #define OBJID_REVERSE 1
  37. #define OBJID_COUNT 2
  38. const WCHAR wchObjectEnd = 0x9F;
  39. const WCHAR rgchObjectEnd[] = {wchObjectEnd};
  40. #define MAX_OBJ_DEPTH 3
  41. extern const LSCBK lscbk;
  42. // Kinsoku break pair information
  43. extern const INT g_cKinsokuCategories;
  44. CLineServices *g_plsc = NULL; // LineServices Context
  45. COls* g_pols = NULL; // COls ptr
  46. const LSBRK rglsbrkDefault[] =
  47. {
  48. 0,0, // Always prohibited
  49. 0,1, // OK across blanks
  50. 1,1 // Always allowed
  51. };
  52. // prototypes
  53. void EmitBrace(COls* pols, PLSCHP pchp, BOOL* pfHid, DWORD* pcch, PLSRUN* pprun, LPCWSTR* plpwch, int id, LPCWSTR str);
  54. void DupShapeState(PLSRUN prun, LONG cch);
  55. // public inline functions
  56. //
  57. // Emitting fake brace to LS
  58. inline void EmitBrace(
  59. COls* pols,
  60. PLSCHP pchp,
  61. BOOL* pfHid,
  62. DWORD* pcch,
  63. PLSRUN* pprun,
  64. LPCWSTR* plpwch,
  65. int id,
  66. LPCWSTR str)
  67. {
  68. ZeroMemory(pchp, sizeof(*pchp));
  69. pchp->idObj = (WORD)id;
  70. *pfHid = 0;
  71. *pcch = 1;
  72. *pprun = pols->GetPlsrun(0, pols->_pme->GetCF(), FALSE);
  73. *plpwch = str;
  74. }
  75. // Duplicate shaping state to each runs in the chain
  76. // note: this macro used only by GetGlyph and GetGlyphPosition
  77. inline void DupShapeState(
  78. PLSRUN prun,
  79. LONG cch)
  80. {
  81. PLSRUN pnext = prun->_pNext;
  82. LONG cpEnd = prun->_cp + cch;
  83. while (pnext && pnext->_cp < cpEnd)
  84. {
  85. CopyMemory(&pnext->_a, &prun->_a, sizeof(SCRIPT_ANALYSIS));
  86. pnext->SetFallback(prun->IsFallback());
  87. prun = pnext;
  88. pnext = prun->_pNext;
  89. }
  90. Assert(!pnext && prun->_cp < cpEnd);
  91. }
  92. LONG COls::GetCpLsFromCpRe(
  93. LONG cpRe)
  94. {
  95. if (_rgcp.Count() == 0)
  96. return cpRe;
  97. LONG *pcp = _rgcp.Elem(0);
  98. for(LONG cpLs = cpRe; cpLs >= *pcp; pcp++)
  99. cpLs++;
  100. return cpLs;
  101. }
  102. LONG COls::GetCpReFromCpLs(
  103. LONG cpLs
  104. )
  105. {
  106. if (_rgcp.Count() == 0)
  107. return cpLs;
  108. LONG *pcp = _rgcp.Elem(0);
  109. for(int dcp = 0; cpLs > *pcp; pcp++)
  110. dcp--;
  111. return cpLs + dcp;
  112. }
  113. #ifdef DEBUG
  114. //#define DEBUG_BRACE
  115. #endif
  116. // return TRUE if braces added
  117. BOOL COls::AddBraceCp(long cpLs)
  118. {
  119. if (_rgcp.Count() == 0)
  120. {
  121. long *pcp = _rgcp.Insert(0, 1);
  122. *pcp = tomForward;
  123. }
  124. long *pcp = _rgcp.Elem(0);
  125. long iel = 0;
  126. while (cpLs > pcp[iel])
  127. iel++;
  128. if (cpLs < pcp[iel])
  129. {
  130. pcp = _rgcp.Insert(iel, 1);
  131. *pcp = cpLs;
  132. return TRUE;
  133. }
  134. return FALSE;
  135. }
  136. // return number of braces before cp
  137. //
  138. LONG COls::BracesBeforeCp(LONG cpLs)
  139. {
  140. LONG iel, cbr = 0;
  141. LONG* pcp;
  142. if (!cpLs || (iel = _rgcp.Count()) < 2)
  143. return 0;
  144. iel -= 2; // exclude the last tomForward one and make a count an index
  145. cpLs--; // start with the cp preceding given cp
  146. pcp = _rgcp.Elem(0);
  147. while (iel > -1 && pcp[iel] > cpLs) // search the first one
  148. iel--;
  149. while (iel > -1 && pcp[iel] == cpLs) // continue counting
  150. {
  151. iel--;
  152. cpLs--;
  153. cbr++;
  154. }
  155. return cbr;
  156. }
  157. /*
  158. * SetRun(plsrun)
  159. *
  160. * @func
  161. * Do whatever is needed to initialize the measurer (pme) to the lsrun
  162. * givin by plsrun and return whether the run is for autonumbering.
  163. *
  164. * @rdesc
  165. * TRUE if plsrun refers to an autonumbering run
  166. */
  167. BOOL COls::SetRun(PLSRUN plsrun)
  168. {
  169. LONG cp = plsrun->_cp;
  170. _pme->SetCp(cp & 0x7FFFFFFF);
  171. return plsrun->IsBullet();
  172. }
  173. /*
  174. * IsSelected()
  175. *
  176. * @mfunc
  177. * return whether or not the run should be drawn as selected.
  178. *
  179. */
  180. CLsrun::IsSelected(void)
  181. {
  182. if (!_fSelected)
  183. return FALSE;
  184. CRenderer *pre = g_pols->GetRenderer();
  185. Assert(pre->IsRenderer());
  186. return pre->_fRenderSelection ? TRUE : FALSE;
  187. }
  188. /*
  189. * CreatePlsrun (void)
  190. *
  191. * @func
  192. * Creates a PLSRUN. Is a little tricky because we allocate them in
  193. * chunks.
  194. *
  195. * @rdesc
  196. */
  197. const int cplsrunAlloc = 8;
  198. PLSRUN COls::CreatePlsrun()
  199. {
  200. CLsrunChunk *plsrunChunk = 0;
  201. //First, find a chunk to use
  202. int cchunk = _rglsrunChunk.Count();
  203. for (int ichunk = 0; cchunk && ichunk < cchunk; ichunk++)
  204. {
  205. plsrunChunk = _rglsrunChunk.Elem(ichunk);
  206. if (plsrunChunk->_cel < cplsrunAlloc)
  207. break;
  208. }
  209. if (!cchunk || ichunk == cchunk || plsrunChunk->_cel == cplsrunAlloc)
  210. {
  211. CLsrun *rglsrun = new CLsrun[cplsrunAlloc];
  212. if (rglsrun)
  213. {
  214. plsrunChunk = _rglsrunChunk.Add(1, 0);
  215. if (!plsrunChunk)
  216. {
  217. delete[] rglsrun;
  218. return 0;
  219. }
  220. plsrunChunk->_prglsrun = rglsrun;
  221. }
  222. else
  223. return 0;
  224. }
  225. return &plsrunChunk->_prglsrun[plsrunChunk->_cel++];
  226. }
  227. /*
  228. * GetPlsrun(cp, pCF, fAutoNumber)
  229. *
  230. * @func
  231. * Return plsrun for info in run. The structure contains the starting cp
  232. * of the run and the script analysis if Uniscribe is activated. The
  233. * analysis information is needed by subsequent callbacks - GetGlyphs and
  234. * GetGlyphPositions to be passed to Uniscribe in order to shape and
  235. * position glyphs correctly for complex scripts.
  236. *
  237. * @rdesc
  238. * plsrun corresponding to info in arguments
  239. */
  240. PLSRUN COls::GetPlsrun(
  241. LONG cp,
  242. const CCharFormat *pCF,
  243. BOOL fAutoNumber)
  244. {
  245. if(fAutoNumber)
  246. cp |= CP_BULLET;
  247. CLsrun *plsrun = CreatePlsrun();
  248. if (plsrun)
  249. {
  250. ZeroMemory(plsrun, sizeof(CLsrun));
  251. plsrun->_pCF = pCF;
  252. plsrun->_cp = fAutoNumber ? _cp | CP_BULLET : cp;
  253. LONG cpSelMin, cpSelMost;
  254. _pme->GetPed()->GetSelRangeForRender(&cpSelMin, &cpSelMost);
  255. plsrun->SetSelected(!plsrun->IsBullet() && cp >= cpSelMin && cp < cpSelMost);
  256. if (pCF->_wScript && !_pme->GetPasswordChar())
  257. {
  258. CUniscribe* pusp = _pme->Getusp();
  259. Assert(pusp);
  260. const SCRIPT_PROPERTIES* psp = pusp->GeteProp(pCF->_wScript);
  261. plsrun->_a.eScript = (pCF->_wScript < SCRIPT_MAX_COUNT) ? pCF->_wScript : 0;
  262. plsrun->_a.fRTL = !psp->fNumeric && (IsBiDiCharSet(pCF->_bCharSet) || IsBiDiCharSet(psp->bCharSet));
  263. plsrun->_a.fLogicalOrder = TRUE;
  264. }
  265. }
  266. return plsrun;
  267. }
  268. /*
  269. * COls::~COls()
  270. *
  271. * @mfunc
  272. * Destructor
  273. */
  274. COls::~COls()
  275. {
  276. for (int ichunk = 0, cchunk = _rglsrunChunk.Count(); ichunk < cchunk; ichunk++)
  277. delete []_rglsrunChunk.Elem(ichunk)->_prglsrun;
  278. DestroyLine(NULL);
  279. if (g_plsc)
  280. LsDestroyContext(g_plsc);
  281. }
  282. /*
  283. * COls::Init(pme)
  284. *
  285. * @mfunc
  286. * Initialize this LineServices object
  287. *
  288. * @rdesc
  289. * HRESULT = (success) ? NOERROR : E_FAIL
  290. */
  291. HRESULT COls::Init(
  292. CMeasurer *pme)
  293. {
  294. _pme = pme;
  295. if(g_plsc)
  296. return NOERROR;
  297. // Build LS context to create
  298. LSCONTEXTINFO lsctxinf;
  299. // Setup object handlers
  300. LSIMETHODS vlsctxinf[OBJID_COUNT];
  301. vlsctxinf[OBJID_OLE] = vlsimethodsOle;
  302. if(LsGetReverseLsimethods(&vlsctxinf[OBJID_REVERSE]) != lserrNone)
  303. return E_FAIL;
  304. lsctxinf.cInstalledHandlers = OBJID_COUNT;
  305. lsctxinf.pInstalledHandlers = &vlsctxinf[0];
  306. // Set default and all other characters to 0xFFFF
  307. memset(&lsctxinf.lstxtcfg, 0xFF, sizeof(lsctxinf.lstxtcfg));
  308. lsctxinf.fDontReleaseRuns = TRUE;
  309. lsctxinf.lstxtcfg.cEstimatedCharsPerLine = cchLineHint;
  310. // Set the characters we handle
  311. lsctxinf.lstxtcfg.wchNull = 0;
  312. lsctxinf.lstxtcfg.wchSpace = ' ';
  313. lsctxinf.lstxtcfg.wchHyphen = '-';
  314. lsctxinf.lstxtcfg.wchTab = '\t';
  315. lsctxinf.lstxtcfg.wchEndLineInPara = '\v';
  316. lsctxinf.lstxtcfg.wchEndPara1 = '\r';
  317. lsctxinf.lstxtcfg.wchEndPara2 = '\n';
  318. lsctxinf.lstxtcfg.wchVisiAltEndPara =
  319. lsctxinf.lstxtcfg.wchVisiEndPara =
  320. lsctxinf.lstxtcfg.wchVisiEndLineInPara = ' ';
  321. lsctxinf.lstxtcfg.wchNonReqHyphen = SOFTHYPHEN;
  322. // Auto number escape character
  323. lsctxinf.lstxtcfg.wchEscAnmRun = wchObjectEnd;
  324. lsctxinf.pols = this;
  325. lsctxinf.lscbk = lscbk;
  326. if(LsCreateContext(&lsctxinf, &g_plsc) != lserrNone)
  327. return E_FAIL;
  328. //REVIEW (keithcu) Quill seems to have a more mature kinsoku
  329. //table. For example, we don't allow breaking across space between
  330. //a word and the ending punctuation. French people want this behavior.
  331. BYTE rgbrkpairsKinsoku[cKinsokuCategories][cKinsokuCategories];
  332. BYTE *prgbrkpairsKinsoku = &rgbrkpairsKinsoku[0][0];
  333. for(LONG i = 0; i < cKinsokuCategories; i++)
  334. {
  335. for(LONG j = 0; j < cKinsokuCategories; j++)
  336. {
  337. LONG iBreak = 2*CanBreak(i, j);
  338. // If don't break, allow break across blanks unless first
  339. // char is open brace or second char is close brace
  340. if (!iBreak &&
  341. GetKinsokuClass(i) != brkclsOpen &&
  342. GetKinsokuClass(j) != brkclsOpen)
  343. {
  344. iBreak = 1;
  345. }
  346. *prgbrkpairsKinsoku++ = iBreak;
  347. }
  348. }
  349. if(g_plsc->SetBreaking(ARRAY_SIZE(rglsbrkDefault), rglsbrkDefault,
  350. cKinsokuCategories, &rgbrkpairsKinsoku[0][0]) != lserrNone)
  351. {
  352. return E_FAIL;
  353. }
  354. return NOERROR;
  355. }
  356. /*
  357. * COls::MeasureLine(xWidth, pliTarget)
  358. *
  359. * @mfunc
  360. * Wrapper for LsCreateLine
  361. *
  362. * @rdesc
  363. * TRUE if success, FALSE if failed
  364. */
  365. const int dxpMaxWidth = 0x000FFFFF;
  366. BOOL COls::MeasureLine(
  367. LONG xWidth, //@parm Width of line in device units
  368. CLine * pliTarget) //@parm Returns target-device line metrics (optional)
  369. {
  370. LONG xWidthActual = xWidth;
  371. CMeasurer *pme = _pme;
  372. const CParaFormat *pPF = pme->Get_pPF();
  373. const CDisplay *pdp = pme->_pdp;
  374. LONG cp = pme->GetCp();
  375. #ifdef DEBUG
  376. LONG cchText = pme->GetTextLength(); // For DEBUG...
  377. AssertSz(cp < cchText || !pme->IsRich() && cp == cchText, "COls::Measure: trying to measure past EOD");
  378. #endif
  379. DestroyLine(NULL);
  380. _cp = cp;
  381. _pdp = pdp;
  382. _fCheckFit = FALSE;
  383. pme->SetUseTargetDevice(FALSE);
  384. LSDEVRES lsdevres;
  385. lsdevres.dyrInch = pme->_dyrInch;
  386. lsdevres.dxrInch = pme->_dxrInch;
  387. lsdevres.dypInch = pme->_dypInch;
  388. lsdevres.dxpInch = pme->_dxpInch;
  389. g_plsc->SetDoc(TRUE, lsdevres.dyrInch == lsdevres.dypInch &&
  390. lsdevres.dxrInch == lsdevres.dxpInch, &lsdevres);
  391. if(xWidth == -1)
  392. {
  393. if (pdp->GetMaxWidth())
  394. xWidth = xWidthActual = pme->LXtoDX(pdp->GetMaxWidth());
  395. else
  396. xWidth = xWidthActual = max(0, pdp->GetMaxPixelWidth() - dxCaret);
  397. }
  398. if(!pdp->GetWordWrap())
  399. {
  400. xWidth = dxpMaxWidth;
  401. BOOL fNearJust = pPF->_bAlignment == PFA_LEFT && !pPF->IsRtlPara() ||
  402. pPF->_bAlignment == PFA_RIGHT && pPF->IsRtlPara();
  403. if (!fNearJust)
  404. _fCheckFit = TRUE;
  405. }
  406. DWORD cBreakRecOut;
  407. LSLINFO lslinfo;
  408. BREAKREC rgBreak[MAX_OBJ_DEPTH];
  409. _xWidth = xWidth;
  410. LSERR lserr = g_plsc->CreateLine(cp, pme->DXtoLX(xWidth), NULL, 0, MAX_OBJ_DEPTH, rgBreak,
  411. &cBreakRecOut, &lslinfo, &_plsline);
  412. if (_fCheckFit)
  413. {
  414. long upJunk, upStartTrailing;
  415. LsQueryLineDup(_plsline, &upJunk, &upJunk, &upJunk, &upStartTrailing, &upJunk);
  416. if (pme->_pPF->InTable())
  417. {
  418. // We play games in case of tables, so we should change width to get proper alignment.
  419. //
  420. // LS formats from negative left indent of -_dxOffset, but we'll actually display
  421. // from the +_dxOffset. We will also lie to LS (or is is truth) about position of
  422. // the last tab. As a result of this, LS thinks the line by _dxOffset shorter than
  423. // it really is.
  424. xWidthActual -= pme->LXtoDX(pme->_pPF->_dxOffset);
  425. }
  426. if (upStartTrailing < xWidthActual)
  427. {
  428. _xWidth = xWidth = xWidthActual;
  429. _fCheckFit = FALSE;
  430. DestroyLine(NULL);
  431. lserr = g_plsc->CreateLine(cp, pme->DXtoLX(xWidth), NULL, 0, MAX_OBJ_DEPTH, rgBreak,
  432. &cBreakRecOut, &lslinfo, &_plsline);
  433. }
  434. }
  435. //Line Services doesn't put the autonumbering dimensions into the line,
  436. //so we have to do it ourselves.
  437. lslinfo.dvpAscent = max(lslinfo.dvpAscent, lslinfo.dvpAscentAutoNumber);
  438. lslinfo.dvpDescent = max(lslinfo.dvpDescent, lslinfo.dvpDescentAutoNumber);
  439. pme->SetUseTargetDevice(FALSE);
  440. lslinfo.cpLim = GetCpReFromCpLs(lslinfo.cpLim);
  441. if (lserr != lserrNone)
  442. {
  443. AssertSz(lserr == lserrOutOfMemory, "Line format failed for invalid reason");
  444. pme->GetPed()->GetCallMgr()->SetOutOfMemory();
  445. return FALSE;
  446. }
  447. //REVIEW (keithcu) Doing this hit-testing during measurement is slow--is it
  448. //worth it to cache this data?
  449. if(!pme->IsRenderer())
  450. {
  451. long upJunk, upStart, upStartTrailing, upLimLine;
  452. // Save some LineServices results in the measurer's CLine
  453. pme->_li._cch = lslinfo.cpLim - cp;
  454. AssertSz(pme->_li._cch > 0, "no cps on line");
  455. // Query line services for line width and indent.
  456. LsQueryLineDup(_plsline, &upJunk, &upJunk, &upStart, &upStartTrailing, &upLimLine);
  457. long dupWidth = upStartTrailing - upStart;
  458. pme->_li._xLeft = upStart;
  459. pme->_li._xWidth = dupWidth;
  460. if(pme->IsRich())
  461. {
  462. pme->_li._yHeight = lslinfo.dvpAscent + lslinfo.dvpDescent;
  463. pme->_li._yDescent = lslinfo.dvpDescent;
  464. }
  465. else
  466. pme->CheckLineHeight(); // Use default heights
  467. pme->_li._cchEOP = 0;
  468. pme->SetCp(lslinfo.cpLim);
  469. if(pme->_rpTX.IsAfterEOP()) // Line ends with an EOP
  470. { // Store cch of EOP (1 or 2)
  471. pme->_rpTX.BackupCpCRLF(FALSE);
  472. UINT ch = pme->GetChar();
  473. if(ch == CR || pme->GetPed()->fUseCRLF() && ch == LF)
  474. pme->_li._bFlags |= fliHasEOP;
  475. pme->_li._cchEOP = pme->_rpTX.AdvanceCpCRLF(FALSE);
  476. }
  477. if (lslinfo.cpLim > pme->GetTextLength() &&
  478. (!pme->IsRich() || pme->IsHidden()))
  479. {
  480. Assert(lslinfo.cpLim == pme->GetTextLength() + 1);
  481. pme->_li._cch--;
  482. }
  483. else
  484. pme->AdjustLineHeight();
  485. }
  486. //Setup pliTarget if caller requests it
  487. //FUTURE (KeithCu) If people want target information, then the display
  488. //information is the same, except that OnFormatRange has a bug.
  489. if (pliTarget)
  490. {
  491. CLine liSave = pme->_li;
  492. pme->_li._yHeight = max(lslinfo.dvrAscent, lslinfo.dvrAscentAutoNumber) +
  493. max(lslinfo.dvrDescent, lslinfo.dvrDescentAutoNumber);
  494. pme->_li._yDescent = lslinfo.dvrDescent;
  495. pme->SetUseTargetDevice(TRUE);
  496. pme->AdjustLineHeight();
  497. pme->SetUseTargetDevice(FALSE);
  498. *pliTarget = pme->_li;
  499. pme->_li = liSave;
  500. }
  501. return TRUE;
  502. }
  503. /*
  504. * COls::RenderLine()
  505. *
  506. * @mfunc
  507. * Wrapper for LsDisplayLine
  508. *
  509. * @rdesc
  510. * TRUE if success, FALSE if failed
  511. */
  512. BOOL COls::RenderLine(
  513. CLine & li) //@parm Line to render
  514. {
  515. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "COls::RenderLine");
  516. LONG cp = _pme->GetCp();
  517. CRenderer *pre = GetRenderer();
  518. LONG xAdj = 0, yAdj = 0;
  519. Assert(pre->_fRenderer);
  520. pre->NewLine(li);
  521. if(li._fCollapsed) // Line is collapsed in Outline mode
  522. {
  523. pre->Advance(li._cch); // Bypass line
  524. return TRUE; // Let dispml continue with next line
  525. }
  526. pre->SetNumber(li._bNumber);
  527. CreateOrGetLine();
  528. if(!_plsline)
  529. return FALSE;
  530. pre->SetCp(cp); // Back to beginning of line
  531. Assert(pre->_fTarget == FALSE);
  532. pre->Check_pccs(FALSE);
  533. pre->SetClipRect();
  534. HDC hdcSave = NULL;
  535. if(li._cch > 0 && pre->fUseOffScreenDC() && (li._bFlags & fliUseOffScreenDC))
  536. {
  537. // Set up an off-screen DC if we can. Note that if this fails,
  538. // we just use the regular DC which won't look as nice but
  539. // will at least display something readable.
  540. hdcSave = pre->SetUpOffScreenDC(xAdj, yAdj);
  541. // Is this a uniform text being rendered off screen?
  542. if(li._bFlags & fliOffScreenOnce)
  543. {
  544. // Yes - turn off special rendering since line has been rendered
  545. li._bFlags &= ~(fliOffScreenOnce | fliUseOffScreenDC);
  546. }
  547. }
  548. POINT pt = pre->GetCurPoint(); // Must follow offscreen setup
  549. RECT rc = pre->GetClipRect(); // since _ptCur, _rc change
  550. LONG x = 0;
  551. if(pre->_pPF->InTable())
  552. {
  553. pt.x += 2*pre->LXtoDX(pre->_pPF->_dxOffset);
  554. x = pt.x + pre->_li._xLeft;
  555. }
  556. pre->_li._xLeft = 0;
  557. pre->RenderStartLine();
  558. pt.x += pre->XFromU(0);
  559. pt.y += li._yHeight - li._yDescent; // Move to baseline for LS
  560. LSERR lserr = LsDisplayLine(_plsline, &pt, pre->GetPdp()->IsMain() ? ETO_CLIPPED : 0, &rc);
  561. AssertSz(lserr == lserrNone, "COls::RenderLine: error in rendering line");
  562. pre->EndRenderLine(hdcSave, xAdj, yAdj, x);
  563. pre->SetCp(cp + li._cch);
  564. return lserr == lserrNone;
  565. }
  566. /*
  567. * COls::CreateOrGetLine()
  568. *
  569. * @mfunc
  570. * If _plsline is nonNull and _cp equals _pme->GetCp(), return. Else
  571. * create line with caching so that _plsline and _cp are correct for
  572. * current line
  573. */
  574. void COls::CreateOrGetLine()
  575. {
  576. if(_plsline && _pme->GetCp() == _cp && _pme->_pdp == _pdp)
  577. return;
  578. MeasureLine(-1, NULL); // Define new _plsline
  579. }
  580. /*
  581. * COls::MeasureText(cch, taMode, pdx, pdy)
  582. *
  583. * @mfunc
  584. * Gets x offset to cp given by CMeasurer _pme + cch chars along with
  585. * display dimensions.
  586. *
  587. * @rdesc
  588. * xwidth measured
  589. */
  590. LONG COls::MeasureText(
  591. LONG cch, //(IN): Max cch to measure
  592. UINT taMode, //(IN): requested coordinate
  593. CDispDim *pdispdim) //(OUT): display dimensions
  594. {
  595. CMeasurer * pme = _pme;
  596. LONG cp = pme->GetCp() + cch; // Enter with me at start of line
  597. POINT pt; // Point at cp in client coords
  598. BOOL fAtLogicalRightEdge = FALSE;
  599. CreateOrGetLine();
  600. if(!_plsline)
  601. return 0;
  602. Assert(pme->_fTarget == FALSE);
  603. // Query point from cp
  604. DWORD cActualDepth;
  605. LSQSUBINFO lsqSubInfo[MAX_OBJ_DEPTH];
  606. LSTEXTCELL lsTextCell;
  607. memset(&lsTextCell, 0, sizeof(lsTextCell));
  608. LsQueryLineCpPpoint(_plsline, GetCpLsFromCpRe(cp), MAX_OBJ_DEPTH, &lsqSubInfo[0],
  609. &cActualDepth, &lsTextCell);
  610. pdispdim->lstflow = lsqSubInfo[cActualDepth - 1].lstflowSubline;
  611. pdispdim->dx = lsTextCell.dupCell;
  612. LSTFLOW lstflowLine = lsqSubInfo[0].lstflowSubline;
  613. POINT ptStart = {pme->XFromU(0), pme->_li._yHeight - pme->_li._yDescent};
  614. POINTUV ptuv = lsTextCell.pointUvStartCell;
  615. if(taMode & (TA_STARTOFLINE | TA_ENDOFLINE) && cActualDepth > 1)
  616. {
  617. ptuv = lsqSubInfo[0].pointUvStartRun;
  618. if(taMode & TA_ENDOFLINE)
  619. ptuv.u += lsqSubInfo[0].dupRun;
  620. }
  621. //If they ask for position inside ligature or at lim of line, give right edge of cell
  622. else if (cp > GetCpReFromCpLs(lsTextCell.cpStartCell))
  623. {
  624. fAtLogicalRightEdge = TRUE;
  625. if (lstflowLine != pdispdim->lstflow)
  626. ptuv.u -= lsTextCell.dupCell;
  627. else
  628. ptuv.u += lsTextCell.dupCell;
  629. }
  630. LsPointXYFromPointUV(&ptStart, lstflowLine, &ptuv, &pt);
  631. if(pme->_pPF->InTable())
  632. pt.x += 2*pme->LXtoDX(pme->_pPF->_dxOffset);
  633. if (pdispdim->lstflow == lstflowWS && !(taMode & (TA_LOGICAL | TA_STARTOFLINE)))
  634. {
  635. if (fAtLogicalRightEdge)
  636. {
  637. if ((taMode & TA_RIGHT) == TA_RIGHT)
  638. pt.x += pdispdim->dx;
  639. else if (taMode & TA_CENTER)
  640. pt.x += pdispdim->dx / 2;
  641. return pt.x;
  642. }
  643. else
  644. pt.x -= pdispdim->dx;
  645. }
  646. LONG dx = 0;
  647. if(taMode & TA_CENTER && !fAtLogicalRightEdge)
  648. dx = pdispdim->dx;
  649. if((taMode & TA_CENTER) == TA_CENTER)
  650. dx >>= 1;
  651. if (pdispdim->lstflow == lstflowWS && (taMode & TA_LOGICAL))
  652. dx = -dx;
  653. return max(0, pt.x + dx);
  654. }
  655. /*
  656. * COls::CchFromXpos(pt, &dx)
  657. *
  658. * @mfunc
  659. * Moves _pme to pt.x. Calls LsQueryLinePointPcp()
  660. */
  661. void COls::CchFromXpos(
  662. POINT pt, //@parm Point to find cch for in line
  663. CDispDim *pdispdim, //@parm dimensions of object
  664. LONG *pcpActual) //@parm CP point
  665. {
  666. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "COls::CchFromXpos");
  667. if(_pme->_pPF->InTable())
  668. pt.x -= 2*_pme->LXtoDX(_pme->_pPF->_dxOffset);
  669. // Make point relative to LS coordinate system - (0,0) in LS is at the
  670. // baseline of the line.
  671. POINTUV ptuv = {_pme->UFromX(pt.x), -pt.y + _pme->_li._yHeight - _pme->_li._yDescent};
  672. LONG cpStart = _pme->GetCp();
  673. CreateOrGetLine();
  674. if(!_plsline)
  675. return;
  676. Assert(_pme->_fTarget == FALSE);
  677. DWORD cActualDepth;
  678. LSQSUBINFO lsqSubInfo[MAX_OBJ_DEPTH];
  679. LSTEXTCELL lsTextCell;
  680. memset(&lsTextCell, 0, sizeof(lsTextCell));
  681. LsQueryLinePointPcp(_plsline, &ptuv, MAX_OBJ_DEPTH, &lsqSubInfo[0], &cActualDepth, &lsTextCell);
  682. if (cActualDepth == 0) //If we got back empty textcell, let's just query cp explicitly to get information
  683. {
  684. LsQueryLineCpPpoint(_plsline, cpStart, MAX_OBJ_DEPTH, &lsqSubInfo[0], &cActualDepth, &lsTextCell);
  685. Assert(cActualDepth != 0);
  686. }
  687. pdispdim->dx = lsTextCell.dupCell;
  688. pdispdim->lstflow = lsqSubInfo[cActualDepth - 1].lstflowSubline;
  689. LONG cp = *pcpActual = GetCpReFromCpLs(lsTextCell.cpStartCell);
  690. POINTUV ptuvCell;
  691. //Convert the hit-test point from u,v of line to u,v of cell
  692. LsPointUV2FromPointUV1(lsqSubInfo[0].lstflowSubline, &lsTextCell.pointUvStartCell, &ptuv,
  693. lsqSubInfo[cActualDepth - 1].lstflowSubline, &ptuvCell);
  694. if(ptuvCell.u > lsTextCell.dupCell/2)
  695. cp += lsTextCell.cpEndCell - lsTextCell.cpStartCell + 1;
  696. if (_pme->GetPed()->_pbrk)
  697. {
  698. // If text breaker is up, verify cluster before placing the caret
  699. CTxtBreaker* pbrk = _pme->GetPed()->_pbrk;
  700. LONG cpEnd = _pme->GetPed()->GetTextLength();
  701. while (cp < cpEnd && !pbrk->CanBreakCp(BRK_CLUSTER, cp))
  702. cp++;
  703. }
  704. _pme->_li._cch = cp - _cp;
  705. _pme->SetCp(cp);
  706. }
  707. /*
  708. * COls::DestroyLine(pdp)
  709. *
  710. * @mfunc
  711. * Destroys any line data structures.
  712. */
  713. void COls::DestroyLine(CDisplay *pdp)
  714. {
  715. CLock lock;
  716. if (pdp && pdp != _pdp)
  717. return;
  718. if(_plsline)
  719. {
  720. g_plsc->DestroyLine(_plsline);
  721. _plsline = NULL;
  722. }
  723. if (_rgcp.Count())
  724. _rgcp.Clear(AF_KEEPMEM);
  725. int cchunk = _rglsrunChunk.Count();
  726. for (int ichunk = 0; ichunk < cchunk; ichunk++)
  727. _rglsrunChunk.Elem(ichunk)->_cel = 0;
  728. }
  729. /*
  730. * LimitChunk(pch, &cchChunk, f10Mode)
  731. *
  732. * @func
  733. * Return object ID at *pch and shorten cchChunk to 1 if object isn't
  734. * text and to the count of text chars up to a nontext object if one
  735. * occurs within cchChunk and within the current paragraph.
  736. *
  737. * @rdesc
  738. * Object ID at *pch
  739. */
  740. DWORD LimitChunk(const WCHAR *pch, LONG &cchChunk, BOOL f10Mode)
  741. {
  742. for(LONG i = 0; i < cchChunk && *pch != CR; i++, pch++)
  743. {
  744. switch(*pch)
  745. {
  746. case WCH_EMBEDDING:
  747. if(i == 0)
  748. {
  749. cchChunk = 1;
  750. return OBJID_OLE; // Entered at an OLE object
  751. }
  752. cchChunk = i; // Will break before
  753. break;
  754. case EURO:
  755. if (i == 0)
  756. {
  757. for(; i < cchChunk && *pch == EURO; i++)
  758. pch++;
  759. }
  760. cchChunk = i;
  761. break;
  762. case FF:
  763. if(f10Mode) // RE 1.0 treats FFs as
  764. continue; // ordinary characters
  765. cchChunk = i; // Will break before
  766. break;
  767. }
  768. }
  769. return idObjTextChp;
  770. }
  771. /*
  772. * SetLsChp(dwObjId, pme, plsChp)
  773. *
  774. * @func
  775. * Helper function that initializes an LS chp from RE CCharFormat
  776. *
  777. * @rdesc
  778. * TRUE iff IsHidden()
  779. */
  780. BOOL COls::SetLsChp(
  781. DWORD dwObjId, //(IN): Object id
  782. PLSRUN plsrun, //(IN): Current Run
  783. PLSCHP plsChp) //(OUT): LS chp
  784. {
  785. ZeroMemory(plsChp, sizeof(*plsChp));
  786. plsChp->idObj = (WORD)dwObjId;
  787. //If we do FE or Latin kerning, we need to set dcpMaxContext to 2
  788. if (_pme->GetPed()->IsComplexScript() && plsrun->_a.eScript && !plsrun->IsBullet())
  789. {
  790. CUniscribe* pusp = _pme->Getusp();
  791. Assert (pusp);
  792. const SCRIPT_PROPERTIES *psp = pusp->GeteProp(plsrun->_a.eScript);
  793. if (psp->fComplex || plsrun->_a.fRTL ||
  794. psp->fNumeric && W32->GetDigitSubstitutionMode() != DIGITS_NOTIMPL)
  795. {
  796. // 1. Complex script
  797. // 2. RTL (internal direction) run (handle mirror glyph i.e.'?')
  798. // 3. Numeric run and substitution mode is either Native or Context
  799. plsChp->fGlyphBased = TRUE;
  800. }
  801. }
  802. DWORD dwEffects = plsrun->_pCF->_dwEffects;
  803. if(dwEffects & (CFE_UNDERLINE | CFE_LINK | CFE_REVISED))
  804. plsChp->fUnderline = TRUE;
  805. if(dwEffects & CFE_STRIKEOUT && !plsrun->IsBullet())
  806. plsChp->fStrike = TRUE;
  807. if (plsrun->_pCF->_yOffset || dwEffects & (CFE_SUPERSCRIPT | CFE_SUBSCRIPT))
  808. {
  809. _pme->SetUseTargetDevice(FALSE);
  810. CCcs *pccs = _pme->Check_pccs(plsrun->IsBullet());
  811. LONG yOffset, yAdjust;
  812. pccs->GetOffset(plsrun->_pCF, _pme->_dypInch, &yOffset, &yAdjust);
  813. plsChp->dvpPos += yOffset + yAdjust;
  814. }
  815. //If its an OLE object, but the Object doesn't exist yet, then hide it
  816. if (dwObjId == OBJID_OLE)
  817. {
  818. COleObject * pobj = _pme->GetPed()->GetObjectMgr()->GetObjectFromCp(_pme->GetCp());
  819. if (!pobj)
  820. return TRUE;
  821. }
  822. return dwEffects & CFE_HIDDEN;
  823. }
  824. /*
  825. * FetchAnmRun(pols, cp, plpwchRun, pcchRun, pfHidden, plsChp, pplsrun)
  826. *
  827. * @func
  828. * LineServices fetch bullets/numbering callback
  829. *
  830. * @rdesc
  831. * LSERR
  832. */
  833. LSERR WINAPI COls::FetchAnmRun(
  834. LSCP cp, //@parm [IN]: RE cp
  835. LPCWSTR *plpwchRun, //@parm [OUT]: Run of characters
  836. DWORD * pcchRun, //@parm [OUT]: Count of characters in run
  837. BOOL * pfHidden, //@parm [OUT]: fHidden run?
  838. PLSCHP plsChp, //@parm [OUT]: Char properties of run
  839. PLSRUN * pplsrun) //@parm [OUT]: Abstract representation of run properties
  840. {
  841. if (cp == cpFirstAnm && _pme->Get_pPF()->IsRtlPara())
  842. {
  843. ZeroMemory(plsChp, sizeof(*plsChp));
  844. plsChp->idObj = OBJID_REVERSE;
  845. *pfHidden = 0; *pcchRun = 1;
  846. *pplsrun = GetPlsrun(_pme->GetCp(), &_CFBullet, TRUE);
  847. *plpwchRun = &_szAnm[0];
  848. return lserrNone;
  849. }
  850. *plpwchRun = &_szAnm[cp - cpFirstAnm];
  851. *pcchRun = _cchAnm - (cp - cpFirstAnm);
  852. *pplsrun = GetPlsrun(_pme->GetCp(), &_CFBullet, TRUE);
  853. SetLsChp(idObjTextChp, *pplsrun, plsChp);
  854. *pfHidden = FALSE;
  855. if (!_pme->GetNumber())
  856. plsChp->fUnderline = FALSE;
  857. return lserrNone;
  858. }
  859. /*
  860. * OlsFetchRun(pols, cp, plpwchRun, pcchRun, pfHidden, plsChp, pplsrun)
  861. *
  862. * @func
  863. * LineServices fetch-run callback
  864. *
  865. * @rdesc
  866. * LSERR
  867. */
  868. LSERR WINAPI OlsFetchRun(
  869. POLS pols, //@parm [IN]: COls *
  870. LSCP cpLs, //@parm [IN]: LS cp
  871. LPCWSTR *plpwchRun, //@parm [OUT]: Run of characters
  872. DWORD * pcchRun, //@parm [OUT]: Count of characters in run
  873. BOOL * pfHidden, //@parm [OUT]: Hidden run?
  874. PLSCHP plsChp, //@parm [OUT]: Char properties of run
  875. PLSRUN * pplsrun) //@parm [OUT]: Abstract representation of run properties
  876. {
  877. if(cpLs < 0)
  878. return pols->FetchAnmRun(cpLs, plpwchRun, pcchRun, pfHidden, plsChp, pplsrun);
  879. CMeasurer *pme = pols->GetMeasurer();
  880. CTxtEdit *ped = pme->GetPed();
  881. BOOL fStart = FALSE;
  882. BOOL fFetchBraces = ped->IsBiDi() && g_pusp && g_pusp->IsValid() &&
  883. !ped->_fItemizePending && ped->GetAdjustedTextLength();
  884. WCHAR chPassword = pme->GetPasswordChar();
  885. LONG cpAccelerator = ped->GetCpAccelerator();
  886. BOOL fAccelerator = FALSE;
  887. BOOL f10Mode = ped->Get10Mode();
  888. if (cpLs == pols->_cp)
  889. {
  890. //If we are formatting (or re-formatting) the line, cleanup
  891. if (pols->_rgcp.Count())
  892. pols->_rgcp.Clear(AF_KEEPMEM);
  893. pols->_cEmit = 0;
  894. }
  895. long cpRe = pols->GetCpReFromCpLs(cpLs);
  896. pme->SetCp(cpRe); // start fetching at given cp
  897. if (fFetchBraces && pme->_rpCF.IsValid())
  898. {
  899. // consider emitting braces only at the run boundary or start of a fetched line
  900. //
  901. if (cpRe == pols->_cp || !pme->GetIchRunCF() || !pme->GetCchLeftRunCF())
  902. {
  903. SHORT cBrClose, cBrOpen;
  904. BYTE bBaseLevel = pme->IsParaRTL() ? 1 : 0;
  905. BYTE bLevel, bLevelPrev;
  906. bLevelPrev = bLevel = bBaseLevel; // assume base level
  907. if (cpRe < ped->GetTextLength())
  908. {
  909. CBiDiLevel level;
  910. bLevel = pme->_rpCF.GetLevel(&level); // got level of current run
  911. fStart = level._fStart;
  912. }
  913. if (cpRe > pols->_cp && pme->Advance(-1))
  914. {
  915. if (pme->_rpPF.SameLevel(bBaseLevel)) // preceding run may be hidden
  916. bLevelPrev = pme->_rpCF.GetLevel(); // got level of preceding run
  917. pme->Advance(1); // resume position
  918. }
  919. cBrOpen = cBrClose = bLevel - bLevelPrev;
  920. if (fStart) // start embedding at the current run
  921. cBrClose = bBaseLevel - bLevelPrev; // this means we must close all braces of preceding run
  922. cBrClose = max(0, -cBrClose);
  923. if (cBrClose > 0 && pols->BracesBeforeCp(cpLs) < cBrClose)
  924. {
  925. // emit close braces
  926. if (pols->_cEmit > 0)
  927. {
  928. EmitBrace(pols, plsChp, pfHidden, pcchRun, pplsrun, plpwchRun, idObjTextChp, rgchObjectEnd);
  929. if (pols->AddBraceCp(cpLs))
  930. pols->_cEmit--;
  931. #ifdef DEBUG_BRACE
  932. Tracef(TRCSEVNONE, "CLOSE(%d) cpLs %d: emitted %d", cBrClose, cpLs, pols->_cEmit);
  933. #endif
  934. return lserrNone;
  935. }
  936. else
  937. {
  938. // We assert. You can click "Ignore All" with no hang.
  939. AssertSz(FALSE, "Prevent emitting close brace (no open counterpart)");
  940. }
  941. }
  942. if (fStart) // start embedding at the current run
  943. cBrOpen = bLevel - bBaseLevel; // we begin openning braces
  944. if (cBrOpen > 0 && pols->BracesBeforeCp(cpLs) < cBrOpen + cBrClose)
  945. {
  946. // emit open braces
  947. EmitBrace(pols, plsChp, pfHidden, pcchRun, pplsrun, plpwchRun, OBJID_REVERSE, L" ");
  948. if (pols->AddBraceCp(cpLs))
  949. pols->_cEmit++;
  950. #ifdef DEBUG_BRACE
  951. Tracef(TRCSEVNONE, "OPEN(%d) cpLs %d: emitted %d", cBrOpen, cpLs, pols->_cEmit);
  952. #endif
  953. return lserrNone;
  954. }
  955. }
  956. }
  957. // Done fetching braces.
  958. // Begin getting real data...
  959. #ifdef DEBUG_BRACE
  960. Tracef(TRCSEVNONE, "cpLs %d: emitted %d", cpLs, pols->_cEmit);
  961. #endif
  962. // Initialized chunk to count of characters in format run
  963. LONG cchChunk = pme->GetCchLeftRunCF();
  964. DWORD dwObjId = idObjTextChp;
  965. if(!pme->IsHidden()) // Run isn't hidden
  966. {
  967. LONG cch;
  968. *plpwchRun = pme->GetPch(cch); // Get text in run
  969. cchChunk = min(cchChunk, cch); // Maybe less than cchChunk
  970. if (!pme->GetPdp()->IsMetafile())
  971. cchChunk = min(cchChunk, cchLineHint);
  972. if (chPassword)
  973. {
  974. cchChunk = min(cchChunk, int(sizeof(pols->_rgchTemp) / sizeof(WCHAR)));
  975. memcpy(pols->_rgchTemp, *plpwchRun, cchChunk * sizeof(WCHAR));
  976. for (int i = 0; i < cchChunk; i++)
  977. {
  978. if (!IsASCIIEOP((*plpwchRun)[i]))
  979. pols->_rgchTemp[i] = chPassword;
  980. else
  981. pols->_rgchTemp[i] = (*plpwchRun)[i];
  982. }
  983. *plpwchRun = pols->_rgchTemp;
  984. }
  985. if(cpAccelerator != -1)
  986. {
  987. LONG cpCur = pme->GetCp(); // Get current cp
  988. // Does accelerator character fall in this chunk?
  989. if (cpCur < cpAccelerator &&
  990. cpCur + cchChunk > cpAccelerator)
  991. {
  992. // Yes. Reduce chunk to char just before accelerator
  993. cchChunk = cpAccelerator - cpCur;
  994. }
  995. // Is this character the accelerator?
  996. else if(cpCur == cpAccelerator)
  997. { // Set chunk size to 1 since only
  998. cchChunk = 1; // want to output underlined char
  999. fAccelerator = TRUE; // Tell downstream routines that
  1000. // we're handling accelerator
  1001. }
  1002. }
  1003. if(pme->GetCF()->_dwEffects & CFE_ALLCAPS)
  1004. {
  1005. cchChunk = min(cchChunk, int(sizeof(pols->_rgchTemp) / sizeof(WCHAR)));
  1006. memcpy(pols->_rgchTemp, *plpwchRun, cchChunk * sizeof(WCHAR));
  1007. CharUpperBuff(pols->_rgchTemp, cchChunk);
  1008. *plpwchRun = pols->_rgchTemp;
  1009. }
  1010. //Line Services handles page breaks in a weird way, so lets just convert to a CR.
  1011. if (*plpwchRun && *(*plpwchRun) == FF && !f10Mode)
  1012. {
  1013. pols->_szAnm[0] = CR;
  1014. *plpwchRun = pols->_szAnm;
  1015. cchChunk = 1;
  1016. }
  1017. AssertSz(cpRe < ped->GetTextLength() || !ped->IsRich(), "0-length run at end of control");
  1018. AssertSz(cch || !ped->IsRich(), "0-length run at end of control");
  1019. // Set run size appropriately for any objects that are in run
  1020. dwObjId = LimitChunk(*plpwchRun, cchChunk, f10Mode);
  1021. // Get regular highlighted positions
  1022. LONG cpSelMin, cpSelMost;
  1023. ped->GetSelRangeForRender(&cpSelMin, &cpSelMost);
  1024. if(cpSelMin != cpSelMost)
  1025. {
  1026. if(cpRe >= cpSelMin)
  1027. {
  1028. if(cpRe < cpSelMost)
  1029. {
  1030. // Current text falls inside selection
  1031. cch = cpSelMost - cpRe;
  1032. cchChunk = min(cchChunk, cch);
  1033. }
  1034. }
  1035. else if(cpRe + cchChunk >= cpSelMin)
  1036. {
  1037. // cp < cpSelMin - run starts outside of selection.
  1038. // Limit text to start of selection.
  1039. cchChunk = cpSelMin - cpRe;
  1040. }
  1041. }
  1042. }
  1043. *pplsrun = pols->GetPlsrun(cpRe, pme->GetCF(), FALSE);
  1044. *pfHidden = pols->SetLsChp(dwObjId, *pplsrun, plsChp);
  1045. if (fAccelerator)
  1046. plsChp->fUnderline = TRUE;
  1047. if(!cchChunk) // Happens in plain-text controls
  1048. { // and if hidden text to end of story
  1049. if (!ped->IsRich() && pols->_cEmit > 0)
  1050. {
  1051. EmitBrace(pols, plsChp, pfHidden, pcchRun, pplsrun, plpwchRun, idObjTextChp, rgchObjectEnd);
  1052. TRACEWARNSZ("(plain)Auto-emit a close brace to make balance");
  1053. if (pols->AddBraceCp(cpLs))
  1054. pols->_cEmit--;
  1055. return lserrNone;
  1056. }
  1057. cchChunk = 1;
  1058. *plpwchRun = szCR;
  1059. *pfHidden = FALSE;
  1060. //Paragraph marks should not have any script state associated with them,
  1061. //even if the pCF that point to does.
  1062. ZeroMemory(&(*pplsrun)->_a, sizeof((*pplsrun)->_a));
  1063. }
  1064. *pcchRun = cchChunk;
  1065. return lserrNone;
  1066. }
  1067. /*
  1068. * OlsGetAutoNumberInfo (pols, plskalAnm, pwchAdd, plschp, pplsrun,
  1069. * pfWord95Model, pduaSpaceAnm, pduaWidthAnm)
  1070. * @func
  1071. * LineServices fetch autonumbering info callback. Return info needed
  1072. * by LS for auto numbering. Get the chp/run for last char from auto
  1073. * number run. Always say we are Word95 model Anm and get rest of info
  1074. * from paragraph properties.
  1075. *
  1076. * @rdesc
  1077. * LSERR
  1078. */
  1079. LSERR WINAPI OlsGetAutoNumberInfo(
  1080. POLS pols, //(IN): Client context
  1081. LSKALIGN *plskalAnm, //(OUT):Justification
  1082. PLSCHP plschpAnm,
  1083. PLSRUN *pplsrunAnm,
  1084. WCHAR * pwchAdd, //(OUT):char to add (Nil is treated as none)
  1085. PLSCHP plsChp, //(OUT):chp for bridge character
  1086. PLSRUN * pplsrun, //(OUT):Run for bridge character
  1087. BOOL * pfWord95Model, //(OUT):Type of autonumber run
  1088. long * pduaSpaceAnm, //(OUT):Relevant iff fWord95Model
  1089. long * pduaWidthAnm) //(OUT):Relevant iff fWord95Model
  1090. {
  1091. CMeasurer *pme = pols->GetMeasurer();
  1092. const CParaFormat *pPF = pme->Get_pPF();
  1093. *pplsrunAnm = *pplsrun = pols->GetPlsrun(pme->GetCp(), &pols->_CFBullet, TRUE);
  1094. pols->SetLsChp(idObjTextChp, *pplsrun, plsChp);
  1095. if (!pme->GetNumber())
  1096. plsChp->fUnderline = FALSE;
  1097. *plschpAnm = *plsChp;
  1098. *pwchAdd = '\t';
  1099. *pfWord95Model = TRUE;
  1100. *pduaSpaceAnm = 0;
  1101. *pduaWidthAnm = max(pPF->_dxOffset, pPF->_wNumberingTab);
  1102. *plskalAnm = (LSKALIGN)(lskalLeft + (pPF->_wNumberingStyle & 3));
  1103. return lserrNone;
  1104. }
  1105. /*
  1106. * OlsGetNumericSeparators (pols, cp, plspap)
  1107. *
  1108. * @func
  1109. * Get numeric separators needed, e.g., for decimal tabs
  1110. *
  1111. * @rdesc
  1112. * LSERR
  1113. */
  1114. LSERR WINAPI OlsGetNumericSeparators(
  1115. POLS pols, //(IN): pols
  1116. PLSRUN plsrun, //(IN): Run (cp here)
  1117. WCHAR * pwchDecimal, //(OUT): Decimal separator for this run
  1118. WCHAR * pwchThousands) //(OUT): Thousands separator for this run
  1119. {
  1120. LCID lcid = plsrun->_pCF->_lcid;
  1121. WCHAR ch = TEXT('.');
  1122. // This may need to be virtualized for Win95/CE...
  1123. ::GetLocaleInfo(lcid, LOCALE_SDECIMAL, &ch, 1);
  1124. *pwchDecimal = ch;
  1125. ch = TEXT(',');
  1126. ::GetLocaleInfo(lcid, LOCALE_STHOUSAND, &ch, 1);
  1127. *pwchThousands = ch;
  1128. return lserrNone;
  1129. }
  1130. /*
  1131. * OlsFetchPap (pols, cp, plspap)
  1132. *
  1133. * @func
  1134. * Fetch paragraph properties
  1135. *
  1136. * @rdesc
  1137. * LSERR
  1138. */
  1139. LSERR WINAPI OlsFetchPap(
  1140. POLS pols, //(IN): pols
  1141. LSCP cpLs, //(IN): an arbitrary cp value inside paragraph
  1142. PLSPAP plspap) //(OUT): Paragraph properties.
  1143. {
  1144. CMeasurer *pme = pols->GetMeasurer();
  1145. pme->SetCp(pols->_cp);
  1146. const CParaFormat *pPF = pme->Get_pPF();
  1147. CTxtEdit * ped = pme->GetPed();
  1148. // Default all results to 0
  1149. ZeroMemory(plspap, sizeof(*plspap));
  1150. //LS doesn't really care where the paragraph starts
  1151. plspap->cpFirst = pols->_cp;
  1152. if(plspap->cpFirst && !pme->fFirstInPara()) // Not first in para: say para
  1153. plspap->cpFirst--; // starts one char earlier
  1154. plspap->cpFirstContent = plspap->cpFirst;
  1155. if (pPF->IsRtlPara() && !pPF->InTable())
  1156. plspap->lstflow = lstflowWS;
  1157. // Alignment
  1158. plspap->lskal = (LSKALIGN) g_rgREtoTOMAlign[pPF->_bAlignment];
  1159. if (pPF->_bAlignment == PFA_FULL_INTERWORD)
  1160. {
  1161. plspap->lskal = lskalLeft;
  1162. plspap->lskj = lskjFullInterWord;
  1163. }
  1164. // Kind of EOP
  1165. plspap->lskeop = ped->fUseCRLF() ? lskeopEndPara12 : lskeopEndPara1;
  1166. if (pPF->IsRtlPara())
  1167. { //For Line Services, left means near and right means far.
  1168. if (plspap->lskal == lskalLeft)
  1169. plspap->lskal = lskalRight;
  1170. else if (plspap->lskal == lskalRight)
  1171. plspap->lskal = lskalLeft;
  1172. }
  1173. if (pols->_fCheckFit)
  1174. plspap->lskal = lskalLeft;
  1175. // Line breaking
  1176. if (pPF->_bAlignment > PFA_FULL_INTERWORD || !ped->fUseSimpleLineBreak() ||
  1177. !pme->GetPdp()->GetWordWrap()) // No word wrap
  1178. {
  1179. plspap->grpf |= fFmiApplyBreakingRules;
  1180. }
  1181. LONG dx = pPF->_dxRightIndent;
  1182. plspap->uaRightBreak = dx;
  1183. plspap->uaRightJustify = dx;
  1184. if(ped->IsInOutlineView())
  1185. {
  1186. plspap->uaLeft = lDefaultTab/2 * (pPF->_bOutlineLevel + 1);
  1187. plspap->duaIndent = 0;
  1188. }
  1189. else
  1190. {
  1191. plspap->uaLeft = pPF->_dxStartIndent + pPF->_dxOffset;
  1192. plspap->duaIndent = -pPF->_dxOffset;
  1193. }
  1194. if(!pPF->InTable() && plspap->uaLeft < 0)
  1195. plspap->uaLeft = 0;
  1196. // Is this a bulleted paragraph? - ignore bullets in a password
  1197. if(pPF->_wNumbering && pme->fFirstInPara() && !pme->GetPasswordChar() &&
  1198. !pPF->IsNumberSuppressed())
  1199. {
  1200. CCcs *pccs = pme->GetCcsBullet(&pols->_CFBullet);
  1201. if (pccs)
  1202. pccs->Release();
  1203. plspap->grpf |= fFmiAnm;
  1204. WCHAR *pchAnm = pols->_szAnm;
  1205. pols->_cchAnm = 0;
  1206. if (pPF->IsRtlPara()) //open character
  1207. *pchAnm++ = ' ';
  1208. //FUTURE (KeithCu) we turn off Indic digits if there is any Hebrew,
  1209. //which should be refined to do a better job with worldwide documents.
  1210. pols->_cchAnm += pPF->NumToStr(pchAnm, pme->GetNumber(),
  1211. (pme->GetPed()->GetCharFlags() & fHEBREW) ? 0 : fIndicDigits);
  1212. pchAnm += pols->_cchAnm;
  1213. if (pPF->IsRtlPara()) //End character for reverser
  1214. {
  1215. *pchAnm++ = wchObjectEnd;
  1216. pols->_cchAnm += 2; //alloc space for open and close
  1217. }
  1218. *pchAnm++ = ' '; //Ensure a little extra space
  1219. *pchAnm++ = wchObjectEnd; //End character for Anm
  1220. pols->_cchAnm += 2;
  1221. }
  1222. return lserrNone;
  1223. }
  1224. /*
  1225. * OlsFetchTabs(pols, LSCP cp, PLSTABS plstabs, BOOL *pfHangingTab,
  1226. * long *pduaHangingTab, WCHAR *pwchHangingTabLeader)
  1227. * @func
  1228. * Fetch tabs
  1229. *
  1230. * @rdesc
  1231. * LSERR
  1232. */
  1233. LSERR WINAPI OlsFetchTabs(
  1234. POLS pols, //(IN): (COls *)
  1235. LSCP cp, //(IN): Arbitrary cp value inside para
  1236. PLSTABS plstabs, //(OUT): Tabs array
  1237. BOOL * pfHangingTab, //(OUT): There is hanging tab
  1238. long * pduaHangingTab, //(OUT): dua of hanging tab
  1239. WCHAR * pwchHangingTabLeader) //(OUT): Leader of hanging tab
  1240. {
  1241. CMeasurer *pme = pols->GetMeasurer();
  1242. const CParaFormat *pPF = pme->Get_pPF();
  1243. const char rgchTabLeader[] = {0, '.', '-', '_', '_', '='};
  1244. LONG cTabCount = pPF->_bTabCount;
  1245. LONG i, iActual;
  1246. LSTBD * prgTab = pols->_rgTab;
  1247. const LONG *prgxTabs = pPF->GetTabs();
  1248. Assert(cTabCount <= MAX_TAB_STOPS && (prgxTabs || !cTabCount));
  1249. plstabs->duaIncrementalTab = pme->GetPed()->GetDefaultTab();
  1250. *pwchHangingTabLeader = 0;
  1251. *pduaHangingTab = pPF->_dxStartIndent + pPF->_dxOffset;
  1252. *pfHangingTab = (!(pPF->InTable()) && pPF->_dxOffset > 0);
  1253. for(i = 0, iActual = 0; i < cTabCount; i++)
  1254. {
  1255. LONG tbAlign, tbLeader;
  1256. pPF->GetTab(i, &prgTab[iActual].ua, &tbAlign, &tbLeader, prgxTabs);
  1257. pme->SetUseTargetDevice(FALSE);
  1258. if (pme->LXtoDX(prgTab[iActual].ua) > pols->_xWidth)
  1259. break;
  1260. if(pPF->InTable())
  1261. {
  1262. tbAlign = lsktLeft; // Don't have alignment and
  1263. tbLeader = 0; // leader yet
  1264. }
  1265. if(tbAlign <= tomAlignDecimal) // Don't include tomAlignBar
  1266. {
  1267. prgTab[iActual].lskt = (lsktab) tbAlign;
  1268. prgTab[iActual].wchTabLeader = rgchTabLeader[tbLeader];
  1269. iActual++;
  1270. }
  1271. }
  1272. plstabs->pTab = prgTab;
  1273. plstabs->iTabUserDefMac = iActual;
  1274. return lserrNone;
  1275. }
  1276. /*
  1277. * OlsCheckParaBoundaries (pols, cpOld, cpNew, pfChanged)
  1278. *
  1279. * @func
  1280. * Determine if para formatting between para containing cpOld and
  1281. * that containing cpNew are incompatible and shouldn't be formatted
  1282. * on the same line when connected by hidden text.
  1283. *
  1284. * @rdesc
  1285. * LSERR
  1286. */
  1287. LSERR WINAPI OlsCheckParaBoundaries(
  1288. POLS pols, //(IN): Interface object
  1289. LONG cpOld, //(IN): cp in one paragraph
  1290. LONG cpNew, //(IN): cp in another paragraph
  1291. BOOL * pfChanged) //(OUT): "Dangerous" change between para properties
  1292. {
  1293. // It's easier (and safer) to allow LS decide which para properties to take.
  1294. // Else we have to close objects (BiDi, for instance) before hidden EOP.
  1295. *pfChanged = fFalse; // they're always compatible
  1296. return lserrNone;
  1297. }
  1298. /*
  1299. * OlsGetRunCharWidths (pols, plrun, deviceID, lpwchRun, cwchRun, du,
  1300. * kTFlow, prgDu, pduRun, plimDu)
  1301. * @func
  1302. * Get run character widths
  1303. *
  1304. * @rdesc
  1305. * LSERR
  1306. */
  1307. LSERR WINAPI OlsGetRunCharWidths(
  1308. POLS pols, //(IN): Interface object
  1309. PLSRUN plsrun, //(IN): Run (cp here)
  1310. enum lsdevice deviceID, //(IN): Preview, reference, or absolute
  1311. LPCWSTR lpwchRun, //(IN): Run of characters
  1312. DWORD cwchRun, //(IN): Count of characters in run
  1313. long du, //(IN): Available space for characters
  1314. LSTFLOW kTFlow, //(IN): Text direction and orientation
  1315. int * prgDu, //(OUT): Widths of characters
  1316. long * pduRun, //(OUT): Sum of widths in rgDx[0] to rgDu[limDx-1]
  1317. long * plimDu) //(OUT): Number of widths fetched
  1318. {
  1319. CMeasurer *pme = pols->GetMeasurer();
  1320. BOOL fBullet = pols->SetRun(plsrun);
  1321. DWORD i = 0;
  1322. LONG xWidth, xAdjust, duCalc = 0;
  1323. BOOL fGlyphRun = FALSE;
  1324. pme->SetUseTargetDevice(deviceID == lsdevReference);
  1325. CCcs *pccs = pme->Check_pccs(fBullet);
  1326. if(!pccs)
  1327. return lserrOutOfMemory;
  1328. if (pme->GetPed()->IsComplexScript() &&
  1329. plsrun->_a.eScript && !plsrun->IsBullet())
  1330. {
  1331. const SCRIPT_PROPERTIES *psp = pme->Getusp()->GeteProp(plsrun->_a.eScript);
  1332. if (psp->fComplex)
  1333. fGlyphRun = TRUE;
  1334. }
  1335. xAdjust = pme->LXtoDX(plsrun->_pCF->_sSpacing);
  1336. for(;i < cwchRun; i++, lpwchRun++)
  1337. {
  1338. if (!fGlyphRun)
  1339. {
  1340. if (IsZerowidthCharacter(*lpwchRun))
  1341. xWidth = 0;
  1342. else
  1343. {
  1344. pccs->Include(*lpwchRun, xWidth);
  1345. xWidth = max(xWidth + xAdjust, 1);
  1346. }
  1347. }
  1348. else
  1349. {
  1350. xWidth = 0;
  1351. if (!IsDiacriticOrKashida(*lpwchRun, 0))
  1352. xWidth = pccs->_xAveCharWidth;
  1353. }
  1354. duCalc += xWidth; // Keep running total of width
  1355. *prgDu++ = xWidth; // Store width in output array
  1356. if(xWidth + duCalc > du) // Width exceeds width available
  1357. {
  1358. i++; // Count this char as processed
  1359. break;
  1360. }
  1361. }
  1362. *plimDu = i; // Store total chars processed
  1363. *pduRun = duCalc; // Store output total width
  1364. return lserrNone;
  1365. }
  1366. /*
  1367. * OlsGetRunTextMetrics (pols, plsrun, deviceID, kTFlow, plsTxMet)
  1368. *
  1369. * @func
  1370. * Get run text metrics
  1371. *
  1372. * @rdesc
  1373. * LSERR
  1374. */
  1375. LSERR WINAPI OlsGetRunTextMetrics(
  1376. POLS pols, //(IN): interface object
  1377. PLSRUN plsrun, //(IN): run (cp here)
  1378. enum lsdevice deviceID, //(IN): presentation or reference
  1379. LSTFLOW kTFlow, //(IN): text direction and orientation
  1380. PLSTXM plsTxMet) //(OUT): Text metrics
  1381. {
  1382. CMeasurer *pme = pols->GetMeasurer();
  1383. BOOL fBullet = pols->SetRun(plsrun);
  1384. // Make sure right font is set for run
  1385. pme->SetUseTargetDevice(deviceID == lsdevReference);
  1386. CCcs *pccs = pme->Check_pccs(fBullet);
  1387. if(!pccs)
  1388. return lserrOutOfMemory;
  1389. LONG yFEAdjust = pccs->AdjustFEHeight(pme->fAdjustFELineHt());
  1390. // Cache descent to save a few indirections
  1391. LONG yDescent = pccs->_yDescent + yFEAdjust;
  1392. // Fill in metric structure
  1393. plsTxMet->dvAscent = pccs->_yHeight + (yFEAdjust << 1) - yDescent;
  1394. plsTxMet->dvDescent = yDescent;
  1395. plsTxMet->dvMultiLineHeight = plsTxMet->dvAscent + yDescent;
  1396. plsTxMet->fMonospaced = pccs->_fFixPitchFont;
  1397. if (plsrun->_pCF->_yOffset)
  1398. {
  1399. LONG yOffset, yAdjust;
  1400. pccs->GetOffset(plsrun->_pCF, deviceID == lsdevReference ? pme->GetDyrInch() :
  1401. pme->GetDypInch(), &yOffset, &yAdjust);
  1402. if (yOffset < 0)
  1403. plsTxMet->dvDescent -= yOffset;
  1404. else
  1405. plsTxMet->dvAscent += yOffset;
  1406. }
  1407. return lserrNone;
  1408. }
  1409. /*
  1410. * OlsGetRunUnderlineInfo (pols, plsrun, pcheights, kTFlow, plsStInfo)
  1411. *
  1412. * @func
  1413. * Get run underline info
  1414. *
  1415. * @rdesc
  1416. * LSERR
  1417. */
  1418. LSERR WINAPI OlsGetRunUnderlineInfo(
  1419. POLS pols, //(IN): Interface object
  1420. PLSRUN plsrun, //(IN): Run (cp here)
  1421. PCHEIGHTS pcheights, //(IN): Height of line
  1422. LSTFLOW kTFlow, //(IN): Text direction and orientation
  1423. PLSULINFO plsUlInfo) //(OUT): Underline information
  1424. {
  1425. CMeasurer *pme = pols->GetMeasurer();
  1426. BOOL fBullet = pols->SetRun(plsrun);
  1427. // Initialize output buffer
  1428. ZeroMemory(plsUlInfo, sizeof(*plsUlInfo));
  1429. //REVIEW KeithCu
  1430. // Make sure right font is set for run
  1431. CCcs *pccs = pme->Check_pccs(fBullet);
  1432. if(!pccs)
  1433. return lserrOutOfMemory;
  1434. long dvpUlOffset = pccs->_dyULOffset;
  1435. plsUlInfo->cNumberOfLines = 1;
  1436. // Set underline type
  1437. if (plsrun->_pCF->_dwEffects & CFE_LINK)
  1438. plsUlInfo->kulbase = CFU_UNDERLINE;
  1439. else if (plsrun->_pCF->_dwEffects & (CFE_UNDERLINE | CFE_REVISED))
  1440. plsUlInfo->kulbase = plsrun->_pCF->_bUnderlineType;
  1441. else
  1442. {
  1443. Assert(pme->GetPed()->GetCpAccelerator() == plsrun->_cp);
  1444. plsUlInfo->kulbase = CFU_UNDERLINE;
  1445. }
  1446. LONG yDescent = pccs->_yDescent + pccs->AdjustFEHeight(pme->fAdjustFELineHt());
  1447. // Some fonts report invalid offset so we fix it up here
  1448. //BUGBUG: subscripts with Line Services don't display.
  1449. if(dvpUlOffset >= yDescent)
  1450. dvpUlOffset = yDescent - 1;
  1451. plsUlInfo->dvpFirstUnderlineOffset = dvpUlOffset;
  1452. plsUlInfo->dvpFirstUnderlineSize = pccs->_dyULWidth;
  1453. return lserrNone;
  1454. }
  1455. /*
  1456. * OlsGetRunStrikethroughInfo (pols, plsrun, pcheights, kTFlow, plsStInfo)
  1457. *
  1458. * @func
  1459. * Get run strikethrough info
  1460. *
  1461. * @rdesc
  1462. * LSERR
  1463. */
  1464. LSERR WINAPI OlsGetRunStrikethroughInfo(
  1465. POLS pols, //(IN): interface object
  1466. PLSRUN plsrun, //(IN): run
  1467. PCHEIGHTS pcheights, //(IN): height of line
  1468. LSTFLOW kTFlow, //(IN): text direction and orientation
  1469. PLSSTINFO plsStInfo) //(OUT): Strikethrough information
  1470. {
  1471. CMeasurer *pme = pols->GetMeasurer();
  1472. BOOL fBullet = pols->SetRun(plsrun);
  1473. AssertSz(plsrun->_pCF->_dwEffects & CFE_STRIKEOUT, "no strikeout");
  1474. // Make sure right font is set for run
  1475. CCcs *pccs = pme->Check_pccs(fBullet);
  1476. if(!pccs)
  1477. return lserrOutOfMemory;
  1478. // Default number of lines
  1479. plsStInfo->cNumberOfLines = 1;
  1480. plsStInfo->dvpLowerStrikethroughOffset = -pccs->_dySOOffset;
  1481. plsStInfo->dvpLowerStrikethroughSize = pccs->_dySOWidth;
  1482. return lserrNone;
  1483. }
  1484. /* OlsDrawUnderline (pols, plsrun, kUlbase, pptStart, dupUL, dvpUL,
  1485. * kTFlow, kDisp, prcClip)
  1486. * @func
  1487. * Draw underline
  1488. *
  1489. * @rdesc
  1490. * LSERR
  1491. */
  1492. LSERR WINAPI OlsDrawUnderline(
  1493. POLS pols, //(IN): interface object
  1494. PLSRUN plsrun, //(IN): run (cp) to use for underlining
  1495. UINT kUlbase, //(IN): underline kind
  1496. const POINT *pptStart, //(IN): starting position (top left)
  1497. DWORD dupUL, //(IN): underline width
  1498. DWORD dvpUL, //(IN): underline thickness
  1499. LSTFLOW lstflow, //(IN): text direction and orientation
  1500. UINT kDisp, //(IN): display mode - opaque, transparent
  1501. const RECT *prcClip) //(IN): clipping rectangle
  1502. {
  1503. CRenderer *pre = pols->GetRenderer();
  1504. Assert(pre->IsRenderer());
  1505. pols->SetRun(plsrun);
  1506. pre->Check_pccs();
  1507. pre->SetSelected(plsrun->IsSelected());
  1508. pre->SetFontAndColor(plsrun->_pCF);
  1509. pre->SetupUnderline(kUlbase);
  1510. pre->RenderUnderline(lstflow == lstflowWS ? pptStart->x - dupUL - 1:
  1511. pptStart->x, pptStart->y, dupUL, dvpUL);
  1512. return lserrNone;
  1513. }
  1514. /*
  1515. * OlsDrawStrikethrough (pols, plsrun, kStbase, pptStart, dupSt, dvpSt,
  1516. * kTFlow, kDisp, prcClip)
  1517. * @func
  1518. * Draw strikethrough
  1519. *
  1520. * @rdesc
  1521. * LSERR
  1522. */
  1523. LSERR WINAPI OlsDrawStrikethrough(
  1524. POLS pols, //(IN): Interface object
  1525. PLSRUN plsrun, //(IN): run (cp) for strikethrough
  1526. UINT kStbase, //(IN): strikethrough kind
  1527. const POINT *pptStart, //(IN): starting position (top left)
  1528. DWORD dupSt, //(IN): strikethrough width
  1529. DWORD dvpSt, //(IN): strikethrough thickness
  1530. LSTFLOW lstflow, //(IN): text direction and orientation
  1531. UINT kDisp, //(IN): display mode - opaque, transparent
  1532. const RECT *prcClip) //(IN): clipping rectangle
  1533. {
  1534. CRenderer *pre = pols->GetRenderer();
  1535. Assert(pre->IsRenderer());
  1536. pols->SetRun(plsrun);
  1537. pre->SetSelected(plsrun->IsSelected());
  1538. pre->RenderStrikeOut(lstflow == lstflowWS ? pptStart->x - dupSt - 1:
  1539. pptStart->x, pptStart->y, dupSt, dvpSt);
  1540. return lserrNone;
  1541. }
  1542. /*
  1543. * OlsFInterruptUnderline(pols, plsrunFirst, cpLastFirst, plsrunSecond,
  1544. * cpStartSecond, pfInterruptUnderline)
  1545. * @func
  1546. * Says whether client wants to interrupt drawing of underline
  1547. * between the first and second runs
  1548. *
  1549. * @rdesc
  1550. * LSERR
  1551. */
  1552. LSERR WINAPI OlsFInterruptUnderline(
  1553. POLS pols, //(IN): Client context
  1554. PLSRUN plsrunFirst, //(IN): Run pointer for previous run
  1555. LSCP cpLastFirst, //(IN): cp of last character of previous run
  1556. PLSRUN plsrunSecond, //(IN): Run pointer for current run
  1557. LSCP cpStartSecond, //(IN): cp of first character of current run
  1558. BOOL * pfInterruptUnderline)//(OUT): Interrupt underline between runs?
  1559. {
  1560. CRenderer *pre = pols->GetRenderer();
  1561. Assert(pre->IsRenderer());
  1562. pre->SetSelected(FALSE); //Selection is handled below
  1563. COLORREF cr = pre->GetTextColor(plsrunFirst->_pCF);
  1564. // Interrupt underline if run text colors differ
  1565. *pfInterruptUnderline = cr != pre->GetTextColor(plsrunSecond->_pCF) ||
  1566. plsrunFirst->IsSelected() != plsrunSecond->IsSelected();
  1567. return lserrNone;
  1568. }
  1569. /*
  1570. * OlsDrawTextRun (pols, plsrun, kStbase, pptStart, dupSt, dvpSt,
  1571. * kTFlow, kDisp, prcClip)
  1572. * @func
  1573. * Draw text run
  1574. *
  1575. * @rdesc
  1576. * LSERR
  1577. */
  1578. LSERR WINAPI OlsDrawTextRun(
  1579. POLS pols, //(IN): Interface object
  1580. PLSRUN plsrun, //(IN): Run (cp) to use for text
  1581. BOOL fStrikeoutOkay, //(IN): TRUE <==> allow strikeout
  1582. BOOL fUnderlineOkay, //(IN): TRUE <==> allow underlining
  1583. const POINT *ppt, //(IN): Starting position
  1584. LPCWSTR pwchRun, //(IN): Run of characters
  1585. const int * rgDupRun, //(IN): Character widths
  1586. DWORD cwchRun, //(IN): Count of chars in run
  1587. LSTFLOW lstflow, //(IN): Text direction and orientation
  1588. UINT kDisp, //(IN): Display mode - opaque, transparent
  1589. const POINT *pptRun, //(IN): Starting point of run
  1590. PCHEIGHTS pheightsPres, //(IN): Presentation heights for run
  1591. long dupRun, //(IN): Presentation width for run
  1592. long dupUlLimRun, //(IN): Underlining limit
  1593. const RECT *prcClip) //(IN): Clipping rectangle
  1594. {
  1595. CRenderer *pre = pols->GetRenderer();
  1596. RECT rc = *prcClip;
  1597. Assert(pre->IsRenderer());
  1598. // Set up drawing point and options
  1599. BOOL fBullet = pols->SetRun(plsrun);
  1600. CCcs *pccs = pre->Check_pccs(fBullet);
  1601. if(!pccs)
  1602. return lserrOutOfMemory;
  1603. // y needs to be moved from baseline to top of character
  1604. POINT pt = {ppt->x, ppt->y - (pccs->_yHeight - pccs->_yDescent)};
  1605. if (lstflow == lstflowWS)
  1606. pt.x -= dupRun - 1;
  1607. pre->SetSelected(plsrun->IsSelected());
  1608. pre->SetFontAndColor(plsrun->_pCF);
  1609. if(!fBullet && pre->fBackgroundColor())
  1610. {
  1611. kDisp = ETO_OPAQUE | ETO_CLIPPED;
  1612. POINT ptCur = pre->GetCurPoint();
  1613. ptCur.x = pt.x;
  1614. pre->SetCurPoint(ptCur);
  1615. pre->SetClipLeftRight(dupRun);
  1616. rc = pre->GetClipRect();
  1617. }
  1618. else if (cwchRun == 1 && pwchRun[0] == ' ') //Don't waste time drawing a space.
  1619. return lserrNone; //(helps grid perf test a lot)
  1620. pre->RenderExtTextOut(pt.x, pt.y, kDisp, &rc, pwchRun, cwchRun, rgDupRun);
  1621. return lserrNone;
  1622. }
  1623. /*
  1624. * GetBreakingClasses (pols, plsrun, ch, pbrkclsBefore, pbrkclsAfter)
  1625. *
  1626. * @func
  1627. * Line services calls this callback for each run, to obtain the
  1628. * breaking classes (line breaking behaviors) for each character
  1629. *
  1630. * For Quill and RichEdit, the breaking class of a character is
  1631. * independent of whether it occurs Before or After a break opportunity.
  1632. *
  1633. * @rdesc
  1634. * LSERR
  1635. */
  1636. LSERR WINAPI OlsGetBreakingClasses(
  1637. POLS pols, //(IN): Interface object
  1638. PLSRUN plsrun, //(IN): Run (cp) to use for text
  1639. LSCP cpLs, //(IN): cp of the character
  1640. WCHAR ch, //(IN): Char to return breaking classes for
  1641. BRKCLS *pbrkclsBefore, //(OUT): Breaking class if ch is lead char in pair
  1642. BRKCLS *pbrkclsAfter) //(OUT): Breaking class if ch is trail char in pair
  1643. {
  1644. long cpRe = pols->GetCpReFromCpLs(cpLs);
  1645. CMeasurer *pme = pols->GetMeasurer();
  1646. CTxtBreaker *pbrk = pme->GetPed()->_pbrk;
  1647. // Get line breaking class and report it twice
  1648. *pbrkclsBefore = *pbrkclsAfter = (pbrk && pbrk->CanBreakCp(BRK_WORD, cpRe)) ?
  1649. brkclsOpen :
  1650. GetKinsokuClass(ch);
  1651. return lserrNone;
  1652. }
  1653. /*
  1654. * OlsFTruncateBefore (pols, cpCur, wchCur, durCur, cpPrev, wchPrev,
  1655. * durPrev, durCut, pfTruncateBefore)
  1656. * @func
  1657. * Line services support function. This should always return
  1658. * FALSE for best performance
  1659. *
  1660. * @rdesc
  1661. * LSERR
  1662. */
  1663. LSERR WINAPI OlsFTruncateBefore(
  1664. POLS pols, // (IN): Client context
  1665. PLSRUN plsrunCur, // (IN): PLSRUN of cp
  1666. LSCP cpCur, // (IN): cp of truncation char
  1667. WCHAR wchCur, // (IN): Truncation character
  1668. long durCur, // (IN): Width of truncation char
  1669. PLSRUN plsrunPrev, // (IN): PLSRUN of cpPrev
  1670. LSCP cpPrev, // (IN): cp of truncation char
  1671. WCHAR wchPrev, // (IN): Truncation character
  1672. long durPrev, // (IN): Width of truncation character
  1673. long durCut, // (IN): Width from RM until end of current char
  1674. BOOL * pfTruncateBefore) // (OUT): Truncation point is before this char
  1675. {
  1676. *pfTruncateBefore = FALSE;
  1677. return lserrNone;
  1678. }
  1679. /*
  1680. * OlsCanBreakBeforeChar (pols, brkcls, pcond)
  1681. *
  1682. * @func
  1683. * Line services calls this callback for a break candidate following an
  1684. * inline object, to determine whether breaks are prevented, possible or
  1685. * mandatory
  1686. *
  1687. * @rdesc
  1688. * LSERR
  1689. */
  1690. LSERR WINAPI OlsCanBreakBeforeChar(
  1691. POLS pols, //(IN): Client context
  1692. BRKCLS brkcls, //(IN): Breaking class
  1693. BRKCOND *pcond) //(OUT): Corresponding break condition
  1694. {
  1695. switch (brkcls)
  1696. {
  1697. default:
  1698. *pcond = brkcondCan;
  1699. break;
  1700. case brkclsClose:
  1701. case brkclsNoStartIdeo:
  1702. case brkclsExclaInterr:
  1703. case brkclsGlueA:
  1704. *pcond = brkcondNever;
  1705. break;
  1706. case brkclsIdeographic:
  1707. case brkclsSpaceN:
  1708. case brkclsSlash:
  1709. *pcond = brkcondPlease;
  1710. break;
  1711. };
  1712. return lserrNone;
  1713. }
  1714. /*
  1715. * OlsCanBreakAfterChar (pols, brkcls, pcond)
  1716. *
  1717. * @func
  1718. * Line services calls this callback for a break candidate preceding an
  1719. * inline object, to determine whether breaks are prevented, possible or
  1720. * mandatory
  1721. *
  1722. * @rdesc
  1723. * LSERR
  1724. */
  1725. LSERR WINAPI OlsCanBreakAfterChar(
  1726. POLS pols, //(IN): Client context
  1727. BRKCLS brkcls, //(IN): Breaking class
  1728. BRKCOND *pcond) //(OUT): Corresponding break condition
  1729. {
  1730. switch (brkcls)
  1731. {
  1732. default:
  1733. *pcond = brkcondCan;
  1734. break;
  1735. case brkclsOpen:
  1736. case brkclsGlueA:
  1737. *pcond = brkcondNever;
  1738. break;
  1739. case brkclsIdeographic:
  1740. case brkclsSpaceN:
  1741. case brkclsSlash:
  1742. *pcond = brkcondPlease;
  1743. break;
  1744. };
  1745. return lserrNone;
  1746. }
  1747. /*
  1748. * OlsFInterruptShaping (pols, kTFlow, plsrunFirst, plsrunSecond, pfInterruptShaping)
  1749. *
  1750. * @func
  1751. * Line services calls this callback to find out if you
  1752. * would like to ligate across these two runs.
  1753. *
  1754. * @rdesc
  1755. * LSERR
  1756. */
  1757. LSERR WINAPI OlsFInterruptShaping(
  1758. POLS pols, //(IN): Client context
  1759. LSTFLOW kTFlow, //(IN): Text direction and orientation
  1760. PLSRUN plsrunFirst, //(IN): Run #1
  1761. PLSRUN plsrunSecond, //(IN): Run #2
  1762. BOOL *pfInterruptShaping) //(OUT): Shape across these 2 runs?
  1763. {
  1764. *pfInterruptShaping = FALSE;
  1765. const CCharFormat* pCFFirst = plsrunFirst->_pCF;
  1766. const CCharFormat* pCFSecond = plsrunSecond->_pCF;
  1767. Assert (plsrunFirst->_a.eScript && plsrunSecond->_a.eScript);
  1768. const DWORD dwMask = CFE_BOLD | CFE_ITALIC | CFM_SUBSCRIPT;
  1769. if (pCFFirst == pCFSecond ||
  1770. (plsrunFirst->_a.eScript == plsrunSecond->_a.eScript &&
  1771. !((pCFFirst->_dwEffects ^ pCFSecond->_dwEffects) & dwMask) &&
  1772. pCFFirst->_iFont == pCFSecond->_iFont &&
  1773. pCFFirst->_yOffset == pCFSecond->_yOffset &&
  1774. pCFFirst->_yHeight == pCFSecond->_yHeight))
  1775. {
  1776. // establish link
  1777. plsrunFirst->_pNext = plsrunSecond;
  1778. return lserrNone;
  1779. }
  1780. *pfInterruptShaping = TRUE;
  1781. return lserrNone;
  1782. }
  1783. // LS calls this callback to shape the codepoint string to a glyph indices string
  1784. // for handling glyph based script such as Arabic, Hebrew and Thai.
  1785. //
  1786. LSERR OlsGetGlyphs(
  1787. POLS pols,
  1788. PLSRUN plsrun,
  1789. LPCWSTR pwch,
  1790. DWORD cch,
  1791. LSTFLOW kTFlow,
  1792. PGMAP pgmap, // OUT: array of logical cluster information
  1793. PGINDEX* ppgi, // OUT: array of output glyph indices
  1794. PGPROP* ppgprop, // OUT: array of glyph's properties
  1795. DWORD* pcgi) // OUT: number of glyph generated
  1796. {
  1797. pols->SetRun(plsrun);
  1798. CMeasurer* pme = pols->GetMeasurer();
  1799. CUniscribe* pusp = pme->Getusp();
  1800. Assert (pusp);
  1801. WORD* pwgi;
  1802. SCRIPT_VISATTR *psva;
  1803. int cgi;
  1804. pme->SetGlyphing(TRUE);
  1805. // Glyphing doesn't care about the target device but always
  1806. // using target device reduces creation of Cccs in general.
  1807. pme->SetUseTargetDevice(TRUE);
  1808. AssertSz(IN_RANGE(1, plsrun->_a.eScript, SCRIPT_MAX_COUNT - 1), "Bad script ID!");
  1809. // Digit substitution
  1810. pusp->SubstituteDigitShaper(plsrun, pme);
  1811. if (!(cgi = (DWORD)pusp->ShapeString(plsrun, &plsrun->_a, pme, pwch, (int)cch, pwgi, pgmap, psva)))
  1812. {
  1813. const SCRIPT_ANALYSIS saUndef = {SCRIPT_UNDEFINED,0,0,0,0,0,0,{0}};
  1814. // Current font cant shape given string.
  1815. // Try SCRIPT_UNDEF so it generates invalid glyphs
  1816. if (!(cgi = (DWORD)pusp->ShapeString(plsrun, (SCRIPT_ANALYSIS*)&saUndef, pme, pwch, (int)cch, pwgi, pgmap, psva)))
  1817. {
  1818. // For whatever reason we still fails.
  1819. // Abandon glyph processing.
  1820. plsrun->_a.fNoGlyphIndex = TRUE;
  1821. cgi = (DWORD)pusp->ShapeString(plsrun, &plsrun->_a, pme, pwch, (int)cch, pwgi, pgmap, psva);
  1822. }
  1823. }
  1824. *pcgi = cgi;
  1825. DupShapeState(plsrun, cch);
  1826. *ppgi = (PGINDEX)pwgi;
  1827. *ppgprop = (PGPROP)psva;
  1828. pme->SetGlyphing(FALSE);
  1829. return lserrNone;
  1830. }
  1831. // LS calls this callback to find out glyph positioning for complex scripts
  1832. //
  1833. LSERR OlsGetGlyphPositions(
  1834. POLS pols,
  1835. PLSRUN plsrun,
  1836. LSDEVICE deviceID,
  1837. LPWSTR pwch,
  1838. PCGMAP pgmap,
  1839. DWORD cch,
  1840. PCGINDEX pgi,
  1841. PCGPROP pgprop,
  1842. DWORD cgi,
  1843. LSTFLOW kTFlow,
  1844. int* pgdx, // OUT: array of glyph advanced width
  1845. PGOFFSET pgduv) // OUT: array of offset between glyphs
  1846. {
  1847. pols->SetRun(plsrun);
  1848. CMeasurer* pme = pols->GetMeasurer();
  1849. CUniscribe* pusp = pme->Getusp();
  1850. Assert (pusp);
  1851. Assert(pgduv);
  1852. pme->SetGlyphing(TRUE);
  1853. // zero out before passing to shaping engine
  1854. ZeroMemory ((void*)pgduv, cgi*sizeof(GOFFSET));
  1855. pme->SetUseTargetDevice(deviceID == lsdevReference);
  1856. AssertSz(IN_RANGE(1, plsrun->_a.eScript, SCRIPT_MAX_COUNT - 1), "Bad script ID!");
  1857. if (!pusp->PlaceString(plsrun, &plsrun->_a, pme, pgi, cgi, (const SCRIPT_VISATTR*)pgprop, pgdx, pgduv, NULL))
  1858. {
  1859. SCRIPT_ANALYSIS saUndef = {SCRIPT_UNDEFINED,0,0,0,0,0,0,{0}};
  1860. if (!pusp->PlaceString(plsrun, &saUndef, pme, pgi, cgi, (const SCRIPT_VISATTR*)pgprop, pgdx, pgduv, NULL))
  1861. {
  1862. plsrun->_a.fNoGlyphIndex = TRUE;
  1863. pusp->PlaceString(plsrun, &plsrun->_a, pme, pgi, cgi, (const SCRIPT_VISATTR*)pgprop, pgdx, pgduv, NULL);
  1864. }
  1865. }
  1866. DupShapeState(plsrun, cch);
  1867. pme->SetGlyphing(FALSE);
  1868. return lserrNone;
  1869. }
  1870. LSERR OlsDrawGlyphs(
  1871. POLS pols,
  1872. PLSRUN plsrun,
  1873. BOOL fStrikeOut,
  1874. BOOL fUnderline,
  1875. PCGINDEX pcgi,
  1876. const int* pgdx, // array of glyph width
  1877. const int* pgdxo, // array of original glyph width (before justification)
  1878. PGOFFSET pgduv, // array of glyph offset
  1879. PGPROP pgprop, // array of glyph's properties
  1880. PCEXPTYPE pgxtype, // array of expansion type
  1881. DWORD cgi,
  1882. LSTFLOW kTFlow,
  1883. UINT kDisp,
  1884. const POINT* pptRun,
  1885. PCHEIGHTS pHeight,
  1886. long dupRun,
  1887. long dupLimUnderline,
  1888. const RECT* prectClip)
  1889. {
  1890. BOOL fBullet = pols->SetRun(plsrun);
  1891. CRenderer* pre = pols->GetRenderer();
  1892. CUniscribe* pusp = pre->Getusp();
  1893. Assert(pusp && pre->IsRenderer());
  1894. pre->SetGlyphing(TRUE);
  1895. RECT rc = *prectClip;
  1896. CCcs* pccs = pre->Check_pccs(fBullet);
  1897. if (!pccs)
  1898. return lserrOutOfMemory;
  1899. // Apply fallback font if we need to
  1900. if (!fBullet)
  1901. pccs = pre->ApplyFontCache(plsrun->IsFallback());
  1902. pre->SetSelected(plsrun->IsSelected());
  1903. pre->SetFontAndColor(plsrun->_pCF);
  1904. // y needs to be moved from baseline to top of character
  1905. POINT pt = {pptRun->x, pptRun->y - (pccs->_yHeight - pccs->_yDescent)};
  1906. if (kTFlow == lstflowWS)
  1907. pt.x -= dupRun - 1;
  1908. if(!fBullet && pre->fBackgroundColor())
  1909. {
  1910. kDisp = ETO_OPAQUE | ETO_CLIPPED;
  1911. POINT ptCur = pre->GetCurPoint();
  1912. ptCur.x = pt.x;
  1913. pre->SetCurPoint(ptCur);
  1914. pre->SetClipLeftRight(dupRun);
  1915. rc = pre->GetClipRect();
  1916. }
  1917. if (rc.left == rc.right)
  1918. goto Exit;
  1919. if (pre->GetPdp()->IsMetafile() && !IsEnhancedMetafileDC(pre->GetDC()))
  1920. {
  1921. // -WMF metafile handling-
  1922. //
  1923. // If the rendering device is WMF metafile. We metafile the codepoint array
  1924. // instead of glyph indices. This requires that the target OS must know how to
  1925. // playback complex script text (shaping, Bidi algorithm, etc.).
  1926. // Metafiling glyph indices only works for EMF since the WMF's META_EXTTEXTOUT
  1927. // record stores the input string as an array of byte but a glyph index is 16-bit
  1928. // word element.
  1929. // WMF also must NOT be used to record ExtTextOutW call otherwise the Unicode
  1930. // string will be converted to mutlibyte text using system codepage. Anything
  1931. // outside the codepage then becomes '?'.
  1932. // We have the workaround for such case in REExtTextOut to make sure we only
  1933. // metafile ExtTextOutA to WMF. (wchao)
  1934. //
  1935. LONG cch;
  1936. const WCHAR* pwch = pre->GetPch(cch);
  1937. PINT piDx;
  1938. cch = min(cch, pre->GetCchLeftRunCF());
  1939. cch = min(cch, pre->GetLine()._cch - plsrun->_cp + pols->_cp);
  1940. // make sure that we record ETO with proper reading order.
  1941. kDisp |= plsrun->_a.fRTL ? ETO_RTLREADING : 0;
  1942. if (pusp->PlaceMetafileString(plsrun, pre, pwch, (int)cch, &piDx))
  1943. {
  1944. pre->RenderExtTextOut(pt.x, pt.y, kDisp, &rc, pwch, cch, piDx);
  1945. goto Exit;
  1946. }
  1947. TRACEERRORSZ("Recording metafile failed!");
  1948. // Fall through... with unexpected error
  1949. // Else, metafile glyph indices for EMF...
  1950. }
  1951. //This is duplicated from RenderExtTextOut but the params are different so simplest solution
  1952. //was to copy code.
  1953. if(pre->_fDisabled)
  1954. {
  1955. if(pre->_crForeDisabled != pre->_crShadowDisabled)
  1956. {
  1957. // The shadow should be offset by a hairline point, namely
  1958. // 3/4 of a point. Calculate how big this is in device units,
  1959. // but make sure it is at least 1 pixel.
  1960. DWORD offset = MulDiv(3, pre->_dypInch, 4*72);
  1961. offset = max(offset, 1);
  1962. // Draw shadow
  1963. pre->SetTextColor(pre->_crShadowDisabled);
  1964. ScriptTextOut(pre->GetDC(), &pccs->_sc, pt.x + offset, pt.y + offset, kDisp, &rc, &plsrun->_a,
  1965. NULL, 0, pcgi, (int)cgi, pgdx, NULL, pgduv);
  1966. // Now set drawing mode to transparent
  1967. kDisp &= ~ETO_OPAQUE;
  1968. }
  1969. pre->SetTextColor(pre->_crForeDisabled);
  1970. }
  1971. ScriptTextOut(pre->GetDC(), &pccs->_sc, pt.x, pt.y, kDisp, &rc, &plsrun->_a,
  1972. NULL, 0, pcgi, (int)cgi, pgdx, NULL, pgduv);
  1973. Exit:
  1974. if (!fBullet)
  1975. pre->ApplyFontCache(0); // reset font fallback if any
  1976. pre->SetGlyphing(FALSE);
  1977. return lserrNone;
  1978. }
  1979. /*
  1980. * OlsResetRunContents (pols, brkcls, pcond)
  1981. *
  1982. * @func
  1983. * Line Services calls this routine when a ligature
  1984. * extends across run boundaries.
  1985. *
  1986. * We don't have to do anything special here if we are
  1987. * careful about how we use our PLSRUNs.
  1988. * @rdesc
  1989. * LSERR
  1990. */
  1991. LSERR WINAPI OlsResetRunContents(
  1992. POLS pols, //(IN): Client context
  1993. PLSRUN plsrun, //(IN): Run being combined
  1994. LSCP cpFirstOld, //(IN): cp of the first run being combined
  1995. LSDCP dcpOld, //(IN): dcp of the first run being combined
  1996. LSCP cpFirstNew, //(IN): new cp of the run
  1997. LSDCP dcpNew) //(IN): new dcp of the run
  1998. {
  1999. return lserrNone;
  2000. }
  2001. /*
  2002. * OlsCheckForDigit (pols, cp, plspap)
  2003. *
  2004. * @func
  2005. * Get numeric separators needed, e.g., for decimal tabs
  2006. *
  2007. * @rdesc
  2008. * LSERR
  2009. */
  2010. LSERR WINAPI OlsCheckForDigit(
  2011. POLS pols, //(IN): pols
  2012. PLSRUN plsrun, //(IN): Run (cp here)
  2013. WCHAR wch, //(IN): Character to check
  2014. BOOL * pfIsDigit) //(OUT): This character is digit
  2015. {
  2016. WORD wType;
  2017. // We could get the run LCID to use for the first parm in the following
  2018. // call, but the digit property should be independent of LCID.
  2019. W32->GetStringTypeEx(0, CT_CTYPE1, &wch, 1, &wType);
  2020. *pfIsDigit = (wType & C1_DIGIT) != 0;
  2021. return lserrNone;
  2022. }
  2023. /*
  2024. * OlsGetBreakThroughTab(pols, uaRightMargin, uaTabPos, puaRightMarginNew)
  2025. *
  2026. * @func
  2027. * Just follow word95 behavior.
  2028. *
  2029. * @rdesc
  2030. * LSERR
  2031. */
  2032. LSERR WINAPI OlsGetBreakThroughTab(
  2033. POLS pols, //(IN): client context
  2034. long uaRightMargin, //(IN): right margin for breaking
  2035. long uaTabPos, //(IN): breakthrough tab position
  2036. long * puaRightMarginNew) //(OUT): new right margin
  2037. {
  2038. *puaRightMarginNew = 20 * 1440;
  2039. return lserrNone;
  2040. }
  2041. /*
  2042. * OlsFGetLastLineJustification(pols, lskj, endr, pfJustifyLastLine)
  2043. *
  2044. * @func
  2045. * Just say no to justify last line.
  2046. *
  2047. * @rdesc
  2048. * LSERR
  2049. */
  2050. LSERR WINAPI OlsFGetLastLineJustification(
  2051. POLS pols, //(IN): client context
  2052. LSKJUST lskj, //(IN): kind of justification
  2053. LSKALIGN lskal, //(IN): kind of alignment
  2054. ENDRES endr, //(IN): result of formatting
  2055. BOOL *pfJustifyLastLine, //(OUT): should last line be fully justified
  2056. LSKALIGN *plskalLine) //(OUT): kind of alignment for this line
  2057. {
  2058. *pfJustifyLastLine = FALSE;
  2059. *plskalLine = lskal;
  2060. return lserrNone;
  2061. }
  2062. /*
  2063. * OlsGetHyphenInfo(pols, plsrun, pkysr, pwchYsr)
  2064. *
  2065. * @func
  2066. * We don't support fancy YSR types, tell LS so.
  2067. *
  2068. * @rdesc
  2069. * LSERR
  2070. */
  2071. LSERR WINAPI OlsGetHyphenInfo(
  2072. POLS pols, //(IN): client context
  2073. PLSRUN plsrun, //(IN)
  2074. DWORD* pkysr, //(OUT): Ysr type - see "lskysr.h"
  2075. WCHAR* pwchYsr) //(OUT): Character code of YSR
  2076. {
  2077. *pkysr = kysrNil;
  2078. *pwchYsr = 0;
  2079. return lserrNone;
  2080. }
  2081. /*
  2082. * OlsReleaseRun (pols, plsrun)
  2083. *
  2084. * @func
  2085. * We do nothing because the run is in an array and is
  2086. * released automatically.
  2087. *
  2088. * @rdesc
  2089. * LSERR
  2090. */
  2091. LSERR WINAPI OlsReleaseRun(
  2092. POLS pols, //(IN): interface object
  2093. PLSRUN plsrun) //(IN): run (cp) to use for underlining
  2094. {
  2095. return lserrNone;
  2096. }
  2097. /*
  2098. * OlsNewPtr(pols, cBytes)
  2099. *
  2100. * @func
  2101. * Memory allocator.
  2102. */
  2103. void* WINAPI OlsNewPtr(
  2104. POLS pols, //@parm Not used
  2105. DWORD cBytes) //@parm Count of bytes to alloc
  2106. {
  2107. return PvAlloc(cBytes, 0);
  2108. }
  2109. /*
  2110. * OlsDisposePtr(pols, pv)
  2111. *
  2112. * @func
  2113. * Memory deallocator.
  2114. */
  2115. void WINAPI OlsDisposePtr(
  2116. POLS pols, //@parm Not used
  2117. void * pv) //@parm [in]: ptr to free
  2118. {
  2119. FreePv(pv);
  2120. }
  2121. /*
  2122. * OlsDisposePtr(pols, pv, cBytes)
  2123. *
  2124. * @func
  2125. * Memory reallocator.
  2126. */
  2127. void* WINAPI OlsReallocPtr(
  2128. POLS pols, //@parm Not used
  2129. void * pv, //@parm [in/out]: ptr to realloc
  2130. DWORD cBytes) //@parm Count of bytes to realloc
  2131. {
  2132. return PvReAlloc(pv, cBytes);
  2133. }
  2134. const REVERSEINIT reverseinit =
  2135. {
  2136. REVERSE_VERSION,
  2137. wchObjectEnd
  2138. };
  2139. LSERR WINAPI OlsGetObjectHandlerInfo(POLS pols, DWORD idObj, void* pObjectInfo)
  2140. {
  2141. switch (idObj)
  2142. {
  2143. case OBJID_REVERSE:
  2144. memcpy(pObjectInfo, (void *)&reverseinit, sizeof(REVERSEINIT));
  2145. break;
  2146. default:
  2147. AssertSz(0, "Undefined Object handler. Add missing case.");
  2148. }
  2149. return lserrNone;
  2150. }
  2151. #ifdef DEBUG
  2152. /* Debugging APIs */
  2153. void WINAPI OlsAssertFailed(
  2154. char *sz,
  2155. char *szFile,
  2156. int iLine)
  2157. {
  2158. AssertSzFn(sz, szFile, iLine);
  2159. }
  2160. #endif
  2161. extern const LSCBK lscbk =
  2162. {
  2163. OlsNewPtr, // pfnNewPtr
  2164. OlsDisposePtr, // pfnDisposePtr
  2165. OlsReallocPtr, // pfnReallocPtr
  2166. OlsFetchRun, // pfnFetchRun
  2167. OlsGetAutoNumberInfo, // pfnGetAutoNumberInfo
  2168. OlsGetNumericSeparators, // pfnGetNumericSeparators
  2169. OlsCheckForDigit, // pfnCheckForDigit
  2170. OlsFetchPap, // pfnFetchPap
  2171. OlsFetchTabs, // pfnFetchTabs
  2172. OlsGetBreakThroughTab, // pfnGetBreakThroughTab
  2173. OlsFGetLastLineJustification,// pfnFGetLastLineJustification
  2174. OlsCheckParaBoundaries, // pfnCheckParaBoundaries
  2175. OlsGetRunCharWidths, // pfnGetRunCharWidths
  2176. 0, // pfnCheckRunKernability
  2177. 0, // pfnGetRunCharKerning
  2178. OlsGetRunTextMetrics, // pfnGetRunTextMetrics
  2179. OlsGetRunUnderlineInfo, // pfnGetRunUnderlineInfo
  2180. OlsGetRunStrikethroughInfo, // pfnGetRunStrikethroughInfo
  2181. 0, // pfnGetBorderInfo
  2182. OlsReleaseRun, // pfnReleaseRun
  2183. 0, // pfnHyphenate
  2184. OlsGetHyphenInfo, // pfnGetHyphenInfo
  2185. OlsDrawUnderline, // pfnDrawUnderline
  2186. OlsDrawStrikethrough, // pfnDrawStrikethrough
  2187. 0, // pfnDrawBorder
  2188. 0, // pfnDrawUnderlineAsText //REVIEW (keithcu) Need to implement this??
  2189. OlsFInterruptUnderline, // pfnFInterruptUnderline
  2190. 0, // pfnFInterruptShade
  2191. 0, // pfnFInterruptBorder
  2192. 0, // pfnShadeRectangle
  2193. OlsDrawTextRun, // pfnDrawTextRun
  2194. 0, // pfnDrawSplatLine
  2195. OlsFInterruptShaping, // pfnFInterruptShaping
  2196. OlsGetGlyphs, // pfnGetGlyphs
  2197. OlsGetGlyphPositions, // pfnGetGlyphPositions
  2198. OlsResetRunContents, // pfnResetRunContents
  2199. OlsDrawGlyphs, // pfnDrawGlyphs
  2200. 0, // pfnGetGlyphExpansionInfo
  2201. 0, // pfnGetGlyphExpansionInkInfo
  2202. 0, // pfnGetEms
  2203. 0, // pfnPunctStartLine
  2204. 0, // pfnModWidthOnRun
  2205. 0, // pfnModWidthSpace
  2206. 0, // pfnCompOnRun
  2207. 0, // pfnCompWidthSpace
  2208. 0, // pfnExpOnRun
  2209. 0, // pfnExpWidthSpace
  2210. 0, // pfnGetModWidthClasses
  2211. OlsGetBreakingClasses, // pfnGetBreakingClasses
  2212. OlsFTruncateBefore, // pfnFTruncateBefore
  2213. OlsCanBreakBeforeChar, // pfnCanBreakBeforeChar
  2214. OlsCanBreakAfterChar, // pfnCanBreakAfterChar
  2215. 0, // pfnFHangingPunct
  2216. 0, // pfnGetSnapGrid
  2217. 0, // pfnDrawEffects
  2218. 0, // pfnFCancelHangingPunct
  2219. 0, // pfnModifyCompAtLastChar
  2220. 0, // pfnEnumText
  2221. 0, // pfnEnumTab
  2222. 0, // pfnEnumPen
  2223. OlsGetObjectHandlerInfo, // pfnGetObjectHandlerInfo
  2224. #ifdef DEBUG
  2225. OlsAssertFailed // pfnAssertFailed
  2226. #else
  2227. 0 // pfnAssertFailed
  2228. #endif
  2229. };
  2230. #endif // LINESERVICES