コード例 #1
0
        internal void Draw(SKCanvas canvas, SKPoint origin)
        {
            SKPaint paint = Paint;

            /* TODO: This originated from Native code, it might be useful for debugging character positions as
             * we improve the FormattedText support. Will need to port this to C# obviously. Rmove when
             * not needed anymore.
             *
             *  SkPaint dpaint;
             *  ctx->Canvas->save();
             *  ctx->Canvas->translate(origin.fX, origin.fY);
             *  for (int c = 0; c < Lines.size(); c++)
             *  {
             *      dpaint.setARGB(255, 0, 0, 0);
             *      SkRect rc;
             *      rc.fLeft = 0;
             *      rc.fTop = Lines[c].Top;
             *      rc.fRight = Lines[c].Width;
             *      rc.fBottom = rc.fTop + LineOffset;
             *      ctx->Canvas->drawRect(rc, dpaint);
             *  }
             *  for (int c = 0; c < Length; c++)
             *  {
             *      dpaint.setARGB(255, c % 10 * 125 / 10 + 125, (c * 7) % 10 * 250 / 10, (c * 13) % 10 * 250 / 10);
             *      dpaint.setStyle(SkPaint::kFill_Style);
             *      ctx->Canvas->drawRect(Rects[c], dpaint);
             *  }
             *  ctx->Canvas->restore();
             */

            for (int c = 0; c < _skiaLines.Count; c++)
            {
                PerspexFormattedTextLine line = _skiaLines[c];
                var subString = _text.Substring(line.Start, line.Length);
                canvas.DrawText(subString, origin.X, origin.Y + line.Top + LineOffset, paint);
            }
        }
コード例 #2
0
        void Rebuild()
        {
            var length = _text.Length;

            _lines.Clear();

            _skiaRects = new SKRect[length];
            _skiaLines = new List <PerspexFormattedTextLine>();

            int   curOff = 0;
            float curY   = 0;

            var metrics  = Paint.FontMetrics;
            var mTop     = metrics.Top;     // The greatest distance above the baseline for any glyph (will be <= 0).
            var mBottom  = metrics.Bottom;  // The greatest distance below the baseline for any glyph (will be >= 0).
            var mLeading = metrics.Leading; // The recommended distance to add between lines of text (will be >= 0).

            // This seems like the best measure of full vertical extent
            float lineHeight = mBottom - mTop;

            // Rendering is relative to baseline
            LineOffset = -metrics.Top;

            string subString;

            byte[]   bytes;
            GCHandle pinnedArray;
            IntPtr   pointer;

            for (int c = 0; curOff < length; c++)
            {
                float lineWidth = -1;
                int   measured;
                int   extraSkip = 0;
                if (WidthConstraint <= 0)
                {
                    measured = length;
                }
                else
                {
                    float constraint = WidthConstraint;
                    if (constraint > MAX_LINE_WIDTH)
                    {
                        constraint = MAX_LINE_WIDTH;
                    }

                    subString = _text.Substring(curOff);

                    // TODO: This method is not linking into SkiaSharp so we must use the RAW buffer version for now
                    //measured = (int)Paint.BreakText(subString, constraint, out lineWidth) / 2;
                    bytes       = Encoding.UTF8.GetBytes(subString);
                    pinnedArray = GCHandle.Alloc(bytes, GCHandleType.Pinned);
                    pointer     = pinnedArray.AddrOfPinnedObject();
                    // for some reason I have to pass nBytes * 2. I assume under the hood it expects Unicode/WChar??
                    measured = (int)Paint.BreakText(pointer, (IntPtr)(bytes.Length * 2), constraint, out lineWidth) / 2;
                    pinnedArray.Free();

                    if (measured == 0)
                    {
                        measured  = 1;
                        lineWidth = -1;
                    }

                    char nextChar = ' ';
                    if (curOff + measured < length)
                    {
                        nextChar = _text[curOff + measured];
                    }

                    if (nextChar != ' ')
                    {
                        // Perform scan for the last space and end the line there
                        for (int si = curOff + measured - 1; si > curOff; si--)
                        {
                            if (_text[si] == ' ')
                            {
                                measured  = si - curOff;
                                extraSkip = 1;
                                break;
                            }
                        }
                    }
                }

                PerspexFormattedTextLine line = new PerspexFormattedTextLine();
                line.Start  = curOff;
                line.Length = measured;
                line.Width  = lineWidth;
                line.Height = lineHeight;
                line.Top    = curY;

                if (line.Width < 0)
                {
                    line.Width = _skiaRects[line.Start + line.Length - 1].Right;
                }

                // Build character rects
                for (int i = line.Start; i < line.Start + line.Length; i++)
                {
                    float prevRight = 0;
                    if (i != line.Start)
                    {
                        prevRight = _skiaRects[i - 1].Right;
                    }

                    subString = _text.Substring(line.Start, i - line.Start + 1);
                    float w = Paint.MeasureText(subString);

                    SKRect rc;
                    rc.Left       = prevRight;
                    rc.Right      = w;
                    rc.Top        = line.Top;
                    rc.Bottom     = line.Top + line.Height;
                    _skiaRects[i] = rc;
                }

                subString  = _text.Substring(line.Start, line.Length);
                line.Width = Paint.MeasureText(subString);

                _skiaLines.Add(line);

                curY += lineHeight;

                // TODO: We may want to consider adding Leading to the vertical line spacing but for now
                // it appears to make no difference. Revisit as part of FormattedText improvements.
                //
                //curY += mLeading;

                curOff += measured + extraSkip;
            }

            // Now convert to Perspex data formats
            _lines.Clear();
            _rects.Clear();
            float maxX = 0;

            for (var c = 0; c < _skiaLines.Count; c++)
            {
                var w = _skiaLines[c].Width;
                if (maxX < w)
                {
                    maxX = w;
                }

                _lines.Add(new FormattedTextLine(_skiaLines[c].Length, _skiaLines[c].Height));
            }

            for (var c = 0; c < _text.Length; c++)
            {
                _rects.Add(_skiaRects[c].ToPerspexRect());
            }

            if (_skiaLines.Count == 0)
            {
                _size = new Size();
            }
            else
            {
                var lastLine = _skiaLines[_skiaLines.Count - 1];
                _size = new Size(maxX, lastLine.Top + lastLine.Height);
            }
        }