// Class: openfl._internal.text.TextEngine

var $global = typeof window != "undefined" ? window : typeof global != "undefined" ? global : typeof self != "undefined" ? self : this

$global.Object.defineProperty(exports, "__esModule", {value: true});

var __map_reserved = {};

// Imports

var $hxClasses = require("./../../../hxClasses_stub").default;
var $import = require("./../../../import_stub").default;
function EReg() {return require("./../../../EReg");}
function lime_text__$UTF8String_UTF8String_$Impl_$() {return require("./../../../lime/text/_UTF8String/UTF8String_Impl_");}
function Std() {return require("./../../../Std");}
function openfl__$Vector_Vector_$Impl_$() {return require("./../../../openfl/_Vector/Vector_Impl_");}
function openfl_text_TextField() {return require("./../../../openfl/text/TextField");}
function js_Browser() {return require("./../../../js/Browser");}
function openfl__$internal_text_TextLayoutGroup() {return require("./../../../openfl/_internal/text/TextLayoutGroup");}
function haxe_ds_StringMap() {return require("./../../../haxe/ds/StringMap");}
function openfl_text_Font() {return require("./../../../openfl/text/Font");}
function StringTools() {return require("./../../../StringTools");}
function openfl_geom_Rectangle() {return require("./../../../openfl/geom/Rectangle");}

// Constructor

var TextEngine = function(textField) {
	this.textField = textField;
	this.width = 100;
	this.height = 100;
	this.set_text("");
	this.bounds = new (openfl_geom_Rectangle().default)(0,0,0,0);
	this.textBounds = new (openfl_geom_Rectangle().default)(0,0,0,0);
	this.type = "dynamic";
	this.autoSize = "none";
	this.embedFonts = false;
	this.selectable = true;
	this.borderColor = 0;
	this.border = false;
	this.backgroundColor = 16777215;
	this.background = false;
	this.gridFitType = "pixel";
	this.maxChars = 0;
	this.multiline = false;
	this.sharpness = 0;
	this.scrollH = 0;
	this.scrollV = 1;
	this.wordWrap = false;
	this.lineAscents = (openfl__$Vector_Vector_$Impl_$().default)._new();
	this.lineBreaks = (openfl__$Vector_Vector_$Impl_$().default)._new();
	this.lineDescents = (openfl__$Vector_Vector_$Impl_$().default)._new();
	this.lineLeadings = (openfl__$Vector_Vector_$Impl_$().default)._new();
	this.lineHeights = (openfl__$Vector_Vector_$Impl_$().default)._new();
	this.lineWidths = (openfl__$Vector_Vector_$Impl_$().default)._new();
	this.layoutGroups = (openfl__$Vector_Vector_$Impl_$().default)._new();
	this.textFormatRanges = (openfl__$Vector_Vector_$Impl_$().default)._new();
	TextEngine.__canvas = (js_Browser().default).get_document().createElement("canvas");
	TextEngine.__context = TextEngine.__canvas.getContext("2d");
}

// Meta

