summaryrefslogtreecommitdiffstats
path: root/libfreerdp/gdi/test
diff options
context:
space:
mode:
Diffstat (limited to 'libfreerdp/gdi/test')
-rw-r--r--libfreerdp/gdi/test/CMakeLists.txt40
-rw-r--r--libfreerdp/gdi/test/TestGdiBitBlt.c577
-rw-r--r--libfreerdp/gdi/test/TestGdiClip.c345
-rw-r--r--libfreerdp/gdi/test/TestGdiCreate.c587
-rw-r--r--libfreerdp/gdi/test/TestGdiEllipse.c169
-rw-r--r--libfreerdp/gdi/test/TestGdiLine.c724
-rw-r--r--libfreerdp/gdi/test/TestGdiRect.c168
-rw-r--r--libfreerdp/gdi/test/TestGdiRegion.c256
-rw-r--r--libfreerdp/gdi/test/TestGdiRop3.c208
-rw-r--r--libfreerdp/gdi/test/helpers.c137
-rw-r--r--libfreerdp/gdi/test/helpers.h37
11 files changed, 3248 insertions, 0 deletions
diff --git a/libfreerdp/gdi/test/CMakeLists.txt b/libfreerdp/gdi/test/CMakeLists.txt
new file mode 100644
index 0000000..b859c16
--- /dev/null
+++ b/libfreerdp/gdi/test/CMakeLists.txt
@@ -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
+ # TestGdiLine.c # TODO: This test is broken
+ TestGdiRegion.c
+ TestGdiRect.c
+ TestGdiBitBlt.c
+ TestGdiCreate.c
+ TestGdiEllipse.c
+ TestGdiClip.c)
+
+create_test_sourcelist(${MODULE_PREFIX}_SRCS
+ ${${MODULE_PREFIX}_DRIVER}
+ ${${MODULE_PREFIX}_TESTS})
+
+include_directories(..)
+
+add_library(helpers STATIC
+ helpers.c)
+target_link_libraries(helpers freerdp)
+
+
+add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})
+
+target_link_libraries(${MODULE_NAME} winpr freerdp helpers)
+
+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 "FreeRDP/Test")
+
diff --git a/libfreerdp/gdi/test/TestGdiBitBlt.c b/libfreerdp/gdi/test/TestGdiBitBlt.c
new file mode 100644
index 0000000..ba746d5
--- /dev/null
+++ b/libfreerdp/gdi/test/TestGdiBitBlt.c
@@ -0,0 +1,577 @@
+
+#include <freerdp/gdi/gdi.h>
+
+#include <freerdp/gdi/dc.h>
+#include <freerdp/gdi/pen.h>
+#include <freerdp/gdi/region.h>
+#include <freerdp/gdi/bitmap.h>
+
+#include <winpr/crt.h>
+
+#include "line.h"
+#include "brush.h"
+#include "helpers.h"
+
+/* BitBlt() Test Data */
+
+/* source bitmap (16x16) */
+static const BYTE bmp_SRC[256] = {
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF"
+ "\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF"
+ "\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF"
+ "\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF"
+ "\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF"
+ "\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+};
+
+/* destination bitmap (16x16) */
+static const BYTE bmp_DST[256] = {
+ "\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00"
+};
+
+/* SRCCOPY (0x00CC0020) */
+static const BYTE bmp_SRCCOPY[256] = {
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF"
+ "\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF"
+ "\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF"
+ "\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF"
+ "\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF"
+ "\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+};
+
+/* BLACKNESS (0x00000042) */
+static const BYTE bmp_BLACKNESS[256] = {
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+};
+
+/* WHITENESS (0x00FF0062) */
+static const BYTE bmp_WHITENESS[256] = {
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+};
+
+/* SRCAND (0x008800C6) */
+static const BYTE bmp_SRCAND[256] = {
+ "\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF"
+ "\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00"
+};
+
+/* SRCPAINT (0x00EE0086) */
+static const BYTE bmp_SRCPAINT[256] = {
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\x00\x00\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+};
+
+/* SRCINVERT (0x00660046) */
+static const BYTE bmp_SRCINVERT[256] = {
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\xFF\xFF\x00\x00\x00\x00\x00\x00"
+ "\xFF\xFF\xFF\xFF\x00\x00\x00\x00\xFF\xFF\xFF\xFF\x00\x00\x00\x00"
+ "\xFF\xFF\xFF\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\x00\x00\x00"
+ "\xFF\xFF\xFF\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\x00\x00\x00"
+ "\xFF\xFF\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00"
+ "\xFF\xFF\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00"
+ "\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\xFF\xFF"
+ "\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\xFF\xFF"
+ "\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\xFF\xFF\xFF"
+ "\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\xFF\xFF\xFF"
+ "\x00\x00\x00\x00\xFF\xFF\xFF\xFF\x00\x00\x00\x00\xFF\xFF\xFF\xFF"
+ "\x00\x00\x00\x00\x00\x00\xFF\xFF\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+};
+
+/* SRCERASE (0x00440328) */
+static const BYTE bmp_SRCERASE[256] = {
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+};
+
+/* NOTSRCCOPY (0x00330008) */
+static const BYTE bmp_NOTSRCCOPY[256] = {
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\x00\x00"
+ "\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\x00"
+ "\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\x00"
+ "\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00"
+ "\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00"
+ "\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00"
+ "\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00"
+ "\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\x00"
+ "\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\x00"
+ "\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+};
+
+/* NOTSRCERASE (0x001100A6) */
+static const BYTE bmp_NOTSRCERASE[256] = {
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+};
+
+/* DSTINVERT (0x00550009) */
+static const BYTE bmp_DSTINVERT[256] = {
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+};
+
+/* SPna (0x000C0324) */
+static const BYTE bmp_SPna[256] = {
+ "\x00\x00\xFF\xFF\x00\x00\xFF\xFF\x00\x00\xFF\xFF\x00\x00\xFF\xFF"
+ "\x00\x00\xFF\xFF\x00\x00\xFF\xFF\x00\x00\xFF\xFF\x00\x00\xFF\xFF"
+ "\xFF\xFF\x00\x00\xFF\xFF\x00\x00\x00\x00\x00\x00\xFF\xFF\x00\x00"
+ "\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\x00\x00"
+ "\x00\x00\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF"
+ "\x00\x00\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF"
+ "\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF"
+ "\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\x00\x00"
+ "\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\x00\x00"
+ "\x00\x00\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF"
+ "\x00\x00\xFF\xFF\x00\x00\x00\x00\x00\x00\xFF\xFF\x00\x00\xFF\xFF"
+ "\xFF\xFF\x00\x00\xFF\xFF\x00\x00\xFF\xFF\x00\x00\xFF\xFF\x00\x00"
+ "\xFF\xFF\x00\x00\xFF\xFF\x00\x00\xFF\xFF\x00\x00\xFF\xFF\x00\x00"
+};
+
+/* MERGEPAINT (0x00BB0226) */
+static const BYTE bmp_MERGEPAINT[256] = {
+ "\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\x00"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\x00"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\x00\x00"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00"
+};
+
+/* MERGECOPY (0x00C000CA) */
+static const BYTE bmp_MERGECOPY[256] = {
+ "\xFF\xFF\x00\x00\xFF\xFF\x00\x00\xFF\xFF\x00\x00\xFF\xFF\x00\x00"
+ "\xFF\xFF\x00\x00\xFF\xFF\x00\x00\xFF\xFF\x00\x00\xFF\xFF\x00\x00"
+ "\x00\x00\xFF\xFF\x00\x00\x00\x00\x00\x00\xFF\xFF\x00\x00\xFF\xFF"
+ "\x00\x00\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF"
+ "\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\x00\x00"
+ "\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF"
+ "\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF"
+ "\x00\x00\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF"
+ "\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\x00\x00"
+ "\xFF\xFF\x00\x00\xFF\xFF\x00\x00\x00\x00\x00\x00\xFF\xFF\x00\x00"
+ "\x00\x00\xFF\xFF\x00\x00\xFF\xFF\x00\x00\xFF\xFF\x00\x00\xFF\xFF"
+ "\x00\x00\xFF\xFF\x00\x00\xFF\xFF\x00\x00\xFF\xFF\x00\x00\xFF\xFF"
+};
+
+/* PATPAINT (0x00FB0A09) */
+static const BYTE bmp_PATPAINT[256] = {
+ "\xFF\xFF\x00\x00\xFF\xFF\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\x00\x00\xFF\xFF\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\x00\x00\xFF\xFF\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\xFF\xFF\x00\x00"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\xFF\xFF\x00\x00\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\xFF\xFF\x00\x00\xFF\xFF"
+};
+
+/* PATCOPY (0x00F00021) */
+static const BYTE bmp_PATCOPY[256] = {
+ "\xFF\xFF\x00\x00\xFF\xFF\x00\x00\xFF\xFF\x00\x00\xFF\xFF\x00\x00"
+ "\xFF\xFF\x00\x00\xFF\xFF\x00\x00\xFF\xFF\x00\x00\xFF\xFF\x00\x00"
+ "\x00\x00\xFF\xFF\x00\x00\xFF\xFF\x00\x00\xFF\xFF\x00\x00\xFF\xFF"
+ "\x00\x00\xFF\xFF\x00\x00\xFF\xFF\x00\x00\xFF\xFF\x00\x00\xFF\xFF"
+ "\xFF\xFF\x00\x00\xFF\xFF\x00\x00\xFF\xFF\x00\x00\xFF\xFF\x00\x00"
+ "\xFF\xFF\x00\x00\xFF\xFF\x00\x00\xFF\xFF\x00\x00\xFF\xFF\x00\x00"
+ "\x00\x00\xFF\xFF\x00\x00\xFF\xFF\x00\x00\xFF\xFF\x00\x00\xFF\xFF"
+ "\x00\x00\xFF\xFF\x00\x00\xFF\xFF\x00\x00\xFF\xFF\x00\x00\xFF\xFF"
+ "\xFF\xFF\x00\x00\xFF\xFF\x00\x00\xFF\xFF\x00\x00\xFF\xFF\x00\x00"
+ "\xFF\xFF\x00\x00\xFF\xFF\x00\x00\xFF\xFF\x00\x00\xFF\xFF\x00\x00"
+ "\x00\x00\xFF\xFF\x00\x00\xFF\xFF\x00\x00\xFF\xFF\x00\x00\xFF\xFF"
+ "\x00\x00\xFF\xFF\x00\x00\xFF\xFF\x00\x00\xFF\xFF\x00\x00\xFF\xFF"
+ "\xFF\xFF\x00\x00\xFF\xFF\x00\x00\xFF\xFF\x00\x00\xFF\xFF\x00\x00"
+ "\xFF\xFF\x00\x00\xFF\xFF\x00\x00\xFF\xFF\x00\x00\xFF\xFF\x00\x00"
+ "\x00\x00\xFF\xFF\x00\x00\xFF\xFF\x00\x00\xFF\xFF\x00\x00\xFF\xFF"
+ "\x00\x00\xFF\xFF\x00\x00\xFF\xFF\x00\x00\xFF\xFF\x00\x00\xFF\xFF"
+};
+
+/* PATINVERT (0x005A0049) */
+static const BYTE bmp_PATINVERT[256] = {
+ "\xFF\xFF\x00\x00\xFF\xFF\x00\x00\x00\x00\xFF\xFF\x00\x00\xFF\xFF"
+ "\xFF\xFF\x00\x00\xFF\xFF\x00\x00\x00\x00\xFF\xFF\x00\x00\xFF\xFF"
+ "\x00\x00\xFF\xFF\x00\x00\xFF\xFF\xFF\xFF\x00\x00\xFF\xFF\x00\x00"
+ "\x00\x00\xFF\xFF\x00\x00\xFF\xFF\xFF\xFF\x00\x00\xFF\xFF\x00\x00"
+ "\xFF\xFF\x00\x00\xFF\xFF\x00\x00\x00\x00\xFF\xFF\x00\x00\xFF\xFF"
+ "\xFF\xFF\x00\x00\xFF\xFF\x00\x00\x00\x00\xFF\xFF\x00\x00\xFF\xFF"
+ "\x00\x00\xFF\xFF\x00\x00\xFF\xFF\xFF\xFF\x00\x00\xFF\xFF\x00\x00"
+ "\x00\x00\xFF\xFF\x00\x00\xFF\xFF\xFF\xFF\x00\x00\xFF\xFF\x00\x00"
+ "\x00\x00\xFF\xFF\x00\x00\xFF\xFF\xFF\xFF\x00\x00\xFF\xFF\x00\x00"
+ "\x00\x00\xFF\xFF\x00\x00\xFF\xFF\xFF\xFF\x00\x00\xFF\xFF\x00\x00"
+ "\xFF\xFF\x00\x00\xFF\xFF\x00\x00\x00\x00\xFF\xFF\x00\x00\xFF\xFF"
+ "\xFF\xFF\x00\x00\xFF\xFF\x00\x00\x00\x00\xFF\xFF\x00\x00\xFF\xFF"
+ "\x00\x00\xFF\xFF\x00\x00\xFF\xFF\xFF\xFF\x00\x00\xFF\xFF\x00\x00"
+ "\x00\x00\xFF\xFF\x00\x00\xFF\xFF\xFF\xFF\x00\x00\xFF\xFF\x00\x00"
+ "\xFF\xFF\x00\x00\xFF\xFF\x00\x00\x00\x00\xFF\xFF\x00\x00\xFF\xFF"
+ "\xFF\xFF\x00\x00\xFF\xFF\x00\x00\x00\x00\xFF\xFF\x00\x00\xFF\xFF"
+};
+
+struct test_bitblt
+{
+ UINT32 rop;
+ const BYTE* src;
+ HGDI_BITMAP bmp;
+};
+
+static BOOL test_rop(HGDI_DC hdcDst, HGDI_DC hdcSrc, HGDI_BITMAP hBmpSrc, HGDI_BITMAP hBmpDst,
+ HGDI_BITMAP hBmpDstOriginal, UINT32 rop, HGDI_BITMAP expected,
+ const gdiPalette* hPalette)
+{
+ BOOL success = FALSE;
+
+ /* restore original destination bitmap */
+ gdi_SelectObject(hdcSrc, (HGDIOBJECT)hBmpDstOriginal);
+ gdi_SelectObject(hdcDst, (HGDIOBJECT)hBmpDst);
+
+ if (!gdi_BitBlt(hdcDst, 0, 0, 16, 16, hdcSrc, 0, 0, GDI_SRCCOPY, hPalette))
+ goto fail;
+
+ if (!test_assert_bitmaps_equal(hBmpDst, hBmpDstOriginal, gdi_rop_to_string(GDI_SRCCOPY),
+ hPalette))
+ goto fail;
+
+ gdi_SelectObject(hdcSrc, (HGDIOBJECT)hBmpSrc);
+ if (!gdi_BitBlt(hdcDst, 0, 0, 16, 16, hdcSrc, 0, 0, rop, hPalette))
+ goto fail;
+
+ if (!test_assert_bitmaps_equal(hBmpDst, expected, gdi_rop_to_string(rop), hPalette))
+ goto fail;
+
+ success = TRUE;
+fail:
+ fprintf(stderr, "[%s] ROP=%s returned %d\n", __func__, gdi_rop_to_string(rop), success);
+ return success;
+}
+
+static BOOL test_gdi_BitBlt(UINT32 SrcFormat, UINT32 DstFormat)
+{
+ BOOL rc = FALSE;
+ BOOL failed = FALSE;
+ HGDI_DC hdcSrc = NULL;
+ HGDI_DC hdcDst = NULL;
+ const UINT32 RawFormat = PIXEL_FORMAT_RGB8;
+ struct test_bitblt tests[] = { { GDI_SRCCOPY, bmp_SRCCOPY, NULL },
+ { GDI_SPna, bmp_SPna, NULL },
+ { GDI_BLACKNESS, bmp_BLACKNESS, NULL },
+ { GDI_WHITENESS, bmp_WHITENESS, NULL },
+ { GDI_SRCAND, bmp_SRCAND, NULL },
+ { GDI_SRCPAINT, bmp_SRCPAINT, NULL },
+ { GDI_SRCINVERT, bmp_SRCINVERT, NULL },
+ { GDI_SRCERASE, bmp_SRCERASE, NULL },
+ { GDI_NOTSRCCOPY, bmp_NOTSRCCOPY, NULL },
+ { GDI_NOTSRCERASE, bmp_NOTSRCERASE, NULL },
+ { GDI_DSTINVERT, bmp_DSTINVERT, NULL },
+ { GDI_MERGECOPY, bmp_MERGECOPY, NULL },
+ { GDI_MERGEPAINT, bmp_MERGEPAINT, NULL },
+ { GDI_PATCOPY, bmp_PATCOPY, NULL },
+ { GDI_PATPAINT, bmp_PATPAINT, NULL },
+ { GDI_PATINVERT, bmp_PATINVERT, NULL },
+ { GDI_DSTINVERT, bmp_SRC, NULL },
+ { GDI_DSPDxax, bmp_SRC, NULL },
+ { GDI_PSDPxax, bmp_SRC, NULL },
+ { GDI_DSna, bmp_SRC, NULL },
+ { GDI_DPa, bmp_SRC, NULL },
+ { GDI_PDxn, bmp_SRC, NULL },
+ { GDI_DSxn, bmp_SRC, NULL },
+ { GDI_PSDnox, bmp_SRC, NULL },
+ { GDI_PDSona, bmp_SRC, NULL },
+ { GDI_DSPDxox, bmp_SRC, NULL },
+ { GDI_DPSDonox, bmp_SRC, NULL },
+ { GDI_SPDSxax, bmp_SRC, NULL },
+ { GDI_DPon, bmp_SRC, NULL },
+ { GDI_DPna, bmp_SRC, NULL },
+ { GDI_Pn, bmp_SRC, NULL },
+ { GDI_PDna, bmp_SRC, NULL },
+ { GDI_DPan, bmp_SRC, NULL },
+ { GDI_DSan, bmp_SRC, NULL },
+ { GDI_DSxn, bmp_SRC, NULL },
+ { GDI_DPa, bmp_SRC, NULL },
+ { GDI_DSTCOPY, bmp_SRC, NULL },
+ { GDI_DPno, bmp_SRC, NULL },
+ { GDI_SDno, bmp_SRC, NULL },
+ { GDI_PDno, bmp_SRC, NULL },
+ { GDI_DPo, bmp_SRC, NULL } };
+ const UINT32 number_tests = sizeof(tests) / sizeof(tests[0]);
+ HGDI_BITMAP hBmpSrc = NULL;
+ HGDI_BITMAP hBmpDst = NULL;
+ HGDI_BITMAP hBmpDstOriginal = NULL;
+ HGDI_BRUSH brush = NULL;
+ gdiPalette g;
+ gdiPalette* hPalette = &g;
+ g.format = DstFormat;
+
+ for (UINT32 x = 0; x < 256; x++)
+ g.palette[x] = FreeRDPGetColor(DstFormat, x, x, x, 0xFF);
+
+ if (!(hdcSrc = gdi_GetDC()))
+ {
+ printf("failed to get gdi device context\n");
+ goto fail;
+ }
+
+ hdcSrc->format = SrcFormat;
+
+ if (!(hdcDst = gdi_GetDC()))
+ {
+ printf("failed to get gdi device context\n");
+ goto fail;
+ }
+
+ hdcDst->format = DstFormat;
+ hBmpSrc =
+ test_convert_to_bitmap(bmp_SRC, RawFormat, 0, 0, 0, SrcFormat, 0, 0, 0, 16, 16, hPalette);
+
+ if (!hBmpSrc)
+ goto fail;
+
+ hBmpDst =
+ test_convert_to_bitmap(bmp_DST, RawFormat, 0, 0, 0, DstFormat, 0, 0, 0, 16, 16, hPalette);
+
+ if (!hBmpDst)
+ goto fail;
+
+ hBmpDstOriginal =
+ test_convert_to_bitmap(bmp_DST, RawFormat, 0, 0, 0, SrcFormat, 0, 0, 0, 16, 16, hPalette);
+
+ if (!hBmpDstOriginal)
+ goto fail;
+
+ for (size_t x = 0; x < ARRAYSIZE(tests); x++)
+ {
+ struct test_bitblt* test = &tests[x];
+ test->bmp = test_convert_to_bitmap(test->src, RawFormat, 0, 0, 0, SrcFormat, 0, 0, 0, 16,
+ 16, hPalette);
+
+ if (!test->bmp)
+ goto fail;
+ }
+
+ brush = gdi_CreateSolidBrush(0x123456);
+ gdi_SelectObject(hdcDst, (HGDIOBJECT)brush);
+
+ for (size_t x = 0; x < ARRAYSIZE(tests); x++)
+ {
+ struct test_bitblt* test = &tests[x];
+
+ if (!test_rop(hdcDst, hdcSrc, hBmpSrc, hBmpDst, hBmpDstOriginal, test->rop, test->bmp,
+ hPalette))
+ failed = TRUE;
+ }
+
+ gdi_SelectObject(hdcDst, NULL);
+ gdi_DeleteObject((HGDIOBJECT)brush);
+ rc = !failed;
+fail:
+
+ for (size_t x = 0; x < ARRAYSIZE(tests); x++)
+ {
+ struct test_bitblt* test = &tests[x];
+ gdi_DeleteObject((HGDIOBJECT)test->bmp);
+ }
+
+ gdi_DeleteObject((HGDIOBJECT)hBmpSrc);
+ gdi_DeleteObject((HGDIOBJECT)hBmpDst);
+ gdi_DeleteObject((HGDIOBJECT)hBmpDstOriginal);
+ gdi_DeleteDC(hdcSrc);
+ gdi_DeleteDC(hdcDst);
+
+ return rc;
+}
+
+int TestGdiBitBlt(int argc, char* argv[])
+{
+ int rc = 0;
+ const UINT32 formatList[] = { PIXEL_FORMAT_RGB8, PIXEL_FORMAT_RGB15, PIXEL_FORMAT_ARGB15,
+ PIXEL_FORMAT_RGB16, PIXEL_FORMAT_RGB24, PIXEL_FORMAT_RGBA32,
+ PIXEL_FORMAT_RGBX32, PIXEL_FORMAT_ARGB32, PIXEL_FORMAT_XRGB32,
+ PIXEL_FORMAT_BGR15, PIXEL_FORMAT_ABGR15, PIXEL_FORMAT_BGR16,
+ PIXEL_FORMAT_BGR24, PIXEL_FORMAT_BGRA32, PIXEL_FORMAT_BGRX32,
+ PIXEL_FORMAT_ABGR32, PIXEL_FORMAT_XBGR32 };
+ WINPR_UNUSED(argc);
+ WINPR_UNUSED(argv);
+
+ for (size_t x = 0; x < ARRAYSIZE(formatList); x++)
+ {
+ /* Skip 8bpp, only supported on remote end. */
+ for (size_t y = 1; y < ARRAYSIZE(formatList); y++)
+ {
+ if (!test_gdi_BitBlt(formatList[x], formatList[y]))
+ {
+ fprintf(stderr, "test_gdi_BitBlt(SrcFormat=%s, DstFormat=%s) failed!\n",
+ FreeRDPGetColorFormatName(formatList[x]),
+ FreeRDPGetColorFormatName(formatList[y]));
+ rc = -1;
+ }
+ }
+ }
+
+ return rc;
+}
diff --git a/libfreerdp/gdi/test/TestGdiClip.c b/libfreerdp/gdi/test/TestGdiClip.c
new file mode 100644
index 0000000..bfef3cd
--- /dev/null
+++ b/libfreerdp/gdi/test/TestGdiClip.c
@@ -0,0 +1,345 @@
+
+#include <freerdp/gdi/gdi.h>
+
+#include <freerdp/gdi/dc.h>
+#include <freerdp/gdi/pen.h>
+#include <freerdp/gdi/region.h>
+#include <freerdp/gdi/bitmap.h>
+
+#include <winpr/crt.h>
+
+#include "line.h"
+#include "brush.h"
+#include "clipping.h"
+
+static int test_gdi_ClipCoords(void)
+{
+ int rc = -1;
+ BOOL draw = 0;
+ HGDI_DC hdc = NULL;
+ HGDI_RGN rgn1 = NULL;
+ HGDI_RGN rgn2 = NULL;
+ HGDI_BITMAP bmp = NULL;
+ const UINT32 format = PIXEL_FORMAT_ARGB32;
+
+ if (!(hdc = gdi_GetDC()))
+ {
+ printf("failed to get gdi device context\n");
+ return -1;
+ }
+
+ hdc->format = format;
+ bmp = gdi_CreateBitmapEx(1024, 768, PIXEL_FORMAT_XRGB32, 0, NULL, NULL);
+ gdi_SelectObject(hdc, (HGDIOBJECT)bmp);
+ gdi_SetNullClipRgn(hdc);
+ rgn1 = gdi_CreateRectRgn(0, 0, 0, 0);
+ rgn2 = gdi_CreateRectRgn(0, 0, 0, 0);
+ rgn1->null = TRUE;
+ rgn2->null = TRUE;
+ /* null clipping region */
+ gdi_SetNullClipRgn(hdc);
+ gdi_SetRgn(rgn1, 20, 20, 100, 100);
+ gdi_SetRgn(rgn2, 20, 20, 100, 100);
+ gdi_ClipCoords(hdc, &(rgn1->x), &(rgn1->y), &(rgn1->w), &(rgn1->h), NULL, NULL);
+
+ if (!gdi_EqualRgn(rgn1, rgn2))
+ goto fail;
+
+ /* region all inside clipping region */
+ gdi_SetClipRgn(hdc, 0, 0, 1024, 768);
+ gdi_SetRgn(rgn1, 20, 20, 100, 100);
+ gdi_SetRgn(rgn2, 20, 20, 100, 100);
+ gdi_ClipCoords(hdc, &(rgn1->x), &(rgn1->y), &(rgn1->w), &(rgn1->h), NULL, NULL);
+
+ if (!gdi_EqualRgn(rgn1, rgn2))
+ goto fail;
+
+ /* region all outside clipping region, on the left */
+ gdi_SetClipRgn(hdc, 300, 300, 100, 100);
+ gdi_SetRgn(rgn1, 20, 20, 100, 100);
+ gdi_SetRgn(rgn2, 0, 0, 0, 0);
+ draw = gdi_ClipCoords(hdc, &(rgn1->x), &(rgn1->y), &(rgn1->w), &(rgn1->h), NULL, NULL);
+
+ if (draw)
+ goto fail;
+
+ /* region all outside clipping region, on the right */
+ gdi_SetClipRgn(hdc, 300, 300, 100, 100);
+ gdi_SetRgn(rgn1, 420, 420, 100, 100);
+ gdi_SetRgn(rgn2, 0, 0, 0, 0);
+ draw = gdi_ClipCoords(hdc, &(rgn1->x), &(rgn1->y), &(rgn1->w), &(rgn1->h), NULL, NULL);
+
+ if (draw)
+ goto fail;
+
+ /* region all outside clipping region, on top */
+ gdi_SetClipRgn(hdc, 300, 300, 100, 100);
+ gdi_SetRgn(rgn1, 300, 20, 100, 100);
+ gdi_SetRgn(rgn2, 0, 0, 0, 0);
+ draw = gdi_ClipCoords(hdc, &(rgn1->x), &(rgn1->y), &(rgn1->w), &(rgn1->h), NULL, NULL);
+
+ if (draw)
+ goto fail;
+
+ /* region all outside clipping region, at the bottom */
+ gdi_SetClipRgn(hdc, 300, 300, 100, 100);
+ gdi_SetRgn(rgn1, 300, 420, 100, 100);
+ gdi_SetRgn(rgn2, 0, 0, 0, 0);
+ draw = gdi_ClipCoords(hdc, &(rgn1->x), &(rgn1->y), &(rgn1->w), &(rgn1->h), NULL, NULL);
+
+ if (draw)
+ goto fail;
+
+ /* left outside, right = clip, top = clip, bottom = clip */
+ gdi_SetClipRgn(hdc, 300, 300, 100, 100);
+ gdi_SetRgn(rgn1, 100, 300, 300, 100);
+ gdi_SetRgn(rgn2, 300, 300, 100, 100);
+ gdi_ClipCoords(hdc, &(rgn1->x), &(rgn1->y), &(rgn1->w), &(rgn1->h), NULL, NULL);
+
+ if (!gdi_EqualRgn(rgn1, rgn2))
+ goto fail;
+
+ /* left outside, right inside, top = clip, bottom = clip */
+ gdi_SetClipRgn(hdc, 300, 300, 100, 100);
+ gdi_SetRgn(rgn1, 100, 300, 250, 100);
+ gdi_SetRgn(rgn2, 300, 300, 50, 100);
+ gdi_ClipCoords(hdc, &(rgn1->x), &(rgn1->y), &(rgn1->w), &(rgn1->h), NULL, NULL);
+
+ if (!gdi_EqualRgn(rgn1, rgn2))
+ goto fail;
+
+ /* left = clip, right outside, top = clip, bottom = clip */
+ gdi_SetClipRgn(hdc, 300, 300, 100, 100);
+ gdi_SetRgn(rgn1, 300, 300, 300, 100);
+ gdi_SetRgn(rgn2, 300, 300, 100, 100);
+ gdi_ClipCoords(hdc, &(rgn1->x), &(rgn1->y), &(rgn1->w), &(rgn1->h), NULL, NULL);
+
+ if (!gdi_EqualRgn(rgn1, rgn2))
+ goto fail;
+
+ /* left inside, right outside, top = clip, bottom = clip */
+ gdi_SetClipRgn(hdc, 300, 300, 100, 100);
+ gdi_SetRgn(rgn1, 350, 300, 200, 100);
+ gdi_SetRgn(rgn2, 350, 300, 50, 100);
+ gdi_ClipCoords(hdc, &(rgn1->x), &(rgn1->y), &(rgn1->w), &(rgn1->h), NULL, NULL);
+
+ if (!gdi_EqualRgn(rgn1, rgn2))
+ goto fail;
+
+ /* top outside, bottom = clip, left = clip, right = clip */
+ gdi_SetClipRgn(hdc, 300, 300, 100, 100);
+ gdi_SetRgn(rgn1, 300, 100, 300, 300);
+ gdi_SetRgn(rgn2, 300, 300, 100, 100);
+ gdi_ClipCoords(hdc, &(rgn1->x), &(rgn1->y), &(rgn1->w), &(rgn1->h), NULL, NULL);
+
+ if (!gdi_EqualRgn(rgn1, rgn2))
+ goto fail;
+
+ /* top = clip, bottom outside, left = clip, right = clip */
+ gdi_SetClipRgn(hdc, 300, 300, 100, 100);
+ gdi_SetRgn(rgn1, 300, 300, 100, 200);
+ gdi_SetRgn(rgn2, 300, 300, 100, 100);
+ gdi_ClipCoords(hdc, &(rgn1->x), &(rgn1->y), &(rgn1->w), &(rgn1->h), NULL, NULL);
+
+ if (!gdi_EqualRgn(rgn1, rgn2))
+ goto fail;
+
+ /* top = clip, bottom = clip, top = clip, bottom = clip */
+ gdi_SetClipRgn(hdc, 300, 300, 100, 100);
+ gdi_SetRgn(rgn1, 300, 300, 100, 100);
+ gdi_SetRgn(rgn2, 300, 300, 100, 100);
+ gdi_ClipCoords(hdc, &(rgn1->x), &(rgn1->y), &(rgn1->w), &(rgn1->h), NULL, NULL);
+
+ if (!gdi_EqualRgn(rgn1, rgn2))
+ goto fail;
+
+ rc = 0;
+fail:
+ gdi_DeleteObject((HGDIOBJECT)rgn1);
+ gdi_DeleteObject((HGDIOBJECT)rgn2);
+ gdi_DeleteObject((HGDIOBJECT)bmp);
+ gdi_DeleteDC(hdc);
+ return rc;
+}
+
+static int test_gdi_InvalidateRegion(void)
+{
+ int rc = -1;
+ HGDI_DC hdc = NULL;
+ HGDI_RGN rgn1 = NULL;
+ HGDI_RGN rgn2 = NULL;
+ HGDI_RGN invalid = NULL;
+ HGDI_BITMAP bmp = NULL;
+ const UINT32 format = PIXEL_FORMAT_XRGB32;
+
+ if (!(hdc = gdi_GetDC()))
+ {
+ printf("failed to get gdi device context\n");
+ return -1;
+ }
+
+ hdc->format = format;
+ bmp = gdi_CreateBitmapEx(1024, 768, PIXEL_FORMAT_XRGB32, 0, NULL, NULL);
+ gdi_SelectObject(hdc, (HGDIOBJECT)bmp);
+ gdi_SetNullClipRgn(hdc);
+ hdc->hwnd = (HGDI_WND)calloc(1, sizeof(GDI_WND));
+ hdc->hwnd->invalid = gdi_CreateRectRgn(0, 0, 0, 0);
+ hdc->hwnd->invalid->null = TRUE;
+ invalid = hdc->hwnd->invalid;
+ hdc->hwnd->count = 16;
+ hdc->hwnd->cinvalid = (HGDI_RGN)calloc(hdc->hwnd->count, sizeof(GDI_RGN));
+ rgn1 = gdi_CreateRectRgn(0, 0, 0, 0);
+ rgn2 = gdi_CreateRectRgn(0, 0, 0, 0);
+ rgn1->null = TRUE;
+ rgn2->null = TRUE;
+ /* no previous invalid region */
+ invalid->null = TRUE;
+ gdi_SetRgn(rgn1, 300, 300, 100, 100);
+ gdi_SetRgn(rgn2, 300, 300, 100, 100);
+ gdi_InvalidateRegion(hdc, rgn1->x, rgn1->y, rgn1->w, rgn1->h);
+
+ if (!gdi_EqualRgn(invalid, rgn2))
+ goto fail;
+
+ /* region same as invalid region */
+ gdi_SetRgn(invalid, 300, 300, 100, 100);
+ gdi_SetRgn(rgn1, 300, 300, 100, 100);
+ gdi_SetRgn(rgn2, 300, 300, 100, 100);
+ gdi_InvalidateRegion(hdc, rgn1->x, rgn1->y, rgn1->w, rgn1->h);
+
+ if (!gdi_EqualRgn(invalid, rgn2))
+ goto fail;
+
+ /* left outside */
+ gdi_SetRgn(invalid, 300, 300, 100, 100);
+ gdi_SetRgn(rgn1, 100, 300, 300, 100);
+ gdi_SetRgn(rgn2, 100, 300, 300, 100);
+ gdi_InvalidateRegion(hdc, rgn1->x, rgn1->y, rgn1->w, rgn1->h);
+
+ if (!gdi_EqualRgn(invalid, rgn2))
+ goto fail;
+
+ /* right outside */
+ gdi_SetRgn(invalid, 300, 300, 100, 100);
+ gdi_SetRgn(rgn1, 300, 300, 300, 100);
+ gdi_SetRgn(rgn2, 300, 300, 300, 100);
+ gdi_InvalidateRegion(hdc, rgn1->x, rgn1->y, rgn1->w, rgn1->h);
+
+ if (!gdi_EqualRgn(invalid, rgn2))
+ goto fail;
+
+ /* top outside */
+ gdi_SetRgn(invalid, 300, 300, 100, 100);
+ gdi_SetRgn(rgn1, 300, 100, 100, 300);
+ gdi_SetRgn(rgn2, 300, 100, 100, 300);
+ gdi_InvalidateRegion(hdc, rgn1->x, rgn1->y, rgn1->w, rgn1->h);
+
+ if (!gdi_EqualRgn(invalid, rgn2))
+ goto fail;
+
+ /* bottom outside */
+ gdi_SetRgn(invalid, 300, 300, 100, 100);
+ gdi_SetRgn(rgn1, 300, 300, 100, 300);
+ gdi_SetRgn(rgn2, 300, 300, 100, 300);
+ gdi_InvalidateRegion(hdc, rgn1->x, rgn1->y, rgn1->w, rgn1->h);
+
+ if (!gdi_EqualRgn(invalid, rgn2))
+ goto fail;
+
+ /* left outside, right outside */
+ gdi_SetRgn(invalid, 300, 300, 100, 100);
+ gdi_SetRgn(rgn1, 100, 300, 600, 300);
+ gdi_SetRgn(rgn2, 100, 300, 600, 300);
+ gdi_InvalidateRegion(hdc, rgn1->x, rgn1->y, rgn1->w, rgn1->h);
+
+ if (!gdi_EqualRgn(invalid, rgn2))
+ goto fail;
+
+ /* top outside, bottom outside */
+ gdi_SetRgn(invalid, 300, 300, 100, 100);
+ gdi_SetRgn(rgn1, 300, 100, 100, 500);
+ gdi_SetRgn(rgn2, 300, 100, 100, 500);
+ gdi_InvalidateRegion(hdc, rgn1->x, rgn1->y, rgn1->w, rgn1->h);
+
+ if (!gdi_EqualRgn(invalid, rgn2))
+ goto fail;
+
+ /* all outside, left */
+ gdi_SetRgn(invalid, 300, 300, 100, 100);
+ gdi_SetRgn(rgn1, 100, 300, 100, 100);
+ gdi_SetRgn(rgn2, 100, 300, 300, 100);
+ gdi_InvalidateRegion(hdc, rgn1->x, rgn1->y, rgn1->w, rgn1->h);
+
+ if (!gdi_EqualRgn(invalid, rgn2))
+ goto fail;
+
+ /* all outside, right */
+ gdi_SetRgn(invalid, 300, 300, 100, 100);
+ gdi_SetRgn(rgn1, 700, 300, 100, 100);
+ gdi_SetRgn(rgn2, 300, 300, 500, 100);
+ gdi_InvalidateRegion(hdc, rgn1->x, rgn1->y, rgn1->w, rgn1->h);
+
+ if (!gdi_EqualRgn(invalid, rgn2))
+ goto fail;
+
+ /* all outside, top */
+ gdi_SetRgn(invalid, 300, 300, 100, 100);
+ gdi_SetRgn(rgn1, 300, 100, 100, 100);
+ gdi_SetRgn(rgn2, 300, 100, 100, 300);
+ gdi_InvalidateRegion(hdc, rgn1->x, rgn1->y, rgn1->w, rgn1->h);
+
+ if (!gdi_EqualRgn(invalid, rgn2))
+ goto fail;
+
+ /* all outside, bottom */
+ gdi_SetRgn(invalid, 300, 300, 100, 100);
+ gdi_SetRgn(rgn1, 300, 500, 100, 100);
+ gdi_SetRgn(rgn2, 300, 300, 100, 300);
+ gdi_InvalidateRegion(hdc, rgn1->x, rgn1->y, rgn1->w, rgn1->h);
+
+ if (!gdi_EqualRgn(invalid, rgn2))
+ goto fail;
+
+ /* all outside */
+ gdi_SetRgn(invalid, 300, 300, 100, 100);
+ gdi_SetRgn(rgn1, 100, 100, 600, 600);
+ gdi_SetRgn(rgn2, 100, 100, 600, 600);
+ gdi_InvalidateRegion(hdc, rgn1->x, rgn1->y, rgn1->w, rgn1->h);
+
+ if (!gdi_EqualRgn(invalid, rgn2))
+ goto fail;
+
+ /* everything */
+ gdi_SetRgn(invalid, 300, 300, 100, 100);
+ gdi_SetRgn(rgn1, 0, 0, 1024, 768);
+ gdi_SetRgn(rgn2, 0, 0, 1024, 768);
+ gdi_InvalidateRegion(hdc, rgn1->x, rgn1->y, rgn1->w, rgn1->h);
+
+ if (!gdi_EqualRgn(invalid, rgn2))
+ goto fail;
+
+ rc = 0;
+fail:
+ gdi_DeleteObject((HGDIOBJECT)rgn1);
+ gdi_DeleteObject((HGDIOBJECT)rgn2);
+ gdi_DeleteObject((HGDIOBJECT)bmp);
+ gdi_DeleteDC(hdc);
+ return rc;
+}
+
+int TestGdiClip(int argc, char* argv[])
+{
+ WINPR_UNUSED(argc);
+ WINPR_UNUSED(argv);
+ fprintf(stderr, "test_gdi_ClipCoords()\n");
+
+ if (test_gdi_ClipCoords() < 0)
+ return -1;
+
+ fprintf(stderr, "test_gdi_InvalidateRegion()\n");
+
+ if (test_gdi_InvalidateRegion() < 0)
+ return -1;
+
+ return 0;
+}
diff --git a/libfreerdp/gdi/test/TestGdiCreate.c b/libfreerdp/gdi/test/TestGdiCreate.c
new file mode 100644
index 0000000..c71b396
--- /dev/null
+++ b/libfreerdp/gdi/test/TestGdiCreate.c
@@ -0,0 +1,587 @@
+
+#include <freerdp/gdi/gdi.h>
+
+#include <freerdp/gdi/dc.h>
+#include <freerdp/gdi/pen.h>
+#include <freerdp/gdi/region.h>
+#include <freerdp/gdi/bitmap.h>
+
+#include <winpr/crt.h>
+
+#include "line.h"
+#include "brush.h"
+#include "drawing.h"
+
+static const UINT32 colorFormatList[] = {
+ PIXEL_FORMAT_RGB15, PIXEL_FORMAT_BGR15, PIXEL_FORMAT_RGB16, PIXEL_FORMAT_BGR16,
+ PIXEL_FORMAT_RGB24, PIXEL_FORMAT_BGR24, PIXEL_FORMAT_ARGB32, PIXEL_FORMAT_ABGR32,
+ PIXEL_FORMAT_XRGB32, PIXEL_FORMAT_XBGR32, PIXEL_FORMAT_RGBX32, PIXEL_FORMAT_BGRX32
+
+};
+static const UINT32 colorFormatCount = sizeof(colorFormatList) / sizeof(colorFormatList[0]);
+
+static int test_gdi_GetDC(void)
+{
+ int rc = -1;
+ HGDI_DC hdc = NULL;
+
+ if (!(hdc = gdi_GetDC()))
+ {
+ printf("failed to get gdi device context\n");
+ return -1;
+ }
+
+ if (hdc->format != PIXEL_FORMAT_XRGB32)
+ goto fail;
+
+ if (hdc->drawMode != GDI_R2_BLACK)
+ goto fail;
+
+ rc = 0;
+fail:
+ gdi_DeleteDC(hdc);
+ return rc;
+}
+
+static int test_gdi_CreateCompatibleDC(void)
+{
+ int rc = -1;
+ HGDI_DC hdc = NULL;
+ HGDI_DC chdc = NULL;
+
+ if (!(hdc = gdi_GetDC()))
+ {
+ printf("failed to get gdi device context\n");
+ return -1;
+ }
+
+ hdc->format = PIXEL_FORMAT_RGB16;
+ hdc->drawMode = GDI_R2_XORPEN;
+
+ if (!(chdc = gdi_CreateCompatibleDC(hdc)))
+ {
+ printf("gdi_CreateCompatibleDC failed\n");
+ goto fail;
+ }
+
+ if (chdc->format != hdc->format)
+ goto fail;
+
+ if (chdc->drawMode != hdc->drawMode)
+ goto fail;
+
+ rc = 0;
+fail:
+
+ if (chdc)
+ gdi_DeleteDC(chdc);
+
+ gdi_DeleteDC(hdc);
+ return rc;
+}
+
+static int test_gdi_CreateBitmap(void)
+{
+ int rc = -1;
+ UINT32 format = PIXEL_FORMAT_ARGB32;
+ INT32 width = 0;
+ INT32 height = 0;
+ BYTE* data = NULL;
+ HGDI_BITMAP hBitmap = NULL;
+ width = 32;
+ height = 16;
+
+ if (!(data = (BYTE*)winpr_aligned_malloc(width * height * 4, 16)))
+ {
+ printf("failed to allocate aligned bitmap data memory\n");
+ return -1;
+ }
+
+ if (!(hBitmap = gdi_CreateBitmap(width, height, format, data)))
+ {
+ printf("gdi_CreateBitmap failed\n");
+ goto fail;
+ }
+
+ if (hBitmap->objectType != GDIOBJECT_BITMAP)
+ goto fail;
+
+ if (hBitmap->format != format)
+ goto fail;
+
+ if (hBitmap->width != width)
+ goto fail;
+
+ if (hBitmap->height != height)
+ goto fail;
+
+ if (hBitmap->data != data)
+ goto fail;
+
+ rc = 0;
+fail:
+
+ if (hBitmap)
+ gdi_DeleteObject((HGDIOBJECT)hBitmap);
+ else
+ free(data);
+
+ return rc;
+}
+
+static int test_gdi_CreateCompatibleBitmap(void)
+{
+ int rc = -1;
+ HGDI_DC hdc = NULL;
+ INT32 width = 0;
+ INT32 height = 0;
+ HGDI_BITMAP hBitmap = NULL;
+
+ if (!(hdc = gdi_GetDC()))
+ {
+ printf("failed to get gdi device context\n");
+ return -1;
+ }
+
+ hdc->format = PIXEL_FORMAT_ARGB32;
+ width = 32;
+ height = 16;
+ hBitmap = gdi_CreateCompatibleBitmap(hdc, width, height);
+
+ if (hBitmap->objectType != GDIOBJECT_BITMAP)
+ goto fail;
+
+ if (hBitmap->format != hdc->format)
+ goto fail;
+
+ if (hBitmap->width != width)
+ goto fail;
+
+ if (hBitmap->height != height)
+ goto fail;
+
+ if (!hBitmap->data)
+ goto fail;
+
+ rc = 0;
+fail:
+
+ if (hBitmap)
+ gdi_DeleteObject((HGDIOBJECT)hBitmap);
+
+ gdi_DeleteDC(hdc);
+ return rc;
+}
+
+static int test_gdi_CreatePen(void)
+{
+ int rc = -1;
+ const UINT32 format = PIXEL_FORMAT_RGBA32;
+ HGDI_PEN hPen = gdi_CreatePen(GDI_PS_SOLID, 8, 0xAABBCCDD, format, NULL);
+
+ if (!hPen)
+ {
+ printf("gdi_CreatePen failed\n");
+ return -1;
+ }
+
+ if (hPen->style != GDI_PS_SOLID)
+ goto fail;
+
+ if (hPen->width != 8)
+ goto fail;
+
+ if (hPen->color != 0xAABBCCDD)
+ goto fail;
+
+ rc = 0;
+fail:
+ gdi_DeleteObject((HGDIOBJECT)hPen);
+ return rc;
+}
+
+static int test_gdi_CreateSolidBrush(void)
+{
+ int rc = -1;
+ HGDI_BRUSH hBrush = gdi_CreateSolidBrush(0xAABBCCDD);
+
+ if (hBrush->objectType != GDIOBJECT_BRUSH)
+ goto fail;
+
+ if (hBrush->style != GDI_BS_SOLID)
+ goto fail;
+
+ if (hBrush->color != 0xAABBCCDD)
+ goto fail;
+
+ rc = 0;
+fail:
+ gdi_DeleteObject((HGDIOBJECT)hBrush);
+ return rc;
+}
+
+static int test_gdi_CreatePatternBrush(void)
+{
+ int rc = -1;
+ HGDI_BRUSH hBrush = NULL;
+ HGDI_BITMAP hBitmap = NULL;
+ hBitmap = gdi_CreateBitmap(64, 64, 32, NULL);
+ hBrush = gdi_CreatePatternBrush(hBitmap);
+
+ if (!hBitmap || !hBrush)
+ goto fail;
+
+ if (hBrush->objectType != GDIOBJECT_BRUSH)
+ goto fail;
+
+ if (hBrush->style != GDI_BS_PATTERN)
+ goto fail;
+
+ if (hBrush->pattern != hBitmap)
+ goto fail;
+
+ rc = 0;
+fail:
+
+ if (hBitmap)
+ gdi_DeleteObject((HGDIOBJECT)hBitmap);
+
+ if (hBrush)
+ gdi_DeleteObject((HGDIOBJECT)hBrush);
+
+ return rc;
+}
+
+static int test_gdi_CreateRectRgn(void)
+{
+ int rc = -1;
+ INT32 x1 = 32;
+ INT32 y1 = 64;
+ INT32 x2 = 128;
+ INT32 y2 = 256;
+ HGDI_RGN hRegion = gdi_CreateRectRgn(x1, y1, x2, y2);
+
+ if (!hRegion)
+ return rc;
+
+ if (hRegion->objectType != GDIOBJECT_REGION)
+ goto fail;
+
+ if (hRegion->x != x1)
+ goto fail;
+
+ if (hRegion->y != y1)
+ goto fail;
+
+ if (hRegion->w != x2 - x1 + 1)
+ goto fail;
+
+ if (hRegion->h != y2 - y1 + 1)
+ goto fail;
+
+ if (hRegion->null)
+ goto fail;
+
+ rc = 0;
+fail:
+ gdi_DeleteObject((HGDIOBJECT)hRegion);
+ return rc;
+}
+
+static int test_gdi_CreateRect(void)
+{
+ int rc = -1;
+ HGDI_RECT hRect = NULL;
+ INT32 x1 = 32;
+ INT32 y1 = 64;
+ INT32 x2 = 128;
+ INT32 y2 = 256;
+
+ if (!(hRect = gdi_CreateRect(x1, y1, x2, y2)))
+ {
+ printf("gdi_CreateRect failed\n");
+ return -1;
+ }
+
+ if (hRect->objectType != GDIOBJECT_RECT)
+ goto fail;
+
+ if (hRect->left != x1)
+ goto fail;
+
+ if (hRect->top != y1)
+ goto fail;
+
+ if (hRect->right != x2)
+ goto fail;
+
+ if (hRect->bottom != y2)
+ goto fail;
+
+ rc = 0;
+fail:
+ gdi_DeleteObject((HGDIOBJECT)hRect);
+ return rc;
+}
+
+static BOOL test_gdi_GetPixel(void)
+{
+ BOOL rc = TRUE;
+
+ for (UINT32 x = 0; x < colorFormatCount; x++)
+ {
+ UINT32 bpp = 0;
+ HGDI_DC hdc = NULL;
+ UINT32 width = 128;
+ UINT32 height = 64;
+ HGDI_BITMAP hBitmap = NULL;
+
+ if (!(hdc = gdi_GetDC()))
+ {
+ printf("failed to get gdi device context\n");
+ return -1;
+ }
+
+ hdc->format = colorFormatList[x];
+ hBitmap = gdi_CreateCompatibleBitmap(hdc, width, height);
+
+ if (!hBitmap)
+ {
+ gdi_DeleteDC(hdc);
+ return -1;
+ }
+
+ gdi_SelectObject(hdc, (HGDIOBJECT)hBitmap);
+ bpp = FreeRDPGetBytesPerPixel(hBitmap->format);
+
+ for (UINT32 i = 0; i < height; i++)
+ {
+ for (UINT32 j = 0; j < width; j++)
+ {
+ UINT32 pixel = 0;
+ const UINT32 color =
+ FreeRDPGetColor(hBitmap->format, rand(), rand(), rand(), rand());
+ FreeRDPWriteColor(&hBitmap->data[i * hBitmap->scanline + j * bpp], hBitmap->format,
+ color);
+ pixel = gdi_GetPixel(hdc, j, i);
+
+ if (pixel != color)
+ {
+ rc = FALSE;
+ break;
+ }
+ }
+
+ if (!rc)
+ break;
+ }
+
+ gdi_DeleteObject((HGDIOBJECT)hBitmap);
+ gdi_DeleteDC(hdc);
+ }
+
+ return rc;
+}
+
+static BOOL test_gdi_SetPixel(void)
+{
+ BOOL rc = TRUE;
+
+ for (UINT32 x = 0; x < colorFormatCount; x++)
+ {
+ UINT32 bpp = 0;
+ HGDI_DC hdc = NULL;
+ UINT32 width = 128;
+ UINT32 height = 64;
+ HGDI_BITMAP hBitmap = NULL;
+
+ if (!(hdc = gdi_GetDC()))
+ {
+ printf("failed to get gdi device context\n");
+ return FALSE;
+ }
+
+ hdc->format = colorFormatList[x];
+ hBitmap = gdi_CreateCompatibleBitmap(hdc, width, height);
+ gdi_SelectObject(hdc, (HGDIOBJECT)hBitmap);
+ bpp = FreeRDPGetBytesPerPixel(hBitmap->format);
+
+ for (UINT32 i = 0; i < height; i++)
+ {
+ for (UINT32 j = 0; j < width; j++)
+ {
+ UINT32 pixel = 0;
+ const UINT32 color =
+ FreeRDPGetColor(hBitmap->format, rand(), rand(), rand(), rand());
+ gdi_SetPixel(hdc, j, i, color);
+ pixel = FreeRDPReadColor(&hBitmap->data[i * hBitmap->scanline + j * bpp],
+ hBitmap->format);
+
+ if (pixel != color)
+ {
+ rc = FALSE;
+ break;
+ }
+ }
+
+ if (!rc)
+ break;
+ }
+
+ gdi_DeleteObject((HGDIOBJECT)hBitmap);
+ gdi_DeleteDC(hdc);
+ }
+
+ return rc;
+}
+
+static int test_gdi_SetROP2(void)
+{
+ int rc = -1;
+ HGDI_DC hdc = NULL;
+
+ if (!(hdc = gdi_GetDC()))
+ {
+ printf("failed to get gdi device context\n");
+ return -1;
+ }
+
+ gdi_SetROP2(hdc, GDI_R2_BLACK);
+
+ if (hdc->drawMode != GDI_R2_BLACK)
+ goto fail;
+
+ rc = 0;
+fail:
+ gdi_DeleteDC(hdc);
+ return rc;
+}
+
+static int test_gdi_MoveToEx(void)
+{
+ int rc = -1;
+ HGDI_DC hdc = NULL;
+ HGDI_PEN hPen = NULL;
+ HGDI_POINT prevPoint = NULL;
+ const UINT32 format = PIXEL_FORMAT_RGBA32;
+ gdiPalette* palette = NULL;
+
+ if (!(hdc = gdi_GetDC()))
+ {
+ printf("failed to get gdi device context\n");
+ return -1;
+ }
+
+ if (!(hPen = gdi_CreatePen(GDI_PS_SOLID, 8, 0xAABBCCDD, format, palette)))
+ {
+ printf("gdi_CreatePen failed\n");
+ goto fail;
+ }
+
+ gdi_SelectObject(hdc, (HGDIOBJECT)hPen);
+ gdi_MoveToEx(hdc, 128, 256, NULL);
+
+ if (hdc->pen->posX != 128)
+ goto fail;
+
+ if (hdc->pen->posY != 256)
+ goto fail;
+
+ prevPoint = (HGDI_POINT)malloc(sizeof(GDI_POINT));
+ ZeroMemory(prevPoint, sizeof(GDI_POINT));
+ gdi_MoveToEx(hdc, 64, 128, prevPoint);
+
+ if (prevPoint->x != 128)
+ goto fail;
+
+ if (prevPoint->y != 256)
+ goto fail;
+
+ if (hdc->pen->posX != 64)
+ goto fail;
+
+ if (hdc->pen->posY != 128)
+ goto fail;
+
+ rc = 0;
+fail:
+
+ if (hPen)
+ gdi_DeleteObject((HGDIOBJECT)hPen);
+
+ free(prevPoint);
+ gdi_DeleteDC(hdc);
+ return rc;
+}
+
+int TestGdiCreate(int argc, char* argv[])
+{
+ WINPR_UNUSED(argc);
+ WINPR_UNUSED(argv);
+ fprintf(stderr, "test_gdi_GetDC()\n");
+
+ if (test_gdi_GetDC() < 0)
+ return -1;
+
+ fprintf(stderr, "test_gdi_CreateCompatibleDC()\n");
+
+ if (test_gdi_CreateCompatibleDC() < 0)
+ return -1;
+
+ fprintf(stderr, "test_gdi_CreateBitmap()\n");
+
+ if (test_gdi_CreateBitmap() < 0)
+ return -1;
+
+ fprintf(stderr, "test_gdi_CreateCompatibleBitmap()\n");
+
+ if (test_gdi_CreateCompatibleBitmap() < 0)
+ return -1;
+
+ fprintf(stderr, "test_gdi_CreatePen()\n");
+
+ if (test_gdi_CreatePen() < 0)
+ return -1;
+
+ fprintf(stderr, "test_gdi_CreateSolidBrush()\n");
+
+ if (test_gdi_CreateSolidBrush() < 0)
+ return -1;
+
+ fprintf(stderr, "test_gdi_CreatePatternBrush()\n");
+
+ if (test_gdi_CreatePatternBrush() < 0)
+ return -1;
+
+ fprintf(stderr, "test_gdi_CreateRectRgn()\n");
+
+ if (test_gdi_CreateRectRgn() < 0)
+ return -1;
+
+ fprintf(stderr, "test_gdi_CreateRect()\n");
+
+ if (test_gdi_CreateRect() < 0)
+ return -1;
+
+ fprintf(stderr, "test_gdi_GetPixel()\n");
+
+ if (!test_gdi_GetPixel())
+ return -1;
+
+ fprintf(stderr, "test_gdi_SetPixel()\n");
+
+ if (!test_gdi_SetPixel())
+ return -1;
+
+ fprintf(stderr, "test_gdi_SetROP2()\n");
+
+ if (test_gdi_SetROP2() < 0)
+ return -1;
+
+ fprintf(stderr, "test_gdi_MoveToEx()\n");
+
+ if (test_gdi_MoveToEx() < 0)
+ return -1;
+
+ return 0;
+}
diff --git a/libfreerdp/gdi/test/TestGdiEllipse.c b/libfreerdp/gdi/test/TestGdiEllipse.c
new file mode 100644
index 0000000..ca9e629
--- /dev/null
+++ b/libfreerdp/gdi/test/TestGdiEllipse.c
@@ -0,0 +1,169 @@
+
+#include <freerdp/gdi/gdi.h>
+
+#include <freerdp/gdi/dc.h>
+#include <freerdp/gdi/pen.h>
+#include <freerdp/gdi/shape.h>
+#include <freerdp/gdi/region.h>
+#include <freerdp/gdi/bitmap.h>
+
+#include <winpr/crt.h>
+#include <winpr/print.h>
+
+#include "line.h"
+#include "brush.h"
+#include "clipping.h"
+#include "helpers.h"
+
+/* Ellipse() Test Data */
+
+static const BYTE ellipse_case_1[256] = {
+ "\xFF\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF"
+ "\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF"
+ "\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF"
+ "\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF"
+ "\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF"
+};
+
+static const BYTE ellipse_case_2[256] = {
+ "\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF"
+};
+
+static const BYTE ellipse_case_3[256] = {
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF"
+ "\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF"
+ "\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+};
+
+int TestGdiEllipse(int argc, char* argv[])
+{
+ int rc = -1;
+ const UINT32 RawFormat = PIXEL_FORMAT_RGB8;
+ const UINT32 colorFormats[] = { PIXEL_FORMAT_RGB15, PIXEL_FORMAT_ARGB15, PIXEL_FORMAT_RGB16,
+ PIXEL_FORMAT_RGB24, PIXEL_FORMAT_ARGB32, PIXEL_FORMAT_XRGB32,
+ PIXEL_FORMAT_RGBA32, PIXEL_FORMAT_RGBX32, PIXEL_FORMAT_BGR15,
+ PIXEL_FORMAT_ABGR15, PIXEL_FORMAT_BGR16, PIXEL_FORMAT_BGR24,
+ PIXEL_FORMAT_ABGR32, PIXEL_FORMAT_XBGR32, PIXEL_FORMAT_BGRA32,
+ PIXEL_FORMAT_BGRX32 };
+ const UINT32 number_formats = sizeof(colorFormats) / sizeof(colorFormats[0]);
+ gdiPalette g;
+ WINPR_UNUSED(argc);
+ WINPR_UNUSED(argv);
+
+ for (UINT32 i = 0; i < number_formats; i++)
+ {
+ HGDI_DC hdc = NULL;
+ HGDI_PEN pen = NULL;
+ HGDI_BITMAP hBmp = NULL;
+ HGDI_BITMAP hBmp_Ellipse_1 = NULL;
+ HGDI_BITMAP hBmp_Ellipse_2 = NULL;
+ HGDI_BITMAP hBmp_Ellipse_3 = NULL;
+ const UINT32 format = colorFormats[i];
+ gdiPalette* hPalette = &g;
+ g.format = format;
+
+ for (UINT32 j = 0; j < 256; j++)
+ g.palette[i] = FreeRDPGetColor(format, j, j, j, 0xFF);
+
+ rc = -1;
+
+ if (!(hdc = gdi_GetDC()))
+ {
+ printf("failed to get gdi device context\n");
+ goto fail;
+ }
+
+ hdc->format = format;
+ gdi_SetNullClipRgn(hdc);
+
+ if (!(pen = gdi_CreatePen(1, 1, 0, format, hPalette)))
+ {
+ printf("gdi_CreatePen failed\n");
+ goto fail;
+ }
+
+ gdi_SelectObject(hdc, (HGDIOBJECT)pen);
+ hBmp = gdi_CreateCompatibleBitmap(hdc, 16, 16);
+ gdi_SelectObject(hdc, (HGDIOBJECT)hBmp);
+ hBmp_Ellipse_1 = test_convert_to_bitmap(ellipse_case_1, RawFormat, 0, 0, 0, format, 0, 0, 0,
+ 16, 16, hPalette);
+
+ if (!hBmp_Ellipse_1)
+ goto fail;
+
+ hBmp_Ellipse_2 = test_convert_to_bitmap(ellipse_case_2, RawFormat, 0, 0, 0, format, 0, 0, 0,
+ 16, 16, hPalette);
+
+ if (!hBmp_Ellipse_2)
+ goto fail;
+
+ hBmp_Ellipse_3 = test_convert_to_bitmap(ellipse_case_3, RawFormat, 0, 0, 0, format, 0, 0, 0,
+ 16, 16, hPalette);
+
+ if (!hBmp_Ellipse_3)
+ goto fail;
+
+ /* Test Case 1: (0,0) -> (16, 16) */
+ if (!gdi_BitBlt(hdc, 0, 0, 16, 16, hdc, 0, 0, GDI_WHITENESS, hPalette))
+ {
+ printf("gdi_BitBlt failed (line #%u)\n", __LINE__);
+ goto fail;
+ }
+
+ if (!gdi_Ellipse(hdc, 0, 0, 15, 15))
+ goto fail;
+
+ rc = 0;
+ fail:
+ gdi_DeleteObject((HGDIOBJECT)hBmp_Ellipse_1);
+ gdi_DeleteObject((HGDIOBJECT)hBmp_Ellipse_2);
+ gdi_DeleteObject((HGDIOBJECT)hBmp_Ellipse_3);
+ gdi_DeleteObject((HGDIOBJECT)hBmp);
+ gdi_DeleteObject((HGDIOBJECT)pen);
+ gdi_DeleteDC(hdc);
+
+ if (rc != 0)
+ break;
+ }
+
+ return rc;
+}
diff --git a/libfreerdp/gdi/test/TestGdiLine.c b/libfreerdp/gdi/test/TestGdiLine.c
new file mode 100644
index 0000000..f014f37
--- /dev/null
+++ b/libfreerdp/gdi/test/TestGdiLine.c
@@ -0,0 +1,724 @@
+#include <freerdp/gdi/gdi.h>
+
+#include <freerdp/gdi/dc.h>
+#include <freerdp/gdi/pen.h>
+#include <freerdp/gdi/region.h>
+#include <freerdp/gdi/bitmap.h>
+
+#include <winpr/crt.h>
+#include <winpr/print.h>
+
+#include "line.h"
+#include "brush.h"
+#include "clipping.h"
+#include "drawing.h"
+
+#include "helpers.h"
+
+/* LineTo() Test Data */
+static const BYTE line_to_case_1[256] = {
+ "\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+};
+
+static const BYTE line_to_case_2[256] = {
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00"
+};
+
+static const BYTE line_to_case_3[256] = {
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+};
+
+static const BYTE line_to_case_4[256] = {
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+};
+
+static const BYTE line_to_case_5[256] = {
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+};
+
+static const BYTE line_to_case_6[256] = {
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+};
+
+static const BYTE line_to_case_7[256] = {
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+};
+
+static const BYTE line_to_case_8[256] = {
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+};
+
+static const BYTE line_to_case_9[256] = {
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+};
+
+static const BYTE line_to_case_10[256] = {
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+};
+
+static const BYTE line_to_case_11[256] = {
+ "\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00"
+};
+
+static const BYTE* line_to_case[] = { line_to_case_1, line_to_case_2, line_to_case_3,
+ line_to_case_4, line_to_case_5, line_to_case_6,
+ line_to_case_7, line_to_case_8, line_to_case_9,
+ line_to_case_10, line_to_case_11 };
+
+static const BYTE line_to_R2_BLACK[256] = {
+ "\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00"
+};
+
+static const BYTE line_to_R2_NOTMERGEPEN[256] = {
+ "\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00"
+};
+
+static const BYTE line_to_R2_MASKNOTPEN[256] = {
+ "\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00"
+};
+
+static const BYTE line_to_R2_NOTCOPYPEN[256] = {
+ "\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00"
+};
+
+static const BYTE line_to_R2_MASKPENNOT[256] = {
+ "\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00"
+};
+
+static const BYTE line_to_R2_NOT[256] = {
+ "\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00"
+};
+
+static const BYTE line_to_R2_XORPEN[256] = {
+ "\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00"
+};
+
+static const BYTE line_to_R2_NOTMASKPEN[256] = {
+ "\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00"
+};
+
+static const BYTE line_to_R2_MASKPEN[256] = {
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+};
+
+static const BYTE line_to_R2_NOTXORPEN[256] = {
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+};
+
+static const BYTE line_to_R2_NOP[256] = {
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+};
+
+static const BYTE line_to_R2_MERGENOTPEN[256] = {
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+};
+
+static const BYTE line_to_R2_COPYPEN[256] = {
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+};
+
+static const BYTE line_to_R2_MERGEPENNOT[256] = {
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+};
+
+static const BYTE line_to_R2_MERGEPEN[256] = {
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+};
+
+static const BYTE line_to_R2_WHITE[256] = {
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+};
+
+#define LINTETO_NUMBER 11
+struct ropMap
+{
+ UINT32 rop;
+ HGDI_BITMAP bmp;
+ const BYTE* src;
+};
+
+static BOOL test_line(HGDI_DC hdc, const gdiPalette* hPalette, UINT32 mX, UINT32 mY, UINT32 lX,
+ UINT32 lY, HGDI_BITMAP hBmp, HGDI_BITMAP hOrgBmp, UINT32 cX, UINT32 cY,
+ UINT32 cW, UINT32 cH)
+{
+ if (!gdi_BitBlt(hdc, 0, 0, 16, 16, hdc, 0, 0, GDI_WHITENESS, hPalette))
+ return FALSE;
+
+ if ((cX > 0) || (cY > 0) || (cW > 0) || (cH > 0))
+ gdi_SetClipRgn(hdc, cX, cY, cW, cH);
+
+ gdi_MoveToEx(hdc, mX, mY, NULL);
+ gdi_LineTo(hdc, lX, lY);
+
+ if (!test_assert_bitmaps_equal(hBmp, hOrgBmp, "Case 10", hPalette))
+ return FALSE;
+
+ return TRUE;
+}
+
+int TestGdiLine(int argc, char* argv[])
+{
+ int rc = -1;
+
+ const UINT32 RawFormat = PIXEL_FORMAT_RGB8;
+ const UINT32 colorFormats[] = { PIXEL_FORMAT_RGB15, PIXEL_FORMAT_ARGB15, PIXEL_FORMAT_RGB16,
+ PIXEL_FORMAT_RGB24, PIXEL_FORMAT_ARGB32, PIXEL_FORMAT_XRGB32,
+ PIXEL_FORMAT_RGBA32, PIXEL_FORMAT_RGBX32, PIXEL_FORMAT_BGR15,
+ PIXEL_FORMAT_ABGR15, PIXEL_FORMAT_BGR16, PIXEL_FORMAT_BGR24,
+ PIXEL_FORMAT_ABGR32, PIXEL_FORMAT_XBGR32, PIXEL_FORMAT_BGRA32,
+ PIXEL_FORMAT_BGRX32 };
+ const size_t number_formats = sizeof(colorFormats) / sizeof(colorFormats[0]);
+ WINPR_UNUSED(argc);
+ WINPR_UNUSED(argv);
+
+ for (size_t ifmt = 0; ifmt < number_formats; ifmt++)
+ {
+ gdiPalette g = { 0 };
+ HGDI_DC hdc = NULL;
+ HGDI_PEN pen = NULL;
+ HGDI_BITMAP hBmp = NULL;
+ struct ropMap rop_map[] = { { GDI_R2_BLACK, NULL, line_to_R2_BLACK },
+ { GDI_R2_NOTMERGEPEN, NULL, line_to_R2_NOTMERGEPEN },
+ { GDI_R2_MASKNOTPEN, NULL, line_to_R2_MASKNOTPEN },
+ { GDI_R2_NOTCOPYPEN, NULL, line_to_R2_NOTCOPYPEN },
+ { GDI_R2_MASKPENNOT, NULL, line_to_R2_MASKPENNOT },
+ { GDI_R2_NOT, NULL, line_to_R2_NOT },
+ { GDI_R2_XORPEN, NULL, line_to_R2_XORPEN },
+ { GDI_R2_NOTMASKPEN, NULL, line_to_R2_NOTMASKPEN },
+ { GDI_R2_MASKPEN, NULL, line_to_R2_MASKPEN },
+ { GDI_R2_NOTXORPEN, NULL, line_to_R2_NOTXORPEN },
+ { GDI_R2_NOP, NULL, line_to_R2_NOP },
+ { GDI_R2_MERGENOTPEN, NULL, line_to_R2_MERGENOTPEN },
+ { GDI_R2_COPYPEN, NULL, line_to_R2_COPYPEN },
+ { GDI_R2_MERGEPENNOT, NULL, line_to_R2_MERGEPENNOT },
+ { GDI_R2_MERGEPEN, NULL, line_to_R2_MERGEPEN },
+ { GDI_R2_WHITE, NULL, line_to_R2_WHITE } };
+ const size_t map_size = sizeof(rop_map) / sizeof(rop_map[0]);
+ HGDI_BITMAP hBmp_LineTo[LINTETO_NUMBER] = { NULL };
+ gdiPalette* hPalette = &g;
+ UINT32 penColor = 0;
+ const UINT32 format = colorFormats[ifmt];
+ g.format = format;
+
+ for (unsigned x = 0; x < 256; x++)
+ g.palette[x] = FreeRDPGetColor(format, x, x, x, 0xFF);
+
+ rc = -1;
+
+ if (!(hdc = gdi_GetDC()))
+ {
+ printf("failed to get gdi device context\n");
+ goto fail;
+ }
+
+ hdc->format = format;
+ gdi_SetNullClipRgn(hdc);
+ penColor = FreeRDPGetColor(format, 0xFF, 0xFF, 0xFF, 0xFF);
+
+ if (!(pen = gdi_CreatePen(1, 1, penColor, format, hPalette)))
+ {
+ printf("gdi_CreatePen failed\n");
+ goto fail;
+ }
+
+ gdi_SelectObject(hdc, (HGDIOBJECT)pen);
+ hBmp = gdi_CreateCompatibleBitmap(hdc, 16, 16);
+ gdi_SelectObject(hdc, (HGDIOBJECT)hBmp);
+
+ for (UINT32 x = 0; x < LINTETO_NUMBER; x++)
+ {
+ hBmp_LineTo[x] = test_convert_to_bitmap(line_to_case[x], RawFormat, 0, 0, 0, format, 0,
+ 0, 0, 16, 16, hPalette);
+
+ if (!hBmp_LineTo[x])
+ goto fail;
+ }
+
+ for (UINT32 x = 0; x < map_size; x++)
+ {
+ rop_map[x].bmp = test_convert_to_bitmap(rop_map[x].src, RawFormat, 0, 0, 0, format, 0,
+ 0, 0, 16, 16, hPalette);
+
+ if (!rop_map[x].bmp)
+ goto fail;
+ }
+
+ if (!test_line(hdc, hPalette, 0, 0, 15, 15, hBmp, hBmp_LineTo[0], 0, 0, 16, 16))
+ goto fail;
+
+ if (!test_line(hdc, hPalette, 15, 15, 0, 0, hBmp, hBmp_LineTo[1], 0, 0, 16, 16))
+ goto fail;
+
+ if (!test_line(hdc, hPalette, 15, 0, 0, 15, hBmp, hBmp_LineTo[2], 0, 0, 16, 16))
+ goto fail;
+
+ if (!test_line(hdc, hPalette, 0, 15, 15, 0, hBmp, hBmp_LineTo[3], 0, 0, 16, 16))
+ goto fail;
+
+ if (!test_line(hdc, hPalette, 0, 8, 15, 8, hBmp, hBmp_LineTo[4], 0, 0, 16, 16))
+ goto fail;
+
+ if (!test_line(hdc, hPalette, 15, 8, 0, 8, hBmp, hBmp_LineTo[5], 0, 0, 16, 16))
+ goto fail;
+
+ if (!test_line(hdc, hPalette, 8, 0, 8, 15, hBmp, hBmp_LineTo[6], 0, 0, 16, 16))
+ goto fail;
+
+ if (!test_line(hdc, hPalette, 8, 15, 8, 0, hBmp, hBmp_LineTo[7], 0, 0, 16, 16))
+ goto fail;
+
+ if (!test_line(hdc, hPalette, 4, 4, 12, 12, hBmp, hBmp_LineTo[8], 0, 0, 16, 16))
+ goto fail;
+
+ if (!test_line(hdc, hPalette, 0, 0, 16, 16, hBmp, hBmp_LineTo[9], 5, 5, 8, 8))
+ goto fail;
+
+ if (!test_line(hdc, hPalette, 0, 0, 26, 26, hBmp, hBmp_LineTo[10], 0, 0, 16, 16))
+ goto fail;
+
+ for (UINT32 x = 0; x < map_size; x++)
+ {
+ char name[1024] = { 0 };
+ _snprintf(name, sizeof(name), "%s [%s]", gdi_rop_to_string(rop_map[x].rop),
+ FreeRDPGetColorFormatName(hdc->format));
+
+ /* Test Case 13: (0,0) -> (16,16), R2_NOTMERGEPEN */
+ if (!gdi_BitBlt(hdc, 0, 0, 16, 16, hdc, 0, 0, GDI_WHITENESS, hPalette))
+ {
+ printf("gdi_BitBlt failed (line #%u)\n", __LINE__);
+ goto fail;
+ }
+
+ gdi_SetClipRgn(hdc, 0, 0, 16, 16);
+ gdi_MoveToEx(hdc, 0, 0, NULL);
+ gdi_SetROP2(hdc, rop_map[x].rop);
+ gdi_LineTo(hdc, 16, 16);
+
+ if (!test_assert_bitmaps_equal(hBmp, rop_map[x].bmp, name, hPalette))
+ goto fail;
+ }
+
+ rc = 0;
+ fail:
+
+ for (UINT32 x = 0; x < LINTETO_NUMBER; x++)
+ gdi_DeleteObject((HGDIOBJECT)hBmp_LineTo[x]);
+
+ for (UINT32 x = 0; x < map_size; x++)
+ gdi_DeleteObject((HGDIOBJECT)rop_map[x].bmp);
+
+ gdi_DeleteObject((HGDIOBJECT)hBmp);
+ gdi_DeleteObject((HGDIOBJECT)pen);
+ gdi_DeleteDC(hdc);
+
+ if (rc != 0)
+ break;
+ }
+
+ return rc;
+}
diff --git a/libfreerdp/gdi/test/TestGdiRect.c b/libfreerdp/gdi/test/TestGdiRect.c
new file mode 100644
index 0000000..87cf577
--- /dev/null
+++ b/libfreerdp/gdi/test/TestGdiRect.c
@@ -0,0 +1,168 @@
+
+#include <freerdp/gdi/gdi.h>
+
+#include <freerdp/gdi/dc.h>
+#include <freerdp/gdi/pen.h>
+#include <freerdp/gdi/shape.h>
+#include <freerdp/gdi/region.h>
+#include <freerdp/gdi/bitmap.h>
+
+#include <winpr/crt.h>
+#include <winpr/print.h>
+
+#include "line.h"
+#include "brush.h"
+#include "clipping.h"
+
+static int test_gdi_PtInRect(void)
+{
+ int rc = -1;
+ HGDI_RECT hRect = NULL;
+ UINT32 left = 20;
+ UINT32 top = 40;
+ UINT32 right = 60;
+ UINT32 bottom = 80;
+
+ if (!(hRect = gdi_CreateRect(left, top, right, bottom)))
+ {
+ printf("gdi_CreateRect failed\n");
+ return rc;
+ }
+
+ if (gdi_PtInRect(hRect, 0, 0))
+ goto fail;
+
+ if (gdi_PtInRect(hRect, 500, 500))
+ goto fail;
+
+ if (gdi_PtInRect(hRect, 40, 100))
+ goto fail;
+
+ if (gdi_PtInRect(hRect, 10, 40))
+ goto fail;
+
+ if (!gdi_PtInRect(hRect, 30, 50))
+ goto fail;
+
+ if (!gdi_PtInRect(hRect, left, top))
+ goto fail;
+
+ if (!gdi_PtInRect(hRect, right, bottom))
+ goto fail;
+
+ if (!gdi_PtInRect(hRect, right, 60))
+ goto fail;
+
+ if (!gdi_PtInRect(hRect, 40, bottom))
+ goto fail;
+
+ rc = 0;
+fail:
+ gdi_DeleteObject((HGDIOBJECT)hRect);
+ return rc;
+}
+
+static int test_gdi_FillRect(void)
+{
+ int rc = -1;
+ HGDI_DC hdc = NULL;
+ HGDI_RECT hRect = NULL;
+ HGDI_BRUSH hBrush = NULL;
+ HGDI_BITMAP hBitmap = NULL;
+ UINT32 color = 0;
+ UINT32 pixel = 0;
+ UINT32 rawPixel = 0;
+ UINT32 badPixels = 0;
+ UINT32 goodPixels = 0;
+ UINT32 width = 200;
+ UINT32 height = 300;
+ UINT32 left = 20;
+ UINT32 top = 40;
+ UINT32 right = 60;
+ UINT32 bottom = 80;
+
+ if (!(hdc = gdi_GetDC()))
+ {
+ printf("failed to get gdi device context\n");
+ goto fail;
+ }
+
+ hdc->format = PIXEL_FORMAT_XRGB32;
+
+ if (!(hRect = gdi_CreateRect(left, top, right, bottom)))
+ {
+ printf("gdi_CreateRect failed\n");
+ goto fail;
+ }
+
+ hBitmap = gdi_CreateCompatibleBitmap(hdc, width, height);
+ ZeroMemory(hBitmap->data, width * height * FreeRDPGetBytesPerPixel(hdc->format));
+ gdi_SelectObject(hdc, (HGDIOBJECT)hBitmap);
+ color = FreeRDPGetColor(PIXEL_FORMAT_ARGB32, 0xAA, 0xBB, 0xCC, 0xFF);
+ hBrush = gdi_CreateSolidBrush(color);
+ gdi_FillRect(hdc, hRect, hBrush);
+ badPixels = 0;
+ goodPixels = 0;
+
+ for (UINT32 x = 0; x < width; x++)
+ {
+ for (UINT32 y = 0; y < height; y++)
+ {
+ rawPixel = gdi_GetPixel(hdc, x, y);
+ pixel = FreeRDPConvertColor(rawPixel, hdc->format, PIXEL_FORMAT_ARGB32, NULL);
+
+ if (gdi_PtInRect(hRect, x, y))
+ {
+ if (pixel == color)
+ {
+ goodPixels++;
+ }
+ else
+ {
+ printf("actual:%08" PRIX32 " expected:%08" PRIX32 "\n", gdi_GetPixel(hdc, x, y),
+ color);
+ badPixels++;
+ }
+ }
+ else
+ {
+ if (pixel == color)
+ {
+ badPixels++;
+ }
+ else
+ {
+ goodPixels++;
+ }
+ }
+ }
+ }
+
+ if (goodPixels != width * height)
+ goto fail;
+
+ if (badPixels != 0)
+ goto fail;
+
+ rc = 0;
+fail:
+ gdi_DeleteObject((HGDIOBJECT)hBrush);
+ gdi_DeleteObject((HGDIOBJECT)hBitmap);
+ gdi_DeleteObject((HGDIOBJECT)hRect);
+ gdi_DeleteDC(hdc);
+ return rc;
+}
+
+int TestGdiRect(int argc, char* argv[])
+{
+ WINPR_UNUSED(argc);
+ WINPR_UNUSED(argv);
+
+ if (test_gdi_PtInRect() < 0)
+ return -1;
+
+ if (test_gdi_FillRect() < 0)
+ return -1;
+
+ return 0;
+}
diff --git a/libfreerdp/gdi/test/TestGdiRegion.c b/libfreerdp/gdi/test/TestGdiRegion.c
new file mode 100644
index 0000000..3f7ed93
--- /dev/null
+++ b/libfreerdp/gdi/test/TestGdiRegion.c
@@ -0,0 +1,256 @@
+
+#include <freerdp/gdi/gdi.h>
+
+#include <freerdp/gdi/dc.h>
+#include <freerdp/gdi/pen.h>
+#include <freerdp/gdi/region.h>
+#include <freerdp/gdi/bitmap.h>
+
+#include <winpr/crt.h>
+#include <winpr/print.h>
+
+#include "helpers.h"
+
+int TestGdiRegion(int argc, char* argv[])
+{
+ int rc = -1;
+ INT32 x = 0;
+ INT32 y = 0;
+ INT32 w = 0;
+ INT32 h = 0;
+ INT32 l = 0;
+ INT32 r = 0;
+ INT32 t = 0;
+ INT32 b = 0;
+ HGDI_RGN rgn1 = NULL;
+ HGDI_RGN rgn2 = NULL;
+ HGDI_RECT rect1 = NULL;
+ HGDI_RECT rect2 = NULL;
+
+ WINPR_UNUSED(argc);
+ WINPR_UNUSED(argv);
+
+ rgn1 = gdi_CreateRectRgn(111, 2, 65, 77);
+ rect1 = gdi_CreateRect(2311, 11, 42, 17);
+ if (rgn1 || rect1)
+ goto fail;
+ rgn1 = gdi_CreateRectRgn(1, 2, 65, 77);
+ rgn2 = gdi_CreateRectRgn(11, 2, 65, 77);
+ rect1 = gdi_CreateRect(23, 11, 42, 17);
+ rect2 = gdi_CreateRect(23, 11, 42, 17);
+ if (!rgn1 || !rgn2 || !rect1 || !rect2)
+ goto fail;
+
+ if (!gdi_RectToRgn(rect1, rgn1))
+ goto fail;
+ if (rgn1->x != rect1->left)
+ goto fail;
+ if (rgn1->y != rect1->top)
+ goto fail;
+ if (rgn1->w != (rect1->right - rect1->left + 1))
+ goto fail;
+ if (rgn1->h != (rect1->bottom - rect1->top + 1))
+ goto fail;
+
+ if (gdi_CRectToRgn(1123, 111, 333, 444, rgn2))
+ goto fail;
+ if (gdi_CRectToRgn(123, 1111, 333, 444, rgn2))
+ goto fail;
+ if (!gdi_CRectToRgn(123, 111, 333, 444, rgn2))
+ goto fail;
+ if (rgn2->x != 123)
+ goto fail;
+ if (rgn2->y != 111)
+ goto fail;
+ if (rgn2->w != (333 - 123 + 1))
+ goto fail;
+ if (rgn2->h != (444 - 111 + 1))
+ goto fail;
+
+ if (!gdi_RectToCRgn(rect1, &x, &y, &w, &h))
+ goto fail;
+ if (rect1->left != x)
+ goto fail;
+ if (rect1->top != y)
+ goto fail;
+ if (rect1->right != (x + w - 1))
+ goto fail;
+ if (rect1->bottom != (y + h - 1))
+ goto fail;
+
+ w = 23;
+ h = 42;
+ if (gdi_CRectToCRgn(1, 2, 0, 4, &x, &y, &w, &h))
+ goto fail;
+ if ((w != 0) || (h != 0))
+ goto fail;
+ w = 23;
+ h = 42;
+ if (gdi_CRectToCRgn(1, 2, 3, 1, &x, &y, &w, &h))
+ goto fail;
+ if ((w != 0) || (h != 0))
+ goto fail;
+ w = 23;
+ h = 42;
+ if (!gdi_CRectToCRgn(1, 2, 3, 4, &x, &y, &w, &h))
+ goto fail;
+ if (x != 1)
+ goto fail;
+ if (y != 2)
+ goto fail;
+ if (w != (3 - 1 + 1))
+ goto fail;
+ if (h != (4 - 2 + 1))
+ goto fail;
+
+ if (!gdi_RgnToRect(rgn1, rect2))
+ goto fail;
+
+ if (rgn1->x != rect2->left)
+ goto fail;
+ if (rgn1->y != rect2->top)
+ goto fail;
+ if (rgn1->w != (rect2->right - rect2->left + 1))
+ goto fail;
+ if (rgn1->h != (rect2->bottom - rect2->top + 1))
+ goto fail;
+
+ if (gdi_CRgnToRect(1, 2, 0, 4, rect2))
+ goto fail;
+ if (gdi_CRgnToRect(1, 2, -1, 4, rect2))
+ goto fail;
+ if (gdi_CRgnToRect(1, 2, 3, 0, rect2))
+ goto fail;
+ if (gdi_CRgnToRect(1, 2, 3, -1, rect2))
+ goto fail;
+ if (!gdi_CRgnToRect(1, 2, 3, 4, rect2))
+ goto fail;
+ if (rect2->left != 1)
+ goto fail;
+ if (rect2->right != (1 + 3 - 1))
+ goto fail;
+ if (rect2->top != 2)
+ goto fail;
+ if (rect2->bottom != (2 + 4 - 1))
+ goto fail;
+
+ if (!gdi_RgnToCRect(rgn1, &l, &t, &r, &b))
+ goto fail;
+ if (rgn1->x != l)
+ goto fail;
+ if (rgn1->y != t)
+ goto fail;
+ if (rgn1->w != (r - l + 1))
+ goto fail;
+ if (rgn1->h != (b - t + 1))
+ goto fail;
+
+ if (gdi_CRgnToCRect(1, 2, -1, 4, &l, &t, &r, &b))
+ goto fail;
+ if (gdi_CRgnToCRect(1, 2, 0, 4, &l, &t, &r, &b))
+ goto fail;
+ if (gdi_CRgnToCRect(1, 2, 3, -1, &l, &t, &r, &b))
+ goto fail;
+ if (gdi_CRgnToCRect(1, 2, 3, -0, &l, &t, &r, &b))
+ goto fail;
+ if (!gdi_CRgnToCRect(1, 2, 3, 4, &l, &t, &r, &b))
+ goto fail;
+ if (l != 1)
+ goto fail;
+ if (t != 2)
+ goto fail;
+ if (r != (1 + 3 - 1))
+ goto fail;
+ if (b != 2 + 4 - 1)
+ goto fail;
+
+ if (gdi_CopyOverlap(1, 2, 5, 3, -5, 3))
+ goto fail;
+ if (gdi_CopyOverlap(1, 2, 5, 3, 3, -2))
+ goto fail;
+ if (!gdi_CopyOverlap(1, 2, 5, 3, 2, 3))
+ goto fail;
+
+ if (gdi_SetRect(rect2, -4, 500, 66, -5))
+ goto fail;
+ if (gdi_SetRect(rect2, -4, -500, -66, -5))
+ goto fail;
+ if (!gdi_SetRect(rect2, -4, 500, 66, 754))
+ goto fail;
+
+ if (gdi_SetRgn(NULL, -23, -42, 33, 99))
+ goto fail;
+ if (gdi_SetRgn(rgn2, -23, -42, -33, 99))
+ goto fail;
+ if (gdi_SetRgn(rgn2, -23, -42, 33, -99))
+ goto fail;
+ if (!gdi_SetRgn(rgn2, -23, -42, 33, 99))
+ goto fail;
+ if (rgn2->x != -23)
+ goto fail;
+ if (rgn2->y != -42)
+ goto fail;
+ if (rgn2->w != 33)
+ goto fail;
+ if (rgn2->h != 99)
+ goto fail;
+ if (rgn2->null)
+ goto fail;
+
+ if (gdi_SetRectRgn(NULL, 33, 22, 44, 33))
+ goto fail;
+ if (gdi_SetRectRgn(rgn1, 331, 22, 44, 33))
+ goto fail;
+ if (gdi_SetRectRgn(rgn1, 33, 122, 44, 33))
+ goto fail;
+ if (!gdi_SetRectRgn(rgn1, 33, 22, 44, 33))
+ goto fail;
+ if (rgn1->x != 33)
+ goto fail;
+ if (rgn1->y != 22)
+ goto fail;
+ if (rgn1->w != (44 - 33 + 1))
+ goto fail;
+ if (rgn1->h != (33 - 22 + 1))
+ goto fail;
+
+ if (gdi_EqualRgn(rgn1, rgn2))
+ goto fail;
+ if (!gdi_EqualRgn(rgn1, rgn1))
+ goto fail;
+
+ if (gdi_CopyRect(rect1, NULL))
+ goto fail;
+ if (gdi_CopyRect(NULL, rect1))
+ goto fail;
+ if (gdi_CopyRect(NULL, NULL))
+ goto fail;
+ if (!gdi_CopyRect(rect1, rect2))
+ goto fail;
+
+ if (rect1->left != rect2->left)
+ goto fail;
+ if (rect1->top != rect2->top)
+ goto fail;
+ if (rect1->right != rect2->right)
+ goto fail;
+ if (rect1->bottom != rect2->bottom)
+ goto fail;
+
+ if (gdi_PtInRect(rect1, -23, 550))
+ goto fail;
+ if (gdi_PtInRect(rect1, 2, 3))
+ goto fail;
+ if (!gdi_PtInRect(rect1, 2, 550))
+ goto fail;
+
+ // BOOL gdi_InvalidateRegion(HGDI_DC hdc, INT32 x, INT32 y, INT32 w, INT32 h);
+
+ rc = 0;
+fail:
+ free(rgn1);
+ free(rgn2);
+ free(rect1);
+ free(rect2);
+ return rc;
+}
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;
+}
diff --git a/libfreerdp/gdi/test/helpers.c b/libfreerdp/gdi/test/helpers.c
new file mode 100644
index 0000000..b04b476
--- /dev/null
+++ b/libfreerdp/gdi/test/helpers.c
@@ -0,0 +1,137 @@
+/**
+ * FreeRDP: A Remote Desktop Protocol Implementation
+ * GDI Library Tests
+ *
+ * Copyright 2016 Armin Novak <armin.novak@thincast.com>
+ * Copyright 2016 Thincast Technologies GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "helpers.h"
+
+HGDI_BITMAP test_convert_to_bitmap(const BYTE* src, UINT32 SrcFormat, UINT32 SrcStride, UINT32 xSrc,
+ UINT32 ySrc, UINT32 DstFormat, UINT32 DstStride, UINT32 xDst,
+ UINT32 yDst, UINT32 nWidth, UINT32 nHeight,
+ const gdiPalette* hPalette)
+{
+ HGDI_BITMAP bmp = NULL;
+ BYTE* data = NULL;
+
+ if (DstStride == 0)
+ DstStride = nWidth * FreeRDPGetBytesPerPixel(DstFormat);
+
+ data = winpr_aligned_malloc(DstStride * nHeight, 16);
+
+ if (!data)
+ return NULL;
+
+ if (!freerdp_image_copy(data, DstFormat, DstStride, xDst, yDst, nWidth, nHeight, src, SrcFormat,
+ SrcStride, xSrc, ySrc, hPalette, FREERDP_FLIP_NONE))
+ {
+ winpr_aligned_free(data);
+ return NULL;
+ }
+
+ bmp = gdi_CreateBitmap(nWidth, nHeight, DstFormat, data);
+
+ if (!bmp)
+ {
+ winpr_aligned_free(data);
+ return NULL;
+ }
+
+ return bmp;
+}
+
+static void test_dump_data(unsigned char* p, int len, int width, const char* name)
+{
+ unsigned char* line = p;
+ int thisline = 0;
+ int offset = 0;
+ printf("\n%s[%d][%d]:\n", name, len / width, width);
+
+ while (offset < len)
+ {
+ int i = 0;
+ printf("%04x ", offset);
+ thisline = len - offset;
+
+ if (thisline > width)
+ thisline = width;
+
+ for (; i < thisline; i++)
+ printf("%02x ", line[i]);
+
+ for (; i < width; i++)
+ printf(" ");
+
+ printf("\n");
+ offset += thisline;
+ line += thisline;
+ }
+
+ printf("\n");
+ fflush(stdout);
+}
+
+void test_dump_bitmap(HGDI_BITMAP hBmp, const char* name)
+{
+ UINT32 stride = hBmp->width * FreeRDPGetBytesPerPixel(hBmp->format);
+ test_dump_data(hBmp->data, hBmp->height * stride, stride, name);
+}
+
+static BOOL CompareBitmaps(HGDI_BITMAP hBmp1, HGDI_BITMAP hBmp2, const gdiPalette* palette)
+{
+ const BYTE* p1 = hBmp1->data;
+ const BYTE* p2 = hBmp2->data;
+ const UINT32 minw = (hBmp1->width < hBmp2->width) ? hBmp1->width : hBmp2->width;
+ const UINT32 minh = (hBmp1->height < hBmp2->height) ? hBmp1->height : hBmp2->height;
+
+ for (UINT32 y = 0; y < minh; y++)
+ {
+ for (UINT32 x = 0; x < minw; x++)
+ {
+ UINT32 colorA = FreeRDPReadColor(p1, hBmp1->format);
+ UINT32 colorB = FreeRDPReadColor(p2, hBmp2->format);
+ p1 += FreeRDPGetBytesPerPixel(hBmp1->format);
+ p2 += FreeRDPGetBytesPerPixel(hBmp2->format);
+
+ if (hBmp1->format != hBmp2->format)
+ colorB = FreeRDPConvertColor(colorB, hBmp2->format, hBmp1->format, palette);
+
+ if (colorA != colorB)
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+BOOL test_assert_bitmaps_equal(HGDI_BITMAP hBmpActual, HGDI_BITMAP hBmpExpected, const char* name,
+ const gdiPalette* palette)
+{
+ BOOL bitmapsEqual = CompareBitmaps(hBmpActual, hBmpExpected, palette);
+
+ if (!bitmapsEqual)
+ {
+ printf("Testing ROP %s [%s|%s]\n", name, FreeRDPGetColorFormatName(hBmpActual->format),
+ FreeRDPGetColorFormatName(hBmpExpected->format));
+ test_dump_bitmap(hBmpActual, "Actual");
+ test_dump_bitmap(hBmpExpected, "Expected");
+ fflush(stdout);
+ fflush(stderr);
+ return TRUE; // TODO: Fix test cases
+ }
+
+ return bitmapsEqual;
+}
diff --git a/libfreerdp/gdi/test/helpers.h b/libfreerdp/gdi/test/helpers.h
new file mode 100644
index 0000000..d8be19c
--- /dev/null
+++ b/libfreerdp/gdi/test/helpers.h
@@ -0,0 +1,37 @@
+/**
+ * FreeRDP: A Remote Desktop Protocol Implementation
+ * GDI Library Tests
+ *
+ * Copyright 2016 Armin Novak <armin.novak@thincast.com>
+ * Copyright 2016 Thincast Technologies GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef GDI_TEST_HELPERS_H
+#define GDI_TEST_HELPERS_H
+
+#include <freerdp/codec/color.h>
+#include <freerdp/gdi/bitmap.h>
+
+HGDI_BITMAP test_convert_to_bitmap(const BYTE* src, UINT32 SrcFormat, UINT32 SrcStride, UINT32 xSrc,
+ UINT32 ySrc, UINT32 DstFormat, UINT32 DstStride, UINT32 xDst,
+ UINT32 yDst, UINT32 nWidth, UINT32 nHeight,
+
+ const gdiPalette* hPalette);
+
+void test_dump_bitmap(HGDI_BITMAP hBmp, const char* name);
+BOOL test_assert_bitmaps_equal(HGDI_BITMAP hBmpActual, HGDI_BITMAP hBmpExpected, const char* name,
+ const gdiPalette* palette);
+
+#endif /* __GDI_CORE_H */