Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygeneditor.c
Go to the documentation of this file.
00001 /* 00002 * RichEdit - functions dealing with editor object 00003 * 00004 * Copyright 2004 by Krzysztof Foltman 00005 * Copyright 2005 by Cihan Altinay 00006 * Copyright 2005 by Phil Krylov 00007 * Copyright 2008 Eric Pouech 00008 * 00009 * This library is free software; you can redistribute it and/or 00010 * modify it under the terms of the GNU Lesser General Public 00011 * License as published by the Free Software Foundation; either 00012 * version 2.1 of the License, or (at your option) any later version. 00013 * 00014 * This library is distributed in the hope that it will be useful, 00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00017 * Lesser General Public License for more details. 00018 * 00019 * You should have received a copy of the GNU Lesser General Public 00020 * License along with this library; if not, write to the Free Software 00021 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00022 */ 00023 00024 /* 00025 API implementation status: 00026 00027 Messages (ANSI versions not done yet) 00028 + EM_AUTOURLDETECT 2.0 00029 + EM_CANPASTE 00030 + EM_CANREDO 2.0 00031 + EM_CANUNDO 00032 + EM_CHARFROMPOS 00033 - EM_DISPLAYBAND 00034 + EM_EMPTYUNDOBUFFER 00035 + EM_EXGETSEL 00036 + EM_EXLIMITTEXT 00037 + EM_EXLINEFROMCHAR 00038 + EM_EXSETSEL 00039 + EM_FINDTEXT (only FR_DOWN flag implemented) 00040 + EM_FINDTEXTEX (only FR_DOWN flag implemented) 00041 - EM_FINDWORDBREAK 00042 - EM_FMTLINES 00043 - EM_FORMATRANGE 00044 + EM_GETAUTOURLDETECT 2.0 00045 - EM_GETBIDIOPTIONS 3.0 00046 - EM_GETCHARFORMAT (partly done) 00047 - EM_GETEDITSTYLE 00048 + EM_GETEVENTMASK 00049 + EM_GETFIRSTVISIBLELINE (can be optimized if needed) 00050 - EM_GETIMECOLOR 1.0asian 00051 - EM_GETIMECOMPMODE 2.0 00052 - EM_GETIMEOPTIONS 1.0asian 00053 - EM_GETIMESTATUS 00054 - EM_GETLANGOPTIONS 2.0 00055 + EM_GETLIMITTEXT 00056 + EM_GETLINE 00057 + EM_GETLINECOUNT returns number of rows, not of paragraphs 00058 + EM_GETMODIFY 00059 + EM_GETOLEINTERFACE 00060 + EM_GETOPTIONS 00061 + EM_GETPARAFORMAT 00062 + EM_GETPASSWORDCHAR 2.0 00063 - EM_GETPUNCTUATION 1.0asian 00064 + EM_GETRECT 00065 - EM_GETREDONAME 2.0 00066 + EM_GETSEL 00067 + EM_GETSELTEXT (ANSI&Unicode) 00068 + EM_GETSCROLLPOS 3.0 00069 ! - EM_GETTHUMB 00070 + EM_GETTEXTEX 2.0 00071 + EM_GETTEXTLENGTHEX (GTL_PRECISE unimplemented) 00072 + EM_GETTEXTMODE 2.0 00073 ? + EM_GETTEXTRANGE (ANSI&Unicode) 00074 - EM_GETTYPOGRAPHYOPTIONS 3.0 00075 - EM_GETUNDONAME 00076 + EM_GETWORDBREAKPROC 00077 - EM_GETWORDBREAKPROCEX 00078 - EM_GETWORDWRAPMODE 1.0asian 00079 + EM_GETZOOM 3.0 00080 + EM_HIDESELECTION 00081 + EM_LIMITTEXT (Also called EM_SETLIMITTEXT) 00082 + EM_LINEFROMCHAR 00083 + EM_LINEINDEX 00084 + EM_LINELENGTH 00085 + EM_LINESCROLL 00086 - EM_PASTESPECIAL 00087 + EM_POSFROMCHAR 00088 + EM_REDO 2.0 00089 + EM_REQUESTRESIZE 00090 + EM_REPLACESEL (proper style?) ANSI&Unicode 00091 + EM_SCROLL 00092 + EM_SCROLLCARET 00093 - EM_SELECTIONTYPE 00094 - EM_SETBIDIOPTIONS 3.0 00095 + EM_SETBKGNDCOLOR 00096 + EM_SETCHARFORMAT (partly done, no ANSI) 00097 - EM_SETEDITSTYLE 00098 + EM_SETEVENTMASK (few notifications supported) 00099 - EM_SETFONTSIZE 00100 - EM_SETIMECOLOR 1.0asian 00101 - EM_SETIMEOPTIONS 1.0asian 00102 - EM_SETIMESTATUS 00103 - EM_SETLANGOPTIONS 2.0 00104 - EM_SETLIMITTEXT 00105 - EM_SETMARGINS 00106 + EM_SETMODIFY (not sure if implementation is correct) 00107 - EM_SETOLECALLBACK 00108 + EM_SETOPTIONS (partially implemented) 00109 - EM_SETPALETTE 2.0 00110 + EM_SETPARAFORMAT 00111 + EM_SETPASSWORDCHAR 2.0 00112 - EM_SETPUNCTUATION 1.0asian 00113 + EM_SETREADONLY no beep on modification attempt 00114 + EM_SETRECT 00115 + EM_SETRECTNP (EM_SETRECT without repainting) 00116 + EM_SETSEL 00117 + EM_SETSCROLLPOS 3.0 00118 - EM_SETTABSTOPS 3.0 00119 - EM_SETTARGETDEVICE (partial) 00120 + EM_SETTEXTEX 3.0 (proper style?) 00121 - EM_SETTEXTMODE 2.0 00122 - EM_SETTYPOGRAPHYOPTIONS 3.0 00123 + EM_SETUNDOLIMIT 2.0 00124 + EM_SETWORDBREAKPROC (used only for word movement at the moment) 00125 - EM_SETWORDBREAKPROCEX 00126 - EM_SETWORDWRAPMODE 1.0asian 00127 + EM_SETZOOM 3.0 00128 + EM_SHOWSCROLLBAR 2.0 00129 + EM_STOPGROUPTYPING 2.0 00130 + EM_STREAMIN 00131 + EM_STREAMOUT 00132 + EM_UNDO 00133 + WM_CHAR 00134 + WM_CLEAR 00135 + WM_COPY 00136 + WM_CUT 00137 + WM_GETDLGCODE (the current implementation is incomplete) 00138 + WM_GETTEXT (ANSI&Unicode) 00139 + WM_GETTEXTLENGTH (ANSI version sucks) 00140 + WM_HSCROLL 00141 + WM_PASTE 00142 + WM_SETFONT 00143 + WM_SETTEXT (resets undo stack !) (proper style?) ANSI&Unicode 00144 + WM_STYLECHANGING (seems to do nothing) 00145 + WM_STYLECHANGED (seems to do nothing) 00146 + WM_UNICHAR 00147 + WM_VSCROLL 00148 00149 Notifications 00150 00151 * EN_CHANGE (sent from the wrong place) 00152 - EN_CORRECTTEXT 00153 - EN_DROPFILES 00154 - EN_ERRSPACE 00155 - EN_HSCROLL 00156 - EN_IMECHANGE 00157 + EN_KILLFOCUS 00158 - EN_LINK 00159 - EN_MAXTEXT 00160 - EN_MSGFILTER 00161 - EN_OLEOPFAILED 00162 - EN_PROTECTED 00163 + EN_REQUESTRESIZE 00164 - EN_SAVECLIPBOARD 00165 + EN_SELCHANGE 00166 + EN_SETFOCUS 00167 - EN_STOPNOUNDO 00168 * EN_UPDATE (sent from the wrong place) 00169 - EN_VSCROLL 00170 00171 Styles 00172 00173 - ES_AUTOHSCROLL 00174 - ES_AUTOVSCROLL 00175 - ES_CENTER 00176 + ES_DISABLENOSCROLL (scrollbar is always visible) 00177 - ES_EX_NOCALLOLEINIT 00178 - ES_LEFT 00179 - ES_MULTILINE (currently single line controls aren't supported) 00180 - ES_NOIME 00181 - ES_READONLY (I'm not sure if beeping is the proper behaviour) 00182 - ES_RIGHT 00183 - ES_SAVESEL 00184 - ES_SELFIME 00185 - ES_SUNKEN 00186 - ES_VERTICAL 00187 - ES_WANTRETURN (don't know how to do WM_GETDLGCODE part) 00188 - WS_SETFONT 00189 + WS_HSCROLL 00190 + WS_VSCROLL 00191 */ 00192 00193 /* 00194 * RICHED20 TODO (incomplete): 00195 * 00196 * - messages/styles/notifications listed above 00197 * - add remaining CHARFORMAT/PARAFORMAT fields 00198 * - right/center align should strip spaces from the beginning 00199 * - pictures/OLE objects (not just smiling faces that lack API support ;-) ) 00200 * - COM interface (looks like a major pain in the TODO list) 00201 * - calculate heights of pictures (half-done) 00202 * - hysteresis during wrapping (related to scrollbars appearing/disappearing) 00203 * - find/replace 00204 * - how to implement EM_FORMATRANGE and EM_DISPLAYBAND ? (Mission Impossible) 00205 * - italic caret with italic fonts 00206 * - IME 00207 * - most notifications aren't sent at all (the most important ones are) 00208 * - when should EN_SELCHANGE be sent after text change ? (before/after EN_UPDATE?) 00209 * - WM_SETTEXT may use wrong style (but I'm 80% sure it's OK) 00210 * - EM_GETCHARFORMAT with SCF_SELECTION may not behave 100% like in original (but very close) 00211 * - full justification 00212 * - hyphenation 00213 * - tables 00214 * - ListBox & ComboBox not implemented 00215 * 00216 * Bugs that are probably fixed, but not so easy to verify: 00217 * - EN_UPDATE/EN_CHANGE are handled very incorrectly (should be OK now) 00218 * - undo for ME_JoinParagraphs doesn't store paragraph format ? (it does) 00219 * - check/fix artificial EOL logic (bCursorAtEnd, hardly logical) 00220 * - caret shouldn't be displayed when selection isn't empty 00221 * - check refcounting in style management functions (looks perfect now, but no bugs is suspicious) 00222 * - undo for setting default format (done, might be buggy) 00223 * - styles might be not released properly (looks like they work like charm, but who knows? 00224 * 00225 */ 00226 00227 #include "editor.h" 00228 #include "commdlg.h" 00229 #include "winreg.h" 00230 #define NO_SHLWAPI_STREAM 00231 #include "shlwapi.h" 00232 #include "rtf.h" 00233 #include "imm.h" 00234 #include "res.h" 00235 00236 #define STACK_SIZE_DEFAULT 100 00237 #define STACK_SIZE_MAX 1000 00238 00239 #define TEXT_LIMIT_DEFAULT 32767 00240 00241 WINE_DEFAULT_DEBUG_CHANNEL(richedit); 00242 00243 static BOOL ME_RegisterEditorClass(HINSTANCE); 00244 static BOOL ME_UpdateLinkAttribute(ME_TextEditor *editor, ME_Cursor *start, int nChars); 00245 00246 static const WCHAR REListBox20W[] = {'R','E','L','i','s','t','B','o','x','2','0','W', 0}; 00247 static const WCHAR REComboBox20W[] = {'R','E','C','o','m','b','o','B','o','x','2','0','W', 0}; 00248 static HCURSOR hLeft; 00249 00250 int me_debug = 0; 00251 HANDLE me_heap = NULL; 00252 00253 static BOOL ME_ListBoxRegistered = FALSE; 00254 static BOOL ME_ComboBoxRegistered = FALSE; 00255 00256 static inline int is_version_nt(void) 00257 { 00258 return !(GetVersion() & 0x80000000); 00259 } 00260 00261 static ME_TextBuffer *ME_MakeText(void) { 00262 00263 ME_TextBuffer *buf = ALLOC_OBJ(ME_TextBuffer); 00264 00265 ME_DisplayItem *p1 = ME_MakeDI(diTextStart); 00266 ME_DisplayItem *p2 = ME_MakeDI(diTextEnd); 00267 00268 p1->prev = NULL; 00269 p1->next = p2; 00270 p2->prev = p1; 00271 p2->next = NULL; 00272 p1->member.para.next_para = p2; 00273 p2->member.para.prev_para = p1; 00274 p2->member.para.nCharOfs = 0; 00275 00276 buf->pFirst = p1; 00277 buf->pLast = p2; 00278 buf->pCharStyle = NULL; 00279 00280 return buf; 00281 } 00282 00283 00284 static LRESULT ME_StreamInText(ME_TextEditor *editor, DWORD dwFormat, ME_InStream *stream, ME_Style *style) 00285 { 00286 WCHAR wszText[STREAMIN_BUFFER_SIZE+1]; 00287 WCHAR *pText; 00288 LRESULT total_bytes_read = 0; 00289 00290 TRACE("%08x %p\n", dwFormat, stream); 00291 00292 do { 00293 LONG nWideChars = 0; 00294 00295 if (!stream->dwSize) 00296 { 00297 ME_StreamInFill(stream); 00298 if (stream->editstream->dwError) 00299 break; 00300 if (!stream->dwSize) 00301 break; 00302 total_bytes_read += stream->dwSize; 00303 } 00304 00305 if (!(dwFormat & SF_UNICODE)) 00306 { 00307 /* FIXME? this is doomed to fail on true MBCS like UTF-8, luckily they're unlikely to be used as CP_ACP */ 00308 nWideChars = MultiByteToWideChar(CP_ACP, 0, stream->buffer, stream->dwSize, wszText, STREAMIN_BUFFER_SIZE); 00309 pText = wszText; 00310 } 00311 else 00312 { 00313 nWideChars = stream->dwSize >> 1; 00314 pText = (WCHAR *)stream->buffer; 00315 } 00316 00317 ME_InsertTextFromCursor(editor, 0, pText, nWideChars, style); 00318 if (stream->dwSize == 0) 00319 break; 00320 stream->dwSize = 0; 00321 } while(1); 00322 return total_bytes_read; 00323 } 00324 00325 static void ME_ApplyBorderProperties(RTF_Info *info, 00326 ME_BorderRect *borderRect, 00327 RTFBorder *borderDef) 00328 { 00329 int i, colorNum; 00330 ME_Border *pBorders[] = {&borderRect->top, 00331 &borderRect->left, 00332 &borderRect->bottom, 00333 &borderRect->right}; 00334 for (i = 0; i < 4; i++) 00335 { 00336 RTFColor *colorDef = info->colorList; 00337 pBorders[i]->width = borderDef[i].width; 00338 colorNum = borderDef[i].color; 00339 while (colorDef && colorDef->rtfCNum != colorNum) 00340 colorDef = colorDef->rtfNextColor; 00341 if (colorDef) 00342 pBorders[i]->colorRef = RGB( 00343 colorDef->rtfCRed >= 0 ? colorDef->rtfCRed : 0, 00344 colorDef->rtfCGreen >= 0 ? colorDef->rtfCGreen : 0, 00345 colorDef->rtfCBlue >= 0 ? colorDef->rtfCBlue : 0); 00346 else 00347 pBorders[i]->colorRef = RGB(0, 0, 0); 00348 } 00349 } 00350 00351 void ME_RTFCharAttrHook(RTF_Info *info) 00352 { 00353 CHARFORMAT2W fmt; 00354 fmt.cbSize = sizeof(fmt); 00355 fmt.dwMask = 0; 00356 fmt.dwEffects = 0; 00357 00358 switch(info->rtfMinor) 00359 { 00360 case rtfPlain: 00361 /* FIXME add more flags once they're implemented */ 00362 fmt.dwMask = CFM_BOLD | CFM_ITALIC | CFM_UNDERLINETYPE | CFM_STRIKEOUT | CFM_COLOR | CFM_BACKCOLOR | CFM_SIZE | CFM_WEIGHT; 00363 fmt.dwEffects = CFE_AUTOCOLOR | CFE_AUTOBACKCOLOR; 00364 fmt.yHeight = 12*20; /* 12pt */ 00365 fmt.wWeight = FW_NORMAL; 00366 fmt.bUnderlineType = CFU_UNDERLINENONE; 00367 break; 00368 case rtfBold: 00369 fmt.dwMask = CFM_BOLD | CFM_WEIGHT; 00370 fmt.dwEffects = info->rtfParam ? CFE_BOLD : 0; 00371 fmt.wWeight = info->rtfParam ? FW_BOLD : FW_NORMAL; 00372 break; 00373 case rtfItalic: 00374 fmt.dwMask = CFM_ITALIC; 00375 fmt.dwEffects = info->rtfParam ? fmt.dwMask : 0; 00376 break; 00377 case rtfUnderline: 00378 fmt.dwMask = CFM_UNDERLINETYPE; 00379 fmt.bUnderlineType = info->rtfParam ? CFU_CF1UNDERLINE : CFU_UNDERLINENONE; 00380 break; 00381 case rtfDotUnderline: 00382 fmt.dwMask = CFM_UNDERLINETYPE; 00383 fmt.bUnderlineType = info->rtfParam ? CFU_UNDERLINEDOTTED : CFU_UNDERLINENONE; 00384 break; 00385 case rtfDbUnderline: 00386 fmt.dwMask = CFM_UNDERLINETYPE; 00387 fmt.bUnderlineType = info->rtfParam ? CFU_UNDERLINEDOUBLE : CFU_UNDERLINENONE; 00388 break; 00389 case rtfWordUnderline: 00390 fmt.dwMask = CFM_UNDERLINETYPE; 00391 fmt.bUnderlineType = info->rtfParam ? CFU_UNDERLINEWORD : CFU_UNDERLINENONE; 00392 break; 00393 case rtfNoUnderline: 00394 fmt.dwMask = CFM_UNDERLINETYPE; 00395 fmt.bUnderlineType = CFU_UNDERLINENONE; 00396 break; 00397 case rtfStrikeThru: 00398 fmt.dwMask = CFM_STRIKEOUT; 00399 fmt.dwEffects = info->rtfParam ? fmt.dwMask : 0; 00400 break; 00401 case rtfSubScript: 00402 case rtfSuperScript: 00403 case rtfSubScrShrink: 00404 case rtfSuperScrShrink: 00405 case rtfNoSuperSub: 00406 fmt.dwMask = CFM_SUBSCRIPT|CFM_SUPERSCRIPT; 00407 if (info->rtfMinor == rtfSubScrShrink) fmt.dwEffects = CFE_SUBSCRIPT; 00408 if (info->rtfMinor == rtfSuperScrShrink) fmt.dwEffects = CFE_SUPERSCRIPT; 00409 if (info->rtfMinor == rtfNoSuperSub) fmt.dwEffects = 0; 00410 break; 00411 case rtfInvisible: 00412 fmt.dwMask = CFM_HIDDEN; 00413 fmt.dwEffects = info->rtfParam ? fmt.dwMask : 0; 00414 break; 00415 case rtfBackColor: 00416 fmt.dwMask = CFM_BACKCOLOR; 00417 fmt.dwEffects = 0; 00418 if (info->rtfParam == 0) 00419 fmt.dwEffects = CFE_AUTOBACKCOLOR; 00420 else if (info->rtfParam != rtfNoParam) 00421 { 00422 RTFColor *c = RTFGetColor(info, info->rtfParam); 00423 if (c && c->rtfCBlue >= 0) 00424 fmt.crTextColor = (c->rtfCBlue<<16)|(c->rtfCGreen<<8)|(c->rtfCRed); 00425 else 00426 fmt.dwEffects = CFE_AUTOBACKCOLOR; 00427 } 00428 break; 00429 case rtfForeColor: 00430 fmt.dwMask = CFM_COLOR; 00431 fmt.dwEffects = 0; 00432 if (info->rtfParam == 0) 00433 fmt.dwEffects = CFE_AUTOCOLOR; 00434 else if (info->rtfParam != rtfNoParam) 00435 { 00436 RTFColor *c = RTFGetColor(info, info->rtfParam); 00437 if (c && c->rtfCBlue >= 0) 00438 fmt.crTextColor = (c->rtfCBlue<<16)|(c->rtfCGreen<<8)|(c->rtfCRed); 00439 else { 00440 fmt.dwEffects = CFE_AUTOCOLOR; 00441 } 00442 } 00443 break; 00444 case rtfFontNum: 00445 if (info->rtfParam != rtfNoParam) 00446 { 00447 RTFFont *f = RTFGetFont(info, info->rtfParam); 00448 if (f) 00449 { 00450 MultiByteToWideChar(CP_ACP, 0, f->rtfFName, -1, fmt.szFaceName, sizeof(fmt.szFaceName)/sizeof(WCHAR)); 00451 fmt.szFaceName[sizeof(fmt.szFaceName)/sizeof(WCHAR)-1] = '\0'; 00452 fmt.bCharSet = f->rtfFCharSet; 00453 fmt.dwMask = CFM_FACE | CFM_CHARSET; 00454 fmt.bPitchAndFamily = f->rtfFPitch | (f->rtfFFamily << 4); 00455 } 00456 } 00457 break; 00458 case rtfFontSize: 00459 fmt.dwMask = CFM_SIZE; 00460 if (info->rtfParam != rtfNoParam) 00461 fmt.yHeight = info->rtfParam*10; 00462 break; 00463 } 00464 if (fmt.dwMask) { 00465 ME_Style *style2; 00466 RTFFlushOutputBuffer(info); 00467 /* FIXME too slow ? how come ? */ 00468 style2 = ME_ApplyStyle(info->style, &fmt); 00469 ME_ReleaseStyle(info->style); 00470 info->style = style2; 00471 info->styleChanged = TRUE; 00472 } 00473 } 00474 00475 /* FIXME this function doesn't get any information about context of the RTF tag, which is very bad, 00476 the same tags mean different things in different contexts */ 00477 void ME_RTFParAttrHook(RTF_Info *info) 00478 { 00479 PARAFORMAT2 fmt; 00480 fmt.cbSize = sizeof(fmt); 00481 fmt.dwMask = 0; 00482 00483 switch(info->rtfMinor) 00484 { 00485 case rtfParDef: /* restores default paragraph attributes */ 00486 if (!info->editor->bEmulateVersion10) /* v4.1 */ 00487 info->borderType = RTFBorderParaLeft; 00488 else /* v1.0 - 3.0 */ 00489 info->borderType = RTFBorderParaTop; 00490 fmt.dwMask = PFM_ALIGNMENT | PFM_BORDER | PFM_LINESPACING | PFM_TABSTOPS | 00491 PFM_OFFSET | PFM_RIGHTINDENT | PFM_SPACEAFTER | PFM_SPACEBEFORE | 00492 PFM_STARTINDENT; 00493 /* TODO: numbering, shading */ 00494 fmt.wAlignment = PFA_LEFT; 00495 fmt.cTabCount = 0; 00496 fmt.dxOffset = fmt.dxStartIndent = fmt.dxRightIndent = 0; 00497 fmt.wBorderWidth = fmt.wBorders = 0; 00498 fmt.wBorderSpace = 0; 00499 fmt.bLineSpacingRule = 0; 00500 fmt.dySpaceBefore = fmt.dySpaceAfter = 0; 00501 fmt.dyLineSpacing = 0; 00502 if (!info->editor->bEmulateVersion10) /* v4.1 */ 00503 { 00504 if (info->tableDef && info->tableDef->tableRowStart && 00505 info->tableDef->tableRowStart->member.para.nFlags & MEPF_ROWEND) 00506 { 00507 ME_Cursor cursor; 00508 ME_DisplayItem *para; 00509 /* We are just after a table row. */ 00510 RTFFlushOutputBuffer(info); 00511 cursor = info->editor->pCursors[0]; 00512 para = cursor.pPara; 00513 if (para == info->tableDef->tableRowStart->member.para.next_para 00514 && !cursor.nOffset && !cursor.pRun->member.run.nCharOfs) 00515 { 00516 /* Since the table row end, no text has been inserted, and the \intbl 00517 * control word has not be used. We can confirm that we are not in a 00518 * table anymore. 00519 */ 00520 info->tableDef->tableRowStart = NULL; 00521 info->canInheritInTbl = FALSE; 00522 } 00523 } 00524 } else { /* v1.0 - v3.0 */ 00525 fmt.dwMask |= PFM_TABLE; 00526 fmt.wEffects &= ~PFE_TABLE; 00527 } 00528 break; 00529 case rtfNestLevel: 00530 if (!info->editor->bEmulateVersion10) /* v4.1 */ 00531 { 00532 while (info->rtfParam > info->nestingLevel) { 00533 RTFTable *tableDef = ALLOC_OBJ(RTFTable); 00534 ZeroMemory(tableDef, sizeof(RTFTable)); 00535 tableDef->parent = info->tableDef; 00536 info->tableDef = tableDef; 00537 00538 RTFFlushOutputBuffer(info); 00539 if (tableDef->tableRowStart && 00540 tableDef->tableRowStart->member.para.nFlags & MEPF_ROWEND) 00541 { 00542 ME_DisplayItem *para = tableDef->tableRowStart; 00543 para = para->member.para.next_para; 00544 para = ME_InsertTableRowStartAtParagraph(info->editor, para); 00545 tableDef->tableRowStart = para; 00546 } else { 00547 ME_Cursor cursor; 00548 WCHAR endl = '\r'; 00549 cursor = info->editor->pCursors[0]; 00550 if (cursor.nOffset || cursor.pRun->member.run.nCharOfs) 00551 ME_InsertTextFromCursor(info->editor, 0, &endl, 1, info->style); 00552 tableDef->tableRowStart = ME_InsertTableRowStartFromCursor(info->editor); 00553 } 00554 00555 info->nestingLevel++; 00556 } 00557 info->canInheritInTbl = FALSE; 00558 } 00559 break; 00560 case rtfInTable: 00561 { 00562 if (!info->editor->bEmulateVersion10) /* v4.1 */ 00563 { 00564 if (info->nestingLevel < 1) 00565 { 00566 RTFTable *tableDef; 00567 if (!info->tableDef) 00568 { 00569 info->tableDef = ALLOC_OBJ(RTFTable); 00570 ZeroMemory(info->tableDef, sizeof(RTFTable)); 00571 } 00572 tableDef = info->tableDef; 00573 RTFFlushOutputBuffer(info); 00574 if (tableDef->tableRowStart && 00575 tableDef->tableRowStart->member.para.nFlags & MEPF_ROWEND) 00576 { 00577 ME_DisplayItem *para = tableDef->tableRowStart; 00578 para = para->member.para.next_para; 00579 para = ME_InsertTableRowStartAtParagraph(info->editor, para); 00580 tableDef->tableRowStart = para; 00581 } else { 00582 ME_Cursor cursor; 00583 WCHAR endl = '\r'; 00584 cursor = info->editor->pCursors[0]; 00585 if (cursor.nOffset || cursor.pRun->member.run.nCharOfs) 00586 ME_InsertTextFromCursor(info->editor, 0, &endl, 1, info->style); 00587 tableDef->tableRowStart = ME_InsertTableRowStartFromCursor(info->editor); 00588 } 00589 info->nestingLevel = 1; 00590 info->canInheritInTbl = TRUE; 00591 } 00592 return; 00593 } else { /* v1.0 - v3.0 */ 00594 fmt.dwMask |= PFM_TABLE; 00595 fmt.wEffects |= PFE_TABLE; 00596 } 00597 break; 00598 } 00599 case rtfFirstIndent: 00600 ME_GetSelectionParaFormat(info->editor, &fmt); 00601 fmt.dwMask = PFM_STARTINDENT | PFM_OFFSET; 00602 fmt.dxStartIndent += fmt.dxOffset + info->rtfParam; 00603 fmt.dxOffset = -info->rtfParam; 00604 break; 00605 case rtfLeftIndent: 00606 ME_GetSelectionParaFormat(info->editor, &fmt); 00607 fmt.dwMask = PFM_STARTINDENT; 00608 fmt.dxStartIndent = info->rtfParam - fmt.dxOffset; 00609 break; 00610 case rtfRightIndent: 00611 fmt.dwMask = PFM_RIGHTINDENT; 00612 fmt.dxRightIndent = info->rtfParam; 00613 break; 00614 case rtfQuadLeft: 00615 case rtfQuadJust: 00616 fmt.dwMask = PFM_ALIGNMENT; 00617 fmt.wAlignment = PFA_LEFT; 00618 break; 00619 case rtfQuadRight: 00620 fmt.dwMask = PFM_ALIGNMENT; 00621 fmt.wAlignment = PFA_RIGHT; 00622 break; 00623 case rtfQuadCenter: 00624 fmt.dwMask = PFM_ALIGNMENT; 00625 fmt.wAlignment = PFA_CENTER; 00626 break; 00627 case rtfTabPos: 00628 ME_GetSelectionParaFormat(info->editor, &fmt); 00629 if (!(fmt.dwMask & PFM_TABSTOPS)) 00630 { 00631 fmt.cTabCount = 0; 00632 } 00633 if (fmt.cTabCount < MAX_TAB_STOPS && info->rtfParam < 0x1000000) 00634 fmt.rgxTabs[fmt.cTabCount++] = info->rtfParam; 00635 fmt.dwMask = PFM_TABSTOPS; 00636 break; 00637 case rtfKeep: 00638 fmt.dwMask = PFM_KEEP; 00639 fmt.wEffects = PFE_KEEP; 00640 break; 00641 case rtfNoWidowControl: 00642 fmt.dwMask = PFM_NOWIDOWCONTROL; 00643 fmt.wEffects = PFE_NOWIDOWCONTROL; 00644 break; 00645 case rtfKeepNext: 00646 fmt.dwMask = PFM_KEEPNEXT; 00647 fmt.wEffects = PFE_KEEPNEXT; 00648 break; 00649 case rtfSpaceAfter: 00650 fmt.dwMask = PFM_SPACEAFTER; 00651 fmt.dySpaceAfter = info->rtfParam; 00652 break; 00653 case rtfSpaceBefore: 00654 fmt.dwMask = PFM_SPACEBEFORE; 00655 fmt.dySpaceBefore = info->rtfParam; 00656 break; 00657 case rtfSpaceBetween: 00658 fmt.dwMask = PFM_LINESPACING; 00659 if ((int)info->rtfParam > 0) 00660 { 00661 fmt.dyLineSpacing = info->rtfParam; 00662 fmt.bLineSpacingRule = 3; 00663 } 00664 else 00665 { 00666 fmt.dyLineSpacing = info->rtfParam; 00667 fmt.bLineSpacingRule = 4; 00668 } 00669 break; 00670 case rtfSpaceMultiply: 00671 fmt.dwMask = PFM_LINESPACING; 00672 fmt.dyLineSpacing = info->rtfParam * 20; 00673 fmt.bLineSpacingRule = 5; 00674 break; 00675 case rtfParBullet: 00676 fmt.dwMask = PFM_NUMBERING; 00677 fmt.wNumbering = PFN_BULLET; 00678 break; 00679 case rtfParSimple: 00680 fmt.dwMask = PFM_NUMBERING; 00681 fmt.wNumbering = 2; /* FIXME: MSDN says it's not used ?? */ 00682 break; 00683 case rtfParNumDecimal: 00684 fmt.dwMask = PFM_NUMBERING; 00685 fmt.wNumbering = 2; /* FIXME: MSDN says it's not used ?? */ 00686 break; 00687 case rtfParNumIndent: 00688 fmt.dwMask = PFM_NUMBERINGTAB; 00689 fmt.wNumberingTab = info->rtfParam; 00690 break; 00691 case rtfParNumStartAt: 00692 fmt.dwMask = PFM_NUMBERINGSTART; 00693 fmt.wNumberingStart = info->rtfParam; 00694 break; 00695 case rtfBorderLeft: 00696 info->borderType = RTFBorderParaLeft; 00697 ME_GetSelectionParaFormat(info->editor, &fmt); 00698 if (!(fmt.dwMask & PFM_BORDER)) 00699 { 00700 fmt.wBorderSpace = 0; 00701 fmt.wBorderWidth = 1; 00702 fmt.wBorders = 0; 00703 } 00704 fmt.wBorders |= 1; 00705 fmt.dwMask = PFM_BORDER; 00706 break; 00707 case rtfBorderRight: 00708 info->borderType = RTFBorderParaRight; 00709 ME_GetSelectionParaFormat(info->editor, &fmt); 00710 if (!(fmt.dwMask & PFM_BORDER)) 00711 { 00712 fmt.wBorderSpace = 0; 00713 fmt.wBorderWidth = 1; 00714 fmt.wBorders = 0; 00715 } 00716 fmt.wBorders |= 2; 00717 fmt.dwMask = PFM_BORDER; 00718 break; 00719 case rtfBorderTop: 00720 info->borderType = RTFBorderParaTop; 00721 ME_GetSelectionParaFormat(info->editor, &fmt); 00722 if (!(fmt.dwMask & PFM_BORDER)) 00723 { 00724 fmt.wBorderSpace = 0; 00725 fmt.wBorderWidth = 1; 00726 fmt.wBorders = 0; 00727 } 00728 fmt.wBorders |= 4; 00729 fmt.dwMask = PFM_BORDER; 00730 break; 00731 case rtfBorderBottom: 00732 info->borderType = RTFBorderParaBottom; 00733 ME_GetSelectionParaFormat(info->editor, &fmt); 00734 if (!(fmt.dwMask & PFM_BORDER)) 00735 { 00736 fmt.wBorderSpace = 0; 00737 fmt.wBorderWidth = 1; 00738 fmt.wBorders = 0; 00739 } 00740 fmt.wBorders |= 8; 00741 fmt.dwMask = PFM_BORDER; 00742 break; 00743 case rtfBorderSingle: 00744 ME_GetSelectionParaFormat(info->editor, &fmt); 00745 /* we assume that borders have been created before (RTF spec) */ 00746 fmt.wBorders &= ~0x700; 00747 fmt.wBorders |= 1 << 8; 00748 fmt.dwMask = PFM_BORDER; 00749 break; 00750 case rtfBorderThick: 00751 ME_GetSelectionParaFormat(info->editor, &fmt); 00752 /* we assume that borders have been created before (RTF spec) */ 00753 fmt.wBorders &= ~0x700; 00754 fmt.wBorders |= 2 << 8; 00755 fmt.dwMask = PFM_BORDER; 00756 break; 00757 case rtfBorderShadow: 00758 ME_GetSelectionParaFormat(info->editor, &fmt); 00759 /* we assume that borders have been created before (RTF spec) */ 00760 fmt.wBorders &= ~0x700; 00761 fmt.wBorders |= 10 << 8; 00762 fmt.dwMask = PFM_BORDER; 00763 break; 00764 case rtfBorderDouble: 00765 ME_GetSelectionParaFormat(info->editor, &fmt); 00766 /* we assume that borders have been created before (RTF spec) */ 00767 fmt.wBorders &= ~0x700; 00768 fmt.wBorders |= 7 << 8; 00769 fmt.dwMask = PFM_BORDER; 00770 break; 00771 case rtfBorderDot: 00772 ME_GetSelectionParaFormat(info->editor, &fmt); 00773 /* we assume that borders have been created before (RTF spec) */ 00774 fmt.wBorders &= ~0x700; 00775 fmt.wBorders |= 11 << 8; 00776 fmt.dwMask = PFM_BORDER; 00777 break; 00778 case rtfBorderWidth: 00779 { 00780 int borderSide = info->borderType & RTFBorderSideMask; 00781 RTFTable *tableDef = info->tableDef; 00782 ME_GetSelectionParaFormat(info->editor, &fmt); 00783 /* we assume that borders have been created before (RTF spec) */ 00784 fmt.wBorderWidth |= ((info->rtfParam / 15) & 7) << 8; 00785 if ((info->borderType & RTFBorderTypeMask) == RTFBorderTypeCell) 00786 { 00787 RTFBorder *border; 00788 if (!tableDef || tableDef->numCellsDefined >= MAX_TABLE_CELLS) 00789 break; 00790 border = &tableDef->cells[tableDef->numCellsDefined].border[borderSide]; 00791 border->width = info->rtfParam; 00792 break; 00793 } 00794 fmt.dwMask = PFM_BORDER; 00795 break; 00796 } 00797 case rtfBorderSpace: 00798 ME_GetSelectionParaFormat(info->editor, &fmt); 00799 /* we assume that borders have been created before (RTF spec) */ 00800 fmt.wBorderSpace = info->rtfParam; 00801 fmt.dwMask = PFM_BORDER; 00802 break; 00803 case rtfBorderColor: 00804 { 00805 RTFTable *tableDef = info->tableDef; 00806 int borderSide = info->borderType & RTFBorderSideMask; 00807 int borderType = info->borderType & RTFBorderTypeMask; 00808 switch(borderType) 00809 { 00810 case RTFBorderTypePara: 00811 if (!info->editor->bEmulateVersion10) /* v4.1 */ 00812 break; 00813 /* v1.0 - 3.0 treat paragraph and row borders the same. */ 00814 case RTFBorderTypeRow: 00815 if (tableDef) { 00816 tableDef->border[borderSide].color = info->rtfParam; 00817 } 00818 break; 00819 case RTFBorderTypeCell: 00820 if (tableDef && tableDef->numCellsDefined < MAX_TABLE_CELLS) { 00821 tableDef->cells[tableDef->numCellsDefined].border[borderSide].color = info->rtfParam; 00822 } 00823 break; 00824 } 00825 break; 00826 } 00827 } 00828 if (fmt.dwMask) { 00829 RTFFlushOutputBuffer(info); 00830 /* FIXME too slow ? how come ?*/ 00831 ME_SetSelectionParaFormat(info->editor, &fmt); 00832 } 00833 } 00834 00835 void ME_RTFTblAttrHook(RTF_Info *info) 00836 { 00837 switch (info->rtfMinor) 00838 { 00839 case rtfRowDef: 00840 { 00841 if (!info->editor->bEmulateVersion10) /* v4.1 */ 00842 info->borderType = 0; /* Not sure */ 00843 else /* v1.0 - 3.0 */ 00844 info->borderType = RTFBorderRowTop; 00845 if (!info->tableDef) { 00846 info->tableDef = ME_MakeTableDef(info->editor); 00847 } else { 00848 ME_InitTableDef(info->editor, info->tableDef); 00849 } 00850 break; 00851 } 00852 case rtfCellPos: 00853 { 00854 int cellNum; 00855 if (!info->tableDef) 00856 { 00857 info->tableDef = ME_MakeTableDef(info->editor); 00858 } 00859 cellNum = info->tableDef->numCellsDefined; 00860 if (cellNum >= MAX_TABLE_CELLS) 00861 break; 00862 info->tableDef->cells[cellNum].rightBoundary = info->rtfParam; 00863 if (cellNum < MAX_TAB_STOPS) { 00864 /* Tab stops were used to store cell positions before v4.1 but v4.1 00865 * still seems to set the tabstops without using them. */ 00866 ME_DisplayItem *para = info->editor->pCursors[0].pPara; 00867 PARAFORMAT2 *pFmt = para->member.para.pFmt; 00868 pFmt->rgxTabs[cellNum] &= ~0x00FFFFFF; 00869 pFmt->rgxTabs[cellNum] = 0x00FFFFFF & info->rtfParam; 00870 } 00871 info->tableDef->numCellsDefined++; 00872 break; 00873 } 00874 case rtfRowBordTop: 00875 info->borderType = RTFBorderRowTop; 00876 break; 00877 case rtfRowBordLeft: 00878 info->borderType = RTFBorderRowLeft; 00879 break; 00880 case rtfRowBordBottom: 00881 info->borderType = RTFBorderRowBottom; 00882 break; 00883 case rtfRowBordRight: 00884 info->borderType = RTFBorderRowRight; 00885 break; 00886 case rtfCellBordTop: 00887 info->borderType = RTFBorderCellTop; 00888 break; 00889 case rtfCellBordLeft: 00890 info->borderType = RTFBorderCellLeft; 00891 break; 00892 case rtfCellBordBottom: 00893 info->borderType = RTFBorderCellBottom; 00894 break; 00895 case rtfCellBordRight: 00896 info->borderType = RTFBorderCellRight; 00897 break; 00898 case rtfRowGapH: 00899 if (info->tableDef) 00900 info->tableDef->gapH = info->rtfParam; 00901 break; 00902 case rtfRowLeftEdge: 00903 if (info->tableDef) 00904 info->tableDef->leftEdge = info->rtfParam; 00905 break; 00906 } 00907 } 00908 00909 void ME_RTFSpecialCharHook(RTF_Info *info) 00910 { 00911 RTFTable *tableDef = info->tableDef; 00912 switch (info->rtfMinor) 00913 { 00914 case rtfNestCell: 00915 if (info->editor->bEmulateVersion10) /* v1.0 - v3.0 */ 00916 break; 00917 /* else fall through since v4.1 treats rtfNestCell and rtfCell the same */ 00918 case rtfCell: 00919 if (!tableDef) 00920 break; 00921 RTFFlushOutputBuffer(info); 00922 if (!info->editor->bEmulateVersion10) { /* v4.1 */ 00923 if (tableDef->tableRowStart) 00924 { 00925 if (!info->nestingLevel && 00926 tableDef->tableRowStart->member.para.nFlags & MEPF_ROWEND) 00927 { 00928 ME_DisplayItem *para = tableDef->tableRowStart; 00929 para = para->member.para.next_para; 00930 para = ME_InsertTableRowStartAtParagraph(info->editor, para); 00931 tableDef->tableRowStart = para; 00932 info->nestingLevel = 1; 00933 } 00934 ME_InsertTableCellFromCursor(info->editor); 00935 } 00936 } else { /* v1.0 - v3.0 */ 00937 ME_DisplayItem *para = info->editor->pCursors[0].pPara; 00938 PARAFORMAT2 *pFmt = para->member.para.pFmt; 00939 if (pFmt->dwMask & PFM_TABLE && pFmt->wEffects & PFE_TABLE && 00940 tableDef->numCellsInserted < tableDef->numCellsDefined) 00941 { 00942 WCHAR tab = '\t'; 00943 ME_InsertTextFromCursor(info->editor, 0, &tab, 1, info->style); 00944 tableDef->numCellsInserted++; 00945 } 00946 } 00947 break; 00948 case rtfNestRow: 00949 if (info->editor->bEmulateVersion10) /* v1.0 - v3.0 */ 00950 break; 00951 /* else fall through since v4.1 treats rtfNestRow and rtfRow the same */ 00952 case rtfRow: 00953 { 00954 ME_DisplayItem *para, *cell, *run; 00955 int i; 00956 00957 if (!tableDef) 00958 break; 00959 RTFFlushOutputBuffer(info); 00960 if (!info->editor->bEmulateVersion10) { /* v4.1 */ 00961 if (!tableDef->tableRowStart) 00962 break; 00963 if (!info->nestingLevel && 00964 tableDef->tableRowStart->member.para.nFlags & MEPF_ROWEND) 00965 { 00966 para = tableDef->tableRowStart; 00967 para = para->member.para.next_para; 00968 para = ME_InsertTableRowStartAtParagraph(info->editor, para); 00969 tableDef->tableRowStart = para; 00970 info->nestingLevel++; 00971 } 00972 para = tableDef->tableRowStart; 00973 cell = ME_FindItemFwd(para, diCell); 00974 assert(cell && !cell->member.cell.prev_cell); 00975 if (tableDef->numCellsDefined < 1) 00976 { 00977 /* 2000 twips appears to be the cell size that native richedit uses 00978 * when no cell sizes are specified. */ 00979 const int defaultCellSize = 2000; 00980 int nRightBoundary = defaultCellSize; 00981 cell->member.cell.nRightBoundary = nRightBoundary; 00982 while (cell->member.cell.next_cell) { 00983 cell = cell->member.cell.next_cell; 00984 nRightBoundary += defaultCellSize; 00985 cell->member.cell.nRightBoundary = nRightBoundary; 00986 } 00987 para = ME_InsertTableCellFromCursor(info->editor); 00988 cell = para->member.para.pCell; 00989 cell->member.cell.nRightBoundary = nRightBoundary; 00990 } else { 00991 for (i = 0; i < tableDef->numCellsDefined; i++) 00992 { 00993 RTFCell *cellDef = &tableDef->cells[i]; 00994 cell->member.cell.nRightBoundary = cellDef->rightBoundary; 00995 ME_ApplyBorderProperties(info, &cell->member.cell.border, 00996 cellDef->border); 00997 cell = cell->member.cell.next_cell; 00998 if (!cell) 00999 { 01000 para = ME_InsertTableCellFromCursor(info->editor); 01001 cell = para->member.para.pCell; 01002 } 01003 } 01004 /* Cell for table row delimiter is empty */ 01005 cell->member.cell.nRightBoundary = tableDef->cells[i-1].rightBoundary; 01006 } 01007 01008 run = ME_FindItemFwd(cell, diRun); 01009 if (info->editor->pCursors[0].pRun != run || 01010 info->editor->pCursors[0].nOffset) 01011 { 01012 int nOfs, nChars; 01013 /* Delete inserted cells that aren't defined. */ 01014 info->editor->pCursors[1].pRun = run; 01015 info->editor->pCursors[1].pPara = ME_GetParagraph(run); 01016 info->editor->pCursors[1].nOffset = 0; 01017 nOfs = ME_GetCursorOfs(&info->editor->pCursors[1]); 01018 nChars = ME_GetCursorOfs(&info->editor->pCursors[0]) - nOfs; 01019 ME_InternalDeleteText(info->editor, &info->editor->pCursors[1], 01020 nChars, TRUE); 01021 } 01022 01023 para = ME_InsertTableRowEndFromCursor(info->editor); 01024 para->member.para.pFmt->dxOffset = abs(info->tableDef->gapH); 01025 para->member.para.pFmt->dxStartIndent = info->tableDef->leftEdge; 01026 ME_ApplyBorderProperties(info, ¶->member.para.border, 01027 tableDef->border); 01028 info->nestingLevel--; 01029 if (!info->nestingLevel) 01030 { 01031 if (info->canInheritInTbl) { 01032 tableDef->tableRowStart = para; 01033 } else { 01034 while (info->tableDef) { 01035 tableDef = info->tableDef; 01036 info->tableDef = tableDef->parent; 01037 heap_free(tableDef); 01038 } 01039 } 01040 } else { 01041 info->tableDef = tableDef->parent; 01042 heap_free(tableDef); 01043 } 01044 } else { /* v1.0 - v3.0 */ 01045 WCHAR endl = '\r'; 01046 ME_DisplayItem *para = info->editor->pCursors[0].pPara; 01047 PARAFORMAT2 *pFmt = para->member.para.pFmt; 01048 pFmt->dxOffset = info->tableDef->gapH; 01049 pFmt->dxStartIndent = info->tableDef->leftEdge; 01050 01051 ME_ApplyBorderProperties(info, ¶->member.para.border, 01052 tableDef->border); 01053 while (tableDef->numCellsInserted < tableDef->numCellsDefined) 01054 { 01055 WCHAR tab = '\t'; 01056 ME_InsertTextFromCursor(info->editor, 0, &tab, 1, info->style); 01057 tableDef->numCellsInserted++; 01058 } 01059 pFmt->cTabCount = min(tableDef->numCellsDefined, MAX_TAB_STOPS); 01060 if (!tableDef->numCellsDefined) 01061 pFmt->wEffects &= ~PFE_TABLE; 01062 ME_InsertTextFromCursor(info->editor, 0, &endl, 1, info->style); 01063 tableDef->numCellsInserted = 0; 01064 } 01065 break; 01066 } 01067 case rtfTab: 01068 case rtfPar: 01069 if (info->editor->bEmulateVersion10) { /* v1.0 - 3.0 */ 01070 ME_DisplayItem *para; 01071 PARAFORMAT2 *pFmt; 01072 RTFFlushOutputBuffer(info); 01073 para = info->editor->pCursors[0].pPara; 01074 pFmt = para->member.para.pFmt; 01075 if (pFmt->dwMask & PFM_TABLE && pFmt->wEffects & PFE_TABLE) 01076 { 01077 /* rtfPar is treated like a space within a table. */ 01078 info->rtfClass = rtfText; 01079 info->rtfMajor = ' '; 01080 } 01081 else if (info->rtfMinor == rtfPar && tableDef) 01082 tableDef->numCellsInserted = 0; 01083 } 01084 break; 01085 } 01086 } 01087 01088 static BOOL ME_RTFInsertOleObject(RTF_Info *info, HENHMETAFILE hemf, HBITMAP hbmp, 01089 const SIZEL* sz) 01090 { 01091 LPOLEOBJECT lpObject = NULL; 01092 LPSTORAGE lpStorage = NULL; 01093 LPOLECLIENTSITE lpClientSite = NULL; 01094 LPDATAOBJECT lpDataObject = NULL; 01095 LPOLECACHE lpOleCache = NULL; 01096 STGMEDIUM stgm; 01097 FORMATETC fm; 01098 CLSID clsid; 01099 BOOL ret = FALSE; 01100 DWORD conn; 01101 01102 if (hemf) 01103 { 01104 stgm.tymed = TYMED_ENHMF; 01105 stgm.u.hEnhMetaFile = hemf; 01106 fm.cfFormat = CF_ENHMETAFILE; 01107 } 01108 else if (hbmp) 01109 { 01110 stgm.tymed = TYMED_GDI; 01111 stgm.u.hBitmap = hbmp; 01112 fm.cfFormat = CF_BITMAP; 01113 } 01114 stgm.pUnkForRelease = NULL; 01115 01116 fm.ptd = NULL; 01117 fm.dwAspect = DVASPECT_CONTENT; 01118 fm.lindex = -1; 01119 fm.tymed = stgm.tymed; 01120 01121 if (!info->lpRichEditOle) 01122 { 01123 CreateIRichEditOle(info->editor, (VOID**)&info->lpRichEditOle); 01124 } 01125 01126 if (OleCreateDefaultHandler(&CLSID_NULL, NULL, &IID_IOleObject, (void**)&lpObject) == S_OK && 01127 #if 0 01128 /* FIXME: enable it when rich-edit properly implements this method */ 01129 IRichEditOle_GetClientSite(info->lpRichEditOle, &lpClientSite) == S_OK && 01130 IOleObject_SetClientSite(lpObject, lpClientSite) == S_OK && 01131 #endif 01132 IOleObject_GetUserClassID(lpObject, &clsid) == S_OK && 01133 IOleObject_QueryInterface(lpObject, &IID_IOleCache, (void**)&lpOleCache) == S_OK && 01134 IOleCache_Cache(lpOleCache, &fm, 0, &conn) == S_OK && 01135 IOleObject_QueryInterface(lpObject, &IID_IDataObject, (void**)&lpDataObject) == S_OK && 01136 IDataObject_SetData(lpDataObject, &fm, &stgm, TRUE) == S_OK) 01137 { 01138 REOBJECT reobject; 01139 01140 reobject.cbStruct = sizeof(reobject); 01141 reobject.cp = REO_CP_SELECTION; 01142 reobject.clsid = clsid; 01143 reobject.poleobj = lpObject; 01144 reobject.pstg = lpStorage; 01145 reobject.polesite = lpClientSite; 01146 /* convert from twips to .01 mm */ 01147 reobject.sizel.cx = MulDiv(sz->cx, 254, 144); 01148 reobject.sizel.cy = MulDiv(sz->cy, 254, 144); 01149 reobject.dvaspect = DVASPECT_CONTENT; 01150 reobject.dwFlags = 0; /* FIXME */ 01151 reobject.dwUser = 0; 01152 01153 ME_InsertOLEFromCursor(info->editor, &reobject, 0); 01154 ret = TRUE; 01155 } 01156 01157 if (lpObject) IOleObject_Release(lpObject); 01158 if (lpClientSite) IOleClientSite_Release(lpClientSite); 01159 if (lpStorage) IStorage_Release(lpStorage); 01160 if (lpDataObject) IDataObject_Release(lpDataObject); 01161 if (lpOleCache) IOleCache_Release(lpOleCache); 01162 01163 return ret; 01164 } 01165 01166 static void ME_RTFReadPictGroup(RTF_Info *info) 01167 { 01168 SIZEL sz; 01169 BYTE* buffer = NULL; 01170 unsigned bufsz, bufidx; 01171 BOOL flip; 01172 BYTE val; 01173 METAFILEPICT mfp; 01174 HENHMETAFILE hemf; 01175 HBITMAP hbmp; 01176 enum gfxkind {gfx_unknown = 0, gfx_enhmetafile, gfx_metafile, gfx_dib} gfx = gfx_unknown; 01177 01178 RTFGetToken (info); 01179 if (info->rtfClass == rtfEOF) 01180 return; 01181 mfp.mm = MM_TEXT; 01182 /* fetch picture type */ 01183 if (RTFCheckMM (info, rtfPictAttr, rtfWinMetafile)) 01184 { 01185 mfp.mm = info->rtfParam; 01186 gfx = gfx_metafile; 01187 } 01188 else if (RTFCheckMM (info, rtfPictAttr, rtfDevIndBitmap)) 01189 { 01190 if (info->rtfParam != 0) FIXME("dibitmap should be 0 (%d)\n", info->rtfParam); 01191 gfx = gfx_dib; 01192 } 01193 else if (RTFCheckMM (info, rtfPictAttr, rtfEmfBlip)) 01194 { 01195 gfx = gfx_enhmetafile; 01196 } 01197 else 01198 { 01199 FIXME("%d %d\n", info->rtfMajor, info->rtfMinor); 01200 goto skip_group; 01201 } 01202 sz.cx = sz.cy = 0; 01203 /* fetch picture attributes */ 01204 for (;;) 01205 { 01206 RTFGetToken (info); 01207 if (info->rtfClass == rtfEOF) 01208 return; 01209 if (info->rtfClass == rtfText) 01210 break; 01211 if (!RTFCheckCM (info, rtfControl, rtfPictAttr)) 01212 { 01213 ERR("Expected picture attribute (%d %d)\n", 01214 info->rtfClass, info->rtfMajor); 01215 goto skip_group; 01216 } 01217 else if (RTFCheckMM (info, rtfPictAttr, rtfPicWid)) 01218 { 01219 if (gfx == gfx_metafile) mfp.xExt = info->rtfParam; 01220 } 01221 else if (RTFCheckMM (info, rtfPictAttr, rtfPicHt)) 01222 { 01223 if (gfx == gfx_metafile) mfp.yExt = info->rtfParam; 01224 } 01225 else if (RTFCheckMM (info, rtfPictAttr, rtfPicGoalWid)) 01226 sz.cx = info->rtfParam; 01227 else if (RTFCheckMM (info, rtfPictAttr, rtfPicGoalHt)) 01228 sz.cy = info->rtfParam; 01229 else 01230 FIXME("Non supported attribute: %d %d %d\n", info->rtfClass, info->rtfMajor, info->rtfMinor); 01231 } 01232 /* fetch picture data */ 01233 bufsz = 1024; 01234 bufidx = 0; 01235 buffer = HeapAlloc(GetProcessHeap(), 0, bufsz); 01236 val = info->rtfMajor; 01237 for (flip = TRUE;; flip = !flip) 01238 { 01239 RTFGetToken (info); 01240 if (info->rtfClass == rtfEOF) 01241 { 01242 HeapFree(GetProcessHeap(), 0, buffer); 01243 return; /* Warn ?? */ 01244 } 01245 if (RTFCheckCM(info, rtfGroup, rtfEndGroup)) 01246 break; 01247 if (info->rtfClass != rtfText) goto skip_group; 01248 if (flip) 01249 { 01250 if (bufidx >= bufsz && 01251 !(buffer = HeapReAlloc(GetProcessHeap(), 0, buffer, bufsz += 1024))) 01252 goto skip_group; 01253 buffer[bufidx++] = RTFCharToHex(val) * 16 + RTFCharToHex(info->rtfMajor); 01254 } 01255 else 01256 val = info->rtfMajor; 01257 } 01258 if (flip) FIXME("wrong hex string\n"); 01259 01260 switch (gfx) 01261 { 01262 case gfx_enhmetafile: 01263 if ((hemf = SetEnhMetaFileBits(bufidx, buffer))) 01264 ME_RTFInsertOleObject(info, hemf, NULL, &sz); 01265 break; 01266 case gfx_metafile: 01267 if ((hemf = SetWinMetaFileBits(bufidx, buffer, NULL, &mfp))) 01268 ME_RTFInsertOleObject(info, hemf, NULL, &sz); 01269 break; 01270 case gfx_dib: 01271 { 01272 BITMAPINFO* bi = (BITMAPINFO*)buffer; 01273 HDC hdc = GetDC(0); 01274 unsigned nc = bi->bmiHeader.biClrUsed; 01275 01276 /* not quite right, especially for bitfields type of compression */ 01277 if (!nc && bi->bmiHeader.biBitCount <= 8) 01278 nc = 1 << bi->bmiHeader.biBitCount; 01279 if ((hbmp = CreateDIBitmap(hdc, &bi->bmiHeader, 01280 CBM_INIT, (char*)(bi + 1) + nc * sizeof(RGBQUAD), 01281 bi, DIB_RGB_COLORS))) 01282 ME_RTFInsertOleObject(info, NULL, hbmp, &sz); 01283 ReleaseDC(0, hdc); 01284 } 01285 break; 01286 default: 01287 break; 01288 } 01289 HeapFree(GetProcessHeap(), 0, buffer); 01290 RTFRouteToken (info); /* feed "}" back to router */ 01291 return; 01292 skip_group: 01293 HeapFree(GetProcessHeap(), 0, buffer); 01294 RTFSkipGroup(info); 01295 RTFRouteToken(info); /* feed "}" back to router */ 01296 } 01297 01298 /* for now, lookup the \result part and use it, whatever the object */ 01299 static void ME_RTFReadObjectGroup(RTF_Info *info) 01300 { 01301 for (;;) 01302 { 01303 RTFGetToken (info); 01304 if (info->rtfClass == rtfEOF) 01305 return; 01306 if (RTFCheckCM(info, rtfGroup, rtfEndGroup)) 01307 break; 01308 if (RTFCheckCM(info, rtfGroup, rtfBeginGroup)) 01309 { 01310 RTFGetToken (info); 01311 if (info->rtfClass == rtfEOF) 01312 return; 01313 if (RTFCheckCMM(info, rtfControl, rtfDestination, rtfObjResult)) 01314 { 01315 int level = 1; 01316 01317 while (RTFGetToken (info) != rtfEOF) 01318 { 01319 if (info->rtfClass == rtfGroup) 01320 { 01321 if (info->rtfMajor == rtfBeginGroup) level++; 01322 else if (info->rtfMajor == rtfEndGroup && --level < 0) break; 01323 } 01324 RTFRouteToken(info); 01325 } 01326 } 01327 else RTFSkipGroup(info); 01328 continue; 01329 } 01330 if (!RTFCheckCM (info, rtfControl, rtfObjAttr)) 01331 { 01332 FIXME("Non supported attribute: %d %d %d\n", info->rtfClass, info->rtfMajor, info->rtfMinor); 01333 return; 01334 } 01335 } 01336 RTFRouteToken(info); /* feed "}" back to router */ 01337 } 01338 01339 static void ME_RTFReadHook(RTF_Info *info) 01340 { 01341 switch(info->rtfClass) 01342 { 01343 case rtfGroup: 01344 switch(info->rtfMajor) 01345 { 01346 case rtfBeginGroup: 01347 if (info->stackTop < maxStack) { 01348 info->stack[info->stackTop].style = info->style; 01349 ME_AddRefStyle(info->style); 01350 info->stack[info->stackTop].codePage = info->codePage; 01351 info->stack[info->stackTop].unicodeLength = info->unicodeLength; 01352 } 01353 info->stackTop++; 01354 info->styleChanged = FALSE; 01355 break; 01356 case rtfEndGroup: 01357 { 01358 RTFFlushOutputBuffer(info); 01359 info->stackTop--; 01360 if (info->stackTop <= 0) 01361 info->rtfClass = rtfEOF; 01362 if (info->stackTop < 0) 01363 return; 01364 01365 ME_ReleaseStyle(info->style); 01366 info->style = info->stack[info->stackTop].style; 01367 info->codePage = info->stack[info->stackTop].codePage; 01368 info->unicodeLength = info->stack[info->stackTop].unicodeLength; 01369 break; 01370 } 01371 } 01372 break; 01373 } 01374 } 01375 01376 void 01377 ME_StreamInFill(ME_InStream *stream) 01378 { 01379 stream->editstream->dwError = stream->editstream->pfnCallback(stream->editstream->dwCookie, 01380 (BYTE *)stream->buffer, 01381 sizeof(stream->buffer), 01382 (LONG *)&stream->dwSize); 01383 stream->dwUsed = 0; 01384 } 01385 01386 static LRESULT ME_StreamIn(ME_TextEditor *editor, DWORD format, EDITSTREAM *stream, BOOL stripLastCR) 01387 { 01388 RTF_Info parser; 01389 ME_Style *style; 01390 int from, to, nUndoMode; 01391 int nEventMask = editor->nEventMask; 01392 ME_InStream inStream; 01393 BOOL invalidRTF = FALSE; 01394 ME_Cursor *selStart, *selEnd; 01395 LRESULT num_read = 0; /* bytes read for SF_TEXT, non-control chars inserted for SF_RTF */ 01396 01397 TRACE("stream==%p editor==%p format==0x%X\n", stream, editor, format); 01398 editor->nEventMask = 0; 01399 01400 ME_GetSelectionOfs(editor, &from, &to); 01401 if (format & SFF_SELECTION && editor->mode & TM_RICHTEXT) 01402 { 01403 ME_GetSelection(editor, &selStart, &selEnd); 01404 style = ME_GetSelectionInsertStyle(editor); 01405 01406 ME_InternalDeleteText(editor, selStart, to - from, FALSE); 01407 01408 /* Don't insert text at the end of the table row */ 01409 if (!editor->bEmulateVersion10) { /* v4.1 */ 01410 ME_DisplayItem *para = editor->pCursors->pPara; 01411 if (para->member.para.nFlags & MEPF_ROWEND) 01412 { 01413 para = para->member.para.next_para; 01414 editor->pCursors[0].pPara = para; 01415 editor->pCursors[0].pRun = ME_FindItemFwd(para, diRun); 01416 editor->pCursors[0].nOffset = 0; 01417 } 01418 if (para->member.para.nFlags & MEPF_ROWSTART) 01419 { 01420 para = para->member.para.next_para; 01421 editor->pCursors[0].pPara = para; 01422 editor->pCursors[0].pRun = ME_FindItemFwd(para, diRun); 01423 editor->pCursors[0].nOffset = 0; 01424 } 01425 editor->pCursors[1] = editor->pCursors[0]; 01426 } else { /* v1.0 - 3.0 */ 01427 if (editor->pCursors[0].pRun->member.run.nFlags & MERF_ENDPARA && 01428 ME_IsInTable(editor->pCursors[0].pRun)) 01429 return 0; 01430 } 01431 } else { 01432 style = editor->pBuffer->pDefaultStyle; 01433 ME_AddRefStyle(style); 01434 ME_SetSelection(editor, 0, 0); 01435 ME_InternalDeleteText(editor, &editor->pCursors[1], 01436 ME_GetTextLength(editor), FALSE); 01437 from = to = 0; 01438 ME_ClearTempStyle(editor); 01439 ME_SetDefaultParaFormat(editor->pCursors[0].pPara->member.para.pFmt); 01440 } 01441 01442 01443 /* Back up undo mode to a local variable */ 01444 nUndoMode = editor->nUndoMode; 01445 01446 /* Only create an undo if SFF_SELECTION is set */ 01447 if (!(format & SFF_SELECTION)) 01448 editor->nUndoMode = umIgnore; 01449 01450 inStream.editstream = stream; 01451 inStream.editstream->dwError = 0; 01452 inStream.dwSize = 0; 01453 inStream.dwUsed = 0; 01454 01455 if (format & SF_RTF) 01456 { 01457 /* Check if it's really RTF, and if it is not, use plain text */ 01458 ME_StreamInFill(&inStream); 01459 if (!inStream.editstream->dwError) 01460 { 01461 if ((!editor->bEmulateVersion10 && strncmp(inStream.buffer, "{\\rtf", 5) && strncmp(inStream.buffer, "{\\urtf", 6)) 01462 || (editor->bEmulateVersion10 && *inStream.buffer != '{')) 01463 { 01464 invalidRTF = TRUE; 01465 inStream.editstream->dwError = -16; 01466 } 01467 } 01468 } 01469 01470 if (!invalidRTF && !inStream.editstream->dwError) 01471 { 01472 if (format & SF_RTF) { 01473 from = ME_GetCursorOfs(&editor->pCursors[0]); 01474 01475 /* setup the RTF parser */ 01476 memset(&parser, 0, sizeof parser); 01477 RTFSetEditStream(&parser, &inStream); 01478 parser.rtfFormat = format&(SF_TEXT|SF_RTF); 01479 parser.editor = editor; 01480 parser.style = style; 01481 WriterInit(&parser); 01482 RTFInit(&parser); 01483 RTFSetReadHook(&parser, ME_RTFReadHook); 01484 RTFSetDestinationCallback(&parser, rtfPict, ME_RTFReadPictGroup); 01485 RTFSetDestinationCallback(&parser, rtfObject, ME_RTFReadObjectGroup); 01486 if (!parser.editor->bEmulateVersion10) /* v4.1 */ 01487 { 01488 RTFSetDestinationCallback(&parser, rtfNoNestTables, RTFSkipGroup); 01489 RTFSetDestinationCallback(&parser, rtfNestTableProps, RTFReadGroup); 01490 } 01491 BeginFile(&parser); 01492 01493 /* do the parsing */ 01494 RTFRead(&parser); 01495 RTFFlushOutputBuffer(&parser); 01496 if (!editor->bEmulateVersion10) { /* v4.1 */ 01497 if (parser.tableDef && parser.tableDef->tableRowStart && 01498 (parser.nestingLevel > 0 || parser.canInheritInTbl)) 01499 { 01500 /* Delete any incomplete table row at the end of the rich text. */ 01501 int nOfs, nChars; 01502 ME_DisplayItem *para; 01503 01504 parser.rtfMinor = rtfRow; 01505 /* Complete the table row before deleting it. 01506 * By doing it this way we will have the current paragraph format set 01507 * properly to reflect that is not in the complete table, and undo items 01508 * will be added for this change to the current paragraph format. */ 01509 if (parser.nestingLevel > 0) 01510 { 01511 while (parser.nestingLevel > 1) 01512 ME_RTFSpecialCharHook(&parser); /* Decrements nestingLevel */ 01513 para = parser.tableDef->tableRowStart; 01514 ME_RTFSpecialCharHook(&parser); 01515 } else { 01516 para = parser.tableDef->tableRowStart; 01517 ME_RTFSpecialCharHook(&parser); 01518 assert(para->member.para.nFlags & MEPF_ROWEND); 01519 para = para->member.para.next_para; 01520 } 01521 01522 editor->pCursors[1].pPara = para; 01523 editor->pCursors[1].pRun = ME_FindItemFwd(para, diRun); 01524 editor->pCursors[1].nOffset = 0; 01525 nOfs = ME_GetCursorOfs(&editor->pCursors[1]); 01526 nChars = ME_GetCursorOfs(&editor->pCursors[0]) - nOfs; 01527 ME_InternalDeleteText(editor, &editor->pCursors[1], nChars, TRUE); 01528 if (parser.tableDef) 01529 parser.tableDef->tableRowStart = NULL; 01530 } 01531 } 01532 ME_CheckTablesForCorruption(editor); 01533 RTFDestroy(&parser); 01534 if (parser.lpRichEditOle) 01535 IRichEditOle_Release(parser.lpRichEditOle); 01536 01537 if (parser.stackTop > 0) 01538 { 01539 while (--parser.stackTop >= 0) 01540 { 01541 ME_ReleaseStyle(parser.style); 01542 parser.style = parser.stack[parser.stackTop].style; 01543 } 01544 if (!inStream.editstream->dwError) 01545 inStream.editstream->dwError = HRESULT_FROM_WIN32(ERROR_HANDLE_EOF); 01546 } 01547 01548 /* Remove last line break, as mandated by tests. This is not affected by 01549 CR/LF counters, since RTF streaming presents only \para tokens, which 01550 are converted according to the standard rules: \r for 2.0, \r\n for 1.0 01551 */ 01552 if (stripLastCR) { 01553 int newto; 01554 ME_GetSelection(editor, &selStart, &selEnd); 01555 newto = ME_GetCursorOfs(selEnd); 01556 if (newto > to + (editor->bEmulateVersion10 ? 1 : 0)) { 01557 WCHAR lastchar[3] = {'\0', '\0'}; 01558 int linebreakSize = editor->bEmulateVersion10 ? 2 : 1; 01559 ME_Cursor linebreakCursor = *selEnd; 01560 01561 ME_MoveCursorChars(editor, &linebreakCursor, -linebreakSize); 01562 ME_GetTextW(editor, lastchar, 2, &linebreakCursor, linebreakSize, 0); 01563 if (lastchar[0] == '\r' && (lastchar[1] == '\n' || lastchar[1] == '\0')) { 01564 ME_InternalDeleteText(editor, &linebreakCursor, linebreakSize, FALSE); 01565 } 01566 } 01567 } 01568 to = ME_GetCursorOfs(&editor->pCursors[0]); 01569 num_read = to - from; 01570 01571 style = parser.style; 01572 } 01573 else if (format & SF_TEXT) 01574 num_read = ME_StreamInText(editor, format, &inStream, style); 01575 else 01576 ERR("EM_STREAMIN without SF_TEXT or SF_RTF\n"); 01577 /* put the cursor at the top */ 01578 if (!(format & SFF_SELECTION)) 01579 ME_SetSelection(editor, 0, 0); 01580 } 01581 01582 /* Restore saved undo mode */ 01583 editor->nUndoMode = nUndoMode; 01584 01585 /* even if we didn't add an undo, we need to commit anything on the stack */ 01586 ME_CommitUndo(editor); 01587 01588 /* If SFF_SELECTION isn't set, delete any undos from before we started too */ 01589 if (!(format & SFF_SELECTION)) 01590 ME_EmptyUndoStack(editor); 01591 01592 ME_ReleaseStyle(style); 01593 editor->nEventMask = nEventMask; 01594 ME_UpdateRepaint(editor, FALSE); 01595 if (!(format & SFF_SELECTION)) { 01596 ME_ClearTempStyle(editor); 01597 } 01598 ITextHost_TxShowCaret(editor->texthost, FALSE); 01599 ME_MoveCaret(editor); 01600 ITextHost_TxShowCaret(editor->texthost, TRUE); 01601 ME_SendSelChange(editor); 01602 ME_SendRequestResize(editor, FALSE); 01603 01604 return num_read; 01605 } 01606 01607 01608 typedef struct tagME_RTFStringStreamStruct 01609 { 01610 char *string; 01611 int pos; 01612 int length; 01613 } ME_RTFStringStreamStruct; 01614 01615 static DWORD CALLBACK ME_ReadFromRTFString(DWORD_PTR dwCookie, LPBYTE lpBuff, LONG cb, LONG *pcb) 01616 { 01617 ME_RTFStringStreamStruct *pStruct = (ME_RTFStringStreamStruct *)dwCookie; 01618 int count; 01619 01620 count = min(cb, pStruct->length - pStruct->pos); 01621 memmove(lpBuff, pStruct->string + pStruct->pos, count); 01622 pStruct->pos += count; 01623 *pcb = count; 01624 return 0; 01625 } 01626 01627 static void 01628 ME_StreamInRTFString(ME_TextEditor *editor, BOOL selection, char *string) 01629 { 01630 EDITSTREAM es; 01631 ME_RTFStringStreamStruct data; 01632 01633 data.string = string; 01634 data.length = strlen(string); 01635 data.pos = 0; 01636 es.dwCookie = (DWORD_PTR)&data; 01637 es.pfnCallback = ME_ReadFromRTFString; 01638 ME_StreamIn(editor, SF_RTF | (selection ? SFF_SELECTION : 0), &es, FALSE); 01639 } 01640 01641 01642 static int 01643 ME_FindText(ME_TextEditor *editor, DWORD flags, const CHARRANGE *chrg, const WCHAR *text, CHARRANGE *chrgText) 01644 { 01645 const int nLen = lstrlenW(text); 01646 const int nTextLen = ME_GetTextLength(editor); 01647 int nMin, nMax; 01648 ME_Cursor cursor; 01649 WCHAR wLastChar = ' '; 01650 01651 TRACE("flags==0x%08x, chrg->cpMin==%d, chrg->cpMax==%d text==%s\n", 01652 flags, chrg->cpMin, chrg->cpMax, debugstr_w(text)); 01653 01654 if (flags & ~(FR_DOWN | FR_MATCHCASE | FR_WHOLEWORD)) 01655 FIXME("Flags 0x%08x not implemented\n", 01656 flags & ~(FR_DOWN | FR_MATCHCASE | FR_WHOLEWORD)); 01657 01658 nMin = chrg->cpMin; 01659 if (chrg->cpMax == -1) 01660 nMax = nTextLen; 01661 else 01662 nMax = chrg->cpMax > nTextLen ? nTextLen : chrg->cpMax; 01663 01664 /* In 1.0 emulation, if cpMax reaches end of text, add the FR_DOWN flag */ 01665 if (editor->bEmulateVersion10 && nMax == nTextLen) 01666 { 01667 flags |= FR_DOWN; 01668 } 01669 01670 /* In 1.0 emulation, cpMin must always be no greater than cpMax */ 01671 if (editor->bEmulateVersion10 && nMax < nMin) 01672 { 01673 if (chrgText) 01674 { 01675 chrgText->cpMin = -1; 01676 chrgText->cpMax = -1; 01677 } 01678 return -1; 01679 } 01680 01681 /* when searching up, if cpMin < cpMax, then instead of searching 01682 * on [cpMin,cpMax], we search on [0,cpMin], otherwise, search on 01683 * [cpMax, cpMin]. The exception is when cpMax is -1, in which 01684 * case, it is always bigger than cpMin. 01685 */ 01686 if (!editor->bEmulateVersion10 && !(flags & FR_DOWN)) 01687 { 01688 int nSwap = nMax; 01689 01690 nMax = nMin > nTextLen ? nTextLen : nMin; 01691 if (nMin < nSwap || chrg->cpMax == -1) 01692 nMin = 0; 01693 else 01694 nMin = nSwap; 01695 } 01696 01697 if (!nLen || nMin < 0 || nMax < 0 || nMax < nMin) 01698 { 01699 if (chrgText) 01700 chrgText->cpMin = chrgText->cpMax = -1; 01701 return -1; 01702 } 01703 01704 if (flags & FR_DOWN) /* Forward search */ 01705 { 01706 /* If possible, find the character before where the search starts */ 01707 if ((flags & FR_WHOLEWORD) && nMin) 01708 { 01709 ME_CursorFromCharOfs(editor, nMin - 1, &cursor); 01710 wLastChar = cursor.pRun->member.run.strText->szData[cursor.nOffset]; 01711 ME_MoveCursorChars(editor, &cursor, 1); 01712 } else { 01713 ME_CursorFromCharOfs(editor, nMin, &cursor); 01714 } 01715 01716 while (cursor.pRun && ME_GetCursorOfs(&cursor) + nLen <= nMax) 01717 { 01718 ME_DisplayItem *pCurItem = cursor.pRun; 01719 int nCurStart = cursor.nOffset; 01720 int nMatched = 0; 01721 01722 while (pCurItem && ME_CharCompare(pCurItem->member.run.strText->szData[nCurStart + nMatched], text[nMatched], (flags & FR_MATCHCASE))) 01723 { 01724 if ((flags & FR_WHOLEWORD) && isalnumW(wLastChar)) 01725 break; 01726 01727 nMatched++; 01728 if (nMatched == nLen) 01729 { 01730 ME_DisplayItem *pNextItem = pCurItem; 01731 int nNextStart = nCurStart; 01732 WCHAR wNextChar; 01733 01734 /* Check to see if next character is a whitespace */ 01735 if (flags & FR_WHOLEWORD) 01736 { 01737 if (nCurStart + nMatched == pCurItem->member.run.strText->nLen) 01738 { 01739 pNextItem = ME_FindItemFwd(pCurItem, diRun); 01740 nNextStart = -nMatched; 01741 } 01742 01743 if (pNextItem) 01744 wNextChar = pNextItem->member.run.strText->szData[nNextStart + nMatched]; 01745 else 01746 wNextChar = ' '; 01747 01748 if (isalnumW(wNextChar)) 01749 break; 01750 } 01751 01752 cursor.nOffset += cursor.pPara->member.para.nCharOfs + cursor.pRun->member.run.nCharOfs; 01753 if (chrgText) 01754 { 01755 chrgText->cpMin = cursor.nOffset; 01756 chrgText->cpMax = cursor.nOffset + nLen; 01757 } 01758 TRACE("found at %d-%d\n", cursor.nOffset, cursor.nOffset + nLen); 01759 return cursor.nOffset; 01760 } 01761 if (nCurStart + nMatched == pCurItem->member.run.strText->nLen) 01762 { 01763 pCurItem = ME_FindItemFwd(pCurItem, diRun); 01764 nCurStart = -nMatched; 01765 } 01766 } 01767 if (pCurItem) 01768 wLastChar = pCurItem->member.run.strText->szData[nCurStart + nMatched]; 01769 else 01770 wLastChar = ' '; 01771 01772 cursor.nOffset++; 01773 if (cursor.nOffset == cursor.pRun->member.run.strText->nLen) 01774 { 01775 ME_NextRun(&cursor.pPara, &cursor.pRun); 01776 cursor.nOffset = 0; 01777 } 01778 } 01779 } 01780 else /* Backward search */ 01781 { 01782 /* If possible, find the character after where the search ends */ 01783 if ((flags & FR_WHOLEWORD) && nMax < nTextLen - 1) 01784 { 01785 ME_CursorFromCharOfs(editor, nMax + 1, &cursor); 01786 wLastChar = cursor.pRun->member.run.strText->szData[cursor.nOffset]; 01787 ME_MoveCursorChars(editor, &cursor, -1); 01788 } else { 01789 ME_CursorFromCharOfs(editor, nMax, &cursor); 01790 } 01791 01792 while (cursor.pRun && ME_GetCursorOfs(&cursor) - nLen >= nMin) 01793 { 01794 ME_DisplayItem *pCurItem = cursor.pRun; 01795 ME_DisplayItem *pCurPara = cursor.pPara; 01796 int nCurEnd = cursor.nOffset; 01797 int nMatched = 0; 01798 01799 if (nCurEnd == 0) 01800 { 01801 ME_PrevRun(&pCurPara, &pCurItem); 01802 nCurEnd = pCurItem->member.run.strText->nLen + nMatched; 01803 } 01804 01805 while (pCurItem && ME_CharCompare(pCurItem->member.run.strText->szData[nCurEnd - nMatched - 1], text[nLen - nMatched - 1], (flags & FR_MATCHCASE))) 01806 { 01807 if ((flags & FR_WHOLEWORD) && isalnumW(wLastChar)) 01808 break; 01809 01810 nMatched++; 01811 if (nMatched == nLen) 01812 { 01813 ME_DisplayItem *pPrevItem = pCurItem; 01814 int nPrevEnd = nCurEnd; 01815 WCHAR wPrevChar; 01816 int nStart; 01817 01818 /* Check to see if previous character is a whitespace */ 01819 if (flags & FR_WHOLEWORD) 01820 { 01821 if (nPrevEnd - nMatched == 0) 01822 { 01823 pPrevItem = ME_FindItemBack(pCurItem, diRun); 01824 if (pPrevItem) 01825 nPrevEnd = pPrevItem->member.run.strText->nLen + nMatched; 01826 } 01827 01828 if (pPrevItem) 01829 wPrevChar = pPrevItem->member.run.strText->szData[nPrevEnd - nMatched - 1]; 01830 else 01831 wPrevChar = ' '; 01832 01833 if (isalnumW(wPrevChar)) 01834 break; 01835 } 01836 01837 nStart = pCurPara->member.para.nCharOfs 01838 + pCurItem->member.run.nCharOfs + nCurEnd - nMatched; 01839 if (chrgText) 01840 { 01841 chrgText->cpMin = nStart; 01842 chrgText->cpMax = nStart + nLen; 01843 } 01844 TRACE("found at %d-%d\n", nStart, nStart + nLen); 01845 return nStart; 01846 } 01847 if (nCurEnd - nMatched == 0) 01848 { 01849 ME_PrevRun(&pCurPara, &pCurItem); 01850 /* Don't care about pCurItem becoming NULL here; it's already taken 01851 * care of in the exterior loop condition */ 01852 nCurEnd = pCurItem->member.run.strText->nLen + nMatched; 01853 } 01854 } 01855 if (pCurItem) 01856 wLastChar = pCurItem->member.run.strText->szData[nCurEnd - nMatched - 1]; 01857 else 01858 wLastChar = ' '; 01859 01860 cursor.nOffset--; 01861 if (cursor.nOffset < 0) 01862 { 01863 ME_PrevRun(&cursor.pPara, &cursor.pRun); 01864 cursor.nOffset = cursor.pRun->member.run.strText->nLen; 01865 } 01866 } 01867 } 01868 TRACE("not found\n"); 01869 if (chrgText) 01870 chrgText->cpMin = chrgText->cpMax = -1; 01871 return -1; 01872 } 01873 01874 static int ME_GetTextEx(ME_TextEditor *editor, GETTEXTEX *ex, LPARAM pText) 01875 { 01876 int nChars; 01877 ME_Cursor start; 01878 01879 if (!ex->cb || !pText) return 0; 01880 01881 if (ex->flags & ~(GT_SELECTION | GT_USECRLF)) 01882 FIXME("GETTEXTEX flags 0x%08x not supported\n", ex->flags & ~(GT_SELECTION | GT_USECRLF)); 01883 01884 if (ex->flags & GT_SELECTION) 01885 { 01886 int from, to; 01887 int nStartCur = ME_GetSelectionOfs(editor, &from, &to); 01888 start = editor->pCursors[nStartCur]; 01889 nChars = to - from; 01890 } 01891 else 01892 { 01893 ME_SetCursorToStart(editor, &start); 01894 nChars = INT_MAX; 01895 } 01896 if (ex->codepage == 1200) 01897 { 01898 return ME_GetTextW(editor, (LPWSTR)pText, ex->cb / sizeof(WCHAR) - 1, 01899 &start, nChars, ex->flags & GT_USECRLF); 01900 } 01901 else 01902 { 01903 /* potentially each char may be a CR, why calculate the exact value with O(N) when 01904 we can just take a bigger buffer? :) 01905 The above assumption still holds with CR/LF counters, since CR->CRLF expansion 01906 occurs only in richedit 2.0 mode, in which line breaks have only one CR 01907 */ 01908 int crlfmul = (ex->flags & GT_USECRLF) ? 2 : 1; 01909 DWORD buflen; 01910 LPWSTR buffer; 01911 LRESULT rc; 01912 01913 buflen = min(crlfmul * nChars, ex->cb - 1); 01914 buffer = heap_alloc((buflen + 1) * sizeof(WCHAR)); 01915 01916 nChars = ME_GetTextW(editor, buffer, buflen, &start, nChars, ex->flags & GT_USECRLF); 01917 rc = WideCharToMultiByte(ex->codepage, 0, buffer, nChars + 1, 01918 (LPSTR)pText, ex->cb, ex->lpDefaultChar, ex->lpUsedDefChar); 01919 if (rc) rc--; /* do not count 0 terminator */ 01920 01921 heap_free(buffer); 01922 return rc; 01923 } 01924 } 01925 01926 static int ME_GetTextRange(ME_TextEditor *editor, WCHAR *strText, 01927 const ME_Cursor *start, int nLen, BOOL unicode) 01928 { 01929 if (!strText) return 0; 01930 if (unicode) { 01931 return ME_GetTextW(editor, strText, INT_MAX, start, nLen, 0); 01932 } else { 01933 int nChars; 01934 WCHAR *p = ALLOC_N_OBJ(WCHAR, nLen+1); 01935 if (!p) return 0; 01936 nChars = ME_GetTextW(editor, p, nLen, start, nLen, 0); 01937 WideCharToMultiByte(CP_ACP, 0, p, nChars+1, (char *)strText, 01938 nLen+1, NULL, NULL); 01939 FREE_OBJ(p); 01940 return nChars; 01941 } 01942 } 01943 01944 typedef struct tagME_GlobalDestStruct 01945 { 01946 HGLOBAL hData; 01947 int nLength; 01948 } ME_GlobalDestStruct; 01949 01950 static DWORD CALLBACK ME_ReadFromHGLOBALUnicode(DWORD_PTR dwCookie, LPBYTE lpBuff, LONG cb, LONG *pcb) 01951 { 01952 ME_GlobalDestStruct *pData = (ME_GlobalDestStruct *)dwCookie; 01953 int i; 01954 WORD *pSrc, *pDest; 01955 01956 cb = cb >> 1; 01957 pDest = (WORD *)lpBuff; 01958 pSrc = GlobalLock(pData->hData); 01959 for (i = 0; i<cb && pSrc[pData->nLength+i]; i++) { 01960 pDest[i] = pSrc[pData->nLength+i]; 01961 } 01962 pData->nLength += i; 01963 *pcb = 2*i; 01964 GlobalUnlock(pData->hData); 01965 return 0; 01966 } 01967 01968 static DWORD CALLBACK ME_ReadFromHGLOBALRTF(DWORD_PTR dwCookie, LPBYTE lpBuff, LONG cb, LONG *pcb) 01969 { 01970 ME_GlobalDestStruct *pData = (ME_GlobalDestStruct *)dwCookie; 01971 int i; 01972 BYTE *pSrc, *pDest; 01973 01974 pDest = lpBuff; 01975 pSrc = GlobalLock(pData->hData); 01976 for (i = 0; i<cb && pSrc[pData->nLength+i]; i++) { 01977 pDest[i] = pSrc[pData->nLength+i]; 01978 } 01979 pData->nLength += i; 01980 *pcb = i; 01981 GlobalUnlock(pData->hData); 01982 return 0; 01983 } 01984 01985 static BOOL ME_Paste(ME_TextEditor *editor) 01986 { 01987 DWORD dwFormat = 0; 01988 EDITSTREAM es; 01989 ME_GlobalDestStruct gds; 01990 UINT nRTFFormat = RegisterClipboardFormatA("Rich Text Format"); 01991 UINT cf = 0; 01992 01993 if (IsClipboardFormatAvailable(nRTFFormat)) 01994 cf = nRTFFormat, dwFormat = SF_RTF; 01995 else if (IsClipboardFormatAvailable(CF_UNICODETEXT)) 01996 cf = CF_UNICODETEXT, dwFormat = SF_TEXT|SF_UNICODE; 01997 else 01998 return FALSE; 01999 02000 if (!OpenClipboard(editor->hWnd)) 02001 return FALSE; 02002 gds.hData = GetClipboardData(cf); 02003 gds.nLength = 0; 02004 es.dwCookie = (DWORD_PTR)&gds; 02005 es.pfnCallback = dwFormat == SF_RTF ? ME_ReadFromHGLOBALRTF : ME_ReadFromHGLOBALUnicode; 02006 ME_StreamIn(editor, dwFormat|SFF_SELECTION, &es, FALSE); 02007 02008 CloseClipboard(); 02009 return TRUE; 02010 } 02011 02012 static BOOL ME_Copy(ME_TextEditor *editor, const ME_Cursor *start, int nChars) 02013 { 02014 LPDATAOBJECT dataObj = NULL; 02015 HRESULT hr = S_OK; 02016 02017 if (editor->cPasswordMask) 02018 return FALSE; /* Copying or Cutting masked text isn't allowed */ 02019 02020 if(editor->lpOleCallback) 02021 { 02022 CHARRANGE range; 02023 range.cpMin = ME_GetCursorOfs(start); 02024 range.cpMax = range.cpMin + nChars; 02025 hr = IRichEditOleCallback_GetClipboardData(editor->lpOleCallback, &range, RECO_COPY, &dataObj); 02026 } 02027 if(FAILED(hr) || !dataObj) 02028 hr = ME_GetDataObject(editor, start, nChars, &dataObj); 02029 if(SUCCEEDED(hr)) { 02030 hr = OleSetClipboard(dataObj); 02031 IDataObject_Release(dataObj); 02032 } 02033 return SUCCEEDED(hr) != 0; 02034 } 02035 02036 /* helper to send a msg filter notification */ 02037 static BOOL 02038 ME_FilterEvent(ME_TextEditor *editor, UINT msg, WPARAM* wParam, LPARAM* lParam) 02039 { 02040 MSGFILTER msgf; 02041 02042 if (!editor->hWnd || !editor->hwndParent) return FALSE; 02043 msgf.nmhdr.hwndFrom = editor->hWnd; 02044 msgf.nmhdr.idFrom = GetWindowLongW(editor->hWnd, GWLP_ID); 02045 msgf.nmhdr.code = EN_MSGFILTER; 02046 msgf.msg = msg; 02047 msgf.wParam = *wParam; 02048 msgf.lParam = *lParam; 02049 if (SendMessageW(editor->hwndParent, WM_NOTIFY, msgf.nmhdr.idFrom, (LPARAM)&msgf)) 02050 return FALSE; 02051 *wParam = msgf.wParam; 02052 *lParam = msgf.lParam; 02053 msgf.wParam = *wParam; 02054 02055 return TRUE; 02056 } 02057 02058 static void ME_UpdateSelectionLinkAttribute(ME_TextEditor *editor) 02059 { 02060 ME_DisplayItem *startPara, *endPara; 02061 ME_DisplayItem *prev_para; 02062 ME_Cursor *from, *to; 02063 ME_Cursor start; 02064 int nChars; 02065 02066 if (!editor->AutoURLDetect_bEnable) return; 02067 02068 ME_GetSelection(editor, &from, &to); 02069 02070 /* Find paragraph previous to the one that contains start cursor */ 02071 startPara = from->pPara; 02072 prev_para = startPara->member.para.prev_para; 02073 if (prev_para->type == diParagraph) startPara = prev_para; 02074 02075 /* Find paragraph that contains end cursor */ 02076 endPara = to->pPara->member.para.next_para; 02077 02078 start.pPara = startPara; 02079 start.pRun = ME_FindItemFwd(startPara, diRun); 02080 start.nOffset = 0; 02081 nChars = endPara->member.para.nCharOfs - startPara->member.para.nCharOfs; 02082 02083 ME_UpdateLinkAttribute(editor, &start, nChars); 02084 } 02085 02086 static BOOL 02087 ME_KeyDown(ME_TextEditor *editor, WORD nKey) 02088 { 02089 BOOL ctrl_is_down = GetKeyState(VK_CONTROL) & 0x8000; 02090 BOOL shift_is_down = GetKeyState(VK_SHIFT) & 0x8000; 02091 02092 if (editor->bMouseCaptured) 02093 return FALSE; 02094 if (nKey != VK_SHIFT && nKey != VK_CONTROL && nKey != VK_MENU) 02095 editor->nSelectionType = stPosition; 02096 02097 switch (nKey) 02098 { 02099 case VK_LEFT: 02100 case VK_RIGHT: 02101 case VK_HOME: 02102 case VK_END: 02103 editor->nUDArrowX = -1; 02104 /* fall through */ 02105 case VK_UP: 02106 case VK_DOWN: 02107 case VK_PRIOR: 02108 case VK_NEXT: 02109 ME_CommitUndo(editor); /* End coalesced undos for typed characters */ 02110 ME_ArrowKey(editor, nKey, shift_is_down, ctrl_is_down); 02111 return TRUE; 02112 case VK_BACK: 02113 case VK_DELETE: 02114 editor->nUDArrowX = -1; 02115 /* FIXME backspace and delete aren't the same, they act different wrt paragraph style of the merged paragraph */ 02116 if (editor->styleFlags & ES_READONLY) 02117 return FALSE; 02118 if (ME_IsSelection(editor)) 02119 { 02120 ME_DeleteSelection(editor); 02121 ME_CommitUndo(editor); 02122 } 02123 else if (nKey == VK_DELETE) 02124 { 02125 /* Delete stops group typing. 02126 * (See MSDN remarks on EM_STOPGROUPTYPING message) */ 02127 ME_DeleteTextAtCursor(editor, 1, 1); 02128 ME_CommitUndo(editor); 02129 } 02130 else if (ME_ArrowKey(editor, VK_LEFT, FALSE, FALSE)) 02131 { 02132 BOOL bDeletionSucceeded; 02133 /* Backspace can be grouped for a single undo */ 02134 ME_ContinueCoalescingTransaction(editor); 02135 bDeletionSucceeded = ME_DeleteTextAtCursor(editor, 1, 1); 02136 if (!bDeletionSucceeded && !editor->bEmulateVersion10) { /* v4.1 */ 02137 /* Deletion was prevented so the cursor is moved back to where it was. 02138 * (e.g. this happens when trying to delete cell boundaries) 02139 */ 02140 ME_ArrowKey(editor, VK_RIGHT, FALSE, FALSE); 02141 } 02142 ME_CommitCoalescingUndo(editor); 02143 } 02144 else 02145 return TRUE; 02146 ME_MoveCursorFromTableRowStartParagraph(editor); 02147 ME_UpdateSelectionLinkAttribute(editor); 02148 ME_UpdateRepaint(editor, FALSE); 02149 ME_SendRequestResize(editor, FALSE); 02150 return TRUE; 02151 case VK_RETURN: 02152 if (editor->bDialogMode) 02153 { 02154 if (ctrl_is_down) 02155 return TRUE; 02156 02157 if (!(editor->styleFlags & ES_WANTRETURN)) 02158 { 02159 if (editor->hwndParent) 02160 { 02161 DWORD dw; 02162 dw = SendMessageW(editor->hwndParent, DM_GETDEFID, 0, 0); 02163 if (HIWORD(dw) == DC_HASDEFID) 02164 { 02165 HWND hwDefCtrl = GetDlgItem(editor->hwndParent, LOWORD(dw)); 02166 if (hwDefCtrl) 02167 { 02168 SendMessageW(editor->hwndParent, WM_NEXTDLGCTL, (WPARAM)hwDefCtrl, TRUE); 02169 PostMessageW(hwDefCtrl, WM_KEYDOWN, VK_RETURN, 0); 02170 } 02171 } 02172 } 02173 return TRUE; 02174 } 02175 } 02176 02177 if (editor->styleFlags & ES_MULTILINE) 02178 { 02179 ME_Cursor cursor = editor->pCursors[0]; 02180 ME_DisplayItem *para = cursor.pPara; 02181 int from, to; 02182 const WCHAR endl = '\r'; 02183 const WCHAR endlv10[] = {'\r','\n'}; 02184 ME_Style *style; 02185 02186 if (editor->styleFlags & ES_READONLY) { 02187 MessageBeep(MB_ICONERROR); 02188 return TRUE; 02189 } 02190 02191 ME_GetSelectionOfs(editor, &from, &to); 02192 if (editor->nTextLimit > ME_GetTextLength(editor) - (to-from)) 02193 { 02194 if (!editor->bEmulateVersion10) { /* v4.1 */ 02195 if (para->member.para.nFlags & MEPF_ROWEND) { 02196 /* Add a new table row after this row. */ 02197 para = ME_AppendTableRow(editor, para); 02198 para = para->member.para.next_para; 02199 editor->pCursors[0].pPara = para; 02200 editor->pCursors[0].pRun = ME_FindItemFwd(para, diRun); 02201 editor->pCursors[0].nOffset = 0; 02202 editor->pCursors[1] = editor->pCursors[0]; 02203 ME_CommitUndo(editor); 02204 ME_CheckTablesForCorruption(editor); 02205 ME_UpdateRepaint(editor, FALSE); 02206 return TRUE; 02207 } 02208 else if (para == editor->pCursors[1].pPara && 02209 cursor.nOffset + cursor.pRun->member.run.nCharOfs == 0 && 02210 para->member.para.prev_para->member.para.nFlags & MEPF_ROWSTART && 02211 !para->member.para.prev_para->member.para.nCharOfs) 02212 { 02213 /* Insert a newline before the table. */ 02214 para = para->member.para.prev_para; 02215 para->member.para.nFlags &= ~MEPF_ROWSTART; 02216 editor->pCursors[0].pPara = para; 02217 editor->pCursors[0].pRun = ME_FindItemFwd(para, diRun); 02218 editor->pCursors[1] = editor->pCursors[0]; 02219 ME_InsertTextFromCursor(editor, 0, &endl, 1, 02220 editor->pCursors[0].pRun->member.run.style); 02221 para = editor->pBuffer->pFirst->member.para.next_para; 02222 ME_SetDefaultParaFormat(para->member.para.pFmt); 02223 para->member.para.nFlags = MEPF_REWRAP; 02224 editor->pCursors[0].pPara = para; 02225 editor->pCursors[0].pRun = ME_FindItemFwd(para, diRun); 02226 editor->pCursors[1] = editor->pCursors[0]; 02227 para->member.para.next_para->member.para.nFlags |= MEPF_ROWSTART; 02228 ME_CommitCoalescingUndo(editor); 02229 ME_CheckTablesForCorruption(editor); 02230 ME_UpdateRepaint(editor, FALSE); 02231 return TRUE; 02232 } 02233 } else { /* v1.0 - 3.0 */ 02234 ME_DisplayItem *para = cursor.pPara; 02235 if (ME_IsInTable(para)) 02236 { 02237 if (cursor.pRun->member.run.nFlags & MERF_ENDPARA) 02238 { 02239 if (from == to) { 02240 ME_ContinueCoalescingTransaction(editor); 02241 para = ME_AppendTableRow(editor, para); 02242 editor->pCursors[0].pPara = para; 02243 editor->pCursors[0].pRun = ME_FindItemFwd(para, diRun); 02244 editor->pCursors[0].nOffset = 0; 02245 editor->pCursors[1] = editor->pCursors[0]; 02246 ME_CommitCoalescingUndo(editor); 02247 ME_UpdateRepaint(editor, FALSE); 02248 return TRUE; 02249 } 02250 } else { 02251 ME_ContinueCoalescingTransaction(editor); 02252 if (cursor.pRun->member.run.nCharOfs + cursor.nOffset == 0 && 02253 !ME_IsInTable(para->member.para.prev_para)) 02254 { 02255 /* Insert newline before table */ 02256 cursor.pRun = ME_FindItemBack(para, diRun); 02257 if (cursor.pRun) { 02258 editor->pCursors[0].pRun = cursor.pRun; 02259 editor->pCursors[0].pPara = para->member.para.prev_para; 02260 } 02261 editor->pCursors[0].nOffset = 0; 02262 editor->pCursors[1] = editor->pCursors[0]; 02263 ME_InsertTextFromCursor(editor, 0, &endl, 1, 02264 editor->pCursors[0].pRun->member.run.style); 02265 } else { 02266 editor->pCursors[1] = editor->pCursors[0]; 02267 para = ME_AppendTableRow(editor, para); 02268 editor->pCursors[0].pPara = para; 02269 editor->pCursors[0].pRun = ME_FindItemFwd(para, diRun); 02270 editor->pCursors[0].nOffset = 0; 02271 editor->pCursors[1] = editor->pCursors[0]; 02272 } 02273 ME_CommitCoalescingUndo(editor); 02274 ME_UpdateRepaint(editor, FALSE); 02275 return TRUE; 02276 } 02277 } 02278 } 02279 02280 style = ME_GetInsertStyle(editor, 0); 02281 ME_SaveTempStyle(editor); 02282 ME_ContinueCoalescingTransaction(editor); 02283 if (shift_is_down) 02284 ME_InsertEndRowFromCursor(editor, 0); 02285 else 02286 if (!editor->bEmulateVersion10) 02287 ME_InsertTextFromCursor(editor, 0, &endl, 1, style); 02288 else 02289 ME_InsertTextFromCursor(editor, 0, endlv10, 2, style); 02290 ME_ReleaseStyle(style); 02291 ME_CommitCoalescingUndo(editor); 02292 SetCursor(NULL); 02293 02294 ME_UpdateSelectionLinkAttribute(editor); 02295 ME_UpdateRepaint(editor, FALSE); 02296 } 02297 return TRUE; 02298 } 02299 break; 02300 case VK_ESCAPE: 02301 if (editor->bDialogMode && editor->hwndParent) 02302 PostMessageW(editor->hwndParent, WM_CLOSE, 0, 0); 02303 return TRUE; 02304 case VK_TAB: 02305 if (editor->bDialogMode && editor->hwndParent) 02306 SendMessageW(editor->hwndParent, WM_NEXTDLGCTL, shift_is_down, 0); 02307 return TRUE; 02308 case 'A': 02309 if (ctrl_is_down) 02310 { 02311 ME_SetSelection(editor, 0, -1); 02312 return TRUE; 02313 } 02314 break; 02315 case 'V': 02316 if (ctrl_is_down) 02317 return ME_Paste(editor); 02318 break; 02319 case 'C': 02320 case 'X': 02321 if (ctrl_is_down) 02322 { 02323 BOOL result; 02324 int nOfs, nChars; 02325 int nStartCur = ME_GetSelectionOfs(editor, &nOfs, &nChars); 02326 ME_Cursor *selStart = &editor->pCursors[nStartCur]; 02327 02328 nChars -= nOfs; 02329 result = ME_Copy(editor, selStart, nChars); 02330 if (result && nKey == 'X') 02331 { 02332 ME_InternalDeleteText(editor, selStart, nChars, FALSE); 02333 ME_CommitUndo(editor); 02334 ME_UpdateRepaint(editor, TRUE); 02335 } 02336 return result; 02337 } 02338 break; 02339 case 'Z': 02340 if (ctrl_is_down) 02341 { 02342 ME_Undo(editor); 02343 return TRUE; 02344 } 02345 break; 02346 case 'Y': 02347 if (ctrl_is_down) 02348 { 02349 ME_Redo(editor); 02350 return TRUE; 02351 } 02352 break; 02353 02354 default: 02355 if (nKey != VK_SHIFT && nKey != VK_CONTROL && nKey && nKey != VK_MENU) 02356 editor->nUDArrowX = -1; 02357 if (ctrl_is_down) 02358 { 02359 if (nKey == 'W') 02360 { 02361 CHARFORMAT2W chf; 02362 char buf[2048]; 02363 chf.cbSize = sizeof(chf); 02364 02365 ME_GetSelectionCharFormat(editor, &chf); 02366 ME_DumpStyleToBuf(&chf, buf); 02367 MessageBoxA(NULL, buf, "Style dump", MB_OK); 02368 } 02369 if (nKey == 'Q') 02370 { 02371 ME_CheckCharOffsets(editor); 02372 } 02373 } 02374 } 02375 return FALSE; 02376 } 02377 02378 static LRESULT ME_Char(ME_TextEditor *editor, WPARAM charCode, 02379 LPARAM flags, BOOL unicode) 02380 { 02381 WCHAR wstr; 02382 02383 if (editor->bMouseCaptured) 02384 return 0; 02385 02386 if (unicode) 02387 wstr = (WCHAR)charCode; 02388 else 02389 { 02390 CHAR charA = charCode; 02391 MultiByteToWideChar(CP_ACP, 0, &charA, 1, &wstr, 1); 02392 } 02393 02394 if (editor->styleFlags & ES_READONLY) { 02395 MessageBeep(MB_ICONERROR); 02396 return 0; /* FIXME really 0 ? */ 02397 } 02398 02399 if ((unsigned)wstr >= ' ' || wstr == '\t') 02400 { 02401 ME_Cursor cursor = editor->pCursors[0]; 02402 ME_DisplayItem *para = cursor.pPara; 02403 int from, to; 02404 BOOL ctrl_is_down = GetKeyState(VK_CONTROL) & 0x8000; 02405 ME_GetSelectionOfs(editor, &from, &to); 02406 if (wstr == '\t' && 02407 /* v4.1 allows tabs to be inserted with ctrl key down */ 02408 !(ctrl_is_down && !editor->bEmulateVersion10)) 02409 { 02410 ME_DisplayItem *para; 02411 BOOL bSelectedRow = FALSE; 02412 02413 para = cursor.pPara; 02414 if (ME_IsSelection(editor) && 02415 cursor.pRun->member.run.nCharOfs + cursor.nOffset == 0 && 02416 to == ME_GetCursorOfs(&editor->pCursors[0]) && 02417 para->member.para.prev_para->type == diParagraph) 02418 { 02419 para = para->member.para.prev_para; 02420 bSelectedRow = TRUE; 02421 } 02422 if (ME_IsInTable(para)) 02423 { 02424 ME_TabPressedInTable(editor, bSelectedRow); 02425 ME_CommitUndo(editor); 02426 return 0; 02427 } 02428 } else if (!editor->bEmulateVersion10) { /* v4.1 */ 02429 if (para->member.para.nFlags & MEPF_ROWEND) { 02430 if (from == to) { 02431 para = para->member.para.next_para; 02432 if (para->member.para.nFlags & MEPF_ROWSTART) 02433 para = para->member.para.next_para; 02434 editor->pCursors[0].pPara = para; 02435 editor->pCursors[0].pRun = ME_FindItemFwd(para, diRun); 02436 editor->pCursors[0].nOffset = 0; 02437 editor->pCursors[1] = editor->pCursors[0]; 02438 } 02439 } 02440 } else { /* v1.0 - 3.0 */ 02441 if (ME_IsInTable(cursor.pRun) && 02442 cursor.pRun->member.run.nFlags & MERF_ENDPARA && 02443 from == to) 02444 { 02445 /* Text should not be inserted at the end of the table. */ 02446 MessageBeep(-1); 02447 return 0; 02448 } 02449 } 02450 /* FIXME maybe it would make sense to call EM_REPLACESEL instead ? */ 02451 /* WM_CHAR is restricted to nTextLimit */ 02452 if(editor->nTextLimit > ME_GetTextLength(editor) - (to-from)) 02453 { 02454 ME_Style *style = ME_GetInsertStyle(editor, 0); 02455 ME_SaveTempStyle(editor); 02456 ME_ContinueCoalescingTransaction(editor); 02457 ME_InsertTextFromCursor(editor, 0, &wstr, 1, style); 02458 ME_ReleaseStyle(style); 02459 ME_CommitCoalescingUndo(editor); 02460 ITextHost_TxSetCursor(editor->texthost, NULL, FALSE); 02461 } 02462 02463 ME_UpdateSelectionLinkAttribute(editor); 02464 ME_UpdateRepaint(editor, FALSE); 02465 } 02466 return 0; 02467 } 02468 02469 /* Process the message and calculate the new click count. 02470 * 02471 * returns: The click count if it is mouse down event, else returns 0. */ 02472 static int ME_CalculateClickCount(ME_TextEditor *editor, UINT msg, WPARAM wParam, 02473 LPARAM lParam) 02474 { 02475 static int clickNum = 0; 02476 if (msg < WM_MOUSEFIRST || msg > WM_MOUSELAST) 02477 return 0; 02478 02479 if ((msg == WM_LBUTTONDBLCLK) || 02480 (msg == WM_RBUTTONDBLCLK) || 02481 (msg == WM_MBUTTONDBLCLK) || 02482 (msg == WM_XBUTTONDBLCLK)) 02483 { 02484 msg -= (WM_LBUTTONDBLCLK - WM_LBUTTONDOWN); 02485 } 02486 02487 if ((msg == WM_LBUTTONDOWN) || 02488 (msg == WM_RBUTTONDOWN) || 02489 (msg == WM_MBUTTONDOWN) || 02490 (msg == WM_XBUTTONDOWN)) 02491 { 02492 static MSG prevClickMsg; 02493 MSG clickMsg; 02494 /* Compare the editor instead of the hwnd so that the this 02495 * can still be done for windowless richedit controls. */ 02496 clickMsg.hwnd = (HWND)editor; 02497 clickMsg.message = msg; 02498 clickMsg.wParam = wParam; 02499 clickMsg.lParam = lParam; 02500 clickMsg.time = GetMessageTime(); 02501 clickMsg.pt.x = (short)LOWORD(lParam); 02502 clickMsg.pt.y = (short)HIWORD(lParam); 02503 if ((clickNum != 0) && 02504 (clickMsg.message == prevClickMsg.message) && 02505 (clickMsg.hwnd == prevClickMsg.hwnd) && 02506 (clickMsg.wParam == prevClickMsg.wParam) && 02507 (clickMsg.time - prevClickMsg.time < GetDoubleClickTime()) && 02508 (abs(clickMsg.pt.x - prevClickMsg.pt.x) < GetSystemMetrics(SM_CXDOUBLECLK)/2) && 02509 (abs(clickMsg.pt.y - prevClickMsg.pt.y) < GetSystemMetrics(SM_CYDOUBLECLK)/2)) 02510 { 02511 clickNum++; 02512 } else { 02513 clickNum = 1; 02514 } 02515 prevClickMsg = clickMsg; 02516 } else { 02517 return 0; 02518 } 02519 return clickNum; 02520 } 02521 02522 static BOOL ME_SetCursor(ME_TextEditor *editor) 02523 { 02524 ME_Cursor cursor; 02525 POINT pt; 02526 BOOL isExact; 02527 SCROLLBARINFO sbi; 02528 DWORD messagePos = GetMessagePos(); 02529 pt.x = (short)LOWORD(messagePos); 02530 pt.y = (short)HIWORD(messagePos); 02531 02532 if (editor->hWnd) 02533 { 02534 sbi.cbSize = sizeof(sbi); 02535 GetScrollBarInfo(editor->hWnd, OBJID_HSCROLL, &sbi); 02536 if (!(sbi.rgstate[0] & (STATE_SYSTEM_INVISIBLE|STATE_SYSTEM_OFFSCREEN)) && 02537 PtInRect(&sbi.rcScrollBar, pt)) 02538 { 02539 ITextHost_TxSetCursor(editor->texthost, 02540 LoadCursorW(NULL, (WCHAR*)IDC_ARROW), FALSE); 02541 return TRUE; 02542 } 02543 sbi.cbSize = sizeof(sbi); 02544 GetScrollBarInfo(editor->hWnd, OBJID_VSCROLL, &sbi); 02545 if (!(sbi.rgstate[0] & (STATE_SYSTEM_INVISIBLE|STATE_SYSTEM_OFFSCREEN)) && 02546 PtInRect(&sbi.rcScrollBar, pt)) 02547 { 02548 ITextHost_TxSetCursor(editor->texthost, 02549 LoadCursorW(NULL, (WCHAR*)IDC_ARROW), FALSE); 02550 return TRUE; 02551 } 02552 } 02553 ITextHost_TxScreenToClient(editor->texthost, &pt); 02554 02555 if (editor->nSelectionType == stLine && editor->bMouseCaptured) { 02556 ITextHost_TxSetCursor(editor->texthost, hLeft, FALSE); 02557 return TRUE; 02558 } 02559 if (!editor->bEmulateVersion10 /* v4.1 */ && 02560 pt.y < editor->rcFormat.top && 02561 pt.x < editor->rcFormat.left) 02562 { 02563 ITextHost_TxSetCursor(editor->texthost, hLeft, FALSE); 02564 return TRUE; 02565 } 02566 if (pt.y < editor->rcFormat.top || pt.y > editor->rcFormat.bottom) 02567 { 02568 if (editor->bEmulateVersion10) /* v1.0 - 3.0 */ 02569 ITextHost_TxSetCursor(editor->texthost, 02570 LoadCursorW(NULL, (WCHAR*)IDC_ARROW), FALSE); 02571 else /* v4.1 */ 02572 ITextHost_TxSetCursor(editor->texthost, 02573 LoadCursorW(NULL, (WCHAR*)IDC_IBEAM), TRUE); 02574 return TRUE; 02575 } 02576 if (pt.x < editor->rcFormat.left) 02577 { 02578 ITextHost_TxSetCursor(editor->texthost, hLeft, FALSE); 02579 return TRUE; 02580 } 02581 ME_CharFromPos(editor, pt.x, pt.y, &cursor, &isExact); 02582 if (isExact) 02583 { 02584 ME_Run *run; 02585 02586 run = &cursor.pRun->member.run; 02587 if (run->style->fmt.dwMask & CFM_LINK && 02588 run->style->fmt.dwEffects & CFE_LINK) 02589 { 02590 ITextHost_TxSetCursor(editor->texthost, 02591 LoadCursorW(NULL, (WCHAR*)IDC_HAND), 02592 FALSE); 02593 return TRUE; 02594 } 02595 02596 if (ME_IsSelection(editor)) 02597 { 02598 int selStart, selEnd; 02599 int offset = ME_GetCursorOfs(&cursor); 02600 02601 ME_GetSelectionOfs(editor, &selStart, &selEnd); 02602 if (selStart <= offset && selEnd >= offset) { 02603 ITextHost_TxSetCursor(editor->texthost, 02604 LoadCursorW(NULL, (WCHAR*)IDC_ARROW), 02605 FALSE); 02606 return TRUE; 02607 } 02608 } 02609 } 02610 ITextHost_TxSetCursor(editor->texthost, 02611 LoadCursorW(NULL, (WCHAR*)IDC_IBEAM), TRUE); 02612 return TRUE; 02613 } 02614 02615 static void ME_SetDefaultFormatRect(ME_TextEditor *editor) 02616 { 02617 ITextHost_TxGetClientRect(editor->texthost, &editor->rcFormat); 02618 editor->rcFormat.top += editor->exStyleFlags & WS_EX_CLIENTEDGE ? 1 : 0; 02619 editor->rcFormat.left += 1 + editor->selofs; 02620 editor->rcFormat.right -= 1; 02621 } 02622 02623 static BOOL ME_ShowContextMenu(ME_TextEditor *editor, int x, int y) 02624 { 02625 CHARRANGE selrange; 02626 HMENU menu; 02627 int seltype = 0; 02628 if(!editor->lpOleCallback || !editor->hWnd) 02629 return FALSE; 02630 ME_GetSelectionOfs(editor, &selrange.cpMin, &selrange.cpMax); 02631 if(selrange.cpMin == selrange.cpMax) 02632 seltype |= SEL_EMPTY; 02633 else 02634 { 02635 /* FIXME: Handle objects */ 02636 seltype |= SEL_TEXT; 02637 if(selrange.cpMax-selrange.cpMin > 1) 02638 seltype |= SEL_MULTICHAR; 02639 } 02640 if(SUCCEEDED(IRichEditOleCallback_GetContextMenu(editor->lpOleCallback, seltype, NULL, &selrange, &menu))) 02641 { 02642 TrackPopupMenu(menu, TPM_LEFTALIGN | TPM_RIGHTBUTTON, x, y, 0, editor->hwndParent, NULL); 02643 DestroyMenu(menu); 02644 } 02645 return TRUE; 02646 } 02647 02648 ME_TextEditor *ME_MakeEditor(ITextHost *texthost, BOOL bEmulateVersion10) 02649 { 02650 ME_TextEditor *ed = ALLOC_OBJ(ME_TextEditor); 02651 int i; 02652 DWORD props; 02653 LONG selbarwidth; 02654 02655 ed->hWnd = NULL; 02656 ed->hwndParent = NULL; 02657 ed->sizeWindow.cx = ed->sizeWindow.cy = 0; 02658 ed->texthost = texthost; 02659 ed->bEmulateVersion10 = bEmulateVersion10; 02660 ed->styleFlags = 0; 02661 ITextHost_TxGetPropertyBits(texthost, 02662 (TXTBIT_RICHTEXT|TXTBIT_MULTILINE| 02663 TXTBIT_READONLY|TXTBIT_USEPASSWORD| 02664 TXTBIT_HIDESELECTION|TXTBIT_SAVESELECTION| 02665 TXTBIT_AUTOWORDSEL|TXTBIT_VERTICAL| 02666 TXTBIT_WORDWRAP|TXTBIT_DISABLEDRAG), 02667 &props); 02668 ITextHost_TxGetScrollBars(texthost, &ed->styleFlags); 02669 ed->styleFlags &= (WS_VSCROLL|WS_HSCROLL|ES_AUTOVSCROLL| 02670 ES_AUTOHSCROLL|ES_DISABLENOSCROLL); 02671 ed->pBuffer = ME_MakeText(); 02672 ed->nZoomNumerator = ed->nZoomDenominator = 0; 02673 ed->nAvailWidth = 0; /* wrap to client area */ 02674 ME_MakeFirstParagraph(ed); 02675 /* The four cursors are for: 02676 * 0 - The position where the caret is shown 02677 * 1 - The anchored end of the selection (for normal selection) 02678 * 2 & 3 - The anchored start and end respectively for word, line, 02679 * or paragraph selection. 02680 */ 02681 ed->nCursors = 4; 02682 ed->pCursors = ALLOC_N_OBJ(ME_Cursor, ed->nCursors); 02683 ME_SetCursorToStart(ed, &ed->pCursors[0]); 02684 ed->pCursors[1] = ed->pCursors[0]; 02685 ed->pCursors[2] = ed->pCursors[0]; 02686 ed->pCursors[3] = ed->pCursors[1]; 02687 ed->nLastTotalLength = ed->nTotalLength = 0; 02688 ed->nLastTotalWidth = ed->nTotalWidth = 0; 02689 ed->nUDArrowX = -1; 02690 ed->nSequence = 0; 02691 ed->rgbBackColor = -1; 02692 ed->hbrBackground = GetSysColorBrush(COLOR_WINDOW); 02693 ed->bCaretAtEnd = FALSE; 02694 ed->nEventMask = 0; 02695 ed->nModifyStep = 0; 02696 ed->nTextLimit = TEXT_LIMIT_DEFAULT; 02697 ed->pUndoStack = ed->pRedoStack = ed->pUndoStackBottom = NULL; 02698 ed->nUndoStackSize = 0; 02699 ed->nUndoLimit = STACK_SIZE_DEFAULT; 02700 ed->nUndoMode = umAddToUndo; 02701 ed->nParagraphs = 1; 02702 ed->nLastSelStart = ed->nLastSelEnd = 0; 02703 ed->pLastSelStartPara = ed->pLastSelEndPara = ed->pCursors[0].pPara; 02704 ed->bHideSelection = FALSE; 02705 ed->pfnWordBreak = NULL; 02706 ed->lpOleCallback = NULL; 02707 ed->mode = TM_MULTILEVELUNDO | TM_MULTICODEPAGE; 02708 ed->mode |= (props & TXTBIT_RICHTEXT) ? TM_RICHTEXT : TM_PLAINTEXT; 02709 ed->AutoURLDetect_bEnable = FALSE; 02710 ed->bHaveFocus = FALSE; 02711 ed->bDialogMode = FALSE; 02712 ed->bMouseCaptured = FALSE; 02713 for (i=0; i<HFONT_CACHE_SIZE; i++) 02714 { 02715 ed->pFontCache[i].nRefs = 0; 02716 ed->pFontCache[i].nAge = 0; 02717 ed->pFontCache[i].hFont = NULL; 02718 } 02719 02720 ME_CheckCharOffsets(ed); 02721 ed->bDefaultFormatRect = TRUE; 02722 ITextHost_TxGetSelectionBarWidth(ed->texthost, &selbarwidth); 02723 if (selbarwidth) { 02724 /* FIXME: Convert selbarwidth from HIMETRIC to pixels */ 02725 ed->selofs = SELECTIONBAR_WIDTH; 02726 ed->styleFlags |= ES_SELECTIONBAR; 02727 } else { 02728 ed->selofs = 0; 02729 } 02730 ed->nSelectionType = stPosition; 02731 02732 ed->cPasswordMask = 0; 02733 if (props & TXTBIT_USEPASSWORD) 02734 ITextHost_TxGetPasswordChar(texthost, &ed->cPasswordMask); 02735 02736 if (props & TXTBIT_AUTOWORDSEL) 02737 ed->styleFlags |= ECO_AUTOWORDSELECTION; 02738 if (props & TXTBIT_MULTILINE) { 02739 ed->styleFlags |= ES_MULTILINE; 02740 ed->bWordWrap = (props & TXTBIT_WORDWRAP) != 0; 02741 } else { 02742 ed->bWordWrap = FALSE; 02743 } 02744 if (props & TXTBIT_READONLY) 02745 ed->styleFlags |= ES_READONLY; 02746 if (!(props & TXTBIT_HIDESELECTION)) 02747 ed->styleFlags |= ES_NOHIDESEL; 02748 if (props & TXTBIT_SAVESELECTION) 02749 ed->styleFlags |= ES_SAVESEL; 02750 if (props & TXTBIT_VERTICAL) 02751 ed->styleFlags |= ES_VERTICAL; 02752 if (props & TXTBIT_DISABLEDRAG) 02753 ed->styleFlags |= ES_NOOLEDRAGDROP; 02754 02755 ed->notified_cr.cpMin = ed->notified_cr.cpMax = 0; 02756 02757 /* Default scrollbar information */ 02758 ed->vert_si.cbSize = sizeof(SCROLLINFO); 02759 ed->vert_si.nMin = 0; 02760 ed->vert_si.nMax = 0; 02761 ed->vert_si.nPage = 0; 02762 ed->vert_si.nPos = 0; 02763 02764 ed->horz_si.cbSize = sizeof(SCROLLINFO); 02765 ed->horz_si.nMin = 0; 02766 ed->horz_si.nMax = 0; 02767 ed->horz_si.nPage = 0; 02768 ed->horz_si.nPos = 0; 02769 02770 OleInitialize(NULL); 02771 02772 return ed; 02773 } 02774 02775 static void ME_DestroyEditor(ME_TextEditor *editor) 02776 { 02777 ME_DisplayItem *pFirst = editor->pBuffer->pFirst; 02778 ME_DisplayItem *p = pFirst, *pNext = NULL; 02779 int i; 02780 02781 ME_ClearTempStyle(editor); 02782 ME_EmptyUndoStack(editor); 02783 while(p) { 02784 pNext = p->next; 02785 ME_DestroyDisplayItem(p); 02786 p = pNext; 02787 } 02788 ME_ReleaseStyle(editor->pBuffer->pDefaultStyle); 02789 for (i=0; i<HFONT_CACHE_SIZE; i++) 02790 { 02791 if (editor->pFontCache[i].hFont) 02792 DeleteObject(editor->pFontCache[i].hFont); 02793 } 02794 if (editor->rgbBackColor != -1) 02795 DeleteObject(editor->hbrBackground); 02796 if(editor->lpOleCallback) 02797 IUnknown_Release(editor->lpOleCallback); 02798 IUnknown_Release(editor->texthost); 02799 OleUninitialize(); 02800 02801 FREE_OBJ(editor->pBuffer); 02802 FREE_OBJ(editor->pCursors); 02803 02804 FREE_OBJ(editor); 02805 } 02806 02807 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) 02808 { 02809 TRACE("\n"); 02810 switch (fdwReason) 02811 { 02812 case DLL_PROCESS_ATTACH: 02813 DisableThreadLibraryCalls(hinstDLL); 02814 me_heap = HeapCreate (0, 0x10000, 0); 02815 if (!ME_RegisterEditorClass(hinstDLL)) return FALSE; 02816 hLeft = LoadCursorW(hinstDLL, MAKEINTRESOURCEW(OCR_REVERSE)); 02817 LookupInit(); 02818 break; 02819 02820 case DLL_PROCESS_DETACH: 02821 UnregisterClassW(RICHEDIT_CLASS20W, 0); 02822 UnregisterClassW(MSFTEDIT_CLASS, 0); 02823 UnregisterClassA(RICHEDIT_CLASS20A, 0); 02824 UnregisterClassA("RichEdit50A", 0); 02825 if (ME_ListBoxRegistered) 02826 UnregisterClassW(REListBox20W, 0); 02827 if (ME_ComboBoxRegistered) 02828 UnregisterClassW(REComboBox20W, 0); 02829 LookupCleanup(); 02830 HeapDestroy (me_heap); 02831 me_heap = NULL; 02832 break; 02833 } 02834 return TRUE; 02835 } 02836 02837 02838 static const char * const edit_messages[] = { 02839 "EM_GETSEL", 02840 "EM_SETSEL", 02841 "EM_GETRECT", 02842 "EM_SETRECT", 02843 "EM_SETRECTNP", 02844 "EM_SCROLL", 02845 "EM_LINESCROLL", 02846 "EM_SCROLLCARET", 02847 "EM_GETMODIFY", 02848 "EM_SETMODIFY", 02849 "EM_GETLINECOUNT", 02850 "EM_LINEINDEX", 02851 "EM_SETHANDLE", 02852 "EM_GETHANDLE", 02853 "EM_GETTHUMB", 02854 "EM_UNKNOWN_BF", 02855 "EM_UNKNOWN_C0", 02856 "EM_LINELENGTH", 02857 "EM_REPLACESEL", 02858 "EM_UNKNOWN_C3", 02859 "EM_GETLINE", 02860 "EM_LIMITTEXT", 02861 "EM_CANUNDO", 02862 "EM_UNDO", 02863 "EM_FMTLINES", 02864 "EM_LINEFROMCHAR", 02865 "EM_UNKNOWN_CA", 02866 "EM_SETTABSTOPS", 02867 "EM_SETPASSWORDCHAR", 02868 "EM_EMPTYUNDOBUFFER", 02869 "EM_GETFIRSTVISIBLELINE", 02870 "EM_SETREADONLY", 02871 "EM_SETWORDBREAKPROC", 02872 "EM_GETWORDBREAKPROC", 02873 "EM_GETPASSWORDCHAR", 02874 "EM_SETMARGINS", 02875 "EM_GETMARGINS", 02876 "EM_GETLIMITTEXT", 02877 "EM_POSFROMCHAR", 02878 "EM_CHARFROMPOS", 02879 "EM_SETIMESTATUS", 02880 "EM_GETIMESTATUS" 02881 }; 02882 02883 static const char * const richedit_messages[] = { 02884 "EM_CANPASTE", 02885 "EM_DISPLAYBAND", 02886 "EM_EXGETSEL", 02887 "EM_EXLIMITTEXT", 02888 "EM_EXLINEFROMCHAR", 02889 "EM_EXSETSEL", 02890 "EM_FINDTEXT", 02891 "EM_FORMATRANGE", 02892 "EM_GETCHARFORMAT", 02893 "EM_GETEVENTMASK", 02894 "EM_GETOLEINTERFACE", 02895 "EM_GETPARAFORMAT", 02896 "EM_GETSELTEXT", 02897 "EM_HIDESELECTION", 02898 "EM_PASTESPECIAL", 02899 "EM_REQUESTRESIZE", 02900 "EM_SELECTIONTYPE", 02901 "EM_SETBKGNDCOLOR", 02902 "EM_SETCHARFORMAT", 02903 "EM_SETEVENTMASK", 02904 "EM_SETOLECALLBACK", 02905 "EM_SETPARAFORMAT", 02906 "EM_SETTARGETDEVICE", 02907 "EM_STREAMIN", 02908 "EM_STREAMOUT", 02909 "EM_GETTEXTRANGE", 02910 "EM_FINDWORDBREAK", 02911 "EM_SETOPTIONS", 02912 "EM_GETOPTIONS", 02913 "EM_FINDTEXTEX", 02914 "EM_GETWORDBREAKPROCEX", 02915 "EM_SETWORDBREAKPROCEX", 02916 "EM_SETUNDOLIMIT", 02917 "EM_UNKNOWN_USER_83", 02918 "EM_REDO", 02919 "EM_CANREDO", 02920 "EM_GETUNDONAME", 02921 "EM_GETREDONAME", 02922 "EM_STOPGROUPTYPING", 02923 "EM_SETTEXTMODE", 02924 "EM_GETTEXTMODE", 02925 "EM_AUTOURLDETECT", 02926 "EM_GETAUTOURLDETECT", 02927 "EM_SETPALETTE", 02928 "EM_GETTEXTEX", 02929 "EM_GETTEXTLENGTHEX", 02930 "EM_SHOWSCROLLBAR", 02931 "EM_SETTEXTEX", 02932 "EM_UNKNOWN_USER_98", 02933 "EM_UNKNOWN_USER_99", 02934 "EM_SETPUNCTUATION", 02935 "EM_GETPUNCTUATION", 02936 "EM_SETWORDWRAPMODE", 02937 "EM_GETWORDWRAPMODE", 02938 "EM_SETIMECOLOR", 02939 "EM_GETIMECOLOR", 02940 "EM_SETIMEOPTIONS", 02941 "EM_GETIMEOPTIONS", 02942 "EM_CONVPOSITION", 02943 "EM_UNKNOWN_USER_109", 02944 "EM_UNKNOWN_USER_110", 02945 "EM_UNKNOWN_USER_111", 02946 "EM_UNKNOWN_USER_112", 02947 "EM_UNKNOWN_USER_113", 02948 "EM_UNKNOWN_USER_114", 02949 "EM_UNKNOWN_USER_115", 02950 "EM_UNKNOWN_USER_116", 02951 "EM_UNKNOWN_USER_117", 02952 "EM_UNKNOWN_USER_118", 02953 "EM_UNKNOWN_USER_119", 02954 "EM_SETLANGOPTIONS", 02955 "EM_GETLANGOPTIONS", 02956 "EM_GETIMECOMPMODE", 02957 "EM_FINDTEXTW", 02958 "EM_FINDTEXTEXW", 02959 "EM_RECONVERSION", 02960 "EM_SETIMEMODEBIAS", 02961 "EM_GETIMEMODEBIAS" 02962 }; 02963 02964 static const char * 02965 get_msg_name(UINT msg) 02966 { 02967 if (msg >= EM_GETSEL && msg <= EM_CHARFROMPOS) 02968 return edit_messages[msg - EM_GETSEL]; 02969 if (msg >= EM_CANPASTE && msg <= EM_GETIMEMODEBIAS) 02970 return richedit_messages[msg - EM_CANPASTE]; 02971 return ""; 02972 } 02973 02974 static void ME_LinkNotify(ME_TextEditor *editor, UINT msg, WPARAM wParam, LPARAM lParam) 02975 { 02976 int x,y; 02977 BOOL isExact; 02978 ME_Cursor cursor; /* The start of the clicked text. */ 02979 02980 ENLINK info; 02981 x = (short)LOWORD(lParam); 02982 y = (short)HIWORD(lParam); 02983 ME_CharFromPos(editor, x, y, &cursor, &isExact); 02984 if (!isExact) return; 02985 02986 if (cursor.pRun->member.run.style->fmt.dwMask & CFM_LINK && 02987 cursor.pRun->member.run.style->fmt.dwEffects & CFE_LINK) 02988 { /* The clicked run has CFE_LINK set */ 02989 info.nmhdr.hwndFrom = NULL; 02990 info.nmhdr.idFrom = 0; 02991 info.nmhdr.code = EN_LINK; 02992 info.msg = msg; 02993 info.wParam = wParam; 02994 info.lParam = lParam; 02995 cursor.nOffset = 0; 02996 info.chrg.cpMin = ME_GetCursorOfs(&cursor); 02997 info.chrg.cpMax = info.chrg.cpMin + cursor.pRun->member.run.strText->nLen; 02998 ITextHost_TxNotify(editor->texthost, info.nmhdr.code, &info); 02999 } 03000 } 03001 03002 #define UNSUPPORTED_MSG(e) \ 03003 case e: \ 03004 FIXME(#e ": stub\n"); \ 03005 *phresult = S_FALSE; \ 03006 return 0; 03007 03008 /* Handle messages for windowless and windoweded richedit controls. 03009 * 03010 * The LRESULT that is returned is a return value for window procs, 03011 * and the phresult parameter is the COM return code needed by the 03012 * text services interface. */ 03013 LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam, 03014 LPARAM lParam, BOOL unicode, HRESULT* phresult) 03015 { 03016 *phresult = S_OK; 03017 03018 switch(msg) { 03019 03020 UNSUPPORTED_MSG(EM_DISPLAYBAND) 03021 UNSUPPORTED_MSG(EM_FINDWORDBREAK) 03022 UNSUPPORTED_MSG(EM_FMTLINES) 03023 UNSUPPORTED_MSG(EM_FORMATRANGE) 03024 UNSUPPORTED_MSG(EM_GETBIDIOPTIONS) 03025 UNSUPPORTED_MSG(EM_GETEDITSTYLE) 03026 UNSUPPORTED_MSG(EM_GETIMECOMPMODE) 03027 UNSUPPORTED_MSG(EM_GETIMESTATUS) 03028 UNSUPPORTED_MSG(EM_SETIMESTATUS) 03029 UNSUPPORTED_MSG(EM_GETLANGOPTIONS) 03030 UNSUPPORTED_MSG(EM_GETREDONAME) 03031 UNSUPPORTED_MSG(EM_GETTYPOGRAPHYOPTIONS) 03032 UNSUPPORTED_MSG(EM_GETUNDONAME) 03033 UNSUPPORTED_MSG(EM_GETWORDBREAKPROCEX) 03034 UNSUPPORTED_MSG(EM_PASTESPECIAL) 03035 UNSUPPORTED_MSG(EM_SELECTIONTYPE) 03036 UNSUPPORTED_MSG(EM_SETBIDIOPTIONS) 03037 UNSUPPORTED_MSG(EM_SETEDITSTYLE) 03038 UNSUPPORTED_MSG(EM_SETFONTSIZE) 03039 UNSUPPORTED_MSG(EM_SETLANGOPTIONS) 03040 UNSUPPORTED_MSG(EM_SETMARGINS) 03041 UNSUPPORTED_MSG(EM_SETPALETTE) 03042 UNSUPPORTED_MSG(EM_SETTABSTOPS) 03043 UNSUPPORTED_MSG(EM_SETTYPOGRAPHYOPTIONS) 03044 UNSUPPORTED_MSG(EM_SETWORDBREAKPROCEX) 03045 03046 /* Messages specific to Richedit controls */ 03047 03048 case EM_STREAMIN: 03049 return ME_StreamIn(editor, wParam, (EDITSTREAM*)lParam, TRUE); 03050 case EM_STREAMOUT: 03051 return ME_StreamOut(editor, wParam, (EDITSTREAM *)lParam); 03052 case WM_GETDLGCODE: 03053 { 03054 UINT code = DLGC_WANTCHARS|DLGC_WANTTAB|DLGC_WANTARROWS|DLGC_HASSETSEL; 03055 if (lParam) 03056 editor->bDialogMode = TRUE; 03057 if (editor->styleFlags & ES_MULTILINE) 03058 code |= DLGC_WANTMESSAGE; 03059 return code; 03060 } 03061 case EM_EMPTYUNDOBUFFER: 03062 ME_EmptyUndoStack(editor); 03063 return 0; 03064 case EM_GETSEL: 03065 { 03066 /* Note: wParam/lParam can be NULL */ 03067 UINT from, to; 03068 PUINT pfrom = wParam ? (PUINT)wParam : &from; 03069 PUINT pto = lParam ? (PUINT)lParam : &to; 03070 ME_GetSelectionOfs(editor, (int *)pfrom, (int *)pto); 03071 if ((*pfrom|*pto) & 0xFFFF0000) 03072 return -1; 03073 return MAKELONG(*pfrom,*pto); 03074 } 03075 case EM_EXGETSEL: 03076 { 03077 CHARRANGE *pRange = (CHARRANGE *)lParam; 03078 ME_GetSelectionOfs(editor, &pRange->cpMin, &pRange->cpMax); 03079 TRACE("EM_EXGETSEL = (%d,%d)\n", pRange->cpMin, pRange->cpMax); 03080 return 0; 03081 } 03082 case EM_SETUNDOLIMIT: 03083 { 03084 if ((int)wParam < 0) 03085 editor->nUndoLimit = STACK_SIZE_DEFAULT; 03086 else 03087 editor->nUndoLimit = min(wParam, STACK_SIZE_MAX); 03088 /* Setting a max stack size keeps wine from getting killed 03089 for hogging memory. Windows allocates all this memory at once, so 03090 no program would realistically set a value above our maximum. */ 03091 return editor->nUndoLimit; 03092 } 03093 case EM_CANUNDO: 03094 return editor->pUndoStack != NULL; 03095 case EM_CANREDO: 03096 return editor->pRedoStack != NULL; 03097 case WM_UNDO: /* FIXME: actually not the same */ 03098 case EM_UNDO: 03099 return ME_Undo(editor); 03100 case EM_REDO: 03101 return ME_Redo(editor); 03102 case EM_GETOPTIONS: 03103 { 03104 /* these flags are equivalent to the ES_* counterparts */ 03105 DWORD mask = ECO_VERTICAL | ECO_AUTOHSCROLL | ECO_AUTOVSCROLL | 03106 ECO_NOHIDESEL | ECO_READONLY | ECO_WANTRETURN | ECO_SELECTIONBAR; 03107 DWORD settings = editor->styleFlags & mask; 03108 03109 return settings; 03110 } 03111 case EM_SETOPTIONS: 03112 { 03113 /* these flags are equivalent to ES_* counterparts, except for 03114 * ECO_AUTOWORDSELECTION that doesn't have an ES_* counterpart, 03115 * but is still stored in editor->styleFlags. */ 03116 const DWORD mask = ECO_VERTICAL | ECO_AUTOHSCROLL | ECO_AUTOVSCROLL | 03117 ECO_NOHIDESEL | ECO_READONLY | ECO_WANTRETURN | 03118 ECO_SELECTIONBAR | ECO_AUTOWORDSELECTION; 03119 DWORD settings = mask & editor->styleFlags; 03120 DWORD oldSettings = settings; 03121 DWORD changedSettings; 03122 03123 switch(wParam) 03124 { 03125 case ECOOP_SET: 03126 settings = lParam; 03127 break; 03128 case ECOOP_OR: 03129 settings |= lParam; 03130 break; 03131 case ECOOP_AND: 03132 settings &= lParam; 03133 break; 03134 case ECOOP_XOR: 03135 settings ^= lParam; 03136 } 03137 changedSettings = oldSettings ^ settings; 03138 03139 if (changedSettings) { 03140 editor->styleFlags = (editor->styleFlags & ~mask) | (settings & mask); 03141 03142 if (changedSettings & ECO_SELECTIONBAR) 03143 { 03144 ITextHost_TxInvalidateRect(editor->texthost, &editor->rcFormat, TRUE); 03145 if (settings & ECO_SELECTIONBAR) { 03146 assert(!editor->selofs); 03147 editor->selofs = SELECTIONBAR_WIDTH; 03148 editor->rcFormat.left += editor->selofs; 03149 } else { 03150 editor->rcFormat.left -= editor->selofs; 03151 editor->selofs = 0; 03152 } 03153 ME_RewrapRepaint(editor); 03154 } 03155 03156 if (changedSettings & settings & ECO_VERTICAL) 03157 FIXME("ECO_VERTICAL not implemented yet!\n"); 03158 if (changedSettings & settings & ECO_AUTOHSCROLL) 03159 FIXME("ECO_AUTOHSCROLL not implemented yet!\n"); 03160 if (changedSettings & settings & ECO_AUTOVSCROLL) 03161 FIXME("ECO_AUTOVSCROLL not implemented yet!\n"); 03162 if (changedSettings & settings & ECO_NOHIDESEL) 03163 FIXME("ECO_NOHIDESEL not implemented yet!\n"); 03164 if (changedSettings & settings & ECO_WANTRETURN) 03165 FIXME("ECO_WANTRETURN not implemented yet!\n"); 03166 if (changedSettings & settings & ECO_AUTOWORDSELECTION) 03167 FIXME("ECO_AUTOWORDSELECTION not implemented yet!\n"); 03168 } 03169 03170 return settings; 03171 } 03172 case EM_SETSEL: 03173 { 03174 ME_InvalidateSelection(editor); 03175 ME_SetSelection(editor, wParam, lParam); 03176 ME_InvalidateSelection(editor); 03177 ITextHost_TxShowCaret(editor->texthost, FALSE); 03178 ME_ShowCaret(editor); 03179 ME_SendSelChange(editor); 03180 return 0; 03181 } 03182 case EM_SETSCROLLPOS: 03183 { 03184 POINT *point = (POINT *)lParam; 03185 ME_ScrollAbs(editor, point->x, point->y); 03186 return 0; 03187 } 03188 case EM_AUTOURLDETECT: 03189 { 03190 if (wParam==1 || wParam ==0) 03191 { 03192 editor->AutoURLDetect_bEnable = (BOOL)wParam; 03193 return 0; 03194 } 03195 return E_INVALIDARG; 03196 } 03197 case EM_GETAUTOURLDETECT: 03198 { 03199 return editor->AutoURLDetect_bEnable; 03200 } 03201 case EM_EXSETSEL: 03202 { 03203 int end; 03204 CHARRANGE range = *(CHARRANGE *)lParam; 03205 03206 TRACE("EM_EXSETSEL (%d,%d)\n", range.cpMin, range.cpMax); 03207 03208 ME_InvalidateSelection(editor); 03209 end = ME_SetSelection(editor, range.cpMin, range.cpMax); 03210 ME_InvalidateSelection(editor); 03211 ITextHost_TxShowCaret(editor->texthost, FALSE); 03212 ME_ShowCaret(editor); 03213 ME_SendSelChange(editor); 03214 03215 return end; 03216 } 03217 case EM_SHOWSCROLLBAR: 03218 { 03219 DWORD flags; 03220 03221 switch (wParam) 03222 { 03223 case SB_HORZ: 03224 flags = WS_HSCROLL; 03225 break; 03226 case SB_VERT: 03227 flags = WS_VSCROLL; 03228 break; 03229 case SB_BOTH: 03230 flags = WS_HSCROLL|WS_VSCROLL; 03231 break; 03232 default: 03233 return 0; 03234 } 03235 03236 if (lParam) { 03237 editor->styleFlags |= flags; 03238 if (flags & WS_HSCROLL) 03239 ITextHost_TxShowScrollBar(editor->texthost, SB_HORZ, 03240 editor->nTotalWidth > editor->sizeWindow.cx); 03241 if (flags & WS_VSCROLL) 03242 ITextHost_TxShowScrollBar(editor->texthost, SB_VERT, 03243 editor->nTotalLength > editor->sizeWindow.cy); 03244 } else { 03245 editor->styleFlags &= ~flags; 03246 ITextHost_TxShowScrollBar(editor->texthost, wParam, FALSE); 03247 } 03248 return 0; 03249 } 03250 case EM_SETTEXTEX: 03251 { 03252 LPWSTR wszText; 03253 SETTEXTEX *pStruct = (SETTEXTEX *)wParam; 03254 size_t len = 0; 03255 int from, to; 03256 ME_Style *style; 03257 BOOL bRtf, bUnicode, bSelection; 03258 int oldModify = editor->nModifyStep; 03259 03260 if (!pStruct) return 0; 03261 03262 /* If we detect ascii rtf at the start of the string, 03263 * we know it isn't unicode. */ 03264 bRtf = (lParam && (!strncmp((char *)lParam, "{\\rtf", 5) || 03265 !strncmp((char *)lParam, "{\\urtf", 6))); 03266 bUnicode = !bRtf && pStruct->codepage == 1200; 03267 03268 TRACE("EM_SETTEXTEX - %s, flags %d, cp %d\n", 03269 bUnicode ? debugstr_w((LPCWSTR)lParam) : debugstr_a((LPCSTR)lParam), 03270 pStruct->flags, pStruct->codepage); 03271 03272 bSelection = (pStruct->flags & ST_SELECTION) != 0; 03273 if (bSelection) { 03274 int nStartCursor = ME_GetSelectionOfs(editor, &from, &to); 03275 style = ME_GetSelectionInsertStyle(editor); 03276 ME_InternalDeleteText(editor, &editor->pCursors[nStartCursor], to - from, FALSE); 03277 } else { 03278 ME_Cursor start; 03279 ME_SetCursorToStart(editor, &start); 03280 ME_InternalDeleteText(editor, &start, ME_GetTextLength(editor), FALSE); 03281 style = editor->pBuffer->pDefaultStyle; 03282 } 03283 03284 if (bRtf) { 03285 ME_StreamInRTFString(editor, bSelection, (char *)lParam); 03286 if (bSelection) { 03287 /* FIXME: The length returned doesn't include the rtf control 03288 * characters, only the actual text. */ 03289 len = lParam ? strlen((char *)lParam) : 0; 03290 } 03291 } else { 03292 /* FIXME: make use of pStruct->codepage in the to unicode translation */ 03293 wszText = lParam ? ME_ToUnicode(bUnicode, (void *)lParam) : NULL; 03294 len = wszText ? lstrlenW(wszText) : 0; 03295 ME_InsertTextFromCursor(editor, 0, wszText, len, style); 03296 ME_EndToUnicode(bUnicode, wszText); 03297 } 03298 03299 if (bSelection) { 03300 ME_ReleaseStyle(style); 03301 ME_UpdateSelectionLinkAttribute(editor); 03302 } else { 03303 ME_Cursor cursor; 03304 len = 1; 03305 ME_SetCursorToStart(editor, &cursor); 03306 ME_UpdateLinkAttribute(editor, &cursor, INT_MAX); 03307 } 03308 ME_CommitUndo(editor); 03309 if (!(pStruct->flags & ST_KEEPUNDO)) 03310 { 03311 editor->nModifyStep = oldModify; 03312 ME_EmptyUndoStack(editor); 03313 } 03314 ME_UpdateRepaint(editor, FALSE); 03315 return len; 03316 } 03317 case EM_SETBKGNDCOLOR: 03318 { 03319 LRESULT lColor; 03320 if (editor->rgbBackColor != -1) { 03321 DeleteObject(editor->hbrBackground); 03322 lColor = editor->rgbBackColor; 03323 } 03324 else lColor = ITextHost_TxGetSysColor(editor->texthost, COLOR_WINDOW); 03325 03326 if (wParam) 03327 { 03328 editor->rgbBackColor = -1; 03329 editor->hbrBackground = GetSysColorBrush(COLOR_WINDOW); 03330 } 03331 else 03332 { 03333 editor->rgbBackColor = lParam; 03334 editor->hbrBackground = CreateSolidBrush(editor->rgbBackColor); 03335 } 03336 ITextHost_TxInvalidateRect(editor->texthost, NULL, TRUE); 03337 ITextHost_TxViewChange(editor->texthost, TRUE); 03338 return lColor; 03339 } 03340 case EM_GETMODIFY: 03341 return editor->nModifyStep == 0 ? 0 : -1; 03342 case EM_SETMODIFY: 03343 { 03344 if (wParam) 03345 editor->nModifyStep = 1; 03346 else 03347 editor->nModifyStep = 0; 03348 03349 return 0; 03350 } 03351 case EM_SETREADONLY: 03352 { 03353 if (wParam) 03354 editor->styleFlags |= ES_READONLY; 03355 else 03356 editor->styleFlags &= ~ES_READONLY; 03357 return 0; 03358 } 03359 case EM_SETEVENTMASK: 03360 { 03361 DWORD nOldMask = editor->nEventMask; 03362 03363 editor->nEventMask = lParam; 03364 return nOldMask; 03365 } 03366 case EM_GETEVENTMASK: 03367 return editor->nEventMask; 03368 case EM_SETCHARFORMAT: 03369 { 03370 CHARFORMAT2W buf, *p; 03371 BOOL bRepaint = TRUE; 03372 p = ME_ToCF2W(&buf, (CHARFORMAT2W *)lParam); 03373 if (p == NULL) return 0; 03374 if (wParam & SCF_ALL) { 03375 if (editor->mode & TM_PLAINTEXT) { 03376 ME_SetDefaultCharFormat(editor, p); 03377 } else { 03378 ME_Cursor start; 03379 ME_SetCursorToStart(editor, &start); 03380 ME_SetCharFormat(editor, &start, NULL, p); 03381 editor->nModifyStep = 1; 03382 } 03383 } else if (wParam & SCF_SELECTION) { 03384 if (editor->mode & TM_PLAINTEXT) 03385 return 0; 03386 if (wParam & SCF_WORD) { 03387 FIXME("EM_SETCHARFORMAT: word selection not supported\n"); 03388 return 0; 03389 } 03390 bRepaint = ME_IsSelection(editor); 03391 ME_SetSelectionCharFormat(editor, p); 03392 if (bRepaint) editor->nModifyStep = 1; 03393 } else { /* SCF_DEFAULT */ 03394 ME_SetDefaultCharFormat(editor, p); 03395 } 03396 ME_CommitUndo(editor); 03397 if (bRepaint) 03398 { 03399 ME_WrapMarkedParagraphs(editor); 03400 ME_UpdateScrollBar(editor); 03401 ME_Repaint(editor); 03402 } 03403 return 1; 03404 } 03405 case EM_GETCHARFORMAT: 03406 { 03407 CHARFORMAT2W tmp, *dst = (CHARFORMAT2W *)lParam; 03408 if (dst->cbSize != sizeof(CHARFORMATA) && 03409 dst->cbSize != sizeof(CHARFORMATW) && 03410 dst->cbSize != sizeof(CHARFORMAT2A) && 03411 dst->cbSize != sizeof(CHARFORMAT2W)) 03412 return 0; 03413 tmp.cbSize = sizeof(tmp); 03414 if (!wParam) 03415 ME_GetDefaultCharFormat(editor, &tmp); 03416 else 03417 ME_GetSelectionCharFormat(editor, &tmp); 03418 ME_CopyToCFAny(dst, &tmp); 03419 return tmp.dwMask; 03420 } 03421 case EM_SETPARAFORMAT: 03422 { 03423 BOOL result = ME_SetSelectionParaFormat(editor, (PARAFORMAT2 *)lParam); 03424 ME_WrapMarkedParagraphs(editor); 03425 ME_UpdateScrollBar(editor); 03426 ME_Repaint(editor); 03427 ME_CommitUndo(editor); 03428 return result; 03429 } 03430 case EM_GETPARAFORMAT: 03431 ME_GetSelectionParaFormat(editor, (PARAFORMAT2 *)lParam); 03432 return ((PARAFORMAT2 *)lParam)->dwMask; 03433 case EM_GETFIRSTVISIBLELINE: 03434 { 03435 ME_DisplayItem *p = editor->pBuffer->pFirst; 03436 int y = editor->vert_si.nPos; 03437 int ypara = 0; 03438 int count = 0; 03439 int ystart, yend; 03440 while(p) { 03441 p = ME_FindItemFwd(p, diStartRowOrParagraphOrEnd); 03442 if (p->type == diTextEnd) 03443 break; 03444 if (p->type == diParagraph) { 03445 ypara = p->member.para.pt.y; 03446 continue; 03447 } 03448 ystart = ypara + p->member.row.pt.y; 03449 yend = ystart + p->member.row.nHeight; 03450 if (y < yend) { 03451 break; 03452 } 03453 count++; 03454 } 03455 return count; 03456 } 03457 case EM_HIDESELECTION: 03458 { 03459 editor->bHideSelection = (wParam != 0); 03460 ME_InvalidateSelection(editor); 03461 return 0; 03462 } 03463 case EM_LINESCROLL: 03464 { 03465 if (!(editor->styleFlags & ES_MULTILINE)) 03466 return FALSE; 03467 ME_ScrollDown(editor, lParam * 8); /* FIXME follow the original */ 03468 return TRUE; 03469 } 03470 case WM_CLEAR: 03471 { 03472 int from, to; 03473 int nStartCursor = ME_GetSelectionOfs(editor, &from, &to); 03474 ME_InternalDeleteText(editor, &editor->pCursors[nStartCursor], to-from, FALSE); 03475 ME_CommitUndo(editor); 03476 ME_UpdateRepaint(editor, TRUE); 03477 return 0; 03478 } 03479 case EM_REPLACESEL: 03480 { 03481 int from, to, nStartCursor; 03482 ME_Style *style; 03483 LPWSTR wszText = lParam ? ME_ToUnicode(unicode, (void *)lParam) : NULL; 03484 size_t len = wszText ? lstrlenW(wszText) : 0; 03485 TRACE("EM_REPLACESEL - %s\n", debugstr_w(wszText)); 03486 03487 nStartCursor = ME_GetSelectionOfs(editor, &from, &to); 03488 style = ME_GetSelectionInsertStyle(editor); 03489 ME_InternalDeleteText(editor, &editor->pCursors[nStartCursor], to-from, FALSE); 03490 ME_InsertTextFromCursor(editor, 0, wszText, len, style); 03491 ME_ReleaseStyle(style); 03492 /* drop temporary style if line end */ 03493 /* 03494 * FIXME question: does abc\n mean: put abc, 03495 * clear temp style, put \n? (would require a change) 03496 */ 03497 if (len>0 && wszText[len-1] == '\n') 03498 ME_ClearTempStyle(editor); 03499 ME_EndToUnicode(unicode, wszText); 03500 ME_CommitUndo(editor); 03501 ME_UpdateSelectionLinkAttribute(editor); 03502 if (!wParam) 03503 ME_EmptyUndoStack(editor); 03504 ME_UpdateRepaint(editor, FALSE); 03505 return len; 03506 } 03507 case EM_SCROLLCARET: 03508 ME_EnsureVisible(editor, &editor->pCursors[0]); 03509 return 0; 03510 case WM_SETFONT: 03511 { 03512 LOGFONTW lf; 03513 CHARFORMAT2W fmt; 03514 HDC hDC; 03515 BOOL bRepaint = LOWORD(lParam); 03516 03517 if (!wParam) 03518 wParam = (WPARAM)GetStockObject(SYSTEM_FONT); 03519 GetObjectW((HGDIOBJ)wParam, sizeof(LOGFONTW), &lf); 03520 hDC = ITextHost_TxGetDC(editor->texthost); 03521 ME_CharFormatFromLogFont(hDC, &lf, &fmt); 03522 ITextHost_TxReleaseDC(editor->texthost, hDC); 03523 if (editor->mode & TM_RICHTEXT) { 03524 ME_Cursor start; 03525 ME_SetCursorToStart(editor, &start); 03526 ME_SetCharFormat(editor, &start, NULL, &fmt); 03527 } 03528 ME_SetDefaultCharFormat(editor, &fmt); 03529 03530 ME_CommitUndo(editor); 03531 ME_MarkAllForWrapping(editor); 03532 ME_WrapMarkedParagraphs(editor); 03533 ME_UpdateScrollBar(editor); 03534 if (bRepaint) 03535 ME_Repaint(editor); 03536 return 0; 03537 } 03538 case WM_SETTEXT: 03539 { 03540 ME_Cursor cursor; 03541 ME_SetCursorToStart(editor, &cursor); 03542 ME_InternalDeleteText(editor, &cursor, ME_GetTextLength(editor), FALSE); 03543 if (lParam) 03544 { 03545 TRACE("WM_SETTEXT lParam==%lx\n",lParam); 03546 if (!strncmp((char *)lParam, "{\\rtf", 5) || 03547 !strncmp((char *)lParam, "{\\urtf", 6)) 03548 { 03549 /* Undocumented: WM_SETTEXT supports RTF text */ 03550 ME_StreamInRTFString(editor, 0, (char *)lParam); 03551 } 03552 else 03553 { 03554 LPWSTR wszText = ME_ToUnicode(unicode, (void *)lParam); 03555 TRACE("WM_SETTEXT - %s\n", debugstr_w(wszText)); /* debugstr_w() */ 03556 if (lstrlenW(wszText) > 0) 03557 { 03558 int len = -1; 03559 03560 /* uses default style! */ 03561 if (!(editor->styleFlags & ES_MULTILINE)) 03562 { 03563 WCHAR * p; 03564 03565 p = wszText; 03566 while (*p != '\0' && *p != '\r' && *p != '\n') p++; 03567 len = p - wszText; 03568 } 03569 ME_InsertTextFromCursor(editor, 0, wszText, len, editor->pBuffer->pDefaultStyle); 03570 } 03571 ME_EndToUnicode(unicode, wszText); 03572 } 03573 } 03574 else 03575 TRACE("WM_SETTEXT - NULL\n"); 03576 ME_SetCursorToStart(editor, &cursor); 03577 ME_UpdateLinkAttribute(editor, &cursor, INT_MAX); 03578 ME_SetSelection(editor, 0, 0); 03579 editor->nModifyStep = 0; 03580 ME_CommitUndo(editor); 03581 ME_EmptyUndoStack(editor); 03582 ME_UpdateRepaint(editor, FALSE); 03583 return 1; 03584 } 03585 case EM_CANPASTE: 03586 { 03587 UINT nRTFFormat = RegisterClipboardFormatA("Rich Text Format"); 03588 if (IsClipboardFormatAvailable(nRTFFormat)) 03589 return TRUE; 03590 if (IsClipboardFormatAvailable(CF_UNICODETEXT)) 03591 return TRUE; 03592 return FALSE; 03593 } 03594 case WM_PASTE: 03595 ME_Paste(editor); 03596 return 0; 03597 case WM_CUT: 03598 case WM_COPY: 03599 { 03600 int nFrom, nTo, nStartCur = ME_GetSelectionOfs(editor, &nFrom, &nTo); 03601 int nChars = nTo - nFrom; 03602 ME_Cursor *selStart = &editor->pCursors[nStartCur]; 03603 03604 if (ME_Copy(editor, selStart, nChars) && msg == WM_CUT) 03605 { 03606 ME_InternalDeleteText(editor, selStart, nChars, FALSE); 03607 ME_CommitUndo(editor); 03608 ME_UpdateRepaint(editor, TRUE); 03609 } 03610 return 0; 03611 } 03612 case WM_GETTEXTLENGTH: 03613 { 03614 GETTEXTLENGTHEX how; 03615 03616 /* CR/LF conversion required in 2.0 mode, verbatim in 1.0 mode */ 03617 how.flags = GTL_CLOSE | (editor->bEmulateVersion10 ? 0 : GTL_USECRLF) | GTL_NUMCHARS; 03618 how.codepage = unicode ? 1200 : CP_ACP; 03619 return ME_GetTextLengthEx(editor, &how); 03620 } 03621 case EM_GETTEXTLENGTHEX: 03622 return ME_GetTextLengthEx(editor, (GETTEXTLENGTHEX *)wParam); 03623 case WM_GETTEXT: 03624 { 03625 GETTEXTEX ex; 03626 ex.cb = wParam * (unicode ? sizeof(WCHAR) : sizeof(CHAR)); 03627 ex.flags = GT_USECRLF; 03628 ex.codepage = unicode ? 1200 : CP_ACP; 03629 ex.lpDefaultChar = NULL; 03630 ex.lpUsedDefChar = NULL; 03631 return ME_GetTextEx(editor, &ex, lParam); 03632 } 03633 case EM_GETTEXTEX: 03634 return ME_GetTextEx(editor, (GETTEXTEX*)wParam, lParam); 03635 case EM_GETSELTEXT: 03636 { 03637 int nFrom, nTo, nStartCur = ME_GetSelectionOfs(editor, &nFrom, &nTo); 03638 ME_Cursor *from = &editor->pCursors[nStartCur]; 03639 return ME_GetTextRange(editor, (WCHAR *)lParam, from, 03640 nTo - nFrom, unicode); 03641 } 03642 case EM_GETSCROLLPOS: 03643 { 03644 POINT *point = (POINT *)lParam; 03645 point->x = editor->horz_si.nPos; 03646 point->y = editor->vert_si.nPos; 03647 /* 16-bit scaled value is returned as stored in scrollinfo */ 03648 if (editor->horz_si.nMax > 0xffff) 03649 point->x = MulDiv(point->x, 0xffff, editor->horz_si.nMax); 03650 if (editor->vert_si.nMax > 0xffff) 03651 point->y = MulDiv(point->y, 0xffff, editor->vert_si.nMax); 03652 return 1; 03653 } 03654 case EM_GETTEXTRANGE: 03655 { 03656 TEXTRANGEW *rng = (TEXTRANGEW *)lParam; 03657 ME_Cursor start; 03658 int nStart = rng->chrg.cpMin; 03659 int nEnd = rng->chrg.cpMax; 03660 int textlength = ME_GetTextLength(editor); 03661 03662 TRACE("EM_GETTEXTRANGE min=%d max=%d unicode=%d textlength=%d\n", 03663 rng->chrg.cpMin, rng->chrg.cpMax, unicode, textlength); 03664 if (nStart < 0) return 0; 03665 if ((nStart == 0 && nEnd == -1) || nEnd > textlength) 03666 nEnd = textlength; 03667 if (nStart >= nEnd) return 0; 03668 03669 ME_CursorFromCharOfs(editor, nStart, &start); 03670 return ME_GetTextRange(editor, rng->lpstrText, &start, nEnd - nStart, unicode); 03671 } 03672 case EM_GETLINE: 03673 { 03674 ME_DisplayItem *run; 03675 const unsigned int nMaxChars = *(WORD *) lParam; 03676 unsigned int nCharsLeft = nMaxChars; 03677 char *dest = (char *) lParam; 03678 BOOL wroteNull = FALSE; 03679 03680 TRACE("EM_GETLINE: row=%d, nMaxChars=%d (%s)\n", (int) wParam, nMaxChars, 03681 unicode ? "Unicode" : "Ansi"); 03682 03683 run = ME_FindRowWithNumber(editor, wParam); 03684 if (run == NULL) 03685 return 0; 03686 03687 while (nCharsLeft && (run = ME_FindItemFwd(run, diRunOrStartRow)) 03688 && run->type == diRun) 03689 { 03690 unsigned int nCopy; 03691 ME_String *strText; 03692 03693 strText = run->member.run.strText; 03694 nCopy = min(nCharsLeft, strText->nLen); 03695 03696 if (unicode) 03697 memcpy(dest, strText->szData, nCopy * sizeof(WCHAR)); 03698 else 03699 nCopy = WideCharToMultiByte(CP_ACP, 0, strText->szData, nCopy, dest, 03700 nCharsLeft, NULL, NULL); 03701 dest += nCopy * (unicode ? sizeof(WCHAR) : 1); 03702 nCharsLeft -= nCopy; 03703 } 03704 03705 /* append line termination, space allowing */ 03706 if (nCharsLeft > 0) 03707 { 03708 if (unicode) 03709 *((WCHAR *)dest) = '\0'; 03710 else 03711 *dest = '\0'; 03712 nCharsLeft--; 03713 wroteNull = TRUE; 03714 } 03715 03716 TRACE("EM_GETLINE: got %u characters\n", nMaxChars - nCharsLeft); 03717 return nMaxChars - nCharsLeft - (wroteNull ? 1 : 0); 03718 } 03719 case EM_GETLINECOUNT: 03720 { 03721 ME_DisplayItem *item = editor->pBuffer->pFirst->next; 03722 int nRows = 0; 03723 03724 ME_DisplayItem *prev_para = NULL, *last_para = NULL; 03725 03726 while (item != editor->pBuffer->pLast) 03727 { 03728 assert(item->type == diParagraph); 03729 prev_para = ME_FindItemBack(item, diRun); 03730 if (prev_para) { 03731 assert(prev_para->member.run.nFlags & MERF_ENDPARA); 03732 } 03733 nRows += item->member.para.nRows; 03734 item = item->member.para.next_para; 03735 } 03736 last_para = ME_FindItemBack(item, diRun); 03737 assert(last_para); 03738 assert(last_para->member.run.nFlags & MERF_ENDPARA); 03739 if (editor->bEmulateVersion10 && prev_para && 03740 last_para->member.run.nCharOfs == 0 && 03741 prev_para->member.run.strText->nLen == 1 && 03742 prev_para->member.run.strText->szData[0] == '\r') 03743 { 03744 /* In 1.0 emulation, the last solitary \r at the very end of the text 03745 (if one exists) is NOT a line break. 03746 FIXME: this is an ugly hack. This should have a more regular model. */ 03747 nRows--; 03748 } 03749 03750 TRACE("EM_GETLINECOUNT: nRows==%d\n", nRows); 03751 return max(1, nRows); 03752 } 03753 case EM_LINEFROMCHAR: 03754 { 03755 if (wParam == -1) 03756 return ME_RowNumberFromCharOfs(editor, ME_GetCursorOfs(&editor->pCursors[1])); 03757 else 03758 return ME_RowNumberFromCharOfs(editor, wParam); 03759 } 03760 case EM_EXLINEFROMCHAR: 03761 { 03762 if (lParam == -1) 03763 return ME_RowNumberFromCharOfs(editor, ME_GetCursorOfs(&editor->pCursors[1])); 03764 else 03765 return ME_RowNumberFromCharOfs(editor, lParam); 03766 } 03767 case EM_LINEINDEX: 03768 { 03769 ME_DisplayItem *item, *para; 03770 int nCharOfs; 03771 03772 if (wParam == -1) 03773 item = ME_FindItemBack(editor->pCursors[0].pRun, diStartRow); 03774 else 03775 item = ME_FindRowWithNumber(editor, wParam); 03776 if (!item) 03777 return -1; 03778 para = ME_GetParagraph(item); 03779 item = ME_FindItemFwd(item, diRun); 03780 nCharOfs = para->member.para.nCharOfs + item->member.run.nCharOfs; 03781 TRACE("EM_LINEINDEX: nCharOfs==%d\n", nCharOfs); 03782 return nCharOfs; 03783 } 03784 case EM_LINELENGTH: 03785 { 03786 ME_DisplayItem *item, *item_end; 03787 int nChars = 0, nThisLineOfs = 0, nNextLineOfs = 0; 03788 ME_DisplayItem *para, *run; 03789 03790 if (wParam > ME_GetTextLength(editor)) 03791 return 0; 03792 if (wParam == -1) 03793 { 03794 FIXME("EM_LINELENGTH: returning number of unselected characters on lines with selection unsupported.\n"); 03795 return 0; 03796 } 03797 ME_RunOfsFromCharOfs(editor, wParam, ¶, &run, NULL); 03798 item = ME_RowStart(run); 03799 nThisLineOfs = ME_CharOfsFromRunOfs(editor, para, ME_FindItemFwd(item, diRun), 0); 03800 item_end = ME_FindItemFwd(item, diStartRowOrParagraphOrEnd); 03801 if (item_end->type == diStartRow) { 03802 nNextLineOfs = ME_CharOfsFromRunOfs(editor, para, ME_FindItemFwd(item_end, diRun), 0); 03803 } else { 03804 ME_DisplayItem *endRun = ME_FindItemBack(item_end, diRun); 03805 assert(endRun && endRun->member.run.nFlags & MERF_ENDPARA); 03806 nNextLineOfs = item_end->member.para.nCharOfs - endRun->member.run.strText->nLen; 03807 } 03808 nChars = nNextLineOfs - nThisLineOfs; 03809 TRACE("EM_LINELENGTH(%ld)==%d\n",wParam, nChars); 03810 return nChars; 03811 } 03812 case EM_EXLIMITTEXT: 03813 { 03814 if ((int)lParam < 0) 03815 return 0; 03816 if (lParam == 0) 03817 editor->nTextLimit = 65536; 03818 else 03819 editor->nTextLimit = (int) lParam; 03820 return 0; 03821 } 03822 case EM_LIMITTEXT: 03823 { 03824 if (wParam == 0) 03825 editor->nTextLimit = 65536; 03826 else 03827 editor->nTextLimit = (int) wParam; 03828 return 0; 03829 } 03830 case EM_GETLIMITTEXT: 03831 { 03832 return editor->nTextLimit; 03833 } 03834 case EM_FINDTEXT: 03835 { 03836 FINDTEXTA *ft = (FINDTEXTA *)lParam; 03837 int nChars = MultiByteToWideChar(CP_ACP, 0, ft->lpstrText, -1, NULL, 0); 03838 WCHAR *tmp; 03839 LRESULT r; 03840 03841 if ((tmp = ALLOC_N_OBJ(WCHAR, nChars)) != NULL) 03842 MultiByteToWideChar(CP_ACP, 0, ft->lpstrText, -1, tmp, nChars); 03843 r = ME_FindText(editor, wParam, &ft->chrg, tmp, NULL); 03844 FREE_OBJ( tmp ); 03845 return r; 03846 } 03847 case EM_FINDTEXTEX: 03848 { 03849 FINDTEXTEXA *ex = (FINDTEXTEXA *)lParam; 03850 int nChars = MultiByteToWideChar(CP_ACP, 0, ex->lpstrText, -1, NULL, 0); 03851 WCHAR *tmp; 03852 LRESULT r; 03853 03854 if ((tmp = ALLOC_N_OBJ(WCHAR, nChars)) != NULL) 03855 MultiByteToWideChar(CP_ACP, 0, ex->lpstrText, -1, tmp, nChars); 03856 r = ME_FindText(editor, wParam, &ex->chrg, tmp, &ex->chrgText); 03857 FREE_OBJ( tmp ); 03858 return r; 03859 } 03860 case EM_FINDTEXTW: 03861 { 03862 FINDTEXTW *ft = (FINDTEXTW *)lParam; 03863 return ME_FindText(editor, wParam, &ft->chrg, ft->lpstrText, NULL); 03864 } 03865 case EM_FINDTEXTEXW: 03866 { 03867 FINDTEXTEXW *ex = (FINDTEXTEXW *)lParam; 03868 return ME_FindText(editor, wParam, &ex->chrg, ex->lpstrText, &ex->chrgText); 03869 } 03870 case EM_GETZOOM: 03871 if (!wParam || !lParam) 03872 return FALSE; 03873 *(int *)wParam = editor->nZoomNumerator; 03874 *(int *)lParam = editor->nZoomDenominator; 03875 return TRUE; 03876 case EM_SETZOOM: 03877 return ME_SetZoom(editor, wParam, lParam); 03878 case EM_CHARFROMPOS: 03879 { 03880 ME_Cursor cursor; 03881 if (ME_CharFromPos(editor, ((POINTL *)lParam)->x, ((POINTL *)lParam)->y, 03882 &cursor, NULL)) 03883 return ME_GetCursorOfs(&cursor); 03884 else 03885 return -1; 03886 } 03887 case EM_POSFROMCHAR: 03888 { 03889 ME_DisplayItem *pPara, *pRun; 03890 int nCharOfs, nOffset, nLength; 03891 POINTL pt = {0,0}; 03892 03893 nCharOfs = wParam; 03894 /* detect which API version we're dealing with */ 03895 if (wParam >= 0x40000) 03896 nCharOfs = lParam; 03897 nLength = ME_GetTextLength(editor); 03898 nCharOfs = min(nCharOfs, nLength); 03899 nCharOfs = max(nCharOfs, 0); 03900 03901 ME_RunOfsFromCharOfs(editor, nCharOfs, &pPara, &pRun, &nOffset); 03902 assert(pRun->type == diRun); 03903 pt.y = pRun->member.run.pt.y; 03904 pt.x = pRun->member.run.pt.x + ME_PointFromChar(editor, &pRun->member.run, nOffset); 03905 pt.y += pPara->member.para.pt.y + editor->rcFormat.top; 03906 pt.x += editor->rcFormat.left; 03907 03908 pt.x -= editor->horz_si.nPos; 03909 pt.y -= editor->vert_si.nPos; 03910 03911 if (wParam >= 0x40000) { 03912 *(POINTL *)wParam = pt; 03913 } 03914 return (wParam >= 0x40000) ? 0 : MAKELONG( pt.x, pt.y ); 03915 } 03916 case WM_CREATE: 03917 { 03918 INT max; 03919 03920 ME_SetDefaultFormatRect(editor); 03921 03922 max = (editor->styleFlags & ES_DISABLENOSCROLL) ? 1 : 0; 03923 if (~editor->styleFlags & ES_DISABLENOSCROLL || editor->styleFlags & WS_VSCROLL) 03924 ITextHost_TxSetScrollRange(editor->texthost, SB_VERT, 0, max, TRUE); 03925 03926 if (~editor->styleFlags & ES_DISABLENOSCROLL || editor->styleFlags & WS_HSCROLL) 03927 ITextHost_TxSetScrollRange(editor->texthost, SB_HORZ, 0, max, TRUE); 03928 03929 if (editor->styleFlags & ES_DISABLENOSCROLL) 03930 { 03931 if (editor->styleFlags & WS_VSCROLL) 03932 { 03933 ITextHost_TxEnableScrollBar(editor->texthost, SB_VERT, ESB_DISABLE_BOTH); 03934 ITextHost_TxShowScrollBar(editor->texthost, SB_VERT, TRUE); 03935 } 03936 if (editor->styleFlags & WS_HSCROLL) 03937 { 03938 ITextHost_TxEnableScrollBar(editor->texthost, SB_HORZ, ESB_DISABLE_BOTH); 03939 ITextHost_TxShowScrollBar(editor->texthost, SB_HORZ, TRUE); 03940 } 03941 } 03942 03943 ME_CommitUndo(editor); 03944 ME_WrapMarkedParagraphs(editor); 03945 ME_MoveCaret(editor); 03946 return 0; 03947 } 03948 case WM_DESTROY: 03949 ME_DestroyEditor(editor); 03950 return 0; 03951 case WM_SETCURSOR: 03952 { 03953 return ME_SetCursor(editor); 03954 } 03955 case WM_LBUTTONDBLCLK: 03956 case WM_LBUTTONDOWN: 03957 { 03958 ME_CommitUndo(editor); /* End coalesced undos for typed characters */ 03959 if ((editor->nEventMask & ENM_MOUSEEVENTS) && 03960 !ME_FilterEvent(editor, msg, &wParam, &lParam)) 03961 return 0; 03962 ITextHost_TxSetFocus(editor->texthost); 03963 ME_LButtonDown(editor, (short)LOWORD(lParam), (short)HIWORD(lParam), 03964 ME_CalculateClickCount(editor, msg, wParam, lParam)); 03965 ITextHost_TxSetCapture(editor->texthost, TRUE); 03966 editor->bMouseCaptured = TRUE; 03967 ME_LinkNotify(editor,msg,wParam,lParam); 03968 if (!ME_SetCursor(editor)) goto do_default; 03969 break; 03970 } 03971 case WM_MOUSEMOVE: 03972 if ((editor->nEventMask & ENM_MOUSEEVENTS) && 03973 !ME_FilterEvent(editor, msg, &wParam, &lParam)) 03974 return 0; 03975 if (editor->bMouseCaptured) 03976 ME_MouseMove(editor, (short)LOWORD(lParam), (short)HIWORD(lParam)); 03977 ME_LinkNotify(editor,msg,wParam,lParam); 03978 /* Set cursor if mouse is captured, since WM_SETCURSOR won't be received. */ 03979 if (editor->bMouseCaptured) 03980 ME_SetCursor(editor); 03981 break; 03982 case WM_LBUTTONUP: 03983 if (editor->bMouseCaptured) { 03984 ITextHost_TxSetCapture(editor->texthost, FALSE); 03985 editor->bMouseCaptured = FALSE; 03986 } 03987 if (editor->nSelectionType == stDocument) 03988 editor->nSelectionType = stPosition; 03989 if ((editor->nEventMask & ENM_MOUSEEVENTS) && 03990 !ME_FilterEvent(editor, msg, &wParam, &lParam)) 03991 return 0; 03992 else 03993 { 03994 ME_SetCursor(editor); 03995 ME_LinkNotify(editor,msg,wParam,lParam); 03996 } 03997 break; 03998 case WM_RBUTTONUP: 03999 case WM_RBUTTONDOWN: 04000 ME_CommitUndo(editor); /* End coalesced undos for typed characters */ 04001 if ((editor->nEventMask & ENM_MOUSEEVENTS) && 04002 !ME_FilterEvent(editor, msg, &wParam, &lParam)) 04003 return 0; 04004 goto do_default; 04005 case WM_CONTEXTMENU: 04006 if (!ME_ShowContextMenu(editor, (short)LOWORD(lParam), (short)HIWORD(lParam))) 04007 goto do_default; 04008 break; 04009 case WM_SETFOCUS: 04010 editor->bHaveFocus = TRUE; 04011 ME_ShowCaret(editor); 04012 ME_SendOldNotify(editor, EN_SETFOCUS); 04013 return 0; 04014 case WM_KILLFOCUS: 04015 ME_CommitUndo(editor); /* End coalesced undos for typed characters */ 04016 editor->bHaveFocus = FALSE; 04017 ME_HideCaret(editor); 04018 ME_SendOldNotify(editor, EN_KILLFOCUS); 04019 return 0; 04020 case WM_COMMAND: 04021 TRACE("editor wnd command = %d\n", LOWORD(wParam)); 04022 return 0; 04023 case WM_KEYUP: 04024 if ((editor->nEventMask & ENM_KEYEVENTS) && 04025 !ME_FilterEvent(editor, msg, &wParam, &lParam)) 04026 return 0; 04027 goto do_default; 04028 case WM_KEYDOWN: 04029 if ((editor->nEventMask & ENM_KEYEVENTS) && 04030 !ME_FilterEvent(editor, msg, &wParam, &lParam)) 04031 return 0; 04032 if (ME_KeyDown(editor, LOWORD(wParam))) 04033 return 0; 04034 goto do_default; 04035 case WM_CHAR: 04036 return ME_Char(editor, wParam, lParam, unicode); 04037 case WM_UNICHAR: 04038 if (unicode) 04039 { 04040 if(wParam == UNICODE_NOCHAR) return TRUE; 04041 if(wParam <= 0x000fffff) 04042 { 04043 if(wParam > 0xffff) /* convert to surrogates */ 04044 { 04045 wParam -= 0x10000; 04046 ME_Char(editor, (wParam >> 10) + 0xd800, 0, TRUE); 04047 ME_Char(editor, (wParam & 0x03ff) + 0xdc00, 0, TRUE); 04048 } else { 04049 ME_Char(editor, wParam, 0, TRUE); 04050 } 04051 } 04052 return 0; 04053 } 04054 break; 04055 case EM_STOPGROUPTYPING: 04056 ME_CommitUndo(editor); /* End coalesced undos for typed characters */ 04057 return 0; 04058 case WM_HSCROLL: 04059 { 04060 const int scrollUnit = 7; 04061 04062 switch(LOWORD(wParam)) 04063 { 04064 case SB_LEFT: 04065 ME_ScrollAbs(editor, 0, 0); 04066 break; 04067 case SB_RIGHT: 04068 ME_ScrollAbs(editor, 04069 editor->horz_si.nMax - (int)editor->horz_si.nPage, 04070 editor->vert_si.nMax - (int)editor->vert_si.nPage); 04071 break; 04072 case SB_LINELEFT: 04073 ME_ScrollLeft(editor, scrollUnit); 04074 break; 04075 case SB_LINERIGHT: 04076 ME_ScrollRight(editor, scrollUnit); 04077 break; 04078 case SB_PAGELEFT: 04079 ME_ScrollLeft(editor, editor->sizeWindow.cx); 04080 break; 04081 case SB_PAGERIGHT: 04082 ME_ScrollRight(editor, editor->sizeWindow.cx); 04083 break; 04084 case SB_THUMBTRACK: 04085 case SB_THUMBPOSITION: 04086 { 04087 int pos = HIWORD(wParam); 04088 if (editor->horz_si.nMax > 0xffff) 04089 pos = MulDiv(pos, editor->horz_si.nMax, 0xffff); 04090 ME_HScrollAbs(editor, pos); 04091 break; 04092 } 04093 } 04094 break; 04095 } 04096 case EM_SCROLL: /* fall through */ 04097 case WM_VSCROLL: 04098 { 04099 int origNPos; 04100 int lineHeight; 04101 04102 origNPos = editor->vert_si.nPos; 04103 lineHeight = 24; 04104 04105 if (editor->pBuffer && editor->pBuffer->pDefaultStyle) 04106 lineHeight = editor->pBuffer->pDefaultStyle->tm.tmHeight; 04107 if (lineHeight <= 0) lineHeight = 24; 04108 04109 switch(LOWORD(wParam)) 04110 { 04111 case SB_TOP: 04112 ME_ScrollAbs(editor, 0, 0); 04113 break; 04114 case SB_BOTTOM: 04115 ME_ScrollAbs(editor, 04116 editor->horz_si.nMax - (int)editor->horz_si.nPage, 04117 editor->vert_si.nMax - (int)editor->vert_si.nPage); 04118 break; 04119 case SB_LINEUP: 04120 ME_ScrollUp(editor,lineHeight); 04121 break; 04122 case SB_LINEDOWN: 04123 ME_ScrollDown(editor,lineHeight); 04124 break; 04125 case SB_PAGEUP: 04126 ME_ScrollUp(editor,editor->sizeWindow.cy); 04127 break; 04128 case SB_PAGEDOWN: 04129 ME_ScrollDown(editor,editor->sizeWindow.cy); 04130 break; 04131 case SB_THUMBTRACK: 04132 case SB_THUMBPOSITION: 04133 { 04134 int pos = HIWORD(wParam); 04135 if (editor->vert_si.nMax > 0xffff) 04136 pos = MulDiv(pos, editor->vert_si.nMax, 0xffff); 04137 ME_VScrollAbs(editor, pos); 04138 break; 04139 } 04140 } 04141 if (msg == EM_SCROLL) 04142 return 0x00010000 | (((editor->vert_si.nPos - origNPos)/lineHeight) & 0xffff); 04143 break; 04144 } 04145 case WM_MOUSEWHEEL: 04146 { 04147 int gcWheelDelta; 04148 UINT pulScrollLines; 04149 BOOL ctrl_is_down; 04150 04151 if ((editor->nEventMask & ENM_MOUSEEVENTS) && 04152 !ME_FilterEvent(editor, msg, &wParam, &lParam)) 04153 return 0; 04154 04155 ctrl_is_down = GetKeyState(VK_CONTROL) & 0x8000; 04156 04157 gcWheelDelta = GET_WHEEL_DELTA_WPARAM(wParam); 04158 04159 if (abs(gcWheelDelta) >= WHEEL_DELTA) 04160 { 04161 if (ctrl_is_down) { 04162 int numerator; 04163 if (!editor->nZoomNumerator || !editor->nZoomDenominator) 04164 { 04165 numerator = 100; 04166 } else { 04167 numerator = editor->nZoomNumerator * 100 / editor->nZoomDenominator; 04168 } 04169 numerator = numerator + (gcWheelDelta / WHEEL_DELTA) * 10; 04170 if (numerator >= 10 && numerator <= 500) 04171 ME_SetZoom(editor, numerator, 100); 04172 } else { 04173 SystemParametersInfoW(SPI_GETWHEELSCROLLLINES,0, &pulScrollLines, 0); 04174 /* FIXME follow the original */ 04175 if (pulScrollLines) 04176 ME_ScrollDown(editor,pulScrollLines * (-gcWheelDelta / WHEEL_DELTA) * 8); 04177 } 04178 } 04179 break; 04180 } 04181 case EM_GETRECT: 04182 { 04183 *((RECT *)lParam) = editor->rcFormat; 04184 if (editor->bDefaultFormatRect) 04185 ((RECT *)lParam)->left -= editor->selofs; 04186 return 0; 04187 } 04188 case EM_SETRECT: 04189 case EM_SETRECTNP: 04190 { 04191 if (lParam) 04192 { 04193 int border = 0; 04194 RECT clientRect; 04195 RECT *rc = (RECT *)lParam; 04196 04197 border = editor->exStyleFlags & WS_EX_CLIENTEDGE ? 1 : 0; 04198 ITextHost_TxGetClientRect(editor->texthost, &clientRect); 04199 if (wParam == 0) 04200 { 04201 editor->rcFormat.top = max(0, rc->top - border); 04202 editor->rcFormat.left = max(0, rc->left - border); 04203 editor->rcFormat.bottom = min(clientRect.bottom, rc->bottom); 04204 editor->rcFormat.right = min(clientRect.right, rc->right + border); 04205 } else if (wParam == 1) { 04206 /* MSDN incorrectly says a wParam value of 1 causes the 04207 * lParam rect to be used as a relative offset, 04208 * however, the tests show it just prevents min/max bound 04209 * checking. */ 04210 editor->rcFormat.top = rc->top - border; 04211 editor->rcFormat.left = rc->left - border; 04212 editor->rcFormat.bottom = rc->bottom; 04213 editor->rcFormat.right = rc->right + border; 04214 } else { 04215 return 0; 04216 } 04217 editor->bDefaultFormatRect = FALSE; 04218 } 04219 else 04220 { 04221 ME_SetDefaultFormatRect(editor); 04222 editor->bDefaultFormatRect = TRUE; 04223 } 04224 ME_MarkAllForWrapping(editor); 04225 ME_WrapMarkedParagraphs(editor); 04226 ME_UpdateScrollBar(editor); 04227 if (msg != EM_SETRECTNP) 04228 ME_Repaint(editor); 04229 return 0; 04230 } 04231 case EM_REQUESTRESIZE: 04232 ME_SendRequestResize(editor, TRUE); 04233 return 0; 04234 case WM_SETREDRAW: 04235 goto do_default; 04236 case WM_SIZE: 04237 { 04238 RECT clientRect; 04239 04240 ITextHost_TxGetClientRect(editor->texthost, &clientRect); 04241 if (editor->bDefaultFormatRect) { 04242 ME_SetDefaultFormatRect(editor); 04243 } else { 04244 editor->rcFormat.right += clientRect.right - editor->prevClientRect.right; 04245 editor->rcFormat.bottom += clientRect.bottom - editor->prevClientRect.bottom; 04246 } 04247 editor->prevClientRect = clientRect; 04248 ME_RewrapRepaint(editor); 04249 goto do_default; 04250 } 04251 /* IME messages to make richedit controls IME aware */ 04252 case WM_IME_SETCONTEXT: 04253 case WM_IME_CONTROL: 04254 case WM_IME_SELECT: 04255 case WM_IME_COMPOSITIONFULL: 04256 return 0; 04257 case WM_IME_STARTCOMPOSITION: 04258 { 04259 editor->imeStartIndex=ME_GetCursorOfs(&editor->pCursors[0]); 04260 ME_DeleteSelection(editor); 04261 ME_CommitUndo(editor); 04262 ME_UpdateRepaint(editor, FALSE); 04263 return 0; 04264 } 04265 case WM_IME_COMPOSITION: 04266 { 04267 HIMC hIMC; 04268 04269 ME_Style *style = ME_GetInsertStyle(editor, 0); 04270 hIMC = ITextHost_TxImmGetContext(editor->texthost); 04271 ME_DeleteSelection(editor); 04272 ME_SaveTempStyle(editor); 04273 if (lParam & (GCS_RESULTSTR|GCS_COMPSTR)) 04274 { 04275 LPWSTR lpCompStr = NULL; 04276 DWORD dwBufLen; 04277 DWORD dwIndex = lParam & GCS_RESULTSTR; 04278 if (!dwIndex) 04279 dwIndex = GCS_COMPSTR; 04280 04281 dwBufLen = ImmGetCompositionStringW(hIMC, dwIndex, NULL, 0); 04282 lpCompStr = HeapAlloc(GetProcessHeap(),0,dwBufLen + sizeof(WCHAR)); 04283 ImmGetCompositionStringW(hIMC, dwIndex, lpCompStr, dwBufLen); 04284 lpCompStr[dwBufLen/sizeof(WCHAR)] = 0; 04285 ME_InsertTextFromCursor(editor,0,lpCompStr,dwBufLen/sizeof(WCHAR),style); 04286 HeapFree(GetProcessHeap(), 0, lpCompStr); 04287 04288 if (dwIndex == GCS_COMPSTR) 04289 ME_SetSelection(editor,editor->imeStartIndex, 04290 editor->imeStartIndex + dwBufLen/sizeof(WCHAR)); 04291 } 04292 ME_ReleaseStyle(style); 04293 ME_CommitUndo(editor); 04294 ME_UpdateRepaint(editor, FALSE); 04295 return 0; 04296 } 04297 case WM_IME_ENDCOMPOSITION: 04298 { 04299 ME_DeleteSelection(editor); 04300 editor->imeStartIndex=-1; 04301 return 0; 04302 } 04303 case EM_GETOLEINTERFACE: 04304 { 04305 LPVOID *ppvObj = (LPVOID*) lParam; 04306 return CreateIRichEditOle(editor, ppvObj); 04307 } 04308 case EM_GETPASSWORDCHAR: 04309 { 04310 return editor->cPasswordMask; 04311 } 04312 case EM_SETOLECALLBACK: 04313 if(editor->lpOleCallback) 04314 IUnknown_Release(editor->lpOleCallback); 04315 editor->lpOleCallback = (LPRICHEDITOLECALLBACK)lParam; 04316 if(editor->lpOleCallback) 04317 IUnknown_AddRef(editor->lpOleCallback); 04318 return TRUE; 04319 case EM_GETWORDBREAKPROC: 04320 return (LRESULT)editor->pfnWordBreak; 04321 case EM_SETWORDBREAKPROC: 04322 { 04323 EDITWORDBREAKPROCW pfnOld = editor->pfnWordBreak; 04324 04325 editor->pfnWordBreak = (EDITWORDBREAKPROCW)lParam; 04326 return (LRESULT)pfnOld; 04327 } 04328 case EM_GETTEXTMODE: 04329 return editor->mode; 04330 case EM_SETTEXTMODE: 04331 { 04332 int mask = 0; 04333 int changes = 0; 04334 04335 if (ME_GetTextLength(editor) || editor->pUndoStack || editor->pRedoStack) 04336 return E_UNEXPECTED; 04337 04338 /* Check for mutually exclusive flags in adjacent bits of wParam */ 04339 if ((wParam & (TM_RICHTEXT | TM_MULTILEVELUNDO | TM_MULTICODEPAGE)) & 04340 (wParam & (TM_PLAINTEXT | TM_SINGLELEVELUNDO | TM_SINGLECODEPAGE)) << 1) 04341 return E_INVALIDARG; 04342 04343 if (wParam & (TM_RICHTEXT | TM_PLAINTEXT)) 04344 { 04345 mask |= TM_RICHTEXT | TM_PLAINTEXT; 04346 changes |= wParam & (TM_RICHTEXT | TM_PLAINTEXT); 04347 if (wParam & TM_PLAINTEXT) { 04348 /* Clear selection since it should be possible to select the 04349 * end of text run for rich text */ 04350 ME_InvalidateSelection(editor); 04351 ME_SetCursorToStart(editor, &editor->pCursors[0]); 04352 editor->pCursors[1] = editor->pCursors[0]; 04353 /* plain text can only have the default style. */ 04354 ME_ClearTempStyle(editor); 04355 ME_AddRefStyle(editor->pBuffer->pDefaultStyle); 04356 ME_ReleaseStyle(editor->pCursors[0].pRun->member.run.style); 04357 editor->pCursors[0].pRun->member.run.style = editor->pBuffer->pDefaultStyle; 04358 } 04359 } 04360 /* FIXME: Currently no support for undo level and code page options */ 04361 editor->mode = (editor->mode & ~mask) | changes; 04362 return 0; 04363 } 04364 case EM_SETPASSWORDCHAR: 04365 { 04366 editor->cPasswordMask = wParam; 04367 ME_RewrapRepaint(editor); 04368 return 0; 04369 } 04370 case EM_SETTARGETDEVICE: 04371 if (wParam == 0) 04372 { 04373 BOOL new = (lParam == 0 && (editor->styleFlags & ES_MULTILINE)); 04374 if (editor->nAvailWidth || editor->bWordWrap != new) 04375 { 04376 editor->bWordWrap = new; 04377 editor->nAvailWidth = 0; /* wrap to client area */ 04378 ME_RewrapRepaint(editor); 04379 } 04380 } else { 04381 int width = max(0, lParam); 04382 if ((editor->styleFlags & ES_MULTILINE) && 04383 (!editor->bWordWrap || editor->nAvailWidth != width)) 04384 { 04385 editor->nAvailWidth = width; 04386 editor->bWordWrap = TRUE; 04387 ME_RewrapRepaint(editor); 04388 } 04389 FIXME("EM_SETTARGETDEVICE doesn't use non-NULL target devices\n"); 04390 } 04391 return TRUE; 04392 default: 04393 do_default: 04394 *phresult = S_FALSE; 04395 break; 04396 } 04397 return 0L; 04398 } 04399 04400 static LRESULT RichEditWndProc_common(HWND hWnd, UINT msg, WPARAM wParam, 04401 LPARAM lParam, BOOL unicode) 04402 { 04403 ME_TextEditor *editor; 04404 HRESULT hresult; 04405 LRESULT lresult = 0; 04406 04407 TRACE("enter hwnd %p msg %04x (%s) %lx %lx, unicode %d\n", 04408 hWnd, msg, get_msg_name(msg), wParam, lParam, unicode); 04409 04410 editor = (ME_TextEditor *)GetWindowLongPtrW(hWnd, 0); 04411 if (!editor) 04412 { 04413 if (msg == WM_NCCREATE) 04414 { 04415 CREATESTRUCTW *pcs = (CREATESTRUCTW *)lParam; 04416 ITextHost *texthost; 04417 04418 TRACE("WM_NCCREATE: hWnd %p style 0x%08x\n", hWnd, pcs->style); 04419 texthost = ME_CreateTextHost(hWnd, pcs, FALSE); 04420 return texthost != NULL; 04421 } 04422 else 04423 { 04424 return DefWindowProcW(hWnd, msg, wParam, lParam); 04425 } 04426 } 04427 04428 switch (msg) 04429 { 04430 case WM_PAINT: 04431 { 04432 HDC hDC; 04433 RECT rc; 04434 PAINTSTRUCT ps; 04435 04436 hDC = BeginPaint(editor->hWnd, &ps); 04437 if (!editor->bEmulateVersion10 || (editor->nEventMask & ENM_UPDATE)) 04438 ME_SendOldNotify(editor, EN_UPDATE); 04439 /* Erase area outside of the formatting rectangle */ 04440 if (ps.rcPaint.top < editor->rcFormat.top) 04441 { 04442 rc = ps.rcPaint; 04443 rc.bottom = editor->rcFormat.top; 04444 FillRect(hDC, &rc, editor->hbrBackground); 04445 ps.rcPaint.top = editor->rcFormat.top; 04446 } 04447 if (ps.rcPaint.bottom > editor->rcFormat.bottom) { 04448 rc = ps.rcPaint; 04449 rc.top = editor->rcFormat.bottom; 04450 FillRect(hDC, &rc, editor->hbrBackground); 04451 ps.rcPaint.bottom = editor->rcFormat.bottom; 04452 } 04453 if (ps.rcPaint.left < editor->rcFormat.left) { 04454 rc = ps.rcPaint; 04455 rc.right = editor->rcFormat.left; 04456 FillRect(hDC, &rc, editor->hbrBackground); 04457 ps.rcPaint.left = editor->rcFormat.left; 04458 } 04459 if (ps.rcPaint.right > editor->rcFormat.right) { 04460 rc = ps.rcPaint; 04461 rc.left = editor->rcFormat.right; 04462 FillRect(hDC, &rc, editor->hbrBackground); 04463 ps.rcPaint.right = editor->rcFormat.right; 04464 } 04465 04466 ME_PaintContent(editor, hDC, &ps.rcPaint); 04467 EndPaint(editor->hWnd, &ps); 04468 return 0; 04469 } 04470 case WM_ERASEBKGND: 04471 { 04472 HDC hDC = (HDC)wParam; 04473 RECT rc; 04474 04475 if (GetUpdateRect(editor->hWnd, &rc, TRUE)) 04476 FillRect(hDC, &rc, editor->hbrBackground); 04477 return 1; 04478 } 04479 case EM_SETOPTIONS: 04480 { 04481 DWORD dwStyle; 04482 const DWORD mask = ECO_VERTICAL | ECO_AUTOHSCROLL | ECO_AUTOVSCROLL | 04483 ECO_NOHIDESEL | ECO_READONLY | ECO_WANTRETURN | 04484 ECO_SELECTIONBAR; 04485 lresult = ME_HandleMessage(editor, msg, wParam, lParam, unicode, &hresult); 04486 dwStyle = GetWindowLongW(hWnd, GWL_STYLE); 04487 dwStyle = (dwStyle & ~mask) | (lresult & mask); 04488 SetWindowLongW(hWnd, GWL_STYLE, dwStyle); 04489 return lresult; 04490 } 04491 case EM_SETREADONLY: 04492 { 04493 DWORD dwStyle; 04494 lresult = ME_HandleMessage(editor, msg, wParam, lParam, unicode, &hresult); 04495 dwStyle = GetWindowLongW(hWnd, GWL_STYLE); 04496 dwStyle &= ~ES_READONLY; 04497 if (wParam) 04498 dwStyle |= ES_READONLY; 04499 SetWindowLongW(hWnd, GWL_STYLE, dwStyle); 04500 return lresult; 04501 } 04502 default: 04503 lresult = ME_HandleMessage(editor, msg, wParam, lParam, unicode, &hresult); 04504 } 04505 04506 if (hresult == S_FALSE) 04507 lresult = DefWindowProcW(hWnd, msg, wParam, lParam); 04508 04509 TRACE("exit hwnd %p msg %04x (%s) %lx %lx, unicode %d -> %lu\n", 04510 hWnd, msg, get_msg_name(msg), wParam, lParam, unicode, lresult); 04511 04512 return lresult; 04513 } 04514 04515 static LRESULT WINAPI RichEditWndProcW(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) 04516 { 04517 BOOL unicode = TRUE; 04518 04519 /* Under Win9x RichEdit20W returns ANSI strings, see the tests. */ 04520 if (msg == WM_GETTEXT && (GetVersion() & 0x80000000)) 04521 unicode = FALSE; 04522 04523 return RichEditWndProc_common(hWnd, msg, wParam, lParam, unicode); 04524 } 04525 04526 static LRESULT WINAPI RichEditWndProcA(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) 04527 { 04528 return RichEditWndProc_common(hWnd, msg, wParam, lParam, FALSE); 04529 } 04530 04531 /****************************************************************** 04532 * RichEditANSIWndProc (RICHED20.10) 04533 */ 04534 LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) 04535 { 04536 return RichEditWndProcA(hWnd, msg, wParam, lParam); 04537 } 04538 04539 /****************************************************************** 04540 * RichEdit10ANSIWndProc (RICHED20.9) 04541 */ 04542 LRESULT WINAPI RichEdit10ANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) 04543 { 04544 if (msg == WM_NCCREATE && !GetWindowLongPtrW(hWnd, 0)) 04545 { 04546 ITextHost *texthost; 04547 CREATESTRUCTW *pcs = (CREATESTRUCTW *)lParam; 04548 04549 TRACE("WM_NCCREATE: hWnd %p style 0x%08x\n", hWnd, pcs->style); 04550 texthost = ME_CreateTextHost(hWnd, pcs, TRUE); 04551 return texthost != NULL; 04552 } 04553 return RichEditANSIWndProc(hWnd, msg, wParam, lParam); 04554 } 04555 04556 void ME_SendOldNotify(ME_TextEditor *editor, int nCode) 04557 { 04558 ITextHost_TxNotify(editor->texthost, nCode, NULL); 04559 } 04560 04561 /* Fill buffer with srcChars unicode characters from the start cursor. 04562 * 04563 * buffer: destination buffer 04564 * buflen: length of buffer in characters excluding the NULL terminator. 04565 * start: start of editor text to copy into buffer. 04566 * srcChars: Number of characters to use from the editor text. 04567 * bCRLF: if true, replaces all end of lines with \r\n pairs. 04568 * 04569 * returns the number of characters written excluding the NULL terminator. 04570 * 04571 * The written text is always NULL terminated. 04572 */ 04573 int ME_GetTextW(ME_TextEditor *editor, WCHAR *buffer, int buflen, 04574 const ME_Cursor *start, int srcChars, BOOL bCRLF) 04575 { 04576 ME_DisplayItem *pRun, *pNextRun; 04577 const WCHAR *pStart = buffer; 04578 const WCHAR cr_lf[] = {'\r', '\n', 0}; 04579 const WCHAR *str; 04580 int nLen; 04581 04582 /* bCRLF flag is only honored in 2.0 and up. 1.0 must always return text verbatim */ 04583 if (editor->bEmulateVersion10) bCRLF = 0; 04584 04585 pRun = start->pRun; 04586 assert(pRun); 04587 pNextRun = ME_FindItemFwd(pRun, diRun); 04588 04589 nLen = pRun->member.run.strText->nLen - start->nOffset; 04590 str = pRun->member.run.strText->szData + start->nOffset; 04591 04592 /* No '\r' is appended to the last paragraph. */ 04593 while (srcChars && buflen && pNextRun) 04594 { 04595 int nFlags = pRun->member.run.nFlags; 04596 04597 if (bCRLF && nFlags & MERF_ENDPARA && ~nFlags & MERF_ENDCELL) 04598 { 04599 if (buflen == 1) break; 04600 /* FIXME: native fails to reduce srcChars here for WM_GETTEXT or 04601 * EM_GETTEXTEX, however, this is done for copying text which 04602 * also uses this function. */ 04603 srcChars -= min(nLen, srcChars); 04604 nLen = 2; 04605 str = cr_lf; 04606 } else { 04607 nLen = min(nLen, srcChars); 04608 srcChars -= nLen; 04609 } 04610 04611 nLen = min(nLen, buflen); 04612 buflen -= nLen; 04613 04614 CopyMemory(buffer, str, sizeof(WCHAR) * nLen); 04615 04616 buffer += nLen; 04617 04618 pRun = pNextRun; 04619 pNextRun = ME_FindItemFwd(pRun, diRun); 04620 04621 nLen = pRun->member.run.strText->nLen; 04622 str = pRun->member.run.strText->szData; 04623 } 04624 *buffer = 0; 04625 return buffer - pStart; 04626 } 04627 04628 static BOOL ME_RegisterEditorClass(HINSTANCE hInstance) 04629 { 04630 WNDCLASSW wcW; 04631 WNDCLASSA wcA; 04632 04633 wcW.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW | CS_GLOBALCLASS; 04634 wcW.lpfnWndProc = RichEditWndProcW; 04635 wcW.cbClsExtra = 0; 04636 wcW.cbWndExtra = sizeof(ME_TextEditor *); 04637 wcW.hInstance = NULL; /* hInstance would register DLL-local class */ 04638 wcW.hIcon = NULL; 04639 wcW.hCursor = LoadCursorW(NULL, MAKEINTRESOURCEW(IDC_IBEAM)); 04640 wcW.hbrBackground = GetStockObject(NULL_BRUSH); 04641 wcW.lpszMenuName = NULL; 04642 04643 if (is_version_nt()) 04644 { 04645 wcW.lpszClassName = RICHEDIT_CLASS20W; 04646 if (!RegisterClassW(&wcW)) return FALSE; 04647 wcW.lpszClassName = MSFTEDIT_CLASS; 04648 if (!RegisterClassW(&wcW)) return FALSE; 04649 } 04650 else 04651 { 04652 /* WNDCLASSA/W have the same layout */ 04653 wcW.lpszClassName = (LPCWSTR)"RichEdit20W"; 04654 if (!RegisterClassA((WNDCLASSA *)&wcW)) return FALSE; 04655 wcW.lpszClassName = (LPCWSTR)"RichEdit50W"; 04656 if (!RegisterClassA((WNDCLASSA *)&wcW)) return FALSE; 04657 } 04658 04659 wcA.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW | CS_GLOBALCLASS; 04660 wcA.lpfnWndProc = RichEditWndProcA; 04661 wcA.cbClsExtra = 0; 04662 wcA.cbWndExtra = sizeof(ME_TextEditor *); 04663 wcA.hInstance = NULL; /* hInstance would register DLL-local class */ 04664 wcA.hIcon = NULL; 04665 wcA.hCursor = LoadCursorW(NULL, MAKEINTRESOURCEW(IDC_IBEAM)); 04666 wcA.hbrBackground = GetStockObject(NULL_BRUSH); 04667 wcA.lpszMenuName = NULL; 04668 wcA.lpszClassName = RICHEDIT_CLASS20A; 04669 if (!RegisterClassA(&wcA)) return FALSE; 04670 wcA.lpszClassName = "RichEdit50A"; 04671 if (!RegisterClassA(&wcA)) return FALSE; 04672 04673 return TRUE; 04674 } 04675 04676 static LRESULT WINAPI REComboWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { 04677 /* FIXME: Not implemented */ 04678 TRACE("hWnd %p msg %04x (%s) %08lx %08lx\n", 04679 hWnd, msg, get_msg_name(msg), wParam, lParam); 04680 return DefWindowProcW(hWnd, msg, wParam, lParam); 04681 } 04682 04683 static LRESULT WINAPI REListWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { 04684 /* FIXME: Not implemented */ 04685 TRACE("hWnd %p msg %04x (%s) %08lx %08lx\n", 04686 hWnd, msg, get_msg_name(msg), wParam, lParam); 04687 return DefWindowProcW(hWnd, msg, wParam, lParam); 04688 } 04689 04690 /****************************************************************** 04691 * REExtendedRegisterClass (RICHED20.8) 04692 * 04693 * FIXME undocumented 04694 * Need to check for errors and implement controls and callbacks 04695 */ 04696 LRESULT WINAPI REExtendedRegisterClass(void) 04697 { 04698 WNDCLASSW wcW; 04699 UINT result; 04700 04701 FIXME("semi stub\n"); 04702 04703 wcW.cbClsExtra = 0; 04704 wcW.cbWndExtra = 4; 04705 wcW.hInstance = NULL; 04706 wcW.hIcon = NULL; 04707 wcW.hCursor = NULL; 04708 wcW.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); 04709 wcW.lpszMenuName = NULL; 04710 04711 if (!ME_ListBoxRegistered) 04712 { 04713 wcW.style = CS_PARENTDC | CS_DBLCLKS | CS_GLOBALCLASS; 04714 wcW.lpfnWndProc = REListWndProc; 04715 wcW.lpszClassName = REListBox20W; 04716 if (RegisterClassW(&wcW)) ME_ListBoxRegistered = TRUE; 04717 } 04718 04719 if (!ME_ComboBoxRegistered) 04720 { 04721 wcW.style = CS_PARENTDC | CS_DBLCLKS | CS_GLOBALCLASS | CS_VREDRAW | CS_HREDRAW; 04722 wcW.lpfnWndProc = REComboWndProc; 04723 wcW.lpszClassName = REComboBox20W; 04724 if (RegisterClassW(&wcW)) ME_ComboBoxRegistered = TRUE; 04725 } 04726 04727 result = 0; 04728 if (ME_ListBoxRegistered) 04729 result += 1; 04730 if (ME_ComboBoxRegistered) 04731 result += 2; 04732 04733 return result; 04734 } 04735 04736 static BOOL isurlspecial(WCHAR c) 04737 { 04738 static const WCHAR special_chars[] = {'.','/','%','@','*','|','\\','+','#',0}; 04739 return strchrW( special_chars, c ) != NULL; 04740 } 04741 04749 static BOOL ME_FindNextURLCandidate(ME_TextEditor *editor, 04750 const ME_Cursor *start, 04751 int nChars, 04752 ME_Cursor *candidate_min, 04753 ME_Cursor *candidate_max) 04754 { 04755 ME_Cursor cursor = *start; 04756 BOOL foundColon = FALSE; 04757 BOOL candidateStarted = FALSE; 04758 WCHAR lastAcceptedChar = '\0'; 04759 04760 while (nChars > 0) 04761 { 04762 WCHAR *strStart = cursor.pRun->member.run.strText->szData; 04763 WCHAR *str = strStart + cursor.nOffset; 04764 int nLen = cursor.pRun->member.run.strText->nLen - cursor.nOffset; 04765 nChars -= nLen; 04766 04767 if (~cursor.pRun->member.run.nFlags & MERF_ENDPARA) 04768 { 04769 /* Find start of candidate */ 04770 if (!candidateStarted) 04771 { 04772 while (nLen) 04773 { 04774 nLen--; 04775 if (isalnumW(*str) || isurlspecial(*str)) 04776 { 04777 cursor.nOffset = str - strStart; 04778 *candidate_min = cursor; 04779 candidateStarted = TRUE; 04780 lastAcceptedChar = *str++; 04781 break; 04782 } 04783 str++; 04784 } 04785 } 04786 04787 /* Find end of candidate */ 04788 if (candidateStarted) { 04789 while (nLen) 04790 { 04791 nLen--; 04792 if (*str == ':' && !foundColon) { 04793 foundColon = TRUE; 04794 } else if (!isalnumW(*str) && !isurlspecial(*str)) { 04795 cursor.nOffset = str - strStart; 04796 if (lastAcceptedChar == ':') 04797 ME_MoveCursorChars(editor, &cursor, -1); 04798 *candidate_max = cursor; 04799 return TRUE; 04800 } 04801 lastAcceptedChar = *str++; 04802 } 04803 } 04804 } else { 04805 /* End of paragraph: skip it if before candidate span, or terminates 04806 current active span */ 04807 if (candidateStarted) { 04808 if (lastAcceptedChar == ':') 04809 ME_MoveCursorChars(editor, &cursor, -1); 04810 *candidate_max = cursor; 04811 return TRUE; 04812 } 04813 } 04814 04815 /* Reaching this point means no span was found, so get next span */ 04816 if (!ME_NextRun(&cursor.pPara, &cursor.pRun)) { 04817 if (candidateStarted) { 04818 /* There are no further runs, so take end of text as end of candidate */ 04819 cursor.nOffset = str - strStart; 04820 if (lastAcceptedChar == ':') 04821 ME_MoveCursorChars(editor, &cursor, -1); 04822 *candidate_max = cursor; 04823 return TRUE; 04824 } 04825 *candidate_max = *candidate_min = cursor; 04826 return FALSE; 04827 } 04828 cursor.nOffset = 0; 04829 } 04830 04831 if (candidateStarted) { 04832 /* There are no further runs, so take end of text as end of candidate */ 04833 if (lastAcceptedChar == ':') 04834 ME_MoveCursorChars(editor, &cursor, -1); 04835 *candidate_max = cursor; 04836 return TRUE; 04837 } 04838 *candidate_max = *candidate_min = cursor; 04839 return FALSE; 04840 } 04841 04845 static BOOL ME_IsCandidateAnURL(ME_TextEditor *editor, const ME_Cursor *start, int nChars) 04846 { 04847 #define MAX_PREFIX_LEN 9 04848 struct prefix_s { 04849 const WCHAR text[MAX_PREFIX_LEN]; 04850 int length; 04851 }prefixes[] = { 04852 {{'p','r','o','s','p','e','r','o',':'}, 9}, 04853 {{'t','e','l','n','e','t',':'}, 7}, 04854 {{'g','o','p','h','e','r',':'}, 7}, 04855 {{'m','a','i','l','t','o',':'}, 7}, 04856 {{'h','t','t','p','s',':'}, 6}, 04857 {{'f','i','l','e',':'}, 5}, 04858 {{'n','e','w','s',':'}, 5}, 04859 {{'w','a','i','s',':'}, 5}, 04860 {{'n','n','t','p',':'}, 5}, 04861 {{'h','t','t','p',':'}, 5}, 04862 {{'w','w','w','.'}, 4}, 04863 {{'f','t','p',':'}, 4}, 04864 }; 04865 WCHAR bufferW[MAX_PREFIX_LEN + 1]; 04866 unsigned int i; 04867 04868 ME_GetTextW(editor, bufferW, MAX_PREFIX_LEN, start, nChars, 0); 04869 for (i = 0; i < sizeof(prefixes) / sizeof(*prefixes); i++) 04870 { 04871 if (nChars < prefixes[i].length) continue; 04872 if (!memcmp(prefixes[i].text, bufferW, prefixes[i].length * sizeof(WCHAR))) 04873 return TRUE; 04874 } 04875 return FALSE; 04876 #undef MAX_PREFIX_LEN 04877 } 04878 04892 static BOOL ME_UpdateLinkAttribute(ME_TextEditor *editor, ME_Cursor *start, int nChars) 04893 { 04894 BOOL modified = FALSE; 04895 ME_Cursor startCur = *start; 04896 04897 if (!editor->AutoURLDetect_bEnable) return FALSE; 04898 04899 do 04900 { 04901 CHARFORMAT2W link; 04902 ME_Cursor candidateStart, candidateEnd; 04903 04904 if (ME_FindNextURLCandidate(editor, &startCur, nChars, 04905 &candidateStart, &candidateEnd)) 04906 { 04907 /* Section before candidate is not an URL */ 04908 int cMin = ME_GetCursorOfs(&candidateStart); 04909 int cMax = ME_GetCursorOfs(&candidateEnd); 04910 04911 if (!ME_IsCandidateAnURL(editor, &candidateStart, cMax - cMin)) 04912 candidateStart = candidateEnd; 04913 nChars -= cMax - ME_GetCursorOfs(&startCur); 04914 } 04915 else 04916 { 04917 /* No more candidates until end of selection */ 04918 nChars = 0; 04919 } 04920 04921 if (startCur.pRun != candidateStart.pRun || 04922 startCur.nOffset != candidateStart.nOffset) 04923 { 04924 /* CFE_LINK effect should be consistently unset */ 04925 link.cbSize = sizeof(link); 04926 ME_GetCharFormat(editor, &startCur, &candidateStart, &link); 04927 if (!(link.dwMask & CFM_LINK) || (link.dwEffects & CFE_LINK)) 04928 { 04929 /* CFE_LINK must be unset from this range */ 04930 memset(&link, 0, sizeof(CHARFORMAT2W)); 04931 link.cbSize = sizeof(link); 04932 link.dwMask = CFM_LINK; 04933 link.dwEffects = 0; 04934 ME_SetCharFormat(editor, &startCur, &candidateStart, &link); 04935 /* Update candidateEnd since setting character formats may split 04936 * runs, which can cause a cursor to be at an invalid offset within 04937 * a split run. */ 04938 while (candidateEnd.nOffset >= candidateEnd.pRun->member.run.strText->nLen) 04939 { 04940 candidateEnd.nOffset -= candidateEnd.pRun->member.run.strText->nLen; 04941 candidateEnd.pRun = ME_FindItemFwd(candidateEnd.pRun, diRun); 04942 } 04943 modified = TRUE; 04944 } 04945 } 04946 if (candidateStart.pRun != candidateEnd.pRun || 04947 candidateStart.nOffset != candidateEnd.nOffset) 04948 { 04949 /* CFE_LINK effect should be consistently set */ 04950 link.cbSize = sizeof(link); 04951 ME_GetCharFormat(editor, &candidateStart, &candidateEnd, &link); 04952 if (!(link.dwMask & CFM_LINK) || !(link.dwEffects & CFE_LINK)) 04953 { 04954 /* CFE_LINK must be set on this range */ 04955 memset(&link, 0, sizeof(CHARFORMAT2W)); 04956 link.cbSize = sizeof(link); 04957 link.dwMask = CFM_LINK; 04958 link.dwEffects = CFE_LINK; 04959 ME_SetCharFormat(editor, &candidateStart, &candidateEnd, &link); 04960 modified = TRUE; 04961 } 04962 } 04963 startCur = candidateEnd; 04964 } while (nChars > 0); 04965 return modified; 04966 } Generated on Sun May 27 2012 04:24:52 for ReactOS by
1.7.6.1
|