diff -r 33a0321a7b6a include/Platform.h
--- a/include/Platform.h	Tue Dec 19 15:00:40 2017 +1100
+++ b/include/Platform.h	Fri Jan 05 20:43:27 2018 +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,49 @@
 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 XYPOSITION *widthReprs;
+	const int tabWidthMinimumPixels;
+
+	ScreenLine(
+		const char *s_,
+		int len_,
+		XYPOSITION width_,
+		XYPOSITION height_,
+		FontID *stylesFontsIDs_,
+		int ctrlCharPadding_,
+		XYPOSITION tabWidth_,
+		const XYPOSITION *widthReprs_,
+		int tabWidthMinimumPixels_=0
+	) :
+		s(s_),
+		len(len_),
+		width(width_),
+		height(height_),
+		stylesFontsIDs(stylesFontsIDs_),
+		ctrlCharPadding(ctrlCharPadding_),
+		tabWidth(tabWidth_),
+		widthReprs(widthReprs_),
+		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 +329,20 @@
 	friend class SurfaceImpl;
 };
 
+#ifdef ENABLE_BIDIRECTIONAL
+
+struct Interval {
+	XYPOSITION left;
+	XYPOSITION right;
+};
+
+class IAddInterval {
+public:
+	virtual void Add(Interval interval)=0;
+};
+
+#endif
+
 /**
  * A surface abstracts a place to draw.
  */
@@ -319,6 +378,12 @@
 	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 FindSelectionIntervals(const ScreenLine *screenLine, int start, int end, IAddInterval *pAdd)=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 33a0321a7b6a src/EditView.cxx
--- a/src/EditView.cxx	Tue Dec 19 15:00:40 2017 +1100
+++ b/src/EditView.cxx	Fri Jan 05 20:43:27 2018 +1100
@@ -588,6 +588,42 @@
 	}
 }
 
+#ifdef ENABLE_BIDIRECTIONAL
+
+//////////////////////////////////////////////////////////////////
+// Fill the line stylesFontsIDs array according to each char style
+void EditView::FillLineFontsIDs(const ViewStyle &vstyle, LineLayout *ll, FontID * stylesFontsIDs) {
+	for (int stylesInLine = 0; stylesInLine < ll->numCharsInLine; stylesInLine++) {
+		FontAlias styleFont = vstyle.styles[ll->styles[stylesInLine]].font;
+		stylesFontsIDs[stylesInLine] = styleFont.GetID();
+	}
+	stylesFontsIDs[ll->numCharsInLine] = nullptr;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Fill lineReprs array with representations of control chars in line if found , and if not found fill with nullptr
+void EditView::FillLineRepresentations(const EditModel &model, LineLayout * ll, XYPOSITION *widthReprs) {
+
+	for (int charsInLine = 0; charsInLine < ll->numCharsInLine; charsInLine++) {
+		const int charWidth = UTF8DrawBytes(reinterpret_cast<unsigned char *>(&ll->chars[charsInLine]), ll->numCharsInLine - charsInLine);
+		const Representation *repr = model.reprs.RepresentationFromCharacter(&ll->chars[charsInLine], charWidth);
+
+		widthReprs[charsInLine] = 0.0f;
+		if (repr) {
+			widthReprs[charsInLine] = ll->positions[charsInLine + charWidth] - ll->positions[charsInLine];
+		}
+		if (charWidth > 1) {
+			for (int c = 1; c < charWidth; c++) {
+				charsInLine++;
+				widthReprs[charsInLine] = 0.0f;
+			}
+		}
+	}
+	widthReprs[ll->numCharsInLine] = 0.0f;
+
+}
+#endif
+
 Point EditView::LocationFromPosition(Surface *surface, const EditModel &model, SelectionPosition pos, Sci::Line topLine,
 				     const ViewStyle &vs, PointEnd pe) {
 	Point pt;
@@ -610,6 +646,44 @@
 		pt.x += vs.textStart - model.xOffset;
 	}
 	pt.x += pos.VirtualSpace() * vs.styles[ll->EndLineStyle()].spaceWidth;
+
+#ifdef ENABLE_BIDIRECTIONAL
+	// Fill the line stylesFontsIDs array
+	FillLineFontsIDs(vs, ll, ll->stylesFontsIDs.get());	
+
+	// Fill line lineReprs array
+	FillLineRepresentations(model, ll, ll->widthReprs.get());
+
+	// Find subLine	
+	int subLine = 0;
+	int line = 0;
+	for (; line < ll->lines; line++) {
+		if ((pos.Position() - posLineStart) >= ll->LineStart(line)) {
+			subLine = line;
+		}
+	}
+	
+	int subLineEnd = subLine < ll->lines - 1 ? (ll->LineStart(subLine + 1) - 1) 
+		: ll->numCharsInLine;
+	int stylePointer = ll->LineStart(subLine);
+
+	FontAlias controlStyleFont = vs.styles[STYLE_CONTROLCHAR].font;
+
+	// Get the point from current position
+	ScreenLine props(&ll->chars[ll->LineStart(subLine)], subLineEnd - ll->LineStart(subLine), static_cast<const float>(ll->widthLine)
+		, static_cast<const float>(vs.lineHeight), &ll->stylesFontsIDs[stylePointer],	vs.ctrlCharPadding, vs.tabWidth,
+		&ll->widthReprs[ll->LineStart(subLine)], tabWidthMinimumPixels);
+
+	int caretPosition = pos.Position() - posLineStart - ll->LineStart(subLine);
+
+	pt = surface->XYFromPosition(&props, caretPosition);
+
+	pt.y = 0;
+	if ((pos.Position() - posLineStart) >= ll->LineStart(subLine)) {
+		pt.y = static_cast<XYPOSITION>(subLine*vs.lineHeight);
+	}
+	pt.y += (lineVisible - topLine) * vs.lineHeight;
+#endif
 	return pt;
 }
 
