blob: 5cf1e8b0d1d221cc101f8cd16d2d66a8305e2e8a [file] [log] [blame]
// 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/blink_glue.h"
#include "libcef/renderer/browser_impl.h"
#include "libcef/renderer/dom_document_impl.h"
#include "libcef/renderer/thread_util.h"
#include "base/logging.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "third_party/blink/public/platform/web_string.h"
#include "third_party/blink/public/web/web_document.h"
#include "third_party/blink/public/web/web_dom_event.h"
#include "third_party/blink/public/web/web_element.h"
#include "third_party/blink/public/web/web_form_control_element.h"
#include "third_party/blink/public/web/web_input_element.h"
#include "third_party/blink/public/web/web_node.h"
#include "third_party/blink/public/web/web_select_element.h"
using blink::WebDocument;
using blink::WebDOMEvent;
using blink::WebElement;
using blink::WebFormControlElement;
using blink::WebInputElement;
using blink::WebNode;
using blink::WebSelectElement;
using blink::WebString;
CefDOMNodeImpl::CefDOMNodeImpl(CefRefPtr<CefDOMDocumentImpl> 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 blink_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<WebElement>();
if (blink_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<WebElement>();
return element.IsFormControlElement();
}
return false;
}
CefString CefDOMNodeImpl::GetFormControlElementType() {
CefString str;
if (!VerifyContext())
return str;
if (node_.IsElementNode()) {
const WebElement& element = node_.ToConst<WebElement>();
if (element.IsFormControlElement()) {
// Retrieve the type from the form control element.
const WebFormControlElement& formElement =
node_.ToConst<WebFormControlElement>();
const base::string16& form_control_type =
formElement.FormControlType().Utf16();
str = form_control_type;
}
}
return str;
}
bool CefDOMNodeImpl::IsSame(CefRefPtr<CefDOMNode> that) {
if (!VerifyContext())
return false;
CefDOMNodeImpl* impl = static_cast<CefDOMNodeImpl*>(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 = blink_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<WebElement>();
if (element.IsFormControlElement()) {
// Retrieve the value from the form control element.
const WebFormControlElement& formElement =
node_.ToConst<WebFormControlElement>();
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<WebInputElement>();
value = input_element.Value().Utf16();
} else if (form_control_type == base::ASCIIToUTF16("select-one")) {
const WebSelectElement& select_element =
formElement.ToConst<WebSelectElement>();
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 blink_glue::SetNodeValue(node_,
WebString::FromUTF16(value.ToString16()));
}
CefString CefDOMNodeImpl::GetAsMarkup() {
CefString str;
if (!VerifyContext())
return str;
const WebString& markup = blink_glue::CreateNodeMarkup(node_);
if (!markup.IsNull())
str = markup.Utf16();
return str;
}
CefRefPtr<CefDOMDocument> CefDOMNodeImpl::GetDocument() {
if (!VerifyContext())
return nullptr;
return document_.get();
}
CefRefPtr<CefDOMNode> CefDOMNodeImpl::GetParent() {
if (!VerifyContext())
return nullptr;
return document_->GetOrCreateNode(node_.ParentNode());
}
CefRefPtr<CefDOMNode> CefDOMNodeImpl::GetPreviousSibling() {
if (!VerifyContext())
return nullptr;
return document_->GetOrCreateNode(node_.PreviousSibling());
}
CefRefPtr<CefDOMNode> CefDOMNodeImpl::GetNextSibling() {
if (!VerifyContext())
return nullptr;
return document_->GetOrCreateNode(node_.NextSibling());
}
bool CefDOMNodeImpl::HasChildren() {
if (!VerifyContext())
return false;
return !node_.FirstChild().IsNull();
}
CefRefPtr<CefDOMNode> CefDOMNodeImpl::GetFirstChild() {
if (!VerifyContext())
return nullptr;
return document_->GetOrCreateNode(node_.FirstChild());
}
CefRefPtr<CefDOMNode> CefDOMNodeImpl::GetLastChild() {
if (!VerifyContext())
return nullptr;
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<blink::WebElement>();
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<blink::WebElement>();
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<blink::WebElement>();
return element.HasAttribute(WebString::FromUTF16(attrName.ToString16()));
}
CefString CefDOMNodeImpl::GetElementAttribute(const CefString& attrName) {
CefString str;
if (!VerifyContext())
return str;
if (!node_.IsElementNode()) {
NOTREACHED();
return str;
}
const WebElement& element = node_.ToConst<blink::WebElement>();
const WebString& attr =
element.GetAttribute(WebString::FromUTF16(attrName.ToString16()));
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<blink::WebElement>();
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<blink::WebElement>();
element.SetAttribute(WebString::FromUTF16(attrName.ToString16()),
WebString::FromUTF16(value.ToString16()));
return true;
}
CefString CefDOMNodeImpl::GetElementInnerText() {
CefString str;
if (!VerifyContext())
return str;
if (!node_.IsElementNode()) {
NOTREACHED();
return str;
}
WebElement element = node_.To<blink::WebElement>();
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::WebElement>();
blink::WebRect rc = element.BoundsInViewport();
rect.Set(rc.x, rc.y, rc.width, rc.height);
return rect;
}
void CefDOMNodeImpl::Detach() {
document_ = nullptr;
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;
}