List<string> NativeFontFamilies() { if (nativeFontCollection == null) { var collectionOptions = new CTFontCollectionOptions (); collectionOptions.RemoveDuplicates = true; nativeFontCollection = new CTFontCollection (collectionOptions); nativeFontDescriptors = new Dictionary<string, CTFontDescriptor> (); } var fontdescs = nativeFontCollection.GetMatchingFontDescriptors (); foreach (var fontdesc in fontdescs) { var font = new CTFont (fontdesc, 0); // Just in case RemoveDuplicates collection option is not working if (!nativeFontDescriptors.ContainsKey (font.FamilyName)) { nativeFontDescriptors.Add (font.FamilyName, fontdesc); } } var fontFamilies = new List<string> (nativeFontDescriptors.Keys); return fontFamilies; }
private CTFont FindMatchingFont(CTFont reference, CTFontSymbolicTraits trait) { CTFontSymbolicTraits symbolic; CTFontTraits traits = reference.GetTraits (); if (traits.SymbolicTraits.HasValue) symbolic = traits.SymbolicTraits.Value | trait; else symbolic = trait; CTFont newFont = reference.WithSymbolicTraits (reference.Size, symbolic, symbolic); if (newFont != null) return newFont; else return reference; }
private void CreateNativeFont(FontFamily familyName, float emSize, FontStyle style, GraphicsUnit unit, byte gdiCharSet, bool gdiVerticalFont ) { // convert to 96 Dpi to be consistent with Windows var dpiSize = emSize * dpiScale; try { nativeFont = new CTFont(familyName.NativeDescriptor,dpiSize); } catch { nativeFont = new CTFont("Helvetica",dpiSize); } CTFontSymbolicTraits tMask = CTFontSymbolicTraits.None; if ((style & FontStyle.Bold) == FontStyle.Bold) tMask |= CTFontSymbolicTraits.Bold; if ((style & FontStyle.Italic) == FontStyle.Italic) tMask |= CTFontSymbolicTraits.Italic; strikeThrough = (style & FontStyle.Strikeout) == FontStyle.Strikeout; underLine = (style & FontStyle.Underline) == FontStyle.Underline; var nativeFont2 = nativeFont.WithSymbolicTraits(dpiSize,tMask,tMask); if (nativeFont2 != null) nativeFont = nativeFont2; bold = (nativeFont.SymbolicTraits & CTFontSymbolicTraits.Bold) == CTFontSymbolicTraits.Bold; italic = (nativeFont.SymbolicTraits & CTFontSymbolicTraits.Italic) == CTFontSymbolicTraits.Italic; sizeInPoints = emSize; this.unit = unit; // FIXME // I do not like the hard coded 72 but am just trying to boot strap the Font class right now size = ConversionHelpers.GraphicsUnitConversion(GraphicsUnit.Point, unit, 72.0f, sizeInPoints); }
private CTFont Italicized(CTFont reference) { return FindMatchingFont (reference, CTFontSymbolicTraits.Italic); }
private CTFont Bolded(CTFont reference) { return FindMatchingFont (reference, CTFontSymbolicTraits.Bold); }
// Listing 2-12: static CTFont CreateBoldFont (CTFont font, bool makeBold) { var desiredTrait = CTFontSymbolicTraits.None; if (makeBold) desiredTrait = CTFontSymbolicTraits.Bold; // Mask off the bold trait to indicate that it is the only trait // desired to be modified. As CTFontSymbolicTraits is a bit field, // we could chooose to change multiple traits if desired. var traitMask = CTFontSymbolicTraits.Bold; // Create a copy of the original font with the masked trait set to the // desired value. If the font family does not have the appropriate style, // This will return null. return font.WithSymbolicTraits (0.0f, desiredTrait, traitMask); }
// Listing 2-9: TODO // Listing 2-10: static float GetLineHeightForFont (CTFont font) { return font.AscentMetric + font.DescentMetric + font.LeadingMetric; }
void LoadFontAndGatherGlyphInfos(int unitSize, Action<List<GlyphInfo>> endHandler) { float scale = UIScreen.MainScreen.Scale; Task.Factory.StartNew (() => { Type typGlyphNames = typeof (FontAwesome.GlyphNames); var memberinfos = typGlyphNames.GetMembers (BindingFlags.Public | BindingFlags.Static | BindingFlags.GetProperty); var ctFont = new CTFont (FontAwesomeUtil.Font, 20f, CGAffineTransform.MakeIdentity ()); var list = memberinfos.Select ((m) => { var fieldInfo = typGlyphNames.GetField (m.Name); var rawName = (string)fieldInfo.GetValue (typGlyphNames); var glyphval = ctFont.GetGlyphWithName (rawName); return new GlyphInfo { GlyphName = m.Name , RawName = rawName , GlyphImage = FontAwesomeUtil.GetImageForBarItem (rawName, unitSize, scale) , GlyphId = glyphval }; }).ToList (); if (endHandler != null) endHandler (list); }); }
internal static CCSize MeasureString(string textg, CTFont font) { return(MeasureString(textg, font, CCSize.Zero)); }
/// <summary> /// Draws text along a given line. /// </summary> /// <param name="target"></param> /// <param name="x"></param> /// <param name="y"></param> /// <param name="color"></param> /// <param name="size"></param> /// <param name="text">Text.</param> protected override void DrawLineText(Target2DWrapper <CGContextWrapper> target, double[] x, double[] y, string text, int color, double size, int?haloColor, int?haloRadius, string fontName) { double[] transformed = this.Tranform(x[0], y[0]); float xPixels = (float)transformed[0]; float yPixels = (float)transformed[1]; float textSize = this.ToPixels(size); // set the fill color as the regular text-color. SimpleColor simpleColor = SimpleColor.FromArgb(color); target.Target.CGContext.InterpolationQuality = CGInterpolationQuality.High; target.Target.CGContext.SetAllowsFontSubpixelQuantization(true); target.Target.CGContext.SetAllowsFontSmoothing(true); target.Target.CGContext.SetFillColor(simpleColor.R / 256.0f, simpleColor.G / 256.0f, simpleColor.B / 256.0f, simpleColor.A / 256.0f); if (haloColor.HasValue) // set the stroke color as the halo color. { SimpleColor haloSimpleColor = SimpleColor.FromArgb(haloColor.Value); target.Target.CGContext.SetStrokeColor(haloSimpleColor.R / 256.0f, haloSimpleColor.G / 256.0f, haloSimpleColor.B / 256.0f, haloSimpleColor.A / 256.0f); } if (haloRadius.HasValue) // set the halo radius as line width. { target.Target.CGContext.SetLineWidth(haloRadius.Value); } // get the glyhps/paths from the font. if (string.IsNullOrWhiteSpace(fontName)) { fontName = "Arial"; } CTFont font = new CTFont(fontName, textSize); CTStringAttributes stringAttributes = new CTStringAttributes { ForegroundColorFromContext = true, Font = font }; NSAttributedString attributedString = new NSAttributedString(text, stringAttributes); CTLine line = new CTLine(attributedString); RectangleF textBounds = line.GetBounds(CTLineBoundsOptions.UseOpticalBounds); CTRun[] runs = line.GetGlyphRuns(); var lineLength = Polyline2D.Length(x, y); // set the correct tranformations to draw the resulting paths. target.Target.CGContext.SaveState(); //target.Target.CGContext.TranslateCTM (xPixels, yPixels); //target.Target.CGContext.ConcatCTM (new CGAffineTransform (1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f)); foreach (CTRun run in runs) { ushort[] glyphs = run.GetGlyphs(); PointF[] positions = run.GetPositions(); float[] characterWidths = new float[glyphs.Length]; float previous = 0; float textLength = (float)this.FromPixels(_target, _view, positions [positions.Length - 1].X); if (lineLength > textLength * 1.2f) { for (int idx = 0; idx < characterWidths.Length - 1; idx++) { characterWidths [idx] = (float)this.FromPixels(_target, _view, positions [idx + 1].X - previous); previous = positions [idx + 1].X; } characterWidths [characterWidths.Length - 1] = characterWidths[characterWidths.Length - 2]; float characterHeight = textBounds.Height; this.DrawLineTextSegment(target, x, y, glyphs, color, haloColor, haloRadius, lineLength / 2f, characterWidths, textLength, characterHeight, font); } } target.Target.CGContext.RestoreState(); }
private CTFont GetFontFromCache(string key, string name, float size) { CTFont font; lock (_fontCache) { if (!_fontCache.TryGetValue(key, out font)) { /*if (name != null && MTFontRegistry.Instance.IsCustomFont(name)) * { * var coreGraphicsFont = MTFontRegistry.Instance.GetCustomFont(name); * if (coreGraphicsFont != null) * { * font = new CTFont(coreGraphicsFont, size, CGAffineTransform.MakeIdentity()); * } * } * else * {*/ var fontStyle = GetFontStyleById(name); if (fontStyle == null) { if (_systemFontName.Equals(name)) { if (name.StartsWith(".", StringComparison.InvariantCultureIgnoreCase)) { var cgfont = _systemFont ?? (_systemFont = CGFont.CreateWithFontName(name)); font = new CTFont(cgfont, size, CGAffineTransform.MakeIdentity()); } else { font = new CTFont(name, size); } } else if (_boldSystemFontName.Equals(name)) { if (name.StartsWith(".", StringComparison.InvariantCultureIgnoreCase)) { var cgfont = _boldSystemFont ?? (_boldSystemFont = CGFont.CreateWithFontName(name)); font = new CTFont(cgfont, size, CGAffineTransform.MakeIdentity()); } else { font = new CTFont(name, size); } } else { fontStyle = GetDefaultFontStyle(); } } if (font == null) { font = new CTFont(fontStyle.Id, size); } //} if (font == null) { return(LoadFont("ArialMT", size)); } _fontCache[key] = font; } } return(font); }
public IOSFont(CTFont font, FontStyle style) { InnerFont = font; _style = style; }
public TextMeasureKey(string text, CTFont font, int maxWidth) { Text = text; Font = font; MaxWidth = maxWidth; }
void LoadFontFile(string fileName) { CTFont nativeFont; var dpiSize = 0; var ext = Path.GetExtension(fileName); if (!String.IsNullOrEmpty(ext)) { if (nativeFontDescriptors == null) { nativeFontDescriptors = new Dictionary <string, CTFontDescriptor> (); } //Try loading from Bundle first var fontName = fileName.Substring(0, fileName.Length - ext.Length); var pathForResource = NSBundle.MainBundle.PathForResource(fontName, ext.Substring(1)); NSUrl url; if (!string.IsNullOrEmpty(pathForResource)) { url = NSUrl.FromFilename(pathForResource); } else { url = NSUrl.FromFilename(fileName); } // We will not use CTFontManager.RegisterFontsForUrl (url, CTFontManagerScope.Process); // here. The reason is that there is no way we can be sure that the font can be created to // to identify the family name afterwards. So instead we will create a CGFont from a data provider. // create CTFont to obtain the CTFontDescriptor, store family name and font descriptor to be accessed // later. try { var dataProvider = new CGDataProvider(url.Path); var cgFont = CGFont.CreateFromProvider(dataProvider); try { nativeFont = new CTFont(cgFont, dpiSize, null); if (!nativeFontDescriptors.ContainsKey(nativeFont.FamilyName)) { nativeFontDescriptors.Add(nativeFont.FamilyName, nativeFont.GetFontDescriptor()); NSError error; var registered = CTFontManager.RegisterGraphicsFont(cgFont, out error); if (!registered) { // If the error code is 105 then the font we are trying to register is already registered // We will not report this as an error. if (error.Code != 105) { throw new ArgumentException("Error registering: " + Path.GetFileName(fileName)); } } } } catch { // note: MS throw the same exception FileNotFoundException if the file exists but isn't a valid font file throw new System.IO.FileNotFoundException(fileName); } } catch (Exception) { // note: MS throw the same exception FileNotFoundException if the file exists but isn't a valid font file throw new System.IO.FileNotFoundException(fileName); } } }
private static void AddAttributes( NSMutableAttributedString attributedString, Text.ITextAttributes attributes, int start, int length, string contextFontName = null, float contextFontSize = 12f, string contextFontColor = null, bool coreTextCompatible = false) { var ctattributes = new CTStringAttributes(); CTFont font; var fontName = attributes.GetFontName() ?? contextFontName; var fontSize = attributes.GetFontSize(contextFontSize); if (fontName != null) { font = new CTFont(fontName, fontSize); } else { /* todo: submit bug to Xamarin as null should be a valid argument to the language */ font = new CTFont(CTFontUIFontType.System, fontSize, NSLocale.CurrentLocale.Identifier); } if (attributes.GetBold() && attributes.GetItalic()) { font = font.WithSymbolicTraits( fontSize, CTFontSymbolicTraits.Bold | CTFontSymbolicTraits.Italic, CTFontSymbolicTraits.Bold | CTFontSymbolicTraits.Italic); } else if (attributes.GetBold()) { font = font.WithSymbolicTraits(fontSize, CTFontSymbolicTraits.Bold, CTFontSymbolicTraits.Bold); } else if (attributes.GetItalic()) { font = font.WithSymbolicTraits(fontSize, CTFontSymbolicTraits.Italic, CTFontSymbolicTraits.Italic); } ctattributes.Font = font; if (attributes.GetUnderline()) { ctattributes.UnderlineStyle = CTUnderlineStyle.Single; } var foreground = attributes.GetForegroundColor(); if (foreground != null) { ctattributes.ForegroundColor = foreground.Parse().ToCGColor(); } else { if (contextFontColor != null) { ctattributes.ForegroundColor = contextFontColor.Parse().ToCGColor(); } else { ctattributes.ForegroundColorFromContext = true; } } var background = attributes.GetBackgroundColor(); if (background != null) { ctattributes.BackgroundColor = background.Parse().ToCGColor(); } attributedString.AddAttributes(ctattributes, new NSRange(start, length)); NSMutableDictionary dictionary = null; #if MONOMAC #if DEBUG var previousCheckStatus = NSApplication.CheckForIllegalCrossThreadCalls; NSApplication.CheckForIllegalCrossThreadCalls = false; #endif if (attributes.GetUnorderedList()) { var paragraphStyle = new NSMutableParagraphStyle(); var textLists = new NSTextList[1]; var marker = "{disc}"; switch (attributes.GetMarker()) { case MarkerType.Hyphen: marker = "{hyphen}"; break; case MarkerType.OpenCircle: marker = "{circle}"; break; } textLists [0] = new NSTextList(marker, NSTextListOptions.PrependEnclosingMarker); paragraphStyle.SetTextLists(textLists); if (dictionary == null) { dictionary = new NSMutableDictionary(); } dictionary.Add(NSStringAttributeKey.ParagraphStyle, paragraphStyle); } #if DEBUG NSApplication.CheckForIllegalCrossThreadCalls = previousCheckStatus; #endif #endif #if MONOMAC if (!coreTextCompatible) { if (attributes.GetSuperscript()) { if (dictionary == null) { dictionary = new NSMutableDictionary(); } dictionary.Add(NSStringAttributeKey.Superscript, NSNumber.FromInt32(1)); } if (attributes.GetSubscript()) { if (dictionary == null) { dictionary = new NSMutableDictionary(); } dictionary.Add(NSStringAttributeKey.Superscript, NSNumber.FromInt32(-1)); } } else { #endif if (attributes.GetSuperscript()) { if (dictionary == null) { dictionary = new NSMutableDictionary(); } dictionary.Add(NSStringAttributeKey.BaselineOffset, NSNumber.FromFloat(fontSize * .5f)); } if (attributes.GetSubscript()) { if (dictionary == null) { dictionary = new NSMutableDictionary(); } dictionary.Add(NSStringAttributeKey.BaselineOffset, NSNumber.FromFloat(-fontSize * .2f)); } #if MONOMAC } #endif if (dictionary != null) { attributedString.AddAttributes(dictionary, new NSRange(start, length)); } }
private void DrawLineTextSegment(Target2DWrapper <CGContextWrapper> target, double[] x, double[] y, ushort[] glyphs, int color, int?haloColor, int?haloRadius, double middlePosition, float[] characterWidths, double textLength, float charachterHeight, CTFont font) { // see if text is 'upside down' double averageAngle = 0; double first = middlePosition - (textLength / 2.0); PointF2D current = Polyline2D.PositionAtPosition(x, y, first); for (int idx = 0; idx < glyphs.Length; idx++) { double nextPosition = middlePosition - (textLength / 2.0) + ((textLength / (glyphs.Length)) * (idx + 1)); PointF2D next = Polyline2D.PositionAtPosition(x, y, nextPosition); // translate to the final position, the center of the line segment between 'current' and 'next'. //PointF2D position = current + ((next - current) / 2.0); // calculate the angle. VectorF2D vector = next - current; VectorF2D horizontal = new VectorF2D(1, 0); double angleDegrees = ((Degree)horizontal.Angle(vector)).Value; averageAngle = averageAngle + angleDegrees; current = next; } averageAngle = averageAngle / glyphs.Length; // revers if 'upside down' double[] xText = x; double[] yText = y; if (averageAngle > 90 && averageAngle < 180 + 90) { xText = x.Reverse().ToArray(); yText = y.Reverse().ToArray(); } first = middlePosition - (textLength / 2.0); current = Polyline2D.PositionAtPosition(xText, yText, first); //target.Target.CGContext.SaveState (); //target.Target.CGContext.TranslateCTM (xText[0], yText[0]); double nextPosition2 = first; for (int idx = 0; idx < glyphs.Length; idx++) { nextPosition2 = nextPosition2 + characterWidths [idx]; PointF2D next = Polyline2D.PositionAtPosition(xText, yText, nextPosition2); //ushort currentChar = glyphs [idx]; PointF2D position = current; target.Target.CGContext.SaveState(); // translate to the final position, the center of the line segment between 'current' and 'next'. double[] transformed = this.Tranform(position[0], position[1]); target.Target.CGContext.TranslateCTM( (float)transformed [0], (float)transformed [1]); // calculate the angle. VectorF2D vector = next - current; VectorF2D horizontal = new VectorF2D(1, 0); double angleDegrees = (horizontal.Angle(vector)).Value; // rotate the character. target.Target.CGContext.RotateCTM((float)angleDegrees); // // // translate the character so the center of its base is over the origin. target.Target.CGContext.TranslateCTM(0, charachterHeight / 3.0f); // rotate 'upside down' target.Target.CGContext.ConcatCTM(new CGAffineTransform(1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f)); target.Target.CGContext.BeginPath(); CGPath path = font.GetPathForGlyph(glyphs [idx]); target.Target.CGContext.AddPath(path); if (haloRadius.HasValue && haloColor.HasValue) // also draw the halo. { target.Target.CGContext.DrawPath(CGPathDrawingMode.FillStroke); } else { target.Target.CGContext.DrawPath(CGPathDrawingMode.Fill); } //target.Target.CGContext.ClosePath (); target.Target.CGContext.RestoreState(); current = next; } }
private bool NativeStyleAvailable(FontStyle style) { // we are going to actually have to create a font object here // will not create an actual variable for this yet. We may // want to do this in the future so that we do not have to keep // creating it over and over again. var font = new CTFont (nativeFontDescriptor,0); switch (style) { case FontStyle.Bold: var tMaskBold = CTFontSymbolicTraits.None; tMaskBold |= CTFontSymbolicTraits.Bold; var bFont = font.WithSymbolicTraits (0, tMaskBold, tMaskBold); if (bFont == null) return false; var bold = (bFont.SymbolicTraits & CTFontSymbolicTraits.Bold) == CTFontSymbolicTraits.Bold; return bold; case FontStyle.Italic: //return (font.SymbolicTraits & CTFontSymbolicTraits.Italic) == CTFontSymbolicTraits.Italic; var tMaskItalic = CTFontSymbolicTraits.None; tMaskItalic |= CTFontSymbolicTraits.Italic; var iFont = font.WithSymbolicTraits (0, tMaskItalic, tMaskItalic); if (iFont == null) return false; var italic = (iFont.SymbolicTraits & CTFontSymbolicTraits.Italic) == CTFontSymbolicTraits.Italic; return italic; case FontStyle.Regular: // Verify if this is correct somehow - we may need to add Bold here as well not sure if ((font.SymbolicTraits & CTFontSymbolicTraits.Condensed) == CTFontSymbolicTraits.Condensed || (font.SymbolicTraits & CTFontSymbolicTraits.Expanded) == CTFontSymbolicTraits.Expanded) return false; else return true; case FontStyle.Underline: return font.UnderlineThickness > 0; case FontStyle.Strikeout: // not implemented yet return false; } return false; }
/// <summary> /// Draws text. /// </summary> /// <param name="target"></param> /// <param name="x"></param> /// <param name="y"></param> /// <param name="text"></param> /// <param name="size"></param> /// <param name="color">Color.</param> protected override void DrawText(Target2DWrapper <CGContextWrapper> target, double x, double y, string text, int color, double size, int?haloColor, int?haloRadius, string fontName) { double[] transformed = this.Tranform(x, y); float xPixels = (float)transformed[0]; float yPixels = (float)transformed[1]; float textSize = this.ToPixels(size) * _scaleFactor; // get the glyhps/paths from the font. CTFont font = this.GetFont(fontName, textSize); CTStringAttributes stringAttributes = new CTStringAttributes { ForegroundColorFromContext = true, Font = font }; NSAttributedString attributedString = new NSAttributedString(text, stringAttributes); CTLine line = new CTLine(attributedString); CTRun[] runs = line.GetGlyphRuns(); // set the correct tranformations to draw the resulting paths. target.Target.CGContext.SaveState(); target.Target.CGContext.TranslateCTM(xPixels, yPixels); target.Target.CGContext.ConcatCTM(new CGAffineTransform(1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f)); foreach (CTRun run in runs) { ushort[] glyphs = run.GetGlyphs(); PointF[] positions = run.GetPositions(); float previousOffset = 0; for (int idx = 0; idx < glyphs.Length; idx++) { CGPath path = font.GetPathForGlyph(glyphs[idx]); target.Target.CGContext.TranslateCTM(positions[idx].X - previousOffset, 0); previousOffset = positions[idx].X; if (haloRadius.HasValue && haloColor.HasValue) { // also draw the halo. using (CGPath haloPath = path.CopyByStrokingPath( haloRadius.Value * 2, CGLineCap.Round, CGLineJoin.Round, 0)) { SimpleColor haloSimpleColor = SimpleColor.FromArgb(haloColor.Value); target.Target.CGContext.SetFillColor(haloSimpleColor.R / 256.0f, haloSimpleColor.G / 256.0f, haloSimpleColor.B / 256.0f, haloSimpleColor.A / 256.0f); target.Target.CGContext.BeginPath(); target.Target.CGContext.AddPath(haloPath); target.Target.CGContext.DrawPath(CGPathDrawingMode.Fill); } } // set the fill color as the regular text-color. SimpleColor simpleColor = SimpleColor.FromArgb(color); target.Target.CGContext.SetFillColor(simpleColor.R / 256.0f, simpleColor.G / 256.0f, simpleColor.B / 256.0f, simpleColor.A / 256.0f); // draw the text paths. target.Target.CGContext.BeginPath(); target.Target.CGContext.AddPath(path); target.Target.CGContext.DrawPath(CGPathDrawingMode.Fill); } } target.Target.CGContext.RestoreState(); }
internal static CCSize MeasureString(string textg, CTFont font, CCSize layoutArea) { return(MeasureString(textg, font, new CCRect(0, 0, layoutArea.Width, layoutArea.Height))); }
/// <summary> /// Draws text along a given line. /// </summary> /// <param name="target"></param> /// <param name="x"></param> /// <param name="y"></param> /// <param name="color"></param> /// <param name="size"></param> /// <param name="text">Text.</param> protected override void DrawLineText(Target2DWrapper <CGContextWrapper> target, double[] xa, double[] ya, string text, int color, double size, int?haloColor, int?haloRadius, string fontName) { float textSize = this.ToPixels(size) * _scaleFactor; // transform first. double[] xTransformed = new double[xa.Length]; double[] yTransformed = new double[ya.Length]; for (int idx = 0; idx < xa.Length; idx++) { double[] transformed = this.Tranform(xa[idx], ya[idx]); xTransformed[idx] = transformed[0]; yTransformed[idx] = transformed[1]; } // set the fill color as the regular text-color. target.Target.CGContext.InterpolationQuality = CGInterpolationQuality.High; target.Target.CGContext.SetAllowsFontSubpixelQuantization(true); target.Target.CGContext.SetAllowsFontSmoothing(true); target.Target.CGContext.SetAllowsAntialiasing(true); target.Target.CGContext.SetAllowsSubpixelPositioning(true); target.Target.CGContext.SetShouldAntialias(true); // get the glyhps/paths from the font. CTFont font = this.GetFont(fontName, textSize); CTStringAttributes stringAttributes = new CTStringAttributes { ForegroundColorFromContext = true, Font = font }; NSAttributedString attributedString = new NSAttributedString(text, stringAttributes); CTLine line = new CTLine(attributedString); RectangleF textBounds = line.GetBounds(CTLineBoundsOptions.UseOpticalBounds); CTRun[] runs = line.GetGlyphRuns(); var lineLength = Polyline2D.Length(xTransformed, yTransformed); // set the correct tranformations to draw the resulting paths. target.Target.CGContext.SaveState(); //target.Target.CGContext.TranslateCTM (xPixels, yPixels); //target.Target.CGContext.ConcatCTM (new CGAffineTransform (1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f)); foreach (CTRun run in runs) { ushort[] glyphs = run.GetGlyphs(); PointF[] positions = run.GetPositions(); float[] characterWidths = new float[glyphs.Length]; float previous = 0; float textLength = (float)positions[positions.Length - 1].X; //float textLength = (float)this.FromPixels(_target, _view, positions [positions.Length - 1].X); if (lineLength > textLength * 1.2f) { for (int idx = 0; idx < characterWidths.Length - 1; idx++) { //characterWidths [idx] = (float)this.FromPixels(_target, _view, positions [idx + 1].X - previous); characterWidths[idx] = (float)(positions[idx + 1].X - previous); previous = positions[idx + 1].X; } characterWidths[characterWidths.Length - 1] = characterWidths[characterWidths.Length - 2]; float characterHeight = textBounds.Height; this.DrawLineTextSegment(target, xTransformed, yTransformed, glyphs, color, haloColor, haloRadius, lineLength / 2f, characterWidths, textLength, characterHeight, font); } } target.Target.CGContext.RestoreState(); }
private static NSMutableAttributedString buildAttributedString(string text, CTFont font, CCColor4B?fontColor = null) { // Create a new attributed string definition var ctAttributes = new CTStringAttributes(); // Font attribute ctAttributes.Font = font; // -- end font if (fontColor.HasValue) { // Font color var fc = fontColor.Value; var cgColor = new CGColor(fc.R / 255f, fc.G / 255f, fc.B / 255f, fc.A / 255f); ctAttributes.ForegroundColor = cgColor; ctAttributes.ForegroundColorFromContext = false; // -- end font Color } if (underLine) { // Underline #if MACOS int single = (int)MonoMac.AppKit.NSUnderlineStyle.Single; int solid = (int)MonoMac.AppKit.NSUnderlinePattern.Solid; var attss = single | solid; ctAttributes.UnderlineStyleValue = attss; #else ctAttributes.UnderlineStyleValue = 1; #endif // --- end underline } if (strikeThrough) { // StrikeThrough // NSColor bcolor = NSColor.Blue; // NSObject bcolorObject = new NSObject(bcolor.Handle); // attsDic.Add(NSAttributedString.StrikethroughColorAttributeName, bcolorObject); // #if MACOS // int stsingle = (int)MonoMac.AppKit.NSUnderlineStyle.Single; // int stsolid = (int)MonoMac.AppKit.NSUnderlinePattern.Solid; // var stattss = stsingle | stsolid; // var stunderlineObject = NSNumber.FromInt32(stattss); // #else // var stunderlineObject = NSNumber.FromInt32 (1); // #endif // // attsDic.Add(StrikethroughStyleAttributeName, stunderlineObject); // --- end underline } // Text alignment var alignment = CTTextAlignment.Left; var alignmentSettings = new CTParagraphStyleSettings(); alignmentSettings.Alignment = alignment; var paragraphStyle = new CTParagraphStyle(alignmentSettings); ctAttributes.ParagraphStyle = paragraphStyle; // end text alignment NSMutableAttributedString atts = new NSMutableAttributedString(text, ctAttributes.Dictionary); return(atts); }
private void DrawLineTextSegment(Target2DWrapper <CGContextWrapper> target, double[] xTransformed, double[] yTransformed, ushort[] glyphs, int color, int?haloColor, int?haloRadius, double middlePosition, float[] characterWidths, double textLength, float charachterHeight, CTFont font) { // see if text is 'upside down' double averageAngle = 0; double first = middlePosition - (textLength / 2.0); PointF2D current = Polyline2D.PositionAtPosition(xTransformed, yTransformed, first); for (int idx = 0; idx < glyphs.Length; idx++) { double nextPosition = middlePosition - (textLength / 2.0) + ((textLength / (glyphs.Length)) * (idx + 1)); PointF2D next = Polyline2D.PositionAtPosition(xTransformed, yTransformed, nextPosition); // translate to the final position, the center of the line segment between 'current' and 'next'. //PointF2D position = current + ((next - current) / 2.0); // calculate the angle. VectorF2D vector = next - current; VectorF2D horizontal = new VectorF2D(1, 0); double angleDegrees = ((Degree)horizontal.Angle(vector)).Value; averageAngle = averageAngle + angleDegrees; current = next; } averageAngle = averageAngle / glyphs.Length; // revers if 'upside down' double[] xText = xTransformed; double[] yText = yTransformed; if (averageAngle > 90 && averageAngle < 180 + 90) { xText = xTransformed.Reverse().ToArray(); yText = yTransformed.Reverse().ToArray(); } first = middlePosition - (textLength / 2.0); current = Polyline2D.PositionAtPosition(xText, yText, first); double nextPosition2 = first; for (int idx = 0; idx < glyphs.Length; idx++) { nextPosition2 = nextPosition2 + characterWidths[idx]; PointF2D next = Polyline2D.PositionAtPosition(xText, yText, nextPosition2); //ushort currentChar = glyphs [idx]; PointF2D position = current; target.Target.CGContext.SaveState(); // translate to the final position, the center of the line segment between 'current' and 'next'. // double[] transformed = this.Tranform(position[0], position[1]); // target.Target.CGContext.TranslateCTM ( // (float)transformed [0], // (float)transformed [1]); target.Target.CGContext.TranslateCTM((float)position[0], (float)position[1]); // calculate the angle. VectorF2D vector = next - current; VectorF2D horizontal = new VectorF2D(1, 0); double angleDegrees = (horizontal.Angle(vector)).Value; // rotate the character. target.Target.CGContext.RotateCTM((float)angleDegrees); // rotate the text to point down no matter what the map tilt is. //target.Target.CGContext.RotateCTM ((float)_view.Angle.Value); // translate the character so the center of its base is over the origin. target.Target.CGContext.TranslateCTM(0, charachterHeight / 3.0f); // rotate 'upside down' target.Target.CGContext.ConcatCTM(new CGAffineTransform(1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f)); target.Target.CGContext.BeginPath(); CGPath path = font.GetPathForGlyph(glyphs[idx]); if (haloRadius.HasValue && haloColor.HasValue) { // also draw the halo. using (CGPath haloPath = path.CopyByStrokingPath( haloRadius.Value * 2, CGLineCap.Round, CGLineJoin.Round, 0)) { SimpleColor haloSimpleColor = SimpleColor.FromArgb(haloColor.Value); target.Target.CGContext.SetFillColor(haloSimpleColor.R / 256.0f, haloSimpleColor.G / 256.0f, haloSimpleColor.B / 256.0f, haloSimpleColor.A / 256.0f); target.Target.CGContext.BeginPath(); target.Target.CGContext.AddPath(haloPath); target.Target.CGContext.DrawPath(CGPathDrawingMode.Fill); } } // set the fill color as the regular text-color. SimpleColor simpleColor = SimpleColor.FromArgb(color); target.Target.CGContext.SetFillColor(simpleColor.R / 256.0f, simpleColor.G / 256.0f, simpleColor.B / 256.0f, simpleColor.A / 256.0f); // draw the text paths. target.Target.CGContext.BeginPath(); target.Target.CGContext.AddPath(path); target.Target.CGContext.DrawPath(CGPathDrawingMode.Fill); // target.Target.CGContext.AddPath (path); // if (haloRadius.HasValue && haloColor.HasValue) { // also draw the halo. // target.Target.CGContext.DrawPath (CGPathDrawingMode.FillStroke); // } else { // target.Target.CGContext.DrawPath (CGPathDrawingMode.Fill); // } //target.Target.CGContext.ClosePath (); target.Target.CGContext.RestoreState(); current = next; } }
// Listing 2-8 static NSData CreateFlattenedFontData (CTFont font) { var descriptor = font.GetFontDescriptor (); if (descriptor == null) return null; var attributes = descriptor.GetAttributes (); if (attributes == null) return null; // TODO: MonoTouch has no binding for CFPropertyListIsValid() return null; }
void LoadFontFile(string fileName) { CTFont nativeFont; var dpiSize = 0; var ext = Path.GetExtension(fileName); if (!String.IsNullOrEmpty(ext)) { if (nativeFontDescriptors == null) nativeFontDescriptors = new Dictionary<string, CTFontDescriptor> (); //Try loading from Bundle first var fontName = fileName.Substring (0, fileName.Length - ext.Length); var pathForResource = NSBundle.MainBundle.PathForResource (fontName, ext.Substring(1)); NSUrl url; if (!string.IsNullOrEmpty(pathForResource)) url = NSUrl.FromFilename (pathForResource); else url = NSUrl.FromFilename (fileName); // We will not use CTFontManager.RegisterFontsForUrl (url, CTFontManagerScope.Process); // here. The reason is that there is no way we can be sure that the font can be created to // to identify the family name afterwards. So instead we will create a CGFont from a data provider. // create CTFont to obtain the CTFontDescriptor, store family name and font descriptor to be accessed // later. try { var dataProvider = new CGDataProvider (url.Path); var cgFont = CGFont.CreateFromProvider (dataProvider); try { nativeFont = new CTFont(cgFont, dpiSize, null); if (!nativeFontDescriptors.ContainsKey(nativeFont.FamilyName)) { nativeFontDescriptors.Add(nativeFont.FamilyName, nativeFont.GetFontDescriptor()); NSError error; var registered = CTFontManager.RegisterGraphicsFont(cgFont, out error); if (!registered) { // If the error code is 105 then the font we are trying to register is already registered // We will not report this as an error. if (error.Code != 105) throw new ArgumentException("Error registering: " + Path.GetFileName(fileName)); } } } catch { // note: MS throw the same exception FileNotFoundException if the file exists but isn't a valid font file throw new System.IO.FileNotFoundException (fileName); } } catch (Exception) { // note: MS throw the same exception FileNotFoundException if the file exists but isn't a valid font file throw new System.IO.FileNotFoundException (fileName); } } }
// Listing 2-11: static void GetGlyphsForCharacters (CTFont font, string value) { var count = value.Length; var characters = value.ToCharArray (); var glyphs = new ushort [characters.Length]; font.GetGlyphsForCharacters (characters, glyphs); // Do something with the glyphs here, if a character is unmapped }
static internal CTFont CreateFont(string familyName, float emSize, FontStyle style, byte gdiCharSet, bool gdiVerticalFont) { if (emSize <= 0) { throw new ArgumentException("emSize is less than or equal to 0, evaluates to infinity, or is not a valid number.", "emSize"); } CTFont nativeFont; // convert to 96 Dpi to be consistent with Windows var dpiSize = emSize; // * dpiScale; var ext = System.IO.Path.GetExtension(familyName); if (!String.IsNullOrEmpty(ext) && ext.ToLower() == ".ttf") { var fontName = familyName.Substring(0, familyName.Length - ext.Length); var path = CCContentManager.SharedContentManager.RootDirectory + Path.DirectorySeparatorChar + fontName; var pathForResource = NSBundle.MainBundle.PathForResource(path, ext.Substring(1)); try { var dataProvider = new CGDataProvider(pathForResource); var cgFont = CGFont.CreateFromProvider(dataProvider); try { nativeFont = new CTFont(cgFont, dpiSize, null); } catch { nativeFont = new CTFont("Helvetica", dpiSize); } } catch (Exception) { try { nativeFont = new CTFont(Path.GetFileNameWithoutExtension(familyName), dpiSize); } catch { nativeFont = new CTFont("Helvetica", dpiSize); } CCLog.Log(string.Format("Could not load font: {0} so will use default {1}.", familyName, nativeFont.DisplayName)); } } else { try { nativeFont = new CTFont(familyName, dpiSize); } catch { nativeFont = new CTFont("Helvetica", dpiSize); } } CTFontSymbolicTraits tMask = CTFontSymbolicTraits.None; if ((style & FontStyle.Bold) == FontStyle.Bold) { tMask |= CTFontSymbolicTraits.Bold; } if ((style & FontStyle.Italic) == FontStyle.Italic) { tMask |= CTFontSymbolicTraits.Italic; } strikeThrough = (style & FontStyle.Strikeout) == FontStyle.Strikeout; underLine = (style & FontStyle.Underline) == FontStyle.Underline; var nativeFont2 = nativeFont.WithSymbolicTraits(dpiSize, tMask, tMask); if (nativeFont2 != null) { nativeFont = nativeFont2; } return(nativeFont); }
// Listing 2-13: static CTFont CreateFontConvertedToFamily (CTFont font, string family) { return font.WithFamily (0.0f, family); }
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(); }
void setupTextLayer(string l) { clearLayer(); var singleLetter = l.Length == 1; var fontSize = singleLetter ? letterFontSize : messageFontSize; var font = new CTFont(new CTFontDescriptor(new CTFontDescriptorAttributes { Name = UIFont.SystemFontOfSize(fontSize).Name, Size = (float?)fontSize }), fontSize); var attrStr = new NSAttributedString(l, singleLetter ? letterStringAttributes : messageStringAttributes); var line = new CTLine(attrStr); var runArray = line.GetGlyphRuns(); var letters = new CGPath(); for (int runIndex = 0; runIndex < runArray.Length; runIndex++) { var run = runArray [runIndex]; for (int runGlyphIndex = 0; runGlyphIndex < run.GlyphCount; runGlyphIndex++) { var thisGlyphRange = new NSRange(runGlyphIndex, 1); var glyph = run.GetGlyphs(thisGlyphRange).FirstOrDefault(); var position = run.GetPositions(thisGlyphRange).FirstOrDefault(); var letter = font.GetPathForGlyph(glyph); var t = CGAffineTransform.MakeTranslation(position.X, position.Y); if (letter != null) { letters.AddPath(t, letter); } } } var path = new UIBezierPath(); path.MoveTo(CGPoint.Empty); path.AppendPath(UIBezierPath.FromPath(letters)); var layer = new CAShapeLayer(); layer.Frame = new CGRect(((animationLayer.Bounds.Width - path.Bounds.Width) / 2) - 10, (animationLayer.Bounds.Height - path.Bounds.Height) / 2, path.Bounds.Width, path.Bounds.Height); layer.GeometryFlipped = true; layer.Path = path.CGPath; layer.StrokeColor = UIColor.Blue.CGColor; layer.FillColor = null; layer.LineWidth = 3; layer.LineJoin = CAShapeLayer.JoinBevel; animationLayer?.AddSublayer(layer); pathLayer = layer; }
void drawLabel(CGContext ctx, CGRect rect, nfloat yCoord, nfloat xCoord, CTTextAlignment alignment, UIColor color, string label, bool flipContext = true) { Console.WriteLine("Finish Draw code"); var attrString = new NSMutableAttributedString (label); var range = new NSRange (0, attrString.Length); var uiFont = UIFont.FromName("HelveticaNeue-Medium", range.Length > 1 ? 15 : 22); var font = new CTFont (uiFont.Name, uiFont.PointSize); //((uiFont.Name as NSString) as CFString, uiFont.pointSize, nil); var path = new CGPath (); var alignStyle = new CTParagraphStyle (new CTParagraphStyleSettings { Alignment = alignment }); var attributes = new CTStringAttributes { Font = font, ForegroundColor = color.CGColor, ParagraphStyle = alignStyle }; attrString.SetAttributes(attributes, new NSRange (0, attrString.Length)); var target = new CGSize (nfloat.MaxValue, nfloat.MaxValue); var fit = new NSRange (0, 0); var framesetter = new CTFramesetter (attrString); var frameSize = framesetter.SuggestFrameSize(range, null, target, out fit); var textRect = new CGRect (xCoord - (frameSize.Width / 2), yCoord - (frameSize.Height / 2), frameSize.Width, frameSize.Height); path.AddRect(textRect); var frame = framesetter.GetFrame(range, path, null); if (flipContext) { ctx.SaveState(); ctx.TranslateCTM(0, rect.Height); ctx.ScaleCTM(1, -1); frame.Draw(ctx); ctx.RestoreState(); } else { frame.Draw(ctx); } }
/// <summary> /// Gets font metrics for the specified font. /// </summary> /// <param name="font">The font.</param> /// <param name="defaultLineHeight">Default line height.</param> /// <param name="delta">The vertical delta.</param> private void GetFontMetrics(CTFont font, out nfloat defaultLineHeight, out nfloat delta) { var ascent = font.AscentMetric; var descent = font.DescentMetric; var leading = font.LeadingMetric; //// http://stackoverflow.com/questions/5511830/how-does-line-spacing-work-in-core-text-and-why-is-it-different-from-nslayoutm leading = leading < 0 ? 0 : (float)Math.Floor(leading + 0.5f); var lineHeight = (nfloat)Math.Floor(ascent + 0.5f) + (nfloat)Math.Floor(descent + 0.5) + leading; var ascenderDelta = leading >= 0 ? 0 : (nfloat)Math.Floor((0.2 * lineHeight) + 0.5); defaultLineHeight = lineHeight + ascenderDelta; delta = ascenderDelta - descent; }
string LoadFontFile(string fileName) { CTFont nativeFont; var dpiSize = 0; var ext = Path.GetExtension(fileName); if (!String.IsNullOrEmpty(ext)) { if (nativeFontDescriptors == null) { nativeFontDescriptors = new Dictionary <string, string> (); } string fd = null; if (nativeFontDescriptors.TryGetValue(fileName, out fd)) { return(fd); } // We will not use CTFontManager.RegisterFontsForUrl (url, CTFontManagerScope.Process); // here. The reason is that there is no way we can be sure that the font can be created to // to identify the family name afterwards. So instead we will create a CGFont from a data provider. // create CTFont to obtain the CTFontDescriptor, store family name and font descriptor to be accessed // later. try { var filePath = string.Empty; CCContentManager.SharedContentManager.GetAssetStreamAsBytes(fileName, out filePath); var dataProvider = new CGDataProvider(filePath); var cgFont = CGFont.CreateFromProvider(dataProvider); try { nativeFont = new CTFont(cgFont, dpiSize, null); if (!nativeFontDescriptors.ContainsKey(fileName)) { nativeFontDescriptors.Add(fileName, nativeFont.PostScriptName); NSError error; var registered = CTFontManager.RegisterGraphicsFont(cgFont, out error); if (!registered) { // If the error code is 105 then the font we are trying to register is already registered // We will not report this as an error. if (error.Code != 105) { throw new ArgumentException("Error registering: " + Path.GetFileName(fileName)); } } } return(nativeFont.PostScriptName); } catch { // note: MS throw the same exception FileNotFoundException if the file exists but isn't a valid font file throw new System.IO.FileNotFoundException(fileName); } } catch (Exception) { // note: MS throw the same exception FileNotFoundException if the file exists but isn't a valid font file throw new System.IO.FileNotFoundException(fileName); } } return(fileName); }
private int GetNativeMetric(Metric metric, FontStyle style) { // we are going to actually have to create a font object here // will not create an actual variable for this yet. We may // want to do this in the future so that we do not have to keep // creating it over and over again. CTFontSymbolicTraits tMask = CTFontSymbolicTraits.None; if ((style & FontStyle.Bold) == FontStyle.Bold) tMask |= CTFontSymbolicTraits.Bold; if ((style & FontStyle.Italic) == FontStyle.Italic) tMask |= CTFontSymbolicTraits.Italic; var font = new CTFont (nativeFontDescriptor,0); font = font.WithSymbolicTraits (0, tMask, tMask); switch (metric) { case Metric.EMHeight: return (int)font.UnitsPerEmMetric; case Metric.CellAscent: return (int)Math.Round(font.AscentMetric / font.Size * font.UnitsPerEmMetric); case Metric.CellDescent: return (int)Math.Round(font.DescentMetric / font.Size * font.UnitsPerEmMetric); case Metric.LineSpacing: float lineHeight = 0; lineHeight += (float)font.AscentMetric; lineHeight += (float)font.DescentMetric; lineHeight += (float)font.LeadingMetric; return (int)Math.Round(lineHeight / font.Size * font.UnitsPerEmMetric); } return 0; }
internal static void NativeDrawString(CGBitmapContext bitmapContext, string s, CTFont font, CCColor4B brush, CGRect layoutRectangle) { if (font == null) { throw new ArgumentNullException("font"); } if (s == null || s.Length == 0) { return; } bitmapContext.ConcatCTM(bitmapContext.GetCTM().Invert()); // This is not needed here since the color is set in the attributed string. //bitmapContext.SetFillColor(brush.R/255f, brush.G/255f, brush.B/255f, brush.A/255f); // I think we only Fill the text with no Stroke surrounding //bitmapContext.SetTextDrawingMode(CGTextDrawingMode.Fill); var attributedString = buildAttributedString(s, font, brush); // Work out the geometry CGRect insetBounds = layoutRectangle; CGPoint textPosition = new CGPoint(insetBounds.X, insetBounds.Y); float boundsWidth = (float)insetBounds.Width; // Calculate the lines nint start = 0; nint length = attributedString.Length; var typesetter = new CTTypesetter(attributedString); float baselineOffset = 0; // First we need to calculate the offset for Vertical Alignment if we // are using anything but Top if (vertical != CCVerticalTextAlignment.Top) { while (start < length) { nint count = typesetter.SuggestLineBreak((int)start, (double)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((float)(ascent + descent + leading + 1)); // +1 matches best to CTFramesetter's behavior line.Dispose(); start += count; } } 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" nint count = typesetter.SuggestLineBreak((int)start, (double)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); // Calculate the string format if need be var penFlushness = 0.0f; if (horizontal == CCTextAlignment.Right) { penFlushness = (float)line.GetPenOffsetForFlush(1.0f, boundsWidth); } else if (horizontal == CCTextAlignment.Center) { penFlushness = (float)line.GetPenOffsetForFlush(0.5f, boundsWidth); } // initialize our Text Matrix or we could get trash in here var textMatrix = CGAffineTransform.MakeIdentity(); if (vertical == CCVerticalTextAlignment.Top) { textMatrix.Translate(penFlushness, insetBounds.Height - textPosition.Y - (float)Math.Floor(ascent - 1)); } if (vertical == CCVerticalTextAlignment.Center) { textMatrix.Translate(penFlushness, ((insetBounds.Height / 2) + (baselineOffset / 2)) - textPosition.Y - (float)Math.Floor(ascent - 1)); } if (vertical == CCVerticalTextAlignment.Bottom) { textMatrix.Translate(penFlushness, baselineOffset - textPosition.Y - (float)Math.Floor(ascent - 1)); } // Set our matrix bitmapContext.TextMatrix = textMatrix; // and draw the line line.Draw(bitmapContext); // 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(); } }
private void CreateNativeFontFamily(string name, FontCollection fontCollection, bool createDefaultIfNotExists) { if (fontCollection != null) { if (fontCollection.nativeFontDescriptors.ContainsKey (name)) nativeFontDescriptor = fontCollection.nativeFontDescriptors [name]; if (nativeFontDescriptor == null && createDefaultIfNotExists) { nativeFontDescriptor = new CTFontDescriptor (SANS_SERIF, 0); } } else { nativeFontDescriptor = new CTFontDescriptor (name, 0); if (nativeFontDescriptor == null && createDefaultIfNotExists) { nativeFontDescriptor = new CTFontDescriptor (SANS_SERIF, 0); } } if (nativeFontDescriptor == null) throw new ArgumentException ("name specifies a font that is not installed on the computer running the application."); else { var attrs = nativeFontDescriptor.GetAttributes (); familyName = attrs.FamilyName; // if the font description attributes do not contain a value for FamilyName then we // need to try and create the font to get the family name from the actual font. if (string.IsNullOrEmpty (familyName)) { var font = new CTFont (nativeFontDescriptor, 0); familyName = font.FamilyName; } } }
public AppleMathFont(AppleMathFont cloneMe, float pointSize) : this(pointSize) { Name = cloneMe.Name; CgFont = cloneMe.CgFont; CtFont = new CTFont(CgFont, pointSize, CGAffineTransform.MakeIdentity()); }