;*DDK*************************************************************************/
;
; COPYRIGHT (C) Microsoft Corporation, 1989
; COPYRIGHT    Copyright (C) 1995 IBM Corporation
;
;    The following IBM OS/2 WARP source code is provided to you solely for
;    the purpose of assisting you in your development of OS/2 WARP device
;    drivers. You may use this code in accordance with the IBM License
;    Agreement provided in the IBM Device Driver Source Kit for OS/2. This
;    Copyright statement may not be removed.;
;*****************************************************************************/
        page    ,132
;/*****************************************************************************
;*
;* SOURCE FILE NAME = COLORTBL.ASM
;*
;* DESCRIPTIVE NAME = routines which interact with color tables
;*
;*
;* VERSION      V2.0
;*
;* DATE         05/16/87
;*
;* DESCRIPTION  This file contains the routines which interact with color tables. 
;*
;* FUNCTIONS    QueryColorData
;*              RealizeColorTable
;*              UnrealizeColorTable
;*              CreateLogColorTable
;*              QueryLogColorTable
;*              QueryRealColors
;*              QueryNearestColor
;*              QueryColorIndex
;*              far_calc_rgb_distance
;*              calc_rgb_distance
;*              rgb_to_nearest_index
;*              far_ipc_to_index
;*              ipc_to_index
;*              QueryRGBColor
;*              save_lct
;*              deselect_lct
;*              far_PropagateSysClrCh
;*              PropagateSysClrChange
;*
;* NOTES        NONE
;*
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES
;*
;*              NONE
;*
;* EXTERNAL FUNCTIONS
;*
;*              NONE
;*
;* CHANGE ACTIVITY =
;*   DATE      FLAG        APAR   CHANGE DESCRIPTION
;*   --------  ----------  -----  --------------------------------------
;*   mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx
;*   05/16/87                     Author:  Hock Lee [hockl] 
;*   07/03/87                     Hock Lee [hockl]
;*                                Changed to share code with
;*                                QueryLogColorTable.
;*                                Hock Lee [hockl]
;*                                Rewrote to include logical color table.
;*   07/09/87                     Hock Lee [hockl]
;*                                Fixed bugs and rewrote.
;*   07/16/87                     Hock Lee [hockl]
;*                                Modified for new DDI.
;*   08/20/87                     Hock Lee [hockl]
;*                                Updated ddc color attributes.
;*   09/16/87                     Hock Lee [hockl]
;*                                Moved ColorData[3..5] to QueryDeviceCaps.
;*                                Hock Lee [hockl]
;*                                Changed color index for colors
;*                                unspecifiable in current color table to -254.
;*   02/10/88                     Whitmer [chuckwh]
;*                                Rewritten for new color tables.
;*   02/17/88                     Charles Whitmer [chuckwh]
;*                                Separated from UnrealizecolorTable.
;*   04/26/88                     Charles Whitmer [chuckwh]
;*                                Added the ability to return the color set
;*                                in the color table.
;*   05/17/88                     Walt Moore [waltm]
;*                                DCR23884 to track realize bit.
;*   07/05/88                     Hock Lee [hockl]
;*                                Fixed PTR 5105.
;*   08/17/88                     Robert J. Carragher [t-robc]
;*                                Changed IPC_INDEX_MASK to ipc_index_mask
;*                                so merging with other drivers is easier
;*                                (other drivers use the variable, not the
;*                                constant).
;*****************************************************************************/

        .286p
        .xlist
        include cmacros.inc
INCL_GPIBITMAPS         equ                      1 ;for RGB2 defintion
INCL_GPILOGCOLORTABLE   equ                      1
INCL_GRE_COLORTABLE     equ                      1
INCL_DDIMISC            equ                      1
BOGUS                   equ                      1 ;!!! this sucks, fix it.
INCL_WINSYS             equ                      1
INCL_DDICOMFLAGS        equ                      1
        include pmgre.inc
DINCL_CLR_TBL           equ                      1
        include driver.inc
        include display.inc
        include njmp.mac
        include assert.mac
        include 8514.inc
        include palette.inc
        .list
        CPUMode 286

        errcode <INSUFFICIENT_MEMORY,INV_COLOR_START_INDEX,INV_LENGTH_OR_COUNT>
        errcode <INV_RGBCOLOR,INV_COLOR_OPTIONS,REALIZE_NOT_SUPPORTED>
        errcode <INV_COLOR_DATA,INV_COLOR_FORMAT,COL_TABLE_NOT_REALIZABLE>
        errcode <INV_IN_PATH,INV_IN_AREA,INV_COLOR_INDEX,COL_TABLE_NOT_REALIZED>
        errcode <PALETTE_SELECTED>

        externFP        far_enter_driver
        externFP        far_leave_driver

;/*
;** ipc_index_mask created to make merging with other drivers easier (other
;** drivers use the variable, not the constant).
;*/
        externW         ipc_index_mask
        externA         MIN_SYSTEM_COLOR
        externA         MIN_SYSTEM_COLOR
        externA         DEVCAPS_COLORS

BACKGND_WORD    equ     0*2                       ;Indicies for accessing rgbs and ipcs
FOREGND_WORD    equ     7*2
BACKGND_DWORD   equ     0*4
FOREGND_DWORD   equ     7*4


sBegin  Data
        externD         phwpal
        externB         argbHW
        externB         ddcInit
        externB         ctDefault
        externB         adrgbDefault
        externW         aipcSpecial
        externD         adrgbSpecial
        externD         adrgbIndex
        externW         ipcSysClrWindow
        externW         ipcSysClrWindowText
        externD         drgbSysClrWindow
        externD         drgbSysClrWindowText
        externD         RealizedPalette
        externD         xlate_rgb_to_palette
        externB         fpalettetype
        externB         saved_fbClrTbl
        externB         saved_ClrTbl
        externD         PalColor

sEnd    Data

        externFP        DosAllocHuge
        externFP        DosFreeSeg
        externFP        far_rgb_to_ipc_with_pal_6
        externFP        far_rgb_to_ipc_with_pal

sBegin  InitSeg
        externNP        private_alloc
        externNP        private_free
sEnd    InitSeg

sBegin  Code
        externW         CodeData

        externNP        enter_driver
        externNP        leave_driver
        externNP        rgb_to_ipc
        externNP        ColorConvert
        externNP        enter_driver
        externNP        leave_driver
        externNP        MakeBrushValid

sEnd    Code

sBegin  FarCode
        assumes cs,FarCode

        externW         FarCodeData


page

;/***************************************************************************
;*
;* FUNCTION NAME = QueryColorData  
;*
;* DESCRIPTION   = This function is called from the GRE's dispatch table in
;*                 response to a GreQueryColorData function call and       
;*                 returns information about the currently available color 
;*                 table and device colors.  Information will only be      
;*                 returned for the number of elements supplied.  Any extra
;*                 elements supplied will be zeroed.                       
;*                                                                         
;*                 Registers Preserved:                                                               
;*                       SI,DI,BP,DS                                                                  
;*                 Registers Destroyed:                                                               
;*                       AX,BX,CX,DX,ES,FLAGS                                                         
;*                                                                         
;* INPUT         = C Prototype:                                                             
;*                   BOOL _syscall QueryColorData(HDC   hdc,                                
;*                                                LONG  cArray,                             
;*                                                PLONG pArray,                             
;*                                                PVOID pInstance,                          
;*                                                ULONG lFunction);                         
;*                                                                                          
;*                    where:                                                                
;*                      All arguments are in accordance with the GreQueryColorData 
;*                      function
;*
;* OUTPUT        =  NONE
;*
;* RETURN-NORMAL =  DX:AX = 1    
;* RETURN-ERROR  =  DX:AX = 0    
;*                  Error logged 
;**************************************************************************/

        check   QueryColorData,<hdc,clColorData,plColorData,hddc,ulFunN>

        assumes ds,nothing
        assumes es,nothing

cProc   QueryColorData,<PUBLIC,FAR,NODATA>,<di,si>
        parmD   hdc
        parmD   Count
        parmD   lpColorData
        parmD   hddc
        parmD   FunN
cBegin
        CPUMode 386
        fw_zero <es>
        ddc?    hddc
        mov     ds,FarCodeData
        assumes ds,Data
        mov     si,hddc.lo
        mov     dx,si
        call    enter_driver
        jc      qcd_exit_no_lock                 ;DX:AX = 0 on error

        cmp     Count.hi,0                        ;Count must be <64K for now
        mov     ax,PMERR_INV_LENGTH_OR_COUNT
        jne     qcd_log_error

        mov     cx,Count.lo                       ;CX = count of entries to copy
        njcxz   qcd_good_exit                     ;Nothing to copy
        les     di,lpColorData                    ;ES:DI is destination array
        assumes es,nothing


        test    [si].ddc_fbBelow,DDC_PALETTE ;is there a custom palette
        jz      default_pal

;/*
;** Custom Palette
;*/
        mov     eax,LCOLF_PALETTE
        stosd                                     ;store palette mode
        .errnz  QCD_LCT_FORMAT                    ;First dword
        dec     cx
        jz      qcd_good_exit

        xor     eax,eax
        stosd                                     ;Lo index always zero for a palette
        .errnz  QCD_LCT_LOINDEX-1                ;Second dword

        dec     cx
        jz      qcd_good_exit

        mov     bx,[si].ddc_npdevpal
        lds     bx,[bx].devpal_pPalSeg
        assumes ds,nothing

        movzx   eax,[bx].palseg_usMax
        stosd
        .errnz  QCD_LCT_HIINDEX-2                ;Third dword

        dec     cx
        jz      qcd_good_exit

        movzx   eax,[bx].palseg_fs
        and     ax,(PR_PURECOLOR or PR_OVERRIDE_DEFAULTS)
        .errnz  high PR_PURECOLOR
        .errnz  high PR_OVERRIDE_DEFAULTS
        .errnz  PR_PURECOLOR - LCOL_PURECOLOR    ; our flags are the same as GPI
        .errnz  PR_OVERRIDE_DEFAULTS - LCOL_OVERRIDE_DEFAULT_COLORS

        stosd
        .errnz  QCD_LCT_OPTIONS-3                ;Fourth dword
        jmp     zero_with_dec


default_pal:
;/*
;** Default Palette Mode (possibly color table)
;*/

        mov     bl,[si].ddc_fbClrTbl             ;BL=Color table flags
        mov     ax,LCOLF_RGB                      ;assume RGB mode
        test    bl,DDC_RGB_MODE
        jnz     short return_color_mode ;Mode is rgb
        lds     si,[si].ddc_pClrTbl              ;DS:SI = color table
        assumes ds,nothing
        mov     ax,LCOLF_DEFAULT
        test    bl,DDC_LOG_CLR_TBL
        jz      short return_color_mode ;Mode is default color table
        mov     ax,LCOLF_INDRGB                  ;AH was trashed by the LAR!
        .errnz  high LCOLF_INDRGB                ;We assumed that all these had
        .errnz  high LCOLF_DEFAULT               ;  the same msb
        .errnz  high LCOLF_RGB
        .errnz  high LCOLF_PALETTE

        ; AX has the current mode (format)
return_color_mode:
        cld                                       ;Return current color table format.
        movzx   eax,ax
        stosd
        .errnz  QCD_LCT_FORMAT                    ;First dword

        dec     cx
        jz      short qcd_good_exit
        cmp     al,LCOLF_RGB                      ;RGB mode?
        jne     get_indices                       ;  Yes, zero fill indices
        .errnz  high LCOLF_INDRGB                ;Once again we assumed these all
        .errnz  high LCOLF_DEFAULT               ;  had the same value for the msb
        .errnz  high LCOLF_RGB
        .errnz  high LCOLF_PALETTE

        xor     eax,eax
        stosd                                     ; LO index is zero for RGB mode
        dec     cx
        jz      short qcd_good_exit
        stosd                                     ; HI index is zero for RGB mode
        jmp     short get_options

get_indices:
        movzx   eax,ds:[si].ct_iMin              ;Minimum loaded color index
        stosd
        .errnz  QCD_LCT_LOINDEX-1                ;Second dword

        dec     cx
        jz      short qcd_good_exit              ;No room for the maximum index
        movzx   eax,ds:[si].ct_iMax              ;Maximum loaded color index
        stosd
        .errnz  QCD_LCT_HIINDEX-2                ;Third dword

