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