diff --git a/addons/addon-webgl/src/customGlyphs/CustomGlyphDefinitions.ts b/addons/addon-webgl/src/customGlyphs/CustomGlyphDefinitions.ts index 1a77d86f..601ff6a7 100644 --- a/addons/addon-webgl/src/customGlyphs/CustomGlyphDefinitions.ts +++ b/addons/addon-webgl/src/customGlyphs/CustomGlyphDefinitions.ts @@ -499,7 +499,22 @@ export const customGlyphDefinitions: { [index: string]: CustomGlyphCharacterDefi // Triangular shade characters (1FB9C-1FB9F) - // TODO: Implement + '\u{1FB9C}': { type: CustomGlyphDefinitionType.BLOCK_PATTERN_WITH_CLIP_PATH, data: [[ // UPPER LEFT TRIANGULAR MEDIUM SHADE + [1, 0], + [0, 1] + ], 'M0,0 L1,0 L0,1 Z'] }, + '\u{1FB9D}': { type: CustomGlyphDefinitionType.BLOCK_PATTERN_WITH_CLIP_PATH, data: [[ // UPPER RIGHT TRIANGULAR MEDIUM SHADE + [1, 0], + [0, 1] + ], 'M0,0 L1,0 L1,1 Z'] }, + '\u{1FB9E}': { type: CustomGlyphDefinitionType.BLOCK_PATTERN_WITH_CLIP_PATH, data: [[ // LOWER RIGHT TRIANGULAR MEDIUM SHADE + [1, 0], + [0, 1] + ], 'M1,0 L1,1 L0,1 Z'] }, + '\u{1FB9F}': { type: CustomGlyphDefinitionType.BLOCK_PATTERN_WITH_CLIP_PATH, data: [[ // LOWER LEFT TRIANGULAR MEDIUM SHADE + [1, 0], + [0, 1] + ], 'M0,0 L1,1 L0,1 Z'] }, // Character cell diagonals (1FBA0-1FBAE) '\u{1FBA0}': { type: CustomGlyphDefinitionType.PATH_FUNCTION_WITH_WEIGHT, data: { [FontWeight.NORMAL]: 'M.5,0 L0,.5' } }, // BOX DRAWINGS LIGHT DIAGONAL UPPER CENTRE TO MIDDLE LEFT diff --git a/addons/addon-webgl/src/customGlyphs/CustomGlyphRasterizer.ts b/addons/addon-webgl/src/customGlyphs/CustomGlyphRasterizer.ts index 549230ad..495bc70e 100644 --- a/addons/addon-webgl/src/customGlyphs/CustomGlyphRasterizer.ts +++ b/addons/addon-webgl/src/customGlyphs/CustomGlyphRasterizer.ts @@ -37,6 +37,9 @@ export function tryDrawCustomGlyph( drawBlockPatternWithRegion(ctx, unifiedCharDefinition.data.pattern, xOffset, yOffset, deviceCellWidth, deviceCellHeight); drawBlockVectorChar(ctx, unifiedCharDefinition.data.vectors, xOffset, yOffset, deviceCellWidth, deviceCellHeight); return true; + case CustomGlyphDefinitionType.BLOCK_PATTERN_WITH_CLIP_PATH: + drawBlockPatternWithClipPath(ctx, unifiedCharDefinition.data, xOffset, yOffset, deviceCellWidth, deviceCellHeight); + return true; case CustomGlyphDefinitionType.PATH_FUNCTION: case CustomGlyphDefinitionType.PATH: drawPathDefinitionCharacter(ctx, unifiedCharDefinition.data, xOffset, yOffset, deviceCellWidth, deviceCellHeight); @@ -286,6 +289,49 @@ function drawPathDefinitionCharacterWithWeight( } } +/** + * Draws a pattern clipped to an arbitrary path (for triangular shades, etc.) + */ +function drawBlockPatternWithClipPath( + ctx: CanvasRenderingContext2D, + definition: [pattern: CustomGlyphPatternDefinition, clipPath: string], + xOffset: number, + yOffset: number, + deviceCellWidth: number, + deviceCellHeight: number +): void { + const [pattern, clipPath] = definition; + + ctx.save(); + + // Build clip path from SVG-like instructions + ctx.beginPath(); + for (const instruction of clipPath.split(' ')) { + const type = instruction[0]; + if (type === 'Z') { + ctx.closePath(); + continue; + } + const args: string[] = instruction.substring(1).split(','); + if (!args[0] || !args[1]) { + continue; + } + const x = xOffset + parseFloat(args[0]) * deviceCellWidth; + const y = yOffset + parseFloat(args[1]) * deviceCellHeight; + if (type === 'M') { + ctx.moveTo(x, y); + } else if (type === 'L') { + ctx.lineTo(x, y); + } + } + ctx.clip(); + + // Draw the pattern + drawPatternChar(ctx, pattern, xOffset, yOffset, deviceCellWidth, deviceCellHeight); + + ctx.restore(); +} + function drawVectorShape( ctx: CanvasRenderingContext2D, charDefinition: ICustomGlyphVectorShape, diff --git a/addons/addon-webgl/src/customGlyphs/Types.ts b/addons/addon-webgl/src/customGlyphs/Types.ts index bfe5155a..4623ea46 100644 --- a/addons/addon-webgl/src/customGlyphs/Types.ts +++ b/addons/addon-webgl/src/customGlyphs/Types.ts @@ -35,6 +35,7 @@ export const enum CustomGlyphDefinitionType { BLOCK_PATTERN, BLOCK_PATTERN_WITH_REGION, BLOCK_PATTERN_WITH_REGION_AND_SOLID_OCTANT_BLOCK_VECTOR, + BLOCK_PATTERN_WITH_CLIP_PATH, PATH_FUNCTION, PATH_FUNCTION_WITH_WEIGHT, PATH, @@ -50,6 +51,7 @@ export type CustomGlyphCharacterDefinition = ( // TODO: Consolidate these, draws should be possible via regions/clipping instead of special // casing { type: CustomGlyphDefinitionType.BLOCK_PATTERN_WITH_REGION_AND_SOLID_OCTANT_BLOCK_VECTOR, data: { pattern: [pattern: CustomGlyphPatternDefinition, region: CustomGlyphRegionDefinition], vectors: ICustomGlyphSolidOctantBlockVector[] } } | + { type: CustomGlyphDefinitionType.BLOCK_PATTERN_WITH_CLIP_PATH, data: [pattern: CustomGlyphPatternDefinition, clipPath: string] } | { type: CustomGlyphDefinitionType.PATH_FUNCTION, data: CustomGlyphPathDrawFunctionDefinition } | { type: CustomGlyphDefinitionType.PATH_FUNCTION_WITH_WEIGHT, data: { [fontWeight: number]: string | CustomGlyphPathDrawFunctionDefinition } } | { type: CustomGlyphDefinitionType.PATH, data: string } |