Setup() abstract private méthode

abstract private Setup ( Graphics graphics, bool fill ) : void
graphics Graphics
fill bool
Résultat void
Exemple #1
0
 public void FillEllipse(Brush brush, RectangleF rect)
 {
     if (brush == null)
     {
         throw new ArgumentNullException("brush");
     }
     brush.Setup(this, true);
     context.FillEllipseInRect(rect);
 }
Exemple #2
0
 void FillBrush(Brush brush, FillMode fillMode = FillMode.Alternate)
 {
     brush.Setup(this, true);
     if (fillMode == FillMode.Alternate)
     {
         context.EOFillPath();
     }
     else
     {
         context.FillPath();
     }
 }
Exemple #3
0
        internal void Setup(Graphics graphics, bool fill)
        {
            brush.Setup(graphics, fill);
            // TODO: apply matrix

            if (graphics.LastPen == this && !changed)
            {
                return;
            }

            graphics.context.SetLineWidth(width);
            // miter limit
            // join
            // cap
            // dashes

            changed          = false;
            graphics.LastPen = this;
        }
Exemple #4
0
        internal DrawStringCache.Entry CreateCacheEntry(string s, Font font, Brush brush, RectangleF layoutRectangle, StringFormat format)
        {
            if (font == null)
            {
                throw new ArgumentNullException(nameof(font));
            }
            if (brush == null)
            {
                throw new ArgumentNullException(nameof(brush));
            }

            layoutRectangle.Location = PointF.Empty;
            var c = new DrawStringCache.Entry(s, font, brush, layoutRectangle, format);

            brush.Setup(this, false);             // Stroke
            var attributedString = buildAttributedString(s, font, format, lastBrushColor);

            // Work out the geometry
            c.layoutAvailable = true;
            var insetBounds = layoutRectangle;

            if (insetBounds.Size == SizeF.Empty)
            {
                insetBounds.Width  = float.MaxValue;
                insetBounds.Height = float.MaxValue;
                c.layoutAvailable  = false;
            }

            c.lineHeight     = font.nativeFont.GetLineHeight();
            c.lines          = new List <CTLine>();
            c.verticalMatrix = default(CGAffineTransform);

            // Calculate the lines
            // If we are drawing vertical direction then we need to rotate our context transform by 90 degrees
            if ((format.FormatFlags & StringFormatFlags.DirectionVertical) == StringFormatFlags.DirectionVertical)
            {
                // Swap out the width and height and calculate the lines
                c.lines        = CreateLines(font, attributedString, new SizeF(insetBounds.Height, insetBounds.Width), format, c.lineHeight);
                c.boundsWidth  = insetBounds.Height;
                c.boundsHeight = insetBounds.Width;
            }
            else
            {
                c.lines        = CreateLines(font, attributedString, insetBounds.Size, format, c.lineHeight);
                c.boundsWidth  = insetBounds.Width;
                c.boundsHeight = insetBounds.Height;
            }

            c.textPosition = new PointF(insetBounds.X + .5f, insetBounds.Y + .5f);
            if (c.layoutAvailable)
            {
                if (format.LineAlignment == StringAlignment.Far)
                {
                    c.textPosition.Y += c.boundsHeight - (c.lines.Count * c.lineHeight);
                }
                else if (format.LineAlignment == StringAlignment.Center)
                {
                    c.textPosition.Y += (c.boundsHeight - (c.lines.Count * c.lineHeight)) / 2;
                }
            }
            else
            {
                // Precalculate maximum width to allow for aligning lines
                if (format.Alignment != StringAlignment.Near)
                {
                    float maxLineWidth = 0;
                    foreach (var line in c.lines)
                    {
                        if (line != null)
                        {
                            nfloat ascent, descent, leading;
                            var    lineWidth = line.GetTypographicBounds(out ascent, out descent, out leading);
                            if ((format.FormatFlags & StringFormatFlags.MeasureTrailingSpaces) != 0)
                            {
                                lineWidth += line.TrailingWhitespaceWidth;
                            }
                            maxLineWidth = Math.Max(maxLineWidth, (float)NMath.Ceiling((float)lineWidth));
                        }
                    }
                    c.boundsWidth = maxLineWidth;
                }
                if (format.LineAlignment == StringAlignment.Far)
                {
                    c.textPosition.Y -= c.lineHeight * c.lines.Count;
                }
                else if (format.LineAlignment == StringAlignment.Center)
                {
                    c.textPosition.Y -= (c.lineHeight * c.lines.Count) / 2;
                }
            }
            return(c);
        }
        public void DrawString(string s, Font font, Brush brush, RectangleF layoutRectangle, StringFormat format = null)
        {
            if (font == null)
                throw new ArgumentNullException ("font");
            if (brush == null)
                throw new ArgumentNullException ("brush");
            if (s == null || s.Length == 0)
                return;

            if (format == null)
            {
                format = StringFormat.GenericDefault;
            }

            // TODO: Take into consideration units

            // Not sure we need the Save and Restore around this yet.
            context.SaveState();

            // TextMatrix is not part of the Graphics State and Restore
            var saveMatrix = context.TextMatrix;
            bool layoutAvailable = true;

            //			context.SelectFont ( font.nativeFont.PostScriptName,
            //			                    font.SizeInPoints,
            //			                    CGTextEncoding.MacRoman);
            //
            //			context.SetCharacterSpacing(1);
            //			context.SetTextDrawingMode(CGTextDrawingMode.Fill); // 5
            //
            //			// Setup both the stroke and the fill ?
            //			brush.Setup(this, true);
            //			brush.Setup(this, false);
            //
            //			var textMatrix = font.nativeFont.Matrix;
            //
            //			textMatrix.Scale(1,-1);
            //			context.TextMatrix = textMatrix;
            //
            //			context.ShowTextAtPoint(layoutRectangle.X,
            //			                        layoutRectangle.Y + font.nativeFont.CapHeightMetric, s);
            //
            //
            // First we call the brush with a fill of false so the brush can setup the stroke color
            // that the text will be using.
            // For LinearGradientBrush this will setup a TransparentLayer so the gradient can
            // be filled at the end.  See comments.
            brush.Setup(this, false); // Stroke

            // I think we only Fill the text with no Stroke surrounding
            context.SetTextDrawingMode(CGTextDrawingMode.Fill);

            var attributedString = buildAttributedString(s, font, format, lastBrushColor);

            // Work out the geometry
            RectangleF insetBounds = layoutRectangle;
            if (insetBounds.Size == SizeF.Empty)
            {
                insetBounds.Width = boundingBox.Width;
                insetBounds.Height = boundingBox.Height;
                layoutAvailable = false;
            }

            PointF textPosition = new PointF(insetBounds.X,
                                             insetBounds.Y);

            float boundsWidth = insetBounds.Width;

            // Calculate the lines
            int start = 0;
            int length = attributedString.Length;
            float baselineOffset = 0;

            var typesetter = new CTTypesetter(attributedString);

            // First we need to calculate the offset for Vertical Alignment if we
            // are using anything but Top
            if (layoutAvailable && format.LineAlignment != StringAlignment.Near) {
                while (start < length) {
                    int count = typesetter.SuggestLineBreak (start, boundsWidth);
                    var line = typesetter.GetLine (new NSRange(start, count));

                    // Create and initialize some values from the bounds.
                    float ascent;
                    float descent;
                    float leading;
                    line.GetTypographicBounds (out ascent, out descent, out leading);
                    baselineOffset += (float)Math.Ceiling (ascent + descent + leading + 1); // +1 matches best to CTFramesetter's behavior
                    line.Dispose ();
                    start += count;
                }

                //textPosition.Y += baselineOffset;
            }

            // If we are drawing vertial direction then we need to rotate our context transform by 90 degrees
            if ((format.FormatFlags & StringFormatFlags.DirectionVertical) == StringFormatFlags.DirectionVertical)
            {
                //textMatrix.Rotate (ConversionHelpers.DegreesToRadians (90));
                var verticalOffset = 0.0f;
                while (start < length) {
                    int count = typesetter.SuggestLineBreak (start, boundsWidth);
                    var line = typesetter.GetLine (new NSRange(start, count));

                    // Create and initialize some values from the bounds.
                    float ascent;
                    float descent;
                    float leading;
                    line.GetTypographicBounds (out ascent, out descent, out leading);
                    verticalOffset += (float)Math.Ceiling (ascent + descent + leading + 1); // +1 matches best to CTFramesetter's behavior
                    line.Dispose ();
                    start += count;
                }
                context.TranslateCTM (layoutRectangle.X, layoutRectangle.Y);
                context.RotateCTM (ConversionHelpers.DegreesToRadians (90));
                context.TranslateCTM (-layoutRectangle.X, -layoutRectangle.Y);
                context.TranslateCTM (0, -verticalOffset);
                start = 0;
            }

            start = 0;
            while (start < length && textPosition.Y < insetBounds.Bottom)
            {

                // Now we ask the typesetter to break off a line for us.
                // This also will take into account line feeds embedded in the text.
                //  Example: "This is text \n with a line feed embedded inside it"
                int count = typesetter.SuggestLineBreak(start, boundsWidth);
                var line = typesetter.GetLine(new NSRange(start, count));

                // Create and initialize some values from the bounds.
                float ascent;
                float descent;
                float leading;
                double lineWidth = line.GetTypographicBounds(out ascent, out descent, out leading);

                // Calculate the string format if need be
                var penFlushness = 0.0f;
                if (format != null)
                {
                    if (layoutAvailable)
                    {
                        if (format.Alignment == StringAlignment.Far)
                            penFlushness = (float)line.GetPenOffsetForFlush(1.0f, boundsWidth);
                        else if (format.Alignment == StringAlignment.Center)
                            penFlushness = (float)line.GetPenOffsetForFlush(0.5f, boundsWidth);
                    }
                    else
                    {
                        // We were only passed in a point so we need to format based
                        // on the point.
                        if (format.Alignment == StringAlignment.Far)
                            penFlushness -= (float)lineWidth;
                        else if (format.Alignment == StringAlignment.Center)
                            penFlushness -= (float)lineWidth / 2.0f;

                    }

                }

                // initialize our Text Matrix or we could get trash in here
                var textMatrix = new CGAffineTransform (
                    1, 0, 0, -1, 0, ascent);

                if (format.LineAlignment == StringAlignment.Near)
                    textMatrix.Translate (penFlushness + textPosition.X, textPosition.Y);
                if (format.LineAlignment == StringAlignment.Center)
                    textMatrix.Translate (penFlushness + textPosition.X, textPosition.Y + ((insetBounds.Height / 2) - (baselineOffset / 2)) );
                if (format.LineAlignment == StringAlignment.Far)
                    textMatrix.Translate(penFlushness + textPosition.X,  textPosition.Y + ((insetBounds.Height) - (baselineOffset)));

                context.TextMatrix = textMatrix;

                // and draw the line
                line.Draw(context);

                // Move the index beyond the line break.
                start += count;
                textPosition.Y += (float)Math.Ceiling(ascent + descent + leading + 1); // +1 matches best to CTFramesetter's behavior
                line.Dispose();

            }

            // Now we call the brush with a fill of true so the brush can do the fill if need be
            // For LinearGradientBrush this will draw the Gradient and end the TransparentLayer.
            // See comments.
            brush.Setup(this, true); // Fill

            context.TextMatrix = saveMatrix;
            context.RestoreState();
        }
 void FillBrush(Brush brush, FillMode fillMode = FillMode.Alternate)
 {
     brush.Setup (this, true);
     if (fillMode == FillMode.Alternate)
         context.EOFillPath ();
     else
         context.FillPath ();
 }
