Example #1
0
 /// <summary>
 /// Clones an already existing <see cref="CssValue"/>
 /// </summary>
 internal CssValue(CssValue sv)
 {
     type  = sv.Type;
     value = sv.value;
     unit  = sv.Unit;
     flags = sv.Flags;
 }
Example #2
0
        internal CssValue(ECssValueTypes type, object value, ECssUnit unit) : this(type)
        {
            this.unit  = unit;
            this.value = value;

            if (type == ECssValueTypes.KEYWORD)// Try and catch some common IMPORTANT keywords
            {
                /* If our keyword can be resolved to another ECssValueType then its an global keyword */
                if (!Lookup.TryEnum(value as string, out ECssValueTypes outType))
                {
                    type = outType;
                }
            }
            else if (type == ECssValueTypes.DIMENSION || type == ECssValueTypes.RESOLUTION)
            {
                /* Make sure to correct the value and distinguish whether we are a Dimension or a Resolution */
                switch (unit)
                {
                case ECssUnit.DPI:
                case ECssUnit.DPCM:
                case ECssUnit.DPPX:
                    type = ECssValueTypes.RESOLUTION;
                    break;

                default:
                    type = ECssValueTypes.DIMENSION;
                    break;
                }
            }
        }
Example #3
0
        /// <summary>
        /// Resolves a <paramref name="value"/> from <paramref name="unitFrom"/> to <paramref name="unitTo"/>
        /// </summary>
        /// <param name="unitFrom">The unit the value is specified in</param>
        /// <param name="unitTo">The unit to convert to</param>
        /// <param name="value">Value to convert</param>
        public double Resolve(double value, ECssUnit unitFrom, ECssUnit unitTo)
        {
            /* First we convert the unit value to the canonical unit (pixels for physical values) */
            double canonical = value * SCALING_TABLE[(int)unitFrom];

            /* Next we divide the canonical value to get the value in (unitTo) units */
            return(canonical / SCALING_TABLE[(int)unitTo]);
        }
Example #4
0
 /// <summary>
 /// Notifys all dimension-properties which use the specified unit that its scale has changed and they need to update
 /// </summary>
 /// <param name="Unit"></param>
 public void Notify_Unit_Scale_Change(ECssUnit Unit)
 {
     if (Unit == ECssUnit.None)
     {
         return;
     }
     foreach (ICssProperty Property in Cascaded.Get_Set_Properties())
     {
         Property.Handle_Unit_Change(Unit);
     }
 }
Example #5
0
 /// <summary>
 /// Resolves a <paramref name="Value"/> from <paramref name="Unit"/> to its canonical form.
 /// </summary>
 /// <param name="Unit">Unit the value is specified in</param>
 /// <param name="Value">Value to convert</param>
 public double Resolve(double Value, ECssUnit Unit)
 {
     /* First we convert the unit value to the canonical unit (pixels for physical values) */
     return(Value * SCALING_TABLE[(int)Unit]);
 }
