Quantcast
Channel: Adobe Community : All Content - Adobe Animate CC - General
Viewing all articles
Browse latest Browse all 13519

Why is getLineMetrics inaccurate when using device fonts* or immediately after resizing a TextField?

$
0
0

1.  We need getLineMetrics to return correct values immediately after changing a TextField's width/height or any property that would affect the layout metrics, withouth having to alter other properties like setting the text to itself (p1.text = p1.text).  Currently, if you change the width of a text field to match the stage width for example, getLineMetrics will not return correct values until the next frame.... UNLESS you set the text property.

 

2.  We also need some kind of "stage scaled" event in addition to the "stage resize" event (which only fires when stage scale mode is no_scale), because stage scaling affects the rendered size of device fonts so dramatically that we must call getLineMetrics again.  This is not the case for fonts antialiased for readability, since their size is relatively stable with scaling, as demonstrated by drawing a box around the first line once and then scaling the stage.

 

So those are the problems.  The asterisk in the title of this post is there because it seem that TextField.getLineMetrics is accurate with device fonts, but I cannot take advantage of that accuracy without a way to detect when the player is scaled.  I can only confirm its accuracy at a 1:1 scale, since there is no way to recalculate the size of the line rectangle once the player is scaled, aside from setting a timer of some sort which is a real hack not to mention horribly inefficient with no way to detect when the stage has actually be scaled.

 

I use device fonts because embedded fonts look terrible and blurred compared to device font rendering.  The "use device font" setting matches the appearance of text in web browsers exactly.  The only way to get embedded/advanced antialiased text in flash to approximate that of the device font look is to primarily set gridFitType to PIXEL instead of SUBPIXEL, and secondly set autokerning to true to fix problems caused by the PIXEL grid fit type.  That ensure strokes are fitted solidly to the nearest pixel, however it still lacks the "ClearType" rendering that device fonts use, which has notable color offset to improve appearance on LCD monitors, rather than the purely grayscale text that flash uses in its subpixel rendering.  Frankly, failure to use device fonts because of API issues, is the only reason why Flash sometimes doesn't look as good as HTML text and why people say text in Flash "looks blurry".  I'm tired of hearing it.  If the player simply dispatched an event when scaled and updated the metrics immediately when any property of the text field that would affect the metrics is changed, then we could all happily use device fonts and Flash text would look great.  As is stands, because of the two problems I mentioned in the opening paragraph, we're stuck dealing with these problems.
FontComparison.png

 

 

 

If you create two text fields named "p1" and "p2" for paragraph 1 and 2, populate them with an identical line of text and set one to "use device fonts" and the other to "antialias for readability", then use this code to draw boxes around the first line of text in each of them:

 

import flash.text.TextField;

import flash.text.TextLineMetrics;

graphics.clear();

drawBoxAroundLine( p1, 0 );

drawBoxAroundLine( p2, 0 );

function drawBoxAroundLine( tf:TextField, line_index:int ):void

{

          var gutter:Number = 2;

          var tlm:TextLineMetrics = tf.getLineMetrics( line_index );

          graphics.lineStyle( 0, 0x0000ff );

          graphics.drawRect( tf.x + gutter, tf.y + gutter, tlm.width, tlm.height );

}

 

The box surrounding the line of text in the "use device fonts" box is way off at first.  Scaling the player demonstrates that the text width of the device font field fluctuates wildly, while the "antialias for readability" field scales with the originally drawn rectangle perfectly.  That much is fine, but again to clarify the problems I mentioned at the top of this post:

 

Since the text width fluctuates wildly upon player resize, assuming that getLineMetrics actually works on device fonts (and that's an assumption at this point), you'd have to detect the player resize and redraw the text.  Unfortunately, Flash does not fire the player resize event unless the stage scale mode is set to NO_SCALE.  That's problem #1.  And if that's by design, then they should definitely add a SCALE event, because changes in player scale dramatically affect device font layout, which requires recalculation of text metrics.  It's a real issue for fluid layouts.

 

The second problem is that even when handling the resize event, and for example setting the text field width's to match the Stage.stageWidth property, when the text line wraps, it's not updated until the next frame.  In other words, at the exact resize event that causes a word to wrap, calling getLineMetrics in this handler reports the previous line length before the last word on the line wrapped.  So it's delayed a frame.  The only way to get the correct metrics immediately is basically to set the text property to itself like "p1.text = p1.text".  That seems to force an update of the metrics.  Otherwise, it's delayed, and useles.  I wrote about this in an answer over a year ago, showing how sensitive the text field property order is: http://stackoverflow.com/a/9558597/88409


Viewing all articles
Browse latest Browse all 13519

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>