get_options:
        dec     cx
        jz      short qcd_good_exit              ;No room for the options
ifdef   FIREWALLS
        push    si
        mov     si,hddc.lo
        mov     gs,FarCodeData
        assert  bl,E,gs:[si].ddc_fbClrTbl
        pop     si
endif

        xor     eax,eax                           ;Clear the options
        bt      bl,6                              ;   A84210
        .errnz  DDC_REALIZED-40h
        rcl     eax,2                             ; 00000r00 r=realized bit
        .errnz  LCOL_REALIZED-16

        btc     bl,0                              ; 0000r00p p=pure bit
        .errnz  DDC_DITHER-1
        cmc
        rcl     eax,1
        .errnz  LCOL_PURECOLOR-4

        bt      bl,5                              ; 00r00pR0 R=realizable bit
        .errnz  DDC_REALIZABLE-20h
        rcl     eax,2
        .errnz  LCOL_REALIZABLE-2

        stosd
        .errnz  QCD_LCT_OPTIONS-3                ;Third dword

zero_with_dec:
        dec     cx                                ;Zero will just fall through
zero_extra_dwords:
        shl     cx,1                              ;Turn dword count into word count
        rep     stosw                             ;Stuff lots of zeros

qcd_good_exit:
        mov     ax,1
qcd_exit:
        mov     ds,FarCodeData                    ;Restore ds for leave_driver!
        assumes ds,Data
        call    leave_driver
        cwd
qcd_exit_no_lock:
        fw_zero <es,cx>
        CPUMode 286
cEnd

qcd_log_error:
        save_error_code
        xor     ax,ax
        jmp     short qcd_exit


page
;/***************************************************************************
;*
;* FUNCTION NAME = RealizeColorTable  
;*
;* DESCRIPTION   = This function is invoked from the GRE dispatch table in      
;*                 response to a call to the GreRealizeColorTable function and  
;*                 causes the system, if possible, to ensure that the device    
;*                 physical color table is set to the closest possible match to 
;*                 the logical color table.  We do not support realizable color 
;*                 tables.  We do, however, track the realize bit passed in to  
;*                 CreateLogColorTable.  If they have specified that the color  
;*                 table is realizable and we're in color table mode, then we'll
;*                 return success and log a warning.  Otherwise, we're in RGB   
;*                 mode or color table mode without the realize bit, in which   
;*                 case we'll log the error.                                    
;*                                                                              
;*                 Registers Preserved:                                                                     
;*                       SI,DI,BP,DS                                                                        
;*                 Registers Destroyed:                                                                     
;*                       AX,BX,CX,DX,ES,FLAGS                                                               
;*                                                                              
;* INPUT         = C Prototype:                                                     
;*                   BOOL _syscall RealizeColorTable (HDC   hdc,                                                  
;*                                                    PVOID pInstance,                                            
;*                                                    ULONG lFunction);                                           
;*                                                                                                                
;*                    where:                                                                                      
;*                       All arguments are as specified for the GreRealizeColorTable                              
;*                       function.                                                                                
;*                                                                              
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = DX:AX = 1
;*                 WARNING PMERR_REALIZE_NOT_SUPPORTED logged
;* RETURN-ERROR  = DX:AX = 0
;*                 PMERR_COL_TABLE_NOT_REALIZABLE logged
;*
;**************************************************************************/

        check   RealizeColorTable,<hdc,hddc,ulFunN>

        assumes ds,nothing
        assumes es,nothing

cProc   RealizeColorTable,<PUBLIC,FAR,NODATA>
        parmD   hdc
        parmD   hddc
        parmD   FunN
cBegin
        ddc?    hddc
        cld
        mov     ds,FarCodeData
        assumes ds,Data
        mov     dx,hddc.lo
        call    enter_driver
        Jnc     @F
        Jmp     rct_exit_no_lock                 ; DX:AX = 0 on error

@@:
        no_path_area    rct_exit,both

        mov     bx,hddc.lo
        test    [bx].ddc_fbClrTbl,DDC_REALIZABLE
        Jnz     @F
        jmp     rct_error                         ;Wasn't allowed to realize it
@@:
        test     [bx].ddc_fb,DDC_DEVICE
        jnz     rct_not_bitmap_dc
        jmp     short rct_save_error

rct_not_bitmap_dc:
        test    [bx].ddc_fbAbove,DDC_INFO_DC
        jz      rct_screen_dc
        jmp     short rct_save_error

rct_screen_dc:
        no_path_area    rct_exit,both

        test    [bx].ddc_fbClrTbl,DDC_REALIZABLE
        jnz     rct_no_error
        mov     ax,PMERR_COL_TABLE_NOT_REALIZABLE

rct_save_error:
        save_error_code
        xor     ax,ax                   ;Return error
        jmp     rct_exit

rct_no_error:
        or      [bx].ddc_fbClrTbl,DDC_REALIZED

        ; save the registers we are about to overwrite
        push    si
        push    di
        push    bx

        ; indicate hardware palette will no longer be the default one
        mov     fpalettetype,REALIZED_PALETTE

        ; save the flags byte for use in ColorConvert
        mov     al,[bx].ddc_fbClrTbl
        mov     saved_fbClrTbl,al

        ; copy the Logical Color Table entries to the saved copy
        mov     cx,TABLE_SIZE/2         ; number of words to save
        les     si,[bx].ddc_pClrTbl     ; es:si -> color table
        assumes es,nothing
        mov     bx,si                   ; we want this again in a moment
                                        ; es:si -> color table
        mov     di,DataOFFSET saved_ClrTbl
                                        ; ds:di -> area to save to

        push    di                      ; need to keep this pointer
        ; need to swap ds and es since we are copying data into the
        ; data segment rather than the expected copy out of the data segment
        push    ds
        push    es
        pop     ds
        assumes ds,nothing
        pop     es
        assumes es,Data
        rep     movsw                   ; copy the table
        push    ds
        push    es
        pop     ds
        assumes ds,Data
        pop     es
        assumes es,nothing

        pop     di                      ; we kept this pointer
        mov     ax,[di].ct_npargb       ; this is a near pointer
        sub     ax,bx                   ; change to an offset into the table
        add     ax,di                   ; form a near pointer to the saved table
        mov     [di].ct_npargb,ax       ; place it in the saved table

        mov     si,bx                   ; es:si -> color table again

        ; copy the Logical Color Table entries to the new palette store
        mov     cx,256

        mov     si,es:[si].ct_npargb    ; es:si -> RGB triplets

        mov     bx,DataOFFSET xlate_rgb_to_palette
        mov     di,DataOFFSET RealizedPalette

each_index:
        ; register summary
        ; ds:di -> saved palette entry
        ; es:si -> rgb triplet
        ; ds:bx -> xlate_rgb_to_palette table start

        mov     ax,es:[si+2]    ; get Red value
        xlatb                   ; get value from translate table
        mov     ds:[di],al      ; move translated Red across to palette
        inc     di              ; next byte in palette
        mov     ax,es:[si]      ; get Green and Blue values (green = ah)
        rol     ax,8            ; put Green in al, (blue in ah)
        xlatb                   ; get value from translate table
                                ; uses al as offset, and replaces al
        mov     ds:[di],al      ; move translated Green across to palette
        inc     di              ; next byte in palette
        mov     al,ah           ; get Blue into al
        xlatb                   ; get value from translate table
        mov     ds:[di],al      ; move translated Blue across to palette
        inc     di              ; next byte in palette
next_index:
        add     si,4            ; advance to next RGB triplet
        loop    each_index

        ; copy the saved palette values to the hardware
        mov     si,DataOFFSET RealizedPalette   ; DS:SI = saved palette
        sub     al,al                   ; start at index 0
        mov     cx,256*3                ; will always load 256 color entries
        mov     dx,RAMDAC_WADDR         ; set index of next RGB to set
        cli                             ; entering critical region
        out     dx,al                   ; select the index to start from
        mov     dx,RAMDAC_RGB           ; send RGB data to this port
        rep outsb                       ; output all the RGB values
        sti                             ; exit critical region

        ; restore saved registers
        pop     bx                      ; ds:bx = DDC
        pop     di
        pop     si

        mov     ax,1                              ; Show success (1)
        jmp     rct_exit

rct_error:
        mov     ax,PMERR_COL_TABLE_NOT_REALIZABLE
        save_error_code
        xor     ax,ax                             ;Return error
        errn$   rct_exit
rct_exit:
        call    leave_driver
        cwd
rct_exit_no_lock:
cEnd
sEnd    FarCode

sBegin  PalSeg
        assumes cs,PalSeg
        externW         PalSegData
        externNP        SetHWPalette              ;critsec.asm

;/***************************************************************************
;*
;* FUNCTION NAME = UnrealizeColorTable  
;*
;* DESCRIPTION   = This function is invoked from the GRE dispatch table in  
;*                 response to a call to the GreUnrealize ColorTable        
;*                 function and is the reverse of RealizeColorTable.  It    
;*                 causes the default physical palette to be reinstated.  If
;*                 a realize call has not been made, then an error will be  
;*                 returned.                                                
;*
;*                 Registers Preserved:       
;*                       SI,DI,BP,DS          
;*                 Registers Destroyed:       
;*                       AX,BX,CX,DX,ES,FLAGS 
;*
;* INPUT         = C Prototype:                                                      
;*                   BOOL _syscall UnrealizeColorTable (HDC   hdc,                   
;*                                                      PVOID pInstance,             
;*                                                      ULONG lFunction);            
;*                                                                                   
;*                    where:                                                         
;*                      All arguments are as specified for the GreUnrealizeColorTable
;*                      function.                                                    
;*
;*
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = DX:AX = 1
;* RETURN-ERROR  = DX:AX = 1
;*                 PMERR_COL_TABLE_NOT_REALIZED logged
;**************************************************************************/

        check   UnrealizeColorTable,<hdc,hddc,ulFunN>

        assumes ds,nothing
        assumes es,nothing

cProc   UnrealizeColorTable,<PUBLIC,FAR,NODATA>
        parmD   hdc
        parmD   hddc
        parmD   FunN
cBegin
        ddc?    hddc
        cld
        mov     ds,PalSegData
        assumes ds,Data
        mov     dx,hddc.lo
        call    far_enter_driver
        jc      uct_exit_no_lock                 ; DX:AX = 0 on error

        no_path_area    uct_exit,both

        mov     bx,hddc.lo
        mov     ax,1                              ;Assume success
        test    fpalettetype,REALIZED_PALETTE
        jnz     uct_update_flag
        mov     ax,PMERR_COL_TABLE_NOT_REALIZED
        save_error_code
        xor     ax,ax
        jmp     uct_exit
uct_update_flag:
        and     [bx].ddc_fbClrTbl,not DDC_REALIZED

        ; indicate hardware palette is reset to the default one
        mov     fpalettetype,DEFAULT_PALETTE

        ; actually restore the default palette

        push    0
        push    256
        push    DS
        mov     ax,DataOFFSET argbHW
        push    ax
        push    0

        Call    SetHWPalette

        mov     ax,1                              ; show success

uct_exit:
        call    far_leave_driver
        cwd
uct_exit_no_lock:
cEnd

sEnd    PalSeg

sBegin  Code
        assumes cs,Code

;/***************************************************************************
;*
;* FUNCTION NAME = CreateLogColorTable 
;*
;* DESCRIPTION   = This function defines the entries of the logical color   
;*                 table.  The Engine will perform the error checking for   
;*                 CreateLogColorTable.  It may cause the color table to be 
;*                 preset to the default values.                            
;*                                                                          
;* INPUT         = C Prototype:                                                      
;*                   BOOL _syscall CreateLogColorTable (HDC   hdc,                   
;*                                                      ULONG flOptions,             
;*                                                      LONG  lFormat,               
;*                                                      LONG  lStart,                
;*                                                      LONG  cCount,                
;*                                                      PLONG pData,                 
;*                                                      PVOID pInstance,             
;*                                                      ULONG lFunction);            
;*                                                                                   
;*                    where:                                                         
;*                      All arguments are as specified for the GreCreateLogColorTable
;*                      function.                                                    
;*
;*                 Registers Preserved:                                                                           
;*                       SI,DI,BP,DS                                                                              
;*                 Registers Destroyed:                                                                           
;*                       AX,BX,CX,DX,ES,FLAGS                                                                     
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = DX:AX = 1 
;* RETURN-ERROR  = DX:AX = 0 
;*
;**************************************************************************/

        check   CreateLogColorTable,<hdc,flCmd,ulFormat,lStart,clColorData,plColorData,hddc,ulFunN>

        assumes ds,nothing
        assumes es,nothing

