// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights // reserved. Use of this source code is governed by a BSD-style license that // can be found in the LICENSE file. #include "libcef/renderer/dom_node_impl.h" #include "libcef/common/tracker.h" #include "libcef/renderer/browser_impl.h" #include "libcef/renderer/dom_document_impl.h" #include "libcef/renderer/thread_util.h" #include "libcef/renderer/webkit_glue.h" #include "base/logging.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "third_party/WebKit/public/platform/WebString.h" #include "third_party/WebKit/public/web/WebDocument.h" #include "third_party/WebKit/public/web/WebDOMEvent.h" #include "third_party/WebKit/public/web/WebElement.h" #include "third_party/WebKit/public/web/WebFrame.h" #include "third_party/WebKit/public/web/WebFormControlElement.h" #include "third_party/WebKit/public/web/WebInputElement.h" #include "third_party/WebKit/public/web/WebNode.h" #include "third_party/WebKit/public/web/WebSelectElement.h" using blink::WebDocument; using blink::WebDOMEvent; using blink::WebElement; using blink::WebFrame; using blink::WebFormControlElement; using blink::WebInputElement; using blink::WebNode; using blink::WebSelectElement; using blink::WebString; CefDOMNodeImpl::CefDOMNodeImpl(CefRefPtr document, const blink::WebNode& node) : document_(document), node_(node) { } CefDOMNodeImpl::~CefDOMNodeImpl() { CEF_REQUIRE_RT(); if (document_.get() && !node_.IsNull()) { // Remove the node from the document. document_->RemoveNode(node_); } } CefDOMNodeImpl::Type CefDOMNodeImpl::GetType() { if (!VerifyContext()) return DOM_NODE_TYPE_UNSUPPORTED; return webkit_glue::GetNodeType(node_); } bool CefDOMNodeImpl::IsText() { if (!VerifyContext()) return false; return node_.IsTextNode(); } bool CefDOMNodeImpl::IsElement() { if (!VerifyContext()) return false; return node_.IsElementNode(); } // Logic copied from RenderViewImpl::IsEditableNode. bool CefDOMNodeImpl::IsEditable() { if (!VerifyContext()) return false; if (node_.IsContentEditable()) return true; if (node_.IsElementNode()) { const WebElement& element = node_.ToConst(); if (webkit_glue::IsTextControlElement(element)) return true; // Also return true if it has an ARIA role of 'textbox'. for (unsigned i = 0; i < element.AttributeCount(); ++i) { if (base::LowerCaseEqualsASCII(element.AttributeLocalName(i).Utf8(), "role")) { if (base::LowerCaseEqualsASCII(element.AttributeValue(i).Utf8(), "textbox")) { return true; } break; } } } return false; } bool CefDOMNodeImpl::IsFormControlElement() { if (!VerifyContext()) return false; if (node_.IsElementNode()) { const WebElement& element = node_.ToConst(); return element.IsFormControlElement(); } return false; } CefString CefDOMNodeImpl::GetFormControlElementType() { CefString str; if (!VerifyContext()) return str; if (node_.IsElementNode()) { const WebElement& element = node_.ToConst(); if (element.IsFormControlElement()) { // Retrieve the type from the form control element. const WebFormControlElement& formElement = node_.ToConst(); const base::string16& form_control_type = formElement.FormControlType().Utf16(); str = form_control_type; } } return str; } bool CefDOMNodeImpl::IsSame(CefRefPtr that) { if (!VerifyContext()) return false; CefDOMNodeImpl* impl = static_cast(that.get()); if (!impl || !impl->VerifyContext()) return false; return node_.Equals(impl->node_); } CefString CefDOMNodeImpl::GetName() { CefString str; if (!VerifyContext()) return str; const WebString& name = webkit_glue::GetNodeName(node_); if (!name.IsNull()) str = name.Utf16(); return str; } CefString CefDOMNodeImpl::GetValue() { CefString str; if (!VerifyContext()) return str; if (node_.IsElementNode()) { const WebElement& element = node_.ToConst(); if (element.IsFormControlElement()) { // Retrieve the value from the form control element. const WebFormControlElement& formElement = node_.ToConst(); base::string16 value; const base::string16& form_control_type = formElement.FormControlType().Utf16(); if (form_control_type == base::ASCIIToUTF16("text")) { const WebInputElement& input_element = formElement.ToConst(); value = input_element.Value().Utf16(); } else if (form_control_type == base::ASCIIToUTF16("select-one")) { const WebSelectElement& select_element = formElement.ToConst(); value = select_element.Value().Utf16(); } base::TrimWhitespace(value, base::TRIM_LEADING, &value); str = value; } } if (str.empty()) { const WebString& value = node_.NodeValue(); if (!value.IsNull()) str = value.Utf16(); } return str; } bool CefDOMNodeImpl::SetValue(const CefString& value) { if (!VerifyContext()) return false; if (node_.IsElementNode()) return false; return webkit_glue::SetNodeValue(node_, WebString::FromUTF16(value)); } CefString CefDOMNodeImpl::GetAsMarkup() { CefString str; if (!VerifyContext()) return str; const WebString& markup = webkit_glue::CreateNodeMarkup(node_); if (!markup.IsNull()) str = markup.Utf16(); return str; } CefRefPtr CefDOMNodeImpl::GetDocument() { if (!VerifyContext()) return NULL; return document_.get(); } CefRefPtr CefDOMNodeImpl::GetParent() { if (!VerifyContext()) return NULL; return document_->GetOrCreateNode(node_.ParentNode()); } CefRefPtr CefDOMNodeImpl::GetPreviousSibling() { if (!VerifyContext()) return NULL; return document_->GetOrCreateNode(node_.PreviousSibling()); } CefRefPtr CefDOMNodeImpl::GetNextSibling() { if (!VerifyContext()) return NULL; return document_->GetOrCreateNode(node_.NextSibling()); } bool CefDOMNodeImpl::HasChildren() { if (!VerifyContext()) return false; return !node_.FirstChild().IsNull(); } CefRefPtr CefDOMNodeImpl::GetFirstChild() { if (!VerifyContext()) return NULL; return document_->GetOrCreateNode(node_.FirstChild()); } CefRefPtr CefDOMNodeImpl::GetLastChild() { if (!VerifyContext()) return NULL; return document_->GetOrCreateNode(node_.LastChild()); } CefString CefDOMNodeImpl::GetElementTagName() { CefString str; if (!VerifyContext()) return str; if (!node_.IsElementNode()) { NOTREACHED(); return str; } const WebElement& element = node_.ToConst(); const WebString& tagname = element.TagName(); if (!tagname.IsNull()) str = tagname.Utf16(); return str; } bool CefDOMNodeImpl::HasElementAttributes() { if (!VerifyContext()) return false; if (!node_.IsElementNode()) { NOTREACHED(); return false; } const WebElement& element = node_.ToConst(); return (element.AttributeCount() > 0); } bool CefDOMNodeImpl::HasElementAttribute(const CefString& attrName) { if (!VerifyContext()) return false; if (!node_.IsElementNode()) { NOTREACHED(); return false; } const WebElement& element = node_.ToConst(); return element.HasAttribute(WebString::FromUTF16(attrName)); } CefString CefDOMNodeImpl::GetElementAttribute(const CefString& attrName) { CefString str; if (!VerifyContext()) return str; if (!node_.IsElementNode()) { NOTREACHED(); return str; } const WebElement& element = node_.ToConst(); const WebString& attr = element.GetAttribute(WebString::FromUTF16(attrName)); if (!attr.IsNull()) str = attr.Utf16(); return str; } void CefDOMNodeImpl::GetElementAttributes(AttributeMap& attrMap) { if (!VerifyContext()) return; if (!node_.IsElementNode()) { NOTREACHED(); return; } const WebElement& element = node_.ToConst(); unsigned int len = element.AttributeCount(); if (len == 0) return; for (unsigned int i = 0; i < len; ++i) { base::string16 name = element.AttributeLocalName(i).Utf16(); base::string16 value = element.AttributeValue(i).Utf16(); attrMap.insert(std::make_pair(name, value)); } } bool CefDOMNodeImpl::SetElementAttribute(const CefString& attrName, const CefString& value) { if (!VerifyContext()) return false; if (!node_.IsElementNode()) { NOTREACHED(); return false; } WebElement element = node_.To(); element.SetAttribute(WebString::FromUTF16(attrName), WebString::FromUTF16(value)); return true; } CefString CefDOMNodeImpl::GetElementInnerText() { CefString str; if (!VerifyContext()) return str; if (!node_.IsElementNode()) { NOTREACHED(); return str; } WebElement element = node_.To(); const WebString& text = element.TextContent(); if (!text.IsNull()) str = text.Utf16(); return str; } CefRect CefDOMNodeImpl::GetElementBounds() { CefRect rect; if (!VerifyContext()) return rect; if (!node_.IsElementNode()) { NOTREACHED(); return rect; } WebElement element = node_.To(); blink::WebRect rc = element.BoundsInViewport(); rect.Set(rc.x, rc.y, rc.width, rc.height); return rect; } void CefDOMNodeImpl::Detach() { document_ = NULL; node_.Assign(WebNode()); } bool CefDOMNodeImpl::VerifyContext() { if (!document_.get()) { NOTREACHED(); return false; } if (!document_->VerifyContext()) return false; if (node_.IsNull()) { NOTREACHED(); return false; } return true; }