diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h
index 6ef13973747..edaf22baab7 100644
--- a/dlls/mshtml/mshtml_private.h
+++ b/dlls/mshtml/mshtml_private.h
@@ -201,6 +201,7 @@ typedef struct EventTarget EventTarget;
XIID(IHTMLOptionElementFactory) \
XIID(IHTMLPerformance) \
XIID(IHTMLPerformanceNavigation) \
+ XIID(IHTMLPerformanceTiming) \
XIID(IHTMLPluginsCollection) \
XIID(IHTMLRect) \
XIID(IHTMLScreen) \
diff --git a/dlls/mshtml/omnavigator.c b/dlls/mshtml/omnavigator.c
index a6a3e1124ed..a6c66d18a20 100644
--- a/dlls/mshtml/omnavigator.c
+++ b/dlls/mshtml/omnavigator.c
@@ -1321,6 +1321,369 @@ IOmNavigator *OmNavigator_Create(void)
return &ret->IOmNavigator_iface;
}
+typedef struct {
+ DispatchEx dispex;
+ IHTMLPerformanceTiming IHTMLPerformanceTiming_iface;
+
+ LONG ref;
+} HTMLPerformanceTiming;
+
+static inline HTMLPerformanceTiming *impl_from_IHTMLPerformanceTiming(IHTMLPerformanceTiming *iface)
+{
+ return CONTAINING_RECORD(iface, HTMLPerformanceTiming, IHTMLPerformanceTiming_iface);
+}
+
+static HRESULT WINAPI HTMLPerformanceTiming_QueryInterface(IHTMLPerformanceTiming *iface, REFIID riid, void **ppv)
+{
+ HTMLPerformanceTiming *This = impl_from_IHTMLPerformanceTiming(iface);
+
+ TRACE("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv);
+
+ if(IsEqualGUID(&IID_IUnknown, riid)) {
+ *ppv = &This->IHTMLPerformanceTiming_iface;
+ }else if(IsEqualGUID(&IID_IHTMLPerformanceTiming, riid)) {
+ *ppv = &This->IHTMLPerformanceTiming_iface;
+ }else if(dispex_query_interface(&This->dispex, riid, ppv)) {
+ return *ppv ? S_OK : E_NOINTERFACE;
+ }else {
+ WARN("Unsupported interface %s\n", debugstr_mshtml_guid(riid));
+ *ppv = NULL;
+ return E_NOINTERFACE;
+ }
+
+ IUnknown_AddRef((IUnknown*)*ppv);
+ return S_OK;
+}
+
+static ULONG WINAPI HTMLPerformanceTiming_AddRef(IHTMLPerformanceTiming *iface)
+{
+ HTMLPerformanceTiming *This = impl_from_IHTMLPerformanceTiming(iface);
+ LONG ref = InterlockedIncrement(&This->ref);
+
+ TRACE("(%p) ref=%d\n", This, ref);
+
+ return ref;
+}
+
+static ULONG WINAPI HTMLPerformanceTiming_Release(IHTMLPerformanceTiming *iface)
+{
+ HTMLPerformanceTiming *This = impl_from_IHTMLPerformanceTiming(iface);
+ LONG ref = InterlockedDecrement(&This->ref);
+
+ TRACE("(%p) ref=%d\n", This, ref);
+
+ if(!ref) {
+ release_dispex(&This->dispex);
+ heap_free(This);
+ }
+
+ return ref;
+}
+
+static HRESULT WINAPI HTMLPerformanceTiming_GetTypeInfoCount(IHTMLPerformanceTiming *iface, UINT *pctinfo)
+{
+ HTMLPerformanceTiming *This = impl_from_IHTMLPerformanceTiming(iface);
+ FIXME("(%p)->(%p)\n", This, pctinfo);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI HTMLPerformanceTiming_GetTypeInfo(IHTMLPerformanceTiming *iface, UINT iTInfo,
+ LCID lcid, ITypeInfo **ppTInfo)
+{
+ HTMLPerformanceTiming *This = impl_from_IHTMLPerformanceTiming(iface);
+
+ return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
+}
+
+static HRESULT WINAPI HTMLPerformanceTiming_GetIDsOfNames(IHTMLPerformanceTiming *iface, REFIID riid,
+ LPOLESTR *rgszNames, UINT cNames,
+ LCID lcid, DISPID *rgDispId)
+{
+ HTMLPerformanceTiming *This = impl_from_IHTMLPerformanceTiming(iface);
+
+ return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface, riid, rgszNames, cNames,
+ lcid, rgDispId);
+}
+
+static HRESULT WINAPI HTMLPerformanceTiming_Invoke(IHTMLPerformanceTiming *iface, DISPID dispIdMember,
+ REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
+ VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
+{
+ HTMLPerformanceTiming *This = impl_from_IHTMLPerformanceTiming(iface);
+
+ return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface, dispIdMember, riid, lcid, wFlags,
+ pDispParams, pVarResult, pExcepInfo, puArgErr);
+}
+
+#define TIMING_FAKE_TIMESTAMP 0xdeadbeef
+
+static HRESULT WINAPI HTMLPerformanceTiming_get_navigationStart(IHTMLPerformanceTiming *iface, ULONGLONG *p)
+{
+ HTMLPerformanceTiming *This = impl_from_IHTMLPerformanceTiming(iface);
+
+ FIXME("(%p)->(%p) returning fake value\n", This, p);
+
+ *p = TIMING_FAKE_TIMESTAMP;
+ return S_OK;
+}
+
+static HRESULT WINAPI HTMLPerformanceTiming_get_unloadEventStart(IHTMLPerformanceTiming *iface, ULONGLONG *p)
+{
+ HTMLPerformanceTiming *This = impl_from_IHTMLPerformanceTiming(iface);
+
+ FIXME("(%p)->(%p) returning fake value\n", This, p);
+
+ *p = TIMING_FAKE_TIMESTAMP;
+ return S_OK;
+}
+
+static HRESULT WINAPI HTMLPerformanceTiming_get_unloadEventEnd(IHTMLPerformanceTiming *iface, ULONGLONG *p)
+{
+ HTMLPerformanceTiming *This = impl_from_IHTMLPerformanceTiming(iface);
+
+ FIXME("(%p)->(%p) returning fake value\n", This, p);
+
+ *p = TIMING_FAKE_TIMESTAMP;
+ return S_OK;
+}
+
+static HRESULT WINAPI HTMLPerformanceTiming_get_redirectStart(IHTMLPerformanceTiming *iface, ULONGLONG *p)
+{
+ HTMLPerformanceTiming *This = impl_from_IHTMLPerformanceTiming(iface);
+
+ FIXME("(%p)->(%p) returning fake value\n", This, p);
+
+ *p = TIMING_FAKE_TIMESTAMP;
+ return S_OK;
+}
+
+static HRESULT WINAPI HTMLPerformanceTiming_get_redirectEnd(IHTMLPerformanceTiming *iface, ULONGLONG *p)
+{
+ HTMLPerformanceTiming *This = impl_from_IHTMLPerformanceTiming(iface);
+
+ FIXME("(%p)->(%p) returning fake value\n", This, p);
+
+ *p = TIMING_FAKE_TIMESTAMP;
+ return S_OK;
+}
+
+static HRESULT WINAPI HTMLPerformanceTiming_get_fetchStart(IHTMLPerformanceTiming *iface, ULONGLONG *p)
+{
+ HTMLPerformanceTiming *This = impl_from_IHTMLPerformanceTiming(iface);
+
+ FIXME("(%p)->(%p) returning fake value\n", This, p);
+
+ *p = TIMING_FAKE_TIMESTAMP;
+ return S_OK;
+}
+
+static HRESULT WINAPI HTMLPerformanceTiming_get_domainLookupStart(IHTMLPerformanceTiming *iface, ULONGLONG *p)
+{
+ HTMLPerformanceTiming *This = impl_from_IHTMLPerformanceTiming(iface);
+
+ FIXME("(%p)->(%p) returning fake value\n", This, p);
+
+ *p = TIMING_FAKE_TIMESTAMP;
+ return S_OK;
+}
+
+static HRESULT WINAPI HTMLPerformanceTiming_get_domainLookupEnd(IHTMLPerformanceTiming *iface, ULONGLONG *p)
+{
+ HTMLPerformanceTiming *This = impl_from_IHTMLPerformanceTiming(iface);
+
+ FIXME("(%p)->(%p) returning fake value\n", This, p);
+
+ *p = TIMING_FAKE_TIMESTAMP;
+ return S_OK;
+}
+
+static HRESULT WINAPI HTMLPerformanceTiming_get_connectStart(IHTMLPerformanceTiming *iface, ULONGLONG *p)
+{
+ HTMLPerformanceTiming *This = impl_from_IHTMLPerformanceTiming(iface);
+
+ FIXME("(%p)->(%p) returning fake value\n", This, p);
+
+ *p = TIMING_FAKE_TIMESTAMP;
+ return S_OK;
+}
+
+static HRESULT WINAPI HTMLPerformanceTiming_get_connectEnd(IHTMLPerformanceTiming *iface, ULONGLONG *p)
+{
+ HTMLPerformanceTiming *This = impl_from_IHTMLPerformanceTiming(iface);
+
+ FIXME("(%p)->(%p) returning fake value\n", This, p);
+
+ *p = TIMING_FAKE_TIMESTAMP;
+ return S_OK;
+}
+
+static HRESULT WINAPI HTMLPerformanceTiming_get_requestStart(IHTMLPerformanceTiming *iface, ULONGLONG *p)
+{
+ HTMLPerformanceTiming *This = impl_from_IHTMLPerformanceTiming(iface);
+
+ FIXME("(%p)->(%p) returning fake value\n", This, p);
+
+ *p = TIMING_FAKE_TIMESTAMP;
+ return S_OK;
+}
+
+static HRESULT WINAPI HTMLPerformanceTiming_get_responseStart(IHTMLPerformanceTiming *iface, ULONGLONG *p)
+{
+ HTMLPerformanceTiming *This = impl_from_IHTMLPerformanceTiming(iface);
+
+ FIXME("(%p)->(%p) returning fake value\n", This, p);
+
+ *p = TIMING_FAKE_TIMESTAMP;
+ return S_OK;
+}
+
+static HRESULT WINAPI HTMLPerformanceTiming_get_responseEnd(IHTMLPerformanceTiming *iface, ULONGLONG *p)
+{
+ HTMLPerformanceTiming *This = impl_from_IHTMLPerformanceTiming(iface);
+
+ FIXME("(%p)->(%p) returning fake value\n", This, p);
+
+ *p = TIMING_FAKE_TIMESTAMP;
+ return S_OK;
+}
+
+static HRESULT WINAPI HTMLPerformanceTiming_get_domLoading(IHTMLPerformanceTiming *iface, ULONGLONG *p)
+{
+ HTMLPerformanceTiming *This = impl_from_IHTMLPerformanceTiming(iface);
+
+ FIXME("(%p)->(%p) returning fake value\n", This, p);
+
+ *p = TIMING_FAKE_TIMESTAMP;
+ return S_OK;
+}
+
+static HRESULT WINAPI HTMLPerformanceTiming_get_domInteractive(IHTMLPerformanceTiming *iface, ULONGLONG *p)
+{
+ HTMLPerformanceTiming *This = impl_from_IHTMLPerformanceTiming(iface);
+
+ FIXME("(%p)->(%p) returning fake value\n", This, p);
+
+ *p = TIMING_FAKE_TIMESTAMP;
+ return S_OK;
+}
+
+static HRESULT WINAPI HTMLPerformanceTiming_get_domContentLoadedEventStart(IHTMLPerformanceTiming *iface, ULONGLONG *p)
+{
+ HTMLPerformanceTiming *This = impl_from_IHTMLPerformanceTiming(iface);
+
+ FIXME("(%p)->(%p) returning fake value\n", This, p);
+
+ *p = TIMING_FAKE_TIMESTAMP;
+ return S_OK;
+}
+
+static HRESULT WINAPI HTMLPerformanceTiming_get_domContentLoadedEventEnd(IHTMLPerformanceTiming *iface, ULONGLONG *p)
+{
+ HTMLPerformanceTiming *This = impl_from_IHTMLPerformanceTiming(iface);
+
+ FIXME("(%p)->(%p) returning fake value\n", This, p);
+
+ *p = TIMING_FAKE_TIMESTAMP;
+ return S_OK;
+}
+
+static HRESULT WINAPI HTMLPerformanceTiming_get_domComplete(IHTMLPerformanceTiming *iface, ULONGLONG *p)
+{
+ HTMLPerformanceTiming *This = impl_from_IHTMLPerformanceTiming(iface);
+
+ FIXME("(%p)->(%p) returning fake value\n", This, p);
+
+ *p = TIMING_FAKE_TIMESTAMP;
+ return S_OK;
+}
+
+static HRESULT WINAPI HTMLPerformanceTiming_get_loadEventStart(IHTMLPerformanceTiming *iface, ULONGLONG *p)
+{
+ HTMLPerformanceTiming *This = impl_from_IHTMLPerformanceTiming(iface);
+
+ FIXME("(%p)->(%p) returning fake value\n", This, p);
+
+ *p = TIMING_FAKE_TIMESTAMP;
+ return S_OK;
+}
+
+static HRESULT WINAPI HTMLPerformanceTiming_get_loadEventEnd(IHTMLPerformanceTiming *iface, ULONGLONG *p)
+{
+ HTMLPerformanceTiming *This = impl_from_IHTMLPerformanceTiming(iface);
+
+ FIXME("(%p)->(%p) returning fake value\n", This, p);
+
+ *p = TIMING_FAKE_TIMESTAMP;
+ return S_OK;
+}
+
+static HRESULT WINAPI HTMLPerformanceTiming_get_msFirstPaint(IHTMLPerformanceTiming *iface, ULONGLONG *p)
+{
+ HTMLPerformanceTiming *This = impl_from_IHTMLPerformanceTiming(iface);
+
+ FIXME("(%p)->(%p) returning fake value\n", This, p);
+
+ *p = TIMING_FAKE_TIMESTAMP;
+ return S_OK;
+}
+
+static HRESULT WINAPI HTMLPerformanceTiming_toString(IHTMLPerformanceTiming *iface, BSTR *string)
+{
+ HTMLPerformanceTiming *This = impl_from_IHTMLPerformanceTiming(iface);
+ FIXME("(%p)->(%p)\n", This, string);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI HTMLPerformanceTiming_toJSON(IHTMLPerformanceTiming *iface, VARIANT *p)
+{
+ HTMLPerformanceTiming *This = impl_from_IHTMLPerformanceTiming(iface);
+ FIXME("(%p)->(%p)\n", This, p);
+ return E_NOTIMPL;
+}
+
+static const IHTMLPerformanceTimingVtbl HTMLPerformanceTimingVtbl = {
+ HTMLPerformanceTiming_QueryInterface,
+ HTMLPerformanceTiming_AddRef,
+ HTMLPerformanceTiming_Release,
+ HTMLPerformanceTiming_GetTypeInfoCount,
+ HTMLPerformanceTiming_GetTypeInfo,
+ HTMLPerformanceTiming_GetIDsOfNames,
+ HTMLPerformanceTiming_Invoke,
+ HTMLPerformanceTiming_get_navigationStart,
+ HTMLPerformanceTiming_get_unloadEventStart,
+ HTMLPerformanceTiming_get_unloadEventEnd,
+ HTMLPerformanceTiming_get_redirectStart,
+ HTMLPerformanceTiming_get_redirectEnd,
+ HTMLPerformanceTiming_get_fetchStart,
+ HTMLPerformanceTiming_get_domainLookupStart,
+ HTMLPerformanceTiming_get_domainLookupEnd,
+ HTMLPerformanceTiming_get_connectStart,
+ HTMLPerformanceTiming_get_connectEnd,
+ HTMLPerformanceTiming_get_requestStart,
+ HTMLPerformanceTiming_get_responseStart,
+ HTMLPerformanceTiming_get_responseEnd,
+ HTMLPerformanceTiming_get_domLoading,
+ HTMLPerformanceTiming_get_domInteractive,
+ HTMLPerformanceTiming_get_domContentLoadedEventStart,
+ HTMLPerformanceTiming_get_domContentLoadedEventEnd,
+ HTMLPerformanceTiming_get_domComplete,
+ HTMLPerformanceTiming_get_loadEventStart,
+ HTMLPerformanceTiming_get_loadEventEnd,
+ HTMLPerformanceTiming_get_msFirstPaint,
+ HTMLPerformanceTiming_toString,
+ HTMLPerformanceTiming_toJSON
+};
+
+static const tid_t HTMLPerformanceTiming_iface_tids[] = {
+ IHTMLPerformanceTiming_tid,
+ 0
+};
+static dispex_static_data_t HTMLPerformanceTiming_dispex = {
+ NULL,
+ IHTMLPerformanceTiming_tid,
+ HTMLPerformanceTiming_iface_tids
+};
+
typedef struct {
DispatchEx dispex;
IHTMLPerformanceNavigation IHTMLPerformanceNavigation_iface;
@@ -1477,6 +1840,7 @@ typedef struct {
LONG ref;
IHTMLPerformanceNavigation *navigation;
+ IHTMLPerformanceTiming *timing;
} HTMLPerformance;
static inline HTMLPerformance *impl_from_IHTMLPerformance(IHTMLPerformance *iface)
@@ -1524,6 +1888,8 @@ static ULONG WINAPI HTMLPerformance_Release(IHTMLPerformance *iface)
TRACE("(%p) ref=%d\n", This, ref);
if(!ref) {
+ if(This->timing)
+ IHTMLPerformanceTiming_Release(This->timing);
if(This->navigation)
IHTMLPerformanceNavigation_Release(This->navigation);
release_dispex(&This->dispex);
@@ -1597,8 +1963,26 @@ static HRESULT WINAPI HTMLPerformance_get_navigation(IHTMLPerformance *iface,
static HRESULT WINAPI HTMLPerformance_get_timing(IHTMLPerformance *iface, IHTMLPerformanceTiming **p)
{
HTMLPerformance *This = impl_from_IHTMLPerformance(iface);
- FIXME("(%p)->(%p)\n", This, p);
- return E_NOTIMPL;
+
+ TRACE("(%p)->(%p)\n", This, p);
+
+ if(!This->timing) {
+ HTMLPerformanceTiming *timing;
+
+ timing = heap_alloc_zero(sizeof(*timing));
+ if(!timing)
+ return E_OUTOFMEMORY;
+
+ timing->IHTMLPerformanceTiming_iface.lpVtbl = &HTMLPerformanceTimingVtbl;
+ timing->ref = 1;
+ init_dispex(&timing->dispex, (IUnknown*)&timing->IHTMLPerformanceTiming_iface,
+ &HTMLPerformanceTiming_dispex);
+
+ This->timing = &timing->IHTMLPerformanceTiming_iface;
+ }
+
+ IHTMLPerformanceTiming_AddRef(*p = This->timing);
+ return S_OK;
}
static HRESULT WINAPI HTMLPerformance_toString(IHTMLPerformance *iface, BSTR *string)