Get rotation working in the text demo.
There are some known artefacts when zoomed in heavily in XCAA mode.
This commit is contained in:
parent
95a1dd0195
commit
1de0378f1e
|
@ -253,6 +253,7 @@ class ThreeDController extends DemoAppController<ThreeDView> {
|
|||
textFrameIndex < this.textFrames.length;
|
||||
textFrameIndex++) {
|
||||
const textFrame = this.textFrames[textFrameIndex];
|
||||
const textBounds = textFrame.bounds;
|
||||
|
||||
let glyphDescriptors = [];
|
||||
for (const run of textFrame.runs) {
|
||||
|
@ -261,7 +262,9 @@ class ThreeDController extends DemoAppController<ThreeDView> {
|
|||
glyphID: run.glyphIDs[glyphIndex],
|
||||
position: run.calculatePixelOriginForGlyphAt(glyphIndex,
|
||||
PIXELS_PER_UNIT,
|
||||
hint),
|
||||
0.0,
|
||||
hint,
|
||||
textBounds),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -361,6 +364,10 @@ class ThreeDRenderer extends Renderer {
|
|||
|
||||
camera: PerspectiveCamera;
|
||||
|
||||
get usesSTTransform(): boolean {
|
||||
return this.camera.usesSTTransform;
|
||||
}
|
||||
|
||||
get destFramebuffer(): WebGLFramebuffer | null {
|
||||
return null;
|
||||
}
|
||||
|
@ -593,7 +600,7 @@ class ThreeDRenderer extends Renderer {
|
|||
});
|
||||
const glyph = this.renderContext.atlasGlyphs[glyphIndex];
|
||||
const glyphMetrics = unwrapNull(font.metricsForGlyph(glyph.glyphKey.id));
|
||||
const glyphUnitMetrics = new UnitMetrics(glyphMetrics, glmatrix.vec2.create());
|
||||
const glyphUnitMetrics = new UnitMetrics(glyphMetrics, 0.0, glmatrix.vec2.create());
|
||||
|
||||
const firstPosition = this.glyphPositions.length / 2;
|
||||
|
||||
|
@ -843,6 +850,7 @@ class ThreeDRenderer extends Renderer {
|
|||
this.renderContext.atlas.layoutGlyphs(atlasGlyphs,
|
||||
this.renderContext.font,
|
||||
this.renderContext.atlasPixelsPerUnit,
|
||||
0.0,
|
||||
hint,
|
||||
glmatrix.vec2.create());
|
||||
|
||||
|
@ -937,7 +945,7 @@ class ThreeDAtlasRenderer extends TextRenderer {
|
|||
if (glyphMetrics == null)
|
||||
continue;
|
||||
|
||||
const glyphUnitMetrics = new UnitMetrics(glyphMetrics, glmatrix.vec2.create());
|
||||
const glyphUnitMetrics = new UnitMetrics(glyphMetrics, 0.0, glmatrix.vec2.create());
|
||||
const atlasGlyphRect = calculatePixelRectForGlyph(glyphUnitMetrics,
|
||||
glyphPixelOrigin,
|
||||
pixelsPerUnit,
|
||||
|
|
|
@ -33,6 +33,7 @@ export class Atlas {
|
|||
layoutGlyphs(glyphs: AtlasGlyph[],
|
||||
font: PathfinderFont,
|
||||
pixelsPerUnit: number,
|
||||
rotationAngle: number,
|
||||
hint: Hint,
|
||||
stemDarkeningAmount: glmatrix.vec2):
|
||||
void {
|
||||
|
@ -45,9 +46,9 @@ export class Atlas {
|
|||
if (metrics == null)
|
||||
continue;
|
||||
|
||||
const unitMetrics = new UnitMetrics(metrics, stemDarkeningAmount);
|
||||
|
||||
const unitMetrics = new UnitMetrics(metrics, rotationAngle, stemDarkeningAmount);
|
||||
glyph.setPixelLowerLeft(nextOrigin, unitMetrics, pixelsPerUnit);
|
||||
|
||||
let pixelOrigin = glyph.calculateSubpixelOrigin(pixelsPerUnit);
|
||||
nextOrigin[0] = calculatePixelRectForGlyph(unitMetrics,
|
||||
pixelOrigin,
|
||||
|
@ -128,7 +129,7 @@ export class AtlasGlyph {
|
|||
const pixelXMin = calculatePixelXMin(metrics, pixelsPerUnit);
|
||||
const pixelDescent = calculatePixelDescent(metrics, pixelsPerUnit);
|
||||
const pixelOrigin = glmatrix.vec2.clone([pixelLowerLeft[0] - pixelXMin,
|
||||
pixelLowerLeft[1] + pixelDescent]);
|
||||
pixelLowerLeft[1] - pixelDescent]);
|
||||
this.setPixelOrigin(pixelOrigin, pixelsPerUnit);
|
||||
}
|
||||
|
||||
|
|
|
@ -272,6 +272,10 @@ class BenchmarkRenderer extends Renderer {
|
|||
|
||||
renderingPromiseCallback: ((time: number) => void) | null;
|
||||
|
||||
get usesSTTransform(): boolean {
|
||||
return this.camera.usesSTTransform;
|
||||
}
|
||||
|
||||
get destFramebuffer(): WebGLFramebuffer | null {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
import * as glmatrix from 'gl-matrix';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import {EPSILON} from "./utils";
|
||||
import {PathfinderView} from "./view";
|
||||
|
||||
const PIXELS_PER_LINE: number = 16.0;
|
||||
|
@ -79,6 +80,8 @@ export interface CameraView {
|
|||
export abstract class Camera {
|
||||
protected canvas: CameraView;
|
||||
|
||||
abstract get usesSTTransform(): boolean;
|
||||
|
||||
constructor(canvas: CameraView) {
|
||||
this.canvas = canvas;
|
||||
}
|
||||
|
@ -105,6 +108,10 @@ export class OrthographicCamera extends Camera {
|
|||
private readonly scaleBounds: boolean;
|
||||
private readonly ignoreBounds: boolean;
|
||||
|
||||
get usesSTTransform(): boolean {
|
||||
return Math.abs(this.rotationAngle) < EPSILON;
|
||||
}
|
||||
|
||||
constructor(canvas: CameraView, options?: OrthographicCameraOptions) {
|
||||
super(canvas);
|
||||
|
||||
|
@ -280,6 +287,10 @@ export class OrthographicCamera extends Camera {
|
|||
export class PerspectiveCamera extends Camera {
|
||||
canvas: HTMLCanvasElement;
|
||||
|
||||
get usesSTTransform(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
onChange: (() => void) | null;
|
||||
|
||||
translation: glmatrix.vec3;
|
||||
|
|
|
@ -469,6 +469,10 @@ class ReferenceTestRenderer extends Renderer {
|
|||
renderContext: ReferenceTestView;
|
||||
camera: OrthographicCamera;
|
||||
|
||||
get usesSTTransform(): boolean {
|
||||
return this.camera.usesSTTransform;
|
||||
}
|
||||
|
||||
get destFramebuffer(): WebGLFramebuffer | null {
|
||||
return null;
|
||||
}
|
||||
|
@ -571,17 +575,8 @@ class ReferenceTestRenderer extends Renderer {
|
|||
}
|
||||
|
||||
getPixelRectForGlyphAt(glyphIndex: number): glmatrix.vec4 {
|
||||
const appController = this.renderContext.appController;
|
||||
const font = unwrapNull(appController.font);
|
||||
const hint = new Hint(font, this.pixelsPerUnit, true);
|
||||
|
||||
const textRun = unwrapNull(appController.textRun);
|
||||
const glyphID = textRun.glyphIDs[glyphIndex];
|
||||
return textRun.pixelRectForGlyphAt(glyphIndex,
|
||||
this.pixelsPerUnit,
|
||||
hint,
|
||||
this.stemDarkeningAmount,
|
||||
SUBPIXEL_GRANULARITY);
|
||||
const textRun = unwrapNull(this.renderContext.appController.textRun);
|
||||
return textRun.pixelRectForGlyphAt(glyphIndex);
|
||||
}
|
||||
|
||||
protected createAAStrategy(aaType: AntialiasingStrategyName,
|
||||
|
@ -609,11 +604,13 @@ class ReferenceTestRenderer extends Renderer {
|
|||
|
||||
const textRun = unwrapNull(appController.textRun);
|
||||
const glyphID = textRun.glyphIDs[0];
|
||||
const pixelRect = textRun.pixelRectForGlyphAt(0,
|
||||
this.pixelsPerUnit,
|
||||
textRun.recalculatePixelRects(this.pixelsPerUnit,
|
||||
0.0,
|
||||
hint,
|
||||
glmatrix.vec2.create(),
|
||||
SUBPIXEL_GRANULARITY);
|
||||
SUBPIXEL_GRANULARITY,
|
||||
glmatrix.vec4.create());
|
||||
const pixelRect = textRun.pixelRectForGlyphAt(0);
|
||||
|
||||
const x = -pixelRect[0] / this.pixelsPerUnit;
|
||||
const y = (canvas.height - (pixelRect[3] - pixelRect[1])) / this.pixelsPerUnit;
|
||||
|
|
|
@ -44,6 +44,8 @@ export abstract class Renderer {
|
|||
meshes: PathfinderMeshBuffers[] | null;
|
||||
meshData: PathfinderMeshData[] | null;
|
||||
|
||||
abstract get usesSTTransform(): boolean;
|
||||
|
||||
get emboldenAmount(): glmatrix.vec2 {
|
||||
return glmatrix.vec2.create();
|
||||
}
|
||||
|
|
|
@ -117,6 +117,10 @@ class SVGDemoRenderer extends Renderer {
|
|||
|
||||
camera: OrthographicCamera;
|
||||
|
||||
get usesSTTransform(): boolean {
|
||||
return this.camera.usesSTTransform;
|
||||
}
|
||||
|
||||
get destAllocatedSize(): glmatrix.vec2 {
|
||||
const canvas = this.renderContext.canvas;
|
||||
return glmatrix.vec2.clone([canvas.width, canvas.height]);
|
||||
|
|
|
@ -27,7 +27,7 @@ import {PathfinderMeshBuffers, PathfinderMeshData} from './meshes';
|
|||
import {Renderer} from './renderer';
|
||||
import {PathfinderShaderProgram, ShaderMap, ShaderProgramSource} from './shader-loader';
|
||||
import SSAAStrategy from './ssaa-strategy';
|
||||
import {calculatePixelDescent, calculatePixelRectForGlyph, PathfinderFont} from "./text";
|
||||
import {calculatePixelRectForGlyph, PathfinderFont} from "./text";
|
||||
import {BUILTIN_FONT_URI, calculatePixelXMin, computeStemDarkeningAmount} from "./text";
|
||||
import {GlyphStore, Hint, SimpleTextLayout, UnitMetrics} from "./text";
|
||||
import {TextRenderContext, TextRenderer} from './text-renderer';
|
||||
|
@ -506,17 +506,21 @@ class TextDemoRenderer extends TextRenderer {
|
|||
|
||||
const hint = this.createHint();
|
||||
const pixelsPerUnit = this.pixelsPerUnit;
|
||||
const rotationAngle = this.rotationAngle;
|
||||
|
||||
let globalGlyphIndex = 0;
|
||||
for (const run of this.layout.textFrame.runs) {
|
||||
run.recalculatePixelRects(pixelsPerUnit,
|
||||
rotationAngle,
|
||||
hint,
|
||||
this.stemDarkeningAmount,
|
||||
SUBPIXEL_GRANULARITY,
|
||||
textBounds);
|
||||
|
||||
for (let glyphIndex = 0;
|
||||
glyphIndex < run.glyphIDs.length;
|
||||
glyphIndex++, globalGlyphIndex++) {
|
||||
const rect = run.pixelRectForGlyphAt(glyphIndex,
|
||||
pixelsPerUnit,
|
||||
hint,
|
||||
this.stemDarkeningAmount,
|
||||
SUBPIXEL_GRANULARITY);
|
||||
const rect = run.pixelRectForGlyphAt(glyphIndex);
|
||||
glyphPositions.set([
|
||||
rect[0], rect[3],
|
||||
rect[2], rect[3],
|
||||
|
@ -545,8 +549,10 @@ class TextDemoRenderer extends TextRenderer {
|
|||
const font = this.renderContext.font;
|
||||
const glyphStore = this.renderContext.glyphStore;
|
||||
const pixelsPerUnit = this.pixelsPerUnit;
|
||||
const rotationAngle = this.rotationAngle;
|
||||
|
||||
const textFrame = this.layout.textFrame;
|
||||
const textBounds = textFrame.bounds;
|
||||
const hint = this.createHint();
|
||||
|
||||
// Only build glyphs in view.
|
||||
|
@ -561,11 +567,7 @@ class TextDemoRenderer extends TextRenderer {
|
|||
const atlasGlyphs = [];
|
||||
for (const run of textFrame.runs) {
|
||||
for (let glyphIndex = 0; glyphIndex < run.glyphIDs.length; glyphIndex++) {
|
||||
const pixelRect = run.pixelRectForGlyphAt(glyphIndex,
|
||||
pixelsPerUnit,
|
||||
hint,
|
||||
this.stemDarkeningAmount,
|
||||
SUBPIXEL_GRANULARITY);
|
||||
const pixelRect = run.pixelRectForGlyphAt(glyphIndex);
|
||||
if (!rectsIntersect(pixelRect, canvasRect))
|
||||
continue;
|
||||
|
||||
|
@ -576,8 +578,10 @@ class TextDemoRenderer extends TextRenderer {
|
|||
|
||||
const subpixel = run.subpixelForGlyphAt(glyphIndex,
|
||||
pixelsPerUnit,
|
||||
rotationAngle,
|
||||
hint,
|
||||
SUBPIXEL_GRANULARITY);
|
||||
SUBPIXEL_GRANULARITY,
|
||||
textBounds);
|
||||
const glyphKey = new GlyphKey(glyphID, subpixel);
|
||||
atlasGlyphs.push(new AtlasGlyph(glyphStoreIndex, glyphKey));
|
||||
}
|
||||
|
@ -586,17 +590,21 @@ class TextDemoRenderer extends TextRenderer {
|
|||
this.buildAtlasGlyphs(atlasGlyphs);
|
||||
|
||||
// TODO(pcwalton): Regenerate the IBOs to include only the glyphs we care about.
|
||||
|
||||
this.setGlyphTexCoords();
|
||||
}
|
||||
|
||||
private setGlyphTexCoords(): void {
|
||||
const gl = this.renderContext.gl;
|
||||
|
||||
const textFrame = this.layout.textFrame;
|
||||
const textBounds = textFrame.bounds;
|
||||
|
||||
const font = this.renderContext.font;
|
||||
const atlasGlyphs = this.renderContext.atlasGlyphs;
|
||||
|
||||
const hint = this.createHint();
|
||||
const pixelsPerUnit = this.pixelsPerUnit;
|
||||
const rotationAngle = this.rotationAngle;
|
||||
|
||||
const atlasGlyphKeys = atlasGlyphs.map(atlasGlyph => atlasGlyph.glyphKey.sortKey);
|
||||
|
||||
|
@ -611,8 +619,10 @@ class TextDemoRenderer extends TextRenderer {
|
|||
|
||||
const subpixel = run.subpixelForGlyphAt(glyphIndex,
|
||||
pixelsPerUnit,
|
||||
rotationAngle,
|
||||
hint,
|
||||
SUBPIXEL_GRANULARITY);
|
||||
SUBPIXEL_GRANULARITY,
|
||||
textBounds);
|
||||
|
||||
const glyphKey = new GlyphKey(textGlyphID, subpixel);
|
||||
|
||||
|
@ -627,6 +637,7 @@ class TextDemoRenderer extends TextRenderer {
|
|||
continue;
|
||||
|
||||
const atlasGlyphUnitMetrics = new UnitMetrics(atlasGlyphMetrics,
|
||||
rotationAngle,
|
||||
this.stemDarkeningAmount);
|
||||
|
||||
const atlasGlyphPixelOrigin =
|
||||
|
@ -649,12 +660,9 @@ class TextDemoRenderer extends TextRenderer {
|
|||
}
|
||||
}
|
||||
|
||||
this.glyphTexCoordsBuffer = unwrapNull(this.renderContext.gl.createBuffer());
|
||||
this.renderContext.gl.bindBuffer(this.renderContext.gl.ARRAY_BUFFER,
|
||||
this.glyphTexCoordsBuffer);
|
||||
this.renderContext.gl.bufferData(this.renderContext.gl.ARRAY_BUFFER,
|
||||
this.glyphBounds,
|
||||
this.renderContext.gl.STATIC_DRAW);
|
||||
this.glyphTexCoordsBuffer = unwrapNull(gl.createBuffer());
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, this.glyphTexCoordsBuffer);
|
||||
gl.bufferData(gl.ARRAY_BUFFER, this.glyphBounds, gl.STATIC_DRAW);
|
||||
}
|
||||
|
||||
private setIdentityTexScaleUniform(uniforms: UniformMap): void {
|
||||
|
|
|
@ -64,6 +64,10 @@ export abstract class TextRenderer extends Renderer {
|
|||
atlasFramebuffer: WebGLFramebuffer;
|
||||
atlasDepthTexture: WebGLTexture;
|
||||
|
||||
get usesSTTransform(): boolean {
|
||||
return this.camera.usesSTTransform;
|
||||
}
|
||||
|
||||
get destFramebuffer(): WebGLFramebuffer {
|
||||
return this.atlasFramebuffer;
|
||||
}
|
||||
|
@ -148,6 +152,7 @@ export abstract class TextRenderer extends Renderer {
|
|||
const pathCount = this.pathCount;
|
||||
const atlasGlyphs = this.renderContext.atlasGlyphs;
|
||||
const pixelsPerUnit = this.pixelsPerUnit;
|
||||
const rotationAngle = this.rotationAngle;
|
||||
const font = this.renderContext.font;
|
||||
const hint = this.createHint();
|
||||
|
||||
|
@ -157,7 +162,9 @@ export abstract class TextRenderer extends Renderer {
|
|||
const atlasGlyphMetrics = font.metricsForGlyph(glyph.glyphKey.id);
|
||||
if (atlasGlyphMetrics == null)
|
||||
continue;
|
||||
const atlasUnitMetrics = new UnitMetrics(atlasGlyphMetrics, this.stemDarkeningAmount);
|
||||
const atlasUnitMetrics = new UnitMetrics(atlasGlyphMetrics,
|
||||
0.0,
|
||||
this.stemDarkeningAmount);
|
||||
|
||||
const pathID = glyph.pathID;
|
||||
boundingRects[pathID * 4 + 0] = atlasUnitMetrics.left;
|
||||
|
@ -196,6 +203,7 @@ export abstract class TextRenderer extends Renderer {
|
|||
protected buildAtlasGlyphs(atlasGlyphs: AtlasGlyph[]): void {
|
||||
const font = this.renderContext.font;
|
||||
const pixelsPerUnit = this.pixelsPerUnit;
|
||||
const rotationAngle = this.rotationAngle;
|
||||
const hint = this.createHint();
|
||||
|
||||
atlasGlyphs.sort((a, b) => a.glyphKey.sortKey - b.glyphKey.sortKey);
|
||||
|
@ -207,6 +215,7 @@ export abstract class TextRenderer extends Renderer {
|
|||
this.renderContext.atlas.layoutGlyphs(atlasGlyphs,
|
||||
font,
|
||||
pixelsPerUnit,
|
||||
rotationAngle,
|
||||
hint,
|
||||
this.stemDarkeningAmount);
|
||||
|
||||
|
|
|
@ -94,6 +94,7 @@ export class TextRun {
|
|||
readonly origin: number[];
|
||||
|
||||
private readonly font: PathfinderFont;
|
||||
private pixelRects: glmatrix.vec4[];
|
||||
|
||||
constructor(text: number[] | string, origin: number[], font: PathfinderFont) {
|
||||
if (typeof(text) === 'string') {
|
||||
|
@ -107,6 +108,7 @@ export class TextRun {
|
|||
this.origin = origin;
|
||||
this.advances = [];
|
||||
this.font = font;
|
||||
this.pixelRects = [];
|
||||
}
|
||||
|
||||
layout() {
|
||||
|
@ -118,38 +120,77 @@ export class TextRun {
|
|||
}
|
||||
}
|
||||
|
||||
calculatePixelOriginForGlyphAt(index: number, pixelsPerUnit: number, hint: Hint):
|
||||
calculatePixelOriginForGlyphAt(index: number,
|
||||
pixelsPerUnit: number,
|
||||
rotationAngle: number,
|
||||
hint: Hint,
|
||||
textFrameBounds: glmatrix.vec4):
|
||||
glmatrix.vec2 {
|
||||
const textGlyphOrigin = glmatrix.vec2.clone(this.origin);
|
||||
textGlyphOrigin[0] += this.advances[index];
|
||||
const textFrameCenter = glmatrix.vec2.clone([
|
||||
0.5 * (textFrameBounds[0] + textFrameBounds[2]),
|
||||
0.5 * (textFrameBounds[1] + textFrameBounds[3]),
|
||||
]);
|
||||
|
||||
const transform = glmatrix.mat2d.create();
|
||||
glmatrix.mat2d.fromTranslation(transform, textFrameCenter);
|
||||
glmatrix.mat2d.rotate(transform, transform, -rotationAngle);
|
||||
glmatrix.vec2.negate(textFrameCenter, textFrameCenter);
|
||||
glmatrix.mat2d.translate(transform, transform, textFrameCenter);
|
||||
|
||||
const textGlyphOrigin = glmatrix.vec2.create();
|
||||
glmatrix.vec2.add(textGlyphOrigin, [this.advances[index], 0.0], this.origin);
|
||||
glmatrix.vec2.transformMat2d(textGlyphOrigin, textGlyphOrigin, transform);
|
||||
|
||||
glmatrix.vec2.scale(textGlyphOrigin, textGlyphOrigin, pixelsPerUnit);
|
||||
return textGlyphOrigin;
|
||||
}
|
||||
|
||||
pixelRectForGlyphAt(index: number,
|
||||
pixelRectForGlyphAt(index: number): glmatrix.vec4 {
|
||||
return this.pixelRects[index];
|
||||
}
|
||||
|
||||
subpixelForGlyphAt(index: number,
|
||||
pixelsPerUnit: number,
|
||||
rotationAngle: number,
|
||||
hint: Hint,
|
||||
subpixelGranularity: number,
|
||||
textFrameBounds: glmatrix.vec4):
|
||||
number {
|
||||
const textGlyphOrigin = this.calculatePixelOriginForGlyphAt(index,
|
||||
pixelsPerUnit,
|
||||
rotationAngle,
|
||||
hint,
|
||||
textFrameBounds)[0];
|
||||
return Math.abs(Math.round(textGlyphOrigin * subpixelGranularity) % subpixelGranularity);
|
||||
}
|
||||
|
||||
recalculatePixelRects(pixelsPerUnit: number,
|
||||
rotationAngle: number,
|
||||
hint: Hint,
|
||||
stemDarkeningAmount: glmatrix.vec2,
|
||||
subpixelGranularity: number):
|
||||
glmatrix.vec4 {
|
||||
subpixelGranularity: number,
|
||||
textFrameBounds: glmatrix.vec4):
|
||||
void {
|
||||
for (let index = 0; index < this.glyphIDs.length; index++) {
|
||||
const metrics = unwrapNull(this.font.metricsForGlyph(this.glyphIDs[index]));
|
||||
const unitMetrics = new UnitMetrics(metrics, stemDarkeningAmount);
|
||||
const textGlyphOrigin = this.calculatePixelOriginForGlyphAt(index, pixelsPerUnit, hint);
|
||||
const unitMetrics = new UnitMetrics(metrics, rotationAngle, stemDarkeningAmount);
|
||||
const textGlyphOrigin = this.calculatePixelOriginForGlyphAt(index,
|
||||
pixelsPerUnit,
|
||||
rotationAngle,
|
||||
hint,
|
||||
textFrameBounds);
|
||||
|
||||
textGlyphOrigin[0] *= subpixelGranularity;
|
||||
glmatrix.vec2.round(textGlyphOrigin, textGlyphOrigin);
|
||||
textGlyphOrigin[0] /= subpixelGranularity;
|
||||
|
||||
return calculatePixelRectForGlyph(unitMetrics, textGlyphOrigin, pixelsPerUnit, hint);
|
||||
}
|
||||
const pixelRect = calculatePixelRectForGlyph(unitMetrics,
|
||||
textGlyphOrigin,
|
||||
pixelsPerUnit,
|
||||
hint);
|
||||
|
||||
subpixelForGlyphAt(index: number,
|
||||
pixelsPerUnit: number,
|
||||
hint: Hint,
|
||||
subpixelGranularity: number):
|
||||
number {
|
||||
const textGlyphOrigin = this.calculatePixelOriginForGlyphAt(index, pixelsPerUnit, hint)[0];
|
||||
return Math.abs(Math.round(textGlyphOrigin * subpixelGranularity) % subpixelGranularity);
|
||||
this.pixelRects[index] = pixelRect;
|
||||
}
|
||||
}
|
||||
|
||||
get measure(): number {
|
||||
|
@ -340,11 +381,29 @@ export class UnitMetrics {
|
|||
ascent: number;
|
||||
descent: number;
|
||||
|
||||
constructor(metrics: Metrics, stemDarkeningAmount: glmatrix.vec2) {
|
||||
this.left = metrics.xMin;
|
||||
this.right = metrics.xMax + stemDarkeningAmount[0] * 2;
|
||||
this.ascent = metrics.yMax + stemDarkeningAmount[1] * 2;
|
||||
this.descent = metrics.yMin;
|
||||
constructor(metrics: Metrics, rotationAngle: number, stemDarkeningAmount: glmatrix.vec2) {
|
||||
const left = metrics.xMin;
|
||||
const bottom = metrics.yMin;
|
||||
const right = metrics.xMax + stemDarkeningAmount[0] * 2;
|
||||
const top = metrics.yMax + stemDarkeningAmount[1] * 2;
|
||||
|
||||
const transform = glmatrix.mat2.create();
|
||||
glmatrix.mat2.fromRotation(transform, -rotationAngle);
|
||||
|
||||
const lowerLeft = glmatrix.vec2.clone([Infinity, Infinity]);
|
||||
const upperRight = glmatrix.vec2.clone([-Infinity, -Infinity]);
|
||||
const points = [[left, bottom], [left, top], [right, top], [right, bottom]];
|
||||
const transformedPoint = glmatrix.vec2.create();
|
||||
for (const point of points) {
|
||||
glmatrix.vec2.transformMat2(transformedPoint, point, transform);
|
||||
glmatrix.vec2.min(lowerLeft, lowerLeft, transformedPoint);
|
||||
glmatrix.vec2.max(upperRight, upperRight, transformedPoint);
|
||||
}
|
||||
|
||||
this.left = lowerLeft[0];
|
||||
this.right = upperRight[0];
|
||||
this.ascent = upperRight[1];
|
||||
this.descent = lowerLeft[1];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -353,7 +412,7 @@ export function calculatePixelXMin(metrics: UnitMetrics, pixelsPerUnit: number):
|
|||
}
|
||||
|
||||
export function calculatePixelDescent(metrics: UnitMetrics, pixelsPerUnit: number): number {
|
||||
return Math.ceil(-metrics.descent * pixelsPerUnit);
|
||||
return Math.floor(metrics.descent * pixelsPerUnit);
|
||||
}
|
||||
|
||||
function calculateSubpixelMetricsForGlyph(metrics: UnitMetrics, pixelsPerUnit: number, hint: Hint):
|
||||
|
|
|
@ -17,6 +17,8 @@ export const UINT16_SIZE: number = 2;
|
|||
export const UINT32_MAX: number = 0xffffffff;
|
||||
export const UINT32_SIZE: number = 4;
|
||||
|
||||
export const EPSILON: number = 0.001;
|
||||
|
||||
export function panic(message: string): never {
|
||||
throw new PathfinderError(message);
|
||||
}
|
||||
|
|
|
@ -1169,8 +1169,11 @@ export class AdaptiveMonochromeXCAAStrategy implements AntialiasingStrategy {
|
|||
}
|
||||
|
||||
private getAppropriateStrategy(renderer: Renderer): AntialiasingStrategy {
|
||||
if (glmatrix.vec2.equals(renderer.emboldenAmount, [0.0, 0.0]))
|
||||
if (glmatrix.vec2.equals(renderer.emboldenAmount, [0.0, 0.0]) &&
|
||||
renderer.usesSTTransform) {
|
||||
return this.mcaaStrategy;
|
||||
}
|
||||
|
||||
return this.ecaaStrategy;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue