1/* sane - Scanner Access Now Easy.
2   Copyright (C) 1997 Geoffrey T. Dairiki
3   This file is part of the SANE package.
4
5   This program is free software; you can redistribute it and/or
6   modify it under the terms of the GNU General Public License as
7   published by the Free Software Foundation; either version 2 of the
8   License, or (at your option) any later version.
9
10   This program is distributed in the hope that it will be useful, but
11   WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13   General Public License for more details.
14
15   You should have received a copy of the GNU General Public License
16   along with this program.  If not, see <https://www.gnu.org/licenses/>.
17
18   As a special exception, the authors of SANE give permission for
19   additional uses of the libraries contained in this release of SANE.
20
21   The exception is that, if you link a SANE library with other files
22   to produce an executable, this does not by itself cause the
23   resulting executable to be covered by the GNU General Public
24   License.  Your use of that executable is in no way restricted on
25   account of linking the SANE library code into it.
26
27   This exception does not, however, invalidate any other reasons why
28   the executable file might be covered by the GNU General Public
29   License.
30
31   If you submit changes to SANE to the maintainers to be included in
32   a subsequent release, you agree by submitting the changes that
33   those changes may be distributed with this exception intact.
34
35   If you write modifications of your own for SANE, it is your choice
36   whether to permit this exception to apply to your modifications.
37   If you do not wish that, delete this exception notice.
38
39   This file is part of a SANE backend for HP Scanners supporting
40   HP Scanner Control Language (SCL).
41*/
42
43/* #define STUBS
44extern int sanei_debug_hp; */
45#define DEBUG_DECLARE_ONLY
46
47#include "../include/sane/config.h"
48#include "../include/sane/sanei_backend.h"
49
50#include "../include/lassert.h"
51#include <string.h>
52
53#include <sys/types.h>
54
55#include "hp.h"
56#include "hp-option.h"
57#include "hp-accessor.h"
58#include "hp-device.h"
59
60#define DATA_SIZE_INCREMENT	(1024)
61
62/*
63 * class HpData
64 */
65struct hp_data_s
66{
67    hp_byte_t *	buf;
68    size_t	bufsiz;
69    size_t	length;
70    hp_bool_t	frozen;
71};
72
73
74static void
75hp_data_resize (HpData this, size_t newsize)
76{
77
78  if (this->bufsiz != newsize)
79    {
80      assert(!this->frozen);
81      this->buf = sanei_hp_realloc(this->buf, newsize);
82      assert(this->buf);
83      this->bufsiz = newsize;
84    }
85}
86
87static void
88hp_data_freeze (HpData this)
89{
90  hp_data_resize(this, this->length);
91  this->frozen = 1;
92}
93
94static size_t
95hp_data_alloc (HpData this, size_t sz)
96{
97  size_t	newsize	= this->bufsiz;
98  size_t	offset	= this->length;
99
100 /*
101  * mike@easysw.com:
102  *
103  * The following code is REQUIRED so that pointers, etc. aren't
104  * misaligned.  This causes MAJOR problems on all SPARC, ALPHA,
105  * and MIPS processors, and possibly others.
106  *
107  * The workaround is to ensure that all allocations are in multiples
108  * of 8 bytes.
109  */
110  sz = (sz + sizeof (long) - 1) & ~(sizeof (long) - 1);
111
112  while (newsize < this->length + sz)
113      newsize += DATA_SIZE_INCREMENT;
114  hp_data_resize(this, newsize);
115
116  this->length += sz;
117  return offset;
118}
119
120static void *
121hp_data_data (HpData this, size_t offset)
122{
123  assert(offset < this->length);
124  return (char *)this->buf + offset;
125}
126
127HpData
128sanei_hp_data_new (void)
129{
130  return sanei_hp_allocz(sizeof(struct hp_data_s));
131}
132
133HpData
134sanei_hp_data_dup (HpData orig)
135{
136  HpData new;
137
138  hp_data_freeze(orig);
139  if (!( new = sanei_hp_memdup(orig, sizeof(*orig)) ))
140      return 0;
141  if (!(new->buf = sanei_hp_memdup(orig->buf, orig->bufsiz)))
142      {
143	sanei_hp_free(new);
144	return 0;
145      }
146  return new;
147}
148
149void
150sanei_hp_data_destroy (HpData this)
151{
152  sanei_hp_free(this->buf);
153  sanei_hp_free(this);
154}
155
156
157/*
158 * class HpAccessor
159 */
160
161typedef const struct hp_accessor_type_s *	HpAccessorType;
162typedef struct hp_accessor_s *			_HpAccessor;
163
164struct hp_accessor_s
165{
166    HpAccessorType	type;
167    size_t		data_offset;
168    size_t		data_size;
169};
170
171struct hp_accessor_type_s
172{
173    SANE_Status (*get)(HpAccessor this, HpData data, void * valp);
174    SANE_Status (*set)(HpAccessor this,  HpData data, void * valp);
175    int	 (*getint)(HpAccessor this, HpData data);
176    void (*setint)(HpAccessor this, HpData data, int val);
177};
178
179SANE_Status
180sanei_hp_accessor_get (HpAccessor this, HpData data, void * valp)
181{
182  if (!this->type->get)
183      return SANE_STATUS_INVAL;
184  return (*this->type->get)(this, data, valp);
185}
186
187SANE_Status
188sanei_hp_accessor_set (HpAccessor this,  HpData data, void * valp)
189{
190  if (!this->type->set)
191      return SANE_STATUS_INVAL;
192  return (*this->type->set)(this, data, valp);
193}
194
195int
196sanei_hp_accessor_getint (HpAccessor this, HpData data)
197{
198  assert (this->type->getint);
199  return (*this->type->getint)(this, data);
200}
201
202void
203sanei_hp_accessor_setint (HpAccessor this, HpData data, int val)
204{
205  assert (this->type->setint);
206  (*this->type->setint)(this, data, val);
207}
208
209const void *
210sanei_hp_accessor_data (HpAccessor this, HpData data)
211{
212  return hp_data_data(data, this->data_offset);
213}
214
215void *
216sanei__hp_accessor_data (HpAccessor this, HpData data)
217{
218  return hp_data_data(data, this->data_offset);
219}
220
221size_t
222sanei_hp_accessor_size (HpAccessor this)
223{
224  return  this->data_size;
225}
226
227HpAccessor
228sanei_hp_accessor_new (HpData data, size_t sz)
229{
230  static const struct hp_accessor_type_s type = {
231      0, 0, 0, 0
232  };
233  _HpAccessor	 new = sanei_hp_alloc(sizeof(*new));
234  new->type = &type;
235  new->data_offset = hp_data_alloc(data, new->data_size = sz);
236  return new;
237}
238
239
240/*
241 * class HpAccessorInt
242 */
243
244#define hp_accessor_int_s	hp_accessor_s
245
246typedef const struct hp_accessor_int_s *	HpAccessorInt;
247typedef struct hp_accessor_int_s *		_HpAccessorInt;
248
249static SANE_Status
250hp_accessor_int_get (HpAccessor this, HpData data, void * valp)
251{
252  *(SANE_Int*)valp = *(int *)hp_data_data(data, this->data_offset);
253  return SANE_STATUS_GOOD;
254}
255
256static SANE_Status
257hp_accessor_int_set (HpAccessor this, HpData data, void * valp)
258{
259  *(int *)hp_data_data(data, this->data_offset) = *(SANE_Int*)valp;
260  return SANE_STATUS_GOOD;
261}
262
263static int
264hp_accessor_int_getint (HpAccessor this, HpData data)
265{
266  return *(int *)hp_data_data(data, this->data_offset);
267}
268
269static void
270hp_accessor_int_setint (HpAccessor this, HpData data, int val)
271{
272  *(int *)hp_data_data(data, this->data_offset) = val;
273}
274
275HpAccessor
276sanei_hp_accessor_int_new (HpData data)
277{
278  static const struct hp_accessor_type_s type = {
279      hp_accessor_int_get, hp_accessor_int_set,
280      hp_accessor_int_getint, hp_accessor_int_setint
281  };
282  _HpAccessorInt	 new = sanei_hp_alloc(sizeof(*new));
283  new->type = &type;
284  new->data_offset = hp_data_alloc(data, new->data_size = sizeof(int));
285  return (HpAccessor)new;
286}
287
288
289/*
290 * class HpAccessorBool
291 */
292
293#define hp_accessor_bool_s	hp_accessor_s
294
295typedef const struct hp_accessor_bool_s *	HpAccessorBool;
296typedef struct hp_accessor_bool_s *		_HpAccessorBool;
297
298static SANE_Status
299hp_accessor_bool_get (HpAccessor this, HpData data, void * valp)
300{
301  int val = *(int *)hp_data_data(data, this->data_offset);
302  *(SANE_Bool*)valp = val ? SANE_TRUE : SANE_FALSE;
303  return SANE_STATUS_GOOD;
304}
305
306static SANE_Status
307hp_accessor_bool_set (HpAccessor this, HpData data, void * valp)
308{
309  int * datap = hp_data_data(data, this->data_offset);
310  *datap = *(SANE_Bool*)valp == SANE_FALSE ? 0 : 1;
311  return SANE_STATUS_GOOD;
312}
313
314HpAccessor
315sanei_hp_accessor_bool_new (HpData data)
316{
317  static const struct hp_accessor_type_s type = {
318      hp_accessor_bool_get, hp_accessor_bool_set,
319      hp_accessor_int_getint, hp_accessor_int_setint
320  };
321  _HpAccessorBool	 new = sanei_hp_alloc(sizeof(*new));
322  new->type = &type;
323  new->data_offset = hp_data_alloc(data, new->data_size = sizeof(int));
324  return (HpAccessor)new;
325}
326
327
328/*
329 * class HpAccessorFixed
330 */
331
332#define hp_accessor_fixed_s	hp_accessor_s
333
334typedef const struct hp_accessor_fixed_s *	HpAccessorFixed;
335typedef struct hp_accessor_fixed_s *		_HpAccessorFixed;
336
337static SANE_Status
338hp_accessor_fixed_get (HpAccessor this, HpData data, void * valp)
339{
340  *(SANE_Fixed*)valp = *(SANE_Fixed *)hp_data_data(data, this->data_offset);
341  return SANE_STATUS_GOOD;
342}
343
344static SANE_Status
345hp_accessor_fixed_set (HpAccessor this, HpData data, void * valp)
346{
347  *(SANE_Fixed *)hp_data_data(data, this->data_offset) = *(SANE_Fixed*)valp;
348  return SANE_STATUS_GOOD;
349}
350
351HpAccessor
352sanei_hp_accessor_fixed_new (HpData data)
353{
354  static const struct hp_accessor_type_s type = {
355      hp_accessor_fixed_get, hp_accessor_fixed_set, 0, 0
356  };
357  _HpAccessorFixed	 new = sanei_hp_alloc(sizeof(*new));
358  new->type = &type;
359  new->data_offset = hp_data_alloc(data, new->data_size = sizeof(SANE_Fixed));
360  return (HpAccessor)new;
361}
362
363
364/*
365 * class HpAccessorChoice
366 */
367
368typedef struct hp_accessor_choice_s *		_HpAccessorChoice;
369
370struct hp_accessor_choice_s
371{
372    HpAccessorType	type;
373    size_t		data_offset;
374    size_t		data_size;
375
376    HpChoice		choices;
377    SANE_String_Const * strlist;
378};
379
380static SANE_Status
381hp_accessor_choice_get (HpAccessor this, HpData data, void * valp)
382{
383  HpChoice choice = *(HpChoice *)hp_data_data(data, this->data_offset);
384  strcpy(valp, choice->name);
385  return SANE_STATUS_GOOD;
386}
387
388static SANE_Status
389hp_accessor_choice_set (HpAccessor _this, HpData data, void * valp)
390{
391  HpAccessorChoice	this	= (HpAccessorChoice)_this;
392  HpChoice 		choice;
393  SANE_String_Const *	strlist = this->strlist;
394
395  for (choice = this->choices; choice; choice = choice->next)
396    {
397      /* Skip choices which aren't in strlist. */
398      if (!*strlist || strcmp(*strlist, choice->name) != 0)
399	  continue;
400      strlist++;
401
402      if (strcmp((const char *)valp, choice->name) == 0)
403	{
404	  *(HpChoice *)hp_data_data(data, this->data_offset) = choice;
405	  return SANE_STATUS_GOOD;
406	}
407    }
408
409  return SANE_STATUS_INVAL;
410}
411
412static int
413hp_accessor_choice_getint (HpAccessor this, HpData data)
414{
415  HpChoice choice = *(HpChoice *)hp_data_data(data, this->data_offset);
416  return choice->val;
417}
418
419static void
420hp_accessor_choice_setint (HpAccessor _this,  HpData data, int val)
421{
422  HpAccessorChoice	this	= (HpAccessorChoice)_this;
423  HpChoice 		choice;
424  HpChoice 		first_choice = 0;
425  SANE_String_Const *	strlist = this->strlist;
426
427  for (choice = this->choices; choice; choice = choice->next)
428    {
429      /* Skip choices which aren't in strlist. */
430      if (!*strlist || strcmp(*strlist, choice->name) != 0)
431	  continue;
432      strlist++;
433
434      if (!first_choice)
435	  first_choice = choice; /* First enabled choice */
436
437      if (choice->val == val)
438	{
439	  *(HpChoice *)hp_data_data(data, this->data_offset) = choice;
440	  return;
441	}
442    }
443
444  if (first_choice)
445      *(HpChoice *)hp_data_data(data, this->data_offset) = first_choice;
446  else
447      assert(!"No choices to choose from?");
448}
449
450SANE_Int
451sanei_hp_accessor_choice_maxsize (HpAccessorChoice this)
452{
453  HpChoice	choice;
454  SANE_Int	size	= 0;
455
456  for (choice = this->choices; choice; choice = choice->next)
457      if ((SANE_Int)strlen(choice->name) >= size)
458	  size = strlen(choice->name) + 1;
459  return size;
460}
461
462SANE_String_Const *
463sanei_hp_accessor_choice_strlist (HpAccessorChoice this,
464			    HpOptSet optset, HpData data,
465                            const HpDeviceInfo *info)
466{
467  if (optset)
468    {
469      int	old_val = hp_accessor_choice_getint((HpAccessor)this, data);
470      HpChoice	choice;
471      size_t	count	= 0;
472
473      for (choice = this->choices; choice; choice = choice->next)
474	  if (sanei_hp_choice_isEnabled(choice, optset, data, info))
475	      this->strlist[count++] = choice->name;
476      this->strlist[count] = 0;
477
478      hp_accessor_choice_setint((HpAccessor)this, data, old_val);
479    }
480
481  return this->strlist;
482}
483
484HpAccessor
485sanei_hp_accessor_choice_new (HpData data, HpChoice choices,
486                              hp_bool_t may_change)
487{
488  static const struct hp_accessor_type_s type = {
489      hp_accessor_choice_get, hp_accessor_choice_set,
490      hp_accessor_choice_getint, hp_accessor_choice_setint
491  };
492  HpChoice	choice;
493  size_t	count	= 0;
494  _HpAccessorChoice this;
495
496  if ( may_change ) data->frozen = 0;
497
498  for (choice = choices; choice; choice = choice->next)
499      count++;
500  this = sanei_hp_alloc(sizeof(*this) + (count+1) * sizeof(*this->strlist));
501  if (!this)
502      return 0;
503
504  this->type = &type;
505  this->data_offset = hp_data_alloc(data, this->data_size = sizeof(HpChoice));
506  this->choices = choices;
507  this->strlist = (SANE_String_Const *)(this + 1);
508
509  count = 0;
510  for (choice = this->choices; choice; choice = choice->next)
511      this->strlist[count++] = choice->name;
512  this->strlist[count] = 0;
513
514  return (HpAccessor)this;
515}
516
517/*
518 * class HpAccessorVector
519 */
520
521typedef struct hp_accessor_vector_s *		_HpAccessorVector;
522
523struct hp_accessor_vector_s
524{
525    HpAccessorType	type;
526    size_t		data_offset;
527    size_t		data_size;
528
529    unsigned short	mask;
530    unsigned short	length;
531    unsigned short	offset;
532    short		stride;
533
534    unsigned short	(*unscale)(HpAccessorVector this, SANE_Fixed fval);
535    SANE_Fixed		(*scale)(HpAccessorVector this, unsigned short val);
536
537    SANE_Fixed		fmin;
538    SANE_Fixed		fmax;
539
540};
541
542unsigned
543sanei_hp_accessor_vector_length (HpAccessorVector this)
544{
545  return this->length;
546}
547
548SANE_Fixed
549sanei_hp_accessor_vector_minval (HpAccessorVector this)
550{
551  return this->fmin;
552}
553
554SANE_Fixed
555sanei_hp_accessor_vector_maxval (HpAccessorVector this)
556{
557  return this->fmax;
558}
559
560static unsigned short
561_v_get (HpAccessorVector this, const unsigned char * data)
562{
563  unsigned short val;
564
565  if (this->mask <= 255)
566      val = data[0];
567  else
568#ifndef NotOrig
569      val = (data[0] << 8) + data[1];
570#else
571      val = (data[1] << 8) + data[0];
572#endif
573
574  return val & this->mask;
575}
576
577static void
578_v_set (HpAccessorVector this, unsigned char * data, unsigned short val)
579{
580  val &= this->mask;
581
582  if (this->mask <= 255)
583    {
584      data[0] = (unsigned char)val;
585    }
586  else
587    {
588#ifndef NotOrig
589      data[1] = (unsigned char)val;
590      data[0] = (unsigned char)(val >> 8);
591#else
592      data[0] = (unsigned char)val;
593      data[1] = (unsigned char)(val >> 8);
594#endif
595    }
596}
597
598static SANE_Status
599hp_accessor_vector_get (HpAccessor _this, HpData d, void * valp)
600{
601  HpAccessorVector	this	= (HpAccessorVector)_this;
602  SANE_Fixed *		ptr	= valp;
603  const SANE_Fixed *	end	= ptr + this->length;
604  const unsigned char *	data	= hp_data_data(d, this->data_offset);
605
606  data += this->offset;
607
608  while (ptr < end)
609    {
610      *ptr++ = (*this->scale)(this, _v_get(this, data));
611      data += this->stride;
612    }
613  return SANE_STATUS_GOOD;
614}
615
616static SANE_Status
617hp_accessor_vector_set (HpAccessor _this, HpData d, void * valp)
618{
619  HpAccessorVector	this	= (HpAccessorVector)_this;
620  SANE_Fixed *		ptr	= valp;
621  const SANE_Fixed *	end	= ptr + this->length;
622  unsigned char *	data	= hp_data_data(d, this->data_offset);
623
624  data += this->offset;
625
626  while (ptr < end)
627    {
628      if (*ptr < this->fmin)
629	  *ptr = this->fmin;
630      if (*ptr > this->fmax)
631	  *ptr = this->fmax;
632
633      _v_set(this, data, (*this->unscale)(this, *ptr++));
634
635      data += this->stride;
636    }
637  return SANE_STATUS_GOOD;
638}
639
640static unsigned short
641_vector_unscale (HpAccessorVector this, SANE_Fixed fval)
642{
643  unsigned short max_val = this->mask;
644  return (fval * max_val + SANE_FIX(0.5)) / SANE_FIX(1.0);
645}
646
647static SANE_Fixed
648_vector_scale (HpAccessorVector this, unsigned short val)
649{
650  unsigned short max_val = this->mask;
651  return (SANE_FIX(1.0) * val + max_val / 2) / max_val;
652}
653
654HpAccessor
655sanei_hp_accessor_vector_new (HpData data, unsigned length, unsigned depth)
656{
657  static const struct hp_accessor_type_s type = {
658      hp_accessor_vector_get, hp_accessor_vector_set, 0, 0
659  };
660  unsigned		width	= depth > 8 ? 2 : 1;
661  _HpAccessorVector	new	= sanei_hp_alloc(sizeof(*new));
662
663  if (!new)
664      return 0;
665
666  assert(depth > 0 && depth <= 16);
667  assert(length > 0);
668
669  new->type = &type;
670  new->data_size   = length * width;
671  new->data_offset = hp_data_alloc(data, new->data_size);
672
673  new->mask  = ((unsigned)1 << depth) - 1;
674  new->length = length;
675  new->offset = 0;
676  new->stride = width;
677
678  new->scale   = _vector_scale;
679  new->unscale = _vector_unscale;
680
681  new->fmin = SANE_FIX(0.0);
682  new->fmax = SANE_FIX(1.0);
683
684  return (HpAccessor)new;
685}
686
687static unsigned short
688_gamma_vector_unscale (HpAccessorVector __sane_unused__ this, SANE_Fixed fval)
689{
690  unsigned short unscaled = fval / SANE_FIX(1.0);
691  if (unscaled > 255) unscaled = 255;
692  unscaled = 255 - unscaled;  /* Don't know why. But this is how it works. */
693
694  return unscaled;
695}
696
697static SANE_Fixed
698_gamma_vector_scale (HpAccessorVector __sane_unused__ this, unsigned short val)
699{
700  SANE_Fixed scaled;
701  val = 255-val;     /* Don't know why. But this is how it works. */
702  scaled = val * SANE_FIX(1.0);
703
704  return scaled;
705}
706
707HpAccessor
708sanei_hp_accessor_gamma_vector_new (HpData data, unsigned length,
709                                    unsigned depth)
710{
711  _HpAccessorVector	this	=
712      ( (_HpAccessorVector) sanei_hp_accessor_vector_new(data, length, depth) );
713
714
715  if (!this)
716      return 0;
717
718  this->offset += this->stride * (this->length - 1);
719  this->stride = -this->stride;
720
721  this->scale   = _gamma_vector_scale;
722  this->unscale = _gamma_vector_unscale;
723
724  this->fmin = SANE_FIX(0.0);
725  this->fmax = SANE_FIX(255.0);
726
727  return (HpAccessor)this;
728}
729
730static unsigned short
731_matrix_vector_unscale (HpAccessorVector this, SANE_Fixed fval)
732{
733  unsigned short max_val  = this->mask >> 1;
734  unsigned short sign_bit = this->mask & ~max_val;
735  unsigned short sign	  = 0;
736
737  if (fval == SANE_FIX(1.0))
738      return sign_bit;
739
740  if (fval < 0)
741    {
742      sign = sign_bit;
743      fval = -fval;
744    }
745  return sign | ((fval * max_val + this->fmax / 2) / this->fmax);
746}
747
748static SANE_Fixed
749_matrix_vector_scale (HpAccessorVector this, unsigned short val)
750{
751  unsigned short max_val  = this->mask >> 1;
752  unsigned short sign_bit = this->mask & ~max_val;
753  SANE_Fixed	 fval;
754
755  if (val == sign_bit)
756      return SANE_FIX(1.0);
757
758  fval = (this->fmax * (val & max_val) + max_val / 2) / max_val;
759
760  if ((val & sign_bit) != 0)
761      fval = -fval;
762
763  return fval;
764}
765
766HpAccessor
767sanei_hp_accessor_matrix_vector_new (HpData data, unsigned length,
768                                     unsigned depth)
769{
770  _HpAccessorVector	this	=
771      ( (_HpAccessorVector) sanei_hp_accessor_vector_new(data, length, depth) );
772
773  if (!this)
774      return 0;
775
776  this->scale   = _matrix_vector_scale;
777  this->unscale = _matrix_vector_unscale;
778
779  this->fmax = depth == 10 ? SANE_FIX(4.0) : SANE_FIX(2.0);
780  this->fmax *= (this->mask >> 1);
781  this->fmax >>= (depth - 1);
782  this->fmin = - this->fmax;
783
784  return (HpAccessor)this;
785}
786
787HpAccessor
788sanei_hp_accessor_subvector_new (HpAccessorVector super,
789			   unsigned nchan, unsigned chan)
790{
791  _HpAccessorVector	this	= sanei_hp_memdup(super, sizeof(*this));
792
793  if (!this)
794      return 0;
795
796  assert(chan < nchan);
797  assert(this->length % nchan == 0);
798
799  this->length /= nchan;
800
801  if (this->stride < 0)
802      this->offset += (nchan - chan - 1) * this->stride;
803  else
804      this->offset += chan * this->stride;
805
806  this->stride *= nchan;
807
808  return (HpAccessor)this;
809}
810
811/*
812 * class HpAccessorGeometry
813 */
814
815typedef const struct hp_accessor_geometry_s *	HpAccessorGeometry;
816typedef struct hp_accessor_geometry_s *		_HpAccessorGeometry;
817
818struct hp_accessor_geometry_s
819{
820    HpAccessorType	type;
821    size_t		data_offset;
822    size_t		data_size;
823
824    HpAccessor		this;
825    HpAccessor		other;
826    hp_bool_t		is_br;
827    HpAccessor		resolution;
828};
829
830
831static SANE_Status
832hp_accessor_geometry_set (HpAccessor _this, HpData data, void * _valp)
833{
834  HpAccessorGeometry	this	= (HpAccessorGeometry)_this;
835  SANE_Fixed *		valp	= _valp;
836  SANE_Fixed		limit;
837
838  sanei_hp_accessor_get(this->other, data, &limit);
839  if (this->is_br ? *valp < limit : *valp > limit)
840      *valp = limit;
841  return sanei_hp_accessor_set(this->this, data, valp);
842}
843
844static int
845_to_devpixels (SANE_Fixed val_mm, SANE_Fixed mm_per_pix)
846{
847  assert(val_mm >= 0);
848  return (val_mm + mm_per_pix / 2) / mm_per_pix;
849}
850
851static int
852hp_accessor_geometry_getint (HpAccessor _this, HpData data)
853{
854  HpAccessorGeometry	this	= (HpAccessorGeometry)_this;
855  SANE_Fixed		this_val, other_val;
856  int			res	= sanei_hp_accessor_getint(this->resolution,
857                                                           data);
858  SANE_Fixed		mm_per_pix = (SANE_FIX(MM_PER_INCH) + res / 2) / res;
859
860  assert(res > 0);
861  sanei_hp_accessor_get(this->this, data, &this_val);
862
863  if (this->is_br)
864    {
865      /* Convert to extent. */
866      sanei_hp_accessor_get(this->other, data, &other_val);
867      assert(this_val >= other_val && other_val >= 0);
868      return (_to_devpixels(this_val, mm_per_pix)
869	      - _to_devpixels(other_val, mm_per_pix) + 1);
870    }
871  return _to_devpixels(this_val, mm_per_pix);
872}
873
874/*
875 * we should implement hp_accessor_geometry_setint, but we don't
876 * need it yet...
877 */
878
879
880HpAccessor
881sanei_hp_accessor_geometry_new (HpAccessor val, HpAccessor lim, hp_bool_t is_br,
882			  HpAccessor resolution)
883{
884  static const struct hp_accessor_type_s type = {
885      hp_accessor_fixed_get, hp_accessor_geometry_set,
886      hp_accessor_geometry_getint, 0
887  };
888  _HpAccessorGeometry new = sanei_hp_alloc(sizeof(*new));
889
890  new->type = &type;
891  new->data_offset = val->data_offset;
892  new->data_size   = val->data_size;
893
894  new->this  = val;
895  new->other = lim;
896  new->is_br = is_br;
897  new->resolution = resolution;
898
899  return (HpAccessor)new;
900}
901