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