Example #6
0
        /// <summary>
        /// Retreives the base scaling factor for the given unit relative to its canonical unit
        /// </summary>
        /// <param name="document"></param>
        /// <param name="Unit"></param>
        /// <returns></returns>
        private static double Get_Scale(Document document, ECssUnit Unit, bool anchor_to_dpi = false)
        {
            switch (Unit)
            {
            /* Physical Units */
            /* Docs: https://www.w3.org/TR/css3-values/#physical-units */
            case ECssUnit.PX:
            {
                return(1.0);
            }

            case ECssUnit.CM:
            {
                if (anchor_to_dpi)
                {
                    return(document.defaultView.screen.dpi / 2.54);
                }

                return(CM_TO_PX);
            }

            case ECssUnit.MM:
            {
                if (anchor_to_dpi)
                {
                    return((document.defaultView.screen.dpi / 2.54) / 10.0);
                }

                return(MM_TO_PX);
            }

            case ECssUnit.Q:
            {
                if (anchor_to_dpi)
                {
                    return((document.defaultView.screen.dpi / 2.54) / 40.0);
                }

                return(Q_TO_PX);
            }

            case ECssUnit.IN:
            {
                if (anchor_to_dpi)
                {
                    return(1.0 / document.defaultView.screen.dpi);
                }

                return(INCH_TO_PX);
            }

            case ECssUnit.PC:
            {
                if (anchor_to_dpi)
                {
                    return((1.0 / document.defaultView.screen.dpi) / 6.0);
                }

                return(PC_TO_PX);
            }

            case ECssUnit.PT:
            {
                if (anchor_to_dpi)
                {
                    return((1.0 / document.defaultView.screen.dpi) / 72.0);
                }

                return(PT_TO_PX);
            }

            /* <Resolution> Units */
            /* Docs: https://www.w3.org/TR/css3-values/#resolution-value */
            case ECssUnit.DPI:
            {
                if (anchor_to_dpi)
                {
                    return(1.0 / document.defaultView.screen.dpi);
                }

                return(1 / 96);
            }

            case ECssUnit.DPCM:
            {
                if (anchor_to_dpi)
                {
                    return(document.defaultView.screen.dpi / 2.54);
                }

                return(PT_TO_PX);
            }

            case ECssUnit.DPPX:
            {
                return(1);
            }

            /* <Time> Units */
            /* Docs: https://www.w3.org/TR/css3-values/#time */
            case ECssUnit.S:
            {
                return(1.0);
            }

            case ECssUnit.MS:
            {
                return(1 / 1000);
            }

            /* <Frequency> Units */
            /* Docs: https://www.w3.org/TR/css3-values/#frequency */
            case ECssUnit.HZ:
            {
                return(1.0);
            }

            case ECssUnit.KHZ:
            {
                return(1 / 1000);
            }


            /* Angle Units */
            /* Docs: https://www.w3.org/TR/css3-values/#angles */
            /* Canonical unit: degrees */

            case ECssUnit.DEG:    // Translate degrees to radians
            {
                return(1.0);
            }

            case ECssUnit.GRAD:
            {
                return(400 / 360);
            }

            case ECssUnit.RAD:
            {
                return(180.0 / Math.PI);
            }

            case ECssUnit.TURN:
            {
                return(360.0);
            }

            /* Font Units */
            /* Docs: https://www.w3.org/TR/css-values-3/#font-relative-lengths */
            case ECssUnit.REM:
            {
                return(document.body.Style.FontSize);
            }

            case ECssUnit.VMAX:
            {
                return(Math.Max(document.defaultView.visualViewport.Width, document.defaultView.visualViewport.Height));
            }

            case ECssUnit.VMIN:
            {
                return(Math.Min(document.defaultView.visualViewport.Width, document.defaultView.visualViewport.Height));
            }

            case ECssUnit.VW:
            {
                return(document.defaultView.visualViewport.Width);
            }

            case ECssUnit.VH:
            {
                return(document.defaultView.visualViewport.Height);
            }

            default:
            {
                throw new NotImplementedException($"CSS Unit type '{Enum.GetName(typeof(ECssUnit), Unit)}' has not been implemented!");
            }
            }
        }
