Improve heuristic for cache re-use
This commit is contained in:
87
src/Layout.c
87
src/Layout.c
@@ -1547,35 +1547,80 @@ static const char* getModeName(css_measure_mode_t mode, bool performLayout) {
|
||||
return performLayout? kLayoutModeNames[mode] : kMeasureModeNames[mode];
|
||||
}
|
||||
|
||||
static bool canUseCachedMeasurement(float availableWidth, float availableHeight,
|
||||
float marginRow, float marginColumn,
|
||||
css_measure_mode_t widthMeasureMode, css_measure_mode_t heightMeasureMode,
|
||||
css_cached_measurement_t cachedLayout) {
|
||||
static bool canUseCachedMeasurement(
|
||||
bool is_text_node,
|
||||
float available_width,
|
||||
float available_height,
|
||||
float margin_row,
|
||||
float margin_column,
|
||||
css_measure_mode_t width_measure_mode,
|
||||
css_measure_mode_t height_measure_mode,
|
||||
css_cached_measurement_t cached_layout) {
|
||||
|
||||
// Is it an exact match?
|
||||
if (eq(cachedLayout.available_width, availableWidth) &&
|
||||
eq(cachedLayout.available_height, availableHeight) &&
|
||||
cachedLayout.width_measure_mode == widthMeasureMode &&
|
||||
cachedLayout.height_measure_mode == heightMeasureMode) {
|
||||
bool is_height_same =
|
||||
(cached_layout.height_measure_mode == CSS_MEASURE_MODE_UNDEFINED && height_measure_mode == CSS_MEASURE_MODE_UNDEFINED) ||
|
||||
(cached_layout.height_measure_mode == height_measure_mode && eq(cached_layout.available_height, available_height));
|
||||
|
||||
bool is_width_same =
|
||||
(cached_layout.width_measure_mode == CSS_MEASURE_MODE_UNDEFINED && width_measure_mode == CSS_MEASURE_MODE_UNDEFINED) ||
|
||||
(cached_layout.width_measure_mode == width_measure_mode && eq(cached_layout.available_width, available_width));
|
||||
|
||||
if (is_height_same && is_width_same) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If the width is an exact match, try a fuzzy match on the height.
|
||||
if (cachedLayout.width_measure_mode == widthMeasureMode &&
|
||||
eq(cachedLayout.available_width, availableWidth) &&
|
||||
heightMeasureMode == CSS_MEASURE_MODE_EXACTLY &&
|
||||
eq(availableHeight - marginColumn, cachedLayout.computed_height)) {
|
||||
bool is_height_valid =
|
||||
(cached_layout.height_measure_mode == CSS_MEASURE_MODE_UNDEFINED && height_measure_mode == CSS_MEASURE_MODE_AT_MOST && cached_layout.computed_height <= (available_height - margin_column)) ||
|
||||
(height_measure_mode == CSS_MEASURE_MODE_EXACTLY && eq(cached_layout.computed_height, available_height - margin_column));
|
||||
|
||||
if (is_width_same && is_height_valid) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If the height is an exact match, try a fuzzy match on the width.
|
||||
if (cachedLayout.height_measure_mode == heightMeasureMode &&
|
||||
eq(cachedLayout.available_height, availableHeight) &&
|
||||
widthMeasureMode == CSS_MEASURE_MODE_EXACTLY &&
|
||||
eq(availableWidth - marginRow, cachedLayout.computed_width)) {
|
||||
bool is_width_valid =
|
||||
(cached_layout.width_measure_mode == CSS_MEASURE_MODE_UNDEFINED && width_measure_mode == CSS_MEASURE_MODE_AT_MOST && cached_layout.computed_width <= (available_width - margin_row)) ||
|
||||
(width_measure_mode == CSS_MEASURE_MODE_EXACTLY && eq(cached_layout.computed_width, available_width - margin_row));
|
||||
|
||||
if (is_height_same && is_width_valid) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (is_height_valid && is_width_valid) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// We know this to be text so we can apply some more specialized heuristics.
|
||||
if (is_text_node) {
|
||||
if (is_width_same) {
|
||||
if (height_measure_mode == CSS_MEASURE_MODE_UNDEFINED) {
|
||||
// Width is the same and height is not restricted. Re-use cahced value.
|
||||
return true;
|
||||
}
|
||||
|
||||
if (height_measure_mode == CSS_MEASURE_MODE_AT_MOST &&
|
||||
cached_layout.computed_height < (available_height - margin_column)) {
|
||||
// Width is the same and height restriction is greater than the cached height. Re-use cached value.
|
||||
return true;
|
||||
}
|
||||
|
||||
// Width is the same but height restriction imposes smaller height than previously measured.
|
||||
// Update the cached value to respect the new height restriction.
|
||||
cached_layout.computed_height = available_height - margin_column;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (cached_layout.width_measure_mode == CSS_MEASURE_MODE_UNDEFINED) {
|
||||
if (width_measure_mode == CSS_MEASURE_MODE_UNDEFINED ||
|
||||
(width_measure_mode == CSS_MEASURE_MODE_AT_MOST &&
|
||||
cached_layout.computed_width <= (available_width - margin_row))) {
|
||||
// Previsouly this text was measured with no width restriction, if width is now restricted
|
||||
// but to a larger value than the previsouly measured width we can re-use the measurement
|
||||
// as we know it will fit.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1617,13 +1662,13 @@ bool layoutNodeInternal(css_node_t* node, float availableWidth, float availableH
|
||||
float marginAxisColumn = getMarginAxis(node, CSS_FLEX_DIRECTION_COLUMN);
|
||||
|
||||
// First, try to use the layout cache.
|
||||
if (canUseCachedMeasurement(availableWidth, availableHeight, marginAxisRow, marginAxisColumn,
|
||||
if (canUseCachedMeasurement(node->is_text_node && node->is_text_node(node->context), availableWidth, availableHeight, marginAxisRow, marginAxisColumn,
|
||||
widthMeasureMode, heightMeasureMode, layout->cached_layout)) {
|
||||
cachedResults = &layout->cached_layout;
|
||||
} else {
|
||||
// Try to use the measurement cache.
|
||||
for (int i = 0; i < layout->next_cached_measurements_index; i++) {
|
||||
if (canUseCachedMeasurement(availableWidth, availableHeight, marginAxisRow, marginAxisColumn,
|
||||
if (canUseCachedMeasurement(node->is_text_node && node->is_text_node(node->context), availableWidth, availableHeight, marginAxisRow, marginAxisColumn,
|
||||
widthMeasureMode, heightMeasureMode, layout->cached_measurements[i])) {
|
||||
cachedResults = &layout->cached_measurements[i];
|
||||
break;
|
||||
|
Reference in New Issue
Block a user