cProc   CreateLogColorTable,<PUBLIC,FAR,NODATA>,<di,si>
        parmD   hdc
        parmD   Options
        parmD   Format
        parmD   Start
        parmD   Count
        parmD   lpColorData
        parmD   hddc
        parmD   FunN

        localD  plNewData
        localW  selClrTbl
cBegin
        ddc?    hddc
        cld
        mov     ds,CodeData
        assumes ds,Data
        mov     si,hddc.lo
        mov     dx,si
        call    enter_driver
        njc     clct_exit_no_lock                ; DX:AX = 0 on error

;/*
;** This function is not allowed when there is a palette selected in the DC.
;*/

        mov     ax,PMERR_PALETTE_SELECTED
        test    [si].ddc_fbBelow,DDC_PALETTE
        jnz     clct_error

        no_path_area    clct_error,both,error

;/*
;** Validate all the arguments.  Option flags have been validated by GPI.
;*/

        xor     bx,bx                             ;BX is expected to be zero later
        mov     ax,PMERR_INV_COLOR_FORMAT
        cmp     Format.hi,bx
        jne     clct_error

        mov     cx,Format.lo                      ;Dispatch to the correct
        mov     dx,cx                             ;  format handler
        dec     cx
        jz      clct_format_logical
        .errnz  LCOLF_INDRGB                     - 1
        dec     cx
        jz      clct_format_logical
        .errnz  LCOLF_CONSECRGB - 2
        dec     cx
        jnz     clct_error
        .errnz  LCOLF_RGB                        - 3

;/*
;** Handle LCOLF_RGB mode                               ;
;*/

        mov     bl,DDC_RGB_MODE

;/*
;** Handle LCOLF_DEFAULT. BL = DDC_RGB_MODE flag value or 0.  ;
;**                                                     ;
;** We use this routine if entering RGB mode, or if LCOL_RESET given ;
;** with a count of 0.  If a color table is present, it is freed if ;
;** needed.
;*/

clct_format_default:
        test    [si].ddc_fbClrTbl,DDC_LOG_CLR_TBL
        jz      default_no_table
        les     di,[si].ddc_pClrTbl
        mov     cx,es
        assumes es,nothing
        dec     es:[di].ct_cSave
        jnz     default_no_table
        call    private_free                      ;Takes selector in CX
default_no_table:
        mov     [si].ddc_fbClrTbl,bl
        mov     [si].ddc_pClrTbl.off,DataOFFSET ctDefault
        mov     [si].ddc_pClrTbl.sel,ds
        jmp     clct_common_exit

;/*
;** Yet another error handler                           ;
;*/

clct_error:
        save_error_code
        xor     ax,ax
        mov     ds,CodeData
        assumes ds,Data
        jmp     clct_exit


;/*
;** Handle LCOLF_INDRGB and LCOLF_CONSECRGB           
;**                                                     
;** Currently:    BX = 0                                
;**               CX = 0                                
;**               DX = Format.lo                        
;**               SI --> ddc                            
;*/

clct_format_logical:
        cmp     Count.hi,bx
        jne     clct_bad_count
        mov     cx,Count.lo
        test    Options.lo,LCOL_SYSCOLORS
        jnz     do_system_colors
        jmp     not_system_colors

do_system_colors:
        jcxz    clct_exit_ok_relay               ;Count is zero, nothing to do
        lds     si,lpColorData
        assumes ds,nothing
        mov     es,CodeData
        assumes es,Data
        cmp     dl,LCOLF_CONSECRGB
        je      validate_sys_consecrgb

;/*
;** Do the SYSTEM INDRGB validation.  We want to make sure that all the
;** indicies and RGB triplets are valid.
;*/

validate_sys_indrgb:
        shr     cx,1
        jc      clct_bad_count

validate_sys_indrgb_loop:
        lodsw
        xchg    ax,dx
        lodsw                                     ;AX:DX = index
        sub     dx,MIN_SYSTEM_COLOR              ;Make it 0 based
        sbb     ax,-1
        jnz     clct_bad_index
        cmp     dx,SYSCLR_CSYSCOLORS
        jae     clct_bad_index
        lodsw
        lodsw
        or      ah,ah
        jnz     clct_bad_color
        loop    validate_sys_indrgb_loop

;/*
;** The colors and indicies seem to be valid.  Set the colors into the
;** system colors color tables.
;*/

        mov     si,lpColorData.lo
        mov     cx,Count.lo
        shr     cx,1
sys_indrgb_loop:
        lodsw
        xchg    ax,di                             ;DI = index
        sub     di,MIN_SYSTEM_COLOR              ;DI = entry number
        lodsw                                     ;Discard index.hi
        lodsw
        xchg    ax,dx
        lodsw
        xchg    ax,dx                             ;DX:AX = color
        shl     di,2                              ;DI = 4 * entry number
        mov     adrgbSpecial[di].lo,ax
        mov     adrgbSpecial[di].hi,dx
        call    rgb_to_ipc
        shr     di,1                              ;DI = 2 * entry number
        mov     aipcSpecial[di],ax
        loop    sys_indrgb_loop
        jmp     short clct_finish_sys_colors


clct_exit_ok_relay:
        jmp     clct_exit_ok

clct_bad_color:
        mov     ax,PMERR_INV_COLOR_DATA
        jmp     clct_error

clct_bad_index:
        mov     ax,PMERR_INV_COLOR_INDEX
        jmp     clct_error

clct_bad_start_index:
        mov     ax,PMERR_INV_COLOR_START_INDEX
        jmp     clct_error

clct_bad_count:
        mov     ax,PMERR_INV_LENGTH_OR_COUNT
        jmp     clct_error


;/*
;** Do the SYSTEM CONSECRGB validation.  We want to make sure that all
;** the RGB triplets are valid, and the range is valid.
;*/

        assumes ds,nothing
        assumes es,Data

validate_sys_consecrgb:
        mov     di,Start.lo
        mov     dx,Start.hi
        sub     di,MIN_SYSTEM_COLOR
        sbb     dx,-1
        jnz     clct_bad_start_index
        mov     dx,SYSCLR_CSYSCOLORS
        sub     dx,di
        jbe     clct_bad_start_index
        cmp     cx,dx
        ja      clct_bad_count
validate_sys_consecrgb_loop:
        lodsw
        lodsw
        or      ah,ah
        jnz     clct_bad_color
        loop    validate_sys_consecrgb_loop

;/*
;** The colors and range seem to be valid.  Set the colors into the
;** system color's color tables.
;*/

        add     di,di
        lea     bx,aipcSpecial[di]
        add     di,di
        add     di,DataOFFSET adrgbSpecial
        mov     cx,Count.lo
        mov     si,lpColorData.lo
sys_consecrgb_loop:
        lodsw
        stosw
        xchg    ax,dx
        lodsw
        stosw
        xchg    ax,dx
        call    rgb_to_ipc
        mov     es:[bx],ax
        inc     bx
        inc     bx
        loop    sys_consecrgb_loop

clct_finish_sys_colors:
        mov     ds,CodeData                          ;needed for leave_driver
        assumes ds,Data

;/*
;** Update colors 0 and 7 in the default color table from the special
;** system colors.  We don't expect system colors to change very often.
;*/

clct_exit_ok_sys_clr_change:
        mov     ax,drgbSysClrWindow.lo
        mov     adrgbDefault[BACKGND_DWORD].lo,ax
        mov     ddcInit.ddc_ia.ia_ba.ba_clrBack.lo,ax
        mov     ddcInit.ddc_pa.pa_ba.ba_clrBack.lo,ax
        mov     ddcInit.ddc_la.la_ba.ba_clrBack.lo,ax
        mov     ddcInit.ddc_ca.ca_ba.ba_clrBack.lo,ax
        mov     ddcInit.ddc_ma.ma_ba.ba_clrBack.lo,ax

        mov     ax,drgbSysClrWindow.hi
        mov     adrgbDefault[BACKGND_DWORD].hi,ax
        mov     ddcInit.ddc_ia.ia_ba.ba_clrBack.hi,ax
        mov     ddcInit.ddc_pa.pa_ba.ba_clrBack.hi,ax
        mov     ddcInit.ddc_la.la_ba.ba_clrBack.hi,ax
        mov     ddcInit.ddc_ca.ca_ba.ba_clrBack.hi,ax
        mov     ddcInit.ddc_ma.ma_ba.ba_clrBack.hi,ax

;/*
;** The mono bit in the background ipc is alway correct, so we can
;** simply pick up the IPC and stuff it into all the appropriate places
;*/

        mov     ax,ipcSysClrWindow
        mov     word ptr ctDefault.ct_aipc[BACKGND_WORD],ax
        mov     word ptr ddcInit.ddc_ia.ia_ba.ba_ipcBack,ax
        mov     word ptr ddcInit.ddc_pa.pa_ba.ba_ipcBack,ax
        mov     word ptr ddcInit.ddc_la.la_ba.ba_ipcBack,ax
        mov     word ptr ddcInit.ddc_ca.ca_ba.ba_ipcBack,ax
        mov     word ptr ddcInit.ddc_ma.ma_ba.ba_ipcBack,ax

        mov     ax,drgbSysClrWindowText.lo
        mov     adrgbDefault[FOREGND_DWORD].lo,ax
        mov     ddcInit.ddc_ia.ia_ba.ba_clr.lo,ax
        mov     ddcInit.ddc_pa.pa_ba.ba_clr.lo,ax
        mov     ddcInit.ddc_la.la_ba.ba_clr.lo,ax
        mov     ddcInit.ddc_ca.ca_ba.ba_clr.lo,ax
        mov     ddcInit.ddc_ma.ma_ba.ba_clr.lo,ax

        mov     ax,drgbSysClrWindowText.hi
        mov     adrgbDefault[FOREGND_DWORD].hi,ax
        mov     ddcInit.ddc_ia.ia_ba.ba_clr.hi,ax
        mov     ddcInit.ddc_pa.pa_ba.ba_clr.hi,ax
        mov     ddcInit.ddc_la.la_ba.ba_clr.hi,ax
        mov     ddcInit.ddc_ca.ca_ba.ba_clr.hi,ax
        mov     ddcInit.ddc_ma.ma_ba.ba_clr.hi,ax

;/*
;** Only the color portion of the foreground ipc is correct.  The mono
;** portion may not be correct.  To get around this, we will hold off
;** stuffing the new foreground color until after we have realized the
;** new brush.  At that point, we can pick the ipc up out of the brush
;** and stuff it in all the appropriate places, having let the normal
;** color conversion code (MakeColorsValid) worry about correct mono-
;** chrome color mapping.
;**
;** Since the default ddc uses the default color table, we have to set
;** the color portion of the foreground IPC before making the call.
;*/

        mov     ax,ipcSysClrWindowText
        mov     word ptr ctDefault.ct_aipc[FOREGND_WORD],ax
        inc     ddcInit.ddc_iSysClr              ;Show system colors changed again

;/*
;** We need to realize the correct brush bits now
;*/

        mov     bx,DataOFFSET ddcInit.ddc_pa
        mov     si,DataOFFSET ddcInit
        or      [si].ddc_pa.pa_ba.ba_fb,BA_CLR_INVALID or BA_CLR_BACK_INV
        xor     cx,cx

        cCall   MakeBrushValid,<ax,ax>  ; argument unused
ifdef FIREWALLS
        js      set_sys_clrs_brush_bad
        mov     al,ddcInit.ddc_pa.pa_ba.ba_fb
        test    al,BA_REREALIZE or BA_CLR_INVALID or BA_CLR_BACK_INV
        jnz     set_sys_clrs_brush_bad
        and     al,BA_CLR_DEF or BA_CLR_BACK_DEF
        cmp     al,BA_CLR_DEF or BA_CLR_BACK_DEF
        je      set_sys_clrs_brush_good
set_sys_clrs_brush_bad:
        rip     text,<Setting System Colors Destroyed Default Brush>
set_sys_clrs_brush_good:
endif

