sane.ds: Implement support for ICAP_PHYSICALHEIGHT and ICAP_PHYSICALWIDTH.
This commit is contained in:
parent
e976158fe7
commit
eae4ac9e8f
|
@ -22,6 +22,8 @@
|
|||
#include "config.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
|
@ -165,7 +167,7 @@ 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_UNITS, ICAP_BITDEPTH, ICAP_COMPRESSION, ICAP_PIXELFLAVOR,
|
||||
ICAP_XRESOLUTION, ICAP_YRESOLUTION };
|
||||
ICAP_XRESOLUTION, ICAP_YRESOLUTION, ICAP_PHYSICALHEIGHT, ICAP_PHYSICALWIDTH };
|
||||
|
||||
pCapability->hContainer = GlobalAlloc (0, FIELD_OFFSET( TW_ARRAY, ItemList[sizeof(supported_caps)] ));
|
||||
pCapability->ConType = TWON_ARRAY;
|
||||
|
@ -692,6 +694,81 @@ static TW_UINT16 SANE_ICAPResolution (pTW_CAPABILITY pCapability, TW_UINT16 acti
|
|||
return twCC;
|
||||
}
|
||||
|
||||
static void convert_double_fix32(double d, TW_FIX32 *fix32)
|
||||
{
|
||||
TW_INT32 value = (TW_INT32) (d * 65536.0 + 0.5);
|
||||
fix32->Whole = value >> 16;
|
||||
fix32->Frac = value & 0x0000ffffL;
|
||||
}
|
||||
|
||||
|
||||
#ifdef SONAME_LIBSANE
|
||||
static BOOL convert_sane_res_to_twain(double sane_res, SANE_Unit unit, TW_FIX32 *twain_res, TW_UINT16 twtype)
|
||||
{
|
||||
double d;
|
||||
|
||||
if (unit != SANE_UNIT_MM)
|
||||
return FALSE;
|
||||
|
||||
if (twtype != TWUN_INCHES)
|
||||
return FALSE;
|
||||
|
||||
d = (sane_res / 10.0) / 2.54;
|
||||
convert_double_fix32((sane_res / 10.0) / 2.54, twain_res);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ICAP_PHYSICALHEIGHT, ICAP_PHYSICALWIDTH */
|
||||
static TW_UINT16 SANE_ICAPPhysical (pTW_CAPABILITY pCapability, TW_UINT16 action, TW_UINT16 cap)
|
||||
{
|
||||
TW_UINT16 twCC = TWCC_BADCAP;
|
||||
#ifdef SONAME_LIBSANE
|
||||
TW_FIX32 res;
|
||||
char option_name[64];
|
||||
SANE_Fixed lower, upper;
|
||||
SANE_Unit lowerunit, upperunit;
|
||||
SANE_Status status;
|
||||
|
||||
TRACE("ICAP_PHYSICAL%s\n", cap == ICAP_PHYSICALHEIGHT? "HEIGHT" : "WIDTH");
|
||||
|
||||
sprintf(option_name, "tl-%c", cap == ICAP_PHYSICALHEIGHT ? 'y' : 'x');
|
||||
status = sane_option_probe_scan_area(activeDS.deviceHandle, option_name, NULL, &lowerunit, &lower, NULL, NULL);
|
||||
if (status != SANE_STATUS_GOOD)
|
||||
return sane_status_to_twcc(status);
|
||||
|
||||
sprintf(option_name, "br-%c", cap == ICAP_PHYSICALHEIGHT ? 'y' : 'x');
|
||||
status = sane_option_probe_scan_area(activeDS.deviceHandle, option_name, NULL, &upperunit, NULL, &upper, NULL);
|
||||
if (status != SANE_STATUS_GOOD)
|
||||
return sane_status_to_twcc(status);
|
||||
|
||||
if (upperunit != lowerunit)
|
||||
return TWCC_BADCAP;
|
||||
|
||||
if (! convert_sane_res_to_twain(SANE_UNFIX(upper) - SANE_UNFIX(lower), upperunit, &res, TWUN_INCHES))
|
||||
return TWCC_BADCAP;
|
||||
|
||||
switch (action)
|
||||
{
|
||||
case MSG_QUERYSUPPORT:
|
||||
twCC = set_onevalue(pCapability, TWTY_INT32,
|
||||
TWQC_GET | TWQC_GETDEFAULT | TWQC_GETCURRENT );
|
||||
break;
|
||||
|
||||
case MSG_GET:
|
||||
case MSG_GETDEFAULT:
|
||||
|
||||
/* .. fall through intentional .. */
|
||||
|
||||
case MSG_GETCURRENT:
|
||||
twCC = set_onevalue(pCapability, TWTY_FIX32, res.Whole | (res.Frac << 16));
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
return twCC;
|
||||
}
|
||||
|
||||
/* ICAP_PIXELFLAVOR */
|
||||
static TW_UINT16 SANE_ICAPPixelFlavor (pTW_CAPABILITY pCapability, TW_UINT16 action)
|
||||
{
|
||||
|
@ -793,6 +870,15 @@ TW_UINT16 SANE_SaneCapability (pTW_CAPABILITY pCapability, TW_UINT16 action)
|
|||
case ICAP_YRESOLUTION:
|
||||
twCC = SANE_ICAPResolution(pCapability, action, pCapability->Cap);
|
||||
break;
|
||||
|
||||
case ICAP_PHYSICALHEIGHT:
|
||||
twCC = SANE_ICAPPhysical(pCapability, action, pCapability->Cap);
|
||||
break;
|
||||
|
||||
case ICAP_PHYSICALWIDTH:
|
||||
twCC = SANE_ICAPPhysical(pCapability, action, pCapability->Cap);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
/* Twain specifies that you should return a 0 in response to QUERYSUPPORT,
|
||||
|
|
|
@ -137,4 +137,30 @@ SANE_Status sane_option_probe_mode(SANE_Handle h, SANE_String_Const **choices, c
|
|||
return SANE_STATUS_NO_MEM;
|
||||
|
||||
}
|
||||
|
||||
SANE_Status sane_option_probe_scan_area(SANE_Handle h, const char *option_name, SANE_Fixed *val,
|
||||
SANE_Unit *unit, SANE_Fixed *min, SANE_Fixed *max, SANE_Fixed *quant)
|
||||
{
|
||||
SANE_Status rc;
|
||||
int optno;
|
||||
const SANE_Option_Descriptor *opt;
|
||||
|
||||
rc = sane_find_option(h, option_name, &opt, &optno, SANE_TYPE_FIXED);
|
||||
if (rc != SANE_STATUS_GOOD)
|
||||
return rc;
|
||||
|
||||
if (unit)
|
||||
*unit = opt->unit;
|
||||
if (min)
|
||||
*min = opt->constraint.range->min;
|
||||
if (max)
|
||||
*max = opt->constraint.range->max;
|
||||
if (quant)
|
||||
*quant = opt->constraint.range->quant;
|
||||
|
||||
if (val)
|
||||
rc = psane_control_option(h, optno, SANE_ACTION_GET_VALUE, val, NULL);
|
||||
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -226,6 +226,8 @@ SANE_Status sane_option_set_int(SANE_Handle h, const char *option_name, SANE_Int
|
|||
SANE_Status sane_option_set_str(SANE_Handle h, const char *option_name, SANE_String 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);
|
||||
SANE_Status sane_option_probe_mode(SANE_Handle h, SANE_String_Const **choices, char *current, int current_size);
|
||||
SANE_Status sane_option_probe_scan_area(SANE_Handle h, const char *option_name, SANE_Fixed *val,
|
||||
SANE_Unit *unit, SANE_Fixed *min, SANE_Fixed *max, SANE_Fixed *quant);
|
||||
#endif
|
||||
|
||||
|
||||
|
|
|
@ -391,6 +391,88 @@ static void test_resolution(TW_IDENTITY *appid, TW_IDENTITY *source, TW_UINT16 c
|
|||
}
|
||||
}
|
||||
|
||||
static void test_physical(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;
|
||||
|
||||
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 PHYSICALXXX is not type FIX32, is type %d\n", type);
|
||||
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)
|
||||
{
|
||||
get_onevalue(cap.hContainer, &val, &type);
|
||||
ok(type == TWTY_FIX32, "GETDEFAULT for PHYSICALXXX is not type FIX32, is type %d\n", type);
|
||||
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)
|
||||
{
|
||||
get_onevalue(cap.hContainer, &val, &type);
|
||||
ok(type == TWTY_FIX32, "GET for PHYSICALXXX is not type FIX32, is type %d\n", type);
|
||||
trace("GET for Physical type 0x%x returns 0x%x\n", captype, val);
|
||||
GlobalFree(cap.hContainer);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void test_single_source(TW_IDENTITY *appid, TW_IDENTITY *source)
|
||||
{
|
||||
|
@ -453,10 +535,14 @@ static void test_single_source(TW_IDENTITY *appid, TW_IDENTITY *source)
|
|||
TWQC_GET | TWQC_GETDEFAULT | TWQC_GETCURRENT);
|
||||
todo_wine
|
||||
ok(capabilities[ICAP_PLANARCHUNKY], "ICAP_PLANARCHUNKY not supported\n");
|
||||
todo_wine
|
||||
ok(capabilities[ICAP_PHYSICALHEIGHT], "ICAP_PHYSICALHEIGHT not supported\n");
|
||||
todo_wine
|
||||
if (capabilities[ICAP_PHYSICALHEIGHT])
|
||||
test_physical(appid, source, ICAP_PHYSICALHEIGHT,
|
||||
TWQC_GET | TWQC_GETDEFAULT | TWQC_GETCURRENT);
|
||||
ok(capabilities[ICAP_PHYSICALWIDTH], "ICAP_PHYSICALWIDTH not supported\n");
|
||||
if (capabilities[ICAP_PHYSICALWIDTH])
|
||||
test_physical(appid, source, ICAP_PHYSICALWIDTH,
|
||||
TWQC_GET | TWQC_GETDEFAULT | TWQC_GETCURRENT);
|
||||
ok(capabilities[ICAP_PIXELFLAVOR], "ICAP_PIXELFLAVOR not supported\n");
|
||||
if (capabilities[ICAP_PIXELFLAVOR])
|
||||
test_onevalue_cap(appid, source, ICAP_PIXELFLAVOR, TWTY_UINT16,
|
||||
|
|
Loading…
Reference in New Issue