Selaa lähdekoodia

change assira.ui: refactor CSS grammar

Ranides Atterwim 1 vuosi sitten
vanhempi
commit
4a9158b0a8

+ 1 - 1
assira.ui/src/main/antlr4/imports/BaseSwing.g4

@@ -7,7 +7,7 @@ point
     : x=numberInt CS y=numberInt
     ;
 
-dimension
+dimension2d
     : w=numberInt CS h=numberInt
     ;
 

+ 1 - 1
assira.ui/src/main/antlr4/imports/CssBorder.g4

@@ -30,7 +30,7 @@ borderSize
     ;
 
 borderSizeComponent
-    : numberUnit
+    : length
     | CSS2_BORDER_thin
     | CSS2_BORDER_medium
     | CSS2_BORDER_thick

+ 28 - 22
assira.ui/src/main/antlr4/imports/CssUnit.g4

@@ -2,7 +2,7 @@ grammar CssUnit;
 
 import BaseNumbers;
 
-numberUnit:
+length:
     number unit
     ;
 
@@ -19,24 +19,27 @@ unitAbs
     | CSS2_UNIT_Q
     | CSS2_UNIT_IN
     | CSS2_UNIT_PC
-    | CSS2_UNIT_EM
-    | CSS2_UNIT_REM
     ;
 
 unitRel
-    : CSS2_UNIT_EX
+    : CSS2_UNIT_EM
+    | CSS2_UNIT_EX
+    | CSS2_UNIT_CAP
+    | CSS2_UNIT_CH
+    | CSS2_UNIT_IC
     | CSS2_UNIT_LH
+
+    | CSS2_UNIT_REM
+    | CSS2_UNIT_REX
+    | CSS2_UNIT_RCAP
+    | CSS2_UNIT_RCH
+    | CSS2_UNIT_RIC
     | CSS2_UNIT_RLH
-    | CSS2_UNIT_VB
-    | CSS2_UNIT_VI
+
     | CSS2_UNIT_VW
     | CSS2_UNIT_VH
-    | CSS2_UNIT_SVW
-    | CSS2_UNIT_SVH
-    | CSS2_UNIT_LVW
-    | CSS2_UNIT_LVH
-    | CSS2_UNIT_BVW
-    | CSS2_UNIT_BVH
+    | CSS2_UNIT_VB
+    | CSS2_UNIT_VI
     ;
 
 CSS2_UNIT_PX : 'px';
@@ -48,18 +51,21 @@ CSS2_UNIT_IN : 'in';
 CSS2_UNIT_PC : 'pc';
 
 CSS2_UNIT_EM : 'em';
-CSS2_UNIT_REM: 'rem';
 CSS2_UNIT_EX : 'ex';
+CSS2_UNIT_CAP : 'cap';
+CSS2_UNIT_CH : 'ch';
+CSS2_UNIT_IC : 'ic';
 CSS2_UNIT_LH : 'lh';
-CSS2_UNIT_RLH: 'rlh';
-CSS2_UNIT_VB : 'vb';
-CSS2_UNIT_VI : 'vi';
+
+CSS2_UNIT_REM : 'rem';
+CSS2_UNIT_REX : 'rex';
+CSS2_UNIT_RCAP : 'rcap';
+CSS2_UNIT_RCH : 'rch';
+CSS2_UNIT_RIC : 'ric';
+CSS2_UNIT_RLH : 'rlh';
+
 CSS2_UNIT_VW : 'vw';
 CSS2_UNIT_VH : 'vh';
-CSS2_UNIT_SVW: 'svw';
-CSS2_UNIT_SVH: 'svh';
-CSS2_UNIT_LVW: 'lvw';
-CSS2_UNIT_LVH: 'lvh';
-CSS2_UNIT_BVW: 'bvw';
-CSS2_UNIT_BVH: 'bvh';
+CSS2_UNIT_VB : 'vb';
+CSS2_UNIT_VI : 'vi';
 

+ 22 - 10
assira.ui/src/main/java/net/ranides/assira/ui/model/CssUnit.java

@@ -1,6 +1,9 @@
 package net.ranides.assira.ui.model;
 
