Esempio n. 1
0
        public override void BuildFilter(RenderContext renderer)
        {
            switch (Overflow)
            {
            case Overflow.Auto:
            case Overflow.Visible:
            case Overflow.Scroll:

                base.BuildFilter(renderer);
                break;

            default:
                ScreenRegion prevClip = renderer.ClipRegion;

                try{
                    Css.ComputedStyle cs = Style.Computed;

                    renderer.SetClip(new BoxRegion(cs.OffsetLeft, cs.OffsetTop, cs.PixelWidth, cs.PixelHeight), false);

                    base.BuildFilter(renderer);
                }finally{
                    renderer.SetClip(prevClip, true);
                }

                break;
            }
        }
Esempio n. 2
0
        /// <summary>Only pops if the given element had a transform to add earlier.</summary>
        public void PopTransform(SVGElement by)
        {
            // Get CS:
            Css.ComputedStyle computed  = by.Style.Computed;
            Transformation    transform = computed.TransformX;

            if (transform != null)
            {
                // Pop it off again:
                Transformations.Pop();
            }
        }
Esempio n. 3
0
        public void PushTransform(SVGElement by)
        {
            // Get CS:
            Css.ComputedStyle computed = by.Style.Computed;

            Transformation transform = computed.TransformX;

            // Push the transform to our stack, if we have one.
            if (transform != null)
            {
                // Add it to the stack:
                Transformations.Push(transform);

                // Update it:
                transform.RecalculateMatrix(computed, computed.FirstBox);
            }
        }
Esempio n. 4
0
        /// <summary>Removes this selector from all the computed styles it affects, except for the target.
        /// Use ComputedStyle.RemoveMatch(x) instead of calling this directly.</summary>
        internal void Remove()
        {
            for (int i = 0; i < MatchedRoots.Length; i++)
            {
                // Remove it (if it's the target and it was active, it'll also remove the style for us too):
                MatchingRoot root = MatchedRoots[i];

                // Remove from matches:
                ComputedStyle cs = (root.Node as IRenderableNode).ComputedStyle;

                // Remove the node:
                if (root.NextInStyle == null)
                {
                    cs.LastMatch = root.PreviousInStyle;
                }
                else
                {
                    root.NextInStyle.PreviousInStyle = root.PreviousInStyle;
                }

                if (root.PreviousInStyle == null)
                {
                    cs.FirstMatch = root.NextInStyle;
                }
                else
                {
                    root.PreviousInStyle.NextInStyle = root.NextInStyle;
                }

                if (root.IsTarget && Active)
                {
                    // Remove props:
                    cs.MatchChanged(Style, false);
                }
            }
        }
 public SparkInformerNode()
 {
     Computed = new ComputedStyle(this);
 }
Esempio n. 6
0
        /// <summary>Lets the renderer know that the given parent element has finished
        /// packing all of its kids. This allows alignment to occur next.</summary>
        /// <param name="renderable">The element that is done packing.</param>
        public void EndLines(LineBoxMeta lineZone, ComputedStyle computed, LayoutBox box)
        {
            // Pop the box:
            BoxStack.Pop();

            // Complete the last line:
            lineZone.CompleteLine(LineBreakMode.NoBreak | LineBreakMode.Last);

            // If inline-block or float, clear:
            if (box.DisplayMode == DisplayMode.InlineBlock || box.FloatMode != FloatMode.None)
            {
                // Must clear:
                lineZone.ClearFloat(FloatMode.Both);

                lineZone.PenY   += lineZone.ClearY_;
                lineZone.ClearY_ = 0f;
            }

            // block, inline-block
            if (lineZone is BlockBoxMeta)
            {
                bool heightChange = false;

                if (box.InnerHeight == -1f)
                {
                    heightChange    = true;
                    box.InnerHeight = lineZone.PenY;

                    // Clip height now:
                    box.InnerHeight = computed.ClipHeight(box.DisplayMode, box.InnerHeight);
                }

                box.ContentHeight = lineZone.PenY;
                box.ContentWidth  = lineZone.LargestLineWidth;

                // If it's inline then we set the line width.
                if (box.InnerWidth == -1f)
                {
                    box.InnerWidth = lineZone.LargestLineWidth;

                    // Apply valid width/height:
                    box.SetDimensions(false, false);
                }
                else if (heightChange)
                {
                    // Apply valid width/height:
                    box.SetDimensions(false, false);
                }

                bool inFlow = (box.PositionMode & PositionMode.InFlow) != 0;

                // Update position of the top-of-stack pen:
                LineBoxMeta tos = TopOfStackSafe;

                if (tos == null)
                {
                    LastBlockBox = null;
                }
                else
                {
                    if (inFlow)
                    {
                        // Advance the pen:
                        tos.AdvancePen(box);
                    }

                    // Restore previous block:
                    LastBlockBox = tos as BlockBoxMeta;

                    if (LastBlockBox == null)
                    {
                        // Rare - block inside inline.
                        LastBlockBox = (tos as InlineBoxMeta).HostBlock;
                    }
                }
            }
        }
