From bcb8b7f642a1f2f2b0c5dd81c8d4d61c55706d95 Mon Sep 17 00:00:00 2001
From: Carlos Amengual
Date: Tue, 8 Oct 2024 20:51:07 +0200
Subject: [PATCH] Custom properties, conditional and property rules, CSS-wide
keywords, calc() and attr()
---
config/checkstyle/suppressions.xml | 1 +
.../echosvg/anim/dom/AbstractSVGLength.java | 7 +-
.../echosvg/anim/dom/SVGOMAnimatedRect.java | 12 +-
.../carte/echosvg/anim/dom/SVGOMElement.java | 7 +-
.../bridge/AbstractGraphicsNodeBridge.java | 7 +-
.../bridge/AnimatableGenericSVGBridge.java | 7 +-
.../carte/echosvg/bridge/BridgeContext.java | 21 +-
.../sf/carte/echosvg/bridge/CSSFontFace.java | 4 +-
.../sf/carte/echosvg/bridge/CSSUtilities.java | 4 +-
.../carte/echosvg/bridge/CursorManager.java | 4 +-
.../sf/carte/echosvg/bridge/PaintServer.java | 11 +-
.../bridge/SVGAnimationElementBridge.java | 7 +-
.../echosvg/bridge/SVGAnimationEngine.java | 16 +-
.../bridge/SVGDescriptiveElementBridge.java | 7 +-
.../echosvg/bridge/SVGDocumentBridge.java | 7 +-
.../echosvg/bridge/SVGTextElementBridge.java | 19 +-
.../carte/echosvg/bridge/TextUtilities.java | 2 +-
.../carte/echosvg/bridge/UnitProcessor.java | 7 +-
.../io/sf/carte/echosvg/bridge/UserAgent.java | 19 +-
.../echosvg/bridge/UserAgentAdapter.java | 10 +-
.../io/sf/carte/echosvg/bridge/ViewBox.java | 14 +-
.../svg12/SVGFlowRootElementBridge.java | 9 +-
.../svg12/SVGSolidColorElementBridge.java | 2 +-
.../echosvg/bridge/ModificationsTest.java | 6 +-
.../carte/echosvg/bridge/PaintServerTest.java | 31 +-
.../echosvg/css/CSSSecurityException.java | 65 +
.../echosvg/css/dom/CSSOMComputedStyle.java | 11 +-
.../carte/echosvg/css/dom/CSSOMSVGColor.java | 8 +-
.../css/dom/CSSOMSVGComputedStyle.java | 3 +-
.../css/dom/CSSOMSVGStyleDeclaration.java | 3 +-
.../css/dom/CSSOMStyleDeclaration.java | 11 +-
.../sf/carte/echosvg/css/dom/CSSOMValue.java | 32 +-
.../io/sf/carte/echosvg/css/dom/CSSValue.java | 358 ------
.../css/engine/CSSCircularityException.java | 23 +-
.../carte/echosvg/css/engine/CSSContext.java | 17 +-
.../carte/echosvg/css/engine/CSSEngine.java | 1142 ++++++++++++++++-
.../css/engine/CSSResourceLimitException.java | 38 +
.../carte/echosvg/css/engine/CounterRef.java | 53 +
.../css/engine/PropertyDefinitionImpl.java | 88 ++
.../echosvg/css/engine/StyleDeclaration.java | 76 +-
.../sf/carte/echosvg/css/engine/StyleMap.java | 79 +-
.../carte/echosvg/css/engine/StyleSheet.java | 20 +
.../echosvg/css/engine/SupportsRule.java | 114 ++
.../engine/value/AbstractColorManager.java | 50 +-
.../css/engine/value/AbstractValue.java | 20 +-
.../engine/value/AbstractValueFactory.java | 2 +-
.../css/engine/value/AbstractValueList.java | 7 +-
.../engine/value/AbstractValueManager.java | 50 +-
.../engine/value/CSSProxyValueException.java | 37 +
.../echosvg/css/engine/value/CSSVal.java | 114 ++
.../echosvg/css/engine/value/CalcValue.java | 138 ++
.../css/engine/value/ColorFunction.java | 2 +-
.../echosvg/css/engine/value/ColorValue.java | 6 +-
.../css/engine/value/ComputedValue.java | 4 +-
.../echosvg/css/engine/value/FloatValue.java | 130 +-
.../css/engine/value/IdentifierManager.java | 21 +-
.../css/engine/value/ImmutableUnitValue.java | 2 +-
.../css/engine/value/InheritValue.java | 37 +-
.../css/engine/value/KeywordValue.java | 57 +
.../css/engine/value/LCHColorValue.java | 4 +-
.../css/engine/value/LabColorValue.java | 2 +-
.../css/engine/value/LengthManager.java | 55 +-
.../css/engine/value/LexicalHelper.java | 43 +
.../css/engine/value/LexicalValue.java | 71 +
.../echosvg/css/engine/value/ListValue.java | 106 +-
.../css/engine/value/NumericValue.java | 76 +-
.../css/engine/value/PendingValue.java | 65 +
.../css/engine/value/PropertyDefinition.java | 57 +
.../css/engine/value/RGBColorValue.java | 38 +-
.../echosvg/css/engine/value/RectManager.java | 79 +-
.../echosvg/css/engine/value/RectValue.java | 2 +-
.../echosvg/css/engine/value/RevertValue.java | 62 +
.../css/engine/value/ShorthandManager.java | 19 +-
.../echosvg/css/engine/value/TypedValue.java | 78 ++
.../echosvg/css/engine/value/UnsetValue.java | 62 +
.../carte/echosvg/css/engine/value/Value.java | 101 +-
.../css/engine/value/ValueConstants.java | 8 +-
.../css/engine/value/ValueManager.java | 15 +-
.../css/engine/value/css2/ClipManager.java | 26 +-
.../css/engine/value/css2/CursorManager.java | 39 +-
.../engine/value/css2/FontFamilyManager.java | 58 +-
.../value/css2/FontShorthandManager.java | 102 +-
.../value/css2/FontSizeAdjustManager.java | 32 +-
.../engine/value/css2/FontSizeManager.java | 47 +-
.../engine/value/css2/FontStretchManager.java | 2 +-
.../engine/value/css2/FontWeightManager.java | 2 +-
.../css/engine/value/css2/SrcManager.java | 82 +-
.../value/css2/TextDecorationManager.java | 45 +-
.../value/svg/BaselineShiftManager.java | 12 +-
.../css/engine/value/svg/ClipPathManager.java | 29 +-
.../engine/value/svg/ColorProfileManager.java | 28 +-
.../value/svg/EnableBackgroundManager.java | 14 +-
.../css/engine/value/svg/FilterManager.java | 27 +-
.../value/svg/GlyphOrientationManager.java | 39 +-
.../svg/GlyphOrientationVerticalManager.java | 2 +-
.../css/engine/value/svg/KerningManager.java | 9 +-
.../css/engine/value/svg/MarkerManager.java | 28 +-
.../value/svg/MarkerShorthandManager.java | 36 +-
.../css/engine/value/svg/MaskManager.java | 28 +-
.../css/engine/value/svg/OpacityManager.java | 34 +-
.../css/engine/value/svg/SVGPaintManager.java | 5 +
.../css/engine/value/svg/SpacingManager.java | 3 +-
.../value/svg/StrokeDasharrayManager.java | 45 +-
.../value/svg/StrokeMiterlimitManager.java | 36 +-
.../engine/value/svg12/LineHeightManager.java | 8 +-
.../value/svg12/MarginShorthandManager.java | 49 +-
.../value/resources/Messages.properties | 7 +-
.../dom/ExtensibleDOMImplementation.java | 4 +-
.../carte/echosvg/parser/UnitProcessor.java | 35 +-
.../sf/carte/echosvg/dom/svg/SVGContext.java | 12 +-
.../echosvg/swing/svg/JSVGComponent.java | 30 +-
.../carte/echosvg/swing/svg/SVGUserAgent.java | 12 +-
.../swing/svg/SVGUserAgentAdapter.java | 9 +-
.../echosvg/test/image/ImageCompareUtil.java | 4 +
.../svg/AbstractBypassRenderingCheck.java | 4 +-
.../test/svg/AbstractSamplesRendering.java | 9 +
.../echosvg/test/svg/DenialOfServiceTest.java | 139 ++
.../test/svg/MermaidRenderingTest.java | 8 +-
.../test/svg/ResolutionPxMmRenderingTest.java | 3 +-
.../test/svg/SVGRenderingAccuracyTest.java | 33 +-
.../test/svg/SamplesSpec2RenderingTest.java | 25 +
.../test/svg/SamplesSpecRenderingTest.java | 6 +
.../test/svg/StyleBypassRenderingTest.java | 10 +-
.../test/svg/TranscoderSecurityCheck.java | 104 ++
.../test/AbstractImageTranscoderTest.java | 4 +
...PixelToMMTest.java => ResolutionTest.java} | 37 +-
.../transcoder/SVGAbstractTranscoder.java | 146 ++-
.../transcoder/image/JPEGTranscoder.java | 6 +-
.../PNGTranscoderImageIOWriteAdapter.java | 5 +-
...NGTranscoderInternalCodecWriteAdapter.java | 8 +-
.../TIFFTranscoderImageIOWriteAdapter.java | 5 +-
.../echosvg/transcoder/impl/SizingHelper.java | 22 +-
.../transcoder/print/PrintTranscoder.java | 1 +
.../transcoder/util/CSSTranscodingHelper.java | 17 +-
gradle.properties | 2 +-
.../tests/spec/painting/visibilityUnset.svg | 139 ++
samples/tests/spec/text/verticalText.svg | 8 +-
samples/tests/spec2/styling/attrValues.svg | 76 ++
.../tests/spec2/styling/conditionalRules.svg | 181 +++
samples/unsupportedRules.svg | 9 +-
.../image/accepted-variation/px2mm72dpi.png | Bin 2404 -> 0 bytes
.../image/accepted-variation/px2mm96dpi.png | Bin 2392 -> 0 bytes
.../echosvg/transcoder/image/px2mm72dpi.png | Bin 1365 -> 0 bytes
.../echosvg/transcoder/image/px2mm96dpi.png | Bin 1368 -> 0 bytes
.../transcoder/image/resolution72dpi.png | Bin 0 -> 2986 bytes
.../transcoder/image/resolution96dpi.png | Bin 0 -> 2986 bytes
.../tests/spec/painting/visibilityUnset.png | Bin 0 -> 14450 bytes
.../spec/rendering/resolution-0.25pxmm.png | Bin 50701 -> 50282 bytes
.../tests/spec2/styling/attrValues.png | Bin 0 -> 47202 bytes
.../spec2/styling/conditionalRules-dark.png | Bin 0 -> 50074 bytes
.../spec2/styling/conditionalRules-print.png | Bin 0 -> 59745 bytes
.../tests/spec2/styling/conditionalRules.png | Bin 0 -> 60929 bytes
.../spec2/styling/conditionalRules_Gray.png | Bin 0 -> 68247 bytes
.../transcoder/image/resources/resolution.svg | 50 +
.../transcoder/security/attrCircularity.svg | 73 ++
.../transcoder/security/varBLAFallback.svg | 94 ++
.../security/varBillionLaughsAttack.svg | 94 ++
.../transcoder/security/varCircularity.svg | 73 ++
.../security/varFallbackCircularity.svg | 73 ++
159 files changed, 5357 insertions(+), 1089 deletions(-)
create mode 100644 echosvg-css/src/main/java/io/sf/carte/echosvg/css/CSSSecurityException.java
delete mode 100644 echosvg-css/src/main/java/io/sf/carte/echosvg/css/dom/CSSValue.java
rename test-resources/io/sf/carte/echosvg/transcoder/image/resources/px2mm.svg => echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/CSSCircularityException.java (62%)
create mode 100644 echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/CSSResourceLimitException.java
create mode 100644 echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/CounterRef.java
create mode 100644 echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/PropertyDefinitionImpl.java
create mode 100644 echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/SupportsRule.java
create mode 100644 echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/CSSProxyValueException.java
create mode 100644 echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/CSSVal.java
create mode 100644 echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/CalcValue.java
create mode 100644 echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/KeywordValue.java
create mode 100644 echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/LexicalHelper.java
create mode 100644 echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/LexicalValue.java
create mode 100644 echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/PendingValue.java
create mode 100644 echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/PropertyDefinition.java
create mode 100644 echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/RevertValue.java
create mode 100644 echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/TypedValue.java
create mode 100644 echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/UnsetValue.java
create mode 100644 echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/DenialOfServiceTest.java
create mode 100644 echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/TranscoderSecurityCheck.java
rename echosvg-test/src/test/java/io/sf/carte/echosvg/transcoder/image/test/{PixelToMMTest.java => ResolutionTest.java} (66%)
create mode 100644 samples/tests/spec/painting/visibilityUnset.svg
create mode 100644 samples/tests/spec2/styling/attrValues.svg
create mode 100644 samples/tests/spec2/styling/conditionalRules.svg
delete mode 100644 test-references/io/sf/carte/echosvg/transcoder/image/accepted-variation/px2mm72dpi.png
delete mode 100644 test-references/io/sf/carte/echosvg/transcoder/image/accepted-variation/px2mm96dpi.png
delete mode 100644 test-references/io/sf/carte/echosvg/transcoder/image/px2mm72dpi.png
delete mode 100644 test-references/io/sf/carte/echosvg/transcoder/image/px2mm96dpi.png
create mode 100644 test-references/io/sf/carte/echosvg/transcoder/image/resolution72dpi.png
create mode 100644 test-references/io/sf/carte/echosvg/transcoder/image/resolution96dpi.png
create mode 100644 test-references/samples/tests/spec/painting/visibilityUnset.png
create mode 100644 test-references/samples/tests/spec2/styling/attrValues.png
create mode 100644 test-references/samples/tests/spec2/styling/conditionalRules-dark.png
create mode 100644 test-references/samples/tests/spec2/styling/conditionalRules-print.png
create mode 100644 test-references/samples/tests/spec2/styling/conditionalRules.png
create mode 100644 test-references/samples/tests/spec2/styling/conditionalRules_Gray.png
create mode 100644 test-resources/io/sf/carte/echosvg/transcoder/image/resources/resolution.svg
create mode 100644 test-resources/io/sf/carte/echosvg/transcoder/security/attrCircularity.svg
create mode 100644 test-resources/io/sf/carte/echosvg/transcoder/security/varBLAFallback.svg
create mode 100644 test-resources/io/sf/carte/echosvg/transcoder/security/varBillionLaughsAttack.svg
create mode 100644 test-resources/io/sf/carte/echosvg/transcoder/security/varCircularity.svg
create mode 100644 test-resources/io/sf/carte/echosvg/transcoder/security/varFallbackCircularity.svg
diff --git a/config/checkstyle/suppressions.xml b/config/checkstyle/suppressions.xml
index 6d414f1b7..d7cc746bd 100644
--- a/config/checkstyle/suppressions.xml
+++ b/config/checkstyle/suppressions.xml
@@ -49,6 +49,7 @@
+
diff --git a/echosvg-anim/src/main/java/io/sf/carte/echosvg/anim/dom/AbstractSVGLength.java b/echosvg-anim/src/main/java/io/sf/carte/echosvg/anim/dom/AbstractSVGLength.java
index 97854996c..cf0f16c33 100644
--- a/echosvg-anim/src/main/java/io/sf/carte/echosvg/anim/dom/AbstractSVGLength.java
+++ b/echosvg-anim/src/main/java/io/sf/carte/echosvg/anim/dom/AbstractSVGLength.java
@@ -242,12 +242,9 @@ public Element getElement() {
return getAssociatedElement();
}
- /**
- * Returns the size of a px CSS unit in millimeters.
- */
@Override
- public float getPixelUnitToMillimeter() {
- return getAssociatedElement().getSVGContext().getPixelUnitToMillimeter();
+ public float getResolution() {
+ return getAssociatedElement().getSVGContext().getResolution();
}
/**
diff --git a/echosvg-anim/src/main/java/io/sf/carte/echosvg/anim/dom/SVGOMAnimatedRect.java b/echosvg-anim/src/main/java/io/sf/carte/echosvg/anim/dom/SVGOMAnimatedRect.java
index 1705662f6..19e8130c1 100644
--- a/echosvg-anim/src/main/java/io/sf/carte/echosvg/anim/dom/SVGOMAnimatedRect.java
+++ b/echosvg-anim/src/main/java/io/sf/carte/echosvg/anim/dom/SVGOMAnimatedRect.java
@@ -18,17 +18,17 @@
*/
package io.sf.carte.echosvg.anim.dom;
+import org.w3c.css.om.unit.CSSUnit;
import org.w3c.dom.Attr;
import org.w3c.dom.DOMException;
import org.w3c.dom.svg.SVGAnimatedRect;
import org.w3c.dom.svg.SVGRect;
-import io.sf.carte.doc.style.css.CSSUnit;
+import io.sf.carte.doc.style.css.CSSExpressionValue;
+import io.sf.carte.doc.style.css.CSSTypedValue;
import io.sf.carte.doc.style.css.CSSValue.CssType;
import io.sf.carte.doc.style.css.property.Evaluator;
-import io.sf.carte.doc.style.css.property.ExpressionValue;
import io.sf.carte.doc.style.css.property.StyleValue;
-import io.sf.carte.doc.style.css.property.TypedValue;
import io.sf.carte.doc.style.css.property.ValueFactory;
import io.sf.carte.doc.style.css.property.ValueList;
import io.sf.carte.echosvg.anim.values.AnimatableRectValue;
@@ -286,7 +286,7 @@ private boolean computeRectangle(StyleValue value, float[] numbers) throws DOMEx
if (item.getCssValueType() != CssType.TYPED) {
return false;
}
- TypedValue typed = (TypedValue) item;
+ CSSTypedValue typed = (CSSTypedValue) item;
switch (item.getPrimitiveType()) {
case NUMERIC:
if (typed.getUnitType() != CSSUnit.CSS_NUMBER) {
@@ -294,8 +294,8 @@ private boolean computeRectangle(StyleValue value, float[] numbers) throws DOMEx
}
break;
case EXPRESSION:
- Evaluator eval = new Evaluator();
- typed = eval.evaluateExpression((ExpressionValue) typed);
+ Evaluator eval = new Evaluator(CSSUnit.CSS_NUMBER);
+ typed = eval.evaluateExpression((CSSExpressionValue) typed);
if (typed.getUnitType() != CSSUnit.CSS_NUMBER) {
return false;
}
diff --git a/echosvg-anim/src/main/java/io/sf/carte/echosvg/anim/dom/SVGOMElement.java b/echosvg-anim/src/main/java/io/sf/carte/echosvg/anim/dom/SVGOMElement.java
index bad75364f..6b67258c2 100644
--- a/echosvg-anim/src/main/java/io/sf/carte/echosvg/anim/dom/SVGOMElement.java
+++ b/echosvg-anim/src/main/java/io/sf/carte/echosvg/anim/dom/SVGOMElement.java
@@ -877,12 +877,9 @@ public Element getElement() {
return SVGOMElement.this;
}
- /**
- * Returns the size of a px CSS unit in millimeters.
- */
@Override
- public float getPixelUnitToMillimeter() {
- return getSVGContext().getPixelUnitToMillimeter();
+ public float getResolution() {
+ return getSVGContext().getResolution();
}
/**
diff --git a/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/AbstractGraphicsNodeBridge.java b/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/AbstractGraphicsNodeBridge.java
index 813cf3b45..d77737eb2 100644
--- a/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/AbstractGraphicsNodeBridge.java
+++ b/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/AbstractGraphicsNodeBridge.java
@@ -490,12 +490,9 @@ protected void fireBBoxChangeEvent() {
// SVGContext implementation ///////////////////////////////////////////
- /**
- * Returns the size of a px CSS unit in millimeters.
- */
@Override
- public float getPixelUnitToMillimeter() {
- return ctx.getUserAgent().getPixelUnitToMillimeter();
+ public float getResolution() {
+ return ctx.getUserAgent().getResolution();
}
protected SoftReference bboxShape = null;
diff --git a/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/AnimatableGenericSVGBridge.java b/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/AnimatableGenericSVGBridge.java
index 01a8f335f..bb74dae71 100644
--- a/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/AnimatableGenericSVGBridge.java
+++ b/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/AnimatableGenericSVGBridge.java
@@ -59,12 +59,9 @@ public void handleElement(BridgeContext ctx, Element e) {
// SVGContext ////////////////////////////////////////////////////////////
- /**
- * Returns the size of a px CSS unit in millimeters.
- */
@Override
- public float getPixelUnitToMillimeter() {
- return ctx.getUserAgent().getPixelUnitToMillimeter();
+ public float getResolution() {
+ return ctx.getUserAgent().getResolution();
}
/**
diff --git a/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/BridgeContext.java b/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/BridgeContext.java
index 05bdca8c8..fc649e5bb 100644
--- a/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/BridgeContext.java
+++ b/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/BridgeContext.java
@@ -70,8 +70,8 @@
import io.sf.carte.echosvg.dom.events.NodeEventTarget;
import io.sf.carte.echosvg.dom.svg.SVGContext;
import io.sf.carte.echosvg.dom.xbl.XBLManager;
-import io.sf.carte.echosvg.ext.awt.color.StandardColorSpaces;
import io.sf.carte.echosvg.ext.awt.color.ColorContext;
+import io.sf.carte.echosvg.ext.awt.color.StandardColorSpaces;
import io.sf.carte.echosvg.gvt.CompositeGraphicsNode;
import io.sf.carte.echosvg.gvt.GraphicsNode;
import io.sf.carte.echosvg.script.Interpreter;
@@ -1830,12 +1830,23 @@ public float getBolderFontWeight(float f) {
/**
* Returns the size of a px CSS unit in millimeters.
+ *
+ * @deprecated Use {@link #getResolution()}.
*/
+ @Deprecated
@Override
public float getPixelUnitToMillimeter() {
return userAgent.getPixelUnitToMillimeter();
}
+ /**
+ * Returns the resolution in dpi.
+ */
+ @Override
+ public float getResolution() {
+ return userAgent.getResolution();
+ }
+
/**
* Returns the medium font size.
*/
@@ -1877,6 +1888,14 @@ public void checkLoadExternalResource(ParsedURL resourceURL, ParsedURL docURL) t
userAgent.checkLoadExternalResource(resourceURL, docURL);
}
+ /**
+ * Get prefers-color-scheme.
+ */
+ @Override
+ public String getPrefersColorScheme() {
+ return userAgent.getPrefersColorScheme();
+ }
+
/**
* Tells whether the given SVG document is dynamic.
*/
diff --git a/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/CSSFontFace.java b/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/CSSFontFace.java
index 92d7b0ea1..0ba8313b6 100644
--- a/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/CSSFontFace.java
+++ b/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/CSSFontFace.java
@@ -21,8 +21,8 @@
import java.util.LinkedList;
import java.util.List;
-import io.sf.carte.echosvg.css.dom.CSSValue.CssType;
-import io.sf.carte.echosvg.css.dom.CSSValue.Type;
+import io.sf.carte.doc.style.css.CSSValue.CssType;
+import io.sf.carte.doc.style.css.CSSValue.Type;
import io.sf.carte.echosvg.css.engine.CSSEngine;
import io.sf.carte.echosvg.css.engine.FontFaceRule;
import io.sf.carte.echosvg.css.engine.SVGCSSEngine;
diff --git a/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/CSSUtilities.java b/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/CSSUtilities.java
index 73b926d71..0d7c03d54 100644
--- a/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/CSSUtilities.java
+++ b/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/CSSUtilities.java
@@ -28,10 +28,10 @@
import org.w3c.dom.Element;
+import io.sf.carte.doc.style.css.CSSValue.CssType;
+import io.sf.carte.doc.style.css.CSSValue.Type;
import io.sf.carte.echosvg.anim.dom.SVGOMDocument;
import io.sf.carte.echosvg.constants.XMLConstants;
-import io.sf.carte.echosvg.css.dom.CSSValue.CssType;
-import io.sf.carte.echosvg.css.dom.CSSValue.Type;
import io.sf.carte.echosvg.css.engine.CSSEngine;
import io.sf.carte.echosvg.css.engine.CSSStylableElement;
import io.sf.carte.echosvg.css.engine.SVGCSSEngine;
diff --git a/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/CursorManager.java b/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/CursorManager.java
index 89114b1b7..4f6e33c3e 100644
--- a/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/CursorManager.java
+++ b/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/CursorManager.java
@@ -40,8 +40,8 @@
import org.w3c.dom.svg.SVGDocument;
import org.w3c.dom.svg.SVGPreserveAspectRatio;
-import io.sf.carte.echosvg.css.dom.CSSValue.CssType;
-import io.sf.carte.echosvg.css.dom.CSSValue.Type;
+import io.sf.carte.doc.style.css.CSSValue.CssType;
+import io.sf.carte.doc.style.css.CSSValue.Type;
import io.sf.carte.echosvg.css.engine.SVGCSSEngine;
import io.sf.carte.echosvg.css.engine.value.Value;
import io.sf.carte.echosvg.dom.AbstractNode;
diff --git a/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/PaintServer.java b/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/PaintServer.java
index 8482d810c..de653a699 100644
--- a/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/PaintServer.java
+++ b/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/PaintServer.java
@@ -32,8 +32,8 @@
import org.w3c.css.om.unit.CSSUnit;
import org.w3c.dom.Element;
-import io.sf.carte.echosvg.css.dom.CSSValue.CssType;
-import io.sf.carte.echosvg.css.dom.CSSValue.Type;
+import io.sf.carte.doc.style.css.CSSValue.CssType;
+import io.sf.carte.doc.style.css.CSSValue.Type;
import io.sf.carte.echosvg.css.engine.SVGCSSEngine;
import io.sf.carte.echosvg.css.engine.value.ColorFunction;
import io.sf.carte.echosvg.css.engine.value.ColorValue;
@@ -305,7 +305,8 @@ public static Paint convertPaint(Element paintedElement, GraphicsNode paintedNod
break;
}
}
- throw new IllegalArgumentException("Paint argument is not an appropriate CSS value");
+ throw new IllegalArgumentException(
+ "Paint argument is not an appropriate CSS value (" + paintDef.getCssText() + ").");
}
/**
@@ -652,7 +653,7 @@ private static Color convert3Color(ColorSpace space, ColorFunction c, float opac
*/
private static float resolveColorComponent(NumericValue item) {
float f;
- switch (item.getCSSUnit()) {
+ switch (item.getUnitType()) {
case CSSUnit.CSS_NUMBER:
f = item.getFloatValue();
if (f < 0f) {
@@ -831,7 +832,7 @@ public static int convertStrokeLinejoin(Value v) {
*/
private static float resolveAlphaComponent(Value v) {
float f;
- switch (v.getCSSUnit()) {
+ switch (v.getUnitType()) {
case CSSUnit.CSS_PERCENTAGE:
f = v.getFloatValue();
f = (f > 100f) ? 100f : (f < 0f) ? 0f : f;
diff --git a/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/SVGAnimationElementBridge.java b/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/SVGAnimationElementBridge.java
index 2104089b6..de11b0e5a 100644
--- a/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/SVGAnimationElementBridge.java
+++ b/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/SVGAnimationElementBridge.java
@@ -386,12 +386,9 @@ public void dispose() {
// SVGContext ///////////////////////////////////////////////////////////
- /**
- * Returns the size of a px CSS unit in millimeters.
- */
@Override
- public float getPixelUnitToMillimeter() {
- return ctx.getUserAgent().getPixelUnitToMillimeter();
+ public float getResolution() {
+ return ctx.getUserAgent().getResolution();
}
@Override
diff --git a/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/SVGAnimationEngine.java b/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/SVGAnimationEngine.java
index 48ba03649..60e3cadcc 100644
--- a/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/SVGAnimationEngine.java
+++ b/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/SVGAnimationEngine.java
@@ -38,6 +38,8 @@
import org.w3c.dom.svg.SVGLength;
import org.w3c.dom.svg.SVGPreserveAspectRatio;
+import io.sf.carte.doc.style.css.CSSValue.CssType;
+import io.sf.carte.doc.style.css.CSSValue.Type;
import io.sf.carte.doc.style.css.property.NumberValue;
import io.sf.carte.echosvg.anim.AnimationEngine;
import io.sf.carte.echosvg.anim.AnimationException;
@@ -67,8 +69,6 @@
import io.sf.carte.echosvg.anim.values.AnimatableStringValue;
import io.sf.carte.echosvg.anim.values.AnimatableValue;
import io.sf.carte.echosvg.constants.XMLConstants;
-import io.sf.carte.echosvg.css.dom.CSSValue.CssType;
-import io.sf.carte.echosvg.css.dom.CSSValue.Type;
import io.sf.carte.echosvg.css.engine.CSSEngine;
import io.sf.carte.echosvg.css.engine.CSSStylableElement;
import io.sf.carte.echosvg.css.engine.StyleMap;
@@ -1203,7 +1203,7 @@ public AnimatableValue createValue(AnimationTarget target, String ns, String ln,
*/
@Override
public AnimatableValue createValue(AnimationTarget target, String pn, Value v) {
- switch (v.getCSSUnit()) {
+ switch (v.getUnitType()) {
case CSSUnit.CSS_PERCENTAGE:
return new AnimatableNumberOrPercentageValue(target, v.getFloatValue(), true);
case CSSUnit.CSS_NUMBER:
@@ -1767,7 +1767,7 @@ protected AnimatableValue createAnimatableValue(AnimationTarget target, String p
return new AnimatableLengthOrIdentValue(target, v.getIdentifierValue());
}
short pcInterp = target.getPercentageInterpretation(null, pn, true);
- return new AnimatableLengthOrIdentValue(target, v.getCSSUnit(), v.getFloatValue(), pcInterp);
+ return new AnimatableLengthOrIdentValue(target, v.getUnitType(), v.getFloatValue(), pcInterp);
}
}
@@ -1805,7 +1805,7 @@ protected class AnimatableAngleValueFactory extends CSSValueFactory {
@Override
protected AnimatableValue createAnimatableValue(AnimationTarget target, String pn, Value v) {
short unit;
- switch (v.getCSSUnit()) {
+ switch (v.getUnitType()) {
case CSSUnit.CSS_NUMBER:
case CSSUnit.CSS_DEG:
unit = SVGAngle.SVG_ANGLETYPE_DEG;
@@ -1818,7 +1818,7 @@ protected AnimatableValue createAnimatableValue(AnimationTarget target, String p
break;
default:
try {
- float f = NumberValue.floatValueConversion(v.getFloatValue(), v.getCSSUnit(),
+ float f = NumberValue.floatValueConversion(v.getFloatValue(), v.getUnitType(),
CSSUnit.CSS_DEG);
return new AnimatableAngleOrIdentValue(target, f, SVGAngle.SVG_ANGLETYPE_DEG);
} catch (DOMException e) {
@@ -1842,7 +1842,7 @@ protected AnimatableValue createAnimatableValue(AnimationTarget target, String p
return new AnimatableAngleOrIdentValue(target, v.getIdentifierValue());
}
short unit;
- switch (v.getCSSUnit()) {
+ switch (v.getUnitType()) {
case CSSUnit.CSS_NUMBER:
case CSSUnit.CSS_DEG:
unit = SVGAngle.SVG_ANGLETYPE_DEG;
@@ -1855,7 +1855,7 @@ protected AnimatableValue createAnimatableValue(AnimationTarget target, String p
break;
default:
try {
- float f = NumberValue.floatValueConversion(v.getFloatValue(), v.getCSSUnit(),
+ float f = NumberValue.floatValueConversion(v.getFloatValue(), v.getUnitType(),
CSSUnit.CSS_DEG);
return new AnimatableAngleOrIdentValue(target, f, SVGAngle.SVG_ANGLETYPE_DEG);
} catch (DOMException e) {
diff --git a/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/SVGDescriptiveElementBridge.java b/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/SVGDescriptiveElementBridge.java
index 9a62c56f4..557bb4180 100644
--- a/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/SVGDescriptiveElementBridge.java
+++ b/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/SVGDescriptiveElementBridge.java
@@ -117,12 +117,9 @@ public void handleOtherAnimationChanged(String type) {
// SVGContext implementation ///////////////////////////////////////////
- /**
- * Returns the size of a px CSS unit in millimeters.
- */
@Override
- public float getPixelUnitToMillimeter() {
- return theCtx.getUserAgent().getPixelUnitToMillimeter();
+ public float getResolution() {
+ return theCtx.getUserAgent().getResolution();
}
@Override
diff --git a/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/SVGDocumentBridge.java b/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/SVGDocumentBridge.java
index abb28904b..0e69203db 100644
--- a/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/SVGDocumentBridge.java
+++ b/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/SVGDocumentBridge.java
@@ -203,12 +203,9 @@ public void dispose() {
// SVGContext //////////////////////////////////////////////////////////
- /**
- * Returns the size of a px CSS unit in millimeters.
- */
@Override
- public float getPixelUnitToMillimeter() {
- return ctx.getUserAgent().getPixelUnitToMillimeter();
+ public float getResolution() {
+ return ctx.getUserAgent().getResolution();
}
@Override
diff --git a/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/SVGTextElementBridge.java b/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/SVGTextElementBridge.java
index c4cbd8486..6f1de47a0 100644
--- a/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/SVGTextElementBridge.java
+++ b/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/SVGTextElementBridge.java
@@ -51,6 +51,7 @@
import org.w3c.dom.svg.SVGTextContentElement;
import org.w3c.dom.svg.SVGTextPositioningElement;
+import io.sf.carte.doc.style.css.CSSValue.Type;
import io.sf.carte.doc.style.css.property.NumberValue;
import io.sf.carte.echosvg.anim.dom.AbstractSVGAnimatedLength;
import io.sf.carte.echosvg.anim.dom.AnimatedLiveAttributeValue;
@@ -61,7 +62,6 @@
import io.sf.carte.echosvg.anim.dom.SVGOMTextPositioningElement;
import io.sf.carte.echosvg.bridge.StrokingTextPainter.TextRun;
import io.sf.carte.echosvg.constants.XMLConstants;
-import io.sf.carte.echosvg.css.dom.CSSValue.Type;
import io.sf.carte.echosvg.css.engine.CSSEngineEvent;
import io.sf.carte.echosvg.css.engine.CSSStylableElement;
import io.sf.carte.echosvg.css.engine.SVGCSSEngine;
@@ -1564,7 +1564,7 @@ protected Map getAttributeMap(BridgeContext ctx, Element elem
GVTAttributedCharacterIterator.TextAttribute.ORIENTATION_AUTO);
break;
case NUMERIC:
- switch (val.getCSSUnit()) {
+ switch (val.getUnitType()) {
case CSSUnit.CSS_DEG:
case CSSUnit.CSS_NUMBER:
result.put(GVTAttributedCharacterIterator.TextAttribute.VERTICAL_ORIENTATION,
@@ -1584,8 +1584,8 @@ protected Map getAttributeMap(BridgeContext ctx, Element elem
val.getFloatValue() * 9 / 5);
break;
default:
- if (CSSUnit.isAngleUnitType(val.getCSSUnit())) {
- float f = NumberValue.floatValueConversion(val.getFloatValue(), val.getCSSUnit(), CSSUnit.CSS_DEG);
+ if (CSSUnit.isAngleUnitType(val.getUnitType())) {
+ float f = NumberValue.floatValueConversion(val.getFloatValue(), val.getUnitType(), CSSUnit.CSS_DEG);
result.put(GVTAttributedCharacterIterator.TextAttribute.VERTICAL_ORIENTATION,
GVTAttributedCharacterIterator.TextAttribute.ORIENTATION_ANGLE);
result.put(GVTAttributedCharacterIterator.TextAttribute.VERTICAL_ORIENTATION_ANGLE, f);
@@ -1601,11 +1601,11 @@ protected Map getAttributeMap(BridgeContext ctx, Element elem
// glyph-orientation-horizontal
val = CSSUtilities.getComputedStyle(element, SVGCSSEngine.GLYPH_ORIENTATION_HORIZONTAL_INDEX);
- short unit = val.getCSSUnit();
+ short unit = val.getUnitType();
if (unit == CSSUnit.CSS_NUMBER || unit == CSSUnit.CSS_DEG) {
result.put(GVTAttributedCharacterIterator.TextAttribute.HORIZONTAL_ORIENTATION_ANGLE, val.getFloatValue());
} else if (CSSUnit.isAngleUnitType(unit)) {
- float f = NumberValue.floatValueConversion(val.getFloatValue(), val.getCSSUnit(), CSSUnit.CSS_DEG);
+ float f = NumberValue.floatValueConversion(val.getFloatValue(), val.getUnitType(), CSSUnit.CSS_DEG);
result.put(GVTAttributedCharacterIterator.TextAttribute.HORIZONTAL_ORIENTATION_ANGLE, f);
} else {
throw new IllegalStateException("unexpected value (H):" + val.getCssText());
@@ -1843,12 +1843,9 @@ public SVGTextElementBridge getTextBridge() {
return textBridge;
}
- /**
- * Returns the size of a px CSS unit in millimeters.
- */
@Override
- public float getPixelUnitToMillimeter() {
- return ctx.getUserAgent().getPixelUnitToMillimeter();
+ public float getResolution() {
+ return ctx.getUserAgent().getResolution();
}
/**
diff --git a/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/TextUtilities.java b/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/TextUtilities.java
index 95f0b5e34..7d124ceab 100644
--- a/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/TextUtilities.java
+++ b/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/TextUtilities.java
@@ -25,7 +25,7 @@
import org.w3c.dom.Element;
import org.w3c.dom.Node;
-import io.sf.carte.echosvg.css.dom.CSSValue.Type;
+import io.sf.carte.doc.style.css.CSSValue.Type;
import io.sf.carte.echosvg.css.engine.SVGCSSEngine;
import io.sf.carte.echosvg.css.engine.value.Value;
import io.sf.carte.echosvg.util.CSSConstants;
diff --git a/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/UnitProcessor.java b/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/UnitProcessor.java
index 5d12a1f4e..07bcff3a6 100644
--- a/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/UnitProcessor.java
+++ b/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/UnitProcessor.java
@@ -310,12 +310,9 @@ public Element getElement() {
return e;
}
- /**
- * Returns the size of a px CSS unit in millimeters.
- */
@Override
- public float getPixelUnitToMillimeter() {
- return ctx.getUserAgent().getPixelUnitToMillimeter();
+ public float getResolution() {
+ return ctx.getUserAgent().getResolution();
}
/**
diff --git a/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/UserAgent.java b/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/UserAgent.java
index 2fcd675b0..935a9586e 100644
--- a/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/UserAgent.java
+++ b/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/UserAgent.java
@@ -88,8 +88,13 @@ public interface UserAgent {
/**
* Returns the size of a px CSS unit in millimeters.
+ *
+ * @deprecated Use {@link #getResolution()}.
*/
- float getPixelUnitToMillimeter();
+ @Deprecated
+ default float getPixelUnitToMillimeter() {
+ return 25.4f / getResolution();
+ }
/**
* Returns the size of a px CSS unit in millimeters. This will be removed after
@@ -102,6 +107,11 @@ default float getPixelToMM() {
return getPixelUnitToMillimeter();
}
+ /**
+ * Returns the resolution in {@code dpi}.
+ */
+ float getResolution();
+
/**
* Returns the medium font size.
*/
@@ -183,6 +193,13 @@ default float getPixelToMM() {
*/
String getMedia();
+ /**
+ * Get prefers-color-scheme.
+ */
+ default String getPrefersColorScheme() {
+ return "light";
+ }
+
/**
* Returns this user agent's alternate style-sheet title.
*/
diff --git a/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/UserAgentAdapter.java b/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/UserAgentAdapter.java
index 86d849f3e..f7794bcd8 100644
--- a/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/UserAgentAdapter.java
+++ b/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/UserAgentAdapter.java
@@ -137,6 +137,14 @@ public float getPixelUnitToMillimeter() {
return 0.26458333333333333333333333333333f; // 96dpi
}
+ /**
+ * Returns the resolution in {@code dpi}.
+ */
+ @Override
+ public float getResolution() {
+ return 96f;
+ }
+
/**
* Returns the default font family.
*/
@@ -151,7 +159,7 @@ public String getDefaultFontFamily() {
@Override
public float getMediumFontSize() {
// 9pt (72pt = 1in)
- return 9f * 25.4f / (72f * getPixelUnitToMillimeter());
+ return 9f * getResolution() / 72f;
}
/**
diff --git a/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/ViewBox.java b/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/ViewBox.java
index c5cbdb595..ab2764ca4 100644
--- a/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/ViewBox.java
+++ b/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/ViewBox.java
@@ -20,6 +20,7 @@
import java.awt.geom.AffineTransform;
+import org.w3c.css.om.unit.CSSUnit;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
@@ -28,12 +29,11 @@
import org.w3c.dom.svg.SVGAnimatedRect;
import org.w3c.dom.svg.SVGPreserveAspectRatio;
-import io.sf.carte.doc.style.css.CSSUnit;
+import io.sf.carte.doc.style.css.CSSExpressionValue;
+import io.sf.carte.doc.style.css.CSSTypedValue;
import io.sf.carte.doc.style.css.CSSValue.CssType;
import io.sf.carte.doc.style.css.property.Evaluator;
-import io.sf.carte.doc.style.css.property.ExpressionValue;
import io.sf.carte.doc.style.css.property.StyleValue;
-import io.sf.carte.doc.style.css.property.TypedValue;
import io.sf.carte.doc.style.css.property.ValueFactory;
import io.sf.carte.doc.style.css.property.ValueList;
import io.sf.carte.echosvg.anim.dom.SVGOMAnimatedRect;
@@ -400,17 +400,17 @@ static boolean computeRectangle(StyleValue value, float[] numbers) throws DOMExc
if (item.getCssValueType() != CssType.TYPED) {
return false;
}
- TypedValue typed;
+ CSSTypedValue typed;
switch (item.getPrimitiveType()) {
case NUMERIC:
- typed = (TypedValue) item;
+ typed = (CSSTypedValue) item;
if (typed.getUnitType() != CSSUnit.CSS_NUMBER) {
return false;
}
break;
case EXPRESSION:
- Evaluator eval = new Evaluator();
- typed = eval.evaluateExpression((ExpressionValue) item);
+ Evaluator eval = new Evaluator(CSSUnit.CSS_NUMBER);
+ typed = eval.evaluateExpression((CSSExpressionValue) item);
if (typed.getUnitType() != CSSUnit.CSS_NUMBER) {
return false;
}
diff --git a/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/svg12/SVGFlowRootElementBridge.java b/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/svg12/SVGFlowRootElementBridge.java
index ee8b02643..8a6061dda 100644
--- a/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/svg12/SVGFlowRootElementBridge.java
+++ b/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/svg12/SVGFlowRootElementBridge.java
@@ -40,6 +40,8 @@
import org.w3c.dom.events.Event;
import org.w3c.dom.events.EventListener;
+import io.sf.carte.doc.style.css.CSSValue;
+import io.sf.carte.doc.style.css.CSSValue.Type;
import io.sf.carte.echosvg.anim.dom.SVGOMElement;
import io.sf.carte.echosvg.anim.dom.SVGOMFlowRegionElement;
import io.sf.carte.echosvg.anim.dom.XBLEventSupport;
@@ -56,12 +58,10 @@
import io.sf.carte.echosvg.bridge.TextUtilities;
import io.sf.carte.echosvg.bridge.UserAgent;
import io.sf.carte.echosvg.constants.XMLConstants;
-import io.sf.carte.echosvg.css.dom.CSSValue.Type;
import io.sf.carte.echosvg.css.engine.CSSEngine;
import io.sf.carte.echosvg.css.engine.SVGCSSEngine;
import io.sf.carte.echosvg.css.engine.value.ComputedValue;
import io.sf.carte.echosvg.css.engine.value.Value;
-import io.sf.carte.echosvg.css.engine.value.ValueConstants;
import io.sf.carte.echosvg.css.engine.value.svg12.LineHeightValue;
import io.sf.carte.echosvg.css.engine.value.svg12.SVG12ValueConstants;
import io.sf.carte.echosvg.dom.AbstractNode;
@@ -849,7 +849,8 @@ public BlockInfo makeBlockInfo(BridgeContext ctx, Element element) {
float indent = v.getFloatValue();
v = CSSUtilities.getComputedStyle(element, textAlignIndex);
- if (v == ValueConstants.INHERIT_VALUE) {
+ if (v.getCssValueType() == CSSValue.CssType.KEYWORD) {
+ // inherit, unset, revert
v = CSSUtilities.getComputedStyle(element, SVGCSSEngine.DIRECTION_INDEX);
if (v.isIdentifier(CSSConstants.CSS_LTR_VALUE))
v = SVG12ValueConstants.START_VALUE;
@@ -888,7 +889,7 @@ protected float getLineHeight(BridgeContext ctx, Element element, float fontSize
initCSSPropertyIndexes(element);
Value v = CSSUtilities.getComputedStyle(element, lineHeightIndex);
- if (v == ValueConstants.INHERIT_VALUE || v.isIdentifier(CSSConstants.CSS_NORMAL_VALUE)) {
+ if (v.getCssValueType() == CSSValue.CssType.KEYWORD || v.isIdentifier(CSSConstants.CSS_NORMAL_VALUE)) {
return fontSize * 1.1f;
}
diff --git a/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/svg12/SVGSolidColorElementBridge.java b/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/svg12/SVGSolidColorElementBridge.java
index 084bbcd5f..8609bff08 100644
--- a/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/svg12/SVGSolidColorElementBridge.java
+++ b/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/svg12/SVGSolidColorElementBridge.java
@@ -25,6 +25,7 @@
import org.w3c.dom.Element;
+import io.sf.carte.doc.style.css.CSSValue.CssType;
import io.sf.carte.echosvg.anim.dom.SVGOMDocument;
import io.sf.carte.echosvg.bridge.AnimatableGenericSVGBridge;
import io.sf.carte.echosvg.bridge.BridgeContext;
@@ -33,7 +34,6 @@
import io.sf.carte.echosvg.bridge.ErrorConstants;
import io.sf.carte.echosvg.bridge.PaintBridge;
import io.sf.carte.echosvg.bridge.PaintServer;
-import io.sf.carte.echosvg.css.dom.CSSValue.CssType;
import io.sf.carte.echosvg.css.engine.CSSEngine;
import io.sf.carte.echosvg.css.engine.CSSStylableElement;
import io.sf.carte.echosvg.css.engine.StyleMap;
diff --git a/echosvg-bridge/src/test/java/io/sf/carte/echosvg/bridge/ModificationsTest.java b/echosvg-bridge/src/test/java/io/sf/carte/echosvg/bridge/ModificationsTest.java
index 07098ad0e..2a59b32af 100644
--- a/echosvg-bridge/src/test/java/io/sf/carte/echosvg/bridge/ModificationsTest.java
+++ b/echosvg-bridge/src/test/java/io/sf/carte/echosvg/bridge/ModificationsTest.java
@@ -36,11 +36,11 @@
import org.w3c.dom.view.ViewCSS;
import org.w3c.dom.views.DocumentView;
+import io.sf.carte.doc.style.css.CSSValue.CssType;
import io.sf.carte.echosvg.anim.dom.SVGDOMImplementation;
import io.sf.carte.echosvg.anim.dom.SVGStylableElement;
import io.sf.carte.echosvg.constants.XMLConstants;
-import io.sf.carte.echosvg.css.dom.CSSValue;
-import io.sf.carte.echosvg.css.dom.CSSValue.CssType;
+import io.sf.carte.echosvg.css.engine.value.CSSVal;
import io.sf.carte.echosvg.gvt.GraphicsNode;
import io.sf.carte.echosvg.util.CSSConstants;
import io.sf.carte.echosvg.util.SVGConstants;
@@ -74,7 +74,7 @@ static CSSStyleValue updateValue(String ptyName, String ptyValue, String newValu
ViewCSS view = (ViewCSS) ((DocumentView) doc).getDefaultView();
CSSStyleDeclaration cs = view.getComputedStyle(rect, null);
- CSSValue val = (CSSValue) cs.getCSSStyleValue(ptyName);
+ CSSVal val = (CSSVal) cs.getCSSStyleValue(ptyName);
assertNotNull(val);
assertEquals(CssType.TYPED, val.getCssValueType());
diff --git a/echosvg-bridge/src/test/java/io/sf/carte/echosvg/bridge/PaintServerTest.java b/echosvg-bridge/src/test/java/io/sf/carte/echosvg/bridge/PaintServerTest.java
index 30de55976..1cb4fbcad 100644
--- a/echosvg-bridge/src/test/java/io/sf/carte/echosvg/bridge/PaintServerTest.java
+++ b/echosvg-bridge/src/test/java/io/sf/carte/echosvg/bridge/PaintServerTest.java
@@ -38,9 +38,9 @@
import org.w3c.dom.svg.SVGDocument;
import org.w3c.dom.svg.SVGSVGElement;
+import io.sf.carte.doc.style.css.CSSValue.Type;
import io.sf.carte.echosvg.anim.dom.SVGDOMImplementation;
import io.sf.carte.echosvg.constants.XMLConstants;
-import io.sf.carte.echosvg.css.dom.CSSValue.Type;
import io.sf.carte.echosvg.css.engine.CSSEngine;
import io.sf.carte.echosvg.css.engine.CSSStylableElement;
import io.sf.carte.echosvg.css.engine.value.ColorValue;
@@ -323,6 +323,35 @@ public void testConvertLCh() {
assertSame(StandardColorSpaces.getRec2020(), context.getColorSpace());
}
+ @Test
+ public void testConvertLCh_sRGB() {
+ Color color = convertPaint(CSSConstants.CSS_FILL_PROPERTY, "lch(48% 77 33)", null);
+ assertNotNull(color);
+ float[] comp = new float[3];
+ color.getColorComponents(comp);
+ assertEquals(0.835736f, comp[0], 1e-5f); // sRGB
+ assertEquals(0.17189053f, comp[1], 1e-5f); // sRGB
+ assertEquals(0.18918473f, comp[2], 1e-5f); // sRGB
+ assertEquals(255, color.getAlpha());
+
+ assertNull(context.getColorSpace());
+ }
+
+ @Test
+ public void testConvertLCh_var() {
+ Color color = convertPaint(CSSConstants.CSS_FILL_PROPERTY, "var(--color);--color:lch(48% 77 33)",
+ null);
+ assertNotNull(color);
+ float[] comp = new float[3];
+ color.getColorComponents(comp);
+ assertEquals(0.835736f, comp[0], 1e-5f); // sRGB
+ assertEquals(0.17189053f, comp[1], 1e-5f); // sRGB
+ assertEquals(0.18918473f, comp[2], 1e-5f); // sRGB
+ assertEquals(255, color.getAlpha());
+
+ assertNull(context.getColorSpace());
+ }
+
@Test
public void testConvertLCh_99Pcnt() {
Color color = convertPaint(CSSConstants.CSS_FILL_PROPERTY, "lch(99% 110 60)", null);
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/CSSSecurityException.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/CSSSecurityException.java
new file mode 100644
index 000000000..22cfcefc1
--- /dev/null
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/CSSSecurityException.java
@@ -0,0 +1,65 @@
+/*
+
+ See the NOTICE file distributed with this work for additional
+ information regarding copyright ownership.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ */
+package io.sf.carte.echosvg.css;
+
+/**
+ * A CSS-related security exception.
+ */
+public class CSSSecurityException extends SecurityException {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Constructs a {@code CSSSecurityException} with no detail message.
+ */
+ public CSSSecurityException() {
+ super();
+ }
+
+ /**
+ * Creates a {@code CSSSecurityException} with the specified cause and a detail
+ * message which typically contains the class and detail message of cause.
+ *
+ * @param cause the cause.
+ */
+ public CSSSecurityException(Throwable cause) {
+ super(cause);
+ }
+
+ /**
+ * Constructs a {@code CSSSecurityException} with a detail message.
+ *
+ * @param message the message.
+ */
+ public CSSSecurityException(String message) {
+ super(message);
+ }
+
+ /**
+ * Creates a {@code CSSSecurityException} with the specified detail message and
+ * cause.
+ *
+ * @param message the message.
+ * @param cause the cause.
+ */
+ public CSSSecurityException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+}
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/dom/CSSOMComputedStyle.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/dom/CSSOMComputedStyle.java
index 4cfa82f2c..e7a7986e4 100644
--- a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/dom/CSSOMComputedStyle.java
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/dom/CSSOMComputedStyle.java
@@ -27,6 +27,7 @@
import io.sf.carte.echosvg.css.engine.CSSEngine;
import io.sf.carte.echosvg.css.engine.CSSStylableElement;
+import io.sf.carte.echosvg.css.engine.value.CSSVal;
import io.sf.carte.echosvg.css.engine.value.Value;
/**
@@ -58,7 +59,7 @@ public class CSSOMComputedStyle implements CSSStyleDeclaration {
/**
* The CSS values.
*/
- protected Map values = new HashMap<>();
+ protected Map values = new HashMap<>();
/**
* Creates a new computed style.
@@ -110,12 +111,12 @@ public String getPropertyValue(String propertyName) {
}
@Override
- public CSSValue getCSSStyleValue(String propertyName) {
+ public CSSVal getCSSStyleValue(String propertyName) {
return getCSSValue(propertyName);
}
- public CSSValue getCSSValue(String propertyName) {
- CSSValue result = values.get(propertyName);
+ public CSSVal getCSSValue(String propertyName) {
+ CSSVal result = values.get(propertyName);
if (result == null) {
int idx = cssEngine.getPropertyIndex(propertyName);
if (idx != -1) {
@@ -187,7 +188,7 @@ public CSSRule getParentRule() {
/**
* Creates a CSSValue to manage the value at the given index.
*/
- protected CSSValue createCSSValue(int idx) {
+ protected CSSVal createCSSValue(int idx) {
return new ComputedCSSValue(idx);
}
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/dom/CSSOMSVGColor.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/dom/CSSOMSVGColor.java
index 63c91db66..4781d274d 100644
--- a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/dom/CSSOMSVGColor.java
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/dom/CSSOMSVGColor.java
@@ -26,6 +26,7 @@
import org.w3c.dom.svg.SVGNumber;
import org.w3c.dom.svg.SVGNumberList;
+import io.sf.carte.echosvg.css.engine.value.CSSVal;
import io.sf.carte.echosvg.css.engine.value.ColorFunction;
import io.sf.carte.echosvg.css.engine.value.ColorValue;
import io.sf.carte.echosvg.css.engine.value.NumericValue;
@@ -44,7 +45,7 @@
* @version $Id$
*/
@SuppressWarnings("removal")
-public class CSSOMSVGColor implements CSSValue, CSSColorValue, SVGICCColor, SVGNumberList {
+public class CSSOMSVGColor implements CSSVal, CSSColorValue, SVGICCColor, SVGNumberList {
/**
* The associated value.
@@ -126,6 +127,11 @@ public String getURIValue() throws DOMException {
return valueProvider.getValue().getURIValue();
}
+ @Override
+ public Value clone() {
+ return valueProvider.getValue().clone();
+ }
+
/**
* DOM: Implements {@link org.w3c.dom.svg.SVGColor#getColorType()}.
*/
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/dom/CSSOMSVGComputedStyle.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/dom/CSSOMSVGComputedStyle.java
index 1dd5ee7de..1b7c923c6 100644
--- a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/dom/CSSOMSVGComputedStyle.java
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/dom/CSSOMSVGComputedStyle.java
@@ -21,6 +21,7 @@
import io.sf.carte.echosvg.css.engine.CSSEngine;
import io.sf.carte.echosvg.css.engine.CSSStylableElement;
import io.sf.carte.echosvg.css.engine.SVGCSSEngine;
+import io.sf.carte.echosvg.css.engine.value.CSSVal;
import io.sf.carte.echosvg.css.engine.value.Value;
import io.sf.carte.echosvg.css.engine.value.svg.SVGColorManager;
import io.sf.carte.echosvg.css.engine.value.svg.SVGPaintManager;
@@ -45,7 +46,7 @@ public CSSOMSVGComputedStyle(CSSEngine e, CSSStylableElement elt, String pseudoE
* Creates a CSSValue to manage the value at the given index.
*/
@Override
- protected CSSValue createCSSValue(int idx) {
+ protected CSSVal createCSSValue(int idx) {
if (idx > SVGCSSEngine.FINAL_INDEX) {
if (cssEngine.getValueManagers()[idx] instanceof SVGPaintManager) {
return new ComputedCSSPaintValue(idx);
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/dom/CSSOMSVGStyleDeclaration.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/dom/CSSOMSVGStyleDeclaration.java
index d942e17e5..0baf3163b 100644
--- a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/dom/CSSOMSVGStyleDeclaration.java
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/dom/CSSOMSVGStyleDeclaration.java
@@ -24,6 +24,7 @@
import io.sf.carte.echosvg.css.engine.CSSEngine;
import io.sf.carte.echosvg.css.engine.SVGCSSEngine;
import io.sf.carte.echosvg.css.engine.value.AbstractValueModificationHandler;
+import io.sf.carte.echosvg.css.engine.value.CSSVal;
import io.sf.carte.echosvg.css.engine.value.Value;
import io.sf.carte.echosvg.css.engine.value.svg.SVGColorManager;
import io.sf.carte.echosvg.css.engine.value.svg.SVGPaintManager;
@@ -56,7 +57,7 @@ public CSSOMSVGStyleDeclaration(ValueProvider vp, CSSRule parent, CSSEngine eng)
* Creates the CSS value associated with the given property.
*/
@Override
- protected CSSValue createCSSValue(String name) {
+ protected CSSVal createCSSValue(String name) {
int idx = cssEngine.getPropertyIndex(name);
if (idx > SVGCSSEngine.FINAL_INDEX) {
if (cssEngine.getValueManagers()[idx] instanceof SVGPaintManager) {
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/dom/CSSOMStyleDeclaration.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/dom/CSSOMStyleDeclaration.java
index 1ed9456d5..c299c4be7 100644
--- a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/dom/CSSOMStyleDeclaration.java
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/dom/CSSOMStyleDeclaration.java
@@ -26,6 +26,7 @@
import org.w3c.dom.DOMException;
import io.sf.carte.echosvg.css.engine.value.AbstractValueModificationHandler;
+import io.sf.carte.echosvg.css.engine.value.CSSVal;
import io.sf.carte.echosvg.css.engine.value.Value;
/**
@@ -57,7 +58,7 @@ public class CSSOMStyleDeclaration implements CSSStyleDeclaration {
/**
* The values.
*/
- protected Map values;
+ protected Map values;
/**
* Creates a new style declaration.
@@ -99,7 +100,7 @@ public String getPropertyValue(String propertyName) {
}
@Override
- public CSSValue getCSSStyleValue(String propertyName) {
+ public CSSVal getCSSStyleValue(String propertyName) {
Value value = valueProvider.getValue(propertyName);
if (value == null) {
return null;
@@ -158,8 +159,8 @@ public CSSRule getParentRule() {
/**
* Gets the CSS value associated with the given property.
*/
- protected CSSValue getCSSValue(String name) {
- CSSValue result = null;
+ protected CSSVal getCSSValue(String name) {
+ CSSVal result = null;
if (values != null) {
result = values.get(name);
}
@@ -176,7 +177,7 @@ protected CSSValue getCSSValue(String name) {
/**
* Creates the CSS value associated with the given property.
*/
- protected CSSValue createCSSValue(String name) {
+ protected CSSVal createCSSValue(String name) {
return new StyleDeclarationValue(name);
}
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/dom/CSSOMValue.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/dom/CSSOMValue.java
index fe3109d44..ec7193bfe 100644
--- a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/dom/CSSOMValue.java
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/dom/CSSOMValue.java
@@ -109,7 +109,7 @@ public float getFloatValue() throws DOMException {
* Converts the actual float value to the given unit type.
*/
public static float convertFloatValue(short unitType, Value value) {
- if (value.getCSSUnit() == unitType) {
+ if (value.getUnitType() == unitType) {
return value.getFloatValue();
}
switch (unitType) {
@@ -153,7 +153,7 @@ public static float convertFloatValue(short unitType, Value value) {
case CSSUnit.CSS_KHZ:
return tokHertz(value);
default:
- return NumberValue.floatValueConversion(value.getFloatValue(), value.getCSSUnit(),
+ return NumberValue.floatValueConversion(value.getFloatValue(), value.getUnitType(),
unitType);
}
throw new DOMException(DOMException.INVALID_ACCESS_ERR, "");
@@ -163,7 +163,7 @@ public static float convertFloatValue(short unitType, Value value) {
* Converts the current value into centimeters.
*/
protected static float toCentimeters(Value value) {
- switch (value.getCSSUnit()) {
+ switch (value.getUnitType()) {
case CSSUnit.CSS_CM:
return value.getFloatValue();
case CSSUnit.CSS_MM:
@@ -183,7 +183,7 @@ protected static float toCentimeters(Value value) {
* Converts the current value into inches.
*/
protected static float toInches(Value value) {
- switch (value.getCSSUnit()) {
+ switch (value.getUnitType()) {
case CSSUnit.CSS_CM:
return (value.getFloatValue() / 2.54f);
case CSSUnit.CSS_MM:
@@ -203,7 +203,7 @@ protected static float toInches(Value value) {
* Converts the current value into millimeters.
*/
protected static float toMillimeters(Value value) {
- switch (value.getCSSUnit()) {
+ switch (value.getUnitType()) {
case CSSUnit.CSS_CM:
return (value.getFloatValue() * 10);
case CSSUnit.CSS_MM:
@@ -223,7 +223,7 @@ protected static float toMillimeters(Value value) {
* Converts the current value into points.
*/
protected static float toPoints(Value value) {
- switch (value.getCSSUnit()) {
+ switch (value.getUnitType()) {
case CSSUnit.CSS_CM:
return (value.getFloatValue() * 72 / 2.54f);
case CSSUnit.CSS_MM:
@@ -243,7 +243,7 @@ protected static float toPoints(Value value) {
* Converts the current value into picas.
*/
protected static float toPicas(Value value) {
- switch (value.getCSSUnit()) {
+ switch (value.getUnitType()) {
case CSSUnit.CSS_CM:
return (value.getFloatValue() * 6 / 2.54f);
case CSSUnit.CSS_MM:
@@ -263,7 +263,7 @@ protected static float toPicas(Value value) {
* Converts the current value into degrees.
*/
protected static float toDegrees(Value value) {
- switch (value.getCSSUnit()) {
+ switch (value.getUnitType()) {
case CSSUnit.CSS_DEG:
return value.getFloatValue();
case CSSUnit.CSS_RAD:
@@ -279,7 +279,7 @@ protected static float toDegrees(Value value) {
* Converts the current value into radians.
*/
protected static float toRadians(Value value) {
- switch (value.getCSSUnit()) {
+ switch (value.getUnitType()) {
case CSSUnit.CSS_DEG:
return (value.getFloatValue() * 5 / 9); // todo ??
case CSSUnit.CSS_RAD:
@@ -295,7 +295,7 @@ protected static float toRadians(Value value) {
* Converts the current value into gradians.
*/
protected static float toGradians(Value value) {
- switch (value.getCSSUnit()) {
+ switch (value.getUnitType()) {
case CSSUnit.CSS_DEG:
return (float) (value.getFloatValue() * Math.PI / 180); // todo ????
case CSSUnit.CSS_RAD:
@@ -311,7 +311,7 @@ protected static float toGradians(Value value) {
* Converts the current value into milliseconds.
*/
protected static float toMilliseconds(Value value) {
- switch (value.getCSSUnit()) {
+ switch (value.getUnitType()) {
case CSSUnit.CSS_MS:
return value.getFloatValue();
case CSSUnit.CSS_S:
@@ -325,7 +325,7 @@ protected static float toMilliseconds(Value value) {
* Converts the current value into seconds.
*/
protected static float toSeconds(Value value) {
- switch (value.getCSSUnit()) {
+ switch (value.getUnitType()) {
case CSSUnit.CSS_MS:
return (value.getFloatValue() / 1000);
case CSSUnit.CSS_S:
@@ -339,7 +339,7 @@ protected static float toSeconds(Value value) {
* Converts the current value into Hertz.
*/
protected static float toHertz(Value value) {
- switch (value.getCSSUnit()) {
+ switch (value.getUnitType()) {
case CSSUnit.CSS_HZ:
return value.getFloatValue();
case CSSUnit.CSS_KHZ:
@@ -353,7 +353,7 @@ protected static float toHertz(Value value) {
* Converts the current value into kHertz.
*/
protected static float tokHertz(Value value) {
- switch (value.getCSSUnit()) {
+ switch (value.getUnitType()) {
case CSSUnit.CSS_HZ:
return (value.getFloatValue() * 1000);
case CSSUnit.CSS_KHZ:
@@ -369,8 +369,8 @@ public String getIdentifierValue() throws DOMException {
}
@Override
- public short getCSSUnit() {
- return valueProvider.getValue().getCSSUnit();
+ public short getUnitType() {
+ return valueProvider.getValue().getUnitType();
}
@Override
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/dom/CSSValue.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/dom/CSSValue.java
deleted file mode 100644
index c7471969b..000000000
--- a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/dom/CSSValue.java
+++ /dev/null
@@ -1,358 +0,0 @@
-/*
-
- See the NOTICE file distributed with this work for additional
- information regarding copyright ownership.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- */
-package io.sf.carte.echosvg.css.dom;
-
-import org.w3c.css.om.typed.CSSKeywordValue;
-import org.w3c.css.om.typed.CSSStringValue;
-import org.w3c.css.om.typed.CSSStyleValue;
-import org.w3c.css.om.unit.CSSUnit;
-import org.w3c.dom.DOMException;
-
-import io.sf.carte.doc.style.css.property.KeywordValue;
-import io.sf.carte.echosvg.css.engine.value.ListValue;
-import io.sf.carte.echosvg.css.engine.value.NumericValue;
-import io.sf.carte.echosvg.css.engine.value.StringValue;
-
-/**
- * A gateway value, useful in the transition to Typed OM.
- *
- * @author See Git history.
- * @version $Id$
- */
-public interface CSSValue extends CSSStyleValue {
-
- /**
- * The main categories of values.
- */
- enum CssType {
-
- /**
- * A CSS-wide keyword like {@code inherit}.
- */
- KEYWORD,
-
- /**
- *
- * A vehicle towards a final value, of a CSS type that cannot be anticipated.
- *
- *
- * Example: {@code var()} or {@code attr()}.
- *
- *
- * (note that {@code attr()} has two components, a main one whose type
- * could be anticipated, and a fallback that could be of a different type).
- *
- */
- PROXY,
-
- /**
- * A typed primitive value, includes numbers and identifiers.
- */
- TYPED,
-
- /**
- * A list of values.
- *
- * You can cast to {@link ListValue}.
- *
- */
- LIST,
-
- /**
- * A shorthand property.
- */
- SHORTHAND
- }
-
- /**
- * The type of value. For keywords, it is the keyword.
- */
- enum Type {
- /**
- * Unknown type, probably a system default or a compat value.
- */
- UNKNOWN,
-
- /**
- * {@code inherit} keyword.
- */
- INHERIT,
-
- /**
- * {@code initial} keyword.
- */
- INITIAL,
-
- /**
- * {@code unset} keyword.
- */
- UNSET,
-
- /**
- * {@code revert} keyword.
- */
- REVERT,
-
- /**
- * Numeric type (excludes {@code calc()} which is an {@link #EXPRESSION}).
- *
- * The value is either a list or a shorthand.
- *
- */
- INVALID
-
- }
-
- /**
- * Get the general category to which this value belongs.
- *
- * @return the general value type.
- */
- CssType getCssValueType();
-
- /**
- * Get the primitive type.
- *
- * @return the primitive type.
- */
- Type getPrimitiveType();
-
- /**
- * Gets the css unit as in CSS4J's {@code CSSUnit}.
- *
- * If the value has no valid CSS unit, returns {@code CSSUnit.CSS_INVALID}.
- *
- *
- * @return the css unit as in CSS4J's {@code CSSUnit}.
- */
- default short getCSSUnit() {
- return CSSUnit.CSS_INVALID;
- }
-
- /**
- * Set this value to the result of parsing the argument.
- *
- * @param cssText a CSS serialization to set this value.
- * @throws DOMException
- */
- void setCssText(String cssText) throws DOMException;
-
- /**
- * Get a parsable representation of this value.
- *
- * @return the CSS serialization of this value.
- */
- String getCssText();
-
- /**
- * Convenience method that either returns the float value, if the value is
- * numeric, or throws an exception.
- *
- * @return the float value.
- */
- float getFloatValue();
-
- /**
- * Convenience method that either returns an identifier or throws an exception.
- *
- * @exception DOMException INVALID_ACCESS_ERR: Raised if the value doesn't
- * contain an identifier value.
- */
- String getIdentifierValue() throws DOMException;
-
- /**
- * If this value can be used where a string is expected, get the value.
- *
- * @return the string value, without the commas.
- * @exception DOMException INVALID_ACCESS_ERR: Raised if the value doesn't
- * contain a String.
- */
- String getStringValue() throws DOMException;
-
- /**
- * Convenience method that either returns a String or URI or throws an exception.
- *
- * @exception DOMException INVALID_ACCESS_ERR: Raised if the value doesn't
- * contain a String nor a URI value.
- */
- String getURIValue() throws DOMException;
-
- /**
- * If this value is a list or contains components, the number of
- * CSSStyleValues in the list. The range of valid values of the
- * indices is 0 to length-1 inclusive.
- *
- * @return the number of components, or {@code 0} if this value is not a list
- * nor does it contain components.
- */
- int getLength();
-
- /**
- * If this value is a list, give the item corresponding to the requested index.
- * If there is no item at such index, return {@code null} If this object is not
- * a list and the index is {@code 0}, return itself.
- *
- * @param index the index on the list.
- * @return the item, or {@code null} if there is no item on that index.
- */
- default CSSValue item(int index) {
- return index == 0 ? this : null;
- }
-
-}
diff --git a/test-resources/io/sf/carte/echosvg/transcoder/image/resources/px2mm.svg b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/CSSCircularityException.java
similarity index 62%
rename from test-resources/io/sf/carte/echosvg/transcoder/image/resources/px2mm.svg
rename to echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/CSSCircularityException.java
index c4b0deb5b..0ed6b2e46 100644
--- a/test-resources/io/sf/carte/echosvg/transcoder/image/resources/px2mm.svg
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/CSSCircularityException.java
@@ -1,7 +1,5 @@
-
-
+/*
-
-
+ private static final long serialVersionUID = 1L;
+
+ public CSSCircularityException(String message) {
+ super(message);
+ }
+
+}
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/CSSContext.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/CSSContext.java
index e423b7561..2e41fc98d 100644
--- a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/CSSContext.java
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/CSSContext.java
@@ -58,8 +58,13 @@ public interface CSSContext {
/**
* Returns the size of a px CSS unit in millimeters.
+ *
+ * @deprecated Use {@link #getResolution()}.
*/
- float getPixelUnitToMillimeter();
+ @Deprecated
+ default float getPixelUnitToMillimeter() {
+ return 25.4f / getResolution();
+ }
/**
* Returns the size of a px CSS unit in millimeters. This will be removed after
@@ -72,6 +77,11 @@ default float getPixelToMillimeter() {
return getPixelUnitToMillimeter();
}
+ /**
+ * Returns the resolution in dpi.
+ */
+ float getResolution();
+
/**
* Returns the medium font size.
*/
@@ -105,6 +115,11 @@ default float getPixelToMillimeter() {
*/
void checkLoadExternalResource(ParsedURL resourceURL, ParsedURL docURL) throws SecurityException;
+ /**
+ * Get prefers-color-scheme.
+ */
+ String getPrefersColorScheme();
+
/**
* Returns true if the document is dynamic, false otherwise.
*/
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/CSSEngine.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/CSSEngine.java
index bba9949bd..41568bcfe 100644
--- a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/CSSEngine.java
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/CSSEngine.java
@@ -18,13 +18,19 @@
*/
package io.sf.carte.echosvg.css.engine;
+import java.awt.GraphicsEnvironment;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
+import java.util.HashMap;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
+import java.util.Locale;
+import java.util.Map;
import java.util.Set;
import org.w3c.dom.Attr;
@@ -39,24 +45,53 @@
import org.w3c.dom.events.MutationEvent;
import io.sf.carte.doc.style.css.BooleanCondition;
+import io.sf.carte.doc.style.css.CSSCanvas;
+import io.sf.carte.doc.style.css.CSSDocument;
import io.sf.carte.doc.style.css.CSSRule;
+import io.sf.carte.doc.style.css.CSSTypedValue;
+import io.sf.carte.doc.style.css.CSSUnit;
+import io.sf.carte.doc.style.css.CSSValue;
+import io.sf.carte.doc.style.css.CSSValue.Type;
+import io.sf.carte.doc.style.css.CSSValueSyntax;
+import io.sf.carte.doc.style.css.CSSValueSyntax.Match;
import io.sf.carte.doc.style.css.MediaQueryList;
import io.sf.carte.doc.style.css.SelectorMatcher;
+import io.sf.carte.doc.style.css.StyleDatabase;
+import io.sf.carte.doc.style.css.UnitStringToId;
+import io.sf.carte.doc.style.css.nsac.ArgumentCondition;
import io.sf.carte.doc.style.css.nsac.AttributeCondition;
+import io.sf.carte.doc.style.css.nsac.CSSBudgetException;
import io.sf.carte.doc.style.css.nsac.CSSHandler;
+import io.sf.carte.doc.style.css.nsac.CSSParseException;
+import io.sf.carte.doc.style.css.nsac.CombinatorCondition;
+import io.sf.carte.doc.style.css.nsac.CombinatorSelector;
import io.sf.carte.doc.style.css.nsac.Condition;
+import io.sf.carte.doc.style.css.nsac.ConditionalSelector;
+import io.sf.carte.doc.style.css.nsac.DeclarationCondition;
import io.sf.carte.doc.style.css.nsac.InputSource;
import io.sf.carte.doc.style.css.nsac.LexicalUnit;
+import io.sf.carte.doc.style.css.nsac.LexicalUnit.LexicalType;
import io.sf.carte.doc.style.css.nsac.PageSelectorList;
import io.sf.carte.doc.style.css.nsac.Parser;
import io.sf.carte.doc.style.css.nsac.ParserControl;
import io.sf.carte.doc.style.css.nsac.Selector;
+import io.sf.carte.doc.style.css.nsac.SelectorFunction;
import io.sf.carte.doc.style.css.nsac.SelectorList;
+import io.sf.carte.doc.style.css.om.AbstractCSSCanvas;
+import io.sf.carte.doc.style.css.om.AbstractStyleDatabase;
+import io.sf.carte.doc.style.css.om.CSSOMParser;
import io.sf.carte.doc.style.css.om.Specificity;
import io.sf.carte.doc.style.css.parser.AttributeConditionVisitor;
-import io.sf.carte.doc.style.css.parser.CSSParser;
+import io.sf.carte.doc.style.css.parser.ParseHelper;
+import io.sf.carte.doc.style.css.parser.SyntaxParser;
+import io.sf.carte.doc.style.css.property.ValueFactory;
+import io.sf.carte.echosvg.css.CSSSecurityException;
+import io.sf.carte.echosvg.css.engine.value.CSSProxyValueException;
import io.sf.carte.echosvg.css.engine.value.ComputedValue;
import io.sf.carte.echosvg.css.engine.value.InheritValue;
+import io.sf.carte.echosvg.css.engine.value.LexicalValue;
+import io.sf.carte.echosvg.css.engine.value.PendingValue;
+import io.sf.carte.echosvg.css.engine.value.PropertyDefinition;
import io.sf.carte.echosvg.css.engine.value.ShorthandManager;
import io.sf.carte.echosvg.css.engine.value.Value;
import io.sf.carte.echosvg.css.engine.value.ValueManager;
@@ -66,8 +101,10 @@
/**
* This is the base class for all the CSS engines.
*
- * @author Stephane Hillion
- * @author For later modifications, see Git history.
+ *
+ * Original author: Stephane Hillion.
+ * For later modifications, see Git history.
+ *
* @version $Id$
*/
public abstract class CSSEngine {
@@ -136,6 +173,10 @@ public static CSSStylableElement getParentCSSStylableElement(Element elt) {
*/
protected CSSContext cssContext;
+ private EngineStyleDatabase styleDb;
+
+ private CSSCanvas csscanvas;
+
/**
* The associated document.
*/
@@ -209,7 +250,7 @@ public static CSSStylableElement getParentCSSStylableElement(Element elt) {
/**
* The media to use to cascade properties.
*/
- protected MediaQueryList media;
+ private String medium;
/**
* The DOM nodes which contains StyleSheets.
@@ -338,6 +379,13 @@ public static CSSStylableElement getParentCSSStylableElement(Element elt) {
*/
protected Set selectorAttributes;
+ /**
+ * The map from custom property names to their definitions.
+ */
+ private HashMap propertyDefinitionMap = null;
+
+ private static final int INITIAL_CUSTOM_PTY_SET_SIZE = 1; // Initial set is never used
+
/**
* Used to fire a change event for all the properties.
*/
@@ -374,6 +422,8 @@ protected CSSEngine(Document doc, ParsedURL uri, Parser p, ValueManager[] vm, Sh
classNamespaceURI = cns;
classLocalName = cln;
cssContext = ctx;
+ styleDb = new EngineStyleDatabase();
+ csscanvas = new EngineCSSCanvas();
isCSSNavigableDocument = doc instanceof CSSNavigableDocument;
@@ -429,6 +479,177 @@ protected CSSEngine(Document doc, ParsedURL uri, Parser p, ValueManager[] vm, Sh
}
}
+ private class EngineStyleDatabase extends AbstractStyleDatabase {
+
+ private static final long serialVersionUID = 1L;
+
+ private final List fonts = getAvailableFontList();
+
+ private List getAvailableFontList() {
+ return Arrays.asList(GraphicsEnvironment.getLocalGraphicsEnvironment()
+ .getAvailableFontFamilyNames());
+ }
+
+ @Override
+ public String getDefaultGenericFontFamily() {
+ return cssContext.getDefaultFontFamily().getStringValue();
+ }
+
+ @Override
+ public String getDefaultGenericFontFamily(String genericFamily) {
+ return genericFamily;
+ }
+
+ @Override
+ public boolean isFontFaceName(String requestedFamily) {
+ for (FontFaceRule ffRule : fontFaces) {
+ StyleMap sm = ffRule.getStyleMap();
+ int pidx = getPropertyIndex(CSSConstants.CSS_FONT_FAMILY_PROPERTY);
+ Value fontFamily = sm.getValue(pidx);
+ if (fontFamily != null && fontFamily.getStringValue().equalsIgnoreCase(requestedFamily)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public int getColorDepth() {
+ // We do not have the actual Graphics2D here, but we try
+ GraphicsEnvironment genv = GraphicsEnvironment.getLocalGraphicsEnvironment();
+ java.awt.GraphicsConfiguration gConfiguration = genv.getDefaultScreenDevice()
+ .getDefaultConfiguration();
+ int bpc = 255;
+ if (gConfiguration != null) {
+ int[] comp = gConfiguration.getColorModel().getComponentSize();
+ for (int i = 0; i < 3; i++) {
+ if (bpc > comp[i]) {
+ bpc = comp[i];
+ }
+ }
+ }
+ return bpc;
+ }
+
+ @Override
+ public float getDeviceHeight() {
+ return cssContext.getViewport(element).getHeight();
+ }
+
+ @Override
+ public float getDeviceWidth() {
+ return cssContext.getViewport(element).getWidth();
+ }
+
+ @Override
+ protected boolean isFontFamilyAvailable(String fontFamily) {
+ return fonts.contains(fontFamily);
+ }
+
+ @Override
+ public CSSTypedValue getInitialColor() {
+ String pcs = cssContext.getPrefersColorScheme();
+ return pcs != null && "dark".equals(pcs) ?
+ darkmodeInitialColor() : super.getInitialColor();
+ }
+
+ private CSSTypedValue darkmodeInitialColor() {
+ return (CSSTypedValue) new ValueFactory().parseProperty("#fff");
+ }
+
+ @Override
+ public boolean supports(SelectorList selectors) {
+ for (Selector selector : selectors) {
+ if (!supports(selector)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private boolean supports(Selector selector) {
+ if (selector != null) {
+ switch (selector.getSelectorType()) {
+ case CHILD:
+ case DESCENDANT:
+ case DIRECT_ADJACENT:
+ case SUBSEQUENT_SIBLING:
+ CombinatorSelector combSel = (CombinatorSelector) selector;
+ return supports(combSel.getSelector())
+ && supports(combSel.getSecondSelector());
+ case CONDITIONAL:
+ ConditionalSelector condSel = (ConditionalSelector) selector;
+ return supports(condSel.getSimpleSelector())
+ && supports(condSel.getCondition());
+ case COLUMN_COMBINATOR:
+ return false;
+ default:
+ }
+ }
+ return true;
+ }
+
+ private boolean supports(Condition condition) {
+ switch (condition.getConditionType()) {
+ case AND:
+ CombinatorCondition combCond = (CombinatorCondition) condition;
+ return supports(combCond.getFirstCondition())
+ && supports(combCond.getSecondCondition());
+ case SELECTOR_ARGUMENT:
+ ArgumentCondition argCond = (ArgumentCondition) condition;
+ SelectorList selist = argCond.getSelectors();
+ return selist == null || supports(selist);
+ default:
+ return true;
+ }
+ }
+
+ }
+
+ private class EngineCSSCanvas extends AbstractCSSCanvas {
+
+ @Override
+ public CSSDocument getDocument() {
+ return null;
+ }
+
+ @Override
+ public StyleDatabase getStyleDatabase() {
+ return styleDb;
+ }
+
+ @Override
+ protected String getOverflowBlock() {
+ return "none";
+ }
+
+ @Override
+ protected String getOverflowInline() {
+ return "none";
+ }
+
+ @Override
+ protected String getPointerAccuracy() {
+ return "none";
+ }
+
+ /**
+ * The desire for light or dark color schemes.
+ *
+ * @return the {@code prefers-color-scheme} feature
+ */
+ @Override
+ protected String getPrefersColorScheme() {
+ return cssContext.getPrefersColorScheme();
+ }
+
+ @Override
+ protected float getResolution() {
+ return cssContext.getResolution();
+ }
+
+ }
+
/**
* Adds event listeners to the document to track CSS changes.
*/
@@ -604,15 +825,7 @@ public List getFontFaces() {
* Sets the media to use to compute the styles.
*/
public void setMedia(String str) {
- try {
- media = parser.parseMediaQueryList(str, null);
- } catch (Exception e) {
- String m = e.getMessage();
- if (m == null)
- m = "";
- String s = Messages.formatMessage("media.error", new Object[] { str, m });
- throw new DOMException(DOMException.SYNTAX_ERR, s);
- }
+ medium = str != null ? str.toLowerCase(Locale.ROOT) : null;
}
/**
@@ -673,7 +886,7 @@ public StyleMap getCascadedStyleMap(CSSStylableElement elt, String pseudo) {
SelectorMatcher matcher = new SVGSelectorMatcher(elt);
if (pseudo != null) {
- CSSParser parser = new CSSParser();
+ Parser parser = createCSSParser();
Condition pseCond = parser.parsePseudoElement(pseudo);
matcher.setPseudoElement(pseCond);
}
@@ -702,7 +915,12 @@ public void property(String pname, LexicalUnit lu, boolean important) {
int idx = getPropertyIndex(pname);
if (idx != -1) {
ValueManager vm = valueManagers[idx];
- Value v = vm.createValue(lu, CSSEngine.this);
+ Value v;
+ try {
+ v = vm.createValue(lu, CSSEngine.this);
+ } catch (CSSProxyValueException e) {
+ v = new LexicalValue(lu);
+ }
putAuthorProperty(result, idx, v, important, StyleMap.NON_CSS_ORIGIN);
return;
}
@@ -712,6 +930,14 @@ public void property(String pname, LexicalUnit lu, boolean important) {
// Shorthand value
shorthandManagers[idx].setValues(CSSEngine.this, this, lu, important);
}
+
+ @Override
+ public void pendingValue(String pname, PendingValue v, boolean important) {
+ int idx = getPropertyIndex(pname);
+ if (idx != -1) { // line-height can be -1
+ putAuthorProperty(result, idx, v, important, StyleMap.NON_CSS_ORIGIN);
+ }
+ }
};
NamedNodeMap attrs = elt.getAttributes();
@@ -800,6 +1026,14 @@ && mediaMatch(ss.getMedia())) {
result.putOrigin(idx, StyleMap.OVERRIDE_ORIGIN);
}
}
+
+ // Custom properties
+ Map customProp = over.getCustomProperties();
+ if (customProp != null) {
+ for (Map.Entry entry : customProp.entrySet()) {
+ result.putCustomProperty(entry.getKey(), entry.getValue());
+ }
+ }
}
}
} finally {
@@ -810,11 +1044,16 @@ && mediaMatch(ss.getMedia())) {
return result;
}
+ private Parser createCSSParser() {
+ return new CSSOMParser();
+ }
+
/**
* Returns the computed style of the given element/pseudo for the property
* corresponding to the given index.
*/
- public Value getComputedStyle(CSSStylableElement elt, String pseudo, int propidx) {
+ public Value getComputedStyle(CSSStylableElement elt, String pseudo, int propidx)
+ throws CSSSecurityException {
StyleMap sm = elt.getComputedStyleMap(pseudo);
if (sm == null) {
sm = getCascadedStyleMap(elt, pseudo);
@@ -829,21 +1068,48 @@ public Value getComputedStyle(CSSStylableElement elt, String pseudo, int propidx
ValueManager vm = valueManagers[propidx];
CSSStylableElement p = getParentCSSStylableElement(elt);
if (value == null) {
- if ((p == null) || !vm.isInheritedProperty())
+ if (p == null || !vm.isInheritedProperty()) {
result = vm.getDefaultValue();
- } else if ((p != null) && (value == InheritValue.INSTANCE)) {
- result = null;
+ }
+ } else if (value.getPrimitiveType() == Type.LEXICAL) {
+ LexicalValue var = (LexicalValue) value;
+ LexicalUnit lunit = replaceLexicalValue(sm, var.getLexicalUnit(), elt, p, propidx);
+ if (lunit != null) {
+ result = vm.createValue(lunit, this);
+ if (result == null || result.getCssValueType() == CSSValue.CssType.KEYWORD) {
+ result = initialOrNull(p != null, vm, result);
+ }
+ } else {
+ result = initialOrNull(p != null, vm, null);
+ }
+ } else if (value.getPrimitiveType() == Type.INTERNAL) {
+ PendingValue pending = (PendingValue) value;
+ if (substitutePendingShorthand(sm, pending, elt, p, propidx)) {
+ result = sm.getValue(propidx);
+ } else {
+ result = initialOrNull(p != null, vm, null);
+ }
+ } else if (value.getCssValueType() == CSSValue.CssType.KEYWORD) {
+ result = initialOrNull(p != null, vm, value);
+ }
+
+ if (result != null) {
+ // Maybe it is a relative value.
+ result = vm.computeValue(elt, pseudo, this, propidx, sm, result);
+ if (result == null) {
+ // calc() gave invalid result
+ result = initialOrNull(p != null, vm, null);
+ }
}
+
if (result == null) {
// Value is 'inherit' and p != null.
// The pseudo class is not propagated.
result = getComputedStyle(p, null, propidx);
sm.putParentRelative(propidx, true);
sm.putInherited(propidx, true);
- } else {
- // Maybe is it a relative value.
- result = vm.computeValue(elt, pseudo, this, propidx, sm, result);
}
+
if (value == null) {
sm.putValue(propidx, result);
sm.putNullCascaded(propidx, true);
@@ -858,6 +1124,563 @@ public Value getComputedStyle(CSSStylableElement elt, String pseudo, int propidx
return result;
}
+ private static Value initialOrNull(boolean hasParent, ValueManager vm, Value value) {
+ Value result;
+ if (hasParent && (vm.isInheritedProperty() || value == InheritValue.getInstance())) {
+ result = null;
+ } else {
+ result = vm.getDefaultValue();
+ }
+ return result;
+ }
+
+ /**
+ * Substitute the {@code PROXY} values in a lexical value.
+ *
+ * @param sm the style map.
+ * @param lexicalUnit the lexical value.
+ * @param elt the element for which the value is computed.
+ * @param parent the parent element, or {@code null} if no parent.
+ * @param propIdx the property index.
+ * @return the replaced lexical unit.
+ * @throws DOMException
+ * @throws CSSCircularityException if a circularity was found while evaluating
+ * custom properties.
+ * @throws CSSResourceLimitException if the limit of recursions or allowed
+ * substitutions was exceeded.
+ */
+ private LexicalUnit replaceLexicalValue(StyleMap sm, LexicalUnit lexicalUnit, CSSStylableElement elt,
+ CSSStylableElement parent, int propIdx) throws CSSSecurityException {
+ HashSet customPropertySet = new HashSet<>(INITIAL_CUSTOM_PTY_SET_SIZE);
+
+ CounterRef counter = new CounterRef();
+
+ LexicalUnit lunit = lexicalUnit.clone();
+ LexicalUnit replUnit;
+ try {
+ replUnit = replaceLexicalProxy(sm, lunit, elt, parent, counter, customPropertySet, propIdx);
+ } catch (CSSSecurityException e) {
+ throw e;
+ } catch (DOMException e) {
+ displayOrThrowError(e);
+ return null;
+ }
+
+ if (replUnit != null && replUnit.getLexicalUnitType() == LexicalType.EMPTY) {
+ replUnit = null;
+ }
+
+ return replUnit;
+ }
+
+ /**
+ * Given a lexical value, replace all occurrences of the {@code VAR} and
+ * {@code ATTR} lexical types with the values of the corresponding custom
+ * properties or attributes, and incrementing the supplied counter.
+ *
+ * @param sm the style map.
+ * @param lexval the lexical value.
+ * @param elt the element for which the value is computed.
+ * @param parent the parent element, or {@code null} if no parent.
+ * @param counter the substitution and recursion counter.
+ * @param customPtySet the set of custom property names, to prevent circular
+ * dependencies.
+ * @param propIdx the property index.
+ * @return the replaced lexical unit.
+ * @throws DOMException
+ * @throws CSSCircularityException if a circularity was found while evaluating
+ * custom properties.
+ * @throws CSSResourceLimitException if the limit of recursions or allowed
+ * substitutions was exceeded.
+ */
+ private LexicalUnit replaceLexicalProxy(StyleMap sm, LexicalUnit lexval, CSSStylableElement elt,
+ CSSStylableElement parent, CounterRef counter, Set customPtySet, int propIdx)
+ throws DOMException, CSSSecurityException {
+ final int REPLACE_COUNT_LIMIT = 0x20000; // Number of allowed lexical substitutions
+
+ /*
+ * Prepare a working set of traversed custom properties
+ */
+ Set ptySet = new HashSet<>(customPtySet.size() + 8);
+ ptySet.addAll(customPtySet);
+
+ /*
+ * Replace the PROXY (var(), attr()) values in the lexical chain
+ */
+ LexicalUnit lu = lexval;
+ do {
+ if (lu.getLexicalUnitType() == LexicalType.VAR) {
+ LexicalUnit newlu;
+ LexicalUnit param = lu.getParameters();
+ String propertyName = param.getStringValue(); // Property name
+ param = param.getNextLexicalUnit(); // Comma?
+ if (param != null) {
+ param = param.getNextLexicalUnit(); // Fallback
+ }
+
+ /*
+ * Obtain a value and replace this var() in the lexical chain
+ */
+ newlu = getCustomPropertyValueOrFallback(sm, propertyName, param, parent, counter, ptySet);
+
+ boolean isLexval = lu == lexval;
+ if (newlu == null) {
+ // The current lexical unit can be removed
+ lu = lu.remove();
+ if (isLexval) {
+ // We are processing the first in the lexical chain, re-assign
+ lexval = lu;
+ }
+ continue;
+ }
+
+ if (newlu.getLexicalUnitType() != LexicalType.EMPTY) {
+ // We do not want to mess with a declared value, so clone it
+ newlu = newlu.clone();
+ try {
+ counter.replaceCounter += lu.countReplaceBy(newlu);
+ } catch (CSSBudgetException e) {
+ throw createVarResourceLimitException(propertyName, e);
+ }
+ if (counter.replaceCounter >= REPLACE_COUNT_LIMIT) {
+ throw createVarResourceLimitException(propertyName);
+ }
+ lu = newlu;
+ if (isLexval) {
+ // We are processing the first in the lexical chain, re-assign
+ lexval = newlu;
+ }
+ // Can we reset the circularity safeguard?
+ LexicalType ltype = lu.getLexicalUnitType();
+ if (ltype != LexicalType.VAR && ltype != LexicalType.ATTR) {
+ ptySet.clear();
+ ptySet.addAll(customPtySet);
+ }
+ } else {
+ // The current lexical unit can be removed
+ lu = lu.remove();
+ if (isLexval) {
+ // We are processing the first in the lexical chain, re-assign
+ lexval = lu;
+ }
+ }
+ continue;
+ } else if (lu.getLexicalUnitType() == LexicalType.ATTR) {
+ if (valueManagers[propIdx].allowsURL()) {
+ return null;
+ }
+ boolean isLexval = lu == lexval;
+ LexicalUnit newlu = replacementAttrUnit(sm, lu, elt, parent, counter, ptySet, propIdx);
+ try {
+ counter.replaceCounter += lu.countReplaceBy(newlu);
+ } catch (CSSBudgetException e) {
+ throw createAttrResourceLimitException(e);
+ }
+ if (counter.replaceCounter >= REPLACE_COUNT_LIMIT) {
+ throw createAttrResourceLimitException();
+ }
+
+ if (newlu == null) {
+ // The current lexical unit can be removed
+ lu = lu.remove();
+ if (isLexval) {
+ // We are processing the first in the lexical chain, re-assign
+ lexval = lu;
+ }
+ continue;
+ }
+
+ if (newlu.getLexicalUnitType() != LexicalType.EMPTY) {
+ // We do not want to mess with a declared value, so clone it
+ newlu = newlu.clone();
+ try {
+ counter.replaceCounter += lu.countReplaceBy(newlu);
+ } catch (CSSBudgetException e) {
+ throw createAttrResourceLimitException(e);
+ }
+ if (counter.replaceCounter >= REPLACE_COUNT_LIMIT) {
+ throw createAttrResourceLimitException();
+ }
+ lu = newlu;
+ if (isLexval) {
+ // We are processing the first in the lexical chain, re-assign
+ lexval = newlu;
+ }
+ } else {
+ // The current lexical unit can be removed
+ lu = lu.remove();
+ if (isLexval) {
+ // We are processing the first in the lexical chain, re-assign
+ lexval = lu;
+ }
+ }
+ continue;
+ } else {
+ LexicalUnit param = lu.getParameters();
+ if (param != null || (param = lu.getSubValues()) != null) {
+ // Ignore return value (it is a parameter or a sub-value)
+ replaceLexicalProxy(sm, param, elt, parent, counter, ptySet, propIdx);
+ }
+ }
+ lu = lu.getNextLexicalUnit();
+ } while (lu != null);
+
+ return lexval;
+ }
+
+ /**
+ * Obtain the (lexical) value of a custom property and replace any {@code VAR}
+ * unit in it, applying the fallback if necessary.
+ *
+ * @param sm
+ * @param customProperty the custom property name.
+ * @param fallbackLU the custom property fallback.
+ * @param parent the parent element, or {@code null} if no parent.
+ * @param counter the counter.
+ * @param customPtySet the set of custom property names, to prevent circular
+ * dependencies.
+ * @return the value of {@code customProperty} or the fallback if there is no
+ * value.
+ * @throws DOMException
+ * @throws CSSCircularityException if a circularity was found while evaluating
+ * custom properties.
+ * @throws CSSResourceLimitException if the limit of recursions or allowed
+ * substitutions was exceeded.
+ */
+ private LexicalUnit getCustomPropertyValueOrFallback(StyleMap sm, String customProperty, LexicalUnit fallbackLU,
+ CSSStylableElement parent, CounterRef counter, Set customPtySet)
+ throws DOMException, CSSSecurityException {
+ if (!customPtySet.add(customProperty)) {
+ throw new CSSCircularityException(
+ "Circularity evaluating custom property " + customProperty + ": " + customPtySet.toString());
+ }
+
+ LexicalUnit custom = getCustomProperty(sm, customProperty, parent);
+
+ if (custom != null) {
+ if (counter.increment()) {
+ return custom;
+ } else {
+ throw createVarResourceLimitException(customProperty);
+ }
+ }
+
+ // customProperty is null, no circularity.
+ customPtySet.remove(customProperty);
+
+ // Fallback
+ return fallbackLU;
+ }
+
+ private LexicalUnit getCustomProperty(StyleMap sm, String name, CSSStylableElement parent) {
+ // First, try to obtain a possible property definition from a @property rule
+ PropertyDefinition definition = getPropertyDefinition(name);
+ boolean inherits = definition == null || definition.inherits();
+
+ LexicalUnit custom;
+ while ((custom = sm.getCustomProperty(name)) == null && inherits) {
+ if (parent != null) {
+ sm = parent.getComputedStyleMap(null);
+ if (sm == null) {
+ sm = getCascadedStyleMap(parent, null);
+ parent.setComputedStyleMap(null, sm);
+ }
+ parent = getParentCSSStylableElement(parent);
+ } else {
+ break;
+ }
+ }
+
+ if (custom == null) {
+ if (definition != null) {
+ custom = definition.getInitialValue();
+ }
+ } else if (definition != null) {
+ CSSValueSyntax syntax = definition.getSyntax();
+ // syntax is never null
+ if (custom.matches(syntax) == Match.FALSE) {
+ custom = definition.getInitialValue();
+ }
+ }
+
+ return custom;
+ }
+
+ private PropertyDefinition getPropertyDefinition(String name) {
+ return propertyDefinitionMap == null ? null : propertyDefinitionMap.get(name);
+ }
+
+ /**
+ * Perform a lexical substitution on a pending shorthand value.
+ *
+ * @param sm the style map.
+ * @param pending the pending longhand value.
+ * @param elt the element for which the value is computed.
+ * @param parent the parent element, or {@code null} if no parent.
+ * @param propIdx the property index.
+ * @return {@code true} if the shorthand was replaced successfully.
+ * @throws DOMException
+ * @throws CSSCircularityException if a circularity was found while evaluating
+ * custom properties.
+ * @throws CSSResourceLimitException if the limit of recursions or allowed
+ * substitutions was exceeded.
+ */
+ private boolean substitutePendingShorthand(StyleMap sm, PendingValue pending, CSSStylableElement elt,
+ CSSStylableElement parent, int propIdx) throws DOMException, CSSSecurityException {
+ LexicalUnit lunit = replaceLexicalProxy(sm, pending.getLexicalUnit().clone(), elt, parent,
+ new CounterRef(), new HashSet<>(INITIAL_CUSTOM_PTY_SET_SIZE), propIdx);
+ boolean ret = lunit != null ?
+ setShorthandLonghands(sm, pending.getShorthandName(), lunit, sm.isImportant(propIdx)) : false;
+ return ret;
+ }
+
+ private boolean setShorthandLonghands(StyleMap sm, String propertyName, LexicalUnit value,
+ boolean important) throws DOMException {
+ try {
+ int idx = getShorthandIndex(propertyName);
+ if (idx == -1)
+ return false; // Unknown property...
+ // Shorthand value
+ shorthandManagers[idx].setValues(CSSEngine.this, new ShorthandManager.PropertyHandler() {
+
+ @Override
+ public void property(String pname, LexicalUnit value, boolean important) {
+ int idx = getPropertyIndex(pname);
+ if (idx != -1) {
+ Value oldv = sm.getValue(idx);
+ if (oldv == null || oldv.getPrimitiveType() == Type.INTERNAL) {
+ ValueManager vm = valueManagers[idx];
+ Value v = vm.createValue(value, CSSEngine.this);
+ sm.putValue(idx, v);
+ // sm.putImportant(idx, important); // already done
+ } // else the value was set later
+ } else {
+ // This can be removed
+ throw new IllegalStateException("Unknown pending value.");
+ }
+ }
+
+ @Override
+ public void pendingValue(String name, PendingValue value, boolean important) {
+ throw new IllegalStateException("Cannot set pending values after replacement.");
+ }
+
+ }, value, important);
+ return true;
+ } catch (DOMException e) {
+ // Report error
+ DOMException ex = new DOMException(e.code, "Error setting shorthand " + propertyName);
+ ex.initCause(e);
+ displayOrThrowError(ex);
+ return false;
+ }
+ }
+
+ private LexicalUnit replacementAttrUnit(StyleMap sm, LexicalUnit attr, CSSStylableElement elt,
+ CSSStylableElement parent, CounterRef counter, Set ptySet, int propIdx) {
+ // Obtain attribute name and type (if set)
+ LexicalUnit lu = attr.getParameters();
+ if (lu.getLexicalUnitType() != LexicalType.IDENT) {
+ valueSyntaxError("Unexpected attribute name (" + lu.getCssText() + ") in " + attr.getCssText());
+ return null;
+ }
+ String attrname = lu.getStringValue();
+ String attrtype;
+ lu = lu.getNextLexicalUnit();
+ if (lu != null) {
+ if (lu.getLexicalUnitType() != LexicalType.OPERATOR_COMMA) {
+ switch (lu.getLexicalUnitType()) {
+ case IDENT:
+ attrtype = lu.getStringValue().toLowerCase(Locale.ROOT);
+ break;
+ case OPERATOR_MOD:
+ attrtype = "%";
+ break;
+ default:
+ valueSyntaxError(
+ "Unexpected attribute type (" + lu.getCssText() + ") in " + attr.getCssText());
+ return null;
+ }
+ lu = lu.getNextLexicalUnit();
+ if (lu != null) {
+ if (lu.getLexicalUnitType() != LexicalType.OPERATOR_COMMA) {
+ valueSyntaxError(
+ "Expected comma, found: " + lu.getCssText() + " in " + attr.getCssText());
+ return null;
+ }
+ lu = lu.getNextLexicalUnit();
+ }
+ } else {
+ lu = lu.getNextLexicalUnit();
+ if (lu == null) {
+ // Ending with comma is wrong syntax
+ valueSyntaxError("Unexpected end after comma in value " + attr.getCssText());
+ return null;
+ }
+ attrtype = null;
+ }
+ } else {
+ attrtype = null;
+ }
+
+ // Obtain the attribute value
+ String attrvalue = elt.getAttribute(attrname);
+
+ Parser parser = createCSSParser();
+
+ /*
+ * string type is a special case
+ */
+ if (attrtype == null || "string".equalsIgnoreCase(attrtype)) {
+ String s = ParseHelper.quote(attrvalue, '"');
+ LexicalUnit substValue;
+ try {
+ substValue = parser.parsePropertyValue(new StringReader(s));
+ } catch (IOException e) {
+ // This won't happen
+ substValue = null;
+ } catch (CSSParseException e) {
+ // Possibly a budget error
+ valueSyntaxError("Unexpected error parsing: " + s.substring(0, Math.min(s.length(), 255)), e);
+ // Process fallback
+ substValue = lu;
+ if (substValue != null) {
+ substValue = substValue.clone();
+ } else {
+ try {
+ return parser.parsePropertyValue(new StringReader(""));
+ } catch (CSSParseException | IOException e1) {
+ }
+ }
+ }
+ // No further processing required
+ return replaceLexicalProxy(sm, substValue, elt, parent, counter, ptySet, propIdx);
+ }
+
+ if (!attrvalue.isEmpty()) {
+ /*
+ * Non-string types
+ */
+ attrvalue = attrvalue.trim();
+
+ // Let's see if the type is an actual type or an unit suffix
+ if (attrtype.length() <= 2 || UnitStringToId.unitFromString(attrtype) != CSSUnit.CSS_OTHER) {
+ attrvalue += attrtype;
+ }
+
+ LexicalUnit substValue;
+ try {
+ substValue = parser.parsePropertyValue(new StringReader(attrvalue));
+ } catch (IOException e) {
+ // This won't happen
+ substValue = null;
+ } catch (CSSParseException e) {
+ valueSyntaxError("Error parsing attribute '" + attrname + "', value: " + attrvalue, e);
+ // Return fallback
+ if (lu != null) {
+ return replaceLexicalProxy(sm, lu.clone(), elt, parent, counter, ptySet, propIdx);
+ }
+ return null;
+ }
+ try {
+ substValue = replaceLexicalProxy(sm, substValue, elt, parent, counter, ptySet, propIdx);
+ } catch (Exception e) {
+ valueSyntaxError("Circularity: " + attr.getCssText() + " references " + substValue.getCssText(), e);
+ // Return fallback
+ substValue = null;
+ }
+ if (substValue != null) {
+ substValue = replaceLexicalProxy(sm, substValue, elt, parent, counter, ptySet, propIdx);
+ // Now check that the value is of the correct type.
+ //
+ // If the attribute type length is 1 or 2, type can only be a unit suffix
+ // and there is no need to check.
+ if (attrtype.length() > 2 && !unitMatchesAttrType(substValue, attrtype)) {
+ substValue = null;
+ valueSyntaxError("Attribute value does not match type (" + attrtype + ").");
+ } else {
+ return substValue;
+ }
+ } else {
+ // Fallback
+ if (lu != null) {
+ substValue = replaceLexicalProxy(sm, lu.clone(), elt, parent, counter, ptySet, propIdx);
+ }
+ return substValue;
+ }
+ }
+
+ // Return fallback
+ return lu == null ? null : replaceLexicalProxy(sm, lu, elt, parent, counter, ptySet, propIdx);
+ }
+
+ private static boolean unitMatchesAttrType(LexicalUnit lunit, String attrtype) {
+ int len = attrtype.length();
+ if (len == 1) {
+ return "%".equals(attrtype) && lunit.getCssUnit() == CSSUnit.CSS_PERCENTAGE;
+ } else if (len == 2) {
+ return attrtype.equalsIgnoreCase(lunit.getDimensionUnitText());
+ }
+ if ("ident".equalsIgnoreCase(attrtype)) {
+ attrtype = "custom-ident";
+ }
+ CSSValueSyntax syn = SyntaxParser.createSimpleSyntax(attrtype);
+ if (syn == null) {
+ // Could be a 3-4 letter unit suffix, or an error
+ return attrtype.equalsIgnoreCase(lunit.getDimensionUnitText());
+ }
+ if (syn.getCategory() == CSSValueSyntax.Category.url) {
+ // There is no syntax for security reasons
+ return false;
+ }
+ return lunit.matches(syn) == Match.TRUE;
+ }
+
+ private void valueSyntaxError(String message) {
+ DOMException ex = new DOMException(DOMException.SYNTAX_ERR, message);
+ displayOrThrowError(ex);
+ }
+
+ private void valueSyntaxError(String message, Throwable cause) {
+ DOMException ex = new DOMException(DOMException.SYNTAX_ERR, message);
+ ex.initCause(cause);
+ displayOrThrowError(ex);
+ }
+
+ private CSSResourceLimitException createVarResourceLimitException(String propertyName) {
+ return createResourceLimitException(
+ "Resource limit hit while replacing custom property: " + propertyName);
+ }
+
+ private CSSResourceLimitException createVarResourceLimitException(String propertyName, Throwable cause) {
+ return createResourceLimitException(
+ "Resource limit hit while replacing custom property " + propertyName, cause);
+ }
+
+ private CSSResourceLimitException createAttrResourceLimitException() {
+ return createResourceLimitException("Resource limit hit while replacing attr() property.");
+ }
+
+ private CSSResourceLimitException createAttrResourceLimitException(Throwable e) {
+ return createResourceLimitException(
+ "Resource limit hit while replacing attr() property.", e);
+ }
+
+ private CSSResourceLimitException createResourceLimitException(String message) {
+ return new CSSResourceLimitException(message);
+ }
+
+ private CSSResourceLimitException createResourceLimitException(String message, Throwable e) {
+ return new CSSResourceLimitException(message, e);
+ }
+
+ private void displayOrThrowError(RuntimeException ex) {
+ if (userAgent == null) {
+ throw ex;
+ }
+ userAgent.displayError(ex);
+ }
+
/**
* Returns the document CSSStyleSheetNodes in a list. This list is updated as
* the document is modified.
@@ -977,6 +1800,11 @@ public void property(String pname, LexicalUnit lu, boolean important) {
// Shorthand value
shorthandManagers[idx].setValues(CSSEngine.this, this, lu, important);
}
+
+ @Override
+ public void pendingValue(String name, PendingValue value, boolean important) {
+ dst.setMainProperty(name, value, important);
+ }
};
ph.property(pname, lu, important);
} catch (Exception e) {
@@ -1005,8 +1833,9 @@ public void property(String pname, LexicalUnit lu, boolean important) {
*/
public Value parsePropertyValue(CSSStylableElement elt, String prop, String value) {
int idx = getPropertyIndex(prop);
- if (idx == -1)
+ if (idx == -1) {
return null;
+ }
ValueManager vm = valueManagers[idx];
try {
element = elt;
@@ -1306,10 +2135,126 @@ protected void addMatchingRules(List rules, StyleSheet ss, SelectorMatcher
addMatchingRules(rules, mr, matcher);
}
break;
+
+ case SupportsRule.TYPE:
+ SupportsRule sr = (SupportsRule) r;
+ if (sr.supports) {
+ addMatchingRules(rules, sr, matcher);
+ }
+ break;
}
}
}
+ /**
+ * Whether the given media list matches the media list of this CSSEngine object.
+ */
+ protected boolean mediaMatch(MediaQueryList ml) {
+ if (medium == null || ml == null || ml.isAllMedia()) {
+ return true;
+ }
+ return ml.matches(medium, csscanvas);
+ }
+
+ private void setSupports(SupportsRule sr) {
+ BooleanCondition condition = sr.getCondition();
+ if (condition != null) {
+ try {
+ sr.supports = supports(condition);
+ return;
+ } catch (Exception e) {
+ }
+ }
+ sr.supports = false;
+ }
+
+ private boolean supports(BooleanCondition condition) {
+ switch (condition.getType()) {
+ case PREDICATE:
+ DeclarationCondition declCond = (DeclarationCondition) condition;
+ return supports(declCond.getName(), declCond.getValue());
+ case AND:
+ List subcond = condition.getSubConditions();
+ if (subcond == null) {
+ // No conditions inside and()
+ DOMException ex = new DOMException(DOMException.SYNTAX_ERR, "No conditions inside and().");
+ userAgent.displayError(ex);
+ return false;
+ }
+ Iterator it = subcond.iterator();
+ while (it.hasNext()) {
+ if (!supports(it.next())) {
+ return false;
+ }
+ }
+ return true;
+ case NOT:
+ BooleanCondition nested = condition.getNestedCondition();
+ if (nested == null) {
+ // No condition inside not()
+ DOMException ex = new DOMException(DOMException.SYNTAX_ERR, "No condition inside not().");
+ userAgent.displayError(ex);
+ return false;
+ }
+ return !supports(nested);
+ case OR:
+ subcond = condition.getSubConditions();
+ if (subcond == null) {
+ // No conditions inside or()
+ DOMException ex = new DOMException(DOMException.SYNTAX_ERR, "No conditions inside or().");
+ userAgent.displayError(ex);
+ return false;
+ }
+ it = subcond.iterator();
+ while (it.hasNext()) {
+ if (supports(it.next())) {
+ return true;
+ }
+ }
+ break;
+ case SELECTOR_FUNCTION:
+ SelectorFunction selCond = (SelectorFunction) condition;
+ return styleDb.supports(selCond.getSelectors());
+ case OTHER:
+ break;
+ }
+
+ return false;
+ }
+
+ private boolean supports(String property, LexicalUnit value) {
+ int idx = getPropertyIndex(property);
+ if (idx != -1) {
+ try {
+ valueManagers[idx].createValue(value, CSSEngine.this);
+ return true;
+ } catch (Exception e) {
+ }
+ return false;
+ }
+
+ idx = getShorthandIndex(property);
+ if (idx != -1) {
+ try {
+ shorthandManagers[idx].setValues(this, new ShorthandManager.PropertyHandler() {
+
+ @Override
+ public void property(String name, LexicalUnit value, boolean important) {
+ }
+
+ @Override
+ public void pendingValue(String name, PendingValue value, boolean important) {
+ }
+
+ }, value, false);
+ return true;
+ } catch (Exception e) {
+ }
+ }
+
+ return false;
+ }
+
/**
* Adds the rules contained in the given list to a stylemap.
*/
@@ -1324,6 +2269,14 @@ protected void addRules(SelectorMatcher matcher, StyleMap sm, ArrayList ru
for (int i = 0; i < len; i++) {
putAuthorProperty(sm, sd.getIndex(i), sd.getValue(i), sd.getPriority(i), origin);
}
+
+ // Custom properties
+ Map customProp = sd.getCustomProperties();
+ if (customProp != null) {
+ for (Map.Entry entry : customProp.entrySet()) {
+ sm.putCustomProperty(entry.getKey(), entry.getValue());
+ }
+ }
}
} else {
for (Rule rule : rules) {
@@ -1382,16 +2335,6 @@ protected void sortRules(ArrayList rules, SelectorMatcher matcher) {
}
}
- /**
- * Whether the given media list matches the media list of this CSSEngine object.
- */
- protected boolean mediaMatch(MediaQueryList ml) {
- if (media == null || ml == null || media.isAllMedia()) {
- return true;
- }
- return ml.matches(media);
- }
-
/**
* To parse a style declaration.
*/
@@ -1430,6 +2373,19 @@ public void property(String name, LexicalUnit value, boolean important) {
}
}
+ @Override
+ public void lexicalProperty(String name, LexicalUnit value, boolean important) {
+ styleMap.putCustomProperty(name, value);
+ }
+
+ @Override
+ public void pendingValue(String name, PendingValue v, boolean important) {
+ int idx = getPropertyIndex(name);
+ if (idx != -1) { // line-height can be -1
+ putAuthorProperty(styleMap, idx, v, important, StyleMap.INLINE_AUTHOR_ORIGIN);
+ }
+ }
+
}
/**
@@ -1455,6 +2411,19 @@ public void property(String name, LexicalUnit value, boolean important) {
}
}
+ @Override
+ public void lexicalProperty(String name, LexicalUnit value, boolean important) {
+ styleDeclaration.setCustomProperty(name, value, important);
+ }
+
+ @Override
+ public void pendingValue(String name, PendingValue value, boolean important) {
+ int idx = getPropertyIndex(name);
+ if (idx != -1) { // line-height can be -1
+ styleDeclaration.append(value, idx, important);
+ }
+ }
+
}
/**
@@ -1466,6 +2435,8 @@ protected class StyleSheetDocumentHandler extends DocumentAdapter implements Sho
protected StyleRule styleRule;
protected StyleDeclaration styleDeclaration;
+ private PropertyDefinitionImpl currentPropertyDefinition = null;
+
private int ignoredForRule = 0;
@Override
@@ -1651,28 +2622,53 @@ public void endFeatureMap() {
public void startProperty(String name) {
if (ignoredForRule == 0) {
ignoredForRule = CSSRule.PROPERTY_RULE;
+ } else {
+ return;
+ }
+
+ if (propertyDefinitionMap == null) {
+ propertyDefinitionMap = new HashMap<>();
}
+
+ currentPropertyDefinition = new PropertyDefinitionImpl(name);
}
@Override
public void endProperty(boolean discard) {
- if (ignoredForRule == CSSRule.PROPERTY_RULE) {
- ignoredForRule = 0;
+ if (ignoredForRule != CSSRule.PROPERTY_RULE) {
+ return;
+ }
+
+ if (!discard) {
+ propertyDefinitionMap.put(currentPropertyDefinition.getName(), currentPropertyDefinition);
}
+
+ currentPropertyDefinition = null;
+ ignoredForRule = 0;
}
@Override
public void startSupports(BooleanCondition condition) {
- if (ignoredForRule == 0) {
- ignoredForRule = CSSRule.SUPPORTS_RULE;
+ if (ignoredForRule > 0) {
+ return;
}
+
+ SupportsRule sr = new SupportsRule(condition);
+
+ setSupports(sr);
+
+ sr.setParent(styleSheet);
+ styleSheet.append(sr);
+ styleSheet = sr;
}
@Override
public void endSupports(BooleanCondition condition) {
- if (ignoredForRule == CSSRule.SUPPORTS_RULE) {
- ignoredForRule = 0;
+ if (ignoredForRule > 0) {
+ return;
}
+
+ styleSheet = styleSheet.getParent();
}
@Override
@@ -1742,6 +2738,55 @@ public void property(String name, LexicalUnit value, boolean important) {
}
}
+ @Override
+ public void lexicalProperty(String name, LexicalUnit value, boolean important) {
+ if (ignoredForRule == CSSRule.PROPERTY_RULE) {
+ propertyRuleDescriptor(name, value, important);
+ return;
+ } else if (ignoredForRule > 0) {
+ return;
+ }
+
+ styleDeclaration.setCustomProperty(name, value, important);
+ }
+
+ private void propertyRuleDescriptor(String name, LexicalUnit value, boolean important) {
+ switch (name) {
+ case "inherits":
+ currentPropertyDefinition.setInherits(!"false".equalsIgnoreCase(value.getStringValue()));
+ break;
+ case "initial-value":
+ currentPropertyDefinition.setInitialValue(value);
+ break;
+ case "syntax":
+ String s = value.getStringValue();
+ if (s == null) {
+ s = "*";
+ }
+ SyntaxParser synParser = new SyntaxParser();
+ CSSValueSyntax syn;
+ try {
+ syn = synParser.parseSyntax(s);
+ } catch (Exception e) {
+ syn = synParser.parseSyntax("*");
+ }
+ currentPropertyDefinition.setSyntax(syn);
+ break;
+ }
+ }
+
+ @Override
+ public void pendingValue(String name, PendingValue v, boolean important) {
+ if (ignoredForRule > 0) {
+ return;
+ }
+
+ int i = getPropertyIndex(name);
+ if (i != -1) { // line-height can be -1
+ styleDeclaration.append(v, i, important);
+ }
+ }
+
}
/**
@@ -2274,6 +3319,22 @@ public void property(String name, LexicalUnit value, boolean important) {
}
}
+ @Override
+ public void pendingValue(String name, PendingValue v, boolean important) {
+ int i = getPropertyIndex(name);
+ if (styleMap.isImportant(i)) {
+ // The previous value is important, and a value
+ // from a style attribute cannot be important...
+ return;
+ }
+
+ updatedProperties[i] = true;
+
+ styleMap.putMask(i, 0);
+ styleMap.putValue(i, v);
+ styleMap.putOrigin(i, StyleMap.INLINE_AUTHOR_ORIGIN);
+ }
+
}
/**
@@ -2299,8 +3360,7 @@ protected void nonCSSPresentationalHintUpdated(CSSStylableElement elt, StyleMap
case MutationEvent.MODIFICATION:
element = elt;
try {
- LexicalUnit lu;
- lu = parser.parsePropertyValue(new StringReader(newValue));
+ LexicalUnit lu = parser.parsePropertyValue(new StringReader(newValue));
ValueManager vm = valueManagers[idx];
Value v = vm.createValue(lu, CSSEngine.this);
style.putMask(idx, 0);
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/CSSResourceLimitException.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/CSSResourceLimitException.java
new file mode 100644
index 000000000..44d4a4cc2
--- /dev/null
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/CSSResourceLimitException.java
@@ -0,0 +1,38 @@
+/*
+
+ See the NOTICE file distributed with this work for additional
+ information regarding copyright ownership.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ */
+package io.sf.carte.echosvg.css.engine;
+
+import io.sf.carte.echosvg.css.CSSSecurityException;
+
+/**
+ * A resource limit was reached.
+ */
+public class CSSResourceLimitException extends CSSSecurityException {
+
+ private static final long serialVersionUID = 1L;
+
+ public CSSResourceLimitException(String message) {
+ super(message);
+ }
+
+ public CSSResourceLimitException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+}
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/CounterRef.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/CounterRef.java
new file mode 100644
index 000000000..3e63a56f7
--- /dev/null
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/CounterRef.java
@@ -0,0 +1,53 @@
+/*
+
+ See the NOTICE file distributed with this work for additional
+ information regarding copyright ownership.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ */
+package io.sf.carte.echosvg.css.engine;
+
+/**
+ * A counter to prevent excessive recursions and replacements.
+ */
+class CounterRef {
+
+ public CounterRef() {
+ super();
+ }
+
+
+ private static final int MAX_RECURSION = 512;
+
+ // Recursion counter
+ private int counter = 0;
+
+ // Counter for replaceBy()
+ int replaceCounter = 0;
+
+ boolean increment() {
+ counter++;
+ if (isInRange()) {
+ return true;
+ }
+ // Give a small margin for further operations
+ counter -= 8;
+ return false;
+ }
+
+ private boolean isInRange() {
+ return counter < MAX_RECURSION;
+ }
+
+}
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/PropertyDefinitionImpl.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/PropertyDefinitionImpl.java
new file mode 100644
index 000000000..019882cd4
--- /dev/null
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/PropertyDefinitionImpl.java
@@ -0,0 +1,88 @@
+/*
+
+ See the NOTICE file distributed with this work for additional
+ information regarding copyright ownership.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ */
+package io.sf.carte.echosvg.css.engine;
+
+import io.sf.carte.doc.style.css.CSSValueSyntax;
+import io.sf.carte.doc.style.css.nsac.LexicalUnit;
+import io.sf.carte.echosvg.css.engine.value.PropertyDefinition;
+
+/**
+ * Implementation of a property definition.
+ */
+class PropertyDefinitionImpl implements PropertyDefinition {
+
+ private final String name;
+
+ boolean inherits = true;
+
+ private CSSValueSyntax syntax;
+
+ private LexicalUnit initialValue;
+
+ PropertyDefinitionImpl(String name) {
+ super();
+ this.name = name;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public boolean inherits() {
+ return inherits;
+ }
+
+ void setInherits(boolean inherits) {
+ this.inherits = inherits;
+ }
+
+ @Override
+ public LexicalUnit getInitialValue() {
+ return initialValue;
+ }
+
+ void setInitialValue(LexicalUnit initialValue) {
+ this.initialValue = initialValue;
+ }
+
+ @Override
+ public CSSValueSyntax getSyntax() {
+ return syntax;
+ }
+
+ void setSyntax(CSSValueSyntax syntax) {
+ this.syntax = syntax;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder buf = new StringBuilder(48);
+ buf.append("@property ").append(name).append(" {\n");
+ buf.append(" syntax: \"").append(syntax.toString()).append("\";\n");
+ buf.append(" inherits: ").append(Boolean.toString(inherits)).append(";\n");
+ if (initialValue != null) {
+ buf.append(" initial-value: ").append(initialValue.toString()).append(";\n");
+ }
+ buf.append("}\n");
+ return buf.toString();
+ }
+
+}
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/StyleDeclaration.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/StyleDeclaration.java
index 6f5927acb..1d8a68e42 100644
--- a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/StyleDeclaration.java
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/StyleDeclaration.java
@@ -18,6 +18,14 @@
*/
package io.sf.carte.echosvg.css.engine;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import io.sf.carte.doc.style.css.CSSValue.Type;
+import io.sf.carte.doc.style.css.nsac.LexicalUnit;
+import io.sf.carte.echosvg.css.engine.value.PendingValue;
import io.sf.carte.echosvg.css.engine.value.Value;
/**
@@ -51,6 +59,11 @@ public class StyleDeclaration {
*/
protected int count;
+ /**
+ * Custom property map.
+ */
+ private Map customProperties = null;
+
/**
* Returns the number of values in the declaration.
*/
@@ -129,6 +142,7 @@ public void append(Value v, int idx, boolean prio) {
indexes = newidx;
priorities = newprio;
}
+
for (int i = 0; i < count; i++) {
if (indexes[i] == idx) {
// Replace existing property values,
@@ -140,23 +154,75 @@ public void append(Value v, int idx, boolean prio) {
return;
}
}
+
values[count] = v;
indexes[count] = idx;
priorities[count] = prio;
count++;
}
+ /**
+ * Set a custom property value in the declaration.
+ *
+ * @param name the custom property name.
+ * @param value the custom property value.
+ * @param important the priority.
+ */
+ public void setCustomProperty(String name, LexicalUnit value, boolean important) {
+ if (customProperties == null) {
+ customProperties = new HashMap<>();
+ }
+
+ customProperties.put(name, value);
+ }
+
+ /**
+ * Get the map of custom properties.
+ *
+ * @return the custom property map, or {@code null} if there are no custom
+ * properties.
+ */
+ public Map getCustomProperties() {
+ return customProperties;
+ }
+
/**
* Returns a printable representation of this style rule.
*/
public String toString(CSSEngine eng) {
- StringBuilder sb = new StringBuilder(count * 8);
+ Set pendingShorthands = null;
+ StringBuilder sb = new StringBuilder(count * 8 + 32);
for (int i = 0; i < count; i++) {
- sb.append(eng.getPropertyName(indexes[i]));
- sb.append(": ");
- sb.append(values[i]);
- sb.append(";\n");
+ Value value = values[i];
+ if (value.getPrimitiveType() != Type.INTERNAL) {
+ sb.append(eng.getPropertyName(indexes[i]));
+ sb.append(": ");
+ sb.append(value);
+ sb.append(";\n");
+ } else {
+ if (pendingShorthands == null) {
+ pendingShorthands = new HashSet<>();
+ }
+ PendingValue pending = (PendingValue) value;
+ String name = pending.getShorthandName();
+ if (pendingShorthands.add(name)) {
+ sb.append(name);
+ sb.append(": ");
+ sb.append(pending.getLexicalUnit().toString());
+ sb.append(";\n");
+ }
+ }
}
+
+ if (customProperties != null) {
+ for (Map.Entry entry : customProperties.entrySet()) {
+ sb.append(entry.getKey());
+ sb.append(": ");
+ sb.append(entry.getValue().toString());
+ sb.append(";\n");
+ }
+ }
+
return sb.toString();
}
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/StyleMap.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/StyleMap.java
index 634ae5a8f..d8824ba98 100644
--- a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/StyleMap.java
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/StyleMap.java
@@ -18,6 +18,14 @@
*/
package io.sf.carte.echosvg.css.engine;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import io.sf.carte.doc.style.css.CSSValue.Type;
+import io.sf.carte.doc.style.css.nsac.LexicalUnit;
+import io.sf.carte.echosvg.css.engine.value.PendingValue;
import io.sf.carte.echosvg.css.engine.value.Value;
/**
@@ -67,6 +75,11 @@ public class StyleMap {
*/
protected int[] masks;
+ /**
+ * Custom property map.
+ */
+ private Map customProperties = null;
+
/**
* Whether the values of this map cannot be re-cascaded.
*/
@@ -371,27 +384,79 @@ public void putViewportRelative(int i, boolean b) {
masks[i] &= ~VIEWPORT_RELATIVE_MASK;
}
+ /**
+ * Set a custom property value.
+ *
+ * @param name the custom property name.
+ * @param value the custom property value.
+ */
+ public void putCustomProperty(String name, LexicalUnit value) {
+ if (customProperties == null) {
+ customProperties = new HashMap<>();
+ }
+
+ customProperties.put(name, value);
+ }
+
+ /**
+ * Get the value of a custom property.
+ *
+ * @param name the custom property name.
+ * @return the custom property value, or {@code null} if there is no value
+ * defined for that custom property.
+ */
+ public LexicalUnit getCustomProperty(String name) {
+ return customProperties != null ? customProperties.get(name) : null;
+ }
+
/**
* Returns a printable representation of this style map.
*/
public String toString(CSSEngine eng) {
+ Set pendingShorthands = null;
// Note that values.length should always be equal to
// eng.getNumberOfProperties() for StyleMaps that were created
// by that CSSEngine.
int nSlots = values.length;
- StringBuilder sb = new StringBuilder(nSlots * 8);
+ StringBuilder sb = new StringBuilder(nSlots * 8 + 32);
for (int i = 0; i < nSlots; i++) {
Value v = values[i];
if (v == null)
continue;
- sb.append(eng.getPropertyName(i));
- sb.append(": ");
- sb.append(v);
- if (isImportant(i))
- sb.append(" !important");
- sb.append(";\n");
+ if (v.getPrimitiveType() != Type.INTERNAL) {
+ sb.append(eng.getPropertyName(i));
+ sb.append(": ");
+ sb.append(v);
+ if (isImportant(i))
+ sb.append(" !important");
+ sb.append(";\n");
+ } else {
+ if (pendingShorthands == null) {
+ pendingShorthands = new HashSet<>();
+ }
+ PendingValue pending = (PendingValue) v;
+ String name = pending.getShorthandName();
+ if (pendingShorthands.add(name)) {
+ sb.append(name);
+ sb.append(": ");
+ sb.append(pending.getLexicalUnit().toString());
+ if (isImportant(i))
+ sb.append(" !important");
+ sb.append(";\n");
+ }
+ }
+ }
+
+ if (customProperties != null) {
+ for (Map.Entry entry : customProperties.entrySet()) {
+ sb.append(entry.getKey());
+ sb.append(": ");
+ sb.append(entry.getValue().toString());
+ sb.append(";\n");
+ }
}
+
return sb.toString();
}
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/StyleSheet.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/StyleSheet.java
index 664d4eace..bb5392afc 100644
--- a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/StyleSheet.java
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/StyleSheet.java
@@ -18,6 +18,8 @@
*/
package io.sf.carte.echosvg.css.engine;
+import org.w3c.dom.DOMException;
+
import io.sf.carte.doc.style.css.MediaQueryList;
/**
@@ -129,6 +131,24 @@ public Rule getRule(int i) {
return rules[i];
}
+ /**
+ * Removes a CSS rule from the CSS rule list at index.
+ *
+ * @param index the rule list index at which the rule must be removed.
+ * @throws DOMException INDEX_SIZE_ERR if index is greater than or
+ * equal to {@link #getSize()}.
+ */
+ public void deleteRule(int index) throws DOMException {
+ if (index < 0 || index >= size) {
+ throw new DOMException(DOMException.INDEX_SIZE_ERR, "Invalid index: " + index + '.');
+ }
+ for (int i = index; i < size - 1; i++) {
+ rules[i] = rules[i + 1];
+ }
+ size--;
+ rules[size] = null;
+ }
+
/**
* Clears the content.
*/
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/SupportsRule.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/SupportsRule.java
new file mode 100644
index 000000000..fb8b195c7
--- /dev/null
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/SupportsRule.java
@@ -0,0 +1,114 @@
+/*
+
+ See the NOTICE file distributed with this work for additional
+ information regarding copyright ownership.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ */
+package io.sf.carte.echosvg.css.engine;
+
+import org.w3c.css.om.CSSRule;
+import org.w3c.dom.DOMException;
+
+import io.sf.carte.doc.style.css.BooleanCondition;
+import io.sf.carte.doc.style.css.nsac.CSSBudgetException;
+import io.sf.carte.doc.style.css.nsac.CSSException;
+import io.sf.carte.doc.style.css.om.CSSOMParser;
+import io.sf.carte.doc.style.css.parser.CSSParser;
+
+/**
+ * This class represents a {@code @supports} CSS rule.
+ *
+ * @version $Id$
+ */
+public class SupportsRule extends StyleSheet implements Rule {
+
+ /**
+ * The type constant.
+ */
+ public static final short TYPE = CSSRule.SUPPORTS_RULE;
+
+ /**
+ * The media list.
+ */
+ private BooleanCondition condition;
+
+ boolean supports;
+
+ public SupportsRule(BooleanCondition condition) {
+ super();
+ this.condition = condition;
+ }
+
+ /**
+ * Returns a constant identifying the rule type.
+ */
+ @Override
+ public short getType() {
+ return TYPE;
+ }
+
+ public BooleanCondition getCondition() {
+ return condition;
+ }
+
+ public String getConditionText() {
+ return condition != null ? condition.toString() : "";
+ }
+
+ public void setConditionText(String conditionText) throws DOMException {
+ parseConditionText(conditionText);
+ }
+
+ /**
+ * Parse the condition text.
+ *
+ * @param conditionText the condition text.
+ */
+ private void parseConditionText(String conditionText) throws DOMException {
+ CSSParser parser = new CSSOMParser();
+ try {
+ condition = parser.parseSupportsCondition(conditionText, null);
+ } catch (CSSBudgetException e) {
+ DOMException ex = new DOMException(DOMException.NOT_SUPPORTED_ERR,
+ "Limit found while parsing condition " + conditionText);
+ ex.initCause(e);
+ throw ex;
+ } catch (CSSException e) {
+ DOMException ex = new DOMException(DOMException.SYNTAX_ERR,
+ "Error parsing condition: " + conditionText);
+ ex.initCause(e);
+ throw ex;
+ }
+ }
+
+ /**
+ * Returns a printable representation of this media rule.
+ */
+ @Override
+ public String toString(CSSEngine eng) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("@supports");
+ if (condition != null) {
+ sb.append(condition.toString());
+ }
+ sb.append(" {\n");
+ for (int i = 0; i < size; i++) {
+ sb.append(rules[i].toString(eng));
+ }
+ sb.append("}\n");
+ return sb.toString();
+ }
+
+}
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/AbstractColorManager.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/AbstractColorManager.java
index 588c030ae..76aa3381b 100644
--- a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/AbstractColorManager.java
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/AbstractColorManager.java
@@ -26,15 +26,17 @@
import io.sf.carte.doc.style.css.CSSColor;
import io.sf.carte.doc.style.css.CSSTypedValue;
+import io.sf.carte.doc.style.css.CSSValue;
import io.sf.carte.doc.style.css.CSSValue.CssType;
+import io.sf.carte.doc.style.css.CSSValue.Type;
import io.sf.carte.doc.style.css.nsac.CSSParseException;
import io.sf.carte.doc.style.css.nsac.LexicalUnit;
import io.sf.carte.doc.style.css.nsac.LexicalUnit.LexicalType;
import io.sf.carte.doc.style.css.parser.CSSParser;
import io.sf.carte.doc.style.css.property.NumberValue;
+import io.sf.carte.doc.style.css.property.PercentageEvaluator;
import io.sf.carte.doc.style.css.property.StyleValue;
import io.sf.carte.doc.style.css.property.ValueFactory;
-import io.sf.carte.echosvg.css.dom.CSSValue.Type;
import io.sf.carte.echosvg.css.engine.CSSEngine;
import io.sf.carte.echosvg.css.engine.CSSStylableElement;
import io.sf.carte.echosvg.css.engine.StyleMap;
@@ -192,9 +194,11 @@ public Value createValue(LexicalUnit lunit, CSSEngine engine) throws DOMExceptio
}
case RGBCOLOR:
return createRGBColor(lunit);
- default:
+ case IDENT:
// Clone so colors can be modified
return super.createValue(lunit, engine).clone();
+ default:
+ return super.createValue(lunit, engine);
}
}
@@ -220,7 +224,7 @@ private LexicalUnit reparseColor(String colorSerialization) throws DOMException
@Override
public Value computeValue(CSSStylableElement elt, String pseudo, CSSEngine engine, int idx, StyleMap sm,
Value value) {
- if (value.getPrimitiveType() == Type.IDENT) {
+ if (value.getPrimitiveType() == CSSValue.Type.IDENT) {
String ident = ((AbstractStringValue) value).getValue();
// Search for a direct computed value.
Value v = (Value) computedValues.get(ident);
@@ -350,6 +354,19 @@ protected NumericValue createRGBColorComponent(LexicalUnit lu) throws DOMExcepti
case PERCENTAGE:
return new FloatValue(CSSUnit.CSS_PERCENTAGE, lu.getFloatValue());
+ case VAR:
+ case ATTR:
+ throw new CSSProxyValueException();
+
+ case CALC:
+ Value calc = createCalc(lu);
+ if (calc.getCssValueType() == CSSValue.CssType.PROXY) {
+ throw new CSSProxyValueException();
+ } else if (calc.getPrimitiveType() != Type.EXPRESSION) {
+ break;
+ }
+ return evaluateComponentExpression((CalcValue) calc);
+
default:
}
throw createInvalidRGBComponentUnitDOMException(lu.getLexicalUnitType());
@@ -369,9 +386,28 @@ protected NumericValue createColorComponent(LexicalUnit lu) throws DOMException
case PERCENTAGE:
return new FloatValue(CSSUnit.CSS_PERCENTAGE, lu.getFloatValue());
+ case VAR:
+ case ATTR:
+ throw new CSSProxyValueException();
+
+ case CALC:
+ Value calc = createCalc(lu);
+ if (calc.getCssValueType() == CSSValue.CssType.PROXY) {
+ throw new CSSProxyValueException();
+ } else if (calc.getPrimitiveType() != Type.EXPRESSION) {
+ break;
+ }
+ return evaluateComponentExpression((CalcValue) calc);
+
default:
}
- throw createInvalidRGBComponentUnitDOMException(lu.getLexicalUnitType());
+ throw createInvalidComponentUnitDOMException(lu.getLexicalUnitType());
+ }
+
+ private FloatValue evaluateComponentExpression(CalcValue calc) {
+ PercentageEvaluator eval = new PercentageEvaluator();
+ CSSTypedValue result = eval.evaluateExpression(calc.getExpressionDelegate());
+ return new FloatValue(CSSUnit.CSS_NUMBER, result.getFloatValue(CSSUnit.CSS_NUMBER));
}
/**
@@ -388,4 +424,10 @@ private DOMException createInvalidRGBComponentUnitDOMException(LexicalType lexic
return new DOMException(DOMException.NOT_SUPPORTED_ERR, s);
}
+ private DOMException createInvalidComponentUnitDOMException(LexicalType lexicalType) {
+ Object[] p = { getPropertyName(), lexicalType.toString() };
+ String s = Messages.formatMessage("invalid.color.component.unit", p);
+ return new DOMException(DOMException.NOT_SUPPORTED_ERR, s);
+ }
+
}
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/AbstractValue.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/AbstractValue.java
index e806cdb64..275db095c 100644
--- a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/AbstractValue.java
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/AbstractValue.java
@@ -19,15 +19,11 @@
package io.sf.carte.echosvg.css.engine.value;
import org.w3c.css.om.typed.CSSCounterValue;
-import org.w3c.css.om.unit.CSSUnit;
import org.w3c.dom.DOMException;
/**
- * This class provides an abstract implementation of the Value interface.
+ * This class provides an abstract implementation of the CSSValue interface.
*
- *
* @version $Id$
*/
public abstract class AbstractValue implements Value, Cloneable {
@@ -39,16 +35,6 @@ public CssType getCssValueType() {
return Value.CssType.TYPED;
}
- @Override
- public Type getPrimitiveType() {
- throw createDOMException();
- }
-
- @Override
- public short getCSSUnit() {
- return CSSUnit.CSS_INVALID;
- }
-
@Override
public void setCssText(String cssText) throws DOMException {
throw createDOMException();
@@ -137,9 +123,9 @@ public boolean equals(Object obj) {
return true;
if (obj == null)
return false;
- if (!(obj instanceof Value))
+ if (!(obj instanceof CSSVal))
return false;
- Value other = (Value) obj;
+ CSSVal other = (CSSVal) obj;
return getPrimitiveType() == other.getPrimitiveType();
}
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/AbstractValueFactory.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/AbstractValueFactory.java
index 70d1e007e..520e86b92 100644
--- a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/AbstractValueFactory.java
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/AbstractValueFactory.java
@@ -20,8 +20,8 @@
import org.w3c.dom.DOMException;
+import io.sf.carte.doc.style.css.CSSValue.Type;
import io.sf.carte.doc.style.css.nsac.LexicalUnit;
-import io.sf.carte.echosvg.css.dom.CSSValue.Type;
import io.sf.carte.echosvg.util.ParsedURL;
/**
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/AbstractValueList.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/AbstractValueList.java
index 9dbc762de..7ecd9ef81 100644
--- a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/AbstractValueList.java
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/AbstractValueList.java
@@ -34,7 +34,7 @@ public class AbstractValueList extends ComponentValue implement
/**
* The items.
*/
- private ArrayList items;
+ ArrayList items;
/**
* The list separator.
@@ -50,6 +50,8 @@ public AbstractValueList() {
/**
* Creates a ListValue with the given separator.
+ *
+ * @param s the separator.
*/
public AbstractValueList(char s) {
this(s, 5);
@@ -57,6 +59,9 @@ public AbstractValueList(char s) {
/**
* Creates a ListValue with the given separator and an initial capacity.
+ *
+ * @param s the separator.
+ * @param initialCapacity the initial capacity.
*/
public AbstractValueList(char s, int initialCapacity) {
separator = s;
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/AbstractValueManager.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/AbstractValueManager.java
index 2a6c764f8..8e3db5179 100644
--- a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/AbstractValueManager.java
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/AbstractValueManager.java
@@ -21,7 +21,11 @@
import org.w3c.css.om.unit.CSSUnit;
import org.w3c.dom.DOMException;
-import io.sf.carte.echosvg.css.dom.CSSValue.Type;
+import io.sf.carte.doc.style.css.CSSExpressionValue;
+import io.sf.carte.doc.style.css.CSSValue.Type;
+import io.sf.carte.doc.style.css.nsac.LexicalUnit;
+import io.sf.carte.doc.style.css.property.StyleValue;
+import io.sf.carte.doc.style.css.property.ValueFactory;
import io.sf.carte.echosvg.css.engine.CSSEngine;
import io.sf.carte.echosvg.css.engine.CSSStylableElement;
import io.sf.carte.echosvg.css.engine.StyleMap;
@@ -50,6 +54,41 @@ public Value createStringValue(Type type, String value, CSSEngine engine) throws
throw createDOMException();
}
+ protected Value createCalc(LexicalUnit lu) throws DOMException {
+ LexicalUnit lunit;
+ if (lu.getNextLexicalUnit() != null) {
+ lunit = lu.shallowClone();
+ } else {
+ lunit = lu;
+ }
+ ValueFactory vf = new ValueFactory();
+ StyleValue cssValue = vf.createCSSValue(lunit);
+
+ Type pType = cssValue.getPrimitiveType();
+ if (pType != Type.EXPRESSION) {
+ if (pType == Type.LEXICAL) {
+ if (lunit.getPreviousLexicalUnit() != null || lunit.isParameter()) {
+ throw new CSSProxyValueException();
+ }
+ return createLexicalValue(lunit);
+ }
+ createInvalidLexicalUnitDOMException(lu.getLexicalUnitType());
+ }
+
+ CalcValue calc = new CalcValue((CSSExpressionValue) cssValue) {
+
+ @Override
+ protected FloatValue absoluteValue(CSSStylableElement elt, String pseudo, CSSEngine engine,
+ int idx, StyleMap sm, FloatValue relative) {
+ return (FloatValue) AbstractValueManager.this.computeValue(elt, pseudo, engine, idx, sm,
+ relative);
+ }
+
+ };
+
+ return calc;
+ }
+
/**
* Implements
* {@link ValueManager#computeValue(CSSStylableElement,String,CSSEngine,int,StyleMap,Value)}.
@@ -68,7 +107,7 @@ public Value computeValue(CSSStylableElement elt, String pseudo, CSSEngine engin
}
protected float lengthValue(Value cv) {
- short unit = cv.getCSSUnit();
+ short unit = cv.getUnitType();
if (!CSSUnit.isLengthUnitType(unit) && unit != CSSUnit.CSS_NUMBER) {
throw createDOMException(unit);
}
@@ -85,4 +124,11 @@ protected DOMException createDOMException(int unit) {
return new DOMException(DOMException.INVALID_ACCESS_ERR, s);
}
+ protected Value createLexicalValue(LexicalUnit lu) throws CSSProxyValueException {
+ if (lu.getPreviousLexicalUnit() != null || lu.isParameter()) {
+ throw new CSSProxyValueException();
+ }
+ return new LexicalValue(lu);
+ }
+
}
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/CSSProxyValueException.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/CSSProxyValueException.java
new file mode 100644
index 000000000..4d01e3ae7
--- /dev/null
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/CSSProxyValueException.java
@@ -0,0 +1,37 @@
+/*
+
+ See the NOTICE file distributed with this work for additional
+ information regarding copyright ownership.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ */
+package io.sf.carte.echosvg.css.engine.value;
+
+import org.w3c.dom.DOMException;
+
+/**
+ * A PROXY value was found.
+ *
+ * This class is intended for internal use by this implementation.
+ *
+ */
+public class CSSProxyValueException extends DOMException {
+
+ private static final long serialVersionUID = 1L;
+
+ public CSSProxyValueException() {
+ super(DOMException.INVALID_ACCESS_ERR, "Found a PROXY value.");
+ }
+
+}
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/CSSVal.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/CSSVal.java
new file mode 100644
index 000000000..162e11a8a
--- /dev/null
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/CSSVal.java
@@ -0,0 +1,114 @@
+/*
+
+ See the NOTICE file distributed with this work for additional
+ information regarding copyright ownership.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ */
+package io.sf.carte.echosvg.css.engine.value;
+
+import java.io.IOException;
+
+import org.w3c.css.om.typed.CSSStyleValue;
+import org.w3c.dom.DOMException;
+
+import io.sf.carte.doc.style.css.CSSValueSyntax;
+import io.sf.carte.doc.style.css.CSSValueSyntax.Match;
+import io.sf.carte.util.SimpleWriter;
+
+/**
+ * A gateway value between CSS Typed OM and an internal representation.
+ *
+ * @author See Git history.
+ * @version $Id$
+ */
+public interface CSSVal extends io.sf.carte.doc.style.css.CSSValue, CSSStyleValue {
+
+ /**
+ * If this value is a list or contains components, the number of
+ * CSSStyleValues in the list. The range of valid values of the
+ * indices is 0 to length-1 inclusive.
+ *
+ * @return the number of components, or {@code 0} if this value is not a list
+ * nor does it contain components.
+ */
+ int getLength();
+
+ /**
+ * If this value is a list, give the item corresponding to the requested index.
+ * If there is no item at such index, return {@code null} If this object is not
+ * a list and the index is {@code 0}, return itself.
+ *
+ * @param index the index on the list.
+ * @return the item, or {@code null} if there is no item on that index.
+ */
+ default CSSVal item(int index) {
+ return index == 0 ? this : null;
+ }
+
+ /**
+ * Convenience method that either returns an identifier or throws an exception.
+ *
+ * @exception DOMException INVALID_ACCESS_ERR: Raised if the value doesn't
+ * contain an identifier value.
+ */
+ String getIdentifierValue() throws DOMException;
+
+ /**
+ * If this value can be used where a string is expected, get the value.
+ *
+ * @return the string value, without the commas.
+ * @exception DOMException INVALID_ACCESS_ERR: Raised if the value doesn't
+ * contain a String.
+ */
+ String getStringValue() throws DOMException;
+
+ /**
+ * Convenience method that either returns a String or URI or throws an exception.
+ *
+ * @exception DOMException INVALID_ACCESS_ERR: Raised if the value doesn't
+ * contain a String nor a URI value.
+ */
+ String getURIValue() throws DOMException;
+
+ /**
+ * Convenience method that either returns the float value, if the value is
+ * numeric, or throws an exception.
+ *
+ * @return the float value.
+ */
+ float getFloatValue();
+
+ @Override
+ default void writeCssText(SimpleWriter wri) throws IOException {
+ wri.write(getCssText());
+ }
+
+ @Override
+ default Match matches(CSSValueSyntax syntax) {
+ return Match.PENDING;
+ }
+
+ /**
+ * Create and return a copy of this object.
+ *
+ * If this object is unmodifiable, the clone will be modifiable.
+ *
+ *
+ * @return a modifiable copy of this object.
+ */
+ @Override
+ CSSVal clone();
+
+}
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/CalcValue.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/CalcValue.java
new file mode 100644
index 000000000..4abdc57e9
--- /dev/null
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/CalcValue.java
@@ -0,0 +1,138 @@
+/*
+
+ See the NOTICE file distributed with this work for additional
+ information regarding copyright ownership.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ */
+package io.sf.carte.echosvg.css.engine.value;
+
+import org.w3c.css.om.typed.CSSUnitValue;
+import org.w3c.css.om.unit.CSSUnit;
+import org.w3c.dom.DOMException;
+
+import io.sf.carte.doc.style.css.CSSExpressionValue;
+import io.sf.carte.doc.style.css.CSSTypedValue;
+import io.sf.carte.doc.style.css.property.Evaluator;
+import io.sf.carte.doc.style.css.property.NumberValue;
+import io.sf.carte.echosvg.css.engine.CSSEngine;
+import io.sf.carte.echosvg.css.engine.CSSStylableElement;
+import io.sf.carte.echosvg.css.engine.StyleMap;
+
+/**
+ * {@code calc()} value.
+ *
+ * @author See Git history.
+ * @version $Id$
+ */
+public class CalcValue extends NumericValue {
+
+ private CSSExpressionValue expressionDelegate;
+
+ /**
+ * Creates a new value.
+ */
+ public CalcValue(CSSExpressionValue expr) {
+ super();
+ this.expressionDelegate = expr;
+ }
+
+ @Override
+ public Type getPrimitiveType() {
+ return Type.EXPRESSION;
+ }
+
+ @Override
+ public String getCssText() {
+ return expressionDelegate.getCssText();
+ }
+
+ @Override
+ short getCSSUnit() {
+ return expressionDelegate.computeUnitType();
+ }
+
+ public CSSExpressionValue getExpressionDelegate() {
+ return expressionDelegate;
+ }
+
+ public FloatValue evaluate(CSSStylableElement elt, String pseudo, CSSEngine engine, int idx, StyleMap sm,
+ final short unit) throws DOMException {
+ Evaluator eval = new Evaluator(unit) {
+
+ @Override
+ protected CSSTypedValue absoluteTypedValue(CSSTypedValue typed) {
+ if (CSSUnit.isRelativeLengthUnitType(typed.getUnitType())) {
+ FloatValue relative = new FloatValue(typed.getUnitType(),
+ typed.getFloatValue(typed.getUnitType()));
+ FloatValue abs = CalcValue.this.absoluteValue(elt, pseudo, engine, idx, sm, relative);
+ short u;
+ if (abs.getUnitType() != CSSUnit.CSS_NUMBER) {
+ u = abs.getUnitType();
+ } else {
+ u = unit;
+ }
+ return NumberValue.createCSSNumberValue(u, abs.getFloatValue());
+ } else {
+ return typed;
+ }
+ }
+
+ @Override
+ protected float percentage(CSSTypedValue typed, short resultType) throws DOMException {
+ FloatValue relative = new FloatValue(typed.getUnitType(), typed.getFloatValue(typed.getUnitType()));
+ FloatValue abs = CalcValue.this.absoluteValue(elt, pseudo, engine, idx, sm, relative);
+ return NumberValue.floatValueConversion(abs.getFloatValue(), abs.getUnitType(), resultType);
+ }
+
+ };
+
+ CSSTypedValue typed = eval.evaluateExpression(expressionDelegate);
+ if (typed.getPrimitiveType() != Type.NUMERIC) {
+ throw new DOMException(DOMException.INVALID_STATE_ERR,
+ "Unexpected calc() result: " + typed.getCssText());
+ }
+
+ float f;
+ short u;
+ if (typed.getUnitType() == CSSUnit.CSS_NUMBER) {
+ // Plain number can be interpreted as px or deg according to context
+ u = CSSUnit.CSS_NUMBER;
+ f = typed.getFloatValue(CSSUnit.CSS_NUMBER);
+ } else {
+ u = unit;
+ f = typed.getFloatValue(unit);
+ }
+
+ return new FloatValue(u, f);
+ }
+
+ protected FloatValue absoluteValue(CSSStylableElement elt, String pseudo, CSSEngine engine, int idx,
+ StyleMap sm, FloatValue relative) throws DOMException {
+ return relative;
+ }
+
+ @Override
+ public CSSUnitValue to(String unit) {
+ throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Not supported.");
+ }
+
+ @Override
+ public CalcValue clone() {
+ CalcValue clon = (CalcValue) super.clone();
+ clon.expressionDelegate = expressionDelegate;
+ return clon;
+ }
+
+}
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/ColorFunction.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/ColorFunction.java
index d4012a2b2..99397b5f8 100644
--- a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/ColorFunction.java
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/ColorFunction.java
@@ -167,7 +167,7 @@ public String getCssText() {
* @throws DOMSyntaxException if the value is inadequate for a component.
*/
private NumericValue numericComponent(NumericValue ch) throws DOMSyntaxException {
- if (ch.getCSSUnit() != CSSUnit.CSS_PERCENTAGE && ch.getCSSUnit() != CSSUnit.CSS_NUMBER) {
+ if (ch.getUnitType() != CSSUnit.CSS_PERCENTAGE && ch.getUnitType() != CSSUnit.CSS_NUMBER) {
throw new DOMSyntaxException("color() component must be a number or percentage.");
}
componentize(ch);
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/ColorValue.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/ColorValue.java
index 1d0acfc72..f3c729f54 100644
--- a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/ColorValue.java
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/ColorValue.java
@@ -29,7 +29,7 @@
* @author See Git history.
* @version $Id$
*/
-public abstract class ColorValue extends ComponentValue implements CSSColorValue {
+public abstract class ColorValue extends ComponentValue implements TypedValue, CSSColorValue {
public static final String RGB_FUNCTION = "rgb";
@@ -134,7 +134,7 @@ public void setAlpha(CSSNumericValue alpha) throws DOMSyntaxException {
private void setAlphaChannel(CSSNumericValue alpha) throws DOMSyntaxException {
NumericValue a = (NumericValue) alpha;
- if (a.getCSSUnit() != CSSUnit.CSS_PERCENTAGE && a.getCSSUnit() != CSSUnit.CSS_NUMBER) {
+ if (a.getUnitType() != CSSUnit.CSS_PERCENTAGE && a.getUnitType() != CSSUnit.CSS_NUMBER) {
throw new DOMSyntaxException("Alpha channel must be a number or percentage.");
}
componentize(a);
@@ -144,7 +144,7 @@ private void setAlphaChannel(CSSNumericValue alpha) throws DOMSyntaxException {
}
boolean isOpaque() {
- switch (alpha.getCSSUnit()) {
+ switch (alpha.getUnitType()) {
case CSSUnit.CSS_NUMBER:
return alpha.getFloatValue() == 1f;
case CSSUnit.CSS_PERCENTAGE:
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/ComputedValue.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/ComputedValue.java
index 0fb8ed4b4..0b8fe9080 100644
--- a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/ComputedValue.java
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/ComputedValue.java
@@ -91,8 +91,8 @@ public Type getPrimitiveType() {
}
@Override
- public short getCSSUnit() {
- return computedValue.getCSSUnit();
+ public short getUnitType() {
+ return computedValue.getUnitType();
}
@Override
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/FloatValue.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/FloatValue.java
index 572839a3b..26cb3cef7 100644
--- a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/FloatValue.java
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/FloatValue.java
@@ -28,10 +28,11 @@
import org.w3c.css.om.unit.CSSUnit;
import org.w3c.dom.DOMException;
+import io.sf.carte.doc.style.css.CSSNumberValue;
+import io.sf.carte.doc.style.css.UnitStringToId;
import io.sf.carte.doc.style.css.nsac.CSSParseException;
import io.sf.carte.doc.style.css.nsac.LexicalUnit;
import io.sf.carte.doc.style.css.parser.CSSParser;
-import io.sf.carte.doc.style.css.parser.ParseHelper;
import io.sf.carte.doc.style.css.property.NumberValue;
/**
@@ -40,7 +41,7 @@
* @author See Git history.
* @version $Id$
*/
-public class FloatValue extends NumericValue implements CSSUnitValue {
+public class FloatValue extends NumericValue implements CSSNumberValue, CSSUnitValue {
/**
* Returns the CSS text associated with the given type/value pair.
@@ -80,6 +81,16 @@ public static FloatValue createConstant(short unit, float value) {
*/
private short unitType;
+ /**
+ * True if this value is the result of a calculation
+ */
+ private boolean calculated = false;
+
+ /**
+ * True if this number is in the same unit as was specified.
+ */
+ private boolean specified = true;
+
/**
* Creates a new value.
*
@@ -100,7 +111,7 @@ public Type getPrimitiveType() {
}
@Override
- public short getCSSUnit() {
+ public short getUnitType() {
return unitType;
}
@@ -181,12 +192,51 @@ public void setCssText(String cssText) throws DOMException {
}
}
+ @Override
+ public boolean isCalculatedNumber() {
+ return calculated;
+ }
+
/**
- * Returns a printable representation of this value.
+ * Sets whether this number is the result of a calculation.
+ *
+ * @param calculated {@code true} if this number was calculated.
*/
@Override
- public String toString() {
- return getCssText();
+ public void setCalculatedNumber(boolean calculated) {
+ this.calculated = calculated;
+ this.specified = this.specified && !calculated;
+ }
+
+ @Override
+ public void setExpectInteger() throws DOMException {
+ if (getUnitType() != CSSUnit.CSS_NUMBER) {
+ super.setExpectInteger();
+ } else if (calculated) {
+ floatValue = Math.round(floatValue);
+ } else if (!isInteger()) {
+ super.setExpectInteger();
+ }
+ }
+
+ private boolean isInteger() {
+ return Math.rint(floatValue) == floatValue;
+ }
+
+ @Override
+ public void roundToInteger() throws DOMException {
+ setExpectInteger();
+ floatValue = Math.round(floatValue);
+ }
+
+ @Override
+ public boolean isNegativeNumber() {
+ return floatValue < 0f;
+ }
+
+ @Override
+ public boolean isNumberZero() {
+ return floatValue == 0f;
}
@Override
@@ -206,81 +256,21 @@ public boolean equals(Object obj) {
if (!(obj instanceof Value))
return false;
Value other = (Value) obj;
- return other.getCSSUnit() == unitType
+ return other.getUnitType() == unitType
&& Float.floatToIntBits(floatValue) == Float.floatToIntBits(other.getFloatValue());
}
@Override
public CSSUnitValue to(String unit) {
- short destUnit = ParseHelper.unitFromString(unit);
+ short destUnit = UnitStringToId.unitFromString(unit);
float destValue = NumberValue.floatValueConversion(floatValue, unitType, destUnit);
FloatValue toVal = new FloatValue(destUnit, destValue);
return toVal;
}
@Override
- public CSSNumericType type() {
- return new NumericType();
- }
-
- class NumericType implements CSSNumericType {
-
- @Override
- public int getLength() {
- return CSSUnit.isLengthUnitType(unitType) ? 1 : 0;
- }
-
- @Override
- public int getAngle() {
- return CSSUnit.isAngleUnitType(unitType) ? 1 : 0;
- }
-
- @Override
- public int getTime() {
- return CSSUnit.isTimeUnitType(unitType) ? 1 : 0;
- }
-
- @Override
- public int getFrequency() {
- return unitType == CSSUnit.CSS_HZ || unitType == CSSUnit.CSS_KHZ ? 1 : 0;
- }
-
- @Override
- public int getResolution() {
- return CSSUnit.isResolutionUnitType(unitType) ? 1 : 0;
- }
-
- @Override
- public int getFlex() {
- return unitType == CSSUnit.CSS_FR ? 1 : 0;
- }
-
- @Override
- public int getPercent() {
- return unitType == CSSUnit.CSS_PERCENTAGE ? 1 : 0;
- }
-
- @Override
- public CSSNumericBaseType getPercentHint() {
- CSSNumericBaseType baseType = null;
- if (CSSUnit.isLengthUnitType(unitType)) {
- baseType = CSSNumericBaseType.length;
- } else if (unitType == CSSUnit.CSS_PERCENTAGE) {
- baseType = CSSNumericBaseType.percent;
- } else if (CSSUnit.isTimeUnitType(unitType)) {
- baseType = CSSNumericBaseType.time;
- } else if (CSSUnit.isAngleUnitType(unitType)) {
- baseType = CSSNumericBaseType.angle;
- } else if (CSSUnit.isResolutionUnitType(unitType)) {
- baseType = CSSNumericBaseType.resolution;
- } else if (unitType == CSSUnit.CSS_HZ || unitType == CSSUnit.CSS_KHZ) {
- baseType = CSSNumericBaseType.frequency;
- } else if (unitType == CSSUnit.CSS_FR) {
- baseType = CSSNumericBaseType.flex;
- }
- return baseType;
- }
-
+ short getCSSUnit() {
+ return unitType;
}
@Override
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/IdentifierManager.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/IdentifierManager.java
index 2b54976c6..e59010bf2 100644
--- a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/IdentifierManager.java
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/IdentifierManager.java
@@ -22,8 +22,8 @@
import org.w3c.dom.DOMException;
+import io.sf.carte.doc.style.css.CSSValue.Type;
import io.sf.carte.doc.style.css.nsac.LexicalUnit;
-import io.sf.carte.echosvg.css.dom.CSSValue.Type;
import io.sf.carte.echosvg.css.engine.CSSEngine;
/**
@@ -44,9 +44,6 @@ public abstract class IdentifierManager extends AbstractValueManager {
@Override
public Value createValue(LexicalUnit lu, CSSEngine engine) throws DOMException {
switch (lu.getLexicalUnitType()) {
- case INHERIT:
- return ValueConstants.INHERIT_VALUE;
-
case IDENT:
String s = lu.getStringValue().toLowerCase(Locale.ROOT).intern();
Object v = getIdentifiers().get(s);
@@ -55,6 +52,22 @@ public Value createValue(LexicalUnit lu, CSSEngine engine) throws DOMException {
}
return (Value) v;
+ case INHERIT:
+ return ValueConstants.INHERIT_VALUE;
+
+ case UNSET:
+ return UnsetValue.getInstance();
+
+ case REVERT:
+ return RevertValue.getInstance();
+
+ case INITIAL:
+ return getDefaultValue();
+
+ case VAR:
+ case ATTR:
+ return createLexicalValue(lu);
+
default:
throw createInvalidLexicalUnitDOMException(lu.getLexicalUnitType());
}
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/ImmutableUnitValue.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/ImmutableUnitValue.java
index dde6aadfc..c54bcbb63 100644
--- a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/ImmutableUnitValue.java
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/ImmutableUnitValue.java
@@ -47,7 +47,7 @@ public void setValue(String cssText) throws DOMException {
@Override
public FloatValue clone() {
- return new FloatValue(getCSSUnit(), getFloatValue());
+ return new FloatValue(getUnitType(), getFloatValue());
}
}
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/InheritValue.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/InheritValue.java
index 3b036b598..711d045be 100644
--- a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/InheritValue.java
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/InheritValue.java
@@ -18,9 +18,6 @@
*/
package io.sf.carte.echosvg.css.engine.value;
-import org.w3c.api.DOMTypeException;
-import org.w3c.css.om.typed.CSSKeywordValue;
-
/**
* This singleton class represents the 'inherit' value.
*
@@ -30,7 +27,7 @@
*
+ */
+public interface PropertyDefinition {
+
+ /**
+ * Gets the property name.
+ *
+ * @return the property name.
+ */
+ String getName();
+
+ /**
+ * Whether the property inherits or not.
+ *
+ * @return {@code true} if the property inherits.
+ */
+ boolean inherits();
+
+ /**
+ * The initial value associated with the property.
+ *
+ * @return the initial value, or {@code null} if none was specified.
+ */
+ LexicalUnit getInitialValue();
+
+ /**
+ * The syntax associated with the property.
+ *
+ * If the syntax descriptor was not recognized, {@code *} will be used.
+ *
+ *
+ * @return the syntax. Cannot be {@code null}.
+ */
+ CSSValueSyntax getSyntax();
+
+}
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/RGBColorValue.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/RGBColorValue.java
index e53a9d73a..3145b2f40 100644
--- a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/RGBColorValue.java
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/RGBColorValue.java
@@ -173,9 +173,9 @@ public static RGBColorValue createLegacy(NumericValue r, NumericValue g, Numeric
g = legacyRange(g);
b = legacyRange(b);
RGBColorValue rgb = new RGBColorValue(r, g, b);
- rgb.pcntSpecified = r.getCSSUnit() == CSSUnit.CSS_PERCENTAGE
- || g.getCSSUnit() == CSSUnit.CSS_PERCENTAGE
- || b.getCSSUnit() == CSSUnit.CSS_PERCENTAGE;
+ rgb.pcntSpecified = r.getUnitType() == CSSUnit.CSS_PERCENTAGE
+ || g.getUnitType() == CSSUnit.CSS_PERCENTAGE
+ || b.getUnitType() == CSSUnit.CSS_PERCENTAGE;
return rgb;
}
@@ -189,18 +189,18 @@ public static RGBColorValue createLegacy(NumericValue r, NumericValue g, Numeric
*/
private static NumericValue constantLegacyRange(NumericValue ch)
throws DOMSyntaxException, IllegalArgumentException {
- if (ch.getCSSUnit() == CSSUnit.CSS_NUMBER) {
+ if (ch.getUnitType() == CSSUnit.CSS_NUMBER) {
if (ch.getPrimitiveType() == Type.NUMERIC) {
ch = new ImmutableUnitValue(CSSUnit.CSS_NUMBER, ch.getFloatValue() / 255f);
} else {
throw new IllegalArgumentException("Cannot normalize value to [0,1] now: " + ch.getCssText());
}
- } else if (ch.getCSSUnit() != CSSUnit.CSS_PERCENTAGE) {
+ } else if (ch.getUnitType() != CSSUnit.CSS_PERCENTAGE) {
throw new DOMSyntaxException("RGB component must be a number or percentage, not a "
- + CSSUnit.dimensionUnitString(ch.getCSSUnit()) + '.');
+ + CSSUnit.dimensionUnitString(ch.getUnitType()) + '.');
}
if (ch.handler != null) {
- ch = new ImmutableUnitValue(ch.getCSSUnit(), ch.getFloatValue());
+ ch = new ImmutableUnitValue(ch.getUnitType(), ch.getFloatValue());
}
return ch;
}
@@ -215,15 +215,15 @@ private static NumericValue constantLegacyRange(NumericValue ch)
*/
private static NumericValue legacyRange(NumericValue ch)
throws DOMSyntaxException, IllegalArgumentException {
- if (ch.getCSSUnit() == CSSUnit.CSS_NUMBER) {
+ if (ch.getUnitType() == CSSUnit.CSS_NUMBER) {
if (ch.getPrimitiveType() == Type.NUMERIC) {
ch.setFloatValue(ch.getFloatValue() / 255f);
} else {
throw new IllegalArgumentException("Cannot normalize value to [0,1] now: " + ch.getCssText());
}
- } else if (ch.getCSSUnit() != CSSUnit.CSS_PERCENTAGE) {
+ } else if (ch.getUnitType() != CSSUnit.CSS_PERCENTAGE) {
throw new DOMSyntaxException("RGB component must be a number or percentage, not a "
- + CSSUnit.dimensionUnitString(ch.getCSSUnit()) + '.');
+ + CSSUnit.dimensionUnitString(ch.getUnitType()) + '.');
}
return ch;
}
@@ -279,7 +279,7 @@ private String rgbComponentText(NumericValue comp, DecimalFormat df) {
}
float f;
- if (comp.getCSSUnit() == CSSUnit.CSS_NUMBER) {
+ if (comp.getUnitType() == CSSUnit.CSS_NUMBER) {
f = comp.getFloatValue() * 255f;
} else {
f = comp.getFloatValue() * 2.55f;
@@ -288,7 +288,7 @@ private String rgbComponentText(NumericValue comp, DecimalFormat df) {
}
private String alphaComponentText(NumericValue alpha, DecimalFormat df) {
- if (alphaPcntSpecified || alpha.getCSSUnit() == CSSUnit.CSS_NUMBER) {
+ if (alphaPcntSpecified || alpha.getUnitType() == CSSUnit.CSS_NUMBER) {
return alpha.getCssText();
}
@@ -320,7 +320,7 @@ public NumericValue getB() {
*
* @return the red component.
*/
- public Value getRed() {
+ public NumericValue getRed() {
return red;
}
@@ -329,7 +329,7 @@ public Value getRed() {
*
* @return the green component.
*/
- public Value getGreen() {
+ public NumericValue getGreen() {
return green;
}
@@ -338,7 +338,7 @@ public Value getGreen() {
*
* @return the blue component.
*/
- public Value getBlue() {
+ public NumericValue getBlue() {
return blue;
}
@@ -354,7 +354,7 @@ public void setR(double r) {
public void setR(CSSNumericValue r) throws DOMSyntaxException {
red = component(r);
componentChanged(red);
- pcntSpecified = red.getCSSUnit() == CSSUnit.CSS_PERCENTAGE;
+ pcntSpecified = red.getUnitType() == CSSUnit.CSS_PERCENTAGE;
}
/**
@@ -366,9 +366,9 @@ public void setR(CSSNumericValue r) throws DOMSyntaxException {
*/
private NumericValue component(CSSNumericValue c) throws DOMSyntaxException {
NumericValue ch = (NumericValue) c;
- if (ch.getCSSUnit() != CSSUnit.CSS_PERCENTAGE && ch.getCSSUnit() != CSSUnit.CSS_NUMBER) {
+ if (ch.getUnitType() != CSSUnit.CSS_PERCENTAGE && ch.getUnitType() != CSSUnit.CSS_NUMBER) {
throw new DOMSyntaxException("RGB component must be a number or percentage, not a "
- + CSSUnit.dimensionUnitString(ch.getCSSUnit()) + '.');
+ + CSSUnit.dimensionUnitString(ch.getUnitType()) + '.');
}
if (ch.handler != null) {
ch = ch.clone();
@@ -411,7 +411,7 @@ public int getLength() throws DOMException {
}
@Override
- public Value item(int index) throws DOMException {
+ public NumericValue item(int index) throws DOMException {
switch (index) {
case 0:
return getR();
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/RectManager.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/RectManager.java
index 8a5d79264..e32fd6cb3 100644
--- a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/RectManager.java
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/RectManager.java
@@ -21,8 +21,8 @@
import org.w3c.css.om.unit.CSSUnit;
import org.w3c.dom.DOMException;
+import io.sf.carte.doc.style.css.CSSValue.Type;
import io.sf.carte.doc.style.css.nsac.LexicalUnit;
-import io.sf.carte.echosvg.css.dom.CSSValue.Type;
import io.sf.carte.echosvg.css.engine.CSSEngine;
import io.sf.carte.echosvg.css.engine.CSSStylableElement;
import io.sf.carte.echosvg.css.engine.StyleMap;
@@ -49,34 +49,53 @@ public abstract class RectManager extends LengthManager {
* Implements {@link ValueManager#createValue(LexicalUnit,CSSEngine)}.
*/
@Override
- public Value createValue(LexicalUnit lu, CSSEngine engine) throws DOMException {
- switch (lu.getLexicalUnitType()) {
+ public Value createValue(final LexicalUnit lunit, CSSEngine engine) throws DOMException {
+ switch (lunit.getLexicalUnitType()) {
case FUNCTION:
- if (!lu.getFunctionName().equalsIgnoreCase("rect")) {
+ // This case could be removed
+ if (!lunit.getFunctionName().equalsIgnoreCase("rect")) {
break;
}
case RECT_FUNCTION:
- lu = lu.getParameters();
- Value top = createRectComponent(lu);
- lu = lu.getNextLexicalUnit();
- if (lu == null || lu.getLexicalUnitType() != LexicalUnit.LexicalType.OPERATOR_COMMA) {
- throw createMalformedRectDOMException();
- }
- lu = lu.getNextLexicalUnit();
- Value right = createRectComponent(lu);
- lu = lu.getNextLexicalUnit();
- if (lu == null || lu.getLexicalUnitType() != LexicalUnit.LexicalType.OPERATOR_COMMA) {
- throw createMalformedRectDOMException();
+ LexicalUnit lu = lunit.getParameters();
+ try {
+ Value top = createRectComponent(lu);
+ lu = lu.getNextLexicalUnit();
+ if (lu == null || lu.getLexicalUnitType() != LexicalUnit.LexicalType.OPERATOR_COMMA) {
+ throw createMalformedRectDOMException();
+ }
+ lu = lu.getNextLexicalUnit();
+ Value right = createRectComponent(lu);
+ lu = lu.getNextLexicalUnit();
+ if (lu == null || lu.getLexicalUnitType() != LexicalUnit.LexicalType.OPERATOR_COMMA) {
+ throw createMalformedRectDOMException();
+ }
+ lu = lu.getNextLexicalUnit();
+ Value bottom = createRectComponent(lu);
+ lu = lu.getNextLexicalUnit();
+ if (lu == null || lu.getLexicalUnitType() != LexicalUnit.LexicalType.OPERATOR_COMMA) {
+ throw createMalformedRectDOMException();
+ }
+ lu = lu.getNextLexicalUnit();
+ Value left = createRectComponent(lu);
+ return new RectValue(top, right, bottom, left);
+ } catch (CSSProxyValueException e) {
+ return createLexicalValue(lunit);
}
- lu = lu.getNextLexicalUnit();
- Value bottom = createRectComponent(lu);
- lu = lu.getNextLexicalUnit();
- if (lu == null || lu.getLexicalUnitType() != LexicalUnit.LexicalType.OPERATOR_COMMA) {
- throw createMalformedRectDOMException();
- }
- lu = lu.getNextLexicalUnit();
- Value left = createRectComponent(lu);
- return new RectValue(top, right, bottom, left);
+
+ case UNSET:
+ return UnsetValue.getInstance();
+
+ case REVERT:
+ return RevertValue.getInstance();
+
+ case INITIAL:
+ return getDefaultValue();
+
+ case VAR:
+ case ATTR:
+ return createLexicalValue(lunit);
+
default:
break;
}
@@ -90,14 +109,26 @@ private Value createRectComponent(LexicalUnit lu) throws DOMException {
return ValueConstants.AUTO_VALUE;
}
break;
+
case DIMENSION:
return createLength(lu);
+
case INTEGER:
return new FloatValue(CSSUnit.CSS_NUMBER, lu.getIntegerValue());
+
case REAL:
return new FloatValue(CSSUnit.CSS_NUMBER, lu.getFloatValue());
+
case PERCENTAGE:
return new FloatValue(CSSUnit.CSS_PERCENTAGE, lu.getFloatValue());
+
+ case VAR:
+ case ATTR:
+ throw new CSSProxyValueException();
+
+ case CALC:
+ return createCalc(lu);
+
default:
break;
}
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/RectValue.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/RectValue.java
index f6dd3d454..b48bb532b 100644
--- a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/RectValue.java
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/RectValue.java
@@ -113,7 +113,7 @@ void setTop(Value top) {
* @throws DOMSyntaxException if the value is inadequate for a component.
*/
Value component(Value c) throws DOMSyntaxException {
- short unit = c.getCSSUnit();
+ short unit = c.getUnitType();
if (unit != CSSUnit.CSS_PERCENTAGE && unit != CSSUnit.CSS_NUMBER
&& !CSSUnit.isLengthUnitType(unit) && c.getPrimitiveType() != Type.IDENT) {
throw new DOMSyntaxException("rect() component must be a length or percentage.");
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/RevertValue.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/RevertValue.java
new file mode 100644
index 000000000..b69367d7c
--- /dev/null
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/RevertValue.java
@@ -0,0 +1,62 @@
+/*
+
+ See the NOTICE file distributed with this work for additional
+ information regarding copyright ownership.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ */
+package io.sf.carte.echosvg.css.engine.value;
+
+/**
+ * This singleton class represents the 'revert' value.
+ *
+ */
+public final class RevertValue extends KeywordValue {
+
+ /**
+ * The only instance of this class.
+ */
+ private static final RevertValue INSTANCE = new RevertValue();
+
+ /**
+ * Creates a new UnsetValue object.
+ */
+ RevertValue() {
+ }
+
+ @Override
+ public String getValue() {
+ return "revert";
+ }
+
+ @Override
+ public Type getPrimitiveType() {
+ return Type.REVERT;
+ }
+
+ @Override
+ public RevertValue clone() {
+ return INSTANCE;
+ }
+
+ /**
+ * Get the instance of {@code revert}.
+ *
+ * @return the instance of {@code revert}.
+ */
+ public static Value getInstance() {
+ return INSTANCE;
+ }
+
+}
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/ShorthandManager.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/ShorthandManager.java
index 3d60ecada..6568f9d74 100644
--- a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/ShorthandManager.java
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/ShorthandManager.java
@@ -27,8 +27,10 @@
* This interface represents the objects which provide support for shorthand
* properties.
*
- * @author Stephane Hillion
- * @author For later modifications, see Git history.
+ *
+ * Original author: Stephane Hillion.
+ * For later modifications, see Git history.
+ *
* @version $Id$
*/
public interface ShorthandManager {
@@ -53,7 +55,7 @@ public interface ShorthandManager {
*
* @param eng The current CSSEngine.
* @param ph The property handler to use.
- * @param lu The SAC lexical unit used to create the value.
+ * @param lu The NSAC lexical unit used to create the value.
* @param imp The property priority.
*/
void setValues(CSSEngine eng, PropertyHandler ph, LexicalUnit lu, boolean imp) throws DOMException;
@@ -65,6 +67,17 @@ interface PropertyHandler {
void property(String name, LexicalUnit value, boolean important);
+ /**
+ * Process a longhand value that points to a shorthand that is pending lexical
+ * substitution.
+ *
+ * @param name the longhand property name.
+ * @param value the pending value that contains the shorthand's lexical
+ * value.
+ * @param important the priority.
+ */
+ void pendingValue(String name, PendingValue value, boolean important);
+
}
}
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/TypedValue.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/TypedValue.java
new file mode 100644
index 000000000..bd4193caa
--- /dev/null
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/TypedValue.java
@@ -0,0 +1,78 @@
+/*
+
+ See the NOTICE file distributed with this work for additional
+ information regarding copyright ownership.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ */
+package io.sf.carte.echosvg.css.engine.value;
+
+import org.w3c.css.om.unit.CSSUnit;
+import org.w3c.dom.DOMException;
+
+import io.sf.carte.doc.style.css.RGBAColor;
+import io.sf.carte.doc.style.css.property.NumberValue;
+
+/**
+ * A gateway value between Typed OM and its internal representation.
+ *
+ * @version $Id$
+ */
+public interface TypedValue extends Value, io.sf.carte.doc.style.css.CSSTypedValue {
+
+ @Override
+ default short getUnitType() {
+ return CSSUnit.CSS_INVALID;
+ }
+
+ @Override
+ default void setExpectInteger() throws DOMException {
+ throw new DOMException(DOMException.TYPE_MISMATCH_ERR,
+ "Expected an integer, found type " + getPrimitiveType());
+ }
+
+ @Override
+ default void setFloatValue(short unitType, float floatValue) throws DOMException {
+ setFloatValue(NumberValue.floatValueConversion(floatValue, unitType, getUnitType()));
+ }
+
+ @Override
+ default float getFloatValue(short unitType) throws DOMException {
+ return NumberValue.floatValueConversion(getFloatValue(), getUnitType(), unitType);
+ }
+
+ @Override
+ default void setStringValue(Type stringType, String stringValue) throws DOMException {
+ throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Please use setValue()");
+ }
+
+ @Override
+ default RGBAColor toRGBColor() throws DOMException {
+ throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Please use getColorValue()");
+ }
+
+ @Override
+ default boolean isCalculatedNumber() {
+ return false;
+ }
+
+ @Override
+ default boolean isNumberZero() {
+ return false;
+ }
+
+ @Override
+ TypedValue clone();
+
+}
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/UnsetValue.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/UnsetValue.java
new file mode 100644
index 000000000..a8f0ff68c
--- /dev/null
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/UnsetValue.java
@@ -0,0 +1,62 @@
+/*
+
+ See the NOTICE file distributed with this work for additional
+ information regarding copyright ownership.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ */
+package io.sf.carte.echosvg.css.engine.value;
+
+/**
+ * This singleton class represents the 'unset' value.
+ *
+ */
+public final class UnsetValue extends KeywordValue {
+
+ /**
+ * The only instance of this class.
+ */
+ private static final UnsetValue INSTANCE = new UnsetValue();
+
+ /**
+ * Creates a new UnsetValue object.
+ */
+ UnsetValue() {
+ }
+
+ @Override
+ public String getValue() {
+ return "unset";
+ }
+
+ @Override
+ public Type getPrimitiveType() {
+ return Type.UNSET;
+ }
+
+ @Override
+ public UnsetValue clone() {
+ return INSTANCE;
+ }
+
+ /**
+ * Get the instance of {@code unset}.
+ *
+ * @return the instance of {@code unset}.
+ */
+ public static Value getInstance() {
+ return INSTANCE;
+ }
+
+}
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/Value.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/Value.java
index c5f71d553..4c94c2686 100644
--- a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/Value.java
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/Value.java
@@ -19,17 +19,62 @@
package io.sf.carte.echosvg.css.engine.value;
import org.w3c.css.om.typed.CSSCounterValue;
+import org.w3c.css.om.typed.CSSStyleValue;
+import org.w3c.css.om.unit.CSSUnit;
import org.w3c.dom.DOMException;
-import io.sf.carte.echosvg.css.dom.CSSValue;
-
/**
* This interface represents a property value.
*
* @author See Git history.
* @version $Id$
*/
-public interface Value extends CSSValue {
+public interface Value extends CSSVal, CSSStyleValue {
+
+ /**
+ * Gets the css unit as in CSS4J's {@code CSSUnit}.
+ *
+ * If the value has no valid CSS unit, returns {@code CSSUnit.CSS_INVALID}.
+ *
+ *
+ * @return the css unit as in CSS4J's {@code CSSUnit}.
+ */
+ default short getUnitType() {
+ return CSSUnit.CSS_INVALID;
+ }
+
+ /**
+ * Set the modification handler.
+ *
+ * @param handler the modification handler.
+ */
+ void setModificationHandler(ValueModificationHandler handler);
+
+ /**
+ * Get the modification handler.
+ *
+ * @return the modification handler, or {@code null} if there is no handler.
+ */
+ ValueModificationHandler getModificationHandler();
+
+ /**
+ * Is this value a component?
+ *
+ * @return {@code true} if the value is a component.
+ */
+ default boolean isComponent() {
+ return false;
+ }
+
+ /**
+ * Do this value represent the given identifier?
+ *
+ * @param internedIdent the interned identifier string.
+ * @return {@code true} if the value is a component.
+ */
+ default boolean isIdentifier(String internedIdent) {
+ return false;
+ }
/**
* Convenience method that either returns an identifier or throws an exception.
@@ -43,6 +88,14 @@ default String getIdentifier() throws DOMException {
return getIdentifierValue();
}
+ /**
+ * If this value is a unit value, set the float value.
+ *
+ * @param value the new value, in the current unit.
+ * @throws DOMException if the value is not a unit value.
+ */
+ void setFloatValue(float value) throws DOMException;
+
/**
* If this value is a list, give the item corresponding to the requested index.
* If there is no item at such index, return {@code null} If this object is not
@@ -81,47 +134,6 @@ default Value item(int index) {
*/
ColorValue getColorValue() throws DOMException;
- /**
- * If this value is a unit value, set the float value.
- *
- * @param value the new value, in the current unit.
- * @throws DOMException if the value is not a unit value.
- */
- void setFloatValue(float value) throws DOMException;
-
- /**
- * Set the modification handler.
- *
- * @param handler the modification handler.
- */
- void setModificationHandler(ValueModificationHandler handler);
-
- /**
- * Get the modification handler.
- *
- * @return the modification handler, or {@code null} if there is no handler.
- */
- ValueModificationHandler getModificationHandler();
-
- /**
- * Is this value a component?
- *
- * @return {@code true} if the value is a component.
- */
- default boolean isComponent() {
- return false;
- }
-
- /**
- * Do this value represent the given identifier?
- *
- * @param internedIdent the interned identifier string.
- * @return {@code true} if the value is a component.
- */
- default boolean isIdentifier(String internedIdent) {
- return false;
- }
-
/**
* Create and return a copy of this object.
*
@@ -130,6 +142,7 @@ default boolean isIdentifier(String internedIdent) {
*
* @return a modifiable copy of this object.
*/
+ @Override
Value clone();
}
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/ValueConstants.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/ValueConstants.java
index 6a03e46bc..2a604c578 100644
--- a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/ValueConstants.java
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/ValueConstants.java
@@ -20,6 +20,7 @@
import org.w3c.css.om.unit.CSSUnit;
+import io.sf.carte.doc.style.css.nsac.LexicalUnit;
import io.sf.carte.echosvg.util.CSSConstants;
/**
@@ -101,7 +102,7 @@ public interface ValueConstants {
/**
* The 'inherit' value.
*/
- Value INHERIT_VALUE = InheritValue.INSTANCE;
+ Value INHERIT_VALUE = InheritValue.getInstance();
/**
* The 'all' keyword.
@@ -828,4 +829,9 @@ public interface ValueConstants {
*/
Value TRANSPARENT_RGB_VALUE = RGBColorValue.createConstant(NUMBER_0, NUMBER_0, NUMBER_0, NUMBER_0);
+ /**
+ * A lexical unit with value zero.
+ */
+ LexicalUnit ZERO_LEXICAL_UNIT = LexicalHelper.parsePropertyValue("0");
+
}
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/ValueManager.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/ValueManager.java
index 8fee9a3a8..4eb295fc7 100644
--- a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/ValueManager.java
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/ValueManager.java
@@ -21,8 +21,8 @@
import org.w3c.dom.DOMException;
+import io.sf.carte.doc.style.css.CSSValue.Type;
import io.sf.carte.doc.style.css.nsac.LexicalUnit;
-import io.sf.carte.echosvg.css.dom.CSSValue.Type;
import io.sf.carte.echosvg.css.engine.CSSEngine;
import io.sf.carte.echosvg.css.engine.CSSStylableElement;
import io.sf.carte.echosvg.css.engine.StyleMap;
@@ -59,6 +59,19 @@ public interface ValueManager {
*/
boolean isAdditiveProperty();
+ /**
+ * Allows URL values.
+ *
+ * If this property accepts URL values, then {@code attr()} values cannot be
+ * used.
+ *
+ *
+ * @return {@code true} if URL values are allowed by this property.
+ */
+ default boolean allowsURL() {
+ return false;
+ }
+
/**
* Returns the type of value this manager handles. This should be one of the
* TYPE_* constants defined in {@link io.sf.carte.echosvg.util.SVGTypes}.
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/css2/ClipManager.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/css2/ClipManager.java
index d40f3c4c2..6b740ce7b 100644
--- a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/css2/ClipManager.java
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/css2/ClipManager.java
@@ -20,11 +20,12 @@
import org.w3c.dom.DOMException;
+import io.sf.carte.doc.style.css.CSSValue.Type;
import io.sf.carte.doc.style.css.nsac.LexicalUnit;
-import io.sf.carte.echosvg.css.dom.CSSValue.Type;
import io.sf.carte.echosvg.css.engine.CSSEngine;
-import io.sf.carte.echosvg.css.engine.value.InheritValue;
import io.sf.carte.echosvg.css.engine.value.RectManager;
+import io.sf.carte.echosvg.css.engine.value.RevertValue;
+import io.sf.carte.echosvg.css.engine.value.UnsetValue;
import io.sf.carte.echosvg.css.engine.value.Value;
import io.sf.carte.echosvg.css.engine.value.ValueConstants;
import io.sf.carte.echosvg.css.engine.value.ValueManager;
@@ -96,13 +97,28 @@ public Value getDefaultValue() {
@Override
public Value createValue(LexicalUnit lu, CSSEngine engine) throws DOMException {
switch (lu.getLexicalUnitType()) {
- case INHERIT:
- return InheritValue.INSTANCE;
-
case IDENT:
if (lu.getStringValue().equalsIgnoreCase(CSSConstants.CSS_AUTO_VALUE)) {
return ValueConstants.AUTO_VALUE;
}
+ break;
+
+ case INHERIT:
+ return ValueConstants.INHERIT_VALUE;
+
+ case UNSET:
+ return UnsetValue.getInstance();
+
+ case REVERT:
+ return RevertValue.getInstance();
+
+ case INITIAL:
+ return getDefaultValue();
+
+ case VAR:
+ case ATTR:
+ return createLexicalValue(lu);
+
default:
break;
}
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/css2/CursorManager.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/css2/CursorManager.java
index 3a393a584..7a3698bce 100644
--- a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/css2/CursorManager.java
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/css2/CursorManager.java
@@ -22,15 +22,17 @@
import org.w3c.dom.DOMException;
+import io.sf.carte.doc.style.css.CSSValue.Type;
import io.sf.carte.doc.style.css.nsac.LexicalUnit;
-import io.sf.carte.echosvg.css.dom.CSSValue.Type;
import io.sf.carte.echosvg.css.engine.CSSEngine;
import io.sf.carte.echosvg.css.engine.CSSStylableElement;
import io.sf.carte.echosvg.css.engine.StyleMap;
import io.sf.carte.echosvg.css.engine.value.AbstractValueManager;
import io.sf.carte.echosvg.css.engine.value.ListValue;
+import io.sf.carte.echosvg.css.engine.value.RevertValue;
import io.sf.carte.echosvg.css.engine.value.StringMap;
import io.sf.carte.echosvg.css.engine.value.URIValue;
+import io.sf.carte.echosvg.css.engine.value.UnsetValue;
import io.sf.carte.echosvg.css.engine.value.Value;
import io.sf.carte.echosvg.css.engine.value.ValueConstants;
import io.sf.carte.echosvg.css.engine.value.ValueManager;
@@ -95,6 +97,11 @@ public boolean isAdditiveProperty() {
return false;
}
+ @Override
+ public boolean allowsURL() {
+ return true;
+ }
+
/**
* Implements {@link ValueManager#getPropertyType()}.
*/
@@ -123,12 +130,10 @@ public Value getDefaultValue() {
* Implements {@link ValueManager#createValue(LexicalUnit,CSSEngine)}.
*/
@Override
- public Value createValue(LexicalUnit lu, CSSEngine engine) throws DOMException {
+ public Value createValue(final LexicalUnit lunit, CSSEngine engine) throws DOMException {
ListValue result = new ListValue();
- switch (lu.getLexicalUnitType()) {
- case INHERIT:
- return ValueConstants.INHERIT_VALUE;
-
+ LexicalUnit lu = lunit;
+ switch (lunit.getLexicalUnitType()) {
case URI:
do {
result.append(
@@ -138,6 +143,9 @@ public Value createValue(LexicalUnit lu, CSSEngine engine) throws DOMException {
throw createMalformedLexicalUnitDOMException();
}
if (lu.getLexicalUnitType() != LexicalUnit.LexicalType.OPERATOR_COMMA) {
+ if (lu.getLexicalUnitType() == LexicalUnit.LexicalType.VAR) {
+ return createLexicalValue(lunit);
+ }
throw createInvalidLexicalUnitDOMException(lu.getLexicalUnitType());
}
lu = lu.getNextLexicalUnit();
@@ -146,6 +154,9 @@ public Value createValue(LexicalUnit lu, CSSEngine engine) throws DOMException {
}
} while (lu.getLexicalUnitType() == LexicalUnit.LexicalType.URI);
if (lu.getLexicalUnitType() != LexicalUnit.LexicalType.IDENT) {
+ if (lu.getLexicalUnitType() == LexicalUnit.LexicalType.VAR) {
+ return createLexicalValue(lunit);
+ }
throw createInvalidLexicalUnitDOMException(lu.getLexicalUnitType());
}
// Fall through...
@@ -159,6 +170,22 @@ public Value createValue(LexicalUnit lu, CSSEngine engine) throws DOMException {
result.append((Value) v);
lu = lu.getNextLexicalUnit();
break;
+
+ case INHERIT:
+ return ValueConstants.INHERIT_VALUE;
+
+ case UNSET:
+ return UnsetValue.getInstance();
+
+ case REVERT:
+ return RevertValue.getInstance();
+
+ case INITIAL:
+ return getDefaultValue();
+
+ case VAR:
+ return createLexicalValue(lunit);
+
default:
break;
}
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/css2/FontFamilyManager.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/css2/FontFamilyManager.java
index 750c7c1fc..a3a784523 100644
--- a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/css2/FontFamilyManager.java
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/css2/FontFamilyManager.java
@@ -31,8 +31,10 @@
import io.sf.carte.echosvg.css.engine.value.AbstractValueManager;
import io.sf.carte.echosvg.css.engine.value.IdentValue;
import io.sf.carte.echosvg.css.engine.value.ListValue;
+import io.sf.carte.echosvg.css.engine.value.RevertValue;
import io.sf.carte.echosvg.css.engine.value.StringMap;
import io.sf.carte.echosvg.css.engine.value.StringValue;
+import io.sf.carte.echosvg.css.engine.value.UnsetValue;
import io.sf.carte.echosvg.css.engine.value.Value;
import io.sf.carte.echosvg.css.engine.value.ValueConstants;
import io.sf.carte.echosvg.css.engine.value.ValueManager;
@@ -53,11 +55,14 @@ public class FontFamilyManager extends AbstractValueManager {
/**
* The default value.
*/
- protected static final ListValue DEFAULT_VALUE = new ListValue();
- static {
- DEFAULT_VALUE.append(new StringValue("Arial"));
- DEFAULT_VALUE.append(new StringValue("Helvetica"));
- DEFAULT_VALUE.append(IdentValue.createConstant(CSSConstants.CSS_SANS_SERIF_VALUE));
+ protected static final ListValue DEFAULT_VALUE = createDefaultValue();
+
+ private static ListValue createDefaultValue() {
+ ListValue def = new ListValue(',', 4);
+ def.append(new StringValue("Arial"));
+ def.append(new StringValue("Helvetica"));
+ def.append(IdentValue.createConstant(CSSConstants.CSS_SANS_SERIF_VALUE));
+ return def.createUnmodifiableView();
}
/**
@@ -117,7 +122,6 @@ public String getPropertyName() {
*/
@Override
public Value getDefaultValue() {
- // Do not clone this value
return DEFAULT_VALUE;
}
@@ -125,18 +129,32 @@ public Value getDefaultValue() {
* Implements {@link ValueManager#createValue(LexicalUnit,CSSEngine)}.
*/
@Override
- public Value createValue(LexicalUnit lu, CSSEngine engine) throws DOMException {
- switch (lu.getLexicalUnitType()) {
+ public Value createValue(final LexicalUnit lunit, CSSEngine engine) throws DOMException {
+ switch (lunit.getLexicalUnitType()) {
case INHERIT:
return ValueConstants.INHERIT_VALUE;
+ case UNSET:
+ return UnsetValue.getInstance();
+
+ case REVERT:
+ return RevertValue.getInstance();
+
+ case INITIAL:
+ return getDefaultValue();
+
+ case VAR:
+ case ATTR:
+ return createLexicalValue(lunit);
+
default:
- throw createInvalidLexicalUnitDOMException(lu.getLexicalUnitType());
+ throw createInvalidLexicalUnitDOMException(lunit.getLexicalUnitType());
case IDENT:
case STRING:
}
ListValue result = new ListValue();
+ LexicalUnit lu = lunit;
for (;;) {
switch (lu.getLexicalUnitType()) {
case STRING:
@@ -171,12 +189,22 @@ public Value createValue(LexicalUnit lu, CSSEngine engine) throws DOMException {
result.append((v != null) ? v : new StringValue(id));
}
break;
+
+ case VAR:
+ case ATTR:
+ return createLexicalValue(lunit);
+
default:
}
- if (lu == null)
+ if (lu == null) {
return result;
- if (lu.getLexicalUnitType() != LexicalUnit.LexicalType.OPERATOR_COMMA)
+ }
+ if (lu.getLexicalUnitType() != LexicalUnit.LexicalType.OPERATOR_COMMA) {
+ if (lu.getLexicalUnitType() == LexicalUnit.LexicalType.VAR) {
+ return createLexicalValue(lunit);
+ }
throw createInvalidLexicalUnitDOMException(lu.getLexicalUnitType());
+ }
lu = lu.getNextLexicalUnit();
if (lu == null)
throw createMalformedLexicalUnitDOMException();
@@ -185,13 +213,7 @@ public Value createValue(LexicalUnit lu, CSSEngine engine) throws DOMException {
private boolean isIdentOrNumber(LexicalUnit lu) {
LexicalType type = lu.getLexicalUnitType();
- switch (type) {
- case IDENT:
- case INTEGER:
- return true;
- default:
- return false;
- }
+ return type == LexicalType.IDENT || type == LexicalType.INTEGER;
}
/**
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/css2/FontShorthandManager.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/css2/FontShorthandManager.java
index aa4641841..5846bab8e 100644
--- a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/css2/FontShorthandManager.java
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/css2/FontShorthandManager.java
@@ -26,15 +26,30 @@
import java.util.Set;
import org.w3c.css.om.unit.CSSUnit;
+import org.w3c.dom.DOMException;
+import io.sf.carte.doc.style.css.CSSExpressionValue;
+import io.sf.carte.doc.style.css.CSSValue;
+import io.sf.carte.doc.style.css.CSSValue.Type;
+import io.sf.carte.doc.style.css.CSSValueSyntax.Match;
import io.sf.carte.doc.style.css.nsac.CSSParseException;
import io.sf.carte.doc.style.css.nsac.LexicalUnit;
import io.sf.carte.doc.style.css.parser.CSSParser;
+import io.sf.carte.doc.style.css.parser.SyntaxParser;
+import io.sf.carte.doc.style.css.property.StyleValue;
+import io.sf.carte.doc.style.css.property.ValueFactory;
import io.sf.carte.echosvg.css.engine.CSSEngine;
+import io.sf.carte.echosvg.css.engine.CSSStylableElement;
+import io.sf.carte.echosvg.css.engine.StyleMap;
import io.sf.carte.echosvg.css.engine.value.AbstractValueFactory;
+import io.sf.carte.echosvg.css.engine.value.CSSProxyValueException;
+import io.sf.carte.echosvg.css.engine.value.CalcValue;
+import io.sf.carte.echosvg.css.engine.value.FloatValue;
import io.sf.carte.echosvg.css.engine.value.IdentifierManager;
+import io.sf.carte.echosvg.css.engine.value.PendingValue;
import io.sf.carte.echosvg.css.engine.value.ShorthandManager;
import io.sf.carte.echosvg.css.engine.value.StringMap;
+import io.sf.carte.echosvg.css.engine.value.Value;
import io.sf.carte.echosvg.css.engine.value.ValueManager;
import io.sf.carte.echosvg.util.CSSConstants;
@@ -146,17 +161,29 @@ public void handleSystemFont(CSSEngine eng, ShorthandManager.PropertyHandler ph,
* {@link ShorthandManager#setValues(CSSEngine,ShorthandManager.PropertyHandler,LexicalUnit,boolean)}.
*/
@Override
- public void setValues(CSSEngine eng, ShorthandManager.PropertyHandler ph, LexicalUnit lu, boolean imp) {
- switch (lu.getLexicalUnitType()) {
- case INHERIT:
- return;
+ public void setValues(CSSEngine eng, ShorthandManager.PropertyHandler ph, final LexicalUnit lunit,
+ boolean imp) {
+ switch (lunit.getLexicalUnitType()) {
case IDENT: {
- String s = lu.getStringValue().toLowerCase(Locale.ROOT);
+ String s = lunit.getStringValue().toLowerCase(Locale.ROOT);
if (values.contains(s)) {
handleSystemFont(eng, ph, s, imp);
return;
}
+ break;
}
+
+ case INHERIT:
+ case UNSET:
+ case REVERT:
+ return;
+
+ case VAR:
+ case ATTR:
+ setPendingLonghands(eng, ph, lunit, imp,
+ eng.getPropertyIndex(CSSConstants.CSS_LINE_HEIGHT_PROPERTY));
+ return;
+
default:
break;
}
@@ -190,6 +217,7 @@ public void setValues(CSSEngine eng, ShorthandManager.PropertyHandler ph, Lexica
// These are all optional.
boolean svwDone = false;
+ LexicalUnit lu = lunit;
LexicalUnit intLU = null;
while (!svwDone && (lu != null)) {
switch (lu.getLexicalUnitType()) {
@@ -237,6 +265,11 @@ public void setValues(CSSEngine eng, ShorthandManager.PropertyHandler ph, Lexica
svwDone = true;
break;
+ case VAR:
+ case ATTR:
+ setPendingLonghands(eng, ph, lunit, imp, lh);
+ return;
+
default: // All other must be size,'/line-height', family
svwDone = true;
break;
@@ -270,6 +303,23 @@ public void setValues(CSSEngine eng, ShorthandManager.PropertyHandler ph, Lexica
fontSize = lu;
lu = lu.getNextLexicalUnit();
break;
+
+ case VAR:
+ case ATTR:
+ setPendingLonghands(eng, ph, lunit, imp, lh);
+ return;
+
+ case CALC:
+ Value calc = createFontSizeCalc(lu);
+ if (calc.getCssValueType() == CSSValue.CssType.PROXY) {
+ throw new CSSProxyValueException();
+ } else if (calc.getPrimitiveType() != Type.EXPRESSION || ((CalcValue) calc).getExpressionDelegate()
+ .matches(new SyntaxParser().parseSyntax("")) != Match.TRUE) {
+ throw createInvalidLexicalUnitDOMException(lu.getLexicalUnitType());
+ }
+ fontSize = lu;
+ lu = lu.getNextLexicalUnit();
+
default:
break;
}
@@ -308,6 +358,12 @@ public void setValues(CSSEngine eng, ShorthandManager.PropertyHandler ph, Lexica
lineHeight = lu;
lu = lu.getNextLexicalUnit();
break;
+
+ case VAR:
+ case ATTR:
+ setPendingLonghands(eng, ph, lunit, imp, lh);
+ return;
+
default:
break;
}
@@ -336,4 +392,40 @@ public void setValues(CSSEngine eng, ShorthandManager.PropertyHandler ph, Lexica
}
}
+ private Value createFontSizeCalc(LexicalUnit lu) throws DOMException {
+ ValueFactory vf = new ValueFactory();
+ StyleValue cssValue = vf.createCSSValue(lu.shallowClone());
+
+ Type pType = cssValue.getPrimitiveType();
+ if (pType != Type.EXPRESSION) {
+ createInvalidLexicalUnitDOMException(lu.getLexicalUnitType());
+ }
+
+ CalcValue calc = new CalcValue((CSSExpressionValue) cssValue) {
+
+ @Override
+ protected FloatValue absoluteValue(CSSStylableElement elt, String pseudo, CSSEngine engine,
+ int idx, StyleMap sm, FloatValue relative) {
+ return (FloatValue) new FontSizeManager().computeValue(elt, pseudo, engine, idx, sm,
+ relative);
+ }
+
+ };
+
+ return calc;
+ }
+
+ private void setPendingLonghands(CSSEngine eng, PropertyHandler ph, LexicalUnit lunit, boolean imp,
+ int lh) {
+ PendingValue pending = new PendingValue(getPropertyName(), lunit);
+ ph.pendingValue(CSSConstants.CSS_FONT_FAMILY_PROPERTY, pending, imp);
+ ph.pendingValue(CSSConstants.CSS_FONT_STYLE_PROPERTY, pending, imp);
+ ph.pendingValue(CSSConstants.CSS_FONT_VARIANT_PROPERTY, pending, imp);
+ ph.pendingValue(CSSConstants.CSS_FONT_WEIGHT_PROPERTY, pending, imp);
+ ph.pendingValue(CSSConstants.CSS_FONT_SIZE_PROPERTY, pending, imp);
+ if (lh != -1) {
+ ph.pendingValue(CSSConstants.CSS_LINE_HEIGHT_PROPERTY, pending, imp);
+ }
+ }
+
}
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/css2/FontSizeAdjustManager.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/css2/FontSizeAdjustManager.java
index a48ed888b..f482a5277 100644
--- a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/css2/FontSizeAdjustManager.java
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/css2/FontSizeAdjustManager.java
@@ -21,11 +21,14 @@
import org.w3c.css.om.unit.CSSUnit;
import org.w3c.dom.DOMException;
+import io.sf.carte.doc.style.css.CSSValue.Type;
import io.sf.carte.doc.style.css.nsac.LexicalUnit;
-import io.sf.carte.echosvg.css.dom.CSSValue.Type;
import io.sf.carte.echosvg.css.engine.CSSEngine;
import io.sf.carte.echosvg.css.engine.value.AbstractValueManager;
+import io.sf.carte.echosvg.css.engine.value.CalcValue;
import io.sf.carte.echosvg.css.engine.value.FloatValue;
+import io.sf.carte.echosvg.css.engine.value.RevertValue;
+import io.sf.carte.echosvg.css.engine.value.UnsetValue;
import io.sf.carte.echosvg.css.engine.value.Value;
import io.sf.carte.echosvg.css.engine.value.ValueConstants;
import io.sf.carte.echosvg.css.engine.value.ValueManager;
@@ -97,9 +100,6 @@ public Value getDefaultValue() {
@Override
public Value createValue(LexicalUnit lu, CSSEngine engine) throws DOMException {
switch (lu.getLexicalUnitType()) {
- case INHERIT:
- return ValueConstants.INHERIT_VALUE;
-
case INTEGER:
return new FloatValue(CSSUnit.CSS_NUMBER, lu.getIntegerValue());
@@ -112,6 +112,30 @@ public Value createValue(LexicalUnit lu, CSSEngine engine) throws DOMException {
}
throw createInvalidIdentifierDOMException(lu.getStringValue());
+ case INHERIT:
+ return ValueConstants.INHERIT_VALUE;
+
+ case UNSET:
+ return UnsetValue.getInstance();
+
+ case REVERT:
+ return RevertValue.getInstance();
+
+ case INITIAL:
+ return getDefaultValue();
+
+ case VAR:
+ case ATTR:
+ return createLexicalValue(lu);
+
+ case CALC:
+ Value calc = createCalc(lu);
+ if (calc.getPrimitiveType() != Type.EXPRESSION) {
+ // In principle this means that a var() was found
+ return calc;
+ }
+ return ((CalcValue) calc).evaluate(null, null, engine, -1, null, CSSUnit.CSS_NUMBER);
+
default:
break;
}
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/css2/FontSizeManager.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/css2/FontSizeManager.java
index abb6c7c2e..adbf4ba31 100644
--- a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/css2/FontSizeManager.java
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/css2/FontSizeManager.java
@@ -23,14 +23,15 @@
import org.w3c.css.om.unit.CSSUnit;
import org.w3c.dom.DOMException;
+import io.sf.carte.doc.style.css.CSSValue.Type;
import io.sf.carte.doc.style.css.nsac.LexicalUnit;
import io.sf.carte.doc.style.css.property.NumberValue;
import io.sf.carte.echosvg.css.Viewport;
-import io.sf.carte.echosvg.css.dom.CSSValue.Type;
import io.sf.carte.echosvg.css.engine.CSSContext;
import io.sf.carte.echosvg.css.engine.CSSEngine;
import io.sf.carte.echosvg.css.engine.CSSStylableElement;
import io.sf.carte.echosvg.css.engine.StyleMap;
+import io.sf.carte.echosvg.css.engine.value.CalcValue;
import io.sf.carte.echosvg.css.engine.value.FloatValue;
import io.sf.carte.echosvg.css.engine.value.IdentifierManager;
import io.sf.carte.echosvg.css.engine.value.LengthManager;
@@ -130,9 +131,6 @@ public Value getDefaultValue() {
@Override
public Value createValue(LexicalUnit lu, CSSEngine engine) throws DOMException {
switch (lu.getLexicalUnitType()) {
- case INHERIT:
- return ValueConstants.INHERIT_VALUE;
-
case IDENT:
String s = lu.getStringValue().toLowerCase(Locale.ROOT).intern();
Object v = values.get(s);
@@ -140,9 +138,14 @@ public Value createValue(LexicalUnit lu, CSSEngine engine) throws DOMException {
throw createInvalidIdentifierDOMException(s);
}
return (Value) v;
+
+ case INHERIT:
+ return ValueConstants.INHERIT_VALUE;
+
default:
break;
}
+
return super.createValue(lu, engine);
}
@@ -168,36 +171,32 @@ public Value computeValue(CSSStylableElement elt, String pseudo, CSSEngine engin
float scale = 1.0f;
boolean doParentRelative = false;
- if (value.getPrimitiveType() == Type.NUMERIC) {
- switch (value.getCSSUnit()) {
+ Type pType = value.getPrimitiveType();
+ if (pType == Type.NUMERIC) {
+ switch (value.getUnitType()) {
case CSSUnit.CSS_NUMBER:
case CSSUnit.CSS_PX:
return value;
case CSSUnit.CSS_MM:
- CSSContext ctx = engine.getCSSContext();
float v = lengthValue(value);
- return new FloatValue(CSSUnit.CSS_NUMBER, v / ctx.getPixelUnitToMillimeter());
+ return new FloatValue(CSSUnit.CSS_NUMBER, v * 3.779527559055f);
case CSSUnit.CSS_CM:
- ctx = engine.getCSSContext();
v = lengthValue(value);
- return new FloatValue(CSSUnit.CSS_NUMBER, v * 10f / ctx.getPixelUnitToMillimeter());
+ return new FloatValue(CSSUnit.CSS_NUMBER, v * 37.79527559055f);
case CSSUnit.CSS_IN:
- ctx = engine.getCSSContext();
v = lengthValue(value);
- return new FloatValue(CSSUnit.CSS_NUMBER, v * 25.4f / ctx.getPixelUnitToMillimeter());
+ return new FloatValue(CSSUnit.CSS_NUMBER, v * 96f);
case CSSUnit.CSS_PT:
- ctx = engine.getCSSContext();
v = lengthValue(value);
- return new FloatValue(CSSUnit.CSS_NUMBER, v * 25.4f / (72f * ctx.getPixelUnitToMillimeter()));
+ return new FloatValue(CSSUnit.CSS_NUMBER, v / 0.75f);
case CSSUnit.CSS_PC:
- ctx = engine.getCSSContext();
v = lengthValue(value);
- return new FloatValue(CSSUnit.CSS_NUMBER, (v * 25.4f / (6f * ctx.getPixelUnitToMillimeter())));
+ return new FloatValue(CSSUnit.CSS_NUMBER, v * 16f);
case CSSUnit.CSS_EM:
doParentRelative = true;
@@ -272,12 +271,16 @@ public Value computeValue(CSSStylableElement elt, String pseudo, CSSEngine engin
return new FloatValue(CSSUnit.CSS_NUMBER, v * max * 0.01f);
default:
// Maybe it is one of the new absolute length units
- try {
- return new FloatValue(CSSUnit.CSS_NUMBER,
- NumberValue.floatValueConversion(value.getFloatValue(), value.getCSSUnit(),
- CSSUnit.CSS_MM) / engine.getCSSContext().getPixelUnitToMillimeter());
- } catch (DOMException e) {
- }
+ return new FloatValue(CSSUnit.CSS_NUMBER,
+ NumberValue.floatValueConversion(value.getFloatValue(), value.getUnitType(),
+ CSSUnit.CSS_PX));
+ }
+ } else if (pType == Type.EXPRESSION) {
+ try {
+ Value calc = evaluateCalc((CalcValue) value, elt, pseudo, engine, idx, sm, CSSUnit.CSS_PX);
+ return new FloatValue(CSSUnit.CSS_NUMBER, calc.getFloatValue());
+ } catch (Exception e) {
+ return isInheritedProperty() ? null : getDefaultValue();
}
}
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/css2/FontStretchManager.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/css2/FontStretchManager.java
index 4f7a22945..16b55e722 100644
--- a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/css2/FontStretchManager.java
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/css2/FontStretchManager.java
@@ -18,7 +18,7 @@
*/
package io.sf.carte.echosvg.css.engine.value.css2;
-import io.sf.carte.echosvg.css.dom.CSSValue.Type;
+import io.sf.carte.doc.style.css.CSSValue.Type;
import io.sf.carte.echosvg.css.engine.CSSEngine;
import io.sf.carte.echosvg.css.engine.CSSStylableElement;
import io.sf.carte.echosvg.css.engine.StyleMap;
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/css2/FontWeightManager.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/css2/FontWeightManager.java
index 67b1de391..2b19e01b0 100644
--- a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/css2/FontWeightManager.java
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/css2/FontWeightManager.java
@@ -21,8 +21,8 @@
import org.w3c.css.om.unit.CSSUnit;
import org.w3c.dom.DOMException;
+import io.sf.carte.doc.style.css.CSSValue.Type;
import io.sf.carte.doc.style.css.nsac.LexicalUnit;
-import io.sf.carte.echosvg.css.dom.CSSValue.Type;
import io.sf.carte.echosvg.css.engine.CSSContext;
import io.sf.carte.echosvg.css.engine.CSSEngine;
import io.sf.carte.echosvg.css.engine.CSSStylableElement;
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/css2/SrcManager.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/css2/SrcManager.java
index 23b188ccc..1fb189139 100644
--- a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/css2/SrcManager.java
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/css2/SrcManager.java
@@ -26,9 +26,11 @@
import io.sf.carte.echosvg.css.engine.CSSEngine;
import io.sf.carte.echosvg.css.engine.value.IdentifierManager;
import io.sf.carte.echosvg.css.engine.value.ListValue;
+import io.sf.carte.echosvg.css.engine.value.RevertValue;
import io.sf.carte.echosvg.css.engine.value.StringMap;
import io.sf.carte.echosvg.css.engine.value.StringValue;
import io.sf.carte.echosvg.css.engine.value.URIValue;
+import io.sf.carte.echosvg.css.engine.value.UnsetValue;
import io.sf.carte.echosvg.css.engine.value.Value;
import io.sf.carte.echosvg.css.engine.value.ValueConstants;
import io.sf.carte.echosvg.css.engine.value.ValueManager;
@@ -83,6 +85,11 @@ public boolean isAdditiveProperty() {
return false;
}
+ @Override
+ public boolean allowsURL() {
+ return true;
+ }
+
/**
* Implements {@link ValueManager#getPropertyType()}.
*/
@@ -113,14 +120,26 @@ public Value getDefaultValue() {
* Implements {@link ValueManager#createValue(LexicalUnit,CSSEngine)}.
*/
@Override
- public Value createValue(LexicalUnit lu, CSSEngine engine) throws DOMException {
+ public Value createValue(final LexicalUnit lunit, CSSEngine engine) throws DOMException {
- switch (lu.getLexicalUnitType()) {
+ switch (lunit.getLexicalUnitType()) {
case INHERIT:
return ValueConstants.INHERIT_VALUE;
+ case UNSET:
+ return UnsetValue.getInstance();
+
+ case REVERT:
+ return RevertValue.getInstance();
+
+ case INITIAL:
+ return getDefaultValue();
+
+ case VAR:
+ return createLexicalValue(lunit);
+
default:
- throw createInvalidLexicalUnitDOMException(lu.getLexicalUnitType());
+ throw createInvalidLexicalUnitDOMException(lunit.getLexicalUnitType());
case IDENT:
case STRING:
@@ -128,6 +147,7 @@ public Value createValue(LexicalUnit lu, CSSEngine engine) throws DOMException {
}
ListValue result = new ListValue();
+ LexicalUnit lu = lunit;
for (;;) {
switch (lu.getLexicalUnitType()) {
case STRING:
@@ -140,36 +160,51 @@ public Value createValue(LexicalUnit lu, CSSEngine engine) throws DOMException {
result.append(new URIValue(lu.getStringValue(), uri));
lu = lu.getNextLexicalUnit();
- if ((lu != null) && (lu.getLexicalUnitType() == LexicalUnit.LexicalType.FUNCTION)) {
- if (!lu.getFunctionName().equalsIgnoreCase("format")) {
+ if (lu != null) {
+ switch (lu.getLexicalUnitType()) {
+ case FUNCTION:
+ if (!lu.getFunctionName().equalsIgnoreCase("format")) {
+ break;
+ }
+ // Format really does us no good so just ignore it.
+
+ // TODO: Should probably turn this into a ListValue
+ // and append the format function CSS Value.
+ lu = lu.getNextLexicalUnit();
+ break;
+ case VAR:
+ return createLexicalValue(lunit);
+ default:
break;
}
- // Format really does us no good so just ignore it.
-
- // TODO: Should probably turn this into a ListValue
- // and append the format function CSS Value.
- lu = lu.getNextLexicalUnit();
}
break;
case IDENT:
StringBuilder sb = new StringBuilder(lu.getStringValue());
lu = lu.getNextLexicalUnit();
- if (lu != null && lu.getLexicalUnitType() == LexicalUnit.LexicalType.IDENT) {
- do {
- sb.append(' ');
- sb.append(lu.getStringValue());
- lu = lu.getNextLexicalUnit();
- } while (lu != null && lu.getLexicalUnitType() == LexicalUnit.LexicalType.IDENT);
- result.append(new StringValue(sb.toString()));
- } else {
- String id = sb.toString();
- String s = id.toLowerCase(Locale.ROOT).intern();
- Value v = (Value) values.get(s);
- result.append((v != null) ? v : new StringValue(id));
+ if (lu != null) {
+ if (lu.getLexicalUnitType() == LexicalUnit.LexicalType.IDENT) {
+ do {
+ sb.append(' ');
+ sb.append(lu.getStringValue());
+ lu = lu.getNextLexicalUnit();
+ } while (lu != null && lu.getLexicalUnitType() == LexicalUnit.LexicalType.IDENT);
+ result.append(new StringValue(sb.toString()));
+ } else if (lu.getLexicalUnitType() == LexicalUnit.LexicalType.VAR) {
+ return createLexicalValue(lunit);
+ } else {
+ String id = sb.toString();
+ String s = id.toLowerCase(Locale.ROOT).intern();
+ Value v = (Value) values.get(s);
+ result.append(v != null ? v : new StringValue(id));
+ }
}
break;
+ case VAR:
+ return createLexicalValue(lunit);
+
default:
break;
@@ -178,6 +213,9 @@ public Value createValue(LexicalUnit lu, CSSEngine engine) throws DOMException {
return result;
}
if (lu.getLexicalUnitType() != LexicalUnit.LexicalType.OPERATOR_COMMA) {
+ if (lu.getLexicalUnitType() == LexicalUnit.LexicalType.VAR) {
+ return createLexicalValue(lunit);
+ }
throw createInvalidLexicalUnitDOMException(lu.getLexicalUnitType());
}
lu = lu.getNextLexicalUnit();
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/css2/TextDecorationManager.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/css2/TextDecorationManager.java
index b2b8fc9e5..a9f4c1bf3 100644
--- a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/css2/TextDecorationManager.java
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/css2/TextDecorationManager.java
@@ -22,15 +22,18 @@
import org.w3c.dom.DOMException;
+import io.sf.carte.doc.style.css.CSSValue.Type;
import io.sf.carte.doc.style.css.nsac.LexicalUnit;
-import io.sf.carte.echosvg.css.dom.CSSValue.Type;
import io.sf.carte.echosvg.css.engine.CSSEngine;
import io.sf.carte.echosvg.css.engine.value.AbstractValueManager;
import io.sf.carte.echosvg.css.engine.value.ListValue;
+import io.sf.carte.echosvg.css.engine.value.RevertValue;
import io.sf.carte.echosvg.css.engine.value.StringMap;
+import io.sf.carte.echosvg.css.engine.value.UnsetValue;
import io.sf.carte.echosvg.css.engine.value.Value;
import io.sf.carte.echosvg.css.engine.value.ValueConstants;
import io.sf.carte.echosvg.css.engine.value.ValueManager;
+import io.sf.carte.echosvg.css.engine.value.LexicalValue;
import io.sf.carte.echosvg.util.CSSConstants;
import io.sf.carte.echosvg.util.SVGTypes;
@@ -108,18 +111,17 @@ public Value getDefaultValue() {
* Implements {@link ValueManager#createValue(LexicalUnit,CSSEngine)}.
*/
@Override
- public Value createValue(LexicalUnit lu, CSSEngine engine) throws DOMException {
- switch (lu.getLexicalUnitType()) {
- case INHERIT:
- return ValueConstants.INHERIT_VALUE;
-
+ public Value createValue(final LexicalUnit lunit, CSSEngine engine) throws DOMException {
+ switch (lunit.getLexicalUnitType()) {
case IDENT:
- if (lu.getStringValue().equalsIgnoreCase(CSSConstants.CSS_NONE_VALUE)) {
+ if (lunit.getStringValue().equalsIgnoreCase(CSSConstants.CSS_NONE_VALUE)) {
return ValueConstants.NONE_VALUE;
}
ListValue lv = new ListValue(' ');
+ LexicalUnit lu = lunit;
do {
- if (lu.getLexicalUnitType() == LexicalUnit.LexicalType.IDENT) {
+ switch (lu.getLexicalUnitType()) {
+ case IDENT:
String s = lu.getStringValue().toLowerCase(Locale.ROOT).intern();
Object obj = values.get(s);
if (obj == null) {
@@ -127,17 +129,36 @@ public Value createValue(LexicalUnit lu, CSSEngine engine) throws DOMException {
}
lv.append((Value) obj);
lu = lu.getNextLexicalUnit();
- } else {
- throw createInvalidLexicalUnitDOMException(lu.getLexicalUnitType());
+ break;
+ case VAR:
+ case ATTR:
+ return new LexicalValue(lunit);
+ default:
+ throw createInvalidLexicalUnitDOMException(lunit.getLexicalUnitType());
}
-
} while (lu != null);
return lv;
+ case INHERIT:
+ return ValueConstants.INHERIT_VALUE;
+
+ case UNSET:
+ return UnsetValue.getInstance();
+
+ case REVERT:
+ return RevertValue.getInstance();
+
+ case INITIAL:
+ return getDefaultValue();
+
+ case VAR:
+ case ATTR:
+ return new LexicalValue(lunit);
+
default:
break;
}
- throw createInvalidLexicalUnitDOMException(lu.getLexicalUnitType());
+ throw createInvalidLexicalUnitDOMException(lunit.getLexicalUnitType());
}
@Override
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg/BaselineShiftManager.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg/BaselineShiftManager.java
index 35b0e7fee..eec2585f8 100644
--- a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg/BaselineShiftManager.java
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg/BaselineShiftManager.java
@@ -23,8 +23,8 @@
import org.w3c.css.om.unit.CSSUnit;
import org.w3c.dom.DOMException;
+import io.sf.carte.doc.style.css.CSSValue.Type;
import io.sf.carte.doc.style.css.nsac.LexicalUnit;
-import io.sf.carte.echosvg.css.dom.CSSValue.Type;
import io.sf.carte.echosvg.css.engine.CSSEngine;
import io.sf.carte.echosvg.css.engine.CSSStylableElement;
import io.sf.carte.echosvg.css.engine.StyleMap;
@@ -112,18 +112,20 @@ public Value getDefaultValue() {
@Override
public Value createValue(LexicalUnit lu, CSSEngine engine) throws DOMException {
switch (lu.getLexicalUnitType()) {
- case INHERIT:
- return ValueConstants.INHERIT_VALUE;
-
case IDENT:
Object v = values.get(lu.getStringValue().toLowerCase(Locale.ROOT).intern());
if (v == null) {
throw createInvalidIdentifierDOMException(lu.getStringValue());
}
return (Value) v;
+
+ case INHERIT:
+ return ValueConstants.INHERIT_VALUE;
+
default:
break;
}
+
return super.createValue(lu, engine);
}
@@ -146,7 +148,7 @@ public Value createStringValue(Type type, String value, CSSEngine engine) throws
@Override
public Value computeValue(CSSStylableElement elt, String pseudo, CSSEngine engine, int idx, StyleMap sm,
Value value) {
- if (value.getCSSUnit() == CSSUnit.CSS_PERCENTAGE) {
+ if (value.getUnitType() == CSSUnit.CSS_PERCENTAGE) {
sm.putLineHeightRelative(idx, true);
int fsi = engine.getLineHeightIndex();
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg/ClipPathManager.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg/ClipPathManager.java
index e2a0d8f86..e55913711 100644
--- a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg/ClipPathManager.java
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg/ClipPathManager.java
@@ -20,11 +20,13 @@
import org.w3c.dom.DOMException;
+import io.sf.carte.doc.style.css.CSSValue.Type;
import io.sf.carte.doc.style.css.nsac.LexicalUnit;
-import io.sf.carte.echosvg.css.dom.CSSValue.Type;
import io.sf.carte.echosvg.css.engine.CSSEngine;
import io.sf.carte.echosvg.css.engine.value.AbstractValueManager;
+import io.sf.carte.echosvg.css.engine.value.RevertValue;
import io.sf.carte.echosvg.css.engine.value.URIValue;
+import io.sf.carte.echosvg.css.engine.value.UnsetValue;
import io.sf.carte.echosvg.css.engine.value.Value;
import io.sf.carte.echosvg.css.engine.value.ValueConstants;
import io.sf.carte.echosvg.css.engine.value.ValueManager;
@@ -74,6 +76,11 @@ public boolean isAdditiveProperty() {
return false;
}
+ @Override
+ public boolean allowsURL() {
+ return true;
+ }
+
/**
* Implements {@link ValueManager#getPropertyType()}.
*/
@@ -96,9 +103,6 @@ public Value getDefaultValue() {
@Override
public Value createValue(LexicalUnit lu, CSSEngine engine) throws DOMException {
switch (lu.getLexicalUnitType()) {
- case INHERIT:
- return ValueConstants.INHERIT_VALUE;
-
case URI:
return new URIValue(lu.getStringValue(), resolveURI(engine.getCSSBaseURI(), lu.getStringValue()));
@@ -106,6 +110,23 @@ public Value createValue(LexicalUnit lu, CSSEngine engine) throws DOMException {
if (lu.getStringValue().equalsIgnoreCase(CSSConstants.CSS_NONE_VALUE)) {
return ValueConstants.NONE_VALUE.clone();
}
+ throw createInvalidIdentifierDOMException(lu.getStringValue());
+
+ case INHERIT:
+ return ValueConstants.INHERIT_VALUE;
+
+ case UNSET:
+ return UnsetValue.getInstance();
+
+ case REVERT:
+ return RevertValue.getInstance();
+
+ case INITIAL:
+ return getDefaultValue();
+
+ case VAR:
+ return createLexicalValue(lu);
+
default:
break;
}
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg/ColorProfileManager.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg/ColorProfileManager.java
index 53dd6b950..741ee9706 100644
--- a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg/ColorProfileManager.java
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg/ColorProfileManager.java
@@ -22,12 +22,14 @@
import org.w3c.dom.DOMException;
+import io.sf.carte.doc.style.css.CSSValue.Type;
import io.sf.carte.doc.style.css.nsac.LexicalUnit;
-import io.sf.carte.echosvg.css.dom.CSSValue.Type;
import io.sf.carte.echosvg.css.engine.CSSEngine;
import io.sf.carte.echosvg.css.engine.value.AbstractValueManager;
import io.sf.carte.echosvg.css.engine.value.IdentValue;
+import io.sf.carte.echosvg.css.engine.value.RevertValue;
import io.sf.carte.echosvg.css.engine.value.URIValue;
+import io.sf.carte.echosvg.css.engine.value.UnsetValue;
import io.sf.carte.echosvg.css.engine.value.Value;
import io.sf.carte.echosvg.css.engine.value.ValueConstants;
import io.sf.carte.echosvg.css.engine.value.ValueManager;
@@ -77,6 +79,11 @@ public boolean isAdditiveProperty() {
return false;
}
+ @Override
+ public boolean allowsURL() {
+ return true;
+ }
+
/**
* Implements {@link ValueManager#getPropertyType()}.
*/
@@ -99,9 +106,6 @@ public Value getDefaultValue() {
@Override
public Value createValue(LexicalUnit lu, CSSEngine engine) throws DOMException {
switch (lu.getLexicalUnitType()) {
- case INHERIT:
- return ValueConstants.INHERIT_VALUE;
-
case IDENT:
String s = lu.getStringValue().toLowerCase(Locale.ROOT);
if (s.equals(CSSConstants.CSS_AUTO_VALUE)) {
@@ -114,6 +118,22 @@ public Value createValue(LexicalUnit lu, CSSEngine engine) throws DOMException {
case URI:
return new URIValue(lu.getStringValue(), resolveURI(engine.getCSSBaseURI(), lu.getStringValue()));
+
+ case INHERIT:
+ return ValueConstants.INHERIT_VALUE;
+
+ case UNSET:
+ return UnsetValue.getInstance();
+
+ case REVERT:
+ return RevertValue.getInstance();
+
+ case INITIAL:
+ return getDefaultValue();
+
+ case VAR:
+ return createLexicalValue(lu);
+
default:
break;
}
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg/EnableBackgroundManager.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg/EnableBackgroundManager.java
index ceb0500fd..daae4912b 100644
--- a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg/EnableBackgroundManager.java
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg/EnableBackgroundManager.java
@@ -22,8 +22,8 @@
import org.w3c.dom.DOMException;
+import io.sf.carte.doc.style.css.CSSValue.Type;
import io.sf.carte.doc.style.css.nsac.LexicalUnit;
-import io.sf.carte.echosvg.css.dom.CSSValue.Type;
import io.sf.carte.echosvg.css.engine.CSSEngine;
import io.sf.carte.echosvg.css.engine.CSSStylableElement;
import io.sf.carte.echosvg.css.engine.StyleMap;
@@ -105,12 +105,6 @@ public Value getDefaultValue() {
@Override
public Value createValue(LexicalUnit lu, CSSEngine engine) throws DOMException {
switch (lu.getLexicalUnitType()) {
- case INHERIT:
- return ValueConstants.INHERIT_VALUE;
-
- default:
- throw createInvalidLexicalUnitDOMException(lu.getLexicalUnitType());
-
case IDENT:
String id = lu.getStringValue().toLowerCase(Locale.ROOT).intern();
if (id == CSSConstants.CSS_ACCUMULATE_VALUE) {
@@ -134,6 +128,12 @@ public Value createValue(LexicalUnit lu, CSSEngine engine) throws DOMException {
result.append(super.createValue(lu, engine));
}
return result;
+
+ case INHERIT:
+ return ValueConstants.INHERIT_VALUE;
+
+ default:
+ throw createInvalidLexicalUnitDOMException(lu.getLexicalUnitType());
}
}
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg/FilterManager.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg/FilterManager.java
index 97557d101..3f0184b4a 100644
--- a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg/FilterManager.java
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg/FilterManager.java
@@ -20,11 +20,13 @@
import org.w3c.dom.DOMException;
+import io.sf.carte.doc.style.css.CSSValue.Type;
import io.sf.carte.doc.style.css.nsac.LexicalUnit;
-import io.sf.carte.echosvg.css.dom.CSSValue.Type;
import io.sf.carte.echosvg.css.engine.CSSEngine;
import io.sf.carte.echosvg.css.engine.value.AbstractValueManager;
+import io.sf.carte.echosvg.css.engine.value.RevertValue;
import io.sf.carte.echosvg.css.engine.value.URIValue;
+import io.sf.carte.echosvg.css.engine.value.UnsetValue;
import io.sf.carte.echosvg.css.engine.value.Value;
import io.sf.carte.echosvg.css.engine.value.ValueConstants;
import io.sf.carte.echosvg.css.engine.value.ValueManager;
@@ -74,6 +76,11 @@ public boolean isAdditiveProperty() {
return false;
}
+ @Override
+ public boolean allowsURL() {
+ return true;
+ }
+
/**
* Implements {@link ValueManager#getPropertyType()}.
*/
@@ -96,9 +103,6 @@ public Value getDefaultValue() {
@Override
public Value createValue(LexicalUnit lu, CSSEngine engine) throws DOMException {
switch (lu.getLexicalUnitType()) {
- case INHERIT:
- return ValueConstants.INHERIT_VALUE;
-
case URI:
return new URIValue(lu.getStringValue(), resolveURI(engine.getCSSBaseURI(), lu.getStringValue()));
@@ -108,6 +112,21 @@ public Value createValue(LexicalUnit lu, CSSEngine engine) throws DOMException {
}
throw createInvalidIdentifierDOMException(lu.getStringValue());
+ case INHERIT:
+ return ValueConstants.INHERIT_VALUE;
+
+ case UNSET:
+ return UnsetValue.getInstance();
+
+ case REVERT:
+ return RevertValue.getInstance();
+
+ case INITIAL:
+ return getDefaultValue();
+
+ case VAR:
+ return createLexicalValue(lu);
+
default:
break;
}
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg/GlyphOrientationManager.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg/GlyphOrientationManager.java
index 817a69488..8f907b5c0 100644
--- a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg/GlyphOrientationManager.java
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg/GlyphOrientationManager.java
@@ -21,11 +21,15 @@
import org.w3c.css.om.unit.CSSUnit;
import org.w3c.dom.DOMException;
+import io.sf.carte.doc.style.css.CSSValue.Type;
import io.sf.carte.doc.style.css.nsac.LexicalUnit;
import io.sf.carte.doc.style.css.property.NumberValue;
import io.sf.carte.echosvg.css.engine.CSSEngine;
import io.sf.carte.echosvg.css.engine.value.AbstractValueManager;
+import io.sf.carte.echosvg.css.engine.value.CalcValue;
import io.sf.carte.echosvg.css.engine.value.FloatValue;
+import io.sf.carte.echosvg.css.engine.value.RevertValue;
+import io.sf.carte.echosvg.css.engine.value.UnsetValue;
import io.sf.carte.echosvg.css.engine.value.Value;
import io.sf.carte.echosvg.css.engine.value.ValueConstants;
import io.sf.carte.echosvg.css.engine.value.ValueManager;
@@ -81,9 +85,6 @@ public int getPropertyType() {
@Override
public Value createValue(LexicalUnit lu, CSSEngine engine) throws DOMException {
switch (lu.getLexicalUnitType()) {
- case INHERIT:
- return ValueConstants.INHERIT_VALUE;
-
case DIMENSION:
switch (lu.getCssUnit()) {
case CSSUnit.CSS_DEG:
@@ -95,16 +96,46 @@ public Value createValue(LexicalUnit lu, CSSEngine engine) throws DOMException {
case CSSUnit.CSS_TURN:
return new FloatValue(CSSUnit.CSS_DEG, lu.getFloatValue() * 360f);
}
+ break;
- // For SVG angle properties unit defaults to 'deg'.
+ // For SVG angle properties unit defaults to 'deg'.
case INTEGER: {
int n = lu.getIntegerValue();
return new FloatValue(CSSUnit.CSS_DEG, n);
}
+
case REAL: {
float n = lu.getFloatValue();
return new FloatValue(CSSUnit.CSS_DEG, n);
}
+
+ case INHERIT:
+ return ValueConstants.INHERIT_VALUE;
+
+ case UNSET:
+ return UnsetValue.getInstance();
+
+ case REVERT:
+ return RevertValue.getInstance();
+
+ case INITIAL:
+ return getDefaultValue();
+
+ case VAR:
+ case ATTR:
+ return createLexicalValue(lu);
+
+ case CALC:
+ Value calc = createCalc(lu);
+ if (calc.getPrimitiveType() != Type.EXPRESSION) {
+ return calc;
+ }
+ FloatValue f = ((CalcValue) calc).evaluate(null, null, engine, -1, null, CSSUnit.CSS_DEG);
+ if (f.getUnitType() == CSSUnit.CSS_NUMBER) {
+ f = new FloatValue(CSSUnit.CSS_DEG, f.getFloatValue());
+ }
+ return f;
+
default:
break;
}
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg/GlyphOrientationVerticalManager.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg/GlyphOrientationVerticalManager.java
index f0513416a..d0fd797f7 100644
--- a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg/GlyphOrientationVerticalManager.java
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg/GlyphOrientationVerticalManager.java
@@ -20,8 +20,8 @@
import org.w3c.dom.DOMException;
+import io.sf.carte.doc.style.css.CSSValue.Type;
import io.sf.carte.doc.style.css.nsac.LexicalUnit;
-import io.sf.carte.echosvg.css.dom.CSSValue.Type;
import io.sf.carte.echosvg.css.engine.CSSEngine;
import io.sf.carte.echosvg.css.engine.value.Value;
import io.sf.carte.echosvg.css.engine.value.ValueConstants;
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg/KerningManager.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg/KerningManager.java
index 74dd4d9a9..f51a609c8 100644
--- a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg/KerningManager.java
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg/KerningManager.java
@@ -20,8 +20,8 @@
import org.w3c.dom.DOMException;
+import io.sf.carte.doc.style.css.CSSValue.Type;
import io.sf.carte.doc.style.css.nsac.LexicalUnit;
-import io.sf.carte.echosvg.css.dom.CSSValue.Type;
import io.sf.carte.echosvg.css.engine.CSSEngine;
import io.sf.carte.echosvg.css.engine.value.LengthManager;
import io.sf.carte.echosvg.css.engine.value.Value;
@@ -95,14 +95,15 @@ public Value getDefaultValue() {
@Override
public Value createValue(LexicalUnit lu, CSSEngine engine) throws DOMException {
switch (lu.getLexicalUnitType()) {
- case INHERIT:
- return ValueConstants.INHERIT_VALUE;
-
case IDENT:
if (lu.getStringValue().equalsIgnoreCase(CSSConstants.CSS_AUTO_VALUE)) {
return ValueConstants.AUTO_VALUE;
}
throw createInvalidIdentifierDOMException(lu.getStringValue());
+
+ case INHERIT:
+ return ValueConstants.INHERIT_VALUE;
+
default:
break;
}
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg/MarkerManager.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg/MarkerManager.java
index b1e3b6b14..8c6ca693b 100644
--- a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg/MarkerManager.java
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg/MarkerManager.java
@@ -20,11 +20,13 @@
import org.w3c.dom.DOMException;
+import io.sf.carte.doc.style.css.CSSValue.Type;
import io.sf.carte.doc.style.css.nsac.LexicalUnit;
-import io.sf.carte.echosvg.css.dom.CSSValue.Type;
import io.sf.carte.echosvg.css.engine.CSSEngine;
import io.sf.carte.echosvg.css.engine.value.AbstractValueManager;
+import io.sf.carte.echosvg.css.engine.value.RevertValue;
import io.sf.carte.echosvg.css.engine.value.URIValue;
+import io.sf.carte.echosvg.css.engine.value.UnsetValue;
import io.sf.carte.echosvg.css.engine.value.Value;
import io.sf.carte.echosvg.css.engine.value.ValueConstants;
import io.sf.carte.echosvg.css.engine.value.ValueManager;
@@ -78,6 +80,11 @@ public boolean isAdditiveProperty() {
return false;
}
+ @Override
+ public boolean allowsURL() {
+ return true;
+ }
+
/**
* Implements {@link ValueManager#getPropertyType()}.
*/
@@ -108,9 +115,6 @@ public Value getDefaultValue() {
@Override
public Value createValue(LexicalUnit lu, CSSEngine engine) throws DOMException {
switch (lu.getLexicalUnitType()) {
- case INHERIT:
- return ValueConstants.INHERIT_VALUE;
-
case URI:
return new URIValue(lu.getStringValue(), resolveURI(engine.getCSSBaseURI(), lu.getStringValue()));
@@ -118,6 +122,22 @@ public Value createValue(LexicalUnit lu, CSSEngine engine) throws DOMException {
if (lu.getStringValue().equalsIgnoreCase(CSSConstants.CSS_NONE_VALUE)) {
return ValueConstants.NONE_VALUE;
}
+ throw createInvalidIdentifierDOMException(lu.getStringValue());
+
+ case INHERIT:
+ return ValueConstants.INHERIT_VALUE;
+
+ case UNSET:
+ return UnsetValue.getInstance();
+
+ case REVERT:
+ return RevertValue.getInstance();
+
+ case INITIAL:
+ return getDefaultValue();
+
+ case VAR:
+ return createLexicalValue(lu);
default:
break;
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg/MarkerShorthandManager.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg/MarkerShorthandManager.java
index 727770868..c94181f82 100644
--- a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg/MarkerShorthandManager.java
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg/MarkerShorthandManager.java
@@ -18,11 +18,17 @@
*/
package io.sf.carte.echosvg.css.engine.value.svg;
+import java.io.IOException;
+import java.io.StringReader;
+
import org.w3c.dom.DOMException;
+import io.sf.carte.doc.style.css.nsac.CSSParseException;
import io.sf.carte.doc.style.css.nsac.LexicalUnit;
+import io.sf.carte.doc.style.css.parser.CSSParser;
import io.sf.carte.echosvg.css.engine.CSSEngine;
import io.sf.carte.echosvg.css.engine.value.AbstractValueFactory;
+import io.sf.carte.echosvg.css.engine.value.PendingValue;
import io.sf.carte.echosvg.css.engine.value.ShorthandManager;
import io.sf.carte.echosvg.css.engine.value.ValueManager;
import io.sf.carte.echosvg.util.CSSConstants;
@@ -31,8 +37,10 @@
* This class represents an object which provide support for the 'marker'
* shorthand properties.
*
- * @author Stephane Hillion
- * @author For later modifications, see Git history.
+ *
+ * Original author: Stephane Hillion.
+ * For later modifications, see Git history.
+ *
* @version $Id$
*/
public class MarkerShorthandManager extends AbstractValueFactory implements ShorthandManager {
@@ -68,9 +76,33 @@ public boolean isAdditiveProperty() {
@Override
public void setValues(CSSEngine eng, ShorthandManager.PropertyHandler ph, LexicalUnit lu, boolean imp)
throws DOMException {
+ switch (lu.getLexicalUnitType()) {
+ case VAR:
+ setPendingLonghands(eng, ph, lu, imp);
+ /* fall-through */
+ case INHERIT:
+ case UNSET:
+ return;
+ case INITIAL:
+ // none
+ try {
+ lu = new CSSParser().parsePropertyValue(new StringReader(CSSConstants.CSS_NONE_VALUE));
+ } catch (CSSParseException | IOException e) {
+ }
+ default:
+ break;
+ }
+
ph.property(CSSConstants.CSS_MARKER_END_PROPERTY, lu, imp);
ph.property(CSSConstants.CSS_MARKER_MID_PROPERTY, lu, imp);
ph.property(CSSConstants.CSS_MARKER_START_PROPERTY, lu, imp);
}
+ private void setPendingLonghands(CSSEngine eng, PropertyHandler ph, LexicalUnit lu, boolean imp) {
+ PendingValue pending = new PendingValue(getPropertyName(), lu);
+ ph.pendingValue(CSSConstants.CSS_MARKER_END_PROPERTY, pending, imp);
+ ph.pendingValue(CSSConstants.CSS_MARKER_MID_PROPERTY, pending, imp);
+ ph.pendingValue(CSSConstants.CSS_MARKER_START_PROPERTY, pending, imp);
+ }
+
}
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg/MaskManager.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg/MaskManager.java
index 7181b4807..813a76a56 100644
--- a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg/MaskManager.java
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg/MaskManager.java
@@ -20,11 +20,13 @@
import org.w3c.dom.DOMException;
+import io.sf.carte.doc.style.css.CSSValue.Type;
import io.sf.carte.doc.style.css.nsac.LexicalUnit;
-import io.sf.carte.echosvg.css.dom.CSSValue.Type;
import io.sf.carte.echosvg.css.engine.CSSEngine;
import io.sf.carte.echosvg.css.engine.value.AbstractValueManager;
+import io.sf.carte.echosvg.css.engine.value.RevertValue;
import io.sf.carte.echosvg.css.engine.value.URIValue;
+import io.sf.carte.echosvg.css.engine.value.UnsetValue;
import io.sf.carte.echosvg.css.engine.value.Value;
import io.sf.carte.echosvg.css.engine.value.ValueConstants;
import io.sf.carte.echosvg.css.engine.value.ValueManager;
@@ -66,6 +68,11 @@ public boolean isAdditiveProperty() {
return false;
}
+ @Override
+ public boolean allowsURL() {
+ return true;
+ }
+
/**
* Implements {@link ValueManager#getPropertyType()}.
*/
@@ -96,9 +103,6 @@ public Value getDefaultValue() {
@Override
public Value createValue(LexicalUnit lu, CSSEngine engine) throws DOMException {
switch (lu.getLexicalUnitType()) {
- case INHERIT:
- return ValueConstants.INHERIT_VALUE;
-
case URI:
return new URIValue(lu.getStringValue(), resolveURI(engine.getCSSBaseURI(), lu.getStringValue()));
@@ -106,6 +110,22 @@ public Value createValue(LexicalUnit lu, CSSEngine engine) throws DOMException {
if (lu.getStringValue().equalsIgnoreCase(CSSConstants.CSS_NONE_VALUE)) {
return ValueConstants.NONE_VALUE;
}
+ throw createInvalidIdentifierDOMException(lu.getStringValue());
+
+ case INHERIT:
+ return ValueConstants.INHERIT_VALUE;
+
+ case UNSET:
+ return UnsetValue.getInstance();
+
+ case REVERT:
+ return RevertValue.getInstance();
+
+ case INITIAL:
+ return getDefaultValue();
+
+ case VAR:
+ return createLexicalValue(lu);
default:
break;
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg/OpacityManager.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg/OpacityManager.java
index da37217b3..7466b1ef1 100644
--- a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg/OpacityManager.java
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg/OpacityManager.java
@@ -21,10 +21,16 @@
import org.w3c.css.om.unit.CSSUnit;
import org.w3c.dom.DOMException;
+import io.sf.carte.doc.style.css.CSSValue;
+import io.sf.carte.doc.style.css.CSSValue.Type;
import io.sf.carte.doc.style.css.nsac.LexicalUnit;
import io.sf.carte.echosvg.css.engine.CSSEngine;
import io.sf.carte.echosvg.css.engine.value.AbstractValueManager;
+import io.sf.carte.echosvg.css.engine.value.CSSProxyValueException;
+import io.sf.carte.echosvg.css.engine.value.CalcValue;
import io.sf.carte.echosvg.css.engine.value.FloatValue;
+import io.sf.carte.echosvg.css.engine.value.RevertValue;
+import io.sf.carte.echosvg.css.engine.value.UnsetValue;
import io.sf.carte.echosvg.css.engine.value.Value;
import io.sf.carte.echosvg.css.engine.value.ValueConstants;
import io.sf.carte.echosvg.css.engine.value.ValueManager;
@@ -113,15 +119,37 @@ public Value getDefaultValue() {
@Override
public Value createValue(LexicalUnit lu, CSSEngine engine) throws DOMException {
switch (lu.getLexicalUnitType()) {
- case INHERIT:
- return ValueConstants.INHERIT_VALUE;
-
case INTEGER:
return new FloatValue(CSSUnit.CSS_NUMBER, lu.getIntegerValue());
case REAL:
return new FloatValue(CSSUnit.CSS_NUMBER, lu.getFloatValue());
+ case INHERIT:
+ return ValueConstants.INHERIT_VALUE;
+
+ case UNSET:
+ return UnsetValue.getInstance();
+
+ case REVERT:
+ return RevertValue.getInstance();
+
+ case INITIAL:
+ return getDefaultValue();
+
+ case VAR:
+ case ATTR:
+ return createLexicalValue(lu);
+
+ case CALC:
+ Value calc = createCalc(lu);
+ if (calc.getCssValueType() == CSSValue.CssType.PROXY) {
+ throw new CSSProxyValueException();
+ } else if (calc.getPrimitiveType() != Type.EXPRESSION) {
+ break;
+ }
+ return ((CalcValue) calc).evaluate(null, null, engine, -1, null, CSSUnit.CSS_NUMBER);
+
default:
break;
}
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg/SVGPaintManager.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg/SVGPaintManager.java
index f31d64e74..0f59bd6bd 100644
--- a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg/SVGPaintManager.java
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg/SVGPaintManager.java
@@ -84,6 +84,11 @@ public boolean isAdditiveProperty() {
return true;
}
+ @Override
+ public boolean allowsURL() {
+ return true;
+ }
+
/**
* Implements {@link ValueManager#getPropertyType()}.
*/
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg/SpacingManager.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg/SpacingManager.java
index 85c7f57f9..64fcfdc58 100644
--- a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg/SpacingManager.java
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg/SpacingManager.java
@@ -20,8 +20,8 @@
import org.w3c.dom.DOMException;
+import io.sf.carte.doc.style.css.CSSValue.Type;
import io.sf.carte.doc.style.css.nsac.LexicalUnit;
-import io.sf.carte.echosvg.css.dom.CSSValue.Type;
import io.sf.carte.echosvg.css.engine.CSSEngine;
import io.sf.carte.echosvg.css.engine.value.LengthManager;
import io.sf.carte.echosvg.css.engine.value.Value;
@@ -115,6 +115,7 @@ public Value createValue(LexicalUnit lu, CSSEngine engine) throws DOMException {
return ValueConstants.NORMAL_VALUE;
}
throw createInvalidIdentifierDOMException(lu.getStringValue());
+
default:
break;
}
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg/StrokeDasharrayManager.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg/StrokeDasharrayManager.java
index fa976a1f1..0bf1cf7dd 100644
--- a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg/StrokeDasharrayManager.java
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg/StrokeDasharrayManager.java
@@ -20,13 +20,15 @@
import org.w3c.dom.DOMException;
+import io.sf.carte.doc.style.css.CSSValue.Type;
import io.sf.carte.doc.style.css.nsac.LexicalUnit;
-import io.sf.carte.echosvg.css.dom.CSSValue.Type;
import io.sf.carte.echosvg.css.engine.CSSEngine;
import io.sf.carte.echosvg.css.engine.CSSStylableElement;
import io.sf.carte.echosvg.css.engine.StyleMap;
import io.sf.carte.echosvg.css.engine.value.LengthManager;
import io.sf.carte.echosvg.css.engine.value.ListValue;
+import io.sf.carte.echosvg.css.engine.value.RevertValue;
+import io.sf.carte.echosvg.css.engine.value.UnsetValue;
import io.sf.carte.echosvg.css.engine.value.Value;
import io.sf.carte.echosvg.css.engine.value.ValueConstants;
import io.sf.carte.echosvg.css.engine.value.ValueManager;
@@ -96,25 +98,48 @@ public Value getDefaultValue() {
* Implements {@link ValueManager#createValue(LexicalUnit,CSSEngine)}.
*/
@Override
- public Value createValue(LexicalUnit lu, CSSEngine engine) throws DOMException {
- switch (lu.getLexicalUnitType()) {
- case INHERIT:
- return ValueConstants.INHERIT_VALUE;
-
+ public Value createValue(final LexicalUnit lunit, CSSEngine engine) throws DOMException {
+ switch (lunit.getLexicalUnitType()) {
case IDENT:
- if (lu.getStringValue().equalsIgnoreCase(CSSConstants.CSS_NONE_VALUE)) {
+ if (lunit.getStringValue().equalsIgnoreCase(CSSConstants.CSS_NONE_VALUE)) {
return ValueConstants.NONE_VALUE;
}
- throw createInvalidIdentifierDOMException(lu.getStringValue());
+ throw createInvalidIdentifierDOMException(lunit.getStringValue());
+
+ case INHERIT:
+ return ValueConstants.INHERIT_VALUE;
+
+ case UNSET:
+ return UnsetValue.getInstance();
+
+ case REVERT:
+ return RevertValue.getInstance();
+
+ case INITIAL:
+ return getDefaultValue();
+
+ case VAR:
+ case ATTR:
+ return createLexicalValue(lunit);
default:
+ /*
+ * "A list of comma and/or white space separated s and s
+ * that specify the lengths of alternating dashes and gaps."
+ */
ListValue lv = new ListValue(' ');
+ LexicalUnit lu = lunit;
do {
Value v = super.createValue(lu, engine);
lv.append(v);
lu = lu.getNextLexicalUnit();
- if (lu != null && lu.getLexicalUnitType() == LexicalUnit.LexicalType.OPERATOR_COMMA) {
- lu = lu.getNextLexicalUnit();
+ if (lu != null) {
+ if (lu.getLexicalUnitType() == LexicalUnit.LexicalType.OPERATOR_COMMA) {
+ lu = lu.getNextLexicalUnit();
+ }
+ if (lu.getLexicalUnitType() == LexicalUnit.LexicalType.VAR) {
+ return createLexicalValue(lunit);
+ }
}
} while (lu != null);
return lv;
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg/StrokeMiterlimitManager.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg/StrokeMiterlimitManager.java
index 7a3203431..5e44e7de3 100644
--- a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg/StrokeMiterlimitManager.java
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg/StrokeMiterlimitManager.java
@@ -21,10 +21,16 @@
import org.w3c.css.om.unit.CSSUnit;
import org.w3c.dom.DOMException;
+import io.sf.carte.doc.style.css.CSSValue;
+import io.sf.carte.doc.style.css.CSSValue.Type;
import io.sf.carte.doc.style.css.nsac.LexicalUnit;
import io.sf.carte.echosvg.css.engine.CSSEngine;
import io.sf.carte.echosvg.css.engine.value.AbstractValueManager;
+import io.sf.carte.echosvg.css.engine.value.CSSProxyValueException;
+import io.sf.carte.echosvg.css.engine.value.CalcValue;
import io.sf.carte.echosvg.css.engine.value.FloatValue;
+import io.sf.carte.echosvg.css.engine.value.RevertValue;
+import io.sf.carte.echosvg.css.engine.value.UnsetValue;
import io.sf.carte.echosvg.css.engine.value.Value;
import io.sf.carte.echosvg.css.engine.value.ValueConstants;
import io.sf.carte.echosvg.css.engine.value.ValueManager;
@@ -96,18 +102,40 @@ public Value getDefaultValue() {
@Override
public Value createValue(LexicalUnit lu, CSSEngine engine) throws DOMException {
switch (lu.getLexicalUnitType()) {
- case INHERIT:
- return ValueConstants.INHERIT_VALUE;
-
case INTEGER:
return new FloatValue(CSSUnit.CSS_NUMBER, lu.getIntegerValue());
case REAL:
return new FloatValue(CSSUnit.CSS_NUMBER, lu.getFloatValue());
+ case INHERIT:
+ return ValueConstants.INHERIT_VALUE;
+
+ case UNSET:
+ return UnsetValue.getInstance();
+
+ case REVERT:
+ return RevertValue.getInstance();
+
+ case INITIAL:
+ return getDefaultValue();
+
+ case VAR:
+ case ATTR:
+ return createLexicalValue(lu);
+
+ case CALC:
+ Value calc = createCalc(lu);
+ if (calc.getCssValueType() == CSSValue.CssType.PROXY) {
+ throw new CSSProxyValueException();
+ } else if (calc.getPrimitiveType() != Type.EXPRESSION) {
+ break;
+ }
+ return ((CalcValue) calc).evaluate(null, null, engine, -1, null, CSSUnit.CSS_NUMBER);
+
default:
- throw createInvalidLexicalUnitDOMException(lu.getLexicalUnitType());
}
+ throw createInvalidLexicalUnitDOMException(lu.getLexicalUnitType());
}
/**
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg12/LineHeightManager.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg12/LineHeightManager.java
index 1e1061361..082b33e78 100644
--- a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg12/LineHeightManager.java
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg12/LineHeightManager.java
@@ -105,14 +105,16 @@ public Value getDefaultValue() {
public Value createValue(LexicalUnit lu, CSSEngine engine) throws DOMException {
switch (lu.getLexicalUnitType()) {
- case INHERIT:
- return ValueConstants.INHERIT_VALUE;
case IDENT: {
String s = lu.getStringValue().toLowerCase(Locale.ROOT);
if (CSSConstants.CSS_NORMAL_VALUE.equals(s))
return SVG12ValueConstants.NORMAL_VALUE;
throw createInvalidIdentifierDOMException(lu.getStringValue());
}
+
+ case INHERIT:
+ return ValueConstants.INHERIT_VALUE;
+
default:
return super.createValue(lu, engine);
}
@@ -137,7 +139,7 @@ public Value computeValue(CSSStylableElement elt, String pseudo, CSSEngine engin
if (value.getCssValueType() != Value.CssType.TYPED)
return value;
- switch (value.getCSSUnit()) {
+ switch (value.getUnitType()) {
case CSSUnit.CSS_NUMBER:
return new LineHeightValue(CSSUnit.CSS_NUMBER, value.getFloatValue(), true);
diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg12/MarginShorthandManager.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg12/MarginShorthandManager.java
index c4c4d8986..b9a209bf5 100644
--- a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg12/MarginShorthandManager.java
+++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/svg12/MarginShorthandManager.java
@@ -21,9 +21,12 @@
import org.w3c.dom.DOMException;
import io.sf.carte.doc.style.css.nsac.LexicalUnit;
+import io.sf.carte.doc.style.css.nsac.LexicalUnit.LexicalType;
import io.sf.carte.echosvg.css.engine.CSSEngine;
import io.sf.carte.echosvg.css.engine.value.AbstractValueFactory;
+import io.sf.carte.echosvg.css.engine.value.PendingValue;
import io.sf.carte.echosvg.css.engine.value.ShorthandManager;
+import io.sf.carte.echosvg.css.engine.value.ValueConstants;
import io.sf.carte.echosvg.css.engine.value.ValueManager;
import io.sf.carte.echosvg.util.SVG12CSSConstants;
@@ -31,8 +34,10 @@
* This class represents an object which provide support for the 'margin'
* shorthand property.
*
- * @author Stephane Hillion
- * @author For later modifications, see Git history.
+ *
+ * Original author: Stephane Hillion.
+ * For later modifications, see Git history.
+ *
* @version $Id$
*/
public class MarginShorthandManager extends AbstractValueFactory implements ShorthandManager {
@@ -69,14 +74,40 @@ public boolean isAdditiveProperty() {
* {@link ShorthandManager#setValues(CSSEngine,ShorthandManager.PropertyHandler,LexicalUnit,boolean)}.
*/
@Override
- public void setValues(CSSEngine eng, ShorthandManager.PropertyHandler ph, LexicalUnit lu, boolean imp)
- throws DOMException {
- if (lu.getLexicalUnitType() == LexicalUnit.LexicalType.INHERIT)
+ public void setValues(CSSEngine eng, ShorthandManager.PropertyHandler ph, final LexicalUnit lunit,
+ boolean imp) throws DOMException {
+ switch (lunit.getLexicalUnitType()) {
+ case INHERIT:
return;
+ case UNSET:
+ case REVERT:
+ case INITIAL:
+ // Set defaults
+ LexicalUnit luZero = ValueConstants.ZERO_LEXICAL_UNIT;
+ ph.property(SVG12CSSConstants.CSS_MARGIN_TOP_PROPERTY, luZero, imp);
+ ph.property(SVG12CSSConstants.CSS_MARGIN_RIGHT_PROPERTY, luZero, imp);
+ ph.property(SVG12CSSConstants.CSS_MARGIN_BOTTOM_PROPERTY, luZero, imp);
+ ph.property(SVG12CSSConstants.CSS_MARGIN_LEFT_PROPERTY, luZero, imp);
+ break;
+
+ case VAR:
+ case ATTR:
+ setPendingLonghands(eng, ph, lunit, imp);
+ return;
+
+ default:
+ break;
+ }
+
+ LexicalUnit lu = lunit;
LexicalUnit[] lus = new LexicalUnit[4];
int cnt = 0;
while (lu != null) {
+ if (lu.getLexicalUnitType() == LexicalType.VAR) {
+ setPendingLonghands(eng, ph, lunit, imp);
+ return;
+ }
if (cnt == 4)
throw createInvalidLexicalUnitDOMException(lu.getLexicalUnitType());
lus[cnt++] = lu;
@@ -102,4 +133,12 @@ public void setValues(CSSEngine eng, ShorthandManager.PropertyHandler ph, Lexica
ph.property(SVG12CSSConstants.CSS_MARGIN_LEFT_PROPERTY, lus[3], imp);
}
+ private void setPendingLonghands(CSSEngine eng, PropertyHandler ph, LexicalUnit lunit, boolean imp) {
+ PendingValue pending = new PendingValue(getPropertyName(), lunit);
+ ph.pendingValue(SVG12CSSConstants.CSS_MARGIN_TOP_PROPERTY, pending, imp);
+ ph.pendingValue(SVG12CSSConstants.CSS_MARGIN_RIGHT_PROPERTY, pending, imp);
+ ph.pendingValue(SVG12CSSConstants.CSS_MARGIN_BOTTOM_PROPERTY, pending, imp);
+ ph.pendingValue(SVG12CSSConstants.CSS_MARGIN_LEFT_PROPERTY, pending, imp);
+ }
+
}
diff --git a/echosvg-css/src/main/resources/io/sf/carte/echosvg/css/engine/value/resources/Messages.properties b/echosvg-css/src/main/resources/io/sf/carte/echosvg/css/engine/value/resources/Messages.properties
index 30f1da964..ac273ea58 100644
--- a/echosvg-css/src/main/resources/io/sf/carte/echosvg/css/engine/value/resources/Messages.properties
+++ b/echosvg-css/src/main/resources/io/sf/carte/echosvg/css/engine/value/resources/Messages.properties
@@ -29,7 +29,7 @@ The given string type ({1}) is invalid for \
the "{0}" property.
invalid.identifier = \
-The "{1}" identifier is not a valid value for the "{0}" property.
+The "{1}" identifier is not a valid value for the "{0}" property.
# !!! choices limited to 30 (java.text bug).
@@ -45,8 +45,11 @@ The given CSS primitive value ({1}) represents an invalid type for the "{0}".
invalid.float.value = \
The number ''{1}'' represents an invalid value for the ''{0}'' property.
+invalid.color.component.unit = \
+The "{0}" property does not support color values with type #{1} components.
+
invalid.rgb.component.unit = \
-The "{0}" property does not support RGB values with type #{1} components.
+The "{0}" property does not support RGB values with type #{1} components.
malformed.lexical.unit = \
A malformed value was assigned to a "{0}" property.
diff --git a/echosvg-dom/src/main/java/io/sf/carte/echosvg/dom/ExtensibleDOMImplementation.java b/echosvg-dom/src/main/java/io/sf/carte/echosvg/dom/ExtensibleDOMImplementation.java
index 80c6908fb..379665809 100644
--- a/echosvg-dom/src/main/java/io/sf/carte/echosvg/dom/ExtensibleDOMImplementation.java
+++ b/echosvg-dom/src/main/java/io/sf/carte/echosvg/dom/ExtensibleDOMImplementation.java
@@ -35,7 +35,7 @@
import org.w3c.dom.view.ViewCSS;
import io.sf.carte.doc.style.css.nsac.Parser;
-import io.sf.carte.doc.style.css.parser.CSSParser;
+import io.sf.carte.doc.style.css.om.CSSOMParser;
import io.sf.carte.echosvg.css.engine.CSSContext;
import io.sf.carte.echosvg.css.engine.CSSEngine;
import io.sf.carte.echosvg.css.engine.value.ShorthandManager;
@@ -117,7 +117,7 @@ public void registerCustomCSSShorthandManager(ShorthandManager sm) {
* Creates new CSSEngine and attach it to the document.
*/
public CSSEngine createCSSEngine(AbstractStylableDocument doc, CSSContext ctx) {
- Parser p = new CSSParser();
+ Parser p = new CSSOMParser();
ValueManager[] vms;
if (customValueManagers == null) {
diff --git a/echosvg-parser/src/main/java/io/sf/carte/echosvg/parser/UnitProcessor.java b/echosvg-parser/src/main/java/io/sf/carte/echosvg/parser/UnitProcessor.java
index a6ceac1ff..d7f9cb77f 100644
--- a/echosvg-parser/src/main/java/io/sf/carte/echosvg/parser/UnitProcessor.java
+++ b/echosvg-parser/src/main/java/io/sf/carte/echosvg/parser/UnitProcessor.java
@@ -144,15 +144,15 @@ public static float svgToUserSpace(float v, short type, short d, Context ctx) {
case SVGLength.SVG_LENGTHTYPE_PX:
return v;
case SVGLength.SVG_LENGTHTYPE_MM:
- return (v / ctx.getPixelUnitToMillimeter());
+ return v * 3.779527559055f; // 96 / 25.4
case SVGLength.SVG_LENGTHTYPE_CM:
- return (v * 10f / ctx.getPixelUnitToMillimeter());
+ return v * 37.79527559055f; // 96 / 2.54
case SVGLength.SVG_LENGTHTYPE_IN:
- return (v * 25.4f / ctx.getPixelUnitToMillimeter());
+ return v * 96f;
case SVGLength.SVG_LENGTHTYPE_PT:
- return (v * 25.4f / (72f * ctx.getPixelUnitToMillimeter()));
+ return v / 0.75f; // Mult. by 96 / 72
case SVGLength.SVG_LENGTHTYPE_PC:
- return (v * 25.4f / (6f * ctx.getPixelUnitToMillimeter()));
+ return v * 16f; // 96 / 6
case SVGLength.SVG_LENGTHTYPE_EMS:
return emsToPixels(v, d, ctx);
case SVGLength.SVG_LENGTHTYPE_EXS:
@@ -179,15 +179,15 @@ public static float userSpaceToSVG(float v, short type, short d, Context ctx) {
case SVGLength.SVG_LENGTHTYPE_PX:
return v;
case SVGLength.SVG_LENGTHTYPE_MM:
- return (v * ctx.getPixelUnitToMillimeter());
+ return v * 0.26458333333333f; // 25.4/96
case SVGLength.SVG_LENGTHTYPE_CM:
- return (v * ctx.getPixelUnitToMillimeter() / 10f);
+ return v * 0.026458333333333f; // 2.54/96
case SVGLength.SVG_LENGTHTYPE_IN:
- return (v * ctx.getPixelUnitToMillimeter() / 25.4f);
+ return v / 96f;
case SVGLength.SVG_LENGTHTYPE_PT:
- return (v * (72f * ctx.getPixelUnitToMillimeter()) / 25.4f);
+ return v * 0.75f; // 72/96
case SVGLength.SVG_LENGTHTYPE_PC:
- return (v * (6f * ctx.getPixelUnitToMillimeter()) / 25.4f);
+ return v / 16f;
case SVGLength.SVG_LENGTHTYPE_EMS:
return pixelsToEms(v, d, ctx);
case SVGLength.SVG_LENGTHTYPE_EXS:
@@ -415,20 +415,9 @@ public interface Context {
Element getElement();
/**
- * Returns the size of a px CSS unit in millimeters.
+ * Returns the resolution in {@code dpi}.
*/
- float getPixelUnitToMillimeter();
-
- /**
- * Returns the size of a px CSS unit in millimeters. This will be removed after
- * next release.
- *
- * @see #getPixelUnitToMillimeter()
- */
- @Deprecated(forRemoval = true)
- default float getPixelToMM() {
- return getPixelUnitToMillimeter();
- }
+ float getResolution();
/**
* Returns the font-size value.
diff --git a/echosvg-svg-dom/src/main/java/io/sf/carte/echosvg/dom/svg/SVGContext.java b/echosvg-svg-dom/src/main/java/io/sf/carte/echosvg/dom/svg/SVGContext.java
index 86e7fbe14..564b86013 100644
--- a/echosvg-svg-dom/src/main/java/io/sf/carte/echosvg/dom/svg/SVGContext.java
+++ b/echosvg-svg-dom/src/main/java/io/sf/carte/echosvg/dom/svg/SVGContext.java
@@ -38,8 +38,13 @@ public interface SVGContext {
/**
* Returns the size of a px CSS unit in millimeters.
+ *
+ * @deprecated Use {@link #getResolution()} instead.
*/
- float getPixelUnitToMillimeter();
+ @Deprecated
+ default float getPixelUnitToMillimeter() {
+ return 25.4f / getResolution();
+ }
/**
* Returns the size of a px CSS unit in millimeters. This will be removed after
@@ -52,6 +57,11 @@ default float getPixelToMM() {
return getPixelUnitToMillimeter();
}
+ /**
+ * Returns the resolution in dpi.
+ */
+ float getResolution();
+
/**
* Returns the tight bounding box in current user space (i.e., after application
* of the transform attribute, if any) on the geometry of all contained graphics
diff --git a/echosvg-swing/src/main/java/io/sf/carte/echosvg/swing/svg/JSVGComponent.java b/echosvg-swing/src/main/java/io/sf/carte/echosvg/swing/svg/JSVGComponent.java
index 6732d549d..8404058e0 100644
--- a/echosvg-swing/src/main/java/io/sf/carte/echosvg/swing/svg/JSVGComponent.java
+++ b/echosvg-swing/src/main/java/io/sf/carte/echosvg/swing/svg/JSVGComponent.java
@@ -2505,6 +2505,25 @@ public void run() {
}
}
+ @Override
+ public float getResolution() {
+ if (EventQueue.isDispatchThread()) {
+ return userAgent.getResolution();
+ } else {
+ class Query implements Runnable {
+ float result;
+
+ @Override
+ public void run() {
+ result = userAgent.getResolution();
+ }
+ }
+ Query q = new Query();
+ invokeAndWait(q);
+ return q.result;
+ }
+ }
+
/**
* Returns the default font family.
*/
@@ -3229,15 +3248,12 @@ public boolean showConfirm(String message) {
return JSVGComponent.this.showConfirm(message);
}
- /**
- * Returns the size of a px CSS unit in millimeters.
- */
@Override
- public float getPixelUnitToMillimeter() {
+ public float getResolution() {
if (svgUserAgent != null) {
- return svgUserAgent.getPixelUnitToMillimeter();
+ return svgUserAgent.getResolution();
}
- return 0.264583333333333333333f; // 96 dpi
+ return 96f; // 96 dpi
}
/**
@@ -3260,7 +3276,7 @@ public float getMediumFontSize() {
return svgUserAgent.getMediumFontSize();
}
// 9pt (72pt = 1in)
- return 9f * 25.4f / (72f * getPixelUnitToMillimeter());
+ return 9f * getResolution() / 72f;
}
/**
diff --git a/echosvg-swing/src/main/java/io/sf/carte/echosvg/swing/svg/SVGUserAgent.java b/echosvg-swing/src/main/java/io/sf/carte/echosvg/swing/svg/SVGUserAgent.java
index 217b20b32..4fee75493 100644
--- a/echosvg-swing/src/main/java/io/sf/carte/echosvg/swing/svg/SVGUserAgent.java
+++ b/echosvg-swing/src/main/java/io/sf/carte/echosvg/swing/svg/SVGUserAgent.java
@@ -72,8 +72,13 @@ public interface SVGUserAgent {
/**
* Returns the size of a px CSS unit in millimeters.
+ *
+ * @deprecated Use {@link #getResolution()}.
*/
- float getPixelUnitToMillimeter();
+ @Deprecated
+ default float getPixelUnitToMillimeter() {
+ return 25.4f / getResolution();
+ }
/**
* Returns the size of a px CSS unit in millimeters. This will be removed after
@@ -86,6 +91,11 @@ default float getPixelToMM() {
return getPixelUnitToMillimeter();
}
+ /**
+ * Returns the resolution in {@code dpi}.
+ */
+ float getResolution();
+
/**
* Returns the default font family.
*/
diff --git a/echosvg-swing/src/main/java/io/sf/carte/echosvg/swing/svg/SVGUserAgentAdapter.java b/echosvg-swing/src/main/java/io/sf/carte/echosvg/swing/svg/SVGUserAgentAdapter.java
index fde735d65..e7624f7b7 100644
--- a/echosvg-swing/src/main/java/io/sf/carte/echosvg/swing/svg/SVGUserAgentAdapter.java
+++ b/echosvg-swing/src/main/java/io/sf/carte/echosvg/swing/svg/SVGUserAgentAdapter.java
@@ -119,6 +119,11 @@ public float getPixelUnitToMillimeter() {
return 0.26458333333333333333333333333333f; // 96dpi
}
+ @Override
+ public float getResolution() {
+ return 96f;
+ }
+
/**
* Returns the default font family.
*/
@@ -132,8 +137,8 @@ public String getDefaultFontFamily() {
*/
@Override
public float getMediumFontSize() {
- // 9pt (72pt == 1in)
- return 9f * 25.4f / (72f * getPixelUnitToMillimeter());
+ // 9pt (72pt = 1in)
+ return 9f * getResolution() / 72f;
}
/**
diff --git a/echosvg-test/src/main/java/io/sf/carte/echosvg/test/image/ImageCompareUtil.java b/echosvg-test/src/main/java/io/sf/carte/echosvg/test/image/ImageCompareUtil.java
index 07a09fda5..c0866ece7 100644
--- a/echosvg-test/src/main/java/io/sf/carte/echosvg/test/image/ImageCompareUtil.java
+++ b/echosvg-test/src/main/java/io/sf/carte/echosvg/test/image/ImageCompareUtil.java
@@ -182,6 +182,10 @@ public String compare(float allowedPercentBelowThreshold, float allowedPercentOv
return null;
}
+ if (result < ImageComparator.DIFFERENT_PIXELS_BELOW_THRESHOLD) {
+ return ImageComparator.getResultDescription(result);
+ }
+
// We are in error (images are different: produce an image
// with the two images side by side as well as a diff image)
BufferedImage diff = ImageComparator.createDiffImage(imageA, imageB);
diff --git a/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/AbstractBypassRenderingCheck.java b/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/AbstractBypassRenderingCheck.java
index e1daa589d..6f17afcd5 100644
--- a/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/AbstractBypassRenderingCheck.java
+++ b/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/AbstractBypassRenderingCheck.java
@@ -56,7 +56,7 @@ public class AbstractBypassRenderingCheck {
static final String BROWSER_MEDIA = "screen";
- static final String PRINT_MEDIUM = "print";
+ static final String PRINT_MEDIA = "print";
void test(String file) throws TranscoderException, IOException {
test(file, 0);
@@ -82,7 +82,7 @@ void test(String file, int expectedErrorCount, boolean validating)
*/
void testPrint(String file, int expectedErrorCount)
throws TranscoderException, IOException {
- test(file, PRINT_MEDIUM, false, null, null, true, expectedErrorCount);
+ test(file, PRINT_MEDIA, false, null, null, true, expectedErrorCount);
}
/**
diff --git a/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/AbstractSamplesRendering.java b/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/AbstractSamplesRendering.java
index 70d7db02a..5e80ae588 100644
--- a/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/AbstractSamplesRendering.java
+++ b/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/AbstractSamplesRendering.java
@@ -183,6 +183,15 @@ void testAlternateSheet(String file, String alt, boolean validating)
runner.runTest(getBelowThresholdAllowed(), getOverThresholdAllowed());
}
+ void testDarkMode(String file)
+ throws TranscoderException, IOException {
+ RenderingTest runner = new RenderingTest();
+ runner.setValidating(Boolean.FALSE);
+ runner.setDarkMode(true);
+ runner.setFile(file);
+ runner.runTest(getBelowThresholdAllowed(), getOverThresholdAllowed());
+ }
+
void testUserSheet(String file, boolean validating) throws TranscoderException, IOException {
AltUserSheetRenderingTest runner = new AltUserSheetRenderingTest();
runner.setValidating(validating);
diff --git a/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/DenialOfServiceTest.java b/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/DenialOfServiceTest.java
new file mode 100644
index 000000000..64522916b
--- /dev/null
+++ b/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/DenialOfServiceTest.java
@@ -0,0 +1,139 @@
+/*
+
+ See the NOTICE file distributed with this work for additional
+ information regarding copyright ownership.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ */
+package io.sf.carte.echosvg.test.svg;
+
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.io.IOException;
+import java.util.concurrent.TimeUnit;
+
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.Timeout;
+
+import io.sf.carte.echosvg.css.engine.CSSCircularityException;
+import io.sf.carte.echosvg.css.engine.CSSResourceLimitException;
+import io.sf.carte.echosvg.test.TestFonts;
+import io.sf.carte.echosvg.transcoder.TranscoderException;
+
+/**
+ * Test documents that attempt a Denial of Service attack.
+ */
+public class DenialOfServiceTest {
+
+ private static String RES_PREFIX = "/io/sf/carte/echosvg/transcoder/security/";
+
+ @BeforeAll
+ public static void setUpBeforeClass() throws Exception {
+ TestFonts.loadTestFonts();
+ }
+
+ private void testSecurity(String file, int expectedErrorCount) throws TranscoderException, IOException {
+ TranscoderSecurityCheck runner = new TranscoderSecurityCheck(expectedErrorCount);
+ runner.runTest(RES_PREFIX + file);
+ }
+
+ /*
+ * Tests
+ */
+
+ /**
+ * Check the behaviour on attr() circularity.
+ *
+ *
+ * If the test runs for more than a few seconds, the test failed.
+ *
+ *
+ * @throws TranscoderException
+ * @throws IOException
+ */
+ @Test
+ @Timeout(value = 2500, unit = TimeUnit.MILLISECONDS)
+ public void testAttrCircularity() throws TranscoderException, IOException {
+ assertThrows(CSSCircularityException.class, () -> testSecurity("attrCircularity.svg", 4));
+ }
+
+ /**
+ * Test a Billion Laughs DoS attack against the var() implementation.
+ *
+ *
+ * If the test runs for more than 3 seconds, either the computer is really slow
+ * or the test failed.
+ *
+ *
+ * @throws TranscoderException
+ * @throws IOException
+ */
+ @Test
+ @Timeout(value = 3000, unit = TimeUnit.MILLISECONDS)
+ public void testVarBLA() throws TranscoderException, IOException {
+ assertThrows(CSSResourceLimitException.class, () -> testSecurity("varBillionLaughsAttack.svg", 0));
+ }
+
+ /**
+ * Test a Billion Laughs DoS attack against the var() implementation, fallback
+ * variant.
+ *
+ *
+ * If the test runs for more than 3 seconds, either the computer is really slow
+ * or the test failed.
+ *
+ * If the test runs for more than a few seconds, the test failed.
+ *
+ *
+ * @throws TranscoderException
+ * @throws IOException
+ */
+ @Test
+ @Timeout(value = 2500, unit = TimeUnit.MILLISECONDS)
+ public void testVarFallbackCircularity() throws TranscoderException, IOException {
+ assertThrows(CSSCircularityException.class, () -> testSecurity("varFallbackCircularity.svg", 0));
+ }
+
+}
diff --git a/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/MermaidRenderingTest.java b/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/MermaidRenderingTest.java
index 02e2df121..580ac0ebf 100644
--- a/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/MermaidRenderingTest.java
+++ b/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/MermaidRenderingTest.java
@@ -112,7 +112,7 @@ public void testC4Dynamic() throws TranscoderException, IOException {
@Test
public void testClass() throws TranscoderException, IOException {
- testMermaid("samples/tests/spec2/foreign/mermaid-class.svg", 1);
+ testMermaid("samples/tests/spec2/foreign/mermaid-class.svg");
}
@Test
@@ -137,17 +137,17 @@ public void testFlowChartCyrillic() throws TranscoderException, IOException {
@Test
public void testGantt() throws TranscoderException, IOException {
- testMermaid("samples/tests/spec2/foreign/mermaid-gantt.svg", 6);
+ testMermaid("samples/tests/spec2/foreign/mermaid-gantt.svg", 1);
}
@Test
public void testGitGraph() throws TranscoderException, IOException {
- testMermaid("samples/tests/spec2/foreign/mermaid-git-graph.svg", 1);
+ testMermaid("samples/tests/spec2/foreign/mermaid-git-graph.svg");
}
@Test
public void testJourney() throws TranscoderException, IOException {
- testMermaid("samples/tests/spec2/foreign/mermaid-journey.svg", 9);
+ testMermaid("samples/tests/spec2/foreign/mermaid-journey.svg", 7);
}
@Test
diff --git a/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/ResolutionPxMmRenderingTest.java b/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/ResolutionPxMmRenderingTest.java
index 66d4e3eb7..ba7673a5d 100644
--- a/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/ResolutionPxMmRenderingTest.java
+++ b/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/ResolutionPxMmRenderingTest.java
@@ -24,7 +24,7 @@
/**
* Checks for regressions in rendering of SVG with varying resolution.
*
- * @see io.sf.carte.echosvg.transcoder.image.test.PixelToMMTest
+ * @see io.sf.carte.echosvg.transcoder.image.test.ResolutionTest
*
* @author See Git history.
* @version $Id$
@@ -55,6 +55,7 @@ protected CharSequence getImageSuffix() {
/**
* Returns the ImageTranscoder the Test should use
*/
+ @SuppressWarnings("deprecation")
@Override
ImageTranscoder getTestImageTranscoder() {
ImageTranscoder t = super.getTestImageTranscoder();
diff --git a/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/SVGRenderingAccuracyTest.java b/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/SVGRenderingAccuracyTest.java
index e3ecd3032..c6eb6e6a4 100644
--- a/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/SVGRenderingAccuracyTest.java
+++ b/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/SVGRenderingAccuracyTest.java
@@ -79,6 +79,10 @@ public class SVGRenderingAccuracyTest extends AbstractRenderingAccuracyTest {
*/
private String media;
+ /*
+ * Enable or disable dark mode.
+ */
+ private boolean darkMode = false;
// Batik uses 9
private static final int DEFAULT_COMPRESSION_LEVEL = 9;
@@ -154,6 +158,15 @@ public void setMedia(String media) {
this.media = media;
}
+ /**
+ * Enable or disable the dark mode.
+ *
+ * @param darkMode {@code true} to enable the dark mode.
+ */
+ public void setDarkMode(boolean darkMode) {
+ this.darkMode = darkMode;
+ }
+
/**
* Set the compression level.
*
@@ -204,7 +217,7 @@ protected CharSequence getImageSuffix() {
boolean nonDefCompr = getCompressionLevel() != getDefaultCompressionLevel();
boolean nonDefMedia = media != null && !DEFAULT_MEDIUM.equals(media);
- if (nonDefCompr && nonDefMedia && tEXt == null && iTXt == null && zTXt == null) {
+ if (nonDefCompr && nonDefMedia && !darkMode && tEXt == null && iTXt == null && zTXt == null) {
return "";
}
@@ -212,6 +225,11 @@ protected CharSequence getImageSuffix() {
if (nonDefMedia) {
buf.append("-").append(media);
}
+
+ if (darkMode) {
+ buf.append("-dark");
+ }
+
if (nonDefCompr) {
buf.append("-z").append(getCompressionLevel());
}
@@ -277,7 +295,14 @@ protected void checkErrorHandler(ErrorHandler errorHandler) {
ImageTranscoder getTestImageTranscoder() {
ImageTranscoder t = createTestImageTranscoder();
t.addTranscodingHint(ImageTranscoder.KEY_FORCE_TRANSPARENT_WHITE, Boolean.FALSE);
- t.addTranscodingHint(ImageTranscoder.KEY_BACKGROUND_COLOR, new Color(0, 0, 0, 0));
+
+ if (darkMode) {
+ // Opaque background for dark mode
+ t.addTranscodingHint(ImageTranscoder.KEY_BACKGROUND_COLOR, new Color(0, 0, 0, 255));
+ } else {
+ t.addTranscodingHint(ImageTranscoder.KEY_BACKGROUND_COLOR, new Color(0, 0, 0, 0));
+ }
+
t.addTranscodingHint(SVGAbstractTranscoder.KEY_EXECUTE_ONLOAD, Boolean.TRUE);
if (validate) {
@@ -292,6 +317,10 @@ ImageTranscoder getTestImageTranscoder() {
t.addTranscodingHint(SVGAbstractTranscoder.KEY_MEDIA, media);
}
+ if (darkMode) {
+ t.addTranscodingHint(SVGAbstractTranscoder.KEY_PREFERS_COLOR_SCHEME, "dark");
+ }
+
if (getCompressionLevel() != getDefaultCompressionLevel()) {
t.addTranscodingHint(PNGTranscoder.KEY_COMPRESSION_LEVEL, getCompressionLevel());
}
diff --git a/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/SamplesSpec2RenderingTest.java b/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/SamplesSpec2RenderingTest.java
index 89537b76f..15e247600 100644
--- a/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/SamplesSpec2RenderingTest.java
+++ b/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/SamplesSpec2RenderingTest.java
@@ -56,6 +56,31 @@ public void testHref() throws TranscoderException, IOException {
/*
* CSS3 Styling
*/
+ @Test
+ public void testAttrValues() throws TranscoderException, IOException {
+ testNV("samples/tests/spec2/styling/attrValues.svg");
+ }
+
+ @Test
+ public void testConditionalRules() throws TranscoderException, IOException {
+ testNV("samples/tests/spec2/styling/conditionalRules.svg");
+ }
+
+ @Test
+ public void testConditionalRulesDark() throws TranscoderException, IOException {
+ testDarkMode("samples/tests/spec2/styling/conditionalRules.svg");
+ }
+
+ @Test
+ public void testConditionalRulesAlternate() throws TranscoderException, IOException {
+ testAlternateSheet("samples/tests/spec2/styling/conditionalRules.svg", "Gray", false);
+ }
+
+ @Test
+ public void testConditionalRulesPrint() throws TranscoderException, IOException {
+ testNVErrIgnore("samples/tests/spec2/styling/conditionalRules.svg", PRINT_MEDIA, 0);
+ }
+
@Test
public void testMermaidColor4() throws TranscoderException, IOException {
testNV("samples/tests/spec2/styling/mermaid-color4.svg");
diff --git a/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/SamplesSpecRenderingTest.java b/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/SamplesSpecRenderingTest.java
index e72ba0243..dcf7b9915 100644
--- a/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/SamplesSpecRenderingTest.java
+++ b/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/SamplesSpecRenderingTest.java
@@ -422,6 +422,11 @@ public void testPaintMarkersVisibility() throws TranscoderException, IOException
test("samples/tests/spec/painting/visibility.svg");
}
+ @Test
+ public void testPaintMarkersVisibilityUnset() throws TranscoderException, IOException {
+ test("samples/tests/spec/painting/visibilityUnset.svg");
+ }
+
/*
* Paints
*/
@@ -523,6 +528,7 @@ public void testRenderingPaintOpacity() throws TranscoderException, IOException
test("samples/tests/spec/rendering/paintOpacity.svg");
}
+ @Test
public void testRenderingResolutionPxMM() throws TranscoderException, IOException {
testResolutionPxMM("samples/tests/spec/rendering/resolution.svg", 0.25f);
}
diff --git a/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/StyleBypassRenderingTest.java b/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/StyleBypassRenderingTest.java
index 1b03a9f29..eab48a6cd 100644
--- a/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/StyleBypassRenderingTest.java
+++ b/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/StyleBypassRenderingTest.java
@@ -1340,28 +1340,28 @@ public void testBug19363() throws TranscoderException, IOException {
@Test
public void testCSS3_All() throws TranscoderException, IOException {
testAllInputSources("samples/tests/spec2/styling/css3.html", null, false, null, null,
- false, 4);
+ false, 0);
}
@Test
public void testCSS3Print() throws TranscoderException, IOException {
- testPrint("samples/tests/spec2/styling/css3.html", 4);
+ testPrint("samples/tests/spec2/styling/css3.html", 0);
}
@Test
public void testCSS3AlternateStylesheet() throws TranscoderException, IOException {
- testAlternate("samples/tests/spec2/styling/css3.html", "Gray", false, 4);
+ testAlternate("samples/tests/spec2/styling/css3.html", "Gray", false, 0);
}
@Test
public void testCSS3Dark() throws TranscoderException, IOException {
- testDark("samples/tests/spec2/styling/css3.html", 4);
+ testDark("samples/tests/spec2/styling/css3.html", 0);
}
@Test
public void testCSS3_Selector() throws TranscoderException, IOException {
test("samples/tests/spec2/styling/css3.html", SVGRenderingAccuracyTest.DEFAULT_MEDIUM,
- false, null, "#theSVG", true, 4);
+ false, null, "#theSVG", true, 0);
}
}
diff --git a/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/TranscoderSecurityCheck.java b/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/TranscoderSecurityCheck.java
new file mode 100644
index 000000000..96133e827
--- /dev/null
+++ b/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/TranscoderSecurityCheck.java
@@ -0,0 +1,104 @@
+/*
+
+ See the NOTICE file distributed with this work for additional
+ information regarding copyright ownership.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ */
+package io.sf.carte.echosvg.test.svg;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import io.sf.carte.echosvg.transcoder.ErrorHandler;
+import io.sf.carte.echosvg.transcoder.SVGAbstractTranscoder;
+import io.sf.carte.echosvg.transcoder.TranscoderException;
+import io.sf.carte.echosvg.transcoder.TranscoderInput;
+import io.sf.carte.echosvg.transcoder.TranscoderOutput;
+import io.sf.carte.echosvg.transcoder.image.ImageTranscoder;
+import io.sf.carte.echosvg.transcoder.image.PNGTranscoder;
+import io.sf.carte.echosvg.transcoder.test.DummyErrorHandler;
+
+/**
+ * Check transcoder security.
+ *
+ *
+ * Use it to transcode an image that is expected to throw a SecurityException.
+ * No attempt is made to compare the result with a reference.
+ *
+ *
+ * @version $Id$
+ */
+public class TranscoderSecurityCheck {
+
+ private final int expectedErrorCount;
+
+ public TranscoderSecurityCheck() {
+ this(0);
+ }
+
+ public TranscoderSecurityCheck(int expectedErrorCount) {
+ super();
+ this.expectedErrorCount = expectedErrorCount;
+ }
+
+ public void runTest(String file) throws TranscoderException, IOException {
+ SVGAbstractTranscoder transcoder = getTestImageTranscoder();
+
+ ErrorHandler errHandler = createErrorHandler();
+ transcoder.setErrorHandler(errHandler);
+
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+ TranscoderOutput dst = new TranscoderOutput(os);
+
+ InputStream is = getSourceStream(file);
+ if (is == null) {
+ throw new IOException("Null stream for " + file);
+ }
+ TranscoderInput inp = new TranscoderInput(is);
+ inp.setEncoding("utf-8");
+
+ try {
+ transcoder.transcode(inp, dst);
+ } finally {
+ is.close();
+ checkErrorHandler(errHandler);
+ }
+ }
+
+ protected InputStream getSourceStream(String file) {
+ return getClass().getResourceAsStream(file);
+ }
+
+ private SVGAbstractTranscoder getTestImageTranscoder() {
+ SVGAbstractTranscoder t = createTestImageTranscoder();
+ t.addTranscodingHint(ImageTranscoder.KEY_FORCE_TRANSPARENT_WHITE, Boolean.FALSE);
+ t.addTranscodingHint(SVGAbstractTranscoder.KEY_EXECUTE_ONLOAD, Boolean.TRUE);
+ return t;
+ }
+
+ SVGAbstractTranscoder createTestImageTranscoder() {
+ return new PNGTranscoder();
+ }
+
+ private ErrorHandler createErrorHandler() {
+ return new DummyErrorHandler();
+ }
+
+ private void checkErrorHandler(ErrorHandler errHandler) {
+ ((DummyErrorHandler) errHandler).assertErrorCount(expectedErrorCount);
+ }
+
+}
diff --git a/echosvg-test/src/test/java/io/sf/carte/echosvg/transcoder/image/test/AbstractImageTranscoderTest.java b/echosvg-test/src/test/java/io/sf/carte/echosvg/transcoder/image/test/AbstractImageTranscoderTest.java
index f227dd31f..4b6e212cf 100644
--- a/echosvg-test/src/test/java/io/sf/carte/echosvg/transcoder/image/test/AbstractImageTranscoderTest.java
+++ b/echosvg-test/src/test/java/io/sf/carte/echosvg/transcoder/image/test/AbstractImageTranscoderTest.java
@@ -275,6 +275,10 @@ private boolean compareImage(BufferedImage img) throws TranscoderException, IOEx
ByteArrayOutputStream out = new ByteArrayOutputStream(2048);
TranscoderOutput output = new TranscoderOutput(out);
PNGTranscoder t = new PNGTranscoder();
+ Map hints = createTranscodingHints();
+ if (hints != null) {
+ t.setTranscodingHints(hints);
+ }
t.writeImage(img, output);
byte[] imgData = out.toByteArray();
diff --git a/echosvg-test/src/test/java/io/sf/carte/echosvg/transcoder/image/test/PixelToMMTest.java b/echosvg-test/src/test/java/io/sf/carte/echosvg/transcoder/image/test/ResolutionTest.java
similarity index 66%
rename from echosvg-test/src/test/java/io/sf/carte/echosvg/transcoder/image/test/PixelToMMTest.java
rename to echosvg-test/src/test/java/io/sf/carte/echosvg/transcoder/image/test/ResolutionTest.java
index 716a530f7..a3107543d 100644
--- a/echosvg-test/src/test/java/io/sf/carte/echosvg/transcoder/image/test/PixelToMMTest.java
+++ b/echosvg-test/src/test/java/io/sf/carte/echosvg/transcoder/image/test/ResolutionTest.java
@@ -29,14 +29,17 @@
import io.sf.carte.echosvg.transcoder.TranscodingHints.Key;
/**
- * Test the ImageTranscoder with the KEY_PIXEL_UNIT_TO_MILLIMETER transcoding
- * hint.
+ * Test the ImageTranscoder with the KEY_RESOLUTION_DPI transcoding hint.
*
- * @author Thierry Kormann
- * @author For later modifications, see Git history.
+ *
+ * Based on PixelToMM test by
+ * Thierry Kormann. For
+ * later modifications, see Git history.
+ *
+ *
* @version $Id$
*/
-public class PixelToMMTest extends AbstractImageTranscoderTest {
+public class ResolutionTest extends AbstractImageTranscoderTest {
/** The URI of the input image. */
private String inputURI;
@@ -44,33 +47,33 @@ public class PixelToMMTest extends AbstractImageTranscoderTest {
/** The URI of the reference image. */
private String refImageURI;
- /** The pixel to mm factor. */
- private float px2mm;
+ /** The resolution. */
+ private float resolution;
@Test
public void test96dpi() throws TranscoderException {
- testPixelToMM("test-resources/io/sf/carte/echosvg/transcoder/image/resources/px2mm.svg",
- "test-references/io/sf/carte/echosvg/transcoder/image/px2mm96dpi.png", 0.2645833f);
+ testResolution("test-resources/io/sf/carte/echosvg/transcoder/image/resources/resolution.svg",
+ "test-references/io/sf/carte/echosvg/transcoder/image/resolution96dpi.png", 96f);
}
@Test
public void test72dpi() throws TranscoderException {
- testPixelToMM("test-resources/io/sf/carte/echosvg/transcoder/image/resources/px2mm.svg",
- "test-references/io/sf/carte/echosvg/transcoder/image/px2mm72dpi.png", 0.3528f);
+ testResolution("test-resources/io/sf/carte/echosvg/transcoder/image/resources/resolution.svg",
+ "test-references/io/sf/carte/echosvg/transcoder/image/resolution72dpi.png", 72f);
}
/**
- * Runs a new PixelToMMTest.
+ * Runs a new ResolutionTest.
*
* @param inputURI the URI of the input image
* @param refImageURI the URI of the reference image
- * @param px2mm the pixel to mm conversion factor
- * @throws TranscoderException
+ * @param resolution the resolution
+ * @throws TranscoderException
*/
- private void testPixelToMM(String inputURI, String refImageURI, float px2mm) throws TranscoderException {
+ private void testResolution(String inputURI, String refImageURI, float resolution) throws TranscoderException {
this.inputURI = inputURI;
this.refImageURI = refImageURI;
- this.px2mm = px2mm;
+ this.resolution = resolution;
runTest();
}
@@ -88,7 +91,7 @@ protected TranscoderInput createTranscoderInput() {
@Override
protected Map createTranscodingHints() {
Map hints = new HashMap<>(3);
- hints.put(SVGAbstractTranscoder.KEY_PIXEL_UNIT_TO_MILLIMETER, px2mm);
+ hints.put(SVGAbstractTranscoder.KEY_RESOLUTION_DPI, resolution);
return hints;
}
diff --git a/echosvg-transcoder/src/main/java/io/sf/carte/echosvg/transcoder/SVGAbstractTranscoder.java b/echosvg-transcoder/src/main/java/io/sf/carte/echosvg/transcoder/SVGAbstractTranscoder.java
index 996bace25..142b92898 100644
--- a/echosvg-transcoder/src/main/java/io/sf/carte/echosvg/transcoder/SVGAbstractTranscoder.java
+++ b/echosvg-transcoder/src/main/java/io/sf/carte/echosvg/transcoder/SVGAbstractTranscoder.java
@@ -895,6 +895,35 @@ protected void setImageSize(float docWidth, float docHeight) {
*/
public static final TranscodingHints.Key KEY_MEDIA = new StringKey();
+ /**
+ * The preferred color scheme key.
+ *
+ *
+ *
+ *
Key:
+ *
KEY_PREFERS_COLOR_SCHEME
+ *
+ *
+ *
Value:
+ *
String
+ *
+ *
+ *
Default:
+ *
"light"
+ *
+ *
+ *
Required:
+ *
No
+ *
+ *
+ *
Description:
+ *
Specify the preferred color scheme to use in
+ * CSS media queries.
+ *
+ *
+ */
+ public static final TranscodingHints.Key KEY_PREFERS_COLOR_SCHEME = new StringKey();
+
/**
* The CSS selector key.
*
@@ -1012,29 +1041,38 @@ protected void setImageSize(float docWidth, float docHeight) {
/**
* The number of millimeters in each pixel key.
- *
- *
- *
- *
Key:
- *
KEY_PIXEL_UNIT_TO_MILLIMETER
- *
- *
- *
Value:
- *
Float
- *
- *
- *
Default:
- *
0.264583
- *
- *
- *
Required:
- *
No
- *
- *
- *
Description:
- *
Specify the size of a px CSS unit in millimeters.
- *
- *
+ *
+ * Using a concept of physical pixels instead of CSS pixels is a bad idea which
+ * leads to distorted shapes, unexpected font sizes and wrong aspect ratios.
+ * Physical pixels were removed from Web standards decades ago, please use
+ * {@code KEY_RESOLUTION_DPI} instead.
+ *
+ * @deprecated as of EchoSVG 2.0
+ * @see #KEY_RESOLUTION_DPI
+ *
+ *
+ *
+ *
Key:
+ *
KEY_PIXEL_UNIT_TO_MILLIMETER
+ *
+ *
+ *
Value:
+ *
Float
+ *
+ *
+ *
Default:
+ *
0.264583
+ *
+ *
+ *
Required:
+ *
No
+ *
+ *
+ *
Description:
+ *
Specify the size of a px CSS unit in
+ * millimeters.
+ *
+ *
*/
public static final TranscodingHints.Key KEY_PIXEL_UNIT_TO_MILLIMETER = new FloatKey();
@@ -1071,6 +1109,36 @@ protected void setImageSize(float docWidth, float docHeight) {
@Deprecated
public static final TranscodingHints.Key KEY_PIXEL_TO_MM = KEY_PIXEL_UNIT_TO_MILLIMETER;
+ /**
+ * The resolution expressed in {@code dpi} key.
+ *
+ *
+ *
+ *
Key:
+ *
KEY_RESOLUTION_DPI
+ *
+ *
+ *
Value:
+ *
Float
+ *
+ *
+ *
Default:
+ *
96
+ *
+ *
+ *
Required:
+ *
No
+ *
+ *
+ *
Description:
+ *
The resolution expressed in {@code dpi}. If
+ * not set, implementations may check for {@code KEY_PIXEL_UNIT_TO_MILLIMETER}
+ * and compute the resolution from that value.
+ *
+ *
+ */
+ public static final TranscodingHints.Key KEY_RESOLUTION_DPI = new FloatKey();
+
/**
* The 'onload' execution key.
*