aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--include/Platform.h5
-rw-r--r--include/Scintilla.h3
-rw-r--r--src/Document.cxx119
-rw-r--r--src/Document.h2
-rw-r--r--src/DocumentAccessor.cxx7
-rw-r--r--src/Editor.cxx6
-rw-r--r--src/LexPython.cxx2
-rw-r--r--src/WindowAccessor.cxx7
-rw-r--r--win32/PlatWin.cxx142
-rw-r--r--win32/ScintillaWin.cxx214
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;
}