예제 #1
0
파일: CTLine.cs 프로젝트: polipo/maccore
		public CTLine GetTruncatedLine (double width, CTLineTruncation truncationType, CTLine truncationToken)
		{
			var h = CTLineCreateTruncatedLine (Handle, width, truncationType,
					truncationToken == null ? IntPtr.Zero : truncationToken.Handle);
			if (h == IntPtr.Zero)
				return null;
			return new CTLine (h, true);
		}
예제 #2
0
 public override double GetBaseline(object backend)
 {
     LayoutInfo li = (LayoutInfo)backend;
     using (var line = new CTLine (CreateAttributedString (li))) {
         nfloat ascent, descent, leading;
         line.GetTypographicBounds (out ascent, out descent, out leading);
         return (double)ascent;
     }
 }
예제 #3
0
		public static ABC GetCharWidthABC(char ch, Font font, System.Drawing.Graphics gr)
		{
			ABC[] _temp = new ABC[1];
			var nativFont = CreateFont (font.Name, font.Size, font.Style, font.GdiCharSet, font.GdiVerticalFont);
			var atts = buildAttributedString(ch.ToString(), nativFont);
			// for now just a line not sure if this is going to work
			CTLine line = new CTLine(atts);

			float ascent;
			float descent;
			float leading;
			_temp[0].abcB = (uint)line.GetTypographicBounds(out ascent, out descent, out leading);


			return _temp[0];
		}
예제 #4
0
 static void PrepareGlyphArcInfo (CTLine line, long glyphCount, GlyphArcInfo[] glyphArcInfo)
 {
         var runArray = line.GetGlyphRuns ();
         
         // Examine each run in the line, updating glyphOffset to track how far along the run is 
         // in terms of glyphCount.
         long glyphOffset = 0;
         float ascent = 0;
         float descent = 0;
         float leading = 0;
         foreach (var run in runArray) {
                 var runGlyphCount = run.GlyphCount;
                 
                 // Ask for the width of each glyph in turn.
                 var runGlyphIndex = 0;
                 for (; runGlyphIndex < runGlyphCount; runGlyphIndex++) {
                         glyphArcInfo[runGlyphIndex + glyphOffset].width = (float)run.GetTypographicBounds (new NSRange (runGlyphIndex, 1), out ascent, out descent, out leading);
                         
                 }
                 
                 glyphOffset += runGlyphCount;
                 
         }
         
         var lineLength = line.GetTypographicBounds (out ascent, out descent, out leading);
         
         var prevHalfWidth = glyphArcInfo[0].width / 2.0;
         glyphArcInfo[0].angle = (float)((prevHalfWidth / lineLength) * Math.PI);
         
         var lineGlyphIndex = 1;
         for (; lineGlyphIndex < glyphCount; lineGlyphIndex++) {
                 
                 var halfWidth = glyphArcInfo[lineGlyphIndex].width / 2.0;
                 var prevCenterToCenter = prevHalfWidth + halfWidth;
                 
                 glyphArcInfo[lineGlyphIndex].angle = (float)((prevCenterToCenter / lineLength) * Math.PI);
                 
                 prevHalfWidth = halfWidth;
                 
         }
 }
        public SizeF MeasureString(string textg, Font font, RectangleF rect)
        {
            // As per documentation
            // https://developer.apple.com/library/mac/#documentation/GraphicsImaging/Conceptual/drawingwithquartz2d/dq_text/dq_text.html#//apple_ref/doc/uid/TP30001066-CH213-TPXREF101
            //
            // * Note * Not sure if we should save off the graphic state, set context transform to identity
            //  and restore state to do the measurement.  Something to be looked into.
            //			context.TextPosition = rect.Location;
            //			var startPos = context.TextPosition;
            //			context.SelectFont ( font.nativeFont.PostScriptName,
            //			                    font.SizeInPoints,
            //			                    CGTextEncoding.MacRoman);
            //			context.SetTextDrawingMode(CGTextDrawingMode.Invisible);
            //
            //			context.SetCharacterSpacing(1);
            //			var textMatrix = CGAffineTransform.MakeScale(1f,-1f);
            //			context.TextMatrix = textMatrix;
            //
            //			context.ShowTextAtPoint(rect.X, rect.Y, textg, textg.Length);
            //			var endPos = context.TextPosition;
            //
            //			var measure = new SizeF(endPos.X - startPos.X, font.nativeFont.CapHeightMetric);

            var atts = buildAttributedString(textg, font);

            // for now just a line not sure if this is going to work
            CTLine line = new CTLine(atts);
            var lineBounds = line.GetImageBounds(context);
            // Create and initialize some values from the bounds.
            float ascent;
            float descent;
            float leading;
            double lineWidth = line.GetTypographicBounds(out ascent, out descent, out leading);

            var measure = new SizeF((float)lineWidth, ascent + descent);

            return measure;
        }