+import javax.swing.*;
+
 public enum CssUnit {
+    // https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Styling_basics/Values_and_units#lengths
     PX,
     PT,
     CM,
@@ -8,20 +11,29 @@ public enum CssUnit {
     Q,
     IN,
     PC,
-    EM,
-    REM,
 
+    // https://developer.mozilla.org/en-US/docs/Web/CSS/length#relative_length_units_based_on_font
+    EM,
     EX,
+    CAP,
+    CH,
+    IC,
     LH,
+
+    // https://developer.mozilla.org/en-US/docs/Web/CSS/length#relative_length_units_based_on_root_elements_font
+    REM,
+    REX,
+    RCAP,
+    RCH,
+    RIC,
     RLH,
-    VB,
-    VI,
+
+    // https://developer.mozilla.org/en-US/docs/Web/CSS/length#relative_length_units_based_on_viewport
     VW,
     VH,
-    SVW,
-    SVH,
-    LVW,
-    LVH,
-    BVW,
-    BVH,
+    VMAX,
+    VMIN,
+    VB,
+    VI,
+    ;
 }

+ 4 - 0
assira.ui/src/main/java/net/ranides/assira/ui/parsers/GrammarBase.java

@@ -23,4 +23,8 @@ public class GrammarBase {
         return node.get(GrammarBase.COMPONENT).orElseThrow(() -> new IllegalArgumentException("There is no associated JComponent with node + " + node));
     }
 
+    public static JComponent root(G4Node node) {
+        return component(node).getRootPane();
+    }
+
 }

+ 1 - 1
assira.ui/src/main/java/net/ranides/assira/ui/parsers/ParseCssBorder.java

