Sanitize results from sizeThatFits:, fix bug where only one of the measure modes is CSSMeasureModeExactly.

Summary: As I've begun to integrate this into the codebase, I've found that sometimes our layouts are affected by bad implementations of sizeThatFits:. For example, in certain configurations of UILabel it won't take clipping into account and return a size that is much larger than the max size we requested. This adds some checks to make sure we never return a size that is larger than the one specified by `_measure`. This also fixes the bug where `CSSMeasureModeExactly` won't be applied if the measure mode for other parameter is node `CSSMeasureModeExactly`.

Reviewed By: emilsjolander

Differential Revision: D4131195

fbshipit-source-id: 4659fd83892a2c149b3b70733b06b19217507bf9
This commit is contained in:
Dustin Shahidehpour
2016-11-07 06:52:16 -08:00
committed by Facebook Github Bot
parent 6165d7a2be
commit 1ffce3edb1

View File

@@ -205,6 +205,7 @@ static CSSSize _measure(
float height,
CSSMeasureMode heightMode)
{
// sizeThatFits: can be expensive. If we can avoid it, lets do it.
if ((widthMode == CSSMeasureModeExactly) && (heightMode == CSSMeasureModeExactly)) {
return (CSSSize) {
.width = width,
@@ -212,18 +213,38 @@ static CSSSize _measure(
};
}
const CGFloat constrainedWidth = (widthMode == CSSMeasureModeUndefined) ? CGFLOAT_MAX : width;
const CGFloat constrainedHeight = (heightMode == CSSMeasureModeUndefined) ? CGFLOAT_MAX: height;
UIView *view = (__bridge UIView*) CSSNodeGetContext(node);
const CGSize sizeThatFits = [view sizeThatFits:(CGSize) {
.width = widthMode == CSSMeasureModeUndefined ? CGFLOAT_MAX : width,
.height = heightMode == CSSMeasureModeUndefined ? CGFLOAT_MAX : height,
.width = constrainedWidth,
.height = constrainedHeight,
}];
return (CSSSize) {
.width = sizeThatFits.width,
.height = sizeThatFits.height,
.width = _sanitizeMeasurement(constrainedWidth, sizeThatFits.width, widthMode),
.height = _sanitizeMeasurement(constrainedHeight, sizeThatFits.height, heightMode),
};
}
static CGFloat _sanitizeMeasurement(
CGFloat constrainedSize,
CGFloat measuredSize,
CSSMeasureMode measureMode)
{
CGFloat result;
if (measureMode == CSSMeasureModeExactly) {
result = constrainedSize;
} else if (measureMode == CSSMeasureModeAtMost) {
result = MIN(constrainedSize, measuredSize);
} else {
result = measuredSize;
}
return result;
}
static void _attachNodesRecursive(UIView *view) {
CSSNodeRef node = [view cssNode];
const BOOL usesFlexbox = [view css_usesFlexbox];