Esempio n. 7
0
        /// <summary>Sets up this renderer so that it's ready to start packing child elements of
        /// a given element into lines.</summary>
        /// <param name="renderable">The parent render data whose children will be packed.</param>
        public LineBoxMeta BeginLines(RenderableData renderable, VirtualElements virts, LayoutBox box, bool autoWidth)
        {
            // Get CS:
            ComputedStyle cs = renderable.computedStyle;

            LineBoxMeta lineZone;

            InfiniText.FontFace face = box.FontFace;

            // Update line height:

            // Line height:
            Css.Value lineHeightValue = cs.LineHeightX;

            float cssLineHeight;

            if (lineHeightValue.IsType(typeof(Css.Keywords.Normal)))
            {
                // Get from the metrics font now:
                cssLineHeight = box.FontFace.BaselineToBaseline * box.FontSize;
            }
            else if (
                lineHeightValue.Type != Css.ValueType.RelativeNumber &&
                lineHeightValue.GetType() != typeof(Css.Units.DecimalUnit)
                )
            {
                // E.g. line-height:14px, but not line-height:1. It's just as-is:
                cssLineHeight = lineHeightValue.GetRawDecimal();
            }
            else
            {
                // Some multiple of the font size:
                cssLineHeight = lineHeightValue.GetRawDecimal() * box.FontSize;
            }

            // Check if it's a block context:
            if (box.DisplayMode == DisplayMode.Inline && LastBlockBox != null)
            {
                // Anything else uses the nearest parent block element as the max.
                lineZone = new InlineBoxMeta(LastBlockBox, TopOfStackSafe, box, renderable);

                // Put up the 'strut':
                lineZone.LineHeight = cssLineHeight;
                box.Baseline        = box.FontSize * face.Descender;
            }
            else
            {
                lineZone      = LastBlockBox = new BlockBoxMeta(TopOfStackSafe, box, renderable);
                lineZone.MaxX = box.InnerWidth;

                if (virts != null && virts.Has(ComputedStyle.VerticalScrollPriority))
                {
                    lineZone.MaxX -= 14;

                    if (lineZone.MaxX < 0)
                    {
                        lineZone.MaxX = 0;
                    }
                }

                bool left = (cs.DrawDirectionX == DirectionMode.RTL);
                lineZone.GoingLeftwards = left;

                // H-align:
                int hAlign = cs.HorizontalAlignX;

                if (hAlign == HorizontalAlignMode.Auto)
                {
                    if (left)
                    {
                        hAlign = HorizontalAlignMode.Right;
                    }
                    else
                    {
                        hAlign = HorizontalAlignMode.Left;
                    }
                }

                if (hAlign == HorizontalAlignMode.Left)
                {
                    // Ok how it is (left by default).
                    hAlign = 0;
                }

                lineZone.HorizontalAlign = hAlign;
            }

            // Apply whitespace mode:
            lineZone.WhiteSpace = cs.WhiteSpaceX;

            // Apply line height:
            lineZone.CssLineHeight = cssLineHeight;

            // Update vertical-align:
            Css.Value vAlign = cs.Resolve(Css.Properties.VerticalAlign.GlobalProperty);

            // Get the complete value:
            float vAlignValue = vAlign.GetDecimal(renderable, Css.Properties.VerticalAlign.GlobalProperty);

            // If it's a keyword..
            if (vAlign is Css.CssKeyword)
            {
                // It's a mode:
                lineZone.VerticalAlign       = (int)vAlignValue;
                lineZone.VerticalAlignOffset = 0f;
            }
            else
            {
                // It's a baseline offset:
                lineZone.VerticalAlign       = VerticalAlignMode.Baseline;
                lineZone.VerticalAlignOffset = vAlignValue;
            }

            box.ContentWidth  = 0;
            box.ContentHeight = 0;

            return(lineZone);
        }
        internal override void Layout(LayoutBox box, Renderman renderer)
        {
            if (Corners != null)
            {
                Corners.PreLayout();
            }

            ComputedStyle computed = RenderData.computedStyle;

            // Find the zIndex:
            // NB: At same depth as BGColour - right at the back.
            float zIndex = (computed.ZIndex - 0.006f);

            // Get the co-ord of the top edge:
            float top  = box.Y;
            float left = box.X;

            // Get the border widths:
            BoxStyle width = box.Border;

            // Move top by the widths:
            top  += width.Top;
            left += width.Left;

            // And the dimensions of the lines:
            float boxWidth  = box.PaddedWidth;
            float boxHeight = box.PaddedHeight;

            // Get the other dimensions:
            float topY    = top - width.Top;
            float right   = left + boxWidth;
            float rightX  = right + width.Right;
            float bottom  = top + boxHeight;
            float bottomY = bottom + width.Bottom;
            float leftX   = left - width.Left;
            int   segment = renderer.Segment;

            Transformation transform = renderer.Transform;

            BoxRegion screenRegion = new BoxRegion();

            // Get the default colour - that's the same as the text colour:
            Color colour = Color.black;

            // Is the border multicoloured?
            bool multiColour = false;

            // Does this border have a colour?
            if (BaseColour == null)
            {
                // Grab the text colour if there is one:
                if (RenderData.Text != null)
                {
                    // It's the same as the font colour:
                    colour = RenderData.Text.BaseColour * renderer.ColorOverlay;
                }
                else
                {
                    // Nope - We need to set alpha:
                    colour.a = renderer.ColorOverlay.a;
                }
            }
            else if (BaseColour.Count == 1)
            {
                colour = BaseColour[0].GetColour(RenderData, Css.Properties.BorderColor.GlobalProperty) * renderer.ColorOverlay;
            }
            else
            {
                multiColour = true;
            }

            // Handle border-radius:
            if (Corners != null)
            {
                for (int i = 0; i < 4; i++)
                {
                    if (multiColour)
                    {
                        colour = BaseColour[i].GetColour(RenderData, Css.Properties.BorderColor.GlobalProperty) * renderer.ColorOverlay;
                    }

                    Corners.Layout(colour, box, renderer, i);
                }
            }

            // Get clipper:
            BoxRegion clip = renderer.ClippingBoundary;

            float origLeftX   = leftX;
            float origTopY    = topY;
            float origBottomY = bottomY;
            float origRightX  = rightX;

            // top and topY:
            if (top < clip.Y)
            {
                top = clip.Y;
            }
            else if (top > clip.MaxY)
            {
                top = clip.MaxY;
            }

            if (topY < clip.Y)
            {
                topY = clip.Y;
            }

            // bottom and bottomY:
            if (bottom > clip.MaxY)
            {
                bottom = clip.MaxY;
            }
            else if (bottom < clip.Y)
            {
                bottom = clip.Y;
            }

            if (bottomY > clip.MaxY)
            {
                bottomY = clip.MaxY;
            }

            // right and rightX:
            if (right < clip.X)
            {
                right = clip.X;
            }
            else if (right > clip.MaxX)
            {
                right = clip.MaxX;
            }

            // rightX vs clip.MaxX
            if (rightX > clip.MaxX)
            {
                rightX = clip.MaxX;
            }

            // left and leftX:
            if (left < clip.X)
            {
                left = clip.X;
            }
            else if (left > clip.MaxX)
            {
                left = clip.MaxX;
            }

            if (leftX < clip.X)
            {
                leftX = clip.X;
            }

            float cornerPointA;
            float cornerPointB;

            for (int i = 0; i < 4; i++)
            {
                // Does this border have multiple colours?
                if (multiColour)
                {
                    colour = BaseColour[i].GetColour(RenderData, Css.Properties.BorderColor.GlobalProperty) * renderer.ColorOverlay;
                }

                // Add to region:
                switch (i)
                {
                case 0:
                    // Top.
                    screenRegion.SetPoints(leftX, topY, rightX, top);
                    break;

                case 1:
                    // Right.

                    // We only draw the right border if 'segment' includes 'end'
                    if ((segment & LineBoxSegment.End) == 0)
                    {
                        goto NextLine;
                    }

                    screenRegion.SetPoints(right, topY, rightX, bottomY);
                    break;

                case 2:
                    // Bottom.

                    screenRegion.SetPoints(leftX, bottom, rightX, bottomY);
                    break;

                case 3:
                    // Left.

                    // Similarly, we only draw left if segment includes 'start':
                    if ((segment & LineBoxSegment.Start) == 0)
                    {
                        goto NextLine;
                    }

                    screenRegion.SetPoints(leftX, topY, left, bottomY);
                    break;
                }

                if (screenRegion.Overlaps(clip))
                {
                    // It's visible.

                    // Ensure we have a batch (doesn't change graphics or font textures, thus both null):
                    renderer.SetupBatch(this, null, null);

                    // And get our block ready:
                    MeshBlock block = Add(renderer);

                    // Set the UV to that of the solid block colour pixel:
                    block.SetSolidColourUV();

                    // Set the border colour:
                    block.SetColour(colour);

                    // Apply verts:

                    switch (i)
                    {
                    case 0:

                        // Top:
                        if (Corners == null)
                        {
                            block.VertexTopLeft     = renderer.PixelToWorldUnit(leftX, topY, zIndex);
                            block.VertexTopRight    = renderer.PixelToWorldUnit(rightX, topY, zIndex);
                            block.VertexBottomLeft  = renderer.PixelToWorldUnit(left, top, zIndex);
                            block.VertexBottomRight = renderer.PixelToWorldUnit(right, top, zIndex);
                        }
                        else
                        {
                            // Top left/right corners:
                            cornerPointA = origLeftX + Corners.TopLeftRadius;
                            cornerPointB = origRightX - Corners.TopRightRadius;

                            if (cornerPointA < clip.X)
                            {
                                cornerPointA = clip.X;
                            }

                            if (cornerPointB > clip.MaxX)
                            {
                                cornerPointB = clip.MaxX;
                            }

                            // Note that we use leftX/rightX for all of them.
                            // That's because the corner has a 'straight' edge.
                            block.VertexTopLeft     = renderer.PixelToWorldUnit(cornerPointA, topY, zIndex);
                            block.VertexTopRight    = renderer.PixelToWorldUnit(cornerPointB, topY, zIndex);
                            block.VertexBottomLeft  = renderer.PixelToWorldUnit(cornerPointA, top, zIndex);
                            block.VertexBottomRight = renderer.PixelToWorldUnit(cornerPointB, top, zIndex);
                        }

                        break;

                    case 1:

                        // Right:
                        if (Corners == null)
                        {
                            block.VertexTopLeft     = renderer.PixelToWorldUnit(right, top, zIndex);
                            block.VertexTopRight    = renderer.PixelToWorldUnit(rightX, topY, zIndex);
                            block.VertexBottomLeft  = renderer.PixelToWorldUnit(right, bottom, zIndex);
                            block.VertexBottomRight = renderer.PixelToWorldUnit(rightX, bottomY, zIndex);
                        }
                        else
                        {
                            // Top right/ bottom right corners:
                            cornerPointA = origTopY + Corners.TopRightRadius;
                            cornerPointB = origBottomY - Corners.BottomRightRadius;


                            if (cornerPointA < clip.Y)
                            {
                                cornerPointA = clip.Y;
                            }

                            if (cornerPointB > clip.MaxY)
                            {
                                cornerPointB = clip.MaxY;
                            }

                            // Note that we use topY/bottomY for all of them.
                            block.VertexTopLeft     = renderer.PixelToWorldUnit(right, cornerPointA, zIndex);
                            block.VertexTopRight    = renderer.PixelToWorldUnit(rightX, cornerPointA, zIndex);
                            block.VertexBottomLeft  = renderer.PixelToWorldUnit(right, cornerPointB, zIndex);
                            block.VertexBottomRight = renderer.PixelToWorldUnit(rightX, cornerPointB, zIndex);
                        }

                        break;

                    case 2:

                        // Bottom:
                        if (Corners == null)
                        {
                            block.VertexTopLeft     = renderer.PixelToWorldUnit(left, bottom, zIndex);
                            block.VertexTopRight    = renderer.PixelToWorldUnit(right, bottom, zIndex);
                            block.VertexBottomLeft  = renderer.PixelToWorldUnit(leftX, bottomY, zIndex);
                            block.VertexBottomRight = renderer.PixelToWorldUnit(rightX, bottomY, zIndex);
                        }
                        else
                        {
                            // Bottom left/ bottom right corners:
                            // Note that we use leftX/rightX for all of them.
                            cornerPointA = origLeftX + Corners.BottomLeftRadius;
                            cornerPointB = origRightX - Corners.BottomRightRadius;

                            if (cornerPointA < clip.X)
                            {
                                cornerPointA = clip.X;
                            }

                            if (cornerPointB > clip.MaxX)
                            {
                                cornerPointB = clip.MaxX;
                            }

                            block.VertexTopLeft     = renderer.PixelToWorldUnit(cornerPointA, bottom, zIndex);
                            block.VertexTopRight    = renderer.PixelToWorldUnit(cornerPointB, bottom, zIndex);
                            block.VertexBottomLeft  = renderer.PixelToWorldUnit(cornerPointA, bottomY, zIndex);
                            block.VertexBottomRight = renderer.PixelToWorldUnit(cornerPointB, bottomY, zIndex);
                        }

                        break;

                    case 3:

                        // Left:
                        if (Corners == null)
                        {
                            block.VertexTopLeft     = renderer.PixelToWorldUnit(leftX, topY, zIndex);
                            block.VertexTopRight    = renderer.PixelToWorldUnit(left, top, zIndex);
                            block.VertexBottomLeft  = renderer.PixelToWorldUnit(leftX, bottomY, zIndex);
                            block.VertexBottomRight = renderer.PixelToWorldUnit(left, bottom, zIndex);
                        }
                        else
                        {
                            // Top right/ bottom right corners:
                            cornerPointA = origTopY + Corners.TopLeftRadius;
                            cornerPointB = origBottomY + width.Bottom - Corners.BottomLeftRadius;

                            if (cornerPointA < clip.Y)
                            {
                                cornerPointA = clip.Y;
                            }

                            if (cornerPointB > clip.MaxY)
                            {
                                cornerPointB = clip.MaxY;
                            }

                            block.VertexTopLeft     = renderer.PixelToWorldUnit(leftX, cornerPointA, zIndex);
                            block.VertexTopRight    = renderer.PixelToWorldUnit(left, cornerPointA, zIndex);
                            block.VertexBottomLeft  = renderer.PixelToWorldUnit(leftX, cornerPointB, zIndex);
                            block.VertexBottomRight = renderer.PixelToWorldUnit(left, cornerPointB, zIndex);
                        }

                        break;
                    }

                    // Done!
                    block.Done(transform);
                }

NextLine:
                continue;
            }
        }