TextEngine.__name__ = ["openfl","_internal","text","TextEngine"];
TextEngine.prototype = {
	createRestrictRegexp: function(restrict) {
		var declinedRange = new (EReg().default)("\\^(.-.|.)","gu");
		var declined = "";
		var accepted = declinedRange.map(restrict,function(ereg) {
			declined += ereg.matched(1);
			return "";
		});
		var testRegexpParts = [];
		if(accepted.length > 0) {
			testRegexpParts.push("[^" + restrict + "]");
		}
		if(declined.length > 0) {
			testRegexpParts.push("[" + declined + "]");
		}
		return new (EReg().default)("(" + testRegexpParts.join("|") + ")","g");
	},
	getBounds: function() {
		var padding = this.border ? 1 : 0;
		this.bounds.width = this.width + padding;
		this.bounds.height = this.height + padding;
		var x = this.width;
		var y = this.width;
		var _g = 0;
		var _g1 = this.layoutGroups;
		while(_g < _g1.get_length()) {
			var group = _g1[_g];
			++_g;
			if(group.offsetX < x) {
				x = group.offsetX;
			}
			if(group.offsetY < y) {
				y = group.offsetY;
			}
		}
		if(x >= this.width) {
			x = 2;
		}
		if(y >= this.height) {
			y = 2;
		}
		this.textBounds.setTo(Math.max(x - 2,0),Math.max(y - 2,0),Math.min(this.textWidth + 4,this.bounds.width + 4),Math.min(this.textHeight + 4,this.bounds.height + 4));
	},
	getLine: function(index) {
		if(index < 0 || index > this.lineBreaks.get_length() + 1) {
			return null;
		}
		if(this.lineBreaks.get_length() == 0) {
			return this.text;
		} else {
			return (lime_text__$UTF8String_UTF8String_$Impl_$().default).substring(this.text,index > 0 ? this.lineBreaks[index - 1] : 0,this.lineBreaks[index]);
		}
	},
	getLineBreakIndex: function(startIndex) {
		if(startIndex == null) {
			startIndex = 0;
		}
		var br = (lime_text__$UTF8String_UTF8String_$Impl_$().default).indexOf(this.text,"<br>",startIndex);
		var cr = (lime_text__$UTF8String_UTF8String_$Impl_$().default).indexOf(this.text,"\n",startIndex);
		var lf = (lime_text__$UTF8String_UTF8String_$Impl_$().default).indexOf(this.text,"\r",startIndex);
		if(cr == -1 && br == -1) {
			return lf;
		}
		if(lf == -1 && br == -1) {
			return cr;
		}
		if(lf == -1 && cr == -1) {
			return br;
		}
		if(cr == -1) {
			return (Std().default)["int"](Math.min(br,lf));
		}
		if(lf == -1) {
			return (Std().default)["int"](Math.min(br,cr));
		}
		if(br == -1) {
			return (Std().default)["int"](Math.min(cr,lf));
		}
		return (Std().default)["int"](Math.min(Math.min(cr,lf),br));
	},
	getLineMeasurements: function() {
		this.lineAscents.set_length(0);
		this.lineDescents.set_length(0);
		this.lineLeadings.set_length(0);
		this.lineHeights.set_length(0);
		this.lineWidths.set_length(0);
		var currentLineAscent = 0.0;
		var currentLineDescent = 0.0;
		var currentLineLeading = null;
		var currentLineHeight = 0.0;
		var currentLineWidth = 0.0;
		var currentTextHeight = 0.0;
		this.textWidth = 0;
		this.textHeight = 0;
		this.numLines = 1;
		this.bottomScrollV = 0;
		this.maxScrollH = 0;
		var _g = 0;
		var _g1 = this.layoutGroups;
		while(_g < _g1.get_length()) {
			var group = _g1[_g];
			++_g;
			while(group.lineIndex > this.numLines - 1) {
				(openfl__$Vector_Vector_$Impl_$().default).push(this.lineAscents,currentLineAscent);
				(openfl__$Vector_Vector_$Impl_$().default).push(this.lineDescents,currentLineDescent);
				(openfl__$Vector_Vector_$Impl_$().default).push(this.lineLeadings,currentLineLeading != null ? currentLineLeading : 0);
				(openfl__$Vector_Vector_$Impl_$().default).push(this.lineHeights,currentLineHeight);
				(openfl__$Vector_Vector_$Impl_$().default).push(this.lineWidths,currentLineWidth);
				currentLineAscent = 0;
				currentLineDescent = 0;
				currentLineLeading = null;
				currentLineHeight = 0;
				currentLineWidth = 0;
				this.numLines++;
				if(this.textHeight <= this.height - 2) {
					this.bottomScrollV++;
				}
			}
			currentLineAscent = Math.max(currentLineAscent,group.ascent);
			currentLineDescent = Math.max(currentLineDescent,group.descent);
			if(currentLineLeading == null) {
				currentLineLeading = group.leading;
			} else {
				currentLineLeading = (Std().default)["int"](Math.max(currentLineLeading,group.leading));
			}
			currentLineHeight = Math.max(currentLineHeight,group.height);
			currentLineWidth = group.offsetX - 2 + group.width;
			if(currentLineWidth > this.textWidth) {
				this.textWidth = currentLineWidth;
			}
			currentTextHeight = group.offsetY - 2 + group.ascent + group.descent;
			if(currentTextHeight > this.textHeight) {
				this.textHeight = currentTextHeight;
			}
		}
		if(this.textHeight == 0 && this.textField != null && this.textField.get_type() == "input") {
			var currentFormat = this.textField.__textFormat;
			var ascent;
			var descent;
			var leading;
			var heightValue;
			if(currentFormat.__ascent != null) {
				ascent = currentFormat.size * currentFormat.__ascent;
				descent = currentFormat.size * currentFormat.__descent;
			} else {
				ascent = currentFormat.size;
				descent = currentFormat.size * 0.185;
			}
			leading = currentFormat.leading;
			heightValue = ascent + descent + leading;
			currentLineAscent = ascent;
			currentLineDescent = descent;
			currentLineLeading = leading;
			currentTextHeight = ascent + descent;
			this.textHeight = currentTextHeight;
		}
		(openfl__$Vector_Vector_$Impl_$().default).push(this.lineAscents,currentLineAscent);
		(openfl__$Vector_Vector_$Impl_$().default).push(this.lineDescents,currentLineDescent);
		(openfl__$Vector_Vector_$Impl_$().default).push(this.lineLeadings,currentLineLeading != null ? currentLineLeading : 0);
		(openfl__$Vector_Vector_$Impl_$().default).push(this.lineHeights,currentLineHeight);
		(openfl__$Vector_Vector_$Impl_$().default).push(this.lineWidths,currentLineWidth);
		if(this.numLines == 1) {
			this.bottomScrollV = 1;
			if(currentLineLeading > 0) {
				this.textHeight += currentLineLeading;
			}
		} else if(this.textHeight <= this.height - 2) {
			this.bottomScrollV++;
		}
		if(this.autoSize != "none") {
			var _g2 = this.autoSize;
			switch(_g2) {
			case "center":case "left":case "right":
				if(!this.wordWrap) {
					this.width = this.textWidth + 4;
				}
				this.height = this.textHeight + 4;
				this.bottomScrollV = this.numLines;
				break;
			default:
			}
		}
		if(this.textWidth > this.width - 4) {
			this.maxScrollH = (Std().default)["int"](this.textWidth - this.width + 4);
		} else {
			this.maxScrollH = 0;
		}
		this.maxScrollV = this.numLines - this.bottomScrollV + 1;
		if(this.scrollV > this.maxScrollV) {
			this.scrollV = this.maxScrollV;
		}
		if(this.scrollH > this.maxScrollH) {
			this.scrollH = this.maxScrollH;
		}
	},
	getLayoutGroups: function() {
		var _gthis = this;
		this.layoutGroups.set_length(0);
		if(this.text == null || (lime_text__$UTF8String_UTF8String_$Impl_$().default).equals(this.text,"")) {
			return;
		}
		var rangeIndex = -1;
		var formatRange = null;
		var font = null;
		var currentFormat = (openfl_text_TextField().default).__defaultTextFormat.clone();
		var leading = 0;
		var ascent = 0.0;
		var maxAscent = 0.0;
		var descent = 0.0;
		var layoutGroup = null;
		var positions = null;
		var widthValue = 0.0;
		var heightValue = 0.0;
		var maxHeightValue = 0.0;
		var previousSpaceIndex = -2;
		var spaceIndex = (lime_text__$UTF8String_UTF8String_$Impl_$().default).indexOf(this.text," ");
		var breakIndex = this.getLineBreakIndex();
		var offsetX = 2.0;
		var offsetY = 2.0;
		var textIndex = 0;
		var lineIndex = 0;
		var lineFormat = null;
		var getPositions = function(text,startIndex,endIndex) {
			var positions1 = [];
			var letterSpacing = 0.0;
			if(formatRange.format.letterSpacing != null) {
				letterSpacing = formatRange.format.letterSpacing;
			}
			if(_gthis.__useIntAdvances == null) {
				var getPositions1 = new (EReg().default)("Trident/7.0","");
				_gthis.__useIntAdvances = getPositions1.match((js_Browser().default).get_navigator().userAgent);
			}
			if(_gthis.__useIntAdvances) {
				var previousWidth = 0.0;
				var width;
				var _g1 = startIndex;
				var _g = endIndex;
				while(_g1 < _g) {
					var i = _g1++;
					width = TextEngine.__context.measureText((lime_text__$UTF8String_UTF8String_$Impl_$().default).substring(text,startIndex,i + 1)).width;
					positions1.push(width - previousWidth);
					previousWidth = width;
				}
			} else {
				var _g11 = startIndex;
				var _g2 = endIndex;
				while(_g11 < _g2) {
					var i1 = _g11++;
					var advance;
					if(i1 < (lime_text__$UTF8String_UTF8String_$Impl_$().default).get_length(text) - 1) {
						var nextWidth = TextEngine.__context.measureText((lime_text__$UTF8String_UTF8String_$Impl_$().default).charAt(text,i1 + 1)).width;
						var twoWidths = TextEngine.__context.measureText((lime_text__$UTF8String_UTF8String_$Impl_$().default).substr(text,i1,2)).width;
						advance = twoWidths - nextWidth;
					} else {
						advance = TextEngine.__context.measureText((lime_text__$UTF8String_UTF8String_$Impl_$().default).charAt(text,i1)).width;
					}
					positions1.push(advance);
				}
			}
			return positions1;
		};
		var getPositionsWidth = function(positions2) {
			var width1 = 0.0;
			var _g3 = 0;
			while(_g3 < positions2.length) {
				var position = positions2[_g3];
				++_g3;
				width1 += position;
			}
			return width1;
		};
		var getTextWidth = function(text1) {
			return TextEngine.__context.measureText(text1).width;
		};
		var nextLayoutGroup = function(startIndex1,endIndex1) {
			if(layoutGroup == null || layoutGroup.startIndex != layoutGroup.endIndex) {
				layoutGroup = new (openfl__$internal_text_TextLayoutGroup().default)(formatRange.format,startIndex1,endIndex1);
				(openfl__$Vector_Vector_$Impl_$().default).push(_gthis.layoutGroups,layoutGroup);
			} else {
				layoutGroup.format = formatRange.format;
				layoutGroup.startIndex = startIndex1;
				layoutGroup.endIndex = endIndex1;
			}
		};
		var nextFormatRange = function() {
			var nextFormatRange1 = _gthis.textFormatRanges.get_length() - 1;
			if(rangeIndex < nextFormatRange1) {
				rangeIndex += 1;
				formatRange = _gthis.textFormatRanges[rangeIndex];
				currentFormat.__merge(formatRange.format);
				TextEngine.__context.font = TextEngine.getFont(currentFormat);
				font = TextEngine.getFontInstance(currentFormat);
				if(currentFormat.__ascent != null) {
					ascent = currentFormat.size * currentFormat.__ascent;
					descent = currentFormat.size * currentFormat.__descent;
				} else if(font != null && font.unitsPerEM != 0) {
					ascent = font.ascender / font.unitsPerEM * currentFormat.size;
					descent = Math.abs(font.descender / font.unitsPerEM * currentFormat.size);
				} else {
					ascent = currentFormat.size;
					descent = currentFormat.size * 0.185;
				}
				leading = currentFormat.leading;
				heightValue = ascent + descent + leading;
			}
			if(heightValue > maxHeightValue) {
				maxHeightValue = heightValue;
			}
			if(ascent > maxAscent) {
				maxAscent = ascent;
			}
		};
		var alignBaseline = function() {
			if(ascent > maxAscent) {
				maxAscent = ascent;
			}
			if(heightValue > maxHeightValue) {
				maxHeightValue = heightValue;
			}
			var i2 = _gthis.layoutGroups.get_length();
			while(--i2 > -1) {
				var lg = _gthis.layoutGroups[i2];
				if(lg.lineIndex < lineIndex) {
					break;
				}
				if(lg.lineIndex > lineIndex) {
					continue;
				}
				lg.ascent = maxAscent;
				lg.height = maxHeightValue;
			}
			offsetY += maxHeightValue;
			maxAscent = 0.0;
			maxHeightValue = 0.0;
			lineIndex += 1;
			offsetX = 2;
		};
		var breakLongWords = function(endIndex2) {
			var tempWidth = (lime_text__$UTF8String_UTF8String_$Impl_$().default).substring(_gthis.text,textIndex,endIndex2);
			var tempWidth1 = getTextWidth(tempWidth);
			while(offsetX + tempWidth1 > _gthis.width - 2) {
				var i3 = 1;
				while(textIndex + i3 < endIndex2 + 1) {
					var tempWidth2 = (lime_text__$UTF8String_UTF8String_$Impl_$().default).substr(_gthis.text,textIndex,i3);
					tempWidth1 = getTextWidth(tempWidth2);
					if(offsetX + tempWidth1 > _gthis.width - 2) {
						--i3;
						break;
					}
					++i3;
				}
				if(i3 == 0 && tempWidth1 > _gthis.width - 4) {
					i3 = (lime_text__$UTF8String_UTF8String_$Impl_$().default).get_length(_gthis.text);
				}
				if(i3 == 0) {
					offsetX = 2;
					offsetY += layoutGroup.height;
					lineIndex += 1;
					break;
				} else {
					nextLayoutGroup(textIndex,textIndex + i3);
					layoutGroup.positions = getPositions(_gthis.text,textIndex,textIndex + i3);
					layoutGroup.offsetX = offsetX;
					layoutGroup.ascent = ascent;
					layoutGroup.descent = descent;
					layoutGroup.leading = leading;
					layoutGroup.lineIndex = lineIndex;
					layoutGroup.offsetY = offsetY;
					layoutGroup.width = getPositionsWidth(layoutGroup.positions);
					layoutGroup.height = heightValue;
					layoutGroup = null;
					alignBaseline();
					textIndex += i3;
					positions = getPositions(_gthis.text,textIndex,endIndex2);
					widthValue = getPositionsWidth(positions);
					tempWidth1 = widthValue;
				}
			}
		};
		nextFormatRange();
		lineFormat = formatRange.format;
		var wrap;
		var maxLoops = (lime_text__$UTF8String_UTF8String_$Impl_$().default).get_length(this.text) + 1;
		while(textIndex < maxLoops) if(breakIndex > -1 && (spaceIndex == -1 || breakIndex < spaceIndex) && formatRange.end >= breakIndex) {
			if(textIndex <= breakIndex) {
				if(this.wordWrap && previousSpaceIndex <= textIndex && this.width >= 4) {
					breakLongWords(breakIndex);
				}
				nextLayoutGroup(textIndex,breakIndex);
				layoutGroup.positions = getPositions(this.text,textIndex,breakIndex);
				layoutGroup.offsetX = offsetX;
				layoutGroup.ascent = ascent;
				layoutGroup.descent = descent;
				layoutGroup.leading = leading;
				layoutGroup.lineIndex = lineIndex;
				layoutGroup.offsetY = offsetY;
				layoutGroup.width = getPositionsWidth(layoutGroup.positions);
				layoutGroup.height = heightValue;
				layoutGroup = null;
			} else if(layoutGroup != null && layoutGroup.startIndex != layoutGroup.endIndex) {
				if(layoutGroup.endIndex == spaceIndex) {
					layoutGroup.width -= layoutGroup.getAdvance(layoutGroup.positions.length - 1);
				}
				layoutGroup = null;
			}
			if(formatRange.end == breakIndex) {
				nextFormatRange();
				lineFormat = formatRange.format;
			}
			if(breakIndex >= (lime_text__$UTF8String_UTF8String_$Impl_$().default).get_length(this.text) - 1) {
				offsetY -= maxHeightValue;
			}
			alignBaseline();
			textIndex = breakIndex + 1;
			breakIndex = this.getLineBreakIndex(textIndex);
		} else if(formatRange.end >= spaceIndex && spaceIndex > -1 && textIndex < formatRange.end) {
			if(layoutGroup != null && layoutGroup.startIndex != layoutGroup.endIndex) {
				layoutGroup = null;
			}
			wrap = false;
			while(textIndex != formatRange.end) {
				var endIndex3 = -1;
				if(spaceIndex == -1) {
					endIndex3 = breakIndex;
				} else {
					endIndex3 = spaceIndex + 1;
					if(breakIndex > -1 && breakIndex < endIndex3) {
						endIndex3 = breakIndex;
					}
				}
				if(endIndex3 == -1 || endIndex3 > formatRange.end) {
					endIndex3 = formatRange.end;
				}
				positions = getPositions(this.text,textIndex,endIndex3);
				widthValue = getPositionsWidth(positions);
				if(lineFormat.align == "justify") {
					if(positions.length > 0 && textIndex == previousSpaceIndex) {
						textIndex += 1;
						var spaceWidth = positions.shift();
						widthValue -= spaceWidth;
						offsetX += spaceWidth;
					}
					if(positions.length > 0 && endIndex3 == spaceIndex + 1) {
						--endIndex3;
						var spaceWidth1 = positions.pop();
						widthValue -= spaceWidth1;
					}
				}
				if(this.wordWrap) {
					if(offsetX + widthValue > this.width - 2) {
						wrap = true;
						if(positions.length > 0 && endIndex3 == spaceIndex + 1) {
							var lastPosition = positions[positions.length - 1];
							var spaceWidth2 = lastPosition;
							if(offsetX + widthValue - spaceWidth2 <= this.width - 2) {
								wrap = false;
							}
						}
					}
				}
				if(wrap) {
					if(lineFormat.align != "justify" && (layoutGroup != null || this.layoutGroups.get_length() > 0)) {
						var previous = layoutGroup;
						if(previous == null) {
							previous = this.layoutGroups[this.layoutGroups.get_length() - 1];
						}
						previous.width -= previous.getAdvance(previous.positions.length - 1);
						previous.endIndex--;
					}
					var i4 = this.layoutGroups.get_length() - 1;
					var offsetCount = 0;
					while(true) {
						layoutGroup = this.layoutGroups[i4];
						if(i4 > 0 && layoutGroup.startIndex > previousSpaceIndex) {
							++offsetCount;
						} else {
							break;
						}
						--i4;
					}
					if(textIndex == previousSpaceIndex + 1) {
						alignBaseline();
					}
					offsetX = 2;
					if(offsetCount > 0) {
						var bumpX = this.layoutGroups[this.layoutGroups.get_length() - offsetCount].offsetX;
						var _g12 = this.layoutGroups.get_length() - offsetCount;
						var _g4 = this.layoutGroups.get_length();
						while(_g12 < _g4) {
							var i5 = _g12++;
							layoutGroup = this.layoutGroups[i5];
							layoutGroup.offsetX -= bumpX;
							layoutGroup.offsetY = offsetY;
							layoutGroup.lineIndex = lineIndex;
							offsetX += layoutGroup.width;
						}
					}
					if(this.width >= 4) {
						breakLongWords(endIndex3);
					}
					nextLayoutGroup(textIndex,endIndex3);
					layoutGroup.positions = positions;
					layoutGroup.offsetX = offsetX;
					layoutGroup.ascent = ascent;
					layoutGroup.descent = descent;
					layoutGroup.leading = leading;
					layoutGroup.lineIndex = lineIndex;
					layoutGroup.offsetY = offsetY;
					layoutGroup.width = widthValue;
					layoutGroup.height = heightValue;
					offsetX += widthValue;
					textIndex = endIndex3;
					wrap = false;
				} else {
					if(layoutGroup != null && textIndex == spaceIndex) {
						if(lineFormat.align != "justify") {
							layoutGroup.endIndex = spaceIndex;
							layoutGroup.positions = layoutGroup.positions.concat(positions);
							layoutGroup.width += widthValue;
						}
					} else if(layoutGroup == null || lineFormat.align == "justify") {
						nextLayoutGroup(textIndex,endIndex3);
						layoutGroup.positions = positions;
						layoutGroup.offsetX = offsetX;
						layoutGroup.ascent = ascent;
						layoutGroup.descent = descent;
						layoutGroup.leading = leading;
						layoutGroup.lineIndex = lineIndex;
						layoutGroup.offsetY = offsetY;
						layoutGroup.width = widthValue;
						layoutGroup.height = heightValue;
					} else {
						layoutGroup.endIndex = endIndex3;
						layoutGroup.positions = layoutGroup.positions.concat(positions);
						layoutGroup.width += widthValue;
						if(breakIndex == endIndex3) {
							++endIndex3;
						}
					}
					offsetX += widthValue;
					textIndex = endIndex3;
				}
				var nextSpaceIndex = (lime_text__$UTF8String_UTF8String_$Impl_$().default).indexOf(this.text," ",textIndex);
				if(formatRange.end <= previousSpaceIndex) {
					layoutGroup = null;
					textIndex = formatRange.end;
					nextFormatRange();
				} else {
					if(breakIndex == previousSpaceIndex) {
						layoutGroup.endIndex = breakIndex;
						if(breakIndex - layoutGroup.startIndex - layoutGroup.positions.length < 0) {
							layoutGroup.positions.push(0.0);
						}
						textIndex = breakIndex + 1;
					}
					previousSpaceIndex = spaceIndex;
					spaceIndex = nextSpaceIndex;
				}
				var tmp;
				var tmp1;
				if(!(breakIndex > -1 && breakIndex <= textIndex && (spaceIndex > breakIndex || spaceIndex == -1))) {
					var tmp2 = (lime_text__$UTF8String_UTF8String_$Impl_$().default).get_length(this.text);
					tmp1 = textIndex > tmp2;
				} else {
					tmp1 = true;
				}
				if(!tmp1) {
					tmp = spaceIndex > formatRange.end;
				} else {
					tmp = true;
				}
				if(tmp) {
					break;
				}
			}
		} else {
			if(textIndex > formatRange.end) {
				break;
			} else {
				var tmp3;
				if(textIndex >= formatRange.end) {
					var tmp4 = (lime_text__$UTF8String_UTF8String_$Impl_$().default).get_length(this.text);
					tmp3 = textIndex == tmp4;
				} else {
					tmp3 = true;
				}
				if(tmp3) {
					if(this.wordWrap && this.width >= 4) {
						breakLongWords(formatRange.end);
					}
					positions = getPositions(this.text,textIndex,formatRange.end);
					widthValue = getPositionsWidth(positions);
					nextLayoutGroup(textIndex,formatRange.end);
					layoutGroup.positions = getPositions(this.text,textIndex,formatRange.end);
					layoutGroup.offsetX = offsetX;
					layoutGroup.ascent = ascent;
					layoutGroup.descent = descent;
					layoutGroup.leading = leading;
					layoutGroup.lineIndex = lineIndex;
					layoutGroup.offsetY = offsetY;
					layoutGroup.width = getPositionsWidth(layoutGroup.positions);
					layoutGroup.height = heightValue;
					offsetX += widthValue;
					textIndex = formatRange.end;
				}
			}
			nextFormatRange();
			if(textIndex == formatRange.end) {
				alignBaseline();
				textIndex += 1;
				break;
			}
		}
	},
	restrictText: function(value) {
		if(value == null) {
			return value;
		}
		if(this.__restrictRegexp != null) {
			value = this.__restrictRegexp.split(value).join("");
		}
		return value;
	},
	setTextAlignment: function() {
		var lineIndex = -1;
		var offsetX = 0.0;
		var totalWidth = this.width - 4;
		var group;
		var lineLength;
		var lineMeasurementsDirty = false;
		var _g1 = 0;
		var _g = this.layoutGroups.get_length();
		while(_g1 < _g) {
			var i = _g1++;
			group = this.layoutGroups[i];
			if(group.lineIndex != lineIndex) {
				lineIndex = group.lineIndex;
				var _g2 = group.format.align;
				switch(_g2) {
				case "center":
					if(this.lineWidths[lineIndex] < totalWidth) {
						offsetX = Math.round((totalWidth - this.lineWidths[lineIndex]) / 2);
					} else {
						offsetX = 0;
					}
					break;
				case "justify":
					if(this.lineWidths[lineIndex] < totalWidth) {
						lineLength = 1;
						var _g3 = i + 1;
						var _g21 = this.layoutGroups.get_length();
						while(_g3 < _g21) {
							var j = _g3++;
							if(this.layoutGroups[j].lineIndex == lineIndex) {
								if(j == 0 || (lime_text__$UTF8String_UTF8String_$Impl_$().default).charCodeAt(this.text,this.layoutGroups[j].startIndex - 1) == 32) {
									++lineLength;
								}
							} else {
								break;
							}
						}
						if(lineLength > 1) {
							group = this.layoutGroups[i + lineLength - 1];
							var endChar = (lime_text__$UTF8String_UTF8String_$Impl_$().default).charCodeAt(this.text,group.endIndex);
							if(group.endIndex < (lime_text__$UTF8String_UTF8String_$Impl_$().default).get_length(this.text) && endChar != 10 && endChar != 13) {
								offsetX = (totalWidth - this.lineWidths[lineIndex]) / (lineLength - 1);
								lineMeasurementsDirty = true;
								var j1 = 1;
								while(true) {
									this.layoutGroups[i + j1].offsetX += offsetX * j1;
									if(!(++j1 < lineLength)) {
										break;
									}
								}
							}
						}
					}
					offsetX = 0;
					break;
				case "right":
					if(this.lineWidths[lineIndex] < totalWidth) {
						offsetX = Math.round(totalWidth - this.lineWidths[lineIndex]);
					} else {
						offsetX = 0;
					}
					break;
				default:
					offsetX = 0;
				}
			}
			if(offsetX > 0) {
				group.offsetX += offsetX;
			}
		}
		if(lineMeasurementsDirty) {
			this.getLineMeasurements();
		}
	},
	trimText: function(value) {
		if(value == null) {
			return value;
		}
		if(this.maxChars > 0 && (lime_text__$UTF8String_UTF8String_$Impl_$().default).get_length(value) > this.maxChars) {
			value = (lime_text__$UTF8String_UTF8String_$Impl_$().default).substr(value,0,this.maxChars);
		}
		return value;
	},
	update: function() {
		if(this.text == null || this.textFormatRanges.get_length() == 0) {
			this.lineAscents.set_length(0);
			this.lineBreaks.set_length(0);
			this.lineDescents.set_length(0);
			this.lineLeadings.set_length(0);
			this.lineHeights.set_length(0);
			this.lineWidths.set_length(0);
			this.layoutGroups.set_length(0);
			this.textWidth = 0;
			this.textHeight = 0;
			this.numLines = 1;
			this.maxScrollH = 0;
			this.maxScrollV = 1;
			this.bottomScrollV = 1;
		} else {
			this.getLayoutGroups();
			this.getLineMeasurements();
			this.setTextAlignment();
		}
		this.getBounds();
	},
	set_restrict: function(value) {
		if((lime_text__$UTF8String_UTF8String_$Impl_$().default).equals(this.restrict,value)) {
			return this.restrict;
		}
		this.restrict = value;
		if(this.restrict == null || (lime_text__$UTF8String_UTF8String_$Impl_$().default).get_length(this.restrict) == 0) {
			this.__restrictRegexp = null;
		} else {
			this.__restrictRegexp = this.createRestrictRegexp(value);
		}
		return this.restrict;
	},
	set_text: function(value) {
		return this.text = value;
	}
};
TextEngine.prototype.__class__ = TextEngine.prototype.constructor = $hxClasses["openfl._internal.text.TextEngine"] = TextEngine;

