New file |
| | |
| | | // |
| | | // YYTextDebugOption.m |
| | | // YYText <https://github.com/ibireme/YYText> |
| | | // |
| | | // Created by ibireme on 15/4/8. |
| | | // Copyright (c) 2015 ibireme. |
| | | // |
| | | // This source code is licensed under the MIT-style license found in the |
| | | // LICENSE file in the root directory of this source tree. |
| | | // |
| | | |
| | | #import "YYTextDebugOption.h" |
| | | #import "YYTextWeakProxy.h" |
| | | #import <libkern/OSAtomic.h> |
| | | #import <pthread.h> |
| | | |
| | | static pthread_mutex_t _sharedDebugLock; |
| | | static CFMutableSetRef _sharedDebugTargets = nil; |
| | | static YYTextDebugOption *_sharedDebugOption = nil; |
| | | |
| | | static const void* _sharedDebugSetRetain(CFAllocatorRef allocator, const void *value) { |
| | | return value; |
| | | } |
| | | |
| | | static void _sharedDebugSetRelease(CFAllocatorRef allocator, const void *value) { |
| | | } |
| | | |
| | | void _sharedDebugSetFunction(const void *value, void *context) { |
| | | id<YYTextDebugTarget> target = (__bridge id<YYTextDebugTarget>)(value); |
| | | [target setDebugOption:_sharedDebugOption]; |
| | | } |
| | | |
| | | static void _initSharedDebug() { |
| | | static dispatch_once_t onceToken; |
| | | dispatch_once(&onceToken, ^{ |
| | | pthread_mutex_init(&_sharedDebugLock, NULL); |
| | | CFSetCallBacks callbacks = kCFTypeSetCallBacks; |
| | | callbacks.retain = _sharedDebugSetRetain; |
| | | callbacks.release = _sharedDebugSetRelease; |
| | | _sharedDebugTargets = CFSetCreateMutable(CFAllocatorGetDefault(), 0, &callbacks); |
| | | }); |
| | | } |
| | | |
| | | static void _setSharedDebugOption(YYTextDebugOption *option) { |
| | | _initSharedDebug(); |
| | | pthread_mutex_lock(&_sharedDebugLock); |
| | | _sharedDebugOption = option.copy; |
| | | CFSetApplyFunction(_sharedDebugTargets, _sharedDebugSetFunction, NULL); |
| | | pthread_mutex_unlock(&_sharedDebugLock); |
| | | } |
| | | |
| | | static YYTextDebugOption *_getSharedDebugOption() { |
| | | _initSharedDebug(); |
| | | pthread_mutex_lock(&_sharedDebugLock); |
| | | YYTextDebugOption *op = _sharedDebugOption; |
| | | pthread_mutex_unlock(&_sharedDebugLock); |
| | | return op; |
| | | } |
| | | |
| | | static void _addDebugTarget(id<YYTextDebugTarget> target) { |
| | | _initSharedDebug(); |
| | | pthread_mutex_lock(&_sharedDebugLock); |
| | | CFSetAddValue(_sharedDebugTargets, (__bridge const void *)(target)); |
| | | pthread_mutex_unlock(&_sharedDebugLock); |
| | | } |
| | | |
| | | static void _removeDebugTarget(id<YYTextDebugTarget> target) { |
| | | _initSharedDebug(); |
| | | pthread_mutex_lock(&_sharedDebugLock); |
| | | CFSetRemoveValue(_sharedDebugTargets, (__bridge const void *)(target)); |
| | | pthread_mutex_unlock(&_sharedDebugLock); |
| | | } |
| | | |
| | | |
| | | @implementation YYTextDebugOption |
| | | |
| | | - (id)copyWithZone:(NSZone *)zone { |
| | | YYTextDebugOption *op = [self.class new]; |
| | | op.baselineColor = self.baselineColor; |
| | | op.CTFrameBorderColor = self.CTFrameBorderColor; |
| | | op.CTFrameFillColor = self.CTFrameFillColor; |
| | | op.CTLineBorderColor = self.CTLineBorderColor; |
| | | op.CTLineFillColor = self.CTLineFillColor; |
| | | op.CTLineNumberColor = self.CTLineNumberColor; |
| | | op.CTRunBorderColor = self.CTRunBorderColor; |
| | | op.CTRunFillColor = self.CTRunFillColor; |
| | | op.CTRunNumberColor = self.CTRunNumberColor; |
| | | op.CGGlyphBorderColor = self.CGGlyphBorderColor; |
| | | op.CGGlyphFillColor = self.CGGlyphFillColor; |
| | | return op; |
| | | } |
| | | |
| | | - (BOOL)needDrawDebug { |
| | | if (self.baselineColor || |
| | | self.CTFrameBorderColor || |
| | | self.CTFrameFillColor || |
| | | self.CTLineBorderColor || |
| | | self.CTLineFillColor || |
| | | self.CTLineNumberColor || |
| | | self.CTRunBorderColor || |
| | | self.CTRunFillColor || |
| | | self.CTRunNumberColor || |
| | | self.CGGlyphBorderColor || |
| | | self.CGGlyphFillColor) return YES; |
| | | return NO; |
| | | } |
| | | |
| | | - (void)clear { |
| | | self.baselineColor = nil; |
| | | self.CTFrameBorderColor = nil; |
| | | self.CTFrameFillColor = nil; |
| | | self.CTLineBorderColor = nil; |
| | | self.CTLineFillColor = nil; |
| | | self.CTLineNumberColor = nil; |
| | | self.CTRunBorderColor = nil; |
| | | self.CTRunFillColor = nil; |
| | | self.CTRunNumberColor = nil; |
| | | self.CGGlyphBorderColor = nil; |
| | | self.CGGlyphFillColor = nil; |
| | | } |
| | | |
| | | + (void)addDebugTarget:(id<YYTextDebugTarget>)target { |
| | | if (target) _addDebugTarget(target); |
| | | } |
| | | |
| | | + (void)removeDebugTarget:(id<YYTextDebugTarget>)target { |
| | | if (target) _removeDebugTarget(target); |
| | | } |
| | | |
| | | + (YYTextDebugOption *)sharedDebugOption { |
| | | return _getSharedDebugOption(); |
| | | } |
| | | |
| | | + (void)setSharedDebugOption:(YYTextDebugOption *)option { |
| | | NSAssert([NSThread isMainThread], @"This method must be called on the main thread"); |
| | | _setSharedDebugOption(option); |
| | | } |
| | | |
| | | @end |
| | | |