@@ -44,7 +44,7 @@ public class ParseCssBorder {
     public static final G4Selector<Integer> SIZE_COMPONENT = new G4SelectorBuilder<Integer>()
         .withName("CSS:border-size")
         .withParser(GrammarBase.PARSER)
-        .inherit(ParseCssUnit.NUMERIC)
+        .inherit(ParseCssUnit.LENGTH)
         .valueForToken(UiGrammarParser.CSS2_BORDER_thin, 1)
         .valueForToken(UiGrammarParser.CSS2_BORDER_medium, 2)
         .valueForToken(UiGrammarParser.CSS2_BORDER_thick, 3)

+ 1 - 2
assira.ui/src/main/java/net/ranides/assira/ui/parsers/ParseCssColor.java

@@ -3,6 +3,7 @@ package net.ranides.assira.ui.parsers;
 import lombok.experimental.UtilityClass;
 import net.ranides.assira.collection.query.CQuery;
 import net.ranides.assira.grammar.G4Exception;
+import net.ranides.assira.grammar.G4Node;
 import net.ranides.assira.grammar.G4Selector;
 import net.ranides.assira.grammar.G4SelectorBuilder;
 import net.ranides.assira.text.StringUtils;
@@ -14,7 +15,6 @@ import java.util.NoSuchElementException;
 @UtilityClass
 public class ParseCssColor {
 
-
     public static final G4Selector<Color> COLOR = new G4SelectorBuilder<Color>()
         .withName("CssColor:COLOR")
         .withParser(GrammarBase.PARSER)
@@ -97,7 +97,6 @@ public class ParseCssColor {
         }
     }
 
-
     public static CQuery<Color> colors(String values) {
         try {
             return COLOR.stream(GrammarBase.PARSER.parse("root_colors", values));

+ 134 - 28
assira.ui/src/main/java/net/ranides/assira/ui/parsers/ParseCssUnit.java

@@ -1,6 +1,8 @@
 package net.ranides.assira.ui.parsers;
 
 import lombok.experimental.UtilityClass;
+import net.ranides.assira.generic.ValueUtils;
+import net.ranides.assira.grammar.G4Node;
 import net.ranides.assira.grammar.G4Selector;
 import net.ranides.assira.grammar.G4SelectorBuilder;
 import net.ranides.assira.ui.model.CssUnit;
@@ -22,50 +24,154 @@ public class ParseCssUnit {
         .valueForToken(UiGrammarParser.CSS2_UNIT_Q, CssUnit.Q)
         .valueForToken(UiGrammarParser.CSS2_UNIT_IN, CssUnit.IN)
         .valueForToken(UiGrammarParser.CSS2_UNIT_PC, CssUnit.PC)
+
         .valueForToken(UiGrammarParser.CSS2_UNIT_EM, CssUnit.EM)
-        .valueForToken(UiGrammarParser.CSS2_UNIT_REM, CssUnit.REM)
         .valueForToken(UiGrammarParser.CSS2_UNIT_EX, CssUnit.EX)
+        .valueForToken(UiGrammarParser.CSS2_UNIT_CAP, CssUnit.CAP)
+        .valueForToken(UiGrammarParser.CSS2_UNIT_CH, CssUnit.CH)
+        .valueForToken(UiGrammarParser.CSS2_UNIT_IC, CssUnit.IC)
         .valueForToken(UiGrammarParser.CSS2_UNIT_LH, CssUnit.LH)
+
+        .valueForToken(UiGrammarParser.CSS2_UNIT_REM, CssUnit.REM)
+        .valueForToken(UiGrammarParser.CSS2_UNIT_REX, CssUnit.REX)
+        .valueForToken(UiGrammarParser.CSS2_UNIT_RCAP, CssUnit.RCAP)
+        .valueForToken(UiGrammarParser.CSS2_UNIT_RCH, CssUnit.RCH)
+        .valueForToken(UiGrammarParser.CSS2_UNIT_RIC, CssUnit.RIC)
         .valueForToken(UiGrammarParser.CSS2_UNIT_RLH, CssUnit.RLH)
+
         .valueForToken(UiGrammarParser.CSS2_UNIT_VB, CssUnit.VB)
         .valueForToken(UiGrammarParser.CSS2_UNIT_VI, CssUnit.VI)
         .valueForToken(UiGrammarParser.CSS2_UNIT_VW, CssUnit.VW)
         .valueForToken(UiGrammarParser.CSS2_UNIT_VH, CssUnit.VH)
-        .valueForToken(UiGrammarParser.CSS2_UNIT_SVW, CssUnit.SVW)
-        .valueForToken(UiGrammarParser.CSS2_UNIT_SVH, CssUnit.SVH)
-        .valueForToken(UiGrammarParser.CSS2_UNIT_LVW, CssUnit.LVW)
-        .valueForToken(UiGrammarParser.CSS2_UNIT_LVH, CssUnit.LVH)
-        .valueForToken(UiGrammarParser.CSS2_UNIT_BVW, CssUnit.BVW)
-        .valueForToken(UiGrammarParser.CSS2_UNIT_BVH, CssUnit.BVH)
         .prepare();
 
-    public static final G4Selector<Integer> NUMERIC = new G4SelectorBuilder<Integer>()
-        .withName("CssUnit:NUMERIC")
+    public static final G4Selector<Integer> LENGTH = new G4SelectorBuilder<Integer>()
+        .withName("CssUnit:LENGTH")
         .withParser(GrammarBase.PARSER)
-        .mapRule(UiGrammarParser.RULE_numberUnit, node -> {
-
+        .mapRule(UiGrammarParser.RULE_length, node -> {
             Number number = ParsePrimitives.NUMBER.single(node.child("number"));
             CssUnit unit = UNIT.single(node.child("unit"));
-            switch (unit) {
-                case PX:
-                    return number.intValue();
-                case PT:
-                    return pt2px(number);
-                case EM:
-                    return pt2px(GrammarBase.component(node).getFont().getSize());
-                case EX:
-                    JComponent component = GrammarBase.component(node);
-                    FontMetrics metrics = component.getFontMetrics(component.getFont());
-                    double h = metrics.getStringBounds("x", component.getGraphics()).getHeight();
-                    return (int)Math.round(h);
-                default:
-                    throw new UnsupportedOperationException("Unsupported unit: " + unit);
-            }
+            return Math.round(length(node, number, unit).floatValue());
 
         })
         .prepare();
 
-    private static int pt2px(Number number) {
-        return (int) Math.round((4.0 * number.doubleValue()) / 3.0);
+    public static Number length(G4Node node, Number number, CssUnit unit) {
+        double v = number.doubleValue();
+
+        switch (unit) {
+            case PX:
+                return number;
+            case PT:
+                return 1.3333 * v;
+            case CM:
+                return 37.8000 * v;
+            case MM:
+                return 3.7800 * v;
+            case Q:
+                return 0.0945 * v;
+            case IN:
+                return 96.0000 * v;
+            case PC:
+                return 16.0000 * v;
+
+            case EM:
+                return v * computeEm(GrammarBase.component(node));
+            case EX:
+                return v * computeEx(GrammarBase.component(node));
+            case CAP:
+                return v * computeCap(GrammarBase.component(node));
+            case CH:
+                return v * computeCh(GrammarBase.component(node));
+            case IC:
+                return v * computeIc(GrammarBase.component(node));
+            case LH:
+                return v * computeLh(GrammarBase.component(node));
+
+            case REM:
+                return v * computeEm(GrammarBase.component(node).getRootPane());
+            case REX:
+                return v * computeEx(GrammarBase.component(node).getRootPane());
+            case RCAP:
+                return v * computeCap(GrammarBase.component(node).getRootPane());
+            case RCH:
+                return v * computeCh(GrammarBase.component(node).getRootPane());
+            case RIC:
+                return v * computeIc(GrammarBase.component(node).getRootPane());
+            case RLH:
+                return v * computeLh(GrammarBase.component(node).getRootPane());
+
+            case VW:
+                return v * computeVw(GrammarBase.component(node));
+            case VH:
+                return v * computeVh(GrammarBase.component(node));
+            case VMAX:
+                return v * computeVmax(GrammarBase.component(node));
+            case VMIN:
+                return v * computeVmin(GrammarBase.component(node));
+            case VB:
+                return v * computeVb(GrammarBase.component(node));
+            case VI:
+                return v * computeVi(GrammarBase.component(node));
+
+            default:
+                throw new UnsupportedOperationException("Unsupported unit: " + unit);
+        }
+    }
+
+    private static double computeEx(JComponent component) {
+        FontMetrics metrics = component.getFontMetrics(component.getFont());
+        return metrics.getStringBounds("x", component.getGraphics()).getHeight();
+    }
+
+    private static double computeCap(JComponent component) {
+        FontMetrics metrics = component.getFontMetrics(component.getFont());
+        return metrics.getStringBounds("A", component.getGraphics()).getHeight();
+    }
+
+    private static double computeCh(JComponent component) {
+        FontMetrics metrics = component.getFontMetrics(component.getFont());
+        return metrics.getStringBounds("0", component.getGraphics()).getWidth();
+    }
+
+    private static double computeEm(JComponent component) {
+        return 1.3333 * component.getFont().getSize();
+    }
+
+    private static double computeVh(JComponent component) {
+        return component.getRootPane().getContentPane().getHeight() / 100.0;
+    }
+
+    private static double computeVw(JComponent component) {
+        return component.getRootPane().getContentPane().getHeight() / 100.0;
+    }
+
+    private static double computeVmax(JComponent component) {
+        Container pane = component.getRootPane().getContentPane();
+        return Math.max(pane.getHeight(), pane.getWidth()) / 100.0;
+    }
+
+    private static double computeVmin(JComponent component) {
+        Container pane = component.getRootPane().getContentPane();
+        return Math.max(pane.getHeight(), pane.getWidth()) / 100.0;
     }
+
+    private static double computeVb(JComponent component) {
+        return ValueUtils.or(component.getParent(), component).getWidth() / 100.0;
+    }
+
+    private static double computeVi(JComponent component) {
+        return ValueUtils.or(component.getParent(), component).getHeight() / 100.0;
+    }
+
+    private static double computeIc(JComponent component) {
+        FontMetrics metrics = component.getFontMetrics(component.getFont());
+        return metrics.getStringBounds("水", component.getGraphics()).getWidth();
+    }
+
+    private static double computeLh(JComponent component) {
+        FontMetrics metrics = component.getFontMetrics(component.getFont());
+        return metrics.getHeight();
+    }
+
 }

+ 7 - 0
assira.ui/src/test/java/net/ranides/assira/ui/parsers/ParseCssUnitTest.java

@@ -0,0 +1,7 @@
+package net.ranides.assira.ui.parsers;
+
+import static org.junit.Assert.*;
+
+public class ParseCssUnitTest {
+
+}

+ 11 - 29
assira.ui/src/test/java/net/ranides/assira/ui/primitives/UiGrammarTest.java

@@ -99,43 +99,25 @@ public class UiGrammarTest {
 
     @Test
     public void grammarInterpretedCoverage() throws IOException {
-        G4ParserCoverage info = G4Parser.builder()
+        G4Parser gp = G4Parser.builder()
             .sourceFile("src\\main\\antlr4\\net\\ranides\\grammars\\generated\\UiGrammar.g4")
             .imports("src\\main\\antlr4\\imports")
             .handler((message, error) -> System.out.println(message))
-            .build()
-            .rules();
-
-        info.use(IGNORE);
-
-        info.use(ParsePrimitives.NUMBER);
-        info.use(ParsePrimitives.INT);
-        info.use(ParsePrimitives.REAL);
-        info.use(ParsePrimitives.CODE);
-        info.use(ParseCssUnit.UNIT);
-        info.use(ParseCssUnit.NUMERIC);
-        info.use(ParseCssColor.COLOR);
-        info.use(ParseCssBorder.STYLE);
-        info.use(ParseCssBorder.SIZE);
-        info.use(ParseCssBorder.SIZE_COMPONENT);
-        info.use(ParseCssBorder.BORDER);
-
-        StringWriter sw = new StringWriter();
-        printCoverage(info, new StrAppender(sw));
-        if(HostSystem.JUNIT.detected() || HostSystem.IDEA.detected()) {
-            printCoverage(info);
-        }
-
-        assertEquals(ResourceUtils.text("grammars/CssCoverage.txt"), sw.toString());
+            .build();
+        grammarCoverage(gp);
     }
 
     @Test
     public void grammarGeneratedCoverage() throws IOException {
-        G4ParserCoverage info = G4Parser.builder()
+        G4Parser gp = G4Parser.builder()
             .lexer(UiGrammarLexer.class)
             .parser(UiGrammarParser.class)
-            .build()
-            .rules();
+            .build();
+        grammarCoverage(gp);
+    }
+
+    public void grammarCoverage(G4Parser gp) throws IOException {
+        G4ParserCoverage info = gp.rules();
 
         info.use(IGNORE);
 
@@ -144,7 +126,7 @@ public class UiGrammarTest {
         info.use(ParsePrimitives.REAL);
         info.use(ParsePrimitives.CODE);
         info.use(ParseCssUnit.UNIT);
-        info.use(ParseCssUnit.NUMERIC);
+        info.use(ParseCssUnit.LENGTH);
         info.use(ParseCssColor.COLOR);
         info.use(ParseCssBorder.STYLE);
         info.use(ParseCssBorder.SIZE);

+ 9 - 8
assira.ui/src/test/resources/grammars/CssCoverage.txt

@@ -14,24 +14,25 @@
 1: CSS2_BORDER_solid
 1: CSS2_BORDER_thick
 1: CSS2_BORDER_thin
-1: CSS2_UNIT_BVH
-1: CSS2_UNIT_BVW
+1: CSS2_UNIT_CAP
+1: CSS2_UNIT_CH
 1: CSS2_UNIT_CM
 1: CSS2_UNIT_EM
 1: CSS2_UNIT_EX
+1: CSS2_UNIT_IC
 1: CSS2_UNIT_IN
 1: CSS2_UNIT_LH
-1: CSS2_UNIT_LVH
-1: CSS2_UNIT_LVW
 1: CSS2_UNIT_MM
 1: CSS2_UNIT_PC
 1: CSS2_UNIT_PT
 1: CSS2_UNIT_PX
 1: CSS2_UNIT_Q
+1: CSS2_UNIT_RCAP
+1: CSS2_UNIT_RCH
 1: CSS2_UNIT_REM
+1: CSS2_UNIT_REX
+1: CSS2_UNIT_RIC
 1: CSS2_UNIT_RLH
-1: CSS2_UNIT_SVH
-1: CSS2_UNIT_SVW
 1: CSS2_UNIT_VB
 1: CSS2_UNIT_VH
 1: CSS2_UNIT_VI
@@ -90,14 +91,14 @@
 1: componentLightness <= numberPct
 1: componentRGB <= numberInt
 1: componentSaturation <= numberPct
-0: dimension
+0: dimension2d
 0: insets
+1: length
 0: number
 1: numberHex <= NUMBER_HEX
 1: numberInt <= NUMBER_INT
 1: numberPct <= NUMBER_PCT
 1: numberReal <= NUMBER_REAL
-1: numberUnit
 0: point
 0: rectangle
 0: root_border