@@ -660,8 +734,32 @@
 			const XYPOSITION subLineStart = ll->positions[rangeSubLine.start];
 			if (subLine > 0)	// Wrapped
 				pt.x -= ll->wrapIndent;
+#ifdef ENABLE_BIDIRECTIONAL
+			// Fill the line stylesFontsIDs array
+			FillLineFontsIDs(vs, ll , ll->stylesFontsIDs.get());
+
+			// Fill line lineReprs array
+			FillLineRepresentations(model, ll, ll->widthReprs.get());
+
+			// String length from subline range
+			int stringLength = subLine < ll->lines - 1 ? (rangeSubLine.end - rangeSubLine.start-1) 
+				: (ll->numCharsInLine - rangeSubLine.start);
+
+			// Get control chars style
+			FontAlias controlStyleFont = vs.styles[STYLE_CONTROLCHAR].font;
+			
+			// Get position from point	
+			Point currentPT(static_cast<XYPOSITION>(pt.x), 0);
+			int stylePointer = rangeSubLine.start ;
+			ScreenLine props(&ll->chars[rangeSubLine.start], stringLength, static_cast<const float>(ll->widthLine), 
+				static_cast<const float>(vs.lineHeight), &ll->stylesFontsIDs[stylePointer],vs.ctrlCharPadding,
+				vs.tabWidth, &ll->widthReprs[ll->LineStart(subLine)], tabWidthMinimumPixels);
+
+			const Sci::Position positionInLine = surface->PositionFromPoint(&props, currentPT, charPosition) + rangeSubLine.start;
+#else
 			const Sci::Position positionInLine = ll->FindPositionFromX(static_cast<XYPOSITION>(pt.x + subLineStart),
 				rangeSubLine, charPosition);
+#endif
 			if (positionInLine < rangeSubLine.end) {
 				return SelectionPosition(model.pdoc->MovePositionOutsideChar(positionInLine + posLineStart, 1));
 			}