;/*
;** Now that ddc_pa.pa_ba.ba_ipc contains the correct mono bit, we need
;** to propagate this bit to the other foreground IPCs.
;*/

        mov     ax,word ptr ddcInit.ddc_pa.pa_ba.ba_ipc
        mov     word ptr ddcInit.ddc_ia.ia_ba.ba_ipc,ax
        mov     word ptr ddcInit.ddc_la.la_ba.ba_ipc,ax
        mov     word ptr ddcInit.ddc_ca.ca_ba.ba_ipc,ax
        mov     word ptr ddcInit.ddc_ma.ma_ba.ba_ipc,ax
        mov     ipcSysClrWindowText,ax
        mov     word ptr ctDefault.ct_aipc[FOREGND_WORD],ax

        jmp     clct_exit_ok

;/*
;** We will be partying on the user's color table, or just creating a     
;** default color table.                                
;**                                                     
;** If the reset option was given and there is no data, then just use 
;** the default table, with whatever control bits they passed in.  If 
;** The reset option wasn't given, we were previously in RGB mode, and    
;** the count is zero, use the default table.         
;**                                                     
;** Currently:    BX = 0                                
;**               CX = Count.lo                         
;**               DX = Format.lo                        
;**               SI --> ddc                            
;*/

        assumes ds,Data
        assumes es,nothing

not_system_colors:
        or      cx,cx
        jnz     count_aint_zero
        test    Options.lo,LCOL_RESET            ;0 + RESET => default table
        jnz     @F
        test    [si].ddc_fbClrTbl,DDC_RGB_MODE
        jnz     @F
        jmp     clct_common_exit                 ;Maybe a little clean up?
@@:
        jmp     clct_format_default              ;Use the default color table


;/*
;** We will never get into any of the code between here and common_exit
;** with a zero count for the number of elements to set.
;**
;** There will be data to be set into the color table.  We want to
;** validate it before we change anything.  That way, we can back
;** out if we need to without having to do major repairs.
;*/

count_aint_zero:
        les     di,lpColorData
        assumes es,nothing
        cmp     dl,LCOLF_CONSECRGB
        mov     dx,LOGICAL_COLOR_TABLE_SIZE
        je      validate_consecrgb

;/*
;** Do the INDRGB validation.                           
;*/

        mov     ax,PMERR_INV_COLOR_INDEX
        shr     cx,1
        jc      clct_inv_len_or_cnt
        mov     bx,PMERR_INV_COLOR_DATA
validate_indrgb_loop:
        cmp     es:[di].lo,dx
        jae     clct_error_relay
        cmp     es:[di].hi,0
        jnz     clct_error_relay
        xchg    ax,bx
        cmp     byte ptr es:[di][7],0
        jnz     clct_error_relay
        xchg    ax,bx
        add     di,SIZE_DWORD*2
        loop    validate_indrgb_loop
        jmp     short everything_ok

clct_inv_len_or_cnt:
        mov     ax,PMERR_INV_LENGTH_OR_COUNT
clct_error_relay:
        jmp     clct_error                        ;AX = error code

;/*
;** Do the CONSECRGB validation.
;*/

validate_consecrgb:
        mov     ax,PMERR_INV_COLOR_START_INDEX
        cmp     Start.hi,0
        jnz     clct_error_relay
        mov     bx,Start.lo
        sub     dx,bx
        jbe     clct_error_relay
        mov     ax,PMERR_INV_LENGTH_OR_COUNT
        cmp     cx,dx
        ja      clct_error_relay
        mov     ax,PMERR_INV_COLOR_DATA
validate_consecrgb_loop:
        cmp     byte ptr es:[di][3],0
        jnz     clct_error_relay
        add     di,SIZE_DWORD
        loop    validate_consecrgb_loop


;/*
;** No doubt about it.  We need to have a color table of our own now.
;** Kind of like becoming 18 and needing your own apartment.
;*/

DRGB_SIZE       = 4
TABLE_SIZE      = SIZE COLOR_TABLE+LOGICAL_COLOR_TABLE_SIZE*(DRGB_SIZE+SIZE_IPC)

everything_ok:
        test    [si].ddc_fbClrTbl,DDC_LOG_CLR_TBL
        jnz     log_table_exists                 ;Already have a color table
        lea     bx,selClrTbl                      ;private_alloc wants SS:BX --> selector
        mov     ax,TABLE_SIZE                     ;  and DX:AX = size
        cwd
        call    private_alloc
        or      cx,cx
        jnz     clct_error_no_memory
        xor     di,di
        mov     [si].ddc_pClrTbl.off,di
        mov     es,selClrTbl
        assumes es,nothing
        mov     [si].ddc_pClrTbl.sel,es ;ES:DI --> color table

;/*
;** LCOL_RESET will initialize all the fields of the color table,
;** so we don;t ahve to perform any initialization.
;*/

        or      Options.lo,LCOL_RESET            ;Must reset the table
        jmp     short have_my_own_table

clct_error_no_memory:
        mov     ax,PMERR_INSUFFICIENT_MEMORY
        jmp     clct_error


;/*
;** See if the existing table belongs to us alone (e.g. not saved).
;** If we don't have exclusive access rights to it, we'll clone it.a
;*/

log_table_exists:
        les     di,[si].ddc_pClrTbl
        assumes es,nothing
        cmp     es:[di].ct_cSave,1
        jz      have_my_own_table
        lea     bx,selClrTbl                      ;private_alloc wants SS:BX --> selector
        mov     ax,TABLE_SIZE                     ;  and DX:AX = size
        cwd
        call    private_alloc
        or      cx,cx
        jnz     clct_error_no_memory
        push    es                                ;Copy the old contents
        push    di
        mov     es,selClrTbl
        assumes es,nothing
        mov     [si].ddc_pClrTbl.sel,es
        xor     di,di
        mov     [si].ddc_pClrTbl.off,di
        pop     si
        pop     ds
        assumes ds,nothing
        mov     cx,TABLE_SIZE / 2
        rep     movsw
        sub     si,TABLE_SIZE                     ;DS:SI = old color table
        sub     di,TABLE_SIZE                     ;ES:DI = new color table
        dec     [si].ct_cSave                     ;We no longer want the old one
        mov     es:[di].ct_cSave,1
        mov     ds,CodeData
        assumes ds,Data
        mov     si,hddc.lo
have_my_own_table:


;/*
;** We now have our very own color table set up ready to take whatever
;** color data that was passed.  We must now handle LCOL_RESET.
;*/

        mov     al,[si].ddc_fbClrTbl             ;Show we have a color table now
        and     al,not DDC_RGB_MODE
        or      al,DDC_LOG_CLR_TBL
        mov     [si].ddc_fbClrTbl,al
        test    Options.lo,LCOL_RESET
        jz      no_reset
        and     al,not (DDC_USER_CLR_0 or DDC_USER_CLR_7)
        mov     [si].ddc_fbClrTbl,al

clct_perform_reset:
        mov     es:[di].ct_usId,CT_IDENT
        mov     es:[di].ct_npargb,ct_aipc + LOGICAL_COLOR_TABLE_SIZE * SIZE_IPC
        mov     es:[di].ct_cSave,1
        mov     es:[di].ct_iMin,0
        mov     es:[di].ct_iMax,DEFAULT_COLOR_TABLE_SIZE - 1
        mov     di,ct_aipc
        mov     si,DataOFFSET ctDefault.ct_aipc
        mov     cx,DEFAULT_COLOR_TABLE_SIZE
        rep     movsw
        mov     ax,INVALID_IPC
        mov     cx,LOGICAL_COLOR_TABLE_SIZE - DEFAULT_COLOR_TABLE_SIZE
        rep     stosw
        mov     cx,2 * DEFAULT_COLOR_TABLE_SIZE
        rep     movsw
        mov     ax,-1
        mov     cx,2 * LOGICAL_COLOR_TABLE_SIZE - 2 * DEFAULT_COLOR_TABLE_SIZE
        rep     stosw
        sub     di,TABLE_SIZE                     ;ES:DI = color table
        mov     si,hddc.lo                        ;DS:SI = HDDC
no_reset:

        ddc?    si
        mov     cx,Count.lo
        jcxz    clct_common_exit_relay
        cmp     Format.lo,LCOLF_CONSECRGB
        jnz     not_consecutive


;/*
;** Handle setting LCOLF_CONSECRGBs into the color table   ;
;*/

        mov     ax,Start.lo                       ;Adjust the min and max
        mov     bx,ax
        cmp     es:[di].ct_iMin,bx
        jb      have_my_min
        mov     es:[di].ct_iMin,bx
have_my_min:
        add     bx,cx
        dec     bx
        cmp     es:[di].ct_iMax,bx
        jg      have_my_max                       ;ct_iMax might be -1
        mov     es:[di].ct_iMax,bx
have_my_max:

;/*
;** If colors 0 or 7 are set by the caller, then we must track these
;** so we don't overwrite them when the system colors change.
;*/

        or      ax,ax
        jnz     dont_have_index_0
        or      [si].ddc_fbClrTbl,DDC_USER_CLR_0
dont_have_index_0:
        cmp     ax,7
        jg      dont_have_index_7
        cmp     bx,7
        jl      dont_have_index_7
        or      [si].ddc_fbClrTbl,DDC_USER_CLR_7
dont_have_index_7:

;/*
;** Set up for the loop and then copy the data over
;*/

        lea     bx,[di].ct_aipc
        add     ax,ax
        add     bx,ax                             ;ES:BX => IPC
        mov     di,es:[di].ct_npargb
        add     di,ax
        add     di,ax                             ;ES:DI => RGB
        lds     si,lpColorData
        assumes ds,nothing                        ;DS:SI => input colors

consecrgb_loop:
        lodsw
        stosw
        xchg    ax,dx
        lodsw
        stosw
        xchg    ax,dx
        call    rgb_to_ipc
        mov     es:[bx],ax
        inc     bx
        inc     bx
        loop    consecrgb_loop
        mov     ds,CodeData
        assumes ds,Data

clct_common_exit_relay:
        jmp     short clct_common_exit


;/*
;** Handle setting LCOLF_INDRGBs into the color table   ;
;*/

not_consecutive:
        shr     cx,1
        lds     si,lpColorData
        assumes ds,nothing
        push    bp                                ;Need an extra register
        xor     bp,bp

indrgb_loop:
        lodsw
        xchg    ax,bx                             ;BX = index
        inc     si                                ;Skip .hi part of index
        inc     si
        lodsw
        xchg    ax,dx
        lodsw
        xchg    ax,dx                             ;DX:AX = color
        cmp     es:[di].ct_iMin,bx
        jb      already_below
        mov     es:[di].ct_iMin,bx
already_below:
        cmp     es:[di].ct_iMax,bx
        jg      already_above                     ; ct_iMax might be -1
        mov     es:[di].ct_iMax,bx
already_above:
        or      bx,bx
        jne     not_index_0
        or      bp,DDC_USER_CLR_0
not_index_0:
        cmp     bx,7
        jne     not_index_7
        or      bp,DDC_USER_CLR_7
not_index_7:
        push    di
        mov     di,es:[di].ct_npargb
        add     bx,bx
        add     di,bx
        add     di,bx
        mov     es:[di].lo,ax
        mov     es:[di].hi,dx
        pop     di
        call    rgb_to_ipc
        mov     es:[di].ct_aipc[bx],ax
        loop    indrgb_loop

        xchg    ax,bp
        pop     bp
        mov     ds,CodeData
        assumes ds,Data
        mov     bx,hddc.lo
        or      [bx].ddc_fbClrTbl,al


;/*
;** We are almost done.  All we need to do is set the dither and relizable;
;** bits, and invalidate all the colors of this ddc.   ;
;*/

clct_common_exit:
        ddc?    hddc
        mov     si,hddc.lo
        mov     al,[si].ddc_fbClrTbl
        and     al,not (DDC_DITHER or DDC_REALIZABLE)
        mov     bx,Options.lo
        test    bl,LCOL_PURECOLOR
        jnz     @F
        or      al,DDC_DITHER
@@:
        test    bl,LCOL_REALIZABLE
        jz      @F
        or      al,DDC_REALIZABLE
