extensions.st
author Jan Vrany <jan.vrany@fit.cvut.cz>
Tue, 05 Apr 2016 10:00:57 +0100
changeset 77 cdf856e78998
parent 72 3eabcca278cd
child 81 094b29cf4c2c
permissions -rw-r--r--
CairoGraphicsContext: Fixed paint setting Even though methods like #foreground: / #foreground:background: method are marked obsolete for quite some time, a lot of core widgets are still using them (!). Therefore CairoGraphicsContext must implement them to correctly update Cairo context. This fixes issues with EditField.

"{ Package: 'stx:goodies/libcairo' }"!

!Depth1Image methodsFor:'accessing'!

bitsA1
    | bitsA1 |

    bitsA1 := ByteArray new: ((width + 31) // 32) * 4 * height.
    self bitsA1Into: bitsA1.
    ^ bitsA1

    "Created: / 07-03-2016 / 17:57:29 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!Depth1Image methodsFor:'accessing'!

bitsA1Into: buffer
    self bitsA1Into: buffer startingAt: 1

    "Created: / 07-03-2016 / 17:57:59 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!Depth1Image methodsFor:'accessing'!

bitsA1Into: buffer startingAt: first
    self bitsA1Into: buffer startingAt: first stride: ((width + 31) // 32) * 4

    "Created: / 07-03-2016 / 18:02:23 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 07-03-2016 / 20:08:06 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!Depth1Image methodsFor:'accessing'!

bitsA1Into: buffer startingAt: first stride: stride
    "Store each pixel is a 1-bit quantity holding an alpha value. Pixels are 
     packed together into 32-bit quantities. The ordering of the bits matches 
     the endianess of the platform. On a big-endian machine, the first pixel 
     is in the uppermost bit, on a little-endian machine the first pixel is 
     in the least-significant bit.
    "
    | widthInBytes baseInBuffer baseInPixelStore reverseBits  |

    widthInBytes := (width + 7) // 8.
    ExternalBytes isBigEndian ifTrue:[
        self breakPoint: #jv. "/ Untested code
        0 to: height - 1 do:[:y | 
            baseInBuffer := (stride * y) + first.
            baseInPixelStore  := (widthInBytes * y) + 1.
            buffer replaceBytesFrom: baseInBuffer to: baseInBuffer + widthInBytes - 1 with: bytes startingAt: baseInPixelStore.
        ].
    ] ifFalse:[ 
        reverseBits := ImageReader reverseBits.    
        "/reverseBits := (0 to: 255) asArray.

        0 to: height - 1 do:[:y |  
            | x4 |

            baseInBuffer := (stride * y) + first.
            baseInPixelStore  := (widthInBytes * y) + 1.

            x4 := 0.
            [ x4 < widthInBytes ] whileTrue:[ 
                                               buffer at: baseInBuffer + x4 + "3"0 put: (reverseBits at: (bytes at: baseInPixelStore + x4 + 0) + 1).
                x4 + 1 < widthInBytes ifTrue:[ buffer at: baseInBuffer + x4 + "2"1 put: (reverseBits at: (bytes at: baseInPixelStore + x4 + 1) + 1) ].
                x4 + 2 < widthInBytes ifTrue:[ buffer at: baseInBuffer + x4 + "1"2 put: (reverseBits at: (bytes at: baseInPixelStore + x4 + 2) + 1) ].
                x4 + 3 < widthInBytes ifTrue:[ buffer at: baseInBuffer + x4 + "0"3 put: (reverseBits at: (bytes at: baseInPixelStore + x4 + 3) + 1) ].
                x4 := x4 + 4.
            ].
        ]
    ]
.
    "
    (ImageMask width: 3 height: 3)
        createPixelStore;
        pixelAtX: 0 y:0 put: 1;
        pixelAtX: 2 y:0 put: 1;
        bitsA1.

    "

    "Created: / 07-03-2016 / 18:03:28 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified (comment): / 08-03-2016 / 14:13:15 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!Depth1Image class methodsFor:'documentation'!

version_HG

    ^ '$Changeset: <not expanded> $'
! !

!DeviceGraphicsContext methodsFor:'accessing'!

cairo
    "Return a Cairo context for drawing onto this GC" 
    | cr |

    cr := Cairo::GraphicsContext onSurface: self cairoSurface.
    ^ cr.

    "Created: / 26-12-2014 / 23:28:49 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 25-02-2016 / 11:05:41 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!DeviceGraphicsContext methodsFor:'accessing'!

cairoSurface
    | surface |

    device isX11Platform ifTrue:[ 
        | view width height |

        drawableType == #window ifTrue:[
            view := device viewFromId:drawableId.
            width := view width.
            height := view height.
        ] ifFalse:[ 
            | extent |

            extent := (device getGeometryOf: drawableId) at: #extent.
            width := extent x.
            height := extent y.
        ].

        surface := Cairo::Surface newXlibWithDisplay: device displayId
                                            drawable: drawableId address
                                              visual: device queryDefaultVisual
                                               width: width
                                              height: height.  
        surface setView: view.
        ^ surface
    ].
    device isWindowsPlatform ifTrue:[ 
        | view |

        drawableType == #window ifTrue:[
            view := device viewFromId:drawableId.
        ].
        gcId isNil ifTrue:[ 
            self initGC
        ].
        surface := Cairo::Surface newWin32WithDC: (device dcLockForGC: gcId).
        surface setView: view.
        ^ surface
    ].
    self error: '(Yet) unsupported device type'

    "Modified: / 25-02-2016 / 11:13:51 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified (format): / 29-03-2016 / 23:56:46 / jv"
