#REFACTORING by cg
authorClaus Gittinger <cg@exept.de>
Tue, 11 Apr 2017 21:19:12 +0200
changeset 8005 44e80d5c9293
parent 8004 1d8a9208c16a
child 8006 55f3c1132660
#REFACTORING by cg class: DeviceGraphicsContext added: #displayDeviceFormNoAlpha:x:y: #displayDeviceFormWithAlpha:x:y: changed: #displayDeviceForm:x:y:
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