diff --git a/Frameworks/CoreGraphics/CGImage.mm b/Frameworks/CoreGraphics/CGImage.mm index 0eda5854bb..b410630789 100644 --- a/Frameworks/CoreGraphics/CGImage.mm +++ b/Frameworks/CoreGraphics/CGImage.mm @@ -358,10 +358,10 @@ CGDataProviderRef CGImageGetDataProvider(CGImageRef img) { RETURN_NULL_IF_FAILED(img->ImageSource()->CopyPixels(nullptr, stride, size, buffer.get())); - woc::unique_cf data{ CFDataCreateWithBytesNoCopy(nullptr, buffer.release(), size, kCFAllocatorDefault) }; - CGDataProviderRef ret = CGDataProviderCreateWithCFData(data.get()); - CFAutorelease(ret); - return ret; + CGDataProviderRef dataProvider = + CGDataProviderCreateWithData(nullptr, buffer.release(), size, [](void* info, const void* data, size_t size) { IwFree(const_cast(data)); }); + CFAutorelease(dataProvider); + return dataProvider; } /** @@ -533,13 +533,8 @@ CGImageRef CGImageCreateWithMask(CGImageRef image, CGImageRef mask) { size_t width = CGImageGetWidth(image); size_t height = CGImageGetHeight(image); - woc::unique_cf context{ CGBitmapContextCreate(nullptr, - width, - height, - 8, - width * 4, - CGImageGetColorSpace(image), - kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Big) }; + woc::unique_cf context{ CGBitmapContextCreate( + nullptr, width, height, 8, width * 4, CGImageGetColorSpace(image), kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Big) }; RETURN_NULL_IF(!context); CGRect rect{ @@ -809,14 +804,14 @@ static void __InvertMemcpy(void* dest, const void* src, size_t len) { uint32_t* d32 = (uint32_t*)dest; const uint32_t* s32 = (const uint32_t*)src; - for(; len >= 4; len -= 4) { + for (; len >= 4; len -= 4) { *d32++ = ~*s32++; } uint8_t* d8 = (uint8_t*)d32; const uint8_t* s8 = (const uint8_t*)s32; - for(; len > 0; --len) { + for (; len > 0; --len) { *d8++ = ~*s8++; } } @@ -873,9 +868,7 @@ static HRESULT __CGImageMaskConvertToWICAlphaBitmap(CGImageRef image, IWICBitmap } else { // stride or length (likely both) differ uint8_t* destEnd = alpha8Data + alpha8Len; - for(uint8_t *src = gray8Data, *dest = alpha8Data; - dest < destEnd; - src += gray8Stride, dest += alpha8Stride) { + for (uint8_t *src = gray8Data, *dest = alpha8Data; dest < destEnd; src += gray8Stride, dest += alpha8Stride) { __InvertMemcpy(dest, src, gray8Stride); } } diff --git a/Frameworks/CoreText/CTFramesetter.mm b/Frameworks/CoreText/CTFramesetter.mm index d2527b409d..ff348b1550 100644 --- a/Frameworks/CoreText/CTFramesetter.mm +++ b/Frameworks/CoreText/CTFramesetter.mm @@ -21,13 +21,26 @@ #import "CGPathInternal.h" #import "DWriteWrapper_CoreText.h" -using namespace std; - @implementation _CTFramesetter : NSObject @end -static _CTFrame* __CreateFrame(_CTFramesetter* framesetter, CGRect frameRect, CFRange range) { - RETURN_NULL_IF(framesetter == nil); +/** + @Status Interoperable +*/ +CTFramesetterRef CTFramesetterCreateWithAttributedString(CFAttributedStringRef string) { + _CTFramesetter* ret = [_CTFramesetter alloc]; + ret->_typesetter = static_cast<_CTTypesetter*>(CTTypesetterCreateWithAttributedString(string)); + return static_cast(ret); +} + +/** + @Status Caveat + @Notes frameAttributes parameter ignored +*/ +CTFrameRef CTFramesetterCreateFrame(CTFramesetterRef framesetterRef, CFRange range, CGPathRef path, CFDictionaryRef frameAttributes) { + RETURN_NULL_IF(framesetterRef == nil || path == nullptr); + CGRect frameRect = CGPathGetBoundingBox(path); + _CTFramesetter* framesetter = static_cast<_CTFramesetter*>(framesetterRef); // Call _DWriteWrapper to get _CTLine object list that makes up this frame _CTTypesetter* typesetter = static_cast<_CTTypesetter*>(framesetter->_typesetter); @@ -36,10 +49,12 @@ @implementation _CTFramesetter : NSObject } StrongId<_CTFrame> ret = _DWriteGetFrame(static_cast(typesetter->_attributedString.get()), range, frameRect); + ret->_path.reset(CGPathRetain(path)); + ret->_frameRect.origin = frameRect.origin; // Trying to access attributes without any text will throw an error if (range.length <= 0L) { - return ret.detach(); + return static_cast(ret.detach()); } CTParagraphStyleRef settings = @@ -48,7 +63,7 @@ @implementation _CTFramesetter : NSObject effectiveRange:nullptr]); if (settings == nullptr) { - return ret.detach(); + return static_cast(ret.detach()); } // DWrite only gives manual control of lineheight when it is constant through a frame @@ -87,30 +102,7 @@ @implementation _CTFramesetter : NSObject } } - return ret.detach(); -} - -/** - @Status Interoperable -*/ -CTFramesetterRef CTFramesetterCreateWithAttributedString(CFAttributedStringRef string) { - _CTFramesetter* ret = [_CTFramesetter alloc]; - ret->_typesetter = static_cast<_CTTypesetter*>(CTTypesetterCreateWithAttributedString(string)); - return static_cast(ret); -} - -/** - @Status Caveat - @Notes frameAttributes parameter ignored -*/ -CTFrameRef CTFramesetterCreateFrame(CTFramesetterRef framesetter, CFRange stringRange, CGPathRef path, CFDictionaryRef frameAttributes) { - CGRect containingRect = CGPathGetBoundingBox(path); - - _CTFrame* ret = __CreateFrame(static_cast<_CTFramesetter*>(framesetter), containingRect, stringRange); - ret->_path.reset(CGPathRetain(path)); - ret->_frameRect.origin = containingRect.origin; - - return static_cast(ret); + return static_cast(ret.detach()); } /** @@ -122,23 +114,20 @@ CTTypesetterRef CTFramesetterGetTypesetter(CTFramesetterRef framesetter) { } /** - @Status Interoperable + @Status Caveat + @Notes frameAttributes parameter ignored @Notes */ CGSize CTFramesetterSuggestFrameSizeWithConstraints( CTFramesetterRef framesetter, CFRange stringRange, CFDictionaryRef frameAttributes, CGSize constraints, CFRange* fitRange) { - CGRect frameSize = CGRectZero; - frameSize.size = constraints; - - _CTFrame* frame = __CreateFrame(static_cast<_CTFramesetter*>(framesetter), frameSize, stringRange); - CGSize ret = frame ? frame->_frameRect.size : CGSizeZero; - - if (fitRange) { - *fitRange = CTFrameGetVisibleStringRange(static_cast(frame)); + if (framesetter == nil) { + return CGSizeZero; } - [frame release]; - return ret; + CFAttributedStringRef string = + static_cast(static_cast<_CTFramesetter*>(framesetter)->_typesetter->_attributedString.get()); + + return _DWriteGetFrameSize(string, stringRange, constraints, fitRange); } /** diff --git a/Frameworks/CoreText/DWriteWrapper_CoreText.h b/Frameworks/CoreText/DWriteWrapper_CoreText.h index c04ae99652..099b188328 100644 --- a/Frameworks/CoreText/DWriteWrapper_CoreText.h +++ b/Frameworks/CoreText/DWriteWrapper_CoreText.h @@ -51,6 +51,7 @@ struct _DWriteGlyphRunDetails { bool _CloneDWriteGlyphRun(_In_ DWRITE_GLYPH_RUN const* src, _Outptr_ DWRITE_GLYPH_RUN* dest); +CGSize _DWriteGetFrameSize(CFAttributedStringRef string, CFRange range, CGSize maxSize, CFRange* fitRange); _CTFrame* _DWriteGetFrame(CFAttributedStringRef string, CFRange range, CGRect frameSize); _CTLine* _DWriteGetLine(CFAttributedStringRef string); diff --git a/Frameworks/CoreText/DWriteWrapper_CoreText.mm b/Frameworks/CoreText/DWriteWrapper_CoreText.mm index adcce634d8..0b7ee1f7f6 100644 --- a/Frameworks/CoreText/DWriteWrapper_CoreText.mm +++ b/Frameworks/CoreText/DWriteWrapper_CoreText.mm @@ -25,6 +25,7 @@ #import #import #import +#import using namespace std; using namespace Microsoft::WRL; @@ -522,4 +523,61 @@ HRESULT STDMETHODCALLTYPE GetPixelsPerDip(_In_opt_ void* clientDrawingContext, _ } return frame; +} + +static CGSize _DWriteGetFrameSize(CFAttributedStringRef string, CFRange range, CGSize maxSize, CFRange* fitRange) { + CGSize ret = CGSizeZero; + + // Treat range.length of 0 as unlimited length + if (range.length == 0L) { + range.length = CFAttributedStringGetLength(string) - range.location; + } + + // No text to draw, just return CGSizeZero + if (!string || range.length <= 0L) { + return ret; + } + + ComPtr textLayout; + if (FAILED(__DWriteTextLayoutCreate(string, range, { CGPointZero, maxSize }, &textLayout))) { + return ret; + } + + DWRITE_TEXT_METRICS textMetrics; + if (FAILED(textLayout->GetMetrics(&textMetrics))) { + return ret; + } + + // TODO:: find more precise value than 1.0 to increase width by to fully enclose frame + ret.width = std::min(maxSize.width, textMetrics.widthIncludingTrailingWhitespace + 1.0f); + ret.height = std::min(maxSize.height, textMetrics.height); + + if (fitRange) { + *fitRange = { range.location, 0L }; + uint32_t lineCount = 0; + + // Should return E_NOT_SUFFICIENT_BUFFER and popluate lineCount + if (textLayout->GetLineMetrics(nullptr, 0, &lineCount) != E_NOT_SUFFICIENT_BUFFER) { + return ret; + } + + std::vector metrics(lineCount); + if (FAILED(textLayout->GetLineMetrics(metrics.data(), lineCount, &lineCount))) { + return ret; + } + + float totalHeight = 0; + CFIndex endPos = range.location; + for (auto metric : metrics) { + totalHeight += metric.baseline; + if (totalHeight > ret.height) { + break; + } + endPos += metric.length; + } + + fitRange->length = endPos; + } + + return ret; } \ No newline at end of file diff --git a/Frameworks/Foundation/NSCFArray.mm b/Frameworks/Foundation/NSCFArray.mm index 72811c22b5..9ab4dc673b 100644 --- a/Frameworks/Foundation/NSCFArray.mm +++ b/Frameworks/Foundation/NSCFArray.mm @@ -1,6 +1,6 @@ //****************************************************************************** // -// Copyright (c) 2016 Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft. All rights reserved. // // This code is licensed under the MIT License (MIT). // @@ -106,6 +106,7 @@ - (void)removeLastObject { - (void)replaceObjectAtIndex:(NSUInteger)index withObject:(NSObject*)obj { BRIDGED_THROW_IF_IMMUTABLE(_CFArrayIsMutable, CFArrayRef); + NS_COLLECTION_THROW_IF_NULL_REASON(obj, [NSString stringWithFormat:@"*** %@ object cannot be nil", NSStringFromSelector(_cmd)]); // Fastpath CFRange range; range.location = index; @@ -115,6 +116,13 @@ - (void)replaceObjectAtIndex:(NSUInteger)index withObject:(NSObject*)obj { - (void)insertObject:(NSObject*)objAddr atIndex:(NSUInteger)index { BRIDGED_THROW_IF_IMMUTABLE(_CFArrayIsMutable, CFArrayRef); + NS_COLLECTION_THROW_IF_NULL_REASON(objAddr, [NSString stringWithFormat:@"*** %@ object cannot be nil", NSStringFromSelector(_cmd)]); + if (objAddr == nil) { + @throw [NSException exceptionWithName:NSInvalidArgumentException + reason:[NSString stringWithFormat:@"*** %@ object cannot be nil", NSStringFromSelector(_cmd)] + userInfo:nil]; + } + CFArrayInsertValueAtIndex(static_cast(self), index, reinterpret_cast(objAddr)); } @@ -125,6 +133,7 @@ - (void)removeAllObjects { - (void)addObject:(NSObject*)objAddr { BRIDGED_THROW_IF_IMMUTABLE(_CFArrayIsMutable, CFArrayRef); + NS_COLLECTION_THROW_IF_NULL_REASON(objAddr, [NSString stringWithFormat:@"*** %@ object cannot be nil", NSStringFromSelector(_cmd)]); CFArrayAppendValue((CFMutableArrayRef)self, (const void*)objAddr); } diff --git a/Frameworks/Foundation/NSCFAttributedString.mm b/Frameworks/Foundation/NSCFAttributedString.mm index 35ec906c0c..f935b28468 100644 --- a/Frameworks/Foundation/NSCFAttributedString.mm +++ b/Frameworks/Foundation/NSCFAttributedString.mm @@ -1,6 +1,6 @@ //****************************************************************************** // -// Copyright (c) 2016 Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft. All rights reserved. // // This code is licensed under the MIT License (MIT). // @@ -19,6 +19,7 @@ #import #import "NSCFAttributedString.h" #import "CFFoundationInternal.h" +#import "NSCFCollectionSupport.h" #import @@ -35,8 +36,10 @@ - (_Nullable instancetype)init { } - (_Nullable instancetype)initWithAttributedString:(NSAttributedString*)string { - return reinterpret_cast(static_cast( - CFAttributedStringCreateWithSubstring(kCFAllocatorDefault, static_cast(string), CFRange{ 0, [string length] }))); + return reinterpret_cast( + static_cast(CFAttributedStringCreateWithSubstring(kCFAllocatorDefault, + static_cast(string), + CFRange{ 0, [string length] }))); } - (_Nullable instancetype)initWithString:(NSString*)string attributes:(NSDictionary*)attributes { @@ -58,11 +61,13 @@ - (_Nullable instancetype)init { } - (_Nullable instancetype)initWithAttributedString:(NSAttributedString*)string { - return reinterpret_cast(CFAttributedStringCreateMutableCopy(kCFAllocatorDefault, 0, static_cast(string))); + return reinterpret_cast( + CFAttributedStringCreateMutableCopy(kCFAllocatorDefault, 0, static_cast(string))); } - (_Nullable instancetype)initWithString:(NSString*)string attributes:(NSDictionary*)attributes { - NSMutableAttributedString* attributedString = static_cast(CFAttributedStringCreateMutable(kCFAllocatorDefault, 0)); + NSMutableAttributedString* attributedString = + static_cast(CFAttributedStringCreateMutable(kCFAllocatorDefault, 0)); CFAttributedStringReplaceString(static_cast(attributedString), CFRange{ 0, 0 }, static_cast(string)); @@ -108,7 +113,7 @@ - (NSMutableString*)mutableString { - (void)addAttribute:(NSString*)name value:(id)value range:(NSRange)range { BRIDGED_THROW_IF_IMMUTABLE(_CFAttributedStringIsMutable, CFAttributedStringRef); THROW_NS_IF_FALSE(E_BOUNDS, ((range.location + range.length) <= [self length])); - + NS_COLLECTION_THROW_IF_NULL_REASON(value, [NSString stringWithFormat:@"*** %@ nil value", NSStringFromSelector(_cmd)]); CFAttributedStringSetAttribute(reinterpret_cast(self), *reinterpret_cast(&range), (__bridge CFStringRef)name, diff --git a/Frameworks/Foundation/NSCFCollectionSupport.h b/Frameworks/Foundation/NSCFCollectionSupport.h index 518f3290f9..55dbaf8132 100644 --- a/Frameworks/Foundation/NSCFCollectionSupport.h +++ b/Frameworks/Foundation/NSCFCollectionSupport.h @@ -1,6 +1,6 @@ //****************************************************************************** // -// Copyright (c) 2016 Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft. All rights reserved. // // This code is licensed under the MIT License (MIT). // @@ -25,4 +25,17 @@ const void* _NSCFCallbackRetain(CFAllocatorRef allocator, const void* value); void _NSCFCallbackRelease(CFAllocatorRef allocator, const void* value); CFStringRef _NSCFCallbackCopyDescription(const void* value); Boolean _NSCFCallbackEquals(const void* value1, const void* value2); -CFHashCode _NSCFCallbackHash(const void* value); \ No newline at end of file +CFHashCode _NSCFCallbackHash(const void* value); + +#ifdef __OBJC__ +#include + +// Helper macro for NSCF collections to use CF counterparts that don't throw when trying to insert nil +#define NS_COLLECTION_THROW_IF_NULL_REASON(VALUE, ...) \ + do { \ + if (VALUE == nil) { \ + @throw [NSException exceptionWithName:NSInvalidArgumentException reason:(__VA_ARGS__) userInfo:nil]; \ + } \ + } while (false) + +#endif // __OBJC__ \ No newline at end of file diff --git a/Frameworks/Foundation/NSCFDictionary.mm b/Frameworks/Foundation/NSCFDictionary.mm index a604c3a1eb..9190d5192a 100644 --- a/Frameworks/Foundation/NSCFDictionary.mm +++ b/Frameworks/Foundation/NSCFDictionary.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). // @@ -112,6 +112,9 @@ - (NSEnumerator*)keyEnumerator { - (void)setObject:(id)object forKey:(id)key { BRIDGED_THROW_IF_IMMUTABLE(_CFDictionaryIsMutable, CFDictionaryRef); + NS_COLLECTION_THROW_IF_NULL_REASON(object, + [NSString + stringWithFormat:@"*** %@ object cannot be nil (key: %@)", NSStringFromSelector(_cmd), key]); CFDictionarySetValue((CFMutableDictionaryRef)self, (const void*)key, (void*)object); } diff --git a/Frameworks/Foundation/NSCFSet.mm b/Frameworks/Foundation/NSCFSet.mm index 3e796718d8..a32187b223 100644 --- a/Frameworks/Foundation/NSCFSet.mm +++ b/Frameworks/Foundation/NSCFSet.mm @@ -1,6 +1,6 @@ //****************************************************************************** // -// Copyright (c) 2016 Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft. All rights reserved. // // This code is licensed under the MIT License (MIT). // @@ -24,12 +24,7 @@ #include static CFSetCallBacks _NSCFSetCallBacks = { - 0, - _NSCFCallbackRetain, - _NSCFCallbackRelease, - _NSCFCallbackCopyDescription, - _NSCFCallbackEquals, - _NSCFCallbackHash, + 0, _NSCFCallbackRetain, _NSCFCallbackRelease, _NSCFCallbackCopyDescription, _NSCFCallbackEquals, _NSCFCallbackHash, }; @interface NSCFSet : NSMutableSet @@ -45,7 +40,8 @@ - (_Nullable instancetype)init { } - (_Nullable instancetype)initWithObjects:(id _Nonnull const*)objs count:(NSUInteger)count { - return reinterpret_cast(static_cast((CFSetCreate(kCFAllocatorDefault, (const void**)(objs), count, &_NSCFSetCallBacks)))); + return reinterpret_cast( + static_cast((CFSetCreate(kCFAllocatorDefault, (const void**)(objs), count, &_NSCFSetCallBacks)))); } @end @@ -111,6 +107,7 @@ - (id)member:(id)object { - (void)addObject:(id)object { BRIDGED_THROW_IF_IMMUTABLE(_CFSetIsMutable, CFSetRef); + NS_COLLECTION_THROW_IF_NULL_REASON(object, [NSString stringWithFormat:@"*** %@ object cannot be nil", NSStringFromSelector(_cmd)]); CFSetAddValue(static_cast(self), object); } diff --git a/Frameworks/Foundation/NSMutableDictionary.mm b/Frameworks/Foundation/NSMutableDictionary.mm index 7fbef69781..d9a1fad28a 100644 --- a/Frameworks/Foundation/NSMutableDictionary.mm +++ b/Frameworks/Foundation/NSMutableDictionary.mm @@ -115,7 +115,11 @@ - (void)setObject:(id)object forKey:(id)key { @Status Interoperable */ - (void)setObject:(id)object forKeyedSubscript:(id)key { - [self setObject:object forKey:key]; + if (object == nil) { + [self removeObjectForKey:key]; + } else { + [self setObject:object forKey:key]; + } } /** diff --git a/Frameworks/Foundation/NSNotificationCenter.mm b/Frameworks/Foundation/NSNotificationCenter.mm index 43fa56bf39..c84e756cba 100644 --- a/Frameworks/Foundation/NSNotificationCenter.mm +++ b/Frameworks/Foundation/NSNotificationCenter.mm @@ -223,7 +223,7 @@ - (void)removeObserver:(id)observer name:(NSString*)name object:(id)object { } if (CFArrayGetCount((CFArrayRef)arr) == 0) { - [observers setObject:nil forKey:name]; + [observers removeObjectForKey:name]; } } diff --git a/Frameworks/ImageIO/CGImageDestination.mm b/Frameworks/ImageIO/CGImageDestination.mm index 7a6d28deb1..72feac3c22 100644 --- a/Frameworks/ImageIO/CGImageDestination.mm +++ b/Frameworks/ImageIO/CGImageDestination.mm @@ -1203,4 +1203,4 @@ bool CGImageDestinationFinalize(CGImageDestinationRef idst) { imageDestination.idGifEncoderMetadataQueryWriter = nullptr; return true; -} \ No newline at end of file +} diff --git a/Frameworks/QuartzCore/CALayer.mm b/Frameworks/QuartzCore/CALayer.mm index a96948d67b..b09e7d5fb7 100644 --- a/Frameworks/QuartzCore/CALayer.mm +++ b/Frameworks/QuartzCore/CALayer.mm @@ -1412,7 +1412,7 @@ - (void)addAnimation:(CAAnimation*)anim forKey:(NSString*)key { - (void)_removeAnimation:(CAAnimation*)animation { CAAnimation* objForKey = [priv->_animations objectForKey:animation->_keyName]; - [priv->_animations setObject:nil forKey:animation->_keyName]; + [priv->_animations removeObjectForKey:animation->_keyName]; } /** diff --git a/Frameworks/UIKit.Xaml/Layer.xaml.cpp b/Frameworks/UIKit.Xaml/Layer.xaml.cpp index fe57c5cb12..89307f3868 100644 --- a/Frameworks/UIKit.Xaml/Layer.xaml.cpp +++ b/Frameworks/UIKit.Xaml/Layer.xaml.cpp @@ -122,3 +122,15 @@ UIKIT_XAML_EXPORT void XamlSetFrameworkElementLayerProperties( frameworkElement->SetValue(UIKit::Xaml::Private::CoreAnimation::Layer::SublayerCanvasProperty, sublayerCanvas); } } + +// Get the layerContentProperty for the specified target xaml element +UIKIT_XAML_EXPORT IInspectable* XamlGetFrameworkElementLayerContentProperty(const Microsoft::WRL::ComPtr& targetElement) { + auto frameworkElement = safe_cast(reinterpret_cast(targetElement.Get())); + return InspectableFromObject(frameworkElement->GetValue(UIKit::Xaml::Private::CoreAnimation::Layer::LayerContentProperty)).Detach(); +} + +// Get the sublayerCanvasProperty for the specified target xaml element +UIKIT_XAML_EXPORT IInspectable* XamlGetFrameworkElementSublayerCanvasProperty(const Microsoft::WRL::ComPtr& targetElement) { + auto frameworkElement = safe_cast(reinterpret_cast(targetElement.Get())); + return InspectableFromObject(frameworkElement->GetValue(UIKit::Xaml::Private::CoreAnimation::Layer::SublayerCanvasProperty)).Detach(); +} \ No newline at end of file diff --git a/Frameworks/UIKit.Xaml/ObjCXamlControls.h b/Frameworks/UIKit.Xaml/ObjCXamlControls.h index fbf5650fee..c690101b4b 100644 --- a/Frameworks/UIKit.Xaml/ObjCXamlControls.h +++ b/Frameworks/UIKit.Xaml/ObjCXamlControls.h @@ -70,6 +70,12 @@ UIKIT_XAML_EXPORT IInspectable* XamlGetLabelTextBox(const Microsoft::WRL::ComPtr UIKIT_XAML_EXPORT void XamlSetFrameworkElementLayerProperties(const Microsoft::WRL::ComPtr& targetElement, const Microsoft::WRL::ComPtr& sublayerCanvasProperty, const Microsoft::WRL::ComPtr& layerContentProperty); + +// Get the layerContentProperty for the specified target xaml element +UIKIT_XAML_EXPORT IInspectable* XamlGetFrameworkElementLayerContentProperty(const Microsoft::WRL::ComPtr& targetElement); + +// Get the sublayerCanvasProperty for the specified target xaml element +UIKIT_XAML_EXPORT IInspectable* XamlGetFrameworkElementSublayerCanvasProperty(const Microsoft::WRL::ComPtr& targetElement); //////////////////////////////////////////////////////////////////////////////////// // ProgressRing.xaml.cpp diff --git a/Frameworks/UIKit/NSParagraphStyle.mm b/Frameworks/UIKit/NSParagraphStyle.mm index 8b883883b4..92de568e90 100644 --- a/Frameworks/UIKit/NSParagraphStyle.mm +++ b/Frameworks/UIKit/NSParagraphStyle.mm @@ -18,6 +18,7 @@ #import #import +#import #import "NSParagraphStyleInternal.h" @implementation NSParagraphStyle @@ -126,7 +127,7 @@ + (BOOL)supportsSecureCoding { - (CTParagraphStyleRef)_createCTParagraphStyle { CTLineBreakMode lineBreakMode = self.lineBreakMode; CTWritingDirection writingDirection = self.baseWritingDirection; - CTTextAlignment alignment = _NSTextAlignmentToCTTextAlignment(self.alignment); + CTTextAlignment alignment = NSTextAlignmentToCTTextAlignment(self.alignment); CTParagraphStyleSetting settings[14] = { { kCTParagraphStyleSpecifierAlignment, sizeof(CTTextAlignment), &alignment }, { kCTParagraphStyleSpecifierFirstLineHeadIndent, sizeof(CGFloat), &_firstLineHeadIndent }, diff --git a/Frameworks/UIKit/NSString+UIKitAdditions.mm b/Frameworks/UIKit/NSString+UIKitAdditions.mm index ba9b577b0d..e6d92a2a5e 100644 --- a/Frameworks/UIKit/NSString+UIKitAdditions.mm +++ b/Frameworks/UIKit/NSString+UIKitAdditions.mm @@ -42,68 +42,6 @@ void NSStringForceinclude() { @implementation NSString (UIKitAdditions) -static void drawString(UIFont* font, - CGContextRef context, - NSString* string, - CGRect rect, - UILineBreakMode lineBreakMode, - UITextAlignment alignment, - CGSize* sizeOut) { - if (font == nil) { - TraceVerbose(TAG, L"drawString: font = nil!"); - return; - } - - if (rect.size.width == 0) { - rect.size.width = FLT_MAX; - } - - if (rect.size.height == 0) { - rect.size.height = FLT_MAX; - } - - CTParagraphStyleSetting styles[2]; - CTTextAlignment align = _NSTextAlignmentToCTTextAlignment(alignment); - styles[0] = { kCTParagraphStyleSpecifierAlignment, sizeof(CTTextAlignment), &align }; - - CTLineBreakMode breakMode = static_cast(lineBreakMode); - styles[1] = { kCTParagraphStyleSpecifierLineBreakMode, sizeof(CTLineBreakMode), &breakMode }; - - NSAttributedString* attr = - [[[NSAttributedString alloc] initWithString:string - attributes:@{ - (NSString*)kCTForegroundColorFromContextAttributeName : (id)kCFBooleanTrue, - (NSString*)kCTParagraphStyleAttributeName : (id)CTParagraphStyleCreate(styles, 2), - (NSString*)kCTFontAttributeName : font - }] autorelease]; - - CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString(static_cast(attr)); - - CGPathRef path = CGPathCreateWithRect(rect, nullptr); - CTFrameRef frame = CTFramesetterCreateFrame(framesetter, {}, path, nullptr); - - // Invert text matrix so glyphs are drawn with correct orientation - CGContextSetTextMatrix(context, CGAffineTransformMakeScale(1.0f, -1.0f)); - - // Can't draw the entire frame because it assumes our space has been flipped and translated - NSArray* lines = static_cast(CTFrameGetLines(frame)); - std::vector origins([lines count]); - CTFrameGetLineOrigins(frame, {}, origins.data()); - for (size_t i = 0; i < origins.size(); ++i) { - // Need to set text position so each line will be drawn in the correct position relative to each other - CGContextSetTextPosition(context, rect.origin.x + origins[i].x, rect.origin.y + origins[i].y); - CTLineDraw(static_cast(lines[i]), context); - } - - if (sizeOut) { - *sizeOut = _CTFrameGetSize(frame); - } - - CGPathRelease(path); - CFRelease(framesetter); - CFRelease(frame); -} - static NSDictionary* _getDefaultUITextAttributes() { static NSDictionary* _defaultUITextAttributes; if (_defaultUITextAttributes == nil) { @@ -116,17 +54,6 @@ static void drawString(UIFont* font, return _defaultUITextAttributes; } -/** - @Status Interoperable -*/ -- (CGSize)drawInRect:(CGRect)rct withFont:(UIFont*)font { - CGSize fontExtent; - - drawString(font, UIGraphicsGetCurrentContext(), self, rct, UILineBreakModeWordWrap, UITextAlignmentLeft, &fontExtent); - - return fontExtent; -} - /** @Status Caveat @Notes Currently UITextAttributeTextShadowColor and UITextAttributeTextShadowOffset will be ignored. @@ -161,48 +88,94 @@ - (void)drawInRect:(CGRect)rect withAttributes:(NSDictionary*)attrs { /** @Status Interoperable */ -- (CGSize)drawInRect:(CGRect)rct withFont:(UIFont*)font lineBreakMode:(UILineBreakMode)lineBreakMode alignment:(UITextAlignment)alignment { - CGSize fontExtent; - - drawString(font, UIGraphicsGetCurrentContext(), self, rct, lineBreakMode, alignment, &fontExtent); - - return fontExtent; +- (CGSize)drawInRect:(CGRect)rect withFont:(UIFont*)font { + return [self drawInRect:rect withFont:font lineBreakMode:UILineBreakModeWordWrap]; } /** - @Status Interoperable + @Status Caveat + @Notes Clipping line break modes unsupported */ -- (CGSize)drawInRect:(CGRect)rct withFont:(UIFont*)font lineBreakMode:(UILineBreakMode)lineBreakMode { - CGSize fontExtent; - - drawString(font, UIGraphicsGetCurrentContext(), self, rct, lineBreakMode, UITextAlignmentLeft, &fontExtent); - - return fontExtent; +- (CGSize)drawInRect:(CGRect)rect withFont:(UIFont*)font lineBreakMode:(UILineBreakMode)lineBreakMode { + return [self drawInRect:rect withFont:font lineBreakMode:lineBreakMode alignment:UITextAlignmentLeft]; } /** - @Status Interoperable + @Status Caveat + @Notes Clipping line break modes unsupported */ -- (CGSize)drawAtPoint:(CGPoint)pt withFont:(UIFont*)font { - CGSize fontExtent; +- (CGSize)drawInRect:(CGRect)rect withFont:(UIFont*)font lineBreakMode:(UILineBreakMode)lineBreakMode alignment:(UITextAlignment)alignment { + // 0 Width or Height treated as unlimited bounds + if (rect.size.width == 0) { + rect.size.width = std::numeric_limits::max(); + } + + if (rect.size.height == 0) { + rect.size.height = std::numeric_limits::max(); + } + + CTParagraphStyleSetting styles[2]; + CTTextAlignment align = NSTextAlignmentToCTTextAlignment(alignment); + styles[0] = { kCTParagraphStyleSpecifierAlignment, sizeof(CTTextAlignment), &align }; + + CTLineBreakMode breakMode = static_cast(lineBreakMode); + styles[1] = { kCTParagraphStyleSpecifierLineBreakMode, sizeof(CTLineBreakMode), &breakMode }; + + NSAttributedString* attr = [[[NSAttributedString alloc] + initWithString:self + attributes:@{ + (NSString*)kCTForegroundColorFromContextAttributeName : (id)kCFBooleanTrue, + (NSString*)kCTParagraphStyleAttributeName : (id)CTParagraphStyleCreate(styles, std::extent::value), + (NSString*)kCTFontAttributeName : (font ? font : [UIFont defaultFont]) + }] autorelease]; + + woc::unique_cf framesetter{ CTFramesetterCreateWithAttributedString(static_cast(attr)) }; + if (framesetter == nil) { + return CGSizeZero; + } + + woc::unique_cf path{ CGPathCreateWithRect(rect, nullptr) }; + if (path == nil) { + return CGSizeZero; + } - CGRect rct; + woc::unique_cf frame{ CTFramesetterCreateFrame(framesetter.get(), {}, path.get(), nullptr) }; + if (frame == nil) { + return CGSizeZero; + } - rct.origin.x = pt.x; - rct.origin.y = pt.y; - rct.size.width = 0; - rct.size.height = 0; + CGContextRef context = UIGraphicsGetCurrentContext(); - drawString(font, UIGraphicsGetCurrentContext(), self, rct, UILineBreakModeClip, UITextAlignmentLeft, &fontExtent); + // Invert text matrix so glyphs are drawn with correct orientation + CGContextSetTextMatrix(context, CGAffineTransformMakeScale(1.0f, -1.0f)); - return fontExtent; + // Can't draw the entire frame because it assumes our space has been flipped and translated + NSArray* lines = static_cast(CTFrameGetLines(frame.get())); + if ([lines count] != 0) { + std::vector origins([lines count]); + CTFrameGetLineOrigins(frame.get(), {}, origins.data()); + for (size_t i = 0; i < origins.size(); ++i) { + // Need to set text position so each line will be drawn in the correct position relative to each other + CGContextSetTextPosition(context, rect.origin.x + origins[i].x, rect.origin.y + origins[i].y); + CTLineDraw(static_cast(lines[i]), context); + } + } + + return _CTFrameGetSize(frame.get()); +} + +/** + @Status Interoperable +*/ +- (CGSize)drawAtPoint:(CGPoint)point withFont:(UIFont*)font { + return [self drawAtPoint:point forWidth:0 withFont:font]; } /** @Status Caveat @Notes Currently UITextAttributeTextShadowColor and UITextAttributeTextShadowOffset will be ignored. */ -- (void)drawAtPoint:(CGPoint)pt withAttributes:(NSDictionary*)attrs { +- (void)drawAtPoint:(CGPoint)point withAttributes:(NSDictionary*)attrs { if (attrs == nil) { attrs = _getDefaultUITextAttributes(); } @@ -225,73 +198,43 @@ - (void)drawAtPoint:(CGPoint)pt withAttributes:(NSDictionary*)attrs { UIFont* uiFont = [attrs valueForKey:UITextAttributeFont]; if (uiFont != nil) { - [self drawAtPoint:pt withFont:uiFont]; + [self drawAtPoint:point withFont:uiFont]; } } -- (CGSize)drawAtPoint:(CGPoint)pt forWidth:(float)forWidth withFont:(UIFont*)font { - CGSize fontExtent; - - CGRect rct; - - rct.origin.x = pt.x; - rct.origin.y = pt.y; - rct.size.width = forWidth; - rct.size.height = 0; - - drawString(font, UIGraphicsGetCurrentContext(), self, rct, UILineBreakModeClip, UITextAlignmentLeft, &fontExtent); - - return fontExtent; +- (CGSize)drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont*)font { + return [self drawInRect:{ point, CGSizeMake(width, 0) } withFont:font lineBreakMode:UILineBreakModeClip]; } /** - @Status Interoperable + @Status Caveat + @Notes parameter baselineAdjustment and minFontSize are ignored as text is drawn at given text size */ -- (CGSize)drawAtPoint:(CGPoint)pt - forWidth:(float)forWidth +- (CGSize)drawAtPoint:(CGPoint)point + forWidth:(float)width withFont:(UIFont*)font minFontSize:(float)minFontSize actualFontSize:(float*)actualFontSize lineBreakMode:(UILineBreakMode)lineBreak baselineAdjustment:(UIBaselineAdjustment)baseline { - CGSize fontExtent; - CGRect rct; - - rct.origin.x = pt.x; - rct.origin.y = pt.y; - rct.size.width = forWidth; - rct.size.height = 0; - - drawString(font, UIGraphicsGetCurrentContext(), self, rct, UILineBreakModeClip, UITextAlignmentLeft, &fontExtent); if (actualFontSize) { *actualFontSize = 10.0f; } - - return fontExtent; + return [self drawInRect:{ point, CGSizeMake(width, 0) } withFont:font lineBreakMode:lineBreak]; } /** - @Status Interoperable + @Status Caveat + @Notes parameter baselineAdjustment is ignored */ -- (CGSize)drawAtPoint:(CGPoint)pt - forWidth:(float)forWidth +- (CGSize)drawAtPoint:(CGPoint)point + forWidth:(float)width withFont:(UIFont*)font fontSize:(float)fontSize lineBreakMode:(UILineBreakMode)lineBreak baselineAdjustment:(UIBaselineAdjustment)baseline { - CGSize fontExtent; - CGRect rct; - - rct.origin.x = pt.x; - rct.origin.y = pt.y; - rct.size.width = forWidth; - rct.size.height = 0; - font = [font fontWithSize:fontSize]; - - drawString(font, UIGraphicsGetCurrentContext(), self, rct, UILineBreakModeClip, UITextAlignmentLeft, &fontExtent); - - return fontExtent; + return [self drawInRect:{ point, CGSizeMake(width, 0) } withFont:font lineBreakMode:lineBreak]; } // Private helper for sizeWith... functions @@ -464,4 +407,4 @@ - (void)drawWithRect:(CGRect)rect UNIMPLEMENTED(); } -@end \ No newline at end of file +@end diff --git a/Frameworks/UIKit/StarboardXaml/LayerProxy.cpp b/Frameworks/UIKit/StarboardXaml/LayerProxy.cpp index f6765c9b6b..a04d37a79a 100644 --- a/Frameworks/UIKit/StarboardXaml/LayerProxy.cpp +++ b/Frameworks/UIKit/StarboardXaml/LayerProxy.cpp @@ -32,6 +32,9 @@ using namespace Windows::UI::Xaml::Media; static const wchar_t* TAG = L"LayerProxy"; +static const bool DEBUG_ALL = false; +static const bool DEBUG_HIERARCHY = DEBUG_ALL | false; + // TODO: We should formally expose this off of XamlCompositor for our use here. extern Canvas^ s_windowCollection; @@ -45,17 +48,33 @@ __inline Panel^ _SubLayerPanelFromInspectable(const ComPtr& elemen // First check if the element implements ILayer ILayer^ layerElement = dynamic_cast(xamlElement); if (layerElement) { + if (DEBUG_HIERARCHY) { + TraceVerbose( + TAG, + L"_SubLayerPanelFromInspectable for [%ws] returning layerElement->SublayerCanvas [%ws].", + layerElement->GetType()->FullName->Data(), + layerElement->SublayerCanvas->GetType()->FullName->Data()); + } + return layerElement->SublayerCanvas; } // Not an ILayer, so default to grabbing the xamlElement's SublayerCanvasProperty (if it exists) - return dynamic_cast(_FrameworkElementFromInspectable(element)->GetValue(Layer::SublayerCanvasProperty)); + Platform::Object^ value = xamlElement->GetValue(Layer::SublayerCanvasProperty); + if (DEBUG_HIERARCHY) { + TraceVerbose( + TAG, + L"GetValue(Layer::SublayerCanvasProperty) for [%ws] returned layerElement->SublayerCanvas [%ws].", + xamlElement->GetType()->FullName->Data(), + (value ? value->GetType()->FullName->Data() : L"nullptr")); + } + + return dynamic_cast(value); }; LayerProxy::LayerProxy(IInspectable* xamlElement) : _xamlElement(nullptr), _isRoot(false), - _parent(nullptr), _currentTexture(nullptr), _topMost(false) { @@ -70,12 +89,6 @@ LayerProxy::LayerProxy(IInspectable* xamlElement) : CoreAnimation::LayerCoordinator::InitializeFrameworkElement(_FrameworkElementFromInspectable(_xamlElement)); } -LayerProxy::~LayerProxy() { - for (auto layer : _subLayers) { - layer->_parent = nullptr; - } -} - Microsoft::WRL::ComPtr LayerProxy::GetXamlElement() { return _xamlElement; } @@ -140,8 +153,11 @@ void LayerProxy::SetTopMost() { void LayerProxy::_SetBackgroundColor(float r, float g, float b, float a) { FrameworkElement^ xamlLayer = _FrameworkElementFromInspectable(_xamlElement); - SolidColorBrush^ backgroundBrush = nullptr; // A null brush is transparent and not hit-testable - if (!_isRoot && !_topMost && (a != 0.0)) { + // A null brush is transparent and not hit-testable; we only want this for 'root' or 'topmost' layers/views. + // For everything else, we simply map through the background color that was set on the layer/view. + // Note that UIView hit-testability is handled in UIView via its 'userInteractionEnabled', 'isHidden', and 'alpha' property values. + SolidColorBrush^ backgroundBrush = nullptr; + if (!_isRoot && !_topMost) { Windows::UI::Color backgroundColor; backgroundColor.R = static_cast(r * 255.0); backgroundColor.G = static_cast(g * 255.0); @@ -189,8 +205,14 @@ void LayerProxy::AddToRoot() { } void LayerProxy::AddSubLayer(const std::shared_ptr& subLayer, const std::shared_ptr& before, const std::shared_ptr& after) { - assert(subLayer->_parent == NULL); - subLayer->_parent = this; + // Make sure the sublayer isn't already parented + { + auto strongParent = subLayer->_parent.lock(); + assert(!strongParent); + } + + // Set ourselves as the sublayer's parent + subLayer->_parent = shared_from_this(); _subLayers.insert(subLayer); FrameworkElement^ xamlElementForSubLayer = _FrameworkElementFromInspectable(subLayer->_xamlElement); @@ -226,12 +248,14 @@ void LayerProxy::AddSubLayer(const std::shared_ptr& subLayer, const } void LayerProxy::MoveLayer(const std::shared_ptr& before, const std::shared_ptr& after) { - assert(_parent != NULL); + // Grab a strong reference to our parent + auto strongParent = _parent.lock(); + assert(strongParent); FrameworkElement^ xamlElementForThisLayer = _FrameworkElementFromInspectable(_xamlElement); - Panel^ subLayerPanelForParentLayer = _SubLayerPanelFromInspectable(_parent->_xamlElement); + Panel^ subLayerPanelForParentLayer = _SubLayerPanelFromInspectable(strongParent->_xamlElement); if (!subLayerPanelForParentLayer) { - FrameworkElement^ xamlElementForParentLayer = _FrameworkElementFromInspectable(_parent->_xamlElement); + FrameworkElement^ xamlElementForParentLayer = _FrameworkElementFromInspectable(strongParent->_xamlElement); UNIMPLEMENTED_WITH_MSG( "MoveLayer for [%ws] not supported on parent [%ws].", xamlElementForThisLayer->GetType()->FullName->Data(), @@ -239,7 +263,7 @@ void LayerProxy::MoveLayer(const std::shared_ptr& before, const std: return; } - if (before != NULL) { + if (before) { FrameworkElement^ xamlBeforeLayer = _FrameworkElementFromInspectable(before->_xamlElement); unsigned int srcIdx = 0; @@ -261,7 +285,7 @@ void LayerProxy::MoveLayer(const std::shared_ptr& before, const std: FAIL_FAST(); } } else { - assert(after != NULL); + assert(after); FrameworkElement^ xamlAfterLayer = _FrameworkElementFromInspectable(after->_xamlElement); unsigned int srcIdx = 0; @@ -286,21 +310,39 @@ void LayerProxy::MoveLayer(const std::shared_ptr& before, const std: } void LayerProxy::RemoveFromSuperLayer() { + // Grab a strong reference to our parent (if one exists) + auto strongParent = _parent.lock(); + FrameworkElement^ xamlElementForThisLayer = _FrameworkElementFromInspectable(_xamlElement); Panel^ subLayerPanelForParentLayer; if (_isRoot) { subLayerPanelForParentLayer = s_windowCollection; } else { - if (!_parent) { + if (!strongParent) { + if (DEBUG_HIERARCHY) { + TraceVerbose( + TAG, + L"RemoveFromSuperLayer for [%ws] doesn't have a parent; nothing left to do.", + xamlElementForThisLayer->GetType()->FullName->Data()); + } + return; } - subLayerPanelForParentLayer = _SubLayerPanelFromInspectable(_parent->_xamlElement); - _parent->_subLayers.erase(shared_from_this()); + subLayerPanelForParentLayer = _SubLayerPanelFromInspectable(strongParent->_xamlElement); + strongParent->_subLayers.erase(shared_from_this()); + } + + if (DEBUG_HIERARCHY) { + TraceVerbose( + TAG, + L"RemoveFromSuperLayer xamlElementForThisLayer = [%ws]; subLayerPanelForParentLayer = [%ws].", + xamlElementForThisLayer->GetType()->FullName->Data(), + subLayerPanelForParentLayer->GetType()->FullName->Data()); } if (!subLayerPanelForParentLayer) { - FrameworkElement^ xamlElementForParentLayer = _FrameworkElementFromInspectable(_parent->_xamlElement); + FrameworkElement^ xamlElementForParentLayer = _FrameworkElementFromInspectable(strongParent->_xamlElement); UNIMPLEMENTED_WITH_MSG( "RemoveFromSuperLayer for [%ws] not supported on parent [%ws].", xamlElementForThisLayer->GetType()->FullName->Data(), @@ -309,12 +351,12 @@ void LayerProxy::RemoveFromSuperLayer() { return; } - _parent = nullptr; - unsigned int idx = 0; if (subLayerPanelForParentLayer->Children->IndexOf(xamlElementForThisLayer, &idx) == true) { subLayerPanelForParentLayer->Children->RemoveAt(idx); } else { FAIL_FAST(); } + + _parent.reset(); } diff --git a/Frameworks/UIKit/StarboardXaml/LayerProxy.h b/Frameworks/UIKit/StarboardXaml/LayerProxy.h index 5ffc1fe806..417fe5b984 100644 --- a/Frameworks/UIKit/StarboardXaml/LayerProxy.h +++ b/Frameworks/UIKit/StarboardXaml/LayerProxy.h @@ -28,7 +28,6 @@ class LayerProxy : public ILayerProxy, public std::enable_shared_from_this { public: explicit LayerProxy(IInspectable* xamlElement); - ~LayerProxy(); // ILayerProxy Microsoft::WRL::ComPtr GetXamlElement() override; @@ -68,8 +67,7 @@ class LayerProxy : public ILayerProxy, public std::enable_shared_from_this _parent; std::set> _subLayers; std::shared_ptr _currentTexture; bool _topMost; diff --git a/Frameworks/UIKit/StarboardXaml/StarboardXaml.cpp b/Frameworks/UIKit/StarboardXaml/StarboardXaml.cpp index a2a4cd093b..2c9be6cf92 100644 --- a/Frameworks/UIKit/StarboardXaml/StarboardXaml.cpp +++ b/Frameworks/UIKit/StarboardXaml/StarboardXaml.cpp @@ -353,7 +353,7 @@ int UIApplicationMain(int argc, char* argv[], void* principalClassName, void* de } // This is the initialization function for non-Islandwood apps that intend to call into Islandwood: -// test executables and general WinRT apps that want to call Islandwood libraries +// general WinRT apps that want to call Islandwood libraries UIKIT_EXPORT void UIApplicationInitialize(const wchar_t* principalClassName, const wchar_t* delegateClassName) { // Register tracelogging @@ -374,6 +374,28 @@ void UIApplicationInitialize(const wchar_t* principalClassName, const wchar_t* d _ApplicationLaunch(ActivationTypeLibrary, nullptr); } +// This is the initialization function for functional tests +UIKIT_EXPORT +void UIApplicationInitializeFunctionalTest(const wchar_t* principalClassName, const wchar_t* delegateClassName) { + // Register tracelogging + TraceRegister(); + + if (principalClassName != nullptr) { + g_principalClassName = ref new Platform::String(principalClassName); + } else { + g_principalClassName = ref new Platform::String(); + } + + if (delegateClassName != nullptr) { + g_delegateClassName = ref new Platform::String(delegateClassName); + } else { + g_delegateClassName = ref new Platform::String(); + } + + // Perform a default app launch + _ApplicationLaunch(ActivationTypeNone, nullptr); +} + // Note: Like UIApplicationMain, delegateClassName is actually an NSString*. UIKIT_EXPORT void UIApplicationActivationTest(IInspectable* activationArgs, void* delegateClassName){ diff --git a/Frameworks/UIKit/UIActionSheet.mm b/Frameworks/UIKit/UIActionSheet.mm index 80375722a8..8529b0f831 100644 --- a/Frameworks/UIKit/UIActionSheet.mm +++ b/Frameworks/UIKit/UIActionSheet.mm @@ -294,7 +294,7 @@ - (void)showFromBarButtonItem:(UIBarButtonItem*)item animated:(BOOL)animated { @Status Interoperable */ - (NSString*)title { - return NSStringFromPropertyValue(_contentDialog.title); + return XamlUtilities::NSStringFromPropertyValue(_contentDialog.title); } /** diff --git a/Frameworks/UIKit/UIActivityIndicatorView.mm b/Frameworks/UIKit/UIActivityIndicatorView.mm index 388c4095b5..9ae0d4f84c 100644 --- a/Frameworks/UIKit/UIActivityIndicatorView.mm +++ b/Frameworks/UIKit/UIActivityIndicatorView.mm @@ -254,7 +254,7 @@ - (BOOL)isAnimating { - (void)setColor:(UIColor*)color { _color = color; - WUColor* convertedColor = ConvertUIColorToWUColor(color); + WUColor* convertedColor = XamlUtilities::ConvertUIColorToWUColor(color); WUXMSolidColorBrush* brush = [WUXMSolidColorBrush makeInstanceWithColor:convertedColor]; [_progressRing setForeground:brush]; } diff --git a/Frameworks/UIKit/UIApplicationMain.mm b/Frameworks/UIKit/UIApplicationMain.mm index 6c1df81045..3934f37f18 100644 --- a/Frameworks/UIKit/UIApplicationMain.mm +++ b/Frameworks/UIKit/UIApplicationMain.mm @@ -145,6 +145,25 @@ int UIApplicationMainInit(NSString* principalClassName, NSRunLoop* runLoop = [NSRunLoop currentRunLoop]; UIApplication* uiApplication; + // Register fonts listed in app's Info.plist, from the app's bundle + // This needs to happen before [UIApplication new]/[objc_getClass(pClassName) new] below, + // as they may attempt to use fonts from the app's bundle + if (infoDict) { + NSArray* fonts = [infoDict objectForKey:@"UIAppFonts"]; + if (fonts != nil) { + NSMutableArray* fontURLs = [NSMutableArray array]; + for (NSString* curFontName in fonts) { + // curFontName contains extension, so pass in nil + NSURL* url = [[NSBundle mainBundle] URLForResource:curFontName withExtension:nil]; + if (url != nil) { + [fontURLs addObject:url]; + } + } + + CTFontManagerRegisterFontsForURLs((CFArrayRef)fontURLs, kCTFontManagerScopeNone, nil); + } + } + if (principalClassName == nil) { principalClassName = [infoDict objectForKey:@"NSPrincipalClass"]; } @@ -168,21 +187,7 @@ int UIApplicationMainInit(NSString* principalClassName, [uiApplication setDelegate:delegateApp]; idretain rootController(nil); - if (infoDict != nil) { - NSArray* fonts = [infoDict objectForKey:@"UIAppFonts"]; - if (fonts != nil) { - NSMutableArray* fontURLs = [NSMutableArray array]; - for (NSString* curFontName in fonts) { - // curFontName contains extension, so pass in nil - NSURL* url = [[NSBundle mainBundle] URLForResource:curFontName withExtension:nil]; - if (url != nil) { - [fontURLs addObject:url]; - } - } - - CTFontManagerRegisterFontsForURLs((CFArrayRef)fontURLs, kCTFontManagerScopeNone, nil); - } - + if (infoDict) { if (defaultOrientation != UIInterfaceOrientationUnknown) { [uiApplication setStatusBarOrientation:defaultOrientation]; [uiApplication _setInternalOrientation:defaultOrientation]; diff --git a/Frameworks/UIKit/UIButton.mm b/Frameworks/UIKit/UIButton.mm index ed9b28e381..842aa62d73 100644 --- a/Frameworks/UIKit/UIButton.mm +++ b/Frameworks/UIKit/UIButton.mm @@ -272,7 +272,7 @@ - (void)setImage:(UIImage*)image forState:(UIControlState)state { // ConvertUIImageToWUXMImageBrush:nil creates a valid imageBrush with null comObj // which isn't what we want if (image) { - WUXMImageBrush* imageBrush = ConvertUIImageToWUXMImageBrush(image); + WUXMImageBrush* imageBrush = XamlUtilities::ConvertUIImageToWUXMImageBrush(image); if (imageBrush) { _states[state].inspectableImage = [imageBrush comObj]; } @@ -311,7 +311,7 @@ - (void)layoutSubviews { // Use the layer contents to draw the background image, similar to UIImageView. UIImageSetLayerContents([self layer], self.currentBackgroundImage); - // UIButton should always stretch its background. Since we're leveraging our backing CALayer's background for + // UIButton should always stretch its background. Since we're leveraging our backing CALayer's background for // the UIButton background, we stretch it via the CALayer's contentsGravity. self.layer.contentsGravity = kCAGravityResize; @@ -551,7 +551,7 @@ - (void)setTitleColor:(UIColor*)color forState:(UIControlState)state { // ConvertUIColorToWUColor:nil creates a valid WUColor with null comObj // which isn't what we want if (color) { - WUColor* convertedColor = ConvertUIColorToWUColor(color); + WUColor* convertedColor = XamlUtilities::ConvertUIColorToWUColor(color); WUXMSolidColorBrush* titleColorBrush = [WUXMSolidColorBrush makeInstanceWithColor:convertedColor]; if (titleColorBrush) { _states[state].inspectableTitleColor = [titleColorBrush comObj]; diff --git a/Frameworks/UIKit/UIButtonProxies.mm b/Frameworks/UIKit/UIButtonProxies.mm index ccff17aa63..e47dac8380 100644 --- a/Frameworks/UIKit/UIButtonProxies.mm +++ b/Frameworks/UIKit/UIButtonProxies.mm @@ -169,11 +169,11 @@ - (NSInteger)numberOfLines { } - (void)setTextAlignment:(UITextAlignment)alignment { - _xamlTextBlock.textAlignment = ConvertUITextAlignmentToWXTextAlignment(alignment); + _xamlTextBlock.textAlignment = XamlUtilities::ConvertUITextAlignmentToWXTextAlignment(alignment); } - (UITextAlignment)textAlignment { - return ConvertWXTextAlignmentToUITextAlignment(_xamlTextBlock.textAlignment); + return XamlUtilities::ConvertWXTextAlignmentToUITextAlignment(_xamlTextBlock.textAlignment); } - (void)setText:(NSString*)text { @@ -235,37 +235,7 @@ - (UIColor*)textColor { } - (void)setLineBreakMode:(UILineBreakMode)mode { - switch (mode) { - case UILineBreakModeWordWrap: - _xamlTextBlock.textTrimming = WXTextTrimmingNone; - _xamlTextBlock.textWrapping = WXTextWrappingWrapWholeWords; - break; - - case UILineBreakModeCharacterWrap: - _xamlTextBlock.textTrimming = WXTextTrimmingNone; - _xamlTextBlock.textWrapping = WXTextWrappingWrap; - break; - - case UILineBreakModeClip: - _xamlTextBlock.textWrapping = WXTextWrappingNoWrap; - _xamlTextBlock.textTrimming = WXTextTrimmingClip; - break; - - case UILineBreakModeHeadTruncation: - // GAP: currently textblock don't support UILineBreakModeHeadTruncation - UNIMPLEMENTED_WITH_MSG("UILineBreakModeHeadTruncation unsupported"); - break; - - case UILineBreakModeMiddleTruncation: - // GAP currently textblock don't support UILineBreakModeMiddleTruncation - UNIMPLEMENTED_WITH_MSG("UILineBreakModeMiddleTruncation unsupported"); - break; - - case UILineBreakModeTailTruncation: - _xamlTextBlock.textWrapping = WXTextWrappingNoWrap; - _xamlTextBlock.textTrimming = WXTextTrimmingCharacterEllipsis; - break; - } + XamlUtilities::ApplyLineBreakModeOnTextBlock(_xamlTextBlock, mode, self.numberOfLines); } - (UILineBreakMode)lineBreakMode { diff --git a/Frameworks/UIKit/UIGraphics.mm b/Frameworks/UIKit/UIGraphics.mm index 1b6038d1b6..bee80e1a03 100644 --- a/Frameworks/UIKit/UIGraphics.mm +++ b/Frameworks/UIKit/UIGraphics.mm @@ -90,12 +90,18 @@ BOOL UIFloatRangeIsEqualToRange(UIFloatRange range, UIFloatRange otherRange) { } /** - @Status Stub - @Notes -*/ -CTTextAlignment NSTextAlignmentToCTTextAlignment(NSTextAlignment nsTextAlignment) { - UNIMPLEMENTED(); - return StubReturn(); + @Status Interoperable + @Notes +*/ +CTTextAlignment NSTextAlignmentToCTTextAlignment(NSTextAlignment alignment) { + switch (alignment) { + case NSTextAlignmentRight: + return kCTRightTextAlignment; + case NSTextAlignmentCenter: + return kCTCenterTextAlignment; + default: + return alignment; + } } /** diff --git a/Frameworks/UIKit/UILabel.mm b/Frameworks/UIKit/UILabel.mm index 2dffeebe5e..dd73043448 100644 --- a/Frameworks/UIKit/UILabel.mm +++ b/Frameworks/UIKit/UILabel.mm @@ -106,20 +106,18 @@ - (void)adjustTextLayerSize { [_textBlock setFontFamily:[WUXMFontFamily makeInstanceWithName:[_font _compatibleFamilyName]]]; - [_textBlock setTextAlignment:ConvertUITextAlignmentToWXTextAlignment(_alignment)]; + [_textBlock setTextAlignment:XamlUtilities::ConvertUITextAlignmentToWXTextAlignment(_alignment)]; [_textBlock setLineHeight:[_font ascender] - [_font descender]]; - // Note: These were set in the compositor before the refactor. - // TODO: Revisit to fix the remaining text issues with the refactor. - [_textBlock setTextWrapping:WXTextWrappingWrap]; + XamlUtilities::ApplyLineBreakModeOnTextBlock(_textBlock, _lineBreakMode, self.numberOfLines); [_textBlock setLineStackingStrategy:WXLineStackingStrategyBlockLineHeight]; UIColor* color = _textColor; if (_isHighlighted && _highlightedTextColor != nil) { color = _highlightedTextColor; } - [_textBlock setForeground:[WUXMSolidColorBrush makeInstanceWithColor:ConvertUIColorToWUColor(color)]]; + [_textBlock setForeground:[WUXMSolidColorBrush makeInstanceWithColor:XamlUtilities::ConvertUIColorToWUColor(color)]]; [self invalidateIntrinsicContentSize]; [self setNeedsDisplay]; diff --git a/Frameworks/UIKit/UIScrollView.mm b/Frameworks/UIKit/UIScrollView.mm index fbf0bb4102..e33de6b8de 100644 --- a/Frameworks/UIKit/UIScrollView.mm +++ b/Frameworks/UIKit/UIScrollView.mm @@ -189,19 +189,11 @@ - (void)_initUIScrollView { _leftInset = [WUXSRectangle make]; _leftInset.name = @"left"; - // Create a content canvas for our subviews - _contentCanvas = [WXCCanvas make]; - _contentCanvas.name = @"Content Canvas"; - - // Create an image for our rendered content - _contentImage = [WXCImage make]; - _contentImage.name = @"Content Element"; + // Grab the content canvas for our subviews - we created it in createXamlElement + _contentCanvas = XamlControls::GetFrameworkElementSublayerCanvasProperty(_scrollViewer); - // Set up the CALayer properties for our backing Xaml element so - // our subviews are placed within our _contentCanvas - XamlControls::SetFrameworkElementLayerProperties(_scrollViewer, - _contentImage, // content element - _contentCanvas); // sublayer canvas + // Grab the image for our rendered content - we created it in createXamlElement + _contentImage = XamlControls::GetFrameworkElementLayerContentProperty(_scrollViewer); // creating and build 3 X 3 content grid _contentGrid = [WXCGrid make]; @@ -585,7 +577,8 @@ - (void)_setupLoadedEventHandler { // representation. if (strongSelf) { // Add the image to the parent of the scrollcontentpresenter - WXFrameworkElement* scrollContentPresenter = FindTemplateChild(strongSelf->_scrollViewer, @"ScrollContentPresenter"); + WXFrameworkElement* scrollContentPresenter = + XamlUtilities::FindTemplateChild(strongSelf->_scrollViewer, @"ScrollContentPresenter"); if (scrollContentPresenter) { WXCGrid* parent = rt_dynamic_cast(scrollContentPresenter.parent); [parent.children insertObject:strongSelf->_contentImage atIndex:0]; @@ -691,8 +684,26 @@ - (instancetype)initWithFrame:(CGRect)frame xamlElement:(WXFrameworkElement*)xam Microsoft Extension */ + (WXFrameworkElement*)createXamlElement { + WXCScrollViewer* scrollViewer = [WXCScrollViewer make]; + + // Create an image for our rendered content + WXCImage* contentImage = [WXCImage make]; + contentImage.name = @"Content Element"; + + // Create a content canvas for our subviews + WXCCanvas* contentCanvas = [WXCCanvas make]; + contentCanvas.name = @"Content Canvas"; + + // Set up the CALayer properties for our backing Xaml element so + // our subviews are placed within our contentCanvas + // Note: It's critical that we do this here in case subviews are added before _initUIScrollView has a chance + // to run (during initWithCoder, for example). + XamlControls::SetFrameworkElementLayerProperties(scrollViewer, + contentImage, // content element + contentCanvas); // sublayer canvas + // No autorelease needed because we compile with ARC - return [WXCScrollViewer make]; + return scrollViewer; } /** @@ -1377,10 +1388,10 @@ - (void)setContentInset:(UIEdgeInsets)inset { if (DEBUG_INSETS) { // setting different color on insets for debugging - _topInset.fill = [WUXMSolidColorBrush makeInstanceWithColor:ConvertUIColorToWUColor([UIColor redColor])]; - _bottomInset.fill = [WUXMSolidColorBrush makeInstanceWithColor:ConvertUIColorToWUColor([UIColor blueColor])]; - _leftInset.fill = [WUXMSolidColorBrush makeInstanceWithColor:ConvertUIColorToWUColor([UIColor redColor])]; - _rightInset.fill = [WUXMSolidColorBrush makeInstanceWithColor:ConvertUIColorToWUColor([UIColor blueColor])]; + _topInset.fill = [WUXMSolidColorBrush makeInstanceWithColor:XamlUtilities::ConvertUIColorToWUColor([UIColor redColor])]; + _bottomInset.fill = [WUXMSolidColorBrush makeInstanceWithColor:XamlUtilities::ConvertUIColorToWUColor([UIColor blueColor])]; + _leftInset.fill = [WUXMSolidColorBrush makeInstanceWithColor:XamlUtilities::ConvertUIColorToWUColor([UIColor redColor])]; + _rightInset.fill = [WUXMSolidColorBrush makeInstanceWithColor:XamlUtilities::ConvertUIColorToWUColor([UIColor blueColor])]; } } diff --git a/Frameworks/UIKit/UITextField.mm b/Frameworks/UIKit/UITextField.mm index bf019915d4..1fde03f671 100644 --- a/Frameworks/UIKit/UITextField.mm +++ b/Frameworks/UIKit/UITextField.mm @@ -61,14 +61,14 @@ @implementation _UIHiddenButtonView @end void SetTextControlContentVerticalAlignment(WXCControl* control, WXVerticalAlignment alignment) { - WXFrameworkElement* elem = FindTemplateChild(control, @"ContentElement"); + WXFrameworkElement* elem = XamlUtilities::FindTemplateChild(control, @"ContentElement"); // set verticalAligment of both content and placeholder of TextBox (or PasswordBox) to be the same value if (elem != nullptr) { elem.verticalAlignment = alignment; } - elem = FindTemplateChild(control, @"PlaceholderTextContentPresenter"); + elem = XamlUtilities::FindTemplateChild(control, @"PlaceholderTextContentPresenter"); if (elem != nullptr) { elem.verticalAlignment = alignment; } @@ -291,7 +291,7 @@ - (UIFont*)font { @Status Interoperable */ - (void)setTextColor:(UIColor*)color { - WUColor* convertedColor = ConvertUIColorToWUColor(color); + WUColor* convertedColor = XamlUtilities::ConvertUIColorToWUColor(color); WUXMSolidColorBrush* brush = [WUXMSolidColorBrush makeInstanceWithColor:convertedColor]; [_secureModeLock lock]; @@ -315,7 +315,7 @@ - (UIColor*)textColor { } if (colorBrush != nil) { - return ConvertWUColorToUIColor(colorBrush.color); + return XamlUtilities::ConvertWUColorToUIColor(colorBrush.color); } return nil; @@ -329,7 +329,7 @@ - (void)setBackgroundColor:(UIColor*)color { // When setting background color, clear out _backgroundImage assigning it to nil. _backgroundImage = nil; - WUColor* convertedColor = ConvertUIColorToWUColor(color); + WUColor* convertedColor = XamlUtilities::ConvertUIColorToWUColor(color); WUXMSolidColorBrush* brush = [WUXMSolidColorBrush makeInstanceWithColor:convertedColor]; [_secureModeLock lock]; @@ -346,16 +346,16 @@ - (void)setBackgroundColor:(UIColor*)color { */ - (UIColor*)backgroundColor { WUXMSolidColorBrush* colorBrush = nil; - if (_secureTextMode) { + if (_secureTextMode && _passwordBox.background != nullptr) { colorBrush = rt_dynamic_cast(_passwordBox.background); - } else { + } else if (!_secureTextMode && _textBox.background != nullptr) { colorBrush = rt_dynamic_cast(_textBox.background); } if (colorBrush != nil) { - return ConvertWUColorToUIColor(colorBrush.color); - } - + return XamlUtilities::ConvertWUColorToUIColor(colorBrush.color); + } + return nil; } @@ -366,7 +366,7 @@ - (void)setTextAlignment:(UITextAlignment)alignment { [_secureModeLock lock]; if (!_secureTextMode) { // passwordBox does not support text alignment - _textBox.textAlignment = ConvertUITextAlignmentToWXTextAlignment(alignment); + _textBox.textAlignment = XamlUtilities::ConvertUITextAlignmentToWXTextAlignment(alignment); } else { UNIMPLEMENTED_WITH_MSG("SecureTextEntry mode does not support UITextAlignment"); } @@ -380,7 +380,7 @@ - (UITextAlignment)textAlignment { if (_secureTextMode) { return UITextAlignmentLeft; } else { - return ConvertWXTextAlignmentToUITextAlignment(_textBox.textAlignment); + return XamlUtilities::ConvertWXTextAlignmentToUITextAlignment(_textBox.textAlignment); } } @@ -570,12 +570,12 @@ - (void)setBorderStyle:(UITextBorderStyle)style { [_secureModeLock lock]; if (_secureTextMode) { - SetControlBorderStyle(_passwordBox, _borderStyle); + XamlUtilities::SetControlBorderStyle(_passwordBox, _borderStyle); } else { - SetControlBorderStyle(_textBox, _borderStyle); + XamlUtilities::SetControlBorderStyle(_textBox, _borderStyle); } - WUColor* convertedColor = ConvertUIColorToWUColor(self.backgroundColor); + WUColor* convertedColor = XamlUtilities::ConvertUIColorToWUColor(self.backgroundColor); WUXMSolidColorBrush* brush = [WUXMSolidColorBrush makeInstanceWithColor:convertedColor]; // If _borderStyle is set to the UITextBorderStyleRoundedRect, @@ -624,7 +624,7 @@ - (void)setBackground:(UIImage*)image { if (_borderStyle != UITextBorderStyleRoundedRect) { Microsoft::WRL::ComPtr inspectableNode(DisplayTexture::GetBitmapForCGImage(cgImg)); - WUXMIBitmapSource* bitmapImageSource = CreateRtProxy([WUXMIBitmapSource class], inspectableNode.Get()); + WUXMIBitmapSource* bitmapImageSource = XamlUtilities::CreateRtProxy([WUXMIBitmapSource class], inspectableNode.Get()); WUXMImageBrush* imageBrush = [WUXMImageBrush make]; imageBrush.imageSource = bitmapImageSource; @@ -928,9 +928,9 @@ - (void)setKeyboardType:(UIKeyboardType)type { [_secureModeLock lock]; if (_secureTextMode) { - _passwordBox.inputScope = ConvertKeyboardTypeToInputScope(_keyboardType, YES); + _passwordBox.inputScope = XamlUtilities::ConvertKeyboardTypeToInputScope(_keyboardType, YES); } else { - _textBox.inputScope = ConvertKeyboardTypeToInputScope(_keyboardType, NO); + _textBox.inputScope = XamlUtilities::ConvertKeyboardTypeToInputScope(_keyboardType, NO); } [_secureModeLock unlock]; } @@ -1155,7 +1155,8 @@ - (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event { - (void)setContentVerticalAlignment:(UIControlContentVerticalAlignment)alignment { [super setContentVerticalAlignment:alignment]; - WXVerticalAlignment verticalAlignment = ConvertUIControlContentVerticalAlignmentToWXVerticalAlignment(self.contentVerticalAlignment); + WXVerticalAlignment verticalAlignment = + XamlUtilities::ConvertUIControlContentVerticalAlignmentToWXVerticalAlignment(self.contentVerticalAlignment); [_secureModeLock lock]; if (self.secureTextEntry) { @@ -1349,17 +1350,17 @@ - (void)_initTextBox:(WXFrameworkElement*)xamlElement { // if passwordbox exits, need to transfer the properties that we set on passwordbox to textbox if (_passwordBox != nil) { if (_backgroundImage == nil || self.borderStyle == UITextBorderStyleRoundedRect) { - WUColor* convertedColor = ConvertUIColorToWUColor(self.backgroundColor); + WUColor* convertedColor = XamlUtilities::ConvertUIColorToWUColor(self.backgroundColor); WUXMSolidColorBrush* brush = [WUXMSolidColorBrush makeInstanceWithColor:convertedColor]; _textBox.background = brush; } - WUColor* convertedTextColor = ConvertUIColorToWUColor(self.textColor); + WUColor* convertedTextColor = XamlUtilities::ConvertUIColorToWUColor(self.textColor); WUXMSolidColorBrush* textBrush = [WUXMSolidColorBrush makeInstanceWithColor:convertedTextColor]; _textBox.foreground = textBrush; - _textBox.textAlignment = ConvertUITextAlignmentToWXTextAlignment(self.textAlignment); - _textBox.inputScope = ConvertKeyboardTypeToInputScope(_keyboardType, NO); + _textBox.textAlignment = XamlUtilities::ConvertUITextAlignmentToWXTextAlignment(self.textAlignment); + _textBox.inputScope = XamlUtilities::ConvertKeyboardTypeToInputScope(_keyboardType, NO); _textBox.text = self.text; _textBox.placeholderText = self.placeholder; _textBox.isSpellCheckEnabled = (self.spellCheckingType == UITextSpellCheckingTypeYes); @@ -1372,13 +1373,13 @@ - (void)_initTextBox:(WXFrameworkElement*)xamlElement { __weak UITextField* weakSelf = self; [self->_textBox addLoadedEvent:^void(RTObject* sender, WXRoutedEventArgs* e) { __strong UITextField* strongSelf = weakSelf; - SetControlBorderStyle(strongSelf->_textBox, strongSelf.borderStyle); + XamlUtilities::SetControlBorderStyle(strongSelf->_textBox, strongSelf.borderStyle); WXVerticalAlignment verticalAlignment = - ConvertUIControlContentVerticalAlignmentToWXVerticalAlignment(strongSelf.contentVerticalAlignment); + XamlUtilities::ConvertUIControlContentVerticalAlignmentToWXVerticalAlignment(strongSelf.contentVerticalAlignment); SetTextControlContentVerticalAlignment(strongSelf->_textBox, verticalAlignment); // retrieve the ContentElement from the template - WXFrameworkElement* frameworkElement = FindTemplateChild(strongSelf->_textBox, @"ContentElement"); + WXFrameworkElement* frameworkElement = XamlUtilities::FindTemplateChild(strongSelf->_textBox, @"ContentElement"); strongSelf->_textContentElement = (frameworkElement != nullptr) ? rt_dynamic_cast(frameworkElement) : nullptr; if (strongSelf->_textContentElement == nullptr) { @@ -1425,22 +1426,22 @@ - (void)_initPasswordBox:(WXFrameworkElement*)xamlElement { // if textbox exists, need to transfer the properties from textbox to passwordbox if (_textBox != nil) { if (_backgroundImage == nil || self.borderStyle == UITextBorderStyleRoundedRect) { - WUColor* convertedColor = ConvertUIColorToWUColor(self.backgroundColor); + WUColor* convertedColor = XamlUtilities::ConvertUIColorToWUColor(self.backgroundColor); WUXMSolidColorBrush* brush = [WUXMSolidColorBrush makeInstanceWithColor:convertedColor]; _passwordBox.background = brush; } - WUColor* convertedTextColor = ConvertUIColorToWUColor(self.textColor); + WUColor* convertedTextColor = XamlUtilities::ConvertUIColorToWUColor(self.textColor); WUXMSolidColorBrush* textBrush = [WUXMSolidColorBrush makeInstanceWithColor:convertedTextColor]; _passwordBox.foreground = textBrush; // passwordBox does not support textAlignment // border manipulate the control tempate and must be done after loaded - SetControlBorderStyle(_passwordBox, self.borderStyle); + XamlUtilities::SetControlBorderStyle(_passwordBox, self.borderStyle); WXVerticalAlignment verticalAlignment = - ConvertUIControlContentVerticalAlignmentToWXVerticalAlignment(self.contentVerticalAlignment); + XamlUtilities::ConvertUIControlContentVerticalAlignmentToWXVerticalAlignment(self.contentVerticalAlignment); SetTextControlContentVerticalAlignment(_passwordBox, verticalAlignment); - _passwordBox.inputScope = ConvertKeyboardTypeToInputScope(_keyboardType, YES); + _passwordBox.inputScope = XamlUtilities::ConvertKeyboardTypeToInputScope(_keyboardType, YES); _passwordBox.password = self.text; _passwordBox.placeholderText = self.placeholder; @@ -1454,13 +1455,13 @@ - (void)_initPasswordBox:(WXFrameworkElement*)xamlElement { [self->_passwordBox addLoadedEvent:^void(RTObject* sender, WXRoutedEventArgs* e) { __strong UITextField* strongSelf = weakSelf; - SetControlBorderStyle(strongSelf->_passwordBox, strongSelf.borderStyle); + XamlUtilities::SetControlBorderStyle(strongSelf->_passwordBox, strongSelf.borderStyle); WXVerticalAlignment verticalAlignment = - ConvertUIControlContentVerticalAlignmentToWXVerticalAlignment(strongSelf.contentVerticalAlignment); + XamlUtilities::ConvertUIControlContentVerticalAlignmentToWXVerticalAlignment(strongSelf.contentVerticalAlignment); SetTextControlContentVerticalAlignment(strongSelf->_passwordBox, verticalAlignment); // retrieve the ContentElement from the template - WXFrameworkElement* frameworkElement = FindTemplateChild(strongSelf->_passwordBox, @"ContentElement"); + WXFrameworkElement* frameworkElement = XamlUtilities::FindTemplateChild(strongSelf->_passwordBox, @"ContentElement"); strongSelf->_textContentElement = (frameworkElement != nullptr) ? rt_dynamic_cast(frameworkElement) : nullptr; if (strongSelf->_textContentElement == nullptr) { diff --git a/Frameworks/UIKit/UIViewController.mm b/Frameworks/UIKit/UIViewController.mm index 67cb4f3942..e7a3dd8135 100644 --- a/Frameworks/UIKit/UIViewController.mm +++ b/Frameworks/UIKit/UIViewController.mm @@ -795,8 +795,8 @@ - (instancetype)initWithNibName:(NSString*)strNib bundle:(NSBundle*)bundle { } // Load the XAML version if found. First prepend the auto-generated XAML namespace to the XAML class name - NSString* xamlClassName = [NSString stringWithFormat:@"%@.%@", XamlAutoGenNamespace, strNib]; - auto xamlType = ReturnXamlType(xamlClassName); + NSString* xamlClassName = [NSString stringWithFormat:@"%@.%@", XamlUtilities::XamlAutoGenNamespace, strNib]; + auto xamlType = XamlUtilities::ReturnXamlType(xamlClassName); if (xamlType.Get() != nullptr) { priv->_xamlClassName = xamlClassName; } @@ -893,13 +893,14 @@ - (void)loadView { TraceVerbose(TAG, L"Loading view %hs with owner=%hs", name ? name : "nil", object_getClassName(self)); if (EbrAccess(openname, 0) != -1) { - UIStoryboard* proxyObjects[1]; - NSString* proxyNames[1]; + UIStoryboard* proxyObject = [self storyboard]; + NSString* proxyName = @"UIStoryboardPlaceholder"; - proxyObjects[0] = [self storyboard]; - proxyNames[0] = @"UIStoryboardPlaceholder"; + NSMutableDictionary* proxyObjectsDict = [NSMutableDictionary dictionary]; + if (proxyObject != nil) { + [proxyObjectsDict setObject:proxyObject forKey:proxyName]; + } - NSMutableDictionary* proxyObjectsDict = [NSMutableDictionary dictionaryWithObjects:proxyObjects forKeys:proxyNames count:1]; [proxyObjectsDict addEntriesFromDictionary:priv->_externalObjects]; UINib* nib = [UINib nibWithNibName:[NSString stringWithCString:openname] bundle:priv->nibBundle]; @@ -1177,12 +1178,13 @@ - (void)presentViewController:(UIViewController*)controller animated:(BOOL)anima } if (visibleParent->priv->_visibility != controllerVisible) { - TraceWarning(TAG, - L"Presenting view controller %08x (%hs) on view controller %08x (%hs) which is not yet fully visible - continuing anyway.", - controller, - object_getClassName(controller), - visibleParent, - object_getClassName(visibleParent)); + TraceWarning( + TAG, + L"Presenting view controller %08x (%hs) on view controller %08x (%hs) which is not yet fully visible - continuing anyway.", + controller, + object_getClassName(controller), + visibleParent, + object_getClassName(visibleParent)); } if (visibleParent != self) { @@ -1206,7 +1208,8 @@ - (void)presentViewController:(UIViewController*)controller animated:(BOOL)anima controller->priv->_presentingViewController = self; if ([controller modalPresentationStyle] == UIModalPresentationPopover) { - controller->priv->_popoverPresentationController.attach([[UIPopoverPresentationController alloc] initWithPresentedViewController:controller presentingViewController:self]); + controller->priv->_popoverPresentationController.attach( + [[UIPopoverPresentationController alloc] initWithPresentedViewController:controller presentingViewController:self]); dispatch_block_t popoverPresent = ^{ [[UIApplication sharedApplication] endIgnoringInteractionEvents]; @@ -1225,7 +1228,9 @@ - (void)presentViewController:(UIViewController*)controller animated:(BOOL)anima dispatch_async(dispatch_get_main_queue(), ^{ // Dispatch the presentation asynchronously so users have the opportunity to configure the // popoverPresentationController after presentViewController but before the actual popover is presented. - [controller->priv->_popoverPresentationController _presentAnimated:animated presentCompletion:popoverPresent dismissCompletion:popoverDismiss]; + [controller->priv->_popoverPresentationController _presentAnimated:animated + presentCompletion:popoverPresent + dismissCompletion:popoverDismiss]; }); } else { controller->priv->_presentCompletionBlock.attach([completion copy]); @@ -1281,7 +1286,8 @@ - (void)_childDismissCleanup { */ - (void)dismissViewControllerAnimated:(BOOL)animated completion:(void (^)(void))completion { if (!priv->_presentedViewController) { - // Calling dismiss on a view controller that hasn't presented additional view controllers itself should result in the parent handling the dismissal. + // Calling dismiss on a view controller that hasn't presented additional view controllers itself should result in the parent + // handling the dismissal. if ([self parentViewController]) { [[self parentViewController] dismissViewControllerAnimated:animated completion:completion]; @@ -1304,23 +1310,24 @@ - (void)dismissViewControllerAnimated:(BOOL)animated completion:(void (^)(void)) // Dismiss the youngest first with specified animation __unsafe_unretained __block UIViewController* parent = [grandChild parentViewController]; - [parent dismissViewControllerAnimated:animated completion:^{ - // Dismiss the remaining with no animation - do { - parent = [parent parentViewController]; - // We rely on dismissViewControllerAnimated:NO blocking until child dismissal - [parent dismissViewControllerAnimated:NO completion:nil]; - } while (parent != self); - - if (completion) { - completion(); - } - }]; + [parent dismissViewControllerAnimated:animated + completion:^{ + // Dismiss the remaining with no animation + do { + parent = [parent parentViewController]; + // We rely on dismissViewControllerAnimated:NO blocking until child dismissal + [parent dismissViewControllerAnimated:NO completion:nil]; + } while (parent != self); + + if (completion) { + completion(); + } + }]; return; } - __block __unsafe_unretained UIViewController *weakSelf = self; + __block __unsafe_unretained UIViewController* weakSelf = self; dispatch_block_t cleanupCompletion = ^{ StrongId strongSelf = weakSelf; [strongSelf _childDismissCleanup]; @@ -1417,7 +1424,6 @@ - (void)_transitionStopped:(id)context { } - (void)_addToTop:(NSNumber*)animatedValue { - if (![self parentViewController]) { TraceError(TAG, L"Modal controller doesn't have a parent!"); [[UIApplication sharedApplication] endIgnoringInteractionEvents]; @@ -1852,7 +1858,7 @@ - (void)_loadXamlPage { // Activate an instance of the XAML class and its page Microsoft::WRL::ComPtr pageObj = nullptr; - auto xamlType = ReturnXamlType(priv->_xamlClassName); + auto xamlType = XamlUtilities::ReturnXamlType(priv->_xamlClassName); xamlType->ActivateInstance(pageObj.GetAddressOf()); [_pageMappings setObject:self forKey:(id)(void*)pageObj.Get()]; @@ -1873,7 +1879,7 @@ - (void)_loadXamlPage { if (propName) { NSString* propNameString = [NSString stringWithCString:propName]; RTObject* obj = [priv->_page findName:propNameString]; - UIView* control = GenerateUIKitControlFromXamlType(obj); + UIView* control = XamlUtilities::GenerateUIKitControlFromXamlType(obj); if (control != nil) { [self setValue:control forKey:propNameString]; } @@ -2141,7 +2147,7 @@ - (void)performSegueWithIdentifier:(NSString*)identifier sender:(id)sender { NSString* controllerName = nil; UIStoryboardSegueTemplate* segueTemplate = nil; - for (UIStoryboardSegueTemplate* cur in(NSArray*)priv->_modalTemplates) { + for (UIStoryboardSegueTemplate* cur in (NSArray*)priv->_modalTemplates) { if ([[cur identifier] isEqualToString:identifier]) { controllerName = [cur destination]; segueTemplate = cur; @@ -2172,7 +2178,7 @@ - (void)performSegueWithDestination:(NSString*)destination sender:(id)sender { NSString* controllerName = nil; UIStoryboardSegueTemplate* segueTemplate = nil; - for (UIStoryboardSegueTemplate* cur in(NSArray*)priv->_modalTemplates) { + for (UIStoryboardSegueTemplate* cur in (NSArray*)priv->_modalTemplates) { if ([[cur destination] isEqualToString:destination]) { controllerName = [cur destination]; segueTemplate = cur; @@ -2320,7 +2326,7 @@ - (void)dealloc { // Remove us from being the parent of our child view controller. // Should we call controller->removeFromParentViewController instead? - for (UIViewController* curController in(NSArray*)priv->_childViewControllers) { + for (UIViewController* curController in (NSArray*)priv->_childViewControllers) { curController->priv->_parentViewController = nil; } diff --git a/Frameworks/UIKit/UIWebView.mm b/Frameworks/UIKit/UIWebView.mm index 14ec7272eb..90c0f2cab4 100644 --- a/Frameworks/UIKit/UIWebView.mm +++ b/Frameworks/UIKit/UIWebView.mm @@ -155,6 +155,15 @@ static void _initUIWebView(UIWebView* self) { } }]; + // Add handler which will be invoked when user calls window.external.notify(msg) function in javascript + [self->_xamlWebControl addScriptNotifyEvent:^void(RTObject* sender, WXCNotifyEventArgs* e) { + // Send event to webView delegate + NSURL* url = [NSURL URLWithString:e.callingUri.absoluteUri]; + if ([weakSelf->_delegate respondsToSelector:@selector(webView:scriptNotify:value:)]) { + [weakSelf->_delegate webView:weakSelf scriptNotify:url value:e.value]; + } + }]; + CGRect bounds; bounds = [self bounds]; @@ -244,7 +253,7 @@ - (void)setDetectsPhoneNumbers:(BOOL)detect { } /** - @Status Gap + @Status Stub */ - (NSString*)stringByEvaluatingJavaScriptFromString:(NSString*)string { UNIMPLEMENTED_WITH_MSG( diff --git a/Frameworks/UIKit/XamlControls.h b/Frameworks/UIKit/XamlControls.h index b79eda12c6..5ef577ff08 100644 --- a/Frameworks/UIKit/XamlControls.h +++ b/Frameworks/UIKit/XamlControls.h @@ -128,4 +128,11 @@ WXCTextBlock* GetLabelTextBlock(WXCGrid* labelGrid); void SetFrameworkElementLayerProperties(WXFrameworkElement* targetElement, WXCImage* layerContentProperty, WXCCanvas* sublayerCanvasProperty); + +// Get the layerContentProperty for the specified target xaml element +WXCImage* GetFrameworkElementLayerContentProperty(WXFrameworkElement* targetElement); + +// Get the sublayerCanvasProperty for the specified target xaml element +WXCCanvas* GetFrameworkElementSublayerCanvasProperty(WXFrameworkElement* targetElement); + } // namespace XamlControls \ No newline at end of file diff --git a/Frameworks/UIKit/XamlControls.mm b/Frameworks/UIKit/XamlControls.mm index 684d308d23..5dd40bbdf7 100644 --- a/Frameworks/UIKit/XamlControls.mm +++ b/Frameworks/UIKit/XamlControls.mm @@ -73,7 +73,7 @@ unsigned int XamlContentDialogAddButtonWithTitle(WXCContentDialog* contentDialog ComPtr inspectable([contentDialog comObj]); ComPtr inspPropVal(XamlContentDialogButtonTitleAtIndex(inspectable, buttonIndex)); - return NSStringFromPropertyValue(inspPropVal); + return XamlUtilities::NSStringFromPropertyValue(inspPropVal); } unsigned int XamlContentDialogNumberOfButtons(WXCContentDialog* contentDialog) { @@ -115,4 +115,14 @@ void SetFrameworkElementLayerProperties(WXFrameworkElement* targetElement, sublayerCanvasProperty ? [sublayerCanvasProperty comObj] : nullptr); } +WXCImage* GetFrameworkElementLayerContentProperty(WXFrameworkElement* targetElement) { + Microsoft::WRL::ComPtr inspectable(XamlGetFrameworkElementLayerContentProperty([targetElement comObj])); + return _createRtProxy([WXCImage class], inspectable.Get()); +} + +WXCCanvas* GetFrameworkElementSublayerCanvasProperty(WXFrameworkElement* targetElement) { + Microsoft::WRL::ComPtr inspectable(XamlGetFrameworkElementSublayerCanvasProperty([targetElement comObj])); + return _createRtProxy([WXCCanvas class], inspectable.Get()); +} + } // namespace XamlControls \ No newline at end of file diff --git a/Frameworks/UIKit/XamlUtilities.h b/Frameworks/UIKit/XamlUtilities.h index 1a044226e5..61dec1ab2b 100644 --- a/Frameworks/UIKit/XamlUtilities.h +++ b/Frameworks/UIKit/XamlUtilities.h @@ -33,6 +33,7 @@ #include "Windows.UI.Xaml.Markup.h" #include "COMIncludes_End.h" +namespace XamlUtilities { NSString* const XamlAutoGenNamespace = @"IslandwoodAutoGenNamespace"; WUXMFontFamily* WUXFontFamilyFromUIFontName(NSString* uiFontName); @@ -82,3 +83,7 @@ UIView* GenerateUIKitControlFromXamlType(RTObject* xamlObject); // We need a type-safe way to do this with projections. This is copied verbatim from the projections // code and works perfectly for this limited usage, but we don't do any type validation below. id CreateRtProxy(Class cls, IInspectable* iface); + +// apply LineBreakMode on xaml TextBock +void ApplyLineBreakModeOnTextBlock(WXCTextBlock* textBlock, UILineBreakMode mode, int numberOfLines); +} \ No newline at end of file diff --git a/Frameworks/UIKit/XamlUtilities.mm b/Frameworks/UIKit/XamlUtilities.mm index f4c49feb2c..c4085f7259 100644 --- a/Frameworks/UIKit/XamlUtilities.mm +++ b/Frameworks/UIKit/XamlUtilities.mm @@ -29,11 +29,13 @@ using namespace Microsoft::WRL; using namespace Windows::Foundation; +using namespace XamlUtilities; + // cornerRadius when border style is set to round rectangle static const int c_borderCornerRadius = 8; static const wchar_t* TAG = L"XamlUtilities"; -WUColor* ConvertUIColorToWUColor(UIColor* uiColor) { +WUColor* XamlUtilities::ConvertUIColorToWUColor(UIColor* uiColor) { CGFloat r, g, b, a; [uiColor getRed:&r green:&g blue:&b alpha:&a]; @@ -41,11 +43,15 @@ [WUColorHelper fromArgb:(unsigned char)(a * 255) r:(unsigned char)(r * 255) g:(unsigned char)(g * 255) b:(unsigned char)(b * 255)]; } -UIColor* ConvertWUColorToUIColor(WUColor* wuColor) { - return [UIColor colorWithRed:wuColor.r / 255 green:wuColor.g / 255 blue:wuColor.b / 255 alpha:wuColor.a / 255]; +UIColor* XamlUtilities::ConvertWUColorToUIColor(WUColor* wuColor) { + CGFloat r = wuColor.r / 255.0; + CGFloat g = wuColor.g / 255.0; + CGFloat b = wuColor.b / 255.0; + CGFloat a = wuColor.a / 255.0; + return [UIColor colorWithRed:r green:g blue:b alpha:a]; } -WUXMImageBrush* ConvertUIImageToWUXMImageBrush(UIImage* image) { +WUXMImageBrush* XamlUtilities::ConvertUIImageToWUXMImageBrush(UIImage* image) { if (!image) { return nil; } @@ -59,7 +65,7 @@ return imageBrush; } -WUXMIBitmapSource* ConvertUIImageToWUXMIBitmapSource(UIImage* image) { +WUXMIBitmapSource* XamlUtilities::ConvertUIImageToWUXMIBitmapSource(UIImage* image) { if (!image) { return nil; } @@ -71,7 +77,7 @@ return bitmapImageSource; } -WXTextAlignment ConvertUITextAlignmentToWXTextAlignment(UITextAlignment alignment) { +WXTextAlignment XamlUtilities::ConvertUITextAlignmentToWXTextAlignment(UITextAlignment alignment) { switch (alignment) { case UITextAlignmentLeft: return WXTextAlignmentLeft; @@ -89,7 +95,7 @@ WXTextAlignment ConvertUITextAlignmentToWXTextAlignment(UITextAlignment alignmen return UITextAlignmentLeft; } -UITextAlignment ConvertWXTextAlignmentToUITextAlignment(WXTextAlignment alignment) { +UITextAlignment XamlUtilities::ConvertWXTextAlignmentToUITextAlignment(WXTextAlignment alignment) { switch (alignment) { case WXTextAlignmentLeft: return UITextAlignmentLeft; @@ -107,7 +113,7 @@ UITextAlignment ConvertWXTextAlignmentToUITextAlignment(WXTextAlignment alignmen return UITextAlignmentLeft; } -WUXIInputScope* ConvertKeyboardTypeToInputScope(UIKeyboardType keyboardType, BOOL secureTextMode) { +WUXIInputScope* XamlUtilities::ConvertKeyboardTypeToInputScope(UIKeyboardType keyboardType, BOOL secureTextMode) { WUXIInputScopeName* inputScopeName = [WUXIInputScopeName make]; inputScopeName.nameValue = WUXIInputScopeNameValueDefault; @@ -173,7 +179,8 @@ UITextAlignment ConvertWXTextAlignmentToUITextAlignment(WXTextAlignment alignmen return inputScope; } -WXVerticalAlignment ConvertUIControlContentVerticalAlignmentToWXVerticalAlignment(UIControlContentVerticalAlignment alignment) { +WXVerticalAlignment XamlUtilities::ConvertUIControlContentVerticalAlignmentToWXVerticalAlignment( + UIControlContentVerticalAlignment alignment) { WXVerticalAlignment ret = WXVerticalAlignmentTop; switch (alignment) { @@ -194,7 +201,7 @@ WXVerticalAlignment ConvertUIControlContentVerticalAlignmentToWXVerticalAlignmen return ret; } -WXFrameworkElement* FindTemplateChild(WXCControl* control, NSString* name) { +WXFrameworkElement* XamlUtilities::FindTemplateChild(WXCControl* control, NSString* name) { WXFrameworkElement* target = nullptr; unsigned int count = [WUXMVisualTreeHelper getChildrenCount:control]; if (count > 0) { @@ -207,13 +214,13 @@ WXVerticalAlignment ConvertUIControlContentVerticalAlignmentToWXVerticalAlignmen return target; } -NSString* NSStringFromPropertyValue(RTObject* rtPropertyValue) { +NSString* XamlUtilities::NSStringFromPropertyValue(RTObject* rtPropertyValue) { // BUGBUG:8791977 - WFIPropertyValue is not publicly exposed via projections so we used a workaround ComPtr inspPropVal = [rtPropertyValue comObj]; return NSStringFromPropertyValue(inspPropVal); } -NSString* NSStringFromPropertyValue(const ComPtr& inspPropertyValue) { +NSString* XamlUtilities::NSStringFromPropertyValue(const ComPtr& inspPropertyValue) { ComPtr propVal; HRESULT hr = inspPropertyValue.As(&propVal); if (SUCCEEDED(hr)) { @@ -230,7 +237,7 @@ WXVerticalAlignment ConvertUIControlContentVerticalAlignmentToWXVerticalAlignmen } // Setup control border style -void SetControlBorderStyle(WXCControl* control, UITextBorderStyle style) { +void XamlUtilities::SetControlBorderStyle(WXCControl* control, UITextBorderStyle style) { switch (style) { case UITextBorderStyleNone: control.borderThickness = [WXThicknessHelper fromUniformLength:0]; @@ -258,7 +265,7 @@ void SetControlBorderStyle(WXCControl* control, UITextBorderStyle style) { } } -ComPtr ReturnXamlType(NSString* xamlClassName) { +ComPtr XamlUtilities::ReturnXamlType(NSString* xamlClassName) { static ComPtr xamlMetaProvider; if (!xamlMetaProvider) { @@ -278,7 +285,7 @@ void SetControlBorderStyle(WXCControl* control, UITextBorderStyle style) { return nullptr; } -UIView* GenerateUIKitControlFromXamlType(RTObject* xamlObject) { +UIView* XamlUtilities::GenerateUIKitControlFromXamlType(RTObject* xamlObject) { if (xamlObject == nil) { return nil; } @@ -312,7 +319,7 @@ void SetControlBorderStyle(WXCControl* control, UITextBorderStyle style) { return control; } -id CreateRtProxy(Class cls, IInspectable* iface) { +id XamlUtilities::CreateRtProxy(Class cls, IInspectable* iface) { // Oddly, WinRT can hand us back NULL objects from successful function calls. Plumb these through as nil. if (!iface) { return nil; @@ -323,3 +330,49 @@ id CreateRtProxy(Class cls, IInspectable* iface) { return ret; } + +void XamlUtilities::ApplyLineBreakModeOnTextBlock(WXCTextBlock* textBlock, UILineBreakMode mode, int numberOfLines) { + // wrapping or not on reference platform is ultimatly decided by numberofLines of UILabel + // e.g., if nubmerOfLines is 1, even though lineBreakMode can be set as UILineBreakModeWordWrap etc, no wrapping is happening. + if (numberOfLines == 1) { + textBlock.textWrapping = WXTextWrappingNoWrap; + } else { + textBlock.textWrapping = WXTextWrappingWrap; + } + + switch (mode) { + case UILineBreakModeWordWrap: + // when wrapping is allowed, no text trimming is happening + textBlock.textTrimming = WXTextTrimmingNone; + break; + + case UILineBreakModeCharacterWrap: + // GAP: currently textblock don't support UILineBreakModeCharacterWrap + UNIMPLEMENTED_WITH_MSG("UILineBreakModeCharacterWrap unsupported, using UILineBreakModeWordWrap instead"); + + // when wrapping is allowed, no text trimming is happening + textBlock.textTrimming = WXTextTrimmingNone; + break; + + case UILineBreakModeClip: + textBlock.textTrimming = WXTextTrimmingClip; + break; + + case UILineBreakModeHeadTruncation: + // GAP: currently textblock don't support UILineBreakModeHeadTruncation + UNIMPLEMENTED_WITH_MSG("UILineBreakModeHeadTruncation unsupported, using UILineBreakModeTailTruncation instead"); + textBlock.textTrimming = WXTextTrimmingCharacterEllipsis; + break; + + case UILineBreakModeMiddleTruncation: + // GAP currently textblock don't support UILineBreakModeMiddleTruncation + UNIMPLEMENTED_WITH_MSG("UILineBreakModeMiddleTruncation unsupported, using UILineBreakModeTailTruncation instead"); + textBlock.textTrimming = WXTextTrimmingCharacterEllipsis; + break; + + case UILineBreakModeTailTruncation: + // this is only truncation supported + textBlock.textTrimming = WXTextTrimmingCharacterEllipsis; + break; + } +} diff --git a/Frameworks/include/LinkedList.h b/Frameworks/include/LinkedList.h index 0376a93c18..c59fa5ab54 100644 --- a/Frameworks/include/LinkedList.h +++ b/Frameworks/include/LinkedList.h @@ -18,6 +18,7 @@ #define __UTILS_LINKEDLIST_H #include +#include #ifdef EBRIUS #include "Foundation/NSArray.h" #endif diff --git a/Frameworks/include/NSParagraphStyleInternal.h b/Frameworks/include/NSParagraphStyleInternal.h index 87bf432ef1..25c9a25da1 100644 --- a/Frameworks/include/NSParagraphStyleInternal.h +++ b/Frameworks/include/NSParagraphStyleInternal.h @@ -41,16 +41,4 @@ @property (nonatomic, readwrite) CGFloat defaultTabInterval; @property (nonatomic, readwrite) float hyphenationFactor; -@end - -// The values of right and center CTTextAlignment and NSTextAlignment do not correspond so they can't be simply cast -inline CTTextAlignment _NSTextAlignmentToCTTextAlignment(NSTextAlignment alignment) { - switch (alignment) { - case NSTextAlignmentRight: - return kCTRightTextAlignment; - case NSTextAlignmentCenter: - return kCTCenterTextAlignment; - default: - return alignment; - } -} +@end \ No newline at end of file diff --git a/Frameworks/include/UIViewInternal.h b/Frameworks/include/UIViewInternal.h index 2e03d94b45..a82e3a7c41 100644 --- a/Frameworks/include/UIViewInternal.h +++ b/Frameworks/include/UIViewInternal.h @@ -17,6 +17,7 @@ #pragma once #import "LinkedList.h" +#import #import #import #import diff --git a/bin/Xib2Nib.exe b/bin/Xib2Nib.exe deleted file mode 100644 index 63a7b1ff5b..0000000000 --- a/bin/Xib2Nib.exe +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:7d9e07802f69d03dce71d1042311e756d002d7b3000c23039f2ecff5e9aa42e9 -size 293888 diff --git a/bin/objc2winmd.exe b/bin/objc2winmd.exe index 5bab139033..d449fe1f53 100644 --- a/bin/objc2winmd.exe +++ b/bin/objc2winmd.exe @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:04e64afbcb82c2f5b3ccddac1bcb76849acbb8cdb1e873d5485f59af92edd621 -size 2290688 +oid sha256:6b36378d4c5f733ac18480746eb3dd34b06c11c3da96e8efef1994faeaaee1c9 +size 2294784 diff --git a/bin/xib2nib.exe b/bin/xib2nib.exe new file mode 100644 index 0000000000..2352ebb9e4 --- /dev/null +++ b/bin/xib2nib.exe @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ac9ffe783fd2df90b38d76b61d44f4a7507645b0c058273c50c74ce261af359b +size 294912 diff --git a/build/OpenGLES/dll/OpenGLES.vcxproj b/build/OpenGLES/dll/OpenGLES.vcxproj index 0155abe4ea..fac9b89574 100644 --- a/build/OpenGLES/dll/OpenGLES.vcxproj +++ b/build/OpenGLES/dll/OpenGLES.vcxproj @@ -1,4 +1,4 @@ - + @@ -120,12 +120,12 @@ COPY /Y "$(angle-BinPath)\libGLESv2.dll" "$(OutDir)libGLESv2.dll" - + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - + \ No newline at end of file diff --git a/build/OpenGLES/dll/packages.config b/build/OpenGLES/dll/packages.config index a796aceffe..70c3dea0e7 100644 --- a/build/OpenGLES/dll/packages.config +++ b/build/OpenGLES/dll/packages.config @@ -1,4 +1,4 @@  - + \ No newline at end of file diff --git a/build/OpenGLES/lib/OpenGLESLib.vcxproj b/build/OpenGLES/lib/OpenGLESLib.vcxproj index baaa43ddb3..24c8a37412 100644 --- a/build/OpenGLES/lib/OpenGLESLib.vcxproj +++ b/build/OpenGLES/lib/OpenGLESLib.vcxproj @@ -153,12 +153,12 @@ - + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - + \ No newline at end of file diff --git a/build/OpenGLES/lib/packages.config b/build/OpenGLES/lib/packages.config index a796aceffe..70c3dea0e7 100644 --- a/build/OpenGLES/lib/packages.config +++ b/build/OpenGLES/lib/packages.config @@ -1,4 +1,4 @@  - + \ No newline at end of file diff --git a/build/Tests/FunctionalTests/FunctionalTests.vcxproj b/build/Tests/FunctionalTests/FunctionalTests.vcxproj index 6a0e093e2b..733fb31709 100644 --- a/build/Tests/FunctionalTests/FunctionalTests.vcxproj +++ b/build/Tests/FunctionalTests/FunctionalTests.vcxproj @@ -240,12 +240,20 @@ + + + + true + + + true + true diff --git a/build/UIKit/dll/UIKit.def b/build/UIKit/dll/UIKit.def index d2d6c2b264..7b4575d242 100644 --- a/build/UIKit/dll/UIKit.def +++ b/build/UIKit/dll/UIKit.def @@ -3,6 +3,7 @@ LIBRARY UIKit ; Application entry points (StarboardXAML) UIApplicationMain UIApplicationInitialize + UIApplicationInitializeFunctionalTest UIApplicationActivationTest UIApplicationLaunched UIApplicationActivated diff --git a/include/UIKit/UIGraphics.h b/include/UIKit/UIGraphics.h index d115be775b..17581f9def 100644 --- a/include/UIKit/UIGraphics.h +++ b/include/UIKit/UIGraphics.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2011, The Iconfactory. All rights reserved. - * Copyright (c) 2016 Microsoft Corporation. All rights reserved. + * Copyright (c) Microsoft. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -31,14 +31,11 @@ #pragma once #import "UIKitExport.h" +#import "UIKitTypes.h" #import @class UIImage; -#ifdef __cplusplus -extern "C" { -#endif - UIKIT_EXPORT void UIGraphicsPushContext(CGContextRef ctx); UIKIT_EXPORT void UIGraphicsPopContext(void); UIKIT_EXPORT CGContextRef UIGraphicsGetCurrentContext(void); @@ -58,6 +55,4 @@ UIKIT_EXPORT void UIRectFillUsingBlendMode(CGRect rect, CGBlendMode blendMode); UIKIT_EXPORT void UIRectFrame(CGRect rect); UIKIT_EXPORT void UIRectFrameUsingBlendMode(CGRect rect, CGBlendMode blendMode); -#ifdef __cplusplus -} -#endif +UIKIT_EXPORT CTTextAlignment NSTextAlignmentToCTTextAlignment(NSTextAlignment nsTextAlignment); \ No newline at end of file diff --git a/include/UIKit/UIWebViewDelegate.h b/include/UIKit/UIWebViewDelegate.h index 4f6b58a3f7..b46fa974d5 100644 --- a/include/UIKit/UIWebViewDelegate.h +++ b/include/UIKit/UIWebViewDelegate.h @@ -31,4 +31,7 @@ - (void)webViewDidStartLoad:(UIWebView*)webView; - (void)webViewDidFinishLoad:(UIWebView*)webView; - (void)webView:(UIWebView*)webView didFailLoadWithError:(NSError*)error; +// Workaround to handle window.external.notify event in HTML part. +// Original UIWebViewDelegate does not have this method +- (void)webView:(UIWebView*)webView scriptNotify:(NSURL*)url value:(NSString*)value; @end diff --git a/samples/XAMLCatalog/XAMLCatalog-WinStore10.sln b/samples/XAMLCatalog/XAMLCatalog-WinStore10.sln index a05a906135..34742ec044 100644 --- a/samples/XAMLCatalog/XAMLCatalog-WinStore10.sln +++ b/samples/XAMLCatalog/XAMLCatalog-WinStore10.sln @@ -2,9 +2,9 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 VisualStudioVersion = 14.0.22823.1 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "XAMLCatalog", "XAMLCatalog", "{126EC4E6-1204-4FE2-8CCB-5F0C07B493A7}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "XAMLCatalog", "XAMLCatalog", "{73A8D974-FFEC-4C22-9A79-56FE8D646D46}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "XAMLCatalog", "XAMLCatalog.vsimporter\XAMLCatalog-WinStore10\XAMLCatalog.vcxproj", "{B1031B85-9024-407A-8D76-107825391494}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "XAMLCatalog", "XAMLCatalog.vsimporter\XAMLCatalog-WinStore10\XAMLCatalog.vcxproj", "{A2D70D6C-657B-4071-83FC-5425BA8164B3}" EndProject Global GlobalSection(SharedMSBuildProjectFiles) = preSolution @@ -16,23 +16,23 @@ Global Release|Win32 = Release|Win32 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {B1031B85-9024-407A-8D76-107825391494}.Debug|ARM.ActiveCfg = Debug|ARM - {B1031B85-9024-407A-8D76-107825391494}.Debug|ARM.Build.0 = Debug|ARM - {B1031B85-9024-407A-8D76-107825391494}.Debug|ARM.Deploy.0 = Debug|ARM - {B1031B85-9024-407A-8D76-107825391494}.Debug|Win32.ActiveCfg = Debug|Win32 - {B1031B85-9024-407A-8D76-107825391494}.Debug|Win32.Build.0 = Debug|Win32 - {B1031B85-9024-407A-8D76-107825391494}.Debug|Win32.Deploy.0 = Debug|Win32 - {B1031B85-9024-407A-8D76-107825391494}.Release|ARM.ActiveCfg = Release|ARM - {B1031B85-9024-407A-8D76-107825391494}.Release|ARM.Build.0 = Release|ARM - {B1031B85-9024-407A-8D76-107825391494}.Release|ARM.Deploy.0 = Release|ARM - {B1031B85-9024-407A-8D76-107825391494}.Release|Win32.ActiveCfg = Release|Win32 - {B1031B85-9024-407A-8D76-107825391494}.Release|Win32.Build.0 = Release|Win32 - {B1031B85-9024-407A-8D76-107825391494}.Release|Win32.Deploy.0 = Release|Win32 + {A2D70D6C-657B-4071-83FC-5425BA8164B3}.Debug|ARM.ActiveCfg = Debug|ARM + {A2D70D6C-657B-4071-83FC-5425BA8164B3}.Debug|ARM.Build.0 = Debug|ARM + {A2D70D6C-657B-4071-83FC-5425BA8164B3}.Debug|ARM.Deploy.0 = Debug|ARM + {A2D70D6C-657B-4071-83FC-5425BA8164B3}.Debug|Win32.ActiveCfg = Debug|Win32 + {A2D70D6C-657B-4071-83FC-5425BA8164B3}.Debug|Win32.Build.0 = Debug|Win32 + {A2D70D6C-657B-4071-83FC-5425BA8164B3}.Debug|Win32.Deploy.0 = Debug|Win32 + {A2D70D6C-657B-4071-83FC-5425BA8164B3}.Release|ARM.ActiveCfg = Release|ARM + {A2D70D6C-657B-4071-83FC-5425BA8164B3}.Release|ARM.Build.0 = Release|ARM + {A2D70D6C-657B-4071-83FC-5425BA8164B3}.Release|ARM.Deploy.0 = Release|ARM + {A2D70D6C-657B-4071-83FC-5425BA8164B3}.Release|Win32.ActiveCfg = Release|Win32 + {A2D70D6C-657B-4071-83FC-5425BA8164B3}.Release|Win32.Build.0 = Release|Win32 + {A2D70D6C-657B-4071-83FC-5425BA8164B3}.Release|Win32.Deploy.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {B1031B85-9024-407A-8D76-107825391494} = {126EC4E6-1204-4FE2-8CCB-5F0C07B493A7} + {A2D70D6C-657B-4071-83FC-5425BA8164B3} = {73A8D974-FFEC-4C22-9A79-56FE8D646D46} EndGlobalSection EndGlobal diff --git a/samples/XAMLCatalog/XAMLCatalog.vsimporter/XAMLCatalog-WinStore10/Package.appxmanifest b/samples/XAMLCatalog/XAMLCatalog.vsimporter/XAMLCatalog-WinStore10/Package.appxmanifest index 3f886b809e..b2037f769e 100644 --- a/samples/XAMLCatalog/XAMLCatalog.vsimporter/XAMLCatalog-WinStore10/Package.appxmanifest +++ b/samples/XAMLCatalog/XAMLCatalog.vsimporter/XAMLCatalog-WinStore10/Package.appxmanifest @@ -7,15 +7,15 @@ IgnorableNamespaces="uap mp"> - + XAMLCatalog - davelamb + jaredh Assets\StoreLogo.png diff --git a/samples/XAMLCatalog/XAMLCatalog.vsimporter/XAMLCatalog-WinStore10/XAMLCatalog-Debug-xcvars.txt b/samples/XAMLCatalog/XAMLCatalog.vsimporter/XAMLCatalog-WinStore10/XAMLCatalog-Debug-xcvars.txt index 295e0764fe..0df3ab4fce 100644 --- a/samples/XAMLCatalog/XAMLCatalog.vsimporter/XAMLCatalog-WinStore10/XAMLCatalog-Debug-xcvars.txt +++ b/samples/XAMLCatalog/XAMLCatalog.vsimporter/XAMLCatalog-WinStore10/XAMLCatalog-Debug-xcvars.txt @@ -85,15 +85,15 @@ PRODUCT_BUNDLE_IDENTIFIER = Microsoft.XAMLCatalog PRODUCT_NAME = XAMLCatalog PRODUCT_TYPE = com.apple.product-type.application PROJECT = XAMLCatalog -PROJECT_DIR = C:/Users/davelamb/git/WinObjC-Github/samples/XAMLCatalog -PROJECT_FILE_PATH = C:\Users\davelamb\git\WinObjC-Github\samples\XAMLCatalog\XAMLCatalog.xcodeproj +PROJECT_DIR = I:/enl/vso_1_WinObjC/samples/XAMLCatalog +PROJECT_FILE_PATH = I:\enl\vso_1_WinObjC\samples\XAMLCatalog\XAMLCatalog.xcodeproj PROJECT_NAME = XAMLCatalog PROJECT_TEMP_DIR = sbuild/XAMLCatalog.sbuild PROJECT_TEMP_ROOT = sbuild PUBLIC_HEADERS_FOLDER_PATH = XAMLCatalog.app/Public -SDKROOT = C:/Users/davelamb/git/WinObjC-Github -SOURCE_ROOT = C:/Users/davelamb/git/WinObjC-Github/samples/XAMLCatalog -SRCROOT = C:/Users/davelamb/git/WinObjC-Github/samples/XAMLCatalog +SDKROOT = I:/enl/vso_1_WinObjC +SOURCE_ROOT = I:/enl/vso_1_WinObjC/samples/XAMLCatalog +SRCROOT = I:/enl/vso_1_WinObjC/samples/XAMLCatalog SYMROOT = sbuild TARGETED_DEVICE_FAMILY = 1,2 TARGETNAME = XAMLCatalog @@ -103,9 +103,9 @@ TARGET_SDKVERSION = 5.0 TARGET_TEMP_DIR = sbuild/XAMLCatalog.sbuild/Debug-iphoneos/XAMLCatalog.sbuild TEMP_DIR = sbuild/XAMLCatalog.sbuild/Debug-iphoneos/XAMLCatalog.sbuild UNLOCALIZED_RESOURCES_FOLDER_PATH = XAMLCatalog.app -USER = davelamb +USER = jaredh USER_HEADER_SEARCH_PATHS = USE_HEADERMAP = YES WARNING_CFLAGS = WARNING_LDFLAGS = -WINOBJC_SDK_ROOT = C:/Users/davelamb/git/WinObjC-Github +WINOBJC_SDK_ROOT = I:/enl/vso_1_WinObjC diff --git a/samples/XAMLCatalog/XAMLCatalog.vsimporter/XAMLCatalog-WinStore10/XAMLCatalog-Release-xcvars.txt b/samples/XAMLCatalog/XAMLCatalog.vsimporter/XAMLCatalog-WinStore10/XAMLCatalog-Release-xcvars.txt index 93fb7e046b..96676c0fff 100644 --- a/samples/XAMLCatalog/XAMLCatalog.vsimporter/XAMLCatalog-WinStore10/XAMLCatalog-Release-xcvars.txt +++ b/samples/XAMLCatalog/XAMLCatalog.vsimporter/XAMLCatalog-WinStore10/XAMLCatalog-Release-xcvars.txt @@ -84,15 +84,15 @@ PRODUCT_BUNDLE_IDENTIFIER = Microsoft.XAMLCatalog PRODUCT_NAME = XAMLCatalog PRODUCT_TYPE = com.apple.product-type.application PROJECT = XAMLCatalog -PROJECT_DIR = C:/Users/davelamb/git/WinObjC-Github/samples/XAMLCatalog -PROJECT_FILE_PATH = C:\Users\davelamb\git\WinObjC-Github\samples\XAMLCatalog\XAMLCatalog.xcodeproj +PROJECT_DIR = I:/enl/vso_1_WinObjC/samples/XAMLCatalog +PROJECT_FILE_PATH = I:\enl\vso_1_WinObjC\samples\XAMLCatalog\XAMLCatalog.xcodeproj PROJECT_NAME = XAMLCatalog PROJECT_TEMP_DIR = sbuild/XAMLCatalog.sbuild PROJECT_TEMP_ROOT = sbuild PUBLIC_HEADERS_FOLDER_PATH = XAMLCatalog.app/Public -SDKROOT = C:/Users/davelamb/git/WinObjC-Github -SOURCE_ROOT = C:/Users/davelamb/git/WinObjC-Github/samples/XAMLCatalog -SRCROOT = C:/Users/davelamb/git/WinObjC-Github/samples/XAMLCatalog +SDKROOT = I:/enl/vso_1_WinObjC +SOURCE_ROOT = I:/enl/vso_1_WinObjC/samples/XAMLCatalog +SRCROOT = I:/enl/vso_1_WinObjC/samples/XAMLCatalog SYMROOT = sbuild TARGETED_DEVICE_FAMILY = 1,2 TARGETNAME = XAMLCatalog @@ -102,10 +102,10 @@ TARGET_SDKVERSION = 5.0 TARGET_TEMP_DIR = sbuild/XAMLCatalog.sbuild/Release-iphoneos/XAMLCatalog.sbuild TEMP_DIR = sbuild/XAMLCatalog.sbuild/Release-iphoneos/XAMLCatalog.sbuild UNLOCALIZED_RESOURCES_FOLDER_PATH = XAMLCatalog.app -USER = davelamb +USER = jaredh USER_HEADER_SEARCH_PATHS = USE_HEADERMAP = YES VALIDATE_PRODUCT = YES WARNING_CFLAGS = WARNING_LDFLAGS = -WINOBJC_SDK_ROOT = C:/Users/davelamb/git/WinObjC-Github +WINOBJC_SDK_ROOT = I:/enl/vso_1_WinObjC diff --git a/samples/XAMLCatalog/XAMLCatalog.vsimporter/XAMLCatalog-WinStore10/XAMLCatalog.vcxproj b/samples/XAMLCatalog/XAMLCatalog.vsimporter/XAMLCatalog-WinStore10/XAMLCatalog.vcxproj index e7c8a435ed..2bfe15a4ca 100644 --- a/samples/XAMLCatalog/XAMLCatalog.vsimporter/XAMLCatalog-WinStore10/XAMLCatalog.vcxproj +++ b/samples/XAMLCatalog/XAMLCatalog.vsimporter/XAMLCatalog-WinStore10/XAMLCatalog.vcxproj @@ -1,4 +1,4 @@ - + @@ -29,7 +29,7 @@ 10.0.14393.0 10.0.10586.0 IslandwoodProj - {B1031B85-9024-407A-8D76-107825391494} + {A2D70D6C-657B-4071-83FC-5425BA8164B3} XAMLCatalog ..\..\..\.. @@ -198,8 +198,10 @@ + + @@ -209,8 +211,10 @@ + + false @@ -248,4 +252,4 @@ - \ No newline at end of file + diff --git a/samples/XAMLCatalog/XAMLCatalog.vsimporter/XAMLCatalog-WinStore10/XAMLCatalog.vcxproj.filters b/samples/XAMLCatalog/XAMLCatalog.vsimporter/XAMLCatalog-WinStore10/XAMLCatalog.vcxproj.filters index 9d1b6aef99..6b6a4770d2 100644 --- a/samples/XAMLCatalog/XAMLCatalog.vsimporter/XAMLCatalog-WinStore10/XAMLCatalog.vcxproj.filters +++ b/samples/XAMLCatalog/XAMLCatalog.vsimporter/XAMLCatalog-WinStore10/XAMLCatalog.vcxproj.filters @@ -1,29 +1,29 @@ - + - {86d91b62-1154-4dab-8c81-5de9374c3c82} + {fdb75f11-e56a-4a96-8dee-751ee9922057} - {d53d2d97-6325-4b9f-88c4-e2044419e1d2} + {7376c44f-2a30-4db1-855d-efc3cf050b54} - {2F2592B7-1AAC-4C42-A938-5A64495DDC53} + {F5278BB7-C8E1-4BC2-B8CC-BF9C60C6AB39} - {53E070C2-E27D-4768-831C-48881671FC45} + {A90D5805-D357-4138-823D-CF386832BB0B} - {368E02DA-E628-4BF5-8CD5-589A9389A03E} + {9A757F10-113C-4F96-81B2-3D31D149AB4D} - {083BC455-EBCF-4EE3-81F5-F897E1DB56DE} + {B63877D8-B1FE-4570-9EDC-049549BC732F} - {DDB161F8-C65B-49EB-A065-B4A2D0410EDB} + {8E17F989-D783-423A-BE3A-85D89F6EDF28} - {678F0B8C-4157-4F10-AF98-409C45CB4EED} + {279DA68E-B966-4EAE-87EF-00BD9928311A} @@ -79,7 +79,7 @@ XAMLCatalog\UIKitControls - XAMLCatalog + XAMLCatalog\UIKitControls XAMLCatalog\UIKitControls @@ -87,6 +87,9 @@ XAMLCatalog\UIKitControls + + XAMLCatalog\UIKitControls + XAMLCatalog @@ -112,7 +115,7 @@ XAMLCatalog\UIKitControls - XAMLCatalog + XAMLCatalog\UIKitControls XAMLCatalog\UIKitControls @@ -120,6 +123,9 @@ XAMLCatalog\UIKitControls + + XAMLCatalog\UIKitControls + XAMLCatalog\Supporting Files @@ -141,4 +147,23 @@ Xcode Variable Files - + + + + + + + + + + + + XAMLCatalog + + + + + XAMLCatalog + + + \ No newline at end of file diff --git a/samples/XAMLCatalog/XAMLCatalog.xcodeproj/project.pbxproj b/samples/XAMLCatalog/XAMLCatalog.xcodeproj/project.pbxproj index f54d94ea1b..3cfdf36d42 100644 --- a/samples/XAMLCatalog/XAMLCatalog.xcodeproj/project.pbxproj +++ b/samples/XAMLCatalog/XAMLCatalog.xcodeproj/project.pbxproj @@ -17,6 +17,7 @@ 6EEB8A461CE4F4050021021E /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6EEB8A451CE4F4050021021E /* Assets.xcassets */; }; 6EEB8A561CE546A80021021E /* MenuTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 6EEB8A551CE546A80021021E /* MenuTableViewController.m */; }; 6EEB8A5C1CE54B4E0021021E /* UIActivityIndicatorViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 6EEB8A5B1CE54B4E0021021E /* UIActivityIndicatorViewController.m */; }; + 71ADC9FA1E26F8F6008BBCAA /* UIViewViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 71ADC9F91E26F8F6008BBCAA /* UIViewViewController.m */; }; 7B67A2081DC366C1004BEF5D /* CustomTextControlViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B67A2071DC366C1004BEF5D /* CustomTextControlViewController.m */; }; 822F85BE1D8F908C001DC8A5 /* blue_background.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 822F85BB1D8F908C001DC8A5 /* blue_background.jpg */; }; 822F85BF1D8F908C001DC8A5 /* button_image.png in Resources */ = {isa = PBXBuildFile; fileRef = 822F85BC1D8F908C001DC8A5 /* button_image.png */; }; @@ -24,6 +25,7 @@ 82E63A5E1D07905D005C0993 /* UISliderViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 82E63A5D1D07905D005C0993 /* UISliderViewController.m */; }; 96857DC01D598FB300EB1FD0 /* MiscellaneousViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 96857DBD1D598FB300EB1FD0 /* MiscellaneousViewController.m */; }; 96857DC11D598FB300EB1FD0 /* UIButtonViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 96857DBF1D598FB300EB1FD0 /* UIButtonViewController.m */; }; + A5EFA1601E26FC0D00881967 /* UILabelViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = A5EFA15F1E26FC0D00881967 /* UILabelViewController.m */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -46,6 +48,8 @@ 6EEB8A551CE546A80021021E /* MenuTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MenuTableViewController.m; sourceTree = ""; }; 6EEB8A5A1CE54B4E0021021E /* UIActivityIndicatorViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UIActivityIndicatorViewController.h; sourceTree = ""; }; 6EEB8A5B1CE54B4E0021021E /* UIActivityIndicatorViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UIActivityIndicatorViewController.m; sourceTree = ""; }; + 71ADC9F81E26F8F6008BBCAA /* UIViewViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UIViewViewController.h; sourceTree = ""; }; + 71ADC9F91E26F8F6008BBCAA /* UIViewViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UIViewViewController.m; sourceTree = ""; }; 7B67A2071DC366C1004BEF5D /* CustomTextControlViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CustomTextControlViewController.m; sourceTree = ""; }; 7B67A20A1DC36756004BEF5D /* CustomTextControlViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CustomTextControlViewController.h; sourceTree = ""; }; 822F85BB1D8F908C001DC8A5 /* blue_background.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; name = blue_background.jpg; path = XAMLCatalog/Images/blue_background.jpg; sourceTree = ""; }; @@ -57,6 +61,8 @@ 96857DBD1D598FB300EB1FD0 /* MiscellaneousViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MiscellaneousViewController.m; sourceTree = ""; }; 96857DBE1D598FB300EB1FD0 /* UIButtonViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UIButtonViewController.h; sourceTree = ""; }; 96857DBF1D598FB300EB1FD0 /* UIButtonViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UIButtonViewController.m; sourceTree = ""; }; + A5EFA15E1E26FC0D00881967 /* UILabelViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UILabelViewController.h; sourceTree = ""; }; + A5EFA15F1E26FC0D00881967 /* UILabelViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UILabelViewController.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -73,6 +79,8 @@ 2324634F1CE69E2C00B7AAE4 /* UIKitControls */ = { isa = PBXGroup; children = ( + 71ADC9F81E26F8F6008BBCAA /* UIViewViewController.h */, + 71ADC9F91E26F8F6008BBCAA /* UIViewViewController.m */, 23E594D11D6FC38D000BB01E /* UIActionSheetViewController.h */, 23E594D21D6FC38D000BB01E /* UIActionSheetViewController.m */, 6EEB8A5A1CE54B4E0021021E /* UIActivityIndicatorViewController.h */, @@ -108,6 +116,8 @@ 6EEB8A351CE4F4050021021E /* XAMLCatalog */ = { isa = PBXGroup; children = ( + A5EFA15E1E26FC0D00881967 /* UILabelViewController.h */, + A5EFA15F1E26FC0D00881967 /* UILabelViewController.m */, 6EEB8A391CE4F4050021021E /* AppDelegate.h */, 6EEB8A3A1CE4F4050021021E /* AppDelegate.m */, 6EEB8A451CE4F4050021021E /* Assets.xcassets */, @@ -227,11 +237,13 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + A5EFA1601E26FC0D00881967 /* UILabelViewController.m in Sources */, 6EEB8A411CE4F4050021021E /* StoryBoardViewController.m in Sources */, 6EEB8A3B1CE4F4050021021E /* AppDelegate.m in Sources */, 6EEB8A3E1CE4F4050021021E /* ProgrammaticViewController.m in Sources */, 96857DC01D598FB300EB1FD0 /* MiscellaneousViewController.m in Sources */, 7B67A2081DC366C1004BEF5D /* CustomTextControlViewController.m in Sources */, + 71ADC9FA1E26F8F6008BBCAA /* UIViewViewController.m in Sources */, 6EEB8A5C1CE54B4E0021021E /* UIActivityIndicatorViewController.m in Sources */, 96857DC11D598FB300EB1FD0 /* UIButtonViewController.m in Sources */, 82E63A5E1D07905D005C0993 /* UISliderViewController.m in Sources */, diff --git a/samples/XAMLCatalog/XAMLCatalog/ProgrammaticViewController.m b/samples/XAMLCatalog/XAMLCatalog/ProgrammaticViewController.m index 0d50d808bf..66ae391113 100644 --- a/samples/XAMLCatalog/XAMLCatalog/ProgrammaticViewController.m +++ b/samples/XAMLCatalog/XAMLCatalog/ProgrammaticViewController.m @@ -19,12 +19,14 @@ #import "UIActionSheetViewController.h" #import "UIActivityIndicatorViewController.h" #import "UIButtonViewController.h" +#import "UILabelViewController.h" #import "UISliderViewController.h" #import "UITextFieldViewController.h" +#import "UIViewViewController.h" #import "CustomTextControlViewController.h" - #import "MiscellaneousViewController.h" + @implementation ProgrammaticViewController - (void)viewDidLoad { @@ -39,12 +41,18 @@ - (void)viewDidLoad { // UIButton [self addMenuItemViewController:[[UIButtonViewController alloc] init] andTitle:@"UIButton"]; + // UILabel + [self addMenuItemViewController:[[UILabelViewController alloc] init] andTitle : @"UILabel"]; + // UISlider [self addMenuItemViewController:[[UISliderViewController alloc] init] andTitle:@"UISlider"]; // UITextField [self addMenuItemViewController:[[UITextFieldViewController alloc] init] andTitle : @"UITextField"]; + // UIViewViewController + [self addMenuItemViewController:[[UIViewViewController alloc] init] andTitle : @"UIView"]; + // CustomTextControlViewController [self addMenuItemViewController:[[CustomTextControlViewController alloc] init] andTitle : @"Custom Text View"]; diff --git a/samples/XAMLCatalog/XAMLCatalog/UILabelViewController.h b/samples/XAMLCatalog/XAMLCatalog/UILabelViewController.h new file mode 100644 index 0000000000..8742fb14de --- /dev/null +++ b/samples/XAMLCatalog/XAMLCatalog/UILabelViewController.h @@ -0,0 +1,21 @@ +//****************************************************************************** +// +// Copyright (c) 2015 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +//****************************************************************************** +#pragma once + +#import "MenuTableViewController.h" + +@interface UILabelViewController : MenuTableViewController +@end \ No newline at end of file diff --git a/samples/XAMLCatalog/XAMLCatalog/UILabelViewController.m b/samples/XAMLCatalog/XAMLCatalog/UILabelViewController.m new file mode 100644 index 0000000000..74121a7a69 --- /dev/null +++ b/samples/XAMLCatalog/XAMLCatalog/UILabelViewController.m @@ -0,0 +1,129 @@ +//****************************************************************************** +// +// Copyright (c) 2015 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +//****************************************************************************** + +#import "UILabelViewController.h" + +static const CGFloat c_originX = 5; +static const CGFloat c_originY = 8; +static const CGFloat c_width = 300; +static const CGFloat c_height = 50; +static const CGFloat c_labelFontSize = 17.0f; +static const int TAG_SUBVIEW_UILABEL = 1; + +@implementation UILabelViewController { +@private + NSMutableArray* _labels; +} + +- (UILabel*)_createUILabelWithColor:(UIColor*)color + text:(NSString*)text + textAlignment:(NSTextAlignment)alignment + lineBreakMode:(UILineBreakMode)lineBreakMode + numberOfLines:(NSInteger)numberOfLines { + CGRect frame = CGRectMake(c_originX, c_originY, c_width, c_height); + UILabel* label = [[UILabel alloc] initWithFrame:frame]; + label.textColor = color; + label.text = text; + label.textAlignment = alignment; + label.lineBreakMode = lineBreakMode; + label.numberOfLines = numberOfLines; + return label; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + + // creating the text Fields + _labels = [[NSMutableArray alloc] init]; + + // Row 0. password with number keyboard with Round border + [_labels addObject:[self _createUILabelWithColor:[UIColor blackColor] + text:@"wordWrap test, You should see this string is wrapped around word" + textAlignment:UITextAlignmentLeft + lineBreakMode:UILineBreakModeWordWrap + numberOfLines:0]]; + + [_labels addObject:[self _createUILabelWithColor:[UIColor redColor] + text:@"chararacterWrap is not supported, treated as wordWrap" + textAlignment:UITextAlignmentLeft + lineBreakMode:UILineBreakModeCharacterWrap + numberOfLines:2]]; + + [_labels addObject:[self _createUILabelWithColor:[UIColor blueColor] + text:@"Clip and wrapping, the string is wrapped and clipped at the end of second line if " + @"the string is long enough" + textAlignment:UITextAlignmentLeft + lineBreakMode:UILineBreakModeClip + numberOfLines:3]]; + + [_labels + addObject:[self _createUILabelWithColor:[UIColor grayColor] + text:@"Clip and nowrapping, cliped at the end of first line and the rest will not wrap and show" + textAlignment:UITextAlignmentLeft + lineBreakMode:UILineBreakModeClip + numberOfLines:1]]; + + [_labels + addObject:[self _createUILabelWithColor:[UIColor purpleColor] + text:@"TailTruncation, this is a very long string, that we are using for testing TailTruncation" + textAlignment:UITextAlignmentLeft + lineBreakMode:UILineBreakModeTailTruncation + numberOfLines:0]]; + + [_labels addObject:[self _createUILabelWithColor:[UIColor blackColor] + text:@"HeadTruncation but shown as TailTruncation, this is a very long string, that we are " + @"using for testing HeadTruncation" + textAlignment:UITextAlignmentLeft + lineBreakMode:UILineBreakModeHeadTruncation + numberOfLines:2]]; + + [_labels addObject:[self _createUILabelWithColor:[UIColor blackColor] + text:@"MiddleTruncation but shown as TailTruncation, this is a very long string, that we " + @"are using for testing MiddleTruncation" + textAlignment:UITextAlignmentLeft + lineBreakMode:UILineBreakModeMiddleTruncation + numberOfLines:3]]; + + [self tableView].allowsSelection = NO; +} + +- (NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)section { + return [_labels count]; +} + +- (CGFloat)tableView:(UITableView*)tableView heightForRowAtIndexPath:(NSIndexPath*)indexPath { + return 60; +} + +- (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath { + UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:@"MenuCell"]; + if (nil == cell) { + cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"MenuCell"]; + } else { + // Before reuse, check if any subview in contentview is tagged with TAG_SUBVIEW_UITEXTFIELD + // if so, we know it is a custom view that we need to remove + UIView* subView = (UIView*)[cell.contentView viewWithTag:TAG_SUBVIEW_UILABEL]; + [subView removeFromSuperview]; + } + + // Tag UITextField subview with TAG_SUBVIEW_TEXTFIELD before adding this subview into contentview + UIView* subView = [_labels objectAtIndex:indexPath.row]; + subView.tag = TAG_SUBVIEW_UILABEL; + [cell.contentView addSubview:subView]; + return cell; +} + +@end diff --git a/samples/XAMLCatalog/XAMLCatalog/UIViewViewController.h b/samples/XAMLCatalog/XAMLCatalog/UIViewViewController.h new file mode 100644 index 0000000000..8b3daad5de --- /dev/null +++ b/samples/XAMLCatalog/XAMLCatalog/UIViewViewController.h @@ -0,0 +1,20 @@ +//****************************************************************************** +// +// Copyright (c) 2015 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +//****************************************************************************** + +#import "MenuTableViewController.h" + +@interface UIViewViewController : MenuTableViewController +@end \ No newline at end of file diff --git a/samples/XAMLCatalog/XAMLCatalog/UIViewViewController.m b/samples/XAMLCatalog/XAMLCatalog/UIViewViewController.m new file mode 100644 index 0000000000..92005a2f7c --- /dev/null +++ b/samples/XAMLCatalog/XAMLCatalog/UIViewViewController.m @@ -0,0 +1,167 @@ +//****************************************************************************** +// +// Copyright (c) 2015 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +//****************************************************************************** + +#import "UIViewViewController.h" +#import + +@interface UIViewHitTest : UIView +@property (nonatomic) BOOL shouldRespondToTouch; +@property (nonatomic) UILabel* statusLabel; +@end + +@implementation UIViewHitTest { + BOOL _shouldRespondToTouch; +}; + +- (instancetype)initWithFrame:(CGRect)frame { + if (self = [super initWithFrame:frame]) { + // Default to true + _shouldRespondToTouch = true; + } + + return self; +} + +- (void)touchesBegan:(NSSet*)touchSet withEvent:(UIEvent*)event { + _statusLabel.text = @"Touches Began"; + + if (!_shouldRespondToTouch) { + assert(false); // TODO: Fail test instead of asserting when we have a mechanism to do so. + _statusLabel.text = @"FAILED: Unexpected touch received!"; + } +} + +-(void)touchesMoved:(NSSet*)touchSet withEvent:(UIEvent*)event { + _statusLabel.text = @"Touches Moved"; + + if (!_shouldRespondToTouch) { + assert(false); // TODO: Fail test instead of asserting when we have a mechanism to do so. + _statusLabel.text = @"FAILED: Unexpected touch received!"; + } +} + +-(void)touchesEnded:(NSSet*)touchSet withEvent:(UIEvent*)event { + _statusLabel.text = @"Touches Ended"; + + if (!_shouldRespondToTouch) { + assert(false); // TODO: Fail test instead of asserting when we have a mechanism to do so. + _statusLabel.text = @"FAILED: Unexpected touch received!"; + } +} + +- (BOOL)shouldRespondToTouch { + return _shouldRespondToTouch; +} + +- (void)setShouldRespondToTouch:(BOOL)shouldRespond { + _shouldRespondToTouch = shouldRespond; +} + +@end + +@implementation UIViewViewController { + CGRect _labelFrame; + CGRect _containerViewFrame; + CGRect _testViewFrame; + CGRect _statusLabelViewFrame; + float _cellHeight; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + self.title = @"UIView"; + [self tableView].allowsSelection = NO; + + static const float margin = 5.0; + + CGRect screenBounds = [[UIScreen mainScreen] bounds]; + _labelFrame = CGRectMake(margin, margin, screenBounds.size.width, 50); + _containerViewFrame = CGRectMake(margin, margin + _labelFrame.size.height, 300, 100); + _testViewFrame = CGRectMake(margin, margin, _containerViewFrame.size.width - (margin * 2.0), _containerViewFrame.size.height - (margin * 2.0)); + _statusLabelViewFrame = CGRectMake(margin * 2.0, margin, _testViewFrame.size.width - (margin * 2.0), 40); + _cellHeight = _labelFrame.size.height + _containerViewFrame.size.height + (margin * 2.0); +} + +- (NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)section { + return 6; +} + +- (CGFloat)tableView:(UITableView*)tableView heightForRowAtIndexPath:(NSIndexPath*)indexPath { + return _cellHeight; +} + +- (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath { + // Grab a cell + UITableViewCell* cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"MenuCell"]; + + // Add the instruction label + UILabel* label = [[UILabel alloc] initWithFrame:_labelFrame]; + // Using adjustsFontSizeToFitWidth so the instruction labels show up on phone + // The need for adjustsFontSizeToFitWidth is tracked by #1690. + // The fact that adjustsFontSizeToFitWidth functions incorrectly on desktop tracked by #1689. + label.adjustsFontSizeToFitWidth = YES; + [cell.contentView addSubview:label]; + + // Add a container view to deliniate bounds of test view + UIView* containerView = [[UIView alloc] initWithFrame:_containerViewFrame]; + containerView.backgroundColor = [UIColor grayColor]; + [cell.contentView addSubview : containerView]; + + // Add the test view + UIViewHitTest* testView = [[UIViewHitTest alloc] initWithFrame:_testViewFrame]; + testView.backgroundColor = [UIColor yellowColor]; + [containerView addSubview:testView]; + + // Add the status label + UILabel* statusLabel = [[UILabel alloc] initWithFrame:_statusLabelViewFrame]; + statusLabel.text = @"No Touch Input Detected"; + statusLabel.userInteractionEnabled = NO; + [containerView addSubview:statusLabel]; + + // Give the testView a label to report status + testView.statusLabel = statusLabel; + + if (indexPath.row == 0) { + // Setup test + label.text = @"Alpha=0.0; yellow background SHOULD NOT be visible and view SHOULD NOT respond to touch."; + testView.alpha = 0.0; + testView.shouldRespondToTouch = NO; + } else if (indexPath.row == 1) { + // Setup test + label.text = @"Yellow background SHOULD be visible and view SHOULD respond to touch."; + } else if (indexPath.row == 2) { + // Setup test + label.text = @"Clear background SHOULD NOT be visible, but view SHOULD respond to touch."; + testView.backgroundColor = [UIColor clearColor]; + } else if (indexPath.row == 3) { + // Setup test + label.text = @"UserInteractionEnabled=NO; yellow background SHOULD be visible but view SHOULD NOT respond to touch."; + testView.userInteractionEnabled = NO; + testView.shouldRespondToTouch = NO; + } else if (indexPath.row == 4) { + // Setup test + label.text = @"Hidden=YES; yellow background SHOULD NOT be visible and view SHOULD NOT respond to touch."; + testView.hidden = YES; + } else if (indexPath.row == 5) { + // Setup test + label.text = @"nil background SHOULD NOT be visible, but view SHOULD respond to touch."; + testView.backgroundColor = nil; + } + + return cell; +} + +@end diff --git a/tests/UnitTests/CoreGraphics.drawing/CGContextDrawingTests.cpp b/tests/UnitTests/CoreGraphics.drawing/CGContextDrawingTests.cpp index afe01b1416..db2d99a991 100644 --- a/tests/UnitTests/CoreGraphics.drawing/CGContextDrawingTests.cpp +++ b/tests/UnitTests/CoreGraphics.drawing/CGContextDrawingTests.cpp @@ -469,7 +469,7 @@ DRAW_TEST_F(CGContext, DrawAnImageWithInterpolationQualityAndAlpha, UIKitMimicTe CGContextDrawImage(context, bounds, image.get()); } -DISABLED_DRAW_TEST_F(CGContext, RedBox, UIKitMimicTest) { +DISABLED_DRAW_TEST_F(CGContext, RedBox, UIKitMimicTest<>) { CGContextRef context = GetDrawingContext(); CGRect bounds = GetDrawingBounds(); @@ -477,7 +477,7 @@ DISABLED_DRAW_TEST_F(CGContext, RedBox, UIKitMimicTest) { CGContextFillRect(context, CGRectInset(bounds, 10, 10)); } -DISABLED_DRAW_TEST_F(CGContext, DrawAContextIntoAnImage, UIKitMimicTest) { +DISABLED_DRAW_TEST_F(CGContext, DrawAContextIntoAnImage, UIKitMimicTest<>) { // This test will create a bitmap context, draw some entity into the context, then create a image out of the bitmap context. // Thereafter it will draw the image into the Canvas context @@ -505,7 +505,7 @@ DISABLED_DRAW_TEST_F(CGContext, DrawAContextIntoAnImage, UIKitMimicTest) { CGContextDrawImage(context, bounds, image.get()); } -DISABLED_DRAW_TEST_F(CGContext, FillThenStrokeIsSameAsDrawFillStroke, WhiteBackgroundTest) { +DISABLED_DRAW_TEST_F(CGContext, FillThenStrokeIsSameAsDrawFillStroke, WhiteBackgroundTest<>) { CGContextRef context = GetDrawingContext(); CGRect bounds = GetDrawingBounds(); @@ -543,7 +543,7 @@ static void _drawThreeCirclesInContext(CGContextRef context, CGRect bounds) { } } -DISABLED_DRAW_TEST_F(CGContext, OverlappingCirclesColorAlpha, WhiteBackgroundTest) { +DISABLED_DRAW_TEST_F(CGContext, OverlappingCirclesColorAlpha, WhiteBackgroundTest<>) { CGContextRef context = GetDrawingContext(); CGRect bounds = GetDrawingBounds(); @@ -554,7 +554,7 @@ DISABLED_DRAW_TEST_F(CGContext, OverlappingCirclesColorAlpha, WhiteBackgroundTes _drawThreeCirclesInContext(context, bounds); } -DISABLED_DRAW_TEST_F(CGContext, OverlappingCirclesGlobalAlpha, WhiteBackgroundTest) { +DISABLED_DRAW_TEST_F(CGContext, OverlappingCirclesGlobalAlpha, WhiteBackgroundTest<>) { CGContextRef context = GetDrawingContext(); CGRect bounds = GetDrawingBounds(); @@ -567,7 +567,7 @@ DISABLED_DRAW_TEST_F(CGContext, OverlappingCirclesGlobalAlpha, WhiteBackgroundTe _drawThreeCirclesInContext(context, bounds); } -DISABLED_DRAW_TEST_F(CGContext, OverlappingCirclesGlobalAlphaStackedWithColorAlpha, WhiteBackgroundTest) { +DISABLED_DRAW_TEST_F(CGContext, OverlappingCirclesGlobalAlphaStackedWithColorAlpha, WhiteBackgroundTest<>) { CGContextRef context = GetDrawingContext(); CGRect bounds = GetDrawingBounds(); @@ -580,7 +580,7 @@ DISABLED_DRAW_TEST_F(CGContext, OverlappingCirclesGlobalAlphaStackedWithColorAlp _drawThreeCirclesInContext(context, bounds); } -DISABLED_DRAW_TEST_F(CGContext, OverlappingCirclesTransparencyLayerAlpha, WhiteBackgroundTest) { +DISABLED_DRAW_TEST_F(CGContext, OverlappingCirclesTransparencyLayerAlpha, WhiteBackgroundTest<>) { CGContextRef context = GetDrawingContext(); CGRect bounds = GetDrawingBounds(); @@ -600,7 +600,7 @@ DISABLED_DRAW_TEST_F(CGContext, OverlappingCirclesTransparencyLayerAlpha, WhiteB // This test proves that the path is stored fully transformed; // changing the CTM before stroking it does not cause it to scale! // However, the stroke width _is_ scaled (!) -DISABLED_DRAW_TEST_F(CGContext, ChangeCTMAfterCreatingPath, WhiteBackgroundTest) { +DISABLED_DRAW_TEST_F(CGContext, ChangeCTMAfterCreatingPath, WhiteBackgroundTest<>) { CGContextRef context = GetDrawingContext(); CGRect bounds = GetDrawingBounds(); @@ -635,4 +635,4 @@ DRAW_TEST(CGContext, PremultipliedAlphaImage) { CGContextSetRGBFillColor(context, 1.0, 0.0, 0.0, 0.5); CGContextFillRect(context, { 0, 0, 100, 100 }); -} \ No newline at end of file +} diff --git a/tests/UnitTests/CoreGraphics.drawing/DrawingTest.cpp b/tests/UnitTests/CoreGraphics.drawing/DrawingTest.cpp index 26b784913a..0dde5ff633 100644 --- a/tests/UnitTests/CoreGraphics.drawing/DrawingTest.cpp +++ b/tests/UnitTests/CoreGraphics.drawing/DrawingTest.cpp @@ -24,21 +24,26 @@ static const CGSize g_defaultCanvasSize{ 512.f, 256.f }; -woc::unique_cf testing::DrawTest::s_deviceColorSpace; +template +woc::unique_cf testing::DrawTest::s_deviceColorSpace; -void testing::DrawTest::SetUpTestCase() { +template +void testing::DrawTest::SetUpTestCase() { s_deviceColorSpace.reset(CGColorSpaceCreateDeviceRGB()); } -void testing::DrawTest::TearDownTestCase() { +template +void testing::DrawTest::TearDownTestCase() { s_deviceColorSpace.release(); } -CGSize testing::DrawTest::CanvasSize() { +template +CGSize testing::DrawTest::CanvasSize() { return g_defaultCanvasSize; } -void testing::DrawTest::SetUp() { +template +void testing::DrawTest::SetUp() { CGSize size = CanvasSize(); _context.reset(CGBitmapContextCreate( @@ -50,11 +55,13 @@ void testing::DrawTest::SetUp() { SetUpContext(); } -CFStringRef testing::DrawTest::CreateAdditionalTestDescription() { +template +CFStringRef testing::DrawTest::CreateAdditionalTestDescription() { return nullptr; } -CFStringRef testing::DrawTest::CreateOutputFilename() { +template +CFStringRef testing::DrawTest::CreateOutputFilename() { const ::testing::TestInfo* const test_info = ::testing::UnitTest::GetInstance()->current_test_info(); woc::unique_cf additionalDesc{ CreateAdditionalTestDescription() }; woc::unique_cf filename{ CFStringCreateWithFormat(nullptr, @@ -67,7 +74,8 @@ CFStringRef testing::DrawTest::CreateOutputFilename() { return filename.release(); } -void testing::DrawTest::TearDown() { +template +void testing::DrawTest::TearDown() { CGContextRef context = GetDrawingContext(); // Generate image from context. @@ -108,7 +116,7 @@ void testing::DrawTest::TearDown() { ASSERT_NE(nullptr, referenceImage); // And fire off a comparator. - PixelByPixelImageComparator comparator; + TComparator comparator; auto delta = comparator.CompareImages(referenceImage.get(), image.get()); if (delta.result != ImageComparisonResult::Same) { @@ -134,29 +142,35 @@ void testing::DrawTest::TearDown() { } } -void testing::DrawTest::SetUpContext() { +template +void testing::DrawTest::SetUpContext() { // The default context is fine as-is. } -void testing::DrawTest::TestBody() { +template +void testing::DrawTest::TestBody() { // Nothing. } -CGContextRef testing::DrawTest::GetDrawingContext() { +template +CGContextRef testing::DrawTest::GetDrawingContext() { return _context.get(); } -void testing::DrawTest::SetDrawingBounds(CGRect bounds) { +template +void testing::DrawTest::SetDrawingBounds(CGRect bounds) { _bounds = bounds; } -CGRect testing::DrawTest::GetDrawingBounds() { +template +CGRect testing::DrawTest::GetDrawingBounds() { return _bounds; } -void WhiteBackgroundTest::SetUpContext() { - CGContextRef context = GetDrawingContext(); - CGRect bounds = GetDrawingBounds(); +template +void WhiteBackgroundTest::SetUpContext() { + CGContextRef context = this->GetDrawingContext(); + CGRect bounds = this->GetDrawingBounds(); CGContextSaveGState(context); CGContextSetRGBFillColor(context, 1.0, 1.0, 1.0, 1.0); @@ -166,21 +180,34 @@ void WhiteBackgroundTest::SetUpContext() { CGContextSetRGBStrokeColor(context, 0.0, 0.0, 0.0, 1.0); } -CGSize UIKitMimicTest::CanvasSize() { - CGSize parent = WhiteBackgroundTest::CanvasSize(); +template +CGSize UIKitMimicTest::CanvasSize() { + CGSize parent = WhiteBackgroundTest::CanvasSize(); return { parent.width * 2., parent.height * 2. }; } -void UIKitMimicTest::SetUpContext() { - WhiteBackgroundTest::SetUpContext(); +template +void UIKitMimicTest::SetUpContext() { + WhiteBackgroundTest::SetUpContext(); - CGContextRef context = GetDrawingContext(); - CGRect bounds = GetDrawingBounds(); + CGContextRef context = this->GetDrawingContext(); + CGRect bounds = this->GetDrawingBounds(); CGContextScaleCTM(context, 1.0, -1.0); CGContextTranslateCTM(context, 0, -bounds.size.height); CGContextScaleCTM(context, 2.0, 2.0); bounds = CGRectApplyAffineTransform(bounds, CGAffineTransformMakeScale(.5, .5)); - SetDrawingBounds(bounds); + this->SetDrawingBounds(bounds); } + +// Force templates so they compile +template class ::testing::DrawTest<>; +template class WhiteBackgroundTest<>; +template class UIKitMimicTest<>; +template class ::testing::DrawTest>; +template class WhiteBackgroundTest>; +template class UIKitMimicTest>; +template class ::testing::DrawTest>; +template class WhiteBackgroundTest>; +template class UIKitMimicTest>; \ No newline at end of file diff --git a/tests/UnitTests/CoreGraphics.drawing/DrawingTest.h b/tests/UnitTests/CoreGraphics.drawing/DrawingTest.h index a0393632ca..513981cfbe 100644 --- a/tests/UnitTests/CoreGraphics.drawing/DrawingTest.h +++ b/tests/UnitTests/CoreGraphics.drawing/DrawingTest.h @@ -20,8 +20,12 @@ #include #include +#include "ImageComparison.h" + +// Due to how templates are compiled as needed, any new usage of templates needs to be "forced" in DrawingTest.cpp namespace testing { +template > class DrawTest : public ::testing::Test { private: woc::unique_cf _context; @@ -63,19 +67,21 @@ inline CGRect _CGRectCenteredOnPoint(CGSize size, CGPoint point) { }; } -class WhiteBackgroundTest : public ::testing::DrawTest { +template > +class WhiteBackgroundTest : public ::testing::DrawTest { protected: virtual void SetUpContext(); }; -class UIKitMimicTest : public WhiteBackgroundTest { +template > +class UIKitMimicTest : public WhiteBackgroundTest { protected: virtual CGSize CanvasSize(); virtual void SetUpContext(); }; #define DRAW_TEST(test_case_name, test_name) \ - GTEST_TEST_(test_case_name, test_name, ::testing::DrawTest, ::testing::internal::GetTestTypeId()) + GTEST_TEST_(test_case_name, test_name, ::testing::DrawTest<>, ::testing::internal::GetTestTypeId()) #define DRAW_TEST_F(test_case_name, test_name, test_fixture) \ GTEST_TEST_(test_case_name, test_name, test_fixture, ::testing::internal::GetTestTypeId()) @@ -83,4 +89,19 @@ class UIKitMimicTest : public WhiteBackgroundTest { #define DISABLED_DRAW_TEST_F(test_case_name, test_name, test_fixture) DRAW_TEST_F(test_case_name, DISABLED_##test_name, test_fixture) #define DRAW_TEST_P(test_case_name, test_name) TEST_P(test_case_name, test_name) -#define DISABLED_DRAW_TEST_P(test_case_name, test_name) DRAW_TEST_P(test_case_name, DISABLED_##test_name) \ No newline at end of file +#define DISABLED_DRAW_TEST_P(test_case_name, test_name) DRAW_TEST_P(test_case_name, DISABLED_##test_name) + +#define TEXT_DRAW_TEST(test_case_name, test_name) \ + GTEST_TEST_(test_case_name, \ + test_name, \ + ::testing::DrawTest>, \ + ::testing::internal::GetTestTypeId()) +#define TEXT_DRAW_TEST_F(test_case_name, test_name, test_fixture) \ + GTEST_TEST_(test_case_name, test_name, test_fixture, ::testing::internal::GetTestTypeId()) + +#define DISABLED_TEXT_DRAW_TEST(test_case_name, test_name) TEXT_DRAW_TEST(test_case_name, DISABLED_##test_name) +#define DISABLED_TEXT_DRAW_TEST_F(test_case_name, test_name, test_fixture) \ + TEXT_DRAW_TEST_F(test_case_name, DISABLED_##test_name, test_fixture) + +#define TEXT_DRAW_TEST_P(test_case_name, test_name) TEST_P(test_case_name, test_name) +#define DISABLED_TEXT_DRAW_TEST_P(test_case_name, test_name) TEXT_DRAW_TEST_P(test_case_name, DISABLED_##test_name) \ No newline at end of file diff --git a/tests/functionaltests/AppDelegate.h b/tests/functionaltests/AppDelegate.h new file mode 100644 index 0000000000..48690e1ca7 --- /dev/null +++ b/tests/functionaltests/AppDelegate.h @@ -0,0 +1,24 @@ +//****************************************************************************** +// +// Copyright (c) Microsoft. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +//****************************************************************************** + +#import + +@interface AppDelegate : UIResponder + +@property (strong, nonatomic) UIWindow* window; +@property (strong, nonatomic) UIViewController* viewController; + +@end diff --git a/tests/functionaltests/AppDelegate.mm b/tests/functionaltests/AppDelegate.mm new file mode 100644 index 0000000000..30bfe35dd9 --- /dev/null +++ b/tests/functionaltests/AppDelegate.mm @@ -0,0 +1,64 @@ +//****************************************************************************** +// +// Copyright (c) Microsoft. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +//****************************************************************************** + +#import +#import + +@interface AppDelegate () + +@end + +@implementation AppDelegate + +- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions { + self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; + MainViewController* mainViewController = [[MainViewController alloc] init]; + self.viewController = (UIViewController*)[[UINavigationController alloc] initWithRootViewController:mainViewController]; + self.window.rootViewController = self.viewController; + [self.window makeKeyAndVisible]; + + return YES; +} + +- (void)applicationWillResignActive:(UIApplication*)application { + // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions + // (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background + // state. + // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to + // pause the game. +} + +- (void)applicationDidEnterBackground:(UIApplication*)application { + // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to + // restore your application to its current state in case it is terminated later. + // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. +} + +- (void)applicationWillEnterForeground:(UIApplication*)application { + // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering + // the background. +} + +- (void)applicationDidBecomeActive:(UIApplication*)application { + // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the + // background, optionally refresh the user interface. +} + +- (void)applicationWillTerminate:(UIApplication*)application { + // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. +} + +@end diff --git a/tests/functionaltests/FunctionalTestHelpers.h b/tests/functionaltests/FunctionalTestHelpers.h index ae89456544..ff3790f07b 100644 --- a/tests/functionaltests/FunctionalTestHelpers.h +++ b/tests/functionaltests/FunctionalTestHelpers.h @@ -16,8 +16,11 @@ #pragma once -// Cleanup method to call after every test class to prevent leaking UIApplication -void FunctionalTestCleanupUIApplication(); +// Setup method to call before every test class to initialize the UIApplication +bool FunctionalTestSetupUIApplication(); + +// Cleanup method to call after every test class to free the UIApplication +bool FunctionalTestCleanupUIApplication(); #ifdef __OBJC__ #import diff --git a/tests/functionaltests/FunctionalTestHelpers.mm b/tests/functionaltests/FunctionalTestHelpers.mm index 1576b82515..99752d993c 100644 --- a/tests/functionaltests/FunctionalTestHelpers.mm +++ b/tests/functionaltests/FunctionalTestHelpers.mm @@ -1,6 +1,6 @@ //****************************************************************************** // -// Copyright (c) 2016 Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft. All rights reserved. // // This code is licensed under the MIT License (MIT). // @@ -14,14 +14,36 @@ // //****************************************************************************** -#import "FunctionalTestHelpers.h" +#import +#import +#import + #include "UIKit/UIApplication.h" +#include "UIViewInternal.h" #import +#import #import -// Prevents UIApplication state from carrying over between functional tests -void FunctionalTestCleanupUIApplication() { - [[UIApplication sharedApplication] _destroy]; +// This is a method that UIKit exposes for the test frameworks to use. +extern "C" void UIApplicationInitializeFunctionalTest(const wchar_t*, const wchar_t*); + +// Launches the functional test app +bool FunctionalTestSetupUIApplication() { + RunSynchronouslyOnMainThread(^{ + // The name of our default 'AppDelegate' class + UIApplicationInitializeFunctionalTest(nullptr, Strings::NarrowToWide(NSStringFromClass([AppDelegate class])).c_str()); + }); + + return true; +} + +// Terminates the functional test app +bool FunctionalTestCleanupUIApplication() { + RunSynchronouslyOnMainThread(^{ + [[UIApplication sharedApplication] _destroy]; + }); + + return true; } // Gets the path to the app installation location diff --git a/tests/functionaltests/FunctionalTests.cpp b/tests/functionaltests/FunctionalTests.cpp index 6be476d6c6..efe998c414 100644 --- a/tests/functionaltests/FunctionalTests.cpp +++ b/tests/functionaltests/FunctionalTests.cpp @@ -28,14 +28,6 @@ MODULE_PROPERTY(L"UAP:Host", L"Xaml") MODULE_PROPERTY(L"UAP:AppXManifest", L"Default.AppxManifest.xml") END_MODULE() -// This is a method that UIKit exposes for the test frameworks to use. -extern "C" void UIApplicationInitialize(const wchar_t*, const wchar_t*); - -static void UIApplicationDefaultInitialize() { - // Pass null to indicate default app and app delegate classes - UIApplicationInitialize(nullptr, nullptr); -} - // // How is functional test organized? // @@ -100,7 +92,7 @@ class SampleTest { // 2. Use the same mechanism as in TEST_METHOD below to export a method from the WinObjC test file and call it here. // 3. If you do not need this functionality feel free to remove this for your test class. TEST_CLASS_SETUP(SampleTestClassSetup) { - return SUCCEEDED(FrameworkHelper::RunOnUIThread(&UIApplicationDefaultInitialize)); + return FunctionalTestSetupUIApplication(); } // SampleTest test class cleanup. @@ -109,7 +101,7 @@ class SampleTest { // 2. Use the same mechanism as in TEST_METHOD below to export a method from the WinObjC test file and call it here. // 3. If you do not need this functionality feel free to remove this for your test class. TEST_CLASS_CLEANUP(SampleTestClassCleanup) { - return true; + return FunctionalTestCleanupUIApplication(); } // SampleTest test method setup. @@ -181,11 +173,11 @@ class NSURL { END_TEST_CLASS() TEST_CLASS_SETUP(NSURLClassSetup) { - return SUCCEEDED(FrameworkHelper::RunOnUIThread(&UIApplicationDefaultInitialize)); + return FunctionalTestSetupUIApplication(); } - TEST_METHOD_CLEANUP(NSURLCleanup) { - return SUCCEEDED(FrameworkHelper::RunOnUIThread(&FunctionalTestCleanupUIApplication)); + TEST_CLASS_CLEANUP(NSURLClassCleanup) { + return FunctionalTestCleanupUIApplication(); } // @@ -268,12 +260,12 @@ class NSUserDefaults { BEGIN_TEST_CLASS(NSUserDefaults) END_TEST_CLASS() - TEST_CLASS_SETUP(NSURLClassSetup) { - return SUCCEEDED(FrameworkHelper::RunOnUIThread(&UIApplicationDefaultInitialize)); + TEST_CLASS_SETUP(NSUserDefaultsClassSetup) { + return FunctionalTestSetupUIApplication(); } - TEST_METHOD_CLEANUP(NSUserDefaultsCleanup) { - return SUCCEEDED(FrameworkHelper::RunOnUIThread(&FunctionalTestCleanupUIApplication)); + TEST_CLASS_CLEANUP(NSUserDefaultsClassCleanup) { + return FunctionalTestCleanupUIApplication(); } TEST_METHOD(NSUserDefaults_Basic) { @@ -304,12 +296,12 @@ class NSBundle { BEGIN_TEST_CLASS(NSBundle) END_TEST_CLASS() - TEST_CLASS_SETUP(NSURLClassSetup) { - return SUCCEEDED(FrameworkHelper::RunOnUIThread(&UIApplicationDefaultInitialize)); + TEST_CLASS_SETUP(NSBundleClassSetup) { + return FunctionalTestSetupUIApplication(); } - TEST_METHOD_CLEANUP(NSBundleCleanup) { - return SUCCEEDED(FrameworkHelper::RunOnUIThread(&FunctionalTestCleanupUIApplication)); + TEST_CLASS_CLEANUP(NSBundleClassCleanup) { + return FunctionalTestCleanupUIApplication(); } TEST_METHOD(NSBundle_MSAppxURL) { @@ -330,15 +322,14 @@ class AssetsLibrary { TEST_CLASS_SETUP(AssetsLibraryClassSetup) { bool success = AssetsLibraryTestVideoSetup("AssetsLibraryTestVideo.mp4"); - return (success & SUCCEEDED(FrameworkHelper::RunOnUIThread(&UIApplicationDefaultInitialize))); + success &= FunctionalTestSetupUIApplication(); + return success; } TEST_CLASS_CLEANUP(AssetsLibraryClassCleanup) { - return AssetsLibraryTestVideoCleanup("AssetsLibraryTestVideo.mp4"); - } - - TEST_METHOD_CLEANUP(AssetsLibraryCleanup) { - return SUCCEEDED(FrameworkHelper::RunOnUIThread(&FunctionalTestCleanupUIApplication)); + bool success = AssetsLibraryTestVideoCleanup("AssetsLibraryTestVideo.mp4"); + success &= FunctionalTestCleanupUIApplication(); + return success; } TEST_METHOD(AssetsLibrary_GetVideoAsset) { @@ -362,8 +353,8 @@ class CortanaVoiceCommandForegroundActivation { return SUCCEEDED(FrameworkHelper::RunOnUIThread(&CortanaTestVoiceCommandForegroundActivation)); } - TEST_METHOD_CLEANUP(CortanaVoiceCommandForegroundCleanup) { - return SUCCEEDED(FrameworkHelper::RunOnUIThread(&FunctionalTestCleanupUIApplication)); + TEST_CLASS_CLEANUP(CortanaVoiceCommandForegroundTestClassCleanup) { + return FunctionalTestCleanupUIApplication(); } TEST_METHOD(Cortana_VoiceCommandForegroundActivationDelegateMethodsCalled) { @@ -384,8 +375,8 @@ class CortanaProtocolForegroundActivation { return SUCCEEDED(FrameworkHelper::RunOnUIThread(&CortanaTestProtocolForegroundActivation)); } - TEST_METHOD_CLEANUP(CortanaProtocolForegroundCleanup) { - return SUCCEEDED(FrameworkHelper::RunOnUIThread(&FunctionalTestCleanupUIApplication)); + TEST_CLASS_CLEANUP(CortanaProtocolForegroundTestClassCleanup) { + return FunctionalTestCleanupUIApplication(); } TEST_METHOD(Cortana_ProtocolForegroundActivationDelegateMethodsCalled) { @@ -405,8 +396,8 @@ class ToastNotificationForegroundActivation { return SUCCEEDED(FrameworkHelper::RunOnUIThread(&ToastNotificationTestForegroundActivation)); } - TEST_METHOD_CLEANUP(ToastNotificationForegroundCleanup) { - return SUCCEEDED(FrameworkHelper::RunOnUIThread(&FunctionalTestCleanupUIApplication)); + TEST_CLASS_CLEANUP(ToastNotificationForegroundTestClassCleanup) { + return FunctionalTestCleanupUIApplication(); } TEST_METHOD(ToastNotification_ForegroundActivationDelegateMethodsCalled) { @@ -422,11 +413,11 @@ class ActivatedAppReceivesToastNotification { TEST_CLASS_SETUP(ActivatedAppReceivesToastNotificationTestClassSetup) { // The class setup allows us to activate the app in our test method, but can only be done once per class - return SUCCEEDED(FrameworkHelper::RunOnUIThread(&UIApplicationDefaultInitialize)); + return FunctionalTestSetupUIApplication(); } - TEST_METHOD_CLEANUP(ActivatedAppReceivesToastNotificationCleanup) { - return SUCCEEDED(FrameworkHelper::RunOnUIThread(&FunctionalTestCleanupUIApplication)); + TEST_CLASS_CLEANUP(ActivatedAppReceivesToastNotificationTestClassCleanup) { + return FunctionalTestCleanupUIApplication(); } TEST_METHOD(ToastNotification_ActivatedAppReceivesToastNotification) { @@ -451,8 +442,8 @@ class FileActivationForegroundActivation { return SUCCEEDED(FrameworkHelper::RunOnUIThread(&FileActivatedTestForegroundActivation)); } - TEST_METHOD_CLEANUP(FileActivationForegroundActivationCleanup) { - return SUCCEEDED(FrameworkHelper::RunOnUIThread(&FunctionalTestCleanupUIApplication)); + TEST_CLASS_CLEANUP(FileActivationForegroundActivationClassCleanup) { + return FunctionalTestCleanupUIApplication(); } TEST_METHOD(FileActivation_TestForegroundActivationDelegateMethodsCalled) { @@ -510,12 +501,12 @@ class UIKitTests { BEGIN_TEST_CLASS(UIKitTests) END_TEST_CLASS() - TEST_CLASS_SETUP(UIKitTestsSetup) { - return SUCCEEDED(FrameworkHelper::RunOnUIThread(&UIApplicationDefaultInitialize)); + TEST_CLASS_SETUP(UIKitTestsClassSetup) { + return FunctionalTestSetupUIApplication(); } - TEST_METHOD_CLEANUP(UIKitTestsCleanup) { - return SUCCEEDED(FrameworkHelper::RunOnUIThread(&FunctionalTestCleanupUIApplication)); + TEST_CLASS_CLEANUP(UIKitTestsClassCleanup) { + return FunctionalTestCleanupUIApplication(); } TEST_METHOD(UIView_Create) { @@ -683,11 +674,11 @@ class ProjectionTest { END_TEST_CLASS() TEST_CLASS_SETUP(ProjectionTestClassSetup) { - return SUCCEEDED(FrameworkHelper::RunOnUIThread(&UIApplicationDefaultInitialize)); + return FunctionalTestSetupUIApplication(); } - TEST_METHOD_CLEANUP(ProjectionTestCleanup) { - return SUCCEEDED(FrameworkHelper::RunOnUIThread(&FunctionalTestCleanupUIApplication)); + TEST_CLASS_CLEANUP(ProjectionTestClassCleanup) { + return FunctionalTestCleanupUIApplication(); } TEST_METHOD(ProjectionTest_WUCCoreDispatcherSanity) { @@ -730,8 +721,12 @@ class UIApplicationTests { BEGIN_TEST_CLASS(UIApplicationTests) END_TEST_CLASS() - TEST_CLASS_SETUP(UIApplicationTestsSetup) { - return SUCCEEDED(FrameworkHelper::RunOnUIThread(&UIApplicationDefaultInitialize)); + TEST_CLASS_SETUP(UIApplicationTestsClassSetup) { + return FunctionalTestSetupUIApplication(); + } + + TEST_CLASS_CLEANUP(UIApplicationTestsClassCleanup) { + return FunctionalTestCleanupUIApplication(); } TEST_METHOD(UIApplicationTests_OpenURL) { @@ -749,12 +744,12 @@ class NSURLStorageFileTests { BEGIN_TEST_CLASS(NSURLStorageFileTests) END_TEST_CLASS() - TEST_CLASS_SETUP(NSURLStorageFileTestsSetup) { - return SUCCEEDED(FrameworkHelper::RunOnUIThread(&UIApplicationDefaultInitialize)); + TEST_CLASS_SETUP(NSURLStorageFileTestsClassSetup) { + return FunctionalTestSetupUIApplication(); } - TEST_METHOD_CLEANUP(NSURLStorageFileTestsCleanup) { - return SUCCEEDED(FrameworkHelper::RunOnUIThread(&FunctionalTestCleanupUIApplication)); + TEST_CLASS_CLEANUP(NSURLStorageFileTestsClassCleanup) { + return FunctionalTestCleanupUIApplication(); } TEST_METHOD(NSURLTests_StorageFileURL) { @@ -773,12 +768,12 @@ class CoreAnimationTests { BEGIN_TEST_CLASS(CoreAnimationTests) END_TEST_CLASS() - TEST_CLASS_SETUP(CoreAnimationTestsSetup) { - return SUCCEEDED(FrameworkHelper::RunOnUIThread(&UIApplicationDefaultInitialize)); + TEST_CLASS_SETUP(CoreAnimationTestsClassSetup) { + return FunctionalTestSetupUIApplication(); } - TEST_METHOD_CLEANUP(CoreAnimationTestsCleanup) { - return SUCCEEDED(FrameworkHelper::RunOnUIThread(&FunctionalTestCleanupUIApplication)); + TEST_CLASS_CLEANUP(CoreAnimationTestsClassCleanup) { + return FunctionalTestCleanupUIApplication(); } TEST_METHOD(CALayerAppearance_OpacityChanged) { diff --git a/tests/functionaltests/Logger.cpp b/tests/functionaltests/Logger.cpp index caf5817181..61692f3c12 100644 --- a/tests/functionaltests/Logger.cpp +++ b/tests/functionaltests/Logger.cpp @@ -1,6 +1,6 @@ //****************************************************************************** // -// Copyright (c) 2016 Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft. All rights reserved. // // This code is licensed under the MIT License (MIT). // diff --git a/tests/functionaltests/Logger.h b/tests/functionaltests/Logger.h index 95b4e51f9c..01ce434f0a 100644 --- a/tests/functionaltests/Logger.h +++ b/tests/functionaltests/Logger.h @@ -1,6 +1,6 @@ //****************************************************************************** // -// Copyright (c) 2016 Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft. All rights reserved. // // This code is licensed under the MIT License (MIT). // diff --git a/tests/functionaltests/MainViewController.h b/tests/functionaltests/MainViewController.h new file mode 100644 index 0000000000..ab6270edcc --- /dev/null +++ b/tests/functionaltests/MainViewController.h @@ -0,0 +1,21 @@ +//****************************************************************************** +// +// Copyright (c) Microsoft. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +//****************************************************************************** + +#import "UIKit/UIViewController.h" + +@interface MainViewController : UIViewController + +@end diff --git a/tests/functionaltests/MainViewController.mm b/tests/functionaltests/MainViewController.mm new file mode 100644 index 0000000000..8f2ea7dc55 --- /dev/null +++ b/tests/functionaltests/MainViewController.mm @@ -0,0 +1,40 @@ +//****************************************************************************** +// +// Copyright (c) 2016 Intel Corporation. All rights reserved. +// Copyright (c) Microsoft. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +//****************************************************************************** + +#import + +#import "UIKit/UIColor.h" +#import "UIKit/UIView.h" + +@interface MainViewController () + +@end + +@implementation MainViewController + +- (void)viewDidLoad { + self.view.backgroundColor = [UIColor lightGrayColor]; + + [super viewDidLoad]; +} + +- (void)didReceiveMemoryWarning { + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} + +@end diff --git a/tests/functionaltests/functionaltest-api.h b/tests/functionaltests/functionaltest-api.h index 7183889bef..659b6e435c 100644 --- a/tests/functionaltests/functionaltest-api.h +++ b/tests/functionaltests/functionaltest-api.h @@ -1,6 +1,6 @@ //****************************************************************************** // -// Copyright (c) 2016 Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft. All rights reserved. // // This code is licensed under the MIT License (MIT). // diff --git a/tests/functionaltests/pch.h b/tests/functionaltests/pch.h index 862a08410a..9d4b22e175 100644 --- a/tests/functionaltests/pch.h +++ b/tests/functionaltests/pch.h @@ -1,6 +1,6 @@ //****************************************************************************** // -// Copyright (c) 2016 Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft. All rights reserved. // // This code is licensed under the MIT License (MIT). // diff --git a/tests/functionaltests/targetver.h b/tests/functionaltests/targetver.h index 62356d604c..c8fb971184 100644 --- a/tests/functionaltests/targetver.h +++ b/tests/functionaltests/targetver.h @@ -1,6 +1,6 @@ //****************************************************************************** // -// Copyright (c) 2016 Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft. All rights reserved. // // This code is licensed under the MIT License (MIT). // diff --git a/tests/unittests/CoreGraphics.Drawing/CGContextDrawing_FillTests.cpp b/tests/unittests/CoreGraphics.Drawing/CGContextDrawing_FillTests.cpp index cc318fb6b5..c248902e60 100644 --- a/tests/unittests/CoreGraphics.Drawing/CGContextDrawing_FillTests.cpp +++ b/tests/unittests/CoreGraphics.Drawing/CGContextDrawing_FillTests.cpp @@ -16,7 +16,7 @@ #include "DrawingTest.h" -DISABLED_DRAW_TEST_F(CGContextFill, ConcentricCirclesWinding, WhiteBackgroundTest) { +DISABLED_DRAW_TEST_F(CGContextFill, ConcentricCirclesWinding, WhiteBackgroundTest<>) { CGContextRef context = GetDrawingContext(); CGRect bounds = GetDrawingBounds(); @@ -38,7 +38,7 @@ DISABLED_DRAW_TEST_F(CGContextFill, ConcentricCirclesWinding, WhiteBackgroundTes CGPathRelease(concentricCirclesPath); } -DISABLED_DRAW_TEST_F(CGContextFill, ConcentricCirclesEvenOdd, WhiteBackgroundTest) { +DISABLED_DRAW_TEST_F(CGContextFill, ConcentricCirclesEvenOdd, WhiteBackgroundTest<>) { CGContextRef context = GetDrawingContext(); CGRect bounds = GetDrawingBounds(); @@ -60,7 +60,7 @@ DISABLED_DRAW_TEST_F(CGContextFill, ConcentricCirclesEvenOdd, WhiteBackgroundTes CGPathRelease(concentricCirclesPath); } -DISABLED_DRAW_TEST_F(CGContextFill, ConcentricRectsWinding, WhiteBackgroundTest) { +DISABLED_DRAW_TEST_F(CGContextFill, ConcentricRectsWinding, WhiteBackgroundTest<>) { CGContextRef context = GetDrawingContext(); CGRect bounds = GetDrawingBounds(); @@ -82,7 +82,7 @@ DISABLED_DRAW_TEST_F(CGContextFill, ConcentricRectsWinding, WhiteBackgroundTest) CGPathRelease(path); } -DISABLED_DRAW_TEST_F(CGContextFill, ConcentricRectsEvenOdd, WhiteBackgroundTest) { +DISABLED_DRAW_TEST_F(CGContextFill, ConcentricRectsEvenOdd, WhiteBackgroundTest<>) { CGContextRef context = GetDrawingContext(); CGRect bounds = GetDrawingBounds(); diff --git a/tests/unittests/CoreGraphics.Drawing/CGContextDrawing_ShadowTests.cpp b/tests/unittests/CoreGraphics.Drawing/CGContextDrawing_ShadowTests.cpp index 9950d3d1b8..68dd68e2a4 100644 --- a/tests/unittests/CoreGraphics.Drawing/CGContextDrawing_ShadowTests.cpp +++ b/tests/unittests/CoreGraphics.Drawing/CGContextDrawing_ShadowTests.cpp @@ -16,7 +16,7 @@ #include "DrawingTest.h" -DISABLED_DRAW_TEST_F(CGContext, Shadow, WhiteBackgroundTest) { +DISABLED_DRAW_TEST_F(CGContext, Shadow, WhiteBackgroundTest<>) { CGContextRef context = GetDrawingContext(); CGRect bounds = GetDrawingBounds(); @@ -31,7 +31,7 @@ DISABLED_DRAW_TEST_F(CGContext, Shadow, WhiteBackgroundTest) { CGContextStrokeRect(context, rect); } -DISABLED_DRAW_TEST_F(CGContext, ShadowWithRotatedCTM, WhiteBackgroundTest) { +DISABLED_DRAW_TEST_F(CGContext, ShadowWithRotatedCTM, WhiteBackgroundTest<>) { CGContextRef context = GetDrawingContext(); CGRect bounds = GetDrawingBounds(); diff --git a/tests/unittests/CoreGraphics.Drawing/CGPathDrawingTests.cpp b/tests/unittests/CoreGraphics.Drawing/CGPathDrawingTests.cpp index 94de69bf7f..c5481983f2 100644 --- a/tests/unittests/CoreGraphics.Drawing/CGPathDrawingTests.cpp +++ b/tests/unittests/CoreGraphics.Drawing/CGPathDrawingTests.cpp @@ -16,7 +16,7 @@ #include "DrawingTest.h" -DRAW_TEST_F(CGPath, AddCurveToPoint, UIKitMimicTest) { +DRAW_TEST_F(CGPath, AddCurveToPoint, UIKitMimicTest<>) { CGContextRef context = GetDrawingContext(); CGRect bounds = GetDrawingBounds(); @@ -36,7 +36,7 @@ DRAW_TEST_F(CGPath, AddCurveToPoint, UIKitMimicTest) { CGPathRelease(thepath); } -DISABLED_DRAW_TEST_F(CGPath, AddEllipse, UIKitMimicTest) { +DISABLED_DRAW_TEST_F(CGPath, AddEllipse, UIKitMimicTest<>) { CGContextRef context = GetDrawingContext(); CGRect bounds = GetDrawingBounds(); @@ -58,7 +58,7 @@ DISABLED_DRAW_TEST_F(CGPath, AddEllipse, UIKitMimicTest) { CGPathRelease(thepath); } -DRAW_TEST_F(CGPath, AddLineToPoint, UIKitMimicTest) { +DRAW_TEST_F(CGPath, AddLineToPoint, UIKitMimicTest<>) { CGContextRef context = GetDrawingContext(); CGRect bounds = GetDrawingBounds(); @@ -84,7 +84,7 @@ DRAW_TEST_F(CGPath, AddLineToPoint, UIKitMimicTest) { CGPathRelease(thepath); } -DRAW_TEST_F(CGPath, AddPath, UIKitMimicTest) { +DRAW_TEST_F(CGPath, AddPath, UIKitMimicTest<>) { CGContextRef context = GetDrawingContext(); CGRect bounds = GetDrawingBounds(); @@ -116,7 +116,7 @@ DRAW_TEST_F(CGPath, AddPath, UIKitMimicTest) { CGPathRelease(theSecondPath); } -DRAW_TEST_F(CGPath, AddQuadCurveToPoint, UIKitMimicTest) { +DRAW_TEST_F(CGPath, AddQuadCurveToPoint, UIKitMimicTest<>) { CGContextRef context = GetDrawingContext(); CGRect bounds = GetDrawingBounds(); @@ -141,7 +141,7 @@ DRAW_TEST_F(CGPath, AddQuadCurveToPoint, UIKitMimicTest) { CGPathRelease(thePath); } -DRAW_TEST_F(CGPath, AddRect, UIKitMimicTest) { +DRAW_TEST_F(CGPath, AddRect, UIKitMimicTest<>) { CGContextRef context = GetDrawingContext(); CGRect bounds = GetDrawingBounds(); @@ -159,7 +159,7 @@ DRAW_TEST_F(CGPath, AddRect, UIKitMimicTest) { CGPathRelease(thePath); } -DRAW_TEST_F(CGPath, Apply, UIKitMimicTest) { +DRAW_TEST_F(CGPath, Apply, UIKitMimicTest<>) { CGContextRef context = GetDrawingContext(); CGRect bounds = GetDrawingBounds(); @@ -196,7 +196,7 @@ DRAW_TEST_F(CGPath, Apply, UIKitMimicTest) { CGPathRelease(thepath); } -DRAW_TEST_F(CGPath, CloseSubpath, UIKitMimicTest) { +DRAW_TEST_F(CGPath, CloseSubpath, UIKitMimicTest<>) { CGContextRef context = GetDrawingContext(); CGRect bounds = GetDrawingBounds(); @@ -223,7 +223,7 @@ DRAW_TEST_F(CGPath, CloseSubpath, UIKitMimicTest) { CGPathRelease(thePath); } -DRAW_TEST_F(CGPath, GetBoundingBox, UIKitMimicTest) { +DRAW_TEST_F(CGPath, GetBoundingBox, UIKitMimicTest<>) { CGContextRef context = GetDrawingContext(); CGRect bounds = GetDrawingBounds(); @@ -261,7 +261,7 @@ static void CGPathApplyCallback(void* context, const CGPathElement* element) { CGContextStrokePath((CGContextRef)context); } -DRAW_TEST_F(CGPath, PathApplyDraw, UIKitMimicTest) { +DRAW_TEST_F(CGPath, PathApplyDraw, UIKitMimicTest<>) { CGContextRef context = GetDrawingContext(); applyBounds = GetDrawingBounds(); CGFloat width = applyBounds.size.width; @@ -319,7 +319,7 @@ static void CGPathControlPointCallback(void* context, const CGPathElement* eleme } } -DRAW_TEST_F(CGPath, PathApplyControlPointsQuadCurve, UIKitMimicTest) { +DRAW_TEST_F(CGPath, PathApplyControlPointsQuadCurve, UIKitMimicTest<>) { CGContextRef context = GetDrawingContext(); CGRect bounds = GetDrawingBounds(); CGFloat width = bounds.size.width; @@ -345,7 +345,7 @@ DRAW_TEST_F(CGPath, PathApplyControlPointsQuadCurve, UIKitMimicTest) { CGPathRelease(thepath); } -DRAW_TEST_F(CGPath, PathApplyControlPointsArcs, UIKitMimicTest) { +DRAW_TEST_F(CGPath, PathApplyControlPointsArcs, UIKitMimicTest<>) { CGContextRef context = GetDrawingContext(); CGRect bounds = GetDrawingBounds(); CGFloat width = bounds.size.width; @@ -381,7 +381,7 @@ DRAW_TEST_F(CGPath, PathApplyControlPointsArcs, UIKitMimicTest) { CGPathRelease(thepath); } -DRAW_TEST_F(CGPath, PathApplyControlPointsArcsSimple, UIKitMimicTest) { +DRAW_TEST_F(CGPath, PathApplyControlPointsArcsSimple, UIKitMimicTest<>) { CGContextRef context = GetDrawingContext(); CGRect bounds = GetDrawingBounds(); CGFloat width = bounds.size.width; @@ -405,4 +405,4 @@ DRAW_TEST_F(CGPath, PathApplyControlPointsArcsSimple, UIKitMimicTest) { CGPathApply(thepath, context, CGPathControlPointCallback); CGPathRelease(thepath); -} \ No newline at end of file +} diff --git a/tests/unittests/CoreGraphics.drawing/CGContextBlendModeTests.cpp b/tests/unittests/CoreGraphics.drawing/CGContextBlendModeTests.cpp index 4354f16ff2..306fd4903c 100644 --- a/tests/unittests/CoreGraphics.drawing/CGContextBlendModeTests.cpp +++ b/tests/unittests/CoreGraphics.drawing/CGContextBlendModeTests.cpp @@ -50,7 +50,7 @@ CGNamedBlendMode compositionModes[] = { CGFloat alphas[] = { 0.5f, 1.f }; -class CGContextBlendMode : public WhiteBackgroundTest, public ::testing::WithParamInterface<::testing::tuple> { +class CGContextBlendMode : public WhiteBackgroundTest<>, public ::testing::WithParamInterface<::testing::tuple> { CFStringRef CreateOutputFilename() { const char* blendModeName = ::testing::get<1>(GetParam()).name; CGFloat alpha = ::testing::get<0>(GetParam()); diff --git a/tests/unittests/CoreGraphics.drawing/CGTextDrawing.cpp b/tests/unittests/CoreGraphics.drawing/CGTextDrawing.cpp index 5952e2516d..8329f1213f 100644 --- a/tests/unittests/CoreGraphics.drawing/CGTextDrawing.cpp +++ b/tests/unittests/CoreGraphics.drawing/CGTextDrawing.cpp @@ -32,7 +32,7 @@ static void __SetFontForContext(CGContextRef context) { CGContextSetFontSize(context, 144); } -DISABLED_DRAW_TEST_F(CGContext, ShowGlyphs, WhiteBackgroundTest) { +TEXT_DRAW_TEST_F(CGContext, ShowGlyphs, WhiteBackgroundTest>) { CGContextRef context = GetDrawingContext(); std::vector glyphs{ __CreateGlyphs() }; __SetFontForContext(context); @@ -40,14 +40,14 @@ DISABLED_DRAW_TEST_F(CGContext, ShowGlyphs, WhiteBackgroundTest) { CGContextShowGlyphs(context, glyphs.data(), glyphs.size()); } -DISABLED_DRAW_TEST_F(CGContext, ShowGlyphsAtPoint, WhiteBackgroundTest) { +TEXT_DRAW_TEST_F(CGContext, ShowGlyphsAtPoint, WhiteBackgroundTest>) { CGContextRef context = GetDrawingContext(); std::vector glyphs{ __CreateGlyphs() }; __SetFontForContext(context); CGContextShowGlyphsAtPoint(context, 25, 50, glyphs.data(), glyphs.size()); } -DISABLED_DRAW_TEST_F(CGContext, DrawWithRotatedTextMatrix, WhiteBackgroundTest) { +TEXT_DRAW_TEST_F(CGContext, DrawWithRotatedTextMatrix, WhiteBackgroundTest>) { CGContextRef context = GetDrawingContext(); std::vector glyphs{ __CreateGlyphs() }; __SetFontForContext(context); @@ -68,10 +68,10 @@ static const CGAffineTransform c_transforms[] = { CGAffineTransformMakeRotation( { 2, 2, 1.75, 2, 0, 0 }, CGAffineTransformIdentity }; -class CGTransform : public WhiteBackgroundTest, +class CGTransform : public WhiteBackgroundTest>, public ::testing::WithParamInterface<::testing::tuple> {}; -DISABLED_DRAW_TEST_P(CGTransform, TestMatrices) { +TEXT_DRAW_TEST_P(CGTransform, TestMatrices) { CGContextRef context = GetDrawingContext(); CGRect bounds = GetDrawingBounds(); @@ -87,10 +87,10 @@ INSTANTIATE_TEST_CASE_P(TestDrawingTextWithTransformedMatrices, CGTransform, ::testing::Combine(::testing::ValuesIn(c_transforms), ::testing::ValuesIn(c_transforms))); -class CGUIKitTransform : public UIKitMimicTest, +class CGUIKitTransform : public UIKitMimicTest>, public ::testing::WithParamInterface<::testing::tuple> {}; -DISABLED_DRAW_TEST_P(CGUIKitTransform, TestMatrices) { +TEXT_DRAW_TEST_P(CGUIKitTransform, TestMatrices) { CGContextRef context = GetDrawingContext(); CGRect bounds = GetDrawingBounds(); @@ -109,7 +109,7 @@ INSTANTIATE_TEST_CASE_P(TestDrawingTextWithTransformedMatrices, // On reference platform, CGContextShowText* can only be used with CGContextSelectFont // Which we do not currently support. #ifdef WINOBJC -DISABLED_DRAW_TEST_F(CGContext, ShowTextAtPoint, WhiteBackgroundTest) { +TEXT_DRAW_TEST_F(CGContext, ShowTextAtPoint, WhiteBackgroundTest>) { CGContextRef context = GetDrawingContext(); __SetFontForContext(context); CGContextShowTextAtPoint(context, 25, 50, "TEST", 4); diff --git a/tests/unittests/CoreGraphics.drawing/CTDrawingTests.cpp b/tests/unittests/CoreGraphics.drawing/CTDrawingTests.cpp index a220a6c5cd..8e2269c884 100644 --- a/tests/unittests/CoreGraphics.drawing/CTDrawingTests.cpp +++ b/tests/unittests/CoreGraphics.drawing/CTDrawingTests.cpp @@ -26,7 +26,7 @@ static NSURL* __GetURLFromPathRelativeToModuleDirectory(NSString* relativePath) } #endif // WINOBJC -DISABLED_DRAW_TEST_F(CTFrame, BasicDrawingTest, WhiteBackgroundTest) { +TEXT_DRAW_TEST_F(CTFrame, BasicDrawingTest, WhiteBackgroundTest>) { CGContextRef context = GetDrawingContext(); CGRect bounds = GetDrawingBounds(); @@ -65,7 +65,7 @@ DISABLED_DRAW_TEST_F(CTFrame, BasicDrawingTest, WhiteBackgroundTest) { CTFrameDraw(frame.get(), context); } -DISABLED_DRAW_TEST_F(CTFrame, BasicUIKitMimicDrawingTest, UIKitMimicTest) { +TEXT_DRAW_TEST_F(CTFrame, BasicUIKitMimicDrawingTest, UIKitMimicTest>) { CGContextRef context = GetDrawingContext(); CGRect bounds = GetDrawingBounds(); @@ -104,7 +104,7 @@ DISABLED_DRAW_TEST_F(CTFrame, BasicUIKitMimicDrawingTest, UIKitMimicTest) { CTFrameDraw(frame.get(), context); } -DISABLED_DRAW_TEST_F(CTFrame, BasicUnicodeTest, WhiteBackgroundTest) { +TEXT_DRAW_TEST_F(CTFrame, BasicUnicodeTest, WhiteBackgroundTest>) { CGContextRef context = GetDrawingContext(); CGRect bounds = GetDrawingBounds(); @@ -145,7 +145,7 @@ DISABLED_DRAW_TEST_F(CTFrame, BasicUnicodeTest, WhiteBackgroundTest) { CTFrameDraw(frame.get(), context); } -class CTFrame : public WhiteBackgroundTest, +class CTFrame : public WhiteBackgroundTest>, public ::testing::WithParamInterface<::testing::tuple> { CFStringRef CreateOutputFilename() { CTTextAlignment alignment = ::testing::get<0>(GetParam()); @@ -186,7 +186,7 @@ static void __DrawLoremIpsum(CGContextRef context, CGPathRef path, const CFStrin CTFrameDraw(frame.get(), context); } -DISABLED_DRAW_TEST_P(CTFrame, AlignLBMFontSize) { +TEXT_DRAW_TEST_P(CTFrame, AlignLBMFontSize) { CGContextRef context = GetDrawingContext(); CGRect bounds = GetDrawingBounds(); @@ -237,10 +237,10 @@ INSTANTIATE_TEST_CASE_P(TestAlignmentLineBreakMode, ::testing::ValuesIn(c_writingDirections), ::testing::ValuesIn(c_fontSizes))); -class Transform : public WhiteBackgroundTest, +class Transform : public WhiteBackgroundTest>, public ::testing::WithParamInterface<::testing::tuple> {}; -DISABLED_DRAW_TEST_P(Transform, TestMatrices) { +TEXT_DRAW_TEST_P(Transform, TestMatrices) { CGContextRef context = GetDrawingContext(); CGRect bounds = GetDrawingBounds(); @@ -292,10 +292,10 @@ INSTANTIATE_TEST_CASE_P(TestDrawingTextWithTransformedMatrices, Transform, ::testing::Combine(::testing::ValuesIn(c_transforms), ::testing::ValuesIn(c_transforms))); -class UIKitTransform : public UIKitMimicTest, +class UIKitTransform : public UIKitMimicTest>, public ::testing::WithParamInterface<::testing::tuple> {}; -DISABLED_DRAW_TEST_P(UIKitTransform, TestMatrices) { +TEXT_DRAW_TEST_P(UIKitTransform, TestMatrices) { CGContextRef context = GetDrawingContext(); CGRect bounds = GetDrawingBounds(); @@ -335,14 +335,16 @@ INSTANTIATE_TEST_CASE_P(TestDrawingUITransforms, UIKitTransform, ::testing::Combine(::testing::ValuesIn(c_transforms), ::testing::ValuesIn(c_transforms))); -class ExtraKerning : public WhiteBackgroundTest, public ::testing::WithParamInterface { +class ExtraKerning : public WhiteBackgroundTest>, + public ::testing::WithParamInterface { CFStringRef CreateOutputFilename() { CGFloat extraKerning = GetParam(); return CFStringCreateWithFormat(nullptr, nullptr, CFSTR("TestImage.ExtraKerning.%.02f.png"), extraKerning); } }; -DISABLED_DRAW_TEST_P(ExtraKerning, TestExtraKerning) { +// TODO 1696: Re-enable +DISABLED_TEXT_DRAW_TEST_P(ExtraKerning, TestExtraKerning) { CGContextRef context = GetDrawingContext(); CGRect bounds = GetDrawingBounds(); @@ -372,14 +374,15 @@ DISABLED_DRAW_TEST_P(ExtraKerning, TestExtraKerning) { static constexpr CGFloat c_extraKernings[] = { -1.0, 1.0, 5.25, 25.75 }; INSTANTIATE_TEST_CASE_P(TestDrawingTextInExtraKerning, ExtraKerning, ::testing::ValuesIn(c_extraKernings)); -class LineHeightMultiple : public WhiteBackgroundTest, public ::testing::WithParamInterface { +class LineHeightMultiple : public WhiteBackgroundTest>, + public ::testing::WithParamInterface { CFStringRef CreateOutputFilename() { CGFloat lineHeightMultiple = GetParam(); return CFStringCreateWithFormat(nullptr, nullptr, CFSTR("TestImage.LineHeightMultiple.%.02f.png"), lineHeightMultiple); } }; -DISABLED_DRAW_TEST_P(LineHeightMultiple, TestLineHeightMultiple) { +TEXT_DRAW_TEST_P(LineHeightMultiple, TestLineHeightMultiple) { CGContextRef context = GetDrawingContext(); CGRect bounds = GetDrawingBounds(); @@ -410,7 +413,7 @@ DISABLED_DRAW_TEST_P(LineHeightMultiple, TestLineHeightMultiple) { static constexpr CGFloat c_lineHeightMultiples[] = { -1.0, .75, 1.25 }; INSTANTIATE_TEST_CASE_P(TestDrawingTextInLineHeightMultiple, LineHeightMultiple, ::testing::ValuesIn(c_lineHeightMultiples)); -DISABLED_DRAW_TEST_F(CTRun, BasicDrawingTest, WhiteBackgroundTest) { +TEXT_DRAW_TEST_F(CTRun, BasicDrawingTest, WhiteBackgroundTest>) { CGContextRef context = GetDrawingContext(); CGRect bounds = GetDrawingBounds(); @@ -438,7 +441,7 @@ DISABLED_DRAW_TEST_F(CTRun, BasicDrawingTest, WhiteBackgroundTest) { CTLineDraw(line.get(), context); } -DISABLED_DRAW_TEST_F(CTLine, BasicDrawingTest, WhiteBackgroundTest) { +TEXT_DRAW_TEST_F(CTLine, BasicDrawingTest, WhiteBackgroundTest>) { CGContextRef context = GetDrawingContext(); CGRect bounds = GetDrawingBounds(); @@ -468,14 +471,15 @@ DISABLED_DRAW_TEST_F(CTLine, BasicDrawingTest, WhiteBackgroundTest) { CTRunDraw(run, context, {}); } -class Fonts : public WhiteBackgroundTest, public ::testing::WithParamInterface { +class Fonts : public WhiteBackgroundTest>, + public ::testing::WithParamInterface { CFStringRef CreateOutputFilename() { CFStringRef fontName = GetParam(); return CFStringCreateWithFormat(nullptr, nullptr, CFSTR("TestImage.Fonts.%@.png"), fontName); } }; -DISABLED_DRAW_TEST_P(Fonts, TestFonts) { +TEXT_DRAW_TEST_P(Fonts, TestFonts) { CGContextRef context = GetDrawingContext(); CGRect bounds = GetDrawingBounds(); @@ -505,7 +509,7 @@ static CFStringRef c_fontNames[] = { CFSTR("Arial"), CFSTR("Times New Roman"), C INSTANTIATE_TEST_CASE_P(TestDrawingTextInFonts, Fonts, ::testing::ValuesIn(c_fontNames)); #ifdef WINOBJC -DISABLED_DRAW_TEST_F(CTFontManager, DrawWithCustomFont, WhiteBackgroundTest) { +TEXT_DRAW_TEST_F(CTFontManager, DrawWithCustomFont, WhiteBackgroundTest>) { CGContextRef context = GetDrawingContext(); CGRect bounds = GetDrawingBounds(); @@ -552,7 +556,7 @@ DISABLED_DRAW_TEST_F(CTFontManager, DrawWithCustomFont, WhiteBackgroundTest) { } #endif // WINOBJC -DISABLED_DRAW_TEST_F(CTFont, DrawGlyphs, WhiteBackgroundTest) { +TEXT_DRAW_TEST_F(CTFont, DrawGlyphs, WhiteBackgroundTest>) { CGContextRef context = GetDrawingContext(); CGRect bounds = GetDrawingBounds(); diff --git a/tests/unittests/CoreGraphics.drawing/DrawingTestConfig.h b/tests/unittests/CoreGraphics.drawing/DrawingTestConfig.h index b07a3d0ee3..2452a82c1b 100644 --- a/tests/unittests/CoreGraphics.drawing/DrawingTestConfig.h +++ b/tests/unittests/CoreGraphics.drawing/DrawingTestConfig.h @@ -15,6 +15,7 @@ //****************************************************************************** #pragma once +#include enum class DrawingTestMode : int { Generate, Compare }; diff --git a/tests/unittests/CoreGraphics.drawing/ImageComparison.cpp b/tests/unittests/CoreGraphics.drawing/ImageComparison.cpp index bdefe2cc21..39dbd8b56a 100644 --- a/tests/unittests/CoreGraphics.drawing/ImageComparison.cpp +++ b/tests/unittests/CoreGraphics.drawing/ImageComparison.cpp @@ -167,7 +167,69 @@ struct RGBAImageBuffer { } }; -ImageDelta PixelByPixelImageComparator::CompareImages(CGImageRef left, CGImageRef right) { +template +struct __comparePixels { + template + Pixel operator()(const LP& background, const LP& bp, const RP& cp, size_t& npxchg); +}; + +template <> +struct __comparePixels { + template + Pixel operator()(const LP& background, const LP& bp, const RP& cp, size_t& npxchg) { + Pixel gp{}; + if (!(bp == cp)) { + ++npxchg; + if (cp == background) { + // Pixel is in EXPECTED but not ACTUAL + gp.r = gp.a = 255; + } else if (bp == background) { + // Pixel is in ACTUAL but not EXPECTED + gp.g = gp.a = 255; + } else { + // Pixel is in BOTH but DIFFERENT + gp.r = gp.g = gp.a = 255; + } + } else { + gp.r = gp.g = gp.b = 0; + gp.a = 255; + } + + return gp; + } +}; + +template <> +struct __comparePixels { + template + Pixel operator()(const LP& background, const LP& bp, const RP& cp, size_t& npxchg) { + Pixel gp{}; + if (!(bp == cp)) { + ++npxchg; + if (cp == background) { + // Pixel is in EXPECTED but not ACTUAL + gp.r = gp.a = 255; + } else if (bp == background) { + // Pixel is in ACTUAL but not EXPECTED + gp.g = gp.a = 255; + } else { + // Pixel is in BOTH but DIFFERENT + // Only comparing as mask so counts as match + gp.r = gp.g = gp.b = 0; + gp.a = 255; + --npxchg; + } + } else { + gp.r = gp.g = gp.b = 0; + gp.a = 255; + } + + return gp; + } +}; + +template +ImageDelta PixelByPixelImageComparator::CompareImages(CGImageRef left, CGImageRef right) { if (!left || !right) { return { ImageComparisonResult::Incomparable }; } @@ -189,27 +251,13 @@ ImageDelta PixelByPixelImageComparator::CompareImages(CGImageRef left, CGImageRe Pixel background = leftAccess.at(0, 0); size_t npxchg = 0; + __comparePixels pixelComparator{}; for (off_t y = 0; y < leftAccess.height; ++y) { for (off_t x = 0; x < leftAccess.width; ++x) { auto bp = leftAccess.at(x, y); auto cp = rightAccess.at(x, y); auto& gp = deltaBuffer.at(x, y); - if (bp != cp) { - ++npxchg; - if (cp == background) { - // Pixel is in EXPECTED but not ACTUAL - gp.r = gp.a = 255; - } else if (bp == background) { - // Pixel is in ACTUAL but not EXPECTED - gp.g = gp.a = 255; - } else { - // Pixel is in BOTH but DIFFERENT - gp.r = gp.g = gp.a = 255; - } - } else { - gp.r = gp.g = gp.b = 0; - gp.a = 255; - } + gp = pixelComparator(background, bp, cp, npxchg); } } @@ -231,6 +279,11 @@ ImageDelta PixelByPixelImageComparator::CompareImages(CGImageRef left, CGImageRe kCGRenderingIntentDefault) }; return { - (npxchg == 0 ? ImageComparisonResult::Same : ImageComparisonResult::Different), npxchg, deltaImage.get(), + (npxchg < FailureThreshold ? ImageComparisonResult::Same : ImageComparisonResult::Different), npxchg, deltaImage.get(), }; } + +// Force templates so they compile +template class PixelByPixelImageComparator<>; +template class PixelByPixelImageComparator; +template class PixelByPixelImageComparator; diff --git a/tests/unittests/CoreGraphics.drawing/ImageComparison.h b/tests/unittests/CoreGraphics.drawing/ImageComparison.h index 3613fba282..e411dd065b 100644 --- a/tests/unittests/CoreGraphics.drawing/ImageComparison.h +++ b/tests/unittests/CoreGraphics.drawing/ImageComparison.h @@ -21,6 +21,8 @@ enum class ImageComparisonResult : unsigned int { Unknown = 0, Incomparable, Different, Same }; +enum struct ComparisonMode { Exact, Mask }; + struct ImageDelta { ImageComparisonResult result; size_t differences; @@ -39,6 +41,7 @@ class ImageComparator { virtual ImageDelta CompareImages(CGImageRef left, CGImageRef right) = 0; }; +template class PixelByPixelImageComparator : public ImageComparator { public: ImageDelta CompareImages(CGImageRef left, CGImageRef right) override; diff --git a/tests/unittests/Foundation/NSArrayTests.mm b/tests/unittests/Foundation/NSArrayTests.mm index 76d5676a40..2c06835f98 100644 --- a/tests/unittests/Foundation/NSArrayTests.mm +++ b/tests/unittests/Foundation/NSArrayTests.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). // @@ -425,3 +425,13 @@ static unsigned long int objectIndexInArray(NSArray* array, int value, int start EXPECT_OBJCNE(input, output); } + +TEST(NSMutableArray, InsertingNilShouldThrow) { + NSMutableArray* arr = [NSMutableArray arrayWithObject:@"hello"]; + EXPECT_ANY_THROW(arr[0] = nil); + EXPECT_ANY_THROW([arr insertObject:nil atIndex:1]); + EXPECT_ANY_THROW([arr addObject:nil]); + EXPECT_ANY_THROW([arr replaceObjectAtIndex:0 withObject:nil]); + EXPECT_OBJCEQ(@"hello", arr[0]); + EXPECT_EQ(1, [arr count]); +} \ No newline at end of file diff --git a/tests/unittests/Foundation/NSAttributedStringTests.mm b/tests/unittests/Foundation/NSAttributedStringTests.mm index da57a7aea1..c562e14c29 100644 --- a/tests/unittests/Foundation/NSAttributedStringTests.mm +++ b/tests/unittests/Foundation/NSAttributedStringTests.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). // @@ -788,3 +788,8 @@ - (NSUInteger)length { EXPECT_OBJCNE(input, output); } + +TEST(NSMutableAttributedString, InsertingNilShouldThrow) { + NSMutableAttributedString* string = [[[NSMutableAttributedString alloc] initWithString:@"hello"] autorelease]; + EXPECT_ANY_THROW([string addAttribute:@"attribute" value:nil range:NSMakeRange(0, 3)]); +} \ No newline at end of file diff --git a/tests/unittests/Foundation/NSDictionaryTests.mm b/tests/unittests/Foundation/NSDictionaryTests.mm index 394a0d95e8..332ff0d659 100644 --- a/tests/unittests/Foundation/NSDictionaryTests.mm +++ b/tests/unittests/Foundation/NSDictionaryTests.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). // @@ -50,11 +50,11 @@ TEST(NSDictionary, KeysSortedByValueUsingComparator) { NSDictionary* testDict = @{ @"A" : @2, @"B" : @4, @"C" : @3, @"D" : @1 }; - NSArray* actualArray = [testDict keysSortedByValueUsingComparator: ^(id obj1, id obj2) { + NSArray* actualArray = [testDict keysSortedByValueUsingComparator:^(id obj1, id obj2) { return [obj1 compare:obj2]; }]; - NSArray* expectedArray = @[@"D", @"A", @"C", @"B" ]; + NSArray* expectedArray = @[ @"D", @"A", @"C", @"B" ]; ASSERT_OBJCEQ(expectedArray, actualArray); } @@ -70,8 +70,8 @@ } TEST(NSDictionary, KeysSortedByValue) { - NSDictionary* dictionary = @{@"f" : @6, @"b": @2, @"a" : @1, @"c" : @3, @"e" : @5, @"d" : @4}; - NSArray* expected = @[@"a", @"b", @"c", @"d", @"e", @"f"]; + NSDictionary* dictionary = @{ @"f" : @6, @"b" : @2, @"a" : @1, @"c" : @3, @"e" : @5, @"d" : @4 }; + NSArray* expected = @[ @"a", @"b", @"c", @"d", @"e", @"f" ]; NSArray* actual = [dictionary keysSortedByValueUsingComparator:^NSComparisonResult(id obj1, id obj2) { int a = [obj1 intValue]; int b = [obj2 intValue]; @@ -86,33 +86,42 @@ } TEST(NSDictionary, KeysSortedByValueWithOptions) { - NSDictionary* dictionary = @{@"f" : @6, @"b": @2, @"a" : @1, @"c" : @3, @"e" : @5, @"d" : @4}; - NSArray* expected = @[@"a", @"b", @"c", @"d", @"e", @"f"]; - NSArray* actual = [dictionary keysSortedByValueWithOptions:0 usingComparator:^NSComparisonResult(id obj1, id obj2) { - int a = [obj1 intValue]; - int b = [obj2 intValue]; - if (a == b) { - return NSOrderedSame; - } - - return (a > b) ? NSOrderedDescending : NSOrderedAscending; - }]; + NSDictionary* dictionary = @{ @"f" : @6, @"b" : @2, @"a" : @1, @"c" : @3, @"e" : @5, @"d" : @4 }; + NSArray* expected = @[ @"a", @"b", @"c", @"d", @"e", @"f" ]; + NSArray* actual = [dictionary keysSortedByValueWithOptions:0 + usingComparator:^NSComparisonResult(id obj1, id obj2) { + int a = [obj1 intValue]; + int b = [obj2 intValue]; + if (a == b) { + return NSOrderedSame; + } + + return (a > b) ? NSOrderedDescending : NSOrderedAscending; + }]; ASSERT_OBJCEQ(expected, actual); } TEST(NSDictionary, KeysSortedByValueWithOptions_Stable) { - NSDictionary* dictionary = @{@"a" : @1, @"b": @1, @"c" : @1, @"d" : @1, @"e" : @1, @"f" : @0}; - NSArray* expected = @[@"f", @"d", @"b", @"e", @"c", @"a"]; // Note: ordering after "f" is dependent on CFDictionary (this ordering matches the reference platform) - NSArray* actual = [dictionary keysSortedByValueWithOptions:NSSortStable usingComparator:^NSComparisonResult(id obj1, id obj2) { - int a = [obj1 intValue]; - int b = [obj2 intValue]; - if (a == b) { - return NSOrderedSame; - } - - return (a > b) ? NSOrderedDescending : NSOrderedAscending; - }]; + NSDictionary* dictionary = @{ @"a" : @1, @"b" : @1, @"c" : @1, @"d" : @1, @"e" : @1, @"f" : @0 }; + NSArray* expected = @[ + @"f", + @"d", + @"b", + @"e", + @"c", + @"a" + ]; // Note: ordering after "f" is dependent on CFDictionary (this ordering matches the reference platform) + NSArray* actual = [dictionary keysSortedByValueWithOptions:NSSortStable + usingComparator:^NSComparisonResult(id obj1, id obj2) { + int a = [obj1 intValue]; + int b = [obj2 intValue]; + if (a == b) { + return NSOrderedSame; + } + + return (a > b) ? NSOrderedDescending : NSOrderedAscending; + }]; ASSERT_OBJCEQ(expected, actual); } @@ -130,3 +139,23 @@ EXPECT_OBJCNE(input, output); } + +TEST(NSMutableDictionary, InsertingNilForKeyedSubscriptShouldRemoveValue) { + NSMutableDictionary* dict = [NSMutableDictionary dictionaryWithObject:@"world" forKey:@"hello"]; + [dict setObject:nil forKeyedSubscript:@"hello"]; + EXPECT_EQ(nil, dict[@"hello"]); + EXPECT_EQ(0, [dict count]); +} + +TEST(NSMutableDictionary, InsertingNilWithSubscriptingShouldRemoveValue) { + NSMutableDictionary* dict = [NSMutableDictionary dictionaryWithObject:@"world" forKey:@"hello"]; + dict[@"hello"] = nil; + EXPECT_EQ(nil, dict[@"hello"]); + EXPECT_EQ(0, [dict count]); +} + +TEST(NSMutableDictionary, SetObjectWithNilShouldThrow) { + NSMutableDictionary* dict = [NSMutableDictionary dictionaryWithObject:@"world" forKey:@"hello"]; + EXPECT_ANY_THROW([dict setObject:nil forKey:@"fail"]); + EXPECT_OBJCEQ(@"world", dict[@"hello"]); +} \ No newline at end of file diff --git a/tests/unittests/Foundation/NSSetTests.mm b/tests/unittests/Foundation/NSSetTests.mm index af4a07d229..1ce342f567 100644 --- a/tests/unittests/Foundation/NSSetTests.mm +++ b/tests/unittests/Foundation/NSSetTests.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). // @@ -143,3 +143,9 @@ EXPECT_OBJCNE(input, output); } + +TEST(NSMutableSet, ShouldThrowWhenTryingToInsertNil) { + NSMutableSet* set = [NSMutableSet set]; + EXPECT_ANY_THROW([set addObject:nil]); + EXPECT_EQ(0, [set count]); +} \ No newline at end of file diff --git a/tools/build/Submit-GithubBuildStatus.ps1 b/tools/build/Submit-GithubBuildStatus.ps1 index ac5a419810..842b072721 100644 --- a/tools/build/Submit-GithubBuildStatus.ps1 +++ b/tools/build/Submit-GithubBuildStatus.ps1 @@ -2,6 +2,7 @@ .SYNOPSIS Submits a CI build status to GitHub for the latest SHA1 in a pull request branch. #> +[CmdletBinding(SupportsShouldProcess=$True)] Param ( [Parameter(Mandatory=$true, HelpMessage="GitHub Pull Request specifier ( )")] [string]$PullRequest, @@ -28,8 +29,8 @@ Param ( [Parameter(HelpMessage="Optional description prepended to test results")] [string]$Description, - [Parameter(HelpMessage="Do not push status to GitHub")] - [switch]$OnlyPrintStatus + [Parameter(HelpMessage="Optional status-related URL")] + [string]$DetailsURL ) $ErrorActionPreference = "Stop"; @@ -82,6 +83,7 @@ $newStatus = [PSCustomObject]@{ state = $Status; context = $BuildDefinition; description = $(If ([string]::IsNullOrWhiteSpace($Description)) { "" } Else { $Description }); + target_url = $(If ([string]::IsNullOrWhiteSpace($DetailsURL)) { "" } Else { $DetailsURL }); } # Bug; GitHub sends a 404 for authentication failures. Unfortunately, Invoke-WebRequest waits for a 401 before retrying with @@ -94,8 +96,9 @@ $statusHeaders = @{ Authorization = "Basic $($encodedAuthCredential)" } -If ($OnlyPrintStatus) { - $newStatus | Format-List -} Else { +If ($PSCmdlet.ShouldProcess($latestSha1, "GitHub Build Status")) { Invoke-WebRequest -Body (ConvertTo-JSON $newStatus) -ContentType "application/json" -Headers $statusHeaders -Method Post -Uri $statusURL | Out-Null +} Else { + Write-Host "Would submit build status:" + Write-Host $newStatus } diff --git a/tools/vsimporter/xib2nib/UILabel.cpp b/tools/vsimporter/xib2nib/UILabel.cpp index 6a0405c0ad..dce2d31706 100644 --- a/tools/vsimporter/xib2nib/UILabel.cpp +++ b/tools/vsimporter/xib2nib/UILabel.cpp @@ -29,15 +29,8 @@ static void WriteLayoutWidth(struct _PropertyMapper* prop, NIBWriter* writer, XI } static PropertyMapper propertyMappings[] = { - "IBUIShadowColor", - "UIShadowColor", - NULL, - "IBUILineBreakMode", - "UILineBreakMode", - NULL, - "preferredMaxLayoutWidth", - "UIPreferredMaxLayoutWidth", - WriteLayoutWidth, + "IBUIShadowColor", "UIShadowColor", NULL, "IBUILineBreakMode", "UILineBreakMode", NULL, "preferredMaxLayoutWidth", + "UIPreferredMaxLayoutWidth", WriteLayoutWidth, }; static const int numPropertyMappings = sizeof(propertyMappings) / sizeof(PropertyMapper); @@ -51,6 +44,9 @@ UILabel::UILabel() { _adjustsFontSizeToFit = false; _minimumFontSize = -1.0f; _font = NULL; + + // default line break mode is tailTrucation + _lineBreakMode = 4; } void UILabel::InitFromXIB(XIBObject* obj) { @@ -69,6 +65,9 @@ void UILabel::InitFromXIB(XIBObject* obj) { _textAlignment = obj->GetInt("IBUITextAlignment", 0); _numberOfLines = obj->GetInt("IBUINumberOfLines", 1); + + // default line break mode is tailTrucation + _lineBreakMode = obj->GetInt("IBUILineBreakMode", 4); _font = (UIFont*)obj->FindMember("IBUIFontDescription"); if (!_font) _font = (UIFont*)obj->FindMember("IBUIFont"); @@ -94,20 +93,48 @@ void UILabel::InitFromStory(XIBObject* obj) { _numberOfLines = atoi(getAttrAndHandle("numberOfLines")); } - if (getAttrib("textAlignment")) { - const char* pAlign = getAttrib("textAlignment"); + const char* lineBreakModeAttributeString = "lineBreakMode"; + const char* lineBreakModeAttributeValue = getAttrib(lineBreakModeAttributeString); + if (lineBreakModeAttributeValue) { + if (strcmp(lineBreakModeAttributeValue, "wordWrap") == 0) { + _lineBreakMode = 0; + getAttrAndHandle(lineBreakModeAttributeString); + } else if (strcmp(lineBreakModeAttributeValue, "characterWrap") == 0) { + _lineBreakMode = 1; + getAttrAndHandle(lineBreakModeAttributeString); + } else if (strcmp(lineBreakModeAttributeValue, "clip") == 0) { + _lineBreakMode = 2; + getAttrAndHandle(lineBreakModeAttributeString); + } else if (strcmp(lineBreakModeAttributeValue, "headTruncation") == 0) { + _lineBreakMode = 3; + getAttrAndHandle(lineBreakModeAttributeString); + } else if (strcmp(lineBreakModeAttributeValue, "tailTruncation") == 0) { + _lineBreakMode = 4; + getAttrAndHandle(lineBreakModeAttributeString); + } else if (strcmp(lineBreakModeAttributeValue, "middleTruncation") == 0) { + _lineBreakMode = 5; + getAttrAndHandle(lineBreakModeAttributeString); + } else { + printf("invalid linebreak value %s, using default (tailTruncation) \n", lineBreakModeAttributeValue); + } + } - if (strcmp(pAlign, "left") == 0) { + const char* textAlignmentAttributeString = "textAlignment"; + const char* textAlignmentAttributeValue = getAttrAndHandle(textAlignmentAttributeString); + if (textAlignmentAttributeValue) { + if (strcmp(textAlignmentAttributeValue, "left") == 0) { _textAlignment = 0; - getAttrAndHandle("textAlignment"); + getAttrAndHandle(textAlignmentAttributeString); - } else if (strcmp(pAlign, "center") == 0) { + } else if (strcmp(textAlignmentAttributeValue, "center") == 0) { _textAlignment = 1; - getAttrAndHandle("textAlignment"); + getAttrAndHandle(textAlignmentAttributeString); - } else if (strcmp(pAlign, "right") == 0) { + } else if (strcmp(textAlignmentAttributeValue, "right") == 0) { _textAlignment = 2; - getAttrAndHandle("textAlignment"); + getAttrAndHandle(textAlignmentAttributeString); + } else { + printf("invalid textAligment value %s, using default (left)\n", textAlignmentAttributeValue); } } @@ -153,6 +180,10 @@ void UILabel::ConvertStaticMappings(NIBWriter* writer, XIBObject* obj) { AddInt(writer, "UINumberOfLines", _numberOfLines); } + if (_lineBreakMode != 4) { + AddInt(writer, "UILineBreakMode", _lineBreakMode); + } + if (_baselineAdjustment != 0) { AddInt(writer, "UIBaselineAdjustment", _baselineAdjustment); } diff --git a/tools/vsimporter/xib2nib/UILabel.h b/tools/vsimporter/xib2nib/UILabel.h index efc58ba13f..41187ee006 100644 --- a/tools/vsimporter/xib2nib/UILabel.h +++ b/tools/vsimporter/xib2nib/UILabel.h @@ -33,6 +33,7 @@ class UILabel : bool _adjustsFontSizeToFit; float _minimumFontSize; int _baselineAdjustment; + int _lineBreakMode; public: UILabel();