summaryrefslogtreecommitdiffstats
path: root/ceee/ie/plugin/bho/dom_utils.cc
blob: 714e1082d4e0c588940829e1ee1751bafb57d7d4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// A collection of utility functions that interrogate or mutate the IE DOM.
#include "ceee/ie/plugin/bho/dom_utils.h"

#include <atlbase.h>

#include "ceee/common/com_utils.h"
#include "base/logging.h"

HRESULT DomUtils::InjectStyleTag(IHTMLDocument2* document,
                                 IHTMLDOMNode* head_node,
                                 const wchar_t* code) {
  DCHECK(document != NULL);
  DCHECK(head_node != NULL);

  CComPtr<IHTMLElement> elem;
  HRESULT hr = document->createElement(CComBSTR(L"style"), &elem);
  if (FAILED(hr)) {
    LOG(ERROR) << "Could not create style element " << com::LogHr(hr);
    return hr;
  }

  CComQIPtr<IHTMLStyleElement> style_elem(elem);
  DCHECK(style_elem != NULL) <<
      "Could not QueryInterface for IHTMLStyleElement";

  hr = style_elem->put_type(CComBSTR(L"text/css"));
  DCHECK(SUCCEEDED(hr)) << "Could not set type of style element" <<
      com::LogHr(hr);

  CComPtr<IHTMLStyleSheet> style_sheet;
  hr = style_elem->get_styleSheet(&style_sheet);
  DCHECK(SUCCEEDED(hr)) << "Could not get styleSheet of style element." <<
      com::LogHr(hr);

  hr = style_sheet->put_cssText(CComBSTR(code));
  if (FAILED(hr)) {
    LOG(ERROR) << "Could not set cssText of styleSheet." << com::LogHr(hr);
    return hr;
  }

  CComQIPtr<IHTMLDOMNode> style_node(style_elem);
  DCHECK(style_node != NULL) << "Could not query interface for IHTMLDomNode.";

  CComPtr<IHTMLDOMNode> dummy;
  hr = head_node->appendChild(style_node, &dummy);
  if (FAILED(hr))
    LOG(ERROR) << "Could not append style node to head node." << com::LogHr(hr);

  return hr;
}

HRESULT DomUtils::GetHeadNode(IHTMLDocument* document,
                              IHTMLDOMNode** head_node) {
  DCHECK(document != NULL);
  DCHECK(head_node != NULL && *head_node == NULL);

  // Find the HEAD element through document.getElementsByTagName.
  CComQIPtr<IHTMLDocument3> document3(document);
  CComPtr<IHTMLElementCollection> head_elements;
  DCHECK(document3 != NULL);  // Should be there on IE >= 5
  if (document3 == NULL) {
    LOG(ERROR) << L"Unable to retrieve IHTMLDocument3 interface";
    return E_NOINTERFACE;
  }
  HRESULT hr = GetElementsByTagName(document3, CComBSTR(L"head"),
                                    &head_elements, NULL);
  if (FAILED(hr)) {
    LOG(ERROR) << "Could not retrieve head elements collection "
        << com::LogHr(hr);
    return hr;
  }

  return GetElementFromCollection(head_elements, 0, IID_IHTMLDOMNode,
                                  reinterpret_cast<void**>(head_node));
}

HRESULT DomUtils::GetElementsByTagName(IHTMLDocument3* document,
                                       BSTR tag_name,
                                       IHTMLElementCollection** elements,
                                       long* length) {
  DCHECK(document != NULL);
  DCHECK(tag_name != NULL);
  DCHECK(elements != NULL && *elements == NULL);

  HRESULT hr = document->getElementsByTagName(tag_name, elements);
  if (FAILED(hr) || *elements == NULL) {
    hr = com::AlwaysError(hr);
    LOG(ERROR) << "Could not retrieve elements collection " << com::LogHr(hr);
    return hr;
  }

  if (length != NULL) {
    hr = (*elements)->get_length(length);
    if (FAILED(hr)) {
      (*elements)->Release();
      *elements = NULL;
      LOG(ERROR) << "Could not retrieve collection length " << com::LogHr(hr);
    }
  }
  return hr;
}

HRESULT DomUtils::GetElementFromCollection(IHTMLElementCollection* collection,
                                           long index,
                                           REFIID id,
                                           void** element) {
  DCHECK(collection != NULL);
  DCHECK(element != NULL && *element == NULL);

  CComPtr<IDispatch> item;
  CComVariant index_variant(index, VT_I4);
  HRESULT hr = collection->item(index_variant, index_variant, &item);
  // As per http://msdn.microsoft.com/en-us/library/aa703930(VS.85).aspx
  // item may still be NULL even if S_OK is returned.
  if (FAILED(hr) || item == NULL) {
    hr = com::AlwaysError(hr);
    LOG(ERROR) << "Could not access item " << com::LogHr(hr);
    return hr;
  }

  return item->QueryInterface(id, element);
}