RenderCore/Geometry/RCComponentSize.mm (65 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 "RCComponentSize.h" #import <RenderCore/RCAssert.h> #import <RenderCore/RCEqualityHelpers.h> #define RCCAssertConstrainedValue(val) \ RCCAssert(!isnan(val), @"Constrained value must not be NaN.") RCComponentSize RCComponentSize::fromCGSize(CGSize size) noexcept { return {size.width, size.height}; } static inline void CKCSConstrain(CGFloat minVal, CGFloat exactVal, CGFloat maxVal, CGFloat *outMin, CGFloat *outMax) noexcept { RCCAssertConstrainedValue(minVal); RCCAssertConstrainedValue(maxVal); // Avoid use of min/max primitives since they're harder to reason // about in the presence of NaN (in exactVal) // Follow CSS: min overrides max overrides exact. // Begin with the min/max range *outMin = minVal; *outMax = maxVal; if (maxVal <= minVal) { // min overrides max and exactVal is irrelevant *outMax = minVal; return; } if (isnan(exactVal) || isinf(exactVal)) { // no exact value, so leave as a min/max range return; } if (exactVal > maxVal) { // clip to max value *outMin = maxVal; } else if (exactVal < minVal) { // clip to min value *outMax = minVal; } else { // use exact value *outMin = *outMax = exactVal; } } CKSizeRange RCComponentSize::resolve(const CGSize &parentSize) const noexcept { CGSize resolvedExact = RCRelativeSize(width, height).resolveSize(parentSize, {NAN, NAN}); CGSize resolvedMin = RCRelativeSize(minWidth, minHeight).resolveSize(parentSize, {0, 0}); CGSize resolvedMax = RCRelativeSize(maxWidth, maxHeight).resolveSize(parentSize, {INFINITY, INFINITY}); CGSize rangeMin, rangeMax; CKCSConstrain(resolvedMin.width, resolvedExact.width, resolvedMax.width, &rangeMin.width, &rangeMax.width); CKCSConstrain(resolvedMin.height, resolvedExact.height, resolvedMax.height, &rangeMin.height, &rangeMax.height); return {rangeMin, rangeMax}; } bool RCComponentSize::operator==(const RCComponentSize &other) const noexcept { return width == other.width && height == other.height && minWidth == other.minWidth && minHeight == other.minHeight && maxWidth == other.maxWidth && maxHeight == other.maxHeight; } NSString *RCComponentSize::description() const noexcept { return [NSString stringWithFormat: @"<RCComponentSize: exact=%@, min=%@, max=%@>", RCRelativeSize(width, height).description(), RCRelativeSize(minWidth, minHeight).description(), RCRelativeSize(maxWidth, maxHeight).description()]; } size_t std::hash<RCComponentSize>::operator ()(const RCComponentSize &size) noexcept { NSUInteger subhashes[] = { std::hash<RCRelativeDimension>()(size.width), std::hash<RCRelativeDimension>()(size.height), std::hash<RCRelativeDimension>()(size.minWidth), std::hash<RCRelativeDimension>()(size.minHeight), std::hash<RCRelativeDimension>()(size.maxWidth), std::hash<RCRelativeDimension>()(size.maxHeight), }; return RCIntegerArrayHash(subhashes, std::end(subhashes) - std::begin(subhashes)); };