@@:
        mov     [si].ddc_fbClrTbl,al
        or      [si].ddc_ca.ca_ba.ba_fb,BA_CLR_INVALID or BA_CLR_BACK_INV or BA_REREALIZE
        or      [si].ddc_pa.pa_ba.ba_fb,BA_CLR_INVALID or BA_CLR_BACK_INV or BA_REREALIZE
        or      [si].ddc_la.la_ba.ba_fb,BA_CLR_INVALID or BA_CLR_BACK_INV or BA_REREALIZE
        or      [si].ddc_ia.ia_ba.ba_fb,BA_CLR_INVALID or BA_CLR_BACK_INV or BA_REREALIZE
        or      [si].ddc_ma.ma_ba.ba_fb,BA_CLR_INVALID or BA_CLR_BACK_INV or BA_REREALIZE

;/*
;** Caching causes a problem in that if the new IPCs match the old, and nothing
;** else changed, we won't pick up on the dithering flag changing.  We will
;** force a rerealization by indicating that the codepoint or font changed.
;*/

        or      [si].ddc_pa.pa_fs,CA_CHANGED

clct_exit_ok:
        mov     ax,1

clct_exit:
        call    leave_driver
        cwd
clct_exit_no_lock:
        fw_zero <es,cx>
cEnd

sEnd    Code

page
sBegin  FarCode
        assumes cs,FarCode

;/***************************************************************************
;*
;* FUNCTION NAME = QueryLogColorTable  
;*
;* DESCRIPTION   = Returns the logical color of the currently associated    
;*                 device, one at a time.                                   
;*
;*                 Registers Destroyed:  
;*                       AX,BX,CX,DX,ES  
;*
;* INPUT         = HDC    hdc                                                                                     
;*                 ULONG  Options                                                                                 
;*                 ULONG  Start                                                                                   
;*                 ULONG  Count                                                                                   
;*                 ULONG *lpColorData                                                                             
;*                 HDDC   hddc                                                                                    
;*                 ULONG  FunN                                                                                    
;*                                                                                   
;*        Options  Flags as follows:
;*            LCOLOPT_INDEX => index is to be returned for each RGB value
;* 
;*        Start    The starting index for which data is to be returned.
;* 
;*        Count    Specifies the number of elements available in the array.
;*                 If LCOLOPT_INDEX is specified, only an even number of
;*                 elements will be returned.
;* 
;*        array    A pointer to an array in which the information is
;*                 returned.  If LCOLOPT_INDEX = B'0', this is an array of
;*                 color values (each value is as defined for
;*                 CreateLogColorTable), starting with the specified
;*                 index, and ending either when there are no further
;*                 loaded entries in the table, or when u32_Count has been
;*                 exhausted.  If the logical color table is not loaded
;*                 with a contiguous set of indices, -1 will be returned
;*                 as the color value for any index values which are not
;*                 loaded.
;*                 If LCOLOPT_INDEX = '1'B, it is an array of alternating
;*                 color indices and values, in the order index1, value1,
;*                 index2, value2,...  If the logical color table is not
;*                 loaded with a contiguous set of indices, any index
;*                 values which are not loaded will be skipped.
;* 
;*  Note that the colors returned may be different from the ones 
;*  defined in CreateLogColorTable.
;*                                                                                   
;* OUTPUT        = As specified for the GreQueryLogColorTable function. 
;*
;* RETURN-NORMAL = DX:AX = number of elements returned                      
;* RETURN-ERROR  =    QLCT_RGB if table in RGB mode.  No elements returned. 
;*                 DX:AX = QLCT_ERROR                                       
;**************************************************************************/

        check   QueryLogColorTable,<hdc,flCmd,lStart,clColorData,plColorData,hddc,ulFunN>

        assumes ds,nothing
        assumes es,nothing

cProc   QueryLogColorTable,<PUBLIC,FAR,NODATA>,<di,si>
        parmD   hdc
        parmD   Options
        parmD   Start
        parmD   Count
        parmD   lpColorData
        parmD   hddc
        parmD   FunN
        localW  nCount
cBegin
        cld
        mov     ds,FarCodeData
        assumes ds,Data
        mov     di,hddc.lo                        ; DS:DI = ddc
        mov     dx,di
        call    enter_driver
        mov     ax,QLCT_ERROR                     ; assume error
        cwd
        njc     qlct_exit_no_lock

;/*
;** reject DC if palette is selected
;*/

        mov     ax,PMERR_PALETTE_SELECTED
        test    [di].ddc_fbBelow,DDC_PALETTE
        jnz     qlct_error

;/*
;** reject     options
;*/

        xor     bx,bx                             ; BX = 0
        mov     nCount,bx                         ; nCount = 0
        mov     ax,PMERR_INV_LENGTH_OR_COUNT
        cmp     Count.hi,bx
        jnz     qlct_error
        mov     ax,PMERR_INV_COLOR_START_INDEX
        cmp     Start.hi,bx
        jnz     qlct_error
        mov     ax,PMERR_INV_COLOR_OPTIONS
        cmp     Options.hi,bx
        jnz     qlct_error
        test    Options.lo,not LCOLOPT_INDEX
        jz      no_obvious_errors
qlct_error:
        save_error_code
        mov     ax,QLCT_ERROR                     ; -1
        jmp     qlct_exit
no_obvious_errors:

;/*
;** Make sure any color table is up to date with the system colors
;*/

        mov     ax,[di].ddc_iSysClr
        cmp     ax,ddcInit.ddc_iSysClr
        je      @F
        call    PropagateSysClrChange
@@:

;/*
;** return if in RGB mode
;*/

        mov     ax,QLCT_RGB                       ; -2
        mov     cl,[di].ddc_fbClrTbl             ; CL = ddc_fbClrTbl
        test    cl,DDC_RGB_MODE
        jnz     qlct_exit

;/*
;** locate logical color table
;*/

        mov     si,[di].ddc_pClrTbl.off
        test    cl,DDC_LOG_CLR_TBL
        jz      have_color_table                 ; only load selector if not Data
        mov     ds,[di].ddc_pClrTbl.sel
        assumes ds,nothing
have_color_table:                                 ; DS:SI = logical color table

;/*
;** determine the number of elements that fit in the return array
;*/

        mov     cx,Count.lo
        jcxz    color_table_copied      ; We're done if they asked for no entries

;/*
;** determine the number that we could copy from the table
;*/

        mov     ax,Start.lo                       ; AX = Logical Color Index
        mov     dx,[si].ct_iMax
        inc     dx
        sub     dx,ax
        jbe     color_table_copied

;/*
;** prepare to copy color table
;*/

        les     di,lpColorData                    ; ES:DI = output buffer
        assumes es,nothing
        mov     si,[si].ct_npargb                ; DS:SI = RGB colors

;/*
;** advance to first index
;*/

        add     si,ax                             ; 4 bytes per RGB entry
        add     si,ax
        add     si,ax
        add     si,ax

;/*
;** split to two loops
;*/

        test    Options.lo,LCOLOPT_INDEX
        jnz     copy_with_index_loop

;/*
;** limit the number we may return to the number we have
;*/

        cmp     cx,dx
        jb      count_is_low_enough
        mov     cx,dx
count_is_low_enough:

;/*
;** just copy the colors
;*/

        mov     ax,cx
        shl     cx,1                              ; change DWORD count to WORD count
        rep     movsw
        jmp     short qlct_exit

;/*
;** copy indices and colors
;*/

copy_with_index_loop:
        xchg    cx,dx                             ; cx = max table entry
        shr     dx,1                              ; dx = # of entries asked for
index_loop:
        cmp     byte ptr [si][3],-1
        jz      skip_color
        stosw                                     ; store index
        xchg    ax,bx                             ; BX = 0  from above!
        stosw                                     ; zero out the high word of the index
        xchg    ax,bx
        movsw                                     ; copy the rgb value
        movsw
        add     nCount,2
        dec     dx                                ; we've filled another element in the
        jz      color_table_copied               ; users array. Is it full Yet?
        sub     si,4
skip_color:
        add     si,4
        inc     ax                                ; advance index
        loop    index_loop                        ; have we exhausted the table yet?

;/*
;** return the number copied
;*/

color_table_copied:
        mov     ax,nCount
qlct_exit:
        cwd
        mov     ds,FarCodeData
        assumes ds,Data
        call    leave_driver
qlct_exit_no_lock:
cEnd

;/***************************************************************************
;*
;* FUNCTION NAME = QueryRealColors  
;*
;* DESCRIPTION   = Returns the RGB values of the distinct colors available  
;*                 on the currently associated device, one at a time.       
;*                                                                          
;*                 Registers Destroyed:                                                         
;*                       AX,BX,CX,DX,ES                                                         
;*                                                                          
;* INPUT         = Options,                                                                                        
;*                 Start,                                                                                          
;*                 Count,                                                                                          
;*                 lpColorData,                                                                                    
;*                 hdc,                                                                                            
;*                 FunN                                                                                            
;*                 
;*                    where:                                                                                      
;*         Options
;*                 Specifies various options:
;*                 Realized (bit 0) Set to 1 if the info required is to be for
;*                         when the logical color table (if any) is realized;
;*                         0 if it is to be for when it is not realized.
;*                 Index    (bit 1) Set to 1 if the index is to be returned
;*                         for each rgb value.
;*         Start
;*                 The ordinal number of the first color required.  To start
;*                 the sequence this would be 0.  Note that this does not
;*                 neccessarily bear any relationship to the color index;
;*                 the order in which the colors are returned is not defined.
;*         Count
;*                 the number of elements available in array.
;*                 If index is specified, only an even number of
;*                 elements will be returned.
;*
;*         lpColorData
;*                 A pointer to a array in which the info is returned.  If
;*                 index = 0, this is an array of color values (each value
;*                 is as defined for CreateLogColorTable).  If index = 1,
;*                 it is an array of alternating color indices and values,
;*                 in the order index1, value1, index2, value2,...
;*                                                                          
;* OUTPUT        = As specified for the GreQueryRealColors function.
;*
;* RETURN-NORMAL = DX:AX = number of elements returned 
;* RETURN-ERROR  = None
;*
;**************************************************************************/

        check   QueryRealColors,<hdc,flCmd,lStart,clColorData,plColorData,hddc,ulFunN>

        assumes ds,nothing
        assumes es,nothing

cProc   QueryRealColors,<PUBLIC,FAR,NODATA>,<di,si>
        parmD   hdc
        parmD   Options
        parmD   Start
        parmD   Count
        parmD   lpColorData
        parmD   hddc
        parmD   FunN
        localW  nCount
        localW  nCountLeft
        localW  ColorFlags
        localD  pPal
cBegin
        cld
        mov     ds,FarCodeData
        assumes ds,Data
        mov     dx,hddc.lo
        call    enter_driver
        mov     ax,-1                             ; assume error
        cwd
        njc     qrc_exit_no_lock

;/*
;** validate the arguments
;*/

        mov     ax,PMERR_INV_LENGTH_OR_COUNT
        xor     bx,bx                             ; BX = 0
        cmp     Count.hi,bx
        jnz     qrc_error
        mov     ax,PMERR_INV_COLOR_OPTIONS
        cmp     Options.hi,bx
        jnz     qrc_error
        test    Options.lo,not (LCOLOPT_REALIZED + LCOLOPT_INDEX)
        jz      qrc_valid
        jmp     short qrc_error
qrc_inv_start:
        mov     ax,PMERR_INV_COLOR_START_INDEX
        errn$   qrc_error
qrc_error:
        save_error_code
        mov     ax,GPI_ALTERROR
        cwd
        jmp     qrc_final_exit

qrc_valid:

        mov     nCount,bx                         ; initialize nCount

;/*
;** get the count of colors we may return
;*/

        mov     cx,Count.lo
        njcxz   qrc_exit
        test    Options.lo,LCOLOPT_INDEX; do we return index as well?
        jz      count_is_num_entry
        shr     cx,1
count_is_num_entry:                               ; CX = color Count

;/*
;** get the count of colors remaining
;*/

        assert  bx,E,0
        cmp     Start.hi,bx
        jnz     qrc_inv_start
        mov     ax,Start.lo                       ; AX = Start
        mov     dx,DEVCAPS_COLORS
        sub     dx,ax                             ; DX = count remaining
        jbe     qrc_inv_start                     ; start out of range

;/*
;** limit the color count to the count remaining
;*/

        cmp     cx,dx
        jb      qrc_small_enough
        mov     cx,dx                             ; CX = colors to copy
qrc_small_enough:
        assert  cx,NE,0
        mov     nCountLeft,cx

;/*
;** we can calculate the return value now
;*/

        test    Options.lo,LCOLOPT_INDEX
        jz      count_is_num_element
        shl     cx,1
