| // Copyright 2019 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #import "ios/chrome/browser/scanner/ui_bundled/preview_overlay_view.h" |
| |
| #import <AVFoundation/AVFoundation.h> |
| |
| #import "ios/chrome/common/ui/util/ui_util.h" |
| #import "ui/base/device_form_factor.h" |
| |
| namespace { |
| |
| // Length of the viewport borders, starting from the corner. |
| const CGFloat kViewportBorderLengthFromCornerIPhone = 25.0; |
| const CGFloat kViewportBorderLengthFromCornerIPad = 30.0; |
| |
| // Opacity of the preview overlay. |
| const CGFloat kPreviewOverlayOpacity = 0.5; |
| |
| // Corner radius of the border around the viewport. |
| const CGFloat kViewportBorderCornerRadius = 2.0; |
| // Line width of the viewport border. |
| const CGFloat kViewportBorderLineWidth = 4.0; |
| // Shadow opacity of the viewport border. |
| const CGFloat kViewportBorderShadowOpacity = 1.0; |
| // Shadow radius of the viewport border. |
| const CGFloat kViewportBorderShadowRadius = 10.0; |
| |
| } // namespace |
| |
| @interface PreviewOverlayView () { |
| // A transparent preview overlay. The overlay is a sublayer of the |
| // PreviewOverlayView's view to keep the opacity of the view's layer 1.0, |
| // otherwise the viewport border would inherit the opacity of the overlay. |
| CALayer* _previewOverlay; |
| // A container for the viewport border to draw a shadow under the border. |
| // Sublayer of PreviewOverlayView's layer. |
| CALayer* _viewportBorderContainer; |
| // The preview viewport border. Sublayer of `_viewportBorderContainer`. |
| CAShapeLayer* _viewportBorder; |
| // The current viewport size. |
| CGSize _viewportSize; |
| } |
| @end |
| |
| @implementation PreviewOverlayView |
| |
| - (instancetype)initWithFrame:(CGRect)frame |
| viewportSize:(CGSize)overlayViewportSize { |
| self = [super initWithFrame:frame]; |
| if (!self) { |
| return nil; |
| } |
| |
| _viewportSize = overlayViewportSize; |
| |
| _previewOverlay = [[CALayer alloc] init]; |
| [_previewOverlay setBackgroundColor:[[UIColor blackColor] CGColor]]; |
| [_previewOverlay setOpacity:kPreviewOverlayOpacity]; |
| [[self layer] addSublayer:_previewOverlay]; |
| |
| _viewportBorderContainer = [[CALayer alloc] init]; |
| [_viewportBorderContainer setShadowColor:[[UIColor blackColor] CGColor]]; |
| [_viewportBorderContainer setShadowOffset:CGSizeZero]; |
| [_viewportBorderContainer setShadowRadius:kViewportBorderShadowRadius]; |
| [_viewportBorderContainer setShadowOpacity:kViewportBorderShadowOpacity]; |
| [_viewportBorderContainer setShouldRasterize:YES]; |
| [_viewportBorderContainer |
| setRasterizationScale:[[UIScreen mainScreen] scale]]; |
| |
| _viewportBorder = [[CAShapeLayer alloc] init]; |
| [_viewportBorder setStrokeColor:[[UIColor whiteColor] CGColor]]; |
| [_viewportBorder setFillColor:nil]; |
| [_viewportBorder setOpacity:1.0]; |
| [_viewportBorder setLineWidth:kViewportBorderLineWidth]; |
| [_viewportBorderContainer addSublayer:_viewportBorder]; |
| |
| [[self layer] addSublayer:_viewportBorderContainer]; |
| return self; |
| } |
| |
| - (void)layoutSubviews { |
| [super layoutSubviews]; |
| CGSize frameSize = self.frame.size; |
| |
| CGFloat viewportWidth = _viewportSize.width; |
| CGFloat viewportHeight = _viewportSize.height; |
| |
| [_previewOverlay |
| setFrame:CGRectMake(0, 0, frameSize.width, frameSize.height)]; |
| [_previewOverlay setMask:[self viewportMaskWithFrameSize:frameSize]]; |
| |
| CGRect borderRect = CGRectMakeCenteredRectInFrame( |
| frameSize, CGSizeMake(viewportWidth + kViewportBorderLineWidth, |
| viewportHeight + kViewportBorderLineWidth)); |
| UIBezierPath* borderPath = |
| [UIBezierPath bezierPathWithRoundedRect:borderRect |
| cornerRadius:kViewportBorderCornerRadius]; |
| |
| [_viewportBorder setPath:[borderPath CGPath]]; |
| [_viewportBorder setMask:[self viewportBorderMaskWithFrameSize:frameSize]]; |
| } |
| |
| #pragma mark - Private |
| |
| // Creates a square mask for the overlay to keep the viewport transparent. |
| - (CAShapeLayer*)viewportMaskWithFrameSize:(CGSize)frameSize { |
| CGRect frameRect = CGRectMake(0, 0, frameSize.width, frameSize.height); |
| CGRect viewportRect = CGRectMakeCenteredRectInFrame(frameSize, _viewportSize); |
| UIBezierPath* maskPath = [UIBezierPath bezierPathWithRect:frameRect]; |
| [maskPath appendPath:[UIBezierPath bezierPathWithRect:viewportRect]]; |
| |
| CAShapeLayer* mask = [[CAShapeLayer alloc] init]; |
| [mask setFillColor:[[UIColor blackColor] CGColor]]; |
| [mask setFillRule:kCAFillRuleEvenOdd]; |
| [mask setFrame:frameRect]; |
| [mask setPath:maskPath.CGPath]; |
| return mask; |
| } |
| |
| // Creates a mask to only draw the corners of the viewport border. |
| - (CAShapeLayer*)viewportBorderMaskWithFrameSize:(CGSize)frameSize { |
| CGFloat viewportBorderCornerLength = |
| (ui::GetDeviceFormFactor() == ui::DEVICE_FORM_FACTOR_TABLET) |
| ? kViewportBorderLengthFromCornerIPad |
| : kViewportBorderLengthFromCornerIPhone; |
| CGRect maskRect = CGRectMakeCenteredRectInFrame( |
| frameSize, |
| CGSizeMake(_viewportSize.width - 2 * viewportBorderCornerLength, |
| _viewportSize.height - 2 * viewportBorderCornerLength)); |
| CGFloat sizeX = maskRect.origin.x; |
| CGFloat sizeY = maskRect.origin.y; |
| CGFloat offsetX = sizeX + maskRect.size.width; |
| CGFloat offsetY = sizeY + maskRect.size.height; |
| |
| UIBezierPath* path = |
| [UIBezierPath bezierPathWithRect:CGRectMake(0, 0, sizeX, sizeY)]; |
| [path appendPath:[UIBezierPath bezierPathWithRect:CGRectMake(0, offsetY, |
| sizeX, sizeY)]]; |
| [path appendPath:[UIBezierPath bezierPathWithRect:CGRectMake(offsetX, 0, |
| sizeX, sizeY)]]; |
| [path appendPath:[UIBezierPath bezierPathWithRect:CGRectMake(offsetX, offsetY, |
| sizeX, sizeY)]]; |
| |
| CAShapeLayer* mask = [[CAShapeLayer alloc] init]; |
| [mask setFillColor:[[UIColor blackColor] CGColor]]; |
| [mask setFrame:CGRectMake(0, 0, frameSize.width, frameSize.height)]; |
| [mask setPath:path.CGPath]; |
| return mask; |
| } |
| |
| @end |