From f8d0aa06c027416b3204edf38b35b48aa2642ea2 Mon Sep 17 00:00:00 2001 From: Xavier Delamotte Date: Wed, 10 Nov 2021 16:48:00 +0000 Subject: [PATCH] Fix adding CanvasPattern The current code was going into an infinite loop It's also setting `patternUnits` to `userSpaceOnUse` in order to get the same behaviour as canvas patterns --- context.js | 16 +++++++++++----- test/index.js | 30 ++++++++++++++++-------------- test/pattern.png | Bin 0 -> 9805 bytes test/tests/pattern.js | 28 ++++++++++++++++++++++++++++ 4 files changed, 55 insertions(+), 19 deletions(-) create mode 100644 test/pattern.png create mode 100644 test/tests/pattern.js diff --git a/context.js b/context.js index 9410415..2d58188 100644 --- a/context.js +++ b/context.js @@ -371,7 +371,7 @@ export default (function () { }) } - var keys = Object.keys(STYLES), i, style, value, id, regex, matches; + var keys = Object.keys(STYLES), i, style, value, regex, matches, id, nodeIndex, node; for (i = 0; i < keys.length; i++) { style = STYLES[keys[i]]; value = this[keys[i]]; @@ -381,10 +381,11 @@ export default (function () { //pattern if (value.__ctx) { //copy over defs - while(value.__ctx.__defs.childNodes.length) { - id = value.__ctx.__defs.childNodes[0].getAttribute("id"); - this.__ids[id] = id; - this.__defs.appendChild(value.__ctx.__defs.childNodes[0]); + for(nodeIndex = 0; nodeIndex < value.__ctx.__defs.childNodes.length; nodeIndex++){ + node = value.__ctx.__defs.childNodes[nodeIndex]; + id = node.getAttribute("id"); + this.__ids[id] = id; + this.__defs.appendChild(node); } } currentElement.setAttribute(style.apply, format("url(#{id})", {id:value.__root.getAttribute("id")})); @@ -1155,6 +1156,11 @@ export default (function () { pattern.setAttribute("id", id); pattern.setAttribute("width", image.width); pattern.setAttribute("height", image.height); + // We want the pattern sizing to be absolute, and not relative + // https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial/Patterns + // https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/patternUnits + pattern.setAttribute("patternUnits", "userSpaceOnUse"); + if (image.nodeName === "CANVAS" || image.nodeName === "IMG") { img = this.__document.createElementNS("http://www.w3.org/2000/svg", "image"); img.setAttribute("width", image.width); diff --git a/test/index.js b/test/index.js index e5cee00..e5cfbdd 100644 --- a/test/index.js +++ b/test/index.js @@ -15,24 +15,26 @@ import setLineDash from './tests/setLineDash' import text from './tests/text' import tiger from './tests/tiger' import transform from './tests/transform' +import pattern from "./tests/pattern"; const tests = [ tiger, - arc, - arcTo, - arcTo2, - emptyArc, - fillstyle, - globalAlpha, - gradient, - linecap, - linewidth, - rgba, - rotate, - saveandrestore, + arc, + arcTo, + arcTo2, + emptyArc, + fillstyle, + globalAlpha, + gradient, + linecap, + linewidth, + rgba, + rotate, + saveandrestore, setLineDash, text, - transform + transform, + pattern ]; for (let fn of tests) { @@ -56,4 +58,4 @@ for (let fn of tests) { const ctx = c.getContext('2d'); fn(ctx); } -} \ No newline at end of file +} diff --git a/test/pattern.png b/test/pattern.png new file mode 100644 index 0000000000000000000000000000000000000000..f9428249248709c704c8043d651c33a4491789d6 GIT binary patch literal 9805 zcmV-TCbHRyP) zn7Ofw+uXygqIv4-+w1P((ao-;se#76oXF0xrKNey#;3lxlKuYuy|azLx0AcIkFKwX zl9_J1zntyv;_U3-v#5W*w2;8NmbSKyw5ox^yqMO~xA^(>+}OeQ`Stkv_VxGj_W1Mk z_VD@p`1tzw{Qdml;LG~@_vh!^0Q zit_X8zPFOJsDatoz0}XO!MK&StA(+oec9H$*w(w()w$o@$J*GxzO|9%9u!_sZ zrSS6T(95mM#;3-OEFeFe#-zl%ne6T0 z`~3RN#;C8MdcL%fy|Rwo+Qi`C$Q}F!w@cr=c@bU2Q@bLZc@bK{P z@bK{P@bK{P@bK{P@bK{P@bLWb@bK{P_3--e@bKZ`^zh;OO5?}?03ZNKL_t(&-b__{ zP||A}{>?Oz+c+KD>2kK&YCG*T=k&+U>}~@J`Wpm~f`ABKxJll?z#A(3L_`S`Mbt!( zAfn|ZA=HjxXljZHW?G)a`z2f5lWlfNt984bq1|@N3+?;w_k7R$e$Vs1?+5(FbNBD| zA3lBx2J`sMUf}opy}Uet0|$UJp99$IaTs=V-|25XkM7yE*JID#10IL|@a^e6M`50O zcAeRYKkkEl?XmaFE{~I5r#!#;=FnG%PW~D2C~A+*;Us9qsq$Xc?c5Na67mTOf^SEK zS~e2-^Q*;BCJMxHdWg(W=-DDv+^LfL?m!U8T(Ogy#3yDDNg*u`Zc2jC{#Rf(DTLL1 zzF6smdJ=GNt(04Zcpt>hl^|kkNG2V6en){uu!0FOBWr)Pw5Xj7%FZi`NqR)OIXonWzgO9yRNd}+anW;xbyc>YZ z)vHe)()*|drAdD7+-L8_5FY_EMj?f?sZ00_T5E1o*=FRQEs99dNWDmb%m9@GGwb%)=?|7Hy;9E zvFTC$WTMNjwKT1in>THEcH21A-%lyjlgVRltpbL0 zbat`mQjyB_BDmRD!Z!aFI8wl>UJg!P&ZxTBQ*CdSnpu6@c+_ouNM&WAeI%#v$rExK zUad|RBt5*-7s=@qhc$KTy|-a<1%Xj*taF%1{<`*bCFX+PD5;UK`Fce0m z7T9ZGz%e0(=e)`TvvC5j0RkOnT!33!IF02DDRrpB!B@lm>1OV=x5LkpX><;z$thGL z-P)qfBmwP~R8Om0=7>9-yy6EZfMfHr+`*w-V_5^PlzVT;x*C-M_eE?m`y#Tfj@L;^ zN#O8@HtE1X_TtA?x*8<+mzvXjP+Q%FKq1S?DG6z&kz47_GugQAAueI^JK)6R(;>b* zdp)m#S4fJ(%#0z`d>7KSRjxNk4_=PcqxF4csAgkhJ)9lc&jcfvlgU`uR%UM(ynJ~X ztjpvwgg>yYj`8@Y%as$~0Y@ela+w#EB$7_2H4wD4?*%wxYy-6E2f};Ys9+my6r5U6 zJ^AlZ8C`Y7YL^O3x#8gEn4wBQX{71A0LdxBBvKpwFOyoLk)(x*g8)oiK!a{Hay1ev z;gW@*?Ci)rOM&5NZ$)!GhavWh%4yYLURt5q2$3RI`@eKy+`@qLzprIZ+2s8owa zBJsCTn)1q}@881!kJ7mC)W-3Oy z0`*9Q8-O&kZcruEkVJ}v`dDNLD-CX8X!ZkNm6b8oDgK73ckjded6}ZP#yD0c+Hc2Z zR0g|iFb#sz)%2-OwVoYZ)fz#j`+P}@#t3;VtwG0YESQ|_Oe}E7jpnkW0L<#>rN=TD zOKbDB^D6^(jV>-*n(pJK%`z##c<}sSmZ^xMrgb^cSQFJ3_ z4;ZY_l73FvNx;icz1T%EXy1)GnxDl(K(^6Wu{n3{S)BH5_e#_nuU+2 zo0>W%=2~q2kl$JNGKKr1erzDK>pEi0!~kM)%-|SB5=_l{rmSiD>GZ;s$UZ%UcP+~ zm7xdK3iMb6NW@;lMuVp8lAAf<%-|hy5kB;qVvUZ0Sy@_|oY!&dc#KSgCi4{F^|+m+ zv8K36Uh4P>s26zoDO<5Axtr`twYH3AgF!&o$XHmXeq;QuDo)M3#xT5&@ zpN+wYzYnVwSUwRA5Bjt;w*SbA>u8eJhIzcOP-C+>nuUor*}D}l;K@<)4j=4!fn=tp{xbX~y><0%ePDGG$~(R)u(ikCEg3j}gGiK5q2$}h zWHT#nYGcw1IJh?XX`UI2IYq1#oqzNDM-7Plp6T+otL3m*V67k ziAarz@})ED>9JOC-_6{;9D`Ppm||lTHd?|Hgo&2-v$F?*V;d9iE%_`fId$mDIhHol zY)Yt!{OkwE|9(5=Uw~TyeEuMw-#g(_e4i z@4fdU5ES%_w)Lg#(w?3xyBiz7#=O7rg{D`|i>mcHj&0h3KUKi7WIJ=h@j}`1ecLzR zPgk<_KCHJ)FBF$Qe}1_91G6x;U3_Xd@bMK3DJV^3w$5y4_hfEt{1)@)9_RHdQ6Fh{ zR@X1htYg0ER)9-M7RDET7^P@CG&$`JckZuoqQml%(yFb`{^2&M)x=a!p&#EH zj&Tm|zg}KmJ~*6d5enI5&gOwC93k~C9iWcr=2rju6(hZ3%xu>D9&=%_fZN?yn!aET zL?t@pJQiF8LPCi+yp&Kd$1SL_u6(_GaB#48kVsR;)n>s+I#Ix_cDeB9hQlE@M*~v- z!my>M^J3@%=I4zyL(LC@Fy8O$L?UhQ*??J*PEHFes8p%axS}M}v2(Cvl{u_dDgb%8 zS#E**lYu!ag>qJNL7Zwqm48DCr{{KGfou%4gKhIfIop9`feINXxZqPEfY|Tsqj%-u z2V-PuC_<4rI@^r0&d$ZQ1QVzx3Ow>*`9wH|lzO(#hyV$M@u5`;;ZCh3&dj{^OU&s)PgU9Xp zth<9a2Cm}akF!(+!E}c@9BzrZSJrl(|949q$W!3G0zn&$ z3pEVA{N}T**H3BJ`z8jip+|8Ujc3fE9SesZ&)yw-5A&|n9!layz z*9iR|Dh{DF(hy?$d{f?N01F=^EfIz0 z_fwvwzQ-zv9_b%2f7I9tz|;hwQbAOeW}kBB>9kLJS;~P5T$itQtbHr=QN5nYCwFzF zqH$M5-N>0l9;%S^%f7~;5mgdMLBPN&`5nwVT@m=r&T>45R;5>Iznn75e8)A)d?-t5eIDhwJw)++N=Hrk@83aeJbEY5f z8gj!&(71AJH|QKev>~n^fnZ>ZoD(t)-9^depgmTOFFFB%$AdxQ$yF@}(=A_`QTJnbRXrEQjXjno_~pH4Tr zC~skY1<=n9o9(O^U@sBP1N|C?TkC6LvrEg{z=b`QyXJ6ZQ%wOc&e-?YWQ9vYgThrk zY98G6xrdOZV9~(5SJOA3Swc<+3XeDb27@_gy3<$DMUs%?x#;4fDK^cRdIvYLu7dSk z$wGv}E0bgK;~`R)N)YL)%~XKn+Oa-ElZT_cuJ3!mH?apvCD$V7LdE|K^U;|LIyjz5 zo{8T#NQ$xbv81^gUN{YBSm)n80n#?cw*bBpe(bmzbiiHAF-%|(Wc+$GVa2`AA%=h@G%$}8?_J1f2^Sjwb|+M-_#*e|=gEeIeDZ=2KR zWvCn#BBDTRg<&Iu2f@jmhvg4Dgmc{B9} zwmhS@gCPlu0DD-k4#s43kdA|x)J`Uxye*s}((#Mc#zheweat&zuu<3ohovk(E<~A$ z(dL!7pTL4(LE>uoXthT_IJYVcRO9{Z?!Is?5v_1|7>|ePf@@`x+KO@odIz7()KWOy z-Ob-3B*^4I(S)Vv>c7c#(D|Nt4x5CYZ58cpzFN)DHwA=8>CZ&%XkBe}99tc_*1!r{ zhNXzqLKC6#0g_k%DDV&V4Yn>(6&zt^U2Iz?-MrW1gK%f&Z~_Y^tBc!x+~K`@KYk&% zw8VuHwhm$jb&a=^_+$@fHDCmOn*K;L_A=mPX2E&Hnh$ z&vjz$LM3w2Bu`*rVz%>=ziK9?zxQP`t2F{ z)6YRgb`0zC_G@V0zr0;pY4T@R`jvS;U%Bx(LXOL*%5LIJg}W;>>DiH{HmC&Zz4T5)Ip?4R9d_xtvJpZ9s5&4CkBG~81spj0NbK4Go&6oBBr z0RY?_3F70{pSF875z(XyZd?ht#c9gH(eTN^XF2mUW1gvbSM^y)Cuz+lFr}j0t{`S(MqPA&r($etpR%%4! zRF1W$rs#Y)4o9tD^ZSzpl}OiCND=Q5#5uNJqBt&|Ve|=o7MO-YEg`-TP*@WZ<;T7}%))D7yYYZg(=W#EeEroKg3|3o6ruNjn=39JmYcQ=_I_E$0IOP z#AQ%yEQ&OVJyzz>=zgvc5k-PnH&lTDY@LL@yZ#aIu78BNHttVN_KC^GvOw&fI7zMJ z;n5~3{xs^q#K#{;Ww{obL~%w*;ub^^Ot78+g=~*Y9DDjU#byu}5}1k?4=*MqCmse4 z2b$xa{Mw$HO)skd49D1ojmelVQjd8I8iwht!+1sHDWr3jSJHE-`IV=wF}{(sF><+x z*H78~$ROr)`n@8HMC4t2I^7Hn9s%BFH$xL&dF7tl=kFnkoISl7N$D4&leW}A7QR$Q zN5X(Tx9(#({Rl!#D7X?}>n=!>sHToRnHk9l*0&YqdYR0L7buJ#1>WyK?>^~Zf2lFi zki=-mPOXFw%#e=3S6pB!YANlxg({hBrTO$KMFDJB{b6}ynIpqMGN*^f;izzR6%itT9K_7Y*lEkm_PnH&ke?l} z>V`i6{@#g3cyUN=p1vL09rGVo8;ToUHF7uIZ8l@Ec2}DRem=WAGc)%*k%1r*H_2XxbumBUbAQ zHr7k5rr91cuD>(cuXPQy5)p~nnVv2#rn`*X{f1ET`8wBU1F-eNov=C8Xa-T8uz`}f zd3--a5BO-7ei{*Lm$WPozjD|2HHUhh*Y?)wAPpUB=B;RnRJ#OgvCy#Q(mi1trgYeA z>KlO*5z!z=HS%u!fM;x zvjsEJCr#8F=;>E3rWg^))a=r2?cBz2U!#^PXJ_uiVn!8mnB;c~;H+c7Ut|NhgyZ1L z63hW@V4|YCk#qKyrP+J+t5W5cM@a2;2s(^bYpzBy(+)DsMjo~57`uWzI*Ux%*JRFTGbgSmESOYaE z%q92nB#TQ+R~LI4#hpQkcXy69oB%mwD#71+Wnv#qi{sf~Pm`<_Vu3}MJgYG7cSS6VY7ZrVD!6oU}g~V#J zQ(Wf`o+F<<<=C~+m`H9WjB%X0rXRcXzejHa?@mg)+iN=__{j+nMF#CwSw<*dEKxTG zRX8HGmx&`g=dRwmzcAcW7#9BW+Lmzt34>-{(*^eK#*%ykOok$1^E;~`ubaU<3LF{x z@#`0g*0`F4lh->8rqSr_-wD;0BwGuTOY8C!cfC}#4s7k_>(_5qZc~FUQw@ilZ^OEZ zRkgTm`4%mLQQbYg*0eNfbIKUw+x0H*5#YU`@9A`&0J5?lK7!Of*s-0n%XMkch^NUG zh#RRnGjAVoFNRTHKU-L_H|FZjG@vlvttQ}Me17sa?53V)oc+OuUjis{@Cp`aY_H@(%OR3+RpHvIn$3-hppS9M%*7twk_b+@RVOB0rWEf_$L+7({AN}F)55N0vYMVoEMQCY~ z90rx-)FeW3c|02g4W|rw^Ky%%>$y8W4|CyP0LRI6`s{tI*(f{y}xbZb7Bz1?9KriCZt{wrqK>$)ms_ zSs?{R{`;n9^@SwJrKBFREWJZxzAHG0$WN*AU1{|AvUIDwgE-v|ux%{Rlhj73ROgXi{ zJjdknbBOnHuQk+h>Ml6W{a#2Z-)4p;+YU?sCB%!N`=VS5{fzW-5$PZQIR<=ncXgeL z+$t;V3bOCadc6f7Xd}T%Y8^3^hG1T#%aJThrso^9Dv>>?>RJfV&jbthn*^xPtQN-> z?RK`CqP%7BzIgWX7;t3bc?G0_EW~B8b2gwXO~qh8pgFN`^rjL?(zdJ>dUG6AmxQZVghM;<1@3F*bJM`P}V8!0*;QPB8<;fr?Zie`Jlb%$VJw z)ji2Jt zdBCW-jub7o&uR>*PJGHPugBnG=tdB{t$vq!9Nz39-Q{VKfE*Ib4+F>X8lCFpyw>FI zT%~QzJJS6y4y9tM#(j8>+b=%qV2CeM4K~YSVBCV-b9X8-r~_akv2w}PHNVwkE1j}# zJbsld!6%`&%##`r++ArZ4!wJ~xV2%w)tAPA#KI;%<6~0{#Ls3%RJkTNV!(ZDK7rWA zwwYg#2Nc9$IH?`S(!Nhf{LC3Qi_>u!Q zImVaNp5ZIK67-l^|5l}(BwXO3^6!20&_ zTPA{H!sX~zr-E?;l?_m_nW?bBa{=L)gqRJ1DcBE7_BG1tFLuc~d>7#)RUP&Mc^XUi1kmP74 zo8nj7RF_(YX~X%YW`AKIK0KX87r7io;?IENID&ymRytzMZ9unEBDC-5Ky#WZn0 zBc=^=M%w!sIf8y;gwx>YFQ2Zh*LyMlA6B8NQFEDjSJFDmrOtx-HOHXpY!x1@CX2IP z4|+g^KLdUqXp7+qAb}7Mn{k#pLaRVUYst*fw$JA4su*AgCGM7p^2BUe*=8sDn;cx%FNKwF{GipJ>Bk= zBg&_I7OPLW{fMO}#30NkNN@rg6OBwgMM<=+X2C}C^{QLCyGIvt9i54mV^F3CTYylTUhz^;~Iy%s6O{rs1}m#)IzDw%mG zRB|W2J1AOUdsO4285QfY?(V;pg^9$g`DH4JZ?D7~#_Mb}eYE+>(o%Y|C$&U5DzM;j z5DtZn?CIokztNMZpm2T#{M4mJ;1Q`wF}O>=(A0Sh^-6Z5c!o0^3P&SUYS37giQTPj z4EA`jfl6yqg-mK=8%bAxIXK23#0TLEY`HVca%nQv=+6Bd_z{_I;;!ZEkZJvHSUl*9 zQ3DaH9xczLOuk|L_QdINcG6BuRbx?}zW#iUXcZ7E{z)V9BM95_zgYvdfcuCwbxZsc zHz)W;2QFY`kZdknK5yodh(_?}letyHd|)AKZdv3R67DjwXjjO|{C6*w<#~X|FRUv( zx7%f(d74w>Tw!J#QyLQG0<6Pry1PMD^~6I7Wu;YRPQ^~mDI5%@Jc45Ue5|ZWLVPMF zCJe&dtXvEx3=AgRG9o~RG`|uDJ3Bi+4>xFS9Wyt-5<9yjE5E!jPzi$!hYT|(P?R0K n@J@wKK!TN3R!mS`S=JN)jB+ZT)nS)600000NkvXXu0mjf2Lkbt literal 0 HcmV?d00001 diff --git a/test/tests/pattern.js b/test/tests/pattern.js new file mode 100644 index 0000000..72df662 --- /dev/null +++ b/test/tests/pattern.js @@ -0,0 +1,28 @@ +export default function pattern(ctx) { + // Create a pattern + const patternCanvas = document.createElement('canvas'); + const patternContext = patternCanvas.getContext('2d'); + + // Give the pattern a width and height of 50 + patternCanvas.width = 50; + patternCanvas.height = 50; + + // Give the pattern a background color and draw an arc + patternContext.fillStyle = '#fec'; + patternContext.fillRect(0, 0, patternCanvas.width, patternCanvas.height); + patternContext.arc(0, 0, 50, 0, .5 * Math.PI); + patternContext.stroke(); + + const pattern = ctx.createPattern(patternCanvas, 'repeat'); + ctx.fillStyle = pattern; + ctx.fillRect(0, 0, 50, 50); + + var img = new Image(); + img.src = 'pattern.png'; + img.onload = function() { + var pattern = ctx.createPattern(img, 'repeat'); + ctx.fillStyle = pattern; + ctx.fillRect(50, 50, 300, 300); + }; + +};