OSDN Git Service

crystaledit: Reduce MFC dependency
[winmerge-jp/winmerge-jp.git] / Externals / crystaledit / editlib / ccrystaltextview.cpp
index aeb9dc1..485ed10 100644 (file)
  *
  * @brief Implementation of the CCrystalTextView class
  */
-// ID line follows -- this is updated by SVN
-// $Id: ccrystaltextview.cpp 7117 2010-02-01 14:24:51Z sdottaka $
 
 #include "StdAfx.h"
-#include <vector>
-#include <algorithm>
-#include <malloc.h>
-#include <imm.h> /* IME */
+#include "ccrystaltextview.h"
 #include "editcmd.h"
 #include "editreg.h"
-#include "ccrystaltextview.h"
 #include "ccrystaltextbuffer.h"
-#include "cfindtextdlg.h"
-#include "ctextmarkerdlg.h"
-#include "fpattern.h"
-#include "filesup.h"
-#include "registry.h"
-#include "gotodlg.h"
+#include "ccrystaltextmarkers.h"
 #include "ViewableWhitespace.h"
 #include "SyntaxColors.h"
-#include "ccrystaltextmarkers.h"
-#include "string_util.h"
-#include "wcwidth.h"
-#include "icu.hpp"
+#include "renderers/ccrystalrendererdirectwrite.h"
+#include "renderers/ccrystalrenderergdi.h"
+#include "dialogs/cfindtextdlg.h"
+#include "dialogs/ctextmarkerdlg.h"
+#include "dialogs/gotodlg.h"
+#include "utils/fpattern.h"
+#include "utils/filesup.h"
+#include "utils/string_util.h"
+#include "utils/wcwidth.h"
+#include "utils/icu.hpp"
+#include <vector>
+#include <algorithm>
+#include <numeric>
+#include <malloc.h>
+#include <imm.h> /* IME */
 
 using std::vector;
 using CrystalLineParser::TEXTBLOCK;
@@ -139,19 +139,17 @@ using CrystalLineParser::TEXTBLOCK;
 
 #define DEFAULT_PRINT_MARGIN        1000    //  10 millimeters
 
-/** @brief Maximum tab-char width. */
-const UINT MAX_TAB_LEN = 64;
+#ifndef WM_MOUSEHWHEEL
+#  define WM_MOUSEHWHEEL 0x20e
+#endif
+
 /** @brief Width of revision marks. */
 const UINT MARGIN_REV_WIDTH = 3;
-/** @brief Width of icons printed in the margin. */
-const UINT MARGIN_ICON_WIDTH = 12;
-/** @brief Height of icons printed in the margin. */
-const UINT MARGIN_ICON_HEIGHT = 12;
 
 /** @brief Color of unsaved line revision mark (dark yellow). */
-const COLORREF UNSAVED_REVMARK_CLR = RGB(0xD7, 0xD7, 0x00);
+const CEColor UNSAVED_REVMARK_CLR{ 0xD7, 0xD7, 0x00 };
 /** @brief Color of saved line revision mark (green). */
-const COLORREF SAVED_REVMARK_CLR = RGB(0x00, 0xFF, 0x00);
+const CEColor SAVED_REVMARK_CLR{ 0x00, 0xFF, 0x00 };
 
 #define SMOOTH_SCROLL_FACTOR        6
 
@@ -165,8 +163,7 @@ LOGFONT CCrystalTextView::m_LogFont;
 IMPLEMENT_DYNCREATE (CCrystalTextView, CView)
 
 HINSTANCE CCrystalTextView::s_hResourceInst = nullptr;
-
-static ptrdiff_t FindStringHelper(LPCTSTR pszLineBegin, LPCTSTR pszFindWhere, LPCTSTR pszFindWhat, DWORD dwFlags, int &nLen, RxNode *&rxnode, RxMatchRes *rxmatch);
+CCrystalTextView::RENDERING_MODE CCrystalTextView::s_nRenderingModeDefault = RENDERING_MODE::GDI;
 
 BEGIN_MESSAGE_MAP (CCrystalTextView, CView)
 //{{AFX_MSG_MAP(CCrystalTextView)
@@ -194,6 +191,7 @@ ON_COMMAND (ID_EDIT_REPEAT, OnEditRepeat)
 ON_UPDATE_COMMAND_UI (ID_EDIT_REPEAT, OnUpdateEditRepeat)
 ON_COMMAND (ID_EDIT_MARK, OnEditMark)
 ON_WM_MOUSEWHEEL ()
+ON_WM_MOUSEHWHEEL ()
 ON_MESSAGE (WM_IME_STARTCOMPOSITION, OnImeStartComposition) /* IME */
 //}}AFX_MSG_MAP
 ON_COMMAND (ID_EDIT_CHAR_LEFT, OnCharLeft)
@@ -250,6 +248,8 @@ ON_UPDATE_COMMAND_UI (ID_EDIT_MATCHBRACE, OnUpdateMatchBrace)
 ON_COMMAND (ID_EDIT_GOTO, OnEditGoTo)
 ON_UPDATE_COMMAND_UI (ID_VIEW_TOGGLE_SRC_HDR, OnUpdateToggleSourceHeader)
 ON_COMMAND (ID_VIEW_TOGGLE_SRC_HDR, OnToggleSourceHeader)
+ON_UPDATE_COMMAND_UI (ID_VIEW_TOPMARGIN, OnUpdateTopMargin)
+ON_COMMAND (ID_VIEW_TOPMARGIN, OnTopMargin)
 ON_UPDATE_COMMAND_UI (ID_VIEW_SELMARGIN, OnUpdateSelMargin)
 ON_COMMAND (ID_VIEW_SELMARGIN, OnSelMargin)
 ON_UPDATE_COMMAND_UI (ID_VIEW_WORDWRAP, OnUpdateWordWrap)
@@ -262,11 +262,11 @@ ON_COMMAND (ID_FORCE_REDRAW, OnForceRedraw)
   ON_UPDATE_COMMAND_UI(ID_EDIT_FIND_INCREMENTAL_FORWARD, OnUpdateEditFindIncrementalForward)
   ON_UPDATE_COMMAND_UI(ID_EDIT_FIND_INCREMENTAL_BACKWARD, OnUpdateEditFindIncrementalBackward)
   //END SW
-ON_COMMAND (ID_EDIT_TOGGLE_COLUMNSELECTION, OnToggleColumnSelection)
+  ON_COMMAND (ID_EDIT_TOGGLE_COLUMNSELECTION, OnToggleColumnSelection)
 END_MESSAGE_MAP ()
 
 #define EXPAND_PRIMITIVE(impl, func)    \
-void CCrystalTextView::On##func() { m_bColumnSelection = false; impl(false); }  \
+void CCrystalTextView::On##func() { m_bRectangularSelection = false; impl(false); }  \
 void CCrystalTextView::OnExt##func() { impl(true); }
 EXPAND_PRIMITIVE (MoveLeft, CharLeft)
 EXPAND_PRIMITIVE (MoveRight, CharRight)
@@ -282,84 +282,11 @@ EXPAND_PRIMITIVE (MoveCtrlHome, TextBegin)
 EXPAND_PRIMITIVE (MoveCtrlEnd, TextEnd)
 #undef EXPAND_PRIMITIVE
 
-// Tabsize is commented out since we have only GUI setting for it now.
-// Not removed because we may later want to have per-filetype settings again.
-// See ccrystaltextview.h for table declaration.
-CCrystalTextView::TextDefinition CCrystalTextView::m_SourceDefs[] =
-  {
-    CCrystalTextView::SRC_PLAIN, _T ("Plain"), _T ("txt,doc,diz"), &CrystalLineParser::ParseLinePlain, SRCOPT_AUTOINDENT, /*4,*/ _T (""), _T (""), _T (""), (DWORD)-1,
-    CCrystalTextView::SRC_ASP, _T ("ASP"), _T ("asp,ascx"), &CrystalLineParser::ParseLineAsp, SRCOPT_AUTOINDENT|SRCOPT_BRACEANSI, /*2,*/ _T (""), _T (""), _T ("'"), (DWORD)-1,
-    CCrystalTextView::SRC_BASIC, _T ("Basic"), _T ("bas,vb,vbs,frm,dsm,cls,ctl,pag,dsr"), &CrystalLineParser::ParseLineBasic, SRCOPT_AUTOINDENT, /*4,*/ _T (""), _T (""), _T ("\'"), (DWORD)-1,
-    CCrystalTextView::SRC_BATCH, _T ("Batch"), _T ("bat,btm,cmd"), &CrystalLineParser::ParseLineBatch, SRCOPT_INSERTTABS|SRCOPT_AUTOINDENT, /*4,*/ _T (""), _T (""), _T ("rem "), (DWORD)-1,
-    CCrystalTextView::SRC_C, _T ("C"), _T ("c,cc,cpp,cxx,h,hpp,hxx,hm,inl,rh,tlh,tli,xs"), &CrystalLineParser::ParseLineC, SRCOPT_AUTOINDENT|SRCOPT_BRACEANSI, /*2,*/ _T ("/*"), _T ("*/"), _T ("//"), (DWORD)-1,
-    CCrystalTextView::SRC_CSHARP, _T ("C#"), _T ("cs"), &CrystalLineParser::ParseLineCSharp, SRCOPT_AUTOINDENT|SRCOPT_BRACEANSI, /*2,*/ _T ("/*"), _T ("*/"), _T ("//"), (DWORD)-1,
-    CCrystalTextView::SRC_CSS, _T ("CSS"), _T ("css"), &CrystalLineParser::ParseLineCss, SRCOPT_AUTOINDENT|SRCOPT_BRACEANSI, /*2,*/ _T ("/*"), _T ("*/"), _T (""), (DWORD)-1,
-    CCrystalTextView::SRC_DCL, _T ("DCL"), _T ("dcl,dcc"), &CrystalLineParser::ParseLineDcl, SRCOPT_AUTOINDENT|SRCOPT_BRACEGNU, /*2,*/ _T ("/*"), _T ("*/"), _T ("//"), (DWORD)-1,
-    CCrystalTextView::SRC_FORTRAN, _T ("Fortran"), _T ("f,f90,f9p,fpp,for,f77"), &CrystalLineParser::ParseLineFortran, SRCOPT_INSERTTABS|SRCOPT_AUTOINDENT, /*8,*/ _T (""), _T (""), _T ("!"), (DWORD)-1,
-    CCrystalTextView::SRC_GO, _T ("Go"), _T ("go"), &CrystalLineParser::ParseLineGo, SRCOPT_AUTOINDENT|SRCOPT_BRACEANSI, /*2,*/ _T ("/*"), _T ("*/"), _T ("//"), (DWORD)-1,
-    CCrystalTextView::SRC_HTML, _T ("HTML"), _T ("html,htm,shtml,ihtml,ssi,stm,stml,jsp"), &CrystalLineParser::ParseLineHtml, SRCOPT_AUTOINDENT|SRCOPT_BRACEANSI, /*2,*/ _T ("<!--"), _T ("-->"), _T (""), (DWORD)-1,
-    CCrystalTextView::SRC_INI, _T ("INI"), _T ("ini,reg,vbp,isl"), &CrystalLineParser::ParseLineIni, SRCOPT_AUTOINDENT|SRCOPT_BRACEGNU|SRCOPT_EOLNUNIX, /*2,*/ _T (""), _T (""), _T (";"), (DWORD)-1,
-    CCrystalTextView::SRC_INNOSETUP, _T ("InnoSetup"), _T ("iss"), &CrystalLineParser::ParseLineInnoSetup, SRCOPT_AUTOINDENT|SRCOPT_BRACEANSI, /*2,*/ _T ("{"), _T ("}"), _T (";"), (DWORD)-1,
-    CCrystalTextView::SRC_INSTALLSHIELD, _T ("InstallShield"), _T ("rul"), &CrystalLineParser::ParseLineIS, SRCOPT_AUTOINDENT|SRCOPT_BRACEANSI, /*2,*/ _T ("/*"), _T ("*/"), _T ("//"), (DWORD)-1,
-    CCrystalTextView::SRC_JAVA, _T ("Java"), _T ("java,jav,js"), &CrystalLineParser::ParseLineJava, SRCOPT_AUTOINDENT|SRCOPT_BRACEANSI, /*2,*/ _T ("/*"), _T ("*/"), _T ("//"), (DWORD)-1,
-    CCrystalTextView::SRC_LISP, _T ("AutoLISP"), _T ("lsp,dsl"), &CrystalLineParser::ParseLineLisp, SRCOPT_AUTOINDENT|SRCOPT_BRACEANSI, /*2,*/ _T (";|"), _T ("|;"), _T (";"), (DWORD)-1,
-    CCrystalTextView::SRC_LUA, _T ("Lua"), _T ("lua"), &CrystalLineParser::ParseLineLua, SRCOPT_AUTOINDENT|SRCOPT_BRACEANSI, /*2,*/ _T ("--[["), _T ("]]"), _T ("--"), (DWORD)-1,
-    CCrystalTextView::SRC_NSIS, _T ("NSIS"), _T ("nsi,nsh"), &CrystalLineParser::ParseLineNsis, SRCOPT_AUTOINDENT|SRCOPT_BRACEANSI, /*2,*/ _T ("/*"), _T ("*/"), _T (";"), (DWORD)-1,
-    CCrystalTextView::SRC_PASCAL, _T ("Pascal"), _T ("pas"), &CrystalLineParser::ParseLinePascal, SRCOPT_AUTOINDENT|SRCOPT_BRACEANSI, /*2,*/ _T ("{"), _T ("}"), _T (""), (DWORD)-1,
-    CCrystalTextView::SRC_PERL, _T ("Perl"), _T ("pl,pm,plx"), &CrystalLineParser::ParseLinePerl, SRCOPT_AUTOINDENT|SRCOPT_EOLNUNIX, /*4,*/ _T (""), _T (""), _T ("#"), (DWORD)-1,
-    CCrystalTextView::SRC_PHP, _T ("PHP"), _T ("php,php3,php4,php5,phtml"), &CrystalLineParser::ParseLinePhp, SRCOPT_AUTOINDENT|SRCOPT_BRACEGNU, /*2,*/ _T ("/*"), _T ("*/"), _T ("//"), (DWORD)-1,
-    CCrystalTextView::SRC_PO, _T ("PO"), _T ("po,pot"), &CrystalLineParser::ParseLinePo, SRCOPT_AUTOINDENT|SRCOPT_EOLNUNIX, /*4,*/ _T (""), _T (""), _T ("#"), (DWORD)-1,
-    CCrystalTextView::SRC_POWERSHELL, _T ("PowerShell"), _T ("ps1"), &CrystalLineParser::ParseLinePowerShell, SRCOPT_AUTOINDENT|SRCOPT_BRACEANSI, /*2,*/ _T (""), _T (""), _T ("#"), (DWORD)-1,
-    CCrystalTextView::SRC_PYTHON, _T ("Python"), _T ("py"), &CrystalLineParser::ParseLinePython, SRCOPT_AUTOINDENT|SRCOPT_BRACEGNU, /*2,*/ _T ("/*"), _T ("*/"), _T ("//"), (DWORD)-1,
-    CCrystalTextView::SRC_REXX, _T ("REXX"), _T ("rex,rexx"), &CrystalLineParser::ParseLineRexx, SRCOPT_AUTOINDENT, /*4,*/ _T ("/*"), _T ("*/"), _T ("//"), (DWORD)-1,
-    CCrystalTextView::SRC_RSRC, _T ("Resources"), _T ("rc,dlg,r16,r32,rc2"), &CrystalLineParser::ParseLineRsrc, SRCOPT_AUTOINDENT, /*4,*/ _T ("/*"), _T ("*/"), _T ("//"), (DWORD)-1,
-    CCrystalTextView::SRC_RUBY, _T ("Ruby"), _T ("rb,rbw,rake,gemspec"), &CrystalLineParser::ParseLineRuby, SRCOPT_AUTOINDENT|SRCOPT_EOLNUNIX, /*4,*/ _T (""), _T (""), _T ("#"), (DWORD)-1,
-    CCrystalTextView::SRC_RUST, _T ("Rust"), _T ("rs"), &CrystalLineParser::ParseLineRust, SRCOPT_AUTOINDENT|SRCOPT_BRACEANSI, /*2,*/ _T ("/*"), _T ("*/"), _T ("//"), (DWORD)-1,
-    CCrystalTextView::SRC_SGML, _T ("Sgml"), _T ("sgml"), &CrystalLineParser::ParseLineSgml, SRCOPT_AUTOINDENT|SRCOPT_BRACEANSI, /*2,*/ _T ("<!--"), _T ("-->"), _T (""), (DWORD)-1,
-    CCrystalTextView::SRC_SH, _T ("Shell"), _T ("sh,conf"), &CrystalLineParser::ParseLineSh, SRCOPT_INSERTTABS|SRCOPT_AUTOINDENT|SRCOPT_EOLNUNIX, /*4,*/ _T (""), _T (""), _T ("#"), (DWORD)-1,
-    CCrystalTextView::SRC_SIOD, _T ("SIOD"), _T ("scm"), &CrystalLineParser::ParseLineSiod, SRCOPT_AUTOINDENT|SRCOPT_BRACEGNU, /*2,*/ _T (";|"), _T ("|;"), _T (";"), (DWORD)-1,
-    CCrystalTextView::SRC_SQL, _T ("SQL"), _T ("sql"), &CrystalLineParser::ParseLineSql, SRCOPT_AUTOINDENT, /*4,*/ _T ("/*"), _T ("*/"), _T ("//"), (DWORD)-1,
-    CCrystalTextView::SRC_TCL, _T ("TCL"), _T ("tcl"), &CrystalLineParser::ParseLineTcl, SRCOPT_AUTOINDENT|SRCOPT_BRACEGNU|SRCOPT_EOLNUNIX, /*2,*/ _T (""), _T (""), _T ("#"), (DWORD)-1,
-    CCrystalTextView::SRC_TEX, _T ("TEX"), _T ("tex,sty,clo,ltx,fd,dtx"), &CrystalLineParser::ParseLineTex, SRCOPT_AUTOINDENT, /*4,*/ _T (""), _T (""), _T ("%"), (DWORD)-1,
-    CCrystalTextView::SRC_VERILOG, _T ("Verilog"), _T ("v,vh"), &CrystalLineParser::ParseLineVerilog, SRCOPT_AUTOINDENT|SRCOPT_BRACEANSI, /*2,*/ _T ("/*"), _T ("*/"), _T ("//"), (DWORD)-1,
-    CCrystalTextView::SRC_VHDL, _T ("VHDL"), _T ("vhd,vhdl,vho"), &CrystalLineParser::ParseLineVhdl, SRCOPT_AUTOINDENT|SRCOPT_BRACEANSI, /*2,*/ _T (""), _T (""), _T ("--"), (DWORD)-1,
-    CCrystalTextView::SRC_XML, _T ("XML"), _T ("xml"), &CrystalLineParser::ParseLineXml, SRCOPT_AUTOINDENT|SRCOPT_BRACEANSI, /*2,*/ _T ("<!--"), _T ("-->"), _T (""), (DWORD)-1
-  };
-
 /////////////////////////////////////////////////////////////////////////////
 // CCrystalTextView construction/destruction
 
-bool
-MatchType (CString pattern, LPCTSTR lpszExt)
-{
-  CString part;
-  int pos, len = pattern.GetLength ();
-
-  while ((pos = pattern.Find (_T (','))) != -1)
-    {
-      part = pattern.Left (pos);
-      if (!part.IsEmpty () && fpattern_isvalid (part))
-        {
-          if (fpattern_matchn (part, lpszExt))
-            {
-              return true;
-            }
-        }
-      len -= pos + 1;
-      pattern = pattern.Right (len);
-    }
-  if (!pattern.IsEmpty () && fpattern_isvalid (pattern))
-    {
-      if (fpattern_matchn (pattern, lpszExt))
-        {
-          return true;
-        }
-    }
-  return false;
-}
-
 bool CCrystalTextView::
-DoSetTextType (TextDefinition *def)
+DoSetTextType (CrystalLineParser::TextDefinition *def)
 {
   m_CurSourceDef = def;
   SetFlags (def->flags);
@@ -395,37 +322,23 @@ DoSetTextType (TextDefinition *def)
   return true;
 }
 
-CCrystalTextView::TextDefinition* CCrystalTextView::
-GetTextType (LPCTSTR pszExt)
-{
-  TextDefinition *def;
-  CString sExt = pszExt;
-
-  def = CCrystalTextView::m_SourceDefs;
-  sExt.MakeLower ();
-  for (int i = 0; i < _countof (CCrystalTextView::m_SourceDefs); i++, def++)
-    if (MatchType (def->exts, sExt))
-      return def;
-  return nullptr;
-}
-
 bool CCrystalTextView::
-SetTextType (LPCTSTR pszExt)
+SetTextType (const tchar_t* pszExt)
 {
-  m_CurSourceDef = m_SourceDefs;
+  m_CurSourceDef = CrystalLineParser::m_SourceDefs;
 
-  TextDefinition *def = GetTextType (pszExt);
+  CrystalLineParser::TextDefinition *def = CrystalLineParser::GetTextType (pszExt);
 
   return SetTextType (def);
 }
 
 bool CCrystalTextView::
-SetTextType (CCrystalTextView::TextType enuType)
+SetTextType (CrystalLineParser::TextType enuType)
 {
-  TextDefinition *def;
+  CrystalLineParser::TextDefinition *def;
 
-  m_CurSourceDef = def = m_SourceDefs;
-  for (int i = 0; i < _countof (m_SourceDefs); i++, def++)
+  m_CurSourceDef = def = CrystalLineParser::m_SourceDefs;
+  for (int i = 0; i < _countof (CrystalLineParser::m_SourceDefs); i++, def++)
     {
       if (def->type == enuType)
         {
@@ -436,7 +349,7 @@ SetTextType (CCrystalTextView::TextType enuType)
 }
 
 bool CCrystalTextView::
-SetTextType (CCrystalTextView::TextDefinition *def)
+SetTextType (CrystalLineParser::TextDefinition *def)
 {
   if (def)
     if (m_CurSourceDef != def)
@@ -446,85 +359,14 @@ SetTextType (CCrystalTextView::TextDefinition *def)
   return false;
 }
 
-void CCrystalTextView::
-LoadSettings ()
-{
-  TextDefinition *def = m_SourceDefs;
-  bool bFontLoaded;
-  CReg reg;
-  if (reg.Open (HKEY_CURRENT_USER, REG_EDITPAD, KEY_READ))
-    {
-      reg.LoadNumber (_T ("DefaultEncoding"), (DWORD*) &CCrystalTextBuffer::m_nDefaultEncoding);
-      for (int i = 0; i < _countof (m_SourceDefs); i++, def++)
-        {
-          CReg reg1;
-          if (reg1.Open (reg.hKey, def->name, KEY_READ))
-            {
-              reg1.LoadString (_T ("Extensions"), def->exts, _countof (def->exts));
-              reg1.LoadNumber (_T ("Flags"), &def->flags);
-//              reg1.LoadNumber (_T ("TabSize"), &def->tabsize);
-              reg1.LoadString (_T ("OpenComment"), def->opencomment, _countof (def->opencomment));
-              reg1.LoadString (_T ("CloseComment"), def->closecomment, _countof (def->closecomment));
-              reg1.LoadString (_T ("CommentLine"), def->commentline, _countof (def->commentline));
-              reg1.LoadNumber (_T ("DefaultEncoding"), &def->encoding);
-            }
-        }
-      bFontLoaded = reg.LoadBinary (_T ("LogFont"), (LPBYTE) &m_LogFont, sizeof (m_LogFont));
-    }
-  else
-    bFontLoaded = false;
-  if (!bFontLoaded)
-    {
-      CWindowDC dc (CWnd::GetDesktopWindow ());
-      NONCLIENTMETRICS info;
-      info.cbSize = sizeof(info);
-      SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(info), &info, 0);
-      memcpy (&m_LogFont, &info.lfMessageFont, sizeof (LOGFONT));
-      m_LogFont.lfHeight = -MulDiv (11, dc.GetDeviceCaps (LOGPIXELSY), 72);
-      m_LogFont.lfWeight = FW_NORMAL;
-      m_LogFont.lfOutPrecision = OUT_DEFAULT_PRECIS;
-      m_LogFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
-      m_LogFont.lfQuality = DEFAULT_QUALITY;
-      m_LogFont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
-      _tcscpy_s (m_LogFont.lfFaceName, _T ("Courier New"));
-    }
-}
-
-void CCrystalTextView::
-SaveSettings ()
-{
-  TextDefinition *def = m_SourceDefs;
-  CReg reg;
-  if (reg.Create (HKEY_CURRENT_USER, REG_EDITPAD, KEY_WRITE))
-    {
-      VERIFY (reg.SaveNumber (_T ("DefaultEncoding"), (DWORD) CCrystalTextBuffer::m_nDefaultEncoding));
-      for (int i = 0; i < _countof (m_SourceDefs); i++, def++)
-        {
-          CReg reg1;
-          if (reg1.Create (reg.hKey, def->name, KEY_WRITE))
-            {
-              VERIFY (reg1.SaveString (_T ("Extensions"), def->exts));
-              VERIFY (reg1.SaveNumber (_T ("Flags"), def->flags));
-//              VERIFY (reg1.SaveNumber (_T ("TabSize"), def->tabsize));
-              VERIFY (reg1.SaveString (_T ("OpenComment"), def->opencomment));
-              VERIFY (reg1.SaveString (_T ("CloseComment"), def->closecomment));
-              VERIFY (reg1.SaveString (_T ("CommentLine"), def->commentline));
-              VERIFY (reg1.SaveNumber (_T ("DefaultEncoding"), def->encoding));
-            }
-        }
-      VERIFY (reg.SaveBinary (_T ("LogFont"), (LPBYTE) &m_LogFont, sizeof (m_LogFont)));
-    }
-}
-
 CCrystalTextView::CCrystalTextView ()
 : m_nScreenChars(-1)
 , m_pFindTextDlg(nullptr)
 , m_CurSourceDef(nullptr)
 , m_dwLastDblClickTime(0)
-, m_iterChar(UBRK_CHARACTER, "en", nullptr, 0)
-, m_iterWord(UBRK_WORD, "en", nullptr, 0)
 , m_rxnode(nullptr)
 , m_pszMatched(nullptr)
+, m_bTopMargin(false)
 , m_bSelMargin(true)
 , m_bViewLineNumbers(false)
 , m_bWordWrap(false)
@@ -532,11 +374,8 @@ CCrystalTextView::CCrystalTextView ()
 , m_bLastSearch(false)
 , m_bBookmarkExist(false)
 , m_bSingle(false) // needed to be set in descendat classes
-, m_bRememberLastPos(false)
 , m_pColors(nullptr)
 , m_nLastLineIndexCalculatedSubLineIndex(-1)
-, m_pIcons(nullptr)
-, m_apFonts{}
 , m_hAccel(nullptr)
 , m_pTextBuffer(nullptr)
 , m_pCacheBitmap(nullptr)
@@ -552,11 +391,11 @@ CCrystalTextView::CCrystalTextView ()
 , m_dwFlags(0)
 , m_nScreenLines(0)
 , m_pMarkers(nullptr)
-, m_panSubLines(new CArray<int, int>())
-, m_panSubLineIndexCache(new CArray<int, int>())
+, m_panSubLines(new std::vector<int>())
+, m_panSubLineIndexCache(new std::vector<int>())
 , m_pstrIncrementalSearchString(new CString)
 , m_pstrIncrementalSearchStringOld(new CString)
-, m_ParseCookies(new vector<DWORD>)
+, m_ParseCookies(new vector<uint32_t>)
 , m_pnActualLineLength(new vector<int>)
 , m_nIdealCharPos(0)
 , m_bFocused(false)
@@ -564,16 +403,19 @@ CCrystalTextView::CCrystalTextView ()
 , m_lfSavedBaseFont{}
 , m_pParser(nullptr)
 , m_pPrintFont(nullptr)
+#ifdef _UNICODE
 , m_bChWidthsCalculated{}
 , m_iChDoubleWidthFlags{}
+#endif
 , m_bPreparingToDrag(false)
 , m_bDraggingText(false)
 , m_bDragSelection(false)
 , m_bWordSelection(false)
 , m_bLineSelection(false)
+, m_bRectangularSelection(false)
 , m_bColumnSelection(false)
 , m_nDragSelTimer(0)
-, m_bOverrideCaret(false)
+, m_bOvrMode(false)
 , m_nLastFindWhatLen(0)
 , m_nPrintPages(0)
 , m_nPrintLineHeight(0)
@@ -592,13 +434,28 @@ CCrystalTextView::CCrystalTextView ()
 , m_bIncrementalSearchBackward(false)
 , m_bIncrementalFound(false)
 , m_rxmatch{}
-{
-  m_panSubLines->SetSize( 0, 4096 );
-  m_panSubLineIndexCache->SetSize( 0, 4096 );
+, m_nRenderingMode(s_nRenderingModeDefault)
+, m_pCrystalRendererSaved(nullptr)
+, m_nColumnResizing(-1)
+, m_nLineNumberUsedAsHeaders(-1)
+{
+#ifdef _WIN64
+  if (m_nRenderingMode == RENDERING_MODE::GDI)
+    m_pCrystalRenderer.reset(new CCrystalRendererGDI());
+  else
+    m_pCrystalRenderer.reset(new CCrystalRendererDirectWrite(static_cast<int>(m_nRenderingMode)));
+#else
+  m_pCrystalRenderer.reset(new CCrystalRendererGDI());
+#endif
+
+  m_panSubLines->reserve(4096);
+  m_panSubLines->resize(0);
+  m_panSubLineIndexCache->reserve (4096);
+  m_panSubLineIndexCache->resize ( 0);
 
   //END SW
-  ResetView ();
-  SetTextType (SRC_PLAIN);
+  CCrystalTextView::ResetView ();
+  SetTextType (CrystalLineParser::SRC_PLAIN);
 }
 
 CCrystalTextView::~CCrystalTextView ()
@@ -609,42 +466,28 @@ CCrystalTextView::~CCrystalTextView ()
 
   delete m_pFindTextDlg;
 
-  if (m_pszLastFindWhat != nullptr)
-    {
-      free (m_pszLastFindWhat);
-      m_pszLastFindWhat=nullptr;
-    }
-  if (m_rxnode != nullptr)
-    {
-      RxFree (m_rxnode);
-      m_rxnode = nullptr;
-    }
-  if (m_pszMatched != nullptr)
-    {
-      free(m_pszMatched); // Allocated by _tcsdup()
-      m_pszMatched = nullptr;
-    }
+  free (m_pszLastFindWhat);
+  m_pszLastFindWhat=nullptr;
+
+  RxFree (m_rxnode);
+  m_rxnode = nullptr;
+
+  free(m_pszMatched); // Allocated by tc::tcsdup()
+  m_pszMatched = nullptr;
+
   //BEGIN SW
-  if( m_panSubLines != nullptr )
-    {
-      delete m_panSubLines;
-      m_panSubLines = nullptr;
-    }
-  if( m_panSubLineIndexCache != nullptr )
-    {
-      delete m_panSubLineIndexCache;
-      m_panSubLineIndexCache = nullptr;
-    }
-  if( m_pstrIncrementalSearchString != nullptr )
-    {
-      delete m_pstrIncrementalSearchString;
-      m_pstrIncrementalSearchString = nullptr;
-    }
-  if( m_pstrIncrementalSearchStringOld != nullptr )
-    {
-      delete m_pstrIncrementalSearchStringOld;
-      m_pstrIncrementalSearchStringOld = nullptr;
-    }
+  delete m_panSubLines;
+  m_panSubLines = nullptr;
+
+  delete m_panSubLineIndexCache;
+  m_panSubLineIndexCache = nullptr;
+
+  delete m_pstrIncrementalSearchString;
+  m_pstrIncrementalSearchString = nullptr;
+
+  delete m_pstrIncrementalSearchStringOld;
+  m_pstrIncrementalSearchStringOld = nullptr;
+
   //END SW
   ASSERT(m_ParseCookies != nullptr);
   delete m_ParseCookies;
@@ -652,9 +495,8 @@ CCrystalTextView::~CCrystalTextView ()
   ASSERT(m_pnActualLineLength != nullptr);
   delete m_pnActualLineLength;
   m_pnActualLineLength = nullptr;
-  delete m_pIcons;
   if (m_pMarkers != nullptr)
-      m_pMarkers->DeleteView(this);
+    m_pMarkers->DeleteView(this);
 }
 
 BOOL CCrystalTextView::
@@ -665,16 +507,16 @@ PreCreateWindow (CREATESTRUCT & cs)
     {
       //  View must always create its own scrollbars,
       //  if only it's not used within splitter
-    //BEGIN SW
-    if( m_bWordWrap )
-      // we do not need a horizontal scroll bar, if we wrap the lines
-      cs.style|= WS_VSCROLL;
-    else
+      //BEGIN SW
+      if( GetTextLayoutMode () == TEXTLAYOUT_WORDWRAP )
+        // we do not need a horizontal scroll bar, if we wrap the lines
+        cs.style|= WS_VSCROLL;
+      else
+        cs.style |= (WS_HSCROLL | WS_VSCROLL);
+      /*ORIGINAL
       cs.style |= (WS_HSCROLL | WS_VSCROLL);
-    /*ORIGINAL
-    cs.style |= (WS_HSCROLL | WS_VSCROLL);
-    */
-    //END SW
+      */
+      //END SW
     }
   cs.lpszClass = AfxRegisterWndClass (CS_DBLCLKS);
   return CView::PreCreateWindow (cs);
@@ -684,12 +526,11 @@ PreCreateWindow (CREATESTRUCT & cs)
 /////////////////////////////////////////////////////////////////////////////
 // CCrystalTextView drawing
 
-void CCrystalTextView::
-GetSelection (CPoint & ptStart, CPoint & ptEnd)
+std::pair<CEPoint, CEPoint> CCrystalTextView::
+GetSelection ()
 {
   PrepareSelBounds ();
-  ptStart = m_ptDrawSelStart;
-  ptEnd = m_ptDrawSelEnd;
+  return { m_ptDrawSelStart, m_ptDrawSelEnd };
 }
 
 bool CCrystalTextView::
@@ -739,9 +580,7 @@ GetColumnSelection (int nLineIndex, int & nSelBegin, int & nSelEnd)
 void CCrystalTextView::
 GetFullySelectedLines(int & firstLine, int & lastLine)
 {
-  CPoint ptStart;
-  CPoint ptEnd;
-  GetSelection(ptStart, ptEnd);
+  auto [ptStart, ptEnd] = GetSelection ();
 
   if (ptStart.x == 0)
     firstLine = ptStart.y;
@@ -785,23 +624,59 @@ GetLineActualLength (int nLineIndex)
     }
 
   if ((*m_pnActualLineLength)[nLineIndex] != - 1)
-      return (*m_pnActualLineLength)[nLineIndex];
+    return (*m_pnActualLineLength)[nLineIndex];
 
   //  Actual line length is not determined yet, let's calculate a little
   int nActualLength = 0;
   int nLength = GetLineLength (nLineIndex);
   if (nLength > 0)
     {
-      LPCTSTR pszChars = GetLineChars (nLineIndex);
+      const tchar_t* pszChars = GetLineChars (nLineIndex);
       const int nTabSize = GetTabSize ();
-      m_iterChar.setText(reinterpret_cast<const UChar *>(pszChars), nLength);
-      for (int i = 0; i < nLength; i = m_iterChar.next())
+      auto pIterChar = ICUBreakIterator::getCharacterBreakIterator(pszChars, nLength);
+      switch ( GetTextLayoutMode ())
         {
-          TCHAR c = pszChars[i];
-          if (c == _T('\t'))
-            nActualLength += (nTabSize - nActualLength % nTabSize);
-          else
-            nActualLength += GetCharCellCountFromChar(pszChars + i);
+          case TEXTLAYOUT_TABLE_NOWORDWRAP:
+          case TEXTLAYOUT_TABLE_WORDWRAP:
+            {
+              int nColumnCount =  m_pTextBuffer->GetColumnCount (nLineIndex);
+              int nColumnTotalWidth = 0;
+              bool bInQuote = false;
+              const int sep = m_pTextBuffer->GetFieldDelimiter ();
+              const int quote = m_pTextBuffer->GetFieldEnclosure ();
+              for (int i = 0, nColumn = 0; i < nLength; i = pIterChar->next())
+                {
+                  tchar_t c = pszChars[i];
+                  if (!bInQuote && c == sep)
+                    {
+                      nColumnTotalWidth += m_pTextBuffer->GetColumnWidth (nColumn++);
+                      nActualLength = nColumnTotalWidth;
+                    }
+                  else
+                    {
+                      if (c == quote)
+                        bInQuote = !bInQuote;
+                      if (c == '\t')
+                        nActualLength ++;
+                      else
+                        nActualLength += GetCharCellCountFromChar (pszChars + i);
+                      if (nColumn < nColumnCount && nActualLength > nColumnTotalWidth + m_pTextBuffer->GetColumnWidth (nColumn))
+                        nActualLength = nColumnTotalWidth + m_pTextBuffer->GetColumnWidth (nColumn);
+                    }
+                }
+            }
+            break;
+          default:
+            {
+              for (int i = 0; i < nLength; i = pIterChar->next())
+                {
+                  tchar_t c = pszChars[i];
+                  if (c == _T('\t'))
+                    nActualLength += (nTabSize - nActualLength % nTabSize);
+                  else
+                    nActualLength += GetCharCellCountFromChar(pszChars + i);
+                }
+            }
         }
     }
 
@@ -810,11 +685,11 @@ GetLineActualLength (int nLineIndex)
 }
 
 void CCrystalTextView::
