libfreerdp-gdi: fix 8bpp FillRect color
authorMarc-André Moreau <marcandre.moreau@gmail.com>
Sun, 3 Feb 2013 20:16:37 +0000 (15:16 -0500)
committerMarc-André Moreau <marcandre.moreau@gmail.com>
Sun, 3 Feb 2013 20:16:37 +0000 (15:16 -0500)
include/freerdp/gdi/gdi.h
libfreerdp/codec/color.c
libfreerdp/gdi/CMakeLists.txt
libfreerdp/gdi/gdi.c
libfreerdp/gdi/test/.gitignore [new file with mode: 0644]
libfreerdp/gdi/test/CMakeLists.txt [new file with mode: 0644]
libfreerdp/gdi/test/TestGdi.c [new file with mode: 0644]
libfreerdp/gdi/test/TestGdiRop3.c [new file with mode: 0644]
winpr/include/winpr/collections.h
winpr/libwinpr/utils/collections/Stack.c

index e44ae52..1ddb144 100644 (file)
 #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
index f5417d3..4a2aa60 100644 (file)
@@ -350,6 +350,17 @@ UINT32 freerdp_color_convert_var_rgb(UINT32 srcColor, int srcBpp, int dstBpp, HC
 
 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
index 09b908a..af47c88 100644 (file)
@@ -58,3 +58,8 @@ else()
 endif()
 
 set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "FreeRDP/libfreerdp")
+
+if(BUILD_TESTING)
+       add_subdirectory(test)
+endif()
+
index 96719af..82f99cc 100644 (file)
@@ -928,7 +928,7 @@ int gdi_init(freerdp* instance, UINT32 flags, BYTE* buffer)
                        gdi->bytesPerPixel = 4;
                }
        }
-       
+
        gdi->hdc = gdi_GetDC();
        gdi->hdc->bitsPerPixel = gdi->dstBpp;
        gdi->hdc->bytesPerPixel = gdi->bytesPerPixel;
diff --git a/libfreerdp/gdi/test/.gitignore b/libfreerdp/gdi/test/.gitignore
new file mode 100644 (file)
index 0000000..6c68d08
--- /dev/null
@@ -0,0 +1,2 @@
+TestCore
+TestCore.c
diff --git a/libfreerdp/gdi/test/CMakeLists.txt b/libfreerdp/gdi/test/CMakeLists.txt
new file mode 100644 (file)
index 0000000..fe12cc2
--- /dev/null
@@ -0,0 +1,40 @@
+
+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")
+
diff --git a/libfreerdp/gdi/test/TestGdi.c b/libfreerdp/gdi/test/TestGdi.c
new file mode 100644 (file)
index 0000000..4149af4
--- /dev/null
@@ -0,0 +1,160 @@
+#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;
+}
diff --git a/libfreerdp/gdi/test/TestGdiRop3.c b/libfreerdp/gdi/test/TestGdiRop3.c
new file mode 100644 (file)
index 0000000..2c15f39
--- /dev/null
@@ -0,0 +1,237 @@
+
+#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;
+}
index 7de0dd6..fbea704 100644 (file)
@@ -81,6 +81,10 @@ WINPR_API void Queue_Free(wQueue* queue);
 
 struct _wStack
 {
+       int size;
+       int capacity;
+       void** array;
+       HANDLE mutex;
        BOOL synchronized;
        wObject object;
 };
index ce6f0ad..383fe0d 100644 (file)
@@ -65,10 +65,7 @@ BOOL Stack_IsSynchronized(wStack* stack)
 
 void Stack_Clear(wStack* stack)
 {
-       if (stack->synchronized)
-       {
 
-       }
 }
 
 /**
@@ -77,11 +74,6 @@ void Stack_Clear(wStack* stack)
 
 BOOL Stack_Contains(wStack* stack, void* obj)
 {
-       if (stack->synchronized)
-       {
-
-       }
-
        return FALSE;
 }
 
@@ -92,9 +84,18 @@ BOOL Stack_Contains(wStack* stack, void* obj)
 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);
 }
 
 /**
@@ -103,12 +104,18 @@ void Stack_Push(wStack* stack, void* obj)
 
 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;
 }
 
 /**
@@ -117,19 +124,25 @@ void* Stack_Pop(wStack* stack)
 
 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;
 
@@ -137,7 +150,14 @@ wStack* Stack_New(BOOL bSynchronized)
 
        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;
@@ -145,5 +165,13 @@ wStack* Stack_New(BOOL bSynchronized)
 
 void Stack_Free(wStack* stack)
 {
-       free(stack);
+       if (stack)
+       {
+               if (stack->synchronized)
+                       CloseHandle(stack->mutex);
+
+               free(stack->array);
+
+               free(stack);
+       }
 }