diff options
Diffstat (limited to 'win32/ScintillaWin.cxx')
-rw-r--r-- | win32/ScintillaWin.cxx | 93 |
1 files changed, 87 insertions, 6 deletions
diff --git a/win32/ScintillaWin.cxx b/win32/ScintillaWin.cxx index d0f99c532..a509ef0ec 100644 --- a/win32/ScintillaWin.cxx +++ b/win32/ScintillaWin.cxx @@ -197,6 +197,7 @@ class ScintillaWin : virtual void StartDrag(); sptr_t WndPaint(uptr_t wParam); sptr_t HandleComposition(uptr_t wParam, sptr_t lParam); + UINT CodePageOfDocument(); virtual bool ValidCodePage(int codePage) const; virtual sptr_t DefWndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam); virtual bool SetIdle(bool on); @@ -215,6 +216,7 @@ class ScintillaWin : virtual int GetCtrlID(); virtual void NotifyParent(SCNotification scn); virtual void NotifyDoubleClick(Point pt, bool shift, bool ctrl, bool alt); + virtual std::string CaseMapString(const std::string &s, int caseMapping); virtual void Copy(); virtual void CopyAllowLine(); virtual bool CanPaste(); @@ -587,6 +589,10 @@ static unsigned int SciMessageFromEM(unsigned int iMessage) { } static UINT CodePageFromCharSet(DWORD characterSet, UINT documentCodePage) { + if (documentCodePage == SC_CP_UTF8) { + // The system calls here are a little slow so avoid if known case. + return SC_CP_UTF8; + } CHARSETINFO ci = { 0, 0, { { 0, 0, 0, 0 }, { 0, 0 } } }; BOOL bci = ::TranslateCharsetInfo((DWORD*)characterSet, &ci, TCI_SRCCHARSET); @@ -604,6 +610,10 @@ static UINT CodePageFromCharSet(DWORD characterSet, UINT documentCodePage) { return cp; } +UINT ScintillaWin::CodePageOfDocument() { + return CodePageFromCharSet(vs.styles[STYLE_DEFAULT].characterSet, pdoc->dbcsCodePage); +} + sptr_t ScintillaWin::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { try { //Platform::DebugPrintf("S M:%x WP:%x L:%x\n", iMessage, wParam, lParam); @@ -800,8 +810,7 @@ sptr_t ScintillaWin::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam UTF8FromUTF16(wcs, 1, utfval, len); AddCharUTF(utfval, len); } else { - UINT cpDest = CodePageFromCharSet( - vs.styles[STYLE_DEFAULT].characterSet, pdoc->dbcsCodePage); + UINT cpDest = CodePageOfDocument(); char inBufferCP[20]; int size = ::WideCharToMultiByte(cpDest, 0, wcs, 1, inBufferCP, sizeof(inBufferCP) - 1, 0, 0); @@ -1289,6 +1298,80 @@ void ScintillaWin::NotifyDoubleClick(Point pt, bool shift, bool ctrl, bool alt) MAKELPARAM(pt.x, pt.y)); } +std::string ScintillaWin::CaseMapString(const std::string &s, int caseMapping) { + if (s.size() == 0) + return std::string(); + + if (caseMapping == cmSame) + return s; + + UINT cpDoc = CodePageOfDocument(); + + unsigned int lengthUTF16 = ::MultiByteToWideChar(cpDoc, 0, s.c_str(), s.size(), NULL, NULL); + if (lengthUTF16 == 0) // Failed to convert + return s; + + DWORD mapFlags = LCMAP_LINGUISTIC_CASING | + ((caseMapping == cmUpper) ? LCMAP_UPPERCASE : LCMAP_LOWERCASE); + + // Many conversions performed by search function are short so optimize this case. + enum { shortSize=20 }; + + if (s.size() > shortSize) { + // Use dynamic allocations for long strings + + // Change text to UTF-16 + std::vector<wchar_t> vwcText(lengthUTF16); + ::MultiByteToWideChar(cpDoc, 0, s.c_str(), s.size(), &vwcText[0], lengthUTF16); + + // Change case + int charsConverted = ::LCMapStringW(LOCALE_SYSTEM_DEFAULT, mapFlags, + &vwcText[0], lengthUTF16, NULL, 0); + std::vector<wchar_t> vwcConverted(charsConverted); + ::LCMapStringW(LOCALE_SYSTEM_DEFAULT, mapFlags, + &vwcText[0], lengthUTF16, &vwcConverted[0], charsConverted); + + // Change back to document encoding + unsigned int lengthConverted = ::WideCharToMultiByte(cpDoc, 0, + &vwcConverted[0], vwcConverted.size(), + NULL, 0, NULL, 0); + std::vector<char> vcConverted(lengthConverted); + ::WideCharToMultiByte(cpDoc, 0, + &vwcConverted[0], vwcConverted.size(), + &vcConverted[0], vcConverted.size(), NULL, 0); + + return std::string(&vcConverted[0], vcConverted.size()); + + } else { + // Use static allocations for short strings as much faster + // A factor of 15 for single character strings + + // Change text to UTF-16 + wchar_t vwcText[shortSize]; + ::MultiByteToWideChar(cpDoc, 0, s.c_str(), s.size(), vwcText, lengthUTF16); + + // Change case + int charsConverted = ::LCMapStringW(LOCALE_SYSTEM_DEFAULT, mapFlags, + vwcText, lengthUTF16, NULL, 0); + // Full mapping may produce up to 3 characters per input character + wchar_t vwcConverted[shortSize*3]; + ::LCMapStringW(LOCALE_SYSTEM_DEFAULT, mapFlags, vwcText, lengthUTF16, + vwcConverted, charsConverted); + + // Change back to document encoding + unsigned int lengthConverted = ::WideCharToMultiByte(cpDoc, 0, + vwcConverted, charsConverted, + NULL, 0, NULL, 0); + // Each UTF-16 code unit may need up to 3 bytes in UTF-8 + char vcConverted[shortSize * 3 * 3]; + ::WideCharToMultiByte(cpDoc, 0, + vwcConverted, charsConverted, + vcConverted, lengthConverted, NULL, 0); + + return std::string(vcConverted, lengthConverted); + } +} + void ScintillaWin::Copy() { //Platform::DebugPrintf("Copy\n"); if (!sel.Empty()) { @@ -1409,8 +1492,7 @@ void ScintillaWin::Paste() { } else { // CF_UNICODETEXT available, but not in Unicode mode // Convert from Unicode to current Scintilla code page - UINT cpDest = CodePageFromCharSet( - vs.styles[STYLE_DEFAULT].characterSet, pdoc->dbcsCodePage); + UINT cpDest = CodePageOfDocument(); len = ::WideCharToMultiByte(cpDest, 0, uptr, memUSelection.Size() / 2, NULL, 0, NULL, NULL) - 1; // subtract 0 terminator putf = new char[len + 1]; @@ -2237,8 +2319,7 @@ STDMETHODIMP ScintillaWin::Drop(LPDATAOBJECT pIDataSource, DWORD grfKeyState, // Default Scintilla behavior in Unicode mode // CF_UNICODETEXT available, but not in Unicode mode // Convert from Unicode to current Scintilla code page - UINT cpDest = CodePageFromCharSet( - vs.styles[STYLE_DEFAULT].characterSet, pdoc->dbcsCodePage); + UINT cpDest = CodePageOfDocument(); int tlen = ::WideCharToMultiByte(cpDest, 0, udata, -1, NULL, 0, NULL, NULL) - 1; // subtract 0 terminator data = new char[tlen + 1]; |