1 /*
2  * Copyright (c) 2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "core/components_ng/pattern/shape/shape_container_pattern.h"
17 
18 #include <algorithm>
19 
20 #include "base/geometry/ng/rect_t.h"
21 #include "base/utils/utils.h"
22 
23 namespace OHOS::Ace::NG {
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,bool skipMeasure,bool skipLayout)24 bool ShapeContainerPattern::OnDirtyLayoutWrapperSwap(
25     const RefPtr<LayoutWrapper>& dirty, bool skipMeasure, bool skipLayout)
26 {
27     if (skipMeasure || dirty->SkipMeasureContent() || isShapeContainerInit_) {
28         return false;
29     }
30     ViewPortTransform();
31     return true;
32 }
33 
ViewPortTransform()34 void ShapeContainerPattern::ViewPortTransform()
35 {
36     auto curFrameNode = GetHost();
37     auto renderContext = curFrameNode->GetRenderContext();
38     auto geoNode = curFrameNode->GetGeometryNode();
39     CHECK_NULL_VOID(geoNode);
40     auto contentSize = geoNode->GetContentSize();
41     auto paintProperty = curFrameNode->GetPaintProperty<ShapeContainerPaintProperty>();
42     if (paintProperty->HasShapeViewBox() && paintProperty->GetShapeViewBoxValue().IsValid()) {
43         double portWidth = paintProperty->GetShapeViewBoxValue().Width().ConvertToPx();
44         double portHeight = paintProperty->GetShapeViewBoxValue().Height().ConvertToPx();
45         double portLeft = paintProperty->GetShapeViewBoxValue().Left().ConvertToPx();
46         double portTop = paintProperty->GetShapeViewBoxValue().Top().ConvertToPx();
47         if (contentSize.IsPositive() && GreatNotEqual(portWidth, 0.0) && GreatNotEqual(portHeight, 0.0)) {
48             double scale = std::min(contentSize.Width() / portWidth, contentSize.Height() / portHeight);
49             double tx = contentSize.Width() * 0.5 - (portWidth * 0.5 + portLeft) * scale;
50             double ty = contentSize.Height() * 0.5 - (portHeight * 0.5 + portTop) * scale;
51             for (const auto& child : curFrameNode->GetChildren()) {
52                 auto node = AceType::DynamicCast<FrameNode>(child);
53                 CHECK_NULL_VOID(node);
54                 auto context = node->GetRenderContext();
55                 CHECK_NULL_VOID(context);
56                 context->UpdateTransformCenter(DimensionOffset(Offset(0.0, 0.0)));
57                 context->OnTransformTranslateUpdate({ tx, ty, 0 });
58                 context->OnTransformScaleUpdate({ scale, scale });
59 
60                 if (context->HasOffset()) {
61                     auto currentOffset = context->GetOffset();
62                     auto newOffset = OffsetT(Dimension(currentOffset->GetX() * scale),
63                         Dimension(currentOffset->GetY() * scale));
64                     context->UpdateOffset(newOffset);
65                     context->OnOffsetUpdate(newOffset);
66                     node->MarkModifyDone();
67                 }
68             }
69         }
70     }
71     isShapeContainerInit_ = true;
72 }
73 
OnModifyDone()74 void ShapeContainerPattern::OnModifyDone()
75 {
76     auto host = GetHost();
77     CHECK_NULL_VOID(host);
78     auto paintProperty = host->GetPaintProperty<ShapeContainerPaintProperty>();
79     CHECK_NULL_VOID(paintProperty);
80     if (paintProperty->HasStrokeMiterLimit()) {
81         auto miterLimit = paintProperty->GetStrokeMiterLimitValue();
82         if (Negative(miterLimit)) {
83             paintProperty->UpdateStrokeMiterLimit(ShapePaintProperty::STROKE_MITERLIMIT_DEFAULT);
84         } else if (NonNegative(miterLimit) &&
85             LessNotEqual(miterLimit, ShapePaintProperty::STROKE_MITERLIMIT_MIN)) {
86             paintProperty->UpdateStrokeMiterLimit(ShapePaintProperty::STROKE_MITERLIMIT_MIN);
87         }
88     }
89 
90     Pattern::OnModifyDone();
91     for (auto childNode : ChildNodes_) {
92         auto child = childNode.Upgrade();
93         if (!child) {
94             continue;
95         }
96         child->MarkNeedRenderOnly();
97     }
98     ChildNodes_.clear();
99 }
100 
OnAttachToFrameNode()101 void ShapeContainerPattern::OnAttachToFrameNode()
102 {
103     auto host = GetHost();
104     CHECK_NULL_VOID(host);
105     host->GetLayoutProperty()->UpdateAlignment(Alignment::TOP_LEFT);
106     host->GetRenderContext()->SetClipToFrame(true);
107 }
108 } // namespace OHOS::Ace::NG
109