sane.ds: Fully support ICAP_PIXELTYPE.
[wine/multimedia.git] / dlls / sane.ds / capability.c
blob06047343742837ec1396b2484f9bd831bcc85ab7
1 /*
2 * Copyright 2000 Corel Corporation
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #define NONAMELESSUNION
20 #define NONAMELESSSTRUCT
22 #include "config.h"
24 #include <stdarg.h>
26 #include "windef.h"
27 #include "winbase.h"
28 #include "twain.h"
29 #include "sane_i.h"
30 #include "wine/debug.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(twain);
34 static TW_UINT16 get_onevalue(pTW_CAPABILITY pCapability, TW_UINT16 *type, TW_UINT32 *value)
36 if (pCapability->hContainer)
38 pTW_ONEVALUE pVal = GlobalLock (pCapability->hContainer);
39 if (pVal)
41 *value = pVal->Item;
42 if (type)
43 *type = pVal->ItemType;
44 GlobalUnlock (pCapability->hContainer);
45 return TWCC_SUCCESS;
48 return TWCC_BUMMER;
52 static TW_UINT16 set_onevalue(pTW_CAPABILITY pCapability, TW_UINT16 type, TW_UINT32 value)
54 pCapability->hContainer = GlobalAlloc (0, sizeof(TW_ONEVALUE));
56 if (pCapability->hContainer)
58 pTW_ONEVALUE pVal = GlobalLock (pCapability->hContainer);
59 if (pVal)
61 pCapability->ConType = TWON_ONEVALUE;
62 pVal->ItemType = type;
63 pVal->Item = value;
64 GlobalUnlock (pCapability->hContainer);
65 return TWCC_SUCCESS;
68 return TWCC_LOWMEMORY;
71 static TW_UINT16 msg_set(pTW_CAPABILITY pCapability, TW_UINT32 *val)
73 if (pCapability->ConType == TWON_ONEVALUE)
74 return get_onevalue(pCapability, NULL, val);
76 FIXME("Partial Stub: MSG_SET only supports TW_ONEVALUE\n");
77 return TWCC_BADCAP;
81 static TW_UINT16 msg_get_enum(pTW_CAPABILITY pCapability, const TW_UINT32 *values, int value_count,
82 TW_UINT16 type, TW_UINT32 current, TW_UINT32 default_value)
84 TW_ENUMERATION *enumv = NULL;
85 TW_UINT32 *p32;
86 TW_UINT16 *p16;
87 int i;
89 pCapability->ConType = TWON_ENUMERATION;
90 pCapability->hContainer = 0;
92 if (type == TWTY_INT16 || type == TWTY_UINT16)
93 pCapability->hContainer = GlobalAlloc (0, FIELD_OFFSET( TW_ENUMERATION, ItemList[value_count * sizeof(TW_UINT16)]));
95 if (type == TWTY_INT32 || type == TWTY_UINT32)
96 pCapability->hContainer = GlobalAlloc (0, FIELD_OFFSET( TW_ENUMERATION, ItemList[value_count * sizeof(TW_UINT32)]));
98 if (pCapability->hContainer)
99 enumv = GlobalLock(pCapability->hContainer);
101 if (! enumv)
102 return TWCC_LOWMEMORY;
104 enumv->ItemType = type;
105 enumv->NumItems = value_count;
107 p16 = (TW_UINT16 *) enumv->ItemList;
108 p32 = (TW_UINT32 *) enumv->ItemList;
109 for (i = 0; i < value_count; i++)
111 if (values[i] == current)
112 enumv->CurrentIndex = i;
113 if (values[i] == default_value)
114 enumv->DefaultIndex = i;
115 if (type == TWTY_INT16 || type == TWTY_UINT16)
116 p16[i] = values[i];
117 if (type == TWTY_INT32 || type == TWTY_UINT32)
118 p32[i] = values[i];
121 GlobalUnlock(pCapability->hContainer);
122 return TWCC_SUCCESS;
125 #ifdef SONAME_LIBSANE
126 static TW_UINT16 msg_get_range(pTW_CAPABILITY pCapability, TW_UINT16 type,
127 TW_UINT32 minval, TW_UINT32 maxval, TW_UINT32 step, TW_UINT32 def, TW_UINT32 current)
129 TW_RANGE *range = NULL;
131 pCapability->ConType = TWON_RANGE;
132 pCapability->hContainer = 0;
134 pCapability->hContainer = GlobalAlloc (0, sizeof(*range));
135 if (pCapability->hContainer)
136 range = GlobalLock(pCapability->hContainer);
138 if (! range)
139 return TWCC_LOWMEMORY;
141 range->ItemType = type;
142 range->MinValue = minval;
143 range->MaxValue = maxval;
144 range->StepSize = step;
145 range->DefaultValue = def;
146 range->CurrentValue = current;
148 GlobalUnlock(pCapability->hContainer);
149 return TWCC_SUCCESS;
151 #endif
153 static TW_UINT16 TWAIN_GetSupportedCaps(pTW_CAPABILITY pCapability)
155 TW_ARRAY *a;
156 static const UINT16 supported_caps[] = { CAP_SUPPORTEDCAPS, CAP_XFERCOUNT, CAP_UICONTROLLABLE,
157 ICAP_XFERMECH, ICAP_PIXELTYPE, ICAP_UNITS, ICAP_BITDEPTH, ICAP_COMPRESSION, ICAP_PIXELFLAVOR,
158 ICAP_XRESOLUTION, ICAP_YRESOLUTION };
160 pCapability->hContainer = GlobalAlloc (0, FIELD_OFFSET( TW_ARRAY, ItemList[sizeof(supported_caps)] ));
161 pCapability->ConType = TWON_ARRAY;
163 if (pCapability->hContainer)
165 UINT16 *u;
166 int i;
167 a = GlobalLock (pCapability->hContainer);
168 a->ItemType = TWTY_UINT16;
169 a->NumItems = sizeof(supported_caps) / sizeof(supported_caps[0]);
170 u = (UINT16 *) a->ItemList;
171 for (i = 0; i < a->NumItems; i++)
172 u[i] = supported_caps[i];
173 GlobalUnlock (pCapability->hContainer);
174 return TWCC_SUCCESS;
176 else
177 return TWCC_LOWMEMORY;
181 /* ICAP_XFERMECH */
182 static TW_UINT16 SANE_ICAPXferMech (pTW_CAPABILITY pCapability, TW_UINT16 action)
184 static const TW_UINT32 possible_values[] = { TWSX_NATIVE, TWSX_MEMORY };
185 TW_UINT32 val;
186 TW_UINT16 twCC = TWCC_BADCAP;
188 TRACE("ICAP_XFERMECH\n");
190 switch (action)
192 case MSG_QUERYSUPPORT:
193 twCC = set_onevalue(pCapability, TWTY_INT32,
194 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET );
195 break;
197 case MSG_GET:
198 twCC = msg_get_enum(pCapability, possible_values, sizeof(possible_values) / sizeof(possible_values[0]),
199 TWTY_UINT16, activeDS.capXferMech, TWSX_NATIVE);
200 break;
202 case MSG_SET:
203 twCC = msg_set(pCapability, &val);
204 if (twCC == TWCC_SUCCESS)
206 activeDS.capXferMech = (TW_UINT16) val;
207 FIXME("Partial Stub: XFERMECH set to %d, but ignored\n", val);
209 break;
211 case MSG_GETDEFAULT:
212 twCC = set_onevalue(pCapability, TWTY_UINT16, TWSX_NATIVE);
213 break;
215 case MSG_RESET:
216 activeDS.capXferMech = TWSX_NATIVE;
217 /* .. fall through intentional .. */
219 case MSG_GETCURRENT:
220 twCC = set_onevalue(pCapability, TWTY_UINT16, activeDS.capXferMech);
221 FIXME("Partial Stub: XFERMECH of %d not actually used\n", activeDS.capXferMech);
222 break;
224 return twCC;
228 /* CAP_XFERCOUNT */
229 static TW_UINT16 SANE_CAPXferCount (pTW_CAPABILITY pCapability, TW_UINT16 action)
231 TW_UINT32 val;
232 TW_UINT16 twCC = TWCC_BADCAP;
234 TRACE("CAP_XFERCOUNT\n");
236 switch (action)
238 case MSG_QUERYSUPPORT:
239 twCC = set_onevalue(pCapability, TWTY_INT32,
240 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET );
241 break;
243 case MSG_GET:
244 twCC = set_onevalue(pCapability, TWTY_INT16, -1);
245 FIXME("Partial Stub: Reporting only support for transfer all\n");
246 break;
248 case MSG_SET:
249 twCC = msg_set(pCapability, &val);
250 if (twCC == TWCC_SUCCESS)
251 FIXME("Partial Stub: XFERCOUNT set to %d, but ignored\n", val);
252 break;
254 case MSG_GETDEFAULT:
255 twCC = set_onevalue(pCapability, TWTY_INT16, -1);
256 break;
258 case MSG_RESET:
259 /* .. fall through intentional .. */
261 case MSG_GETCURRENT:
262 twCC = set_onevalue(pCapability, TWTY_INT16, -1);
263 break;
265 return twCC;
268 #ifdef SONAME_LIBSANE
269 static BOOL pixeltype_to_sane_mode(TW_UINT16 pixeltype, SANE_String mode, int len)
271 SANE_String_Const m = NULL;
272 switch (pixeltype)
274 case TWPT_GRAY:
275 m = SANE_VALUE_SCAN_MODE_GRAY;
276 break;
277 case TWPT_RGB:
278 m = SANE_VALUE_SCAN_MODE_COLOR;
279 break;
280 case TWPT_BW:
281 m = SANE_VALUE_SCAN_MODE_LINEART;
282 break;
284 if (! m)
285 return FALSE;
286 if (strlen(m) >= len)
287 return FALSE;
288 strcpy(mode, m);
289 return TRUE;
291 static BOOL sane_mode_to_pixeltype(SANE_String_Const mode, TW_UINT16 *pixeltype)
293 if (strcmp(mode, SANE_VALUE_SCAN_MODE_LINEART) == 0)
294 *pixeltype = TWPT_BW;
295 else if (memcmp(mode, SANE_VALUE_SCAN_MODE_GRAY, strlen(SANE_VALUE_SCAN_MODE_GRAY)) == 0)
296 *pixeltype = TWPT_GRAY;
297 else if (strcmp(mode, SANE_VALUE_SCAN_MODE_COLOR) == 0)
298 *pixeltype = TWPT_RGB;
299 else
300 return FALSE;
302 return TRUE;
305 static TW_UINT16 sane_status_to_twcc(SANE_Status rc)
307 switch (rc)
309 case SANE_STATUS_GOOD:
310 return TWCC_SUCCESS;
311 case SANE_STATUS_UNSUPPORTED:
312 return TWCC_CAPUNSUPPORTED;
313 case SANE_STATUS_JAMMED:
314 return TWCC_PAPERJAM;
315 case SANE_STATUS_NO_MEM:
316 return TWCC_LOWMEMORY;
317 case SANE_STATUS_ACCESS_DENIED:
318 return TWCC_DENIED;
320 case SANE_STATUS_IO_ERROR:
321 case SANE_STATUS_NO_DOCS:
322 case SANE_STATUS_COVER_OPEN:
323 case SANE_STATUS_EOF:
324 case SANE_STATUS_INVAL:
325 case SANE_STATUS_CANCELLED:
326 case SANE_STATUS_DEVICE_BUSY:
327 default:
328 return TWCC_BUMMER;
331 #endif
333 /* ICAP_PIXELTYPE */
334 static TW_UINT16 SANE_ICAPPixelType (pTW_CAPABILITY pCapability, TW_UINT16 action)
336 TW_UINT16 twCC = TWCC_BADCAP;
337 #ifdef SONAME_LIBSANE
338 TW_UINT32 possible_values[3];
339 int possible_value_count;
340 TW_UINT32 val;
341 SANE_Status rc;
342 SANE_Int status;
343 SANE_String_Const *choices;
344 char current_mode[64];
345 TW_UINT16 current_pixeltype = TWPT_BW;
346 SANE_Char mode[64];
348 TRACE("ICAP_PIXELTYPE\n");
350 rc = sane_option_probe_mode(activeDS.deviceHandle, &choices, current_mode, sizeof(current_mode));
351 if (rc != SANE_STATUS_GOOD)
353 ERR("Unable to retrieve mode from sane, ICAP_PIXELTYPE unsupported\n");
354 return twCC;
357 sane_mode_to_pixeltype(current_mode, &current_pixeltype);
359 /* Sane does not support a concept of a default mode, so we simply cache
360 * the first mode we find */
361 if (! activeDS.PixelTypeSet)
363 activeDS.PixelTypeSet = TRUE;
364 activeDS.defaultPixelType = current_pixeltype;
367 switch (action)
369 case MSG_QUERYSUPPORT:
370 twCC = set_onevalue(pCapability, TWTY_INT32,
371 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET );
372 break;
374 case MSG_GET:
375 for (possible_value_count = 0; choices && *choices && possible_value_count < 3; choices++)
377 TW_UINT16 pix;
378 if (sane_mode_to_pixeltype(*choices, &pix))
379 possible_values[possible_value_count++] = pix;
381 twCC = msg_get_enum(pCapability, possible_values, possible_value_count,
382 TWTY_UINT16, current_pixeltype, activeDS.defaultPixelType);
383 break;
385 case MSG_SET:
386 twCC = msg_set(pCapability, &val);
387 if (twCC == TWCC_SUCCESS)
389 if (! pixeltype_to_sane_mode(val, mode, sizeof(mode)))
390 return TWCC_BADVALUE;
392 status = 0;
393 rc = sane_option_set_str(activeDS.deviceHandle, "mode", mode, &status);
394 /* Some SANE devices use 'Grayscale' instead of the standard 'Gray' */
395 if (rc == SANE_STATUS_INVAL && strcmp(mode, SANE_VALUE_SCAN_MODE_GRAY) == 0)
397 strcpy(mode, "Grayscale");
398 rc = sane_option_set_str(activeDS.deviceHandle, "mode", mode, &status);
400 if (rc != SANE_STATUS_GOOD)
401 return sane_status_to_twcc(rc);
402 if (status & SANE_INFO_RELOAD_PARAMS)
403 psane_get_parameters (activeDS.deviceHandle, &activeDS.sane_param);
405 break;
407 case MSG_GETDEFAULT:
408 twCC = set_onevalue(pCapability, TWTY_UINT16, activeDS.defaultPixelType);
409 break;
411 case MSG_RESET:
412 current_pixeltype = activeDS.defaultPixelType;
413 if (! pixeltype_to_sane_mode(current_pixeltype, mode, sizeof(mode)))
414 return TWCC_BADVALUE;
416 status = 0;
417 rc = sane_option_set_str(activeDS.deviceHandle, "mode", mode, &status);
418 /* Some SANE devices use 'Grayscale' instead of the standard 'Gray' */
419 if (rc == SANE_STATUS_INVAL && strcmp(mode, SANE_VALUE_SCAN_MODE_GRAY) == 0)
421 strcpy(mode, "Grayscale");
422 rc = sane_option_set_str(activeDS.deviceHandle, "mode", mode, &status);
424 if (rc != SANE_STATUS_GOOD)
425 return sane_status_to_twcc(rc);
426 if (status & SANE_INFO_RELOAD_PARAMS)
427 psane_get_parameters (activeDS.deviceHandle, &activeDS.sane_param);
429 /* .. fall through intentional .. */
431 case MSG_GETCURRENT:
432 twCC = set_onevalue(pCapability, TWTY_UINT16, current_pixeltype);
433 break;
436 #endif
437 return twCC;
440 /* ICAP_UNITS */
441 static TW_UINT16 SANE_ICAPUnits (pTW_CAPABILITY pCapability, TW_UINT16 action)
443 TW_UINT32 val;
444 TW_UINT16 twCC = TWCC_BADCAP;
446 TRACE("ICAP_UNITS\n");
448 switch (action)
450 case MSG_QUERYSUPPORT:
451 twCC = set_onevalue(pCapability, TWTY_INT32,
452 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET );
453 break;
455 case MSG_GET:
456 twCC = set_onevalue(pCapability, TWTY_UINT16, TWUN_INCHES);
457 break;
459 case MSG_SET:
460 twCC = msg_set(pCapability, &val);
461 if (twCC == TWCC_SUCCESS)
463 if (val != TWUN_INCHES)
465 ERR("Sane supports only SANE_UNIT_DPI\n");
466 twCC = TWCC_BADVALUE;
469 break;
471 case MSG_GETDEFAULT:
472 case MSG_RESET:
473 /* .. fall through intentional .. */
475 case MSG_GETCURRENT:
476 twCC = set_onevalue(pCapability, TWTY_UINT16, TWUN_INCHES);
477 break;
480 return twCC;
483 /* ICAP_BITDEPTH */
484 static TW_UINT16 SANE_ICAPBitDepth(pTW_CAPABILITY pCapability, TW_UINT16 action)
486 TW_UINT16 twCC = TWCC_BADCAP;
487 #ifdef SONAME_LIBSANE
488 TW_UINT32 possible_values[1];
490 TRACE("ICAP_BITDEPTH\n");
492 possible_values[0] = activeDS.sane_param.depth;
494 switch (action)
496 case MSG_QUERYSUPPORT:
497 twCC = set_onevalue(pCapability, TWTY_INT32,
498 TWQC_GET | TWQC_GETDEFAULT | TWQC_GETCURRENT );
499 break;
501 case MSG_GET:
502 twCC = msg_get_enum(pCapability, possible_values, sizeof(possible_values) / sizeof(possible_values[0]),
503 TWTY_UINT16, activeDS.sane_param.depth, activeDS.sane_param.depth);
504 break;
506 case MSG_GETDEFAULT:
507 /* .. Fall through intentional .. */
509 case MSG_GETCURRENT:
510 twCC = set_onevalue(pCapability, TWTY_UINT16, activeDS.sane_param.depth);
511 break;
513 #endif
514 return twCC;
517 /* CAP_UICONTROLLABLE */
518 static TW_UINT16 SANE_CAPUiControllable(pTW_CAPABILITY pCapability, TW_UINT16 action)
520 TW_UINT16 twCC = TWCC_BADCAP;
522 TRACE("CAP_UICONTROLLABLE\n");
524 switch (action)
526 case MSG_QUERYSUPPORT:
527 twCC = set_onevalue(pCapability, TWTY_INT32, TWQC_GET);
528 break;
530 case MSG_GET:
531 twCC = set_onevalue(pCapability, TWTY_BOOL, TRUE);
532 break;
535 return twCC;
538 /* ICAP_COMPRESSION */
539 static TW_UINT16 SANE_ICAPCompression (pTW_CAPABILITY pCapability, TW_UINT16 action)
541 static const TW_UINT32 possible_values[] = { TWCP_NONE };
542 TW_UINT32 val;
543 TW_UINT16 twCC = TWCC_BADCAP;
545 TRACE("ICAP_COMPRESSION\n");
547 switch (action)
549 case MSG_QUERYSUPPORT:
550 twCC = set_onevalue(pCapability, TWTY_INT32,
551 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET );
552 break;
554 case MSG_GET:
555 twCC = msg_get_enum(pCapability, possible_values, sizeof(possible_values) / sizeof(possible_values[0]),
556 TWTY_UINT16, TWCP_NONE, TWCP_NONE);
557 FIXME("Partial stub: We don't attempt to support compression\n");
558 break;
560 case MSG_SET:
561 twCC = msg_set(pCapability, &val);
562 if (twCC == TWCC_SUCCESS)
563 FIXME("Partial Stub: COMPRESSION set to %d, but ignored\n", val);
564 break;
566 case MSG_GETDEFAULT:
567 twCC = set_onevalue(pCapability, TWTY_UINT16, TWCP_NONE);
568 break;
570 case MSG_RESET:
571 /* .. fall through intentional .. */
573 case MSG_GETCURRENT:
574 twCC = set_onevalue(pCapability, TWTY_UINT16, TWCP_NONE);
575 break;
577 return twCC;
580 /* ICAP_XRESOLUTION, ICAP_YRESOLUTION */
581 static TW_UINT16 SANE_ICAPResolution (pTW_CAPABILITY pCapability, TW_UINT16 action, TW_UINT16 cap)
583 TW_UINT16 twCC = TWCC_BADCAP;
584 #ifdef SONAME_LIBSANE
585 TW_UINT32 val;
586 SANE_Int current_resolution;
587 TW_FIX32 *default_res;
588 const char *best_option_name;
589 SANE_Int minval, maxval, quantval;
590 SANE_Status sane_rc;
591 SANE_Int set_status;
593 TRACE("ICAP_%cRESOLUTION\n", cap == ICAP_XRESOLUTION ? 'X' : 'Y');
595 /* Some scanners support 'x-resolution', most seem to just support 'resolution' */
596 if (cap == ICAP_XRESOLUTION)
598 best_option_name = "x-resolution";
599 default_res = &activeDS.defaultXResolution;
601 else
603 best_option_name = "y-resolution";
604 default_res = &activeDS.defaultYResolution;
606 if (sane_option_get_int(activeDS.deviceHandle, best_option_name, &current_resolution) != SANE_STATUS_GOOD)
608 best_option_name = "resolution";
609 if (sane_option_get_int(activeDS.deviceHandle, best_option_name, &current_resolution) != SANE_STATUS_GOOD)
610 return TWCC_BADCAP;
613 /* Sane does not support a concept of 'default' resolution, so we have to
614 * cache the resolution the very first time we load the scanner, and use that
615 * as the default */
616 if (cap == ICAP_XRESOLUTION && ! activeDS.XResolutionSet)
618 default_res->Whole = current_resolution;
619 default_res->Frac = 0;
620 activeDS.XResolutionSet = TRUE;
623 if (cap == ICAP_YRESOLUTION && ! activeDS.YResolutionSet)
625 default_res->Whole = current_resolution;
626 default_res->Frac = 0;
627 activeDS.YResolutionSet = TRUE;
630 switch (action)
632 case MSG_QUERYSUPPORT:
633 twCC = set_onevalue(pCapability, TWTY_INT32,
634 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET );
635 break;
637 case MSG_GET:
638 sane_rc = sane_option_probe_resolution(activeDS.deviceHandle, best_option_name, &minval, &maxval, &quantval);
639 if (sane_rc != SANE_STATUS_GOOD)
640 twCC = TWCC_BADCAP;
641 else
642 twCC = msg_get_range(pCapability, TWTY_FIX32,
643 minval, maxval, quantval == 0 ? 1 : quantval, default_res->Whole, current_resolution);
644 break;
646 case MSG_SET:
647 twCC = msg_set(pCapability, &val);
648 if (twCC == TWCC_SUCCESS)
650 TW_FIX32 f32;
651 memcpy(&f32, &val, sizeof(f32));
652 sane_rc = sane_option_set_int(activeDS.deviceHandle, best_option_name, f32.Whole, &set_status);
653 if (sane_rc != SANE_STATUS_GOOD)
655 FIXME("Status of %d not expected or handled\n", sane_rc);
656 twCC = TWCC_BADCAP;
658 else if (set_status == SANE_INFO_INEXACT)
659 twCC = TWCC_CHECKSTATUS;
661 break;
663 case MSG_GETDEFAULT:
664 twCC = set_onevalue(pCapability, TWTY_FIX32, default_res->Whole);
665 break;
667 case MSG_RESET:
668 sane_rc = sane_option_set_int(activeDS.deviceHandle, best_option_name, default_res->Whole, NULL);
669 if (sane_rc != SANE_STATUS_GOOD)
670 return TWCC_BADCAP;
672 /* .. fall through intentional .. */
674 case MSG_GETCURRENT:
675 twCC = set_onevalue(pCapability, TWTY_FIX32, current_resolution);
676 break;
678 #endif
679 return twCC;
682 /* ICAP_PIXELFLAVOR */
683 static TW_UINT16 SANE_ICAPPixelFlavor (pTW_CAPABILITY pCapability, TW_UINT16 action)
685 static const TW_UINT32 possible_values[] = { TWPF_CHOCOLATE, TWPF_VANILLA };
686 TW_UINT32 val;
687 TW_UINT16 twCC = TWCC_BADCAP;
689 TRACE("ICAP_PIXELFLAVOR\n");
691 switch (action)
693 case MSG_QUERYSUPPORT:
694 twCC = set_onevalue(pCapability, TWTY_INT32,
695 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET );
696 break;
698 case MSG_GET:
699 twCC = msg_get_enum(pCapability, possible_values, sizeof(possible_values) / sizeof(possible_values[0]),
700 TWTY_UINT16, TWPF_CHOCOLATE, TWPF_CHOCOLATE);
701 break;
703 case MSG_SET:
704 twCC = msg_set(pCapability, &val);
705 if (twCC == TWCC_SUCCESS)
707 FIXME("Stub: PIXELFLAVOR set to %d, but ignored\n", val);
709 break;
711 case MSG_GETDEFAULT:
712 twCC = set_onevalue(pCapability, TWTY_UINT16, TWPF_CHOCOLATE);
713 break;
715 case MSG_RESET:
716 /* .. fall through intentional .. */
718 case MSG_GETCURRENT:
719 twCC = set_onevalue(pCapability, TWTY_UINT16, TWPF_CHOCOLATE);
720 break;
722 return twCC;
726 TW_UINT16 SANE_SaneCapability (pTW_CAPABILITY pCapability, TW_UINT16 action)
728 TW_UINT16 twCC = TWCC_CAPUNSUPPORTED;
730 TRACE("capability=%d action=%d\n", pCapability->Cap, action);
732 switch (pCapability->Cap)
734 case CAP_SUPPORTEDCAPS:
735 if (action == MSG_GET)
736 twCC = TWAIN_GetSupportedCaps(pCapability);
737 else
738 twCC = TWCC_BADVALUE;
739 break;
741 case CAP_XFERCOUNT:
742 twCC = SANE_CAPXferCount (pCapability, action);
743 break;
745 case CAP_UICONTROLLABLE:
746 twCC = SANE_CAPUiControllable (pCapability, action);
747 break;
749 case ICAP_PIXELTYPE:
750 twCC = SANE_ICAPPixelType (pCapability, action);
751 break;
753 case ICAP_UNITS:
754 twCC = SANE_ICAPUnits (pCapability, action);
755 break;
757 case ICAP_BITDEPTH:
758 twCC = SANE_ICAPBitDepth(pCapability, action);
759 break;
761 case ICAP_XFERMECH:
762 twCC = SANE_ICAPXferMech (pCapability, action);
763 break;
765 case ICAP_PIXELFLAVOR:
766 twCC = SANE_ICAPPixelFlavor (pCapability, action);
767 break;
769 case ICAP_COMPRESSION:
770 twCC = SANE_ICAPCompression(pCapability, action);
771 break;
773 case ICAP_XRESOLUTION:
774 twCC = SANE_ICAPResolution(pCapability, action, pCapability->Cap);
775 break;
777 case ICAP_YRESOLUTION:
778 twCC = SANE_ICAPResolution(pCapability, action, pCapability->Cap);
779 break;
782 /* Twain specifies that you should return a 0 in response to QUERYSUPPORT,
783 * even if you don't formally support the capability */
784 if (twCC == TWCC_CAPUNSUPPORTED && action == MSG_QUERYSUPPORT)
785 twCC = set_onevalue(pCapability, 0, TWTY_INT32);
787 if (twCC == TWCC_CAPUNSUPPORTED)
788 TRACE("capability 0x%x/action=%d being reported as unsupported\n", pCapability->Cap, action);
790 return twCC;