Ejemplo n.º 1
0
        private void RenderWord(float x, float y, TextNode node)
        {
            if (node.Type != TextNodeType.Word)
                return;

            int charGaps = node.Text.Length - 1;
            bool isCrumbleWord = CrumbledWord(node);
            if (isCrumbleWord)
                charGaps++;

            int pixelsPerGap = 0;
            int leftOverPixels = 0;

            if (charGaps != 0)
            {
                pixelsPerGap = (int)node.LengthTweak / charGaps;
                leftOverPixels = (int)node.LengthTweak - pixelsPerGap * charGaps;
            }

            for(int i = 0; i < node.Text.Length; i++){
                char c = node.Text[i];
                if(fontData.CharSetMapping.ContainsKey(c)){
                    var glyph = fontData.CharSetMapping[c];

                    RenderGlyph(x,y,c, false);

                    if (IsMonospacingActive)
                        x += MonoSpaceWidth;
                    else
                        x += (int)Math.Ceiling(glyph.rect.Width + fontData.meanGlyphWidth * Options.CharacterSpacing + fontData.GetKerningPairCorrection(i, node.Text, node));

                    x += pixelsPerGap;
                    if (leftOverPixels > 0)
                    {
                        x += 1.0f;
                        leftOverPixels--;
                    }
                    else if (leftOverPixels < 0)
                    {
                        x -= 1.0f;
                        leftOverPixels++;
                    }

                }
            }
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Checks whether to skip trailing space on line because the next word does not
        /// fit.
        /// 
        /// We only check one space - the assumption is that if there is more than one,
        /// it is a deliberate attempt to insert spaces.
        /// </summary>
        /// <param name="node"></param>
        /// <param name="lengthSoFar"></param>
        /// <param name="boundWidth"></param>
        /// <returns></returns>
        private bool SkipTrailingSpace(TextNode node, float lengthSoFar, float boundWidth)
        {
            if (node.Type == TextNodeType.Space && node.Next != null && node.Next.Type == TextNodeType.Word && node.ModifiedLength + node.Next.ModifiedLength + lengthSoFar > boundWidth)
            {
                return true;
            }

            return false;
        }
Ejemplo n.º 3
0
 public virtual bool MoveNext()
 {
     if (currentNode == null)
         currentNode = targetList.Head;
     else
         currentNode = currentNode.Next;
     return currentNode != null;
 }
Ejemplo n.º 4
0
 public void Reset()
 {
     currentNode = null;
 }
Ejemplo n.º 5
0
        private SizeF PrintOrMeasure(ProcessedText processedText, bool measureOnly)
        {
            // init values we'll return
            float maxMeasuredWidth = 0f;

            float xPos = 0f;
            float yPos = 0f;

            float xOffset = xPos;
            float yOffset = yPos;

            // determine what capacities we need
            var caps = new EnableCap[] { };

            if (!measureOnly && !UsingVertexBuffers)
            {
                GL.Color4(1.0f, 1.0f, 1.0f, 1.0f);

                caps = new EnableCap[] { EnableCap.Texture2D, EnableCap.Blend };
            }

            Helper.SafeGLEnable(caps, () =>
            {
                if (!measureOnly && !UsingVertexBuffers && Options.UseDefaultBlendFunction)
                {
                    GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);
                }

                float maxWidth = processedText.maxSize.Width;
                var alignment  = processedText.alignment;


                //TODO - use these instead of translate when rendering by position (at some point)

                var nodeList = processedText.textNodeList;
                for (TextNode node = nodeList.Head; node != null; node = node.Next)
                {
                    node.LengthTweak = 0f;  //reset tweaks
                }
                if (alignment == QFontAlignment.Right)
                {
                    xOffset -= (float)Math.Ceiling(TextNodeLineLength(nodeList.Head, maxWidth) - maxWidth);
                }
                else if (alignment == QFontAlignment.Centre)
                {
                    xOffset -= (float)Math.Ceiling(0.5f * TextNodeLineLength(nodeList.Head, maxWidth));
                }
                else if (alignment == QFontAlignment.Justify)
                {
                    JustifyLine(nodeList.Head, maxWidth);
                }


                bool atLeastOneNodeCosumedOnLine = false;
                float length = 0f;
                for (TextNode node = nodeList.Head; node != null; node = node.Next)
                {
                    bool newLine = false;

                    if (node.Type == TextNodeType.LineBreak)
                    {
                        newLine = true;
                    }
                    else
                    {
                        if (Options.WordWrap && SkipTrailingSpace(node, length, maxWidth) && atLeastOneNodeCosumedOnLine)
                        {
                            newLine = true;
                        }
                        else if (length + node.ModifiedLength <= maxWidth || !atLeastOneNodeCosumedOnLine)
                        {
                            atLeastOneNodeCosumedOnLine = true;

                            if (!measureOnly)
                            {
                                RenderWord(xOffset + length, yOffset, node);
                            }
                            length += node.ModifiedLength;

                            maxMeasuredWidth = Math.Max(length, maxMeasuredWidth);
                        }
                        else if (Options.WordWrap)
                        {
                            newLine = true;
                            if (node.Previous != null)
                            {
                                node = node.Previous;
                            }
                        }
                        else
                        {
                            continue; // continue so we still read line breaks even if reached max width
                        }
                    }

                    if (newLine)
                    {
                        if (yOffset + LineSpacing - yPos >= processedText.maxSize.Height)
                        {
                            break;
                        }

                        yOffset += LineSpacing;
                        xOffset  = xPos;
                        length   = 0f;
                        atLeastOneNodeCosumedOnLine = false;

                        if (node.Next != null)
                        {
                            if (alignment == QFontAlignment.Right)
                            {
                                xOffset -= (float)Math.Ceiling(TextNodeLineLength(node.Next, maxWidth) - maxWidth);
                            }
                            else if (alignment == QFontAlignment.Centre)
                            {
                                xOffset -= (float)Math.Ceiling(0.5f * TextNodeLineLength(node.Next, maxWidth));
                            }
                            else if (alignment == QFontAlignment.Justify)
                            {
                                JustifyLine(node.Next, maxWidth);
                            }
                        }
                    }
                }
            });

            return(new SizeF(maxMeasuredWidth, yOffset + LineSpacing - yPos));
        }
