TextFields still broken

Hi,
I have just updated my Haxe libs and now textfields are broken: autosizing centered texts cut away a part of them on the right, but only if they are bigger than… about 50-60 pixels, and I have problems also trying to get their bounds with getBounds: I get 0 for both width and height.
Searching in the forum I noticed that this problem is coming out periodically…

So it worked before you updated? Do you remember which version it was?

Are you using openfl legacy?

Does it work on flash? What target are you using?

Sorry, I missed a few details.
Yes, it worked before update, in particular I am talking about HTML5 target, the problem with textfields is there. In Flash everything is ok as before.

No legacy.

Old versions were Lime 2.5.2 + OpenFl 3.2.2

Could you share a small code sample that reproduces the problem? There’s been a ton of TextField, but I would not be surprised if there are same cases we aren’t handling just yet :slight_smile:

Looks similar to the problem I exposed with a code sample there: Application crash (Black screen) on android with openfl legacy

Hello everybody,

I registered only for that issue; I am new in the Haxe as well as OOP + GUI programming and I was quite frustrated by those bugs which prevent the TextField to show; in addition to show it pixelated or with a bad rendering in most of platforms; I am not sure how to solve all the issues or do workarounds but I’ve been messing with it a couple of days.

I can make the TextField work almost everywhere, as long as in native platforms I use -Dlegacy however in android when a TextField gets a TextFormat assigned to the property the whole TextField doesn’t appear anymore even if it is actually there.

The next code sample can shows what I mean:

package;

import openfl.text.TextFormatAlign;
import openfl.text.TextFormat;
import openfl.display.Sprite;
import openfl.text.TextField;
import openfl.events.MouseEvent;

class Main extends Sprite
{
    private var messageField:TextField;
    function new(){
        super();
        var messageFormat:TextFormat = new TextFormat("Verdana", 24, 0xFF0000);
        messageFormat.align = TextFormatAlign.LEFT;

        messageField = new TextField();
        messageField.width = 500;
        messageField.x = messageField.y = 10;
        messageField.defaultTextFormat = messageFormat;
        messageField.text = #if !mobile "<move the mouse>" #else "<touch the screen>" #end ;
        addChild(messageField);
        stage.addEventListener(MouseEvent.MOUSE_MOVE, MouseProcess);
    }

    private function text(txt:String) { messageField.text = txt; }
    private function MouseProcess(cursor:MouseEvent):Void {
        text('(${ cursor.stageX }, ${ cursor.stageY })');
        trace("It is happening: (${ cursor.stageX }, ${ cursor.stageY })");
    }
}

Note that embedding the font or use -Dlegacy doesn’t help; just to remove the code about the format.

I compiled and had success with the next targets (despite pixelated results in all except IOS and bitfive):

haxelib run lime test project.xml html5 -j16 # works, also with bitfive :smiley: 
haxelib run lime test project.xml cpp -j16 # works
haxelib run lime test project.xml ios -j16 -Dlegacy -simulator  # Works surprisingly good

I spent a huge amount of time in the next ones:

haxelib run lime test project.xml android -j16 -Dlegacy # Doesn't show text
haxelib run lime test project.xml flash -j16  # Doesn't work, if it compiles at all

My setup (up to date from today via haxelib):

actuate: 1.8.3 [1.8.6]
....
haxelib_client: [3.2.0-rc.3]
hxcpp: [3.2.102] 3.2.81
openfl-bitfive: 3.0.0 [3.3.3]
openfl-html5-dom: [1.2.2]
openfl-html5: [1.0.5]
openfl-native: [1.4.0]
openfl-samples: 2.2.2 [3.3.0]
openfl-tools: [1.0.10]
openfl: 3.0.1 3.0.2 3.0.6 3.0.8 3.3.1 [3.3.3]

Let me now If I can provide any additional information; including the issues with the pixelated rendering (it certainly doesn’t look like a scaled vectorial graphic :frowning: )

@Thomas_Bernard: yes, it looks like the origin of your problem is similar.

@nudpiedo: this one looks a worse problem, pretty different.

@singmajesty: tomorrow I will try to isolate the problem in a small piece of code.

Did you test the “AddingText” and “PiratePig” samples? If yes, can you see the textfields in those?
Actually your problem is strange because I have no problem to display textfields on android (whether compiled with openfl legacy or openfl next) with openfl version 3.3.3 (apppart from the small alignment bug I mentionned before with text.wrap = true and that has now beeing fixed by singmajesty on openfl git version :slight_smile: )
Your problem is probably linked to the fact that the “Verdana” font is not correctly recognised. Did you embeded this font and are you sure you called it exactly this way in you project.xml file?

