ntdll: Use a separate memory allocation for the kernel stack.
[wine.git] / dlls / sane.ds / capability.c
blob15ca4ea740a033fd07c0cfbe193bae7bbfedb1e7
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 #include <stdarg.h>
20 #include <stdio.h>
21 #include <math.h>
23 #include "sane_i.h"
24 #include "winnls.h"
25 #include "wine/debug.h"
27 WINE_DEFAULT_DEBUG_CHANNEL(twain);
29 static TW_UINT16 get_onevalue(pTW_CAPABILITY pCapability, TW_UINT16 *type, TW_UINT32 *value)
31 if (pCapability->hContainer)
33 pTW_ONEVALUE pVal = GlobalLock (pCapability->hContainer);
34 if (pVal)
36 *value = pVal->Item;
37 if (type)
38 *type = pVal->ItemType;
39 GlobalUnlock (pCapability->hContainer);
40 return TWCC_SUCCESS;
43 return TWCC_BUMMER;
47 static TW_UINT16 set_onevalue(pTW_CAPABILITY pCapability, TW_UINT16 type, TW_UINT32 value)
49 pCapability->hContainer = GlobalAlloc (0, sizeof(TW_ONEVALUE));
51 if (pCapability->hContainer)
53 pTW_ONEVALUE pVal = GlobalLock (pCapability->hContainer);
54 if (pVal)
56 pCapability->ConType = TWON_ONEVALUE;
57 pVal->ItemType = type;
58 pVal->Item = value;
59 GlobalUnlock (pCapability->hContainer);
60 return TWCC_SUCCESS;
63 return TWCC_LOWMEMORY;
66 static TW_UINT16 msg_set(pTW_CAPABILITY pCapability, TW_UINT32 *val)
68 if (pCapability->ConType == TWON_ONEVALUE)
69 return get_onevalue(pCapability, NULL, val);
71 FIXME("Partial Stub: MSG_SET only supports TW_ONEVALUE\n");
72 return TWCC_BADCAP;
76 static TW_UINT16 msg_get_enum(pTW_CAPABILITY pCapability, const TW_UINT32 *values, int value_count,
77 TW_UINT16 type, TW_UINT32 current, TW_UINT32 default_value)
79 TW_ENUMERATION *enumv = NULL;
80 TW_UINT32 *p32;
81 TW_UINT16 *p16;
82 int i;
84 pCapability->ConType = TWON_ENUMERATION;
85 pCapability->hContainer = 0;
87 if (type == TWTY_INT16 || type == TWTY_UINT16)
88 pCapability->hContainer = GlobalAlloc (0, FIELD_OFFSET( TW_ENUMERATION, ItemList[value_count * sizeof(TW_UINT16)]));
90 if (type == TWTY_INT32 || type == TWTY_UINT32)
91 pCapability->hContainer = GlobalAlloc (0, FIELD_OFFSET( TW_ENUMERATION, ItemList[value_count * sizeof(TW_UINT32)]));
93 if (pCapability->hContainer)
94 enumv = GlobalLock(pCapability->hContainer);
96 if (! enumv)
97 return TWCC_LOWMEMORY;
99 enumv->ItemType = type;
100 enumv->NumItems = value_count;
102 p16 = (TW_UINT16 *) enumv->ItemList;
103 p32 = (TW_UINT32 *) enumv->ItemList;
104 for (i = 0; i < value_count; i++)
106 if (values[i] == current)
107 enumv->CurrentIndex = i;
108 if (values[i] == default_value)
109 enumv->DefaultIndex = i;
110 if (type == TWTY_INT16 || type == TWTY_UINT16)
111 p16[i] = values[i];
112 if (type == TWTY_INT32 || type == TWTY_UINT32)
113 p32[i] = values[i];
116 GlobalUnlock(pCapability->hContainer);
117 return TWCC_SUCCESS;
120 static TW_UINT16 msg_get_range(pTW_CAPABILITY pCapability, TW_UINT16 type,
121 TW_UINT32 minval, TW_UINT32 maxval, TW_UINT32 step, TW_UINT32 def, TW_UINT32 current)
123 TW_RANGE *range = NULL;
125 pCapability->ConType = TWON_RANGE;
126 pCapability->hContainer = 0;
128 pCapability->hContainer = GlobalAlloc (0, sizeof(*range));
129 if (pCapability->hContainer)
130 range = GlobalLock(pCapability->hContainer);
132 if (! range)
133 return TWCC_LOWMEMORY;
135 range->ItemType = type;
136 range->MinValue = minval;
137 range->MaxValue = maxval;
138 range->StepSize = step;
139 range->DefaultValue = def;
140 range->CurrentValue = current;
142 GlobalUnlock(pCapability->hContainer);
143 return TWCC_SUCCESS;
146 static TW_UINT16 TWAIN_GetSupportedCaps(pTW_CAPABILITY pCapability)
148 TW_ARRAY *a;
149 static const UINT16 supported_caps[] = { CAP_SUPPORTEDCAPS, CAP_XFERCOUNT, CAP_UICONTROLLABLE,
150 CAP_AUTOFEED, CAP_FEEDERENABLED,
151 ICAP_XFERMECH, ICAP_PIXELTYPE, ICAP_UNITS, ICAP_BITDEPTH, ICAP_COMPRESSION, ICAP_PIXELFLAVOR,
152 ICAP_XRESOLUTION, ICAP_YRESOLUTION, ICAP_PHYSICALHEIGHT, ICAP_PHYSICALWIDTH, ICAP_SUPPORTEDSIZES };
154 pCapability->hContainer = GlobalAlloc (0, FIELD_OFFSET( TW_ARRAY, ItemList[sizeof(supported_caps)] ));
155 pCapability->ConType = TWON_ARRAY;
157 if (pCapability->hContainer)
159 UINT16 *u;
160 TW_UINT32 i;
161 a = GlobalLock (pCapability->hContainer);
162 a->ItemType = TWTY_UINT16;
163 a->NumItems = ARRAY_SIZE(supported_caps);
164 u = (UINT16 *) a->ItemList;
165 for (i = 0; i < a->NumItems; i++)
166 u[i] = supported_caps[i];
167 GlobalUnlock (pCapability->hContainer);
168 return TWCC_SUCCESS;
170 else
171 return TWCC_LOWMEMORY;
175 /* ICAP_XFERMECH */
176 static TW_UINT16 SANE_ICAPXferMech (pTW_CAPABILITY pCapability, TW_UINT16 action)
178 static const TW_UINT32 possible_values[] = { TWSX_NATIVE, TWSX_MEMORY };
179 TW_UINT32 val;
180 TW_UINT16 twCC = TWCC_BADCAP;
182 TRACE("ICAP_XFERMECH\n");
184 switch (action)
186 case MSG_QUERYSUPPORT:
187 twCC = set_onevalue(pCapability, TWTY_INT32,
188 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET );
189 break;
191 case MSG_GET:
192 twCC = msg_get_enum(pCapability, possible_values, ARRAY_SIZE(possible_values),
193 TWTY_UINT16, activeDS.capXferMech, TWSX_NATIVE);
194 break;
196 case MSG_SET:
197 twCC = msg_set(pCapability, &val);
198 if (twCC == TWCC_SUCCESS)
200 activeDS.capXferMech = (TW_UINT16) val;
201 FIXME("Partial Stub: XFERMECH set to %ld, but ignored\n", val);
203 break;
205 case MSG_GETDEFAULT:
206 twCC = set_onevalue(pCapability, TWTY_UINT16, TWSX_NATIVE);
207 break;
209 case MSG_RESET:
210 activeDS.capXferMech = TWSX_NATIVE;
211 /* .. fall through intentional .. */
213 case MSG_GETCURRENT:
214 twCC = set_onevalue(pCapability, TWTY_UINT16, activeDS.capXferMech);
215 FIXME("Partial Stub: XFERMECH of %d not actually used\n", activeDS.capXferMech);
216 break;
218 return twCC;
222 /* CAP_XFERCOUNT */
223 static TW_UINT16 SANE_CAPXferCount (pTW_CAPABILITY pCapability, TW_UINT16 action)
225 TW_UINT32 val;
226 TW_UINT16 twCC = TWCC_BADCAP;
228 TRACE("CAP_XFERCOUNT\n");
230 switch (action)
232 case MSG_QUERYSUPPORT:
233 twCC = set_onevalue(pCapability, TWTY_INT32,
234 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET );
235 break;
237 case MSG_GET:
238 twCC = set_onevalue(pCapability, TWTY_INT16, -1);
239 FIXME("Partial Stub: Reporting only support for transfer all\n");
240 break;
242 case MSG_SET:
243 twCC = msg_set(pCapability, &val);
244 if (twCC == TWCC_SUCCESS)
245 FIXME("Partial Stub: XFERCOUNT set to %ld, but ignored\n", val);
246 break;
248 case MSG_GETDEFAULT:
249 twCC = set_onevalue(pCapability, TWTY_INT16, -1);
250 break;
252 case MSG_RESET:
253 /* .. fall through intentional .. */
255 case MSG_GETCURRENT:
256 twCC = set_onevalue(pCapability, TWTY_INT16, -1);
257 break;
259 return twCC;
262 static BOOL pixeltype_to_sane_mode(TW_UINT16 pixeltype, char *mode, int len)
264 const char *m = NULL;
265 switch (pixeltype)
267 case TWPT_GRAY:
268 m = "Gray";
269 break;
270 case TWPT_RGB:
271 m = "Color";
272 break;
273 case TWPT_BW:
274 m = "Lineart";
275 break;
277 if (! m)
278 return FALSE;
279 if (strlen(m) >= len)
280 return FALSE;
281 strcpy(mode, m);
282 return TRUE;
285 /* ICAP_PIXELTYPE */
286 static TW_UINT16 SANE_ICAPPixelType (pTW_CAPABILITY pCapability, TW_UINT16 action)
288 TW_UINT16 twCC;
289 TW_UINT32 possible_values[3];
290 int possible_value_count;
291 TW_UINT32 val;
292 BOOL reload = FALSE;
293 TW_UINT16 current_pixeltype = TWPT_BW;
294 char mode[64];
296 TRACE("ICAP_PIXELTYPE\n");
298 twCC = sane_option_probe_mode(&current_pixeltype, possible_values, &possible_value_count);
299 if (twCC != TWCC_SUCCESS)
301 ERR("Unable to retrieve mode from sane, ICAP_PIXELTYPE unsupported\n");
302 return twCC;
305 /* Sane does not support a concept of a default mode, so we simply cache
306 * the first mode we find */
307 if (! activeDS.PixelTypeSet)
309 activeDS.PixelTypeSet = TRUE;
310 activeDS.defaultPixelType = current_pixeltype;
313 switch (action)
315 case MSG_QUERYSUPPORT:
316 twCC = set_onevalue(pCapability, TWTY_INT32,
317 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET );
318 break;
320 case MSG_GET:
321 twCC = msg_get_enum(pCapability, possible_values, possible_value_count,
322 TWTY_UINT16, current_pixeltype, activeDS.defaultPixelType);
323 break;
325 case MSG_SET:
326 twCC = msg_set(pCapability, &val);
327 if (twCC == TWCC_SUCCESS)
329 TRACE("Setting pixeltype to %ld\n", val);
330 if (! pixeltype_to_sane_mode(val, mode, sizeof(mode)))
331 return TWCC_BADVALUE;
333 twCC = sane_option_set_str("mode", mode, &reload);
334 /* Some SANE devices use 'Grayscale' instead of the standard 'Gray' */
335 if (twCC != TWCC_SUCCESS && strcmp(mode, "Gray") == 0)
337 strcpy(mode, "Grayscale");
338 twCC = sane_option_set_str("mode", mode, &reload);
340 if (reload) get_sane_params( &activeDS.frame_params );
342 break;
344 case MSG_GETDEFAULT:
345 twCC = set_onevalue(pCapability, TWTY_UINT16, activeDS.defaultPixelType);
346 break;
348 case MSG_RESET:
349 current_pixeltype = activeDS.defaultPixelType;
350 if (! pixeltype_to_sane_mode(current_pixeltype, mode, sizeof(mode)))
351 return TWCC_BADVALUE;
353 twCC = sane_option_set_str("mode", mode, &reload);
354 /* Some SANE devices use 'Grayscale' instead of the standard 'Gray' */
355 if (twCC != TWCC_SUCCESS && strcmp(mode, "Gray") == 0)
357 strcpy(mode, "Grayscale");
358 twCC = sane_option_set_str("mode", mode, &reload);
360 if (twCC != TWCC_SUCCESS) break;
361 if (reload) get_sane_params( &activeDS.frame_params );
363 /* .. fall through intentional .. */
365 case MSG_GETCURRENT:
366 twCC = set_onevalue(pCapability, TWTY_UINT16, current_pixeltype);
367 TRACE("Returning current pixeltype of %d\n", current_pixeltype);
368 break;
371 return twCC;
374 /* ICAP_UNITS */
375 static TW_UINT16 SANE_ICAPUnits (pTW_CAPABILITY pCapability, TW_UINT16 action)
377 TW_UINT32 val;
378 TW_UINT16 twCC = TWCC_BADCAP;
380 TRACE("ICAP_UNITS\n");
382 switch (action)
384 case MSG_QUERYSUPPORT:
385 twCC = set_onevalue(pCapability, TWTY_INT32,
386 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET );
387 break;
389 case MSG_GET:
390 twCC = set_onevalue(pCapability, TWTY_UINT16, TWUN_INCHES);
391 break;
393 case MSG_SET:
394 twCC = msg_set(pCapability, &val);
395 if (twCC == TWCC_SUCCESS)
397 if (val != TWUN_INCHES)
399 ERR("Sane supports only SANE_UNIT_DPI\n");
400 twCC = TWCC_BADVALUE;
403 break;
405 case MSG_GETDEFAULT:
406 case MSG_RESET:
407 /* .. fall through intentional .. */
409 case MSG_GETCURRENT:
410 twCC = set_onevalue(pCapability, TWTY_UINT16, TWUN_INCHES);
411 break;
414 return twCC;
417 /* ICAP_BITDEPTH */
418 static TW_UINT16 SANE_ICAPBitDepth(pTW_CAPABILITY pCapability, TW_UINT16 action)
420 TW_UINT16 twCC = TWCC_BADCAP;
421 TW_UINT32 possible_values[1];
423 TRACE("ICAP_BITDEPTH\n");
425 possible_values[0] = activeDS.frame_params.depth;
427 switch (action)
429 case MSG_QUERYSUPPORT:
430 twCC = set_onevalue(pCapability, TWTY_INT32,
431 TWQC_GET | TWQC_GETDEFAULT | TWQC_GETCURRENT );
432 break;
434 case MSG_GET:
435 twCC = msg_get_enum(pCapability, possible_values, ARRAY_SIZE(possible_values),
436 TWTY_UINT16, activeDS.frame_params.depth, activeDS.frame_params.depth);
437 break;
439 case MSG_GETDEFAULT:
440 /* .. Fall through intentional .. */
442 case MSG_GETCURRENT:
443 TRACE("Returning current bitdepth of %d\n", activeDS.frame_params.depth);
444 twCC = set_onevalue(pCapability, TWTY_UINT16, activeDS.frame_params.depth);
445 break;
447 return twCC;
450 /* CAP_UICONTROLLABLE */
451 static TW_UINT16 SANE_CAPUiControllable(pTW_CAPABILITY pCapability, TW_UINT16 action)
453 TW_UINT16 twCC = TWCC_BADCAP;
455 TRACE("CAP_UICONTROLLABLE\n");
457 switch (action)
459 case MSG_QUERYSUPPORT:
460 twCC = set_onevalue(pCapability, TWTY_INT32, TWQC_GET);
461 break;
463 case MSG_GET:
464 twCC = set_onevalue(pCapability, TWTY_BOOL, TRUE);
465 break;
468 return twCC;
471 /* ICAP_COMPRESSION */
472 static TW_UINT16 SANE_ICAPCompression (pTW_CAPABILITY pCapability, TW_UINT16 action)
474 static const TW_UINT32 possible_values[] = { TWCP_NONE };
475 TW_UINT32 val;
476 TW_UINT16 twCC = TWCC_BADCAP;
478 TRACE("ICAP_COMPRESSION\n");
480 switch (action)
482 case MSG_QUERYSUPPORT:
483 twCC = set_onevalue(pCapability, TWTY_INT32,
484 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET );
485 break;
487 case MSG_GET:
488 twCC = msg_get_enum(pCapability, possible_values, ARRAY_SIZE(possible_values),
489 TWTY_UINT16, TWCP_NONE, TWCP_NONE);
490 FIXME("Partial stub: We don't attempt to support compression\n");
491 break;
493 case MSG_SET:
494 twCC = msg_set(pCapability, &val);
495 if (twCC == TWCC_SUCCESS)
496 FIXME("Partial Stub: COMPRESSION set to %ld, but ignored\n", val);
497 break;
499 case MSG_GETDEFAULT:
500 twCC = set_onevalue(pCapability, TWTY_UINT16, TWCP_NONE);
501 break;
503 case MSG_RESET:
504 /* .. fall through intentional .. */
506 case MSG_GETCURRENT:
507 twCC = set_onevalue(pCapability, TWTY_UINT16, TWCP_NONE);
508 break;
510 return twCC;
513 /* ICAP_XRESOLUTION, ICAP_YRESOLUTION */
514 static TW_UINT16 SANE_ICAPResolution (pTW_CAPABILITY pCapability, TW_UINT16 action, TW_UINT16 cap)
516 TW_UINT16 twCC = TWCC_BADCAP;
517 TW_UINT32 val;
518 int current_resolution;
519 TW_FIX32 *default_res;
520 const char *best_option_name;
521 int minval, maxval, quantval;
523 TRACE("ICAP_%cRESOLUTION\n", cap == ICAP_XRESOLUTION ? 'X' : 'Y');
525 /* Some scanners support 'x-resolution', most seem to just support 'resolution' */
526 if (cap == ICAP_XRESOLUTION)
528 best_option_name = "x-resolution";
529 default_res = &activeDS.defaultXResolution;
531 else
533 best_option_name = "y-resolution";
534 default_res = &activeDS.defaultYResolution;
536 if (sane_option_get_int(best_option_name, &current_resolution) != TWCC_SUCCESS)
538 best_option_name = "resolution";
539 if (sane_option_get_int(best_option_name, &current_resolution) != TWCC_SUCCESS)
540 return TWCC_BADCAP;
543 /* Sane does not support a concept of 'default' resolution, so we have to
544 * cache the resolution the very first time we load the scanner, and use that
545 * as the default */
546 if (cap == ICAP_XRESOLUTION && ! activeDS.XResolutionSet)
548 default_res->Whole = current_resolution;
549 default_res->Frac = 0;
550 activeDS.XResolutionSet = TRUE;
553 if (cap == ICAP_YRESOLUTION && ! activeDS.YResolutionSet)
555 default_res->Whole = current_resolution;
556 default_res->Frac = 0;
557 activeDS.YResolutionSet = TRUE;
560 switch (action)
562 case MSG_QUERYSUPPORT:
563 twCC = set_onevalue(pCapability, TWTY_INT32,
564 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET );
565 break;
567 case MSG_GET:
568 twCC = sane_option_probe_resolution(best_option_name, &minval, &maxval, &quantval);
569 if (twCC == TWCC_SUCCESS)
570 twCC = msg_get_range(pCapability, TWTY_FIX32,
571 minval, maxval, quantval == 0 ? 1 : quantval, default_res->Whole, current_resolution);
572 break;
574 case MSG_SET:
575 twCC = msg_set(pCapability, &val);
576 if (twCC == TWCC_SUCCESS)
578 TW_FIX32 f32;
579 BOOL reload = FALSE;
580 memcpy(&f32, &val, sizeof(f32));
581 twCC = sane_option_set_int(best_option_name, f32.Whole, &reload);
582 if (reload) twCC = TWCC_CHECKSTATUS;
584 break;
586 case MSG_GETDEFAULT:
587 twCC = set_onevalue(pCapability, TWTY_FIX32, default_res->Whole);
588 break;
590 case MSG_RESET:
591 twCC = sane_option_set_int(best_option_name, default_res->Whole, NULL);
592 if (twCC != TWCC_SUCCESS) return twCC;
594 /* .. fall through intentional .. */
596 case MSG_GETCURRENT:
597 twCC = set_onevalue(pCapability, TWTY_FIX32, current_resolution);
598 break;
600 return twCC;
603 /* ICAP_PHYSICALHEIGHT, ICAP_PHYSICALWIDTH */
604 static TW_UINT16 SANE_ICAPPhysical (pTW_CAPABILITY pCapability, TW_UINT16 action, TW_UINT16 cap)
606 TW_UINT16 twCC;
607 TW_FIX32 res;
608 int tlx, tly, brx, bry;
610 TRACE("ICAP_PHYSICAL%s\n", cap == ICAP_PHYSICALHEIGHT? "HEIGHT" : "WIDTH");
612 twCC = sane_option_get_max_scan_area( &tlx, &tly, &brx, &bry );
613 if (twCC != TWCC_SUCCESS) return twCC;
615 res = convert_sane_res_to_twain( (cap == ICAP_PHYSICALHEIGHT) ? bry - tly : brx - tlx );
617 switch (action)
619 case MSG_QUERYSUPPORT:
620 twCC = set_onevalue(pCapability, TWTY_INT32,
621 TWQC_GET | TWQC_GETDEFAULT | TWQC_GETCURRENT );
622 break;
624 case MSG_GET:
625 case MSG_GETDEFAULT:
627 /* .. fall through intentional .. */
629 case MSG_GETCURRENT:
630 twCC = set_onevalue(pCapability, TWTY_FIX32, res.Whole | (res.Frac << 16));
631 break;
633 return twCC;
636 /* ICAP_PIXELFLAVOR */
637 static TW_UINT16 SANE_ICAPPixelFlavor (pTW_CAPABILITY pCapability, TW_UINT16 action)
639 TW_UINT16 twCC = TWCC_BADCAP;
640 static const TW_UINT32 possible_values[] = { TWPF_CHOCOLATE, TWPF_VANILLA };
641 TW_UINT32 val;
642 TW_UINT32 flavor = activeDS.frame_params.depth == 1 ? TWPF_VANILLA : TWPF_CHOCOLATE;
644 TRACE("ICAP_PIXELFLAVOR\n");
646 switch (action)
648 case MSG_QUERYSUPPORT:
649 twCC = set_onevalue(pCapability, TWTY_INT32,
650 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET );
651 break;
653 case MSG_GET:
654 twCC = msg_get_enum(pCapability, possible_values, ARRAY_SIZE(possible_values),
655 TWTY_UINT16, flavor, flavor);
656 break;
658 case MSG_SET:
659 twCC = msg_set(pCapability, &val);
660 if (twCC == TWCC_SUCCESS)
662 FIXME("Stub: PIXELFLAVOR set to %ld, but ignored\n", val);
664 break;
666 case MSG_GETDEFAULT:
667 twCC = set_onevalue(pCapability, TWTY_UINT16, flavor);
668 break;
670 case MSG_RESET:
671 /* .. fall through intentional .. */
673 case MSG_GETCURRENT:
674 twCC = set_onevalue(pCapability, TWTY_UINT16, flavor);
675 break;
677 return twCC;
680 static TW_UINT16 get_width_height(double *width, double *height, BOOL max)
682 TW_UINT16 rc;
683 int tlx, tly, brx, bry;
685 if (max) rc = sane_option_get_max_scan_area( &tlx, &tly, &brx, &bry );
686 else rc = sane_option_get_scan_area( &tlx, &tly, &brx, &bry );
688 if (rc == TWCC_SUCCESS)
690 *width = (brx - tlx) / 65536.0;
691 *height = (bry - tly) / 65536.0;
693 return rc;
696 static TW_UINT16 set_width_height(double width, double height)
698 return sane_option_set_scan_area( 0, 0, width * 65536, height * 65536, NULL );
701 typedef struct
703 TW_UINT32 size;
704 double x;
705 double y;
706 } supported_size_t;
708 static const supported_size_t supported_sizes[] =
710 { TWSS_NONE, 0, 0 },
711 { TWSS_A4, 210, 297 },
712 { TWSS_JISB5, 182, 257 },
713 { TWSS_USLETTER, 215.9, 279.4 },
714 { TWSS_USLEGAL, 215.9, 355.6 },
715 { TWSS_A5, 148, 210 },
716 { TWSS_B4, 250, 353 },
717 { TWSS_B6, 125, 176 },
718 { TWSS_USLEDGER, 215.9, 431.8 },
719 { TWSS_USEXECUTIVE, 184.15, 266.7 },
720 { TWSS_A3, 297, 420 },
723 static TW_UINT16 get_default_paper_size(const supported_size_t *s, int n)
725 DWORD paper;
726 int rc;
727 int defsize = -1;
728 double width, height;
729 int i;
730 rc = GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_IPAPERSIZE | LOCALE_RETURN_NUMBER, (void *) &paper, sizeof(paper));
731 if (rc > 0)
732 switch (paper)
734 case 1:
735 defsize = TWSS_USLETTER;
736 break;
737 case 5:
738 defsize = TWSS_USLEGAL;
739 break;
740 case 8:
741 defsize = TWSS_A3;
742 break;
743 case 9:
744 defsize = TWSS_A4;
745 break;
748 if (defsize == -1)
749 return TWSS_NONE;
751 if (get_width_height(&width, &height, TRUE) != TWCC_SUCCESS)
752 return TWSS_NONE;
754 for (i = 0; i < n; i++)
755 if (s[i].size == defsize)
757 /* Sane's use of integers to store floats is a hair lossy; deal with it */
758 if (s[i].x > (width + .01) || s[i].y > (height + 0.01))
759 return TWSS_NONE;
760 else
761 return s[i].size;
764 return TWSS_NONE;
767 static TW_UINT16 get_current_paper_size(const supported_size_t *s, int n)
769 int i;
770 double width, height;
771 double xdelta, ydelta;
773 if (get_width_height(&width, &height, FALSE) != TWCC_SUCCESS)
774 return TWSS_NONE;
776 for (i = 0; i < n; i++)
778 /* Sane's use of integers to store floats results
779 * in a very small error; cope with that */
780 xdelta = s[i].x - width;
781 ydelta = s[i].y - height;
782 if (xdelta < 0.01 && xdelta > -0.01 &&
783 ydelta < 0.01 && ydelta > -0.01)
784 return s[i].size;
787 return TWSS_NONE;
790 /* ICAP_SUPPORTEDSIZES */
791 static TW_UINT16 SANE_ICAPSupportedSizes (pTW_CAPABILITY pCapability, TW_UINT16 action)
793 TW_UINT16 twCC = TWCC_BADCAP;
795 static TW_UINT32 possible_values[ARRAY_SIZE(supported_sizes)];
796 unsigned int i;
797 TW_UINT32 val;
798 TW_UINT16 default_size = get_default_paper_size(supported_sizes, ARRAY_SIZE(supported_sizes));
799 TW_UINT16 current_size = get_current_paper_size(supported_sizes, ARRAY_SIZE(supported_sizes));
801 TRACE("ICAP_SUPPORTEDSIZES\n");
803 switch (action)
805 case MSG_QUERYSUPPORT:
806 twCC = set_onevalue(pCapability, TWTY_INT32,
807 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET );
808 break;
810 case MSG_GET:
811 for (i = 0; i < ARRAY_SIZE(supported_sizes); i++)
812 possible_values[i] = supported_sizes[i].size;
813 twCC = msg_get_enum(pCapability, possible_values, ARRAY_SIZE(possible_values),
814 TWTY_UINT16, current_size, default_size);
815 WARN("Partial Stub: our supported size selection is a bit thin.\n");
816 break;
818 case MSG_SET:
819 twCC = msg_set(pCapability, &val);
820 if (twCC == TWCC_SUCCESS)
821 for (i = 1; i < ARRAY_SIZE(supported_sizes); i++)
822 if (supported_sizes[i].size == val)
823 return set_width_height(supported_sizes[i].x, supported_sizes[i].y);
825 ERR("Unsupported size %ld\n", val);
826 twCC = TWCC_BADCAP;
827 break;
829 case MSG_GETDEFAULT:
830 twCC = set_onevalue(pCapability, TWTY_UINT16, default_size);
831 break;
833 case MSG_RESET:
834 twCC = TWCC_BADCAP;
835 for (i = 1; i < ARRAY_SIZE(supported_sizes); i++)
836 if (supported_sizes[i].size == default_size)
838 twCC = set_width_height(supported_sizes[i].x, supported_sizes[i].y);
839 break;
841 if (twCC != TWCC_SUCCESS)
842 return twCC;
844 /* .. fall through intentional .. */
846 case MSG_GETCURRENT:
847 twCC = set_onevalue(pCapability, TWTY_UINT16, current_size);
848 break;
851 return twCC;
854 /* CAP_AUTOFEED */
855 static TW_UINT16 SANE_CAPAutofeed (pTW_CAPABILITY pCapability, TW_UINT16 action)
857 TW_UINT16 twCC = TWCC_BADCAP;
858 TW_UINT32 val;
859 BOOL autofeed;
861 TRACE("CAP_AUTOFEED\n");
863 if (sane_option_get_bool("batch-scan", &autofeed) != TWCC_SUCCESS)
864 return TWCC_BADCAP;
866 switch (action)
868 case MSG_QUERYSUPPORT:
869 twCC = set_onevalue(pCapability, TWTY_INT32,
870 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET );
871 break;
873 case MSG_GET:
874 twCC = set_onevalue(pCapability, TWTY_BOOL, autofeed);
875 break;
877 case MSG_SET:
878 twCC = msg_set(pCapability, &val);
879 if (twCC == TWCC_SUCCESS)
880 twCC = sane_option_set_bool("batch-scan", !!val);
881 break;
883 case MSG_GETDEFAULT:
884 twCC = set_onevalue(pCapability, TWTY_BOOL, TRUE);
885 break;
887 case MSG_RESET:
888 autofeed = TRUE;
889 twCC = sane_option_set_bool("batch-scan", autofeed);
890 if (twCC != TWCC_SUCCESS) break;
891 /* .. fall through intentional .. */
893 case MSG_GETCURRENT:
894 twCC = set_onevalue(pCapability, TWTY_BOOL, autofeed);
895 break;
897 return twCC;
900 /* CAP_FEEDERENABLED */
901 static TW_UINT16 SANE_CAPFeederEnabled (pTW_CAPABILITY pCapability, TW_UINT16 action)
903 TW_UINT16 twCC = TWCC_BADCAP;
904 TW_UINT32 val;
905 TW_BOOL enabled;
906 char source[64];
908 TRACE("CAP_FEEDERENABLED\n");
910 if (sane_option_get_str("source", source, sizeof(source)) != TWCC_SUCCESS)
911 return TWCC_BADCAP;
913 if (strcmp(source, "Auto") == 0 || strcmp(source, "ADF") == 0)
914 enabled = TRUE;
915 else
916 enabled = FALSE;
918 switch (action)
920 case MSG_QUERYSUPPORT:
921 twCC = set_onevalue(pCapability, TWTY_INT32,
922 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET );
923 break;
925 case MSG_GET:
926 twCC = set_onevalue(pCapability, TWTY_BOOL, enabled);
927 break;
929 case MSG_SET:
930 twCC = msg_set(pCapability, &val);
931 if (twCC == TWCC_SUCCESS)
933 strcpy(source, "ADF");
934 twCC = sane_option_set_str("source", source, NULL);
935 if (twCC != TWCC_SUCCESS)
937 strcpy(source, "Auto");
938 twCC = sane_option_set_str("source", source, NULL);
941 break;
943 case MSG_GETDEFAULT:
944 twCC = set_onevalue(pCapability, TWTY_BOOL, TRUE);
945 break;
947 case MSG_RESET:
948 strcpy(source, "Auto");
949 if (sane_option_set_str("source", source, NULL) == TWCC_SUCCESS)
950 enabled = TRUE;
951 /* .. fall through intentional .. */
953 case MSG_GETCURRENT:
954 twCC = set_onevalue(pCapability, TWTY_BOOL, enabled);
955 break;
957 return twCC;
962 TW_UINT16 SANE_SaneCapability (pTW_CAPABILITY pCapability, TW_UINT16 action)
964 TW_UINT16 twCC = TWCC_CAPUNSUPPORTED;
966 TRACE("capability=%d action=%d\n", pCapability->Cap, action);
968 switch (pCapability->Cap)
970 case CAP_SUPPORTEDCAPS:
971 if (action == MSG_GET)
972 twCC = TWAIN_GetSupportedCaps(pCapability);
973 else
974 twCC = TWCC_BADVALUE;
975 break;
977 case CAP_XFERCOUNT:
978 twCC = SANE_CAPXferCount (pCapability, action);
979 break;
981 case CAP_UICONTROLLABLE:
982 twCC = SANE_CAPUiControllable (pCapability, action);
983 break;
985 case CAP_AUTOFEED:
986 twCC = SANE_CAPAutofeed (pCapability, action);
987 break;
989 case CAP_FEEDERENABLED:
990 twCC = SANE_CAPFeederEnabled (pCapability, action);
991 break;
993 case ICAP_PIXELTYPE:
994 twCC = SANE_ICAPPixelType (pCapability, action);
995 break;
997 case ICAP_UNITS:
998 twCC = SANE_ICAPUnits (pCapability, action);
999 break;
1001 case ICAP_BITDEPTH:
1002 twCC = SANE_ICAPBitDepth(pCapability, action);
1003 break;
1005 case ICAP_XFERMECH:
1006 twCC = SANE_ICAPXferMech (pCapability, action);
1007 break;
1009 case ICAP_PIXELFLAVOR:
1010 twCC = SANE_ICAPPixelFlavor (pCapability, action);
1011 break;
1013 case ICAP_COMPRESSION:
1014 twCC = SANE_ICAPCompression(pCapability, action);
1015 break;
1017 case ICAP_XRESOLUTION:
1018 twCC = SANE_ICAPResolution(pCapability, action, pCapability->Cap);
1019 break;
1021 case ICAP_YRESOLUTION:
1022 twCC = SANE_ICAPResolution(pCapability, action, pCapability->Cap);
1023 break;
1025 case ICAP_PHYSICALHEIGHT:
1026 twCC = SANE_ICAPPhysical(pCapability, action, pCapability->Cap);
1027 break;
1029 case ICAP_PHYSICALWIDTH:
1030 twCC = SANE_ICAPPhysical(pCapability, action, pCapability->Cap);
1031 break;
1033 case ICAP_SUPPORTEDSIZES:
1034 twCC = SANE_ICAPSupportedSizes (pCapability, action);
1035 break;
1037 case ICAP_PLANARCHUNKY:
1038 FIXME("ICAP_PLANARCHUNKY not implemented\n");
1039 break;
1041 case ICAP_BITORDER:
1042 FIXME("ICAP_BITORDER not implemented\n");
1043 break;
1047 /* Twain specifies that you should return a 0 in response to QUERYSUPPORT,
1048 * even if you don't formally support the capability */
1049 if (twCC == TWCC_CAPUNSUPPORTED && action == MSG_QUERYSUPPORT)
1050 twCC = set_onevalue(pCapability, 0, TWTY_INT32);
1052 if (twCC == TWCC_CAPUNSUPPORTED)
1053 TRACE("capability 0x%x/action=%d being reported as unsupported\n", pCapability->Cap, action);
1055 return twCC;
1058 TW_UINT16 SANE_SaneSetDefaults (void)
1060 TW_CAPABILITY cap;
1062 memset(&cap, 0, sizeof(cap));
1063 cap.Cap = CAP_AUTOFEED;
1064 cap.ConType = TWON_DONTCARE16;
1066 if (SANE_SaneCapability(&cap, MSG_RESET) == TWCC_SUCCESS)
1067 GlobalFree(cap.hContainer);
1069 memset(&cap, 0, sizeof(cap));
1070 cap.Cap = CAP_FEEDERENABLED;
1071 cap.ConType = TWON_DONTCARE16;
1073 if (SANE_SaneCapability(&cap, MSG_RESET) == TWCC_SUCCESS)
1074 GlobalFree(cap.hContainer);
1076 memset(&cap, 0, sizeof(cap));
1077 cap.Cap = ICAP_SUPPORTEDSIZES;
1078 cap.ConType = TWON_DONTCARE16;
1080 if (SANE_SaneCapability(&cap, MSG_RESET) == TWCC_SUCCESS)
1081 GlobalFree(cap.hContainer);
1083 return TWCC_SUCCESS;