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_document_impl.h" 6 #include "libcef/renderer/dom_node_impl.h" 7 #include "libcef/renderer/thread_util.h" 8 9 #include "base/logging.h" 10 #include "third_party/blink/public/platform/web_string.h" 11 #include "third_party/blink/public/platform/web_url.h" 12 #include "third_party/blink/public/web/web_document.h" 13 #include "third_party/blink/public/web/web_element.h" 14 #include "third_party/blink/public/web/web_local_frame.h" 15 #include "third_party/blink/public/web/web_node.h" 16 #include "third_party/blink/public/web/web_range.h" 17 18 using blink::WebDocument; 19 using blink::WebElement; 20 using blink::WebLocalFrame; 21 using blink::WebNode; 22 using blink::WebRange; 23 using blink::WebString; 24 using blink::WebURL; 25 CefDOMDocumentImpl(CefBrowserImpl * browser,WebLocalFrame * frame)26CefDOMDocumentImpl::CefDOMDocumentImpl(CefBrowserImpl* browser, 27 WebLocalFrame* frame) 28 : browser_(browser), frame_(frame) { 29 const WebDocument& document = frame_->GetDocument(); 30 DCHECK(!document.IsNull()); 31 } 32 ~CefDOMDocumentImpl()33CefDOMDocumentImpl::~CefDOMDocumentImpl() { 34 CEF_REQUIRE_RT(); 35 36 // Verify that the Detach() method has been called. 37 DCHECK(frame_ == nullptr); 38 } 39 GetType()40CefDOMDocumentImpl::Type CefDOMDocumentImpl::GetType() { 41 if (!VerifyContext()) 42 return DOM_DOCUMENT_TYPE_UNKNOWN; 43 44 const WebDocument& document = frame_->GetDocument(); 45 if (document.IsHTMLDocument()) 46 return DOM_DOCUMENT_TYPE_HTML; 47 if (document.IsXHTMLDocument()) 48 return DOM_DOCUMENT_TYPE_XHTML; 49 if (document.IsPluginDocument()) 50 return DOM_DOCUMENT_TYPE_PLUGIN; 51 return DOM_DOCUMENT_TYPE_UNKNOWN; 52 } 53 GetDocument()54CefRefPtr<CefDOMNode> CefDOMDocumentImpl::GetDocument() { 55 const WebDocument& document = frame_->GetDocument(); 56 return GetOrCreateNode(document.GetDocument()); 57 } 58 GetBody()59CefRefPtr<CefDOMNode> CefDOMDocumentImpl::GetBody() { 60 const WebDocument& document = frame_->GetDocument(); 61 return GetOrCreateNode(document.Body()); 62 } 63 GetHead()64CefRefPtr<CefDOMNode> CefDOMDocumentImpl::GetHead() { 65 WebDocument document = frame_->GetDocument(); 66 return GetOrCreateNode(document.Head()); 67 } 68 GetTitle()69CefString CefDOMDocumentImpl::GetTitle() { 70 CefString str; 71 if (!VerifyContext()) 72 return str; 73 74 const WebDocument& document = frame_->GetDocument(); 75 const WebString& title = document.Title(); 76 if (!title.IsNull()) 77 str = title.Utf16(); 78 79 return str; 80 } 81 GetElementById(const CefString & id)82CefRefPtr<CefDOMNode> CefDOMDocumentImpl::GetElementById(const CefString& id) { 83 const WebDocument& document = frame_->GetDocument(); 84 return GetOrCreateNode( 85 document.GetElementById(WebString::FromUTF16(id.ToString16()))); 86 } 87 GetFocusedNode()88CefRefPtr<CefDOMNode> CefDOMDocumentImpl::GetFocusedNode() { 89 const WebDocument& document = frame_->GetDocument(); 90 return GetOrCreateNode(document.FocusedElement()); 91 } 92 HasSelection()93bool CefDOMDocumentImpl::HasSelection() { 94 if (!VerifyContext()) 95 return false; 96 97 return frame_->HasSelection(); 98 } 99 GetSelectionStartOffset()100int CefDOMDocumentImpl::GetSelectionStartOffset() { 101 if (!VerifyContext()) 102 return 0; 103 104 if (!frame_->HasSelection()) 105 return 0; 106 107 const WebRange& range = frame_->SelectionRange(); 108 if (range.IsNull()) 109 return 0; 110 111 return range.StartOffset(); 112 } 113 GetSelectionEndOffset()114int CefDOMDocumentImpl::GetSelectionEndOffset() { 115 if (!VerifyContext()) 116 return 0; 117 118 if (!frame_->HasSelection()) 119 return 0; 120 121 const WebRange& range = frame_->SelectionRange(); 122 if (range.IsNull()) 123 return 0; 124 125 return range.EndOffset(); 126 } 127 GetSelectionAsMarkup()128CefString CefDOMDocumentImpl::GetSelectionAsMarkup() { 129 CefString str; 130 if (!VerifyContext()) 131 return str; 132 133 if (!frame_->HasSelection()) 134 return str; 135 136 const WebString& markup = frame_->SelectionAsMarkup(); 137 if (!markup.IsNull()) 138 str = markup.Utf16(); 139 140 return str; 141 } 142 GetSelectionAsText()143CefString CefDOMDocumentImpl::GetSelectionAsText() { 144 CefString str; 145 if (!VerifyContext()) 146 return str; 147 148 if (!frame_->HasSelection()) 149 return str; 150 151 const WebString& text = frame_->SelectionAsText(); 152 if (!text.IsNull()) 153 str = text.Utf16(); 154 155 return str; 156 } 157 GetBaseURL()158CefString CefDOMDocumentImpl::GetBaseURL() { 159 CefString str; 160 if (!VerifyContext()) 161 return str; 162 163 const WebDocument& document = frame_->GetDocument(); 164 const WebURL& url = document.BaseURL(); 165 if (!url.IsNull()) { 166 GURL gurl = url; 167 str = gurl.spec(); 168 } 169 170 return str; 171 } 172 GetCompleteURL(const CefString & partialURL)173CefString CefDOMDocumentImpl::GetCompleteURL(const CefString& partialURL) { 174 CefString str; 175 if (!VerifyContext()) 176 return str; 177 178 const WebDocument& document = frame_->GetDocument(); 179 const WebURL& url = 180 document.CompleteURL(WebString::FromUTF16(partialURL.ToString16())); 181 if (!url.IsNull()) { 182 GURL gurl = url; 183 str = gurl.spec(); 184 } 185 186 return str; 187 } 188 GetOrCreateNode(const blink::WebNode & node)189CefRefPtr<CefDOMNode> CefDOMDocumentImpl::GetOrCreateNode( 190 const blink::WebNode& node) { 191 if (!VerifyContext()) 192 return nullptr; 193 194 // Nodes may potentially be null. 195 if (node.IsNull()) 196 return nullptr; 197 198 if (!node_map_.empty()) { 199 // Locate the existing node, if any. 200 NodeMap::const_iterator it = node_map_.find(node); 201 if (it != node_map_.end()) 202 return it->second; 203 } 204 205 // Create the new node object. 206 CefRefPtr<CefDOMNode> nodeImpl(new CefDOMNodeImpl(this, node)); 207 node_map_.insert(std::make_pair(node, nodeImpl.get())); 208 return nodeImpl; 209 } 210 RemoveNode(const blink::WebNode & node)211void CefDOMDocumentImpl::RemoveNode(const blink::WebNode& node) { 212 if (!VerifyContext()) 213 return; 214 215 if (!node_map_.empty()) { 216 NodeMap::iterator it = node_map_.find(node); 217 if (it != node_map_.end()) 218 node_map_.erase(it); 219 } 220 } 221 Detach()222void CefDOMDocumentImpl::Detach() { 223 if (!VerifyContext()) 224 return; 225 226 // If you hit this assert it means that you are keeping references to node 227 // objects beyond the valid scope. 228 DCHECK(node_map_.empty()); 229 230 // If you hit this assert it means that you are keeping references to this 231 // document object beyond the valid scope. 232 DCHECK(HasOneRef()); 233 234 if (!node_map_.empty()) { 235 NodeMap::const_iterator it = node_map_.begin(); 236 for (; it != node_map_.end(); ++it) 237 static_cast<CefDOMNodeImpl*>(it->second)->Detach(); 238 node_map_.clear(); 239 } 240 241 frame_ = nullptr; 242 } 243 VerifyContext()244bool CefDOMDocumentImpl::VerifyContext() { 245 if (!CEF_CURRENTLY_ON_RT() || frame_ == nullptr) { 246 NOTREACHED(); 247 return false; 248 } 249 return true; 250 } 251