Hello,

Thank you for the fast answer.

As @Thomas_Bernard supposed the problem was that in Android the font was not found and instead of fallback in a default one it just didn’t show any of them (and somehow I missed the warning in the debug outputs); that didn’t happen in any of the other targets including CPP.

As soon as I embedded one from the Assets it worked on every target except html-bitfive which doesn’t implement this functionality yet. I wonder why I couldn’t embed Verdana from my system :confused:

The problem with the ugly rendering (showing pixelated) I will report it later in a separate thread, because at the moment the only way I see to have a clean defined font is to use a dom based HTML (where the rendering falls in the browser side).

For other targets where it was working, this was probably because the “verdana” font already existed in the system you where testing it. In android, there is no such font by default. So if it can’t found the embedded verdana font, it can’t fall back to a “verdana” font provided by your system. Whereas with fash or windows, it probably is able to recover this font directly from the system (if this font is installed) if the embedded font import has failed…
For the ugly rendering, I don’t have any pixelated rendering on android, flash or windows (whatever the font I use) targets. Not tested on html5 with latest openfl versions yet so I can’t say for this one.

1 Like

In the recent releases something has been fixed, but today I have found and fixed a bug that caused part of the problem I explained at first.

When I use getColorBoundsRect on a BitmapData I expect to receive a Rectangle and nothing more, and in Flash it works like that, but not in HTML5.
In HTML5 something breaks, and I found out what: in the Image.hx class the getColorBoundsRect function switches between CANVAS, DATA and FLASH

public function getColorBoundsRect (mask:Int, color:Int, findColor:Bool = true, format:PixelFormat = null):Rectangle {
		
	if (buffer == null) return null;
		
	switch (type) {
			
		case CANVAS:
				
			#if (js && html5)
			ImageCanvasUtil.convertToData (this);
			#end
				
			return ImageDataUtil.getColorBoundsRect (this, mask, color, findColor, format);
			
		case DATA:
				
			return ImageDataUtil.getColorBoundsRect (this, mask, color, findColor, format);
			
		case FLASH:
				
			var rect = buffer.__srcBitmapData.getColorBoundsRect (mask, color, findColor);
			return new Rectangle (rect.x, rect.y, rect.width, rect.height);
			
		default:
				
			return null;
	}
		
}

What’s happening in the CANVAS case? And in particular when the condition #if (js && html5) is true? The instance of the current Image is converted to data, losing the original BitmapData I am working on!

I fixed this by cloning the instance (tempClone) and passing the clone to the function below for conversion

case CANVAS:
	var tempClone: Image = new Image(this.buffer.clone());
	#if (js && html5)
	ImageCanvasUtil.convertToData (tempClone);
	#end
				
	return ImageDataUtil.getColorBoundsRect (tempClone, mask, color, findColor, format);

Fixed! Now I can get a correct Rectangle without destroying the original BitmapData! If you think a more efficient method exists please tell me here. If you think this is a coherent bug-fix it can be committed for a next release.

somebody push this to github?

I could do it (I just need to remember how…), but before committing this change I’d like to know if somebody knows a better way to do it.

On HTML5, Images (usually) begin as an HTML5 Image. When you make certain modifications, (or create from scratch) it becomes a Canvas. If you read or modify pixels, CanvasImageData is read. Depending on the operations, this is synced back to the source Canvas, or remains as a data array.