count_is_num_element:
        mov     nCount,cx


;/*
;** get pointer to the RGB table
;*/
        mov     si,hddc.lo                         ; ds:bx = DDC
        test    Options.lo,LCOL_RESET
        jnz     got_rgb_pointer
        test    [si].ddc_fbClrTbl,DDC_RGB_MODE
        jnz     got_rgb_pointer

        mov     si, DataOFFSET adrgbIndex

        jmp     got_one_or_the_other

got_rgb_pointer:


;/*
;** All of the above is common to both default and custom palettes.  The
;** rest of the work is different depending on the situation.
;*/

        mov     si,hddc.lo
        test    [si].ddc_fbBelow,DDC_PALETTE
        jnz     qrc_palette

;/*
;** get pointer to the RGB table
;*/

        mov     si,DataOFFSET argbHW

got_one_or_the_other:

        add     ax,ax
        add     ax,ax
ifdef   CLR2
;/*
;** The only choices are black and white.
;*/
        mov     dx,15
        mul     dx
endif ; CLR2
        add     si,ax

;/*
;** do the copy loop
;*/

        les     di,lpColorData                    ; ES:DI = lpColorData
        assumes es,nothing
        mov     bx,hddc.lo                        ; DS:BX = ddc
qrc_loop:

;/*
;** store the index first, if requested
;*/

        test    Options.lo,LCOLOPT_INDEX
        jz      qrc_no_index
        mov     ax,[si].lo
        mov     dx,[si].hi
        call    rgb_to_ipc                         ; AX = our physical color
        call    far ptr far_ipc_to_index         ; DX:AX = index
        stosw
        xchg    ax,dx
        stosw
qrc_no_index:

;/*
;** copy the color
;*/

        movsw
        movsw
        mov     byte ptr es:[di-1],0              ; clear rgb2_fcOptions

        dec     nCountLeft
        jnz     qrc_loop
        jmp     short qrc_exit

;/*
;** There's a palette.  The inner loop is different enough to require
;** a special section to handle this case.
;*/

qrc_inv_options:
        mov     ax,PMERR_INV_COLOR_OPTIONS
        jmp     qrc_error

qrc_palette:
        test    Options.lo,LCOLOPT_REALIZED
        jnz     qrc_inv_options

        mov     bx,[si].ddc_npdevpal
        mov     cx,[bx].devpal_pPalSeg.lo
        mov     pPal.lo,cx
        mov     cx,[bx].devpal_pPalSeg.hi
        mov     pPal.hi,cx

        lds     si,phwpal
        assumes ds,nothing
        shl     ax,2
        .errnz  (SIZE RGB2) - 4
        add     si,ax

;/*
;** do the copy loop
;*/

        les     di,lpColorData                    ; ES:DI = lpColorData
        assumes es,nothing

;/*
;** store the index first, if requested
;*/

qrc_pal_loop:
        test    Options.lo,LCOLOPT_INDEX
        jz      qrc_copy_color
        mov     ax,[si].lo
        mov     dx,[si].hi

        farPtr  myRGBColor,dx,ax
        cCall   far_rgb_to_ipc_with_pal_6,<myRGBColor,pPal>
        or      dx,dx
        jnz     qrc_no_index_pal
        stosw
        xchg    ax,dx
        stosw
        jmp     short qrc_copy_color

qrc_no_index_pal:
        mov     ax,CLR_NOINDEX and 0FFFFh
        stosw
        mov     ax,CLR_NOINDEX shr 16
        stosw

;/*
;** copy the color
;*/

qrc_copy_color:
        movsw
        movsw
        mov     byte ptr es:[di-1],0              ; clear rgb2_fcOptions
ifdef   CLR2
;/*
;** The only choices are black and white.
;*/
        add     si,14*4
endif ; CLR2
        dec     nCountLeft
        njnz    qrc_loop

;/*
;** Return the count of colors copied.
;*/

qrc_exit:
        mov     ax,nCount
        cwd
qrc_final_exit:
        call    leave_driver
qrc_exit_no_lock:
cEnd

sEnd    FarCode

;/***************************************************************************
;*
;* FUNCTION NAME = QueryNearestColor  
;*
;* DESCRIPTION   = Returns the nearest color available to the specified     
;*                 color.  Both colors are specified as RGB.  Note that the 
;*                 nearest color returned may not be present in the current 
;*                 logical color table.                                     
;*                                                                          
;*                 Registers Destroyed:                                                           
;*                       AX,BX,CX,DX,ES  
;*
;* INPUT         = Options,
;*                 RGBIn,
;*                 hdc,
;*                 FunN
;*                                                                                          
;*         where:
;*
;*         Options
;*                 Specifies various options:
;*                 Realized (bit 0) Set to 1 if the info required is to be for
;*                         when the logical color table (if any) is realized;
;*                         0 if it is to be for when it is not realized.
;*         RGBIn
;*                 The required color
;*
;* OUTPUT        = As specified in the GreQueryNearestColor function.  
;*
;* RETURN-NORMAL = AX = RgbColorOut (the nearest available color 
;*                 to the specified color)
;* RETURN-ERROR  = As specified in the GreQueryNearestColor function.
;*
;**************************************************************************/

sBegin  Code
        assumes cs,Code

        check   QueryNearestColor,<hdc,flCmd,clr,hddc,ulFunN>

        assumes ds,nothing
        assumes es,nothing

cProc   QueryNearestColor,<PUBLIC,FAR,NODATA>,<si,di>
        parmD   hdc
        parmD   Options
        parmD   RGBIn
        parmD   hddc
        parmD   FunN
cBegin

;/*
;** validate the arguments
;*/

        xor     bx,bx
        mov     ax,PMERR_INV_COLOR_OPTIONS
        cmp     Options.hi,bx
        jnz     qnc_error
        test    Options.lo,not LCOLOPT_REALIZED
        jnz     qnc_error
        mov     ax,PMERR_INV_RGBCOLOR
        cmp     byte ptr RGBIn[3],bl
        jz      qnc_valid
qnc_error:
        save_error_code
qnc_exit_no_lock:
        mov     ax,-1
        cwd
        jmp     qnc_final_exit
qnc_inv_options:
        mov     ax,PMERR_INV_COLOR_OPTIONS
        jmp     short qnc_error
qnc_valid:

;/*
;** do the work
;*/

        mov     ds,CodeData
        assumes ds,Data
        mov     dx,hddc.lo
        call    enter_driver
        jc      qnc_exit_no_lock                 ; error exit without leave_driver

ifdef   CLR2

;/*
;** The only choices are black and white.  If R+G+B > 3/2 * 255 then return
;** white.  Otherwise return black.
;*/

        xor     dx,dx
        mov     ax,RGBIn.lo
        xchg    ah,dl
        add     ax,dx                             ; AX = sum of Green and Blue.
        add     ax,RGBIn.hi                       ; AX = sum of Red, Green, and Blue.
        cmp     ax,383                            ; Least integer greater than 3/2 * 255
                                                  ;  Carry is set if nearest is Black.
        sbb     ax,ax                             ; AX = -1 if black, AX = 0 if white
        not     ax                                ; AX = 0 if black, AX = -1 if white
        mov     dl,al                             ; DH already is 0.

else ; not CLR2

;/*
;** get physical color
;*/

        mov     ax,RGBIn.lo                       ; DX:AX = RGB color
        mov     dx,RGBIn.hi

;/*
;** See if there's a palette.
;*/

        mov     si,hddc.lo
        test    [si].ddc_fbBelow,DDC_PALETTE
        jz      qnc_no_palette
        test    Options.lo,LCOLOPT_REALIZED
        jnz     qnc_inv_options

;/*
;** There is a palette.  Return the nearest color possible on the device,
;** given that the caller can put this color into a palette and realize it.
;** Since the 8514 has 6 bits per color component, just clear off the low
;** 2 bits of each and return.
;*/

        and     ax,0FCFCh                         
        and     dx,000FCh                         


        jmp     short qnc_exit

;/*
;** No palette.
;*/

qnc_no_palette:
        call    rgb_to_ipc                        ; AX = physical color index
        and     ax,ipc_index_mask
        mov     bl,al
        xor     bh,bh
        rgbOff  bx
        mov     ax,word ptr argbHW[bx].lo
        mov     dl,byte ptr argbHW[bx].hi
        xor     dh,dh

endif ; CLR2

qnc_exit:
        call    leave_driver
qnc_final_exit:
cEnd

;/***************************************************************************
;*
;* FUNCTION NAME = QueryColorIndex 
;*
;* DESCRIPTION   = This function is invoked from the GRE dispatch table in 
;*                 response to a call to the GreQueryColorIndex function.  
;*                 It returns the logical colr index that is closest to the
;*                 specified RGB color representation for the device.  If  
;*                 the color index is RGB mode, the supplied RGB value is  
;*                 returned.                                               
;*                                                                         
;*                 Registers Destroyed:                                                         
;*                       AX,BX,CX,DX,ES 
;*                                                                         
;* INPUT         = Options, 
;*                 RGBColor,
;*                 hdc,     
;*                 FunN     
;*                                                                                                                
;*        where:                                                                                                  
;*                                                                         
;*         Options
;*                 Specifies various options:
;*                 Realized (bit 0) Set to 1 if the info required is to be for
;*                         when the logical color table (if any) is realized;
;*                         0 if it is to be for when it is not realized.
;*         RGBColor
;*                 Specifies a color in RGB terms
;*
;* OUTPUT        = As specified in the GreQueryColorIndex function
;*
;* RETURN-NORMAL = DX:AX = closest match color index 
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        check   QueryColorIndex,<hdc,flCmd,clr,hddc,ulFunN>

        assumes ds,nothing
        assumes es,nothing

cProc   QueryColorIndex,<PUBLIC,FAR,NODATA>,<si,di>
        parmD   hdc
        parmD   Options
        parmD   RGBColor
        parmD   hddc
        parmD   FunN
cBegin

;/*
;** validate the arguments
;*/

        mov     ax,PMERR_INV_RGBCOLOR
        cmp     byte ptr RGBColor[3],0
        jnz     qci_error
        cmp     Options.hi,0
        jnz     qci_inv_options
        test    Options.lo,not LCOLOPT_REALIZED
        jz      qci_valid
qci_inv_options:
        mov     ax,PMERR_INV_COLOR_OPTIONS
qci_error:
        save_error_code
qci_exit_no_lock:
        mov     ax,-1
        cwd
        jmp     short qci_final_exit
qci_valid:

;/*
;** do it!
;*/

        mov     ds,CodeData
        assumes ds,Data
        mov     dx,hddc.lo
        call    enter_driver
        jc      qci_exit_no_lock                 ; error exit without leave_driver

;/*
;** get physical color
;*/

        mov     bx,hddc.lo                        ; DS:BX = ddc
        mov     ax,RGBColor.lo                    ; DX:AX = RGB color
        mov     dx,RGBColor.hi

;/*
;** See if there's a palette.
;*/

        test    [bx].ddc_fbBelow,DDC_PALETTE
        jz      qci_no_palette
        test    Options.lo,LCOLOPT_REALIZED
        jnz     qci_inv_options

        farPtr  myRGBColor,dx,ax
        farPtr  pPal,<[bx].devpal_pPalSeg.hi>,<[bx].devpal_pPalSeg.lo>
        mov     bx,[bx].ddc_npdevpal
        cCall   far_rgb_to_ipc_with_pal,<myRGBColor,pPal>
        xor     ah,ah                            ;don't want ipc status flags
        cwd
        jmp     short qci_exit

;/*
;** just return the input for RGB mode
;*/

qci_no_palette:
        test    byte ptr [bx].ddc_fbClrTbl,DDC_RGB_MODE
        jnz     qci_exit

;/*
;** look up the index
;*/

        call    rgb_to_ipc                        ; AX = our physical color
        call    ipc_to_index                      ; DX:AX = index
        or      dx,dx
        jz      qci_exit                          ; index found

        cCall   rgb_to_nearest_index,<RGBColor>

qci_exit:
        call    leave_driver                      ; dx:ax = RGBOut
qci_final_exit:
cEnd


