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