1/* holo-masks - Evidence HoloHDR engine: mask rasterizers. 2 3 Every function returns a plain 2D canvas the backends upload as the mask 4 texture (alpha = foil coverage; RED channel = steel glyphs). Two-canvas 5 convention from the reference implementation: the shader texture is a FULL 6 COVERAGE fill (black, or red for steel), while the SHAPE (rounded pill / 7 glyphs) is applied as a CSS mask-image data-URL on the injected canvas - 8 CSS masks clip AFTER the blur filter, so any softening affects only the 9 effect while silhouettes and letter edges stay crisp. 10 11 Premultiply caveat (load-bearing): the canvas-to-GPU upload premultiplies, 12 so steel glyphs are ALWAYS drawn '#f00' at alpha 1 - NEVER partial alpha, 13 the premultiply round trip would corrupt the red value. */ 14(function(){ 15 'use strict'; 16 var H=window.EVD_HOLO; 17 if(!H||H._masks) return; 18 19 var CAP=4096; /* texture edge cap - shared with both backends */ 20 21 function mk(W,H2){ 22 var c=document.createElement('canvas'); 23 c.width=Math.max(1,Math.min(Math.round(W),CAP)); 24 c.height=Math.max(1,Math.min(Math.round(H2),CAP)); 25 return c; 26 } 27 28 /* full-coverage fill: the shader shades the whole rect; shape comes from 29 CSS masks (ours below, or the element's own .hl--pat rules) */ 30 function fullMask(W,H2,steel){ 31 var oc=mk(W,H2); 32 var c=oc.getContext('2d'); 33 c.fillStyle=steel?'#f00':'#000'; 34 c.fillRect(0,0,oc.width,oc.height); 35 return oc; 36 } 37 38 /* rounded-rect at the element's own computed border radius */ 39 function roundedRect(el,W,H2,DPR){ 40 var oc=mk(W,H2); 41 var c=oc.getContext('2d'); 42 var rad=parseFloat(getComputedStyle(el).borderTopLeftRadius)||0; 43 /* clamp to min(w,h)/2: pill radii (9999px, .hl--btn) rasterize as true 44 stadium caps instead of a corrupt path */ 45 var r=Math.min(rad*DPR,oc.width/2,oc.height/2); 46 var w=oc.width,h=oc.height; 47 /* black fill: the shape read is ALPHA only, red stays 0 for steel */ 48 c.fillStyle='#000'; 49 c.beginPath(); 50 c.moveTo(r,0); c.lineTo(w-r,0); c.arcTo(w,0,w,r,r); 51 c.lineTo(w,h-r); c.arcTo(w,h,w-r,h,r); 52 c.lineTo(r,h); c.arcTo(0,h,0,h-r,r); 53 c.lineTo(0,r); c.arcTo(0,0,r,0,r); 54 c.closePath(); c.fill(); 55 return oc; 56 } 57 58 /* the element's own text rasterised as glyphs (steel masks). Pass the 59 previous raster as `reuse` to redraw in place (EVD_HOLO.refresh's cheap 60 path for live steel counters - no per-tick canvas allocation). */ 61 function glyphs(el,W,H2,DPR,reuse){ 62 var oc=reuse||mk(W,H2); 63 if(reuse){ 64 var rw=Math.max(1,Math.min(Math.round(W),CAP)); 65 var rh=Math.max(1,Math.min(Math.round(H2),CAP)); 66 if(oc.width!==rw) oc.width=rw; 67 if(oc.height!==rh) oc.height=rh; 68 } 69 var c=oc.getContext('2d'); 70 c.clearRect(0,0,oc.width,oc.height); 71 var style=getComputedStyle(el); 72 var fpx=parseFloat(style.fontSize)*DPR; 73 c.fillStyle='#f00'; 74 c.font=style.fontStyle+' '+style.fontWeight+' '+fpx+'px '+style.fontFamily; 75 var ls=parseFloat(style.letterSpacing); 76 if(!isNaN(ls)) c.letterSpacing=(ls*DPR)+'px'; 77 c.textBaseline='middle'; 78 var text=el.textContent; 79 c.fillText(text, 80 (oc.width-c.measureText(text).width)/2, 81 oc.height*0.5+fpx*0.04); /* small optical drop */ 82 return oc; 83 } 84 85 /* fit an image into the box: 'cover' anchors bottom-right, 'left'/'right' 86 scale to width; capped at 4096 by mk() */ 87 function svgFit(img,W,H2,fit){ 88 var oc=mk(W,H2); 89 var c=oc.getContext('2d'); 90 var iw=img.naturalWidth||img.width,ih=img.naturalHeight||img.height; 91 if(!iw||!ih) return oc; 92 var s,dw,dh; 93 if(fit==='cover'){ 94 s=Math.max(oc.width/iw,oc.height/ih); dw=iw*s; dh=ih*s; 95 c.drawImage(img,oc.width-dw,oc.height-dh,dw,dh); /* anchor bottom right */ 96 }else{ 97 s=oc.width/iw; dw=oc.width; dh=ih*s; 98 c.drawImage(img,0,0,dw,dh); 99 } 100 return oc; 101 } 102 103 /* vertical band: fill the band's width and TILE down the full height 104 (the artworks are repeating columns) */ 105 function svgTile(img,W,H2){ 106 var oc=mk(W,H2); 107 var c=oc.getContext('2d');
108 var iw=img.naturalWidth||img.width,ih=img.naturalHeight||img.height; 109 if(!iw||!ih) return oc; 110 var s=oc.width/iw, dw=oc.width, dh=ih*s; 111 for(var ty=0;ty<oc.height;ty+=dh){ c.drawImage(img,0,ty,dw,dh); } 112 return oc; 113 } 114 115 /* composite: rounded ring stroke (tier ring frame) with an optional shape 116 drawn inside. The tier card covers the centre, so the plain plate works 117 too - the stroke variant keeps the alpha honest for translucent pages. */ 118 function composite(el,W,H2,DPR,opts){ 119 opts=opts||{}; 120 var oc=roundedRect(el,W,H2,DPR); 121 if(opts.ring){ 122 var c=oc.getContext('2d'); 123 var t=Math.max(2,(opts.ringWidth||8)*DPR); 124 c.globalCompositeOperation='destination-out'; 125 var rad=parseFloat(getComputedStyle(el).borderTopLeftRadius)||0; 126 var r=Math.max(0,Math.min(rad*DPR,oc.height/2)-t); 127 var x=t,y=t,w=oc.width-2*t,h=oc.height-2*t; 128 c.beginPath(); 129 c.moveTo(x+r,y); c.lineTo(x+w-r,y); c.arcTo(x+w,y,x+w,y+r,r); 130 c.lineTo(x+w,y+h-r); c.arcTo(x+w,y+h,x+w-r,y+h,r); 131 c.lineTo(x+r,y+h); c.arcTo(x,y+h,x,y+h-r,r); 132 c.lineTo(x,y+r); c.arcTo(x,y,x+r,y,r); 133 c.closePath(); c.fill(); 134 c.globalCompositeOperation='source-over'; 135 } 136 return oc; 137 } 138 139 /* the live globe mask contract: the backend re-uploads the registered 140 canvas whenever its version advances (published by holo-globe.js) */ 141 function liveGlobe(){ 142 return window.EVD_HOLO_GLOBE||null; 143 } 144 145 /* the SHAPE canvas applied as a CSS mask on the injected canvas: clips 146 after blur, silhouettes stay crisp */ 147 function applyCssMask(canvas,shape){ 148 try{ 149 var du=shape.toDataURL(); 150 canvas.style.webkitMaskImage='url('+du+')'; 151 canvas.style.maskImage='url('+du+')'; 152 canvas.style.webkitMaskSize='100% 100%'; 153 canvas.style.maskSize='100% 100%'; 154 /* reset any leftover intersect layering (surface re-classified) */ 155 canvas.style.webkitMaskPosition=''; 156 canvas.style.maskPosition=''; 157 canvas.style.webkitMaskRepeat=''; 158 canvas.style.maskRepeat=''; 159 canvas.style.webkitMaskComposite=''; 160 canvas.style.maskComposite=''; 161 }catch(e){} 162 } 163 164 /* glyph â© pattern: two comma-layered mask images - the rastered glyph 165 shape first (stretched over the box, like applyCssMask), the pattern 166 tile second (center-anchored, .hl--pat-* conventions) - composited with 167 mask-composite:intersect (standard) / -webkit-mask-composite:source-in 168 (legacy alias of the same op), so the foil only shows where BOTH the 169 glyphs and the tile have alpha. tileSize defaults to 'cover' to mirror 170 the .hl--pat-* rules; pass e.g. 'auto 100%' for repeating strips. */ 171 function applyCssMaskIntersect(canvas,shape,tileUrl,tileSize){ 172 try{ 173 var du=shape.toDataURL(); 174 var layers='url('+du+'), url("'+tileUrl+'")'; 175 var size='100% 100%, '+(tileSize||'cover'); 176 canvas.style.webkitMaskImage=layers; 177 canvas.style.maskImage=layers; 178 canvas.style.webkitMaskSize=size; 179 canvas.style.maskSize=size; 180 canvas.style.webkitMaskPosition='0 0, center'; 181 canvas.style.maskPosition='0 0, center'; 182 canvas.style.webkitMaskRepeat='no-repeat, no-repeat'; 183 canvas.style.maskRepeat='no-repeat, no-repeat'; 184 canvas.style.webkitMaskComposite='source-in'; 185 canvas.style.maskComposite='intersect'; 186 }catch(e){} 187 } 188 function clearCssMask(canvas){ 189 canvas.style.webkitMaskImage=''; 190 canvas.style.maskImage=''; 191 canvas.style.webkitMaskSize=''; 192 canvas.style.maskSize=''; 193 canvas.style.webkitMaskPosition=''; 194 canvas.style.maskPosition=''; 195 canvas.style.webkitMaskRepeat=''; 196 canvas.style.maskRepeat=''; 197 canvas.style.webkitMaskComposite=''; 198 canvas.style.maskComposite=''; 199 } 200 201 H._masks={ 202 CAP:CAP, 203 fullMask:fullMask, 204 roundedRect:roundedRect, 205 glyphs:glyphs, 206 svgFit:svgFit, 207 svgTile:svgTile, 208 composite:composite, 209 liveGlobe:liveGlobe, 210 applyCssMask:applyCssMask, 211 applyCssMaskIntersect:applyCssMaskIntersect, 212 clearCssMask:clearCssMask 213 }; 214})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.