diff -r a6a621b767ed include/Platform.h
--- a/include/Platform.h	Tue Dec 19 15:00:40 2017 +1100
+++ b/include/Platform.h	Wed Dec 20 09:04:18 2017 +1100
@@ -82,6 +82,8 @@
 // Underlying the implementation of the platform classes are platform specific types.
 // Sometimes these need to be passed around by client code so they are defined here
 
+//#define ENABLE_BIDIRECTIONAL 1
+
 typedef void *FontID;
 typedef void *SurfaceID;
 typedef void *WindowID;
@@ -90,6 +92,52 @@
 typedef void *Function;
 typedef void *IdlerID;
 
+#ifdef ENABLE_BIDIRECTIONAL
+typedef const char *CharArray;
+
+struct ScreenLine {
+	const char *s;
+	int len;
+	const XYPOSITION width;
+	const XYPOSITION height;
+	const FontID * stylesFontsIDs;
+	const int ctrlCharPadding;
+	const XYPOSITION tabWidth;
+	const FontID repStyle;
+	const CharArray *lineReprs;
+	const int tabWidthMinimumPixels;
+
+	ScreenLine(
+		const char *s_,
+		int len_,
+		XYPOSITION width_,
+		XYPOSITION height_,
+		FontID *stylesFontsIDs_,
+		int ctrlCharPadding_,
+		XYPOSITION tabWidth_,
+		FontID repStyle_,
+		CharArray *lineReprs_,
+		int tabWidthMinimumPixels_=0
+	) :
+		s(s_),
+		len(len_),
+		width(width_),
+		height(height_),
+		stylesFontsIDs(stylesFontsIDs_),
+		ctrlCharPadding(ctrlCharPadding_),
+		tabWidth(tabWidth_),
+		repStyle(repStyle_),
+		lineReprs(lineReprs_),
+		tabWidthMinimumPixels(tabWidthMinimumPixels_)
+	{}
+
+	int TabStop(XYPOSITION x) const {
+		return static_cast<int>(x / tabWidth);
+	}
+};
+
+#endif
+
 /**
  * A geometric point class.
  * Point is similar to the Win32 POINT and GTK+ GdkPoint types.
@@ -284,6 +332,15 @@
 	friend class SurfaceImpl;
 };
 
+#ifdef ENABLE_BIDIRECTIONAL
+
+class IDrawRectangle {
+public:
+	virtual void Draw(PRectangle rc)=0;
+};
+
+#endif
+
 /**
  * A surface abstracts a place to draw.
  */
@@ -319,6 +376,13 @@
 	virtual void Ellipse(PRectangle rc, ColourDesired fore, ColourDesired back)=0;
 	virtual void Copy(PRectangle rc, Point from, Surface &surfaceSource)=0;
 
+#ifdef ENABLE_BIDIRECTIONAL
+	virtual int PositionFromPoint(const ScreenLine *screenLine, Point pt, bool charPosition)=0;
+	virtual Point XYFromPosition(const ScreenLine *screenLine, int caretPosition)=0;
+	virtual void FillSelectionRectangle(const ScreenLine *screenLine, int start, int end, PRectangle rcLine,
+		int xStart, IDrawRectangle *pDraw)=0;
+#endif
+
 	virtual void DrawTextNoClip(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourDesired fore, ColourDesired back)=0;
 	virtual void DrawTextClipped(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourDesired fore, ColourDesired back)=0;
 	virtual void DrawTextTransparent(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourDesired fore)=0;
diff -r a6a621b767ed win32/PlatWin.cxx
--- a/win32/PlatWin.cxx	Tue Dec 19 15:00:40 2017 +1100
+++ b/win32/PlatWin.cxx	Wed Dec 20 09:04:18 2017 +1100
@@ -543,6 +543,12 @@
 	void Ellipse(PRectangle rc, ColourDesired fore, ColourDesired back) override;
 	void Copy(PRectangle rc, Point from, Surface &surfaceSource) override;
 