Calling getColorBoundsRect should create the image data array (if it does not exist), but should not destroy the original image. If you have an example of how the image is damaged by calling getColorBoundsRect, please let me know. (does this commit make a difference? https://github.com/openfl/lime/commit/4b5e649da18af6bf58907e06ca1f22d69992f869)

Well, you could test that with the small project I sent you, do you remember the null rectangle?

Yes, that modification fix the problem (restoring the original Image.hx) : it looks like I made my fix a few hours before I downloaded the fixed Lime (2.6.9) :smiley:
Ok, ignore my fix, now it works ok.

UPDATE: it looks like getColorBoundsRect behaves differently in hTML5 from browser to browser, and the result is that I have different results. Is it possible that JS behaves differently from browser to browser in operations like this one?

UPDATE: it looks like lime.graphics.Image.getColorBoundsRect (targeting HTML5) does NOTHING! I still have to clone image itself to avoid destruction by ImageCanvasUtil.convertToData, and I obtain a rectangle as big as the initial image, even if it has transparent pixels around and I want to cut them out. Please fix this, it is driving me crazy!

I am reading getColorBoundsRect in ImageDataUtil trying to understand why it does not return the trimmed rectangle.

P.S.: I have upgraded to the last Openfl/lime, but I found out that this function never worked correctly when targeting HTML5


UPDATE2: the problem is a very old one: when I update a textfield in HTML5 I can get a textfield with a cut out section on the right, so if I try to get the Rectangle of a text set on-the-fly I could obtain an empty or a smaller one. It is like the text box/mask is wrongly updated when changing the content of a textfield, and it depends by text length, I think.

UPDATE 3:
I created a small class to reproduce the problem, so if you want you can test it by yourself:
Textfields in HTML5 have always been a terrible problem for me, and the cause is… AUTOALIGN, and if I am not wrong it is a very old and never fixed bug.

I think the problems are in TextField.hx (maybe __updateLayout) or/and in TextEngine (maybe setTextAlignment() and update()), but I didn’t understand how the textfield width is calculated.
If you activate the textfield border you can also see that textfield width grows more than expected when setting long strings: it adds empty space on the right.

This example:

  • instances 2 textfields, WITHOUT autosize enabled
  • after 2 seconds it enables autosize
  • later it tests text strings with growing lengths: 1 character string never shows up, and the following ones are ok, even if in some cases (sometimes yes, sometimes no) you can see a delayed horizontal alignment after text changes, as if it was desynchronized from text update.

The results change by initializing textfields in different ways, with string of different lengths and size.
Aligning and autosizing texts to the LEFT everything seems to show correctly, I think the problem arises when texts are aligned to CENTER or RIGHT.

I can’t find a workaround to bypass this problem and I am lost.

Source code follows:

    package;

    import motion.Actuate;
    import openfl.display.BitmapData;
    import openfl.display.DisplayObject;
    import openfl.display.Shape;
    import openfl.display.Sprite;
    import openfl.geom.Matrix;
    import openfl.geom.Rectangle;
    import openfl.text.TextField;
    import openfl.text.TextFieldAutoSize;
    import openfl.text.TextFormat;
    import openfl.text.TextFormatAlign;


    class Main extends Sprite {
    	private var xRef: Shape;
    	private var xRef2: Shape;
    	private var yRef: Shape;
    	private var tf: TextField;
    	private var tf2: TextField;

    	public function new() {
    		super();
    		
    		// reference lines for alignment
    		xRef = new Shape();
    		xRef.graphics.beginFill(0xffffff);
    		xRef.graphics.drawRect(0, 0, 1, 600);
    		xRef.graphics.endFill();
    		xRef.x = 300;
    		xRef.y = 100;
    		addChild(xRef);
    		
    		xRef2 = new Shape();
    		xRef2.graphics.beginFill(0xffffff);
    		xRef2.graphics.drawRect(0, 0, 1, 600);
    		xRef2.graphics.endFill();
    		xRef2.x = 800;
    		xRef2.y = 100;
    		addChild(xRef2);
    		
    		yRef = new Shape();
    		yRef.graphics.beginFill(0xffffff);
    		yRef.graphics.drawRect(0, 0, 1000, 1);
    		yRef.graphics.endFill();
    		yRef.x = 100;
    		yRef.y = 300;
    		addChild(yRef);
    		
    		//----------------------------------------------------------
    		// TEXT WITH INITIAL WIDTH SET
    		var tfFormat: TextFormat = new TextFormat();
    		tfFormat.size = 30;
    		tfFormat.color = 0xff0000;
    		tfFormat.align = TextFormatAlign.CENTER;
    		
    		tf = new TextField();
    		tf.selectable = false;
    		tf.width = 300;									// width set
    		tf.border = true;
    		tf.borderColor = 0xffffff;
    		//tf.autoSize = TextFieldAutoSize.LEFT;			// not enabled yet
    		tf.defaultTextFormat = tfFormat;
    		
    		tf.x = xRef.x;
    		this.addChild(tf);
    		
    		// -----
    		// TEXT WITH INITIAL WIDTH NOT SET
    		tf2 = new TextField();
    		tf2.selectable = false;
    		//tf2.width = 300;									// width NOT set
    		tf2.border = false;
    //		tf2.wordWrap = true;
    		tf2.borderColor = 0xffffff;
    		//tf2.autoSize = TextFieldAutoSize.LEFT;			// not enabled yet
    		tf2.defaultTextFormat = tfFormat;
    		
    		tf2.x = xRef2.x;
    		this.addChild(tf2);
    		
    		// test ----------------------------------------------------
    		
    		changeText("CIAOCIAOCIAO");
    		
    		Actuate.timer(2).onComplete(autosize);							// activate autosize -> cut the text
    		Actuate.timer(5).onComplete(changeText, ["I"]);					// autosize is wrong, the text is completely cut out
    		Actuate.timer(7).onComplete(changeText, ["IA"]);
    		Actuate.timer(9).onComplete(changeText, ["IAT"]);
    		Actuate.timer(11).onComplete(changeText, ["IATA"]);
    		Actuate.timer(13).onComplete(changeText, ["IATAT"]);
    		Actuate.timer(15).onComplete(changeText, ["IATATA"]);
    		Actuate.timer(17).onComplete(changeText, ["IATATAT"]);
    		Actuate.timer(19).onComplete(changeText, ["IATATATA"]);
    	}
    	
    	private function changeText(text: String): Void {
    		trace("--- CHANGE TEXT ---> " + text);
    		tf.text = text;
    		tf2.text = text;
    		
    		// align vertically considering pixels, not text bounds
    		var tfTrimmedRectangle: Rectangle;
    		tfTrimmedRectangle = getTrimmedRectangle(tf);
    		tf.y = yRef.y - tfTrimmedRectangle.y - tfTrimmedRectangle.height;
    		
    		tfTrimmedRectangle = getTrimmedRectangle(tf2);
    		tf2.y = yRef.y - tfTrimmedRectangle.y - tfTrimmedRectangle.height;
    	}
    	
    	private function autosize(text: String): Void {
    		trace("--- ACTIVATE AUTOSIZE ---");
    		tf.autoSize = TextFieldAutoSize.CENTER;
    		tf2.autoSize = TextFieldAutoSize.CENTER;
    	}
    	
    	private function getTrimmedRectangle(target: DisplayObject): Rectangle {
    		var bounds: Rectangle = target.getBounds(target);
    		
    		var bmd: BitmapData = new BitmapData(Math.ceil(bounds.width), Math.ceil(bounds.height), false, 0xabcdef);
    		bmd.draw(target, new Matrix(1, 0, 0, 1, -bounds.x, -bounds.y), null, null, null, false);
    		return  bmd.getColorBoundsRect(0x00FFFFFF, 0xabcdef, false);
    	}
    }

Another example of wrong text rendering: I thought Left alignment was safe, but it has problems, in this example the textbox cuts out a part of the text, that is not correctly wrapped too.
I haven’t got a clue on where I can see to fix the problem, and I think it is not a small one, as a lot of texts in different situations are wrong.

To see the differences target HTML5 first (the bugged one) and then Flash (correct).

package;

import openfl.display.Sprite;
import openfl.text.TextField;
import openfl.text.TextFieldAutoSize;
import openfl.text.TextFormat;
import openfl.text.TextFormatAlign;

class Main extends Sprite 
{
	public function new()
	{
		super();
		var textInstance : TextField = new TextField();
		var textInstance2 : TextField = new TextField();
		var txtFormat : TextFormat = new TextFormat(30, null);
		
		txtFormat.color = Std.parseInt("0xFF0000");
		txtFormat.align = TextFormatAlign.LEFT;
		
		textInstance.defaultTextFormat = txtFormat;
		textInstance.width = 500;
		textInstance.multiline = true;
		textInstance.wordWrap = true;
		textInstance.autoSize = TextFieldAutoSize.LEFT;
		textInstance.border = true;
		textInstance.borderColor = 0xFF0000;
		textInstance.x = 150;
		textInstance.y = 50;
		textInstance.text = "CIOO CIOO CIOOCIOOCIOOCIOOC IOOCIOOCIOOCIOO CIOOCIOOCIOOCIOOCIOOCIOO   CIOOCIOOCIOO ";
		
		textInstance2.defaultTextFormat = txtFormat;
		textInstance2.width = 500;
		textInstance2.multiline = true;
		textInstance2.wordWrap = true;
		textInstance2.autoSize = TextFieldAutoSize.LEFT;
		textInstance2.border = true;
		textInstance2.borderColor = 0xFF0000;
		textInstance2.x = 150;
		textInstance2.y = 250;
		textInstance2.text = "CIOO CIOO CIOOCIOOCIOOCIOOCIOOCIOOCIOOCIOO CIOOCIOOCIOOCIOOCIOOCIOO   CIOOCIOOCIOO ";
		
		addChild(textInstance);
		addChild(textInstance2);
	}
}

I have the same issue : TextFieldAutoSize.CENTER doesn’t behave correctly on html5 target, only the default ( left ) works

It’s kinda hard to isolate the problem, since multiline, wordWrap, width and height all seem to break at the same time

Workaround : i had better results centering using TextFormatAlign.CENTER in TextFormat, instead of using the autosize property ( which I left by default )