Example #7
0
        public static double Get_Font_Unit_Scale(Element Owner, ICssProperty Property, ECssUnit Unit)
        {
            switch (Unit)
            {
            case ECssUnit.CH:
                throw new NotImplementedException($"CSS Unit type '{Enum.GetName(typeof(ECssUnit), Unit)}' has not been implemented!");

            case ECssUnit.EM:
            {
                /*
                 * CSS Specs:
                 * When used in the value of the font-size property on the element they refer to,
                 * these units refer to the computed font metrics of the parent element
                 * (or the computed font metrics corresponding to the initial values of the font property, if the element has no parent).
                 * When used outside the context of an element (such as in media queries),
                 * these units refer to the computed font metrics corresponding to the initial values of the font property.
                 */

                if (Property.CssName == "font-size" && ReferenceEquals(Property.Owner, Owner))
                {        // We are being called from the font-size property
                    if (Property.Owner.parentElement is object)
                    {    // Basically just try and inherit our parents unit scale
                        return(Get_Font_Unit_Scale(Owner.parentElement, Property, Unit));
                    }
                    else        // No parent
                    {
                        /*
                         * CSS Specs:
                         * When used in the value of the font-size property on the element they refer to,
                         * these units refer to the computed font metrics of the parent element
                         * (or the computed font metrics corresponding to the initial values of the font property, if the element has no parent)
                         */

                        // I can only assume this means we default to the property declerations default/initial value
                        var def = CssDefinitions.StyleDefinitions[Property.CssName];
                        if (def != null)
                        {
                            return(def.Initial.Resolve() ?? throw new CssException($"Failed to resolve the default value specified in the '{Property.CssName}' property decleration to a number!"));
                        }
                    }
                }
#if DISABLE_FONT_SYSTEM
                return(1);
#else
                if (Owner.Style.Font != null)
                {
                    return(Owner.Style.Font.EmSize);
                }
                else
                {
                    return(Owner.Style.FontSize);
                }
#endif
            }

            case ECssUnit.EX:
            {
                /*
                 * CSS Specs:
                 * The 'ex' unit is defined by the element's first available font.
                 * The exception is when 'ex' occurs in the value of the 'font-size' property,
                 * in which case it refers to the 'ex' of the parent element.
                 */
                if (Property.CssName.Equals("font-size") && Property.Owner == Owner)
                {        // We are being called from the font-size property
                    if (Owner.parentElement != null)
                    {    // Basically just try and inherit our parents unit scale
                        return(Get_Font_Unit_Scale(Owner.parentElement, Property, Unit));
                    }
                    else        // No parent
                    {
                        /*
                         * CSS Specs:
                         * When used in the value of the font-size property on the element they refer to,
                         * these units refer to the computed font metrics of the parent element
                         * (or the computed font metrics corresponding to the initial values of the font property, if the element has no parent)
                         */

                        // I can only assume this means we default to the property declerations default/initial value
                        var def = CssDefinitions.StyleDefinitions[Property.CssName];
                        if (def != null)
                        {
                            return(def.Initial.Resolve() ?? throw new CssException($"Failed to resolve the default value specified in the '{Property.CssName}' property decleration to a number!"));
                        }
                    }
                }

#if DISABLE_FONT_SYSTEM
#else
                if (Owner.Style.Font != null)
                {
                    // XXX: implement logic to measure the 'x' height for our font. SEE: https://www.w3.org/TR/css-values-3/#font-relative-lengths
                    throw new NotImplementedException();
                }
#endif

                /*
                 * CSS Specs:
                 * In the cases where it is impossible or impractical to determine the x-height, a value of 0.5em should be used.
                 */
                return(Get_Font_Unit_Scale(Owner, Property, ECssUnit.EM) * 0.5);
            }

            default:
                throw new NotImplementedException($"CSS Unit type '{Enum.GetName(typeof(ECssUnit), Unit)}' has not been implemented!");
            }
        }
Example #8
0
        public static CssValue Consume_CssValue(DataConsumer <CssToken> Stream)
        {
            if (Stream is null)
            {
                throw new CssParserException(CssErrors.STREAM_IS_NULL);
            }
            Contract.EndContractBlock();


            CssToken Token = Stream.Next;

            switch (Token.Type)
            {
            case ECssTokenType.Dimension:
            {
                var      tok  = Stream.Consume() as DimensionToken;
                ECssUnit unit = ECssUnit.PX;

                if (!string.IsNullOrEmpty(tok.Unit))
                {
                    ECssUnit unitLookup = Lookup.Enum <ECssUnit>(tok.Unit);
                    unit = unitLookup;
                }

                return(new CssValue(ECssValueTypes.DIMENSION, tok.Number, unit));
            }

            case ECssTokenType.Number:
            {
                var tok = Stream.Consume() as NumberToken;
                return(new CssValue(ECssValueTypes.NUMBER, tok.Number));
            }

            case ECssTokenType.Percentage:
            {
                var tok = Stream.Consume() as PercentageToken;
                return(new CssValue(ECssValueTypes.PERCENT, tok.Number));
            }

            case ECssTokenType.String:
            {
                var tok = Stream.Consume() as StringToken;
                return(new CssValue(ECssValueTypes.STRING, tok.Value));
            }

            case ECssTokenType.Ident:    // Keyword
            {
                var tok = Stream.Consume() as IdentToken;
                return(new CssValue(ECssValueTypes.KEYWORD, tok.Value));
            }

            case ECssTokenType.FunctionName:
            {
                CssFunction func = Consume_Function(Stream);
                return(new CssValue(func));
            }

            case ECssTokenType.Function:
            {
                var func = Stream.Consume() as CssFunction;
                return(new CssValue(func));
            }

            case ECssTokenType.Url:
            {        /* XXX: Finish this */
                throw new NotSupportedException("URL values are not supported as of yet!");
            }

            case ECssTokenType.EOF:
            {
                return(CssValue.Null);
            }

            default:
            {
                throw new CssParserException(String.Format(CultureInfo.InvariantCulture, CssErrors.UNHANDLED_TOKEN_FOR_CSS_VALUE, Token.Type), Stream);
            }
            }
        }