예제 #6
0
		public override Size GetSize (object backend)
		{
			LayoutInfo li = (LayoutInfo)backend;
			using (CTFrame frame = CreateFrame (li)) {
				if (frame == null)
					return Size.Zero;

				Size result = Size.Zero;
				CTLine [] lines = frame.GetLines ();
				float lineHeight = li.Font.Ascender - li.Font.Descender + li.Font.Leading;

				CTLine ellipsis = null;
				bool ellipsize = li.Width.HasValue && li.TextTrimming == TextTrimming.WordElipsis;
				if (ellipsize)
					ellipsis = new CTLine (CreateAttributedString (li, "..."));

				// try to approximate Pango's layout
				foreach (var line in lines) {
					var l = line;
					if (ellipsize) { // we need to create a new CTLine here because the framesetter already truncated the text for the line
						l = new CTLine (CreateAttributedString (li, li.Text.Substring (line.StringRange.Location)))
							.GetTruncatedLine (li.Width.Value, CTLineTruncation.End, ellipsis);
						line.Dispose ();
					}

					result.Width = Math.Max (result.Width, l.GetTypographicBounds ());
					result.Height += lineHeight;

					// clean up after ourselves as we go
					l.Dispose ();
				}

				// CoreText throws away trailing line breaks..
				if (li.Text.EndsWith ("\n"))
					result.Height += lineHeight;

				result.Width = Math.Ceiling (result.Width);
				result.Height = Math.Ceiling (result.Height);
				return result;
			}
		}
예제 #7
0
		internal static void Draw (CGContext ctx, object layout, double x, double y)
		{
			LayoutInfo li = (LayoutInfo)layout;
			using (CTFrame frame = CreateFrame (li)) {
				if (frame == null)
					return;

				CTLine ellipsis = null;
				bool ellipsize = li.Width.HasValue && li.TextTrimming == TextTrimming.WordElipsis;
				if (ellipsize)
					ellipsis = new CTLine (CreateAttributedString (li, "..."));

				float lineHeight = li.Font.Ascender - li.Font.Descender + li.Font.Leading;

				ctx.SaveState ();
				ctx.TextMatrix = CGAffineTransform.MakeScale (1f, -1f);
				ctx.TranslateCTM ((float)x, (float)y + li.Font.Ascender);
				foreach (var line in frame.GetLines ()) {
					ctx.TextPosition = PointF.Empty;
					if (ellipsize) // we need to create a new CTLine here because the framesetter already truncated the text for the line
						new CTLine (CreateAttributedString (li, li.Text.Substring (line.StringRange.Location)))
							.GetTruncatedLine (li.Width.Value, CTLineTruncation.End, ellipsis).Draw (ctx);
					else
						line.Draw (ctx);
					ctx.TranslateCTM (0, lineHeight);
				}
				ctx.RestoreState ();
			}
		}
