Пример #1
0
        UGlyphRun BuildGlyphRun(int start, int length, UStyleRange currentStyle, UText text, BreakType bt)
        {
            FontClass useFont = Translate(currentStyle == null ? text.font : currentStyle.fontOverride ?? text.font);

            var gr = new UGlyphRun()
            {
                startPosition = start,
                runLength     = length,
                breakingType  = bt,
                drawStyle     = currentStyle,
                charSizes     = new Size[length]
            };

            float tw = 0;

            gr.content = gr.runLength > 0 ? text.text.Substring(gr.startPosition, gr.runLength) : "";
            gr.runSize = MeasureString(text, gr.content, useFont);
            if (bt == BreakType.word)
            {
                // handle space spacing ;)
                String ltx = gr.startPosition > 0 ? text.text.Substring(gr.startPosition - 1, 1) : "";
                String rtx = gr.startPosition + length < text.text.Length ? text.text.Substring(length, 1) : "";
                var    s1  = MeasureString(text, ltx + gr.content + rtx, useFont);
                var    s2  = MeasureString(text, ltx + rtx, useFont);
                gr.runSize.width = s1.width - s2.width;
            }
            for (int i = 0; i < gr.content.Length; i++)
            {
                gr.charSizes[i] = MeasureString(text, gr.content.Substring(i, 1), useFont);
                tw += gr.charSizes[i].width;
            }
            float corr = gr.runSize.width / tw;

            for (int i = 0; i < gr.content.Length; i++)
            {
                gr.charSizes[i].width *= corr;
            }

            return(gr);
        }
Пример #2
0
        // FIXME Cache!! (most importantly)
        public UTextGlyphingInfo GetTextInfo(UText text)
        {
            // gotta do a line or end before we can decide the char tops (baseline aligned, presumably...)
            float             currX = 0, currY = 0, maxGlyphHeight = 0;
            int               lglst         = 0;  // last glyphrun line start
            int               lastWordBreak = -1; // last wordbreaking glyph on the current line
            int               currLine      = 0;
            UTextGlyphingInfo ret           = new UTextGlyphingInfo();

            // begin on assumption we're top left align..then correct after
            UGlyphRun lastGr = null;

            foreach (var gr in GetGlyphRuns(text))
            {
                // tracking max height for the line baselineing
                maxGlyphHeight = Math.Max(gr.runSize.height, maxGlyphHeight);
                // whichever way, this line is this many chars longer

                // Potential runs include words, spaces and linebreaks, and font breaks
                if (gr.breakingType == BreakType.line)
                {//LineBreaking
                    // add the glyphrun, resolve info for the line, and begin on new line!
                    ret.glyphRuns.Add(new UGlyphRunLayoutInfo()
                    {
                        lineNumber = currLine,
                        location   = new Point(currX, 0), // dunno about y position yet
                        run        = gr
                    });

                    currY         += maxGlyphHeight;
                    maxGlyphHeight = 0;
                    lastWordBreak  = -1;
                    float xAlighnShifty = GetShift(text.width, (currX + gr.runSize.width), text.halign);
                    currX = 0;

                    // resolving the glyphruns of this line
                    do
                    {
                        var igr = ret.glyphRuns[lglst];
                        igr.location = new Point(igr.location.X + xAlighnShifty, currY - igr.run.runSize.height);
                    } while (++lglst < ret.glyphRuns.Count);

                    // begin a new line
                    currLine++;
                }
                else if (lastWordBreak > -1 && currX + gr.runSize.width > text.width && text.wrapped)
                {// WordWrapping
                    // Must define the concept of glyph groups here.  Those between line and/or word breaks.
                    // The whole of such a group must be broken.  We need to define the breaking glyph.
                    currY         += maxGlyphHeight;
                    maxGlyphHeight = 0;
                    currX          = 0;
                    // #1 Is there a word break previous to this glyphrun on this line?
                    //    then put all glyphs following that on the next line.
                    for (int i = lastWordBreak + 1; i < ret.glyphRuns.Count; i++)
                    {
                        ret.glyphRuns[i].lineNumber++;
                        ret.glyphRuns[i].location = new Point(currX, 0);
                    }
                    lastWordBreak = -1;
                    currLine++;

                    // Is this glyphrun a wordbreak? who cares, next iteration will take care via #1.
                    // Not wordbreak? no prev worbreak? who cares, carry on.
                    ret.glyphRuns.Add(new UGlyphRunLayoutInfo()
                    {
                        lineNumber = currLine,
                        location   = new Point(currX, 0), // dunno about y position yet
                        run        = gr
                    });

                    // resolving the glyphruns of the last line
                    do
                    {
                        var igr = ret.glyphRuns[lglst];
                        igr.location = new Point(igr.location.X, currY - igr.run.runSize.height);
                    } while (++lglst <= lastWordBreak);
                    lastGr = gr;
                }
                else
                {// Buisness as Normal
                    // add glyphrun, increment currX
                    ret.glyphRuns.Add(new UGlyphRunLayoutInfo()
                    {
                        lineNumber = currLine,
                        location   = new Point(currX, 0),
                        run        = gr
                    });
                    if (gr.breakingType == BreakType.word)
                    {
                        lastWordBreak = ret.glyphRuns.Count - 1;
                    }
                    currX += gr.runSize.width;
                }
            }
            currY         += maxGlyphHeight;
            maxGlyphHeight = 0;
            lastWordBreak  = -1;
            float lastXShift = GetShift(text.width, (currX + (lastGr == null ? 0 :lastGr.runSize.width)), text.halign);

            currX = 0;
            // resolving the glyphruns of the final line
            for (; lglst < ret.glyphRuns.Count; lglst++)
            {
                var igr = ret.glyphRuns[lglst];
                igr.location.Y  = currY - igr.run.runSize.height;
                igr.location.X += lastXShift;
            }

            float yAlignShifty = GetShift(text.height, currY, text.valign);

            // assign the linelengths to textinfo and do y alignment
            int   cl = 0; int cc = 0; int cnl = 0;
            float cx = 0, cy = 0, maxy = 0, maxx = 0;

            for (int i = 0; i < ret.glyphRuns.Count; i++)
            {
                var gri = ret.glyphRuns[i];
                gri.location.Y += yAlignShifty;
                if (gri.lineNumber > cl)
                {
                    // add lineinfo (and reset counters)
                    cl = gri.lineNumber;
                    ret.lineLengths.Add(cc);
                    ret.newLineLengths.Add(cl);
                    ret.lineSizes.Add(new Size(cx, maxy));
                    cc   = cnl = 0;
                    cy  += maxy;
                    maxx = Math.Max(maxx, cx);
                    maxy = cx = 0;
                }

                // Continue adding lineinfo data
                cc += gri.run.runLength;
                cx += gri.run.runSize.width;
                if (gri.run.breakingType == BreakType.line)
                {
                    cnl += gri.run.runLength;
                }
                maxy = Math.Max(gri.run.runSize.height, maxy);
            }
            ret.minSize = new Size(maxx, cy);
            return(ret);
        }