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#pragma warning(push, 0)
34#include <WebCore/Document.h>
35#include <WebCore/Frame.h>
36#include <WebCore/HitTestResult.h>
37#include <WebCore/FrameLoader.h>
38#include <WebCore/Image.h>
39#include <WebCore/KURL.h>
40#include <WebCore/RenderObject.h>
41#pragma warning(pop)
42
43using namespace WebCore;
44
45// WebElementPropertyBag -----------------------------------------------
46WebElementPropertyBag::WebElementPropertyBag(const HitTestResult& result)
47    : m_result(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) = SysAllocStringLen(string.characters(), string.length());
107    if (string.length() && !V_BSTR(pVar))
108        return E_OUTOFMEMORY;
109
110    return S_OK;
111}
112
113
114HRESULT STDMETHODCALLTYPE 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()
131           && m_result->innerNonSharedNode()->document()->frame()))
132            return E_FAIL;
133        Frame* coreFrame = m_result->innerNonSharedNode()->document()->frame();
134        WebFrame* webFrame = static_cast<WebFrame*>(coreFrame->loader()->client());
135        IWebFrame* iWebFrame;
136        if (FAILED(webFrame->QueryInterface(IID_IWebFrame, (void**)&iWebFrame)))
137            return E_FAIL;
138        V_VT(pVar) = VT_UNKNOWN;
139        V_UNKNOWN(pVar) = iWebFrame;
140        return S_OK;
141    } else if (isEqual(WebElementImageAltStringKey, key))
142        return convertStringToVariant(pVar, m_result->altDisplayString());
143    else if (isEqual(WebElementImageKey, key)) {
144        V_VT(pVar) = VT_BYREF;
145        V_BYREF(pVar) = m_result->image();
146        return S_OK;
147    } else if (isEqual(WebElementImageRectKey, key)) {
148        V_VT(pVar) = VT_ARRAY;
149        IntRect boundingBox = m_result->innerNonSharedNode() && m_result->innerNonSharedNode()->renderer() ?
150                                m_result->innerNonSharedNode()->renderer()->absoluteBoundingBoxRect(true) : IntRect();
151        V_ARRAY(pVar) = MarshallingHelpers::intRectToSafeArray(boundingBox);
152        return S_OK;
153    } else if (isEqual(WebElementImageURLKey, key))
154        return convertStringToVariant(pVar, m_result->absoluteImageURL().string());
155    else if (isEqual(WebElementIsSelectedKey, key)) {
156        V_VT(pVar) = VT_BOOL;
157        if (m_result->isSelected())
158            V_BOOL(pVar) = VARIANT_TRUE;
159        else
160            V_BOOL(pVar) = VARIANT_FALSE;
161        return S_OK;
162    } else if (isEqual(WebElementSpellingToolTipKey, key)) {
163        TextDirection dir;
164        return convertStringToVariant(pVar, m_result->spellingToolTip(dir));
165    } else if (isEqual(WebElementTitleKey, key)) {
166        TextDirection dir;
167        return convertStringToVariant(pVar, m_result->title(dir));
168    }
169    else if (isEqual(WebElementLinkURLKey, key))
170        return convertStringToVariant(pVar, m_result->absoluteLinkURL().string());
171    else if (isEqual(WebElementLinkTargetFrameKey, key)) {
172        if (!m_result->targetFrame())
173            return E_FAIL;
174        WebFrame* webFrame = kit(m_result->targetFrame());
175        IWebFrame* iWebFrame;
176        if (FAILED(webFrame->QueryInterface(IID_IWebFrame, (void**)&iWebFrame)))
177            return E_FAIL;
178        V_VT(pVar) = VT_UNKNOWN;
179        V_UNKNOWN(pVar) = iWebFrame;
180        return S_OK;
181    } else if (isEqual(WebElementLinkTitleKey, key))
182        return convertStringToVariant(pVar, m_result->titleDisplayString());
183    else if (isEqual(WebElementLinkLabelKey, key))
184        return convertStringToVariant(pVar, m_result->textContent());
185    else if (isEqual(WebElementIsContentEditableKey, key)) {
186        V_VT(pVar) = VT_BOOL;
187        if (m_result->isContentEditable())
188            V_BOOL(pVar) = VARIANT_TRUE;
189        else
190            V_BOOL(pVar) = VARIANT_FALSE;
191        return S_OK;
192    }
193
194    return E_INVALIDARG;
195}
196
197HRESULT STDMETHODCALLTYPE WebElementPropertyBag::Write(LPCOLESTR pszPropName, VARIANT* pVar)
198{
199    if (!pszPropName || !pVar)
200        return E_POINTER;
201
202    return E_FAIL;
203}
204