Esempio n. 9
0
        /// <summary>Applies a structurally matched selector to the DOM.
        /// Occurs shortly after StructureMatch.</summary>
        public MatchingSelector BakeToTarget(ComputedStyle cs, CssEvent e)
        {
            // Get the node:
            Node node = cs.Element;

            // First, generate our instance:
            MatchingSelector ms = new MatchingSelector();

            // Update it:
            ms.Selector     = this;
            ms.MatchedRoots = new MatchingRoot[RootCount];

            // For each root, create a MatchingRoot object.

            // Apply target - this helps track which element we're actually testing:
            e.CurrentNode    = node;
            e.SelectorTarget = null;

            // We always start from the tail and work backwards.
            // If we get a match, then the caller can do whatever it wants to the target.

            for (int i = RootCount - 1; i >= 0; i--)
            {
                // Get the matcher:
                RootMatcher rm = Roots[i];

                // Try matching this root:
                if (!rm.TryMatch(e.CurrentNode))
                {
                    // Failed! If we had a matcher and it has Repeat set true, try again:
                    if (rm.NextMatcher != null && rm.NextMatcher.Repeat)
                    {
                        // Move target:
                        rm.NextMatcher.MoveUpwards(e);

                        // Try matching again:
                        i++;
                        continue;
                    }
                }
                else
                {
                    // Match! e.CurrentNode is the node to add.

                    // Create the instance:
                    MatchingRoot matchedRoot = new MatchingRoot();
                    matchedRoot.Root     = rm;
                    matchedRoot.Selector = ms;
                    matchedRoot.Node     = e.CurrentNode;

                    // Get renderable node:
                    IRenderableNode renderable = (e.CurrentNode as IRenderableNode);

                    // Add to selector:
                    ms.MatchedRoots[i] = matchedRoot;

                    // Add:
                    ComputedStyle nodeCs = renderable.ComputedStyle;

                    // Push the match now into the linked list:
                    if (nodeCs.FirstMatch == null)
                    {
                        nodeCs.FirstMatch = matchedRoot;
                        nodeCs.LastMatch  = matchedRoot;
                    }
                    else
                    {
                        matchedRoot.PreviousInStyle  = nodeCs.LastMatch;
                        nodeCs.LastMatch.NextInStyle = matchedRoot;
                        nodeCs.LastMatch             = matchedRoot;
                    }

                    if (rm.IsTarget)
                    {
                        // Update the target now:
                        e.SelectorTarget = renderable.RenderData;
                    }
                }

                // If we have a structure matcher, run it now. It'll move CurrentNode for us:
                if (rm.PreviousMatcher != null)
                {
                    // Move target:
                    rm.PreviousMatcher.MoveUpwards(e);
                }
            }

            // Final pass - if we have a pseudo-element, apply it now:
            if (PseudoElement != null)
            {
                PseudoElement.Select(e);
            }

            // Apply target:
            ms.Target = e.SelectorTarget;

            // Finally, refresh all:
            ms.ResetActive();

            return(ms);
        }
