/* Tencent is pleased to support the open source community by making Hippy * available. Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights * reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "HPLayoutCache.h" #include "HPUtil.h" #ifdef __DEBUG__ #include #include #endif HPLayoutCache::HPLayoutCache() { initCache(); } HPLayoutCache::~HPLayoutCache() {} void HPLayoutCache::cacheResult(HPSize availableSize, HPSize resultSize, HPSizeMode measureMode, FlexLayoutAction layoutAction) { if (layoutAction == LayoutActionLayout) { cachedLayout.availableSize = availableSize; cachedLayout.widthMeasureMode = measureMode.widthMeasureMode; cachedLayout.heightMeasureMode = measureMode.heightMeasureMode; cachedLayout.resultSize = resultSize; cachedLayout.layoutAction = layoutAction; } else { cachedMeasures[nextMeasureIndex].availableSize = availableSize; cachedMeasures[nextMeasureIndex].widthMeasureMode = measureMode.widthMeasureMode; cachedMeasures[nextMeasureIndex].heightMeasureMode = measureMode.heightMeasureMode; cachedMeasures[nextMeasureIndex].resultSize = resultSize; cachedMeasures[nextMeasureIndex].layoutAction = layoutAction; nextMeasureIndex = (nextMeasureIndex + 1) % MAX_MEASURES_COUNT; } } static inline bool SizeIsExactAndMatchesOldMeasuredSize(MeasureMode sizeMode, float size, float lastResultSize) { return sizeMode == MeasureModeExactly && FloatIsEqual(size, lastResultSize); } static inline bool OldSizeIsUndefinedAndStillFits(MeasureMode sizeMode, float size, MeasureMode lastSizeMode, float lastResultSize) { return sizeMode == MeasureModeAtMost && lastSizeMode == MeasureModeUndefined && (size >= lastResultSize || FloatIsEqual(size, lastResultSize)); } static inline bool NewMeasureSizeIsStricterAndStillValid(MeasureMode sizeMode, float size, MeasureMode lastSizeMode, float lastSize, float lastResultSize) { return lastSizeMode == MeasureModeAtMost && sizeMode == MeasureModeAtMost && lastSize > size && (lastResultSize <= size || FloatIsEqual(size, lastResultSize)); } MeasureResult* HPLayoutCache::useMeasureCacheIfPossible(HPSize availableSize, HPSizeMode measureMode, FlexLayoutAction layoutAction, bool isMeasureNode) { if (nextMeasureIndex <= 0) { return nullptr; } for (uint32_t i = 0; i < nextMeasureIndex; i++) { MeasureResult& cacheMeasure = cachedMeasures[i]; if (layoutAction != cacheMeasure.layoutAction && !isMeasureNode) { continue; } bool widthCanUse = false; widthCanUse = cacheMeasure.widthMeasureMode == measureMode.widthMeasureMode && FloatIsEqual(cacheMeasure.availableSize.width, availableSize.width); if (isMeasureNode) { if (!widthCanUse) { widthCanUse = SizeIsExactAndMatchesOldMeasuredSize( measureMode.widthMeasureMode, availableSize.width, cacheMeasure.resultSize.width); } if (!widthCanUse) { widthCanUse = OldSizeIsUndefinedAndStillFits( measureMode.widthMeasureMode, availableSize.width, cacheMeasure.widthMeasureMode, cacheMeasure.resultSize.width); } if (!widthCanUse) { widthCanUse = NewMeasureSizeIsStricterAndStillValid( measureMode.widthMeasureMode, availableSize.width, cacheMeasure.widthMeasureMode, cacheMeasure.availableSize.width, cacheMeasure.resultSize.width); } } bool heightCanUse = false; heightCanUse = cacheMeasure.heightMeasureMode == measureMode.heightMeasureMode && FloatIsEqual(cacheMeasure.availableSize.height, availableSize.height); if (isMeasureNode) { if (!heightCanUse) { heightCanUse = SizeIsExactAndMatchesOldMeasuredSize( measureMode.heightMeasureMode, availableSize.height, cacheMeasure.resultSize.height); } if (!heightCanUse) { heightCanUse = OldSizeIsUndefinedAndStillFits( measureMode.heightMeasureMode, availableSize.height, cacheMeasure.heightMeasureMode, cacheMeasure.resultSize.height); } if (!heightCanUse) { heightCanUse = NewMeasureSizeIsStricterAndStillValid( measureMode.heightMeasureMode, availableSize.height, cacheMeasure.heightMeasureMode, cacheMeasure.availableSize.height, cacheMeasure.resultSize.height); } } if (widthCanUse && heightCanUse) { #ifdef __DEBUG__ HPLogd("cache: action:%d\n", cacheMeasure.layoutAction); #endif return &cacheMeasure; } } return nullptr; } MeasureResult* HPLayoutCache::useLayoutCacheIfPossible(HPSize availableSize, HPSizeMode measureMode) { if (isUndefined(cachedLayout.availableSize.width) || isUndefined(cachedLayout.availableSize.height)) { return nullptr; } if (HPSizeIsEqual(cachedLayout.availableSize, availableSize) && cachedLayout.widthMeasureMode == measureMode.widthMeasureMode && cachedLayout.heightMeasureMode == measureMode.heightMeasureMode) { #ifdef __DEBUG__ HPLogd("cache: action:%d\n", LayoutActionLayout); #endif return &cachedLayout; } return nullptr; } MeasureResult* HPLayoutCache::getCachedMeasureResult(HPSize availableSize, HPSizeMode measureMode, FlexLayoutAction layoutAction, bool isMeasureNode) { if (isMeasureNode) { MeasureResult* result = useLayoutCacheIfPossible(availableSize, measureMode); if (result != nullptr) { return result; } return useMeasureCacheIfPossible(availableSize, measureMode, layoutAction, isMeasureNode); } else if (layoutAction == LayoutActionLayout) { return useLayoutCacheIfPossible(availableSize, measureMode); } else { return useMeasureCacheIfPossible(availableSize, measureMode, layoutAction, isMeasureNode); } return nullptr; } MeasureResult* HPLayoutCache::getCachedLayout() { return &cachedLayout; } void HPLayoutCache::initCache() { cachedLayout.availableSize = {VALUE_UNDEFINED, VALUE_UNDEFINED}; cachedLayout.resultSize = {VALUE_UNDEFINED, VALUE_UNDEFINED}; cachedLayout.widthMeasureMode = MeasureModeUndefined; cachedLayout.heightMeasureMode = MeasureModeUndefined; for (uint32_t i = 0; i < MAX_MEASURES_COUNT; i++) { cachedMeasures[i].availableSize = {VALUE_UNDEFINED, VALUE_UNDEFINED}; cachedMeasures[i].resultSize = {VALUE_UNDEFINED, VALUE_UNDEFINED}; cachedMeasures[i].widthMeasureMode = MeasureModeUndefined; cachedMeasures[i].heightMeasureMode = MeasureModeUndefined; } nextMeasureIndex = 0; } void HPLayoutCache::clearCache() { initCache(); }