From eabf38aa3184e26ebe5be334802ddd452d54591b Mon Sep 17 00:00:00 2001 From: Oliver Saal Date: Wed, 22 Feb 2017 06:12:00 -0800 Subject: [PATCH 1/8] Remove Xib2Nib logic that declares UIRoundedRectButton as a separate class (#2018) --- bin/xib2nib.exe | 2 +- tools/vsimporter/xib2nib/UIButton.cpp | 21 +++------------------ 2 files changed, 4 insertions(+), 19 deletions(-) diff --git a/bin/xib2nib.exe b/bin/xib2nib.exe index c21fb0824b..d2bd73783a 100644 --- a/bin/xib2nib.exe +++ b/bin/xib2nib.exe @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:28d70329d20caa244f44b4d974e6e862cc86ff3ae5ed6e32e945c8fbcf5d3234 +oid sha256:7f09eeb3a798ddb23720e7c368ada2afc9794e371f2acdf5b64331cb629a8fb4 size 294912 diff --git a/tools/vsimporter/xib2nib/UIButton.cpp b/tools/vsimporter/xib2nib/UIButton.cpp index 9533f8914f..1961316166 100644 --- a/tools/vsimporter/xib2nib/UIButton.cpp +++ b/tools/vsimporter/xib2nib/UIButton.cpp @@ -235,15 +235,7 @@ void UIButton::InitFromXIB(XIBObject* obj) { if (!_font) _font = (UIFont*)obj->FindMember("IBUIFont"); - switch (_buttonType) { - case 1: - obj->_outputClassName = "UIRoundedRectButton"; - break; - - default: - obj->_outputClassName = "UIButton"; - break; - } + obj->_outputClassName = "UIButton"; } void UIButton::InitFromStory(XIBObject* obj) { @@ -253,6 +245,7 @@ void UIButton::InitFromStory(XIBObject* obj) { if (type) { if (strcmp(type, "roundedRect") == 0) { getAttrAndHandle("buttonType"); + // TODO: Investigate why this value deviates from UIButtonType _buttonType = 1; } else { printf("Unknown button type <%s>\n", type); @@ -260,15 +253,7 @@ void UIButton::InitFromStory(XIBObject* obj) { } } - switch (_buttonType) { - case 1: - obj->_outputClassName = "UIRoundedRectButton"; - break; - - default: - obj->_outputClassName = "UIButton"; - break; - } + obj->_outputClassName = "UIButton"; } void UIButton::ConvertStaticMappings(NIBWriter* writer, XIBObject* obj) { From 808248d5d383083c04d59ac3fad41e8d6368ffa3 Mon Sep 17 00:00:00 2001 From: "Dustin L. Howett" Date: Thu, 26 Jan 2017 13:18:21 -0800 Subject: [PATCH 2/8] Allow a 0b stride bitmap context to calculate its own stride. This adds a few more failure cases for bad bitmap contexts, and changes format imputation in the CG<->WIC mapper. --- Frameworks/CoreGraphics/CGContext.mm | 13 +++++ Frameworks/CoreGraphics/CGImage.mm | 50 +++++++++++++------ Frameworks/include/CGImageInternal.h | 1 + .../CoreGraphics/CGBitmapContextTests.mm | 40 +++++++++++++++ 4 files changed, 89 insertions(+), 15 deletions(-) diff --git a/Frameworks/CoreGraphics/CGContext.mm b/Frameworks/CoreGraphics/CGContext.mm index 00a86e9254..54c81549a5 100644 --- a/Frameworks/CoreGraphics/CGContext.mm +++ b/Frameworks/CoreGraphics/CGContext.mm @@ -2935,7 +2935,20 @@ CGContextRef CGBitmapContextCreateWithData(void* data, RETURN_NULL_IF(!height); RETURN_NULL_IF(!colorSpace); + size_t imputedBitsPerPixel = _CGImageImputeBitsPerPixelFromFormat(colorSpace, bitsPerComponent, bitmapInfo); size_t bitsPerPixel = ((bytesPerRow / width) << 3); + size_t estimatedBytesPerRow = (imputedBitsPerPixel >> 3) * width; + + if (data && estimatedBytesPerRow > bytesPerRow) { + TraceError(TAG, L"Invalid data stride: a %ux%u %ubpp context requires at least a %u-byte stride (requested: %u bytes/row).", width, height, imputedBitsPerPixel, estimatedBytesPerRow, bytesPerRow); + return nullptr; + } + + if (!bytesPerRow) { // When data is not provided, we are allowed to use our estimates. + bitsPerPixel = imputedBitsPerPixel; + bytesPerRow = estimatedBytesPerRow; + } + WICPixelFormatGUID requestedPixelFormat; RETURN_NULL_IF_FAILED( _CGImageGetWICPixelFormatFromImageProperties(bitsPerComponent, bitsPerPixel, colorSpace, bitmapInfo, &requestedPixelFormat)); diff --git a/Frameworks/CoreGraphics/CGImage.mm b/Frameworks/CoreGraphics/CGImage.mm index 5d7099178d..7dd8a8705a 100644 --- a/Frameworks/CoreGraphics/CGImage.mm +++ b/Frameworks/CoreGraphics/CGImage.mm @@ -710,6 +710,36 @@ CGImageRef _CGImageLoadImageWithWICDecoder(REFGUID decoderCls, void* bytes, int return nil; } +size_t _CGImageImputeBitsPerPixelFromFormat(CGColorSpaceRef colorSpace, size_t bitsPerComponent, CGBitmapInfo bitmapInfo) { + unsigned int alphaInfo = bitmapInfo & kCGBitmapAlphaInfoMask; + unsigned int byteOrder = bitmapInfo & kCGBitmapByteOrderMask; + + // Try byte order first: The user can specify 32 or 16 directly. + switch (byteOrder) { + case kCGBitmapByteOrder32Little: + case kCGBitmapByteOrder32Big: + return 32; + case kCGBitmapByteOrder16Little: + case kCGBitmapByteOrder16Big: + return 16; + } + + // Otherwise, try to figure out how many components there are. + size_t nComponents = CGColorSpaceGetNumberOfComponents(colorSpace); + switch (alphaInfo) { + case kCGImageAlphaNoneSkipFirst: + case kCGImageAlphaPremultipliedFirst: + case kCGImageAlphaFirst: + case kCGImageAlphaNoneSkipLast: + case kCGImageAlphaPremultipliedLast: + case kCGImageAlphaLast: + nComponents += 1; + break; + } + + return (bitsPerComponent * nComponents); +} + // CG packed format key // |Color |bits/px|CGBitmapInfo | // |-------|-------|---------------| @@ -766,23 +796,13 @@ HRESULT _CGImageGetWICPixelFormatFromImageProperties( RETURN_HR_IF(E_POINTER, !pixelFormat); - CGColorSpaceModel colorSpaceModel = CGColorSpaceGetModel(colorSpace); - - unsigned int alphaInfo = bitmapInfo & kCGBitmapAlphaInfoMask; - unsigned int byteOrder = bitmapInfo & kCGBitmapByteOrderMask; - unsigned int formatImputedBpp = 0; - switch (byteOrder) { - case kCGBitmapByteOrder32Little: - case kCGBitmapByteOrder32Big: - formatImputedBpp = 32; - break; - case kCGBitmapByteOrder16Little: - case kCGBitmapByteOrder16Big: - formatImputedBpp = 16; - break; + size_t formatImputedBpp = _CGImageImputeBitsPerPixelFromFormat(colorSpace, bitsPerComponent, bitmapInfo); + if (bitsPerPixel == 0) { + bitsPerPixel = formatImputedBpp; } - if (formatImputedBpp == 0 || formatImputedBpp == bitsPerPixel) { + if (formatImputedBpp == bitsPerPixel) { + CGColorSpaceModel colorSpaceModel = CGColorSpaceGetModel(colorSpace); auto found = s_CGWICFormatMap.find(CG_FORMAT_KEY(colorSpaceModel, bitsPerPixel, bitmapInfo, 0)); if (found != s_CGWICFormatMap.end()) { *pixelFormat = found->second; diff --git a/Frameworks/include/CGImageInternal.h b/Frameworks/include/CGImageInternal.h index 14904841ec..c3775c1d92 100644 --- a/Frameworks/include/CGImageInternal.h +++ b/Frameworks/include/CGImageInternal.h @@ -192,6 +192,7 @@ COREGRAPHICS_EXPORT void* _CGImageGetRawBytes(CGImageRef image); // Obtain the associated DisplayTexture __declspec(dllexport) std::shared_ptr _CGImageGetDisplayTexture(CGImageRef image); +size_t _CGImageImputeBitsPerPixelFromFormat(CGColorSpaceRef colorSpace, size_t bitsPerComponent, CGBitmapInfo bitmapInfo); HRESULT _CGImageGetWICPixelFormatFromImageProperties(unsigned int bitsPerComponent, unsigned int bitsPerPixel, CGColorSpaceRef colorSpace, diff --git a/tests/unittests/CoreGraphics/CGBitmapContextTests.mm b/tests/unittests/CoreGraphics/CGBitmapContextTests.mm index f2dfb2ab58..b4d926a253 100644 --- a/tests/unittests/CoreGraphics/CGBitmapContextTests.mm +++ b/tests/unittests/CoreGraphics/CGBitmapContextTests.mm @@ -288,3 +288,43 @@ void _TestPixelFormat(const CGRect bounds, const CGBitmapInfo info, DWORD expect // clang-format on INSTANTIATE_TEST_CASE_P(CGBitmapContextFormat, BitmapFormats, ::testing::ValuesIn(bitmapFormatTestCases)); + +TEST(CGBitmapContext, BadStrides) { + uint32_t data = 0; + auto colorSpace = woc::MakeStrongCF(CGColorSpaceCreateDeviceRGB()); + + { + auto context = woc::MakeStrongCF(CGBitmapContextCreateWithData(&data, 1, 1, 8, 0, colorSpace, kCGImageAlphaLast, nullptr, nullptr)); + ASSERT_EQ(nullptr, context); + } + + { + auto context = woc::MakeStrongCF(CGBitmapContextCreateWithData(&data, 1, 1, 8, 1, colorSpace, kCGImageAlphaLast, nullptr, nullptr)); + ASSERT_EQ(nullptr, context); + } +} + +TEST(CGBitmapContext, MismatchedConfigurationValues) { + auto colorSpace = woc::MakeStrongCF(CGColorSpaceCreateDeviceRGB()); + + { + // Provided 1 byte per row, but using 3-component + alpha = 32bpp (4 byte/pixel) + auto context = woc::MakeStrongCF(CGBitmapContextCreateWithData(nullptr, 1, 1, 8, 1, colorSpace, kCGImageAlphaLast, nullptr, nullptr)); + ASSERT_EQ(nullptr, context); + } + + { + // Provided 2 bytes per row, requested 32bpp, but using 3-component no alpha = 24bpp (3 byte/pixel) + // Context imputes format to be 32, but provided values should not match. + auto context = woc::MakeStrongCF(CGBitmapContextCreateWithData(nullptr, 1, 1, 8, 2, colorSpace, kCGImageAlphaNone | kCGBitmapByteOrder32Big, nullptr, nullptr)); + ASSERT_EQ(nullptr, context); + } +} + +TEST(CGBitmapContext, ImputeStrideRGBA) { + auto colorSpace = woc::MakeStrongCF(CGColorSpaceCreateDeviceRGB()); + auto context = woc::MakeStrongCF(CGBitmapContextCreateWithData(nullptr, 1, 1, 8, 0, colorSpace, kCGImageAlphaPremultipliedLast, nullptr, nullptr)); + ASSERT_NE(nullptr, context); + EXPECT_EQ(32, CGBitmapContextGetBitsPerPixel(context)); + EXPECT_LE(4, CGBitmapContextGetBytesPerRow(context)); // 4 <= stride +} \ No newline at end of file From 8315b07e6f474a4f28f638f2f541b6869ee3fdca Mon Sep 17 00:00:00 2001 From: "Dustin L. Howett" Date: Tue, 21 Feb 2017 10:45:50 -0800 Subject: [PATCH 3/8] Update libobjc2 to f2e4c5a. Fixes Microsoft/WinObjC#1924. --- deps/3rdparty/libobjc2 | 2 +- deps/prebuilt/Universal Windows/ARM/Debug/libobjc2.dll | 4 ++-- deps/prebuilt/Universal Windows/ARM/Debug/libobjc2.lib | 2 +- deps/prebuilt/Universal Windows/ARM/Debug/libobjc2.pdb | 2 +- deps/prebuilt/Universal Windows/ARM/Release/libobjc2.dll | 4 ++-- deps/prebuilt/Universal Windows/ARM/Release/libobjc2.lib | 2 +- deps/prebuilt/Universal Windows/ARM/Release/libobjc2.pdb | 4 ++-- deps/prebuilt/Universal Windows/x86/Debug/libobjc2.dll | 4 ++-- deps/prebuilt/Universal Windows/x86/Debug/libobjc2.lib | 2 +- deps/prebuilt/Universal Windows/x86/Debug/libobjc2.pdb | 4 ++-- deps/prebuilt/Universal Windows/x86/Release/libobjc2.dll | 4 ++-- deps/prebuilt/Universal Windows/x86/Release/libobjc2.lib | 2 +- deps/prebuilt/Universal Windows/x86/Release/libobjc2.pdb | 4 ++-- 13 files changed, 20 insertions(+), 20 deletions(-) diff --git a/deps/3rdparty/libobjc2 b/deps/3rdparty/libobjc2 index 58a7fd2146..f2e4c5ac4b 160000 --- a/deps/3rdparty/libobjc2 +++ b/deps/3rdparty/libobjc2 @@ -1 +1 @@ -Subproject commit 58a7fd2146eaa7312bd315e9e74e45433198e91f +Subproject commit f2e4c5ac4b3ac17f413a38bbc7ee1242f9efd0f7 diff --git a/deps/prebuilt/Universal Windows/ARM/Debug/libobjc2.dll b/deps/prebuilt/Universal Windows/ARM/Debug/libobjc2.dll index 2a068a6947..049bd001ae 100644 --- a/deps/prebuilt/Universal Windows/ARM/Debug/libobjc2.dll +++ b/deps/prebuilt/Universal Windows/ARM/Debug/libobjc2.dll @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:65c36e0092ccc944908ae09b347f2ff0e41240ec9ce1e7d7242a875ac805e559 -size 248832 +oid sha256:391206167c5467a6733a5d202c0b823558b048ce7e85607b2dcf05ced98ba596 +size 249344 diff --git a/deps/prebuilt/Universal Windows/ARM/Debug/libobjc2.lib b/deps/prebuilt/Universal Windows/ARM/Debug/libobjc2.lib index 7c2f121b74..3e78f77810 100644 --- a/deps/prebuilt/Universal Windows/ARM/Debug/libobjc2.lib +++ b/deps/prebuilt/Universal Windows/ARM/Debug/libobjc2.lib @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:098d5ed6195c83543855ac6713f4d124d811447fc7b640ddb694822b03092d16 +oid sha256:e789d3530f7dbddc7910d341b8c5ccece64e2c1238bf25e75b115a13a38a8bd1 size 41870 diff --git a/deps/prebuilt/Universal Windows/ARM/Debug/libobjc2.pdb b/deps/prebuilt/Universal Windows/ARM/Debug/libobjc2.pdb index bc25d63192..bda540cdd2 100644 --- a/deps/prebuilt/Universal Windows/ARM/Debug/libobjc2.pdb +++ b/deps/prebuilt/Universal Windows/ARM/Debug/libobjc2.pdb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e9ae3dd6b8ec1a49830c44459884a8a7d49659fbf1d2e089d26bc06e829f4f3b +oid sha256:67a3a21ec9999efa5b697872de546d5ed12b454925750ee74f6f9f1379be00f4 size 1298432 diff --git a/deps/prebuilt/Universal Windows/ARM/Release/libobjc2.dll b/deps/prebuilt/Universal Windows/ARM/Release/libobjc2.dll index 8353533176..0c0cf8d5c5 100644 --- a/deps/prebuilt/Universal Windows/ARM/Release/libobjc2.dll +++ b/deps/prebuilt/Universal Windows/ARM/Release/libobjc2.dll @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8224c56d91159a872f61b4abea02c575c284583cdf64580fcf0e455bf645bd46 -size 93696 +oid sha256:c81a0cf4e8df174e4924d88d2d81f9a8097369968e73696e19c6e3d138d949b4 +size 94720 diff --git a/deps/prebuilt/Universal Windows/ARM/Release/libobjc2.lib b/deps/prebuilt/Universal Windows/ARM/Release/libobjc2.lib index f8e608260b..ae1fd5e175 100644 --- a/deps/prebuilt/Universal Windows/ARM/Release/libobjc2.lib +++ b/deps/prebuilt/Universal Windows/ARM/Release/libobjc2.lib @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9598aaedf5440bd6baa25a125a465ae9d043d1b8d7d74be3bad168736e24ffd4 +oid sha256:607b82720857e5fd36abdaad58ddd276a2dc444ffc2448d99fd5614193c1709c size 41870 diff --git a/deps/prebuilt/Universal Windows/ARM/Release/libobjc2.pdb b/deps/prebuilt/Universal Windows/ARM/Release/libobjc2.pdb index 378d82d708..a1cca7c8fa 100644 --- a/deps/prebuilt/Universal Windows/ARM/Release/libobjc2.pdb +++ b/deps/prebuilt/Universal Windows/ARM/Release/libobjc2.pdb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:51759bf5b71d0794c21fbb5a32bf0c9d9f35a9a45a873731d637fc93c65bf183 -size 1044480 +oid sha256:37ec205af083d520460c97225dd210b63646b5f6566224bb55ad68fcc2cf6932 +size 1052672 diff --git a/deps/prebuilt/Universal Windows/x86/Debug/libobjc2.dll b/deps/prebuilt/Universal Windows/x86/Debug/libobjc2.dll index 0e256ae6e2..22b73b3d61 100644 --- a/deps/prebuilt/Universal Windows/x86/Debug/libobjc2.dll +++ b/deps/prebuilt/Universal Windows/x86/Debug/libobjc2.dll @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6421fdba5cf80654ffc7731a8d954705283f75f6725629e6156c691d95f7dce6 -size 190976 +oid sha256:aa2db996f6874880f747b256f9e3270c3fc927b25292adfb0a95877d5b8d24fe +size 191488 diff --git a/deps/prebuilt/Universal Windows/x86/Debug/libobjc2.lib b/deps/prebuilt/Universal Windows/x86/Debug/libobjc2.lib index 3a92b02776..535ce1a80e 100644 --- a/deps/prebuilt/Universal Windows/x86/Debug/libobjc2.lib +++ b/deps/prebuilt/Universal Windows/x86/Debug/libobjc2.lib @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d8fa0e7e9e6e66a4e434f78ae22a9a7dac0d33eb58af446319125abc007cb46d +oid sha256:666127145866ad705a6c227b51a3caac0c2e665da6592d441e5609d0d4ed70c4 size 42758 diff --git a/deps/prebuilt/Universal Windows/x86/Debug/libobjc2.pdb b/deps/prebuilt/Universal Windows/x86/Debug/libobjc2.pdb index 3fd1b4a4f2..cb09f238f1 100644 --- a/deps/prebuilt/Universal Windows/x86/Debug/libobjc2.pdb +++ b/deps/prebuilt/Universal Windows/x86/Debug/libobjc2.pdb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e37f75aa55d70f3f6181a7cbd83fd9fd3c5ff60ffe93e16be153d8a1880f4ea7 -size 1265664 +oid sha256:57768f07f31b60a64f9f971d13448206970c6f65bbb542227bb5f3f67aaac51d +size 1273856 diff --git a/deps/prebuilt/Universal Windows/x86/Release/libobjc2.dll b/deps/prebuilt/Universal Windows/x86/Release/libobjc2.dll index 35d89d042b..4f98cd1d7c 100644 --- a/deps/prebuilt/Universal Windows/x86/Release/libobjc2.dll +++ b/deps/prebuilt/Universal Windows/x86/Release/libobjc2.dll @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:92bcb3e5ac22e343b70fa4e831c2be29d1b63e320850601d3669d45cb731f113 -size 95232 +oid sha256:d4139631fa7fdcb8637d5506aa83682ec126faf247d084f66e730e6d4d16115c +size 95744 diff --git a/deps/prebuilt/Universal Windows/x86/Release/libobjc2.lib b/deps/prebuilt/Universal Windows/x86/Release/libobjc2.lib index 6251b92f53..52eb0506bb 100644 --- a/deps/prebuilt/Universal Windows/x86/Release/libobjc2.lib +++ b/deps/prebuilt/Universal Windows/x86/Release/libobjc2.lib @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:07521ec4bd28240555617d74e64823e65390cae53c0b64ef02fc52ee6c164509 +oid sha256:91a529ac5b0cbaca86afb45e08d92cafe3e2d3c7b964c86dcd342b923f341714 size 42758 diff --git a/deps/prebuilt/Universal Windows/x86/Release/libobjc2.pdb b/deps/prebuilt/Universal Windows/x86/Release/libobjc2.pdb index ba2b8e9a3c..f7792adae8 100644 --- a/deps/prebuilt/Universal Windows/x86/Release/libobjc2.pdb +++ b/deps/prebuilt/Universal Windows/x86/Release/libobjc2.pdb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:53f4006dcdb77626bf681a22152052f0ceaeb276b9b970b7b23189c65fb9728d -size 1077248 +oid sha256:ea441a2df50b59b25101feae366c60c0811a408815ac477f27e6f4acd092862e +size 1085440 From e56b77135f461dc54c383a44a1675701c1fee7f9 Mon Sep 17 00:00:00 2001 From: Jared Date: Mon, 27 Feb 2017 08:52:24 -0800 Subject: [PATCH 4/8] Protecting UIButton's CGSize calculations against nil receivers; more fallout from #1965 and #1365. Fixes #2066. (#2094) --- Frameworks/AutoLayout/AutoLayout.mm | 18 ++++-- Frameworks/UIKit/UIButton.mm | 97 +++++++++++++++++++---------- 2 files changed, 75 insertions(+), 40 deletions(-) diff --git a/Frameworks/AutoLayout/AutoLayout.mm b/Frameworks/AutoLayout/AutoLayout.mm index 642988114f..568fbb4b4e 100644 --- a/Frameworks/AutoLayout/AutoLayout.mm +++ b/Frameworks/AutoLayout/AutoLayout.mm @@ -473,10 +473,10 @@ - (BOOL)autoLayoutInvalidateContentSize { if (CGSizeEqualToSize(layoutProperties->_intrinsicContentSize, newContentSize)) { if (DEBUG_AUTO_LAYOUT_LIGHT) { TraceVerbose(TAG, L"autoLayoutInvalidateContentSize: Size {%f, %f} didn't change; no need to revalidate constraints; no need to re-layout %hs(0x%p).", - object_getClassName(self), - self, newContentSize.width, - newContentSize.height); + newContentSize.height, + object_getClassName(self), + self); } // No more work left to be done; the size didn't actually change. @@ -484,12 +484,12 @@ - (BOOL)autoLayoutInvalidateContentSize { } else { if (DEBUG_AUTO_LAYOUT_LIGHT) { TraceVerbose(TAG, L"autoLayoutInvalidateContentSize: intrinsicContentSize changed from {%f, %f} to {%f, %f}; need to revalidate constraints and re-layout %hs(0x%p).", - object_getClassName(self), - self, newContentSize.width, newContentSize.height, layoutProperties->_intrinsicContentSize.width, - layoutProperties->_intrinsicContentSize.height); + layoutProperties->_intrinsicContentSize.height, + object_getClassName(self), + self); } // Store the new intrinsicContentSize @@ -611,6 +611,12 @@ - (UIView*)autolayoutRoot { - (void)autoLayoutUpdateConstraints { AutoLayoutProperties* layoutProperties = self._autoLayoutProperties; + if (DEBUG_AUTO_LAYOUT_LIGHT) { + TraceVerbose(TAG, L"autoLayoutUpdateConstraints: %hs(0x%p).", + object_getClassName(self), + self); + } + if (![layoutProperties->_associatedConstraints count]) { return; } diff --git a/Frameworks/UIKit/UIButton.mm b/Frameworks/UIKit/UIButton.mm index f1dd269537..5e6b8d05c0 100644 --- a/Frameworks/UIKit/UIButton.mm +++ b/Frameworks/UIKit/UIButton.mm @@ -371,21 +371,32 @@ - (CGRect)contentRectForBounds:(CGRect)bounds { @Status Interoperable */ - (CGRect)imageRectForContentRect:(CGRect)contentRect { - CGSize titleSize = [self.currentTitle sizeWithFont:self.font]; - // TODO #1365 :: Currently cannot assume getting size from nil will return CGSizeZero - CGSize imageSize = CGSizeZero; - CGRect insetsRect = UIEdgeInsetsInsetRect(contentRect, self.imageEdgeInsets); - - if (!self.currentImage) { + ///////////////////////////////////////////////////////////////////// + // Note: #1365 All size calculations here must check for nil, + // as we cannot assume getting a size from nil will return CGSizeZero + ///////////////////////////////////////////////////////////////////// + UIImage* currentImage = self.currentImage; + if (!currentImage) { + // No image, so we return zero for the entire content rect return CGRectZero; } - imageSize = self.currentImage.size; + // Grab the size of the current title + // TODO: Should we be asking our label for this? + NSString* currentTitle = self.currentTitle; + CGSize titleSize = CGSizeZero; + if (currentTitle) { + // We need to round the font size to the nearest pixel value to avoid rounding errors when used in conjunction with the + // frame values that are rounded by UIView. + titleSize = doPixelRound([currentTitle sizeWithFont:self.font]); + } - CGSize totalSize = imageSize; + // Now calculate the total size based on the image and title sizes + CGSize totalSize = currentImage.size; totalSize.width += titleSize.width; // Get the frame based on the control alignment. + CGRect insetsRect = UIEdgeInsetsInsetRect(contentRect, self.imageEdgeInsets); CGRect ret = calculateContentRect(self, totalSize, insetsRect); ret.size.width -= titleSize.width; @@ -404,19 +415,34 @@ - (CGRect)imageRectForContentRect:(CGRect)contentRect { @Status Interoperable */ - (CGRect)titleRectForContentRect:(CGRect)contentRect { - // TODO: Should we be asking our label for its intrinsicContentSize? - // We need to round the font size to the nearest pixel value to avoid rounding errors when used in conjunction with the - // frame values that are rounded by UIView. - CGSize titleSize = doPixelRound([self.currentTitle sizeWithFont:self.font]); - CGSize totalSize = titleSize; - // TODO #1365 :: Currently cannot assume getting size from nil will return CGSizeZero - CGSize imageSize = self.currentImage ? [self.currentImage size] : CGSizeZero; - CGRect insetsRect = UIEdgeInsetsInsetRect(contentRect, self.titleEdgeInsets); + ///////////////////////////////////////////////////////////////////// + // Note: #1365 All size calculations here must check for nil, + // as we cannot assume getting a size from nil will return CGSizeZero + ///////////////////////////////////////////////////////////////////// - if ([self currentTitle].length == 0) { + // Grab the size of the current title + // TODO: Should we be asking our label for this? + NSString* currentTitle = self.currentTitle; + CGSize titleSize = CGSizeZero; + if (currentTitle && currentTitle.length > 0) { + // We need to round the font size to the nearest pixel value to avoid rounding errors when used in conjunction with the + // frame values that are rounded by UIView. + titleSize = doPixelRound([currentTitle sizeWithFont:self.font]); + } else { + // No title, so we return zero for the entire content rect return CGRectZero; } + // Grab the size of the current image + UIImage* currentImage = self.currentImage; + CGSize imageSize = CGSizeZero; + if (currentImage) { + imageSize = [currentImage size]; + } + + CGRect insetsRect = UIEdgeInsetsInsetRect(contentRect, self.titleEdgeInsets); + + CGSize totalSize = titleSize; totalSize.width += imageSize.width; // Get the frame based on the control alignment. @@ -951,32 +977,35 @@ - (UIImageView*)imageView { - (CGSize)intrinsicContentSize { CGSize ret = CGSizeZero; - UIImage* img = self.currentImage; - UIEdgeInsets contentInsets = self.contentEdgeInsets; - - // TODO: Should we be asking our label for its intrinsicContentSize? - // We need to round the font size to the nearest pixel value to avoid rounding errors when used in conjunction with the - // frame values that are rounded by UIView. - CGSize textSize = doPixelRound([[self currentTitle] sizeWithFont:self.font]); + //////////////////////////////////////////////////////////////////// + // Note: #1365 All size calculations here must check for nil, + // as we cannot assume getting a size from nil will return CGSizeZero + //////////////////////////////////////////////////////////////////// // Size should at least fit the image in a normal state. - if (img != nil) { - ret = [img size]; + UIImage* currentImage = self.currentImage; + if (currentImage) { + ret = [currentImage size]; } - if ([self currentTitle].length) { + // TODO: Should we be asking our label for its intrinsicContentSize? + CGSize textSize = CGSizeZero; + NSString* currentTitle = self.currentTitle; + if (currentTitle && (currentTitle.length > 0)) { + // We need to round the font size to the nearest pixel value to avoid rounding errors when used in conjunction with the + // frame values that are rounded by UIView. + textSize = doPixelRound([currentTitle sizeWithFont:self.font]); ret.width = std::max(textSize.width, ret.width); ret.height = std::max(textSize.height, ret.height); } // If we have a background, its image size dictates the smallest size. - if (self.currentBackgroundImage) { - UIImage* background = self.currentBackgroundImage; - // TODO #1365 :: Currently cannot assume getting size from nil will return CGSizeZero - CGSize size = background ? [background size] : CGSizeZero; - - ret.width = std::max(size.width, ret.width); - ret.height = std::max(size.height, ret.height); + UIEdgeInsets contentInsets = self.contentEdgeInsets; + UIImage* currentBackgroundImage = self.currentBackgroundImage; + if (currentBackgroundImage) { + CGSize imageSize = [currentBackgroundImage size]; + ret.width = std::max(imageSize.width, ret.width); + ret.height = std::max(imageSize.height, ret.height); } else if (UIEdgeInsetsEqualToEdgeInsets(contentInsets, UIEdgeInsetsZero)) { // Min values found emperically; set if no contentInsets are set. ret.width = std::max(ret.width, 30.0f); From a01904f57252a9bd0edc06ffac042382b805aa83 Mon Sep 17 00:00:00 2001 From: "Dustin L. Howett (MSFT)" Date: Mon, 27 Feb 2017 00:08:25 -0800 Subject: [PATCH 5/8] Reintroduce support for the CGImage destruction listener. (#2099) Fixes #1928. Fixes #2096. Refs #2098. --- Frameworks/CoreGraphics/CGImage.mm | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Frameworks/CoreGraphics/CGImage.mm b/Frameworks/CoreGraphics/CGImage.mm index 7dd8a8705a..fd19f05fec 100644 --- a/Frameworks/CoreGraphics/CGImage.mm +++ b/Frameworks/CoreGraphics/CGImage.mm @@ -39,15 +39,13 @@ static const wchar_t* TAG = L"CGImage"; -// TODO #1124: remove old code -#pragma region OLD_CODE +// This is used by XamlCompositor to flush the DisplayTexture cache. +// TODO GH#2098 look at where we're using the image cache and what we can do to avoid it. static std::vector _imageDestructionListeners; COREGRAPHICS_EXPORT void CGImageAddDestructionListener(CGImageDestructionListener listener) { _imageDestructionListeners.push_back(listener); } -#pragma endregion OLD_CODE - #pragma region CGImageImplementation struct __CGImageImpl { @@ -225,6 +223,12 @@ inline WICPixelFormatGUID PixelFormat() const { _impl.renderingIntent = intent; return *this; } + + ~__CGImage() { + for (auto listener: _imageDestructionListeners) { + listener(this); + } + } }; #pragma endregion CGImageImplementation From 8afb177d6002bbe6c4494ee605fd3d9dd7c3b5ba Mon Sep 17 00:00:00 2001 From: Ram Date: Mon, 27 Feb 2017 22:25:48 -0800 Subject: [PATCH 6/8] GLKTexture load files without assuming it's PNG (#2106) * GLKTexture load files without assuming it's PNG * update others * intro of a new function * update name --- Frameworks/CoreGraphics/CGImage.mm | 13 ++++++++++--- Frameworks/GLKit/GLKTexture.mm | 11 +++++++---- Frameworks/include/CGImageInternal.h | 21 +++++++++++---------- build/CoreGraphics/dll/CoreGraphics.def | 1 + 4 files changed, 29 insertions(+), 17 deletions(-) diff --git a/Frameworks/CoreGraphics/CGImage.mm b/Frameworks/CoreGraphics/CGImage.mm index fd19f05fec..de409a0801 100644 --- a/Frameworks/CoreGraphics/CGImage.mm +++ b/Frameworks/CoreGraphics/CGImage.mm @@ -225,7 +225,7 @@ inline WICPixelFormatGUID PixelFormat() const { } ~__CGImage() { - for (auto listener: _imageDestructionListeners) { + for (auto listener : _imageDestructionListeners) { listener(this); } } @@ -366,7 +366,9 @@ CGDataProviderRef CGImageGetDataProvider(CGImageRef img) { RETURN_NULL_IF_FAILED(img->ImageSource()->CopyPixels(nullptr, stride, size, buffer.get())); CGDataProviderRef dataProvider = - CGDataProviderCreateWithData(nullptr, buffer.release(), size, [](void* info, const void* data, size_t size) { IwFree(const_cast(data)); }); + CGDataProviderCreateWithData(nullptr, buffer.release(), size, [](void* info, const void* data, size_t size) { + IwFree(const_cast(data)); + }); CFAutorelease(dataProvider); return dataProvider; } @@ -650,6 +652,12 @@ CGImageRef _CGImageCreateCopyWithPixelFormat(CGImageRef image, WICPixelFormatGUI return imageRef; } +CGImageRef _CGImageCreateFromDataProvider(CGDataProviderRef provider) { + RETURN_NULL_IF(!provider); + unsigned char* dataBytes = static_cast(const_cast(_CGDataProviderGetData(provider))); + return _CGImageGetImageFromData(dataBytes, _CGDataProviderGetSize(provider)); +} + CGImageRef _CGImageGetImageFromData(void* data, int length) { return _CGImageLoadImageWithWICDecoder(GUID_NULL, data, length); } @@ -753,7 +761,6 @@ size_t _CGImageImputeBitsPerPixelFromFormat(CGColorSpaceRef colorSpace, size_t b HRESULT _CGImageGetWICPixelFormatFromImageProperties( unsigned int bitsPerComponent, unsigned int bitsPerPixel, CGColorSpaceRef colorSpace, CGBitmapInfo bitmapInfo, GUID* pixelFormat) { - // clang-format off static std::map s_CGWICFormatMap{ { CG_FORMAT_KEY(kCGColorSpaceModelRGB , 24, kCGBitmapByteOrderDefault, kCGImageAlphaNone), GUID_WICPixelFormat24bppRGB }, diff --git a/Frameworks/GLKit/GLKTexture.mm b/Frameworks/GLKit/GLKTexture.mm index c92e4898eb..62ce46258f 100644 --- a/Frameworks/GLKit/GLKTexture.mm +++ b/Frameworks/GLKit/GLKTexture.mm @@ -1,6 +1,6 @@ //****************************************************************************** // -// Copyright (c) 2015 Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft. All rights reserved. // // This code is licensed under the MIT License (MIT). // @@ -25,6 +25,7 @@ #import #import #import "NSLogging.h" +#import "CGImageInternal.h" static const wchar_t* TAG = L"GLKTexture"; @@ -277,7 +278,7 @@ @implementation GLKTextureLoader { */ + (GLKTextureInfo*)textureWithContentsOfFile:(NSString*)fname options:(NSDictionary*)opts error:(NSError**)err { CGDataProviderRef provider = CGDataProviderCreateWithFilename([fname UTF8String]); - CGImageRef img = CGImageCreateWithPNGDataProvider(provider, NULL, NO, kCGRenderingIntentDefault); + CGImageRef img = _CGImageCreateFromDataProvider(provider); GLKTextureInfo* res = [self textureWithCGImage:img options:opts error:err]; @@ -395,7 +396,8 @@ + (GLKTextureInfo*)cubeMapWithContentsOfFile:(NSString*)fname options:(NSDiction if (!provider) { return nil; } - CGImageRef img = CGImageCreateWithPNGDataProvider(provider, NULL, NO, kCGRenderingIntentDefault); + + CGImageRef img = _CGImageCreateFromDataProvider(provider); if (!img) { CGDataProviderRelease(provider); return nil; @@ -541,7 +543,8 @@ + (GLKTextureInfo*)cubeMapWithContentsOfFiles:(NSArray*)fnames options:(NSDictio curSide++; continue; } - CGImageRef img = CGImageCreateWithPNGDataProvider(provider, NULL, NO, kCGRenderingIntentDefault); + + CGImageRef img = _CGImageCreateFromDataProvider(provider); if (!img) { CGDataProviderRelease(provider); NSTraceWarning(TAG, @"Unable to create image from cube side texture %@", fn); diff --git a/Frameworks/include/CGImageInternal.h b/Frameworks/include/CGImageInternal.h index c3775c1d92..1da3541734 100644 --- a/Frameworks/include/CGImageInternal.h +++ b/Frameworks/include/CGImageInternal.h @@ -49,11 +49,13 @@ struct GuidPixelLess : public std::binary_function { } }; -static const std::map s_ValidRenderTargetPixelFormat = { { GUID_WICPixelFormat8bppAlpha, 1 }, // A8 Straight - { GUID_WICPixelFormat32bppRGB, 1 }, // RGBX - { GUID_WICPixelFormat32bppPRGBA, 1 }, // RGBA Premultiplied - { GUID_WICPixelFormat32bppBGR, 1 }, // BGRX - { GUID_WICPixelFormat32bppPBGRA, 1 } }; // BGRX Premultiplied +static const std::map s_ValidRenderTargetPixelFormat = { { GUID_WICPixelFormat8bppAlpha, 1 }, // A8 Straight + { GUID_WICPixelFormat32bppRGB, 1 }, // RGBX + { GUID_WICPixelFormat32bppPRGBA, + 1 }, // RGBA Premultiplied + { GUID_WICPixelFormat32bppBGR, 1 }, // BGRX + { GUID_WICPixelFormat32bppPBGRA, + 1 } }; // BGRX Premultiplied static const std::map s_PixelFormats = { // RGB(A) formats @@ -189,15 +191,14 @@ COREGRAPHICS_EXPORT HRESULT _CGImageGetWICImageSource(CGImageRef image, IWICBitm // Obtain a direct pointer to the data. COREGRAPHICS_EXPORT void* _CGImageGetRawBytes(CGImageRef image); +COREGRAPHICS_EXPORT CGImageRef _CGImageCreateFromDataProvider(CGDataProviderRef provider); + // Obtain the associated DisplayTexture __declspec(dllexport) std::shared_ptr _CGImageGetDisplayTexture(CGImageRef image); size_t _CGImageImputeBitsPerPixelFromFormat(CGColorSpaceRef colorSpace, size_t bitsPerComponent, CGBitmapInfo bitmapInfo); -HRESULT _CGImageGetWICPixelFormatFromImageProperties(unsigned int bitsPerComponent, - unsigned int bitsPerPixel, - CGColorSpaceRef colorSpace, - CGBitmapInfo bitmapInfo, - GUID* pixelFormat); +HRESULT _CGImageGetWICPixelFormatFromImageProperties( + unsigned int bitsPerComponent, unsigned int bitsPerPixel, CGColorSpaceRef colorSpace, CGBitmapInfo bitmapInfo, GUID* pixelFormat); // If the image is of the same format, the image is retained and returned. COREGRAPHICS_EXPORT CGImageRef _CGImageCreateCopyWithPixelFormat(CGImageRef image, WICPixelFormatGUID pixelFormat); diff --git a/build/CoreGraphics/dll/CoreGraphics.def b/build/CoreGraphics/dll/CoreGraphics.def index 692b3e3622..9caae62c36 100644 --- a/build/CoreGraphics/dll/CoreGraphics.def +++ b/build/CoreGraphics/dll/CoreGraphics.def @@ -381,6 +381,7 @@ LIBRARY CoreGraphics ; CGImage private exports _CGImageLoadImageWithWICDecoder _CGImageGetImageFromData + _CGImageCreateFromDataProvider _CGImagePNGRepresentation _CGImageJPEGRepresentation _CGImageRepresentation From 2eaddf042922505a8195f4e832c7fa3b6be19461 Mon Sep 17 00:00:00 2001 From: Raj Seshasankaran Date: Tue, 28 Feb 2017 17:16:27 -0800 Subject: [PATCH 7/8] Updating build version for 1702 release.2 --- build/winobjc.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/winobjc.version b/build/winobjc.version index 303e175096..0f3b16da7a 100644 --- a/build/winobjc.version +++ b/build/winobjc.version @@ -1,4 +1,4 @@ # MAJOR.MINOR.BUILD.REVISION # BUILD = YYMM # REVISION = DD -0.2.1702.16 +0.2.1702.28 From ff8784c263d9a8a7aeeba080bfa1564216b4f1f0 Mon Sep 17 00:00:00 2001 From: "Dustin L. Howett (MSFT)" Date: Tue, 28 Feb 2017 20:11:14 -0800 Subject: [PATCH 8/8] Fix the rendering issues that were causing #2095. (#2117) * `-[CALayer renderInContext:]` has the ability to render a cached version of itself; it was doing so upside-down because it was using a Cairo implementation detail. * `-[UIImage drawAtPoint:]` squashed every image it rendered because it switched width & height. The bug in UIImage dates back to the Cairo implementation as well; the invalid size was passed to a function that ignored it. When our refactor made use of that parameter, things rapidly went south. We did not catch the second regression because all the images we drew with it were square. Fixes #2095. --- Frameworks/QuartzCore/CALayer.mm | 22 ++++++++++++++-------- Frameworks/UIKit/UIImage.mm | 4 ++-- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/Frameworks/QuartzCore/CALayer.mm b/Frameworks/QuartzCore/CALayer.mm index 5725d6d83d..022f95558e 100644 --- a/Frameworks/QuartzCore/CALayer.mm +++ b/Frameworks/QuartzCore/CALayer.mm @@ -427,14 +427,20 @@ - (void)renderInContext:(CGContextRef)ctx { [priv->delegate drawLayer:self inContext:ctx]; } } else { - CGRect rect; - - rect.origin.x = 0; - rect.origin.y = priv->bounds.size.height * priv->contentsScale; - rect.size.width = priv->bounds.size.width * priv->contentsScale; - rect.size.height = -priv->bounds.size.height * priv->contentsScale; - - _CGContextDrawImageRect(ctx, priv->contents, rect, destRect); + // If the layer has cached contents, blit them directly. + + // Since the layer was rendered in Quartz referential (ULO) AND the current context + // is assumed to be Quartz referential (ULO), BUT the layer's cached contents + // were captured in a CGImage (CGImage referential, LLO), we have to flip + // the context again before we render it. + + // |1 0 0| is the transformation matrix for flipping a rect anchored at 0,0 about its Y midpoint. + // |0 -1 0| + // |0 h 1| + CGContextSaveGState(ctx); + CGContextConcatCTM(ctx, CGAffineTransformMake(1, 0, 0, -1, 0, destRect.size.height)); + CGContextDrawImage(ctx, destRect, priv->contents); + CGContextRestoreGState(ctx); } // Draw sublayers diff --git a/Frameworks/UIKit/UIImage.mm b/Frameworks/UIKit/UIImage.mm index dcba1ef6b9..47a101277b 100644 --- a/Frameworks/UIKit/UIImage.mm +++ b/Frameworks/UIKit/UIImage.mm @@ -491,8 +491,8 @@ - (void)drawAtPoint:(CGPoint)point blendMode:(CGBlendMode)mode alpha:(float)alph CGRect pos; pos.origin = point; - pos.size.width = (img_height / _scale); - pos.size.height = (img_width / _scale); + pos.size.height = (img_height / _scale); + pos.size.width = (img_width / _scale); // |1 0 0| is the transformation matrix for flipping a rect about its Y midpoint m. (m = (y + h/2)) // |0 -1 0|