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}). - *

- * Cast to {@link NumericValue}. - *

- */ - NUMERIC, - - /** - * String. - *

- * Cast to {@link StringValue}. - *

- */ - STRING, - - /** - * Identifier. - *

- * Cast to {@link KeywordValue}. - *

- */ - IDENT, - - /** - * Color. - */ - COLOR, - - /** - * Color-Mix function. - */ - COLOR_MIX, - - /** - * URI ({@code url()}). - *

- * Cast to {@link CSSStringValue}. - *

- */ - URI, - - /** - * {@code rect()} function. - */ - RECT, - - /** - * An expression with algebraic syntax (i.e. calc()). - */ - EXPRESSION, - - /** - * Gradient function. - */ - GRADIENT, - - /** - * CSS counter() function. - */ - COUNTER, - - /** - * CSS counters() function. - */ - COUNTERS, - - /** - * cubic-bezier() easing function. - */ - CUBIC_BEZIER, - - /** - * steps() easing function. - */ - STEPS, - - /** - * Function. - */ - FUNCTION, - - /** - * Mathematical function (as defined by CSS Values and Units). - */ - MATH_FUNCTION, - - /** - * Unicode range. - */ - UNICODE_RANGE, - - /** - * Unicode character. - */ - UNICODE_CHARACTER, - - /** - * Unicode wildcard. - */ - UNICODE_WILDCARD, - - /** - * Element reference. - *

- * Cast to {@link CSSKeywordValue}. - *

- */ - ELEMENT_REFERENCE, - - /** - * Ratio value. - */ - RATIO, - - /** - * {@code attr()} function. - */ - ATTR, - - /** - * Custom property reference. - */ - VAR, - - /** - * Environment variable. - */ - ENV, - - /** - * Lexical value. - */ - LEXICAL, - - /** - * For this library's internal use. - */ - INTERNAL, - - /** - * Invalid (non-primitive and non-keyword) value. - *

- * 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 @@ - - +/* - - + */ +package io.sf.carte.echosvg.css.engine; - +import io.sf.carte.echosvg.css.CSSSecurityException; - +/** + * A circularity was detected. + */ +public class CSSCircularityException extends CSSSecurityException { - + 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. * - *

- * Original author: Stephane Hillion. - *

* @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 @@ *

* @version $Id$ */ -public class InheritValue extends AbstractValue implements CSSKeywordValue { +public final class InheritValue extends KeywordValue { /** * The only instance of this class. @@ -40,15 +37,7 @@ public class InheritValue extends AbstractValue implements CSSKeywordValue { /** * Creates a new InheritValue object. */ - protected InheritValue() { - } - - /** - * A string representation of the current value. - */ - @Override - public String getCssText() { - return getValue(); + InheritValue() { } @Override @@ -56,19 +45,6 @@ public String getValue() { return "inherit"; } - @Override - public void setValue(String value) throws DOMTypeException { - throw new DOMTypeException("Not supported."); - } - - /** - * A code defining the type of the value. - */ - @Override - public CssType getCssValueType() { - return CssType.KEYWORD; - } - @Override public Type getPrimitiveType() { return Type.INHERIT; @@ -80,11 +56,12 @@ public InheritValue clone() { } /** - * Returns a printable representation of this object. + * Get the instance of {@code inherit}. + * + * @return the instance of {@code inherit}. */ - @Override - public String toString() { - return getCssText(); + public static Value getInstance() { + return INSTANCE; } } diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/KeywordValue.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/KeywordValue.java new file mode 100644 index 000000000..8795e6d1c --- /dev/null +++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/KeywordValue.java @@ -0,0 +1,57 @@ +/* + + 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.api.DOMTypeException; +import org.w3c.css.om.typed.CSSKeywordValue; + +/** + * A CSS-wide non-primitive keyword value: 'inherit', 'unset', 'revert'. + * + */ +abstract class KeywordValue extends AbstractValue implements CSSKeywordValue { + + /** + * Creates a new UnsetValue object. + */ + protected KeywordValue() { + } + + /** + * A string representation of the current value. + */ + @Override + public String getCssText() { + return getValue(); + } + + @Override + public void setValue(String value) throws DOMTypeException { + throw new DOMTypeException("Not supported."); + } + + /** + * A code defining the type of the value. + */ + @Override + public CssType getCssValueType() { + return CssType.KEYWORD; + } + +} diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/LCHColorValue.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/LCHColorValue.java index 46d273651..0181def91 100644 --- a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/LCHColorValue.java +++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/LCHColorValue.java @@ -124,7 +124,7 @@ public void setL(CSSNumericValue lightness) 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("LC component must be a number or percentage."); } if (ch.handler != null) { @@ -162,7 +162,7 @@ public void setH(CSSNumericValue h) throws DOMSyntaxException { private NumericValue hueComponent(CSSNumericValue h) { NumericValue ch = (NumericValue) h; - if (ch.getCSSUnit() != CSSUnit.CSS_NUMBER && !CSSUnit.isAngleUnitType(ch.getCSSUnit())) { + if (ch.getUnitType() != CSSUnit.CSS_NUMBER && !CSSUnit.isAngleUnitType(ch.getUnitType())) { throw new DOMSyntaxException("Hue component must be a number or angle."); } if (ch.handler != null) { diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/LabColorValue.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/LabColorValue.java index 17cb92ed2..29e71e1e0 100644 --- a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/LabColorValue.java +++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/LabColorValue.java @@ -124,7 +124,7 @@ public void setL(CSSNumericValue lightness) 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("Lab component must be a number or percentage."); } if (ch.handler != null) { diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/LengthManager.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/LengthManager.java index 48c5072d8..69b7e2674 100644 --- a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/LengthManager.java +++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/LengthManager.java @@ -21,10 +21,10 @@ 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; @@ -64,6 +64,23 @@ public Value createValue(LexicalUnit lu, CSSEngine engine) throws DOMException { case PERCENTAGE: return new FloatValue(CSSUnit.CSS_PERCENTAGE, lu.getFloatValue()); + + case UNSET: + return UnsetValue.getInstance(); + + case REVERT: + return RevertValue.getInstance(); + + case INITIAL: + return getDefaultValue(); + + case VAR: + case ATTR: + return createLexicalValue(lu); + + case CALC: + return createCalc(lu); + default: break; } @@ -96,38 +113,41 @@ public Value createFloatValue(short type, float floatValue) throws DOMException public Value computeValue(CSSStylableElement elt, String pseudo, CSSEngine engine, int idx, StyleMap sm, Value value) { if (value.getPrimitiveType() != Type.NUMERIC) { - return value; + if (value.getPrimitiveType() != Type.EXPRESSION) { + return value; + } + try { + return evaluateCalc((CalcValue) value, elt, pseudo, engine, idx, sm, CSSUnit.CSS_PX); + } catch (Exception e) { + return isInheritedProperty() ? null : getDefaultValue(); + } } - switch (value.getCSSUnit()) { + CSSContext ctx; + switch (value.getUnitType()) { case CSSUnit.CSS_NUMBER: case CSSUnit.CSS_PX: return value; case CSSUnit.CSS_MM: - CSSContext ctx = engine.getCSSContext(); float v = value.getFloatValue(); - 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 = value.getFloatValue(); - 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 = value.getFloatValue(); - 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 = value.getFloatValue(); - 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 = value.getFloatValue(); - return new FloatValue(CSSUnit.CSS_NUMBER, (v * 25.4f / (6f * ctx.getPixelUnitToMillimeter()))); + return new FloatValue(CSSUnit.CSS_NUMBER, v * 16f); case CSSUnit.CSS_EM: sm.putFontSizeRelative(idx, true); @@ -247,8 +267,8 @@ public Value computeValue(CSSStylableElement elt, String pseudo, CSSEngine engin // Maybe it is one of the new absolute length units try { value = new FloatValue(CSSUnit.CSS_NUMBER, - NumberValue.floatValueConversion(value.getFloatValue(), value.getCSSUnit(), CSSUnit.CSS_MM) - / engine.getCSSContext().getPixelUnitToMillimeter()); + NumberValue.floatValueConversion(value.getFloatValue(), value.getUnitType(), + CSSUnit.CSS_PX)); } catch (DOMException e) { } } @@ -256,6 +276,11 @@ public Value computeValue(CSSStylableElement elt, String pseudo, CSSEngine engin return value; } + protected Value evaluateCalc(CalcValue value, CSSStylableElement elt, String pseudo, CSSEngine engine, + int idx, StyleMap sm, short destUnit) throws DOMException { + return value.evaluate(elt, pseudo, engine, idx, sm, destUnit); + } + // // Orientation enumeration // diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/LexicalHelper.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/LexicalHelper.java new file mode 100644 index 000000000..5e70ce3ca --- /dev/null +++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/LexicalHelper.java @@ -0,0 +1,43 @@ +/* + + 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 java.io.StringReader; + +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; + +/** + * Lexical Helper + * + * @version $Id$ + */ +class LexicalHelper { + + public static LexicalUnit parsePropertyValue(String value) { + try { + return new CSSParser().parsePropertyValue(new StringReader(value)); + } catch (CSSParseException | IOException e) { + return null; + } + } + +} diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/LexicalValue.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/LexicalValue.java new file mode 100644 index 000000000..e26f7e321 --- /dev/null +++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/LexicalValue.java @@ -0,0 +1,71 @@ +/* + + 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 io.sf.carte.doc.style.css.nsac.LexicalUnit; + +/** + * A value containing {@code var()} or any PROXY value. + * + * @version $Id$ + */ +public class LexicalValue extends AbstractValue { + + private LexicalUnit lunit = null; + + /** + * Creates a new LexicalValue object. + * + * @param params the lexical unit with the {@code var()} function(s). + */ + public LexicalValue(LexicalUnit lunit) throws IllegalArgumentException { + super(); + this.lunit = lunit; + } + + /** + * A code defining the type of the value. + */ + @Override + public CssType getCssValueType() { + return CssType.PROXY; + } + + @Override + public Type getPrimitiveType() { + return Type.LEXICAL; + } + + public LexicalUnit getLexicalUnit() { + return lunit; + } + + @Override + public String getCssText() { + return lunit.toString(); + } + + @Override + public LexicalValue clone() { + LexicalValue clon = (LexicalValue) super.clone(); + clon.lunit = lunit; + return clon; + } + +} diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/ListValue.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/ListValue.java index d6aabf205..5d52eda02 100644 --- a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/ListValue.java +++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/ListValue.java @@ -18,6 +18,10 @@ */ package io.sf.carte.echosvg.css.engine.value; +import java.util.Iterator; + +import org.w3c.dom.DOMException; + /** * This class represents a list of values. * @@ -25,6 +29,7 @@ * @version $Id$ */ public class ListValue extends AbstractValueList { + /** * Creates a ListValue. */ @@ -34,15 +39,20 @@ public ListValue() { /** * Creates a ListValue with the given separator. + * + * @param s the separator. */ public ListValue(char s) { super(s); } /** - * Creates a ListValue with the given separator. + * Creates a ListValue with the given separator and initial capacity. + * + * @param s the separator. + * @param initialCapacity the initial capacity. */ - ListValue(char s, int initialCapacity) { + public ListValue(char s, int initialCapacity) { super(s, initialCapacity); } @@ -53,4 +63,96 @@ public void append(Value v) { add(v); } + /** + * Create an unmodifiable view of this list value. + * + * @return the unmodifiable view. + */ + public ListValue createUnmodifiableView() { + return new UnmodifiableListValue(); + } + + private class UnmodifiableListValue extends ListValue { + UnmodifiableListValue() { + super(ListValue.this.getSeparatorChar(), 1); + } + + @Override + public char getSeparatorChar() { + return ListValue.this.getSeparatorChar(); + } + + @Override + public String getCssText() { + return ListValue.this.getCssText(); + } + + @Override + public Value item(int index) { + return ListValue.this.item(index); + } + + @Override + public int getLength() { + return ListValue.this.getLength(); + } + + @Override + public Iterator iterator() { + return new Iterator() { + Iterator iter = ListValue.this.items.iterator(); + + @Override + public boolean hasNext() { + return iter.hasNext(); + } + + @Override + public Value next() { + return iter.next(); + } + + }; + } + + @Override + public boolean isEmpty() { + return ListValue.this.isEmpty(); + } + + @Override + public AbstractValueList clone() { + return ListValue.this.clone(); + } + + @Override + public boolean add(Value value) { + throw createNoModificationDOMException(); + } + + @Override + public void clear() { + throw createNoModificationDOMException(); + } + + @Override + public Value remove(int index) { + throw createNoModificationDOMException(); + } + + @Override + public Value set(int index, Value value) { + throw createNoModificationDOMException(); + } + + /** + * Creates a NO_MODIFICATION_ALLOWED_ERR exception. + */ + private DOMException createNoModificationDOMException() { + return new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, + "Cannot modify this list."); + } + + } + } diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/NumericValue.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/NumericValue.java index 24568e3b5..c2b44c6d6 100644 --- a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/NumericValue.java +++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/NumericValue.java @@ -19,6 +19,7 @@ package io.sf.carte.echosvg.css.engine.value; import org.w3c.css.om.typed.CSSNumericValue; +import org.w3c.css.om.unit.CSSUnit; /** * Base class for numeric values. @@ -26,7 +27,7 @@ * @author See Git history. * @version $Id$ */ -public abstract class NumericValue extends AbstractValue implements CSSNumericValue { +public abstract class NumericValue extends AbstractValue implements TypedValue, CSSNumericValue { /** * Creates a new value. @@ -36,6 +37,77 @@ public NumericValue() { } @Override - public abstract NumericValue clone(); + public NumericValue clone() { + return (NumericValue) super.clone(); + } + + abstract short getCSSUnit(); + + @Override + public CSSNumericType type() { + return new NumericType(); + } + + class NumericType implements CSSNumericType { + + @Override + public int getLength() { + return CSSUnit.isLengthUnitType(getCSSUnit()) ? 1 : 0; + } + + @Override + public int getAngle() { + return CSSUnit.isAngleUnitType(getCSSUnit()) ? 1 : 0; + } + + @Override + public int getTime() { + return CSSUnit.isTimeUnitType(getCSSUnit()) ? 1 : 0; + } + + @Override + public int getFrequency() { + short unit = getCSSUnit(); + return unit == CSSUnit.CSS_HZ || unit == CSSUnit.CSS_KHZ ? 1 : 0; + } + + @Override + public int getResolution() { + return CSSUnit.isResolutionUnitType(getCSSUnit()) ? 1 : 0; + } + + @Override + public int getFlex() { + return getCSSUnit() == CSSUnit.CSS_FR ? 1 : 0; + } + + @Override + public int getPercent() { + return getCSSUnit() == CSSUnit.CSS_PERCENTAGE ? 1 : 0; + } + + @Override + public CSSNumericBaseType getPercentHint() { + short unitType = getCSSUnit(); + 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; + } + + } } diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/PendingValue.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/PendingValue.java new file mode 100644 index 000000000..2bbbb8378 --- /dev/null +++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/PendingValue.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.engine.value; + +import io.sf.carte.doc.style.css.nsac.LexicalUnit; + +/** + * A value meaning that a longhand property is pending the PROXY substitution of + * a shorthand value. + * + * @version $Id$ + */ +public class PendingValue extends LexicalValue { + + private String shorthandName; + + /** + * Creates a new PendingValue object. + * + * @param shorthandName the shorthand name. + * @param the lexical unit that is pending substitution. + */ + public PendingValue(String shorthandName, LexicalUnit lunit) throws IllegalArgumentException { + super(lunit); + this.shorthandName = shorthandName; + } + + @Override + public Type getPrimitiveType() { + return Type.INTERNAL; + } + + public String getShorthandName() { + return shorthandName; + } + + @Override + public String getCssText() { + return ""; + } + + @Override + public PendingValue clone() { + PendingValue clon = (PendingValue) super.clone(); + clon.shorthandName = shorthandName; + return clon; + } + +} diff --git a/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/PropertyDefinition.java b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/PropertyDefinition.java new file mode 100644 index 000000000..b441ebbda --- /dev/null +++ b/echosvg-css/src/main/java/io/sf/carte/echosvg/css/engine/value/PropertyDefinition.java @@ -0,0 +1,57 @@ +/* + * This software adapts interfaces defined by CSS Properties and Values API Level 1 + * (https://www.w3.org/TR/css-properties-values-api-1/). + * Copyright © 2020 W3C® (MIT, ERCIM, Keio, Beihang). + * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document + */ +/* + * SPDX-License-Identifier: W3C-20150513 + */ + +package io.sf.carte.echosvg.css.engine.value; + +import io.sf.carte.doc.style.css.CSSValueSyntax; +import io.sf.carte.doc.style.css.nsac.LexicalUnit; + +/** + * A property definition. + *

+ * See CSS + * Properties and Values API Level 1. + *

+ */ +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. + *

+ * + * @throws TranscoderException + * @throws IOException + */ + @Test + @Timeout(value = 3000, unit = TimeUnit.MILLISECONDS) + public void testVarBLAFallback() throws TranscoderException, IOException { + assertThrows(CSSResourceLimitException.class, () -> testSecurity("varBLAFallback.svg", 0)); + } + + /** + * Check the behaviour on var() 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 testVarCircularity() throws TranscoderException, IOException { + assertThrows(CSSCircularityException.class, () -> testSecurity("varCircularity.svg", 0)); + } + + /** + * Check the behaviour on var() fallback 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 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. * @@ -1318,9 +1386,32 @@ public float getPixelUnitToMillimeter() { return (Float) obj; } + obj = SVGAbstractTranscoder.this.hints.get(KEY_RESOLUTION_DPI); + if (obj != null) { + return 25.4f / ((Float) obj).floatValue(); + } + return super.getPixelUnitToMillimeter(); } + /** + * Returns the resolution in dpi. + */ + @Override + public float getResolution() { + Object obj = SVGAbstractTranscoder.this.hints.get(KEY_RESOLUTION_DPI); + if (obj != null) { + return (Float) obj; + } + + obj = SVGAbstractTranscoder.this.hints.get(KEY_PIXEL_UNIT_TO_MILLIMETER); + if (obj != null) { + return 25.4f / ((Float) obj).floatValue(); + } + + return 96f; + } + /** * Returns the user language specified in the TranscodingHints or * "en" (english) if any. @@ -1346,6 +1437,15 @@ public String getMedia() { return super.getMedia(); } + @Override + public String getPrefersColorScheme() { + String s = (String) hints.get(KEY_PREFERS_COLOR_SCHEME); + if (s != null) + return s; + + return super.getPrefersColorScheme(); + } + /** * Returns the default font family. */ diff --git a/echosvg-transcoder/src/main/java/io/sf/carte/echosvg/transcoder/image/JPEGTranscoder.java b/echosvg-transcoder/src/main/java/io/sf/carte/echosvg/transcoder/image/JPEGTranscoder.java index 84473209d..47197f596 100644 --- a/echosvg-transcoder/src/main/java/io/sf/carte/echosvg/transcoder/image/JPEGTranscoder.java +++ b/echosvg-transcoder/src/main/java/io/sf/carte/echosvg/transcoder/image/JPEGTranscoder.java @@ -87,9 +87,9 @@ public void writeImage(BufferedImage img, TranscoderOutput output) throws Transc ImageWriter writer = ImageWriterRegistry.getInstance().getWriterFor("image/jpeg"); ImageWriterParams params = new ImageWriterParams(); params.setJPEGQuality(quality, true); - float PixSzMM = getUserAgent().getPixelUnitToMillimeter(); - int PixSzInch = (int) (25.4 / PixSzMM + 0.5); - params.setResolution(PixSzInch); + float resol = getUserAgent().getResolution(); + int iResol = Math.round(resol); + params.setResolution(iResol); writer.writeImage(img, ostream, params); ostream.flush(); } catch (IOException ex) { diff --git a/echosvg-transcoder/src/main/java/io/sf/carte/echosvg/transcoder/image/PNGTranscoderImageIOWriteAdapter.java b/echosvg-transcoder/src/main/java/io/sf/carte/echosvg/transcoder/image/PNGTranscoderImageIOWriteAdapter.java index 9e02fd373..5c9a77bff 100644 --- a/echosvg-transcoder/src/main/java/io/sf/carte/echosvg/transcoder/image/PNGTranscoderImageIOWriteAdapter.java +++ b/echosvg-transcoder/src/main/java/io/sf/carte/echosvg/transcoder/image/PNGTranscoderImageIOWriteAdapter.java @@ -86,9 +86,8 @@ public void writeImage(PNGTranscoder transcoder, BufferedImage img, TranscoderOu params.setCompressedText(text); } - float PixSzMM = transcoder.getUserAgent().getPixelUnitToMillimeter(); - int PixSzInch = (int) (25.4 / PixSzMM + 0.5); - params.setResolution(PixSzInch); + float resol = transcoder.getUserAgent().getResolution(); + params.setResolution(Math.round(resol)); try { OutputStream ostream = output.getOutputStream(); diff --git a/echosvg-transcoder/src/main/java/io/sf/carte/echosvg/transcoder/image/PNGTranscoderInternalCodecWriteAdapter.java b/echosvg-transcoder/src/main/java/io/sf/carte/echosvg/transcoder/image/PNGTranscoderInternalCodecWriteAdapter.java index bf43089b7..3237b8900 100644 --- a/echosvg-transcoder/src/main/java/io/sf/carte/echosvg/transcoder/image/PNGTranscoderInternalCodecWriteAdapter.java +++ b/echosvg-transcoder/src/main/java/io/sf/carte/echosvg/transcoder/image/PNGTranscoderInternalCodecWriteAdapter.java @@ -103,10 +103,10 @@ public void writeImage(PNGTranscoder transcoder, BufferedImage img, TranscoderOu params.setCompressedText(text); } - float PixSzMM = transcoder.getUserAgent().getPixelUnitToMillimeter(); - // num Pixs in 1 Meter - int numPix = (int) ((1000 / PixSzMM) + 0.5); - params.setPhysicalDimension(numPix, numPix, 1); // 1 means 'pix/meter' + float resol = transcoder.getUserAgent().getResolution(); + // number of pixels in 1 Meter + int numPix = Math.round(resol / 0.0254f); + params.setPhysicalDimension(numPix, numPix, 1); // 1 means 'pixels/meter' try { OutputStream ostream = output.getOutputStream(); diff --git a/echosvg-transcoder/src/main/java/io/sf/carte/echosvg/transcoder/image/TIFFTranscoderImageIOWriteAdapter.java b/echosvg-transcoder/src/main/java/io/sf/carte/echosvg/transcoder/image/TIFFTranscoderImageIOWriteAdapter.java index 77f480d01..a57437a0f 100644 --- a/echosvg-transcoder/src/main/java/io/sf/carte/echosvg/transcoder/image/TIFFTranscoderImageIOWriteAdapter.java +++ b/echosvg-transcoder/src/main/java/io/sf/carte/echosvg/transcoder/image/TIFFTranscoderImageIOWriteAdapter.java @@ -60,9 +60,8 @@ public void writeImage(TIFFTranscoder transcoder, BufferedImage img, TranscoderO ImageWriter writer = ImageWriterRegistry.getInstance().getWriterFor("image/tiff"); ImageWriterParams params = new ImageWriterParams(); - float PixSzMM = transcoder.getUserAgent().getPixelUnitToMillimeter(); - int PixSzInch = (int) (25.4 / PixSzMM + 0.5); - params.setResolution(PixSzInch); + float resol = transcoder.getUserAgent().getResolution(); + params.setResolution(Math.round(resol)); if (hints.containsKey(TIFFTranscoder.KEY_COMPRESSION_METHOD)) { String method = (String) hints.get(TIFFTranscoder.KEY_COMPRESSION_METHOD); diff --git a/echosvg-transcoder/src/main/java/io/sf/carte/echosvg/transcoder/impl/SizingHelper.java b/echosvg-transcoder/src/main/java/io/sf/carte/echosvg/transcoder/impl/SizingHelper.java index edceac0f9..62c5e8567 100644 --- a/echosvg-transcoder/src/main/java/io/sf/carte/echosvg/transcoder/impl/SizingHelper.java +++ b/echosvg-transcoder/src/main/java/io/sf/carte/echosvg/transcoder/impl/SizingHelper.java @@ -18,15 +18,15 @@ */ package io.sf.carte.echosvg.transcoder.impl; +import org.w3c.css.om.unit.CSSUnit; import org.w3c.dom.DOMException; import org.w3c.dom.Element; -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.transcoder.TranscoderException; @@ -139,17 +139,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; } @@ -170,10 +170,10 @@ static float floatValue(String number) throws TranscoderException, DOMException throw new TranscoderException("Leave value unchanged."); } - TypedValue typed; + CSSTypedValue typed; switch (value.getPrimitiveType()) { case NUMERIC: - typed = (TypedValue) value; + typed = (CSSTypedValue) value; if (typed.getUnitType() != CSSUnit.CSS_NUMBER) { if (CSSUnit.isRelativeLengthUnitType(typed.getUnitType())) { throw new TranscoderException("Leave value unchanged."); @@ -183,8 +183,8 @@ static float floatValue(String number) throws TranscoderException, DOMException } break; case EXPRESSION: - Evaluator eval = new Evaluator(); - typed = eval.evaluateExpression((ExpressionValue) value); + Evaluator eval = new Evaluator(CSSUnit.CSS_NUMBER); + typed = eval.evaluateExpression((CSSExpressionValue) value); if (typed.getUnitType() != CSSUnit.CSS_NUMBER) { if (CSSUnit.isRelativeLengthUnitType(typed.getUnitType())) { throw new TranscoderException("Leave value unchanged."); diff --git a/echosvg-transcoder/src/main/java/io/sf/carte/echosvg/transcoder/print/PrintTranscoder.java b/echosvg-transcoder/src/main/java/io/sf/carte/echosvg/transcoder/print/PrintTranscoder.java index 334015050..ed5604b01 100644 --- a/echosvg-transcoder/src/main/java/io/sf/carte/echosvg/transcoder/print/PrintTranscoder.java +++ b/echosvg-transcoder/src/main/java/io/sf/carte/echosvg/transcoder/print/PrintTranscoder.java @@ -676,6 +676,7 @@ private void drawError(Graphics g, Exception e) { public static final String USAGE = "java io.sf.carte.echosvg.transcoder.print.PrintTranscoder "; + @SuppressWarnings("deprecation") public static void main(String[] args) throws Exception { if (args.length < 1) { System.err.println(USAGE); diff --git a/echosvg-transcoder/src/main/java/io/sf/carte/echosvg/transcoder/util/CSSTranscodingHelper.java b/echosvg-transcoder/src/main/java/io/sf/carte/echosvg/transcoder/util/CSSTranscodingHelper.java index 7531b9c77..ad7c75645 100644 --- a/echosvg-transcoder/src/main/java/io/sf/carte/echosvg/transcoder/util/CSSTranscodingHelper.java +++ b/echosvg-transcoder/src/main/java/io/sf/carte/echosvg/transcoder/util/CSSTranscodingHelper.java @@ -36,6 +36,7 @@ import java.util.Locale; import java.util.Set; +import org.w3c.css.om.unit.CSSUnit; import org.w3c.dom.Attr; import org.w3c.dom.Document; import org.w3c.dom.DocumentType; @@ -59,7 +60,6 @@ import io.sf.carte.doc.style.css.CSSMediaException; import io.sf.carte.doc.style.css.CSSStyleSheetFactory; 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.CssType; import io.sf.carte.doc.style.css.StyleDatabase; @@ -69,6 +69,7 @@ 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.LexicalUnit; import io.sf.carte.doc.style.css.nsac.Selector; import io.sf.carte.doc.style.css.nsac.SelectorList; import io.sf.carte.doc.style.css.om.AbstractCSSCanvas; @@ -1101,7 +1102,9 @@ public CSSTypedValue getInitialColor() { } @Override - public boolean supports(String property, CSSValue value) { + public boolean supports(String property, LexicalUnit lunit) { + ValueFactory valueFactory = new ValueFactory(); + CSSValue value = valueFactory.createCSSValue(lunit); if ("color".equalsIgnoreCase(property) || "background-color".equalsIgnoreCase(property)) { return supportsColor(value); @@ -1183,8 +1186,16 @@ private boolean supports(Condition condition) { private class MyCanvas extends AbstractCSSCanvas { + private CSSDocument document; + protected MyCanvas(CSSDocument doc) { - super(doc); + super(); + document = doc; + } + + @Override + public CSSDocument getDocument() { + return document; } @Override diff --git a/gradle.properties b/gradle.properties index e26045328..6b7b86c05 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,7 +1,7 @@ # Dependency versions checkstyleVersion=10.18.0 grGitVersion=5.2.2 -css4jVersion=4.4 +css4jVersion=5.0 css4jAwtVersion=4.0 xmlDtdVersion=4.3 rhinoVersion=1.7.15 diff --git a/samples/tests/spec/painting/visibilityUnset.svg b/samples/tests/spec/painting/visibilityUnset.svg new file mode 100644 index 000000000..3dc97f443 --- /dev/null +++ b/samples/tests/spec/painting/visibilityUnset.svg @@ -0,0 +1,139 @@ + + + + + + + + + + + + + + + + + Test 'visibility' property with 'unset' and 'initial' values + + + + + + Test 'visibility' property with 'unset' and 'initial' values + + + + + + + + + unset | unset | unset + <g> unset + + + + + + unset | unset | unset + <g> hidden + + + + + + + + + + + + + + + + + + + + + + unset | hidden | initial + <g> unset + + + + + + unset | hidden | initial + <g> initial + + + + + + + + + + + + + + + + + + + + + unset | hidden | initial + <g> collapse + + + + + + unset | hidden | initial + <g> hidden + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/tests/spec/text/verticalText.svg b/samples/tests/spec/text/verticalText.svg index b01f04cd1..4b38423b7 100644 --- a/samples/tests/spec/text/verticalText.svg +++ b/samples/tests/spec/text/verticalText.svg @@ -77,13 +77,13 @@ Writing top to bottom画像 Glyph Orientation:auto画像 - Glyph Orientation:0画像 - Glyph Orientation:90画像 - Glyph Orientation:180画像 - Glyph Orientation:270画像 Embedded <tspan> element Embedded orientated element diff --git a/samples/tests/spec2/styling/attrValues.svg b/samples/tests/spec2/styling/attrValues.svg new file mode 100644 index 000000000..2d7e30acd --- /dev/null +++ b/samples/tests/spec2/styling/attrValues.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + Media Queries + Conditional rules + Color Level 4 / calc() + Custom Properties + + + diff --git a/samples/tests/spec2/styling/conditionalRules.svg b/samples/tests/spec2/styling/conditionalRules.svg new file mode 100644 index 000000000..60a5b61be --- /dev/null +++ b/samples/tests/spec2/styling/conditionalRules.svg @@ -0,0 +1,181 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Media Queries + Conditional rules + Color Level 4 / calc() + Custom Properties (*) + * and registered custom properties + + + diff --git a/samples/unsupportedRules.svg b/samples/unsupportedRules.svg index ba9f43290..bc2171f95 100644 --- a/samples/unsupportedRules.svg +++ b/samples/unsupportedRules.svg @@ -19,16 +19,17 @@ --> - + qmot~3f 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 diff --git a/test-references/samples/tests/spec2/styling/attrValues.png b/test-references/samples/tests/spec2/styling/attrValues.png new file mode 100644 index 0000000000000000000000000000000000000000..0c55aa154bcb71a951205102d7dd81e09dc19df4 GIT binary patch literal 47202 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 literal 0 HcmV?d00001 diff --git a/test-references/samples/tests/spec2/styling/conditionalRules-dark.png b/test-references/samples/tests/spec2/styling/conditionalRules-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..1748f39fb4d4f4b53dd1064e4d945cb01b847883 GIT binary patch literal 50074 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

(Y>=VPJL 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 literal 0 HcmV?d00001 diff --git a/test-references/samples/tests/spec2/styling/conditionalRules-print.png b/test-references/samples/tests/spec2/styling/conditionalRules-print.png new file mode 100644 index 0000000000000000000000000000000000000000..d133bf1ad30426fcfa48859f8964278ba7c91a29 GIT binary patch literal 59745 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 d|7jMIB?cDuM-ZE{!1cTS + + + + + + + + +pt + + +pc + + +in + + +mm + + +cm + + +em + + +px + + diff --git a/test-resources/io/sf/carte/echosvg/transcoder/security/attrCircularity.svg b/test-resources/io/sf/carte/echosvg/transcoder/security/attrCircularity.svg new file mode 100644 index 000000000..9364ac1dd --- /dev/null +++ b/test-resources/io/sf/carte/echosvg/transcoder/security/attrCircularity.svg @@ -0,0 +1,73 @@ + + + + + + + + + + + + +attr() fallback circularity + + + + + + + + + + + +attr() fallback circularity + + diff --git a/test-resources/io/sf/carte/echosvg/transcoder/security/varBLAFallback.svg b/test-resources/io/sf/carte/echosvg/transcoder/security/varBLAFallback.svg new file mode 100644 index 000000000..c855deb70 --- /dev/null +++ b/test-resources/io/sf/carte/echosvg/transcoder/security/varBLAFallback.svg @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + +Billion Laughs DoS attack against var() fallback + + + + + + + + + + + +Billion laughs attack against var() fallback + + diff --git a/test-resources/io/sf/carte/echosvg/transcoder/security/varBillionLaughsAttack.svg b/test-resources/io/sf/carte/echosvg/transcoder/security/varBillionLaughsAttack.svg new file mode 100644 index 000000000..4af8bb045 --- /dev/null +++ b/test-resources/io/sf/carte/echosvg/transcoder/security/varBillionLaughsAttack.svg @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + +Billion Laughs DoS attack + + + + + + + + + + + +Billion laughs attack against var() + + diff --git a/test-resources/io/sf/carte/echosvg/transcoder/security/varCircularity.svg b/test-resources/io/sf/carte/echosvg/transcoder/security/varCircularity.svg new file mode 100644 index 000000000..d91a14539 --- /dev/null +++ b/test-resources/io/sf/carte/echosvg/transcoder/security/varCircularity.svg @@ -0,0 +1,73 @@ + + + + + + + + + + + + +var() circularity + + + + + + + + + + + +var() circularity + + diff --git a/test-resources/io/sf/carte/echosvg/transcoder/security/varFallbackCircularity.svg b/test-resources/io/sf/carte/echosvg/transcoder/security/varFallbackCircularity.svg new file mode 100644 index 000000000..bd6280821 --- /dev/null +++ b/test-resources/io/sf/carte/echosvg/transcoder/security/varFallbackCircularity.svg @@ -0,0 +1,73 @@ + + + + + + + + + + + + +var() circularity + + + + + + + + + + + +var() fallback circularity + +