1/*
2 * Copyright (C) 2006, 2007, 2013 Apple Inc.  All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "WebKitDLL.h"
28#include "WebElementPropertyBag.h"
29
30#include "MarshallingHelpers.h"
31#include "DOMCoreClasses.h"
32#include "WebFrame.h"
33#include "WebFrameLoaderClient.h"
34#include <WebCore/BString.h>
35#include <WebCore/Document.h>
36#include <WebCore/Frame.h>
37#include <WebCore/HitTestResult.h>
38#include <WebCore/FrameLoader.h>
39#include <WebCore/Image.h>
40#include <WebCore/URL.h>
41#include <WebCore/RenderObject.h>
42
43using namespace WebCore;
44
45// WebElementPropertyBag -----------------------------------------------
46WebElementPropertyBag::WebElementPropertyBag(const HitTestResult& result)
47    : m_result(adoptPtr(new HitTestResult(result)))
48    , m_refCount(0)
49{
50    gClassCount++;
51    gClassNameCount.add("WebElementPropertyBag");
52}
53
54WebElementPropertyBag::~WebElementPropertyBag()
55{
56    gClassCount--;
57    gClassNameCount.remove("WebElementPropertyBag");
58}
59
60WebElementPropertyBag* WebElementPropertyBag::createInstance(const HitTestResult& result)
61{
62    WebElementPropertyBag* instance = new WebElementPropertyBag(result);
63    instance->AddRef();
64
65    return instance;
66}
67
68// IUnknown -------------------------------------------------------------------
69
70HRESULT STDMETHODCALLTYPE WebElementPropertyBag::QueryInterface(REFIID riid, void** ppvObject)
71{
72    *ppvObject = 0;
73    if (IsEqualGUID(riid, IID_IUnknown))
74        *ppvObject = static_cast<IPropertyBag*>(this);
75    else if (IsEqualGUID(riid, IID_IPropertyBag))
76        *ppvObject = static_cast<IPropertyBag*>(this);
77    else
78        return E_NOINTERFACE;
79
80    AddRef();
81    return S_OK;
82}
83
84ULONG STDMETHODCALLTYPE WebElementPropertyBag::AddRef(void)
85{
86    return ++m_refCount;
87}
88
89ULONG STDMETHODCALLTYPE WebElementPropertyBag::Release(void)
90{
91    ULONG newRef = --m_refCount;
92    if (!newRef)
93        delete this;
94
95    return newRef;
96}
97
98static bool isEqual(LPCWSTR s1, LPCWSTR s2)
99{
100    return !wcscmp(s1, s2);
101}
102
103static HRESULT convertStringToVariant(VARIANT* pVar, const String& string)
104{
105    V_VT(pVar) = VT_BSTR;
106    V_BSTR(pVar) = BString(string).release();
107    if (string.length() && !V_BSTR(pVar))
108        return E_OUTOFMEMORY;
109
110    return S_OK;
111}
112
113
114HRESULT WebElementPropertyBag::Read(LPCOLESTR pszPropName, VARIANT *pVar, IErrorLog * /*pErrorLog*/)
115{
116    if (!pszPropName)
117        return E_POINTER;
118
119    if (!m_result)
120        return E_FAIL;
121
122    BSTR key = (BSTR)pszPropName;
123    VariantClear(pVar);
124    if (isEqual(WebElementDOMNodeKey, key)) {
125        IDOMNode* node = DOMNode::createInstance(m_result->innerNonSharedNode());
126        V_VT(pVar) = VT_UNKNOWN;
127        V_UNKNOWN(pVar) = node;
128        return S_OK;
129    } else if (isEqual(WebElementFrameKey, key)) {
130        if (!(m_result->innerNonSharedNode() && m_result->innerNonSharedNode()->document().frame()))
131            return E_FAIL;
132        Frame* coreFrame = m_result->innerNonSharedNode()->document().frame();
133        WebFrame* webFrame = static_cast<WebFrameLoaderClient&>(coreFrame->loader().client()).webFrame();
134        IWebFrame* iWebFrame;
135        if (FAILED(webFrame->QueryInterface(IID_IWebFrame, (void**)&iWebFrame)))
136            return E_FAIL;
137        V_VT(pVar) = VT_UNKNOWN;
138        V_UNKNOWN(pVar) = iWebFrame;
139        return S_OK;
140    } else if (isEqual(WebElementImageAltStringKey, key))
141        return convertStringToVariant(pVar, m_result->altDisplayString());
142    else if (isEqual(WebElementImageKey, key)) {
143        V_VT(pVar) = VT_BYREF;
144        V_BYREF(pVar) = m_result->image();
145        return S_OK;
146    } else if (isEqual(WebElementImageRectKey, key)) {
147        V_VT(pVar) = VT_ARRAY;
148        IntRect boundingBox = m_result->innerNonSharedNode() && m_result->innerNonSharedNode()->renderer() ?
149                                m_result->innerNonSharedNode()->renderer()->absoluteBoundingBoxRect(true) : IntRect();
150        V_ARRAY(pVar) = MarshallingHelpers::intRectToSafeArray(boundingBox);
151        return S_OK;
152    } else if (isEqual(WebElementImageURLKey, key))
153        return convertStringToVariant(pVar, m_result->absoluteImageURL().string());
154    else if (isEqual(WebElementIsSelectedKey, key)) {
155        V_VT(pVar) = VT_BOOL;
156        if (m_result->isSelected())
157            V_BOOL(pVar) = VARIANT_TRUE;
158        else
159            V_BOOL(pVar) = VARIANT_FALSE;
160        return S_OK;
161    }
162    if (isEqual(WebElementMediaURLKey, key))
163        return convertStringToVariant(pVar, m_result->absoluteMediaURL().string());
164    if (isEqual(WebElementSpellingToolTipKey, key)) {
165        TextDirection dir;
166        return convertStringToVariant(pVar, m_result->spellingToolTip(dir));
167    } else if (isEqual(WebElementTitleKey, key)) {
168        TextDirection dir;
169        return convertStringToVariant(pVar, m_result->title(dir));
170    }
171    else if (isEqual(WebElementLinkURLKey, key))
172        return convertStringToVariant(pVar, m_result->absoluteLinkURL().string());
173    else if (isEqual(WebElementLinkTargetFrameKey, key)) {
174        if (!m_result->targetFrame())
175            return E_FAIL;
176        WebFrame* webFrame = kit(m_result->targetFrame());
177        IWebFrame* iWebFrame;
178        if (FAILED(webFrame->QueryInterface(IID_IWebFrame, (void**)&iWebFrame)))
179            return E_FAIL;
180        V_VT(pVar) = VT_UNKNOWN;
181        V_UNKNOWN(pVar) = iWebFrame;
182        return S_OK;
183    } else if (isEqual(WebElementLinkTitleKey, key))
184        return convertStringToVariant(pVar, m_result->titleDisplayString());
185    else if (isEqual(WebElementLinkLabelKey, key))
186        return convertStringToVariant(pVar, m_result->textContent());
187    else if (isEqual(WebElementIsContentEditableKey, key)) {
188        V_VT(pVar) = VT_BOOL;
189        if (m_result->isContentEditable())
190            V_BOOL(pVar) = VARIANT_TRUE;
191        else
192            V_BOOL(pVar) = VARIANT_FALSE;
193        return S_OK;
194    }
195
196    return E_INVALIDARG;
197}
198
199HRESULT STDMETHODCALLTYPE WebElementPropertyBag::Write(LPCOLESTR pszPropName, VARIANT* pVar)
200{
201    if (!pszPropName || !pVar)
202        return E_POINTER;
203
204    return E_FAIL;
205}
206