[CoreText] CTParagraphStyle uses the incorrect float return type. Fixes bug 54148. (#1975)

* [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

* Add comment about the weird Dispose method implementation in CreateFromSettings
This commit is contained in:
Alex Soto 2017-04-10 01:24:25 -05:00 коммит произвёл Rolf Bjarne Kvinge
Родитель 2a85ec1674
Коммит 3fe0d2010a
3 изменённых файлов: 186 добавлений и 25 удалений

Просмотреть файл

@ -375,7 +375,9 @@ namespace XamCore.CoreText {
} }
handle = CTParagraphStyleCreate (settings, settings.Length); 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; i = 0;
foreach (var e in specifiers) { foreach (var e in specifiers) {
e.Dispose (values, i); e.Dispose (values, i);
@ -431,51 +433,121 @@ namespace XamCore.CoreText {
get {return (CTWritingDirection) GetByteValue (CTParagraphStyleSpecifier.BaseWritingDirection);} get {return (CTWritingDirection) GetByteValue (CTParagraphStyleSpecifier.BaseWritingDirection);}
} }
public float FirstLineHeadIndent { public
#if XAMCORE_4_0
nfloat
#else
float
#endif
FirstLineHeadIndent {
get { return GetFloatValue (CTParagraphStyleSpecifier.FirstLineHeadIndent); } get { return GetFloatValue (CTParagraphStyleSpecifier.FirstLineHeadIndent); }
} }
unsafe float GetFloatValue (CTParagraphStyleSpecifier spec) unsafe
#if XAMCORE_4_0
nfloat
#else
float
#endif
GetFloatValue (CTParagraphStyleSpecifier spec)
{ {
float value; nfloat value;
if (!CTParagraphStyleGetValueForSpecifier (handle, spec, sizeof (float), &value)) if (!CTParagraphStyleGetValueForSpecifier (handle, spec, (nuint) sizeof (nfloat), &value))
throw new InvalidOperationException ("Unable to get property value."); throw new InvalidOperationException ("Unable to get property value.");
return value; return
#if !XAMCORE_4_0
(float)
#endif
value;
} }
public float HeadIndent { public
#if XAMCORE_4_0
nfloat
#else
float
#endif
HeadIndent {
get { return GetFloatValue (CTParagraphStyleSpecifier.HeadIndent); } get { return GetFloatValue (CTParagraphStyleSpecifier.HeadIndent); }
} }
public float TailIndent { public
#if XAMCORE_4_0
nfloat
#else
float
#endif
TailIndent {
get { return GetFloatValue (CTParagraphStyleSpecifier.TailIndent); } get { return GetFloatValue (CTParagraphStyleSpecifier.TailIndent); }
} }
public float DefaultTabInterval { public
#if XAMCORE_4_0
nfloat
#else
float
#endif
DefaultTabInterval {
get { return GetFloatValue (CTParagraphStyleSpecifier.DefaultTabInterval); } get { return GetFloatValue (CTParagraphStyleSpecifier.DefaultTabInterval); }
} }
public float LineHeightMultiple { public
#if XAMCORE_4_0
nfloat
#else
float
#endif
LineHeightMultiple {
get { return GetFloatValue (CTParagraphStyleSpecifier.LineHeightMultiple); } get { return GetFloatValue (CTParagraphStyleSpecifier.LineHeightMultiple); }
} }
public float MaximumLineHeight { public
#if XAMCORE_4_0
nfloat
#else
float
#endif
MaximumLineHeight {
get { return GetFloatValue (CTParagraphStyleSpecifier.MaximumLineHeight); } get { return GetFloatValue (CTParagraphStyleSpecifier.MaximumLineHeight); }
} }
public float MinimumLineHeight { public
#if XAMCORE_4_0
nfloat
#else
float
#endif
MinimumLineHeight {
get { return GetFloatValue (CTParagraphStyleSpecifier.MinimumLineHeight); } get { return GetFloatValue (CTParagraphStyleSpecifier.MinimumLineHeight); }
} }
public float LineSpacing { public
#if XAMCORE_4_0
nfloat
#else
float
#endif
LineSpacing {
get { return GetFloatValue (CTParagraphStyleSpecifier.LineSpacing); } get { return GetFloatValue (CTParagraphStyleSpecifier.LineSpacing); }
} }
public float ParagraphSpacing { public
#if XAMCORE_4_0
nfloat
#else
float
#endif
ParagraphSpacing {
get { return GetFloatValue (CTParagraphStyleSpecifier.ParagraphSpacing); } get { return GetFloatValue (CTParagraphStyleSpecifier.ParagraphSpacing); }
} }
public float ParagraphSpacingBefore { public
#if XAMCORE_4_0
nfloat
#else
float
#endif
ParagraphSpacingBefore {
get { return GetFloatValue (CTParagraphStyleSpecifier.ParagraphSpacingBefore); } get { return GetFloatValue (CTParagraphStyleSpecifier.ParagraphSpacingBefore); }
} }
#endregion #endregion

Просмотреть файл

@ -0,0 +1,88 @@
//
// Unit tests for CTParagraphStyle
//
// Authors:
// Alex Soto <alexsoto@microsoft.com>
//
// 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

Просмотреть файл

@ -649,6 +649,7 @@
<Compile Include="AVFoundation\PlayerItemVideoOutputTest.cs" /> <Compile Include="AVFoundation\PlayerItemVideoOutputTest.cs" />
<Compile Include="mono\ConfigTest.cs" /> <Compile Include="mono\ConfigTest.cs" />
<Compile Include="OpenGLES\EAGLContext.cs" /> <Compile Include="OpenGLES\EAGLContext.cs" />
<Compile Include="CoreText\CTParagraphStyleTests.cs" />
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\iOS\Xamarin.iOS.CSharp.targets" /> <Import Project="$(MSBuildExtensionsPath)\Xamarin\iOS\Xamarin.iOS.CSharp.targets" />
<ItemGroup> <ItemGroup>