예제 #8
0
        internal static void Draw(CGContext ctx, object layout, double x, double y)
        {
            LayoutInfo li = (LayoutInfo)layout;
            if (li.Framesetter == null)
                return;

            CGPath path = new CGPath ();
            path.AddRect (new RectangleF (0, 0, li.Width ?? float.MaxValue, li.Height ?? float.MaxValue));
            CTFrame frame = li.Framesetter.GetFrame (new NSRange (0, li.Text.Length), path, null);

            CTLine ellipsis = null;
            bool ellipsize = li.Width.HasValue && li.TextTrimming == TextTrimming.WordElipsis;
            if (ellipsize)
                ellipsis = new CTLine (CreateAttributedString (li, "..."));

            float lineHeight = layoutManager.DefaultLineHeightForFont (li.Font);

            ctx.SaveState ();
            ctx.TextMatrix = CGAffineTransform.MakeScale (1f, -1f);
            ctx.TranslateCTM ((float)x, (float)y + li.Font.Ascender);
            foreach (var line in frame.GetLines ()) {
                ctx.TextPosition = PointF.Empty;
                if (ellipsize) // we need to create a new CTLine here because the framesetter already truncated the text for the line
                    new CTLine (CreateAttributedString (li, li.Text.Substring (line.StringRange.Location)))
                        .GetTruncatedLine (li.Width.Value, CTLineTruncation.End, ellipsis).Draw (ctx);
                else
                    line.Draw (ctx);
                ctx.TranslateCTM (0, lineHeight);
            }
            ctx.RestoreState ();
        }
예제 #9
0
        public CTLine GetTruncatedLine(double width, CTLineTruncation truncationType, CTLine truncationToken)
        {
            var h = CTLineCreateTruncatedLine(Handle, width, truncationType,
                                              truncationToken == null ? IntPtr.Zero : truncationToken.Handle);

            if (h == IntPtr.Zero)
            {
                return(null);
            }
            return(new CTLine(h, true));
        }
		internal static CCSize MeasureString (string textg, CTFont font, CCRect rect)
		{

			var atts = buildAttributedString(textg, font);

			// for now just a line not sure if this is going to work
			CTLine line = new CTLine(atts);

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

            var measure = new CCSize((float)(lineWidth + leading), (float)(ascent + descent));

			return measure;
		}
		// This only handles one character for right now
		internal static void GetCharABCWidthsFloat (char characters, CTFont font, out ABCFloat[] abc)
		{

			var atts = buildAttributedString(characters.ToString(), font);

			// for now just a line not sure if this is going to work
			CTLine line = new CTLine(atts);

			nfloat ascent;
			nfloat descent;
			nfloat leading;
			abc = new ABCFloat[1];
			abc[0].abcfB = (float)line.GetTypographicBounds(out ascent, out descent, out leading);
            abc [0].abcfB += (float)leading;
		}
        /// <summary>
        /// Measures the text.
        /// </summary>
        /// <param name="text">The text.</param>
        /// <param name="fontFamily">The font family.</param>
        /// <param name="fontSize">Size of the font.</param>
        /// <param name="fontWeight">The font weight.</param>
        /// <returns>
        /// The size of the text.
        /// </returns>
        public override OxySize MeasureText(string text, string fontFamily, double fontSize, double fontWeight)
        {
            if (string.IsNullOrEmpty (text) || fontFamily == null) {
                return OxySize.Empty;
            }

            var fontName = GetActualFontName (fontFamily, fontWeight);
            var font = this.GetCachedFont (fontName, (float)fontSize);
            using (var attributedString = new NSAttributedString (text, new CTStringAttributes {
                ForegroundColorFromContext = true,
                Font = font
            })) {
                using (var textLine = new CTLine (attributedString)) {
                    float lineHeight, delta;
                    this.GetFontMetrics (font, out lineHeight, out delta);

                    // the text position must be set to get the correct bounds
                    this.gctx.TextPosition = new PointF (0, 0);

                    var bounds = textLine.GetImageBounds (this.gctx);
                    var width = bounds.Left + bounds.Width;

                    return new OxySize (width, lineHeight);
                }
            }
        }
        /// <summary>
        /// Draws the text.
        /// </summary>
        /// <param name="p">The position of the text.</param>
        /// <param name="text">The text.</param>
        /// <param name="fill">The fill color.</param>
        /// <param name="fontFamily">The font family.</param>
        /// <param name="fontSize">Size of the font.</param>
        /// <param name="fontWeight">The font weight.</param>
        /// <param name="rotate">The rotation angle.</param>
        /// <param name="halign">The horizontal alignment.</param>
        /// <param name="valign">The vertical alignment.</param>
        /// <param name="maxSize">The maximum size of the text.</param>
        public override void DrawText(ScreenPoint p, string text, OxyColor fill, string fontFamily, double fontSize, double fontWeight, double rotate, HorizontalAlignment halign, VerticalAlignment valign, OxySize? maxSize)
        {
            if (string.IsNullOrEmpty (text)) {
                return;
            }

            var fontName = GetActualFontName (fontFamily, fontWeight);

            var font = this.GetCachedFont (fontName, fontSize);
            using (var attributedString = new NSAttributedString (text, new CTStringAttributes {
                ForegroundColorFromContext = true,
                Font = font
            })) {
                using (var textLine = new CTLine (attributedString)) {
                    float width;
                    float height;

                    this.gctx.TextPosition = new PointF (0, 0);

                    float lineHeight, delta;
                    this.GetFontMetrics (font, out lineHeight, out delta);

                    var bounds = textLine.GetImageBounds (this.gctx);

                    var x0 = 0;
                    var y0 = delta;

                    if (maxSize.HasValue || halign != HorizontalAlignment.Left || valign != VerticalAlignment.Bottom) {
                        width = bounds.Left + bounds.Width;
                        height = lineHeight;
                    } else {
                        width = height = 0f;
                    }

                    if (maxSize.HasValue) {
                        if (width > maxSize.Value.Width) {
                            width = (float)maxSize.Value.Width;
                        }

                        if (height > maxSize.Value.Height) {
                            height = (float)maxSize.Value.Height;
                        }
                    }

                    var dx = halign == HorizontalAlignment.Left ? 0d : (halign == HorizontalAlignment.Center ? -width * 0.5 : -width);
                    var dy = valign == VerticalAlignment.Bottom ? 0d : (valign == VerticalAlignment.Middle ? height * 0.5 : height);

                    this.SetFill (fill);
                    this.SetAlias (false);

                    this.gctx.SaveState ();
                    this.gctx.TranslateCTM ((float)p.X, (float)p.Y);
                    if (!rotate.Equals (0)) {
                        this.gctx.RotateCTM ((float)(rotate / 180 * Math.PI));
                    }

                    this.gctx.TranslateCTM ((float)dx + x0, (float)dy + y0);
                    this.gctx.ScaleCTM (1f, -1f);

                    if (maxSize.HasValue) {
                        var clipRect = new RectangleF (-x0, y0, (float)Math.Ceiling (width), (float)Math.Ceiling (height));
                        this.gctx.ClipToRect (clipRect);
                    }

                    textLine.Draw (this.gctx);

                    this.gctx.RestoreState ();
                }
            }
        }