Ejemplo n.º 6
0
        private float MeasureTextNodeLength(TextNode node, QFontData fontData, QFontRenderOptions options)
        {
            bool monospaced = fontData.IsMonospacingActive(options);
            float monospaceWidth = fontData.GetMonoSpaceWidth(options);

            if (node.Type == TextNodeType.Space)
            {
                if (monospaced)
                    return monospaceWidth;

                return (float)Math.Ceiling(fontData.meanGlyphWidth * options.WordSpacing);
            }

            float length = 0f;
            if (node.Type == TextNodeType.Word)
            {

                for (int i = 0; i < node.Text.Length; i++)
                {
                    char c = node.Text[i];
                    if (fontData.CharSetMapping.ContainsKey(c))
                    {
                        if (monospaced)
                            length += monospaceWidth;
                        else
                            length += (float)Math.Ceiling(fontData.CharSetMapping[c].rect.Width + fontData.meanGlyphWidth * options.CharacterSpacing + fontData.GetKerningPairCorrection(i, node.Text, node));
                    }
                }
            }
            return length;
        }
Ejemplo n.º 7
0
 public void Add(TextNode node)
 {
     //new node is head (and tail)
     if(Head == null){
         Head = node;
         Tail = node;
     } else {
         Tail.Next = node;
         node.Previous = Tail;
         Tail = node;
     }
 }
