From 1f2060b0b8d12e8458217f9d50a0ffe7e31cead2 Mon Sep 17 00:00:00 2001 From: "ester.zhou" Date: Mon, 31 Jul 2023 20:44:53 +0800 Subject: [PATCH] Update docs (20875) Signed-off-by: ester.zhou --- en/application-dev/napi/figures/onDestroy.png | Bin 0 -> 13943 bytes en/application-dev/napi/figures/onLoad.png | Bin 0 -> 20164 bytes .../napi/xcomponent-guidelines.md | 902 ++++++++++++++++++ 3 files changed, 902 insertions(+) create mode 100644 en/application-dev/napi/figures/onDestroy.png create mode 100644 en/application-dev/napi/figures/onLoad.png create mode 100644 en/application-dev/napi/xcomponent-guidelines.md diff --git a/en/application-dev/napi/figures/onDestroy.png b/en/application-dev/napi/figures/onDestroy.png new file mode 100644 index 0000000000000000000000000000000000000000..41f10a3a0a1ecafb673f5013199977a42bc9b531 GIT binary patch literal 13943 zcmb`uXH-+s+wF@YpmY`KRY02b0MeBpy;r42KtMW#CJ;m*p%)1t9i&T@-Xpz9M|$ry zK@0Z;c_wd7^6N(N}RfIl8sy-|IGh4m|n;2QF;h?=q z^L`q36xZ);%*?u;)}B@l&<{-M>QOMkA(Z@UhoulocpLI7gp%XC79SyVken?(V)in3 zx2WW4k^Qe0zG*hg@8tqh72w3iixu!Tw>dRO5O&^O!gbeMQ>1UbzJjj3oeia2!w++i z{CR%4T(j%lU93m$ZOvqLnw-+om-HL$+oNs&a#Im)eE6`*8xEfXn+Ts13fr~0bXw|} z@z{K_cvI2Wr+f36FD{|IoR#Ca(EKZG_(_o|%7or~m%k2Ozw?0xn;v!!5ncR(jX&S)YH91{^Eg23 zysX>+KKH96M#~x_!<=fr_}jmH!o<60Se{{Toh`xGJ#lCD;$XY5w6{Bk*;t|tPUL!+ z;xX^#)fM~Tne%$0Rj=Tn1alZU_b1JuvJV~jYz>ax6avU6`>4BSl{5*_W?Mr-Dgjw^ z!+!I5NtwjKZ|riHwchiRTAOcLLj&$TtO?!qZacF-R-dX%FsV!5RPH>ibGN=ub?N0m zU&iU1*aRb9bw$u@>?UJBb8aIN>Hfy5oMJ893a0zF%YHb5MnYrp?~8`$QJ zq$k2Ylk&Z+tv%sTuiu&-d6PKnbJUONW{#?@eU=8#RyXQik*>PNw33{Wt}FJj{y|;J z3(IkGmP$97e@_{^SJsvOO;PQ4YOOQd?0B)Ed4k2aUVX&`6lp*2)?>UEw8q(mR;WEA zx4*h*gSp@YTZ?v+nF5)*OUw9TJAoKAsa?exN3M)h1HZ%(wF!C`c#vHBjpOGmhZ{Cs zw;9{*?P{GIYD)eOfr4AX@cx%Z<8PU9J?MyfQr?%Dy)gy}<%^$An$I;o;ds2^_vbtR zz#yE6=0n2gACDEYjzL5?9?R{#4!ljr->z7>mp2U7n2bQ}9uwCtgF?~n*#|~GlLd|E z+9InuBIpnXkV8ZtqO3MX`n6iCOOziswnaNjPd?_#D>T=LrvQ&Guy^phO^e94I* zaZ^uYGMoxLcSdYoVeWa2Ldll(y~=Y^$LL#|Rqk@rM;E{bDjWxe6RyU;TrML)xdA?>qQzpaA5|J%1 zTK*+lf_05Sx_bu!y!w>1lO!*d%x`K{Wut@$L7<6?Mftp(=_U4VKCe%0&gL|Rx)>NjTgA6 zicj1|%eE%tB|`2UbV=Vj`%HWXzW%+%q8gsCF8x;A0otCLtS_IBH<#Q+T1AarGXoww zW^2wZzu4C=GHDWX?t9X~ynHD2_{oGR!;A%-O>X3;&t%y|EKXS!+XG)61>E$I^v?#hlV3p}bbK|Uj6(k=g%gLR?3xUj9f!nmDS9!P^lH`k z``cTRp9ZHB7YbO!YR}m$O0kziGko5W$tr%6CY-4bdSNKJfgk#|R=$2NESukNZeMX(lhRnQ@e`hCYI)#n~q1bAs^TC6~9x!CRbt^9&4KF1Njl@5< z)O|<84i-j6H|xkS@$Y`ZpVoxpB-FBdt|i%)IJfaFcaeCRTP9Ra5oNk`3p!9DlZ45F zQpuJ(7SE!=#LmoY?y^`^8l)(-_%Pk`eds=<8B9Pa%U?eJgxog zT1G?S>?~s=j8?N^M-w`u81_fT@zh;M2SPmUGyUxdBJjhsVul=s!Ky4iZLNfxKi)rd zukUVi%*N7MhGepQk{FiC*{tYpkJ^by{q<9)04hOnHwoc3U=c zY)Z7U*QG@m38u$Xth^^KjCRUejdp4k%#p!25~Ds1F&)SzOS*Z39Il2u>?7NlvP$Qk zOc`S*+~q7QE9J!qA@nX7d#z{6aI*~qc0<3*uoJ&qFry2u;v^5cIY}RHMan#SN@O~> zeBkJJH8a^cIk&0D+W-om7ud6_A`|xI3w@II-JJ)#RJH|YO2mFg-SySSdVF-uL$el&v) zuSY}}CYNxRM6syhuij;RkfP6R8D}n>t~FN>JOzD(xC%e=tL`0`^+jCUxF@IuQ1Tc&!q^*Sk;ko}&G|BM zTOQ|^GEdwaC-#Bn_c9kL5y!C~I>Ma&Mq&bZ=tsuBw%hfbxuQV@AcRfIRA z#BK0XabFtswGI2mq13CubsJDj8E?%dO@!R-IbHmY#-pK&kvH4h}~%0xnZE zn2b-rU4(1DrI&O#ST2TZeRI}OIS5I2s3!v%-eHcbeg}jMUdC&sg)i(o*)N+q;_Kfv zl$0p~KFHlwbrrS{d$laJ9f&rkW|-I1I475;zSr(?vM8-}|Iiq1rF70KV|jIJI(H{Jp)mLTSW;xQcx(bMr zV-cJ?JDh5AH}PRats7ooaf_1`*0rY#Yw~P+!j{jytgS%bscIHwS~2ESQ*kk;Jr7T@ zEWghrL;hY4t1}l7%gnodUXF_O@zG}C)sMigxx}=&t<+d>S4OImozGZo_XMM?Y>`6P z``EE`enpTTzU6bt)1qje80A6Yf==s(46=7oW;0LQ$l2ZT>C%fe zBcJ$PtR>9dXP$wd-pF1t?)Du!UW(pGW)FMed*7@QU3BE%WP9YfJc`ujn`Rn=b%hFS zX_&kaFD&j<#*xEL_W0ZTH%uy;NLsvTULZF{>%6ncQE_nKnVNrgJ>}kGvetDvA_()Ze?Ds|JSb+V9RPcXJOK?Su!7SWk@Qw1z`?)lH;*~FS?b%Q+{bG zzS`DH?P0y6ypKi_TdujR&Znv{A^CF2l#r6*$etS17+8&dNGM5ZOv&s0jcLdwL)TgS zy}NOaQ%mG?pw;)A&rqZ*-kHk|feJ(OtfTtH^cM$VC3a^O4kRBGCWqfeJM>=It}wnL zYL^G^WQ($aIwzDP=!w;$iFfyAi=<_H=GEpy1xP(}el#Xl`-b@rHQT~oYYOlriL6dp%=l}A!+5=+cdC(BKm{a}sX=%%A zuEH>t#IbQqLU8ej@;%(ZnL=55(~7tAiJz_Q4Aq%)%I*elIR;HdHBPsl2z{FzuwEEb zr#xTKktz6H-y%P=vzjeF-s>&h^Mi~y7}*-iKosrU;1T_kwo>LS^!zyymtIkHCK%D_ zp}O%`-!u+A*PwiNdt;uw4o*={;BlMCl8@rCo|O}*_}E`w?(l}wb~)@NG`zAE5%*W% zIALdX?llJs59r4W7a_%=DY;16EqL}n8;hDXPv-^w0L)c4V0O8&aS5aSvGID_NTg{S zgi}v;CK_Hb_#SIo8BlYR2(7M^_wl&8AfLptsmGr!_(?b0&PV`?wuD~9VU}`+ER91u zx7%wYm14n?tsv^7fFhaCnSZ2TFGrq2sY%l+U}Qs{l(?e4_)3M|3wq6*Bxn_BH(B-u zaAa%=MlK=YbmHR?uanx$qa7nr`W2BFT4bK+FWxwg{N9oS<4yqYYs=`!lZ79_$c%WL&klj#WJ4+FM zt16v`LXbhTf3ttd^BP9kfW(M)KS?4~al*7Z%im0-k5T;Hu_Ly@+ z_ozt__JOYp@YNxNHkn%&9ln60E&ueF(<6fJVD)1@T-rj@8%MOPjY#_Z1aa3r;Pj-1 z2@GEaCDk2|D9^<%HeaE`?6>>)k>I{Brrf-m@g%IF^XU&~E6y3dlyobU z$}^%umqn4|l`MPx!wEh&5!br zoQBdy)dDzZMg1E_UiU4z=JQc^uqdhY;p6y58((%sUr>()HODS_&KGIM3Im%^)8UL~ zUnLvepNs0{N2QN;KDM?Mh@=sX$vi8(4_$xzy1gK_1n26(1v% zXH27aXKG3XOHsG=4e65J?%;QX5Yx|FtQ+wW`Q>xGw<7k_$R~r9HlrytTj31SCg{2i zdJ&MNb(3WuInbsh0Iy5`Q#_YL)IRny+^y;(_9u%?n(CPdCxBcE8k!O% zfeEhAKdTrJ>oew>+Ga9LL7ub*5g6a{AFcPhx&xEr6qVMCHsM%ZcHy!7N$d3c-l48< z8v6#|4B4s`)w5}h=o6)e)Dp$4ZwV9;=QWIspaz_WJ0db~#W70=1~e?ztV$QsykV83 zWD)t6X)s;dlm~T?=qV2-*3U#RFhW6U*@W(^8kw%YDWhqUw=AnYdMth z=Fr$2aLkWQ|E^5fi-~Unn~nbr`sC8! z8kC*Ej1#yXg7~0tzdvGGL5q?JIszsZWpQR=eJQ&TRT^{T&#gqBt|4ZX;tc;6(tX-B zkgi_}S>rY0xVb!WMH$vOxTTJZOksLsDOtO$A8ta!Lt8!hR+Enp1MXOr;}t+J<7pfl zhlBc`#hnFFm^h(&d*ir_5!#6e5@4ik0wsR&HXg`$kc3ZlX~A z3Nl;ktmglNvQDo&js_hrBQTuej|M@a;gE+|;TbawK(Z9|V zISEmu-9_Y;oo!WmEJI&>JkU1-n_U~R7U~8tF`fGpp~6}VQR|Q1|3y(RYhOE2Mo7PW zn!#^_*XmS!d#<{H+f10vAZ(P*hk_Vmd38$m5Q(F9d$JZ@x1ATzl(eZW#qy|ODB*w4 zL3fG0L=SfwM%8rY?e-qJaLm|QhWdW@!+h6i{vwI~QUntp5jarbt11Drp3IT4FL;nuP`(BX?%Ern~wPZx1@ex!f1GL+-wezo)o@S?8E4Q=^D(~JKe zz9l~n$cK2Wp1(mt%65KNQ-pN}&93o>GHBz=F;6Z9uNOM#vn1s;JoCwd0(uhkmAjEj z@FU1>5K|nW%AkY?G}D{3^;`7ETNcl10wgH=tHuwzetVxPx&K><20ahd2NF@tjVqPs zvjnzZurLOxm?{3>C|IewXR8@V&7GWVS13HqJOeV)B9rZxi*2)2Sl!(z`pjprMaY>; zRn)O{lBl-knFRjDKL>g#$KYs>`HFwm7}Q0;-v|Q79e$*9xFn}{9Oh^|g!{EFA!;yV z2c7BgVUf*)06#*9*`rT0+-IDdAXU6cppFaba$s`OC?#j z&j8L7HgvefzEoH^?YtR&$%B%?I})dWZ93u8QFy?f%~r+Qdcu6KJ$-UA4lh#QuZ@Ea z3YG9i)(F;?xIkGKEGNS(v5Fj%$C<%Hu2jc6vTvpJ*V)DIl-~|{Jftk=x}|z{c_CmJ zrsN673EY2v5M(`~AC$s%Ple$-z1gwtTQ`DXAEAxLM_DI)IYVmQCuMOyi?5?tey}xO z8O?|cD`XAdV`fSbSwg&T^mLv+l8Bf?a0ESnJ|}Xa1aeFORynEWLV1cEwO30I&SrF4 z9We_)bcYNuC6m;bA@Mnkh_seTa-9zxz68|!^G%&$T0n@!+&$k(pq*&!n!FA zUArUKl|97m@P0fDnINYw3+kLB2y?j=xuEp(kF?c0{2S5nx|MzDc{&fv*HyPPd>jt=jQ8V(>}DgFwrN={py& zEk^p=%5-6D^k@!MEBluUywM1)Zx(;zd9%F8mPc*0@mbaK$-=86Qu6@g)1s(@zZPTv z_Pxb<|A+8uB5~|$?nxM++d^J!FB~7SP^&UD^WCIluA^{!VRKwANm7*X;Zw8AgEy8D zDaU&C0 z)Ge+Cqk`>sY_iE5K3|$ol@-fvt1u&RHHA=^7PYC`VgohF>_X(*yYP{Wmm`GUZpG0y zd3$s-WB+CE8c}xf6!TL&C@GJ-$xe35k(WZ0Iqi`@4MdQ$^?kV{a1I=1xMF}RE#d$F zw(fs7j7nt0>qQ~Au6WS+!y2sK*@gRyjV9t1HI=^t43&}U?ql6|?<;gK-3y|v#$lX( zcV>Cv3?uTNo<}&fH+y#vUwOn3r(ioEY5$qFh?!5Tez#p$m~O6g1ymZHWt8>zG8^v* z1wm=(k?e}<&@j_-rp|HbT^ zZZid3xkVaBXmucELIi6~DMYWz=11y&Wclm_n+PlMQS*YDE9}E`CdS7db*c8!2I%@$ zLr{*f(#3O3v1(gux78Upsre&cnsSKO)?Cac(oV?vBap2H%IoqGKbqf9cFJDmf!`+X zo~u~s>n0v=YHe)K{%pF@?iALR^*Y{9jG?Hv&56;D0OmPIh2^ZH?pUe|@&KZFF_YeBxS49(F|pef}cWw{ zLMr`6PF!ccfe4xZD*=eE%{@5Nr0BVANs`%c@n)Fknc&m1lYrT@^w_vu+n27F7coHDZrHFzZ> zMdx1Q<#wTf%c{Z@!1*jD%OC@LjYk8@hOqyELb-_Zj{wle+iXkqFZr}s>y5(z;bVxKCNC z8J=y8b{Su#eh>Y90HS^6lyO9Hsn`W9tIKJgeev93_OfX{7)2367W(BQL_j!aJ~Zy_ zM!$BhiZgSRZlPWsTe(!6uJG)mwo;jQ%fHiJxwW^(h8+Cq^Bt4oFr9o{!;pTd%w|{u z-8b=*z4~8ZDfNQoi&&qrxcDrRQ-f1T-O~hkSA=&jmB=>FqZ8~vR#+UHv3JXzuDQbw7>dCgdjHz~szez6iP=OotqA`h|djjG50zL9R=O-)K zv}G$4-o0{t8hyrn_r-g|UOBHwJsKGmCXL6NP_$IOoW>pF#T+CfbJKAlzI8opkg~om zlGE%#$q7hudm0}#qMD!EH7?5bnq#(59QQ7}@Z=lUe+PqakzYSfI`T~`w8|W2f-l?+ z@)b268jzA{O}+{y@IK(e_Nfb&eyOn={a2prJ(oIDQLbvo)sg~&FHluRJnDyy8Hr-K zrA*t^*057FNuATmwEC!g8`sn-vl^yIW1Z9SUBZ`_foy6KTrUSnmq&#c6NIw+@B+R3 zp*EK`EIq2QM+s5scJ@#FAT*%y<0CoBYpb#9k@m6xDKx0b&xLa*ZT2kAZjud;zKIlF zr`*u%o+B8N$UNU@K`J7|AJ2OilYm%${GtJEKPE(TvLyrnQ+ zMZVg3@h6=FZ$zVZ{POod=vkshEPZ`2DGwuM*fRDx>?pS$em?QYRTpy+UHSB}C}oP?a0+b7puU344ky5%M1+w?Bx_F-&M(zmtR!T1im&F3GKjPn&g zP1e1hddf?Xqa6RzdGCvwwnFe7km5z`Z!;P9%Jg)oR|_WwR`Vl2Qo=#bdGl0zmWkl?`oYO;1wBW!J@G|+^s`o z){1L?pSVQNSOin^Cw-7qFTS^m*e0d5^Ku8n#d8?v7N(Ck$~UC&HT45^eKEy);@4d` zb8ncW=+d~RESS};(tWGBXo%FOK^dd!(oLD*o%}DRdTX({Zpg-e@wZYl{NlUR!U=#(XR7Tm6*`mCa>chRY5(z$I_s2KwIBNU?&mCd4EK@S?n)EzY5Bt7* zULR1dMp0|-GRKu&SM=mXJ7{?^l`i1=T(nk>ylJfWq^K_7Lovl@IUI!TZjBs|VyzM% z&5=nP<=J}FIy1%^XQRfga?H-8{ooysq^R%Xha!n#&Xpn*h!g9S;}RZSKB=M zNkOeq4~w8hEO)X*dn$K?iUonP$qk%FYg72OPatNW)a-SorHfSm6kqr$wjWcknyWA& zGu!_GE&OsNK@696pe ze%{hsB5;UOi<4`gv5?yUC7|!y`nd|92Yulu1PBc?^~=fn z@}>Vx>yP68N4!DjvyAHHa>q^H^FIfMjc78s1q*nO?E~?`Z40Za2r{4tTv>2nlJ&NR zwk<$^0+NvhM`hHKoGV@ppuGzmaeiTK1JtPt{lG-R`UyV|u-3))*MjP_&%Q2fUhi_VnHS z7!Gw9JL+zSd~2pkX0|VUI2f{0-F=&U_u?r6&6+AUi81H+@Q?mjZQ$2ADe!L1}5umMsKoyLUnsj6G?p(2quzV=QY(a8$2fLwe?qL>`KSyKPXN|zv@{j(dtkRp+ zg{WI4Ziixn0+=M4YOP$BK zHq3giL>wAR0#_>u>;Sv&pp_s85S&`JesV=Do1_usVtNO75ZRx_y~9ETJpnUK>8o&XQx&I0#0sa!3>`<@x z`DA--oLrzKC7bnqol6d_`y^x}Pd$Ay_u?8j+gRz_!zlFUv3yOJgBHAooev*+zOiDW z{I0=3$jP*DG2nrpbO*JYu2h`&Ju?>F&d>TllU4i_x<~d-`5f4DEv74N1gr*9fFjNC z1`_C{N-k@Lvx(PQ+(@0P)kUXBGt<>R3iVHVln9C>0F+ocQu@~OeXUcbU`KaWl+-rz zZ~EP})xQK|9^b!w#u0U6BnltGk`V#weBJ~YiE0bi-Yrw0f{i0&Uf22UdoP6T8$@MG z6~1`-wuV&{cI|n_Vp?e(vpe|<45y{+0i+0ypseo;BG>K^43zEd&bbf?a z{+{>VDp~#8&%^X5g0JBhdD1sMH*jYB*UlNVWT_t*1+_)dzR~_rr%@kG;ckQqrLIQC zNkD36A;iZ;HKFXh#c>ni9Y=7+BAWkH6>+H}+IpEmSJsJx6m<_A#D!hEujS==v2(t& zK2GF=$jo&y_!*r6)iHnHw)N!W^#!K*mXn&$54W;$H)+1f}k zS!0k(P5KmWdo3qwRJGptnGulpV(p63+x zR9p^UJ~uUhQ==H*w%4veiKKY=d@RamR970w=59bg>0F9#?~!!*NsAextMENY!glI{6xe#5MnSrgxcCTK8psf6H0t(>h1d0A5SomE*i4l)@~E@OeIZ@H3eIU_x9dUN^BM(Q9y1%?o(ht|fJT>e@2;?*G$x_t$q zXrevv(uV8Vz>`5xODhmi`joCGo;SCOjr8gYycuo($BC5*MQ> zE!xs{_@vy<_R9a_$sHw^NIWWaP_(&R8!`Z*U-tSfY`$yD{Htl((mDvbGlFJL#=JVS zZZMh&yj=JPx<5Zhv`5(qd3Rz8czD+^u|~u1#}q7yt!7Tx@MLN|#Pas~Q3C3^qvM&w zg)guaIZi(B$C-Z>L0$hRReXXdOpwSFSXg*8&7rV1rcXROf9J5&9^aBL&+shX4J z>I7Z`1-^4E&ssJiB_Ct+PsHUR5Gp!!gg#SMOL)b;;s#ieINlu~q-*8A zer0C?@hs;(K7irAV6gr&Ve01_`bJLg_=xF`>kH_T(C7MY(Tx;l>6c*EjjgTzeLET2)$i;UZ;&(9zTD)DL2&@Dj+O;bAcaz$(W{+l+VO^y7WF z#r+GYad5eOfi}gMV*WwwZxRymRxRlw)dMq*7okcVW$YjTTFVhJE5=@`H~YwuN(~=O zck~N0HqcRWzQ1UtXkJX?R3y@!d*>->dHp`fu*xQgfJRRWiab0utZnix;d)~^oI zBliyE16Ykwhg;f|Ige#L)4tX_)d7h3tdMUz1b!y!_7z%WSi{qNNxQ3|7o;RYo!g)Z zekc7s_uq-QTC?CujwfL1FWx*#iOF&5j2W-?{sNo!r8;vKj_pZpDnIIz4yI4c)Nn2~#3Rugi zD6qnfvVZ4;scJy2SDt@4lZhPZ@N8A);i&c0M~ls(QKDVz$$y!Kx|B3YpeaBgwH=0i z-Z$Uf?2Es>H%73}5Aq26?lMt6>as>*shba_VjWrn4Q6*ZEiCwV<7zV@vC1E(3FH*r z%q99TrmF~skU)PX?h8YewRDvH;Y!RI75opZ`qqP)Bb|<9sH>#>ZT_Hu&gXodoH5*N z%9pgQ5j;~~F@Gp;pyPQy2HVU;%tj-j3QSg{4u=NWgjhRN8fN}(5N{k9^HqMg4+ZPW9LCP~p?(4Zf3}f37D(v+aM;m$ef(-!z zdNeDxh`T+os;a78gZJw+O}8e&^qE(VZ{ z#J}OOL~;Qa$|a_qbzWt`h>X*CTFJFJ%f{h6+HP%bL`O%bR)`3xbG`@G&Osp6ap-!Vl(gRSa0#>HRX69x2nFpG~}NJ-2_LZ3OiEWHb6R zh?-&dfC!g?|6<6?6Faiz#i1*(0@RD#ZaPu69<4JtG%oi^p87m&H;im7?hz{G$3{#! zJ%4KRczp;=;zk$0ul}%WCK7eg?`Uzd{TF>=$0%u%pojD0zFy-YG^a=J(SywE=kn{KCUVca^SXdoh!UwYYbFYiUkUcPZ|? zHVjWw^F1ZJ36TRzqM?hMiNIegsosA6Bpq$RA1*L!M34|f3|?tMY;`0Vh!+38WjmgX zPkW#M{@QDIBvv5$^|eo@9WSVg7&sQq7hZONkRP9y&?5tXn7+QnB%q+F?}^kQY3J-j z&39%EQJJE2LJ9gVsOvRefVCftt!vv#znu6yelMIxWFUeZs&p`>t=?0&k+yTag(uaW zA#k~&ViqmvFI`eHOa3us?FnX8+0+V-MppqWsdnr16)z?dXY6 zA4I@ZWbty^1a8dP2R8!-zLQ9_w8drwCj==Ch-qltR}l3ZyzOKgI`dh^UtqR8Zc1EVj{1FHHow+xu3 zz@neaA8iJ|m!F@=L5#6+YWW<8_}HVIfJF$2tpCd7slE3UU%Ci1>&Q5D+L*l442_5RkCI*XIauz`q~b>?46skd8_c zq7da{ga^QXU`$26i9kU7jYN7je1GN#J4sDP2nf`k_YcT;dQ<`k2suqDF%cCvy_2*L znW|HB9djwk)FB-7L$bRgL$ad3x`Nq$qwEUO)FWbUT@hyVkH0iG}=MMuCDp@o6+hY3&u z9{P~`hqmSMu!PO93ubV5IQGw6JX3HqKxw%332r$J^yu7?@&W9=wk4F_deFV0DBABT2lp59pkhZsD;nWQ^$0t;N#zTPl zh#*adj_?^hPLvc~l9VP$m^4aQ0nuNW)St5$YX~2kF`~4T!BZ)$pPL>kF7Wa^bD;Q# z>K=)PGwIWSq_|PIBo=fMJPo?ptlUEzTX;7_DxYil9|CSUD*1GVhldBnp=AH2=i4P) zHlJrVFt4LYQ3gUD(R_@Qpj`8VQP?Nuy75pN9c+}v-*v?Zp;$qcRts#NzYDYfE^5OE zRoZQcHlEZiRU_QZ0$ z>?&cYaWCDHxt`Fz2P5CF&{H+2srBV{$zjELZg9=_&AMtc9_B=YFjqdALrTx{q!#gF zU+_)>kMzk>T5T#D_7QC_!?*2eH^nv;XVDzGNjwaPms45YL%YeTNI5GXcDZ_7kYHuB z@nEW;8911;FE?}g6BvnhMEl3Ka|N5pmgV;SM6NnDd#QAZ`%4a9dehW+WAe`Yz+lcI z?A;MrprNp8f4Myk=U%Nmt1&F*e{S5KY4`Ol=(2gT;A})C0`b(QTIn-F&NVukK9$=< z6Y#rLE?HHNE(1r;^ohlCmcezHvA#iF&%O6_FVb_l!WegM-)G%U%7}V7^c_=HB-c zJH1wqo9%SZ)4v>>2z+NP)m|69pC$|BNq9GYVr~P&TpqzEhQwG=oTebnCE1&V(;|+; ze6nZK9(GpORd+&!>2B4tVyE{Q4s^c*oUlY_R32fMHE&nP*qYcp!|q?%L{`=!U^~jX z1rvg&h~6%%9`AXx#EBenRb-rw-~%E~kBkSZ+Pk&uEuaCV8<@Y2Ck`A>GNL;fdWciEI~Zie|uqds^k) zI}~N!Pq&v75+vA~fuLv&p=hB4!hTM#hn>Wec?(J<)DNX}GX5yvio>n&l~&*jOe#}& z?7v6j02iNj8e*0Ap4a*^n$YvV8n1erm1Q^rt99Tc@ZMdG3-NJ&NJ9+V;dH60~g&oc{6ND5lYo6$H-f0+*#+(CEwkR;1jhM@r*hM$7ZfbQ+#sd}91Y zoU+{CD}N6CwMe1Y`J!fnn^{P!mktItn`NGYt{=uQW0AHUBT|jbZTH{rjw;$goV96) zdCHJA*WR}a{WC?%{fBR_PiK7C!X;?l*{8uPQ}wD9dabF5b((B(u`ZNpc zz%+2GVy~G@htaGCAA3>~V_%G0wz5zlFn#S>+_7vJOth=wkG+yuH!X599q&}^H$wN% z|GW8Knrr$FpFszNrO@I|^I02xm1HHCDh8h_YPn1zlN`LVV#;HkV$h+>vb_X7G)|%% zvPrak>Z{6*4u`gpltFmmrd>Ebr$cd#Yy!l>qIp4@?5m0hud0O{HI__wXpVm4EwBpK z-(GpQ3^O$+S(P}j$+&l;aMv_-DoPL;TW@wwTCKJ;4x$=g+-QKyY7)9E)De9QSTmVg zua)WtsZ!=Ml~8Q@&l52v^1Nn2r)yfy224s-T z{A=BkjrKONd(iq()lqpfXy*BJh`xfOdTnc*VvSZgf4)P*_vPl>1X-a~4W8&8eEN7| z_)!s(voMYK5=6kaW`8YRaqH36X+*nV5}$?>=)D6gt2JjTdAnf zjr0a)va6dWKM_wlsd2+jRvF8bz@LO)p02hwPid~b0JDNx-zPmcvZf)hk|-Y3P_slN zaXw7PFs5DE*u7jCPBZuYEhOBFP4kJ#-of$dthTLyvc@WQNOM>XWh{DmsJf)^nnI*$ zx_jRbq&$}avfz2Y0)e74=Jw}JV7g;h?pcO@FsRxD#ijSxfASt~v@EMl*nx*9@v3Y- zt{N_twa3!}mvuFvC5h8jW>?29+jXO42UT|vitrNs7T;B-t6|I5T9WlTZ%51v*Q!C5 zS`~X^EnxlN{FR0M8$oY&t4;-!`JP3;wtLOrs2`5zEa0>DHy?IW)-|3nxHuV8YQ>DT zHcM!2{C0()h0tcmxL60jb{v|sSb0HO?lrIK_zzd$j?E-iBZlxQ1*+4EgrALA#r&a{ zlX$B`6{6Np_AI(Z@Vf%}OjNAy_GNUR=riDzGuS4n8mv;!Hqw(W{KE3oz}^MrnTSh^ ziFFpUrC{*Da`3ZC=Mrxz(*r4KKkG2$9khB-i;9T$KlHgUpX@X{bDmGGG)&M92&Hn6 zH)QgQVS=V_E3Rv``bd1Q_gkZ!N+qL<3&Rp@%lgz96aEaK^_>y+@frt%KIK!MxG=8E z%54;j#zoFj+=*EjZ(8iz{{!*Pw$^tT+qMT2MM9W+73EntRA}(! zKRKN*co-~j_;!T;*XJvD(3NLFQ68Aw5SLJwO5DR(NYE*5*~__4kYDh;1O=HhU;No7 zsC(qiOr1Z7F+vbXE;B!Xw)@sHw%YWpWa-|X*4||CKCY3%b%i2Z$IHnTG7rhFuqX~s ztNm7xrNQ#e;Av~U7o&xK3A9plIh9%#S>aTyAKgSbgiGmCl<6%0V&iu!THY9`MdR`Z zG+|QO^EaU9=g)w1hvp{DGHFP3gHk9shVUR^3^QoX6R}aFsbUKs&4Q`@j=M?W9Cn(d zTCG|ON{g65>I|>%=1%C4L?-%h=v`l5krg5^bH(;CaN%D6_7iJ!SVC3LX9W{m7=NYN z*8$-esyWV-(|>@80SAbP>uIndL_H?vlMW=3QnIt*e1H;VQTV1rpfd7{1_JBDutQv= zaPH$Cj=}Z=0vv8=;AK&>(NGY?ryh81DFetteOnwtYjL3qKU{YDp^v!J*C>HtQqoSL zb7)%ByZqN{l%Z>&{HxYX>Y%GGY5F}|H`p^Q3kuEfp<*`C#^UuBCdgbjUu(#g`Bf(Y zr|=q=r(U6#4*||nriG1U=5zSTc42H966Z&rfPY-sjcPJFDI_b3Y(+)84ZTp%s!;d` zay`8UJ^=|6$N69~FN`*Zt^&)<%>+c=#NV>53rqfjj4Vsz^C`v~4%QqQtA-s#4tfL1 zAiYn7v~_mJ0}i)XwN8>_!Y1xxKUlymBEWwq=%a|K z9Sh$@D#RWcZd_zxUB(9tINOulz$Vg`?fzDDTr~)E9vu=a^uWvanRw?XOZKsX9t|P` z6U;}*?opA>LK2HTHs#4*ago>`;0W6rKOj(;usLT7))csU`gz+D{c}O6);A}UA2Avl zvj3SF4>ie?xDf6F`4|R?p^jREBr3oC0u-`;XNb#aciLhu(p0=igz4hgMiG2i&h20_NAn#1k z4auT+m%`*Hz4V0Byg^Z80(im=ya+sqks63L&?Zdgsok|Y{SK^wP`w?3&UeN?)`lZ( zKXH}kF>5$ba&=bKFjJUc+)^;txxE?wWg%d%9crM3th7h*rYwio{$D;+sq~`sEbkmjNwiLPH|H z`A^|}Gv!$P+Y%HClK3NNP-toJx%M`i1pP>nBsA#bfzQ1CuKCm}7e8n)_Z%WV>5YfR zeF|-6;tls^mYimN07WRbZP!f3joy8j#SAa!_{ZOuuD z-}(gYOpPZp4H;?!v~|)4zH~?;gnt5`Mv0Z~ET&eFo#lA8nZ( z$endPO4^_qV&!uMVf<10v>%dJM8vk!lcMQn#%r{L?)RRFw>(dJ=zhZ_|M?I=&e zL?J#3=`Qeo#ozn9#vH#)stzONt`0XG3t!#f^X+e6oTzcYm{{|cew8Sc*>V-4lCi&s zqEJ9`4;{L}Eyn5(vOTxrnquUe+_s{_d|H@x2ssP4?P3TGfOcSK!rzYWOwDbEF+YF&FvSf2;fQwmAV5A^TKkTM&EgDbRjjL2 zDHz5Wqs$#0@>FvOi_&6g-9^|{%%2-}DOu8UWvTL%5LB4kz?2R%M^`(C(1*hbK|&VT zg?&FM2mKgyYZR6zHE#h*l862qfviuM>_1Z=;KBbJKFP#_@)w5sfBAt>A3e(F5orhj zHc6JH%05A=3qt#!cbCm1z1lw0PVH?=`GlCG7_hf@GJ=*adAIHLt$6cH$waWr!>lmWb z7H1P2U2H$5VH8HdRpq6O66_x@rh6xkip<$ICg13S;{3nL z4!X-+QmVI)4`YH$^raVf_w&DslcH+`GE83#X~=SZUBDfGG~7zDPYWZxMbT-bfSs| zFbBSOVwlr9^kFN?KE>t_Te`OgXp$~yrjv6{hoaVECI*G}V?zTD~a0*o+EK10x<6ZVs2AY6$_tIuSvRMl1lpO!Z}JNwRh zAX>sgwW&lAc5p@8qqLmB&9qs?cZYu>@Pj##g7_z8{6MqXz<)b$G_iWP*ZWC7?(M1l zEtc1DS4?6S*;0&ldv{lB=KxqW;Vv8Ox3&*UDiQ!@#SAKO1G*C~-h>@gu%%>bxL^K>tA|{< zFdW7z%a@Tac(nA!ThBZ-@Hb@4i}1#(sdkS|%4%pk@Qdk>c5gpugq*LfuK^73l{V<# zZd^FW;qJpp{aWd>PB8yD5ibZJIt=aijlzQV?i-**^j=vlx|W;WEWsLHwoT(;qe0`_ zs%>LGkEf%}>b43#M5a~!^lnr>+0&LQIb|1NzRA9U^(y1x<9Q1a`fC!dCi?&a0sE}s zsWZo$4Bp{u_WFD4y7X9W1vhW0ca$jy?^u&K05(lOaQa$#2J%}5M$vJE(5qYh80e@W zfl<2&sLCfNZJG|K>Q_CE8aKLwo7>-Bmm=H+ANMKds!hkUw-z-|0etQR^u$>w`T%1& z{Y7A7S1h>;=`RgtsU1}YSbWmVc#dUcFK$7j=1Xo<1@7t@(^Qz~W^S5LUd+Vh-XA4#y&XALP z@4J;f6;{p00huxezH&AHJnN=|{Dj0Nj?+mQW@qcgn!ndS%$lw1S7tdaXGe;R*WU>f zpPcT@V%04Vz@b;(v1z}+bzswPwSFLHSiB*ys`Llm{2YTWeBBMkPG*I9zis==>||8P zFBF2N6_=&a(;T$~zL)E%vgK=}1JL@3jvGMZN>|naW^0!Qa&`c)Qrk?*k&^wY`(7h3 zYb>=*^#RZ~)pD(^wKlPdZkD9Dl!1h3+J(5#+59AHX!`J9js#lCC+}Z>4m#?tyxvZ0 zrsU)pH?w`N3$eFR`Ok$5Lc5E04yV%?EhvWa5otl}0!Ypb`2-a%I{oZh9@jk&Tw}_A z7vrGK{Ob&EqcCrfjaMQGCNrPX6qFH>@SqeXd!Ywxg#K#aNdI_4zDO|ddA((7wD zzHz`4K!!9P0ccpp4@%J#P@tpX8dDD&=Cqg|h{*fC=6&a!;rrU??Yr&|Uy24K1>c{h z@5-A`tGFmDek36mVv1INV~ChZm(H>JTr(FG`rovkyMNY_h#m zty)@l$}jEv$V{Lu?I?|)R+?WqYT({@JCvddIt|5=@ks=#*m^BC7ovX!(_k0A?WixM ztp_AJ%*(J){o6OA+-pgL^69p%Hwp145qzhW{F5Tf67dyt%@ zHTV);TGHPZdif~32eOP7eM_!zN-Z1cHuzMhVF!N<>|vjWPgj~#1yh?Y%( z`6A-B$IBEd)pNUp6O43Tr5cE@L>dFL%)YdcOJOu zKrYfq02?nY67JL2GKn+FH8UG4%lxImiI14m_g$g-{2g{V<@L@U7VB42xXV~cMH`*P z!{>oOE$;jd1t=Q#M}(*}ASYY8+a#sx99qU!*D?HyeJLCfbJSK$qass+2h#h-u1KOW zof;Z}12;YWM_vQxG7Z(M;4j{FAUqn^H@QGaqH>e6!UqPJA#~IVXGni3HRRr`{QA+< zcdB^e$cP9JDH4T&Fcy-N-yZ+%+vdI`ISq@+S6g>CgwpJP4H7LnG!muca6-^5sMQF@ zq-kI)kJaeY~vzI$=6oY*A2+H(B&?mjh zv+a__c1I1i(<-6b+IPJDRdypw}`$S zLo$5CPO%0>TptD2?p{-RP$D>?GuT|pl!YF`gj~kX^R%&m^K(AC2{GwFQkc)L@9Uq( z1L8Wzzxq9OWJ1Tyu#fW_K@;x;42J&$D5bNBV6m+&6U?0n+`&S1!6@CK=~C%oJRvmR zm6Ery_KCsm!D4L*?Wdo9PyMFQYV<7Ctb5>5T6j_aknr9f)@8^Jr#|s>rjIu0CW1^5 z)kMbRo1?YM!6M_x(rGN-f7w`6AsxZD(s@`4n;I-59e(cLcw5*yC*5Bk_C`GnNGW4= z`Wpf|x;zQZJMPnCL7bc&OymSN!d`Dc!V{tsVW;eC&`AtdefLY%cbX7S*fnM#Y7?9$>b-1# zdl`?|qN}pNsIOF`U8H?8RILzn``uSeE=-q-SgowjElv9~GZOXDY+Um?(O?azX{|Cc zKTl|u&w;0*>;&DuutXKInu}#==AHYKldli@%LVYmB-g~|P>h+IF5SdMOV+ql!j}6P zU`)7AhM;2Bz+e;B1G&wTJ&_8|vo*yZj{#q7wM0c1Nt+eyAJ%SEDz)#hYS3*P~_qZ@-Pv8I1j-) z`)6j-HDnu<1e4NC_>>zN8B=1{2+=ENhK{R&crsLJAN^VcU~(3yD+>d8L0Z4H@Z@wk zniJ~ODNXvFKiVJS%-^Y0IymoV1#4xLkTW+4IjgC^SNwE4hhON>|HS*l$-*n1$NP^l zqr$LaQ|bm^(v5zM4Hii!EW5>;^C?>Fs~F0K%2U%)Dr0ifsMS=Iw%}X*F0O&0`J4Wl zM;4VvEFox0QAt4hi)R1Vcunt)Ke~7<3sWMW-Hat~cVa`HV(g`xP#qf>c1hcu`1kP( z8g6A~xJos0q3cU)&?{x(%hyAdl$PSLswMkF2SgnR1Ljd|cHUvUiC~)#NV-_UTw~$y zUvd=$ptD!O`HlHEcbJX3^D;ioiH;m--@qyiKBFE{P*2-vc@opMLe&P+phYl)F4=AQW7d%>6Rubx^v*I^pcSW&t(Nu3>A26S1FG zjajsS?>c;m=c z1@RNvN6i(P7y#KX!!YmuQw=6`_}x0+JIn!u&<;S8)!6#de+x7Qi%qTik2a1Z-R?nqj!Pnj#;Rhw-bY+BGYHsd1uDF1) zI`MG~mP)s!DD^7$qz~eqnZDN(5{zl}7r1W7(yPeZSrr~PhmG%%?c`vj|JdS->zcQz zZF2FE;W(!kpi?A_*}DPR`N^o-={S9N?giE7I~ZcgMWDRD+q$Phu8=QNE7wn1=bM--mFhHqL?6VNrp6Lk>KYYiZais6hb%F5W9piyn9Jnnl z*~G!%vjqINc7hmhVz9@(ScpONA0oclG04;LqmB!1 z4QT8zV6b9D@?ZWIe_~yTU28C^bRc9;=RS6Gj3glz!8@-bq2jORDuI6M87GKn zIVoss2Va*eooj)h!Q7~tJGdaH!ZM3<4w68A)b}j9O}E?jTg)2@_p(8IhLq+bAiF&L z!RH)O<8dQ;NON5UE*&UL;3z@90X;f%edmbfuC{Hfa~CuRGMi6SPy_V2rF;*%+xSKg zrhLsB<~ry13Q0F{uzJd1;9OCN{JK&m?m(D+?JgumDV!d>$@&$D&Ab8A-c2CMUtUmy z9cbQ4b%3tvHf^rT9X83)>o~Cg=Ufl_i@#Df`-m?>2^u!0-UQ=lifif}AXqH9>UG2F z4bLnr`EY-Hwq-aZtsUbMWfFJ*x0s1Gh|MioQ!%lIW6&=ZBJ0wXf_xT}g4W2Rw zlWh?UBkGpf5F%k8r#kfM%PVZieRn~XyLfjyiSH%~m?R?_Oq*ie1Wxt3l$vyE6;0gg z{!21HK8%4mFfb5zQnw~22fFxduJB8}02(_|{E+BUMW*;-NOG<`p-Ge6h>9_)I(R%P zgNb%WKkZgJtC}uIJX(nc<@Ia^c9y?ZRb*UK<6c7DjVsH1$~n(OE}tRnd#p33_iidI zo9CF7XI)m27QzA@L*uYfqQ5l4mz#D94_=xe(Bk+RRu0x=6Pg+RW_M3=^>yi_ReoBR z8d+U$@rdPI87F-GYLFKor!WcW*C{$V@zTbN)|0glep3Dy=M|Kv5HyG z-l`N@KbrvqFN7VB+#6IzNipMCe>tZ<*73-ow z|4f!-A*X;ilUn!9Lb87JNNTHTp=!ME#yD)ZHakw(nbJ7Z-rmNaVHoM6|4$k}m#?`#is|HNh`g5l)$=Q0lm0P)ogKu% zV>kCtW%v3jofqYD<8Kx)N;q*XV)8$u6g8fx6JMcH<&O!Uq5qqxAuFyD3RBIHj_LZF zh!V+zAbruAw5J|u=;|?ku%LyeS}Aj5*mLWFrae!Zc~~voy|*6Onzl~GyySb>Tu#eT z6C#kEt45VOovzFHk>;h!!e_Xl!LM?`L4hLx}FyZi1xw-@Bwg4bdy zt_U8ke$l$yt*PwgF7XIyR~Ug=C}iMsZA!6nL9WL2lQFlvL7gkw(uuduKeBKZu^E`n zpc%dLeb8W_;=_8~$r~Rvxjp1Ij;jO}o`$!0p1 zYR0Uvki>19&Y;)Avq(=O%{MeuinaM(5;y?P(vWeYE|u%Deek;(rYL=I4={1#^$!1c z;ynNq2h^CSTCEU7wNNWaPKfP@>S=vof*gF>A>cF!eKM001sd z>F+(@;O+o)=g%!2JOCn_fyGKXfk_viNYgzEY5N+$W?>O3s5T87aF$`5orv^63+E>C zdiM4zzv_LbJ7od56#0a}E4lP+NO^0{bU1A)Ql45x$ zY+gqE{ue>@H*mGAkYid(Sq6*o5EcVQL3Q)+_;|h1;{7S$ z&)VVP;o00CFSsxe0d(FenAoGxI^B3UftSec6gY5^5pgI)Fy#QOpU``#Hk%-?U$SX# z{13+zprjLud%sYL4j=E%GVH93X=!LGJq4bQt0$tXa)uVHYiHCZ^m=nG=gQ?wdw`~k z;1xJ(;%utK{}Pl7A&3HJte;O&-`HlH?SL(fIH?~Z3M!xK40ao8-+GZ3GC=%Jvo&G{P6 zpc^zD;V7gN3<(W4&zZgzDWu2LaxTjEEAJApqlN$wNb@d@<(07g-2&48+NyU^)P>N_ zUXEu2MiVGtjDf)9uS;iSj}xJgPs=F8O0#SIS;q@4y|w#!Cp`7Y=W3JD7>Y>#$;&S5 zj>Unou?QthvhdqN0Ou86Mn?)h4n!DT@L!Fv-x9q$+wa}Ld;C%-zX&M9Oh={F5zCI_ z0xlz0095}?M@GK{Lm|iT2vAiEzkIQsU!{aSHG9oP|?H zIIQOXJ#yOc7Inqx`#kg>P5?@qCE9K5M!_NYn-HLhE*1EiJ6>+L9Tx;D3cq2C}()L?yF|CEWxs*cjtigI1H3v4DU*CjqREq z$mKZ6fRpkHs1}EDw5`Yhlpd{Z)7TqfFPMPM798($)_RB2s8_5YMlCh`^e)vHO(-w| z(3g!;6HzB0N~Iz8C(a0vq7AhHa`%KBe3^2m1D%4)$~#~-e{XGGfUz0-j&HcGZuNooK`{pjImL zyx#~u@lY^y2F`Y(vg_c1UnN@+!KPCt?+J_RF4z==jc!T5W^-IZuflkp9>X4fXoo{~8&wbn|`wN_K*SBpylzm+di z{&e&>A93O!(*b11AXF;>e_X}%3(L{6txmNk_Qvia)@$q{DSyzJ{h4nXbIBrX>KrMxuNPqh_DcQian32Nfy{>N3Gmu#3nkF8fwrc=eSz!BAmr)y)TEkM-9l#xjnCE<}1*7&2@GlmkBq zG(w(#ZO|zGEbh}E?Lb$HtmTdS*L&EFKqZmI8<`p>-b@`xi;4(E zCi{!+fI%~N*)B|h9GOYjo^{@d%Zb3cCYs0yVyX_*yd=n?peRPe0>?ZwuyvG!6T|ng z9UFH0ung$@Wy}!0zwA7x$sH`r7u~N}nN$dWz``OSAG?tp%G#X9jHLs)JBuA|5{-P? z#)=GcD^^}^pS;H4dm8%28zE`{F`mLb9%s&<1{p$rBOUQr^R5Qj$}+QU%87sszTkR)(N9u_eDT-uYLvTKF3rVB`R#eh zp4%g5c_sMq<}gH!YEcFzR>M^LDIz2vy0;CQDVRG$m|$c?`LZjn=|3Wa{6_2~?~8UN zthG52!@0gG))byGB|?MOjjsl3-|Gw=>;?BQSX4Hut~SwM`gA+6wm_=HZ03`n9m82D z2KAR1Ku_(3|3Xl6&E&=6!(ioDzYLy5eL-ba2RJ1QJu9nJH#W2mDJiq6$1M@dPLcL_ zy1WVg!dO`2;wqGEyc1*(PR;aF%L2a99M)5^V3R@&FzjEEvmoK{*ixYm#N7 z>I8=c^6~*2g&gr%69pO|g|*%9CcE2gza0Li#|#$S^ccAjxSgi}X(8No=k?q`r|q0z z+TG3S`+BqI#gfTCMtGJ4pw~W%QR8YqbWzIuf?zw8W&0<~{oGiD4puGdx);R~pe5Ik@C>klswzvR+DVBeoYeeMXJ zItD!4tNWBF3eRrYW7{Da1=WsvNl)><}%!CuH()C<=n0 zrEbBwzg8vefxWWlIht9W@DgO%sSRkuRp=xN_MHX_hYa6CBdRup4y{PvjnozD1@2wE zAh#t?1-l+t8Z_?#>Q}De5*j2Jc&FRHZs`9=YQRl)YHEl68KFwbm`j^@uT4DD{yx_) zV&3R(6*MtNxWSL_K`d~HrlT*b?aN4Th0_Tmhb0O1;c8h*S2V=Q<$@e;r2D#aIh+rt z&1`v*xkx-OGk-R?7JJyq3u%h9w8X{MU06fPCJm6DoD3g5ti8ROdPja&yDOnd7fZhY z&6VpeJw{8wOo!KAX&!hw?dMFkh&u`hf&SvENz$fz&uUU3AXI&VONd5zR>U*uYY<-# zQIGQ@!oC@nSBWq{6d@`_;;7Kq{_08Iq0&&3IWy4%6NmuCrqKwG10x+KoUi}7El5KP zN7N|=^;Lr$fr_ZZfjUt8MJUBM3G6?ncBMYeU;W|+4;_e>MON9zAd)UG_>ep5;zY;J ztM;MVNe2&t=p-KH7?4I1(A4CB8lY5;hM@Grqy~OpF(lR}{}vT#5pOMJ*)^}L@RdXd zjP0vAw!q>w>mB~PWyh2Bk$(tuUA^8PPQNQ+xQWrSAhF`PPFF4gB|OC@f)F`*WP zA!0s29>u*+JA!UFY)Yk`mMRd-OO6JF~r?Y5R!HAeLt1VIp-ESGpYVqp6s$VyuWhE z&|*j%^r9qo3h?D7f3d=`SM6b`+%({tIzrb&2iwWl zs8XZ;2%Ncpou=07iLN2sQHf_rP~F9Z4B>txBC=@y+Lu(s=o0YdGl8Cgbf7T*DC!+@ znnXlZhuQQ2WY&cDtUCg8I(K9`R+#)RBgr~N+eZ?mIFg5nkj~qgntCS^Wre$eAIYBo zNP41Gq!t?of+FiHWo1&PZm$_HD4@U{O8hs%ROVkcg$797Cta^u*Ytf)I3-{rE_9S+ zvqsJYrMPkvc$4YGOv zUa*`gHhwr?N2`XB`8|?65YHhEKR3M)*jGR}f{@Ev%~k?IB{(dd z6sG!jRRHPf*2kj zvXE5Q830i#ycl52Vq*G8Kp!Y?Vs*H+l+QUXs{DiZ?-+`WjkU&+PS;|=4rkLuOx4t8Okik}*n@-eukz1(x!Ts> zIrDv0ODxQx3nnDcF8N4xMF~pypr26k1d&RFB}!W9Pzlj}7PDO}&|Zuk5KK0LHZ(mG z((1JWKMEfD$!KM$eNiS%txaq`Q9(PU-m9hswDf>RIYafIH>TD|`_BjW3T2c2hQ;m1 zsjF07EVCnBdh^jJ_F2?wwT%+t`;WIjT_l#=$2u2~H9SyzEEA!6shw(tL@~7d( zZqtF>Vd)|)msZQF8ZCMWE$$&!kq-_^&LWb}f#$F5*RC@`uO?7QAZqpe(XsfyrnU6{ zVG<(0c-6_ix`L@pU?7Vod5XYkwCsC(L)w_123Cm};_dFeaGlIP4* zLG(ZDO;r9gRGae}GkmA5UT3X)?_rnu_z_52H0+|mWVpeQ|LsQK|DV*66if$udj}WD z0TV|GH$GD4@0AEbM!Hr+SS|G%&+xFyGG(9#Jb>MiFYn)@H znMz+J5{u7vy`M0l>3{gO5s}?d!oVwyEuQHC z1Ph#|?}RV~r}lGwrtrJVsvCOlN>a@CuCU@ykHsk0SyDaKS<@Aq{nJUF9*t0fnu(7q zK|_;$78T6631)D7h{1TxH;504r~p&4+5R1__F!=V5sDDwYuP%h?N>`1`KUGN$8wjy#)CZ7QwL+8$)1<)=iDAysI!kBN>Z zTTuGa_xw;zc(+<|=^2TXUGu)VJo4Bl^LVK=jbUt@agy0zIMbnfT91!j;_Dl$rbqjm zmUNziXd!78s!DUFA+VXeQg!v)8!h2DrN#@H4=x}@)2Qe9QGW#Xom-FE(91N^23^v~ z0`rQynhQe$y4kWY&K@&nu>8loyg(}p(^<88O1IDc9m(H|w5c9o8-rMXe#YGgt>?L@ zq2RsrGt=XnF%Vd^h^;{Z&oSKTH%OZOueh@k5tr8?R~F1hxv1^^4htvhr{BrnC9tSUXDX)Wcf36|}*we0OFnQ`}$DzWALL)*cGt1egIHloBHCq09M14VpSzoqwcc|^vP8~q$K8v z{R!(5=_b@;z=}ElK{om2aCE)peEeh&VofLlA z2qs}z1J=iZZ1J${oS=8)ldwl%+d}5JI}#Fs)8!3x5Y942IOPB@i@VeZOl8t{fceh8 zOyr=9_f|U~)}Ok9kgSEUFPd5alVP&fQk?*|a=|1;bCpo$*U=`TA+V`h?Q~Ah^BX`j zP5NISkC^cQMCE<=59eKb1-R|}t)lRB{L!Y(jU#xk{y)Azd_B4&iZPzX$1RNwY|^p)aeuxsTeph;<<#ftgq!aS5RDVw zmC1-HDvcmQ0^sfeU4dUTEC=Y^C%AwHLCWkcR66hRgc0dVW7ZmIV<~aaSjd+Mw@1M&&t}u zd=?VYPv$WHJ{0Kx0JOr|V3V;_+MB}}c99>#1<4oy%A}-Dcgv=Q^CdBPe80~FvBy3c zU$BE!%SE5V^F_bRN)zRq-X?GsZBAi~SAcD`KL8sz5rA=A(%(>wjiT6vY1uN>z2iH3T%Z>q7$W0HsGq4A|e$#Ti6XB)Id98XIMk0`t zq?zX<%G@szIX*?x%YotH>N9||c{!P6T@nJ`w6}!)I}3QP-^o~|doTG)< zI_m&=d*D3`-UBSEUN!ww&mIg3jrQn0AoMk^+Qps*fU>RoDzHO6-^|oQHfcU$fiwkh?QWNJ?Wt&3XH?zp zPjnZtEC|jO#jiX4k220Rp6R}i<6?;CP2azD7A|6i})|IzRJ{e2E^Bd3pxdO+fK z%hqyRHss+x@_OC`#3>MiF8;X{%Hvlk*!+_h(i6;kYmi2BM;E7Szf~;c!DMKb!&?&# zeqRDW9dnN<(6-5$n&2fcwtQvQ4-8meSUE?7c5R92&mHx14i9KYps6z$kFh5FwMK9exa?I~W=XvZ2Fzjx<9 z8%kxeNi0{>lFI4aQ_sO4O)%cUOB4bfDbO+oNPn00=L%o?u~4$Gw1HhBXd=WBYNLp~ zGYHBNS9DB`tk6oer7^~~+W@=u1u6ge87u>5tlg<%(qd3J57P9tSQUgk^Rl6OBTqWM z&tlm9##QWEHF+SK%H7|a2y?QjcQB|SKA$9@p32tN<$TET2=+0zzmJ_4z~KhA#{Et| z-LK&f%GPRLP=1-^96eNyCML7f<%we+IB#^E*LfJn-t(}BRIt({gmORlD~#(VWsy2; zy1VcT1ZiX%BvkdK75cJ)aG3@m3PYUUq$r?h-*|H5Ze=VC{nh5jWI^YqQ*>$T&g?^6 zKTjRRp*;>0rW3DF?VzEF z+xZuBUJ0pQ&X7m+$@Ur`tYHPok+OZk@pGOdH(gGcijuchCMNcO=d0N7?lo-;6^v)X zAQFl**96_A4zx4g!cU6jul)A255rcGT{7aX#e9yvEu<1V4Rk!zQ<>43Bg=qjLYxA; z1nm4DHsk!+_nJS8{k28{fzrS3#`dfhJ0>)p0?qQWgF5KMp|~yeBktETv^0*_AB>gv zPD{RXaVJ?=F%Yr3ZyB{=FK-pjEJ?wpvO8NBqBa;h*SzzK(CHs~k?`Ee12ZTfI&W47%3ilO7T}fy& z@{xZ1cuU)_kB+RNtCr>w*ry0U@XU?2{GtoQ0{Hzqp?TkP-R!60zSgS5pU{r2J@d8w zpy6;B*?ZPwbrxmsv-CxPpm^^wL6U|Yny)o_+AKi;d8DVqES(nkPH#IbYIj~nJlv_h2=_eEBE+qI5M-ElMnAMgJC@)%{?Xw@pYmHcanFq9uH!? zV3~HTF0(sAxB8oe&gEAjt8;IQrtOG!v&^RXj=wQ%0kgMzYTBNJet1)2sI6X2iDKSW z3@OR^JI7+7gEwxvNLJqbxVcC4Ubt~kqNkAL*H!uL?MH2Y+*z)Dzx*sGJ0~9;{AY%X zo}WkEO>{f30e7_An#YosOSpzK774U}F!p#c!&UOdJX0>uQ$1Cb-vvM)4i(6 zXvl&TC=q$7(N-u!Kth&!V2*}t(9|eC*Q6AqV}-|(YpAg;Ym1_~6ehzcMWz%gw8wXx zoe+Xv9y-pH>=>+0I_i%*Np3OG{~S;}B)j1hy`e*hRraB*Ir5EqeoX%b+&QmG1xR2p zTDZQ;ke}d5 zv^Ps-*7^AN!W;C2Z=tpm$Xm1vo1~SOPr`@_6FeTu4UnVEKXMkOwqVM#%8aFoOMX9U zuAD+cPzPm)>A(CAnAvW(FLr(70Y8T7YWRLPzQ)dl@`o72PdVPW?Hz+;Gqe(^;>*hM zWr=UuidQp>sPsPld^ZWo9f-LwwqF(Ug441WAi}R20#*Wj2ROKw%k9J4mMXbT4e8DD z((ui4xmj!E?i|n}A;;;}&5BIW&XP7dC>41=awll-8I*F{AbouMQ`BBJrFhbPswyMK zx$l7Yit!X?O<$plSA(f%75L0`q=Gt5&%>>}d9yvjVPj|h+KfSyniQn12x}4I8FMo_ zTA|NcQ;!B^-v-XI*@~GqM(Q5vu}Q?OtCaY>YN)Pdu(Z%8;GJ6q2$>JIBBz@w)E^sp zQthFNI-SLV^QcH$6_ff43hHqKzbW<6)tLcr-B6~l7^RgG+r}};3Kw(@*4^19V*hmI zN{}?34LqYsJNDy~X@KBVW)Jz$!RQgEO8+iKLq|B?3fRPFJerbQwmcB(E>IGRv(kq!NlS$nDF$;pF@|z9X=FUM>It| zhdWmiHGOSqF>}(Z;g>956x)h-^uR@#T275D`^g$#WX6Id(%0ml_kkvYEWGlIE2tp zLyi3FWvyoBSzD;9F*`(K>B_G;sX2@M=CI`t35;dNo4dEB%-z#k+r1h*N*<(Eb|?+G z{V0fpeSZ!zYrD;2E;$vA#<&foQUh9rzm?jq0r}^ES49ZyhhWB~R_tzw#9C-_Do4u9 zunOj{fubHh$Fyb?`T8N*Mg0OXiB|MX{vW#jAek~hWr=d37CtbaQBxIGb^I@Ftko=w zsq~57_kE*F#YI$3-G+$7Z233G;B%zeGf*dVY$qi24@ckx>U8 z%thVb!#h|C%^gwQ6YS!Dvl~>TgdhX4mgVXBCrWTXVKPy=SE4S=PO5wJa$ch^3er+r zqk84c`csd(ia;s^`-6IWvSP;rRI51+KYf-B!ABrm(*pXv|0A9Kp8#^kl&kdOq!Y$V T{s|h8=lCqltWBAhv6TM+k%5BL literal 0 HcmV?d00001 diff --git a/en/application-dev/napi/xcomponent-guidelines.md b/en/application-dev/napi/xcomponent-guidelines.md new file mode 100644 index 0000000000..dd365dd461 --- /dev/null +++ b/en/application-dev/napi/xcomponent-guidelines.md @@ -0,0 +1,902 @@ +# XComponent Development + +## When to Use + +**NativeXComponent** provides an instance for the **\** at the native layer, which can be used as a bridge for binding with the **\** at the JS layer. The NDK APIs provided by the **\** depend on this instance. The provided APIs include those for obtaining a native window, obtaining the layout or event information of the **\**, registering the lifecycle callbacks of the **\**, and registering the callbacks for the touch, mouse, and key events of the **\**. You can use the provided APIs in the following scenarios: + +- Register the lifecycle and event callbacks of the **\**. +- In these callbacks, you can initialize the environment, obtain the current state, and respond to various events. +- Use the native window and EGL APIs to develop custom drawing content, and apply for and submit buffers to the graphics queue. + +## Available APIs + +| API| Description.| +| -------- | -------- | +|OH_NativeXComponent_GetXComponentId(OH_NativeXComponent* component, char* id, uint64_t* size)|Obtains the ID of the **\**.| +|OH_NativeXComponent_GetXComponentSize(OH_NativeXComponent* component, const void* window, uint64_t* width, uint64_t* height)|Obtains the size of the surface held by the **\**.| +|OH_NativeXComponent_GetXComponentOffset(OH_NativeXComponent* component, const void* window, double* x, double* y)|Obtains the offset of the surface held by the **\** relative to the upper left corner of the window.| +|OH_NativeXComponent_GetTouchEvent(OH_NativeXComponent* component, const void* window, OH_NativeXComponent_TouchEvent* touchEvent)|Obtains the touch event triggered by the **\**.| +|OH_NativeXComponent_GetTouchPointToolType(OH_NativeXComponent* component, uint32_t pointIndex, OH_NativeXComponent_TouchPointToolType* toolType)|Obtains the tool type of the **\** touch point.| +|OH_NativeXComponent_GetTouchPointTiltX(OH_NativeXComponent* component, uint32_t pointIndex, float* tiltX)|Obtains the tilt angle of the **\** touch point relative to the x-axis.| +|OH_NativeXComponent_GetTouchPointTiltY(OH_NativeXComponent* component, uint32_t pointIndex, float* tiltY)|Obtains the tilt angle of the **\** touch point relative to the y-axis.| +|OH_NativeXComponent_GetMouseEvent(OH_NativeXComponent* component, const void* window, OH_NativeXComponent_MouseEvent* mouseEvent)|Obtains the mouse event triggered by the **\**.| +|OH_NativeXComponent_RegisterCallback(OH_NativeXComponent* component, OH_NativeXComponent_Callback* callback)|Registers the lifecycle and touch event callback for this **OH_NativeXComponent** instance.| +|OH_NativeXComponent_RegisterMouseEventCallback(OH_NativeXComponent* component, OH_NativeXComponent_MouseEvent_Callback* callback)|Registers the mouse event callback for this **OH_NativeXComponent** instance.| +|OH_NativeXComponent_RegisterFocusEventCallback(OH_NativeXComponent* component, void (\*callback)(OH_NativeXComponent* component, void* window))|Registers the focus obtaining event callback function for this **OH_NativeXComponent** instance.| +|OH_NativeXComponent_RegisterKeyEventCallback(OH_NativeXComponent* component, void (\*callback)(OH_NativeXComponent* component, void* window))|Registers the key event callback for this **OH_NativeXComponent** instance.| +|OH_NativeXComponent_RegisterBlurEventCallback(OH_NativeXComponent* component, void (\*callback)(OH_NativeXComponent* component, void* window))|Registers the focus loss event callback for this **OH_NativeXComponent** instance.| +|OH_NativeXComponent_GetKeyEvent(OH_NativeXComponent* component, OH_NativeXComponent_KeyEvent\** keyEvent)|Obtains the key event triggered by the **\**.| +|OH_NativeXComponent_GetKeyEventAction(OH_NativeXComponent_KeyEvent* keyEvent, OH_NativeXComponent_KeyAction* action)|Obtains the action of a key event.| +|OH_NativeXComponent_GetKeyEventCode(OH_NativeXComponent_KeyEvent* keyEvent, OH_NativeXComponent_KeyCode* code)|Obtains the key code value of a key event.| +|OH_NativeXComponent_GetKeyEventSourceType(OH_NativeXComponent_KeyEvent* keyEvent, OH_NativeXComponent_EventSourceType* sourceType)|Obtains the input source type of a key event.| +|OH_NativeXComponent_GetKeyEventDeviceId(OH_NativeXComponent_KeyEvent* keyEvent, int64_t* deviceId)|Obtains the device ID of a key event.| +|OH_NativeXComponent_GetKeyEventTimestamp(OH_NativeXComponent_KeyEvent* keyEvent, int64_t* timestamp)|Obtains the timestamp of a key event.| + +## Lifecycle Description + +You can use the **\** to develop EGL/OpenGL ES rendering by using the following code on the ArkTS side: + +```typescript +XComponent({ id: 'xcomponentId1', type: 'surface', libraryname: 'nativerender' }) + .onLoad((context) => {}) + .onDestroy(() => {}) +``` + +### **onLoad** Event + +Trigger time: when the surface of the **\** is ready. + +**context** parameter: where the native API exposed on the module is mounted. Its usage is similar to the usage of a **context** instance obtained after the module is directly loaded using **import context from "libnativerender.so"**. + +Time sequence: subject to the surface. The figure below shows the time sequence of the **onLoad** event and the **OnSurfaceCreated** event at the native layer. + +![onLoad](./figures/onLoad.png) + +### **onDestroy** Event + +Trigger time: when the **\** is destroyed, in the same manner as that when an ArkUI component is destroyed. The figure below shows the time sequence of the **onDestroy** event and the **OnSurfaceDestroyed** event at the native layer. + +![onDestroy](./figures/onDestroy.png) + +## How to Develop +The following describes how to use the **\** to call the native APIs to create the EGL/GLES environment, draw graphics on the main page, and change graphics colors. + +1. Define the **\** on the GUI. + + ```typescript + // ... + // Define XComponent in an .ets file. + XComponent({ + id: 'xcomponentId', + type: XComponentType.SURFACE, + libraryname: 'nativerender' + }) + .focusable(true) // Set the component to be able to respond to key events. + .onLoad((xComponentContext) => { + this.xComponentContext = xComponentContext; + }) + .onDestroy(() => { + console.log("onDestroy"); + }) + // ... + ``` + +2. Register the N-API module. For details, see [Using Native APIs in Application Projects](https://gitee.com/openharmony/docs/blob/master/en/application-dev/napi/napi-guidelines.md). + + ```c++ + // In the napi_init.cpp file, use the Init method to register the target function to transfer the encapsulated C++ methods for the JS side to call. + EXTERN_C_START + static napi_value Init(napi_env env, napi_value exports) + { + // ... + // Expose the getContext() API to the JS side. + napi_property_descriptor desc[] = { + { "getContext", nullptr, PluginManager::GetContext, nullptr, nullptr, nullptr, napi_default, nullptr } + }; + if (napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc) != napi_ok) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Init", "napi_define_properties failed"); + return nullptr; + } + // Check whether the environment variables in the method contain the instance. If the instance exists, register the drawing-related API. + PluginManager::GetInstance()->Export(env, exports); + return exports; + } + EXTERN_C_END + + // Write the API description. You can modify the corresponding parameters as required. + static napi_module nativerenderModule = { + .nm_version = 1, + .nflag_s = 0, + .nm_filename = nullptr, + // Entry function + .nm_register_func = Init, + // Module name + .nm_modname = "nativerender", + .nm_priv = ((void *)0), + .reserved = { 0 } + }; + + // The method decorated by __attribute__((constructor)) is automatically called by the system. The N-API napi_module_register() is used to transfer the module description for module registration. + extern "C" __attribute__((constructor)) void RegisterModule(void) + { + napi_module_register(&nativerenderModule); + } + + // Use the napi_define_properties method in the N-APIs to expose the drawPattern() method to the JS side and call the drawPattern() method on the JS side to draw content. + void PluginRender::Export(napi_env env, napi_value exports) + { + // ... + // Register the function as the JS API drawPattern. + napi_property_descriptor desc[] = { + { "drawPattern", nullptr, PluginRender::NapiDrawPattern, nullptr, nullptr, nullptr, napi_default, nullptr } + }; + if (napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc) != napi_ok) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "PluginRender", "Export: napi_define_properties failed"); + } + } + ``` + +3. Register the **\** event callback and use the N-API to implement it. + + (1) Define the callbacks for the touch event of the **\** and for when a surface is successfully created, changed, or destroyed. + + ```c++ + // Define the OnSurfaceCreatedCB() function to encapsulate the initialization environment and drawing background. + void OnSurfaceCreatedCB(OH_NativeXComponent *component, void *window) + { + // ... + // Obtain the ID of the , that is, the id parameter in the struct on the JS side. + char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = { '\0' }; + uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1; + if (OH_NativeXComponent_GetXComponentId(component, idStr, &idSize) != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Callback", + "OnSurfaceCreatedCB: Unable to get XComponent id"); + return; + } + + // Initialize the environment and draw the background. + std::string id(idStr); + auto render = PluginRender::GetInstance(id); + uint64_t width; + uint64_t height; + // Obtain the size of the surface held by the . + int32_t xSize = OH_NativeXComponent_GetXComponentSize(component, window, &width, &height); + if ((xSize == OH_NATIVEXCOMPONENT_RESULT_SUCCESS) && (render != nullptr)) { + if (render->eglCore_->EglContextInit(window, width, height)) { + render->eglCore_->Background(); + } + } + } + + // Define the OnSurfaceChangedCB() function. + void OnSurfaceChangedCB(OH_NativeXComponent *component, void *window) + { + // ... + // Obtain the ID of the . + char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = { '\0' }; + uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1; + if (OH_NativeXComponent_GetXComponentId(component, idStr, &idSize) != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Callback", + "OnSurfaceChangedCB: Unable to get XComponent id"); + return; + } + + std::string id(idStr); + auto render = PluginRender::GetInstance(id); + if (render != nullptr) { + // Encapsulate the OnSurfaceChanged method. + render->OnSurfaceChanged(component, window); + } + } + + // Define the OnSurfaceDestroyedCB() function and encapsulate in it the Release() method in the PluginRender class for releasing resources. + void OnSurfaceDestroyedCB(OH_NativeXComponent *component, void *window) + { + // ... + // Obtain the ID of the . + char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = { '\0' }; + uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1; + if (OH_NativeXComponent_GetXComponentId(component, idStr, &idSize) != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Callback", + "OnSurfaceDestroyedCB: Unable to get XComponent id"); + return; + } + + std::string id(idStr); + // Release resources. + PluginRender::Release(id); + } + + // Define the DispatchTouchEventCB() function, which is triggered when a touch event is responded to. + void DispatchTouchEventCB(OH_NativeXComponent *component, void *window) + { + // ... + // Obtain the ID of the . + char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = { '\0' }; + uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1; + if (OH_NativeXComponent_GetXComponentId(component, idStr, &idSize) != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Callback", + "DispatchTouchEventCB: Unable to get XComponent id"); + return; + } + + std::string id(idStr); + PluginRender *render = PluginRender::GetInstance(id); + if (render != nullptr) { + // Encapsulate the OnTouchEvent method. + render->OnTouchEvent(component, window); + } + } + + // Define the DispatchMouseEventCB() function, which is triggered when a mouse event is responded to. + void DispatchMouseEventCB(OH_NativeXComponent *component, void *window) { + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "Callback", "DispatchMouseEventCB"); + int32_t ret; + char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {}; + uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1; + ret = OH_NativeXComponent_GetXComponentId(component, idStr, &idSize); + if (ret != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) { + return; + } + + std::string id(idStr); + auto render = PluginRender::GetInstance(id); + if (render) { + // Encapsulate the OnMouseEvent method. + render->OnMouseEvent(component, window); + } + } + + // Define the DispatchHoverEventCB() function, which is triggered when the mouse pointer hover event is responded to. + void DispatchHoverEventCB(OH_NativeXComponent *component, bool isHover) { + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "Callback", "DispatchHoverEventCB"); + int32_t ret; + char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {}; + uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1; + ret = OH_NativeXComponent_GetXComponentId(component, idStr, &idSize); + if (ret != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) { + return; + } + + std::string id(idStr); + auto render = PluginRender::GetInstance(id); + if (render) { + // Encapsulate the OnHoverEvent method. + render->OnHoverEvent(component, isHover); + } + } + + // Define the OnFocusEventCB() function, which is triggered when a focus obtaining event is responded to. + void OnFocusEventCB(OH_NativeXComponent *component, void *window) { + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "Callback", "OnFocusEventCB"); + int32_t ret; + char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {}; + uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1; + ret = OH_NativeXComponent_GetXComponentId(component, idStr, &idSize); + if (ret != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) { + return; + } + + std::string id(idStr); + auto render = PluginRender::GetInstance(id); + if (render) { + // Encapsulate the OnFocusEvent method. + render->OnFocusEvent(component, window); + } + } + + // Define the OnBlurEventCB() function, which is triggered when the focus loss event is responded to. + void OnBlurEventCB(OH_NativeXComponent *component, void *window) { + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "Callback", "OnBlurEventCB"); + int32_t ret; + char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {}; + uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1; + ret = OH_NativeXComponent_GetXComponentId(component, idStr, &idSize); + if (ret != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) { + return; + } + + std::string id(idStr); + auto render = PluginRender::GetInstance(id); + if (render) { + // Encapsulate the OnBlurEvent method. + render->OnBlurEvent(component, window); + } + } + + // Define the OnKeyEventCB() function, which is triggered when a key event is responded to. + void OnKeyEventCB(OH_NativeXComponent *component, void *window) { + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "Callback", "OnKeyEventCB"); + int32_t ret; + char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {}; + uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1; + ret = OH_NativeXComponent_GetXComponentId(component, idStr, &idSize); + if (ret != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) { + return; + } + std::string id(idStr); + auto render = PluginRender::GetInstance(id); + if (render) { + // Encapsulate the OnKeyEvent method. + render->OnKeyEvent(component, window); + } + } + + // Define an OnSurfaceChanged() method. + void PluginRender::OnSurfaceChanged(OH_NativeXComponent* component, void* window) + { + // ... + std::string id(idStr); + PluginRender* render = PluginRender::GetInstance(id); + double offsetX; + double offsetY; + // Obtain the offset of the surface held by the relative to the upper left corner of the window. + OH_NativeXComponent_GetXComponentOffset(component, window, &offsetX, &offsetY); + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "OH_NativeXComponent_GetXComponentOffset", + "offsetX = %{public}lf, offsetY = %{public}lf", offsetX, offsetY); + uint64_t width; + uint64_t height; + OH_NativeXComponent_GetXComponentSize(component, window, &width, &height); + if (render != nullptr) { + render->eglCore_->UpdateSize(width, height); + } + } + + // Define an OnTouchEvent() method. + void PluginRender::OnTouchEvent(OH_NativeXComponent* component, void* window) + { + // ... + OH_NativeXComponent_TouchEvent touchEvent; + // Obtain the touch event triggered by the . + OH_NativeXComponent_GetTouchEvent(component, window, &touchEvent); + std::string id(idStr); + PluginRender* render = PluginRender::GetInstance(id); + if (render != nullptr && touchEvent.type == OH_NativeXComponent_TouchEventType::OH_NATIVEXCOMPONENT_UP) { + render->eglCore_->ChangeColor(); + hasChangeColor_ = 1; + } + float tiltX = 0.0f; + float tiltY = 0.0f; + OH_NativeXComponent_TouchPointToolType toolType = + OH_NativeXComponent_TouchPointToolType::OH_NATIVEXCOMPONENT_TOOL_TYPE_UNKNOWN; + // Obtain the tool type of the touch point. + OH_NativeXComponent_GetTouchPointToolType(component, 0, &toolType); + // Obtain the tilt angle of the touch point relative to the x-axis. + OH_NativeXComponent_GetTouchPointTiltX(component, 0, &tiltX); + // Obtain the tilt angle of the touch point relative to the y-axis. + OH_NativeXComponent_GetTouchPointTiltY(component, 0, &tiltY); + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "OnTouchEvent", + "touch info: toolType = %{public}d, tiltX = %{public}lf, tiltY = %{public}lf", toolType, tiltX, tiltY); + } + + // Define an OnMouseEvent() method. + void PluginRender::OnMouseEvent(OH_NativeXComponent *component, void *window) { + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "PluginRender", "OnMouseEvent"); + OH_NativeXComponent_MouseEvent mouseEvent; + // Obtain the mouse event triggered by the . + int32_t ret = OH_NativeXComponent_GetMouseEvent(component, window, &mouseEvent); + if (ret == OH_NATIVEXCOMPONENT_RESULT_SUCCESS) { + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "PluginRender", "MouseEvent Info: x = %{public}f, y = %{public}f, action = %{public}d, button = %{public}d", mouseEvent.x, mouseEvent.y, mouseEvent.action, mouseEvent.button); + } else { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "PluginRender", "GetMouseEvent error"); + } + } + + // Define an OnMouseEvent() method. + void PluginRender::OnKeyEvent(OH_NativeXComponent *component, void *window) { + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "PluginRender", "OnKeyEvent"); + + OH_NativeXComponent_KeyEvent *keyEvent = nullptr; + // Obtain the key event triggered by the . + if (OH_NativeXComponent_GetKeyEvent(component, &keyEvent) >= 0) { + OH_NativeXComponent_KeyAction action; + // Obtain the action of a key event. + OH_NativeXComponent_GetKeyEventAction(keyEvent, &action); + OH_NativeXComponent_KeyCode code; + // Obtain the key code value of a key event. + OH_NativeXComponent_GetKeyEventCode(keyEvent, &code); + OH_NativeXComponent_EventSourceType sourceType; + // Obtain the input source type of a key event. + OH_NativeXComponent_GetKeyEventSourceType(keyEvent, &sourceType); + int64_t deviceId; + // Obtain the device ID of a key event. + OH_NativeXComponent_GetKeyEventDeviceId(keyEvent, &deviceId); + int64_t timeStamp; + // Obtain the timestamp of a key event. + OH_NativeXComponent_GetKeyEventTimestamp(keyEvent, &timeStamp); + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "PluginRender", "KeyEvent Info: action=%{public}d, code=%{public}d, sourceType=%{public}d, deviceId=%{public}ld, timeStamp=%{public}ld", action, code, sourceType, deviceId, timeStamp); + } else { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "PluginRender", "GetKeyEvent error"); + } + } + ``` + + (2) Register the **\** event callback and call the method defined in step 3.1 when the **\** event is triggered. + + ```c++ + void PluginRender::RegisterCallback(OH_NativeXComponent *nativeXComponent) { + // Set the callback of the component creation event. When the component is created, related operations are triggered to initialize the environment and draw the background. + renderCallback_.OnSurfaceCreated = OnSurfaceCreatedCB; + // Set the callback of the component change event. When the component changes, related operations are triggered. + renderCallback_.OnSurfaceChanged = OnSurfaceChangedCB; + // Set the callback of the component destruction event. When the component is destroyed, related operations are triggered to release the requested resources. + renderCallback_.OnSurfaceDestroyed = OnSurfaceDestroyedCB; + // Set the callback of the touch event. When the touch event is triggered, the N-API is called to call the original C++ method. + renderCallback_.DispatchTouchEvent = DispatchTouchEventCB; + // Register OH_NativeXComponent_Callback with NativeXComponent. + OH_NativeXComponent_RegisterCallback(nativeXComponent, &renderCallback_); + + // Set the callback of the mouse event. When the event is triggered, the N-API is called to call the original C++ method. + mouseCallback_.DispatchMouseEvent = DispatchMouseEventCB; + // Set the callback of the mouse event. When the event is triggered, the N-API is called to call the original C++ method. + mouseCallback_.DispatchHoverEvent = DispatchHoverEventCB; + // Register OH_NativeXComponent_MouseEvent_Callback with NativeXComponent. + OH_NativeXComponent_RegisterMouseEventCallback(nativeXComponent, &mouseCallback_); + + // Register the OnFocusEventCB method with NativeXComponent. + OH_NativeXComponent_RegisterFocusEventCallback(nativeXComponent, OnFocusEventCB); + // Register the OnKeyEventCB method with NativeXComponent. + OH_NativeXComponent_RegisterKeyEventCallback(nativeXComponent, OnKeyEventCB); + // Register the OnBlurEventCB method with NativeXComponent. + OH_NativeXComponent_RegisterBlurEventCallback(nativeXComponent, OnBlurEventCB); + } + ``` + + (3) Define the **NapiDrawPattern** method, which will be called by the **drawPattern()** method exposed to the JS side. + + ```c++ + napi_value PluginRender::NapiDrawPattern(napi_env env, napi_callback_info info) + { + // ... + // Obtain environment variables. + napi_value thisArg; + if (napi_get_cb_info(env, info, nullptr, nullptr, &thisArg, nullptr) != napi_ok) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "PluginRender", "NapiDrawPattern: napi_get_cb_info fail"); + return nullptr; + } + + // Obtain the XComponent instance from the environment variables. + napi_value exportInstance; + if (napi_get_named_property(env, thisArg, OH_NATIVE_XCOMPONENT_OBJ, &exportInstance) != napi_ok) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "PluginRender", + "NapiDrawPattern: napi_get_named_property fail"); + return nullptr; + } + + // Use napi_unwrap to obtain the pointer to the XComponent instance. + OH_NativeXComponent *nativeXComponent = nullptr; + if (napi_unwrap(env, exportInstance, reinterpret_cast(&nativeXComponent)) != napi_ok) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "PluginRender", "NapiDrawPattern: napi_unwrap fail"); + return nullptr; + } + + // Obtain the ID of the XComponent instance. + char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = { '\0' }; + uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1; + if (OH_NativeXComponent_GetXComponentId(nativeXComponent, idStr, &idSize) != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "PluginRender", + "NapiDrawPattern: Unable to get XComponent id"); + return nullptr; + } + + std::string id(idStr); + PluginRender *render = PluginRender::GetInstance(id); + if (render) { + // Call the drawing method. + render->eglCore_->Draw(); + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "PluginRender", "render->eglCore_->Draw() executed"); + } + return nullptr; + } + ``` + +4. Initialize the environment, including initializing the available EGLDisplay, determining the available surface configuration, creating the rendering area surface, and creating and associating the context. + + ```c++ + void EGLCore::UpdateSize(int width, int height) + { + width_ = width; + height_ = height; + if (width_ > 0) { + // Calculate the width percentage of the drawn rectangle. + width_Percent_ = FIFTY_PERCENT * height_ / width_; + } + } + + bool EGLCore::EglContextInit(void *window, int width, int height) + { + // ... + UpdateSize(width, height); + eglWindow_ = static_cast(window); + + // Initialize the display. + eglDisplay_ = eglGetDisplay(EGL_DEFAULT_DISPLAY); + if (eglDisplay_ == EGL_NO_DISPLAY) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "eglGetDisplay: unable to get EGL display"); + return false; + } + + // Initialize the EGL. + EGLint majorVersion; + EGLint minorVersion; + if (!eglInitialize(eglDisplay_, &majorVersion, &minorVersion)) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", + "eglInitialize: unable to get initialize EGL display"); + return false; + } + + // Select the configuration. + const EGLint maxConfigSize = 1; + EGLint numConfigs; + if (!eglChooseConfig(eglDisplay_, ATTRIB_LIST, &eglConfig_, maxConfigSize, &numConfigs)) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "eglChooseConfig: unable to choose configs"); + return false; + } + + // Create an environment. + return CreateEnvironment(); + } + ``` + + ```c++ + bool EGLCore::CreateEnvironment() + { + // ... + // Create a surface. + eglSurface_ = eglCreateWindowSurface(eglDisplay_, eglConfig_, eglWindow_, NULL); + + // ... + // Create a context. + eglContext_ = eglCreateContext(eglDisplay_, eglConfig_, EGL_NO_CONTEXT, CONTEXT_ATTRIBS); + if (!eglMakeCurrent(eglDisplay_, eglSurface_, eglSurface_, eglContext_)) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "eglMakeCurrent failed"); + return false; + } + + // Create a program. + program_ = CreateProgram(VERTEX_SHADER, FRAGMENT_SHADER); + if (program_ == PROGRAM_ERROR) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "CreateProgram: unable to create program"); + return false; + } + return true; + } + ``` + +5. Implement the rendering function. + + (1) Draw the background. + + ```c++ + // Draw the background color #f4f4f4. + const GLfloat BACKGROUND_COLOR[] = { 244.0f / 255, 244.0f / 255, 244.0f / 255, 1.0f }; + + // Draw the background vertex. + const GLfloat BACKGROUND_RECTANGLE_VERTICES[] = { + -1.0f, 1.0f, + 1.0f, 1.0f, + 1.0f, -1.0f, + -1.0f, -1.0f + }; + ``` + + ```c++ + // Draw the background color. + void EGLCore::Background() + { + GLint position = PrepareDraw(); + if (position == POSITION_ERROR) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "Background get position failed"); + return; + } + + if (!ExecuteDraw(position, BACKGROUND_COLOR, BACKGROUND_RECTANGLE_VERTICES, + sizeof(BACKGROUND_RECTANGLE_VERTICES))) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "Background execute draw failed"); + return; + } + + if (!FinishDraw()) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "Background FinishDraw failed"); + return; + } + } + + // Prepare for drawing and obtain the value of position. When the creation is successful, the value of position starts from 0. + GLint EGLCore::PrepareDraw() + { + if ((eglDisplay_ == nullptr) || (eglSurface_ == nullptr) || (eglContext_ == nullptr) || + (!eglMakeCurrent(eglDisplay_, eglSurface_, eglSurface_, eglContext_))) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "PrepareDraw: param error"); + return POSITION_ERROR; + } + + glViewport(DEFAULT_X_POSITION, DEFAULT_Y_POSITION, width_, height_); + glClearColor(GL_RED_DEFAULT, GL_GREEN_DEFAULT, GL_BLUE_DEFAULT, GL_ALPHA_DEFAULT); + glClear(GL_COLOR_BUFFER_BIT); + glUseProgram(program_); + + return glGetAttribLocation(program_, POSITION_NAME); + } + + // Draw a specified color in the specified area based on the input parameters. + bool EGLCore::ExecuteDraw(GLint position, const GLfloat *color, const GLfloat shapeVertices[], + unsigned long vertSize) + { + if ((position > 0) || (color == nullptr) || (vertSize / sizeof(shapeVertices[0]) != SHAPE_VERTICES_SIZE)) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "ExecuteDraw: param error"); + return false; + } + + glVertexAttribPointer(position, POINTER_SIZE, GL_FLOAT, GL_FALSE, 0, shapeVertices); + glEnableVertexAttribArray(position); + glVertexAttrib4fv(1, color); + glDrawArrays(GL_TRIANGLE_FAN, 0, TRIANGLE_FAN_SIZE); + glDisableVertexAttribArray(position); + + return true; + } + + // End the drawing operation. + bool EGLCore::FinishDraw() + { + // Forcibly refresh the buffer. + glFlush(); + glFinish(); + return eglSwapBuffers(eglDisplay_, eglSurface_); + } + ``` + + (2) Draw the shape. + + ```c++ + void EGLCore::Draw() + { + flag_ = false; + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "EGLCore", "Draw"); + GLint position = PrepareDraw(); + if (position == POSITION_ERROR) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "Draw get position failed"); + return; + } + + // Draw the background. + if (!ExecuteDraw(position, BACKGROUND_COLOR, BACKGROUND_RECTANGLE_VERTICES, + sizeof(BACKGROUND_RECTANGLE_VERTICES))) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "Draw execute draw background failed"); + return; + } + + // Divide the pentagon into five quadrilaterals and calculate the four vertices of one of the quadrilaterals. + GLfloat rotateX = 0; + GLfloat rotateY = FIFTY_PERCENT * height_; + GLfloat centerX = 0; + GLfloat centerY = -rotateY * (M_PI / 180 * 54) * (M_PI / 180 * 18); + GLfloat leftX = -rotateY * (M_PI / 180 * 18); + GLfloat leftY = 0; + GLfloat rightX = rotateY * (M_PI / 180 * 18); + GLfloat rightY = 0; + + // Determine the vertices for drawing the quadrilateral, which are represented by the percentage of the drawing area. + const GLfloat shapeVertices[] = { + centerX / width_, centerY / height_, + leftX / width_, leftY / height_, + rotateX / width_, rotateY / height_, + rightX / width_, rightY / height_ + }; + + if (!ExecuteDrawStar(position, DRAW_COLOR, shapeVertices, sizeof(shapeVertices))) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "Draw execute draw star failed"); + return; + } + + GLfloat rad = M_PI / 180 * 72; + for (int i = 0; i < 4; ++i) + { + // Obtain the vertices of the other four quadrilaterals through rotation. + rotate2d(centerX, centerY, &rotateX, &rotateY,rad); + rotate2d(centerX, centerY, &leftX, &leftY,rad); + rotate2d(centerX, centerY, &rightX, &rightY,rad); + + // Determine the vertices for drawing the quadrilateral, which are represented by the percentage of the drawing area. + const GLfloat shapeVertices[] = { + centerX / width_, centerY / height_, + leftX / width_, leftY / height_, + rotateX / width_, rotateY / height_, + rightX / width_, rightY / height_ + }; + + // Draw the shape. + if (!ExecuteDrawStar(position, DRAW_COLOR, shapeVertices, sizeof(shapeVertices))) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "Draw execute draw star failed"); + return; + } + } + + // End drawing. + if (!FinishDraw()) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "Draw FinishDraw failed"); + return; + } + + flag_ = true; + } + ``` + + (3) Change the colors, by drawing a new shape with the same size but different colors and replacing the original shape with the new shape. + + ```c++ + void EGLCore::ChangeColor() + { + if (!flag_) { + return; + } + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "EGLCore", "ChangeColor"); + GLint position = PrepareDraw(); + if (position == POSITION_ERROR) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "ChangeColor get position failed"); + return; + } + + // Draw the background. + if (!ExecuteDraw(position, BACKGROUND_COLOR, BACKGROUND_RECTANGLE_VERTICES, + sizeof(BACKGROUND_RECTANGLE_VERTICES))) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "ChangeColor execute draw background failed"); + return; + } + + // Determine the vertices for drawing the quadrilateral, which are represented by the percentage of the drawing area. + GLfloat rotateX = 0; + GLfloat rotateY = FIFTY_PERCENT * height_; + GLfloat centerX = 0; + GLfloat centerY = -rotateY * (M_PI / 180 * 54) * (M_PI / 180 * 18); + GLfloat leftX = -rotateY * (M_PI / 180 * 18); + GLfloat leftY = 0; + GLfloat rightX = rotateY * (M_PI / 180 * 18); + GLfloat rightY = 0; + + // Determine the vertices for drawing the quadrilateral, which are represented by the percentage of the drawing area. + const GLfloat shapeVertices[] = { + centerX / width_, centerY / height_, + leftX / width_, leftY / height_, + rotateX / width_, rotateY / height_, + rightX / width_, rightY / height_ + }; + + // Use the new colors for drawing. + if (!ExecuteDrawStar2(position, CHANGE_COLOR, shapeVertices, sizeof(shapeVertices))) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "Draw execute draw star failed"); + return; + } + + GLfloat rad = M_PI / 180 * 72; + for (int i = 0; i < 4; ++i) + { + // Obtain the vertices of the other four quadrilaterals through rotation. + rotate2d(centerX, centerY, &rotateX, &rotateY,rad); + rotate2d(centerX, centerY, &leftX, &leftY,rad); + rotate2d(centerX, centerY, &rightX, &rightY,rad); + + // Determine the vertices for drawing the quadrilateral, which are represented by the percentage of the drawing area. + const GLfloat shapeVertices[] = { + centerX / width_, centerY / height_, + leftX / width_, leftY / height_, + rotateX / width_, rotateY / height_, + rightX / width_, rightY / height_ + }; + + // Use the new colors for drawing. + if (!ExecuteDrawStar2(position, CHANGE_COLOR, shapeVertices, sizeof(shapeVertices))) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "Draw execute draw star failed"); + return; + } + } + + // End drawing. + if (!FinishDraw()) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "ChangeColor FinishDraw failed"); + } + } + ``` + +6. Release related resources. + + (1) Create the **Release()** method in the **EGLCore** class to release the resources requested during environment initialization, including the window display, rendering area surface, and environment context. + + ```c++ + void EGLCore::Release() + { + // Release the surface. + if ((eglDisplay_ == nullptr) || (eglSurface_ == nullptr) || (!eglDestroySurface(eglDisplay_, eglSurface_))) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "Release eglDestroySurface failed"); + } + // Release the context. + if ((eglDisplay_ == nullptr) || (eglContext_ == nullptr) || (!eglDestroyContext(eglDisplay_, eglContext_))) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "Release eglDestroyContext failed"); + } + // Release the display. + if ((eglDisplay_ == nullptr) || (!eglTerminate(eglDisplay_))) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "Release eglTerminate failed"); + } + } + ``` + + (2) Add the **Release()** method to the **PluginRender** class to release the **EGLCore** and **PluginRender** instances. + + ```c++ + void PluginRender::Release(std::string &id) + { + PluginRender *render = PluginRender::GetInstance(id); + if (render != nullptr) { + render->eglCore_->Release(); + delete render->eglCore_; + render->eglCore_ = nullptr; + delete render; + render = nullptr; + instance_.erase(instance_.find(id)); + } + } + ``` + +7. Use the CMake toolchain to compile the C++ source code into a dynamic link library (DLL) file. + + ```CMake + # Set the minimum CMake version. + cmake_minimum_required(VERSION 3.4.1) + # Project name + project(XComponent) + + set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR}) + add_definitions(-DOHOS_PLATFORM) + # Set the header file search directory. + include_directories( + ${NATIVERENDER_ROOT_PATH} + ${NATIVERENDER_ROOT_PATH}/include + ) + # Add the **nativerender** dynamic library, with the **libnativerender.so** library file. Add the .cpp file. + add_library(nativerender SHARED + render/egl_core.cpp + render/plugin_render.cpp + manager/plugin_manager.cpp + napi_init.cpp + ) + + find_library( + EGL-lib + EGL + ) + + find_library( + GLES-lib + GLESv3 + ) + + find_library( + hilog-lib + hilog_ndk.z + ) + + find_library( + libace-lib + ace_ndk.z + ) + + find_library( + libnapi-lib + ace_napi.z + ) + + find_library( + libuv-lib + uv + ) + # Add the library to be linked. + target_link_libraries(nativerender PUBLIC + ${EGL-lib} ${GLES-lib} ${hilog-lib} ${libace-lib} ${libnapi-lib} ${libuv-lib}) + ``` + +## + + + +- -- GitLab