예제 #14
0
 public override void DrawRect (RectangleF dirtyRect)
 {
         // Don't draw if we don't have a font or a title.
         if (Font == null || Title == string.Empty)
                 return;
         
         // Initialize the text matrix to a known value
         CGContext context = NSGraphicsContext.CurrentContext.GraphicsPort;
         context.TextMatrix = CGAffineTransform.MakeIdentity ();
         
         // Draw a white background
         NSColor.White.Set ();
         context.FillRect (dirtyRect);
         
         //CTLineRef line = CTLineCreateWithAttributedString((CFAttributedStringRef)self.attributedString);
         CTLine line = new CTLine (AttributedString);
         
         int glyphCount = line.GlyphCount;
         if (glyphCount == 0)
                 return;
         
         GlyphArcInfo[] glyphArcInfo = new GlyphArcInfo[glyphCount];
         PrepareGlyphArcInfo (line, glyphCount, glyphArcInfo);
         
         // Move the origin from the lower left of the view nearer to its center.
         context.SaveState ();
         context.TranslateCTM (dirtyRect.GetMidX (), dirtyRect.GetMidY () - Radius / 2);
         
         // Stroke the arc in red for verification.
         context.BeginPath ();
         context.AddArc (0, 0, Radius, (float)Math.PI, 0, true);
         context.SetRGBStrokeColor (1, 0, 0, 1);
         context.StrokePath ();
         
         // Rotate the context 90 degrees counterclockwise.
         context.RotateCTM ((float)PI_2);
         
         // Now for the actual drawing. The angle offset for each glyph relative to the previous 
         //      glyph has already been calculated; with that information in hand, draw those glyphs 
         //      overstruck and centered over one another, making sure to rotate the context after each 
         //      glyph so the glyphs are spread along a semicircular path.
         PointF textPosition = new PointF (0, Radius);
         context.TextPosition = textPosition;
         
         var runArray = line.GetGlyphRuns ();
         var runCount = runArray.Count ();
         
         var glyphOffset = 0;
         var runIndex = 0;
         
         for (; runIndex < runCount; runIndex++) {
                 var run = runArray[runIndex];
                 var runGlyphCount = run.GlyphCount;
                 bool drawSubstitutedGlyphsManually = false;
                 CTFont runFont = run.GetAttributes ().Font;
                 
                 // Determine if we need to draw substituted glyphs manually. Do so if the runFont is not 
                 //      the same as the overall font.
                 NSFont rrunFont = new NSFont (runFont.Handle);
                 // used for comparison
                 if (DimsSubstitutedGlyphs && Font != rrunFont) {
                         drawSubstitutedGlyphsManually = true;
                 }
                 
                 var runGlyphIndex = 0;
                 for (; runGlyphIndex < runGlyphCount; runGlyphIndex++) {
                         var glyphRange = new NSRange (runGlyphIndex, 1);
                         context.RotateCTM (-(glyphArcInfo[runGlyphIndex + glyphOffset].angle));
                         
                         // Center this glyph by moving left by half its width.
                         var glyphWidth = glyphArcInfo[runGlyphIndex + glyphOffset].width;
                         var halfGlyphWidth = glyphWidth / 2.0;
                         var positionForThisGlyph = new PointF (textPosition.X - (float)halfGlyphWidth, textPosition.Y);
                         
                         // Glyphs are positioned relative to the text position for the line, so offset text position leftwards by this glyph's 
                         //      width in preparation for the next glyph.
                         textPosition.X -= glyphWidth;
                         
                         CGAffineTransform textMatrix = run.TextMatrix;
                         textMatrix.x0 = positionForThisGlyph.X;
                         textMatrix.y0 = positionForThisGlyph.Y;
                         context.TextMatrix = textMatrix;
                         
                         if (!drawSubstitutedGlyphsManually)
                                 run.Draw (context, glyphRange);
                         else {
                                 
                                 // We need to draw the glyphs manually in this case because we are effectively applying a graphics operation by 
                                 //      setting the context fill color. Normally we would use kCTForegroundColorAttributeName, but this does not apply 
                                 // as we don't know the ranges for the colors in advance, and we wanted demonstrate how to manually draw.
                                 var cgFont = runFont.ToCGFont ();
                                 
                                 var glyph = run.GetGlyphs (glyphRange);
                                 var position = run.GetPositions (glyphRange);
                                 
                                 context.SetFont (cgFont);
                                 context.SetFontSize (runFont.Size);
                                 context.SetRGBFillColor (0.25f, 0.25f, 0.25f, 1);
                                 context.ShowGlyphsAtPositions (glyph, position, 1);
                                 
                         }
                         
                         // Draw the glyph bounds 
                         if (ShowsGlyphBounds) {
                                 
                                 var glyphBounds = run.GetImageBounds (context, glyphRange);
                                 context.SetRGBStrokeColor (0, 0, 1, 1);
                                 context.StrokeRect (glyphBounds);
                         }
                         
                         // Draw the bounding boxes defined by the line metrics
                         if (ShowsLineMetrics) {
                                 
                                 var lineMetrics = new RectangleF ();
                                 float ascent = 0;
                                 float descent = 0;
                                 float leading = 0;
                                 
                                 run.GetTypographicBounds (glyphRange, out ascent, out descent, out leading);
                                 
                                 // The glyph is centered around the y-axis
                                 lineMetrics.Location = new PointF (-(float)halfGlyphWidth, positionForThisGlyph.Y - descent);
                                 lineMetrics.Size = new SizeF (glyphWidth, ascent + descent);
                                 context.SetRGBStrokeColor (0, 1, 0, 1);
                                 context.StrokeRect (lineMetrics);
                         }
                         
                         
                 }
                 
                 glyphOffset += runGlyphCount;
         }
         
         context.RestoreState ();
 }