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