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