summaryrefslogtreecommitdiffstats
path: root/libfreerdp/gdi/test/TestGdiRop3.c
diff options
context:
space:
mode:
Diffstat (limited to 'libfreerdp/gdi/test/TestGdiRop3.c')
-rw-r--r--libfreerdp/gdi/test/TestGdiRop3.c208
1 files changed, 208 insertions, 0 deletions
diff --git a/libfreerdp/gdi/test/TestGdiRop3.c b/libfreerdp/gdi/test/TestGdiRop3.c
new file mode 100644
index 0000000..2756633
--- /dev/null
+++ b/libfreerdp/gdi/test/TestGdiRop3.c
@@ -0,0 +1,208 @@
+
+#include <winpr/crt.h>
+#include <winpr/winpr.h>
+#include <winpr/collections.h>
+
+/**
+ * Ternary Raster Operations:
+ * See "Windows Graphics Programming: Win32 GDI and DirectDraw", chapter 11. Advanced Bitmap
+ * Graphics
+ *
+ * Operators:
+ *
+ * AND & a
+ * OR | o
+ * NOT ~ n
+ * XOR ^ x
+ *
+ * Operands:
+ *
+ * Pen/Brush P
+ * Destination D
+ * Source S
+ *
+ * Example:
+ *
+ * Raster operation which returns P if S is 1 or D otherwise:
+ * (rop_S & rop_P) | (~rop_S & rop_D); -> 0xE2 (0x00E20746)
+ *
+ * Postfix notation: DSPDxax
+ * Infix notation: D^(S&(P^D))), (S&P)|(~S&D)
+ *
+ * DSPDxax using D^(S&(P^D)):
+ *
+ * mov eax, P // P
+ * xor eax, D // P^D
+ * and eax, S // S&(P^D)
+ * xor eax, D // D^(S&(P^D))
+ * mov D, eax // write result
+ *
+ * DSPDxax using (S&P)|(~S&D):
+ *
+ * mov eax, S // S
+ * and eax, P // S&P
+ * mov ebx, S // S
+ * not ebx // ~S
+ * and ebx, D // ~D&D
+ * or eax, ebx // (S&P)|(~S&D)
+ * mov D, eax // write result
+ *
+ * Raster operation lower word encoding:
+ *
+ * _______________________________________________________________________________
+ * | | | | | | | | | | | | | | | | |
+ * | Op5 | Op4 | Op3 | Op2 | Op1 | Not| Parse String | Offset |
+ * |____|____|____|____|____|____|____|____|____|____|____|____|____|____|____|____|
+ * 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+ *
+ * Operator:
+ * 0: NOT
+ * 1: XOR
+ * 2: OR
+ * 3: AND
+ *
+ * Parse String:
+ * 0: SPDDDDDD
+ * 1: SPDSPDSP
+ * 2: SDPSDPSD
+ * 3: DDDDDDDD
+ * 4: DDDDDDDD
+ * 5: S+SP-DSS
+ * 6: S+SP-PDS
+ * 7: S+SD-PDS
+ *
+ * The lower word for 0x00E20746 is 0x0746 (00000111 01000110)
+ *
+ * 00 Op5 (NOT, n)
+ * 00 Op4 (NOT, n)
+ * 01 Op3 (XOR, x)
+ * 11 Op2 (AND, a)
+ * 01 Op1 (XOR, x)
+ * 0 Not (unused)
+ * 001 String (SPDSPDSP)
+ * 10 Offset (2)
+ *
+ * We shift SPDSPDSP to the left by 2: DSPDSPSP
+ *
+ * We have 5 operators: 3 binary operators and the last two are unary operators,
+ * so only four operands are needed. The parse string is truncated to reflect
+ * the number of operands we need: DSPD
+ *
+ * The operator string (from Op1 to Op5) is xaxnn, which can be simplified to xax
+ *
+ * The complete string representing the operation is DSPDxax
+ *
+ */
+
+static char* gdi_convert_postfix_to_infix(const char* postfix)
+{
+ size_t length = 0;
+ BOOL unary = 0;
+ wStack* stack = NULL;
+ size_t al = 0;
+ size_t bl = 0;
+ size_t cl = 0;
+ size_t dl = 0;
+ char* a = NULL;
+ char* b = NULL;
+ char* c = NULL;
+ char* d = NULL;
+ bl = cl = dl = 0;
+ stack = Stack_New(FALSE);
+ length = strlen(postfix);
+
+ for (size_t i = 0; i < length; i++)
+ {
+ if ((postfix[i] == 'P') || (postfix[i] == 'D') || (postfix[i] == 'S'))
+ {
+ /* token is an operand, push on the stack */
+ a = malloc(2);
+ a[0] = postfix[i];
+ a[1] = '\0';
+ // printf("Operand: %s\n", a);
+ Stack_Push(stack, a);
+ }
+ else
+ {
+ /* token is an operator */
+ unary = FALSE;
+ c = malloc(2);
+ c[0] = postfix[i];
+ c[1] = '\0';
+
+ if (c[0] == 'a')
+ {
+ c[0] = '&';
+ }
+ else if (c[0] == 'o')
+ {
+ c[0] = '|';
+ }
+ else if (c[0] == 'n')
+ {
+ c[0] = '~';
+ unary = TRUE;
+ }
+ else if (c[0] == 'x')
+ {
+ c[0] = '^';
+ }
+ else
+ {
+ printf("invalid operator: %c\n", c[0]);
+ }
+
+ // printf("Operator: %s\n", c);
+ a = (char*)Stack_Pop(stack);
+
+ if (unary)
+ b = NULL;
+ else
+ b = (char*)Stack_Pop(stack);
+
+ al = strlen(a);
+
+ if (b)
+ bl = strlen(b);
+
+ cl = 1;
+ dl = al + bl + cl + 3;
+ d = malloc(dl + 1);
+ sprintf_s(d, dl, "(%s%s%s)", b ? b : "", c, a);
+ Stack_Push(stack, d);
+ free(a);
+ free(b);
+ free(c);
+ }
+ }
+
+ d = (char*)Stack_Pop(stack);
+ Stack_Free(stack);
+ return d;
+}
+
+static const char* test_ROP3[] = { "DSPDxax", "PSDPxax", "SPna", "DSna", "DPa",
+ "PDxn", "DSxn", "PSDnox", "PDSona", "DSPDxox",
+ "DPSDonox", "SPDSxax", "DPon", "DPna", "Pn",
+ "PDna", "DPan", "DSan", "DSxn", "DPa",
+ "D", "DPno", "SDno", "PDno", "DPo" };
+
+int TestGdiRop3(int argc, char* argv[])
+{
+ WINPR_UNUSED(argc);
+ WINPR_UNUSED(argv);
+
+ for (size_t index = 0; index < sizeof(test_ROP3) / sizeof(test_ROP3[0]); index++)
+ {
+ const char* postfix = test_ROP3[index];
+ char* infix = gdi_convert_postfix_to_infix(postfix);
+
+ if (!infix)
+ return -1;
+
+ printf("%s\t\t%s\n", postfix, infix);
+ free(infix);
+ }
+
+ return 0;
+}