Esempio n. 10
0
        /// <summary>Figures out if this root is active or not.
        /// That may, in turn, figure out if the whole selector is/ is not.</summary>
        public void ResetActive()
        {
            // Get the local matchers:
            LocalMatcher[] locals = Root.LocalMatchers;

            bool active = true;

            if (locals != null)
            {
                // For each one..
                for (int i = 0; i < locals.Length; i++)
                {
                    // Is it active?
                    if (!locals[i].TryMatch(Node))
                    {
                        active = false;
                        break;
                    }
                }
            }

            if (active == Active)
            {
                return;
            }

            // Active changed!
            Active = active;

            // Tell the selector:
            int activeCount = Selector.ActiveRoots;

            if (active)
            {
                activeCount++;
            }
            else
            {
                activeCount--;
            }

            Selector.ActiveRoots = activeCount;

            if (activeCount == Selector.RootCount)
            {
                // They're all active!
                Selector.Active = true;

                if (Selector.Target != null)
                {
                    // Apply target:
                    ComputedStyle cs = Selector.Target.computedStyle;

                    // Apply now!
                    cs.MatchChanged(Style, true);
                }
            }
            else if (Selector.Active)
            {
                // The selector is no longer active.
                Selector.Active = false;

                if (Selector.Target != null)
                {
                    // Apply target:
                    ComputedStyle cs = Selector.Target.computedStyle;

                    // Apply now!
                    cs.MatchChanged(Style, false);
                }
            }
        }