Ejemplo n.º 8
0
        /// <summary>
        /// Computes the length of the next line, and whether the line is valid for
        /// justification.
        /// </summary>
        private void JustifyLine(TextNode node, float targetLength)
        {
            bool justifiable = false;

            if (node == null)
                return;

            var headNode = node; //keep track of the head node

            //start by finding the length of the block of text that we know will actually fit:

            int charGaps = 0;
            int spaceGaps = 0;

            bool atLeastOneNodeCosumedOnLine = false;
            float length = 0;
            var expandEndNode = node; //the node at the end of the smaller list (before adding additional word)
            for (; node != null; node = node.Next)
            {

                if (node.Type == TextNodeType.LineBreak)
                    break;

                if (SkipTrailingSpace(node, length, targetLength) && atLeastOneNodeCosumedOnLine)
                {
                    justifiable = true;
                    break;
                }

                if (length + node.Length < targetLength || !atLeastOneNodeCosumedOnLine)
                {

                    expandEndNode = node;

                    if (node.Type == TextNodeType.Space)
                        spaceGaps++;

                    if (node.Type == TextNodeType.Word)
                    {
                        charGaps += (node.Text.Length - 1);

                        //word was part of a crumbled word, so there's an extra char cap between the two words
                        if (CrumbledWord(node))
                            charGaps++;

                    }

                    atLeastOneNodeCosumedOnLine = true;
                    length += node.Length;
                }
                else
                {
                    justifiable = true;
                    break;
                }

            }

            //now we check how much additional length is added by adding an additional word to the line
            float extraLength = 0f;
            int extraSpaceGaps = 0;
            int extraCharGaps = 0;
            bool contractPossible = false;
            TextNode contractEndNode = null;
            for (node = expandEndNode.Next; node != null; node = node.Next)
            {

                if (node.Type == TextNodeType.LineBreak)
                    break;

                if (node.Type == TextNodeType.Space)
                {
                    extraLength += node.Length;
                    extraSpaceGaps++;
                }
                else if (node.Type == TextNodeType.Word)
                {
                    contractEndNode = node;
                    contractPossible = true;
                    extraLength += node.Length;
                    extraCharGaps += (node.Text.Length - 1);
                    break;
                }
            }

            if (justifiable)
            {

                //last part of this condition is to ensure that the full contraction is possible (it is all or nothing with contractions, since it looks really bad if we don't manage the full)
                bool contract = contractPossible && (extraLength + length - targetLength) * Options.JustifyContractionPenalty < (targetLength - length) &&
                    ((targetLength - (length + extraLength + 1)) / targetLength > -Options.JustifyCapContract);

                if((!contract && length < targetLength) || (contract && length + extraLength > targetLength))  //calculate padding pixels per word and char
                {

                    if (contract)
                    {
                        length += extraLength + 1;
                        charGaps += extraCharGaps;
                        spaceGaps += extraSpaceGaps;
                    }

                    int totalPixels = (int)(targetLength - length); //the total number of pixels that need to be added to line to justify it
                    int spacePixels = 0; //number of pixels to spread out amongst spaces
                    int charPixels = 0; //number of pixels to spread out amongst char gaps

                    if (contract)
                    {

                        if (totalPixels / targetLength < -Options.JustifyCapContract)
                            totalPixels = (int)(-Options.JustifyCapContract * targetLength);
                    }
                    else
                    {
                        if (totalPixels / targetLength > Options.JustifyCapExpand)
                            totalPixels = (int)(Options.JustifyCapExpand * targetLength);
                    }

                    //work out how to spread pixles between character gaps and word spaces
                    if (charGaps == 0)
                    {
                        spacePixels = totalPixels;
                    }
                    else if (spaceGaps == 0)
                    {
                        charPixels = totalPixels;
                    }
                    else
                    {

                        if(contract)
                            charPixels = (int)(totalPixels * Options.JustifyCharacterWeightForContract * charGaps / spaceGaps);
                        else
                            charPixels = (int)(totalPixels * Options.JustifyCharacterWeightForExpand * charGaps / spaceGaps);

                        if ((!contract && charPixels > totalPixels) ||
                            (contract && charPixels < totalPixels) )
                            charPixels = totalPixels;

                        spacePixels = totalPixels - charPixels;
                    }

                    int pixelsPerChar = 0;  //minimum number of pixels to add per char
                    int leftOverCharPixels = 0; //number of pixels remaining to only add for some chars

                    if (charGaps != 0)
                    {
                        pixelsPerChar = charPixels / charGaps;
                        leftOverCharPixels = charPixels - pixelsPerChar * charGaps;
                    }

                    int pixelsPerSpace = 0; //minimum number of pixels to add per space
                    int leftOverSpacePixels = 0; //number of pixels remaining to only add for some spaces

                    if (spaceGaps != 0)
                    {
                        pixelsPerSpace = spacePixels / spaceGaps;
                        leftOverSpacePixels = spacePixels - pixelsPerSpace * spaceGaps;
                    }

                    //now actually iterate over all nodes and set tweaked length
                    for (node = headNode; node != null; node = node.Next)
                    {

                        if (node.Type == TextNodeType.Space)
                        {
                            node.LengthTweak = pixelsPerSpace;
                            if (leftOverSpacePixels > 0)
                            {
                                node.LengthTweak += 1;
                                leftOverSpacePixels--;
                            }
                            else if (leftOverSpacePixels < 0)
                            {
                                node.LengthTweak -= 1;
                                leftOverSpacePixels++;
                            }

                        }
                        else if (node.Type == TextNodeType.Word)
                        {
                            int cGaps = (node.Text.Length - 1);
                            if (CrumbledWord(node))
                                cGaps++;

                            node.LengthTweak = cGaps * pixelsPerChar;

                            if (leftOverCharPixels >= cGaps)
                            {
                                node.LengthTweak += cGaps;
                                leftOverCharPixels -= cGaps;
                            }
                            else if (leftOverCharPixels <= -cGaps)
                            {
                                node.LengthTweak -= cGaps;
                                leftOverCharPixels += cGaps;
                            }
                            else
                            {
                                node.LengthTweak += leftOverCharPixels;
                                leftOverCharPixels = 0;
                            }
                        }

                        if ((!contract && node == expandEndNode) || (contract && node == contractEndNode))
                            break;

                    }

                }

            }
        }