Example #9
0
 /// <summary>Create an absolute length value if not null, or return the given default value</summary>
 public static CssValue From(double?value, ECssUnit Unit, CssValue defaultValue) => (!value.HasValue ? defaultValue : new CssValue(ECssValueTypes.DIMENSION, value.Value, Unit));
Example #10
0
 /// <summary>Create an absolute length value</summary>
 public static CssValue From(double value, ECssUnit Unit) => new CssValue(ECssValueTypes.DIMENSION, value, Unit);
Example #11
0
        private static ECssValueFlags Get_Inherent_Value_Type_Flags(ECssValueTypes Type, ECssUnit Unit, object Value)
        {
            ECssValueFlags Flags = ECssValueFlags.None;

            /*if (Value is Array)
             * {
             *  Flags |= ECssValueFlags.Collection;
             * }*/

            switch (Type)
            {
            // NOTE: Auto values get calculated in vastly different ways, sometimes this doesn't even indicate that a value depends on the value of other properties,
            //so it should NOT get the 'Depends' flag
            case ECssValueTypes.INHERIT:    // Inherited values function like redirects which compute to the current value of the matching property for the owning element's parent
            case ECssValueTypes.PERCENT:    // Percentage values represent a percentage of another property's value
            {
                Flags |= ECssValueFlags.Depends;
                break;
            }

            case ECssValueTypes.NULL:
            case ECssValueTypes.NONE:
            case ECssValueTypes.INITIAL:
            case ECssValueTypes.INTEGER:
            case ECssValueTypes.NUMBER:
            case ECssValueTypes.STRING:
            case ECssValueTypes.KEYWORD:
            case ECssValueTypes.COLOR:
            case ECssValueTypes.IMAGE:
            case ECssValueTypes.POSITION:    // The position has already been resolved here.
            case ECssValueTypes.FUNCTION:    // The function args have already been resolved here.
            {
                Flags |= ECssValueFlags.Absolute;
                break;
            }

            case ECssValueTypes.UNSET:
            case ECssValueTypes.AUTO:
            case ECssValueTypes.DIMENSION:
            case ECssValueTypes.RATIO:
            case ECssValueTypes.RESOLUTION:
            {
                /* XXX:
                 * These values when used on properties CAN be dependant but arent always so idk maybe its best to leave them as absolute?
                 * Maybe we can come up with some sort of intermediate state that causes them to resolve their flag to absolute/dependent AFTER they get assigned to a property?
                 */
                Flags |= ECssValueFlags.Absolute;
                break;
            }

            case ECssValueTypes.COLLECTION:    // A collections flags are the combined flags of all it's sub-values
            {
                if (Value is Array array)
                {        // Multi object
                    foreach (object o in array)
                    {
                        if (o is CssValue cssValue)
                        {
                            Flags |= Get_Inherent_Value_Type_Flags(cssValue.Type, cssValue.Unit, cssValue.value);
                        }
                        else
                        {
                            throw new CssException($"All {nameof(CssValue)} collection members must be {nameof(CssValue)}s");
                        }
                    }
                    return(Flags);
                }
                else if (Value is CssValue cssValue)
                {        // Single object
                    Flags |= Get_Inherent_Value_Type_Flags(cssValue.Type, cssValue.Unit, cssValue.value);
                }
                else
                {
                    throw new CssException($"All {nameof(CssValue)} collection members must be {nameof(CssValue)}s");
                }
                break;
            }

            default:
            {
                throw new NotImplementedException($"Flag handling for the '{Enum.GetName(typeof(ECssValueTypes), Type)}' css-value type has not been implemented!");
            }
            }

            return(Flags);
        }