From dcbab7af809664a13417c504205b279e6bd48520 Mon Sep 17 00:00:00 2001 From: Carlos Amengual Date: Mon, 7 Oct 2024 22:19: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 + .../test/svg/MermaidRenderingTest.java | 8 +- .../test/svg/ResolutionPxMmRenderingTest.java | 3 +- .../test/svg/SVGRenderingAccuracyTest.java | 33 +- .../test/svg/SamplesSpec2RenderingTest.java | 125 ++ .../test/svg/SamplesSpecRenderingTest.java | 1 + .../test/svg/StyleBypassRenderingTest.java | 10 +- .../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 +- samples/tests/spec/text/verticalText.svg | 8 +- .../tests/spec2/security/attrCircularity.svg | 73 ++ .../tests/spec2/security/varBLAFallback.svg | 94 ++ .../spec2/security/varBillionLaughsAttack.svg | 94 ++ .../tests/spec2/security/varCircularity.svg | 73 ++ .../spec2/security/varFallbackCircularity.svg | 73 ++ samples/tests/spec2/styling/attrValues.svg | 76 ++ .../tests/spec2/styling/conditionalRules.svg | 153 +++ 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 .../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 -> 45616 bytes .../spec2/styling/conditionalRules-print.png | Bin 0 -> 56530 bytes .../tests/spec2/styling/conditionalRules.png | Bin 0 -> 55736 bytes .../spec2/styling/conditionalRules_Gray.png | Bin 0 -> 61605 bytes .../transcoder/image/resources/resolution.svg | 50 + 155 files changed, 5042 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 rename echosvg-test/src/test/java/io/sf/carte/echosvg/transcoder/image/test/{PixelToMMTest.java => ResolutionTest.java} (66%) create mode 100644 samples/tests/spec2/security/attrCircularity.svg create mode 100644 samples/tests/spec2/security/varBLAFallback.svg create mode 100644 samples/tests/spec2/security/varBillionLaughsAttack.svg create mode 100644 samples/tests/spec2/security/varCircularity.svg create mode 100644 samples/tests/spec2/security/varFallbackCircularity.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/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 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/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..56faa3772 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 @@ -18,11 +18,17 @@ */ 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; @@ -45,6 +51,100 @@ public static void setUpBeforeClass() throws Exception { TestFonts.loadTestFonts(); } + /* + * Security + */ + + /** + * 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, + () -> testNVErrIgnore("samples/tests/spec2/security/attrCircularity.svg", BROWSER_MEDIA, 0)); + } + + /** + * 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, + () -> testNVErrIgnore("samples/tests/spec2/security/varBillionLaughsAttack.svg", + BROWSER_MEDIA, 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, + () -> testNVErrIgnore("samples/tests/spec2/security/varBLAFallback.svg", + BROWSER_MEDIA, 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, + () -> testNVErrIgnore("samples/tests/spec2/security/varCircularity.svg", BROWSER_MEDIA, 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, () -> testNVErrIgnore( + "samples/tests/spec2/security/varFallbackCircularity.svg", BROWSER_MEDIA, 0)); + } + /* * Namespaceless href */ @@ -56,6 +156,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..2b8ff0ca9 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 @@ -523,6 +523,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/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/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/security/attrCircularity.svg b/samples/tests/spec2/security/attrCircularity.svg new file mode 100644 index 000000000..9364ac1dd --- /dev/null +++ b/samples/tests/spec2/security/attrCircularity.svg @@ -0,0 +1,73 @@ + + + + + + + + + + + + +attr() fallback circularity + + + + + + + + + + + +attr() fallback circularity + + diff --git a/samples/tests/spec2/security/varBLAFallback.svg b/samples/tests/spec2/security/varBLAFallback.svg new file mode 100644 index 000000000..c855deb70 --- /dev/null +++ b/samples/tests/spec2/security/varBLAFallback.svg @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + +Billion Laughs DoS attack against var() fallback + + + + + + + + + + + +Billion laughs attack against var() fallback + + diff --git a/samples/tests/spec2/security/varBillionLaughsAttack.svg b/samples/tests/spec2/security/varBillionLaughsAttack.svg new file mode 100644 index 000000000..4af8bb045 --- /dev/null +++ b/samples/tests/spec2/security/varBillionLaughsAttack.svg @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + +Billion Laughs DoS attack + + + + + + + + + + + +Billion laughs attack against var() + + diff --git a/samples/tests/spec2/security/varCircularity.svg b/samples/tests/spec2/security/varCircularity.svg new file mode 100644 index 000000000..d91a14539 --- /dev/null +++ b/samples/tests/spec2/security/varCircularity.svg @@ -0,0 +1,73 @@ + + + + + + + + + + + + +var() circularity + + + + + + + + + + + +var() circularity + + diff --git a/samples/tests/spec2/security/varFallbackCircularity.svg b/samples/tests/spec2/security/varFallbackCircularity.svg new file mode 100644 index 000000000..bd6280821 --- /dev/null +++ b/samples/tests/spec2/security/varFallbackCircularity.svg @@ -0,0 +1,73 @@ + + + + + + + + + + + + +var() circularity + + + + + + + + + + + +var() fallback circularity + + 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..06b63d46e --- /dev/null +++ b/samples/tests/spec2/styling/conditionalRules.svg @@ -0,0 +1,153 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Media Queries + Conditional rules + Color Level 4 / calc() + 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..bdb04459134a3fed84a463fdc0f0feeb73beb4a6 GIT binary patch literal 45616 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

(Y>=VPJL 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 UdBgPi&FiBir!HG3Z4v%I00Jx6yZ`_I 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..f675fccb883acd668b0aa2c6d79348494a110511 GIT binary patch literal 56530 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 literal 0 HcmV?d00001 diff --git a/test-references/samples/tests/spec2/styling/conditionalRules.png b/test-references/samples/tests/spec2/styling/conditionalRules.png new file mode 100644 index 0000000000000000000000000000000000000000..944efdad305a235ad3174cadd6332113320f3702 GIT binary patch literal 55736 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 N=BJ`Wy_j+6{{VNkZ=e7G literal 0 HcmV?d00001 diff --git a/test-resources/io/sf/carte/echosvg/transcoder/image/resources/resolution.svg b/test-resources/io/sf/carte/echosvg/transcoder/image/resources/resolution.svg new file mode 100644 index 000000000..60cdf4c68 --- /dev/null +++ b/test-resources/io/sf/carte/echosvg/transcoder/image/resources/resolution.svg @@ -0,0 +1,50 @@ + + + + + + + + + +pt + + +pc + + +in + + +mm + + +cm + + +em + + +px + +