Ejemplo n.º 9
0
        /// <summary>
        ///     Computes the length of the next line, and whether the line is valid for
        ///     justification.
        /// </summary>
        /// <param name="node">The starting text node</param>
        /// <param name="targetLength">The target line length</param>
        private void JustifyLine(TextNode node, float targetLength)
        {
            bool justifiable = false;

            if (node == null)
            {
                return;
            }

            TextNode headNode = node; //keep track of the head node


            //start by finding the length of the block of text that we know will actually fit:

            int charGaps  = 0;
            int spaceGaps = 0;

            bool     atLeastOneNodeCosumedOnLine = false;
            float    length        = 0;
            TextNode expandEndNode = node; //the node at the end of the smaller list (before adding additional word)

            for (; node != null; node = node.Next)
            {
                if (node.Type == TextNodeType.LineBreak)
                {
                    break;
                }

                if (SkipTrailingSpace(node, length, targetLength) && atLeastOneNodeCosumedOnLine)
                {
                    justifiable = true;
                    break;
                }

                if (length + node.Length < targetLength || !atLeastOneNodeCosumedOnLine)
                {
                    expandEndNode = node;

                    if (node.Type == TextNodeType.Space)
                    {
                        spaceGaps++;
                    }

                    if (node.Type == TextNodeType.Word)
                    {
                        charGaps += (node.Text.Length - 1);

                        //word was part of a crumbled word, so there's an extra char cap between the two words
                        if (CrumbledWord(node))
                        {
                            charGaps++;
                        }
                    }

                    atLeastOneNodeCosumedOnLine = true;
                    length += node.Length;
                }
                else
                {
                    justifiable = true;
                    break;
                }
            }

            //now we check how much additional length is added by adding an additional word to the line
            float    extraLength      = 0f;
            int      extraSpaceGaps   = 0;
            int      extraCharGaps    = 0;
            bool     contractPossible = false;
            TextNode contractEndNode  = null;

            for (node = expandEndNode.Next; node != null; node = node.Next)
            {
                if (node.Type == TextNodeType.LineBreak)
                {
                    break;
                }

                if (node.Type == TextNodeType.Space)
                {
                    extraLength += node.Length;
                    extraSpaceGaps++;
                }
                else if (node.Type == TextNodeType.Word)
                {
                    contractEndNode  = node;
                    contractPossible = true;
                    extraLength     += node.Length;
                    extraCharGaps   += (node.Text.Length - 1);
                    break;
                }
            }

            if (justifiable)
            {
                //last part of this condition is to ensure that the full contraction is possible (it is all or nothing with contractions, since it looks really bad if we don't manage the full)
                bool contract = contractPossible &&
                                (extraLength + length - targetLength) * Options.JustifyContractionPenalty <
                                (targetLength - length) &&
                                ((targetLength - (length + extraLength + 1)) / targetLength > -Options.JustifyCapContract);

                if ((!contract && length < targetLength) || (contract && length + extraLength > targetLength))
                //calculate padding pixels per word and char
                {
                    if (contract)
                    {
                        length    += extraLength + 1;
                        charGaps  += extraCharGaps;
                        spaceGaps += extraSpaceGaps;
                    }


                    var totalPixels = (int)(targetLength - length);
                    //the total number of pixels that need to be added to line to justify it
                    int spacePixels = 0; //number of pixels to spread out amongst spaces
                    int charPixels  = 0; //number of pixels to spread out amongst char gaps


                    if (contract)
                    {
                        if (totalPixels / targetLength < -Options.JustifyCapContract)
                        {
                            totalPixels = (int)(-Options.JustifyCapContract * targetLength);
                        }
                    }
                    else
                    {
                        if (totalPixels / targetLength > Options.JustifyCapExpand)
                        {
                            totalPixels = (int)(Options.JustifyCapExpand * targetLength);
                        }
                    }

                    //work out how to spread pixles between character gaps and word spaces
                    if (charGaps == 0)
                    {
                        spacePixels = totalPixels;
                    }
                    else if (spaceGaps == 0)
                    {
                        charPixels = totalPixels;
                    }
                    else
                    {
                        if (contract)
                        {
                            charPixels =
                                (int)(totalPixels * Options.JustifyCharacterWeightForContract * charGaps / spaceGaps);
                        }
                        else
                        {
                            charPixels = (int)(totalPixels * Options.JustifyCharacterWeightForExpand * charGaps / spaceGaps);
                        }


                        if ((!contract && charPixels > totalPixels) ||
                            (contract && charPixels < totalPixels))
                        {
                            charPixels = totalPixels;
                        }

                        spacePixels = totalPixels - charPixels;
                    }


                    int pixelsPerChar      = 0; //minimum number of pixels to add per char
                    int leftOverCharPixels = 0; //number of pixels remaining to only add for some chars

                    if (charGaps != 0)
                    {
                        pixelsPerChar      = charPixels / charGaps;
                        leftOverCharPixels = charPixels - pixelsPerChar * charGaps;
                    }

                    int pixelsPerSpace      = 0; //minimum number of pixels to add per space
                    int leftOverSpacePixels = 0; //number of pixels remaining to only add for some spaces

                    if (spaceGaps != 0)
                    {
                        pixelsPerSpace      = spacePixels / spaceGaps;
                        leftOverSpacePixels = spacePixels - pixelsPerSpace * spaceGaps;
                    }

                    //now actually iterate over all nodes and set tweaked length
                    for (node = headNode; node != null; node = node.Next)
                    {
                        if (node.Type == TextNodeType.Space)
                        {
                            node.LengthTweak = pixelsPerSpace;
                            if (leftOverSpacePixels > 0)
                            {
                                node.LengthTweak += 1;
                                leftOverSpacePixels--;
                            }
                            else if (leftOverSpacePixels < 0)
                            {
                                node.LengthTweak -= 1;
                                leftOverSpacePixels++;
                            }
                        }
                        else if (node.Type == TextNodeType.Word)
                        {
                            int cGaps = (node.Text.Length - 1);
                            if (CrumbledWord(node))
                            {
                                cGaps++;
                            }

                            node.LengthTweak = cGaps * pixelsPerChar;


                            if (leftOverCharPixels >= cGaps)
                            {
                                node.LengthTweak   += cGaps;
                                leftOverCharPixels -= cGaps;
                            }
                            else if (leftOverCharPixels <= -cGaps)
                            {
                                node.LengthTweak   -= cGaps;
                                leftOverCharPixels += cGaps;
                            }
                            else
                            {
                                node.LengthTweak  += leftOverCharPixels;
                                leftOverCharPixels = 0;
                            }
                        }

                        if ((!contract && node == expandEndNode) || (contract && node == contractEndNode))
                        {
                            break;
                        }
                    }
                }
            }
        }