+#ifdef ENABLE_BIDIRECTIONAL
+	int PositionFromPoint(const ScreenLine *, Point, bool) override;
+	Point XYFromPosition(const ScreenLine *, int) override;
+	void FillSelectionRectangle(const ScreenLine *, int, int, PRectangle, int, IDrawRectangle *) override;
+#endif
+
 	void DrawTextCommon(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, UINT fuOptions);
 	void DrawTextNoClip(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourDesired fore, ColourDesired back) override;
 	void DrawTextClipped(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourDesired fore, ColourDesired back) override;
@@ -880,6 +886,22 @@
 		static_cast<int>(from.x), static_cast<int>(from.y), SRCCOPY);
 }
 
+#ifdef ENABLE_BIDIRECTIONAL
+
+int SurfaceGDI::PositionFromPoint(const ScreenLine *, Point, bool) {
+	return 0;
+}
+
+Point SurfaceGDI::XYFromPosition(const ScreenLine *, int) {
+	Point pt(-1, -1);
+	return pt;
+}
+
+void SurfaceGDI::FillSelectionRectangle(const ScreenLine *, int, int, PRectangle, int, IDrawRectangle *) {
+}
+
+#endif
+
 typedef VarBuffer<int, stackBufferLength> TextPositionsI;
 
 void SurfaceGDI::DrawTextCommon(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, UINT fuOptions) {
@@ -1098,6 +1120,18 @@
 	void Ellipse(PRectangle rc, ColourDesired fore, ColourDesired back) override;
 	void Copy(PRectangle rc, Point from, Surface &surfaceSource) override;
 
+#ifdef ENABLE_BIDIRECTIONAL
+	int PositionFromPoint(const ScreenLine *screenLine, Point pt, bool charPosition) override;
+	Point XYFromPosition(const ScreenLine *screenLine, int caretPosition) override;
+	void FillSelectionRectangle(const ScreenLine *screenLine, int start, int end, PRectangle rcLine,
+		int xStart, IDrawRectangle *pDraw) override;
+	void FillTextLayoutFormats(const ScreenLine *screenLine, IDWriteTextLayout *textLayout);
+	std::wstring ReplaceRepresentation(const CharArray *lineReprs, int len, const char *s);
+	int GetPositionInLayout(const char *s, int position, const CharArray *lineReprs);
+	int GetPositionInString(const char *s, int position, int len, const CharArray *lineReprs);
+	float FindLostSpace(const ScreenLine *screenLine, int pos, IDWriteTextLayout *textLayout);
+#endif
+
 	void DrawTextCommon(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, UINT fuOptions);
 	void DrawTextNoClip(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourDesired fore, ColourDesired back) override;
 	void DrawTextClipped(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourDesired fore, ColourDesired back) override;
@@ -1550,6 +1584,536 @@
 	}
 }
 