@@ -1331,6 +1429,26 @@
 		const XYPOSITION virtualOffset = posCaret.VirtualSpace() * spaceWidth;
 		if (ll->InLine(offset, subLine) && offset <= ll->numCharsBeforeEOL) {
 			XYPOSITION xposCaret = ll->positions[offset] + virtualOffset - ll->positions[ll->LineStart(subLine)];
+#ifdef ENABLE_BIDIRECTIONAL
+			// Get caret point
+			// tabWidthMinimumPixels
+			int subLineEnd = subLine < ll->lines - 1 ? (ll->LineStart(subLine+1) - 1) : ll->numCharsInLine;
+			int stylePointer = ll->LineStart(subLine);
+
+			//Get control chars style
+			FontAlias controlStyleFont = vsDraw.styles[STYLE_CONTROLCHAR].font;
+
+			ScreenLine props(&ll->chars[ll->LineStart(subLine)], subLineEnd - ll->LineStart(subLine), 
+				static_cast<const float>(ll->widthLine), static_cast<const float>(vsDraw.lineHeight) ,
+				&ll->stylesFontsIDs[stylePointer], vsDraw.ctrlCharPadding, vsDraw.tabWidth,
+				&ll->widthReprs[ll->LineStart(subLine)], tabWidthMinimumPixels);
+
+			int caretPosition = posCaret.Position() - posLineStart - ll->LineStart(subLine);
+
+			Point caretLeft = surface->XYFromPosition(&props, caretPosition);
+
+			xposCaret = caretLeft.x + virtualOffset;
+#endif
 			if (ll->wrapIndent != 0) {
 				const Sci::Position lineStart = ll->LineStart(subLine);
 				if (lineStart != 0)	// Wrapped
@@ -1546,8 +1664,35 @@
 		marks >>= 1;
 	}
 }
+
+#ifdef ENABLE_BIDIRECTIONAL
+
+namespace {
+
+class DrawSelectionRectangle : public IAddInterval {
+	Surface *surface;
+	PRectangle rcLine;
+	int xStart;
+	ColourDesired colour;
+	int alpha;
+public:
+	DrawSelectionRectangle(Surface *surface_, PRectangle rcLine_, int xStart_, ColourDesired colour_, int alpha_) :
+		surface(surface_), rcLine(rcLine_), xStart(xStart_), colour(colour_), alpha(alpha_){}
+	void Add(Interval interval) override {
+		PRectangle rc(interval.left + xStart, rcLine.top, interval.right + xStart, rcLine.bottom);
+		SimpleAlphaRectangle(surface, rc, colour, alpha);
+	}
+};
+
+};
+
+#endif
 static void DrawTranslucentSelection(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll,
-	Sci::Line line, PRectangle rcLine, int subLine, Range lineRange, int xStart) {
+	Sci::Line line, PRectangle rcLine, int subLine, Range lineRange, int xStart
+#ifdef ENABLE_BIDIRECTIONAL
+	, int tabWidthMinimumPixels
+#endif
+	) {
 	if ((vsDraw.selAlpha != SC_ALPHA_NOALPHA) || (vsDraw.selAdditionalAlpha != SC_ALPHA_NOALPHA)) {
 		const Sci::Position posLineStart = static_cast<Sci::Position>(model.pdoc->LineStart(line));
 		const XYACCUMULATOR subLineStart = ll->positions[lineRange.start];
@@ -1566,10 +1711,29 @@
 				if (!portion.Empty()) {
 					const XYPOSITION spaceWidth = vsDraw.styles[ll->EndLineStyle()].spaceWidth;
 					PRectangle rcSegment = rcLine;
+#ifdef ENABLE_BIDIRECTIONAL
+					int stringLength = lineRange.end < ll->numCharsInLine ? (lineRange.end - lineRange.start - 1)
+						: (ll->numCharsInLine - lineRange.start);
+					int selectionStart = (portion.start.Position() - posLineStart - lineRange.start);
+					int selectionEnd = (portion.end.Position() - posLineStart - lineRange.start);
+					int stylePointer = lineRange.start;
+
+					DrawSelectionRectangle drawInterval(surface, rcLine, xStart,
+						SelectionBackground(vsDraw, r == model.sel.Main(), model.primarySelection), alpha);
+
+					//Get control chars style
+					FontAlias controlStyleFont = vsDraw.styles[STYLE_CONTROLCHAR].font;
+
+					ScreenLine props(&ll->chars[lineRange.start], stringLength, static_cast<const float>(ll->widthLine)
+						, static_cast<const float>(vsDraw.lineHeight), &ll->stylesFontsIDs[stylePointer], vsDraw.ctrlCharPadding,
+						vsDraw.tabWidth, &ll->widthReprs[ll->LineStart(subLine)], tabWidthMinimumPixels);
+
+					surface->FindSelectionIntervals(&props, selectionStart, selectionEnd, &drawInterval);
+#else
 					rcSegment.left = xStart + ll->positions[portion.start.Position() - posLineStart] -
-						static_cast<XYPOSITION>(subLineStart)+portion.start.VirtualSpace() * spaceWidth;
+						static_cast<XYPOSITION>(subLineStart) + portion.start.VirtualSpace() * spaceWidth;
 					rcSegment.right = xStart + ll->positions[portion.end.Position() - posLineStart] -
-						static_cast<XYPOSITION>(subLineStart)+portion.end.VirtualSpace() * spaceWidth;
+						static_cast<XYPOSITION>(subLineStart) + portion.end.VirtualSpace() * spaceWidth;
 					if ((ll->wrapIndent != 0) && (lineRange.start != 0)) {
 						if ((portion.start.Position() - posLineStart) == lineRange.start && model.sel.Range(r).ContainsCharacter(portion.start.Position() - 1))
 							rcSegment.left -= static_cast<int>(ll->wrapIndent); // indentation added to xStart was truncated to int, so we do the same here
@@ -1578,6 +1742,7 @@
 					rcSegment.right = (rcSegment.right < rcLine.right) ? rcSegment.right : rcLine.right;
 					if (rcSegment.right > rcLine.left)
 						SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw, r == model.sel.Main(), model.primarySelection), alpha);
+#endif
 				}
 			}
 		}