Ejemplo n.º 10
0
 /// <summary>Sets the enumerator to its initial position, which is before the first element in the collection.</summary>
 /// <exception cref="T:System.InvalidOperationException">The collection was modified after the enumerator was created. </exception>
 /// <filterpriority>2</filterpriority>
 public void Reset()
 {
     _currentNode = null;
 }
Ejemplo n.º 11
0
 /// <summary>
 /// Checks whether a textnode has been crumbled
 /// </summary>
 /// <param name="node">The starting node</param>
 /// <returns>Whether the textnode has been crumbled</returns>
 private bool CrumbledWord(TextNode node)
 {
     return(node.Type == TextNodeType.Word && node.Next != null && node.Next.Type == TextNodeType.Word);
 }
Ejemplo n.º 12
0
        /// <summary>
        /// Print or measure the specified processed text
        /// </summary>
        /// <param name="processedText">The processed text</param>
        /// <param name="measureOnly">Whether to only measure the text</param>
        /// <param name="clippingRectangle">The clipping rectangle to scissor test the text with</param>
        /// <returns>The size of the text</returns>
        private SizeF PrintOrMeasure(ProcessedText processedText, bool measureOnly, Rectangle clippingRectangle = default(Rectangle))
        {
            // init values we'll return
            float maxMeasuredWidth = 0f;
            float maxCharHeight    = 0f;

            const float xPos = 0f;
            const float yPos = 0f;

            float xOffset = xPos;
            float yOffset = yPos;

            float          maxWidth  = processedText.MaxSize.Width;
            QFontAlignment alignment = processedText.Alignment;

            //TODO - use these instead of translate when rendering by position (at some point)

            TextNodeList nodeList = processedText.TextNodeList;

            for (TextNode node = nodeList.Head; node != null; node = node.Next)
            {
                node.LengthTweak = 0f; //reset tweaks
            }
            if (alignment == QFontAlignment.Right)
            {
                xOffset -= (float)Math.Ceiling(TextNodeLineLength(nodeList.Head, maxWidth) - maxWidth);
            }
            else if (alignment == QFontAlignment.Centre)
            {
                xOffset -= (float)Math.Ceiling(0.5f * TextNodeLineLength(nodeList.Head, maxWidth));
            }
            else if (alignment == QFontAlignment.Justify)
            {
                JustifyLine(nodeList.Head, maxWidth);
            }


            bool  atLeastOneNodeCosumedOnLine = false;
            float length = 0f;

            for (TextNode node = nodeList.Head; node != null; node = node.Next)
            {
                bool newLine = false;

                if (node.Type == TextNodeType.LineBreak)
                {
                    newLine = true;
                }
                else
                {
                    if (Options.WordWrap && SkipTrailingSpace(node, length, maxWidth) && atLeastOneNodeCosumedOnLine)
                    {
                        newLine = true;
                    }
                    else if (length + node.ModifiedLength <= maxWidth || !atLeastOneNodeCosumedOnLine)
                    {
                        atLeastOneNodeCosumedOnLine = true;

                        if (!measureOnly)
                        {
                            RenderWord(xOffset + length, yOffset, node, ref clippingRectangle);
                        }
                        length += node.ModifiedLength;

                        maxCharHeight    = Math.Max(maxCharHeight, node.Height);
                        maxMeasuredWidth = Math.Max(length, maxMeasuredWidth);
                    }
                    else if (Options.WordWrap)
                    {
                        newLine = true;
                        if (node.Previous != null)
                        {
                            node = node.Previous;
                        }
                    }
                    else
                    {
                        continue; // continue so we still read line breaks even if reached max width
                    }
                }

                if (newLine)
                {
                    if (processedText.MaxSize.Height > 0 &&
                        yOffset + LineSpacing - yPos >= processedText.MaxSize.Height)
                    {
                        break;
                    }
                    yOffset += LineSpacing;
                    xOffset  = xPos;
                    length   = 0f;
                    atLeastOneNodeCosumedOnLine = false;

                    if (node.Next != null)
                    {
                        if (alignment == QFontAlignment.Right)
                        {
                            xOffset -= (float)Math.Ceiling(TextNodeLineLength(node.Next, maxWidth) - maxWidth);
                        }
                        else if (alignment == QFontAlignment.Centre)
                        {
                            xOffset -= (float)Math.Ceiling(0.5f * TextNodeLineLength(node.Next, maxWidth));
                        }
                        else if (alignment == QFontAlignment.Justify)
                        {
                            JustifyLine(node.Next, maxWidth);
                        }
                    }
                }
            }

            LastSize = new SizeF(maxMeasuredWidth, yOffset + LineSpacing - yPos);
            return(LastSize);
        }