Exemple #7
0
        public void DrawString(string s, Font font, Brush brush, RectangleF layoutRectangle, StringFormat format = null)
        {
            if (font == null)
            {
                throw new ArgumentNullException("font");
            }
            if (brush == null)
            {
                throw new ArgumentNullException("brush");
            }
            if (s == null || s.Length == 0)
            {
                return;
            }

            if (format == null)
            {
                format = StringFormat.GenericDefault;
            }

            // TODO: Take into consideration units

            // Not sure we need the Save and Restore around this yet.
            context.SaveState();

            // TextMatrix is not part of the Graphics State and Restore
            var  saveMatrix      = context.TextMatrix;
            bool layoutAvailable = true;

            //			context.SelectFont ( font.nativeFont.PostScriptName,
            //			                    font.SizeInPoints,
            //			                    CGTextEncoding.MacRoman);
            //
            //			context.SetCharacterSpacing(1);
            //			context.SetTextDrawingMode(CGTextDrawingMode.Fill); // 5
            //
            //			// Setup both the stroke and the fill ?
            //			brush.Setup(this, true);
            //			brush.Setup(this, false);
            //
            //			var textMatrix = font.nativeFont.Matrix;
            //
            //			textMatrix.Scale(1,-1);
            //			context.TextMatrix = textMatrix;
            //
            //			context.ShowTextAtPoint(layoutRectangle.X,
            //			                        layoutRectangle.Y + font.nativeFont.CapHeightMetric, s);
            //
            //
            // First we call the brush with a fill of false so the brush can setup the stroke color
            // that the text will be using.
            // For LinearGradientBrush this will setup a TransparentLayer so the gradient can
            // be filled at the end.  See comments.
            brush.Setup(this, false);             // Stroke

            // I think we only Fill the text with no Stroke surrounding
            context.SetTextDrawingMode(CGTextDrawingMode.Fill);

            var attributedString = buildAttributedString(s, font, format, lastBrushColor);

            // Work out the geometry
            RectangleF insetBounds = layoutRectangle;

            if (insetBounds.Size == SizeF.Empty)
            {
                insetBounds.Width  = boundingBox.Width;
                insetBounds.Height = boundingBox.Height;
                layoutAvailable    = false;

                if (format.LineAlignment != StringAlignment.Near)
                {
                    insetBounds.Size = MeasureString(s, font);
                }
            }

            PointF textPosition = new PointF(insetBounds.X,
                                             insetBounds.Y);

            float boundsWidth = insetBounds.Width;

            // Calculate the lines
            int   start          = 0;
            int   length         = (int)attributedString.Length;
            float baselineOffset = 0;

            var typesetter = new CTTypesetter(attributedString);

            // First we need to calculate the offset for Vertical Alignment if we
            // are using anything but Top
            if (layoutAvailable && format.LineAlignment != StringAlignment.Near)
            {
                while (start < length)
                {
                    int count = (int)typesetter.SuggestLineBreak(start, boundsWidth);
                    var line  = typesetter.GetLine(new NSRange(start, count));

                    // Create and initialize some values from the bounds.
                    nfloat ascent;
                    nfloat descent;
                    nfloat leading;
                    line.GetTypographicBounds(out ascent, out descent, out leading);
                    baselineOffset += (float)Math.Ceiling(ascent + descent + leading + 1);                      // +1 matches best to CTFramesetter's behavior
                    line.Dispose();
                    start += count;
                }

                start = 0;
            }

            // If we are drawing vertial direction then we need to rotate our context transform by 90 degrees
            if ((format.FormatFlags & StringFormatFlags.DirectionVertical) == StringFormatFlags.DirectionVertical)
            {
                //textMatrix.Rotate (ConversionHelpers.DegreesToRadians (90));
                var verticalOffset = 0.0f;
                while (start < length)
                {
                    int count = (int)typesetter.SuggestLineBreak(start, boundsWidth);
                    var line  = typesetter.GetLine(new NSRange(start, count));

                    // Create and initialize some values from the bounds.
                    nfloat ascent;
                    nfloat descent;
                    nfloat leading;
                    line.GetTypographicBounds(out ascent, out descent, out leading);
                    verticalOffset += (float)Math.Ceiling(ascent + descent + leading + 1);                      // +1 matches best to CTFramesetter's behavior
                    line.Dispose();
                    start += count;
                }
                context.TranslateCTM(layoutRectangle.X, layoutRectangle.Y);
                context.RotateCTM(ConversionHelpers.DegreesToRadians(90));
                context.TranslateCTM(-layoutRectangle.X, -layoutRectangle.Y);
                context.TranslateCTM(0, -verticalOffset);
                start = 0;
            }

            start = 0;
            while (start < length && textPosition.Y < insetBounds.Bottom)
            {
                // Now we ask the typesetter to break off a line for us.
                // This also will take into account line feeds embedded in the text.
                //  Example: "This is text \n with a line feed embedded inside it"
                int count = (int)typesetter.SuggestLineBreak(start, boundsWidth);
                var line  = typesetter.GetLine(new NSRange(start, count));

                // Create and initialize some values from the bounds.
                nfloat ascent;
                nfloat descent;
                nfloat leading;
                double lineWidth = line.GetTypographicBounds(out ascent, out descent, out leading);

                // Calculate the string format if need be
                var penFlushness = 0.0f;
                if (format != null)
                {
                    if (layoutAvailable)
                    {
                        if (format.Alignment == StringAlignment.Far)
                        {
                            penFlushness = (float)line.GetPenOffsetForFlush(1.0f, boundsWidth);
                        }
                        else if (format.Alignment == StringAlignment.Center)
                        {
                            penFlushness = (float)line.GetPenOffsetForFlush(0.5f, boundsWidth);
                        }
                    }
                    else
                    {
                        // We were only passed in a point so we need to format based
                        // on the point.
                        if (format.Alignment == StringAlignment.Far)
                        {
                            penFlushness -= (float)lineWidth;
                        }
                        else if (format.Alignment == StringAlignment.Center)
                        {
                            penFlushness -= (float)lineWidth / 2.0f;
                        }
                    }
                }

                // initialize our Text Matrix or we could get trash in here
                var textMatrix = new CGAffineTransform(
                    1, 0, 0, -1, 0, ascent);

                if (format.LineAlignment == StringAlignment.Near)
                {
                    textMatrix.Translate(penFlushness + textPosition.X, textPosition.Y);
                }
                if (format.LineAlignment == StringAlignment.Center)
                {
                    if (layoutAvailable)
                    {
                        textMatrix.Translate(penFlushness + textPosition.X, textPosition.Y + ((insetBounds.Height / 2) - (baselineOffset / 2)));
                    }
                    else
                    {
                        textMatrix.Translate(penFlushness + textPosition.X, textPosition.Y - ((insetBounds.Height / 2) - (baselineOffset / 2)));
                    }
                }

                if (format.LineAlignment == StringAlignment.Far)
                {
                    if (layoutAvailable)
                    {
                        textMatrix.Translate(penFlushness + textPosition.X, textPosition.Y + ((insetBounds.Height) - (baselineOffset)));
                    }
                    else
                    {
                        textMatrix.Translate(penFlushness + textPosition.X, textPosition.Y - ((insetBounds.Height) - (baselineOffset)));
                    }
                }

                context.TextMatrix = textMatrix;

                // and draw the line
                line.Draw(context);

                // Move the index beyond the line break.
                start          += count;
                textPosition.Y += (float)Math.Ceiling(ascent + descent + leading + 1);                 // +1 matches best to CTFramesetter's behavior
                line.Dispose();
            }

            // Now we call the brush with a fill of true so the brush can do the fill if need be
            // For LinearGradientBrush this will draw the Gradient and end the TransparentLayer.
            // See comments.
            brush.Setup(this, true);             // Fill

            context.TextMatrix = saveMatrix;
            context.RestoreState();
        }