Esempio n. 11
0
 /// <summary>Creates a new element style for the given element.</summary>
 /// <param name="element">The element that this will be the style for.</param>
 public ElementStyle(Dom.Element element) : base(element)
 {
     Computed = new ComputedStyle(element);
 }
Esempio n. 12
0
 /// <summary>Call this if the current property requires a text object. NOTE: This one may be null.</summary>
 public TextRenderingProperty3D GetText3D(ComputedStyle style)
 {
     // Grab it:
     return(style.RenderData.Text3D);
 }
Esempio n. 13
0
 /// <summary>Apply this CSS style to the given computed style.
 /// Note that you can grab the element from the computed style if you need that.</summary>
 /// <param name="style">The computed style to apply the property to.</param>
 /// <param name="value">The new value being applied.</param>
 public virtual void ApplyText(TextRenderingProperty text, RenderableData data, ComputedStyle style, Value value)
 {
 }
Esempio n. 14
0
 /// <summary>Apply this CSS style to the given computed style.
 /// Note that you can grab the element from the computed style if you need that.</summary>
 /// <param name="style">The computed style to apply the property to.</param>
 /// <param name="value">The new value being applied.</param>
 public virtual ApplyState Apply(ComputedStyle style, Value value)
 {
     // Ok!
     return(ApplyState.Ok);
 }
 public SparkInformerNode(InformNodeEvent onStart, InformNodeEvent onEnd)
 {
     OnStart  = onStart;
     OnEnd    = onEnd;
     Computed = new ComputedStyle(this);
 }
Esempio n. 16
0
 public KeyframesAnimationInstance(ComputedStyle style, KeyframesRule anim)
 {
     Style        = style;
     RawAnimation = anim;
 }