Ejemplo n.º 13
0
        private SizeF PrintOrMeasure(ProcessedText processedText, bool measureOnly)
        {
            var popRequired = false;

            if (!measureOnly && !ProjectionStack.Begun && Options.TransformToViewport != null)
            {
                GL.PushMatrix();
                popRequired = true;
                GL.Scale(1 / fontData.scaleDueToTransformToViewport, 1 / fontData.scaleDueToTransformToViewport, 0);
            }

            float maxMeasuredWidth = 0f;

            if (!measureOnly)
            {
                GL.Color4(1.0f, 1.0f, 1.0f, 1.0f);
                GL.Enable(EnableCap.Texture2D);
                GL.Enable(EnableCap.Blend);


                if (Options.UseDefaultBlendFunction)
                {
                    GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);
                }
            }


            float maxWidth  = processedText.maxWidth;
            var   alignment = processedText.alignment;


            //TODO - use these instead of translate when rendering by position (at some point)
            float xPos = 0f;
            float yPos = 0f;


            float xOffset = xPos;
            float yOffset = yPos;

            var nodeList = processedText.textNodeList;

            for (TextNode node = nodeList.Head; node != null; node = node.Next)
            {
                node.LengthTweak = 0f;  //reset tweaks
            }
            if (alignment == QFontAlignment.Right)
            {
                xOffset -= (float)Math.Ceiling(TextNodeLineLength(nodeList.Head, maxWidth) - maxWidth);
            }
            else if (alignment == QFontAlignment.Centre)
            {
                xOffset -= (float)Math.Ceiling(0.5f * TextNodeLineLength(nodeList.Head, maxWidth));
            }
            else if (alignment == QFontAlignment.Justify)
            {
                JustifyLine(nodeList.Head, maxWidth);
            }



            bool  atLeastOneNodeCosumedOnLine = false;
            float length = 0f;

            for (TextNode node = nodeList.Head; node != null; node = node.Next)
            {
                bool newLine = false;

                if (node.Type == TextNodeType.LineBreak)
                {
                    newLine = true;
                }
                else
                {
                    if (SkipTrailingSpace(node, length, maxWidth) && atLeastOneNodeCosumedOnLine)
                    {
                        newLine = true;
                    }
                    else if (length + node.ModifiedLength <= maxWidth || !atLeastOneNodeCosumedOnLine)
                    {
                        atLeastOneNodeCosumedOnLine = true;
                        if (!measureOnly)
                        {
                            RenderWord(xOffset + length, yOffset, node);
                        }
                        length += node.ModifiedLength;

                        maxMeasuredWidth = Math.Max(length, maxMeasuredWidth);
                    }
                    else
                    {
                        newLine = true;
                        if (node.Previous != null)
                        {
                            node = node.Previous;
                        }
                    }
                }

                if (newLine)
                {
                    yOffset += LineSpacing;
                    xOffset  = xPos;
                    length   = 0f;
                    atLeastOneNodeCosumedOnLine = false;

                    if (node.Next != null)
                    {
                        if (alignment == QFontAlignment.Right)
                        {
                            xOffset -= (float)Math.Ceiling(TextNodeLineLength(node.Next, maxWidth) - maxWidth);
                        }
                        else if (alignment == QFontAlignment.Centre)
                        {
                            xOffset -= (float)Math.Ceiling(0.5f * TextNodeLineLength(node.Next, maxWidth));
                        }
                        else if (alignment == QFontAlignment.Justify)
                        {
                            JustifyLine(node.Next, maxWidth);
                        }
                    }
                }
            }


            if (popRequired)
            {
                GL.PopMatrix();
            }


            return(new SizeF(maxMeasuredWidth, yOffset + LineSpacing - yPos));
        }
