From 02ffdfa2f59bf5f156f04ac3f253695f118fae16 Mon Sep 17 00:00:00 2001 From: Alex Soto Date: Sat, 8 Apr 2017 01:13:53 -0500 Subject: [PATCH 1/2] [CoreText] Fix bug 54148 - CoreText.CTParagraphStyle does not pick up settings from CTParagraphStyleSettings https://bugzilla.xamarin.com/show_bug.cgi?id=54148 CTParagraphStyle float properties have the incorrect float return type, the headers state this API's returns CGFloats (aka nfloat) instead of floats this used to work ok fetching them due to there is no difference in size for 32 bits devices but once 64 bit devices appeared the API began to fail The actual method that fetches the values `CTParagraphStyleGetValueForSpecifier` asks for the size of the returned data and we used to give the size of a float which is incorrect in 64 bits devices and the API call just correctly returned false because it could not write back the value to us. Added tests for the full properties available on CTParagraphStyle --- src/CoreText/CTParagraphStyle.cs | 158 +++++++++++++----- .../CoreText/CTParagraphStyleTests.cs | 88 ++++++++++ tests/monotouch-test/monotouch-test.csproj | 1 + 3 files changed, 203 insertions(+), 44 deletions(-) create mode 100644 tests/monotouch-test/CoreText/CTParagraphStyleTests.cs diff --git a/src/CoreText/CTParagraphStyle.cs b/src/CoreText/CTParagraphStyle.cs index 3017cfd1b4db..f7d7537248e1 100644 --- a/src/CoreText/CTParagraphStyle.cs +++ b/src/CoreText/CTParagraphStyle.cs @@ -431,52 +431,122 @@ public CTWritingDirection BaseWritingDirection { get {return (CTWritingDirection) GetByteValue (CTParagraphStyleSpecifier.BaseWritingDirection);} } - public float FirstLineHeadIndent { - get {return GetFloatValue (CTParagraphStyleSpecifier.FirstLineHeadIndent);} - } - - unsafe float GetFloatValue (CTParagraphStyleSpecifier spec) + public +#if XAMCORE_4_0 + nfloat +#else + float +#endif + FirstLineHeadIndent { + get { return GetFloatValue (CTParagraphStyleSpecifier.FirstLineHeadIndent); } + } + + unsafe +#if XAMCORE_4_0 + nfloat +#else + float +#endif + GetFloatValue (CTParagraphStyleSpecifier spec) { - float value; - if (!CTParagraphStyleGetValueForSpecifier (handle, spec, sizeof (float), &value)) + nfloat value; + if (!CTParagraphStyleGetValueForSpecifier (handle, spec, (nuint) sizeof (nfloat), &value)) throw new InvalidOperationException ("Unable to get property value."); - return value; - } - - public float HeadIndent { - get {return GetFloatValue (CTParagraphStyleSpecifier.HeadIndent);} - } - - public float TailIndent { - get {return GetFloatValue (CTParagraphStyleSpecifier.TailIndent);} - } - - public float DefaultTabInterval { - get {return GetFloatValue (CTParagraphStyleSpecifier.DefaultTabInterval);} - } - - public float LineHeightMultiple { - get {return GetFloatValue (CTParagraphStyleSpecifier.LineHeightMultiple);} - } - - public float MaximumLineHeight { - get {return GetFloatValue (CTParagraphStyleSpecifier.MaximumLineHeight);} - } - - public float MinimumLineHeight { - get {return GetFloatValue (CTParagraphStyleSpecifier.MinimumLineHeight);} - } - - public float LineSpacing { - get {return GetFloatValue (CTParagraphStyleSpecifier.LineSpacing);} - } - - public float ParagraphSpacing { - get {return GetFloatValue (CTParagraphStyleSpecifier.ParagraphSpacing);} - } - - public float ParagraphSpacingBefore { - get {return GetFloatValue (CTParagraphStyleSpecifier.ParagraphSpacingBefore);} + return +#if !XAMCORE_4_0 + (float) +#endif + value; + } + + public +#if XAMCORE_4_0 + nfloat +#else + float +#endif + HeadIndent { + get { return GetFloatValue (CTParagraphStyleSpecifier.HeadIndent); } + } + + public +#if XAMCORE_4_0 + nfloat +#else + float +#endif + TailIndent { + get { return GetFloatValue (CTParagraphStyleSpecifier.TailIndent); } + } + + public +#if XAMCORE_4_0 + nfloat +#else + float +#endif + DefaultTabInterval { + get { return GetFloatValue (CTParagraphStyleSpecifier.DefaultTabInterval); } + } + + public +#if XAMCORE_4_0 + nfloat +#else + float +#endif + LineHeightMultiple { + get { return GetFloatValue (CTParagraphStyleSpecifier.LineHeightMultiple); } + } + +public +#if XAMCORE_4_0 + nfloat +#else + float +#endif + MaximumLineHeight { + get { return GetFloatValue (CTParagraphStyleSpecifier.MaximumLineHeight); } + } + + public +#if XAMCORE_4_0 + nfloat +#else + float +#endif + MinimumLineHeight { + get { return GetFloatValue (CTParagraphStyleSpecifier.MinimumLineHeight); } + } + + public +#if XAMCORE_4_0 + nfloat +#else + float +#endif + LineSpacing { + get { return GetFloatValue (CTParagraphStyleSpecifier.LineSpacing); } + } + + public +#if XAMCORE_4_0 + nfloat +#else + float +#endif + ParagraphSpacing { + get { return GetFloatValue (CTParagraphStyleSpecifier.ParagraphSpacing); } + } + + public +#if XAMCORE_4_0 + nfloat +#else + float +#endif + ParagraphSpacingBefore { + get { return GetFloatValue (CTParagraphStyleSpecifier.ParagraphSpacingBefore); } } #endregion } diff --git a/tests/monotouch-test/CoreText/CTParagraphStyleTests.cs b/tests/monotouch-test/CoreText/CTParagraphStyleTests.cs new file mode 100644 index 000000000000..ed8183c33cd3 --- /dev/null +++ b/tests/monotouch-test/CoreText/CTParagraphStyleTests.cs @@ -0,0 +1,88 @@ +// +// Unit tests for CTParagraphStyle +// +// Authors: +// Alex Soto +// +// Copyright 2017 Xamarin Inc. All rights reserved. +// + +#if !__WATCHOS__ + +using System; +using NUnit.Framework; +using System.Linq; + +#if XAMCORE_2_0 +using Foundation; +using CoreText; +#else +using MonoTouch.CoreText; +using MonoTouch.Foundation; +#endif + + +#if XAMCORE_2_0 +using RectangleF = CoreGraphics.CGRect; +using SizeF = CoreGraphics.CGSize; +using PointF = CoreGraphics.CGPoint; +#else +using nfloat = global::System.Single; +using nint = global::System.Int32; +using nuint = global::System.UInt32; +#endif + +namespace MonoTouchFixtures.CoreText { + + [TestFixture] + [Preserve (AllMembers = true)] + public class CTParagraphStyleTests { + + [Test] + public void StylePropertiesTest () + { + var settings = new CTParagraphStyleSettings () { + TailIndent = 5, + ParagraphSpacingBefore = 5, + ParagraphSpacing = 5, + LineSpacing = 5, + MinimumLineHeight = 5, + MaximumLineHeight = 5, + LineHeightMultiple = 5, + DefaultTabInterval = 5, + HeadIndent = 5, + FirstLineHeadIndent = 5, + LineBreakMode = CTLineBreakMode.TruncatingHead, + BaseWritingDirection = CTWritingDirection.Natural, + Alignment = CTTextAlignment.Justified, + TabStops = new [] { + new CTTextTab (CTTextAlignment.Justified, 2), + new CTTextTab (CTTextAlignment.Natural, 1) + } + }; + + var style = new CTParagraphStyle (settings); + Assert.DoesNotThrow (() => { + Assert.AreEqual (settings.TailIndent, style.TailIndent, "TailIndent"); + Assert.AreEqual (settings.ParagraphSpacingBefore, style.ParagraphSpacingBefore, "ParagraphSpacingBefore"); + Assert.AreEqual (settings.ParagraphSpacing, style.ParagraphSpacing, "ParagraphSpacing"); + Assert.AreEqual (settings.LineSpacing, style.LineSpacing, "LineSpacing"); + Assert.AreEqual (settings.MinimumLineHeight, style.MinimumLineHeight, "MinimumLineHeight"); + Assert.AreEqual (settings.MaximumLineHeight, style.MaximumLineHeight, "MaximumLineHeight"); + Assert.AreEqual (settings.LineHeightMultiple, style.LineHeightMultiple, "LineHeightMultiple"); + Assert.AreEqual (settings.DefaultTabInterval, style.DefaultTabInterval, "DefaultTabInterval"); + Assert.AreEqual (settings.HeadIndent, style.HeadIndent, "HeadIndent"); + Assert.AreEqual (settings.FirstLineHeadIndent, style.FirstLineHeadIndent, "FirstLineHeadIndent"); + Assert.AreEqual (settings.LineBreakMode, style.LineBreakMode, "LineBreakMode"); + Assert.AreEqual (settings.BaseWritingDirection, style.BaseWritingDirection, "LineBreakMode"); + Assert.AreEqual (settings.Alignment, style.Alignment, "Alignment"); + + var styleTabStops = style.GetTabStops (); + Assert.AreEqual (settings.TabStops.Count (), styleTabStops.Length, "TabStops"); + Assert.True (styleTabStops.Any (t => t.Location == 2 && t.TextAlignment == CTTextAlignment.Justified)); + Assert.True (styleTabStops.Any (t => t.Location == 1 && t.TextAlignment == CTTextAlignment.Natural)); + }); + } + } +} +#endif diff --git a/tests/monotouch-test/monotouch-test.csproj b/tests/monotouch-test/monotouch-test.csproj index 0a8897f97723..6b49f9189e62 100644 --- a/tests/monotouch-test/monotouch-test.csproj +++ b/tests/monotouch-test/monotouch-test.csproj @@ -649,6 +649,7 @@ + From 334a0f728ebbbe57549b607b0a756cdd457a86da Mon Sep 17 00:00:00 2001 From: Alex Soto Date: Sun, 9 Apr 2017 11:41:07 -0500 Subject: [PATCH 2/2] Add comment about the weird Dispose method implementation in CreateFromSettings --- src/CoreText/CTParagraphStyle.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/CoreText/CTParagraphStyle.cs b/src/CoreText/CTParagraphStyle.cs index f7d7537248e1..6693da15453f 100644 --- a/src/CoreText/CTParagraphStyle.cs +++ b/src/CoreText/CTParagraphStyle.cs @@ -375,7 +375,9 @@ static unsafe IntPtr CreateFromSettings (CTParagraphStyleSettings s) } handle = CTParagraphStyleCreate (settings, settings.Length); } - + // Yes this weird Dispose implementation is correct, this bugzilla + // comment explains more about it. TL;DR: check CTParagraphStyleSpecifierIntPtrsValue + // https://bugzilla.xamarin.com/show_bug.cgi?id=54148#c4 i = 0; foreach (var e in specifiers) { e.Dispose (values, i);