Skip to content

Commit

Permalink
Chore: Cleanup Text and TextMetrics (#8915)
Browse files Browse the repository at this point in the history
  • Loading branch information
SuperSodaSea committed Dec 2, 2022
1 parent ec72e44 commit 7151ba7
Show file tree
Hide file tree
Showing 6 changed files with 225 additions and 207 deletions.
4 changes: 3 additions & 1 deletion bundles/pixi.js-node/src/adapter/adapter.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import canvasModule from 'canvas';
import { fetch, Request, Response } from 'cross-fetch';
import fs from 'fs';
import { WebGLRenderingContext } from 'gl';
Expand All @@ -15,7 +16,8 @@ export const NodeAdapter = {
* @param height - height of the canvas
*/
createCanvas: (width?: number, height?: number) => new NodeCanvasElement(width, height),
/** Returns a webgl rendering context using the gl package. */
getCanvasRenderingContext2D: () => canvasModule.CanvasRenderingContext2D,
/** Returns a WebGL rendering context using the gl package. */
getWebGLRenderingContext: () => WebGLRenderingContext,
/** Returns the fake user agent string of `node` */
getNavigator: () => ({ userAgent: 'node' }),
Expand Down
1 change: 1 addition & 0 deletions bundles/pixi.js-webworker/src/adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export const WebWorkerAdapter = {
* @param height - height of the canvas
*/
createCanvas: (width?: number, height?: number) => new OffscreenCanvas(width | 0, height | 0),
getCanvasRenderingContext2D: () => CanvasRenderingContext2D,
getWebGLRenderingContext: () => WebGLRenderingContext,
getNavigator: () => navigator,
getBaseUrl: () => globalThis.location.href,
Expand Down
3 changes: 3 additions & 0 deletions packages/settings/src/ICanvasRenderingContext2D.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,7 @@ export interface ICanvasRenderingContext2D extends
drawImage(image: CanvasImageSource | ICanvas, dx: number, dy: number, dw: number, dh: number): void;
drawImage(image: CanvasImageSource | ICanvas, sx: number, sy: number, sw: number, sh: number,
dx: number, dy: number, dw: number, dh: number): void;

letterSpacing?: string;
textLetterSpacing?: string; // For Chrome < 94
}
6 changes: 5 additions & 1 deletion packages/settings/src/adapter.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { ICanvas } from './ICanvas';
import type { ICanvasRenderingContext2D } from './ICanvasRenderingContext2D';

/**
* This interface describes all the DOM dependent calls that Pixi makes throughout its codebase.
Expand All @@ -10,7 +11,9 @@ export interface IAdapter
{
/** Returns a canvas object that can be used to create a webgl context. */
createCanvas: (width?: number, height?: number) => ICanvas;
/** Returns a webgl rendering context. */
/** Returns a 2D rendering context. */
getCanvasRenderingContext2D: () => { prototype: ICanvasRenderingContext2D; };
/** Returns a WebGL rendering context. */
getWebGLRenderingContext: () => typeof WebGLRenderingContext;
/** Returns a partial implementation of the browsers window.navigator */
getNavigator: () => { userAgent: string };
Expand All @@ -37,6 +40,7 @@ export const BrowserAdapter = {

return canvas;
},
getCanvasRenderingContext2D: () => CanvasRenderingContext2D,
getWebGLRenderingContext: () => WebGLRenderingContext,
getNavigator: () => navigator,
getBaseUrl: () => (document.baseURI ?? window.location.href),
Expand Down
103 changes: 32 additions & 71 deletions packages/text/src/Text.ts
Original file line number Diff line number Diff line change
@@ -1,50 +1,20 @@
/* eslint max-depth: [2, 8] */
import { Sprite } from '@pixi/sprite';
import { Texture, settings, Rectangle, utils } from '@pixi/core';
import { Sprite } from '@pixi/sprite';
import { TEXT_GRADIENT } from './const';
import { TextStyle } from './TextStyle';
import { TextMetrics } from './TextMetrics';
import { TextStyle } from './TextStyle';

import type { Renderer } from '@pixi/core';
import type { ICanvas, ICanvasRenderingContext2D, Renderer } from '@pixi/core';
import type { IDestroyOptions } from '@pixi/display';
import type { ICanvas, ICanvasRenderingContext2D } from '@pixi/settings';
import type { ITextStyle } from './TextStyle';

// The type for Intl.Segmenter is only available since TypeScript 4.7.2, so let's make a polyfill for it.
interface ISegmentData
{
segment: string;
}
interface ISegments
{
[Symbol.iterator](): IterableIterator<ISegmentData>;
}
interface ISegmenter
{
segment(input: string): ISegments;
}
interface IIntl
{
Segmenter?: {
prototype: ISegmenter;
new(): ISegmenter;
};
}

const defaultDestroyOptions: IDestroyOptions = {
texture: true,
children: false,
baseTexture: true,
};

interface ModernContext2D extends ICanvasRenderingContext2D
{
// for chrome less 94
textLetterSpacing?: number;
// for chrome greater 94
letterSpacing?: number;
}

/**
* A Text Object will create a line or multiple lines of text.
*
Expand Down Expand Up @@ -101,39 +71,27 @@ export class Text extends Sprite
public static defaultResolution: number;

/**
* New rendering behavior for letter-spacing which uses Chrome's new native API. This will
* lead to more accurate letter-spacing results because it does not try to manually draw
* each character. However, this Chrome API is experimental and may not serve all cases yet.
*/
public static experimentalLetterSpacing = false;

/**
* A Unicode "character", or "grapheme cluster", can be composed of multiple Unicode code points,
* such as letters with diacritical marks (e.g. `'\u0065\u0301'`, letter e with acute)
* or emojis with modifiers (e.g. `'\uD83E\uDDD1\u200D\uD83D\uDCBB'`, technologist).
* The new `Intl.Segmenter` API in ES2022 can split the string into grapheme clusters correctly. If it is not available,
* PixiJS will fallback to use the iterator of String, which can only spilt the string into code points.
* If you want to get full functionality in environments that don't support `Intl.Segmenter` (such as Firefox),
* you can use other libraries such as [grapheme-splitter]{@link https://www.npmjs.com/package/grapheme-splitter}
* or [graphemer]{@link https://www.npmjs.com/package/graphemer} to create a polyfill. Since these libraries can be
* relatively large in size to handle various Unicode grapheme clusters properly, PixiJS won't use them directly.
* @see PIXI.TextMetrics.experimentalLetterSpacing
* @deprecated since 7.1.0
*/
public static graphemeSegmenter: (s: string) => string[] = (() =>
public static get experimentalLetterSpacing()
{
if (typeof (Intl as IIntl)?.Segmenter === 'function')
{
const segmenter = new (Intl as IIntl).Segmenter();

return (s: string) => [...segmenter.segment(s)].map((x) => x.segment);
}
return TextMetrics.experimentalLetterSpacing;
}
public static set experimentalLetterSpacing(value)
{
// #if _DEBUG
utils.deprecation('7.1.0',
'Text.experimentalLetterSpacing is deprecated, use TextMetrics.experimentalLetterSpacing');
// #endif

return (s: string) => [...s];
})();
TextMetrics.experimentalLetterSpacing = value;
}

/** The canvas element that everything is drawn to. */
public canvas: ICanvas;
/** The canvas 2d context that everything is drawn with. */
public context: ModernContext2D;
public context: ICanvasRenderingContext2D;
public localStyleID: number;
public dirty: boolean;

Expand Down Expand Up @@ -393,22 +351,25 @@ export class Text extends Sprite
// letterSpacing of 0 means normal
const letterSpacing = style.letterSpacing;

// Checking that we can use moddern canvas2D api
// https://developer.chrome.com/origintrials/#/view_trial/3585991203293757441
// note: this is unstable API, Chrome less 94 use a `textLetterSpacing`, newest use a letterSpacing
// eslint-disable-next-line max-len
const supportLetterSpacing = Text.experimentalLetterSpacing
&& ('letterSpacing' in CanvasRenderingContext2D.prototype
|| 'textLetterSpacing' in CanvasRenderingContext2D.prototype);
let useExperimentalLetterSpacing = false;

if (letterSpacing === 0 || supportLetterSpacing)
if (TextMetrics.experimentalLetterSpacingSupported)
{
if (supportLetterSpacing)
if (TextMetrics.experimentalLetterSpacing)
{
this.context.letterSpacing = letterSpacing;
this.context.textLetterSpacing = letterSpacing;
this.context.letterSpacing = `${letterSpacing}px`;
this.context.textLetterSpacing = `${letterSpacing}px`;
useExperimentalLetterSpacing = true;
}
else
{
this.context.letterSpacing = '0px';
this.context.textLetterSpacing = '0px';
}
}

if (letterSpacing === 0 || useExperimentalLetterSpacing)
{
if (isStroke)
{
this.context.strokeText(text, x, y);
Expand All @@ -423,7 +384,7 @@ export class Text extends Sprite

let currentPosition = x;

const stringArray = Text.graphemeSegmenter(text);
const stringArray = TextMetrics.graphemeSegmenter(text);
let previousWidth = this.context.measureText(text).width;
let currentWidth = 0;

Expand Down

0 comments on commit 7151ba7

Please sign in to comment.