2
// TextLayoutBackendHandler.cs
5
// Lluis Sanchez <lluis@xamarin.com>
7
// Copyright (c) 2011 Xamarin Inc
9
// Permission is hereby granted, free of charge, to any person obtaining a copy
10
// of this software and associated documentation files (the "Software"), to deal
11
// in the Software without restriction, including without limitation the rights
12
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
// copies of the Software, and to permit persons to whom the Software is
14
// furnished to do so, subject to the following conditions:
16
// The above copyright notice and this permission notice shall be included in
17
// all copies or substantial portions of the Software.
19
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
30
using MonoMac.Foundation;
31
using MonoMac.CoreText;
32
using MonoMac.CoreGraphics;
36
using PointF = System.Drawing.PointF;
37
using SizeF = System.Drawing.SizeF;
38
using RectangleF = System.Drawing.RectangleF;
42
public class TextLayoutBackendHandler: ITextLayoutBackendHandler
46
public CTFramesetter Framesetter;
49
public float? Width, Height;
50
public TextTrimming TextTrimming;
53
public object Create (Xwt.Drawing.Context context)
55
return new LayoutInfo ();
58
public object Create (ICanvasBackend canvas)
60
return new LayoutInfo {
61
Font = (NSFont)canvas.Font
65
public void SetText (object backend, string text)
67
LayoutInfo li = (LayoutInfo)backend;
69
InvalidateFramesetter (li);
72
public void SetFont (object backend, Xwt.Drawing.Font font)
74
LayoutInfo li = (LayoutInfo)backend;
75
li.Font = (NSFont)WidgetRegistry.GetBackend (font);
76
InvalidateFramesetter (li);
79
public void SetWidth (object backend, double value)
81
LayoutInfo li = (LayoutInfo)backend;
82
li.Width = value < 0 ? null : (float?)value;
85
public void SetHeight (object backend, double value)
87
LayoutInfo li = (LayoutInfo)backend;
88
li.Height = value < 0 ? null : (float?)value;
91
public void SetTrimming (object backend, TextTrimming value)
93
LayoutInfo li = (LayoutInfo)backend;
94
li.TextTrimming = value;
97
public Size GetSize (object backend)
99
LayoutInfo li = (LayoutInfo)backend;
100
if (li.Framesetter == null)
104
SizeF constraint = new SizeF (li.Width ?? float.MaxValue, float.MaxValue);
105
return li.Framesetter.SuggestFrameSize (new NSRange (0, li.Text.Length), null, constraint, out unused).ToXwtSize ();
108
static void InvalidateFramesetter (LayoutInfo li)
110
if (li.Framesetter != null) {
111
li.Framesetter.Dispose ();
112
li.Framesetter = null;
114
if (!string.IsNullOrEmpty (li.Text))
115
li.Framesetter = new CTFramesetter (CreateAttributedString (li));
118
static NSAttributedString CreateAttributedString (LayoutInfo li, string overrideText = null)
121
if (li.Font != null) {
122
dict = NSDictionary.FromObjectsAndKeys (
123
new object[] { li.Font, new NSNumber (true) },
124
new object[] { CTStringAttributeKey.Font, CTStringAttributeKey.ForegroundColorFromContext }
127
dict = NSDictionary.FromObjectsAndKeys (
128
new object[] { new NSNumber (true) },
129
new object[] { CTStringAttributeKey.ForegroundColorFromContext }
132
return new NSAttributedString (overrideText ?? li.Text, dict);
135
internal static void Draw (CGContext ctx, object layout, double x, double y)
137
LayoutInfo li = (LayoutInfo)layout;
138
if (li.Framesetter == null)
141
CGPath path = new CGPath ();
142
path.AddRect (new RectangleF (0, 0, li.Width ?? float.MaxValue, li.Height ?? float.MaxValue));
143
CTFrame frame = li.Framesetter.GetFrame (new NSRange (0, li.Text.Length), path, null);
145
CTLine ellipsis = null;
146
bool ellipsize = li.Width.HasValue && li.TextTrimming == TextTrimming.WordElipsis;
148
ellipsis = new CTLine (CreateAttributedString (li, "..."));
150
float lineHeight = layoutManager.DefaultLineHeightForFont (li.Font);
153
ctx.TextMatrix = CGAffineTransform.MakeScale (1f, -1f);
154
ctx.TranslateCTM ((float)x, (float)y + li.Font.Ascender);
155
foreach (var line in frame.GetLines ()) {
156
ctx.TextPosition = PointF.Empty;
157
if (ellipsize) // we need to create a new CTLine here because the framesetter already truncated the text for the line
158
new CTLine (CreateAttributedString (li, li.Text.Substring (line.StringRange.Location)))
159
.GetTruncatedLine (li.Width.Value, CTLineTruncation.End, ellipsis).Draw (ctx);
162
ctx.TranslateCTM (0, lineHeight);
167
static readonly NSLayoutManager layoutManager = new NSLayoutManager ();