/*
All material copyright Esri, All Rights Reserved, unless otherwise specified.
See https://js.arcgis.com/5.0/esri/copyright.txt for details.
*/
import has from"../../../../core/has.js";import{throwIfNotAbortError as t}from"../../../../core/promiseUtils.js";import e from"./Rect.js";import i from"./RectangleBinPack.js";import h from"../../../webgl/Texture.js";import{TextureDescriptor as s}from"../../../webgl/TextureDescriptor.js";const r=256,a=t=>Math.floor(t/256);function n(t){const e=new Set;for(const i of t)e.add(a(i));return e}function c(e,i,h){return e.has(i)||e.set(i,h().then(()=>{e.delete(i)}).catch(h=>{e.delete(i),t(h)})),e.get(i)}const o=t=>({rect:new e(0,0,0,0),page:0,metrics:{left:0,width:0,height:0,advance:0,top:0},code:t,sdf:!0});class l{constructor(t,e,h){this.width=0,this.height=0,this._dirties=[],this._glyphData=[],this._currentPage=0,this._glyphCache={},this._textures=[],this._rangePromises=new Map,this._preloadCache={},this.width=t,this.height=e,this._glyphSource=h,this._binPack=new i(t,e),this._glyphData.push(new Uint8Array(t*e)),this._dirties.push(!0),this._textures.push(null),this._initDecorationGlyphs()}dispose(){this._binPack=null;for(const t of this._textures)t&&t.dispose();this._textures.length=0,this._glyphData.length=0}_initDecorationGlyphs(){const t=[117,149,181,207,207,181,149,117],e=[],i=[];for(let r=0;r<t.length;r++){const h=t[r];for(let t=0;t<11;t++){const s=r>=3&&r<5&&t>=3&&t<8?255:0;e.push(h),i.push(s)}}const h={metrics:{width:5,height:2,left:0,top:0,advance:0},bitmap:new Uint8Array(e)},s={metrics:{width:5,height:2,left:0,top:0,advance:0},bitmap:new Uint8Array(i)};this._recordGlyph(h),this._recordGlyph(s)}getTexture(t,e){if(!this._textures[e]){const i=new s(this.width,this.height);i.pixelFormat=6406,i.wrapMode=33071,this._textures[e]=new h(t,i,new Uint8Array(this.width*this.height))}return this._dirties[e]&&(this._textures[e].setData(this._glyphData[e]),this._dirties[e]=!1),this._textures[e]}async getGlyphItems(t,e,i){const h=this._getGlyphCache(t);return await this._fetchRanges(t,e,i),e.map(e=>this._getMosaicItem(h,t,e))}bind(t,e,i,h){const s=this.getTexture(t,i);s.setSamplingMode(e),t.bindTexture(s,h)}preloadASCIIGlyphCache(t){const e=this._preloadCache[t];if(null!=e)return e;const i=this._glyphSource.preloadASCIIRange(t).then(()=>{const e=this._getGlyphCache(t);for(let i=0;i<256;i++)this._getMosaicItem(e,t,i)});return this._preloadCache[t]=i,i}_getGlyphCache(t){return this._glyphCache[t]||(this._glyphCache[t]={}),this._glyphCache[t]}_invalidate(){this._dirties[this._currentPage]=!0}async _fetchRanges(t,e,i){const h=n(e),s=[];h.forEach(e=>{s.push(this._fetchRange(t,e,i))}),await Promise.all(s)}async _fetchRange(t,e,i){if(e>r)return;const h=t+e;return c(this._rangePromises,h,()=>this._glyphSource.getRange(t,e,i))}_getMosaicItem(t,e,i){if(!t[i]){const h=this._glyphSource.getGlyph(e,i);if(!h?.metrics)return o(i);const s=this._recordGlyph(h),r=this._currentPage,a=h.metrics;t[i]={rect:s,page:r,metrics:a,code:i,sdf:!0},this._invalidate()}return t[i]}_recordGlyph(t){const h=t.metrics;let s;if(0===h.width)s=new e(0,0,0,0);else{const e=3,r=h.width+2*e,a=h.height+2*e;s=this._binPack.allocate(r,a),s.isEmpty&&(this._dirties[this._currentPage]||(this._glyphData[this._currentPage]=null),this._currentPage=this._glyphData.length,this._glyphData.push(new Uint8Array(this.width*this.height)),this._dirties.push(!0),this._textures.push(null),this._initDecorationGlyphs(),this._binPack=new i(this.width,this.height),s=this._binPack.allocate(r,a));const n=this._glyphData[this._currentPage],c=t.bitmap;let o,l;if(c)for(let t=0;t<a;t++){o=r*t,l=this.width*(s.y+t)+s.x;for(let t=0;t<r;t++)n[l+t]=c[o+t]}has("esri-glyph-debug")&&this._showDebugPage(n)}return s}_showDebugPage(t){const e=document.createElement("canvas"),i=e.getContext("2d"),h=new ImageData(this.width,this.height),s=h.data;e.width=this.width,e.height=this.height,e.style.border="1px solid black";for(let r=0;r<t.length;++r)s[4*r]=t[r],s[4*r+1]=0,s[4*r+2]=0,s[4*r+3]=255;i.putImageData(h,0,0),document.body.appendChild(e)}}export{l as default};
