diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c
index de0c94871f6..64356f5fde0 100644
--- a/dlls/mshtml/dispex.c
+++ b/dlls/mshtml/dispex.c
@@ -146,6 +146,7 @@ static REFIID tid_ids[] = {
&IID_IHTMLInputElement,
&IID_IHTMLLocation,
&IID_IHTMLOptionElement,
+ &IID_IHTMLRect,
&IID_IHTMLScreen,
&IID_IHTMLScriptElement,
&IID_IHTMLSelectElement,
diff --git a/dlls/mshtml/htmlelem2.c b/dlls/mshtml/htmlelem2.c
index 548bab8b2f5..b6030b8b54a 100644
--- a/dlls/mshtml/htmlelem2.c
+++ b/dlls/mshtml/htmlelem2.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2006 Jacek Caban for CodeWeavers
+ * Copyright 2006-2010 Jacek Caban for CodeWeavers
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -33,6 +33,198 @@
WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
+typedef struct {
+ DispatchEx dispex;
+ const IHTMLRectVtbl *lpIHTMLRectVtbl;
+ LONG ref;
+} HTMLRect;
+
+#define HTMLRECT(x) ((IHTMLRect*) &(x)->lpIHTMLRectVtbl)
+
+#define HTMLRECT_THIS(iface) DEFINE_THIS(HTMLRect, IHTMLRect, iface)
+
+static HRESULT WINAPI HTMLRect_QueryInterface(IHTMLRect *iface, REFIID riid, void **ppv)
+{
+ HTMLRect *This = HTMLRECT_THIS(iface);
+
+ if(IsEqualGUID(&IID_IUnknown, riid)) {
+ TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
+ *ppv = HTMLRECT(This);
+ }else if(IsEqualGUID(&IID_IHTMLRect, riid)) {
+ TRACE("(%p)->(IID_IHTMLRect %p)\n", This, ppv);
+ *ppv = HTMLRECT(This);
+ }else if(dispex_query_interface(&This->dispex, riid, ppv)) {
+ return *ppv ? S_OK : E_NOINTERFACE;
+ }else {
+ FIXME("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
+ *ppv = NULL;
+ return E_NOINTERFACE;
+ }
+
+ IUnknown_AddRef((IUnknown*)*ppv);
+ return S_OK;
+}
+
+static ULONG WINAPI HTMLRect_AddRef(IHTMLRect *iface)
+{
+ HTMLRect *This = HTMLRECT_THIS(iface);
+ LONG ref = InterlockedIncrement(&This->ref);
+
+ TRACE("(%p) ref=%d\n", This, ref);
+
+ return ref;
+}
+
+static ULONG WINAPI HTMLRect_Release(IHTMLRect *iface)
+{
+ HTMLRect *This = HTMLRECT_THIS(iface);
+ LONG ref = InterlockedDecrement(&This->ref);
+
+ TRACE("(%p) ref=%d\n", This, ref);
+
+ if(!ref)
+ heap_free(This);
+
+ return ref;
+}
+
+static HRESULT WINAPI HTMLRect_GetTypeInfoCount(IHTMLRect *iface, UINT *pctinfo)
+{
+ HTMLRect *This = HTMLRECT_THIS(iface);
+ FIXME("(%p)->(%p)\n", This, pctinfo);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI HTMLRect_GetTypeInfo(IHTMLRect *iface, UINT iTInfo,
+ LCID lcid, ITypeInfo **ppTInfo)
+{
+ HTMLRect *This = HTMLRECT_THIS(iface);
+
+ return IDispatchEx_GetTypeInfo(DISPATCHEX(&This->dispex), iTInfo, lcid, ppTInfo);
+}
+
+static HRESULT WINAPI HTMLRect_GetIDsOfNames(IHTMLRect *iface, REFIID riid,
+ LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
+{
+ HTMLRect *This = HTMLRECT_THIS(iface);
+
+ return IDispatchEx_GetIDsOfNames(DISPATCHEX(&This->dispex), riid, rgszNames, cNames, lcid, rgDispId);
+}
+
+static HRESULT WINAPI HTMLRect_Invoke(IHTMLRect *iface, DISPID dispIdMember,
+ REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
+ VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
+{
+ HTMLRect *This = HTMLRECT_THIS(iface);
+
+ return IDispatchEx_Invoke(DISPATCHEX(&This->dispex), dispIdMember, riid, lcid, wFlags, pDispParams,
+ pVarResult, pExcepInfo, puArgErr);
+}
+
+static HRESULT WINAPI HTMLRect_put_left(IHTMLRect *iface, LONG v)
+{
+ HTMLRect *This = HTMLRECT_THIS(iface);
+ FIXME("(%p)->(%d)\n", This, v);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI HTMLRect_get_left(IHTMLRect *iface, LONG *p)
+{
+ HTMLRect *This = HTMLRECT_THIS(iface);
+ FIXME("(%p)->(%p)\n", This, p);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI HTMLRect_put_top(IHTMLRect *iface, LONG v)
+{
+ HTMLRect *This = HTMLRECT_THIS(iface);
+ FIXME("(%p)->(%d)\n", This, v);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI HTMLRect_get_top(IHTMLRect *iface, LONG *p)
+{
+ HTMLRect *This = HTMLRECT_THIS(iface);
+ FIXME("(%p)->(%p)\n", This, p);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI HTMLRect_put_right(IHTMLRect *iface, LONG v)
+{
+ HTMLRect *This = HTMLRECT_THIS(iface);
+ FIXME("(%p)->(%d)\n", This, v);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI HTMLRect_get_right(IHTMLRect *iface, LONG *p)
+{
+ HTMLRect *This = HTMLRECT_THIS(iface);
+ FIXME("(%p)->(%p)\n", This, p);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI HTMLRect_put_bottom(IHTMLRect *iface, LONG v)
+{
+ HTMLRect *This = HTMLRECT_THIS(iface);
+ FIXME("(%p)->(%d)\n", This, v);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI HTMLRect_get_bottom(IHTMLRect *iface, LONG *p)
+{
+ HTMLRect *This = HTMLRECT_THIS(iface);
+ FIXME("(%p)->(%p)\n", This, p);
+ return E_NOTIMPL;
+}
+
+#undef HTMLRECT_THIS
+
+static const IHTMLRectVtbl HTMLRectVtbl = {
+ HTMLRect_QueryInterface,
+ HTMLRect_AddRef,
+ HTMLRect_Release,
+ HTMLRect_GetTypeInfoCount,
+ HTMLRect_GetTypeInfo,
+ HTMLRect_GetIDsOfNames,
+ HTMLRect_Invoke,
+ HTMLRect_put_left,
+ HTMLRect_get_left,
+ HTMLRect_put_top,
+ HTMLRect_get_top,
+ HTMLRect_put_right,
+ HTMLRect_get_right,
+ HTMLRect_put_bottom,
+ HTMLRect_get_bottom
+};
+
+static const tid_t HTMLRect_iface_tids[] = {
+ IHTMLRect_tid,
+ 0
+};
+static dispex_static_data_t HTMLRect_dispex = {
+ NULL,
+ IHTMLRect_tid,
+ NULL,
+ HTMLRect_iface_tids
+};
+
+static HRESULT create_html_rect(IHTMLRect **ret)
+{
+ HTMLRect *rect;
+
+ rect = heap_alloc_zero(sizeof(HTMLRect));
+ if(!rect)
+ return E_OUTOFMEMORY;
+
+ rect->lpIHTMLRectVtbl = &HTMLRectVtbl;
+ rect->ref = 1;
+
+ init_dispex(&rect->dispex, (IUnknown*)HTMLRECT(rect), &HTMLRect_dispex);
+
+ *ret = HTMLRECT(rect);
+ return S_OK;
+}
+
#define HTMLELEM2_THIS(iface) DEFINE_THIS(HTMLElement, HTMLElement2, iface)
static HRESULT WINAPI HTMLElement2_QueryInterface(IHTMLElement2 *iface,
@@ -364,8 +556,10 @@ static HRESULT WINAPI HTMLElement2_getClientRects(IHTMLElement2 *iface, IHTMLRec
static HRESULT WINAPI HTMLElement2_getBoundingClientRect(IHTMLElement2 *iface, IHTMLRect **pRect)
{
HTMLElement *This = HTMLELEM2_THIS(iface);
- FIXME("(%p)->(%p)\n", This, pRect);
- return E_NOTIMPL;
+
+ TRACE("(%p)->(%p)\n", This, pRect);
+
+ return create_html_rect(pRect);
}
static HRESULT WINAPI HTMLElement2_setExpression(IHTMLElement2 *iface, BSTR propname,
diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h
index 4deb4d6357d..46886d8b3b1 100644
--- a/dlls/mshtml/mshtml_private.h
+++ b/dlls/mshtml/mshtml_private.h
@@ -120,6 +120,7 @@ typedef enum {
IHTMLInputElement_tid,
IHTMLLocation_tid,
IHTMLOptionElement_tid,
+ IHTMLRect_tid,
IHTMLScreen_tid,
IHTMLScriptElement_tid,
IHTMLSelectElement_tid,
diff --git a/dlls/mshtml/tests/dom.c b/dlls/mshtml/tests/dom.c
index 4f954a8ba30..c877b96e3b7 100644
--- a/dlls/mshtml/tests/dom.c
+++ b/dlls/mshtml/tests/dom.c
@@ -2852,6 +2852,23 @@ static void _test_style_set_csstext(unsigned line, IHTMLStyle *style, const char
SysFreeString(tmp);
}
+static void test_elem_bounding_client_rect(IUnknown *unk)
+{
+ IHTMLElement2 *elem2;
+ IHTMLRect *rect;
+ HRESULT hres;
+
+ elem2 = get_elem2_iface(unk);
+ hres = IHTMLElement2_getBoundingClientRect(elem2, &rect);
+ IHTMLElement2_Release(elem2);
+ ok(hres == S_OK, "getBoundingClientRect failed: %08x\n", hres);
+ ok(rect != NULL, "rect == NULL\n");
+
+ test_disp((IUnknown*)rect, &IID_IHTMLRect, "[object]");
+
+ IHTMLRect_Release(rect);
+}
+
static void test_elem_col_item(IHTMLElementCollection *col, const char *n,
const elem_type_t *elem_types, LONG len)
{
@@ -5862,6 +5879,7 @@ static void test_elems(IHTMLDocument2 *doc)
test_elem_set_title((IUnknown*)select, "Title");
test_elem_title((IUnknown*)select, "Title");
test_elem_offset((IUnknown*)select);
+ test_elem_bounding_client_rect((IUnknown*)select);
node = get_first_child((IUnknown*)select);
ok(node != NULL, "node == NULL\n");