开发者

Silverlight: Glyphs Width

开发者 https://www.devze.com 2023-02-16 15:11 出处:网络
Scenario I want to use Glyphs on WP7 to create a line of text that is justified, i.e. touches the left and right border of the surrounding rectangle.

Scenario

I want to use Glyphs on WP7 to create a line of text that is justified, i.e. touches the left and right border of the surrounding rectangle.

My solution

var gly开发者_运维百科phs = new Glyphs();
glyphs.FontUri = new Uri("/MyAssembly;component/MyPath/MyFont.ttf", UriKind.Relative);
glyphs.FontRenderingEmSize = 20;
glyphs.Fill = new SolidColorBrush(Colors.Red);

// measue width of space
glyphs.UnicodeString = " ";
glyphs.Measure(availableSize);
double spaceWidth = glyphs.DesiredSize.Width;
glyphs.InvalidateMeasure();

// setup justified text
string text = "Lorem Ipsum is dummy text of the printing and typesetting industry.";
int spaceCount = 10; // number of spaces in above text

glyphs.UnicodeString = text;
glyphs.Measure(availableSize); // now DesiredSize.Width = width of left aligned text

// I suspect my error to be in this formula:
double spaceAdvance = ((availableSize.Width - glyphs.DesiredSize.Width) 
                       / spaceCount + spaceWidth) / glyphs.FontRenderingEmSize * 100;
string spaceAdvanceString = String.Format(",{0};", spaceAdvance);

var indices = new StringBuilder();
foreach (char c in text)
{
    if (c == ' ')   indices.Append(spaceAdvanceString);
    else            indices.Append(';');
}
glyphs.Indices = indices.ToString();

Problem and Question

The right side of the glyphs is not exactly touching the availableSize.Width-Border but is some pixels off, and that looks weired when there are several lines of text stacked up.

What is wrong with my calculation?


This could be down to problems with floating point accuracy.

Generally speaking, every floating-point arithmetic operation introduces an error at least equal to the machine accuracy (i.e. the smallest number that, when added to 1.0, produces a floating-point result that is different from 1.0) into the result. This error is known as roundoff error. Roundoff errors are cumulative and sometimes dependent on the order of operations.

Instead of

double spaceAdvance = ((availableSize.Width - glyphs.DesiredSize.Width)
         / spaceCount + spaceWidth) / glyphs.FontRenderingEmSize * 100;

try moving the multiplication to the front, i.e.

double spaceAdvance = 100.0 * ((availableSize.Width - glyphs.DesiredSize.Width)
         / spaceCount + spaceWidth) / glyphs.FontRenderingEmSize;

Alternatively, you could also try

double spaceAdvance = (100.0 * (availableSize.Width - glyphs.DesiredSize.Width)
         / spaceCount + 100.0 * spaceWidth) / glyphs.FontRenderingEmSize;


Alternative proposal: You can use the RichTextBox control which supports "justify".


What about layout rounding?

var glyphs = new Glyphs();
glyphs.FontUri = new Uri("/MyAssembly;component/MyPath/MyFont.ttf", UriKind.Relative);
glyphs.FontRenderingEmSize = 20;
glyphs.Fill = new SolidColorBrush(Colors.Red);
glyphs.UseLayoutRounding = false;

Also, you may want to experiment with ActualWidth instead of DesiredSize.Width

double spaceAdvance = ((availableSize.Width - glyphs.ActualWidth) / 
             spaceCount + spaceWidth) / glyphs.FontRenderingEmSize * 100.0;
0

精彩评论

暂无评论...
验证码 换一张
取 消