;/***************************************************************************
;*
;* FUNCTION NAME = calc_rgb_distance
;*
;* DESCRIPTION   = 
;*                 Registers Destroyed:                                                         
;*                       AX,CX,DX
;*                                                                         
;* INPUT         = dl = Red         RGB color 1 
;*                 ah = Green                   
;*                 al = Blue                    
;*                                              
;*                 dh = red         RGB color 2                                                                   
;*                 ch = green
;*                 cl = blue                                               
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = DX:AX = (square of) distance apart in RGB space 
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

cProc   calc_rgb_distance,<NEAR,PUBLIC>,<bx,di>
cBegin
        sub     al,cl                   ; blue difference
        jnc     positive_blue
        neg     al
positive_blue:
        mov     cl,ah                   ; save green before mult overwrites ah
        ; maximum difference is FF - 0 = FF, hence just in al
        ; maximum square is FF * FF = FE01, it fits in ax
        mul     al                      ; square the difference
        mov     di,ax                   ; save the difference so far
        xor     bx,bx                   ; zero high word of difference

        mov     al,cl                   ; saved green value
        sub     al,ch                   ; green difference
        jnc     positive_green
        neg     al
positive_green:
        ; maximum difference is FF - 0 = FF, hence just in al
        ; maximum square is FF * FF = FE01, it fits in ax
        mul     al                      ; square the difference
        add     di,ax                   ; add to the total
        adc     bl,bh                   ; add in carry to high word
                                        ; (bx is currently zero)

        mov     al,dl
        sub     al,dh                   ; red difference
        jnc     positive_red
        neg     al                      ; ensure diff is positive
positive_red:
        ; maximum difference is FF - 0 = FF, hence just in al
        ; maximum square is FF * FF = FE01, it fits in ax
        mul     al                      ; square the difference

        ; move the rgb distance into dx:ax
        add     ax,di                   ; add the accumulated differences
        adc     bl,bh                   ; include any carry to the high word
                                        ; (bh is still zero)
        mov     dx,bx                   ; move high word to dx

cEnd

;/***************************************************************************
;*
;* FUNCTION NAME = rgb_to_nearest_index
;*
;* DESCRIPTION   = Converts an RGB to the nearest valid color index.  Scans color  
;*                 tables to find the index with the smallest error.
;*                 Warnings:
;*                       Assumes DDC is in not in RGB mode.
;*
;*                 Registers Destroyed:                                                         
;*                       AX,BX,CX,DX,ES,SI,DI 
;*                                                                         
;* INPUT         = DS:BX = DDC 
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = DX:AX = color index 
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        assumes ds,Data
        assumes es,nothing

cProc   rgb_to_nearest_index,<PUBLIC,NEAR,NODATA,NONWIN>,<DS>
        parmD   RGBWanted
        localD  bestError
        localW  bestIndex
cBegin

        mov     bestError.hi,0FFFFh              ; start with a big error
        mov     bestIndex,0                       ; just in case!

ifdef   FIREWALLS
        test    [bx].ddc_fbClrTbl,DDC_RGB_MODE
        assert  Z
@@:
endif   ;FIREWALLS

;/*
;** Adjust system colors if necessary
;*/
        ddc?    bx
        mov     ax,[bx].ddc_iSysClr
        cmp     ax,ddcInit.ddc_iSysClr
        je      @F
        mov     si,bx
        call    far ptr far_PropagateSysClrChange
@@:

;/*
;** locate the logical color table
;*/
        lds     si,[bx].ddc_pClrTbl              ; DS:SI = color table
        assumes es,nothing

;/*
;** Grab some color table info
;*/

        mov     di,[si].ct_iMax                  ; DI = max valid entry
        mov     bx,[si].ct_iMin                  ; BX = min (start) entry
        assert  bx,E,0
        mov     si,[si].ct_npargb                ; DS:SI => RGB array
        cld

        public  rni_scan_loop
rni_scan_loop:

;/*
;** Load new quess
;*/
        lodsw                                     ; AX = green and blue
        mov     dx,ax                             ; save green and blue
        lodsw                                     ; AL = current guess's red
        cmp     ax,-1                             ; this RGB may not be valid
        je      rni_end_loop                      ;   just skip if not
        xchg    dx,ax                             ; DL,AH,AL = R,G,B

        mov     dh,byte ptr RGBWanted.hi ; DH = red we want
        mov     cx,RGBWanted.lo                  ; CX = green and blue

        call    calc_rgb_distance                ; compares RGBs DL,AH,AL -- DH,CH,CL

        cmp     dx,bestError.hi
        jb      rni_its_better
        ja      rni_end_loop

        cmp     ax,bestError.lo
        jae     rni_end_loop

        public  rni_its_better
rni_its_better:
        mov     bestError.hi,dx
        mov     bestError.lo,ax
        mov     bestIndex,bx

rni_end_loop:
        inc     bx
        cmp     bx,di
        jbe     rni_scan_loop

;/*
;**get the index:
;*/
        mov     ax,bestIndex
        cwd                             ; DX:AX = index
cEnd


;/***************************************************************************
;*
;* FUNCTION NAME = ipc_to_index
;*
;* DESCRIPTION   = Converts an IPC to a valid color index.  Scans color tables  
;*                 to find the index if needed.
;*
;*                       Assumes DDC is in not in RGB mode.
;*
;*                 Registers Destroyed:                                                         
;*                       CX
;*                                                                         
;* INPUT         = DS:BX = DDC 
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = DS:BX = DDC 
                   AX    = IPC 
;* RETURN-ERROR  = DX:AX = CLR_NOINDEX  if no index exists 
;*
;**************************************************************************/

        assumes ds,Data
        assumes es,nothing

cProc   far_ipc_to_index,<PUBLIC,FAR,NODATA,NONWIN>
cBegin
        call    ipc_to_index
cEnd

cProc   ipc_to_index,<PUBLIC,NEAR,NODATA,NONWIN>,<si,di,es>
cBegin

;/*
;** If RGB mode, just look up the RGB in the argbHW array.
;*/

        test    [bx].ddc_fbClrTbl,DDC_RGB_MODE
        jz      not_rgb_mode
        and     ax,ipc_index_mask                ; mask off accel. bits
        add     ax,ax                             ; AX = 2 * ipc
        add     ax,ax                             ; AX = 4 * ipc
        mov     di,ax
        mov     ax,word ptr argbHW[di].lo
        mov     dl,byte ptr argbHW[di].hi
        xor     dh,dh
        .errnz  rgb2_fcOptions-3
        jmp     return_this_index
not_rgb_mode:

;/*
;** See if there's a custom palette.  The default palettes are handled by
;** scanning the default log color tables.
;*/

        test    [bx].ddc_fbBelow,DDC_PALETTE
        jz      not_palette_mode

;/*
;** Initialize registers used by both bitmap and device paths.
;*/

        and     ax,ipc_index_mask                ; mask off accel. bits
        mov     si,[bx].ddc_npdevpal
        les     si,[si].devpal_pPalSeg           ;ES:SI --> palseg
        assumes es,nothing

;/*
;** If the ddc is a bitmap, then just validate the index and return it.
;*/

        test    [bx].ddc_fb,DDC_DEVICE
        jnz     iti_device_and_palette

        xor     dx,dx                             ;high word of return code, assume ok
        cmp     ax,es:[si].palseg_usMax
        njbe    return_this_index
        njmp    no_match_at_all

;/*
;** There's a palette selected into a device DDC.  Assume the palette has been
;** realized and look through the bCur values in order for an exact match.
;*/

iti_device_and_palette:
        mov     di,si
        palSize cx,es,di
        add     di,palseg_apalclr
iti_device_and_palette_loop:
        cmp     al,es:[di].palclr_bCur
        je      iti_got_a_pal_match
        add     di,SIZE PALCLR
        loop    iti_device_and_palette_loop
        njmp    no_match_at_all

;/*
;** Found an exact match.  Extract the index from the palclr address and return.
;*/

iti_got_a_pal_match:
        sub     di,si
        sub     di,palseg_apalclr
        palInd  di
        xchg    ax,di
        xor     ah,ah
        cwd
        njmp    return_this_index

;/*
;** locate the logical color table
;*/

not_palette_mode:
        mov     si,[bx].ddc_pClrTbl.off
        mov     dx,[bx].ddc_pClrTbl.sel
        test    byte ptr [bx].ddc_fbClrTbl,DDC_LOG_CLR_TBL
        jz      dont_validate
        push    ax
        mov     ax,[bx].ddc_iSysClr
        cmp     ax,ddcInit.ddc_iSysClr
        je      @F
        xchg    bx,si
        call    far ptr far_PropagateSysClrChange
        xchg    bx,si
@@:
        pop     ax
dont_validate:
        mov     es,dx
        assumes es,nothing                        ; ES:SI = color table

;/*
;** locate the IPC in the table
;*/

        mov     cx,es:[si].ct_iMax
        inc     cx                                ; CX = size of table
        lea     di,[si].ct_aipc                  ; ES:DI => IPC array
        cld

;/*
;**PROBLEM: -- the MONO_BITs are not set correctly in the default
;**            color table, so the "repnz scasw" will not find the
;**            color it should.  As a temporary fix, just look at
;**            the hardware palette index.
;*/

        dec     di                                ; predecrement for first scasb
@@:     inc     di                                ; increment to low byte of next word
        scasb
        loopnz  @B
        jnz     found_no_match
        inc     di                                ; expects DI to point 2 bytes beyond
        jmp     short found_a_match
found_no_match:

;/*
;** check for MONO bit match, if monochrome
;*/

        mov     di,[bx].ddc_npsd                 ; DS:DI = surface definition
        test    [di].sd_fb,SD_COLOR
        jnz     no_match_at_all

;/*
;** look for an ON bit
;*/

        mov     cx,es:[si].ct_iMax
        inc     cx                                ; CX = size of table
        lea     di,[si].ct_aipc                  ; ES:DI => IPC array
        mov     dx,di
        test    ax,MONO_BIT
        jz      look_for_OFF_loop
look_for_ON_loop:
        add     dx,2
        test    word ptr es:[di],MONO_BIT
        mov     di,dx
        loopz   look_for_ON_loop
        jnz     found_a_match
no_match_at_all:
        mov     ax,CLR_NOINDEX
        cwd
        jmp     short return_this_index

;/*
;** look for an OFF bit
;*/

look_for_OFF_loop:
        add     dx,2
        test    word ptr es:[di],MONO_BIT
        mov     di,dx
        loopnz  look_for_OFF_loop
        jnz     no_match_at_all

;/*
;** calculate the index
;*/

found_a_match:
        sub     di,si
        sub     di,ct_aipc + 2
        mov     ax,di                             ; DI = 2 * index
        shr     ax,1
        cwd                                       ; DX:AX = index
return_this_index:
cEnd

;/***************************************************************************
;*
;* FUNCTION NAME = QueryRGBColor 
;*
;* DESCRIPTION   = This function is invoked from the GRE dispatch table in  
;*                 response to a call to the GreQueryRGBColor function and  
;*                 returns the actual RGB color which will result from the  
;*                 specified color index for the specified device.          
;*                                                                          
;*                 Registers Destroyed:                                                         
;*                       AX,BX,CX,DX,ES
;*                                                                          
;* INPUT         = hdc,
;*                 Options,
;*                 hddc,
;*                 Index,
;*                 FunN  
;*                                                                                                                
;*         where:  Options:                                                                                       
;*                   bit 0 = 0:  Return the RGB assuming the color table is not realized    
;*                   bit 0 = 1:  Return the RGB assuming the color table is realized        
;*                   bit 1 = 0:  Return the displayable RGB color                           
;*                   bit 1 = 1:  Return the requested RGB color from the color table
;*                                                                                          
;*                 Index:  Specifies a color index                                          
;*                                                                     
;* OUTPUT        = As specified for the GreQueryRGBColor function. 
;*
;* RETURN-NORMAL = DX:AX = corresponding RGB color 
;* RETURN-ERROR  = AX =  -1 (ERROR_BAD_INDEX)      
;*
;**************************************************************************/

LCOLOPT_REQUESTED       equ                      2 

        check   QueryRGBColor,<hdc,flCmd,clr,hddc,ulFunN>

        assumes ds,nothing
        assumes es,nothing

cProc   QueryRGBColor,<PUBLIC,FAR,NODATA>,<si,di>
        parmD   hdc
        parmD   Options
        parmD   Index
        parmD   hddc
        parmD   FunN
cBegin