! !

!DeviceGraphicsContext methodsFor:'cairo support'!

drawableId

    ^drawableId

    "Created: / 10-07-2008 / 10:20:04 / Jan Vrany <vranyj1@fel.cvut.cz>"
! !

!GraphicsContext methodsFor:'drawing in device coordinates'!

displayDeviceLineFromX:x1 y:y1 toX:x2 y:y2
    "draw a line in device coordinates"

    |sav|

    sav := transformation.
    self transformation: nil.
    self displayLineFromX:x1 y:y1 toX:x2 y:y2.
    self transformation: sav

    "Created: / 01-01-2015 / 22:50:49 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!GraphicsContext methodsFor:'drawing in device coordinates'!

displayDeviceRectangleX:x y:y width:w height:h
    "draw a rectangle in device coordinates"

    |sav|

    sav := transformation.
    self transformation: nil.
    self displayRectangleX:x y:y width:w height:h.
    self transformation: sav

    "Created: / 01-01-2015 / 22:51:09 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!GraphicsContext methodsFor:'drawing in device coordinates'!

fillDeviceRectangleX:x y:y width:w height:h
    "fill a rectangle with current paint color (device coordinates)"

    |sav|

    sav := transformation.
    self transformation: nil.
    self fillRectangleX:x y:y width:w height:h.
    self transformation: sav

    "Created: / 01-01-2015 / 22:51:22 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!GraphicsDevice methodsFor:'cairo support'!

cairoSurfaceFor: view

    self error:'Graphics device not supported'

    "Created: / 10-07-2008 / 10:16:21 / Jan Vrany <vranyj1@fel.cvut.cz>"
! !

!GraphicsDevice methodsFor:'accessing'!

displayId
    ^ displayId

    "Created: / 04-07-2008 / 12:58:56 / Jan Vrany <vranyj1@fel.cvut.cz>"
! !

!GraphicsMedium methodsFor:'misc'!

cairoify
    "Change to use Cairo for rendering"
    gc class == CairoGraphicsContext ifFalse:[
        gc := CairoGraphicsContext onDeviceGraphicsContext:gc.
    ].

    "Created: / 15-02-2016 / 21:24:41 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 24-02-2016 / 17:17:07 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!Image methodsFor:'converting'!

asSurfaceWithFormat: format similarTo: surface
    "Returns the receiver as Cairo::Surface (image) with given `format`. If `surface` is not
     nil, then the new surface is made as compatible as possible for uploading to 
     and the use in conjunction with an `surface`.

     CAVEAT: For now, only ARB32 and A1 formats are supported
    "

    | image |

    surface notNil ifTrue:[
        image := Cairo::Surface newImageWithFormat: format  width: width height: height similarTo: surface.   
    ] ifFalse:[ 
        image := Cairo::Surface newImageWithFormat: format  width: width height: height.
    ].
    format == Cairo::Format CAIRO_FORMAT_ARGB32 ifTrue:[ 
        self bitsARGB32Into: image data startingAt: 1 stride: image stride 
    ] ifFalse:[ 
        format == Cairo::Format CAIRO_FORMAT_A1 ifTrue:[ 
            self bitsA1Into: image data startingAt: 1 stride: image stride.
        ] ifFalse:[ 
            self error: 'Unsupported format'.
            ^ nil.    
        ].
    ].
    " 
    image data asByteArray
    "  
    image markDirty.         
    ^ image

    "Created: / 07-03-2016 / 21:57:01 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified (comment): / 08-03-2016 / 14:13:57 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!Image methodsFor:'inspecting'!

inspector2TabImageCairo
    <inspector2Tab>

    | view |

    view := PluggableView new.
    view cairoify.
    view redrawAction:[ self displayOn: view ].
    ^self newInspector2Tab
        label: 'Image (Cairo)';
        priority: 49;
        view: (HVScrollableView forView: view);
        yourself

    "Created: / 31-12-2014 / 12:01:07 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 07-03-2016 / 22:25:07 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!SimpleView methodsFor:'accessing - cairo'!