Ejemplo n.º 14
0
        /// <summary>
        /// Computes the length of the next line, and whether the line is valid for
        /// justification.
        /// </summary>
        /// <param name="node"></param>
        /// <param name="maxLength"></param>
        /// <param name="justifable"></param>
        /// <returns></returns>
        private float TextNodeLineLength(TextNode node, float maxLength)
        {
            if (node == null)
                return 0;

            bool atLeastOneNodeCosumedOnLine = false;
            float length = 0;
            for (; node != null; node = node.Next)
            {

                if (node.Type == TextNodeType.LineBreak)
                    break;

                if (SkipTrailingSpace(node, length, maxLength) && atLeastOneNodeCosumedOnLine)
                    break;

                if (length + node.Length <= maxLength || !atLeastOneNodeCosumedOnLine)
                {
                    atLeastOneNodeCosumedOnLine = true;
                    length += node.Length;
                }
                else
                {
                    break;
                }

            }
            return length;
        }
Ejemplo n.º 15
0
        /// <summary>
        /// Splits a word into sub-words of size less than or equal to baseCaseSize 
        /// </summary>
        /// <param name="node"></param>
        /// <param name="baseCaseSize"></param>
        public void Crumble(TextNode node, int baseCaseSize)
        {
            //base case
            if(node.Text.Length <= baseCaseSize )
                return;

            var left = SplitNode(node);
            var right = left.Next;

            Crumble(left,baseCaseSize);
            Crumble(right,baseCaseSize);
        }
Ejemplo n.º 16
0
 private bool CrumbledWord(TextNode node)
 {
     return (node.Type == TextNodeType.Word && node.Next != null && node.Next.Type == TextNodeType.Word);
 }
Ejemplo n.º 17
0
        /// <summary>
        /// Splits a word node in two, adding both new nodes to the list in sequence.
        /// </summary>
        /// <param name="node"></param>
        /// <returns>The first new node</returns>
        public TextNode SplitNode(TextNode node)
        {
            if (node.Type != TextNodeType.Word)
                throw new Exception("Cannot slit text node of type: " + node.Type);

            int midPoint = node.Text.Length / 2;

            string newFirstHalf = node.Text.Substring(0, midPoint);
            string newSecondHalf = node.Text.Substring(midPoint, node.Text.Length - midPoint);

            TextNode newFirst = new TextNode(TextNodeType.Word, newFirstHalf);
            TextNode newSecond = new TextNode(TextNodeType.Word, newSecondHalf);
            newFirst.Next = newSecond;
            newSecond.Previous = newFirst;

            //node is head
            if (node.Previous == null)
                Head = newFirst;
            else
            {
                node.Previous.Next = newFirst;
                newFirst.Previous = node.Previous;
            }

            //node is tail
            if (node.Next == null)
                Tail = newSecond;
            else
            {
                node.Next.Previous = newSecond;
                newSecond.Next = node.Next;
            }

            return newFirst;
        }