@@ -1931,7 +2096,11 @@
 	}
 
 	if (!hideSelection && (phase & drawSelectionTranslucent)) {
-		DrawTranslucentSelection(surface, model, vsDraw, ll, line, rcLine, subLine, lineRange, xStart);
+		DrawTranslucentSelection(surface, model, vsDraw, ll, line, rcLine, subLine, lineRange, xStart
+#ifdef ENABLE_BIDIRECTIONAL
+			, tabWidthMinimumPixels
+#endif
+		);
 	}
 
 	if (phase & drawLineTranslucent) {
@@ -2074,6 +2243,14 @@
 						surface->FillRectangle(rcSpacer, vsDraw.styles[STYLE_DEFAULT].back);
 					}
 
+#ifdef ENABLE_BIDIRECTIONAL
+					// Fill the line stylesFontsIDs array
+					FillLineFontsIDs(vsDraw, ll , ll->stylesFontsIDs.get());
+
+					// Fill line lineReprs array
+					FillLineRepresentations(model, ll, ll->widthReprs.get());
+#endif
+
 					DrawLine(surface, model, vsDraw, ll, lineDoc, visibleLine, xStart, rcLine, subLine, phase);
 					//durPaint += et.Duration(true);
 
diff -r 33a0321a7b6a src/EditView.h
--- a/src/EditView.h	Tue Dec 19 15:00:40 2017 +1100
+++ b/src/EditView.h	Fri Jan 05 20:43:27 2018 +1100
@@ -112,6 +112,11 @@
 	void LayoutLine(const EditModel &model, Sci::Line line, Surface *surface, const ViewStyle &vstyle,
 		LineLayout *ll, int width = LineLayout::wrapWidthInfinite);
 
+#ifdef ENABLE_BIDIRECTIONAL
+	void FillLineFontsIDs(const ViewStyle &vstyle , LineLayout *ll, FontID * stylesFontsIDs);
+	void FillLineRepresentations(const EditModel &model, LineLayout *ll, XYPOSITION *widthReprs);
+#endif
+
 	Point LocationFromPosition(Surface *surface, const EditModel &model, SelectionPosition pos, Sci::Line topLine,
 				   const ViewStyle &vs, PointEnd pe);
 	Range RangeDisplayLine(Surface *surface, const EditModel &model, Sci::Line lineVisible, const ViewStyle &vs);
diff -r 33a0321a7b6a src/PositionCache.cxx
--- a/src/PositionCache.cxx	Tue Dec 19 15:00:40 2017 +1100
+++ b/src/PositionCache.cxx	Fri Jan 05 20:43:27 2018 +1100
@@ -78,6 +78,10 @@
 		// Extra position allocated as sometimes the Windows
 		// GetTextExtentExPoint API writes an extra element.
 		positions.reset(new XYPOSITION[maxLineLength_ + 1 + 1]);
+#ifdef ENABLE_BIDIRECTIONAL
+		stylesFontsIDs.reset(new FontID[maxLineLength_ + 1]); 
+		widthReprs.reset(new XYPOSITION[maxLineLength_ + 1]);
+#endif
 		maxLineLength = maxLineLength_;
 	}
 }
