;*DDK*************************************************************************/
;
; COPYRIGHT (C) Lexmark 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.;
;*****************************************************************************/
;*****************************************************************************
;*
;* SOURCE FILE NAME = BITMOUT.ASM
;*
;* DESCRIPTIVE NAME = Scan and output the bitmap.
;*
;*
;* VERSION      V2.0
;*
;* DATE
;*
;* DESCRIPTION
;*
;* FUNCTIONS   : prdp_ParseSegment
;*               prdp_Invert
;*               prdp_OutputRules
;*               search_down
;*
;*
;* NOTES       : Winthorn Functional Specification
;*               Device Driver Interface Specification
;*               Printer Device Driver Design Specification
;*
;*
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES
;*
;*              NONE
;*
;* EXTERNAL FUNCTIONS
;*
;*              NONE
;*
;* CHANGE ACTIVITY =
;*   DATE      FLAG          APAR     CHANGE DESCRIPTION
;*   --------  ----------    -----    --------------------------------------
;*   mm/dd/yy  @Vr.mpppxx    xxxxx    xxxxxxx
;*
;*
;*  06/25/91                 PD00149 : Substitute stack for OS2_PM_DRV_
;*                                     DEVMODE.  P. Springett
;*
;*  06/27/91                 PD00268 : Only substitue stack if it looks
;*                                     like it is really necessary. EXCEL
;*                                     testcase.  P. Springett
;*
;*  08/06/91                 PD00272 : Remove stack routines as they are
;*                                     not used anymore.  Sue Murch
;*
;*  09/19/91                 PD00469 : New function prdp_ParseSegment for
;*                                     white space elimination speed up.
;*                                     P. Springett
;*
;*  09/19/91                 PD00406 : New function prdp_DwordSet for
;*                                     BitBlt speed up.  P. Springett
;*
;*  10/11/91                 PD00481 : Created new .ASM module to hold
;*                                     common .ASM routines for all three
;*                                     drivers.  Removed these functions
;*                                     from BITMOUT.ASM to reduce driver
;*                                     size.  Randy O'Neal
;*
;*
;*
;*  10/15/92                 600DPI  : Added.  Sue Murch
;*
;*  12/15/92                 PD00775 : Save and restore additional used
;*                                     registers.  L. Cheatham
;*
;*  03/31/93                 CON3201 : prdp_ParseSegment and prdp_Invert
;*                                     are removed.  Kranthi Ravi
;*
;*
;******************************************************************************/


.386p
INCL_NOCOMMON    EQU   1
.xlist
INCLUDE 32cmacro.inc
?PLM = CC_SYSCALL
INCLUDE os2.inc
.list

wordpart      struc
   lo         dw         ?
   hi         dw         ?
wordpart      ends


        externP  prdp_PrintRule       ; Output filled rectangles

CODE32      SEGMENT Dword USE32 PUBLIC 'CODE'
            ASSUME CS:FLAT,SS:FLAT,DS:FLAT,ES:FLAT



