nwrkbiz / android-xserver

Maintaining the original project to make it work again with new Android versions.
MIT License
167 stars 18 forks source link

Bitwise operation on pixels #36

Open Hagb opened 1 year ago

Hagb commented 1 year ago

Refer to https://www.x.org/releases/current/doc/xproto/x11protocol.html#requests:CreateGC . With function and plane-mask on CreateGC, client can tell server to draw with bitwise operations:

    ((src FUNC dst) AND plane-mask) OR (dst AND (NOT plane-mask))
Function Operation
Clear 0
And src AND dst
AndReverse src AND (NOT dst)
Copy src
AndInverted (NOT src) AND dst
NoOp dst
Xor src XOR dst
Or src OR dst
Nor (NOT src) AND (NOT dst)
Equiv (NOT src) XOR dst
Invert NOT dst
OrReverse src OR (NOT dst)
CopyInverted NOT src
OrInverted (NOT src) OR dst
Nand (NOT src) OR (NOT dst)
Set 1

I failed to find an efficient way to implement these bitwise operation after spending many hours. I think it might be difficult to implement a paint with bitwise Xfermode. As a result, it is hard to draw via methods of canvas.

TL;DR:

Android doesn't have bitwise Xfermode now. PixelXorXfermode has been removed, and Xfermode has only one subclass PorterDuffXfermode now, which has no bitwise operation, and PorterDuff.Mode.XOR is xor operation for area but not for color, which is misused in

https://github.com/nwrkbiz/android-xserver/blob/51e907880d4295ee3c381a593c738ca365c066fb/library/src/main/java/au/com/darkside/xserver/GContext.java#L406

I tried to write our own Xfermode subclass, so that we can still use methods of canvas to draw. But finally found that Paint uses native code and hardcodes PorterDuffXfermode, even if Paint.setXfermode accepts Xfermode.

ColorMatrixColorFilter can be used to implement bitwise NOT on src but not dst.

nwrkbiz commented 1 year ago

Hmm I think paint.setColorFilter() with an appropiate filter matrix might provide the same functionality like bitwise XOR:

private ColorMatrix getColorMatrix() {
    return new ColorMatrix(new float[] {
        -1,  0,  0,  0, 255,
        0, -1,  0,  0, 255,
        0,  0, -1,  0, 255,
        0,  0,  0,  1,   0
    });
}

// ...
// ...

_paint.setColorFilter(new ColorMatrixColorFilter(getColorMatrix()));
Hagb commented 1 year ago

Hmm I think paint.setColorFilter() with an appropiate filter matrix might provide the same functionality like bitwise XOR:

private ColorMatrix getColorMatrix() {
    return new ColorMatrix(new float[] {
        -1,  0,  0,  0, 255,
        0, -1,  0,  0, 255,
        0,  0, -1,  0, 255,
        0,  0,  0,  1,   0
    });
}

// ...
// ...

_paint.setColorFilter(new ColorMatrixColorFilter(getColorMatrix()));

if I was not mistaken, color filters is only applied to source but not destination, and the above matrix is bitwise NOT. (And any linear matrix operations can not simulate XOR, AND or OR.) When plane-mask is 0xffffff, with ColorMatrix, we can implement CopyInverted (NOT src), but not some other functions includingXOR, AND and OR.

For example, with the above _paint, _canvas.drawLines(points, paint) means drawing a line with CopyInverted (NOT src).