From 778faedbaecdab5bba377861ddece0d110eab747 Mon Sep 17 00:00:00 2001 From: Huw Davies Date: Fri, 15 Jul 2016 08:59:29 +0100 Subject: [PATCH] gdi32: Copy 1-bpp pixels one byte at a time. Signed-off-by: Huw Davies Signed-off-by: Alexandre Julliard --- dlls/gdi32/dibdrv/primitives.c | 290 ++++++++++++++++++++++++++++++--- dlls/gdi32/tests/dib.c | 42 +++-- 2 files changed, 293 insertions(+), 39 deletions(-) diff --git a/dlls/gdi32/dibdrv/primitives.c b/dlls/gdi32/dibdrv/primitives.c index 00b71f200a6..e75792c33d7 100644 --- a/dlls/gdi32/dibdrv/primitives.c +++ b/dlls/gdi32/dibdrv/primitives.c @@ -106,6 +106,7 @@ static inline BYTE *get_pixel_ptr_1(const dib_info *dib, int x, int y) static const BYTE pixel_masks_4[2] = {0xf0, 0x0f}; static const BYTE pixel_masks_1[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01}; +static const BYTE edge_masks_1[8] = {0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01}; static inline void do_rop_32(DWORD *ptr, DWORD and, DWORD xor) { @@ -226,33 +227,275 @@ static inline void do_rop_codes_line_rev_4(BYTE *dst, int dst_x, const BYTE *src } } -static inline void do_rop_codes_line_1(BYTE *dst, int dst_x, const BYTE *src, int src_x, - struct rop_codes *codes, int len) +/************************************************** + * get_src_byte_1 + * + * Return a byte representing 8 pixels of src data + * that is aligned with the dst. + * + * off is the number of bits that src is ahead of dst + * measured from the start. If off is +ve then we need to + * grab data from src[0] and src[1]. If off is -ve we use + * last (which is equivalent to src[-1]) and src[0]. For + * the first call in a line the last component will not be + * needed so it's safe for the caller to zero-init it. + * + * S |.....xxx|xxxxxxxx + * D |..xxxxxx|xxxxxxxx off = +3 + * + * S |..xxxxxx|xxxxxxxx + * D |.....xxx|xxxxxxxx off = -3 + */ +static inline BYTE get_src_byte_1(const BYTE *src, int off, BYTE *last) { BYTE src_val; - for (src += src_x / 8, dst += dst_x / 8; len > 0; len--, dst_x++, src_x++) + if (off == 0) + src_val = src[0]; + else if (off > 0) + src_val = (src[0] << off) | (src[1] >> (8 - off)); + else { - src_val = *src & pixel_masks_1[src_x & 7] ? 0xff : 0; - do_rop_codes_mask_8( dst, src_val, codes, pixel_masks_1[dst_x & 7] ); - if ((src_x & 7) == 7) src++; - if ((dst_x & 7) == 7) dst++; + src_val = (*last << (8 + off)) | (src[0] >> -off); + *last = src[0]; + } + + return src_val; +} + +static inline void do_rop_codes_line_1(BYTE *dst, int dst_x, const BYTE *src, int src_x, + struct rop_codes *codes, int len, int rop2) +{ + BYTE src_val, last_src = 0; + int off = (src_x & 7) - (dst_x & 7), i, full_bytes; + int dst_end = dst_x + len; + BYTE mask; + + src += src_x / 8; + dst += dst_x / 8; + + /* Handle special case of all of dst in one byte. */ + if ((dst_x & ~7) == ((dst_end - 1) & ~7)) + { + if (off == 0) + src_val = src[0]; + else if (off > 0) + { + src_val = src[0] << off; + if ((dst_end & 7) + off > 8) + src_val |= (src[1] >> (8 - off)); + } + else + src_val = src[0] >> -off; + + mask = edge_masks_1[dst_x & 7]; + if (dst_end & 7) + mask &= ~edge_masks_1[dst_end & 7]; + do_rop_codes_mask_8( dst, src_val, codes, mask ); + return; + } + + if (dst_x & 7) + { + src_val = get_src_byte_1( src, off, &last_src ); + mask = edge_masks_1[dst_x & 7]; + do_rop_codes_mask_8( dst, src_val, codes, mask ); + src++; + dst++; + } + + full_bytes = (dst_end - ((dst_x + 7) & ~7)) / 8; + + if (off == 0) + { + if (rop2 == R2_COPYPEN) + { + memmove( dst, src, full_bytes ); + src += full_bytes; + dst += full_bytes; + } + else + { + for (i = 0; i < full_bytes; i++, src++, dst++) + do_rop_codes_8( dst, src[0], codes ); + } + } + else if (off > 0) + { + if (rop2 == R2_COPYPEN) + { + for (i = 0; i < full_bytes; i++, src++, dst++) + dst[0] = (src[0] << off) | (src[1] >> (8 - off)); + } + else + { + for (i = 0; i < full_bytes; i++, src++, dst++) + do_rop_codes_8( dst, (src[0] << off) | (src[1] >> (8 - off)), codes ); + } + } + else + { + if (rop2 == R2_COPYPEN) + { + for (i = 0; i < full_bytes; i++, src++, dst++) + { + src_val = (last_src << (8 + off)) | (src[0] >> -off); + last_src = src[0]; + dst[0] = src_val; + } + } + else + { + for (i = 0; i < full_bytes; i++, src++, dst++) + { + src_val = (last_src << (8 + off)) | (src[0] >> -off); + last_src = src[0]; + do_rop_codes_8( dst, src_val, codes ); + } + } + } + + if (dst_end & 7) + { + if (off > 0 && (dst_end & 7) + off <= 8) + /* Don't read src[1] if everything's in src[0]. */ + src_val = src[0] << off; + else if (off < 0 && (dst_end & 7) + off <= 0) + /* Don't read src[0] if everything's in last_src. */ + src_val = last_src << (8 + off); + else + src_val = get_src_byte_1( src, off, &last_src ); + mask = ~edge_masks_1[dst_end & 7]; + do_rop_codes_mask_8( dst, src_val, codes, mask ); } } -static inline void do_rop_codes_line_rev_1(BYTE *dst, int dst_x, const BYTE *src, int src_x, - struct rop_codes *codes, int len) +/************************************************** + * get_src_byte_rev_1 + * + * Return a byte representing 8 pixels of src data + * that is aligned with the dst. + * + * off is the number of bits that src is ahead of dst + * measured from the end. If off is +ve then we need to + * grab data from src[0] and last (which is equivalent to src[1]). + * If off is -ve we use src[-1]) and src[0]. For the first call + * in a line the last component wil not be needed so it is safe + * for the caller to zero-init it. + * + * S xxxxxxxx|xxxxxx..| + * D xxxxxxxx|xxx.....| off = +3 + * + * S xxxxxxxx|xxx.....| + * D xxxxxxxx|xxxxxx..| off = -3 + */ +static inline BYTE get_src_byte_rev_1(const BYTE *src, int off, BYTE *last) { BYTE src_val; - src_x += len - 1; - dst_x += len - 1; - for (src += src_x / 8, dst += dst_x / 8; len > 0; len--, dst_x--, src_x--) + if (off == 0) + src_val = src[0]; + else if (off > 0) { - src_val = *src & pixel_masks_1[src_x & 7] ? 0xff : 0; - do_rop_codes_mask_8( dst, src_val, codes, pixel_masks_1[dst_x & 7] ); - if ((src_x & 7) == 0) src--; - if ((dst_x & 7) == 0) dst--; + src_val = (src[0] << off) | (*last >> (8 - off)); + *last = *src; + } + else + src_val = (src[-1] << (8 + off)) | (src[0] >> -off); + + return src_val; +} + +static inline void do_rop_codes_line_rev_1(BYTE *dst, int dst_x, const BYTE *src, int src_x, + struct rop_codes *codes, int len, int rop2) +{ + BYTE src_val, last_src = 0; + int src_end = src_x + len, dst_end = dst_x + len; + int off = ((src_end - 1) & 7) - ((dst_end - 1) & 7), i, full_bytes; + BYTE mask; + + /* Handle special case of all of dst in one byte. */ + if ((dst_x & ~7) == ((dst_end - 1) & ~7)) + { + do_rop_codes_line_1(dst, dst_x, src, src_x, codes, len, rop2); + return; + } + + src += (src_end - 1) / 8; + dst += (dst_end - 1) / 8; + + if (dst_end & 7) + { + src_val = get_src_byte_rev_1( src, off, &last_src ); + mask = ~edge_masks_1[dst_end & 7]; + do_rop_codes_mask_8( dst, src_val, codes, mask ); + src--; + dst--; + } + + full_bytes = (dst_end - ((dst_x + 7) & ~7)) / 8; + + if (off == 0) + { + if (rop2 == R2_COPYPEN) + { + memmove( dst, src, full_bytes ); + src -= full_bytes; + dst -= full_bytes; + } + else + { + for (i = 0; i < full_bytes; i++, src--, dst--) + do_rop_codes_8( dst, src[0], codes ); + } + } + else if (off > 0) + { + if (rop2 == R2_COPYPEN) + { + for (i = 0; i < full_bytes; i++, src--, dst--) + { + src_val = (src[0] << off) | (last_src >> (8 - off)); + last_src = src[0]; + dst[0] = src_val; + } + } + else + { + for (i = 0; i < full_bytes; i++, src--, dst--) + { + src_val = (src[0] << off) | (last_src >> (8 - off)); + last_src = src[0]; + do_rop_codes_8( dst, src_val, codes ); + } + } + } + else + { + if (rop2 == R2_COPYPEN) + { + for (i = 0; i < full_bytes; i++, src--, dst--) + dst[0] = (src[-1] << (8 + off)) | (src[0] >> -off); + } + else + { + for (i = 0; i < full_bytes; i++, src--, dst--) + do_rop_codes_8( dst, (src[-1] << (8 + off)) | (src[0] >> -off), codes ); + } + } + + if (dst_x & 7) + { + if (off < 0 && (dst_x & 7) + off >= 0) + /* Don't read src[-1] if everything's in src[0]. */ + src_val = src[0] >> -off; + else if (off > 0 && (dst_x & 7) + off >= 8) + /* Don't read src[0] if everything's in last_src. */ + src_val = last_src >> (8 - off); + else + src_val = get_src_byte_rev_1( src, off, &last_src ); + mask = edge_masks_1[dst_x & 7]; + do_rop_codes_mask_8( dst, src_val, codes, mask ); } } @@ -526,7 +769,6 @@ static void solid_rects_1(const dib_info *dib, int num, const RECT *rc, DWORD an int x, y, i; BYTE byte_and = (and & 1) ? 0xff : 0; BYTE byte_xor = (xor & 1) ? 0xff : 0; - static const BYTE masks[8] = {0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01}; for(i = 0; i < num; i++, rc++) { @@ -539,7 +781,7 @@ static void solid_rects_1(const dib_info *dib, int num, const RECT *rc, DWORD an if ((left & ~7) == (right & ~7)) /* Special case for lines that start and end in the same byte */ { - BYTE mask = masks[left & 7] & ~masks[right & 7]; + BYTE mask = edge_masks_1[left & 7] & ~edge_masks_1[right & 7]; for(y = rc->top; y < rc->bottom; y++, start += dib->stride) { @@ -553,14 +795,14 @@ static void solid_rects_1(const dib_info *dib, int num, const RECT *rc, DWORD an ptr = start; if(left & 7) - do_rop_8(ptr++, byte_and | ~masks[left & 7], byte_xor & masks[left & 7]); + do_rop_8(ptr++, byte_and | ~edge_masks_1[left & 7], byte_xor & edge_masks_1[left & 7]); for(x = (left + 7) & ~7; x < (right & ~7); x += 8) do_rop_8(ptr++, byte_and, byte_xor); if(right & 7) /* this is inverted wrt start mask */ - do_rop_8(ptr, byte_and | masks[right & 7], byte_xor & ~masks[right & 7]); + do_rop_8(ptr, byte_and | edge_masks_1[right & 7], byte_xor & ~edge_masks_1[right & 7]); } } else @@ -572,12 +814,12 @@ static void solid_rects_1(const dib_info *dib, int num, const RECT *rc, DWORD an ptr = start; if(left & 7) - do_rop_8(ptr++, ~masks[left & 7], byte_xor & masks[left & 7]); + do_rop_8(ptr++, ~edge_masks_1[left & 7], byte_xor & edge_masks_1[left & 7]); memset( ptr, byte_xor, byte_len ); if(right & 7) - do_rop_8(ptr + byte_len, masks[right & 7], byte_xor & ~masks[right & 7]); + do_rop_8(ptr + byte_len, edge_masks_1[right & 7], byte_xor & ~edge_masks_1[right & 7]); } } } @@ -1585,9 +1827,9 @@ static void copy_rect_1(const dib_info *dst, const RECT *rc, for (y = rc->top; y < rc->bottom; y++, dst_start += dst_stride, src_start += src_stride) { if (overlap & OVERLAP_RIGHT) - do_rop_codes_line_rev_1( dst_start, left & 7, src_start, org_x & 7, &codes, right - left ); + do_rop_codes_line_rev_1( dst_start, left & 7, src_start, org_x & 7, &codes, right - left, rop2 ); else - do_rop_codes_line_1( dst_start, left & 7, src_start, org_x & 7, &codes, right - left ); + do_rop_codes_line_1( dst_start, left & 7, src_start, org_x & 7, &codes, right - left, rop2 ); } } diff --git a/dlls/gdi32/tests/dib.c b/dlls/gdi32/tests/dib.c index d1ebd3ddf6e..b59c0dd2f74 100644 --- a/dlls/gdi32/tests/dib.c +++ b/dlls/gdi32/tests/dib.c @@ -116,7 +116,7 @@ static const char *sha1_graphics_a8r8g8b8[] = "94645300d6eb51020a7ef8261dee2941cd51b5df", "c56f5bdc9cac4f0bc81c33295d9aed8eaf4cb1f2", "21cdfde38ac7edbb241ec83d82f31286e90c4629", - "1fd2f4dcb62f8522171872e43fd4a35041d68100", + "0e6fc62522b0d6d2019f826ac0b586b91bd0d4fe", "68c18db6abfda626cab12d198298d4c39264bfbc", "6b59ae6c20749020ad43175e05110dc33b6a59b5", "39c31de73aafcfcadf0bf414da4495be9de54417", @@ -189,7 +189,7 @@ static const char *sha1_graphics_a8r8g8b8_bitfields[] = "94645300d6eb51020a7ef8261dee2941cd51b5df", "c56f5bdc9cac4f0bc81c33295d9aed8eaf4cb1f2", "21cdfde38ac7edbb241ec83d82f31286e90c4629", - "1fd2f4dcb62f8522171872e43fd4a35041d68100", + "0e6fc62522b0d6d2019f826ac0b586b91bd0d4fe", "68c18db6abfda626cab12d198298d4c39264bfbc", "6b59ae6c20749020ad43175e05110dc33b6a59b5", "39c31de73aafcfcadf0bf414da4495be9de54417", @@ -262,7 +262,7 @@ static const char *sha1_graphics_a8b8g8r8[] = "19b32a0daa91201725b5e13820c343d0a84ff698", "abca6a80a99b05722d2d87ce2a8b94ef1ae549e1", "2ba70994d0b4ce87fdf6fbc33ada11252178061e", - "7b4e1d47a03e2cec236d8fb6e2ae89d8ed078f79", + "9b81ccc2d956d1de019085f971ba19435fe5feae", "075c4cb50e2cf96ab5d132c9f7bb1c1deb4735bd", "8566c1110ab5cb8f754787b47923c8bff38f790c", "89e90d6159d59886bbbf0c40a7cd01293c3cfda3", @@ -335,7 +335,7 @@ static const char *sha1_graphics_r10g10b10[] = "5f629ab51719dd0ca5a67d880eb2631f5b598a7b", "1ceb85697f649a62b1753438daa14944af7f450c", "98ce4dbc04eb48fa0f96ef813db5b4dfa1b2dd39", - "3addb9ccd8f56fc0825f61b1b5af67d3297f4ded", + "1cb0c7d9d89cdbce7b47d19ef0365bb6b2adc831", "f00bac7e18827cfb264fae2e8a0da17b9db18d52", "63c1c6c63e82f3b8bd977a1381b248e05321394d", "ada202d2f526f6995f83412479891c1764b66e5a", @@ -408,7 +408,7 @@ static const char *sha1_graphics_r6g6b6[] = "3d27002f4fe3c943468b7e3ef6985962c41ac8dc", "3231c4d87faefb7ec5bd377613969c05b70343fc", "00394e438e9edde978e88602c9ad2a572e965bf6", - "e760be69cb37c7be35d5968d7a294e1fd49d4f66", + "c0c41390270ba082ee8211576fee39c676813c42", "996fb708ddc4b94eb8d1585bd83a5c8a1e2633ba", "caa39eb482e8fc2e00f1c6737735c023ac9363ef", "c1250ff2b67e6d2a8baccc5c93f8f5ad933c5c4f", @@ -481,7 +481,7 @@ static const char *sha1_graphics_24[] = "b0a959745b2db1d9f449e68e4479a4f36301879c", "63f764b9bd2f4876ab1ee0f3c0eb55b5a7de5212", "e171f6ec77bca91d6b8559911bce296c0bac469e", - "9725669042ef68acb408404d196496d10340bb5a", + "33bb75c12f083d799d287fe9caddedbb3892e6fa", "26e7e1c300ba0c5aaaef03eeb71d529f6def9289", "b1f602d2a74095cc0115ae2ae07b642498e6c0fc", "03d5eb8e3a6662e6dc183f88ee2f285065fc9c51", @@ -553,7 +553,7 @@ static const char *sha1_graphics_r5g5b5[] = "a8d6a5285a927ba3a3be34b06a06c70a20d4c1b3", "e428d213ad02651287894f093413949dcb369208", "7df915bedcc5951a1b6f828490f7dbb93212e835", - "645dc251d205139282b17eb7bece1055fff3bcd0", + "8720478d904a84c24071e97c731c1ba7882b131e", "76215275593631f5900aad3616d725733dc39493", "81655a550703849a616d4a16504bb9c6f999285f", "573d65665d20f00d36d9782ae2b89772140524ab", @@ -630,7 +630,7 @@ static const char *sha1_graphics_r4g4b4[] = "957a86fbe8a96dd068db65e4e624a52bcc84af46", "13b0f240054dc57ba0e2dfde74048496304a2c7f", "51ef267eb9c15487c9430f505e8a6c929eb2170c", - "1b593d8e031d3b37fecf6f1df5a8f96c8e8bfef8", + "60c0752f592c6426a2f4a71173b44c5c086f4f2a", "9dd123938b0a02601d8d458ecbd6535ddefea724", "815a1e4fc7f3a00c2990c150e87eba0b13f66811", "75ae8c80af4356a1a5eebde6608fbc31e8a95372", @@ -702,7 +702,7 @@ static const char *sha1_graphics_8_color[] = "3b7488731da48635d86be551ab7c8c0f91c78219", "4fd49cb49853ef950fd0b7e2e35718a71c8374c7", "e15a355fc09bfd22267917898e2266168ff410e3", - "b9688566bddf18586787c00e68724e51e97dfb72", + "7a9c326a56a94621377a7258be70ba50042ca9a2", "5e38e03310f1c66f2052af2a745d8c60515707c5", "f994fb5019bf4c1a96eccf89af599eae0aa6b412", "3a71ad6fef147067641e49a5f69b2454e3a5010d", @@ -784,7 +784,7 @@ static const char *sha1_graphics_8_grayscale[] = "24caede65b40815a60b83c4edfa06bdc542388cd", "650a51bedd1af92469d2950eb95220db35f95c6e", "3f43aa11e6fccb747cc13224583fb2f951fee08c", - "04cea9753b575ecce8e55357eddfcec10ddfbbea", + "b83f78ae85df87fc7af565db276c60c102274f20", "6b6f4b97f05e015eb37a5f6aff637235feacd030", "1bd06e4e11929e5e91c3c9f20def639b20e731e8", "d63a6086547e90d2ba84aaebfeae24f3ba0c04f1", @@ -863,7 +863,7 @@ static const char *sha1_graphics_8[] = "ea39ac62ca2f815a1d029340c6465994b6f03cb0", "9a603513cd81acf70cf8b27b0d544e7f672e9d40", "f4a334e69535de74ee5ed54be93a75120a66e54a", - "559fd1d15447745527c61fe43a94c6708bff3e39", + "f751a55fb738b63b6fd7c229c33ef92605d0c9c1", "995f77f2f53398399f09d1365cb4dfd105764e5c", "61907a6685bba93077da40cfb28cf2ab74552fd2", "122015e5e17c1c317c6e51c0e207826b606a4077", @@ -939,7 +939,7 @@ static const char *sha1_graphics_4[] = "b672afbeeafb44194a821f0def81a8892872937e", "db0124045882b598feea192186cf7eb7a0387866", "602d91471378fe24a2d0248bd8a92b624f099fea", - "e772873b87a0f55ea51a3da323f64bf8814c6703", + "c93a86adfe58dc2d461f2ed962883d6b90888848", "21aa1ff238a2d78efed1aa658ac8fe21b1e64daa", "1a579cd280422131c35e907a023ee0e80749b5a4", "bbf027f506cbb80d359bf4892fcb75f816f2e446", @@ -1011,7 +1011,7 @@ static const char *sha1_graphics_4_grayscale[] = "9c0da52c4ceaa8fdfcff7351328dd520bb57e985", "f8224430462f6a93f85ef33b8aa7299525990708", "1cf93cecc942b41ab8fae21ea18418a6d64873e5", - "d58b8760ef01c12e691651c932d683c66fde3654", + "71a1705ee14068ee8c6c6680c1bd99703fb6abd7", "94438c82b8812fe81a69d5d1429c5967cdbfed7a", "764ea26f10fe11f7bdb538a26fc33d44b3a95d6d", "94ad53c578f6034dfc5c666e363203cdfb00f2cc", @@ -1101,7 +1101,7 @@ static const char *sha1_graphics_1[] = "be36cda370650e6d5fb0570aeb8ced491d0c2b1c", "4c34cb8e47f9ff4b4348aa2d40cce7cb54d65cb0", "18f4497e43903e8df5b27da4ceebf62b15550a87", - "3fa3570a2ebd38042b90f24bd3496233bca5a23d", + "399e988c922b7fad1c8f6907541c5dda65e60408", "2fcd25c2d19a01fa631fd19135d9f28b26b86259", "655cfadeb157233c804d42b58195569c8846e3c1", "65c8811c609203fd424f5ed5f92ca2268a1dca54", @@ -1175,7 +1175,7 @@ static const RECT graphics_bounds[] = { 10, 10, 110, 110 }, { 10, 10, 120, 110 }, { 10, 10, 110, 120 }, - { 100, 100, 356, 356 }, + { 0, 4, 356, 356 }, { 100, 100, 356, 356 }, { 50, 50, 306, 306 }, { 100, 100, 356, 356 }, @@ -2181,6 +2181,18 @@ static void draw_graphics(HDC hdc, const BITMAPINFO *bmi, BYTE *bits) } BitBlt( hdc, 100, 100, 256, 256, src_dc, 0, 0, SRCCOPY ); + + /* Interesting cases for 1-bpp dst */ + BitBlt( hdc, 1, 4, 2, 2, src_dc, 0, 0, SRCCOPY ); + BitBlt( hdc, 1, 8, 16, 2, src_dc, 0, 0, SRCCOPY ); + BitBlt( hdc, 1, 12, 15, 2, src_dc, 0, 0, SRCCOPY ); + BitBlt( hdc, 0, 16, 8, 2, src_dc, 0, 0, SRCCOPY ); + BitBlt( hdc, 0, 20, 9, 2, src_dc, 0, 0, SRCCOPY ); + BitBlt( hdc, 7, 24, 1, 2, src_dc, 0, 0, SRCCOPY ); + BitBlt( hdc, 7, 28, 2, 2, src_dc, 0, 0, SRCCOPY ); + BitBlt( hdc, 7, 32, 9, 2, src_dc, 0, 0, SRCCOPY ); + BitBlt( hdc, 7, 36, 10, 2, src_dc, 0, 0, SRCCOPY ); + if (bmi->bmiHeader.biBitCount == 8) /* broken on NT4 */ compare_hash_broken_todo(hdc, bmi, bits, "BitBlt src 32-bpp SRCCOPY", 1, FALSE ); else