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.

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