* Copyright (c) 2024 Huawei Device Co., Ltd.
* 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 "movingphoto_layout_algorithm.h"
#include "movingphoto_pattern.h"
namespace OHOS::Ace::NG {
namespace {
constexpr int32_t ROUND_XMAGE_MODE_VALUE = 0;
constexpr int32_t ROUND_XMAGE_PIXEL_GAP = 2;
}
void MovingPhotoLayoutAlgorithm::Layout(LayoutWrapper* layoutWrapper)
{
BoxLayoutAlgorithm::PerformLayout(layoutWrapper);
auto contentOffset = layoutWrapper->GetGeometryNode()->GetContentOffset();
auto host = layoutWrapper->GetHostNode();
CHECK_NULL_VOID(host);
auto pattern = DynamicCast<MovingPhotoPattern>(host->GetPattern());
CHECK_NULL_VOID(pattern);
SizeF xmageOffset = GetXmageLayoutOffset(layoutWrapper);
for (auto&& child : layoutWrapper->GetAllChildrenWithBuild()) {
CHECK_NULL_VOID(child);
if (child->GetHostTag() == V2::IMAGE_ETS_TAG) {
child->GetGeometryNode()->SetMarginFrameOffset({ contentOffset.GetX(), contentOffset.GetY() });
} else if (child->GetHostTag() == V2::COLUMN_ETS_TAG) {
child->GetGeometryNode()->SetMarginFrameOffset(
{ contentOffset.GetX() + xmageOffset.Width(), contentOffset.GetY() + xmageOffset.Height() });
}
child->Layout();
if (child->GetHostTag() != V2::COLUMN_ETS_TAG) {
continue;
}
int32_t childCount = host->GetTotalChildCount();
CHECK_NULL_VOID(childCount >= 1);
auto childLayoutWrapper = host->GetChildByIndex(childCount - 1);
for (auto&& videoChild : childLayoutWrapper->GetAllChildrenWithBuild()) {
if (videoChild->GetHostTag() == V2::COLUMN_ETS_TAG) {
videoChild->GetGeometryNode()->SetMarginFrameOffset({ contentOffset.GetX(), contentOffset.GetY() });
}
videoChild->Layout();
}
}
}
void MovingPhotoLayoutAlgorithm::Measure(LayoutWrapper* layoutWrapper)
{
auto layoutConstraint = layoutWrapper->GetLayoutProperty()->CreateChildConstraint();
auto contentSize = layoutWrapper->GetGeometryNode()->GetContentSize();
auto host = layoutWrapper->GetHostNode();
CHECK_NULL_VOID(host);
auto pattern = DynamicCast<MovingPhotoPattern>(host->GetPattern());
CHECK_NULL_VOID(pattern);
pattern->SetXmagePosition();
if (pattern->GetXmageModeStatus() && pattern->GetXmageModeValue() != ROUND_XMAGE_MODE_VALUE) {
MeasureInXmageMode(layoutWrapper);
return;
}
for (auto&& child : layoutWrapper->GetAllChildrenWithBuild()) {
CHECK_NULL_VOID(child);
if (child->GetHostTag() == V2::IMAGE_ETS_TAG) {
auto layoutConstraintForImage = layoutConstraint;
layoutConstraintForImage.UpdateSelfMarginSizeWithCheck(OptionalSizeF(contentSize));
layoutConstraintForImage.UpdateMaxSizeWithCheck(contentSize);
layoutConstraintForImage.UpdateMinSizeWithCheck(contentSize);
child->Measure(layoutConstraintForImage);
} else if (child->GetHostTag() == V2::COLUMN_ETS_TAG) {
auto layoutConstraintForColumn = layoutConstraint;
layoutConstraintForColumn.UpdateSelfMarginSizeWithCheck(OptionalSizeF(contentSize));
layoutConstraintForColumn.UpdateMaxSizeWithCheck(contentSize);
layoutConstraintForColumn.UpdateMinSizeWithCheck(contentSize);
child->Measure(layoutConstraintForColumn);
int32_t childCount = host->GetTotalChildCount();
CHECK_NULL_VOID(childCount >= 1);
auto childLayoutWrapper = host->GetChildByIndex(childCount - 1);
CHECK_NULL_VOID(childLayoutWrapper);
ChildMeasure(childLayoutWrapper, contentSize, layoutConstraint);
if (childLayoutWrapper) {
PerformMeasureSelf(&*childLayoutWrapper);
}
}
}
PerformMeasureSelf(layoutWrapper);
}
void MovingPhotoLayoutAlgorithm::ChildMeasure(RefPtr<LayoutWrapper> childLayoutWrapper,
SizeF contentSize, LayoutConstraintF layoutConstraint)
{
for (auto&& columnChild : childLayoutWrapper->GetAllChildrenWithBuild()) {
if (columnChild->GetHostTag() == V2::COLUMN_ETS_TAG) {
auto layoutConstraintForVideo = layoutConstraint;
layoutConstraintForVideo.UpdateSelfMarginSizeWithCheck(OptionalSizeF(contentSize));
layoutConstraintForVideo.UpdateMaxSizeWithCheck(contentSize);
layoutConstraintForVideo.UpdateMinSizeWithCheck(contentSize);
columnChild->Measure(layoutConstraintForVideo);
}
}
}
void MovingPhotoLayoutAlgorithm::MeasureInXmageMode(LayoutWrapper* layoutWrapper)
{
CHECK_NULL_VOID(layoutWrapper->GetLayoutProperty());
auto layoutConstraint = layoutWrapper->GetLayoutProperty()->CreateChildConstraint();
auto contentSize = layoutWrapper->GetGeometryNode()->GetContentSize();
auto layoutProperty = DynamicCast<MovingPhotoLayoutProperty>(layoutWrapper->GetLayoutProperty());
CHECK_NULL_VOID(layoutProperty);
auto host = layoutWrapper->GetHostNode();
CHECK_NULL_VOID(host);
auto pattern = DynamicCast<MovingPhotoPattern>(host->GetPattern());
CHECK_NULL_VOID(pattern);
for (auto&& child : layoutWrapper->GetAllChildrenWithBuild()) {
CHECK_NULL_VOID(child);
if (child->GetHostTag() == V2::IMAGE_ETS_TAG) {
auto layoutConstraintForImage = layoutConstraint;
layoutConstraintForImage.UpdateSelfMarginSizeWithCheck(OptionalSizeF(contentSize));
layoutConstraintForImage.UpdateMaxSizeWithCheck(contentSize);
layoutConstraintForImage.UpdateMinSizeWithCheck(contentSize);
child->Measure(layoutConstraintForImage);
} else if (child->GetHostTag() == V2::COLUMN_ETS_TAG) {
auto layoutConstraintForColumn = layoutConstraint;
auto columnSize = contentSize;
SizeF xmageOffsetRatio = pattern->CalculateXmageOffsetRatio(contentSize);
SizeF imageSize = layoutProperty->HasImageSize() ? layoutProperty->GetImageSize().value() : SizeF(0, 0);
columnSize.SetHeight(imageSize.Height() * xmageOffsetRatio.Height() + ROUND_XMAGE_PIXEL_GAP);
columnSize.SetWidth(imageSize.Width() * xmageOffsetRatio.Width() + ROUND_XMAGE_PIXEL_GAP);
layoutConstraintForColumn.UpdateSelfMarginSizeWithCheck(OptionalSizeF(columnSize));
layoutConstraintForColumn.UpdateMaxSizeWithCheck(columnSize);
layoutConstraintForColumn.UpdateMinSizeWithCheck(columnSize);
child->Measure(layoutConstraintForColumn);
int32_t childCount = host->GetTotalChildCount();
CHECK_NULL_VOID(childCount >= 1);
auto childLayoutWrapper = host->GetChildByIndex(childCount - 1);
CHECK_NULL_VOID(childLayoutWrapper);
ChildMeasureInXmage(childLayoutWrapper, contentSize, imageSize, xmageOffsetRatio, layoutConstraint);
if (childLayoutWrapper) {
PerformMeasureSelf(&*childLayoutWrapper);
}
}
}
PerformMeasureSelf(layoutWrapper);
}
void MovingPhotoLayoutAlgorithm::ChildMeasureInXmage(RefPtr<LayoutWrapper> childLayoutWrapper, SizeF contentSize,
SizeF imageSize, SizeF xmageRatio, LayoutConstraintF layoutConstraint)
{
for (auto&& columnChild : childLayoutWrapper->GetAllChildrenWithBuild()) {
CHECK_NULL_VOID(columnChild);
if (columnChild->GetHostTag() == V2::COLUMN_ETS_TAG) {
auto layoutConstraintForVideo = layoutConstraint;
auto videoSize = contentSize;
videoSize.SetHeight(imageSize.Height() * xmageRatio.Height() + ROUND_XMAGE_PIXEL_GAP);
videoSize.SetWidth(imageSize.Width() * xmageRatio.Width() + ROUND_XMAGE_PIXEL_GAP);
layoutConstraintForVideo.UpdateSelfMarginSizeWithCheck(OptionalSizeF(videoSize));
layoutConstraintForVideo.UpdateMaxSizeWithCheck(videoSize);
layoutConstraintForVideo.UpdateMinSizeWithCheck(videoSize);
columnChild->Measure(layoutConstraintForVideo);
}
}
}
std::optional<SizeF> MovingPhotoLayoutAlgorithm::MeasureContent(
const LayoutConstraintF& contentConstraint, LayoutWrapper* layoutWrapper)
{
auto layoutSize = contentConstraint.selfIdealSize.IsValid() ? contentConstraint.selfIdealSize.ConvertToSizeT()
: contentConstraint.maxSize;
return layoutSize;
}
SizeF MovingPhotoLayoutAlgorithm::GetXmageLayoutOffset(LayoutWrapper* layoutWrapper)
{
SizeF ret = SizeF(0, 0);
auto host = layoutWrapper->GetHostNode();
CHECK_NULL_RETURN(host, ret);
auto pattern = DynamicCast<MovingPhotoPattern>(host->GetPattern());
CHECK_NULL_RETURN(pattern, ret);
if (pattern->GetXmageModeStatus() && (pattern->GetXmageModeValue() != ROUND_XMAGE_MODE_VALUE)) {
auto contentSize = layoutWrapper->GetGeometryNode()->GetContentSize();
auto layoutProperty = DynamicCast<MovingPhotoLayoutProperty>(layoutWrapper->GetLayoutProperty());
CHECK_NULL_RETURN(layoutProperty, ret);
if (!layoutProperty->HasXmageOffset()) {
return ret;
}
SizeF xmageOffset = layoutProperty->HasXmageOffset() ? layoutProperty->GetXmageOffset().value() : SizeF(0, 0);
SizeF xmageOffsetRatio = pattern->CalculateXmageOffsetRatio(contentSize);
ret = SizeF(xmageOffset.Width() * xmageOffsetRatio.Width() - 1,
xmageOffset.Height() * xmageOffsetRatio.Height() - 1);
}
return ret;
}
}