ComponentTextKit/Utility/CKHighlightOverlayLayer.mm (89 lines of code) (raw):
/*
* Copyright (c) 2014-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
#import "CKHighlightOverlayLayer.h"
#import <ComponentKit/CKInternalHelpers.h>
static const CGFloat kCornerRadius = 2.5;
static const UIEdgeInsets padding = {2, 4, 1.5, 4};
@implementation CKHighlightOverlayLayer
{
NSArray *_rects;
}
+ (id)defaultValueForKey:(NSString *)key
{
if ([key isEqualToString:@"contentsScale"]) {
return [NSNumber numberWithFloat:CKScreenScale()];
} else if ([key isEqualToString:@"highlightColor"]) {
CGFloat components[] = {0, 0, 0, 0.25};
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGColorRef color = CGColorCreate(colorSpace, components);
CGColorSpaceRelease(colorSpace);
return CFBridgingRelease(color);
} else {
return [super defaultValueForKey:key];
}
}
+ (BOOL)needsDisplayForKey:(NSString *)key
{
if ([key isEqualToString:@"bounds"]) {
return YES;
} else {
return [super needsDisplayForKey:key];
}
}
- (id)initWithRects:(NSArray *)rects
{
return [self initWithRects:rects targetLayer:nil];
}
- (id)initWithRects:(NSArray *)rects targetLayer:(id)targetLayer
{
if (self = [super init]) {
_rects = [rects copy];
_targetLayer = targetLayer;
}
return self;
}
@dynamic highlightColor;
- (void)drawInContext:(CGContextRef)ctx
{
[super drawInContext:ctx];
CGAffineTransform affine = CGAffineTransformIdentity;
CGMutablePathRef highlightPath = CGPathCreateMutable();
CALayer *targetLayer = self.targetLayer;
for (NSValue *value in _rects) {
CGRect rect = [value CGRectValue];
if (targetLayer != nil) {
rect = [self convertRect:rect fromLayer:targetLayer];
}
rect = CGRectMake(roundf(rect.origin.x), roundf(rect.origin.y), roundf(rect.size.width), roundf(rect.size.height));
CGFloat minX = rect.origin.x - padding.left;
CGFloat maxX = CGRectGetMaxX(rect) + padding.right;
CGFloat midX = (maxX - minX) / 2 + minX;
CGFloat minY = rect.origin.y - padding.top;
CGFloat maxY = CGRectGetMaxY(rect) + padding.bottom;
CGFloat midY = (maxY - minY) / 2 + minY;
CGPathMoveToPoint(highlightPath, &affine, minX, midY);
CGPathAddArcToPoint(highlightPath, &affine, minX, maxY, midX, maxY, kCornerRadius);
CGPathAddArcToPoint(highlightPath, &affine, maxX, maxY, maxX, midY, kCornerRadius);
CGPathAddArcToPoint(highlightPath, &affine, maxX, minY, midX, minY, kCornerRadius);
CGPathAddArcToPoint(highlightPath, &affine, minX, minY, minX, midY, kCornerRadius);
CGPathCloseSubpath(highlightPath);
}
CGContextAddPath(ctx, highlightPath);
CGContextSetFillColorWithColor(ctx, self.highlightColor);
CGContextDrawPath(ctx, kCGPathFill);
CGPathRelease(highlightPath);
}
- (CALayer *)hitTest:(CGPoint)p
{
// Don't handle taps
return nil;
}
@end
@implementation CALayer (CKHighlightOverlayLayerSupport)
// CKHighlightOverlayLayer compatibility
static NSString *kAllowsHighlightDrawingKey = @"allows_highlight_drawing";
- (BOOL)ck_allowsHighlightDrawing
{
return [[self valueForKey:kAllowsHighlightDrawingKey] boolValue];
}
- (void)ck_setAllowsHighlightDrawing:(BOOL)allowsHighlightDrawing
{
[self setValue:@(allowsHighlightDrawing) forKey:kAllowsHighlightDrawingKey];
}
@end