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