The “Flash vs. HTML5” series has covered bitmap drawing pretty well by now, but what about text rendering? Virtually every game has text in it and sometimes a lot. Quest text, name tags, button labels, tooltips, and so on combine to fill the screen with quite a bit of the stuff. So how does Flash’s text rendering compare with that of HTML5? Read on to find out!

Much like the bitmap tests, today’s test draws 10,000 strings to a canvas‘s “2d” context for HTML5 and a BitmapData for Flash. Two strings are used- a short string (“the”) mostly to measure overhead and a long string (a sentence) to reduce overhead. The result is an unintelligible garble of overlapping strings, but the visual representation isn’t the point. If you want to see more clearly, just lower the REPS variable to some small value like 10. Try out the tests to see for yourself and then check out my results below.

Launch the HTML5 version
Launch the Flash version

Here is the source code for the Flash version:

	import flash.geom.Matrix;
	import flash.text.TextFormat;
	import flash.geom.Rectangle;
	import flash.utils.getTimer;
	import flash.text.TextFieldAutoSize;
	import flash.display.StageScaleMode;
	import flash.display.StageAlign;
	import flash.text.TextField;
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.Sprite;
	public class TextTest extends Sprite
		private var shortTF:TextField;
		private var longTF:TextField;
		private var screenBMD:BitmapData;
		private var screenRect:Rectangle;
		private var drawMat:Matrix;
		private var time:TextField;
		public function TextTest()
			stage.align = StageAlign.TOP_LEFT;
			stage.scaleMode = StageScaleMode.NO_SCALE;
			screenRect = new Rectangle(0, 0, stage.stageWidth, stage.stageHeight);
			screenBMD = new BitmapData(640, 480);
			addChild(new Bitmap(screenBMD));
			drawMat = new Matrix();
			var textFormat:TextFormat = new TextFormat();
			textFormat.size = 12;
			textFormat.color = 0xff000000;
			shortTF = new TextField();
			shortTF.autoSize = TextFieldAutoSize.LEFT;
			shortTF.defaultTextFormat = textFormat;
			shortTF.text = "the";
			longTF = new TextField();
			longTF.autoSize = TextFieldAutoSize.LEFT;
			longTF.defaultTextFormat = textFormat;
			longTF.text = "the quick brown fox jumped over the lazy dog";
			makeButtons("Short", "Long");
			time = new TextField();
			time.text = "Time: 9999";
			time.autoSize = TextFieldAutoSize.LEFT;
			time.x = stage.stageWidth - time.width;
			time.y = stage.stageHeight - time.height;
			time.background = true;
			time.backgroundColor = 0xffffffff;
		private function makeButtons(...labels): Number
			const PAD:Number = 5;
			var curX:Number = PAD;
			var curY:Number = stage.stageHeight - PAD;
			for each (var label:String in labels)
				if (label == null)
					curX = PAD;
					curY -= button.height + PAD;
				var tf:TextField = new TextField();
				tf.mouseEnabled = false;
				tf.selectable = false;
				tf.defaultTextFormat = new TextFormat("_sans");
				tf.autoSize = TextFieldAutoSize.LEFT;
				tf.text = label; = "lbl";
				var button:Sprite = new Sprite();
				button.buttonMode = true;;, 0, tf.width+PAD, tf.height+PAD);;;, 0, tf.width+PAD, tf.height+PAD);
				button.addEventListener(MouseEvent.CLICK, onButton);
				if (curX + button.width > stage.stageWidth - PAD)
					curX = PAD;
					curY -= button.height + PAD;
				button.x = curX;
				button.y = curY - button.height;
				curX += button.width + PAD;
			return curY - button.height;
		private function onButton(ev:MouseEvent): void
			var mode:String ="lbl").text;
			switch (mode)
				case "Short":
				case "Long":
		private function test(tf:TextField): void
			var REPS:int = 10000;
			var maxX:int = screenRect.width - tf.width;
			var maxY:int = screenRect.height - tf.height;
			var beforeTime:int = getTimer();
			screenBMD.fillRect(screenRect, 0xffffffff);
			for (var i:int = 0; i < REPS; ++i)
				drawMat.tx = Math.random()*maxX;
				drawMat.ty = Math.random()*maxY;
				screenBMD.draw(tf, drawMat);
			var afterTime:int = getTimer();
			time.text = "Time: " + (afterTime-beforeTime); 

