You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@weex.apache.org by ac...@apache.org on 2018/04/26 12:39:58 UTC
[06/16] incubator-weex git commit: [WEEX-311] [iOS] use new
layoutEngin to replace yoga
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Component/WXTextComponent.mm
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXTextComponent.mm b/ios/sdk/WeexSDK/Sources/Component/WXTextComponent.mm
new file mode 100644
index 0000000..c951068
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXTextComponent.mm
@@ -0,0 +1,1170 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#import "WXTextComponent.h"
+#import "WXSDKInstance_private.h"
+#import "WXComponent_internal.h"
+#import "WXLayer.h"
+#import "WXUtility.h"
+#import "WXConvert.h"
+#import "WXRuleManager.h"
+#import "WXDefine.h"
+#import "WXView.h"
+#import "WXComponent+Layout.h"
+#import <pthread/pthread.h>
+#import <CoreText/CoreText.h>
+#import "WXComponent+Layout.h"
+
+// WXText is a non-public is not permitted
+@interface WXTextView : WXView
+@property (nonatomic, strong) NSTextStorage *textStorage;
+@end
+
+@implementation WXTextView
+
+- (instancetype)initWithFrame:(CGRect)frame
+{
+ if ((self = [super initWithFrame:frame])) {
+ self.accessibilityTraits |= UIAccessibilityTraitStaticText;
+
+ self.opaque = NO;
+ self.contentMode = UIViewContentModeRedraw;
+ self.textStorage = [NSTextStorage new];
+ }
+ return self;
+}
+
++ (Class)layerClass
+{
+ return [WXLayer class];
+}
+
+- (void)copy:(id)sender
+{
+ [[UIPasteboard generalPasteboard] setString:((WXTextComponent*)self.wx_component).text];
+}
+
+- (void)setTextStorage:(NSTextStorage *)textStorage
+{
+ if (_textStorage != textStorage) {
+ _textStorage = textStorage;
+ [self.wx_component setNeedsDisplay];
+ }
+}
+
+- (BOOL)canBecomeFirstResponder
+{
+ return YES;
+}
+
+- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
+{
+ if (action == @selector(copy:)) {
+ return [[self.wx_component valueForKey:@"_enableCopy"] boolValue];
+ }
+ return [super canPerformAction:action withSender:sender];
+}
+
+- (NSString *)description
+{
+ NSString *superDescription = super.description;
+ NSRange semicolonRange = [superDescription rangeOfString:@";"];
+ NSString * content = _textStorage.string;
+ if ([(WXTextComponent*)self.wx_component useCoreText]) {
+ content = ((WXTextComponent*)self.wx_component).text;
+ }
+ NSString *replacement = [NSString stringWithFormat:@"; text: %@; frame:%f,%f,%f,%f", content, self.frame.origin.x, self.frame.origin.y, self.frame.size.width, self.frame.size.height];
+ return [superDescription stringByReplacingCharactersInRange:semicolonRange withString:replacement];
+}
+
+- (NSString *)accessibilityValue
+{
+ if (self.wx_component && self.wx_component->_ariaLabel) {
+ return [super accessibilityValue];
+ }
+ if (![(WXTextComponent*)self.wx_component useCoreText]) {
+ return _textStorage.string;
+ }
+ return ((WXTextComponent*)self.wx_component).text;
+}
+
+- (NSString *)accessibilityLabel
+{
+ if (self.wx_component) {
+ if (self.wx_component->_ariaLabel) {
+ return self.wx_component->_ariaLabel;
+ }
+ }
+ return [super accessibilityLabel];
+}
+
+@end
+
+static BOOL textRenderUsingCoreText = YES;
+
+NSString *const WXTextTruncationToken = @"\u2026";
+CGFloat WXTextDefaultLineThroughWidth = 1.2;
+
+@interface WXTextComponent()
+@property (nonatomic, strong) NSString *useCoreTextAttr;
+@end
+
+@implementation WXTextComponent
+{
+ UIEdgeInsets _border;
+ UIEdgeInsets _padding;
+ NSTextStorage *_textStorage;
+ CGFloat _textStorageWidth;
+
+ UIColor *_color;
+ NSString *_fontFamily;
+ CGFloat _fontSize;
+ CGFloat _fontWeight;
+ WXTextStyle _fontStyle;
+ NSUInteger _lines;
+ NSTextAlignment _textAlign;
+ NSString *_direction;
+ WXTextDecoration _textDecoration;
+ NSString *_textOverflow;
+ CGFloat _lineHeight;
+ CGFloat _letterSpacing;
+ BOOL _truncationLine; // support trunk tail
+
+ NSAttributedString * _ctAttributedString;
+ NSString *_wordWrap;
+
+ pthread_mutex_t _ctAttributedStringMutex;
+ pthread_mutexattr_t _propertMutexAttr;
+ BOOL _observerIconfont;
+ BOOL _enableCopy;
+}
+
++ (void)setRenderUsingCoreText:(BOOL)usingCoreText
+{
+ textRenderUsingCoreText = usingCoreText;
+}
+
++ (BOOL)textRenderUsingCoreText
+{
+ return textRenderUsingCoreText;
+}
+
+- (instancetype)initWithRef:(NSString *)ref
+ type:(NSString *)type
+ styles:(NSDictionary *)styles
+ attributes:(NSDictionary *)attributes
+ events:(NSArray *)events
+ weexInstance:(WXSDKInstance *)weexInstance
+{
+ self = [super initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:weexInstance];
+ if (self) {
+ // just for coretext and textkit render replacement
+ pthread_mutexattr_init(&(_propertMutexAttr));
+ pthread_mutexattr_settype(&(_propertMutexAttr), PTHREAD_MUTEX_RECURSIVE);
+ pthread_mutex_init(&(_ctAttributedStringMutex), &(_propertMutexAttr));
+
+ if ([attributes objectForKey:@"coretext"]) {
+ _useCoreTextAttr = [WXConvert NSString:attributes[@"coretext"]];
+ } else {
+ _useCoreTextAttr = nil;
+ }
+
+ [self fillCSSStyles:styles];
+ [self fillAttributes:attributes];
+
+ }
+ return self;
+}
+
+- (BOOL)useCoreText
+{
+ if ([_useCoreTextAttr isEqualToString:@"true"]) {
+ return YES;
+ }
+ if ([_useCoreTextAttr isEqualToString:@"false"]) {
+ return NO;
+ }
+
+ if ([WXTextComponent textRenderUsingCoreText]) {
+ return YES;
+ }
+ return NO;
+}
+
+- (void)dealloc
+{
+ if (_fontFamily && _observerIconfont) {
+ [[NSNotificationCenter defaultCenter] removeObserver:self name:WX_ICONFONT_DOWNLOAD_NOTIFICATION object:nil];
+ }
+ pthread_mutex_destroy(&_ctAttributedStringMutex);
+ pthread_mutexattr_destroy(&_propertMutexAttr);
+}
+
+#define WX_STYLE_FILL_TEXT(key, prop, type, needLayout)\
+do {\
+ id value = styles[@#key];\
+ if (value) {\
+ _##prop = [WXConvert type:value];\
+ [self setNeedsRepaint];\
+ if (needLayout) {\
+ [self setNeedsLayout];\
+ }\
+ }\
+} while(0);
+
+#define WX_STYLE_FILL_TEXT_WITH_DEFAULT_VALUE(key, prop, type, defaultValue,needLayout)\
+do {\
+ id value = styles[@#key];\
+ if (value) {\
+ if([WXUtility isBlankString:value]){\
+ _##prop = defaultValue;\
+ }else {\
+ _##prop = [WXConvert type:value];\
+ }\
+ [self setNeedsRepaint];\
+ if (needLayout) {\
+ [self setNeedsLayout];\
+ }\
+ }\
+} while(0);
+
+
+#define WX_STYLE_FILL_TEXT_PIXEL(key, prop, needLayout)\
+do {\
+ id value = styles[@#key];\
+ if (value) {\
+ _##prop = [WXConvert WXPixelType:value scaleFactor:self.weexInstance.pixelScaleFactor];\
+ [self setNeedsRepaint];\
+ if (needLayout) {\
+ [self setNeedsLayout];\
+ }\
+}\
+} while(0);
+
+- (void)fillCSSStyles:(NSDictionary *)styles
+{
+ WX_STYLE_FILL_TEXT_WITH_DEFAULT_VALUE(color, color, UIColor, [UIColor blackColor], NO)
+ WX_STYLE_FILL_TEXT(fontFamily, fontFamily, NSString, YES)
+ WX_STYLE_FILL_TEXT_PIXEL(fontSize, fontSize, YES)
+ WX_STYLE_FILL_TEXT(fontWeight, fontWeight, WXTextWeight, YES)
+ WX_STYLE_FILL_TEXT(fontStyle, fontStyle, WXTextStyle, YES)
+ WX_STYLE_FILL_TEXT(lines, lines, NSUInteger, YES)
+ WX_STYLE_FILL_TEXT(textAlign, textAlign, NSTextAlignment, NO)
+ WX_STYLE_FILL_TEXT(textDecoration, textDecoration, WXTextDecoration, YES)
+ WX_STYLE_FILL_TEXT(textOverflow, textOverflow, NSString, NO)
+ WX_STYLE_FILL_TEXT_PIXEL(lineHeight, lineHeight, YES)
+ WX_STYLE_FILL_TEXT_PIXEL(letterSpacing, letterSpacing, YES)
+ WX_STYLE_FILL_TEXT(wordWrap, wordWrap, NSString, YES);
+ WX_STYLE_FILL_TEXT(direction, direction, NSString, YES)
+ if (_fontFamily && !_observerIconfont) {
+ // notification received when custom icon font file download finish
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(repaintText:) name:WX_ICONFONT_DOWNLOAD_NOTIFICATION object:nil];
+ _observerIconfont = YES;
+ }
+
+//#ifndef USE_FLEX
+ if(![WXComponent isUseFlex])
+ {
+ UIEdgeInsets padding = {
+ WXFloorPixelValue(self.cssNode->style.padding[CSS_TOP] + self.cssNode->style.border[CSS_TOP]),
+ WXFloorPixelValue(self.cssNode->style.padding[CSS_LEFT] + self.cssNode->style.border[CSS_LEFT]),
+ WXFloorPixelValue(self.cssNode->style.padding[CSS_BOTTOM] + self.cssNode->style.border[CSS_BOTTOM]),
+ WXFloorPixelValue(self.cssNode->style.padding[CSS_RIGHT] + self.cssNode->style.border[CSS_RIGHT])
+ };
+
+ if (!UIEdgeInsetsEqualToEdgeInsets(padding, _padding)) {
+ _padding = padding;
+ [self setNeedsRepaint];
+ }
+ }
+
+//#else
+ else
+ {
+ UIEdgeInsets flex_padding = {
+ WXFloorPixelValue(self.flexCssNode->getPaddingTop()+ self.flexCssNode->getBorderWidthTop()),
+ WXFloorPixelValue(self.flexCssNode->getPaddingLeft() + self.flexCssNode->getBorderWidthLeft()),
+ WXFloorPixelValue(self.flexCssNode->getPaddingBottom() + self.flexCssNode->getBorderWidthBottom()),
+ WXFloorPixelValue(self.flexCssNode->getPaddingRight() + self.flexCssNode->getBorderWidthRight())
+ };
+
+ if (!UIEdgeInsetsEqualToEdgeInsets(flex_padding, _padding)) {
+ _padding = flex_padding;
+ [self setNeedsRepaint];
+ }
+ }
+//#endif
+
+}
+
+- (void)fillAttributes:(NSDictionary *)attributes
+{
+ id text = [WXConvert NSString:attributes[@"value"]];
+ if (text && ![self.text isEqualToString:text]) {
+ self.text = text;
+ [self setNeedsRepaint];
+ [self setNeedsLayout];
+ }
+ if (attributes[@"enableCopy"]) {
+ _enableCopy = [WXConvert BOOL:attributes[@"enableCopy"]];
+ }
+}
+
+- (void)setNeedsRepaint
+{
+ _textStorage = nil;
+
+ pthread_mutex_lock(&(_ctAttributedStringMutex));
+ _ctAttributedString = nil;
+ pthread_mutex_unlock(&(_ctAttributedStringMutex));
+
+}
+
+#pragma mark - Subclass
+
+- (void)setNeedsLayout
+{
+ [super setNeedsLayout];
+}
+
+- (void)viewDidLoad
+{
+ [super viewDidLoad];
+ BOOL useCoreText = NO;
+ if ([self.view.wx_component isKindOfClass:NSClassFromString(@"WXTextComponent")] && [self.view.wx_component respondsToSelector:@selector(useCoreText)]) {
+ useCoreText = [(WXTextComponent*)self.view.wx_component useCoreText];
+ }
+ if (!useCoreText) {
+ ((WXTextView *)self.view).textStorage = _textStorage;
+ }
+ if (_enableCopy) {
+ UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(displayMenuController:)];
+ [self.view addGestureRecognizer:longPress];
+ }
+ self.view.isAccessibilityElement = YES;
+
+ [self setNeedsDisplay];
+}
+
+- (void)displayMenuController:(id)sender
+{
+ if ([self.view becomeFirstResponder] && ((UILongPressGestureRecognizer*)sender).state == UIGestureRecognizerStateBegan) {
+ UIMenuController *theMenu = [UIMenuController sharedMenuController];
+ CGSize size = [self ctAttributedString].size;
+ CGRect selectionRect = CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y, size.width, size.height);
+ [theMenu setTargetRect:selectionRect inView:self.view.superview];
+ [theMenu setMenuVisible:YES animated:YES];
+ }
+}
+
+- (UIView *)loadView
+{
+ return [[WXTextView alloc] init];
+}
+
+- (BOOL)needsDrawRect
+{
+ return YES;
+}
+
+- (UIImage *)drawRect:(CGRect)rect;
+{
+ CGContextRef context = UIGraphicsGetCurrentContext();
+ if (_isCompositingChild) {
+ [self drawTextWithContext:context bounds:rect padding:_padding view:nil];
+ } else {
+ WXTextView *textView = (WXTextView *)_view;
+ [self drawTextWithContext:context bounds:rect padding:_padding view:textView];
+ }
+
+ return nil;
+}
+
+- (CGSize (^)(CGSize))measureBlock
+{
+ __weak typeof(self) weakSelf = self;
+ return ^CGSize (CGSize constrainedSize) {
+#ifdef DEBUG
+ WXLogDebug(@"flexLayout -> measureblock %@, constrainedSize:%@",
+ self.type,
+ NSStringFromCGSize(constrainedSize)
+ );
+#endif
+ CGSize computedSize = CGSizeZero;
+ NSTextStorage *textStorage = nil;
+
+ //TODO:more elegant way to use max and min constrained size
+//#ifndef USE_FLEX
+ if(![WXComponent isUseFlex])
+ {
+ if (!isnan(weakSelf.cssNode->style.minDimensions[CSS_WIDTH])) {
+ constrainedSize.width = MAX(constrainedSize.width, weakSelf.cssNode->style.minDimensions[CSS_WIDTH]);
+ }
+
+ if (!isnan(weakSelf.cssNode->style.maxDimensions[CSS_WIDTH])) {
+ constrainedSize.width = MIN(constrainedSize.width, weakSelf.cssNode->style.maxDimensions[CSS_WIDTH]);
+ }
+ }
+//#else
+ else
+ {
+ if (!isnan(weakSelf.flexCssNode->getMinWidth())) {
+ constrainedSize.width = MAX(constrainedSize.width, weakSelf.flexCssNode->getMinWidth());
+ }
+
+ if (!isnan(weakSelf.flexCssNode->getMaxWidth())) {
+ constrainedSize.width = MIN(constrainedSize.width, weakSelf.flexCssNode->getMaxWidth());
+ }
+ }
+//#endif
+
+ if (![self useCoreText]) {
+ textStorage = [weakSelf textStorageWithWidth:constrainedSize.width];
+ NSLayoutManager *layoutManager = textStorage.layoutManagers.firstObject;
+ NSTextContainer *textContainer = layoutManager.textContainers.firstObject;
+ computedSize = [layoutManager usedRectForTextContainer:textContainer].size;
+ } else {
+ computedSize = [weakSelf calculateTextHeightWithWidth:constrainedSize.width];
+ }
+//#ifndef USE_FLEX
+ if(![WXComponent isUseFlex])
+ {
+ //TODO:more elegant way to use max and min constrained size
+ if (!isnan(weakSelf.cssNode->style.minDimensions[CSS_WIDTH])) {
+ computedSize.width = MAX(computedSize.width, weakSelf.cssNode->style.minDimensions[CSS_WIDTH]);
+ }
+
+ if (!isnan(weakSelf.cssNode->style.maxDimensions[CSS_WIDTH])) {
+ computedSize.width = MIN(computedSize.width, weakSelf.cssNode->style.maxDimensions[CSS_WIDTH]);
+ }
+
+ if (!isnan(weakSelf.cssNode->style.minDimensions[CSS_HEIGHT])) {
+ computedSize.height = MAX(computedSize.height, weakSelf.cssNode->style.minDimensions[CSS_HEIGHT]);
+ }
+
+ if (!isnan(weakSelf.cssNode->style.maxDimensions[CSS_HEIGHT])) {
+ computedSize.height = MIN(computedSize.height, weakSelf.cssNode->style.maxDimensions[CSS_HEIGHT]);
+ }
+ }
+
+//#else
+ else
+ {
+ if (!isnan(weakSelf.flexCssNode->getMinWidth())) {
+ computedSize.width = MAX(computedSize.width, weakSelf.flexCssNode->getMinWidth());
+ }
+
+ if (!isnan(weakSelf.flexCssNode->getMaxWidth())) {
+ computedSize.width = MIN(computedSize.width, weakSelf.flexCssNode->getMaxWidth());
+ }
+
+ if (!isnan(weakSelf.flexCssNode->getMinHeight())) {
+ computedSize.height = MAX(computedSize.height, weakSelf.flexCssNode->getMinHeight());
+ }
+
+ if (!isnan(weakSelf.flexCssNode->getMaxHeight())) {
+ computedSize.height = MIN(computedSize.height, weakSelf.flexCssNode->getMaxHeight());
+ }
+ }
+
+//#endif
+ if (textStorage && [WXUtility isBlankString:textStorage.string]) {
+ // if the text value is empty or nil, then set the height is 0.
+ computedSize.height = 0;
+ }
+
+ return (CGSize) {
+ WXCeilPixelValue(computedSize.width),
+ WXCeilPixelValue(computedSize.height)
+ };
+ };
+}
+
+#pragma mark Text Building
+
+- (NSAttributedString *)ctAttributedString
+{
+ if (!self.text) {
+ return nil;
+ }
+ NSAttributedString * attributedString = nil;
+ pthread_mutex_lock(&(_ctAttributedStringMutex));
+ if (!_ctAttributedString) {
+ _ctAttributedString = [self buildCTAttributeString];
+ WXPerformBlockOnComponentThread(^{
+ [self.weexInstance.componentManager startComponentTasks];
+ });
+ }
+ attributedString = [_ctAttributedString copy];
+ pthread_mutex_unlock(&(_ctAttributedStringMutex));
+ return attributedString;
+}
+
+- (void)repaintText:(NSNotification *)notification
+{
+ if (![_fontFamily isEqualToString:notification.userInfo[@"fontFamily"]]) {
+ return;
+ }
+ [self setNeedsRepaint];
+ WXPerformBlockOnComponentThread(^{
+ [self.weexInstance.componentManager startComponentTasks];
+ WXPerformBlockOnMainThread(^{
+ [self setNeedsLayout];
+ [self setNeedsDisplay];
+ });
+ });
+}
+
+- (NSMutableAttributedString *)buildCTAttributeString
+{
+ NSString * string = self.text;
+ if (![string isKindOfClass:[NSString class]]) {
+ WXLogError(@"text %@ is invalid", self.text);
+ string = @"";
+ }
+ NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString: string];
+ if (_color) {
+ [attributedString addAttribute:NSForegroundColorAttributeName value:_color range:NSMakeRange(0, string.length)];
+ }
+
+ // set font
+ UIFont *font = [WXUtility fontWithSize:_fontSize textWeight:_fontWeight textStyle:_fontStyle fontFamily:_fontFamily scaleFactor:self.weexInstance.pixelScaleFactor useCoreText:[self useCoreText]];
+ CTFontRef ctFont = CTFontCreateWithName((__bridge CFStringRef)font.fontName,
+ font.pointSize,
+ NULL);
+ if (ctFont) {
+ [attributedString addAttribute:(id)kCTFontAttributeName value:(__bridge id)(ctFont) range:NSMakeRange(0, string.length)];
+ CFRelease(ctFont);
+ }
+
+ if(_textDecoration == WXTextDecorationUnderline){
+ [attributedString addAttribute:(id)kCTUnderlineStyleAttributeName value:@(kCTUnderlinePatternSolid | kCTUnderlineStyleSingle) range:NSMakeRange(0, string.length)];
+ } else if(_textDecoration == WXTextDecorationLineThrough){
+ [attributedString addAttribute:NSStrikethroughStyleAttributeName value:@(NSUnderlinePatternSolid | NSUnderlineStyleSingle) range:NSMakeRange(0, string.length)];
+ }
+
+ NSMutableParagraphStyle *paragraphStyle = [NSMutableParagraphStyle new];
+
+ // handle text direction style, default ltr
+ BOOL isRtl = false;
+ if ([WXComponent isUseFlex]) {
+ isRtl = [_direction isEqualToString:@"rtl"];
+ }else{
+ isRtl = _cssNode->layout.direction == CSS_DIRECTION_RTL;
+ }
+ if (isRtl) {
+ if (0 == _textAlign) {
+ //force text right-align if don't specified any align.
+ _textAlign = NSTextAlignmentRight;
+ }
+ paragraphStyle.baseWritingDirection = NSWritingDirectionRightToLeft;
+ } else {
+ //if you specify NSWritingDirectionNaturalDirection, the receiver resolves the writing
+ //directionto eitherNSWritingDirectionLeftToRight or NSWritingDirectionRightToLeft,
+ //depending on the direction for the user’s language preference setting.
+ paragraphStyle.baseWritingDirection = NSWritingDirectionNatural;
+ }
+
+ if (_textAlign) {
+ paragraphStyle.alignment = _textAlign;
+ }
+
+ if ([[_wordWrap lowercaseString] isEqualToString:@"break-word"]) {
+ paragraphStyle.lineBreakMode = NSLineBreakByWordWrapping;
+ } else if ([[_wordWrap lowercaseString] isEqualToString:@"normal"]){
+ paragraphStyle.lineBreakMode = NSLineBreakByClipping;
+ } else {
+ // set default lineBreakMode
+ paragraphStyle.lineBreakMode = NSLineBreakByCharWrapping;
+ }
+ _truncationLine = NO;
+ if (_textOverflow && [_textOverflow length] > 0) {
+ if (_lines && [_textOverflow isEqualToString:@"ellipsis"])
+ _truncationLine = YES;
+ }
+
+ if (_lineHeight) {
+ paragraphStyle.maximumLineHeight = _lineHeight;
+ paragraphStyle.minimumLineHeight = _lineHeight;
+ }
+ if (_lineHeight || _textAlign || [_textOverflow length] > 0) {
+ [attributedString addAttribute:NSParagraphStyleAttributeName
+ value:paragraphStyle
+ range:(NSRange){0, attributedString.length}];
+ }
+
+ if (_letterSpacing) {
+ [attributedString addAttribute:NSKernAttributeName value:@(_letterSpacing) range:(NSRange){0, attributedString.length}];
+ }
+
+ if ([self adjustLineHeight]) {
+ if (_lineHeight > font.lineHeight) {
+ [attributedString addAttribute:NSBaselineOffsetAttributeName
+ value:@((_lineHeight - font.lineHeight)/ 2)
+ range:(NSRange){0, attributedString.length}];
+ }
+ }
+
+ return attributedString;
+}
+
+- (NSAttributedString *)buildAttributeString
+{
+ NSString *string = self.text ?: @"";
+
+ NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:string];
+
+ // set textColor
+ if(_color) {
+ [attributedString addAttribute:NSForegroundColorAttributeName value:_color range:NSMakeRange(0, string.length)];
+ }
+
+ // set font
+ UIFont *font = [WXUtility fontWithSize:_fontSize textWeight:_fontWeight textStyle:_fontStyle fontFamily:_fontFamily scaleFactor:self.weexInstance.pixelScaleFactor];
+ if (font) {
+ [attributedString addAttribute:NSFontAttributeName value:font range:NSMakeRange(0, string.length)];
+ }
+
+ if(_textDecoration == WXTextDecorationUnderline){
+ [attributedString addAttribute:NSUnderlineStyleAttributeName value:@(NSUnderlinePatternSolid | NSUnderlineStyleSingle) range:NSMakeRange(0, string.length)];
+ } else if(_textDecoration == WXTextDecorationLineThrough){
+ [attributedString addAttribute:NSStrikethroughStyleAttributeName value:@(NSUnderlinePatternSolid | NSUnderlineStyleSingle) range:NSMakeRange(0, string.length)];
+ }
+
+ NSMutableParagraphStyle *paragraphStyle = [NSMutableParagraphStyle new];
+
+ // handle text direction style, default ltr
+ BOOL isRtl = false;
+ if ([WXComponent isUseFlex]) {
+ isRtl = [_direction isEqualToString:@"rtl"];
+ }else{
+ isRtl = _cssNode->layout.direction == CSS_DIRECTION_RTL;
+ }
+ if (isRtl) {
+ if (0 == _textAlign) {
+ //force text right-align if don't specified any align.
+ _textAlign = NSTextAlignmentRight;
+ }
+ paragraphStyle.baseWritingDirection = NSWritingDirectionRightToLeft;
+ } else {
+ //if you specify NSWritingDirectionNaturalDirection, the receiver resolves the writing
+ //directionto eitherNSWritingDirectionLeftToRight or NSWritingDirectionRightToLeft,
+ //depending on the direction for the user’s language preference setting.
+ paragraphStyle.baseWritingDirection = NSWritingDirectionNatural;
+ }
+
+ if (_textAlign) {
+ paragraphStyle.alignment = _textAlign;
+ }
+
+ if (_lineHeight) {
+ paragraphStyle.maximumLineHeight = _lineHeight;
+ paragraphStyle.minimumLineHeight = _lineHeight;
+ }
+
+ if (_lineHeight || _textAlign) {
+ [attributedString addAttribute:NSParagraphStyleAttributeName
+ value:paragraphStyle
+ range:(NSRange){0, attributedString.length}];
+ }
+ if ([self adjustLineHeight]) {
+ if (_lineHeight > font.lineHeight) {
+ [attributedString addAttribute:NSBaselineOffsetAttributeName
+ value:@((_lineHeight - font.lineHeight)/ 2)
+ range:(NSRange){0, attributedString.length}];
+ }
+ }
+
+ return attributedString;
+}
+
+- (BOOL)adjustLineHeight
+{
+ if (WX_SYS_VERSION_LESS_THAN(@"10.0")) {
+ return true;
+ }
+ return ![self useCoreText];
+}
+
+- (NSTextStorage *)textStorageWithWidth:(CGFloat)width
+{
+ if (_textStorage && width == _textStorageWidth) {
+ return _textStorage;
+ }
+
+ NSLayoutManager *layoutManager = [NSLayoutManager new];
+
+ // build AttributeString
+ NSAttributedString *attributedString = [self buildAttributeString];
+
+ NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:attributedString];
+ [textStorage addLayoutManager:layoutManager];
+
+ NSTextContainer *textContainer = [NSTextContainer new];
+ textContainer.lineFragmentPadding = 0.0;
+
+ if ([[_wordWrap lowercaseString] isEqualToString:@"break-word"]) {
+ textContainer.lineBreakMode = NSLineBreakByWordWrapping;
+ } else if ([[_wordWrap lowercaseString] isEqualToString:@"normal"]){
+ textContainer.lineBreakMode = NSLineBreakByClipping;
+ } else {
+ // set default lineBreakMode
+ textContainer.lineBreakMode = NSLineBreakByCharWrapping;
+ }
+
+ if (_textOverflow && [_textOverflow length] > 0) {
+ if ([_textOverflow isEqualToString:@"ellipsis"])
+ textContainer.lineBreakMode = NSLineBreakByTruncatingTail;
+ }
+ textContainer.maximumNumberOfLines = _lines > 0 ? _lines : 0;
+ textContainer.size = (CGSize){isnan(width) ? CGFLOAT_MAX : width, CGFLOAT_MAX};
+
+ [layoutManager addTextContainer:textContainer];
+ [layoutManager ensureLayoutForTextContainer:textContainer];
+
+ _textStorageWidth = width;
+ _textStorage = textStorage;
+
+ return textStorage;
+}
+
+- (void)syncTextStorageForView
+{
+ CGFloat width = self.calculatedFrame.size.width - (_padding.left + _padding.right);
+ NSTextStorage *textStorage = nil;
+ if (![self useCoreText]) {
+ textStorage = [self textStorageWithWidth:width];
+ }
+ [self.weexInstance.componentManager _addUITask:^{
+ if ([self isViewLoaded]) {
+ if (![self useCoreText]) {
+ ((WXTextView *)self.view).textStorage = textStorage;
+ }
+ [self readyToRender]; // notify super component
+ [self setNeedsDisplay];
+ }
+ }];
+}
+
+- (void)_frameDidCalculated:(BOOL)isChanged
+{
+ [super _frameDidCalculated:isChanged];
+ [self syncTextStorageForView];
+}
+
+- (void)_updateStylesOnComponentThread:(NSDictionary *)styles resetStyles:(NSMutableArray *)resetStyles isUpdateStyles:(BOOL)isUpdateStyles
+{
+ [super _updateStylesOnComponentThread:styles resetStyles:(NSMutableArray *)resetStyles isUpdateStyles:isUpdateStyles];
+ NSMutableDictionary * newStyles = [styles mutableCopy];
+ for (NSString * key in [resetStyles copy]) {
+ [newStyles setObject:@"" forKey:key];
+ }
+ [self fillCSSStyles:newStyles];
+
+ [self syncTextStorageForView];
+}
+
+- (void)_updateAttributesOnComponentThread:(NSDictionary *)attributes
+{
+ [super _updateAttributesOnComponentThread:attributes];
+
+ [self fillAttributes:attributes];
+
+ [self syncTextStorageForView];
+}
+
+- (void)drawTextWithContext:(CGContextRef)context bounds:(CGRect)bounds padding:(UIEdgeInsets)padding view:(WXTextView *)view
+{
+ if (bounds.size.width <= 0 || bounds.size.height <= 0) {
+ return;
+ }
+
+ if ([self _needsDrawBorder]) {
+ [self _drawBorderWithContext:context size:bounds.size];
+ } else {
+ WXPerformBlockOnMainThread(^{
+ [self _resetNativeBorderRadius];
+ });
+ }
+ if (![self useCoreText]) {
+ NSLayoutManager *layoutManager = _textStorage.layoutManagers.firstObject;
+ NSTextContainer *textContainer = layoutManager.textContainers.firstObject;
+
+ CGRect textFrame = UIEdgeInsetsInsetRect(bounds, padding);
+ NSRange glyphRange = [layoutManager glyphRangeForTextContainer:textContainer];
+
+ [layoutManager drawBackgroundForGlyphRange:glyphRange atPoint:textFrame.origin];
+ [layoutManager drawGlyphsForGlyphRange:glyphRange atPoint:textFrame.origin];
+ } else {
+ CGRect textFrame = UIEdgeInsetsInsetRect(bounds, padding);
+ // sufficient height for text to draw, or frame lines will be empty
+ textFrame.size.height = bounds.size.height * 2;
+ CGContextSaveGState(context);
+ //flip the coordinate system
+ CGContextSetTextMatrix(context, CGAffineTransformIdentity);
+ CGContextTranslateCTM(context, 0, textFrame.size.height);
+ CGContextScaleCTM(context, 1.0, -1.0);
+
+ NSAttributedString * attributedStringCopy = [self ctAttributedString];
+ //add path
+ CGPathRef cgPath = NULL;
+ cgPath = CGPathCreateWithRect(textFrame, NULL);
+ CTFrameRef _coreTextFrameRef = NULL;
+ if (_coreTextFrameRef) {
+ CFRelease(_coreTextFrameRef);
+ _coreTextFrameRef = NULL;
+ }
+ if(!attributedStringCopy) {
+ return;
+ }
+ CTFramesetterRef ctframesetterRef = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef)(attributedStringCopy));
+ _coreTextFrameRef = CTFramesetterCreateFrame(ctframesetterRef, CFRangeMake(0, attributedStringCopy.length), cgPath, NULL);
+ CFArrayRef ctLines = NULL;
+ if (NULL == _coreTextFrameRef) {
+ // try to protect crash from frame is NULL
+ return;
+ }
+ CFRelease(ctframesetterRef);
+ ctframesetterRef = NULL;
+ ctLines = CTFrameGetLines(_coreTextFrameRef);
+ CFIndex lineCount = CFArrayGetCount(ctLines);
+ NSMutableArray * mutableLines = [NSMutableArray new];
+ CGPoint lineOrigins[lineCount];
+ NSUInteger rowCount = 0;
+ BOOL needTruncation = NO;
+ CTLineRef ctTruncatedLine = NULL;
+ CTFrameGetLineOrigins(_coreTextFrameRef, CFRangeMake(0, 0), lineOrigins);
+ for (CFIndex lineIndex = 0;(!_lines || _lines > lineIndex) && lineIndex < lineCount; lineIndex ++) {
+ CTLineRef lineRef = NULL;
+ lineRef = (CTLineRef)CFArrayGetValueAtIndex(ctLines, lineIndex);
+ if (!lineRef) {
+ break;
+ }
+ CGPoint lineOrigin = lineOrigins[lineIndex];
+ lineOrigin.x += padding.left;
+ lineOrigin.y -= padding.top;
+ CFArrayRef runs = CTLineGetGlyphRuns(lineRef);
+ [mutableLines addObject:(__bridge id _Nonnull)(lineRef)];
+ // lineIndex base 0
+ rowCount = lineIndex + 1;
+ if (_lines > 0 && _truncationLine) {
+ if (_truncationLine && rowCount > _lines) {
+ needTruncation = YES;
+ do {
+ NSUInteger lastRow = [mutableLines count];
+ if (lastRow < rowCount) {
+ break;
+ }
+ [mutableLines removeLastObject];
+ } while (1);
+
+ }
+ }
+ if (_lines > 0 && _truncationLine) {
+ if (rowCount >= _lines &&!needTruncation && (CTLineGetStringRange(lineRef).length + CTLineGetStringRange(lineRef).location) < attributedStringCopy.length) {
+ needTruncation = YES;
+ }
+ }
+
+ if (needTruncation) {
+ CGContextSetTextPosition(context, lineOrigin.x, lineOrigin.y);
+ ctTruncatedLine = [self buildTruncatedLineWithRuns:runs lines:mutableLines path:cgPath];
+ if (ctTruncatedLine) {
+ CFArrayRef truncatedRuns = CTLineGetGlyphRuns(ctTruncatedLine);
+ [self drawTextWithRuns:truncatedRuns context:context lineOrigin:lineOrigin];
+ CFRelease(ctTruncatedLine);
+ ctTruncatedLine = NULL;
+ continue;
+ }
+ }else {
+ [self drawTextWithRuns:runs context:context lineOrigin:lineOrigin];
+ }
+ }
+
+ [mutableLines removeAllObjects];
+ CGPathRelease(cgPath);
+ CFRelease(_coreTextFrameRef);
+ _coreTextFrameRef = NULL;
+ cgPath = NULL;
+ CGContextRestoreGState(context);
+ }
+}
+
+- (void)drawTextWithRuns:(CFArrayRef)runs context:(CGContextRef)context lineOrigin:(CGPoint)lineOrigin
+{
+ for (CFIndex runIndex = 0; runIndex < CFArrayGetCount(runs); runIndex ++) {
+ CTRunRef run = NULL;
+ run = (CTRunRef)CFArrayGetValueAtIndex(runs, runIndex);
+ CFDictionaryRef attr = NULL;
+ attr = CTRunGetAttributes(run);
+ if (0 == runIndex) {
+ NSNumber *baselineOffset = (NSNumber*)CFDictionaryGetValue(attr, (__bridge void *)NSBaselineOffsetAttributeName);
+ if (baselineOffset) {
+ lineOrigin.y += [baselineOffset doubleValue];
+ }
+ }
+ CGContextSetTextPosition(context, lineOrigin.x, lineOrigin.y);
+ CTRunDraw(run, context, CFRangeMake(0, 0));
+ CFIndex glyphCount = CTRunGetGlyphCount(run);
+ if (glyphCount <= 0) continue;
+
+ long longForStrikethroughStyleAttributeName= (long)CFDictionaryGetValue(attr, (__bridge void *)NSStrikethroughStyleAttributeName);
+ NSUnderlineStyle strikethrough = (NSUnderlineStyle)longForStrikethroughStyleAttributeName;
+
+ if (strikethrough) {
+ // draw strikethrough
+ [self drawLineThroughWithRun:runs context:context index:runIndex origin:lineOrigin];
+ }
+ }
+}
+
+- (CTLineRef)buildTruncatedLineWithRuns:(CFArrayRef)runs lines:(NSMutableArray*)mutableLines path:(CGPathRef)cgPath
+{
+ NSAttributedString * truncationToken = nil;
+ CTLineRef ctTruncatedLine = NULL;
+ CTLineRef lastLine = (__bridge CTLineRef)(mutableLines.lastObject);
+
+ CFArrayRef lastLineRuns = CTLineGetGlyphRuns(lastLine);
+ NSUInteger lastLineRunCount = CFArrayGetCount(lastLineRuns);
+
+ CTLineRef truncationTokenLine = NULL;
+ NSMutableDictionary *attrs = nil;
+ if (lastLineRunCount > 0) {
+ CTRunRef run = (CTRunRef)CFArrayGetValueAtIndex(runs, lastLineRunCount - 1);
+ attrs = (id)CTRunGetAttributes(run);
+ attrs = attrs ? attrs.mutableCopy : [NSMutableDictionary new];
+ CTFontRef font = (__bridge CTFontRef)(attrs[(id)kCTFontAttributeName]);
+ CGFloat fontSize = font ? CTFontGetSize(font):32 * self.weexInstance.pixelScaleFactor;
+ UIFont * uiFont = [UIFont systemFontOfSize:fontSize];
+ if (uiFont) {
+ font = CTFontCreateWithName((__bridge CFStringRef)uiFont.fontName, uiFont.pointSize, NULL);
+ }
+ if (font) {
+ attrs[(id)kCTFontAttributeName] = (__bridge id)(font);
+ uiFont = nil;
+ CFRelease(font);
+ }
+ CGColorRef color = (__bridge CGColorRef)(attrs[(id)kCTForegroundColorAttributeName]);
+ if (color && CFGetTypeID(color) == CGColorGetTypeID() && CGColorGetAlpha(color) == 0) {
+ [attrs removeObjectForKey:(id)kCTForegroundColorAttributeName];
+ }
+
+ attrs = attrs?:[NSMutableDictionary new];
+ truncationToken = [[NSAttributedString alloc] initWithString:WXTextTruncationToken attributes:attrs];
+ truncationTokenLine = CTLineCreateWithAttributedString((CFAttributedStringRef)truncationToken);
+ }
+
+ if (truncationTokenLine) {
+ // default truncationType is kCTLineTruncationEnd
+ CTLineTruncationType truncationType = kCTLineTruncationEnd;
+ NSAttributedString *attributedString = [self ctAttributedString];
+ NSAttributedString * lastLineText = nil;
+ NSRange lastLineTextRange = WXNSRangeFromCFRange(CTLineGetStringRange(lastLine));
+ NSRange attributeStringRange = NSMakeRange(0, attributedString.string.length);
+ NSRange interSectionRange = NSIntersectionRange(lastLineTextRange, attributeStringRange);
+ if (!NSEqualRanges(interSectionRange, lastLineTextRange)) {
+ // out of bounds
+ lastLineTextRange = interSectionRange;
+ }
+ lastLineText = [attributedString attributedSubstringFromRange: lastLineTextRange];
+ if (!lastLineText) {
+ lastLineText = attributedString;
+ }
+ NSMutableAttributedString *mutableLastLineText = lastLineText.mutableCopy;
+ [mutableLastLineText appendAttributedString:truncationToken];
+ CTLineRef ctLastLineExtend = CTLineCreateWithAttributedString((__bridge CFAttributedStringRef)[mutableLastLineText copy]);
+ if (ctLastLineExtend) {
+ CGRect cgPathRect = CGRectZero;
+ CGFloat truncatedWidth = 0;
+ if (CGPathIsRect(cgPath, &cgPathRect)) {
+ truncatedWidth = cgPathRect.size.width;
+ }
+ ctTruncatedLine = CTLineCreateTruncatedLine(ctLastLineExtend, truncatedWidth, truncationType, truncationTokenLine);
+ CFRelease(ctLastLineExtend);
+ ctLastLineExtend = NULL;
+ CFRelease(truncationTokenLine);
+ truncationTokenLine = NULL;
+ }
+ }
+
+ return ctTruncatedLine;
+}
+
+- (void)drawLineThroughWithRun:(CFArrayRef)runs context:(CGContextRef)context index:(CFIndex)runIndex origin:(CGPoint)lineOrigin
+{
+ CFRetain(runs);
+ CGContextRetain(context);
+
+ CGContextSaveGState(context);
+ CGFloat xHeight = 0, underLinePosition = 0, lineThickness = 0;
+ CTRunRef run = (CTRunRef)CFArrayGetValueAtIndex(runs, runIndex);
+ WXTextGetRunsMaxMetric(runs, &xHeight, &underLinePosition, &lineThickness);
+
+ CGPoint strikethroughStart;
+ strikethroughStart.x = lineOrigin.x - underLinePosition;
+ strikethroughStart.y = lineOrigin.y + xHeight/2;
+ CGPoint runPosition = CGPointZero;
+ CTRunGetPositions(run, CFRangeMake(0, 1), &runPosition);
+ strikethroughStart.x = lineOrigin.x + runPosition.x;
+ CGContextSetLineWidth(context, WXTextDefaultLineThroughWidth);
+ double length = CTRunGetTypographicBounds(run, CFRangeMake(0, 0), NULL, NULL, NULL);
+ CGContextMoveToPoint(context, strikethroughStart.x, strikethroughStart.y);
+ CGContextAddLineToPoint(context, strikethroughStart.x + length, strikethroughStart.y);
+ CGContextStrokePath(context);
+
+ CGContextRestoreGState(context);
+ CFRelease(runs);
+ CGContextRelease(context);
+}
+
+- (CGSize)calculateTextHeightWithWidth:(CGFloat)aWidth
+{
+ CGFloat totalHeight = 0;
+ CGSize suggestSize = CGSizeZero;
+ NSAttributedString * attributedStringCpy = [self ctAttributedString];
+ if (!attributedStringCpy) {
+ return CGSizeZero;
+ }
+ if (isnan(aWidth)) {
+ aWidth = CGFLOAT_MAX;
+ }
+ aWidth = [attributedStringCpy boundingRectWithSize:CGSizeMake(aWidth, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading context:nil].size.width;
+ CTFramesetterRef ctframesetterRef = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef)(attributedStringCpy));
+ suggestSize = CTFramesetterSuggestFrameSizeWithConstraints(ctframesetterRef, CFRangeMake(0, 0), NULL, CGSizeMake(aWidth, MAXFLOAT), NULL);
+
+ CGMutablePathRef path = NULL;
+ path = CGPathCreateMutable();
+ // sufficient height to draw text
+ CGPathAddRect(path, NULL, CGRectMake(0, 0, aWidth, suggestSize.height * 10));
+
+ CTFrameRef frameRef = NULL;
+ frameRef = CTFramesetterCreateFrame(ctframesetterRef, CFRangeMake(0, attributedStringCpy.length), path, NULL);
+ CGPathRelease(path);
+
+ CFArrayRef lines = NULL;
+ if (NULL == frameRef) {
+ //try to protect unexpected crash.
+ return suggestSize;
+ }
+ CFRelease(ctframesetterRef);
+ ctframesetterRef = NULL;
+ lines = CTFrameGetLines(frameRef);
+ CFIndex lineCount = CFArrayGetCount(lines);
+ CGFloat ascent = 0;
+ CGFloat descent = 0;
+ CGFloat leading = 0;
+
+ // height = ascent + descent + lineCount*leading
+ // ignore linespaing
+ NSUInteger actualLineCount = 0;
+ for (CFIndex lineIndex = 0; (!_lines|| lineIndex < _lines) && lineIndex < lineCount; lineIndex ++)
+ {
+ CTLineRef lineRef = NULL;
+ lineRef = (CTLineRef)CFArrayGetValueAtIndex(lines, lineIndex);
+ CTLineGetTypographicBounds(lineRef, &ascent, &descent, &leading);
+ totalHeight += ascent + descent;
+ actualLineCount ++;
+ }
+
+ totalHeight = totalHeight + actualLineCount * leading;
+ CFRelease(frameRef);
+ frameRef = NULL;
+
+ if (WX_SYS_VERSION_LESS_THAN(@"10.0")) {
+ // there is something wrong with coreText drawing text height, trying to fix this with more efficent way.
+ if(actualLineCount && actualLineCount < lineCount) {
+ suggestSize.height = suggestSize.height * actualLineCount / lineCount;
+ }
+ return CGSizeMake(aWidth, suggestSize.height);
+ }
+ return CGSizeMake(aWidth, totalHeight);
+}
+
+static void WXTextGetRunsMaxMetric(CFArrayRef runs, CGFloat *xHeight, CGFloat *underlinePosition, CGFloat *lineThickness)
+{
+ CFRetain(runs);
+ CGFloat maxXHeight = 0;
+ CGFloat maxUnderlinePos = 0;
+ CGFloat maxLineThickness = 0;
+ for (NSUInteger index = 0, runsCount = CFArrayGetCount(runs); index < runsCount; index ++) {
+ CTRunRef run = (CTRunRef)CFArrayGetValueAtIndex(runs, index);
+ CFDictionaryRef attrs = CTRunGetAttributes(run);
+ if (attrs) {
+ CTFontRef font = (CTFontRef)CFDictionaryGetValue(attrs, kCTFontAttributeName);
+ if (font) {
+ CGFloat xHeight = CTFontGetXHeight(font);
+ if (xHeight > maxXHeight) {
+ maxXHeight = xHeight;
+ }
+
+ CGFloat underlinePos = CTFontGetUnderlinePosition(font);
+ if (underlinePos < maxUnderlinePos) {
+ maxUnderlinePos = underlinePos;
+ }
+
+ CGFloat lineThickness = CTFontGetUnderlineThickness(font);
+ if (lineThickness > maxLineThickness) {
+ maxLineThickness = lineThickness;
+ }
+ }
+ }
+ }
+
+ if (xHeight) {
+ *xHeight = maxXHeight;
+ }
+
+ if (underlinePosition) {
+ *underlinePosition = maxUnderlinePos;
+ }
+
+ if (lineThickness) {
+ *lineThickness = maxLineThickness;
+ }
+
+ CFRelease(runs);
+}
+
+NS_INLINE NSRange WXNSRangeFromCFRange(CFRange range) {
+ return NSMakeRange(range.location, range.length);
+}
+
+#ifdef UITEST
+- (NSString *)description
+{
+ return super.description;
+}
+#endif
+
+- (void)_resetCSSNodeStyles:(NSArray *)styles
+{
+ [super _resetCSSNodeStyles:styles];
+ if ([styles containsObject:@"color"]) {
+ _color = [UIColor blackColor];
+ [self setNeedsRepaint];
+ }
+ if ([styles containsObject:@"fontSize"]) {
+ _fontSize = WX_TEXT_FONT_SIZE;
+ [self setNeedsRepaint];
+ [self setNeedsLayout];
+ }
+}
+
+@end
+
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Engine/WXSDKEngine.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Engine/WXSDKEngine.m b/ios/sdk/WeexSDK/Sources/Engine/WXSDKEngine.m
index dad372c..e2d35d6 100644
--- a/ios/sdk/WeexSDK/Sources/Engine/WXSDKEngine.m
+++ b/ios/sdk/WeexSDK/Sources/Engine/WXSDKEngine.m
@@ -38,6 +38,8 @@
#import "WXUtility.h"
#import "WXExtendCallNativeManager.h"
#import "WXExceptionUtils.h"
+#import "WXConfigCenterProtocol.h"
+#import "WXComponent+Layout.h"
@implementation WXSDKEngine
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Layout/WXComponent+Layout.h
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Layout/WXComponent+Layout.h b/ios/sdk/WeexSDK/Sources/Layout/WXComponent+Layout.h
index 1baa20f..651af7c 100644
--- a/ios/sdk/WeexSDK/Sources/Layout/WXComponent+Layout.h
+++ b/ios/sdk/WeexSDK/Sources/Layout/WXComponent+Layout.h
@@ -20,7 +20,65 @@
#import "WXComponent.h"
#import "WXSDKInstance.h"
#import "WXUtility.h"
+#import "WXLayoutDefine.h"
+#import "WXCoreLayout.h"
-@interface WXComponent (Layout)
+#define FlexUndefined NAN
+//#define USE_FLEX
+
+
+
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ bool flexIsUndefined(float value);
+#ifdef __cplusplus
+}
+#endif
+@interface WXComponent ()
+{
+ @package
+ /**
+ * Layout
+ */
+//#ifndef USE_FLEX
+ css_node_t *_cssNode;
+//#else
+#ifdef __cplusplus
+ WeexCore::WXCoreLayoutNode *_flexCssNode;
+#endif // __cplusplus
+//#endif //USE_FLEX
+ BOOL _isLayoutDirty;
+ CGRect _calculatedFrame;
+ CGPoint _absolutePosition;
+ WXPositionType _positionType;
+}
+
+//#ifndef USE_FLEX
+/**
+ * @abstract Return the css node used to layout.
+ *
+ * @warning Subclasses must not override this.
+ */
+@property(nonatomic, readonly, assign) css_node_t *cssNode;
+//#else
+#ifdef __cplusplus
+@property(nonatomic, readonly, assign) WeexCore::WXCoreLayoutNode *flexCssNode;
+#endif
+//#endif
+
+@end
+
+@interface WXComponent (Layout)
+//#ifndef USE_FLEX
+//#else
+- (void)_insertChildCssNode:(WXComponent*)subcomponent atIndex:(NSInteger)index;
+- (void)_rmChildCssNode:(WXComponent*)subcomponent;
+- (NSInteger) getActualNodeIndex:(WXComponent*)subcomponent atIndex:(NSInteger) index;
++ (void) setUseFlex:(BOOL) useFlex;
++ (BOOL) isUseFlex;
+//#endif
@end
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Layout/WXComponent+Layout.mm
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Layout/WXComponent+Layout.mm b/ios/sdk/WeexSDK/Sources/Layout/WXComponent+Layout.mm
new file mode 100644
index 0000000..4bdb8f4
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Layout/WXComponent+Layout.mm
@@ -0,0 +1,963 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#import "WXComponent+Layout.h"
+#import "WXComponent_internal.h"
+#import "WXTransform.h"
+#import "WXAssert.h"
+#import "WXSDKInstance_private.h"
+#import "WXComponent+BoxShadow.h"
+#import "WXLog.h"
+
+bool flexIsUndefined(float value) {
+ return isnan(value);
+}
+
+static BOOL sUseFlex = TRUE;
+
+
+@implementation WXComponent (Layout)
+
+#pragma clang diagnostic ignored "-Wobjc-protocol-method-implementation"
+
+#pragma mark Public
+
+- (void)setNeedsLayout
+{
+ _isLayoutDirty = YES;
+ WXComponent *supercomponent = [self supercomponent];
+ if ([WXComponent isUseFlex]) {
+ //protet nil ptr
+ if (self.flexCssNode) {
+ self.flexCssNode->markDirty();
+ }else{
+ WXLogError(@"flexCssNode is nil");
+ }
+ }
+
+ if(supercomponent){
+ [supercomponent setNeedsLayout];
+ }
+}
+
+- (BOOL)needsLayout
+{
+ return _isLayoutDirty;
+}
+
+- (CGSize (^)(CGSize))measureBlock
+{
+ return nil;
+}
+
+- (void)layoutDidFinish
+{
+ WXAssertMainThread();
+}
+
+#pragma mark Private
+
+- (void)_initCSSNodeWithStyles:(NSDictionary *)styles
+{
+//#ifndef USE_FLEX
+ if (! [WXComponent isUseFlex]) {
+ _cssNode = new_css_node();
+
+ _cssNode->print = cssNodePrint;
+ _cssNode->get_child = cssNodeGetChild;
+ _cssNode->is_dirty = cssNodeIsDirty;
+ if ([self measureBlock]) {
+ _cssNode->measure = cssNodeMeasure;
+ }
+ _cssNode->context = (__bridge void *)self;
+
+ [self _recomputeCSSNodeChildren];
+ [self _fillCSSNode:styles isUpdate:NO];
+
+ // To be in conformity with Android/Web, hopefully remove this in the future.
+ if ([self.ref isEqualToString:WX_SDK_ROOT_REF]) {
+ if (isUndefined(_cssNode->style.dimensions[CSS_HEIGHT]) && self.weexInstance.frame.size.height) {
+ _cssNode->style.dimensions[CSS_HEIGHT] = self.weexInstance.frame.size.height;
+ }
+
+ if (isUndefined(_cssNode->style.dimensions[CSS_WIDTH]) && self.weexInstance.frame.size.width) {
+ _cssNode->style.dimensions[CSS_WIDTH] = self.weexInstance.frame.size.width;
+ }
+ }
+ }
+
+//#else
+ else
+ {
+ _flexCssNode = new WeexCore::WXCoreLayoutNode();
+ if ([self measureBlock]) {
+ _flexCssNode->setMeasureFunc(flexCssNodeMeasure);
+ }
+ _flexCssNode->setContext((__bridge void *)self);
+ [self _recomputeCSSNodeChildren];
+ [self _fillCSSNode:styles isUpdate:NO];
+
+ if ([self.ref isEqualToString:WX_SDK_ROOT_REF]) {
+ if (flexIsUndefined(_flexCssNode->getStyleHeight()) && self.weexInstance.frame.size.height) {
+ _flexCssNode->setStyleHeight(self.weexInstance.frame.size.height);
+ }
+
+ if (flexIsUndefined(_flexCssNode->getStyleWidth()) && self.weexInstance.frame.size.width) {
+ _flexCssNode->setStyleWidth(self.weexInstance.frame.size.width,NO);
+ }
+ }
+ }
+//#endif
+}
+
+- (void)_updateCSSNodeStyles:(NSDictionary *)styles
+{
+ [self _fillCSSNode:styles isUpdate:YES];
+}
+
+-(void)_resetCSSNodeStyles:(NSArray *)styles
+{
+ [self _resetCSSNode:styles];
+}
+
+- (void)_recomputeCSSNodeChildren
+{
+//#ifndef USE_FLEX
+ if (![WXComponent isUseFlex]) {
+ _cssNode->children_count = (int)[self _childrenCountForLayout];
+ }
+//#else
+
+//#endif
+}
+
+- (NSUInteger)_childrenCountForLayout
+{
+ NSArray *subcomponents = _subcomponents;
+ NSUInteger count = subcomponents.count;
+ for (WXComponent *component in subcomponents) {
+ if (!component->_isNeedJoinLayoutSystem) {
+ count--;
+ }
+ }
+ return (int)(count);
+}
+
+
+- (void)_frameDidCalculated:(BOOL)isChanged
+{
+ WXAssertComponentThread();
+
+ if ([self isViewLoaded] && isChanged && [self isViewFrameSyncWithCalculated]) {
+
+ __weak typeof(self) weakSelf = self;
+ [self.weexInstance.componentManager _addUITask:^{
+ __strong typeof(weakSelf) strongSelf = weakSelf;
+ if (strongSelf->_transform && !CATransform3DEqualToTransform(strongSelf.layer.transform, CATransform3DIdentity)) {
+ // From the UIView's frame documentation:
+ // https://developer.apple.com/reference/uikit/uiview#//apple_ref/occ/instp/UIView/frame
+ // Warning : If the transform property is not the identity transform, the value of this property is undefined and therefore should be ignored.
+ // So layer's transform must be reset to CATransform3DIdentity before setFrame, otherwise frame will be incorrect
+ strongSelf.layer.transform = CATransform3DIdentity;
+ }
+
+ if (!CGRectEqualToRect(strongSelf.view.frame,strongSelf.calculatedFrame)) {
+ strongSelf.view.frame = strongSelf.calculatedFrame;
+ strongSelf->_absolutePosition = CGPointMake(NAN, NAN);
+ [strongSelf configBoxShadow:_boxShadow];
+ } else {
+ if (![strongSelf equalBoxShadow:_boxShadow withBoxShadow:_lastBoxShadow]) {
+ [strongSelf configBoxShadow:_boxShadow];
+ }
+ }
+
+ [self _resetNativeBorderRadius];
+
+ if (strongSelf->_transform) {
+ [strongSelf->_transform applyTransformForView:strongSelf.view];
+ }
+
+ if (strongSelf->_backgroundImage) {
+ [strongSelf setGradientLayer];
+ }
+ [strongSelf setNeedsDisplay];
+ }];
+ }
+}
+
+- (void)_calculateFrameWithSuperAbsolutePosition:(CGPoint)superAbsolutePosition
+ gatherDirtyComponents:(NSMutableSet<WXComponent *> *)dirtyComponents
+{
+ WXAssertComponentThread();
+
+//#ifndef USE_FLEX
+ if (![WXComponent isUseFlex])
+ {
+ if (!_cssNode->layout.should_update) {
+ return;
+ }
+ _cssNode->layout.should_update = false;
+ _isLayoutDirty = NO;
+
+ CGRect newFrame = CGRectMake(isnan(WXRoundPixelValue(_cssNode->layout.position[CSS_LEFT]))?0:WXRoundPixelValue(_cssNode->layout.position[CSS_LEFT]),
+ isnan(WXRoundPixelValue(_cssNode->layout.position[CSS_TOP]))?0:WXRoundPixelValue(_cssNode->layout.position[CSS_TOP]),
+ isnan(WXRoundPixelValue(_cssNode->layout.dimensions[CSS_WIDTH]))?0:WXRoundPixelValue(_cssNode->layout.dimensions[CSS_WIDTH]),
+ isnan(WXRoundPixelValue(_cssNode->layout.dimensions[CSS_HEIGHT]))?0:WXRoundPixelValue(_cssNode->layout.dimensions[CSS_HEIGHT]));
+
+ BOOL isFrameChanged = NO;
+ if (!CGRectEqualToRect(newFrame, _calculatedFrame)) {
+ isFrameChanged = YES;
+ _calculatedFrame = newFrame;
+ [dirtyComponents addObject:self];
+ }
+
+ _cssNode->layout.dimensions[CSS_WIDTH] = CSS_UNDEFINED;
+ _cssNode->layout.dimensions[CSS_HEIGHT] = CSS_UNDEFINED;
+ _cssNode->layout.position[CSS_LEFT] = 0;
+ _cssNode->layout.position[CSS_TOP] = 0;
+
+ [self _frameDidCalculated:isFrameChanged];
+ NSArray * subcomponents = [_subcomponents copy];
+ for (WXComponent *subcomponent in subcomponents) {
+ [subcomponent _calculateFrameWithSuperAbsolutePosition:superAbsolutePosition gatherDirtyComponents:dirtyComponents];
+ }
+#ifdef DEBUG
+ WXLogDebug(@"flexLayout -> newFrame ,type:%@,ref:%@, parentRef:%@,size :%@ ,instance:%@",self.type,self.ref,self.supercomponent.ref,NSStringFromCGRect(newFrame),self.weexInstance.instanceId);
+#endif
+ }
+
+//#else
+ else
+ {
+ if (self.flexCssNode->hasNewLayout()) {
+ self.flexCssNode->setHasNewLayout(false);
+ _isLayoutDirty = NO;
+ CGRect newFrame = CGRectMake(
+ isnan(WXRoundPixelValue(_flexCssNode->getLayoutPositionLeft()))?0:WXRoundPixelValue(_flexCssNode->getLayoutPositionLeft())
+ ,isnan(WXRoundPixelValue(_flexCssNode->getLayoutPositionTop()))?0:WXRoundPixelValue(_flexCssNode->getLayoutPositionTop())
+ ,isnan(WXRoundPixelValue(_flexCssNode->getLayoutWidth()))?0:WXRoundPixelValue(_flexCssNode->getLayoutWidth())
+ ,isnan(WXRoundPixelValue(_flexCssNode->getLayoutHeight()))?0:WXRoundPixelValue(_flexCssNode->getLayoutHeight())
+ );
+ BOOL isFrameChanged = NO;
+
+ if (!CGRectEqualToRect(newFrame, _calculatedFrame)) {
+
+ isFrameChanged = YES;
+ _calculatedFrame = newFrame;
+ [dirtyComponents addObject:self];
+ }
+
+ [self _frameDidCalculated:isFrameChanged];
+#ifdef DEBUG
+ WXLogDebug(@"flexLayout -> newFrame ,type:%@,ref:%@, parentRef:%@,size :%@ ,instance:%@",self.type,self.ref,self.supercomponent.ref,NSStringFromCGRect(newFrame),self.weexInstance.instanceId);
+#endif
+ }
+
+ NSArray * subcomponents = [_subcomponents copy];
+ for (WXComponent *subcomponent in subcomponents) {
+ [subcomponent _calculateFrameWithSuperAbsolutePosition:superAbsolutePosition gatherDirtyComponents:dirtyComponents];
+ }
+ }
+//#endif
+}
+
+- (void)_layoutDidFinish
+{
+ WXAssertMainThread();
+
+ if (_positionType == WXPositionTypeSticky) {
+ [self.ancestorScroller adjustSticky];
+ }
+ [self layoutDidFinish];
+}
+
+//#ifndef USE_FLEX
+
+#define WX_STYLE_FILL_CSS_NODE(key, cssProp, type)\
+do {\
+ id value = styles[@#key];\
+ if (value) {\
+ typeof(_cssNode->style.cssProp) convertedValue = (typeof(_cssNode->style.cssProp))[WXConvert type:value];\
+ _cssNode->style.cssProp = convertedValue;\
+ [self setNeedsLayout];\
+ }\
+} while(0);
+
+#define WX_STYLE_FILL_CSS_NODE_PIXEL(key, cssProp)\
+do {\
+ id value = styles[@#key];\
+ if (value) {\
+ CGFloat pixel = [self WXPixelType:value];\
+ if (isnan(pixel)) {\
+ WXLogError(@"Invalid NaN value for style:%@, ref:%@", @#key, self.ref);\
+ } else {\
+ _cssNode->style.cssProp = pixel;\
+ [self setNeedsLayout];\
+ }\
+ }\
+} while(0);
+
+#define WX_STYLE_FILL_CSS_NODE_ALL_DIRECTION(key, cssProp)\
+do {\
+ WX_STYLE_FILL_CSS_NODE_PIXEL(key, cssProp[CSS_TOP])\
+ WX_STYLE_FILL_CSS_NODE_PIXEL(key, cssProp[CSS_LEFT])\
+ WX_STYLE_FILL_CSS_NODE_PIXEL(key, cssProp[CSS_RIGHT])\
+ WX_STYLE_FILL_CSS_NODE_PIXEL(key, cssProp[CSS_BOTTOM])\
+} while(0);
+
+//#else
+
+#define WX_STYLE_FLEX_NODE_JUDGE_LEGAL(key) styles[key]&&!isnan([WXConvert WXPixelType:styles[key] scaleFactor:self.weexInstance.pixelScaleFactor])
+
+//#endif
+
+- (CGFloat)WXPixelType:(id)value
+{
+ return [WXConvert WXPixelType:value scaleFactor:self.weexInstance.pixelScaleFactor];
+}
+
+- (void)_fillCSSNode:(NSDictionary *)styles isUpdate:(BOOL)isUpdate
+{
+//#ifndef USE_FLEX
+ if(![WXComponent isUseFlex])
+ {
+ WX_STYLE_FILL_CSS_NODE(direction, direction, css_direction_t)
+ // flex
+ WX_STYLE_FILL_CSS_NODE(flex, flex, CGFloat)
+ WX_STYLE_FILL_CSS_NODE(flexDirection, flex_direction, css_flex_direction_t)
+ WX_STYLE_FILL_CSS_NODE(alignItems, align_items, css_align_t)
+ WX_STYLE_FILL_CSS_NODE(alignSelf, align_self, css_align_t)
+ WX_STYLE_FILL_CSS_NODE(flexWrap, flex_wrap, css_wrap_type_t)
+ WX_STYLE_FILL_CSS_NODE(justifyContent, justify_content, css_justify_t)
+
+ // position
+ WX_STYLE_FILL_CSS_NODE(position, position_type, css_position_type_t)
+ WX_STYLE_FILL_CSS_NODE_PIXEL(top, position[CSS_TOP])
+ WX_STYLE_FILL_CSS_NODE_PIXEL(left, position[CSS_LEFT])
+ WX_STYLE_FILL_CSS_NODE_PIXEL(right, position[CSS_RIGHT])
+ WX_STYLE_FILL_CSS_NODE_PIXEL(bottom, position[CSS_BOTTOM])
+
+ // dimension
+ WX_STYLE_FILL_CSS_NODE_PIXEL(width, dimensions[CSS_WIDTH])
+ WX_STYLE_FILL_CSS_NODE_PIXEL(height, dimensions[CSS_HEIGHT])
+ WX_STYLE_FILL_CSS_NODE_PIXEL(minWidth, minDimensions[CSS_WIDTH])
+ WX_STYLE_FILL_CSS_NODE_PIXEL(minHeight, minDimensions[CSS_HEIGHT])
+ WX_STYLE_FILL_CSS_NODE_PIXEL(maxWidth, maxDimensions[CSS_WIDTH])
+ WX_STYLE_FILL_CSS_NODE_PIXEL(maxHeight, maxDimensions[CSS_HEIGHT])
+
+ // margin
+ WX_STYLE_FILL_CSS_NODE_ALL_DIRECTION(margin, margin)
+ WX_STYLE_FILL_CSS_NODE_PIXEL(marginTop, margin[CSS_TOP])
+ WX_STYLE_FILL_CSS_NODE_PIXEL(marginLeft, margin[CSS_LEFT])
+ WX_STYLE_FILL_CSS_NODE_PIXEL(marginRight, margin[CSS_RIGHT])
+ WX_STYLE_FILL_CSS_NODE_PIXEL(marginBottom, margin[CSS_BOTTOM])
+
+ // border
+ WX_STYLE_FILL_CSS_NODE_ALL_DIRECTION(borderWidth, border)
+ WX_STYLE_FILL_CSS_NODE_PIXEL(borderTopWidth, border[CSS_TOP])
+ WX_STYLE_FILL_CSS_NODE_PIXEL(borderLeftWidth, border[CSS_LEFT])
+ WX_STYLE_FILL_CSS_NODE_PIXEL(borderRightWidth, border[CSS_RIGHT])
+ WX_STYLE_FILL_CSS_NODE_PIXEL(borderBottomWidth, border[CSS_BOTTOM])
+
+ // padding
+ WX_STYLE_FILL_CSS_NODE_ALL_DIRECTION(padding, padding)
+ WX_STYLE_FILL_CSS_NODE_PIXEL(paddingTop, padding[CSS_TOP])
+ WX_STYLE_FILL_CSS_NODE_PIXEL(paddingLeft, padding[CSS_LEFT])
+ WX_STYLE_FILL_CSS_NODE_PIXEL(paddingRight, padding[CSS_RIGHT])
+ WX_STYLE_FILL_CSS_NODE_PIXEL(paddingBottom, padding[CSS_BOTTOM])
+ }
+
+//#else
+ else
+ {
+ // flex
+ if (styles[@"flex"]) {
+ _flexCssNode->setFlex([WXConvert CGFloat:styles[@"flex"]]);
+ }
+ if (isnan(_flexCssNode->getFlex())) {
+ // to make the default flex value is zero, yoga is nan, maybe this can configured by yoga config
+ _flexCssNode->setFlex(0);
+ }
+
+ if (styles[@"flexDirection"]) {
+ _flexCssNode->setFlexDirection([self fxFlexDirection:styles[@"flexDirection"]],isUpdate);
+ }
+ if (styles[@"alignItems"]) {
+ _flexCssNode->setAlignItems([self fxAlign:styles[@"alignItems"]]);
+ }
+ if (styles[@"alignSelf"]) {
+ _flexCssNode->setAlignSelf([self fxAlignSelf:styles[@"alignSelf"]]);
+ }
+ if (styles[@"flexWrap"]) {
+ _flexCssNode->setFlexWrap([self fxWrap:styles[@"flexWrap"]]);
+ }
+ if (styles[@"justifyContent"]) {
+ _flexCssNode->setJustifyContent([self fxJustify:styles[@"justifyContent"]]);
+ }
+
+ // position
+ if (styles[@"position"]) {
+ _flexCssNode->setStylePositionType([self fxPositionType:styles[@"position"]]);
+ }
+ if (styles[@"top"]) {
+ _flexCssNode->setStylePosition(WeexCore::kPositionEdgeTop,
+ [self judgePropValuePropValue:styles[@"top"] defaultValue:NAN]);
+ }
+ if (styles[@"left"]) {
+ _flexCssNode->setStylePosition(WeexCore::kPositionEdgeLeft,
+ [self judgePropValuePropValue:styles[@"left"] defaultValue:NAN]);
+ }
+ if(styles[@"right"]) {
+ _flexCssNode->setStylePosition(WeexCore::kPositionEdgeRight,
+ [self judgePropValuePropValue:styles[@"right"] defaultValue:NAN]);
+ }
+ if (styles[@"bottom"]) {
+ _flexCssNode->setStylePosition(WeexCore::kPositionEdgeBottom,
+ [self judgePropValuePropValue:styles[@"bottom"] defaultValue:NAN]);
+ }
+
+ // dimension
+ if (styles[@"width"]) {
+ _flexCssNode->setStyleWidth([self judgePropValuePropValue:styles[@"width"] defaultValue:NAN]
+ ,isUpdate);
+ }
+ if (styles[@"height"]) {
+ _flexCssNode->setStyleHeight([self judgePropValuePropValue:styles[@"height"] defaultValue:NAN]);
+ }
+ if (styles[@"minWidth"]) {
+ _flexCssNode->setMinWidth([self judgePropValuePropValue:styles[@"minWidth"] defaultValue:NAN]
+ ,isUpdate);
+ }
+ if (styles[@"minHeight"]) {
+ _flexCssNode->setMinHeight([self judgePropValuePropValue:styles[@"minHeight"] defaultValue:NAN]);
+ }
+ if (styles[@"maxWidth"]) {
+ _flexCssNode->setMaxWidth([self judgePropValuePropValue:styles[@"maxWidth"] defaultValue:NAN]
+ ,isUpdate);
+ }
+ if (styles[@"maxHeight"]) {
+ _flexCssNode->setMaxHeight([self judgePropValuePropValue:styles[@"maxHeight"] defaultValue:NAN]);
+ }
+
+ // margin
+ if (styles[@"margin"]) {
+ _flexCssNode->setMargin(WeexCore::kMarginALL,
+ [self judgePropValuePropValue:styles[@"margin"] defaultValue:0]);
+ }
+ if (styles[@"marginTop"]) {
+ _flexCssNode->setMargin(WeexCore::kMarginTop,
+ [self judgePropValuePropValue:styles[@"marginTop"] defaultValue:0]);
+ }
+ if (styles[@"marginBottom"]) {
+ _flexCssNode->setMargin(WeexCore::kMarginBottom,
+ [self judgePropValuePropValue:styles[@"marginBottom"] defaultValue:0]);
+ }
+ if (styles[@"marginRight"]) {
+ _flexCssNode->setMargin(WeexCore::kMarginRight,
+ [self judgePropValuePropValue:styles[@"marginRight"] defaultValue:0]);
+ }
+ if (styles[@"marginLeft"]) {
+ _flexCssNode->setMargin(WeexCore::kMarginLeft,
+ [self judgePropValuePropValue:styles[@"marginLeft"] defaultValue:0]);
+ }
+
+ // border
+ if (styles[@"borderWidth"]) {
+ _flexCssNode->setBorderWidth(WeexCore::kBorderWidthALL,
+ [self judgePropValuePropValue:styles[@"borderWidth"] defaultValue:0]);
+ }
+ if (styles[@"borderTopWidth"]) {
+ _flexCssNode->setBorderWidth(WeexCore::kBorderWidthTop,
+ [self judgePropValuePropValue:styles[@"borderTopWidth"] defaultValue:0]);
+ }
+
+ if (styles[@"borderLeftWidth"]) {
+ _flexCssNode->setBorderWidth(WeexCore::kBorderWidthLeft,
+ [self judgePropValuePropValue:styles[@"borderLeftWidth"] defaultValue:0]);
+ }
+
+ if (styles[@"borderBottomWidth"]) {
+ _flexCssNode->setBorderWidth(WeexCore::kBorderWidthBottom,
+ [self judgePropValuePropValue:styles[@"borderBottomWidth"] defaultValue:0]);
+ }
+ if (styles[@"borderRightWidth"]) {
+ _flexCssNode->setBorderWidth(WeexCore::kBorderWidthRight,
+ [self judgePropValuePropValue:styles[@"borderRightWidth"] defaultValue:0]);
+ }
+
+ // padding
+ if (styles[@"padding"]) {
+ _flexCssNode->setPadding(WeexCore::kPaddingALL,
+ [self judgePropValuePropValue:styles[@"padding"] defaultValue:0]);
+ }
+ if (styles[@"paddingTop"]) {
+ _flexCssNode->setPadding(WeexCore::kPaddingTop,
+ [self judgePropValuePropValue:styles[@"paddingTop"] defaultValue:0]);
+ }
+ if (styles[@"paddingLeft"]) {
+ _flexCssNode->setPadding(WeexCore::kPaddingLeft,
+ [self judgePropValuePropValue:styles[@"paddingLeft"] defaultValue:0]);
+ }
+ if (styles[@"paddingBottom"]) {
+ _flexCssNode->setPadding(WeexCore::kPaddingBottom,
+ [self judgePropValuePropValue:styles[@"paddingBottom"] defaultValue:0]);
+ }
+ if (styles[@"paddingRight"]) {
+ _flexCssNode->setPadding(WeexCore::kPaddingRight,
+ [self judgePropValuePropValue:styles[@"paddingRight"] defaultValue:0]);
+ }
+
+ [self setNeedsLayout];
+ }
+
+//#endif
+}
+
+-(CGFloat)judgePropValuePropValue:(NSString *)propValue defaultValue:(CGFloat)defaultValue{
+ CGFloat convertValue = (CGFloat)[WXConvert WXPixelType:propValue scaleFactor:self.weexInstance.pixelScaleFactor];
+ if (!isnan(convertValue)) {
+ return convertValue;
+ }
+ return defaultValue;
+}
+
+//#ifndef USE_FLEX
+
+#define WX_STYLE_RESET_CSS_NODE(key, cssProp, defaultValue)\
+do {\
+ if (styles && [styles containsObject:@#key]) {\
+ _cssNode->style.cssProp = defaultValue;\
+ [self setNeedsLayout];\
+ }\
+} while(0);
+
+#define WX_STYLE_RESET_CSS_NODE_ALL_DIRECTION(key, cssProp, defaultValue)\
+do {\
+ WX_STYLE_RESET_CSS_NODE(key, cssProp[CSS_TOP], defaultValue)\
+ WX_STYLE_RESET_CSS_NODE(key, cssProp[CSS_LEFT], defaultValue)\
+ WX_STYLE_RESET_CSS_NODE(key, cssProp[CSS_RIGHT], defaultValue)\
+ WX_STYLE_RESET_CSS_NODE(key, cssProp[CSS_BOTTOM], defaultValue)\
+} while(0);
+
+//#else
+
+#define WX_FLEX_STYLE_RESET_CSS_NODE(key, defaultValue)\
+do {\
+ WX_FLEX_STYLE_RESET_CSS_NODE_GIVEN_KEY(key,key,defaultValue)\
+} while(0);
+
+#define WX_FLEX_STYLE_RESET_CSS_NODE_GIVEN_KEY(judgeKey, propKey, defaultValue)\
+do {\
+ if (styles && [styles containsObject:@#judgeKey]) {\
+ NSMutableDictionary *resetStyleDic = [[NSMutableDictionary alloc] init];\
+ [resetStyleDic setValue:defaultValue forKey:@#propKey];\
+ [self _updateCSSNodeStyles:resetStyleDic];\
+ [self setNeedsLayout];\
+ }\
+} while(0);
+
+#define WX_FLEX_STYLE_RESET_CSS_NODE_GIVEN_DIRECTION_KEY(judgeKey, propTopKey,propLeftKey,propRightKey,propBottomKey, defaultValue)\
+do {\
+ if (styles && [styles containsObject:@#judgeKey]) {\
+ NSMutableDictionary *resetStyleDic = [[NSMutableDictionary alloc] init];\
+ [resetStyleDic setValue:defaultValue forKey:@#propTopKey];\
+ [resetStyleDic setValue:defaultValue forKey:@#propLeftKey];\
+ [resetStyleDic setValue:defaultValue forKey:@#propRightKey];\
+ [resetStyleDic setValue:defaultValue forKey:@#propBottomKey];\
+ [self _updateCSSNodeStyles:resetStyleDic];\
+ [self setNeedsLayout];\
+ }\
+} while(0);
+
+//#endif
+
+
+- (void)_resetCSSNode:(NSArray *)styles
+{
+//#ifndef USE_FLEX
+ if(![WXComponent isUseFlex])
+ {
+ WX_STYLE_RESET_CSS_NODE(direction, direction, CSS_DIRECTION_LTR)
+ // flex
+ WX_STYLE_RESET_CSS_NODE(flex, flex, 0.0)
+ WX_STYLE_RESET_CSS_NODE(flexDirection, flex_direction, CSS_FLEX_DIRECTION_COLUMN)
+ WX_STYLE_RESET_CSS_NODE(alignItems, align_items, CSS_ALIGN_STRETCH)
+ WX_STYLE_RESET_CSS_NODE(alignSelf, align_self, CSS_ALIGN_AUTO)
+ WX_STYLE_RESET_CSS_NODE(flexWrap, flex_wrap, CSS_NOWRAP)
+ WX_STYLE_RESET_CSS_NODE(justifyContent, justify_content, CSS_JUSTIFY_FLEX_START)
+
+ // position
+ WX_STYLE_RESET_CSS_NODE(position, position_type, CSS_POSITION_RELATIVE)
+ WX_STYLE_RESET_CSS_NODE(top, position[CSS_TOP], CSS_UNDEFINED)
+ WX_STYLE_RESET_CSS_NODE(left, position[CSS_LEFT], CSS_UNDEFINED)
+ WX_STYLE_RESET_CSS_NODE(right, position[CSS_RIGHT], CSS_UNDEFINED)
+ WX_STYLE_RESET_CSS_NODE(bottom, position[CSS_BOTTOM], CSS_UNDEFINED)
+
+ // dimension
+ WX_STYLE_RESET_CSS_NODE(width, dimensions[CSS_WIDTH], CSS_UNDEFINED)
+ WX_STYLE_RESET_CSS_NODE(height, dimensions[CSS_HEIGHT], CSS_UNDEFINED)
+ WX_STYLE_RESET_CSS_NODE(minWidth, minDimensions[CSS_WIDTH], CSS_UNDEFINED)
+ WX_STYLE_RESET_CSS_NODE(minHeight, minDimensions[CSS_HEIGHT], CSS_UNDEFINED)
+ WX_STYLE_RESET_CSS_NODE(maxWidth, maxDimensions[CSS_WIDTH], CSS_UNDEFINED)
+ WX_STYLE_RESET_CSS_NODE(maxHeight, maxDimensions[CSS_HEIGHT], CSS_UNDEFINED)
+
+ // margin
+ WX_STYLE_RESET_CSS_NODE_ALL_DIRECTION(margin, margin, 0.0)
+ WX_STYLE_RESET_CSS_NODE(marginTop, margin[CSS_TOP], 0.0)
+ WX_STYLE_RESET_CSS_NODE(marginLeft, margin[CSS_LEFT], 0.0)
+ WX_STYLE_RESET_CSS_NODE(marginRight, margin[CSS_RIGHT], 0.0)
+ WX_STYLE_RESET_CSS_NODE(marginBottom, margin[CSS_BOTTOM], 0.0)
+
+ // border
+ WX_STYLE_RESET_CSS_NODE_ALL_DIRECTION(borderWidth, border, 0.0)
+ WX_STYLE_RESET_CSS_NODE(borderTopWidth, border[CSS_TOP], 0.0)
+ WX_STYLE_RESET_CSS_NODE(borderLeftWidth, border[CSS_LEFT], 0.0)
+ WX_STYLE_RESET_CSS_NODE(borderRightWidth, border[CSS_RIGHT], 0.0)
+ WX_STYLE_RESET_CSS_NODE(borderBottomWidth, border[CSS_BOTTOM], 0.0)
+
+ // padding
+ WX_STYLE_RESET_CSS_NODE_ALL_DIRECTION(padding, padding, 0.0)
+ WX_STYLE_RESET_CSS_NODE(paddingTop, padding[CSS_TOP], 0.0)
+ WX_STYLE_RESET_CSS_NODE(paddingLeft, padding[CSS_LEFT], 0.0)
+ WX_STYLE_RESET_CSS_NODE(paddingRight, padding[CSS_RIGHT], 0.0)
+ WX_STYLE_RESET_CSS_NODE(paddingBottom, padding[CSS_BOTTOM], 0.0)
+ }
+
+//#else
+ else
+ {
+ if (styles.count<=0) {
+ return;
+ }
+
+ WX_FLEX_STYLE_RESET_CSS_NODE(flex, @0.0)
+ WX_FLEX_STYLE_RESET_CSS_NODE(flexDirection, @(CSS_FLEX_DIRECTION_COLUMN))
+ WX_FLEX_STYLE_RESET_CSS_NODE(alignItems, @(CSS_ALIGN_STRETCH))
+ WX_FLEX_STYLE_RESET_CSS_NODE(alignSelf, @(CSS_ALIGN_AUTO))
+ WX_FLEX_STYLE_RESET_CSS_NODE(flexWrap, @(CSS_NOWRAP))
+ WX_FLEX_STYLE_RESET_CSS_NODE(justifyContent, @(CSS_JUSTIFY_FLEX_START))
+
+ // position
+ WX_FLEX_STYLE_RESET_CSS_NODE(position, @(CSS_POSITION_RELATIVE))
+ WX_FLEX_STYLE_RESET_CSS_NODE(top, @(CSS_UNDEFINED))
+ WX_FLEX_STYLE_RESET_CSS_NODE(left, @(CSS_UNDEFINED))
+ WX_FLEX_STYLE_RESET_CSS_NODE(right, @(CSS_UNDEFINED))
+ WX_FLEX_STYLE_RESET_CSS_NODE(bottom, @(CSS_UNDEFINED))
+
+ // dimension
+ WX_FLEX_STYLE_RESET_CSS_NODE(width, @(CSS_UNDEFINED))
+ WX_FLEX_STYLE_RESET_CSS_NODE(height, @(CSS_UNDEFINED))
+ WX_FLEX_STYLE_RESET_CSS_NODE(minWidth, @(CSS_UNDEFINED))
+ WX_FLEX_STYLE_RESET_CSS_NODE(minHeight, @(CSS_UNDEFINED))
+ WX_FLEX_STYLE_RESET_CSS_NODE(maxWidth, @(CSS_UNDEFINED))
+ WX_FLEX_STYLE_RESET_CSS_NODE(maxHeight, @(CSS_UNDEFINED))
+
+ // margin
+ WX_FLEX_STYLE_RESET_CSS_NODE_GIVEN_DIRECTION_KEY(margin
+ ,marginTop
+ ,marginLeft
+ ,marginRight
+ ,marginBottom
+ , @(0.0))
+ WX_FLEX_STYLE_RESET_CSS_NODE(marginTop, @(0.0))
+ WX_FLEX_STYLE_RESET_CSS_NODE(marginLeft, @(0.0))
+ WX_FLEX_STYLE_RESET_CSS_NODE(marginRight, @(0.0))
+ WX_FLEX_STYLE_RESET_CSS_NODE(marginBottom, @(0.0))
+
+ // border
+ WX_FLEX_STYLE_RESET_CSS_NODE_GIVEN_DIRECTION_KEY(borderWidth
+ , borderTopWidth
+ , borderLeftWidth
+ , borderRightWidth
+ , borderBottomWidth
+ , @(0.0))
+ WX_FLEX_STYLE_RESET_CSS_NODE(borderTopWidth, @(0.0))
+ WX_FLEX_STYLE_RESET_CSS_NODE(borderLeftWidth, @(0.0))
+ WX_FLEX_STYLE_RESET_CSS_NODE(borderRightWidth, @(0.0))
+ WX_FLEX_STYLE_RESET_CSS_NODE(borderBottomWidth, @(0.0))
+
+ // padding
+ WX_FLEX_STYLE_RESET_CSS_NODE_GIVEN_DIRECTION_KEY(padding
+ , paddingTop
+ , paddingLeft
+ , paddingRight
+ , paddingBottom
+ , @(0.0))
+ WX_FLEX_STYLE_RESET_CSS_NODE(paddingTop, @(0.0))
+ WX_FLEX_STYLE_RESET_CSS_NODE(paddingLeft, @(0.0))
+ WX_FLEX_STYLE_RESET_CSS_NODE(paddingRight, @(0.0))
+ WX_FLEX_STYLE_RESET_CSS_NODE(paddingBottom, @(0.0))
+ }
+
+
+//#endif
+}
+
+#pragma mark CSS Node Override
+
+//#ifndef USE_FLEX
+#if defined __cplusplus
+extern "C" {
+#endif
+static void cssNodePrint(void *context)
+{
+ WXComponent *component = (__bridge WXComponent *)context;
+ // TODO:
+ printf("%s:%s ", component.ref.UTF8String, component->_type.UTF8String);
+}
+
+static css_node_t * cssNodeGetChild(void *context, int i)
+{
+ WXComponent *component = (__bridge WXComponent *)context;
+ NSArray *subcomponents = component->_subcomponents;
+ for (int j = 0; j <= i && j < subcomponents.count; j++) {
+ WXComponent *child = subcomponents[j];
+ if (!child->_isNeedJoinLayoutSystem) {
+ i++;
+ }
+ }
+
+ if(i >= 0 && i < subcomponents.count){
+ WXComponent *child = subcomponents[i];
+// WXLogInfo(@"FlexLayout -- P:%@ -> C:%@",component,(__bridge WXComponent *)child->_cssNode->context);
+ return child->_cssNode;
+ }
+
+ WXAssert(NO, @"Can not find component:%@'s css node child at index: %ld, totalCount:%ld", component, i, subcomponents.count);
+ return NULL;
+}
+
+static bool cssNodeIsDirty(void *context)
+{
+ WXAssertComponentThread();
+
+ WXComponent *component = (__bridge WXComponent *)context;
+ BOOL needsLayout = [component needsLayout];
+
+ return needsLayout;
+}
+
+static css_dim_t cssNodeMeasure(void *context, float width, css_measure_mode_t widthMode, float height, css_measure_mode_t heightMode)
+{
+ WXComponent *component = (__bridge WXComponent *)context;
+ CGSize (^measureBlock)(CGSize) = [component measureBlock];
+
+ if (!measureBlock) {
+ return (css_dim_t){NAN, NAN};
+ }
+
+ CGSize constrainedSize = CGSizeMake(width, height);
+ CGSize resultSize = measureBlock(constrainedSize);
+#ifdef DEBUG
+ WXLogDebug(@"flexLayout -> measureblock %@, resultSize:%@",
+ component.type,
+ NSStringFromCGSize(resultSize)
+ );
+#endif
+
+ return (css_dim_t){(float)resultSize.width, (float)resultSize.height};
+}
+#if defined __cplusplus
+};
+#endif
+
+//#else
+
+static WeexCore::WXCoreSize flexCssNodeMeasure(WeexCore::WXCoreLayoutNode *node, float width, WeexCore::MeasureMode widthMeasureMode,float height, WeexCore::MeasureMode heightMeasureMode){
+
+ if (node->getContext() == nullptr) { //为空
+ return WeexCore::WXCoreSize();
+ }
+ WXComponent *component = (__bridge WXComponent *)(node->getContext());
+
+ if (![component respondsToSelector:@selector(measureBlock)]) {
+ return WeexCore::WXCoreSize();
+ }
+
+ CGSize (^measureBlock)(CGSize) = [component measureBlock];
+
+ if (!measureBlock) {
+ return WeexCore::WXCoreSize();
+ }
+
+ CGSize constrainedSize = CGSizeMake(width, height);
+ CGSize resultSize = measureBlock(constrainedSize);
+#ifdef DEBUG
+ WXLogDebug(@"flexLayout -> measureblock %@, resultSize:%@",
+ component.type,
+ NSStringFromCGSize(resultSize)
+ );
+#endif
+ WeexCore::WXCoreSize size;
+ size.height=(float)resultSize.height;
+ size.width=(float)resultSize.width;
+ return size;
+}
+
+-(WeexCore::WXCorePositionType)fxPositionType:(id)value
+{
+ if([value isKindOfClass:[NSString class]]){
+ if ([value isEqualToString:@"absolute"]) {
+ return WeexCore::kAbsolute;
+ } else if ([value isEqualToString:@"relative"]) {
+ return WeexCore::kRelative;
+ } else if ([value isEqualToString:@"fixed"]) {
+ return WeexCore::kFixed;
+ } else if ([value isEqualToString:@"sticky"]) {
+ return WeexCore::kRelative;
+ }
+ }
+ return WeexCore::kRelative;
+}
+
+- (WeexCore::WXCoreFlexDirection)fxFlexDirection:(id)value
+{
+ if([value isKindOfClass:[NSString class]]){
+ if ([value isEqualToString:@"column"]) {
+ return WeexCore::kFlexDirectionColumn;
+ } else if ([value isEqualToString:@"column-reverse"]) {
+ return WeexCore::kFlexDirectionColumnReverse;
+ } else if ([value isEqualToString:@"row"]) {
+ return WeexCore::kFlexDirectionRow;
+ } else if ([value isEqualToString:@"row-reverse"]) {
+ return WeexCore::kFlexDirectionRowReverse;
+ }
+ }
+ return WeexCore::kFlexDirectionColumn;
+}
+
+//TODO
+- (WeexCore::WXCoreAlignItems)fxAlign:(id)value
+{
+ if([value isKindOfClass:[NSString class]]){
+ if ([value isEqualToString:@"stretch"]) {
+ return WeexCore::kAlignItemsStretch;
+ } else if ([value isEqualToString:@"flex-start"]) {
+ return WeexCore::kAlignItemsFlexStart;
+ } else if ([value isEqualToString:@"flex-end"]) {
+ return WeexCore::kAlignItemsFlexEnd;
+ } else if ([value isEqualToString:@"center"]) {
+ return WeexCore::kAlignItemsCenter;
+ //return WXCoreFlexLayout::WXCore_AlignItems_Center;
+ } else if ([value isEqualToString:@"auto"]) {
+// return YGAlignAuto;
+ } else if ([value isEqualToString:@"baseline"]) {
+// return YGAlignBaseline;
+ }
+ }
+
+ return WeexCore::kAlignItemsStretch;
+}
+
+- (WeexCore::WXCoreAlignSelf)fxAlignSelf:(id)value
+{
+ if([value isKindOfClass:[NSString class]]){
+ if ([value isEqualToString:@"stretch"]) {
+ return WeexCore::kAlignSelfStretch;
+ } else if ([value isEqualToString:@"flex-start"]) {
+ return WeexCore::kAlignSelfFlexStart;
+ } else if ([value isEqualToString:@"flex-end"]) {
+ return WeexCore::kAlignSelfFlexEnd;
+ } else if ([value isEqualToString:@"center"]) {
+ return WeexCore::kAlignSelfCenter;
+ } else if ([value isEqualToString:@"auto"]) {
+ return WeexCore::kAlignSelfAuto;
+ } else if ([value isEqualToString:@"baseline"]) {
+ // return YGAlignBaseline;
+ }
+ }
+
+ return WeexCore::kAlignSelfStretch;
+}
+
+- (WeexCore::WXCoreFlexWrap)fxWrap:(id)value
+{
+ if([value isKindOfClass:[NSString class]]) {
+ if ([value isEqualToString:@"nowrap"]) {
+ return WeexCore::kNoWrap;
+ } else if ([value isEqualToString:@"wrap"]) {
+ return WeexCore::kWrap;
+ } else if ([value isEqualToString:@"wrap-reverse"]) {
+ return WeexCore::kWrapReverse;
+ }
+ }
+ return WeexCore::kNoWrap;
+}
+
+- (WeexCore::WXCoreJustifyContent)fxJustify:(id)value
+{
+ if([value isKindOfClass:[NSString class]]){
+ if ([value isEqualToString:@"flex-start"]) {
+ return WeexCore::kJustifyFlexStart;
+ } else if ([value isEqualToString:@"center"]) {
+ return WeexCore::kJustifyCenter;
+ } else if ([value isEqualToString:@"flex-end"]) {
+ return WeexCore::kJustifyFlexEnd;
+ } else if ([value isEqualToString:@"space-between"]) {
+ return WeexCore::kJustifySpaceBetween;
+ } else if ([value isEqualToString:@"space-around"]) {
+ return WeexCore::kJustifySpaceAround;
+ }
+ }
+ return WeexCore::kJustifyFlexStart;
+}
+
+
+- (NSInteger) getActualNodeIndex:(WXComponent*)subcomponent atIndex:(NSInteger) index
+{
+ NSInteger actualIndex = 0; //实际除去不需要布局的subComponent,此时所在的正确位置
+ for (WXComponent *child in _subcomponents) {
+ if ([child.ref isEqualToString:subcomponent.ref]) {
+ break;
+ }
+ if (child->_isNeedJoinLayoutSystem) {
+ actualIndex ++;
+ }
+ }
+ return actualIndex;
+}
+
+- (void)_insertChildCssNode:(WXComponent*)subcomponent atIndex:(NSInteger)index
+{
+ self.flexCssNode->addChildAt(subcomponent.flexCssNode, (uint32_t)index);
+}
+
+- (void)_rmChildCssNode:(WXComponent *)subcomponent
+{
+ self.flexCssNode->removeChild(subcomponent->_flexCssNode);
+#ifdef DEBUG
+ WXLogDebug(@"flexLayout -> ref:%@ ,flexCssNode->removeChild ,childRef:%@",self.ref,subcomponent.ref);
+#endif
+}
+
+
++ (void) setUseFlex:(BOOL)useFlex
+{
+ sUseFlex =useFlex;
+}
+
+
++ (BOOL) isUseFlex
+{
+ return sUseFlex;
+}
+
+//#endif
+
+@end
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Layout/WXCoreFlexEnum.h
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Layout/WXCoreFlexEnum.h b/ios/sdk/WeexSDK/Sources/Layout/WXCoreFlexEnum.h
new file mode 100644
index 0000000..26fe8a3
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Layout/WXCoreFlexEnum.h
@@ -0,0 +1,107 @@
+#ifdef __cplusplus
+
+#ifndef WEEXCORE_FLEXLAYOUT_WXCOREFLEXENUM_H
+#define WEEXCORE_FLEXLAYOUT_WXCOREFLEXENUM_H
+
+namespace WeexCore {
+
+ /**
+ * MainAxis direction
+ */
+ enum WXCoreFlexDirection {
+ kFlexDirectionColumn,
+ kFlexDirectionColumnReverse,
+ kFlexDirectionRow,
+ kFlexDirectionRowReverse,
+ };
+
+ /**
+ * Controls the position of the element on the MainAxis
+ */
+ enum WXCoreJustifyContent {
+ kJustifyFlexStart,
+ kJustifyCenter,
+ kJustifyFlexEnd,
+ kJustifySpaceBetween,
+ kJustifySpaceAround,
+ };
+
+ /**
+ * Controls the position of the element on the CrossAxis and whether Stretch
+ */
+ enum WXCoreAlignItems {
+ kAlignItemsFlexStart,
+ kAlignItemsCenter,
+ kAlignItemsFlexEnd,
+ kAlignItemsStretch,
+ };
+
+ /**
+ * Controls the count of flexlines
+ */
+ enum WXCoreFlexWrap {
+ kNoWrap,
+ kWrap,
+ kWrapReverse,
+ };
+
+ /**
+ * The align-self will overrides the align-items specified by the Flex container.
+ * The two attributes have the same range of values.
+ */
+ enum WXCoreAlignSelf {
+ kAlignSelfAuto = -1,
+ kAlignSelfFlexStart = kAlignItemsFlexStart,
+ kAlignSelfCenter = kAlignItemsCenter,
+ kAlignSelfFlexEnd = kAlignItemsFlexEnd,
+ kAlignSelfStretch = kAlignItemsStretch,
+ };
+
+ enum WXCorePositionType {
+ kRelative,
+ kAbsolute,
+ kFixed,
+ kSticky = kRelative
+ };
+
+ enum WXCorePositionEdge {
+ kPositionEdgeTop,
+ kPositionEdgeBottom,
+ kPositionEdgeLeft,
+ kPositionEdgeRight,
+ };
+
+ enum WXCoreMarginEdge {
+ kMarginALL,
+ kMarginTop,
+ kMarginBottom,
+ kMarginLeft,
+ kMarginRight,
+ };
+
+ enum WXCorePaddingEdge {
+ kPaddingALL,
+ kPaddingTop,
+ kPaddingBottom,
+ kPaddingLeft,
+ kPaddingRight,
+ };
+
+ enum WXCoreBorderWidthEdge {
+ kBorderWidthALL,
+ kBorderWidthTop,
+ kBorderWidthBottom,
+ kBorderWidthLeft,
+ kBorderWidthRight,
+ };
+
+ enum WXCoreEdge{
+ kTop,
+ kRight,
+ kBottom,
+ kLeft,
+ };
+
+}
+#endif //WEEXCORE_FLEXLAYOUT_WXCOREFLEXENUM_H
+#endif
\ No newline at end of file