-ScrollToChar (int nNewOffsetChar, bool bNoSmoothScroll /*= false*/ , bool bTrackScrollBar /*= true*/ )
+ScrollToChar (int nNewOffsetChar, bool bNoSmoothScroll /*= false*/, bool bTrackScrollBar /*= true*/ )
 {
   //BEGIN SW
   // no horizontal scrolling, when word wrapping is enabled
-  if( m_bWordWrap )
+  if (GetTextLayoutMode () == TEXTLAYOUT_WORDWRAP)
     return;
   //END SW
 
@@ -826,6 +701,8 @@ ScrollToChar (int nNewOffsetChar, bool bNoSmoothScroll /*= false*/ , bool bTrack
       CRect rcScroll;
       GetClientRect (&rcScroll);
       rcScroll.left += GetMarginWidth ();
+         CRect rcTopMargin(rcScroll.left, rcScroll.top, rcScroll.right, GetTopMarginHeight());
+         InvalidateRect (&rcTopMargin); // Make sure the ruler is drawn correctly when scrolling horizontally 
       ScrollWindow (nScrollChars * GetCharWidth (), 0, &rcScroll, &rcScroll);
       UpdateWindow ();
       if (bTrackScrollBar)
@@ -849,6 +726,18 @@ void CCrystalTextView::ScrollToSubLine( int nNewTopSubLine,
 {
   if (m_nTopSubLine != nNewTopSubLine)
     {
+      CRect rcScroll;
+      GetClientRect (&rcScroll);
+
+      if (m_pTextBuffer->GetTableEditing () &&
+         ((m_nTopSubLine > 0 && nNewTopSubLine == 0) || (m_nTopSubLine == 0 && nNewTopSubLine > 0)))
+        {
+          CRect rcTopMargin(rcScroll.left, rcScroll.top, rcScroll.right, GetTopMarginHeight ());
+          InvalidateRect (&rcTopMargin);
+        }
+
+      rcScroll.top += GetTopMarginHeight ();
+
       if (bNoSmoothScroll || ! m_bSmoothScroll)
         {
           // Limit scrolling so that we show one empty line at end of file
@@ -866,12 +755,12 @@ void CCrystalTextView::ScrollToSubLine( int nNewTopSubLine,
           // OnDraw() uses m_nTopLine to determine topline
           int dummy;
           GetLineBySubLine(m_nTopSubLine, m_nTopLine, dummy);
-          ScrollWindow(0, nScrollLines * GetLineHeight());
+          ScrollWindow(0, nScrollLines * GetLineHeight(), rcScroll, rcScroll);
           UpdateWindow();
           if (bTrackScrollBar)
             {
               RecalcVertScrollBar(true);
-              RecalcHorzScrollBar();
+              InvalidateHorzScrollBar ();
             }
         }
       else
@@ -888,12 +777,12 @@ void CCrystalTextView::ScrollToSubLine( int nNewTopSubLine,
                     nTopSubLine = nNewTopSubLine;
                   const int nScrollLines = nTopSubLine - m_nTopSubLine;
                   m_nTopSubLine = nTopSubLine;
-                  ScrollWindow(0, - nLineHeight * nScrollLines);
+                  ScrollWindow(0, - nLineHeight * nScrollLines, rcScroll, rcScroll);
                   UpdateWindow();
                   if (bTrackScrollBar)
                     {
                       RecalcVertScrollBar(true);
-                      RecalcHorzScrollBar();
+                      InvalidateHorzScrollBar ();
                     }
                 }
             }
@@ -907,12 +796,12 @@ void CCrystalTextView::ScrollToSubLine( int nNewTopSubLine,
                     nTopSubLine = nNewTopSubLine;
                   const int nScrollLines = nTopSubLine - m_nTopSubLine;
                   m_nTopSubLine = nTopSubLine;
-                  ScrollWindow(0, - nLineHeight * nScrollLines);
+                  ScrollWindow(0, - nLineHeight * nScrollLines, rcScroll, rcScroll);
                   UpdateWindow();
                   if (bTrackScrollBar)
                     {
                       RecalcVertScrollBar(true);
-                      RecalcHorzScrollBar();
+                      InvalidateHorzScrollBar ();
                     }
                 }
             }
@@ -923,34 +812,34 @@ void CCrystalTextView::ScrollToSubLine( int nNewTopSubLine,
 }
 
 void CCrystalTextView::
-ScrollToLine (int nNewTopLine, bool bNoSmoothScroll /*= false*/ , bool bTrackScrollBar /*= true*/ )
+ScrollToLine (int nNewTopLine, bool bNoSmoothScroll /*= false*/, bool bTrackScrollBar /*= true*/ )
 {
   if( m_nTopLine != nNewTopLine )
     ScrollToSubLine( GetSubLineIndex( nNewTopLine ), bNoSmoothScroll, bTrackScrollBar );
 }
 
 /** Append szadd to string str, and advance position curpos */
-static void AppendStringAdv(CString & str, int & curpos, LPCTSTR szadd)
+static void AppendStringAdv(CString & str, int & curpos, const tchar_t* szadd)
 {
   str += szadd;
-  curpos += (int) _tcslen(szadd);
+  curpos += (int) tc::tcslen(szadd);
 }
 
 /** Append escaped control char to string str, and advance position curpos */
-static void AppendEscapeAdv(CString & str, int & curpos, TCHAR c)
+static void AppendEscapeAdv(CString & str, int & curpos, tchar_t c)
 {
   int curlen = str.GetLength();
-  LPTSTR szadd = str.GetBufferSetLength(curlen + 3) + curlen;
+  tchar_t* szadd = str.GetBufferSetLength(curlen + 3) + curlen;
   curpos += wsprintf(szadd, _T("\t%02X"), static_cast<int>(c));
 }
 
 int CCrystalTextView::
-ExpandChars (LPCTSTR pszChars, int nOffset, int nCount, CString & line, int nActualOffset)
+ExpandChars (int nLineIndex, int nOffset, int nCount, CString & line, int nActualOffset)
 {
   line.Empty();
   // Request whitespace characters for codepage ACP
   // because that is the codepage used by ExtTextOut
-  const ViewableWhitespaceChars * lpspc = GetViewableWhitespaceChars(GetACP());
+  const ViewableWhitespaceChars * lpspc = GetViewableWhitespaceChars(GetACP(), m_nRenderingMode != RENDERING_MODE::GDI);
 
   if (nCount <= 0)
     {
@@ -959,12 +848,13 @@ ExpandChars (LPCTSTR pszChars, int nOffset, int nCount, CString & line, int nAct
 
   const int nTabSize = GetTabSize ();
 
+  const tchar_t* pszChars = GetLineChars(nLineIndex);
   pszChars += nOffset;
   int nLength = nCount;
 
   for (int i = 0; i < nLength; i++)
     {
-      TCHAR c = pszChars[i];
+      tchar_t c = pszChars[i];
       if (c == _T('\t'))
         nCount += nTabSize - 1;
       else if (c >= _T('\x00') && c <= _T('\x1F') && c != _T('\r') && c != _T('\n'))
@@ -975,16 +865,17 @@ ExpandChars (LPCTSTR pszChars, int nOffset, int nCount, CString & line, int nAct
   line.GetBuffer(nCount + 1); // at least this many characters
   line.ReleaseBuffer(0);
   int nCurPos = 0;
+  const bool bTableEditing = m_pTextBuffer->GetTableEditing ();
 
   if (nCount > nLength || m_bViewTabs || m_bViewEols)
     {
-      m_iterChar.setText(reinterpret_cast<const UChar *>(pszChars), nLength);
+      auto pIterChar = ICUBreakIterator::getCharacterBreakIterator(pszChars, nLength);
       for (int i = 0, next = 0; i < nLength; i = next)
         {
-          next = m_iterChar.next();
+          next = pIterChar->next();
           if (pszChars[i] == _T('\t'))
             {
-              int nSpaces = nTabSize - (nActualOffset + nCurPos) % nTabSize;
+              int nSpaces = bTableEditing ? 1 : (nTabSize - (nActualOffset + nCurPos) % nTabSize);
               if (m_bViewTabs)
                 {
                   AppendStringAdv(line, nCurPos, lpspc->c_tab);
@@ -1009,7 +900,7 @@ ExpandChars (LPCTSTR pszChars, int nOffset, int nCount, CString & line, int nAct
                     }
                   else
                     {
-                      if (pszChars[i] == '\r' && i < nLength - 1 && pszChars[i+1] == '\n' && m_bDistinguishEols)
+                      if (i < nLength - 1 && pszChars[i] == '\r' && pszChars[i+1] == '\n' && m_bDistinguishEols)
                         {
                           AppendStringAdv(line, nCurPos, lpspc->c_eol);
                           i++;
@@ -1023,7 +914,7 @@ ExpandChars (LPCTSTR pszChars, int nOffset, int nCount, CString & line, int nAct
                           AppendStringAdv(line, nCurPos, lpspc->c_eol);
                         }
                     }
-                 }
+                }
             }
           else if (pszChars[i] >= _T('\x00') && pszChars[i] <= _T('\x1F'))
             {
@@ -1039,18 +930,267 @@ ExpandChars (LPCTSTR pszChars, int nOffset, int nCount, CString & line, int nAct
     }
   else
     {
-      m_iterChar.setText(reinterpret_cast<const UChar *>(pszChars), nLength);
+      auto pIterChar = ICUBreakIterator::getCharacterBreakIterator(pszChars, nLength);
       for (int i1=0, next=0; i1<nLength; i1 = next)
-      {
-        next = m_iterChar.next();
-        nCurPos += GetCharCellCountFromChar(pszChars + i1);
-        for (; i1 < next; ++i1)
-          line += pszChars[i1];
-      }
+        {
+          next = pIterChar->next();
+          nCurPos += GetCharCellCountFromChar(pszChars + i1);
+          for (; i1 < next; ++i1)
+            line += pszChars[i1];
+        }
     }
   return nCurPos;
 }
 
+int CCrystalTextView::
+ExpandCharsTableEditingNoWrap(int nLineIndex, int nOffset, int nCount, CString& line, int nActualOffset)
+{
+  if (m_pTextBuffer == nullptr || nCount <= 0)
+    return 0;
+
+  const tchar_t* pszChars = GetLineChars(nLineIndex);
+  line.Empty();
+  // Request whitespace characters for codepage ACP
+  // because that is the codepage used by ExtTextOut
+  const ViewableWhitespaceChars * lpspc = GetViewableWhitespaceChars(GetACP(), m_nRenderingMode != RENDERING_MODE::GDI);
+
+  int nLength = nCount;
+  int nColumn = 0;
+  int nColumnCount = 0;
+  int nCurColumn = -1;
+  int nColumnTotalWidth = 0;
+  int nColumnBegin = 0;
+  int nColumnTotalWidthBegin = 0;
+  const int nLineLength = GetFullLineLength (nLineIndex);
+  const int nTabSize = GetTabSize ();
+  const int sep = m_pTextBuffer->GetFieldDelimiter ();
+  const int quote = m_pTextBuffer->GetFieldEnclosure ();
+  const int eollen = nLineLength - GetLineLength (nLineIndex);
+  bool bInQuote = false;
+  bool bInQuoteBegin = false;
+
+  for (int i = 0; i < nLineLength; i++)
+    {
+      tchar_t c = pszChars[i];
+      if (i == nOffset)
+        {
+          nColumnBegin = nColumn;
+          nColumnTotalWidthBegin = nColumnTotalWidth;
+          bInQuoteBegin = bInQuote;
+        }
+      if (nLineIndex == m_ptCursorPos.y && i == m_ptCursorPos.x)
+        nCurColumn = nColumn;
+      if (!bInQuote && c == sep)
+        {
+          nColumnTotalWidth += m_pTextBuffer->GetColumnWidth (nColumn++);
+          nCount = nColumnTotalWidth;
+        }
+      else if (c == '\t')
+        nCount += 1 - 1;
+      else if (c == quote)
+        {
+          bInQuote = !bInQuote;
+        }
+      else if (c >= '\x00' && c <= '\x1F' && c != '\r' && c != '\n')
+        nCount += 3 - 1;
+    }
+  nColumnCount = nColumn + 1;
+
+  // Preallocate line buffer, to avoid reallocations as we add characters
+  line.GetBuffer (nCount + 1); // at least this many characters
+  line.ReleaseBuffer (0);
+  int nCurPos = nActualOffset;
+
+  pszChars += nOffset;
+
+  int curColumnTextCellWidth = 0;
+  bool beforeCursorPos = (nLineIndex == m_ptCursorPos.y && nOffset < m_ptCursorPos.x);
+  CString curColumnText;
+  std::vector<std::pair<int, int>> curColumnByteLenCellWidth;
+  nColumn = nColumnBegin;
+  nColumnTotalWidth = nColumnTotalWidthBegin;
+  bInQuote = bInQuoteBegin;
+  auto pIterChar = ICUBreakIterator::getCharacterBreakIterator (pszChars, nLineLength - nOffset);
+  auto nextColumnDistance = [&](int nCurPos)
+    {
+      return (nColumn == nColumnCount - 1) ? INT_MAX : nColumnTotalWidth + m_pTextBuffer->GetColumnWidth (nColumn) - nCurPos;
+    };
+  auto appendChars = [&](int i, int next, int pos, CString& text, int& textwidth)
+    {
+      tchar_t c = pszChars[i];
+      if ((c == '\r' || c == '\n') && i >= nLineLength - nOffset - eollen)
+        {
+          if (m_bViewEols)
+            {
+              if (c == '\n' && !m_bDistinguishEols && i+nOffset>0 && pszChars[i-1] == '\r')
+                {
+                  // Ignore \n after \r
+                }
+              else
+                {
+                  int prevtextwidth = textwidth;
+                  if (c == '\r' && i < nLength - 1 && pszChars[i+1] == '\n' && m_bDistinguishEols)
+                    AppendStringAdv (text, textwidth, lpspc->c_eol);
+                  else if (c == '\r' && m_bDistinguishEols)
+                    AppendStringAdv (text, textwidth, lpspc->c_cr);
+                  else if (c == '\n' && m_bDistinguishEols)
+                    {
+                      if (i == 0 || pszChars[i - 1] != '\r')
+                        AppendStringAdv (text, textwidth, lpspc->c_lf);
+                    }
+                  else
+                    AppendStringAdv (text, textwidth, lpspc->c_eol);
+                  if (textwidth - prevtextwidth > 0)
+                    curColumnByteLenCellWidth.push_back ({ textwidth - prevtextwidth, textwidth - prevtextwidth});
+                }
+            }
+        }
+      else if (c == '\t')
+        {
+          int nSpaces = 1;
+          if (sep != '\t' || bInQuote)
+            {
+              nSpaces = 1;
+              if (nSpaces > nextColumnDistance (pos))
+                  nSpaces = nextColumnDistance (pos);
+            }
+          if (nSpaces >= 1 && m_bViewTabs)
+            {
+              curColumnByteLenCellWidth.push_back ({ 1, 1 });
+              AppendStringAdv (text, textwidth, lpspc->c_tab);
+              nSpaces--;
+            }
+          while (nSpaces > 0)
+            {
+              curColumnByteLenCellWidth.push_back ({ 1, 1 });
+              textwidth++;
+              text += ' ';
+              nSpaces--;
+            }
+        }
+      else if (c == ' ' && m_bViewTabs)
+        {
+          curColumnByteLenCellWidth.push_back ({ 1, 1 });
+          AppendStringAdv (text, textwidth, lpspc->c_space);
+       }
+      else if (c >= '\x00' && c <= '\x1F')
+        {
+          curColumnByteLenCellWidth.push_back ({ 3, 3 });
+          AppendEscapeAdv (text, textwidth, c);
+          if (c == '\r' && pszChars[i + 1] == '\n')
+            AppendEscapeAdv (text, textwidth, pszChars[i + 1]);
+        }
+      else
+        {
+          int nLen = GetCharCellCountFromChar (pszChars + i);
+          curColumnByteLenCellWidth.push_back ({ nLen, next - i });
+          textwidth += nLen;
+          for (; i < next; ++i)
+            text += pszChars[i];
+        }
+      if (!bInQuote && c == sep)
+        {
+          int nSpaces = nextColumnDistance (pos + 1);
+          while (nSpaces > 0)
+            {
+              text += ' ';
+              ++textwidth;
+              --nSpaces;
+            }
+          nColumnTotalWidth += m_pTextBuffer->GetColumnWidth (nColumn);
+          ++nColumn;
+        }
+    };
+  int i, next;
+  for (i = 0, next = 0; i < nLength; i = next)
+    {
+      next = pIterChar->next ();
+      tchar_t c = pszChars[i];
+      if (c == quote)
+        bInQuote = !bInQuote;
+      int nLen = GetCharCellCountFromChar (pszChars + i);
+      if (nColumn == nCurColumn && beforeCursorPos)
+        {
+          appendChars (i, next, nCurPos + curColumnTextCellWidth, curColumnText, curColumnTextCellWidth);
+          if (next + nOffset == m_ptCursorPos.x || next >= nLength)
+            {
+              int curColumnTextLenAppended = 0;
+              int curColumnTextCellWidthAppended = 0;
+              if (next + nOffset == m_ptCursorPos.x)
+                beforeCursorPos = false;
+              else
+                {
+                  int curColumnTextLenSaved = curColumnText.GetLength();
+                  int curColumnTextCellWidthSaved = curColumnTextCellWidth;
+                  i = next;
+                  for (; i < nLineLength - nOffset && nColumn == nCurColumn && next + nOffset < m_ptCursorPos.x; i = next)
+                    {
+                      next = pIterChar->next ();
+                      c = pszChars[i];
+                      if (c == quote)
+                        bInQuote = !bInQuote;
+                      nLen = GetCharCellCountFromChar (pszChars + i);
+                      appendChars (i, next, nCurPos + curColumnTextCellWidth, curColumnText, curColumnTextCellWidth);
+                    }
+                  curColumnTextLenAppended = curColumnText.GetLength() - curColumnTextLenSaved;
+                  curColumnTextCellWidthAppended = curColumnTextCellWidth - curColumnTextCellWidthSaved;
+                }
+              if (curColumnTextCellWidth > nextColumnDistance (nCurPos))
+                {
+                  for (size_t k = 0; k < curColumnByteLenCellWidth.size () && curColumnTextCellWidth > nextColumnDistance (nCurPos); ++k)
+                    {
+                      curColumnTextCellWidth -= curColumnByteLenCellWidth[k].first;
+                      curColumnText = curColumnText.Mid (curColumnByteLenCellWidth[k].second);
+                    }
+                  int nSpaces = nextColumnDistance (nCurPos) - curColumnTextCellWidth;
+                  if (nSpaces > 0)
+                    {
+                      CString spaces (' ', nSpaces);
+                      curColumnText.Insert (0, spaces);
+                      curColumnTextCellWidth = m_pTextBuffer->GetColumnWidth (nColumn);
+                    }
+                }
+              if (curColumnTextLenAppended > 0)
+                {
+                  if (curColumnTextLenAppended < curColumnText.GetLength())
+                    {
+                      line += curColumnText.Left(curColumnText.GetLength() - curColumnTextLenAppended);
+                      nCurPos += curColumnTextCellWidth - curColumnTextCellWidthAppended;
+                    }
+                }
+              else
+                {
+                  line += curColumnText;
+                  nCurPos += curColumnTextCellWidth;
+                }
+            }
+        }
+      else
+        {
+          if (nLen <= nextColumnDistance (nCurPos))
+            {
+              appendChars (i, next, nCurPos, line, nCurPos);
+              curColumnByteLenCellWidth.clear ();
+            }
+          else
+            {
+              int nSpaces = nextColumnDistance (nCurPos);
+              while (nSpaces > 0)
+                {
+                  line += ' ';
+                  ++nCurPos;
+                  --nSpaces;
+                }
+              if (!bInQuote && c == sep)
+                {
+                  nColumnTotalWidth += m_pTextBuffer->GetColumnWidth (nColumn);
+                  ++nColumn;
+                }
+            }
+        }
+    }
+  return nCurPos - nActualOffset;
+}
 
 
 /**
@@ -1059,26 +1199,29 @@ ExpandChars (LPCTSTR pszChars, int nOffset, int nCount, CString & line, int nAct
  * @note In ANSI build, this routine is buggy for multibytes or double-width characters
  */
 void CCrystalTextView::
-DrawLineHelperImpl (CDC * pdc, CPoint & ptOrigin, const CRect & rcClip,
-                    int nColorIndex, int nBgColorIndex, COLORREF crText, COLORREF crBkgnd, LPCTSTR pszChars, int nOffset, int nCount, int &nActualOffset)
+DrawLineHelperImpl (CPoint & ptOrigin, const CRect & rcClip, int nColorIndex,
+                    int nBgColorIndex, CEColor crText, CEColor crBkgnd, int nLineIndex, int nOffset, int nCount, int &nActualOffset)
 {
   ASSERT (nCount >= 0);
   if (nCount > 0)
     {
       CString line;
-      nActualOffset += ExpandChars (pszChars, nOffset, nCount, line, nActualOffset);
+      if (GetTextLayoutMode () == TEXTLAYOUT_TABLE_NOWORDWRAP)
+        nActualOffset += ExpandCharsTableEditingNoWrap (nLineIndex, nOffset, nCount, line, nActualOffset);
+      else
+        nActualOffset += ExpandChars (nLineIndex, nOffset, nCount, line, nActualOffset);
       const int lineLen = line.GetLength();
       const int nCharWidth = GetCharWidth();
       const int nCharWidthNarrowed = nCharWidth / 2;
       const int nCharWidthWidened = nCharWidth * 2 - nCharWidthNarrowed;
       const int nLineHeight = GetLineHeight();
-      m_iterChar.setText(reinterpret_cast<const UChar *>((LPCTSTR)line), lineLen);
+      auto pIterChar = ICUBreakIterator::getCharacterBreakIterator((const tchar_t*)line, lineLen);
 
       // i the character index, from 0 to lineLen-1
       int i = 0;
 
       // Pass if the text begins after the right end of the clipping region
-      if (ptOrigin.x < rcClip.right)
+      if (ptOrigin.x < rcClip.right && ptOrigin.y < rcClip.bottom)
         {
           // Because ExtTextOut is buggy when ptOrigin.x < - 4095 * charWidth
           // or when nCount >= 4095
@@ -1088,18 +1231,18 @@ DrawLineHelperImpl (CDC * pdc, CPoint & ptOrigin, const CRect & rcClip,
           // Update the position after the left clipped characters
           // stop for i = first visible character, at least partly
           const int clipLeft = rcClip.left - nCharWidth * 2;
-          for ( ; i < lineLen; i = m_iterChar.next())
-          {
-            int pnWidthsCurrent = GetCharCellCountFromChar(static_cast<const TCHAR *>(line) + i) * nCharWidth;
-            ptOrigin.x += pnWidthsCurrent;
-            if (ptOrigin.x >= clipLeft)
+          for ( ; i < lineLen; i = pIterChar->next())
             {
-              ptOrigin.x -= pnWidthsCurrent;
-              break;
+              int pnWidthsCurrent = GetCharCellCountFromChar(static_cast<const tchar_t *>(line) + i) * nCharWidth;
+              ptOrigin.x += pnWidthsCurrent;
+              if (ptOrigin.x >= clipLeft)
+                {
+                  ptOrigin.x -= pnWidthsCurrent;
+                  break;
+                }
             }
-          }
-        
-          // 
+
+          //
 #ifdef _DEBUG
           //CSize sz = pdc->GetTextExtent(line, nCount);
           //ASSERT(sz.cx == m_nCharWidth * nCount);
@@ -1111,91 +1254,84 @@ DrawLineHelperImpl (CDC * pdc, CPoint & ptOrigin, const CRect & rcClip,
               int ibegin = i;
               int nSumWidth = 0;
 
-              // A raw estimate of the number of characters to display
-              // For wide characters, nCountFit may be overvalued
               int nWidth = rcClip.right - ptOrigin.x;
-              int nCount1 = lineLen - ibegin;
-              int nCountFit = nWidth / nCharWidth + 2/* wide char */;
-              if (nCount1 > nCountFit) {
-#ifndef _UNICODE
-                if (_ismbslead((unsigned char *)(LPCSTR)line, (unsigned char *)(LPCSTR)line + nCountFit - 1))
-                  nCountFit++;
-#endif
-                nCount1 = nCountFit;
-              }
 
               // Table of charwidths as CCrystalEditor thinks they are
               // Seems that CrystalEditor's and ExtTextOut()'s charwidths aren't
               // same with some fonts and text is drawn only partially
               // if this table is not used.
-              vector<int> nWidths(nCount1 + 2);
+              vector<int> nWidths(nWidth / nCharWidth * 2 + 2);
               bool bdisphex = false;
-              for (int next = i; i < nCount1 + ibegin ; i = next)
+              for (int next = i; i < lineLen && nSumWidth < nWidth ; i = next)
                 {
-                  next = m_iterChar.next();
                   if (line[i] == '\t') // Escape sequence leadin?
-                  {
-                    bdisphex = true;
-                    // Substitute a space narrowed to half the width of a character cell.
-                    line.SetAt(i, ' ');
-                    nSumWidth += nWidths[i - ibegin] = nCharWidthNarrowed;
-                    // 1st hex digit has normal width.
-                    nSumWidth += nWidths[++i - ibegin] = nCharWidth;
-                    // 2nd hex digit is padded by half the width of a character cell.
-                    nSumWidth += nWidths[++i - ibegin] = nCharWidthWidened;
-                  }
+                    {
+                      bdisphex = true;
+                      // Substitute a space narrowed to half the width of a character cell.
+                      line.SetAt(i, ' ');
+                      size_t idx = i - ibegin;
+                      if (idx >= nWidths.size())
+                        nWidths.resize(nWidths.size() * 2);
+                      nSumWidth += nWidths[idx] = nCharWidthNarrowed;
+                      // 1st hex digit has normal width.
+                      idx = pIterChar->next() - ibegin;
+                      if (idx >= nWidths.size())
+                        nWidths.resize(nWidths.size() * 2);
+                      nSumWidth += nWidths[idx] = nCharWidth;
+                      // 2nd hex digit is padded by half the width of a character cell.
+                      idx = pIterChar->next() - ibegin;
+                      if (idx >= nWidths.size())
+                        nWidths.resize(nWidths.size() * 2);
+                      nSumWidth += nWidths[idx] = nCharWidthWidened;
+                    }
                   else
-                  {
-                    nSumWidth += nWidths[i - ibegin] = GetCharCellCountFromChar(static_cast<const TCHAR *>(line) + i) * nCharWidth;
-                  }
+                    {
+                      size_t idx = i - ibegin;
+                      if (idx >= nWidths.size())
+                        nWidths.resize(nWidths.size() * 2);
+                      nSumWidth += nWidths[idx] = GetCharCellCountFromChar(static_cast<const tchar_t *>(line) + i) * nCharWidth;
+                    }
+                  next = pIterChar->next();
                 }
+              int nCount1 = i - ibegin;
 
               if (ptOrigin.x + nSumWidth > rcClip.left)
                 {
+                  CEColor crText2 = crText;
+                  CEColor crBkgnd2 = crBkgnd;
                   if (crText == CLR_NONE || nColorIndex & COLORINDEX_APPLYFORCE)
-                    pdc->SetTextColor(GetColor(nColorIndex));
-                  else
-                    pdc->SetTextColor(crText);
+                    crText2 = GetColor(nColorIndex);
                   if (crBkgnd == CLR_NONE || nBgColorIndex & COLORINDEX_APPLYFORCE)
-                    pdc->SetBkColor(GetColor(nBgColorIndex));
-                  else
-                    pdc->SetBkColor(crBkgnd);
+                    crBkgnd2 = GetColor(nBgColorIndex);
+                  if (nColorIndex & COLORINDEX_INTERMEDIATECOLOR)
+                    crText2 = CEColor::GetIntermediateColor(crText2, crBkgnd2, 0.333f);
+                  m_pCrystalRenderer->SetTextColor(crText2);
+                  m_pCrystalRenderer->SetBkColor(crBkgnd2);
 
-                  pdc->SelectObject(GetFont(GetItalic(nColorIndex),
-                      GetBold(nColorIndex)));
+                  m_pCrystalRenderer->SwitchFont(GetItalic(nColorIndex), GetBold(nColorIndex));
                   // we are sure to have less than 4095 characters because all the chars are visible
                   RECT rcIntersect;
                   RECT rcTextBlock = {ptOrigin.x, ptOrigin.y, ptOrigin.x + nSumWidth + 2, ptOrigin.y + nLineHeight};
                   IntersectRect(&rcIntersect, &rcClip, &rcTextBlock);
-                  VERIFY(pdc->ExtTextOut(ptOrigin.x, ptOrigin.y, ETO_CLIPPED | ETO_OPAQUE,
-                      &rcIntersect, LPCTSTR(line) + ibegin, nCount1, &nWidths[0]));
+                  m_pCrystalRenderer->DrawText(ptOrigin.x, ptOrigin.y, rcIntersect, (const tchar_t*)(line) + ibegin, nCount1, &nWidths[0]);
                   if (bdisphex)
                     {
-                     // Draw rounded rectangles around control characters
-                     pdc->SaveDC();
-                     pdc->IntersectClipRect(&rcClip);
-                     HDC hDC = pdc->m_hDC;
-                     HGDIOBJ hBrush = ::GetStockObject(NULL_BRUSH);
-                     hBrush = ::SelectObject(hDC, hBrush);
-                     HGDIOBJ hPen = ::CreatePen(PS_SOLID, 1, ::GetTextColor(hDC));
-                     hPen = ::SelectObject(hDC, hPen);
-                     int x = ptOrigin.x;
-                     for (int j = 0 ; j < nCount1 ; ++j)
-                     {
-                       // Assume narrowed space is converted escape sequence leadin.
-                       if (line[ibegin + j] == ' ' && nWidths[j] < nCharWidth)
-                       {
-                         ::RoundRect(hDC, x + 2, ptOrigin.y + 1,
-                           x + 3 * nCharWidth - 2, ptOrigin.y + nLineHeight - 1,
-                           nCharWidth / 2, nLineHeight / 2);
-                       }
-                       x += nWidths[j];
-                     }
-                     hPen = ::SelectObject(hDC, hPen);
-                     ::DeleteObject(hPen);
-                     hBrush = ::SelectObject(hDC, hBrush);
-                     pdc->RestoreDC(-1);
-                   }
+                      // Draw rounded rectangles around control characters
+                      m_pCrystalRenderer->PushAxisAlignedClip(rcClip);
+                      int x = ptOrigin.x;
+                      for (int j = 0 ; j < nCount1 ; ++j)
+                        {
+                          // Assume narrowed space is converted escape sequence leadin.
+                          if (line[ibegin + j] == ' ' && nWidths[j] < nCharWidth)
+                            {
+                              m_pCrystalRenderer->DrawRoundRectangle(x + 2, ptOrigin.y + 1,
+                                                                     x + 3 * nCharWidth - 2, ptOrigin.y + nLineHeight - 1,
+                                                                     nCharWidth / 2, nLineHeight / 2);
+                            }
+                          x += nWidths[j];
+                        }
+                      m_pCrystalRenderer->PopAxisAlignedClip();
+                    }
                 }
 
               // Update the final position after the visible characters
@@ -1204,60 +1340,47 @@ DrawLineHelperImpl (CDC * pdc, CPoint & ptOrigin, const CRect & rcClip,
             }
         }
       // Update the final position after the right clipped characters
-      for ( ; i < lineLen; i = m_iterChar.next())
+      for ( ; i < lineLen; i = pIterChar->next())
         {
-          ptOrigin.x += GetCharCellCountFromChar(static_cast<const TCHAR *>(line) + i) * nCharWidth;
+          ptOrigin.x += GetCharCellCountFromChar(static_cast<const tchar_t *>(line) + i) * nCharWidth;
         }
     }
 }
 
+bool CCrystalTextView::
+GetSelectionLeftRight(int nLineIndex, int& nSelLeft, int& nSelRight)
+{
+    int nLineLength = GetViewableLineLength (nLineIndex);
+    nSelLeft = 0;
+    nSelRight = 0;
+    if ( !m_bRectangularSelection )
+      {
+        if (m_ptDrawSelStart.y > nLineIndex)
+            nSelLeft = nLineLength;
+        else if (m_ptDrawSelStart.y == nLineIndex)
+          nSelLeft = m_ptDrawSelStart.x;
+        if (m_ptDrawSelEnd.y > nLineIndex)
+            nSelRight = nLineLength;
+        else if (m_ptDrawSelEnd.y == nLineIndex)
+          nSelRight = m_ptDrawSelEnd.x;
+        return (m_ptDrawSelStart.y <= nLineIndex && nLineIndex <= m_ptDrawSelEnd.y);
+      }
+    else
+      return GetColumnSelection (nLineIndex, nSelLeft, nSelRight);
+}
+
 void CCrystalTextView::
-DrawLineHelper (CDC * pdc, CPoint & ptOrigin, const CRect & rcClip, int nColorIndex, int nBgColorIndex, 
-                COLORREF crText, COLORREF crBkgnd, LPCTSTR pszChars, int nOffset, int nCount, int &nActualOffset, CPoint ptTextPos)
+DrawLineHelper (CPoint & ptOrigin, const CRect & rcClip, int nColorIndex, int nBgColorIndex, 
+                CEColor crText, CEColor crBkgnd,
+                int nLineIndex, int nOffset, int nCount, int &nActualOffset, CEPoint ptTextPos,
+                int nSelLeft, int nSelRight)
 {
   if (nCount > 0)
     {
       if (m_bFocused || m_bShowInactiveSelection)
         {
-          int nSelBegin = 0, nSelEnd = 0;
-          if ( !m_bColumnSelection )
-            {
-              if (m_ptDrawSelStart.y > ptTextPos.y)
-                {
-                  nSelBegin = nCount;
-                }
-              else if (m_ptDrawSelStart.y == ptTextPos.y)
-                {
-                  nSelBegin = m_ptDrawSelStart.x - ptTextPos.x;
-                  if (nSelBegin < 0)
-                    nSelBegin = 0;
-                  if (nSelBegin > nCount)
-                    nSelBegin = nCount;
-                }
-              if (m_ptDrawSelEnd.y > ptTextPos.y)
-                {
-                  nSelEnd = nCount;
-                }
-              else if (m_ptDrawSelEnd.y == ptTextPos.y)
-                {
-                  nSelEnd = m_ptDrawSelEnd.x - ptTextPos.x;
-                  if (nSelEnd < 0)
-                    nSelEnd = 0;
-                  if (nSelEnd > nCount)
-                    nSelEnd = nCount;
-                }
-            }
-          else
-            {
-              int nSelLeft, nSelRight;
-              GetColumnSelection (ptTextPos.y, nSelLeft, nSelRight);
-              nSelBegin = nSelLeft - ptTextPos.x;
-              nSelEnd = nSelRight - ptTextPos.x;
-              if (nSelBegin < 0) nSelBegin = 0;
-              if (nSelBegin > nCount) nSelBegin = nCount;
-              if (nSelEnd < 0) nSelEnd = 0;
-              if (nSelEnd > nCount) nSelEnd = nCount;
-            }
+          int nSelBegin = std::clamp<int>(nSelLeft - ptTextPos.x, 0, nCount);
+          int nSelEnd = std::clamp<int>(nSelRight - ptTextPos.x, 0, nCount);
 
           ASSERT (nSelBegin >= 0 && nSelBegin <= nCount);
           ASSERT (nSelEnd >= 0 && nSelEnd <= nCount);
@@ -1266,48 +1389,50 @@ DrawLineHelper (CDC * pdc, CPoint & ptOrigin, const CRect & rcClip, int nColorIn
           //  Draw part of the text before selection
           if (nSelBegin > 0)
             {
-              DrawLineHelperImpl (pdc, ptOrigin, rcClip, nColorIndex, nBgColorIndex, crText, crBkgnd, pszChars, nOffset, nSelBegin, nActualOffset);
+              DrawLineHelperImpl (ptOrigin, rcClip, nColorIndex, nBgColorIndex, crText, crBkgnd, nLineIndex, nOffset, nSelBegin, nActualOffset);
             }
           if (nSelBegin < nSelEnd)
             {
-              DrawLineHelperImpl (pdc, ptOrigin, rcClip,
-                  nColorIndex & ~COLORINDEX_APPLYFORCE, nBgColorIndex & ~COLORINDEX_APPLYFORCE, 
-                  GetColor (COLORINDEX_SELTEXT),
-                  GetColor (COLORINDEX_SELBKGND),
-                  pszChars, nOffset + nSelBegin, nSelEnd - nSelBegin, nActualOffset);
+              DrawLineHelperImpl (ptOrigin, rcClip,
+                                  nColorIndex & ~COLORINDEX_MASK,
+                                  nBgColorIndex & ~COLORINDEX_MASK,
+                                  GetColor (COLORINDEX_SELTEXT),
+                                  GetColor (COLORINDEX_SELBKGND),
+                                  nLineIndex,
+                                  nOffset + nSelBegin, nSelEnd - nSelBegin, nActualOffset);
             }
           if (nSelEnd < nCount)
             {
-              DrawLineHelperImpl (pdc, ptOrigin, rcClip, nColorIndex, nBgColorIndex, crText, crBkgnd, pszChars, nOffset + nSelEnd, nCount - nSelEnd, nActualOffset);
+              DrawLineHelperImpl (ptOrigin, rcClip, nColorIndex, nBgColorIndex, crText, crBkgnd, nLineIndex, nOffset + nSelEnd, nCount - nSelEnd, nActualOffset);
             }
         }
       else
         {
-          DrawLineHelperImpl (pdc, ptOrigin, rcClip, nColorIndex, nBgColorIndex, crText, crBkgnd, pszChars, nOffset, nCount, nActualOffset);
+          DrawLineHelperImpl (ptOrigin, rcClip, nColorIndex, nBgColorIndex, crText, crBkgnd, nLineIndex, nOffset, nCount, nActualOffset);
         }
     }
 }
 
 void CCrystalTextView::
-GetLineColors (int nLineIndex, COLORREF & crBkgnd,
-               COLORREF & crText, bool & bDrawWhitespace)
+GetLineColors (int nLineIndex, CEColor & crBkgnd,
+               CEColor & crText, bool & bDrawWhitespace)
 {
-  DWORD dwLineFlags = GetLineFlags (nLineIndex);
+  lineflags_t dwLineFlags = GetLineFlags (nLineIndex);
   bDrawWhitespace = true;
-  crText = RGB (255, 255, 255);
+  crText = { 255, 255, 255 };
   if (dwLineFlags & LF_EXECUTION)
     {
-      crBkgnd = RGB (0, 128, 0);
+      crBkgnd = { 0, 128, 0 };
       return;
     }
   if (dwLineFlags & LF_BREAKPOINT)
     {
-      crBkgnd = RGB (255, 0, 0);
+      crBkgnd = { 255, 0, 0 };
       return;
     }
   if (dwLineFlags & LF_INVALID_BREAKPOINT)
     {
-      crBkgnd = RGB (128, 128, 0);
+      crBkgnd = { 128, 128, 0 };
       return;
     }
   crBkgnd = CLR_NONE;
@@ -1322,7 +1447,7 @@ GetParseCookie (int nLineIndex)
   if (m_ParseCookies->size() == 0)
     {
       // must be initialized to invalid value (DWORD) -1
-      m_ParseCookies->assign(nLineCount, static_cast<DWORD>(-1));
+      m_ParseCookies->assign(nLineCount, static_cast<uint32_t>(-1));
     }
 
   if (nLineIndex < 0)
@@ -1335,10 +1460,10 @@ GetParseCookie (int nLineIndex)
     L--;
   L++;
 
-  int nBlocks;
+  int nBlocks = 0;
   while (L <= nLineIndex)
     {
-      DWORD dwCookie = 0;
+      unsigned dwCookie = 0;
       if (L > 0)
         dwCookie = (*m_ParseCookies)[L - 1];
       ASSERT (dwCookie != - 1);
@@ -1357,7 +1482,7 @@ GetAdditionalTextBlocks (int nLineIndex)
 }
 
 //BEGIN SW
-void CCrystalTextView::WrapLine( int nLineIndex, int nMaxLineWidth, int *anBreaks, int &nBreaks )
+void CCrystalTextView::WrapLine( int nLineIndex, int nMaxLineWidth, std::vector<int> *anBreaks, int &nBreaks )
 {
   // There must be a parser attached to this view
   if( m_pParser == nullptr )
@@ -1368,37 +1493,39 @@ void CCrystalTextView::WrapLine( int nLineIndex, int nMaxLineWidth, int *anBreak
 
 
 void CCrystalTextView::WrapLineCached( 
-                    int nLineIndex, int nMaxLineWidth, int *anBreaks, int &nBreaks )
+                    int nLineIndex, int nMaxLineWidth, std::vector<int> *anBreaks, int &nBreaks )
 {
   if( !GetLineVisible (nLineIndex) )
-  {
-    nBreaks = -1;
-    return;
-  }
+    {
+      nBreaks = -1;
+      return;
+    }
 
   // If the word wrap is not active, there is no breaks in the line
   if( !m_bWordWrap )
-  {
-    nBreaks = 0;
-    return;
-  }
+    {
+      nBreaks = 0;
+      return;
+    }
 
   // word wrap is active
-  if( nLineIndex < m_panSubLines->GetSize() && !anBreaks && (*m_panSubLines)[nLineIndex] > -1 )
+  if( nLineIndex < m_panSubLines->size () && !anBreaks && (*m_panSubLines)[nLineIndex] > -1 )
     // return cached data
     nBreaks = (*m_panSubLines)[nLineIndex] - 1;
   else
-  {
-    // recompute line wrap
-    nBreaks = 0;
-    WrapLine( nLineIndex, nMaxLineWidth, anBreaks, nBreaks );
+    {
+      // recompute line wrap
+      nBreaks = 0;
+      WrapLine( nLineIndex, nMaxLineWidth, anBreaks, nBreaks );
 
-    // cache data
-    ASSERT( nBreaks > -1 );
-    m_panSubLines->SetAtGrow( nLineIndex, nBreaks + 1 );
+      // cache data
+      ASSERT( nBreaks > -1 );
+      if (nLineIndex >= m_panSubLines->size())
+          m_panSubLines->resize(nLineIndex + 1);
+      (*m_panSubLines)[nLineIndex] = nBreaks + 1;
 
-    // RecalcVertScrollBar();
-  }
+      // RecalcVertScrollBar();
+    }
 }
 
 
@@ -1409,8 +1536,8 @@ void CCrystalTextView::InvalidateLineCache( int nLineIndex1, int nLineIndex2 /*=
 
   // invalidate cached sub line count
 
-  if( nLineIndex2 == -1 && nLineIndex1 < m_panSubLines->GetSize() )
-    for( int i = nLineIndex1; i < m_panSubLines->GetSize(); i++ )
+  if( nLineIndex2 == -1 && nLineIndex1 < m_panSubLines->size () )
+    for( int i = nLineIndex1; i < m_panSubLines->size (); i++ )
       (*m_panSubLines)[i] = -1;
   else
     {
@@ -1421,16 +1548,16 @@ void CCrystalTextView::InvalidateLineCache( int nLineIndex1, int nLineIndex2 /*=
           nLineIndex2 = nStorage;
         }
 
-    if( nLineIndex1 >= m_panSubLines->GetSize() )
-      return;
+      if( nLineIndex1 >= m_panSubLines->size () )
+        return;
 
-    if( nLineIndex2 >= m_panSubLines->GetSize() )
-      nLineIndex2 = (int) m_panSubLines->GetUpperBound();
+      if( nLineIndex2 >= m_panSubLines->size () )
+        nLineIndex2 = (int) m_panSubLines->size () - 1;
 
-    for( int i = nLineIndex1; i <= nLineIndex2; i++ )
-      if( i >= 0 && i < m_panSubLines->GetSize() )
-        (*m_panSubLines)[i] = -1;
-  }
+      for( int i = nLineIndex1; i <= nLineIndex2; i++ )
+        if( i >= 0 && i < m_panSubLines->size () )
+          (*m_panSubLines)[i] = -1;
+    }
 }
 
 /**
@@ -1460,16 +1587,16 @@ void CCrystalTextView::InvalidateScreenRect(bool bInvalidateView)
     {
       Invalidate();
       m_nTopSubLine = GetSubLineIndex(m_nTopLine);
-      RecalcVertScrollBar ();
-      RecalcHorzScrollBar ();
+      InvalidateVertScrollBar ();
+      InvalidateHorzScrollBar ();
       UpdateCaret ();
     }
 }
 
-void CCrystalTextView::DrawScreenLine( CDC *pdc, CPoint &ptOrigin, const CRect &rcClip,
+void CCrystalTextView::DrawScreenLine( CPoint &ptOrigin, const CRect &rcClip,
          const std::vector<TEXTBLOCK>& blocks, int &nActualItem, 
-         COLORREF crText, COLORREF crBkgnd, bool bDrawWhitespace,
-         LPCTSTR pszChars, int nOffset, int nCount, int &nActualOffset, CPoint ptTextPos )
+         CEColor crText, CEColor crBkgnd, bool bDrawWhitespace,
+         int nLineIndex, int nOffset, int nCount, int &nActualOffset, CEPoint ptTextPos )
 {
   CPoint       originalOrigin = ptOrigin;
   CPoint       ptOriginZeroWidthBlock;
@@ -1486,6 +1613,9 @@ void CCrystalTextView::DrawScreenLine( CDC *pdc, CPoint &ptOrigin, const CRect &
   int nBlockSize = static_cast<int>(blocks.size());
   ASSERT( nActualItem < nBlockSize );
 
+  int nSelLeft = 0, nSelRight = 0;
+  GetSelectionLeftRight(ptTextPos.y, nSelLeft, nSelRight);
+
   if( nBlockSize > 0 && nActualItem < nBlockSize - 1 && 
     blocks[nActualItem + 1].m_nCharPos >= nOffset && 
     blocks[nActualItem + 1].m_nCharPos <= nOffset + nCount )
@@ -1505,73 +1635,89 @@ void CCrystalTextView::DrawScreenLine( CDC *pdc, CPoint &ptOrigin, const CRect &
           if (blocks[I + 1].m_nCharPos - nOffsetToUse > 0)
             {
               int nOldActualOffset = nActualOffset;
-              DrawLineHelper(pdc, ptOrigin, rcClip, blk.m_nColorIndex, blk.m_nBgColorIndex, crText, crBkgnd, pszChars,
+              DrawLineHelper(ptOrigin, rcClip, blk.m_nColorIndex, blk.m_nBgColorIndex, crText, crBkgnd, nLineIndex,
                 (nOffset > blk.m_nCharPos)? nOffset : blk.m_nCharPos, 
                 blocks[I + 1].m_nCharPos - nOffsetToUse,
-                nActualOffset, CPoint( nOffsetToUse, ptTextPos.y ));
+                nActualOffset, CEPoint( nOffsetToUse, ptTextPos.y ), nSelLeft, nSelRight);
               if (bPrevZeroWidthBlock)
                 {
                   CRect rcClipZeroWidthBlock(ptOriginZeroWidthBlock.x, rcClip.top, ptOriginZeroWidthBlock.x + ZEROWIDTHBLOCK_WIDTH, rcClip.bottom);
-                  DrawLineHelper(pdc, ptOriginZeroWidthBlock, rcClipZeroWidthBlock, blk.m_nColorIndex, nBgColorIndexZeorWidthBlock, crText, crBkgnd, pszChars,
+                  DrawLineHelper(ptOriginZeroWidthBlock, rcClipZeroWidthBlock, blk.m_nColorIndex, nBgColorIndexZeorWidthBlock, crText, crBkgnd, nLineIndex,
                       (nOffset > blk.m_nCharPos)? nOffset : blk.m_nCharPos, 
                       blocks[I + 1].m_nCharPos - nOffsetToUse,
-                      nOldActualOffset, CPoint( nOffsetToUse, ptTextPos.y ));
+                      nOldActualOffset, CEPoint( nOffsetToUse, ptTextPos.y ), nSelLeft, nSelRight);
                   bPrevZeroWidthBlock = false;
                 }
             }
           else
             {
-              if (!bPrevZeroWidthBlock)
+              if (!bPrevZeroWidthBlock && (blk.m_nCharPos < nOffset + nCount || nOffset + nCount == nLineLength))
                 {
                   int nBgColorIndex = blk.m_nBgColorIndex;
-                  COLORREF clrBkColor;
-                  if (crBkgnd == CLR_NONE || nBgColorIndex & COLORINDEX_APPLYFORCE)
+                  CEColor clrBkColor;
+                  if (IsInsideSelBlock (CEPoint{nOffsetToUse, ptTextPos.y}))
+                    clrBkColor = GetColor(COLORINDEX_SELBKGND);
+                  else if (crBkgnd == CLR_NONE || nBgColorIndex & COLORINDEX_APPLYFORCE)
                     clrBkColor = GetColor(nBgColorIndex);
                   else
                     clrBkColor = crBkgnd;
-                  pdc->FillSolidRect(ptOrigin.x, ptOrigin.y, ZEROWIDTHBLOCK_WIDTH, GetLineHeight(), clrBkColor);
+                  CRect rc(ptOrigin.x, ptOrigin.y, ptOrigin.x + ZEROWIDTHBLOCK_WIDTH, ptOrigin.y + GetLineHeight());
+                  m_pCrystalRenderer->SetBkColor(clrBkColor);
+                  m_pCrystalRenderer->FillRectangle(rc);
                   ptOriginZeroWidthBlock = ptOrigin;
                   nBgColorIndexZeorWidthBlock = blk.m_nBgColorIndex;
                   bPrevZeroWidthBlock = true;
                 }
             }
           if (ptOrigin.x > rcClip.right)
-            break;
+            {
+              if (GetTextLayoutMode () == TEXTLAYOUT_TABLE_WORDWRAP)
+                {
+                  while (I < blocks.size () - 1 && blocks[I + 1].m_nCharPos <= nOffset + nCount)
+                    I++;
+                }
+              break;
+            }
         }
 
       nActualItem = static_cast<int>(I);
 
-      ASSERT(blocks[nActualItem].m_nCharPos >= 0 &&
-        blocks[nActualItem].m_nCharPos <= nLineLength);
+      const TEXTBLOCK& blk = blocks[nActualItem];
+      ASSERT(blk.m_nCharPos >= 0 &&
+        blk.m_nCharPos <= nLineLength);
 
-      if (nOffset + nCount - blocks[nActualItem].m_nCharPos > 0)
+      if (nOffset + nCount - blk.m_nCharPos > 0)
         {
           int nOldActualOffset = nActualOffset;
-          DrawLineHelper(pdc, ptOrigin, rcClip, blocks[nActualItem].m_nColorIndex, blocks[nActualItem].m_nBgColorIndex,
-                  crText, crBkgnd, pszChars, blocks[nActualItem].m_nCharPos,
-                  nOffset + nCount - blocks[nActualItem].m_nCharPos,
-                  nActualOffset, CPoint(blocks[nActualItem].m_nCharPos, ptTextPos.y));
+          DrawLineHelper(ptOrigin, rcClip, blk.m_nColorIndex, blk.m_nBgColorIndex,
+                  crText, crBkgnd, nLineIndex, blk.m_nCharPos,
+                  nOffset + nCount - blk.m_nCharPos,
+                  nActualOffset, CEPoint(blk.m_nCharPos, ptTextPos.y), nSelLeft, nSelRight);
           if (bPrevZeroWidthBlock)
             {
               CRect rcClipZeroWidthBlock(ptOriginZeroWidthBlock.x, rcClip.top, ptOriginZeroWidthBlock.x + ZEROWIDTHBLOCK_WIDTH, rcClip.bottom);
-              DrawLineHelper(pdc, ptOriginZeroWidthBlock, rcClipZeroWidthBlock, blocks[nActualItem].m_nColorIndex, nBgColorIndexZeorWidthBlock,
-                  crText, crBkgnd, pszChars, blocks[nActualItem].m_nCharPos,
-                  nOffset + nCount - blocks[nActualItem].m_nCharPos,
-                  nOldActualOffset, CPoint(blocks[nActualItem].m_nCharPos, ptTextPos.y));
+              DrawLineHelper(ptOriginZeroWidthBlock, rcClipZeroWidthBlock, blk.m_nColorIndex, nBgColorIndexZeorWidthBlock,
+                  crText, crBkgnd, nLineIndex, blk.m_nCharPos,
+                  nOffset + nCount - blk.m_nCharPos,
+                  nOldActualOffset, CEPoint(blk.m_nCharPos, ptTextPos.y), nSelLeft, nSelRight);
               bPrevZeroWidthBlock = false;
             }
         }
       else
         {
-          if (!bPrevZeroWidthBlock)
+          if (!bPrevZeroWidthBlock && (blk.m_nCharPos < nOffset + nCount || nOffset + nCount == nLineLength))
             {
-              int nBgColorIndex = blocks[nActualItem].m_nBgColorIndex;
-              COLORREF clrBkColor;
-              if (crBkgnd == CLR_NONE || nBgColorIndex & COLORINDEX_APPLYFORCE)
+              int nBgColorIndex = blk.m_nBgColorIndex;
+              CEColor clrBkColor;
+              if (IsInsideSelBlock (CEPoint{blk.m_nCharPos, ptTextPos.y}))
+                clrBkColor = GetColor(COLORINDEX_SELBKGND);
+              else if (crBkgnd == CLR_NONE || nBgColorIndex & COLORINDEX_APPLYFORCE)
                 clrBkColor = GetColor(nBgColorIndex);
               else
                 clrBkColor = crBkgnd;
-              pdc->FillSolidRect(ptOrigin.x, ptOrigin.y, ZEROWIDTHBLOCK_WIDTH, GetLineHeight(), clrBkColor);
+              CRect rc(ptOrigin.x, ptOrigin.y, ptOrigin.x + ZEROWIDTHBLOCK_WIDTH, ptOrigin.y + GetLineHeight());
+              m_pCrystalRenderer->SetBkColor(clrBkColor);
+              m_pCrystalRenderer->FillRectangle(rc);
               bPrevZeroWidthBlock = true;
             }
         }
@@ -1579,8 +1725,8 @@ void CCrystalTextView::DrawScreenLine( CDC *pdc, CPoint &ptOrigin, const CRect &
   else
     {
       DrawLineHelper(
-              pdc, ptOrigin, rcClip, blocks[nActualItem].m_nColorIndex, blocks[nActualItem].m_nBgColorIndex,
-              crText, crBkgnd, pszChars, nOffset, nCount, nActualOffset, ptTextPos);
+              ptOrigin, rcClip, blocks[nActualItem].m_nColorIndex, blocks[nActualItem].m_nBgColorIndex,
+              crText, crBkgnd, nLineIndex, nOffset, nCount, nActualOffset, ptTextPos, nSelLeft, nSelRight);
     }
 
   // Draw space on the right of the text
@@ -1588,15 +1734,16 @@ void CCrystalTextView::DrawScreenLine( CDC *pdc, CPoint &ptOrigin, const CRect &
   frect.left = ptOrigin.x + (bPrevZeroWidthBlock ? ZEROWIDTHBLOCK_WIDTH : 0);
 
   if ((m_bFocused || m_bShowInactiveSelection) 
-    && !m_bColumnSelection
-    && IsInsideSelBlock(CPoint(nLineLength, ptTextPos.y)) 
+    && !m_bRectangularSelection
+    && IsInsideSelBlock(CEPoint(nLineLength, ptTextPos.y)) 
     && (nOffset + nCount) == nLineLength )
     {
       if (frect.left >= rcClip.left)
         {
           const int nCharWidth = GetCharWidth();
-          pdc->FillSolidRect(frect.left, frect.top, nCharWidth, frect.Height(),
-              GetColor(COLORINDEX_SELBKGND));
+          CRect rc(frect.left, frect.top, frect.left + nCharWidth, frect.bottom);
+          m_pCrystalRenderer->SetBkColor(GetColor(COLORINDEX_SELBKGND));
+          m_pCrystalRenderer->FillRectangle(rc);
           frect.left += nCharWidth;
         }
     }
@@ -1604,8 +1751,10 @@ void CCrystalTextView::DrawScreenLine( CDC *pdc, CPoint &ptOrigin, const CRect &
     frect.left = rcClip.left;
 
   if (frect.right > frect.left)
-    pdc->FillSolidRect(frect, bDrawWhitespace ?
-      crBkgnd : GetColor(COLORINDEX_WHITESPACE));
+    {
+      m_pCrystalRenderer->SetBkColor(bDrawWhitespace ? crBkgnd : GetColor(COLORINDEX_WHITESPACE));
+      m_pCrystalRenderer->FillRectangle(frect);
+    }
 
   // set origin to beginning of next screen line
   ptOrigin.x = originalOrigin.x;
@@ -1613,12 +1762,6 @@ void CCrystalTextView::DrawScreenLine( CDC *pdc, CPoint &ptOrigin, const CRect &
 }
 //END SW
 
-class IntArray : public CArray<int, int>
-{
-public:
-  explicit IntArray(int len) { SetSize(len); }
-};
-
 std::vector<TEXTBLOCK> CCrystalTextView::
 MergeTextBlocks (const std::vector<TEXTBLOCK>& blocks1, const std::vector<TEXTBLOCK>& blocks2) const
 {
@@ -1636,8 +1779,8 @@ MergeTextBlocks (const std::vector<TEXTBLOCK>& blocks1, const std::vector<TEXTBL
           (blocks1[i].m_nCharPos == blocks2[j].m_nCharPos))
         {
           mergedBlocks[k].m_nCharPos = blocks2[j].m_nCharPos;
-          if (blocks2[j].m_nColorIndex == COLORINDEX_NONE)
-            mergedBlocks[k].m_nColorIndex = blocks1[i].m_nColorIndex;
+          if ((blocks2[j].m_nColorIndex & ~COLORINDEX_MASK) == COLORINDEX_NONE)
+            mergedBlocks[k].m_nColorIndex = blocks1[i].m_nColorIndex | (blocks2[j].m_nColorIndex & COLORINDEX_MASK);
           else
             mergedBlocks[k].m_nColorIndex = blocks2[j].m_nColorIndex;
           if (blocks2[j].m_nBgColorIndex == COLORINDEX_NONE)
@@ -1651,8 +1794,9 @@ MergeTextBlocks (const std::vector<TEXTBLOCK>& blocks1, const std::vector<TEXTBL
           blocks1[i].m_nCharPos < blocks2[j].m_nCharPos))
         {
           mergedBlocks[k].m_nCharPos = blocks1[i].m_nCharPos;
-          if (blocks2.size() == 0 || blocks2[j - 1].m_nColorIndex == COLORINDEX_NONE)
-            mergedBlocks[k].m_nColorIndex = blocks1[i].m_nColorIndex;
+          if (blocks2.size() == 0 || (blocks2[j - 1].m_nColorIndex & ~COLORINDEX_MASK) == COLORINDEX_NONE)
+            mergedBlocks[k].m_nColorIndex = blocks1[i].m_nColorIndex | 
+              (blocks2.size() == 0 ? 0 : (blocks2[j - 1].m_nColorIndex & COLORINDEX_MASK));
           else
             mergedBlocks[k].m_nColorIndex = blocks2[j - 1].m_nColorIndex;
           if (blocks2.size() == 0 || blocks2[j - 1].m_nBgColorIndex == COLORINDEX_NONE)
@@ -1664,8 +1808,8 @@ MergeTextBlocks (const std::vector<TEXTBLOCK>& blocks1, const std::vector<TEXTBL
       else if (i >= blocks1.size() || (j < blocks2.size() && blocks1[i].m_nCharPos > blocks2[j].m_nCharPos))
         {
           mergedBlocks[k].m_nCharPos = blocks2[j].m_nCharPos;
-          if (i > 0 && blocks2[j].m_nColorIndex == COLORINDEX_NONE)
-            mergedBlocks[k].m_nColorIndex = blocks1[i - 1].m_nColorIndex;
+          if (i > 0 && (blocks2[j].m_nColorIndex & ~COLORINDEX_MASK) == COLORINDEX_NONE)
+            mergedBlocks[k].m_nColorIndex = blocks1[i - 1].m_nColorIndex | (blocks2[j].m_nColorIndex & COLORINDEX_MASK);
           else
             mergedBlocks[k].m_nColorIndex = blocks2[j].m_nColorIndex;
           if (i > 0 && blocks2[j].m_nBgColorIndex == COLORINDEX_NONE)
@@ -1693,6 +1837,49 @@ MergeTextBlocks (const std::vector<TEXTBLOCK>& blocks1, const std::vector<TEXTBL
 }
 
 std::vector<TEXTBLOCK>
+CCrystalTextView::GetWhitespaceTextBlocks(int nLineIndex) const
+{
+  const tchar_t *pszChars = GetLineChars(nLineIndex);
+  int nLineLength = GetLineLength(nLineIndex);
+  std::vector<TEXTBLOCK> blocks((nLineLength + 1) * 3);
+  blocks[0].m_nCharPos = 0;
+  blocks[0].m_nColorIndex = COLORINDEX_NONE;
+  blocks[0].m_nBgColorIndex = COLORINDEX_NONE;
+  int nBlocks = 1;
+  if (pszChars != nullptr)
+    {
+      for (int i = 0; i < nLineLength; ++i)
+        {
+          if (pszChars[i] == ' ' || pszChars[i] == '\t')
+            {
+              blocks[nBlocks].m_nCharPos = i;
+              blocks[nBlocks].m_nColorIndex = COLORINDEX_NONE | COLORINDEX_INTERMEDIATECOLOR;
+              blocks[nBlocks].m_nBgColorIndex = COLORINDEX_NONE;
+              ++nBlocks;
+              while (i < nLineLength && (pszChars[i] == ' ' || pszChars[i] == '\t'))
+                  ++i;
+              if (i < nLineLength)
+                {
+                  blocks[nBlocks].m_nCharPos = i;
+                  blocks[nBlocks].m_nColorIndex = COLORINDEX_NONE;
+                  blocks[nBlocks].m_nBgColorIndex = COLORINDEX_NONE;
+                  ++nBlocks;
+                }
+            }
+        }
+    }
+  if (nBlocks == 0 || blocks[nBlocks].m_nColorIndex == COLORINDEX_NONE)
+    {
+      blocks[nBlocks].m_nCharPos = nLineLength;
+      blocks[nBlocks].m_nColorIndex = COLORINDEX_NONE | COLORINDEX_INTERMEDIATECOLOR;
+      blocks[nBlocks].m_nBgColorIndex = COLORINDEX_NONE;
+      ++nBlocks;
+    }
+  blocks.resize(nBlocks);
+  return blocks;
+}
+
+std::vector<TEXTBLOCK>
 CCrystalTextView::GetMarkerTextBlocks(int nLineIndex) const
 {
   std::vector<TEXTBLOCK> allblocks;
@@ -1704,39 +1891,40 @@ CCrystalTextView::GetMarkerTextBlocks(int nLineIndex) const
   for (const auto& marker : m_pMarkers->GetMarkers())
     {
       if (!marker.second.bVisible)
-          continue;
+        continue;
       int nBlocks = 0;
       std::vector<TEXTBLOCK> blocks((nLength + 1) * 3); // be aware of nLength == 0
       blocks[0].m_nCharPos = 0;
       blocks[0].m_nColorIndex = COLORINDEX_NONE;
       blocks[0].m_nBgColorIndex = COLORINDEX_NONE;
       ++nBlocks;
-      const TCHAR *pszChars = GetLineChars(nLineIndex);
+      const tchar_t *pszChars = GetLineChars(nLineIndex);
       int nLineLength = GetLineLength(nLineIndex);
       if (pszChars != nullptr)
         {
-          for (const TCHAR *p = pszChars; p < pszChars + nLineLength; )
+          RxNode *node = nullptr;
+          for (const tchar_t *p = pszChars; p < pszChars + nLineLength; )
             {
-              RxNode *node = nullptr;
               RxMatchRes matches;
               int nMatchLen = 0;
-              size_t nPos = ::FindStringHelper(pszChars, p, marker.second.sFindWhat, marker.second.dwFlags | FIND_NO_WRAP, nMatchLen, node, &matches);
+              size_t nPos = ::FindStringHelper(pszChars, nLineLength, p, marker.second.sFindWhat, marker.second.dwFlags | FIND_NO_WRAP, nMatchLen, node, &matches);
               if (nPos == -1)
-                  break;
-              if (nLineLength < static_cast<int>((p - pszChars) + nPos) + nMatchLen)
-                  nMatchLen = static_cast<int>(nLineLength - (p - pszChars));
-              ASSERT(((p - pszChars) + nPos) < INT_MAX);
-              blocks[nBlocks].m_nCharPos = static_cast<int>((p - pszChars) + nPos);
+                break;
+              if (nLineLength < static_cast<int>(nPos) + nMatchLen)
+                nMatchLen = static_cast<int>(nLineLength - nPos);
+              ASSERT(nPos < INT_MAX);
+              blocks[nBlocks].m_nCharPos = static_cast<int>(nPos);
               blocks[nBlocks].m_nBgColorIndex = marker.second.nBgColorIndex | COLORINDEX_APPLYFORCE;
               blocks[nBlocks].m_nColorIndex = COLORINDEX_NONE;
               ++nBlocks;
-              ASSERT(((p - pszChars) + nPos + nMatchLen) < INT_MAX);
-              blocks[nBlocks].m_nCharPos = static_cast<int>((p - pszChars) + nPos + nMatchLen);
+              ASSERT((nPos + nMatchLen) < INT_MAX);
+              blocks[nBlocks].m_nCharPos = static_cast<int>(nPos + nMatchLen);
               blocks[nBlocks].m_nBgColorIndex = COLORINDEX_NONE;
               blocks[nBlocks].m_nColorIndex = COLORINDEX_NONE;
               ++nBlocks;
-              p += nPos + (nMatchLen == 0 ? 1 : nMatchLen);
+              p = pszChars + nPos + (nMatchLen == 0 ? 1 : nMatchLen);
             }
+          RxFree (node);
           blocks.resize(nBlocks);
           allblocks = MergeTextBlocks(allblocks, blocks);
         }
@@ -1751,7 +1939,7 @@ CCrystalTextView::GetTextBlocks(int nLineIndex)
   int nLength = GetViewableLineLength (nLineIndex);
 
   //  Parse the line
-  DWORD dwCookie = GetParseCookie(nLineIndex - 1);
+  unsigned dwCookie = GetParseCookie(nLineIndex - 1);
   std::vector<TEXTBLOCK> blocks((nLength + 1) * 3); // be aware of nLength == 0
   int nBlocks = 0;
   // insert at least one textblock of normal color at the beginning
@@ -1762,15 +1950,21 @@ CCrystalTextView::GetTextBlocks(int nLineIndex)
   (*m_ParseCookies)[nLineIndex] = ParseLine(dwCookie, GetLineChars(nLineIndex), GetLineLength(nLineIndex), blocks.data(), nBlocks);
   ASSERT((*m_ParseCookies)[nLineIndex] != -1);
   blocks.resize(nBlocks);
-  
-  return MergeTextBlocks(blocks, 
-          (m_pMarkers && m_pMarkers->GetEnabled() && m_pMarkers->GetMarkers().size() > 0) ?
-          MergeTextBlocks(GetAdditionalTextBlocks(nLineIndex), GetMarkerTextBlocks(nLineIndex)) :
-          GetAdditionalTextBlocks(nLineIndex));
+
+  std::vector<TEXTBLOCK> additionalBlocks = GetAdditionalTextBlocks(nLineIndex);
+  std::vector<TEXTBLOCK> mergedBlocks;
+  if (m_pMarkers && m_pMarkers->GetEnabled() && m_pMarkers->GetMarkers().size() > 0)
+    mergedBlocks = MergeTextBlocks(additionalBlocks, GetMarkerTextBlocks(nLineIndex));
+  else
+    mergedBlocks = std::move(additionalBlocks);
+  std::vector<TEXTBLOCK> mergedBlocks2 = MergeTextBlocks(blocks, mergedBlocks);
+  if (m_bViewTabs || m_bViewEols)
+      return MergeTextBlocks(mergedBlocks2, GetWhitespaceTextBlocks(nLineIndex));
+  return mergedBlocks2;
 }
 
 void CCrystalTextView::
-DrawSingleLine (CDC * pdc, const CRect & rc, int nLineIndex)
+DrawSingleLine (const CRect & rc, int nLineIndex)
 {
   const int nCharWidth = GetCharWidth();
   ASSERT (nLineIndex >= -1 && nLineIndex < GetLineCount ());
@@ -1778,46 +1972,82 @@ DrawSingleLine (CDC * pdc, const CRect & rc, int nLineIndex)
   if (nLineIndex == -1)
     {
       //  Draw line beyond the text
-      pdc->FillSolidRect (rc, GetColor (COLORINDEX_WHITESPACE));
+      m_pCrystalRenderer->FillSolidRectangle (rc, GetColor (COLORINDEX_WHITESPACE));
       return;
     }
 
   //  Acquire the background color for the current line
   bool bDrawWhitespace = false;
-  COLORREF crBkgnd, crText;
+  CEColor crBkgnd, crText;
   GetLineColors (nLineIndex, crBkgnd, crText, bDrawWhitespace);
 
   int nLength = GetViewableLineLength (nLineIndex);
-  LPCTSTR pszChars = GetLineChars (nLineIndex);
 
   std::vector<TEXTBLOCK> blocks = GetTextBlocks(nLineIndex);
 
   int nActualItem = 0;
   int nActualOffset = 0;
   // Wrap the line
-  IntArray anBreaks(nLength);
+  std::vector<int> anBreaks(nLength);
   int nBreaks = 0;
 
-  WrapLineCached( nLineIndex, GetScreenChars(), anBreaks.GetData(), nBreaks );
+  WrapLineCached( nLineIndex, GetScreenChars(), &anBreaks, nBreaks );
 
   //  Draw the line text
   CPoint origin (rc.left - m_nOffsetChar * nCharWidth, rc.top);
   if (crBkgnd != CLR_NONE)
-    pdc->SetBkColor (crBkgnd);
+    m_pCrystalRenderer->SetBkColor (crBkgnd);
   if (crText != CLR_NONE)
-    pdc->SetTextColor (crText);
+    m_pCrystalRenderer->SetTextColor (crText);
 
-  if( nBreaks > 0 )
+  const TextLayoutMode layoutMode = GetTextLayoutMode ();
+  if (layoutMode == TEXTLAYOUT_TABLE_WORDWRAP)
+    {
+      anBreaks.push_back (-nLength);
+      CPoint originOrg = origin;
+      DrawScreenLine(
+        origin, rc,
+        blocks, nActualItem,
+        crText, crBkgnd, bDrawWhitespace,
+        nLineIndex, 0, abs(anBreaks[0]),
+        nActualOffset, CEPoint( 0, nLineIndex ) );
+      int nColumn = 0;
+      for( int i = 0, j = 0; i < static_cast<int> (anBreaks.size ()) - 1; i++, j++ )
+        {
+          if (anBreaks[i] < 0)
+            {
+              if (j < nBreaks)
+                {
+                  CRect frect( origin.x, originOrg.y + (j + 1) * GetLineHeight (),
+                    origin.x + m_pTextBuffer->GetColumnWidth (nColumn) * nCharWidth, rc.bottom );
+                  if (frect.left < rc.left)
+                    frect.left = rc.left;
+                  if (frect.right > rc.left)
+                    m_pCrystalRenderer->FillSolidRectangle (frect, crBkgnd == CLR_NONE ? GetColor(COLORINDEX_WHITESPACE) : crBkgnd);
+                }
+              origin.y = originOrg.y;
+              origin.x += m_pTextBuffer->GetColumnWidth (nColumn++) * nCharWidth;
+              j = -1;
+            }
+          DrawScreenLine(
+            origin, rc,
+            blocks, nActualItem,
+            crText, crBkgnd, bDrawWhitespace,
+            nLineIndex, abs(anBreaks[i]), abs(anBreaks[i + 1]) - abs(anBreaks[i]),
+            nActualOffset, CEPoint( abs(anBreaks[i]), nLineIndex ) );
+        }
+    }
+  else if (layoutMode == TEXTLAYOUT_WORDWRAP && nBreaks > 0)
     {
       // Draw all the screen lines of the wrapped line
       ASSERT( anBreaks[0] < nLength );
 
       // draw start of line to first break
       DrawScreenLine(
-        pdc, origin, rc,
+        origin, rc,
         blocks, nActualItem,
         crText, crBkgnd, bDrawWhitespace,
-        pszChars, 0, anBreaks[0], nActualOffset, CPoint( 0, nLineIndex ) );
+        nLineIndex, 0, anBreaks[0], nActualOffset, CEPoint( 0, nLineIndex ) );
 
       // draw from first break to last break
       int i=0;
@@ -1825,35 +2055,35 @@ DrawSingleLine (CDC * pdc, const CRect & rc, int nLineIndex)
         {
           ASSERT( anBreaks[i] >= 0 && anBreaks[i] < nLength );
           DrawScreenLine(
-            pdc, origin, rc,
+            origin, rc,
             blocks, nActualItem,
             crText, crBkgnd, bDrawWhitespace,
-            pszChars, anBreaks[i], anBreaks[i + 1] - anBreaks[i],
-            nActualOffset, CPoint( anBreaks[i], nLineIndex ) );
+            nLineIndex, anBreaks[i], anBreaks[i + 1] - anBreaks[i],
+            nActualOffset, CEPoint( anBreaks[i], nLineIndex ) );
         }
 
       // draw from last break till end of line
       DrawScreenLine(
-        pdc, origin, rc,
+        origin, rc,
         blocks, nActualItem,
         crText, crBkgnd, bDrawWhitespace,
-        pszChars, anBreaks[i], nLength - anBreaks[i],
-        nActualOffset, CPoint( anBreaks[i], nLineIndex ) );
+        nLineIndex, anBreaks[i], nLength - anBreaks[i],
+        nActualOffset, CEPoint( anBreaks[i], nLineIndex ) );
     }
   else
-      DrawScreenLine(
-        pdc, origin, rc,
-        blocks, nActualItem,
-        crText, crBkgnd, bDrawWhitespace,
-        pszChars, 0, nLength, nActualOffset, CPoint(0, nLineIndex));
+    DrawScreenLine(
+      origin, rc,
+      blocks, nActualItem,
+      crText, crBkgnd, bDrawWhitespace,
+      nLineIndex, 0, nLength, nActualOffset, CEPoint(0, nLineIndex));
 
   // Draw empty sublines
   int nEmptySubLines = GetEmptySubLines(nLineIndex);
   if (nEmptySubLines > 0)
     {
       CRect frect = rc;
-      frect.top = frect.bottom - nEmptySubLines * GetLineHeight();
-      pdc->FillSolidRect(frect, crBkgnd == CLR_NONE ? GetColor(COLORINDEX_WHITESPACE) : crBkgnd);
+      frect.top += (nBreaks + 1) * GetLineHeight ();
+      m_pCrystalRenderer->FillSolidRectangle(frect, crBkgnd == CLR_NONE ? GetColor(COLORINDEX_WHITESPACE) : crBkgnd);
     }
 }
 
@@ -1872,7 +2102,7 @@ EscapeHTML (const CString & strText, bool & bLastCharSpace, int & nNonbreakChars
   int len = strText.GetLength ();
   for (int i = 0; i < len; ++i)
     {
-      TCHAR ch = strText[i];
+      tchar_t ch = strText[i];
       switch (ch)
         {
           case '&':
@@ -1898,7 +2128,7 @@ EscapeHTML (const CString & strText, bool & bLastCharSpace, int & nNonbreakChars
             nNonbreakChars = 0;
             break;
           case ' ':
-            if (bLastCharSpace)
+            if (i == 0 || bLastCharSpace)
               {
                 strHTML += _T("&nbsp;");
                 bLastCharSpace = false;
@@ -1930,7 +2160,7 @@ EscapeHTML (const CString & strText, bool & bLastCharSpace, int & nNonbreakChars
 }
 
 // Make a CString from printf-style args (single call version of CString::Format)
-static CString Fmt(LPCTSTR fmt, ...)
+static CString Fmt(const tchar_t* fmt, ...)
 {
   CString str;
   va_list args;
@@ -1972,26 +2202,39 @@ GetHTMLStyles ()
   };
 
   CString strStyles;
-  for (int f = 0; f < sizeof(arColorIndices)/sizeof(int); f++)
+  for (int i = 0; i < 2; i++)
     {
-      int nColorIndex = arColorIndices[f];
-      for (int b = 0; b < sizeof(arBgColorIndices)/sizeof(int); b++)
+      for (int f = 0; f < sizeof(arColorIndices) / sizeof(int); f++)
         {
-          int nBgColorIndex = arBgColorIndices[b];
-          COLORREF clr;
-
-          strStyles += Fmt (_T(".sf%db%d {"), nColorIndex, nBgColorIndex);
-          clr = GetColor (nColorIndex);
-          strStyles += Fmt (_T("color: #%02x%02x%02x; "), GetRValue (clr), GetGValue (clr), GetBValue (clr));
-          clr = GetColor (nBgColorIndex);
-          strStyles += Fmt (_T("background-color: #%02x%02x%02x; "), GetRValue (clr), GetGValue (clr), GetBValue (clr));
-          if (GetBold (nColorIndex))
-            strStyles += _T("font-weight: bold; ");
-          if (GetItalic (nColorIndex))
-            strStyles += _T("font-style: italic; ");
-          strStyles += _T("}\n");
+          int nColorIndex = arColorIndices[f];
+          for (int b = 0; b < sizeof(arBgColorIndices) / sizeof(int); b++)
+            {
+              int nBgColorIndex = arBgColorIndices[b];
+              CEColor clr;
+
+              strStyles += Fmt(_T(".sf%db%d%s {"), nColorIndex, nBgColorIndex, i == 0 ? _T("") : _T("i"));
+              clr = GetColor(nColorIndex);
+              if (i == 1)
+                clr = CEColor::GetIntermediateColor(clr, GetColor(nBgColorIndex), 0.333f);
+              strStyles += Fmt(_T("color: #%02x%02x%02x; "), GetRValue(clr), GetGValue(clr), GetBValue(clr));
+              clr = GetColor(nBgColorIndex);
+              strStyles += Fmt(_T("background-color: #%02x%02x%02x; "), GetRValue(clr), GetGValue(clr), GetBValue(clr));
+              if (GetBold(nColorIndex))
+                strStyles += _T("font-weight: bold; ");
+              if (GetItalic(nColorIndex))
+                strStyles += _T("font-style: italic; ");
+              strStyles += _T("}\n");
+            }
         }
     }
+  CEColor clrSelMargin = GetColor(COLORINDEX_SELMARGIN);
+  CEColor clrNormalText = GetColor(COLORINDEX_NORMALTEXT);
+  strStyles += Fmt(_T(".cn {text-align: center; word-break: normal; color: #%02x%02x%02x; background-color: #%02x%02x%02x;}\n")
+                   _T(".ln {text-align: right; word-break: normal; color: #%02x%02x%02x; background-color: #%02x%02x%02x;}\n"),
+    GetRValue(clrNormalText), GetGValue(clrNormalText), GetBValue(clrNormalText),
+    GetRValue(clrSelMargin), GetGValue(clrSelMargin), GetBValue(clrSelMargin),
+    GetRValue(clrNormalText), GetGValue(clrNormalText), GetBValue(clrNormalText),
+    GetRValue(clrSelMargin), GetGValue(clrSelMargin), GetBValue(clrSelMargin));
   return strStyles;
 }
 
@@ -2004,26 +2247,28 @@ GetHTMLStyles ()
  * @return The HTML attribute
  */
 CString CCrystalTextView::
-GetHTMLAttribute (int nColorIndex, int nBgColorIndex, COLORREF crText, COLORREF crBkgnd)
+GetHTMLAttribute (int nColorIndex, int nBgColorIndex, CEColor crText, CEColor crBkgnd)
 {
   CString strAttr;
-  COLORREF clr;
+  CEColor clr, clrBk;
 
   if ((crText == CLR_NONE || (nColorIndex & COLORINDEX_APPLYFORCE)) && 
       (crBkgnd == CLR_NONE || (nBgColorIndex & COLORINDEX_APPLYFORCE)))
-    return Fmt(_T("class=\"sf%db%d\""), nColorIndex & ~COLORINDEX_APPLYFORCE, nBgColorIndex & ~COLORINDEX_APPLYFORCE);
+    return Fmt(_T("class=\"sf%db%d%s\""), nColorIndex & ~COLORINDEX_MASK, nBgColorIndex & ~COLORINDEX_MASK,
+      (nColorIndex & COLORINDEX_INTERMEDIATECOLOR) ? _T("i") : _T(""));
 
   if (crText == CLR_NONE || (nColorIndex & COLORINDEX_APPLYFORCE))
     clr = GetColor (nColorIndex);
   else
     clr = crText;
-  strAttr += Fmt (_T("style=\"color: #%02x%02x%02x; "), GetRValue (clr), GetGValue (clr), GetBValue (clr));
-
   if (crBkgnd == CLR_NONE || (nBgColorIndex & COLORINDEX_APPLYFORCE))
-    clr = GetColor (nBgColorIndex);
+    clrBk = GetColor (nBgColorIndex);
   else
-    clr = crBkgnd;
-  strAttr += Fmt (_T("background-color: #%02x%02x%02x; "), GetRValue (clr), GetGValue (clr), GetBValue (clr));
+    clrBk = crBkgnd;
+  if (nColorIndex & COLORINDEX_INTERMEDIATECOLOR)
+    clr = CEColor::GetIntermediateColor(clr, clrBk, 0.333f);
+  strAttr += Fmt (_T("style=\"color: #%02x%02x%02x; "), GetRValue (clr), GetGValue (clr), GetBValue (clr));
+  strAttr += Fmt (_T("background-color: #%02x%02x%02x; "), GetRValue (clrBk), GetGValue (clrBk), GetBValue (clrBk));
 
   if (GetBold (nColorIndex))
     strAttr += _T("font-weight: bold; ");
@@ -2035,86 +2280,185 @@ GetHTMLAttribute (int nColorIndex, int nBgColorIndex, COLORREF crText, COLORREF
   return strAttr;
 }
 
+CString CCrystalTextView::
+GetColumnName(int nColumn)
+{
+  CString columnName;
+  for (int i = 0; ; ++i)
+    {
+      tchar_t c = 'A' + (nColumn % 26) - (i == 0 ? 0 : 1);
+      columnName.Insert (0, c);
+      nColumn /= 26;
+      if (nColumn == 0)
+        break;
+    }
+  return columnName;
+};
+
 /**
  * @brief Retrieve the html version of the line
  * @param [in] nLineIndex  Index of line in view
  * @param [in] pszTag      The HTML tag to enclose the line
+ * @param [in] nColumnCountMax Maximum number of columns
  * @return The html version of the line
  */
 CString CCrystalTextView::
-GetHTMLLine (int nLineIndex, LPCTSTR pszTag)
+GetHTMLLine (int nLineIndex, const tchar_t* pszTag, int nColumnCountMax)
 {
   ASSERT (nLineIndex >= -1 && nLineIndex < GetLineCount ());
 
   int nLength = GetViewableLineLength (nLineIndex);
-  LPCTSTR pszChars = GetLineChars (nLineIndex);
 
   //  Acquire the background color for the current line
   bool bDrawWhitespace = false;
-  COLORREF crBkgnd, crText;
+  CEColor crBkgnd, crText;
   GetLineColors (nLineIndex, crBkgnd, crText, bDrawWhitespace);
 
   std::vector<TEXTBLOCK> blocks = GetTextBlocks(nLineIndex);
-
+  int nColumn = 0;
+  const int nColumnCount = m_pTextBuffer->GetColumnCount (nLineIndex);
   CString strHTML;
   CString strExpanded;
-  size_t i;
   int nNonbreakChars = 0;
   bool bLastCharSpace = false;
   const int nScreenChars = 40; //  GetScreenChars();
 
-  strHTML += _T("<");
-  strHTML += pszTag;
-  strHTML += _T(" ");
-  strHTML += GetHTMLAttribute (COLORINDEX_NORMALTEXT, COLORINDEX_BKGND, crText, crBkgnd);
-  strHTML += _T("><code>");
+  auto MakeSpan = [&](const TEXTBLOCK& block, const CString& strExpanded) {
+      CString strHTML;
+      strHTML += _T("<span ");
+      strHTML += GetHTMLAttribute (block.m_nColorIndex, block.m_nBgColorIndex, crText, crBkgnd);
+      strHTML += _T(">");
+      strHTML += EscapeHTML (strExpanded, bLastCharSpace, nNonbreakChars, nScreenChars);
+      strHTML += _T("</span>");
+      return strHTML;
+      };
+
+  const TextLayoutMode layoutMode = GetTextLayoutMode ();
+  if (layoutMode == TEXTLAYOUT_TABLE_NOWORDWRAP ||
+      layoutMode == TEXTLAYOUT_TABLE_WORDWRAP)
+    {
+      std::vector<int> anBreaks;
+      if (layoutMode == TEXTLAYOUT_TABLE_WORDWRAP)
+        {
+          int nBreaks = 0;
+          anBreaks.resize (GetLineLength(nLineIndex) + 1);
+          WrapLineCached ( nLineIndex, nScreenChars, &anBreaks, nBreaks );
+        }
+      anBreaks.push_back (-nLength);
+
+      const tchar_t* pszChars = GetLineChars (nLineIndex);
+      const int sep = m_pTextBuffer->GetFieldDelimiter ();
+      const int quote = m_pTextBuffer->GetFieldEnclosure ();
+      bool bInQuote = false;
 
-  for (i = 0; i < blocks.size() - 1; i++)
-    {
-      ExpandChars (pszChars, blocks[i].m_nCharPos, blocks[i + 1].m_nCharPos - blocks[i].m_nCharPos, strExpanded, 0);
-      if (!strExpanded.IsEmpty())
+      strHTML += _T("<");
+      strHTML += pszTag;
+      strHTML += _T(" ");
+      if (nColumn + 1 == nColumnCount && (nColumnCountMax - nColumn) > 1)
+        {
+          CString colspan;
+          colspan.Format (_T("colspan=\"%d\" "), nColumnCountMax - nColumn);
+          strHTML += colspan;
+        }
+      strHTML += GetHTMLAttribute (COLORINDEX_NORMALTEXT, COLORINDEX_BKGND, crText, crBkgnd);
+      strHTML += _T("><code>");
+      int k = 0;
+      for (size_t j = 0; j < blocks.size(); j++)
         {
-          strHTML += _T("<span ");
-          strHTML += GetHTMLAttribute (blocks[i].m_nColorIndex, blocks[i].m_nBgColorIndex, crText, crBkgnd);
-          strHTML += _T(">");
-          strHTML += EscapeHTML (strExpanded, bLastCharSpace, nNonbreakChars, nScreenChars);
-          strHTML += _T("</span>");
+          int blockBegin = blocks[j].m_nCharPos;
+          int blockEnd = (j + 1 < blocks.size()) ? blocks[j + 1].m_nCharPos : nLength;
+          for (int i = blockBegin; i < blockEnd; i++)
+            {
+              tchar_t c = pszChars[i];
+              if (abs(anBreaks[k]) == i)
+                {
+                  if (anBreaks[k] >= 0)
+                    {
+                      ExpandChars (nLineIndex, blockBegin, i - blockBegin, strExpanded, 0);
+                      strHTML += MakeSpan (blocks[j], strExpanded);
+                      strHTML += _T("<br />");
+                      blockBegin = i;
+                    }
+                  k++;
+                }
+              if (!bInQuote && c == sep)
+                {
+                  ExpandChars (nLineIndex, blockBegin, i + 1 - blockBegin, strExpanded, 0);
+                  strHTML += MakeSpan (blocks[j], strExpanded);
+                  blockBegin = i + 1;
+                  bLastCharSpace = false;
+                  nNonbreakChars = 0;
+                  nColumn++;
+                  strHTML += _T("</code></");
+                  strHTML += pszTag;
+                  strHTML += _T("><");
+                  strHTML += pszTag;
+                  strHTML += _T(" ");
+                  if (nColumn + 1 == nColumnCount && (nColumnCountMax - nColumn) > 1)
+                    {
+                      CString colspan;
+                      colspan.Format (_T("colspan=\"%d\" "), nColumnCountMax - nColumn);
+                      strHTML += colspan;
+                    }
+                  strHTML += GetHTMLAttribute (COLORINDEX_NORMALTEXT, COLORINDEX_BKGND, crText, crBkgnd);
+                  strHTML += _T("><code>");
+                }
+              else if (c == quote)
+                {
+                  bInQuote = !bInQuote;
+                }
+            }
+          ExpandChars (nLineIndex, blockBegin, blockEnd - blockBegin, strExpanded, 0);
+          strHTML += MakeSpan (blocks[j], strExpanded);
         }
+      strHTML += _T("</code></");
+      strHTML += pszTag;
+      strHTML += _T(">");
     }
-  if (blocks.size() > 0)
-  {
-    ExpandChars (pszChars, blocks[i].m_nCharPos, nLength - blocks[i].m_nCharPos, strExpanded, 0);
-    if (!strExpanded.IsEmpty())
+  else
+    {
+      strHTML += _T("<");
+      strHTML += pszTag;
+      strHTML += _T(" ");
+      strHTML += GetHTMLAttribute (COLORINDEX_NORMALTEXT, COLORINDEX_BKGND, crText, crBkgnd);
+      strHTML += _T("><code>");
+
+      size_t i;
+      for (i = 0; i < blocks.size() - 1; i++)
       {
-        strHTML += _T("<span ");
-        strHTML += GetHTMLAttribute (blocks[i].m_nColorIndex, blocks[i].m_nBgColorIndex, crText, crBkgnd);
-        strHTML += _T(">");
-        strHTML += EscapeHTML (strExpanded, bLastCharSpace, nNonbreakChars, nScreenChars);
-        strHTML += _T("</span>");
+          ExpandChars (nLineIndex, blocks[i].m_nCharPos, blocks[i + 1].m_nCharPos - blocks[i].m_nCharPos, strExpanded, 0);
+          if (!strExpanded.IsEmpty())
+              strHTML += MakeSpan(blocks[i], strExpanded);
       }
-    if (strExpanded.Compare (CString (' ', strExpanded.GetLength())) == 0)
-      strHTML += _T("&nbsp;");
-  }
-  strHTML += _T("</code></");
-  strHTML += pszTag;
-  strHTML += _T(">");
+      if (blocks.size() > 0)
+      {
+          ExpandChars (nLineIndex, blocks[i].m_nCharPos, nLength - blocks[i].m_nCharPos, strExpanded, 0);
+          if (!strExpanded.IsEmpty())
+              strHTML += MakeSpan(blocks[i], strExpanded);
+          if (strExpanded.Compare (CString (' ', strExpanded.GetLength())) == 0)
+              strHTML += _T("&nbsp;");
+      }
+      strHTML += _T("</code></");
+      strHTML += pszTag;
+      strHTML += _T(">");
+    }
 
   return strHTML;
 }
 
-COLORREF CCrystalTextView::
-GetColor (int nColorIndex)
+CEColor CCrystalTextView::
+GetColor (int nColorIndex) const
 {
   if (m_pColors != nullptr)
     {
-      nColorIndex &= ~COLORINDEX_APPLYFORCE;
+      nColorIndex &= ~COLORINDEX_MASK;
       return m_pColors->GetColor(nColorIndex);
     }
   else
-    return RGB(0, 0, 0);
+    return { 0, 0, 0 };
 }
 
-DWORD CCrystalTextView::
+lineflags_t CCrystalTextView::
 GetLineFlags (int nLineIndex) const
 {
   if (m_pTextBuffer == nullptr)
@@ -2122,6 +2466,82 @@ GetLineFlags (int nLineIndex) const
   return m_pTextBuffer->GetLineFlags (nLineIndex);
 }
 
+void CCrystalTextView::
+GetTopMarginText (const CRect& rect, CString& text, std::vector<int>& nWidths)
+{
+  auto replaceControlChars = [](const CString& text) -> CString
+    {
+      CString result;
+      for (int i = 0; i < text.GetLength(); ++i)
+        {
+          if (_istcntrl(text[i]))
+            {
+              if (i == 0 || !_istcntrl(text[i - 1]))
+                  result += L' ';
+            }
+          else
+            result += text[i];
+        }
+      return result;
+    };
+
+  const int nCharWidth = GetCharWidth ();
+  const int nMarginWidth = GetMarginWidth ();
+  for (int nColumn = 0, x = nMarginWidth - m_nOffsetChar * nCharWidth; x < rect.Width (); ++nColumn)
+    {
+      int nColumnWidth = m_pTextBuffer->GetColumnWidth (nColumn);
+      CString columnName;
+      if (m_nLineNumberUsedAsHeaders >= 0 && m_nLineNumberUsedAsHeaders < m_pTextBuffer->GetLineCount() && 
+          (m_nTopSubLine > 0 || (m_pTextBuffer->GetLineFlags(m_nLineNumberUsedAsHeaders) & LF_INVISIBLE)))
+        columnName = replaceControlChars (m_pTextBuffer->GetCellText (m_nLineNumberUsedAsHeaders, nColumn).c_str ()); // Use std::basic_string<tchar_t> instead of CString
+      if (columnName.IsEmpty())
+        columnName = GetColumnName (nColumn);
+      int columnNameLen = 0;
+      std::vector<int> nCharWidths;
+      for (int i = 0; i < columnName.GetLength(); ++i)
+        {
+          int cnt = GetCharCellCountFromChar (((const tchar_t*)columnName) + i);
+          nCharWidths.push_back (cnt * nCharWidth);
+          columnNameLen += cnt;
+        }
+      while (nColumnWidth < columnNameLen)
+        {
+          columnNameLen -= nCharWidths.back() / nCharWidth;
+          columnName.Truncate(columnName.GetLength() - 1);
+          nCharWidths.resize(columnName.GetLength());
+        }
+      const int leftspaces = (nColumnWidth - columnNameLen) / 2;
+      const int rightspaces = nColumnWidth - leftspaces - columnNameLen;
+      text += CString (' ', leftspaces) + columnName + CString (' ', rightspaces);
+      std::vector<int> preWidths(leftspaces, nCharWidth);
+      std::vector<int> postWidths(rightspaces, nCharWidth);
+      nCharWidths.insert (nCharWidths.begin (), preWidths.begin (), preWidths.end ());
+      nCharWidths.insert (nCharWidths.end (), postWidths.begin (), postWidths.end ());
+      x += nColumnWidth * nCharWidth;
+      nWidths.insert (nWidths.end (), nCharWidths.begin (), nCharWidths.end ());
+    }
+}
+
+void CCrystalTextView::
+DrawTopMargin (const CRect& rect)
+{
+  if (!m_bTopMargin)
+    return;
+  m_pCrystalRenderer->SetBkColor (GetColor (COLORINDEX_SELMARGIN));
+  m_pCrystalRenderer->FillRectangle (rect);
+  m_pCrystalRenderer->SetTextColor (GetColor (COLORINDEX_NORMALTEXT));
+  if (m_pTextBuffer->GetTableEditing ())
+    {
+      CString columnNames;
+      std::vector<int> nWidths;
+      GetTopMarginText (rect, columnNames, nWidths);
+      m_pCrystalRenderer->SwitchFont (false, false);
+      m_pCrystalRenderer->DrawText (rect.left + GetMarginWidth () - m_nOffsetChar * GetCharWidth (), 0, rect, columnNames, columnNames.GetLength (), nWidths.data ());
+    }
+  else
+    m_pCrystalRenderer->DrawRuler (GetMarginWidth (), 0, rect.Width (), rect.Height (), GetCharWidth (), m_nOffsetChar);
+}
+
 /**
  * @brief Draw selection margin.
  * @param [in] pdc         Pointer to draw context.
@@ -2130,32 +2550,26 @@ GetLineFlags (int nLineIndex) const
  * @param [in] nLineNumber Line number to display. if -1, it's not displayed.
  */
 void CCrystalTextView::
-DrawMargin (CDC * pdc, const CRect & rect, int nLineIndex, int nLineNumber)
+DrawMargin (const CRect & rect, int nLineIndex, int nLineNumber)
 {
   if (!m_bSelMargin && !m_bViewLineNumbers)
-    pdc->FillSolidRect (rect, GetColor (COLORINDEX_BKGND));
+    m_pCrystalRenderer->SetBkColor(GetColor (COLORINDEX_BKGND));
   else
-    pdc->FillSolidRect (rect, GetColor (COLORINDEX_SELMARGIN));
+    m_pCrystalRenderer->SetBkColor(GetColor (COLORINDEX_SELMARGIN));
+  m_pCrystalRenderer->FillRectangle(rect);
 
   if (m_bViewLineNumbers && nLineNumber > 0)
     {
-      TCHAR szNumbers[32];
-      wsprintf(szNumbers, _T("%d"), nLineNumber);
-      CFont *pOldFont = pdc->SelectObject(GetFont());
-      COLORREF clrOldColor = pdc->SetTextColor(GetColor(COLORINDEX_NORMALTEXT));
-      UINT uiOldAlign = pdc->SetTextAlign(TA_RIGHT);
-      pdc->TextOut(rect.right - (pdc->IsPrinting() ? 0 : 4), rect.top, szNumbers, lstrlen(szNumbers));
-      pdc->SetTextAlign(uiOldAlign);
-      pdc->SelectObject(pOldFont);
-      pdc->SetTextColor(clrOldColor);
+      m_pCrystalRenderer->SetTextColor(GetColor(COLORINDEX_NORMALTEXT));
+      m_pCrystalRenderer->DrawMarginLineNumber(rect.right, rect.top, nLineNumber);
     }
 
   // Draw line revision mark (or background) whenever we have valid lineindex
-  COLORREF clrRevisionMark = GetColor(COLORINDEX_WHITESPACE);
+  CEColor clrRevisionMark = GetColor(COLORINDEX_WHITESPACE);
   if (nLineIndex >= 0 && m_pTextBuffer != nullptr)
     {
       // get line revision marks color
-      DWORD dwRevisionNumber = m_pTextBuffer->GetLineRevisionNumber(nLineIndex);
+      uint32_t dwRevisionNumber = m_pTextBuffer->GetLineRevisionNumber(nLineIndex);
       if (dwRevisionNumber > 0)
         {
           if (m_pTextBuffer->m_dwRevisionNumberOnSave < dwRevisionNumber)
@@ -2166,17 +2580,17 @@ DrawMargin (CDC * pdc, const CRect & rect, int nLineIndex, int nLineNumber)
     }
 
   // draw line revision marks
-  CRect rc(rect.right - (pdc->IsPrinting () ? 0 : MARGIN_REV_WIDTH), rect.top, rect.right, rect.bottom);
-  pdc->FillSolidRect (rc, clrRevisionMark);
+  CRect rc(rect.right - MARGIN_REV_WIDTH, rect.top, rect.right, rect.bottom);
+  m_pCrystalRenderer->FillSolidRectangle (rc, clrRevisionMark);
 
-  if (!m_bSelMargin || pdc->IsPrinting ())
+  if (!m_bSelMargin)
     return;
 
   int nImageIndex = -1;
   if (nLineIndex >= 0)
     {
-      DWORD dwLineFlags = GetLineFlags (nLineIndex);
-      static const DWORD adwFlags[] =
+      lineflags_t dwLineFlags = GetLineFlags (nLineIndex);
+      static const lineflags_t adwFlags[] =
         {
           LF_EXECUTION,
           LF_BREAKPOINT,
@@ -2203,63 +2617,30 @@ DrawMargin (CDC * pdc, const CRect & rect, int nLineIndex, int nLineNumber)
             }
         }
     }
-  if (m_pIcons == nullptr)
-    {
-      m_pIcons = new CImageList;
-      VERIFY (m_pIcons->Create(MARGIN_ICON_WIDTH, MARGIN_ICON_HEIGHT,
-          ILC_COLOR32 | ILC_MASK, 0, 1));
-      CBitmap bmp;
-      bmp.LoadBitmap(IDR_MARGIN_ICONS);
-      m_pIcons->Add(&bmp, RGB(255, 255, 255));
-    }
   if (nImageIndex >= 0)
     {
-      CPoint pt(rect.left + 2, rect.top + (GetLineHeight() - MARGIN_ICON_HEIGHT) / 2);
-      VERIFY(m_pIcons->Draw(pdc, nImageIndex, pt, ILD_TRANSPARENT));
-      VERIFY (m_pIcons->Draw (pdc, nImageIndex, pt, ILD_TRANSPARENT));
+      const int iconsize = GetMarginIconSize();
+      m_pCrystalRenderer->DrawMarginIcon(
+        rect.left + 2, rect.top + (GetLineHeight() - iconsize) / 2, nImageIndex, iconsize);
     }
 
   // draw wrapped-line-icon
   if (nLineNumber > 0)
     {
+      const int iconsize = GetMarginIconSize();
       int nBreaks = 0;
       WrapLineCached( nLineIndex, GetScreenChars(), nullptr, nBreaks );
       for (int i = 0; i < nBreaks; i++)
         {
-          CPoint pt(rect.right - MARGIN_ICON_WIDTH, rect.top + (GetLineHeight()
-              - MARGIN_ICON_WIDTH) / 2 + (i+1) * GetLineHeight());
-          m_pIcons->Draw (pdc, ICON_INDEX_WRAPLINE, pt, ILD_TRANSPARENT);
+          m_pCrystalRenderer->DrawMarginIcon(
+              rect.right - iconsize, rect.top + (GetLineHeight()
+              - iconsize) / 2 + (i+1) * GetLineHeight(), ICON_INDEX_WRAPLINE, iconsize);
         }
     }
 }
 
-void CCrystalTextView::
-DrawBoundaryLine (CDC * pdc, int nLeft, int nRight, int y)
-{
-  CPen *pOldPen = (CPen *)pdc->SelectStockObject (BLACK_PEN);
-  pdc->MoveTo (nLeft, y);
-  pdc->LineTo (nRight, y);
-  pdc->SelectObject (pOldPen);
-}
-
-void CCrystalTextView::
-DrawLineCursor (CDC * pdc, int nLeft, int nRight, int y, int nHeight)
-{
-  CDC  dcMem;
-  dcMem.CreateCompatibleDC (pdc);
-  CBitmap bitmap;
-  bitmap.CreateCompatibleBitmap (pdc, nRight - nLeft, nHeight);
-  CBitmap *pOldBitmap = dcMem.SelectObject (&bitmap);
-  dcMem.SetBkColor(RGB(0, 255, 0));
-  BLENDFUNCTION blend = {0};
-  blend.BlendOp = AC_SRC_OVER;
-  blend.SourceConstantAlpha = 24;
-  pdc->AlphaBlend (nLeft, y, nRight - nLeft, nHeight, &dcMem, 0, 0, nRight - nLeft, nHeight, blend);
-  dcMem.SelectObject (pOldBitmap);
-}
-
 bool CCrystalTextView::
-IsInsideSelBlock (CPoint ptTextPos)
+IsInsideSelBlock (CEPoint ptTextPos)
 {
   PrepareSelBounds();
   ASSERT_VALIDTEXTPOS (ptTextPos);
@@ -2267,6 +2648,8 @@ IsInsideSelBlock (CPoint ptTextPos)
     return false;
   if (ptTextPos.y > m_ptDrawSelEnd.y)
     return false;
+  if (m_bRectangularSelection)
+    return ptTextPos.x >= m_ptDrawSelStart.x && ptTextPos.x < m_ptDrawSelEnd.x;
   if (ptTextPos.y < m_ptDrawSelEnd.y && ptTextPos.y > m_ptDrawSelStart.y)
     return true;
   if (m_ptDrawSelStart.y < m_ptDrawSelEnd.y)
@@ -2281,7 +2664,7 @@ IsInsideSelBlock (CPoint ptTextPos)
 }
 
 bool CCrystalTextView::
-IsInsideSelection (const CPoint & ptTextPos)
+IsInsideSelection (const CEPoint & ptTextPos)
 {
   PrepareSelBounds ();
   return IsInsideSelBlock (ptTextPos);
@@ -2322,7 +2705,11 @@ OnDraw (CDC * pdc)
 
   if (m_pTextBuffer == nullptr)
     {
-      pdc->FillSolidRect(&rcClient, GetSysColor(COLOR_WINDOW));
+      m_pCrystalRenderer->BindDC(*pdc, rcClient);
+      m_pCrystalRenderer->BeginDraw();
+      m_pCrystalRenderer->SetBkColor(GetSysColor(COLOR_WINDOW));
+      m_pCrystalRenderer->FillRectangle(rcClient);
+      m_pCrystalRenderer->EndDraw();
       return;
     }
 
@@ -2346,72 +2733,80 @@ OnDraw (CDC * pdc)
     }
   CBitmap *pOldBitmap = cacheDC.SelectObject (m_pCacheBitmap);
 
-  CRect rcLine;
-  rcLine = rcClient;
-  rcLine.bottom = rcLine.top + nLineHeight;
-  CRect rcCacheMargin (0, 0, GetMarginWidth (), nLineHeight);
-  CRect rcCacheLine (GetMarginWidth (), 0, rcLine.Width (), nLineHeight);
-  //BEGIN SW
   // initialize rects
-  int          nSubLineOffset = GetSubLineIndex( m_nTopLine ) - m_nTopSubLine;
-  if( nSubLineOffset < 0 )
-  {
-    rcCacheMargin.OffsetRect( 0, nSubLineOffset * nLineHeight );
-    rcCacheLine.OffsetRect( 0, nSubLineOffset * nLineHeight );
-  }
-
+  int nSubLineOffset = GetSubLineIndex( m_nTopLine ) - m_nTopSubLine;
   int nCursorY = TextToClient (m_ptCursorPos).y;
 
-  //END SW
+  CRect rcLine;
+  CRect rcTopMargin(rcClient.left, rcClient.top, rcClient.right, rcClient.top + GetTopMarginHeight());
+  rcLine = rcClient;
+  rcLine.top = rcTopMargin.bottom + nSubLineOffset * nLineHeight;
+  CRect rcMargin (rcLine.left, rcLine.top, rcLine.left + GetMarginWidth (), rcLine.top + nLineHeight);
+  rcLine.left = rcMargin.right;
 
+  m_pCrystalRenderer->BindDC(cacheDC, rcClient);
+  m_pCrystalRenderer->BeginDraw();
+
+  int nLastLineBottom = 0;
   int nCurrentLine = m_nTopLine;
   while (rcLine.top < rcClient.bottom)
     {
-      //BEGIN SW
       int nSubLines = 1;
       if( nCurrentLine < nLineCount /*&& GetLineLength( nCurrentLine ) > nMaxLineChars*/ )
-         nSubLines = GetSubLines(nCurrentLine);
+        nSubLines = GetSubLines(nCurrentLine);
 
-      rcLine.bottom = rcLine.top + nSubLines * nLineHeight;
-      rcCacheLine.bottom = rcCacheLine.top + rcLine.Height();
-      rcCacheMargin.bottom = rcCacheMargin.top + rcLine.Height();
+      rcLine.bottom = (std::min)(rcClient.bottom, rcLine.top + nSubLines * nLineHeight);
+      rcMargin.bottom = rcLine.bottom;
 
-      if( rcCacheLine.top < 0 )
-        rcLine.bottom+= rcCacheLine.top;
-      //END SW
-      if (pdc->RectVisible(rcLine))
+      CRect rcMarginAndLine(rcClient.left, rcLine.top, rcClient.right, rcLine.bottom);
+      if (pdc->RectVisible(rcMarginAndLine))
         {
           if (nCurrentLine < nLineCount && GetLineVisible (nCurrentLine))
             {
-              DrawMargin (&cacheDC, rcCacheMargin, nCurrentLine, nCurrentLine + 1);
-              DrawSingleLine (&cacheDC, rcCacheLine, nCurrentLine);
+              DrawMargin (rcMargin, nCurrentLine, nCurrentLine + 1);
+              DrawSingleLine (rcLine, nCurrentLine);
               if (nCurrentLine+1 < nLineCount && !GetLineVisible (nCurrentLine + 1))
-                DrawBoundaryLine (&cacheDC, rcCacheMargin.left, rcCacheLine.right, rcCacheMargin.bottom-1);
+                m_pCrystalRenderer->DrawBoundaryLine (rcMargin.left, rcLine.right, rcMargin.top + nSubLines * nLineHeight - 1);
+              if (m_pTextBuffer->GetTableEditing ())
+                m_pCrystalRenderer->DrawGridLine (rcMargin.left, rcMargin.top + nSubLines * nLineHeight - 1, rcLine.right, rcMargin.top + nSubLines * nLineHeight - 1, 24);
               if (nCurrentLine == m_ptCursorPos.y)
-                DrawLineCursor (&cacheDC, rcCacheMargin.left, rcCacheLine.right, 
-                  nCursorY - rcLine.top + nLineHeight - 1, 1);
+                m_pCrystalRenderer->DrawLineCursor (rcMargin.left, rcLine.right, 
+                  nCursorY + nLineHeight - 1, 1);
+              nLastLineBottom = rcMargin.bottom;
             }
           else
             {
-              DrawMargin (&cacheDC, rcCacheMargin, -1, -1);
-              DrawSingleLine (&cacheDC, rcCacheLine, -1);
+              DrawMargin (rcMargin, -1, -1);
+              DrawSingleLine (rcLine, -1);
             }
-
-          VERIFY (pdc->BitBlt (rcLine.left, rcLine.top, rcLine.Width (),
-              rcLine.Height (), &cacheDC, 0, 0, SRCCOPY));
         }
 
       nCurrentLine++;
-      //BEGIN SW
-      rcLine.top = rcLine.bottom;
-      rcCacheLine.top = 0;
-      rcCacheMargin.top = 0;
-      /*ORIGINAL
-      rcLine.OffsetRect(0, nLineHeight);
-      */
-      //END SW
+      rcLine.top += nSubLines * nLineHeight;
+      rcMargin.top = rcLine.top;
+    }
+
+  if (pdc->RectVisible (rcTopMargin))
+    DrawTopMargin (rcTopMargin);
+
+  if (m_pTextBuffer->GetTableEditing ())
+    {
+      int nCharWidth = GetCharWidth ();
+      int nMarginWidth = GetMarginWidth ();
+      for (int nColumn = 0, x = nMarginWidth - m_nOffsetChar * nCharWidth;
+           x < rcClient.Width();
+           x += m_pTextBuffer->GetColumnWidth (nColumn++) * nCharWidth)
+        {
+          if (x >= nMarginWidth && nColumn > 0)
+            m_pCrystalRenderer->DrawGridLine (x, rcClient.top, x, nLastLineBottom, 24);
+        }
     }
 
+  m_pCrystalRenderer->EndDraw();
+
+  VERIFY (pdc->BitBlt (rcClient.left, rcClient.top, rcClient.Width (),
+          rcClient.Height (), &cacheDC, 0, 0, SRCCOPY));
+
   cacheDC.SelectObject (pOldBitmap);
   cacheDC.DeleteDC ();
 }
@@ -2430,19 +2825,6 @@ ResetView ()
   m_nIdealCharPos = -1;
   m_ptAnchor.x = 0;
   m_ptAnchor.y = 0;
-  if (m_pIcons != nullptr)
-    {
-      delete m_pIcons;
-      m_pIcons = nullptr;
-    }
-  for (int I = 0; I < 4; I++)
-    {
-      if (m_apFonts[I] != nullptr)
-        {
-          delete m_apFonts[I];
-          m_apFonts[I] = nullptr;
-        }
-    }
   InvalidateLineCache( 0, -1 );
   m_ParseCookies->clear();
   m_pnActualLineLength->clear();
@@ -2472,11 +2854,21 @@ UpdateCaret ()
 {
   ASSERT_VALIDTEXTPOS (m_ptCursorPos);
   if (m_bFocused && !m_bCursorHidden &&
-        CalculateActualOffset (m_ptCursorPos.y, m_ptCursorPos.x) >= m_nOffsetChar)
+        CalculateActualOffset (m_ptCursorPos.y, m_ptCursorPos.x) >= m_nOffsetChar &&
+        m_ptCursorPos.y >= m_nTopLine)
     {
       int nCaretHeight = GetLineVisible(m_ptCursorPos.y) ? GetLineHeight () : 0;
-      if (m_bOverrideCaret)  //UPDATE
-        CreateSolidCaret(GetCharWidth(), nCaretHeight);
+      if (m_bOvrMode)  //UPDATE
+        {
+          int nCaretWidth = GetCharWidth ();
+          if (m_ptCursorPos.x < GetLineLength (m_ptCursorPos.y))
+            {
+              const tchar_t* pszLine = GetLineChars  (m_ptCursorPos.y);
+              if (pszLine[m_ptCursorPos.x] != '\t')
+                  nCaretWidth *= GetCharCellCountFromChar (pszLine + m_ptCursorPos.x);
+            }
+          CreateSolidCaret (nCaretWidth, nCaretHeight);
+        }
       else
         CreateSolidCaret (2, nCaretHeight);
 
@@ -2496,14 +2888,14 @@ OnUpdateCaret()
 {
 }
 
-int CCrystalTextView::
+CRLFSTYLE CCrystalTextView::
 GetCRLFMode ()
 {
   if (m_pTextBuffer != nullptr)
     {
       return m_pTextBuffer->GetCRLFMode ();
     }
-  return -1;
+  return CRLFSTYLE::AUTOMATIC;
 }
 
 void CCrystalTextView::
@@ -2537,62 +2929,20 @@ SetTabSize (int nTabSize)
       m_pTextBuffer->SetTabSize( nTabSize );
 
       m_pnActualLineLength->clear();
-      RecalcHorzScrollBar ();
+      InvalidateHorzScrollBar ();
       Invalidate ();
       UpdateCaret ();
     }
 }
 
-CFont *CCrystalTextView::
-GetFont (bool bItalic /*= false*/ , bool bBold /*= false*/ )
-{
-  int nIndex = 0;
-  if (bBold)
-    nIndex |= 1;
-  if (bItalic)
-    nIndex |= 2;
-
-  if (m_apFonts[nIndex] == nullptr)
-    {
-      m_apFonts[nIndex] = new CFont;
-      if (!m_lfBaseFont.lfHeight)
-        {
-          CClientDC dc (GetDesktopWindow ());
-          m_lfBaseFont.lfHeight = -MulDiv (11, dc.GetDeviceCaps (LOGPIXELSY), 72);
-        }
-      m_lfBaseFont.lfWeight = bBold ? FW_BOLD : FW_NORMAL;
-      m_lfBaseFont.lfItalic = (BYTE) bItalic;
-      if (!m_apFonts[nIndex]->CreateFontIndirect (&m_lfBaseFont))
-        {
-          delete m_apFonts[nIndex];
-          m_apFonts[nIndex] = nullptr;
-          return CView::GetFont ();
-        }
-    }
-  return m_apFonts[nIndex];
-}
-
 void CCrystalTextView::
 CalcLineCharDim ()
 {
-  CDC *pdc = GetDC ();
-  CFont *pOldFont = pdc->SelectObject (GetFont ());
-  CSize szCharExt = pdc->GetTextExtent (_T ("X"));
+  CSize szCharExt = m_pCrystalRenderer->GetCharWidthHeight();
   m_nLineHeight = szCharExt.cy;
   if (m_nLineHeight < 1)
     m_nLineHeight = 1;
   m_nCharWidth = szCharExt.cx;
-  /*
-     TEXTMETRIC tm;
-     if (pdc->GetTextMetrics(&tm))
-     m_nCharWidth -= tm.tmOverhang;
-   */
-  pdc->SelectObject (GetFont (false, true));
-  szCharExt = pdc->GetTextExtent (_T ("X"));
-  if (m_nLineHeight < szCharExt.cy)
-    m_nLineHeight = szCharExt.cy;
-  pdc->SelectObject (pOldFont);
-  ReleaseDC (pdc);
 }
 
 int CCrystalTextView::
@@ -2612,11 +2962,6 @@ int CCrystalTextView::GetSubLines( int nLineIndex )
   return GetEmptySubLines(nLineIndex) + nBreaks + 1;
 }
 
-int CCrystalTextView::GetEmptySubLines( int nLineIndex )
-{
-  return 0;
-}
-
 bool CCrystalTextView::IsEmptySubLineIndex( int nSubLineIndex )
 {
   int nLineIndex;
@@ -2629,7 +2974,7 @@ bool CCrystalTextView::IsEmptySubLineIndex( int nSubLineIndex )
     return false;
 }
 
-int CCrystalTextView::CharPosToPoint( int nLineIndex, int nCharPos, CPoint &charPoint )
+int CCrystalTextView::CharPosToPoint( int nLineIndex, int nCharPos, CEPoint &charPoint, int* pnColumn )
 {
   // if we do not wrap lines, y is allways 0 and x is equl to nCharPos
   if (!m_bWordWrap)
@@ -2642,22 +2987,47 @@ int CCrystalTextView::CharPosToPoint( int nLineIndex, int nCharPos, CPoint &char
   vector<int> anBreaks(GetLineLength (nLineIndex) + 1);
   int nBreaks = 0;
 
-  WrapLineCached (nLineIndex, GetScreenChars(), &anBreaks[0], nBreaks);
+  WrapLineCached (nLineIndex, GetScreenChars(), &anBreaks, nBreaks);
+
+  if (GetTextLayoutMode () == TEXTLAYOUT_TABLE_WORDWRAP)
+    {
+      int nColumn = 0;
+      int j = 0;
+      size_t i = 0;
+      for (; i < anBreaks.size () && abs (anBreaks[i]) <= nCharPos ; ++i)
+        {
+          if (anBreaks[i] < 0)
+            {
+              nColumn++;
+              j = 0;
+            }
+          else
+            ++j;
+        }
+      charPoint.x = (i > 0) ? nCharPos - abs (anBreaks[i - 1]) : nCharPos;
+      charPoint.y = j;
+      if (pnColumn)
+        *pnColumn = nColumn;
 
-  int i = (nBreaks <= 0) ? -1 : nBreaks - 1;
-  for (; i >= 0 && nCharPos < anBreaks[i]; i--)
-    ; // Empty loop!
+      return (i > 0)? abs (anBreaks[i - 1]) : 0;
+    }
+  else
+    {
+      int i = (nBreaks <= 0) ? -1 : nBreaks - 1;
+      for (; i >= 0 && nCharPos < anBreaks[i]; i--)
+          ; // Empty loop!
 
-  charPoint.x = (i >= 0)? nCharPos - anBreaks[i] : nCharPos;
-  charPoint.y = i + 1;
+      charPoint.x = (i >= 0)? nCharPos - anBreaks[i] : nCharPos;
+      charPoint.y = i + 1;
 
-  int nReturnVal = (i >= 0)? anBreaks[i] : 0;
+      int nReturnVal = (i >= 0)? anBreaks[i] : 0;
 
-  return nReturnVal;
+      return nReturnVal;
+    }
 }
 
 /** Does character introduce a multicharacter character? */
-static inline bool IsLeadByte(TCHAR ch)
+static inline bool IsLeadByte(tchar_t ch)
 {
 #ifdef UNICODE
   return false;
@@ -2666,18 +3036,18 @@ static inline bool IsLeadByte(TCHAR ch)
 #endif
 }
 
-int CCrystalTextView::CursorPointToCharPos( int nLineIndex, const CPoint &curPoint )
+int CCrystalTextView::CursorPointToCharPos( int nLineIndex, const CEPoint &curPoint )
 {
   // calculate char pos out of point
   const int nLength = GetLineLength( nLineIndex );
   const int nScreenChars = GetScreenChars();
-  LPCTSTR      szLine = GetLineChars( nLineIndex );
+  const tchar_t*       szLine = GetLineChars( nLineIndex );
 
   // wrap line
   vector<int> anBreaks(nLength + 1);
   int  nBreaks = 0;
 
-  WrapLineCached( nLineIndex, nScreenChars, &anBreaks[0], nBreaks );
+  WrapLineCached( nLineIndex, nScreenChars, &anBreaks, nBreaks );
 
   // find char pos that matches cursor position
   int nXPos = 0;
@@ -2686,38 +3056,134 @@ int CCrystalTextView::CursorPointToCharPos( int nLineIndex, const CPoint &curPoi
   const int nTabSize = GetTabSize();
 
   int nIndex=0, nPrevIndex = 0;
-  m_iterChar.setText(reinterpret_cast<const UChar *>(szLine), nLength);
-  for( nIndex = 0; nIndex < nLength; nIndex = m_iterChar.next())
+  auto pIterChar = ICUBreakIterator::getCharacterBreakIterator(szLine, nLength);
+  switch (GetTextLayoutMode ())
     {
-      if( nBreaks > 0 && nIndex == anBreaks[nYPos] )
+      case TEXTLAYOUT_TABLE_NOWORDWRAP:
         {
-          nXPos = 0;
-          nYPos++;
-        }
+          int nColumnCount = m_pTextBuffer->GetColumnCount (nLineIndex);
+          int nColumnTotalWidth = 0;
+          int nColumn = 0;
+          bool bInQuote = false;
+          const int sep = m_pTextBuffer->GetFieldDelimiter ();
+          const int quote = m_pTextBuffer->GetFieldEnclosure ();
+          for( nIndex = 0; nIndex < nLength; nIndex = pIterChar->next())
+            {
+              int nOffset;
+              if (!bInQuote && szLine[nIndex] == sep)
+                {
+                  nColumnTotalWidth += m_pTextBuffer->GetColumnWidth (nColumn++);
+                  nOffset = nColumnTotalWidth - nXPos;
+                }
+              else
+                {
+                  if (szLine[nIndex] == quote)
+                    bInQuote = !bInQuote;
+                  if (szLine[nIndex] == '\t')
+                    nOffset = 1;
+                  else
+                    nOffset = GetCharCellCountFromChar (szLine + nIndex);
+                  if (nColumn < nColumnCount && nCurPos + nOffset > nColumnTotalWidth + m_pTextBuffer->GetColumnWidth (nColumn))
+                    nOffset = nColumnTotalWidth + m_pTextBuffer->GetColumnWidth (nColumn) - nXPos;
+                }
+              nXPos += nOffset;
+              nCurPos += nOffset;
 
-      int nOffset;
-      if (szLine[nIndex] == _T('\t'))
-        nOffset = nTabSize - nCurPos % nTabSize;
-      else
-        nOffset = GetCharCellCountFromChar(szLine + nIndex);
-      nXPos += nOffset;
-      nCurPos += nOffset;
+              if( nXPos > curPoint.x && nYPos == curPoint.y )
+                break;
+              else if( nYPos > curPoint.y )
+                {
+                  nIndex = nPrevIndex;
+                  break;
+                }
 
-      if( nXPos > curPoint.x && nYPos == curPoint.y )
+              nPrevIndex = nIndex;
+            }
+        }
         break;
-      else if( nYPos > curPoint.y )
+      case TEXTLAYOUT_TABLE_WORDWRAP:
         {
-          nIndex = nPrevIndex;
-          break;
+          int i = 0;
+          int nColumn = 0;
+          int nColumnSumWidth = 0;
+          int nColumnCurPoint = INT_MAX;
+          if (curPoint.x < m_pTextBuffer->GetColumnWidth (0))
+            nColumnCurPoint = 0;
+          for( nIndex = 0; nIndex < nLength; nIndex = pIterChar->next ())
+            {
+              if (i < static_cast<int>(anBreaks.size ()) && nIndex == abs (anBreaks[i]))
+                {
+                  if (anBreaks[i++] < 0)
+                    {
+                      nYPos = 0;
+                      nColumnSumWidth += m_pTextBuffer->GetColumnWidth (nColumn++);
+                      nXPos = nColumnSumWidth;
+                      if (nColumnSumWidth <= curPoint.x && curPoint.x < nColumnSumWidth + m_pTextBuffer->GetColumnWidth (nColumn))
+                        nColumnCurPoint = nColumn;
+                    }
+                  else
+                    {
+                      nXPos = nColumnSumWidth;
+                      nYPos++;
+                    }
+                }
+
+              int nOffset;
+              if (szLine[nIndex] == '\t')
+                nOffset = 1;
+              else
+                nOffset = GetCharCellCountFromChar (szLine + nIndex);
+              nXPos += nOffset;
+              nCurPos += nOffset;
+
+              if( nXPos > curPoint.x && nYPos == curPoint.y )
+                break;
+              else if( nColumnCurPoint < nColumn && nPrevIndex != 0)
+                {
+                  nIndex = nPrevIndex;
+                  break;
+                }
+              else if ( nYPos == curPoint.y)
+                nPrevIndex = nIndex;
+            }
+          if (nIndex == nLength && nYPos != curPoint.y)
+            nIndex = nPrevIndex;
         }
+        break;
+      default:
+        {
+          for( nIndex = 0; nIndex < nLength; nIndex = pIterChar->next())
+            {
+              if( nBreaks > 0 && nYPos < static_cast<int>(anBreaks.size ()) && nIndex == anBreaks[nYPos] )
+                {
+                  nXPos = 0;
+                  nYPos++;
+                }
 
-      nPrevIndex = nIndex;
-    }
+              int nOffset;
+              if (szLine[nIndex] == _T('\t'))
+                nOffset = nTabSize - nCurPos % nTabSize;
+              else
+                nOffset = GetCharCellCountFromChar(szLine + nIndex);
+              nXPos += nOffset;
+              nCurPos += nOffset;
 
+              if( nXPos > curPoint.x && nYPos == curPoint.y )
+                break;
+              else if( nYPos > curPoint.y )
+                {
+                  nIndex = nPrevIndex;
+                  break;
+                }
+
+              nPrevIndex = nIndex;
+            }
+        }
+    }
   return nIndex;
 }
 
-void CCrystalTextView::SubLineCursorPosToTextPos( const CPoint &subLineCurPos, CPoint &textPos )
+void CCrystalTextView::SubLineCursorPosToTextPos( const CEPoint &subLineCurPos, CEPoint &textPos )
 {
   // Get line breaks
   int  nSubLineOffset, nLine;
@@ -2725,7 +3191,7 @@ void CCrystalTextView::SubLineCursorPosToTextPos( const CPoint &subLineCurPos, C
   GetLineBySubLine( subLineCurPos.y, nLine, nSubLineOffset );
 
   // compute cursor-position
-  textPos.x = CursorPointToCharPos( nLine, CPoint( subLineCurPos.x, nSubLineOffset ) );
+  textPos.x = CursorPointToCharPos( nLine, CEPoint( subLineCurPos.x, nSubLineOffset ) );
   textPos.y = nLine;
 }
 
@@ -2747,7 +3213,22 @@ int CCrystalTextView::SubLineEndToCharPos(int nLineIndex, int nSubLineOffset)
   vector<int> anBreaks(nLength + 1);
   int nBreaks = 0;
 
-  WrapLineCached(nLineIndex, GetScreenChars(), &anBreaks[0], nBreaks);
+  WrapLineCached(nLineIndex, GetScreenChars(), &anBreaks, nBreaks);
+
+  if (GetTextLayoutMode() == TEXTLAYOUT_TABLE_WORDWRAP)
+    {
+      int nBreakLast = -1;
+      for (int i = 0, j = 1; i < static_cast<int>(anBreaks.size ()); ++i, ++j)
+        {
+          if (anBreaks[i] < 0)
+            j = 0;
+          if (j == nSubLineOffset)
+            nBreakLast = i;
+        }
+      if (nBreakLast < static_cast<int>(anBreaks.size ()) - 1)
+        return abs (anBreaks[nBreakLast + 1]) - 1;
+      return nLength;
+    }
 
   // if there is no break inside the line or the given subline is the last
   // one in this line...
@@ -2781,7 +3262,19 @@ int CCrystalTextView::SubLineHomeToCharPos(int nLineIndex, int nSubLineOffset)
   vector<int> anBreaks(nLength + 1);
   int nBreaks = 0;
 
-  WrapLineCached(nLineIndex, GetScreenChars(), &anBreaks[0], nBreaks);
+  WrapLineCached(nLineIndex, GetScreenChars(), &anBreaks, nBreaks);
+
+  if (GetTextLayoutMode() == TEXTLAYOUT_TABLE_WORDWRAP)
+    {
+      for (int i = 0, j = 1; i < static_cast<int>(anBreaks.size ()); ++i, ++j)
+        {
+          if (anBreaks[i] < 0)
+            j = 0;
+          if (j == nSubLineOffset)
+            return abs (anBreaks[i]);
+        }
+      return 0;
+    }
 
   // if there is no break inside the line...
   if (nBreaks == 0)
@@ -2820,6 +3313,18 @@ GetMaxLineLength (int nTopLine, int nLines)
   return nMaxLineLength;
 }
 
+bool CCrystalTextView::
+CoverLength(int nTopLine, int nLines, int min_length)
+{
+  const int nLineCount = (std::min)(nTopLine + nLines, GetLineCount ());
+  for (int I = nTopLine; I != nLineCount; I++)
+    {
+      if (GetLineActualLength (I) >= min_length)
+        return true;
+    }
+  return false;
+}
+
 CCrystalTextView *CCrystalTextView::
 GetSiblingView (int nRow, int nCol)
 {
@@ -2830,14 +3335,14 @@ GetSiblingView (int nRow, int nCol)
                  ::GetDlgItem (pSplitter->m_hWnd, pSplitter->IdFromRowCol (nRow, nCol)));
   if (pWnd == nullptr || !pWnd->IsKindOf (RUNTIME_CLASS (CCrystalTextView)))
     return nullptr;
-  return (CCrystalTextView *) pWnd;
+  return static_cast<CCrystalTextView *>(pWnd);
 }
 
 void CCrystalTextView::
 GoToLine (int nLine, bool bRelative)
 {
   int nLines = m_pTextBuffer->GetLineCount () - 1;
-  CPoint ptCursorPos = GetCursorPos ();
+  CEPoint ptCursorPos = GetCursorPos ();
   if (bRelative)
     {
       nLine += ptCursorPos.y;
@@ -2877,9 +3382,9 @@ void CCrystalTextView::
 OnInitialUpdate ()
 {
   CView::OnInitialUpdate ();
-  CString sDoc = GetDocument ()->GetPathName (), sExt = GetExt (sDoc);
-  if (!sExt.IsEmpty())
-      SetTextType (sExt);
+  std::basic_string<tchar_t> sDoc = GetDocument ()->GetPathName (), sExt = GetExt (sDoc);
+  if (!sExt.empty ())
+    SetTextType (sExt.c_str ());
   AttachToBuffer (nullptr);
 
   CSplitterWnd *pSplitter = GetParentSplitter (this, false);
@@ -2912,30 +3417,6 @@ OnInitialUpdate ()
         }
     }
   SetFont (m_LogFont);
-  if (m_bRememberLastPos && !sDoc.IsEmpty ())
-    {
-      DWORD dwLastPos[3];
-      CString sKey = REG_EDITPAD;
-      sKey += _T ("\\Remembered");
-      CReg reg;
-      if (reg.Open (HKEY_CURRENT_USER, sKey, KEY_READ) &&
-        reg.LoadBinary (sDoc, (LPBYTE) dwLastPos, sizeof (dwLastPos)))
-        {
-          CPoint ptCursorPos;
-          ptCursorPos.x = dwLastPos[1];
-          ptCursorPos.y = dwLastPos[2];
-          if (IsValidTextPosY (ptCursorPos))
-            {
-              if (!IsValidTextPosX (ptCursorPos))
-                ptCursorPos.x = 0;
-              ASSERT_VALIDTEXTPOS (ptCursorPos);
-              SetCursorPos (ptCursorPos);
-              SetSelection (ptCursorPos, ptCursorPos);
-              SetAnchor (ptCursorPos);
-              EnsureVisible (ptCursorPos);
-            }
-        }
-    }
 }
 
 /////////////////////////////////////////////////////////////////////////////
@@ -3010,23 +3491,12 @@ PrintFooter (CDC * pdc, int nPageNum)
 void CCrystalTextView::
 GetPrintMargins (long & nLeft, long & nTop, long & nRight, long & nBottom)
 {
-  nLeft = DEFAULT_PRINT_MARGIN;
-  nTop = DEFAULT_PRINT_MARGIN;
-  nRight = DEFAULT_PRINT_MARGIN;
-  nBottom = DEFAULT_PRINT_MARGIN;
-  CReg reg;
-  if (reg.Open (HKEY_CURRENT_USER, REG_EDITPAD, KEY_READ))
-    {
-      DWORD dwTemp;
-      if (reg.LoadNumber (_T ("PageLeft"), &dwTemp))
-        nLeft = dwTemp;
-      if (reg.LoadNumber (_T ("PageRight"), &dwTemp))
-        nRight = dwTemp;
-      if (reg.LoadNumber (_T ("PageTop"), &dwTemp))
-        nTop = dwTemp;
-      if (reg.LoadNumber (_T ("PageBottom"), &dwTemp))
-        nBottom = dwTemp;
-    }
+  CWinApp *pApp = AfxGetApp ();
+  ASSERT (pApp != nullptr);
+  nLeft   = pApp->GetProfileInt(EDITPAD_SECTION, _T("PageLeft"),   DEFAULT_PRINT_MARGIN);
+  nRight  = pApp->GetProfileInt(EDITPAD_SECTION, _T("PageRight"),  DEFAULT_PRINT_MARGIN);
+  nTop    = pApp->GetProfileInt(EDITPAD_SECTION, _T("PageTop"),    DEFAULT_PRINT_MARGIN);
+  nBottom = pApp->GetProfileInt(EDITPAD_SECTION, _T("PageBottom"), DEFAULT_PRINT_MARGIN);
 }
 
 void CCrystalTextView::
@@ -3039,8 +3509,6 @@ RecalcPageLayouts (CDC * pdc, CPrintInfo * pInfo)
 
   m_rcPrintArea = m_ptPageArea;
   CSize szTopLeft, szBottomRight;
-  CWinApp *pApp = AfxGetApp ();
-  ASSERT (pApp != nullptr);
   GetPrintMargins (szTopLeft.cx, szTopLeft.cy, szBottomRight.cx, szBottomRight.cy);
   pdc->HIMETRICtoLP (&szTopLeft);
   pdc->HIMETRICtoLP (&szBottomRight);
@@ -3063,15 +3531,15 @@ void CCrystalTextView::
 OnBeginPrinting (CDC * pdc, CPrintInfo * pInfo)
 {
   ASSERT (m_pPrintFont == nullptr);
-  CFont *pDisplayFont = GetFont ();
-
-  LOGFONT lf;
+  LOGFONT lf = m_lfBaseFont;
   CDC *pDisplayDC = GetDC ();
-  pDisplayFont->GetLogFont (&lf);
   lf.lfHeight = MulDiv (lf.lfHeight, pdc->GetDeviceCaps (LOGPIXELSY), pDisplayDC->GetDeviceCaps (LOGPIXELSY));
   lf.lfWidth = MulDiv (lf.lfWidth, pdc->GetDeviceCaps (LOGPIXELSX), pDisplayDC->GetDeviceCaps (LOGPIXELSX));
   ReleaseDC (pDisplayDC);
 
+  m_pCrystalRendererSaved = m_pCrystalRenderer.release();
+  m_pCrystalRenderer.reset(new CCrystalRendererGDI());
+
   m_pPrintFont = new CFont;
   if (!m_pPrintFont->CreateFontIndirect (&lf))
     {
@@ -3091,6 +3559,11 @@ OnBeginPrinting (CDC * pdc, CPrintInfo * pInfo)
 void CCrystalTextView::
 OnEndPrinting (CDC * pdc, CPrintInfo * pInfo)
 {
+  if (m_pCrystalRendererSaved)
+    {
+      m_pCrystalRenderer.reset(m_pCrystalRendererSaved);
+      m_pCrystalRendererSaved = nullptr;
+    }
   if (m_pPrintFont != nullptr)
     {
       delete m_pPrintFont;
@@ -3107,8 +3580,8 @@ OnPrint (CDC * pdc, CPrintInfo * pInfo)
 {
   pdc->SelectObject (m_pPrintFont);
 
-  const COLORREF defaultLineColor = RGB(0,0,0);
-  const COLORREF defaultBgColor = RGB(255,255,255);
+  const CEColor defaultLineColor{ 0,0,0 };
+  const CEColor defaultBgColor{ 255,255,255 };
 
   RecalcPageLayouts (pdc, pInfo);
 
@@ -3128,8 +3601,11 @@ OnPrint (CDC * pdc, CPrintInfo * pInfo)
   TRACE (_T ("Printing page %d of %d, lines %d - %d\n"), 
         pInfo->m_nCurPage, m_nPrintPages, nTopLine, nEndLine);
 
-  pdc->SetTextColor(defaultLineColor);
-  pdc->SetBkColor(defaultBgColor);
+  m_pCrystalRenderer->BindDC(*pdc, m_rcPrintArea);
+  m_pCrystalRenderer->BeginDraw();
+
+  m_pCrystalRenderer->SetTextColor(defaultLineColor);
+  m_pCrystalRenderer->SetBkColor(defaultBgColor);
 
   if (m_bPrintHeader)
     {
@@ -3172,9 +3648,9 @@ OnPrint (CDC * pdc, CPrintInfo * pInfo)
 
   int nSubLineOffset = GetSubLineIndex (nTopLine) - nTopSubLine;
   if( nSubLineOffset < 0 )
-  {
-    rcLine.OffsetRect( 0, nSubLineOffset * nLineHeight );
-  }
+    {
+      rcLine.OffsetRect( 0, nSubLineOffset * nLineHeight );
+    }
 
   int nLineCount = GetLineCount();
   int nCurrentLine;
@@ -3185,16 +3661,18 @@ OnPrint (CDC * pdc, CPrintInfo * pInfo)
 
       if (nCurrentLine < nLineCount && GetLineVisible (nCurrentLine))
         {
-          DrawMargin (pdc, rcMargin, nCurrentLine, nCurrentLine + 1);
-          DrawSingleLine (pdc, rcLine, nCurrentLine);
+          DrawMargin (rcMargin, nCurrentLine, nCurrentLine + 1);
+          DrawSingleLine (rcLine, nCurrentLine);
           if (nCurrentLine+1 < nLineCount && !GetLineVisible (nCurrentLine + 1))
-            DrawBoundaryLine (pdc, rcMargin.left, rcLine.right, rcMargin.bottom-1);
+            m_pCrystalRenderer->DrawBoundaryLine (rcMargin.left, rcLine.right, rcMargin.bottom-1);
         }
 
       rcLine.top = rcLine.bottom;
       rcMargin.top = rcLine.bottom;
     }
 
+  m_pCrystalRenderer->EndDraw();
+
   pdc->SelectClipRgn (nullptr);
 }
 
@@ -3225,7 +3703,7 @@ int CCrystalTextView::GetSubLineCount()
 
   // calculate number of sub lines
   if (nLineCount <= 0)
-      return 0;
+    return 0;
   return CCrystalTextView::GetSubLineIndex( nLineCount - 1 ) + GetSubLines( nLineCount - 1 );
 }
 
@@ -3252,16 +3730,21 @@ int CCrystalTextView::GetSubLineIndex( int nLineIndex )
   else
     {
       m_nLastLineIndexCalculatedSubLineIndex = 0;
-      m_panSubLineIndexCache->SetAtGrow( 0, 0 );
+      m_panSubLineIndexCache->resize (1);
+      (*m_panSubLineIndexCache)[0] = 0;
     }
 
 // TODO: Rethink this, it is very time consuming
   for( int i = m_nLastLineIndexCalculatedSubLineIndex; i < nLineIndex; i++ )
     {
-      m_panSubLineIndexCache->SetAtGrow( i, nSubLineCount);
+      if (m_panSubLineIndexCache->size () >= i)
+        m_panSubLineIndexCache->resize (i + 1);
+      (*m_panSubLineIndexCache)[i] = nSubLineCount;
       nSubLineCount+= GetSubLines( i );
     }
-  m_panSubLineIndexCache->SetAtGrow( nLineIndex, nSubLineCount);
+  if (m_panSubLineIndexCache->size () >= nLineIndex)
+    m_panSubLineIndexCache->resize (nLineIndex + 1);
+  (*m_panSubLineIndexCache)[nLineIndex] = nSubLineCount;
   m_nLastLineIndexCalculatedSubLineIndex = nLineIndex;
 
   return nSubLineCount;
@@ -3336,7 +3819,7 @@ GetViewableLineLength (int nLineIndex) const
     return GetLineLength(nLineIndex);
 }
 
-LPCTSTR CCrystalTextView::
+const tchar_t* CCrystalTextView::
 GetLineChars (int nLineIndex) const
 {
   if (m_pTextBuffer == nullptr)
@@ -3372,7 +3855,7 @@ ReAttachToBuffer (CCrystalTextBuffer * pBuf /*= nullptr*/ )
     pVertScrollBarCtrl->EnableScrollBar (GetScreenLines () >= GetLineCount ()?
                                          ESB_DISABLE_BOTH : ESB_ENABLE_BOTH);
   //  Update vertical scrollbar only
-  RecalcVertScrollBar ();
+  InvalidateVertScrollBar ();
 }
 
 /** 
@@ -3401,12 +3884,12 @@ AttachToBuffer (CCrystalTextBuffer * pBuf /*= nullptr*/ )
                                          ESB_DISABLE_BOTH : ESB_ENABLE_BOTH);
   CScrollBar *pHorzScrollBarCtrl = GetScrollBarCtrl (SB_HORZ);
   if (pHorzScrollBarCtrl != nullptr)
-    pHorzScrollBarCtrl->EnableScrollBar (GetScreenChars () >= GetMaxLineLength (m_nTopLine, GetScreenLines())?
-                                         ESB_DISABLE_BOTH : ESB_ENABLE_BOTH);
+      pHorzScrollBarCtrl->EnableScrollBar(CoverLength(m_nTopLine, GetScreenLines(), GetScreenChars()) ?
+          ESB_DISABLE_BOTH : ESB_ENABLE_BOTH);
 
   //  Update scrollbars
-  RecalcVertScrollBar ();
-  RecalcHorzScrollBar ();
+  InvalidateVertScrollBar ();
+  InvalidateHorzScrollBar ();
 }
 
 void CCrystalTextView::
@@ -3428,7 +3911,7 @@ GetScreenLines ()
     {
       CRect rect;
       GetClientRect (&rect);
-      m_nScreenLines = rect.Height () / GetLineHeight ();
+      m_nScreenLines = (rect.Height () - GetTopMarginHeight ()) / GetLineHeight ();
     }
   return m_nScreenLines;
 }
@@ -3449,7 +3932,7 @@ GetBold (int nColorIndex)
 {
   if (m_pColors  != nullptr)
     {
-      nColorIndex &= ~COLORINDEX_APPLYFORCE;
+      nColorIndex &= ~COLORINDEX_MASK;
       return m_pColors->GetBold(nColorIndex);
     }
   else
@@ -3471,20 +3954,11 @@ GetScreenChars ()
 void CCrystalTextView::
 OnDestroy ()
 {
-  GetFont ()->GetLogFont (&m_lfBaseFont);
   DetachFromBuffer ();
   m_hAccel = nullptr;
 
   CView::OnDestroy ();
 
-  for (int I = 0; I < 4; I++)
-    {
-      if (m_apFonts[I] != nullptr)
-        {
-          delete m_apFonts[I];
-          m_apFonts[I] = nullptr;
-        }
-    }
   if (m_pCacheBitmap != nullptr)
     {
       delete m_pCacheBitmap;
@@ -3506,8 +3980,8 @@ OnSize (UINT nType, int cx, int cy)
 
   //BEGIN SW
   // get char position of top left visible character with old cached word wrap
-  CPoint       topPos;
-  SubLineCursorPosToTextPos( CPoint( 0, m_nTopSubLine ), topPos );
+  CEPoint      topPos;
+  SubLineCursorPosToTextPos( CEPoint( 0, m_nTopSubLine ), topPos );
   //END SW
 
   //BEGIN SW
@@ -3515,7 +3989,7 @@ OnSize (UINT nType, int cx, int cy)
   InvalidateScreenRect(false);
 
   // compute new top sub line
-  CPoint       topSubLine;
+  CEPoint      topSubLine;
   CharPosToPoint( topPos.y, topPos.x, topSubLine );
   m_nTopSubLine = GetSubLineIndex(topPos.y) + topSubLine.y;
 
@@ -3525,8 +3999,8 @@ OnSize (UINT nType, int cx, int cy)
   UpdateCaret();
   //END SW
 
-  RecalcVertScrollBar (false, false);
-  RecalcHorzScrollBar (false, false);
+  InvalidateVertScrollBar ();
+  InvalidateHorzScrollBar ();
 }
 
 void CCrystalTextView::
@@ -3603,8 +4077,7 @@ OnUpdateSibling (CCrystalTextView * pUpdateSource, bool bHorz)
 void CCrystalTextView::
 RecalcVertScrollBar (bool bPositionOnly /*= false*/, bool bRedraw /*= true */)
 {
-  SCROLLINFO si = {0};
-  si.cbSize = sizeof (si);
+  SCROLLINFO si{ sizeof (si) };
   if (bPositionOnly)
     {
       si.fMask = SIF_POS;
@@ -3634,8 +4107,7 @@ OnVScroll (UINT nSBCode, UINT nPos, CScrollBar * pScrollBar)
   CView::OnVScroll (nSBCode, nPos, pScrollBar);
 
   // Note we cannot use nPos because of its 16-bit nature
-  SCROLLINFO si = {0};
-  si.cbSize = sizeof (si);
+  SCROLLINFO si{ sizeof(si) };
   si.fMask = SIF_PAGE | SIF_POS | SIF_RANGE | SIF_TRACKPOS;
   VERIFY (GetScrollInfo (SB_VERT, &si));
 
@@ -3688,31 +4160,38 @@ OnVScroll (UINT nSBCode, UINT nPos, CScrollBar * pScrollBar)
       break;
     }
   ScrollToSubLine(nCurPos, bDisableSmooth);
+  UpdateCaret ();
 }
 
 void CCrystalTextView::
 RecalcHorzScrollBar (bool bPositionOnly /*= false*/, bool bRedraw /*= true */)
 {
-  SCROLLINFO si = {0};
-  si.cbSize = sizeof (si);
+  SCROLLINFO si{ sizeof(si) };
 
   const int nScreenChars = GetScreenChars();
+  const TextLayoutMode layoutMode = GetTextLayoutMode ();
   
-  if (m_bWordWrap)
+  if (layoutMode == TEXTLAYOUT_WORDWRAP)
     {
-       if (m_nOffsetChar > nScreenChars)
-         {
-           m_nOffsetChar = 0;
-           UpdateCaret ();
-         }
+      if (m_nOffsetChar > nScreenChars)
+        {
+          m_nOffsetChar = 0;
+          UpdateCaret ();
+        }
 
       // Disable horizontal scroll bar
       si.fMask = SIF_DISABLENOSCROLL | SIF_PAGE | SIF_POS | SIF_RANGE;
+      si.nPage = 1;
       SetScrollInfo (SB_HORZ, &si);
       return;
     }
 
-  const int nMaxLineLen = GetMaxLineLength (m_nTopLine, GetScreenLines());
+  int nMaxLineLen = GetMaxLineLength (m_nTopLine, GetScreenLines());
+  if (layoutMode == TEXTLAYOUT_TABLE_NOWORDWRAP || layoutMode == TEXTLAYOUT_TABLE_WORDWRAP)
+    {
+      auto widths = m_pTextBuffer->GetColumnWidths ();
+      nMaxLineLen = (std::max)(nMaxLineLen, std::accumulate (widths.begin (), widths.end (), 0));
+    }
 
   if (bPositionOnly)
     {
@@ -3745,8 +4224,7 @@ OnHScroll (UINT nSBCode, UINT nPos, CScrollBar * pScrollBar)
   //CView::OnHScroll (nSBCode, nPos, pScrollBar);
 
   //  Again, we cannot use nPos because it's 16-bit
-  SCROLLINFO si = {0};
-  si.cbSize = sizeof (si);
+  SCROLLINFO si { sizeof(si) };
   si.fMask = SIF_PAGE | SIF_POS | SIF_RANGE | SIF_TRACKPOS;
   VERIFY (GetScrollInfo (SB_HORZ, &si));
 
@@ -3811,13 +4289,25 @@ OnSetCursor (CWnd * pWnd, UINT nHitTest, UINT message)
       CPoint pt;
       ::GetCursorPos (&pt);
       ScreenToClient (&pt);
-      if (pt.x < GetMarginWidth ())
+      if (pt.y < GetTopMarginHeight ())
+        {
+          if (m_pTextBuffer->GetTableEditing ())
+            {
+              const int nColumnResizing = ClientToColumnResizing (pt.x);
+              ::SetCursor (::LoadCursor (nullptr, nColumnResizing >= 0 ? IDC_SIZEWE : IDC_ARROW));
+            }
+          else
+            {
+              ::SetCursor (::LoadCursor (nullptr, IDC_ARROW));
+            }
+        }
+      else if (pt.x < GetMarginWidth ())
         {
           ::SetCursor (::LoadCursor (AfxGetInstanceHandle (), MAKEINTRESOURCE (IDR_MARGIN_CURSOR)));
         }
       else
         {
-          CPoint ptText = ClientToText (pt);
+          CEPoint ptText = ClientToText (pt);
           PrepareSelBounds ();
           if (IsInsideSelBlock (ptText))
             {
@@ -3835,21 +4325,32 @@ OnSetCursor (CWnd * pWnd, UINT nHitTest, UINT message)
   return CView::OnSetCursor (pWnd, nHitTest, message);
 }
 
+int CCrystalTextView::
+ClientToIdealTextPos (int x)
+{
+  int nPos;
+  if (x > GetMarginWidth ())
+    nPos = m_nOffsetChar + (x - GetMarginWidth ()) / GetCharWidth ();
+  else
+    nPos = 0;
+  return nPos;
+}
+
 /** 
  * @brief Converts client area point to text position.
  * @param [in] point Client area point.
  * @return Text position (line index, char index in line).
  * @note For gray selection area char index is 0.
  */
-CPoint CCrystalTextView::
+CEPoint CCrystalTextView::
 ClientToText (const CPoint & point)
 {
   //BEGIN SW
   const int nSubLineCount = GetSubLineCount();
   const int nLineCount = GetLineCount();
 
-  CPoint pt;
-  pt.y = m_nTopSubLine + point.y / GetLineHeight();
+  CEPoint pt;
+  pt.y = m_nTopSubLine + (point.y - GetTopMarginHeight ()) / GetLineHeight();
   if (pt.y >= nSubLineCount)
     pt.y = nSubLineCount - 1;
   if (pt.y < 0)
@@ -3857,12 +4358,11 @@ ClientToText (const CPoint & point)
 
   int nLine;
   int nSubLineOffset;
-  int nOffsetChar = m_nOffsetChar;
 
   GetLineBySubLine( pt.y, nLine, nSubLineOffset );
   pt.y = nLine;
 
-  LPCTSTR pszLine = nullptr;
+  const tchar_t* pszLine = nullptr;
   int nLength = 0;
   vector<int> anBreaks(1);
   int nBreaks = 0;
@@ -3872,55 +4372,137 @@ ClientToText (const CPoint & point)
       nLength = GetLineLength( pt.y );
       anBreaks.resize(nLength + 1);
       pszLine = GetLineChars(pt.y);
-      WrapLineCached( pt.y, GetScreenChars(), &anBreaks[0], nBreaks );
+      WrapLineCached( pt.y, GetScreenChars(), &anBreaks, nBreaks );
 
-      if (nSubLineOffset > 0)
-        {
-          if (nSubLineOffset < nBreaks)
-            nOffsetChar = anBreaks[nSubLineOffset - 1];
-          else if (nBreaks > 0)
-            nOffsetChar = anBreaks[nBreaks - 1];
-        }
-      if (nBreaks > nSubLineOffset)
+      if (nBreaks > nSubLineOffset && GetTextLayoutMode () == TEXTLAYOUT_WORDWRAP)
         nLength = anBreaks[nSubLineOffset] - 1;
     }
 
-  int nPos = 0;
   // Char index for margin area is 0
-  if (point.x > GetMarginWidth())
-    nPos = nOffsetChar + (point.x - GetMarginWidth()) / GetCharWidth();
-  if (nPos < 0)
-    nPos = 0;
-
-  int nIndex = 0, nPrevIndex = 0;
+  int nPos = ClientToIdealTextPos (point.x);
+  int nIndex = 0;
   int nCurPos = 0;
   int n = 0;
   int i = 0;
   const int nTabSize = GetTabSize();
 
-  m_iterChar.setText(reinterpret_cast<const UChar *>(pszLine), nLength);
-  while (nIndex < nLength)
+  auto pIterChar = ICUBreakIterator::getCharacterBreakIterator(pszLine, nLength);
+  switch (GetTextLayoutMode ())
     {
-      if (nBreaks && nIndex == anBreaks[i])
+      case TEXTLAYOUT_TABLE_NOWORDWRAP:
         {
-          n = nIndex;
-          i++;
+          int nColumnCount = m_pTextBuffer->GetColumnCount (nLine);
+          int nColumnTotalWidth = 0;
+          int nColumn = 0;
+          bool bInQuote = false;
+          const int sep = m_pTextBuffer->GetFieldDelimiter ();
+          const int quote = m_pTextBuffer->GetFieldEnclosure ();
+          while (nIndex < nLength)
+            {
+              int nOffset;
+              if (!bInQuote && pszLine[nIndex] == sep)
+                {
+                  nColumnTotalWidth += m_pTextBuffer->GetColumnWidth (nColumn++);
+                  nOffset = nColumnTotalWidth - nCurPos;
+                }
+              else
+                {
+                  if (pszLine[nIndex] == quote)
+                    bInQuote = !bInQuote;
+                  if (pszLine[nIndex] == '\t')
+                    nOffset = 1;
+                  else
+                    nOffset = GetCharCellCountFromChar (pszLine + nIndex);
+                  if (nColumn < nColumnCount && nCurPos + nOffset > nColumnTotalWidth + m_pTextBuffer->GetColumnWidth (nColumn))
+                    nOffset = nColumnTotalWidth + m_pTextBuffer->GetColumnWidth (nColumn) - nCurPos;
+                }
+              n += nOffset;
+              nCurPos += nOffset;
+
+              if (n > nPos && i == nSubLineOffset)
+                break;
+
+              nIndex = pIterChar->next ();
+            }
         }
+        break;
+      case TEXTLAYOUT_TABLE_WORDWRAP:
+        {
+          int j = 0;
+          int nColumn = 0;
+          int nColumnSumWidth = 0;
+          int nColumnCurPoint = INT_MAX;
+          int nPrevIndex = 0;
+          if (nPos < m_pTextBuffer->GetColumnWidth (0))
+            nColumnCurPoint = 0;
+          while (nIndex < nLength)
+            {
+              if (i < static_cast<int>(anBreaks.size()) && nIndex == abs(anBreaks[i]))
+                {
+                  if (anBreaks[i++] < 0)
+                    {
+                      j = 0;
+                      nColumnSumWidth += m_pTextBuffer->GetColumnWidth (nColumn++);
+                      n = nColumnSumWidth;
+                      if (nColumnSumWidth <= nPos && nPos < nColumnSumWidth + m_pTextBuffer->GetColumnWidth (nColumn))
+                        nColumnCurPoint = nColumn;
+                    }
+                  else
+                    {
+                      n = nColumnSumWidth;
+                      j++;
+                    }
+                }
+      
+              int nOffset;
+              if (pszLine[nIndex] == '\t')
+                nOffset = 1;
+              else
+                nOffset = GetCharCellCountFromChar(pszLine + nIndex);
+              n += nOffset;
+              nCurPos += nOffset;
 
-      int nOffset;
-      if (pszLine[nIndex] == '\t')
-        nOffset = nTabSize - nCurPos % nTabSize;
-      else
-        nOffset = GetCharCellCountFromChar(pszLine + nIndex);
-      n += nOffset;
-      nCurPos += nOffset;
+              if (n > nPos && j == nSubLineOffset)
+                break;
+              else if( nColumnCurPoint < nColumn && nPrevIndex != 0)
+                {
+                  nIndex = nPrevIndex;
+                  break;
+                }
+              else if ( j == nSubLineOffset)
+                nPrevIndex = nIndex;
 
-      if (n > nPos && i == nSubLineOffset)
+              nIndex = pIterChar->next();
+            }
+          if (nIndex == nLength && j != nSubLineOffset)
+            nIndex = nPrevIndex;
+        }
         break;
+      default:
+        {
+          while (nIndex < nLength)
+            {
+              if (nBreaks && i < static_cast<int>(anBreaks.size ()) && nIndex == anBreaks[i])
+                {
+                  n = 0;
+                  i++;
+                }
+
+              int nOffset;
+              if (pszLine[nIndex] == '\t')
+                nOffset = nTabSize - nCurPos % nTabSize;
+              else
+                nOffset = GetCharCellCountFromChar(pszLine + nIndex);
+              n += nOffset;
+              nCurPos += nOffset;
 
-      nPrevIndex = nIndex;
+              if (n > nPos && i == nSubLineOffset)
+                break;
 
-      nIndex = m_iterChar.next();
+              nIndex = pIterChar->next();
+            }
+        }
+        break;
     }
 
   ASSERT(nIndex >= 0 && nIndex <= nLength);
@@ -3928,9 +4510,38 @@ ClientToText (const CPoint & point)
   return pt;
 }
 
+int CCrystalTextView::
+ClientToColumn (int x)
+{
+  CRect rcClient;
+  GetClientRect (&rcClient);
+  int nCharWidth = GetCharWidth ();
+  int nMarginWidth = GetMarginWidth ();
+  for (int nColumn = 0, columnleft = nMarginWidth - m_nOffsetChar * nCharWidth;
+      columnleft < rcClient.Width ();
+      columnleft += m_pTextBuffer->GetColumnWidth (nColumn++) * nCharWidth)
+    {
+      if (columnleft <= x && x < columnleft + m_pTextBuffer->GetColumnWidth (nColumn) * nCharWidth)
+        return nColumn;
+    }
+  return -1;
+}
+
+int CCrystalTextView::
+ClientToColumnResizing (int x)
+{
+  const int nColumn = ClientToColumn (x);
+  const int nColumnL = ClientToColumn (x - 4);
+  const int nColumnR = ClientToColumn (x + 4);
+  if (nColumn != nColumnL || nColumn != nColumnR)
+    {
+      return (nColumn != nColumnL) ? nColumnL : nColumn;
+    }
+  return -1;
+}
 #ifdef _DEBUG
 void CCrystalTextView::
-AssertValidTextPos (const CPoint & point)
+AssertValidTextPos (const CEPoint & point)
 {
   if (GetLineCount () > 0)
     {
@@ -3942,43 +4553,44 @@ AssertValidTextPos (const CPoint & point)
 #endif
 
 bool CCrystalTextView::
-IsValidTextPos (const CPoint &point)
+IsValidTextPos (const CEPoint &point)
 {
   return GetLineCount () > 0 && m_nTopLine >= 0 && m_nOffsetChar >= 0 &&
     point.y >= 0 && point.y < GetLineCount () && point.x >= 0 && point.x <= GetLineLength (point.y);
 }
 
 bool CCrystalTextView::
-IsValidTextPosX (const CPoint &point)
+IsValidTextPosX (const CEPoint &point)
 {
   return GetLineCount () > 0 && m_nTopLine >= 0 && m_nOffsetChar >= 0 &&
     point.y >= 0 && point.y < GetLineCount () && point.x >= 0 && point.x <= GetLineLength (point.y);
 }
 
 bool CCrystalTextView::
-IsValidTextPosY (const CPoint &point)
+IsValidTextPosY (const CEPoint &point)
 {
   return GetLineCount () > 0 && m_nTopLine >= 0 && m_nOffsetChar >= 0 &&
     point.y >= 0 && point.y < GetLineCount ();
 }
 
 CPoint CCrystalTextView::
-TextToClient (const CPoint & point)
+TextToClient (const CEPoint & point)
 {
   ASSERT_VALIDTEXTPOS (point);
-  LPCTSTR pszLine = GetLineChars (point.y);
+  const tchar_t* pszLine = GetLineChars (point.y);
 
+  int nColumnIndex = 0;
   CPoint pt;
   //BEGIN SW
-  CPoint       charPoint;
-  int                  nSubLineStart = CharPosToPoint( point.y, point.x, charPoint );
+  CEPoint      charPoint;
+  int nSubLineStart = CharPosToPoint( point.y, point.x, charPoint, &nColumnIndex );
   charPoint.y+= GetSubLineIndex( point.y );
 
   // compute y-position
-  pt.y = (charPoint.y - m_nTopSubLine) * GetLineHeight();
+  pt.y = (charPoint.y - m_nTopSubLine) * GetLineHeight() + GetTopMarginHeight ();
 
   // if pt.x is null, we know the result
-  if( charPoint.x == 0 )
+  if( charPoint.x == 0 && nColumnIndex == 0)
     {
       pt.x = GetMarginWidth();
       return pt;
@@ -3992,30 +4604,100 @@ TextToClient (const CPoint & point)
   //END SW
   pt.x = 0;
   int nTabSize = GetTabSize ();
-  m_iterChar.setText(reinterpret_cast<const UChar *>(pszLine), point.x);
-  for (int nIndex = 0; nIndex < point.x; nIndex = m_iterChar.next())
+  auto pIterChar = ICUBreakIterator::getCharacterBreakIterator(pszLine, point.x);
+  switch (GetTextLayoutMode ())
     {
-      //BEGIN SW
-      if( nIndex == nSubLineStart )
-        nPreOffset = pt.x;
-      //END SW
-      if (pszLine[nIndex] == _T ('\t'))
-        pt.x += (nTabSize - pt.x % nTabSize);
-      else
-        pt.x += GetCharCellCountFromChar(pszLine + nIndex);
+      case TEXTLAYOUT_TABLE_NOWORDWRAP:
+        {
+          int nColumnCount = m_pTextBuffer->GetColumnCount (point.y);
+          int nColumnTotalWidth = 0;
+          int nColumn = 0;
+          bool bInQuote = false;
+          const int sep = m_pTextBuffer->GetFieldDelimiter ();
+          const int quote = m_pTextBuffer->GetFieldEnclosure ();
+          for (int nIndex = 0; nIndex < point.x; nIndex = pIterChar->next())
+            {
+              if (!bInQuote && pszLine[nIndex] == sep)
+                {
+                  nColumnTotalWidth += m_pTextBuffer->GetColumnWidth (nColumn++);
+                  pt.x = nColumnTotalWidth;
+                }
+              else
+                {
+                  if (pszLine[nIndex] == quote)
+                    bInQuote = !bInQuote;
+                  if (pszLine[nIndex] == _T ('\t'))
+                    pt.x ++;
+                  else
+                    pt.x += GetCharCellCountFromChar(pszLine + nIndex);
+                  if (nColumn < nColumnCount && pt.x > nColumnTotalWidth + m_pTextBuffer->GetColumnWidth (nColumn))
+                    pt.x = nColumnTotalWidth + m_pTextBuffer->GetColumnWidth (nColumn);
+                }
+            }
+          pt.x = (pt.x - m_nOffsetChar) * GetCharWidth () + GetMarginWidth ();
+          return pt;
+        }
+        break;
+      case TEXTLAYOUT_TABLE_WORDWRAP:
+        {
+          pt.x = 0;
+          for (int i = 0; i < nColumnIndex; ++i)
+              pt.x += m_pTextBuffer->GetColumnWidth (i);
+          for (int nIndex = 0; nIndex < point.x; nIndex = pIterChar->next())
+            {
+              if( nIndex >= nSubLineStart )
+                {
+                  if (pszLine[nIndex] == '\t')
+                    pt.x ++;
+                  else
+                    pt.x += GetCharCellCountFromChar (pszLine + nIndex);
+                }
+            }
+          pt.x = (pt.x - m_nOffsetChar) * GetCharWidth () + GetMarginWidth ();
+          return pt;
+        }
+        break;
+      default:
+        {
+          for (int nIndex = 0; nIndex < point.x; nIndex = pIterChar->next())
+            {
+              //BEGIN SW
+              if( nIndex == nSubLineStart )
+                nPreOffset = pt.x;
+              //END SW
+              if (pszLine[nIndex] == _T ('\t'))
+                pt.x += (nTabSize - pt.x % nTabSize);
+              else
+                pt.x += GetCharCellCountFromChar(pszLine + nIndex);
+            }
+          //BEGIN SW
+          pt.x-= nPreOffset;
+          //END SW
+      
+          pt.x = (pt.x - m_nOffsetChar) * GetCharWidth () + GetMarginWidth ();
+          return pt;
+        }
     }
-  //BEGIN SW
-  pt.x-= nPreOffset;
-  //END SW
+}
 
-  pt.x = (pt.x - m_nOffsetChar) * GetCharWidth () + GetMarginWidth ();
-  return pt;
+int CCrystalTextView::
+ColumnToClient (int nColumn)
+{
+  CRect rcClient;
+  GetClientRect (&rcClient);
+  int nCharWidth = GetCharWidth ();
+  int columnleft = GetMarginWidth () - m_nOffsetChar * nCharWidth;
+  for (int nColumn2 = 0; nColumn2 != nColumn && columnleft < rcClient.Width ();
+      columnleft += m_pTextBuffer->GetColumnWidth (nColumn2++) * nCharWidth)
+      ;
+  return columnleft;
 }
 
 void CCrystalTextView::
 InvalidateLines (int nLine1, int nLine2, bool bInvalidateMargin /*= false*/ )
 {
   bInvalidateMargin = true;
+  const int nTopMarginHeight = GetTopMarginHeight ();
   const int nLineHeight = GetLineHeight();
   if (nLine2 == -1)
     {
@@ -4024,7 +4706,7 @@ InvalidateLines (int nLine1, int nLine2, bool bInvalidateMargin /*= false*/ )
       if (!bInvalidateMargin)
         rcInvalid.left += GetMarginWidth ();
       //BEGIN SW
-      rcInvalid.top = (GetSubLineIndex( nLine1 ) - m_nTopSubLine) * nLineHeight;
+      rcInvalid.top = (GetSubLineIndex( nLine1 ) - m_nTopSubLine) * nLineHeight + nTopMarginHeight;
       /*ORIGINAL
       rcInvalid.top = (nLine1 - m_nTopLine) * GetLineHeight();
       */
@@ -4044,8 +4726,8 @@ InvalidateLines (int nLine1, int nLine2, bool bInvalidateMargin /*= false*/ )
       if (!bInvalidateMargin)
         rcInvalid.left += GetMarginWidth ();
       //BEGIN SW
-      rcInvalid.top = (GetSubLineIndex( nLine1 ) - m_nTopSubLine) * nLineHeight;
-      rcInvalid.bottom = (GetSubLineIndex( nLine2 ) - m_nTopSubLine + GetSubLines( nLine2 )) * nLineHeight;
+      rcInvalid.top = (GetSubLineIndex( nLine1 ) - m_nTopSubLine) * nLineHeight + nTopMarginHeight;
+      rcInvalid.bottom = (GetSubLineIndex( nLine2 ) - m_nTopSubLine + GetSubLines( nLine2 )) * nLineHeight + nTopMarginHeight;
       /*ORIGINAL
       rcInvalid.top = (nLine1 - m_nTopLine) * GetLineHeight();
       rcInvalid.bottom = (nLine2 - m_nTopLine + 1) * GetLineHeight();
@@ -4056,11 +4738,11 @@ InvalidateLines (int nLine1, int nLine2, bool bInvalidateMargin /*= false*/ )
 }
 
 void CCrystalTextView::
-SetSelection (const CPoint & ptStart, const CPoint & ptEnd, bool bUpdateView /* = true */)
+SetSelection (const CEPoint & ptStart, const CEPoint & ptEnd, bool bUpdateView /* = true */)
 {
   ASSERT_VALIDTEXTPOS (ptStart);
   ASSERT_VALIDTEXTPOS (ptEnd);
-  if (m_ptSelStart == ptStart && !m_bColumnSelection)
+  if (m_ptSelStart == ptStart && !m_bRectangularSelection)
     {
       if (m_ptSelEnd != ptEnd)
         InvalidateLines (ptEnd.y, m_ptSelEnd.y);
@@ -4092,8 +4774,8 @@ OnSetFocus (CWnd * pOldWnd)
   UpdateCaret ();
 }
 
-DWORD CCrystalTextView::
-ParseLine (DWORD dwCookie, const TCHAR *pszChars, int nLength, TEXTBLOCK * pBuf, int &nActualItems)
+unsigned CCrystalTextView::
+ParseLine (unsigned dwCookie, const tchar_t *pszChars, int nLength, TEXTBLOCK * pBuf, int &nActualItems)
 {
   return m_CurSourceDef->ParseLineX (dwCookie, pszChars, nLength, pBuf, nActualItems);
 }
@@ -4103,156 +4785,181 @@ CalculateActualOffset (int nLineIndex, int nCharIndex, bool bAccumulate)
 {
   const int nLength = GetLineLength (nLineIndex);
   ASSERT (nCharIndex >= 0 && nCharIndex <= nLength);
-  LPCTSTR pszChars = GetLineChars (nLineIndex);
+  const tchar_t* pszChars = GetLineChars (nLineIndex);
   int nOffset = 0;
   const int nTabSize = GetTabSize ();
-  //BEGIN SW
-  vector<int>   anBreaks(nLength + 1);
-  int                  nBreaks = 0;
-
-  /*if( nLength > GetScreenChars() )*/
-  WrapLineCached( nLineIndex, GetScreenChars(), &anBreaks[0], nBreaks );
-
-  int  nPreOffset = 0;
-  int  nPreBreak = 0;
-
-  if( nBreaks > 0 )
-  {
-    int J=0;
-    for( J = nBreaks - 1; J >= 0 && nCharIndex < anBreaks[J]; J-- );
-    nPreBreak = (J >= 0) ? anBreaks[J] : 0;
-  }
-  //END SW
-  m_iterChar.setText(reinterpret_cast<const UChar *>(pszChars), nCharIndex);
+  auto pIterChar = ICUBreakIterator::getCharacterBreakIterator(pszChars, nCharIndex);
   int I=0;
-  for (I = 0; I < nCharIndex; I = m_iterChar.next())
-    {
-      //BEGIN SW
-      if( nPreBreak == I && nBreaks )
-      nPreOffset = nOffset;
-      //END SW
-      if (pszChars[I] == _T ('\t'))
-        nOffset += (nTabSize - nOffset % nTabSize);
-      else
-        nOffset += GetCharCellCountFromChar(pszChars + I);
-    }
-  if (bAccumulate)
-    return nOffset;
-  //BEGIN SW
-  if( nPreBreak == I && nBreaks > 0)
-    return 0;
-  else
-    return nOffset - nPreOffset;
-  /*ORIGINAL
-  return nOffset;
-  *///END SW
-}
-
-int CCrystalTextView::
-ApproxActualOffset (int nLineIndex, int nOffset)
-{
-  if (nOffset == 0)
-    return 0;
-
-  int nLength = GetLineLength (nLineIndex);
-  LPCTSTR pszChars = GetLineChars (nLineIndex);
-  int nCurrentOffset = 0;
-  int nTabSize = GetTabSize ();
-  m_iterChar.setText(reinterpret_cast<const UChar *>(pszChars), nLength);
-  for (int I = 0; I < nLength; I = m_iterChar.next())
+  switch (GetTextLayoutMode ())
     {
-      if (pszChars[I] == _T ('\t'))
-        nCurrentOffset += (nTabSize - nCurrentOffset % nTabSize);
-      else
+      case TEXTLAYOUT_TABLE_NOWORDWRAP:
         {
-          nCurrentOffset += GetCharCellCountFromChar(pszChars + I);
+          int nColumnCount = m_pTextBuffer->GetColumnCount (nLineIndex);
+          int nColumnTotalWidth = 0;
+          int nColumn = 0;
+          bool bInQuote = false;
+          const int sep = m_pTextBuffer->GetFieldDelimiter ();
+          const int quote = m_pTextBuffer->GetFieldEnclosure ();
+          for (I = 0; I < nCharIndex; I = pIterChar->next())
+            {
+              if (!bInQuote && pszChars[I] == sep)
+                {
+                  nColumnTotalWidth += m_pTextBuffer->GetColumnWidth (nColumn++);
+                  nOffset = nColumnTotalWidth;
+                }
+              else
+                {
+                  if (pszChars[I] == quote)
+                    bInQuote = !bInQuote;
+                  else if (pszChars[I] == '\t')
+                    nOffset ++;
+                  else
+                    nOffset += GetCharCellCountFromChar (pszChars + I);
+                  if (nColumn < nColumnCount && nOffset > nColumnTotalWidth + m_pTextBuffer->GetColumnWidth (nColumn))
+                    nOffset = nColumnTotalWidth + m_pTextBuffer->GetColumnWidth (nColumn);
+                }
+            }
+          return nOffset;
         }
-      if (nCurrentOffset >= nOffset)
+        break;
+      case TEXTLAYOUT_TABLE_WORDWRAP:
         {
-          if (nOffset <= nCurrentOffset - nTabSize / 2)
-            return I;
-          return m_iterChar.next();
-        }
-    }
-  return nLength;
-}
-
-void CCrystalTextView::
-EnsureVisible (CPoint pt)
-{
-  //  Scroll vertically
-  int                  nSubLineCount = GetSubLineCount();
-  int                  nNewTopSubLine = m_nTopSubLine;
-  CPoint       subLinePos;
-
-  CharPosToPoint( pt.y, pt.x, subLinePos );
-  subLinePos.y+= GetSubLineIndex( pt.y );
-
-  if( subLinePos.y >= nNewTopSubLine + GetScreenLines() )
-    nNewTopSubLine = subLinePos.y - GetScreenLines() + 1;
-  if( subLinePos.y < nNewTopSubLine )
-    nNewTopSubLine = subLinePos.y;
-
-  if( nNewTopSubLine < 0 )
-    nNewTopSubLine = 0;
-  if( nNewTopSubLine >= nSubLineCount )
-    nNewTopSubLine = nSubLineCount - 1;
-
-  if ( !m_bWordWrap && !m_bHideLines )
-    {
-      // WINMERGE: This line fixes (cursor) slowdown after merges!
-      // I don't know exactly why, but propably we are setting
-      // m_nTopLine to zero in ResetView() and are not setting to
-      // valid value again. Maybe this is a good place to set it?
-      m_nTopLine = nNewTopSubLine;
-    }
-  else
-    {
-      int dummy;
-      GetLineBySubLine(nNewTopSubLine, m_nTopLine, dummy);
-    }
-
-  if( nNewTopSubLine != m_nTopSubLine )
-    {
-      ScrollToSubLine( nNewTopSubLine );
-      UpdateCaret();
-      UpdateSiblingScrollPos( false );
-    }
-
-  //  Scroll horizontally
-  // we do not need horizontally scrolling, if we wrap the words
-  if( m_bWordWrap )
-    return;
-  int nActualPos = CalculateActualOffset (pt.y, pt.x);
-  int nNewOffset = m_nOffsetChar;
-  const int nScreenChars = GetScreenChars ();
-  
-  // Keep 5 chars visible right to cursor
-  if (nActualPos > nNewOffset + nScreenChars - 5)
-    {
-      // Add 10 chars width space after line
-      nNewOffset = nActualPos - nScreenChars + 10;
-    }
-  // Keep 5 chars visible left to cursor
-  if (nActualPos < nNewOffset + 5)
-    {
-      // Jump by 10 char steps, so user sees previous letters too
-      nNewOffset = nActualPos - 10;
+          int nColumnIndex = 0;
+          CEPoint charPoint;
+          int nSubLineStart = CharPosToPoint( nLineIndex, nCharIndex, charPoint, &nColumnIndex );
+          for (int i = 0; i < nColumnIndex; ++i)
+              nOffset += m_pTextBuffer->GetColumnWidth (i);
+          for (int nIndex = 0; nIndex < nCharIndex; nIndex = pIterChar->next())
+            {
+              if( nIndex >= nSubLineStart )
+                {
+                  if (pszChars[nIndex] == '\t')
+                    nOffset ++;
+                  else
+                    nOffset += GetCharCellCountFromChar (pszChars + nIndex);
+                }
+            }
+          return nOffset;
+        }
+        break;
+      default:
+        {
+          //BEGIN SW
+          vector<int>   anBreaks(nLength + 1);
+          int                  nBreaks = 0;
+          /*if( nLength > GetScreenChars() )*/
+          WrapLineCached( nLineIndex, GetScreenChars(), &anBreaks, nBreaks );
+          int  nPreOffset = 0;
+          int  nPreBreak = 0;
+          if( nBreaks > 0 )
+            {
+              int J=0;
+              for( J = nBreaks - 1; J >= 0 && nCharIndex < anBreaks[J]; J-- );
+              nPreBreak = (J >= 0) ? anBreaks[J] : 0;
+            }
+          //END SW
+          for (I = 0; I < nCharIndex; I = pIterChar->next())
+            {
+              //BEGIN SW
+              if( nPreBreak == I && nBreaks )
+              nPreOffset = nOffset;
+              //END SW
+            if (pszChars[I] == _T ('\t'))
+                nOffset += (nTabSize - nOffset % nTabSize);
+              else
+                nOffset += GetCharCellCountFromChar(pszChars + I);
+            }
+          if (bAccumulate)
+            return nOffset;
+          //BEGIN SW
+          if( nPreBreak == I && nBreaks > 0)
+            return 0;
+          else
+            return nOffset - nPreOffset;
+          /*ORIGINAL
+          return nOffset;
+          *///END SW
+        }
     }
+}
 
-  // Horiz scroll limit to longest line + one screenwidth
-  const int nMaxLineLen = GetMaxLineLength (m_nTopLine, GetScreenLines());
-  if (nNewOffset >= nMaxLineLen + nScreenChars)
-    nNewOffset = nMaxLineLen + nScreenChars - 1;
-  if (nNewOffset < 0)
-    nNewOffset = 0;
+int CCrystalTextView::
+ApproxActualOffset (int nLineIndex, int nOffset)
+{
+  if (nOffset == 0)
+    return 0;
 
-  if (m_nOffsetChar != nNewOffset)
+  int nLength = GetLineLength (nLineIndex);
+  const tchar_t* pszChars = GetLineChars (nLineIndex);
+  int nCurrentOffset = 0;
+  int nTabSize = GetTabSize ();
+  auto pIterChar = ICUBreakIterator::getCharacterBreakIterator(pszChars, nLength);
+  switch (GetTextLayoutMode ())
     {
-      ScrollToChar (nNewOffset);
-      UpdateCaret ();
-      UpdateSiblingScrollPos (true);
+      case TEXTLAYOUT_TABLE_NOWORDWRAP:
+      case TEXTLAYOUT_TABLE_WORDWRAP:
+        {
+          int nColumnCount = m_pTextBuffer->GetColumnCount (nLineIndex);
+          int nColumnTotalWidth = 0;
+          bool bInQuote = false;
+          const int sep = m_pTextBuffer->GetFieldDelimiter ();
+          const int quote = m_pTextBuffer->GetFieldEnclosure ();
+          for (int I = 0, nColumn = 0; I < nLength; I = pIterChar->next())
+            {
+              if (!bInQuote && pszChars[I] ==sep)
+                {
+                  nColumnTotalWidth += m_pTextBuffer->GetColumnWidth (nColumn++);
+                  nCurrentOffset = nColumnTotalWidth;
+                }
+              else
+                {
+                  if (pszChars[I] == quote)
+                    bInQuote = !bInQuote;
+                  if (pszChars[I] == '\t')
+                    nCurrentOffset ++;
+                  else
+                    nCurrentOffset += GetCharCellCountFromChar (pszChars + I);
+                  if (nColumn < nColumnCount && nCurrentOffset > nColumnTotalWidth + m_pTextBuffer->GetColumnWidth (nColumn))
+                    nCurrentOffset = nColumnTotalWidth + m_pTextBuffer->GetColumnWidth (nColumn);
+                }
+              if (nCurrentOffset >= nOffset)
+                {
+                  if (nOffset <= nCurrentOffset - nTabSize / 2)
+                    return I;
+                  return pIterChar->next ();
+                }
+            }
+        }
+        break;
+      default:
+        {
+          for (int I = 0; I < nLength; I = pIterChar->next())
+            {
+              if (pszChars[I] == _T ('\t'))
+                nCurrentOffset += (nTabSize - nCurrentOffset % nTabSize);
+              else
+                {
+                  nCurrentOffset += GetCharCellCountFromChar(pszChars + I);
+                }
+              if (nCurrentOffset >= nOffset)
+                {
+                  if (nOffset <= nCurrentOffset - nTabSize / 2)
+                    return I;
+                  return pIterChar->next();
+                }
+            }
+        }
     }
+  return nLength;
+}
+
+void CCrystalTextView::
+EnsureVisible (CEPoint pt)
+{
+  EnsureVisible(pt, pt);
 }
 
 void CCrystalTextView::
@@ -4280,10 +4987,14 @@ OnSysColorChange ()
 }
 
 void CCrystalTextView::
-GetText (const CPoint & ptStart, const CPoint & ptEnd, CString & text, bool bExcludeInvisibleLines /*= true*/)
+GetText (const CEPoint & ptStart, const CEPoint & ptEnd, CString & text, bool bExcludeInvisibleLines /*= true*/)
 {
   if (m_pTextBuffer != nullptr)
-    m_pTextBuffer->GetText (ptStart.y, ptStart.x, ptEnd.y, ptEnd.x, text);
+    {
+      std::basic_string<tchar_t> sText;
+      m_pTextBuffer->GetText (ptStart.y, ptStart.x, ptEnd.y, ptEnd.x, sText);
+      text.SetString(sText.c_str (), static_cast<int> (sText.length ())); // TODO: Use std::basic_string<tchar_t> instead of CString
+    }
   else
     text = _T ("");
 }
@@ -4299,12 +5010,12 @@ GetTextInColumnSelection (CString & text, bool bExcludeInvisibleLines /*= true*/
 
   PrepareSelBounds ();
 
-  CString sEol = m_pTextBuffer->GetStringEol (CRLF_STYLE_DOS);
+  CString sEol = m_pTextBuffer->GetStringEol (CRLFSTYLE::DOS);
 
   int nBufSize = 1;
   for (int L = m_ptDrawSelStart.y; L <= m_ptDrawSelEnd.y; L++)
-      nBufSize += GetLineLength (L) + sEol.GetLength ();
-  LPTSTR pszBuf = text.GetBuffer (nBufSize);
+    nBufSize += GetLineLength (L) + sEol.GetLength ();
+  tchar_t* pszBuf = text.GetBuffer (nBufSize);
 
   for (int I = m_ptDrawSelStart.y; I <= m_ptDrawSelEnd.y; I++)
     {
@@ -4312,9 +5023,9 @@ GetTextInColumnSelection (CString & text, bool bExcludeInvisibleLines /*= true*/
         continue;
       int nSelLeft, nSelRight;
       GetColumnSelection (I, nSelLeft, nSelRight);
-      memcpy (pszBuf, GetLineChars (I) + nSelLeft, sizeof (TCHAR) * (nSelRight - nSelLeft));
+      memcpy (pszBuf, GetLineChars (I) + nSelLeft, sizeof (tchar_t) * (nSelRight - nSelLeft));
       pszBuf += (nSelRight - nSelLeft);
-      memcpy (pszBuf, sEol, sizeof (TCHAR) * sEol.GetLength ());
+      memcpy (pszBuf, sEol, sizeof (tchar_t) * sEol.GetLength ());
       pszBuf += sEol.GetLength ();
     }
   pszBuf[0] = 0;
@@ -4324,14 +5035,14 @@ GetTextInColumnSelection (CString & text, bool bExcludeInvisibleLines /*= true*/
 
 void CCrystalTextView::
 UpdateView (CCrystalTextView * pSource, CUpdateContext * pContext,
-            DWORD dwFlags, int nLineIndex /*= -1*/ )
+            updateview_flags_t dwFlags, int nLineIndex /*= -1*/ )
 {
   // SetTextType (GetExt (GetDocument ()->GetPathName ()));
   if (dwFlags & UPDATE_RESET)
     {
       ResetView ();
-      RecalcVertScrollBar ();
-      RecalcHorzScrollBar ();
+      InvalidateVertScrollBar ();
+      InvalidateHorzScrollBar ();
       return;
     }
 
@@ -4348,7 +5059,7 @@ UpdateView (CCrystalTextView * pSource, CUpdateContext * pContext,
           ASSERT (cookiesSize == nLineCount);
           // must be reinitialized to invalid value (DWORD) - 1
           for (int i = nLineIndex; i < cookiesSize; ++i)
-            (*m_ParseCookies)[i] = static_cast<DWORD>(-1);
+            (*m_ParseCookies)[i] = static_cast<uint32_t>(-1);
         }
       //  This line'th actual length must be recalculated
       if (m_pnActualLineLength->size())
@@ -4356,9 +5067,9 @@ UpdateView (CCrystalTextView * pSource, CUpdateContext * pContext,
           ASSERT (m_pnActualLineLength->size() == static_cast<size_t>(nLineCount));
           // must be initialized to invalid code -1
           (*m_pnActualLineLength)[nLineIndex] = -1;
-      //BEGIN SW
-      InvalidateLineCache( nLineIndex, nLineIndex );
-      //END SW
+          //BEGIN SW
+          InvalidateLineCache( nLineIndex, nLineIndex );
+          //END SW
         }
       //  Repaint the lines
       InvalidateLines (nLineIndex, -1, true);
@@ -4383,17 +5094,17 @@ UpdateView (CCrystalTextView * pSource, CUpdateContext * pContext,
               arrSize = nLineCount;
               // must be initialized to invalid value (DWORD) - 1
               for (size_t i = oldsize; i < arrSize; ++i)
-                (*m_ParseCookies)[i] = static_cast<DWORD>(-1);
+                (*m_ParseCookies)[i] = static_cast<uint32_t>(-1);
             }
           for (size_t i = nLineIndex; i < arrSize; ++i)
-            (*m_ParseCookies)[i] = static_cast<DWORD>(-1);
+            (*m_ParseCookies)[i] = static_cast<uint32_t>(-1);
         }
 
       //  Recalculate actual length for all lines below this
       if (m_pnActualLineLength->size())
         {
-            size_t arrsize = m_pnActualLineLength->size();
-            if (arrsize != static_cast<size_t>(nLineCount))
+          size_t arrsize = m_pnActualLineLength->size();
+          if (arrsize != static_cast<size_t>(nLineCount))
             {
               //  Reallocate actual length array
               size_t oldsize = arrsize; 
@@ -4406,9 +5117,9 @@ UpdateView (CCrystalTextView * pSource, CUpdateContext * pContext,
           for (size_t i = nLineIndex; i < arrsize; ++i)
             (*m_pnActualLineLength)[i] = -1;
         }
-    //BEGIN SW
-    InvalidateLineCache( nLineIndex, -1 );
-    //END SW
+      //BEGIN SW
+      InvalidateLineCache( nLineIndex, -1 );
+      //END SW
       //  Repaint the lines
       InvalidateLines (nLineIndex, -1, true);
     }
@@ -4431,7 +5142,7 @@ UpdateView (CCrystalTextView * pSource, CUpdateContext * pContext,
           ASSERT_VALIDTEXTPOS (m_ptDraggedTextBegin);
           ASSERT_VALIDTEXTPOS (m_ptDraggedTextEnd);
         }
-      CPoint ptTopLine (0, m_nTopLine);
+      CEPoint ptTopLine (0, m_nTopLine);
       pContext->RecalcPoint (ptTopLine);
       ASSERT_VALIDTEXTPOS (ptTopLine);
       m_nTopLine = ptTopLine.y;
@@ -4442,14 +5153,14 @@ UpdateView (CCrystalTextView * pSource, CUpdateContext * pContext,
   if ((dwFlags & UPDATE_VERTRANGE) != 0)
     {
       if (!m_bVertScrollBarLocked)
-        RecalcVertScrollBar ();
+        InvalidateVertScrollBar ();
     }
 
   //  Recalculate horizontal scrollbar, if needed
   if ((dwFlags & UPDATE_HORZRANGE) != 0)
     {
       if (!m_bHorzScrollBarLocked)
-        RecalcHorzScrollBar ();
+        InvalidateHorzScrollBar ();
     }
 }
 
@@ -4469,7 +5180,7 @@ int CCrystalTextView::
 OnCreate (LPCREATESTRUCT lpCreateStruct)
 {
   m_lfBaseFont = {};
-  _tcscpy_s (m_lfBaseFont.lfFaceName, _T ("FixedSys"));
+  tc::tcslcpy (m_lfBaseFont.lfFaceName, _T ("FixedSys"));
   m_lfBaseFont.lfHeight = 0;
   m_lfBaseFont.lfWeight = FW_NORMAL;
   m_lfBaseFont.lfItalic = false;
@@ -4492,14 +5203,14 @@ OnCreate (LPCREATESTRUCT lpCreateStruct)
 }
 
 void CCrystalTextView::
-SetAnchor (const CPoint & ptNewAnchor)
+SetAnchor (const CEPoint & ptNewAnchor)
 {
   ASSERT_VALIDTEXTPOS (ptNewAnchor);
   m_ptAnchor = ptNewAnchor;
 }
 
 void CCrystalTextView::
-OnEditOperation (int nAction, LPCTSTR pszText, size_t cchText)
+OnEditOperation (int nAction, const tchar_t* pszText, size_t cchText)
 {
 }
 
@@ -4525,14 +5236,8 @@ PreTranslateMessage (MSG * pMsg)
   return CView::PreTranslateMessage (pMsg);
 }
 
-CPoint CCrystalTextView::
-GetCursorPos () const
-{
-  return m_ptCursorPos;
-}
-
 void CCrystalTextView::
-SetCursorPos (const CPoint & ptCursorPos)
+SetCursorPos (const CEPoint & ptCursorPos)
 {
   ASSERT_VALIDTEXTPOS (ptCursorPos);
   m_ptCursorPos = ptCursorPos;
@@ -4557,15 +5262,29 @@ void CCrystalTextView::
 UpdateCompositionWindowFont() /* IME */
 {
   HIMC hIMC = ImmGetContext(m_hWnd);
-  LOGFONT logfont;
 
-  GetFont()->GetLogFont(&logfont);
-  ImmSetCompositionFont(hIMC, &logfont);
+  ImmSetCompositionFont(hIMC, &m_lfBaseFont);
 
   ImmReleaseContext(m_hWnd, hIMC);
 }
 
 void CCrystalTextView::
+SetTopMargin (bool bTopMargin)
+{
+  if (m_bTopMargin != bTopMargin)
+    {
+      m_bTopMargin = bTopMargin;
+      if (::IsWindow (m_hWnd))
+        {
+          Invalidate ();
+          m_nScreenLines = -1;
+          InvalidateVertScrollBar ();
+          UpdateCaret ();
+        }
+    }
+}
+
+void CCrystalTextView::
 SetSelectionMargin (bool bSelMargin)
 {
   if (m_bSelMargin != bSelMargin)
@@ -4598,31 +5317,18 @@ SetViewLineNumbers (bool bViewLineNumbers)
 }
 
 void CCrystalTextView::
-GetFont (LOGFONT & lf)
-{
-  lf = m_lfBaseFont;
-}
-
-void CCrystalTextView::
 SetFont (const LOGFONT & lf)
 {
   m_lfBaseFont = lf;
   m_nCharWidth = -1;
   m_nLineHeight = -1;
-  for (int I = 0; I < 4; I++)
-    {
-      if (m_apFonts[I] != nullptr)
-        {
-          delete m_apFonts[I];
-          m_apFonts[I] = nullptr;
-        }
-    }
+  m_pCrystalRenderer->SetFont(lf);
   if (::IsWindow (m_hWnd))
     {
       InvalidateScreenRect();
       m_nTopSubLine = GetSubLineIndex(m_nTopLine);
-      RecalcVertScrollBar ();
-      RecalcHorzScrollBar ();
+      InvalidateVertScrollBar ();
+      InvalidateHorzScrollBar ();
       UpdateCaret ();
     }
 #ifdef _UNICODE
@@ -4649,26 +5355,26 @@ OnUpdateIndicatorCRLF (CCmdUI * pCmdUI)
 {
   if (m_pTextBuffer != nullptr)
     {
-      std::basic_string<TCHAR> eol;
+      std::basic_string<tchar_t> eol;
       CRLFSTYLE crlfMode = m_pTextBuffer->GetCRLFMode ();
       switch (crlfMode)
         {
-        case CRLF_STYLE_DOS:
+        case CRLFSTYLE::DOS:
           eol = LoadResString (IDS_EOL_DOS);
           pCmdUI->SetText (eol.c_str());
           pCmdUI->Enable (true);
           break;
-        case CRLF_STYLE_UNIX:
+        case CRLFSTYLE::UNIX:
           eol = LoadResString (IDS_EOL_UNIX);
           pCmdUI->SetText (eol.c_str());
           pCmdUI->Enable (true);
           break;
-        case CRLF_STYLE_MAC:
+        case CRLFSTYLE::MAC:
           eol = LoadResString (IDS_EOL_MAC);
           pCmdUI->SetText (eol.c_str());
           pCmdUI->Enable (true);
           break;
-        case CRLF_STYLE_MIXED:
+        case CRLFSTYLE::MIXED:
           eol = LoadResString (IDS_EOL_MIXED);
           pCmdUI->SetText (eol.c_str());
           pCmdUI->Enable (true);
@@ -4692,8 +5398,8 @@ OnToggleBookmark (UINT nCmdID)
   ASSERT (nBookmarkID >= 0 && nBookmarkID <= 9);
   if (m_pTextBuffer != nullptr)
     {
-      DWORD dwFlags = GetLineFlags (m_ptCursorPos.y);
-      DWORD dwMask = LF_BOOKMARK (nBookmarkID);
+      lineflags_t dwFlags = GetLineFlags (m_ptCursorPos.y);
+      lineflags_t dwMask = LF_BOOKMARK (nBookmarkID);
       m_pTextBuffer->SetLineFlag (m_ptCursorPos.y, dwMask, (dwFlags & dwMask) == 0);
     }
 }
@@ -4708,7 +5414,7 @@ OnGoBookmark (UINT nCmdID)
       int nLine = m_pTextBuffer->GetLineWithFlag (LF_BOOKMARK (nBookmarkID));
       if (nLine >= 0)
         {
-          CPoint pt (0, nLine);
+          CEPoint pt (0, nLine);
           ASSERT_VALIDTEXTPOS (pt);
           SetCursorPos (pt);
           SetSelection (pt, pt);
@@ -4749,12 +5455,6 @@ HideCursor ()
   UpdateCaret ();
 }
 
-DROPEFFECT CCrystalTextView::
-GetDropEffect ()
-{
-  return DROPEFFECT_COPY;
-}
-
 void CCrystalTextView::
 OnDropSource (DROPEFFECT de)
 {
@@ -4771,12 +5471,12 @@ PrepareDragData ()
   CString text;
   GetText (m_ptDrawSelStart, m_ptDrawSelEnd, text);
   int cchText = text.GetLength();
-  SIZE_T cbData = (cchText + 1) * sizeof(TCHAR);
+  SIZE_T cbData = (cchText + 1) * sizeof(tchar_t);
   HGLOBAL hData =::GlobalAlloc (GMEM_MOVEABLE | GMEM_DDESHARE, cbData);
   if (hData == nullptr)
     return nullptr;
 
-  LPTSTR pszData = (LPTSTR)::GlobalLock (hData);
+  tchar_t* pszData = (tchar_t*)::GlobalLock (hData);
   if (pszData == nullptr)
     {
       ::GlobalFree(hData);
@@ -4790,64 +5490,6 @@ PrepareDragData ()
   return hData;
 }
 
-static ptrdiff_t
-FindStringHelper (LPCTSTR pszLineBegin, LPCTSTR pszFindWhere, LPCTSTR pszFindWhat, DWORD dwFlags, int &nLen, RxNode *&rxnode, RxMatchRes *rxmatch)
-{
-  if (dwFlags & FIND_REGEXP)
-    {
-      ptrdiff_t pos = -1;
-
-      if (rxnode)
-        RxFree (rxnode);
-      rxnode = nullptr;
-      if (pszFindWhat[0] == '^' && pszLineBegin != pszFindWhere)
-        return pos;
-      rxnode = RxCompile (pszFindWhat, (dwFlags & FIND_MATCH_CASE) != 0 ? RX_CASE : 0);
-      if (rxnode && RxExec (rxnode, pszFindWhere, _tcslen (pszFindWhere), pszFindWhere, rxmatch))
-        {
-          pos = rxmatch->Open[0];
-          ASSERT((rxmatch->Close[0] - rxmatch->Open[0]) < INT_MAX);
-          nLen = static_cast<int>(rxmatch->Close[0] - rxmatch->Open[0]);
-        }
-      return pos;
-    }
-  else
-    {
-      ASSERT (pszFindWhere != nullptr);
-      ASSERT (pszFindWhat != nullptr);
-      int nCur = 0;
-      int nLength = (int) _tcslen (pszFindWhat);
-      LPCTSTR pszFindWhereOrig = pszFindWhere;
-      nLen = nLength;
-      for (;;)
-        {
-          LPCTSTR pszPos;
-          if (dwFlags & FIND_MATCH_CASE)
-            pszPos = _tcsstr(pszFindWhere, pszFindWhat);
-          else
-            pszPos = StrStrI(pszFindWhere, pszFindWhat);
-          if (pszPos == nullptr)
-            return -1;
-          if ((dwFlags & FIND_WHOLE_WORD) == 0)
-            return nCur + (int) (pszPos - pszFindWhere);
-          if (pszPos > pszFindWhereOrig && xisalnum (pszPos[-1]))
-            {
-              nCur += (int) (pszPos - pszFindWhere + 1);
-              pszFindWhere = pszPos + 1;
-              continue;
-            }
-          if (xisalnum (pszPos[nLength]))
-            {
-              nCur += (int) (pszPos - pszFindWhere + 1);
-              pszFindWhere = pszPos + 1;
-              continue;
-            }
-          return nCur + (int) (pszPos - pszFindWhere);
-        }
-    }
-//~  ASSERT (false);               // Unreachable
-}
-
 /** 
  * @brief Select text in editor.
  * @param [in] ptStartPos Star position for highlight.
@@ -4856,11 +5498,11 @@ FindStringHelper (LPCTSTR pszLineBegin, LPCTSTR pszFindWhere, LPCTSTR pszFindWha
  *  selection, if false cursor is positioned to right-end.
  */
 bool CCrystalTextView::
-HighlightText (const CPoint & ptStartPos, int nLength,
-    bool bCursorToLeft /*= false*/)
+HighlightText (const CEPoint & ptStartPos, int nLength,
+    bool bCursorToLeft /*= false*/, bool bUpdateView /*= true*/)
 {
   ASSERT_VALIDTEXTPOS (ptStartPos);
-  CPoint ptEndPos = ptStartPos;
+  CEPoint ptEndPos = ptStartPos;
   int nCount = GetLineLength (ptEndPos.y) - ptEndPos.x;
   if (nLength <= nCount)
     {
@@ -4880,6 +5522,10 @@ HighlightText (const CPoint & ptStartPos, int nLength,
   m_ptCursorPos = bCursorToLeft ? ptStartPos : ptEndPos;
   m_ptAnchor = bCursorToLeft ? ptEndPos : ptStartPos;
   SetSelection (ptStartPos, ptEndPos);
+
+  if (!bUpdateView)
+      return true;
+
   UpdateCaret ();
   
   // Scrolls found text to middle of screen if out-of-screen
@@ -4897,8 +5543,8 @@ HighlightText (const CPoint & ptStartPos, int nLength,
 }
 
 bool CCrystalTextView::
-FindText (LPCTSTR pszText, const CPoint & ptStartPos, DWORD dwFlags,
-          bool bWrapSearch, CPoint * pptFoundPos)
+FindText (const tchar_t* pszText, const CEPoint & ptStartPos, DWORD dwFlags,
+          bool bWrapSearch, CEPoint * pptFoundPos)
 {
   if (m_pMarkers != nullptr)
     {
@@ -4907,17 +5553,17 @@ FindText (LPCTSTR pszText, const CPoint & ptStartPos, DWORD dwFlags,
         m_pMarkers->UpdateViews();
     }
   int nLineCount = GetLineCount ();
-  return FindTextInBlock (pszText, ptStartPos, CPoint (0, 0),
-                          CPoint (GetLineLength (nLineCount - 1), nLineCount - 1),
+  return FindTextInBlock (pszText, ptStartPos, CEPoint (0, 0),
+                          CEPoint (GetLineLength (nLineCount - 1), nLineCount - 1),
                           dwFlags, bWrapSearch, pptFoundPos);
 }
 
-int HowManyStr (LPCTSTR s, LPCTSTR m)
+int HowManyStr (const tchar_t* s, const tchar_t* m)
 {
-  LPCTSTR p = s;
+  const tchar_t* p = s;
   int n = 0;
-  const int l = (int) _tcslen (m);
-  while ((p = _tcsstr (p, m)) != nullptr)
+  const int l = (int) tc::tcslen (m);
+  while ((p = tc::tcsstr (p, m)) != nullptr)
     {
       n++;
       p += l;
@@ -4925,11 +5571,11 @@ int HowManyStr (LPCTSTR s, LPCTSTR m)
   return n;
 }
 
-int HowManyStr (LPCTSTR s, TCHAR c)
+int HowManyStr (const tchar_t* s, tchar_t c)
 {
-  LPCTSTR p = s;
+  const tchar_t* p = s;
   int n = 0;
-  while ((p = _tcschr (p, c)) != nullptr)
+  while ((p = tc::tcschr (p, c)) != nullptr)
     {
       n++;
       p++;
@@ -4938,13 +5584,13 @@ int HowManyStr (LPCTSTR s, TCHAR c)
 }
 
 bool CCrystalTextView::
-FindTextInBlock (LPCTSTR pszText, const CPoint & ptStartPosition,
-                 const CPoint & ptBlockBegin, const CPoint & ptBlockEnd,
-                 DWORD dwFlags, bool bWrapSearch, CPoint * pptFoundPos)
+FindTextInBlock (const tchar_t* pszText, const CEPoint & ptStartPosition,
+                 const CEPoint & ptBlockBegin, const CEPoint & ptBlockEnd,
+                 findtext_flags_t dwFlags, bool bWrapSearch, CEPoint * pptFoundPos)
 {
-  CPoint ptCurrentPos = ptStartPosition;
+  CEPoint ptCurrentPos = ptStartPosition;
 
-  ASSERT (pszText != nullptr && _tcslen (pszText) > 0);
+  ASSERT (pszText != nullptr && tc::tcslen (pszText) > 0);
   ASSERT_VALIDTEXTPOS (ptCurrentPos);
   ASSERT_VALIDTEXTPOS (ptBlockBegin);
   ASSERT_VALIDTEXTPOS (ptBlockEnd);
@@ -4987,7 +5633,7 @@ FindTextInBlock (LPCTSTR pszText, const CPoint & ptStartPosition,
                   for (int i = 0; i <= nEolns && ptCurrentPos.y >= i; i++)
                     {
                       CString item;
-                      LPCTSTR pszChars = GetLineChars (ptCurrentPos.y - i);
+                      const tchar_t* pszChars = GetLineChars (ptCurrentPos.y - i);
                       if (i)
                         {
                           nLineLength = GetLineLength (ptCurrentPos.y - i);
@@ -5000,9 +5646,7 @@ FindTextInBlock (LPCTSTR pszText, const CPoint & ptStartPosition,
                         }
                       if (nLineLength > 0)
                         {
-                          LPTSTR pszBuf = item.GetBuffer (nLineLength + 1);
-                          _tcsncpy_s (pszBuf, nLineLength+1, pszChars, nLineLength);
-                          item.ReleaseBuffer (nLineLength);
+                          item.SetString(pszChars, nLineLength);
                           line = item + line;
                         }
                     }
@@ -5017,15 +5661,12 @@ FindTextInBlock (LPCTSTR pszText, const CPoint & ptStartPosition,
                     {
                       ptCurrentPos.x = nLineLength;
                     }
-                  else
-                    if( ptCurrentPos.x > nLineLength )
-                      ptCurrentPos.x = nLineLength;
+                  else if( ptCurrentPos.x > nLineLength )
+                    ptCurrentPos.x = nLineLength;
                   if (ptCurrentPos.x == -1)
                     ptCurrentPos.x = 0;
 
-                  LPCTSTR pszChars = GetLineChars (ptCurrentPos.y);
-                  _tcsncpy_s (line.GetBuffer(ptCurrentPos.x + 1), ptCurrentPos.x + 1, pszChars, ptCurrentPos.x);
-                  line.ReleaseBuffer (ptCurrentPos.x);
+                  line.SetString (GetLineChars (ptCurrentPos.y), ptCurrentPos.x);
                 }
 
               ptrdiff_t nFoundPos = -1;
@@ -5034,10 +5675,10 @@ FindTextInBlock (LPCTSTR pszText, const CPoint & ptStartPosition,
               size_t nPos = 0;
               for (;;)
                 {
-                  size_t nPosRel = ::FindStringHelper(line, static_cast<LPCTSTR>(line) + nPos, what, dwFlags, m_nLastFindWhatLen, m_rxnode, &m_rxmatch);
-                  if (nPosRel == -1)
+                  nPos = ::FindStringHelper(line, nLineLen, static_cast<const tchar_t*>(line) + nPos, what, dwFlags, m_nLastFindWhatLen, m_rxnode, &m_rxmatch);
+                  if (nPos == -1)
                     break;
-                  nFoundPos = nPos + nPosRel;
+                  nFoundPos = nPos;
                   nMatchLen = m_nLastFindWhatLen;
                   nPos += nMatchLen == 0 ? 1 : nMatchLen;
                 }
@@ -5060,7 +5701,7 @@ FindTextInBlock (LPCTSTR pszText, const CPoint & ptStartPosition,
 
           //  Start again from the end of text
           bWrapSearch = false;
-          ptCurrentPos = CPoint (GetLineLength (GetLineCount () - 1), GetLineCount () - 1);
+          ptCurrentPos = CEPoint (GetLineLength (GetLineCount () - 1), GetLineCount () - 1);
         }
     }
   else
@@ -5076,8 +5717,7 @@ FindTextInBlock (LPCTSTR pszText, const CPoint & ptStartPosition,
                   int nLines = m_pTextBuffer->GetLineCount ();
                   for (int i = 0; i <= nEolns && ptCurrentPos.y + i < nLines; i++)
                     {
-                      CString item;
-                      LPCTSTR pszChars = GetLineChars (ptCurrentPos.y + i);
+                      const tchar_t* pszChars = GetLineChars (ptCurrentPos.y + i);
                       nLineLength = GetLineLength (ptCurrentPos.y + i);
                       if (i)
                         {
@@ -5085,10 +5725,8 @@ FindTextInBlock (LPCTSTR pszText, const CPoint & ptStartPosition,
                         }
                       if (nLineLength > 0)
                         {
-                          LPTSTR pszBuf = item.GetBuffer (nLineLength + 1);
-                          _tcsncpy_s (pszBuf, nLineLength + 1, pszChars, nLineLength);
-                          item.ReleaseBuffer (nLineLength);
-                          line += item;
+                          int nLineLengthOld = line.GetLength();
+                          memcpy(line.GetBufferSetLength(nLineLengthOld + nLineLength) + nLineLengthOld, pszChars, nLineLength * sizeof(tchar_t));
                         }
                     }
                   nLineLength = line.GetLength ();
@@ -5103,20 +5741,20 @@ FindTextInBlock (LPCTSTR pszText, const CPoint & ptStartPosition,
                       continue;
                     }
 
-                  line = GetLineChars (ptCurrentPos.y);
+                  line.SetString(GetLineChars(ptCurrentPos.y), GetLineLength(ptCurrentPos.y));
                 }
 
               //  Perform search in the line
-              size_t nPos = ::FindStringHelper (line, static_cast<LPCTSTR>(line) + ptCurrentPos.x, what, dwFlags, m_nLastFindWhatLen, m_rxnode, &m_rxmatch);
+              size_t nPos = ::FindStringHelper (line, line.GetLength (), static_cast<const tchar_t*>(line) + ptCurrentPos.x, what, dwFlags, m_nLastFindWhatLen, m_rxnode, &m_rxmatch);
               if (nPos != -1)
                 {
                   if (m_pszMatched != nullptr)
                     free(m_pszMatched);
-                  m_pszMatched = _tcsdup (line);
+                  m_pszMatched = tc::tcsdup (line);
                   if (nEolns)
                     {
                       CString item = line.Left (static_cast<LONG>(nPos));
-                      LPCTSTR current = _tcsrchr (item, _T('\n'));
+                      const tchar_t* current = tc::tcsrchr (item, _T('\n'));
                       if (current)
                         current++;
                       else
@@ -5125,18 +5763,18 @@ FindTextInBlock (LPCTSTR pszText, const CPoint & ptStartPosition,
                       if (nEolns)
                         {
                           ptCurrentPos.y += nEolns;
-                          ptCurrentPos.x = static_cast<LONG>(nPos - (current - (LPCTSTR) item));
+                          ptCurrentPos.x = static_cast<LONG>(nPos - (current - (const tchar_t*) item));
                         }
                       else
                         {
-                          ptCurrentPos.x += static_cast<LONG>(nPos - (current - (LPCTSTR) item));
+                          ptCurrentPos.x = static_cast<LONG>(nPos - (current - (const tchar_t*) item));
                         }
                       if (ptCurrentPos.x < 0)
                         ptCurrentPos.x = 0;
                     }
                   else
                     {
-                      ptCurrentPos.x += static_cast<LONG>(nPos);
+                      ptCurrentPos.x = static_cast<LONG>(nPos);
                     }
                   //  Check of the text found is outside the block.
                   if (ptCurrentPos.y == ptBlockEnd.y && ptCurrentPos.x >= ptBlockEnd.x)
@@ -5167,43 +5805,32 @@ FindTextInBlock (LPCTSTR pszText, const CPoint & ptStartPosition,
         }
     }
 
- //~ ASSERT (false);               // Unreachable
 //~ ASSERT (false);               // Unreachable
 }
 
-static DWORD ConvertSearchInfosToSearchFlags(const LastSearchInfos *lastSearch)
+CEPoint CCrystalTextView::
+GetSearchPos(findtext_flags_t dwSearchFlags)
 {
-  DWORD dwSearchFlags = 0;
-  if (lastSearch->m_bMatchCase)
-    dwSearchFlags |= FIND_MATCH_CASE;
-  if (lastSearch->m_bWholeWord)
-    dwSearchFlags |= FIND_WHOLE_WORD;
-  if (lastSearch->m_bRegExp)
-    dwSearchFlags |= FIND_REGEXP;
-  if (lastSearch->m_nDirection == 0)
-    dwSearchFlags |= FIND_DIRECTION_UP;
-  if (lastSearch->m_bNoWrap)
-    dwSearchFlags |= FIND_NO_WRAP;
-  if (lastSearch->m_bNoClose)
-    dwSearchFlags |= FIND_NO_CLOSE;
-  return dwSearchFlags;
-}
-
-static void ConvertSearchFlagsToLastSearchInfos(LastSearchInfos *lastSearch, DWORD dwFlags)
-{
-  lastSearch->m_bMatchCase = (dwFlags & FIND_MATCH_CASE) != 0;
-  lastSearch->m_bWholeWord = (dwFlags & FIND_WHOLE_WORD) != 0;
-  lastSearch->m_bRegExp = (dwFlags & FIND_REGEXP) != 0;
-  lastSearch->m_nDirection = (dwFlags & FIND_DIRECTION_UP) == 0;
-  lastSearch->m_bNoWrap = (dwFlags & FIND_NO_WRAP) != 0;
-  lastSearch->m_bNoClose = (dwFlags & FIND_NO_CLOSE) != 0;
+  CEPoint ptSearchPos;
+  if (IsSelection())
+    {
+      auto [ptStart, ptEnd] = GetSelection ();
+      if( dwSearchFlags & FIND_DIRECTION_UP)
+        ptSearchPos = ptStart;
+      else
+        ptSearchPos = ptEnd;
+    }
+  else
+    ptSearchPos = m_ptCursorPos;
+  return ptSearchPos;
 }
 
 bool CCrystalTextView::
 FindText (const LastSearchInfos * lastSearch)
 {
-  CPoint ptTextPos;
-  DWORD dwSearchFlags = ConvertSearchInfosToSearchFlags(lastSearch);
-  if (!FindText (lastSearch->m_sText, m_ptCursorPos, dwSearchFlags, !lastSearch->m_bNoWrap,
+  CEPoint ptTextPos;
+  findtext_flags_t dwSearchFlags = ConvertSearchInfosToSearchFlags(lastSearch);
+  if (!FindText (lastSearch->m_sText, GetSearchPos(dwSearchFlags), dwSearchFlags, !lastSearch->m_bNoWrap,
       &ptTextPos))
     {
       return false;
@@ -5216,11 +5843,11 @@ FindText (const LastSearchInfos * lastSearch)
   m_bLastSearch = true;
   if (m_pszLastFindWhat != nullptr)
     free (m_pszLastFindWhat);
-  m_pszLastFindWhat = _tcsdup (lastSearch->m_sText);
+  m_pszLastFindWhat = tc::tcsdup (lastSearch->m_sText);
   m_dwLastSearchFlags = dwSearchFlags;
 
   //  Save search parameters to registry
-  VERIFY (RegSaveNumber (HKEY_CURRENT_USER, REG_EDITPAD, _T ("FindFlags"), m_dwLastSearchFlags));
+  VERIFY (AfxGetApp ()->WriteProfileInt (EDITPAD_SECTION, _T ("FindFlags"), m_dwLastSearchFlags));
 
   return true;
 }
@@ -5228,9 +5855,6 @@ FindText (const LastSearchInfos * lastSearch)
 void CCrystalTextView::
 OnEditFind ()
 {
-  CWinApp *pApp = AfxGetApp ();
-  ASSERT (pApp != nullptr);
-
   if (m_pFindTextDlg == nullptr)
     m_pFindTextDlg = new CFindTextDlg (this);
 
@@ -5245,9 +5869,7 @@ OnEditFind ()
     }
   else
     {
-      DWORD dwFlags;
-      if (!RegLoadNumber (HKEY_CURRENT_USER, REG_EDITPAD, _T ("FindFlags"), &dwFlags))
-        dwFlags = 0;
+      findtext_flags_t dwFlags = AfxGetApp ()->GetProfileInt (EDITPAD_SECTION, _T("FindFlags"), FIND_NO_CLOSE);
       ConvertSearchFlagsToLastSearchInfos(lastSearch, dwFlags);
     }
   m_pFindTextDlg->UseLastSearch ();
@@ -5255,16 +5877,15 @@ OnEditFind ()
   //  Take the current selection, if any
   if (IsSelection ())
     {
-      CPoint ptSelStart, ptSelEnd;
-      GetSelection (ptSelStart, ptSelEnd);
+      auto [ptSelStart, ptSelEnd] = GetSelection ();
       if (ptSelStart.y == ptSelEnd.y)
         GetText (ptSelStart, ptSelEnd, m_pFindTextDlg->m_sText);
     }
   else
     {
-      CPoint ptCursorPos = GetCursorPos ();
-      CPoint ptStart = WordToLeft (ptCursorPos);
-      CPoint ptEnd = WordToRight (ptCursorPos);
+      CEPoint ptCursorPos = GetCursorPos ();
+      CEPoint ptStart = WordToLeft (ptCursorPos);
+      CEPoint ptEnd = WordToRight (ptCursorPos);
       if (IsValidTextPos (ptStart) && IsValidTextPos (ptEnd) && ptStart != ptEnd)
         GetText (ptStart, ptEnd, m_pFindTextDlg->m_sText);
     }
@@ -5283,7 +5904,7 @@ OnEditRepeat ()
 {
   bool bEnable = m_bLastSearch;
   // Show dialog if no last find text
-  if (m_pszLastFindWhat == nullptr || _tcslen(m_pszLastFindWhat) == 0)
+  if (m_pszLastFindWhat == nullptr || tc::tcslen(m_pszLastFindWhat) == 0)
     bEnable = false;
   CString sText;
   if (bEnable)
@@ -5308,15 +5929,14 @@ OnEditRepeat ()
     {
       if (IsSelection())
         {
-          CPoint ptSelStart, ptSelEnd;
-          GetSelection (ptSelStart, ptSelEnd);
+          auto [ptSelStart, ptSelEnd] = GetSelection ();
           GetText (ptSelStart, ptSelEnd, sText);
         }
       else
         {
-          CPoint ptCursorPos = GetCursorPos ();
-          CPoint ptStart = WordToLeft (ptCursorPos);
-          CPoint ptEnd = WordToRight (ptCursorPos);
+          CEPoint ptCursorPos = GetCursorPos ();
+          CEPoint ptStart = WordToLeft (ptCursorPos);
+          CEPoint ptEnd = WordToRight (ptCursorPos);
           if (IsValidTextPos (ptStart) && IsValidTextPos (ptEnd) && ptStart != ptEnd)
             GetText (ptStart, ptEnd, sText);
         }
@@ -5324,7 +5944,7 @@ OnEditRepeat ()
         {
           bEnable = true;
           free(m_pszLastFindWhat);
-          m_pszLastFindWhat = _tcsdup (sText);
+          m_pszLastFindWhat = tc::tcsdup (sText);
           m_bLastSearch = true;
         }
     }
@@ -5334,21 +5954,14 @@ OnEditRepeat ()
     m_dwLastSearchFlags &= ~FIND_DIRECTION_UP;
   if (bEnable)
     {
-      CPoint ptFoundPos;
+      CEPoint ptFoundPos;
       //BEGIN SW
       // for correct backward search we need some changes:
-      CPoint ptSearchPos = m_ptCursorPos;
-      if( m_dwLastSearchFlags & FIND_DIRECTION_UP && IsSelection() )
-        {
-          CPoint ptDummy;
-          GetSelection( ptSearchPos, ptDummy );
-        }
-
-      if (! FindText(sText, ptSearchPos, m_dwLastSearchFlags,
+      if (! FindText(sText, GetSearchPos(m_dwLastSearchFlags), m_dwLastSearchFlags,
             (m_dwLastSearchFlags & FIND_NO_WRAP) == 0, &ptFoundPos))
         {
           CString prompt;
-          prompt.Format (LoadResString(IDS_EDIT_TEXT_NOT_FOUND).c_str(), (LPCTSTR)sText);
+          prompt.Format (LoadResString(IDS_EDIT_TEXT_NOT_FOUND).c_str(), (const tchar_t*)sText);
           AfxMessageBox (prompt, MB_ICONINFORMATION);
           return;
         }
@@ -5369,23 +5982,20 @@ void CCrystalTextView::
 OnEditMark ()
 {
   CString sText;
-  DWORD dwFlags;
-  if (!RegLoadNumber (HKEY_CURRENT_USER, REG_EDITPAD, _T ("MarkerFlags"), &dwFlags))
-    dwFlags = 0;
+  findtext_flags_t dwFlags = AfxGetApp ()->GetProfileInt (EDITPAD_SECTION, _T("MarkerFlags"), 0);
 
   //  Take the current selection, if any
   if (IsSelection ())
     {
-      CPoint ptSelStart, ptSelEnd;
-      GetSelection (ptSelStart, ptSelEnd);
+      auto[ptSelStart, ptSelEnd] = GetSelection ();
       if (ptSelStart.y == ptSelEnd.y)
         GetText (ptSelStart, ptSelEnd, sText);
     }
   else
     {
-      CPoint ptCursorPos = GetCursorPos ();
-      CPoint ptStart = WordToLeft (ptCursorPos);
-      CPoint ptEnd = WordToRight (ptCursorPos);
+      CEPoint ptCursorPos = GetCursorPos ();
+      CEPoint ptStart = WordToLeft (ptCursorPos);
+      CEPoint ptEnd = WordToRight (ptCursorPos);
       if (IsValidTextPos (ptStart) && IsValidTextPos (ptEnd) && ptStart != ptEnd)
         GetText (ptStart, ptEnd, sText);
     }
@@ -5395,7 +6005,7 @@ OnEditMark ()
   if (markerDlg.DoModal() == IDOK)
     {
       //  Save search parameters to registry
-      VERIFY (RegSaveNumber (HKEY_CURRENT_USER, REG_EDITPAD, _T ("MarkerFlags"), markerDlg.GetLastSearchFlags()));
+      VERIFY (AfxGetApp ()->WriteProfileInt (EDITPAD_SECTION, _T ("MarkerFlags"), markerDlg.GetLastSearchFlags()));
       m_pMarkers->SaveToRegistry();
     }
 }
@@ -5414,39 +6024,20 @@ OnFilePageSetup ()
   dlg.m_psd.hDevMode = pd.hDevMode;
   dlg.m_psd.hDevNames = pd.hDevNames;
   dlg.m_psd.Flags |= PSD_INHUNDREDTHSOFMILLIMETERS|PSD_MARGINS;
-  dlg.m_psd.rtMargin.left = DEFAULT_PRINT_MARGIN;
-  dlg.m_psd.rtMargin.right = DEFAULT_PRINT_MARGIN;
-  dlg.m_psd.rtMargin.top = DEFAULT_PRINT_MARGIN;
-  dlg.m_psd.rtMargin.bottom = DEFAULT_PRINT_MARGIN;
-  CReg reg;
-  if (reg.Open (HKEY_CURRENT_USER, REG_EDITPAD, KEY_READ))
-    {
-      DWORD dwTemp;
-      if (reg.LoadNumber (_T ("PageWidth"), &dwTemp))
-        dlg.m_psd.ptPaperSize.x = dwTemp;
-      if (reg.LoadNumber (_T ("PageHeight"), &dwTemp))
-        dlg.m_psd.ptPaperSize.y = dwTemp;
-      if (reg.LoadNumber (_T ("PageLeft"), &dwTemp))
-        dlg.m_psd.rtMargin.left = dwTemp;
-      if (reg.LoadNumber (_T ("PageRight"), &dwTemp))
-        dlg.m_psd.rtMargin.right = dwTemp;
-      if (reg.LoadNumber (_T ("PageTop"), &dwTemp))
-        dlg.m_psd.rtMargin.top = dwTemp;
-      if (reg.LoadNumber (_T ("PageBottom"), &dwTemp))
-        dlg.m_psd.rtMargin.bottom = dwTemp;
-    }
+  dlg.m_psd.ptPaperSize.x   = pApp->GetProfileInt(EDITPAD_SECTION, _T("PageWidth"),  dlg.m_psd.ptPaperSize.x);
+  dlg.m_psd.ptPaperSize.y   = pApp->GetProfileInt(EDITPAD_SECTION, _T("PageHeight"), dlg.m_psd.ptPaperSize.y);
+  dlg.m_psd.rtMargin.left   = pApp->GetProfileInt(EDITPAD_SECTION, _T("PageLeft"),   DEFAULT_PRINT_MARGIN);
+  dlg.m_psd.rtMargin.right  = pApp->GetProfileInt(EDITPAD_SECTION, _T("PageRight"),  DEFAULT_PRINT_MARGIN);
+  dlg.m_psd.rtMargin.top    = pApp->GetProfileInt(EDITPAD_SECTION, _T("PageTop"),    DEFAULT_PRINT_MARGIN);
+  dlg.m_psd.rtMargin.bottom = pApp->GetProfileInt(EDITPAD_SECTION, _T("PageBottom"), DEFAULT_PRINT_MARGIN);
   if (dlg.DoModal () == IDOK)
     {
-      CReg reg1;
-      if (reg1.Create (HKEY_CURRENT_USER, REG_EDITPAD, KEY_WRITE))
-        {
-          VERIFY (reg1.SaveNumber (_T ("PageWidth"), dlg.m_psd.ptPaperSize.x));
-          VERIFY (reg1.SaveNumber (_T ("PageHeight"), dlg.m_psd.ptPaperSize.y));
-          VERIFY (reg1.SaveNumber (_T ("PageLeft"), dlg.m_psd.rtMargin.left));
-          VERIFY (reg1.SaveNumber (_T ("PageRight"), dlg.m_psd.rtMargin.right));
-          VERIFY (reg1.SaveNumber (_T ("PageTop"), dlg.m_psd.rtMargin.top));
-          VERIFY (reg1.SaveNumber (_T ("PageBottom"), dlg.m_psd.rtMargin.bottom));
-        }
+      VERIFY (pApp->WriteProfileInt (EDITPAD_SECTION, _T ("PageWidth"), dlg.m_psd.ptPaperSize.x));
+      VERIFY (pApp->WriteProfileInt (EDITPAD_SECTION, _T ("PageHeight"), dlg.m_psd.ptPaperSize.y));
+      VERIFY (pApp->WriteProfileInt (EDITPAD_SECTION, _T ("PageLeft"), dlg.m_psd.rtMargin.left));
+      VERIFY (pApp->WriteProfileInt (EDITPAD_SECTION, _T ("PageRight"), dlg.m_psd.rtMargin.right));
+      VERIFY (pApp->WriteProfileInt (EDITPAD_SECTION, _T ("PageTop"), dlg.m_psd.rtMargin.top));
+      VERIFY (pApp->WriteProfileInt (EDITPAD_SECTION, _T ("PageBottom"), dlg.m_psd.rtMargin.bottom));
       pApp->SelectPrinter (dlg.m_psd.hDevNames, dlg.m_psd.hDevMode, false);
     }
 }
@@ -5461,8 +6052,8 @@ void CCrystalTextView::ToggleBookmark(int nLine)
   ASSERT(nLine >= 0 && nLine < GetLineCount());
   if (m_pTextBuffer != nullptr)
     {
-      DWORD dwFlags = GetLineFlags (nLine);
-      DWORD dwMask = LF_BOOKMARKS;
+      lineflags_t dwFlags = GetLineFlags (nLine);
+      lineflags_t dwMask = LF_BOOKMARKS;
       m_pTextBuffer->SetLineFlag (nLine, dwMask, (dwFlags & dwMask) == 0, false);
       const int nBookmarkLine = m_pTextBuffer->GetLineWithFlag (LF_BOOKMARKS);
       if (nBookmarkLine >= 0)
@@ -5488,7 +6079,7 @@ OnNextBookmark ()
       int nLine = m_pTextBuffer->FindNextBookmarkLine (m_ptCursorPos.y);
       if (nLine >= 0)
         {
-          CPoint pt (0, nLine);
+          CEPoint pt (0, nLine);
           ASSERT_VALIDTEXTPOS (pt);
           SetCursorPos (pt);
           SetSelection (pt, pt);
@@ -5506,7 +6097,7 @@ OnPrevBookmark ()
       int nLine = m_pTextBuffer->FindPrevBookmarkLine (m_ptCursorPos.y);
       if (nLine >= 0)
         {
-          CPoint pt (0, nLine);
+          CEPoint pt (0, nLine);
           ASSERT_VALIDTEXTPOS (pt);
           SetCursorPos (pt);
           SetSelection (pt, pt);
@@ -5549,12 +6140,6 @@ OnUpdateClearAllBookmarks (CCmdUI * pCmdUI)
   pCmdUI->Enable (m_bBookmarkExist);
 }
 
-bool CCrystalTextView::
-GetViewTabs ()
-{
-  return m_bViewTabs;
-}
-
 void CCrystalTextView::
 SetViewTabs (bool bViewTabs)
 {
@@ -5578,12 +6163,6 @@ SetViewEols (bool bViewEols, bool bDistinguishEols)
     }
 }
 
-DWORD CCrystalTextView::
-GetFlags ()
-{
-  return m_dwFlags;
-}
-
 void CCrystalTextView::
 SetFlags (DWORD dwFlags)
 {
@@ -5595,16 +6174,12 @@ SetFlags (DWORD dwFlags)
     }
 }
 
-bool CCrystalTextView::
-GetSelectionMargin ()
-{
-  return m_bSelMargin;
-}
-
-bool CCrystalTextView::
-GetViewLineNumbers () const
+int CCrystalTextView::
+GetTopMarginHeight()
 {
-  return m_bViewLineNumbers;
+  if (!m_bTopMargin)
+    return 0;
+  return GetLineHeight();
 }
 
 /**
@@ -5635,7 +6210,7 @@ GetMarginWidth (CDC *pdc /*= nullptr*/)
   if (m_bSelMargin)
     {
       if (pdc == nullptr || !pdc->IsPrinting ())
-        nMarginWidth += MARGIN_ICON_WIDTH  + 7;  // Width for icon markers and some margin
+        nMarginWidth += GetMarginIconSize () + 7;  // Width for icon markers and some margin
     }
   else
     {
@@ -5646,32 +6221,6 @@ GetMarginWidth (CDC *pdc /*= nullptr*/)
   return nMarginWidth;
 }
 
-bool CCrystalTextView::
-GetSmoothScroll ()
-const
-{
-  return m_bSmoothScroll;
-}
-
-void CCrystalTextView::SetSmoothScroll (bool bSmoothScroll)
-{
-  m_bSmoothScroll = bSmoothScroll;
-}
-
-//  [JRT]
-bool CCrystalTextView::
-GetDisableDragAndDrop ()
-const
-{
-  return m_bDisableDragAndDrop;
-}
-
-//  [JRT]
-void CCrystalTextView::SetDisableDragAndDrop (bool bDDAD)
-{
-  m_bDisableDragAndDrop = bDDAD;
-}
-
 void CCrystalTextView::CopyProperties (CCrystalTextView *pSource)
 {
   m_nTopLine = pSource->m_nTopLine;
@@ -5679,6 +6228,7 @@ void CCrystalTextView::CopyProperties (CCrystalTextView *pSource)
   m_bViewTabs = pSource->m_bViewTabs;
   m_bViewEols = pSource->m_bViewEols;
   m_bDistinguishEols = pSource->m_bDistinguishEols;
+  m_bTopMargin = pSource->m_bTopMargin;
   m_bSelMargin = pSource->m_bSelMargin;
   m_bViewLineNumbers = pSource->m_bViewLineNumbers;
   m_bSmoothScroll = pSource->m_bSmoothScroll;
@@ -5699,8 +6249,7 @@ void CCrystalTextView::CopyProperties (CCrystalTextView *pSource)
 BOOL CCrystalTextView::
 OnMouseWheel (UINT nFlags, short zDelta, CPoint pt)
 {
-  SCROLLINFO si = {0};
-  si.cbSize = sizeof (si);
+  SCROLLINFO si{ sizeof(si) };
   si.fMask = SIF_PAGE | SIF_RANGE;
   VERIFY (GetScrollInfo (SB_VERT, &si));
 
@@ -5713,33 +6262,54 @@ OnMouseWheel (UINT nFlags, short zDelta, CPoint pt)
 
   ScrollToSubLine(nNewTopSubLine, true);
   UpdateSiblingScrollPos(false);
+  UpdateCaret ();
 
   return CView::OnMouseWheel (nFlags, zDelta, pt);
 }
 
 void CCrystalTextView::
+OnMouseHWheel (UINT nFlags, short zDelta, CPoint pt)
+{
+  SCROLLINFO si = { sizeof(si) };
+  si.fMask = SIF_POS | SIF_RANGE;
+  VERIFY (GetScrollInfo (SB_HORZ, &si));
+
+  int nCurPos = si.nPos + zDelta / 40;
+  if (nCurPos < si.nMin)
+    nCurPos = si.nMin;
+  else if (nCurPos > si.nMax)
+    nCurPos = si.nMax;
+
+  ScrollToChar (nCurPos, true);
+  UpdateCaret ();
+  UpdateSiblingScrollPos (true);
+
+  CView::OnMouseHWheel (nFlags, zDelta, pt);
+}
+
+void CCrystalTextView::
 OnSourceType (UINT nId)
 {
-  SetTextType ((CCrystalTextView::TextType) (nId - ID_SOURCE_PLAIN));
+  SetTextType ((CrystalLineParser::TextType) (nId - ID_SOURCE_PLAIN));
   Invalidate ();
 }
 
 void CCrystalTextView::
 OnUpdateSourceType (CCmdUI * pCmdUI)
 {
-  pCmdUI->SetRadio (m_SourceDefs + (pCmdUI->m_nID - ID_SOURCE_PLAIN) == m_CurSourceDef);
+  pCmdUI->SetRadio (CrystalLineParser::m_SourceDefs + (pCmdUI->m_nID - ID_SOURCE_PLAIN) == m_CurSourceDef);
 }
 
 int
-bracetype (TCHAR c)
+bracetype (tchar_t c)
 {
-  static LPCTSTR braces = _T("{}()[]<>");
-  LPCTSTR pos = _tcschr (braces, c);
+  static const tchar_t* braces = _T("{}()[]<>");
+  const tchar_t* pos = tc::tcschr (braces, c);
   return pos != nullptr ? (int) (pos - braces) + 1 : 0;
 }
 
 int
-bracetype (LPCTSTR s)
+bracetype (const tchar_t* s)
 {
   if (s[1])
     return 0;
@@ -5749,9 +6319,9 @@ bracetype (LPCTSTR s)
 void CCrystalTextView::
 OnMatchBrace ()
 {
-  CPoint ptCursorPos = GetCursorPos ();
+  CEPoint ptCursorPos = GetCursorPos ();
   int nLength = m_pTextBuffer->GetLineLength (ptCursorPos.y);
-  LPCTSTR pszText = m_pTextBuffer->GetLineChars (ptCursorPos.y), pszEnd = pszText + ptCursorPos.x;
+  const tchar_t* pszText = m_pTextBuffer->GetLineChars (ptCursorPos.y), *pszEnd = pszText + ptCursorPos.x;
   bool bAfter = false;
   int nType = 0;
   if (ptCursorPos.x < nLength)
@@ -5761,7 +6331,7 @@ OnMatchBrace ()
         {
           bAfter = false;
         }
-      else if (!nType && ptCursorPos.x > 0)
+      else if (ptCursorPos.x > 0)
         {
           nType = bracetype (pszEnd[-1]);
           bAfter = true;
@@ -5787,12 +6357,12 @@ OnMatchBrace ()
           if (!(nOther & 1))
             pszEnd++;
         }
-      LPCTSTR pszOpenComment = m_CurSourceDef->opencomment,
-        pszCloseComment = m_CurSourceDef->closecomment,
-        pszCommentLine = m_CurSourceDef->commentline, pszTest;
-      int nOpenComment = (int) _tcslen (pszOpenComment),
-        nCloseComment = (int) _tcslen (pszCloseComment),
-        nCommentLine = (int) _tcslen (pszCommentLine);
+      const tchar_t* pszOpenComment = m_CurSourceDef->opencomment,
+        *pszCloseComment = m_CurSourceDef->closecomment,
+        *pszCommentLine = m_CurSourceDef->commentline, *pszTest;
+      int nOpenComment = (int) tc::tcslen (pszOpenComment),
+        nCloseComment = (int) tc::tcslen (pszCloseComment),
+        nCommentLine = (int) tc::tcslen (pszCommentLine);
       if (nOther & 1)
         {
           for (;;)
@@ -5800,7 +6370,7 @@ OnMatchBrace ()
               while (--pszEnd >= pszText)
                 {
                   pszTest = pszEnd - nOpenComment + 1;
-                  if (pszTest >= pszText && !_tcsnicmp (pszTest, pszOpenComment, nOpenComment))
+                  if (pszTest >= pszText && !tc::tcsnicmp (pszTest, pszOpenComment, nOpenComment))
                     {
                       nComment--;
                       pszEnd = pszTest;
@@ -5810,7 +6380,7 @@ OnMatchBrace ()
                         }
                     }
                   pszTest = pszEnd - nCloseComment + 1;
-                  if (pszTest >= pszText && !_tcsnicmp (pszTest, pszCloseComment, nCloseComment))
+                  if (pszTest >= pszText && !tc::tcsnicmp (pszTest, pszCloseComment, nCloseComment))
                     {
                       nComment++;
                       pszEnd = pszTest;
@@ -5822,7 +6392,7 @@ OnMatchBrace ()
                   if (!nComment)
                     {
                       pszTest = pszEnd - nCommentLine + 1;
-                      if (pszTest >= pszText && !_tcsnicmp (pszTest, pszCommentLine, nCommentLine))
+                      if (pszTest >= pszText && !tc::tcsnicmp (pszTest, pszCommentLine, nCommentLine))
                         {
                           break;
                         }
@@ -5858,7 +6428,7 @@ OnMatchBrace ()
         }
       else
         {
-          LPCTSTR pszBegin = pszText;
+          const tchar_t* pszBegin = pszText;
           pszText = pszEnd;
           pszEnd = pszBegin + nLength;
           int nLines = m_pTextBuffer->GetLineCount ();
@@ -5867,7 +6437,7 @@ OnMatchBrace ()
               while (pszText < pszEnd)
                 {
                   pszTest = pszText + nCloseComment;
-                  if (pszTest <= pszEnd && !_tcsnicmp (pszText, pszCloseComment, nCloseComment))
+                  if (pszTest <= pszEnd && !tc::tcsnicmp (pszText, pszCloseComment, nCloseComment))
                     {
                       nComment--;
                       pszText = pszTest;
@@ -5877,7 +6447,7 @@ OnMatchBrace ()
                         }
                     }
                   pszTest = pszText + nOpenComment;
-                  if (pszTest <= pszEnd && !_tcsnicmp (pszText, pszOpenComment, nOpenComment))
+                  if (pszTest <= pszEnd && !tc::tcsnicmp (pszText, pszOpenComment, nOpenComment))
                     {
                       nComment++;
                       pszText = pszTest;
@@ -5889,7 +6459,7 @@ OnMatchBrace ()
                   if (!nComment)
                     {
                       pszTest = pszText + nCommentLine;
-                      if (pszTest <= pszEnd && !_tcsnicmp (pszText, pszCommentLine, nCommentLine))
+                      if (pszTest <= pszEnd && !tc::tcsnicmp (pszText, pszCommentLine, nCommentLine))
                         {
                           break;
                         }
@@ -5931,9 +6501,9 @@ OnMatchBrace ()
 void CCrystalTextView::
 OnUpdateMatchBrace (CCmdUI * pCmdUI)
 {
-  CPoint ptCursorPos = GetCursorPos ();
+  CEPoint ptCursorPos = GetCursorPos ();
   int nLength = m_pTextBuffer->GetLineLength (ptCursorPos.y);
-  LPCTSTR pszText = m_pTextBuffer->GetLineChars (ptCursorPos.y) + ptCursorPos.x;
+  const tchar_t* pszText = m_pTextBuffer->GetLineChars (ptCursorPos.y) + ptCursorPos.x;
   pCmdUI->Enable (ptCursorPos.x < nLength && (bracetype (*pszText) || ptCursorPos.x > 0 && bracetype (pszText[-1])) || ptCursorPos.x > 0 && bracetype (pszText[-1]));
 }
 
@@ -5947,26 +6517,31 @@ OnEditGoTo ()
 void CCrystalTextView::
 OnUpdateToggleSourceHeader (CCmdUI * pCmdUI)
 {
-  pCmdUI->Enable (m_CurSourceDef->type == SRC_C);
+  pCmdUI->Enable (m_CurSourceDef->type == CrystalLineParser::SRC_C);
 }
 
 void CCrystalTextView::
 OnToggleSourceHeader ()
 {
-  if (m_CurSourceDef->type == SRC_C)
+  auto FileExist = [](const tchar_t* lpszPath) -> bool
+    {
+      CFileStatus status;
+      return CFile::GetStatus(lpszPath, status) != 0;
+    };
+  if (m_CurSourceDef->type == CrystalLineParser::SRC_C)
     {
       CDocument *pDoc = GetDocument ();
       ASSERT (pDoc != nullptr);
       CString sFilePath = pDoc->GetPathName (), sOriginalPath = sFilePath;
-      if (!_tcsicmp (sFilePath.Right (2), _T (".c")))
+      if (!tc::tcsicmp (sFilePath.Right (2), _T (".c")))
         {
           sFilePath = sFilePath.Left (sFilePath.GetLength () - 1) + _T ('h');
         }
-      else if (!_tcsicmp (sFilePath.Right (4), _T (".cpp")))
+      else if (!tc::tcsicmp (sFilePath.Right (4), _T (".cpp")))
         {
           sFilePath = sFilePath.Left (sFilePath.GetLength () - 3) + _T ('h');
         }
-      else if (!_tcsicmp (sFilePath.Right (4), _T (".inl")))
+      else if (!tc::tcsicmp (sFilePath.Right (4), _T (".inl")))
         {
           sFilePath = sFilePath.Left (sFilePath.GetLength () - 3) + _T ('c');
           if (!FileExist(sFilePath))
@@ -5974,7 +6549,7 @@ OnToggleSourceHeader ()
               sFilePath = sFilePath + _T ("pp");
             }
         }
-      else if (!_tcsicmp (sFilePath.Right (4), _T (".hpp")))
+      else if (!tc::tcsicmp (sFilePath.Right (4), _T (".hpp")))
         {
           sFilePath = sFilePath.Left (sFilePath.GetLength () - 3) + _T ("inl");
           if (!FileExist(sFilePath))
@@ -5986,7 +6561,7 @@ OnToggleSourceHeader ()
                 }
             }
         }
-      else if (!_tcsicmp (sFilePath.Right (2), _T (".h")))
+      else if (!tc::tcsicmp (sFilePath.Right (2), _T (".h")))
         {
           sFilePath = sFilePath.Left (sFilePath.GetLength () - 1) + _T ("hpp");
           if (!FileExist(sFilePath))
@@ -6011,7 +6586,7 @@ OnToggleSourceHeader ()
                 {
                   m_ptCursorLast.x = m_ptCursorLast.y = 0;
                   ASSERT_VALIDTEXTPOS (m_ptCursorLast);
-                  CPoint ptCursorPos = m_ptCursorLast;
+                  CEPoint ptCursorPos = m_ptCursorLast;
                   SetCursorPos (ptCursorPos);
                   SetSelection (ptCursorPos, ptCursorPos);
                   SetAnchor (ptCursorPos);
@@ -6024,6 +6599,23 @@ OnToggleSourceHeader ()
 }
 
 void CCrystalTextView::
+OnUpdateTopMargin (CCmdUI * pCmdUI)
+{
+  pCmdUI->SetCheck (m_bTopMargin);
+}
+
+void CCrystalTextView::
+OnTopMargin ()
+{
+  ASSERT (m_CurSourceDef != nullptr);
+  if (m_bTopMargin)
+    m_CurSourceDef->flags &= ~SRCOPT_TOPMARGIN;
+  else
+    m_CurSourceDef->flags |= SRCOPT_TOPMARGIN;
+  SetTopMargin (!m_bTopMargin);
+}
+
+void CCrystalTextView::
 OnUpdateSelMargin (CCmdUI * pCmdUI)
 {
   pCmdUI->SetCheck (m_bSelMargin);
@@ -6034,15 +6626,10 @@ OnSelMargin ()
 {
   ASSERT (m_CurSourceDef != nullptr);
   if (m_bSelMargin)
-    {
-      m_CurSourceDef->flags &= ~SRCOPT_SELMARGIN;
-      SetSelectionMargin (false);
-    }
+    m_CurSourceDef->flags &= ~SRCOPT_SELMARGIN;
   else
-    {
-      m_CurSourceDef->flags |= SRCOPT_SELMARGIN;
-      SetSelectionMargin (true);
-    }
+    m_CurSourceDef->flags |= SRCOPT_SELMARGIN;
+  SetSelectionMargin (!m_bSelMargin);
 }
 
 void CCrystalTextView::
@@ -6077,10 +6664,22 @@ OnForceRedraw ()
 void CCrystalTextView::
 OnToggleColumnSelection ()
 {
-  m_bColumnSelection = !m_bColumnSelection;
+  m_bRectangularSelection = !m_bRectangularSelection;
   Invalidate ();
 }
 
+void CCrystalTextView::SetRenderingMode(RENDERING_MODE nRenderingMode)
+{
+#ifdef _WIN64
+  if (nRenderingMode == RENDERING_MODE::GDI)
+    m_pCrystalRenderer.reset(new CCrystalRendererGDI());
+  else
+    m_pCrystalRenderer.reset(new CCrystalRendererDirectWrite(static_cast<int>(nRenderingMode)));
+  m_pCrystalRenderer->SetFont(m_lfBaseFont);
+#endif
+  m_nRenderingMode = nRenderingMode;
+}
+
 //BEGIN SW
 bool CCrystalTextView::GetWordWrapping() const
 {
@@ -6111,16 +6710,6 @@ CCrystalParser *CCrystalTextView::SetParser( CCrystalParser *pParser )
 }
 //END SW
 
-bool CCrystalTextView::GetEnableHideLines () const
-{
-  return m_bHideLines;
-}
-
-void CCrystalTextView::SetEnableHideLines (bool bHideLines)
-{
-  m_bHideLines = bHideLines;
-}
-
 /**
  * @brief Return whether a line is visible.
  */
@@ -6193,7 +6782,7 @@ void CCrystalTextView::OnChar( wchar_t nChar, UINT nRepCnt, UINT nFlags )
     }
 
   // add character to incremental search string and search
-  *m_pstrIncrementalSearchString += (TCHAR) nChar;
+  *m_pstrIncrementalSearchString += (tchar_t) nChar;
   OnEditFindIncremental();
 }
 
@@ -6232,13 +6821,12 @@ void CCrystalTextView::OnEditFindIncremental( bool bFindNextOccurence /*= false*
 
   // otherwise search next occurence of search string, 
   // starting at current cursor position
-  CPoint       matchStart, matchEnd;
+  CEPoint      matchStart, matchEnd;
 
   // calculate start point for search
   if( bFindNextOccurence )
     {
-      CPoint   selStart, selEnd;
-      GetSelection( selStart, selEnd );
+      auto[selStart, selEnd] = GetSelection ();
       m_incrementalSearchStartPos = (m_bIncrementalSearchBackward)? selStart : selEnd;
     }
 
@@ -6377,7 +6965,7 @@ void CCrystalTextView::OnUpdateStatusMessage( CStatusBar *pStatusBar )
     formatid = IDS_FIND_INCREMENTAL_BACKWARD;
   else
     return;
-  strFormat.Format( LoadResString(formatid).c_str(), (LPCTSTR)*m_pstrIncrementalSearchString );
+  strFormat.Format( LoadResString(formatid).c_str(), (const tchar_t*)*m_pstrIncrementalSearchString );
 
   pStatusBar->SetPaneText( 0, strFormat );
   bUpdatedAtLastCall = false;
@@ -6415,23 +7003,24 @@ int CCrystalTextView::GetCharCellCountUnicodeChar(const wchar_t *pch)
           int nWidthArray[256];
           wchar_t nStart = ch/256*256;
           wchar_t nEnd = nStart + 255;
-          CDC *pdc = GetDC();
-          CFont *pOldFont = pdc->SelectObject(GetFont());
-          GetCharWidth32(pdc->m_hDC, nStart, nEnd, nWidthArray);
+          m_pCrystalRenderer->GetCharWidth(nStart, nEnd, nWidthArray);
           int nCharWidth = GetCharWidth();
+          const ViewableWhitespaceChars * lpspc = GetViewableWhitespaceChars(GetACP(), m_nRenderingMode != RENDERING_MODE::GDI);
           for (int i = 0; i < 256; i++) 
             {
+              wchar_t ch2 = static_cast<wchar_t>(nStart + i);
               if (nCharWidth * 15 < nWidthArray[i] * 10)
-                m_iChDoubleWidthFlags[(nStart+i)/32] |= 1 << (i % 32);
+                {
+                  if (ch2 != lpspc->c_space[0] && ch2 != lpspc->c_tab[0])
+                    m_iChDoubleWidthFlags[ch2 / 32] |= 1 << (i % 32);
+                }
               else
                 {
-                  wchar_t ch2 = static_cast<wchar_t>(nStart + i);
                   if (wcwidth(ch2) > 1)
-                    m_iChDoubleWidthFlags[(nStart + i) / 32] |= 1 << (i % 32);
+                    m_iChDoubleWidthFlags[ch2 / 32] |= 1 << (i % 32);
                 }
             }
           m_bChWidthsCalculated[ch / 256] = true;
-          pdc->SelectObject(pOldFont);
         }
     }
   if (m_iChDoubleWidthFlags[ch / 32] & (1 << (ch % 32)))
@@ -6451,19 +7040,16 @@ void CCrystalTextView::ResetCharWidths ()
 }
 
 // This function assumes selection is in one line
-void CCrystalTextView::EnsureVisible (CPoint ptStart, CPoint ptEnd)
+void CCrystalTextView::EnsureVisible (CEPoint ptStart, CEPoint ptEnd)
 {
   //  Scroll vertically
   //BEGIN SW
   int nSubLineCount = GetSubLineCount();
   int nNewTopSubLine = m_nTopSubLine;
-  CPoint subLinePos;
-  CPoint subLinePosEnd;
+  CEPoint subLinePos;
 
   CharPosToPoint( ptStart.y, ptStart.x, subLinePos );
   subLinePos.y += GetSubLineIndex( ptStart.y );
-  CharPosToPoint( ptEnd.y, ptEnd.x, subLinePosEnd );
-  subLinePosEnd.y += GetSubLineIndex( ptEnd.y );
 
   if( subLinePos.y >= nNewTopSubLine + GetScreenLines() )
     nNewTopSubLine = subLinePos.y - GetScreenLines() + 1;
@@ -6499,47 +7085,66 @@ void CCrystalTextView::EnsureVisible (CPoint ptStart, CPoint ptEnd)
   //  Scroll horizontally
   //BEGIN SW
   // we do not need horizontally scrolling, if we wrap the words
-  if( m_bWordWrap )
+  if( GetTextLayoutMode () == TEXTLAYOUT_WORDWRAP )
     return;
   //END SW
   int nActualPos = CalculateActualOffset (ptStart.y, ptStart.x);
-  int nActualEndPos = CalculateActualOffset (ptEnd.y, ptEnd.x);
   int nNewOffset = m_nOffsetChar;
   const int nScreenChars = GetScreenChars ();
-  const int nBeginOffset = nActualPos - m_nOffsetChar;
-  const int nEndOffset = nActualEndPos - m_nOffsetChar;
-  const int nSelLen = nActualEndPos - nActualPos;
 
-  // Selection fits to screen, scroll whole selection visible
-  if (nSelLen < nScreenChars)
+  if (ptStart == ptEnd)
     {
-      // Begin of selection not visible 
-      if (nBeginOffset > nScreenChars)
+      // Keep 5 chars visible right to cursor
+      if (nActualPos > nNewOffset + nScreenChars - 5)
         {
-          // Scroll so that there is max 5 chars margin at end
-          if (nScreenChars - nSelLen > 5)
-            nNewOffset = nActualPos + 5 - nScreenChars + nSelLen;
-          else
-            nNewOffset = nActualPos - 5;
+          // Add 10 chars width space after line
+          nNewOffset = nActualPos - nScreenChars + 10;
         }
-      else if (nBeginOffset < 0)
+      // Keep 5 chars visible left to cursor
+      if (nActualPos < nNewOffset + 5)
         {
-          // Scroll so that there is max 5 chars margin at begin
-          if (nScreenChars - nSelLen >= 5)
-            nNewOffset = nActualPos - 5;
-          else
-            nNewOffset = nActualPos - 5 - nScreenChars + nSelLen;
+          // Jump by 10 char steps, so user sees previous letters too
+          nNewOffset = nActualPos - 10;
+        }
+    }
+  else
+    {
+      int nActualEndPos = CalculateActualOffset (ptEnd.y, ptEnd.x);
+      const int nBeginOffset = nActualPos - m_nOffsetChar;
+      const int nEndOffset = nActualEndPos - m_nOffsetChar;
+      const int nSelLen = nActualEndPos - nActualPos;
+
+      // Selection fits to screen, scroll whole selection visible
+      if (nSelLen < nScreenChars)
+        {
+          // Begin of selection not visible 
+          if (nBeginOffset > nScreenChars)
+            {
+              // Scroll so that there is max 5 chars margin at end
+              if (nScreenChars - nSelLen > 5)
+                nNewOffset = nActualPos + 5 - nScreenChars + nSelLen;
+              else
+                nNewOffset = nActualPos - 5;
+            }
+          else if (nBeginOffset < 0)
+            {
+              // Scroll so that there is max 5 chars margin at begin
+              if (nScreenChars - nSelLen >= 5)
+                nNewOffset = nActualPos - 5;
+              else
+                nNewOffset = nActualPos - 5 - nScreenChars + nSelLen;
+            }
+          // End of selection not visible
+          else if (nEndOffset > nScreenChars ||
+              nEndOffset < 0)
+            {
+              nNewOffset = nActualPos - 5;
+            }
         }
-      // End of selection not visible
-      else if (nEndOffset > nScreenChars ||
-          nEndOffset < 0)
+      else // Selection does not fit screen so scroll to begin of selection
         {
           nNewOffset = nActualPos - 5;
         }
-     }
-  else // Selection does not fit screen so scroll to begin of selection
-    {
-      nNewOffset = nActualPos - 5;
     }
 
   // Horiz scroll limit to longest line + one screenwidth
@@ -6560,21 +7165,124 @@ void CCrystalTextView::EnsureVisible (CPoint ptStart, CPoint ptEnd)
 // Analyze the first line of file to detect its type
 // Mainly it works for xml files
 bool CCrystalTextView::
-SetTextTypeByContent (LPCTSTR pszContent)
+SetTextTypeByContent (const tchar_t* pszContent)
 {
   RxNode *rxnode = nullptr;
   RxMatchRes rxmatch;
   int nLen;
-  if (::FindStringHelper(pszContent, pszContent, _T("^\\s*\\<\\?xml\\s+.+?\\?\\>\\s*$"),
+  if (::FindStringHelper(pszContent, tc::tcslen(pszContent), pszContent, _T("^\\s*\\<\\?xml\\s+.+?\\?\\>\\s*$"),
       FIND_REGEXP, nLen, rxnode, &rxmatch) == 0)
     {
       if (rxnode)
         RxFree (rxnode);
-      return SetTextType(CCrystalTextView::SRC_XML);
+      return SetTextType(CrystalLineParser::SRC_XML);
     }
   if (rxnode)
     RxFree (rxnode);
   return false;
 }
 
+void CCrystalTextView::
+AutoFitColumn (int nColumn)
+{
+  int nLastColumn = 0;
+  int nLastColumnWidth = 0;
+  const int nTabSize = GetTabSize ();
+  std::vector<int> aColumnWidths;
+  const int nScreenChars = GetScreenChars ();
+  const int nMaxColumnWidth = nScreenChars < 1 ? 1 : nScreenChars - 1;
+  for (auto& pbuf : m_pTextBuffer->GetTextBufferList ())
+  {
+      const tchar_t sep = pbuf->GetFieldDelimiter ();
+      const int quote = pbuf->GetFieldEnclosure ();
+      const int nLineCount = pbuf->GetLineCount ();
+      for (int i = 0; i < nLineCount; ++i)
+        {
+          bool bInQuote = false;
+          int nColumn2 = 0;
+          int nColumnWidth = 0;
+          const tchar_t* pszChars = pbuf->GetLineChars (i);
+          const size_t nLineLength = pbuf->GetFullLineLength (i);
+          for (size_t j = 0; j < nLineLength; j += U16_IS_SURROGATE (pszChars[j]) ? 2 : 1)
+            {
+              bool bDelimiterOrNewLine = false;
+              tchar_t c = pszChars[j];
+              if (c == quote)
+                bInQuote = !bInQuote;
+              if (!bInQuote && c == sep)
+                {
+                  bDelimiterOrNewLine = true;
+                  ++nColumnWidth;
+                }
+              else if (c == '\r' || c == '\n')
+                {
+                  if (m_bWordWrap)
+                    {
+                      if (c == '\r')
+                        {
+                          if (j == nLineLength - 1 || pszChars[j + 1] != '\n')
+                            {
+                              nColumnWidth += 2;
+                              bDelimiterOrNewLine = true;
+                            }
+                        }
+                      else
+                        {
+                          if (j > 0 && pszChars[j - 1] == '\r')
+                            nColumnWidth += 4;
+                          else
+                            nColumnWidth += 2;
+                          bDelimiterOrNewLine = true;
+                        }
+                    }
+                  else
+                    nColumnWidth += GetCharCellCountFromChar (pszChars + j);
+                }
+              else if (c == '\t')
+                nColumnWidth ++;
+              else
+                nColumnWidth += GetCharCellCountFromChar (pszChars + j);
+
+              if (bDelimiterOrNewLine)
+                {
+                  if (nColumnWidth > nMaxColumnWidth)
+                    nColumnWidth = nMaxColumnWidth;
+                  if (static_cast<int>(aColumnWidths.size ()) < nColumn2 + 1)
+                    aColumnWidths.resize (nColumn2 + 1, nTabSize);
+                  if (aColumnWidths[nColumn2] < nColumnWidth)
+                    aColumnWidths[nColumn2] = nColumnWidth;
+                  nColumnWidth = 0;
+                  if (c == sep)
+                    ++nColumn2;
+                }
+            }
+          if (nLastColumn < nColumn2)
+            {
+              nLastColumn = nColumn2;
+              nLastColumnWidth = 0;
+            }
+          if (nLastColumnWidth < nColumnWidth)
+              nLastColumnWidth = nColumnWidth;
+        }
+    }
+
+  aColumnWidths.resize (nLastColumn + 1, nTabSize);
+  if (aColumnWidths[nLastColumn] < nLastColumnWidth)
+    aColumnWidths[nLastColumn] = nLastColumnWidth;
+
+  for (size_t nColumn2 = 0; nColumn2 < aColumnWidths.size (); ++nColumn2)
+    {
+      if (nColumn == -1 || nColumn == static_cast<int>(nColumn2))
+        m_pTextBuffer->SetColumnWidth (static_cast<int>(nColumn2), aColumnWidths[nColumn2]);
+    }
+  m_pTextBuffer->InvalidateColumns ();
+}
+
+CCrystalTextView::TextLayoutMode CCrystalTextView::GetTextLayoutMode () const
+{
+  if (m_pTextBuffer && m_pTextBuffer->GetTableEditing ())
+    return m_bWordWrap ? TEXTLAYOUT_TABLE_WORDWRAP : TEXTLAYOUT_TABLE_NOWORDWRAP;
+  return m_bWordWrap ? TEXTLAYOUT_WORDWRAP : TEXTLAYOUT_NOWORDWRAP;
+}
+
 ////////////////////////////////////////////////////////////////////////////