From ff230d4360ec7002331ada408d50f8e30e7d7637 Mon Sep 17 00:00:00 2001 From: Benedikt Schroeder Date: Sun, 6 May 2018 12:12:47 +0200 Subject: [PATCH] resm filename globbing --- samples/ControlCatalog/ControlCatalog.csproj | 18 + .../ControlCatalog/Fonts/Aspergit_Bold.ttf | Bin 0 -> 16860 bytes .../Fonts/Aspergit_Bold_Italic.ttf | Bin 0 -> 18256 bytes .../ControlCatalog/Fonts/Aspergit_Italic.ttf | Bin 0 -> 18248 bytes samples/ControlCatalog/Fonts/BolshevikBd.ttf | Bin 0 -> 6928 bytes .../ControlCatalog/Fonts/PinkHighwayBold.ttf | Bin 0 -> 43816 bytes .../Fonts/PixelOperator-Bold.ttf | Bin 0 -> 18068 bytes .../ControlCatalog/Fonts/PixelOperator.ttf | Bin 0 -> 19836 bytes samples/ControlCatalog/Pages/BorderPage.xaml | 40 +- src/Avalonia.Visuals/Media/FontFamily.cs | 387 ++++++++++++------ .../Converters/FontFamilyTypeConverter.cs | 13 +- src/Shared/PlatformSupport/AssetLoader.cs | 8 +- src/Skia/Avalonia.Skia/TypefaceCache.cs | 18 +- .../Media/FormattedTextImpl.cs | 47 ++- 14 files changed, 357 insertions(+), 174 deletions(-) create mode 100644 samples/ControlCatalog/Fonts/Aspergit_Bold.ttf create mode 100644 samples/ControlCatalog/Fonts/Aspergit_Bold_Italic.ttf create mode 100644 samples/ControlCatalog/Fonts/Aspergit_Italic.ttf create mode 100644 samples/ControlCatalog/Fonts/BolshevikBd.ttf create mode 100644 samples/ControlCatalog/Fonts/PinkHighwayBold.ttf create mode 100644 samples/ControlCatalog/Fonts/PixelOperator-Bold.ttf create mode 100644 samples/ControlCatalog/Fonts/PixelOperator.ttf diff --git a/samples/ControlCatalog/ControlCatalog.csproj b/samples/ControlCatalog/ControlCatalog.csproj index b8a8479a49..74bf3ec4bb 100644 --- a/samples/ControlCatalog/ControlCatalog.csproj +++ b/samples/ControlCatalog/ControlCatalog.csproj @@ -11,6 +11,24 @@ + + + + + + + + + + + + + + + + + + diff --git a/samples/ControlCatalog/Fonts/Aspergit_Bold.ttf b/samples/ControlCatalog/Fonts/Aspergit_Bold.ttf new file mode 100644 index 0000000000000000000000000000000000000000..c9d6b840e9e340fb6ab698c2e230a2a9c2593f7a GIT binary patch literal 16860 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 Q=>AUMY`hes{XYx-7Yu%bUH||9 literal 0 HcmV?d00001 diff --git a/samples/ControlCatalog/Fonts/Aspergit_Bold_Italic.ttf b/samples/ControlCatalog/Fonts/Aspergit_Bold_Italic.ttf new file mode 100644 index 0000000000000000000000000000000000000000..a5ba97f37749d88caeed4346b3151291063384db GIT binary patch literal 18256 zcmd6Pdt6l4wg2Ad3^TwC3^2%u4;&a|5EO9+XHbqP@(^F(1LdJfL);)B*nz1=qxH@J|L1B?8BIGh-gm zea@oNrA=M!58!?*&K+}>E}Pxm`P-jiWE0L$lrEj@j(szUbZ>XzoThHt)4Ddh4c~o7~<~3Q5Z;xRtbQ5D!PuAB~`=u`T zKLO8z``&t7FntsPWO)J3lk3;DZ#uAYRtL^8UN$tf)Ks4<`u7UJzlLi&)>Us>&%+sT z5*Pch;JXS09!M9#yvS(U#rvrKrg zcMAV;B=Fl;&}R(!j(nKOER;!f6(5X~uJ##OSjf}3|3Juh1SIXA_Whc;@*2xwCUJpA za&c`I%h0ayYtjW4!VJ;{X*aIy(SG?y%*}cLpM}b}8paHFGd3Bm**L^!=~Db8GKb@& zz<~ib^w%%|%&TZSn1MH;4_#h}1KeT91>6(TdA5l6FpvBjc1)^Zt8x7VyTr0^r0{3i zz5JhS1Fj|TTiF^K!+(wApR5x1t1zyJ+JLuGa9z4~RKvY#VFG_0{-Y zhTmiI61G}i#oXxUmVVE+f^LE-4snj_Vy?-!zg)X6pJQ%01jiD#h5E~WeH?HHoO9q= z9bmq0*u!3z9>)D`_^s0E_%(Z7(DN}%<_7kXz>ns(0#Cvf2k0YwDsYIo+3~(MNz&Sw zQ^Qs3%LD!SHsFSX&ZTO00R2|;uW??@TEG)pH{w|eep944*1#^ZOnz%$0r%pU#_nS$ zLY`*F1pn8AF2eUB_>;f%yT;4?LfyUs+-s0&4(Tw*()M z6+h0W(>eqngd@R|(wSfIN#}QPo9GE%i@-fGw>JL)YD1=)a8Kj+4RA2W2Hcw-7~B7g zwLqKGnlKm%{TQR^2fL0dr1fK9|31cV2I&fmWVf(8*kf3UC)xM027P=fujZThoqWIa zW2xH_>lo!oa3ncW9GQ-jeSH|`V7IYH_5NqrD|`uGh5mQw{cVnsjxhuM`#$aar0>1H zcl&gCDP?^N$yNocpo&w`X)b=~Cd6fZ1rqz-JUo2sH6q z&)QfWYlXD6v$d>|Rm1+RV>Qrvqiz(?iIe@IBlyF~hK3kTp<&@>OGKnKDmum%J0i|L zGJe$PF=G?PITDkc$>UR8sT0!DCr-+koH@nq$(ri*Wlx))qs+*iIg91Z&WFpGQ#^Ox z`~?e3N*66&vb1d3^74wxsue45x%D>2?%la-_x^_-e(cfjKK{KEPd@$BGbf)t_1yEP z&-~!*i!Z!<{=yF#+sIh+9mj#z*3Im`Z?i3EZ3`gz#7lR>)~}{hKf7ngq58I#^-b&6 zHlAazZeXiKuRE)2)^z^c_C5FSePG|W9z4hn96fe~)!t6`?h+j||HIPszg)J2?PTwB z2VcY6`5}Ief589BRmmcalG3CKX{~ffdRzKjj+G1K3i%QFiu^nIYlFp*WbhjNhLeWN zA%>9Dka;2gkZmE4g;}PQ(Hd&xC&xe$5uSVB9w@=5&I&JM?4>KIpTK_Uq>1vV*vR$5kGc@`S@f9bqUiO}`=if9 zzaPV5;$kMo6vV8G*%Nan<}=$!+XCAT+j-kBV`F2LSbyx^*bA}UBcu_^h~^Q;NBlC* z5;r?;N8FXTukES!3j1#RtM*^nzZhv4nJ}_y+AMKAT6ja;I-~wNgFSrr3J; zHPv#+??=BAQU$LJ^t1UqCJ&AiW0kQ9IHZb0_yCf`7UAnMZ0%?^j-m&fPC z;W5qR7;3k2-*`Zfj-H#8JLx=*ijYl99x}W*Id}5QIB-_>ZS}P!=ga)`$vLCc)^hyv zv-}5V&SD;!dHT*vm2wsv&n7YtV*qW-FnWEtTufkc$_YlJDUuU4vN6tXi{v(Mic8Mr z9`ng*G4YNO_J}YZV%@wTQi(ieJ~b_7q+`TLOL*Xt$voLJHLK+3;gdaC?nMe8Zw!x& ziW{An7Qf(jb8(TPerOD{23?Snv!~m5lzE}r=9_L)|0}!%k;yS2`ZjnL%3@d?_~8Oa za=AM$k|(A3jB#$S&zq8D4C5XS^paBOmJwGXd7N9C7QN@mRgS$+-nPJ!-{H5I@umKN zzcEWyE(Y$D$Ib4jjmz)2T()uJlN}vpIZK!3 zx4t7bu6~qKyzuz=F`-I`ZB*-2Puf~*WvS2e#C-mN`gqoy)$>YHQxDX&EyzEbIVC=S zN=~X{a!j(LQT?j4WelG(jd0;4PrBSOk|vTQk|J?0tM3i&k<-96W(R7vT%N;C&Lk5s zLgV&v$;Lg#spFt1k%m1y)EIA3CXSP?jGL%fdozt;h)e-L1u&9z7)~Du!SbhbG~!Hh zB%g`FR%s76VQ~C7C*Wl%idDLT(G$n@W{#UEVBE_qVcD*-XaKaET##jx%jfdhfv?Zb z8&|vM#Vhg6N&9O&qT!UBThdl;-@Yo0$Ovcwnf<1dZT{ zC(S35lq85=lEN#MQ>T=ZV$OuVV{9{1AmPl8{#D92#eW=d*6>K)gm?wl2@YS?W9i|M z8m*+mTUim^^8v}NFmFXgMYxD@xF>mq-m)<60{8J;?n*J5j1WSovOUgd;)(oC^)55t zI4NX8>c)(5W+i6gtY@ZWn`Wv{ai7AwGCPuzV$sy zBDpDn)Cq)oSB@UD!b>ep z*OW47mqzPK(BTBF;f&4X(C9>;M|S#FT6lV%`X0BXE7eL`x59s=rgf{9Zf(qBjJXSA z!1>WU(UfQ+{R8z$E?*oFbEPDiw$0%e%i=ok)R%`6lan#hAa*(2scDD&B~h_5t%zI#?ZR!<_UAYvm*NTBE8;7k3_soa9Q) zi<(p-EzPT1F{^k|!q)lq`w!I3-La`_3M(0|5ck8k_S=pB}!w|MyyJv+Gybi`3uV5 zHGNwKnEN!C+!QjCyL^0Kg!*p87Z)P=k)lV6wr(vH{5l3i$u7jPQ6$kGw|6EdQ(zLx zWQ8?yS|z9Ns}V|0tvQU0fmu_cu&BLd;UaiwUYe6ZdP4e=QP$z6Kms4gMPH}9NV*+d ziec$UQ@}gKNd||FmS6LUSPYMQCMVA%gvQG0Iz*&E;U@0=zM}q9y_^EKQ?e8C@W_sD z#Xs1&c2)Gs*7}ar=j!V^V#hBYflJ%FZ{yzXZuN3E-&oqRZZXNl_LpW=lplEe!2bGI zm#^La(mAXLY^0n4T1~=Adu&cuqRAP?6J^Qje>pE*O<0%5|EYe!pKT?}_4L!yX*G+# zrO`t6bsxq?LW>=ULu`o<@qnpunu&3QIhXZ@yNgdKTNM>BHDz_#U(Tp8oAYzjE7@P> zz|rT;kgjel^R5^(rV5q@Q+--CJ*P~4Lj9DyJ0|6@^-P|OIinCy*o_WX3K(cNr8taI zoI^U1)T#cYqH+c|a&M)3p4!vxd5{|qr!_Y>gBQ(dE6=Gt=LmN}xAZRHgp!Bz*o1N# z25@$F{pZos;}X=KqvN(d-q{^L>fmm07293zqyFW3AUK_M3K?Hb%i2l6j@9P}O_#tE; zE)QSy_{Ctl^|@cv@J+NO!Yg^?L>&B2`Ra~*rAx`@+wj9H)hDE@>Jz-OH->m6=nTXw z;FRp{Qo2YO0{8e{zyv)MK|?isZtv%7m9bB_PAl-%20)}g>`YWzB@%^xN?Ws|^w zOJ~*9+_Lz~0uNAFz)xfDUFvQ=H&^`|nj883{qxXz!Jm?j+dP}WShcZBQ50Miunl&! zA~6y9Tke$cXY<&&!4Ah8qRuP)b;wSo%l|$B^V^po>Q*Jm@rs+X7fUuO-6%*LR?+wlZ;!&kvs}% zQZJvbia)qr6R6IQ_{O8%Bvjo;JI|3&y+n9uviX_713V6Bl{3*~lM~5BI3X^Dt=r@5 zuePfHNZDD&!zv$2s>KH7(bm>SFF|XT+nFLD#$L|{k4LR`jVObK_m*=8~Cd zGjF+8PAV0Qb0kGG0i4r0LTu+v@HRbG_SmySP`}iVJg0q)M0+m8FbEvUkYt3wWr<)I z{wg5^hQ{eJUxwKT9qlVB@QyS?;(luWDNJ(E1!ZYY+O&kYQLY6rD1%NQGf-lQ^Z_1= zd^yProcT3#_fBQ!fG_9BkTB_w=x3!^#iPfDBsI$BI=~igHOxQRDd^dOx@% z`e$J-s4LASVj)Cvi9Q!UZ{}Z`dw&yx$Vj!=Bq?6-^0AT1YDt39X!{e|+Mq*T7*5Uhu~OAF+KR(Ng=^tjFm74KU!eM8H|q4??+qgluhc-+6wr z@9#7|1W^G$uI{k#ZAAk1OHwmmrol!WVCNItQro5G1z8KAHzIb!KHfsnX`(O46ORw5 zb&`?)DQdvwW~!S89CEqlVtaaYw+mirI!*DQh)c)!bvVuU^@&K57U~rqP-4| zysj-LDl-uCmD~$U_-w`gEBnjK0hI#0b)b*%%mkjaN29H?J$dajfoR!T z@lHo-Mfp1lzgvrx)93D|xLM#uFh~akUa*|~)Y@&bh&m9CxV_SgT}pu5)||ZRs1+rp zJE90ZS`R^R1z)0C7Ox}RT7q~OMfN~gLxGwe(NHjz=shA;%qgAiEWe@$F2-GZx5o30 za(Ceh--LN0PD$uqQHY>S$Tk0=z>}g&?A1J`B%>AIhtrg5gvsX8d#&jgE#2MxTK#^d zrL>zuKHyQ&XO!*(kK!mov14z6ST3-j*vyi{N<#3Z$6gigj7N4v4Nw|Qu_l!@?t;eFOj_!6Pyx3K2TYN-KYCA@ zC8x&RsAOVHrm%Zbat}qI8jfKYCt?=(eoqKYw3S2f>bSE+?YmU=y(J^DsDI|8dwSkl zv`ruLP5xhA1pb1%L^G|4Gl+H*i88uN4>1@_F+P)b#{-i+O}c^a!v)Gl47^10MDWHJ;t6w7GXXsu%!fUbHdSnMl;g$Wm(os{Tfa}m-DIzbQ$Xn)S%1ia{=*LC*ZEuWi_CSwgExKJ`Er>UA%9ns^~UhUWPK_sdIGAb>&~};uNKz;TcJ7{&nzU6#480X*ZV$$zNm8s{H`4AcV+Us zZu6eRY?Co%hLRL!u9?2a5_GzHx-vP@F+O%=PUiF_LCpYc$R6xIB%6{!6ia4yTe@M1 zdla=8eQ1qHUn#yv!idx}h0>bB3XPhgOwqQ)Xb?ktdU|N*ORFr_hNFgsJqgBRe?FRW z5l;CRjXXL}eJ$?}XwNeKjB3GMF^_x?TBwHf&*K_2TVPf>mS#Or<}Hm*sUs<+xo32& zwd%hDhdi%umX3#z-+p_Lj5(ld<6Ry~ok7>&QbXH{t4_>$Z)5Swr{-M$`bR(d`udN5 zOnTOW^(WlHAMDb7g`AZ!-=F|ao|6Uh9hOh!&qa|Dp32FpJz?dH8}&7CKWlPyKQKX#he zzB;Ad!pAB~&7I1l+cqiN9#!tF5q^QQOynUBB3i z4tO_^htFiwA&>uJE*zP zu+RZGX9l2&5rjX%JlH=*K-J`%Ys#bvxR^p8!|{B=L>|R|L^du)m#uco)Lf?}E0{}zVZK3cbNG$7$fbTG<)El5lsSk8<|sME`|A@DC|E^c&_Y4AwkL@M55j0?OI$|9fxL*& zp&`B`QIHvMDf}%WOcs0F4^fK@#cqjwc3|IV(+$_4{o}o`V4vX_*hk7)!jwtO)R)ZO zlVSi7D~Fg$#JwiOz57v0Mo_N@zCv$S_q{D;;u#k^)mcM)$Y5i~L+&~bnLwB91z)Y) zg~BIQLAfD(sXHgNqNpld318~TN}e`X@jB-(58sib%$=E)KhB*MMs)_&wK;@O!B53(}MP zDafFp1s+gXaMq_2FJ0BFw}hv%mg@B};y=2fBUIPqw3EaKSIOQN`E0#bRz*5+7W-GN zCJk+cj8}Hq_DSby|B5HY^f(exE=8v#YP2`dHg_%=fhmHg(uJKdZp7c%?6l?NAtpr( zwRQoQR7-g|B2ys54ge1A4S`(Hsb5K^9B*C@@NxHlxJ9>2cfw|5C~K zLRUooeLSk4SWcl49!j~)q*}^M$z$RTdIG+nqh?S79um`Y^8~!`v2upI9a3f%QXiD@ zri9p#toKyP3t*2M$b2s%76WV8k740pJ%+$pP3sc`=hz@PI|M$oj}OL2`12u<#_Ilk z0H=4!)%WAHTEN2E2g90)0t(r}A<$+8Y-12^2LfgiPd90F7VG@F0V=``A=^Wsru57D z0G5aJpd|qFu#V@L!I+9i0kF z3t1xk|5L~?a8INMGRVg1?i-IE*!atd*HPp6h`&21XRm&!e(*^ZRy~lr?=O6y2GQ3d zY7nuy^$99L!1TCGe6nZV%p0o^%}Muvx6t1hw>YR2u`;bKq)U@|;3-u=E`?MMR0a}F zGNf`)eSj(oAwnwkkV2M(ENS-qrZ8++`5`b;g+vBmlnjD#Sc^#p;UT1P2$XnT8Ut_+ z56B|uDHimA^MfGiQZoeBs(z^nKr7Z|M#3{(jNcCa2%9SMBH)W3m53*G1=YDgYfgPP z4C)K|sqcHb63QC2)c0xh{XgOfUF@U;TtVm4=>1^7qRARnq+=TFVu6Q0fk74K# zYyAzg>=q(0be@Ak$_Hp!E#^VaWSDvMNc0r)5SRUA8jd#WR`V2p#u4CUY zW1+5XLuW*(9$uP5)_=jfr7_T95o2J{L5JPM?OjP-HJ+L-=YbkGU$})H`PsTPeajZg z24HU~Q|x0y%?Xk9OfGgzZW>9IG0JyyuZvSiGTvxMF)PV9y|HLCZJu^lG$u6`j;5mP zzm+#iSK_jJ|1$6P&hFmt#`&b^x$8SWN~>zveYCr(D)7rU-d?U27QeK8eI?VF1SDVxZAszv$gTnghnj&gG$tvs~=oMK%@r*z^HzA_b>>hG}iF?adMWcSVH}S7~eS35K zW=nx|_2kB~vW`=dQLp}!JThqlU?oA%MCK>xi5g0OBS)$~)I_D_Z(H1hpQND@0g}TO z@$5{2sZFVq>`KrRG^iSswkUXLCfn6}N&+KEzeUbi+9hg1up`4&gT_O$hOY?mSjgCo zWuaI4ZPmXxhhX}!RVSW@6}WK@Zq_CV(D8_%16E@=I`kaUu(Pl}A&W!iS*97pz&!P0 z9_-GBohPt2A9g05pj*Ttb4ddR(V(wSiM~GHFk}CQbl4fs>FO|K!VsYifw?puj-%&D zhodf65)Zoehp@v-#_=0t*&8SS^PqTkAdirMr^+S==Mg9t57Z0#D=tCx${Q02s4w=H z^af`V0uL4q&Lm)0NR@?wOoDi%NMsV=9`IaKi>O5+=WEw@T>x{)VS;0`}pk zLuU0?CYRL~`qxHzf*<2cFOs|Z^^WpxVi!0}1(AZ|;i`!9pmR4?5_$AsefS^Y!@v&* ze=PKE2>e@a1|K_|;qVs*f4CWHgsu&lqf67ZfIJ3hKqX_iS@d9FxOtA~fG{NyV zdau&l9`)bdA8!#J1$c~r@IYK5B6giTnqd}5IgUfjQXspv=Dw{gm{aPHKaE7g8I@72$zM)VlbeixxH{t@PJiOu~2bnh6O-3sZ`$b4GW~TQFyI{JsSX zico}AzpT2HmF2Cfyp%QFRqyiqUF!bA)Ku5uf`SRI)WZ~u(4KC&RFBAfl;-=WP8d|R z?2plJQoX!25Dx~IF{SwfrmtT|c7by?%1+;;qDgM)W>rn$kOr4Fg*yt^?{9)hZs?{k z$pH<98E`-SxIQRw#lGSuxY~p++zfKB5QG~*&nJ-x;9D=?!av^xZh*@-gWT_AZU7$S zVi0p{{<%cw^UY@oxR;yF5^yXxOrp6J(4ajhpNE!^X?m0pSugQq?A=sRXyhZXtF$SR zctBS99FNF0Q4USS+R|OflLf`vlt$KKZK`FuOyh5iwP(7b@I*s-c3x86glOdM%BRod z7cHaJ*C);>y;nV88O3L$&nVrIHnpInNVRq$EOKzgmd_G(3 zC1h+UwADhw2EqI7fPCF2O&4^Iycwms@fiy9N!_Xrg8G1FQ6;U`3;u}}4^(?ahHjwZ zy9zW0Recv|MpJ+O0QM~K{K3GpM1!6`_)*ZaM1!6`kU!TSCK~hrf~?~-UEqZ5*#K60 zmTv&F&vn{@up`1mO_JgL(Pl&h+Q)-;47E1L9^zTOEx~rbqqk+2#1r+lfyMTZ4Pi0* zTh@5}8tqT?J|;FTQ`7un+aNfu-^Sy&ZyghCB7P5$y|l+r)0= zf79EcEK<5xZ-=4%u-*=5YoxP!+rq}ki}iK{J0jnyx1(5;p+#kM zy~9}tUbo{(oK(EQIRU?JmdU1|a_WEu+l=o;c)xQ4ykQI4OT^o&c{ppr*}&*FaaN1> zLThog1K)nCSLL^?-`v_zSKsbPt(o9(XHM}rR&RDJs@~Al;#iX5$ZKkHh}&(B*4nn( z){a^~2IT?DdI6_SykW}n+Sb>$)-|*4>I=iLG@0iKh=P2^5!1cLb((1Whqr5Hb|c;Q;sJ9}I-C<$}aEP|(7fG4~WO zEK{&P2#@8pt!)i0&5kJ1}TT+{b+>lZZjI6N^Yb4iWE2WT;0W&o~BE^#s&{9f%Vx4!Fev%3?1gv+ zXAUa{XXml`Yyo&&!b%~`iy_=gvF6L5^5v`o?+;e76>KHm|GyP)^smCp#&6)Q{(ooB zu=m-I+3(o%>@)TPe8w4emfgorvmdbEu;1hV2>1hgnSGb-V4t(ScwX&W>>;)bb@czh z{~>US{e-;^wSb{W3%E%r0^Hv1!_=@;w@`#F0K*8VHj#eT(p$=-t$ z{+WHr?#JpkKtk3*x|-Q>NW$%qx>iWe2FOYW#QINc6Eet~@fOV;cvJoy{uhF~*q!Wd zb`Sf4U1jGDg&SI1w58Gh$C4=2lKaTt;9?|>CUH~3T2QP?9-aPQlQ3XQ**SVwnq(eN zo8gagv2|$IuD<3HPFaok2*F4gF=& zqCSLAs_0D^Yc0ZSj<`mcQ_Bb_HprM8va(p8KO8ccFa%HB6d%Hu{p9|ZDfIjHrD+H0 Jm;Rra{|4kce7FDr literal 0 HcmV?d00001 diff --git a/samples/ControlCatalog/Fonts/Aspergit_Italic.ttf b/samples/ControlCatalog/Fonts/Aspergit_Italic.ttf new file mode 100644 index 0000000000000000000000000000000000000000..d74ec43df22c7ff7e9df6eef9e2babedf76bfb05 GIT binary patch literal 18248 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 L$00h?@5B5Ll|r$X literal 0 HcmV?d00001 diff --git a/samples/ControlCatalog/Fonts/BolshevikBd.ttf b/samples/ControlCatalog/Fonts/BolshevikBd.ttf new file mode 100644 index 0000000000000000000000000000000000000000..359ee1bc15d02b37194a2e1dfaca2327b280cbef GIT binary patch literal 6928 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 M6aBvW_;U~b4?>$VrvLx| literal 0 HcmV?d00001 diff --git a/samples/ControlCatalog/Fonts/PixelOperator-Bold.ttf b/samples/ControlCatalog/Fonts/PixelOperator-Bold.ttf new file mode 100644 index 0000000000000000000000000000000000000000..154890a659f1d8c1ea956582dc58b56e4cc09e8f GIT binary patch literal 18068 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 F^8Ztzpb!86 literal 0 HcmV?d00001 diff --git a/samples/ControlCatalog/Fonts/PixelOperator.ttf b/samples/ControlCatalog/Fonts/PixelOperator.ttf new file mode 100644 index 0000000000000000000000000000000000000000..277c408b5851e75ccbff95ae1ad462373e6fd309 GIT binary patch literal 19836 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 - - Border - A control which decorates a child with a border and background + + Border + A control which decorates a child with a border and background - - - Border - - + Border + + - Border and Background - - Border and Background + + - Rounded Corners - - Rounded Corners + + - Rounded Corners - + + Rounded Corners + Rounded Corners + Rounded Corners + Rounded Corners + Rounded Corners + + + - \ No newline at end of file diff --git a/src/Avalonia.Visuals/Media/FontFamily.cs b/src/Avalonia.Visuals/Media/FontFamily.cs index 7442619b5c..db4ecb2189 100644 --- a/src/Avalonia.Visuals/Media/FontFamily.cs +++ b/src/Avalonia.Visuals/Media/FontFamily.cs @@ -2,41 +2,71 @@ // Licensed under the MIT license. See licence.md file in the project root for full license information. using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using Avalonia.Platform; namespace Avalonia.Media { public class FontFamily { - public FontFamily(string familyName = "Courier New", Uri baseUri = null) + public FontFamily(string name = "Courier New") { - if (familyName == null) throw new ArgumentNullException(nameof(familyName)); - - Key = new FontFamilyKey(familyName, baseUri); + Name = name ?? throw new ArgumentNullException(nameof(name)); } - public string Name => Key.FriendlyName; + public FontFamily(string name, Uri source) : this(name) + { + Key = new FontFamilyKey(source); + } - public Uri BaseUri => Key.BaseUri; + public string Name { get; } public FontFamilyKey Key { get; } public override string ToString() { - return Key.ToString(); + if (Key != null) + { + return Key + "#" + Name; + } + + return Name; } } public class FontFamilyKey { - public FontFamilyKey(string friendlyName, Uri baseUri = null) + public FontFamilyKey(Uri source) { - FriendlyName = friendlyName; - BaseUri = baseUri; + if (source.AbsolutePath.Contains(".ttf")) + { + var filePathWithoutExtension = source.AbsolutePath.Replace(".ttf", ""); + + if (source.Scheme == "resm") + { + var fileNameWithoutExtension = filePathWithoutExtension.Split('.').Last(); + FileName = fileNameWithoutExtension + ".ttf"; + Location = new Uri(source.OriginalString.Replace("." + FileName, ""), UriKind.RelativeOrAbsolute); + } + + if (source.Scheme == "res") + { + FileName = source.AbsolutePath.Split('/').Last(); + } + } + else + { + Location = source; + } } - public string FriendlyName { get; } + public Uri Location { get; } - public Uri BaseUri { get; } + public string FileName { get; } public override int GetHashCode() { @@ -44,14 +74,14 @@ namespace Avalonia.Media { var hash = (int)2166136261; - if (FriendlyName != null) + if (Location != null) { - hash = (hash * 16777619) ^ FriendlyName.GetHashCode(); + hash = (hash * 16777619) ^ Location.GetHashCode(); } - if (BaseUri != null) + if (FileName != null) { - hash = (hash * 16777619) ^ BaseUri.GetHashCode(); + hash = (hash * 16777619) ^ FileName.GetHashCode(); } return hash; @@ -62,117 +92,242 @@ namespace Avalonia.Media { if (!(obj is FontFamilyKey other)) return false; - if (FriendlyName != other.FriendlyName) return false; + if (Location != other.Location) return false; - if (BaseUri != other.BaseUri) return false; + if (FileName != other.FileName) return false; return true; } public override string ToString() { - if (BaseUri != null) + if (FileName != null) { - return BaseUri + "#" + FriendlyName; + if (Location.Scheme == "resm") + { + return Location + "." + FileName; + } + + return Location + "/" + FileName; } - return FriendlyName; + return Location.ToString(); } } - //public class FamilyTypeface - //{ - // public FamilyTypeface(Uri resourceUri = null, FontWeight fontWeight = FontWeight.Normal, FontStyle fontStyle = FontStyle.Normal) - // { - // ResourceUri = resourceUri; - // FontStyle = fontStyle; - // FontWeight = fontWeight; - // } - - // public Uri ResourceUri { get; } - // public FontWeight FontWeight { get; } - // public FontStyle FontStyle { get; } - //} - - //public class FamilyTypefaceKey - //{ - // public FamilyTypefaceKey(FontWeight fontWeight = FontWeight.Normal, FontStyle fontStyle = FontStyle.Normal) - // { - // FontWeight = fontWeight; - // FontStyle = fontStyle; - // } - - // public FontWeight FontWeight { get; } - - // public FontStyle FontStyle { get; } - - // public override int GetHashCode() - // { - // unchecked - // { - // var hash = (int)2166136261; - - // hash = (hash * 16777619) ^ FontWeight.GetHashCode(); - - // hash = (hash * 16777619) ^ FontStyle.GetHashCode(); - - // return hash; - // } - // } - - // public override bool Equals(object obj) - // { - // if (!(obj is FamilyTypefaceKey other)) return false; - - // if (FontWeight != other.FontWeight) return false; - - // if (FontStyle != other.FontStyle) return false; - - // return true; - // } - //} - - //public class CachedFontFamily - //{ - // private readonly ConcurrentDictionary _typefaces = - // new ConcurrentDictionary(); - - // public bool TryGetFamilyTypeface(out FamilyTypeface typeface, FontWeight fontWeight = FontWeight.Normal, - // FontStyle fontStyle = FontStyle.Normal) - // { - // return _typefaces.TryGetValue(new FamilyTypefaceKey(fontWeight, fontStyle), out typeface); - // } - - // public bool TryAddFamilyTypeface(Uri resourceUri, FontWeight fontWeight = FontWeight.Normal, FontStyle fontStyle = FontStyle.Normal) - // { - // var familyTypefaceKeytypefaceKey = new FamilyTypefaceKey(fontWeight, fontStyle); - - // return _typefaces.TryAdd(familyTypefaceKeytypefaceKey, CreateFamilyTypeface(familyTypefaceKeytypefaceKey, resourceUri)); - // } - - // private static FamilyTypeface CreateFamilyTypeface(FamilyTypefaceKey familyTypefaceKey, Uri resourceUri) - // { - // return new FamilyTypeface(resourceUri, familyTypefaceKey.FontWeight, familyTypefaceKey.FontStyle); - // } - //} - - //public class FontFamilyCache - //{ - // private readonly ConcurrentDictionary _cachedFontFamilies = new ConcurrentDictionary(); - - // public bool TryGetCachedFontFamily(FontFamily fontFamily, out CachedFontFamily cachedFontFamily) - // { - // return _cachedFontFamilies.TryGetValue(fontFamily.Key, out cachedFontFamily); - // } - - // public CachedFontFamily GetOrAddCachedFontFamily(FontFamily fontFamily) - // { - // return _cachedFontFamilies.GetOrAdd(fontFamily.Key, CreateCachedFontFamily); - // } - - // private static CachedFontFamily CreateCachedFontFamily(FontFamilyKey fontFamilyKey) - // { - // return new CachedFontFamily(); - // } - //} + public class FontResource + { + public FontResource(Uri source) + { + Source = source; + } + + public Uri Source { get; } + } + + public class FontResourceCollection + { + private Dictionary _fontResources; + private readonly IFontResourceLoader _fontResourceLoader = new FontResourceLoader(); + + public FontResourceCollection(FontFamilyKey key) + { + Key = key; + } + + public FontFamilyKey Key { get; } + + public IEnumerable FontResources + { + get + { + if (_fontResources == null) + { + _fontResources = CreateFontResources(); + } + + return _fontResources.Values; + } + } + + private Dictionary CreateFontResources() + { + return _fontResourceLoader.GetFontResources(Key).ToDictionary(x => x.Source); + } + } + + public interface IFontResourceLoader + { + IEnumerable GetFontResources(FontFamilyKey fontFamilyKey); + } + + public class FontResourceLoader : IFontResourceLoader + { + private static readonly Dictionary s_assemblyNameCache + = new Dictionary(); + + private readonly AssemblyDescriptor _defaultAssembly; + + public FontResourceLoader(Assembly assembly = null) + { + if (assembly == null) + { + assembly = Assembly.GetEntryAssembly(); + } + if (assembly != null) + { + _defaultAssembly = new AssemblyDescriptor(assembly); + } + } + + public IEnumerable GetFontResources(FontFamilyKey fontFamilyKey) + { + return fontFamilyKey.FileName != null + ? GetFontResourcesByFileName(fontFamilyKey.Location, fontFamilyKey.FileName) + : GetFontResourcesByLocation(fontFamilyKey.Location); + } + + private IEnumerable GetFontResourcesByLocation(Uri location) + { + var assembly = GetAssembly(location); + + var locationPath = GetLocationPath(location); + + var matchingResources = assembly.Resources.Where(x => x.Contains(locationPath)); + + return matchingResources.Select(x => new FontResource(GetResourceUri(x, assembly.Name))); + } + + private IEnumerable GetFontResourcesByFileName(Uri location, string fileName) + { + var assembly = GetAssembly(location); + + var compareTo = fileName.Split('*').First(); + + var matchingResources = assembly.Resources.Where(x => x.Contains(compareTo)); + + return matchingResources.Select(x => new FontResource(GetResourceUri(x, assembly.Name))); + } + + private static Uri GetResourceUri(string path, string assemblyName) + { + return new Uri("resm:" + path + "?assembly=" + assemblyName); + } + + private static string GetLocationPath(Uri uri) + { + if (uri.Scheme == "resm") return uri.AbsolutePath; + + var path = new StringBuilder(); + + for (var index = 0; index < uri.Segments.Length; index++) + { + path.Append(uri.Segments[index]); + if (index < uri.Segments.Length - 1) + { + path.Append('.'); + } + } + + return path.ToString(); + } + + private AssemblyDescriptor GetAssembly(Uri uri) + { + if (uri == null) return null; + + var parameters = ParseParameters(uri); + + return parameters.TryGetValue("assembly", out var assemblyName) ? GetAssembly(assemblyName) : null; + } + + private AssemblyDescriptor GetAssembly(string name) + { + if (name == null) + { + return _defaultAssembly; + } + + if (!s_assemblyNameCache.TryGetValue(name, out var rv)) + { + var loadedAssemblies = AvaloniaLocator.Current.GetService().GetLoadedAssemblies(); + var match = loadedAssemblies.FirstOrDefault(a => a.GetName().Name == name); + if (match != null) + { + s_assemblyNameCache[name] = rv = new AssemblyDescriptor(match); + } + else + { + // iOS does not support loading assemblies dynamically! + // +#if NETCOREAPP1_0 + s_assemblyNameCache[name] = rv = new AssemblyDescriptor(Assembly.Load(new AssemblyName(name))); +#elif __IOS__ + throw new InvalidOperationException( + $"Assembly {name} needs to be referenced and explicitly loaded before loading resources"); +#else + s_assemblyNameCache[name] = rv = new AssemblyDescriptor(Assembly.Load(name)); +#endif + } + } + + return rv; + } + + private static Dictionary ParseParameters(Uri uri) + { + return uri.Query.TrimStart('?') + .Split(new[] { '&' }, StringSplitOptions.RemoveEmptyEntries) + .Select(p => p.Split('=')) + .ToDictionary(p => p[0], p => p[1]); + } + + private class AssemblyDescriptor + { + public AssemblyDescriptor(Assembly assembly) + { + Assembly = assembly; + + if (Assembly == null) return; + + Resources = assembly.GetManifestResourceNames().ToList(); + + Name = Assembly.GetName().Name; + } + + public string Name { get; } + public Assembly Assembly { get; } + public List Resources { get; } + } + } + + public class CachedFontFamily + { + private readonly FontResourceCollection _fontResourceCollection; + + public CachedFontFamily(FontFamilyKey key, FontResourceCollection fontResourceCollection) + { + Key = key; + _fontResourceCollection = fontResourceCollection; + } + + public FontFamilyKey Key { get; } + + public IEnumerable FontResources => _fontResourceCollection.FontResources; + } + + public class FontFamilyCache + { + private static readonly ConcurrentDictionary s_cachedFontFamilies = new ConcurrentDictionary(); + + public CachedFontFamily GetOrAddFontFamily(FontFamilyKey key) + { + return s_cachedFontFamilies.GetOrAdd(key, CreateCachedFontFamily); + } + + private static CachedFontFamily CreateCachedFontFamily(FontFamilyKey fontFamilyKey) + { + return new CachedFontFamily(fontFamilyKey, new FontResourceCollection(fontFamilyKey)); + } + } } diff --git a/src/Markup/Avalonia.Markup.Xaml/Converters/FontFamilyTypeConverter.cs b/src/Markup/Avalonia.Markup.Xaml/Converters/FontFamilyTypeConverter.cs index 6cd7c24632..59742f8b12 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Converters/FontFamilyTypeConverter.cs +++ b/src/Markup/Avalonia.Markup.Xaml/Converters/FontFamilyTypeConverter.cs @@ -18,13 +18,16 @@ namespace Avalonia.Markup.Xaml.Converters if (string.IsNullOrEmpty(s)) throw new ArgumentException("Specified family is not supported."); - if (!s.StartsWith("resm:")) return new FontFamily(s); - var fontFamilyExpression = s.Split('#'); + if (fontFamilyExpression.Length == 1) + { + return new FontFamily(s); + } + string familyName; - Uri baseUri = null; + Uri source = null; switch (fontFamilyExpression.Length) { @@ -35,7 +38,7 @@ namespace Avalonia.Markup.Xaml.Converters } case 2: { - baseUri = new Uri(fontFamilyExpression[0], UriKind.RelativeOrAbsolute); + source = new Uri(fontFamilyExpression[0], UriKind.RelativeOrAbsolute); familyName = fontFamilyExpression[1]; break; } @@ -45,7 +48,7 @@ namespace Avalonia.Markup.Xaml.Converters } } - return new FontFamily(familyName, baseUri); + return new FontFamily(familyName, source); } } } \ No newline at end of file diff --git a/src/Shared/PlatformSupport/AssetLoader.cs b/src/Shared/PlatformSupport/AssetLoader.cs index 4287fd0b9e..659a72e9a5 100644 --- a/src/Shared/PlatformSupport/AssetLoader.cs +++ b/src/Shared/PlatformSupport/AssetLoader.cs @@ -106,9 +106,8 @@ namespace Avalonia.Shared.PlatformSupport if (uri != null) { var qs = ParseQueryString(uri); - string assemblyName; - if (qs.TryGetValue("assembly", out assemblyName)) + if (qs.TryGetValue("assembly", out var assemblyName)) { return GetAssembly(assemblyName); } @@ -124,8 +123,7 @@ namespace Avalonia.Shared.PlatformSupport return _defaultAssembly; } - AssemblyDescriptor rv; - if (!AssemblyNameCache.TryGetValue(name, out rv)) + if (!AssemblyNameCache.TryGetValue(name, out var rv)) { var loadedAssemblies = AvaloniaLocator.Current.GetService().GetLoadedAssemblies(); var match = loadedAssemblies.FirstOrDefault(a => a.GetName().Name == name); @@ -199,5 +197,5 @@ namespace Avalonia.Shared.PlatformSupport public Dictionary Resources { get; } public string Name { get; } } - } + } } diff --git a/src/Skia/Avalonia.Skia/TypefaceCache.cs b/src/Skia/Avalonia.Skia/TypefaceCache.cs index ed84d4818e..f4598df8ec 100644 --- a/src/Skia/Avalonia.Skia/TypefaceCache.cs +++ b/src/Skia/Avalonia.Skia/TypefaceCache.cs @@ -56,21 +56,21 @@ namespace Avalonia.Skia if (!entry.TryGetValue(key, out var typeface)) { - if (fontFamily.BaseUri != null) - { - var stream = AvaloniaLocator.Current.GetService().Open(fontFamily.BaseUri); - - typeface = SKTypeface.FromStream(stream); - } - else - { + //if (fontFamily.BaseUri != null) + //{ + // var stream = AvaloniaLocator.Current.GetService().Open(fontFamily.BaseUri); + + // typeface = SKTypeface.FromStream(stream); + //} + //else + //{ typeface = SKTypeface.FromFamilyName(familyKey, key.Weight, SKFontStyleWidth.Normal, key.Slant); if (typeface == null) { typeface = SKTypeface.FromFamilyName(null, SKTypefaceStyle.Normal); } - } + //} entry[key] = typeface; } diff --git a/src/Windows/Avalonia.Direct2D1/Media/FormattedTextImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/FormattedTextImpl.cs index c7356fde1f..732089b79d 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/FormattedTextImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/FormattedTextImpl.cs @@ -4,7 +4,9 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.IO; using System.Linq; +using System.Reflection; using Avalonia.Media; using Avalonia.Platform; using SharpDX; @@ -24,13 +26,17 @@ namespace Avalonia.Direct2D1.Media { Text = text; - var factory = AvaloniaLocator.Current.GetService(); + var factory = AvaloniaLocator.Current.GetService(); DWrite.TextFormat textFormat; - if (typeface.FontFamily.BaseUri != null) + if (typeface.FontFamily.Key != null) { - var fontCollection = Direct2D1CustomFontResourceCache.GetOrAddCustomFontResource(typeface.FontFamily, factory); + var fontFamilyCache = new FontFamilyCache(); + + var fontFamily = fontFamilyCache.GetOrAddFontFamily(typeface.FontFamily.Key); + + var fontCollection = Direct2D1CustomFontCollectionCache.GetOrAddCustomFontCollection(fontFamily, factory); textFormat = new DWrite.TextFormat( factory, @@ -81,11 +87,6 @@ namespace Avalonia.Direct2D1.Media public DWrite.TextLayout TextLayout { get; } - //public void Dispose() - //{ - // TextLayout.Dispose(); - //} - public IEnumerable GetLines() { var result = TextLayout.GetLineMetrics(); @@ -148,19 +149,19 @@ namespace Avalonia.Direct2D1.Media } } - internal static class Direct2D1CustomFontResourceCache + internal static class Direct2D1CustomFontCollectionCache { private static readonly ConcurrentDictionary s_cachedFonts = new ConcurrentDictionary(); - public static DWrite.FontCollection GetOrAddCustomFontResource(FontFamily fontFamily, DWrite.Factory factory) + public static DWrite.FontCollection GetOrAddCustomFontCollection(CachedFontFamily fontFamily, DWrite.Factory factory) { - return s_cachedFonts.GetOrAdd(fontFamily.Key, x => CreateCustomFontResource(x, factory)); + return s_cachedFonts.GetOrAdd(fontFamily.Key, x => CreateCustomFontCollection(fontFamily, factory)); } - private static DWrite.FontCollection CreateCustomFontResource(FontFamilyKey fontFamilyKey, DWrite.Factory factory) + private static DWrite.FontCollection CreateCustomFontCollection(CachedFontFamily fontFamily, DWrite.Factory factory) { - var fontLoader = new ResourceFontLoader(factory, fontFamilyKey.BaseUri); + var fontLoader = new ResourceFontLoader(factory, fontFamily.FontResources); return new DWrite.FontCollection(factory, fontLoader, fontLoader.Key); } @@ -172,27 +173,29 @@ namespace Avalonia.Direct2D1.Media private readonly List _enumerators = new List(); private readonly DataStream _keyStream; - /// /// Initializes a new instance of the class. /// /// The factory. - /// - public ResourceFontLoader(DWrite.Factory factory, Uri fontResource) + /// + public ResourceFontLoader(DWrite.Factory factory, IEnumerable fontResources) { var factory1 = factory; - var assets = AvaloniaLocator.Current.GetService(); + var assetLoader = AvaloniaLocator.Current.GetService(); - var resourceStream = assets.Open(fontResource); + foreach (var font in fontResources) + { + var resourceStream = assetLoader.Open(font.Source); - var dataStream = new DataStream((int)resourceStream.Length, true, true); + var dataStream = new DataStream((int)resourceStream.Length, true, true); - resourceStream.CopyTo(dataStream); + resourceStream.CopyTo(dataStream); - dataStream.Position = 0; + dataStream.Position = 0; - _fontStreams.Add(new ResourceFontFileStream(dataStream)); + _fontStreams.Add(new ResourceFontFileStream(dataStream)); + } // Build a Key storage that stores the index of the font _keyStream = new DataStream(sizeof(int) * _fontStreams.Count, true, true);