;/***************************************************************************
;*
;* FUNCTION NAME = prdp_ParseSegment
;*
;* DESCRIPTION   = No longer necessary due to 32 bit flat model
;*
;* INPUT         = NONE
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL =
;*
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/
;; nobody uses this function any more
;;cProc   prdp_ParseSegment,<FAR,PUBLIC,NODATA,NONWIN>,<bx,ds,si>
;;        parmD   lpSegment

;/***************************************************************************
;*
;* FUNCTION NAME = prdp_Invert
;*
;* DESCRIPTION   = No longer necessary due to 32 bit flat model
;*
;* INPUT         = NONE
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL =
;*
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/
;; nobody uses this function any more
;;cProc   ,<FAR,PUBLIC,NODATA,NONWIN>,<ds,bx>
;;        parmD  ScanLinePtr



;/***************************************************************************
;*
;* FUNCTION NAME = prdp_OutputRules
;*
;* DESCRIPTION   = Scan and output the bitmap.  See design note.
;*
;* INPUT         = NONE
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL =
;*
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/
;--------------------------------------------------------------
;
; Design :
;       This bitmap is scanned for a non-zero byte - top
;       to bottom.
;
;       When a byte is found a search is made downwards (search_down) to
;       see how often the same byte is duplicated in a
;       vertical direction (RuleDepth)
;
;       A horizonal scan is then made to see many contiguous bits we
;       can find where the byte containing the bits is
;       also replicated vertically by at least RuleDepth rows.
;       (note that at this stage no check has been made that
;        the first byte contains contiguous bits from the first
;        bit to the end of the byte - this is tidied up later)
;       from this we get rulewidth
;
;       We check to see if we've found enough bytes to make a
;       rule worth it (very heuristic test).
;
;       If no suitable rule was found we continue scanning the
;       bitmap from the next byte and adjust the return code to
;       note we didn't process everything.
;
;       We then compute the real rule by checking right and
;       left masks and contiguity.
;
;       The rule data is then erased from the bitmap.  If the
;       rule is narrow we extend it down over non-identical bytes
;       which include the rule mask(s).  When erasing we do not
;       zero bytes which are not identical to the first byte in
;       a vertical scan.  This stops vertical lines introducing
;       gaps in subsequent horizontal scans.
;
;       The rule is then output and we continue at the CURRENT BYTE
;
;       Things to change/tidy up
;       - Improve the calculation about when a rule is worth it
;       - Do the contiguity check on the first byte before scanning
;         right - this way we avoid extra work and finding bogus rules
;       - When scanning across be more intelligent about the depth of
;         subsequent vertical scans rather than insisting they go as
;         far down as the current scan
;
;--------------------------------------------------------------
;--------------------------------------------------------------
;            : Save bx, cx registers
;            : No need to save ds,cx registers anymore
;--------------------------------------------------------------

cProc   prdp_OutputRules,<PUBLIC,NODATA,NONWIN>,<esi,edi,ebx>
        parmD  ScanLinePtr         ; 'current' scanline
        parmD  ScanLen
        parmD  DCInstance
        parmD  MemoryPtr
        parmD  pMemoryIndex
        parmW  MemorySize
        parmD  PDBInst
        parmW  Resolution
        parmW  ResAdjFactor
        parmD  pSPPData
        parmD  pRIGData
      ;;parmW  HugeInc               ;;           no use
        parmW  BitHeight             ; Y - Distance to bottom of bitmap
        parmW  MarginPels
        parmW  BandOffset
        parmW  MinRuleVert
        parmW  MinRuleHorz
        parmW  MinRuleArea
        localD CurrentPtr
      ;;localW RuleDepth
      ;;localW RuleWidth
      ;;localW depth
      ;;localW ScanEnd
        localD RuleDepth        ;;
        localD RuleWidth        ;;
        localD depth            ;;       changed to dwords for convenience
        localD ScanEnd          ;;
        localW bFound
        localW masks
        localD LocScanLnPtr      ;;local scanline ptr
cBegin
      ;;mov    ax,BitHeight
      ;;mov    depth,ax
        movzx  eax,BitHeight     ;;check this out . with whoom !!!!!!!!!!
        mov    depth,eax
        mov    bFound,1           ; Gets set to 2 we can't do everything here

;-------------------------------------------------------------------------
;
; Scan the huge bitmap looking for non-null bytes
;
; ES:DI points to the current byte in the bitmap
; DX shadows ES for huge incrementing
;
;-------------------------------------------------------------------------
      ;;les    di,ScanLinePtr
        mov    edi,ScanLinePtr
        mov    LocScanLnPtr,edi     ;;a copy of original ptr
      ;;mov    dx,es
;-------------------------------------------------------------------------
; Search repeatedly along a line for interesting bytes (ie not 0)
;
;-------------------------------------------------------------------------
        cmp    depth,0
        jnz    @F
good_return:
        mov    ax,bFound
        jmp    finished
next_scanline:
@@:
      ;;mov    ax,ScanLen
      ;;add    ax,off_ScanLinePtr
      ;;mov    ScanEnd,ax
        mov    eax,ScanLinePtr
        add    eax,ScanLen
        sub    eax,LocScanLnPtr        ;;??????????????????????
        mov    ScanEnd,eax
repeat_scanning:
      ;;mov    ax,ScanEnd
      ;;sub    ax,di                         ; finished ?
      ;;mov    eax,edi                       ;;get the pointer ScanLinePtr
        mov    eax,LocScanLnPtr
        add    eax,ScanEnd                   ;;add scanend to get endptr
        sub    eax,edi                       ;;at this point we have ScanEnd
                                             ;;in eax (it is a count also)
        jz     finished_scanning_line
      ;;mov    cx,ax
        mov    ecx,eax
      ;;add    ax,di
      ;;jnc    @F                                ; Split over segment ?
      ;;mov    bx,ax
      ;;mov    cx,di
      ;;neg    cx                                ; Just go to the end
      ;;xor    al,al
      ;;repe   scasb                             ; scan for != al (ie not 0)
      ;;jne    found_non_zero
      ;;mov    cx,bx
      ;;add    dx,HugeInc                        ; Do our increment
      ;;mov    es,dx
;;@@
        xor    al,al
        repe   scasb                             ; Search for non-null
        jne    found_non_zero                    ; Found something

; Move on to the next line

finished_scanning_line:
        dec    Depth
        jz     good_return
      ;;les    di,ScanLinePtr
        mov    edi,ScanLinePtr
      ;;sub    di,ScanLen
      ;;jae    @F
      ;;sub    dx,HugeInc
      ;;mov    es,dx
      ;;mov    seg_ScanLinePtr,dx
        sub    edi,ScanLen
;;@@:
      ;;mov    off_ScanLinePtr,di
        mov    ScanLinePtr,edi
        mov    LocScanLnPtr,edi    ;;;check this out
        jmp    next_scanline

;-------------------------------------------------------------------------
; We've found a non-zero byte.  First see if this is a candidate for
; Rules - we need certain area before we're prepared to use a rule
;
; ax = Current width of area
; cx = Current Height of area
; ds:bx = Current bottom of area
;           
;
;-------------------------------------------------------------------------
found_non_zero:
      ;;dec    di
      ;;mov    seg_CurrentPtr,dx
      ;;mov    off_CurrentPtr,di
        dec    edi
        mov    CurrentPtr,edi

; Go down first - find how many identical bytes there are

      ;;mov    cx,depth
      ;;mov    al,byte ptr es:[di]     ; byte to compare
      ;;mov    ah,0ffh                 ; mask
        mov    ecx,depth
        mov    al,byte ptr [edi]
        mov    ah,0ffh
        cCall  search_down
        mov    RuleDepth,ecx
        mov    RuleWidth,1

; Look for horizontal prospects

        test   ax,1           ; Rule extends into next byte ?
        jz     end_rule

;--------------------------------------------------------
; Loop trying to expand the rule horizontally
;
; al = our current byte       ;;still holds good
;
; es:di -> current byte       ;;now ! this is edi
;--------------------------------------------------------
      ;;mov   cx,ScanEnd
      ;;sub   cx,di              ; cx = number to end of line
        mov   ecx,LocScanLnPtr
        add   ecx,ScanEnd
        sub   ecx,edi            ;; ecx = number to end of line
                                 ;; anybody is sure about this ??????
scan_rule_horiz:

        dec   ecx                 ; step on to next byte
        jz    end_rule

      ;;inc   di
      ;;jnz   @F
      ;;add   dx,HugeInc
      ;;mov   es,dx
;;@@:                   ;;
        inc   edi

        test  byte ptr [edi],80h ; Test if scan continues into next byte
        jz    end_rule
        mov   al,byte ptr [edi]
        push  ecx
        mov   ecx,RuleDepth
        mov   ah,0ffh
        cCall search_down
        cmp   ecx,RuleDepth
        pop   ecx
        jb    end_rule
        inc   RuleWidth
        cmp   al,0ffh            ; byte was 0ffh ?
        je    scan_rule_horiz

end_rule:
     ;; mov   cx, MinRuleVert    ;            Variable MinRule value dependant
     ;; cmp   RuleDepth,cx       ; on resolution and now passed into this
     ;; jae   test_area          ; routine
     ;; mov   cx, MinRuleHorz
     ;; cmp   RuleWidth,cx
     ;; jb    no_rule
        movzx ecx,MinRuleVert
        cmp   RuleDepth,ecx
        jae   test_area
        movzx ecx,MinRuleHorz
        cmp   RuleWidth,ecx
        jb    no_rule
test_area:
        push  eax
        push  edx
        mov   eax,RuleDepth
        mul   RuleWidth
        mov   ebx,eax
        pop   edx
        pop   eax
        jo    do_rule
        cmp   bx, MinRuleArea    ;            Variable MinRuleArea value
        ja    do_rule

        public no_rule
no_rule:

;-----------------------------------------------------------
; If we get here we've failed to do everything with rules
; so set the return code accordingly
;-----------------------------------------------------------
        mov   bFound,2

; Here we must move on to the next byte to avoid loops

      ;;cmp   dx,seg_CurrentPtr    ;;
      ;;jz    @F                   ;;
      ;;les   di,CurrentPtr        ;;
      ;;mov   dx,es                ;;
;;@@:                              ;;
      ;;mov   di,off_CurrentPtr    ;;

        mov   edi,CurrentPtr

        push  eax                  ;;
        mov   eax,LocScanLnPtr     ;;     this section of code is needed to
        add   eax,ScanEnd          ;;     make the ScanEnd a pointer briefly

        inc   edi
      ;;cmp   di,ScanEnd              ; Don't step over end
        cmp   edi,eax              ;; Don't worry. eax now has ScanEnd
        pop   eax
        jnz   @F
        jmp   finished_scanning_line
@@:
      ;;or    di,di
      ;;jnz   @F                  ;; don't need this, as well
      ;;add   dx,HugeInc
      ;;mov   es,dx
;;@@:
        jmp   repeat_scanning

;------------------------------------------------------------------
; Can't do a rule - continue with normal algorithms
;
;------------------------------------------------------------------

;------------------------------------------------------------------
; Work out what our rule command should be - there may be
; several hidden here.  Search for the maximum we
; can do for single-byte rules
;
; Also we must zero all the bytes we output so subsequent code
; won't find them.
;
; al contains the last byte scanned
;
;------------------------------------------------------------------
do_rule:
do_until_0:
      ;;les   di,CurrentPtr
     ;; mov   dx,es
        mov   edi,CurrentPtr
        mov   bh,al  ; save last byte
; Repeat until we've cleared out this byte

        mov   al,byte ptr [edi]
@@:
; Find our mask - at the end :
;  bl = mask
;  cl = first bit
;  ch = last bit
        mov   ah,01h
        xor   cx,cx
        dec   cx
        xor   bl,bl

; Loop to set 'first bit'

@@:
        ror   ah,1
        inc   cx
        test  al,ah
        jz    @B
        mov   ch,cl
        dec   ch

; Loop to set 'first mask' and (possibly) 'last bit'

@@:
        or    bl,ah
        inc   ch
        shr   ah,1
        test  al,ah
        jnz   @B
        mov   ah,bl            ; For just 1 byte this is 'last' mask
;
; Check that the first byte ran to the end
;
        cmp   RuleWidth,1
        jz    got_right_mask
        cmp   ch,7
        jz    get_right_mask
        mov   RuleWidth,1
        mov   bh,al
        jmp   got_right_mask
;
; Get right mask in ah
;
get_right_mask:
        xor   ah,ah
@@:
        shl   bh,1
        jnc   got_right_mask
        rcr   ah,1
        inc   ch
        jnz   @B

got_right_mask:
;---------------------------------------------------
; For narrow bands see if we can go a bit deeper
;---------------------------------------------------
        cmp   RuleWidth,2
        ja    not_narrow
        push  ax
        push  cx

        xchg  ah,bl
        push  bx
      ;;les   di,CurrentPtr
        mov   edi,CurrentPtr
        mov   al,ah            ; Scan under mask
        mov   ecx,depth
        cCall search_down
        pop   bx
        xchg  ah,bl
        push  bx
        cmp   RuleWidth,1
        je    one_wide

        inc   edi
      ;;jnz   @F
     ;; mov   dx,es
      ;;add   dx,HugeInc
      ;;mov   es,dx
;;@@:
        mov   al,ah
        cCall search_down      ; Won't go beyond cx
one_wide:
        mov   RuleDepth,ecx
        pop   bx

        pop   cx
        pop   ax
not_narrow:
;---------------------------------------------------------------
; Compute total extent of bitmap and clear it out with our
; masks
;
; Currently :  ah = right mask
;              bl = left mask
;              cl = left bit pos
;              ch = right bit pos (may be > 7 if right mask as well)
;              es(dx):di -> first byte
; Compute :
;
;
;---------------------------------------------------------------
        not   ah
        not   bl
        mov   al,bl
        mov   esi,RuleWidth
        xor   ebx,ebx           ; bx steps through the rows
        mov   masks,ax
        push  cx
clear_loop:
      ;;les   di,CurrentPtr
        mov   edi,CurrentPtr
      ;;mov   dx,es
        add   edi,ebx
      ;;add   di,bx
      ;;jnc   @F
      ;;add   dx,HugeInc
      ;;mov   es,dx
;;@@:
        cmp   esi,1
        jne   @F
        mov   ax,masks            ; Last line
        mov   al,ah
@@:
        mov   ah,byte ptr [edi] ; To test if there are other
        not   ah                  ; bits not in the 'rule'
        mov   ecx,RuleDepth

clear_vertical:
        and   byte ptr [edi],al
        jz    cleared_it      ; Don't valdalize pontential horiz rules
        test  byte ptr [edi],ah
        jz    @F
        not   al
        or    byte ptr [edi],al
        not   al
@@:
cleared_it:
        dec   ecx
        jz    next_vertical   ; Don't step es if last line
        sub   edi,ScanLen
      ;;jae   @F
      ;;sub   dx,HugeInc
      ;;mov   es,dx
;;@@:
        jmp   clear_vertical
next_vertical:
        mov   al,0
        inc   ebx
        dec   esi
        jnz   clear_loop
        pop   cx
;--------------------------------------------------------------
; Now call our code to output the printer command
;
;--------------------------------------------------------------
        xor   ax,ax
        xchg  al,ch          ; cx = left bit pos
        mov   esi,RuleWidth
        sub   esi,2
        jle   @F
        shl   esi,3
        add   eax,esi          ; ax = right bit pos
@@:
      ;;mov   si,off_CurrentPtr
      ;;sub   si,off_ScanLinePtr
      ;;shl   si,3
        mov   esi,CurrentPtr
        sub   esi,ScanLinePtr
        shl   esi,3

        add   eax,esi          ; Bit position of right
        inc   eax             ; Make it a size
        add   ecx,esi          ; Bit position of left
        movzx ebx,BitHeight    ;; do we ever get a -ve bitheight ? weird quest.
        sub   ebx,depth
        Arg   RuleDepth
        movzx ecx,cx
        movzx eax,ax
        Arg   ecx
        Arg   eax
        Arg   MemoryPtr
        Arg   pMemoryIndex
        Arg   MemorySize
        Arg   MarginPels
        Arg   DCInstance
        Arg   pSPPData
        Arg   ResAdjFactor
        Arg   BandOffset
        Arg   PDBInst
        Arg   ebx
        cCall prdp_PrintRule
        or    ax,ax
        jz    finished
      ;;les   di,CurrentPtr
        mov   edi,CurrentPtr
      ;;mov   dx,es
        jmp   repeat_scanning
finished:
cEnd

;/***************************************************************************
;*
;* FUNCTION NAME =
;*
;* DESCRIPTION   = Search down the bitmap to for bytes equal to al for a
;*                 maxmimum distance and return the result.  The compare is
;*                 under max ah.  See design note that follows.
;*
;* INPUT         = ah = mask
;*                 al = byte to compare
;*                 edi -> current position
;*                 ecx = max depth to go
;*
;* OUTPUT        = cx = number of rows which compared
;*
;* RETURN-NORMAL =
;*
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/
;------------------------------------------------------------------
;
; Design:
;
; inputs :
;          ah = mask
;          al = byte to compare
;          edi -> current position
;          ecx = max depth to go
;
; outputs :
;           cx = number of rows which compared
;
; registers destroyed
;           si,bx
;
; Note this routine must not use any local variables as it
; uses the stack frame of the main routine
;------------------------------------------------------------------
;--------------------------------------------------------------
;            : The above note still holds good
;              ecx = number of rows which compared.
;              registers destroyed none
;            : Save bx, di, si and es registers
;            : no need to save es
;--------------------------------------------------------------
cProc  search_down,<PUBLIC,NONWIN>,<edi,esi,ebx>
cBegin
        mov    esi,ecx
        jmp    scan_loop
scanning:
        sub    edi,ScanLen
        mov    bl,ah
        and    bl,byte ptr [edi]
        cmp    al,bl
        jne    finished_down
scan_loop:
        loop   scanning

finished_down:

; Set cx = depth of run

        sub    esi,ecx
        mov    ecx,esi

cEnd

CODE32  ENDS
        end
