mirror of
https://github.com/reactos/wine.git
synced 2024-11-28 14:10:32 +00:00
sane.ds: Implement support for ICAP_XRESOLUTION and ICAP_YRESOLUTION.
This commit is contained in:
parent
f728c19a73
commit
6ace799f5a
@ -122,11 +122,40 @@ static TW_UINT16 msg_get_enum(pTW_CAPABILITY pCapability, const TW_UINT32 *value
|
||||
return TWCC_SUCCESS;
|
||||
}
|
||||
|
||||
#ifdef SONAME_LIBSANE
|
||||
static TW_UINT16 msg_get_range(pTW_CAPABILITY pCapability, TW_UINT16 type,
|
||||
TW_UINT32 minval, TW_UINT32 maxval, TW_UINT32 step, TW_UINT32 def, TW_UINT32 current)
|
||||
{
|
||||
TW_RANGE *range = NULL;
|
||||
|
||||
pCapability->ConType = TWON_RANGE;
|
||||
pCapability->hContainer = 0;
|
||||
|
||||
pCapability->hContainer = GlobalAlloc (0, sizeof(*range));
|
||||
if (pCapability->hContainer)
|
||||
range = GlobalLock(pCapability->hContainer);
|
||||
|
||||
if (! range)
|
||||
return TWCC_LOWMEMORY;
|
||||
|
||||
range->ItemType = type;
|
||||
range->MinValue = minval;
|
||||
range->MaxValue = maxval;
|
||||
range->StepSize = step;
|
||||
range->DefaultValue = def;
|
||||
range->CurrentValue = current;
|
||||
|
||||
GlobalUnlock(pCapability->hContainer);
|
||||
return TWCC_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
|
||||
static TW_UINT16 TWAIN_GetSupportedCaps(pTW_CAPABILITY pCapability)
|
||||
{
|
||||
TW_ARRAY *a;
|
||||
static const UINT16 supported_caps[] = { CAP_SUPPORTEDCAPS, CAP_XFERCOUNT, CAP_UICONTROLLABLE,
|
||||
ICAP_XFERMECH, ICAP_PIXELTYPE, ICAP_COMPRESSION, ICAP_PIXELFLAVOR };
|
||||
ICAP_XFERMECH, ICAP_PIXELTYPE, ICAP_COMPRESSION, ICAP_PIXELFLAVOR,
|
||||
ICAP_XRESOLUTION, ICAP_YRESOLUTION };
|
||||
|
||||
pCapability->hContainer = GlobalAlloc (0, FIELD_OFFSET( TW_ARRAY, ItemList[sizeof(supported_caps)] ));
|
||||
pCapability->ConType = TWON_ARRAY;
|
||||
@ -345,6 +374,108 @@ static TW_UINT16 SANE_ICAPCompression (pTW_CAPABILITY pCapability, TW_UINT16 act
|
||||
return twCC;
|
||||
}
|
||||
|
||||
/* ICAP_XRESOLUTION, ICAP_YRESOLUTION */
|
||||
static TW_UINT16 SANE_ICAPResolution (pTW_CAPABILITY pCapability, TW_UINT16 action, TW_UINT16 cap)
|
||||
{
|
||||
TW_UINT16 twCC = TWCC_BADCAP;
|
||||
#ifdef SONAME_LIBSANE
|
||||
TW_UINT32 val;
|
||||
SANE_Int current_resolution;
|
||||
TW_FIX32 *default_res;
|
||||
const char *best_option_name;
|
||||
SANE_Int minval, maxval, quantval;
|
||||
SANE_Status sane_rc;
|
||||
SANE_Int set_status;
|
||||
|
||||
TRACE("ICAP_%cRESOLUTION\n", cap == ICAP_XRESOLUTION ? 'X' : 'Y');
|
||||
|
||||
/* Some scanners support 'x-resolution', most seem to just support 'resolution' */
|
||||
if (cap == ICAP_XRESOLUTION)
|
||||
{
|
||||
best_option_name = "x-resolution";
|
||||
default_res = &activeDS.defaultXResolution;
|
||||
}
|
||||
else
|
||||
{
|
||||
best_option_name = "y-resolution";
|
||||
default_res = &activeDS.defaultYResolution;
|
||||
}
|
||||
if (sane_option_get_int(activeDS.deviceHandle, best_option_name, ¤t_resolution) != SANE_STATUS_GOOD)
|
||||
{
|
||||
best_option_name = "resolution";
|
||||
if (sane_option_get_int(activeDS.deviceHandle, best_option_name, ¤t_resolution) != SANE_STATUS_GOOD)
|
||||
return TWCC_BADCAP;
|
||||
}
|
||||
|
||||
/* Sane does not support a concept of 'default' resolution, so we have to
|
||||
* cache the resolution the very first time we load the scanner, and use that
|
||||
* as the default */
|
||||
if (cap == ICAP_XRESOLUTION && ! activeDS.XResolutionSet)
|
||||
{
|
||||
default_res->Whole = current_resolution;
|
||||
default_res->Frac = 0;
|
||||
activeDS.XResolutionSet = TRUE;
|
||||
}
|
||||
|
||||
if (cap == ICAP_YRESOLUTION && ! activeDS.YResolutionSet)
|
||||
{
|
||||
default_res->Whole = current_resolution;
|
||||
default_res->Frac = 0;
|
||||
activeDS.YResolutionSet = TRUE;
|
||||
}
|
||||
|
||||
switch (action)
|
||||
{
|
||||
case MSG_QUERYSUPPORT:
|
||||
twCC = set_onevalue(pCapability, TWTY_INT32,
|
||||
TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET );
|
||||
break;
|
||||
|
||||
case MSG_GET:
|
||||
sane_rc = sane_option_probe_resolution(activeDS.deviceHandle, best_option_name, &minval, &maxval, &quantval);
|
||||
if (sane_rc != SANE_STATUS_GOOD)
|
||||
twCC = TWCC_BADCAP;
|
||||
else
|
||||
twCC = msg_get_range(pCapability, TWTY_FIX32,
|
||||
minval, maxval, quantval == 0 ? 1 : quantval, default_res->Whole, current_resolution);
|
||||
break;
|
||||
|
||||
case MSG_SET:
|
||||
twCC = msg_set(pCapability, &val);
|
||||
if (twCC == TWCC_SUCCESS)
|
||||
{
|
||||
TW_FIX32 f32;
|
||||
memcpy(&f32, &val, sizeof(f32));
|
||||
sane_rc = sane_option_set_int(activeDS.deviceHandle, best_option_name, f32.Whole, &set_status);
|
||||
if (sane_rc != SANE_STATUS_GOOD)
|
||||
{
|
||||
FIXME("Status of %d not expected or handled\n", sane_rc);
|
||||
twCC = TWCC_BADCAP;
|
||||
}
|
||||
else if (set_status == SANE_INFO_INEXACT)
|
||||
twCC = TWCC_CHECKSTATUS;
|
||||
}
|
||||
break;
|
||||
|
||||
case MSG_GETDEFAULT:
|
||||
twCC = set_onevalue(pCapability, TWTY_FIX32, default_res->Whole);
|
||||
break;
|
||||
|
||||
case MSG_RESET:
|
||||
sane_rc = sane_option_set_int(activeDS.deviceHandle, best_option_name, default_res->Whole, NULL);
|
||||
if (sane_rc != SANE_STATUS_GOOD)
|
||||
return TWCC_BADCAP;
|
||||
|
||||
/* .. fall through intentional .. */
|
||||
|
||||
case MSG_GETCURRENT:
|
||||
twCC = set_onevalue(pCapability, TWTY_FIX32, current_resolution);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
return twCC;
|
||||
}
|
||||
|
||||
/* ICAP_PIXELFLAVOR */
|
||||
static TW_UINT16 SANE_ICAPPixelFlavor (pTW_CAPABILITY pCapability, TW_UINT16 action)
|
||||
{
|
||||
@ -427,6 +558,14 @@ TW_UINT16 SANE_SaneCapability (pTW_CAPABILITY pCapability, TW_UINT16 action)
|
||||
case ICAP_COMPRESSION:
|
||||
twCC = SANE_ICAPCompression(pCapability, action);
|
||||
break;
|
||||
|
||||
case ICAP_XRESOLUTION:
|
||||
twCC = SANE_ICAPResolution(pCapability, action, pCapability->Cap);
|
||||
break;
|
||||
|
||||
case ICAP_YRESOLUTION:
|
||||
twCC = SANE_ICAPResolution(pCapability, action, pCapability->Cap);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Twain specifies that you should return a 0 in response to QUERYSUPPORT,
|
||||
|
@ -162,7 +162,13 @@ TW_UINT16 SANE_CapabilitySet (pTW_IDENTITY pOrigin,
|
||||
else
|
||||
{
|
||||
twCC = SANE_SaneCapability (pCapability, MSG_SET);
|
||||
twRC = (twCC == TWCC_SUCCESS)?TWRC_SUCCESS:TWRC_FAILURE;
|
||||
if (twCC == TWCC_CHECKSTATUS)
|
||||
{
|
||||
twCC = TWCC_SUCCESS;
|
||||
twRC = TWRC_CHECKSTATUS;
|
||||
}
|
||||
else
|
||||
twRC = (twCC == TWCC_SUCCESS)?TWRC_SUCCESS:TWRC_FAILURE;
|
||||
activeDS.twCC = twCC;
|
||||
}
|
||||
return twRC;
|
||||
|
@ -26,7 +26,8 @@
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(twain);
|
||||
|
||||
#ifdef SONAME_LIBSANE
|
||||
SANE_Status sane_option_get_int(SANE_Handle h, const char *option_name, SANE_Int *val)
|
||||
static SANE_Status sane_find_option(SANE_Handle h, const char *option_name,
|
||||
const SANE_Option_Descriptor **opt_p, int *optno, SANE_Value_Type type)
|
||||
{
|
||||
SANE_Status rc;
|
||||
SANE_Int optcount;
|
||||
@ -41,9 +42,59 @@ SANE_Status sane_option_get_int(SANE_Handle h, const char *option_name, SANE_Int
|
||||
{
|
||||
opt = psane_get_option_descriptor(h, i);
|
||||
if (opt && (opt->name && strcmp(opt->name, option_name) == 0) &&
|
||||
opt->type == SANE_TYPE_INT )
|
||||
return psane_control_option(h, i, SANE_ACTION_GET_VALUE, val, NULL);
|
||||
opt->type == type)
|
||||
{
|
||||
*opt_p = opt;
|
||||
*optno = i;
|
||||
return SANE_STATUS_GOOD;
|
||||
}
|
||||
}
|
||||
return SANE_STATUS_EOF;
|
||||
}
|
||||
|
||||
SANE_Status sane_option_get_int(SANE_Handle h, const char *option_name, SANE_Int *val)
|
||||
{
|
||||
SANE_Status rc;
|
||||
int optno;
|
||||
const SANE_Option_Descriptor *opt;
|
||||
|
||||
rc = sane_find_option(h, option_name, &opt, &optno, SANE_TYPE_INT);
|
||||
if (rc != SANE_STATUS_GOOD)
|
||||
return rc;
|
||||
|
||||
return psane_control_option(h, optno, SANE_ACTION_GET_VALUE, val, NULL);
|
||||
}
|
||||
|
||||
SANE_Status sane_option_set_int(SANE_Handle h, const char *option_name, SANE_Int val, SANE_Int *status)
|
||||
{
|
||||
SANE_Status rc;
|
||||
int optno;
|
||||
const SANE_Option_Descriptor *opt;
|
||||
|
||||
rc = sane_find_option(h, option_name, &opt, &optno, SANE_TYPE_INT);
|
||||
if (rc != SANE_STATUS_GOOD)
|
||||
return rc;
|
||||
|
||||
return psane_control_option(h, optno, SANE_ACTION_SET_VALUE, (void *) &val, status);
|
||||
}
|
||||
|
||||
SANE_Status sane_option_probe_resolution(SANE_Handle h, const char *option_name, SANE_Int *minval, SANE_Int *maxval, SANE_Int *quant)
|
||||
{
|
||||
SANE_Status rc;
|
||||
int optno;
|
||||
const SANE_Option_Descriptor *opt;
|
||||
|
||||
rc = sane_find_option(h, option_name, &opt, &optno, SANE_TYPE_INT);
|
||||
if (rc != SANE_STATUS_GOOD)
|
||||
return rc;
|
||||
|
||||
if (opt->constraint_type != SANE_CONSTRAINT_RANGE)
|
||||
return SANE_STATUS_UNSUPPORTED;
|
||||
|
||||
*minval = opt->constraint.range->min;
|
||||
*maxval = opt->constraint.range->max;
|
||||
*quant = opt->constraint.range->quant;
|
||||
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
|
@ -53,6 +53,8 @@ MAKE_FUNCPTR(sane_strstatus)
|
||||
|
||||
extern HINSTANCE SANE_instance;
|
||||
|
||||
#define TWCC_CHECKSTATUS (TWCC_CUSTOMBASE + 1)
|
||||
|
||||
/* internal information about an active data source */
|
||||
struct tagActiveDS
|
||||
{
|
||||
@ -73,6 +75,10 @@ struct tagActiveDS
|
||||
/* Capabilities */
|
||||
TW_UINT16 capXferMech; /* ICAP_XFERMECH */
|
||||
TW_UINT16 capPixelType; /* ICAP_PIXELTYPE */
|
||||
BOOL XResolutionSet;
|
||||
TW_FIX32 defaultXResolution;
|
||||
BOOL YResolutionSet;
|
||||
TW_FIX32 defaultYResolution;
|
||||
} activeDS;
|
||||
|
||||
/* Helper functions */
|
||||
@ -214,6 +220,8 @@ HWND ScanningDialogBox(HWND dialog, LONG progress);
|
||||
/* Option functions */
|
||||
#ifdef SONAME_LIBSANE
|
||||
SANE_Status sane_option_get_int(SANE_Handle h, const char *option_name, SANE_Int *val);
|
||||
SANE_Status sane_option_set_int(SANE_Handle h, const char *option_name, SANE_Int val, SANE_Int *status);
|
||||
SANE_Status sane_option_probe_resolution(SANE_Handle h, const char *option_name, SANE_Int *minval, SANE_Int *maxval, SANE_Int *quant);
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -267,6 +267,127 @@ static void test_onevalue_cap(TW_IDENTITY *appid, TW_IDENTITY *source, TW_UINT16
|
||||
}
|
||||
}
|
||||
|
||||
static void test_resolution(TW_IDENTITY *appid, TW_IDENTITY *source, TW_UINT16 captype, TW_INT32 minimum_support)
|
||||
{
|
||||
TW_UINT16 rc;
|
||||
TW_STATUS status;
|
||||
TW_CAPABILITY cap;
|
||||
TW_UINT32 val;
|
||||
TW_UINT16 type;
|
||||
TW_INT32 actual_support;
|
||||
TW_FIX32 orig_value = { 0, 0 };
|
||||
TW_UINT32 new_value = 0;
|
||||
TW_FIX32 default_value = { 0, 0 };
|
||||
|
||||
memset(&cap, 0, sizeof(cap));
|
||||
cap.Cap = captype;
|
||||
cap.ConType = TWON_DONTCARE16;
|
||||
|
||||
rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_QUERYSUPPORT, &cap);
|
||||
get_condition_code(appid, source, &status);
|
||||
ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
|
||||
"Error [rc %d|cc %d] doing MSG_QUERYSUPPORT for type 0x%x\n", rc, status.ConditionCode, captype);
|
||||
if (rc != TWRC_SUCCESS)
|
||||
return;
|
||||
ok(get_onevalue(cap.hContainer, (TW_UINT32 *) &actual_support, NULL), "Returned cap.hContainer invalid for QuerySupport on type 0x%x\n", captype);
|
||||
ok((actual_support & minimum_support) == minimum_support,
|
||||
"Error: minimum support 0x%x for type 0x%x, got 0x%x\n", minimum_support,
|
||||
captype, actual_support);
|
||||
|
||||
|
||||
if (actual_support & TWQC_GETCURRENT)
|
||||
{
|
||||
memset(&cap, 0, sizeof(cap));
|
||||
cap.Cap = captype;
|
||||
cap.ConType = TWON_DONTCARE16;
|
||||
|
||||
rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_GETCURRENT, &cap);
|
||||
get_condition_code(appid, source, &status);
|
||||
ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
|
||||
"Error [rc %d|cc %d] doing MSG_GETCURRENT for type 0x%x\n", rc, status.ConditionCode, captype);
|
||||
if (rc == TWRC_SUCCESS)
|
||||
{
|
||||
get_onevalue(cap.hContainer, &val, &type);
|
||||
ok(type == TWTY_FIX32, "GETCURRENT for RESOLUTION is not type FIX32, is type %d\n", type);
|
||||
memcpy(&orig_value, &val, sizeof(orig_value));
|
||||
GlobalFree(cap.hContainer);
|
||||
}
|
||||
}
|
||||
|
||||
if (actual_support & TWQC_GETDEFAULT)
|
||||
{
|
||||
memset(&cap, 0, sizeof(cap));
|
||||
cap.Cap = captype;
|
||||
cap.ConType = TWON_DONTCARE16;
|
||||
|
||||
rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_GETDEFAULT, &cap);
|
||||
get_condition_code(appid, source, &status);
|
||||
ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
|
||||
"Error [rc %d|cc %d] doing MSG_GETDEFAULT for type 0x%x\n", rc, status.ConditionCode, captype);
|
||||
if (rc == TWRC_SUCCESS)
|
||||
{
|
||||
ok(type == TWTY_FIX32, "GETDEFAULT for RESOLUTION is not type FIX32, is type %d\n", type);
|
||||
memcpy(&default_value, &val, sizeof(default_value));
|
||||
GlobalFree(cap.hContainer);
|
||||
}
|
||||
}
|
||||
|
||||
if (actual_support & TWQC_GET)
|
||||
{
|
||||
memset(&cap, 0, sizeof(cap));
|
||||
cap.Cap = captype;
|
||||
cap.ConType = TWON_DONTCARE16;
|
||||
|
||||
rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_GET, &cap);
|
||||
get_condition_code(appid, source, &status);
|
||||
ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
|
||||
"Error [rc %d|cc %d] doing MSG_GET for type 0x%x\n", rc, status.ConditionCode, captype);
|
||||
if (rc == TWRC_SUCCESS)
|
||||
{
|
||||
TW_RANGE *range;
|
||||
ok(cap.ConType == TWON_RANGE, "MSG_GET for ICAP_[XY]RESOLUTION did not return TWON_RANGE, but %d\n", cap.ConType);
|
||||
range = GlobalLock(cap.hContainer);
|
||||
trace("MSG_GET of 0x%x returned [ItemType %d|MinValue %d|MaxValue %d|StepSize %d|DefaultValue %d|CurrentValue %d]:\n",
|
||||
cap.Cap, range->ItemType, range->MinValue, range->MaxValue, range->StepSize,
|
||||
range->DefaultValue, range->CurrentValue);
|
||||
for (new_value = range->MinValue; new_value < range->MaxValue; new_value += range->StepSize)
|
||||
if (new_value != range->CurrentValue)
|
||||
break;
|
||||
GlobalUnlock(cap.hContainer);
|
||||
GlobalFree(cap.hContainer);
|
||||
}
|
||||
}
|
||||
|
||||
if (actual_support & TWQC_SET)
|
||||
{
|
||||
memset(&cap, 0, sizeof(cap));
|
||||
cap.Cap = captype;
|
||||
cap.ConType = TWON_ONEVALUE;
|
||||
cap.hContainer = alloc_and_set_onevalue(new_value, TWTY_FIX32);
|
||||
|
||||
rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_SET, &cap);
|
||||
get_condition_code(appid, source, &status);
|
||||
ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
|
||||
"Error [rc %d|cc %d] doing MSG_SET for type 0x%x\n", rc, status.ConditionCode, captype);
|
||||
GlobalFree(cap.hContainer);
|
||||
|
||||
}
|
||||
|
||||
if (actual_support & TWQC_RESET)
|
||||
{
|
||||
memset(&cap, 0, sizeof(cap));
|
||||
cap.Cap = captype;
|
||||
cap.ConType = TWON_DONTCARE16;
|
||||
|
||||
rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_RESET, &cap);
|
||||
get_condition_code(appid, source, &status);
|
||||
ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
|
||||
"Error [rc %d|cc %d] doing MSG_RESET for type 0x%x\n", rc, status.ConditionCode, captype);
|
||||
if (rc == TWRC_SUCCESS)
|
||||
GlobalFree(cap.hContainer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void test_single_source(TW_IDENTITY *appid, TW_IDENTITY *source)
|
||||
{
|
||||
@ -356,10 +477,14 @@ static void test_single_source(TW_IDENTITY *appid, TW_IDENTITY *source)
|
||||
if (capabilities[ICAP_XFERMECH])
|
||||
test_onevalue_cap(appid, source, ICAP_XFERMECH, TWTY_UINT16,
|
||||
TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET);
|
||||
todo_wine
|
||||
ok(capabilities[ICAP_XRESOLUTION], "ICAP_XRESOLUTION not supported\n");
|
||||
todo_wine
|
||||
if (capabilities[ICAP_XRESOLUTION])
|
||||
test_resolution(appid, source, ICAP_XRESOLUTION,
|
||||
TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET);
|
||||
ok(capabilities[ICAP_YRESOLUTION], "ICAP_YRESOLUTION not supported\n");
|
||||
if (capabilities[ICAP_YRESOLUTION])
|
||||
test_resolution(appid, source, ICAP_YRESOLUTION,
|
||||
TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user