d3d9/tests: Warn that tests were skipped if we could not load d3d9.dll.
[wine/wine64.git] / dlls / mshtml / editor.c
blob0a444bfbeaaa5d8924ad363239313ae507f30885
1 /*
2 * Copyright 2006 Jacek Caban for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include "config.h"
21 #include <stdarg.h>
22 #include <stdio.h>
24 #define COBJMACROS
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winuser.h"
29 #include "winnls.h"
30 #include "ole2.h"
32 #include "wine/debug.h"
33 #include "wine/unicode.h"
35 #include "mshtml_private.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
39 #define DOM_VK_LEFT VK_LEFT
40 #define DOM_VK_UP VK_UP
41 #define DOM_VK_RIGHT VK_RIGHT
42 #define DOM_VK_DOWN VK_DOWN
44 static const WCHAR wszFont[] = {'f','o','n','t',0};
45 static const WCHAR wszSize[] = {'s','i','z','e',0};
47 static nsISelection *get_ns_selection(HTMLDocument *This)
49 nsIDOMWindow *dom_window;
50 nsISelection *nsselection = NULL;
51 nsresult nsres;
53 if(!This->nscontainer)
54 return NULL;
56 nsres = nsIWebBrowser_GetContentDOMWindow(This->nscontainer->webbrowser, &dom_window);
57 if(NS_FAILED(nsres))
58 return NULL;
60 nsIDOMWindow_GetSelection(dom_window, &nsselection);
61 nsIDOMWindow_Release(dom_window);
63 return nsselection;
67 static void remove_child_attr(nsIDOMElement *elem, LPCWSTR tag, nsAString *attr_str)
69 PRBool has_children;
70 PRUint32 child_cnt, i;
71 nsIDOMNode *child_node;
72 nsIDOMNodeList *node_list;
73 PRUint16 node_type;
75 nsIDOMElement_HasChildNodes(elem, &has_children);
76 if(!has_children)
77 return;
79 nsIDOMElement_GetChildNodes(elem, &node_list);
80 nsIDOMNodeList_GetLength(node_list, &child_cnt);
82 for(i=0; i<child_cnt; i++) {
83 nsIDOMNodeList_Item(node_list, i, &child_node);
85 nsIDOMNode_GetNodeType(child_node, &node_type);
86 if(node_type == ELEMENT_NODE) {
87 nsIDOMElement *child_elem;
88 nsAString tag_str;
89 const PRUnichar *ctag;
91 nsIDOMNode_QueryInterface(child_node, &IID_nsIDOMElement, (void**)&child_elem);
93 nsAString_Init(&tag_str, NULL);
94 nsIDOMElement_GetTagName(child_elem, &tag_str);
95 nsAString_GetData(&tag_str, &ctag, NULL);
97 if(!strcmpiW(ctag, tag))
98 /* FIXME: remove node if there are no more attributes */
99 nsIDOMElement_RemoveAttribute(child_elem, attr_str);
101 nsAString_Finish(&tag_str);
103 remove_child_attr(child_elem, tag, attr_str);
105 nsIDOMNode_Release(child_elem);
108 nsIDOMNode_Release(child_node);
111 nsIDOMNodeList_Release(node_list);
114 void get_font_size(HTMLDocument *This, WCHAR *ret)
116 nsISelection *nsselection = get_ns_selection(This);
117 nsIDOMElement *elem = NULL;
118 nsIDOMNode *node = NULL, *tmp_node;
119 nsAString tag_str;
120 LPCWSTR tag;
121 PRUint16 node_type;
122 nsresult nsres;
124 *ret = 0;
126 if(!nsselection)
127 return;
129 nsISelection_GetFocusNode(nsselection, &node);
130 nsISelection_Release(nsselection);
132 while(node) {
133 nsres = nsIDOMNode_GetNodeType(node, &node_type);
134 if(NS_FAILED(nsres) || node_type == DOCUMENT_NODE)
135 break;
137 if(node_type == ELEMENT_NODE) {
138 nsIDOMNode_QueryInterface(node, &IID_nsIDOMElement, (void**)&elem);
140 nsAString_Init(&tag_str, NULL);
141 nsIDOMElement_GetTagName(elem, &tag_str);
142 nsAString_GetData(&tag_str, &tag, NULL);
144 if(!strcmpiW(tag, wszFont)) {
145 nsAString size_str, val_str;
146 LPCWSTR val;
148 TRACE("found font tag %p\n", elem);
150 nsAString_Init(&size_str, wszSize);
151 nsAString_Init(&val_str, NULL);
153 nsIDOMElement_GetAttribute(elem, &size_str, &val_str);
154 nsAString_GetData(&val_str, &val, NULL);
156 if(*val) {
157 TRACE("found size %s\n", debugstr_w(val));
158 strcpyW(ret, val);
161 nsAString_Finish(&size_str);
162 nsAString_Finish(&val_str);
165 nsAString_Finish(&tag_str);
167 nsIDOMElement_Release(elem);
170 if(*ret)
171 break;
173 tmp_node = node;
174 nsIDOMNode_GetParentNode(node, &node);
175 nsIDOMNode_Release(tmp_node);
178 if(node)
179 nsIDOMNode_Release(node);
182 void set_font_size(HTMLDocument *This, LPCWSTR size)
184 nsISelection *nsselection;
185 PRBool collapsed;
186 nsIDOMDocument *nsdoc;
187 nsIDOMElement *elem;
188 nsIDOMRange *range;
189 PRInt32 range_cnt = 0;
190 nsAString font_str;
191 nsAString size_str;
192 nsAString val_str;
193 nsresult nsres;
195 nsselection = get_ns_selection(This);
197 if(!nsselection)
198 return;
200 nsres = nsIWebNavigation_GetDocument(This->nscontainer->navigation, &nsdoc);
201 if(NS_FAILED(nsres))
202 return;
204 nsAString_Init(&font_str, wszFont);
205 nsAString_Init(&size_str, wszSize);
206 nsAString_Init(&val_str, size);
208 nsISelection_GetRangeCount(nsselection, &range_cnt);
209 if(range_cnt != 1)
210 FIXME("range_cnt %d not supprted\n", range_cnt);
212 nsIDOMDocument_CreateElement(nsdoc, &font_str, &elem);
213 nsIDOMElement_SetAttribute(elem, &size_str, &val_str);
215 nsISelection_GetRangeAt(nsselection, 0, &range);
216 nsISelection_GetIsCollapsed(nsselection, &collapsed);
217 nsISelection_RemoveAllRanges(nsselection);
219 nsIDOMRange_SurroundContents(range, (nsIDOMNode*)elem);
221 if(collapsed) {
222 nsISelection_Collapse(nsselection, (nsIDOMNode*)elem, 0);
223 }else {
224 /* Remove all size attrbutes from the range */
225 remove_child_attr(elem, wszFont, &size_str);
226 nsISelection_SelectAllChildren(nsselection, (nsIDOMNode*)elem);
229 nsIDOMRange_Release(range);
230 nsIDOMElement_Release(elem);
232 nsAString_Finish(&font_str);
233 nsAString_Finish(&size_str);
234 nsAString_Finish(&val_str);
236 nsISelection_Release(nsselection);
237 nsIDOMDocument_Release(nsdoc);
240 static BOOL is_visible_text_node(nsIDOMNode *node)
242 nsIDOMCharacterData *char_data;
243 nsAString data_str;
244 LPCWSTR data, ptr;
245 PRUint32 len;
247 nsIDOMNode_QueryInterface(node, &IID_nsIDOMCharacterData, (void**)&char_data);
249 nsIDOMCharacterData_GetLength(char_data, &len);
251 nsAString_Init(&data_str, NULL);
252 nsIDOMCharacterData_GetData(char_data, &data_str);
253 nsAString_GetData(&data_str, &data, NULL);
255 if(*data == '\n') {
256 len--;
257 for(ptr=data+1; ptr && isspaceW(*ptr); ptr++)
258 len--;
261 nsAString_Finish(&data_str);
263 nsIDOMCharacterData_Release(char_data);
265 return len != 0;
268 static nsIDOMNode *get_child_text_node(nsIDOMNode *node, BOOL first)
270 nsIDOMNode *iter, *iter2;
272 if(first)
273 nsIDOMNode_GetFirstChild(node, &iter);
274 else
275 nsIDOMNode_GetLastChild(node, &iter);
277 while(iter) {
278 PRUint16 node_type;
280 nsIDOMNode_GetNodeType(iter, &node_type);
281 switch(node_type) {
282 case TEXT_NODE:
283 if(is_visible_text_node(iter))
284 return iter;
285 case ELEMENT_NODE:
286 iter2 = get_child_text_node(iter, first);
287 if(iter2) {
288 nsIDOMNode_Release(iter);
289 return iter2;
293 if(first)
294 nsIDOMNode_GetNextSibling(iter, &iter2);
295 else
296 nsIDOMNode_GetPreviousSibling(iter, &iter2);
298 nsIDOMNode_Release(iter);
299 iter = iter2;
302 return NULL;
305 static nsIDOMNode *get_next_text_node(nsIDOMNode *node, BOOL next)
307 nsIDOMNode *iter, *iter2 = NULL, *parent = NULL;
308 PRUint16 node_type;
310 iter = node;
311 nsIDOMNode_AddRef(iter);
313 while(1) {
314 if(next)
315 nsIDOMNode_GetNextSibling(iter, &iter2);
316 else
317 nsIDOMNode_GetPreviousSibling(iter, &iter2);
319 while(!iter2) {
320 nsIDOMNode_GetParentNode(iter, &parent);
321 nsIDOMNode_Release(iter);
322 if(!parent)
323 return NULL;
325 iter = parent;
327 if(next)
328 nsIDOMNode_GetNextSibling(iter, &iter2);
329 else
330 nsIDOMNode_GetPreviousSibling(iter, &iter2);
333 nsIDOMNode_Release(iter);
334 iter = iter2;
336 nsIDOMNode_GetNodeType(iter, &node_type);
338 switch(node_type) {
339 case TEXT_NODE:
340 if(is_visible_text_node(iter))
341 return iter;
342 case ELEMENT_NODE:
343 iter2 = get_child_text_node(iter, next);
344 if(iter2) {
345 nsIDOMNode_Release(iter);
346 return iter2;
351 return NULL;
354 static void collapse_end_node(nsISelection *selection, nsIDOMNode *node)
356 nsIDOMCharacterData *char_data;
357 PRUint32 len;
359 nsIDOMNode_QueryInterface(node, &IID_nsIDOMCharacterData, (void**)&char_data);
360 nsIDOMCharacterData_GetLength(char_data, &len);
361 nsIDOMCharacterData_Release(char_data);
363 nsISelection_Collapse(selection, node, len);
366 static void collapse_next_char(HTMLDocument *doc, nsIDOMKeyEvent *event, BOOL next)
368 nsISelection *selection = get_ns_selection(doc);
369 nsIDOMNode *node;
370 PRBool collapsed, b;
371 PRUint16 node_type;
372 nsIDOMNode *text_node;
374 nsIDOMKeyEvent_GetCtrlKey(event, &b);
375 if(b) return;
377 nsIDOMKeyEvent_GetShiftKey(event, &b);
378 if(b) return;
380 nsISelection_GetIsCollapsed(selection, &collapsed);
381 if(!collapsed)
382 nsISelection_CollapseToEnd(selection);
384 nsISelection_GetFocusNode(selection, &node);
385 nsIDOMNode_GetNodeType(node, &node_type);
387 if(node_type == TEXT_NODE) {
388 nsIDOMCharacterData *char_data;
389 PRInt32 offset;
390 PRUint32 len;
392 nsISelection_GetFocusOffset(selection, &offset);
394 nsIDOMNode_QueryInterface(node, &IID_nsIDOMCharacterData, (void**)&char_data);
395 nsIDOMCharacterData_GetLength(char_data, &len);
396 nsIDOMCharacterData_Release(char_data);
398 if(next ? offset != len : offset) {
399 nsISelection_Collapse(selection, node, offset + (next?1:-1));
400 return;
404 text_node = get_next_text_node(node, next);
405 if(text_node) {
406 if(next)
407 nsISelection_Collapse(selection, text_node, 1);
408 else
409 collapse_end_node(selection, text_node);
410 nsIDOMNode_Release(text_node);
413 nsIDOMNode_Release(node);
414 nsISelection_Release(selection);
417 void handle_edit_event(HTMLDocument *This, nsIDOMEvent *event)
419 nsIDOMKeyEvent *key_event;
420 PRUint32 code;
422 nsIDOMEvent_QueryInterface(event, &IID_nsIDOMKeyEvent, (void**)&key_event);
424 nsIDOMKeyEvent_GetKeyCode(key_event, &code);
426 switch(code) {
427 case DOM_VK_LEFT:
428 TRACE("left\n");
429 collapse_next_char(This, key_event, FALSE);
430 break;
431 case DOM_VK_RIGHT:
432 TRACE("right\n");
433 collapse_next_char(This, key_event, TRUE);
436 nsIDOMKeyEvent_Release(key_event);