// Init



// Statics

TextEngine.findFont = function(name) {
	return (openfl_text_Font().default).__fontByName.get(name);
}
TextEngine.findFontVariant = function(format) {
	var fontName = format.font;
	var bold = format.bold;
	var italic = format.italic;
	if(fontName == null) {
		fontName = "_serif";
	}
	var fontNamePrefix = (StringTools().default).replace((StringTools().default).replace(fontName," Normal","")," Regular","");
	if(bold && italic && (openfl_text_Font().default).__fontByName.exists(fontNamePrefix + " Bold Italic")) {
		return TextEngine.findFont(fontNamePrefix + " Bold Italic");
	} else if(bold && (openfl_text_Font().default).__fontByName.exists(fontNamePrefix + " Bold")) {
		return TextEngine.findFont(fontNamePrefix + " Bold");
	} else if(italic && (openfl_text_Font().default).__fontByName.exists(fontNamePrefix + " Italic")) {
		return TextEngine.findFont(fontNamePrefix + " Italic");
	}
	return TextEngine.findFont(fontName);
}
TextEngine.getFormatHeight = function(format) {
	var ascent;
	var descent;
	var leading;
	TextEngine.__context.font = TextEngine.getFont(format);
	var font = TextEngine.getFontInstance(format);
	if(format.__ascent != null) {
		ascent = format.size * format.__ascent;
		descent = format.size * format.__descent;
	} else if(font != null && font.unitsPerEM != 0) {
		ascent = font.ascender / font.unitsPerEM * format.size;
		descent = Math.abs(font.descender / font.unitsPerEM * format.size);
	} else {
		ascent = format.size;
		descent = format.size * 0.185;
	}
	leading = format.leading;
	return ascent + descent + leading;
}
TextEngine.getFont = function(format) {
	var fontName = format.font;
	var bold = format.bold;
	var italic = format.italic;
	if(fontName == null) {
		fontName = "_serif";
	}
	var fontNamePrefix = (StringTools().default).replace((StringTools().default).replace(fontName," Normal","")," Regular","");
	if(bold && italic && (openfl_text_Font().default).__fontByName.exists(fontNamePrefix + " Bold Italic")) {
		fontName = fontNamePrefix + " Bold Italic";
		bold = false;
		italic = false;
	} else if(bold && (openfl_text_Font().default).__fontByName.exists(fontNamePrefix + " Bold")) {
		fontName = fontNamePrefix + " Bold";
		bold = false;
	} else if(italic && (openfl_text_Font().default).__fontByName.exists(fontNamePrefix + " Italic")) {
		fontName = fontNamePrefix + " Italic";
		italic = false;
	} else {
		if(bold && (fontName.indexOf(" Bold ") > -1 || (StringTools().default).endsWith(fontName," Bold"))) {
			bold = false;
		}
		if(italic && (fontName.indexOf(" Italic ") > -1 || (StringTools().default).endsWith(fontName," Italic"))) {
			italic = false;
		}
	}
	var font = italic ? "italic " : "normal ";
	font += "normal ";
	font += bold ? "bold " : "normal ";
	font += format.size + "px";
	font += "/" + (format.leading + format.size + 3) + "px ";
	var font1;
	switch(fontName) {
	case "_sans":
		font1 = "sans-serif";
		break;
	case "_serif":
		font1 = "serif";
		break;
	case "_typewriter":
		font1 = "monospace";
		break;
	default:
		font1 = "'" + new (EReg().default)("^[\\s'\"]+(.*)[\\s'\"]+$","").replace(fontName,"$1") + "'";
	}
	font += "" + font1;
	return font;
}
TextEngine.getFontInstance = function(format) {
	return TextEngine.findFontVariant(format);
}
TextEngine.UTF8_TAB = 9
TextEngine.UTF8_ENDLINE = 10
TextEngine.UTF8_SPACE = 32
TextEngine.UTF8_HYPHEN = 45
TextEngine.__defaultFonts = new (haxe_ds_StringMap().default)()

// Export

exports.default = TextEngine;