/* All material copyright ESRI, All Rights Reserved, unless otherwise specified. See https://js.arcgis.com/4.25/esri/copyright.txt for details. */ import{bidiText as t}from"../../core/BidiText.js";import{getFontFamily as e}from"../../core/fontUtils.js";import{clone as r}from"../../core/lang.js";import i from"../../core/Logger.js";import{isNone as s,isSome as o}from"../../core/maybe.js";import n from"../../core/ObjectPool.js";import{px2pt as a,pt2px as l}from"../../core/screenUtils.js";import{create as h,fromValues as c}from"../../geometry/support/aaBoundingRect.js";import{getBoundsXY as m}from"../../geometry/support/boundsUtils.js";import{polygonCentroid as f}from"../../geometry/support/centroid.js";import{isPoint as u,isPolygon as p,isPolyline as d,isExtent as _,isMultipoint as g}from"../../geometry/support/jsonUtils.js";import{SimpleGeometryCursor as y}from"./CIMEffects.js";import P from"./CIMImageColorSubstitutionHelper.js";import{getEffectOperator as w,getPlacementOperator as x}from"./CIMOperators.js";import{Placement as S}from"./CIMPlacements.js";import{LineCapStyle as M,LineJoinStyle as b}from"./enums.js";import{getFirstFrame as k}from"./imageUtils.js";import C from"./Rect.js";import T from"./TextRasterizer.js";import{isSVGImage as I,fromCIMFontDecoration as R,fromCIMFontStyle as v,fromCIMHorizontalAlignment as z,fromCIMVerticalAlignment as F,getFillColor as L,getStrokeColor as A,getFontStyle as j,getFontWeight as U}from"./utils.js";import{HAlign as H,VAlign as B}from"../../views/2d/engine/webgl/alignmentUtils.js";import{GLYPH_SIZE as D,MAGIC_LABEL_LINE_HEIGHT as G}from"../../views/2d/engine/webgl/definitions.js";import{shapeGlyphs as X}from"../../views/2d/engine/webgl/mesh/templates/shapingUtils.js";const E=Math.PI/180,J=10,N=i.getLogger("esri.symbols.cim.CIMSymbolDrawHelper");class O{constructor(t){this._t=t}static createIdentity(){return new O([1,0,0,0,1,0])}clone(){const t=this._t;return new O(t.slice())}transform(t){const e=this._t;return[e[0]*t[0]+e[1]*t[1]+e[2],e[3]*t[0]+e[4]*t[1]+e[5]]}static createScale(t,e){return new O([t,0,0,0,e,0])}scale(t,e){const r=this._t;return r[0]*=t,r[1]*=t,r[2]*=t,r[3]*=e,r[4]*=e,r[5]*=e,this}scaleRatio(){return Math.sqrt(this._t[0]*this._t[0]+this._t[1]*this._t[1])}static createTranslate(t,e){return new O([0,0,t,0,0,e])}translate(t,e){const r=this._t;return r[2]+=t,r[5]+=e,this}static createRotate(t){const e=Math.cos(t),r=Math.sin(t);return new O([e,-r,0,r,e,0])}rotate(t){return O.multiply(this,O.createRotate(t),this)}angle(){const t=this._t[0],e=this._t[3],r=Math.sqrt(t*t+e*e);return[t/r,e/r]}static multiply(t,e,r){const i=t._t,s=e._t,o=i[0]*s[0]+i[3]*s[1],n=i[1]*s[0]+i[4]*s[1],a=i[2]*s[0]+i[5]*s[1]+s[2],l=i[0]*s[3]+i[3]*s[4],h=i[1]*s[3]+i[4]*s[4],c=i[2]*s[3]+i[5]*s[4]+s[5],m=r._t;return m[0]=o,m[1]=n,m[2]=a,m[3]=l,m[4]=h,m[5]=c,r}invert(){const t=this._t;let e=t[0]*t[4]-t[1]*t[3];if(0===e)return new O([0,0,0,0,0,0]);e=1/e;const r=(t[1]*t[5]-t[2]*t[4])*e,i=(t[2]*t[3]-t[0]*t[5])*e,s=t[4]*e,o=-t[1]*e,n=-t[3]*e,a=t[0]*e;return new O([s,o,r,n,a,i])}}class Y{constructor(t,e){this._resourceManager=t,this._transfos=[],this._sizeTransfos=[],this._geomUnitsPerPoint=1,this._placementPool=new n(S,void 0,void 0,100),this._earlyReturn=!1,this._mapRotation=0,this._transfos.push(e||O.createIdentity()),this._sizeTransfos.push(e?e.scaleRatio():1)}setTransform(t,e){this._transfos=[t||O.createIdentity()],this._sizeTransfos=[e||(t?t.scaleRatio():1)]}setGeomUnitsPerPoint(t){this._geomUnitsPerPoint=t}transformPt(t){return this._transfos[this._transfos.length-1].transform(t)}transformSize(t){return t*this._sizeTransfos[this._sizeTransfos.length-1]}reverseTransformPt(t){return this._transfos[this._transfos.length-1].invert().transform(t)}reverseTransformSize(t){return t/this._sizeTransfos[this._sizeTransfos.length-1]}getTransformAngle(){return this._transfos[this._transfos.length-1].angle()}geomUnitsPerPoint(){return this.isEmbedded()?1:this._geomUnitsPerPoint}isEmbedded(){return this._transfos.length>1}back(){return this._transfos[this._transfos.length-1]}push(t,e){const r=e?t.scaleRatio():1;O.multiply(t,this.back(),t),this._transfos.push(t),this._sizeTransfos.push(this._sizeTransfos[this._sizeTransfos.length-1]*r)}pop(){this._transfos.splice(-1,1),this._sizeTransfos.splice(-1,1)}drawSymbol(t,e,r){if(t)switch(t.type){case"CIMPointSymbol":case"CIMLineSymbol":case"CIMPolygonSymbol":this.drawMultiLayerSymbol(t,e);break;case"CIMTextSymbol":this.drawTextSymbol(t,e,r)}}drawMultiLayerSymbol(t,e){if(!t)return;const r=t.symbolLayers;if(!r)return;const i=t.effects;if(i&&i.length>0){const t=this.executeEffects(i,e);if(t){let e=t.next();for(;e;)this.drawSymbolLayers(r,e),e=t.next()}}else this.drawSymbolLayers(r,e)}executeEffects(t,e){const r=this._resourceManager.geometryEngine;let i=new y(e);for(const s of t){const t=w(s);t&&(i=t.execute(i,s,this.geomUnitsPerPoint(),r))}return i}drawSymbolLayers(t,e){let r=t.length;for(;r--;){const i=t[r];if(!i||!1===i.enable)continue;const s=i.effects;if(s&&s.length>0){const t=this.executeEffects(s,e);if(t){let e=null;for(;(e=t.next())&&(this.drawSymbolLayer(i,e),!this._earlyReturn););}}else this.drawSymbolLayer(i,e);if(this._earlyReturn)return}}drawSymbolLayer(t,e){switch(t.type){case"CIMSolidFill":this.drawSolidFill(e,t.color);break;case"CIMHatchFill":this.drawHatchFill(e,t);break;case"CIMPictureFill":this.drawPictureFill(e,t);break;case"CIMGradientFill":this.drawGradientFill(e,t);break;case"CIMSolidStroke":this.drawSolidStroke(e,t.color,t.width,t.capStyle,t.joinStyle,t.miterLimit);break;case"CIMPictureStroke":this.drawPictureStroke(e,t);break;case"CIMGradientStroke":this.drawGradientStroke(e,t);break;case"CIMCharacterMarker":case"CIMPictureMarker":case"CIMVectorMarker":this.drawMarkerLayer(t,e)}}drawHatchFill(t,e){const r=this._buildHatchPolyline(e,t,this.geomUnitsPerPoint());r&&(this.pushClipPath(t),this.drawMultiLayerSymbol(e.lineSymbol,r),this.popClipPath())}drawPictureFill(t,e){}drawGradientFill(t,e){}drawPictureStroke(t,e){}drawGradientStroke(t,e){}drawMarkerLayer(t,e){const r=t.markerPlacement;if(r){const i=x(r);if(i){const s="CIMMarkerPlacementInsidePolygon"===r.type||"CIMMarkerPlacementPolygonCenter"===r.type&&r.clipAtBoundary;s&&this.pushClipPath(e);const o=i.execute(e,r,this.geomUnitsPerPoint(),this._resourceManager.geometryEngine);if(o){let e=null;for(;(e=o.next())&&(this.drawMarker(t,e),!this._earlyReturn););}s&&this.popClipPath()}}else{const r=this._placementPool.acquire();if(u(e))r.tx=e.x,r.ty=e.y,this.drawMarker(t,r);else if(p(e))[r.tx,r.ty]=f(e),this.drawMarker(t,r);else for(const i of e.points)if(r.tx=i[0],r.ty=i[1],this.drawMarker(t,r),this._earlyReturn)break;this._placementPool.release(r)}}drawMarker(t,e){switch(t.type){case"CIMCharacterMarker":case"CIMPictureMarker":this.drawPictureMarker(t,e);break;case"CIMVectorMarker":this.drawVectorMarker(t,e)}}drawPictureMarker(t,e){if(!t)return;const r=this._resourceManager.getResource(t.url),i=t.size??10;if(s(r)||i<=0)return;const o=r.width,n=r.height;if(!o||!n)return;const a=o/n,l=t.scaleX??1,h=O.createIdentity(),c=t.anchorPoint;if(c){let e=c.x,r=c.y;"Absolute"!==t.anchorPointUnits&&(e*=i*a*l,r*=i),h.translate(-e,-r)}let m=t.rotation??0;t.rotateClockwise&&(m=-m),this._mapRotation&&(m+=this._mapRotation),m&&h.rotate(m*E);let f=t.offsetX??0,u=t.offsetY??0;if(f||u){if(this._mapRotation){const t=E*this._mapRotation,e=Math.cos(t),r=Math.sin(t),i=f*r+u*e;f=f*e-u*r,u=i}h.translate(f,u)}const p=this.geomUnitsPerPoint();1!==p&&h.scale(p,p);const d=e.getAngle();d&&h.rotate(d),h.translate(e.tx,e.ty),this.push(h,!1),this.drawImage(t,i),this.pop()}drawVectorMarker(t,e){if(!t)return;const r=t.markerGraphics;if(!r)return;const i=t.size??10,s=t.frame,o=s?s.ymax-s.ymin:0,n=i&&o?i/o:1,a=O.createIdentity();s&&a.translate(.5*-(s.xmax+s.xmin),.5*-(s.ymax+s.ymin));const l=t.anchorPoint;if(l){let e=l.x,r=l.y;"Absolute"!==t.anchorPointUnits?s&&(e*=s.xmax-s.xmin,r*=s.ymax-s.ymin):(e/=n,r/=n),a.translate(-e,-r)}1!==n&&a.scale(n,n);let h=t.rotation??0;t.rotateClockwise&&(h=-h),this._mapRotation&&(h+=this._mapRotation),h&&a.rotate(h*E);let c=t.offsetX??0,m=t.offsetY??0;if(c||m){if(this._mapRotation){const t=E*this._mapRotation,e=Math.cos(t),r=Math.sin(t),i=c*r+m*e;c=c*e-m*r,m=i}a.translate(c,m)}const f=this.geomUnitsPerPoint();1!==f&&a.scale(f,f);const u=e.getAngle();u&&a.rotate(u),a.translate(e.tx,e.ty),this.push(a,t.scaleSymbolsProportionally);for(const p of r)if(p&&p.symbol&&p.geometry||N.error("Invalid marker graphic",p),this.drawSymbol(p.symbol,p.geometry,p.textString),this._earlyReturn)break;this.pop()}drawTextSymbol(t,e,r){if(!t)return;if(!u(e))return;if((t.height??10)<=0)return;const i=O.createIdentity();let s=t.angle??0;s=-s,s&&i.rotate(s*E);const o=t.offsetX??0,n=t.offsetY??0;(o||n)&&i.translate(o,n);const a=this.geomUnitsPerPoint();1!==a&&i.scale(a,a),i.translate(e.x,e.y),this.push(i,!1),this.drawText(t,r),this.pop()}_buildHatchPolyline(t,e,r){let i=(void 0!==t.separation?t.separation:4)*r,s=void 0!==t.rotation?t.rotation:0;if(0===i)return null;i<0&&(i=-i);let o=0;const n=.5*i;for(;o>n;)o-=i;for(;o<-n;)o+=i;const a=h();m(a,e),a[0]-=n,a[1]-=n,a[2]+=n,a[3]+=n;const l=[[a[0],a[1]],[a[0],a[3]],[a[2],a[3]],[a[2],a[1]]];for(;s>180;)s-=180;for(;s<0;)s+=180;const c=Math.cos(s*E),f=Math.sin(s*E),u=-i*f,p=i*c;let d,_,g,y;o=(void 0!==t.offsetX?t.offsetX*r:0)*f-(void 0!==t.offsetY?t.offsetY*r:0)*c,d=g=Number.MAX_VALUE,_=y=-Number.MAX_VALUE;for(const h of l){const t=h[0],e=h[1],r=c*t+f*e,i=-f*t+c*e;d=Math.min(d,r),g=Math.min(g,i),_=Math.max(_,r),y=Math.max(y,i)}g=Math.floor(g/i)*i;let P=c*d-f*g-u*o/i,w=f*d+c*g-p*o/i,x=c*_-f*g-u*o/i,S=f*_+c*g-p*o/i;const M=1+Math.round((y-g)/i),b=[];for(let h=0;h0))if(p(t))this._processPath(t.rings,0);else if(d(t))this._processPath(t.paths,0);else if(_(t)){const e=Q(t);e&&this._processPath(e.rings,0)}else console.error("drawSolidFill Unexpected geometry type!")}drawSolidStroke(t,e,r){if(!t||this._clipCount>0)return;const i=.5*this.transformSize(r);if(p(t))this._processPath(t.rings,i);else if(d(t))this._processPath(t.paths,i);else if(_(t)){const e=Q(t);e&&this._processPath(e.rings,i)}else console.error("drawSolidStroke unexpected geometry type!")}drawMarkerLayer(t,e){p(e)&&t.markerPlacement&&("CIMMarkerPlacementInsidePolygon"===t.markerPlacement.type||"CIMMarkerPlacementPolygonCenter"===t.markerPlacement.type&&t.markerPlacement.clipAtBoundary)?this._processPath(e.rings,0):super.drawMarkerLayer(t,e)}drawHatchFill(t,e){this.drawSolidFill(t)}drawPictureFill(t,e){this.drawSolidFill(t)}drawGradientFill(t,e){this.drawSolidFill(t)}drawPictureStroke(t,e){this.drawSolidStroke(t,null,e.width)}drawGradientStroke(t,e){this.drawSolidStroke(t,null,e.width)}pushClipPath(t){this.drawSolidFill(t),this._clipCount++}popClipPath(){this._clipCount--}drawImage(t,e){const{url:r}=t,i=t.scaleX??1;let s=i*e,n=e;const a=this._resourceManager.getResource(r);!e&&o(a)&&(s=i*a.width,n=a.height),this._merge(this.transformPt([-s/2,-n/2]),0),this._merge(this.transformPt([-s/2,n/2]),0),this._merge(this.transformPt([s/2,-n/2]),0),this._merge(this.transformPt([s/2,n/2]),0)}drawText(t,e){if(!e||0===e.length)return;this._textRasterizer||(this._textRasterizer=new T);const r=et(t),[i,s]=this._textRasterizer.computeTextSize(e,r);let o=0;switch(t.horizontalAlignment){case"Left":o=i/2;break;case"Right":o=-i/2}let n=0;switch(t.verticalAlignment){case"Bottom":n=s/2;break;case"Top":n=-s/2;break;case"Baseline":n=s/6}this._merge(this.transformPt([-i/2+o,-s/2+n]),0),this._merge(this.transformPt([-i/2+o,s/2+n]),0),this._merge(this.transformPt([i/2+o,-s/2+n]),0),this._merge(this.transformPt([i/2+o,s/2+n]),0)}_processPath(t,e){if(t)for(const r of t){const t=r?r.length:0;if(t>1){this._merge(this.transformPt(r[0]),e);for(let i=1;ithis._xmax&&(this._xmax=t[0]+e),t[1]-ethis._ymax&&(this._ymax=t[1]+e)}}class V extends Y{constructor(){super(...arguments),this._searchPoint=[0,0],this._searchDistPoint=0}hitTest(t,e,r,i,s,o){const n=o*l(1);this.setTransform(),this.setGeomUnitsPerPoint(n),this._searchPoint=[(t[0]+t[2])/2,(t[1]+t[3])/2],this._searchDistPoint=(t[2]-t[0])/2/n,this._textInfo=i;const a=e&&("CIMPointSymbol"===e.type&&"Map"!==e.angleAlignment||"CIMTextSymbol"===e.type);return this._mapRotation=a?s:0,this._earlyReturn=!1,this.drawSymbol(e,r),this._earlyReturn}drawSolidFill(t,e){this._hitTestFill(t)}drawHatchFill(t,e){this._hitTestFill(t)}drawPictureFill(t,e){this._hitTestFill(t)}drawGradientFill(t,e){this._hitTestFill(t)}drawSolidStroke(t,e,r,i,s,o){this._hitTestStroke(t,r)}drawPictureStroke(t,e){this._hitTestStroke(t,e.width)}drawGradientStroke(t,e){this._hitTestStroke(t,e.width)}drawMarkerLayer(t,e){t.markerPlacement&&("CIMMarkerPlacementInsidePolygon"===t.markerPlacement.type||"CIMMarkerPlacementPolygonCenter"===t.markerPlacement.type&&t.markerPlacement.clipAtBoundary)?this._hitTestFill(e):super.drawMarkerLayer(t,e)}pushClipPath(t){}popClipPath(){}drawImage(t,e){const{url:r}=t,i=t.scaleX??1,o=this._resourceManager.getResource(r);if(s(o)||0===o.height||0===e)return;const n=e*this.geomUnitsPerPoint(),a=n*i*(o.width/o.height),l=this.reverseTransformPt(this._searchPoint),h=this._searchDistPoint;Math.abs(l[0])t.xTopLeft&&u-t.yBottomRight&&p<-t.yTopLeft){this._earlyReturn=!0;break}}_hitTestFill(t){let e=null;if(_(t)){const r=t;e=[[[r.xmin,r.ymin],[r.xmin,r.ymax],[r.xmax,r.ymax],[r.xmax,r.ymin],[r.xmin,r.ymin]]]}else if(p(t))e=t.rings;else{if(!d(t))return;e=t.paths}const r=this.reverseTransformPt(this._searchPoint);if(this._pointInPolygon(r,e)&&(this._earlyReturn=!0),!this._earlyReturn){const t=this.reverseTransformSize(this._searchDistPoint)*this.geomUnitsPerPoint();this._nearLine(r,e,t)&&(this._earlyReturn=!0)}}_hitTestStroke(t,e){let r=null;if(_(t)){const e=t;r=[[[e.xmin,e.ymin],[e.xmin,e.ymax],[e.xmax,e.ymax],[e.xmax,e.ymin],[e.xmin,e.ymin]]]}else if(p(t))r=t.rings;else{if(!d(t))return;r=t.paths}const i=this.reverseTransformPt(this._searchPoint),s=e*this.geomUnitsPerPoint(),o=this.reverseTransformSize(this._searchDistPoint)*this.geomUnitsPerPoint();this._nearLine(i,r,s/2+o)&&(this._earlyReturn=!0)}_pointInPolygon(t,e){let r=0;for(const i of e){const e=i.length;for(let s=1;st[1]==o[1]>t[1])continue;(o[0]-e[0])*(t[1]-e[1])-(o[1]-e[1])*(t[0]-e[0])>0?r++:r--}}return 0!==r}_nearLine(t,e,r){for(const i of e){const e=i.length;for(let s=1;s-r&&i1){let s=this.transformPt(i[0]);r.moveTo(s[0],s[1]);for(let e=1;et?{spatialReference:t.spatialReference,rings:[[[t.xmin,t.ymin],[t.xmin,t.ymax],[t.xmax,t.ymax],[t.xmax,t.ymin],[t.xmin,t.ymin]]]}:null,Z=t=>{switch(t){case"Left":return H.Left;case"Right":return H.Right;case"Center":return H.Center;case"Justify":return N.warnOnce("Horizontal alignment 'justify' is not implemented. Falling back to 'center'."),H.Center}},$=t=>{switch(t){case"Top":return B.Top;case"Center":return B.Center;case"Bottom":return B.Bottom;case"Baseline":return B.Baseline}},tt=(t,e,r)=>{switch(t){case"ExtraLeading":return 1+e/r;case"Multiple":return e;case"Exact":return e/r}};function et(t,r=1){const i=R(t),s=v(t.fontStyleName),o=e(t.fontFamilyName),{weight:n,style:a}=s,l=r*(t.height||5),h=z(t.horizontalAlignment),c=F(t.verticalAlignment),m=L(t),f=A(t.haloSymbol),u=f?r*(0|t.haloSize):0;return{color:m,size:l,horizontalAlignment:h,verticalAlignment:c,font:{family:o,style:j(a),weight:U(n),decoration:i},halo:{size:u||0,color:f,style:a},pixelRatio:1,premultiplyColors:!0}}const rt=1e-4;function it(t){let e,r,i,s,o,n=t[0],a=1;for(;a