Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygentxtrange.c
Go to the documentation of this file.
00001 /* 00002 * Copyright 2006-2007 Jacek Caban for CodeWeavers 00003 * 00004 * This library is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU Lesser General Public 00006 * License as published by the Free Software Foundation; either 00007 * version 2.1 of the License, or (at your option) any later version. 00008 * 00009 * This library is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 * Lesser General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU Lesser General Public 00015 * License along with this library; if not, write to the Free Software 00016 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00017 */ 00018 00019 #include <stdarg.h> 00020 00021 #define COBJMACROS 00022 00023 #include "windef.h" 00024 #include "winbase.h" 00025 #include "winuser.h" 00026 #include "ole2.h" 00027 #include "mshtmcid.h" 00028 00029 #include "wine/debug.h" 00030 #include "wine/unicode.h" 00031 00032 #include "mshtml_private.h" 00033 00034 WINE_DEFAULT_DEBUG_CHANNEL(mshtml); 00035 00036 static const WCHAR brW[] = {'b','r',0}; 00037 static const WCHAR hrW[] = {'h','r',0}; 00038 00039 typedef struct { 00040 const IHTMLTxtRangeVtbl *lpHTMLTxtRangeVtbl; 00041 const IOleCommandTargetVtbl *lpOleCommandTargetVtbl; 00042 00043 LONG ref; 00044 00045 nsIDOMRange *nsrange; 00046 HTMLDocumentNode *doc; 00047 00048 struct list entry; 00049 } HTMLTxtRange; 00050 00051 #define HTMLTXTRANGE(x) ((IHTMLTxtRange*) &(x)->lpHTMLTxtRangeVtbl) 00052 00053 typedef struct { 00054 WCHAR *buf; 00055 DWORD len; 00056 DWORD size; 00057 } wstrbuf_t; 00058 00059 typedef struct { 00060 PRUint16 type; 00061 nsIDOMNode *node; 00062 PRUint32 off; 00063 nsAString str; 00064 const PRUnichar *p; 00065 } dompos_t; 00066 00067 typedef enum { 00068 RU_UNKNOWN, 00069 RU_CHAR, 00070 RU_WORD, 00071 RU_SENTENCE, 00072 RU_TEXTEDIT 00073 } range_unit_t; 00074 00075 static HTMLTxtRange *get_range_object(HTMLDocumentNode *doc, IHTMLTxtRange *iface) 00076 { 00077 HTMLTxtRange *iter; 00078 00079 LIST_FOR_EACH_ENTRY(iter, &doc->range_list, HTMLTxtRange, entry) { 00080 if(HTMLTXTRANGE(iter) == iface) 00081 return iter; 00082 } 00083 00084 ERR("Could not find range in document\n"); 00085 return NULL; 00086 } 00087 00088 static range_unit_t string_to_unit(LPCWSTR str) 00089 { 00090 static const WCHAR characterW[] = 00091 {'c','h','a','r','a','c','t','e','r',0}; 00092 static const WCHAR wordW[] = 00093 {'w','o','r','d',0}; 00094 static const WCHAR sentenceW[] = 00095 {'s','e','n','t','e','n','c','e',0}; 00096 static const WCHAR texteditW[] = 00097 {'t','e','x','t','e','d','i','t',0}; 00098 00099 if(!strcmpiW(str, characterW)) return RU_CHAR; 00100 if(!strcmpiW(str, wordW)) return RU_WORD; 00101 if(!strcmpiW(str, sentenceW)) return RU_SENTENCE; 00102 if(!strcmpiW(str, texteditW)) return RU_TEXTEDIT; 00103 00104 return RU_UNKNOWN; 00105 } 00106 00107 static int string_to_nscmptype(LPCWSTR str) 00108 { 00109 static const WCHAR seW[] = {'S','t','a','r','t','T','o','E','n','d',0}; 00110 static const WCHAR ssW[] = {'S','t','a','r','t','T','o','S','t','a','r','t',0}; 00111 static const WCHAR esW[] = {'E','n','d','T','o','S','t','a','r','t',0}; 00112 static const WCHAR eeW[] = {'E','n','d','T','o','E','n','d',0}; 00113 00114 if(!strcmpiW(str, seW)) return NS_START_TO_END; 00115 if(!strcmpiW(str, ssW)) return NS_START_TO_START; 00116 if(!strcmpiW(str, esW)) return NS_END_TO_START; 00117 if(!strcmpiW(str, eeW)) return NS_END_TO_END; 00118 00119 return -1; 00120 } 00121 00122 static PRUint16 get_node_type(nsIDOMNode *node) 00123 { 00124 PRUint16 type = 0; 00125 00126 if(node) 00127 nsIDOMNode_GetNodeType(node, &type); 00128 00129 return type; 00130 } 00131 00132 static BOOL is_elem_tag(nsIDOMNode *node, LPCWSTR istag) 00133 { 00134 nsIDOMElement *elem; 00135 nsAString tag_str; 00136 const PRUnichar *tag; 00137 BOOL ret = FALSE; 00138 nsresult nsres; 00139 00140 nsres = nsIDOMNode_QueryInterface(node, &IID_nsIDOMElement, (void**)&elem); 00141 if(NS_FAILED(nsres)) 00142 return FALSE; 00143 00144 nsAString_Init(&tag_str, NULL); 00145 nsIDOMElement_GetTagName(elem, &tag_str); 00146 nsIDOMElement_Release(elem); 00147 nsAString_GetData(&tag_str, &tag); 00148 00149 ret = !strcmpiW(tag, istag); 00150 00151 nsAString_Finish(&tag_str); 00152 00153 return ret; 00154 } 00155 00156 static BOOL is_space_elem(nsIDOMNode *node) 00157 { 00158 nsIDOMElement *elem; 00159 nsAString tag_str; 00160 const PRUnichar *tag; 00161 BOOL ret = FALSE; 00162 nsresult nsres; 00163 00164 nsres = nsIDOMNode_QueryInterface(node, &IID_nsIDOMElement, (void**)&elem); 00165 if(NS_FAILED(nsres)) 00166 return FALSE; 00167 00168 nsAString_Init(&tag_str, NULL); 00169 nsIDOMElement_GetTagName(elem, &tag_str); 00170 nsIDOMElement_Release(elem); 00171 nsAString_GetData(&tag_str, &tag); 00172 00173 ret = !strcmpiW(tag, brW) || !strcmpiW(tag, hrW); 00174 00175 nsAString_Finish(&tag_str); 00176 00177 return ret; 00178 } 00179 00180 static inline BOOL wstrbuf_init(wstrbuf_t *buf) 00181 { 00182 buf->len = 0; 00183 buf->size = 16; 00184 buf->buf = heap_alloc(buf->size * sizeof(WCHAR)); 00185 if (!buf->buf) return FALSE; 00186 *buf->buf = 0; 00187 return TRUE; 00188 } 00189 00190 static inline void wstrbuf_finish(wstrbuf_t *buf) 00191 { 00192 heap_free(buf->buf); 00193 } 00194 00195 static void wstrbuf_append_len(wstrbuf_t *buf, LPCWSTR str, int len) 00196 { 00197 if(buf->len+len >= buf->size) { 00198 buf->size = 2*buf->size+len; 00199 buf->buf = heap_realloc(buf->buf, buf->size * sizeof(WCHAR)); 00200 } 00201 00202 memcpy(buf->buf+buf->len, str, len*sizeof(WCHAR)); 00203 buf->len += len; 00204 buf->buf[buf->len] = 0; 00205 } 00206 00207 static void wstrbuf_append_nodetxt(wstrbuf_t *buf, LPCWSTR str, int len) 00208 { 00209 const WCHAR *s = str; 00210 WCHAR *d; 00211 00212 TRACE("%s\n", debugstr_wn(str, len)); 00213 00214 if(buf->len+len >= buf->size) { 00215 buf->size = 2*buf->size+len; 00216 buf->buf = heap_realloc(buf->buf, buf->size * sizeof(WCHAR)); 00217 } 00218 00219 if(buf->len && isspaceW(buf->buf[buf->len-1])) { 00220 while(s < str+len && isspaceW(*s)) 00221 s++; 00222 } 00223 00224 d = buf->buf+buf->len; 00225 while(s < str+len) { 00226 if(isspaceW(*s)) { 00227 *d++ = ' '; 00228 s++; 00229 while(s < str+len && isspaceW(*s)) 00230 s++; 00231 }else { 00232 *d++ = *s++; 00233 } 00234 } 00235 00236 buf->len = d - buf->buf; 00237 *d = 0; 00238 } 00239 00240 static void wstrbuf_append_node(wstrbuf_t *buf, nsIDOMNode *node) 00241 { 00242 00243 switch(get_node_type(node)) { 00244 case TEXT_NODE: { 00245 nsIDOMText *nstext; 00246 nsAString data_str; 00247 const PRUnichar *data; 00248 00249 nsIDOMNode_QueryInterface(node, &IID_nsIDOMText, (void**)&nstext); 00250 00251 nsAString_Init(&data_str, NULL); 00252 nsIDOMText_GetData(nstext, &data_str); 00253 nsAString_GetData(&data_str, &data); 00254 wstrbuf_append_nodetxt(buf, data, strlenW(data)); 00255 nsAString_Finish(&data_str); 00256 00257 nsIDOMText_Release(nstext); 00258 00259 break; 00260 } 00261 case ELEMENT_NODE: 00262 if(is_elem_tag(node, brW)) { 00263 static const WCHAR endlW[] = {'\r','\n'}; 00264 wstrbuf_append_len(buf, endlW, 2); 00265 }else if(is_elem_tag(node, hrW)) { 00266 static const WCHAR endl2W[] = {'\r','\n','\r','\n'}; 00267 wstrbuf_append_len(buf, endl2W, 4); 00268 } 00269 } 00270 } 00271 00272 static void wstrbuf_append_node_rec(wstrbuf_t *buf, nsIDOMNode *node) 00273 { 00274 nsIDOMNode *iter, *tmp; 00275 00276 wstrbuf_append_node(buf, node); 00277 00278 nsIDOMNode_GetFirstChild(node, &iter); 00279 while(iter) { 00280 wstrbuf_append_node_rec(buf, iter); 00281 nsIDOMNode_GetNextSibling(iter, &tmp); 00282 nsIDOMNode_Release(iter); 00283 iter = tmp; 00284 } 00285 } 00286 00287 static BOOL fill_nodestr(dompos_t *pos) 00288 { 00289 nsIDOMText *text; 00290 nsresult nsres; 00291 00292 if(pos->type != TEXT_NODE) 00293 return FALSE; 00294 00295 nsres = nsIDOMNode_QueryInterface(pos->node, &IID_nsIDOMText, (void**)&text); 00296 if(NS_FAILED(nsres)) 00297 return FALSE; 00298 00299 nsAString_Init(&pos->str, NULL); 00300 nsIDOMText_GetData(text, &pos->str); 00301 nsIDOMText_Release(text); 00302 nsAString_GetData(&pos->str, &pos->p); 00303 00304 if(pos->off == -1) 00305 pos->off = *pos->p ? strlenW(pos->p)-1 : 0; 00306 00307 return TRUE; 00308 } 00309 00310 static nsIDOMNode *next_node(nsIDOMNode *iter) 00311 { 00312 nsIDOMNode *ret, *tmp; 00313 nsresult nsres; 00314 00315 if(!iter) 00316 return NULL; 00317 00318 nsres = nsIDOMNode_GetFirstChild(iter, &ret); 00319 if(NS_SUCCEEDED(nsres) && ret) 00320 return ret; 00321 00322 nsIDOMNode_AddRef(iter); 00323 00324 do { 00325 nsres = nsIDOMNode_GetNextSibling(iter, &ret); 00326 if(NS_SUCCEEDED(nsres) && ret) { 00327 nsIDOMNode_Release(iter); 00328 return ret; 00329 } 00330 00331 nsres = nsIDOMNode_GetParentNode(iter, &tmp); 00332 nsIDOMNode_Release(iter); 00333 iter = tmp; 00334 }while(NS_SUCCEEDED(nsres) && iter); 00335 00336 return NULL; 00337 } 00338 00339 static nsIDOMNode *prev_node(HTMLTxtRange *This, nsIDOMNode *iter) 00340 { 00341 nsIDOMNode *ret, *tmp; 00342 nsresult nsres; 00343 00344 if(!iter) { 00345 nsIDOMHTMLElement *nselem; 00346 00347 nsIDOMHTMLDocument_GetBody(This->doc->nsdoc, &nselem); 00348 nsIDOMElement_GetLastChild(nselem, &tmp); 00349 if(!tmp) 00350 return (nsIDOMNode*)nselem; 00351 00352 while(tmp) { 00353 ret = tmp; 00354 nsIDOMNode_GetLastChild(ret, &tmp); 00355 } 00356 00357 nsIDOMElement_Release(nselem); 00358 00359 return ret; 00360 } 00361 00362 nsres = nsIDOMNode_GetLastChild(iter, &ret); 00363 if(NS_SUCCEEDED(nsres) && ret) 00364 return ret; 00365 00366 nsIDOMNode_AddRef(iter); 00367 00368 do { 00369 nsres = nsIDOMNode_GetPreviousSibling(iter, &ret); 00370 if(NS_SUCCEEDED(nsres) && ret) { 00371 nsIDOMNode_Release(iter); 00372 return ret; 00373 } 00374 00375 nsres = nsIDOMNode_GetParentNode(iter, &tmp); 00376 nsIDOMNode_Release(iter); 00377 iter = tmp; 00378 }while(NS_SUCCEEDED(nsres) && iter); 00379 00380 return NULL; 00381 } 00382 00383 static nsIDOMNode *get_child_node(nsIDOMNode *node, PRUint32 off) 00384 { 00385 nsIDOMNodeList *node_list; 00386 nsIDOMNode *ret = NULL; 00387 00388 nsIDOMNode_GetChildNodes(node, &node_list); 00389 nsIDOMNodeList_Item(node_list, off, &ret); 00390 nsIDOMNodeList_Release(node_list); 00391 00392 return ret; 00393 } 00394 00395 static void get_cur_pos(HTMLTxtRange *This, BOOL start, dompos_t *pos) 00396 { 00397 nsIDOMNode *node; 00398 PRInt32 off; 00399 00400 pos->p = NULL; 00401 00402 if(!start) { 00403 PRBool collapsed; 00404 nsIDOMRange_GetCollapsed(This->nsrange, &collapsed); 00405 start = collapsed; 00406 } 00407 00408 if(start) { 00409 nsIDOMRange_GetStartContainer(This->nsrange, &node); 00410 nsIDOMRange_GetStartOffset(This->nsrange, &off); 00411 }else { 00412 nsIDOMRange_GetEndContainer(This->nsrange, &node); 00413 nsIDOMRange_GetEndOffset(This->nsrange, &off); 00414 } 00415 00416 pos->type = get_node_type(node); 00417 if(pos->type == ELEMENT_NODE) { 00418 if(start) { 00419 pos->node = get_child_node(node, off); 00420 pos->off = 0; 00421 }else { 00422 pos->node = off ? get_child_node(node, off-1) : prev_node(This, node); 00423 pos->off = -1; 00424 } 00425 00426 pos->type = get_node_type(pos->node); 00427 nsIDOMNode_Release(node); 00428 }else if(start) { 00429 pos->node = node; 00430 pos->off = off; 00431 }else if(off) { 00432 pos->node = node; 00433 pos->off = off-1; 00434 }else { 00435 pos->node = prev_node(This, node); 00436 pos->off = -1; 00437 nsIDOMNode_Release(node); 00438 } 00439 00440 if(pos->type == TEXT_NODE) 00441 fill_nodestr(pos); 00442 } 00443 00444 static void set_range_pos(HTMLTxtRange *This, BOOL start, dompos_t *pos) 00445 { 00446 nsresult nsres; 00447 00448 if(start) { 00449 if(pos->type == TEXT_NODE) 00450 nsres = nsIDOMRange_SetStart(This->nsrange, pos->node, pos->off); 00451 else 00452 nsres = nsIDOMRange_SetStartBefore(This->nsrange, pos->node); 00453 }else { 00454 if(pos->type == TEXT_NODE && pos->p[pos->off+1]) 00455 nsres = nsIDOMRange_SetEnd(This->nsrange, pos->node, pos->off+1); 00456 else 00457 nsres = nsIDOMRange_SetEndAfter(This->nsrange, pos->node); 00458 } 00459 00460 if(NS_FAILED(nsres)) 00461 ERR("failed: %p %08x\n", pos->node, nsres); 00462 } 00463 00464 static inline void dompos_release(dompos_t *pos) 00465 { 00466 if(pos->node) 00467 nsIDOMNode_Release(pos->node); 00468 00469 if(pos->p) 00470 nsAString_Finish(&pos->str); 00471 } 00472 00473 static inline void dompos_addref(dompos_t *pos) 00474 { 00475 if(pos->node) 00476 nsIDOMNode_AddRef(pos->node); 00477 00478 if(pos->type == TEXT_NODE) 00479 fill_nodestr(pos); 00480 } 00481 00482 static inline BOOL dompos_cmp(const dompos_t *pos1, const dompos_t *pos2) 00483 { 00484 return pos1->node == pos2->node && pos1->off == pos2->off; 00485 } 00486 00487 static void range_to_string(HTMLTxtRange *This, wstrbuf_t *buf) 00488 { 00489 nsIDOMNode *iter, *tmp; 00490 dompos_t start_pos, end_pos; 00491 PRBool collapsed; 00492 00493 nsIDOMRange_GetCollapsed(This->nsrange, &collapsed); 00494 if(collapsed) { 00495 wstrbuf_finish(buf); 00496 buf->buf = NULL; 00497 buf->size = 0; 00498 return; 00499 } 00500 00501 get_cur_pos(This, FALSE, &end_pos); 00502 get_cur_pos(This, TRUE, &start_pos); 00503 00504 if(start_pos.type == TEXT_NODE) { 00505 if(start_pos.node == end_pos.node) { 00506 wstrbuf_append_nodetxt(buf, start_pos.p+start_pos.off, end_pos.off-start_pos.off+1); 00507 iter = start_pos.node; 00508 nsIDOMNode_AddRef(iter); 00509 }else { 00510 wstrbuf_append_nodetxt(buf, start_pos.p+start_pos.off, strlenW(start_pos.p+start_pos.off)); 00511 iter = next_node(start_pos.node); 00512 } 00513 }else { 00514 iter = start_pos.node; 00515 nsIDOMNode_AddRef(iter); 00516 } 00517 00518 while(iter != end_pos.node) { 00519 wstrbuf_append_node(buf, iter); 00520 tmp = next_node(iter); 00521 nsIDOMNode_Release(iter); 00522 iter = tmp; 00523 } 00524 00525 nsIDOMNode_AddRef(end_pos.node); 00526 00527 if(start_pos.node != end_pos.node) { 00528 if(end_pos.type == TEXT_NODE) 00529 wstrbuf_append_nodetxt(buf, end_pos.p, end_pos.off+1); 00530 else 00531 wstrbuf_append_node(buf, end_pos.node); 00532 } 00533 00534 nsIDOMNode_Release(iter); 00535 dompos_release(&start_pos); 00536 dompos_release(&end_pos); 00537 00538 if(buf->len) { 00539 WCHAR *p; 00540 00541 for(p = buf->buf+buf->len-1; p >= buf->buf && isspaceW(*p); p--); 00542 00543 p = strchrW(p, '\r'); 00544 if(p) 00545 *p = 0; 00546 } 00547 } 00548 00549 HRESULT get_node_text(HTMLDOMNode *node, BSTR *ret) 00550 { 00551 wstrbuf_t buf; 00552 HRESULT hres = S_OK; 00553 00554 if (!wstrbuf_init(&buf)) 00555 return E_OUTOFMEMORY; 00556 wstrbuf_append_node_rec(&buf, node->nsnode); 00557 if(buf.buf) { 00558 *ret = SysAllocString(buf.buf); 00559 if(!*ret) 00560 hres = E_OUTOFMEMORY; 00561 } else { 00562 *ret = NULL; 00563 } 00564 wstrbuf_finish(&buf); 00565 00566 if(SUCCEEDED(hres)) 00567 TRACE("ret %s\n", debugstr_w(*ret)); 00568 return hres; 00569 } 00570 00571 static WCHAR get_pos_char(const dompos_t *pos) 00572 { 00573 switch(pos->type) { 00574 case TEXT_NODE: 00575 return pos->p[pos->off]; 00576 case ELEMENT_NODE: 00577 if(is_space_elem(pos->node)) 00578 return '\n'; 00579 } 00580 00581 return 0; 00582 } 00583 00584 static void end_space(const dompos_t *pos, dompos_t *new_pos) 00585 { 00586 const WCHAR *p; 00587 00588 *new_pos = *pos; 00589 dompos_addref(new_pos); 00590 00591 if(pos->type != TEXT_NODE) 00592 return; 00593 00594 p = new_pos->p+new_pos->off; 00595 00596 if(!*p || !isspace(*p)) 00597 return; 00598 00599 while(p[1] && isspace(p[1])) 00600 p++; 00601 00602 new_pos->off = p - new_pos->p; 00603 } 00604 00605 static WCHAR next_char(const dompos_t *pos, dompos_t *new_pos) 00606 { 00607 nsIDOMNode *iter, *tmp; 00608 dompos_t last_space, tmp_pos; 00609 const WCHAR *p; 00610 WCHAR cspace = 0; 00611 00612 if(pos->type == TEXT_NODE && pos->off != -1 && pos->p[pos->off]) { 00613 p = pos->p+pos->off; 00614 00615 if(isspace(*p)) 00616 while(isspaceW(*++p)); 00617 else 00618 p++; 00619 00620 if(*p && isspaceW(*p)) { 00621 cspace = ' '; 00622 while(p[1] && isspaceW(p[1])) 00623 p++; 00624 } 00625 00626 if(*p) { 00627 *new_pos = *pos; 00628 new_pos->off = p - pos->p; 00629 dompos_addref(new_pos); 00630 00631 return cspace ? cspace : *p; 00632 }else { 00633 last_space = *pos; 00634 last_space.off = p - pos->p; 00635 dompos_addref(&last_space); 00636 } 00637 } 00638 00639 iter = next_node(pos->node); 00640 00641 while(iter) { 00642 switch(get_node_type(iter)) { 00643 case TEXT_NODE: 00644 tmp_pos.node = iter; 00645 tmp_pos.type = TEXT_NODE; 00646 tmp_pos.off = 0; 00647 dompos_addref(&tmp_pos); 00648 00649 p = tmp_pos.p; 00650 00651 if(!*p) { 00652 dompos_release(&tmp_pos); 00653 break; 00654 }else if(isspaceW(*p)) { 00655 if(cspace) 00656 dompos_release(&last_space); 00657 else 00658 cspace = ' '; 00659 00660 while(p[1] && isspaceW(p[1])) 00661 p++; 00662 00663 tmp_pos.off = p-tmp_pos.p; 00664 00665 if(!p[1]) { 00666 last_space = tmp_pos; 00667 break; 00668 } 00669 00670 *new_pos = tmp_pos; 00671 nsIDOMNode_Release(iter); 00672 return cspace; 00673 }else if(cspace) { 00674 *new_pos = last_space; 00675 dompos_release(&tmp_pos); 00676 nsIDOMNode_Release(iter); 00677 00678 return cspace; 00679 }else if(*p) { 00680 tmp_pos.off = 0; 00681 *new_pos = tmp_pos; 00682 } 00683 00684 nsIDOMNode_Release(iter); 00685 return *p; 00686 00687 case ELEMENT_NODE: 00688 if(is_elem_tag(iter, brW)) { 00689 if(cspace) 00690 dompos_release(&last_space); 00691 cspace = '\n'; 00692 00693 nsIDOMNode_AddRef(iter); 00694 last_space.node = iter; 00695 last_space.type = ELEMENT_NODE; 00696 last_space.off = 0; 00697 last_space.p = NULL; 00698 }else if(is_elem_tag(iter, hrW)) { 00699 if(cspace) { 00700 *new_pos = last_space; 00701 nsIDOMNode_Release(iter); 00702 return cspace; 00703 } 00704 00705 new_pos->node = iter; 00706 new_pos->type = ELEMENT_NODE; 00707 new_pos->off = 0; 00708 new_pos->p = NULL; 00709 return '\n'; 00710 } 00711 } 00712 00713 tmp = iter; 00714 iter = next_node(iter); 00715 nsIDOMNode_Release(tmp); 00716 } 00717 00718 if(cspace) { 00719 *new_pos = last_space; 00720 }else { 00721 *new_pos = *pos; 00722 dompos_addref(new_pos); 00723 } 00724 00725 return cspace; 00726 } 00727 00728 static WCHAR prev_char(HTMLTxtRange *This, const dompos_t *pos, dompos_t *new_pos) 00729 { 00730 nsIDOMNode *iter, *tmp; 00731 const WCHAR *p; 00732 BOOL skip_space = FALSE; 00733 00734 if(pos->type == TEXT_NODE && isspaceW(pos->p[pos->off])) 00735 skip_space = TRUE; 00736 00737 if(pos->type == TEXT_NODE && pos->off) { 00738 p = pos->p+pos->off-1; 00739 00740 if(skip_space) { 00741 while(p >= pos->p && isspace(*p)) 00742 p--; 00743 } 00744 00745 if(p >= pos->p) { 00746 *new_pos = *pos; 00747 new_pos->off = p-pos->p; 00748 dompos_addref(new_pos); 00749 return new_pos->p[new_pos->off]; 00750 } 00751 } 00752 00753 iter = prev_node(This, pos->node); 00754 00755 while(iter) { 00756 switch(get_node_type(iter)) { 00757 case TEXT_NODE: { 00758 dompos_t tmp_pos; 00759 00760 tmp_pos.node = iter; 00761 tmp_pos.type = TEXT_NODE; 00762 tmp_pos.off = 0; 00763 dompos_addref(&tmp_pos); 00764 00765 p = tmp_pos.p + strlenW(tmp_pos.p)-1; 00766 00767 if(skip_space) { 00768 while(p >= tmp_pos.p && isspaceW(*p)) 00769 p--; 00770 } 00771 00772 if(p < tmp_pos.p) { 00773 dompos_release(&tmp_pos); 00774 break; 00775 } 00776 00777 tmp_pos.off = p-tmp_pos.p; 00778 *new_pos = tmp_pos; 00779 nsIDOMNode_Release(iter); 00780 return *p; 00781 } 00782 00783 case ELEMENT_NODE: 00784 if(is_elem_tag(iter, brW)) { 00785 if(skip_space) { 00786 skip_space = FALSE; 00787 break; 00788 } 00789 }else if(!is_elem_tag(iter, hrW)) { 00790 break; 00791 } 00792 00793 new_pos->node = iter; 00794 new_pos->type = ELEMENT_NODE; 00795 new_pos->off = 0; 00796 new_pos->p = NULL; 00797 return '\n'; 00798 } 00799 00800 tmp = iter; 00801 iter = prev_node(This, iter); 00802 nsIDOMNode_Release(tmp); 00803 } 00804 00805 *new_pos = *pos; 00806 dompos_addref(new_pos); 00807 return 0; 00808 } 00809 00810 static LONG move_next_chars(LONG cnt, const dompos_t *pos, BOOL col, const dompos_t *bound_pos, 00811 BOOL *bounded, dompos_t *new_pos) 00812 { 00813 dompos_t iter, tmp; 00814 LONG ret = 0; 00815 WCHAR c; 00816 00817 if(bounded) 00818 *bounded = FALSE; 00819 00820 if(col) 00821 ret++; 00822 00823 if(ret >= cnt) { 00824 end_space(pos, new_pos); 00825 return ret; 00826 } 00827 00828 c = next_char(pos, &iter); 00829 ret++; 00830 00831 while(ret < cnt) { 00832 tmp = iter; 00833 c = next_char(&tmp, &iter); 00834 dompos_release(&tmp); 00835 if(!c) 00836 break; 00837 00838 ret++; 00839 if(bound_pos && dompos_cmp(&tmp, bound_pos)) { 00840 *bounded = TRUE; 00841 ret++; 00842 } 00843 } 00844 00845 *new_pos = iter; 00846 return ret; 00847 } 00848 00849 static LONG move_prev_chars(HTMLTxtRange *This, LONG cnt, const dompos_t *pos, BOOL end, 00850 const dompos_t *bound_pos, BOOL *bounded, dompos_t *new_pos) 00851 { 00852 dompos_t iter, tmp; 00853 LONG ret = 0; 00854 BOOL prev_eq = FALSE; 00855 WCHAR c; 00856 00857 if(bounded) 00858 *bounded = FALSE; 00859 00860 c = prev_char(This, pos, &iter); 00861 if(c) 00862 ret++; 00863 00864 while(c && ret < cnt) { 00865 tmp = iter; 00866 c = prev_char(This, &tmp, &iter); 00867 dompos_release(&tmp); 00868 if(!c) { 00869 if(end) 00870 ret++; 00871 break; 00872 } 00873 00874 ret++; 00875 00876 if(prev_eq) { 00877 *bounded = TRUE; 00878 ret++; 00879 } 00880 00881 prev_eq = bound_pos && dompos_cmp(&iter, bound_pos); 00882 } 00883 00884 *new_pos = iter; 00885 return ret; 00886 } 00887 00888 static LONG find_prev_space(HTMLTxtRange *This, const dompos_t *pos, BOOL first_space, dompos_t *ret) 00889 { 00890 dompos_t iter, tmp; 00891 WCHAR c; 00892 00893 c = prev_char(This, pos, &iter); 00894 if(!c || (first_space && isspaceW(c))) { 00895 *ret = iter; 00896 return FALSE; 00897 } 00898 00899 while(1) { 00900 tmp = iter; 00901 c = prev_char(This, &tmp, &iter); 00902 if(!c || isspaceW(c)) { 00903 dompos_release(&iter); 00904 break; 00905 } 00906 dompos_release(&tmp); 00907 } 00908 00909 *ret = tmp; 00910 return TRUE; 00911 } 00912 00913 static int find_word_end(const dompos_t *pos, dompos_t *ret) 00914 { 00915 dompos_t iter, tmp; 00916 int cnt = 1; 00917 WCHAR c; 00918 c = get_pos_char(pos); 00919 if(isspaceW(c)) { 00920 *ret = *pos; 00921 dompos_addref(ret); 00922 return 0; 00923 } 00924 00925 c = next_char(pos, &iter); 00926 if(!c) { 00927 *ret = iter; 00928 return 0; 00929 } 00930 if(c == '\n') { 00931 *ret = *pos; 00932 dompos_addref(ret); 00933 return 0; 00934 } 00935 00936 while(c && !isspaceW(c)) { 00937 tmp = iter; 00938 c = next_char(&tmp, &iter); 00939 if(c == '\n') { 00940 dompos_release(&iter); 00941 iter = tmp; 00942 }else { 00943 cnt++; 00944 dompos_release(&tmp); 00945 } 00946 } 00947 00948 *ret = iter; 00949 return cnt; 00950 } 00951 00952 static LONG move_next_words(LONG cnt, const dompos_t *pos, dompos_t *new_pos) 00953 { 00954 dompos_t iter, tmp; 00955 LONG ret = 0; 00956 WCHAR c; 00957 00958 c = get_pos_char(pos); 00959 if(isspaceW(c)) { 00960 end_space(pos, &iter); 00961 ret++; 00962 }else { 00963 c = next_char(pos, &iter); 00964 if(c && isspaceW(c)) 00965 ret++; 00966 } 00967 00968 while(c && ret < cnt) { 00969 tmp = iter; 00970 c = next_char(&tmp, &iter); 00971 dompos_release(&tmp); 00972 if(isspaceW(c)) 00973 ret++; 00974 } 00975 00976 *new_pos = iter; 00977 return ret; 00978 } 00979 00980 static LONG move_prev_words(HTMLTxtRange *This, LONG cnt, const dompos_t *pos, dompos_t *new_pos) 00981 { 00982 dompos_t iter, tmp; 00983 LONG ret = 0; 00984 00985 iter = *pos; 00986 dompos_addref(&iter); 00987 00988 while(ret < cnt) { 00989 if(!find_prev_space(This, &iter, FALSE, &tmp)) 00990 break; 00991 00992 dompos_release(&iter); 00993 iter = tmp; 00994 ret++; 00995 } 00996 00997 *new_pos = iter; 00998 return ret; 00999 } 01000 01001 #define HTMLTXTRANGE_THIS(iface) DEFINE_THIS(HTMLTxtRange, HTMLTxtRange, iface) 01002 01003 static HRESULT WINAPI HTMLTxtRange_QueryInterface(IHTMLTxtRange *iface, REFIID riid, void **ppv) 01004 { 01005 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface); 01006 01007 *ppv = NULL; 01008 01009 if(IsEqualGUID(&IID_IUnknown, riid)) { 01010 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv); 01011 *ppv = HTMLTXTRANGE(This); 01012 }else if(IsEqualGUID(&IID_IDispatch, riid)) { 01013 TRACE("(%p)->(IID_IDispatch %p)\n", This, ppv); 01014 *ppv = HTMLTXTRANGE(This); 01015 }else if(IsEqualGUID(&IID_IHTMLTxtRange, riid)) { 01016 TRACE("(%p)->(IID_IHTMLTxtRange %p)\n", This, ppv); 01017 *ppv = HTMLTXTRANGE(This); 01018 }else if(IsEqualGUID(&IID_IOleCommandTarget, riid)) { 01019 TRACE("(%p)->(IID_IOleCommandTarget %p)\n", This, ppv); 01020 *ppv = CMDTARGET(This); 01021 } 01022 01023 if(*ppv) { 01024 IUnknown_AddRef((IUnknown*)*ppv); 01025 return S_OK; 01026 } 01027 01028 WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv); 01029 return E_NOINTERFACE; 01030 } 01031 01032 static ULONG WINAPI HTMLTxtRange_AddRef(IHTMLTxtRange *iface) 01033 { 01034 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface); 01035 LONG ref = InterlockedIncrement(&This->ref); 01036 01037 TRACE("(%p) ref=%d\n", This, ref); 01038 01039 return ref; 01040 } 01041 01042 static ULONG WINAPI HTMLTxtRange_Release(IHTMLTxtRange *iface) 01043 { 01044 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface); 01045 LONG ref = InterlockedDecrement(&This->ref); 01046 01047 TRACE("(%p) ref=%d\n", This, ref); 01048 01049 if(!ref) { 01050 if(This->nsrange) 01051 nsISelection_Release(This->nsrange); 01052 if(This->doc) 01053 list_remove(&This->entry); 01054 heap_free(This); 01055 } 01056 01057 return ref; 01058 } 01059 01060 static HRESULT WINAPI HTMLTxtRange_GetTypeInfoCount(IHTMLTxtRange *iface, UINT *pctinfo) 01061 { 01062 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface); 01063 FIXME("(%p)->(%p)\n", This, pctinfo); 01064 return E_NOTIMPL; 01065 } 01066 01067 static HRESULT WINAPI HTMLTxtRange_GetTypeInfo(IHTMLTxtRange *iface, UINT iTInfo, 01068 LCID lcid, ITypeInfo **ppTInfo) 01069 { 01070 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface); 01071 FIXME("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo); 01072 return E_NOTIMPL; 01073 } 01074 01075 static HRESULT WINAPI HTMLTxtRange_GetIDsOfNames(IHTMLTxtRange *iface, REFIID riid, 01076 LPOLESTR *rgszNames, UINT cNames, 01077 LCID lcid, DISPID *rgDispId) 01078 { 01079 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface); 01080 FIXME("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, 01081 lcid, rgDispId); 01082 return E_NOTIMPL; 01083 } 01084 01085 static HRESULT WINAPI HTMLTxtRange_Invoke(IHTMLTxtRange *iface, DISPID dispIdMember, 01086 REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, 01087 VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) 01088 { 01089 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface); 01090 FIXME("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid), 01091 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); 01092 return E_NOTIMPL; 01093 } 01094 01095 static HRESULT WINAPI HTMLTxtRange_get_htmlText(IHTMLTxtRange *iface, BSTR *p) 01096 { 01097 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface); 01098 01099 TRACE("(%p)->(%p)\n", This, p); 01100 01101 *p = NULL; 01102 01103 if(This->nsrange) { 01104 nsIDOMDocumentFragment *fragment; 01105 nsresult nsres; 01106 01107 nsres = nsIDOMRange_CloneContents(This->nsrange, &fragment); 01108 if(NS_SUCCEEDED(nsres)) { 01109 const PRUnichar *nstext; 01110 nsAString nsstr; 01111 01112 nsAString_Init(&nsstr, NULL); 01113 nsnode_to_nsstring((nsIDOMNode*)fragment, &nsstr); 01114 nsIDOMDocumentFragment_Release(fragment); 01115 01116 nsAString_GetData(&nsstr, &nstext); 01117 *p = SysAllocString(nstext); 01118 01119 nsAString_Finish(&nsstr); 01120 } 01121 } 01122 01123 if(!*p) { 01124 const WCHAR emptyW[] = {0}; 01125 *p = SysAllocString(emptyW); 01126 } 01127 01128 TRACE("return %s\n", debugstr_w(*p)); 01129 return S_OK; 01130 } 01131 01132 static HRESULT WINAPI HTMLTxtRange_put_text(IHTMLTxtRange *iface, BSTR v) 01133 { 01134 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface); 01135 nsIDOMText *text_node; 01136 nsAString text_str; 01137 nsresult nsres; 01138 01139 TRACE("(%p)->(%s)\n", This, debugstr_w(v)); 01140 01141 if(!This->doc) 01142 return MSHTML_E_NODOC; 01143 01144 nsAString_InitDepend(&text_str, v); 01145 nsres = nsIDOMHTMLDocument_CreateTextNode(This->doc->nsdoc, &text_str, &text_node); 01146 nsAString_Finish(&text_str); 01147 if(NS_FAILED(nsres)) { 01148 ERR("CreateTextNode failed: %08x\n", nsres); 01149 return S_OK; 01150 } 01151 nsres = nsIDOMRange_DeleteContents(This->nsrange); 01152 if(NS_FAILED(nsres)) 01153 ERR("DeleteContents failed: %08x\n", nsres); 01154 01155 nsres = nsIDOMRange_InsertNode(This->nsrange, (nsIDOMNode*)text_node); 01156 if(NS_FAILED(nsres)) 01157 ERR("InsertNode failed: %08x\n", nsres); 01158 01159 nsres = nsIDOMRange_SetEndAfter(This->nsrange, (nsIDOMNode*)text_node); 01160 if(NS_FAILED(nsres)) 01161 ERR("SetEndAfter failed: %08x\n", nsres); 01162 01163 return IHTMLTxtRange_collapse(HTMLTXTRANGE(This), VARIANT_FALSE); 01164 } 01165 01166 static HRESULT WINAPI HTMLTxtRange_get_text(IHTMLTxtRange *iface, BSTR *p) 01167 { 01168 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface); 01169 wstrbuf_t buf; 01170 01171 TRACE("(%p)->(%p)\n", This, p); 01172 01173 *p = NULL; 01174 if(!This->nsrange) 01175 return S_OK; 01176 01177 if (!wstrbuf_init(&buf)) 01178 return E_OUTOFMEMORY; 01179 range_to_string(This, &buf); 01180 if (buf.buf) 01181 *p = SysAllocString(buf.buf); 01182 wstrbuf_finish(&buf); 01183 01184 TRACE("ret %s\n", debugstr_w(*p)); 01185 return S_OK; 01186 } 01187 01188 static HRESULT WINAPI HTMLTxtRange_parentElement(IHTMLTxtRange *iface, IHTMLElement **parent) 01189 { 01190 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface); 01191 nsIDOMNode *nsnode, *tmp; 01192 HTMLDOMNode *node; 01193 01194 TRACE("(%p)->(%p)\n", This, parent); 01195 01196 nsIDOMRange_GetCommonAncestorContainer(This->nsrange, &nsnode); 01197 while(nsnode && get_node_type(nsnode) != ELEMENT_NODE) { 01198 nsIDOMNode_GetParentNode(nsnode, &tmp); 01199 nsIDOMNode_Release(nsnode); 01200 nsnode = tmp; 01201 } 01202 01203 if(!nsnode) { 01204 *parent = NULL; 01205 return S_OK; 01206 } 01207 01208 node = get_node(This->doc, nsnode, TRUE); 01209 nsIDOMNode_Release(nsnode); 01210 01211 return IHTMLDOMNode_QueryInterface(HTMLDOMNODE(node), &IID_IHTMLElement, (void**)parent); 01212 } 01213 01214 static HRESULT WINAPI HTMLTxtRange_duplicate(IHTMLTxtRange *iface, IHTMLTxtRange **Duplicate) 01215 { 01216 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface); 01217 nsIDOMRange *nsrange = NULL; 01218 HRESULT hres; 01219 01220 TRACE("(%p)->(%p)\n", This, Duplicate); 01221 01222 nsIDOMRange_CloneRange(This->nsrange, &nsrange); 01223 hres = HTMLTxtRange_Create(This->doc, nsrange, Duplicate); 01224 nsIDOMRange_Release(nsrange); 01225 01226 return hres; 01227 } 01228 01229 static HRESULT WINAPI HTMLTxtRange_inRange(IHTMLTxtRange *iface, IHTMLTxtRange *Range, 01230 VARIANT_BOOL *InRange) 01231 { 01232 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface); 01233 HTMLTxtRange *src_range; 01234 PRInt16 nsret = 0; 01235 nsresult nsres; 01236 01237 TRACE("(%p)->(%p %p)\n", This, Range, InRange); 01238 01239 *InRange = VARIANT_FALSE; 01240 01241 src_range = get_range_object(This->doc, Range); 01242 if(!src_range) 01243 return E_FAIL; 01244 01245 nsres = nsIDOMRange_CompareBoundaryPoints(This->nsrange, NS_START_TO_START, 01246 src_range->nsrange, &nsret); 01247 if(NS_SUCCEEDED(nsres) && nsret <= 0) { 01248 nsres = nsIDOMRange_CompareBoundaryPoints(This->nsrange, NS_END_TO_END, 01249 src_range->nsrange, &nsret); 01250 if(NS_SUCCEEDED(nsres) && nsret >= 0) 01251 *InRange = VARIANT_TRUE; 01252 } 01253 01254 if(NS_FAILED(nsres)) 01255 ERR("CompareBoundaryPoints failed: %08x\n", nsres); 01256 01257 return S_OK; 01258 } 01259 01260 static HRESULT WINAPI HTMLTxtRange_isEqual(IHTMLTxtRange *iface, IHTMLTxtRange *Range, 01261 VARIANT_BOOL *IsEqual) 01262 { 01263 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface); 01264 HTMLTxtRange *src_range; 01265 PRInt16 nsret = 0; 01266 nsresult nsres; 01267 01268 TRACE("(%p)->(%p %p)\n", This, Range, IsEqual); 01269 01270 *IsEqual = VARIANT_FALSE; 01271 01272 src_range = get_range_object(This->doc, Range); 01273 if(!src_range) 01274 return E_FAIL; 01275 01276 nsres = nsIDOMRange_CompareBoundaryPoints(This->nsrange, NS_START_TO_START, 01277 src_range->nsrange, &nsret); 01278 if(NS_SUCCEEDED(nsres) && !nsret) { 01279 nsres = nsIDOMRange_CompareBoundaryPoints(This->nsrange, NS_END_TO_END, 01280 src_range->nsrange, &nsret); 01281 if(NS_SUCCEEDED(nsres) && !nsret) 01282 *IsEqual = VARIANT_TRUE; 01283 } 01284 01285 if(NS_FAILED(nsres)) 01286 ERR("CompareBoundaryPoints failed: %08x\n", nsres); 01287 01288 return S_OK; 01289 } 01290 01291 static HRESULT WINAPI HTMLTxtRange_scrollIntoView(IHTMLTxtRange *iface, VARIANT_BOOL fStart) 01292 { 01293 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface); 01294 FIXME("(%p)->(%x)\n", This, fStart); 01295 return E_NOTIMPL; 01296 } 01297 01298 static HRESULT WINAPI HTMLTxtRange_collapse(IHTMLTxtRange *iface, VARIANT_BOOL Start) 01299 { 01300 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface); 01301 01302 TRACE("(%p)->(%x)\n", This, Start); 01303 01304 nsIDOMRange_Collapse(This->nsrange, Start != VARIANT_FALSE); 01305 return S_OK; 01306 } 01307 01308 static HRESULT WINAPI HTMLTxtRange_expand(IHTMLTxtRange *iface, BSTR Unit, VARIANT_BOOL *Success) 01309 { 01310 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface); 01311 range_unit_t unit; 01312 01313 TRACE("(%p)->(%s %p)\n", This, debugstr_w(Unit), Success); 01314 01315 unit = string_to_unit(Unit); 01316 if(unit == RU_UNKNOWN) 01317 return E_INVALIDARG; 01318 01319 *Success = VARIANT_FALSE; 01320 01321 switch(unit) { 01322 case RU_WORD: { 01323 dompos_t end_pos, start_pos, new_start_pos, new_end_pos; 01324 PRBool collapsed; 01325 01326 nsIDOMRange_GetCollapsed(This->nsrange, &collapsed); 01327 01328 get_cur_pos(This, TRUE, &start_pos); 01329 get_cur_pos(This, FALSE, &end_pos); 01330 01331 if(find_word_end(&end_pos, &new_end_pos) || collapsed) { 01332 set_range_pos(This, FALSE, &new_end_pos); 01333 *Success = VARIANT_TRUE; 01334 } 01335 01336 if(start_pos.type && (get_pos_char(&end_pos) || !dompos_cmp(&new_end_pos, &end_pos))) { 01337 if(find_prev_space(This, &start_pos, TRUE, &new_start_pos)) { 01338 set_range_pos(This, TRUE, &new_start_pos); 01339 *Success = VARIANT_TRUE; 01340 } 01341 dompos_release(&new_start_pos); 01342 } 01343 01344 dompos_release(&new_end_pos); 01345 dompos_release(&end_pos); 01346 dompos_release(&start_pos); 01347 01348 break; 01349 } 01350 01351 case RU_TEXTEDIT: { 01352 nsIDOMHTMLElement *nsbody = NULL; 01353 nsresult nsres; 01354 01355 nsres = nsIDOMHTMLDocument_GetBody(This->doc->nsdoc, &nsbody); 01356 if(NS_FAILED(nsres) || !nsbody) { 01357 ERR("Could not get body: %08x\n", nsres); 01358 break; 01359 } 01360 01361 nsres = nsIDOMRange_SelectNodeContents(This->nsrange, (nsIDOMNode*)nsbody); 01362 nsIDOMHTMLElement_Release(nsbody); 01363 if(NS_FAILED(nsres)) { 01364 ERR("Collapse failed: %08x\n", nsres); 01365 break; 01366 } 01367 01368 *Success = VARIANT_TRUE; 01369 break; 01370 } 01371 01372 default: 01373 FIXME("Unimplemented unit %s\n", debugstr_w(Unit)); 01374 } 01375 01376 return S_OK; 01377 } 01378 01379 static HRESULT WINAPI HTMLTxtRange_move(IHTMLTxtRange *iface, BSTR Unit, 01380 LONG Count, LONG *ActualCount) 01381 { 01382 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface); 01383 range_unit_t unit; 01384 01385 TRACE("(%p)->(%s %d %p)\n", This, debugstr_w(Unit), Count, ActualCount); 01386 01387 unit = string_to_unit(Unit); 01388 if(unit == RU_UNKNOWN) 01389 return E_INVALIDARG; 01390 01391 if(!Count) { 01392 *ActualCount = 0; 01393 return IHTMLTxtRange_collapse(HTMLTXTRANGE(This), TRUE); 01394 } 01395 01396 switch(unit) { 01397 case RU_CHAR: { 01398 dompos_t cur_pos, new_pos; 01399 01400 get_cur_pos(This, TRUE, &cur_pos); 01401 01402 if(Count > 0) { 01403 *ActualCount = move_next_chars(Count, &cur_pos, TRUE, NULL, NULL, &new_pos); 01404 set_range_pos(This, FALSE, &new_pos); 01405 dompos_release(&new_pos); 01406 01407 IHTMLTxtRange_collapse(HTMLTXTRANGE(This), FALSE); 01408 }else { 01409 *ActualCount = -move_prev_chars(This, -Count, &cur_pos, FALSE, NULL, NULL, &new_pos); 01410 set_range_pos(This, TRUE, &new_pos); 01411 IHTMLTxtRange_collapse(HTMLTXTRANGE(This), TRUE); 01412 dompos_release(&new_pos); 01413 } 01414 01415 dompos_release(&cur_pos); 01416 break; 01417 } 01418 01419 case RU_WORD: { 01420 dompos_t cur_pos, new_pos; 01421 01422 get_cur_pos(This, TRUE, &cur_pos); 01423 01424 if(Count > 0) { 01425 *ActualCount = move_next_words(Count, &cur_pos, &new_pos); 01426 set_range_pos(This, FALSE, &new_pos); 01427 dompos_release(&new_pos); 01428 IHTMLTxtRange_collapse(HTMLTXTRANGE(This), FALSE); 01429 }else { 01430 *ActualCount = -move_prev_words(This, -Count, &cur_pos, &new_pos); 01431 set_range_pos(This, TRUE, &new_pos); 01432 IHTMLTxtRange_collapse(HTMLTXTRANGE(This), TRUE); 01433 dompos_release(&new_pos); 01434 } 01435 01436 dompos_release(&cur_pos); 01437 break; 01438 } 01439 01440 default: 01441 FIXME("unimplemented unit %s\n", debugstr_w(Unit)); 01442 } 01443 01444 TRACE("ret %d\n", *ActualCount); 01445 return S_OK; 01446 } 01447 01448 static HRESULT WINAPI HTMLTxtRange_moveStart(IHTMLTxtRange *iface, BSTR Unit, 01449 LONG Count, LONG *ActualCount) 01450 { 01451 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface); 01452 range_unit_t unit; 01453 01454 TRACE("(%p)->(%s %d %p)\n", This, debugstr_w(Unit), Count, ActualCount); 01455 01456 unit = string_to_unit(Unit); 01457 if(unit == RU_UNKNOWN) 01458 return E_INVALIDARG; 01459 01460 if(!Count) { 01461 *ActualCount = 0; 01462 return S_OK; 01463 } 01464 01465 switch(unit) { 01466 case RU_CHAR: { 01467 dompos_t start_pos, end_pos, new_pos; 01468 PRBool collapsed; 01469 01470 get_cur_pos(This, TRUE, &start_pos); 01471 get_cur_pos(This, FALSE, &end_pos); 01472 nsIDOMRange_GetCollapsed(This->nsrange, &collapsed); 01473 01474 if(Count > 0) { 01475 BOOL bounded; 01476 01477 *ActualCount = move_next_chars(Count, &start_pos, collapsed, &end_pos, &bounded, &new_pos); 01478 set_range_pos(This, !bounded, &new_pos); 01479 if(bounded) 01480 IHTMLTxtRange_collapse(HTMLTXTRANGE(This), FALSE); 01481 }else { 01482 *ActualCount = -move_prev_chars(This, -Count, &start_pos, FALSE, NULL, NULL, &new_pos); 01483 set_range_pos(This, TRUE, &new_pos); 01484 } 01485 01486 dompos_release(&start_pos); 01487 dompos_release(&end_pos); 01488 dompos_release(&new_pos); 01489 break; 01490 } 01491 01492 default: 01493 FIXME("unimplemented unit %s\n", debugstr_w(Unit)); 01494 } 01495 01496 return S_OK; 01497 } 01498 01499 static HRESULT WINAPI HTMLTxtRange_moveEnd(IHTMLTxtRange *iface, BSTR Unit, 01500 LONG Count, LONG *ActualCount) 01501 { 01502 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface); 01503 range_unit_t unit; 01504 01505 TRACE("(%p)->(%s %d %p)\n", This, debugstr_w(Unit), Count, ActualCount); 01506 01507 unit = string_to_unit(Unit); 01508 if(unit == RU_UNKNOWN) 01509 return E_INVALIDARG; 01510 01511 if(!Count) { 01512 *ActualCount = 0; 01513 return S_OK; 01514 } 01515 01516 switch(unit) { 01517 case RU_CHAR: { 01518 dompos_t start_pos, end_pos, new_pos; 01519 PRBool collapsed; 01520 01521 get_cur_pos(This, TRUE, &start_pos); 01522 get_cur_pos(This, FALSE, &end_pos); 01523 nsIDOMRange_GetCollapsed(This->nsrange, &collapsed); 01524 01525 if(Count > 0) { 01526 *ActualCount = move_next_chars(Count, &end_pos, collapsed, NULL, NULL, &new_pos); 01527 set_range_pos(This, FALSE, &new_pos); 01528 }else { 01529 BOOL bounded; 01530 01531 *ActualCount = -move_prev_chars(This, -Count, &end_pos, TRUE, &start_pos, &bounded, &new_pos); 01532 set_range_pos(This, bounded, &new_pos); 01533 if(bounded) 01534 IHTMLTxtRange_collapse(HTMLTXTRANGE(This), TRUE); 01535 } 01536 01537 dompos_release(&start_pos); 01538 dompos_release(&end_pos); 01539 dompos_release(&new_pos); 01540 break; 01541 } 01542 01543 default: 01544 FIXME("unimplemented unit %s\n", debugstr_w(Unit)); 01545 } 01546 01547 return S_OK; 01548 } 01549 01550 static HRESULT WINAPI HTMLTxtRange_select(IHTMLTxtRange *iface) 01551 { 01552 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface); 01553 nsISelection *nsselection; 01554 nsresult nsres; 01555 01556 TRACE("(%p)\n", This); 01557 01558 nsres = nsIDOMWindow_GetSelection(This->doc->basedoc.window->nswindow, &nsselection); 01559 if(NS_FAILED(nsres)) { 01560 ERR("GetSelection failed: %08x\n", nsres); 01561 return E_FAIL; 01562 } 01563 01564 nsISelection_RemoveAllRanges(nsselection); 01565 nsISelection_AddRange(nsselection, This->nsrange); 01566 nsISelection_Release(nsselection); 01567 return S_OK; 01568 } 01569 01570 static HRESULT WINAPI HTMLTxtRange_pasteHTML(IHTMLTxtRange *iface, BSTR html) 01571 { 01572 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface); 01573 FIXME("(%p)->(%s)\n", This, debugstr_w(html)); 01574 return E_NOTIMPL; 01575 } 01576 01577 static HRESULT WINAPI HTMLTxtRange_moveToElementText(IHTMLTxtRange *iface, IHTMLElement *element) 01578 { 01579 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface); 01580 FIXME("(%p)->(%p)\n", This, element); 01581 return E_NOTIMPL; 01582 } 01583 01584 static HRESULT WINAPI HTMLTxtRange_setEndPoint(IHTMLTxtRange *iface, BSTR how, 01585 IHTMLTxtRange *SourceRange) 01586 { 01587 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface); 01588 FIXME("(%p)->(%s %p)\n", This, debugstr_w(how), SourceRange); 01589 return E_NOTIMPL; 01590 } 01591 01592 static HRESULT WINAPI HTMLTxtRange_compareEndPoints(IHTMLTxtRange *iface, BSTR how, 01593 IHTMLTxtRange *SourceRange, LONG *ret) 01594 { 01595 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface); 01596 HTMLTxtRange *src_range; 01597 PRInt16 nsret = 0; 01598 int nscmpt; 01599 nsresult nsres; 01600 01601 TRACE("(%p)->(%s %p %p)\n", This, debugstr_w(how), SourceRange, ret); 01602 01603 nscmpt = string_to_nscmptype(how); 01604 if(nscmpt == -1) 01605 return E_INVALIDARG; 01606 01607 src_range = get_range_object(This->doc, SourceRange); 01608 if(!src_range) 01609 return E_FAIL; 01610 01611 nsres = nsIDOMRange_CompareBoundaryPoints(This->nsrange, nscmpt, src_range->nsrange, &nsret); 01612 if(NS_FAILED(nsres)) 01613 ERR("CompareBoundaryPoints failed: %08x\n", nsres); 01614 01615 *ret = nsret; 01616 return S_OK; 01617 } 01618 01619 static HRESULT WINAPI HTMLTxtRange_findText(IHTMLTxtRange *iface, BSTR String, 01620 LONG count, LONG Flags, VARIANT_BOOL *Success) 01621 { 01622 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface); 01623 FIXME("(%p)->(%s %d %08x %p)\n", This, debugstr_w(String), count, Flags, Success); 01624 return E_NOTIMPL; 01625 } 01626 01627 static HRESULT WINAPI HTMLTxtRange_moveToPoint(IHTMLTxtRange *iface, LONG x, LONG y) 01628 { 01629 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface); 01630 FIXME("(%p)->(%d %d)\n", This, x, y); 01631 return E_NOTIMPL; 01632 } 01633 01634 static HRESULT WINAPI HTMLTxtRange_getBookmark(IHTMLTxtRange *iface, BSTR *Bookmark) 01635 { 01636 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface); 01637 FIXME("(%p)->(%p)\n", This, Bookmark); 01638 return E_NOTIMPL; 01639 } 01640 01641 static HRESULT WINAPI HTMLTxtRange_moveToBookmark(IHTMLTxtRange *iface, BSTR Bookmark, 01642 VARIANT_BOOL *Success) 01643 { 01644 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface); 01645 FIXME("(%p)->(%s %p)\n", This, debugstr_w(Bookmark), Success); 01646 return E_NOTIMPL; 01647 } 01648 01649 static HRESULT WINAPI HTMLTxtRange_queryCommandSupported(IHTMLTxtRange *iface, BSTR cmdID, 01650 VARIANT_BOOL *pfRet) 01651 { 01652 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface); 01653 FIXME("(%p)->(%s %p)\n", This, debugstr_w(cmdID), pfRet); 01654 return E_NOTIMPL; 01655 } 01656 01657 static HRESULT WINAPI HTMLTxtRange_queryCommandEnabled(IHTMLTxtRange *iface, BSTR cmdID, 01658 VARIANT_BOOL *pfRet) 01659 { 01660 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface); 01661 FIXME("(%p)->(%s %p)\n", This, debugstr_w(cmdID), pfRet); 01662 return E_NOTIMPL; 01663 } 01664 01665 static HRESULT WINAPI HTMLTxtRange_queryCommandState(IHTMLTxtRange *iface, BSTR cmdID, 01666 VARIANT_BOOL *pfRet) 01667 { 01668 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface); 01669 FIXME("(%p)->(%s %p)\n", This, debugstr_w(cmdID), pfRet); 01670 return E_NOTIMPL; 01671 } 01672 01673 static HRESULT WINAPI HTMLTxtRange_queryCommandIndeterm(IHTMLTxtRange *iface, BSTR cmdID, 01674 VARIANT_BOOL *pfRet) 01675 { 01676 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface); 01677 FIXME("(%p)->(%s %p)\n", This, debugstr_w(cmdID), pfRet); 01678 return E_NOTIMPL; 01679 } 01680 01681 static HRESULT WINAPI HTMLTxtRange_queryCommandText(IHTMLTxtRange *iface, BSTR cmdID, 01682 BSTR *pcmdText) 01683 { 01684 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface); 01685 FIXME("(%p)->(%s %p)\n", This, debugstr_w(cmdID), pcmdText); 01686 return E_NOTIMPL; 01687 } 01688 01689 static HRESULT WINAPI HTMLTxtRange_queryCommandValue(IHTMLTxtRange *iface, BSTR cmdID, 01690 VARIANT *pcmdValue) 01691 { 01692 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface); 01693 FIXME("(%p)->(%s %p)\n", This, debugstr_w(cmdID), pcmdValue); 01694 return E_NOTIMPL; 01695 } 01696 01697 static HRESULT WINAPI HTMLTxtRange_execCommand(IHTMLTxtRange *iface, BSTR cmdID, 01698 VARIANT_BOOL showUI, VARIANT value, VARIANT_BOOL *pfRet) 01699 { 01700 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface); 01701 FIXME("(%p)->(%s %x v %p)\n", This, debugstr_w(cmdID), showUI, pfRet); 01702 return E_NOTIMPL; 01703 } 01704 01705 static HRESULT WINAPI HTMLTxtRange_execCommandShowHelp(IHTMLTxtRange *iface, BSTR cmdID, 01706 VARIANT_BOOL *pfRet) 01707 { 01708 HTMLTxtRange *This = HTMLTXTRANGE_THIS(iface); 01709 FIXME("(%p)->(%s %p)\n", This, debugstr_w(cmdID), pfRet); 01710 return E_NOTIMPL; 01711 } 01712 01713 #undef HTMLTXTRANGE_THIS 01714 01715 static const IHTMLTxtRangeVtbl HTMLTxtRangeVtbl = { 01716 HTMLTxtRange_QueryInterface, 01717 HTMLTxtRange_AddRef, 01718 HTMLTxtRange_Release, 01719 HTMLTxtRange_GetTypeInfoCount, 01720 HTMLTxtRange_GetTypeInfo, 01721 HTMLTxtRange_GetIDsOfNames, 01722 HTMLTxtRange_Invoke, 01723 HTMLTxtRange_get_htmlText, 01724 HTMLTxtRange_put_text, 01725 HTMLTxtRange_get_text, 01726 HTMLTxtRange_parentElement, 01727 HTMLTxtRange_duplicate, 01728 HTMLTxtRange_inRange, 01729 HTMLTxtRange_isEqual, 01730 HTMLTxtRange_scrollIntoView, 01731 HTMLTxtRange_collapse, 01732 HTMLTxtRange_expand, 01733 HTMLTxtRange_move, 01734 HTMLTxtRange_moveStart, 01735 HTMLTxtRange_moveEnd, 01736 HTMLTxtRange_select, 01737 HTMLTxtRange_pasteHTML, 01738 HTMLTxtRange_moveToElementText, 01739 HTMLTxtRange_setEndPoint, 01740 HTMLTxtRange_compareEndPoints, 01741 HTMLTxtRange_findText, 01742 HTMLTxtRange_moveToPoint, 01743 HTMLTxtRange_getBookmark, 01744 HTMLTxtRange_moveToBookmark, 01745 HTMLTxtRange_queryCommandSupported, 01746 HTMLTxtRange_queryCommandEnabled, 01747 HTMLTxtRange_queryCommandState, 01748 HTMLTxtRange_queryCommandIndeterm, 01749 HTMLTxtRange_queryCommandText, 01750 HTMLTxtRange_queryCommandValue, 01751 HTMLTxtRange_execCommand, 01752 HTMLTxtRange_execCommandShowHelp 01753 }; 01754 01755 #define OLECMDTRG_THIS(iface) DEFINE_THIS(HTMLTxtRange, OleCommandTarget, iface) 01756 01757 static HRESULT WINAPI RangeCommandTarget_QueryInterface(IOleCommandTarget *iface, REFIID riid, void **ppv) 01758 { 01759 HTMLTxtRange *This = OLECMDTRG_THIS(iface); 01760 return IHTMLTxtRange_QueryInterface(HTMLTXTRANGE(This), riid, ppv); 01761 } 01762 01763 static ULONG WINAPI RangeCommandTarget_AddRef(IOleCommandTarget *iface) 01764 { 01765 HTMLTxtRange *This = OLECMDTRG_THIS(iface); 01766 return IHTMLTxtRange_AddRef(HTMLTXTRANGE(This)); 01767 } 01768 01769 static ULONG WINAPI RangeCommandTarget_Release(IOleCommandTarget *iface) 01770 { 01771 HTMLTxtRange *This = OLECMDTRG_THIS(iface); 01772 return IHTMLTxtRange_Release(HTMLTXTRANGE(This)); 01773 } 01774 01775 static HRESULT WINAPI RangeCommandTarget_QueryStatus(IOleCommandTarget *iface, const GUID *pguidCmdGroup, 01776 ULONG cCmds, OLECMD prgCmds[], OLECMDTEXT *pCmdText) 01777 { 01778 HTMLTxtRange *This = OLECMDTRG_THIS(iface); 01779 FIXME("(%p)->(%s %d %p %p)\n", This, debugstr_guid(pguidCmdGroup), cCmds, prgCmds, pCmdText); 01780 return E_NOTIMPL; 01781 } 01782 01783 static HRESULT exec_indent(HTMLTxtRange *This, VARIANT *in, VARIANT *out) 01784 { 01785 nsIDOMHTMLElement *blockquote_elem, *p_elem; 01786 nsIDOMDocumentFragment *fragment; 01787 nsIDOMNode *tmp; 01788 01789 static const PRUnichar blockquoteW[] = {'B','L','O','C','K','Q','U','O','T','E',0}; 01790 static const PRUnichar pW[] = {'P',0}; 01791 01792 TRACE("(%p)->(%p %p)\n", This, in, out); 01793 01794 if(!This->doc->nsdoc) { 01795 WARN("NULL nsdoc\n"); 01796 return E_NOTIMPL; 01797 } 01798 01799 create_nselem(This->doc, blockquoteW, &blockquote_elem); 01800 create_nselem(This->doc, pW, &p_elem); 01801 01802 nsIDOMRange_ExtractContents(This->nsrange, &fragment); 01803 nsIDOMElement_AppendChild(p_elem, (nsIDOMNode*)fragment, &tmp); 01804 nsIDOMDocumentFragment_Release(fragment); 01805 nsIDOMNode_Release(tmp); 01806 01807 nsIDOMElement_AppendChild(blockquote_elem, (nsIDOMNode*)p_elem, &tmp); 01808 nsIDOMElement_Release(p_elem); 01809 nsIDOMNode_Release(tmp); 01810 01811 nsIDOMRange_InsertNode(This->nsrange, (nsIDOMNode*)blockquote_elem); 01812 nsIDOMElement_Release(blockquote_elem); 01813 01814 return S_OK; 01815 } 01816 01817 static HRESULT WINAPI RangeCommandTarget_Exec(IOleCommandTarget *iface, const GUID *pguidCmdGroup, 01818 DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut) 01819 { 01820 HTMLTxtRange *This = OLECMDTRG_THIS(iface); 01821 01822 TRACE("(%p)->(%s %d %x %p %p)\n", This, debugstr_guid(pguidCmdGroup), nCmdID, 01823 nCmdexecopt, pvaIn, pvaOut); 01824 01825 if(pguidCmdGroup && IsEqualGUID(&CGID_MSHTML, pguidCmdGroup)) { 01826 switch(nCmdID) { 01827 case IDM_INDENT: 01828 return exec_indent(This, pvaIn, pvaOut); 01829 default: 01830 FIXME("Unsupported cmdid %d of CGID_MSHTML\n", nCmdID); 01831 } 01832 }else { 01833 FIXME("Unsupported cmd %d of group %s\n", nCmdID, debugstr_guid(pguidCmdGroup)); 01834 } 01835 01836 return E_NOTIMPL; 01837 } 01838 01839 #undef OLECMDTRG_THIS 01840 01841 static const IOleCommandTargetVtbl OleCommandTargetVtbl = { 01842 RangeCommandTarget_QueryInterface, 01843 RangeCommandTarget_AddRef, 01844 RangeCommandTarget_Release, 01845 RangeCommandTarget_QueryStatus, 01846 RangeCommandTarget_Exec 01847 }; 01848 01849 HRESULT HTMLTxtRange_Create(HTMLDocumentNode *doc, nsIDOMRange *nsrange, IHTMLTxtRange **p) 01850 { 01851 HTMLTxtRange *ret; 01852 01853 ret = heap_alloc(sizeof(HTMLTxtRange)); 01854 if(!ret) 01855 return E_OUTOFMEMORY; 01856 01857 ret->lpHTMLTxtRangeVtbl = &HTMLTxtRangeVtbl; 01858 ret->lpOleCommandTargetVtbl = &OleCommandTargetVtbl; 01859 ret->ref = 1; 01860 01861 if(nsrange) 01862 nsIDOMRange_AddRef(nsrange); 01863 ret->nsrange = nsrange; 01864 01865 ret->doc = doc; 01866 list_add_head(&doc->range_list, &ret->entry); 01867 01868 *p = HTMLTXTRANGE(ret); 01869 return S_OK; 01870 } 01871 01872 void detach_ranges(HTMLDocumentNode *This) 01873 { 01874 HTMLTxtRange *iter; 01875 01876 LIST_FOR_EACH_ENTRY(iter, &This->range_list, HTMLTxtRange, entry) { 01877 iter->doc = NULL; 01878 } 01879 } Generated on Sat May 26 2012 04:23:44 for ReactOS by
1.7.6.1
|