You can get the source code of the HTML5 version by simply opening up the HTML file.

Here are the devices tested:

MacBook Pro Retina 2.3 GHz Intel Core i7 NVIDIA GeForce GT 650M OS X 10.8.3
Windows Desktop 3.4 GHz Intel Core i7 2600 Nvidia GeForce GTX 550 Ti Windows 7 SP 1
iPad 2 1 GHz ARM Cortex-A9 PowerVR SGX543MP2 iOS 6.1.3
LG Optimus G 1.5 GHz Qualcomm Krait Qualcomm Adreno 320 Android 4.1
HTC Evo V 4G 1.2 GHz Qualcomm Snapdragon Qualcomm Adreno 220 Android 4.0
Motorola Xoom 1 GHz NVIDIA Tegra 2 T20 NVIDIA Tegra 2 T20 Android 4.1

And here are the results:

Device Short Long
HTC Evo V 4G – Android 4 Browser 349 1081
HTC Evo V 4G – Google Chrome 27 503 1585
Apple iPad 2 – Safari 165 419
LG Optimus G – Android Browser 418 881
LG Optimus G – Google Chrome 27 309 609
Motorola Xoom – Android 4 Browser 301 1104
Motorola Xoom – Google Chrome 27 221 564
MacBook Pro Retina – Google Chrome 27 40 84
MacBook Pro Retina – Firefox 21 119 305
MacBook Pro Retina – Safari 6 26 94
MacBook Pro Retina – Flash Player 11.7 509 673
Windows Desktop – Google Chrome 27 38 98
Windows Desktop – Firefox 21 152 278
Windows Desktop – Internet Explorer 10 124 202
Windows Desktop – Flash Player 11.7 310 570

Performance Graph (all)

Performance Graph (Windows, Mac)

Performance Graph (mobile)

From this data we can draw some interesting conclusions:

  • Flash renders text 3-8x slower than HTML5 depending on OS, browser, and string length
  • Flash’s text rendering is so slow that it is about on par with HTML5 on mobile despite a huge CPU advantage
  • All browsers and Flash take about 2-3x longer to render the long text than the short text despite the long text being 15x longer than the short text. Overhead is costly in text rendering!
  • Safari on iOS is 2-3x faster than the Android Browser or Chrome for Android on devices with similar CPUs (e.g. iPad 2 is similar to Motorola Xoom)
  • On desktops, Firefox is about 3x slower than Chrome and marginally slower than Internet Explorer. Safari is on par with Chrome and essentially ties for best performance.
  • On mobile, there is no clear winner between the Android Browser and Chrome. Sometimes Chrome is faster than Android Browser and sometimes not. Sometimes one is 2x faster than the other.

As seems to be the theme with this series of articles, you need to plan for quite a lot of variation based on OS and browser if you’re going the HTML5 route. Targeting such a wide array means that you’ll need to expect up to a 12x difference in performance from the fastest desktop to the slowest mobile, more if you’re counting older mobile devices like iPad 1. Even on the same device you can expect a 2-3x performance gap depending on browser choice. And one thing’s for certain: if you’re going with Flash you need to expect very slow text rendering compared to HTML5. Make good use of cacheAsBitmap or GPU textures for those strings that don’t change frequently&em;most of them&em;and you may even see a performance advantage over HTML5 as in previous articles in this series.

As a disclaimer with mobile, there are many devices out there with wildly different performance characteristics. Even iOS has five base models of iPad, six of the iPhone, and five of the iPod Touch. There are hundreds to thousands of Android devices. It’s therefore really hard to get a complete picture of mobile performance since very few people have access to so many devices. I certainly don’t. However, I’m guessing many people reading this article have a couple of minutes to point their mobile browsers at the above tests. Want to contribute your own test results? Post a comment with your device name, short and long times, and if you have them or can look them up, CPU and GPU specs.