1/** 2 * Copyright (c) 2015-present, Horcrux. 3 * All rights reserved. 4 * 5 * This source code is licensed under the MIT-style license found in the 6 * LICENSE file in the root directory of this source tree. 7 */ 8 9#import "RNSVGViewBox.h" 10#import <math.h> 11#import "RNSVGUse.h" 12 13@implementation RNSVGViewBox 14 15+ (CGAffineTransform)getTransform:(CGRect)vbRect 16 eRect:(CGRect)eRect 17 align:(NSString *)align 18 meetOrSlice:(RNSVGVBMOS)meetOrSlice 19{ 20 // based on https://svgwg.org/svg2-draft/coords.html#ComputingAViewportsTransform 21 22 // Let vb-x, vb-y, vb-width, vb-height be the min-x, min-y, width and height values of the viewBox attribute 23 // respectively. 24 CGFloat vbX = CGRectGetMinX(vbRect); 25 CGFloat vbY = CGRectGetMinY(vbRect); 26 CGFloat vbWidth = CGRectGetWidth(vbRect); 27 CGFloat vbHeight = CGRectGetHeight(vbRect); 28 29 // Let e-x, e-y, e-width, e-height be the position and size of the element respectively. 30 CGFloat eX = CGRectGetMinX(eRect); 31 CGFloat eY = CGRectGetMinY(eRect); 32 CGFloat eWidth = CGRectGetWidth(eRect); 33 CGFloat eHeight = CGRectGetHeight(eRect); 34 35 // Let align be the align value of preserveAspectRatio, or 'xMidyMid' if preserveAspectRatio is not defined. 36 37 // Let meetOrSlice be the meetOrSlice value of preserveAspectRatio, or 'meet' if preserveAspectRatio is not defined or 38 // if meetOrSlice is missing from this value. 39 40 // Initialize scale-x to e-width/vb-width. 41 CGFloat scaleX = eWidth / vbWidth; 42 43 // Initialize scale-y to e-height/vb-height. 44 CGFloat scaleY = eHeight / vbHeight; 45 46 // Initialize translate-x to e-x - (vb-x * scale-x). 47 // Initialize translate-y to e-y - (vb-y * scale-y). 48 CGFloat translateX = eX - (vbX * scaleX); 49 CGFloat translateY = eY - (vbY * scaleY); 50 51 // If align is 'none' 52 if (meetOrSlice == kRNSVGVBMOSNone) { 53 // Let scale be set the smaller value of scale-x and scale-y. 54 // Assign scale-x and scale-y to scale. 55 CGFloat scale = scaleX = scaleY = fmin(scaleX, scaleY); 56 57 // If scale is greater than 1 58 if (scale > 1) { 59 // Minus translateX by (eWidth / scale - vbWidth) / 2 60 // Minus translateY by (eHeight / scale - vbHeight) / 2 61 translateX -= (eWidth / scale - vbWidth) / 2; 62 translateY -= (eHeight / scale - vbHeight) / 2; 63 } else { 64 translateX -= (eWidth - vbWidth * scale) / 2; 65 translateY -= (eHeight - vbHeight * scale) / 2; 66 } 67 } else { 68 // If align is not 'none' and meetOrSlice is 'meet', set the larger of scale-x and scale-y to the smaller. 69 // Otherwise, if align is not 'none' and meetOrSlice is 'slice', set the smaller of scale-x and scale-y to the 70 // larger. 71 if (![align isEqualToString:@"none"] && meetOrSlice == kRNSVGVBMOSMeet) { 72 scaleX = scaleY = fmin(scaleX, scaleY); 73 } else if (![align isEqualToString:@"none"] && meetOrSlice == kRNSVGVBMOSSlice) { 74 scaleX = scaleY = fmax(scaleX, scaleY); 75 } 76 77 // If align contains 'xMid', add (e-width - vb-width * scale-x) / 2 to translate-x. 78 if ([align containsString:@"xMid"]) { 79 translateX += (eWidth - vbWidth * scaleX) / 2.0; 80 } 81 82 // If align contains 'xMax', add (e-width - vb-width * scale-x) to translate-x. 83 if ([align containsString:@"xMax"]) { 84 translateX += (eWidth - vbWidth * scaleX); 85 } 86 87 // If align contains 'yMid', add (e-height - vb-height * scale-y) / 2 to translate-y. 88 if ([align containsString:@"YMid"]) { 89 translateY += (eHeight - vbHeight * scaleY) / 2.0; 90 } 91 92 // If align contains 'yMax', add (e-height - vb-height * scale-y) to translate-y. 93 if ([align containsString:@"YMax"]) { 94 translateY += (eHeight - vbHeight * scaleY); 95 } 96 } 97 98 // The transform applied to content contained by the element is given by 99 // translate(translate-x, translate-y) scale(scale-x, scale-y). 100 CGAffineTransform transform = CGAffineTransformMakeTranslation(translateX, translateY); 101 return CGAffineTransformScale(transform, scaleX, scaleY); 102} 103 104@end 105