diff options
-rw-r--r-- | include/Platform.h | 5 | ||||
-rw-r--r-- | include/Scintilla.h | 3 | ||||
-rw-r--r-- | src/Document.cxx | 119 | ||||
-rw-r--r-- | src/Document.h | 2 | ||||
-rw-r--r-- | src/DocumentAccessor.cxx | 7 | ||||
-rw-r--r-- | src/Editor.cxx | 6 | ||||
-rw-r--r-- | src/LexPython.cxx | 2 | ||||
-rw-r--r-- | src/WindowAccessor.cxx | 7 | ||||
-rw-r--r-- | win32/PlatWin.cxx | 142 | ||||
-rw-r--r-- | win32/ScintillaWin.cxx | 214 |
10 files changed, 361 insertions, 146 deletions
diff --git a/include/Platform.h b/include/Platform.h index 021bcf686..1ac931ce2 100644 --- a/include/Platform.h +++ b/include/Platform.h @@ -221,6 +221,7 @@ public: // A surface abstracts a place to draw class Surface { private: + bool unicodeMode; #if PLAT_GTK GdkDrawable *drawable; GdkGC *gc; @@ -293,6 +294,10 @@ public: int SetPalette(Palette *pal, bool inBackGround); void SetClip(PRectangle rc); void FlushCachedState(); + + void SetUnicodeMode(bool unicodeMode_) { + unicodeMode=unicodeMode_; + } }; // Class to hide the details of window manipulation diff --git a/include/Scintilla.h b/include/Scintilla.h index 822b2ea9d..f39ce4535 100644 --- a/include/Scintilla.h +++ b/include/Scintilla.h @@ -107,6 +107,9 @@ extern "C" { #define SCI_STARTSTYLING SCI_START + 32 #define SCI_SETSTYLING SCI_START + 33 +// This is the same value as CP_UTF8 in Windows +#define SC_CP_UTF8 65001 + #define SCI_SETBUFFEREDDRAW SCI_START + 35 #define SCI_SETTABWIDTH SCI_START + 36 #define SCI_SETCODEPAGE SCI_START + 37 diff --git a/src/Document.cxx b/src/Document.cxx index 7a30d7fd1..650c0ced2 100644 --- a/src/Document.cxx +++ b/src/Document.cxx @@ -202,18 +202,23 @@ bool Document::IsCrLf(int pos) { bool Document::IsDBCS(int pos) { #if PLAT_WIN if (dbcsCodePage) { - // Anchor DBCS calculations at start of line because start of line can - // not be a DBCS trail byte. - int startLine = pos; - while (startLine > 0 && cb.CharAt(startLine) != '\r' && cb.CharAt(startLine) != '\n') - startLine--; - while (startLine <= pos) { - if (IsDBCSLeadByteEx(dbcsCodePage, cb.CharAt(startLine))) { + if (SC_CP_UTF8 == dbcsCodePage) { + unsigned char ch = static_cast<unsigned char>(cb.CharAt(pos)); + return ch >= 0x80; + } else { + // Anchor DBCS calculations at start of line because start of line can + // not be a DBCS trail byte. + int startLine = pos; + while (startLine > 0 && cb.CharAt(startLine) != '\r' && cb.CharAt(startLine) != '\n') + startLine--; + while (startLine <= pos) { + if (IsDBCSLeadByteEx(dbcsCodePage, cb.CharAt(startLine))) { + startLine++; + if (startLine >= pos) + return true; + } startLine++; - if (startLine >= pos) - return true; } - startLine++; } } return false; @@ -222,6 +227,28 @@ bool Document::IsDBCS(int pos) { #endif } +int Document::LenChar(int pos) { + if (IsCrLf(pos)) { + return 2; + } else if (SC_CP_UTF8 == dbcsCodePage) { + unsigned char ch = static_cast<unsigned char>(cb.CharAt(pos)); + if (ch < 0x80) + return 1; + int len = 2; + if (ch >= (0x80+0x40+0x20)) + len = 3; + int lengthDoc = Length(); + if ((pos + len) > lengthDoc) + return lengthDoc-pos; + else + return len; + } else if (IsDBCS(pos)) { + return 2; + } else { + return 1; + } +} + // Normalise a position so that it is not halfway through a two byte character. // This can occur in two situations - // When lines are terminated with \r\n pairs which should be treated as one character. @@ -253,29 +280,41 @@ int Document::MovePositionOutsideChar(int pos, int moveDir, bool checkLineEnd) { #if PLAT_WIN if (dbcsCodePage) { - // Anchor DBCS calculations at start of line because start of line can - // not be a DBCS trail byte. - int startLine = pos; - while (startLine > 0 && cb.CharAt(startLine) != '\r' && cb.CharAt(startLine) != '\n') - startLine--; - bool atLeadByte = false; - while (startLine < pos) { - if (atLeadByte) - atLeadByte = false; - else if (IsDBCSLeadByteEx(dbcsCodePage, cb.CharAt(startLine))) - atLeadByte = true; - else - atLeadByte = false; - startLine++; - //Platform::DebugPrintf("DBCS %s\n", atlead ? "D" : "-"); - } + if (SC_CP_UTF8 == dbcsCodePage) { + unsigned char ch = static_cast<unsigned char>(cb.CharAt(pos)); + while ((pos > 0) && (pos < Length()) && (ch >= 0x80) && (ch < (0x80 + 0x40))) { + // ch is a trail byte + if (moveDir > 0) + pos++; + else + pos--; + ch = static_cast<unsigned char>(cb.CharAt(pos)); + } + } else { + // Anchor DBCS calculations at start of line because start of line can + // not be a DBCS trail byte. + int startLine = pos; + while (startLine > 0 && cb.CharAt(startLine) != '\r' && cb.CharAt(startLine) != '\n') + startLine--; + bool atLeadByte = false; + while (startLine < pos) { + if (atLeadByte) + atLeadByte = false; + else if (IsDBCSLeadByteEx(dbcsCodePage, cb.CharAt(startLine))) + atLeadByte = true; + else + atLeadByte = false; + startLine++; + //Platform::DebugPrintf("DBCS %s\n", atlead ? "D" : "-"); + } - if (atLeadByte) { - // Position is between a lead byte and a trail byte - if (moveDir > 0) - return pos + 1; - else - return pos - 1; + if (atLeadByte) { + // Position is between a lead byte and a trail byte + if (moveDir > 0) + return pos + 1; + else + return pos - 1; + } } } #endif @@ -440,13 +479,7 @@ void Document::ChangeChar(int pos, char ch) { } void Document::DelChar(int pos) { - if (IsCrLf(pos)) { - DeleteChars(pos, 2); - } else if (IsDBCS(pos)) { - DeleteChars(pos, 2); - } else if (pos < Length()) { - DeleteChars(pos, 1); - } + DeleteChars(pos, LenChar(pos)); } int Document::DelCharBack(int pos) { @@ -455,6 +488,10 @@ int Document::DelCharBack(int pos) { } else if (IsCrLf(pos - 2)) { DeleteChars(pos - 2, 2); return pos - 2; + } else if (SC_CP_UTF8 == dbcsCodePage) { + int startChar = MovePositionOutsideChar(pos-1, -1, false); + DeleteChars(startChar, pos - startChar); + return startChar; } else if (IsDBCS(pos - 1)) { DeleteChars(pos - 2, 2); return pos - 2; @@ -529,6 +566,8 @@ void Document::ConvertLineEnds(int eolModeSet) { } bool Document::IsWordChar(unsigned char ch) { + if ((SC_CP_UTF8 == dbcsCodePage) && (ch >0x80)) + return true; return wordchars[ch]; } @@ -653,7 +692,7 @@ void Document::ChangeCase(Range r, bool makeUpperCase) { for (int pos=r.start; pos<r.end; pos++) { char ch = CharAt(pos); if (dbcsCodePage && IsDBCS(pos)) { - pos++; + pos += LenChar(pos); } else { if (makeUpperCase) { if (islower(ch)) { diff --git a/src/Document.h b/src/Document.h index 7ab187573..ae25d69f4 100644 --- a/src/Document.h +++ b/src/Document.h @@ -87,6 +87,7 @@ public: int stylingBitsMask; int eolMode; + // dbcsCodePage can also be SC_CP_UTF8 to enable UTF-8 mode int dbcsCodePage; int tabInChars; @@ -99,6 +100,7 @@ public: int LineFromPosition(int pos); int ClampPositionIntoDocument(int pos); bool IsCrLf(int pos); + int LenChar(int pos); int MovePositionOutsideChar(int pos, int moveDir, bool checkLineEnd=true); // Gateways to modifying document diff --git a/src/DocumentAccessor.cxx b/src/DocumentAccessor.cxx index dd156fa24..420a359d6 100644 --- a/src/DocumentAccessor.cxx +++ b/src/DocumentAccessor.cxx @@ -22,7 +22,12 @@ bool DocumentAccessor::InternalIsLeadByte(char ch) { // TODO: support DBCS under GTK+ return false; #elif PLAT_WIN - return IsDBCSLeadByteEx(codePage, ch); + if (SC_CP_UTF8 == codePage) + // For lexing, all characters >= 0x80 are treated the + // same so none is considered a lead byte. + return false; + else + return IsDBCSLeadByteEx(codePage, ch); #elif PLAT_WX return false; #endif diff --git a/src/Editor.cxx b/src/Editor.cxx index 1566ffa6e..111142d90 100644 --- a/src/Editor.cxx +++ b/src/Editor.cxx @@ -210,6 +210,7 @@ Point Editor::LocationFromPosition(unsigned int pos) { //Platform::DebugPrintf("line=%d\n", line); Surface surface; surface.Init(); + surface.SetUnicodeMode(SC_CP_UTF8 == pdoc->dbcsCodePage); Point pt; pt.y = (lineVisible - topLine) * vs.lineHeight; // + half a lineheight? unsigned int posLineStart = pdoc->LineStart(line); @@ -252,6 +253,7 @@ int Editor::PositionFromLocation(Point pt) { //Platform::DebugPrintf("Position of (%d,%d) line = %d top=%d\n", pt.x, pt.y, line, topLine); Surface surface; surface.Init(); + surface.SetUnicodeMode(SC_CP_UTF8 == pdoc->dbcsCodePage); unsigned int posLineStart = pdoc->LineStart(line); LineLayout ll; @@ -273,6 +275,7 @@ int Editor::PositionFromLineX(int line, int x) { //Platform::DebugPrintf("Position of (%d,%d) line = %d top=%d\n", pt.x, pt.y, line, topLine); Surface surface; surface.Init(); + surface.SetUnicodeMode(SC_CP_UTF8 == pdoc->dbcsCodePage); unsigned int posLineStart = pdoc->LineStart(line); LineLayout ll; @@ -1024,6 +1027,7 @@ void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) { } else { surface = surfaceWindow; } + surface->SetUnicodeMode(SC_CP_UTF8 == pdoc->dbcsCodePage); int visibleLine = topLine + screenLinePaintFirst; int line = cs.DocFromDisplay(visibleLine); @@ -1164,8 +1168,10 @@ long Editor::FormatRange(bool draw, FORMATRANGE *pfr) { Surface *surface = new Surface(); surface->Init(pfr->hdc); + surface->SetUnicodeMode(SC_CP_UTF8 == pdoc->dbcsCodePage); Surface *surfaceMeasure = new Surface(); surfaceMeasure->Init(pfr->hdcTarget); + surfaceMeasure->SetUnicodeMode(SC_CP_UTF8 == pdoc->dbcsCodePage); ViewStyle vsPrint(vs); diff --git a/src/LexPython.cxx b/src/LexPython.cxx index 86597e863..1864412a6 100644 --- a/src/LexPython.cxx +++ b/src/LexPython.cxx @@ -71,9 +71,9 @@ static void ColourisePyDoc(unsigned int startPos, int length, int initStyle, for (int i = startPos; i <= lengthDoc; i++) { if (atStartLine) { - char chFlags; char chBad = static_cast<char>(64); char chGood = static_cast<char>(0); + char chFlags = chGood; if (whingeLevel == 1) { chFlags = (spaceFlags & wsInconsistent) ? chBad : chGood; } else if (whingeLevel == 2) { diff --git a/src/WindowAccessor.cxx b/src/WindowAccessor.cxx index d04c0142d..f0ad45914 100644 --- a/src/WindowAccessor.cxx +++ b/src/WindowAccessor.cxx @@ -19,7 +19,12 @@ bool WindowAccessor::InternalIsLeadByte(char ch) { // TODO: support DBCS under GTK+ return false; #elif PLAT_WIN - return IsDBCSLeadByteEx(codePage, ch); + if (SC_CP_UTF8 == codePage) + // For lexing, all characters >= 0x80 are treated the + // same so none is considered a lead byte. + return false; + else + return IsDBCSLeadByteEx(codePage, ch); #elif PLAT_WX return false; #endif diff --git a/win32/PlatWin.cxx b/win32/PlatWin.cxx index 63dd56648..7ce9930e4 100644 --- a/win32/PlatWin.cxx +++ b/win32/PlatWin.cxx @@ -323,20 +323,49 @@ void Surface::Copy(PRectangle rc, Point from, Surface &surfaceSource) { surfaceSource.hdc, from.x, from.y, SRCCOPY); } -#define ASCII_ONLY 1 +int UCS2FromUTF8(const char *s, int len, wchar_t *tbuf, int tlen) { +#ifdef USE_API + return ::MultiByteToWideChar(CP_UTF8, 0, s, len, tbuf, tlen); +#else + int ui=0; + const unsigned char *us = reinterpret_cast<const unsigned char *>(s); + int i=0; + while (i<len) { + unsigned char ch = us[i++]; + if (ch < 0x80) { + tbuf[ui] = ch; + } else if (ch < 0x80 + 0x40 + 0x20) { + tbuf[ui] = (ch & 0x1F) << 6; + ch = us[i++]; + tbuf[ui] += ch & 0x7F; + } else { + tbuf[ui] = (ch & 0xF) << 12; + ch = us[i++]; + tbuf[ui] += (ch & 0x7F) << 6; + ch = us[i++]; + tbuf[ui] += ch & 0x7F; + } + ui++; + } + return ui; +#endif +} + +#define MAX_US_LEN 5000 void Surface::DrawText(PRectangle rc, Font &font_, int ybase, const char *s, int len, Colour fore, Colour back) { SetFont(font_); ::SetTextColor(hdc, fore.AsLong()); ::SetBkColor(hdc, back.AsLong()); RECT rcw = RectFromPRectangle(rc); -#ifdef ASCII_ONLY - ::ExtTextOut(hdc, rc.left, ybase, ETO_OPAQUE, &rcw, s, len, NULL); -#else - wchar_t tbuf[20000]; - int tlen = MultiByteToWideChar(CP_UTF8, 0, s, len, tbuf, sizeof(tbuf)); - ::ExtTextOutW(hdc, rc.left, ybase, ETO_OPAQUE, &rcw, tbuf, tlen, NULL); -#endif + if (unicodeMode) { + wchar_t tbuf[MAX_US_LEN]; + int tlen = UCS2FromUTF8(s, len, tbuf, sizeof(tbuf)/sizeof(wchar_t)); + tbuf[tlen] = L'\0'; + ::ExtTextOutW(hdc, rc.left, ybase, ETO_OPAQUE, &rcw, tbuf, tlen, NULL); + } else { + ::ExtTextOut(hdc, rc.left, ybase, ETO_OPAQUE, &rcw, s, len, NULL); + } } void Surface::DrawTextClipped(PRectangle rc, Font &font_, int ybase, const char *s, int len, Colour fore, Colour back) { @@ -344,60 +373,75 @@ void Surface::DrawTextClipped(PRectangle rc, Font &font_, int ybase, const char ::SetTextColor(hdc, fore.AsLong()); ::SetBkColor(hdc, back.AsLong()); RECT rcw = RectFromPRectangle(rc); -#ifdef ASCII_ONLY - ::ExtTextOut(hdc, rc.left, ybase, ETO_OPAQUE | ETO_CLIPPED, &rcw, s, len, NULL); -#else - wchar_t tbuf[20000]; - int tlen = MultiByteToWideChar(CP_UTF8, 0, s, len, tbuf, sizeof(tbuf)); - ::ExtTextOutW(hdc, rc.left, ybase, ETO_OPAQUE | ETO_CLIPPED, &rcw, tbuf, tlen, NULL); -#endif + if (unicodeMode) { + wchar_t tbuf[MAX_US_LEN]; + int tlen = UCS2FromUTF8(s, len, tbuf, sizeof(tbuf)/sizeof(wchar_t)); + tbuf[tlen] = L'\0'; + ::ExtTextOutW(hdc, rc.left, ybase, ETO_OPAQUE | ETO_CLIPPED, &rcw, tbuf, tlen, NULL); + } else { + ::ExtTextOut(hdc, rc.left, ybase, ETO_OPAQUE | ETO_CLIPPED, &rcw, s, len, NULL); + } } int Surface::WidthText(Font &font_, const char *s, int len) { SetFont(font_); - SIZE sz; -#ifdef ASCII_ONLY - ::GetTextExtentPoint32(hdc, s, len, &sz); -#else - wchar_t tbuf[20000]; - int tlen = MultiByteToWideChar(CP_UTF8, 0, s, len, tbuf, sizeof(tbuf)); - ::GetTextExtentPoint32W(hdc, tbuf, tlen, &sz); -#endif + SIZE sz={0,0}; + if (unicodeMode) { + int fit = 0; + wchar_t tbuf[MAX_US_LEN]; + int tlen = UCS2FromUTF8(s, len, tbuf, sizeof(tbuf)/sizeof(wchar_t)); + tbuf[tlen] = L'\0'; + fit = tlen; + //::GetTextExtentPoint32W(hdc, tbuf, tlen, &sz); + if (!::GetTextExtentExPointW(hdc, tbuf, tlen, 30000, &fit, NULL, &sz)) { + DWORD dw = GetLastError(); + Platform::DebugPrintf("Error for 1 GTEEPW %d\n", dw); + } else { + //Platform::DebugPrintf("OK 1 GTEEPW %d\n", len); + } + } else { + ::GetTextExtentPoint32(hdc, s, len, &sz); + } return sz.cx; } void Surface::MeasureWidths(Font &font_, const char *s, int len, int *positions) { SetFont(font_); - SIZE sz; + SIZE sz={0,0}; int fit = 0; -#ifdef ASCII_ONLY - ::GetTextExtentExPoint(hdc, s, len, 30000, &fit, positions, &sz); -#else - wchar_t tbuf[20000]; - int poses[20000]; - int tlen = MultiByteToWideChar(CP_UTF8, 0, s, len, tbuf, sizeof(tbuf)); - ::GetTextExtentExPointW(hdc, tbuf, tlen, 30000, &fit, poses, &sz); - int ui=0; - const unsigned char *us = reinterpret_cast<const unsigned char *>(s); - int i=0; - while (i<len) { - positions[i] = poses[ui]; - if (us[i] < 128) { - ui++; - } else if (us[i] < (128 + 64 + 32)) { - positions[i+1] = poses[ui]; - ui++; - i++; + if (unicodeMode) { + wchar_t tbuf[MAX_US_LEN]; + int tlen = UCS2FromUTF8(s, len, tbuf, sizeof(tbuf)/sizeof(wchar_t)); + tbuf[tlen] = L'\0'; + int poses[MAX_US_LEN]; + fit = tlen; + SetLastError(0); + if (!::GetTextExtentExPointW(hdc, tbuf, tlen, 30000, &fit, poses, &sz)) { + DWORD dw = GetLastError(); + Platform::DebugPrintf("Error for GTEEPW %d\n", dw); } else { - positions[i+1] = poses[ui]; - positions[i+2] = poses[ui]; + //Platform::DebugPrintf("OK GTEEPW %d\n", len); + } + int ui=0; + const unsigned char *us = reinterpret_cast<const unsigned char *>(s); + int i=0; + while (i<len) { + unsigned char uch = us[i]; + positions[i++] = poses[ui]; + if (uch >= 0x80) { + if (uch < (0x80 + 0x40 + 0x20)) { + positions[i++] = poses[ui]; + } else { + positions[i++] = poses[ui]; + positions[i++] = poses[ui]; + } + } ui++; - i++; - i++; } - i++; + positions[i] = sz.cx; + } else { + ::GetTextExtentExPoint(hdc, s, len, 30000, &fit, positions, &sz); } -#endif } int Surface::WidthChar(Font &font_, char ch) { @@ -704,7 +748,7 @@ int Platform::Maximum(int a, int b) { return b; } -//#define TRACE +#define TRACE void Platform::DebugPrintf(const char *format, ...) { #ifdef TRACE diff --git a/win32/ScintillaWin.cxx b/win32/ScintillaWin.cxx index 9334ae215..104f15423 100644 --- a/win32/ScintillaWin.cxx +++ b/win32/ScintillaWin.cxx @@ -137,7 +137,7 @@ class ScintillaWin : void ImeEndComposition(); void GetIntelliMouseParameters(); - HGLOBAL GetSelText(); + void CopySelTextToClipboard(); void ScrollMessage(WPARAM wParam); void HorizontalScrollMessage(WPARAM wParam); void RealizeWindowPalette(bool inBackGround); @@ -268,6 +268,7 @@ LRESULT ScintillaWin::WndProc(UINT iMessage, WPARAM wParam, LPARAM lParam) { BeginPaint(wMain.GetID(), &ps); Surface surfaceWindow; surfaceWindow.Init(ps.hdc); + surfaceWindow.SetUnicodeMode(SC_CP_UTF8 == pdoc->dbcsCodePage); rcPaint = PRectangle(ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right, ps.rcPaint.bottom); PRectangle rcText = GetTextRectangle(); paintingAllText = rcPaint.Contains(rcText); @@ -456,11 +457,13 @@ LRESULT ScintillaWin::WndProc(UINT iMessage, WPARAM wParam, LPARAM lParam) { break; case EM_CANPASTE: { - OpenClipboard(wMain.GetID()); - HGLOBAL hmemSelection = GetClipboardData(CF_TEXT); + ::OpenClipboard(wMain.GetID()); + HGLOBAL hmemSelection = ::GetClipboardData(CF_TEXT); + if (!hmemSelection && (SC_CP_UTF8 == pdoc->dbcsCodePage)) + hmemSelection = ::GetClipboardData(CF_UNICODETEXT); if (hmemSelection) - GlobalUnlock(hmemSelection); - CloseClipboard(); + ::GlobalUnlock(hmemSelection); + ::CloseClipboard(); return hmemSelection != 0; } @@ -585,10 +588,9 @@ void ScintillaWin::NotifyDoubleClick(Point pt, bool shift) { void ScintillaWin::Copy() { //Platform::DebugPrintf("Copy\n"); if (currentPos != anchor) { - HGLOBAL hmemSelection = GetSelText(); ::OpenClipboard(wMain.GetID()); ::EmptyClipboard(); - ::SetClipboardData(CF_TEXT, hmemSelection); + CopySelTextToClipboard(); if (selType == selRectangle) { ::SetClipboardData(cfColumnSelect, 0); } @@ -596,31 +598,88 @@ void ScintillaWin::Copy() { } } +unsigned int UTF8Length(wchar_t *uptr, unsigned int tlen) { + unsigned int len = 0; + for (unsigned int i = 0; i < tlen && uptr[i]; i++) { + unsigned int uch = uptr[i]; + if (uch < 0x80) + len++; + else if (uch < 0x800) + len+=2; + else + len +=3; + } + return len; +} + +void UTF8FromUCS2(wchar_t *uptr, unsigned int tlen, char *putf, int len) { + int k = 0; + for (unsigned int i = 0; i < tlen && uptr[i]; i++) { + unsigned int uch = uptr[i]; + if (uch < 0x80) { + putf[k++] = uch; + } else if (uch < 0x800) { + putf[k++] = 0xC0 | (uch >> 6); + putf[k++] = 0x80 | (uch & 0x3f); + } else { + putf[k++] = 0xE0 | (uch >> 12); + putf[k++] = 0x80 | ((uch >> 6) & 0x3f); + putf[k++] = 0x80 | (uch & 0x3f); + } + } + putf[len] = '\0'; +} + void ScintillaWin::Paste() { pdoc->BeginUndoAction(); int selStart = SelectionStart(); ClearSelection(); ::OpenClipboard(wMain.GetID()); bool isRectangular = ::IsClipboardFormatAvailable(cfColumnSelect); - HGLOBAL hmemSelection = ::GetClipboardData(CF_TEXT); - if (hmemSelection) { - char *ptr = static_cast<char *>( - ::GlobalLock(hmemSelection)); - if (ptr) { - unsigned int bytes = ::GlobalSize(hmemSelection); - unsigned int len = bytes; - for (unsigned int i = 0; i < bytes; i++) { - if ((len == bytes) && (0 == ptr[i])) - len = i; + HGLOBAL hmemUSelection = 0; + if (SC_CP_UTF8 == pdoc->dbcsCodePage) { + hmemUSelection = ::GetClipboardData(CF_UNICODETEXT); + if (hmemUSelection) { + wchar_t *uptr = static_cast<wchar_t *>(::GlobalLock(hmemUSelection)); + if (uptr) { + unsigned int bytes = ::GlobalSize(hmemUSelection); + unsigned int len = UTF8Length(uptr, bytes/2); + char *putf = new char[len+1]; + if (putf) { + UTF8FromUCS2(uptr, bytes/2, putf, len); + if (isRectangular) { + PasteRectangular(selStart, putf, len); + } else { + pdoc->InsertString(currentPos, putf, len); + SetEmptySelection(currentPos + len); + } + delete []putf; + } } - if (isRectangular) { - PasteRectangular(selStart, ptr, len); - } else { - pdoc->InsertString(currentPos, ptr, len); - SetEmptySelection(currentPos + len); + ::GlobalUnlock(hmemUSelection); + } + } + if (!hmemUSelection) { + HGLOBAL hmemSelection = ::GetClipboardData(CF_TEXT); + if (hmemSelection) { + char *ptr = static_cast<char *>( + ::GlobalLock(hmemSelection)); + if (ptr) { + unsigned int bytes = ::GlobalSize(hmemSelection); + unsigned int len = bytes; + for (unsigned int i = 0; i < bytes; i++) { + if ((len == bytes) && (0 == ptr[i])) + len = i; + } + if (isRectangular) { + PasteRectangular(selStart, ptr, len); + } else { + pdoc->InsertString(currentPos, ptr, len); + SetEmptySelection(currentPos + len); + } } + ::GlobalUnlock(hmemSelection); } - ::GlobalUnlock(hmemSelection); } ::CloseClipboard(); pdoc->EndUndoAction(); @@ -795,7 +854,7 @@ STDMETHODIMP DataObject_QueryGetData(DataObject *pd, FORMATETC *pFE) { } if ( - ((pFE->cfFormat != CF_TEXT) && (pFE->cfFormat != CF_HDROP)) || + ((pFE->cfFormat != CF_TEXT) && (pFE->cfFormat != CF_UNICODETEXT) && (pFE->cfFormat != CF_HDROP)) || pFE->ptd != 0 || (pFE->dwAspect & DVASPECT_CONTENT) == 0 || pFE->lindex != -1 || @@ -963,25 +1022,56 @@ void ScintillaWin::GetIntelliMouseParameters() { ::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &ucWheelScrollLines, 0); } -HGLOBAL ScintillaWin::GetSelText() { +void ScintillaWin::CopySelTextToClipboard() { int bytes = SelectionRangeLength(); + char *selChars = CopySelectionRange(); + if (!selChars) + return; HGLOBAL hand = ::GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, bytes + 1); if (hand) { char *ptr = static_cast<char *>(::GlobalLock(hand)); - char *selChars = CopySelectionRange(); - if (selChars) { - memcpy(ptr, selChars, bytes); - delete []selChars; - //for (int i = 0; i < bytes; i++) { - // ptr[i] = pdoc->CharAt(startPos + i); - //} - } + memcpy(ptr, selChars, bytes); ptr[bytes] = '\0'; ::GlobalUnlock(hand); } - return hand; + ::SetClipboardData(CF_TEXT, hand); + + if (SC_CP_UTF8 == pdoc->dbcsCodePage) { + int uchars = 0; + for (int i=0;i<bytes;i++) { + unsigned char ch = static_cast<unsigned char>(selChars[i]); + if ((ch < 0x80) || (ch > (0x80 + 0x40))) + uchars++; + } + HGLOBAL uhand = ::GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, + 2 * (uchars + 1)); + if (uhand) { + wchar_t *uptr = static_cast<wchar_t *>(::GlobalLock(uhand)); + int k=0; + for (int j=0; j<uchars; j++) { + unsigned char ch = static_cast<unsigned char>(selChars[k++]); + if (ch < 0x80) { + uptr[j] = ch; + } else if (ch < 0x80 + 0x40 + 0x20) { + uptr[j] = (ch & 0x1F) << 6; + ch = static_cast<unsigned char>(selChars[k++]); + uptr[j] += ch & 0x7F; + } else { + uptr[j] = (ch & 0xF) << 12; + ch = static_cast<unsigned char>(selChars[k++]); + uptr[j] += (ch & 0x7F) << 6; + ch = static_cast<unsigned char>(selChars[k++]); + uptr[j] += ch & 0x7F; + } + } + uptr[uchars] = 0; + ::GlobalUnlock(uhand); + } + ::SetClipboardData(CF_UNICODETEXT, uhand); + } + delete []selChars; } void ScintillaWin::ScrollMessage(WPARAM wParam) { @@ -1068,6 +1158,7 @@ void ScintillaWin::FullPaint() { HDC hdc = ::GetDC(wMain.GetID()); Surface surfaceWindow; surfaceWindow.Init(hdc); + surfaceWindow.SetUnicodeMode(SC_CP_UTF8 == pdoc->dbcsCodePage); Paint(&surfaceWindow, rcPaint); surfaceWindow.Release(); ::ReleaseDC(wMain.GetID(), hdc); @@ -1151,30 +1242,42 @@ STDMETHODIMP ScintillaWin::Drop(LPDATAOBJECT pIDataSource, DWORD grfKeyState, SetDragPosition(invalidPosition); - FORMATETC fmte = {CF_TEXT, - NULL, - DVASPECT_CONTENT, - -1, - TYMED_HGLOBAL - }; STGMEDIUM medium; + HRESULT hr = S_OK; + + wchar_t *udata = 0; + char *data = 0; + int dataLen = 0; + + if (SC_CP_UTF8 == pdoc->dbcsCodePage) { + FORMATETC fmtu = {CF_UNICODETEXT, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; + hr = pIDataSource->GetData(&fmtu, &medium); + if (SUCCEEDED(hr) && medium.hGlobal) { + udata = static_cast<wchar_t *>(::GlobalLock(medium.hGlobal)); + int tlen = ::GlobalSize(medium.hGlobal); + // Convert UCS-2 to UTF-8 + dataLen = UTF8Length(udata, tlen/2); + data = new char[dataLen+1]; + if (data) { + UTF8FromUCS2(udata, tlen/2, data, dataLen); + } + } + } - HRESULT hres = pIDataSource->GetData(&fmte, &medium); - if (FAILED(hres)) { - //Platform::DebugPrintf("Bad data format: 0x%x\n", hres); - return hres; + if (!data) { + FORMATETC fmte = {CF_TEXT, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; + hr = pIDataSource->GetData(&fmte, &medium); + if (SUCCEEDED(hr) && medium.hGlobal) { + data = static_cast<char *>(::GlobalLock(medium.hGlobal)); + } } - if (medium.hGlobal == 0) { - return E_OUTOFMEMORY; + + if (!data) { + //Platform::DebugPrintf("Bad data format: 0x%x\n", hres); + return hr; } - char *data = static_cast<char *>(::GlobalLock(medium.hGlobal)); - - FORMATETC fmtr = {cfColumnSelect, - NULL, - DVASPECT_CONTENT, - -1, - TYMED_HGLOBAL - }; + + FORMATETC fmtr = {cfColumnSelect, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; HRESULT hrRectangular = pIDataSource->QueryGetData(&fmtr); POINT rpt = {pt.x, pt.y}; @@ -1190,6 +1293,9 @@ STDMETHODIMP ScintillaWin::Drop(LPDATAOBJECT pIDataSource, DWORD grfKeyState, if (medium.pUnkForRelease != NULL) medium.pUnkForRelease->Release(); + if (udata) + delete []data; + return S_OK; } |