Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
150 changes: 150 additions & 0 deletions packages/vrender-core/__tests__/unit/render/rect-split-stroke.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {
DefaultRectRenderContribution,
SplitRectAfterRenderContribution,
SplitRectBeforeRenderContribution
} from '../../../src/render/contributions/render/contributions/rect-contribution-render';
Expand Down Expand Up @@ -71,4 +72,153 @@ describe('rect split stroke contribution', () => {
expect(context.lineTo).toHaveBeenCalledWith(10, 60);
expect(context.stroke).toHaveBeenCalledTimes(1);
});

test('emits the same outer-border path for positive and negative rect widths', () => {
const contribution = new DefaultRectRenderContribution();
const positiveContext = { beginPath: jest.fn(), rect: jest.fn() };
const negativeContext = { beginPath: jest.fn(), rect: jest.fn() };
const rectAttribute = {
x: 92,
y: 20,
opacity: 1,
scaleX: 1,
scaleY: 1,
keepStrokeScale: true,
cornerRadius: 0,
cornerType: 'round',
outerBorder: { distance: 6 },
innerBorder: { distance: 0 }
};

contribution.drawShape(
{ attribute: { x: 92, y: 20, width: 8, height: 10, outerBorder: { distance: 6 } } } as any,
positiveContext as any,
92,
20,
true,
true,
true,
true,
rectAttribute as any,
{} as any
);
contribution.drawShape(
{ attribute: { x: 100, y: 20, x1: 92, y1: 30, outerBorder: { distance: 6 } } } as any,
negativeContext as any,
100,
20,
true,
true,
true,
true,
{ ...rectAttribute, x: 100 } as any,
{} as any
);

expect(positiveContext.rect).toHaveBeenCalledWith(86, 14, 20, 22);
expect(negativeContext.rect).toHaveBeenCalledWith(86, 14, 20, 22);
});

test('extends a negative-width outer-border path across the physical bounds', () => {
const contribution = new DefaultRectRenderContribution();
const context = { beginPath: jest.fn(), rect: jest.fn() };

contribution.drawShape(
{ attribute: { x: 100, y: 20, x1: 92, y1: 30, outerBorder: { distance: 6 } } } as any,
context as any,
100,
20,
true,
true,
true,
true,
{
x: 100,
y: 20,
opacity: 1,
scaleX: 1,
scaleY: 1,
keepStrokeScale: true,
cornerRadius: 0,
cornerType: 'round',
outerBorder: { distance: 6 },
innerBorder: { distance: 0 }
} as any,
{} as any
);

const [x, , width] = context.rect.mock.calls[0];
expect([x, x + width]).toEqual([86, 106]);
});

test('resolves x1 width in attribute space when the draw origin includes dx', () => {
const contribution = new DefaultRectRenderContribution();
const context = { beginPath: jest.fn(), rect: jest.fn() };

contribution.drawShape(
{
attribute: {
x: 100,
x1: 92,
y: 20,
height: 10,
dx: 10,
outerBorder: { distance: 6 }
}
} as any,
context as any,
110,
20,
true,
true,
true,
true,
{
x: 100,
y: 20,
opacity: 1,
scaleX: 1,
scaleY: 1,
keepStrokeScale: true,
cornerRadius: 0,
cornerType: 'round',
outerBorder: { distance: 6 },
innerBorder: { distance: 0 }
} as any,
{} as any
);

expect(context.rect).toHaveBeenCalledWith(96, 14, 20, 22);
});

test('preserves the non-degenerate positive inner-border path', () => {
const contribution = new DefaultRectRenderContribution();
const context = { beginPath: jest.fn(), rect: jest.fn() };

contribution.drawShape(
{ attribute: { x: 92, y: 20, width: 8, height: 10, innerBorder: { distance: 2 } } } as any,
context as any,
92,
20,
true,
true,
true,
true,
{
x: 92,
y: 20,
opacity: 1,
scaleX: 1,
scaleY: 1,
keepStrokeScale: true,
cornerRadius: 0,
cornerType: 'round',
outerBorder: { distance: 0 },
innerBorder: { distance: 2 }
} as any,
{} as any
);

expect(context.rect).toHaveBeenCalledWith(94, 22, 4, 6);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -68,22 +68,26 @@ export class DefaultRectRenderContribution implements IRectRenderContribution {

let { width, height } = rect.attribute;

width = (width ?? x1 - x) || 0;
height = (height ?? y1 - y) || 0;
width = (width ?? x1 - originX) || 0;
height = (height ?? y1 - originY) || 0;
const borderX = width < 0 ? x + width : x;
const borderY = height < 0 ? y + height : y;
const borderWidth = width < 0 ? -width : width;
const borderHeight = height < 0 ? -height : height;

const renderBorder = (borderStyle: Partial<IBorderStyle>, key: 'outerBorder' | 'innerBorder') => {
const doStroke = !!(borderStyle && borderStyle.stroke);

const sign = key === 'outerBorder' ? -1 : 1;
const { distance = rectAttribute[key].distance } = borderStyle;
const d = keepStrokeScale ? (distance as number) : getScaledStroke(context, distance as number, context.dpr);
const nextX = x + sign * d;
const nextY = y + sign * d;
const nextX = borderX + sign * d;
const nextY = borderY + sign * d;
const dw = d * 2;
if (cornerRadius === 0 || (isArray(cornerRadius) && (<number[]>cornerRadius).every(num => num === 0))) {
// 不需要处理圆角
context.beginPath();
context.rect(nextX, nextY, width - sign * dw, height - sign * dw);
context.rect(nextX, nextY, borderWidth - sign * dw, borderHeight - sign * dw);
} else {
context.beginPath();

Expand All @@ -92,8 +96,8 @@ export class DefaultRectRenderContribution implements IRectRenderContribution {
context,
nextX,
nextY,
width - sign * dw,
height - sign * dw,
borderWidth - sign * dw,
borderHeight - sign * dw,
cornerRadius,
cornerType !== 'bevel'
);
Expand Down
Loading