1 /*
2 * Copyright (c) 2021-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 "bridge/declarative_frontend/jsview/js_view_stack_processor.h"
17
18 #include "bridge/declarative_frontend/engine/bindings.h"
19 #include "bridge/declarative_frontend/engine/js_execution_scope_defines.h"
20 #include "bridge/declarative_frontend/engine/js_types.h"
21 #include "bridge/declarative_frontend/jsview/models/view_stack_model_impl.h"
22 #include "bridge/declarative_frontend/view_stack_processor.h"
23 #include "core/common/container.h"
24 #include "core/components_ng/base/view_stack_model.h"
25 #include "core/components_ng/base/view_stack_model_ng.h"
26 #include "core/components_ng/base/view_stack_processor.h"
27 #include "foundation/arkui/ace_engine/frameworks/core/common/ace_application_info.h"
28 #include "frameworks/core/common/layout_inspector.h"
29 #include "frameworks/core/pipeline/base/element_register.h"
30
31 namespace OHOS::Ace {
32
GetInstance()33 ViewStackModel* ViewStackModel::GetInstance()
34 {
35 #ifdef NG_BUILD
36 static NG::ViewStackModelNG instance;
37 return &instance;
38 #else
39 if (Container::IsCurrentUseNewPipeline()) {
40 static NG::ViewStackModelNG instance;
41 return &instance;
42 } else {
43 static Framework::ViewStackModelImpl instance;
44 return &instance;
45 }
46 #endif
47 }
48
49 } // namespace OHOS::Ace
50 namespace OHOS::Ace::Framework {
51
JSVisualState(const JSCallbackInfo & info)52 void JSViewStackProcessor::JSVisualState(const JSCallbackInfo& info)
53 {
54 if ((info.Length() < 1) || (!info[0]->IsString())) {
55 ViewStackModel::GetInstance()->ClearVisualState();
56 return;
57 }
58
59 std::string state = info[0]->ToString();
60 VisualState visualState = JSViewStackProcessor::StringToVisualState(state);
61 ViewStackModel::GetInstance()->SetVisualState(visualState);
62 }
63
64 // public static emthods exposed to JS
JSBind(BindingTarget globalObj)65 void JSViewStackProcessor::JSBind(BindingTarget globalObj)
66 {
67 JSClass<JSViewStackProcessor>::Declare("ViewStackProcessor");
68 MethodOptions opt = MethodOptions::NONE;
69
70 JSClass<JSViewStackProcessor>::StaticMethod(
71 "AllocateNewElmetIdForNextComponent", &JSViewStackProcessor::JsAllocateNewElmetIdForNextComponent, opt);
72 JSClass<JSViewStackProcessor>::StaticMethod(
73 "StartGetAccessRecordingFor", &JSViewStackProcessor::JsStartGetAccessRecordingFor, opt);
74 JSClass<JSViewStackProcessor>::StaticMethod(
75 "SetElmtIdToAccountFor", &JSViewStackProcessor::JsSetElmtIdToAccountFor, opt);
76 JSClass<JSViewStackProcessor>::StaticMethod(
77 "GetElmtIdToAccountFor", &JSViewStackProcessor::JsGetElmtIdToAccountFor, opt);
78 JSClass<JSViewStackProcessor>::StaticMethod(
79 "StopGetAccessRecording", &JSViewStackProcessor::JsStopGetAccessRecording, opt);
80 JSClass<JSViewStackProcessor>::StaticMethod(
81 "ImplicitPopBeforeContinue", &JSViewStackProcessor::JsImplicitPopBeforeContinue, opt);
82 JSClass<JSViewStackProcessor>::StaticMethod("visualState", JSVisualState, opt);
83 JSClass<JSViewStackProcessor>::StaticMethod("MakeUniqueId", &JSViewStackProcessor::JSMakeUniqueId, opt);
84 JSClass<JSViewStackProcessor>::StaticMethod("UsesNewPipeline", &JSViewStackProcessor::JsUsesNewPipeline, opt);
85 JSClass<JSViewStackProcessor>::StaticMethod("getApiVersion", &JSViewStackProcessor::JsGetApiVersion, opt);
86 JSClass<JSViewStackProcessor>::StaticMethod("GetAndPushFrameNode", &JSViewStackProcessor::JsGetAndPushFrameNode);
87 JSClass<JSViewStackProcessor>::StaticMethod("moveDeletedElmtIds", &JSViewStackProcessor::JsMoveDeletedElmtIds);
88 JSClass<JSViewStackProcessor>::StaticMethod(
89 "scheduleUpdateOnNextVSync", &JSViewStackProcessor::JSScheduleUpdateOnNextVSync);
90 JSClass<JSViewStackProcessor>::StaticMethod("PushPrebuildCompCmd",
91 &JSViewStackProcessor::JsPushPrebuildCompCmd, opt);
92 JSClass<JSViewStackProcessor>::StaticMethod("CheckIsPrebuildTimeout",
93 &JSViewStackProcessor::JsCheckIsPrebuildTimeout, opt);
94 JSClass<JSViewStackProcessor>::StaticMethod("sendStateInfo", &JSViewStackProcessor::JsSendStateInfo);
95 #ifdef ACE_STATIC
96 JSClass<JSViewStackProcessor>::StaticMethod("push", &JSViewStackProcessor::JsPush, opt);
97 JSClass<JSViewStackProcessor>::StaticMethod("pop", &JSViewStackProcessor::JsPop, opt);
98 #endif
99 JSClass<JSViewStackProcessor>::Bind<>(globalObj);
100 }
101
StringToVisualState(const std::string & stateString)102 VisualState JSViewStackProcessor::StringToVisualState(const std::string& stateString)
103 {
104 if (stateString == "normal") {
105 return VisualState::NORMAL;
106 }
107 if (stateString == "focused") {
108 return VisualState::FOCUSED;
109 }
110 if (stateString == "pressed" || stateString == "clicked") {
111 return VisualState::PRESSED;
112 }
113 if (stateString == "disabled") {
114 return VisualState::DISABLED;
115 }
116 if (stateString == "hover") {
117 return VisualState::HOVER;
118 }
119 if (stateString == "selected") {
120 return VisualState::SELECTED;
121 }
122 LOGE("Unknown visual state \"%{public}s\", resetting to UNDEFINED", stateString.c_str());
123 return VisualState::NOTSET;
124 }
125
JsStartGetAccessRecordingFor(ElementIdType elmtId)126 void JSViewStackProcessor::JsStartGetAccessRecordingFor(ElementIdType elmtId)
127 {
128 ViewStackModel::GetInstance()->StartGetAccessRecordingFor(elmtId);
129 }
130
JsGetElmtIdToAccountFor()131 int32_t JSViewStackProcessor::JsGetElmtIdToAccountFor()
132 {
133 return ViewStackModel::GetInstance()->GetElmtIdToAccountFor();
134 }
135
JsSetElmtIdToAccountFor(ElementIdType elmtId)136 void JSViewStackProcessor::JsSetElmtIdToAccountFor(ElementIdType elmtId)
137 {
138 ViewStackModel::GetInstance()->SetElmtIdToAccountFor(elmtId);
139 }
140
JsStopGetAccessRecording()141 void JSViewStackProcessor::JsStopGetAccessRecording()
142 {
143 return ViewStackModel::GetInstance()->StopGetAccessRecording();
144 }
145
JsImplicitPopBeforeContinue()146 void JSViewStackProcessor::JsImplicitPopBeforeContinue()
147 {
148 ViewStackModel::GetInstance()->ImplicitPopBeforeContinue();
149 }
150
JSMakeUniqueId(const JSCallbackInfo & info)151 void JSViewStackProcessor::JSMakeUniqueId(const JSCallbackInfo& info)
152 {
153 const auto result = ElementRegister::GetInstance()->MakeUniqueId();
154 info.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(result)));
155 }
JsMoveDeletedElmtIds(const JSCallbackInfo & info)156 void JSViewStackProcessor::JsMoveDeletedElmtIds(const JSCallbackInfo& info)
157 {
158 auto jsArrInfo = info[0];
159 if (!jsArrInfo->IsArray()) {
160 return;
161 }
162 JSRef<JSArray> jsArr = JSRef<JSArray>::Cast(jsArrInfo);
163
164 RemovedElementsType removedElements;
165 ElementRegister::GetInstance()->MoveRemovedItems(removedElements);
166 size_t index = jsArr->Length();
167 for (const auto& rmElmtId : removedElements) {
168 jsArr->SetValueAt(index++, JSRef<JSVal>::Make(ToJSValue(rmElmtId)));
169 }
170 }
171
172 // Initiates a frame request to RosenWindow and handles the callback from the Vsync request
JSScheduleUpdateOnNextVSync(const JSCallbackInfo & info)173 void JSViewStackProcessor::JSScheduleUpdateOnNextVSync(const JSCallbackInfo& info)
174 {
175 // Get the correct container
176 int32_t containerId = -1;
177 if (info.Length() > 1 && info[1]->IsNumber()) {
178 containerId = info[1]->ToNumber<int32_t>();
179 } else {
180 LOGE("ERROR: JSScheduleUpdateOnNextVSync() no containerId provided.");
181 return;
182 }
183
184 if (containerId < 0) {
185 LOGE("ERROR: JSScheduleUpdateOnNextVSync() invalid containerId.");
186 return;
187 }
188
189 auto container = Container::GetContainer(containerId);
190 if (!container) {
191 LOGE("JSScheduleUpdateOnNextVSync container is null");
192 return;
193 }
194 auto context = container->GetPipelineContext();
195 if (!context) {
196 LOGE("JSScheduleUpdateOnNextVSync context is null");
197 return;
198 }
199
200 if (info[0]->IsFunction()) {
201 auto flushTSFunc = [execCtx = info.GetExecutionContext(),
202 func = JSRef<JSFunc>::Cast(info[0])](int32_t containerId) -> bool {
203 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, false);
204 JSRef<JSVal> jsId = JSRef<JSVal>::Make(ToJSValue(containerId));
205 JSRef<JSVal> retVal = func->Call(JSRef<JSObject>(), 1, &jsId);
206 if (!retVal->IsBoolean()) {
207 LOGE("JSScheduleUpdateOnNextVSync: flushTSFunc retVal is not boolean.");
208 return false;
209 }
210 return retVal->ToBoolean();
211 };
212 context->SetFlushTSUpdates(std::move(flushTSFunc));
213 } else {
214 context->SetFlushTSUpdates(nullptr);
215 }
216 }
217
JsSendStateInfo(const std::string & stateInfo)218 void JSViewStackProcessor::JsSendStateInfo(const std::string& stateInfo)
219 {
220 #if defined(PREVIEW) || !defined(OHOS_PLATFORM)
221 return;
222 #else
223 if (!LayoutInspector::GetStateProfilerStatus()) {
224 return;
225 }
226 auto container = Container::CurrentSafely();
227 CHECK_NULL_VOID(container);
228 auto pipeline = container->GetPipelineContext();
229 CHECK_NULL_VOID(pipeline);
230 auto info = JsonUtil::ParseJsonString(stateInfo);
231 info->Put("timeStamp", GetCurrentTimestampMicroSecond());
232 info->Put("vsyncID", (int32_t)pipeline->GetFrameCount());
233 info->Put("processID", getpid());
234 info->Put("windowID", (int32_t)pipeline->GetWindowId());
235 TAG_LOGD(AceLogTag::ACE_STATE_MGMT, "ArkUI SendStateInfo %{public}s", info->ToString().c_str());
236 LayoutInspector::SendMessage(info->ToString());
237 #endif
238 }
239
240 /**
241 * return true of current Container uses new Pipeline
242 */
JsUsesNewPipeline()243 bool JSViewStackProcessor::JsUsesNewPipeline()
244 {
245 auto container = Container::Current();
246 return container ? container->IsUseNewPipeline() : AceApplicationInfo::GetInstance().IsUseNewPipeline();
247 }
248
249 /**
250 * return the API version specified in the manifest.json
251 */
JsGetApiVersion()252 int32_t JSViewStackProcessor::JsGetApiVersion()
253 {
254 return AceApplicationInfo::GetInstance().GetApiTargetVersion();
255 }
256
JsGetAndPushFrameNode(const JSCallbackInfo & info)257 void JSViewStackProcessor::JsGetAndPushFrameNode(const JSCallbackInfo& info)
258 {
259 if (info.Length() < 2) {
260 return;
261 }
262 if (!info[0]->IsString() || !info[1]->IsNumber()) {
263 return;
264 }
265 ViewStackModel::GetInstance()->GetAndPushFrameNode(info[0]->ToString(), info[1]->ToNumber<int32_t>());
266 }
267
JsPushPrebuildCompCmd(const JSCallbackInfo & info)268 void JSViewStackProcessor::JsPushPrebuildCompCmd(const JSCallbackInfo& info)
269 {
270 ViewStackModel::GetInstance()->PushPrebuildCompCmd();
271 }
272
JsCheckIsPrebuildTimeout()273 bool JSViewStackProcessor::JsCheckIsPrebuildTimeout()
274 {
275 return ViewStackModel::GetInstance()->CheckIsPrebuildTimeout();
276 }
277
278 #ifdef ACE_STATIC
JsPush(const JSCallbackInfo & info)279 void JSViewStackProcessor::JsPush(const JSCallbackInfo &info)
280 {
281 if (info.Length() < 1) {
282 return;
283 }
284 if (!info[0]->IsNumber()) {
285 return;
286 }
287
288 return ViewStackModel::GetInstance()->PushPtr(info[0]->ToNumber<int64_t>());
289 }
290
JsPop()291 void JSViewStackProcessor::JsPop()
292 {
293 return ViewStackModel::GetInstance()->Pop();
294 }
295 #endif
296 } // namespace OHOS::Ace::Framework
297