cairo
    "Return a Cairo context for drawing onto this view"           
    ^ gc cairo

    "Created: / 10-09-2008 / 18:23:11 / Jan Vrany <vranyj1@fel.cvut.cz>"
    "Modified (comment): / 26-12-2014 / 23:29:09 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!SimpleView methodsFor:'accessing - cairo'!

cairoSurface
    "Return a Cairo Surface representing the receiver."
    ^ gc cairoSurface

    "Created: / 26-02-2016 / 22:24:55 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!SimpleView methodsFor:'misc'!

cairoify
    super cairoify.
    self subViews do:[:each | each cairoify ].
    self invalidate.

    "Created: / 18-02-2016 / 22:43:04 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 25-02-2016 / 11:12:05 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!SimpleView methodsFor:'redrawing - cairo'!

redrawWithCairo
    | cr |

    cr := self cairo.
    [  
        self redrawWithCairo: cr
    ] ensure:[
        cr ~~ gc ifTrue:[ cr release ].
    ].

    "Created: / 27-12-2014 / 00:30:15 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 12-02-2016 / 16:38:36 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!SimpleView methodsFor:'redrawing - cairo'!

redrawWithCairo: cr x: x y: y width: w height: h
    cr rectangleX: x  y: y width: w height: h. 
    cr clip.
    self redrawWithCairo: cr

    "Created: / 27-12-2014 / 00:29:03 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!SimpleView methodsFor:'redrawing - cairo'!

redrawWithCairoBuffered
    | cr |

    cr := self cairo.
    [  
        self redrawWithCairoBuffered: cr
    ] ensure:[ 
        cr ~~ gc ifTrue:[ cr release ].
    ].

    "Created: / 27-12-2014 / 00:30:27 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 12-02-2016 / 16:38:44 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!SimpleView methodsFor:'redrawing - cairo'!

redrawWithCairoBuffered: view_cr

    | image_surface image_cr |

    [     
        image_surface := Cairo::Surface newImageWithFormat: Cairo::Format CAIRO_FORMAT_ARGB32 width:self width
                               height:self height.
        image_cr := Cairo::GraphicsContext onSurface: image_surface. 
        self redrawWithCairo: image_cr.  
        view_cr sourceSurface: image_surface x: 0 y: 0.
        view_cr draw.
    ] ensure:[ 
        image_surface notNil ifTrue:[ image_surface release ].
        image_cr notNil ifTrue:[ image_cr release ]
    ].

    "Created: / 27-12-2014 / 00:13:29 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 27-02-2016 / 16:01:29 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!SimpleView methodsFor:'redrawing - cairo'!

redrawWithCairoBuffered: view_cr x: x y: y width: w height: h

    | image_surface image_cr |

    [     
        image_surface := Cairo::Surface newImageWithFormat: Cairo::Format CAIRO_FORMAT_ARGB32 width:self width
                               height:self height.
        image_cr := Cairo::GraphicsContext onSurface: image_surface. 
        image_cr rectangleX: x  y: y width: w height: h. 
        image_cr clip.
        self redrawWithCairo: image_cr x: x y: y width: w height: h.
        view_cr rectangleX: x  y: y width: w height: h. 
        view_cr clip.
        view_cr setSourceSurface: image_surface. 
        view_cr paint.
    ] ensure:[ 
        image_surface notNil ifTrue:[ image_surface release ].
        image_cr notNil ifTrue:[ image_cr release ]
    ].

    "Created: / 27-12-2014 / 00:28:37 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 27-02-2016 / 16:01:42 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!SimpleView methodsFor:'redrawing - cairo'!

redrawWithCairoBufferedX: x y: y width: w height: h     
    | cr |

    cr := self cairo.
    [  
        self redrawWithCairoBuffered: cr x: x y: y width: w height: h     
    ] ensure:[ 
        cr ~~ gc ifTrue:[ cr release ].
    ].

    "Created: / 27-12-2014 / 00:31:33 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 12-02-2016 / 16:38:10 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!SimpleView methodsFor:'redrawing - cairo'!

redrawWithCairoX: x y: y width: w height: h     
    | cr |

    cr := self cairo.
    [  
        self redrawWithCairo: cr x: x y: y width: w height: h     
    ] ensure:[ 
        cr ~~ gc ifTrue:[ cr release ].
    ].

    "Created: / 27-12-2014 / 00:31:22 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 12-02-2016 / 16:38:58 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!stx_libbasic class methodsFor:'documentation'!

version_HG
    ^ '$Changeset: <not expanded> $'
! !

!stx_libview2 class methodsFor:'documentation'!

version_HG
    ^ '$Changeset: <not expanded> $'
! !

!stx_goodies_libcairo class methodsFor:'documentation'!

extensionsVersion_HG

    ^ '$Changeset: <not expanded> $'
! !