@arcgis/core
Version:
ArcGIS Maps SDK for JavaScript: A complete 2D and 3D mapping and data visualization API
3 lines (2 loc) • 5.78 kB
JavaScript
/* COPYRIGHT Esri - https://js.arcgis.com/5.0.8/LICENSE.txt */
import t from"../../../../request.js";import{bidiText as e}from"../../../../core/BidiText.js";import has from"../../../../core/has.js";import{throwIfNotAbortError as i}from"../../../../core/promiseUtils.js";import{loadTextModule as s}from"../../../../libs/text/loadTextModule.js";import{sdfRadiusComplex as h,sdfBufferGlyphSDFCreator as r,sdfSizeComplex as a,sdfBufferServer as o}from"./definitions.js";import{GlyphSDFCreator as n}from"./GlyphSDFCreator.js";import c from"./Rect.js";import l from"./RectangleBinPack.js";import{charCodes as p}from"./Utils.js";import g from"../../../webgl/Texture.js";import{TextureDescriptor as _}from"../../../webgl/TextureDescriptor.js";const d=256,f=.25,u=t=>Math.floor(t/256);function y(t){const e=new Set;for(const i of t)e.add(u(i));return e}function m(t,e,s){return t.has(e)||t.set(e,s().then(()=>{t.delete(e)}).catch(s=>{t.delete(e),i(s)})),t.get(e)}const w=t=>({rect:new c(0,0,0,0),page:0,metrics:{left:0,width:0,height:0,advance:0,top:0},code:t,sdf:!0});class x{constructor(t,e,i){this.width=0,this.height=0,this._dirties=[],this._glyphData=[],this._currentPage=0,this._glyphCache={},this._glyphCacheById={},this._textures=[],this._rangePromises=new Map,this._facePromises=new Map,this._preloadCache={},this._glyphSDFCreator=new n({sdfSizePx:a,sdfBufferPx:r,radius:h,cutoff:f}),this._faces=new Map,this.width=t,this.height=e,this._glyphSource=i,this._binPack=new l(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 s=t[r];for(let t=0;t<11;t++){const h=r>=3&&r<5&&t>=3&&t<8?255:0;e.push(s),i.push(h)}}const s={metrics:{width:5,height:2,left:0,top:0,advance:0},bitmap:new Uint8Array(e)},h={metrics:{width:5,height:2,left:0,top:0,advance:0},bitmap:new Uint8Array(i)};this._recordGlyph(s,o),this._recordGlyph(h,o)}getTexture(t,e){if(!this._textures[e]){const i=new _(this.width,this.height);i.pixelFormat=6406,i.wrapMode=33071,this._textures[e]=new g(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,i,s,h){let r,a,o=!1;if(i){const i=this._getGlyphCacheById(s),h=await this.getFace(s),n=this._glyphSDFCreator.sdfSizePx,[c,l,p]=e(t,!1);o=l;const g=new Uint32Array(Array.from(c).map((t,e)=>p.levels[p.targetToSource[e]]));r={baseline:h.baseline()/n,midline:h.midline()/n},a=h.shape(c,g,n).map(t=>this._getMosaicItemComplex(i,t,h))}else{const[i,r,n]=e(t);o=r;const c=this._getGlyphCache(s),l=p(i);await this._fetchRanges(s,l,h),a=l.map(t=>this._getMosaicItem(c,s,t))}return{isRightToLeft:o,glyphs:a,faceInfo:r}}async getFace(e){if(this._faces.has(e))return this._faces.get(e);const i=this._glyphSource.woffURL(e);return await m(this._facePromises,e,async()=>{const h=await t(i,{responseType:"array-buffer"}),r=(await s()).Face.parseWoff2(new Uint8Array(h.data));this._faces.set(e,r)}),this._faces.get(e)}_getMosaicItem(t,e,i){if(!t[i]){const s=this._glyphSource.getGlyph(e,i);if(!s?.metrics)return w(i);const h=this._recordGlyph(s,o),r=this._currentPage,a=s.metrics;t[i]={rect:h,page:r,metrics:a,code:i,sdf:!0},this._invalidate()}return t[i]}_getMosaicItemComplex(t,e,i){if(!t[e.glyphId]){const s=this._glyphSDFCreator.draw(i,e.glyphId),h={width:s?.width??0,height:s?.height??0,left:s?.left??0,top:s?.top??0,advance:e.xAdvance};let a=new c(0,0,0,0);if(s){const t={bitmap:s.buffer,metrics:h};a=this._recordGlyph(t,r)}const o=e.isNewline?10:e.isWhitespace?32:NaN;t[e.glyphId]={rect:a,page:this._currentPage,metrics:h,sdf:!0,code:o}}return t[e.glyphId]}bind(t,e,i,s){const h=this.getTexture(t,i);h.setSamplingMode(e),t.bindTexture(h,s)}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]}_getGlyphCacheById(t){return this._glyphCacheById[t]||(this._glyphCacheById[t]={}),this._glyphCacheById[t]}_invalidate(){this._dirties[this._currentPage]=!0}async _fetchRanges(t,e,i){const s=y(e),h=[];s.forEach(e=>{h.push(this._fetchRange(t,e,i))}),await Promise.all(h)}async _fetchRange(t,e,i){if(e>d)return;const s=t+e;return m(this._rangePromises,s,()=>this._glyphSource.getRange(t,e,i))}_allocNewPage(){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 l(this.width,this.height)}_recordGlyph(t,e){const i=t.metrics;let s;if(0===i.width)s=new c(0,0,0,0);else{const h=i.width+2*e,r=i.height+2*e;s=this._binPack.allocate(h,r),s.isEmpty&&(this._allocNewPage(),s=this._binPack.allocate(h,r));const a=this._glyphData[this._currentPage],o=t.bitmap;let n,c;if(o)for(let t=0;t<r;t++){n=h*t,c=this.width*(s.y+t)+s.x;for(let t=0;t<h;t++)a[c+t]=o[n+t]}has("esri-glyph-debug")&&this._showDebugPage(a)}return s}_showDebugPage(t){const e=document.createElement("canvas"),i=e.getContext("2d"),s=new ImageData(this.width,this.height),h=s.data;e.width=this.width,e.height=this.height,e.style.border="1px solid black";for(let r=0;r<t.length;++r)h[4*r]=t[r],h[4*r+1]=0,h[4*r+2]=0,h[4*r+3]=255;i.putImageData(s,0,0),document.body.appendChild(e)}}export{x as default};