;/*
;**!!! must recognize color/mono for nearest color
;*/

        mov     ds,CodeData
        assumes ds,Data
        mov     si,hddc.lo                        ; SI = ddc
        mov     dx,si
        call    enter_driver
        mov     ax,-1                             ; assume error
        cwd
        njc     qrgb_exit_no_lock

;/*
;** validate the arguments
;*/

        cmp     Options.hi,0
        jnz     qrgb_inv_options
        test    Options.lo,not LCOLOPT_REALIZED+LCOLOPT_REQUESTED
        jz      qrgb_valid
qrgb_inv_options:
        mov     ax,PMERR_INV_COLOR_OPTIONS
qrgb_error:
        save_error_code
qrgb_return_error:
        mov     ax,-1
        cwd
        jmp     QueryRGBColor_exit
qrgb_valid:


        mov     dx,Index.hi                       ; DX:AX = Index
        mov     ax,Index.lo

;/*
;** See if there's a palette.
;*/

        test    [si].ddc_fbBelow,DDC_PALETTE
        jz      qrgb_no_palette
        test    Options.lo,LCOLOPT_REALIZED
        jnz     qrgb_inv_options

;/*
;** If the palette is not selected into a device ddc, and the color is
;** not marked as PC_EXPLICIT, then always return the requested rgb.
;*/

        mov     bx,[si].ddc_npdevpal
        les     bx,[bx].devpal_pPalSeg
        assumes es,nothing

        mov     cx,es:[bx].palseg_usMax

;/*
;** Check that the index is in range to avoid GP faulting.
;*/

        or      dx,dx
        njnz    invalid_color_index
        cmp     ax,cx
        nja     invalid_color_index

;/*
;** The index is in range.
;*/

        palOff  ax
        add     bx,ax

;/*
;** If the color is marked as PC_EXPLICIT, then return the displayable RGB
;** regardless of other options.
;*/

        test    es:[bx].palseg_apalclr.palclr_rgb.rgb2_fcOptions,PC_EXPLICIT
        jnz     qrgb_get_explicit_index

        test    [si].ddc_fb,DDC_DEVICE
        jz      qrgb_return_requested

;/*
;** It's a device ddc.  To return the displayable color, map through
;** palclr_bCur to a hardware index and back to an rgb through hwpal.
;*/

        test    Options.lo,LCOLOPT_REQUESTED
        jnz     qrgb_return_requested

        mov     al,es:[bx].palseg_apalclr.palclr_bCur
qrgb_return_displayable:
        xor     ah,ah
        rgbOff  ax
        les     bx,phwpal
        assumes es,nothing
        add     bx,ax
        mov     ax,word ptr es:[bx].rgb2_bBlue
        mov     dl,         es:[bx].rgb2_bRed
        xor     dh,dh

        jmp     QueryRGBColor_exit

qrgb_get_explicit_index:
        mov     al,es:[bx].palseg_apalclr.palclr_rgb.rgb2_bBlue
        jmp     short qrgb_return_displayable

qrgb_return_requested:
        mov     ax,word ptr es:[bx].palseg_apalclr.palclr_rgb.rgb2_bBlue
        mov     dl,         es:[bx].palseg_apalclr.palclr_rgb.rgb2_bRed
        xor     dh,dh

        jmp     QueryRGBColor_exit

;/*
;** handle the DISPLAYABLE RGB case
;*/

qrgb_no_palette:
        test    Options.lo,LCOLOPT_REQUESTED
        jnz     get_requested_color

;/*
;** translate the index
;*/

        xor     cx,cx                             ; no defaults
        call    ColorConvert                      ; get AX = IPC
        njs     qrgb_return_error

;/*
;** convert the IPC into an RGB
;*/

        and     ax,ipc_index_mask
        shl     ax,2
        mov     bx,ax
        mov     ax,word ptr argbHW[bx].lo
        mov     dl,byte ptr argbHW[bx].hi
        xor     dh,dh
        jmp     short QueryRGBColor_exit

;/*
;** handle the REQUESTED RGB case
;*/

get_requested_color:
        cmp     dx,-1                             ;If negative, might be one of the
        jnz     not_special_color                ;  special colors
        sub     ax,MIN_SYSTEM_COLOR              ;Special color within range?
        jc      invalid_color_index

;/*
;** The color is a SPECIAL color.  Look it up in adrgbSpecial.  ;
;*/

        shl     ax,2
        xchg    ax,bx
        mov     ax,adrgbSpecial[bx].lo
        mov     dx,adrgbSpecial[bx].hi
check_requested_color:
        or      dh,dh
        jz      QueryRGBColor_exit
invalid_color_index:
        mov     ax,PMERR_INV_COLOR_INDEX
        jmp     qrgb_error

;/*
;** The color was not a special color.                 ;
;*/

not_special_color:
        test    [si].ddc_fbClrTbl,DDC_RGB_MODE
        jnz     check_requested_color            ; just return for RGB mode
        or      dx,dx
        jnz     invalid_color_index              ;DX <> 0, error
        push    ax
        call    far ptr far_PropagateSysClrChange
        pop     ax
        les     bx,[si].ddc_pClrTbl
        assumes es,nothing
        cmp     ax,es:[bx].ct_iMax
        ja      invalid_color_index
        shl     ax,2
        xchg    ax,si
        add     si,es:[bx].ct_npargb
        mov     ax,es:[si].lo
        mov     dx,es:[si].hi
        jmp     check_requested_color

QueryRGBColor_exit:
        call    leave_driver
qrgb_exit_no_lock:
cEnd

;/***************************************************************************
;*
;* FUNCTION NAME = save_lct 
;*
;* DESCRIPTION   = Increments the reference count for the user's color table.
;*
;*                 Registers Destroyed: 
;*                       AX,BX,ES       
;*
;* INPUT         = DS:SI = DDC 
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        assumes ds,Data
        assumes es,nothing

cProc   save_lct,<PUBLIC,NEAR>
cBegin
        ddc?    si

;/*
;** just return if there is no user color table
;*/

        test    [si].ddc_fbClrTbl,DDC_LOG_CLR_TBL
        jz      save_lct_done

;/*
;** locate the table
;*/

        les     bx,[si].ddc_pClrTbl
        assumes es,nothing

;/*
;** increment the reference count
;*/

        inc     es:[bx].ct_cSave
save_lct_done:
cEnd

;/***************************************************************************
;*
;* FUNCTION NAME = deselect_lct 
;*
;* DESCRIPTION   = Frees a reference to a logical color table.  Decrements 
;*                 the reference count and frees the memory if it hits     
;*                 zero.                                                   
;*
;* INPUT         = DS:SI = DDC                                                          
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

        assumes ds,Data
        assumes es,nothing

cProc   deselect_lct,<PUBLIC,NEAR,NODATA,NONWIN>
cBegin
        ddc?    si

;/*
;** just return if there is no user color table
;*/

        test    [si].ddc_fbClrTbl,DDC_LOG_CLR_TBL
        jz      deselect_lct_done

;/*
;** locate the table
;*/

        les     bx,[si].ddc_pClrTbl
        assumes es,nothing

;/*
;** decrement the reference count
;*/

        dec     es:[bx].ct_cSave
        jnz     dont_free_it
        mov     cx,es                             ;Global free wants selecotr in CX
        call    private_free
dont_free_it:

;/*
;** Mark the flags to indicate there is no user table, since
;** this might be part of a ResetDC.
;*/

        and     [si].ddc_fbClrTbl,not DDC_LOG_CLR_TBL
        mov     [si].ddc_pClrTbl.off,DataOFFSET ctDefault
        mov     [si].ddc_pClrTbl.sel,ds
deselect_lct_done:
cEnd

sEnd    Code

;/***************************************************************************
;*
;* FUNCTION NAME = PropagateSysClrChange 
;*
;* DESCRIPTION   = Prepare the system to act correctly the next time it     
;*                 needs to use a color after a system color has changed.   
;*                 This subroutine is called only after at least one system 
;*                 color has changed.  Since we can't know which color      
;*                 changed, we must act as though all of them have.  Two    
;*                 color table indices, 0 and 7, are by default set to      
;*                 certain system colors.  If either of these system colors 
;*                 change, and the default mapping is still in effect, then 
;*                 the corresponding IPC (internal physical color) must be  
;*                 updated from the default color table.  The default       
;*                 mapping is in effect unless the user explicitly defined  
;*                 the colors, indicated by the DDC_CLR_*_USERS bits being  
;*                 set.  Furthermore, any attribute bundle which has a      
;*                 system color selected into it must be updated.  We do    
;*                 this lazily by marking the IPC as invalid, so that it    
;*                 won't be re-realized until necessary.                    
;*                                                                          
;*                 Registers Preserved:                                                                   
;*                       BX,CX,DX,SI,DI,BP,DS,ES                                                          
;*                 Registers Destroyed:                                                                   
;*                       AX                                                                               
;*
;* INPUT         = DS:SI = DDC 
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

sBegin  FarCode
        assumes cs,FarCode

        assumes ds,Data
        assumes es,nothing

cProc   far_PropagateSysClrChange,<PUBLIC,FAR,NODATA,NONWIN>
cBegin
        cCall PropagateSysClrChange
cEnd
cProc   PropagateSysClrChange,<PUBLIC,NEAR,NODATA,NONWIN>,<di,es>
cBegin

        ddc?    si

;/*
;** Mark as invalid any attributes that use a system color.  Since it's
;** expensive to check them all, we'll just invalidate everything.
;**
;** !!! Output-time performance can be improved by only invalidating
;** !!! the attributes that use system colors.  This would require
;** !!! checking each foreground and background color from each
;** !!! attribute structure against the range of system colors, and
;** !!! against 0 and 7 if in user-index mode.
;*/

        or      [si].ddc_ca.ca_ba.ba_fb,BA_CLR_INVALID or BA_CLR_BACK_INV or BA_REREALIZE
        or      [si].ddc_pa.pa_ba.ba_fb,BA_CLR_INVALID or BA_CLR_BACK_INV or BA_REREALIZE
        or      [si].ddc_la.la_ba.ba_fb,BA_CLR_INVALID or BA_CLR_BACK_INV or BA_REREALIZE
        or      [si].ddc_ia.ia_ba.ba_fb,BA_CLR_INVALID or BA_CLR_BACK_INV or BA_REREALIZE
        or      [si].ddc_ma.ma_ba.ba_fb,BA_CLR_INVALID or BA_CLR_BACK_INV or BA_REREALIZE

        test    [si].ddc_fbClrTbl,DDC_LOG_CLR_TBL
        jz      pscc_exit
        mov     es,[si].ddc_pClrTbl.sel
        assumes es,nothing

;/*
;** Copy index zero over unless it has been defined by the app
;*/

        test    [si].ddc_fbClrTbl,DDC_USER_CLR_0
        jnz     pscc_checked_index_0
        mov     di,[si].ddc_pClrTbl.off
        mov     ax,word ptr ctDefault.ct_aipc[BACKGND_WORD]
        mov     es:[di].ct_aipc[BACKGND_WORD],ax
        mov     di,es:[di].ct_npargb
        mov     ax,adrgbDefault[BACKGND_DWORD].lo
        mov     es:[di][BACKGND_DWORD].lo,ax
        mov     ax,adrgbDefault[BACKGND_DWORD].hi
        mov     es:[di][BACKGND_DWORD].hi,ax
pscc_checked_index_0:

;/*
;** Copy index seven over unless it has been defined by the app
;*/

        test    [si].ddc_fbClrTbl,DDC_USER_CLR_7
        jnz     pscc_checked_index_7
        mov     di,[si].ddc_pClrTbl.off
        mov     ax,word ptr ctDefault.ct_aipc[FOREGND_WORD]
        mov     es:[di].ct_aipc[FOREGND_WORD],ax
        mov     di,es:[di].ct_npargb
        mov     ax,adrgbDefault[FOREGND_DWORD].lo
        mov     es:[di][FOREGND_DWORD].lo,ax
        mov     ax,adrgbDefault[FOREGND_DWORD].hi
        mov     es:[di][FOREGND_DWORD].hi,ax
pscc_checked_index_7:

pscc_exit:
        mov     ax,ddcInit.ddc_iSysClr           ;Show up-to-date by setting iSysClr
        mov     [si].ddc_iSysClr,ax              ;  to current system count
        or      [si].ddc_fbBelow,DDC_DIRTY_ATTRS
cEnd
sEnd    FarCode
        end
