#define GDI_DPa 0x00A000C9 /* D = D & P */
#define GDI_PDxn 0x00A50065 /* D = D ^ ~P */
-#define GDI_DSxn 0x00990066
-#define GDI_PSDnox 0x002D060A
-#define GDI_PDSona 0x00100C85
-#define GDI_DSPDxox 0x00740646
-#define GDI_DPSDonox 0x005B18A9
-
-#define GDI_DPon 0x000500A9
-#define GDI_DPna 0x000A0329
-#define GDI_Pn 0x000F0001
-#define GDI_PDna 0x00500325
-#define GDI_DPan 0x005F00E9
-#define GDI_DSan 0x007700E6
-#define GDI_DSxn 0x00990066
-#define GDI_DPa 0x00A000C9
-#define GDI_D 0x00AA0029
-#define GDI_DPno 0x00AF0229
-#define GDI_SDno 0x00DD0228
-#define GDI_PDno 0x00F50225
-#define GDI_DPo 0x00FA0089
+#define GDI_DSxn 0x00990066 /* D = ~(D ^ S) */
+#define GDI_PSDnox 0x002D060A /* D = P ^ (S | ~D) */
+#define GDI_PDSona 0x00100C85 /* D = P & ~(D | S) */
+#define GDI_DSPDxox 0x00740646 /* D = D ^ (S | ( P ^ D)) */
+#define GDI_DPSDonox 0x005B18A9 /* D = D ^ (P | ~(S | D)) */
+
+#define GDI_DPon 0x000500A9 /* D = ~(D | P) */
+#define GDI_DPna 0x000A0329 /* D = D & ~P */
+#define GDI_Pn 0x000F0001 /* D = ~P */
+#define GDI_PDna 0x00500325 /* D = P &~D */
+#define GDI_DPan 0x005F00E9 /* D = ~(D & P) */
+#define GDI_DSan 0x007700E6 /* D = ~(D & S) */
+#define GDI_DSxn 0x00990066 /* D = ~(D ^ S) */
+#define GDI_DPa 0x00A000C9 /* D = D & P */
+#define GDI_D 0x00AA0029 /* D = D */
+#define GDI_DPno 0x00AF0229 /* D = D | ~P */
+#define GDI_SDno 0x00DD0228 /* D = S | ~D */
+#define GDI_PDno 0x00F50225 /* D = P | ~D */
+#define GDI_DPo 0x00FA0089 /* D = D | P */
/* Brush Styles */
#define GDI_BS_SOLID 0x00
UINT32 freerdp_color_convert_var_bgr(UINT32 srcColor, int srcBpp, int dstBpp, HCLRCONV clrconv)
{
+ if (srcBpp == 8)
+ {
+ BYTE alpha = 0xFF;
+ UINT32 dstColor = 0;
+ PALETTE_ENTRY* entry = &clrconv->palette->entries[srcColor & 0xFF];
+
+ freerdp_color_make_rgb(&dstColor, dstBpp, &entry->red, &entry->green, &entry->blue, &alpha, clrconv);
+
+ return dstColor;
+ }
+
if (srcBpp > 16)
return freerdp_color_convert_bgr(srcColor, srcBpp, dstBpp, clrconv);
else
endif()
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "FreeRDP/libfreerdp")
+
+if(BUILD_TESTING)
+ add_subdirectory(test)
+endif()
+
gdi->bytesPerPixel = 4;
}
}
-
+
gdi->hdc = gdi_GetDC();
gdi->hdc->bitsPerPixel = gdi->dstBpp;
gdi->hdc->bytesPerPixel = gdi->bytesPerPixel;
--- /dev/null
+TestCore
+TestCore.c
--- /dev/null
+
+set(MODULE_NAME "TestGdi")
+set(MODULE_PREFIX "TEST_GDI")
+
+set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c)
+
+set(${MODULE_PREFIX}_TESTS
+ TestGdiRop3.c)
+
+create_test_sourcelist(${MODULE_PREFIX}_SRCS
+ ${${MODULE_PREFIX}_DRIVER}
+ ${${MODULE_PREFIX}_TESTS})
+
+include_directories(..)
+
+add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})
+
+set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${CMOCKERY_LIBRARIES})
+
+set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
+ MONOLITHIC ${MONOLITHIC_BUILD}
+ MODULE freerdp
+ MODULES freerdp-gdi)
+
+set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
+ MONOLITHIC ${MONOLITHIC_BUILD}
+ MODULE winpr
+ MODULES winpr-crt winpr-utils)
+
+target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
+
+set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}")
+
+foreach(test ${${MODULE_PREFIX}_TESTS})
+ get_filename_component(TestName ${test} NAME_WE)
+ add_test(${TestName} ${TESTING_OUTPUT_DIRECTORY}/${MODULE_NAME} ${TestName})
+endforeach()
+
+set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR/Test")
+
--- /dev/null
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+
+
+
+/* Forward declare test functions. */
+int TestGdiRop3(int, char*[]);
+
+
+/* Create map. */
+
+typedef int (*MainFuncPointer)(int , char*[]);
+typedef struct
+{
+ const char* name;
+ MainFuncPointer func;
+} functionMapEntry;
+
+functionMapEntry cmakeGeneratedFunctionMapEntries[] = {
+ {
+ "TestGdiRop3",
+ TestGdiRop3
+ },
+
+ {0,0}
+};
+
+/* Allocate and create a lowercased copy of string
+ (note that it has to be free'd manually) */
+
+char* lowercase(const char *string)
+{
+ char *new_string, *p;
+
+#ifdef __cplusplus
+ new_string = static_cast<char *>(malloc(sizeof(char) *
+ static_cast<size_t>(strlen(string) + 1)));
+#else
+ new_string = (char *)(malloc(sizeof(char) * (size_t)(strlen(string) + 1)));
+#endif
+
+ if (!new_string)
+ {
+ return 0;
+ }
+ strcpy(new_string, string);
+ p = new_string;
+ while (*p != 0)
+ {
+#ifdef __cplusplus
+ *p = static_cast<char>(tolower(*p));
+#else
+ *p = (char)(tolower(*p));
+#endif
+
+ ++p;
+ }
+ return new_string;
+}
+
+int main(int ac, char *av[])
+{
+ int i, NumTests, testNum, partial_match;
+ char *arg, *test_name;
+ int count;
+ int testToRun = -1;
+
+
+
+ for(count =0; cmakeGeneratedFunctionMapEntries[count].name != 0; count++)
+ {
+ }
+ NumTests = count;
+ /* If no test name was given */
+ /* process command line with user function. */
+ if (ac < 2)
+ {
+ /* Ask for a test. */
+ printf("Available tests:\n");
+ for (i =0; i < NumTests; ++i)
+ {
+ printf("%3d. %s\n", i, cmakeGeneratedFunctionMapEntries[i].name);
+ }
+ printf("To run a test, enter the test number: ");
+ fflush(stdout);
+ testNum = 0;
+ if( scanf("%d", &testNum) != 1 )
+ {
+ printf("Couldn't parse that input as a number\n");
+ return -1;
+ }
+ if (testNum >= NumTests)
+ {
+ printf("%3d is an invalid test number.\n", testNum);
+ return -1;
+ }
+ testToRun = testNum;
+ ac--;
+ av++;
+ }
+ partial_match = 0;
+ arg = 0;
+ /* If partial match is requested. */
+ if(testToRun == -1 && ac > 1)
+ {
+ partial_match = (strcmp(av[1], "-R") == 0) ? 1 : 0;
+ }
+ if (partial_match && ac < 3)
+ {
+ printf("-R needs an additional parameter.\n");
+ return -1;
+ }
+ if(testToRun == -1)
+ {
+ arg = lowercase(av[1 + partial_match]);
+ }
+ for (i =0; i < NumTests && testToRun == -1; ++i)
+ {
+ test_name = lowercase(cmakeGeneratedFunctionMapEntries[i].name);
+ if (partial_match && strstr(test_name, arg) != NULL)
+ {
+ testToRun = i;
+ ac -=2;
+ av += 2;
+ }
+ else if (!partial_match && strcmp(test_name, arg) == 0)
+ {
+ testToRun = i;
+ ac--;
+ av++;
+ }
+ free(test_name);
+ }
+ if(arg)
+ {
+ free(arg);
+ }
+ if(testToRun != -1)
+ {
+ int result;
+
+ result = (*cmakeGeneratedFunctionMapEntries[testToRun].func)(ac, av);
+
+ return result;
+ }
+
+
+ /* Nothing was run, display the test names. */
+ printf("Available tests:\n");
+ for (i =0; i < NumTests; ++i)
+ {
+ printf("%3d. %s\n", i, cmakeGeneratedFunctionMapEntries[i].name);
+ }
+ printf("Failed: %s is an invalid test name.\n", av[1]);
+
+ return -1;
+}
--- /dev/null
+
+#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
+ *
+ */
+
+const BYTE rop_P = 0xF0; /* 11110000 */
+const BYTE rop_S = 0xCC; /* 11001100 */
+const BYTE rop_D = 0xAA; /* 10101010 */
+
+char* gdi_convert_postfix_to_infix(char* postfix)
+{
+ int i;
+ int length;
+ BOOL unary;
+ wStack* stack;
+ int al, bl, cl, dl;
+ char *a, *b, *c, *d;
+
+ stack = Stack_New(FALSE);
+
+ length = strlen(postfix);
+
+ for (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: %s\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(cl + 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 char* test_ROP3[] =
+{
+ "DSPDxax",
+ "PSDPxax",
+ "SPna",
+ "DSna",
+ "DPa",
+ "PDxn",
+ "DSxn",
+ "PSDnox",
+ "PDSona",
+ "DSPDxox",
+ "DPSDonox",
+ "DPon",
+ "DPna",
+ "Pn",
+ "PDna",
+ "DPan",
+ "DSan",
+ "DSxn",
+ "DPa",
+ "D",
+ "DPno",
+ "SDno",
+ "PDno",
+ "DPo"
+};
+
+int TestGdiRop3(int argc, char* argv[])
+{
+ int index;
+ char* infix;
+ char* postfix;
+
+ for (index = 0; index < sizeof(test_ROP3) / sizeof(test_ROP3[0]); index++)
+ {
+ postfix = test_ROP3[index];
+ infix = gdi_convert_postfix_to_infix(postfix);
+ printf("%s\t\t%s\n", postfix, infix);
+ free(infix);
+ }
+
+ return 0;
+}
struct _wStack
{
+ int size;
+ int capacity;
+ void** array;
+ HANDLE mutex;
BOOL synchronized;
wObject object;
};
void Stack_Clear(wStack* stack)
{
- if (stack->synchronized)
- {
- }
}
/**
BOOL Stack_Contains(wStack* stack, void* obj)
{
- if (stack->synchronized)
- {
-
- }
-
return FALSE;
}
void Stack_Push(wStack* stack, void* obj)
{
if (stack->synchronized)
- {
+ WaitForSingleObject(stack->mutex, INFINITE);
+ if ((stack->size + 1) >= stack->capacity)
+ {
+ stack->capacity *= 2;
+ stack->array = (void**) realloc(stack->array, sizeof(void*) * stack->capacity);
}
+
+ stack->array[(stack->size)++] = obj;
+
+ if (stack->synchronized)
+ ReleaseMutex(stack->mutex);
}
/**
void* Stack_Pop(wStack* stack)
{
+ void* obj = NULL;
+
if (stack->synchronized)
- {
+ WaitForSingleObject(stack->mutex, INFINITE);
- }
+ if (stack->size > 0)
+ obj = stack->array[--(stack->size)];
+
+ if (stack->synchronized)
+ ReleaseMutex(stack->mutex);
- return NULL;
+ return obj;
}
/**
void* Stack_Peek(wStack* stack)
{
+ void* obj = NULL;
+
if (stack->synchronized)
- {
+ WaitForSingleObject(stack->mutex, INFINITE);
- }
+ if (stack->size > 0)
+ obj = stack->array[stack->size];
+
+ if (stack->synchronized)
+ ReleaseMutex(stack->mutex);
- return NULL;
+ return obj;
}
/**
* Construction, Destruction
*/
-wStack* Stack_New(BOOL bSynchronized)
+wStack* Stack_New(BOOL synchronized)
{
wStack* stack = NULL;
if (stack)
{
- stack->synchronized = bSynchronized;
+ stack->synchronized = synchronized;
+
+ if (stack->synchronized)
+ stack->mutex = CreateMutex(NULL, FALSE, NULL);
+
+ stack->size = 0;
+ stack->capacity = 32;
+ stack->array = (void**) malloc(sizeof(void*) * stack->capacity);
}
return stack;
void Stack_Free(wStack* stack)
{
- free(stack);
+ if (stack)
+ {
+ if (stack->synchronized)
+ CloseHandle(stack->mutex);
+
+ free(stack->array);
+
+ free(stack);
+ }
}