Esempio n. 17
0
        /// <summary>Gets or creates the base value for the given property.
        /// The base value is essentially the value held directly in this style sheet.
        /// E.g. if the value you're setting is the R channel of color-overlay, this sets up the color-overlay value for you.</summary>
        /// <returns>The raw value (which may have just been created). Never an 'inherit' or 'initial' keyword.</returns>
        internal Css.Value GetBaseValue(CssProperty property)
        {
            Css.Value propertyValue;

            // Does it exist already?
            if (!Properties.TryGetValue(property, out propertyValue))
            {
                // Nope! Create it now. Does the computed style hold a value instead?
                ComputedStyle computed = GetComputed();

                if (computed != null && computed.Properties.TryGetValue(property, out propertyValue) && propertyValue != null)
                {
                    // Derive from the computed value.
                    if (propertyValue is Css.Keywords.Inherit)
                    {
                        // Must clone the inherited value (using special inherit copy):
                        propertyValue = (propertyValue as Css.Keywords.Inherit).SetCopy();
                    }
                    else if (propertyValue is Css.Keywords.Initial)
                    {
                        // Clone the initial value:
                        propertyValue = property.InitialValue.Copy();
                    }
                    else
                    {
                        // Must copy it:
                        propertyValue = propertyValue.Copy();
                    }

                    // Make sure it has low specif:
                    propertyValue.Specifity = -1;
                }
                else
                {
                    // Needs to be created. Must also copy it.
                    // Copy is used because it'll probably change some internal value.
                    propertyValue = property.InitialValue.Copy();
                }

                Properties[property] = propertyValue;
            }
            else if (propertyValue is Css.Keywords.Inherit)
            {
                // Must clone the inherited value (using special inherit copy):
                propertyValue = (propertyValue as Css.Keywords.Inherit).SetCopy();

                // Make sure it has low specif:
                propertyValue.Specifity = -1;

                Properties[property] = propertyValue;
            }
            else if (propertyValue is Css.Keywords.Initial)
            {
                // Clone the initial value:
                propertyValue = property.InitialValue.Copy();

                // Make sure it has low specif:
                propertyValue.Specifity = -1;

                Properties[property] = propertyValue;
            }

            // If it's not currently a set, we need it as one.
            int size = property.SetSize;

            if (propertyValue is Css.ValueSet)
            {
                if (propertyValue.Count < size)
                {
                    // Resize it:
                    propertyValue.Count = size;
                }
            }
            else
            {
                // Create the set:
                Css.ValueSet set = new Css.ValueSet();
                set.Count = size;

                // Make sure it has low specif:
                set.Specifity = -1;

                for (int i = 0; i < size; i++)
                {
                    // Must copy each value (e.g. if they get animated):
                    set[i] = propertyValue.Copy();
                }

                Properties[property] = set;

                propertyValue = set;
            }

            return(propertyValue);
        }
Esempio n. 18
0
        /// <summary>True if this selector matches the structure of the DOM where the given CS is.</summary>
        public bool StructureMatch(ComputedStyle cs, CssEvent e)
        {
            // Get the node:
            Node node = cs.Element;

            if (node == null)
            {
                return(false);
            }

            // Apply target - this helps track which element we're actually testing:
            e.CurrentNode = node;

            // We always start from the tail and work backwards.
            // If we get a match, then the caller can do whatever it wants to the target.
            for (int i = RootCount - 1; i >= 0; i--)
            {
                // Get the matcher:
                RootMatcher rm = Roots[i];

                // Try matching this root:
                if (!rm.TryMatch(e.CurrentNode))
                {
                    // Failed! If we had a matcher and it has Repeat set true, try again:
                    if (rm.NextMatcher != null && rm.NextMatcher.Repeat)
                    {
                        // Move target:
                        rm.NextMatcher.MoveUpwards(e);

                        // Still got a node?
                        if (e.CurrentNode == null)
                        {
                            return(false);
                        }

                        // Try matching again:
                        i++;
                        continue;
                    }

                    return(false);
                }

                // If we have a structure matcher, run it now. It'll move CurrentNode for us:
                if (rm.PreviousMatcher != null)
                {
                    // Move target:
                    rm.PreviousMatcher.MoveUpwards(e);

                    // Still got a node?
                    if (e.CurrentNode == null)
                    {
                        return(false);
                    }
                }
            }

            // If we have a pseudo element, make sure parents haven't also matched this selector.
            if (PseudoElement != null)
            {
                // Have any parents matched this selector?
                Node parent = node.parentNode;

                while (parent != null)
                {
                    if (parent["spark-virt"] != null)
                    {
                        // Already on a virtual element - quit there.
                        return(false);
                    }

                    parent = parent.parentNode;
                }
            }

            // All clear!
            return(true);
        }
