# HG changeset patch # User Claus Gittinger # Date 1491938352 -7200 # Node ID 44e80d5c9293e62e986518316de227bf645446c5 # Parent 1d8a9208c16aa53aeeea593e3037c42099d96d20 #REFACTORING by cg class: DeviceGraphicsContext added: #displayDeviceFormNoAlpha:x:y: #displayDeviceFormWithAlpha:x:y: changed: #displayDeviceForm:x:y: diff -r 1d8a9208c16a -r 44e80d5c9293 DeviceGraphicsContext.st --- a/DeviceGraphicsContext.st Tue Apr 11 21:18:55 2017 +0200 +++ b/DeviceGraphicsContext.st Tue Apr 11 21:19:12 2017 +0200 @@ -1910,11 +1910,44 @@ !DeviceGraphicsContext methodsFor:'drawing in device coordinates'! -displayDeviceForm:aForm x:x y:y +displayDeviceForm:aFormOrImage x:x y:y "draw a form or image non opaque (i.e. only foreground color is drawn); If it's a 1-plane bitmap, 1-bits are drawn in the current paint-color, leaving pixels with 0-bits unchanged (i.e. only 1-bits are drawn from the form). + + If it's a deep form (i.e. a pixmap) the current paint + settings are ignored and the form is drawn as-is; + however, the mask is applied if present. + + The form should have been allocated on the same device, + otherwise it's converted here, which slows down the draw. + No transformation or scaling is done. + Care must be taken, that the paint color is correctly allocated + (by sending #on: to the color) before doing so. + Using functions other than #copy only makes sense if you are + certain, that the colors are real colors (actually, only for + noColor or allColor)." + + (aFormOrImage isImage and:[aFormOrImage photometric == #rgba]) ifTrue:[ + Error handle:[:ex | + Logger error:'error when drawinf alpha: %1' with:ex description. + ] do:[ + self displayDeviceFormWithAlpha:aFormOrImage x:x y:y. + ^ self. + ]. + ]. + self displayDeviceFormNoAlpha:aFormOrImage x:x y:y. + + "Modified: / 11-04-2017 / 18:29:56 / cg" +! + +displayDeviceFormNoAlpha:aForm x:x y:y + "draw a form or image non opaque (i.e. only foreground color is drawn); + If it's a 1-plane bitmap, 1-bits are drawn in the + current paint-color, leaving pixels with 0-bits unchanged + (i.e. only 1-bits are drawn from the form). + If it's a deep form (i.e. a pixmap) the current paint settings are ignored and the form is drawn as-is; however, the mask is applied if present. @@ -1996,8 +2029,7 @@ "/ stamp out using mask device - setForeground:0 background:allBits in:gcId; - setFunction:#and in:gcId; + setForeground:0 background:allBits function:#and in:gcId; copyPlaneFromPixmapId:maskId x:0 y:0 gc:deviceMaskGcId to:drawableId @@ -2037,9 +2069,7 @@ ] ifFalse:[ "/ must do it slow, using a temporary form .. - " - create temp-form; - " + "/ create temp-form; tmpForm := Form width:w height:h depth:device depth onDevice:device. tmpForm isNil ifTrue:[ 'DeviceGraphicsContext [warning]: cannot create temp form' errorPrintCR. @@ -2048,15 +2078,11 @@ tmpId := tmpForm drawableId. tmpGCId := tmpForm initGC. - " - fill tempform with image - " + "/ fill tempform with image depth == 1 ifTrue:[ (colorMap := deviceForm colorMap) notNil ifTrue:[ colorMap size < 2 ifTrue:[ - device - setForegroundColor:(colorMap at:1) - in:tmpGCId. + device setForegroundColor:(colorMap at:1) in:tmpGCId. ] ifFalse:[ device setForegroundColor:(colorMap at:2) @@ -2067,66 +2093,45 @@ device copyPlaneFromPixmapId:id x:0 y:0 gc:deviceFormGCId - to:tmpId - x:0 y:0 gc:tmpGCId + to:tmpId x:0 y:0 gc:tmpGCId width:w height:h. ] ifFalse:[ device copyFromPixmapId:id x:0 y:0 gc:deviceFormGCId - to:tmpId - x:0 y:0 gc:tmpGCId + to:tmpId x:0 y:0 gc:tmpGCId width:w height:h. ]. - " - stamp out mask in temp form - set unmasked pixels to allBits and masked pixels to 0 - " + "/ stamp out mask in temp form + "/ set unmasked pixels to allBits and masked pixels to 0 device - setForeground:allBits background:0 in:tmpGCId; - setFunction:#and in:tmpGCId; + setForeground:allBits background:0 function:#and in:tmpGCId; copyPlaneFromPixmapId:maskId x:0 y:0 gc:deviceMaskGcId - to:tmpId - x:0 y:0 gc:tmpGCId + to:tmpId x:0 y:0 gc:tmpGCId width:w height:h. -"/Debug = 1 ifTrue:[ -"/ Debug := 0. -"/ tmpForm asImage inspect. -"/ deviceForm inspect. -"/]. - - " - stamp out mask in destination - set unmasked pixels to 0 and masked pixels to allBits - " + + "/ stamp out mask in destination + "/ set unmasked pixels to 0 and masked pixels to allBits device - setForeground:0 background:allBits in:gcId; - setFunction:#and in:gcId; + setForeground:0 background:allBits function:#and in:gcId; copyPlaneFromPixmapId:maskId x:0 y:0 gc:deviceMaskGcId - to:drawableId - x:pX y:pY gc:gcId + to:drawableId x:pX y:pY gc:gcId width:w height:h. - " - or-in tempform-bits ... - " + "/ or-in tempform-bits ... device - setForeground:0 background:0 in:gcId; - setFunction:#or in:gcId; + setForeground:0 background:0 function:#or in:gcId; copyFromPixmapId:tmpId x:0 y:0 gc:tmpGCId - to:drawableId - x:pX y:pY gc:gcId + to:drawableId x:pX y:pY gc:gcId width:w height:h. - " - release tempForm immediately - (although GC will eventually do it, - this creates less stress to the Xserver in the meanwhile ...) - " + "/ release tempForm immediately + "/ (although GC will eventually do it, + "/ this creates less stress to the Xserver in the meanwhile ...) tmpForm destroy. ]. @@ -2142,7 +2147,6 @@ ] ] ]. - device copyFromPixmapId:id x:0 y:0 gc:deviceFormGCId @@ -2152,17 +2156,13 @@ ^ self ]. - " - the following code is somewhat complicated, since it has to deal - with dithered paint colors, which cannot be done directly on most - devices (actually, a test for the device's capabilities has to be added here) - (just assume drawing a bitmap with dithered paint color ... sigh) - " + "/ the following code is somewhat complicated, since it has to deal + "/ with dithered paint colors, which cannot be done directly on most + "/ devices (actually, a test for the device's capabilities has to be added here) + "/ (just assume drawing a bitmap with dithered paint color ... sigh) easy := (function == #copy). - " - if paint is not a real color, we have to do it the hard way ... - " + "/ if paint is not a real color, we have to do it the hard way ... easy ifTrue:[ paint isColor ifTrue:[ paintDither := paint ditherForm. @@ -2179,23 +2179,15 @@ allBits := allColor colorId. easy ifTrue:[ - " - paint is a real color - " - - " - if paint color is all-0 or all-1's, we can do it in one - operation ... - " + "/ paint is a real color + + "/ if paint color is all-0 or all-1's, we can do it in one operation ... fgId := paint colorId. ((fgId ~~ ((1 bitShift:device depth)-1)) and:[fgId ~~ allBits]) ifTrue:[ - " - clear fg-bits ... - " - device setForeground:0 background:allBits in:gcId. - device setFunction:#and in:gcId. + "/ clear fg-bits ... + device setForeground:0 background:allBits function:#and in:gcId. device copyPlaneFromPixmapId:id x:0 y:0 gc:deviceFormGCId @@ -2205,11 +2197,8 @@ ]. fgId ~~ 0 ifTrue:[ - " - or-in fg-bits ... - " - device setForeground:fgId background:0 in:gcId. - device setFunction:#or in:gcId. + "/ or-in fg-bits ... + device setForeground:fgId background:0 function:#or in:gcId. device copyPlaneFromPixmapId:id x:0 y:0 gc:deviceFormGCId @@ -2217,12 +2206,8 @@ x:pX y:pY gc:gcId width:w height:h ]. - " - flush foreground/background cache - " + "/ flush foreground/background cache device setForegroundColor:foreground backgroundColor:background in:gcId. - "/ foreground := nil. - "/ background := nil. device setFunction:function in:gcId. ^ self ]. @@ -2240,9 +2225,7 @@ fgId := paint colorId. fgId ~~ 0 ifTrue:[ - " - or-in fg-bits ... - " + "/ or-in fg-bits ... device setForeground:fgId background:0 in:gcId. device copyPlaneFromPixmapId:id @@ -2251,89 +2234,184 @@ x:pX y:pY gc:gcId width:w height:h ]. - " - flush foreground/background cache - " + "/ flush foreground/background cache foreground := nil. background := nil. ^ self ]. ]. - " - hard case; paint is a dithered color - " - + "/ hard case; paint is a dithered color noColor := Color noColor. - " - create temp-form; - " + "/ create temp-form; tmpForm := Form width:w height:h depth:device depth onDevice:device. tmpForm isNil ifTrue:[ 'DeviceGraphicsContext [warning]: cannot create temp form' errorPrintCR. ^self ]. - " - fill tempform - " - tmpForm paint:paint. - tmpForm fillRectangleX:0 y:0 width:w height:h. - " - stamp out background - " - tmpForm paint:allColor on:noColor. - tmpForm function:#and. + + "/ fill tempform + tmpForm paint:paint; fillRectangleX:0 y:0 width:w height:h. + + "/ stamp out background + tmpForm paint:allColor on:noColor; function:#and. tmpForm displayOpaqueForm:deviceForm x:0 y:0. - " - stamp out foreground from destination - " - device setForeground:0 background:allBits in:gcId. - device setFunction:#and in:gcId. + + "/ stamp out foreground from destination + device setForeground:0 background:allBits function:#and in:gcId. device copyPlaneFromPixmapId:id - x:0 - y:0 + x:0 y:0 gc:deviceFormGCId - to:drawableId - x:pX - y:pY - gc:gcId - width:w - height:h. - " - or-in temp into destination - " - device setForeground:allBits background:0 in:gcId. - device setFunction:#or in:gcId. + to:drawableId x:pX y:pY + gc:gcId width:w height:h. + + "/ or-in temp into destination + device setForeground:allBits background:0 function:#or in:gcId. device copyFromPixmapId:tmpForm drawableId - x:0 - y:0 + x:0 y:0 gc:tmpForm gcId - to:drawableId - x:pX - y:pY - gc:gcId - width:w - height:h. - - " - release tempForm immediately - (although GC will eventually do it, - this creates less stress to the Xserver in the meanwhile ...) - " + to:drawableId x:pX y:pY + gc:gcId width:w height:h. + + "/ release tempForm immediately + "/ (although GC will eventually do it, + "/ this creates less stress to the Xserver in the meanwhile ...) tmpForm destroy. - " - flush foreground/background cache - " + + "/ flush foreground/background cache foreground := nil. background := nil. device setFunction:function in:gcId. - "Modified: / 15-03-2017 / 12:45:36 / cg" + "Created: / 11-04-2017 / 16:45:18 / cg" +! + +displayDeviceFormWithAlpha:anImage x:x y:y + "draw a form or image non opaque (i.e. only foreground color is drawn); + If it's a 1-plane bitmap, 1-bits are drawn in the + current paint-color, leaving pixels with 0-bits unchanged + (i.e. only 1-bits are drawn from the form). + + If it's a deep form (i.e. a pixmap) the current paint + settings are ignored and the form is drawn as-is; + however, the mask is applied if present. + + The form should have been allocated on the same device, + otherwise it's converted here, which slows down the draw. + No transformation or scaling is done. + Care must be taken, that the paint color is correctly allocated + (by sending #on: to the color) before doing so. + Using functions other than #copy only makes sense if you are + certain, that the colors are real colors (actually, only for + noColor or allColor)." + + |bytesPerLine orgDstData dstData imgData info w h pX pY bppDrawable + dstBytesPerRow "{Class: SmallInteger}" + imgBytesPerRow "{Class: SmallInteger}" + dstIndex "{Class: SmallInteger}" + imgIndex "{Class: SmallInteger}" + dstRowIndex "{Class: SmallInteger}" + imgRowIndex "{Class: SmallInteger}"| + + device sync. + + w := anImage width. + h := anImage height. + (w = 0 or:[h = 0]) ifTrue:[^ self]. + + pX := x rounded. + pY := y rounded. + + "/ give it more than enough bytes + bytesPerLine := (w * 32 + 31) // 32 * 4. + dstData := ByteArray uninitializedNew:(bytesPerLine * h). + drawableType == #pixmap ifTrue:[ + info := device getBitsFromPixmapId:(self drawableId) x:pX y:pY width:w height:h into:dstData. + ] ifFalse:[ + info := device getBitsFromViewId:(self drawableId) x:pX y:pY width:w height:h into:dstData. + ]. + + dstBytesPerRow := info at:#bytesPerLine. + imgBytesPerRow := anImage bytesPerRow. + + imgData := anImage bits. + orgDstData := dstData copy. + + bppDrawable := info at:#bitsPerPixel. + bppDrawable == 32 ifTrue:[ + "/ data is coming as bytes in r,g,b,a order + dstRowIndex := 1. + imgRowIndex := 1. + + "/ draw "by hand" here + 0 to:h-1 do:[:y | + dstIndex := dstRowIndex. + imgIndex := imgRowIndex. + 0 to:w-1 do:[:x | + |rD "{Class: SmallInteger}" + gD "{Class: SmallInteger}" + bD "{Class: SmallInteger}" + rI "{Class: SmallInteger}" + gI "{Class: SmallInteger}" + bI "{Class: SmallInteger}" + aI "{Class: SmallInteger}" + aD "{Class: SmallInteger}" + nR "{Class: SmallInteger}" + nG "{Class: SmallInteger}" + nB "{Class: SmallInteger}"| + + rD := dstData at:(dstIndex+0). + gD := dstData at:(dstIndex+1). + bD := dstData at:(dstIndex+2). + + rI := imgData at:(imgIndex). + gI := imgData at:(imgIndex+1). + bI := imgData at:(imgIndex+2). + aI := imgData at:(imgIndex+3). + + aI == 255 ifTrue:[ + nR := rI. + nG := gI. + nB := bI. + ] ifFalse:[ + aI == 0 ifTrue:[ + nR := rD. + nG := gD. + nB := bD. + ] ifFalse:[ + aD := 255 - aI. + + nR := (((rI * aI)+(rD * aD)) // 255). + nG := (((gI * aI)+(gD * aD)) // 255). + nB := (((bI * aI)+(bD * aD)) // 255). + ]. + ]. + dstData at:(dstIndex+1) put:nR. + dstData at:(dstIndex+2) put:nG. + dstData at:(dstIndex+3) put:nB. + + dstIndex := dstIndex + 4. + imgIndex := imgIndex + 4. + ]. + dstRowIndex := dstRowIndex + dstBytesPerRow. + imgRowIndex := imgRowIndex + imgBytesPerRow. + ]. + "/ draw the pixels (always MSB) + device + drawBits:dstData msb:true bitsPerPixel:32 depth:24 padding:32 + width:w height:h x:0 y:0 + into:(self drawableId) x:pX y:pY width:w height:h with:gcId. + ^ self. + ]. + self halt. + + "Created: / 11-04-2017 / 16:45:39 / cg" + "Modified (format): / 11-04-2017 / 21:11:50 / cg" ! displayDeviceLineFromX:x0 y:y0 toX:x1 y:y1