1 // Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
2 // reserved. Use of this source code is governed by a BSD-style license that
3 // can be found in the LICENSE file.
4
5 #include "libcef/renderer/dom_node_impl.h"
6
7 #include "libcef/common/tracker.h"
8 #include "libcef/renderer/blink_glue.h"
9 #include "libcef/renderer/browser_impl.h"
10 #include "libcef/renderer/dom_document_impl.h"
11 #include "libcef/renderer/thread_util.h"
12
13 #include "base/logging.h"
14 #include "base/strings/string_util.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "third_party/blink/public/platform/web_string.h"
17 #include "third_party/blink/public/web/web_document.h"
18 #include "third_party/blink/public/web/web_dom_event.h"
19 #include "third_party/blink/public/web/web_element.h"
20 #include "third_party/blink/public/web/web_form_control_element.h"
21 #include "third_party/blink/public/web/web_input_element.h"
22 #include "third_party/blink/public/web/web_node.h"
23 #include "third_party/blink/public/web/web_select_element.h"
24
25 using blink::WebDocument;
26 using blink::WebDOMEvent;
27 using blink::WebElement;
28 using blink::WebFormControlElement;
29 using blink::WebInputElement;
30 using blink::WebNode;
31 using blink::WebSelectElement;
32 using blink::WebString;
33
CefDOMNodeImpl(CefRefPtr<CefDOMDocumentImpl> document,const blink::WebNode & node)34 CefDOMNodeImpl::CefDOMNodeImpl(CefRefPtr<CefDOMDocumentImpl> document,
35 const blink::WebNode& node)
36 : document_(document), node_(node) {}
37
~CefDOMNodeImpl()38 CefDOMNodeImpl::~CefDOMNodeImpl() {
39 CEF_REQUIRE_RT();
40
41 if (document_.get() && !node_.IsNull()) {
42 // Remove the node from the document.
43 document_->RemoveNode(node_);
44 }
45 }
46
GetType()47 CefDOMNodeImpl::Type CefDOMNodeImpl::GetType() {
48 if (!VerifyContext())
49 return DOM_NODE_TYPE_UNSUPPORTED;
50
51 return blink_glue::GetNodeType(node_);
52 }
53
IsText()54 bool CefDOMNodeImpl::IsText() {
55 if (!VerifyContext())
56 return false;
57
58 return node_.IsTextNode();
59 }
60
IsElement()61 bool CefDOMNodeImpl::IsElement() {
62 if (!VerifyContext())
63 return false;
64
65 return node_.IsElementNode();
66 }
67
68 // Logic copied from RenderViewImpl::IsEditableNode.
IsEditable()69 bool CefDOMNodeImpl::IsEditable() {
70 if (!VerifyContext())
71 return false;
72
73 if (node_.IsContentEditable())
74 return true;
75
76 if (node_.IsElementNode()) {
77 const WebElement& element = node_.ToConst<WebElement>();
78 if (blink_glue::IsTextControlElement(element))
79 return true;
80
81 // Also return true if it has an ARIA role of 'textbox'.
82 for (unsigned i = 0; i < element.AttributeCount(); ++i) {
83 if (base::LowerCaseEqualsASCII(element.AttributeLocalName(i).Utf8(),
84 "role")) {
85 if (base::LowerCaseEqualsASCII(element.AttributeValue(i).Utf8(),
86 "textbox")) {
87 return true;
88 }
89 break;
90 }
91 }
92 }
93
94 return false;
95 }
96
IsFormControlElement()97 bool CefDOMNodeImpl::IsFormControlElement() {
98 if (!VerifyContext())
99 return false;
100
101 if (node_.IsElementNode()) {
102 const WebElement& element = node_.ToConst<WebElement>();
103 return element.IsFormControlElement();
104 }
105
106 return false;
107 }
108
GetFormControlElementType()109 CefString CefDOMNodeImpl::GetFormControlElementType() {
110 CefString str;
111 if (!VerifyContext())
112 return str;
113
114 if (node_.IsElementNode()) {
115 const WebElement& element = node_.ToConst<WebElement>();
116 if (element.IsFormControlElement()) {
117 // Retrieve the type from the form control element.
118 const WebFormControlElement& formElement =
119 node_.ToConst<WebFormControlElement>();
120
121 const std::u16string& form_control_type =
122 formElement.FormControlType().Utf16();
123 str = form_control_type;
124 }
125 }
126
127 return str;
128 }
129
IsSame(CefRefPtr<CefDOMNode> that)130 bool CefDOMNodeImpl::IsSame(CefRefPtr<CefDOMNode> that) {
131 if (!VerifyContext())
132 return false;
133
134 CefDOMNodeImpl* impl = static_cast<CefDOMNodeImpl*>(that.get());
135 if (!impl || !impl->VerifyContext())
136 return false;
137
138 return node_.Equals(impl->node_);
139 }
140
GetName()141 CefString CefDOMNodeImpl::GetName() {
142 CefString str;
143 if (!VerifyContext())
144 return str;
145
146 const WebString& name = blink_glue::GetNodeName(node_);
147 if (!name.IsNull())
148 str = name.Utf16();
149
150 return str;
151 }
152
GetValue()153 CefString CefDOMNodeImpl::GetValue() {
154 CefString str;
155 if (!VerifyContext())
156 return str;
157
158 if (node_.IsElementNode()) {
159 const WebElement& element = node_.ToConst<WebElement>();
160 if (element.IsFormControlElement()) {
161 // Retrieve the value from the form control element.
162 const WebFormControlElement& formElement =
163 node_.ToConst<WebFormControlElement>();
164
165 std::u16string value;
166 const std::u16string& form_control_type =
167 formElement.FormControlType().Utf16();
168 if (form_control_type == u"text") {
169 const WebInputElement& input_element =
170 formElement.ToConst<WebInputElement>();
171 value = input_element.Value().Utf16();
172 } else if (form_control_type == u"select-one") {
173 const WebSelectElement& select_element =
174 formElement.ToConst<WebSelectElement>();
175 value = select_element.Value().Utf16();
176 }
177
178 base::TrimWhitespace(value, base::TRIM_LEADING, &value);
179 str = value;
180 }
181 }
182
183 if (str.empty()) {
184 const WebString& value = node_.NodeValue();
185 if (!value.IsNull())
186 str = value.Utf16();
187 }
188
189 return str;
190 }
191
SetValue(const CefString & value)192 bool CefDOMNodeImpl::SetValue(const CefString& value) {
193 if (!VerifyContext())
194 return false;
195
196 if (node_.IsElementNode())
197 return false;
198
199 return blink_glue::SetNodeValue(node_,
200 WebString::FromUTF16(value.ToString16()));
201 }
202
GetAsMarkup()203 CefString CefDOMNodeImpl::GetAsMarkup() {
204 CefString str;
205 if (!VerifyContext())
206 return str;
207
208 const WebString& markup = blink_glue::CreateNodeMarkup(node_);
209 if (!markup.IsNull())
210 str = markup.Utf16();
211
212 return str;
213 }
214
GetDocument()215 CefRefPtr<CefDOMDocument> CefDOMNodeImpl::GetDocument() {
216 if (!VerifyContext())
217 return nullptr;
218
219 return document_.get();
220 }
221
GetParent()222 CefRefPtr<CefDOMNode> CefDOMNodeImpl::GetParent() {
223 if (!VerifyContext())
224 return nullptr;
225
226 return document_->GetOrCreateNode(node_.ParentNode());
227 }
228
GetPreviousSibling()229 CefRefPtr<CefDOMNode> CefDOMNodeImpl::GetPreviousSibling() {
230 if (!VerifyContext())
231 return nullptr;
232
233 return document_->GetOrCreateNode(node_.PreviousSibling());
234 }
235
GetNextSibling()236 CefRefPtr<CefDOMNode> CefDOMNodeImpl::GetNextSibling() {
237 if (!VerifyContext())
238 return nullptr;
239
240 return document_->GetOrCreateNode(node_.NextSibling());
241 }
242
HasChildren()243 bool CefDOMNodeImpl::HasChildren() {
244 if (!VerifyContext())
245 return false;
246
247 return !node_.FirstChild().IsNull();
248 }
249
GetFirstChild()250 CefRefPtr<CefDOMNode> CefDOMNodeImpl::GetFirstChild() {
251 if (!VerifyContext())
252 return nullptr;
253
254 return document_->GetOrCreateNode(node_.FirstChild());
255 }
256
GetLastChild()257 CefRefPtr<CefDOMNode> CefDOMNodeImpl::GetLastChild() {
258 if (!VerifyContext())
259 return nullptr;
260
261 return document_->GetOrCreateNode(node_.LastChild());
262 }
263
GetElementTagName()264 CefString CefDOMNodeImpl::GetElementTagName() {
265 CefString str;
266 if (!VerifyContext())
267 return str;
268
269 if (!node_.IsElementNode()) {
270 NOTREACHED();
271 return str;
272 }
273
274 const WebElement& element = node_.ToConst<blink::WebElement>();
275 const WebString& tagname = element.TagName();
276 if (!tagname.IsNull())
277 str = tagname.Utf16();
278
279 return str;
280 }
281
HasElementAttributes()282 bool CefDOMNodeImpl::HasElementAttributes() {
283 if (!VerifyContext())
284 return false;
285
286 if (!node_.IsElementNode()) {
287 NOTREACHED();
288 return false;
289 }
290
291 const WebElement& element = node_.ToConst<blink::WebElement>();
292 return (element.AttributeCount() > 0);
293 }
294
HasElementAttribute(const CefString & attrName)295 bool CefDOMNodeImpl::HasElementAttribute(const CefString& attrName) {
296 if (!VerifyContext())
297 return false;
298
299 if (!node_.IsElementNode()) {
300 NOTREACHED();
301 return false;
302 }
303
304 const WebElement& element = node_.ToConst<blink::WebElement>();
305 return element.HasAttribute(WebString::FromUTF16(attrName.ToString16()));
306 }
307
GetElementAttribute(const CefString & attrName)308 CefString CefDOMNodeImpl::GetElementAttribute(const CefString& attrName) {
309 CefString str;
310 if (!VerifyContext())
311 return str;
312
313 if (!node_.IsElementNode()) {
314 NOTREACHED();
315 return str;
316 }
317
318 const WebElement& element = node_.ToConst<blink::WebElement>();
319 const WebString& attr =
320 element.GetAttribute(WebString::FromUTF16(attrName.ToString16()));
321 if (!attr.IsNull())
322 str = attr.Utf16();
323
324 return str;
325 }
326
GetElementAttributes(AttributeMap & attrMap)327 void CefDOMNodeImpl::GetElementAttributes(AttributeMap& attrMap) {
328 if (!VerifyContext())
329 return;
330
331 if (!node_.IsElementNode()) {
332 NOTREACHED();
333 return;
334 }
335
336 const WebElement& element = node_.ToConst<blink::WebElement>();
337 unsigned int len = element.AttributeCount();
338 if (len == 0)
339 return;
340
341 for (unsigned int i = 0; i < len; ++i) {
342 std::u16string name = element.AttributeLocalName(i).Utf16();
343 std::u16string value = element.AttributeValue(i).Utf16();
344 attrMap.insert(std::make_pair(name, value));
345 }
346 }
347
SetElementAttribute(const CefString & attrName,const CefString & value)348 bool CefDOMNodeImpl::SetElementAttribute(const CefString& attrName,
349 const CefString& value) {
350 if (!VerifyContext())
351 return false;
352
353 if (!node_.IsElementNode()) {
354 NOTREACHED();
355 return false;
356 }
357
358 WebElement element = node_.To<blink::WebElement>();
359 element.SetAttribute(WebString::FromUTF16(attrName.ToString16()),
360 WebString::FromUTF16(value.ToString16()));
361 return true;
362 }
363
GetElementInnerText()364 CefString CefDOMNodeImpl::GetElementInnerText() {
365 CefString str;
366 if (!VerifyContext())
367 return str;
368
369 if (!node_.IsElementNode()) {
370 NOTREACHED();
371 return str;
372 }
373
374 WebElement element = node_.To<blink::WebElement>();
375 const WebString& text = element.TextContent();
376 if (!text.IsNull())
377 str = text.Utf16();
378
379 return str;
380 }
381
GetElementBounds()382 CefRect CefDOMNodeImpl::GetElementBounds() {
383 CefRect rect;
384 if (!VerifyContext())
385 return rect;
386
387 if (!node_.IsElementNode()) {
388 NOTREACHED();
389 return rect;
390 }
391
392 WebElement element = node_.To<blink::WebElement>();
393 const auto& rc = element.BoundsInViewport();
394 rect.Set(rc.x(), rc.y(), rc.width(), rc.height());
395
396 return rect;
397 }
398
Detach()399 void CefDOMNodeImpl::Detach() {
400 document_ = nullptr;
401 node_.Assign(WebNode());
402 }
403
VerifyContext()404 bool CefDOMNodeImpl::VerifyContext() {
405 if (!document_.get()) {
406 NOTREACHED();
407 return false;
408 }
409 if (!document_->VerifyContext())
410 return false;
411 if (node_.IsNull()) {
412 NOTREACHED();
413 return false;
414 }
415 return true;
416 }
417