@@ -22,14 +22,15 @@ export function tryDrawCustomGlyph(
2222 deviceCharHeight : number ,
2323 fontSize : number ,
2424 devicePixelRatio : number ,
25- backgroundColor ?: string
25+ backgroundColor ?: string ,
26+ variantOffset : number = 0
2627) : boolean {
2728 const unifiedCharDefinition = customGlyphDefinitions [ c ] ;
2829 if ( unifiedCharDefinition ) {
2930 // Normalize to array for uniform handling
3031 const parts = Array . isArray ( unifiedCharDefinition ) ? unifiedCharDefinition : [ unifiedCharDefinition ] ;
3132 for ( const part of parts ) {
32- drawDefinitionPart ( ctx , part , xOffset , yOffset , deviceCellWidth , deviceCellHeight , deviceCharWidth , deviceCharHeight , fontSize , devicePixelRatio , backgroundColor ) ;
33+ drawDefinitionPart ( ctx , part , xOffset , yOffset , deviceCellWidth , deviceCellHeight , deviceCharWidth , deviceCharHeight , fontSize , devicePixelRatio , backgroundColor , variantOffset ) ;
3334 }
3435 return true ;
3536 }
@@ -48,7 +49,8 @@ function drawDefinitionPart(
4849 deviceCharHeight : number ,
4950 fontSize : number ,
5051 devicePixelRatio : number ,
51- backgroundColor ?: string
52+ backgroundColor ?: string ,
53+ variantOffset : number = 0
5254) : void {
5355 // Handle scaleType - adjust dimensions and offset when scaling to character area
5456 let drawWidth = deviceCellWidth ;
@@ -74,7 +76,7 @@ function drawDefinitionPart(
7476 drawBlockVectorChar ( ctx , part . data , drawXOffset , drawYOffset , drawWidth , drawHeight ) ;
7577 break ;
7678 case CustomGlyphDefinitionType . BLOCK_PATTERN :
77- drawPatternChar ( ctx , part . data , drawXOffset , drawYOffset , drawWidth , drawHeight ) ;
79+ drawPatternChar ( ctx , part . data , drawXOffset , drawYOffset , drawWidth , drawHeight , variantOffset ) ;
7880 break ;
7981 case CustomGlyphDefinitionType . PATH_FUNCTION :
8082 drawPathFunctionCharacter ( ctx , part . data , drawXOffset , drawYOffset , drawWidth , drawHeight , devicePixelRatio , part . strokeWidth ) ;
@@ -437,7 +439,8 @@ function drawPatternChar(
437439 xOffset : number ,
438440 yOffset : number ,
439441 deviceCellWidth : number ,
440- deviceCellHeight : number
442+ deviceCellHeight : number ,
443+ variantOffset : number = 0
441444) : void {
442445 let patternSet = cachedPatterns . get ( charDefinition ) ;
443446 if ( ! patternSet ) {
@@ -486,6 +489,15 @@ function drawPatternChar(
486489 pattern = throwIfFalsy ( ctx . createPattern ( tmpCanvas , null ) ) ;
487490 patternSet . set ( fillStyle , pattern ) ;
488491 }
492+ // Apply pattern offset to ensure seamless tiling across cells when cell dimensions are odd.
493+ // variantOffset encodes: bit 1 = x pixel shift, bit 0 = y pixel shift.
494+ const dx = ( variantOffset >> 1 ) & 1 ;
495+ const dy = variantOffset & 1 ;
496+ if ( dx !== 0 || dy !== 0 ) {
497+ pattern . setTransform ( new DOMMatrix ( ) . translateSelf ( - dx , - dy ) ) ;
498+ } else {
499+ pattern . setTransform ( new DOMMatrix ( ) ) ;
500+ }
489501 ctx . fillStyle = pattern ;
490502 ctx . fillRect ( xOffset , yOffset , deviceCellWidth , deviceCellHeight ) ;
491503}
0 commit comments