Skip to content

Commit 5b38e98

Browse files
authored
Aspect ratio (#308)
* aspect-ratio per https://www.w3.org/TR/2021/WD-css-sizing-4-20210520/#propdef-aspect-ratio * can't change grammar to allow ratio as a value, as it failed for examples like: bimg35 { border-image: 10 5% 20 2% / 10 10 10 10 /10px 20 30 40px } due to the "10/10" parsing leading to a dangling 'px' * rewrite ratio to use BigDecimal like all number-based values * fake the CssRatio parsing to avoid conflict with / as a switch
1 parent 6a2f0b5 commit 5b38e98

File tree

5 files changed

+275
-31
lines changed

5 files changed

+275
-31
lines changed

org/w3c/css/properties/CSS3Properties.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,7 @@ cursor: org.w3c.css.properties.css3.CssCursor
330330
caret: org.w3c.css.properties.css3.CssCaret
331331
caret-color: org.w3c.css.properties.css3.CssCaretColor
332332
caret-shape: org.w3c.css.properties.css3.CssCaretShape
333+
aspect-ratio: org.w3c.css.properties.css3.CssAspectRatio
333334

334335
word-spacing: org.w3c.css.properties.css3.CssWordSpacing
335336
letter-spacing: org.w3c.css.properties.css3.CssLetterSpacing
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
//
2+
// Author: Yves Lafon <ylafon@w3.org>
3+
//
4+
// (c) COPYRIGHT MIT, ERCIM, Keio, Beihang, 2021.
5+
// Please first read the full copyright statement in file COPYRIGHT.html
6+
package org.w3c.css.properties.css;
7+
8+
import org.w3c.css.parser.CssStyle;
9+
import org.w3c.css.properties.css3.Css3Style;
10+
import org.w3c.css.util.ApplContext;
11+
import org.w3c.css.util.InvalidParamException;
12+
import org.w3c.css.values.CssExpression;
13+
import org.w3c.css.values.CssValue;
14+
15+
/**
16+
* @since CSS3
17+
*/
18+
public class CssAspectRatio extends CssProperty {
19+
20+
public CssValue value;
21+
22+
/**
23+
* Create a new CssAspectRatio
24+
*/
25+
public CssAspectRatio() {
26+
}
27+
28+
/**
29+
* Creates a new CssAspectRatio
30+
*
31+
* @param expression The expression for this property
32+
* @throws InvalidParamException Expressions are incorrect
33+
*/
34+
public CssAspectRatio(ApplContext ac, CssExpression expression, boolean check)
35+
throws InvalidParamException {
36+
throw new InvalidParamException("value",
37+
expression.getValue().toString(),
38+
getPropertyName(), ac);
39+
}
40+
41+
public CssAspectRatio(ApplContext ac, CssExpression expression)
42+
throws InvalidParamException {
43+
this(ac, expression, false);
44+
}
45+
46+
/**
47+
* Returns the value of this property
48+
*/
49+
public Object get() {
50+
return value;
51+
}
52+
53+
54+
/**
55+
* Returns the name of this property
56+
*/
57+
public final String getPropertyName() {
58+
return "aspect-ratio";
59+
}
60+
61+
/**
62+
* Returns true if this property is "softly" inherited
63+
* e.g. his value is equals to inherit
64+
*/
65+
public boolean isSoftlyInherited() {
66+
return inherit.equals(value);
67+
}
68+
69+
/**
70+
* Returns a string representation of the object.
71+
*/
72+
public String toString() {
73+
return value.toString();
74+
}
75+
76+
/**
77+
* Add this property to the CssStyle.
78+
*
79+
* @param style The CssStyle
80+
*/
81+
public void addToStyle(ApplContext ac, CssStyle style) {
82+
if (((Css3Style) style).cssAspectRatio != null)
83+
style.addRedefinitionWarning(ac, this);
84+
((Css3Style) style).cssAspectRatio = this;
85+
}
86+
87+
/**
88+
* Compares two properties for equality.
89+
*
90+
* @param property The other property.
91+
*/
92+
public boolean equals(CssProperty property) {
93+
return (property instanceof CssAspectRatio &&
94+
value.equals(((CssAspectRatio) property).value));
95+
}
96+
97+
98+
/**
99+
* Get this property in the style.
100+
*
101+
* @param style The style where the property is
102+
* @param resolve if true, resolve the style to find this property
103+
*/
104+
public CssProperty getPropertyInStyle(CssStyle style, boolean resolve) {
105+
if (resolve) {
106+
return ((Css3Style) style).getAspectRatio();
107+
} else {
108+
return ((Css3Style) style).cssAspectRatio;
109+
}
110+
}
111+
}
112+

org/w3c/css/properties/css3/Css3Style.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import org.w3c.css.properties.css.CssAnimationPlayState;
2626
import org.w3c.css.properties.css.CssAnimationTimingFunction;
2727
import org.w3c.css.properties.css.CssAppearance;
28+
import org.w3c.css.properties.css.CssAspectRatio;
2829
import org.w3c.css.properties.css.CssBackfaceVisibility;
2930
import org.w3c.css.properties.css.CssBackgroundBlendMode;
3031
import org.w3c.css.properties.css.CssBackgroundClip;
@@ -603,7 +604,17 @@ public class Css3Style extends ATSCStyle {
603604
public CssBorderStartEndRadius cssBorderStartEndRadius;
604605
public CssBorderEndStartRadius cssBorderEndStartRadius;
605606
public CssBorderEndEndRadius cssBorderEndEndRadius;
607+
public CssAspectRatio cssAspectRatio;
606608

609+
public CssAspectRatio getAspectRatio() {
610+
if (cssAspectRatio == null) {
611+
cssAspectRatio =
612+
(CssAspectRatio) style.CascadingOrder(new CssAspectRatio(),
613+
style, selector);
614+
}
615+
return cssAspectRatio;
616+
}
617+
607618
public CssBorderEndEndRadius getBorderEndEndRadius() {
608619
if (cssBorderEndEndRadius == null) {
609620
cssBorderEndEndRadius =
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
//
2+
// Author: Yves Lafon <ylafon@w3.org>
3+
//
4+
// (c) COPYRIGHT MIT, ERCIM, Keio, Beihang, 2021.
5+
// Please first read the full copyright statement in file COPYRIGHT.html
6+
package org.w3c.css.properties.css3;
7+
8+
import org.w3c.css.util.ApplContext;
9+
import org.w3c.css.util.InvalidParamException;
10+
import org.w3c.css.values.CssExpression;
11+
import org.w3c.css.values.CssIdent;
12+
import org.w3c.css.values.CssRatio;
13+
import org.w3c.css.values.CssTypes;
14+
import org.w3c.css.values.CssValue;
15+
import org.w3c.css.values.CssValueList;
16+
17+
import java.math.BigDecimal;
18+
import java.util.ArrayList;
19+
20+
import static org.w3c.css.values.CssOperator.SPACE;
21+
22+
/**
23+
* @spec https://www.w3.org/TR/2021/WD-css-sizing-4-20210520/#propdef-aspect-ratio
24+
*/
25+
public class CssAspectRatio extends org.w3c.css.properties.css.CssAspectRatio {
26+
27+
public static final CssIdent auto = CssIdent.getIdent("auto");
28+
29+
/**
30+
* Create a new CssAspectRatio
31+
*/
32+
public CssAspectRatio() {
33+
value = initial;
34+
}
35+
36+
/**
37+
* Creates a new CssAspectRatio
38+
*
39+
* @param expression The expression for this property
40+
* @throws InvalidParamException Expressions are incorrect
41+
*/
42+
public CssAspectRatio(ApplContext ac, CssExpression expression, boolean check)
43+
throws InvalidParamException {
44+
if (check && expression.getCount() > 4) {
45+
throw new InvalidParamException("unrecognize", ac);
46+
}
47+
CssValue val;
48+
ArrayList<CssValue> v = new ArrayList<>();
49+
char op;
50+
int ratio_state = 0;
51+
setByUser();
52+
BigDecimal dividend = null;
53+
BigDecimal divisor = null;
54+
55+
while (!expression.end()) {
56+
val = expression.getValue();
57+
op = expression.getOperator();
58+
59+
switch (val.getType()) {
60+
// so we are cheating and create a CssRatio when needed.
61+
case CssTypes.CSS_NUMBER:
62+
if (ratio_state == 0) {
63+
dividend = val.getNumber().getBigDecimalValue();
64+
ratio_state++;
65+
break;
66+
} else if (ratio_state == 2) {
67+
divisor = val.getNumber().getBigDecimalValue();
68+
ratio_state++;
69+
v.add(new CssRatio(dividend, divisor)) ;
70+
break;
71+
}
72+
throw new InvalidParamException("value", val.toString(),
73+
getPropertyName(), ac);
74+
case CssTypes.CSS_SWITCH:
75+
if (ratio_state == 1) {
76+
ratio_state++;
77+
break;
78+
}
79+
throw new InvalidParamException("value", val.toString(),
80+
getPropertyName(), ac);
81+
case CssTypes.CSS_IDENT:
82+
if (inherit.equals(val)) {
83+
if (expression.getCount() > 1) {
84+
throw new InvalidParamException("value", val.toString(),
85+
getPropertyName(), ac);
86+
}
87+
v.add(inherit);
88+
break;
89+
}
90+
if (auto.equals(val)) {
91+
v.add(auto);
92+
break;
93+
}
94+
// unrecognize ident, let it fail
95+
default:
96+
throw new InvalidParamException("value",
97+
val.toString(),
98+
getPropertyName(), ac);
99+
}
100+
if (op != SPACE) {
101+
throw new InvalidParamException("operator",
102+
Character.toString(op), ac);
103+
}
104+
expression.next();
105+
}
106+
// if things are not entirely parsed
107+
if (v.size() == 0) {
108+
throw new InvalidParamException("value",
109+
expression.toString(),
110+
getPropertyName(), ac);
111+
}
112+
if (v.size() > 1) {
113+
if (v.get(0).getType() == v.get(1).getType()) {
114+
throw new InvalidParamException("value", v.get(1).toString(),
115+
getPropertyName(), ac);
116+
}
117+
value = new CssValueList(v);
118+
} else {
119+
value = v.get(0);
120+
}
121+
}
122+
123+
124+
public CssAspectRatio(ApplContext ac, CssExpression expression)
125+
throws InvalidParamException {
126+
this(ac, expression, false);
127+
}
128+
}
129+

org/w3c/css/values/CssRatio.java

Lines changed: 22 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88

99
import org.w3c.css.util.ApplContext;
1010
import org.w3c.css.util.InvalidParamException;
11-
import org.w3c.css.util.Util;
11+
12+
import java.math.BigDecimal;
13+
import java.math.RoundingMode;
1214

1315
/**
1416
* @spec http://www.w3.org/TR/2010/CR-css3-mediaqueries-20100727/#values
@@ -22,10 +24,7 @@ public final int getType() {
2224
return type;
2325
}
2426

25-
float w;
26-
boolean isWInt;
27-
float h;
28-
boolean isHInt;
27+
BigDecimal w, h;
2928

3029

3130
/**
@@ -34,17 +33,20 @@ public final int getType() {
3433
public CssRatio() {
3534
}
3635

36+
public CssRatio(BigDecimal w, BigDecimal h) {
37+
this.w = w;
38+
this.h = h;
39+
}
40+
3741
/**
3842
* Set the value of this ratio.
3943
*
4044
* @param s the string representation of the ratio.
4145
* @param ac For errors and warnings reports.
42-
* @throws org.w3c.css.util.InvalidParamException
43-
* (incorrect format)
46+
* @throws org.w3c.css.util.InvalidParamException (incorrect format)
4447
*/
4548
public void set(String s, ApplContext ac) throws InvalidParamException {
4649
String sw, sh;
47-
s = s.toLowerCase();
4850
int slash = s.indexOf('/');
4951

5052
if (slash == -1) {
@@ -56,37 +58,25 @@ public void set(String s, ApplContext ac) throws InvalidParamException {
5658
sw = s.substring(0, slash).trim();
5759
sh = s.substring(slash + 1).trim();
5860
try {
59-
w = Integer.parseInt(sw);
60-
isWInt = true;
61+
w = new BigDecimal(sw);
6162
} catch (NumberFormatException nex) {
62-
try {
63-
w = Float.parseFloat(sw);
64-
} catch (NumberFormatException ne) {
65-
// not an int, not a float... bail out
66-
throw new InvalidParamException("value", s, ac);
67-
}
63+
// not an int, not a float... bail out
64+
throw new InvalidParamException("value", s, ac);
6865
}
6966
// sanity check
70-
if (w <= 0.f) {
67+
if (w.signum() != 1) {
7168
throw new InvalidParamException("strictly-positive", s, ac);
7269
}
7370

7471
try {
75-
h = Integer.parseInt(sh);
76-
isHInt = true;
72+
h = new BigDecimal(sh);
7773
} catch (NumberFormatException nex) {
78-
try {
79-
h = Float.parseFloat(sh);
80-
} catch (NumberFormatException ne) {
81-
// not an int, not a float... bail out
82-
throw new InvalidParamException("value", s, ac);
83-
}
74+
throw new InvalidParamException("value", s, ac);
8475
}
8576
// sanity check
86-
if (h <= 0.f) {
77+
if (h.signum() != 1) {
8778
throw new InvalidParamException("strictly-positive", s, ac);
8879
}
89-
9080
}
9181

9282
/**
@@ -101,9 +91,7 @@ public Object get() {
10191
*/
10292
public String toString() {
10393
StringBuilder sb = new StringBuilder();
104-
sb.append((isWInt) ? Integer.toString((int) w) : Util.displayFloat(w));
105-
sb.append('/');
106-
sb.append((isHInt) ? Integer.toString((int) h) : Util.displayFloat(h));
94+
sb.append(w.toPlainString()).append('/').append(h.toPlainString());
10795
return sb.toString();
10896
}
10997

@@ -116,7 +104,10 @@ public boolean equals(Object value) {
116104
try {
117105
CssRatio other = (CssRatio) value;
118106
// check that the ratio are the same
119-
return (Float.compare(w / h, other.w / other.h) == 0);
107+
BigDecimal ratio, other_ratio;
108+
ratio = w.divide(h, RoundingMode.CEILING);
109+
other_ratio = other.w.divide(other.h, RoundingMode.CEILING);
110+
return (ratio.compareTo(other_ratio) == 0);
120111
} catch (ClassCastException cce) {
121112
return false;
122113
}

0 commit comments

Comments
 (0)