1/*
2 * Copyright (C) 2006, 2007 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 COMPUTER, 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 COMPUTER, 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 <WebCore/Document.h>
34#include <WebCore/Frame.h>
35#include <WebCore/HitTestResult.h>
36#include <WebCore/FrameLoader.h>
37#include <WebCore/Image.h>
38#include <WebCore/KURL.h>
39#include <WebCore/RenderObject.h>
40
41using namespace WebCore;
42
43// WebElementPropertyBag -----------------------------------------------
44WebElementPropertyBag::WebElementPropertyBag(const HitTestResult& result)
45    : m_result(new HitTestResult(result))
46    , m_refCount(0)
47{
48    gClassCount++;
49    gClassNameCount.add("WebElementPropertyBag");
50}
51
52WebElementPropertyBag::~WebElementPropertyBag()
53{
54    gClassCount--;
55    gClassNameCount.remove("WebElementPropertyBag");
56}
57
58WebElementPropertyBag* WebElementPropertyBag::createInstance(const HitTestResult& result)
59{
60    WebElementPropertyBag* instance = new WebElementPropertyBag(result);
61    instance->AddRef();
62
63    return instance;
64}
65
66// IUnknown -------------------------------------------------------------------
67
68HRESULT STDMETHODCALLTYPE WebElementPropertyBag::QueryInterface(REFIID riid, void** ppvObject)
69{
70    *ppvObject = 0;
71    if (IsEqualGUID(riid, IID_IUnknown))
72        *ppvObject = static_cast<IPropertyBag*>(this);
73    else if (IsEqualGUID(riid, IID_IPropertyBag))
74        *ppvObject = static_cast<IPropertyBag*>(this);
75    else
76        return E_NOINTERFACE;
77
78    AddRef();
79    return S_OK;
80}
81
82ULONG STDMETHODCALLTYPE WebElementPropertyBag::AddRef(void)
83{
84    return ++m_refCount;
85}
86
87ULONG STDMETHODCALLTYPE WebElementPropertyBag::Release(void)
88{
89    ULONG newRef = --m_refCount;
90    if (!newRef)
91        delete this;
92
93    return newRef;
94}
95
96static bool isEqual(LPCWSTR s1, LPCWSTR s2)
97{
98    return !wcscmp(s1, s2);
99}
100
101static HRESULT convertStringToVariant(VARIANT* pVar, const String& string)
102{
103    V_VT(pVar) = VT_BSTR;
104    V_BSTR(pVar) = SysAllocStringLen(string.characters(), string.length());
105    if (string.length() && !V_BSTR(pVar))
106        return E_OUTOFMEMORY;
107
108    return S_OK;
109}
110
111
112HRESULT STDMETHODCALLTYPE WebElementPropertyBag::Read(LPCOLESTR pszPropName, VARIANT *pVar, IErrorLog * /*pErrorLog*/)
113{
114    if (!pszPropName)
115        return E_POINTER;
116
117    if (!m_result)
118        return E_FAIL;
119
120    BSTR key = (BSTR)pszPropName;
121    VariantClear(pVar);
122    if (isEqual(WebElementDOMNodeKey, key)) {
123        IDOMNode* node = DOMNode::createInstance(m_result->innerNonSharedNode());
124        V_VT(pVar) = VT_UNKNOWN;
125        V_UNKNOWN(pVar) = node;
126        return S_OK;
127    } else if (isEqual(WebElementFrameKey, key)) {
128        if (!(m_result->innerNonSharedNode() && m_result->innerNonSharedNode()->document()
129           && m_result->innerNonSharedNode()->document()->frame()))
130            return E_FAIL;
131        Frame* coreFrame = m_result->innerNonSharedNode()->document()->frame();
132        WebFrame* webFrame = static_cast<WebFrame*>(coreFrame->loader()->client());
133        IWebFrame* iWebFrame;
134        if (FAILED(webFrame->QueryInterface(IID_IWebFrame, (void**)&iWebFrame)))
135            return E_FAIL;
136        V_VT(pVar) = VT_UNKNOWN;
137        V_UNKNOWN(pVar) = iWebFrame;
138        return S_OK;
139    } else if (isEqual(WebElementImageAltStringKey, key))
140        return convertStringToVariant(pVar, m_result->altDisplayString());
141    else if (isEqual(WebElementImageKey, key)) {
142        V_VT(pVar) = VT_BYREF;
143        V_BYREF(pVar) = m_result->image();
144        return S_OK;
145    } else if (isEqual(WebElementImageRectKey, key)) {
146        V_VT(pVar) = VT_ARRAY;
147        IntRect boundingBox = m_result->innerNonSharedNode() && m_result->innerNonSharedNode()->renderer() ?
148                                m_result->innerNonSharedNode()->renderer()->absoluteBoundingBoxRect(true) : IntRect();
149        V_ARRAY(pVar) = MarshallingHelpers::intRectToSafeArray(boundingBox);
150        return S_OK;
151    } else if (isEqual(WebElementImageURLKey, key))
152        return convertStringToVariant(pVar, m_result->absoluteImageURL().string());
153    else if (isEqual(WebElementIsSelectedKey, key)) {
154        V_VT(pVar) = VT_BOOL;
155        if (m_result->isSelected())
156            V_BOOL(pVar) = VARIANT_TRUE;
157        else
158            V_BOOL(pVar) = VARIANT_FALSE;
159        return S_OK;
160    }
161    if (isEqual(WebElementMediaURLKey, key))
162        return convertStringToVariant(pVar, m_result->absoluteMediaURL().string());
163    if (isEqual(WebElementSpellingToolTipKey, key)) {
164        TextDirection dir;
165        return convertStringToVariant(pVar, m_result->spellingToolTip(dir));
166    } else if (isEqual(WebElementTitleKey, key)) {
167        TextDirection dir;
168        return convertStringToVariant(pVar, m_result->title(dir));
169    }
170    else if (isEqual(WebElementLinkURLKey, key))
171        return convertStringToVariant(pVar, m_result->absoluteLinkURL().string());
172    else if (isEqual(WebElementLinkTargetFrameKey, key)) {
173        if (!m_result->targetFrame())
174            return E_FAIL;
175        WebFrame* webFrame = kit(m_result->targetFrame());
176        IWebFrame* iWebFrame;
177        if (FAILED(webFrame->QueryInterface(IID_IWebFrame, (void**)&iWebFrame)))
178            return E_FAIL;
179        V_VT(pVar) = VT_UNKNOWN;
180        V_UNKNOWN(pVar) = iWebFrame;
181        return S_OK;
182    } else if (isEqual(WebElementLinkTitleKey, key))
183        return convertStringToVariant(pVar, m_result->titleDisplayString());
184    else if (isEqual(WebElementLinkLabelKey, key))
185        return convertStringToVariant(pVar, m_result->textContent());
186    else if (isEqual(WebElementIsContentEditableKey, key)) {
187        V_VT(pVar) = VT_BOOL;
188        if (m_result->isContentEditable())
189            V_BOOL(pVar) = VARIANT_TRUE;
190        else
191            V_BOOL(pVar) = VARIANT_FALSE;
192        return S_OK;
193    }
194
195    return E_INVALIDARG;
196}
197
198HRESULT STDMETHODCALLTYPE WebElementPropertyBag::Write(LPCOLESTR pszPropName, VARIANT* pVar)
199{
200    if (!pszPropName || !pVar)
201        return E_POINTER;
202
203    return E_FAIL;
204}
205