Ejemplo n.º 18
0
        /// <summary>
        /// Returns the kerning length correction for the character at the given index in the given string.
        /// Also, if the text is part of a textNode list, the nextNode is given so that the following 
        /// node can be checked incase of two adjacent word nodes.
        /// </summary>
        /// <param name="index"></param>
        /// <param name="text"></param>
        /// <param name="textNode"></param>
        /// <returns></returns>
        public int GetKerningPairCorrection(int index, string text, TextNode textNode)
        {
            if (KerningPairs == null)
                return 0;

            var chars = new char[2];

            if (index + 1 == text.Length)
            {
                if (textNode != null && textNode.Next != null && textNode.Next.Type == TextNodeType.Word)
                    chars[1] = textNode.Next.Text[0];
                else
                    return 0;
            }
            else
            {
                chars[1] = text[index + 1];
            }

            chars[0] = text[index];

            String str = new String(chars);

            if (KerningPairs.ContainsKey(str))
                return KerningPairs[str];

            return 0;
        }
Ejemplo n.º 19
0
        private SizeF PrintOrMeasure(ProcessedText processedText, bool measureOnly)
        {
            float maxWidth = 0f;

            if (!measureOnly)
            {
                GL.Color4(1.0f, 1.0f, 1.0f, 1.0f);
                GL.Enable(EnableCap.Texture2D);
                GL.Enable(EnableCap.Blend);
                GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);
            }


            var bounds    = processedText.bounds;
            var alignment = processedText.alignment;

            float xOffset = bounds.X;
            float yOffset = bounds.Y;

            var nodeList = processedText.textNodeList;

            for (TextNode node = nodeList.Head; node != null; node = node.Next)
            {
                node.LengthTweak = 0f;  //reset tweaks
            }
            if (alignment == QFontAlignment.Right)
            {
                xOffset -= (float)Math.Ceiling(TextNodeLineLength(nodeList.Head, bounds.Width) - bounds.Width);
            }
            else if (alignment == QFontAlignment.Centre)
            {
                xOffset -= (float)Math.Ceiling(0.5f * TextNodeLineLength(nodeList.Head, bounds.Width) - bounds.Width * 0.5f);
            }
            else if (alignment == QFontAlignment.Justify)
            {
                JustifyLine(nodeList.Head, bounds.Width);
            }



            bool  atLeastOneNodeCosumedOnLine = false;
            float length = 0f;

            for (TextNode node = nodeList.Head; node != null; node = node.Next)
            {
                bool newLine = false;

                if (node.Type == TextNodeType.LineBreak)
                {
                    newLine = true;
                }
                else
                {
                    if (SkipTrailingSpace(node, length, bounds.Width) && atLeastOneNodeCosumedOnLine)
                    {
                        newLine = true;
                    }
                    else if (length + node.ModifiedLength <= bounds.Width || !atLeastOneNodeCosumedOnLine)
                    {
                        atLeastOneNodeCosumedOnLine = true;
                        if (!measureOnly)
                        {
                            RenderWord(xOffset + length, yOffset, node);
                        }
                        length += node.ModifiedLength;

                        maxWidth = Math.Max(length, maxWidth);
                    }
                    else
                    {
                        newLine = true;
                        if (node.Previous != null)
                        {
                            node = node.Previous;
                        }
                    }
                }

                if (newLine)
                {
                    yOffset += LineSpacing;
                    xOffset  = bounds.X;
                    length   = 0f;
                    atLeastOneNodeCosumedOnLine = false;

                    if (node.Next != null)
                    {
                        if (alignment == QFontAlignment.Right)
                        {
                            xOffset -= (float)Math.Ceiling(TextNodeLineLength(node.Next, bounds.Width) - bounds.Width);
                        }
                        else if (alignment == QFontAlignment.Centre)
                        {
                            xOffset -= (float)Math.Ceiling(0.5f * TextNodeLineLength(node.Next, bounds.Width) - bounds.Width * 0.5f);
                        }
                        else if (alignment == QFontAlignment.Justify)
                        {
                            JustifyLine(node.Next, bounds.Width);
                        }
                    }
                }
            }


            return(new SizeF(maxWidth, yOffset + LineSpacing - bounds.Y));
        }