• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2023 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 #ifndef FOUNDATION_ACE_FRAMEWORKS_BRIDGE_DECLARATIVE_FRONTEND_JS_VIEW_JS_VIEW_H
17 #define FOUNDATION_ACE_FRAMEWORKS_BRIDGE_DECLARATIVE_FRONTEND_JS_VIEW_JS_VIEW_H
18 
19 #include <functional>
20 #include <list>
21 #include <string>
22 
23 #include "base/log/ace_scoring_log.h"
24 #include "base/memory/ace_type.h"
25 #include "base/memory/referenced.h"
26 #include "core/components_ng/base/view_partial_update_model.h"
27 #include "core/components_ng/syntax/repeat_virtual_scroll_node.h"
28 #include "frameworks/bridge/declarative_frontend/engine/js_ref_ptr.h"
29 #include "frameworks/bridge/declarative_frontend/jsview/js_view_abstract.h"
30 #include "frameworks/bridge/declarative_frontend/jsview/js_view_functions.h"
31 
32 namespace OHOS::Ace::Framework {
33 
34 class JSView : public JSViewAbstract, public virtual AceType {
35     DECLARE_ACE_TYPE(JSView, AceType);
36 
37 public:
JSView()38     JSView() : instanceId_(Container::CurrentId()) {}
39     ~JSView() override = default;
40     virtual void Destroy(JSView* parentCustomView) = 0;
41 
42     virtual RefPtr<AceType> CreateViewNode(bool isTitleNode = false, bool isCustomAppBar = false)
43     {
44         LOGE("Internal error. Not implemented");
45         return nullptr;
46     }
47 
48     void SyncInstanceId();
49     void RestoreInstanceId();
50     void GetInstanceId(const JSCallbackInfo& info);
51     void GetMainInstanceId(const JSCallbackInfo& info);
52 
FireOnShow()53     void FireOnShow()
54     {
55         if (jsViewFunction_) {
56             ACE_SCORING_EVENT("OnShow");
57             jsViewFunction_->ExecuteShow();
58         }
59     }
60 
FireOnHide()61     void FireOnHide()
62     {
63         if (jsViewFunction_) {
64             ACE_SCORING_EVENT("OnHide");
65             jsViewFunction_->ExecuteHide();
66         }
67     }
68 
FireOnBackPress()69     bool FireOnBackPress()
70     {
71         if (jsViewFunction_) {
72             ACE_SCORING_EVENT("OnBackPress");
73             return jsViewFunction_->ExecuteOnBackPress();
74         }
75         return false;
76     }
77 
FireOnFormRecycle()78     std::string FireOnFormRecycle()
79     {
80         if (jsViewFunction_) {
81             ACE_SCORING_EVENT("OnFormRecycle");
82             return jsViewFunction_->ExecuteOnFormRecycle();
83         }
84         LOGE("jsViewFunction_ is null");
85         return "";
86     }
87 
FireOnFormRecover(const std::string & statusData)88     void FireOnFormRecover(const std::string &statusData)
89     {
90         if (jsViewFunction_) {
91             ACE_SCORING_EVENT("OnFormRecover");
92             return jsViewFunction_->ExecuteOnFormRecover(statusData);
93         }
94         LOGE("jsViewFunction_ is null");
95     }
96 
FireOnNewParam(const std::string & newParam)97     void FireOnNewParam(const std::string &newParam)
98     {
99         if (jsViewFunction_) {
100             ACE_SCORING_EVENT("OnNewParam");
101             return jsViewFunction_->ExecuteOnNewParam(newParam);
102         }
103         TAG_LOGE(AceLogTag::ACE_ROUTER, "fire onNewParam failed, jsViewFunction_ is null!");
104     }
105 
106     virtual void RenderJSExecution();
107 
108     virtual void SetPrebuildPhase(PrebuildPhase prebuildPhase, int64_t deadline = 0) {};
109 
110     virtual void MarkNeedUpdate() = 0;
111 
NeedsUpdate()112     bool NeedsUpdate()
113     {
114         return needsUpdate_;
115     }
116 
117     static void JSBind(BindingTarget globalObj);
118     /**
119      * Views which do not have a state can mark static.
120      * The element will be reused and re-render will be skipped.
121      */
MarkStatic()122     void MarkStatic()
123     {
124         isStatic_ = true;
125     }
126 
IsStatic()127     bool IsStatic()
128     {
129         return isStatic_;
130     }
131 
SetContext(const JSExecutionContext & context)132     void SetContext(const JSExecutionContext& context)
133     {
134         jsViewFunction_->SetContext(context);
135     }
136 
137     // Used to set/get card id C++
SetCardId(int64_t cardId)138     void SetCardId(int64_t cardId)
139     {
140         cardId_ = cardId;
141     }
142 
GetCardId()143     int64_t GetCardId() const
144     {
145         return cardId_;
146     }
147 
RegisterRenderDoneCallback(std::function<void ()> && OnRenderDone)148     void RegisterRenderDoneCallback(std::function<void()>&& OnRenderDone)
149     {
150         notifyRenderDone_ = std::move(OnRenderDone);
151     }
152 
153     // Used to set/get card id JS
154     void JsSetCardId(int64_t cardId);
155     void JsGetCardId(const JSCallbackInfo& info);
156 
157     // Used by full update variant only from js_lazy_foreach.cpp
RemoveChildGroupById(const std::string & viewId)158     virtual void RemoveChildGroupById(const std::string& viewId) {}
MarkLazyForEachProcess(const std::string & groudId)159     virtual void MarkLazyForEachProcess(const std::string& groudId) {}
ResetLazyForEachProcess()160     virtual void ResetLazyForEachProcess() {}
ExecuteUpdateWithValueParams(const std::string & jsonData)161     virtual void ExecuteUpdateWithValueParams(const std::string& jsonData) {}
ExecuteInitiallyProvidedValue(const std::string & jsonData)162     virtual void ExecuteInitiallyProvidedValue(const std::string& jsonData) {}
163 
isFullUpdate()164     virtual bool isFullUpdate() const
165     {
166         return true;
167     }
168 
GetInstanceId()169     int32_t GetInstanceId() const
170     {
171         return instanceId_;
172     }
173 
GetViewNode()174     RefPtr<AceType> GetViewNode() const
175     {
176         return viewNode_.Upgrade();
177     }
178 
OnDumpInfo(const std::vector<std::string> & params)179     virtual void OnDumpInfo(const std::vector<std::string>& params) {}
180 
181     static JSView* GetNativeView(JSRef<JSObject> obj);
182 protected:
183     RefPtr<ViewFunctions> jsViewFunction_;
184     bool needsUpdate_ = false;
185 
186     WeakPtr<AceType> viewNode_;
187     // view id for custom view itself
188     std::string viewId_;
189 
190     // card id for eTS Card
191     // set on the root JSView of the card and inherited by all child JSViews
192     // -1 means not part of a card
193     int64_t cardId_ = -1;
194     std::function<void()> notifyRenderDone_;
195 
196 private:
197     int32_t instanceId_ = -1;
198     std::vector<int32_t> restoreInstanceIdStack_;
199     static constexpr uint32_t PRIMARY_ID_STACK_SIZE = 32;
200     uint32_t primaryStackSize_ = 0;
201     // The primary id stack is protection for restoreInstanceIdStack_.
202     // This can avoid crashing when the pointer in vector is corrupted.
203     std::array<int32_t, PRIMARY_ID_STACK_SIZE> primaryIdStack_{};
204     bool isStatic_ = false;
205 };
206 
207 class JSViewFullUpdate : public JSView {
208     DECLARE_ACE_TYPE(JSViewFullUpdate, JSView);
209 
210 public:
211     JSViewFullUpdate(const std::string& viewId, JSRef<JSObject> jsObject, JSRef<JSFunc> jsRenderFunction);
212     ~JSViewFullUpdate() override;
213 
214     void Destroy(JSView* parentCustomView) override;
215 
216     // TODO: delete this after the toolchain for partial update is ready.
217     RefPtr<AceType> InternalRender();
218 
219     RefPtr<AceType> CreateViewNode(bool isTitleNode = false, bool isCustomAppBar = false) override;
220 
221     void MarkNeedUpdate() override;
222 
223     /**
224      * During render function execution, the child custom view with same id will
225      * be recycled if they exist already in our child map. The ones which are not
226      * recycled needs to be cleaned. So After render function execution, clean the
227      * abandoned child custom view.
228      */
229     void CleanUpAbandonedChild();
230 
231     /**
232      * Retries the custom view child for recycling
233      * always use FindChildById to be certain before calling this method
234      */
235     JSRef<JSObject> GetChildById(const std::string& viewId);
236 
237     void FindChildById(const JSCallbackInfo& info);
238     void FindChildByIdForPreview(const JSCallbackInfo& info);
239     bool GetChildByViewId(const std::string& viewId, JSRef<JSObject>& childView, JSRef<JSObject>& targetView);
240 
ExecuteUpdateWithValueParams(const std::string & jsonData)241     void ExecuteUpdateWithValueParams(const std::string& jsonData) override
242     {
243         jsViewFunction_->ExecuteUpdateWithValueParams(jsonData);
244     }
245 
MarkLazyForEachProcess(const std::string & groudId)246     void MarkLazyForEachProcess(const std::string& groudId) override
247     {
248         isLazyForEachProcessed_ = true;
249         lazyItemGroupId_ = groudId;
250     }
251 
ResetLazyForEachProcess()252     void ResetLazyForEachProcess() override
253     {
254         isLazyForEachProcessed_ = false;
255         lazyItemGroupId_ = "";
256     }
257 
258     /**
259      * New CustomView child will be added to the map.
260      * and it can be retrieved for recycling in next render function
261      * In next render call if this child is not recycled, it will be destroyed.
262      */
263     std::string AddChildById(const std::string& viewId, const JSRef<JSObject>& obj);
264 
265     void RemoveChildGroupById(const std::string& viewId) override;
266 
267     static void Create(const JSCallbackInfo& info);
268     static void JSBind(BindingTarget globalObj);
269 
270     static void ConstructorCallback(const JSCallbackInfo& args);
271     static void DestructorCallback(JSViewFullUpdate* instance);
272 
273 private:
274     void DestroyChild(JSView* parentCustomView);
275 
276     /**
277      * Takes care of the viewId wrt to foreach
278      */
279     std::string ProcessViewId(const std::string& viewId);
280     /**
281      * creates a set of valid view ids on a render function execution
282      * its cleared after cleaning up the abandoned child.
283      */
284     void ChildAccessedById(const std::string& viewId);
285 
286     bool isLazyForEachProcessed_ = false;
287     std::string lazyItemGroupId_;
288 
289     // unique view id for custom view to recycle.
290     std::string id_;
291     // hold handle to the native and javascript object to keep them alive
292     // until they are abandoned
293     std::unordered_map<std::string, JSRef<JSObject>> customViewChildren_;
294 
295     // hold handle to the native and javascript object to keep them alive
296     // until they are abandoned used by lazyForEach
297     std::unordered_map<std::string, JSRef<JSObject>> customViewChildrenWithLazy_;
298 
299     // hold js view ids by lazy item ground.
300     // until they are abandoned used by lazyForEach
301     std::unordered_map<std::string, std::list<std::string>> lazyItemGroups_;
302 
303     // a set of valid view ids on a render function execution
304     // its cleared after cleaning up the abandoned child.
305     std::unordered_set<std::string> lastAccessedViewIds_;
306 
307     // The C++ JSView object owns a reference to the JS Object
308     // AssignNewView assigns the JS View
309     // Destroy deleted the ref, and thereby triggers the deletion
310     // GC -> JS View Object -> JSView C++ Object
311     JSRef<JSObject> jsViewObject_;
312 };
313 
314 class JSViewPartialUpdate : public JSView {
315     DECLARE_ACE_TYPE(JSViewPartialUpdate, JSView);
316 
317 public:
318     explicit JSViewPartialUpdate(JSRef<JSObject> jsObject);
319     ~JSViewPartialUpdate() override;
320 
321     void Destroy(JSView* parentCustomView) override;
322 
323     void DoRenderJSExecution(int64_t deadline, bool& isTimeout);
324 
325     /**
326      * RenderJSExecutionForPrebuild is only applicable to the PreBuild of components.
327      * Unlike RenderJSExecution, when RenderJSExecutionForPrebuild is repeatedly called,
328      * it will not execute the logic that was previously executed
329      * deadline is the input parameter. It represents the expected completion time of this function
330      * isTimeout is the output parameter. When the function is not completed before the deadline, isTimeout = true
331      * We will repeatedly call this function in the next frame until isTimeout = false
332      */
333     void RenderJSExecutionForPrebuild(int64_t deadline, bool& isTimeout);
334 
335     RefPtr<AceType> InitialRender(int64_t deadline, bool& isTimeout);
336 
337     void PrebuildComponentsInMultiFrame(int64_t deadline, bool& isTimeout);
338 
339     void SetPrebuildPhase(PrebuildPhase prebuildPhase, int64_t deadline = 0) override;
340 
341     RefPtr<AceType> CreateViewNode(bool isTitleNode = false, bool isCustomAppBar = false) override;
342 
343     static void Create(const JSCallbackInfo& info);
344     static void CreateRecycle(const JSCallbackInfo& info);
345     static void JSBind(BindingTarget globalObj);
346 
347     static void ConstructorCallback(const JSCallbackInfo& args);
348     static void DestructorCallback(JSViewPartialUpdate* instance);
349 
350     // public functions added by partial update added below ==================
351 
352     /**
353      * Last step of executing an partial update function
354      * get the result component from ViewStackProcessor
355      * add it to the queue to [elmtId, Component] to
356      * execute an local update on in the UI thread
357      * parameters
358      * elmtId of the Component/Element that's updated
359      * removedElementId : Array<number>  ids of Elements that were removed while updating
360      * caused by if condition toggle or ForEach array deleted / replaced items
361      * return boolean - true means success
362      */
363     void JsFinishUpdateFunc(int32_t elmtId);
364 
365     /**
366     JS exposed function to check from ElementRegister if given elmtId is (still) in use
367     */
368     bool JsElementIdExists(int32_t elmtId);
369 
370     void JSGetProxiedItemRenderState(const JSCallbackInfo& info);
371 
372     void JSGetNavDestinationInfo(const JSCallbackInfo& info);
373 
374     void JSGetRouterPageInfo(const JSCallbackInfo& info);
375 
376     void JSGetNavigationInfo(const JSCallbackInfo& info);
377 
378     void JSGetUIContext(const JSCallbackInfo& info);
379 
380     void JSGetUniqueId(const JSCallbackInfo& info);
381 
382     // Release the UINode hold on the JS object and trigger the delete phase.
JSResetRecycleCustomNode(const JSCallbackInfo & info)383     void JSResetRecycleCustomNode(const JSCallbackInfo& info)
384     {
385         recycleCustomNode_.Reset();
386     }
387 
388     void JSSendStateInfo(const std::string& stateInfo);
389 
isFullUpdate()390     bool isFullUpdate() const override
391     {
392         return false;
393     }
394 
395     void IsFirstRender(const JSCallbackInfo& info);
396     void FindChildByIdForPreview(const JSCallbackInfo& info);
397 
SetJSViewName(const std::string & name)398     void SetJSViewName(const std::string& name)
399     {
400         jsViewName_ = name;
401     }
GetJSViewName()402     const std::string& GetJSViewName() const
403     {
404         return jsViewName_;
405     }
406 
ExecuteInitiallyProvidedValue(const std::string & jsonData)407     void ExecuteInitiallyProvidedValue(const std::string& jsonData) override
408     {
409         jsViewFunction_->ExecuteInitiallyProvidedValue(jsonData);
410     }
SetRecycleCustomNode(const RefPtr<NG::CustomNodeBase> & recycleNode)411     void SetRecycleCustomNode(const RefPtr<NG::CustomNodeBase>& recycleNode)
412     {
413         recycleCustomNode_ = recycleNode;
414     }
415 
GetCachedRecycleNode()416     RefPtr<NG::CustomNodeBase> GetCachedRecycleNode()
417     {
418         auto node = RefPtr<NG::CustomNodeBase>(recycleCustomNode_);
419         recycleCustomNode_.Reset();
420         return node;
421     }
422 
GetRecycleCustomNodeName()423     const std::string& GetRecycleCustomNodeName()
424     {
425         return recycleCustomNodeName_;
426     }
427 
SetRecycleCustomNodeName(const std::string & recycleCustomNodeName)428     void SetRecycleCustomNodeName(const std::string& recycleCustomNodeName)
429     {
430         recycleCustomNodeName_ = recycleCustomNodeName;
431     }
432 
SetIsRecycleRerender(bool isRecycleRerender)433     void SetIsRecycleRerender(bool isRecycleRerender)
434     {
435         isRecycleRerender_ = isRecycleRerender;
436     }
437 
GetIsRecycleRerender()438     bool GetIsRecycleRerender()
439     {
440         return isRecycleRerender_;
441     }
442 
443     void JSSetIsV2(const bool isV2);
444 
GetJSIsV2()445     bool GetJSIsV2() const
446     {
447         return isV2_;
448     }
449 
450     void OnDumpInfo(const std::vector<std::string>& params) override;
451 
452     void JSGetDialogController(const JSCallbackInfo& info);
453 
454     bool JSAllowReusableV2Descendant();
455 private:
456     void MarkNeedUpdate() override;
457 
458     // indicates if the JSView has ever completed initial render
459     // used for code branching in lambda given to ComposedComponent
460     // render callback
461     bool isFirstRender_ = true;
462     PrebuildPhase prebuildPhase_ = PrebuildPhase::NONE;
463 
464     /* list of update function result is a triple (tuple with three entries)
465     <0> elmtId
466     <1> outmost wrapping Component
467     <2> main Component
468     */
469     std::list<UpdateTask> pendingUpdateTasks_;
470 
471     // The C++ JSView object owns a reference to the JS Object
472     // AssignNewView assigns the JS View
473     // Destroy deleted the ref, and thereby triggers the deletion
474     // GC -> JS View Object -> JSView C++ Object
475     JSRef<JSObject> jsViewObject_;
476 
477     // Restore the custom node related to the JSView object
478     // If the JSView object is GC by engine, this CustomNode will abe deleted
479     // If the JSView object is hold by RecycleManager, this CustomNode will be reused
480     RefPtr<NG::CustomNodeBase> recycleCustomNode_;
481 
482     // Store the recycle nodes name as key
483     std::string recycleCustomNodeName_;
484     std::string jsViewName_;
485 
486     bool isRecycleRerender_ = false;
487     bool isV2_ = false;
488     bool executedAboutToRender_ = false;
489     bool executedOnRenderDone_ = false;
490     bool executedRender_ = false;
491 };
492 
493 } // namespace OHOS::Ace::Framework
494 #endif // FOUNDATION_ACE_FRAMEWORKS_BRIDGE_DECLARATIVE_FRONTEND_JS_VIEW_JS_VIEW_H
495