1 /* 2 * Copyright (c) 2021-2022 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 Referenced { 34 public: JSView()35 JSView() : instanceId_(Container::CurrentId()) {} 36 ~JSView() override = default; 37 virtual void Destroy(JSView* parentCustomView) = 0; 38 CreateViewNode()39 virtual RefPtr<AceType> CreateViewNode() 40 { 41 LOGE("Internal error. Not implemented"); 42 return nullptr; 43 } 44 45 void SyncInstanceId(); 46 void RestoreInstanceId(); 47 FireOnShow()48 void FireOnShow() 49 { 50 if (jsViewFunction_) { 51 ACE_SCORING_EVENT("OnShow"); 52 jsViewFunction_->ExecuteShow(); 53 } 54 } 55 FireOnHide()56 void FireOnHide() 57 { 58 if (jsViewFunction_) { 59 ACE_SCORING_EVENT("OnHide"); 60 jsViewFunction_->ExecuteHide(); 61 } 62 } 63 FireOnBackPress()64 bool FireOnBackPress() 65 { 66 if (jsViewFunction_) { 67 ACE_SCORING_EVENT("OnBackPress"); 68 return jsViewFunction_->ExecuteOnBackPress(); 69 } 70 return false; 71 } 72 73 void RenderJSExecution(); 74 75 virtual void MarkNeedUpdate() = 0; 76 77 bool NeedsUpdate(); 78 79 static void JSBind(BindingTarget globalObj); 80 /** 81 * Views which do not have a state can mark static. 82 * The element will be reused and re-render will be skipped. 83 */ 84 void MarkStatic(); 85 IsStatic()86 bool IsStatic() 87 { 88 return isStatic_; 89 } 90 SetContext(const JSExecutionContext & context)91 void SetContext(const JSExecutionContext& context) 92 { 93 jsViewFunction_->SetContext(context); 94 } 95 96 // Used to set/get card id C++ SetCardId(int64_t cardId)97 void SetCardId(int64_t cardId) 98 { 99 cardId_ = cardId; 100 } 101 GetCardId()102 int64_t GetCardId() const 103 { 104 return cardId_; 105 } 106 RegisterRenderDoneCallback(std::function<void ()> && OnRenderDone)107 void RegisterRenderDoneCallback(std::function<void()>&& OnRenderDone) 108 { 109 notifyRenderDone_ = std::move(OnRenderDone); 110 } 111 112 // Used to set/get card id JS 113 void JsSetCardId(int64_t cardId); 114 void JsGetCardId(const JSCallbackInfo& info); 115 116 // Used by full update variant only from js_lazy_foreach.cpp RemoveChildGroupById(const std::string & viewId)117 virtual void RemoveChildGroupById(const std::string& viewId) {} MarkLazyForEachProcess(const std::string & groudId)118 virtual void MarkLazyForEachProcess(const std::string& groudId) {} ResetLazyForEachProcess()119 virtual void ResetLazyForEachProcess() {} ExecuteUpdateWithValueParams(const std::string & jsonData)120 virtual void ExecuteUpdateWithValueParams(const std::string& jsonData) {} ExecuteInitiallyProvidedValue(const std::string & jsonData)121 virtual void ExecuteInitiallyProvidedValue(const std::string& jsonData) {} 122 isFullUpdate()123 virtual bool isFullUpdate() const 124 { 125 return true; 126 } 127 128 #ifdef UICAST_COMPONENT_SUPPORTED ExecuteCreateChildView(const std::string & childViewId)129 void ExecuteCreateChildView(const std::string& childViewId) 130 { 131 std::string jsonData = R"({"viewID":")" + childViewId + R"("})"; 132 LOGI("UICast para: %{public}s", jsonData.c_str()); 133 jsViewFunction_->ExecuteCreateChildView(jsonData); 134 } 135 ExecuteRouterHandle(const std::string & type,const std::string & uri)136 void ExecuteRouterHandle(const std::string& type, const std::string& uri) 137 { 138 std::string jsonData = R"({"uri":")" + uri + R"(","type":")" + type + R"("})"; 139 LOGI("UICast para: %{public}s", jsonData.c_str()); 140 ContainerScope scope(instanceId_); 141 jsViewFunction_->ExecuteRouterHandle(jsonData); 142 } 143 ExecuteReplayOnEvent(const std::string & event)144 void ExecuteReplayOnEvent(const std::string& event) 145 { 146 std::string jsonData = R"({"event":")" + event + R"("})"; 147 LOGI("UICast para: %{public}s", jsonData.c_str()); 148 jsViewFunction_->ExecuteReplayOnEvent(jsonData); 149 } 150 #endif 151 UICastGetViewId()152 std::string UICastGetViewId() const 153 { 154 return viewId_; 155 } 156 UICastGetUniqueId()157 int UICastGetUniqueId() const 158 { 159 return uniqueId_; 160 } 161 GetInstanceId()162 int32_t GetInstanceId() const 163 { 164 return instanceId_; 165 } 166 167 protected: 168 RefPtr<ViewFunctions> jsViewFunction_; 169 bool needsUpdate_ = false; 170 171 WeakPtr<AceType> viewNode_; 172 // view id for custom view itself 173 std::string viewId_; 174 int uniqueId_ = -1; 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 int32_t restoreInstanceId_ = -1; 184 bool isStatic_ = false; 185 std::function<void()> notifyRenderDone_; 186 }; 187 188 class JSViewFullUpdate : public JSView { 189 public: 190 JSViewFullUpdate(const std::string& viewId, JSRef<JSObject> jsObject, JSRef<JSFunc> jsRenderFunction); 191 ~JSViewFullUpdate() override; 192 193 void Destroy(JSView* parentCustomView) override; 194 195 // TODO: delete this after the toolchain for partial update is ready. 196 RefPtr<AceType> InternalRender(); 197 198 RefPtr<AceType> CreateViewNode() override; 199 200 void MarkNeedUpdate() override; 201 202 /** 203 * During render function execution, the child custom view with same id will 204 * be recycled if they exist already in our child map. The ones which are not 205 * recycled needs to be cleaned. So After render function execution, clean the 206 * abandoned child custom view. 207 */ 208 void CleanUpAbandonedChild(); 209 210 /** 211 * Retries the custom view child for recycling 212 * always use FindChildById to be certain before calling this method 213 */ 214 JSRef<JSObject> GetChildById(const std::string& viewId); 215 216 void FindChildById(const JSCallbackInfo& info); 217 void FindChildByIdForPreview(const JSCallbackInfo& info); 218 bool GetChildByViewId(const std::string& viewId, JSRef<JSObject>& childView, JSRef<JSObject>& targetView); 219 ExecuteUpdateWithValueParams(const std::string & jsonData)220 void ExecuteUpdateWithValueParams(const std::string& jsonData) override 221 { 222 jsViewFunction_->ExecuteUpdateWithValueParams(jsonData); 223 } 224 MarkLazyForEachProcess(const std::string & groudId)225 void MarkLazyForEachProcess(const std::string& groudId) override 226 { 227 isLazyForEachProcessed_ = true; 228 lazyItemGroupId_ = groudId; 229 } 230 ResetLazyForEachProcess()231 void ResetLazyForEachProcess() override 232 { 233 isLazyForEachProcessed_ = false; 234 lazyItemGroupId_ = ""; 235 } 236 237 /** 238 * New CustomView child will be added to the map. 239 * and it can be retrieved for recycling in next render function 240 * In next render call if this child is not recycled, it will be destroyed. 241 */ 242 std::string AddChildById(const std::string& viewId, const JSRef<JSObject>& obj); 243 244 void RemoveChildGroupById(const std::string& viewId) override; 245 246 static void Create(const JSCallbackInfo& info); 247 static void JSBind(BindingTarget globalObj); 248 249 static void ConstructorCallback(const JSCallbackInfo& args); 250 static void DestructorCallback(JSViewFullUpdate* instance); 251 252 private: 253 void DestroyChild(JSView* parentCustomView); 254 255 /** 256 * Takes care of the viewId wrt to foreach 257 */ 258 std::string ProcessViewId(const std::string& viewId); 259 /** 260 * creates a set of valid view ids on a render function execution 261 * its cleared after cleaning up the abandoned child. 262 */ 263 void ChildAccessedById(const std::string& viewId); 264 265 bool isLazyForEachProcessed_ = false; 266 std::string lazyItemGroupId_; 267 268 // unique view id for custom view to recycle. 269 std::string id_; 270 // hold handle to the native and javascript object to keep them alive 271 // until they are abandoned 272 std::unordered_map<std::string, JSRef<JSObject>> customViewChildren_; 273 274 // hold handle to the native and javascript object to keep them alive 275 // until they are abandoned used by lazyForEach 276 std::unordered_map<std::string, JSRef<JSObject>> customViewChildrenWithLazy_; 277 278 // hold js view ids by lazy item ground. 279 // until they are abandoned used by lazyForEach 280 std::unordered_map<std::string, std::list<std::string>> lazyItemGroups_; 281 282 // a set of valid view ids on a render function execution 283 // its cleared after cleaning up the abandoned child. 284 std::unordered_set<std::string> lastAccessedViewIds_; 285 286 // The C++ JSView object owns a reference to the JS Object 287 // AssignNewView assigns the JS View 288 // Destroy deleted the ref, and thereby triggers the deletion 289 // GC -> JS View Object -> JSView C++ Object 290 JSRef<JSObject> jsViewObject_; 291 }; 292 293 class JSViewPartialUpdate : public JSView { 294 public: 295 explicit JSViewPartialUpdate(JSRef<JSObject> jsObject); 296 ~JSViewPartialUpdate() override; 297 298 void Destroy(JSView* parentCustomView) override; 299 300 RefPtr<AceType> InitialRender(); 301 302 RefPtr<AceType> CreateViewNode() override; 303 304 static void Create(const JSCallbackInfo& info); 305 static void JSBind(BindingTarget globalObj); 306 307 static void ConstructorCallback(const JSCallbackInfo& args); 308 static void DestructorCallback(JSViewPartialUpdate* instance); 309 310 // public functions added by partial update added below ================== 311 312 /** 313 * Last step of executing an partial update function 314 * get the result component from ViewStackProcessor 315 * add it to the queue to [elmtId, Component] to 316 * execute an local update on in the UI thread 317 * parameters 318 * elmtId of the Component/Element that's updated 319 * removedElementId : Array<number> ids of Elements that were removed while updating 320 * caused by if condition toggle or ForEach array deleted / replaced items 321 * return boolean - true means success 322 */ 323 void JsFinishUpdateFunc(int32_t elmtId); 324 325 // The process of Component to Element sync leads to Elements being 326 // deleted. ElementRegister keeps track of these deletions 327 // before the framework can forget about these elmtIds 328 // these need to be removed from its own book keeping 329 // state variables keep track of dependent elmtIds and 330 // View objects keep a map elmtId -> update function, 331 // both on TS side. 332 // View.purgeDeletedElmtIds cleans both state variables 333 // and update function map from deleted ElmtIds 334 // afterwards it informs the ElementRegister that elmtIds 335 // it was able to purge. 336 // only then ElementRegister can forget about these elmtIds 337 void JsGetDeletedElemtIds(const JSCallbackInfo& info); 338 339 // JS signature: View.deletedElmtIdsHaveBeenPurged(elmtIds : number[]) 340 // inform ElementRegister that given deleted eltIds 341 // have been deleted from partial updates book keeping 342 // at this point ElementRegister can forget about the, 343 void JsDeletedElmtIdsHaveBeenPurged(const JSCallbackInfo& info); 344 345 /** 346 JS exposed function to check from ElementRegister if given elmtId is (still) in use 347 */ 348 bool JsElementIdExists(int32_t elmtId); 349 350 void JSGetProxiedItemRenderState(const JSCallbackInfo& info); 351 isFullUpdate()352 bool isFullUpdate() const override 353 { 354 return false; 355 } 356 357 void IsFirstRender(const JSCallbackInfo& info); 358 void FindChildByIdForPreview(const JSCallbackInfo& info); 359 ExecuteInitiallyProvidedValue(const std::string & jsonData)360 void ExecuteInitiallyProvidedValue(const std::string& jsonData) override 361 { 362 jsViewFunction_->ExecuteInitiallyProvidedValue(jsonData); 363 } 364 365 private: 366 void MarkNeedUpdate() override; 367 368 // indicates if the JSView has ever completed initial render 369 // used for code branching in lambda given to ComposedComponent 370 // render callback 371 bool isFirstRender_ = true; 372 373 /* list of update function result is a triple (tuple with three entries) 374 <0> elmtId 375 <1> outmost wrapping Component 376 <2> main Component 377 */ 378 std::list<UpdateTask> pendingUpdateTasks_; 379 380 // The C++ JSView object owns a reference to the JS Object 381 // AssignNewView assigns the JS View 382 // Destroy deleted the ref, and thereby triggers the deletion 383 // GC -> JS View Object -> JSView C++ Object 384 JSRef<JSObject> jsViewObject_; 385 }; 386 387 } // namespace OHOS::Ace::Framework 388 #endif // FOUNDATION_ACE_FRAMEWORKS_BRIDGE_DECLARATIVE_FRONTEND_JS_VIEW_JS_VIEW_H 389