From 5d2f14f37f3b12aebd438765abb083cf9f078552 Mon Sep 17 00:00:00 2001 From: Nick Badal Date: Sat, 21 May 2022 22:42:08 -0700 Subject: [PATCH] feat: add support for 'auto' values in clip property --- src/css/property-descriptors/clip.ts | 21 ++++++++++++--------- src/css/syntax/parser.ts | 2 ++ src/css/syntax/tokenizer.ts | 5 +++++ src/render/bound-curves.ts | 26 +++++++++++++++----------- tests/reftests/clip.html | 8 ++++++++ 5 files changed, 42 insertions(+), 20 deletions(-) diff --git a/src/css/property-descriptors/clip.ts b/src/css/property-descriptors/clip.ts index 275ed88..03a370c 100644 --- a/src/css/property-descriptors/clip.ts +++ b/src/css/property-descriptors/clip.ts @@ -1,31 +1,34 @@ import {IPropertyValueDescriptor, PropertyDescriptorParsingType} from '../IPropertyDescriptor'; -import {CSSValue, isDimensionToken, isIdentWithValue, nonFunctionArgSeparator} from '../syntax/parser'; +import {CSSValue, isAutoIdentToken, isDimensionToken} from '../syntax/parser'; import {Context} from '../../core/context'; -import {DimensionToken, TokenType} from '../syntax/tokenizer'; +import {AutoIdentToken, DimensionToken, TokenType} from '../syntax/tokenizer'; export interface RectClip { - top: DimensionToken; - right: DimensionToken; - bottom: DimensionToken; - left: DimensionToken; + top: DimensionToken | AutoIdentToken; + right: DimensionToken | AutoIdentToken; + bottom: DimensionToken | AutoIdentToken; + left: DimensionToken | AutoIdentToken; } +const isDimensionOrAutoToken = (token: CSSValue): token is DimensionToken | AutoIdentToken => + isDimensionToken(token) || isAutoIdentToken(token); + export const clip: IPropertyValueDescriptor = { name: 'clip', initialValue: 'auto', type: PropertyDescriptorParsingType.VALUE, prefix: false, parse: (_context: Context, token: CSSValue) => { - if (isIdentWithValue(token, 'auto')) { + if (isAutoIdentToken(token)) { return null; } if (token.type !== TokenType.FUNCTION || token.name !== 'rect') { throw new Error('Clip value must be auto or a rect function'); } - const rectArgs = token.values.filter(nonFunctionArgSeparator).filter(isDimensionToken); + const rectArgs = token.values.filter(isDimensionOrAutoToken); if (rectArgs.length !== 4) { - throw new Error('Rect clip must have 4 dimension elements'); + throw new Error('Rect clip must have 4 elements that are either a dimension or "auto"'); } return { diff --git a/src/css/syntax/parser.ts b/src/css/syntax/parser.ts index 7d65779..cf17016 100644 --- a/src/css/syntax/parser.ts +++ b/src/css/syntax/parser.ts @@ -1,4 +1,5 @@ import { + AutoIdentToken, CSSToken, DimensionToken, EOF_TOKEN, @@ -145,6 +146,7 @@ export const isDimensionToken = (token: CSSValue): token is DimensionToken => to export const isNumberToken = (token: CSSValue): token is NumberValueToken => token.type === TokenType.NUMBER_TOKEN; export const isIdentToken = (token: CSSValue): token is StringValueToken => token.type === TokenType.IDENT_TOKEN; export const isStringToken = (token: CSSValue): token is StringValueToken => token.type === TokenType.STRING_TOKEN; +export const isAutoIdentToken = (token: CSSValue): token is AutoIdentToken => isIdentWithValue(token, 'auto'); export const isIdentWithValue = (token: CSSValue, value: string): boolean => isIdentToken(token) && token.value === value; diff --git a/src/css/syntax/tokenizer.ts b/src/css/syntax/tokenizer.ts index 11bbb03..b9b139d 100644 --- a/src/css/syntax/tokenizer.ts +++ b/src/css/syntax/tokenizer.ts @@ -97,6 +97,11 @@ export interface DimensionToken extends IToken { number: number; } +export interface AutoIdentToken extends IToken { + type: TokenType.IDENT_TOKEN; + value: 'auto'; +} + export interface UnicodeRangeToken extends IToken { type: TokenType.UNICODE_RANGE_TOKEN; start: number; diff --git a/src/render/bound-curves.ts b/src/render/bound-curves.ts index 6a7b30c..ca2577b 100644 --- a/src/render/bound-curves.ts +++ b/src/render/bound-curves.ts @@ -1,8 +1,9 @@ import {ElementContainer} from '../dom/element-container'; -import {getAbsoluteValue, getAbsoluteValueForTuple, getAbsoluteValueForDimension} from '../css/types/length-percentage'; +import {getAbsoluteValue, getAbsoluteValueForDimension, getAbsoluteValueForTuple} from '../css/types/length-percentage'; import {Vector} from './vector'; import {BezierCurve} from './bezier-curve'; import {Path} from './path'; +import {TokenType} from '../css/syntax/tokenizer'; export class BoundCurves { readonly topLeftBorderDoubleOuterBox: Path; @@ -76,16 +77,19 @@ export class BoundCurves { const paddingBottom = getAbsoluteValue(styles.paddingBottom, element.bounds.width); const paddingLeft = getAbsoluteValue(styles.paddingLeft, element.bounds.width); - let rectClipTop = 0; - let rectClipRight = 0; - let rectClipBottom = 0; - let rectClipLeft = 0; - if (styles.clip) { - rectClipTop = getAbsoluteValueForDimension(styles.clip.top); - rectClipRight = getAbsoluteValueForDimension(styles.clip.right); - rectClipBottom = getAbsoluteValueForDimension(styles.clip.bottom); - rectClipLeft = getAbsoluteValueForDimension(styles.clip.left); - } + const rectClipTop = + styles.clip?.top.type == TokenType.DIMENSION_TOKEN ? getAbsoluteValueForDimension(styles.clip.top) : 0; + const rectClipLeft = + styles.clip?.left.type == TokenType.DIMENSION_TOKEN ? getAbsoluteValueForDimension(styles.clip.left) : 0; + + const rectClipBottom = + styles.clip?.bottom.type == TokenType.DIMENSION_TOKEN + ? getAbsoluteValueForDimension(styles.clip.bottom) + : bounds.height; + const rectClipRight = + styles.clip?.right.type == TokenType.DIMENSION_TOKEN + ? getAbsoluteValueForDimension(styles.clip.right) + : bounds.width; this.topLeftBorderDoubleOuterBox = tlh > 0 || tlv > 0 diff --git a/tests/reftests/clip.html b/tests/reftests/clip.html index 88f4cae..4166f75 100644 --- a/tests/reftests/clip.html +++ b/tests/reftests/clip.html @@ -45,5 +45,13 @@
Some inline text followed by text in span followed by more inline text.

Then a block level element.

Then more inline text.
+ +
Some inline text followed by text in span followed by more inline text. +

Then a block level element.

+ Then more inline text.
+ +
Some inline text followed by text in span followed by more inline text. +

Then a block level element.

+ Then more inline text.