@@ -87,6 +91,10 @@
 	styles.reset();
 	positions.reset();
 	lineStarts.reset();
+#ifdef ENABLE_BIDIRECTIONAL
+	stylesFontsIDs.reset();
+	widthReprs.reset();
+#endif
 }
 
 void LineLayout::Invalidate(validLevel validity_) {
diff -r 33a0321a7b6a src/PositionCache.h
--- a/src/PositionCache.h	Tue Dec 19 15:00:40 2017 +1100
+++ b/src/PositionCache.h	Fri Jan 05 20:43:27 2018 +1100
@@ -61,6 +61,12 @@
 	bool highlightColumn;
 	bool containsCaret;
 	int edgeColumn;
+
+#ifdef ENABLE_BIDIRECTIONAL
+	std::unique_ptr<FontID[]> stylesFontsIDs;
+	std::unique_ptr<XYPOSITION[]> widthReprs;
+#endif
+
 	std::unique_ptr<char[]> chars;
 	std::unique_ptr<unsigned char[]> styles;
 	std::unique_ptr<XYPOSITION[]> positions;
diff -r 33a0321a7b6a win32/PlatWin.cxx
--- a/win32/PlatWin.cxx	Tue Dec 19 15:00:40 2017 +1100
+++ b/win32/PlatWin.cxx	Fri Jan 05 20:43:27 2018 +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 FindSelectionIntervals(const ScreenLine *, int, int, IAddInterval *) 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::FindSelectionIntervals(const ScreenLine *, int, int, IAddInterval *) {
+}
+
+#endif
+
 typedef VarBuffer<int, stackBufferLength> TextPositionsI;
 
 void SurfaceGDI::DrawTextCommon(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, UINT fuOptions) {
@@ -1040,6 +1062,10 @@
 
 #if defined(USE_D2D)
 
+#ifdef ENABLE_BIDIRECTIONAL
+class BlobInline;
+#endif
+
 class SurfaceD2D : public Surface {
 	bool unicodeMode;
 	int x, y;
@@ -1098,6 +1124,17 @@
 	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 FindSelectionIntervals(const ScreenLine *screenLine, int start, int end, IAddInterval *pAdd) override;
+	void FillTextLayoutFormats(const ScreenLine *screenLine, IDWriteTextLayout *textLayout, std::vector<BlobInline> &blobs);
+	std::wstring ReplaceRepresentation(int len, const char *s);
+	int GetPositionInLayout(const char *s, int position);
+	int GetPositionInString(const char *s, int position, int len);
+	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 +1587,544 @@
 	}
 }
 
+#ifdef ENABLE_BIDIRECTIONAL
+
+class BlobInline : public IDWriteInlineObject {
+	XYPOSITION width;
+
+	STDMETHOD(QueryInterface)(
+		/* [in] */ REFIID riid,
+		/* [iid_is][out] */ _COM_Outptr_ void __RPC_FAR *__RPC_FAR *ppvObject);
+	STDMETHODIMP_(ULONG)AddRef();
+	STDMETHODIMP_(ULONG)Release();
+
+	STDMETHOD(Draw)(
+		_In_opt_ void* clientDrawingContext,
+		_In_ IDWriteTextRenderer* renderer,
+		FLOAT originX,
+		FLOAT originY,
+		BOOL isSideways,
+		BOOL isRightToLeft,
+		_In_opt_ IUnknown* clientDrawingEffect
+		);
+
+	STDMETHOD(GetMetrics)(
+		_Out_ DWRITE_INLINE_OBJECT_METRICS* metrics
+		);
+
+	STDMETHOD(GetOverhangMetrics)(
+		_Out_ DWRITE_OVERHANG_METRICS* overhangs
+		);
+
+	STDMETHOD(GetBreakConditions)(
+		_Out_ DWRITE_BREAK_CONDITION* breakConditionBefore,
+		_Out_ DWRITE_BREAK_CONDITION* breakConditionAfter
+		);
+public:
+	BlobInline(XYPOSITION width_=0.0f) : width(width_) {
+	}
+	virtual ~BlobInline() {
+	}
+	void SetWidth(XYPOSITION width_) {
+		width = width_;
+	}
+};
+
+/// Implement IUnknown
+STDMETHODIMP BlobInline::QueryInterface(REFIID riid, PVOID *ppv) {
+	// Never called so not checked.
+	*ppv = NULL;
+	if (riid == IID_IUnknown)
+		*ppv = static_cast<IUnknown *>(this);
+	if (riid == __uuidof(IDWriteInlineObject))
+		*ppv = static_cast<IDWriteInlineObject *>(this);
+	if (!*ppv)
+		return E_NOINTERFACE;
+	return S_OK;
+}
+
+STDMETHODIMP_(ULONG) BlobInline::AddRef() {
+	// Lifetime tied to Platform methods so ignore any reference operations.
+	return 1;
+}
+
+STDMETHODIMP_(ULONG) BlobInline::Release() {
+	// Lifetime tied to Platform methods so ignore any reference operations.
+	return 1;
+}
+
+/// Implement IDWriteInlineObject
+HRESULT STDMETHODCALLTYPE BlobInline::Draw(
+	__maybenull void*,
+	IDWriteTextRenderer*,
+	FLOAT,
+	FLOAT,
+	BOOL,
+	BOOL,
+	IUnknown*) {
+	// Since not performing drawing, not necessary to implement
+	// Could be implemented by calling back into platform-independent code.
+	// This would allow more of the drawing to be mediated through DirectWrite.
+	return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE BlobInline::GetMetrics(
+	__out DWRITE_INLINE_OBJECT_METRICS* metrics
+) {
+	metrics->width = width;
+	metrics->height = 2;
+	metrics->baseline = 1;
+	metrics->supportsSideways = FALSE;
+	return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE BlobInline::GetOverhangMetrics(
+	__out DWRITE_OVERHANG_METRICS* overhangs
+) {
+	overhangs->left = 0;
+	overhangs->top = 0;
+	overhangs->right = 0;
+	overhangs->bottom = 0;
+	return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE BlobInline::GetBreakConditions(
+	__out DWRITE_BREAK_CONDITION* breakConditionBefore,
+	__out DWRITE_BREAK_CONDITION* breakConditionAfter
+) {
+	// Since not performing 2D layout, not necessary to implement
+	*breakConditionBefore = DWRITE_BREAK_CONDITION_NEUTRAL;
+	*breakConditionAfter = DWRITE_BREAK_CONDITION_NEUTRAL;
+	return S_OK;
+}
+
+// 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->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;
+	}
+
+	std::vector<BlobInline> blobs;
+
+	// Fill the textLayout chars with their own formats
+	FillTextLayoutFormats(screenLine, textLayout, blobs);
+
+	// 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 */
+
+	const 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
+		const 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);
+
+	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
+	const int position = GetPositionInLayout(screenLine->s, caretPosition);
+
+	// 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->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);
+
+	std::vector<BlobInline> blobs;
+
+	// Fill the textLayout chars with their own formats
+	FillTextLayoutFormats(screenLine, textLayout, blobs);
+
+	// 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 .
+	const float lostSpace = FindLostSpace(screenLine, caretMetrics.textPosition, textLayout);
+
+	pt.x += lostSpace;
+
+	textLayout->Release();
+
+	return pt;
+}
+
+/////////////////////////////////////////////////////////
+// Find the selection range rectangles
+
+void SurfaceD2D::FindSelectionIntervals(const ScreenLine *screenLine, int start, int end, IAddInterval *pAdd) {
+	// 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
+	const int startPos = GetPositionInLayout(screenLine->s, start);
+	const int endPos = GetPositionInLayout(screenLine->s, end);
+
+	// 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->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);
+
+	std::vector<BlobInline> blobs;
+
+	// Fill the textLayout chars with their own formats
+	FillTextLayoutFormats(screenLine, textLayout, blobs);
+
+	// 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) {
+		for (size_t i = 0; i < actualHitTestCount; ++i) {
+			// Calculate added space in case of using ctrl chars representations and tabs
+			const float rightAddedSpace = FindLostSpace(screenLine, hitTestMetrics[i].textPosition + hitTestMetrics[i].length, textLayout);
+			const float leftAddedSpace = FindLostSpace(screenLine, hitTestMetrics[i].textPosition, textLayout);
+
+			// Draw selection rectangle
+			const DWRITE_HIT_TEST_METRICS &htm = hitTestMetrics[i];
+			Interval selectionInterval;
+
+			selectionInterval.left = htm.left + leftAddedSpace;
+			selectionInterval.right = htm.left + htm.width + rightAddedSpace;
+
+			pAdd->Add(selectionInterval);
+		}
+	}
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// 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, std::vector<BlobInline> &blobs) {
+	std::wstring wBuffer;
+
+	for (int l = 0; l < screenLine->len;) {
+		const int charStart = l;
+		const int 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(wideChar.buffer, wideChar.tlen);
+
+		DWRITE_TEXT_RANGE textRange;
+		textRange.length = static_cast<UINT32>(charBuf.length());
+		textRange.startPosition = static_cast<UINT32>(wBuffer.length());
+
+		if (screenLine->widthReprs[charStart] > 0.0f) {
+			blobs.push_back(BlobInline(screenLine->widthReprs[charStart]));
+			textLayout->SetInlineObject(&blobs.back(), textRange);
+		}
+
+		FormatAndMetrics *pfm = 
+			static_cast<FormatAndMetrics *>(screenLine->stylesFontsIDs[charStart]);
+
+		const unsigned int fontFamilyNameSize = pfm->pTextFormat->GetFontFamilyNameLength();
+		std::vector<WCHAR> fontFamilyName(fontFamilyNameSize + 1);
+
+		pfm->pTextFormat->GetFontFamilyName(fontFamilyName.data(), fontFamilyNameSize + 1);
+		textLayout->SetFontFamilyName(fontFamilyName.data(), textRange);
+
+		textLayout->SetFontSize(pfm->pTextFormat->GetFontSize(), textRange);
+		textLayout->SetFontWeight(pfm->pTextFormat->GetFontWeight(), textRange);
+		textLayout->SetFontStyle(pfm->pTextFormat->GetFontStyle(), textRange);
+
+		const unsigned int localNameSize = pfm->pTextFormat->GetLocaleNameLength();
+		std::vector<WCHAR> localName(localNameSize + 1);
+
+		pfm->pTextFormat->GetLocaleName(localName.data(), localNameSize);
+		textLayout->SetLocaleName(localName.data(), textRange);
+
+		textLayout->SetFontStretch(pfm->pTextFormat->GetFontStretch(), textRange);
+
+		IDWriteFontCollection *fontCollection;
+		pfm->pTextFormat->GetFontCollection(&fontCollection);
+		textLayout->SetFontCollection(fontCollection, textRange);
+
+		wBuffer.append(charBuf);
+	}
+
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+/* 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(int len, const char *s) {
+	const TextWide wideText(s, len, unicodeMode, codePageText);
+	return std::wstring(wideText.buffer, wideText.tlen);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////
+// 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) {
+	std::wstring buffer = ReplaceRepresentation(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) {
+	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(wideChar.buffer, wideChar.tlen);
+		wBuffer.append(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 addedTabSpace = 0.0;
+
+	int charBytes = 0;
+	std::wstring wBuffer;
+	for (int l = 0; l < screenLine->len && static_cast<int>(wBuffer.length()) < pos; l += charBytes) {
+		const 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(wideChar.buffer, wideChar.tlen);
+
+		if (charBuf == L"\t") {
+			// Translate tabs offset to point x,y.
+
+			Point realPt;
+			DWRITE_HIT_TEST_METRICS realCaretMetrics;
+			textLayout->HitTestTextPosition(
+				static_cast<UINT32>(wBuffer.length()),
+				false, // trailing if false, else leading edge
+				&realPt.x,
+				&realPt.y,
+				&realCaretMetrics
+			);
+
+			float tabRemainder = screenLine->tabWidth - fmodf((realPt.x + 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;
+			}
+
+		}
+
+		wBuffer.append(charBuf);
+	}
+
+	return addedTabSpace;
+}
+
+#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 33a0321a7b6a win32/makefile
--- a/win32/makefile	Tue Dec 19 15:00:40 2017 +1100
+++ b/win32/makefile	Fri Jan 05 20:43:27 2018 +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 33a0321a7b6a win32/scintilla.mak
--- a/win32/scintilla.mak	Tue Dec 19 15:00:40 2017 +1100
+++ b/win32/scintilla.mak	Fri Jan 05 20:43:27 2018 +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
