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.

3885 lines
106 KiB

  1. /*
  2. * @doc EXTERNAL
  3. *
  4. * @module TEXTSERV.CPP -- Text Services Implementation |
  5. *
  6. * Original Author: <nl>
  7. * Rick Sailor
  8. *
  9. * History: <nl>
  10. * 8/1/95 ricksa Created and documented
  11. * 10/95 murrays Further doc and simplifications
  12. *
  13. * Documentation is generated straight from the code. The following
  14. * date/time stamp indicates the version of code from which the
  15. * the documentation was generated.
  16. *
  17. * $Header: /richedit/src/textserv.cpp 53 11/15/95 2:39p Ricksa $
  18. *
  19. * Copyright (c) 1995-2001, Microsoft Corporation. All rights reserved.
  20. */
  21. #include "_common.h"
  22. #include "_edit.h"
  23. #include "_dispprt.h"
  24. #include "_dispml.h"
  25. #include "_dispsl.h"
  26. #include "_select.h"
  27. #include "_text.h"
  28. #include "_runptr.h"
  29. #include "_font.h"
  30. #include "_measure.h"
  31. #include "_render.h"
  32. #include "_m_undo.h"
  33. #include "_antievt.h"
  34. #include "_rtext.h"
  35. #include "_urlsup.h"
  36. #include "_magelln.h"
  37. #ifndef NOLINESERVICES
  38. #include "_ols.h"
  39. #endif
  40. #include "_clasfyc.h"
  41. #include "_tomfmt.h"
  42. #ifndef OBJID_NATIVEOM
  43. #define OBJID_NATIVEOM 0xFFFFFFF0
  44. #endif
  45. #ifndef NOPRIVATEMESSAGE
  46. #include "_MSREMSG.H"
  47. #include "_dxfrobj.h"
  48. #endif
  49. #ifndef NOACCESSIBILITY
  50. #include "oleacc.h"
  51. #endif
  52. // By turning on the PROFILE_TS compiler directive, you tell IceCap2.0
  53. // to turn on profiling for only ITextServices API's. Typically only
  54. // used during profiling work.
  55. //#define PROFILE_TS
  56. #ifdef PROFILE_TS
  57. #include <icapexp.h>
  58. class CapProfile
  59. {
  60. public:
  61. CapProfile() { StartCAP(); }
  62. ~CapProfile() { StopCAP(); }
  63. };
  64. #define START_PROFILING CapProfile capprf;
  65. #else
  66. #define START_PROFILING
  67. #endif //PROFILE_TS
  68. ASSERTDATA
  69. // Macros to get mouse coordinates out of a message
  70. // need to cast to SHORT first for sign extension
  71. #define MOUSEX ((INT)(SHORT)LOWORD(lparam))
  72. #define MOUSEY ((INT)(SHORT)HIWORD(lparam))
  73. LONG ValidateTextRange(TEXTRANGE *pstrg);
  74. BOOL g_OLSBusy = 0;
  75. // Helper function in edit.cpp
  76. LONG GetECDefaultHeightAndWidth(
  77. ITextServices *pts,
  78. HDC hdc,
  79. LONG lZoomNumerator,
  80. LONG lZoomDenominator,
  81. LONG yPixelsPerInch,
  82. LONG *pxAveWidth,
  83. LONG *pxOverhang,
  84. LONG *pxUnderhang);
  85. // if there's an active object being dragged around, on WM_PAINT we always
  86. // try to reposition it to there it should be. A not-so-well-behaved object
  87. // my generate another WM_PAINT message in response to that, even if it actually
  88. // did not move. So we limit our number of attempts to reposition it and reset
  89. // this counter every time a mouse moves.
  90. // The corresponding field is declared as :2, so don't try to bump it up
  91. // without allocating more bits!!
  92. #define MAX_ACTIVE_OBJ_POS_TRIES (3)
  93. // Interchange horizontal and vertical commands
  94. WORD InterchangeScrollCode(WORD wCode)
  95. {
  96. switch(wCode)
  97. {
  98. case SB_BOTTOM:
  99. return SB_TOP;
  100. case SB_LINEDOWN:
  101. return SB_LINEUP;
  102. case SB_LINEUP:
  103. return SB_LINEDOWN;
  104. case SB_PAGEDOWN:
  105. return SB_PAGEUP;
  106. case SB_PAGEUP:
  107. return SB_PAGEDOWN;
  108. case SB_TOP:
  109. return SB_BOTTOM;
  110. default:
  111. return wCode;
  112. }
  113. }
  114. ///////////////////////////// Helper Functions ///////////////////////////////////
  115. /*
  116. * BOOL CTxtEdit::LoadMsgFilter(msg, wparam, lparam)
  117. *
  118. * @func
  119. * Check if we should load the IME message filter
  120. *
  121. * @rdesc
  122. * TRUE - Load it
  123. * FALSE - Don't load
  124. */
  125. BOOL CTxtEdit::LoadMsgFilter(
  126. UINT msg, //@parm Message ID
  127. WPARAM wparam, //@parm Message wparam
  128. LPARAM lparam) //@parm Message lparam
  129. {
  130. //TRACEBEGIN(TRCSUBSYSTS, TRCSCOPEINTERN, "CTxtEdit::LoadMsgFilter");
  131. // For the first ever message, we want to check if
  132. // our client has created AIMM object for current thread
  133. #ifndef NOFEPROCESSING
  134. if (!_fCheckAIMM)
  135. {
  136. DWORD dwThreadId;
  137. DWORD dwLoadActiveInput = 0;
  138. _fCheckAIMM = 1;
  139. #ifndef NOPRIVATEMESSAGE
  140. if (!_f10Mode) // Don't check if 1.0 mode
  141. {
  142. if (FindAtomA("_CTF_PROCESS_ATOM_")) // Is process using Cicero?
  143. dwLoadActiveInput = SES_USECTF;
  144. if (FindAtomA("_AIMM12_PROCESS_ATOM_")) // Is process using Aimm 1.2?
  145. dwLoadActiveInput = SES_USEAIMM12; // Yes, this will override SES_USECTF.
  146. else if (dwThreadId = GetCurrentThreadId())
  147. {
  148. char szBuf[20];
  149. sprintf(szBuf, "AIMM:%08x", dwThreadId);
  150. if (FindAtomA(szBuf)) // Is thread using Aimm 1.1?
  151. dwLoadActiveInput = SES_USEAIMM11; // Yes, load Aimm 1.1
  152. }
  153. if (!dwLoadActiveInput) // Process is not using anything...
  154. {
  155. if (W32->fUseCTF()) // Ini file say use Cicero
  156. dwLoadActiveInput = SES_USECTF;
  157. else if (W32->fUseAimm()) // Ini file say use Aimm 1.2
  158. dwLoadActiveInput = SES_USEAIMM12;
  159. }
  160. if (dwLoadActiveInput)
  161. {
  162. HWND hWnd = NULL;
  163. TxGetWindow( &hWnd );
  164. if (hWnd)
  165. {
  166. if (_fInOurHost)
  167. PostMessage(hWnd, EM_SETUIM, dwLoadActiveInput, dwLoadActiveInput);
  168. else
  169. {
  170. LRESULT lResult;
  171. TxSendMessage(EM_SETUIM, dwLoadActiveInput, dwLoadActiveInput, &lResult);
  172. }
  173. }
  174. }
  175. }
  176. #endif
  177. }
  178. switch (msg)
  179. {
  180. case WM_KEYDOWN:
  181. case WM_SYSKEYDOWN:
  182. if ( (WORD) wparam == VK_PROCESSKEY )
  183. return TRUE;
  184. break;
  185. case WM_INPUTLANGCHANGE:
  186. if (IsFELCID((WORD)(lparam)))
  187. return TRUE;
  188. break;
  189. case EM_SETEDITSTYLE:
  190. if ((lparam & (SES_USEAIMM | SES_NOIME | SES_USECTF | SES_CTFALLOWEMBED | SES_CTFALLOWSMARTTAG | SES_CTFALLOWPROOFING)) ||
  191. (wparam & (SES_USEAIMM | SES_NOIME | SES_USECTF | SES_CTFALLOWEMBED | SES_CTFALLOWSMARTTAG | SES_CTFALLOWPROOFING)))
  192. return TRUE;
  193. break;
  194. case EM_RECONVERSION:
  195. case WM_IME_NOTIFY:
  196. case WM_IME_REQUEST:
  197. case WM_IME_STARTCOMPOSITION:
  198. case EM_GETIMEOPTIONS:
  199. case EM_SETIMEOPTIONS:
  200. case EM_SETIMECOLOR:
  201. case EM_GETIMECOLOR:
  202. case WM_IME_CHAR:
  203. #ifndef NOPRIVATEMESSAGE
  204. case EM_SETUIM:
  205. #endif
  206. case EM_SETIMEMODEBIAS:
  207. case EM_GETIMEMODEBIAS:
  208. case EM_GETCTFMODEBIAS:
  209. case EM_SETCTFMODEBIAS:
  210. case EM_GETCTFOPENSTATUS:
  211. case EM_SETCTFOPENSTATUS:
  212. case EM_GETIMECOMPTEXT:
  213. case EM_ISIME:
  214. case EM_GETIMEPROPERTY:
  215. return TRUE;
  216. case EM_SETLANGOPTIONS:
  217. if (lparam & (IMF_IMEALWAYSSENDNOTIFY | IMF_IMECANCELCOMPLETE))
  218. return TRUE;
  219. break;
  220. default:
  221. if (msg)
  222. {
  223. if (msg == MSIMEReconvertMsg || msg == MSIMEDocFeedMsg
  224. || msg == MSIMEQueryPositionMsg)
  225. return TRUE;
  226. }
  227. break;
  228. }
  229. #endif
  230. return FALSE;
  231. }
  232. /*
  233. * CTxtEdit::FormatAndPrint (hdcDraw, hicTargetDev, ptd, lprcBounds,
  234. * lprcWBounds)
  235. * @mfunc
  236. * Format and Print data in control
  237. *
  238. * @rdesc
  239. * S_OK - everything worked
  240. * E_FAIL - unexpected failure occurred
  241. */
  242. HRESULT CTxtEdit::FormatAndPrint(
  243. HDC hdcDraw, //@parm HDC to draw on
  244. HDC hicTargetDev, //@parm Input information context if any
  245. DVTARGETDEVICE *ptd, //@parm Device target information
  246. RECT *lprcBounds, //@parm Rectangle to measure
  247. RECT *lprcWBounds) //@parm Metafile information
  248. {
  249. TRACEBEGIN(TRCSUBSYSTS, TRCSCOPEINTERN, "CTxtEdit::FormatAndPrint");
  250. // Put client rectangle in format structure
  251. FORMATRANGE fr;
  252. fr.rc = *lprcBounds;
  253. // Get number of device units per inch
  254. LONG xPerInch;
  255. LONG yPerInch;
  256. if (NULL == lprcWBounds)
  257. {
  258. xPerInch = GetDeviceCaps(hdcDraw, LOGPIXELSX);
  259. yPerInch = GetDeviceCaps(hdcDraw, LOGPIXELSY);
  260. }
  261. else
  262. {
  263. //Forms ^3 draws using screen resolution, while OLE specifies HIMETRIC
  264. xPerInch = fInOurHost() ? 2540 : W32->GetXPerInchScreenDC();
  265. yPerInch = fInOurHost() ? 2540 : W32->GetYPerInchScreenDC();
  266. SetWindowOrgEx(hdcDraw, lprcWBounds->left, lprcWBounds->top, NULL);
  267. SetWindowExtEx(hdcDraw, lprcWBounds->right, lprcWBounds->bottom, NULL);
  268. }
  269. // Convert rectangle into TWIPS
  270. fr.rc.left = MulDiv(fr.rc.left, LX_PER_INCH, xPerInch);
  271. fr.rc.top = MulDiv(fr.rc.top, LY_PER_INCH, yPerInch);
  272. fr.rc.right = MulDiv(fr.rc.right, LX_PER_INCH, xPerInch);
  273. fr.rc.bottom = MulDiv(fr.rc.bottom, LY_PER_INCH, yPerInch);
  274. // Use message based printing code to do our printing for us
  275. fr.hdc = hdcDraw;
  276. fr.hdcTarget = hicTargetDev;
  277. fr.rcPage = fr.rc;
  278. fr.chrg.cpMin = _pdp->GetFirstVisibleCp();
  279. fr.chrg.cpMost = -1;
  280. // Assume this is all going to work
  281. HRESULT hr = S_OK;
  282. SPrintControl prtcon;
  283. prtcon._fDoPrint = TRUE;
  284. prtcon._fPrintFromDraw = TRUE;
  285. // Print control
  286. if(OnFormatRange(&fr, prtcon, TRUE) == -1)
  287. {
  288. // For some reason the control could not be printed
  289. hr = E_FAIL;
  290. }
  291. return hr;
  292. }
  293. /*
  294. * CTxtEdit::SetText (pstr, flags, CodePage, publdr, plres)
  295. *
  296. * @mfunc Sets the text in the document, clearing out any existing text
  297. *
  298. * @rdesc HRESULT
  299. */
  300. HRESULT CTxtEdit::SetText(
  301. LPCWSTR pstr, //@parm Text to set
  302. DWORD flags, //@parm 0 or more ST_xxx's
  303. LONG CodePage, //@parm CodePage
  304. IUndoBuilder *publdr, //@parm Optional place to put undo events
  305. LRESULT * plres) //@parm Optional place to return cch added
  306. {
  307. CCallMgr callmgr(this);
  308. BOOL fSel = flags & ST_SELECTION;
  309. BOOL fSetTextMax = TRUE;
  310. CTxtRange rg(this, 0, -GetTextLength()); // Select whole story
  311. CTxtRange * prg = &rg;
  312. LRESULT lres = 0;
  313. CFreezeDisplay fd(_pdp);
  314. CCharFormat CF;
  315. BOOL fSetCF = FALSE;
  316. BOOL fInputString = FALSE; // Initialize to no input string
  317. // NOTE: WM_SETTEXT is the only message using flags == ST_CHECKPROTECTION.
  318. // This is sent in via ANSIWndProc(). Do we need another flag to indicate
  319. // WM_SETTEXT or is this check good enough? This only affect 1.0 mode.
  320. BOOL f10WM_SETTEXT = flags & ST_10WM_SETTEXT;
  321. if(plres)
  322. *plres = 0;
  323. if(fSel) // Set selected text
  324. {
  325. if(!_psel)
  326. {
  327. Beep();
  328. return E_FAIL;
  329. }
  330. // Bug fix: 6498 - we need to know if scroll position is at bottom
  331. // before inserting text
  332. if (Get10Mode())
  333. {
  334. LONG nMin, nMax, nPos, nPage;
  335. BOOL nEnable;
  336. TxGetVScroll(&nMin, &nMax, &nPos, &nPage, &nEnable);
  337. if (nEnable)
  338. _psel->SetAutoVScroll((nMax - nPage - 3) <= nPos);
  339. }
  340. prg = _psel;
  341. }
  342. else
  343. {
  344. _qwCharFlags &= FRTL | FDIGITSHAPE; // No chars, so kill char flags
  345. if (!IsRich())
  346. {
  347. // Deleting all text from Plain text, we want to
  348. // go back to the -1 format
  349. prg->Set_iCF(-1);
  350. prg->SetUseiFormat(TRUE);
  351. }
  352. else
  353. _qwCharFlags |= FBELOWX40; // For final EOP
  354. }
  355. if (flags & ST_CHECKPROTECTION &&
  356. IsProtectedRange(WM_SETTEXT, 0, (LPARAM)pstr, prg))
  357. {
  358. return E_ACCESSDENIED;
  359. }
  360. // 1.0 COMPATABILITY
  361. // 1.0 didn't scroll to selection if text is inserted via EM_REPLACESEL
  362. // and fHideSelection is FALSE;
  363. BOOL fUpdateCaret = !(Get10Mode() && (flags & ST_10REPLACESEL) &&
  364. fHideSelection() && !_psel->GetAutoVScroll());
  365. if(!(flags & ST_KEEPUNDO))
  366. {
  367. if(IsRich() && !fSel)
  368. {
  369. if (f10WM_SETTEXT)
  370. {
  371. // If pstr is empty string, retain format at end of current text.
  372. // If pstr is not empty string, retain format at cp = 1.
  373. // Note: prg->_rpCF is already at SetRun(0,0)
  374. CFormatRunPtr rp(prg->_rpCF);
  375. if (!pstr || *(LPBYTE)pstr == '\0')
  376. {
  377. LONG cchAdjusted = GetAdjustedTextLength() - 1;
  378. if (cchAdjusted > 0)
  379. rp.Move(cchAdjusted);
  380. }
  381. CF = *(GetCharFormat(rp.GetFormat()));
  382. fSetCF = TRUE;
  383. prg->SetText(NULL); // delete all the text first
  384. }
  385. // SetText causing all formatting to return to the default. We use
  386. // the notification system to remove the formatting. This is
  387. // particularly important for the final EOP which cannot be deleted.
  388. // Notify every interested party that they should dump their formatting
  389. _nm.NotifyPreReplaceRange(NULL, CONVERT_TO_PLAIN, 0, 0, 0, 0);
  390. // Tell document to dump its format runs
  391. _story.DeleteFormatRuns();
  392. if (fSetCF)
  393. prg->SetCharFormat(&CF, 0, NULL, CFM_ALL, 0);
  394. }
  395. publdr = NULL;
  396. if(_pundo)
  397. _pundo->ClearAll();
  398. if(_predo)
  399. _predo->ClearAll();
  400. // If we are re-entered, there may be anti-events higher up the
  401. // chain. Grab the undo builder and clear things away if necessary.
  402. CGenUndoBuilder undobldr(this, 0);
  403. undobldr.Discard();
  404. }
  405. if(publdr)
  406. publdr->StopGroupTyping();
  407. // Need to reinit zoomin variables if entire text is being replaced
  408. if (!fSel)
  409. InitDocInfo();
  410. else if(_psel->GetCch()) // If insert into selection, need to
  411. { // insert an EOP if selection ends
  412. CPFRunPtr rp(*_psel); // at a table row delimiter
  413. if(_psel->GetCch() < 0)
  414. rp.Move(-_psel->GetCch());
  415. if(rp.IsTableRowDelimiter())
  416. _psel->InsertEOP(publdr, 0);
  417. }
  418. LONG lStreamFormat = IsRich() && IsRTF((LPSTR)pstr, 10) ? SF_RTF : 0;
  419. if(pstr && *(LPSTR)pstr && (CodePage != 1200 || lStreamFormat || *pstr < 128 && fSel && !*(pstr+1)))
  420. {
  421. LONG cch = strlen((LPSTR)pstr); // REMARK: little endian dependence
  422. DWORD ch = *(LPBYTE)pstr; // for CodePage = 1200 cases
  423. fInputString = TRUE;
  424. if(ch < 128 && fSel && cch == 1)
  425. {
  426. lres = 1;
  427. fSetTextMax = FALSE;
  428. TxSetMaxToMaxText(1);
  429. if(ch == CR)
  430. InsertEOP(0, FALSE, publdr);
  431. else
  432. _psel->PutChar(ch, 0, publdr);
  433. }
  434. else if(cch == 2 && ch == CR && *((LPSTR)pstr + 1) == LF)
  435. {
  436. lres = 2;
  437. fSetTextMax = FALSE;
  438. TxSetMaxToMaxText(2);
  439. InsertEOP(0, FALSE, publdr);
  440. }
  441. else
  442. {
  443. READHGLOBAL rhg = {(LPSTR)pstr, cch};
  444. EDITSTREAM es = {(DWORD_PTR)&rhg, S_OK, ReadHGlobal};
  445. HCURSOR hcur = NULL;
  446. // Want wait cursor to display sooner
  447. bool fSetCursor = rhg.cbLeft > NUMPASTECHARSWAITCURSOR;
  448. if(fSetCursor)
  449. hcur = TxSetCursor(LoadCursor(NULL, IDC_WAIT));
  450. if (CodePage <= 0)
  451. {
  452. if (Get10Mode())
  453. {
  454. LONG iFormat = _psel->GetiFormat();
  455. const CCharFormat *pCF = GetCharFormat(iFormat);
  456. CodePage = CodePageFromCharRep(pCF->_iCharRep);
  457. }
  458. else
  459. CodePage = (CodePage == 0) ? GetACP() : GetDefaultCodePage(EM_SETTEXTEX);
  460. }
  461. if(!lStreamFormat)
  462. lStreamFormat = SF_TEXT;
  463. lStreamFormat |= SF_USECODEPAGE | (CodePage << 16);
  464. if(fSel)
  465. lStreamFormat |= SFF_SELECTION;
  466. lres = _ldte.LoadFromEs(prg, lStreamFormat, &es, FALSE, publdr);
  467. if(fSetCursor)
  468. TxSetCursor(hcur);
  469. if(es.dwError != NOERROR)
  470. return (HRESULT)es.dwError;
  471. }
  472. }
  473. else
  474. {
  475. // 9052: Don't delete all if 4 (ST_NEWCHARS) is passed in EM_SETTEXTEX
  476. DWORD dwFlags = (flags & 4)
  477. ? RR_ITMZ_UNICODEBIDI | RR_NEW_CHARS
  478. : RR_ITMZ_UNICODEBIDI;
  479. if (CodePage != 1200 && pstr && !*(LPSTR)pstr)
  480. pstr = NULL;
  481. if(pstr && *pstr)
  482. fInputString = TRUE;
  483. lres = prg->CleanseAndReplaceRange(-1, pstr, FALSE, publdr, NULL, NULL, dwFlags);
  484. }
  485. if(!lres && fInputString)
  486. {
  487. // There was an input string but for some reason there was no update.
  488. return E_FAIL;
  489. }
  490. if (_fOutlineView)
  491. {
  492. // Outline view must have formatting.
  493. _psel->Check_rpPF();
  494. }
  495. if(_psel)
  496. {
  497. if(fSel)
  498. _psel->Update(fUpdateCaret);
  499. else
  500. {
  501. // Setting the text means a new document so if there is a selection
  502. // turn it into an insertion point at the beginning of the document.
  503. _psel->ClearPrevSel();
  504. _psel->Set(0, 0);
  505. // Since the text is being completely replaced and all formatting
  506. // is being lost, let's go back to the default format for the
  507. // selection.
  508. if (!f10WM_SETTEXT)
  509. _psel->Set_iCF(-1);
  510. else if (fSetCF)
  511. _psel->SetCharFormat(&CF, 0, NULL, CFM_ALL, 0);
  512. if(_fFocus || _psel->IsParaRTL())
  513. {
  514. // Update caret to reflect new postion
  515. _psel->UpdateCaret(fUpdateCaret);
  516. }
  517. }
  518. }
  519. // If we've replaced the entire document, the control isn't
  520. // really "modified" anymore. This is necessary to match
  521. // the Windows MLE behavior. However, since RichEdit 1.0
  522. // did _not_ do this (they left fModified to be TRUE), we
  523. // only do this for RichEdit 2.0 and later.
  524. if(!Get10Mode() && !publdr && !fSel)
  525. _fModified = FALSE;
  526. _fSaved = FALSE; // ITextDocument isn't Saved
  527. // Adjust text limit if necessary
  528. if (fSetTextMax)
  529. TxSetMaxToMaxText();
  530. if(plres)
  531. *plres = fSel ? lres : 1;
  532. return S_OK;
  533. }
  534. /////////////////////////// ITextServices Methods ////////////////////////////////
  535. // External IME Message Filter Interface factory
  536. #ifndef NOFEPROCESSING
  537. void CreateIMEMessageFilter(ITextMsgFilter **ppNewFilter);
  538. #endif
  539. /*
  540. * @doc EXTERNAL
  541. *
  542. * CTxtEdit::TxSendMessage (msg, wparam, lparam, plresult)
  543. *
  544. * @mfunc
  545. * Used by window host to forward messages sent to its window to the
  546. * text services.
  547. *
  548. * @rdesc
  549. * NOERROR Message was processed, and some action taken <nl>
  550. * S_FALSE Message was not processed. Typically indicates that caller
  551. * should process message, maybe by calling DefWindowProc <nl>
  552. * S_MSG_KEYIGNORED Message processed, but no action was taken <nl>
  553. * E_OUTOFMEMORY <nl>
  554. *
  555. * @comm
  556. * Note that two return values are passed back from this function.
  557. * <p plresult> is the return value that should be passed back from a
  558. * window proc. However, in some cases, the returned LRESULT does not
  559. * contain enough information. For example, to implement cursoring
  560. * around controls, it's useful to know if a keystroke (such as right
  561. * arrow) was processed, but ignored (e.g. the caret is already at the
  562. * rightmost position in the the text). In these cases, extra
  563. * information may be returned via the returned HRESULT.
  564. *
  565. * WM_CHAR and WM_KEYDOWN should return S_MSG_KEYIGNORED when a key or
  566. * char has been recognized but had no effect given the current state,
  567. * e.g., a VK_RIGHT key when the insertion point is already at the end of
  568. * the document). This is used by Forms3 to pass the key up the visual
  569. * hierarchy, so that for example, focus moves to the next control in the
  570. * TAB order.
  571. *
  572. * This includes the following cases:
  573. *
  574. * 1. Any key trying to move the insertion point beyond the end of the
  575. * document; or before the begining of the document.
  576. *
  577. * 2. Any key trying to move the insertion point beyond the last line or
  578. * before the first line.
  579. *
  580. * 3. Any insertion of character (WM_CHAR) that would move the insertion
  581. * point past the maximum length of the control.
  582. */
  583. HRESULT CTxtEdit::TxSendMessage (
  584. UINT msg, //@parm Message id
  585. WPARAM wparam, //@parm WPARAM from window's message
  586. LPARAM lparam, //@parm LPARAM from window's message
  587. LRESULT *plresult) //@parm Where to put message's return LRESULT
  588. {
  589. TRACEBEGINPARAM(TRCSUBSYSTS, TRCSCOPEEXTERN, "CTxtEdit::TxSendMessage", msg);
  590. CObjectMgr *pobjmgr;
  591. HRESULT hr = NOERROR;
  592. LRESULT lres = 0;
  593. CCallMgr callmgr(this);
  594. if ( CW32System::_MSMouseRoller == msg ) // map Magellan msg.
  595. {
  596. // map this message to WM_MOUSEWHEEL
  597. // In these cases the driver doesn't set the key state properly so
  598. // we have to do it ourselves
  599. short zdelta = (short)(long)wparam;
  600. short kstate = 0;
  601. if (GetKeyboardFlag(CTRL, VK_CONTROL))
  602. kstate |= MK_CONTROL;
  603. if (GetKeyboardFlag(SHIFT, VK_SHIFT))
  604. kstate |= MK_SHIFT;
  605. wparam = MAKELONG(kstate, zdelta);
  606. msg = WM_MOUSEWHEEL;
  607. }
  608. #ifndef NOFEPROCESSING
  609. if (_pMsgFilter)
  610. {
  611. PassMsg:
  612. hr = _pMsgFilter->HandleMessage(&msg, &wparam, &lparam, &lres);
  613. if (hr == S_OK) // Message has been handled.
  614. {
  615. if(plresult)
  616. *plresult = lres;
  617. return S_OK;
  618. }
  619. hr = S_OK; // Reset
  620. }
  621. else if (LoadMsgFilter(msg, wparam, lparam))
  622. {
  623. HWND hwnd = NULL;
  624. if (_fInOurHost)
  625. {
  626. // If not in Forms^3 we can get the window from our host.
  627. // For Forms^3 we will use NULL for the desktop Window and pray
  628. TxGetWindow( &hwnd );
  629. }
  630. ITextMsgFilter *pNewFilter = NULL;
  631. CreateIMEMessageFilter(&pNewFilter);
  632. if (pNewFilter)
  633. {
  634. pNewFilter->AttachDocument( hwnd, (ITextDocument2 *) this, (ITextServices *) this );
  635. AttachMsgFilter(pNewFilter);
  636. goto PassMsg;
  637. }
  638. }
  639. #endif
  640. START_PROFILING
  641. IUndoBuilder * publdr;
  642. CGenUndoBuilder undobldr(this, UB_AUTOCOMMIT, &publdr);
  643. switch(msg)
  644. {
  645. case EM_CANPASTE:
  646. // we don't check for protection here, as RichEdit 1.0
  647. // doesn't
  648. lres = _ldte.CanPaste(NULL, (CLIPFORMAT) wparam, RECO_PASTE);
  649. break;
  650. case EM_CANUNDO:
  651. if(_pundo)
  652. lres = _pundo->CanUndo();
  653. break;
  654. case EM_CANREDO:
  655. if(_predo)
  656. lres = _predo->CanUndo();
  657. break;
  658. case EM_GETUNDONAME:
  659. if(_pundo)
  660. lres = _pundo->GetNameIDFromAE((void*)wparam);
  661. break;
  662. case EM_GETREDONAME:
  663. if(_predo)
  664. lres = _predo->GetNameIDFromAE((void*)wparam);
  665. break;
  666. case EM_STOPGROUPTYPING:
  667. if(_pundo)
  668. {
  669. // we'll only stop group typing iff wparam
  670. // is zero (meaning stop regardless) _or_ if
  671. // wparam matches the merge anti event.
  672. //
  673. // This feature allows clients to say that only
  674. // a specific anti-event should close out it's
  675. // "fuzzy" state. Note that currently, only the
  676. // merge anti-event has this fuzzy state.
  677. if(!wparam || (IAntiEvent *)wparam == _pundo->GetMergeAntiEvent())
  678. _pundo->StopGroupTyping();
  679. }
  680. break;
  681. case WM_UNICHAR: // Unambiguous Unicode character
  682. if(wparam == NOTACHAR)
  683. {
  684. lres = TRUE; // Tell caller we understand msg
  685. break;
  686. } // Else fall thru to WM_CHAR
  687. case WM_CHAR:
  688. if(GetKeyboardFlags() & (ALTNUMPAD | HOTEURO))
  689. {
  690. if (GetKeyboardFlags() & ALTNUMPAD)
  691. {
  692. if (GetKeyboardFlags() & ALT0 &&
  693. GetCharFormat(-1)->_iCharRep == MAC_INDEX &&
  694. GetKeyboardCharRep(0) == ANSI_INDEX)
  695. {
  696. WCHAR ch;
  697. UnicodeFromMbcs(&ch, 1, (char *)&wparam, 1, 10000);
  698. wparam = ch;
  699. SetKeyPadNumber(ch);
  700. ResetKeyboardFlag(ALTNUMPAD | ALT0);
  701. }
  702. #ifndef NOANSIWINDOWS
  703. else
  704. {
  705. CW32System::WM_CHAR_INFO wmci;
  706. wmci._fAccumulate = FALSE;
  707. W32->AnsiFilter(msg, wparam, lparam, (void *)&wmci);
  708. }
  709. #endif
  710. }
  711. else // (GetKeyboardFlags() & HOTEURO) case
  712. {
  713. // We have handled the Euro, just eat this WM_CHAR
  714. ResetKeyboardFlag(HOTEURO);
  715. break;
  716. }
  717. } // Fall thru to WM_IME_CHAR
  718. case WM_IME_CHAR: // 2 byte character, usually FE.
  719. lres = hr = OnTxChar((DWORD)wparam, (DWORD)lparam, publdr);
  720. ResetKeyboardFlag(HOTEURO);
  721. break;
  722. case WM_USER + 39: // For backward compat with NT 3.51
  723. case EM_CHARFROMPOS:
  724. hr = TxCharFromPos((LPPOINT)lparam, &lres);
  725. break;
  726. #ifdef WM_INPUTLANGCHANGE
  727. case WM_INPUTLANGCHANGE:
  728. if (_fSingleCodePage)
  729. {
  730. // See if the charset for the specified keyboard is supported by
  731. // the single code page we support. If we don't have a _pDocInfo,
  732. // assume the code page is the system code page. We will always
  733. // support the ANSI charset, as all code pages contain at least
  734. // a large portion of this charset (the ASCII block).
  735. wparam = (!wparam || wparam == GetCharSet(_pDocInfo ?
  736. _pDocInfo->_wCpg : GetSystemDefaultCodePage()));
  737. }
  738. goto update_kbd;
  739. case WM_INPUTLANGCHANGEREQUEST:
  740. // If the SingleCodePage option is set, then we must have a
  741. // "good" code page to go to; if not, just eat this message.
  742. //
  743. // This will prevent folks from typing French and Greek
  744. // on the same edit control, which is useful for certain
  745. // kinds of backward compatibility scenarios.
  746. //
  747. // HACK ALERT! the documentation on WM_INPUTLANGCHANGEREQUEST
  748. // is wrong. It turns out that _only_ the low bit of wparam
  749. // indicates whether or not the new keyboard can be considered
  750. // as the same code page.
  751. if (_fSingleCodePage && !(wparam & 1))
  752. {
  753. // The lowest bit check is not reliable in some platforms e.g. Viet OSR2
  754. // since it doesnt allow English kbd to match system charset (bug #6365).
  755. wparam = PRIMARYLANGID(LOWORD(lparam)) == LANG_ENGLISH &&
  756. IN_RANGE (SUBLANG_ENGLISH_US, SUBLANGID(LOWORD(lparam)), SUBLANG_ENGLISH_UK);
  757. }
  758. update_kbd:
  759. if(!_fSingleCodePage || (wparam & 1))
  760. {
  761. WORD wKLCurrent = LOWORD(GetKeyboardLayout(0));
  762. // Update our idea of current keyboard layout
  763. W32->RefreshKeyboardLayout();
  764. if(GetKeyboardFlags() & CTRL && GetKeyboardFlags() & SHIFT)
  765. SetKeyboardFlag(LETAFTERSHIFT);
  766. if( wKLCurrent == LOWORD(lparam) || // No change in keyboard
  767. GetSel()->CheckChangeFont((HKL)lparam, CharRepFromLID(LOWORD(lparam))))
  768. hr = S_FALSE; // cause default window to allow kb switch.
  769. }
  770. break;
  771. #endif
  772. case WM_CLEAR:
  773. OnClear(publdr);
  774. break;
  775. case WM_CONTEXTMENU:
  776. hr = OnContextMenu(lparam);
  777. break;
  778. case WM_COPY:
  779. case WM_CUT:
  780. lres = hr = CutOrCopySelection(msg, wparam, lparam, publdr);
  781. break;
  782. case WM_RENDERFORMAT:
  783. lres = hr = _ldte.RenderClipboardFormat(wparam);
  784. break;
  785. case WM_RENDERALLFORMATS:
  786. lres = hr = _ldte.RenderAllClipboardFormats();
  787. break;
  788. case WM_DESTROYCLIPBOARD:
  789. lres = hr = _ldte.DestroyClipboard();
  790. break;
  791. case EM_DISPLAYBAND:
  792. if (fInplaceActive())
  793. {
  794. {
  795. CLock lock;
  796. if (g_OLSBusy)
  797. {
  798. hr = OLE_E_INVALIDRECT;
  799. break;
  800. }
  801. }
  802. OnDisplayBand((const RECT *) lparam, FALSE);
  803. lres = 1;
  804. }
  805. else
  806. hr = OLE_E_INVALIDRECT;
  807. break;
  808. #ifdef WM_DROPFILES
  809. case WM_DROPFILES:
  810. OnDropFiles((HANDLE) wparam);
  811. break;
  812. #endif
  813. case EM_EMPTYUNDOBUFFER:
  814. ClearUndo(publdr);
  815. break;
  816. case WM_ERASEBKGND:
  817. lres = 1; // We handle background erase during painting
  818. break;
  819. case EM_EXGETSEL: // Has cp output parameter
  820. OnExGetSel((CHARRANGE *)lparam);
  821. break;
  822. case EM_FINDTEXT: // Has cp input/output parms
  823. case EM_FINDTEXTW: // Has cp input/output parms
  824. case EM_FINDTEXTEX: // Has cp input/output parms
  825. case EM_FINDTEXTEXW: // Has cp input/output parms
  826. lres = OnFindText(msg, (DWORD)wparam, (FINDTEXTEX *)lparam);
  827. break;
  828. case EM_FINDWORDBREAK: // Has cp input/output parms
  829. hr = TxFindWordBreak((INT)wparam, (LONG)lparam, &lres);
  830. break;
  831. case EM_FORMATRANGE: // Has cp input/output parms
  832. if(fInplaceActive())
  833. {
  834. {
  835. CLock lock;
  836. if (g_OLSBusy)
  837. {
  838. hr = OLE_E_INVALIDRECT;
  839. break;
  840. }
  841. }
  842. SPrintControl prtcon;
  843. prtcon._fDoPrint = (wparam) ? TRUE : FALSE;
  844. lres = OnFormatRange((FORMATRANGE *) lparam, prtcon);
  845. }
  846. else
  847. hr = OLE_E_INVALIDRECT;
  848. break;
  849. case EM_GETTYPOGRAPHYOPTIONS:
  850. lres = _bTypography;
  851. break;
  852. case EM_GETBIDIOPTIONS:
  853. if((Get10Mode() || !wparam) && lparam && ((BIDIOPTIONS *)lparam)->cbSize == sizeof(BIDIOPTIONS))
  854. {
  855. ((BIDIOPTIONS *)lparam)->wMask =
  856. BOM_NEUTRALOVERRIDE | BOM_CONTEXTREADING | BOM_CONTEXTALIGNMENT;
  857. ((BIDIOPTIONS *)lparam)->wEffects =
  858. (_fNeutralOverride ? BOE_NEUTRALOVERRIDE : 0) |
  859. (_nContextDir == CTX_NONE ? 0 : BOE_CONTEXTREADING) |
  860. (_nContextAlign == CTX_NONE ? 0 : BOE_CONTEXTALIGNMENT);
  861. }
  862. break;
  863. case EM_GETCHARFORMAT:
  864. lres = OnGetCharFormat((CHARFORMAT2 *)lparam, wparam);
  865. break;
  866. case EM_GETCODEPAGE:
  867. lres = GetDefaultCodePage((UINT)wparam);
  868. break;
  869. case EM_GETFIRSTVISIBLELINE:
  870. if (fInplaceActive())
  871. lres = _pdp->GetFirstVisibleLine();
  872. else
  873. hr = OLE_E_INVALIDRECT;
  874. break;
  875. case EM_GETLIMITTEXT: // Has cp output parameter (sort of)
  876. lres = TxGetMaxLength(); // Ignore unless testing screams
  877. break;
  878. case EM_GETLINE:
  879. if(fInplaceActive())
  880. {
  881. lres = _pdp->GetLineText((LONG)wparam, (TCHAR *)lparam,
  882. (LONG) (*(WORD *) lparam));
  883. }
  884. else
  885. hr = OLE_E_INVALIDRECT;
  886. break;
  887. case EM_GETLINECOUNT:
  888. hr = TxGetLineCount(&lres);
  889. break;
  890. case EM_GETMODIFY: // RichEdit 1.0 returned -1 if _fModified
  891. lres = -(LONG)_fModified; // is TRUE (go figure). So for backward
  892. break; // compatibility, we do too :-(
  893. case EM_GETOLEINTERFACE:
  894. if(lparam)
  895. {
  896. #ifndef NOFEPROCESSING
  897. if (wparam == 0x065737777) // 'AIMM'
  898. W32->GetAimmObject((IUnknown **)(lparam));
  899. else
  900. #endif
  901. {
  902. *(IRichEditOle **)lparam = (IRichEditOle *)this;
  903. AddRef();
  904. }
  905. }
  906. lres = TRUE;
  907. break;
  908. case EM_GETSCROLLPOS:
  909. {
  910. POINT *point = (POINT *)lparam;
  911. point->x = _pdp->GetUpScroll();
  912. point->y = _pdp->GetVpScroll();
  913. point->y = _pdp->ConvertVPosToScrollPos(point->y);
  914. lres = 1;
  915. }
  916. break;
  917. case EM_SETOLECALLBACK:
  918. hr = E_FAIL;
  919. if(lparam)
  920. {
  921. pobjmgr = GetObjectMgr();
  922. if(pobjmgr)
  923. {
  924. pobjmgr->SetRECallback((IRichEditOleCallback *)lparam);
  925. lres = TRUE;
  926. hr = NOERROR;
  927. }
  928. }
  929. break;
  930. case EM_GETPAGE:
  931. lres = -1; // Signal page not available
  932. if(_pdp)
  933. {
  934. LONG i;
  935. hr = _pdp->GetPage(&i, (DWORD)wparam, (CHARRANGE *)lparam);
  936. if(hr == NOERROR)
  937. lres = i;
  938. }
  939. break;
  940. case EM_GETPARAFORMAT:
  941. lres = OnGetParaFormat((PARAFORMAT2 *)lparam, wparam);
  942. break;
  943. case EM_GETSEL: // Has cp output parameter
  944. lres = OnGetSel((LONG*)wparam, (LONG*)lparam);
  945. break;
  946. case EM_GETSELTEXT:
  947. lres = OnGetSelText((TCHAR *)lparam);
  948. break;
  949. case WM_GETTEXT:
  950. {
  951. GETTEXTEX gt;
  952. gt.cb = wparam * 2;
  953. gt.flags = GT_USECRLF;
  954. gt.codepage = 1200;
  955. gt.lpDefaultChar = NULL;
  956. gt.lpUsedDefChar = NULL;
  957. lres = GetTextEx(&gt, (TCHAR *)lparam);
  958. }
  959. break;
  960. case WM_GETTEXTLENGTH: // Has cp output parameter
  961. {
  962. GETTEXTLENGTHEX gtl;
  963. gtl.flags = GTL_NUMCHARS | GTL_PRECISE | GTL_USECRLF;
  964. gtl.codepage = 1200;
  965. lres = GetTextLengthEx(&gtl);
  966. }
  967. break;
  968. case EM_GETTEXTEX:
  969. lres = GetTextEx((GETTEXTEX *)wparam, (TCHAR *)lparam);
  970. break;
  971. case EM_GETTEXTLENGTHEX: // Has cp output parameter
  972. lres = GetTextLengthEx((GETTEXTLENGTHEX *)wparam);
  973. break;
  974. case EM_GETTEXTRANGE: // Has cp input parameter
  975. {
  976. TEXTRANGE * const ptr = (TEXTRANGE *)lparam;
  977. LONG cch = ValidateTextRange(ptr);
  978. // Only copy if there's something to copy and destination is valid
  979. if(cch)
  980. {
  981. LONG cpMin = GetCpFromAcp(ptr->chrg.cpMin);
  982. if(cch < 0) // Get text character count
  983. cch = GetTextLength(); // because caller wants it all
  984. else // + 1 is for terminating 0
  985. cch = GetCpFromAcp(ptr->chrg.cpMost) - cpMin + 1;
  986. if(!IsBadWritePtr(ptr->lpstrText, cch * sizeof(TCHAR)))
  987. lres = GetTextRange(cpMin, cch, ptr->lpstrText);
  988. }
  989. }
  990. break;
  991. case EM_GETVIEWKIND:
  992. GetViewKind(&lres);
  993. break;
  994. #ifndef NOWORDBREAKPROC
  995. case EM_GETWORDBREAKPROC:
  996. // Client can only use either WordBreakProc or ExWordBreakProc
  997. // Return NULL if ExWordBreakProc is being used.
  998. if (!_fExWordBreakProc)
  999. lres = (LRESULT) _pfnWB;
  1000. break;
  1001. case EM_GETWORDBREAKPROCEX:
  1002. // Return ExWordBreakProc if it is being used.
  1003. if (_fExWordBreakProc)
  1004. lres = (LRESULT) _pfnWB;
  1005. break;
  1006. #endif
  1007. case EM_GETZOOM:
  1008. if(wparam && lparam)
  1009. {
  1010. *(unsigned *)wparam = GetZoomNumerator();
  1011. *(unsigned *)lparam = GetZoomDenominator();
  1012. lres = 1;
  1013. }
  1014. break;
  1015. case EM_HIDESELECTION:
  1016. if (Get10Mode() && lparam)
  1017. _fHideSelection = !!wparam;
  1018. if(!lparam || !_fFocus)
  1019. lres = OnHideSelectionChange((BOOL)wparam);
  1020. break;
  1021. case WM_HSCROLL:
  1022. if (IsUVerticalTflow(_pdp->GetTflow()))
  1023. {
  1024. WORD wCode = LOWORD(wparam);
  1025. wCode = InterchangeScrollCode(wCode);
  1026. LONG vpPos = HIWORD(wparam);
  1027. //In vertical displays the scrollbar position needs to be swapped.
  1028. if (_pdp->GetTflow() == tflowSW &&
  1029. (wCode == SB_THUMBTRACK || wCode == SB_THUMBPOSITION))
  1030. {
  1031. LONG vpMax, vpPage;
  1032. TxGetHScroll(NULL, &vpMax, NULL, &vpPage, NULL);
  1033. vpPos = vpMax - vpPos - vpPage;
  1034. vpPos = max(vpPos, 0);
  1035. }
  1036. hr = _pdp->VScroll(wCode, vpPos);
  1037. }
  1038. else
  1039. {
  1040. _pdp->UScroll(LOWORD(wparam), HIWORD(wparam));
  1041. hr = 0;
  1042. }
  1043. break;
  1044. case WM_KEYDOWN:
  1045. hr = OnTxKeyDown((WORD) wparam, (DWORD) lparam, publdr);
  1046. break;
  1047. case WM_KEYUP:
  1048. if(wparam == VK_APPS)
  1049. HandleKbdContextMenu();
  1050. else // Else don't say we processed
  1051. hr = S_FALSE; // message
  1052. W32->_fLRMorRLM = 0;
  1053. if(wparam == VK_CONTROL || wparam == VK_SHIFT)
  1054. {
  1055. // If a BiDi keyboard is installed, no strong-context behavior,
  1056. // both a Ctrl and a Shift key are pressed, no letter has been
  1057. // typed after the Ctrl and Shift keys have been pressed, and
  1058. // ReadOnly/Protected tests allow, then the selected paragraphs
  1059. // are set to RTL/LTR direction for the right/left Shift key,
  1060. // respectively. The keyboard and caret are also matched to this
  1061. // direction, and an alignment notification is sent.
  1062. // ReadOnly/Protected tests is removed for backward compatibility.
  1063. DWORD dwFlags = GetKeyboardFlags();
  1064. if (IsBiDiKbdInstalled() &&
  1065. !IsStrongContext(_nContextDir) &&
  1066. !IsStrongContext(_nContextAlign) &&
  1067. (dwFlags & CTRL) && (dwFlags & SHIFT) &&
  1068. !(dwFlags & LETAFTERSHIFT)
  1069. /* && IsntProtectedOrReadOnly(WM_KEYUP, wparam, lparam) */ )
  1070. {
  1071. CParaFormat PF;
  1072. PF._wEffects = (dwFlags & RSHIFT) ? PFE_RTLPARA : 0;
  1073. OnSetParaFormat(0, &PF, publdr, PFM_RTLPARA, PFM2_PARAFORMAT);
  1074. TxNotify(PF._wEffects ? EN_ALIGNRTL : EN_ALIGNLTR, 0);
  1075. }
  1076. if(wparam == VK_CONTROL)
  1077. lparam = (HIWORD(lparam) & KF_EXTENDED) ? RCTRL : LCTRL;
  1078. else
  1079. {
  1080. lparam = (LOBYTE(HIWORD(lparam)) == 0x36) ? RSHIFT : LSHIFT;
  1081. if(GetKeyState(VK_SHIFT) >= 0) // Ensure both shifts are off
  1082. lparam = SHIFT; // (potential Win95 problem)
  1083. }
  1084. ResetKeyboardFlag(lparam | LETAFTERSHIFT | HOTEURO);
  1085. }
  1086. else if(wparam == VK_MENU)
  1087. ResetKeyboardFlag((HIWORD(lparam) & KF_EXTENDED) ? (RALT | HOTEURO) : (LALT | HOTEURO));
  1088. break;
  1089. case WM_KILLFOCUS:
  1090. lres = OnKillFocus();
  1091. break;
  1092. case WM_LBUTTONDBLCLK:
  1093. hr = OnTxLButtonDblClk(MOUSEX, MOUSEY, (WORD) wparam);
  1094. break;
  1095. case WM_LBUTTONDOWN:
  1096. if(_fEatLeftDown)
  1097. {
  1098. TxSetFocus();
  1099. _fEatLeftDown = FALSE;
  1100. }
  1101. else
  1102. hr = OnTxLButtonDown(MOUSEX, MOUSEY, (WORD) wparam);
  1103. break;
  1104. case WM_LBUTTONUP:
  1105. hr = OnTxLButtonUp(MOUSEX, MOUSEY, (WORD) wparam, LB_RELEASECAPTURE | LB_FLUSHNOTIFY);
  1106. break;
  1107. #if !defined(NOMAGELLAN)
  1108. case WM_MBUTTONDBLCLK: // Magellan zmouse scroll
  1109. case WM_NCMBUTTONDOWN: // support commandeers middle
  1110. case WM_MBUTTONDOWN: // button.
  1111. OnTxMButtonDown(MOUSEX, MOUSEY, (WORD) wparam);
  1112. break;
  1113. case WM_MBUTTONUP:
  1114. OnTxMButtonUp(MOUSEX, MOUSEY, (WORD) wparam);
  1115. break;
  1116. case WM_MOUSEWHEEL: // Magellan zmouse scroll n lines.
  1117. lres = HandleMouseWheel(wparam, lparam);
  1118. break;
  1119. #endif
  1120. case EM_LINEFROMCHAR: // Has cp input parameter
  1121. lparam = wparam; // Fall thru to EM_EXLINEFROMCHAR
  1122. case EM_EXLINEFROMCHAR: // Has cp input parameter
  1123. hr = TxLineFromCp((LONG)lparam, &lres);
  1124. break;
  1125. case EM_LINEINDEX: // Has cp output parameter
  1126. hr = TxLineIndex((LONG)wparam, &lres);
  1127. break;
  1128. case EM_LINELENGTH: // Has cp input/output parameters
  1129. hr = TxLineLength((LONG)wparam, &lres);
  1130. break;
  1131. case EM_LINESCROLL: // Has cp input parameter (cch)
  1132. // Documentation says the line to scroll to should be relative to the current top line.
  1133. // Richedit 2.0 based it on an absolute position. We're breaking richedit 2.0 compatibility
  1134. // to go back to the documentation specification and to match what riched 1.0 originally
  1135. // did
  1136. hr = TxLineScroll((LONG)lparam, (LONG)wparam);// but not curr impl
  1137. lres = _pdp->IsMultiLine();
  1138. break;
  1139. #ifdef MA_ACTIVATE
  1140. case WM_MOUSEACTIVATE:
  1141. lres = MA_ACTIVATE;
  1142. // If the window that currently has focus is part of our "application",
  1143. // then don't eat the mouse click. Otherwise, if it's from another
  1144. // app, the user is probably trying to swap apps, so eat the mouse
  1145. // down message and let our host app get a chance to come to the
  1146. // foreground.
  1147. if (!(IsChild((HWND)wparam, GetFocus()) ||
  1148. (wparam && (HWND)wparam == GetFocus())))
  1149. {
  1150. _fEatLeftDown = TRUE;
  1151. }
  1152. hr = S_FALSE; // pass WM_MOUSEACTIVATE message to DefWindProc
  1153. break;
  1154. #endif
  1155. case WM_MOUSEMOVE:
  1156. // We reset the "number of tries to put an active object
  1157. // in place" count here
  1158. _cActiveObjPosTries = MAX_ACTIVE_OBJ_POS_TRIES;
  1159. hr = OnTxMouseMove(MOUSEX, MOUSEY, (WORD)wparam, publdr);
  1160. break;
  1161. case EM_OUTLINE:
  1162. {
  1163. CFreezeDisplay cfd(_pdp);
  1164. if(wparam == EMO_GETVIEWMODE)
  1165. {
  1166. hr = GetViewKind(&lres);
  1167. break;
  1168. }
  1169. CTxtSelection * psel = GetSelNC();
  1170. if(!_pdp->IsMultiLine() || !IsRich() || !psel) // Control must be rich,
  1171. break; // multiline and active
  1172. if(wparam == EMO_ENTER || wparam == EMO_EXIT)
  1173. {
  1174. hr = SetViewKind(wparam == EMO_ENTER ? VM_OUTLINE : VM_NORMAL);
  1175. lres = !hr;
  1176. break;
  1177. }
  1178. if(!IsInOutlineView() || !IsntProtectedOrReadOnly(msg, wparam, lparam))
  1179. break;
  1180. CTxtRange rg(*psel);
  1181. switch(wparam)
  1182. {
  1183. case EMO_PROMOTE:
  1184. hr = rg.Promote(lparam, publdr);
  1185. psel->Update_iFormat(-1);
  1186. psel->Update(FALSE);
  1187. break;
  1188. case EMO_EXPAND:
  1189. hr = rg.ExpandOutline((short)LOWORD(lparam),
  1190. HIWORD(lparam) == EMO_EXPANDDOCUMENT);
  1191. break;
  1192. case EMO_MOVESELECTION:
  1193. hr = MoveSelection(lparam, publdr);
  1194. psel->Update(TRUE);
  1195. break;
  1196. default:
  1197. // TraceMessage("Unknown outline function received\r\n");
  1198. break;
  1199. };
  1200. lres = !hr;
  1201. _fModified = TRUE;
  1202. }
  1203. break;
  1204. case WM_PASTE:
  1205. case EM_PASTESPECIAL:
  1206. if(IsntProtectedOrReadOnly(msg, wparam, lparam))
  1207. {
  1208. CTxtSelection *psel = GetSel();
  1209. hr = PasteDataObjectToRange(NULL, psel,
  1210. (CLIPFORMAT) wparam, (REPASTESPECIAL *)lparam, publdr,
  1211. PDOR_NONE);
  1212. }
  1213. break;
  1214. case WM_USER + 38: // For backward compat with NT 3.51
  1215. case EM_POSFROMCHAR: // Has cp input parameter
  1216. // RichEdit 2.x used wparam instead of lparam for the cp and ignored
  1217. // wparam, unlike RE 1.0 and the Win32 documentation (sigh!). We fix
  1218. // this, but are compatible with RE 2.x for cp's whose values
  1219. // correspond to invalid write ptr's.
  1220. if(IsBadWritePtr((LPPOINT)wparam, sizeof(POINT)))
  1221. {
  1222. // Invalid write ptr, so assume incorrect RE 2.0 params
  1223. // TODO: enable following Assert when msgtest gets updated
  1224. //AssertSz(FALSE,
  1225. // "EM_POSFROMCHAR: wparam is illegal ptr, assuming cp value");
  1226. POINT pt;
  1227. hr = TxPosFromChar((LONG)wparam, &pt);
  1228. lres = SUCCEEDED(hr) ? MAKELONG(pt.x, pt.y) : -1;
  1229. }
  1230. else
  1231. hr = TxPosFromChar((LONG)lparam, (LPPOINT)wparam);
  1232. break;
  1233. #ifndef NORBUTTON
  1234. case WM_RBUTTONDBLCLK:
  1235. case WM_RBUTTONDOWN:
  1236. case WM_RBUTTONUP:
  1237. // Give client a chance to handle these messages,
  1238. // if we are over a link
  1239. if(HandleLinkNotification(msg, wparam, lparam))
  1240. break;
  1241. if(msg == WM_RBUTTONUP)
  1242. hr = OnTxRButtonUp(MOUSEX, MOUSEY, (WORD) wparam, RB_DEFAULT);
  1243. else if( msg == WM_RBUTTONDOWN)
  1244. hr = OnTxRButtonDown(MOUSEX, MOUSEY, (WORD) wparam);
  1245. break;
  1246. #endif
  1247. case EM_INSERTTABLE:
  1248. lres = hr = OnInsertTable((TABLEROWPARMS *)wparam, (TABLECELLPARMS *)lparam, publdr);
  1249. break;
  1250. case EM_REPLACESEL:
  1251. wparam = wparam ? ST_CHECKPROTECTION | ST_SELECTION | ST_KEEPUNDO
  1252. : ST_CHECKPROTECTION | ST_SELECTION;
  1253. hr = SetText((LPTSTR)lparam, wparam, 1200, publdr, &lres);
  1254. break;
  1255. case EM_REQUESTRESIZE:
  1256. hr = _pdp->RequestResize();
  1257. break;
  1258. case EM_SCROLL:
  1259. // TxVScroll returns the number of lines scrolled;
  1260. // this info should be returned in lres
  1261. lres = _pdp->VScroll((WORD)wparam, 0);
  1262. break;
  1263. case EM_SCROLLCARET:
  1264. OnScrollCaret();
  1265. break;
  1266. case EM_SELECTIONTYPE:
  1267. {
  1268. SELCHANGE selchg;
  1269. GetSel()->SetSelectionInfo(&selchg);
  1270. lres = selchg.seltyp;
  1271. }
  1272. break;
  1273. case EM_SETTYPOGRAPHYOPTIONS:
  1274. // Don't allow typography options for password & accelerator instances
  1275. hr = OnSetTypographyOptions(wparam, lparam);
  1276. lres = (hr == S_OK);
  1277. break;
  1278. case EM_SETBIDIOPTIONS:
  1279. if((Get10Mode() || !wparam) && lparam && !IsRich())
  1280. {
  1281. WORD wMask = ((BIDIOPTIONS *)lparam)->wMask;
  1282. WORD wEffects = (_fNeutralOverride ? BOE_NEUTRALOVERRIDE : 0) |
  1283. (_nContextDir == CTX_NONE ? 0 : BOE_CONTEXTREADING) |
  1284. (_nContextAlign == CTX_NONE ? 0 : BOE_CONTEXTALIGNMENT);
  1285. wEffects &= ~wMask;
  1286. wEffects |= (wMask & ((BIDIOPTIONS *)lparam)->wEffects);
  1287. if (_fNeutralOverride != !!(wEffects & BOE_NEUTRALOVERRIDE))
  1288. {
  1289. _fNeutralOverride = !_fNeutralOverride;
  1290. if (!_pdp->IsPrinter()) // Refresh display
  1291. {
  1292. _pdp->InvalidateRecalc();
  1293. TxInvalidate();
  1294. }
  1295. }
  1296. _nContextDir = (WORD)((wEffects & BOE_CONTEXTREADING) ? CTX_NEUTRAL : CTX_NONE);
  1297. _nContextAlign = (WORD)((wEffects & BOE_CONTEXTALIGNMENT) ? CTX_NEUTRAL : CTX_NONE);
  1298. if(_nContextDir != CTX_NONE || _nContextAlign != CTX_NONE)
  1299. {
  1300. SetContextDirection(TRUE);
  1301. Assert(_nContextDir != CTX_NONE || _nContextAlign != CTX_NONE);
  1302. }
  1303. }
  1304. break;
  1305. case WM_SETFOCUS:
  1306. hr = OnSetFocus();
  1307. break;
  1308. case EM_SETFONTSIZE:
  1309. lres = OnSetFontSize(LONG(wparam), (DWORD)lparam, publdr);
  1310. break;
  1311. case EM_SETMODIFY:
  1312. _fModified = wparam != 0;
  1313. #ifdef LATER
  1314. if (!_fModified)
  1315. ObFreezeFrames();
  1316. #endif // LATER
  1317. break;
  1318. case EM_SETSCROLLPOS:
  1319. {
  1320. POINT *pPoint = (POINT*)lparam;
  1321. _pdp->ScrollView(pPoint->x, pPoint->y, FALSE, TRUE);
  1322. lres = 1;
  1323. }
  1324. break;
  1325. case EM_EXSETSEL:
  1326. // EM_EXSETSEL duplicates the functionality of the 32-bit EM_SETSEL
  1327. // and exists purely for backward compatibility with Win16. We just
  1328. // repackage the params and fall thru to EM_SETSEL
  1329. wparam = (WPARAM)((CHARRANGE *)lparam)->cpMin;
  1330. lparam = (LPARAM)((CHARRANGE *)lparam)->cpMost;
  1331. // FALL-THROUGH to EM_SETSEL!!!
  1332. case EM_SETSEL:
  1333. lres = OnSetSel((LONG)wparam, (LONG)lparam);
  1334. break;
  1335. // INCREDIBLY EVIL HACK ALERT!!!!! Win95's dialog manager doesn't even
  1336. // pretend to be 32 bits despite the best attempts of our marketing dudes.
  1337. // WM_USER + 1 is the old Win3.0 EM_SETSEL in which the selection range
  1338. // was packed into the lparam.
  1339. //
  1340. // Sometimes (like tabbing through a dialog), Win95 will send us the 16
  1341. // bit EM_SETSEL message, so process it here.
  1342. case (WM_USER + 1):
  1343. lres = OnSetSel(LOWORD(lparam), HIWORD(lparam));
  1344. break;
  1345. case EM_SETTARGETDEVICE:
  1346. // Keep width sane so that LXtoDX works OK at least for displays
  1347. // Note that 0x7fffff = 485 feet! This keeps LXtoDX working provided
  1348. // _xPerInch < 257 (it's typically 96 for displays). For more
  1349. // generality, we'd need to use 64-bit arithmetic (see LXtoDX).
  1350. lparam = min(lparam, (LPARAM)0x7fffff);
  1351. lres = _pdp->SetMainTargetDC((HDC)wparam, (LONG)lparam);
  1352. break;
  1353. case EM_SETTEXTEX:
  1354. hr = SetText((LPTSTR)lparam, ((SETTEXTEX *)wparam)->flags,
  1355. ((SETTEXTEX *)wparam)->codepage, publdr, &lres);
  1356. break;
  1357. case WM_SETTEXT:
  1358. hr = SetText((LPTSTR)lparam, ST_CHECKPROTECTION, wparam ? wparam : 1200, publdr, &lres);
  1359. break;
  1360. case EM_SETVIEWKIND:
  1361. hr = SetViewKind(wparam);
  1362. break;
  1363. #ifndef NOWORDBREAKPROC
  1364. case EM_SETWORDBREAKPROC:
  1365. _fExWordBreakProc = 0;
  1366. _pfnWB = (EDITWORDBREAKPROC) lparam;
  1367. break;
  1368. case EM_SETWORDBREAKPROCEX:
  1369. // We don't support this API in 2.0 and greater because we pass
  1370. // UNICODE text to the callback function. Therefore there
  1371. // are no benefits to this API. Exists for 1.0 backward
  1372. // compatibility only.
  1373. if (Get10Mode())
  1374. {
  1375. _fExWordBreakProc = 1;
  1376. // This is a bit deceiving, but lparam is a EDITWORDBREAKPROCEX but the compiler
  1377. // will generate an error if you try to type cast the l-value
  1378. _pfnWB = (EDITWORDBREAKPROC) lparam;
  1379. }
  1380. break;
  1381. #endif
  1382. case WM_SYSCHAR:
  1383. lres = hr = OnTxSysChar((WORD)wparam, (DWORD)lparam, publdr);
  1384. if(hr == S_OK)
  1385. break;
  1386. goto def;
  1387. case WM_SYSKEYUP:
  1388. if(IN_RANGE(VK_SHIFT, wparam, VK_MENU))
  1389. ResetKeyboardFlag(GetKbdFlags((WORD)wparam, (DWORD)lparam));
  1390. if (IN_RANGE(VK_NUMPAD0, wparam, VK_NUMPAD9) ||
  1391. wparam == VK_CLEAR || wparam == VK_INSERT ||
  1392. IN_RANGE(VK_PRIOR, wparam, VK_DOWN))
  1393. {
  1394. // Collect AltNumPad number to word around NT 4 bug and
  1395. // generalize to any Unicode value (in decimal, ugh!)
  1396. const static BYTE VkeyNumbers[] = {VK_NUMPAD9, VK_NUMPAD3, VK_NUMPAD1,
  1397. VK_NUMPAD7, VK_NUMPAD4, VK_NUMPAD8, VK_NUMPAD6, VK_NUMPAD2, 0, 0,
  1398. 0, 0, VK_NUMPAD0};
  1399. // Flag Alt NumPad char typed to
  1400. SetKeyboardFlag(ALTNUMPAD); // distinguish hiANSI from lead
  1401. if(!IN_RANGE(VK_NUMPAD0, wparam, VK_NUMPAD9)) // byte in Win3.1 IME
  1402. { // Collect AltNumPad number
  1403. if(wparam == VK_CLEAR) // NumLock not active: translate
  1404. wparam = VK_NUMPAD5; // to digit codes
  1405. else
  1406. wparam = VkeyNumbers[wparam - VK_PRIOR];
  1407. }
  1408. DWORD dwNum = GetKeyPadNumber();
  1409. if(!dwNum && wparam == VK_NUMPAD0)
  1410. SetKeyboardFlag(ALT0); // Flag that 0 is first digit
  1411. SetKeyPadNumber(10*dwNum + wparam - VK_NUMPAD0);
  1412. }
  1413. goto def;
  1414. case WM_SYSKEYDOWN:
  1415. if(OnTxSysKeyDown(wparam, lparam, publdr) == S_OK)
  1416. {
  1417. lres = TRUE;
  1418. break;
  1419. }
  1420. goto def;
  1421. case WM_TIMER:
  1422. OnTxTimer((UINT)wparam);
  1423. goto def;
  1424. case EM_UNDO:
  1425. case WM_UNDO:
  1426. if (!_fReadOnly)
  1427. {
  1428. hr = PopAndExecuteAntiEvent(_pundo, (void*)wparam);
  1429. if(hr == NOERROR)
  1430. lres = TRUE;
  1431. }
  1432. break;
  1433. case EM_REDO:
  1434. if (!_fReadOnly)
  1435. {
  1436. hr = PopAndExecuteAntiEvent(_predo, (void*)wparam);
  1437. if(hr == NOERROR)
  1438. lres = TRUE;
  1439. }
  1440. break;
  1441. case EM_SETUNDOLIMIT:
  1442. lres = HandleSetUndoLimit((DWORD)wparam);
  1443. break;
  1444. case WM_VSCROLL:
  1445. // TxVScroll returns the number of lines scrolled;
  1446. // WM_VSCROLL doesn't care about that info however.
  1447. Assert(lres == 0);
  1448. Assert(hr == NOERROR);
  1449. if (IsUVerticalTflow(_pdp->GetTflow()))
  1450. _pdp->UScroll(LOWORD(wparam), HIWORD(wparam));
  1451. else
  1452. _pdp->VScroll(LOWORD(wparam), HIWORD(wparam));
  1453. break;
  1454. case EM_GETHYPHENATEINFO:
  1455. {
  1456. HYPHENATEINFO *phyphinfo = (HYPHENATEINFO*) wparam;
  1457. if (phyphinfo->cbSize >= sizeof(HYPHENATEINFO))
  1458. {
  1459. phyphinfo->pfnHyphenate = _pfnHyphenate;
  1460. phyphinfo->dxHyphenateZone = _dulHyphenateZone;
  1461. }
  1462. else
  1463. hr = E_INVALIDARG;
  1464. }
  1465. break;
  1466. case EM_SETHYPHENATEINFO:
  1467. {
  1468. HYPHENATEINFO *phyphinfo = (HYPHENATEINFO*) wparam;
  1469. if (phyphinfo->cbSize >= sizeof(HYPHENATEINFO))
  1470. {
  1471. BOOL fRedraw = FALSE;
  1472. if (phyphinfo->pfnHyphenate != _pfnHyphenate ||
  1473. _pfnHyphenate && _dulHyphenateZone != phyphinfo->dxHyphenateZone)
  1474. fRedraw = TRUE;
  1475. _pfnHyphenate = phyphinfo->pfnHyphenate;
  1476. _dulHyphenateZone = _pfnHyphenate ? phyphinfo->dxHyphenateZone : 0;
  1477. if (fRedraw)
  1478. _pdp->UpdateView();
  1479. }
  1480. else
  1481. hr = E_INVALIDARG;
  1482. }
  1483. break;
  1484. case EM_GETAUTOCORRECTPROC:
  1485. {
  1486. if (_pDocInfo)
  1487. lres = (LRESULT) _pDocInfo->_pfnAutoCorrect;
  1488. }
  1489. break;
  1490. case EM_SETAUTOCORRECTPROC:
  1491. {
  1492. CDocInfo *pDocInfo = GetDocInfo();
  1493. if (pDocInfo)
  1494. pDocInfo->_pfnAutoCorrect = (AutoCorrectProc) wparam;
  1495. else;
  1496. lres = TRUE;
  1497. }
  1498. break;
  1499. // Old stuff that's no longer supported
  1500. case EM_FMTLINES: // Controls returning CRCRLFs for soft
  1501. // line breaks in EM_GETTEXT. Could
  1502. // implement
  1503. case WM_GETFONT: // Can support but have to hang onto a
  1504. // default HFONT. CCcs has an _hfont, but
  1505. // need to be sure default font is in
  1506. // cache at time of return
  1507. #ifdef EM_GETHANDLE
  1508. case EM_GETHANDLE: // Not supported by Win95 32-bit MLE either
  1509. case EM_SETHANDLE: // Not supported by Win95 32-bit MLE either
  1510. #endif
  1511. #ifdef DEBUG
  1512. TRACEINFOSZ("Old message that is no longer supported.");
  1513. #endif
  1514. break;
  1515. case EM_SETTABSTOPS:
  1516. {
  1517. // this message only works for multi-line edit controls
  1518. if(!_pdp->IsMultiLine())
  1519. break;
  1520. // perform some validation checks
  1521. Assert(lparam || !wparam);
  1522. LPDWORD prgdwdlgCoord = (LPDWORD)lparam;
  1523. if (wparam && (!prgdwdlgCoord || !(*prgdwdlgCoord)))
  1524. break;
  1525. AssertSz(wparam <= MAX_TAB_STOPS, "Tab stop count beyond maximum allowed");
  1526. if (wparam > MAX_TAB_STOPS)
  1527. wparam = MAX_TAB_STOPS;
  1528. PARAFORMAT2 pf;
  1529. ZeroMemory(&pf, sizeof(PARAFORMAT2));
  1530. pf.cbSize = sizeof(PARAFORMAT2);
  1531. // contains the average width for the default font
  1532. LONG lAvgWidth;
  1533. //Average char width based on default font
  1534. HDC hdc = _phost->TxGetDC();
  1535. GetECDefaultHeightAndWidth(this, hdc, 1, 1,
  1536. W32->GetYPerInchScreenDC(), &lAvgWidth, NULL, NULL);
  1537. _phost->TxReleaseDC(hdc);
  1538. Assert(lAvgWidth);
  1539. // According to documentation wparam == 1 means the tab settings
  1540. // will be set at incremental positions *prgdwdlgCoord and wparam == 0
  1541. // the tab settings will be set at the default incremental position 32 (dialog coord)
  1542. long lTab = (wparam) ? *prgdwdlgCoord : 32;
  1543. long nCt = (wparam <= 1) ? MAX_TAB_STOPS : (signed)wparam;
  1544. for (int i = 0; i < nCt; i++)
  1545. {
  1546. long lval;
  1547. lval = (wparam <= 1) ? ((i+1) * lTab) : *prgdwdlgCoord;
  1548. pf.rgxTabs[i] = MulDiv(MulDiv(lval, lAvgWidth, 4), 1440, W32->GetXPerInchScreenDC());
  1549. if((unsigned)pf.rgxTabs[i] > 0xFFFFFF) // Keep in range
  1550. pf.rgxTabs[i] = 0xFFFFFF;
  1551. prgdwdlgCoord++;
  1552. }
  1553. // Set the default paragraph formatting
  1554. pf.cTabCount = nCt;
  1555. pf.dwMask = PFM_TABSTOPS;
  1556. CParaFormat PF;
  1557. PF.Set(&pf);
  1558. // Need to turn off group typing just like the selection would.
  1559. if (publdr)
  1560. publdr->StopGroupTyping();
  1561. lres = OnSetParaFormat(SPF_SETDEFAULT, &PF, publdr, PFM_TABSTOPS, PFM2_PARAFORMAT);
  1562. GetTabsCache()->Release(PF._iTabs);
  1563. break;
  1564. }
  1565. case EM_SETCHARFORMAT:
  1566. {
  1567. CHARFORMAT2 *pCF2 = (CHARFORMAT2 *)lparam;
  1568. UINT CodePage = 1200;
  1569. DWORD dwMask = pCF2->dwMask;
  1570. DWORD dwMask2 = 0;
  1571. if(!IsValidCharFormatW(pCF2))
  1572. {
  1573. if(!IsValidCharFormatA((CHARFORMAT2A *)lparam))
  1574. break;
  1575. if(dwMask & CFM_FACE) // Need to convert to Unicode
  1576. CodePage = GetDefaultCodePage(EM_SETCHARFORMAT);
  1577. }
  1578. if(dwMask & CFM_CHARSET && CharRepFromCharSet(pCF2->bCharSet) < 0)
  1579. dwMask &= ~CFM_CHARSET;
  1580. if(wparam & (SCF_ASSOCIATEFONT | SCF_ASSOCIATEFONT2))
  1581. {
  1582. lres = OnSetAssociateFont(pCF2, (DWORD)wparam);
  1583. break;
  1584. }
  1585. if(Get10Mode() && (dwMask & CFM_SIZE) && (pCF2->yHeight <= 0))
  1586. {
  1587. // 1.0 has a hack where if the height is being set and it is
  1588. // negative, then the height field is ignored.
  1589. dwMask &= ~CFM_SIZE;
  1590. }
  1591. if (pCF2->cbSize == sizeof(CHARFORMATW) ||
  1592. pCF2->cbSize == sizeof(CHARFORMATA))
  1593. {
  1594. // Restrict specifications to CHARFORMAT parameters. If the
  1595. // host isn't our Windows host, we allow this to include the
  1596. // CHARFORMAT2 disabled effect, since Forms^3 wanted that effect
  1597. // but wasn't willing to use CHARFORMAT2 (even tho they asked
  1598. // for it...)
  1599. dwMask &= fInOurHost() ? CFM_ALL : (CFM_ALL | CFM_DISABLED);
  1600. dwMask2 = CFM2_CHARFORMAT; // Tell callees that CHARFORMAT
  1601. } // was used
  1602. CCharFormat CF; // Transfer external CHARFORMAT(2)
  1603. CF.Set(pCF2, CodePage); // parms to internal CCharFormat
  1604. lres = OnSetCharFormat(wparam, &CF, publdr, dwMask, dwMask2);
  1605. break;
  1606. }
  1607. case WM_SETFONT:
  1608. lres = OnSetFont((HFONT)wparam);
  1609. break;
  1610. case EM_SETPAGE:
  1611. if(_pdp)
  1612. hr = _pdp->SetPage(wparam);
  1613. break;
  1614. case EM_SETPARAFORMAT:
  1615. {
  1616. PARAFORMAT2 *pPF2 = (PARAFORMAT2 *)lparam;
  1617. if(!IsValidParaFormat(pPF2))
  1618. break;
  1619. DWORD dwMask = pPF2->dwMask;
  1620. // Two more things to validate: (1) We don't let an applications set
  1621. // up tables and (2) Tabs coming from applications must be valid.
  1622. if(dwMask & (PFM_TABLE | PFM_TABLEROWDELIMITER |
  1623. PFM_OUTLINELEVEL | PFM_COLLAPSED))
  1624. {
  1625. // Trying to set up a table or outline view
  1626. break;
  1627. }
  1628. if ((dwMask & PFM_TABSTOPS) && (pPF2->cTabCount != 0))
  1629. {
  1630. // Make sure all submitted tabstops make sense.
  1631. int iMax = min(MAX_TAB_STOPS, pPF2->cTabCount);
  1632. for (int i = 0; i < iMax; i++)
  1633. {
  1634. // Make sure that tab stops make sense - make sure alignment
  1635. // is valid.
  1636. if (GetTabAlign(pPF2->rgxTabs[i]) > tomAlignBar)
  1637. {
  1638. // Invalid alignment.
  1639. break;
  1640. }
  1641. }
  1642. if (i != iMax)
  1643. {
  1644. // Found error in validation loop so we are done.
  1645. break;
  1646. }
  1647. }
  1648. DWORD dwMask2 = 0;
  1649. if(pPF2->cbSize == sizeof(PARAFORMAT))
  1650. {
  1651. dwMask &= PFM_ALL; // Restrict to PARAFORMAT parms
  1652. dwMask2 = PFM2_PARAFORMAT; // Tell callees that
  1653. } // PARAFORMAT was used
  1654. CParaFormat PF; // Transfer external PARAFORMAT(2)
  1655. PF.Set(pPF2); // parms to internal CParaFormat
  1656. lres = OnSetParaFormat(wparam, &PF, publdr, dwMask, dwMask2);
  1657. GetTabsCache()->Release(PF._iTabs);
  1658. break;
  1659. }
  1660. case EM_SETZOOM:
  1661. if ((unsigned)(wparam | lparam) < 65536 && (!(wparam | lparam) ||
  1662. (LONG)wparam < (lparam << 6) && lparam < (LONG)(wparam << 6)))
  1663. {
  1664. // Only get here if
  1665. // 1) 0 <= wparam <= 65535 and 0 <= lparam <= 65535, and
  1666. // 2) either wparam = lparam = 0 (which turns off zooming by this
  1667. // message) or 1/64 < (zoom factor given by wparam/lparam) < 64.
  1668. SetZoomNumerator(wparam);
  1669. SetZoomDenominator(lparam);
  1670. _pdp->UpdateView();
  1671. lres = 1;
  1672. }
  1673. break;
  1674. case EM_STREAMIN:
  1675. case EM_STREAMOUT:
  1676. {
  1677. CTxtRange rg(this, 0, -GetTextLength());
  1678. CTxtRange * prg = &rg; // Default whole doc
  1679. wparam = W32->ValidateStreamWparam(wparam);
  1680. if(wparam & SFF_SELECTION) // Save to current selection
  1681. {
  1682. prg = (CTxtRange *)GetSel();
  1683. AssertSz(prg,
  1684. "EM_STREAMIN/OUT: requested selection doesn't exist");
  1685. }
  1686. else if(msg == EM_STREAMIN)
  1687. {
  1688. // If we are not streaming into the selection, then we are
  1689. // "loading" the entire file; this is not an undo-able operation,
  1690. // so set the undo builder to NULL and get rid of the current
  1691. // undo stacks
  1692. publdr = NULL;
  1693. ClearUndo(&undobldr);
  1694. // Clear away the file info if necessary
  1695. if(!(wparam & SFF_KEEPDOCINFO))
  1696. CloseFile(FALSE);
  1697. }
  1698. if(msg == EM_STREAMIN)
  1699. {
  1700. // If we are going to be loading an entire file, we only
  1701. // want to check "normal' protection; we can ignore the
  1702. // fIsDBCS protection. This does mean that somebody
  1703. // can do an "insert file" and break apart a DBCS combo,
  1704. // but we'll have to live with that. Outlook uses
  1705. // RTF streaming in many different places, so the strong
  1706. // fIsDBCS protection breaks them.
  1707. if ((_dwEventMask & ENM_PROTECTED) &&
  1708. prg->IsProtected(CHKPROT_EITHER) == PROTECTED_ASK &&
  1709. QueryUseProtection(prg, msg, wparam, lparam))
  1710. {
  1711. Beep();
  1712. Assert(lres == 0);
  1713. break;
  1714. }
  1715. // Freeze the display before loading
  1716. CFreezeDisplay fd(_pdp);
  1717. lres = _ldte.LoadFromEs(prg, wparam, (EDITSTREAM *)lparam,
  1718. FALSE, publdr);
  1719. if (_fOutlineView)
  1720. {
  1721. // Outline view must have formatting.
  1722. _psel->Check_rpPF();
  1723. }
  1724. if (_fFocus)
  1725. {
  1726. // Update caret but delay till display is thawed and do so only
  1727. // if we have the focus. If we do this all the time we get wierd
  1728. // scrolling effects such as scrolling to the beginning of a
  1729. // document when the focus is set. See bug #1649 for repro of
  1730. // wierd effects.
  1731. _pdp->SaveUpdateCaret(TRUE);
  1732. }
  1733. }
  1734. else
  1735. lres = _ldte.SaveToEs (prg, wparam, (EDITSTREAM *)lparam);
  1736. break;
  1737. }
  1738. #ifdef WM_SYSCOLORCHANGE
  1739. case WM_SYSCOLORCHANGE:
  1740. #ifndef NODRAFTMODE
  1741. if (_fDraftMode)
  1742. {
  1743. W32->InitSysParams(TRUE);
  1744. _pdp->InvalidateRecalc();
  1745. }
  1746. #endif
  1747. TxInvalidate();
  1748. break;
  1749. #endif
  1750. // debug stuff
  1751. #if defined(DEBUG) && !defined(NOFULLDEBUG)
  1752. case EM_DBGPED:
  1753. OnDumpPed();
  1754. break;
  1755. #endif // DEBUG
  1756. case EM_SETEVENTMASK:
  1757. lres = _dwEventMask; // Set up to return value before
  1758. _dwEventMask = (DWORD)lparam; // the change
  1759. if (lparam & ENM_REQUESTRESIZE)
  1760. {
  1761. // We need to update the display just in case it changes.
  1762. _pdp->UpdateView();
  1763. }
  1764. break;
  1765. case EM_GETEVENTMASK:
  1766. lres = _dwEventMask;
  1767. break;
  1768. #ifdef EM_GETTHUMB
  1769. case EM_GETTHUMB:
  1770. LONG Pos;
  1771. BOOL fIsEnabled;
  1772. if (TxGetVScroll(NULL, NULL, &Pos, NULL, &fIsEnabled) == S_OK
  1773. && fIsEnabled)
  1774. {
  1775. lres = Pos;
  1776. }
  1777. break;
  1778. #endif
  1779. case EM_SETLANGOPTIONS:
  1780. _fAutoFont = (lparam & IMF_AUTOFONT) != 0;
  1781. _fAutoKeyboard = (lparam & IMF_AUTOKEYBOARD) != 0;
  1782. _fAutoFontSizeAdjust = (lparam & IMF_AUTOFONTSIZEADJUST) != 0;
  1783. _fDualFont = (lparam & IMF_DUALFONT) != 0;
  1784. _fUIFont = (lparam & IMF_UIFONTS) != 0;
  1785. lres = 1;
  1786. break;
  1787. case EM_GETLANGOPTIONS:
  1788. if(_fAutoFont)
  1789. lres |= IMF_AUTOFONT;
  1790. if(_fAutoKeyboard)
  1791. lres |= IMF_AUTOKEYBOARD;
  1792. if(_fAutoFontSizeAdjust)
  1793. lres |= IMF_AUTOFONTSIZEADJUST;
  1794. if(_fDualFont)
  1795. lres |= IMF_DUALFONT;
  1796. if(_fUIFont)
  1797. lres |= IMF_UIFONTS;
  1798. break;
  1799. case EM_SETEDITSTYLE:
  1800. if (!Get10Mode()) // Not support in 1.0 mode
  1801. {
  1802. BOOL fForceRepaint = FALSE;
  1803. DWORD dwEditStyle = _dwEditStyle & ~lparam; // Kill current flag values
  1804. // Change following mask to give the largest SES_xxx defined)
  1805. dwEditStyle |= wparam & lparam & (SES_CTFALLOWPROOFING*2 - 1); // Or in new values
  1806. // Certain bits aren't switchable
  1807. dwEditStyle |= (_fSystemEditMode ? SES_EMULATESYSEDIT : 0);
  1808. _dwEditStyle = dwEditStyle;
  1809. // There are certain things which we won't allow user to reset, ie SES_EMULATESYSEDIT.
  1810. // So reset everything and except for the SES_EMULATESYSEDIT
  1811. if(dwEditStyle & SES_EMULATESYSEDIT)
  1812. {
  1813. if(SUCCEEDED(HandleSetTextMode(TM_SINGLELEVELUNDO | TM_PLAINTEXT)))
  1814. {
  1815. // SES_EMULATESYSEDIT implies SES_BEEPONMAXTEXT
  1816. _fSystemEditBeep = TRUE;
  1817. }
  1818. else
  1819. _fSystemEditMode = FALSE;
  1820. }
  1821. #ifndef NODRAFTMODE
  1822. // Repaint and recalc if draft mode is turned on or off
  1823. if (lparam & SES_DRAFTMODE)
  1824. fForceRepaint = TRUE;
  1825. #endif
  1826. if (fForceRepaint || (lparam & SES_USEATFONT))
  1827. {
  1828. _pdp->InvalidateRecalc();
  1829. TxInvalidate();
  1830. }
  1831. if(dwEditStyle & SES_BIDI)
  1832. OrCharFlags(FRTL, publdr);
  1833. _fLowerCase = !_fUpperCase && (dwEditStyle & SES_LOWERCASE);
  1834. } // Fall thru to EM_GETEDITSTYLE
  1835. // to return _bEditStyle
  1836. case EM_GETEDITSTYLE:
  1837. if (!Get10Mode()) // Not support in 1.0 mode
  1838. lres |= _dwEditStyle; // Some EditStyles have been filled in Cmsgflt
  1839. break;
  1840. case EM_SETPAGEROTATE:
  1841. lres = HandleSetTextFlow(wparam);
  1842. break;
  1843. case EM_GETPAGEROTATE:
  1844. lres = _pdp->GetTflow();
  1845. break;
  1846. case EM_SETTEXTMODE:
  1847. // 1.0 mode does not supported EM_SETTEXTMODE
  1848. if (!Get10Mode())
  1849. lres = HandleSetTextMode(wparam);
  1850. break;
  1851. case EM_GETTEXTMODE:
  1852. lres = IsRich() ? TM_RICHTEXT : TM_PLAINTEXT;
  1853. lres |= (_pundo && ((CUndoStack *)_pundo)->GetSingleLevelMode())
  1854. ? TM_SINGLELEVELUNDO : TM_MULTILEVELUNDO;
  1855. lres |= _fSingleCodePage ? TM_SINGLECODEPAGE : TM_MULTICODEPAGE;
  1856. break;
  1857. case EM_LIMITTEXT:
  1858. lparam = wparam;
  1859. // Intentionally fall through. These messages are duplicates. But
  1860. // Win9x manages to convert wparam = 0x3FFFFFFF to 0xFFFFFFFF. No
  1861. // such problem exists with EM_EXLIMITTEXT.
  1862. case EM_EXLIMITTEXT: // Has cp input parameter (sort of)
  1863. if(!lparam) // We ignore translation between
  1864. { // acp and cp
  1865. // 0 means set the control to the maximum size. However, because
  1866. // 1.0 set this to 64K will keep this the same value so as not to
  1867. // surprise anyone. Apps are free to set the value to be above 64K.
  1868. lparam = (LPARAM)cResetTextMax;
  1869. }
  1870. if (Get10Mode())
  1871. {
  1872. // 1.0 used a signed variable to hold the length of the string. So
  1873. // if lparam is negative then just set lparam to zero to emulate
  1874. // 1.0 behavior
  1875. if ((LONG)lparam < 0)
  1876. lparam = 0;
  1877. }
  1878. _cchTextMost = (LONG)lparam;
  1879. break;
  1880. case EM_AUTOURLDETECT:
  1881. if(lparam || (wparam | 1) != 1)
  1882. {
  1883. hr = lres = E_INVALIDARG;
  1884. break;
  1885. }
  1886. if(wparam == TRUE && !_pdetecturl)
  1887. {
  1888. _pdetecturl = new CDetectURL(this);
  1889. if(!_pdetecturl)
  1890. hr = lres = E_OUTOFMEMORY;
  1891. }
  1892. else if(!wparam && _pdetecturl)
  1893. {
  1894. delete _pdetecturl;
  1895. _pdetecturl = NULL;
  1896. }
  1897. break;
  1898. case EM_GETAUTOURLDETECT:
  1899. Assert(lres == 0 && hr == NOERROR);
  1900. if(_pdetecturl)
  1901. lres = TRUE;
  1902. break;
  1903. case WM_SIZE:
  1904. // We reset the "number of tries to put an active object
  1905. // in place" count here
  1906. _cActiveObjPosTries = MAX_ACTIVE_OBJ_POS_TRIES;
  1907. hr = S_FALSE;
  1908. break;
  1909. case WM_SETTINGCHANGE:
  1910. // System parameters have changed. We need to update them.
  1911. // Note : Since we don't protect access to system parameters
  1912. // with locks, it may be possible for some instances to not
  1913. // see the changes immediately
  1914. lres = 0;
  1915. W32->InitSysParams(TRUE);
  1916. #ifndef NODRAFTMODE
  1917. if (_fDraftMode)
  1918. {
  1919. _pdp->InvalidateRecalc();
  1920. TxInvalidate();
  1921. }
  1922. #endif
  1923. #ifndef NOCOMPLEXSCRIPTS
  1924. if (W32->GetDigitSubstitutionMode() != DIGITS_NOTIMPL)
  1925. OrCharFlags(FRTL, publdr);
  1926. #endif
  1927. break;
  1928. case EM_CONVPOSITION:
  1929. if (wparam)
  1930. lres = GetCpFromAcp(lparam);
  1931. else
  1932. lres = GetAcpFromCp(lparam);
  1933. break;
  1934. #ifndef NOPRIVATEMESSAGE
  1935. case EM_INSERTOBJ:
  1936. {
  1937. // This message supports Cicero InsertEmbedded
  1938. int cpMin = ((CHARRANGE *)wparam)->cpMin;
  1939. int cpMost = ((CHARRANGE *)wparam)->cpMost;
  1940. CTxtRange rg(this, cpMin, cpMin - cpMost);
  1941. REPASTESPECIAL rps; // @parm Special paste info
  1942. rps.dwAspect = DVASPECT_CONTENT;
  1943. hr = S_FALSE;
  1944. if (!rg.WriteAccessDenied())
  1945. hr = _ldte.CreateOleObjFromDataObj((IDataObject *)lparam, &rg, &rps, iEmbObj, publdr);
  1946. }
  1947. break;;
  1948. case EM_SETCALLBACK: // Setup message filter callback
  1949. _pMsgCallBack = (CMsgCallBack *)lparam;
  1950. break;
  1951. case EM_SETUPNOTIFY:
  1952. if (!_pMsgNotify)
  1953. _pMsgNotify = new CTextNotify(this);
  1954. if (_pMsgNotify)
  1955. {
  1956. if (wparam == 0)
  1957. _pMsgNotify->Remove((ITxNotify *)lparam);
  1958. else
  1959. _pMsgNotify->Add((ITxNotify *)lparam);
  1960. }
  1961. break;
  1962. case EM_GETDOCFLAGS:
  1963. lres = 0;
  1964. if (_fReadOnly)
  1965. lres |= GDF_READONLY;
  1966. if (_fOverstrike)
  1967. lres |= GDF_OVERTYPE;
  1968. if (_fSingleCodePage)
  1969. lres |= GDF_SINGLECPG;
  1970. if (_fRich)
  1971. lres |= GDF_RICHTEXT;
  1972. lres &= wparam;
  1973. break;
  1974. case EM_GETPARATXTFLOW:
  1975. {
  1976. CTxtPara *pTxtPara = (CTxtPara *)lparam;
  1977. lres = pTxtPara->_PF.IsRtlPara();
  1978. break;
  1979. }
  1980. #endif
  1981. #ifndef NOACCESSIBILITY
  1982. case WM_GETOBJECT:
  1983. {
  1984. IUnknown* punk = NULL;
  1985. lres = 0;
  1986. if (lparam == OBJID_NATIVEOM)
  1987. {
  1988. QueryInterface(IID_IUnknown, (void**)&punk); // Need to expose Tom interdface
  1989. }
  1990. else if (lparam == OBJID_CLIENT && _fInOurHost)
  1991. {
  1992. HWND hwnd = NULL;
  1993. TxGetWindow( &hwnd );
  1994. if (hwnd)
  1995. W32->CreateStdAccessibleProxyW(hwnd, L"RichEdit", OBJID_CLIENT, IID_IAccessible, (void**)&punk);
  1996. }
  1997. if (punk)
  1998. {
  1999. lres = W32->LResultFromObject(IID_IUnknown, wparam, (LPUNKNOWN)punk);
  2000. punk->Release();
  2001. }
  2002. break;
  2003. }
  2004. #endif
  2005. default:
  2006. def: hr = S_FALSE;
  2007. break;
  2008. }
  2009. if(plresult)
  2010. *plresult = lres;
  2011. #ifndef NOFEPROCESSING
  2012. if (hr == S_FALSE && _pMsgFilter && _pMsgCallBack)
  2013. {
  2014. HWND hWnd;
  2015. TxGetWindow(&hWnd);
  2016. hr = _pMsgCallBack->HandlePostMessage(hWnd, msg, wparam, lparam, plresult);
  2017. }
  2018. #endif
  2019. return hr;
  2020. }
  2021. /*
  2022. * CTxtEdit::TxDraw (dwDrawAspect, lindex, pvAspect, ptd, hdcDraw,
  2023. * hicTargetDev, lprcBounds, lprcWBounds, lprcUpdate,
  2024. * pfnContinue, dwContinue)
  2025. *
  2026. * @mfunc Draws the text services object
  2027. *
  2028. * @rdesc HRESULT (typically S_OK).
  2029. *
  2030. * @comm
  2031. *
  2032. * This method renders the Text Services. It accepts the same parameters
  2033. * as the corresponding IViewObject::Draw method in OLE, with the extra
  2034. * <p lprcUpdate > parameter. It can be used while the host is inactive
  2035. * or active (in-place).
  2036. *
  2037. * If dwDrawAspect is DVASPECT_CONTENT, this method should render a screen
  2038. * image of the text content to the hdcDraw device context. The hicTargetDev
  2039. * and ptd parameters give information on the target device context if any
  2040. * (usually a printer).
  2041. *
  2042. * The lprcClient parameter gives the rectangle to render to, also called
  2043. * "client rectangle". This rectangle represents the position and extents
  2044. * of the entire image of the Text Services to be drawn. It is expressed in
  2045. * the logical coordinate system of hdcDraw. This parameter can only be NULL
  2046. * if the control is active. In that case, Text Services should render the
  2047. * in-place active view (which client rectangle can be obtained by calling
  2048. * TxGetClientRect on the host).
  2049. *
  2050. * The lprcUpdate parameter, if not NULL, gives the rectangle to update
  2051. * inside that client rectangle. It is given in the logical coordinate system
  2052. * of hdcDraw. If NULL, the entire client rectangle should be painted.
  2053. *
  2054. * Text Services should render with the appropriate zooming factor, which
  2055. * can be obtained from the client rect and the native size given by
  2056. * ITextHost::TxGetExtent. For more information, see ITextHost::TxGetExtent.
  2057. *
  2058. * If the drawing aspect is DVASPECT_DOCPRINT, the TxDraw method can assume
  2059. * that it is rendering to the printer. In that case, hdcDraw is the printer
  2060. * device context. TxDraw should still render the lprcBounds rectangle,
  2061. * starting at the current scrolling position. TS can make optimization for
  2062. * rendering to the printer (like not painting the background color if white)
  2063. * and certain screen specific elements (such as the selection) should not be
  2064. * rendered.
  2065. *
  2066. * General comments on OLE hosts and TxDraw (and TxSetCursor, TxQueryHitPoint):
  2067. *
  2068. * OLE hosts can call the TxDraw method at any time with any rendering DC or
  2069. * client rectangle. All an inactive OLE object has on a permanent basis is
  2070. * a himetric extent. It gets the rectangle in which to render only via the
  2071. * IViewObject::Draw call and this rectangle is valid only for the scope of
  2072. * that method. In fact, the same control can be rendered consecutively in
  2073. * different rectangles and different DCs for example because it is displayed
  2074. * simultaneously in different views on the screen.
  2075. *
  2076. * The client rectangle and DC passed to TxDraw should normally not be cached.
  2077. * However, this would force Text Services to recalc lines for every single
  2078. * draw, which would lead to terrible performance. So it is likely that Text
  2079. * Services will actually cache some information computed for a specific
  2080. * client rectangle and DC (such as the line breaks for example). On the
  2081. * next call to TxDraw, however, the validity of the cached information
  2082. * should be checked before it gets used, and updated information should be
  2083. * regenerated if necessary.
  2084. *
  2085. * When the control is in-place active, the problem is even more complex
  2086. * since TxDraw can still be called to render other views than the in-place
  2087. * active one. In other words, the client rectangle passed to TxDraw may
  2088. * not be the same as the active view one (passed to OnTxInPlaceActivate
  2089. * and obtained via TxGetClientRect on the host).The the host specifies
  2090. * what view they wish to display based on the lViewId parameter. If the
  2091. * value for lViewId is TXTVIEW_ACTIVE, the view referred to is the inplace
  2092. * active view. TXTVIEW_INACTIVE means some other view such as a print
  2093. * preview or even printing itself. It is important to note that
  2094. * TXTVIEW_INACTIVE views may not have scroll bars.
  2095. *
  2096. * The same comments apply to TxSetCursor and TxQueryHitPoint, discussed
  2097. * in the following sections.
  2098. */
  2099. HRESULT CTxtEdit::TxDraw(
  2100. DWORD dwDrawAspect, //@parm Draw aspect
  2101. LONG lindex, //@parm Currently unused
  2102. void * pvAspect, //@parm Info for drawing optimizations (OCX 96)
  2103. DVTARGETDEVICE *ptd, //@parm Info on target device
  2104. HDC hdcDraw, //@parm Rendering device context
  2105. HDC hicTargetDev, //@parm Target information context
  2106. LPCRECTL lprcBounds, //@parm Bounding (client) rectangle
  2107. LPCRECTL lprcWBounds, //@parm Clipping rect for metafiles
  2108. LPRECT lprcUpdate, //@parm Dirty rectangle inside lprcBounds
  2109. BOOL (CALLBACK * pfnContinue) (DWORD), //@parm Callback for interupting
  2110. // long display (currently unused)
  2111. DWORD dwContinue, //@parm Parameter to pass to pfnContinue function
  2112. LONG lViewId) //@parm View identifier
  2113. {
  2114. TRACEBEGIN(TRCSUBSYSTS, TRCSCOPEEXTERN, "CTxtEdit::TxDraw");
  2115. HRESULT hr;
  2116. // JMO : FUTURE : We should do something about reentrant draws sometime.
  2117. // If we do that may procide a simpler fix for RAID bug 7212.
  2118. #if !defined(NOMAGELLAN)
  2119. CMagellanBMPStateWrap bmpOff(*this, hdcDraw);
  2120. #endif
  2121. CCallMgr callmgr(this);
  2122. START_PROFILING
  2123. {
  2124. CLock lock;
  2125. if (g_OLSBusy)
  2126. return E_UNEXPECTED;
  2127. }
  2128. // If the display is frozen, don't let ourselves draw. This is a pretty
  2129. // hoaky re-entrancy check.
  2130. // FUTURE (alexgo/ricksa): be better about this.
  2131. if(TXTVIEW_ACTIVE == lViewId && _pdp->IsFrozen())
  2132. {
  2133. _pdp->SetNeedRedisplayOnThaw(TRUE);
  2134. TRACEINFOSZ("Forcing a redisplay on thaw");
  2135. return E_UNEXPECTED;
  2136. }
  2137. if(dwDrawAspect != DVASPECT_CONTENT && dwDrawAspect != DVASPECT_DOCPRINT)
  2138. {
  2139. // We don't support the aspect requested
  2140. return DV_E_DVASPECT;
  2141. }
  2142. if(!lprcBounds && !_fInPlaceActive || hicTargetDev && !ptd)
  2143. {
  2144. // If we are not inplace active we must have a client rectangle
  2145. return E_INVALIDARG;
  2146. }
  2147. HDC hicLocal = NULL;
  2148. // Did they give us a ptd without a hic?
  2149. if(!hicTargetDev && ptd)
  2150. {
  2151. // Create and information context for the device information
  2152. // since it wasn't supplied.
  2153. hicLocal = CreateIC(
  2154. (TCHAR *)((BYTE *) ptd + ptd->tdDriverNameOffset),
  2155. (TCHAR *)((BYTE *) ptd + ptd->tdDeviceNameOffset),
  2156. (TCHAR *)((BYTE *) ptd + ptd->tdPortNameOffset),
  2157. (DEVMODE *)((BYTE *) ptd + ptd->tdExtDevmodeOffset));
  2158. if(!hicLocal)
  2159. return E_FAIL; // Couldn't create it
  2160. hicTargetDev = hicLocal;
  2161. }
  2162. AssertSz(GetMapMode(hdcDraw) == MM_TEXT || GetDeviceCaps(hdcDraw, TECHNOLOGY) == DT_METAFILE,
  2163. "RichEdit requires MM_TEXT."); // REVIEW (keithcu) Clients do (and should) use MM_TEXT
  2164. // Preallocate the memory so the set cannnot fail and we don't
  2165. // have to use the heap. Note that all clean up is handled
  2166. // outside of this object. Also note that we don't assign any
  2167. // information here because we may not use this structure. If
  2168. // recursion is happening we will use the top level structure.
  2169. CDrawInfo di(this);
  2170. _pdp->SetDrawInfo(
  2171. &di,
  2172. dwDrawAspect,
  2173. lindex,
  2174. pvAspect,
  2175. ptd,
  2176. hicTargetDev);
  2177. // We use our main display object if we are the active view (which is
  2178. // indicate by the supplied client rectangle) or if the object is
  2179. // inactive and the ptd is NULL. We assume that the ptd being NULL means
  2180. // that the display request is for the screen and not for a print or
  2181. // print preview.
  2182. if(TXTVIEW_ACTIVE == lViewId || !ptd)
  2183. {
  2184. hr = S_FALSE;
  2185. // The main display object draws active views and tries to draw
  2186. // inactive views if the control is not active.
  2187. if (!lprcWBounds &&
  2188. ( fInplaceActive() && TXTVIEW_ACTIVE == lViewId ||
  2189. !fInplaceActive() && TXTVIEW_INACTIVE == lViewId))
  2190. {
  2191. hr = _pdp->Draw(hdcDraw, hicTargetDev, // We aren't interruptable
  2192. (RECT *)lprcBounds, // drawing to screen, so
  2193. (RECT *)lprcWBounds, // why pretend?
  2194. lprcUpdate, NULL, 0);
  2195. }
  2196. if(S_FALSE == hr)
  2197. {
  2198. // This is an inactive view for which the cached state
  2199. // does not match the input request so we make a special
  2200. // object to do the drawing.
  2201. CDisplay *pdp = _pdp->Clone();
  2202. if(pdp)
  2203. {
  2204. // Force recalc - this tells Draw to draw no matter what
  2205. pdp->InvalidateRecalc();
  2206. hr = pdp->Draw(hdcDraw, hicTargetDev, // Do the draw
  2207. (RECT *)lprcBounds,
  2208. (RECT *)lprcWBounds,
  2209. lprcUpdate, NULL, 0);
  2210. }
  2211. delete pdp;
  2212. }
  2213. }
  2214. else
  2215. {
  2216. // Make a copy so that we can update it
  2217. RECT rcForPrint = *((RECT *)lprcBounds);
  2218. // We want data both formatted and printed
  2219. hr = FormatAndPrint(hdcDraw, hicTargetDev, ptd, &rcForPrint,
  2220. (RECT*)lprcWBounds);
  2221. struct SPrintControl prtcon;
  2222. // This call to OnFormatRange simply cleans up printer object
  2223. OnFormatRange(NULL, prtcon);
  2224. }
  2225. _pdp->ReleaseDrawInfo();
  2226. if(hicLocal) // Clean up information context
  2227. DeleteDC(hicLocal); // if we created one
  2228. // An active OLE object might have been dragged/scrolled away
  2229. // from where it belongs. We need to put it back.
  2230. // The _cActiveObjPosTries guards us from an indefinite looop here
  2231. // (OnReposition may post another paint message, and so on)
  2232. // We only do this when we were notified of a position or size change
  2233. COleObject* poleobjActive;
  2234. if (HasObjects() && _cActiveObjPosTries &&
  2235. (poleobjActive = GetObjectMgr()->GetInPlaceActiveObject()))
  2236. {
  2237. // Reduce number of tries
  2238. _cActiveObjPosTries--;
  2239. // BUG FIX 6073
  2240. // Only fetch the extent if the object view size or position
  2241. // has changed
  2242. // Get new object size (we might have resized it,
  2243. // and we don't want to lose that!!)
  2244. if (poleobjActive->GetViewChanged())
  2245. {
  2246. poleobjActive->FetchObjectExtents();
  2247. poleobjActive->ResetViewChanged();
  2248. }
  2249. // and put it there!!
  2250. poleobjActive->OnReposition();
  2251. }
  2252. return hr;
  2253. }
  2254. /*
  2255. * CTxtEdit::TxGetHScroll (plMin, plMax, plPos, plPage, pfEnabled)
  2256. *
  2257. * @mfunc
  2258. * Get horizontal scroll bar state information
  2259. *
  2260. * @rdesc
  2261. * HRESULT = S_OK
  2262. */
  2263. HRESULT CTxtEdit::TxGetHScroll(
  2264. LONG *plMin, //@parm Minimum scroll position
  2265. LONG *plMax, //@parm Maximum scroll position
  2266. LONG *plPos, //@parm Current scroll position
  2267. LONG *plPage, //@parm View width in pixels
  2268. BOOL *pfEnabled) //@parm Whether horizonatl scrolling is enabled.
  2269. {
  2270. TRACEBEGIN(TRCSUBSYSTS, TRCSCOPEEXTERN, "CTxtEdit::TxGetHScroll");
  2271. START_PROFILING
  2272. if(plMin)
  2273. *plMin = 0;
  2274. if (IsUVerticalTflow(_pdp->GetTflow()))
  2275. {
  2276. if(plMax)
  2277. *plMax = _pdp->GetScrollRange(SB_VERT);
  2278. if(plPage)
  2279. *plPage = _pdp->ConvertVPosToScrollPos(_pdp->GetDvpView());
  2280. if(plPos)
  2281. {
  2282. *plPos = _pdp->ConvertVPosToScrollPos(_pdp->GetVpScroll());
  2283. if (_pdp->GetTflow() == tflowSW)
  2284. *plPos = *plMax - *plPos - *plPage;
  2285. *plPos = max(*plPos, 0);
  2286. }
  2287. if(pfEnabled)
  2288. *pfEnabled = _pdp->IsVScrollEnabled();
  2289. }
  2290. else
  2291. {
  2292. if(plMax)
  2293. *plMax = _pdp->GetScrollRange(SB_HORZ);
  2294. if(plPos)
  2295. *plPos = _pdp->GetUpScroll();
  2296. if(plPage)
  2297. *plPage = _pdp->GetDupView();
  2298. // CDisplay::_fUScrollEnabled may be TRUE when not in-place active
  2299. // because it has a dual meaning: 1) need Horiz scroll bars, and 2)
  2300. // CDisplay::_upScroll is allowed for ES_AUTOHSCROLL even with no
  2301. // horizontal scrollbar. The latter can turn on _fUScrollEnabled when
  2302. // the control is active and when the control goes inactive, it stays
  2303. // on, so we say it's off to keep Forms^3 from displaying a horizontal
  2304. // scroll bar. We probably should have two flags: _fUScrollEnabled and
  2305. // _fUScrollbarEnabled, but for now, we stick with one. No such problem
  2306. // for vertical case, since vertical scrolling always uses a scrollbar.
  2307. if(pfEnabled)
  2308. *pfEnabled = _fInPlaceActive ? _pdp->IsUScrollEnabled() : 0;
  2309. }
  2310. return S_OK;
  2311. }
  2312. /*
  2313. * CTxtEdit::TxGetVScroll (plMin, plMax, plPos, plPage, pfEnabled)
  2314. *
  2315. * @mfunc
  2316. * Get vertical scroll bar state information
  2317. *
  2318. * @rdesc
  2319. * HRESULT = S_OK
  2320. */
  2321. HRESULT CTxtEdit::TxGetVScroll(
  2322. LONG *plMin, //@parm Minimum scroll position
  2323. LONG *plMax, //@parm Maximum scroll position
  2324. LONG *plPos, //@parm Current scroll position
  2325. LONG *plPage, //@parm Height of view in pixels
  2326. BOOL *pfEnabled) //@parm Whether vertical scroll bar is enabled.
  2327. {
  2328. TRACEBEGIN(TRCSUBSYSTS, TRCSCOPEEXTERN, "CTxtEdit::TxGetVScroll");
  2329. if(plMin)
  2330. *plMin = 0;
  2331. if (IsUVerticalTflow(_pdp->GetTflow()))
  2332. {
  2333. if(plMax)
  2334. *plMax = _pdp->GetScrollRange(SB_HORZ);
  2335. if(plPos)
  2336. *plPos = _pdp->GetUpScroll();
  2337. if(plPage)
  2338. *plPage = _pdp->GetDupView();
  2339. if(pfEnabled)
  2340. *pfEnabled = _fInPlaceActive ? _pdp->IsUScrollEnabled() : 0;
  2341. }
  2342. else
  2343. {
  2344. if(plMax)
  2345. *plMax = _pdp->GetScrollRange(SB_VERT);
  2346. if(plPos)
  2347. *plPos = _pdp->ConvertVPosToScrollPos(_pdp->GetVpScroll());
  2348. if(plPage)
  2349. *plPage = _pdp->ConvertVPosToScrollPos(_pdp->GetDvpView());
  2350. if(pfEnabled)
  2351. *pfEnabled = _pdp->IsVScrollEnabled();
  2352. }
  2353. return S_OK;
  2354. }
  2355. /*
  2356. * CTxtEdit::OnTxSetCursor (dwDrawAspect, lindex, pvAspect, ptd, hdcDraw,
  2357. * hicTargetDev, lprcClient, x, y)
  2358. * @mfunc
  2359. * Notification for text services to set the cursor
  2360. *
  2361. * @rdesc
  2362. * HRESULT = FAILED(RectChangeHelper()) ? E_INVALIDARG : S_OK
  2363. *
  2364. * @comm
  2365. * Text Services may remeasure as a result of this call in
  2366. * order to determine the correct cursor. The correct
  2367. * cursor will be set via ITextHost::TxSetCursor
  2368. *
  2369. * More details:
  2370. *
  2371. * The lprcClient parameter is the client rectangle of the view of the
  2372. * control over which the mouse cursor is. It is in device coordinates
  2373. * of the containing window in the same way the WM_SIZE message is. This
  2374. * may not be the view that was rendered last. Furthermore, if the control
  2375. * is in-place active, this may not be the view currently being active.
  2376. * As a consequence, Text Services should check this rectangle against
  2377. * its current caches values and determine whether recalcing the lines
  2378. * is necessary or not. The zoom factor should be included in this
  2379. * computation.
  2380. *
  2381. * This method should only be called for screen views of the control.
  2382. * Therefore the DC is not passed in but should be assumed to be a screen
  2383. * DC.
  2384. *
  2385. * The x and y parameters hold the cursor position in the same coordinate
  2386. * system as lprcClient, i.e., the client coordinates of the containing
  2387. * window.
  2388. */
  2389. //REVIEW (keithcu) Do people really pass rectangles different from those
  2390. //returned from TxGetClientRect? I'd be surprised if that happens, and if it did
  2391. //who cares if we display the wrong cursor??
  2392. HRESULT CTxtEdit::OnTxSetCursor (
  2393. DWORD dwDrawAspect, //@parm Draw aspect
  2394. LONG lindex, //@parm Currently unused
  2395. void * pvAspect, //@parm Info for drawing optimizations (OCX 96)
  2396. DVTARGETDEVICE *ptd, //@parm Info on target device
  2397. HDC hdcDraw, //@parm Rendering device context
  2398. HDC hicTargetDev, //@parm Target information context
  2399. LPCRECT lprcClient, //@parm Control's client rectangle
  2400. INT x, //@parm x position of cursor
  2401. INT y) //@parm y position of cursor
  2402. {
  2403. TRACEBEGIN(TRCSUBSYSTS, TRCSCOPEEXTERN, "CTxtEdit::OnTxSetCursor");
  2404. CCallMgr callmgr(this);
  2405. BOOL fText = FALSE;
  2406. HITTEST Hit;
  2407. RECT rcxyClient;
  2408. BOOL fGotDC = FALSE;
  2409. START_PROFILING
  2410. if (_fInPlaceActive)
  2411. TxGetClientRect(&rcxyClient);
  2412. else if (lprcClient)
  2413. rcxyClient = *lprcClient;
  2414. else
  2415. return E_INVALIDARG;
  2416. if (!_pdp->IsValid())
  2417. {
  2418. HDC hdc = GetDC(NULL);
  2419. _pdp->SetDC(hdc);
  2420. fGotDC = TRUE;
  2421. }
  2422. // Set the cursor
  2423. CTxtSelection * const psel = GetSel();
  2424. HCURSOR hcurNew = _hcurArrow; // Default using system arrow
  2425. POINT ptxy = {x, y};
  2426. POINTUV pt;
  2427. RECTUV rcClient;
  2428. BOOL fInLink = FALSE;
  2429. _pdp->RectuvFromRect(rcClient, rcxyClient);
  2430. _pdp->PointuvFromPoint(pt, ptxy);
  2431. if(PtInRect(&rcxyClient, ptxy))
  2432. {
  2433. // Find out what the cursor is pointing at
  2434. _pdp->CpFromPoint(pt, &rcClient, NULL, NULL, FALSE, &Hit);
  2435. if(Hit == HT_LeftOfText)
  2436. hcurNew = _hcurSelBar;
  2437. // This is a bit strange, but RichEdit 1.0 does this--give client a
  2438. // chance to handle cursor itself if we are over a link.
  2439. else if(Hit == HT_Link)
  2440. {
  2441. if(HandleLinkNotification(WM_SETCURSOR, 0, MAKELPARAM(ptxy.x, ptxy.y), &fInLink))
  2442. {
  2443. return NOERROR;
  2444. }
  2445. hcurNew = _hcurHand;
  2446. }
  2447. else if(Hit != HT_Nothing && Hit != HT_OutlineSymbol && Hit != HT_BulletArea)
  2448. {
  2449. if(!psel || !psel->PointInSel(pt, &rcClient, Hit) || _fDisableDrag)
  2450. {
  2451. if (IsUVerticalTflow(_pdp->GetTflow()))
  2452. hcurNew = (Hit == HT_Italic) ? _hcurVItalic : _hcurVIBeam;
  2453. else
  2454. hcurNew = (Hit == HT_Italic) ? _hcurItalic : _hcurIBeam;
  2455. fText = TRUE;
  2456. }
  2457. // If we have an object manager and if there is a selected object,
  2458. // check for hits on the frame handles.
  2459. if(_pobjmgr)
  2460. {
  2461. COleObject *pobjselect = _pobjmgr->GetSingleSelect();
  2462. if(pobjselect)
  2463. {
  2464. // Handle hits on frame handles.
  2465. LPTSTR idcur = pobjselect->CheckForHandleHit(pt);
  2466. HCURSOR hcurObj = W32->GetSizeCursor(idcur);
  2467. if(hcurObj)
  2468. hcurNew = hcurObj;
  2469. }
  2470. }
  2471. }
  2472. }
  2473. _phost->TxSetCursor(hcurNew, fText); // Tell host to set cursor
  2474. if (fGotDC)
  2475. {
  2476. HDC hdc = _pdp->GetDC();
  2477. ::ReleaseDC(NULL, hdc);
  2478. _pdp->SetDC(NULL);
  2479. }
  2480. return S_OK;
  2481. }
  2482. /*
  2483. * CTxtEdit::TxQueryHitPoint (dwDrawAspect, lindex, pvAspect, ptd, hdcDraw,
  2484. * hicTargetDev, lprcClient, x, y, pHitResult)
  2485. * @mfunc
  2486. * Returns whether point is within text services rectangle
  2487. *
  2488. * @rdesc
  2489. * HRESULT
  2490. *
  2491. * @comm
  2492. * This method allows the host to implement transparent hit-testing
  2493. * on text.
  2494. *
  2495. * The lprcClient parameter is the client rectangle in device coordinates
  2496. * of the view on which hit testing is performed.
  2497. *
  2498. * The pt parameter hold the position of the cursor in the same
  2499. * coordinate system as the lprcClient rectangle (the client
  2500. * coordinates of the containing window).
  2501. *
  2502. * Same general comments about client rectangle and DC as for
  2503. * TxSetCursor apply.
  2504. *
  2505. * pHitResult returns one of the following values: <nl>
  2506. *
  2507. * TXTHITRESULT_NOHIT Hit was outside client rectangle. <nl>
  2508. * TXTHITRESULT_HIT Point was inside client rectangle and over
  2509. * either text or an opaque background.
  2510. * TXTHITRESULT_TRANSPARENT Point was inside client rectangle with a
  2511. * transparent background and not over text.
  2512. * TXTHITRESULT_CLOSE Hit was close to an opaque area.
  2513. *
  2514. * Refer to the Windowless OLE Control spec for more details on
  2515. * these return values and how they should be determined.
  2516. */
  2517. HRESULT CTxtEdit::TxQueryHitPoint(
  2518. DWORD dwDrawAspect, //@parm Draw aspect
  2519. LONG lindex, //@parm Currently unused
  2520. void * pvAspect, //@parm Info for drawing optimizations (OCX 96)
  2521. DVTARGETDEVICE *ptd, //@parm Info on target device
  2522. HDC hdcDraw, //@parm Rendering device context
  2523. HDC hicTargetDev, //@parm Target information context
  2524. LPCRECT lprcClient, //@parm Control's client rectangle
  2525. INT x, //@parm x coordinate to check
  2526. INT y, //@parm y coordinate to check
  2527. DWORD * pHitResult) //@parm Result of hit test see TXTHITRESULT
  2528. // enumeration for valid values
  2529. {
  2530. TRACEBEGIN(TRCSUBSYSTS, TRCSCOPEEXTERN, "CTxtEdit::TxQueryHitPoint");
  2531. RECTUV rcClient;
  2532. RECT rcxyClient;
  2533. CCallMgr callmgr(this);
  2534. START_PROFILING
  2535. if (_fInPlaceActive)
  2536. TxGetClientRect(&rcxyClient);
  2537. else if (lprcClient)
  2538. rcxyClient = *lprcClient;
  2539. else
  2540. return E_INVALIDARG;
  2541. HRESULT hr;
  2542. POINT ptxy = {x, y};
  2543. POINTUV pt;
  2544. _pdp->PointuvFromPoint(pt, ptxy);
  2545. _pdp->RectuvFromRect(rcClient, rcxyClient);
  2546. if(!_fTransparent)
  2547. {
  2548. *pHitResult = TXTHITRESULT_HIT;
  2549. hr = S_OK;
  2550. }
  2551. else
  2552. hr = _pdp->TransparentHitTest(hdcDraw, &rcxyClient, pt, pHitResult);
  2553. return hr;
  2554. }
  2555. /*
  2556. * CTxtEdit::OnTxInPlaceActivate (prcClient)
  2557. *
  2558. * @mfunc
  2559. * Notifies text services that this control is inplace active
  2560. *
  2561. * @rdesc
  2562. * S_OK - successfully activated object <nl>
  2563. * E_FAIL - could not activate object due to error. <nl>
  2564. *
  2565. * @comm
  2566. * When transitioning directly from a non-active state to the UI-active
  2567. * state, the host should call OnTxInPlaceActivate first and then
  2568. * OnTxUIActivate. Similarly, when transitioning from the UI-active
  2569. * state to a non active state, the host should call OnTxUIDeactivate
  2570. * first and then OnTxInPlaceDeactivate.
  2571. *
  2572. * OnTxInPlaceActivate takes the client rectangle of the view being
  2573. * activated as a parameter. This rectangle is given in client coordinate
  2574. * of the containing window. It is the same as would be obtained by
  2575. * calling TxGetClientRect on the host.
  2576. *
  2577. * UI-activation is different from getting the focus. To let Text
  2578. * Services know that the control is getting or losing focus, the
  2579. * host will send WM_SETFOCUS and WM_KILLFOCUS messages. Note that a
  2580. * windowless host will pass NULL as the wParam (window that lost the
  2581. * focus) for these messages.
  2582. *
  2583. * As a reminder, inplace activation typically refers to an embedded
  2584. * object "running inplace" (for regular controls && embeddings, it
  2585. * would have a window to draw in, for example). UI active means that
  2586. * an object currently has the 'editing focus'. Specifically, things
  2587. * like menus and toolbars on the container may also contain elements
  2588. * from the UI active control/embedding. There can only be one
  2589. * UI active control at any given time, while many can be inplace active
  2590. * at once.
  2591. */
  2592. HRESULT CTxtEdit::OnTxInPlaceActivate(
  2593. const RECT *prcClient) //@parm Control's client rectangle
  2594. {
  2595. TRACEBEGIN(TRCSUBSYSTS, TRCSCOPEEXTERN, "CTxtEdit::OnTxInPlaceActivate");
  2596. RECTUV rcView;
  2597. HDC hdc;
  2598. BOOL fSucceeded = TRUE;
  2599. CCallMgr callmgr(this);
  2600. RECTUV rcClient;
  2601. START_PROFILING
  2602. // Needs to set here for further TxGetDC() to work
  2603. _fInPlaceActive = TRUE;
  2604. // Set rendering DC to be the screen
  2605. hdc = TxGetDC();
  2606. if(!hdc)
  2607. goto err;
  2608. // Tell display that it is active
  2609. _pdp->SetActiveFlag(TRUE);
  2610. _pdp->SetDC(hdc);
  2611. //REVIEW (keithcu) I removed prcClient usage here because it appears that
  2612. //clients pass in wrong rectangles to OnTxInPlaceActivate. That is quite
  2613. //scary--do they pass in wrong rectangles to other places? (We could see
  2614. //weird results when not in-place active. If (as the comment says) the prcClient
  2615. //should be the same as what would be gotten from the host, we will now just fetch
  2616. //the value from the host rather than look at what is passed down.
  2617. #if 1
  2618. prcClient = 0;
  2619. #else
  2620. if (prcClient)
  2621. _pdp->RectuvFromRect(rcClient, *prcClient);
  2622. //Verify the rectangle passed in is the same as what we'd fetch from
  2623. //getting it from the client
  2624. #ifdef DEBUG
  2625. {
  2626. RECT rcDebug;
  2627. TxGetClientRect(&rcDebug);
  2628. AssertSz(rcDebug.right - rcDebug.left == prcClient->right - prcClient->left &&
  2629. rcDebug.bottom - rcDebug.top == prcClient->bottom - prcClient->top,
  2630. "CLIENT BUG: Inconsistent rectangles between ITextServices::"
  2631. "OnTxInPlaceActivate(RECT*) and ITextHost::TxGetClientRect(RECT*)");
  2632. }
  2633. #endif
  2634. #endif
  2635. // Compute view rect from passed in client rect
  2636. _pdp->GetViewRect(rcView, prcClient ? &rcClient : 0);
  2637. // Recalc/update view
  2638. _pdp->RecalcView(rcView);
  2639. // Get selection. Otherwise, if SetFocus is called later without
  2640. // selection, then the Selection state is not set correctly.
  2641. GetSel();
  2642. if(_pdp->GetDupView())
  2643. {
  2644. // Get selection if we can
  2645. if(_psel) // Set the caret
  2646. _psel->Update(FALSE);
  2647. else // Couldn't create selection,
  2648. fSucceeded = FALSE; // so fail activation
  2649. }
  2650. // Release the DC
  2651. TxReleaseDC(hdc);
  2652. _pdp->SetDC(NULL);
  2653. // If getting the selection worked we are home free
  2654. if(fSucceeded)
  2655. return S_OK;
  2656. err:
  2657. _fInPlaceActive = FALSE;
  2658. return E_FAIL;
  2659. }
  2660. /*
  2661. * CTxtEdit::OnTxInPlaceDeactivate()
  2662. *
  2663. * @mfunc Notifies text services that this is no longer in place active.
  2664. *
  2665. * @rdesc S_OK
  2666. *
  2667. * @comm See OnTxInPlaceActivate for a detailed description of
  2668. * activation/deactivation.
  2669. *
  2670. * @xref <mf CTxtEdit::OnTxInPlaceActivate>
  2671. *
  2672. */
  2673. HRESULT CTxtEdit::OnTxInPlaceDeactivate()
  2674. {
  2675. TRACEBEGIN(TRCSUBSYSTS, TRCSCOPEEXTERN, "CTxtEdit::OnTxInPlaceDeactivate");
  2676. START_PROFILING
  2677. // Get properties that affect whether we will discard the selection
  2678. DWORD dwBits;
  2679. // Tell display that it is not longer active
  2680. _pdp->SetActiveFlag(FALSE);
  2681. // Because we are inactive, this will tell any background recalc going
  2682. // on to stop.
  2683. _pdp->StepBackgroundRecalc();
  2684. _phost->TxGetPropertyBits(TXTBIT_HIDESELECTION | TXTBIT_SAVESELECTION,
  2685. &dwBits);
  2686. // If we don't want to save the selection and we want to hide it while
  2687. // inactive, then we discard our selection
  2688. if(!(dwBits & TXTBIT_SAVESELECTION) && (dwBits & TXTBIT_HIDESELECTION))
  2689. DiscardSelection();
  2690. _fInPlaceActive = FALSE;
  2691. return S_OK;
  2692. }
  2693. /*
  2694. * CTxtEdit::OnTxUIActivate()
  2695. *
  2696. * @mfunc Informs text services that the control is now UI active.
  2697. *
  2698. * @rdesc S_OK
  2699. *
  2700. * @comm See OnTxInPlaceActivate for a detailed description of
  2701. * activation/deactivation.
  2702. *
  2703. * @xref <mf CTxtEdit::OnTxInPlaceActivate>
  2704. *
  2705. *
  2706. */
  2707. HRESULT CTxtEdit::OnTxUIActivate()
  2708. {
  2709. TRACEBEGIN(TRCSUBSYSTS, TRCSCOPEEXTERN, "CTxtEdit::OnTxUIActivate");
  2710. return S_OK;
  2711. }
  2712. /*
  2713. * CTxtEdit::OnTxUIDeactivate()
  2714. *
  2715. * @mfunc Informs text services that the control is now UI deactive.
  2716. *
  2717. * @rdesc S_OK
  2718. *
  2719. * @comm See OnTxInPlaceActivate for a detailed description of
  2720. * activation/deactivation.
  2721. *
  2722. * @xref <mf CTxtEdit::OnTxInPlaceActivate>
  2723. *
  2724. */
  2725. HRESULT CTxtEdit::OnTxUIDeactivate()
  2726. {
  2727. TRACEBEGIN(TRCSUBSYSTS, TRCSCOPEEXTERN, "CTxtEdit::OnTxUIDeactivate");
  2728. return S_OK;
  2729. }
  2730. /*
  2731. * CTxtEdit::TxGetText (pbstrText)
  2732. *
  2733. * @mfunc Returns all of the UNICODE plain text in the control as an
  2734. * OLE BSTR.
  2735. *
  2736. * @rdesc
  2737. * S_OK - Text successfully returned in the output argument <nl>
  2738. * E_INVALIDARG - invalid BSTR pointer passed in. <nl>
  2739. * E_OUTOFMEMORY - could not allocate memory for copy of the text <nl>
  2740. *
  2741. * @comm The caller takes ownership of the returned BSTR. WM_GETTEXT
  2742. * and TOM ITextRange::GetText are alternate techniques for
  2743. * retrieving plain text data.
  2744. *
  2745. * If there is no text in the control, no BSTR will be allocated
  2746. * and NULL will be returned.
  2747. *
  2748. * The returned text will NOT necessarily be NULL terminated.
  2749. */
  2750. HRESULT CTxtEdit::TxGetText(
  2751. BSTR *pbstrText ) //@parm where to return an allocated BSTR
  2752. {
  2753. TRACEBEGIN(TRCSUBSYSTS, TRCSCOPEEXTERN, "CTxtEdit::TxGetText");
  2754. CTxtPtr tp(this, 0);
  2755. CCallMgr callmgr(this);
  2756. START_PROFILING
  2757. if(!pbstrText)
  2758. return E_INVALIDARG;
  2759. const LONG cch = GetTextLength();
  2760. if(cch <= 0)
  2761. {
  2762. *pbstrText = 0;
  2763. return S_OK;
  2764. }
  2765. *pbstrText = SysAllocStringLen(NULL, cch);
  2766. if(!*pbstrText)
  2767. {
  2768. GetCallMgr()->SetOutOfMemory();
  2769. return E_OUTOFMEMORY;
  2770. }
  2771. tp.GetText(cch, *pbstrText);
  2772. return S_OK;
  2773. }
  2774. /*
  2775. * CTxtEdit::TxSetText (pszText)
  2776. *
  2777. * @mfunc Sets all of the text in the control
  2778. *
  2779. * @rdesc
  2780. * S_OK - text was successfully set <nl>
  2781. * E_FAIL - text could not be updated. <nl>
  2782. *
  2783. * @comm
  2784. * This method should be used with care; it essentially re-initializes
  2785. * the text engine with some new data; any previous data and formatting
  2786. * information will be LOST, including undo information.
  2787. *
  2788. * If previous data has been copied to the clipboard, that data will be
  2789. * rendered completely to the clipboard (via OleFlushClipboard) before
  2790. * it is discarded.
  2791. *
  2792. * This method is NOT undo-able.
  2793. *
  2794. * Two alternate approaches to setting text are WM_SETTEXT and TOM
  2795. * ITextRange::SetText.
  2796. *
  2797. * @xref
  2798. * <mf CTxtRange::SetText>
  2799. */
  2800. HRESULT CTxtEdit::TxSetText(
  2801. LPCTSTR pszText) //@parm String to replace the current text with
  2802. {
  2803. TRACEBEGIN(TRCSUBSYSTS, TRCSCOPEEXTERN, "CTxtEdit::TxSetText");
  2804. START_PROFILING
  2805. return SetText(pszText, ST_CHECKPROTECTION, 1200);
  2806. }
  2807. /*
  2808. * CTxtEdit::TxGetCurTargetX (px)
  2809. *
  2810. * @mfunc
  2811. * Get the target x position of the caret
  2812. *
  2813. * @rdesc
  2814. * HRESULT with possible values:
  2815. *
  2816. * S_OK - x position of the caret returned <nl>
  2817. * E_FAIL - There is no selection <nl>
  2818. * E_INVALIDARG - Input argument is invalid <nl>
  2819. *
  2820. * @comm
  2821. * This method is useful for implementing up-down cursoring
  2822. * through a conceptual vertical line. To illustrate this feature,
  2823. * consider setting the insertion point at, say, column 20 in a
  2824. * text editor. Now cursor up and down--notice that wherever possible,
  2825. * the editor tries to put the insertion point as close to column 20
  2826. * as it can for the current line. Column 20 is thus the "target" column
  2827. * for the insertion point.
  2828. *
  2829. * Users would like to have this same capability when cursoring through
  2830. * Forms; however, as other controls don't necessarily share the same
  2831. * notion of column position, the target caret position is expressed simply
  2832. * as an x-coordinate on the display (in *client* coordinates).
  2833. */
  2834. HRESULT CTxtEdit::TxGetCurTargetX(
  2835. LONG *px) //@parm the x location in client coordinates
  2836. {
  2837. TRACEBEGIN(TRCSUBSYSTS, TRCSCOPEEXTERN, "CTxtEdit::TxGetCurTargetX");
  2838. START_PROFILING
  2839. CTxtSelection *psel = GetSel();
  2840. if(!psel)
  2841. return E_FAIL;
  2842. if(!px)
  2843. return E_INVALIDARG;
  2844. *px = psel->GetUpCaretReally();
  2845. return S_OK;
  2846. }
  2847. /*
  2848. * CTxtEdit::TxGetBaseLinePos(pBaseLinePos)
  2849. *
  2850. * @mfunc Get the base line position of the first visible line, in pixels,
  2851. * relative the TS client rectangle. Needed for aligning controls on their
  2852. * baselines.
  2853. *
  2854. * @rdesc HRESULT = E_NOTIMPL
  2855. */
  2856. HRESULT CTxtEdit::TxGetBaseLinePos(
  2857. LONG *pBaseLinePos) //@parm Where to return baseline position
  2858. {
  2859. TRACEBEGIN(TRCSUBSYSTS, TRCSCOPEEXTERN, "CTxtEdit::TxGetBaseLinePos");
  2860. return E_NOTIMPL;
  2861. }
  2862. /*
  2863. * CTxtEdit::TxGetNaturalSize (dwAspect, hdcDraw, hicTargetDev, ptd, dwMode,
  2864. * psizelExtent, pwidth, pheight)
  2865. *
  2866. * @mfunc Allow control to be resized so it fits content appropriately
  2867. *
  2868. * @rdesc S_OK <nl>
  2869. * E_INVALIDARG <nl>
  2870. * E_FAIL Unable to determine correct size <nl>
  2871. * E_OUTOFMEMORY <nl>
  2872. *
  2873. * @comm
  2874. *
  2875. * The first 4 parameters are similar to equivalent parameters in
  2876. * TxDraw and give the same information. In the case TS needs to
  2877. * recalc lines, it should use these values the same ways as in
  2878. * TxDraw.
  2879. *
  2880. * <p pWidth> and <p pHeight> are IN/OUT parameters. The host passes the
  2881. * "tentative" width and height of the client rectangle for the text object
  2882. * and Text Services will compare these values against its current cached
  2883. * state, and if different should recalc lines. Then it will compute
  2884. * and return the natural size. As spec-ed currently, the host can ask for 2
  2885. * different kinds of natural sizes:
  2886. *
  2887. * TXTNS_FITTOCONTENT: the entire text should be formatted to the
  2888. * width that is passed in.Then Text Services return the height of
  2889. * the entire text and the width of the widest line. Note that this
  2890. * option ignores any paragraph formatting such as centering and
  2891. * only returns the raw size for the text.
  2892. *
  2893. * TXTNS_ROUNDTOLINE: returns the integral height of the number of lines that
  2894. * will fit in the input height rounded to the next full line boundary.
  2895. *
  2896. * Note that passed and returned width and height correspond to
  2897. * the *client* rectangle in client units.
  2898. *
  2899. *
  2900. * BACKGROUND
  2901. * Here is a quick description of the features mentioned above:
  2902. *
  2903. * FITTOCONTEXT: Normally happens when the user double clicks one
  2904. * of the control grab handles. Sizes the control to the "optimal"
  2905. * size to fit the entire content. Should accomodate the height of
  2906. * the entire text and the width of the widest line.
  2907. *
  2908. * ROUNDTOLINE (Integral height): if this property is set, when the
  2909. * user resizes the control, it snaps to heights that allow an
  2910. * integral number of lines to be displayed (no line will be clipped).
  2911. */
  2912. HRESULT CTxtEdit::TxGetNaturalSize(
  2913. DWORD dwAspect, //@parm Aspect for drawing. Values taken from OLE's
  2914. // DVASPECT enumeration
  2915. HDC hdcDraw, //@parm DC into which drawing would occur
  2916. HDC hicTargetDev, //@parm DC for which text should be formatted, i.e.,
  2917. // for WYSIWYG
  2918. DVTARGETDEVICE *ptd,//@parm More info on the target device
  2919. DWORD dwMode, //@parm Type of fitting requested. Either
  2920. // TXTNS_FITTOCONTENT or TXTNS_ROUNDTOLINE
  2921. const SIZEL *psizelExtent,//@parm Size of extent to use for zooming
  2922. LONG * pwidth, //@parm Width for such a fitting [in,out]
  2923. LONG * pheight) //@parm Height for such a fitting [in,out]
  2924. {
  2925. TRACEBEGIN(TRCSUBSYSTS, TRCSCOPEEXTERN, "CTxtEdit::TxGetNaturalSize");
  2926. HRESULT hr;
  2927. CCallMgr callmgr(this);
  2928. START_PROFILING
  2929. if(dwAspect != DVASPECT_CONTENT && dwAspect != DVASPECT_DOCPRINT)
  2930. {
  2931. // We don't support the aspect requested
  2932. return DV_E_DVASPECT;
  2933. }
  2934. if (hicTargetDev && !ptd || !pwidth || !pheight ||
  2935. !IN_RANGE(TXTNS_FITTOCONTENT2, dwMode, TXTNS_ROUNDTOLINE))
  2936. {
  2937. // Either and information context is provided without the device
  2938. // target or the mode is not valid or the width was not provided
  2939. // or the height was not provided. In short, the input parameters
  2940. // are not valid so tell the caller.
  2941. return E_INVALIDARG;
  2942. }
  2943. if(!psizelExtent->cy)
  2944. {
  2945. // No extent for control, so just return 0
  2946. *pwidth = 0;
  2947. *pheight = 0;
  2948. return S_OK;
  2949. }
  2950. HDC hicLocal = NULL;
  2951. // Did they give us a ptd without a hic?
  2952. if(!hicTargetDev && ptd)
  2953. {
  2954. // Create and information context for the device information
  2955. // since it wasn't supplied.
  2956. hicLocal = CreateIC(
  2957. (TCHAR *)((BYTE *) ptd + ptd->tdDriverNameOffset),
  2958. (TCHAR *)((BYTE *) ptd + ptd->tdDeviceNameOffset),
  2959. (TCHAR *)((BYTE *) ptd + ptd->tdPortNameOffset),
  2960. (DEVMODE *)((BYTE *) ptd + ptd->tdExtDevmodeOffset));
  2961. if(!hicLocal)
  2962. return E_FAIL; // Couldn't create it
  2963. hicTargetDev = hicLocal;
  2964. }
  2965. // Convenient place to put height & width for converting them to
  2966. // device units.
  2967. POINT pt;
  2968. pt.x = *pwidth;
  2969. pt.y = *pheight;
  2970. AssertSz(GetMapMode(hdcDraw) == MM_TEXT || GetDeviceCaps(hdcDraw, TECHNOLOGY) == DT_METAFILE,
  2971. "RichEdit requires MM_TEXT."); // REVIEW (keithcu) Clients do (and should) use MM_TEXT
  2972. // Set the extent information needed for zooming
  2973. _pdp->SetTempZoomDenominator(psizelExtent->cy);
  2974. if(TXTNS_ROUNDTOLINE == dwMode)
  2975. {
  2976. // Round to fit simply calculates the
  2977. hr = _pdp->RoundToLine(hdcDraw, pt.x, &pt.y);
  2978. }
  2979. else
  2980. {
  2981. // Get natural size for entire presentation
  2982. // Allocate memory for the draw information
  2983. CDrawInfo di(this);
  2984. // Set up the drawing parameters
  2985. _pdp->SetDrawInfo(
  2986. &di,
  2987. dwAspect,
  2988. -1,
  2989. NULL,
  2990. ptd,
  2991. hicTargetDev);
  2992. // Set the Draw DC
  2993. _pdp->SetDC(hdcDraw);
  2994. // Tell display to figure size needed for this display
  2995. hr = _pdp->GetNaturalSize(hdcDraw, hicTargetDev, dwMode, &pt.x, &pt.y);
  2996. _pdp->ResetDC(); // Restore state
  2997. _pdp->ReleaseDrawInfo();
  2998. }
  2999. if(SUCCEEDED(hr)) // Set return values if this worked
  3000. {
  3001. *pwidth = pt.x; // Update return values
  3002. *pheight = pt.y;
  3003. }
  3004. if(hicLocal) // Clean up info context
  3005. DeleteDC(hicLocal); // if we created one
  3006. _pdp->ResetTempZoomDenominator(); // Reset temporary zoom factor
  3007. return hr;
  3008. }
  3009. /*
  3010. * CTxtEdit::TxGetDropTarget (ppDropTarget)
  3011. *
  3012. * @mfunc Get the drop target for the text control
  3013. *
  3014. * @rdesc
  3015. * S_OK - Got drop target successfully <nl>
  3016. * E_OUTOFMEMORY - Could not create drop target <nl>
  3017. *
  3018. * @comm
  3019. * The caller (host) is responsible for calling Register/Revoke
  3020. * DragDrop and for calling IUnknown::Release on the returned
  3021. * drop target when done.
  3022. */
  3023. HRESULT CTxtEdit::TxGetDropTarget(
  3024. IDropTarget **ppDropTarget) //@parm Where to put pointer to drop target
  3025. {
  3026. #ifndef NODRAGDROP
  3027. TRACEBEGIN(TRCSUBSYSTS, TRCSCOPEEXTERN, "CTxtEdit::TxGetDropTarget");
  3028. HRESULT hr;
  3029. CCallMgr callmgr(this);
  3030. START_PROFILING
  3031. hr = _ldte.GetDropTarget(ppDropTarget);
  3032. if(hr == NOERROR)
  3033. (*ppDropTarget)->AddRef();
  3034. return hr;
  3035. #else
  3036. return 0;
  3037. #endif
  3038. }
  3039. /*
  3040. * CTxtEdit::OnTxPropertyBitsChange (dwMask, dwBits)
  3041. *
  3042. * @mfunc Set properties that can be represented by bits.
  3043. *
  3044. * @rdesc HRESULT
  3045. *
  3046. * @comm The following property bits are understood: <nl>
  3047. *
  3048. * TXTBIT_RICHTEXT <nl>
  3049. * TXTBIT_MULTILINE <nl>
  3050. * TXTBIT_READONLY <nl>
  3051. * TXTBIT_SHOWACCELERATOR <nl>
  3052. * TXTBIT_USEPASSWORD <nl>
  3053. * TXTBIT_HIDESELECTION <nl>
  3054. * TXTBIT_SAVESELECTION <nl>
  3055. * TXTBIT_AUTOWORDSEL <nl>
  3056. * TXTBIT_AUTOSIZE <nl>
  3057. * TXTBIT_VERTICAL <nl>
  3058. * TXTBIT_SELECTIONBAR <nl>
  3059. * TXTBIT_WORDWRAP <nl>
  3060. *
  3061. * TXTBIT_CLIENTRECTCHANGE <nl>
  3062. * TXTBIT_VIEWINSETCHANGE <nl>
  3063. * TXTBIT_BACKSTYLECHANGE <nl>
  3064. * TXTBIT_MAXLENGTHCHANGE <nl>
  3065. * TXTBIT_SCROLLBARCHANGE <nl>
  3066. * TXTBIT_CHARFORMATCHANGE <nl>
  3067. * TXTBIT_PARAFORMATCHANGE <nl>
  3068. * TXTBIT_ALLOWBEEP <nl>
  3069. * TXTBIT_EXTENTCHANGE <nl>
  3070. *
  3071. * A brief description of each property follows:
  3072. *
  3073. *
  3074. * Client rectangle (TXTBIT_CLIENTRECTCHANGE):
  3075. *
  3076. * The rectangle the Text Services are responsible for painting
  3077. * and managing. The host will rely on the Text Services for painting
  3078. * that area. Text Services must not paint or invalidate areas outside of
  3079. * that rectangle.
  3080. *
  3081. * The host will forward mouse messages to the Text Services whenever the
  3082. * cursor is over this rectangle.
  3083. *
  3084. * This rectangle is expressed in client coordinates of the containing window.
  3085. *
  3086. * IMPORTANT: this property cannot be queried from the host when it is
  3087. * inactive. The TxGetClientRect method will fail if called at inactive time.
  3088. *
  3089. *
  3090. * View inset (TXTBIT_VIEWINSETCHANGE):
  3091. *
  3092. * This is the amount of space on each side between the client rectangle and
  3093. * the view rectangle. The view rectangle (also called Formating rectangle)
  3094. * is the rectangle the text should be formatted in.
  3095. *
  3096. * The view insets are is passed in a RECT structure but this is not really
  3097. * a rectangle. It should be treated as 4 independent values to substract
  3098. * on each side of the client rectangle to figure the view rectangle.
  3099. *
  3100. * The view insets are passed in himetrics so that they do not depend on
  3101. * the client rectangle and the rendering DC.
  3102. *
  3103. * View insets can be negative on either side of the client rectangle,
  3104. * leading to a bigger view rectangle than the client rectangle. The text
  3105. * should then be clipped to the client rectangle. If the view rectangle
  3106. * is wider than the client rectangle, then the host may add a horizontal
  3107. * scrollbar to the control.
  3108. *
  3109. * Single line Text Services ignore the right boundary of the view rectangle
  3110. * when formatting text.
  3111. *
  3112. * The view inset is available from the host at all times, active or
  3113. * inactive.
  3114. *
  3115. *
  3116. * Backstyle (TXTBIT_BACKSTYLECHANGE):
  3117. *
  3118. * The style of the background of the client rectangle. Can be either of
  3119. * the following values: <nl>
  3120. * #define TXTBACK_TRANSPARENT 0 <nl>
  3121. * #define TXTBACK_SOLID 1 <nl>
  3122. *
  3123. * Values for this property are similar to VB4 values for the same property.
  3124. *
  3125. *
  3126. * MaxLength (TXTBIT_MAXLENGTHCHANGE):
  3127. *
  3128. * The maximum length the text can have. Text Services should reject
  3129. * character insertion and pasted text when this maximum is reached.
  3130. * TxSetText however should still accept (and set) text longer than the
  3131. * maximum length. This is because this method is used for binding and
  3132. * it is critical to maintain the integrity of the data the control
  3133. * is bound to.
  3134. *
  3135. *
  3136. * Scrollbar (TXTBIT_SCROLLBARCHANGE):
  3137. *
  3138. * This property indicates which scollbar is present and whether scollbars
  3139. * are hidden or disabled when scrolling is impossible. It also controls
  3140. * auto-scrolling when the insertion point gets off the client rectangle.
  3141. *
  3142. * This is a DWORD where bits are layed out as in the system window style.
  3143. * Possible bits are:
  3144. * WS_HSCROLL // control has horizontal scrollbar <nl>
  3145. * WS_VSCROLL // control has vertical scrollbar <nl>
  3146. * ES_AUTOVSCROLL // auto-scroll horizontally <nl>
  3147. * ES_AUTOVSCROLL // auto-scroll vertically <nl>
  3148. * ES_DISABLENOSCROLL // scrollbar should be disabled when scrolling
  3149. * impossible <nl>
  3150. *
  3151. * Default CHARFORMAT (TXTBIT_CHARFORMATCHANGE):
  3152. *
  3153. * The CHARFORMAT or CHARFORMAT2 used for default character-format runs,
  3154. * i.e., those not explicitly formatted via the selection or TOM methods.
  3155. *
  3156. * Default PARAFORMAT (TXTBIT_PARAFORMATCHANGE):
  3157. *
  3158. * The PARAFORMAT or PARAFORMAT2 used for default paragraph-format runs,
  3159. * i.e., those not explicitly formatted via the selection or TOM methods.
  3160. *
  3161. *
  3162. * TXTBIT_ALLOWBEEP:
  3163. *
  3164. * TXTBIT_EXTENTCHANGE:
  3165. *
  3166. *
  3167. * TXTBIT_RICHTEXT:
  3168. *
  3169. * Whether the Text Services should be in Rich-Text mode or not. This
  3170. * principally affects how editing commands are applied. For example,
  3171. * applying bold to some text in a plain edit control makes all of the
  3172. * text bold, rather than just the selected text in a rich text control.
  3173. *
  3174. * Note that if there is either undo state or the object has any text,
  3175. * the attempt to change this bit will be ignored.
  3176. *
  3177. *
  3178. * TXTBIT_MULTILINE:
  3179. *
  3180. * If this property is FALSE, Text Services should not process the CR
  3181. * key and truncate any incoming text containing hard line breaks just
  3182. * before the first line break. It is OK to also truncate text set via
  3183. * TxSetText (meaning, it is the responsibility of the host to not use a s
  3184. * single line control when bound to a multi-line field).
  3185. *
  3186. * If this property is TRUE, Text Services should work in multiline mode.
  3187. * The TXTBIT_WORDWRAP can be used to know whether to wrap the lines to
  3188. * the view rectangle or clip them.
  3189. *
  3190. *
  3191. * TXTBIT_READONLY:
  3192. *
  3193. * If this property is TRUE, Text Services should not accept any editing
  3194. * change via the user interface. However, they should still accept
  3195. * programmatic changes via EM_SETTEXT, EM_REPLACETEXT and TxSetText.
  3196. *
  3197. * In read only mode, the user should still be able to move the
  3198. * insertion point, select text and carry out other non content modifying
  3199. * operations such as Copy.
  3200. *
  3201. *
  3202. * TXTBIT_SHOWACCELERATOR:
  3203. *
  3204. * Refer to the "Accelerator" section for details about this property.
  3205. *
  3206. *
  3207. * TXTBIT_USEPASSWORD:
  3208. *
  3209. * If this property is TRUE, the Text Services should show the entire
  3210. * text using the character obtained by TxGetPasswordChar.
  3211. *
  3212. * The notification on this property may mean two different things:
  3213. * The password character changed,
  3214. * The password character was not used before and is used now
  3215. * (or vice versa).
  3216. *
  3217. *
  3218. * TXTBIT_HIDESELECTION:
  3219. *
  3220. * If this property is TRUE, Text Services should hide the selection
  3221. * when the control is inactive. If it is FALSE, the selection, if any,
  3222. * should still be displayed when the control is inactive.
  3223. *
  3224. * If TRUE, this property implies TXTBIT_SAVESELECTION = TRUE.
  3225. *
  3226. *
  3227. * TXTBIT_SAVESELECTION:
  3228. *
  3229. * If this property is TRUE, Text Services should remember the
  3230. * boundaries of the selection when the control goes inactive. If FALSE,
  3231. * it is not necessary to remember the selection when the control goes
  3232. * inactive. It can be reset to start = 0, length = 0 when the control
  3233. * goes active again.
  3234. *
  3235. * This property is used by hosts for which it is not necessary to
  3236. * remember the selection when inactive.
  3237. *
  3238. *
  3239. * TXTBIT_AUTOWORDSEL:
  3240. *
  3241. * This property turns the AutoWordSelect feature on or off.
  3242. *
  3243. *
  3244. * TXTBIT_AUTOSIZE:
  3245. *
  3246. * This property turns the AutoSize feature on or off. Refer to the
  3247. * "AutoSize" section for more details.
  3248. *
  3249. *
  3250. * TXTBIT_VERTICAL:
  3251. *
  3252. * This property turns on vertical writing. Used for FE support.
  3253. * Details TBD.
  3254. *
  3255. *
  3256. * TXTBIT_WORDWRAP:
  3257. *
  3258. * If this property is TRUE and MultiLine is also TRUE, then Text Services
  3259. * should wrap the line to the view rectangle. If this property is FALSE,
  3260. * the lines should not be wrapped but clipped. The right side of the
  3261. * view rectangle should be ignored.
  3262. *
  3263. * If the MultiLine property is off, this property has no effect.
  3264. *
  3265. *
  3266. * TXTBIT_LINESELECTION:
  3267. *
  3268. * This property turns on or off the Line Selection feature. This feature
  3269. * enable the user to select lines or paragraph by placing the mouse cursor
  3270. * over a "line selection" area on the left of the control. The cursor is
  3271. * displayed as a NE arrow in that area. If the Line Selection feature is
  3272. * off, that area should not be shown.
  3273. *
  3274. */
  3275. HRESULT CTxtEdit::OnTxPropertyBitsChange(
  3276. DWORD dwMask, //@parm Bits representing properties to be changed
  3277. DWORD dwBits) //@parm New values for bit properties
  3278. {
  3279. TRACEBEGIN(TRCSUBSYSTS, TRCSCOPEEXTERN, "CTxtEdit::OnTxPropertyBitsChange");
  3280. HRESULT hr = E_FAIL;
  3281. DWORD dwLoopMask = dwMask;
  3282. CCallMgr callmgr(this);
  3283. START_PROFILING
  3284. for (int i = 0; (i < MAX_PROPERTY_BITS) && (dwLoopMask != 0);
  3285. i++, dwLoopMask >>= 1)
  3286. {
  3287. if (dwLoopMask & 1)
  3288. {
  3289. hr = (this->*_fnpPropChg[i])((dwBits & (1 << i)) != 0);
  3290. if (FAILED(hr))
  3291. return hr;
  3292. }
  3293. }
  3294. return S_OK;
  3295. }
  3296. /*
  3297. * CTxtEdit::TxGetCachedSize (pdup, pdvp)
  3298. *
  3299. * @mfunc
  3300. * Returns the cached drawing size (if any) that text services
  3301. * is using. Typically, this will be the size of the last client
  3302. * rect used in TxDraw, TxSetCursor, etc., although it is not
  3303. * guaranteed to be.
  3304. *
  3305. * @rdesc
  3306. * HRESULT
  3307. *
  3308. * @comm
  3309. * This information is provided to allow the host to potentially
  3310. * perform various optimizations, amongst other things.
  3311. */
  3312. HRESULT CTxtEdit::TxGetCachedSize(
  3313. DWORD *pdupClient, //@parm Where to put width (in client coords)
  3314. DWORD *pdvpClient) //@parm Where to put height (in client coords)
  3315. {
  3316. TRACEBEGIN(TRCSUBSYSTS, TRCSCOPEEXTERN, "CTxtEdit::TxGetCachedSize");
  3317. return _pdp->GetCachedSize((long*) pdupClient, (long*) pdvpClient);
  3318. }
  3319. // Forward declaration of initialization helper.
  3320. // These really should be in some header file. But which?
  3321. // Currently the definitions are in dxfrobj.cpp and font.cpp
  3322. void RegisterFETCs();
  3323. void InitFontCache();
  3324. /*
  3325. * CreateTextServices (punkOuter, phost, ppserv)
  3326. *
  3327. * @func
  3328. * Create an instance of the RichEdit Engine. This engine supports the
  3329. * ITextServices and Microsoft Text Object Model (TOM) interfaces.
  3330. *
  3331. * @rdesc
  3332. * S_OK - New text services instance created successfully. <nl>
  3333. * E_INVALIDARG - An invalid argument was passed in. <nl>
  3334. * E_OUTOFMEMORY - Memory for text services object could not be allocated. <nl>
  3335. * E_FAIL - Text services could not be initialized
  3336. *
  3337. * @comm
  3338. * Text Services may be created as a standard OLE aggregated object.
  3339. * Callers should follow standard OLE32 rules for dealing with
  3340. * aggregated objects and caching interface pointers obtained via
  3341. * QueryInterface from the private IUnknown.
  3342. */
  3343. STDAPI CreateTextServices(
  3344. IUnknown *punkOuter, //@parm Outer unknown, may be NULL
  3345. ITextHost *phost, //@parm Client's ITextHost implementation; must be
  3346. // valid
  3347. IUnknown **ppUnk) //@parm Private IUnknown of text services engine
  3348. {
  3349. TRACEBEGIN(TRCSUBSYSTS, TRCSCOPEEXTERN, "CreateTextServices");
  3350. static bool fOnce = FALSE;
  3351. if (!fOnce) {
  3352. CLock lock;
  3353. fOnce = TRUE;
  3354. W32->InitSysParams();
  3355. W32->InitPreferredFontInfo();
  3356. RegisterFETCs(); // Register new clipboard formats
  3357. CreateFormatCaches(); // Create global format caches
  3358. if ( !InitKinsokuClassify() )
  3359. {
  3360. // Init tables for classifying Unicode chars.
  3361. return E_FAIL;
  3362. }
  3363. InitFontCache();
  3364. }
  3365. if(!ppUnk)
  3366. return E_INVALIDARG;
  3367. CTxtEdit *ped = new CTxtEdit((ITextHost2*)phost, punkOuter);
  3368. if(!ped)
  3369. return E_OUTOFMEMORY;
  3370. if(ped->Init(NULL))
  3371. {
  3372. *ppUnk = ped->GetPrivateIUnknown();
  3373. return S_OK;
  3374. }
  3375. delete ped;
  3376. return E_FAIL;
  3377. }