Wine-devel
Threads by month
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2002 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2001 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
June 2021
- 82 participants
- 607 discussions
[PATCH resend 1/4] iphlpapi: Implement asynchronous events for IcmpSendEcho2(Ex).
by Gabriel Ivăncescu 15 Jun '21
by Gabriel Ivăncescu 15 Jun '21
15 Jun '21
Signed-off-by: Gabriel Ivăncescu <gabrielopcode(a)gmail.com>
---
dlls/iphlpapi/icmp.c | 108 +++++++++++++++++++++++++++++++++++++++----
1 file changed, 100 insertions(+), 8 deletions(-)
diff --git a/dlls/iphlpapi/icmp.c b/dlls/iphlpapi/icmp.c
index 8ef0321..ceeab69 100644
--- a/dlls/iphlpapi/icmp.c
+++ b/dlls/iphlpapi/icmp.c
@@ -106,9 +106,42 @@ WINE_DECLARE_DEBUG_CHANNEL(winediag);
typedef struct {
int sid;
+ LONG lock_count;
+ HANDLE lock_event;
IP_OPTION_INFORMATION default_opts;
} icmp_t;
+static void icmp_lock(icmp_t *icp)
+{
+ InterlockedIncrement(&icp->lock_count);
+}
+
+static void icmp_unlock(icmp_t *icp)
+{
+ if (InterlockedDecrement(&icp->lock_count) == 0x80000000)
+ {
+ if (icp->lock_event)
+ SetEvent(icp->lock_event);
+ }
+}
+
+static void icmp_wait_for_released_locks(icmp_t *icp)
+{
+ HANDLE event = CreateEventW(NULL, TRUE, FALSE, NULL);
+
+ icp->lock_event = event;
+ if (InterlockedExchangeAdd(&icp->lock_count, 0x80000000) != 0)
+ {
+ do
+ {
+ if (event) WaitForSingleObjectEx(event, INFINITE, TRUE);
+ else SleepEx(1, TRUE);
+ }
+ while (icp->lock_count != 0x80000000);
+ }
+ if (event) CloseHandle(event);
+}
+
#define IP_OPTS_UNKNOWN 0
#define IP_OPTS_DEFAULT 1
#define IP_OPTS_CUSTOM 2
@@ -347,6 +380,30 @@ done:
return res;
}
+struct icmp_get_reply_async_ctx
+{
+ icmp_t *icp;
+ HANDLE event;
+ unsigned char *buffer;
+ void *reply_buf;
+ DWORD reply_size;
+ DWORD send_time;
+ DWORD timeout;
+};
+
+static DWORD WINAPI icmp_get_reply_async_func(VOID *parameter)
+{
+ struct icmp_get_reply_async_ctx *ctx = parameter;
+
+ icmp_get_reply(ctx->icp->sid, ctx->buffer, ctx->send_time, ctx->reply_buf, ctx->reply_size, ctx->timeout);
+
+ SetEvent(ctx->event);
+
+ icmp_unlock(ctx->icp);
+ HeapFree(GetProcessHeap(), 0, ctx);
+ return 0;
+}
+
/*
@@ -381,6 +438,7 @@ HANDLE WINAPI Icmp6CreateFile(VOID)
}
icp->sid=sid;
icp->default_opts.OptionsSize=IP_OPTS_UNKNOWN;
+ icp->lock_count=0;
return (HANDLE)icp;
}
@@ -439,6 +497,7 @@ HANDLE WINAPI IcmpCreateFile(VOID)
}
icp->sid=sid;
icp->default_opts.OptionsSize=IP_OPTS_UNKNOWN;
+ icp->lock_count=0;
return (HANDLE)icp;
}
@@ -455,6 +514,9 @@ BOOL WINAPI IcmpCloseHandle(HANDLE IcmpHandle)
return FALSE;
}
+ /* Windows waits until all outstanding async requests are complete or timed out */
+ icmp_wait_for_released_locks(icp);
+
close( icp->sid );
HeapFree(GetProcessHeap (), 0, icp);
return TRUE;
@@ -526,6 +588,7 @@ DWORD WINAPI IcmpSendEcho2Ex(
unsigned char *buffer;
int reqsize, repsize;
DWORD send_time;
+ DWORD res = 0;
TRACE("(%p, %p, %p, %p, %08x, %08x, %p, %d, %p, %p, %d, %d)\n", IcmpHandle,
Event, ApcRoutine, ApcContext, SourceAddress, DestinationAddress, RequestData,
@@ -553,11 +616,6 @@ DWORD WINAPI IcmpSendEcho2Ex(
return 0;
}
- if (Event)
- {
- FIXME("unsupported for events\n");
- return 0;
- }
if (ApcRoutine)
{
FIXME("unsupported for APCs\n");
@@ -569,6 +627,8 @@ DWORD WINAPI IcmpSendEcho2Ex(
return 0;
}
+ icmp_lock(icp);
+
/* Prepare the request */
id=getpid() & 0xFFFF;
seq=InterlockedIncrement(&icmp_sequence) & 0xFFFF;
@@ -580,7 +640,7 @@ DWORD WINAPI IcmpSendEcho2Ex(
buffer = HeapAlloc(GetProcessHeap(), 0, max( repsize, reqsize ));
if (buffer == NULL) {
SetLastError(ERROR_OUTOFMEMORY);
- return 0;
+ goto done;
}
icmp_header=(struct icmp*)buffer;
@@ -661,10 +721,42 @@ DWORD WINAPI IcmpSendEcho2Ex(
}
}
HeapFree(GetProcessHeap(), 0, buffer);
- return 0;
+ goto done;
}
- return icmp_get_reply(icp->sid, buffer, send_time, ReplyBuffer, ReplySize, Timeout);
+ if (Event)
+ {
+ struct icmp_get_reply_async_ctx *ctx = HeapAlloc(GetProcessHeap(), 0, sizeof(*ctx));
+
+ if (ctx)
+ {
+ ctx->icp = icp;
+ ctx->event = Event;
+ ctx->buffer = buffer;
+ ctx->reply_buf = ReplyBuffer;
+ ctx->reply_size = ReplySize;
+ ctx->send_time = send_time;
+ ctx->timeout = Timeout;
+ if (QueueUserWorkItem(icmp_get_reply_async_func, ctx, WT_EXECUTEDEFAULT | WT_EXECUTELONGFUNCTION))
+ {
+ SetLastError(ERROR_IO_PENDING);
+ return 0;
+ }
+
+ HeapFree(GetProcessHeap(), 0, ctx);
+ }
+ else
+ SetLastError(ERROR_OUTOFMEMORY);
+
+ HeapFree(GetProcessHeap(), 0, buffer);
+ goto done;
+ }
+
+ res = icmp_get_reply(icp->sid, buffer, send_time, ReplyBuffer, ReplySize, Timeout);
+
+done:
+ icmp_unlock(icp);
+ return res;
}
/*
--
2.31.1
1
3
Signed-off-by: Jacek Caban <jacek(a)codeweavers.com>
---
dlls/win32u/Makefile.in | 1 +
dlls/win32u/win32u.spec | 1317 +++++++++++++++++++++++++++++++++++++++
2 files changed, 1318 insertions(+)
create mode 100644 dlls/win32u/Makefile.in
create mode 100644 dlls/win32u/win32u.spec
1
0
15 Jun '21
Signed-off-by: Paul Gofman <pgofman(a)codeweavers.com>
---
dlls/jscript/compile.c | 5 +++++
dlls/jscript/lex.c | 2 ++
dlls/jscript/parser.h | 1 +
dlls/jscript/parser.y | 29 ++++++++++++++++++++++++-----
dlls/jscript/tests/lang.js | 25 +++++++++++++++++++++++++
dlls/mshtml/tests/es5.js | 17 +++++++++++++++++
6 files changed, 74 insertions(+), 5 deletions(-)
diff --git a/dlls/jscript/compile.c b/dlls/jscript/compile.c
index 9bb9ff13d14..2a17639641f 100644
--- a/dlls/jscript/compile.c
+++ b/dlls/jscript/compile.c
@@ -1138,6 +1138,11 @@ static HRESULT compile_variable_list(compiler_ctx_t *ctx, variable_declaration_t
if(!iter->expr)
continue;
+ if (iter->block_scope)
+ FIXME("Block scope variables are not supported.\n");
+ if (iter->constant)
+ FIXME("Constant variables are not supported.\n");
+
hres = emit_identifier_ref(ctx, iter->identifier, 0);
if(FAILED(hres))
return hres;
diff --git a/dlls/jscript/lex.c b/dlls/jscript/lex.c
index efed1038a95..3dd609885e6 100644
--- a/dlls/jscript/lex.c
+++ b/dlls/jscript/lex.c
@@ -41,6 +41,7 @@ static const struct {
{L"break", kBREAK, TRUE},
{L"case", kCASE},
{L"catch", kCATCH},
+ {L"const", kCONST, FALSE},
{L"continue", kCONTINUE, TRUE},
{L"default", kDEFAULT},
{L"delete", kDELETE},
@@ -54,6 +55,7 @@ static const struct {
{L"if", kIF},
{L"in", kIN},
{L"instanceof", kINSTANCEOF},
+ {L"let", kLET, FALSE, SCRIPTLANGUAGEVERSION_ES5},
{L"new", kNEW},
{L"null", kNULL},
{L"return", kRETURN, TRUE},
diff --git a/dlls/jscript/parser.h b/dlls/jscript/parser.h
index b88a52af242..c4dd0752ee9 100644
--- a/dlls/jscript/parser.h
+++ b/dlls/jscript/parser.h
@@ -95,6 +95,7 @@ literal_t *new_boolean_literal(parser_ctx_t*,BOOL) DECLSPEC_HIDDEN;
typedef struct _variable_declaration_t {
const WCHAR *identifier;
+ BOOL block_scope, constant;
expression_t *expr;
struct _variable_declaration_t *next;
diff --git a/dlls/jscript/parser.y b/dlls/jscript/parser.y
index f11119143b8..7d0630582e0 100644
--- a/dlls/jscript/parser.y
+++ b/dlls/jscript/parser.y
@@ -87,7 +87,7 @@ static variable_list_t *variable_list_add(parser_ctx_t*,variable_list_t*,variabl
static void *new_statement(parser_ctx_t*,statement_type_t,size_t,unsigned);
static statement_t *new_block_statement(parser_ctx_t*,unsigned,statement_list_t*);
-static statement_t *new_var_statement(parser_ctx_t*,unsigned,variable_list_t*);
+static statement_t *new_var_statement(parser_ctx_t*,BOOL,BOOL,unsigned,variable_list_t*);
static statement_t *new_expression_statement(parser_ctx_t*,unsigned,expression_t*);
static statement_t *new_if_statement(parser_ctx_t*,unsigned,expression_t*,statement_t*,statement_t*);
static statement_t *new_while_statement(parser_ctx_t*,unsigned,BOOL,expression_t*,statement_t*);
@@ -168,8 +168,9 @@ static source_elements_t *source_elements_add_statement(source_elements_t*,state
}
/* keywords */
-%token <identifier> kBREAK kCASE kCATCH kCONTINUE kDEFAULT kDELETE kDO kELSE kFUNCTION kIF kFINALLY kFOR kGET kIN kSET
-%token <identifier> kINSTANCEOF kNEW kNULL kRETURN kSWITCH kTHIS kTHROW kTRUE kFALSE kTRY kTYPEOF kVAR kVOID kWHILE kWITH
+%token <identifier> kBREAK kCASE kCATCH kCONST kCONTINUE kDEFAULT kDELETE kDO kELSE kFUNCTION kIF kFINALLY kFOR
+%token <identifier> kGET kIN kLET kSET kINSTANCEOF kNEW kNULL kRETURN kSWITCH kTHIS kTHROW kTRUE kFALSE
+%token <identifier> kTRY kTYPEOF kVAR kVOID kWHILE kWITH
%token tANDAND tOROR tINC tDEC tHTMLCOMMENT kDIVEQ kDCOL
/* tokens */
@@ -182,6 +183,7 @@ static source_elements_t *source_elements_add_statement(source_elements_t*,state
%type <source_elements> FunctionBody
%type <statement> Statement
%type <statement> Block
+%type <statement> LexicalDeclaration
%type <statement> VariableStatement
%type <statement> EmptyStatement
%type <statement> ExpressionStatement
@@ -291,6 +293,7 @@ FormalParameterList_opt
/* ECMA-262 3rd Edition 12 */
Statement
: Block { $$ = $1; }
+ | LexicalDeclaration { $$ = $1; }
| VariableStatement { $$ = $1; }
| EmptyStatement { $$ = $1; }
| FunctionExpression { $$ = new_expression_statement(ctx, @$, $1); }
@@ -322,10 +325,17 @@ Block
: '{' StatementList '}' { $$ = new_block_statement(ctx, @2, $2); }
| '{' '}' { $$ = new_block_statement(ctx, @$, NULL); }
+/* ECMA-262 10th Edition 13.3.1, TODO: BindingList*/
+LexicalDeclaration
+ : kLET VariableDeclarationList semicolon_opt
+ { $$ = new_var_statement(ctx, TRUE, FALSE, @$, $2); }
+ | kCONST VariableDeclarationList semicolon_opt
+ { $$ = new_var_statement(ctx, TRUE, TRUE, @$, $2); }
+
/* ECMA-262 3rd Edition 12.2 */
VariableStatement
: kVAR VariableDeclarationList semicolon_opt
- { $$ = new_var_statement(ctx, @$, $2); }
+ { $$ = new_var_statement(ctx, FALSE, FALSE, @$, $2); }
/* ECMA-262 3rd Edition 12.2 */
VariableDeclarationList
@@ -834,6 +844,7 @@ ReservedAsIdentifier
: kBREAK { $$ = $1; }
| kCASE { $$ = $1; }
| kCATCH { $$ = $1; }
+ | kCONST { $$ = $1; }
| kCONTINUE { $$ = $1; }
| kDEFAULT { $$ = $1; }
| kDELETE { $$ = $1; }
@@ -847,6 +858,7 @@ ReservedAsIdentifier
| kIF { $$ = $1; }
| kIN { $$ = $1; }
| kINSTANCEOF { $$ = $1; }
+ | kLET { $$ = $1; }
| kNEW { $$ = $1; }
| kNULL { $$ = $1; }
| kRETURN { $$ = $1; }
@@ -1144,8 +1156,10 @@ static variable_list_t *variable_list_add(parser_ctx_t *ctx, variable_list_t *li
return list;
}
-static statement_t *new_var_statement(parser_ctx_t *ctx, unsigned loc, variable_list_t *variable_list)
+static statement_t *new_var_statement(parser_ctx_t *ctx, BOOL block_scope, BOOL constant, unsigned loc,
+ variable_list_t *variable_list)
{
+ variable_declaration_t *var;
var_statement_t *ret;
ret = new_statement(ctx, STAT_VAR, sizeof(*ret), loc);
@@ -1153,6 +1167,11 @@ static statement_t *new_var_statement(parser_ctx_t *ctx, unsigned loc, variable_
return NULL;
ret->variable_list = variable_list->head;
+ for (var = ret->variable_list; var; var = var->next)
+ {
+ var->block_scope = block_scope;
+ var->constant = constant;
+ }
return &ret->stat;
}
diff --git a/dlls/jscript/tests/lang.js b/dlls/jscript/tests/lang.js
index 9e6e6ad239f..2028d233ccf 100644
--- a/dlls/jscript/tests/lang.js
+++ b/dlls/jscript/tests/lang.js
@@ -2030,3 +2030,28 @@ Math = 6;
ok(Math === 6, "NaN !== 6");
reportSuccess();
+
+function test_es5_keywords() {
+ var let = 1
+ var tmp
+ ok(let == 1, "let != 1");
+
+ tmp = false
+ try {
+ eval('var var = 1;');
+ }
+ catch(e) {
+ tmp = true
+ }
+ ok(tmp === true, "Expected exception for 'var var = 1;'");
+
+ tmp = false
+ try {
+ eval('var const = 1;');
+ }
+ catch(e) {
+ tmp = true
+ }
+ ok(tmp === true, "Expected exception for 'var const = 1;'");
+}
+test_es5_keywords();
diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js
index 7e46848d40e..24906de5231 100644
--- a/dlls/mshtml/tests/es5.js
+++ b/dlls/mshtml/tests/es5.js
@@ -1207,3 +1207,20 @@ sync_test("head_setter", function() {
document.head = "";
ok(typeof(document.head) === "object", "typeof(document.head) = " + typeof(document.head));
});
+
+
+sync_test("declaration_let", function() {
+ ok(a === undefined, "a is not undefined");
+ var a = 3;
+
+ {
+ let a = 2;
+
+ ok(a == 2, "a != 2");
+
+ a = 4;
+ ok(a == 4, "a != 4");
+ }
+
+ todo_wine.ok(a == 3, "a != 3");
+});
--
2.31.1
3
11
[PATCH 1/4] mf: Move presentation clock implementation to a separate file.
by Nikolay Sivov 15 Jun '21
by Nikolay Sivov 15 Jun '21
15 Jun '21
Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com>
---
dlls/mf/Makefile.in | 1 +
dlls/mf/clock.c | 1162 +++++++++++++++++++++++++++++++++++++++++++
dlls/mf/session.c | 1135 ------------------------------------------
3 files changed, 1163 insertions(+), 1135 deletions(-)
create mode 100644 dlls/mf/clock.c
diff --git a/dlls/mf/Makefile.in b/dlls/mf/Makefile.in
index e56d4c04a84..e80883fb642 100644
--- a/dlls/mf/Makefile.in
+++ b/dlls/mf/Makefile.in
@@ -6,6 +6,7 @@ DELAYIMPORTS = evr user32
EXTRADLLFLAGS = -mno-cygwin -Wb,--prefer-native
C_SRCS = \
+ clock.c \
copier.c \
evr.c \
main.c \
diff --git a/dlls/mf/clock.c b/dlls/mf/clock.c
new file mode 100644
index 00000000000..a9ca9b4528b
--- /dev/null
+++ b/dlls/mf/clock.c
@@ -0,0 +1,1162 @@
+/*
+ * Copyright 2017 Nikolay Sivov
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#define COBJMACROS
+
+#include "wine/debug.h"
+#include "wine/heap.h"
+#include "wine/list.h"
+
+#include "mf_private.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
+
+struct clock_sink
+{
+ struct list entry;
+ IMFClockStateSink *state_sink;
+};
+
+enum clock_command
+{
+ CLOCK_CMD_START = 0,
+ CLOCK_CMD_STOP,
+ CLOCK_CMD_PAUSE,
+ CLOCK_CMD_SET_RATE,
+ CLOCK_CMD_MAX,
+};
+
+enum clock_notification
+{
+ CLOCK_NOTIFY_START,
+ CLOCK_NOTIFY_STOP,
+ CLOCK_NOTIFY_PAUSE,
+ CLOCK_NOTIFY_RESTART,
+ CLOCK_NOTIFY_SET_RATE,
+};
+
+struct clock_state_change_param
+{
+ union
+ {
+ LONGLONG offset;
+ float rate;
+ } u;
+};
+
+struct sink_notification
+{
+ IUnknown IUnknown_iface;
+ LONG refcount;
+ MFTIME system_time;
+ struct clock_state_change_param param;
+ enum clock_notification notification;
+ IMFClockStateSink *sink;
+};
+
+struct clock_timer
+{
+ IUnknown IUnknown_iface;
+ LONG refcount;
+ IMFAsyncResult *result;
+ IMFAsyncCallback *callback;
+ MFWORKITEM_KEY key;
+ struct list entry;
+};
+
+struct presentation_clock
+{
+ IMFPresentationClock IMFPresentationClock_iface;
+ IMFRateControl IMFRateControl_iface;
+ IMFTimer IMFTimer_iface;
+ IMFShutdown IMFShutdown_iface;
+ IMFAsyncCallback sink_callback;
+ IMFAsyncCallback timer_callback;
+ LONG refcount;
+ IMFPresentationTimeSource *time_source;
+ IMFClockStateSink *time_source_sink;
+ MFCLOCK_STATE state;
+ LONGLONG start_offset;
+ struct list sinks;
+ struct list timers;
+ float rate;
+ LONGLONG frequency;
+ CRITICAL_SECTION cs;
+ BOOL is_shut_down;
+};
+
+static struct presentation_clock *impl_from_IMFPresentationClock(IMFPresentationClock *iface)
+{
+ return CONTAINING_RECORD(iface, struct presentation_clock, IMFPresentationClock_iface);
+}
+
+static struct presentation_clock *impl_from_IMFRateControl(IMFRateControl *iface)
+{
+ return CONTAINING_RECORD(iface, struct presentation_clock, IMFRateControl_iface);
+}
+
+static struct presentation_clock *impl_from_IMFTimer(IMFTimer *iface)
+{
+ return CONTAINING_RECORD(iface, struct presentation_clock, IMFTimer_iface);
+}
+
+static struct presentation_clock *impl_from_IMFShutdown(IMFShutdown *iface)
+{
+ return CONTAINING_RECORD(iface, struct presentation_clock, IMFShutdown_iface);
+}
+
+static struct presentation_clock *impl_from_sink_callback_IMFAsyncCallback(IMFAsyncCallback *iface)
+{
+ return CONTAINING_RECORD(iface, struct presentation_clock, sink_callback);
+}
+
+static struct presentation_clock *impl_from_timer_callback_IMFAsyncCallback(IMFAsyncCallback *iface)
+{
+ return CONTAINING_RECORD(iface, struct presentation_clock, timer_callback);
+}
+
+static struct clock_timer *impl_clock_timer_from_IUnknown(IUnknown *iface)
+{
+ return CONTAINING_RECORD(iface, struct clock_timer, IUnknown_iface);
+}
+
+static struct sink_notification *impl_sink_notification_from_IUnknown(IUnknown *iface)
+{
+ return CONTAINING_RECORD(iface, struct sink_notification, IUnknown_iface);
+}
+
+static HRESULT WINAPI sink_notification_QueryInterface(IUnknown *iface, REFIID riid, void **out)
+{
+ if (IsEqualIID(riid, &IID_IUnknown))
+ {
+ *out = iface;
+ IUnknown_AddRef(iface);
+ return S_OK;
+ }
+
+ WARN("Unsupported %s.\n", debugstr_guid(riid));
+ *out = NULL;
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI sink_notification_AddRef(IUnknown *iface)
+{
+ struct sink_notification *notification = impl_sink_notification_from_IUnknown(iface);
+ ULONG refcount = InterlockedIncrement(¬ification->refcount);
+
+ TRACE("%p, refcount %u.\n", iface, refcount);
+
+ return refcount;
+}
+
+static ULONG WINAPI sink_notification_Release(IUnknown *iface)
+{
+ struct sink_notification *notification = impl_sink_notification_from_IUnknown(iface);
+ ULONG refcount = InterlockedDecrement(¬ification->refcount);
+
+ TRACE("%p, refcount %u.\n", iface, refcount);
+
+ if (!refcount)
+ {
+ IMFClockStateSink_Release(notification->sink);
+ heap_free(notification);
+ }
+
+ return refcount;
+}
+
+static const IUnknownVtbl sinknotificationvtbl =
+{
+ sink_notification_QueryInterface,
+ sink_notification_AddRef,
+ sink_notification_Release,
+};
+
+static void clock_notify_async_sink(struct presentation_clock *clock, MFTIME system_time,
+ struct clock_state_change_param param, enum clock_notification notification, IMFClockStateSink *sink)
+{
+ struct sink_notification *object;
+ IMFAsyncResult *result;
+ HRESULT hr;
+
+ object = heap_alloc(sizeof(*object));
+ if (!object)
+ return;
+
+ object->IUnknown_iface.lpVtbl = &sinknotificationvtbl;
+ object->refcount = 1;
+ object->system_time = system_time;
+ object->param = param;
+ object->notification = notification;
+ object->sink = sink;
+ IMFClockStateSink_AddRef(object->sink);
+
+ hr = MFCreateAsyncResult(&object->IUnknown_iface, &clock->sink_callback, NULL, &result);
+ IUnknown_Release(&object->IUnknown_iface);
+ if (SUCCEEDED(hr))
+ {
+ MFPutWorkItemEx(MFASYNC_CALLBACK_QUEUE_STANDARD, result);
+ IMFAsyncResult_Release(result);
+ }
+}
+
+static HRESULT WINAPI present_clock_QueryInterface(IMFPresentationClock *iface, REFIID riid, void **out)
+{
+ struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
+
+ TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out);
+
+ if (IsEqualIID(riid, &IID_IMFPresentationClock) ||
+ IsEqualIID(riid, &IID_IMFClock) ||
+ IsEqualIID(riid, &IID_IUnknown))
+ {
+ *out = &clock->IMFPresentationClock_iface;
+ }
+ else if (IsEqualIID(riid, &IID_IMFRateControl))
+ {
+ *out = &clock->IMFRateControl_iface;
+ }
+ else if (IsEqualIID(riid, &IID_IMFTimer))
+ {
+ *out = &clock->IMFTimer_iface;
+ }
+ else if (IsEqualIID(riid, &IID_IMFShutdown))
+ {
+ *out = &clock->IMFShutdown_iface;
+ }
+ else
+ {
+ WARN("Unsupported %s.\n", debugstr_guid(riid));
+ *out = NULL;
+ return E_NOINTERFACE;
+ }
+
+ IUnknown_AddRef((IUnknown *)*out);
+ return S_OK;
+}
+
+static ULONG WINAPI present_clock_AddRef(IMFPresentationClock *iface)
+{
+ struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
+ ULONG refcount = InterlockedIncrement(&clock->refcount);
+
+ TRACE("%p, refcount %u.\n", iface, refcount);
+
+ return refcount;
+}
+
+static ULONG WINAPI present_clock_Release(IMFPresentationClock *iface)
+{
+ struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
+ ULONG refcount = InterlockedDecrement(&clock->refcount);
+ struct clock_timer *timer, *timer2;
+ struct clock_sink *sink, *sink2;
+
+ TRACE("%p, refcount %u.\n", iface, refcount);
+
+ if (!refcount)
+ {
+ if (clock->time_source)
+ IMFPresentationTimeSource_Release(clock->time_source);
+ if (clock->time_source_sink)
+ IMFClockStateSink_Release(clock->time_source_sink);
+ LIST_FOR_EACH_ENTRY_SAFE(sink, sink2, &clock->sinks, struct clock_sink, entry)
+ {
+ list_remove(&sink->entry);
+ IMFClockStateSink_Release(sink->state_sink);
+ heap_free(sink);
+ }
+ LIST_FOR_EACH_ENTRY_SAFE(timer, timer2, &clock->timers, struct clock_timer, entry)
+ {
+ list_remove(&timer->entry);
+ IUnknown_Release(&timer->IUnknown_iface);
+ }
+ DeleteCriticalSection(&clock->cs);
+ heap_free(clock);
+ }
+
+ return refcount;
+}
+
+static HRESULT WINAPI present_clock_GetClockCharacteristics(IMFPresentationClock *iface, DWORD *flags)
+{
+ struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
+ HRESULT hr = MF_E_CLOCK_NO_TIME_SOURCE;
+
+ TRACE("%p, %p.\n", iface, flags);
+
+ EnterCriticalSection(&clock->cs);
+ if (clock->time_source)
+ hr = IMFPresentationTimeSource_GetClockCharacteristics(clock->time_source, flags);
+ LeaveCriticalSection(&clock->cs);
+
+ return hr;
+}
+
+static HRESULT WINAPI present_clock_GetCorrelatedTime(IMFPresentationClock *iface, DWORD reserved,
+ LONGLONG *clock_time, MFTIME *system_time)
+{
+ struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
+ HRESULT hr = MF_E_CLOCK_NO_TIME_SOURCE;
+
+ TRACE("%p, %#x, %p, %p.\n", iface, reserved, clock_time, system_time);
+
+ EnterCriticalSection(&clock->cs);
+ if (clock->time_source)
+ hr = IMFPresentationTimeSource_GetCorrelatedTime(clock->time_source, reserved, clock_time, system_time);
+ LeaveCriticalSection(&clock->cs);
+
+ return hr;
+}
+
+static HRESULT WINAPI present_clock_GetContinuityKey(IMFPresentationClock *iface, DWORD *key)
+{
+ TRACE("%p, %p.\n", iface, key);
+
+ *key = 0;
+
+ return S_OK;
+}
+
+static HRESULT WINAPI present_clock_GetState(IMFPresentationClock *iface, DWORD reserved, MFCLOCK_STATE *state)
+{
+ struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
+
+ TRACE("%p, %#x, %p.\n", iface, reserved, state);
+
+ EnterCriticalSection(&clock->cs);
+ *state = clock->state;
+ LeaveCriticalSection(&clock->cs);
+
+ return S_OK;
+}
+
+static HRESULT WINAPI present_clock_GetProperties(IMFPresentationClock *iface, MFCLOCK_PROPERTIES *props)
+{
+ struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
+ HRESULT hr = MF_E_CLOCK_NO_TIME_SOURCE;
+
+ TRACE("%p, %p.\n", iface, props);
+
+ EnterCriticalSection(&clock->cs);
+ if (clock->time_source)
+ hr = IMFPresentationTimeSource_GetProperties(clock->time_source, props);
+ LeaveCriticalSection(&clock->cs);
+
+ return hr;
+}
+
+static HRESULT WINAPI present_clock_SetTimeSource(IMFPresentationClock *iface,
+ IMFPresentationTimeSource *time_source)
+{
+ struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
+ MFCLOCK_PROPERTIES props;
+ IMFClock *source_clock;
+ HRESULT hr;
+
+ TRACE("%p, %p.\n", iface, time_source);
+
+ EnterCriticalSection(&clock->cs);
+
+ if (clock->time_source)
+ IMFPresentationTimeSource_Release(clock->time_source);
+ if (clock->time_source_sink)
+ IMFClockStateSink_Release(clock->time_source_sink);
+ clock->time_source = NULL;
+ clock->time_source_sink = NULL;
+
+ hr = IMFPresentationTimeSource_QueryInterface(time_source, &IID_IMFClockStateSink, (void **)&clock->time_source_sink);
+ if (SUCCEEDED(hr))
+ {
+ clock->time_source = time_source;
+ IMFPresentationTimeSource_AddRef(clock->time_source);
+ }
+
+ if (SUCCEEDED(IMFPresentationTimeSource_GetUnderlyingClock(time_source, &source_clock)))
+ {
+ if (SUCCEEDED(IMFClock_GetProperties(source_clock, &props)))
+ clock->frequency = props.qwClockFrequency;
+ IMFClock_Release(source_clock);
+ }
+
+ if (!clock->frequency)
+ clock->frequency = MFCLOCK_FREQUENCY_HNS;
+
+ LeaveCriticalSection(&clock->cs);
+
+ return hr;
+}
+
+static HRESULT WINAPI present_clock_GetTimeSource(IMFPresentationClock *iface,
+ IMFPresentationTimeSource **time_source)
+{
+ struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
+ HRESULT hr = S_OK;
+
+ TRACE("%p, %p.\n", iface, time_source);
+
+ if (!time_source)
+ return E_INVALIDARG;
+
+ EnterCriticalSection(&clock->cs);
+ if (clock->time_source)
+ {
+ *time_source = clock->time_source;
+ IMFPresentationTimeSource_AddRef(*time_source);
+ }
+ else
+ hr = MF_E_CLOCK_NO_TIME_SOURCE;
+ LeaveCriticalSection(&clock->cs);
+
+ return hr;
+}
+
+static HRESULT WINAPI present_clock_GetTime(IMFPresentationClock *iface, MFTIME *time)
+{
+ struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
+ HRESULT hr = MF_E_CLOCK_NO_TIME_SOURCE;
+ MFTIME systime;
+
+ TRACE("%p, %p.\n", iface, time);
+
+ if (!time)
+ return E_POINTER;
+
+ EnterCriticalSection(&clock->cs);
+ if (clock->time_source)
+ hr = IMFPresentationTimeSource_GetCorrelatedTime(clock->time_source, 0, time, &systime);
+ LeaveCriticalSection(&clock->cs);
+
+ return hr;
+}
+
+static HRESULT WINAPI present_clock_AddClockStateSink(IMFPresentationClock *iface, IMFClockStateSink *state_sink)
+{
+ struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
+ struct clock_sink *sink, *cur;
+ HRESULT hr = S_OK;
+
+ TRACE("%p, %p.\n", iface, state_sink);
+
+ if (!state_sink)
+ return E_INVALIDARG;
+
+ sink = heap_alloc(sizeof(*sink));
+ if (!sink)
+ return E_OUTOFMEMORY;
+
+ sink->state_sink = state_sink;
+ IMFClockStateSink_AddRef(sink->state_sink);
+
+ EnterCriticalSection(&clock->cs);
+ LIST_FOR_EACH_ENTRY(cur, &clock->sinks, struct clock_sink, entry)
+ {
+ if (cur->state_sink == state_sink)
+ {
+ hr = E_INVALIDARG;
+ break;
+ }
+ }
+ if (SUCCEEDED(hr))
+ {
+ static const enum clock_notification notifications[MFCLOCK_STATE_PAUSED + 1] =
+ {
+ /* MFCLOCK_STATE_INVALID */ 0, /* Does not apply */
+ /* MFCLOCK_STATE_RUNNING */ CLOCK_NOTIFY_START,
+ /* MFCLOCK_STATE_STOPPED */ CLOCK_NOTIFY_STOP,
+ /* MFCLOCK_STATE_PAUSED */ CLOCK_NOTIFY_PAUSE,
+ };
+ struct clock_state_change_param param;
+
+ if (!clock->is_shut_down && clock->state != MFCLOCK_STATE_INVALID)
+ {
+ param.u.offset = clock->start_offset;
+ clock_notify_async_sink(clock, MFGetSystemTime(), param, notifications[clock->state], sink->state_sink);
+ }
+
+ list_add_tail(&clock->sinks, &sink->entry);
+ }
+ LeaveCriticalSection(&clock->cs);
+
+ if (FAILED(hr))
+ {
+ IMFClockStateSink_Release(sink->state_sink);
+ heap_free(sink);
+ }
+
+ return hr;
+}
+
+static HRESULT WINAPI present_clock_RemoveClockStateSink(IMFPresentationClock *iface,
+ IMFClockStateSink *state_sink)
+{
+ struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
+ struct clock_sink *sink;
+
+ TRACE("%p, %p.\n", iface, state_sink);
+
+ if (!state_sink)
+ return E_INVALIDARG;
+
+ EnterCriticalSection(&clock->cs);
+ LIST_FOR_EACH_ENTRY(sink, &clock->sinks, struct clock_sink, entry)
+ {
+ if (sink->state_sink == state_sink)
+ {
+ IMFClockStateSink_Release(sink->state_sink);
+ list_remove(&sink->entry);
+ heap_free(sink);
+ break;
+ }
+ }
+ LeaveCriticalSection(&clock->cs);
+
+ return S_OK;
+}
+
+static HRESULT clock_call_state_change(MFTIME system_time, struct clock_state_change_param param,
+ enum clock_notification notification, IMFClockStateSink *sink)
+{
+ HRESULT hr = S_OK;
+
+ switch (notification)
+ {
+ case CLOCK_NOTIFY_START:
+ hr = IMFClockStateSink_OnClockStart(sink, system_time, param.u.offset);
+ break;
+ case CLOCK_NOTIFY_STOP:
+ hr = IMFClockStateSink_OnClockStop(sink, system_time);
+ break;
+ case CLOCK_NOTIFY_PAUSE:
+ hr = IMFClockStateSink_OnClockPause(sink, system_time);
+ break;
+ case CLOCK_NOTIFY_RESTART:
+ hr = IMFClockStateSink_OnClockRestart(sink, system_time);
+ break;
+ case CLOCK_NOTIFY_SET_RATE:
+ /* System time source does not allow 0.0 rate, presentation clock allows it without raising errors. */
+ IMFClockStateSink_OnClockSetRate(sink, system_time, param.u.rate);
+ break;
+ default:
+ ;
+ }
+
+ return hr;
+}
+
+static HRESULT clock_change_state(struct presentation_clock *clock, enum clock_command command,
+ struct clock_state_change_param param)
+{
+ static const BYTE state_change_is_allowed[MFCLOCK_STATE_PAUSED+1][CLOCK_CMD_MAX] =
+ { /* S S* P, R */
+ /* INVALID */ { 1, 1, 1, 1 },
+ /* RUNNING */ { 1, 1, 1, 1 },
+ /* STOPPED */ { 1, 1, 0, 1 },
+ /* PAUSED */ { 1, 1, 0, 1 },
+ };
+ static const MFCLOCK_STATE states[CLOCK_CMD_MAX] =
+ {
+ /* CLOCK_CMD_START */ MFCLOCK_STATE_RUNNING,
+ /* CLOCK_CMD_STOP */ MFCLOCK_STATE_STOPPED,
+ /* CLOCK_CMD_PAUSE */ MFCLOCK_STATE_PAUSED,
+ /* CLOCK_CMD_SET_RATE */ 0, /* Unused */
+ };
+ static const enum clock_notification notifications[CLOCK_CMD_MAX] =
+ {
+ /* CLOCK_CMD_START */ CLOCK_NOTIFY_START,
+ /* CLOCK_CMD_STOP */ CLOCK_NOTIFY_STOP,
+ /* CLOCK_CMD_PAUSE */ CLOCK_NOTIFY_PAUSE,
+ /* CLOCK_CMD_SET_RATE */ CLOCK_NOTIFY_SET_RATE,
+ };
+ enum clock_notification notification;
+ struct clock_sink *sink;
+ MFCLOCK_STATE old_state;
+ IMFAsyncResult *result;
+ MFTIME system_time;
+ HRESULT hr;
+
+ if (!clock->time_source)
+ return MF_E_CLOCK_NO_TIME_SOURCE;
+
+ if (command != CLOCK_CMD_SET_RATE && clock->state == states[command] && clock->state != MFCLOCK_STATE_RUNNING)
+ return MF_E_CLOCK_STATE_ALREADY_SET;
+
+ if (!state_change_is_allowed[clock->state][command])
+ return MF_E_INVALIDREQUEST;
+
+ system_time = MFGetSystemTime();
+
+ if (command == CLOCK_CMD_START && clock->state == MFCLOCK_STATE_PAUSED &&
+ param.u.offset == PRESENTATION_CURRENT_POSITION)
+ {
+ notification = CLOCK_NOTIFY_RESTART;
+ }
+ else
+ notification = notifications[command];
+
+ if (FAILED(hr = clock_call_state_change(system_time, param, notification, clock->time_source_sink)))
+ return hr;
+
+ old_state = clock->state;
+ if (command != CLOCK_CMD_SET_RATE)
+ clock->state = states[command];
+
+ /* Dump all pending timer requests immediately on start; otherwise try to cancel scheduled items when
+ transitioning from running state. */
+ if ((clock->state == MFCLOCK_STATE_RUNNING) ^ (old_state == MFCLOCK_STATE_RUNNING))
+ {
+ struct clock_timer *timer, *timer2;
+
+ if (clock->state == MFCLOCK_STATE_RUNNING)
+ {
+ LIST_FOR_EACH_ENTRY_SAFE(timer, timer2, &clock->timers, struct clock_timer, entry)
+ {
+ list_remove(&timer->entry);
+ hr = MFCreateAsyncResult(&timer->IUnknown_iface, &clock->timer_callback, NULL, &result);
+ IUnknown_Release(&timer->IUnknown_iface);
+ if (SUCCEEDED(hr))
+ {
+ MFPutWorkItemEx(MFASYNC_CALLBACK_QUEUE_TIMER, result);
+ IMFAsyncResult_Release(result);
+ }
+ }
+ }
+ else
+ {
+ LIST_FOR_EACH_ENTRY(timer, &clock->timers, struct clock_timer, entry)
+ {
+ if (timer->key)
+ {
+ MFCancelWorkItem(timer->key);
+ timer->key = 0;
+ }
+ }
+ }
+ }
+
+ LIST_FOR_EACH_ENTRY(sink, &clock->sinks, struct clock_sink, entry)
+ {
+ clock_notify_async_sink(clock, system_time, param, notification, sink->state_sink);
+ }
+
+ return S_OK;
+}
+
+static HRESULT WINAPI present_clock_Start(IMFPresentationClock *iface, LONGLONG start_offset)
+{
+ struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
+ struct clock_state_change_param param = {{0}};
+ HRESULT hr;
+
+ TRACE("%p, %s.\n", iface, debugstr_time(start_offset));
+
+ EnterCriticalSection(&clock->cs);
+ clock->start_offset = param.u.offset = start_offset;
+ hr = clock_change_state(clock, CLOCK_CMD_START, param);
+ LeaveCriticalSection(&clock->cs);
+
+ return hr;
+}
+
+static HRESULT WINAPI present_clock_Stop(IMFPresentationClock *iface)
+{
+ struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
+ struct clock_state_change_param param = {{0}};
+ HRESULT hr;
+
+ TRACE("%p.\n", iface);
+
+ EnterCriticalSection(&clock->cs);
+ hr = clock_change_state(clock, CLOCK_CMD_STOP, param);
+ LeaveCriticalSection(&clock->cs);
+
+ return hr;
+}
+
+static HRESULT WINAPI present_clock_Pause(IMFPresentationClock *iface)
+{
+ struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
+ struct clock_state_change_param param = {{0}};
+ HRESULT hr;
+
+ TRACE("%p.\n", iface);
+
+ EnterCriticalSection(&clock->cs);
+ hr = clock_change_state(clock, CLOCK_CMD_PAUSE, param);
+ LeaveCriticalSection(&clock->cs);
+
+ return hr;
+}
+
+static const IMFPresentationClockVtbl presentationclockvtbl =
+{
+ present_clock_QueryInterface,
+ present_clock_AddRef,
+ present_clock_Release,
+ present_clock_GetClockCharacteristics,
+ present_clock_GetCorrelatedTime,
+ present_clock_GetContinuityKey,
+ present_clock_GetState,
+ present_clock_GetProperties,
+ present_clock_SetTimeSource,
+ present_clock_GetTimeSource,
+ present_clock_GetTime,
+ present_clock_AddClockStateSink,
+ present_clock_RemoveClockStateSink,
+ present_clock_Start,
+ present_clock_Stop,
+ present_clock_Pause,
+};
+
+static HRESULT WINAPI present_clock_rate_control_QueryInterface(IMFRateControl *iface, REFIID riid, void **out)
+{
+ struct presentation_clock *clock = impl_from_IMFRateControl(iface);
+ return IMFPresentationClock_QueryInterface(&clock->IMFPresentationClock_iface, riid, out);
+}
+
+static ULONG WINAPI present_clock_rate_control_AddRef(IMFRateControl *iface)
+{
+ struct presentation_clock *clock = impl_from_IMFRateControl(iface);
+ return IMFPresentationClock_AddRef(&clock->IMFPresentationClock_iface);
+}
+
+static ULONG WINAPI present_clock_rate_control_Release(IMFRateControl *iface)
+{
+ struct presentation_clock *clock = impl_from_IMFRateControl(iface);
+ return IMFPresentationClock_Release(&clock->IMFPresentationClock_iface);
+}
+
+static HRESULT WINAPI present_clock_rate_SetRate(IMFRateControl *iface, BOOL thin, float rate)
+{
+ struct presentation_clock *clock = impl_from_IMFRateControl(iface);
+ struct clock_state_change_param param;
+ HRESULT hr;
+
+ TRACE("%p, %d, %f.\n", iface, thin, rate);
+
+ if (thin)
+ return MF_E_THINNING_UNSUPPORTED;
+
+ EnterCriticalSection(&clock->cs);
+ param.u.rate = rate;
+ if (SUCCEEDED(hr = clock_change_state(clock, CLOCK_CMD_SET_RATE, param)))
+ clock->rate = rate;
+ LeaveCriticalSection(&clock->cs);
+
+ return hr;
+}
+
+static HRESULT WINAPI present_clock_rate_GetRate(IMFRateControl *iface, BOOL *thin, float *rate)
+{
+ struct presentation_clock *clock = impl_from_IMFRateControl(iface);
+
+ TRACE("%p, %p, %p.\n", iface, thin, rate);
+
+ if (!rate)
+ return E_INVALIDARG;
+
+ if (thin)
+ *thin = FALSE;
+
+ EnterCriticalSection(&clock->cs);
+ *rate = clock->rate;
+ LeaveCriticalSection(&clock->cs);
+
+ return S_OK;
+}
+
+static const IMFRateControlVtbl presentclockratecontrolvtbl =
+{
+ present_clock_rate_control_QueryInterface,
+ present_clock_rate_control_AddRef,
+ present_clock_rate_control_Release,
+ present_clock_rate_SetRate,
+ present_clock_rate_GetRate,
+};
+
+static HRESULT WINAPI present_clock_timer_QueryInterface(IMFTimer *iface, REFIID riid, void **out)
+{
+ struct presentation_clock *clock = impl_from_IMFTimer(iface);
+ return IMFPresentationClock_QueryInterface(&clock->IMFPresentationClock_iface, riid, out);
+}
+
+static ULONG WINAPI present_clock_timer_AddRef(IMFTimer *iface)
+{
+ struct presentation_clock *clock = impl_from_IMFTimer(iface);
+ return IMFPresentationClock_AddRef(&clock->IMFPresentationClock_iface);
+}
+
+static ULONG WINAPI present_clock_timer_Release(IMFTimer *iface)
+{
+ struct presentation_clock *clock = impl_from_IMFTimer(iface);
+ return IMFPresentationClock_Release(&clock->IMFPresentationClock_iface);
+}
+
+static HRESULT present_clock_schedule_timer(struct presentation_clock *clock, DWORD flags, LONGLONG time,
+ struct clock_timer *timer)
+{
+ IMFAsyncResult *result;
+ MFTIME systime, clocktime;
+ LONGLONG frequency;
+ HRESULT hr;
+
+ if (!(flags & MFTIMER_RELATIVE))
+ {
+ if (FAILED(hr = IMFPresentationTimeSource_GetCorrelatedTime(clock->time_source, 0, &clocktime, &systime)))
+ {
+ WARN("Failed to get clock time, hr %#x.\n", hr);
+ return hr;
+ }
+ time -= clocktime;
+ }
+
+ frequency = clock->frequency / 1000;
+ time /= frequency;
+
+ /* Scheduled item is using clock instance callback, with timer instance as an object. Clock callback will
+ call user callback and cleanup timer list. */
+
+ if (FAILED(hr = MFCreateAsyncResult(&timer->IUnknown_iface, &clock->timer_callback, NULL, &result)))
+ return hr;
+
+ hr = MFScheduleWorkItemEx(result, -time, &timer->key);
+ IMFAsyncResult_Release(result);
+
+ return hr;
+}
+
+static HRESULT WINAPI clock_timer_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
+{
+ if (IsEqualIID(riid, &IID_IUnknown))
+ {
+ *obj = iface;
+ IUnknown_AddRef(iface);
+ return S_OK;
+ }
+
+ *obj = NULL;
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI clock_timer_AddRef(IUnknown *iface)
+{
+ struct clock_timer *timer = impl_clock_timer_from_IUnknown(iface);
+ return InterlockedIncrement(&timer->refcount);
+}
+
+static ULONG WINAPI clock_timer_Release(IUnknown *iface)
+{
+ struct clock_timer *timer = impl_clock_timer_from_IUnknown(iface);
+ ULONG refcount = InterlockedDecrement(&timer->refcount);
+
+ if (!refcount)
+ {
+ IMFAsyncResult_Release(timer->result);
+ IMFAsyncCallback_Release(timer->callback);
+ heap_free(timer);
+ }
+
+ return refcount;
+}
+
+static const IUnknownVtbl clock_timer_vtbl =
+{
+ clock_timer_QueryInterface,
+ clock_timer_AddRef,
+ clock_timer_Release,
+};
+
+static HRESULT WINAPI present_clock_timer_SetTimer(IMFTimer *iface, DWORD flags, LONGLONG time,
+ IMFAsyncCallback *callback, IUnknown *state, IUnknown **cancel_key)
+{
+ struct presentation_clock *clock = impl_from_IMFTimer(iface);
+ struct clock_timer *clock_timer;
+ HRESULT hr;
+
+ TRACE("%p, %#x, %s, %p, %p, %p.\n", iface, flags, debugstr_time(time), callback, state, cancel_key);
+
+ if (!(clock_timer = heap_alloc_zero(sizeof(*clock_timer))))
+ return E_OUTOFMEMORY;
+
+ if (FAILED(hr = MFCreateAsyncResult(NULL, NULL, state, &clock_timer->result)))
+ {
+ heap_free(clock_timer);
+ return hr;
+ }
+
+ clock_timer->IUnknown_iface.lpVtbl = &clock_timer_vtbl;
+ clock_timer->refcount = 1;
+ clock_timer->callback = callback;
+ IMFAsyncCallback_AddRef(clock_timer->callback);
+
+ EnterCriticalSection(&clock->cs);
+
+ if (clock->state == MFCLOCK_STATE_RUNNING)
+ hr = present_clock_schedule_timer(clock, flags, time, clock_timer);
+ else if (clock->state == MFCLOCK_STATE_STOPPED)
+ hr = MF_S_CLOCK_STOPPED;
+
+ if (SUCCEEDED(hr))
+ {
+ list_add_tail(&clock->timers, &clock_timer->entry);
+ if (cancel_key)
+ {
+ *cancel_key = &clock_timer->IUnknown_iface;
+ IUnknown_AddRef(*cancel_key);
+ }
+ }
+
+ LeaveCriticalSection(&clock->cs);
+
+ if (FAILED(hr))
+ IUnknown_Release(&clock_timer->IUnknown_iface);
+
+ return hr;
+}
+
+static HRESULT WINAPI present_clock_timer_CancelTimer(IMFTimer *iface, IUnknown *cancel_key)
+{
+ struct presentation_clock *clock = impl_from_IMFTimer(iface);
+ struct clock_timer *timer;
+
+ TRACE("%p, %p.\n", iface, cancel_key);
+
+ EnterCriticalSection(&clock->cs);
+
+ LIST_FOR_EACH_ENTRY(timer, &clock->timers, struct clock_timer, entry)
+ {
+ if (&timer->IUnknown_iface == cancel_key)
+ {
+ list_remove(&timer->entry);
+ if (timer->key)
+ {
+ MFCancelWorkItem(timer->key);
+ timer->key = 0;
+ }
+ IUnknown_Release(&timer->IUnknown_iface);
+ break;
+ }
+ }
+
+ LeaveCriticalSection(&clock->cs);
+
+ return S_OK;
+}
+
+static const IMFTimerVtbl presentclocktimervtbl =
+{
+ present_clock_timer_QueryInterface,
+ present_clock_timer_AddRef,
+ present_clock_timer_Release,
+ present_clock_timer_SetTimer,
+ present_clock_timer_CancelTimer,
+};
+
+static HRESULT WINAPI present_clock_shutdown_QueryInterface(IMFShutdown *iface, REFIID riid, void **out)
+{
+ struct presentation_clock *clock = impl_from_IMFShutdown(iface);
+ return IMFPresentationClock_QueryInterface(&clock->IMFPresentationClock_iface, riid, out);
+}
+
+static ULONG WINAPI present_clock_shutdown_AddRef(IMFShutdown *iface)
+{
+ struct presentation_clock *clock = impl_from_IMFShutdown(iface);
+ return IMFPresentationClock_AddRef(&clock->IMFPresentationClock_iface);
+}
+
+static ULONG WINAPI present_clock_shutdown_Release(IMFShutdown *iface)
+{
+ struct presentation_clock *clock = impl_from_IMFShutdown(iface);
+ return IMFPresentationClock_Release(&clock->IMFPresentationClock_iface);
+}
+
+static HRESULT WINAPI present_clock_shutdown_Shutdown(IMFShutdown *iface)
+{
+ struct presentation_clock *clock = impl_from_IMFShutdown(iface);
+
+ TRACE("%p.\n", iface);
+
+ EnterCriticalSection(&clock->cs);
+ clock->is_shut_down = TRUE;
+ LeaveCriticalSection(&clock->cs);
+
+ return S_OK;
+}
+
+static HRESULT WINAPI present_clock_shutdown_GetShutdownStatus(IMFShutdown *iface, MFSHUTDOWN_STATUS *status)
+{
+ struct presentation_clock *clock = impl_from_IMFShutdown(iface);
+ HRESULT hr = S_OK;
+
+ TRACE("%p, %p.\n", iface, status);
+
+ if (!status)
+ return E_INVALIDARG;
+
+ EnterCriticalSection(&clock->cs);
+ if (clock->is_shut_down)
+ *status = MFSHUTDOWN_COMPLETED;
+ else
+ hr = MF_E_INVALIDREQUEST;
+ LeaveCriticalSection(&clock->cs);
+
+ return hr;
+}
+
+static const IMFShutdownVtbl presentclockshutdownvtbl =
+{
+ present_clock_shutdown_QueryInterface,
+ present_clock_shutdown_AddRef,
+ present_clock_shutdown_Release,
+ present_clock_shutdown_Shutdown,
+ present_clock_shutdown_GetShutdownStatus,
+};
+
+static HRESULT WINAPI present_clock_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **out)
+{
+ if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
+ IsEqualIID(riid, &IID_IUnknown))
+ {
+ *out = iface;
+ IMFAsyncCallback_AddRef(iface);
+ return S_OK;
+ }
+
+ WARN("Unsupported %s.\n", wine_dbgstr_guid(riid));
+ *out = NULL;
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI present_clock_sink_callback_AddRef(IMFAsyncCallback *iface)
+{
+ struct presentation_clock *clock = impl_from_sink_callback_IMFAsyncCallback(iface);
+ return IMFPresentationClock_AddRef(&clock->IMFPresentationClock_iface);
+}
+
+static ULONG WINAPI present_clock_sink_callback_Release(IMFAsyncCallback *iface)
+{
+ struct presentation_clock *clock = impl_from_sink_callback_IMFAsyncCallback(iface);
+ return IMFPresentationClock_Release(&clock->IMFPresentationClock_iface);
+}
+
+static HRESULT WINAPI present_clock_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue)
+{
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI present_clock_sink_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
+{
+ struct sink_notification *data;
+ IUnknown *object;
+ HRESULT hr;
+
+ if (FAILED(hr = IMFAsyncResult_GetObject(result, &object)))
+ return hr;
+
+ data = impl_sink_notification_from_IUnknown(object);
+
+ clock_call_state_change(data->system_time, data->param, data->notification, data->sink);
+
+ IUnknown_Release(object);
+
+ return S_OK;
+}
+
+static const IMFAsyncCallbackVtbl presentclocksinkcallbackvtbl =
+{
+ present_clock_callback_QueryInterface,
+ present_clock_sink_callback_AddRef,
+ present_clock_sink_callback_Release,
+ present_clock_callback_GetParameters,
+ present_clock_sink_callback_Invoke,
+};
+
+static ULONG WINAPI present_clock_timer_callback_AddRef(IMFAsyncCallback *iface)
+{
+ struct presentation_clock *clock = impl_from_timer_callback_IMFAsyncCallback(iface);
+ return IMFPresentationClock_AddRef(&clock->IMFPresentationClock_iface);
+}
+
+static ULONG WINAPI present_clock_timer_callback_Release(IMFAsyncCallback *iface)
+{
+ struct presentation_clock *clock = impl_from_timer_callback_IMFAsyncCallback(iface);
+ return IMFPresentationClock_Release(&clock->IMFPresentationClock_iface);
+}
+
+static HRESULT WINAPI present_clock_timer_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
+{
+ struct presentation_clock *clock = impl_from_timer_callback_IMFAsyncCallback(iface);
+ struct clock_timer *timer;
+ IUnknown *object;
+ HRESULT hr;
+
+ if (FAILED(hr = IMFAsyncResult_GetObject(result, &object)))
+ return hr;
+
+ timer = impl_clock_timer_from_IUnknown(object);
+
+ EnterCriticalSection(&clock->cs);
+ list_remove(&timer->entry);
+ IUnknown_Release(&timer->IUnknown_iface);
+ LeaveCriticalSection(&clock->cs);
+
+ IMFAsyncCallback_Invoke(timer->callback, timer->result);
+
+ IUnknown_Release(object);
+
+ return S_OK;
+}
+
+static const IMFAsyncCallbackVtbl presentclocktimercallbackvtbl =
+{
+ present_clock_callback_QueryInterface,
+ present_clock_timer_callback_AddRef,
+ present_clock_timer_callback_Release,
+ present_clock_callback_GetParameters,
+ present_clock_timer_callback_Invoke,
+};
+
+/***********************************************************************
+ * MFCreatePresentationClock (mf.@)
+ */
+HRESULT WINAPI MFCreatePresentationClock(IMFPresentationClock **clock)
+{
+ struct presentation_clock *object;
+
+ TRACE("%p.\n", clock);
+
+ object = heap_alloc_zero(sizeof(*object));
+ if (!object)
+ return E_OUTOFMEMORY;
+
+ object->IMFPresentationClock_iface.lpVtbl = &presentationclockvtbl;
+ object->IMFRateControl_iface.lpVtbl = &presentclockratecontrolvtbl;
+ object->IMFTimer_iface.lpVtbl = &presentclocktimervtbl;
+ object->IMFShutdown_iface.lpVtbl = &presentclockshutdownvtbl;
+ object->sink_callback.lpVtbl = &presentclocksinkcallbackvtbl;
+ object->timer_callback.lpVtbl = &presentclocktimercallbackvtbl;
+ object->refcount = 1;
+ list_init(&object->sinks);
+ list_init(&object->timers);
+ object->rate = 1.0f;
+ InitializeCriticalSection(&object->cs);
+
+ *clock = &object->IMFPresentationClock_iface;
+
+ return S_OK;
+}
diff --git a/dlls/mf/session.c b/dlls/mf/session.c
index 9f233295773..a7f81e694c2 100644
--- a/dlls/mf/session.c
+++ b/dlls/mf/session.c
@@ -247,80 +247,6 @@ struct media_session
CRITICAL_SECTION cs;
};
-struct clock_sink
-{
- struct list entry;
- IMFClockStateSink *state_sink;
-};
-
-enum clock_command
-{
- CLOCK_CMD_START = 0,
- CLOCK_CMD_STOP,
- CLOCK_CMD_PAUSE,
- CLOCK_CMD_SET_RATE,
- CLOCK_CMD_MAX,
-};
-
-enum clock_notification
-{
- CLOCK_NOTIFY_START,
- CLOCK_NOTIFY_STOP,
- CLOCK_NOTIFY_PAUSE,
- CLOCK_NOTIFY_RESTART,
- CLOCK_NOTIFY_SET_RATE,
-};
-
-struct clock_state_change_param
-{
- union
- {
- LONGLONG offset;
- float rate;
- } u;
-};
-
-struct sink_notification
-{
- IUnknown IUnknown_iface;
- LONG refcount;
- MFTIME system_time;
- struct clock_state_change_param param;
- enum clock_notification notification;
- IMFClockStateSink *sink;
-};
-
-struct clock_timer
-{
- IUnknown IUnknown_iface;
- LONG refcount;
- IMFAsyncResult *result;
- IMFAsyncCallback *callback;
- MFWORKITEM_KEY key;
- struct list entry;
-};
-
-struct presentation_clock
-{
- IMFPresentationClock IMFPresentationClock_iface;
- IMFRateControl IMFRateControl_iface;
- IMFTimer IMFTimer_iface;
- IMFShutdown IMFShutdown_iface;
- IMFAsyncCallback sink_callback;
- IMFAsyncCallback timer_callback;
- LONG refcount;
- IMFPresentationTimeSource *time_source;
- IMFClockStateSink *time_source_sink;
- MFCLOCK_STATE state;
- LONGLONG start_offset;
- struct list sinks;
- struct list timers;
- float rate;
- LONGLONG frequency;
- CRITICAL_SECTION cs;
- BOOL is_shut_down;
-};
-
enum quality_manager_state
{
QUALITY_MANAGER_READY = 0,
@@ -384,46 +310,6 @@ static struct session_op *impl_op_from_IUnknown(IUnknown *iface)
return CONTAINING_RECORD(iface, struct session_op, IUnknown_iface);
}
-static struct presentation_clock *impl_from_IMFPresentationClock(IMFPresentationClock *iface)
-{
- return CONTAINING_RECORD(iface, struct presentation_clock, IMFPresentationClock_iface);
-}
-
-static struct presentation_clock *impl_from_IMFRateControl(IMFRateControl *iface)
-{
- return CONTAINING_RECORD(iface, struct presentation_clock, IMFRateControl_iface);
-}
-
-static struct presentation_clock *impl_from_IMFTimer(IMFTimer *iface)
-{
- return CONTAINING_RECORD(iface, struct presentation_clock, IMFTimer_iface);
-}
-
-static struct presentation_clock *impl_from_IMFShutdown(IMFShutdown *iface)
-{
- return CONTAINING_RECORD(iface, struct presentation_clock, IMFShutdown_iface);
-}
-
-static struct presentation_clock *impl_from_sink_callback_IMFAsyncCallback(IMFAsyncCallback *iface)
-{
- return CONTAINING_RECORD(iface, struct presentation_clock, sink_callback);
-}
-
-static struct presentation_clock *impl_from_timer_callback_IMFAsyncCallback(IMFAsyncCallback *iface)
-{
- return CONTAINING_RECORD(iface, struct presentation_clock, timer_callback);
-}
-
-static struct clock_timer *impl_clock_timer_from_IUnknown(IUnknown *iface)
-{
- return CONTAINING_RECORD(iface, struct clock_timer, IUnknown_iface);
-}
-
-static struct sink_notification *impl_sink_notification_from_IUnknown(IUnknown *iface)
-{
- return CONTAINING_RECORD(iface, struct sink_notification, IUnknown_iface);
-}
-
static struct quality_manager *impl_from_IMFQualityManager(IMFQualityManager *iface)
{
return CONTAINING_RECORD(iface, struct quality_manager, IMFQualityManager_iface);
@@ -3795,1027 +3681,6 @@ failed:
return hr;
}
-static HRESULT WINAPI sink_notification_QueryInterface(IUnknown *iface, REFIID riid, void **out)
-{
- if (IsEqualIID(riid, &IID_IUnknown))
- {
- *out = iface;
- IUnknown_AddRef(iface);
- return S_OK;
- }
-
- WARN("Unsupported %s.\n", debugstr_guid(riid));
- *out = NULL;
- return E_NOINTERFACE;
-}
-
-static ULONG WINAPI sink_notification_AddRef(IUnknown *iface)
-{
- struct sink_notification *notification = impl_sink_notification_from_IUnknown(iface);
- ULONG refcount = InterlockedIncrement(¬ification->refcount);
-
- TRACE("%p, refcount %u.\n", iface, refcount);
-
- return refcount;
-}
-
-static ULONG WINAPI sink_notification_Release(IUnknown *iface)
-{
- struct sink_notification *notification = impl_sink_notification_from_IUnknown(iface);
- ULONG refcount = InterlockedDecrement(¬ification->refcount);
-
- TRACE("%p, refcount %u.\n", iface, refcount);
-
- if (!refcount)
- {
- IMFClockStateSink_Release(notification->sink);
- heap_free(notification);
- }
-
- return refcount;
-}
-
-static const IUnknownVtbl sinknotificationvtbl =
-{
- sink_notification_QueryInterface,
- sink_notification_AddRef,
- sink_notification_Release,
-};
-
-static void clock_notify_async_sink(struct presentation_clock *clock, MFTIME system_time,
- struct clock_state_change_param param, enum clock_notification notification, IMFClockStateSink *sink)
-{
- struct sink_notification *object;
- IMFAsyncResult *result;
- HRESULT hr;
-
- object = heap_alloc(sizeof(*object));
- if (!object)
- return;
-
- object->IUnknown_iface.lpVtbl = &sinknotificationvtbl;
- object->refcount = 1;
- object->system_time = system_time;
- object->param = param;
- object->notification = notification;
- object->sink = sink;
- IMFClockStateSink_AddRef(object->sink);
-
- hr = MFCreateAsyncResult(&object->IUnknown_iface, &clock->sink_callback, NULL, &result);
- IUnknown_Release(&object->IUnknown_iface);
- if (SUCCEEDED(hr))
- {
- MFPutWorkItemEx(MFASYNC_CALLBACK_QUEUE_STANDARD, result);
- IMFAsyncResult_Release(result);
- }
-}
-
-static HRESULT WINAPI present_clock_QueryInterface(IMFPresentationClock *iface, REFIID riid, void **out)
-{
- struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
-
- TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out);
-
- if (IsEqualIID(riid, &IID_IMFPresentationClock) ||
- IsEqualIID(riid, &IID_IMFClock) ||
- IsEqualIID(riid, &IID_IUnknown))
- {
- *out = &clock->IMFPresentationClock_iface;
- }
- else if (IsEqualIID(riid, &IID_IMFRateControl))
- {
- *out = &clock->IMFRateControl_iface;
- }
- else if (IsEqualIID(riid, &IID_IMFTimer))
- {
- *out = &clock->IMFTimer_iface;
- }
- else if (IsEqualIID(riid, &IID_IMFShutdown))
- {
- *out = &clock->IMFShutdown_iface;
- }
- else
- {
- WARN("Unsupported %s.\n", debugstr_guid(riid));
- *out = NULL;
- return E_NOINTERFACE;
- }
-
- IUnknown_AddRef((IUnknown *)*out);
- return S_OK;
-}
-
-static ULONG WINAPI present_clock_AddRef(IMFPresentationClock *iface)
-{
- struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
- ULONG refcount = InterlockedIncrement(&clock->refcount);
-
- TRACE("%p, refcount %u.\n", iface, refcount);
-
- return refcount;
-}
-
-static ULONG WINAPI present_clock_Release(IMFPresentationClock *iface)
-{
- struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
- ULONG refcount = InterlockedDecrement(&clock->refcount);
- struct clock_timer *timer, *timer2;
- struct clock_sink *sink, *sink2;
-
- TRACE("%p, refcount %u.\n", iface, refcount);
-
- if (!refcount)
- {
- if (clock->time_source)
- IMFPresentationTimeSource_Release(clock->time_source);
- if (clock->time_source_sink)
- IMFClockStateSink_Release(clock->time_source_sink);
- LIST_FOR_EACH_ENTRY_SAFE(sink, sink2, &clock->sinks, struct clock_sink, entry)
- {
- list_remove(&sink->entry);
- IMFClockStateSink_Release(sink->state_sink);
- heap_free(sink);
- }
- LIST_FOR_EACH_ENTRY_SAFE(timer, timer2, &clock->timers, struct clock_timer, entry)
- {
- list_remove(&timer->entry);
- IUnknown_Release(&timer->IUnknown_iface);
- }
- DeleteCriticalSection(&clock->cs);
- heap_free(clock);
- }
-
- return refcount;
-}
-
-static HRESULT WINAPI present_clock_GetClockCharacteristics(IMFPresentationClock *iface, DWORD *flags)
-{
- struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
- HRESULT hr = MF_E_CLOCK_NO_TIME_SOURCE;
-
- TRACE("%p, %p.\n", iface, flags);
-
- EnterCriticalSection(&clock->cs);
- if (clock->time_source)
- hr = IMFPresentationTimeSource_GetClockCharacteristics(clock->time_source, flags);
- LeaveCriticalSection(&clock->cs);
-
- return hr;
-}
-
-static HRESULT WINAPI present_clock_GetCorrelatedTime(IMFPresentationClock *iface, DWORD reserved,
- LONGLONG *clock_time, MFTIME *system_time)
-{
- struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
- HRESULT hr = MF_E_CLOCK_NO_TIME_SOURCE;
-
- TRACE("%p, %#x, %p, %p.\n", iface, reserved, clock_time, system_time);
-
- EnterCriticalSection(&clock->cs);
- if (clock->time_source)
- hr = IMFPresentationTimeSource_GetCorrelatedTime(clock->time_source, reserved, clock_time, system_time);
- LeaveCriticalSection(&clock->cs);
-
- return hr;
-}
-
-static HRESULT WINAPI present_clock_GetContinuityKey(IMFPresentationClock *iface, DWORD *key)
-{
- TRACE("%p, %p.\n", iface, key);
-
- *key = 0;
-
- return S_OK;
-}
-
-static HRESULT WINAPI present_clock_GetState(IMFPresentationClock *iface, DWORD reserved, MFCLOCK_STATE *state)
-{
- struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
-
- TRACE("%p, %#x, %p.\n", iface, reserved, state);
-
- EnterCriticalSection(&clock->cs);
- *state = clock->state;
- LeaveCriticalSection(&clock->cs);
-
- return S_OK;
-}
-
-static HRESULT WINAPI present_clock_GetProperties(IMFPresentationClock *iface, MFCLOCK_PROPERTIES *props)
-{
- struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
- HRESULT hr = MF_E_CLOCK_NO_TIME_SOURCE;
-
- TRACE("%p, %p.\n", iface, props);
-
- EnterCriticalSection(&clock->cs);
- if (clock->time_source)
- hr = IMFPresentationTimeSource_GetProperties(clock->time_source, props);
- LeaveCriticalSection(&clock->cs);
-
- return hr;
-}
-
-static HRESULT WINAPI present_clock_SetTimeSource(IMFPresentationClock *iface,
- IMFPresentationTimeSource *time_source)
-{
- struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
- MFCLOCK_PROPERTIES props;
- IMFClock *source_clock;
- HRESULT hr;
-
- TRACE("%p, %p.\n", iface, time_source);
-
- EnterCriticalSection(&clock->cs);
-
- if (clock->time_source)
- IMFPresentationTimeSource_Release(clock->time_source);
- if (clock->time_source_sink)
- IMFClockStateSink_Release(clock->time_source_sink);
- clock->time_source = NULL;
- clock->time_source_sink = NULL;
-
- hr = IMFPresentationTimeSource_QueryInterface(time_source, &IID_IMFClockStateSink, (void **)&clock->time_source_sink);
- if (SUCCEEDED(hr))
- {
- clock->time_source = time_source;
- IMFPresentationTimeSource_AddRef(clock->time_source);
- }
-
- if (SUCCEEDED(IMFPresentationTimeSource_GetUnderlyingClock(time_source, &source_clock)))
- {
- if (SUCCEEDED(IMFClock_GetProperties(source_clock, &props)))
- clock->frequency = props.qwClockFrequency;
- IMFClock_Release(source_clock);
- }
-
- if (!clock->frequency)
- clock->frequency = MFCLOCK_FREQUENCY_HNS;
-
- LeaveCriticalSection(&clock->cs);
-
- return hr;
-}
-
-static HRESULT WINAPI present_clock_GetTimeSource(IMFPresentationClock *iface,
- IMFPresentationTimeSource **time_source)
-{
- struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
- HRESULT hr = S_OK;
-
- TRACE("%p, %p.\n", iface, time_source);
-
- if (!time_source)
- return E_INVALIDARG;
-
- EnterCriticalSection(&clock->cs);
- if (clock->time_source)
- {
- *time_source = clock->time_source;
- IMFPresentationTimeSource_AddRef(*time_source);
- }
- else
- hr = MF_E_CLOCK_NO_TIME_SOURCE;
- LeaveCriticalSection(&clock->cs);
-
- return hr;
-}
-
-static HRESULT WINAPI present_clock_GetTime(IMFPresentationClock *iface, MFTIME *time)
-{
- struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
- HRESULT hr = MF_E_CLOCK_NO_TIME_SOURCE;
- MFTIME systime;
-
- TRACE("%p, %p.\n", iface, time);
-
- if (!time)
- return E_POINTER;
-
- EnterCriticalSection(&clock->cs);
- if (clock->time_source)
- hr = IMFPresentationTimeSource_GetCorrelatedTime(clock->time_source, 0, time, &systime);
- LeaveCriticalSection(&clock->cs);
-
- return hr;
-}
-
-static HRESULT WINAPI present_clock_AddClockStateSink(IMFPresentationClock *iface, IMFClockStateSink *state_sink)
-{
- struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
- struct clock_sink *sink, *cur;
- HRESULT hr = S_OK;
-
- TRACE("%p, %p.\n", iface, state_sink);
-
- if (!state_sink)
- return E_INVALIDARG;
-
- sink = heap_alloc(sizeof(*sink));
- if (!sink)
- return E_OUTOFMEMORY;
-
- sink->state_sink = state_sink;
- IMFClockStateSink_AddRef(sink->state_sink);
-
- EnterCriticalSection(&clock->cs);
- LIST_FOR_EACH_ENTRY(cur, &clock->sinks, struct clock_sink, entry)
- {
- if (cur->state_sink == state_sink)
- {
- hr = E_INVALIDARG;
- break;
- }
- }
- if (SUCCEEDED(hr))
- {
- static const enum clock_notification notifications[MFCLOCK_STATE_PAUSED + 1] =
- {
- /* MFCLOCK_STATE_INVALID */ 0, /* Does not apply */
- /* MFCLOCK_STATE_RUNNING */ CLOCK_NOTIFY_START,
- /* MFCLOCK_STATE_STOPPED */ CLOCK_NOTIFY_STOP,
- /* MFCLOCK_STATE_PAUSED */ CLOCK_NOTIFY_PAUSE,
- };
- struct clock_state_change_param param;
-
- if (!clock->is_shut_down && clock->state != MFCLOCK_STATE_INVALID)
- {
- param.u.offset = clock->start_offset;
- clock_notify_async_sink(clock, MFGetSystemTime(), param, notifications[clock->state], sink->state_sink);
- }
-
- list_add_tail(&clock->sinks, &sink->entry);
- }
- LeaveCriticalSection(&clock->cs);
-
- if (FAILED(hr))
- {
- IMFClockStateSink_Release(sink->state_sink);
- heap_free(sink);
- }
-
- return hr;
-}
-
-static HRESULT WINAPI present_clock_RemoveClockStateSink(IMFPresentationClock *iface,
- IMFClockStateSink *state_sink)
-{
- struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
- struct clock_sink *sink;
-
- TRACE("%p, %p.\n", iface, state_sink);
-
- if (!state_sink)
- return E_INVALIDARG;
-
- EnterCriticalSection(&clock->cs);
- LIST_FOR_EACH_ENTRY(sink, &clock->sinks, struct clock_sink, entry)
- {
- if (sink->state_sink == state_sink)
- {
- IMFClockStateSink_Release(sink->state_sink);
- list_remove(&sink->entry);
- heap_free(sink);
- break;
- }
- }
- LeaveCriticalSection(&clock->cs);
-
- return S_OK;
-}
-
-static HRESULT clock_call_state_change(MFTIME system_time, struct clock_state_change_param param,
- enum clock_notification notification, IMFClockStateSink *sink)
-{
- HRESULT hr = S_OK;
-
- switch (notification)
- {
- case CLOCK_NOTIFY_START:
- hr = IMFClockStateSink_OnClockStart(sink, system_time, param.u.offset);
- break;
- case CLOCK_NOTIFY_STOP:
- hr = IMFClockStateSink_OnClockStop(sink, system_time);
- break;
- case CLOCK_NOTIFY_PAUSE:
- hr = IMFClockStateSink_OnClockPause(sink, system_time);
- break;
- case CLOCK_NOTIFY_RESTART:
- hr = IMFClockStateSink_OnClockRestart(sink, system_time);
- break;
- case CLOCK_NOTIFY_SET_RATE:
- /* System time source does not allow 0.0 rate, presentation clock allows it without raising errors. */
- IMFClockStateSink_OnClockSetRate(sink, system_time, param.u.rate);
- break;
- default:
- ;
- }
-
- return hr;
-}
-
-static HRESULT clock_change_state(struct presentation_clock *clock, enum clock_command command,
- struct clock_state_change_param param)
-{
- static const BYTE state_change_is_allowed[MFCLOCK_STATE_PAUSED+1][CLOCK_CMD_MAX] =
- { /* S S* P, R */
- /* INVALID */ { 1, 1, 1, 1 },
- /* RUNNING */ { 1, 1, 1, 1 },
- /* STOPPED */ { 1, 1, 0, 1 },
- /* PAUSED */ { 1, 1, 0, 1 },
- };
- static const MFCLOCK_STATE states[CLOCK_CMD_MAX] =
- {
- /* CLOCK_CMD_START */ MFCLOCK_STATE_RUNNING,
- /* CLOCK_CMD_STOP */ MFCLOCK_STATE_STOPPED,
- /* CLOCK_CMD_PAUSE */ MFCLOCK_STATE_PAUSED,
- /* CLOCK_CMD_SET_RATE */ 0, /* Unused */
- };
- static const enum clock_notification notifications[CLOCK_CMD_MAX] =
- {
- /* CLOCK_CMD_START */ CLOCK_NOTIFY_START,
- /* CLOCK_CMD_STOP */ CLOCK_NOTIFY_STOP,
- /* CLOCK_CMD_PAUSE */ CLOCK_NOTIFY_PAUSE,
- /* CLOCK_CMD_SET_RATE */ CLOCK_NOTIFY_SET_RATE,
- };
- enum clock_notification notification;
- struct clock_sink *sink;
- MFCLOCK_STATE old_state;
- IMFAsyncResult *result;
- MFTIME system_time;
- HRESULT hr;
-
- if (!clock->time_source)
- return MF_E_CLOCK_NO_TIME_SOURCE;
-
- if (command != CLOCK_CMD_SET_RATE && clock->state == states[command] && clock->state != MFCLOCK_STATE_RUNNING)
- return MF_E_CLOCK_STATE_ALREADY_SET;
-
- if (!state_change_is_allowed[clock->state][command])
- return MF_E_INVALIDREQUEST;
-
- system_time = MFGetSystemTime();
-
- if (command == CLOCK_CMD_START && clock->state == MFCLOCK_STATE_PAUSED &&
- param.u.offset == PRESENTATION_CURRENT_POSITION)
- {
- notification = CLOCK_NOTIFY_RESTART;
- }
- else
- notification = notifications[command];
-
- if (FAILED(hr = clock_call_state_change(system_time, param, notification, clock->time_source_sink)))
- return hr;
-
- old_state = clock->state;
- if (command != CLOCK_CMD_SET_RATE)
- clock->state = states[command];
-
- /* Dump all pending timer requests immediately on start; otherwise try to cancel scheduled items when
- transitioning from running state. */
- if ((clock->state == MFCLOCK_STATE_RUNNING) ^ (old_state == MFCLOCK_STATE_RUNNING))
- {
- struct clock_timer *timer, *timer2;
-
- if (clock->state == MFCLOCK_STATE_RUNNING)
- {
- LIST_FOR_EACH_ENTRY_SAFE(timer, timer2, &clock->timers, struct clock_timer, entry)
- {
- list_remove(&timer->entry);
- hr = MFCreateAsyncResult(&timer->IUnknown_iface, &clock->timer_callback, NULL, &result);
- IUnknown_Release(&timer->IUnknown_iface);
- if (SUCCEEDED(hr))
- {
- MFPutWorkItemEx(MFASYNC_CALLBACK_QUEUE_TIMER, result);
- IMFAsyncResult_Release(result);
- }
- }
- }
- else
- {
- LIST_FOR_EACH_ENTRY(timer, &clock->timers, struct clock_timer, entry)
- {
- if (timer->key)
- {
- MFCancelWorkItem(timer->key);
- timer->key = 0;
- }
- }
- }
- }
-
- LIST_FOR_EACH_ENTRY(sink, &clock->sinks, struct clock_sink, entry)
- {
- clock_notify_async_sink(clock, system_time, param, notification, sink->state_sink);
- }
-
- return S_OK;
-}
-
-static HRESULT WINAPI present_clock_Start(IMFPresentationClock *iface, LONGLONG start_offset)
-{
- struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
- struct clock_state_change_param param = {{0}};
- HRESULT hr;
-
- TRACE("%p, %s.\n", iface, debugstr_time(start_offset));
-
- EnterCriticalSection(&clock->cs);
- clock->start_offset = param.u.offset = start_offset;
- hr = clock_change_state(clock, CLOCK_CMD_START, param);
- LeaveCriticalSection(&clock->cs);
-
- return hr;
-}
-
-static HRESULT WINAPI present_clock_Stop(IMFPresentationClock *iface)
-{
- struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
- struct clock_state_change_param param = {{0}};
- HRESULT hr;
-
- TRACE("%p.\n", iface);
-
- EnterCriticalSection(&clock->cs);
- hr = clock_change_state(clock, CLOCK_CMD_STOP, param);
- LeaveCriticalSection(&clock->cs);
-
- return hr;
-}
-
-static HRESULT WINAPI present_clock_Pause(IMFPresentationClock *iface)
-{
- struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
- struct clock_state_change_param param = {{0}};
- HRESULT hr;
-
- TRACE("%p.\n", iface);
-
- EnterCriticalSection(&clock->cs);
- hr = clock_change_state(clock, CLOCK_CMD_PAUSE, param);
- LeaveCriticalSection(&clock->cs);
-
- return hr;
-}
-
-static const IMFPresentationClockVtbl presentationclockvtbl =
-{
- present_clock_QueryInterface,
- present_clock_AddRef,
- present_clock_Release,
- present_clock_GetClockCharacteristics,
- present_clock_GetCorrelatedTime,
- present_clock_GetContinuityKey,
- present_clock_GetState,
- present_clock_GetProperties,
- present_clock_SetTimeSource,
- present_clock_GetTimeSource,
- present_clock_GetTime,
- present_clock_AddClockStateSink,
- present_clock_RemoveClockStateSink,
- present_clock_Start,
- present_clock_Stop,
- present_clock_Pause,
-};
-
-static HRESULT WINAPI present_clock_rate_control_QueryInterface(IMFRateControl *iface, REFIID riid, void **out)
-{
- struct presentation_clock *clock = impl_from_IMFRateControl(iface);
- return IMFPresentationClock_QueryInterface(&clock->IMFPresentationClock_iface, riid, out);
-}
-
-static ULONG WINAPI present_clock_rate_control_AddRef(IMFRateControl *iface)
-{
- struct presentation_clock *clock = impl_from_IMFRateControl(iface);
- return IMFPresentationClock_AddRef(&clock->IMFPresentationClock_iface);
-}
-
-static ULONG WINAPI present_clock_rate_control_Release(IMFRateControl *iface)
-{
- struct presentation_clock *clock = impl_from_IMFRateControl(iface);
- return IMFPresentationClock_Release(&clock->IMFPresentationClock_iface);
-}
-
-static HRESULT WINAPI present_clock_rate_SetRate(IMFRateControl *iface, BOOL thin, float rate)
-{
- struct presentation_clock *clock = impl_from_IMFRateControl(iface);
- struct clock_state_change_param param;
- HRESULT hr;
-
- TRACE("%p, %d, %f.\n", iface, thin, rate);
-
- if (thin)
- return MF_E_THINNING_UNSUPPORTED;
-
- EnterCriticalSection(&clock->cs);
- param.u.rate = rate;
- if (SUCCEEDED(hr = clock_change_state(clock, CLOCK_CMD_SET_RATE, param)))
- clock->rate = rate;
- LeaveCriticalSection(&clock->cs);
-
- return hr;
-}
-
-static HRESULT WINAPI present_clock_rate_GetRate(IMFRateControl *iface, BOOL *thin, float *rate)
-{
- struct presentation_clock *clock = impl_from_IMFRateControl(iface);
-
- TRACE("%p, %p, %p.\n", iface, thin, rate);
-
- if (!rate)
- return E_INVALIDARG;
-
- if (thin)
- *thin = FALSE;
-
- EnterCriticalSection(&clock->cs);
- *rate = clock->rate;
- LeaveCriticalSection(&clock->cs);
-
- return S_OK;
-}
-
-static const IMFRateControlVtbl presentclockratecontrolvtbl =
-{
- present_clock_rate_control_QueryInterface,
- present_clock_rate_control_AddRef,
- present_clock_rate_control_Release,
- present_clock_rate_SetRate,
- present_clock_rate_GetRate,
-};
-
-static HRESULT WINAPI present_clock_timer_QueryInterface(IMFTimer *iface, REFIID riid, void **out)
-{
- struct presentation_clock *clock = impl_from_IMFTimer(iface);
- return IMFPresentationClock_QueryInterface(&clock->IMFPresentationClock_iface, riid, out);
-}
-
-static ULONG WINAPI present_clock_timer_AddRef(IMFTimer *iface)
-{
- struct presentation_clock *clock = impl_from_IMFTimer(iface);
- return IMFPresentationClock_AddRef(&clock->IMFPresentationClock_iface);
-}
-
-static ULONG WINAPI present_clock_timer_Release(IMFTimer *iface)
-{
- struct presentation_clock *clock = impl_from_IMFTimer(iface);
- return IMFPresentationClock_Release(&clock->IMFPresentationClock_iface);
-}
-
-static HRESULT present_clock_schedule_timer(struct presentation_clock *clock, DWORD flags, LONGLONG time,
- struct clock_timer *timer)
-{
- IMFAsyncResult *result;
- MFTIME systime, clocktime;
- LONGLONG frequency;
- HRESULT hr;
-
- if (!(flags & MFTIMER_RELATIVE))
- {
- if (FAILED(hr = IMFPresentationTimeSource_GetCorrelatedTime(clock->time_source, 0, &clocktime, &systime)))
- {
- WARN("Failed to get clock time, hr %#x.\n", hr);
- return hr;
- }
- time -= clocktime;
- }
-
- frequency = clock->frequency / 1000;
- time /= frequency;
-
- /* Scheduled item is using clock instance callback, with timer instance as an object. Clock callback will
- call user callback and cleanup timer list. */
-
- if (FAILED(hr = MFCreateAsyncResult(&timer->IUnknown_iface, &clock->timer_callback, NULL, &result)))
- return hr;
-
- hr = MFScheduleWorkItemEx(result, -time, &timer->key);
- IMFAsyncResult_Release(result);
-
- return hr;
-}
-
-static HRESULT WINAPI clock_timer_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
-{
- if (IsEqualIID(riid, &IID_IUnknown))
- {
- *obj = iface;
- IUnknown_AddRef(iface);
- return S_OK;
- }
-
- *obj = NULL;
- return E_NOINTERFACE;
-}
-
-static ULONG WINAPI clock_timer_AddRef(IUnknown *iface)
-{
- struct clock_timer *timer = impl_clock_timer_from_IUnknown(iface);
- return InterlockedIncrement(&timer->refcount);
-}
-
-static ULONG WINAPI clock_timer_Release(IUnknown *iface)
-{
- struct clock_timer *timer = impl_clock_timer_from_IUnknown(iface);
- ULONG refcount = InterlockedDecrement(&timer->refcount);
-
- if (!refcount)
- {
- IMFAsyncResult_Release(timer->result);
- IMFAsyncCallback_Release(timer->callback);
- heap_free(timer);
- }
-
- return refcount;
-}
-
-static const IUnknownVtbl clock_timer_vtbl =
-{
- clock_timer_QueryInterface,
- clock_timer_AddRef,
- clock_timer_Release,
-};
-
-static HRESULT WINAPI present_clock_timer_SetTimer(IMFTimer *iface, DWORD flags, LONGLONG time,
- IMFAsyncCallback *callback, IUnknown *state, IUnknown **cancel_key)
-{
- struct presentation_clock *clock = impl_from_IMFTimer(iface);
- struct clock_timer *clock_timer;
- HRESULT hr;
-
- TRACE("%p, %#x, %s, %p, %p, %p.\n", iface, flags, debugstr_time(time), callback, state, cancel_key);
-
- if (!(clock_timer = heap_alloc_zero(sizeof(*clock_timer))))
- return E_OUTOFMEMORY;
-
- if (FAILED(hr = MFCreateAsyncResult(NULL, NULL, state, &clock_timer->result)))
- {
- heap_free(clock_timer);
- return hr;
- }
-
- clock_timer->IUnknown_iface.lpVtbl = &clock_timer_vtbl;
- clock_timer->refcount = 1;
- clock_timer->callback = callback;
- IMFAsyncCallback_AddRef(clock_timer->callback);
-
- EnterCriticalSection(&clock->cs);
-
- if (clock->state == MFCLOCK_STATE_RUNNING)
- hr = present_clock_schedule_timer(clock, flags, time, clock_timer);
- else if (clock->state == MFCLOCK_STATE_STOPPED)
- hr = MF_S_CLOCK_STOPPED;
-
- if (SUCCEEDED(hr))
- {
- list_add_tail(&clock->timers, &clock_timer->entry);
- if (cancel_key)
- {
- *cancel_key = &clock_timer->IUnknown_iface;
- IUnknown_AddRef(*cancel_key);
- }
- }
-
- LeaveCriticalSection(&clock->cs);
-
- if (FAILED(hr))
- IUnknown_Release(&clock_timer->IUnknown_iface);
-
- return hr;
-}
-
-static HRESULT WINAPI present_clock_timer_CancelTimer(IMFTimer *iface, IUnknown *cancel_key)
-{
- struct presentation_clock *clock = impl_from_IMFTimer(iface);
- struct clock_timer *timer;
-
- TRACE("%p, %p.\n", iface, cancel_key);
-
- EnterCriticalSection(&clock->cs);
-
- LIST_FOR_EACH_ENTRY(timer, &clock->timers, struct clock_timer, entry)
- {
- if (&timer->IUnknown_iface == cancel_key)
- {
- list_remove(&timer->entry);
- if (timer->key)
- {
- MFCancelWorkItem(timer->key);
- timer->key = 0;
- }
- IUnknown_Release(&timer->IUnknown_iface);
- break;
- }
- }
-
- LeaveCriticalSection(&clock->cs);
-
- return S_OK;
-}
-
-static const IMFTimerVtbl presentclocktimervtbl =
-{
- present_clock_timer_QueryInterface,
- present_clock_timer_AddRef,
- present_clock_timer_Release,
- present_clock_timer_SetTimer,
- present_clock_timer_CancelTimer,
-};
-
-static HRESULT WINAPI present_clock_shutdown_QueryInterface(IMFShutdown *iface, REFIID riid, void **out)
-{
- struct presentation_clock *clock = impl_from_IMFShutdown(iface);
- return IMFPresentationClock_QueryInterface(&clock->IMFPresentationClock_iface, riid, out);
-}
-
-static ULONG WINAPI present_clock_shutdown_AddRef(IMFShutdown *iface)
-{
- struct presentation_clock *clock = impl_from_IMFShutdown(iface);
- return IMFPresentationClock_AddRef(&clock->IMFPresentationClock_iface);
-}
-
-static ULONG WINAPI present_clock_shutdown_Release(IMFShutdown *iface)
-{
- struct presentation_clock *clock = impl_from_IMFShutdown(iface);
- return IMFPresentationClock_Release(&clock->IMFPresentationClock_iface);
-}
-
-static HRESULT WINAPI present_clock_shutdown_Shutdown(IMFShutdown *iface)
-{
- struct presentation_clock *clock = impl_from_IMFShutdown(iface);
-
- TRACE("%p.\n", iface);
-
- EnterCriticalSection(&clock->cs);
- clock->is_shut_down = TRUE;
- LeaveCriticalSection(&clock->cs);
-
- return S_OK;
-}
-
-static HRESULT WINAPI present_clock_shutdown_GetShutdownStatus(IMFShutdown *iface, MFSHUTDOWN_STATUS *status)
-{
- struct presentation_clock *clock = impl_from_IMFShutdown(iface);
- HRESULT hr = S_OK;
-
- TRACE("%p, %p.\n", iface, status);
-
- if (!status)
- return E_INVALIDARG;
-
- EnterCriticalSection(&clock->cs);
- if (clock->is_shut_down)
- *status = MFSHUTDOWN_COMPLETED;
- else
- hr = MF_E_INVALIDREQUEST;
- LeaveCriticalSection(&clock->cs);
-
- return hr;
-}
-
-static const IMFShutdownVtbl presentclockshutdownvtbl =
-{
- present_clock_shutdown_QueryInterface,
- present_clock_shutdown_AddRef,
- present_clock_shutdown_Release,
- present_clock_shutdown_Shutdown,
- present_clock_shutdown_GetShutdownStatus,
-};
-
-static HRESULT WINAPI present_clock_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **out)
-{
- if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
- IsEqualIID(riid, &IID_IUnknown))
- {
- *out = iface;
- IMFAsyncCallback_AddRef(iface);
- return S_OK;
- }
-
- WARN("Unsupported %s.\n", wine_dbgstr_guid(riid));
- *out = NULL;
- return E_NOINTERFACE;
-}
-
-static ULONG WINAPI present_clock_sink_callback_AddRef(IMFAsyncCallback *iface)
-{
- struct presentation_clock *clock = impl_from_sink_callback_IMFAsyncCallback(iface);
- return IMFPresentationClock_AddRef(&clock->IMFPresentationClock_iface);
-}
-
-static ULONG WINAPI present_clock_sink_callback_Release(IMFAsyncCallback *iface)
-{
- struct presentation_clock *clock = impl_from_sink_callback_IMFAsyncCallback(iface);
- return IMFPresentationClock_Release(&clock->IMFPresentationClock_iface);
-}
-
-static HRESULT WINAPI present_clock_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue)
-{
- return E_NOTIMPL;
-}
-
-static HRESULT WINAPI present_clock_sink_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
-{
- struct sink_notification *data;
- IUnknown *object;
- HRESULT hr;
-
- if (FAILED(hr = IMFAsyncResult_GetObject(result, &object)))
- return hr;
-
- data = impl_sink_notification_from_IUnknown(object);
-
- clock_call_state_change(data->system_time, data->param, data->notification, data->sink);
-
- IUnknown_Release(object);
-
- return S_OK;
-}
-
-static const IMFAsyncCallbackVtbl presentclocksinkcallbackvtbl =
-{
- present_clock_callback_QueryInterface,
- present_clock_sink_callback_AddRef,
- present_clock_sink_callback_Release,
- present_clock_callback_GetParameters,
- present_clock_sink_callback_Invoke,
-};
-
-static ULONG WINAPI present_clock_timer_callback_AddRef(IMFAsyncCallback *iface)
-{
- struct presentation_clock *clock = impl_from_timer_callback_IMFAsyncCallback(iface);
- return IMFPresentationClock_AddRef(&clock->IMFPresentationClock_iface);
-}
-
-static ULONG WINAPI present_clock_timer_callback_Release(IMFAsyncCallback *iface)
-{
- struct presentation_clock *clock = impl_from_timer_callback_IMFAsyncCallback(iface);
- return IMFPresentationClock_Release(&clock->IMFPresentationClock_iface);
-}
-
-static HRESULT WINAPI present_clock_timer_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
-{
- struct presentation_clock *clock = impl_from_timer_callback_IMFAsyncCallback(iface);
- struct clock_timer *timer;
- IUnknown *object;
- HRESULT hr;
-
- if (FAILED(hr = IMFAsyncResult_GetObject(result, &object)))
- return hr;
-
- timer = impl_clock_timer_from_IUnknown(object);
-
- EnterCriticalSection(&clock->cs);
- list_remove(&timer->entry);
- IUnknown_Release(&timer->IUnknown_iface);
- LeaveCriticalSection(&clock->cs);
-
- IMFAsyncCallback_Invoke(timer->callback, timer->result);
-
- IUnknown_Release(object);
-
- return S_OK;
-}
-
-static const IMFAsyncCallbackVtbl presentclocktimercallbackvtbl =
-{
- present_clock_callback_QueryInterface,
- present_clock_timer_callback_AddRef,
- present_clock_timer_callback_Release,
- present_clock_callback_GetParameters,
- present_clock_timer_callback_Invoke,
-};
-
-/***********************************************************************
- * MFCreatePresentationClock (mf.@)
- */
-HRESULT WINAPI MFCreatePresentationClock(IMFPresentationClock **clock)
-{
- struct presentation_clock *object;
-
- TRACE("%p.\n", clock);
-
- object = heap_alloc_zero(sizeof(*object));
- if (!object)
- return E_OUTOFMEMORY;
-
- object->IMFPresentationClock_iface.lpVtbl = &presentationclockvtbl;
- object->IMFRateControl_iface.lpVtbl = &presentclockratecontrolvtbl;
- object->IMFTimer_iface.lpVtbl = &presentclocktimervtbl;
- object->IMFShutdown_iface.lpVtbl = &presentclockshutdownvtbl;
- object->sink_callback.lpVtbl = &presentclocksinkcallbackvtbl;
- object->timer_callback.lpVtbl = &presentclocktimercallbackvtbl;
- object->refcount = 1;
- list_init(&object->sinks);
- list_init(&object->timers);
- object->rate = 1.0f;
- InitializeCriticalSection(&object->cs);
-
- *clock = &object->IMFPresentationClock_iface;
-
- return S_OK;
-}
-
static HRESULT WINAPI standard_quality_manager_QueryInterface(IMFQualityManager *iface, REFIID riid, void **out)
{
struct quality_manager *manager = impl_from_IMFQualityManager(iface);
--
2.30.2
1
3
15 Jun '21
Signed-off-by: Ziqing Hui <zhui(a)codeweavers.com>
---
v2:
* Merge 2 patches.
* Get rid of shift operation.
* Replace copy_texture with get_texuture_readback.
* Use winetest_push_context rather than "Test %u:".
* Release created texture.
* Only use D3D10_CPU_ACCESS_READ for readback.
v3: Fix test crash.
dlls/d3dx10_43/tests/d3dx10.c | 458 +++++++++++++++++++++++++++++-----
1 file changed, 394 insertions(+), 64 deletions(-)
2
1
Signed-off-by: Ziqing Hui <zhui(a)codeweavers.com>
---
v2: This is a new patch in patch set.
v3: No changes.
dlls/d3dx10_43/tests/d3dx10.c | 205 ++++++++++++++++++----------------
1 file changed, 108 insertions(+), 97 deletions(-)
2
1
15 Jun '21
Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com>
---
dlls/winegstreamer/media_source.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c
index 3c87bbb2146..9c554c7c415 100644
--- a/dlls/winegstreamer/media_source.c
+++ b/dlls/winegstreamer/media_source.c
@@ -170,6 +170,11 @@ static ULONG WINAPI source_async_command_Release(IUnknown *iface)
{
if (command->op == SOURCE_ASYNC_START)
PropVariantClear(&command->u.start.position);
+ else if (command->op == SOURCE_ASYNC_REQUEST_SAMPLE)
+ {
+ if (command->u.request_sample.token)
+ IUnknown_Release(command->u.request_sample.token);
+ }
free(command);
}
@@ -467,8 +472,6 @@ static void wait_on_sample(struct media_stream *stream, IUnknown *token)
case WG_PARSER_EVENT_EOS:
stream->eos = TRUE;
- if (token)
- IUnknown_Release(token);
IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, MEEndOfStream, &GUID_NULL, S_OK, &empty_var);
dispatch_end_of_presentation(stream->parent_source);
return;
--
2.30.2
1
0
[PATCH v4] iphlpapi: Fix the field 'AdapterName' of IP_ADAPTER_INFO returned by GetAdaptersInfo.
by Yeshun Ye 15 Jun '21
by Yeshun Ye 15 Jun '21
15 Jun '21
Signed-off-by: Yeshun Ye <yeyeshun(a)uniontech.com>
---
dlls/iphlpapi/iphlpapi_main.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/dlls/iphlpapi/iphlpapi_main.c b/dlls/iphlpapi/iphlpapi_main.c
index 09414d26dde..21edd9ee128 100644
--- a/dlls/iphlpapi/iphlpapi_main.c
+++ b/dlls/iphlpapi/iphlpapi_main.c
@@ -706,9 +706,16 @@ DWORD WINAPI GetAdaptersInfo(PIP_ADAPTER_INFO pAdapterInfo, PULONG pOutBufLen)
DWORD i;
PIP_ADDR_STRING currentIPAddr = &ptr->IpAddressList;
BOOL firstIPAddr = TRUE;
+ NET_LUID luid;
+ GUID guid;
/* on Win98 this is left empty, but whatever */
- getInterfaceNameByIndex(table->indexes[ndx], ptr->AdapterName);
+ ConvertInterfaceIndexToLuid(table->indexes[ndx], &luid);
+ ConvertInterfaceLuidToGuid(&luid, &guid);
+ sprintf(ptr->AdapterName, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
+ guid.Data1, guid.Data2, guid.Data3, guid.Data4[0], guid.Data4[1],
+ guid.Data4[2], guid.Data4[3], guid.Data4[4], guid.Data4[5],
+ guid.Data4[6], guid.Data4[7]);
getInterfaceNameByIndex(table->indexes[ndx], ptr->Description);
ptr->AddressLength = sizeof(ptr->Address);
getInterfacePhysicalByIndex(table->indexes[ndx],
--
2.20.1
2
1
Signed-off-by: Zebediah Figura <z.figura12(a)gmail.com>
---
dlls/ntdll/unix/socket.c | 6 ++++++
include/wine/afd.h | 7 +++++++
server/sock.c | 22 ++++++++++++++++++++++
3 files changed, 35 insertions(+)
diff --git a/dlls/ntdll/unix/socket.c b/dlls/ntdll/unix/socket.c
index 088f29f85ff..3b8206474f0 100644
--- a/dlls/ntdll/unix/socket.c
+++ b/dlls/ntdll/unix/socket.c
@@ -1181,6 +1181,12 @@ NTSTATUS sock_ioctl( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc
break;
}
+ case IOCTL_AFD_GET_EVENTS:
+ if (in_size) FIXME( "unexpected input size %u\n", in_size );
+
+ status = STATUS_BAD_DEVICE_TYPE;
+ break;
+
case IOCTL_AFD_RECV:
{
const struct afd_recv_params *params = in_buffer;
diff --git a/include/wine/afd.h b/include/wine/afd.h
index 2eb3e6f12a9..46d242c7582 100644
--- a/include/wine/afd.h
+++ b/include/wine/afd.h
@@ -36,6 +36,7 @@
#define IOCTL_AFD_RECV CTL_CODE(FILE_DEVICE_BEEP, 0x805, METHOD_NEITHER, FILE_ANY_ACCESS)
#define IOCTL_AFD_POLL CTL_CODE(FILE_DEVICE_BEEP, 0x809, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_AFD_EVENT_SELECT CTL_CODE(FILE_DEVICE_BEEP, 0x821, METHOD_NEITHER, FILE_ANY_ACCESS)
+#define IOCTL_AFD_GET_EVENTS CTL_CODE(FILE_DEVICE_BEEP, 0x822, METHOD_NEITHER, FILE_ANY_ACCESS)
enum afd_poll_bit
{
@@ -125,6 +126,12 @@ struct afd_event_select_params_32
int mask;
};
+struct afd_get_events_params
+{
+ int flags;
+ NTSTATUS status[13];
+};
+
#define IOCTL_AFD_WINE_CREATE CTL_CODE(FILE_DEVICE_NETWORK, 200, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_AFD_WINE_ACCEPT CTL_CODE(FILE_DEVICE_NETWORK, 201, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_AFD_WINE_ACCEPT_INTO CTL_CODE(FILE_DEVICE_NETWORK, 202, METHOD_BUFFERED, FILE_ANY_ACCESS)
diff --git a/server/sock.c b/server/sock.c
index 3556ee21aa3..1d992d8f9e4 100644
--- a/server/sock.c
+++ b/server/sock.c
@@ -2011,6 +2011,28 @@ static int sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async )
}
return 1;
+ case IOCTL_AFD_GET_EVENTS:
+ {
+ struct afd_get_events_params params = {0};
+ unsigned int i;
+
+ if (get_reply_max_size() < sizeof(params))
+ {
+ set_error( STATUS_INVALID_PARAMETER );
+ return 0;
+ }
+
+ params.flags = sock->pending_events & sock->mask;
+ for (i = 0; i < ARRAY_SIZE( params.status ); ++i)
+ params.status[i] = sock_get_ntstatus( sock->errors[i] );
+
+ sock->pending_events = 0;
+ sock_reselect( sock );
+
+ set_reply_data( ¶ms, sizeof(params) );
+ return 0;
+ }
+
case IOCTL_AFD_EVENT_SELECT:
{
struct event *event = NULL;
--
2.30.2
2
7
COLORONCOLOR(STRETCH_DELETESCANS) was used in place of HALFTONE. COLORONCOLOR mode may delete rows
of pixels without trying to preserve information so it will cause Wine to render poorly when the
destination rectangle is small.
According to tests, HALFTONE mode uses box filter when doing integer downscaling and nearest
neighbor interpolation when doing upscaling in both horizontally and vertically. In other cases,
HALFTONE mode uses a lanczos3 like algorithm to interpolate pixels. There are also other heuristics
involved. For example, shrinking a 2x2 image to 1x1 may not use box filter depending on image data.
Since this algorithm is undocumented, it's difficult to reverse engineer the original algorithm and
produce identical results. Instead, this patch uses a naive implementation of bilinear interpolation
to implement HALFTONE mode and it produces good quality images.
For 8-bit and lower color depth images, nulldrv_StretchBlt should resize the images first and then
converts color depth.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=46375
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
v3: Supersede 206858. Mark some user32 cursoricon tests as todo because they end up using HALFTONE mode
and compare the exact data values. As said in the commit message, this patch doesn't produce identical
results. Previously the cursoricon tests can succeed are coincidences. They will fail if source image
changes.
dlls/gdi32/dibdrv/bitblt.c | 7 +
dlls/gdi32/dibdrv/dibdrv.h | 2 +
dlls/gdi32/dibdrv/primitives.c | 629 ++++++++++++++++++++++++++++++++-
dlls/user32/tests/cursoricon.c | 18 +-
4 files changed, 640 insertions(+), 16 deletions(-)
diff --git a/dlls/gdi32/dibdrv/bitblt.c b/dlls/gdi32/dibdrv/bitblt.c
index d2f59965b02..9b46ad2916f 100644
--- a/dlls/gdi32/dibdrv/bitblt.c
+++ b/dlls/gdi32/dibdrv/bitblt.c
@@ -1216,6 +1216,12 @@ DWORD stretch_bitmapinfo( const BITMAPINFO *src_info, void *src_bits, struct bit
init_dib_info_from_bitmapinfo( &src_dib, src_info, src_bits );
init_dib_info_from_bitmapinfo( &dst_dib, dst_info, dst_bits );
+ if (mode == HALFTONE)
+ {
+ dst_dib.funcs->halftone( &dst_dib, dst, &src_dib, src );
+ goto done;
+ }
+
/* v */
ret = calc_1d_stretch_params( dst->y, dst->height, dst->visrect.top, dst->visrect.bottom,
src->y, src->height, src->visrect.top, src->visrect.bottom,
@@ -1300,6 +1306,7 @@ DWORD stretch_bitmapinfo( const BITMAPINFO *src_info, void *src_bits, struct bit
}
}
+done:
/* update coordinates, the destination rectangle is always stored at 0,0 */
*src = *dst;
src->x -= src->visrect.left;
diff --git a/dlls/gdi32/dibdrv/dibdrv.h b/dlls/gdi32/dibdrv/dibdrv.h
index d3a35b96c75..0492c0bd51e 100644
--- a/dlls/gdi32/dibdrv/dibdrv.h
+++ b/dlls/gdi32/dibdrv/dibdrv.h
@@ -211,6 +211,8 @@ typedef struct primitive_funcs
void (* shrink_row)(const dib_info *dst_dib, const POINT *dst_start,
const dib_info *src_dib, const POINT *src_start,
const struct stretch_params *params, int mode, BOOL keep_dst);
+ void (* halftone)(const dib_info *dst_dib, const struct bitblt_coords *dst,
+ const dib_info *src_dib, const struct bitblt_coords *src);
} primitive_funcs;
extern const primitive_funcs funcs_8888 DECLSPEC_HIDDEN;
diff --git a/dlls/gdi32/dibdrv/primitives.c b/dlls/gdi32/dibdrv/primitives.c
index e4b18a6656d..5eca124b918 100644
--- a/dlls/gdi32/dibdrv/primitives.c
+++ b/dlls/gdi32/dibdrv/primitives.c
@@ -7430,6 +7430,608 @@ static void shrink_row_null(const dib_info *dst_dib, const POINT *dst_start,
return;
}
+static float clampf( float value, float min, float max )
+{
+ return max( min, min( value, max ) );
+}
+
+static int clamp( int value, int min, int max )
+{
+ return max( min, min( value, max ) );
+}
+
+static BYTE linear_interpolate( BYTE start, BYTE end, float delta )
+{
+ return start + (end - start) * delta + 0.5f;
+}
+
+static BYTE bilinear_interpolate( BYTE c00, BYTE c01, BYTE c10, BYTE c11, float dx, float dy )
+{
+ return linear_interpolate( linear_interpolate( c00, c01, dx ),
+ linear_interpolate( c10, c11, dx ), dy );
+}
+
+static void calc_halftone_params( const struct bitblt_coords *dst, const struct bitblt_coords *src,
+ RECT *dst_rect, RECT *src_rect, int *src_start_x,
+ int *src_start_y, float *src_inc_x, float *src_inc_y )
+{
+ int src_width, src_height, dst_width, dst_height;
+ BOOL mirrored_x, mirrored_y;
+
+ get_bounding_rect( src_rect, src->x, src->y, src->width, src->height );
+ get_bounding_rect( dst_rect, dst->x, dst->y, dst->width, dst->height );
+ intersect_rect( src_rect, &src->visrect, src_rect );
+ intersect_rect( dst_rect, &dst->visrect, dst_rect );
+ offset_rect( dst_rect, -dst_rect->left, -dst_rect->top );
+
+ src_width = src_rect->right - src_rect->left;
+ src_height = src_rect->bottom - src_rect->top;
+ dst_width = dst_rect->right - dst_rect->left;
+ dst_height = dst_rect->bottom - dst_rect->top;
+
+ mirrored_x = (dst->width < 0) != (src->width < 0);
+ mirrored_y = (dst->height < 0) != (src->height < 0);
+ *src_start_x = mirrored_x ? src_rect->right - 1 : src_rect->left;
+ *src_start_y = mirrored_y ? src_rect->bottom - 1 : src_rect->top;
+ *src_inc_x = mirrored_x ? -(float)src_width / dst_width : (float)src_width / dst_width;
+ *src_inc_y = mirrored_y ? -(float)src_height / dst_height : (float)src_height / dst_height;
+}
+
+static void halftone_888( const dib_info *dst_dib, const struct bitblt_coords *dst,
+ const dib_info *src_dib, const struct bitblt_coords *src )
+{
+ int src_start_x, src_start_y, src_ptr_dy, dst_x, dst_y, x0, x1, y0, y1;
+ DWORD *dst_ptr, *src_ptr, *c00_ptr, *c01_ptr, *c10_ptr, *c11_ptr;
+ float src_inc_x, src_inc_y, float_x, float_y, dx, dy;
+ BYTE c00_r, c01_r, c10_r, c11_r;
+ BYTE c00_g, c01_g, c10_g, c11_g;
+ BYTE c00_b, c01_b, c10_b, c11_b;
+ RECT dst_rect, src_rect;
+ BYTE r, g, b;
+
+ calc_halftone_params( dst, src, &dst_rect, &src_rect, &src_start_x, &src_start_y, &src_inc_x,
+ &src_inc_y );
+
+ float_y = src_start_y;
+ dst_ptr = get_pixel_ptr_32( dst_dib, dst_rect.left, dst_rect.top );
+ for (dst_y = 0; dst_y < dst_rect.bottom - dst_rect.top; ++dst_y)
+ {
+ float_y = clampf( float_y, src_rect.top, src_rect.bottom - 1 );
+ y0 = float_y;
+ y1 = clamp( y0 + 1, src_rect.top, src_rect.bottom - 1 );
+ dy = float_y - y0;
+
+ float_x = src_start_x;
+ src_ptr = get_pixel_ptr_32( src_dib, 0, y0 );
+ src_ptr_dy = (y1 - y0) * src_dib->stride / 4;
+ for (dst_x = 0; dst_x < dst_rect.right - dst_rect.left; ++dst_x)
+ {
+ float_x = clampf( float_x, src_rect.left, src_rect.right - 1 );
+ x0 = float_x;
+ x1 = clamp( x0 + 1, src_rect.left, src_rect.right - 1 );
+ dx = float_x - x0;
+
+ c00_ptr = src_ptr + x0;
+ c01_ptr = src_ptr + x1;
+ c10_ptr = c00_ptr + src_ptr_dy;
+ c11_ptr = c01_ptr + src_ptr_dy;
+ c00_r = (*c00_ptr >> 16) & 0xff;
+ c01_r = (*c01_ptr >> 16) & 0xff;
+ c10_r = (*c10_ptr >> 16) & 0xff;
+ c11_r = (*c11_ptr >> 16) & 0xff;
+ c00_g = (*c00_ptr >> 8) & 0xff;
+ c01_g = (*c01_ptr >> 8) & 0xff;
+ c10_g = (*c10_ptr >> 8) & 0xff;
+ c11_g = (*c11_ptr >> 8) & 0xff;
+ c00_b = *c00_ptr & 0xff;
+ c01_b = *c01_ptr & 0xff;
+ c10_b = *c10_ptr & 0xff;
+ c11_b = *c11_ptr & 0xff;
+ r = bilinear_interpolate( c00_r, c01_r, c10_r, c11_r, dx, dy );
+ g = bilinear_interpolate( c00_g, c01_g, c10_g, c11_g, dx, dy );
+ b = bilinear_interpolate( c00_b, c01_b, c10_b, c11_b, dx, dy );
+ dst_ptr[dst_x] = ((r << 16) & 0xff0000) | ((g << 8) & 0x00ff00) | (b & 0x0000ff);
+
+ float_x += src_inc_x;
+ }
+
+ dst_ptr += dst_dib->stride / 4;
+ float_y += src_inc_y;
+ }
+}
+
+static void halftone_32( const dib_info *dst_dib, const struct bitblt_coords *dst,
+ const dib_info *src_dib, const struct bitblt_coords *src )
+{
+ int src_start_x, src_start_y, src_ptr_dy, dst_x, dst_y, x0, x1, y0, y1;
+ DWORD *dst_ptr, *src_ptr, *c00_ptr, *c01_ptr, *c10_ptr, *c11_ptr;
+ float src_inc_x, src_inc_y, float_x, float_y, dx, dy;
+ BYTE c00_r, c01_r, c10_r, c11_r;
+ BYTE c00_g, c01_g, c10_g, c11_g;
+ BYTE c00_b, c01_b, c10_b, c11_b;
+ RECT dst_rect, src_rect;
+ BYTE r, g, b;
+
+ calc_halftone_params( dst, src, &dst_rect, &src_rect, &src_start_x, &src_start_y, &src_inc_x,
+ &src_inc_y );
+
+ float_y = src_start_y;
+ dst_ptr = get_pixel_ptr_32( dst_dib, dst_rect.left, dst_rect.top );
+ for (dst_y = 0; dst_y < dst_rect.bottom - dst_rect.top; ++dst_y)
+ {
+ float_y = clampf( float_y, src_rect.top, src_rect.bottom - 1 );
+ y0 = float_y;
+ y1 = clamp( y0 + 1, src_rect.top, src_rect.bottom - 1 );
+ dy = float_y - y0;
+
+ float_x = src_start_x;
+ src_ptr = get_pixel_ptr_32( src_dib, 0, y0 );
+ src_ptr_dy = (y1 - y0) * src_dib->stride / 4;
+ for (dst_x = 0; dst_x < dst_rect.right - dst_rect.left; ++dst_x)
+ {
+ float_x = clampf( float_x, src_rect.left, src_rect.right - 1 );
+ x0 = float_x;
+ x1 = clamp( x0 + 1, src_rect.left, src_rect.right - 1 );
+ dx = float_x - x0;
+
+ c00_ptr = src_ptr + x0;
+ c01_ptr = src_ptr + x1;
+ c10_ptr = c00_ptr + src_ptr_dy;
+ c11_ptr = c01_ptr + src_ptr_dy;
+ c00_r = get_field( *c00_ptr, src_dib->red_shift, src_dib->red_len );
+ c01_r = get_field( *c01_ptr, src_dib->red_shift, src_dib->red_len );
+ c10_r = get_field( *c10_ptr, src_dib->red_shift, src_dib->red_len );
+ c11_r = get_field( *c11_ptr, src_dib->red_shift, src_dib->red_len );
+ c00_g = get_field( *c00_ptr, src_dib->green_shift, src_dib->green_len );
+ c01_g = get_field( *c01_ptr, src_dib->green_shift, src_dib->green_len );
+ c10_g = get_field( *c10_ptr, src_dib->green_shift, src_dib->green_len );
+ c11_g = get_field( *c11_ptr, src_dib->green_shift, src_dib->green_len );
+ c00_b = get_field( *c00_ptr, src_dib->blue_shift, src_dib->blue_len );
+ c01_b = get_field( *c01_ptr, src_dib->blue_shift, src_dib->blue_len );
+ c10_b = get_field( *c10_ptr, src_dib->blue_shift, src_dib->blue_len );
+ c11_b = get_field( *c11_ptr, src_dib->blue_shift, src_dib->blue_len );
+ r = bilinear_interpolate( c00_r, c01_r, c10_r, c11_r, dx, dy );
+ g = bilinear_interpolate( c00_g, c01_g, c10_g, c11_g, dx, dy );
+ b = bilinear_interpolate( c00_b, c01_b, c10_b, c11_b, dx, dy );
+ dst_ptr[dst_x] = rgb_to_pixel_masks( dst_dib, r, g, b );
+
+ float_x += src_inc_x;
+ }
+
+ dst_ptr += dst_dib->stride / 4;
+ float_y += src_inc_y;
+ }
+}
+
+static void halftone_24( const dib_info *dst_dib, const struct bitblt_coords *dst,
+ const dib_info *src_dib, const struct bitblt_coords *src )
+{
+ int src_start_x, src_start_y, src_ptr_dy, dst_x, dst_y, x0, x1, y0, y1;
+ BYTE *dst_ptr, *src_ptr, *c00_ptr, *c01_ptr, *c10_ptr, *c11_ptr;
+ float src_inc_x, src_inc_y, float_x, float_y, dx, dy;
+ BYTE c00_r, c01_r, c10_r, c11_r;
+ BYTE c00_g, c01_g, c10_g, c11_g;
+ BYTE c00_b, c01_b, c10_b, c11_b;
+ RECT dst_rect, src_rect;
+ BYTE r, g, b;
+
+ calc_halftone_params( dst, src, &dst_rect, &src_rect, &src_start_x, &src_start_y, &src_inc_x,
+ &src_inc_y );
+
+ float_y = src_start_y;
+ dst_ptr = get_pixel_ptr_24( dst_dib, dst_rect.left, dst_rect.top );
+ for (dst_y = 0; dst_y < dst_rect.bottom - dst_rect.top; ++dst_y)
+ {
+ float_y = clampf( float_y, src_rect.top, src_rect.bottom - 1 );
+ y0 = float_y;
+ y1 = clamp( y0 + 1, src_rect.top, src_rect.bottom - 1 );
+ dy = float_y - y0;
+
+ float_x = src_start_x;
+ src_ptr = get_pixel_ptr_24( src_dib, 0, y0 );
+ src_ptr_dy = (y1 - y0) * src_dib->stride;
+ for (dst_x = 0; dst_x < dst_rect.right - dst_rect.left; ++dst_x)
+ {
+ float_x = clampf( float_x, src_rect.left, src_rect.right - 1 );
+ x0 = float_x;
+ x1 = clamp( x0 + 1, src_rect.left, src_rect.right - 1 );
+ dx = float_x - x0;
+
+ c00_ptr = src_ptr + x0 * 3;
+ c01_ptr = src_ptr + x1 * 3;
+ c10_ptr = c00_ptr + src_ptr_dy;
+ c11_ptr = c01_ptr + src_ptr_dy;
+ c00_b = c00_ptr[0];
+ c01_b = c01_ptr[0];
+ c10_b = c10_ptr[0];
+ c11_b = c11_ptr[0];
+ c00_g = c00_ptr[1];
+ c01_g = c01_ptr[1];
+ c10_g = c10_ptr[1];
+ c11_g = c11_ptr[1];
+ c00_r = c00_ptr[2];
+ c01_r = c01_ptr[2];
+ c10_r = c10_ptr[2];
+ c11_r = c11_ptr[2];
+ r = bilinear_interpolate( c00_r, c01_r, c10_r, c11_r, dx, dy );
+ g = bilinear_interpolate( c00_g, c01_g, c10_g, c11_g, dx, dy );
+ b = bilinear_interpolate( c00_b, c01_b, c10_b, c11_b, dx, dy );
+ dst_ptr[dst_x * 3] = b;
+ dst_ptr[dst_x * 3 + 1] = g;
+ dst_ptr[dst_x * 3 + 2] = r;
+
+ float_x += src_inc_x;
+ }
+
+ dst_ptr += dst_dib->stride;
+ float_y += src_inc_y;
+ }
+}
+
+static void halftone_555( const dib_info *dst_dib, const struct bitblt_coords *dst,
+ const dib_info *src_dib, const struct bitblt_coords *src )
+{
+ int src_start_x, src_start_y, src_ptr_dy, dst_x, dst_y, x0, x1, y0, y1;
+ WORD *dst_ptr, *src_ptr, *c00_ptr, *c01_ptr, *c10_ptr, *c11_ptr;
+ float src_inc_x, src_inc_y, float_x, float_y, dx, dy;
+ BYTE c00_r, c01_r, c10_r, c11_r;
+ BYTE c00_g, c01_g, c10_g, c11_g;
+ BYTE c00_b, c01_b, c10_b, c11_b;
+ RECT dst_rect, src_rect;
+ BYTE r, g, b;
+
+ calc_halftone_params( dst, src, &dst_rect, &src_rect, &src_start_x, &src_start_y, &src_inc_x,
+ &src_inc_y );
+
+ float_y = src_start_y;
+ dst_ptr = get_pixel_ptr_16( dst_dib, dst_rect.left, dst_rect.top );
+ for (dst_y = 0; dst_y < dst_rect.bottom - dst_rect.top; ++dst_y)
+ {
+ float_y = clampf( float_y, src_rect.top, src_rect.bottom - 1 );
+ y0 = float_y;
+ y1 = clamp( y0 + 1, src_rect.top, src_rect.bottom - 1 );
+ dy = float_y - y0;
+
+ float_x = src_start_x;
+ src_ptr = get_pixel_ptr_16( src_dib, 0, y0 );
+ src_ptr_dy = (y1 - y0) * src_dib->stride / 2;
+ for (dst_x = 0; dst_x < dst_rect.right - dst_rect.left; ++dst_x)
+ {
+ float_x = clampf( float_x, src_rect.left, src_rect.right - 1 );
+ x0 = float_x;
+ x1 = clamp( x0 + 1, src_rect.left, src_rect.right - 1 );
+ dx = float_x - x0;
+
+ c00_ptr = src_ptr + x0;
+ c01_ptr = src_ptr + x1;
+ c10_ptr = c00_ptr + src_ptr_dy;
+ c11_ptr = c01_ptr + src_ptr_dy;
+ c00_r = ((*c00_ptr >> 7) & 0xf8) | ((*c00_ptr >> 12) & 0x07);
+ c01_r = ((*c01_ptr >> 7) & 0xf8) | ((*c01_ptr >> 12) & 0x07);
+ c10_r = ((*c10_ptr >> 7) & 0xf8) | ((*c10_ptr >> 12) & 0x07);
+ c11_r = ((*c11_ptr >> 7) & 0xf8) | ((*c11_ptr >> 12) & 0x07);
+ c00_g = ((*c00_ptr >> 2) & 0xf8) | ((*c00_ptr >> 7) & 0x07);
+ c01_g = ((*c01_ptr >> 2) & 0xf8) | ((*c01_ptr >> 7) & 0x07);
+ c10_g = ((*c10_ptr >> 2) & 0xf8) | ((*c10_ptr >> 7) & 0x07);
+ c11_g = ((*c11_ptr >> 2) & 0xf8) | ((*c11_ptr >> 7) & 0x07);
+ c00_b = ((*c00_ptr << 3) & 0xf8) | ((*c00_ptr >> 2) & 0x07);
+ c01_b = ((*c01_ptr << 3) & 0xf8) | ((*c01_ptr >> 2) & 0x07);
+ c10_b = ((*c10_ptr << 3) & 0xf8) | ((*c10_ptr >> 2) & 0x07);
+ c11_b = ((*c11_ptr << 3) & 0xf8) | ((*c11_ptr >> 2) & 0x07);
+ r = bilinear_interpolate( c00_r, c01_r, c10_r, c11_r, dx, dy );
+ g = bilinear_interpolate( c00_g, c01_g, c10_g, c11_g, dx, dy );
+ b = bilinear_interpolate( c00_b, c01_b, c10_b, c11_b, dx, dy );
+ dst_ptr[dst_x] = ((r << 7) & 0x7c00) | ((g << 2) & 0x03e0) | ((b >> 3) & 0x001f);
+
+ float_x += src_inc_x;
+ }
+
+ dst_ptr += dst_dib->stride / 2;
+ float_y += src_inc_y;
+ }
+}
+
+static void halftone_16( const dib_info *dst_dib, const struct bitblt_coords *dst,
+ const dib_info *src_dib, const struct bitblt_coords *src )
+{
+ int src_start_x, src_start_y, src_ptr_dy, dst_x, dst_y, x0, x1, y0, y1;
+ WORD *dst_ptr, *src_ptr, *c00_ptr, *c01_ptr, *c10_ptr, *c11_ptr;
+ float src_inc_x, src_inc_y, float_x, float_y, dx, dy;
+ BYTE c00_r, c01_r, c10_r, c11_r;
+ BYTE c00_g, c01_g, c10_g, c11_g;
+ BYTE c00_b, c01_b, c10_b, c11_b;
+ RECT dst_rect, src_rect;
+ BYTE r, g, b;
+
+ calc_halftone_params( dst, src, &dst_rect, &src_rect, &src_start_x, &src_start_y, &src_inc_x,
+ &src_inc_y );
+
+ float_y = src_start_y;
+ dst_ptr = get_pixel_ptr_16( dst_dib, dst_rect.left, dst_rect.top );
+ for (dst_y = 0; dst_y < dst_rect.bottom - dst_rect.top; ++dst_y)
+ {
+ float_y = clampf( float_y, src_rect.top, src_rect.bottom - 1 );
+ y0 = float_y;
+ y1 = clamp( y0 + 1, src_rect.top, src_rect.bottom - 1 );
+ dy = float_y - y0;
+
+ float_x = src_start_x;
+ src_ptr = get_pixel_ptr_16( src_dib, 0, y0 );
+ src_ptr_dy = (y1 - y0) * src_dib->stride / 2;
+ for (dst_x = 0; dst_x < dst_rect.right - dst_rect.left; ++dst_x)
+ {
+ float_x = clampf( float_x, src_rect.left, src_rect.right - 1 );
+ x0 = float_x;
+ x1 = clamp( x0 + 1, src_rect.left, src_rect.right - 1 );
+ dx = float_x - x0;
+
+ c00_ptr = src_ptr + x0;
+ c01_ptr = src_ptr + x1;
+ c10_ptr = c00_ptr + src_ptr_dy;
+ c11_ptr = c01_ptr + src_ptr_dy;
+ c00_r = get_field( *c00_ptr, src_dib->red_shift, src_dib->red_len );
+ c01_r = get_field( *c01_ptr, src_dib->red_shift, src_dib->red_len );
+ c10_r = get_field( *c10_ptr, src_dib->red_shift, src_dib->red_len );
+ c11_r = get_field( *c11_ptr, src_dib->red_shift, src_dib->red_len );
+ c00_g = get_field( *c00_ptr, src_dib->green_shift, src_dib->green_len );
+ c01_g = get_field( *c01_ptr, src_dib->green_shift, src_dib->green_len );
+ c10_g = get_field( *c10_ptr, src_dib->green_shift, src_dib->green_len );
+ c11_g = get_field( *c11_ptr, src_dib->green_shift, src_dib->green_len );
+ c00_b = get_field( *c00_ptr, src_dib->blue_shift, src_dib->blue_len );
+ c01_b = get_field( *c01_ptr, src_dib->blue_shift, src_dib->blue_len );
+ c10_b = get_field( *c10_ptr, src_dib->blue_shift, src_dib->blue_len );
+ c11_b = get_field( *c11_ptr, src_dib->blue_shift, src_dib->blue_len );
+ r = bilinear_interpolate( c00_r, c01_r, c10_r, c11_r, dx, dy );
+ g = bilinear_interpolate( c00_g, c01_g, c10_g, c11_g, dx, dy );
+ b = bilinear_interpolate( c00_b, c01_b, c10_b, c11_b, dx, dy );
+ dst_ptr[dst_x] = rgb_to_pixel_masks( dst_dib, r, g, b );
+
+ float_x += src_inc_x;
+ }
+
+ dst_ptr += dst_dib->stride / 2;
+ float_y += src_inc_y;
+ }
+}
+
+static void halftone_8( const dib_info *dst_dib, const struct bitblt_coords *dst,
+ const dib_info *src_dib, const struct bitblt_coords *src )
+{
+ int src_start_x, src_start_y, src_ptr_dy, dst_x, dst_y, x0, x1, y0, y1;
+ BYTE *dst_ptr, *src_ptr, *c00_ptr, *c01_ptr, *c10_ptr, *c11_ptr;
+ RGBQUAD c00_rgb, c01_rgb, c10_rgb, c11_rgb, zero_rgb = {0};
+ float src_inc_x, src_inc_y, float_x, float_y, dx, dy;
+ const RGBQUAD *src_clr_table;
+ RECT dst_rect, src_rect;
+ BYTE r, g, b;
+
+ calc_halftone_params( dst, src, &dst_rect, &src_rect, &src_start_x, &src_start_y, &src_inc_x,
+ &src_inc_y );
+
+ float_y = src_start_y;
+ src_clr_table = get_dib_color_table( src_dib );
+ dst_ptr = get_pixel_ptr_8( dst_dib, dst_rect.left, dst_rect.top );
+ for (dst_y = 0; dst_y < dst_rect.bottom - dst_rect.top; ++dst_y)
+ {
+ float_y = clampf( float_y, src_rect.top, src_rect.bottom - 1 );
+ y0 = float_y;
+ y1 = clamp( y0 + 1, src_rect.top, src_rect.bottom - 1 );
+ dy = float_y - y0;
+
+ float_x = src_start_x;
+ src_ptr = get_pixel_ptr_8( src_dib, 0, y0 );
+ src_ptr_dy = (y1 - y0) * src_dib->stride;
+ for (dst_x = 0; dst_x < dst_rect.right - dst_rect.left; ++dst_x)
+ {
+ float_x = clampf( float_x, src_rect.left, src_rect.right - 1 );
+ x0 = float_x;
+ x1 = clamp( x0 + 1, src_rect.left, src_rect.right - 1 );
+ dx = float_x - x0;
+
+ c00_ptr = src_ptr + x0;
+ c01_ptr = src_ptr + x1;
+ c10_ptr = c00_ptr + src_ptr_dy;
+ c11_ptr = c01_ptr + src_ptr_dy;
+ if (src_clr_table)
+ {
+ c00_rgb = *c00_ptr < src_dib->color_table_size ? src_clr_table[*c00_ptr] : zero_rgb;
+ c01_rgb = *c01_ptr < src_dib->color_table_size ? src_clr_table[*c01_ptr] : zero_rgb;
+ c10_rgb = *c10_ptr < src_dib->color_table_size ? src_clr_table[*c10_ptr] : zero_rgb;
+ c11_rgb = *c11_ptr < src_dib->color_table_size ? src_clr_table[*c11_ptr] : zero_rgb;
+ r = bilinear_interpolate( c00_rgb.rgbRed, c01_rgb.rgbRed, c10_rgb.rgbRed, c11_rgb.rgbRed, dx, dy );
+ g = bilinear_interpolate( c00_rgb.rgbGreen, c01_rgb.rgbGreen, c10_rgb.rgbGreen, c11_rgb.rgbGreen, dx, dy );
+ b = bilinear_interpolate( c00_rgb.rgbBlue, c01_rgb.rgbBlue, c10_rgb.rgbBlue, c11_rgb.rgbBlue, dx, dy );
+ }
+ else
+ {
+ r = 0;
+ g = 0;
+ b = 0;
+ }
+ dst_ptr[dst_x] = rgb_to_pixel_colortable( dst_dib, r, g, b );
+
+ float_x += src_inc_x;
+ }
+
+ dst_ptr += dst_dib->stride;
+ float_y += src_inc_y;
+ }
+}
+
+static void halftone_4( const dib_info *dst_dib, const struct bitblt_coords *dst,
+ const dib_info *src_dib, const struct bitblt_coords *src )
+{
+ BYTE *dst_col_ptr, *dst_ptr, *src_ptr, *c00_ptr, *c01_ptr, *c10_ptr, *c11_ptr;
+ int src_start_x, src_start_y, src_ptr_dy, dst_x, dst_y, x0, x1, y0, y1;
+ RGBQUAD c00_rgb, c01_rgb, c10_rgb, c11_rgb, zero_rgb = {0};
+ float src_inc_x, src_inc_y, float_x, float_y, dx, dy;
+ BYTE r, g, b, val, c00, c01, c10, c11;
+ const RGBQUAD *src_clr_table;
+ RECT dst_rect, src_rect;
+
+ calc_halftone_params( dst, src, &dst_rect, &src_rect, &src_start_x, &src_start_y, &src_inc_x,
+ &src_inc_y );
+
+ float_y = src_start_y;
+ src_clr_table = get_dib_color_table( src_dib );
+ dst_col_ptr = (BYTE *)dst_dib->bits.ptr + (dst_dib->rect.top + dst_rect.top) * dst_dib->stride;
+ for (dst_y = 0; dst_y < dst_rect.bottom - dst_rect.top; ++dst_y)
+ {
+ float_y = clampf( float_y, src_rect.top, src_rect.bottom - 1 );
+ y0 = float_y;
+ y1 = clamp( y0 + 1, src_rect.top, src_rect.bottom - 1 );
+ dy = float_y - y0;
+
+ float_x = src_start_x;
+ src_ptr = (BYTE *)src_dib->bits.ptr + (src_dib->rect.top + y0) * src_dib->stride;
+ src_ptr_dy = (y1 - y0) * src_dib->stride;
+ for (dst_x = dst_rect.left; dst_x < dst_rect.right; ++dst_x)
+ {
+ float_x = clampf( float_x, src_rect.left, src_rect.right - 1 );
+ x0 = float_x;
+ x1 = clamp( x0 + 1, src_rect.left, src_rect.right - 1 );
+ dx = float_x - x0;
+
+ c00_ptr = src_ptr + (src_dib->rect.left + x0) / 2;
+ c01_ptr = src_ptr + (src_dib->rect.left + x1) / 2;
+ c10_ptr = c00_ptr + src_ptr_dy;
+ c11_ptr = c01_ptr + src_ptr_dy;
+ if ((src_dib->rect.left + x0) & 1)
+ {
+ c00 = *c00_ptr & 0x0f;
+ c10 = *c10_ptr & 0x0f;
+ }
+ else
+ {
+ c00 = (*c00_ptr >> 4) & 0x0f;
+ c10 = (*c10_ptr >> 4) & 0x0f;
+ }
+ if ((src_dib->rect.left + x1) & 1)
+ {
+ c01 = *c01_ptr & 0x0f;
+ c11 = *c11_ptr & 0x0f;
+ }
+ else
+ {
+ c01 = (*c01_ptr >> 4) & 0x0f;
+ c11 = (*c11_ptr >> 4) & 0x0f;
+ }
+
+ if (src_clr_table)
+ {
+ c00_rgb = c00 < src_dib->color_table_size ? src_clr_table[c00] : zero_rgb;
+ c01_rgb = c01 < src_dib->color_table_size ? src_clr_table[c01] : zero_rgb;
+ c10_rgb = c10 < src_dib->color_table_size ? src_clr_table[c10] : zero_rgb;
+ c11_rgb = c11 < src_dib->color_table_size ? src_clr_table[c11] : zero_rgb;
+ r = bilinear_interpolate( c00_rgb.rgbRed, c01_rgb.rgbRed, c10_rgb.rgbRed, c11_rgb.rgbRed, dx, dy );
+ g = bilinear_interpolate( c00_rgb.rgbGreen, c01_rgb.rgbGreen, c10_rgb.rgbGreen, c11_rgb.rgbGreen, dx, dy );
+ b = bilinear_interpolate( c00_rgb.rgbBlue, c01_rgb.rgbBlue, c10_rgb.rgbBlue, c11_rgb.rgbBlue, dx, dy );
+ }
+ else
+ {
+ r = 0;
+ g = 0;
+ b = 0;
+ }
+
+ dst_ptr = dst_col_ptr + (dst_dib->rect.left + dst_x) / 2;
+ val = rgb_to_pixel_colortable( dst_dib, r, g, b );
+ if ((dst_x + dst_dib->rect.left) & 1)
+ *dst_ptr = (val & 0x0f) | (*dst_ptr & 0xf0);
+ else
+ *dst_ptr = (val << 4) & 0xf0;
+
+ float_x += src_inc_x;
+ }
+
+ dst_col_ptr += dst_dib->stride;
+ float_y += src_inc_y;
+ }
+}
+
+static void halftone_1( const dib_info *dst_dib, const struct bitblt_coords *dst,
+ const dib_info *src_dib, const struct bitblt_coords *src )
+{
+ int src_start_x, src_start_y, src_ptr_dy, dst_x, dst_y, x0, x1, y0, y1, bit_pos;
+ BYTE *dst_col_ptr, *dst_ptr, *src_ptr, *c00_ptr, *c01_ptr, *c10_ptr, *c11_ptr;
+ RGBQUAD c00_rgb, c01_rgb, c10_rgb, c11_rgb, zero_rgb = {0};
+ float src_inc_x, src_inc_y, float_x, float_y, dx, dy;
+ BYTE r, g, b, val, c00, c01, c10, c11;
+ const RGBQUAD *src_clr_table;
+ RECT dst_rect, src_rect;
+ RGBQUAD bg_entry;
+ DWORD bg_pixel;
+
+ calc_halftone_params( dst, src, &dst_rect, &src_rect, &src_start_x, &src_start_y, &src_inc_x,
+ &src_inc_y );
+
+ float_y = src_start_y;
+ bg_entry = *get_dib_color_table( dst_dib );
+ src_clr_table = get_dib_color_table( src_dib );
+ dst_col_ptr = (BYTE *)dst_dib->bits.ptr + (dst_dib->rect.top + dst_rect.top) * dst_dib->stride;
+ for (dst_y = dst_rect.top; dst_y < dst_rect.bottom; ++dst_y)
+ {
+ float_y = clampf( float_y, src_rect.top, src_rect.bottom - 1 );
+ y0 = float_y;
+ y1 = clamp( y0 + 1, src_rect.top, src_rect.bottom - 1 );
+ dy = float_y - y0;
+
+ float_x = src_start_x;
+ src_ptr = (BYTE *)src_dib->bits.ptr + (src_dib->rect.top + y0) * src_dib->stride;
+ src_ptr_dy = (y1 - y0) * src_dib->stride;
+ for (dst_x = dst_rect.left; dst_x < dst_rect.right; ++dst_x)
+ {
+ float_x = clampf( float_x, src_rect.left, src_rect.right - 1 );
+ x0 = float_x;
+ x1 = clamp( x0 + 1, src_rect.left, src_rect.right - 1 );
+ dx = float_x - x0;
+
+ c00_ptr = src_ptr + (src_dib->rect.left + x0) / 8;
+ c01_ptr = src_ptr + (src_dib->rect.left + x1) / 8;
+ c10_ptr = c00_ptr + src_ptr_dy;
+ c11_ptr = c01_ptr + src_ptr_dy;
+ c00 = (*c00_ptr & pixel_masks_1[(src_dib->rect.left + x0) & 7]) ? 1 : 0;
+ c01 = (*c01_ptr & pixel_masks_1[(src_dib->rect.left + x1) & 7]) ? 1 : 0;
+ c10 = (*c10_ptr & pixel_masks_1[(src_dib->rect.left + x0) & 7]) ? 1 : 0;
+ c11 = (*c11_ptr & pixel_masks_1[(src_dib->rect.left + x1) & 7]) ? 1 : 0;
+
+ if (src_clr_table)
+ {
+ c00_rgb = c00 < src_dib->color_table_size ? src_clr_table[c00] : zero_rgb;
+ c01_rgb = c01 < src_dib->color_table_size ? src_clr_table[c01] : zero_rgb;
+ c10_rgb = c10 < src_dib->color_table_size ? src_clr_table[c10] : zero_rgb;
+ c11_rgb = c11 < src_dib->color_table_size ? src_clr_table[c11] : zero_rgb;
+ r = bilinear_interpolate( c00_rgb.rgbRed, c01_rgb.rgbRed, c10_rgb.rgbRed, c11_rgb.rgbRed, dx, dy );
+ g = bilinear_interpolate( c00_rgb.rgbGreen, c01_rgb.rgbGreen, c10_rgb.rgbGreen, c11_rgb.rgbGreen, dx, dy );
+ b = bilinear_interpolate( c00_rgb.rgbBlue, c01_rgb.rgbBlue, c10_rgb.rgbBlue, c11_rgb.rgbBlue, dx, dy );
+ }
+ else
+ {
+ r = 0;
+ g = 0;
+ b = 0;
+ }
+
+ dst_ptr = dst_col_ptr + (dst_dib->rect.left + dst_x) / 8;
+ bit_pos = (dst_x + dst_dib->rect.left) & 7;
+ bg_pixel = FILTER_DIBINDEX(bg_entry, RGB(bg_entry.rgbRed, bg_entry.rgbGreen, bg_entry.rgbBlue));
+ val = rgb_to_pixel_mono( dst_dib, FALSE, dst_x, dst_y, RGB(r, g, b), bg_pixel, r, g, b );
+ if (bit_pos == 0)
+ *dst_ptr = 0;
+ *dst_ptr = (*dst_ptr & ~pixel_masks_1[bit_pos]) | (val & pixel_masks_1[bit_pos]);
+
+ float_x += src_inc_x;
+ }
+
+ dst_col_ptr += dst_dib->stride;
+ float_y += src_inc_y;
+ }
+}
+
+static void halftone_null( const dib_info *dst_dib, const struct bitblt_coords *dst,
+ const dib_info *src_dib, const struct bitblt_coords *src )
+{}
+
const primitive_funcs funcs_8888 =
{
solid_rects_32,
@@ -7448,7 +8050,8 @@ const primitive_funcs funcs_8888 =
create_rop_masks_32,
create_dither_masks_null,
stretch_row_32,
- shrink_row_32
+ shrink_row_32,
+ halftone_888
};
const primitive_funcs funcs_32 =
@@ -7469,7 +8072,8 @@ const primitive_funcs funcs_32 =
create_rop_masks_32,
create_dither_masks_null,
stretch_row_32,
- shrink_row_32
+ shrink_row_32,
+ halftone_32
};
const primitive_funcs funcs_24 =
@@ -7490,7 +8094,8 @@ const primitive_funcs funcs_24 =
create_rop_masks_24,
create_dither_masks_null,
stretch_row_24,
- shrink_row_24
+ shrink_row_24,
+ halftone_24
};
const primitive_funcs funcs_555 =
@@ -7511,7 +8116,8 @@ const primitive_funcs funcs_555 =
create_rop_masks_16,
create_dither_masks_null,
stretch_row_16,
- shrink_row_16
+ shrink_row_16,
+ halftone_555
};
const primitive_funcs funcs_16 =
@@ -7532,7 +8138,8 @@ const primitive_funcs funcs_16 =
create_rop_masks_16,
create_dither_masks_null,
stretch_row_16,
- shrink_row_16
+ shrink_row_16,
+ halftone_16
};
const primitive_funcs funcs_8 =
@@ -7553,7 +8160,8 @@ const primitive_funcs funcs_8 =
create_rop_masks_8,
create_dither_masks_8,
stretch_row_8,
- shrink_row_8
+ shrink_row_8,
+ halftone_8
};
const primitive_funcs funcs_4 =
@@ -7574,7 +8182,8 @@ const primitive_funcs funcs_4 =
create_rop_masks_4,
create_dither_masks_4,
stretch_row_4,
- shrink_row_4
+ shrink_row_4,
+ halftone_4
};
const primitive_funcs funcs_1 =
@@ -7595,7 +8204,8 @@ const primitive_funcs funcs_1 =
create_rop_masks_1,
create_dither_masks_1,
stretch_row_1,
- shrink_row_1
+ shrink_row_1,
+ halftone_1
};
const primitive_funcs funcs_null =
@@ -7616,5 +8226,6 @@ const primitive_funcs funcs_null =
create_rop_masks_null,
create_dither_masks_null,
stretch_row_null,
- shrink_row_null
+ shrink_row_null,
+ halftone_null
};
diff --git a/dlls/user32/tests/cursoricon.c b/dlls/user32/tests/cursoricon.c
index 39ffe9d88e6..f84312f3ea2 100644
--- a/dlls/user32/tests/cursoricon.c
+++ b/dlls/user32/tests/cursoricon.c
@@ -2897,10 +2897,10 @@ static COLORREF get_color_from_bits(const unsigned char *bits, const BITMAPINFO
return RGB(color.rgbRed, color.rgbGreen, color.rgbBlue);
}
-#define compare_bitmap_bits(a, b, c, d, e, f, g) compare_bitmap_bits_(__LINE__, a, b, c, d, e, f, g)
+#define compare_bitmap_bits(a, b, c, d, e, f, g, h) compare_bitmap_bits_(__LINE__, a, b, c, d, e, f, g, h)
static void compare_bitmap_bits_(unsigned int line, HDC hdc, HBITMAP bitmap, BITMAPINFO *bmi,
size_t result_bits_size, const unsigned char *expected_bits, unsigned int test_index,
- const unsigned char *expected_broken_bits)
+ BOOL allow_todo, const unsigned char *expected_broken_bits)
{
unsigned char *result_bits;
unsigned int row, column;
@@ -2919,6 +2919,7 @@ static void compare_bitmap_bits_(unsigned int line, HDC hdc, HBITMAP bitmap, BIT
result = get_color_from_bits(result_bits, bmi, row, column);
expected = get_color_from_bits(expected_bits, bmi, row, column);
+ todo_wine_if(allow_todo && result != expected)
ok_(__FILE__, line)(result == expected || broken(expected_broken_bits
&& result == get_color_from_bits(expected_broken_bits, bmi, row, column)),
"Colors do not match, got 0x%06x, expected 0x%06x, test_index %u, row %u, column %u.\n",
@@ -2999,21 +3000,22 @@ static void test_Image_StretchMode(void)
size_t test_bits_size, result_bits_size;
const RGBQUAD *bmi_colors;
size_t bmi_colors_size;
+ BOOL allow_todo;
const unsigned char *expected_broken_bits;
}
tests[] =
{
{4, 4, 2, 2, 24, test_bits_24, expected_bits_24,
- sizeof(test_bits_24), sizeof(expected_bits_24), NULL, 0,
+ sizeof(test_bits_24), sizeof(expected_bits_24), NULL, 0, TRUE,
/* Broken on Windows before Win10 1607+ */ expected_broken_bits_24},
{4, 4, 2, 2, 1, test_bits_1, expected_bits_1,
sizeof(test_bits_1), sizeof(expected_bits_1), colors_bits_1,
sizeof(colors_bits_1)},
{4, 4, 2, 2, 8, test_bits_8, expected_bits_8,
sizeof(test_bits_8), sizeof(expected_bits_8), colors_bits_8,
- sizeof(colors_bits_8)},
+ sizeof(colors_bits_8), TRUE},
{4, 4, 2, 2, 16, (const unsigned char *)test_bits_16, (const unsigned char *)expected_bits_16,
- sizeof(test_bits_16), sizeof(expected_bits_16), NULL, 0},
+ sizeof(test_bits_16), sizeof(expected_bits_16), NULL, 0, TRUE},
};
static const char filename[] = "test.bmp";
BITMAPINFO *bmi, *bmi_output;
@@ -3059,7 +3061,8 @@ static void test_Image_StretchMode(void)
ok(!!bitmap_copy, "CopyImage() failed, result %u.\n", GetLastError());
compare_bitmap_bits(hdc, bitmap_copy, bmi_output, tests[test_index].result_bits_size,
- tests[test_index].expected_bits, test_index, tests[test_index].expected_broken_bits);
+ tests[test_index].expected_bits, test_index, tests[test_index].allow_todo,
+ tests[test_index].expected_broken_bits);
DeleteObject(bitmap);
DeleteObject(bitmap_copy);
@@ -3069,7 +3072,8 @@ static void test_Image_StretchMode(void)
ok(!!bitmap, "LoadImageA() failed, result %u.\n", GetLastError());
DeleteFileA(filename);
compare_bitmap_bits(hdc, bitmap, bmi_output, tests[test_index].result_bits_size,
- tests[test_index].expected_bits, test_index, tests[test_index].expected_broken_bits);
+ tests[test_index].expected_bits, test_index, tests[test_index].allow_todo,
+ tests[test_index].expected_broken_bits);
DeleteObject(bitmap);
}
ReleaseDC(0, hdc);
--
2.30.2
2
1