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