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::vector<int32_t> restoreInstanceIdStack_; 184 static constexpr uint32_t PRIMARY_ID_STACK_SIZE = 32; 185 uint32_t primaryStackSize_ = 0; 186 // The primary id stack is protection for restoreInstanceIdStack_. 187 // This can avoid crashing when the pointer in vector is corrupted. 188 std::array<int32_t, PRIMARY_ID_STACK_SIZE> primaryIdStack_{}; 189 bool isStatic_ = false; 190 std::function<void()> notifyRenderDone_; 191 }; 192 193 class JSViewFullUpdate : public JSView { 194 DECLARE_ACE_TYPE(JSViewFullUpdate, JSView) 195 196 public: 197 JSViewFullUpdate(const std::string& viewId, JSRef<JSObject> jsObject, JSRef<JSFunc> jsRenderFunction); 198 ~JSViewFullUpdate() override; 199 200 void Destroy(JSView* parentCustomView) override; 201 202 // TODO: delete this after the toolchain for partial update is ready. 203 RefPtr<AceType> InternalRender(); 204 205 RefPtr<AceType> CreateViewNode(bool isTitleNode = false) override; 206 207 void MarkNeedUpdate() override; 208 209 /** 210 * During render function execution, the child custom view with same id will 211 * be recycled if they exist already in our child map. The ones which are not 212 * recycled needs to be cleaned. So After render function execution, clean the 213 * abandoned child custom view. 214 */ 215 void CleanUpAbandonedChild(); 216 217 /** 218 * Retries the custom view child for recycling 219 * always use FindChildById to be certain before calling this method 220 */ 221 JSRef<JSObject> GetChildById(const std::string& viewId); 222 223 void FindChildById(const JSCallbackInfo& info); 224 void FindChildByIdForPreview(const JSCallbackInfo& info); 225 bool GetChildByViewId(const std::string& viewId, JSRef<JSObject>& childView, JSRef<JSObject>& targetView); 226 ExecuteUpdateWithValueParams(const std::string & jsonData)227 void ExecuteUpdateWithValueParams(const std::string& jsonData) override 228 { 229 jsViewFunction_->ExecuteUpdateWithValueParams(jsonData); 230 } 231 MarkLazyForEachProcess(const std::string & groudId)232 void MarkLazyForEachProcess(const std::string& groudId) override 233 { 234 isLazyForEachProcessed_ = true; 235 lazyItemGroupId_ = groudId; 236 } 237 ResetLazyForEachProcess()238 void ResetLazyForEachProcess() override 239 { 240 isLazyForEachProcessed_ = false; 241 lazyItemGroupId_ = ""; 242 } 243 244 /** 245 * New CustomView child will be added to the map. 246 * and it can be retrieved for recycling in next render function 247 * In next render call if this child is not recycled, it will be destroyed. 248 */ 249 std::string AddChildById(const std::string& viewId, const JSRef<JSObject>& obj); 250 251 void RemoveChildGroupById(const std::string& viewId) override; 252 253 static void Create(const JSCallbackInfo& info); 254 static void JSBind(BindingTarget globalObj); 255 256 static void ConstructorCallback(const JSCallbackInfo& args); 257 static void DestructorCallback(JSViewFullUpdate* instance); 258 259 private: 260 void DestroyChild(JSView* parentCustomView); 261 262 /** 263 * Takes care of the viewId wrt to foreach 264 */ 265 std::string ProcessViewId(const std::string& viewId); 266 /** 267 * creates a set of valid view ids on a render function execution 268 * its cleared after cleaning up the abandoned child. 269 */ 270 void ChildAccessedById(const std::string& viewId); 271 272 bool isLazyForEachProcessed_ = false; 273 std::string lazyItemGroupId_; 274 275 // unique view id for custom view to recycle. 276 std::string id_; 277 // hold handle to the native and javascript object to keep them alive 278 // until they are abandoned 279 std::unordered_map<std::string, JSRef<JSObject>> customViewChildren_; 280 281 // hold handle to the native and javascript object to keep them alive 282 // until they are abandoned used by lazyForEach 283 std::unordered_map<std::string, JSRef<JSObject>> customViewChildrenWithLazy_; 284 285 // hold js view ids by lazy item ground. 286 // until they are abandoned used by lazyForEach 287 std::unordered_map<std::string, std::list<std::string>> lazyItemGroups_; 288 289 // a set of valid view ids on a render function execution 290 // its cleared after cleaning up the abandoned child. 291 std::unordered_set<std::string> lastAccessedViewIds_; 292 293 // The C++ JSView object owns a reference to the JS Object 294 // AssignNewView assigns the JS View 295 // Destroy deleted the ref, and thereby triggers the deletion 296 // GC -> JS View Object -> JSView C++ Object 297 JSRef<JSObject> jsViewObject_; 298 }; 299 300 class JSViewPartialUpdate : public JSView { 301 DECLARE_ACE_TYPE(JSViewPartialUpdate, JSView) 302 303 public: 304 explicit JSViewPartialUpdate(JSRef<JSObject> jsObject); 305 ~JSViewPartialUpdate() override; 306 307 void Destroy(JSView* parentCustomView) override; 308 309 RefPtr<AceType> InitialRender(); 310 311 RefPtr<AceType> CreateViewNode(bool isTitleNode = false) override; 312 313 static void Create(const JSCallbackInfo& info); 314 static void CreateRecycle(const JSCallbackInfo& info); 315 static void JSBind(BindingTarget globalObj); 316 317 static void ConstructorCallback(const JSCallbackInfo& args); 318 static void DestructorCallback(JSViewPartialUpdate* instance); 319 320 // public functions added by partial update added below ================== 321 322 /** 323 * Last step of executing an partial update function 324 * get the result component from ViewStackProcessor 325 * add it to the queue to [elmtId, Component] to 326 * execute an local update on in the UI thread 327 * parameters 328 * elmtId of the Component/Element that's updated 329 * removedElementId : Array<number> ids of Elements that were removed while updating 330 * caused by if condition toggle or ForEach array deleted / replaced items 331 * return boolean - true means success 332 */ 333 void JsFinishUpdateFunc(int32_t elmtId); 334 335 /** 336 JS exposed function to check from ElementRegister if given elmtId is (still) in use 337 */ 338 bool JsElementIdExists(int32_t elmtId); 339 340 void JSGetProxiedItemRenderState(const JSCallbackInfo& info); 341 342 void JSGetNavDestinationInfo(const JSCallbackInfo& info); 343 344 void JSGetRouterPageInfo(const JSCallbackInfo& info); 345 346 void JSGetNavigationInfo(const JSCallbackInfo& info); 347 348 void JSGetUIContext(const JSCallbackInfo& info); 349 350 void JSGetUniqueId(const JSCallbackInfo& info); 351 352 // Release the UINode hold on the JS object and trigger the delete phase. JSResetRecycleCustomNode(const JSCallbackInfo & info)353 void JSResetRecycleCustomNode(const JSCallbackInfo& info) 354 { 355 recycleCustomNode_.Reset(); 356 } 357 358 void JSSendStateInfo(const std::string& stateInfo); 359 isFullUpdate()360 bool isFullUpdate() const override 361 { 362 return false; 363 } 364 365 void IsFirstRender(const JSCallbackInfo& info); 366 void FindChildByIdForPreview(const JSCallbackInfo& info); 367 SetJSViewName(const std::string & name)368 void SetJSViewName(const std::string& name) 369 { 370 jsViewName_ = name; 371 } GetJSViewName()372 const std::string& GetJSViewName() const 373 { 374 return jsViewName_; 375 } 376 ExecuteInitiallyProvidedValue(const std::string & jsonData)377 void ExecuteInitiallyProvidedValue(const std::string& jsonData) override 378 { 379 jsViewFunction_->ExecuteInitiallyProvidedValue(jsonData); 380 } SetRecycleCustomNode(const RefPtr<NG::CustomNodeBase> & recycleNode)381 void SetRecycleCustomNode(const RefPtr<NG::CustomNodeBase>& recycleNode) 382 { 383 recycleCustomNode_ = recycleNode; 384 } 385 GetCachedRecycleNode()386 RefPtr<NG::CustomNodeBase> GetCachedRecycleNode() 387 { 388 auto node = RefPtr<NG::CustomNodeBase>(recycleCustomNode_); 389 recycleCustomNode_.Reset(); 390 return node; 391 } 392 GetRecycleCustomNodeName()393 const std::string& GetRecycleCustomNodeName() 394 { 395 return recycleCustomNodeName_; 396 } 397 SetRecycleCustomNodeName(const std::string & recycleCustomNodeName)398 void SetRecycleCustomNodeName(const std::string& recycleCustomNodeName) 399 { 400 recycleCustomNodeName_ = recycleCustomNodeName; 401 } 402 SetIsRecycleRerender(bool isRecycleRerender)403 void SetIsRecycleRerender(bool isRecycleRerender) 404 { 405 isRecycleRerender_ = isRecycleRerender; 406 } 407 GetIsRecycleRerender()408 bool GetIsRecycleRerender() 409 { 410 return isRecycleRerender_; 411 } 412 413 void JSSetIsV2(const bool isV2); 414 GetJSIsV2()415 bool GetJSIsV2() const 416 { 417 return isV2_; 418 } 419 420 void OnDumpInfo(const std::vector<std::string>& params) override; 421 422 private: 423 void MarkNeedUpdate() override; 424 425 // indicates if the JSView has ever completed initial render 426 // used for code branching in lambda given to ComposedComponent 427 // render callback 428 bool isFirstRender_ = true; 429 430 /* list of update function result is a triple (tuple with three entries) 431 <0> elmtId 432 <1> outmost wrapping Component 433 <2> main Component 434 */ 435 std::list<UpdateTask> pendingUpdateTasks_; 436 437 // The C++ JSView object owns a reference to the JS Object 438 // AssignNewView assigns the JS View 439 // Destroy deleted the ref, and thereby triggers the deletion 440 // GC -> JS View Object -> JSView C++ Object 441 JSRef<JSObject> jsViewObject_; 442 443 // Restore the custom node related to the JSView object 444 // If the JSView object is GC by engine, this CustomNode will abe deleted 445 // If the JSView object is hold by RecycleManager, this CustomNode will be reused 446 RefPtr<NG::CustomNodeBase> recycleCustomNode_; 447 448 // Store the recycle nodes name as key 449 std::string recycleCustomNodeName_; 450 std::string jsViewName_; 451 452 bool isRecycleRerender_ = false; 453 bool isV2_ = false; 454 }; 455 456 } // namespace OHOS::Ace::Framework 457 #endif // FOUNDATION_ACE_FRAMEWORKS_BRIDGE_DECLARATIVE_FRONTEND_JS_VIEW_JS_VIEW_H 458