Exemple #8
0
        internal void Setup(Graphics graphics, bool fill)
        {
            CGContext context = graphics.context;

            brush.Setup(graphics, fill);
            // TODO: apply matrix

            if (graphics.LastPen == this && !changed)
            {
                return;
            }


            //  A Width of 0 will result in the Pen drawing as if the Width were 1.
            width = width == 0 ? 1 : width;
            //width = graphics.GraphicsUnitConvertFloat (width);

            context.SetLineWidth(width);

            switch (startCap)
            {
            case LineCap.Flat:
                context.SetLineCap(width > 1f || dashStyle != DashStyle.Solid ? CGLineCap.Butt : CGLineCap.Square);
                break;

            case LineCap.Square:
                context.SetLineCap(CGLineCap.Square);
                break;

            case LineCap.Round:
                context.SetLineCap(CGLineCap.Round);
                break;

//			case LineCap.Triangle:
//			case LineCap.NoAnchor:
//			case LineCap.SquareAnchor:
//			case LineCap.RoundAnchor:
//			case LineCap.DiamondAnchor:
//			case LineCap.ArrowAnchor:
//			case LineCap.AnchorMask:
//			case LineCap.Custom:
            default:
                context.SetLineCap(CGLineCap.Butt);
                break;
            }

            switch (dashStyle)
            {
            case DashStyle.Custom:
                context.SetLineDash(dashOffset, setupMorseCode(dashPattern));
                break;

            case DashStyle.Dash:
                context.SetLineDash(dashOffset, setupMorseCode(Dash));
                break;

            case DashStyle.Dot:
                context.SetLineDash(dashOffset, setupMorseCode(Dot));
                break;

            case DashStyle.DashDot:
                context.SetLineDash(dashOffset, setupMorseCode(DashDot));
                break;

            case DashStyle.DashDotDot:
                context.SetLineDash(dashOffset, setupMorseCode(DashDotDot));
                break;

            default:
                context.SetLineDash(0, new nfloat[0]);
                break;
            }
            // miter limit
            // join
            // cap
            // dashes

            changed          = false;
            graphics.LastPen = this;
        }
        public void DrawString(string s, Font font, Brush brush, RectangleF layoutRectangle, StringFormat format = null)
        {
            if (font == null)
            {
                throw new ArgumentNullException("font");
            }
            if (brush == null)
            {
                throw new ArgumentNullException("brush");
            }
            if (s == null || s.Length == 0)
            {
                return;
            }

            // TODO: Take into consideration units

            // Not sure we need the Save and Restore around this yet.
            context.SaveState();

            // TextMatrix is not part of the Graphics State and Restore
            var  saveMatrix      = context.TextMatrix;
            bool layoutAvailable = true;

            //			context.SelectFont ( font.nativeFont.PostScriptName,
            //			                    font.SizeInPoints,
            //			                    CGTextEncoding.MacRoman);
            //
            //			context.SetCharacterSpacing(1);
            //			context.SetTextDrawingMode(CGTextDrawingMode.Fill); // 5
            //
            //			// Setup both the stroke and the fill ?
            //			brush.Setup(this, true);
            //			brush.Setup(this, false);
            //
            //			var textMatrix = font.nativeFont.Matrix;
            //
            //			textMatrix.Scale(1,-1);
            //			context.TextMatrix = textMatrix;
            //
            //			context.ShowTextAtPoint(layoutRectangle.X,
            //			                        layoutRectangle.Y + font.nativeFont.CapHeightMetric, s);
            //
            //
            // First we call the brush with a fill of false so the brush can setup the stroke color
            // that the text will be using.
            // For LinearGradientBrush this will setup a TransparentLayer so the gradient can
            // be filled at the end.  See comments.
            brush.Setup(this, false);             // Stroke

            // I think we only Fill the text with no Stroke surrounding
            context.SetTextDrawingMode(CGTextDrawingMode.Fill);

            var attributedString = buildAttributedString(s, font, lastBrushColor);

            // Work out the geometry
            RectangleF insetBounds = layoutRectangle;

            if (insetBounds.Size == SizeF.Empty)
            {
                insetBounds.Width  = boundingBox.Width;
                insetBounds.Height = boundingBox.Height;
                layoutAvailable    = false;
            }

            PointF textPosition = new PointF(insetBounds.X,
                                             insetBounds.Y);

            float boundsWidth = insetBounds.Width;

            // Calculate the lines
            int start  = 0;
            int length = attributedString.Length;

            var typesetter = new CTTypesetter(attributedString);

            while (start < length && textPosition.Y < insetBounds.Bottom)
            {
                // Now we ask the typesetter to break off a line for us.
                // This also will take into account line feeds embedded in the text.
                //  Example: "This is text \n with a line feed embedded inside it"
                int count = typesetter.SuggestLineBreak(start, boundsWidth);
                var line  = typesetter.GetLine(new NSRange(start, count));

                // Create and initialize some values from the bounds.
                float  ascent;
                float  descent;
                float  leading;
                double lineWidth = line.GetTypographicBounds(out ascent, out descent, out leading);

                // Calculate the string format if need be
                var penFlushness = 0.0f;
                if (format != null)
                {
                    if (layoutAvailable)
                    {
                        if (format.Alignment == StringAlignment.Far)
                        {
                            penFlushness = (float)line.GetPenOffsetForFlush(1.0f, boundsWidth);
                        }
                        else if (format.Alignment == StringAlignment.Center)
                        {
                            penFlushness = (float)line.GetPenOffsetForFlush(0.5f, boundsWidth);
                        }
                    }
                    else
                    {
                        // We were only passed in a point so we need to format based
                        // on the point.
                        if (format.Alignment == StringAlignment.Far)
                        {
                            penFlushness -= (float)lineWidth;
                        }
                        else if (format.Alignment == StringAlignment.Center)
                        {
                            penFlushness -= (float)lineWidth / 2.0f;
                        }
                    }
                }

                // initialize our Text Matrix or we could get trash in here
                var textMatrix = CGAffineTransform.MakeIdentity();
                // flip us over or things just do not look good
                textMatrix.Scale(1, -1);
                context.TextMatrix = textMatrix;

                // move us to our graphics baseline
                var textViewPos = textPosition;
                textViewPos.Y += (float)Math.Floor(ascent - 1);

                // take into account our justification
                textViewPos.X += penFlushness;

                // setup our text position
                context.TextPosition = textViewPos;
                // and draw the line
                line.Draw(context);

                // Move the index beyond the line break.
                start          += count;
                textPosition.Y += (float)Math.Ceiling(ascent + descent + leading + 1);                 // +1 matches best to CTFramesetter's behavior
                line.Dispose();
            }

            // Now we call the brush with a fill of true so the brush can do the fill if need be
            // For LinearGradientBrush this will draw the Gradient and end the TransparentLayer.
            // See comments.
            brush.Setup(this, true);             // Fill

            context.TextMatrix = saveMatrix;
            context.RestoreState();
        }