Esempio n. 19
0
        public void AddViewBoxTransform(BoxRegion region, AspectRatio aspectRatio, SVGSVGElement frag)
        {
            // Get the tags computed style:
            Css.ComputedStyle tagStyle = (frag == null) ? null : frag.Style.Computed;

            float x = (tagStyle == null ? 0 : tagStyle.OffsetLeft);
            float y = (tagStyle == null ? 0 : tagStyle.OffsetTop);

            if (region.IsEmpty)
            {
                PushMatrix(TranslateMatrix(x, y));
                return;
            }

            float width  = (tagStyle == null ? region.Width : tagStyle.PixelWidth);
            float height = (tagStyle == null ? region.Height : tagStyle.PixelHeight);

            float fScaleX = width / region.Width;
            float fScaleY = height / region.Height;             //(this.MinY < 0 ? -1 : 1) *
            float fMinX   = -region.X * fScaleX;
            float fMinY   = -region.Y * fScaleY;

            if (aspectRatio == null)
            {
                aspectRatio = new AspectRatio(SVGPreserveAspectRatio.xMidYMid, false);
            }

            if (aspectRatio.Align != SVGPreserveAspectRatio.none)
            {
                if (aspectRatio.Slice)
                {
                    fScaleX = (float)Math.Max(fScaleX, fScaleY);
                    fScaleY = (float)Math.Max(fScaleX, fScaleY);
                }
                else
                {
                    fScaleX = (float)Math.Min(fScaleX, fScaleY);
                    fScaleY = (float)Math.Min(fScaleX, fScaleY);
                }

                float fViewMidX = (region.Width / 2) * fScaleX;
                float fViewMidY = (region.Height / 2) * fScaleY;
                float fMidX     = width / 2;
                float fMidY     = height / 2;
                fMinX = -region.X * fScaleX;
                fMinY = -region.Y * fScaleY;

                switch (aspectRatio.Align)
                {
                case SVGPreserveAspectRatio.xMinYMin:
                    break;

                case SVGPreserveAspectRatio.xMidYMin:
                    fMinX += fMidX - fViewMidX;
                    break;

                case SVGPreserveAspectRatio.xMaxYMin:
                    fMinX += width - region.Width * fScaleX;
                    break;

                case SVGPreserveAspectRatio.xMinYMid:
                    fMinY += fMidY - fViewMidY;
                    break;

                case SVGPreserveAspectRatio.xMidYMid:
                    fMinX += fMidX - fViewMidX;
                    fMinY += fMidY - fViewMidY;
                    break;

                case SVGPreserveAspectRatio.xMaxYMid:
                    fMinX += width - region.Width * fScaleX;
                    fMinY += fMidY - fViewMidY;
                    break;

                case SVGPreserveAspectRatio.xMinYMax:
                    fMinY += height - region.Height * fScaleY;
                    break;

                case SVGPreserveAspectRatio.xMidYMax:
                    fMinX += fMidX - fViewMidX;
                    fMinY += height - region.Height * fScaleY;
                    break;

                case SVGPreserveAspectRatio.xMaxYMax:
                    fMinX += width - region.Width * fScaleX;
                    fMinY += height - region.Height * fScaleY;
                    break;

                default:
                    break;
                }
            }

            // Clip now:
            SetClip(new BoxRegion(x, y, width, height), false);

            Matrix4x4 matrix = ScaleMatrix(fScaleX, fScaleY);

            matrix *= TranslateMatrix(x, y);
            matrix *= TranslateMatrix(fMinX, fMinY);

            // Push it:
            PushMatrix(matrix);
        }
        /// <summary>Loads the character array (<see cref="Css.TextRenderingProperty.Characters"/>) from the given text string.</summary>
        internal void LoadCharacters(string text, RenderableData renderable)
        {
            if (Characters != null && Visible)
            {
                // Make sure each char goes offscreen:
                NowOffScreen();

                // Clear visible:
                Visible = false;
            }

            // Get the computed style:
            ComputedStyle computedStyle = renderable.computedStyle;

            // No longer dirty:
            Dirty = false;

            char[] characters = text.ToCharArray();

            // Get text transform:
            int textTransform = computedStyle.ResolveInt(Css.Properties.TextTransform.GlobalProperty);

            if (textTransform != TextTransformMode.None && characters.Length > 0)
            {
                switch (textTransform)
                {
                case TextTransformMode.Capitalize:

                    // Uppercase the first character:
                    characters[0] = char.ToUpper(characters[0]);

                    break;

                case TextTransformMode.Lowercase:

                    // Lowercase the whole string:
                    for (int i = 0; i < characters.Length; i++)
                    {
                        characters[i] = char.ToLower(characters[i]);
                    }

                    break;

                case TextTransformMode.Uppercase:

                    // Uppercase the whole string:
                    for (int i = 0; i < characters.Length; i++)
                    {
                        characters[i] = char.ToUpper(characters[i]);
                    }

                    break;
                }
            }

            // Get the whitespace mode:
            int whiteSpaceMode = computedStyle.WhiteSpaceX;

            // Purge characters that we don't want:
            if ((whiteSpaceMode & WhiteSpaceMode.NormalOrNoWrap) != 0)
            {
                // Dump breaks and repeated whitespace.
                bool dumpWhiteSpace = false;

                for (int i = 0; i < characters.Length; i++)
                {
                    char character = characters[i];

                    if (character == '\t')
                    {
                        // Dump:
                        characters[i] = '\0';
                    }
                    else if (character == '\r' || character == '\n')
                    {
                        // Dump:
                        characters[i] = '\0';

                        // Dump whitespaces immediately after these:
                        dumpWhiteSpace = true;
                        continue;
                    }
                    else if (character == '\u00A0')
                    {
                        // NBSP:
                        characters[i] = ' ';
                    }
                    else if (character == ' ')
                    {
                        if (dumpWhiteSpace)
                        {
                            // Dump:
                            characters[i] = '\0';
                        }
                        else
                        {
                            // Dump any consecutive whitespace (except for &nbsp;):
                            dumpWhiteSpace = true;
                        }

                        continue;
                    }

                    dumpWhiteSpace = false;
                }
            }
            else if (whiteSpaceMode == WhiteSpaceMode.PreLine)
            {
                // Dump repeated whitespace (and \r) only.
                bool dumpWhiteSpace = false;

                for (int i = 0; i < characters.Length; i++)
                {
                    char character = characters[i];

                    if (character == ' ')
                    {
                        if (dumpWhiteSpace)
                        {
                            // Dump:
                            characters[i] = '\0';
                        }
                        else
                        {
                            dumpWhiteSpace = true;
                        }

                        continue;
                    }
                    else if (character == '\u00A0')
                    {
                        // NBSP:
                        characters[i] = ' ';
                    }
                    else if (character == '\r')
                    {
                        characters[i]  = '\0';
                        dumpWhiteSpace = true;
                        continue;
                    }
                    else if (character == '\n')
                    {
                        dumpWhiteSpace = true;
                        continue;
                    }

                    dumpWhiteSpace = false;
                }
            }
            else
            {
                // \r and nbsp only.

                for (int i = 0; i < characters.Length; i++)
                {
                    char character = characters[i];

                    if (character == '\r')
                    {
                        characters[i] = '\0';
                    }
                    else if (character == '\u00A0')
                    {
                        // NBSP:
                        characters[i] = ' ';
                    }
                }
            }

            // Create characters if they're needed:
            if (Characters == null || Characters.Length != characters.Length)
            {
                Characters = new Glyph[characters.Length];
                Kerning    = null;
            }

            // Considered all empty until shown otherwise.
            AllEmpty = true;

            // Next, for each character, find its dynamic character.
            // At the same time we want to find out what dimensions this word has so it can be located correctly.
            Glyph previous = null;

            for (int i = 0; i < characters.Length; i++)
            {
                char rawChar = characters[i];

                if (rawChar == '\0')
                {
                    // It got dumped.
                    continue;
                }

                Glyph character = null;

                // Is it a unicode high/low surrogate pair?
                if (char.IsHighSurrogate(rawChar) && i != characters.Length - 1)
                {
                    // Low surrogate follows:
                    char lowChar = characters[i + 1];

                    // Get the full charcode:
                    int charcode = char.ConvertToUtf32(rawChar, lowChar);

                    // Grab the surrogate pair char:
                    character = FontToDraw.GetGlyphOrEmoji(charcode);

                    // Make sure there is no char in the low surrogate spot:
                    Characters[i + 1] = null;
                    // Update this character:
                    Characters[i] = character;
                    // Skip the low surrogate:
                    i++;
                }
                else if (rawChar == '\n')
                {
                    // Special case for newlines (They don't show up in host fonts).
                    if (NEWLINE_GLYPH == null)
                    {
                        NEWLINE_GLYPH             = new Glyph();
                        NEWLINE_GLYPH.RawCharcode = (int)'\n';
                    }

                    Characters[i] = NEWLINE_GLYPH;
                }
                else
                {
                    character     = FontToDraw.GetGlyphOrEmoji((int)rawChar);
                    Characters[i] = character;
                }


                if (character == null)
                {
                    continue;
                }

                if (previous != null)
                {
                    // Look for a kern pair:
                    if (character.Kerning != null)
                    {
                        float offset;

                        if (character.Kerning.TryGetValue(previous, out offset))
                        {
                            // Got a kern!
                            if (Kerning == null)
                            {
                                Kerning = new float[characters.Length];
                            }

                            Kerning[i] = offset;
                        }
                    }
                }

                previous = character;
                AllEmpty = false;
            }
        }
        /// <summary>Runs before reflow.</summary>
        public override void UpdateCss(Renderman renderer)
        {
            // Clear the blocks:
            FirstBox = null;
            LastBox  = null;

            // Get the text renderer (or create it):
            Css.TextRenderingProperty text = RequireTextProperty();

            // Get computed style:
            ComputedStyle cs = computedStyle;

            // Get the first box as it contains the fontface/ size:
            LayoutBox box = cs.FirstBox;

            // Colour too:
            Color fontColour = cs.Resolve(Css.Properties.ColorProperty.GlobalProperty).GetColour(this, Css.Properties.ColorProperty.GlobalProperty);

            // Colour:
            text.BaseColour = fontColour;

            // Font size update:
            float fontSize = box.FontSize;

            text.FontSize = fontSize;

            // Spacing:
            float wordSpacing   = cs.ResolveDecimal(Css.Properties.WordSpacing.GlobalProperty);
            float letterSpacing = cs.ResolveDecimal(Css.Properties.LetterSpacing.GlobalProperty);

            // If word spacing is not 'normal', remove 1em from it (Note that letter spacing is always additive):
            if (wordSpacing == -1f)
            {
                wordSpacing = 0f;
            }
            else
            {
                wordSpacing -= fontSize;
            }

            text.WordSpacing   = wordSpacing;
            text.LetterSpacing = letterSpacing;

            // Decoration:
            int decoration = cs.ResolveInt(Css.Properties.TextDecorationLine.GlobalProperty);

            if (decoration == 0)
            {
                // Remove a line if we have one:
                text.TextLine = null;
            }
            else
            {
                // Got a line!
                if (text.TextLine == null)
                {
                    text.TextLine = new TextDecorationInfo(decoration);
                }

                // Get the colour:
                Css.Value lineColour = cs.Resolve(Css.Properties.TextDecorationColor.GlobalProperty);

                if (lineColour == null || lineColour.IsType(typeof(Css.Keywords.CurrentColor)))
                {
                    // No override:
                    text.TextLine.ColourOverride = false;
                }
                else
                {
                    // Set the colour:
                    text.TextLine.SetColour(lineColour.GetColour(this, Css.Properties.TextDecorationColor.GlobalProperty));
                }
            }

            // Get the font face:
            text.FontToDraw = box.FontFace;

            // Overflow-wrap mode (only active for 'break-word' which is just '1'):
            text.OverflowWrapActive = (cs.ResolveInt(Css.Properties.OverflowWrap.GlobalProperty) == 1);

            // Check if the text is 'dirty'.
            // If it is, that means we'll need to rebuild the TextRenderingProperty's Glyph array.

            if (text.Dirty)
            {
                // Setup text now:
                // (Resets text.Characters based on all the text related CSS properties like variant etc).
                text.LoadCharacters((Node as RenderableTextNode).characterData_, this);
            }

            if (text.Characters == null || text.AllEmpty)
            {
                text.FontSize = 0f;
                return;
            }
        }