+#ifdef ENABLE_BIDIRECTIONAL
+
+// Get the exact position from the provided point
+int SurfaceD2D::PositionFromPoint(const ScreenLine *screenLine, Point pt, bool charPosition) {
+	// If the text is empty, then no need to go through this function
+	if (!screenLine->len)
+		return 0;
+
+	// Get textFormat
+	FormatAndMetrics *pfm = static_cast<FormatAndMetrics *>(screenLine->stylesFontsIDs[0]);
+
+	if (!pIDWriteFactory || !pfm->pTextFormat) {
+		return -1;
+	}
+
+	// Convert the string to wstring and replace the original control characters with their representative chars.
+	std::wstring buffer =  ReplaceRepresentation(screenLine->lineReprs, screenLine->len, screenLine->s);
+
+	// Create a text layout
+	IDWriteTextLayout *textLayout = 0;
+
+	const HRESULT hrCreate = pIDWriteFactory->CreateTextLayout(buffer.c_str(), static_cast<UINT32>(buffer.length()),
+		pfm->pTextFormat, screenLine->width, screenLine->height, &textLayout);
+	if (!SUCCEEDED(hrCreate)) {
+		return -1;
+	}
+
+	// Fill the textLayout chars with their own formats
+	FillTextLayoutFormats(screenLine, textLayout);
+
+	// Tab is a special case of representation, taking a variable amount of space, the tab space depends on the drawing style tab stop.
+	textLayout->SetIncrementalTabStop(screenLine->tabWidth);
+
+	// Returns the text position corresponding to the mouse x,y.
+	// If hitting the trailing side of a cluster, return the
+	// leading edge of the following text position.
+
+	BOOL isTrailingHit;
+	BOOL isInside;
+	DWRITE_HIT_TEST_METRICS caretMetrics;
+
+	textLayout->HitTestPoint(
+		pt.x,
+		pt.y,
+		&isTrailingHit,
+		&isInside,
+		&caretMetrics
+	);
+
+	/* Sometimes the tab character have a very small space, so more space = tabWidth is added to tab char wisth of this specific position.
+	Also each ctrl char has additional padding after is, so we need to calculate all of this added space,
+	because it's lost in DirectWrite textLayout */
+
+	size_t lastTabPos = buffer.find_last_of(L"\t", caretMetrics.textPosition);
+
+	int currentPosTabStop = 0;
+	float tabStopRemainder = 0.0;
+	int lastTabStop = 0;
+	float spaceBeforeTab = 0.0;
+
+	// Translate text character offset to point x,y.
+	DWRITE_HIT_TEST_METRICS tabCaretMetrics;
+	Point tabPt;
+
+	if (lastTabPos >= 0 && lastTabPos < caretMetrics.textPosition) {
+		spaceBeforeTab = FindLostSpace(screenLine, static_cast<int>(lastTabPos -1), textLayout);
+
+		textLayout->HitTestTextPosition(
+			static_cast<UINT32>(lastTabPos),
+			false, // trailing if false, else leading edge
+			&tabPt.x,
+			&tabPt.y,
+			&tabCaretMetrics
+		);
+		tabStopRemainder = screenLine->tabWidth - fmodf((spaceBeforeTab + tabPt.x), screenLine->tabWidth);
+		lastTabStop = screenLine->TabStop(spaceBeforeTab + tabPt.x);
+		currentPosTabStop = screenLine->TabStop(pt.x);
+	}
+
+	// When a tab doesn't find enough space tabWidthMinimumPixels, it takes more width tabWidth
+	// So if the click position is inside the tab space on screen, then set the pt.x as position in layout
+	if (lastTabPos >= 0 && tabStopRemainder < screenLine->tabWidthMinimumPixels
+			&& roundf(tabStopRemainder) > 0.0 && currentPosTabStop == (lastTabStop + 1)) {
+		pt.x = tabPt.x;
+	} else if (lastTabPos >= 0 && tabStopRemainder < screenLine->tabWidthMinimumPixels &&
+		// And if the click position is before the tab space on screen, then subctract the pt.x the previous lost spaces
+		roundf(tabStopRemainder) > 0.0 && currentPosTabStop < (lastTabStop + 1)) {
+		pt.x -= spaceBeforeTab;
+	} else {
+		// Subtract lost space of ctrl chars and tabs
+		float lostSpace = FindLostSpace(screenLine, caretMetrics.textPosition, textLayout);
+
+		pt.x -= lostSpace;
+	}
+
+	textLayout->HitTestPoint(
+		pt.x,
+		pt.y,
+		&isTrailingHit,
+		&isInside,
+		&caretMetrics
+	);
+
+	DWRITE_HIT_TEST_METRICS hitTestMetrics = {};
+	if (isTrailingHit) {
+		FLOAT caretX = 0.0f;
+		FLOAT caretY = 0.0f;
+
+		// Uses hit-testing to align the current caret position to a whole cluster,
+		// rather than residing in the middle of a base character + diacritic,
+		// surrogate pair, or character + UVS.
+
+		// Align the caret to the nearest whole cluster.
+		textLayout->HitTestTextPosition(
+			caretMetrics.textPosition,
+			false,
+			&caretX,
+			&caretY,
+			&hitTestMetrics
+		);
+	}
+
+	textLayout->Release();
+	int pos;
+	if (charPosition) {
+		pos = isTrailingHit ? hitTestMetrics.textPosition : caretMetrics.textPosition;
+	} else {
+		pos = isTrailingHit ? hitTestMetrics.textPosition + hitTestMetrics.length : caretMetrics.textPosition;
+	}
+
+	// Get the character position in original string
+	int posInString = GetPositionInString(screenLine->s, pos, screenLine->len, screenLine->lineReprs);
+
+	return posInString;
+}
+
+///////////////////////////////////////////////////////////////////
+// Finds the point of the caret position
+
+Point SurfaceD2D::XYFromPosition(const ScreenLine *screenLine, int caretPosition) {
+	// If the text is empty, then no need to go through this function
+	if (!screenLine->len)
+		return Point(0, 0);
+
+	// Find the exact position in the line, after simulating the exact text on the screen
+	int position = GetPositionInLayout(screenLine->s, caretPosition, screenLine->lineReprs);
+
+	// Get textFormat
+	FormatAndMetrics *pfm = static_cast<FormatAndMetrics *>(screenLine->stylesFontsIDs[0]);
+
+	if (!pIDWriteFactory || !pfm->pTextFormat) {
+		return Point(-1, -1);
+	}
+
+	// Convert the string to wstring and replace the original control characters with their representative chars.
+	std::wstring buffer = ReplaceRepresentation(screenLine->lineReprs, screenLine->len, screenLine->s);
+
+	// Create a text layout
+	IDWriteTextLayout *textLayout = 0;
+
+	const HRESULT hrCreate = pIDWriteFactory->CreateTextLayout(buffer.c_str(), static_cast<UINT32>(buffer.length()+1),
+		pfm->pTextFormat, screenLine->width, screenLine->height, &textLayout);
+
+	if (!SUCCEEDED(hrCreate)) {
+		return Point(-1, -1);
+	}
+
+	// Tab is a special case of representation, taking a variable amount of space, the tab space depends on the drawing style tab stop.
+	textLayout->SetIncrementalTabStop(screenLine->tabWidth);
+
+
+	// Fill the textLayout chars with their own formats
+	FillTextLayoutFormats(screenLine, textLayout);
+
+	// Translate text character offset to point x,y.
+	DWRITE_HIT_TEST_METRICS caretMetrics;
+	Point pt;
+
+	textLayout->HitTestTextPosition(
+		position,
+		false, // trailing if false, else leading edge
+		&pt.x,
+		&pt.y,
+		&caretMetrics
+	);
+
+	// We need to adjust ctrl chars and tab spaces .
+	float lostSpace = 0.0;
+	lostSpace += FindLostSpace(screenLine, caretMetrics.textPosition, textLayout);
+
+	pt.x += lostSpace;
+
+	textLayout->Release();
+
+	return pt;
+}
+
+/////////////////////////////////////////////////////////
+// Find the selection range rectangles
+
+void SurfaceD2D::FillSelectionRectangle(const ScreenLine *screenLine, int start, int end, PRectangle rcLine,
+					int xStart, IDrawRectangle *pDraw) {
+	// If the text is empty, then no need to go through this function
+	if (!screenLine->len)
+		return;
+
+	// Find the exact position of selection start and end in the line, after simulating the exact text on the screen
+	int startPos = GetPositionInLayout(screenLine->s, start, screenLine->lineReprs);
+	int endPos = GetPositionInLayout(screenLine->s, end, screenLine->lineReprs);
+
+	// Get textFormat
+	FormatAndMetrics *pfm = static_cast<FormatAndMetrics *>(screenLine->stylesFontsIDs[0]);
+
+	if (!pIDWriteFactory || !pfm->pTextFormat) {
+		return;
+	}
+
+
+	// Convert the string to wstring and replace the original control characters with their representative chars.
+	std::wstring buffer = ReplaceRepresentation(screenLine->lineReprs, screenLine->len, screenLine->s);
+
+	// Create a text layout
+	IDWriteTextLayout *textLayout = 0;
+
+	const HRESULT hrCreate = pIDWriteFactory->CreateTextLayout(buffer.c_str(), static_cast<UINT32>(buffer.length() + 1),
+		pfm->pTextFormat, screenLine->width, screenLine->height, &textLayout);
+
+	if (!SUCCEEDED(hrCreate)) {
+		return;
+	}
+
+	// Tab is a special case of representation, taking a variable amount of space, the tab space depends on the drawing style tab stop.
+	textLayout->SetIncrementalTabStop(screenLine->tabWidth);
+
+	// Fill the textLayout chars with their own formats
+	FillTextLayoutFormats(screenLine, textLayout);
+
+	// Find selection range length
+	int RangeLength = (endPos > startPos) ? (endPos - startPos) : (startPos - endPos);
+
+	// Determine actual number of hit-test ranges
+	UINT32 actualHitTestCount = 0;
+
+	if (RangeLength > 0) {
+		textLayout->HitTestTextRange(
+			startPos,
+			RangeLength,
+			0, // x
+			0, // y
+			NULL,
+			0, // metrics count
+			&actualHitTestCount
+		);
+	}
+
+	// Allocate enough room to return all hit-test metrics.
+	std::vector<DWRITE_HIT_TEST_METRICS> hitTestMetrics(actualHitTestCount);
+
+	if (RangeLength > 0) {
+		textLayout->HitTestTextRange(
+			startPos,
+			RangeLength,
+			0, // x
+			0, // y
+			&hitTestMetrics[0],
+			static_cast<UINT32>(hitTestMetrics.size()),
+			&actualHitTestCount
+		);
+	}
+
+	// Get the selection ranges behind the text.
+
+	if (actualHitTestCount > 0) {
+		float leftAddedSpace = 0.0;
+		float rightAddedSpace = 0.0;
+		for (size_t i = 0; i < actualHitTestCount; ++i) {
+			// Calculate added space in case of using ctrl chars representations and tabs
+			rightAddedSpace = FindLostSpace(screenLine, hitTestMetrics[i].textPosition + hitTestMetrics[i].length, textLayout);
+			leftAddedSpace = FindLostSpace(screenLine, hitTestMetrics[i].textPosition, textLayout);
+
+			// Draw selection rectangle
+			const DWRITE_HIT_TEST_METRICS &htm = hitTestMetrics[i];
+			PRectangle selectionRect;
+
+			selectionRect.left = htm.left + xStart + leftAddedSpace;
+			selectionRect.right = htm.left + htm.width + xStart + rightAddedSpace;
+
+			selectionRect.top = rcLine.top;
+			selectionRect.bottom = rcLine.bottom;
+
+			pDraw->Draw(selectionRect);
+		}
+	}
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// Each char can have its own style, so we fill the textLayout with the textFormat of each char
+
+void SurfaceD2D::FillTextLayoutFormats(const ScreenLine *screenLine, IDWriteTextLayout *textLayout) {
+	int charBytes = 0;
+	std::wstring wBuffer = L"";
+
+	for (int l = 0; l < screenLine->len;) {
+		int charStart = l;
+		charBytes = UTF8DrawBytes(reinterpret_cast<const unsigned char *>(&screenLine->s[l]), screenLine->len - l);
+		l += charBytes;
+
+		const TextWide wideChar(&screenLine->s[charStart], charBytes, unicodeMode, codePageText);
+		std::wstring charBuf = L"";
+		charBuf.append(wideChar.buffer, wideChar.tlen);
+		for (int r = charStart; r < charStart + charBytes; r++) {
+			if (screenLine->lineReprs[r]) {
+				if (r == charStart) {
+					charBuf.clear();
+				}
+				const TextWide reps(screenLine->lineReprs[r], static_cast<UINT32>(strlen(screenLine->lineReprs[r])), unicodeMode, codePageText);
+				charBuf.insert(charBuf.length(), reps.buffer, reps.tlen);
+			} else
+				break;
+		}
+
+		DWRITE_TEXT_RANGE textRange;
+		textRange.length = static_cast<UINT32>(charBuf.length());
+		textRange.startPosition = static_cast<UINT32>(wBuffer.length());
+
+		FormatAndMetrics *pfm = screenLine->lineReprs[charStart] ?
+					static_cast<FormatAndMetrics *>(screenLine->repStyle):
+					static_cast<FormatAndMetrics *>(screenLine->stylesFontsIDs[charStart]);
+
+		int fontFamilyNameSize = pfm->pTextFormat->GetFontFamilyNameLength();
+		WCHAR *fontFamilyName = new WCHAR[fontFamilyNameSize + 1];
+
+		pfm->pTextFormat->GetFontFamilyName(fontFamilyName, fontFamilyNameSize + 1);
+		textLayout->SetFontFamilyName(fontFamilyName, textRange);
+
+		textLayout->SetFontSize(pfm->pTextFormat->GetFontSize(), textRange);
+		textLayout->SetFontWeight(pfm->pTextFormat->GetFontWeight(), textRange);
+		textLayout->SetFontStyle(pfm->pTextFormat->GetFontStyle(), textRange);
+
+		int localNameSize = pfm->pTextFormat->GetLocaleNameLength();
+		WCHAR *localName = new WCHAR[localNameSize + 1];
+
+		pfm->pTextFormat->GetLocaleName(localName, localNameSize);
+		textLayout->SetLocaleName(localName, textRange);
+
+		textLayout->SetFontStretch(pfm->pTextFormat->GetFontStretch(), textRange);
+
+		IDWriteFontCollection *fontCollection;
+		pfm->pTextFormat->GetFontCollection(&fontCollection);
+		textLayout->SetFontCollection(fontCollection, textRange);
+
+		delete[] localName;
+		delete[] fontFamilyName;
+
+		wBuffer.insert(wBuffer.length(), charBuf);
+		charBytes = 0;
+	}
+
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+/* When the string contains control characters, they are represented on the screen as blob chars,
+ so we need to replace the original control characters with their representative chars to simulate what is displayed on the screen */
+
+std::wstring SurfaceD2D::ReplaceRepresentation(const CharArray *lineReprs, int len, const char *s) {
+	int charBytes = 0;
+	std::wstring wBuffer = L"";
+	for (int l = 0; l < len;) {
+		int charStart = l;
+		charBytes = UTF8DrawBytes(reinterpret_cast<const unsigned char *>(&s[l]), len - l);
+
+		const TextWide wideChar(&s[charStart], charBytes, unicodeMode, codePageText);
+		std::wstring charBuf =L"";
+		charBuf.append(wideChar.buffer, wideChar.tlen);
+		for (int r = charStart; r < charStart + charBytes; r++) {
+			if (lineReprs[r]) {
+				if (r == charStart) {
+					charBuf.clear();
+				}
+				const TextWide reps(lineReprs[r], static_cast<int>(strlen(lineReprs[r])), unicodeMode, codePageText);
+				charBuf.insert(charBuf.length(), reps.buffer, reps.tlen);
+			}
+
+		}
+		wBuffer.insert(wBuffer.length(), charBuf);
+		l += charBytes;
+		charBytes = 0;
+	}
+	return wBuffer;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Finds the exact position in the text, after simulatint the exact text on the screen
+// i.e the text can have right to left chars, or control chars
+
+int SurfaceD2D::GetPositionInLayout(const char *s, int position, const CharArray *lineReprs) {
+	std::wstring buffer =  ReplaceRepresentation(lineReprs, position, s);
+
+	return static_cast<int>(buffer.length());
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Converts position in wstring to position in string
+
+int SurfaceD2D::GetPositionInString(const char *s, int position, int len, const CharArray *lineReprs) {
+	int PosInString = 0;
+	int charBytes = 0;
+	std::wstring wBuffer = L"";
+	for (PosInString = 0; PosInString < len && position > static_cast<int>(wBuffer.length());) {
+		int charStart = PosInString;
+		charBytes = UTF8DrawBytes(reinterpret_cast<const unsigned char *>(&s[PosInString]), len - PosInString);
+		PosInString += charBytes;
+
+		const TextWide wideChar(&s[charStart], charBytes, unicodeMode, codePageText);
+		std::wstring charBuf = L"";
+		charBuf.append(wideChar.buffer, wideChar.tlen);
+		for (int r = charStart; r < charStart + charBytes; r++) {
+			if (lineReprs[r]) {
+				if (r == charStart) {
+					charBuf.clear();
+				}
+				const TextWide reps(lineReprs[r], static_cast<int>(strlen(lineReprs[r])), unicodeMode, codePageText);
+				charBuf.insert(charBuf.length(), reps.buffer, reps.tlen);
+			}
+
+		}
+		wBuffer.insert(wBuffer.length(), charBuf);
+		charBytes = 0;
+	}
+
+	return PosInString;
+}
+
+///////////////////////////////////////////////////////////////////////////
+// ctrl chars has padding space, and tab also has when remaining space is less than minimum allowed width, a new tab width is added
+
+float SurfaceD2D::FindLostSpace(const ScreenLine *screenLine, int pos, IDWriteTextLayout *textLayout) {
+	float totalLostSpace = 0.0;
+	// Each control char has a padding space after its representative chars, so we need to adjust this space .
+
+	DWRITE_HIT_TEST_METRICS realCaretMetrics;
+	Point realPt;
+	int lastTabStop = 0;
+	int lastCtrlPos = 0;
+	bool tabFound = false;
+	bool ctrlFound = false;
+	float addedCtrlSpace = 0.0;
+	float addedTabSpace = 0.0;
+
+	int charBytes = 0;
+	int ctrlCount = 0;
+	std::wstring wBuffer = L"";
+	for (int l = 0; l < screenLine->len && static_cast<int>(wBuffer.length()) < pos; l += charBytes) {
+		charBytes = 0;
+		int charStart = l;
+		charBytes = UTF8DrawBytes(reinterpret_cast<const unsigned char *>(&screenLine->s[l]), screenLine->len - l);
+
+		const TextWide wideChar(&screenLine->s[charStart], charBytes, unicodeMode, codePageText);
+		std::wstring charBuf = L"";
+		charBuf.append(wideChar.buffer, wideChar.tlen);
+		for (int r = charStart; r < charStart + charBytes; r++) {
+			// Each ctrl char has ctrlCharPadding space following its end, So if the current char is a control char, then add ctrlCharPadding
+			if (screenLine->lineReprs[r]) {
+				ctrlCount++;
+
+				if (r == charStart) {
+					charBuf.clear();
+				}
+				const TextWide reps(screenLine->lineReprs[r], static_cast<int>(strlen(screenLine->lineReprs[r])), unicodeMode, codePageText);
+				charBuf.insert(charBuf.length(), reps.buffer, reps.tlen);
+
+				// Translate ctrl chars offset to point x,y.
+
+				textLayout->HitTestTextPosition(
+					static_cast<UINT32>(wBuffer.length() + charBuf.length()),
+					false, // trailing if false, else leading edge
+					&realPt.x,
+					&realPt.y,
+					&realCaretMetrics
+				);
+				addedCtrlSpace += screenLine->ctrlCharPadding;
+				totalLostSpace += screenLine->ctrlCharPadding;
+
+				lastCtrlPos = screenLine->TabStop(realPt.x + addedCtrlSpace + addedTabSpace);
+
+				ctrlFound = true;
+			}
+		}
+
+		if (charBuf == L"\t") {
+			// Translate tabs offset to point x,y.
+
+			textLayout->HitTestTextPosition(
+				static_cast<UINT32>(wBuffer.length()),
+				false, // trailing if false, else leading edge
+				&realPt.x,
+				&realPt.y,
+				&realCaretMetrics
+			);
+			tabFound = true;
+			lastTabStop = screenLine->TabStop(realPt.x + addedCtrlSpace + addedTabSpace);
+
+			float tabRemainder = screenLine->tabWidth - fmodf((realPt.x + addedCtrlSpace + addedTabSpace), screenLine->tabWidth);
+
+			/* Using roundf(tabRemainder) > 0.0 instead of tabRemainder > 0.0, because in some cases the remainder is misleading,
+			for example if we have 5 tabs, the x of the fifth tab will be 176.062500, then the remainder will be  2.129925361877514e-7 */
+			if (tabRemainder < screenLine->tabWidthMinimumPixels && roundf(tabRemainder) > 0.0) {
+				addedTabSpace += screenLine->tabWidth;
+				totalLostSpace += screenLine->tabWidth;
+			}
+
+		}
+
+		if (tabFound && ctrlFound && lastCtrlPos == lastTabStop) {
+			// If ctrl chars are in the same tab stop with a tab, then ctrlCharPadding are skipped
+			totalLostSpace -= totalLostSpace >= (screenLine->ctrlCharPadding * ctrlCount) ?
+					  (screenLine->ctrlCharPadding* ctrlCount) : 0;
+			tabFound = false;
+			ctrlFound = false;
+			ctrlCount = 0;
+			addedCtrlSpace = 0.0;
+		}
+		wBuffer.insert(wBuffer.length(), charBuf);
+	}
+
+	return totalLostSpace;
+}
+
+#endif
+
 void SurfaceD2D::DrawTextTransparent(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len,
 	ColourDesired fore) {
 	// Avoid drawing spaces in transparent mode
diff -r a6a621b767ed win32/makefile
--- a/win32/makefile	Tue Dec 19 15:00:40 2017 +1100
+++ b/win32/makefile	Wed Dec 20 09:04:18 2017 +1100
@@ -43,7 +43,11 @@
 D2DFLAGS=-DDISABLE_D2D
 endif
 
-CXXBASEFLAGS=--std=$(CXXSTD) -Wall -pedantic $(INCLUDEDIRS) $(D2DFLAGS) -D_CRT_SECURE_NO_DEPRECATE=1
+ifdef ENABLE_BIDIRECTIONAL
+BIDIFLAGS=-DENABLE_BIDIRECTIONAL
+endif
+
+CXXBASEFLAGS=--std=$(CXXSTD) -Wall -pedantic $(INCLUDEDIRS) $(D2DFLAGS) $(BIDIFLAGS) -D_CRT_SECURE_NO_DEPRECATE=1
 
 ifdef NO_CXX11_REGEX
 REFLAGS=-DNO_CXX11_REGEX
diff -r a6a621b767ed win32/scintilla.mak
--- a/win32/scintilla.mak	Tue Dec 19 15:00:40 2017 +1100
+++ b/win32/scintilla.mak	Wed Dec 20 09:04:18 2017 +1100
@@ -40,6 +40,10 @@
 LDFLAGS=$(LDFLAGS) $(NOLOGO)
 !ENDIF
 
+!IFDEF ENABLE_BIDIRECTIONAL
+CXXFLAGS=$(CXXFLAGS) -DENABLE_BIDIRECTIONAL
+!ENDIF
+
 !IF [cl -c -nologo CheckD2D.cxx >NUL:]
 CXXFLAGS=$(CXXFLAGS) -DDISABLE_D2D
 !MESSAGE Direct2D is not available
